From 0e2c520ecd05226475d892364ce1cd3a6cd4c70d Mon Sep 17 00:00:00 2001 From: Zexi Li Date: Fri, 28 Oct 2022 19:53:03 +0800 Subject: [PATCH] feat(misc): use cloudmux package (#15254) --- cmd/aliyuncli/main.go | 152 -- cmd/apsaracli/main.go | 154 -- cmd/awscli/main.go | 154 -- cmd/azurecli/main.go | 171 -- cmd/bingocli/main.go | 150 -- cmd/climc/shell/compute/buckets.go | 2 +- cmd/climc/shell/misc/version.go | 2 +- cmd/cloudpodscli/main.go | 153 -- cmd/ctyuncli/main.go | 149 -- cmd/ecloudcli/main.go | 147 -- cmd/esxicli/main.go | 146 -- cmd/googlecli/main.go | 179 -- cmd/hcscli/main.go | 157 -- cmd/hcsocli/main.go | 154 -- cmd/huaweicli/main.go | 152 -- cmd/incloudspherecli/main.go | 149 -- cmd/jdcloudcli/main.go | 151 -- cmd/ncli/main.go | 151 -- cmd/openstackcli/main.go | 164 -- cmd/proxmoxcli/main.go | 152 -- cmd/qcloudcli/main.go | 149 -- cmd/s3cli/main.go | 139 -- cmd/ucloudcli/main.go | 150 -- cmd/zstackcli/main.go | 155 -- go.mod | 49 +- go.sum | 28 +- pkg/apihelper/reflect.go | 4 +- pkg/apis/cloudprovider/zz_generated.model.go | 44 +- pkg/apis/compute/bucket.go | 2 +- pkg/apis/compute/cdn.go | 3 +- pkg/apis/compute/cloudaccount.go | 2 +- pkg/apis/compute/cloudaccount_const.go | 3 +- pkg/apis/compute/cloudprovider.go | 2 +- pkg/apis/compute/disk.go | 2 +- pkg/apis/compute/dnsrecordsets.go | 2 +- pkg/apis/compute/loadbalancer_const.go | 11 +- pkg/apis/compute/regiondata.go | 2 +- pkg/apis/compute/waf_instance.go | 3 +- pkg/apis/compute/waf_rules.go | 3 +- pkg/baremetal/utils/raid/adaptec/adaptec.go | 13 +- pkg/cloudcommon/db/opslog_const.go | 2 +- pkg/cloudcommon/db/opslog_test.go | 2 +- pkg/cloudcommon/policy/policy.go | 2 - pkg/cloudevent/models/cloudevents.go | 2 +- pkg/cloudevent/models/cloudproviders.go | 2 +- pkg/cloudevent/service/service.go | 2 +- pkg/cloudevent/tasks/cloudevent_sync_task.go | 2 +- pkg/cloudid/models/cloudaccount.go | 2 +- pkg/cloudid/models/cloudgroup.go | 2 +- pkg/cloudid/models/cloudgroupcaches.go | 2 +- pkg/cloudid/models/cloudpolicy.go | 2 +- pkg/cloudid/models/cloudpolicycaches.go | 2 +- pkg/cloudid/models/cloudprovider.go | 2 +- pkg/cloudid/models/cloudrole.go | 2 +- pkg/cloudid/models/clouduser.go | 2 +- pkg/cloudid/models/clouduser_policies.go | 2 +- pkg/cloudid/models/saml_provider.go | 2 +- pkg/cloudid/saml/providers/aliyun/factory.go | 3 +- pkg/cloudid/saml/providers/aws/factory.go | 3 +- pkg/cloudid/saml/providers/awscn/factory.go | 3 +- pkg/cloudid/saml/providers/azure/factory.go | 3 +- pkg/cloudid/saml/providers/google/factory.go | 3 +- pkg/cloudid/saml/providers/huawei/factory.go | 3 +- pkg/cloudid/saml/providers/qcloud/factory.go | 3 +- pkg/cloudid/service/service.go | 2 +- pkg/cloudid/tasks/cloud_role_delete_task.go | 2 +- pkg/cloudid/tasks/cloudgroup_delete_task.go | 2 +- .../tasks/cloudgroupcache_delete_task.go | 2 +- pkg/cloudid/tasks/clouduser_delete_task.go | 2 +- .../tasks/saml_provider_create_task.go | 2 +- .../tasks/saml_provider_delete_task.go | 2 +- .../saml_provider_update_metadata_task.go | 2 +- .../tasks/sync_cloudid_resources_task.go | 2 +- pkg/cloudid/tasks/sync_cloudusers_task.go | 2 +- pkg/cloudmon/misc/usageservice.go | 6 +- pkg/cloudmon/providerdriver/base.go | 2 +- pkg/cloudmon/providerdriver/driver.go | 3 +- pkg/cloudmon/providerdriver/huawei.go | 2 +- pkg/cloudmon/providerdriver/huaweistack.go | 2 +- pkg/cloudmon/providerdriver/qcloud.go | 2 +- pkg/cloudmon/resources/resources.go | 2 +- pkg/cloudmon/service/service.go | 2 +- pkg/cloudprovider/dnszone_test.go | 179 -- pkg/cloudprovider/doc.go | 15 - pkg/cloudprovider/objectstore_test.go | 52 - pkg/compute/guestdrivers/aliyun.go | 2 +- pkg/compute/guestdrivers/aws.go | 2 +- pkg/compute/guestdrivers/azure.go | 2 +- pkg/compute/guestdrivers/baremetals.go | 2 +- pkg/compute/guestdrivers/base.go | 2 +- pkg/compute/guestdrivers/bingocloud.go | 3 +- pkg/compute/guestdrivers/cloudpods.go | 2 +- pkg/compute/guestdrivers/container.go | 2 +- pkg/compute/guestdrivers/ctyun.go | 2 +- pkg/compute/guestdrivers/ecloud.go | 2 +- pkg/compute/guestdrivers/esxi.go | 4 +- pkg/compute/guestdrivers/google.go | 4 +- pkg/compute/guestdrivers/hcs.go | 2 +- pkg/compute/guestdrivers/huawei.go | 2 +- pkg/compute/guestdrivers/huaweistack.go | 2 +- pkg/compute/guestdrivers/incloudsphere.go | 2 +- pkg/compute/guestdrivers/jdcloud.go | 3 +- pkg/compute/guestdrivers/kvm.go | 2 +- pkg/compute/guestdrivers/managedvirtual.go | 2 +- pkg/compute/guestdrivers/nutanix.go | 2 +- pkg/compute/guestdrivers/openstack.go | 2 +- pkg/compute/guestdrivers/proxmox.go | 3 +- pkg/compute/guestdrivers/qcloud.go | 2 +- pkg/compute/guestdrivers/remotefile.go | 3 +- pkg/compute/guestdrivers/ucloud.go | 2 +- pkg/compute/guestdrivers/utils.go | 2 +- pkg/compute/guestdrivers/zstack.go | 2 +- pkg/compute/hostdrivers/esxi.go | 4 +- pkg/compute/hostdrivers/kvm.go | 2 +- pkg/compute/hostdrivers/managedvirtual.go | 2 +- pkg/compute/models/access_group_caches.go | 2 +- pkg/compute/models/access_group_rules.go | 2 +- pkg/compute/models/access_groups.go | 2 +- pkg/compute/models/app.go | 2 +- pkg/compute/models/app_environment.go | 2 +- pkg/compute/models/buckets.go | 2 +- pkg/compute/models/cachedimages.go | 2 +- pkg/compute/models/capabilities.go | 2 +- pkg/compute/models/cdn_domains.go | 2 +- pkg/compute/models/cloudaccounts.go | 4 +- pkg/compute/models/cloudaccounts_prepare.go | 4 +- pkg/compute/models/cloudaccounts_test.go | 3 +- pkg/compute/models/cloudprovider_quotas.go | 2 +- pkg/compute/models/cloudproviders.go | 2 +- pkg/compute/models/cloudregionresource.go | 2 +- pkg/compute/models/cloudregions.go | 2 +- pkg/compute/models/cloudsync.go | 2 +- pkg/compute/models/cloudsyncelasticcache.go | 2 +- pkg/compute/models/cloudsyncelb.go | 2 +- pkg/compute/models/dbinstance_accounts.go | 2 +- pkg/compute/models/dbinstance_backups.go | 2 +- pkg/compute/models/dbinstance_databases.go | 2 +- pkg/compute/models/dbinstance_parameters.go | 2 +- pkg/compute/models/dbinstance_privileges.go | 2 +- pkg/compute/models/dbinstance_skus.go | 2 +- pkg/compute/models/dbinstancenetworks.go | 2 +- pkg/compute/models/dbinstances.go | 2 +- pkg/compute/models/disks.go | 2 +- pkg/compute/models/dns_recordsets.go | 2 +- pkg/compute/models/dns_trafficpolicy.go | 2 +- pkg/compute/models/dns_zonecaches.go | 2 +- pkg/compute/models/dns_zones.go | 2 +- pkg/compute/models/dynamicschedtags.go | 2 +- pkg/compute/models/elastic_search.go | 2 +- pkg/compute/models/elasticcache_accounts.go | 2 +- pkg/compute/models/elasticcache_acls.go | 2 +- pkg/compute/models/elasticcache_backups.go | 2 +- pkg/compute/models/elasticcache_instances.go | 2 +- pkg/compute/models/elasticcache_parameters.go | 2 +- pkg/compute/models/elasticcache_skus.go | 2 +- pkg/compute/models/elasticcacheresource.go | 2 +- pkg/compute/models/elasticips.go | 2 +- pkg/compute/models/external_projects.go | 2 +- pkg/compute/models/filesystem.go | 2 +- pkg/compute/models/globalvpcs.go | 2 +- pkg/compute/models/guest_actions.go | 2 +- pkg/compute/models/guest_queries.go | 2 +- pkg/compute/models/guestdrivers.go | 2 +- pkg/compute/models/guests.go | 2 +- pkg/compute/models/host_recycle.go | 2 +- pkg/compute/models/hosts.go | 4 +- pkg/compute/models/hoststorages.go | 2 +- pkg/compute/models/i18nresource.go | 2 +- pkg/compute/models/instance_snapshots.go | 2 +- pkg/compute/models/inter_vpc_network.go | 2 +- .../models/inter_vpc_network_routeset.go | 2 +- pkg/compute/models/ipv6_gateways.go | 2 +- pkg/compute/models/kafka.go | 4 +- pkg/compute/models/kube_clusters.go | 2 +- pkg/compute/models/kube_node_pools.go | 2 +- pkg/compute/models/kube_nodes.go | 2 +- pkg/compute/models/loadbalanceracls.go | 2 +- pkg/compute/models/loadbalanceragents.go | 5 +- .../models/loadbalancerawscachedlbb.go | 2 +- .../models/loadbalancerawscachedlbbg.go | 2 +- .../models/loadbalancerbackendgroups.go | 2 +- pkg/compute/models/loadbalancerbackends.go | 2 +- pkg/compute/models/loadbalancercachedacls.go | 2 +- .../models/loadbalancercachedcertificates.go | 2 +- .../models/loadbalancercertificates.go | 6 +- .../models/loadbalancerhuaweicachedlbb.go | 2 +- .../models/loadbalancerhuaweicachedlbbg.go | 2 +- .../models/loadbalancerlistenerrules.go | 2 +- pkg/compute/models/loadbalancerlisteners.go | 10 +- .../models/loadbalanceropenstackcachedlbb.go | 2 +- .../models/loadbalanceropenstackcachedlbbg.go | 2 +- .../models/loadbalancerqcloudcachedlbb.go | 2 +- .../models/loadbalancerqcloudcachedlbbg.go | 2 +- pkg/compute/models/loadbalancers.go | 2 +- pkg/compute/models/managedresource.go | 2 +- pkg/compute/models/miscresources.go | 2 +- pkg/compute/models/modelarts_pool_sku.go | 2 +- pkg/compute/models/modelarts_pools.go | 2 +- pkg/compute/models/mongodb.go | 2 +- pkg/compute/models/mount_targets.go | 2 +- pkg/compute/models/nat_skus.go | 2 +- pkg/compute/models/natdtable.go | 2 +- pkg/compute/models/natgateways.go | 2 +- pkg/compute/models/natstable.go | 2 +- pkg/compute/models/networkaddresses.go | 2 +- pkg/compute/models/networkinterfacenetwork.go | 2 +- pkg/compute/models/networkinterfaces.go | 2 +- pkg/compute/models/networks.go | 2 +- pkg/compute/models/regiondrivers.go | 2 +- pkg/compute/models/route_table_associtaion.go | 2 +- pkg/compute/models/routetable_routesets.go | 2 +- pkg/compute/models/routetables.go | 2 +- pkg/compute/models/secgroupcache.go | 2 +- pkg/compute/models/secgrouprules.go | 2 +- pkg/compute/models/secgroups.go | 2 +- pkg/compute/models/skuresource.go | 2 +- pkg/compute/models/skus.go | 2 +- pkg/compute/models/snapshotpolicy.go | 2 +- pkg/compute/models/snapshotpolicycache.go | 2 +- pkg/compute/models/snapshotpolicydisks.go | 1 - pkg/compute/models/snapshots.go | 2 +- pkg/compute/models/storagecachedimages.go | 2 +- pkg/compute/models/storagecaches.go | 2 +- pkg/compute/models/storages.go | 2 +- pkg/compute/models/syncutils.go | 2 +- pkg/compute/models/tablestores.go | 2 +- pkg/compute/models/vpc_peering_connections.go | 2 +- pkg/compute/models/vpcresource.go | 2 +- pkg/compute/models/vpcs.go | 2 +- pkg/compute/models/waf_instances.go | 2 +- pkg/compute/models/waf_ipset_caches.go | 2 +- pkg/compute/models/waf_ipsets.go | 2 +- pkg/compute/models/waf_regexset_caches.go | 2 +- pkg/compute/models/waf_regexsets.go | 2 +- pkg/compute/models/waf_rule_group_caches.go | 2 +- pkg/compute/models/waf_rule_groups.go | 2 +- pkg/compute/models/waf_rule_statements.go | 2 +- pkg/compute/models/waf_rules.go | 2 +- pkg/compute/models/wires.go | 2 +- pkg/compute/models/zones.go | 2 +- pkg/compute/options/options.go | 2 +- pkg/compute/regiondrivers/aliyun.go | 2 +- pkg/compute/regiondrivers/aws.go | 2 +- pkg/compute/regiondrivers/azure.go | 2 +- pkg/compute/regiondrivers/base.go | 2 +- pkg/compute/regiondrivers/bingocloud.go | 2 +- pkg/compute/regiondrivers/ctyun.go | 2 +- pkg/compute/regiondrivers/google.go | 2 +- pkg/compute/regiondrivers/huawei.go | 2 +- pkg/compute/regiondrivers/jdcloud.go | 2 +- pkg/compute/regiondrivers/kvm.go | 2 +- pkg/compute/regiondrivers/managedvirtual.go | 2 +- pkg/compute/regiondrivers/openstack.go | 2 +- pkg/compute/regiondrivers/qcloud.go | 2 +- .../regiondrivers/secgroup_aliyun_test.go | 2 +- .../regiondrivers/secgroup_aws_test.go | 2 +- .../regiondrivers/secgroup_azure_test.go | 2 +- .../regiondrivers/secgroup_ctyun_test.go | 2 +- .../regiondrivers/secgroup_kvm_test.go | 2 +- .../regiondrivers/secgroup_openstack_test.go | 2 +- .../regiondrivers/secgroup_qcloud_test.go | 2 +- pkg/compute/regiondrivers/secgroup_test.go | 3 +- pkg/compute/regiondrivers/ucloud.go | 2 +- pkg/compute/regiondrivers/zstack.go | 2 +- pkg/compute/service/service.go | 4 +- .../tasks/access_group_cache_delete_task.go | 2 +- pkg/compute/tasks/access_group_delete_task.go | 2 +- pkg/compute/tasks/app_remote_update_task.go | 2 +- pkg/compute/tasks/cdn_domain_create_task.go | 2 +- pkg/compute/tasks/cdn_domain_delete_task.go | 2 +- .../tasks/cdn_domain_remote_update_task.go | 2 +- .../tasks/cloud_account_sync_vmware_net.go | 2 +- .../tasks/dbinstance_account_create_task.go | 2 +- ...dbinstance_account_grant_privilege_task.go | 2 +- ...binstance_account_revoke_privilege_task.go | 2 +- .../dbinstance_account_set_privileges_task.go | 2 +- pkg/compute/tasks/dbinstance_backup_delete.go | 2 +- .../tasks/dbinstance_database_create_task.go | 2 +- pkg/compute/tasks/dbinstance_delete_task.go | 2 +- .../dbinstance_public_connection_task.go | 2 +- pkg/compute/tasks/dbinstance_reboot_task.go | 2 +- pkg/compute/tasks/dbinstance_recovery_task.go | 2 +- pkg/compute/tasks/dbinstance_renew_task.go | 2 +- pkg/compute/tasks/disk_delete_task.go | 2 +- pkg/compute/tasks/dnszone_create_task.go | 2 +- pkg/compute/tasks/dnszone_delete_task.go | 2 +- pkg/compute/tasks/dnszone_sync_vpcs_task.go | 2 +- pkg/compute/tasks/dnszonecache_create_task.go | 2 +- pkg/compute/tasks/dnszonecache_delete_task.go | 2 +- pkg/compute/tasks/eip_allocate_task.go | 2 +- pkg/compute/tasks/eip_deallocate_task.go | 2 +- pkg/compute/tasks/eip_dissociate_task.go | 2 +- .../tasks/elastic_search_delete_task.go | 2 +- .../tasks/file_system_remote_update_task.go | 2 +- pkg/compute/tasks/filesystem_create_task.go | 2 +- pkg/compute/tasks/filesystem_delete_task.go | 2 +- pkg/compute/tasks/global_vpc_create_task.go | 2 +- pkg/compute/tasks/global_vpc_delete_task.go | 2 +- pkg/compute/tasks/guest_create_disk_task.go | 2 +- pkg/compute/tasks/guest_delete_task.go | 2 +- pkg/compute/tasks/guest_live_migrate_task.go | 4 +- pkg/compute/tasks/guest_syncstatus_task.go | 2 +- .../tasks/inter_vpc_network_add_vpc_task.go | 2 +- .../tasks/inter_vpc_network_create_task.go | 2 +- .../inter_vpc_network_remove_vpc_task.go | 2 +- pkg/compute/tasks/kafka_delete_task.go | 2 +- pkg/compute/tasks/kube_cluster_delete_task.go | 2 +- .../loadbalancer_backendgroup_create_task.go | 2 +- .../modelarts_pool_change_config_task.go | 2 +- .../tasks/modelarts_pool_create_task.go | 2 +- .../tasks/modelarts_pool_delete_task.go | 2 +- pkg/compute/tasks/mongodb_delete_task.go | 2 +- .../tasks/mongodb_remote_update_task.go | 2 +- pkg/compute/tasks/mount_target_create_task.go | 2 +- .../tasks/mount_target_syncstatus_task.go | 2 +- pkg/compute/tasks/nat_create_task.go | 2 +- pkg/compute/tasks/nat_delete_task.go | 2 +- pkg/compute/tasks/nat_renew_task.go | 2 +- pkg/compute/tasks/natdentry_create_task.go | 2 +- pkg/compute/tasks/natdentry_delete_task.go | 2 +- .../tasks/natgateway_remote_update_task.go | 2 +- pkg/compute/tasks/natsentry_create_task.go | 2 +- pkg/compute/tasks/natsentry_delete_task.go | 2 +- pkg/compute/tasks/network_delete_task.go | 2 +- pkg/compute/tasks/route_table_update_task.go | 2 +- .../tasks/security_group_cache_delete_task.go | 2 +- .../tasks/security_group_delete_task.go | 2 +- .../tasks/security_group_sync_rules_task.go | 2 +- pkg/compute/tasks/server_sku_create_task.go | 2 +- pkg/compute/tasks/server_sku_delete_task.go | 2 +- pkg/compute/tasks/snapshot_delete_task.go | 2 +- .../vpc_peering_connection_create_task.go | 2 +- .../vpc_peering_connection_delete_task.go | 2 +- pkg/compute/tasks/waf_create_task.go | 2 +- pkg/compute/tasks/waf_delete_task.go | 2 +- .../tasks/waf_instance_remote_update_task.go | 2 +- .../tasks/waf_ipset_cache_delete_task.go | 2 +- pkg/compute/tasks/waf_ipset_delete_task.go | 2 +- .../tasks/waf_regexset_cache_delete_task.go | 2 +- pkg/compute/tasks/waf_regexset_delete_task.go | 2 +- pkg/compute/tasks/waf_rule_create_task.go | 2 +- pkg/compute/tasks/waf_rule_delete_task.go | 2 +- pkg/compute/tasks/waf_rule_update_task.go | 2 +- pkg/esxi/options/options.go | 3 +- pkg/esxi/service/esxi_agent_service.go | 2 +- pkg/hostman/guestman/arch/arm.go | 4 +- pkg/hostman/guestman/arch/x86.go | 2 +- pkg/hostman/guestman/esxi.go | 2 +- pkg/hostman/guestman/guesthelper.go | 2 +- pkg/hostman/guestman/qemu-kvm.go | 6 +- pkg/hostman/guestman/qemu/qemu.go | 4 +- pkg/hostman/monitor/qga/qga.go | 7 +- pkg/hostman/storageman/core.go | 2 +- pkg/hostman/storageman/disk_agent.go | 4 +- pkg/hostman/storageman/disk_local.go | 2 +- pkg/hostman/storageman/disk_rbd.go | 2 +- .../storageman/diskhandlers/diskhandler.go | 2 +- pkg/hostman/storageman/imagecache_local.go | 2 +- .../storageman/imagecachemanager_agent.go | 6 +- pkg/hostman/storageman/storage_agent.go | 6 +- pkg/hostman/storageman/storage_local.go | 2 +- pkg/hostman/storageman/storage_nas.go | 2 +- pkg/hostman/storageman/storage_rbd.go | 4 +- pkg/image/drivers/s3/minio.go | 4 +- pkg/image/models/images.go | 2 +- pkg/keystone/tokens/handlers.go | 8 +- pkg/lbagent/utils/configdir.go | 2 +- pkg/mcclient/modules/compute/mod_buckets.go | 2 +- .../modules/compute/mod_cloudproviders.go | 2 +- .../modules/compute/mod_cloudregions.go | 2 +- pkg/mcclient/options/cloudaccounts.go | 2 +- pkg/monitor/alerting/ticker.go | 14 +- pkg/monitor/notifydrivers/feishu/types.go | 4 +- pkg/multicloud/aliyun/access_groups.go | 329 --- pkg/multicloud/aliyun/bucket.go | 778 -------- pkg/multicloud/aliyun/business.go | 126 -- pkg/multicloud/aliyun/cdn.go | 315 --- pkg/multicloud/aliyun/charge.go | 42 - .../aliyun/cloud_enterprise_network.go | 394 ---- pkg/multicloud/aliyun/dbinstance.go | 908 --------- pkg/multicloud/aliyun/dbinstance_account.go | 178 -- pkg/multicloud/aliyun/dbinstance_backup.go | 357 ---- pkg/multicloud/aliyun/dbinstance_database.go | 118 -- pkg/multicloud/aliyun/dbinstance_privilege.go | 55 - pkg/multicloud/aliyun/disk.go | 427 ---- pkg/multicloud/aliyun/dns_domain.go | 437 ---- pkg/multicloud/aliyun/doc.go | 15 - pkg/multicloud/aliyun/eip.go | 395 ---- pkg/multicloud/aliyun/elastic_search.go | 373 ---- pkg/multicloud/aliyun/elasticcache_account.go | 212 -- pkg/multicloud/aliyun/elasticcache_acl.go | 106 - pkg/multicloud/aliyun/elasticcache_backup.go | 143 -- .../aliyun/elasticcache_instance.go | 990 --------- .../aliyun/elasticcache_parameter.go | 86 - pkg/multicloud/aliyun/events.go | 186 -- pkg/multicloud/aliyun/filesystem.go | 362 ---- pkg/multicloud/aliyun/host.go | 295 --- pkg/multicloud/aliyun/image.go | 398 ---- pkg/multicloud/aliyun/instance.go | 1190 ----------- pkg/multicloud/aliyun/instancenic.go | 234 --- pkg/multicloud/aliyun/kafka.go | 320 --- pkg/multicloud/aliyun/kube_cluster.go | 258 --- pkg/multicloud/aliyun/kube_node.go | 114 -- pkg/multicloud/aliyun/kube_node_pools.go | 156 -- .../aliyun/latitud_and_longitude.go | 49 - pkg/multicloud/aliyun/loadbalancer.go | 494 ----- pkg/multicloud/aliyun/loadbalanceracl.go | 162 -- pkg/multicloud/aliyun/loadbalancerbackend.go | 117 -- .../aliyun/loadbalancerbackendgroup.go | 277 --- .../aliyun/loadbalancerdefaultbackend.go | 115 -- .../aliyun/loadbalancerdefaultbackendgroup.go | 159 -- .../aliyun/loadbalancerhttplistener.go | 379 ---- .../aliyun/loadbalancerhttpslistener.go | 409 ---- .../aliyun/loadbalancerlistenerrule.go | 182 -- .../aliyun/loadbalancermasterslavebackend.go | 92 - .../loadbalancermasterslavebackendgroup.go | 214 -- .../aliyun/loadbalancerservercertificate.go | 139 -- .../aliyun/loadbalancertcplistener.go | 368 ---- .../aliyun/loadbalancerudplistener.go | 294 --- pkg/multicloud/aliyun/mongodb.go | 523 ----- pkg/multicloud/aliyun/monitor.go | 634 ------ pkg/multicloud/aliyun/mount_target.go | 158 -- pkg/multicloud/aliyun/natdtable.go | 187 -- pkg/multicloud/aliyun/natgateway.go | 381 ---- pkg/multicloud/aliyun/natstable.go | 221 -- pkg/multicloud/aliyun/networkinterfaces.go | 167 -- pkg/multicloud/aliyun/objects.go | 112 -- pkg/multicloud/aliyun/private_zone.go | 405 ---- pkg/multicloud/aliyun/project.go | 145 -- pkg/multicloud/aliyun/provider/doc.go | 15 - pkg/multicloud/aliyun/provider/provider.go | 513 ----- pkg/multicloud/aliyun/quota.go | 136 -- pkg/multicloud/aliyun/ram_group.go | 325 --- pkg/multicloud/aliyun/ram_policy.go | 316 --- pkg/multicloud/aliyun/ram_role.go | 224 --- pkg/multicloud/aliyun/ram_user.go | 406 ---- pkg/multicloud/aliyun/ramimage.go | 203 -- pkg/multicloud/aliyun/region.go | 1255 ------------ pkg/multicloud/aliyun/resource_tags.go | 191 -- pkg/multicloud/aliyun/routetable.go | 341 ---- pkg/multicloud/aliyun/saml_provider.go | 201 -- pkg/multicloud/aliyun/securitygroup.go | 551 ----- pkg/multicloud/aliyun/shell/access_groups.go | 87 - pkg/multicloud/aliyun/shell/bucket.go | 21 - pkg/multicloud/aliyun/shell/business.go | 61 - pkg/multicloud/aliyun/shell/cdn.go | 63 - pkg/multicloud/aliyun/shell/cen_route.go | 83 - .../aliyun/shell/cloud_enterprise_network.go | 129 -- pkg/multicloud/aliyun/shell/dbinstance.go | 111 -- .../aliyun/shell/dbinstance_account.go | 70 - .../aliyun/shell/dbinstance_backup.go | 80 - .../aliyun/shell/dbinstance_database.go | 59 - pkg/multicloud/aliyun/shell/disk.go | 49 - pkg/multicloud/aliyun/shell/dns_domain.go | 185 -- pkg/multicloud/aliyun/shell/doc.go | 15 - pkg/multicloud/aliyun/shell/eip.go | 73 - pkg/multicloud/aliyun/shell/elasticcache.go | 87 - pkg/multicloud/aliyun/shell/elk.go | 53 - pkg/multicloud/aliyun/shell/events.go | 53 - pkg/multicloud/aliyun/shell/filesystem.go | 54 - pkg/multicloud/aliyun/shell/image.go | 103 - pkg/multicloud/aliyun/shell/instance.go | 232 --- pkg/multicloud/aliyun/shell/instancetype.go | 48 - pkg/multicloud/aliyun/shell/kafka.go | 62 - pkg/multicloud/aliyun/shell/keypair.go | 48 - pkg/multicloud/aliyun/shell/kube_cluster.go | 68 - pkg/multicloud/aliyun/shell/kube_node.go | 37 - .../aliyun/shell/kube_node_pools.go | 35 - pkg/multicloud/aliyun/shell/loadbalancer.go | 47 - .../aliyun/shell/loadbalanceracl.go | 33 - .../aliyun/shell/loadbalancerbackend.go | 43 - .../aliyun/shell/loadbalancerbackendgroup.go | 44 - .../aliyun/shell/loadbalancercertificate.go | 33 - .../aliyun/shell/loadbalancerlistener.go | 63 - .../aliyun/shell/loadbalancerlistenerrule.go | 35 - pkg/multicloud/aliyun/shell/mongodb.go | 88 - pkg/multicloud/aliyun/shell/monitor.go | 99 - pkg/multicloud/aliyun/shell/mount_target.go | 56 - pkg/multicloud/aliyun/shell/natgateway.go | 167 -- .../aliyun/shell/networkinterface.go | 36 - pkg/multicloud/aliyun/shell/oss.go | 202 -- pkg/multicloud/aliyun/shell/printutils.go | 25 - pkg/multicloud/aliyun/shell/private_zone.go | 207 -- pkg/multicloud/aliyun/shell/quota.go | 33 - pkg/multicloud/aliyun/shell/ram_group.go | 109 - pkg/multicloud/aliyun/shell/ram_policy.go | 84 - pkg/multicloud/aliyun/shell/ram_role.go | 117 -- pkg/multicloud/aliyun/shell/ram_user.go | 128 -- pkg/multicloud/aliyun/shell/region.go | 32 - pkg/multicloud/aliyun/shell/resource_tag.go | 77 - pkg/multicloud/aliyun/shell/resourcegroup.go | 62 - pkg/multicloud/aliyun/shell/routetable.go | 52 - pkg/multicloud/aliyun/shell/saml_provider.go | 59 - pkg/multicloud/aliyun/shell/secgroup.go | 77 - pkg/multicloud/aliyun/shell/snapshot.go | 68 - .../aliyun/shell/snapshot_policy.go | 95 - pkg/multicloud/aliyun/shell/tablestore.go | 35 - pkg/multicloud/aliyun/shell/task.go | 56 - pkg/multicloud/aliyun/shell/vpc.go | 75 - pkg/multicloud/aliyun/shell/vrouter.go | 35 - pkg/multicloud/aliyun/shell/vswitch.go | 55 - pkg/multicloud/aliyun/shell/waf.go | 73 - pkg/multicloud/aliyun/shell/zone.go | 40 - pkg/multicloud/aliyun/snapshot.go | 223 --- pkg/multicloud/aliyun/snapshot_policy.go | 303 --- pkg/multicloud/aliyun/storage.go | 191 -- pkg/multicloud/aliyun/storagecache.go | 355 ---- pkg/multicloud/aliyun/tablestore.go | 107 - pkg/multicloud/aliyun/vpc.go | 333 ---- pkg/multicloud/aliyun/vswitch.go | 276 --- pkg/multicloud/aliyun/waf.go | 61 - pkg/multicloud/aliyun/wire.go | 140 -- pkg/multicloud/aliyun/zone.go | 304 --- pkg/multicloud/apsara/bucket.go | 541 ----- pkg/multicloud/apsara/charge.go | 42 - pkg/multicloud/apsara/dbinstance.go | 802 -------- pkg/multicloud/apsara/dbinstance_account.go | 178 -- pkg/multicloud/apsara/dbinstance_backup.go | 304 --- pkg/multicloud/apsara/dbinstance_database.go | 118 -- pkg/multicloud/apsara/dbinstance_privilege.go | 55 - pkg/multicloud/apsara/disk.go | 439 ---- pkg/multicloud/apsara/doc.go | 15 - pkg/multicloud/apsara/eip.go | 378 ---- pkg/multicloud/apsara/elasticcache_account.go | 212 -- pkg/multicloud/apsara/elasticcache_acl.go | 106 - pkg/multicloud/apsara/elasticcache_backup.go | 143 -- .../apsara/elasticcache_instance.go | 941 --------- .../apsara/elasticcache_parameter.go | 86 - pkg/multicloud/apsara/host.go | 295 --- pkg/multicloud/apsara/image.go | 390 ---- pkg/multicloud/apsara/instance.go | 1043 ---------- pkg/multicloud/apsara/instancenic.go | 52 - pkg/multicloud/apsara/instancetype.go | 194 -- pkg/multicloud/apsara/ipv6_gateway.go | 132 -- pkg/multicloud/apsara/loadbalancer.go | 410 ---- pkg/multicloud/apsara/loadbalanceracl.go | 160 -- pkg/multicloud/apsara/loadbalancerbackend.go | 114 -- .../apsara/loadbalancerbackendgroup.go | 274 --- .../apsara/loadbalancerdefaultbackend.go | 112 -- .../apsara/loadbalancerdefaultbackendgroup.go | 156 -- .../apsara/loadbalancerhttplistener.go | 376 ---- .../apsara/loadbalancerhttpslistener.go | 406 ---- .../apsara/loadbalancerlistenerrule.go | 173 -- .../apsara/loadbalancermasterslavebackend.go | 89 - .../loadbalancermasterslavebackendgroup.go | 211 -- .../apsara/loadbalancerservercertificate.go | 135 -- .../apsara/loadbalancertcplistener.go | 365 ---- .../apsara/loadbalancerudplistener.go | 291 --- pkg/multicloud/apsara/monitor.go | 457 ----- pkg/multicloud/apsara/natdtable.go | 187 -- pkg/multicloud/apsara/natgateway.go | 227 --- pkg/multicloud/apsara/natstable.go | 221 -- pkg/multicloud/apsara/networkinterfaces.go | 167 -- pkg/multicloud/apsara/objects.go | 112 -- pkg/multicloud/apsara/project.go | 149 -- pkg/multicloud/apsara/provider/doc.go | 15 - pkg/multicloud/apsara/provider/provider.go | 246 --- pkg/multicloud/apsara/quota.go | 136 -- pkg/multicloud/apsara/ram_group.go | 325 --- pkg/multicloud/apsara/ram_policy.go | 316 --- pkg/multicloud/apsara/ram_user.go | 406 ---- pkg/multicloud/apsara/ramimage.go | 201 -- pkg/multicloud/apsara/region.go | 1100 ---------- pkg/multicloud/apsara/resource_tags.go | 244 --- pkg/multicloud/apsara/routetable.go | 319 --- pkg/multicloud/apsara/securitygroup.go | 512 ----- pkg/multicloud/apsara/shell/bucket.go | 58 - pkg/multicloud/apsara/shell/dbinstance.go | 102 - .../apsara/shell/dbinstance_account.go | 70 - .../apsara/shell/dbinstance_backup.go | 64 - .../apsara/shell/dbinstance_database.go | 59 - pkg/multicloud/apsara/shell/disk.go | 49 - pkg/multicloud/apsara/shell/doc.go | 15 - pkg/multicloud/apsara/shell/eip.go | 70 - pkg/multicloud/apsara/shell/elasticcache.go | 87 - pkg/multicloud/apsara/shell/image.go | 88 - pkg/multicloud/apsara/shell/instance.go | 223 --- pkg/multicloud/apsara/shell/instancetype.go | 48 - pkg/multicloud/apsara/shell/ipv6_gateway.go | 50 - pkg/multicloud/apsara/shell/keypair.go | 48 - pkg/multicloud/apsara/shell/loadbalancer.go | 47 - .../apsara/shell/loadbalanceracl.go | 33 - .../apsara/shell/loadbalancerbackend.go | 43 - .../apsara/shell/loadbalancerbackendgroup.go | 44 - .../apsara/shell/loadbalancercertificate.go | 33 - .../apsara/shell/loadbalancerlistener.go | 63 - .../apsara/shell/loadbalancerlistenerrule.go | 35 - pkg/multicloud/apsara/shell/monitor.go | 38 - pkg/multicloud/apsara/shell/natgateway.go | 156 -- .../apsara/shell/networkinterface.go | 36 - pkg/multicloud/apsara/shell/printutils.go | 25 - pkg/multicloud/apsara/shell/quota.go | 33 - pkg/multicloud/apsara/shell/ram_group.go | 109 - pkg/multicloud/apsara/shell/ram_policy.go | 84 - pkg/multicloud/apsara/shell/ram_role.go | 102 - pkg/multicloud/apsara/shell/ram_user.go | 128 -- pkg/multicloud/apsara/shell/region.go | 32 - pkg/multicloud/apsara/shell/resource_tag.go | 59 - pkg/multicloud/apsara/shell/resourcegroup.go | 86 - pkg/multicloud/apsara/shell/routetable.go | 52 - pkg/multicloud/apsara/shell/secgroup.go | 68 - pkg/multicloud/apsara/shell/snapshot.go | 68 - .../apsara/shell/snapshot_policy.go | 95 - pkg/multicloud/apsara/shell/task.go | 56 - pkg/multicloud/apsara/shell/vpc.go | 44 - pkg/multicloud/apsara/shell/vrouter.go | 35 - pkg/multicloud/apsara/shell/vswitch.go | 55 - pkg/multicloud/apsara/shell/zone.go | 40 - pkg/multicloud/apsara/snapshot.go | 219 -- pkg/multicloud/apsara/snapshot_policy.go | 300 --- pkg/multicloud/apsara/storage.go | 179 -- pkg/multicloud/apsara/storagecache.go | 324 --- pkg/multicloud/apsara/vpc.go | 317 --- pkg/multicloud/apsara/vswitch.go | 272 --- pkg/multicloud/apsara/wire.go | 140 -- pkg/multicloud/apsara/zone.go | 288 --- pkg/multicloud/aws/aws_test.go | 30 - pkg/multicloud/aws/bucket.go | 800 -------- pkg/multicloud/aws/cloudtrail.go | 201 -- pkg/multicloud/aws/dbinstance.go | 655 ------ pkg/multicloud/aws/dbinstance_account.go | 30 - pkg/multicloud/aws/dbinstance_database.go | 47 - pkg/multicloud/aws/dbinstance_snapshot.go | 194 -- pkg/multicloud/aws/disk.go | 552 ----- pkg/multicloud/aws/doc.go | 15 - pkg/multicloud/aws/eip.go | 296 --- pkg/multicloud/aws/host.go | 288 --- pkg/multicloud/aws/iam_group.go | 329 --- pkg/multicloud/aws/iam_policy.go | 476 ----- pkg/multicloud/aws/iam_role.go | 211 -- pkg/multicloud/aws/iam_user.go | 399 ---- pkg/multicloud/aws/image.go | 589 ------ pkg/multicloud/aws/imageowners_test.go | 49 - pkg/multicloud/aws/instance.go | 1376 ------------- pkg/multicloud/aws/instancenic.go | 149 -- pkg/multicloud/aws/keypair.go | 175 -- pkg/multicloud/aws/keypair_test.go | 44 - pkg/multicloud/aws/latitude_and_longitude.go | 49 - pkg/multicloud/aws/loadbalancer.go | 516 ----- pkg/multicloud/aws/loadbalancerbackend.go | 114 -- .../aws/loadbalancerbackendgroup.go | 521 ----- pkg/multicloud/aws/loadbalancercert.go | 199 -- pkg/multicloud/aws/loadbalancerlistener.go | 768 ------- .../aws/loadbalancerlistenerrule.go | 490 ----- pkg/multicloud/aws/monitor.go | 193 -- pkg/multicloud/aws/natgateway.go | 244 --- pkg/multicloud/aws/network.go | 273 --- pkg/multicloud/aws/networkinterface.go | 100 - pkg/multicloud/aws/organizations.go | 296 --- pkg/multicloud/aws/provider/doc.go | 15 - pkg/multicloud/aws/provider/provider.go | 410 ---- pkg/multicloud/aws/region.go | 1071 ---------- pkg/multicloud/aws/resource_tag.go | 121 -- pkg/multicloud/aws/routetable.go | 365 ---- pkg/multicloud/aws/s3object.go | 116 -- pkg/multicloud/aws/saml_provider.go | 179 -- pkg/multicloud/aws/securitygroup.go | 491 ----- pkg/multicloud/aws/shell/bucket.go | 21 - pkg/multicloud/aws/shell/cloudtrail.go | 38 - pkg/multicloud/aws/shell/dbinstance.go | 58 - .../aws/shell/dbinstance_parameter.go | 36 - .../aws/shell/dbinstance_snapshot.go | 37 - pkg/multicloud/aws/shell/disk.go | 66 - pkg/multicloud/aws/shell/doc.go | 15 - pkg/multicloud/aws/shell/eip.go | 76 - pkg/multicloud/aws/shell/elasticache.go | 94 - pkg/multicloud/aws/shell/hostedzone.go | 209 -- pkg/multicloud/aws/shell/iam_group.go | 133 -- pkg/multicloud/aws/shell/iam_policy.go | 126 -- pkg/multicloud/aws/shell/iam_role.go | 91 - pkg/multicloud/aws/shell/iam_user.go | 143 -- pkg/multicloud/aws/shell/image.go | 55 - pkg/multicloud/aws/shell/instance.go | 205 -- pkg/multicloud/aws/shell/instancetype.go | 35 - pkg/multicloud/aws/shell/keypair.go | 48 - pkg/multicloud/aws/shell/monitor.go | 38 - pkg/multicloud/aws/shell/natgateway.go | 45 - pkg/multicloud/aws/shell/network.go | 35 - pkg/multicloud/aws/shell/networkinterface.go | 34 - pkg/multicloud/aws/shell/organizations.go | 94 - pkg/multicloud/aws/shell/printutils.go | 25 - pkg/multicloud/aws/shell/region.go | 33 - pkg/multicloud/aws/shell/reservedinstance.go | 41 - pkg/multicloud/aws/shell/resource_tag.go | 53 - pkg/multicloud/aws/shell/routetable.go | 63 - pkg/multicloud/aws/shell/s3.go | 133 -- pkg/multicloud/aws/shell/saml_provider.go | 79 - pkg/multicloud/aws/shell/secgroup.go | 84 - pkg/multicloud/aws/shell/snapshot.go | 59 - pkg/multicloud/aws/shell/sts.go | 33 - pkg/multicloud/aws/shell/vpc.go | 118 -- pkg/multicloud/aws/shell/waf.go | 210 -- pkg/multicloud/aws/shell/zone.go | 40 - pkg/multicloud/aws/snapshot.go | 235 --- pkg/multicloud/aws/storage.go | 166 -- pkg/multicloud/aws/storagecache.go | 496 ----- pkg/multicloud/aws/utils.go | 513 ----- pkg/multicloud/aws/vpc.go | 723 ------- pkg/multicloud/aws/vpc_peering_connection.go | 323 --- pkg/multicloud/aws/waf.go | 545 ----- pkg/multicloud/aws/wire.go | 141 -- pkg/multicloud/aws/zone.go | 209 -- pkg/multicloud/azure/app_gateways.go | 216 -- pkg/multicloud/azure/app_service_plan.go | 199 -- pkg/multicloud/azure/cloudgroup.go | 247 --- pkg/multicloud/azure/cloudpolicy.go | 207 -- pkg/multicloud/azure/clouduser.go | 359 ---- pkg/multicloud/azure/concurrent/doc.go | 15 - pkg/multicloud/azure/dbinstance.go | 406 ---- pkg/multicloud/azure/dbinstance_account.go | 29 - pkg/multicloud/azure/dbinstance_database.go | 89 - pkg/multicloud/azure/disk.go | 337 ---- pkg/multicloud/azure/doc.go | 15 - pkg/multicloud/azure/eip.go | 273 --- pkg/multicloud/azure/enrollment_account.go | 100 - pkg/multicloud/azure/event.go | 154 -- pkg/multicloud/azure/host.go | 309 --- pkg/multicloud/azure/image.go | 607 ------ pkg/multicloud/azure/instance.go | 1122 ----------- pkg/multicloud/azure/instancenic.go | 235 --- pkg/multicloud/azure/kube_cluster.go | 220 -- pkg/multicloud/azure/kube_node_pools.go | 64 - pkg/multicloud/azure/loadbalancer.go | 751 ------- pkg/multicloud/azure/loadbalancerbackend.go | 99 - .../azure/loadbalancerbackendgroup.go | 221 -- pkg/multicloud/azure/loadbalancercert.go | 183 -- pkg/multicloud/azure/loadbalancerlistener.go | 600 ------ .../azure/loadbalancerlistenerrule.go | 192 -- pkg/multicloud/azure/monitor.go | 506 ----- pkg/multicloud/azure/network.go | 125 -- pkg/multicloud/azure/progress/doc.go | 15 - pkg/multicloud/azure/provider/doc.go | 15 - pkg/multicloud/azure/provider/provider.go | 297 --- pkg/multicloud/azure/rds_sqlserver.go | 215 -- pkg/multicloud/azure/redis.go | 402 ---- pkg/multicloud/azure/region.go | 731 ------- pkg/multicloud/azure/resourcegroup.go | 88 - pkg/multicloud/azure/saml_provider.go | 137 -- pkg/multicloud/azure/securitygroup.go | 489 ----- pkg/multicloud/azure/service.go | 95 - pkg/multicloud/azure/shell/account.go | 33 - pkg/multicloud/azure/shell/app_gateways.go | 33 - .../azure/shell/app_service_plan.go | 81 - pkg/multicloud/azure/shell/bucket.go | 23 - pkg/multicloud/azure/shell/cloudgroup.go | 83 - pkg/multicloud/azure/shell/cloudpolicy.go | 80 - pkg/multicloud/azure/shell/clouduser.go | 98 - pkg/multicloud/azure/shell/dbinstance.go | 48 - .../azure/shell/dbinstance_databases.go | 36 - .../azure/shell/dbinstance_networkRules.go | 36 - .../azure/shell/dbinstance_paraments.go | 36 - pkg/multicloud/azure/shell/disk.go | 86 - pkg/multicloud/azure/shell/doc.go | 15 - pkg/multicloud/azure/shell/eip.go | 95 - .../azure/shell/enrollment_account.go | 33 - pkg/multicloud/azure/shell/event.go | 37 - pkg/multicloud/azure/shell/image.go | 114 -- pkg/multicloud/azure/shell/instance.go | 250 --- pkg/multicloud/azure/shell/kube_cluster.go | 47 - pkg/multicloud/azure/shell/loadbalancer.go | 145 -- pkg/multicloud/azure/shell/loganalytics.go | 52 - pkg/multicloud/azure/shell/monitor.go | 39 - pkg/multicloud/azure/shell/network.go | 95 - pkg/multicloud/azure/shell/policy.go | 60 - pkg/multicloud/azure/shell/printutils.go | 25 - pkg/multicloud/azure/shell/redis.go | 55 - pkg/multicloud/azure/shell/region.go | 47 - pkg/multicloud/azure/shell/resourcegroup.go | 78 - pkg/multicloud/azure/shell/saml_provider.go | 50 - pkg/multicloud/azure/shell/secgroup.go | 78 - pkg/multicloud/azure/shell/service.go | 55 - pkg/multicloud/azure/shell/snapshot.go | 77 - pkg/multicloud/azure/shell/storageaccount.go | 184 -- pkg/multicloud/azure/shell/subscription.go | 57 - pkg/multicloud/azure/shell/usage.go | 35 - pkg/multicloud/azure/shell/vpc.go | 73 - pkg/multicloud/azure/shell/waf.go | 70 - pkg/multicloud/azure/shell/web_app.go | 68 - pkg/multicloud/azure/snapshot.go | 173 -- pkg/multicloud/azure/storage.go | 155 -- pkg/multicloud/azure/storageaccount.go | 1305 ------------ pkg/multicloud/azure/storagecache.go | 290 --- pkg/multicloud/azure/subscription.go | 40 - pkg/multicloud/azure/usage.go | 82 - pkg/multicloud/azure/vpc.go | 167 -- pkg/multicloud/azure/waf.go | 656 ------ pkg/multicloud/azure/web_app.go | 316 --- pkg/multicloud/azure/wire.go | 120 -- pkg/multicloud/azure/zone.go | 178 -- pkg/multicloud/bingocloud/cluster.go | 105 - pkg/multicloud/bingocloud/disk.go | 255 --- pkg/multicloud/bingocloud/doc.go | 15 - pkg/multicloud/bingocloud/eip.go | 174 -- pkg/multicloud/bingocloud/image.go | 245 --- pkg/multicloud/bingocloud/instance.go | 384 ---- pkg/multicloud/bingocloud/instancenic.go | 113 -- pkg/multicloud/bingocloud/monitor.go | 144 -- pkg/multicloud/bingocloud/network.go | 199 -- pkg/multicloud/bingocloud/node.go | 270 --- pkg/multicloud/bingocloud/provider/doc.go | 15 - .../bingocloud/provider/provider.go | 162 -- pkg/multicloud/bingocloud/region.go | 175 -- pkg/multicloud/bingocloud/secgroup.go | 190 -- pkg/multicloud/bingocloud/shell/cluster.go | 33 - pkg/multicloud/bingocloud/shell/disk.go | 36 - pkg/multicloud/bingocloud/shell/doc.go | 15 - pkg/multicloud/bingocloud/shell/eip.go | 36 - pkg/multicloud/bingocloud/shell/host.go | 34 - pkg/multicloud/bingocloud/shell/image.go | 35 - pkg/multicloud/bingocloud/shell/instance.go | 51 - pkg/multicloud/bingocloud/shell/monitor.go | 38 - pkg/multicloud/bingocloud/shell/network.go | 36 - pkg/multicloud/bingocloud/shell/node.go | 35 - pkg/multicloud/bingocloud/shell/printutils.go | 25 - pkg/multicloud/bingocloud/shell/region.go | 33 - pkg/multicloud/bingocloud/shell/secgroup.go | 36 - pkg/multicloud/bingocloud/shell/storage.go | 34 - pkg/multicloud/bingocloud/shell/vpc.go | 34 - pkg/multicloud/bingocloud/shell/zone.go | 33 - pkg/multicloud/bingocloud/storage.go | 173 -- pkg/multicloud/bingocloud/storagecache.go | 71 - pkg/multicloud/bingocloud/vpc.go | 142 -- pkg/multicloud/bingocloud/wire.go | 94 - pkg/multicloud/cloudpods/disk.go | 281 --- pkg/multicloud/cloudpods/doc.go | 15 - pkg/multicloud/cloudpods/eip.go | 182 -- pkg/multicloud/cloudpods/host.go | 289 --- pkg/multicloud/cloudpods/image.go | 219 -- pkg/multicloud/cloudpods/instance.go | 565 ------ pkg/multicloud/cloudpods/instancenic.go | 101 - pkg/multicloud/cloudpods/network.go | 136 -- pkg/multicloud/cloudpods/project.go | 70 - pkg/multicloud/cloudpods/provider/doc.go | 15 - pkg/multicloud/cloudpods/provider/provider.go | 160 -- pkg/multicloud/cloudpods/region.go | 130 -- pkg/multicloud/cloudpods/secgroup.go | 206 -- pkg/multicloud/cloudpods/shell/disk.go | 35 - pkg/multicloud/cloudpods/shell/doc.go | 15 - pkg/multicloud/cloudpods/shell/hosts.go | 34 - pkg/multicloud/cloudpods/shell/image.go | 47 - pkg/multicloud/cloudpods/shell/instance.go | 72 - pkg/multicloud/cloudpods/shell/network.go | 34 - pkg/multicloud/cloudpods/shell/printutils.go | 25 - pkg/multicloud/cloudpods/shell/region.go | 33 - pkg/multicloud/cloudpods/shell/secgroup.go | 46 - pkg/multicloud/cloudpods/shell/vpc.go | 33 - pkg/multicloud/cloudpods/shell/wire.go | 35 - pkg/multicloud/cloudpods/shell/zones.go | 33 - pkg/multicloud/cloudpods/sku.go | 160 -- pkg/multicloud/cloudpods/snapshot.go | 111 -- pkg/multicloud/cloudpods/storage.go | 139 -- pkg/multicloud/cloudpods/storagecache.go | 128 -- pkg/multicloud/cloudpods/vpc.go | 151 -- pkg/multicloud/cloudpods/wire.go | 120 -- pkg/multicloud/cloudpods/zone.go | 89 - pkg/multicloud/clouduser.go | 36 - pkg/multicloud/ctyun/disk.go | 599 ------ pkg/multicloud/ctyun/doc.go | 15 - pkg/multicloud/ctyun/eip.go | 398 ---- pkg/multicloud/ctyun/host.go | 288 --- pkg/multicloud/ctyun/image.go | 214 -- pkg/multicloud/ctyun/instance.go | 1306 ------------ pkg/multicloud/ctyun/instancenic.go | 94 - pkg/multicloud/ctyun/latitud_and_longitude.go | 62 - pkg/multicloud/ctyun/network.go | 295 --- pkg/multicloud/ctyun/project.go | 70 - pkg/multicloud/ctyun/provider/doc.go | 15 - pkg/multicloud/ctyun/provider/provider.go | 199 -- pkg/multicloud/ctyun/region.go | 488 ----- pkg/multicloud/ctyun/securitygroup.go | 364 ---- pkg/multicloud/ctyun/shell/crm.go | 36 - pkg/multicloud/ctyun/shell/disk.go | 86 - .../ctyun/shell/diskbackuppolicy.go | 77 - pkg/multicloud/ctyun/shell/doc.go | 15 - pkg/multicloud/ctyun/shell/eip.go | 49 - pkg/multicloud/ctyun/shell/image.go | 34 - pkg/multicloud/ctyun/shell/instance.go | 57 - pkg/multicloud/ctyun/shell/job.go | 52 - pkg/multicloud/ctyun/shell/network.go | 51 - pkg/multicloud/ctyun/shell/printutils.go | 25 - pkg/multicloud/ctyun/shell/project.go | 33 - pkg/multicloud/ctyun/shell/region.go | 30 - pkg/multicloud/ctyun/shell/secgroup.go | 75 - pkg/multicloud/ctyun/shell/vpc.go | 46 - pkg/multicloud/ctyun/storage.go | 164 -- pkg/multicloud/ctyun/storagecache.go | 105 - pkg/multicloud/ctyun/vpc.go | 232 --- pkg/multicloud/ctyun/wire.go | 141 -- pkg/multicloud/ctyun/zone.go | 151 -- pkg/multicloud/doc.go | 15 - pkg/multicloud/ecloud/client.go | 322 --- pkg/multicloud/ecloud/client_test.go | 57 - pkg/multicloud/ecloud/disk.go | 276 --- pkg/multicloud/ecloud/doc.go | 15 - pkg/multicloud/ecloud/eip.go | 171 -- pkg/multicloud/ecloud/host.go | 172 -- pkg/multicloud/ecloud/image.go | 196 -- pkg/multicloud/ecloud/instance.go | 528 ----- pkg/multicloud/ecloud/instancenic.go | 87 - .../ecloud/latitud_and_longitude.go | 51 - pkg/multicloud/ecloud/monitor.go | 206 -- pkg/multicloud/ecloud/network.go | 190 -- pkg/multicloud/ecloud/provider/doc.go | 15 - pkg/multicloud/ecloud/provider/provider.go | 185 -- pkg/multicloud/ecloud/region.go | 355 ---- pkg/multicloud/ecloud/shell/disk.go | 33 - pkg/multicloud/ecloud/shell/doc.go | 15 - pkg/multicloud/ecloud/shell/image.go | 34 - pkg/multicloud/ecloud/shell/instance.go | 68 - pkg/multicloud/ecloud/shell/monitor.go | 50 - pkg/multicloud/ecloud/shell/network.go | 39 - pkg/multicloud/ecloud/shell/printutils.go | 25 - pkg/multicloud/ecloud/shell/region.go | 38 - pkg/multicloud/ecloud/shell/vpc.go | 33 - pkg/multicloud/ecloud/snapshot.go | 130 -- pkg/multicloud/ecloud/storage.go | 166 -- pkg/multicloud/ecloud/storagecache.go | 100 - pkg/multicloud/ecloud/vpc.go | 178 -- pkg/multicloud/ecloud/wire.go | 140 -- pkg/multicloud/ecloud/zone.go | 148 -- pkg/multicloud/esxi/cluster.go | 110 - pkg/multicloud/esxi/datacenter.go | 596 ------ pkg/multicloud/esxi/doc.go | 15 - pkg/multicloud/esxi/host.go | 1769 ----------------- pkg/multicloud/esxi/host_test.go | 41 - pkg/multicloud/esxi/image.go | 158 -- pkg/multicloud/esxi/manager.go | 743 ------- pkg/multicloud/esxi/manager_test.go | 38 - pkg/multicloud/esxi/mobase_test.go | 28 - pkg/multicloud/esxi/monitor.go | 292 --- pkg/multicloud/esxi/provider/doc.go | 15 - pkg/multicloud/esxi/provider/provider.go | 232 --- pkg/multicloud/esxi/resourcepool.go | 58 - pkg/multicloud/esxi/shell/cluster.go | 86 - pkg/multicloud/esxi/shell/datacenter.go | 33 - pkg/multicloud/esxi/shell/doc.go | 15 - pkg/multicloud/esxi/shell/host.go | 120 -- pkg/multicloud/esxi/shell/ip.go | 154 -- pkg/multicloud/esxi/shell/monitor.go | 50 - pkg/multicloud/esxi/shell/network.go | 38 - pkg/multicloud/esxi/shell/resourcepool.go | 63 - pkg/multicloud/esxi/shell/store.go | 253 --- pkg/multicloud/esxi/shell/utils.go | 25 - pkg/multicloud/esxi/shell/virtualmachine.go | 348 ---- pkg/multicloud/esxi/snapshot.go | 87 - pkg/multicloud/esxi/storage.go | 1198 ----------- pkg/multicloud/esxi/storagecache.go | 292 --- pkg/multicloud/esxi/utils_test.go | 45 - pkg/multicloud/esxi/vcenter/doc.go | 15 - pkg/multicloud/esxi/virtualmachine.go | 1534 -------------- pkg/multicloud/google/bucket.go | 528 ----- pkg/multicloud/google/dbinstance.go | 636 ------ pkg/multicloud/google/dbinstance_account.go | 125 -- pkg/multicloud/google/dbinstance_backup.go | 171 -- pkg/multicloud/google/dbinstance_database.go | 105 - pkg/multicloud/google/disk.go | 274 --- pkg/multicloud/google/doc.go | 15 - pkg/multicloud/google/eip.go | 223 --- pkg/multicloud/google/globalnetwork.go | 136 -- pkg/multicloud/google/host.go | 189 -- pkg/multicloud/google/image.go | 270 --- pkg/multicloud/google/instance.go | 998 ---------- pkg/multicloud/google/instancenic.go | 65 - .../google/latitude_and_longitude.go | 97 - pkg/multicloud/google/loadbalancer.go | 480 ----- pkg/multicloud/google/loadbalancer_backend.go | 205 -- .../google/loadbalancer_backendgroup.go | 173 -- pkg/multicloud/google/loadbalancer_cert.go | 172 -- .../google/loadbalancer_listener.go | 596 ------ .../google/loadbalancer_listenerrule.go | 182 -- pkg/multicloud/google/machinetype.go | 57 - pkg/multicloud/google/monitor.go | 119 -- pkg/multicloud/google/network.go | 110 - pkg/multicloud/google/project.go | 99 - pkg/multicloud/google/provider/doc.go | 15 - pkg/multicloud/google/provider/provider.go | 315 --- pkg/multicloud/google/quota.go | 60 - pkg/multicloud/google/region.go | 833 -------- pkg/multicloud/google/resourcepolicy.go | 164 -- pkg/multicloud/google/s3object.go | 207 -- pkg/multicloud/google/securitygroup.go | 429 ---- pkg/multicloud/google/shell/bigquery.go | 35 - pkg/multicloud/google/shell/bucket.go | 97 - pkg/multicloud/google/shell/cloudbuild.go | 35 - pkg/multicloud/google/shell/dbinstance.go | 103 - .../google/shell/dbinstance_account.go | 44 - .../google/shell/dbinstance_backup.go | 44 - .../google/shell/dbinstance_database.go | 45 - pkg/multicloud/google/shell/disk.go | 107 - pkg/multicloud/google/shell/doc.go | 15 - pkg/multicloud/google/shell/eip.go | 67 - pkg/multicloud/google/shell/firewall.go | 49 - pkg/multicloud/google/shell/globalnetwork.go | 62 - pkg/multicloud/google/shell/iam.go | 146 -- pkg/multicloud/google/shell/image.go | 64 - pkg/multicloud/google/shell/instance.go | 230 --- pkg/multicloud/google/shell/loadbalancer.go | 214 -- pkg/multicloud/google/shell/machinetype.go | 49 - pkg/multicloud/google/shell/monitor.go | 38 - pkg/multicloud/google/shell/network.go | 67 - pkg/multicloud/google/shell/object.go | 160 -- pkg/multicloud/google/shell/printutils.go | 25 - pkg/multicloud/google/shell/project.go | 35 - pkg/multicloud/google/shell/region.go | 30 - pkg/multicloud/google/shell/resourcepolicy.go | 59 - pkg/multicloud/google/shell/skubilling.go | 82 - pkg/multicloud/google/shell/snapshot.go | 68 - pkg/multicloud/google/shell/storage.go | 74 - pkg/multicloud/google/shell/zone.go | 49 - pkg/multicloud/google/sku.go | 352 ---- pkg/multicloud/google/snapshot.go | 114 -- pkg/multicloud/google/storage.go | 156 -- pkg/multicloud/google/storagecache.go | 210 -- pkg/multicloud/google/vpc.go | 170 -- pkg/multicloud/google/wire.go | 94 - pkg/multicloud/google/zone.go | 128 -- pkg/multicloud/hcs/bucket.go | 803 -------- pkg/multicloud/hcs/dbinstance.go | 706 ------- pkg/multicloud/hcs/dbinstance_account.go | 125 -- pkg/multicloud/hcs/dbinstance_backup.go | 238 --- pkg/multicloud/hcs/dbinstance_database.go | 72 - pkg/multicloud/hcs/dbinstance_privilege.go | 43 - pkg/multicloud/hcs/dbinstance_skus.go | 273 --- pkg/multicloud/hcs/disk.go | 438 ---- pkg/multicloud/hcs/doc.go | 1 - pkg/multicloud/hcs/eip.go | 434 ---- pkg/multicloud/hcs/host.go | 254 --- pkg/multicloud/hcs/image.go | 466 ----- pkg/multicloud/hcs/instance.go | 1114 ----------- pkg/multicloud/hcs/instancenic.go | 86 - pkg/multicloud/hcs/instancetype.go | 223 --- pkg/multicloud/hcs/job.go | 105 - pkg/multicloud/hcs/loadbalancer.go | 601 ------ pkg/multicloud/hcs/loadbalancer_acl.go | 155 -- pkg/multicloud/hcs/loadbalancer_backend.go | 141 -- .../hcs/loadbalancer_backendgroup.go | 490 ----- pkg/multicloud/hcs/loadbalancer_cert.go | 182 -- pkg/multicloud/hcs/loadbalancer_listener.go | 643 ------ .../hcs/loadbalancer_listener_rule.go | 168 -- pkg/multicloud/hcs/monitor.go | 494 ----- pkg/multicloud/hcs/natdtable.go | 149 -- pkg/multicloud/hcs/natgateway.go | 265 --- pkg/multicloud/hcs/natstable.go | 142 -- pkg/multicloud/hcs/network.go | 167 -- pkg/multicloud/hcs/object.go | 104 - pkg/multicloud/hcs/port.go | 161 -- pkg/multicloud/hcs/project.go | 98 - pkg/multicloud/hcs/provider/doc.go | 1 - pkg/multicloud/hcs/provider/provider.go | 217 -- pkg/multicloud/hcs/redis.go | 608 ------ pkg/multicloud/hcs/region.go | 332 ---- pkg/multicloud/hcs/routetables.go | 214 -- pkg/multicloud/hcs/securitygroup.go | 340 ---- pkg/multicloud/hcs/shell/bucket.go | 43 - pkg/multicloud/hcs/shell/dbinstance.go | 97 - .../hcs/shell/dbinstance_account.go | 76 - .../hcs/shell/dbinstance_database.go | 55 - pkg/multicloud/hcs/shell/dbinstance_skus.go | 48 - pkg/multicloud/hcs/shell/disk.go | 83 - pkg/multicloud/hcs/shell/doc.go | 1 - pkg/multicloud/hcs/shell/eip.go | 88 - pkg/multicloud/hcs/shell/image.go | 56 - pkg/multicloud/hcs/shell/instance.go | 261 --- pkg/multicloud/hcs/shell/instancetype.go | 48 - pkg/multicloud/hcs/shell/job.go | 35 - pkg/multicloud/hcs/shell/keypair.go | 46 - pkg/multicloud/hcs/shell/lb.go | 345 ---- pkg/multicloud/hcs/shell/monitor.go | 38 - pkg/multicloud/hcs/shell/natgateway.go | 141 -- pkg/multicloud/hcs/shell/network.go | 48 - pkg/multicloud/hcs/shell/port.go | 34 - pkg/multicloud/hcs/shell/printutils.go | 25 - pkg/multicloud/hcs/shell/project.go | 33 - pkg/multicloud/hcs/shell/redis.go | 95 - pkg/multicloud/hcs/shell/region.go | 30 - pkg/multicloud/hcs/shell/securitygroup.go | 90 - pkg/multicloud/hcs/shell/snapshot.go | 63 - pkg/multicloud/hcs/shell/vpc.go | 57 - pkg/multicloud/hcs/shell/vpc_peer.go | 52 - pkg/multicloud/hcs/shell/zone.go | 33 - pkg/multicloud/hcs/snapshot.go | 192 -- pkg/multicloud/hcs/storage.go | 134 -- pkg/multicloud/hcs/storagecache.go | 253 --- pkg/multicloud/hcs/vpc.go | 312 --- pkg/multicloud/hcs/vpc_peering.go | 143 -- pkg/multicloud/hcs/wire.go | 127 -- pkg/multicloud/hcs/zone.go | 230 --- pkg/multicloud/hcso/bucket.go | 773 ------- .../hcso/client/auth/credentials/doc.go | 15 - pkg/multicloud/hcso/client/auth/doc.go | 15 - pkg/multicloud/hcso/client/auth/signer.go | 214 -- .../hcso/client/auth/signers/doc.go | 15 - .../client/auth/signers/signer_access_key.go | 55 - pkg/multicloud/hcso/client/client.go | 286 --- pkg/multicloud/hcso/client/doc.go | 15 - pkg/multicloud/hcso/client/manager/doc.go | 15 - pkg/multicloud/hcso/client/manager/manager.go | 84 - pkg/multicloud/hcso/client/modules/doc.go | 15 - .../hcso/client/modules/manager_base.go | 268 --- .../hcso/client/modules/manager_resource.go | 298 --- pkg/multicloud/hcso/client/modules/mod_ces.go | 120 -- .../hcso/client/modules/mod_credential.go | 37 - .../hcso/client/modules/mod_dbinstance.go | 103 - .../client/modules/mod_dbinstance_backup.go | 37 - .../client/modules/mod_dbinstance_flavor.go | 37 - .../hcso/client/modules/mod_dbinstance_job.go | 43 - .../hcso/client/modules/mod_disks.go | 76 - .../hcso/client/modules/mod_dnat_rules.go | 41 - .../hcso/client/modules/mod_domains.go | 95 - .../hcso/client/modules/mod_elasticcache.go | 118 -- .../client/modules/mod_enterpriceprojects.go | 39 - .../hcso/client/modules/mod_flavors.go | 37 - .../hcso/client/modules/mod_groups.go | 39 - .../hcso/client/modules/mod_images.go | 101 - .../hcso/client/modules/mod_interface.go | 38 - .../hcso/client/modules/mod_jobs.go | 71 - .../hcso/client/modules/mod_keypairs.go | 37 - .../hcso/client/modules/mod_mapping.go | 39 - .../hcso/client/modules/mod_natgateway.go | 50 - .../hcso/client/modules/mod_port.go | 53 - .../hcso/client/modules/mod_projects.go | 89 - .../hcso/client/modules/mod_quotas.go | 37 - .../hcso/client/modules/mod_regions.go | 37 - .../hcso/client/modules/mod_roles.go | 39 - .../hcso/client/modules/mod_saml_provider.go | 39 - .../hcso/client/modules/mod_secgroup_rules.go | 37 - .../hcso/client/modules/mod_secgroups.go | 51 - .../hcso/client/modules/mod_servers.go | 124 -- pkg/multicloud/hcso/client/modules/mod_sfs.go | 48 - .../hcso/client/modules/mod_snapshots.go | 59 - .../hcso/client/modules/mod_snat_rules.go | 41 - .../hcso/client/modules/mod_subnets.go | 37 - .../hcso/client/modules/mod_traces.go | 37 - .../hcso/client/modules/mod_users.go | 69 - .../hcso/client/modules/mod_vpc_peerings.go | 37 - .../hcso/client/modules/mod_vpc_routes.go | 38 - .../hcso/client/modules/mod_vpcs.go | 37 - .../hcso/client/modules/mod_zones.go | 37 - pkg/multicloud/hcso/client/requests/doc.go | 15 - pkg/multicloud/hcso/client/responses/doc.go | 15 - .../hcso/client/responses/responses_test.go | 37 - pkg/multicloud/hcso/cloudgroup.go | 446 ----- pkg/multicloud/hcso/clouduser.go | 293 --- pkg/multicloud/hcso/dbinstance.go | 693 ------- pkg/multicloud/hcso/dbinstance_account.go | 132 -- pkg/multicloud/hcso/dbinstance_backup.go | 236 --- pkg/multicloud/hcso/dbinstance_database.go | 72 - pkg/multicloud/hcso/dbinstance_privilege.go | 43 - pkg/multicloud/hcso/dbinstance_skus.go | 263 --- pkg/multicloud/hcso/disk.go | 533 ----- pkg/multicloud/hcso/doc.go | 15 - pkg/multicloud/hcso/eip.go | 401 ---- pkg/multicloud/hcso/elasticcache_account.go | 108 - pkg/multicloud/hcso/elasticcache_backup.go | 138 -- pkg/multicloud/hcso/elasticcache_instance.go | 751 ------- pkg/multicloud/hcso/elasticcache_parameter.go | 78 - pkg/multicloud/hcso/enterpriceprojects.go | 114 -- pkg/multicloud/hcso/host.go | 349 ---- pkg/multicloud/hcso/huawei.go | 554 ------ pkg/multicloud/hcso/image.go | 469 ----- pkg/multicloud/hcso/instance.go | 1466 -------------- pkg/multicloud/hcso/instancenic.go | 110 - pkg/multicloud/hcso/instancetype.go | 314 --- pkg/multicloud/hcso/latitud_and_longitude.go | 44 - pkg/multicloud/hcso/loadbalancer.go | 553 ------ pkg/multicloud/hcso/loadbalancer_acl.go | 113 -- pkg/multicloud/hcso/loadbalancer_backend.go | 168 -- .../hcso/loadbalancer_backendgroup.go | 541 ----- pkg/multicloud/hcso/loadbalancer_cert.go | 123 -- pkg/multicloud/hcso/loadbalancer_listener.go | 694 ------- .../hcso/loadbalancer_listener_rule.go | 172 -- pkg/multicloud/hcso/modelarts.go | 394 ---- pkg/multicloud/hcso/modelarts_sku.go | 130 -- pkg/multicloud/hcso/monitor.go | 107 - pkg/multicloud/hcso/nat_skus.go | 97 - pkg/multicloud/hcso/natdtable.go | 131 -- pkg/multicloud/hcso/natgateway.go | 353 ---- pkg/multicloud/hcso/natstable.go | 121 -- pkg/multicloud/hcso/network.go | 174 -- pkg/multicloud/hcso/object.go | 103 - pkg/multicloud/hcso/port.go | 161 -- pkg/multicloud/hcso/project.go | 106 - pkg/multicloud/hcso/provider/doc.go | 15 - pkg/multicloud/hcso/provider/provider.go | 336 ---- pkg/multicloud/hcso/quota.go | 80 - pkg/multicloud/hcso/region.go | 1114 ----------- pkg/multicloud/hcso/roles.go | 164 -- pkg/multicloud/hcso/routetable.go | 356 ---- pkg/multicloud/hcso/saml_provider.go | 349 ---- pkg/multicloud/hcso/securitygroup.go | 275 --- pkg/multicloud/hcso/sfs-turbo.go | 298 --- pkg/multicloud/hcso/shell/bucket.go | 49 - pkg/multicloud/hcso/shell/cloudgroup.go | 97 - pkg/multicloud/hcso/shell/clouduser.go | 122 -- pkg/multicloud/hcso/shell/dbinstance.go | 97 - .../hcso/shell/dbinstance_account.go | 76 - .../hcso/shell/dbinstance_database.go | 55 - pkg/multicloud/hcso/shell/dbinstance_skus.go | 48 - pkg/multicloud/hcso/shell/disk.go | 54 - pkg/multicloud/hcso/shell/doc.go | 15 - pkg/multicloud/hcso/shell/eip.go | 69 - pkg/multicloud/hcso/shell/elasticcache.go | 69 - pkg/multicloud/hcso/shell/endpoints.go | 30 - .../hcso/shell/enterpriseprojects.go | 48 - pkg/multicloud/hcso/shell/events.go | 37 - pkg/multicloud/hcso/shell/filesystem.go | 60 - pkg/multicloud/hcso/shell/hosts.go | 34 - pkg/multicloud/hcso/shell/iam.go | 35 - pkg/multicloud/hcso/shell/image.go | 56 - pkg/multicloud/hcso/shell/instance.go | 218 -- pkg/multicloud/hcso/shell/instancetype.go | 36 - pkg/multicloud/hcso/shell/keypair.go | 47 - pkg/multicloud/hcso/shell/loadbalancer.go | 337 ---- pkg/multicloud/hcso/shell/modelarts.go | 82 - pkg/multicloud/hcso/shell/modelarts_sku.go | 35 - pkg/multicloud/hcso/shell/monitor.go | 62 - pkg/multicloud/hcso/shell/natdtable.go | 34 - pkg/multicloud/hcso/shell/natgateway.go | 141 -- pkg/multicloud/hcso/shell/natstable.go | 34 - pkg/multicloud/hcso/shell/network.go | 34 - pkg/multicloud/hcso/shell/obs.go | 75 - pkg/multicloud/hcso/shell/port.go | 34 - pkg/multicloud/hcso/shell/printutils.go | 25 - pkg/multicloud/hcso/shell/quota.go | 34 - pkg/multicloud/hcso/shell/region.go | 79 - pkg/multicloud/hcso/shell/role.go | 91 - pkg/multicloud/hcso/shell/routetable.go | 34 - pkg/multicloud/hcso/shell/saml_provider.go | 106 - pkg/multicloud/hcso/shell/secgroup.go | 90 - pkg/multicloud/hcso/shell/service.go | 30 - pkg/multicloud/hcso/shell/skus.go | 34 - pkg/multicloud/hcso/shell/snapshot.go | 55 - pkg/multicloud/hcso/shell/vpc.go | 122 -- pkg/multicloud/hcso/shell/zone.go | 34 - pkg/multicloud/hcso/snapshot.go | 189 -- pkg/multicloud/hcso/storage.go | 161 -- pkg/multicloud/hcso/storagecache.go | 324 --- pkg/multicloud/hcso/traces.go | 131 -- pkg/multicloud/hcso/utils.go | 270 --- pkg/multicloud/hcso/vpc.go | 368 ---- pkg/multicloud/hcso/vpc_peering.go | 159 -- pkg/multicloud/hcso/wire.go | 206 -- pkg/multicloud/hcso/zone.go | 262 --- pkg/multicloud/huawei/bucket.go | 766 ------- .../huawei/client/auth/credentials/doc.go | 15 - pkg/multicloud/huawei/client/auth/doc.go | 15 - pkg/multicloud/huawei/client/auth/signer.go | 215 -- .../huawei/client/auth/signers/doc.go | 15 - .../client/auth/signers/signer_access_key.go | 55 - pkg/multicloud/huawei/client/client.go | 249 --- pkg/multicloud/huawei/client/doc.go | 15 - pkg/multicloud/huawei/client/manager/doc.go | 15 - .../huawei/client/manager/manager.go | 81 - pkg/multicloud/huawei/client/modules/doc.go | 15 - .../huawei/client/modules/manager_base.go | 272 --- .../huawei/client/modules/manager_resource.go | 298 --- .../huawei/client/modules/mod_ces.go | 152 -- .../huawei/client/modules/mod_credential.go | 37 - .../huawei/client/modules/mod_dbinstance.go | 103 - .../client/modules/mod_dbinstance_backup.go | 37 - .../client/modules/mod_dbinstance_flavor.go | 37 - .../client/modules/mod_dbinstance_job.go | 43 - .../huawei/client/modules/mod_disks.go | 76 - .../huawei/client/modules/mod_dnat_rules.go | 41 - .../huawei/client/modules/mod_domains.go | 95 - .../huawei/client/modules/mod_elasticcache.go | 118 -- .../client/modules/mod_enterpriceprojects.go | 39 - .../huawei/client/modules/mod_flavors.go | 37 - .../huawei/client/modules/mod_groups.go | 39 - .../huawei/client/modules/mod_images.go | 101 - .../huawei/client/modules/mod_interface.go | 38 - .../huawei/client/modules/mod_jobs.go | 71 - .../huawei/client/modules/mod_keypairs.go | 37 - .../huawei/client/modules/mod_mapping.go | 39 - .../huawei/client/modules/mod_natgateway.go | 50 - .../huawei/client/modules/mod_port.go | 53 - .../huawei/client/modules/mod_projects.go | 89 - .../huawei/client/modules/mod_quotas.go | 37 - .../huawei/client/modules/mod_regions.go | 37 - .../huawei/client/modules/mod_roles.go | 39 - .../client/modules/mod_saml_provider.go | 39 - .../client/modules/mod_secgroup_rules.go | 37 - .../huawei/client/modules/mod_secgroups.go | 51 - .../huawei/client/modules/mod_servers.go | 124 -- .../huawei/client/modules/mod_sfs.go | 48 - .../huawei/client/modules/mod_snapshots.go | 59 - .../huawei/client/modules/mod_snat_rules.go | 41 - .../huawei/client/modules/mod_subnets.go | 37 - .../huawei/client/modules/mod_traces.go | 37 - .../huawei/client/modules/mod_users.go | 69 - .../huawei/client/modules/mod_vpc_peerings.go | 37 - .../huawei/client/modules/mod_vpc_routes.go | 38 - .../huawei/client/modules/mod_vpcs.go | 37 - .../huawei/client/modules/mod_zones.go | 37 - pkg/multicloud/huawei/client/requests/doc.go | 15 - pkg/multicloud/huawei/client/responses/doc.go | 15 - .../huawei/client/responses/responses_test.go | 37 - pkg/multicloud/huawei/cloudgroup.go | 465 ----- pkg/multicloud/huawei/clouduser.go | 289 --- pkg/multicloud/huawei/dbinstance.go | 780 -------- pkg/multicloud/huawei/dbinstance_account.go | 132 -- pkg/multicloud/huawei/dbinstance_backup.go | 236 --- pkg/multicloud/huawei/dbinstance_database.go | 72 - pkg/multicloud/huawei/dbinstance_privilege.go | 43 - pkg/multicloud/huawei/disk.go | 558 ------ pkg/multicloud/huawei/doc.go | 15 - pkg/multicloud/huawei/eip.go | 396 ---- pkg/multicloud/huawei/elasticcache_account.go | 108 - pkg/multicloud/huawei/elasticcache_backup.go | 138 -- .../huawei/elasticcache_instance.go | 760 ------- .../huawei/elasticcache_parameter.go | 78 - pkg/multicloud/huawei/enterpriceprojects.go | 114 -- pkg/multicloud/huawei/host.go | 306 --- pkg/multicloud/huawei/huawei.go | 862 -------- pkg/multicloud/huawei/image.go | 474 ----- pkg/multicloud/huawei/instance.go | 1538 -------------- pkg/multicloud/huawei/instancenic.go | 111 -- .../huawei/latitud_and_longitude.go | 44 - pkg/multicloud/huawei/loadbalancer.go | 625 ------ pkg/multicloud/huawei/loadbalancer_acl.go | 152 -- pkg/multicloud/huawei/loadbalancer_backend.go | 161 -- .../huawei/loadbalancer_backendgroup.go | 509 ----- pkg/multicloud/huawei/loadbalancer_cert.go | 154 -- .../huawei/loadbalancer_listener.go | 663 ------ .../huawei/loadbalancer_listener_rule.go | 166 -- pkg/multicloud/huawei/modelarts_pool.go | 393 ---- pkg/multicloud/huawei/modelarts_pool_sku.go | 130 -- pkg/multicloud/huawei/monitor.go | 563 ------ pkg/multicloud/huawei/natdtable.go | 131 -- pkg/multicloud/huawei/natgateway.go | 353 ---- pkg/multicloud/huawei/natstable.go | 121 -- pkg/multicloud/huawei/network.go | 174 -- pkg/multicloud/huawei/object.go | 103 - pkg/multicloud/huawei/obs/doc.go | 15 - pkg/multicloud/huawei/order.go | 193 -- pkg/multicloud/huawei/port.go | 161 -- pkg/multicloud/huawei/project.go | 94 - pkg/multicloud/huawei/provider/doc.go | 15 - pkg/multicloud/huawei/provider/provider.go | 314 --- pkg/multicloud/huawei/quota.go | 80 - pkg/multicloud/huawei/region.go | 862 -------- pkg/multicloud/huawei/roles.go | 99 - pkg/multicloud/huawei/routetables.go | 232 --- pkg/multicloud/huawei/saml_provider.go | 367 ---- pkg/multicloud/huawei/securitygroup.go | 275 --- pkg/multicloud/huawei/sfs-turbo.go | 298 --- pkg/multicloud/huawei/shell/bucket.go | 49 - pkg/multicloud/huawei/shell/business.go | 33 - pkg/multicloud/huawei/shell/cloudgroup.go | 97 - pkg/multicloud/huawei/shell/clouduser.go | 122 -- pkg/multicloud/huawei/shell/dbinstance.go | 97 - .../huawei/shell/dbinstance_account.go | 76 - .../huawei/shell/dbinstance_database.go | 55 - pkg/multicloud/huawei/shell/disk.go | 54 - pkg/multicloud/huawei/shell/doc.go | 15 - pkg/multicloud/huawei/shell/eip.go | 75 - pkg/multicloud/huawei/shell/elasticcache.go | 69 - .../huawei/shell/enterpriseprojects.go | 48 - pkg/multicloud/huawei/shell/events.go | 37 - pkg/multicloud/huawei/shell/filesystem.go | 60 - pkg/multicloud/huawei/shell/iam.go | 35 - pkg/multicloud/huawei/shell/image.go | 56 - pkg/multicloud/huawei/shell/instance.go | 231 --- pkg/multicloud/huawei/shell/instancetype.go | 36 - pkg/multicloud/huawei/shell/keypair.go | 47 - pkg/multicloud/huawei/shell/loadbalancer.go | 345 ---- pkg/multicloud/huawei/shell/modelarts_pool.go | 78 - .../huawei/shell/modelarts_pool_sku.go | 35 - pkg/multicloud/huawei/shell/monitor.go | 65 - pkg/multicloud/huawei/shell/natdtable.go | 34 - pkg/multicloud/huawei/shell/natgateway.go | 141 -- pkg/multicloud/huawei/shell/natstable.go | 34 - pkg/multicloud/huawei/shell/network.go | 34 - pkg/multicloud/huawei/shell/obs.go | 75 - pkg/multicloud/huawei/shell/order.go | 36 - pkg/multicloud/huawei/shell/port.go | 34 - pkg/multicloud/huawei/shell/printutils.go | 25 - pkg/multicloud/huawei/shell/quota.go | 34 - pkg/multicloud/huawei/shell/region.go | 66 - pkg/multicloud/huawei/shell/role.go | 35 - pkg/multicloud/huawei/shell/routetable.go | 47 - pkg/multicloud/huawei/shell/saml_provider.go | 131 -- pkg/multicloud/huawei/shell/secgroup.go | 90 - pkg/multicloud/huawei/shell/snapshot.go | 55 - pkg/multicloud/huawei/shell/vpc.go | 122 -- pkg/multicloud/huawei/shell/zone.go | 34 - pkg/multicloud/huawei/snapshot.go | 189 -- pkg/multicloud/huawei/storage.go | 161 -- pkg/multicloud/huawei/storagecache.go | 302 --- pkg/multicloud/huawei/traces.go | 131 -- pkg/multicloud/huawei/utils.go | 270 --- pkg/multicloud/huawei/vpc.go | 361 ---- pkg/multicloud/huawei/vpc_peering.go | 159 -- pkg/multicloud/huawei/wire.go | 192 -- pkg/multicloud/huawei/zone.go | 204 -- pkg/multicloud/incloudsphere/disk.go | 246 --- pkg/multicloud/incloudsphere/doc.go | 15 - pkg/multicloud/incloudsphere/host.go | 452 ----- pkg/multicloud/incloudsphere/image.go | 183 -- pkg/multicloud/incloudsphere/instance.go | 613 ------ pkg/multicloud/incloudsphere/network.go | 184 -- pkg/multicloud/incloudsphere/nic.go | 129 -- pkg/multicloud/incloudsphere/provider/doc.go | 15 - .../incloudsphere/provider/provider.go | 171 -- pkg/multicloud/incloudsphere/region.go | 212 -- pkg/multicloud/incloudsphere/shell/disk.go | 72 - pkg/multicloud/incloudsphere/shell/doc.go | 15 - pkg/multicloud/incloudsphere/shell/host.go | 48 - pkg/multicloud/incloudsphere/shell/image.go | 62 - .../incloudsphere/shell/instance.go | 85 - pkg/multicloud/incloudsphere/shell/network.go | 48 - .../incloudsphere/shell/printutils.go | 25 - pkg/multicloud/incloudsphere/shell/region.go | 34 - pkg/multicloud/incloudsphere/shell/storage.go | 34 - pkg/multicloud/incloudsphere/shell/version.go | 33 - pkg/multicloud/incloudsphere/shell/wire.go | 46 - pkg/multicloud/incloudsphere/shell/zone.go | 34 - pkg/multicloud/incloudsphere/storage.go | 224 --- pkg/multicloud/incloudsphere/storagecache.go | 126 -- pkg/multicloud/incloudsphere/task.go | 58 - pkg/multicloud/incloudsphere/vpc.go | 98 - pkg/multicloud/incloudsphere/wire.go | 146 -- pkg/multicloud/incloudsphere/zone.go | 156 -- pkg/multicloud/jdcloud/disk.go | 285 --- pkg/multicloud/jdcloud/doc.go | 15 - pkg/multicloud/jdcloud/eip.go | 151 -- pkg/multicloud/jdcloud/host.go | 187 -- pkg/multicloud/jdcloud/image.go | 215 -- pkg/multicloud/jdcloud/instance.go | 443 ----- pkg/multicloud/jdcloud/instancenic.go | 52 - .../jdcloud/latitud_and_longitude.go | 27 - pkg/multicloud/jdcloud/monitor.go | 155 -- pkg/multicloud/jdcloud/network.go | 156 -- pkg/multicloud/jdcloud/networkinterface.go | 107 - pkg/multicloud/jdcloud/provider/doc.go | 15 - pkg/multicloud/jdcloud/provider/provider.go | 200 -- pkg/multicloud/jdcloud/rds.go | 266 --- pkg/multicloud/jdcloud/region.go | 312 --- pkg/multicloud/jdcloud/securitygroup.go | 162 -- pkg/multicloud/jdcloud/shell/balance.go | 33 - pkg/multicloud/jdcloud/shell/doc.go | 15 - pkg/multicloud/jdcloud/shell/image.go | 35 - pkg/multicloud/jdcloud/shell/instance.go | 71 - pkg/multicloud/jdcloud/shell/monitor.go | 37 - pkg/multicloud/jdcloud/shell/network.go | 52 - pkg/multicloud/jdcloud/shell/rds.go | 99 - pkg/multicloud/jdcloud/shell/utils.go | 30 - pkg/multicloud/jdcloud/shell/vpc.go | 33 - pkg/multicloud/jdcloud/shell/zone.go | 33 - pkg/multicloud/jdcloud/snapshot.go | 159 -- pkg/multicloud/jdcloud/storage.go | 148 -- pkg/multicloud/jdcloud/storagecache.go | 107 - pkg/multicloud/jdcloud/utils.go | 46 - pkg/multicloud/jdcloud/vpc.go | 190 -- pkg/multicloud/jdcloud/wire.go | 120 -- pkg/multicloud/jdcloud/zone.go | 195 -- pkg/multicloud/loader/doc.go | 15 - pkg/multicloud/loader/loader.go | 49 - pkg/multicloud/loader/proxyfunc_test.go | 140 -- pkg/multicloud/nutanix/disk.go | 355 ---- pkg/multicloud/nutanix/doc.go | 15 - pkg/multicloud/nutanix/host.go | 512 ----- pkg/multicloud/nutanix/image.go | 249 --- pkg/multicloud/nutanix/instance.go | 422 ---- pkg/multicloud/nutanix/instancenic.go | 106 - pkg/multicloud/nutanix/network.go | 183 -- pkg/multicloud/nutanix/provider/doc.go | 15 - pkg/multicloud/nutanix/provider/provider.go | 201 -- pkg/multicloud/nutanix/region.go | 222 --- pkg/multicloud/nutanix/shell/cluster.go | 47 - pkg/multicloud/nutanix/shell/disk.go | 49 - pkg/multicloud/nutanix/shell/doc.go | 15 - pkg/multicloud/nutanix/shell/host.go | 47 - pkg/multicloud/nutanix/shell/image.go | 80 - pkg/multicloud/nutanix/shell/instance.go | 47 - pkg/multicloud/nutanix/shell/printutils.go | 25 - pkg/multicloud/nutanix/shell/storage.go | 47 - pkg/multicloud/nutanix/shell/task.go | 47 - pkg/multicloud/nutanix/shell/vpc.go | 72 - pkg/multicloud/nutanix/storage.go | 332 ---- pkg/multicloud/nutanix/storagecache.go | 136 -- pkg/multicloud/nutanix/vpc.go | 182 -- pkg/multicloud/nutanix/wire.go | 103 - pkg/multicloud/nutanix/zone.go | 118 -- pkg/multicloud/objectstore/ceph/bucket.go | 67 - pkg/multicloud/objectstore/ceph/doc.go | 15 - .../objectstore/ceph/provider/doc.go | 15 - .../objectstore/ceph/provider/provider.go | 65 - pkg/multicloud/objectstore/doc.go | 15 - pkg/multicloud/objectstore/object.go | 92 - pkg/multicloud/objectstore/provider/doc.go | 15 - .../objectstore/provider/provider.go | 166 -- pkg/multicloud/objectstore/shell/bucket.go | 21 - pkg/multicloud/objectstore/shell/doc.go | 15 - pkg/multicloud/objectstore/shell/minio.go | 140 -- .../objectstore/shell/printutils.go | 25 - pkg/multicloud/objectstore/xsky/bucket.go | 89 - pkg/multicloud/objectstore/xsky/doc.go | 15 - .../objectstore/xsky/provider/doc.go | 15 - .../objectstore/xsky/provider/provider.go | 68 - pkg/multicloud/openstack/disk.go | 448 ----- pkg/multicloud/openstack/doc.go | 15 - pkg/multicloud/openstack/eip.go | 335 ---- pkg/multicloud/openstack/flavor.go | 285 --- pkg/multicloud/openstack/image.go | 335 ---- pkg/multicloud/openstack/instance.go | 1167 ----------- pkg/multicloud/openstack/instancenic.go | 99 - pkg/multicloud/openstack/loadbalanceracl.go | 187 -- .../openstack/loadbalancerlistener.go | 774 -------- pkg/multicloud/openstack/network.go | 347 ---- pkg/multicloud/openstack/port.go | 219 -- pkg/multicloud/openstack/project.go | 125 -- pkg/multicloud/openstack/provider/doc.go | 15 - pkg/multicloud/openstack/provider/provider.go | 225 --- pkg/multicloud/openstack/quota.go | 165 -- pkg/multicloud/openstack/region.go | 620 ------ pkg/multicloud/openstack/roles.go | 67 - pkg/multicloud/openstack/routetable.go | 139 -- pkg/multicloud/openstack/securitygroup.go | 324 --- pkg/multicloud/openstack/shell/disk.go | 86 - pkg/multicloud/openstack/shell/doc.go | 15 - pkg/multicloud/openstack/shell/eip.go | 58 - pkg/multicloud/openstack/shell/flavor.go | 78 - pkg/multicloud/openstack/shell/host.go | 58 - pkg/multicloud/openstack/shell/image.go | 81 - pkg/multicloud/openstack/shell/instance.go | 141 -- pkg/multicloud/openstack/shell/keypair.go | 66 - .../openstack/shell/loadbalancer.go | 83 - pkg/multicloud/openstack/shell/messages.go | 34 - pkg/multicloud/openstack/shell/network.go | 63 - pkg/multicloud/openstack/shell/port.go | 49 - pkg/multicloud/openstack/shell/printutils.go | 25 - pkg/multicloud/openstack/shell/project.go | 56 - pkg/multicloud/openstack/shell/quota.go | 38 - pkg/multicloud/openstack/shell/region.go | 30 - pkg/multicloud/openstack/shell/role.go | 45 - pkg/multicloud/openstack/shell/router.go | 33 - .../openstack/shell/securitygroup.go | 73 - pkg/multicloud/openstack/shell/snapshot.go | 67 - pkg/multicloud/openstack/shell/storage.go | 45 - pkg/multicloud/openstack/shell/vpc.go | 64 - pkg/multicloud/openstack/shell/zone.go | 45 - pkg/multicloud/openstack/snapshot.go | 216 -- pkg/multicloud/openstack/storage.go | 257 --- pkg/multicloud/openstack/storagecache.go | 160 -- pkg/multicloud/openstack/vpc.go | 268 --- pkg/multicloud/openstack/wire.go | 112 -- pkg/multicloud/openstack/zone.go | 210 -- pkg/multicloud/proxmox/disk.go | 236 --- pkg/multicloud/proxmox/doc.go | 15 - pkg/multicloud/proxmox/host.go | 335 ---- pkg/multicloud/proxmox/image.go | 249 --- pkg/multicloud/proxmox/instance.go | 1019 ---------- pkg/multicloud/proxmox/network.go | 187 -- pkg/multicloud/proxmox/nic.go | 65 - pkg/multicloud/proxmox/provider/doc.go | 1 - pkg/multicloud/proxmox/provider/provider.go | 200 -- pkg/multicloud/proxmox/region.go | 204 -- pkg/multicloud/proxmox/shell/cluster.go | 52 - pkg/multicloud/proxmox/shell/disk.go | 48 - pkg/multicloud/proxmox/shell/doc.go | 1 - pkg/multicloud/proxmox/shell/hosts.go | 48 - pkg/multicloud/proxmox/shell/image.go | 35 - pkg/multicloud/proxmox/shell/instance.go | 110 - pkg/multicloud/proxmox/shell/network.go | 47 - pkg/multicloud/proxmox/shell/printutils.go | 25 - pkg/multicloud/proxmox/shell/region.go | 34 - pkg/multicloud/proxmox/shell/storage.go | 47 - pkg/multicloud/proxmox/shell/zone.go | 34 - pkg/multicloud/proxmox/storage.go | 230 --- pkg/multicloud/proxmox/storagecache.go | 95 - pkg/multicloud/proxmox/task.go | 86 - pkg/multicloud/proxmox/vpc.go | 98 - pkg/multicloud/proxmox/wire.go | 95 - pkg/multicloud/proxmox/zone.go | 157 -- pkg/multicloud/qcloud/bucket.go | 1169 ----------- pkg/multicloud/qcloud/cam_group.go | 385 ---- pkg/multicloud/qcloud/cam_policy.go | 285 --- pkg/multicloud/qcloud/cam_role.go | 275 --- pkg/multicloud/qcloud/cam_user.go | 297 --- pkg/multicloud/qcloud/cdn.go | 321 --- .../qcloud/cloud_connect_network.go | 400 ---- pkg/multicloud/qcloud/dbinstance.go | 63 - pkg/multicloud/qcloud/disk.go | 415 ---- pkg/multicloud/qcloud/doc.go | 113 -- pkg/multicloud/qcloud/eip.go | 424 ---- pkg/multicloud/qcloud/elastic_search.go | 351 ---- pkg/multicloud/qcloud/elasticcache_account.go | 172 -- pkg/multicloud/qcloud/elasticcache_backup.go | 185 -- .../qcloud/elasticcache_instance.go | 1229 ------------ pkg/multicloud/qcloud/events.go | 158 -- pkg/multicloud/qcloud/host.go | 289 --- pkg/multicloud/qcloud/image.go | 383 ---- pkg/multicloud/qcloud/instance.go | 1072 ---------- pkg/multicloud/qcloud/instancenic.go | 54 - pkg/multicloud/qcloud/kafka.go | 250 --- pkg/multicloud/qcloud/keypair.go | 193 -- pkg/multicloud/qcloud/kube_node_pools.go | 113 -- pkg/multicloud/qcloud/kube_nodes.go | 126 -- .../qcloud/latitud_and_longitude.go | 43 - pkg/multicloud/qcloud/loadbalancer.go | 715 ------- pkg/multicloud/qcloud/loadbalancer_acl.go | 73 - pkg/multicloud/qcloud/loadbalancer_backend.go | 209 -- .../qcloud/loadbalancer_backendgroup.go | 422 ---- .../qcloud/loadbalancer_listener.go | 884 -------- .../qcloud/loadbalancer_listenerrule.go | 170 -- pkg/multicloud/qcloud/memcached.go | 314 --- pkg/multicloud/qcloud/mongodb.go | 406 ---- pkg/multicloud/qcloud/monitor.go | 372 ---- pkg/multicloud/qcloud/natdtable.go | 104 - pkg/multicloud/qcloud/natgateway.go | 164 -- pkg/multicloud/qcloud/network.go | 183 -- pkg/multicloud/qcloud/networkinterface.go | 199 -- pkg/multicloud/qcloud/object.go | 90 - pkg/multicloud/qcloud/project.go | 115 -- pkg/multicloud/qcloud/provider/doc.go | 15 - pkg/multicloud/qcloud/provider/provider.go | 463 ----- pkg/multicloud/qcloud/quota.go | 131 -- pkg/multicloud/qcloud/rds_mysql.go | 923 --------- pkg/multicloud/qcloud/region.go | 1244 ------------ pkg/multicloud/qcloud/route_table.go | 245 --- pkg/multicloud/qcloud/saml_provider.go | 184 -- pkg/multicloud/qcloud/securitygroup.go | 570 ------ pkg/multicloud/qcloud/shell/balance.go | 33 - .../qcloud/shell/bandwidthpackage.go | 37 - pkg/multicloud/qcloud/shell/cam_group.go | 108 - pkg/multicloud/qcloud/shell/cam_policy.go | 85 - pkg/multicloud/qcloud/shell/cam_role.go | 98 - pkg/multicloud/qcloud/shell/cam_user.go | 123 -- pkg/multicloud/qcloud/shell/ccn_route.go | 58 - pkg/multicloud/qcloud/shell/cdn.go | 68 - .../qcloud/shell/cloud_connect_network.go | 127 -- pkg/multicloud/qcloud/shell/cos.go | 23 - pkg/multicloud/qcloud/shell/disk.go | 95 - pkg/multicloud/qcloud/shell/dnspod.go | 155 -- pkg/multicloud/qcloud/shell/doc.go | 15 - pkg/multicloud/qcloud/shell/eip.go | 86 - pkg/multicloud/qcloud/shell/elasticcache.go | 85 - pkg/multicloud/qcloud/shell/elasticsearch.go | 45 - pkg/multicloud/qcloud/shell/events.go | 40 - pkg/multicloud/qcloud/shell/image.go | 181 -- pkg/multicloud/qcloud/shell/instance.go | 245 --- pkg/multicloud/qcloud/shell/kafka.go | 56 - pkg/multicloud/qcloud/shell/keypair.go | 59 - pkg/multicloud/qcloud/shell/kube_cluster.go | 59 - .../qcloud/shell/kube_node_pools.go | 35 - pkg/multicloud/qcloud/shell/kube_nodes.go | 37 - pkg/multicloud/qcloud/shell/loadbalancer.go | 106 - pkg/multicloud/qcloud/shell/memcached.go | 36 - pkg/multicloud/qcloud/shell/mongodb.go | 62 - pkg/multicloud/qcloud/shell/monitor.go | 37 - pkg/multicloud/qcloud/shell/natdtable.go | 35 - pkg/multicloud/qcloud/shell/natgateway.go | 36 - pkg/multicloud/qcloud/shell/network.go | 68 - .../qcloud/shell/networkinterface.go | 38 - pkg/multicloud/qcloud/shell/printutils.go | 25 - pkg/multicloud/qcloud/shell/project.go | 48 - pkg/multicloud/qcloud/shell/quota.go | 47 - pkg/multicloud/qcloud/shell/rds_mariadb.go | 60 - pkg/multicloud/qcloud/shell/rds_mysql.go | 180 -- pkg/multicloud/qcloud/shell/rds_postgre.go | 48 - pkg/multicloud/qcloud/shell/rds_sqlserver.go | 49 - pkg/multicloud/qcloud/shell/region.go | 30 - pkg/multicloud/qcloud/shell/route_table.go | 48 - pkg/multicloud/qcloud/shell/saml_provider.go | 76 - pkg/multicloud/qcloud/shell/securitygroup.go | 98 - pkg/multicloud/qcloud/shell/snapshot.go | 59 - .../qcloud/shell/snapshot_policy.go | 96 - pkg/multicloud/qcloud/shell/storage.go | 34 - pkg/multicloud/qcloud/shell/sts.go | 33 - pkg/multicloud/qcloud/shell/tags.go | 59 - pkg/multicloud/qcloud/shell/tdsql.go | 36 - pkg/multicloud/qcloud/shell/vpc.go | 175 -- pkg/multicloud/qcloud/shell/zone.go | 49 - pkg/multicloud/qcloud/snapshot.go | 233 --- pkg/multicloud/qcloud/snapshot_policy.go | 275 --- pkg/multicloud/qcloud/storage.go | 156 -- pkg/multicloud/qcloud/storagecache.go | 213 -- pkg/multicloud/qcloud/vpc.go | 428 ---- .../qcloud/vpc_peering_connection.go | 287 --- pkg/multicloud/qcloud/wire.go | 156 -- pkg/multicloud/qcloud/zone.go | 312 --- pkg/multicloud/remotefile/bucket.go | 185 -- pkg/multicloud/remotefile/dbinstance.go | 216 -- pkg/multicloud/remotefile/disk.go | 131 -- pkg/multicloud/remotefile/doc.go | 1 - pkg/multicloud/remotefile/eip.go | 73 - pkg/multicloud/remotefile/host.go | 193 -- pkg/multicloud/remotefile/instance.go | 264 --- pkg/multicloud/remotefile/instancenic.go | 64 - pkg/multicloud/remotefile/loadbalancer.go | 118 -- pkg/multicloud/remotefile/monitor.go | 34 - pkg/multicloud/remotefile/network.go | 68 - pkg/multicloud/remotefile/provider/doc.go | 1 - .../remotefile/provider/provider.go | 155 -- pkg/multicloud/remotefile/region.go | 324 --- pkg/multicloud/remotefile/securitygroup.go | 48 - pkg/multicloud/remotefile/storage.go | 111 -- pkg/multicloud/remotefile/vpc.go | 153 -- pkg/multicloud/remotefile/wire.go | 93 - pkg/multicloud/remotefile/zone.go | 90 - pkg/multicloud/tag_base.go | 559 ------ pkg/multicloud/test/doc.go | 15 - pkg/multicloud/test/readonly.go | 255 --- pkg/multicloud/ucloud/client.go | 204 -- pkg/multicloud/ucloud/client_test.go | 68 - pkg/multicloud/ucloud/disk.go | 456 ----- pkg/multicloud/ucloud/doc.go | 15 - pkg/multicloud/ucloud/eip.go | 289 --- pkg/multicloud/ucloud/host.go | 359 ---- pkg/multicloud/ucloud/image.go | 228 --- pkg/multicloud/ucloud/instance.go | 705 ------- pkg/multicloud/ucloud/instancenic.go | 56 - .../ucloud/latitud_and_longitude.go | 48 - pkg/multicloud/ucloud/network.go | 201 -- pkg/multicloud/ucloud/project.go | 64 - pkg/multicloud/ucloud/provider/doc.go | 15 - pkg/multicloud/ucloud/provider/provider.go | 193 -- pkg/multicloud/ucloud/region.go | 697 ------- pkg/multicloud/ucloud/securitygroup.go | 253 --- pkg/multicloud/ucloud/shell/disk.go | 46 - pkg/multicloud/ucloud/shell/doc.go | 15 - pkg/multicloud/ucloud/shell/eip.go | 74 - pkg/multicloud/ucloud/shell/image.go | 51 - pkg/multicloud/ucloud/shell/instance.go | 162 -- pkg/multicloud/ucloud/shell/network.go | 34 - pkg/multicloud/ucloud/shell/printutils.go | 25 - pkg/multicloud/ucloud/shell/region.go | 39 - pkg/multicloud/ucloud/shell/secgroup.go | 67 - pkg/multicloud/ucloud/shell/snapshot.go | 57 - pkg/multicloud/ucloud/shell/ufile.go | 23 - pkg/multicloud/ucloud/shell/vip.go | 33 - pkg/multicloud/ucloud/shell/vpc.go | 33 - pkg/multicloud/ucloud/shell/zone.go | 34 - pkg/multicloud/ucloud/snapshot.go | 207 -- pkg/multicloud/ucloud/storage.go | 157 -- pkg/multicloud/ucloud/storagecache.go | 393 ---- pkg/multicloud/ucloud/ufile.go | 394 ---- pkg/multicloud/ucloud/vip.go | 119 -- pkg/multicloud/ucloud/vpc.go | 242 --- pkg/multicloud/ucloud/wire.go | 113 -- pkg/multicloud/ucloud/zone.go | 203 -- pkg/multicloud/zstack/disk.go | 419 ---- pkg/multicloud/zstack/doc.go | 15 - pkg/multicloud/zstack/eip.go | 203 -- pkg/multicloud/zstack/host.go | 479 ----- pkg/multicloud/zstack/image.go | 303 --- pkg/multicloud/zstack/instance.go | 689 ------- pkg/multicloud/zstack/instancenic.go | 74 - pkg/multicloud/zstack/monitor.go | 141 -- pkg/multicloud/zstack/network.go | 258 --- pkg/multicloud/zstack/provider/doc.go | 15 - pkg/multicloud/zstack/provider/provider.go | 167 -- pkg/multicloud/zstack/quota.go | 104 - pkg/multicloud/zstack/region.go | 386 ---- pkg/multicloud/zstack/securitygroup.go | 264 --- pkg/multicloud/zstack/shell/cluster.go | 35 - pkg/multicloud/zstack/shell/configration.go | 33 - pkg/multicloud/zstack/shell/disk.go | 81 - pkg/multicloud/zstack/shell/disk_offering.go | 56 - pkg/multicloud/zstack/shell/doc.go | 15 - pkg/multicloud/zstack/shell/eip.go | 36 - pkg/multicloud/zstack/shell/host.go | 36 - pkg/multicloud/zstack/shell/image.go | 72 - pkg/multicloud/zstack/shell/image_server.go | 36 - pkg/multicloud/zstack/shell/instance.go | 96 - .../zstack/shell/instance_offering.go | 62 - pkg/multicloud/zstack/shell/monitor.go | 32 - pkg/multicloud/zstack/shell/network.go | 135 -- pkg/multicloud/zstack/shell/printutils.go | 25 - pkg/multicloud/zstack/shell/quota.go | 33 - pkg/multicloud/zstack/shell/region.go | 30 - pkg/multicloud/zstack/shell/securitygroup.go | 36 - pkg/multicloud/zstack/shell/snapshot.go | 58 - pkg/multicloud/zstack/shell/storage.go | 51 - pkg/multicloud/zstack/shell/tag.go | 37 - pkg/multicloud/zstack/shell/user.go | 34 - pkg/multicloud/zstack/shell/version.go | 33 - pkg/multicloud/zstack/shell/vip.go | 51 - pkg/multicloud/zstack/shell/wire.go | 36 - pkg/multicloud/zstack/shell/zone.go | 33 - pkg/multicloud/zstack/snapshot.go | 144 -- pkg/multicloud/zstack/storage.go | 266 --- pkg/multicloud/zstack/storagecache.go | 137 -- pkg/multicloud/zstack/vip.go | 180 -- pkg/multicloud/zstack/vpc.go | 116 -- pkg/multicloud/zstack/wire.go | 147 -- pkg/multicloud/zstack/zone.go | 183 -- pkg/notify/models/event_template.go | 2 +- pkg/s3gateway/handlers/handlers.go | 2 +- pkg/s3gateway/handlers/multipart.go | 2 +- pkg/s3gateway/handlers/object.go | 2 +- pkg/s3gateway/models/buckets.go | 82 +- pkg/s3gateway/models/cloudproviders.go | 2 +- pkg/s3gateway/service/service.go | 2 +- pkg/scheduledtask/models/scheduled_tasks.go | 3 +- .../predicates/guest/image_predicate.go | 2 +- pkg/util/alipayclient/alipay.go | 8 +- pkg/util/atexit/atexit.go | 2 +- pkg/util/cephutils/ceph.go | 2 +- pkg/util/gin/middleware/log.go | 5 +- pkg/util/qemuimg/qemuimg.go | 2 +- pkg/util/rbacutils/policycore.go | 5 +- pkg/util/rbacutils/policyset.go | 3 +- pkg/util/rbacutils/policytags.go | 4 +- pkg/util/s3auth/v2.go | 16 +- pkg/util/s3auth/v4.go | 83 +- pkg/util/sysutils/sysutils.go | 7 +- pkg/util/tagutils/tagsetlist.go | 5 +- pkg/webconsole/session/remote_console.go | 2 +- vendor/github.com/fatih/color/README.md | 19 +- vendor/github.com/fatih/color/color.go | 25 +- vendor/github.com/fatih/color/doc.go | 2 + .../signedxml/exclusivecanonicalization.go | 19 +- .../mattn/go-colorable/noncolorable.go | 5 +- vendor/github.com/tredoe/osutil/AUTHORS.md | 2 +- .../github.com/tredoe/osutil/CONTRIBUTORS.md | 6 +- .../tredoe/osutil/user/crypt/common/salt.go | 6 +- .../github.com/vishvananda/netlink/.gitignore | 1 + .../vishvananda/netlink/.travis.yml | 6 + .../vishvananda/netlink/addr_linux.go | 105 +- .../vishvananda/netlink/bridge_linux.go | 9 +- .../github.com/vishvananda/netlink/class.go | 141 +- .../vishvananda/netlink/class_linux.go | 145 +- .../vishvananda/netlink/conntrack_linux.go | 121 +- .../vishvananda/netlink/devlink_linux.go | 272 +++ .../github.com/vishvananda/netlink/filter.go | 102 +- .../vishvananda/netlink/filter_linux.go | 240 ++- .../vishvananda/netlink/fou_linux.go | 6 +- .../vishvananda/netlink/genetlink_linux.go | 3 + .../vishvananda/netlink/handle_linux.go | 2 +- .../vishvananda/netlink/handle_unspecified.go | 12 + .../vishvananda/netlink/ioctl_linux.go | 10 +- vendor/github.com/vishvananda/netlink/link.go | 242 ++- .../vishvananda/netlink/link_linux.go | 1122 ++++++++--- .../github.com/vishvananda/netlink/neigh.go | 7 + .../vishvananda/netlink/neigh_linux.go | 191 +- .../github.com/vishvananda/netlink/netlink.go | 3 +- .../netlink/netlink_unspecified.go | 12 + .../vishvananda/netlink/netns_linux.go | 141 ++ .../vishvananda/netlink/netns_unspecified.go | 19 + .../vishvananda/netlink/nl/bridge_linux.go | 4 +- .../vishvananda/netlink/nl/conntrack_linux.go | 40 +- .../vishvananda/netlink/nl/devlink_linux.go | 40 + .../vishvananda/netlink/nl/link_linux.go | 72 +- .../vishvananda/netlink/nl/nl_linux.go | 66 +- .../vishvananda/netlink/nl/rdma_link_linux.go | 35 + .../vishvananda/netlink/nl/route_linux.go | 26 + .../vishvananda/netlink/nl/seg6_linux.go | 43 + .../vishvananda/netlink/nl/seg6local_linux.go | 76 + .../vishvananda/netlink/nl/syscall.go | 11 +- .../vishvananda/netlink/nl/tc_linux.go | 166 +- .../vishvananda/netlink/nl/xfrm_linux.go | 62 +- .../vishvananda/netlink/protinfo.go | 4 + .../vishvananda/netlink/protinfo_linux.go | 7 +- .../github.com/vishvananda/netlink/qdisc.go | 48 + .../vishvananda/netlink/qdisc_linux.go | 69 +- .../vishvananda/netlink/rdma_link_linux.go | 264 +++ .../github.com/vishvananda/netlink/route.go | 2 + .../vishvananda/netlink/route_linux.go | 229 ++- .../vishvananda/netlink/rule_linux.go | 2 +- .../vishvananda/netlink/socket_linux.go | 5 +- .../vishvananda/netlink/xfrm_monitor_linux.go | 6 +- .../vishvananda/netlink/xfrm_policy.go | 26 +- .../vishvananda/netlink/xfrm_policy_linux.go | 19 +- .../vishvananda/netlink/xfrm_state.go | 6 +- .../vishvananda/netlink/xfrm_state_linux.go | 27 +- vendor/golang.org/x/time/rate/rate.go | 12 +- vendor/modules.txt | 95 +- vendor/yunion.io/x/cloudmux/LICENSE | 201 ++ .../pkg/apis/billing/billing_const.go | 20 + .../x/cloudmux/pkg/apis/cloudid/cloudid.go | 23 + .../cloudmux/pkg/apis/cloudid/cloudpolicy.go | 26 + .../pkg/apis/cloudid/saml_provider.go | 29 + .../x/cloudmux/pkg/apis/compute/bucket.go | 33 + .../pkg/apis/compute/cachedimages_const.go | 32 + .../x/cloudmux/pkg/apis/compute/cdn.go | 38 + .../pkg/apis/compute/cloudaccount_const.go | 265 +++ .../pkg/apis/compute/cloudregions_const.go | 233 +++ .../pkg/apis/compute/dbinstance_const.go | 187 ++ .../pkg/apis/compute/dbinstance_sku_const.go | 20 + .../x/cloudmux/pkg/apis/compute/disk_const.go | 75 + .../pkg/apis/compute/dnsrecordsets.go | 19 + .../x/cloudmux/pkg/apis/compute/dnszone.go | 84 + .../pkg/apis/compute/elastic_search.go | 24 + .../pkg/apis/compute/elasticache_const.go | 133 ++ .../pkg/apis/compute/elasticips_const.go | 57 + .../x/cloudmux/pkg/apis/compute/esxi_const.go | 19 + .../pkg/apis/compute/externalproject.go | 29 + .../x/cloudmux/pkg/apis/compute/filesystem.go | 36 + .../pkg/apis/compute/globalvpc_const.go | 20 + .../cloudmux/pkg/apis/compute/guest_const.go | 384 ++++ .../x/cloudmux/pkg/apis/compute/host_const.go | 135 ++ .../pkg/apis/compute/inter_vpc_network.go | 31 + .../x/cloudmux/pkg/apis/compute/kafka.go | 24 + .../cloudmux/pkg/apis/compute/kube_cluster.go | 29 + .../pkg/apis/compute/loadbalancer_const.go | 436 ++++ .../pkg/apis/compute/modelarts_pool.go | 25 + .../pkg/apis/compute/modelarts_pool_sku.go | 20 + .../pkg/apis/compute/mongodb_const.go | 38 + .../pkg/apis/compute/mount_targets.go | 25 + .../x/cloudmux/pkg/apis/compute/nat_skus.go | 22 + .../x/cloudmux/pkg/apis/compute/natgateway.go | 39 + .../x/cloudmux/pkg/apis/compute/network.go | 20 + .../pkg/apis/compute/network_const.go | 66 + .../apis/compute/networkinterface_const.go | 32 + .../x/cloudmux/pkg/apis/compute/regiondata.go | 568 ++++++ .../x/cloudmux/pkg/apis/compute/routetable.go | 22 + .../pkg/apis/compute/routetable_routesets.go | 48 + .../pkg/apis/compute/secgroup_const.go | 23 + .../x/cloudmux/pkg/apis/compute/sku_const.go | 59 + .../pkg/apis/compute/snapshot_const.go | 61 + .../pkg/apis/compute/storage_const.go | 162 ++ .../cloudmux/pkg/apis/compute/tablestores.go | 20 + .../apis/compute/vpc_peering_connection.go | 25 + .../x/cloudmux/pkg/apis/compute/vpcs_const.go | 38 + .../x/cloudmux/pkg/apis/compute/vpcs_ovn.go | 37 + .../cloudmux/pkg/apis/compute/waf_instance.go | 30 + .../x/cloudmux/pkg/apis/compute/wire_const.go | 22 + .../cloudmux/pkg/apis/compute/zones_const.go | 23 + vendor/yunion.io/x/cloudmux/pkg/apis/const.go | 102 + .../yunion.io/x/cloudmux/pkg/apis/metadata.go | 20 + vendor/yunion.io/x/cloudmux/pkg/apis/share.go | 22 + .../pkg}/cloudprovider/access_group.go | 0 .../x/cloudmux/pkg}/cloudprovider/cdn.go | 0 .../pkg}/cloudprovider/cloudprovider.go | 1 + .../cloudmux/pkg}/cloudprovider/cloudrole.go | 0 .../cloudmux/pkg}/cloudprovider/clouduser.go | 0 .../x/cloudmux/pkg}/cloudprovider/consts.go | 0 .../cloudmux/pkg}/cloudprovider/dbinstance.go | 0 .../x/cloudmux/pkg}/cloudprovider/disk.go | 0 .../x/cloudmux/pkg}/cloudprovider/dnszone.go | 0 .../x/cloudmux/pkg/cloudprovider/doc.go | 15 + .../x/cloudmux/pkg}/cloudprovider/eip.go | 0 .../pkg}/cloudprovider/elasticcache.go | 0 .../pkg}/cloudprovider/elasticsearch.go | 0 .../cloudmux/pkg}/cloudprovider/endpoints.go | 0 .../x/cloudmux/pkg}/cloudprovider/extra.go | 0 .../cloudmux/pkg}/cloudprovider/fakeregion.go | 0 .../x/cloudmux/pkg}/cloudprovider/geoinfo.go | 0 .../cloudmux/pkg}/cloudprovider/globalvpc.go | 0 .../x/cloudmux/pkg}/cloudprovider/i18n.go | 0 .../x/cloudmux/pkg}/cloudprovider/images.go | 0 .../x/cloudmux/pkg}/cloudprovider/instance.go | 0 .../pkg}/cloudprovider/inter_vpc_network.go | 0 .../x/cloudmux/pkg}/cloudprovider/kafka.go | 0 .../pkg}/cloudprovider/kube_cluster.go | 0 .../pkg}/cloudprovider/loadbalancer.go | 0 .../pkg}/cloudprovider/loadbalanceracl.go | 0 .../pkg}/cloudprovider/loadbalancerbackend.go | 0 .../cloudprovider/loadbalancerbackendgroup.go | 0 .../cloudprovider/loadbalancercertificate.go | 0 .../cloudprovider/loadbalancerlistener.go | 0 .../x/cloudmux/pkg}/cloudprovider/metrics.go | 0 .../pkg}/cloudprovider/modelarts_pool.go | 0 .../x/cloudmux/pkg}/cloudprovider/mongodb.go | 0 .../pkg}/cloudprovider/mount_target.go | 0 .../x/cloudmux/pkg}/cloudprovider/nas.go | 0 .../x/cloudmux/pkg}/cloudprovider/nat.go | 0 .../x/cloudmux/pkg}/cloudprovider/network.go | 0 .../pkg}/cloudprovider/objectstore.go | 0 .../x/cloudmux/pkg}/cloudprovider/osinfo.go | 0 .../cloudmux/pkg}/cloudprovider/resources.go | 0 .../pkg}/cloudprovider/resourcetags.go | 0 .../x/cloudmux/pkg}/cloudprovider/retry.go | 0 .../pkg}/cloudprovider/route_table.go | 0 .../x/cloudmux/pkg}/cloudprovider/saml.go | 0 .../pkg}/cloudprovider/securitygroup.go | 0 .../cloudmux/pkg}/cloudprovider/serversku.go | 0 .../pkg}/cloudprovider/snapshot_policy.go | 0 .../cloudmux/pkg}/cloudprovider/subaccount.go | 0 .../pkg}/cloudprovider/subscription.go | 0 .../cloudmux/pkg}/cloudprovider/transport.go | 0 .../x/cloudmux/pkg}/cloudprovider/vpc.go | 0 .../cloudprovider/vpc_peering_connection.go | 0 .../x/cloudmux/pkg}/cloudprovider/waf.go | 0 .../cloudmux/pkg}/cloudprovider/waitstatus.go | 0 .../pkg/multicloud/aliyun/access_groups.go | 329 +++ .../cloudmux/pkg}/multicloud/aliyun/aliyun.go | 5 +- .../cloudmux/pkg/multicloud/aliyun/bucket.go | 778 ++++++++ .../pkg/multicloud/aliyun/business.go | 126 ++ .../x/cloudmux/pkg/multicloud/aliyun/cdn.go | 315 +++ .../cloudmux/pkg/multicloud/aliyun/charge.go | 42 + .../aliyun/cloud_enterprise_network.go | 394 ++++ .../aliyun/cloud_enterprise_network_route.go | 6 +- .../pkg/multicloud/aliyun/dbinstance.go | 908 +++++++++ .../multicloud/aliyun/dbinstance_account.go | 178 ++ .../multicloud/aliyun/dbinstance_backup.go | 357 ++++ .../multicloud/aliyun/dbinstance_database.go | 118 ++ .../multicloud/aliyun/dbinstance_parameter.go | 0 .../multicloud/aliyun/dbinstance_privilege.go | 55 + .../x/cloudmux/pkg/multicloud/aliyun/disk.go | 427 ++++ .../pkg/multicloud/aliyun/dns_domain.go | 437 ++++ .../multicloud/aliyun/dns_domain_record.go | 4 +- .../x/cloudmux/pkg/multicloud/aliyun/doc.go | 15 + .../x/cloudmux/pkg/multicloud/aliyun/eip.go | 395 ++++ .../pkg/multicloud/aliyun/elastic_search.go | 373 ++++ .../aliyun/elastic_search_instance_types.go | 0 .../multicloud/aliyun/elasticcache_account.go | 212 ++ .../pkg/multicloud/aliyun/elasticcache_acl.go | 106 + .../multicloud/aliyun/elasticcache_backup.go | 143 ++ .../aliyun/elasticcache_instance.go | 990 +++++++++ .../aliyun/elasticcache_parameter.go | 86 + .../cloudmux/pkg}/multicloud/aliyun/errors.go | 0 .../cloudmux/pkg/multicloud/aliyun/events.go | 186 ++ .../pkg/multicloud/aliyun/filesystem.go | 362 ++++ .../x/cloudmux/pkg/multicloud/aliyun/host.go | 295 +++ .../x/cloudmux/pkg/multicloud/aliyun/image.go | 398 ++++ .../pkg/multicloud/aliyun/instance.go | 1183 +++++++++++ .../pkg/multicloud/aliyun/instancenic.go | 234 +++ .../pkg}/multicloud/aliyun/instancetype.go | 0 .../x/cloudmux/pkg/multicloud/aliyun/kafka.go | 320 +++ .../pkg}/multicloud/aliyun/keypair.go | 0 .../pkg/multicloud/aliyun/kube_cluster.go | 258 +++ .../pkg/multicloud/aliyun/kube_node.go | 114 ++ .../pkg/multicloud/aliyun/kube_node_pools.go | 156 ++ .../aliyun/latitud_and_longitude.go | 49 + .../pkg/multicloud/aliyun/loadbalancer.go | 494 +++++ .../pkg/multicloud/aliyun/loadbalanceracl.go | 162 ++ .../multicloud/aliyun/loadbalancerbackend.go | 117 ++ .../aliyun/loadbalancerbackendgroup.go | 277 +++ .../aliyun/loadbalancerdefaultbackend.go | 115 ++ .../aliyun/loadbalancerdefaultbackendgroup.go | 159 ++ .../aliyun/loadbalancerhttplistener.go | 379 ++++ .../aliyun/loadbalancerhttpslistener.go | 409 ++++ .../aliyun/loadbalancerlistenerrule.go | 182 ++ .../aliyun/loadbalancermasterslavebackend.go | 92 + .../loadbalancermasterslavebackendgroup.go | 214 ++ .../aliyun/loadbalancerservercertificate.go | 139 ++ .../aliyun/loadbalancertcplistener.go | 368 ++++ .../aliyun/loadbalancerudplistener.go | 294 +++ .../cloudmux/pkg/multicloud/aliyun/mongodb.go | 523 +++++ .../pkg}/multicloud/aliyun/mongodb_backup.go | 2 +- .../cloudmux/pkg/multicloud/aliyun/monitor.go | 634 ++++++ .../pkg/multicloud/aliyun/mount_target.go | 158 ++ .../pkg/multicloud/aliyun/natdtable.go | 187 ++ .../pkg/multicloud/aliyun/natgateway.go | 381 ++++ .../pkg/multicloud/aliyun/natstable.go | 221 ++ .../multicloud/aliyun/networkinterfaces.go | 167 ++ .../cloudmux/pkg/multicloud/aliyun/objects.go | 112 ++ .../pkg/multicloud/aliyun/private_zone.go | 405 ++++ .../multicloud/aliyun/private_zone_record.go | 4 +- .../cloudmux/pkg/multicloud/aliyun/project.go | 145 ++ .../pkg/multicloud/aliyun/provider/doc.go | 15 + .../multicloud/aliyun/provider/provider.go | 513 +++++ .../x/cloudmux/pkg/multicloud/aliyun/quota.go | 136 ++ .../x/cloudmux/pkg}/multicloud/aliyun/ram.go | 0 .../pkg/multicloud/aliyun/ram_group.go | 325 +++ .../pkg/multicloud/aliyun/ram_policy.go | 316 +++ .../pkg/multicloud/aliyun/ram_role.go | 224 +++ .../pkg/multicloud/aliyun/ram_user.go | 406 ++++ .../pkg/multicloud/aliyun/ramimage.go | 203 ++ .../cloudmux/pkg/multicloud/aliyun/region.go | 1255 ++++++++++++ .../pkg/multicloud/aliyun/resource_tags.go | 191 ++ .../pkg/multicloud/aliyun/routetable.go | 341 ++++ .../pkg/multicloud/aliyun/saml_provider.go | 201 ++ .../pkg/multicloud/aliyun/securitygroup.go | 551 +++++ .../pkg/multicloud/aliyun/snapshot.go | 223 +++ .../pkg/multicloud/aliyun/snapshot_policy.go | 303 +++ .../cloudmux/pkg/multicloud/aliyun/storage.go | 191 ++ .../pkg/multicloud/aliyun/storagecache.go | 355 ++++ .../x/cloudmux/pkg}/multicloud/aliyun/sts.go | 0 .../pkg/multicloud/aliyun/tablestore.go | 107 + .../pkg/multicloud/aliyun/tag_base.go | 78 + .../x/cloudmux/pkg}/multicloud/aliyun/task.go | 0 .../cloudmux/pkg}/multicloud/aliyun/utils.go | 0 .../x/cloudmux/pkg/multicloud/aliyun/vpc.go | 333 ++++ .../pkg}/multicloud/aliyun/vrouter.go | 0 .../cloudmux/pkg/multicloud/aliyun/vswitch.go | 276 +++ .../x/cloudmux/pkg/multicloud/aliyun/waf.go | 61 + .../pkg}/multicloud/aliyun/waf_domain.go | 8 +- .../x/cloudmux/pkg/multicloud/aliyun/wire.go | 140 ++ .../pkg}/multicloud/aliyun/wrapper.go | 0 .../x/cloudmux/pkg/multicloud/aliyun/zone.go | 304 +++ .../cloudmux/pkg}/multicloud/apsara/apsara.go | 4 +- .../cloudmux/pkg/multicloud/apsara/bucket.go | 541 +++++ .../cloudmux/pkg/multicloud/apsara/charge.go | 42 + .../pkg/multicloud/apsara/dbinstance.go | 802 ++++++++ .../multicloud/apsara/dbinstance_account.go | 178 ++ .../multicloud/apsara/dbinstance_backup.go | 304 +++ .../multicloud/apsara/dbinstance_database.go | 118 ++ .../multicloud/apsara/dbinstance_parameter.go | 0 .../multicloud/apsara/dbinstance_privilege.go | 55 + .../x/cloudmux/pkg/multicloud/apsara/disk.go | 439 ++++ .../x/cloudmux/pkg/multicloud/apsara/doc.go | 15 + .../x/cloudmux/pkg/multicloud/apsara/eip.go | 378 ++++ .../multicloud/apsara/elasticcache_account.go | 212 ++ .../pkg/multicloud/apsara/elasticcache_acl.go | 106 + .../multicloud/apsara/elasticcache_backup.go | 143 ++ .../apsara/elasticcache_instance.go | 941 +++++++++ .../apsara/elasticcache_parameter.go | 86 + .../cloudmux/pkg}/multicloud/apsara/errors.go | 0 .../x/cloudmux/pkg/multicloud/apsara/host.go | 295 +++ .../x/cloudmux/pkg/multicloud/apsara/image.go | 390 ++++ .../pkg/multicloud/apsara/instance.go | 1043 ++++++++++ .../pkg/multicloud/apsara/instancenic.go | 52 + .../pkg/multicloud/apsara/instancetype.go | 194 ++ .../pkg/multicloud/apsara/ipv6_gateway.go | 132 ++ .../pkg}/multicloud/apsara/keypair.go | 0 .../pkg/multicloud/apsara/loadbalancer.go | 410 ++++ .../pkg/multicloud/apsara/loadbalanceracl.go | 160 ++ .../multicloud/apsara/loadbalancerbackend.go | 114 ++ .../apsara/loadbalancerbackendgroup.go | 274 +++ .../apsara/loadbalancerdefaultbackend.go | 112 ++ .../apsara/loadbalancerdefaultbackendgroup.go | 156 ++ .../apsara/loadbalancerhttplistener.go | 376 ++++ .../apsara/loadbalancerhttpslistener.go | 406 ++++ .../apsara/loadbalancerlistenerrule.go | 173 ++ .../apsara/loadbalancermasterslavebackend.go | 89 + .../loadbalancermasterslavebackendgroup.go | 211 ++ .../apsara/loadbalancerservercertificate.go | 135 ++ .../apsara/loadbalancertcplistener.go | 365 ++++ .../apsara/loadbalancerudplistener.go | 291 +++ .../cloudmux/pkg/multicloud/apsara/monitor.go | 457 +++++ .../pkg/multicloud/apsara/natdtable.go | 187 ++ .../pkg/multicloud/apsara/natgateway.go | 227 +++ .../pkg/multicloud/apsara/natstable.go | 221 ++ .../multicloud/apsara/networkinterfaces.go | 167 ++ .../cloudmux/pkg/multicloud/apsara/objects.go | 112 ++ .../pkg}/multicloud/apsara/organization.go | 6 +- .../x/cloudmux/pkg}/multicloud/apsara/ots.go | 8 +- .../cloudmux/pkg/multicloud/apsara/project.go | 149 ++ .../pkg/multicloud/apsara/provider/doc.go | 15 + .../multicloud/apsara/provider/provider.go | 246 +++ .../x/cloudmux/pkg/multicloud/apsara/quota.go | 136 ++ .../x/cloudmux/pkg}/multicloud/apsara/ram.go | 0 .../pkg/multicloud/apsara/ram_group.go | 325 +++ .../pkg/multicloud/apsara/ram_policy.go | 316 +++ .../pkg}/multicloud/apsara/ram_role.go | 0 .../pkg/multicloud/apsara/ram_user.go | 406 ++++ .../pkg/multicloud/apsara/ramimage.go | 201 ++ .../cloudmux/pkg/multicloud/apsara/region.go | 1100 ++++++++++ .../pkg/multicloud/apsara/resource_tags.go | 244 +++ .../pkg/multicloud/apsara/routetable.go | 319 +++ .../pkg/multicloud/apsara/securitygroup.go | 512 +++++ .../pkg/multicloud/apsara/snapshot.go | 219 ++ .../pkg/multicloud/apsara/snapshot_policy.go | 300 +++ .../cloudmux/pkg/multicloud/apsara/storage.go | 179 ++ .../pkg/multicloud/apsara/storagecache.go | 324 +++ .../x/cloudmux/pkg}/multicloud/apsara/sts.go | 0 .../pkg/multicloud/apsara/tag_base.go | 65 + .../x/cloudmux/pkg}/multicloud/apsara/task.go | 0 .../cloudmux/pkg}/multicloud/apsara/utils.go | 0 .../x/cloudmux/pkg/multicloud/apsara/vpc.go | 317 +++ .../pkg}/multicloud/apsara/vrouter.go | 0 .../cloudmux/pkg/multicloud/apsara/vswitch.go | 272 +++ .../x/cloudmux/pkg/multicloud/apsara/wire.go | 140 ++ .../pkg}/multicloud/apsara/wrapper.go | 0 .../x/cloudmux/pkg/multicloud/apsara/zone.go | 288 +++ .../x/cloudmux/pkg}/multicloud/aws/aws.go | 4 +- .../pkg}/multicloud/aws/aws_request.go | 2 +- .../x/cloudmux/pkg/multicloud/aws/bucket.go | 800 ++++++++ .../cloudmux/pkg/multicloud/aws/cloudtrail.go | 201 ++ .../cloudmux/pkg/multicloud/aws/dbinstance.go | 655 ++++++ .../pkg/multicloud/aws/dbinstance_account.go | 30 + .../pkg}/multicloud/aws/dbinstance_const.go | 0 .../pkg/multicloud/aws/dbinstance_database.go | 47 + .../multicloud/aws/dbinstance_parameter.go | 0 .../pkg/multicloud/aws/dbinstance_snapshot.go | 194 ++ .../x/cloudmux/pkg/multicloud/aws/disk.go | 552 +++++ .../pkg}/multicloud/aws/dnshostedzone.go | 8 +- .../pkg}/multicloud/aws/dnsrecordset.go | 4 +- .../pkg}/multicloud/aws/dnstrafficpolicy.go | 0 .../x/cloudmux/pkg/multicloud/aws/doc.go | 15 + .../x/cloudmux/pkg/multicloud/aws/eip.go | 296 +++ .../multicloud/aws/elasticache_instance.go | 10 +- .../multicloud/aws/elasticache_parameter.go | 6 +- .../multicloud/aws/elasticache_snapshot.go | 8 +- .../pkg}/multicloud/aws/elasticache_user.go | 8 +- .../x/cloudmux/pkg/multicloud/aws/host.go | 288 +++ .../cloudmux/pkg/multicloud/aws/iam_group.go | 329 +++ .../cloudmux/pkg/multicloud/aws/iam_policy.go | 476 +++++ .../x/cloudmux/pkg/multicloud/aws/iam_role.go | 211 ++ .../x/cloudmux/pkg/multicloud/aws/iam_user.go | 399 ++++ .../x/cloudmux/pkg/multicloud/aws/image.go | 589 ++++++ .../pkg}/multicloud/aws/imageowners.go | 2 +- .../x/cloudmux/pkg/multicloud/aws/instance.go | 1376 +++++++++++++ .../pkg/multicloud/aws/instancenic.go | 149 ++ .../pkg}/multicloud/aws/internetgateway.go | 6 +- .../x/cloudmux/pkg/multicloud/aws/keypair.go | 175 ++ .../multicloud/aws/latitude_and_longitude.go | 49 + .../pkg/multicloud/aws/loadbalancer.go | 516 +++++ .../pkg/multicloud/aws/loadbalancerbackend.go | 114 ++ .../aws/loadbalancerbackendgroup.go | 521 +++++ .../pkg/multicloud/aws/loadbalancercert.go | 199 ++ .../multicloud/aws/loadbalancerlistener.go | 768 +++++++ .../aws/loadbalancerlistenerrule.go | 490 +++++ .../x/cloudmux/pkg/multicloud/aws/monitor.go | 193 ++ .../cloudmux/pkg/multicloud/aws/natgateway.go | 244 +++ .../x/cloudmux/pkg/multicloud/aws/network.go | 273 +++ .../pkg/multicloud/aws/networkinterface.go | 100 + .../pkg/multicloud/aws/organizations.go | 296 +++ .../pkg/multicloud/aws/provider/doc.go | 15 + .../pkg/multicloud/aws/provider/provider.go | 410 ++++ .../x/cloudmux/pkg/multicloud/aws/region.go | 1071 ++++++++++ .../pkg}/multicloud/aws/reservedinstance.go | 0 .../pkg/multicloud/aws/resource_tag.go | 121 ++ .../x/cloudmux/pkg}/multicloud/aws/route.go | 6 +- .../cloudmux/pkg/multicloud/aws/routetable.go | 365 ++++ .../x/cloudmux/pkg/multicloud/aws/s3object.go | 116 ++ .../pkg/multicloud/aws/saml_provider.go | 179 ++ .../pkg/multicloud/aws/securitygroup.go | 491 +++++ .../x/cloudmux/pkg}/multicloud/aws/sku.go | 0 .../x/cloudmux/pkg/multicloud/aws/snapshot.go | 235 +++ .../pkg}/multicloud/aws/snapshot_policy.go | 0 .../x/cloudmux/pkg/multicloud/aws/storage.go | 166 ++ .../pkg/multicloud/aws/storagecache.go | 496 +++++ .../x/cloudmux/pkg}/multicloud/aws/sts.go | 0 .../x/cloudmux/pkg/multicloud/aws/tag_base.go | 73 + .../x/cloudmux/pkg/multicloud/aws/utils.go | 513 +++++ .../x/cloudmux/pkg/multicloud/aws/vpc.go | 723 +++++++ .../multicloud/aws/vpc_peering_connection.go | 323 +++ .../x/cloudmux/pkg/multicloud/aws/waf.go | 545 +++++ .../pkg}/multicloud/aws/waf_ipsets.go | 2 +- .../pkg}/multicloud/aws/waf_regexsets.go | 2 +- .../pkg}/multicloud/aws/waf_rule_groups.go | 0 .../cloudmux/pkg}/multicloud/aws/waf_rules.go | 2 +- .../x/cloudmux/pkg/multicloud/aws/wire.go | 141 ++ .../x/cloudmux/pkg/multicloud/aws/zone.go | 209 ++ .../pkg/multicloud/azure/app_gateways.go | 216 ++ .../pkg/multicloud/azure/app_service_plan.go | 197 ++ .../multicloud/azure/autoscale_setting.go | 4 +- .../x/cloudmux/pkg}/multicloud/azure/azure.go | 4 +- .../pkg}/multicloud/azure/blobobject.go | 2 +- .../pkg}/multicloud/azure/classic_disk.go | 10 +- .../pkg}/multicloud/azure/classic_eip.go | 10 +- .../pkg}/multicloud/azure/classic_host.go | 6 +- .../pkg}/multicloud/azure/classic_instance.go | 12 +- .../multicloud/azure/classic_instancenic.go | 2 +- .../multicloud/azure/classic_instancesize.go | 0 .../pkg}/multicloud/azure/classic_network.go | 8 +- .../multicloud/azure/classic_secruitygroup.go | 6 +- .../pkg}/multicloud/azure/classic_snapshot.go | 8 +- .../pkg}/multicloud/azure/classic_storage.go | 8 +- .../pkg}/multicloud/azure/classic_vpc.go | 8 +- .../pkg}/multicloud/azure/classic_wire.go | 8 +- .../pkg/multicloud/azure/cloudgroup.go | 247 +++ .../pkg/multicloud/azure/cloudpolicy.go | 207 ++ .../pkg/multicloud/azure/clouduser.go | 359 ++++ .../multicloud/azure/concurrent/balancer.go | 0 .../pkg/multicloud/azure/concurrent/doc.go | 15 + .../pkg}/multicloud/azure/concurrent/pool.go | 0 .../multicloud/azure/concurrent/request.go | 0 .../multicloud/azure/concurrent/worker.go | 0 .../pkg}/multicloud/azure/data_disk.go | 8 +- .../pkg/multicloud/azure/dbinstance.go | 406 ++++ .../multicloud/azure/dbinstance_account.go | 29 + .../azure/dbinstance_configuration.go | 0 .../multicloud/azure/dbinstance_database.go | 89 + .../x/cloudmux/pkg}/multicloud/azure/debug.go | 0 .../x/cloudmux/pkg/multicloud/azure/disk.go | 337 ++++ .../x/cloudmux/pkg/multicloud/azure/doc.go | 15 + .../x/cloudmux/pkg/multicloud/azure/eip.go | 273 +++ .../multicloud/azure/enrollment_account.go | 100 + .../pkg}/multicloud/azure/enterprise_redis.go | 8 +- .../x/cloudmux/pkg/multicloud/azure/event.go | 154 ++ .../pkg}/multicloud/azure/geographicinfo.go | 4 +- .../x/cloudmux/pkg/multicloud/azure/host.go | 309 +++ .../x/cloudmux/pkg/multicloud/azure/image.go | 607 ++++++ .../cloudmux/pkg/multicloud/azure/instance.go | 1122 +++++++++++ .../pkg/multicloud/azure/instancenic.go | 235 +++ .../pkg/multicloud/azure/kube_cluster.go | 220 ++ .../pkg/multicloud/azure/kube_node_pools.go | 64 + .../pkg/multicloud/azure/loadbalancer.go | 751 +++++++ .../multicloud/azure/loadbalancer_props.go | 0 .../multicloud/azure/loadbalancerbackend.go | 99 + .../azure/loadbalancerbackendgroup.go | 221 ++ .../pkg/multicloud/azure/loadbalancercert.go | 183 ++ .../multicloud/azure/loadbalancerlistener.go | 600 ++++++ .../azure/loadbalancerlistenerrule.go | 192 ++ .../pkg}/multicloud/azure/loganalytics.go | 0 .../cloudmux/pkg/multicloud/azure/monitor.go | 506 +++++ .../cloudmux/pkg/multicloud/azure/network.go | 125 ++ .../cloudmux/pkg}/multicloud/azure/os_disk.go | 8 +- .../cloudmux/pkg}/multicloud/azure/policy.go | 0 .../multicloud/azure/progress/computeStats.go | 0 .../pkg/multicloud/azure/progress/doc.go | 15 + .../azure/progress/readerWithProgress.go | 0 .../pkg}/multicloud/azure/progress/status.go | 0 .../pkg/multicloud/azure/provider/doc.go | 15 + .../pkg/multicloud/azure/provider/provider.go | 297 +++ .../pkg}/multicloud/azure/publisher.go | 2 +- .../multicloud/azure/rds_managed_sqlserver.go | 6 +- .../azure/rds_managed_sqlserver_account.go | 4 +- .../azure/rds_managed_sqlserver_database.go | 8 +- .../pkg/multicloud/azure/rds_sqlserver.go | 215 ++ .../multicloud/azure/rds_sqlserver_account.go | 4 +- .../multicloud/azure/rds_sqlserver_backup.go | 8 +- .../azure/rds_sqlserver_database.go | 8 +- .../x/cloudmux/pkg/multicloud/azure/redis.go | 402 ++++ .../pkg}/multicloud/azure/redis_acl.go | 8 +- .../x/cloudmux/pkg/multicloud/azure/region.go | 731 +++++++ .../pkg/multicloud/azure/resourcegroup.go | 88 + .../pkg}/multicloud/azure/resourcesku.go | 0 .../pkg/multicloud/azure/saml_provider.go | 137 ++ .../pkg/multicloud/azure/securitygroup.go | 489 +++++ .../cloudmux/pkg/multicloud/azure/service.go | 95 + .../cloudmux/pkg/multicloud/azure/snapshot.go | 173 ++ .../cloudmux/pkg/multicloud/azure/storage.go | 155 ++ .../pkg/multicloud/azure/storageaccount.go | 1305 ++++++++++++ .../pkg/multicloud/azure/storagecache.go | 290 +++ .../pkg/multicloud/azure/subscription.go | 40 + .../cloudmux/pkg/multicloud/azure/tag_base.go | 37 + .../cloudmux/pkg}/multicloud/azure/upload.go | 4 +- .../x/cloudmux/pkg/multicloud/azure/usage.go | 82 + .../x/cloudmux/pkg/multicloud/azure/vpc.go | 167 ++ .../x/cloudmux/pkg/multicloud/azure/waf.go | 656 ++++++ .../pkg}/multicloud/azure/waf_front_doors.go | 0 .../pkg}/multicloud/azure/waf_rule_groups.go | 0 .../cloudmux/pkg/multicloud/azure/web_app.go | 316 +++ .../x/cloudmux/pkg/multicloud/azure/wire.go | 120 ++ .../x/cloudmux/pkg/multicloud/azure/zone.go | 178 ++ .../cloudmux/pkg}/multicloud/billing_base.go | 2 +- .../pkg}/multicloud/bingocloud/bingo.go | 4 +- .../pkg/multicloud/bingocloud/cluster.go | 105 + .../pkg/multicloud/bingocloud/disk.go | 255 +++ .../cloudmux/pkg/multicloud/bingocloud/doc.go | 15 + .../cloudmux/pkg/multicloud/bingocloud/eip.go | 174 ++ .../pkg}/multicloud/bingocloud/host.go | 0 .../pkg/multicloud/bingocloud/image.go | 245 +++ .../pkg/multicloud/bingocloud/instance.go | 384 ++++ .../pkg/multicloud/bingocloud/instancenic.go | 113 ++ .../pkg/multicloud/bingocloud/monitor.go | 144 ++ .../pkg/multicloud/bingocloud/network.go | 199 ++ .../pkg/multicloud/bingocloud/node.go | 270 +++ .../pkg/multicloud/bingocloud/provider/doc.go | 15 + .../bingocloud/provider/provider.go | 162 ++ .../pkg/multicloud/bingocloud/region.go | 175 ++ .../pkg/multicloud/bingocloud/secgroup.go | 190 ++ .../pkg/multicloud/bingocloud/storage.go | 173 ++ .../pkg/multicloud/bingocloud/storagecache.go | 71 + .../pkg/multicloud/bingocloud/tag_base.go | 44 + .../cloudmux/pkg/multicloud/bingocloud/vpc.go | 142 ++ .../pkg/multicloud/bingocloud/wire.go | 94 + .../pkg}/multicloud/bingocloud/zone.go | 0 .../x/cloudmux/pkg}/multicloud/bucket_base.go | 4 +- .../pkg}/multicloud/cloudpods/cloudpods.go | 5 +- .../cloudmux/pkg/multicloud/cloudpods/disk.go | 282 +++ .../cloudmux/pkg/multicloud/cloudpods/doc.go | 15 + .../cloudmux/pkg/multicloud/cloudpods/eip.go | 183 ++ .../cloudmux/pkg/multicloud/cloudpods/host.go | 290 +++ .../pkg/multicloud/cloudpods/image.go | 220 ++ .../pkg/multicloud/cloudpods/instance.go | 566 ++++++ .../pkg/multicloud/cloudpods/instancenic.go | 102 + .../pkg}/multicloud/cloudpods/keypair.go | 0 .../pkg/multicloud/cloudpods/network.go | 137 ++ .../pkg/multicloud/cloudpods/project.go | 71 + .../pkg/multicloud/cloudpods/provider/doc.go | 15 + .../multicloud/cloudpods/provider/provider.go | 161 ++ .../pkg/multicloud/cloudpods/region.go | 131 ++ .../pkg/multicloud/cloudpods/secgroup.go | 207 ++ .../cloudmux/pkg/multicloud/cloudpods/sku.go | 161 ++ .../pkg/multicloud/cloudpods/snapshot.go | 112 ++ .../pkg/multicloud/cloudpods/storage.go | 140 ++ .../pkg/multicloud/cloudpods/storagecache.go | 129 ++ .../pkg/multicloud/cloudpods/tag_base.go | 46 + .../cloudmux/pkg/multicloud/cloudpods/vpc.go | 152 ++ .../cloudmux/pkg/multicloud/cloudpods/wire.go | 121 ++ .../cloudmux/pkg/multicloud/cloudpods/zone.go | 90 + .../x/cloudmux/pkg/multicloud/clouduser.go | 36 + .../x/cloudmux/pkg}/multicloud/ctyun/crm.go | 0 .../x/cloudmux/pkg}/multicloud/ctyun/ctyun.go | 4 +- .../x/cloudmux/pkg/multicloud/ctyun/disk.go | 599 ++++++ .../pkg}/multicloud/ctyun/diskbackup.go | 6 +- .../multicloud/ctyun/diskbackup_policy.go | 8 +- .../x/cloudmux/pkg/multicloud/ctyun/doc.go | 15 + .../x/cloudmux/pkg/multicloud/ctyun/eip.go | 398 ++++ .../x/cloudmux/pkg/multicloud/ctyun/host.go | 288 +++ .../x/cloudmux/pkg/multicloud/ctyun/image.go | 214 ++ .../cloudmux/pkg/multicloud/ctyun/instance.go | 1306 ++++++++++++ .../pkg/multicloud/ctyun/instancenic.go | 94 + .../cloudmux/pkg}/multicloud/ctyun/keypair.go | 0 .../multicloud/ctyun/latitud_and_longitude.go | 62 + .../cloudmux/pkg/multicloud/ctyun/network.go | 295 +++ .../x/cloudmux/pkg}/multicloud/ctyun/order.go | 0 .../cloudmux/pkg/multicloud/ctyun/project.go | 70 + .../pkg/multicloud/ctyun/provider/doc.go | 15 + .../pkg/multicloud/ctyun/provider/provider.go | 199 ++ .../x/cloudmux/pkg/multicloud/ctyun/region.go | 488 +++++ .../pkg}/multicloud/ctyun/secrules.go | 0 .../pkg/multicloud/ctyun/securitygroup.go | 364 ++++ .../cloudmux/pkg/multicloud/ctyun/storage.go | 164 ++ .../pkg/multicloud/ctyun/storagecache.go | 105 + .../cloudmux/pkg/multicloud/ctyun/tag_base.go | 36 + .../x/cloudmux/pkg/multicloud/ctyun/vpc.go | 232 +++ .../x/cloudmux/pkg/multicloud/ctyun/wire.go | 141 ++ .../x/cloudmux/pkg/multicloud/ctyun/zone.go | 151 ++ .../multicloud/dbinstance_account_base.go | 4 +- .../pkg}/multicloud/dbinstance_backup_base.go | 4 +- .../pkg}/multicloud/dbinstance_base.go | 2 +- .../multicloud/dbinstance_database_base.go | 2 +- .../x/cloudmux/pkg}/multicloud/disk_base.go | 0 .../x/cloudmux/pkg/multicloud/doc.go | 15 + .../cloudmux/pkg/multicloud/ecloud/client.go | 322 +++ .../pkg}/multicloud/ecloud/create_time.go | 0 .../x/cloudmux/pkg/multicloud/ecloud/disk.go | 276 +++ .../x/cloudmux/pkg/multicloud/ecloud/doc.go | 15 + .../x/cloudmux/pkg/multicloud/ecloud/eip.go | 171 ++ .../x/cloudmux/pkg/multicloud/ecloud/host.go | 172 ++ .../x/cloudmux/pkg/multicloud/ecloud/image.go | 196 ++ .../pkg/multicloud/ecloud/instance.go | 528 +++++ .../pkg/multicloud/ecloud/instancenic.go | 87 + .../ecloud/latitud_and_longitude.go | 51 + .../cloudmux/pkg/multicloud/ecloud/monitor.go | 206 ++ .../cloudmux/pkg/multicloud/ecloud/network.go | 190 ++ .../pkg/multicloud/ecloud/provider/doc.go | 15 + .../multicloud/ecloud/provider/provider.go | 185 ++ .../cloudmux/pkg/multicloud/ecloud/region.go | 355 ++++ .../pkg}/multicloud/ecloud/request.go | 0 .../cloudmux/pkg}/multicloud/ecloud/signer.go | 0 .../pkg/multicloud/ecloud/snapshot.go | 130 ++ .../cloudmux/pkg/multicloud/ecloud/storage.go | 166 ++ .../pkg/multicloud/ecloud/storagecache.go | 100 + .../pkg/multicloud/ecloud/tag_base.go | 36 + .../x/cloudmux/pkg/multicloud/ecloud/vpc.go | 178 ++ .../x/cloudmux/pkg/multicloud/ecloud/wire.go | 140 ++ .../x/cloudmux/pkg/multicloud/ecloud/zone.go | 148 ++ .../x/cloudmux/pkg}/multicloud/eip_base.go | 0 .../pkg}/multicloud/elasticcache_base.go | 0 .../x/cloudmux/pkg/multicloud/esxi/cluster.go | 110 + .../pkg/multicloud/esxi/datacenter.go | 596 ++++++ .../x/cloudmux/pkg}/multicloud/esxi/device.go | 0 .../cloudmux/pkg}/multicloud/esxi/devtools.go | 0 .../x/cloudmux/pkg/multicloud/esxi/doc.go | 15 + .../pkg}/multicloud/esxi/fakeregion.go | 4 +- .../cloudmux/pkg}/multicloud/esxi/guestos.go | 0 .../x/cloudmux/pkg/multicloud/esxi/host.go | 1769 +++++++++++++++++ .../cloudmux/pkg}/multicloud/esxi/hostnic.go | 0 .../x/cloudmux/pkg/multicloud/esxi/image.go | 158 ++ .../x/cloudmux/pkg}/multicloud/esxi/ip.go | 0 .../x/cloudmux/pkg}/multicloud/esxi/logger.go | 0 .../x/cloudmux/pkg/multicloud/esxi/manager.go | 743 +++++++ .../x/cloudmux/pkg}/multicloud/esxi/mobase.go | 2 +- .../x/cloudmux/pkg/multicloud/esxi/monitor.go | 292 +++ .../pkg}/multicloud/esxi/net_topology.go | 0 .../pkg}/multicloud/esxi/net_topology_pro.go | 0 .../cloudmux/pkg}/multicloud/esxi/network.go | 0 .../pkg/multicloud/esxi/provider/doc.go | 15 + .../pkg/multicloud/esxi/provider/provider.go | 232 +++ .../pkg/multicloud/esxi/resourcepool.go | 58 + .../cloudmux/pkg/multicloud/esxi/snapshot.go | 87 + .../x/cloudmux/pkg/multicloud/esxi/storage.go | 1198 +++++++++++ .../pkg/multicloud/esxi/storagecache.go | 292 +++ .../cloudmux/pkg}/multicloud/esxi/template.go | 6 +- .../x/cloudmux/pkg}/multicloud/esxi/utils.go | 0 .../pkg/multicloud/esxi/vcenter/doc.go | 15 + .../pkg}/multicloud/esxi/vcenter/vcenter.go | 0 .../x/cloudmux/pkg}/multicloud/esxi/vdisk.go | 10 +- .../pkg/multicloud/esxi/virtualmachine.go | 1534 ++++++++++++++ .../x/cloudmux/pkg}/multicloud/esxi/vnic.go | 2 +- .../cloudmux/pkg}/multicloud/esxi/vswitch.go | 0 .../pkg}/multicloud/google/bigquery.go | 0 .../cloudmux/pkg/multicloud/google/bucket.go | 528 +++++ .../pkg}/multicloud/google/bucketacl.go | 2 +- .../pkg}/multicloud/google/cloudbuild.go | 0 .../pkg/multicloud/google/dbinstance.go | 636 ++++++ .../multicloud/google/dbinstance_account.go | 125 ++ .../multicloud/google/dbinstance_backup.go | 171 ++ .../multicloud/google/dbinstance_database.go | 105 + .../multicloud/google/dbinstance_parameter.go | 0 .../x/cloudmux/pkg/multicloud/google/disk.go | 274 +++ .../x/cloudmux/pkg/multicloud/google/doc.go | 15 + .../x/cloudmux/pkg/multicloud/google/eip.go | 223 +++ .../pkg/multicloud/google/globalnetwork.go | 135 ++ .../cloudmux/pkg}/multicloud/google/google.go | 4 +- .../x/cloudmux/pkg/multicloud/google/host.go | 189 ++ .../pkg}/multicloud/google/iampolicy.go | 4 +- .../x/cloudmux/pkg/multicloud/google/image.go | 270 +++ .../pkg/multicloud/google/instance.go | 998 ++++++++++ .../pkg/multicloud/google/instancenic.go | 65 + .../google/latitude_and_longitude.go | 97 + .../pkg/multicloud/google/loadbalancer.go | 480 +++++ .../multicloud/google/loadbalancer_backend.go | 205 ++ .../google/loadbalancer_backendgroup.go | 173 ++ .../multicloud/google/loadbalancer_cert.go | 172 ++ .../google/loadbalancer_components.go | 2 +- .../google/loadbalancer_listener.go | 596 ++++++ .../google/loadbalancer_listenerrule.go | 182 ++ .../pkg/multicloud/google/machinetype.go | 57 + .../cloudmux/pkg/multicloud/google/monitor.go | 119 ++ .../cloudmux/pkg/multicloud/google/network.go | 109 + .../pkg}/multicloud/google/operation.go | 2 +- .../cloudmux/pkg/multicloud/google/project.go | 99 + .../pkg/multicloud/google/provider/doc.go | 15 + .../multicloud/google/provider/provider.go | 315 +++ .../x/cloudmux/pkg/multicloud/google/quota.go | 60 + .../cloudmux/pkg/multicloud/google/region.go | 833 ++++++++ .../pkg}/multicloud/google/regiondisk.go | 0 .../pkg}/multicloud/google/regionstorage.go | 0 .../pkg}/multicloud/google/resourcebase.go | 0 .../pkg/multicloud/google/resourcepolicy.go | 163 ++ .../pkg/multicloud/google/s3object.go | 207 ++ .../x/cloudmux/pkg}/multicloud/google/saml.go | 0 .../pkg/multicloud/google/securitygroup.go | 429 ++++ .../x/cloudmux/pkg/multicloud/google/sku.go | 352 ++++ .../pkg/multicloud/google/snapshot.go | 113 ++ .../cloudmux/pkg/multicloud/google/storage.go | 155 ++ .../pkg/multicloud/google/storagecache.go | 210 ++ .../pkg/multicloud/google/tag_base.go | 53 + .../x/cloudmux/pkg/multicloud/google/vpc.go | 170 ++ .../x/cloudmux/pkg/multicloud/google/wire.go | 94 + .../x/cloudmux/pkg/multicloud/google/zone.go | 128 ++ .../x/cloudmux/pkg/multicloud/hcs/bucket.go | 804 ++++++++ .../cloudmux/pkg/multicloud/hcs/dbinstance.go | 707 +++++++ .../pkg/multicloud/hcs/dbinstance_account.go | 126 ++ .../pkg/multicloud/hcs/dbinstance_backup.go | 239 +++ .../pkg/multicloud/hcs/dbinstance_database.go | 73 + .../multicloud/hcs/dbinstance_parameter.go | 0 .../multicloud/hcs/dbinstance_privilege.go | 43 + .../pkg/multicloud/hcs/dbinstance_skus.go | 273 +++ .../x/cloudmux/pkg/multicloud/hcs/disk.go | 439 ++++ .../x/cloudmux/pkg/multicloud/hcs/doc.go | 1 + .../x/cloudmux/pkg/multicloud/hcs/eip.go | 434 ++++ .../x/cloudmux/pkg}/multicloud/hcs/hcs.go | 6 +- .../x/cloudmux/pkg/multicloud/hcs/host.go | 254 +++ .../x/cloudmux/pkg/multicloud/hcs/image.go | 469 +++++ .../x/cloudmux/pkg/multicloud/hcs/instance.go | 1115 +++++++++++ .../pkg/multicloud/hcs/instancenic.go | 86 + .../pkg/multicloud/hcs/instancetype.go | 223 +++ .../x/cloudmux/pkg/multicloud/hcs/job.go | 105 + .../x/cloudmux/pkg}/multicloud/hcs/keypair.go | 0 .../pkg/multicloud/hcs/loadbalancer.go | 602 ++++++ .../pkg/multicloud/hcs/loadbalancer_acl.go | 156 ++ .../multicloud/hcs/loadbalancer_backend.go | 142 ++ .../hcs/loadbalancer_backendgroup.go | 491 +++++ .../pkg/multicloud/hcs/loadbalancer_cert.go | 182 ++ .../hcs/loadbalancer_healthcheck.go | 0 .../multicloud/hcs/loadbalancer_listener.go | 644 ++++++ .../hcs/loadbalancer_listener_rule.go | 169 ++ .../x/cloudmux/pkg/multicloud/hcs/monitor.go | 494 +++++ .../x/cloudmux/pkg}/multicloud/hcs/nat_sku.go | 4 +- .../cloudmux/pkg/multicloud/hcs/natdtable.go | 149 ++ .../cloudmux/pkg/multicloud/hcs/natgateway.go | 265 +++ .../cloudmux/pkg/multicloud/hcs/natstable.go | 143 ++ .../x/cloudmux/pkg/multicloud/hcs/network.go | 167 ++ .../x/cloudmux/pkg/multicloud/hcs/object.go | 104 + .../x/cloudmux/pkg/multicloud/hcs/port.go | 162 ++ .../x/cloudmux/pkg/multicloud/hcs/project.go | 98 + .../pkg/multicloud/hcs/provider/doc.go | 1 + .../pkg/multicloud/hcs/provider/provider.go | 217 ++ .../x/cloudmux/pkg/multicloud/hcs/redis.go | 608 ++++++ .../pkg}/multicloud/hcs/redis_account.go | 9 +- .../pkg}/multicloud/hcs/redis_backup.go | 9 +- .../pkg}/multicloud/hcs/redis_instancetype.go | 6 +- .../pkg}/multicloud/hcs/redis_parameter.go | 7 +- .../x/cloudmux/pkg/multicloud/hcs/region.go | 332 ++++ .../pkg/multicloud/hcs/routetables.go | 215 ++ .../pkg/multicloud/hcs/securitygroup.go | 340 ++++ .../x/cloudmux/pkg}/multicloud/hcs/signer.go | 0 .../x/cloudmux/pkg/multicloud/hcs/snapshot.go | 192 ++ .../x/cloudmux/pkg/multicloud/hcs/storage.go | 135 ++ .../pkg/multicloud/hcs/storagecache.go | 255 +++ .../x/cloudmux/pkg/multicloud/hcs/tag_base.go | 46 + .../x/cloudmux/pkg/multicloud/hcs/vpc.go | 312 +++ .../pkg/multicloud/hcs/vpc_peering.go | 144 ++ .../x/cloudmux/pkg/multicloud/hcs/wire.go | 127 ++ .../x/cloudmux/pkg/multicloud/hcs/zone.go | 230 +++ .../x/cloudmux/pkg/multicloud/hcso/bucket.go | 775 ++++++++ .../multicloud/hcso/client/auth/credential.go | 0 .../auth/credentials/access_key_credential.go | 0 .../hcso/client/auth/credentials/doc.go | 15 + .../pkg/multicloud/hcso/client/auth/doc.go | 15 + .../pkg/multicloud/hcso/client/auth/signer.go | 214 ++ .../hcso/client/auth/signers/doc.go | 15 + .../client/auth/signers/signer_access_key.go | 55 + .../pkg/multicloud/hcso/client/client.go | 286 +++ .../pkg/multicloud/hcso/client/doc.go | 15 + .../pkg/multicloud/hcso/client/manager/doc.go | 15 + .../multicloud/hcso/client/manager/manager.go | 84 + .../pkg/multicloud/hcso/client/modules/doc.go | 15 + .../hcso/client/modules/manager_base.go | 268 +++ .../hcso/client/modules/manager_resource.go | 298 +++ .../hcso/client/modules/mod_bandwidths.go | 2 +- .../multicloud/hcso/client/modules/mod_ces.go | 120 ++ .../hcso/client/modules/mod_credential.go | 37 + .../hcso/client/modules/mod_dbinstance.go | 103 + .../client/modules/mod_dbinstance_backup.go | 37 + .../modules/mod_dbinstance_datastore.go | 2 +- .../client/modules/mod_dbinstance_flavor.go | 37 + .../hcso/client/modules/mod_dbinstance_job.go | 43 + .../client/modules/mod_dbinstance_storage.go | 2 +- .../hcso/client/modules/mod_disks.go | 76 + .../hcso/client/modules/mod_dnat_rules.go | 41 + .../hcso/client/modules/mod_domains.go | 95 + .../hcso/client/modules/mod_eips.go | 2 +- .../hcso/client/modules/mod_elasticcache.go | 118 ++ .../hcso/client/modules/mod_endpoints.go | 2 +- .../client/modules/mod_enterpriceprojects.go | 39 + .../hcso/client/modules/mod_flavors.go | 37 + .../hcso/client/modules/mod_groups.go | 39 + .../hcso/client/modules/mod_images.go | 101 + .../hcso/client/modules/mod_interface.go | 38 + .../hcso/client/modules/mod_jobs.go | 71 + .../hcso/client/modules/mod_keypairs.go | 37 + .../modules/mod_loadbalancer_backend.go | 2 +- .../modules/mod_loadbalancer_backend_group.go | 2 +- .../modules/mod_loadbalancer_certificates.go | 2 +- .../modules/mod_loadbalancer_healthcheck.go | 2 +- .../modules/mod_loadbalancer_listeners.go | 2 +- .../modules/mod_loadbalancer_policies.go | 2 +- .../client/modules/mod_loadbalancer_rules.go | 2 +- .../modules/mod_loadbalancer_whitelists.go | 2 +- .../hcso/client/modules/mod_loadbalancers.go | 2 +- .../hcso/client/modules/mod_mapping.go | 39 + .../hcso/client/modules/mod_natgateway.go | 50 + .../hcso/client/modules/mod_port.go | 53 + .../hcso/client/modules/mod_projects.go | 89 + .../hcso/client/modules/mod_quotas.go | 37 + .../hcso/client/modules/mod_regions.go | 37 + .../hcso/client/modules/mod_roles.go | 39 + .../hcso/client/modules/mod_saml_provider.go | 39 + .../hcso/client/modules/mod_secgroup_rules.go | 37 + .../hcso/client/modules/mod_secgroups.go | 51 + .../hcso/client/modules/mod_servers.go | 124 ++ .../hcso/client/modules/mod_services.go | 2 +- .../multicloud/hcso/client/modules/mod_sfs.go | 48 + .../hcso/client/modules/mod_snapshots.go | 59 + .../hcso/client/modules/mod_snat_rules.go | 41 + .../hcso/client/modules/mod_subnets.go | 37 + .../hcso/client/modules/mod_traces.go | 37 + .../hcso/client/modules/mod_users.go | 69 + .../hcso/client/modules/mod_vpc_peerings.go | 37 + .../hcso/client/modules/mod_vpc_routes.go | 38 + .../hcso/client/modules/mod_vpcs.go | 37 + .../hcso/client/modules/mod_zones.go | 37 + .../multicloud/hcso/client/requests/doc.go | 15 + .../hcso/client/requests/requests.go | 0 .../multicloud/hcso/client/responses/doc.go | 15 + .../hcso/client/responses/responses.go | 0 .../pkg/multicloud/hcso/cloudgroup.go | 446 +++++ .../cloudmux/pkg/multicloud/hcso/clouduser.go | 293 +++ .../x/cloudmux/pkg}/multicloud/hcso/consts.go | 0 .../pkg/multicloud/hcso/dbinstance.go | 694 +++++++ .../pkg/multicloud/hcso/dbinstance_account.go | 133 ++ .../pkg/multicloud/hcso/dbinstance_backup.go | 237 +++ .../multicloud/hcso/dbinstance_database.go | 73 + .../multicloud/hcso/dbinstance_parameter.go | 0 .../multicloud/hcso/dbinstance_privilege.go | 43 + .../pkg/multicloud/hcso/dbinstance_skus.go | 263 +++ .../x/cloudmux/pkg/multicloud/hcso/disk.go | 534 +++++ .../cloudmux/pkg}/multicloud/hcso/disktype.go | 0 .../x/cloudmux/pkg/multicloud/hcso/doc.go | 15 + .../x/cloudmux/pkg}/multicloud/hcso/domain.go | 0 .../x/cloudmux/pkg/multicloud/hcso/eip.go | 402 ++++ .../multicloud/hcso/elasticcache_account.go | 109 + .../pkg}/multicloud/hcso/elasticcache_acl.go | 0 .../multicloud/hcso/elasticcache_backup.go | 139 ++ .../multicloud/hcso/elasticcache_instance.go | 752 +++++++ .../multicloud/hcso/elasticcache_parameter.go | 79 + .../pkg/multicloud/hcso/enterpriceprojects.go | 115 ++ .../x/cloudmux/pkg}/multicloud/hcso/hcso.go | 2 +- .../x/cloudmux/pkg/multicloud/hcso/host.go | 349 ++++ .../x/cloudmux/pkg/multicloud/hcso/huawei.go | 554 ++++++ .../x/cloudmux/pkg/multicloud/hcso/image.go | 472 +++++ .../cloudmux/pkg/multicloud/hcso/instance.go | 1467 ++++++++++++++ .../pkg/multicloud/hcso/instancenic.go | 110 + .../pkg/multicloud/hcso/instancetype.go | 314 +++ .../cloudmux/pkg}/multicloud/hcso/keypair.go | 0 .../multicloud/hcso/latitud_and_longitude.go | 44 + .../pkg/multicloud/hcso/loadbalancer.go | 554 ++++++ .../pkg/multicloud/hcso/loadbalancer_acl.go | 114 ++ .../multicloud/hcso/loadbalancer_backend.go | 169 ++ .../hcso/loadbalancer_backendgroup.go | 542 +++++ .../pkg/multicloud/hcso/loadbalancer_cert.go | 124 ++ .../hcso/loadbalancer_healthcheck.go | 0 .../multicloud/hcso/loadbalancer_listener.go | 695 +++++++ .../hcso/loadbalancer_listener_rule.go | 173 ++ .../cloudmux/pkg/multicloud/hcso/modelarts.go | 394 ++++ .../pkg/multicloud/hcso/modelarts_sku.go | 131 ++ .../x/cloudmux/pkg/multicloud/hcso/monitor.go | 107 + .../cloudmux/pkg/multicloud/hcso/nat_skus.go | 97 + .../cloudmux/pkg/multicloud/hcso/natdtable.go | 132 ++ .../pkg/multicloud/hcso/natgateway.go | 354 ++++ .../cloudmux/pkg/multicloud/hcso/natstable.go | 122 ++ .../x/cloudmux/pkg/multicloud/hcso/network.go | 175 ++ .../x/cloudmux/pkg/multicloud/hcso/object.go | 103 + .../x/cloudmux/pkg}/multicloud/hcso/order.go | 0 .../x/cloudmux/pkg/multicloud/hcso/port.go | 162 ++ .../x/cloudmux/pkg/multicloud/hcso/project.go | 106 + .../pkg/multicloud/hcso/provider/doc.go | 15 + .../pkg/multicloud/hcso/provider/provider.go | 336 ++++ .../x/cloudmux/pkg/multicloud/hcso/quota.go | 80 + .../x/cloudmux/pkg/multicloud/hcso/region.go | 1114 +++++++++++ .../x/cloudmux/pkg/multicloud/hcso/roles.go | 164 ++ .../pkg/multicloud/hcso/routetable.go | 357 ++++ .../pkg/multicloud/hcso/saml_provider.go | 350 ++++ .../pkg/multicloud/hcso/securitygroup.go | 276 +++ .../cloudmux/pkg/multicloud/hcso/sfs-turbo.go | 299 +++ .../cloudmux/pkg/multicloud/hcso/snapshot.go | 190 ++ .../x/cloudmux/pkg/multicloud/hcso/storage.go | 162 ++ .../pkg/multicloud/hcso/storagecache.go | 325 +++ .../x/cloudmux/pkg}/multicloud/hcso/task.go | 0 .../x/cloudmux/pkg/multicloud/hcso/traces.go | 131 ++ .../x/cloudmux/pkg/multicloud/hcso/utils.go | 271 +++ .../x/cloudmux/pkg/multicloud/hcso/vpc.go | 369 ++++ .../pkg/multicloud/hcso/vpc_peering.go | 160 ++ .../x/cloudmux/pkg/multicloud/hcso/wire.go | 207 ++ .../x/cloudmux/pkg/multicloud/hcso/zone.go | 263 +++ .../x/cloudmux/pkg}/multicloud/host_base.go | 0 .../cloudmux/pkg/multicloud/huawei/bucket.go | 766 +++++++ .../huawei/client/auth/credential.go | 0 .../auth/credentials/access_key_credential.go | 0 .../huawei/client/auth/credentials/doc.go | 15 + .../pkg/multicloud/huawei/client/auth/doc.go | 15 + .../multicloud/huawei/client/auth/signer.go | 215 ++ .../huawei/client/auth/signers/doc.go | 15 + .../client/auth/signers/signer_access_key.go | 55 + .../pkg/multicloud/huawei/client/client.go | 249 +++ .../pkg/multicloud/huawei/client/doc.go | 15 + .../multicloud/huawei/client/manager/doc.go | 15 + .../huawei/client/manager/manager.go | 81 + .../multicloud/huawei/client/modules/doc.go | 15 + .../huawei/client/modules/manager_base.go | 272 +++ .../huawei/client/modules/manager_resource.go | 298 +++ .../huawei/client/modules/mod_balances.go | 4 +- .../huawei/client/modules/mod_ces.go | 152 ++ .../huawei/client/modules/mod_credential.go | 37 + .../huawei/client/modules/mod_dbinstance.go | 103 + .../client/modules/mod_dbinstance_backup.go | 37 + .../client/modules/mod_dbinstance_flavor.go | 37 + .../client/modules/mod_dbinstance_job.go | 43 + .../huawei/client/modules/mod_disks.go | 76 + .../huawei/client/modules/mod_dnat_rules.go | 41 + .../huawei/client/modules/mod_domains.go | 95 + .../huawei/client/modules/mod_elasticcache.go | 118 ++ .../client/modules/mod_enterpriceprojects.go | 39 + .../huawei/client/modules/mod_flavors.go | 37 + .../huawei/client/modules/mod_groups.go | 39 + .../huawei/client/modules/mod_images.go | 101 + .../huawei/client/modules/mod_interface.go | 38 + .../huawei/client/modules/mod_jobs.go | 71 + .../huawei/client/modules/mod_keypairs.go | 37 + .../huawei/client/modules/mod_mapping.go | 39 + .../huawei/client/modules/mod_natgateway.go | 50 + .../huawei/client/modules/mod_orders.go | 4 +- .../huawei/client/modules/mod_port.go | 53 + .../huawei/client/modules/mod_projects.go | 89 + .../huawei/client/modules/mod_quotas.go | 37 + .../huawei/client/modules/mod_regions.go | 37 + .../huawei/client/modules/mod_roles.go | 39 + .../huawei/client/modules/mod_routetables.go | 2 +- .../client/modules/mod_saml_provider.go | 39 + .../client/modules/mod_secgroup_rules.go | 37 + .../huawei/client/modules/mod_secgroups.go | 51 + .../huawei/client/modules/mod_servers.go | 124 ++ .../huawei/client/modules/mod_sfs.go | 48 + .../huawei/client/modules/mod_snapshots.go | 59 + .../huawei/client/modules/mod_snat_rules.go | 41 + .../huawei/client/modules/mod_subnets.go | 37 + .../huawei/client/modules/mod_traces.go | 37 + .../huawei/client/modules/mod_users.go | 69 + .../huawei/client/modules/mod_vpc_peerings.go | 37 + .../huawei/client/modules/mod_vpc_routes.go | 38 + .../huawei/client/modules/mod_vpcs.go | 37 + .../huawei/client/modules/mod_zones.go | 37 + .../multicloud/huawei/client/requests/doc.go | 15 + .../huawei/client/requests/requests.go | 0 .../multicloud/huawei/client/responses/doc.go | 15 + .../huawei/client/responses/responses.go | 0 .../pkg/multicloud/huawei/cloudgroup.go | 465 +++++ .../pkg/multicloud/huawei/clouduser.go | 289 +++ .../cloudmux/pkg}/multicloud/huawei/consts.go | 0 .../pkg/multicloud/huawei/dbinstance.go | 780 ++++++++ .../multicloud/huawei/dbinstance_account.go | 132 ++ .../multicloud/huawei/dbinstance_backup.go | 236 +++ .../multicloud/huawei/dbinstance_database.go | 72 + .../multicloud/huawei/dbinstance_parameter.go | 0 .../multicloud/huawei/dbinstance_privilege.go | 43 + .../x/cloudmux/pkg/multicloud/huawei/disk.go | 558 ++++++ .../pkg}/multicloud/huawei/disktype.go | 0 .../x/cloudmux/pkg/multicloud/huawei/doc.go | 15 + .../cloudmux/pkg}/multicloud/huawei/domain.go | 0 .../x/cloudmux/pkg/multicloud/huawei/eip.go | 396 ++++ .../multicloud/huawei/elasticcache_account.go | 108 + .../multicloud/huawei/elasticcache_acl.go | 0 .../multicloud/huawei/elasticcache_backup.go | 138 ++ .../huawei/elasticcache_instance.go | 760 +++++++ .../huawei/elasticcache_parameter.go | 78 + .../multicloud/huawei/enterpriceprojects.go | 114 ++ .../x/cloudmux/pkg/multicloud/huawei/host.go | 306 +++ .../cloudmux/pkg/multicloud/huawei/huawei.go | 863 ++++++++ .../x/cloudmux/pkg/multicloud/huawei/image.go | 474 +++++ .../pkg/multicloud/huawei/instance.go | 1538 ++++++++++++++ .../pkg/multicloud/huawei/instancenic.go | 111 ++ .../pkg}/multicloud/huawei/instancetype.go | 0 .../pkg}/multicloud/huawei/keypair.go | 0 .../huawei/latitud_and_longitude.go | 44 + .../pkg/multicloud/huawei/loadbalancer.go | 625 ++++++ .../pkg/multicloud/huawei/loadbalancer_acl.go | 152 ++ .../multicloud/huawei/loadbalancer_backend.go | 161 ++ .../huawei/loadbalancer_backendgroup.go | 509 +++++ .../multicloud/huawei/loadbalancer_cert.go | 154 ++ .../huawei/loadbalancer_healthcheck.go | 0 .../huawei/loadbalancer_listener.go | 663 ++++++ .../huawei/loadbalancer_listener_rule.go | 166 ++ .../pkg/multicloud/huawei/modelarts_pool.go | 393 ++++ .../multicloud/huawei/modelarts_pool_sku.go | 130 ++ .../cloudmux/pkg/multicloud/huawei/monitor.go | 563 ++++++ .../pkg/multicloud/huawei/natdtable.go | 131 ++ .../pkg/multicloud/huawei/natgateway.go | 353 ++++ .../pkg/multicloud/huawei/natstable.go | 121 ++ .../cloudmux/pkg/multicloud/huawei/network.go | 174 ++ .../cloudmux/pkg/multicloud/huawei/object.go | 103 + .../pkg}/multicloud/huawei/obs/auth.go | 0 .../pkg}/multicloud/huawei/obs/client.go | 0 .../pkg}/multicloud/huawei/obs/conf.go | 0 .../pkg}/multicloud/huawei/obs/const.go | 0 .../pkg}/multicloud/huawei/obs/convert.go | 0 .../cloudmux/pkg/multicloud/huawei/obs/doc.go | 15 + .../pkg}/multicloud/huawei/obs/error.go | 0 .../pkg}/multicloud/huawei/obs/http.go | 0 .../pkg}/multicloud/huawei/obs/log.go | 0 .../pkg}/multicloud/huawei/obs/model.go | 0 .../pkg}/multicloud/huawei/obs/temporary.go | 0 .../pkg}/multicloud/huawei/obs/trait.go | 0 .../pkg}/multicloud/huawei/obs/util.go | 0 .../x/cloudmux/pkg/multicloud/huawei/order.go | 193 ++ .../x/cloudmux/pkg/multicloud/huawei/port.go | 161 ++ .../cloudmux/pkg/multicloud/huawei/project.go | 94 + .../pkg/multicloud/huawei/provider/doc.go | 15 + .../multicloud/huawei/provider/provider.go | 314 +++ .../x/cloudmux/pkg/multicloud/huawei/quota.go | 80 + .../cloudmux/pkg/multicloud/huawei/region.go | 862 ++++++++ .../x/cloudmux/pkg/multicloud/huawei/roles.go | 99 + .../pkg/multicloud/huawei/routetables.go | 232 +++ .../pkg/multicloud/huawei/saml_provider.go | 367 ++++ .../pkg/multicloud/huawei/securitygroup.go | 275 +++ .../pkg/multicloud/huawei/sfs-turbo.go | 298 +++ .../pkg/multicloud/huawei/snapshot.go | 189 ++ .../cloudmux/pkg/multicloud/huawei/storage.go | 161 ++ .../pkg/multicloud/huawei/storagecache.go | 302 +++ .../pkg/multicloud/huawei/tag_base.go | 62 + .../x/cloudmux/pkg}/multicloud/huawei/task.go | 0 .../cloudmux/pkg/multicloud/huawei/traces.go | 131 ++ .../x/cloudmux/pkg/multicloud/huawei/utils.go | 270 +++ .../x/cloudmux/pkg/multicloud/huawei/vpc.go | 361 ++++ .../pkg/multicloud/huawei/vpc_peering.go | 159 ++ .../x/cloudmux/pkg/multicloud/huawei/wire.go | 192 ++ .../x/cloudmux/pkg/multicloud/huawei/zone.go | 204 ++ .../x/cloudmux/pkg}/multicloud/image_base.go | 2 +- .../pkg/multicloud/incloudsphere/disk.go | 246 +++ .../pkg/multicloud/incloudsphere/doc.go | 15 + .../pkg/multicloud/incloudsphere/host.go | 452 +++++ .../pkg/multicloud/incloudsphere/image.go | 183 ++ .../pkg/multicloud/incloudsphere/instance.go | 613 ++++++ .../pkg/multicloud/incloudsphere/network.go | 184 ++ .../pkg/multicloud/incloudsphere/nic.go | 129 ++ .../multicloud/incloudsphere/provider/doc.go | 15 + .../incloudsphere/provider/provider.go | 171 ++ .../pkg/multicloud/incloudsphere/region.go | 212 ++ .../pkg}/multicloud/incloudsphere/sphere.go | 4 +- .../pkg/multicloud/incloudsphere/storage.go | 224 +++ .../multicloud/incloudsphere/storagecache.go | 126 ++ .../pkg/multicloud/incloudsphere/tag_base.go | 37 + .../pkg/multicloud/incloudsphere/task.go | 58 + .../pkg}/multicloud/incloudsphere/version.go | 0 .../pkg/multicloud/incloudsphere/vpc.go | 98 + .../pkg/multicloud/incloudsphere/wire.go | 146 ++ .../pkg/multicloud/incloudsphere/zone.go | 156 ++ .../cloudmux/pkg}/multicloud/instance_base.go | 2 +- .../pkg}/multicloud/jdcloud/balance.go | 0 .../x/cloudmux/pkg/multicloud/jdcloud/disk.go | 285 +++ .../x/cloudmux/pkg/multicloud/jdcloud/doc.go | 15 + .../x/cloudmux/pkg/multicloud/jdcloud/eip.go | 151 ++ .../x/cloudmux/pkg/multicloud/jdcloud/host.go | 187 ++ .../cloudmux/pkg/multicloud/jdcloud/image.go | 215 ++ .../pkg/multicloud/jdcloud/instance.go | 443 +++++ .../pkg/multicloud/jdcloud/instancenic.go | 52 + .../pkg}/multicloud/jdcloud/instancetype.go | 0 .../pkg}/multicloud/jdcloud/jdcloud.go | 4 +- .../jdcloud/latitud_and_longitude.go | 27 + .../x/cloudmux/pkg}/multicloud/jdcloud/log.go | 0 .../pkg/multicloud/jdcloud/monitor.go | 155 ++ .../pkg/multicloud/jdcloud/network.go | 156 ++ .../multicloud/jdcloud/networkinterface.go | 107 + .../pkg/multicloud/jdcloud/provider/doc.go | 15 + .../multicloud/jdcloud/provider/provider.go | 200 ++ .../x/cloudmux/pkg/multicloud/jdcloud/rds.go | 266 +++ .../pkg}/multicloud/jdcloud/rds_account.go | 8 +- .../pkg}/multicloud/jdcloud/rds_backup.go | 8 +- .../pkg}/multicloud/jdcloud/rds_database.go | 8 +- .../pkg}/multicloud/jdcloud/rds_privilege.go | 0 .../cloudmux/pkg/multicloud/jdcloud/region.go | 312 +++ .../pkg/multicloud/jdcloud/securitygroup.go | 162 ++ .../pkg/multicloud/jdcloud/snapshot.go | 159 ++ .../pkg/multicloud/jdcloud/storage.go | 148 ++ .../pkg/multicloud/jdcloud/storagecache.go | 107 + .../pkg/multicloud/jdcloud/tag_base.go | 36 + .../cloudmux/pkg/multicloud/jdcloud/utils.go | 46 + .../x/cloudmux/pkg/multicloud/jdcloud/vpc.go | 190 ++ .../x/cloudmux/pkg/multicloud/jdcloud/wire.go | 120 ++ .../x/cloudmux/pkg/multicloud/jdcloud/zone.go | 195 ++ .../pkg}/multicloud/lbredirect_base.go | 0 .../pkg}/multicloud/loadbalancer_base.go | 2 +- .../x/cloudmux/pkg/multicloud/loader/doc.go | 15 + .../cloudmux/pkg/multicloud/loader/loader.go | 49 + .../cloudmux/pkg}/multicloud/mongodb_base.go | 0 .../x/cloudmux/pkg}/multicloud/nas_base.go | 0 .../pkg}/multicloud/natgateway_base.go | 2 +- .../pkg}/multicloud/networkinterface_base.go | 0 .../cloudmux/pkg}/multicloud/no_lb_region.go | 2 +- .../pkg}/multicloud/no_storage_region.go | 2 +- .../pkg}/multicloud/nutanix/cluster.go | 0 .../x/cloudmux/pkg/multicloud/nutanix/disk.go | 355 ++++ .../x/cloudmux/pkg/multicloud/nutanix/doc.go | 15 + .../x/cloudmux/pkg/multicloud/nutanix/host.go | 512 +++++ .../cloudmux/pkg/multicloud/nutanix/image.go | 249 +++ .../pkg/multicloud/nutanix/instance.go | 422 ++++ .../pkg/multicloud/nutanix/instancenic.go | 106 + .../pkg/multicloud/nutanix/network.go | 183 ++ .../pkg}/multicloud/nutanix/nutanix.go | 4 +- .../pkg/multicloud/nutanix/provider/doc.go | 15 + .../multicloud/nutanix/provider/provider.go | 201 ++ .../cloudmux/pkg/multicloud/nutanix/region.go | 222 +++ .../pkg/multicloud/nutanix/storage.go | 332 ++++ .../pkg/multicloud/nutanix/storagecache.go | 136 ++ .../cloudmux/pkg}/multicloud/nutanix/task.go | 0 .../x/cloudmux/pkg/multicloud/nutanix/vpc.go | 182 ++ .../x/cloudmux/pkg/multicloud/nutanix/wire.go | 103 + .../x/cloudmux/pkg/multicloud/nutanix/zone.go | 118 ++ .../pkg}/multicloud/objectstore/buckets.go | 6 +- .../multicloud/objectstore/ceph/adminapi.go | 0 .../pkg/multicloud/objectstore/ceph/bucket.go | 67 + .../pkg}/multicloud/objectstore/ceph/ceph.go | 6 +- .../pkg/multicloud/objectstore/ceph/doc.go | 15 + .../objectstore/ceph/provider/doc.go | 15 + .../objectstore/ceph/provider/provider.go | 65 + .../pkg/multicloud/objectstore/doc.go | 15 + .../pkg}/multicloud/objectstore/interface.go | 2 +- .../pkg/multicloud/objectstore/object.go | 92 + .../multicloud/objectstore/objectstore.go | 6 +- .../multicloud/objectstore/provider/doc.go | 15 + .../objectstore/provider/provider.go | 166 ++ .../pkg}/multicloud/objectstore/shell.go | 2 +- .../multicloud/objectstore/xsky/adminapi.go | 3 +- .../pkg/multicloud/objectstore/xsky/bucket.go | 89 + .../pkg/multicloud/objectstore/xsky/doc.go | 15 + .../objectstore/xsky/provider/doc.go | 15 + .../objectstore/xsky/provider/provider.go | 68 + .../pkg}/multicloud/objectstore/xsky/xsky.go | 6 +- .../cloudmux/pkg/multicloud/openstack/disk.go | 448 +++++ .../cloudmux/pkg/multicloud/openstack/doc.go | 15 + .../cloudmux/pkg/multicloud/openstack/eip.go | 335 ++++ .../pkg/multicloud/openstack/flavor.go | 285 +++ .../pkg}/multicloud/openstack/host.go | 0 .../pkg}/multicloud/openstack/hypervisor.go | 6 +- .../pkg/multicloud/openstack/image.go | 335 ++++ .../pkg/multicloud/openstack/instance.go | 1167 +++++++++++ .../pkg/multicloud/openstack/instancenic.go | 99 + .../pkg}/multicloud/openstack/keypaire.go | 2 +- .../multicloud/openstack/loadbalabcerpool.go | 8 +- .../multicloud/openstack/loadbalanceracl.go | 187 ++ .../openstack/loadbalancerl7policy.go | 8 +- .../openstack/loadbalancerl7rule.go | 8 +- .../openstack/loadbalancerlistener.go | 774 ++++++++ .../openstack/loadbalancermember.go | 6 +- .../pkg}/multicloud/openstack/loadbalbacer.go | 8 +- .../openstack/loadbalbancerhealthmonitor.go | 8 +- .../pkg}/multicloud/openstack/message.go | 0 .../pkg/multicloud/openstack/network.go | 347 ++++ .../pkg}/multicloud/openstack/nova_disk.go | 10 +- .../pkg}/multicloud/openstack/novastorage.go | 8 +- .../pkg}/multicloud/openstack/openstack.go | 6 +- .../cloudmux/pkg/multicloud/openstack/port.go | 219 ++ .../pkg/multicloud/openstack/project.go | 125 ++ .../pkg/multicloud/openstack/provider/doc.go | 15 + .../multicloud/openstack/provider/provider.go | 225 +++ .../pkg/multicloud/openstack/quota.go | 165 ++ .../pkg/multicloud/openstack/region.go | 620 ++++++ .../pkg/multicloud/openstack/roles.go | 67 + .../pkg}/multicloud/openstack/router.go | 0 .../pkg/multicloud/openstack/routetable.go | 139 ++ .../pkg/multicloud/openstack/securitygroup.go | 324 +++ .../pkg/multicloud/openstack/snapshot.go | 216 ++ .../pkg/multicloud/openstack/storage.go | 257 +++ .../pkg/multicloud/openstack/storagecache.go | 160 ++ .../pkg/multicloud/openstack/tag_base.go | 37 + .../cloudmux/pkg/multicloud/openstack/vpc.go | 268 +++ .../cloudmux/pkg/multicloud/openstack/wire.go | 112 ++ .../cloudmux/pkg/multicloud/openstack/zone.go | 210 ++ .../x/cloudmux/pkg}/multicloud/progress.go | 0 .../cloudmux/pkg}/multicloud/project_base.go | 0 .../pkg}/multicloud/proxmox/cluster.go | 0 .../x/cloudmux/pkg/multicloud/proxmox/disk.go | 236 +++ .../x/cloudmux/pkg/multicloud/proxmox/doc.go | 15 + .../x/cloudmux/pkg/multicloud/proxmox/host.go | 335 ++++ .../cloudmux/pkg/multicloud/proxmox/image.go | 249 +++ .../pkg/multicloud/proxmox/instance.go | 1019 ++++++++++ .../pkg/multicloud/proxmox/network.go | 187 ++ .../x/cloudmux/pkg/multicloud/proxmox/nic.go | 65 + .../pkg/multicloud/proxmox/provider/doc.go | 1 + .../multicloud/proxmox/provider/provider.go | 200 ++ .../pkg}/multicloud/proxmox/proxmox.go | 4 +- .../cloudmux/pkg/multicloud/proxmox/region.go | 204 ++ .../pkg/multicloud/proxmox/storage.go | 230 +++ .../pkg/multicloud/proxmox/storagecache.go | 95 + .../pkg/multicloud/proxmox/tag_base.go | 37 + .../x/cloudmux/pkg/multicloud/proxmox/task.go | 86 + .../cloudmux/pkg}/multicloud/proxmox/util.go | 0 .../x/cloudmux/pkg/multicloud/proxmox/vpc.go | 98 + .../x/cloudmux/pkg/multicloud/proxmox/wire.go | 95 + .../x/cloudmux/pkg/multicloud/proxmox/zone.go | 157 ++ .../multicloud/qcloud/bandwidthpackage.go | 0 .../cloudmux/pkg/multicloud/qcloud/bucket.go | 1169 +++++++++++ .../multicloud/qcloud/cam_collaborator.go | 0 .../pkg/multicloud/qcloud/cam_group.go | 385 ++++ .../pkg/multicloud/qcloud/cam_policy.go | 285 +++ .../pkg/multicloud/qcloud/cam_role.go | 275 +++ .../pkg/multicloud/qcloud/cam_user.go | 297 +++ .../x/cloudmux/pkg/multicloud/qcloud/cdn.go | 321 +++ .../pkg}/multicloud/qcloud/certificate.go | 6 +- .../qcloud/cloud_connect_network.go | 400 ++++ .../qcloud/cloud_connect_network_route.go | 6 +- .../pkg/multicloud/qcloud/dbinstance.go | 63 + .../x/cloudmux/pkg}/multicloud/qcloud/deal.go | 2 +- .../x/cloudmux/pkg/multicloud/qcloud/disk.go | 415 ++++ .../pkg}/multicloud/qcloud/dnspod_domain.go | 8 +- .../pkg}/multicloud/qcloud/dnspod_record.go | 4 +- .../x/cloudmux/pkg/multicloud/qcloud/doc.go | 113 ++ .../x/cloudmux/pkg/multicloud/qcloud/eip.go | 424 ++++ .../pkg/multicloud/qcloud/elastic_search.go | 351 ++++ .../multicloud/qcloud/elasticcache_account.go | 172 ++ .../multicloud/qcloud/elasticcache_backup.go | 185 ++ .../qcloud/elasticcache_instance.go | 1229 ++++++++++++ .../qcloud/elasticcache_parameters.go | 8 +- .../qcloud/elasticcache_secgroup.go | 2 +- .../multicloud/qcloud/elasticcache_task.go | 0 .../cloudmux/pkg}/multicloud/qcloud/errors.go | 0 .../cloudmux/pkg/multicloud/qcloud/events.go | 158 ++ .../x/cloudmux/pkg/multicloud/qcloud/host.go | 289 +++ .../x/cloudmux/pkg/multicloud/qcloud/image.go | 383 ++++ .../pkg/multicloud/qcloud/instance.go | 1072 ++++++++++ .../pkg/multicloud/qcloud/instancenic.go | 54 + .../pkg}/multicloud/qcloud/instancetype.go | 0 .../x/cloudmux/pkg/multicloud/qcloud/kafka.go | 250 +++ .../pkg}/multicloud/qcloud/kafka_topic.go | 2 +- .../cloudmux/pkg/multicloud/qcloud/keypair.go | 193 ++ .../pkg}/multicloud/qcloud/kube_clusters.go | 6 +- .../pkg/multicloud/qcloud/kube_node_pools.go | 113 ++ .../pkg/multicloud/qcloud/kube_nodes.go | 126 ++ .../qcloud/latitud_and_longitude.go | 43 + .../pkg/multicloud/qcloud/loadbalancer.go | 715 +++++++ .../pkg/multicloud/qcloud/loadbalancer_acl.go | 73 + .../multicloud/qcloud/loadbalancer_backend.go | 209 ++ .../qcloud/loadbalancer_backendgroup.go | 422 ++++ .../qcloud/loadbalancer_listener.go | 884 ++++++++ .../qcloud/loadbalancer_listenerrule.go | 170 ++ .../pkg}/multicloud/qcloud/localdisk.go | 8 +- .../pkg}/multicloud/qcloud/localstorage.go | 6 +- .../pkg/multicloud/qcloud/memcached.go | 314 +++ .../cloudmux/pkg/multicloud/qcloud/mongodb.go | 406 ++++ .../cloudmux/pkg/multicloud/qcloud/monitor.go | 372 ++++ .../pkg/multicloud/qcloud/natdtable.go | 104 + .../pkg/multicloud/qcloud/natgateway.go | 164 ++ .../cloudmux/pkg/multicloud/qcloud/network.go | 183 ++ .../pkg/multicloud/qcloud/networkinterface.go | 199 ++ .../cloudmux/pkg/multicloud/qcloud/object.go | 90 + .../cloudmux/pkg/multicloud/qcloud/project.go | 115 ++ .../pkg/multicloud/qcloud/provider/doc.go | 15 + .../multicloud/qcloud/provider/provider.go | 463 +++++ .../cloudmux/pkg}/multicloud/qcloud/qcloud.go | 4 +- .../x/cloudmux/pkg/multicloud/qcloud/quota.go | 131 ++ .../pkg}/multicloud/qcloud/rds_mariadb_sku.go | 2 +- .../pkg/multicloud/qcloud/rds_mysql.go | 923 +++++++++ .../multicloud/qcloud/rds_mysql_account.go | 8 +- .../multicloud/qcloud/rds_mysql_backup.go | 8 +- .../multicloud/qcloud/rds_mysql_database.go | 8 +- .../pkg}/multicloud/qcloud/rds_mysql_sku.go | 2 +- .../pkg}/multicloud/qcloud/rds_postgre_sku.go | 2 +- .../multicloud/qcloud/rds_sqlserver_sku.go | 2 +- .../pkg}/multicloud/qcloud/rds_tdsql.go | 10 +- .../cloudmux/pkg/multicloud/qcloud/region.go | 1244 ++++++++++++ .../pkg/multicloud/qcloud/route_table.go | 245 +++ .../pkg/multicloud/qcloud/saml_provider.go | 184 ++ .../pkg/multicloud/qcloud/securitygroup.go | 570 ++++++ .../pkg/multicloud/qcloud/snapshot.go | 233 +++ .../pkg/multicloud/qcloud/snapshot_policy.go | 275 +++ .../cloudmux/pkg/multicloud/qcloud/storage.go | 156 ++ .../pkg/multicloud/qcloud/storagecache.go | 213 ++ .../x/cloudmux/pkg}/multicloud/qcloud/sts.go | 0 .../pkg/multicloud/qcloud/tag_base.go | 105 + .../x/cloudmux/pkg}/multicloud/qcloud/tags.go | 0 .../pkg}/multicloud/qcloud/tdsql_account.go | 6 +- .../pkg}/multicloud/qcloud/tdsql_database.go | 8 +- .../cloudmux/pkg}/multicloud/qcloud/types.go | 0 .../x/cloudmux/pkg/multicloud/qcloud/vpc.go | 428 ++++ .../qcloud/vpc_peering_connection.go | 287 +++ .../x/cloudmux/pkg/multicloud/qcloud/wire.go | 156 ++ .../x/cloudmux/pkg/multicloud/qcloud/zone.go | 312 +++ .../x/cloudmux/pkg}/multicloud/region_base.go | 2 +- .../pkg/multicloud/remotefile/bucket.go | 185 ++ .../pkg/multicloud/remotefile/dbinstance.go | 216 ++ .../pkg/multicloud/remotefile/disk.go | 131 ++ .../cloudmux/pkg/multicloud/remotefile/doc.go | 1 + .../cloudmux/pkg/multicloud/remotefile/eip.go | 73 + .../pkg/multicloud/remotefile/host.go | 193 ++ .../pkg/multicloud/remotefile/instance.go | 264 +++ .../pkg/multicloud/remotefile/instancenic.go | 64 + .../pkg/multicloud/remotefile/loadbalancer.go | 118 ++ .../pkg}/multicloud/remotefile/misc.go | 0 .../pkg/multicloud/remotefile/monitor.go | 34 + .../pkg/multicloud/remotefile/network.go | 68 + .../pkg}/multicloud/remotefile/projects.go | 6 +- .../pkg/multicloud/remotefile/provider/doc.go | 1 + .../remotefile/provider/provider.go | 155 ++ .../pkg/multicloud/remotefile/region.go | 324 +++ .../pkg}/multicloud/remotefile/remotefile.go | 4 +- .../pkg}/multicloud/remotefile/resource.go | 6 +- .../multicloud/remotefile/securitygroup.go | 48 + .../pkg/multicloud/remotefile/storage.go | 111 ++ .../pkg/multicloud/remotefile/tag_base.go | 38 + .../cloudmux/pkg/multicloud/remotefile/vpc.go | 153 ++ .../pkg/multicloud/remotefile/wire.go | 93 + .../pkg/multicloud/remotefile/zone.go | 90 + .../cloudmux/pkg}/multicloud/resource_base.go | 0 .../cloudmux/pkg}/multicloud/secgroup_base.go | 2 +- .../pkg}/multicloud/serversku_base.go | 2 +- .../cloudmux/pkg}/multicloud/storage_base.go | 0 .../x/cloudmux/pkg/multicloud/tag_base.go | 44 + .../cloudmux/pkg/multicloud/ucloud/client.go | 204 ++ .../cloudmux/pkg}/multicloud/ucloud/consts.go | 0 .../x/cloudmux/pkg/multicloud/ucloud/disk.go | 456 +++++ .../x/cloudmux/pkg/multicloud/ucloud/doc.go | 15 + .../x/cloudmux/pkg/multicloud/ucloud/eip.go | 289 +++ .../x/cloudmux/pkg/multicloud/ucloud/host.go | 359 ++++ .../x/cloudmux/pkg/multicloud/ucloud/image.go | 228 +++ .../pkg/multicloud/ucloud/instance.go | 705 +++++++ .../pkg/multicloud/ucloud/instancenic.go | 56 + .../ucloud/latitud_and_longitude.go | 48 + .../cloudmux/pkg/multicloud/ucloud/network.go | 201 ++ .../cloudmux/pkg/multicloud/ucloud/project.go | 64 + .../pkg/multicloud/ucloud/provider/doc.go | 15 + .../multicloud/ucloud/provider/provider.go | 193 ++ .../cloudmux/pkg/multicloud/ucloud/region.go | 697 +++++++ .../pkg/multicloud/ucloud/securitygroup.go | 253 +++ .../pkg/multicloud/ucloud/snapshot.go | 207 ++ .../cloudmux/pkg/multicloud/ucloud/storage.go | 157 ++ .../pkg/multicloud/ucloud/storagecache.go | 393 ++++ .../pkg/multicloud/ucloud/tag_base.go | 36 + .../cloudmux/pkg}/multicloud/ucloud/ucloud.go | 4 +- .../x/cloudmux/pkg/multicloud/ucloud/ufile.go | 394 ++++ .../cloudmux/pkg}/multicloud/ucloud/utils.go | 0 .../x/cloudmux/pkg/multicloud/ucloud/vip.go | 119 ++ .../x/cloudmux/pkg/multicloud/ucloud/vpc.go | 242 +++ .../x/cloudmux/pkg/multicloud/ucloud/wire.go | 113 ++ .../x/cloudmux/pkg/multicloud/ucloud/zone.go | 203 ++ .../pkg}/multicloud/virtualresource_base.go | 0 .../x/cloudmux/pkg}/multicloud/vpc_base.go | 4 +- .../pkg}/multicloud/zstack/cluster.go | 0 .../pkg}/multicloud/zstack/configuration.go | 0 .../x/cloudmux/pkg/multicloud/zstack/disk.go | 419 ++++ .../pkg}/multicloud/zstack/disk_offering.go | 0 .../x/cloudmux/pkg/multicloud/zstack/doc.go | 15 + .../x/cloudmux/pkg/multicloud/zstack/eip.go | 203 ++ .../x/cloudmux/pkg/multicloud/zstack/host.go | 479 +++++ .../x/cloudmux/pkg/multicloud/zstack/image.go | 303 +++ .../pkg}/multicloud/zstack/image_server.go | 0 .../pkg/multicloud/zstack/instance.go | 689 +++++++ .../pkg/multicloud/zstack/instancenic.go | 74 + .../cloudmux/pkg/multicloud/zstack/monitor.go | 141 ++ .../cloudmux/pkg/multicloud/zstack/network.go | 258 +++ .../pkg}/multicloud/zstack/network_service.go | 0 .../pkg}/multicloud/zstack/offering.go | 8 +- .../pkg/multicloud/zstack/provider/doc.go | 15 + .../multicloud/zstack/provider/provider.go | 167 ++ .../x/cloudmux/pkg/multicloud/zstack/quota.go | 104 + .../cloudmux/pkg/multicloud/zstack/region.go | 386 ++++ .../pkg/multicloud/zstack/securitygroup.go | 264 +++ .../pkg/multicloud/zstack/snapshot.go | 144 ++ .../cloudmux/pkg/multicloud/zstack/storage.go | 266 +++ .../pkg}/multicloud/zstack/storage_local.go | 8 +- .../pkg/multicloud/zstack/storagecache.go | 137 ++ .../cloudmux/pkg}/multicloud/zstack/systag.go | 0 .../pkg/multicloud/zstack/tag_base.go | 36 + .../pkg}/multicloud/zstack/version.go | 0 .../x/cloudmux/pkg/multicloud/zstack/vip.go | 180 ++ .../x/cloudmux/pkg/multicloud/zstack/vpc.go | 116 ++ .../x/cloudmux/pkg/multicloud/zstack/wire.go | 147 ++ .../x/cloudmux/pkg/multicloud/zstack/zone.go | 183 ++ .../cloudmux/pkg}/multicloud/zstack/zstack.go | 4 +- .../pkg}/multicloud/zstack/zstack_const.go | 0 3181 files changed, 220134 insertions(+), 251243 deletions(-) delete mode 100644 cmd/aliyuncli/main.go delete mode 100644 cmd/apsaracli/main.go delete mode 100644 cmd/awscli/main.go delete mode 100644 cmd/azurecli/main.go delete mode 100644 cmd/bingocli/main.go delete mode 100644 cmd/cloudpodscli/main.go delete mode 100644 cmd/ctyuncli/main.go delete mode 100644 cmd/ecloudcli/main.go delete mode 100644 cmd/esxicli/main.go delete mode 100644 cmd/googlecli/main.go delete mode 100644 cmd/hcscli/main.go delete mode 100644 cmd/hcsocli/main.go delete mode 100644 cmd/huaweicli/main.go delete mode 100644 cmd/incloudspherecli/main.go delete mode 100644 cmd/jdcloudcli/main.go delete mode 100644 cmd/ncli/main.go delete mode 100644 cmd/openstackcli/main.go delete mode 100644 cmd/proxmoxcli/main.go delete mode 100644 cmd/qcloudcli/main.go delete mode 100644 cmd/s3cli/main.go delete mode 100644 cmd/ucloudcli/main.go delete mode 100644 cmd/zstackcli/main.go delete mode 100644 pkg/cloudprovider/dnszone_test.go delete mode 100644 pkg/cloudprovider/doc.go delete mode 100644 pkg/cloudprovider/objectstore_test.go delete mode 100644 pkg/multicloud/aliyun/access_groups.go delete mode 100644 pkg/multicloud/aliyun/bucket.go delete mode 100644 pkg/multicloud/aliyun/business.go delete mode 100644 pkg/multicloud/aliyun/cdn.go delete mode 100644 pkg/multicloud/aliyun/charge.go delete mode 100644 pkg/multicloud/aliyun/cloud_enterprise_network.go delete mode 100644 pkg/multicloud/aliyun/dbinstance.go delete mode 100644 pkg/multicloud/aliyun/dbinstance_account.go delete mode 100644 pkg/multicloud/aliyun/dbinstance_backup.go delete mode 100644 pkg/multicloud/aliyun/dbinstance_database.go delete mode 100644 pkg/multicloud/aliyun/dbinstance_privilege.go delete mode 100644 pkg/multicloud/aliyun/disk.go delete mode 100644 pkg/multicloud/aliyun/dns_domain.go delete mode 100644 pkg/multicloud/aliyun/doc.go delete mode 100644 pkg/multicloud/aliyun/eip.go delete mode 100644 pkg/multicloud/aliyun/elastic_search.go delete mode 100644 pkg/multicloud/aliyun/elasticcache_account.go delete mode 100644 pkg/multicloud/aliyun/elasticcache_acl.go delete mode 100644 pkg/multicloud/aliyun/elasticcache_backup.go delete mode 100644 pkg/multicloud/aliyun/elasticcache_instance.go delete mode 100644 pkg/multicloud/aliyun/elasticcache_parameter.go delete mode 100644 pkg/multicloud/aliyun/events.go delete mode 100644 pkg/multicloud/aliyun/filesystem.go delete mode 100644 pkg/multicloud/aliyun/host.go delete mode 100644 pkg/multicloud/aliyun/image.go delete mode 100644 pkg/multicloud/aliyun/instance.go delete mode 100644 pkg/multicloud/aliyun/instancenic.go delete mode 100644 pkg/multicloud/aliyun/kafka.go delete mode 100644 pkg/multicloud/aliyun/kube_cluster.go delete mode 100644 pkg/multicloud/aliyun/kube_node.go delete mode 100644 pkg/multicloud/aliyun/kube_node_pools.go delete mode 100644 pkg/multicloud/aliyun/latitud_and_longitude.go delete mode 100644 pkg/multicloud/aliyun/loadbalancer.go delete mode 100644 pkg/multicloud/aliyun/loadbalanceracl.go delete mode 100644 pkg/multicloud/aliyun/loadbalancerbackend.go delete mode 100644 pkg/multicloud/aliyun/loadbalancerbackendgroup.go delete mode 100644 pkg/multicloud/aliyun/loadbalancerdefaultbackend.go delete mode 100644 pkg/multicloud/aliyun/loadbalancerdefaultbackendgroup.go delete mode 100644 pkg/multicloud/aliyun/loadbalancerhttplistener.go delete mode 100644 pkg/multicloud/aliyun/loadbalancerhttpslistener.go delete mode 100644 pkg/multicloud/aliyun/loadbalancerlistenerrule.go delete mode 100644 pkg/multicloud/aliyun/loadbalancermasterslavebackend.go delete mode 100644 pkg/multicloud/aliyun/loadbalancermasterslavebackendgroup.go delete mode 100644 pkg/multicloud/aliyun/loadbalancerservercertificate.go delete mode 100644 pkg/multicloud/aliyun/loadbalancertcplistener.go delete mode 100644 pkg/multicloud/aliyun/loadbalancerudplistener.go delete mode 100644 pkg/multicloud/aliyun/mongodb.go delete mode 100644 pkg/multicloud/aliyun/monitor.go delete mode 100644 pkg/multicloud/aliyun/mount_target.go delete mode 100644 pkg/multicloud/aliyun/natdtable.go delete mode 100644 pkg/multicloud/aliyun/natgateway.go delete mode 100644 pkg/multicloud/aliyun/natstable.go delete mode 100644 pkg/multicloud/aliyun/networkinterfaces.go delete mode 100644 pkg/multicloud/aliyun/objects.go delete mode 100644 pkg/multicloud/aliyun/private_zone.go delete mode 100644 pkg/multicloud/aliyun/project.go delete mode 100644 pkg/multicloud/aliyun/provider/doc.go delete mode 100644 pkg/multicloud/aliyun/provider/provider.go delete mode 100644 pkg/multicloud/aliyun/quota.go delete mode 100644 pkg/multicloud/aliyun/ram_group.go delete mode 100644 pkg/multicloud/aliyun/ram_policy.go delete mode 100644 pkg/multicloud/aliyun/ram_role.go delete mode 100644 pkg/multicloud/aliyun/ram_user.go delete mode 100644 pkg/multicloud/aliyun/ramimage.go delete mode 100644 pkg/multicloud/aliyun/region.go delete mode 100644 pkg/multicloud/aliyun/resource_tags.go delete mode 100644 pkg/multicloud/aliyun/routetable.go delete mode 100644 pkg/multicloud/aliyun/saml_provider.go delete mode 100644 pkg/multicloud/aliyun/securitygroup.go delete mode 100644 pkg/multicloud/aliyun/shell/access_groups.go delete mode 100644 pkg/multicloud/aliyun/shell/bucket.go delete mode 100644 pkg/multicloud/aliyun/shell/business.go delete mode 100644 pkg/multicloud/aliyun/shell/cdn.go delete mode 100644 pkg/multicloud/aliyun/shell/cen_route.go delete mode 100644 pkg/multicloud/aliyun/shell/cloud_enterprise_network.go delete mode 100644 pkg/multicloud/aliyun/shell/dbinstance.go delete mode 100644 pkg/multicloud/aliyun/shell/dbinstance_account.go delete mode 100644 pkg/multicloud/aliyun/shell/dbinstance_backup.go delete mode 100644 pkg/multicloud/aliyun/shell/dbinstance_database.go delete mode 100644 pkg/multicloud/aliyun/shell/disk.go delete mode 100644 pkg/multicloud/aliyun/shell/dns_domain.go delete mode 100644 pkg/multicloud/aliyun/shell/doc.go delete mode 100644 pkg/multicloud/aliyun/shell/eip.go delete mode 100644 pkg/multicloud/aliyun/shell/elasticcache.go delete mode 100644 pkg/multicloud/aliyun/shell/elk.go delete mode 100644 pkg/multicloud/aliyun/shell/events.go delete mode 100644 pkg/multicloud/aliyun/shell/filesystem.go delete mode 100644 pkg/multicloud/aliyun/shell/image.go delete mode 100644 pkg/multicloud/aliyun/shell/instance.go delete mode 100644 pkg/multicloud/aliyun/shell/instancetype.go delete mode 100644 pkg/multicloud/aliyun/shell/kafka.go delete mode 100644 pkg/multicloud/aliyun/shell/keypair.go delete mode 100644 pkg/multicloud/aliyun/shell/kube_cluster.go delete mode 100644 pkg/multicloud/aliyun/shell/kube_node.go delete mode 100644 pkg/multicloud/aliyun/shell/kube_node_pools.go delete mode 100644 pkg/multicloud/aliyun/shell/loadbalancer.go delete mode 100644 pkg/multicloud/aliyun/shell/loadbalanceracl.go delete mode 100644 pkg/multicloud/aliyun/shell/loadbalancerbackend.go delete mode 100644 pkg/multicloud/aliyun/shell/loadbalancerbackendgroup.go delete mode 100644 pkg/multicloud/aliyun/shell/loadbalancercertificate.go delete mode 100644 pkg/multicloud/aliyun/shell/loadbalancerlistener.go delete mode 100644 pkg/multicloud/aliyun/shell/loadbalancerlistenerrule.go delete mode 100644 pkg/multicloud/aliyun/shell/mongodb.go delete mode 100644 pkg/multicloud/aliyun/shell/monitor.go delete mode 100644 pkg/multicloud/aliyun/shell/mount_target.go delete mode 100644 pkg/multicloud/aliyun/shell/natgateway.go delete mode 100644 pkg/multicloud/aliyun/shell/networkinterface.go delete mode 100644 pkg/multicloud/aliyun/shell/oss.go delete mode 100644 pkg/multicloud/aliyun/shell/printutils.go delete mode 100644 pkg/multicloud/aliyun/shell/private_zone.go delete mode 100644 pkg/multicloud/aliyun/shell/quota.go delete mode 100644 pkg/multicloud/aliyun/shell/ram_group.go delete mode 100644 pkg/multicloud/aliyun/shell/ram_policy.go delete mode 100644 pkg/multicloud/aliyun/shell/ram_role.go delete mode 100644 pkg/multicloud/aliyun/shell/ram_user.go delete mode 100644 pkg/multicloud/aliyun/shell/region.go delete mode 100644 pkg/multicloud/aliyun/shell/resource_tag.go delete mode 100644 pkg/multicloud/aliyun/shell/resourcegroup.go delete mode 100644 pkg/multicloud/aliyun/shell/routetable.go delete mode 100644 pkg/multicloud/aliyun/shell/saml_provider.go delete mode 100644 pkg/multicloud/aliyun/shell/secgroup.go delete mode 100644 pkg/multicloud/aliyun/shell/snapshot.go delete mode 100644 pkg/multicloud/aliyun/shell/snapshot_policy.go delete mode 100644 pkg/multicloud/aliyun/shell/tablestore.go delete mode 100644 pkg/multicloud/aliyun/shell/task.go delete mode 100644 pkg/multicloud/aliyun/shell/vpc.go delete mode 100644 pkg/multicloud/aliyun/shell/vrouter.go delete mode 100644 pkg/multicloud/aliyun/shell/vswitch.go delete mode 100644 pkg/multicloud/aliyun/shell/waf.go delete mode 100644 pkg/multicloud/aliyun/shell/zone.go delete mode 100644 pkg/multicloud/aliyun/snapshot.go delete mode 100644 pkg/multicloud/aliyun/snapshot_policy.go delete mode 100644 pkg/multicloud/aliyun/storage.go delete mode 100644 pkg/multicloud/aliyun/storagecache.go delete mode 100644 pkg/multicloud/aliyun/tablestore.go delete mode 100644 pkg/multicloud/aliyun/vpc.go delete mode 100644 pkg/multicloud/aliyun/vswitch.go delete mode 100644 pkg/multicloud/aliyun/waf.go delete mode 100644 pkg/multicloud/aliyun/wire.go delete mode 100644 pkg/multicloud/aliyun/zone.go delete mode 100644 pkg/multicloud/apsara/bucket.go delete mode 100644 pkg/multicloud/apsara/charge.go delete mode 100644 pkg/multicloud/apsara/dbinstance.go delete mode 100644 pkg/multicloud/apsara/dbinstance_account.go delete mode 100644 pkg/multicloud/apsara/dbinstance_backup.go delete mode 100644 pkg/multicloud/apsara/dbinstance_database.go delete mode 100644 pkg/multicloud/apsara/dbinstance_privilege.go delete mode 100644 pkg/multicloud/apsara/disk.go delete mode 100644 pkg/multicloud/apsara/doc.go delete mode 100644 pkg/multicloud/apsara/eip.go delete mode 100644 pkg/multicloud/apsara/elasticcache_account.go delete mode 100644 pkg/multicloud/apsara/elasticcache_acl.go delete mode 100644 pkg/multicloud/apsara/elasticcache_backup.go delete mode 100644 pkg/multicloud/apsara/elasticcache_instance.go delete mode 100644 pkg/multicloud/apsara/elasticcache_parameter.go delete mode 100644 pkg/multicloud/apsara/host.go delete mode 100644 pkg/multicloud/apsara/image.go delete mode 100644 pkg/multicloud/apsara/instance.go delete mode 100644 pkg/multicloud/apsara/instancenic.go delete mode 100644 pkg/multicloud/apsara/instancetype.go delete mode 100644 pkg/multicloud/apsara/ipv6_gateway.go delete mode 100644 pkg/multicloud/apsara/loadbalancer.go delete mode 100644 pkg/multicloud/apsara/loadbalanceracl.go delete mode 100644 pkg/multicloud/apsara/loadbalancerbackend.go delete mode 100644 pkg/multicloud/apsara/loadbalancerbackendgroup.go delete mode 100644 pkg/multicloud/apsara/loadbalancerdefaultbackend.go delete mode 100644 pkg/multicloud/apsara/loadbalancerdefaultbackendgroup.go delete mode 100644 pkg/multicloud/apsara/loadbalancerhttplistener.go delete mode 100644 pkg/multicloud/apsara/loadbalancerhttpslistener.go delete mode 100644 pkg/multicloud/apsara/loadbalancerlistenerrule.go delete mode 100644 pkg/multicloud/apsara/loadbalancermasterslavebackend.go delete mode 100644 pkg/multicloud/apsara/loadbalancermasterslavebackendgroup.go delete mode 100644 pkg/multicloud/apsara/loadbalancerservercertificate.go delete mode 100644 pkg/multicloud/apsara/loadbalancertcplistener.go delete mode 100644 pkg/multicloud/apsara/loadbalancerudplistener.go delete mode 100644 pkg/multicloud/apsara/monitor.go delete mode 100644 pkg/multicloud/apsara/natdtable.go delete mode 100644 pkg/multicloud/apsara/natgateway.go delete mode 100644 pkg/multicloud/apsara/natstable.go delete mode 100644 pkg/multicloud/apsara/networkinterfaces.go delete mode 100644 pkg/multicloud/apsara/objects.go delete mode 100644 pkg/multicloud/apsara/project.go delete mode 100644 pkg/multicloud/apsara/provider/doc.go delete mode 100644 pkg/multicloud/apsara/provider/provider.go delete mode 100644 pkg/multicloud/apsara/quota.go delete mode 100644 pkg/multicloud/apsara/ram_group.go delete mode 100644 pkg/multicloud/apsara/ram_policy.go delete mode 100644 pkg/multicloud/apsara/ram_user.go delete mode 100644 pkg/multicloud/apsara/ramimage.go delete mode 100644 pkg/multicloud/apsara/region.go delete mode 100644 pkg/multicloud/apsara/resource_tags.go delete mode 100644 pkg/multicloud/apsara/routetable.go delete mode 100644 pkg/multicloud/apsara/securitygroup.go delete mode 100644 pkg/multicloud/apsara/shell/bucket.go delete mode 100644 pkg/multicloud/apsara/shell/dbinstance.go delete mode 100644 pkg/multicloud/apsara/shell/dbinstance_account.go delete mode 100644 pkg/multicloud/apsara/shell/dbinstance_backup.go delete mode 100644 pkg/multicloud/apsara/shell/dbinstance_database.go delete mode 100644 pkg/multicloud/apsara/shell/disk.go delete mode 100644 pkg/multicloud/apsara/shell/doc.go delete mode 100644 pkg/multicloud/apsara/shell/eip.go delete mode 100644 pkg/multicloud/apsara/shell/elasticcache.go delete mode 100644 pkg/multicloud/apsara/shell/image.go delete mode 100644 pkg/multicloud/apsara/shell/instance.go delete mode 100644 pkg/multicloud/apsara/shell/instancetype.go delete mode 100644 pkg/multicloud/apsara/shell/ipv6_gateway.go delete mode 100644 pkg/multicloud/apsara/shell/keypair.go delete mode 100644 pkg/multicloud/apsara/shell/loadbalancer.go delete mode 100644 pkg/multicloud/apsara/shell/loadbalanceracl.go delete mode 100644 pkg/multicloud/apsara/shell/loadbalancerbackend.go delete mode 100644 pkg/multicloud/apsara/shell/loadbalancerbackendgroup.go delete mode 100644 pkg/multicloud/apsara/shell/loadbalancercertificate.go delete mode 100644 pkg/multicloud/apsara/shell/loadbalancerlistener.go delete mode 100644 pkg/multicloud/apsara/shell/loadbalancerlistenerrule.go delete mode 100644 pkg/multicloud/apsara/shell/monitor.go delete mode 100644 pkg/multicloud/apsara/shell/natgateway.go delete mode 100644 pkg/multicloud/apsara/shell/networkinterface.go delete mode 100644 pkg/multicloud/apsara/shell/printutils.go delete mode 100644 pkg/multicloud/apsara/shell/quota.go delete mode 100644 pkg/multicloud/apsara/shell/ram_group.go delete mode 100644 pkg/multicloud/apsara/shell/ram_policy.go delete mode 100644 pkg/multicloud/apsara/shell/ram_role.go delete mode 100644 pkg/multicloud/apsara/shell/ram_user.go delete mode 100644 pkg/multicloud/apsara/shell/region.go delete mode 100644 pkg/multicloud/apsara/shell/resource_tag.go delete mode 100644 pkg/multicloud/apsara/shell/resourcegroup.go delete mode 100644 pkg/multicloud/apsara/shell/routetable.go delete mode 100644 pkg/multicloud/apsara/shell/secgroup.go delete mode 100644 pkg/multicloud/apsara/shell/snapshot.go delete mode 100644 pkg/multicloud/apsara/shell/snapshot_policy.go delete mode 100644 pkg/multicloud/apsara/shell/task.go delete mode 100644 pkg/multicloud/apsara/shell/vpc.go delete mode 100644 pkg/multicloud/apsara/shell/vrouter.go delete mode 100644 pkg/multicloud/apsara/shell/vswitch.go delete mode 100644 pkg/multicloud/apsara/shell/zone.go delete mode 100644 pkg/multicloud/apsara/snapshot.go delete mode 100644 pkg/multicloud/apsara/snapshot_policy.go delete mode 100644 pkg/multicloud/apsara/storage.go delete mode 100644 pkg/multicloud/apsara/storagecache.go delete mode 100644 pkg/multicloud/apsara/vpc.go delete mode 100644 pkg/multicloud/apsara/vswitch.go delete mode 100644 pkg/multicloud/apsara/wire.go delete mode 100644 pkg/multicloud/apsara/zone.go delete mode 100644 pkg/multicloud/aws/aws_test.go delete mode 100644 pkg/multicloud/aws/bucket.go delete mode 100644 pkg/multicloud/aws/cloudtrail.go delete mode 100644 pkg/multicloud/aws/dbinstance.go delete mode 100644 pkg/multicloud/aws/dbinstance_account.go delete mode 100644 pkg/multicloud/aws/dbinstance_database.go delete mode 100644 pkg/multicloud/aws/dbinstance_snapshot.go delete mode 100644 pkg/multicloud/aws/disk.go delete mode 100644 pkg/multicloud/aws/doc.go delete mode 100644 pkg/multicloud/aws/eip.go delete mode 100644 pkg/multicloud/aws/host.go delete mode 100644 pkg/multicloud/aws/iam_group.go delete mode 100644 pkg/multicloud/aws/iam_policy.go delete mode 100644 pkg/multicloud/aws/iam_role.go delete mode 100644 pkg/multicloud/aws/iam_user.go delete mode 100644 pkg/multicloud/aws/image.go delete mode 100644 pkg/multicloud/aws/imageowners_test.go delete mode 100644 pkg/multicloud/aws/instance.go delete mode 100644 pkg/multicloud/aws/instancenic.go delete mode 100644 pkg/multicloud/aws/keypair.go delete mode 100644 pkg/multicloud/aws/keypair_test.go delete mode 100644 pkg/multicloud/aws/latitude_and_longitude.go delete mode 100644 pkg/multicloud/aws/loadbalancer.go delete mode 100644 pkg/multicloud/aws/loadbalancerbackend.go delete mode 100644 pkg/multicloud/aws/loadbalancerbackendgroup.go delete mode 100644 pkg/multicloud/aws/loadbalancercert.go delete mode 100644 pkg/multicloud/aws/loadbalancerlistener.go delete mode 100644 pkg/multicloud/aws/loadbalancerlistenerrule.go delete mode 100644 pkg/multicloud/aws/monitor.go delete mode 100644 pkg/multicloud/aws/natgateway.go delete mode 100644 pkg/multicloud/aws/network.go delete mode 100644 pkg/multicloud/aws/networkinterface.go delete mode 100644 pkg/multicloud/aws/organizations.go delete mode 100644 pkg/multicloud/aws/provider/doc.go delete mode 100644 pkg/multicloud/aws/provider/provider.go delete mode 100644 pkg/multicloud/aws/region.go delete mode 100644 pkg/multicloud/aws/resource_tag.go delete mode 100644 pkg/multicloud/aws/routetable.go delete mode 100644 pkg/multicloud/aws/s3object.go delete mode 100644 pkg/multicloud/aws/saml_provider.go delete mode 100644 pkg/multicloud/aws/securitygroup.go delete mode 100644 pkg/multicloud/aws/shell/bucket.go delete mode 100644 pkg/multicloud/aws/shell/cloudtrail.go delete mode 100644 pkg/multicloud/aws/shell/dbinstance.go delete mode 100644 pkg/multicloud/aws/shell/dbinstance_parameter.go delete mode 100644 pkg/multicloud/aws/shell/dbinstance_snapshot.go delete mode 100644 pkg/multicloud/aws/shell/disk.go delete mode 100644 pkg/multicloud/aws/shell/doc.go delete mode 100644 pkg/multicloud/aws/shell/eip.go delete mode 100644 pkg/multicloud/aws/shell/elasticache.go delete mode 100644 pkg/multicloud/aws/shell/hostedzone.go delete mode 100644 pkg/multicloud/aws/shell/iam_group.go delete mode 100644 pkg/multicloud/aws/shell/iam_policy.go delete mode 100644 pkg/multicloud/aws/shell/iam_role.go delete mode 100644 pkg/multicloud/aws/shell/iam_user.go delete mode 100644 pkg/multicloud/aws/shell/image.go delete mode 100644 pkg/multicloud/aws/shell/instance.go delete mode 100644 pkg/multicloud/aws/shell/instancetype.go delete mode 100644 pkg/multicloud/aws/shell/keypair.go delete mode 100644 pkg/multicloud/aws/shell/monitor.go delete mode 100644 pkg/multicloud/aws/shell/natgateway.go delete mode 100644 pkg/multicloud/aws/shell/network.go delete mode 100644 pkg/multicloud/aws/shell/networkinterface.go delete mode 100644 pkg/multicloud/aws/shell/organizations.go delete mode 100644 pkg/multicloud/aws/shell/printutils.go delete mode 100644 pkg/multicloud/aws/shell/region.go delete mode 100644 pkg/multicloud/aws/shell/reservedinstance.go delete mode 100644 pkg/multicloud/aws/shell/resource_tag.go delete mode 100644 pkg/multicloud/aws/shell/routetable.go delete mode 100644 pkg/multicloud/aws/shell/s3.go delete mode 100644 pkg/multicloud/aws/shell/saml_provider.go delete mode 100644 pkg/multicloud/aws/shell/secgroup.go delete mode 100644 pkg/multicloud/aws/shell/snapshot.go delete mode 100644 pkg/multicloud/aws/shell/sts.go delete mode 100644 pkg/multicloud/aws/shell/vpc.go delete mode 100644 pkg/multicloud/aws/shell/waf.go delete mode 100644 pkg/multicloud/aws/shell/zone.go delete mode 100644 pkg/multicloud/aws/snapshot.go delete mode 100644 pkg/multicloud/aws/storage.go delete mode 100644 pkg/multicloud/aws/storagecache.go delete mode 100644 pkg/multicloud/aws/utils.go delete mode 100644 pkg/multicloud/aws/vpc.go delete mode 100644 pkg/multicloud/aws/vpc_peering_connection.go delete mode 100644 pkg/multicloud/aws/waf.go delete mode 100644 pkg/multicloud/aws/wire.go delete mode 100644 pkg/multicloud/aws/zone.go delete mode 100644 pkg/multicloud/azure/app_gateways.go delete mode 100644 pkg/multicloud/azure/app_service_plan.go delete mode 100644 pkg/multicloud/azure/cloudgroup.go delete mode 100644 pkg/multicloud/azure/cloudpolicy.go delete mode 100644 pkg/multicloud/azure/clouduser.go delete mode 100644 pkg/multicloud/azure/concurrent/doc.go delete mode 100644 pkg/multicloud/azure/dbinstance.go delete mode 100644 pkg/multicloud/azure/dbinstance_account.go delete mode 100644 pkg/multicloud/azure/dbinstance_database.go delete mode 100644 pkg/multicloud/azure/disk.go delete mode 100644 pkg/multicloud/azure/doc.go delete mode 100644 pkg/multicloud/azure/eip.go delete mode 100644 pkg/multicloud/azure/enrollment_account.go delete mode 100644 pkg/multicloud/azure/event.go delete mode 100644 pkg/multicloud/azure/host.go delete mode 100644 pkg/multicloud/azure/image.go delete mode 100644 pkg/multicloud/azure/instance.go delete mode 100644 pkg/multicloud/azure/instancenic.go delete mode 100644 pkg/multicloud/azure/kube_cluster.go delete mode 100644 pkg/multicloud/azure/kube_node_pools.go delete mode 100644 pkg/multicloud/azure/loadbalancer.go delete mode 100644 pkg/multicloud/azure/loadbalancerbackend.go delete mode 100644 pkg/multicloud/azure/loadbalancerbackendgroup.go delete mode 100644 pkg/multicloud/azure/loadbalancercert.go delete mode 100644 pkg/multicloud/azure/loadbalancerlistener.go delete mode 100644 pkg/multicloud/azure/loadbalancerlistenerrule.go delete mode 100644 pkg/multicloud/azure/monitor.go delete mode 100644 pkg/multicloud/azure/network.go delete mode 100644 pkg/multicloud/azure/progress/doc.go delete mode 100644 pkg/multicloud/azure/provider/doc.go delete mode 100644 pkg/multicloud/azure/provider/provider.go delete mode 100644 pkg/multicloud/azure/rds_sqlserver.go delete mode 100644 pkg/multicloud/azure/redis.go delete mode 100644 pkg/multicloud/azure/region.go delete mode 100644 pkg/multicloud/azure/resourcegroup.go delete mode 100644 pkg/multicloud/azure/saml_provider.go delete mode 100644 pkg/multicloud/azure/securitygroup.go delete mode 100644 pkg/multicloud/azure/service.go delete mode 100644 pkg/multicloud/azure/shell/account.go delete mode 100644 pkg/multicloud/azure/shell/app_gateways.go delete mode 100644 pkg/multicloud/azure/shell/app_service_plan.go delete mode 100644 pkg/multicloud/azure/shell/bucket.go delete mode 100644 pkg/multicloud/azure/shell/cloudgroup.go delete mode 100644 pkg/multicloud/azure/shell/cloudpolicy.go delete mode 100644 pkg/multicloud/azure/shell/clouduser.go delete mode 100644 pkg/multicloud/azure/shell/dbinstance.go delete mode 100644 pkg/multicloud/azure/shell/dbinstance_databases.go delete mode 100644 pkg/multicloud/azure/shell/dbinstance_networkRules.go delete mode 100644 pkg/multicloud/azure/shell/dbinstance_paraments.go delete mode 100644 pkg/multicloud/azure/shell/disk.go delete mode 100644 pkg/multicloud/azure/shell/doc.go delete mode 100644 pkg/multicloud/azure/shell/eip.go delete mode 100644 pkg/multicloud/azure/shell/enrollment_account.go delete mode 100644 pkg/multicloud/azure/shell/event.go delete mode 100644 pkg/multicloud/azure/shell/image.go delete mode 100644 pkg/multicloud/azure/shell/instance.go delete mode 100644 pkg/multicloud/azure/shell/kube_cluster.go delete mode 100644 pkg/multicloud/azure/shell/loadbalancer.go delete mode 100644 pkg/multicloud/azure/shell/loganalytics.go delete mode 100644 pkg/multicloud/azure/shell/monitor.go delete mode 100644 pkg/multicloud/azure/shell/network.go delete mode 100644 pkg/multicloud/azure/shell/policy.go delete mode 100644 pkg/multicloud/azure/shell/printutils.go delete mode 100644 pkg/multicloud/azure/shell/redis.go delete mode 100644 pkg/multicloud/azure/shell/region.go delete mode 100644 pkg/multicloud/azure/shell/resourcegroup.go delete mode 100644 pkg/multicloud/azure/shell/saml_provider.go delete mode 100644 pkg/multicloud/azure/shell/secgroup.go delete mode 100644 pkg/multicloud/azure/shell/service.go delete mode 100644 pkg/multicloud/azure/shell/snapshot.go delete mode 100644 pkg/multicloud/azure/shell/storageaccount.go delete mode 100644 pkg/multicloud/azure/shell/subscription.go delete mode 100644 pkg/multicloud/azure/shell/usage.go delete mode 100644 pkg/multicloud/azure/shell/vpc.go delete mode 100644 pkg/multicloud/azure/shell/waf.go delete mode 100644 pkg/multicloud/azure/shell/web_app.go delete mode 100644 pkg/multicloud/azure/snapshot.go delete mode 100644 pkg/multicloud/azure/storage.go delete mode 100644 pkg/multicloud/azure/storageaccount.go delete mode 100644 pkg/multicloud/azure/storagecache.go delete mode 100644 pkg/multicloud/azure/subscription.go delete mode 100644 pkg/multicloud/azure/usage.go delete mode 100644 pkg/multicloud/azure/vpc.go delete mode 100644 pkg/multicloud/azure/waf.go delete mode 100644 pkg/multicloud/azure/web_app.go delete mode 100644 pkg/multicloud/azure/wire.go delete mode 100644 pkg/multicloud/azure/zone.go delete mode 100644 pkg/multicloud/bingocloud/cluster.go delete mode 100644 pkg/multicloud/bingocloud/disk.go delete mode 100644 pkg/multicloud/bingocloud/doc.go delete mode 100644 pkg/multicloud/bingocloud/eip.go delete mode 100644 pkg/multicloud/bingocloud/image.go delete mode 100644 pkg/multicloud/bingocloud/instance.go delete mode 100644 pkg/multicloud/bingocloud/instancenic.go delete mode 100644 pkg/multicloud/bingocloud/monitor.go delete mode 100644 pkg/multicloud/bingocloud/network.go delete mode 100644 pkg/multicloud/bingocloud/node.go delete mode 100644 pkg/multicloud/bingocloud/provider/doc.go delete mode 100644 pkg/multicloud/bingocloud/provider/provider.go delete mode 100644 pkg/multicloud/bingocloud/region.go delete mode 100644 pkg/multicloud/bingocloud/secgroup.go delete mode 100644 pkg/multicloud/bingocloud/shell/cluster.go delete mode 100644 pkg/multicloud/bingocloud/shell/disk.go delete mode 100644 pkg/multicloud/bingocloud/shell/doc.go delete mode 100644 pkg/multicloud/bingocloud/shell/eip.go delete mode 100644 pkg/multicloud/bingocloud/shell/host.go delete mode 100644 pkg/multicloud/bingocloud/shell/image.go delete mode 100644 pkg/multicloud/bingocloud/shell/instance.go delete mode 100644 pkg/multicloud/bingocloud/shell/monitor.go delete mode 100644 pkg/multicloud/bingocloud/shell/network.go delete mode 100644 pkg/multicloud/bingocloud/shell/node.go delete mode 100644 pkg/multicloud/bingocloud/shell/printutils.go delete mode 100644 pkg/multicloud/bingocloud/shell/region.go delete mode 100644 pkg/multicloud/bingocloud/shell/secgroup.go delete mode 100644 pkg/multicloud/bingocloud/shell/storage.go delete mode 100644 pkg/multicloud/bingocloud/shell/vpc.go delete mode 100644 pkg/multicloud/bingocloud/shell/zone.go delete mode 100644 pkg/multicloud/bingocloud/storage.go delete mode 100644 pkg/multicloud/bingocloud/storagecache.go delete mode 100644 pkg/multicloud/bingocloud/vpc.go delete mode 100644 pkg/multicloud/bingocloud/wire.go delete mode 100644 pkg/multicloud/cloudpods/disk.go delete mode 100644 pkg/multicloud/cloudpods/doc.go delete mode 100644 pkg/multicloud/cloudpods/eip.go delete mode 100644 pkg/multicloud/cloudpods/host.go delete mode 100644 pkg/multicloud/cloudpods/image.go delete mode 100644 pkg/multicloud/cloudpods/instance.go delete mode 100644 pkg/multicloud/cloudpods/instancenic.go delete mode 100644 pkg/multicloud/cloudpods/network.go delete mode 100644 pkg/multicloud/cloudpods/project.go delete mode 100644 pkg/multicloud/cloudpods/provider/doc.go delete mode 100644 pkg/multicloud/cloudpods/provider/provider.go delete mode 100644 pkg/multicloud/cloudpods/region.go delete mode 100644 pkg/multicloud/cloudpods/secgroup.go delete mode 100644 pkg/multicloud/cloudpods/shell/disk.go delete mode 100644 pkg/multicloud/cloudpods/shell/doc.go delete mode 100644 pkg/multicloud/cloudpods/shell/hosts.go delete mode 100644 pkg/multicloud/cloudpods/shell/image.go delete mode 100644 pkg/multicloud/cloudpods/shell/instance.go delete mode 100644 pkg/multicloud/cloudpods/shell/network.go delete mode 100644 pkg/multicloud/cloudpods/shell/printutils.go delete mode 100644 pkg/multicloud/cloudpods/shell/region.go delete mode 100644 pkg/multicloud/cloudpods/shell/secgroup.go delete mode 100644 pkg/multicloud/cloudpods/shell/vpc.go delete mode 100644 pkg/multicloud/cloudpods/shell/wire.go delete mode 100644 pkg/multicloud/cloudpods/shell/zones.go delete mode 100644 pkg/multicloud/cloudpods/sku.go delete mode 100644 pkg/multicloud/cloudpods/snapshot.go delete mode 100644 pkg/multicloud/cloudpods/storage.go delete mode 100644 pkg/multicloud/cloudpods/storagecache.go delete mode 100644 pkg/multicloud/cloudpods/vpc.go delete mode 100644 pkg/multicloud/cloudpods/wire.go delete mode 100644 pkg/multicloud/cloudpods/zone.go delete mode 100644 pkg/multicloud/clouduser.go delete mode 100644 pkg/multicloud/ctyun/disk.go delete mode 100644 pkg/multicloud/ctyun/doc.go delete mode 100644 pkg/multicloud/ctyun/eip.go delete mode 100644 pkg/multicloud/ctyun/host.go delete mode 100644 pkg/multicloud/ctyun/image.go delete mode 100644 pkg/multicloud/ctyun/instance.go delete mode 100644 pkg/multicloud/ctyun/instancenic.go delete mode 100644 pkg/multicloud/ctyun/latitud_and_longitude.go delete mode 100644 pkg/multicloud/ctyun/network.go delete mode 100644 pkg/multicloud/ctyun/project.go delete mode 100644 pkg/multicloud/ctyun/provider/doc.go delete mode 100644 pkg/multicloud/ctyun/provider/provider.go delete mode 100644 pkg/multicloud/ctyun/region.go delete mode 100644 pkg/multicloud/ctyun/securitygroup.go delete mode 100644 pkg/multicloud/ctyun/shell/crm.go delete mode 100644 pkg/multicloud/ctyun/shell/disk.go delete mode 100644 pkg/multicloud/ctyun/shell/diskbackuppolicy.go delete mode 100644 pkg/multicloud/ctyun/shell/doc.go delete mode 100644 pkg/multicloud/ctyun/shell/eip.go delete mode 100644 pkg/multicloud/ctyun/shell/image.go delete mode 100644 pkg/multicloud/ctyun/shell/instance.go delete mode 100644 pkg/multicloud/ctyun/shell/job.go delete mode 100644 pkg/multicloud/ctyun/shell/network.go delete mode 100644 pkg/multicloud/ctyun/shell/printutils.go delete mode 100644 pkg/multicloud/ctyun/shell/project.go delete mode 100644 pkg/multicloud/ctyun/shell/region.go delete mode 100644 pkg/multicloud/ctyun/shell/secgroup.go delete mode 100644 pkg/multicloud/ctyun/shell/vpc.go delete mode 100644 pkg/multicloud/ctyun/storage.go delete mode 100644 pkg/multicloud/ctyun/storagecache.go delete mode 100644 pkg/multicloud/ctyun/vpc.go delete mode 100644 pkg/multicloud/ctyun/wire.go delete mode 100644 pkg/multicloud/ctyun/zone.go delete mode 100644 pkg/multicloud/doc.go delete mode 100644 pkg/multicloud/ecloud/client.go delete mode 100644 pkg/multicloud/ecloud/client_test.go delete mode 100644 pkg/multicloud/ecloud/disk.go delete mode 100644 pkg/multicloud/ecloud/doc.go delete mode 100644 pkg/multicloud/ecloud/eip.go delete mode 100644 pkg/multicloud/ecloud/host.go delete mode 100644 pkg/multicloud/ecloud/image.go delete mode 100644 pkg/multicloud/ecloud/instance.go delete mode 100644 pkg/multicloud/ecloud/instancenic.go delete mode 100644 pkg/multicloud/ecloud/latitud_and_longitude.go delete mode 100644 pkg/multicloud/ecloud/monitor.go delete mode 100644 pkg/multicloud/ecloud/network.go delete mode 100644 pkg/multicloud/ecloud/provider/doc.go delete mode 100644 pkg/multicloud/ecloud/provider/provider.go delete mode 100644 pkg/multicloud/ecloud/region.go delete mode 100644 pkg/multicloud/ecloud/shell/disk.go delete mode 100644 pkg/multicloud/ecloud/shell/doc.go delete mode 100644 pkg/multicloud/ecloud/shell/image.go delete mode 100644 pkg/multicloud/ecloud/shell/instance.go delete mode 100644 pkg/multicloud/ecloud/shell/monitor.go delete mode 100644 pkg/multicloud/ecloud/shell/network.go delete mode 100644 pkg/multicloud/ecloud/shell/printutils.go delete mode 100644 pkg/multicloud/ecloud/shell/region.go delete mode 100644 pkg/multicloud/ecloud/shell/vpc.go delete mode 100644 pkg/multicloud/ecloud/snapshot.go delete mode 100644 pkg/multicloud/ecloud/storage.go delete mode 100644 pkg/multicloud/ecloud/storagecache.go delete mode 100644 pkg/multicloud/ecloud/vpc.go delete mode 100644 pkg/multicloud/ecloud/wire.go delete mode 100644 pkg/multicloud/ecloud/zone.go delete mode 100644 pkg/multicloud/esxi/cluster.go delete mode 100644 pkg/multicloud/esxi/datacenter.go delete mode 100644 pkg/multicloud/esxi/doc.go delete mode 100644 pkg/multicloud/esxi/host.go delete mode 100644 pkg/multicloud/esxi/host_test.go delete mode 100644 pkg/multicloud/esxi/image.go delete mode 100644 pkg/multicloud/esxi/manager.go delete mode 100644 pkg/multicloud/esxi/manager_test.go delete mode 100644 pkg/multicloud/esxi/mobase_test.go delete mode 100644 pkg/multicloud/esxi/monitor.go delete mode 100644 pkg/multicloud/esxi/provider/doc.go delete mode 100644 pkg/multicloud/esxi/provider/provider.go delete mode 100644 pkg/multicloud/esxi/resourcepool.go delete mode 100644 pkg/multicloud/esxi/shell/cluster.go delete mode 100644 pkg/multicloud/esxi/shell/datacenter.go delete mode 100644 pkg/multicloud/esxi/shell/doc.go delete mode 100644 pkg/multicloud/esxi/shell/host.go delete mode 100644 pkg/multicloud/esxi/shell/ip.go delete mode 100644 pkg/multicloud/esxi/shell/monitor.go delete mode 100644 pkg/multicloud/esxi/shell/network.go delete mode 100644 pkg/multicloud/esxi/shell/resourcepool.go delete mode 100644 pkg/multicloud/esxi/shell/store.go delete mode 100644 pkg/multicloud/esxi/shell/utils.go delete mode 100644 pkg/multicloud/esxi/shell/virtualmachine.go delete mode 100644 pkg/multicloud/esxi/snapshot.go delete mode 100644 pkg/multicloud/esxi/storage.go delete mode 100644 pkg/multicloud/esxi/storagecache.go delete mode 100644 pkg/multicloud/esxi/utils_test.go delete mode 100644 pkg/multicloud/esxi/vcenter/doc.go delete mode 100644 pkg/multicloud/esxi/virtualmachine.go delete mode 100644 pkg/multicloud/google/bucket.go delete mode 100644 pkg/multicloud/google/dbinstance.go delete mode 100644 pkg/multicloud/google/dbinstance_account.go delete mode 100644 pkg/multicloud/google/dbinstance_backup.go delete mode 100644 pkg/multicloud/google/dbinstance_database.go delete mode 100644 pkg/multicloud/google/disk.go delete mode 100644 pkg/multicloud/google/doc.go delete mode 100644 pkg/multicloud/google/eip.go delete mode 100644 pkg/multicloud/google/globalnetwork.go delete mode 100644 pkg/multicloud/google/host.go delete mode 100644 pkg/multicloud/google/image.go delete mode 100644 pkg/multicloud/google/instance.go delete mode 100644 pkg/multicloud/google/instancenic.go delete mode 100644 pkg/multicloud/google/latitude_and_longitude.go delete mode 100644 pkg/multicloud/google/loadbalancer.go delete mode 100644 pkg/multicloud/google/loadbalancer_backend.go delete mode 100644 pkg/multicloud/google/loadbalancer_backendgroup.go delete mode 100644 pkg/multicloud/google/loadbalancer_cert.go delete mode 100644 pkg/multicloud/google/loadbalancer_listener.go delete mode 100644 pkg/multicloud/google/loadbalancer_listenerrule.go delete mode 100644 pkg/multicloud/google/machinetype.go delete mode 100644 pkg/multicloud/google/monitor.go delete mode 100644 pkg/multicloud/google/network.go delete mode 100644 pkg/multicloud/google/project.go delete mode 100644 pkg/multicloud/google/provider/doc.go delete mode 100644 pkg/multicloud/google/provider/provider.go delete mode 100644 pkg/multicloud/google/quota.go delete mode 100644 pkg/multicloud/google/region.go delete mode 100644 pkg/multicloud/google/resourcepolicy.go delete mode 100644 pkg/multicloud/google/s3object.go delete mode 100644 pkg/multicloud/google/securitygroup.go delete mode 100644 pkg/multicloud/google/shell/bigquery.go delete mode 100644 pkg/multicloud/google/shell/bucket.go delete mode 100644 pkg/multicloud/google/shell/cloudbuild.go delete mode 100644 pkg/multicloud/google/shell/dbinstance.go delete mode 100644 pkg/multicloud/google/shell/dbinstance_account.go delete mode 100644 pkg/multicloud/google/shell/dbinstance_backup.go delete mode 100644 pkg/multicloud/google/shell/dbinstance_database.go delete mode 100644 pkg/multicloud/google/shell/disk.go delete mode 100644 pkg/multicloud/google/shell/doc.go delete mode 100644 pkg/multicloud/google/shell/eip.go delete mode 100644 pkg/multicloud/google/shell/firewall.go delete mode 100644 pkg/multicloud/google/shell/globalnetwork.go delete mode 100644 pkg/multicloud/google/shell/iam.go delete mode 100644 pkg/multicloud/google/shell/image.go delete mode 100644 pkg/multicloud/google/shell/instance.go delete mode 100644 pkg/multicloud/google/shell/loadbalancer.go delete mode 100644 pkg/multicloud/google/shell/machinetype.go delete mode 100644 pkg/multicloud/google/shell/monitor.go delete mode 100644 pkg/multicloud/google/shell/network.go delete mode 100644 pkg/multicloud/google/shell/object.go delete mode 100644 pkg/multicloud/google/shell/printutils.go delete mode 100644 pkg/multicloud/google/shell/project.go delete mode 100644 pkg/multicloud/google/shell/region.go delete mode 100644 pkg/multicloud/google/shell/resourcepolicy.go delete mode 100644 pkg/multicloud/google/shell/skubilling.go delete mode 100644 pkg/multicloud/google/shell/snapshot.go delete mode 100644 pkg/multicloud/google/shell/storage.go delete mode 100644 pkg/multicloud/google/shell/zone.go delete mode 100644 pkg/multicloud/google/sku.go delete mode 100644 pkg/multicloud/google/snapshot.go delete mode 100644 pkg/multicloud/google/storage.go delete mode 100644 pkg/multicloud/google/storagecache.go delete mode 100644 pkg/multicloud/google/vpc.go delete mode 100644 pkg/multicloud/google/wire.go delete mode 100644 pkg/multicloud/google/zone.go delete mode 100644 pkg/multicloud/hcs/bucket.go delete mode 100644 pkg/multicloud/hcs/dbinstance.go delete mode 100644 pkg/multicloud/hcs/dbinstance_account.go delete mode 100644 pkg/multicloud/hcs/dbinstance_backup.go delete mode 100644 pkg/multicloud/hcs/dbinstance_database.go delete mode 100644 pkg/multicloud/hcs/dbinstance_privilege.go delete mode 100644 pkg/multicloud/hcs/dbinstance_skus.go delete mode 100644 pkg/multicloud/hcs/disk.go delete mode 100644 pkg/multicloud/hcs/doc.go delete mode 100644 pkg/multicloud/hcs/eip.go delete mode 100644 pkg/multicloud/hcs/host.go delete mode 100644 pkg/multicloud/hcs/image.go delete mode 100644 pkg/multicloud/hcs/instance.go delete mode 100644 pkg/multicloud/hcs/instancenic.go delete mode 100644 pkg/multicloud/hcs/instancetype.go delete mode 100644 pkg/multicloud/hcs/job.go delete mode 100644 pkg/multicloud/hcs/loadbalancer.go delete mode 100644 pkg/multicloud/hcs/loadbalancer_acl.go delete mode 100644 pkg/multicloud/hcs/loadbalancer_backend.go delete mode 100644 pkg/multicloud/hcs/loadbalancer_backendgroup.go delete mode 100644 pkg/multicloud/hcs/loadbalancer_cert.go delete mode 100644 pkg/multicloud/hcs/loadbalancer_listener.go delete mode 100644 pkg/multicloud/hcs/loadbalancer_listener_rule.go delete mode 100644 pkg/multicloud/hcs/monitor.go delete mode 100644 pkg/multicloud/hcs/natdtable.go delete mode 100644 pkg/multicloud/hcs/natgateway.go delete mode 100644 pkg/multicloud/hcs/natstable.go delete mode 100644 pkg/multicloud/hcs/network.go delete mode 100644 pkg/multicloud/hcs/object.go delete mode 100644 pkg/multicloud/hcs/port.go delete mode 100644 pkg/multicloud/hcs/project.go delete mode 100644 pkg/multicloud/hcs/provider/doc.go delete mode 100644 pkg/multicloud/hcs/provider/provider.go delete mode 100644 pkg/multicloud/hcs/redis.go delete mode 100644 pkg/multicloud/hcs/region.go delete mode 100644 pkg/multicloud/hcs/routetables.go delete mode 100644 pkg/multicloud/hcs/securitygroup.go delete mode 100644 pkg/multicloud/hcs/shell/bucket.go delete mode 100644 pkg/multicloud/hcs/shell/dbinstance.go delete mode 100644 pkg/multicloud/hcs/shell/dbinstance_account.go delete mode 100644 pkg/multicloud/hcs/shell/dbinstance_database.go delete mode 100644 pkg/multicloud/hcs/shell/dbinstance_skus.go delete mode 100644 pkg/multicloud/hcs/shell/disk.go delete mode 100644 pkg/multicloud/hcs/shell/doc.go delete mode 100644 pkg/multicloud/hcs/shell/eip.go delete mode 100644 pkg/multicloud/hcs/shell/image.go delete mode 100644 pkg/multicloud/hcs/shell/instance.go delete mode 100644 pkg/multicloud/hcs/shell/instancetype.go delete mode 100644 pkg/multicloud/hcs/shell/job.go delete mode 100644 pkg/multicloud/hcs/shell/keypair.go delete mode 100644 pkg/multicloud/hcs/shell/lb.go delete mode 100644 pkg/multicloud/hcs/shell/monitor.go delete mode 100644 pkg/multicloud/hcs/shell/natgateway.go delete mode 100644 pkg/multicloud/hcs/shell/network.go delete mode 100644 pkg/multicloud/hcs/shell/port.go delete mode 100644 pkg/multicloud/hcs/shell/printutils.go delete mode 100644 pkg/multicloud/hcs/shell/project.go delete mode 100644 pkg/multicloud/hcs/shell/redis.go delete mode 100644 pkg/multicloud/hcs/shell/region.go delete mode 100644 pkg/multicloud/hcs/shell/securitygroup.go delete mode 100644 pkg/multicloud/hcs/shell/snapshot.go delete mode 100644 pkg/multicloud/hcs/shell/vpc.go delete mode 100644 pkg/multicloud/hcs/shell/vpc_peer.go delete mode 100644 pkg/multicloud/hcs/shell/zone.go delete mode 100644 pkg/multicloud/hcs/snapshot.go delete mode 100644 pkg/multicloud/hcs/storage.go delete mode 100644 pkg/multicloud/hcs/storagecache.go delete mode 100644 pkg/multicloud/hcs/vpc.go delete mode 100644 pkg/multicloud/hcs/vpc_peering.go delete mode 100644 pkg/multicloud/hcs/wire.go delete mode 100644 pkg/multicloud/hcs/zone.go delete mode 100644 pkg/multicloud/hcso/bucket.go delete mode 100644 pkg/multicloud/hcso/client/auth/credentials/doc.go delete mode 100644 pkg/multicloud/hcso/client/auth/doc.go delete mode 100644 pkg/multicloud/hcso/client/auth/signer.go delete mode 100644 pkg/multicloud/hcso/client/auth/signers/doc.go delete mode 100644 pkg/multicloud/hcso/client/auth/signers/signer_access_key.go delete mode 100644 pkg/multicloud/hcso/client/client.go delete mode 100644 pkg/multicloud/hcso/client/doc.go delete mode 100644 pkg/multicloud/hcso/client/manager/doc.go delete mode 100644 pkg/multicloud/hcso/client/manager/manager.go delete mode 100644 pkg/multicloud/hcso/client/modules/doc.go delete mode 100644 pkg/multicloud/hcso/client/modules/manager_base.go delete mode 100644 pkg/multicloud/hcso/client/modules/manager_resource.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_ces.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_credential.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_dbinstance.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_dbinstance_backup.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_dbinstance_flavor.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_dbinstance_job.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_disks.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_dnat_rules.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_domains.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_elasticcache.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_enterpriceprojects.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_flavors.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_groups.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_images.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_interface.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_jobs.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_keypairs.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_mapping.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_natgateway.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_port.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_projects.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_quotas.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_regions.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_roles.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_saml_provider.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_secgroup_rules.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_secgroups.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_servers.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_sfs.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_snapshots.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_snat_rules.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_subnets.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_traces.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_users.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_vpc_peerings.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_vpc_routes.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_vpcs.go delete mode 100644 pkg/multicloud/hcso/client/modules/mod_zones.go delete mode 100644 pkg/multicloud/hcso/client/requests/doc.go delete mode 100644 pkg/multicloud/hcso/client/responses/doc.go delete mode 100644 pkg/multicloud/hcso/client/responses/responses_test.go delete mode 100644 pkg/multicloud/hcso/cloudgroup.go delete mode 100644 pkg/multicloud/hcso/clouduser.go delete mode 100644 pkg/multicloud/hcso/dbinstance.go delete mode 100644 pkg/multicloud/hcso/dbinstance_account.go delete mode 100644 pkg/multicloud/hcso/dbinstance_backup.go delete mode 100644 pkg/multicloud/hcso/dbinstance_database.go delete mode 100644 pkg/multicloud/hcso/dbinstance_privilege.go delete mode 100644 pkg/multicloud/hcso/dbinstance_skus.go delete mode 100644 pkg/multicloud/hcso/disk.go delete mode 100644 pkg/multicloud/hcso/doc.go delete mode 100644 pkg/multicloud/hcso/eip.go delete mode 100644 pkg/multicloud/hcso/elasticcache_account.go delete mode 100644 pkg/multicloud/hcso/elasticcache_backup.go delete mode 100644 pkg/multicloud/hcso/elasticcache_instance.go delete mode 100644 pkg/multicloud/hcso/elasticcache_parameter.go delete mode 100644 pkg/multicloud/hcso/enterpriceprojects.go delete mode 100644 pkg/multicloud/hcso/host.go delete mode 100644 pkg/multicloud/hcso/huawei.go delete mode 100644 pkg/multicloud/hcso/image.go delete mode 100644 pkg/multicloud/hcso/instance.go delete mode 100644 pkg/multicloud/hcso/instancenic.go delete mode 100644 pkg/multicloud/hcso/instancetype.go delete mode 100644 pkg/multicloud/hcso/latitud_and_longitude.go delete mode 100644 pkg/multicloud/hcso/loadbalancer.go delete mode 100644 pkg/multicloud/hcso/loadbalancer_acl.go delete mode 100644 pkg/multicloud/hcso/loadbalancer_backend.go delete mode 100644 pkg/multicloud/hcso/loadbalancer_backendgroup.go delete mode 100644 pkg/multicloud/hcso/loadbalancer_cert.go delete mode 100644 pkg/multicloud/hcso/loadbalancer_listener.go delete mode 100644 pkg/multicloud/hcso/loadbalancer_listener_rule.go delete mode 100644 pkg/multicloud/hcso/modelarts.go delete mode 100644 pkg/multicloud/hcso/modelarts_sku.go delete mode 100644 pkg/multicloud/hcso/monitor.go delete mode 100644 pkg/multicloud/hcso/nat_skus.go delete mode 100644 pkg/multicloud/hcso/natdtable.go delete mode 100644 pkg/multicloud/hcso/natgateway.go delete mode 100644 pkg/multicloud/hcso/natstable.go delete mode 100644 pkg/multicloud/hcso/network.go delete mode 100644 pkg/multicloud/hcso/object.go delete mode 100644 pkg/multicloud/hcso/port.go delete mode 100644 pkg/multicloud/hcso/project.go delete mode 100644 pkg/multicloud/hcso/provider/doc.go delete mode 100644 pkg/multicloud/hcso/provider/provider.go delete mode 100644 pkg/multicloud/hcso/quota.go delete mode 100644 pkg/multicloud/hcso/region.go delete mode 100644 pkg/multicloud/hcso/roles.go delete mode 100644 pkg/multicloud/hcso/routetable.go delete mode 100644 pkg/multicloud/hcso/saml_provider.go delete mode 100644 pkg/multicloud/hcso/securitygroup.go delete mode 100644 pkg/multicloud/hcso/sfs-turbo.go delete mode 100644 pkg/multicloud/hcso/shell/bucket.go delete mode 100644 pkg/multicloud/hcso/shell/cloudgroup.go delete mode 100644 pkg/multicloud/hcso/shell/clouduser.go delete mode 100644 pkg/multicloud/hcso/shell/dbinstance.go delete mode 100644 pkg/multicloud/hcso/shell/dbinstance_account.go delete mode 100644 pkg/multicloud/hcso/shell/dbinstance_database.go delete mode 100644 pkg/multicloud/hcso/shell/dbinstance_skus.go delete mode 100644 pkg/multicloud/hcso/shell/disk.go delete mode 100644 pkg/multicloud/hcso/shell/doc.go delete mode 100644 pkg/multicloud/hcso/shell/eip.go delete mode 100644 pkg/multicloud/hcso/shell/elasticcache.go delete mode 100644 pkg/multicloud/hcso/shell/endpoints.go delete mode 100644 pkg/multicloud/hcso/shell/enterpriseprojects.go delete mode 100644 pkg/multicloud/hcso/shell/events.go delete mode 100644 pkg/multicloud/hcso/shell/filesystem.go delete mode 100644 pkg/multicloud/hcso/shell/hosts.go delete mode 100644 pkg/multicloud/hcso/shell/iam.go delete mode 100644 pkg/multicloud/hcso/shell/image.go delete mode 100644 pkg/multicloud/hcso/shell/instance.go delete mode 100644 pkg/multicloud/hcso/shell/instancetype.go delete mode 100644 pkg/multicloud/hcso/shell/keypair.go delete mode 100644 pkg/multicloud/hcso/shell/loadbalancer.go delete mode 100644 pkg/multicloud/hcso/shell/modelarts.go delete mode 100644 pkg/multicloud/hcso/shell/modelarts_sku.go delete mode 100644 pkg/multicloud/hcso/shell/monitor.go delete mode 100644 pkg/multicloud/hcso/shell/natdtable.go delete mode 100644 pkg/multicloud/hcso/shell/natgateway.go delete mode 100644 pkg/multicloud/hcso/shell/natstable.go delete mode 100644 pkg/multicloud/hcso/shell/network.go delete mode 100644 pkg/multicloud/hcso/shell/obs.go delete mode 100644 pkg/multicloud/hcso/shell/port.go delete mode 100644 pkg/multicloud/hcso/shell/printutils.go delete mode 100644 pkg/multicloud/hcso/shell/quota.go delete mode 100644 pkg/multicloud/hcso/shell/region.go delete mode 100644 pkg/multicloud/hcso/shell/role.go delete mode 100644 pkg/multicloud/hcso/shell/routetable.go delete mode 100644 pkg/multicloud/hcso/shell/saml_provider.go delete mode 100644 pkg/multicloud/hcso/shell/secgroup.go delete mode 100644 pkg/multicloud/hcso/shell/service.go delete mode 100644 pkg/multicloud/hcso/shell/skus.go delete mode 100644 pkg/multicloud/hcso/shell/snapshot.go delete mode 100644 pkg/multicloud/hcso/shell/vpc.go delete mode 100644 pkg/multicloud/hcso/shell/zone.go delete mode 100644 pkg/multicloud/hcso/snapshot.go delete mode 100644 pkg/multicloud/hcso/storage.go delete mode 100644 pkg/multicloud/hcso/storagecache.go delete mode 100644 pkg/multicloud/hcso/traces.go delete mode 100644 pkg/multicloud/hcso/utils.go delete mode 100644 pkg/multicloud/hcso/vpc.go delete mode 100644 pkg/multicloud/hcso/vpc_peering.go delete mode 100644 pkg/multicloud/hcso/wire.go delete mode 100644 pkg/multicloud/hcso/zone.go delete mode 100644 pkg/multicloud/huawei/bucket.go delete mode 100644 pkg/multicloud/huawei/client/auth/credentials/doc.go delete mode 100644 pkg/multicloud/huawei/client/auth/doc.go delete mode 100644 pkg/multicloud/huawei/client/auth/signer.go delete mode 100644 pkg/multicloud/huawei/client/auth/signers/doc.go delete mode 100644 pkg/multicloud/huawei/client/auth/signers/signer_access_key.go delete mode 100644 pkg/multicloud/huawei/client/client.go delete mode 100644 pkg/multicloud/huawei/client/doc.go delete mode 100644 pkg/multicloud/huawei/client/manager/doc.go delete mode 100644 pkg/multicloud/huawei/client/manager/manager.go delete mode 100644 pkg/multicloud/huawei/client/modules/doc.go delete mode 100644 pkg/multicloud/huawei/client/modules/manager_base.go delete mode 100644 pkg/multicloud/huawei/client/modules/manager_resource.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_ces.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_credential.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_dbinstance.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_disks.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_dnat_rules.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_domains.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_elasticcache.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_flavors.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_groups.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_images.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_interface.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_jobs.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_keypairs.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_mapping.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_natgateway.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_port.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_projects.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_quotas.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_regions.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_roles.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_saml_provider.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_secgroup_rules.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_secgroups.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_servers.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_sfs.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_snapshots.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_snat_rules.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_subnets.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_traces.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_users.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_vpc_routes.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_vpcs.go delete mode 100644 pkg/multicloud/huawei/client/modules/mod_zones.go delete mode 100644 pkg/multicloud/huawei/client/requests/doc.go delete mode 100644 pkg/multicloud/huawei/client/responses/doc.go delete mode 100644 pkg/multicloud/huawei/client/responses/responses_test.go delete mode 100644 pkg/multicloud/huawei/cloudgroup.go delete mode 100644 pkg/multicloud/huawei/clouduser.go delete mode 100644 pkg/multicloud/huawei/dbinstance.go delete mode 100644 pkg/multicloud/huawei/dbinstance_account.go delete mode 100644 pkg/multicloud/huawei/dbinstance_backup.go delete mode 100644 pkg/multicloud/huawei/dbinstance_database.go delete mode 100644 pkg/multicloud/huawei/dbinstance_privilege.go delete mode 100644 pkg/multicloud/huawei/disk.go delete mode 100644 pkg/multicloud/huawei/doc.go delete mode 100644 pkg/multicloud/huawei/eip.go delete mode 100644 pkg/multicloud/huawei/elasticcache_account.go delete mode 100644 pkg/multicloud/huawei/elasticcache_backup.go delete mode 100644 pkg/multicloud/huawei/elasticcache_instance.go delete mode 100644 pkg/multicloud/huawei/elasticcache_parameter.go delete mode 100644 pkg/multicloud/huawei/enterpriceprojects.go delete mode 100644 pkg/multicloud/huawei/host.go delete mode 100644 pkg/multicloud/huawei/huawei.go delete mode 100644 pkg/multicloud/huawei/image.go delete mode 100644 pkg/multicloud/huawei/instance.go delete mode 100644 pkg/multicloud/huawei/instancenic.go delete mode 100644 pkg/multicloud/huawei/latitud_and_longitude.go delete mode 100644 pkg/multicloud/huawei/loadbalancer.go delete mode 100644 pkg/multicloud/huawei/loadbalancer_acl.go delete mode 100644 pkg/multicloud/huawei/loadbalancer_backend.go delete mode 100644 pkg/multicloud/huawei/loadbalancer_backendgroup.go delete mode 100644 pkg/multicloud/huawei/loadbalancer_cert.go delete mode 100644 pkg/multicloud/huawei/loadbalancer_listener.go delete mode 100644 pkg/multicloud/huawei/loadbalancer_listener_rule.go delete mode 100644 pkg/multicloud/huawei/modelarts_pool.go delete mode 100644 pkg/multicloud/huawei/modelarts_pool_sku.go delete mode 100644 pkg/multicloud/huawei/monitor.go delete mode 100644 pkg/multicloud/huawei/natdtable.go delete mode 100644 pkg/multicloud/huawei/natgateway.go delete mode 100644 pkg/multicloud/huawei/natstable.go delete mode 100644 pkg/multicloud/huawei/network.go delete mode 100644 pkg/multicloud/huawei/object.go delete mode 100644 pkg/multicloud/huawei/obs/doc.go delete mode 100644 pkg/multicloud/huawei/order.go delete mode 100644 pkg/multicloud/huawei/port.go delete mode 100644 pkg/multicloud/huawei/project.go delete mode 100644 pkg/multicloud/huawei/provider/doc.go delete mode 100644 pkg/multicloud/huawei/provider/provider.go delete mode 100644 pkg/multicloud/huawei/quota.go delete mode 100644 pkg/multicloud/huawei/region.go delete mode 100644 pkg/multicloud/huawei/roles.go delete mode 100644 pkg/multicloud/huawei/routetables.go delete mode 100644 pkg/multicloud/huawei/saml_provider.go delete mode 100644 pkg/multicloud/huawei/securitygroup.go delete mode 100644 pkg/multicloud/huawei/sfs-turbo.go delete mode 100644 pkg/multicloud/huawei/shell/bucket.go delete mode 100644 pkg/multicloud/huawei/shell/business.go delete mode 100644 pkg/multicloud/huawei/shell/cloudgroup.go delete mode 100644 pkg/multicloud/huawei/shell/clouduser.go delete mode 100644 pkg/multicloud/huawei/shell/dbinstance.go delete mode 100644 pkg/multicloud/huawei/shell/dbinstance_account.go delete mode 100644 pkg/multicloud/huawei/shell/dbinstance_database.go delete mode 100644 pkg/multicloud/huawei/shell/disk.go delete mode 100644 pkg/multicloud/huawei/shell/doc.go delete mode 100644 pkg/multicloud/huawei/shell/eip.go delete mode 100644 pkg/multicloud/huawei/shell/elasticcache.go delete mode 100644 pkg/multicloud/huawei/shell/enterpriseprojects.go delete mode 100644 pkg/multicloud/huawei/shell/events.go delete mode 100644 pkg/multicloud/huawei/shell/filesystem.go delete mode 100644 pkg/multicloud/huawei/shell/iam.go delete mode 100644 pkg/multicloud/huawei/shell/image.go delete mode 100644 pkg/multicloud/huawei/shell/instance.go delete mode 100644 pkg/multicloud/huawei/shell/instancetype.go delete mode 100644 pkg/multicloud/huawei/shell/keypair.go delete mode 100644 pkg/multicloud/huawei/shell/loadbalancer.go delete mode 100644 pkg/multicloud/huawei/shell/modelarts_pool.go delete mode 100644 pkg/multicloud/huawei/shell/modelarts_pool_sku.go delete mode 100644 pkg/multicloud/huawei/shell/monitor.go delete mode 100644 pkg/multicloud/huawei/shell/natdtable.go delete mode 100644 pkg/multicloud/huawei/shell/natgateway.go delete mode 100644 pkg/multicloud/huawei/shell/natstable.go delete mode 100644 pkg/multicloud/huawei/shell/network.go delete mode 100644 pkg/multicloud/huawei/shell/obs.go delete mode 100644 pkg/multicloud/huawei/shell/order.go delete mode 100644 pkg/multicloud/huawei/shell/port.go delete mode 100644 pkg/multicloud/huawei/shell/printutils.go delete mode 100644 pkg/multicloud/huawei/shell/quota.go delete mode 100644 pkg/multicloud/huawei/shell/region.go delete mode 100644 pkg/multicloud/huawei/shell/role.go delete mode 100644 pkg/multicloud/huawei/shell/routetable.go delete mode 100644 pkg/multicloud/huawei/shell/saml_provider.go delete mode 100644 pkg/multicloud/huawei/shell/secgroup.go delete mode 100644 pkg/multicloud/huawei/shell/snapshot.go delete mode 100644 pkg/multicloud/huawei/shell/vpc.go delete mode 100644 pkg/multicloud/huawei/shell/zone.go delete mode 100644 pkg/multicloud/huawei/snapshot.go delete mode 100644 pkg/multicloud/huawei/storage.go delete mode 100644 pkg/multicloud/huawei/storagecache.go delete mode 100644 pkg/multicloud/huawei/traces.go delete mode 100644 pkg/multicloud/huawei/utils.go delete mode 100644 pkg/multicloud/huawei/vpc.go delete mode 100644 pkg/multicloud/huawei/vpc_peering.go delete mode 100644 pkg/multicloud/huawei/wire.go delete mode 100644 pkg/multicloud/huawei/zone.go delete mode 100644 pkg/multicloud/incloudsphere/disk.go delete mode 100644 pkg/multicloud/incloudsphere/doc.go delete mode 100644 pkg/multicloud/incloudsphere/host.go delete mode 100644 pkg/multicloud/incloudsphere/image.go delete mode 100644 pkg/multicloud/incloudsphere/instance.go delete mode 100644 pkg/multicloud/incloudsphere/network.go delete mode 100644 pkg/multicloud/incloudsphere/nic.go delete mode 100644 pkg/multicloud/incloudsphere/provider/doc.go delete mode 100644 pkg/multicloud/incloudsphere/provider/provider.go delete mode 100644 pkg/multicloud/incloudsphere/region.go delete mode 100644 pkg/multicloud/incloudsphere/shell/disk.go delete mode 100644 pkg/multicloud/incloudsphere/shell/doc.go delete mode 100644 pkg/multicloud/incloudsphere/shell/host.go delete mode 100644 pkg/multicloud/incloudsphere/shell/image.go delete mode 100644 pkg/multicloud/incloudsphere/shell/instance.go delete mode 100644 pkg/multicloud/incloudsphere/shell/network.go delete mode 100644 pkg/multicloud/incloudsphere/shell/printutils.go delete mode 100644 pkg/multicloud/incloudsphere/shell/region.go delete mode 100644 pkg/multicloud/incloudsphere/shell/storage.go delete mode 100644 pkg/multicloud/incloudsphere/shell/version.go delete mode 100644 pkg/multicloud/incloudsphere/shell/wire.go delete mode 100644 pkg/multicloud/incloudsphere/shell/zone.go delete mode 100644 pkg/multicloud/incloudsphere/storage.go delete mode 100644 pkg/multicloud/incloudsphere/storagecache.go delete mode 100644 pkg/multicloud/incloudsphere/task.go delete mode 100644 pkg/multicloud/incloudsphere/vpc.go delete mode 100644 pkg/multicloud/incloudsphere/wire.go delete mode 100644 pkg/multicloud/incloudsphere/zone.go delete mode 100644 pkg/multicloud/jdcloud/disk.go delete mode 100644 pkg/multicloud/jdcloud/doc.go delete mode 100644 pkg/multicloud/jdcloud/eip.go delete mode 100644 pkg/multicloud/jdcloud/host.go delete mode 100644 pkg/multicloud/jdcloud/image.go delete mode 100644 pkg/multicloud/jdcloud/instance.go delete mode 100644 pkg/multicloud/jdcloud/instancenic.go delete mode 100644 pkg/multicloud/jdcloud/latitud_and_longitude.go delete mode 100644 pkg/multicloud/jdcloud/monitor.go delete mode 100644 pkg/multicloud/jdcloud/network.go delete mode 100644 pkg/multicloud/jdcloud/networkinterface.go delete mode 100644 pkg/multicloud/jdcloud/provider/doc.go delete mode 100644 pkg/multicloud/jdcloud/provider/provider.go delete mode 100644 pkg/multicloud/jdcloud/rds.go delete mode 100644 pkg/multicloud/jdcloud/region.go delete mode 100644 pkg/multicloud/jdcloud/securitygroup.go delete mode 100644 pkg/multicloud/jdcloud/shell/balance.go delete mode 100644 pkg/multicloud/jdcloud/shell/doc.go delete mode 100644 pkg/multicloud/jdcloud/shell/image.go delete mode 100644 pkg/multicloud/jdcloud/shell/instance.go delete mode 100644 pkg/multicloud/jdcloud/shell/monitor.go delete mode 100644 pkg/multicloud/jdcloud/shell/network.go delete mode 100644 pkg/multicloud/jdcloud/shell/rds.go delete mode 100644 pkg/multicloud/jdcloud/shell/utils.go delete mode 100644 pkg/multicloud/jdcloud/shell/vpc.go delete mode 100644 pkg/multicloud/jdcloud/shell/zone.go delete mode 100644 pkg/multicloud/jdcloud/snapshot.go delete mode 100644 pkg/multicloud/jdcloud/storage.go delete mode 100644 pkg/multicloud/jdcloud/storagecache.go delete mode 100644 pkg/multicloud/jdcloud/utils.go delete mode 100644 pkg/multicloud/jdcloud/vpc.go delete mode 100644 pkg/multicloud/jdcloud/wire.go delete mode 100644 pkg/multicloud/jdcloud/zone.go delete mode 100644 pkg/multicloud/loader/doc.go delete mode 100644 pkg/multicloud/loader/loader.go delete mode 100644 pkg/multicloud/loader/proxyfunc_test.go delete mode 100644 pkg/multicloud/nutanix/disk.go delete mode 100644 pkg/multicloud/nutanix/doc.go delete mode 100644 pkg/multicloud/nutanix/host.go delete mode 100644 pkg/multicloud/nutanix/image.go delete mode 100644 pkg/multicloud/nutanix/instance.go delete mode 100644 pkg/multicloud/nutanix/instancenic.go delete mode 100644 pkg/multicloud/nutanix/network.go delete mode 100644 pkg/multicloud/nutanix/provider/doc.go delete mode 100644 pkg/multicloud/nutanix/provider/provider.go delete mode 100644 pkg/multicloud/nutanix/region.go delete mode 100644 pkg/multicloud/nutanix/shell/cluster.go delete mode 100644 pkg/multicloud/nutanix/shell/disk.go delete mode 100644 pkg/multicloud/nutanix/shell/doc.go delete mode 100644 pkg/multicloud/nutanix/shell/host.go delete mode 100644 pkg/multicloud/nutanix/shell/image.go delete mode 100644 pkg/multicloud/nutanix/shell/instance.go delete mode 100644 pkg/multicloud/nutanix/shell/printutils.go delete mode 100644 pkg/multicloud/nutanix/shell/storage.go delete mode 100644 pkg/multicloud/nutanix/shell/task.go delete mode 100644 pkg/multicloud/nutanix/shell/vpc.go delete mode 100644 pkg/multicloud/nutanix/storage.go delete mode 100644 pkg/multicloud/nutanix/storagecache.go delete mode 100644 pkg/multicloud/nutanix/vpc.go delete mode 100644 pkg/multicloud/nutanix/wire.go delete mode 100644 pkg/multicloud/nutanix/zone.go delete mode 100644 pkg/multicloud/objectstore/ceph/bucket.go delete mode 100644 pkg/multicloud/objectstore/ceph/doc.go delete mode 100644 pkg/multicloud/objectstore/ceph/provider/doc.go delete mode 100644 pkg/multicloud/objectstore/ceph/provider/provider.go delete mode 100644 pkg/multicloud/objectstore/doc.go delete mode 100644 pkg/multicloud/objectstore/object.go delete mode 100644 pkg/multicloud/objectstore/provider/doc.go delete mode 100644 pkg/multicloud/objectstore/provider/provider.go delete mode 100644 pkg/multicloud/objectstore/shell/bucket.go delete mode 100644 pkg/multicloud/objectstore/shell/doc.go delete mode 100644 pkg/multicloud/objectstore/shell/minio.go delete mode 100644 pkg/multicloud/objectstore/shell/printutils.go delete mode 100644 pkg/multicloud/objectstore/xsky/bucket.go delete mode 100644 pkg/multicloud/objectstore/xsky/doc.go delete mode 100644 pkg/multicloud/objectstore/xsky/provider/doc.go delete mode 100644 pkg/multicloud/objectstore/xsky/provider/provider.go delete mode 100644 pkg/multicloud/openstack/disk.go delete mode 100644 pkg/multicloud/openstack/doc.go delete mode 100644 pkg/multicloud/openstack/eip.go delete mode 100644 pkg/multicloud/openstack/flavor.go delete mode 100644 pkg/multicloud/openstack/image.go delete mode 100644 pkg/multicloud/openstack/instance.go delete mode 100644 pkg/multicloud/openstack/instancenic.go delete mode 100644 pkg/multicloud/openstack/loadbalanceracl.go delete mode 100644 pkg/multicloud/openstack/loadbalancerlistener.go delete mode 100644 pkg/multicloud/openstack/network.go delete mode 100644 pkg/multicloud/openstack/port.go delete mode 100644 pkg/multicloud/openstack/project.go delete mode 100644 pkg/multicloud/openstack/provider/doc.go delete mode 100644 pkg/multicloud/openstack/provider/provider.go delete mode 100644 pkg/multicloud/openstack/quota.go delete mode 100644 pkg/multicloud/openstack/region.go delete mode 100644 pkg/multicloud/openstack/roles.go delete mode 100644 pkg/multicloud/openstack/routetable.go delete mode 100644 pkg/multicloud/openstack/securitygroup.go delete mode 100644 pkg/multicloud/openstack/shell/disk.go delete mode 100644 pkg/multicloud/openstack/shell/doc.go delete mode 100644 pkg/multicloud/openstack/shell/eip.go delete mode 100644 pkg/multicloud/openstack/shell/flavor.go delete mode 100644 pkg/multicloud/openstack/shell/host.go delete mode 100644 pkg/multicloud/openstack/shell/image.go delete mode 100644 pkg/multicloud/openstack/shell/instance.go delete mode 100644 pkg/multicloud/openstack/shell/keypair.go delete mode 100644 pkg/multicloud/openstack/shell/loadbalancer.go delete mode 100644 pkg/multicloud/openstack/shell/messages.go delete mode 100644 pkg/multicloud/openstack/shell/network.go delete mode 100644 pkg/multicloud/openstack/shell/port.go delete mode 100644 pkg/multicloud/openstack/shell/printutils.go delete mode 100644 pkg/multicloud/openstack/shell/project.go delete mode 100644 pkg/multicloud/openstack/shell/quota.go delete mode 100644 pkg/multicloud/openstack/shell/region.go delete mode 100644 pkg/multicloud/openstack/shell/role.go delete mode 100644 pkg/multicloud/openstack/shell/router.go delete mode 100644 pkg/multicloud/openstack/shell/securitygroup.go delete mode 100644 pkg/multicloud/openstack/shell/snapshot.go delete mode 100644 pkg/multicloud/openstack/shell/storage.go delete mode 100644 pkg/multicloud/openstack/shell/vpc.go delete mode 100644 pkg/multicloud/openstack/shell/zone.go delete mode 100644 pkg/multicloud/openstack/snapshot.go delete mode 100644 pkg/multicloud/openstack/storage.go delete mode 100644 pkg/multicloud/openstack/storagecache.go delete mode 100644 pkg/multicloud/openstack/vpc.go delete mode 100644 pkg/multicloud/openstack/wire.go delete mode 100644 pkg/multicloud/openstack/zone.go delete mode 100644 pkg/multicloud/proxmox/disk.go delete mode 100644 pkg/multicloud/proxmox/doc.go delete mode 100644 pkg/multicloud/proxmox/host.go delete mode 100644 pkg/multicloud/proxmox/image.go delete mode 100644 pkg/multicloud/proxmox/instance.go delete mode 100644 pkg/multicloud/proxmox/network.go delete mode 100644 pkg/multicloud/proxmox/nic.go delete mode 100644 pkg/multicloud/proxmox/provider/doc.go delete mode 100644 pkg/multicloud/proxmox/provider/provider.go delete mode 100644 pkg/multicloud/proxmox/region.go delete mode 100644 pkg/multicloud/proxmox/shell/cluster.go delete mode 100644 pkg/multicloud/proxmox/shell/disk.go delete mode 100644 pkg/multicloud/proxmox/shell/doc.go delete mode 100644 pkg/multicloud/proxmox/shell/hosts.go delete mode 100644 pkg/multicloud/proxmox/shell/image.go delete mode 100644 pkg/multicloud/proxmox/shell/instance.go delete mode 100644 pkg/multicloud/proxmox/shell/network.go delete mode 100644 pkg/multicloud/proxmox/shell/printutils.go delete mode 100644 pkg/multicloud/proxmox/shell/region.go delete mode 100644 pkg/multicloud/proxmox/shell/storage.go delete mode 100644 pkg/multicloud/proxmox/shell/zone.go delete mode 100644 pkg/multicloud/proxmox/storage.go delete mode 100644 pkg/multicloud/proxmox/storagecache.go delete mode 100644 pkg/multicloud/proxmox/task.go delete mode 100644 pkg/multicloud/proxmox/vpc.go delete mode 100644 pkg/multicloud/proxmox/wire.go delete mode 100644 pkg/multicloud/proxmox/zone.go delete mode 100644 pkg/multicloud/qcloud/bucket.go delete mode 100644 pkg/multicloud/qcloud/cam_group.go delete mode 100644 pkg/multicloud/qcloud/cam_policy.go delete mode 100644 pkg/multicloud/qcloud/cam_role.go delete mode 100644 pkg/multicloud/qcloud/cam_user.go delete mode 100644 pkg/multicloud/qcloud/cdn.go delete mode 100644 pkg/multicloud/qcloud/cloud_connect_network.go delete mode 100644 pkg/multicloud/qcloud/dbinstance.go delete mode 100644 pkg/multicloud/qcloud/disk.go delete mode 100644 pkg/multicloud/qcloud/doc.go delete mode 100644 pkg/multicloud/qcloud/eip.go delete mode 100644 pkg/multicloud/qcloud/elastic_search.go delete mode 100644 pkg/multicloud/qcloud/elasticcache_account.go delete mode 100644 pkg/multicloud/qcloud/elasticcache_backup.go delete mode 100644 pkg/multicloud/qcloud/elasticcache_instance.go delete mode 100644 pkg/multicloud/qcloud/events.go delete mode 100644 pkg/multicloud/qcloud/host.go delete mode 100644 pkg/multicloud/qcloud/image.go delete mode 100644 pkg/multicloud/qcloud/instance.go delete mode 100644 pkg/multicloud/qcloud/instancenic.go delete mode 100644 pkg/multicloud/qcloud/kafka.go delete mode 100644 pkg/multicloud/qcloud/keypair.go delete mode 100644 pkg/multicloud/qcloud/kube_node_pools.go delete mode 100644 pkg/multicloud/qcloud/kube_nodes.go delete mode 100644 pkg/multicloud/qcloud/latitud_and_longitude.go delete mode 100644 pkg/multicloud/qcloud/loadbalancer.go delete mode 100644 pkg/multicloud/qcloud/loadbalancer_acl.go delete mode 100644 pkg/multicloud/qcloud/loadbalancer_backend.go delete mode 100644 pkg/multicloud/qcloud/loadbalancer_backendgroup.go delete mode 100644 pkg/multicloud/qcloud/loadbalancer_listener.go delete mode 100644 pkg/multicloud/qcloud/loadbalancer_listenerrule.go delete mode 100644 pkg/multicloud/qcloud/memcached.go delete mode 100644 pkg/multicloud/qcloud/mongodb.go delete mode 100644 pkg/multicloud/qcloud/monitor.go delete mode 100644 pkg/multicloud/qcloud/natdtable.go delete mode 100644 pkg/multicloud/qcloud/natgateway.go delete mode 100644 pkg/multicloud/qcloud/network.go delete mode 100644 pkg/multicloud/qcloud/networkinterface.go delete mode 100644 pkg/multicloud/qcloud/object.go delete mode 100644 pkg/multicloud/qcloud/project.go delete mode 100644 pkg/multicloud/qcloud/provider/doc.go delete mode 100644 pkg/multicloud/qcloud/provider/provider.go delete mode 100644 pkg/multicloud/qcloud/quota.go delete mode 100644 pkg/multicloud/qcloud/rds_mysql.go delete mode 100644 pkg/multicloud/qcloud/region.go delete mode 100644 pkg/multicloud/qcloud/route_table.go delete mode 100644 pkg/multicloud/qcloud/saml_provider.go delete mode 100644 pkg/multicloud/qcloud/securitygroup.go delete mode 100644 pkg/multicloud/qcloud/shell/balance.go delete mode 100644 pkg/multicloud/qcloud/shell/bandwidthpackage.go delete mode 100644 pkg/multicloud/qcloud/shell/cam_group.go delete mode 100644 pkg/multicloud/qcloud/shell/cam_policy.go delete mode 100644 pkg/multicloud/qcloud/shell/cam_role.go delete mode 100644 pkg/multicloud/qcloud/shell/cam_user.go delete mode 100644 pkg/multicloud/qcloud/shell/ccn_route.go delete mode 100644 pkg/multicloud/qcloud/shell/cdn.go delete mode 100644 pkg/multicloud/qcloud/shell/cloud_connect_network.go delete mode 100644 pkg/multicloud/qcloud/shell/cos.go delete mode 100644 pkg/multicloud/qcloud/shell/disk.go delete mode 100644 pkg/multicloud/qcloud/shell/dnspod.go delete mode 100644 pkg/multicloud/qcloud/shell/doc.go delete mode 100644 pkg/multicloud/qcloud/shell/eip.go delete mode 100644 pkg/multicloud/qcloud/shell/elasticcache.go delete mode 100644 pkg/multicloud/qcloud/shell/elasticsearch.go delete mode 100644 pkg/multicloud/qcloud/shell/events.go delete mode 100644 pkg/multicloud/qcloud/shell/image.go delete mode 100644 pkg/multicloud/qcloud/shell/instance.go delete mode 100644 pkg/multicloud/qcloud/shell/kafka.go delete mode 100644 pkg/multicloud/qcloud/shell/keypair.go delete mode 100644 pkg/multicloud/qcloud/shell/kube_cluster.go delete mode 100644 pkg/multicloud/qcloud/shell/kube_node_pools.go delete mode 100644 pkg/multicloud/qcloud/shell/kube_nodes.go delete mode 100644 pkg/multicloud/qcloud/shell/loadbalancer.go delete mode 100644 pkg/multicloud/qcloud/shell/memcached.go delete mode 100644 pkg/multicloud/qcloud/shell/mongodb.go delete mode 100644 pkg/multicloud/qcloud/shell/monitor.go delete mode 100644 pkg/multicloud/qcloud/shell/natdtable.go delete mode 100644 pkg/multicloud/qcloud/shell/natgateway.go delete mode 100644 pkg/multicloud/qcloud/shell/network.go delete mode 100644 pkg/multicloud/qcloud/shell/networkinterface.go delete mode 100644 pkg/multicloud/qcloud/shell/printutils.go delete mode 100644 pkg/multicloud/qcloud/shell/project.go delete mode 100644 pkg/multicloud/qcloud/shell/quota.go delete mode 100644 pkg/multicloud/qcloud/shell/rds_mariadb.go delete mode 100644 pkg/multicloud/qcloud/shell/rds_mysql.go delete mode 100644 pkg/multicloud/qcloud/shell/rds_postgre.go delete mode 100644 pkg/multicloud/qcloud/shell/rds_sqlserver.go delete mode 100644 pkg/multicloud/qcloud/shell/region.go delete mode 100644 pkg/multicloud/qcloud/shell/route_table.go delete mode 100644 pkg/multicloud/qcloud/shell/saml_provider.go delete mode 100644 pkg/multicloud/qcloud/shell/securitygroup.go delete mode 100644 pkg/multicloud/qcloud/shell/snapshot.go delete mode 100644 pkg/multicloud/qcloud/shell/snapshot_policy.go delete mode 100644 pkg/multicloud/qcloud/shell/storage.go delete mode 100644 pkg/multicloud/qcloud/shell/sts.go delete mode 100644 pkg/multicloud/qcloud/shell/tags.go delete mode 100644 pkg/multicloud/qcloud/shell/tdsql.go delete mode 100644 pkg/multicloud/qcloud/shell/vpc.go delete mode 100644 pkg/multicloud/qcloud/shell/zone.go delete mode 100644 pkg/multicloud/qcloud/snapshot.go delete mode 100644 pkg/multicloud/qcloud/snapshot_policy.go delete mode 100644 pkg/multicloud/qcloud/storage.go delete mode 100644 pkg/multicloud/qcloud/storagecache.go delete mode 100644 pkg/multicloud/qcloud/vpc.go delete mode 100644 pkg/multicloud/qcloud/vpc_peering_connection.go delete mode 100644 pkg/multicloud/qcloud/wire.go delete mode 100644 pkg/multicloud/qcloud/zone.go delete mode 100644 pkg/multicloud/remotefile/bucket.go delete mode 100644 pkg/multicloud/remotefile/dbinstance.go delete mode 100644 pkg/multicloud/remotefile/disk.go delete mode 100644 pkg/multicloud/remotefile/doc.go delete mode 100644 pkg/multicloud/remotefile/eip.go delete mode 100644 pkg/multicloud/remotefile/host.go delete mode 100644 pkg/multicloud/remotefile/instance.go delete mode 100644 pkg/multicloud/remotefile/instancenic.go delete mode 100644 pkg/multicloud/remotefile/loadbalancer.go delete mode 100644 pkg/multicloud/remotefile/monitor.go delete mode 100644 pkg/multicloud/remotefile/network.go delete mode 100644 pkg/multicloud/remotefile/provider/doc.go delete mode 100644 pkg/multicloud/remotefile/provider/provider.go delete mode 100644 pkg/multicloud/remotefile/region.go delete mode 100644 pkg/multicloud/remotefile/securitygroup.go delete mode 100644 pkg/multicloud/remotefile/storage.go delete mode 100644 pkg/multicloud/remotefile/vpc.go delete mode 100644 pkg/multicloud/remotefile/wire.go delete mode 100644 pkg/multicloud/remotefile/zone.go delete mode 100644 pkg/multicloud/tag_base.go delete mode 100644 pkg/multicloud/test/doc.go delete mode 100644 pkg/multicloud/test/readonly.go delete mode 100644 pkg/multicloud/ucloud/client.go delete mode 100644 pkg/multicloud/ucloud/client_test.go delete mode 100644 pkg/multicloud/ucloud/disk.go delete mode 100644 pkg/multicloud/ucloud/doc.go delete mode 100644 pkg/multicloud/ucloud/eip.go delete mode 100644 pkg/multicloud/ucloud/host.go delete mode 100644 pkg/multicloud/ucloud/image.go delete mode 100644 pkg/multicloud/ucloud/instance.go delete mode 100644 pkg/multicloud/ucloud/instancenic.go delete mode 100644 pkg/multicloud/ucloud/latitud_and_longitude.go delete mode 100644 pkg/multicloud/ucloud/network.go delete mode 100644 pkg/multicloud/ucloud/project.go delete mode 100644 pkg/multicloud/ucloud/provider/doc.go delete mode 100644 pkg/multicloud/ucloud/provider/provider.go delete mode 100644 pkg/multicloud/ucloud/region.go delete mode 100644 pkg/multicloud/ucloud/securitygroup.go delete mode 100644 pkg/multicloud/ucloud/shell/disk.go delete mode 100644 pkg/multicloud/ucloud/shell/doc.go delete mode 100644 pkg/multicloud/ucloud/shell/eip.go delete mode 100644 pkg/multicloud/ucloud/shell/image.go delete mode 100644 pkg/multicloud/ucloud/shell/instance.go delete mode 100644 pkg/multicloud/ucloud/shell/network.go delete mode 100644 pkg/multicloud/ucloud/shell/printutils.go delete mode 100644 pkg/multicloud/ucloud/shell/region.go delete mode 100644 pkg/multicloud/ucloud/shell/secgroup.go delete mode 100644 pkg/multicloud/ucloud/shell/snapshot.go delete mode 100644 pkg/multicloud/ucloud/shell/ufile.go delete mode 100644 pkg/multicloud/ucloud/shell/vip.go delete mode 100644 pkg/multicloud/ucloud/shell/vpc.go delete mode 100644 pkg/multicloud/ucloud/shell/zone.go delete mode 100644 pkg/multicloud/ucloud/snapshot.go delete mode 100644 pkg/multicloud/ucloud/storage.go delete mode 100644 pkg/multicloud/ucloud/storagecache.go delete mode 100644 pkg/multicloud/ucloud/ufile.go delete mode 100644 pkg/multicloud/ucloud/vip.go delete mode 100644 pkg/multicloud/ucloud/vpc.go delete mode 100644 pkg/multicloud/ucloud/wire.go delete mode 100644 pkg/multicloud/ucloud/zone.go delete mode 100644 pkg/multicloud/zstack/disk.go delete mode 100644 pkg/multicloud/zstack/doc.go delete mode 100644 pkg/multicloud/zstack/eip.go delete mode 100644 pkg/multicloud/zstack/host.go delete mode 100644 pkg/multicloud/zstack/image.go delete mode 100644 pkg/multicloud/zstack/instance.go delete mode 100644 pkg/multicloud/zstack/instancenic.go delete mode 100644 pkg/multicloud/zstack/monitor.go delete mode 100644 pkg/multicloud/zstack/network.go delete mode 100644 pkg/multicloud/zstack/provider/doc.go delete mode 100644 pkg/multicloud/zstack/provider/provider.go delete mode 100644 pkg/multicloud/zstack/quota.go delete mode 100644 pkg/multicloud/zstack/region.go delete mode 100644 pkg/multicloud/zstack/securitygroup.go delete mode 100644 pkg/multicloud/zstack/shell/cluster.go delete mode 100644 pkg/multicloud/zstack/shell/configration.go delete mode 100644 pkg/multicloud/zstack/shell/disk.go delete mode 100644 pkg/multicloud/zstack/shell/disk_offering.go delete mode 100644 pkg/multicloud/zstack/shell/doc.go delete mode 100644 pkg/multicloud/zstack/shell/eip.go delete mode 100644 pkg/multicloud/zstack/shell/host.go delete mode 100644 pkg/multicloud/zstack/shell/image.go delete mode 100644 pkg/multicloud/zstack/shell/image_server.go delete mode 100644 pkg/multicloud/zstack/shell/instance.go delete mode 100644 pkg/multicloud/zstack/shell/instance_offering.go delete mode 100644 pkg/multicloud/zstack/shell/monitor.go delete mode 100644 pkg/multicloud/zstack/shell/network.go delete mode 100644 pkg/multicloud/zstack/shell/printutils.go delete mode 100644 pkg/multicloud/zstack/shell/quota.go delete mode 100644 pkg/multicloud/zstack/shell/region.go delete mode 100644 pkg/multicloud/zstack/shell/securitygroup.go delete mode 100644 pkg/multicloud/zstack/shell/snapshot.go delete mode 100644 pkg/multicloud/zstack/shell/storage.go delete mode 100644 pkg/multicloud/zstack/shell/tag.go delete mode 100644 pkg/multicloud/zstack/shell/user.go delete mode 100644 pkg/multicloud/zstack/shell/version.go delete mode 100644 pkg/multicloud/zstack/shell/vip.go delete mode 100644 pkg/multicloud/zstack/shell/wire.go delete mode 100644 pkg/multicloud/zstack/shell/zone.go delete mode 100644 pkg/multicloud/zstack/snapshot.go delete mode 100644 pkg/multicloud/zstack/storage.go delete mode 100644 pkg/multicloud/zstack/storagecache.go delete mode 100644 pkg/multicloud/zstack/vip.go delete mode 100644 pkg/multicloud/zstack/vpc.go delete mode 100644 pkg/multicloud/zstack/wire.go delete mode 100644 pkg/multicloud/zstack/zone.go create mode 100644 vendor/github.com/vishvananda/netlink/.gitignore create mode 100644 vendor/github.com/vishvananda/netlink/devlink_linux.go create mode 100644 vendor/github.com/vishvananda/netlink/netns_linux.go create mode 100644 vendor/github.com/vishvananda/netlink/netns_unspecified.go create mode 100644 vendor/github.com/vishvananda/netlink/nl/devlink_linux.go create mode 100644 vendor/github.com/vishvananda/netlink/nl/rdma_link_linux.go create mode 100644 vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go create mode 100644 vendor/github.com/vishvananda/netlink/rdma_link_linux.go create mode 100644 vendor/yunion.io/x/cloudmux/LICENSE create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/billing/billing_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/cloudid.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/cloudpolicy.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/saml_provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/bucket.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/cachedimages_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/cdn.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/cloudaccount_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/cloudregions_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/dbinstance_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/dbinstance_sku_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/disk_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/dnsrecordsets.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/dnszone.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/elastic_search.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/elasticache_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/elasticips_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/esxi_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/externalproject.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/filesystem.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/globalvpc_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/guest_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/host_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/inter_vpc_network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/kafka.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/kube_cluster.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/loadbalancer_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/modelarts_pool.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/modelarts_pool_sku.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/mongodb_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/mount_targets.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/nat_skus.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/natgateway.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/network_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/networkinterface_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/regiondata.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/routetable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/routetable_routesets.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/secgroup_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/sku_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/snapshot_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/storage_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/tablestores.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpc_peering_connection.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpcs_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpcs_ovn.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/waf_instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/wire_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/compute/zones_const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/const.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/metadata.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/apis/share.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/access_group.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/cdn.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/cloudprovider.go (99%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/cloudrole.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/clouduser.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/consts.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/dbinstance.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/disk.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/dnszone.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/cloudprovider/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/eip.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/elasticcache.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/elasticsearch.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/endpoints.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/extra.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/fakeregion.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/geoinfo.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/globalvpc.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/i18n.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/images.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/instance.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/inter_vpc_network.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/kafka.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/kube_cluster.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/loadbalancer.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/loadbalanceracl.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/loadbalancerbackend.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/loadbalancerbackendgroup.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/loadbalancercertificate.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/loadbalancerlistener.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/metrics.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/modelarts_pool.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/mongodb.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/mount_target.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/nas.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/nat.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/network.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/objectstore.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/osinfo.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/resources.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/resourcetags.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/retry.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/route_table.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/saml.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/securitygroup.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/serversku.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/snapshot_policy.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/subaccount.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/subscription.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/transport.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/vpc.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/vpc_peering_connection.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/waf.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/cloudprovider/waitstatus.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/access_groups.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/aliyun.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/bucket.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/business.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/cdn.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/charge.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/cloud_enterprise_network.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/cloud_enterprise_network_route.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_account.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_database.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/dbinstance_parameter.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_privilege.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dns_domain.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/dns_domain_record.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elastic_search.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/elastic_search_instance_types.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_account.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_acl.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_parameter.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/errors.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/events.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/filesystem.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/instancenic.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/instancetype.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kafka.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/keypair.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_cluster.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_node.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_node_pools.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/latitud_and_longitude.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancer.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalanceracl.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerbackend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerbackendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerdefaultbackend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerdefaultbackendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerhttplistener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerhttpslistener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerlistenerrule.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancermasterslavebackend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancermasterslavebackendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerservercertificate.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancertcplistener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerudplistener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/mongodb.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/mongodb_backup.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/mount_target.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natdtable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natgateway.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natstable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/networkinterfaces.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/objects.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/private_zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/private_zone_record.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/project.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/quota.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/ram.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_group.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_policy.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_role.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_user.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ramimage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/resource_tags.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/routetable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/saml_provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/snapshot_policy.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/storagecache.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/sts.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/tablestore.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/tag_base.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/task.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/utils.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/vpc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/vrouter.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/vswitch.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/waf.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/waf_domain.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/wire.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aliyun/wrapper.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/apsara.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/bucket.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/charge.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_account.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_database.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/dbinstance_parameter.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_privilege.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_account.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_acl.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_parameter.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/errors.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instancenic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instancetype.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ipv6_gateway.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/keypair.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancer.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalanceracl.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerbackend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerbackendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerdefaultbackend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerdefaultbackendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerhttplistener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerhttpslistener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerlistenerrule.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancermasterslavebackend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancermasterslavebackendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerservercertificate.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancertcplistener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerudplistener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natdtable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natgateway.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natstable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/networkinterfaces.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/objects.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/organization.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/ots.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/project.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/quota.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/ram.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_group.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_policy.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/ram_role.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_user.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ramimage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/resource_tags.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/routetable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/snapshot_policy.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/storagecache.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/sts.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/tag_base.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/task.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/utils.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/vpc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/vrouter.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/vswitch.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/wire.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/apsara/wrapper.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/aws.go (99%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/aws_request.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/bucket.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/cloudtrail.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_account.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/dbinstance_const.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_database.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/dbinstance_parameter.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/disk.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/dnshostedzone.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/dnsrecordset.go (99%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/dnstrafficpolicy.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/eip.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/elasticache_instance.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/elasticache_parameter.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/elasticache_snapshot.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/elasticache_user.go (95%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_group.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_policy.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_role.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_user.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/image.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/imageowners.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/instancenic.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/internetgateway.go (93%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/keypair.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/latitude_and_longitude.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancer.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerbackend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerbackendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancercert.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerlistener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerlistenerrule.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/natgateway.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/networkinterface.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/organizations.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/region.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/reservedinstance.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/resource_tag.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/route.go (96%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/routetable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/s3object.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/saml_provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/securitygroup.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/sku.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/snapshot.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/snapshot_policy.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/storagecache.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/sts.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/utils.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/vpc_peering_connection.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/waf_ipsets.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/waf_regexsets.go (99%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/waf_rule_groups.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/aws/waf_rules.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/zone.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/app_gateways.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/app_service_plan.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/autoscale_setting.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/azure.go (99%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/blobobject.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_disk.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_eip.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_host.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_instance.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_instancenic.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_instancesize.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_network.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_secruitygroup.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_snapshot.go (93%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_storage.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_vpc.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/classic_wire.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/cloudgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/cloudpolicy.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/clouduser.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/concurrent/balancer.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/concurrent/pool.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/concurrent/request.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/concurrent/worker.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/data_disk.go (96%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance_account.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/dbinstance_configuration.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance_database.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/debug.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/enrollment_account.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/enterprise_redis.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/event.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/geographicinfo.go (97%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/instancenic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/kube_cluster.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/kube_node_pools.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancer.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/loadbalancer_props.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerbackend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerbackendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancercert.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerlistener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerlistenerrule.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/loganalytics.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/network.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/os_disk.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/policy.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/progress/computeStats.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/progress/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/progress/readerWithProgress.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/progress/status.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/provider/provider.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/publisher.go (99%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/rds_managed_sqlserver.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/rds_managed_sqlserver_account.go (93%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/rds_managed_sqlserver_database.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/rds_sqlserver_account.go (93%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/rds_sqlserver_backup.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/rds_sqlserver_database.go (96%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/redis.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/redis_acl.go (93%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/resourcegroup.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/resourcesku.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/saml_provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/service.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storageaccount.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/subscription.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/tag_base.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/upload.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/usage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/waf.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/waf_front_doors.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/azure/waf_rule_groups.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/web_app.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/billing_base.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/bingocloud/bingo.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/cluster.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/eip.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/bingocloud/host.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/instancenic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/node.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/secgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/wire.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/bingocloud/zone.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/bucket_base.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/cloudpods/cloudpods.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/instancenic.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/cloudpods/keypair.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/project.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/secgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/sku.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/zone.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/clouduser.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ctyun/crm.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ctyun/ctyun.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/disk.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ctyun/diskbackup.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ctyun/diskbackup_policy.go (97%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/instancenic.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ctyun/keypair.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/latitud_and_longitude.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/network.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ctyun/order.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/project.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/region.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ctyun/secrules.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/dbinstance_account_base.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/dbinstance_backup_base.go (93%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/dbinstance_base.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/dbinstance_database_base.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/disk_base.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/client.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ecloud/create_time.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/instancenic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/latitud_and_longitude.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/region.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ecloud/request.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ecloud/signer.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/eip_base.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/elasticcache_base.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/cluster.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/datacenter.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/device.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/devtools.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/fakeregion.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/guestos.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/host.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/hostnic.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/image.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/ip.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/logger.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/manager.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/mobase.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/monitor.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/net_topology.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/net_topology_pro.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/network.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/resourcepool.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storagecache.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/template.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/utils.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/vcenter/vcenter.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/vdisk.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/virtualmachine.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/vnic.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/esxi/vswitch.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/bigquery.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/bucket.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/bucketacl.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/cloudbuild.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_account.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_database.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/dbinstance_parameter.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/globalnetwork.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/google.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/host.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/iampolicy.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/instancenic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/latitude_and_longitude.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_backend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_backendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_cert.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/loadbalancer_components.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_listener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_listenerrule.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/machinetype.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/network.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/operation.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/project.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/quota.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/region.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/regiondisk.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/regionstorage.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/resourcebase.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/resourcepolicy.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/s3object.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/google/saml.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/sku.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/google/zone.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/bucket.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_account.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_database.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcs/dbinstance_parameter.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_privilege.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_skus.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/eip.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcs/hcs.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instancenic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instancetype.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/job.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcs/keypair.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_acl.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_backend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_backendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_cert.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcs/loadbalancer_healthcheck.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_listener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_listener_rule.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/monitor.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcs/nat_sku.go (95%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natdtable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natgateway.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natstable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/object.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/port.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/project.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcs/redis_account.go (92%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcs/redis_backup.go (94%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcs/redis_instancetype.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcs/redis_parameter.go (93%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/routetables.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/securitygroup.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcs/signer.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/vpc_peering.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/zone.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/bucket.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/auth/credential.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/auth/credentials/access_key_credential.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signer.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signers/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signers/signer_access_key.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/client.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager/manager.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/manager_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/manager_resource.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_bandwidths.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_ces.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_credential.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_backup.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_dbinstance_datastore.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_flavor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_job.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_dbinstance_storage.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_disks.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dnat_rules.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_domains.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_eips.go (95%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_elasticcache.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_endpoints.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_enterpriceprojects.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_flavors.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_groups.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_images.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_interface.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_jobs.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_keypairs.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_loadbalancer_backend.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_loadbalancer_backend_group.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_loadbalancer_certificates.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_loadbalancer_healthcheck.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_loadbalancer_listeners.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_loadbalancer_policies.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_loadbalancer_rules.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_loadbalancer_whitelists.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_loadbalancers.go (95%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_mapping.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_natgateway.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_port.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_projects.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_quotas.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_regions.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_roles.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_saml_provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_secgroup_rules.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_secgroups.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_servers.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/modules/mod_services.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_sfs.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_snapshots.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_snat_rules.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_subnets.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_traces.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_users.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpc_peerings.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpc_routes.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpcs.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_zones.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/requests/requests.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/client/responses/responses.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/cloudgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/clouduser.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/consts.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_account.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_database.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/dbinstance_parameter.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_privilege.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_skus.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/disk.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/disktype.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/domain.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_account.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/elasticcache_acl.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_parameter.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/enterpriceprojects.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/hcso.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/huawei.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instancenic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instancetype.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/keypair.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/latitud_and_longitude.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_acl.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_backend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_backendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_cert.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/loadbalancer_healthcheck.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_listener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_listener_rule.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts_sku.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/nat_skus.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natdtable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natgateway.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natstable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/object.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/order.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/port.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/project.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/quota.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/roles.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/routetable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/saml_provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/sfs-turbo.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/storagecache.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/hcso/task.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/traces.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/utils.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/vpc_peering.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/host_base.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/bucket.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/client/auth/credential.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/client/auth/credentials/access_key_credential.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signer.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/signer_access_key.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/client.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/manager.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_resource.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/client/modules/mod_balances.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_ces.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_credential.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_disks.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dnat_rules.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_domains.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_elasticcache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_flavors.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_groups.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_images.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_interface.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_jobs.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_keypairs.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_mapping.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_natgateway.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/client/modules/mod_orders.go (96%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_port.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_projects.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_quotas.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_regions.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_roles.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/client/modules/mod_routetables.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_saml_provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_secgroup_rules.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_secgroups.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_servers.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_sfs.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snapshots.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snat_rules.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_subnets.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_traces.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_users.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_routes.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpcs.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_zones.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/client/requests/requests.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/client/responses/responses.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/cloudgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/clouduser.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/consts.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_account.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_database.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/dbinstance_parameter.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_privilege.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/disk.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/disktype.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/domain.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_account.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/elasticcache_acl.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_parameter.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/enterpriceprojects.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/huawei.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancenic.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/instancetype.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/keypair.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/latitud_and_longitude.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_acl.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_cert.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/loadbalancer_healthcheck.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_listener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_listener_rule.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool_sku.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natdtable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natgateway.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natstable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/object.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/auth.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/client.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/conf.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/const.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/convert.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/error.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/http.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/log.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/model.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/temporary.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/trait.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/obs/util.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/order.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/port.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/project.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/quota.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/roles.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/routetables.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/saml_provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/sfs-turbo.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/tag_base.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/huawei/task.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/traces.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/utils.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc_peering.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/image_base.go (95%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/nic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/region.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/incloudsphere/sphere.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/task.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/incloudsphere/version.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/instance_base.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/jdcloud/balance.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/instancenic.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/jdcloud/instancetype.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/jdcloud/jdcloud.go (96%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/latitud_and_longitude.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/jdcloud/log.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/networkinterface.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/jdcloud/rds_account.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/jdcloud/rds_backup.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/jdcloud/rds_database.go (94%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/jdcloud/rds_privilege.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/utils.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/lbredirect_base.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/loadbalancer_base.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/loader/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/loader/loader.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/mongodb_base.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/nas_base.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/natgateway_base.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/networkinterface_base.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/no_lb_region.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/no_storage_region.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/nutanix/cluster.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/instancenic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/network.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/nutanix/nutanix.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/storagecache.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/nutanix/task.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/objectstore/buckets.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/objectstore/ceph/adminapi.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/bucket.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/objectstore/ceph/ceph.go (95%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/doc.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/objectstore/interface.go (96%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/object.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/objectstore/objectstore.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider/provider.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/objectstore/shell.go (99%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/objectstore/xsky/adminapi.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/bucket.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/provider/provider.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/objectstore/xsky/xsky.go (96%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/flavor.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/host.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/hypervisor.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/instancenic.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/keypaire.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/loadbalabcerpool.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalanceracl.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/loadbalancerl7policy.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/loadbalancerl7rule.go (97%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancerlistener.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/loadbalancermember.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/loadbalbacer.go (99%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/loadbalbancerhealthmonitor.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/message.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/network.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/nova_disk.go (94%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/novastorage.go (94%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/openstack.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/port.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/project.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/quota.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/roles.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/openstack/router.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/routetable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/progress.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/project_base.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/proxmox/cluster.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/nic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/provider/provider.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/proxmox/proxmox.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/task.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/proxmox/util.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/bandwidthpackage.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/bucket.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/cam_collaborator.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_group.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_policy.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_role.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_user.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cdn.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/certificate.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cloud_connect_network.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/cloud_connect_network_route.go (97%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/dbinstance.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/deal.go (97%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/disk.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/dnspod_domain.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/dnspod_record.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elastic_search.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_account.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_backup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_instance.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/elasticcache_parameters.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/elasticcache_secgroup.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/elasticcache_task.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/errors.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/events.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/instancenic.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/instancetype.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kafka.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/kafka_topic.go (97%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/keypair.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/kube_clusters.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kube_node_pools.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kube_nodes.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/latitud_and_longitude.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_acl.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_backend.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_backendgroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_listener.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_listenerrule.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/localdisk.go (95%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/localstorage.go (96%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/memcached.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/mongodb.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/natdtable.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/natgateway.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/networkinterface.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/object.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/project.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/provider/provider.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/qcloud.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/quota.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/rds_mariadb_sku.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/rds_mysql_account.go (98%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/rds_mysql_backup.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/rds_mysql_database.go (94%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/rds_mysql_sku.go (99%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/rds_postgre_sku.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/rds_sqlserver_sku.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/rds_tdsql.go (98%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/route_table.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/saml_provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/snapshot_policy.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/storagecache.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/sts.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tag_base.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/tags.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/tdsql_account.go (96%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/tdsql_database.go (93%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/qcloud/types.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/vpc_peering_connection.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/region_base.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/bucket.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/dbinstance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/instancenic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/loadbalancer.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/remotefile/misc.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/network.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/remotefile/projects.go (90%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/region.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/remotefile/remotefile.go (99%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/remotefile/resource.go (94%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/resource_base.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/secgroup_base.go (94%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/serversku_base.go (94%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/storage_base.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/tag_base.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/client.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ucloud/consts.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/disk.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/image.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/instancenic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/latitud_and_longitude.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/network.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/project.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/storage.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/storagecache.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/tag_base.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ucloud/ucloud.go (99%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/ufile.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/ucloud/utils.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/vip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/virtualresource_base.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/vpc_base.go (97%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/zstack/cluster.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/zstack/configuration.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/disk.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/zstack/disk_offering.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/eip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/host.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/image.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/zstack/image_server.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/instance.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/instancenic.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/monitor.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/network.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/zstack/network_service.go (100%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/zstack/offering.go (97%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/provider/doc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/provider/provider.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/quota.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/region.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/securitygroup.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/snapshot.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/storage.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/zstack/storage_local.go (97%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/storagecache.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/zstack/systag.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/tag_base.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/zstack/version.go (100%) create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/vip.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/vpc.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/wire.go create mode 100644 vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/zone.go rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/zstack/zstack.go (99%) rename {pkg => vendor/yunion.io/x/cloudmux/pkg}/multicloud/zstack/zstack_const.go (100%) diff --git a/cmd/aliyuncli/main.go b/cmd/aliyuncli/main.go deleted file mode 100644 index 8d4f0cc8e1..0000000000 --- a/cmd/aliyuncli/main.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - _ "yunion.io/x/onecloud/pkg/multicloud/aliyun/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - CloudEnv string `help:"Cloud environment" default:"$ALIYUN_CLOUD_ENV" choices:"InternationalCloud|FinanceCloud" metavar:"ALIYUN_CLOUD_ENV"` - AccessKey string `help:"Access key" default:"$ALIYUN_ACCESS_KEY" metavar:"ALIYUN_ACCESS_KEY"` - Secret string `help:"Secret" default:"$ALIYUN_SECRET" metavar:"ALIYUN_SECRET"` - RegionId string `help:"RegionId" default:"$ALIYUN_REGION" metavar:"ALIYUN_REGION"` - SUBCOMMAND string `help:"aliyuncli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "aliyuncli", - "Command-line interface to aliyun API.", - `See "aliyuncli COMMAND --help" 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.") - } - - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*aliyun.SRegion, error) { - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing accessKey") - } - - if len(options.Secret) == 0 { - return nil, fmt.Errorf("Missing secret") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := aliyun.NewAliyunClient( - aliyun.NewAliyunClientConfig( - options.CloudEnv, - options.AccessKey, - options.Secret, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - 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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - return - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *aliyun.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/apsaracli/main.go b/cmd/apsaracli/main.go deleted file mode 100644 index 3faca57e93..0000000000 --- a/cmd/apsaracli/main.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/apsara" - _ "yunion.io/x/onecloud/pkg/multicloud/apsara/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - AccessKey string `help:"Access key" default:"$APSARA_ACCESS_KEY" metavar:"APSARA_ACCESS_KEY"` - Secret string `help:"Secret" default:"$APSARA_SECRET" metavar:"APSARA_SECRET"` - Endpoint string `help:"Apsara endpoint" default:"$APSARA_ENDPOINT" metavar:"APSARA_ENDPOINT"` - RegionId string `help:"RegionId" default:"$APSARA_REGION" metavar:"APSARA_REGION"` - DEFAULT_REGION string `help:"Default region" default:"$APSARA_DEFAULT_REGION"` - SUBCOMMAND string `help:"apsaracli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "apsaracli", - "Command-line interface to apsara API.", - `See "apsaracli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*apsara.SRegion, error) { - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing accessKey") - } - - if len(options.Secret) == 0 { - return nil, fmt.Errorf("Missing secret") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := apsara.NewApsaraClient( - apsara.NewApsaraClientConfig( - options.AccessKey, - options.Secret, - options.Endpoint, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - URL: options.Endpoint, - DefaultRegion: options.DEFAULT_REGION, - }, - ), - ) - 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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - return - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *apsara.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/awscli/main.go b/cmd/awscli/main.go deleted file mode 100644 index 3ae9a69730..0000000000 --- a/cmd/awscli/main.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/pkg/errors" - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aws" - _ "yunion.io/x/onecloud/pkg/multicloud/aws/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - AccessUrl string `help:"Access key" default:"$AWS_ACCESS_URL" choices:"ChinaCloud|InternationalCloud" metavar:"AWS_ACCESS_URL"` - AccessKey string `help:"Access key" default:"$AWS_ACCESS_KEY" metavar:"AWS_ACCESS_KEY"` - Secret string `help:"Secret" default:"$AWS_SECRET" metavar:"AWS_SECRET"` - RegionId string `help:"RegionId" default:"$AWS_REGION" metavar:"AWS_REGION"` - AccountId string `help:"Subaccount ID" default:"$AWS_ACCOUNT_ID" metavar:"AWS_ACCOUNT_ID"` - SUBCOMMAND string `help:"awscli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "awscli", - "Command-line interface to aws API.", - `See "awscli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - 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") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := aws.NewAwsClient( - aws.NewAwsClientConfig( - options.AccessUrl, - options.AccessKey, - options.Secret, - options.AccountId, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - if err != nil { - return nil, err - } - - region, err := cli.GetRegion(options.RegionId) - if err != nil { - return nil, errors.Wrapf(err, "GetRegion(%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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - return - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *aws.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/azurecli/main.go b/cmd/azurecli/main.go deleted file mode 100644 index 489391371c..0000000000 --- a/cmd/azurecli/main.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/azure" - _ "yunion.io/x/onecloud/pkg/multicloud/azure/shell" - "yunion.io/x/onecloud/pkg/util/printutils" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - DirectoryID string `help:"Azure account Directory ID/Tenant ID" default:"$AZURE_DIRECTORY_ID" metavar:"AZURE_DIRECTORY_ID"` - SubscriptionID string `help:"Azure account subscription ID" default:"$AZURE_SUBSCRIPTION_ID" metavar:"AZURE_SUBSCRIPTION_ID"` - ApplicationID string `help:"Azure application ID" default:"$AZURE_APPLICATION_ID" metavar:"AZURE_APPLICATION_ID"` - ApplicationKey string `help:"Azure application key" default:"$AZURE_APPLICATION_KEY" metavar:"AZURE_APPLICATION_KEY"` - RegionId string `help:"RegionId" default:"$AZURE_REGION_ID" metavar:"AZURE_REGION_ID"` - CloudEnv string `help:"Cloud Environment" default:"$AZURE_CLOUD_ENV" choices:"AzureGermanCloud|AzureChinaCloud|AzureUSGovernmentCloud|AzurePublicCloud" metavar:"AZURE_CLOUD_ENV"` - SUBCOMMAND string `help:"azurecli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "azurecli", - "Command-line interface to azure API.", - `See "azurecli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*azure.SRegion, error) { - if len(options.DirectoryID) == 0 { - return nil, fmt.Errorf("Missing Directory ID") - } - - if len(options.SubscriptionID) == 0 { - return nil, fmt.Errorf("Missing subscription ID") - } - - if len(options.ApplicationID) == 0 { - return nil, fmt.Errorf("Missing Application ID") - } - - if len(options.ApplicationKey) == 0 { - return nil, fmt.Errorf("Missing Application Key") - } - - if len(options.CloudEnv) == 0 { - return nil, fmt.Errorf("Missing Cloud Environment") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := azure.NewAzureClient( - azure.NewAzureClientConfig( - options.CloudEnv, - options.DirectoryID, - options.ApplicationID, - options.ApplicationKey, - ). - SubscriptionId(options.SubscriptionID). - Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - - if err != nil { - return nil, err - } - region := cli.GetRegion(options.RegionId) - if region == nil { - fmt.Println("Please chooce which region you are going to use:") - regions := cli.GetRegions() - printutils.PrintInterfaceList(regions, 0, 0, 0, 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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *azure.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/bingocli/main.go b/cmd/bingocli/main.go deleted file mode 100644 index 197ee574fe..0000000000 --- a/cmd/bingocli/main.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - _ "yunion.io/x/onecloud/pkg/multicloud/bingocloud/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - RegionId string - Endpoint string `help:"Endpoint" default:"$BINGO_CLOUD_ENDPOINT" metavar:"BINGO_CLOUD_ENDPOINT"` - AccessKey string `help:"Access Key" default:"$BINGO_CLOUD_ACCESS_KEY" metavar:"BINGO_CLOUD_ACCESS_KEY"` - SecretKey string `help:"Secret Key" default:"$BINGO_CLOUD_SECRET_KEY" metavar:"BINGO_CLOUD_SECRET_KEY"` - SUBCOMMAND string `help:"bingocli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "bingocli", - "Command-line interface to bingo cloud API.", - `See "bingocli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*bingocloud.SRegion, error) { - if len(options.Endpoint) == 0 { - return nil, fmt.Errorf("Missing endpoint") - } - - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing access key") - } - - if len(options.SecretKey) == 0 { - return nil, fmt.Errorf("Missing secret key") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := bingocloud.NewBingoCloudClient( - bingocloud.NewBingoCloudClientConfig( - options.Endpoint, - options.AccessKey, - options.SecretKey, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - if err != nil { - return nil, err - } - - return cli.GetRegion(options.RegionId) -} - -func main() { - parser, e := getSubcommandParser() - if e != nil { - showErrorAndExit(e) - } - e = parser.ParseArgs(os.Args[1:], false) - options := parser.Options().(*BaseOptions) - - if parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - return - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *bingocloud.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/climc/shell/compute/buckets.go b/cmd/climc/shell/compute/buckets.go index 599505f969..92721cb060 100644 --- a/cmd/climc/shell/compute/buckets.go +++ b/cmd/climc/shell/compute/buckets.go @@ -19,6 +19,7 @@ import ( "io" "os" + "yunion.io/x/cloudmux/pkg/multicloud/objectstore" "yunion.io/x/jsonutils" api "yunion.io/x/onecloud/pkg/apis/compute" @@ -26,7 +27,6 @@ import ( "yunion.io/x/onecloud/pkg/mcclient/modulebase" modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" "yunion.io/x/onecloud/pkg/mcclient/options" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" ) func init() { diff --git a/cmd/climc/shell/misc/version.go b/cmd/climc/shell/misc/version.go index 2fa6f686f2..c502c6ae9f 100644 --- a/cmd/climc/shell/misc/version.go +++ b/cmd/climc/shell/misc/version.go @@ -17,11 +17,11 @@ package misc import ( "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modulebase" modules "yunion.io/x/onecloud/pkg/mcclient/modules" diff --git a/cmd/cloudpodscli/main.go b/cmd/cloudpodscli/main.go deleted file mode 100644 index dc982ef04f..0000000000 --- a/cmd/cloudpodscli/main.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" - _ "yunion.io/x/onecloud/pkg/multicloud/cloudpods/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - AuthURL string `help:"Auth URL" default:"$CLOUDPODS_AUTH_URL" metavar:"CLOUDPODS_AUTH_URL"` - AccessKey string `help:"AccessKey" default:"$CLOUDPODS_ACCESS_KEY" metavar:"CLOUDPODS_ACCESS_KEY"` - AccessSecret string `help:"AccessSecret" default:"$CLOUDPODS_ACCESS_SECRET" metavar:"CLOUDPODS_ACCESS_SECRET"` - RegionId string `help:"RegionId" default:"$CLOUDPODS_REGION_ID|default" metavar:"CLOUDPODS_REGION_ID"` - SUBCOMMAND string `help:"cloudpodscli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, err := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "cloudpodscli", - "Command-line interface to cloudpods API.", - `See "cloudpodscli COMMAND --help" for help on a specific command.`) - - if err != nil { - return nil, err - } - - subcmd := parse.GetSubcommand() - if subcmd == nil { - return nil, fmt.Errorf("No subcommand argument.") - } - for _, v := range shellutils.CommandTable { - _, err = subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if err != nil { - return nil, err - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*cloudpods.SRegion, error) { - if len(options.AuthURL) == 0 { - return nil, fmt.Errorf("Missing AuthURL") - } - - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing access key") - } - - if len(options.AccessSecret) == 0 { - return nil, fmt.Errorf("Missing access secret") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := cloudpods.NewCloudpodsClient( - cloudpods.NewCloudpodsClientConfig( - options.AuthURL, - options.AccessKey, - options.AccessSecret, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - if err != nil { - return nil, err - } - region, err := cli.GetRegion(options.RegionId) - if err != nil { - return nil, err - } - return region, nil -} - -func main() { - parser, err := getSubcommandParser() - if err != nil { - showErrorAndExit(err) - } - err = parser.ParseArgs(os.Args[1:], false) - options := parser.Options().(*BaseOptions) - - if parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if err != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(err) - return - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *cloudpods.SRegion - region, err = newClient(options) - if err != nil { - showErrorAndExit(err) - } - err = subcmd.Invoke(region, suboptions) - if err != nil { - showErrorAndExit(err) - } -} diff --git a/cmd/ctyuncli/main.go b/cmd/ctyuncli/main.go deleted file mode 100644 index b302c8409d..0000000000 --- a/cmd/ctyuncli/main.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - _ "yunion.io/x/onecloud/pkg/multicloud/ctyun/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - cloudprovider.SCtyunExtraOptions - - Debug bool `help:"Show debug" default:"false"` - AccessKey string `help:"Access key" default:"$CTYUN_ACCESS_KEY"` - Secret string `help:"Secret" default:"$CTYUN_SECRET"` - RegionId string `help:"RegionId" default:"$CTYUN_REGION"` - SUBCOMMAND string `help:"ctyuncli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "ctyuncli", - "Command-line interface to ctyun API.", - `See "ctyuncli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*ctyun.SRegion, error) { - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing accessKey") - } - - if len(options.Secret) == 0 { - return nil, fmt.Errorf("Missing secret") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := ctyun.NewSCtyunClient( - ctyun.NewSCtyunClientConfig( - options.AccessKey, options.Secret, &options.SCtyunExtraOptions, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - 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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *ctyun.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/ecloudcli/main.go b/cmd/ecloudcli/main.go deleted file mode 100644 index ee540fc5c0..0000000000 --- a/cmd/ecloudcli/main.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/ecloud" - _ "yunion.io/x/onecloud/pkg/multicloud/ecloud/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type Options struct { - Debug bool `help:"Show debug" default:"false"` - AccessKey string `help:"Access key" default:"$ECLOUD_ACCESS_KEY"` - AccessSecret string `help:"Secret" default:"$ECLOUD_ACCESS_SECRET"` - RegionId string `help:"RegionId" default:"$ECLOUD_REGION"` - SUBCOMMAND string `help:"ecloudcli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&Options{}, - "ecloudcli", - "Command-line interface to ecloud API.", - `See "ecloudcli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *Options) (*ecloud.SRegion, error) { - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing access key") - } - - if len(options.AccessSecret) == 0 { - return nil, fmt.Errorf("Missing access secret") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := ecloud.NewEcloudClient( - ecloud.NewEcloudClientConfig( - ecloud.NewRamRoleSigner(options.AccessKey, options.AccessSecret), - ).SetDebug(options.Debug). - SetCloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - if err != nil { - return nil, err - } - - region, err := cli.GetRegionById(options.RegionId) - if err != nil { - return nil, err - } - - return region, nil -} - -func main() { - parser, e := getSubcommandParser() - if e != nil { - showErrorAndExit(e) - } - e = parser.ParseArgs(os.Args[1:], false) - options := parser.Options().(*Options) - - if parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *ecloud.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/esxicli/main.go b/cmd/esxicli/main.go deleted file mode 100644 index 8fdd8b8b3b..0000000000 --- a/cmd/esxicli/main.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/esxi" - _ "yunion.io/x/onecloud/pkg/multicloud/esxi/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Host string `help:"Host IP or NAME" default:"$VMWARE_HOST" metavar:"VMWARE_HOST"` - Port int `help:"Service port" default:"$VMWARE_PORT" metavar:"VMWARE_PORT"` - Account string `help:"VCenter or ESXi Account" default:"$VMWARE_ACCOUNT" metavar:"VMWARE_ACCOUNT"` - Password string `help:"Password" default:"$VMWARE_PASSWORD" metavar:"VMWARE_PASSWORD"` - Debug bool - Format string `choices:"xml|json" default:"json"` - SUBCOMMAND string `help:"aliyuncli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "esxicli", - "Command-line interface to VMware VSphere Webservice API.", - `See "esxicli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*esxi.SESXiClient, error) { - if len(options.Host) == 0 { - return nil, fmt.Errorf("Missing host") - } - - if len(options.Account) == 0 { - return nil, fmt.Errorf("Missing account") - } - - if len(options.Password) == 0 { - return nil, fmt.Errorf("Missing password") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - return esxi.NewESXiClient2( - esxi.NewESXiClientConfig( - options.Host, - options.Port, - options.Account, - options.Password, - ). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ).Debug(options.Debug).Format(options.Format), - ) -} - -func main() { - parser, e := getSubcommandParser() - if e != nil { - showErrorAndExit(e) - } - e = parser.ParseArgs(os.Args[1:], false) - options := parser.Options().(*BaseOptions) - - if parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var esxicli *esxi.SESXiClient - esxicli, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(esxicli, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/googlecli/main.go b/cmd/googlecli/main.go deleted file mode 100644 index 0952a75559..0000000000 --- a/cmd/googlecli/main.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/google" - _ "yunion.io/x/onecloud/pkg/multicloud/google/shell" - "yunion.io/x/onecloud/pkg/util/fileutils2" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - AuthFile string `help:"google cloud auth json file path" default:"$GOOGLE_AUTH_FILE" metavar:"GOOGLE_AUTH_FILE"` - ClientEmail string `help:"Client email" default:"$GOOGLE_CLIENT_EMAIL" metavar:"GOOGLE_CLIENT_EMAIL"` - ProjectID string `help:"Project ID" default:"$GOOGLE_PROJECT_ID" metavar:"GOOGLE_PROJECT_ID"` - PrivateKeyID string `help:"Private Key ID" default:"$GOOGLE_PRIVATE_KEY_ID" metavar:"GOOGLE_PRIVATE_KEY_ID"` - PrivateKey string `help:"Private Key" default:"$GOOGLE_PRIVATE_KEY" metavar:"GOOGLE_PRIVATE_KEY"` - RegionID string `help:"RegionID" default:"$GOOGLE_REGION" metavar:"GOOGLE_REGION"` - SUBCOMMAND string `help:"googlecli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "googlecli", - "Command-line interface to google API.", - `See "googlecli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(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) (*google.SRegion, error) { - if len(options.AuthFile) > 0 { - jsonStr, err := fileutils2.FileGetContents(options.AuthFile) - if err != nil { - return nil, errors.Wrap(err, "FileGetContents") - } - jsonCfg, err := jsonutils.ParseString(jsonStr) - if err != nil { - return nil, errors.Wrap(err, "jsonutils.ParseString") - } - options.ClientEmail, _ = jsonCfg.GetString("client_email") - options.PrivateKeyID, _ = jsonCfg.GetString("private_key_id") - options.PrivateKey, _ = jsonCfg.GetString("private_key") - options.ProjectID, _ = jsonCfg.GetString("project_id") - } - if len(options.ClientEmail) == 0 { - return nil, fmt.Errorf("Missing ClientEmail") - } - - if len(options.PrivateKeyID) == 0 { - return nil, fmt.Errorf("Missing PrivateKeyID") - } - - if len(options.PrivateKey) == 0 { - return nil, fmt.Errorf("Missing PrivateKey") - } - - if len(options.ProjectID) == 0 { - return nil, fmt.Errorf("Missing ProjectID") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := google.NewGoogleClient( - google.NewGoogleClientConfig( - options.ProjectID, - options.ClientEmail, - options.PrivateKeyID, - options.PrivateKey, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - 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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - return - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *google.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/hcscli/main.go b/cmd/hcscli/main.go deleted file mode 100644 index 1694354e31..0000000000 --- a/cmd/hcscli/main.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcs" - _ "yunion.io/x/onecloud/pkg/multicloud/hcs/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - AuthUrl string `help:"Auth url" default:"$HCS_AUTH_URL"` - AccessKey string `help:"Access key" default:"$HCS_ACCESS_KEY" metavar:"HCS_ACCESS_KEY"` - Secret string `help:"Secret" default:"$HCS_SECRET" metavar:"HCS_SECRET"` - RegionId string `help:"RegionId" default:"$HCS_REGION" metavar:"HCS_REGION"` - ProjectId string `help:"RegionId" default:"$HCS_PROJECT_ID" metavar:"HCS_PROJECT_ID"` - SUBCOMMAND string `help:"hcscli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "hcscli", - "Command-line interface to hcs API.", - `See "hcscli COMMAND --help" 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.") - } - - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*hcs.SRegion, error) { - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing accessKey") - } - - if len(options.Secret) == 0 { - return nil, fmt.Errorf("Missing secret") - } - - if len(options.AuthUrl) == 0 { - return nil, fmt.Errorf("Missing authUrl") - } - - if len(options.RegionId) == 0 { - return nil, fmt.Errorf("Missing regionId") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := hcs.NewHcsClient( - hcs.NewHcsConfig( - options.AccessKey, - options.Secret, - options.ProjectId, - options.AuthUrl, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - if err != nil { - return nil, err - } - - return cli.GetRegion(options.RegionId) -} - -func main() { - parser, e := getSubcommandParser() - if e != nil { - showErrorAndExit(e) - } - e = parser.ParseArgs(os.Args[1:], false) - options := parser.Options().(*BaseOptions) - - if parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - return - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *hcs.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/hcsocli/main.go b/cmd/hcsocli/main.go deleted file mode 100644 index 6bf054030a..0000000000 --- a/cmd/hcsocli/main.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - _ "yunion.io/x/onecloud/pkg/multicloud/hcso/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - cloudprovider.SHCSOEndpoints - Debug bool `help:"Show debug" default:"false"` - AccessKey string `help:"Access key" default:"$HUAWEI_ACCESS_KEY" metavar:"HUAWEI_ACCESS_KEY"` - Secret string `help:"Secret" default:"$HUAWEI_SECRET" metavar:"HUAWEI_SECRET"` - RegionId string `help:"RegionId" default:"$HUAWEI_REGION" metavar:"HUAWEI_REGION"` - DEFAULT_REGION string `help:"Default Region" default:"$HUAWEI_DEFAULT_REGION" metavar:"HUAWEI_DEFAULT_REGION"` - ProjectId string `help:"ProjectId" default:"$HUAWEI_PROJECT" metavar:"HUAWEI_PROJECT"` - SUBCOMMAND string `help:"huaweicli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "hcsocli", - "Command-line interface to huawei API.", - `See "hcsocli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*huawei.SRegion, error) { - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing accessKey") - } - - if len(options.Secret) == 0 { - return nil, fmt.Errorf("Missing secret") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := huawei.NewHuaweiClient( - huawei.NewHuaweiClientConfig( - options.AccessKey, - options.Secret, - options.ProjectId, - &options.SHCSOEndpoints, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - DefaultRegion: options.DEFAULT_REGION, - }, - ), - ) - 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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *huawei.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/huaweicli/main.go b/cmd/huaweicli/main.go deleted file mode 100644 index 85341f5837..0000000000 --- a/cmd/huaweicli/main.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei" - _ "yunion.io/x/onecloud/pkg/multicloud/huawei/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"Show debug" default:"false"` - CloudEnv string `help:"Cloud environment" default:"$HUAWEI_CLOUD_ENV" choices:"ChinaCloud|InternationalCloud" metavar:"HUAWEI_CLOUD_ENV"` - AccessKey string `help:"Access key" default:"$HUAWEI_ACCESS_KEY" metavar:"HUAWEI_ACCESS_KEY"` - Secret string `help:"Secret" default:"$HUAWEI_SECRET" metavar:"HUAWEI_SECRET"` - RegionId string `help:"RegionId" default:"$HUAWEI_REGION" metavar:"HUAWEI_REGION"` - ProjectId string `help:"RegionId" default:"$HUAWEI_PROJECT" metavar:"HUAWEI_PROJECT"` - SUBCOMMAND string `help:"huaweicli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "huaweicli", - "Command-line interface to huawei API.", - `See "huaweicli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*huawei.SRegion, error) { - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing accessKey") - } - - if len(options.Secret) == 0 { - return nil, fmt.Errorf("Missing secret") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := huawei.NewHuaweiClient( - huawei.NewHuaweiClientConfig( - options.CloudEnv, - options.AccessKey, - options.Secret, - options.ProjectId, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - 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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *huawei.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/incloudspherecli/main.go b/cmd/incloudspherecli/main.go deleted file mode 100644 index 827c81c318..0000000000 --- a/cmd/incloudspherecli/main.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" - _ "yunion.io/x/onecloud/pkg/multicloud/incloudsphere/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - Host string `help:"Host" default:"$INCLOUD_SPHERE_HOST" metavar:"INCLOUD_SPHERE_HOST"` - AccessKeyId string `help:"AccessKey" default:"$INCLOUD_SPHERE_ACCESS_KEY_ID" metavar:"INCLOUD_SPHERE_ACCESS_KEY_ID"` - AccessSecret string `help:"AccessSecret" default:"$INCLOUD_SPHERE_ACCESS_KEY_SECRET" metavar:"INCLOUD_SPHERE_ACCESS_SECRET"` - SUBCOMMAND string `help:"incloudspherecli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "incloudspherecli", - "Command-line interface to InCloud Sphere API.", - `See "incloudspherecli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*incloudsphere.SRegion, error) { - if len(options.Host) == 0 { - return nil, fmt.Errorf("Missing host") - } - - if len(options.AccessKeyId) == 0 { - return nil, fmt.Errorf("Missing access key id") - } - - if len(options.AccessSecret) == 0 { - return nil, fmt.Errorf("Missing access secret") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := incloudsphere.NewSphereClient( - incloudsphere.NewSphereClientConfig( - options.Host, - options.AccessKeyId, - options.AccessSecret, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - if err != nil { - return nil, err - } - - return cli.GetRegion() -} - -func main() { - parser, e := getSubcommandParser() - if e != nil { - showErrorAndExit(e) - } - e = parser.ParseArgs(os.Args[1:], false) - options := parser.Options().(*BaseOptions) - - if parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - return - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *incloudsphere.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/jdcloudcli/main.go b/cmd/jdcloudcli/main.go deleted file mode 100644 index 57f8461f84..0000000000 --- a/cmd/jdcloudcli/main.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "github.com/sirupsen/logrus" - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/log" - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/jdcloud" - _ "yunion.io/x/onecloud/pkg/multicloud/jdcloud/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type Options struct { - Debug bool `help:"Show debug" default:"false"` - AccessKey string `help:"Access key" default:"$JDCLOUD_ACCESS_KEY"` - AccessSecret string `help:"Secret" default:"$JDCLOUD_SECRET"` - RegionId string `help:"RegionId" default:"$JDCLOUD_REGION"` - SUBCOMMAND string `help:"jdcloudcli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, err := structarg.NewArgumentParserWithHelp(&Options{}, - "jdcloudcli", - "Command-line interface to ecloud API.", - `See "jdcloudcli COMMAND --help" for help on a specific command.`, - ) - if err != nil { - return nil, err - } - - subcmd := parse.GetSubcommand() - if subcmd == nil { - return nil, fmt.Errorf("No subcommand argument") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *Options) (*jdcloud.SJDCloudClient, error) { - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing access key") - } - if len(options.AccessSecret) == 0 { - return nil, fmt.Errorf("Missing access secret") - } - regionId := options.RegionId - if regionId == "" { - regionId = jdcloud.JDCLOUD_DEFAULT_REGION - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cfcg := cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - } - - return jdcloud.NewJDCloudClient( - jdcloud.NewJDCloudClientConfig( - options.AccessKey, - options.AccessSecret, - ).CloudproviderConfig(cfcg).Debug(options.Debug), - ) -} - -func main() { - parser, err := getSubcommandParser() - if err != nil { - showErrorAndExit(err) - } - err = parser.ParseArgs(os.Args[1:], false) - options := parser.Options().(*Options) - - if parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - if options.Debug { - log.SetLogLevel(log.Logger(), logrus.DebugLevel) - } else { - log.SetLogLevel(log.Logger(), logrus.InfoLevel) - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if err != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(err) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - client, err := newClient(options) - if err != nil { - showErrorAndExit(err) - } - region := client.GetRegion(options.RegionId) - if region == nil { - fmt.Printf("not found region: %s", options.RegionId) - return - } - err = subcmd.Invoke(region, suboptions) - if err != nil { - showErrorAndExit(err) - } -} diff --git a/cmd/ncli/main.go b/cmd/ncli/main.go deleted file mode 100644 index 35339f159c..0000000000 --- a/cmd/ncli/main.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/nutanix" - _ "yunion.io/x/onecloud/pkg/multicloud/nutanix/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - Host string `help:"Host" default:"$NUTANIX_HOST" metavar:"NUTANIX_HOST"` - Username string `help:"Username" default:"$NUTANIX_USERNAME" metavar:"NUTANIX_USERNAME"` - Password string `help:"Password" default:"$NUTANIX_PASSWORD" metavar:"NUTANIX_PASSWORD"` - Port int `help:"Port" default:"$NUTANIX_PORT|9440" metavar:"NUTANIX_PORT"` - SUBCOMMAND string `help:"ncli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "ncli", - "Command-line interface to nutanix API.", - `See "ncli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*nutanix.SRegion, error) { - if len(options.Host) == 0 { - return nil, fmt.Errorf("Missing host") - } - - if len(options.Username) == 0 { - return nil, fmt.Errorf("Missing username") - } - - if len(options.Password) == 0 { - return nil, fmt.Errorf("Missing password") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := nutanix.NewNutanixClient( - nutanix.NewNutanixClientConfig( - options.Host, - options.Username, - options.Password, - options.Port, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - if err != nil { - return nil, err - } - - return cli.GetRegion() -} - -func main() { - parser, e := getSubcommandParser() - if e != nil { - showErrorAndExit(e) - } - e = parser.ParseArgs(os.Args[1:], false) - options := parser.Options().(*BaseOptions) - - if parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - return - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *nutanix.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/openstackcli/main.go b/cmd/openstackcli/main.go deleted file mode 100644 index afea364b42..0000000000 --- a/cmd/openstackcli/main.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/openstack" - _ "yunion.io/x/onecloud/pkg/multicloud/openstack/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - AuthURL string `help:"Auth URL" default:"$OPENSTACK_AUTH_URL" metavar:"OPENSTACK_AUTH_URL"` - Username string `help:"Username" default:"$OPENSTACK_USERNAME" metavar:"OPENSTACK_USERNAME"` - Password string `help:"Password" default:"$OPENSTACK_PASSWORD" metavar:"OPENSTACK_PASSWORD"` - Project string `help:"Project" default:"$OPENSTACK_PROJECT" metavar:"OPENSTACK_PROJECT"` - EndpointType string `help:"Project" default:"$OPENSTACK_ENDPOINT_TYPE|internal" metavar:"OPENSTACK_ENDPOINT_TYPE"` - DomainName string `help:"Domain of user" default:"$OPENSTACK_DOMAIN_NAME|Default" metavar:"OPENSTACK_DOMAIN_NAME"` - ProjectDomain string `help:"Domain of project" default:"$OPENSTACK_PROJECT_DOMAIN|Default" metavar:"OPENSTACK_PROJECT_DOMAIN"` - RegionID string `help:"RegionId" default:"$OPENSTACK_REGION_ID" metavar:"OPENSTACK_REGION_ID"` - SUBCOMMAND string `help:"openstackcli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "openstackcli", - "Command-line interface to openstack API.", - `See "openstackcli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*openstack.SRegion, error) { - if len(options.AuthURL) == 0 { - return nil, fmt.Errorf("Missing AuthURL") - } - - if len(options.Username) == 0 { - return nil, fmt.Errorf("Missing Username") - } - - if len(options.Password) == 0 { - return nil, fmt.Errorf("Missing Password") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := openstack.NewOpenStackClient( - openstack.NewOpenstackClientConfig( - options.AuthURL, - options.Username, - options.Password, - options.Project, - options.ProjectDomain, - ). - EndpointType(options.EndpointType). - DomainName(options.DomainName). - Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - 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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *openstack.SRegion - if len(options.RegionID) == 0 { - options.RegionID = openstack.OPENSTACK_DEFAULT_REGION - } - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/proxmoxcli/main.go b/cmd/proxmoxcli/main.go deleted file mode 100644 index 177be0c361..0000000000 --- a/cmd/proxmoxcli/main.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/proxmox" - _ "yunion.io/x/onecloud/pkg/multicloud/proxmox/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - Username string `help:"Username" default:"$PROXMOX_USERNAME" metavar:"PROXMOX_USERNAME"` - Password string `help:"Password" default:"$PROXMOX_PASSWORD" metavar:"PROXMOX_PASSWORD"` - Host string `help:"Host" default:"$PROXMOX_HOST" metavar:"PROXMOX_HOST"` - Port int `help:"Port" default:"$PROXMOX_PORT|8006" metavar:"PROXMOX_PORT"` - SUBCOMMAND string `help:"proxmoxcli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "proxmoxcli", - "Command-line interface to proxmoxc API.", - `See "proxmoxcli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*proxmox.SRegion, error) { - if len(options.Host) == 0 { - return nil, fmt.Errorf("Missing host") - } - - if len(options.Username) == 0 { - return nil, fmt.Errorf("Missing username") - } - - if len(options.Password) == 0 { - return nil, fmt.Errorf("Missing password") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := proxmox.NewProxmoxClient( - proxmox.NewProxmoxClientConfig( - options.Username, - options.Password, - options.Host, - options.Port, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - if err != nil { - return nil, err - } - - return cli.GetRegion(), nil -} - -func main() { - parser, e := getSubcommandParser() - if e != nil { - showErrorAndExit(e) - } - - e = parser.ParseArgs(os.Args[1:], false) - options := parser.Options().(*BaseOptions) - - if parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - return - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *proxmox.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/qcloudcli/main.go b/cmd/qcloudcli/main.go deleted file mode 100644 index 60630ee926..0000000000 --- a/cmd/qcloudcli/main.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - _ "yunion.io/x/onecloud/pkg/multicloud/qcloud/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - AppID string `help:"AppID" default:"$QCLOUD_APPID" metavar:"QCLOUD_APPID"` - SecretID string `help:"Secret" default:"$QCLOUD_SECRET_ID" metavar:"QCLOUD_SECRET_ID"` - SecretKey string `help:"Access key" default:"$QCLOUD_SECRET_KEY" metavar:"QCLOUD_SECRET_KEY"` - RegionId string `help:"RegionId" default:"$QCLOUD_REGION" metavar:"QCLOUD_REGION"` - SUBCOMMAND string `help:"azurecli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "qcloudcli", - "Command-line interface to tencentcloud API.", - `See "qcloudcli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*qcloud.SRegion, error) { - if len(options.SecretKey) == 0 { - return nil, fmt.Errorf("Missing SecretKey") - } - - if len(options.SecretID) == 0 { - return nil, fmt.Errorf("Missing SecretID") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - if cli, err := qcloud.NewQcloudClient( - qcloud.NewQcloudClientConfig( - options.SecretID, - options.SecretKey, - ).AppId(options.AppID). - Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ); err != nil { - return nil, err - } else if region := cli.GetRegion(options.RegionId); region == nil { - return nil, fmt.Errorf("No such region %s", options.RegionId) - } else { - 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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *qcloud.SRegion - if len(options.RegionId) == 0 { - options.RegionId = qcloud.QCLOUD_DEFAULT_REGION - } - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/s3cli/main.go b/cmd/s3cli/main.go deleted file mode 100644 index 6b5109887b..0000000000 --- a/cmd/s3cli/main.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "os" - - "yunion.io/x/structarg" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" - "yunion.io/x/onecloud/pkg/multicloud/objectstore/ceph" - _ "yunion.io/x/onecloud/pkg/multicloud/objectstore/shell" - "yunion.io/x/onecloud/pkg/multicloud/objectstore/xsky" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - AccessUrl string `help:"Access url" default:"$S3_ACCESS_URL" metavar:"S3_ACCESS_URL"` - AccessKey string `help:"Access key" default:"$S3_ACCESS_KEY" metavar:"S3_ACCESS_KEY"` - Secret string `help:"Secret" default:"$S3_SECRET" metavar:"S3_SECRET"` - Backend string `help:"Backend driver" default:"$S3_BACKEND" metavar:"S3_BACKEND"` - SUBCOMMAND string `help:"s3cli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "s3cli", - "Command-line interface to standard S3 API.", - `See "s3cli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (cloudprovider.ICloudRegion, error) { - if len(options.AccessUrl) == 0 { - return nil, fmt.Errorf("Missing accessUrl") - } - - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing accessKey") - } - - if len(options.Secret) == 0 { - return nil, fmt.Errorf("Missing secret") - } - - if options.Backend == api.CLOUD_PROVIDER_CEPH { - return ceph.NewCephRados( - objectstore.NewObjectStoreClientConfig( - options.AccessUrl, options.AccessKey, options.Secret, - ).Debug(options.Debug), - ) - } else if options.Backend == api.CLOUD_PROVIDER_XSKY { - return xsky.NewXskyClient( - objectstore.NewObjectStoreClientConfig( - options.AccessUrl, options.AccessKey, options.Secret, - ).Debug(options.Debug), - ) - } - return objectstore.NewObjectStoreClient( - objectstore.NewObjectStoreClientConfig( - options.AccessUrl, options.AccessKey, options.Secret, - ).Debug(options.Debug), - ) -} - -func main() { - parser, e := getSubcommandParser() - if e != nil { - showErrorAndExit(e) - } - e = parser.ParseArgs(os.Args[1:], false) - options := parser.Options().(*BaseOptions) - - if parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var client cloudprovider.ICloudRegion - client, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(client, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/ucloudcli/main.go b/cmd/ucloudcli/main.go deleted file mode 100644 index 8e2cb3730b..0000000000 --- a/cmd/ucloudcli/main.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - _ "yunion.io/x/onecloud/pkg/multicloud/ucloud/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"Show debug" default:"false"` - - AccessKey string `help:"Access key" default:"$UCLOUD_ACCESS_KEY" metavar:"UCLOUD_ACCESS_KEY"` - Secret string `help:"Secret" default:"$UCLOUD_SECRET" metavar:"UCLOUD_SECRET"` - RegionId string `help:"RegionId" default:"$UCLOUD_REGION" metavar:"UCLOUD_REGION"` - ProjectId string `help:"ProjectId" default:"$UCLOUD_PROJECT" metavar:"UCLOUD_PROJECT"` - SUBCOMMAND string `help:"ucloudcli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "ucloudcli", - "Command-line interface to ucloud API.", - `See "ucloudcli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*ucloud.SRegion, error) { - if len(options.AccessKey) == 0 { - return nil, fmt.Errorf("Missing accessKey") - } - - if len(options.Secret) == 0 { - return nil, fmt.Errorf("Missing secret") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := ucloud.NewUcloudClient( - ucloud.NewUcloudClientConfig( - options.AccessKey, - options.Secret, - ).ProjectId(options.ProjectId).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - 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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *ucloud.SRegion - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/cmd/zstackcli/main.go b/cmd/zstackcli/main.go deleted file mode 100644 index a37b736174..0000000000 --- a/cmd/zstackcli/main.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 main - -import ( - "fmt" - "net/http" - "net/url" - "os" - - "golang.org/x/net/http/httpproxy" - - "yunion.io/x/structarg" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/zstack" - _ "yunion.io/x/onecloud/pkg/multicloud/zstack/shell" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type BaseOptions struct { - Debug bool `help:"debug mode"` - AuthURL string `help:"Auth URL" default:"$ZSTACK_AUTH_URL" metavar:"ZSTACK_AUTH_URL"` - Username string `help:"Username" default:"$ZSTACK_USERNAME" metavar:"ZSTACK_USERNAME"` - Password string `help:"Password" default:"$ZSTACK_PASSWORD" metavar:"ZSTACK_PASSWORD"` - RegionID string `help:"RegionId" default:"$ZSTACK_REGION_ID" metavar:"ZSTACK_REGION_ID"` - SUBCOMMAND string `help:"zstackcli subcommand" subcommand:"true"` -} - -func getSubcommandParser() (*structarg.ArgumentParser, error) { - parse, e := structarg.NewArgumentParserWithHelp(&BaseOptions{}, - "zstackcli", - "Command-line interface to zstack API.", - `See "zstackcli COMMAND --help" 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.") - } - for _, v := range shellutils.CommandTable { - _, e := subcmd.AddSubParserWithHelp(v.Options, v.Command, v.Desc, v.Callback) - if e != nil { - return nil, e - } - } - return parse, nil -} - -func showErrorAndExit(e error) { - fmt.Fprintf(os.Stderr, "%s", e) - fmt.Fprintln(os.Stderr) - os.Exit(1) -} - -func newClient(options *BaseOptions) (*zstack.SRegion, error) { - if len(options.AuthURL) == 0 { - return nil, fmt.Errorf("Missing AuthURL") - } - - if len(options.Username) == 0 { - return nil, fmt.Errorf("Missing Username") - } - - if len(options.Password) == 0 { - return nil, fmt.Errorf("Missing Password") - } - - cfg := &httpproxy.Config{ - HTTPProxy: os.Getenv("HTTP_PROXY"), - HTTPSProxy: os.Getenv("HTTPS_PROXY"), - NoProxy: os.Getenv("NO_PROXY"), - } - cfgProxyFunc := cfg.ProxyFunc() - proxyFunc := func(req *http.Request) (*url.URL, error) { - return cfgProxyFunc(req.URL) - } - - cli, err := zstack.NewZStackClient( - zstack.NewZstackClientConfig( - options.AuthURL, - options.Username, - options.Password, - ).Debug(options.Debug). - CloudproviderConfig( - cloudprovider.ProviderConfig{ - ProxyFunc: proxyFunc, - }, - ), - ) - 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 parser.IsHelpSet() { - fmt.Print(parser.HelpString()) - return - } - subcmd := parser.GetSubcommand() - subparser := subcmd.GetSubParser() - if e != nil || subparser == nil { - if subparser != nil { - fmt.Print(subparser.Usage()) - } else { - fmt.Print(parser.Usage()) - } - showErrorAndExit(e) - } - suboptions := subparser.Options() - if subparser.IsHelpSet() { - fmt.Print(subparser.HelpString()) - return - } - var region *zstack.SRegion - if len(options.RegionID) == 0 { - options.RegionID = zstack.ZSTACK_DEFAULT_REGION - } - region, e = newClient(options) - if e != nil { - showErrorAndExit(e) - } - e = subcmd.Invoke(region, suboptions) - if e != nil { - showErrorAndExit(e) - } -} diff --git a/go.mod b/go.mod index 339a88b72c..b17c879dee 100644 --- a/go.mod +++ b/go.mod @@ -4,20 +4,10 @@ go 1.18 require ( bazil.org/fuse v0.0.0-20180421153158-65cc252bf669 - cloud.google.com/go/storage v1.10.0 github.com/360EntSecGroup-Skylar/excelize v1.4.0 - github.com/Azure/azure-sdk-for-go v36.1.0+incompatible - github.com/Azure/go-autorest/autorest v0.9.6 - github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 github.com/LeeEirc/terminalparser v0.0.0-20220328021224-de16b7643ea4 github.com/Masterminds/sprig v2.22.0+incompatible - github.com/Microsoft/azure-vhd-utils v0.0.0-20181115010904-44cbada2ece3 - github.com/aliyun/alibaba-cloud-sdk-go v1.61.684 - github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible github.com/anacrolix/torrent v0.0.0-20181129073333-cc531b8c4a80 - github.com/aokoli/goutils v1.0.1 - github.com/aws/aws-sdk-go v1.39.0 - github.com/basgys/goxml2json v1.1.1-0.20181031222924-996d9fc8d313 github.com/benbjohnson/clock v1.0.0 github.com/bitly/go-simplejson v0.5.0 github.com/c-bata/go-prompt v0.2.4 @@ -25,7 +15,7 @@ require ( github.com/coredns/coredns v1.3.0 github.com/coreos/go-iptables v0.6.0 github.com/creack/pty v1.1.11 - github.com/fatih/color v1.10.0 + github.com/fatih/color v1.13.0 github.com/fernet/fernet-go v0.0.0-20180830025343-9eac43b88a5e github.com/fsnotify/fsnotify v1.4.9 github.com/ghodss/yaml v1.0.0 @@ -42,15 +32,12 @@ require ( github.com/gorilla/websocket v1.4.1 github.com/gosuri/uitable v0.0.0-20160404203958-36ee7e946282 github.com/hako/durafmt v0.0.0-20180520121703-7b7ae1e72ead - github.com/huaweicloud/huaweicloud-sdk-go v1.0.26 - github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.12+incompatible github.com/jaypipes/ghw v0.9.1 - github.com/jdcloud-api/jdcloud-sdk-go v1.55.0 github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c github.com/lestrrat-go/jwx v1.0.2 github.com/lestrrat/go-jwx v0.0.0-20180221005942-b7d4802280ae github.com/libvirt/libvirt-go-xml v5.2.0+incompatible - github.com/ma314smith/signedxml v0.0.0-20200410192636-c342a2d0ae60 + github.com/ma314smith/signedxml v0.0.0-20210628192057-abc5b481ae1c github.com/mattn/go-sqlite3 v1.14.12 github.com/mdlayher/arp v0.0.0-20190313224443-98a83c8a2717 github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 @@ -66,28 +53,23 @@ require ( github.com/serialx/hashring v0.0.0-20180504054112-49a4782e9908 github.com/sevlyar/go-daemon v0.1.5 github.com/shirou/gopsutil v3.21.11+incompatible - github.com/sirupsen/logrus v1.9.0 github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 github.com/smartystreets/goconvey v1.6.4 github.com/stretchr/testify v1.7.2 github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.413 - github.com/tencentyun/cos-go-sdk-v5 v0.7.24 github.com/tjfoc/gmsm v1.4.1 - github.com/tredoe/osutil v0.0.0-20161130133508-7d3ee1afa71c - github.com/vishvananda/netlink v1.0.0 + github.com/tredoe/osutil v1.0.6 + github.com/vishvananda/netlink v1.1.0 github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 github.com/vmihailenco/msgpack v4.0.4+incompatible - github.com/vmware/govmomi v0.20.1 go.etcd.io/etcd/api/v3 v3.5.0 go.etcd.io/etcd/client/v3 v3.5.0 golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 - golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 golang.org/x/text v0.3.7 - golang.org/x/time v0.0.0-20191024005414-555d28b269f0 + golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20191008142428-8d021180e987 google.golang.org/grpc v1.38.0 @@ -101,6 +83,7 @@ require ( k8s.io/client-go v0.19.3 k8s.io/cluster-bootstrap v0.19.3 moul.io/http2curl/v2 v2.3.0 + yunion.io/x/cloudmux v0.3.10-0-alpha.0 yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656 yunion.io/x/jsonutils v1.0.1-0.20220819091305-3bab322ab4fd yunion.io/x/log v1.0.0 @@ -113,7 +96,11 @@ require ( require ( cloud.google.com/go v0.65.0 // indirect + cloud.google.com/go/storage v1.10.0 // indirect + github.com/Azure/azure-sdk-for-go v36.1.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.9.6 // indirect github.com/Azure/go-autorest/autorest/adal v0.8.2 // indirect + github.com/Azure/go-autorest/autorest/azure/auth v0.4.2 // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.3.1 // indirect github.com/Azure/go-autorest/autorest/date v0.2.0 // indirect github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect @@ -124,11 +111,14 @@ require ( github.com/DataDog/zstd v1.3.4 // indirect github.com/Masterminds/goutils v1.1.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect + github.com/Microsoft/azure-vhd-utils v0.0.0-20181115010904-44cbada2ece3 // indirect github.com/RoaringBitmap/roaring v0.4.16 // indirect github.com/Shopify/sarama v1.20.0 // indirect github.com/Shopify/toxiproxy v2.1.4+incompatible // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/VividCortex/ewma v1.1.1 // indirect + github.com/aliyun/alibaba-cloud-sdk-go v1.61.684 // indirect + github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible // indirect github.com/anacrolix/dht v0.0.0-20181129074040-b09db78595aa // indirect github.com/anacrolix/go-libutp v0.0.0-20180808010927-aebbeb60ea05 // indirect github.com/anacrolix/log v0.0.0-20180808012509-286fcf906b48 // indirect @@ -136,8 +126,11 @@ require ( github.com/anacrolix/mmsg v0.0.0-20180808012353-5adb2c1127c0 // indirect github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778 // indirect github.com/anacrolix/utp v0.0.0-20180219060659-9e0e1d1d0572 // indirect + github.com/aokoli/goutils v1.0.1 // indirect github.com/apache/thrift v0.12.0 // indirect + github.com/aws/aws-sdk-go v1.39.0 // indirect github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect + github.com/basgys/goxml2json v1.1.1-0.20181031222924-996d9fc8d313 // indirect github.com/beevik/etree v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect @@ -185,7 +178,10 @@ require ( github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect github.com/huandu/xstrings v1.2.0 // indirect + github.com/huaweicloud/huaweicloud-sdk-go v1.0.26 // indirect + github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.12+incompatible // indirect github.com/imdario/mergo v0.3.6 // indirect + github.com/jdcloud-api/jdcloud-sdk-go v1.55.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/jstemmer/go-junit-report v0.9.1 // indirect @@ -195,7 +191,7 @@ require ( github.com/lestrrat-go/iter v0.0.0-20200422075355-fc1769541911 // indirect github.com/lestrrat-go/pdebug v0.0.0-20200204225717-4d6bd78da58d // indirect github.com/lestrrat/go-pdebug v0.0.0-20180220043741-569c97477ae8 // indirect - github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-colorable v0.1.9 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mattn/go-tty v0.0.0-20181127064339-e4f871175a2f // indirect @@ -226,15 +222,19 @@ require ( github.com/rivo/uniseg v0.2.0 // indirect github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect github.com/satori/go.uuid v1.2.0 // indirect + github.com/sirupsen/logrus v1.9.0 // indirect github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stretchr/objx v0.1.1 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.413 // indirect + github.com/tencentyun/cos-go-sdk-v5 v0.7.24 // indirect github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e // indirect github.com/tinylib/msgp v1.1.0 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/numcpus v0.4.0 // indirect github.com/ugorji/go/codec v1.1.7 // indirect + github.com/vmware/govmomi v0.20.1 // indirect github.com/willf/bitset v1.1.9 // indirect github.com/willf/bloom v2.0.3+incompatible // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect @@ -245,6 +245,7 @@ require ( go.uber.org/zap v1.17.0 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/mod v0.4.2 // indirect + golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/tools v0.1.2 // indirect google.golang.org/api v0.30.0 // indirect diff --git a/go.sum b/go.sum index 36503b3656..e9b60be153 100644 --- a/go.sum +++ b/go.sum @@ -3,7 +3,6 @@ bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxo cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= @@ -242,8 +241,9 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/farsightsec/golang-framestream v0.0.0-20181102145529-8a0cb8ba8710 h1:QdyRyGZWLEvJG5Kw3VcVJvhXJ5tZ1MkRgqpJOEZSySM= github.com/farsightsec/golang-framestream v0.0.0-20181102145529-8a0cb8ba8710/go.mod h1:eNde4IQyEiA5br02AouhEHCu3p3UzrCdFR4LuQHklMI= -github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fernet/fernet-go v0.0.0-20180830025343-9eac43b88a5e h1:P10tZmVD2XclAaT9l7OduMH1OLFzTa1wUuUqHZnEdI0= github.com/fernet/fernet-go v0.0.0-20180830025343-9eac43b88a5e/go.mod h1:2H9hjfbpSMHwY503FclkV/lZTBh2YlOmLLSda12uL8c= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= @@ -486,13 +486,14 @@ github.com/lestrrat/go-pdebug v0.0.0-20180220043741-569c97477ae8/go.mod h1:VXFH1 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/libvirt/libvirt-go-xml v5.2.0+incompatible h1:ALyVpa0/lFfFaUpb5l0fNBohufmQG6jsOGRCl/nKEi8= github.com/libvirt/libvirt-go-xml v5.2.0+incompatible/go.mod h1:oBlgD3xOA01ihiK5stbhFzvieyW+jVS6kbbsMVF623A= -github.com/ma314smith/signedxml v0.0.0-20200410192636-c342a2d0ae60 h1:q5rqPuvxdOzg1NC6sls3XSpRokQ5KAmLIYdLW1/kyOo= -github.com/ma314smith/signedxml v0.0.0-20200410192636-c342a2d0ae60/go.mod h1:KEgVcb43+f5KFUH/x6Vd3NROG0AIL2CuKMrIqYsmx6E= +github.com/ma314smith/signedxml v0.0.0-20210628192057-abc5b481ae1c h1:UPJygtyk491bJJ/DnRJFuzcq9Dl9NSeFrJ7VdiRzMxc= +github.com/ma314smith/signedxml v0.0.0-20210628192057-abc5b481ae1c/go.mod h1:KEgVcb43+f5KFUH/x6Vd3NROG0AIL2CuKMrIqYsmx6E= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= @@ -694,13 +695,16 @@ github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03O github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o= github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= -github.com/tredoe/osutil v0.0.0-20161130133508-7d3ee1afa71c h1:5q7IHeqvAA4hWR1CfpTOS7RFsTDC36TaSZ8Dvc00bPk= -github.com/tredoe/osutil v0.0.0-20161130133508-7d3ee1afa71c/go.mod h1:M/I710pXKQToMdqt/D+mJ4QsnW6WDaajyB6DWFmDXBs= +github.com/tredoe/fileutil v1.0.5/go.mod h1:HFzzpvg+3Q8LgmZgo1mVF5epHc/CVkWKEb3hja+/1Zo= +github.com/tredoe/goutil v1.0.0/go.mod h1:Qhf75QLcNEChimbl4wb8nROzw9PCFCPYTEUmTnoszXY= +github.com/tredoe/osutil v1.0.6 h1:KJvG9AFmUPLe3hsNKyPMIjNx77CkAJtMKVS4ugAT7vM= +github.com/tredoe/osutil v1.0.6/go.mod h1:zNq93p2DLHJWkHi2/+zi3xOjZl8xxiv3tiI2A6zcB3w= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -github.com/vishvananda/netlink v1.0.0 h1:bqNY2lgheFIu1meHUFSH3d7vG93AFyqg3oGbJCOJgSM= -github.com/vishvananda/netlink v1.0.0/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk= +github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= @@ -872,6 +876,7 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -936,8 +941,9 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1156,6 +1162,8 @@ sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +yunion.io/x/cloudmux v0.3.10-0-alpha.0 h1:lHjIqTm/VYxKZ3XHcIIfQ+/qOdDG3aP+8IypXoR2uqw= +yunion.io/x/cloudmux v0.3.10-0-alpha.0/go.mod h1:V2DwCkdaS+IZ/qrNlO1bSZY0mccB3tw/xqZ75GuAXyU= yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656 h1:0zlZD5uhZoIHgLVAWCz2aHaYk2ZrNsACCYD7R6EIBII= yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656/go.mod h1:Uxuou9WQIeJXNpy7t2fPLL0BYLvLiMvGQwY7Qc6aSws= yunion.io/x/jsonutils v0.0.0-20190625054549-a964e1e8a051/go.mod h1:4N0/RVzsYL3kH3WE/H1BjUQdFiWu50JGCFQuuy+Z634= diff --git a/pkg/apihelper/reflect.go b/pkg/apihelper/reflect.go index f0f7a3e298..04151d96be 100644 --- a/pkg/apihelper/reflect.go +++ b/pkg/apihelper/reflect.go @@ -226,8 +226,8 @@ type ModelSetUpdateResult struct { // ModelSetApplyUpdates applies bSet to aSet. // -// - PendingDeleted in bSet are removed from aSet -// - Newer models in bSet are updated in aSet +// - PendingDeleted in bSet are removed from aSet +// - Newer models in bSet are updated in aSet func ModelSetApplyUpdates(aSet, bSet IModelSet) *ModelSetUpdateResult { r := &ModelSetUpdateResult{ Changed: false, diff --git a/pkg/apis/cloudprovider/zz_generated.model.go b/pkg/apis/cloudprovider/zz_generated.model.go index 7d5dfcdf6f..df150d8908 100644 --- a/pkg/apis/cloudprovider/zz_generated.model.go +++ b/pkg/apis/cloudprovider/zz_generated.model.go @@ -14,9 +14,9 @@ package cloudprovider -import "yunion.io/x/onecloud/pkg/cloudprovider" +import "yunion.io/x/cloudmux/pkg/cloudprovider" -// DefaultAction is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.DefaultAction. +// DefaultAction is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.DefaultAction. type DefaultAction struct { // Allow, Block, Log, Count, Alert, Detection, Prevention Action string `json:"action"` @@ -30,7 +30,7 @@ type DefaultAction struct { ResponseHeaders map[string]string `json:"response_headers"` } -// SCdnDomain is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.SCdnDomain. +// SCdnDomain is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.SCdnDomain. type SCdnDomain struct { // cdn加速域名 Domain string `json:"domain"` @@ -46,7 +46,7 @@ type SCdnDomain struct { OriginType string `json:"origin_type"` } -// SCdnOrigin is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.SCdnOrigin. +// SCdnOrigin is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.SCdnOrigin. type SCdnOrigin struct { Type string `json:"type"` Origin string `json:"origin"` @@ -58,18 +58,18 @@ type SCdnOrigin struct { Priority int `json:"priority"` } -// SCdnOrigins is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.SCdnOrigins. +// SCdnOrigins is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.SCdnOrigins. type SCdnOrigins []SCdnOrigin -// SExcludeRule is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.SExcludeRule. +// SExcludeRule is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.SExcludeRule. type SExcludeRule struct { Name string `json:"name"` } -// SExcludeRules is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.SExcludeRules. +// SExcludeRules is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.SExcludeRules. type SExcludeRules []SExcludeRule -// SGeographicInfo is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.SGeographicInfo. +// SGeographicInfo is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.SGeographicInfo. type SGeographicInfo struct { // 纬度 // example: 26.647003 @@ -85,7 +85,7 @@ type SGeographicInfo struct { CountryCode string `json:"country_code"` } -// SSubAccount is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.SSubAccount. +// SSubAccount is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.SSubAccount. type SSubAccount struct { // 若Account不为空,可不传 Name string `json:"name"` @@ -96,7 +96,7 @@ type SSubAccount struct { DefaultProjectId string `json:"default_project_id"` } -// SWafStatement is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.SWafStatement. +// SWafStatement is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.SWafStatement. type SWafStatement struct { // 管理规则组名称 ManagedRuleGroupName string `json:"managed_rule_group_name"` @@ -130,14 +130,14 @@ type SWafStatement struct { RuleGroupId string `json:"rule_group_id"` } -// ServerVncInput is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.ServerVncInput. +// ServerVncInput is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.ServerVncInput. type ServerVncInput struct { // 是否使用原生vnc控制台,此选项仅对openstack有效 // default: false Origin bool `json:"origin"` } -// ServerVncOutput is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.ServerVncOutput. +// ServerVncOutput is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.ServerVncOutput. type ServerVncOutput struct { Id string `json:"id"` // baremetal @@ -160,7 +160,7 @@ type ServerVncOutput struct { Hypervisor string `json:"hypervisor"` } -// SubAccounts is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.SubAccounts. +// SubAccounts is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.SubAccounts. type SubAccounts struct { // 若输出则是全量子账号列表,若输入,代表允许同步的子账号 Accounts []cloudprovider.SSubAccount `json:"accounts"` @@ -172,29 +172,29 @@ type SubAccounts struct { } `json:"cloudregions"` } -// TWafAction is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.TWafAction. +// TWafAction is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.TWafAction. type TWafAction string -// TWafMatchField is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.TWafMatchField. +// TWafMatchField is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.TWafMatchField. type TWafMatchField string -// TWafMatchFieldValues is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.TWafMatchFieldValues. +// TWafMatchFieldValues is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.TWafMatchFieldValues. type TWafMatchFieldValues []string -// TWafOperator is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.TWafOperator. +// TWafOperator is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.TWafOperator. type TWafOperator string -// TWafStatementType is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.TWafStatementType. +// TWafStatementType is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.TWafStatementType. type TWafStatementType string -// TWafTextTransformation is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.TWafTextTransformation. +// TWafTextTransformation is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.TWafTextTransformation. type TWafTextTransformation string -// TextTransformations is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.TextTransformations. +// TextTransformations is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.TextTransformations. type TextTransformations []TWafTextTransformation -// WafAddresses is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.WafAddresses. +// WafAddresses is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.WafAddresses. type WafAddresses []string -// WafRegexPatterns is an autogenerated struct via yunion.io/x/onecloud/pkg/cloudprovider.WafRegexPatterns. +// WafRegexPatterns is an autogenerated struct via yunion.io/x/cloudmux/pkg/cloudprovider.WafRegexPatterns. type WafRegexPatterns []string diff --git a/pkg/apis/compute/bucket.go b/pkg/apis/compute/bucket.go index 6de6d2154c..01ed044b75 100644 --- a/pkg/apis/compute/bucket.go +++ b/pkg/apis/compute/bucket.go @@ -17,12 +17,12 @@ package compute import ( "net/http" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/regutils" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" ) diff --git a/pkg/apis/compute/cdn.go b/pkg/apis/compute/cdn.go index 55932c32df..1babff84b7 100644 --- a/pkg/apis/compute/cdn.go +++ b/pkg/apis/compute/cdn.go @@ -15,8 +15,9 @@ package compute import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/cloudprovider" ) const ( diff --git a/pkg/apis/compute/cloudaccount.go b/pkg/apis/compute/cloudaccount.go index 53993c37cf..6a0038e356 100644 --- a/pkg/apis/compute/cloudaccount.go +++ b/pkg/apis/compute/cloudaccount.go @@ -18,13 +18,13 @@ import ( "fmt" "reflect" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/gotypes" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/apis" proxyapi "yunion.io/x/onecloud/pkg/apis/cloudcommon/proxy" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" ) diff --git a/pkg/apis/compute/cloudaccount_const.go b/pkg/apis/compute/cloudaccount_const.go index 2c2f882959..f84b3b85de 100644 --- a/pkg/apis/compute/cloudaccount_const.go +++ b/pkg/apis/compute/cloudaccount_const.go @@ -15,8 +15,9 @@ package compute import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/choices" ) diff --git a/pkg/apis/compute/cloudprovider.go b/pkg/apis/compute/cloudprovider.go index aa71115bdd..efa652d265 100644 --- a/pkg/apis/compute/cloudprovider.go +++ b/pkg/apis/compute/cloudprovider.go @@ -15,11 +15,11 @@ package compute import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/apis" proxyapi "yunion.io/x/onecloud/pkg/apis/cloudcommon/proxy" - "yunion.io/x/onecloud/pkg/cloudprovider" ) type ManagedResourceInfo struct { diff --git a/pkg/apis/compute/disk.go b/pkg/apis/compute/disk.go index 8634b4a02d..03c0ba2ebc 100644 --- a/pkg/apis/compute/disk.go +++ b/pkg/apis/compute/disk.go @@ -17,13 +17,13 @@ package compute import ( "time" + "yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter" "yunion.io/x/jsonutils" "yunion.io/x/pkg/util/fileutils" "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/apis/billing" "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud/esxi/vcenter" ) type DiskCreateInput struct { diff --git a/pkg/apis/compute/dnsrecordsets.go b/pkg/apis/compute/dnsrecordsets.go index 222b651005..3a32dd2500 100644 --- a/pkg/apis/compute/dnsrecordsets.go +++ b/pkg/apis/compute/dnsrecordsets.go @@ -17,11 +17,11 @@ package compute import ( "regexp" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/util/regutils" "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" ) diff --git a/pkg/apis/compute/loadbalancer_const.go b/pkg/apis/compute/loadbalancer_const.go index 356d96a02d..ffe9ac9227 100644 --- a/pkg/apis/compute/loadbalancer_const.go +++ b/pkg/apis/compute/loadbalancer_const.go @@ -20,10 +20,10 @@ import ( // Load balancer status transition (for spec status) // -// create start stop delete -// init running - - - -// running - - stopped stopped -// stopped - running - - +// create start stop delete +// init running - - - +// running - - stopped stopped +// stopped - running - - // // Each entity will have spec and runtime version. Spec version will increment // on entity attribute update. Runtime version will be filled by the scheduler @@ -35,7 +35,6 @@ import ( // In the case of instance has PendingDeleted marked, it is also the // scheduler's duty to make the runtime status to stopped and finally the // entity in question -// const ( LB_STATUS_ENABLED = "enabled" LB_STATUS_DISABLED = "disabled" @@ -321,7 +320,7 @@ var LB_BOOL_VALUES = choices.NewChoices( LB_BOOL_OFF, ) -//TODO +// TODO // // - qch, quic connection id // - mh, maglev consistent hash diff --git a/pkg/apis/compute/regiondata.go b/pkg/apis/compute/regiondata.go index a5ae819bd4..91ab4c24f3 100644 --- a/pkg/apis/compute/regiondata.go +++ b/pkg/apis/compute/regiondata.go @@ -15,7 +15,7 @@ package compute import ( - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) var ( diff --git a/pkg/apis/compute/waf_instance.go b/pkg/apis/compute/waf_instance.go index f501adfb19..5f4390f4c4 100644 --- a/pkg/apis/compute/waf_instance.go +++ b/pkg/apis/compute/waf_instance.go @@ -15,8 +15,9 @@ package compute import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/cloudprovider" ) const ( diff --git a/pkg/apis/compute/waf_rules.go b/pkg/apis/compute/waf_rules.go index 0a69d1e203..0c3669fd6f 100644 --- a/pkg/apis/compute/waf_rules.go +++ b/pkg/apis/compute/waf_rules.go @@ -15,8 +15,9 @@ package compute import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/cloudprovider" ) const ( diff --git a/pkg/baremetal/utils/raid/adaptec/adaptec.go b/pkg/baremetal/utils/raid/adaptec/adaptec.go index ffdf24427d..6a2effbf84 100644 --- a/pkg/baremetal/utils/raid/adaptec/adaptec.go +++ b/pkg/baremetal/utils/raid/adaptec/adaptec.go @@ -306,12 +306,13 @@ func (ada *AdaptecRaidAdaptor) getCreateCmd(args ...string) string { } // setControllerMode change adapter controller's mode -// Controller Modes : 0 - RAID: Expose RAW -// : 1 - Auto Volume Mode -// : 2 - HBA Mode -// : 3 - RAID: Hide RAW -// : 4 - Simple Volume Mode -// : 5 - Mixed +// +// Controller Modes : 0 - RAID: Expose RAW +// : 1 - Auto Volume Mode +// : 2 - HBA Mode +// : 3 - RAID: Hide RAW +// : 4 - Simple Volume Mode +// : 5 - Mixed func (ada *AdaptecRaidAdaptor) setControllerMode(mode int) error { cmd := GetCommand("SETCONTROLLERMODE", fmt.Sprintf("%d", ada.GetIndex()), fmt.Sprintf("%d", mode), "noprompt") if _, err := ada.remoteRun(fmt.Sprintf("set controller mode to %d", mode), cmd); err != nil { diff --git a/pkg/cloudcommon/db/opslog_const.go b/pkg/cloudcommon/db/opslog_const.go index 6b2d03ebe5..a20e78c544 100644 --- a/pkg/cloudcommon/db/opslog_const.go +++ b/pkg/cloudcommon/db/opslog_const.go @@ -4,7 +4,7 @@ // 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 +// 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, diff --git a/pkg/cloudcommon/db/opslog_test.go b/pkg/cloudcommon/db/opslog_test.go index e344414fb2..5b9b34f0a8 100644 --- a/pkg/cloudcommon/db/opslog_test.go +++ b/pkg/cloudcommon/db/opslog_test.go @@ -4,7 +4,7 @@ // 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 +// 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, diff --git a/pkg/cloudcommon/policy/policy.go b/pkg/cloudcommon/policy/policy.go index 782a5e1a2f..e5f55c9a2f 100644 --- a/pkg/cloudcommon/policy/policy.go +++ b/pkg/cloudcommon/policy/policy.go @@ -390,10 +390,8 @@ func (manager *SPolicyManager) allowWithoutCache(policies rbacutils.TPolicySet, return result } -// // result: allow/deny for the named policy // userResult: allow/deny for the matched policies of userCred -// func explainPolicy(userCred mcclient.TokenCredential, policyReq jsonutils.JSONObject, policyData *sPolicyData) ([]string, rbacutils.SPolicyResult, rbacutils.SPolicyResult, error) { _, request, result, userResult, err := explainPolicyInternal(userCred, policyReq, policyData) return request, result, userResult, err diff --git a/pkg/cloudevent/models/cloudevents.go b/pkg/cloudevent/models/cloudevents.go index 9f9fcacef3..547cc5c385 100644 --- a/pkg/cloudevent/models/cloudevents.go +++ b/pkg/cloudevent/models/cloudevents.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/cloudevent" "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/cloudevent/models/cloudproviders.go b/pkg/cloudevent/models/cloudproviders.go index 022c504621..7dbb33cc2d 100644 --- a/pkg/cloudevent/models/cloudproviders.go +++ b/pkg/cloudevent/models/cloudproviders.go @@ -22,6 +22,7 @@ import ( "golang.org/x/net/http/httpproxy" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -35,7 +36,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudevent/options" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" diff --git a/pkg/cloudevent/service/service.go b/pkg/cloudevent/service/service.go index c16909d6f4..952f2c3134 100644 --- a/pkg/cloudevent/service/service.go +++ b/pkg/cloudevent/service/service.go @@ -18,6 +18,7 @@ import ( "os" "time" + _ "yunion.io/x/cloudmux/pkg/multicloud/loader" "yunion.io/x/log" _ "yunion.io/x/sqlchemy/backends" @@ -32,7 +33,6 @@ import ( _ "yunion.io/x/onecloud/pkg/cloudevent/policy" _ "yunion.io/x/onecloud/pkg/cloudevent/tasks" _ "yunion.io/x/onecloud/pkg/mcclient/modules" - _ "yunion.io/x/onecloud/pkg/multicloud/loader" ) func StartService() { diff --git a/pkg/cloudevent/tasks/cloudevent_sync_task.go b/pkg/cloudevent/tasks/cloudevent_sync_task.go index 0f83120b6a..37f982051a 100644 --- a/pkg/cloudevent/tasks/cloudevent_sync_task.go +++ b/pkg/cloudevent/tasks/cloudevent_sync_task.go @@ -20,6 +20,7 @@ import ( "github.com/pkg/errors" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudevent/models" "yunion.io/x/onecloud/pkg/cloudevent/options" - "yunion.io/x/onecloud/pkg/cloudprovider" ) type CloudeventSyncTask struct { diff --git a/pkg/cloudid/models/cloudaccount.go b/pkg/cloudid/models/cloudaccount.go index 2bb8086915..3f67b1fa75 100644 --- a/pkg/cloudid/models/cloudaccount.go +++ b/pkg/cloudid/models/cloudaccount.go @@ -24,6 +24,7 @@ import ( "golang.org/x/net/http/httpproxy" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -39,7 +40,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudid/options" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" diff --git a/pkg/cloudid/models/cloudgroup.go b/pkg/cloudid/models/cloudgroup.go index 15eedfd0cb..0da185e2ec 100644 --- a/pkg/cloudid/models/cloudgroup.go +++ b/pkg/cloudid/models/cloudgroup.go @@ -20,6 +20,7 @@ import ( "gopkg.in/fatih/set.v0" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -29,7 +30,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/cloudid/models/cloudgroupcaches.go b/pkg/cloudid/models/cloudgroupcaches.go index a28d7dcc26..d9846b94e2 100644 --- a/pkg/cloudid/models/cloudgroupcaches.go +++ b/pkg/cloudid/models/cloudgroupcaches.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -29,7 +30,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/cloudid/models/cloudpolicy.go b/pkg/cloudid/models/cloudpolicy.go index 9c64a3da1e..adb612f850 100644 --- a/pkg/cloudid/models/cloudpolicy.go +++ b/pkg/cloudid/models/cloudpolicy.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/cloudid/models/cloudpolicycaches.go b/pkg/cloudid/models/cloudpolicycaches.go index 32e1d34eac..653bcc409d 100644 --- a/pkg/cloudid/models/cloudpolicycaches.go +++ b/pkg/cloudid/models/cloudpolicycaches.go @@ -19,13 +19,13 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/cloudid" "yunion.io/x/onecloud/pkg/cloudcommon/db" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/cloudid/models/cloudprovider.go b/pkg/cloudid/models/cloudprovider.go index 3cedae0a40..2092843311 100644 --- a/pkg/cloudid/models/cloudprovider.go +++ b/pkg/cloudid/models/cloudprovider.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudid/options" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" diff --git a/pkg/cloudid/models/cloudrole.go b/pkg/cloudid/models/cloudrole.go index 6f333b21f0..8869b690ae 100644 --- a/pkg/cloudid/models/cloudrole.go +++ b/pkg/cloudid/models/cloudrole.go @@ -22,6 +22,7 @@ import ( "gopkg.in/fatih/set.v0" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" @@ -31,7 +32,6 @@ import ( computeapi "yunion.io/x/onecloud/pkg/apis/compute" "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/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" ) diff --git a/pkg/cloudid/models/clouduser.go b/pkg/cloudid/models/clouduser.go index be2ff8569f..bbbc33ffdc 100644 --- a/pkg/cloudid/models/clouduser.go +++ b/pkg/cloudid/models/clouduser.go @@ -21,6 +21,7 @@ import ( "gopkg.in/fatih/set.v0" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -36,7 +37,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" npk "yunion.io/x/onecloud/pkg/mcclient/modules/notify" diff --git a/pkg/cloudid/models/clouduser_policies.go b/pkg/cloudid/models/clouduser_policies.go index 3f35a2a638..c1267d0c32 100644 --- a/pkg/cloudid/models/clouduser_policies.go +++ b/pkg/cloudid/models/clouduser_policies.go @@ -17,13 +17,13 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/cloudid" "yunion.io/x/onecloud/pkg/cloudcommon/db" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/cloudid/models/saml_provider.go b/pkg/cloudid/models/saml_provider.go index ebd893a600..5b20dd37f0 100644 --- a/pkg/cloudid/models/saml_provider.go +++ b/pkg/cloudid/models/saml_provider.go @@ -19,6 +19,7 @@ import ( "fmt" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -29,7 +30,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" "yunion.io/x/onecloud/pkg/cloudid/options" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/samlutils" diff --git a/pkg/cloudid/saml/providers/aliyun/factory.go b/pkg/cloudid/saml/providers/aliyun/factory.go index 9573953a81..765cbabb3a 100644 --- a/pkg/cloudid/saml/providers/aliyun/factory.go +++ b/pkg/cloudid/saml/providers/aliyun/factory.go @@ -15,8 +15,9 @@ package aliyun import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" ) type SAliyunSAMLDriver struct{} diff --git a/pkg/cloudid/saml/providers/aws/factory.go b/pkg/cloudid/saml/providers/aws/factory.go index 4123c37529..b8b4b658d2 100644 --- a/pkg/cloudid/saml/providers/aws/factory.go +++ b/pkg/cloudid/saml/providers/aws/factory.go @@ -15,8 +15,9 @@ package aws import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" ) type SAWSSAMLDriver struct{} diff --git a/pkg/cloudid/saml/providers/awscn/factory.go b/pkg/cloudid/saml/providers/awscn/factory.go index b59fba16e7..2753a99fa6 100644 --- a/pkg/cloudid/saml/providers/awscn/factory.go +++ b/pkg/cloudid/saml/providers/awscn/factory.go @@ -15,8 +15,9 @@ package awscn import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" ) type SAWSCNSAMLDriver struct{} diff --git a/pkg/cloudid/saml/providers/azure/factory.go b/pkg/cloudid/saml/providers/azure/factory.go index 3dc3cffa58..7d854e71b8 100644 --- a/pkg/cloudid/saml/providers/azure/factory.go +++ b/pkg/cloudid/saml/providers/azure/factory.go @@ -15,8 +15,9 @@ package azure import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" ) type SAzureSAMLDriver struct{} diff --git a/pkg/cloudid/saml/providers/google/factory.go b/pkg/cloudid/saml/providers/google/factory.go index f87da34e5f..cc8e86bd0e 100644 --- a/pkg/cloudid/saml/providers/google/factory.go +++ b/pkg/cloudid/saml/providers/google/factory.go @@ -15,8 +15,9 @@ package google import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" ) type SGoogleSAMLDriver struct{} diff --git a/pkg/cloudid/saml/providers/huawei/factory.go b/pkg/cloudid/saml/providers/huawei/factory.go index b281ccb490..408066d2bb 100644 --- a/pkg/cloudid/saml/providers/huawei/factory.go +++ b/pkg/cloudid/saml/providers/huawei/factory.go @@ -15,8 +15,9 @@ package huawei import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" ) func init() { diff --git a/pkg/cloudid/saml/providers/qcloud/factory.go b/pkg/cloudid/saml/providers/qcloud/factory.go index ef456de108..81a6d108ac 100644 --- a/pkg/cloudid/saml/providers/qcloud/factory.go +++ b/pkg/cloudid/saml/providers/qcloud/factory.go @@ -15,8 +15,9 @@ package qcloud import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" ) type SQcloudSAMLDriver struct{} diff --git a/pkg/cloudid/service/service.go b/pkg/cloudid/service/service.go index 4c03d5a233..3110a441ca 100644 --- a/pkg/cloudid/service/service.go +++ b/pkg/cloudid/service/service.go @@ -18,6 +18,7 @@ import ( "os" "time" + _ "yunion.io/x/cloudmux/pkg/multicloud/loader" "yunion.io/x/log" _ "yunion.io/x/sqlchemy/backends" @@ -32,7 +33,6 @@ import ( _ "yunion.io/x/onecloud/pkg/cloudid/policy" "yunion.io/x/onecloud/pkg/cloudid/saml" _ "yunion.io/x/onecloud/pkg/cloudid/tasks" - _ "yunion.io/x/onecloud/pkg/multicloud/loader" ) func StartService() { diff --git a/pkg/cloudid/tasks/cloud_role_delete_task.go b/pkg/cloudid/tasks/cloud_role_delete_task.go index c0faa9dfba..be87513f78 100644 --- a/pkg/cloudid/tasks/cloud_role_delete_task.go +++ b/pkg/cloudid/tasks/cloud_role_delete_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/cloudid/tasks/cloudgroup_delete_task.go b/pkg/cloudid/tasks/cloudgroup_delete_task.go index b2a77658be..633166fa21 100644 --- a/pkg/cloudid/tasks/cloudgroup_delete_task.go +++ b/pkg/cloudid/tasks/cloudgroup_delete_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/cloudid/tasks/cloudgroupcache_delete_task.go b/pkg/cloudid/tasks/cloudgroupcache_delete_task.go index f8f5dfe18b..669ba5648e 100644 --- a/pkg/cloudid/tasks/cloudgroupcache_delete_task.go +++ b/pkg/cloudid/tasks/cloudgroupcache_delete_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/cloudid/tasks/clouduser_delete_task.go b/pkg/cloudid/tasks/clouduser_delete_task.go index 0b4baebf96..eea252e0be 100644 --- a/pkg/cloudid/tasks/clouduser_delete_task.go +++ b/pkg/cloudid/tasks/clouduser_delete_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/cloudid/tasks/saml_provider_create_task.go b/pkg/cloudid/tasks/saml_provider_create_task.go index 1592326306..a4483a02eb 100644 --- a/pkg/cloudid/tasks/saml_provider_create_task.go +++ b/pkg/cloudid/tasks/saml_provider_create_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/cloudid/tasks/saml_provider_delete_task.go b/pkg/cloudid/tasks/saml_provider_delete_task.go index 05e7112c8a..033e724c17 100644 --- a/pkg/cloudid/tasks/saml_provider_delete_task.go +++ b/pkg/cloudid/tasks/saml_provider_delete_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/cloudid/tasks/saml_provider_update_metadata_task.go b/pkg/cloudid/tasks/saml_provider_update_metadata_task.go index 639769db1f..a93453a3fc 100644 --- a/pkg/cloudid/tasks/saml_provider_update_metadata_task.go +++ b/pkg/cloudid/tasks/saml_provider_update_metadata_task.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/cloudid/tasks/sync_cloudid_resources_task.go b/pkg/cloudid/tasks/sync_cloudid_resources_task.go index e435da6983..1149cb7837 100644 --- a/pkg/cloudid/tasks/sync_cloudid_resources_task.go +++ b/pkg/cloudid/tasks/sync_cloudid_resources_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" ) type SyncCloudIdResourcesTask struct { diff --git a/pkg/cloudid/tasks/sync_cloudusers_task.go b/pkg/cloudid/tasks/sync_cloudusers_task.go index 774900f102..6dfdf35f29 100644 --- a/pkg/cloudid/tasks/sync_cloudusers_task.go +++ b/pkg/cloudid/tasks/sync_cloudusers_task.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -26,7 +27,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudid/models" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/cloudmon/misc/usageservice.go b/pkg/cloudmon/misc/usageservice.go index 9babdfd801..dde1da9f9b 100644 --- a/pkg/cloudmon/misc/usageservice.go +++ b/pkg/cloudmon/misc/usageservice.go @@ -101,7 +101,7 @@ func UsegReport(ctx context.Context, userCred mcclient.TokenCredential, isStart } } -//根据capabilities中的hypevisors和brands中的对应属性,组装Metric +// 根据capabilities中的hypevisors和brands中的对应属性,组装Metric func packMetricList(session *mcclient.ClientSession, dataList []influxdb.SMetricData, imageUsageFieldsDict *jsonutils.JSONDict, paramKey string, paramValue string, nowTime time.Time) (rtnList []influxdb.SMetricData, err error) { @@ -141,7 +141,7 @@ func packMetricList(session *mcclient.ClientSession, dataList []influxdb.SMetric return dataList, nil } -//获得镜像使用量 +// 获得镜像使用量 func getImageUsageFields(session *mcclient.ClientSession) (jsonutils.JSONObject, error) { respObj, e := (&image.ImageUsages).GetUsage(session, nil) if e != nil { @@ -154,7 +154,7 @@ func getImageUsageFields(session *mcclient.ClientSession) (jsonutils.JSONObject, return respDict, nil } -//将JSONDict的信息放置到SMetricData中 +// 将JSONDict的信息放置到SMetricData中 func jsonTometricData(obj *jsonutils.JSONDict, metric *influxdb.SMetricData, metricDataType string) (*influxdb.SMetricData, error) { diff --git a/pkg/cloudmon/providerdriver/base.go b/pkg/cloudmon/providerdriver/base.go index b9dcc3c6fd..0b659b2f97 100644 --- a/pkg/cloudmon/providerdriver/base.go +++ b/pkg/cloudmon/providerdriver/base.go @@ -20,13 +20,13 @@ import ( "sync" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudmon/options" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/util/influxdb" ) diff --git a/pkg/cloudmon/providerdriver/driver.go b/pkg/cloudmon/providerdriver/driver.go index fecd6925c5..b6b2df4883 100644 --- a/pkg/cloudmon/providerdriver/driver.go +++ b/pkg/cloudmon/providerdriver/driver.go @@ -19,8 +19,9 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" + api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/influxdb" ) diff --git a/pkg/cloudmon/providerdriver/huawei.go b/pkg/cloudmon/providerdriver/huawei.go index 1c9f3eff08..e3e181d920 100644 --- a/pkg/cloudmon/providerdriver/huawei.go +++ b/pkg/cloudmon/providerdriver/huawei.go @@ -20,13 +20,13 @@ import ( "sync" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudmon/options" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/util/influxdb" ) diff --git a/pkg/cloudmon/providerdriver/huaweistack.go b/pkg/cloudmon/providerdriver/huaweistack.go index 97c00855f4..0315446ea9 100644 --- a/pkg/cloudmon/providerdriver/huaweistack.go +++ b/pkg/cloudmon/providerdriver/huaweistack.go @@ -20,13 +20,13 @@ import ( "sync" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudmon/options" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/util/influxdb" ) diff --git a/pkg/cloudmon/providerdriver/qcloud.go b/pkg/cloudmon/providerdriver/qcloud.go index d63e179ada..11f3ea8e97 100644 --- a/pkg/cloudmon/providerdriver/qcloud.go +++ b/pkg/cloudmon/providerdriver/qcloud.go @@ -21,13 +21,13 @@ import ( "sync" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudmon/options" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/util/influxdb" ) diff --git a/pkg/cloudmon/resources/resources.go b/pkg/cloudmon/resources/resources.go index e49515f8e5..6a6ed1d976 100644 --- a/pkg/cloudmon/resources/resources.go +++ b/pkg/cloudmon/resources/resources.go @@ -21,6 +21,7 @@ import ( "sync" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -29,7 +30,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudmon/options" "yunion.io/x/onecloud/pkg/cloudmon/providerdriver" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modulebase" diff --git a/pkg/cloudmon/service/service.go b/pkg/cloudmon/service/service.go index acd79f82f0..4938eddcdc 100644 --- a/pkg/cloudmon/service/service.go +++ b/pkg/cloudmon/service/service.go @@ -18,6 +18,7 @@ import ( "os" "time" + _ "yunion.io/x/cloudmux/pkg/multicloud/loader" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/apis" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudmon/misc" "yunion.io/x/onecloud/pkg/cloudmon/options" "yunion.io/x/onecloud/pkg/cloudmon/resources" - _ "yunion.io/x/onecloud/pkg/multicloud/loader" ) func StartService() { diff --git a/pkg/cloudprovider/dnszone_test.go b/pkg/cloudprovider/dnszone_test.go deleted file mode 100644 index e1677a41ac..0000000000 --- a/pkg/cloudprovider/dnszone_test.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudprovider - -import ( - "testing" - - "yunion.io/x/jsonutils" -) - -func TestDiff(t *testing.T) { - cases := []struct { - Name string - Remote []DnsRecordSet - Local []DnsRecordSet - CommonCount int - AddCount int - DelCount int - UpdateCount int - }{ - { - Name: "Test delete", - CommonCount: 4, - AddCount: 0, - DelCount: 1, - UpdateCount: 0, - Remote: []DnsRecordSet{ - DnsRecordSet{ExternalId: "650124294", Enabled: true, DnsName: "@", DnsType: DnsTypeNS, DnsValue: "f1g1ns1.dnspod.net.", Ttl: 86400, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "650124301", Enabled: true, DnsName: "@", DnsType: DnsTypeNS, DnsValue: "f1g1ns2.dnspod.net.", Ttl: 86400, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "650124650", Enabled: true, DnsName: "@", DnsType: DnsTypeMX, DnsValue: "qiye163mx01.mxmail.netease.com.", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "650124659", Enabled: true, DnsName: "@", DnsType: DnsTypeMX, DnsValue: "qiye163mx02.mxmail.netease.com.", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "650124661", Enabled: true, DnsName: "mail", DnsType: DnsTypeCNAME, DnsValue: "qiye.163.com.", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - }, - Local: []DnsRecordSet{ - DnsRecordSet{Id: "d599c0e0-0653-40ed-85e1-86502a8d23d4", Enabled: true, DnsName: "mail", DnsType: DnsTypeCNAME, DnsValue: "qiye.163.com.", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Id: "5728b06e-f8cb-41eb-86e9-0e5836195ad1", Enabled: true, DnsName: "@", DnsType: DnsTypeMX, DnsValue: "qiye163mx01.mxmail.netease.com.", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Id: "427b38d2-77e2-4705-8880-0852da9cfb6b", Enabled: true, DnsName: "@", DnsType: DnsTypeNS, DnsValue: "f1g1ns1.dnspod.net.", Ttl: 86400, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Id: "0390724d-cb49-43f8-8ccd-117fef3f5034", Enabled: true, DnsName: "@", DnsType: DnsTypeNS, DnsValue: "f1g1ns2.dnspod.net.", Ttl: 86400, PolicyType: DnsPolicyTypeSimple}, - }, - }, - { - Name: "Test update", - CommonCount: 14, - AddCount: 0, - DelCount: 0, - UpdateCount: 1, - Remote: []DnsRecordSet{ - DnsRecordSet{ExternalId: "647776715", Enabled: true, DnsName: "@", Ttl: 86400, DnsType: DnsTypeNS, DnsValue: "f1g1ns1.dnspod.net.", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "647776716", Enabled: true, DnsName: "@", Ttl: 86400, DnsType: DnsTypeNS, DnsValue: "f1g1ns2.dnspod.net.", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "647850198", Enabled: true, DnsName: "abc", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.12.12.12", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "647850256", Enabled: true, DnsName: "abc", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.21.21.21", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "651667846", Enabled: false, DnsName: "ert", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.23.23.23", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "651667854", Enabled: false, DnsName: "ert2", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.23.23.23", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "651690475", Enabled: false, DnsName: "ert7", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.23.23.23", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "651667834", Enabled: true, DnsName: "example3.com", Ttl: 600, DnsType: DnsTypeA, DnsValue: "12.12.12.12", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "651694910", Enabled: true, DnsName: "example3.com", Ttl: 600, DnsType: DnsTypeA, DnsValue: "12.12.21.122", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "651694952", Enabled: true, DnsName: "sd.sd", Ttl: 600, DnsType: DnsTypeA, DnsValue: "13.34.34.34", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "651694923", Enabled: true, DnsName: "stest", Ttl: 600, DnsType: DnsTypeA, DnsValue: "234.90.8.8", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "651694918", Enabled: true, DnsName: "teset34", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.56.56.56", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "651694931", Enabled: true, DnsName: "teset66", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.56.56.56", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "651694942", Enabled: true, DnsName: "teset67", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.56.56.56", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{ExternalId: "651694960", Enabled: true, DnsName: "test", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.34.34.34", PolicyType: DnsPolicyTypeSimple}, - }, - Local: []DnsRecordSet{ - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.23.23.23", Enabled: false, Id: "1a38903e-dac8-4f75-877e-05f88f515a1f", DnsName: "ert7", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.23.23.23", Enabled: false, Id: "6e7d2c83-770c-4ecd-8c6b-4caf87fe8c23", DnsName: "ert2", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.23.23.23", Enabled: false, Id: "7fd3796a-fada-4af5-88c4-afbf36c697cd", DnsName: "ert", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeNS, DnsValue: "f1g1ns2.dnspod.net.", Enabled: true, Id: "3de80b12-851d-4418-8ffc-bd6ef90fb1f0", DnsName: "@", Ttl: 86400, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeNS, DnsValue: "f1g1ns1.dnspod.net.", Enabled: true, Id: "fc7dde12-1c96-479f-82dd-e97200b8737f", DnsName: "@", Ttl: 86400, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.56.56.56", Enabled: true, Id: "6d6ede14-01e8-49e4-8316-13b77d481b6c", DnsName: "teset34", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "13.34.34.34", Enabled: true, Id: "0e001e25-4567-4d76-8e45-ddb0012dcedf", DnsName: "sd.sd", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.56.56.56", Enabled: true, Id: "6479e99f-8031-43c7-855a-8abc1f82028c", DnsName: "teset67", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.56.56.56", Enabled: false, Id: "3b0e373f-ba22-4137-8900-d93fb2e55f12", DnsName: "teset66", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.34.34.34", Enabled: true, Id: "c9b607e5-e5ac-485f-8189-966f74914203", DnsName: "test", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.21.21.21", Enabled: true, Id: "a08cd8a6-fc7c-4de7-89b1-f962f2d9d5e5", DnsName: "abc", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "12.12.21.122", Enabled: true, Id: "251224a5-c6a1-447c-87f3-b64be34f4dd6", DnsName: "example3.com", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "12.12.12.12", Enabled: true, Id: "0ad65043-a4ca-4866-8032-56a51b018b46", DnsName: "example3.com", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "234.90.8.8", Enabled: true, Id: "f0ee44c9-12d4-40a3-84c4-ce9df25d0831", DnsName: "stest", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.12.12.12", Enabled: true, Id: "f82d1a9b-f3db-4617-8e59-4c264cecc1b6", DnsName: "abc", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - }, - }, - { - Name: "Test update", - CommonCount: 13, - AddCount: 2, - DelCount: 0, - UpdateCount: 3, - Remote: []DnsRecordSet{ - DnsRecordSet{Enabled: true, ExternalId: "647776715", DnsName: "@", Ttl: 86400, DnsType: DnsTypeNS, DnsValue: "f1g1ns1.dnspod.net.", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "647776716", DnsName: "@", Ttl: 86400, DnsType: DnsTypeNS, DnsValue: "f1g1ns2.dnspod.net.", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "647850198", DnsName: "abc", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.12.12.12", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "647850256", DnsName: "abc", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.21.21.21", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: false, ExternalId: "651667846", DnsName: "ert", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.23.23.23", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: false, ExternalId: "651667854", DnsName: "ert2", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.23.23.23", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: false, ExternalId: "651690475", DnsName: "ert7", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.23.23.23", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "652048718", DnsName: "ert8", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.23.23.23", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "652048736", DnsName: "example3.com", Ttl: 600, DnsType: DnsTypeA, DnsValue: "12.12.12.12", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "652048745", DnsName: "example3.com", Ttl: 600, DnsType: DnsTypeA, DnsValue: "12.12.21.122", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "652048753", DnsName: "sd.sd", Ttl: 600, DnsType: DnsTypeA, DnsValue: "13.34.34.34", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "652048760", DnsName: "stest", Ttl: 600, DnsType: DnsTypeA, DnsValue: "234.90.8.8", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "652048770", DnsName: "teset34", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.56.56.56", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "652048778", DnsName: "teset66", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.56.56.56", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "652048785", DnsName: "teset67", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.56.56.56", PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{Enabled: true, ExternalId: "652048789", DnsName: "test", Ttl: 600, DnsType: DnsTypeA, DnsValue: "123.34.34.34", PolicyType: DnsPolicyTypeSimple}, - }, - Local: []DnsRecordSet{ - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.23.23.23", Enabled: false, Id: "9402de3c-43e4-499d-8257-3b546abff684", DnsName: "ert10", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.23.23.23", Enabled: false, Id: "89a3d7f9-7d68-4f2f-834f-2caf787d7ff1", DnsName: "ert9", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.23.23.23", Enabled: false, Id: "5edb132b-7c67-4cc7-8b85-f32f6e22d88a", DnsName: "ert8", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.23.23.23", Enabled: false, Id: "1a38903e-dac8-4f75-877e-05f88f515a1f", DnsName: "ert7", Status: "init", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.23.23.23", Enabled: false, Id: "6e7d2c83-770c-4ecd-8c6b-4caf87fe8c23", DnsName: "ert2", Status: "init", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.23.23.23", Enabled: false, Id: "7fd3796a-fada-4af5-88c4-afbf36c697cd", DnsName: "ert", Status: "init", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeNS, DnsValue: "f1g1ns2.dnspod.net.", Enabled: true, Id: "3de80b12-851d-4418-8ffc-bd6ef90fb1f0", DnsName: "@", Status: "available", Ttl: 86400, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeNS, DnsValue: "f1g1ns1.dnspod.net.", Enabled: true, Id: "fc7dde12-1c96-479f-82dd-e97200b8737f", DnsName: "@", Status: "available", Ttl: 86400, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.56.56.56", Enabled: false, Id: "6d6ede14-01e8-49e4-8316-13b77d481b6c", DnsName: "teset34", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "13.34.34.34", Enabled: true, Id: "0e001e25-4567-4d76-8e45-ddb0012dcedf", DnsName: "sd.sd", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.56.56.56", Enabled: true, Id: "6479e99f-8031-43c7-855a-8abc1f82028c", DnsName: "teset67", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.56.56.56", Enabled: false, Id: "3b0e373f-ba22-4137-8900-d93fb2e55f12", DnsName: "teset66", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.34.34.34", Enabled: true, Id: "c9b607e5-e5ac-485f-8189-966f74914203", DnsName: "test", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.21.21.21", Enabled: true, Id: "a08cd8a6-fc7c-4de7-89b1-f962f2d9d5e5", DnsName: "abc", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "12.12.21.122", Enabled: true, Id: "251224a5-c6a1-447c-87f3-b64be34f4dd6", DnsName: "example3.com", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "12.12.12.12", Enabled: true, Id: "0ad65043-a4ca-4866-8032-56a51b018b46", DnsName: "example3.com", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "234.90.8.8", Enabled: true, Id: "f0ee44c9-12d4-40a3-84c4-ce9df25d0831", DnsName: "stest", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - DnsRecordSet{DnsType: DnsTypeA, DnsValue: "123.12.12.12", Enabled: true, Id: "f82d1a9b-f3db-4617-8e59-4c264cecc1b6", DnsName: "abc", Status: "available", Ttl: 600, PolicyType: DnsPolicyTypeSimple}, - }, - }, - } - for _, c := range cases { - iRecords := []ICloudDnsRecordSet{} - for i := range c.Remote { - iRecords = append(iRecords, &c.Remote[i]) - } - common, added, removed, updated := CompareDnsRecordSet(iRecords, c.Local, true) - if len(common) != c.CommonCount { - t.Fatalf("[%s] common should be %d current is %d", c.Name, c.CommonCount, len(common)) - } - if len(added) != c.AddCount { - t.Fatalf("[%s] added should be %d current is %d", c.Name, c.AddCount, len(added)) - } - if len(removed) != c.DelCount { - t.Fatalf("[%s] removed should be %d current is %d", c.Name, c.DelCount, len(removed)) - } - if len(updated) != c.UpdateCount { - t.Fatalf("[%s] updated should be %d current is %d", c.Name, c.UpdateCount, len(updated)) - } - t.Logf("%s update:", c.Name) - for i, update := range updated { - t.Logf("%d %s", i, jsonutils.Marshal(update)) - } - } -} - -func TestDiscreteTTlRange(t *testing.T) { - cases := []struct { - TtlInput int64 - TtlOutPut int64 - }{ - {TtlInput: 0, TtlOutPut: 5}, - {TtlInput: 86399, TtlOutPut: 86400}, - {TtlInput: 86401, TtlOutPut: 86400}, - } - for _, c := range cases { - if c.TtlOutPut != TtlRangeAliyunPvtz.GetSuppportedTTL(c.TtlInput) { - t.Fatalf("input %d GetSuppportedTTL should be %d", c.TtlInput, c.TtlOutPut) - } - } -} diff --git a/pkg/cloudprovider/doc.go b/pkg/cloudprovider/doc.go deleted file mode 100644 index 3492eb2e1e..0000000000 --- a/pkg/cloudprovider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudprovider // import "yunion.io/x/onecloud/pkg/cloudprovider" diff --git a/pkg/cloudprovider/objectstore_test.go b/pkg/cloudprovider/objectstore_test.go deleted file mode 100644 index 8d5eafed39..0000000000 --- a/pkg/cloudprovider/objectstore_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudprovider - -import "testing" - -func TestParseRange(t *testing.T) { - cases := []struct { - in string - start int64 - end int64 - }{ - { - in: "bytes=0-200", - start: 0, - end: 200, - }, - { - in: "200-3232300", - start: 200, - end: 3232300, - }, - { - in: "200-", - start: 200, - end: 0, - }, - { - in: "-232323", - start: 0, - end: 232323, - }, - } - for _, c := range cases { - got := ParseRange(c.in) - if got.Start != c.start || got.End != c.end { - t.Fatalf("got.start(%d) != want.start(%d) or got.end(%d) != want.end(%d)", got.Start, c.start, got.End, c.end) - } - } -} diff --git a/pkg/compute/guestdrivers/aliyun.go b/pkg/compute/guestdrivers/aliyun.go index 9b3877a8ca..93c7921318 100644 --- a/pkg/compute/guestdrivers/aliyun.go +++ b/pkg/compute/guestdrivers/aliyun.go @@ -18,13 +18,13 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/guestdrivers/aws.go b/pkg/compute/guestdrivers/aws.go index 15ced67af4..6d709c7528 100644 --- a/pkg/compute/guestdrivers/aws.go +++ b/pkg/compute/guestdrivers/aws.go @@ -19,6 +19,7 @@ import ( "fmt" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/osprofile" "yunion.io/x/pkg/utils" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/guestdrivers/azure.go b/pkg/compute/guestdrivers/azure.go index 8872d2e52e..c2fcc09bc1 100644 --- a/pkg/compute/guestdrivers/azure.go +++ b/pkg/compute/guestdrivers/azure.go @@ -19,12 +19,12 @@ import ( "fmt" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/guestdrivers/baremetals.go b/pkg/compute/guestdrivers/baremetals.go index afd46427b2..d9e5e034b5 100644 --- a/pkg/compute/guestdrivers/baremetals.go +++ b/pkg/compute/guestdrivers/baremetals.go @@ -21,6 +21,7 @@ import ( "regexp" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,7 +31,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/baremetal" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" diff --git a/pkg/compute/guestdrivers/base.go b/pkg/compute/guestdrivers/base.go index 4407a5df98..6824ad3a24 100644 --- a/pkg/compute/guestdrivers/base.go +++ b/pkg/compute/guestdrivers/base.go @@ -21,6 +21,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/osprofile" @@ -28,7 +29,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" guestdriver_types "yunion.io/x/onecloud/pkg/compute/guestdrivers/types" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/guestdrivers/bingocloud.go b/pkg/compute/guestdrivers/bingocloud.go index 83ffd44b87..2100f49d37 100644 --- a/pkg/compute/guestdrivers/bingocloud.go +++ b/pkg/compute/guestdrivers/bingocloud.go @@ -15,9 +15,10 @@ package guestdrivers import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/guestdrivers/cloudpods.go b/pkg/compute/guestdrivers/cloudpods.go index 796db2e9f5..50744acfe6 100644 --- a/pkg/compute/guestdrivers/cloudpods.go +++ b/pkg/compute/guestdrivers/cloudpods.go @@ -15,11 +15,11 @@ package guestdrivers import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/guestdrivers/container.go b/pkg/compute/guestdrivers/container.go index 58695b7975..2d6547e396 100644 --- a/pkg/compute/guestdrivers/container.go +++ b/pkg/compute/guestdrivers/container.go @@ -18,13 +18,13 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "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/compute/options" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/guestdrivers/ctyun.go b/pkg/compute/guestdrivers/ctyun.go index 5476b38902..b59b36d164 100644 --- a/pkg/compute/guestdrivers/ctyun.go +++ b/pkg/compute/guestdrivers/ctyun.go @@ -17,11 +17,11 @@ package guestdrivers import ( "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/guestdrivers/ecloud.go b/pkg/compute/guestdrivers/ecloud.go index ce611e3e8e..92def4ce68 100644 --- a/pkg/compute/guestdrivers/ecloud.go +++ b/pkg/compute/guestdrivers/ecloud.go @@ -15,11 +15,11 @@ package guestdrivers import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/guestdrivers/esxi.go b/pkg/compute/guestdrivers/esxi.go index 62a585f3a5..78bcd05b35 100644 --- a/pkg/compute/guestdrivers/esxi.go +++ b/pkg/compute/guestdrivers/esxi.go @@ -20,6 +20,8 @@ import ( "sort" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/esxi" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,12 +32,10 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "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/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/esxi" "yunion.io/x/onecloud/pkg/util/billing" "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/guestdrivers/google.go b/pkg/compute/guestdrivers/google.go index 6ddfcd55da..1ae4051190 100644 --- a/pkg/compute/guestdrivers/google.go +++ b/pkg/compute/guestdrivers/google.go @@ -20,6 +20,8 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/google" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -29,11 +31,9 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "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/httperrors" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/google" "yunion.io/x/onecloud/pkg/util/billing" "yunion.io/x/onecloud/pkg/util/rbacutils" ) diff --git a/pkg/compute/guestdrivers/hcs.go b/pkg/compute/guestdrivers/hcs.go index 0f1216029f..ebeede7c4e 100644 --- a/pkg/compute/guestdrivers/hcs.go +++ b/pkg/compute/guestdrivers/hcs.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" @@ -27,7 +28,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/billing" diff --git a/pkg/compute/guestdrivers/huawei.go b/pkg/compute/guestdrivers/huawei.go index feb8fb72ea..d50192e1b3 100644 --- a/pkg/compute/guestdrivers/huawei.go +++ b/pkg/compute/guestdrivers/huawei.go @@ -17,11 +17,11 @@ package guestdrivers import ( "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/billing" diff --git a/pkg/compute/guestdrivers/huaweistack.go b/pkg/compute/guestdrivers/huaweistack.go index b729a61c83..efda0dd7cf 100644 --- a/pkg/compute/guestdrivers/huaweistack.go +++ b/pkg/compute/guestdrivers/huaweistack.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" @@ -27,7 +28,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/billing" diff --git a/pkg/compute/guestdrivers/incloudsphere.go b/pkg/compute/guestdrivers/incloudsphere.go index 285ded613d..ea57a35cd2 100644 --- a/pkg/compute/guestdrivers/incloudsphere.go +++ b/pkg/compute/guestdrivers/incloudsphere.go @@ -18,12 +18,12 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "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/compute/options" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/guestdrivers/jdcloud.go b/pkg/compute/guestdrivers/jdcloud.go index cbd28c5df6..3f3e2e6526 100644 --- a/pkg/compute/guestdrivers/jdcloud.go +++ b/pkg/compute/guestdrivers/jdcloud.go @@ -15,9 +15,10 @@ package guestdrivers import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/billing" diff --git a/pkg/compute/guestdrivers/kvm.go b/pkg/compute/guestdrivers/kvm.go index 339275c9ea..e700961e20 100644 --- a/pkg/compute/guestdrivers/kvm.go +++ b/pkg/compute/guestdrivers/kvm.go @@ -21,6 +21,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -34,7 +35,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" guestdriver_types "yunion.io/x/onecloud/pkg/compute/guestdrivers/types" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" diff --git a/pkg/compute/guestdrivers/managedvirtual.go b/pkg/compute/guestdrivers/managedvirtual.go index 3befe5cb70..d56372daf8 100644 --- a/pkg/compute/guestdrivers/managedvirtual.go +++ b/pkg/compute/guestdrivers/managedvirtual.go @@ -20,6 +20,7 @@ import ( "math" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "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/compute/options" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/guestdrivers/nutanix.go b/pkg/compute/guestdrivers/nutanix.go index cbc8777bc3..e78f8adc47 100644 --- a/pkg/compute/guestdrivers/nutanix.go +++ b/pkg/compute/guestdrivers/nutanix.go @@ -19,12 +19,12 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "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/compute/options" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/guestdrivers/openstack.go b/pkg/compute/guestdrivers/openstack.go index 6bd648261b..02aaaa9c1a 100644 --- a/pkg/compute/guestdrivers/openstack.go +++ b/pkg/compute/guestdrivers/openstack.go @@ -19,6 +19,7 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,7 +31,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "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/compute/options" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/guestdrivers/proxmox.go b/pkg/compute/guestdrivers/proxmox.go index 3ef27691f3..aabdea6f1a 100644 --- a/pkg/compute/guestdrivers/proxmox.go +++ b/pkg/compute/guestdrivers/proxmox.go @@ -17,10 +17,11 @@ package guestdrivers import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "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/compute/options" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/guestdrivers/qcloud.go b/pkg/compute/guestdrivers/qcloud.go index 504e67be82..e9c5565321 100644 --- a/pkg/compute/guestdrivers/qcloud.go +++ b/pkg/compute/guestdrivers/qcloud.go @@ -19,12 +19,12 @@ import ( "fmt" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/util/osprofile" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/guestdrivers/remotefile.go b/pkg/compute/guestdrivers/remotefile.go index 3b48a48f79..cac60616d6 100644 --- a/pkg/compute/guestdrivers/remotefile.go +++ b/pkg/compute/guestdrivers/remotefile.go @@ -15,9 +15,10 @@ package guestdrivers import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" + api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/guestdrivers/ucloud.go b/pkg/compute/guestdrivers/ucloud.go index 10361423e2..e5420ad038 100644 --- a/pkg/compute/guestdrivers/ucloud.go +++ b/pkg/compute/guestdrivers/ucloud.go @@ -17,11 +17,11 @@ package guestdrivers import ( "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/guestdrivers/utils.go b/pkg/compute/guestdrivers/utils.go index 7a64e9d285..96e0f1bd2d 100644 --- a/pkg/compute/guestdrivers/utils.go +++ b/pkg/compute/guestdrivers/utils.go @@ -17,13 +17,13 @@ package guestdrivers import ( "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/utils" billing_api "yunion.io/x/onecloud/pkg/apis/billing" "yunion.io/x/onecloud/pkg/cloudcommon/db" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/seclib2" ) diff --git a/pkg/compute/guestdrivers/zstack.go b/pkg/compute/guestdrivers/zstack.go index d45ccc942a..ef84df0420 100644 --- a/pkg/compute/guestdrivers/zstack.go +++ b/pkg/compute/guestdrivers/zstack.go @@ -18,11 +18,11 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/hostdrivers/esxi.go b/pkg/compute/hostdrivers/esxi.go index d46d7906c3..edc1890503 100644 --- a/pkg/compute/hostdrivers/esxi.go +++ b/pkg/compute/hostdrivers/esxi.go @@ -18,16 +18,16 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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" - "yunion.io/x/onecloud/pkg/multicloud/esxi/vcenter" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/pkg/compute/hostdrivers/kvm.go b/pkg/compute/hostdrivers/kvm.go index 3fc3eac4ae..f37daf51d5 100644 --- a/pkg/compute/hostdrivers/kvm.go +++ b/pkg/compute/hostdrivers/kvm.go @@ -23,6 +23,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/cmdline" "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/baremetal" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" diff --git a/pkg/compute/hostdrivers/managedvirtual.go b/pkg/compute/hostdrivers/managedvirtual.go index 33fac8709f..703a04cc00 100644 --- a/pkg/compute/hostdrivers/managedvirtual.go +++ b/pkg/compute/hostdrivers/managedvirtual.go @@ -22,6 +22,7 @@ import ( "github.com/pkg/errors" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/utils" @@ -30,7 +31,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "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/compute/options" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/models/access_group_caches.go b/pkg/compute/models/access_group_caches.go index e7fdcb1410..7872d9b7e3 100644 --- a/pkg/compute/models/access_group_caches.go +++ b/pkg/compute/models/access_group_caches.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/access_group_rules.go b/pkg/compute/models/access_group_rules.go index fa82ebccc8..f8fe81c66a 100644 --- a/pkg/compute/models/access_group_rules.go +++ b/pkg/compute/models/access_group_rules.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/compute/models/access_groups.go b/pkg/compute/models/access_groups.go index e57c9ebef2..9ee87a71f3 100644 --- a/pkg/compute/models/access_groups.go +++ b/pkg/compute/models/access_groups.go @@ -19,6 +19,7 @@ import ( "database/sql" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -29,7 +30,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" diff --git a/pkg/compute/models/app.go b/pkg/compute/models/app.go index 8af020bb48..64e641bd65 100644 --- a/pkg/compute/models/app.go +++ b/pkg/compute/models/app.go @@ -19,6 +19,7 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/app_environment.go b/pkg/compute/models/app_environment.go index 439dfb6d6b..71e69d476e 100644 --- a/pkg/compute/models/app_environment.go +++ b/pkg/compute/models/app_environment.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -25,7 +26,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" ) diff --git a/pkg/compute/models/buckets.go b/pkg/compute/models/buckets.go index 3706913626..dd2d969e7c 100644 --- a/pkg/compute/models/buckets.go +++ b/pkg/compute/models/buckets.go @@ -25,6 +25,7 @@ import ( "github.com/minio/minio-go/pkg/s3utils" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -40,7 +41,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/cachedimages.go b/pkg/compute/models/cachedimages.go index 4cea14735d..bd7227e3dd 100644 --- a/pkg/compute/models/cachedimages.go +++ b/pkg/compute/models/cachedimages.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "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/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/capabilities.go b/pkg/compute/models/capabilities.go index 998d5e12fa..1c4321e914 100644 --- a/pkg/compute/models/capabilities.go +++ b/pkg/compute/models/capabilities.go @@ -20,6 +20,7 @@ import ( "fmt" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/tristate" @@ -30,7 +31,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/policy" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/cdn_domains.go b/pkg/compute/models/cdn_domains.go index 8b9db71fe5..85dbd9d311 100644 --- a/pkg/compute/models/cdn_domains.go +++ b/pkg/compute/models/cdn_domains.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/cloudaccounts.go b/pkg/compute/models/cloudaccounts.go index ca2ec84dc1..9b96ace568 100644 --- a/pkg/compute/models/cloudaccounts.go +++ b/pkg/compute/models/cloudaccounts.go @@ -24,6 +24,8 @@ import ( "sync" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -42,12 +44,10 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" - "yunion.io/x/onecloud/pkg/multicloud/esxi/vcenter" "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/cloudaccounts_prepare.go b/pkg/compute/models/cloudaccounts_prepare.go index 0a0d3575d1..c55ffbc43d 100644 --- a/pkg/compute/models/cloudaccounts_prepare.go +++ b/pkg/compute/models/cloudaccounts_prepare.go @@ -19,6 +19,8 @@ import ( "fmt" "sort" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/esxi" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/netutils" @@ -28,11 +30,9 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/proxy" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/esxi" "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/rbacutils" ) diff --git a/pkg/compute/models/cloudaccounts_test.go b/pkg/compute/models/cloudaccounts_test.go index 5625697147..598dff2f91 100644 --- a/pkg/compute/models/cloudaccounts_test.go +++ b/pkg/compute/models/cloudaccounts_test.go @@ -20,10 +20,9 @@ import ( "sort" "testing" + "yunion.io/x/cloudmux/pkg/multicloud/esxi" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/netutils" - - "yunion.io/x/onecloud/pkg/multicloud/esxi" ) func TestParseAndSuggest(t *testing.T) { diff --git a/pkg/compute/models/cloudprovider_quotas.go b/pkg/compute/models/cloudprovider_quotas.go index 162f73fea6..8cf7370c1a 100644 --- a/pkg/compute/models/cloudprovider_quotas.go +++ b/pkg/compute/models/cloudprovider_quotas.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index d74e8b4de7..b73a3cdf53 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -22,6 +22,7 @@ import ( "sync" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -38,7 +39,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/proxy" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/cloudregionresource.go b/pkg/compute/models/cloudregionresource.go index 495f84e38a..1c7f009ff0 100644 --- a/pkg/compute/models/cloudregionresource.go +++ b/pkg/compute/models/cloudregionresource.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/cloudregions.go b/pkg/compute/models/cloudregions.go index 916a3c7940..7e95e54d87 100644 --- a/pkg/compute/models/cloudregions.go +++ b/pkg/compute/models/cloudregions.go @@ -20,6 +20,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/cloudsync.go b/pkg/compute/models/cloudsync.go index 640fa3e4fd..3ed6b7a993 100644 --- a/pkg/compute/models/cloudsync.go +++ b/pkg/compute/models/cloudsync.go @@ -19,6 +19,7 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -28,7 +29,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules/scheduler" diff --git a/pkg/compute/models/cloudsyncelasticcache.go b/pkg/compute/models/cloudsyncelasticcache.go index 5e70596576..0861da9f59 100644 --- a/pkg/compute/models/cloudsyncelasticcache.go +++ b/pkg/compute/models/cloudsyncelasticcache.go @@ -20,12 +20,12 @@ import ( "github.com/pkg/errors" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/util/compare" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/cloudsyncelb.go b/pkg/compute/models/cloudsyncelb.go index 250f64b257..4108355c87 100644 --- a/pkg/compute/models/cloudsyncelb.go +++ b/pkg/compute/models/cloudsyncelb.go @@ -18,12 +18,12 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/util/compare" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/dbinstance_accounts.go b/pkg/compute/models/dbinstance_accounts.go index 4dd4015c27..ee9c719c78 100644 --- a/pkg/compute/models/dbinstance_accounts.go +++ b/pkg/compute/models/dbinstance_accounts.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,7 +31,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/dbinstance_backups.go b/pkg/compute/models/dbinstance_backups.go index 26aeecdf81..5d752f3af6 100644 --- a/pkg/compute/models/dbinstance_backups.go +++ b/pkg/compute/models/dbinstance_backups.go @@ -21,6 +21,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/dbinstance_databases.go b/pkg/compute/models/dbinstance_databases.go index 656ca2b173..4bbf1ae34c 100644 --- a/pkg/compute/models/dbinstance_databases.go +++ b/pkg/compute/models/dbinstance_databases.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/dbinstance_parameters.go b/pkg/compute/models/dbinstance_parameters.go index e05bd6c649..45c7878d7d 100644 --- a/pkg/compute/models/dbinstance_parameters.go +++ b/pkg/compute/models/dbinstance_parameters.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/dbinstance_privileges.go b/pkg/compute/models/dbinstance_privileges.go index 4260a8f7bb..4d1fa0172e 100644 --- a/pkg/compute/models/dbinstance_privileges.go +++ b/pkg/compute/models/dbinstance_privileges.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -26,7 +27,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/dbinstance_skus.go b/pkg/compute/models/dbinstance_skus.go index 8bab735bf8..cacc0b0d08 100644 --- a/pkg/compute/models/dbinstance_skus.go +++ b/pkg/compute/models/dbinstance_skus.go @@ -20,6 +20,7 @@ import ( "fmt" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/dbinstancenetworks.go b/pkg/compute/models/dbinstancenetworks.go index 1df2372792..2f86d62b41 100644 --- a/pkg/compute/models/dbinstancenetworks.go +++ b/pkg/compute/models/dbinstancenetworks.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/dbinstances.go b/pkg/compute/models/dbinstances.go index 653b69d76a..23510aeff6 100644 --- a/pkg/compute/models/dbinstances.go +++ b/pkg/compute/models/dbinstances.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -41,7 +42,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index 07de46887d..f48e264d7d 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -23,6 +23,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -42,7 +43,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/dns_recordsets.go b/pkg/compute/models/dns_recordsets.go index 974b5bbb6d..2ba952317c 100644 --- a/pkg/compute/models/dns_recordsets.go +++ b/pkg/compute/models/dns_recordsets.go @@ -21,6 +21,7 @@ import ( "regexp" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/tristate" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/compute/models/dns_trafficpolicy.go b/pkg/compute/models/dns_trafficpolicy.go index 697153ef3e..0063d07253 100644 --- a/pkg/compute/models/dns_trafficpolicy.go +++ b/pkg/compute/models/dns_trafficpolicy.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/dns_zonecaches.go b/pkg/compute/models/dns_zonecaches.go index e12ecb08cc..5795b641f2 100644 --- a/pkg/compute/models/dns_zonecaches.go +++ b/pkg/compute/models/dns_zonecaches.go @@ -21,6 +21,7 @@ import ( "gopkg.in/fatih/set.v0" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/dns_zones.go b/pkg/compute/models/dns_zones.go index 63c3d6a524..c66766c547 100644 --- a/pkg/compute/models/dns_zones.go +++ b/pkg/compute/models/dns_zones.go @@ -21,6 +21,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -37,7 +38,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/policy" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/dynamicschedtags.go b/pkg/compute/models/dynamicschedtags.go index 019661b4d2..75b60140ef 100644 --- a/pkg/compute/models/dynamicschedtags.go +++ b/pkg/compute/models/dynamicschedtags.go @@ -97,8 +97,8 @@ func (man *SDynamicschedtagManager) InitializeData() error { // dynamic schedtag is called before scan host candidates, dynamically adding additional schedtag to hosts // condition examples: -// host.sys_load > 1.5 || host.mem_used_percent > 0.7 => "high_load" // +// host.sys_load > 1.5 || host.mem_used_percent > 0.7 => "high_load" type SDynamicschedtag struct { db.SStandaloneResourceBase SSchedtagResourceBase `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required" update:"admin"` diff --git a/pkg/compute/models/elastic_search.go b/pkg/compute/models/elastic_search.go index 6b42797981..8e40d22bbe 100644 --- a/pkg/compute/models/elastic_search.go +++ b/pkg/compute/models/elastic_search.go @@ -20,6 +20,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/elasticcache_accounts.go b/pkg/compute/models/elasticcache_accounts.go index 9a11593706..b2c411328b 100644 --- a/pkg/compute/models/elasticcache_accounts.go +++ b/pkg/compute/models/elasticcache_accounts.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/choices" diff --git a/pkg/compute/models/elasticcache_acls.go b/pkg/compute/models/elasticcache_acls.go index ef0eced1fc..e5f03272e3 100644 --- a/pkg/compute/models/elasticcache_acls.go +++ b/pkg/compute/models/elasticcache_acls.go @@ -19,6 +19,7 @@ import ( "fmt" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/elasticcache_backups.go b/pkg/compute/models/elasticcache_backups.go index 09f9dcddae..067cc29205 100644 --- a/pkg/compute/models/elasticcache_backups.go +++ b/pkg/compute/models/elasticcache_backups.go @@ -19,6 +19,7 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,7 +31,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/elasticcache_instances.go b/pkg/compute/models/elasticcache_instances.go index 3189baa588..b3b2a16b84 100644 --- a/pkg/compute/models/elasticcache_instances.go +++ b/pkg/compute/models/elasticcache_instances.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -41,7 +42,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/elasticcache_parameters.go b/pkg/compute/models/elasticcache_parameters.go index 6105fde1ab..37c89b8102 100644 --- a/pkg/compute/models/elasticcache_parameters.go +++ b/pkg/compute/models/elasticcache_parameters.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/elasticcache_skus.go b/pkg/compute/models/elasticcache_skus.go index 189a7f9229..57676c5f91 100644 --- a/pkg/compute/models/elasticcache_skus.go +++ b/pkg/compute/models/elasticcache_skus.go @@ -19,6 +19,7 @@ import ( "database/sql" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/elasticcacheresource.go b/pkg/compute/models/elasticcacheresource.go index 9c0d5c20a9..8a683784be 100644 --- a/pkg/compute/models/elasticcacheresource.go +++ b/pkg/compute/models/elasticcacheresource.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/elasticips.go b/pkg/compute/models/elasticips.go index 5312c11769..b1e3e79356 100644 --- a/pkg/compute/models/elasticips.go +++ b/pkg/compute/models/elasticips.go @@ -20,6 +20,7 @@ import ( "fmt" "sort" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -38,7 +39,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/pinyinutils" diff --git a/pkg/compute/models/external_projects.go b/pkg/compute/models/external_projects.go index b889f91fc8..ae6ea0b66f 100644 --- a/pkg/compute/models/external_projects.go +++ b/pkg/compute/models/external_projects.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/filesystem.go b/pkg/compute/models/filesystem.go index 1e2032869c..5a3fee5781 100644 --- a/pkg/compute/models/filesystem.go +++ b/pkg/compute/models/filesystem.go @@ -19,6 +19,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -33,7 +34,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/globalvpcs.go b/pkg/compute/models/globalvpcs.go index 04f9a029e2..8f82053f08 100644 --- a/pkg/compute/models/globalvpcs.go +++ b/pkg/compute/models/globalvpcs.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/guest_actions.go b/pkg/compute/models/guest_actions.go index b6c0faf71a..c396453103 100644 --- a/pkg/compute/models/guest_actions.go +++ b/pkg/compute/models/guest_actions.go @@ -27,6 +27,7 @@ import ( "gopkg.in/fatih/set.v0" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -54,7 +55,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/userdata" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" guestdriver_types "yunion.io/x/onecloud/pkg/compute/guestdrivers/types" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/models/guest_queries.go b/pkg/compute/models/guest_queries.go index e32089e824..7774cf1d11 100644 --- a/pkg/compute/models/guest_queries.go +++ b/pkg/compute/models/guest_queries.go @@ -19,6 +19,7 @@ import ( "database/sql" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" ) diff --git a/pkg/compute/models/guestdrivers.go b/pkg/compute/models/guestdrivers.go index da4c806afd..616e07b121 100644 --- a/pkg/compute/models/guestdrivers.go +++ b/pkg/compute/models/guestdrivers.go @@ -19,12 +19,12 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" guestdriver_types "yunion.io/x/onecloud/pkg/compute/guestdrivers/types" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/billing" diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 6f24a623df..1661c2a9a9 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -23,6 +23,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -50,7 +51,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/userdata" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/compute/sshkeys" devtool_utils "yunion.io/x/onecloud/pkg/devtool/utils" diff --git a/pkg/compute/models/host_recycle.go b/pkg/compute/models/host_recycle.go index c70c2e0e51..0e689d8682 100644 --- a/pkg/compute/models/host_recycle.go +++ b/pkg/compute/models/host_recycle.go @@ -21,6 +21,7 @@ import ( "github.com/golang-plus/errors" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/tristate" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/baremetal" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/hosts.go b/pkg/compute/models/hosts.go index fed0b0659a..855a48e067 100644 --- a/pkg/compute/models/hosts.go +++ b/pkg/compute/models/hosts.go @@ -28,6 +28,8 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/esxi" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -52,14 +54,12 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/types" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/baremetal" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" "yunion.io/x/onecloud/pkg/mcclient/modules/scheduler" - "yunion.io/x/onecloud/pkg/multicloud/esxi" "yunion.io/x/onecloud/pkg/util/cgrouputils/cpuset" "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/k8s/tokens" diff --git a/pkg/compute/models/hoststorages.go b/pkg/compute/models/hoststorages.go index 7a6ceab7bb..de84d8fbd1 100644 --- a/pkg/compute/models/hoststorages.go +++ b/pkg/compute/models/hoststorages.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/i18nresource.go b/pkg/compute/models/i18nresource.go index 4810d1991c..33bc128f8f 100644 --- a/pkg/compute/models/i18nresource.go +++ b/pkg/compute/models/i18nresource.go @@ -17,12 +17,12 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/cloudcommon/db" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/instance_snapshots.go b/pkg/compute/models/instance_snapshots.go index 0f0c53f895..225f9e47e8 100644 --- a/pkg/compute/models/instance_snapshots.go +++ b/pkg/compute/models/instance_snapshots.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,7 +31,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/inter_vpc_network.go b/pkg/compute/models/inter_vpc_network.go index a8342b48e3..7795c9ae5f 100644 --- a/pkg/compute/models/inter_vpc_network.go +++ b/pkg/compute/models/inter_vpc_network.go @@ -21,6 +21,7 @@ import ( "gopkg.in/fatih/set.v0" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/tristate" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/inter_vpc_network_routeset.go b/pkg/compute/models/inter_vpc_network_routeset.go index d06621aaf9..c7033944cb 100644 --- a/pkg/compute/models/inter_vpc_network_routeset.go +++ b/pkg/compute/models/inter_vpc_network_routeset.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/tristate" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/ipv6_gateways.go b/pkg/compute/models/ipv6_gateways.go index 4f4183959a..8767619455 100644 --- a/pkg/compute/models/ipv6_gateways.go +++ b/pkg/compute/models/ipv6_gateways.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -28,7 +29,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/policy" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/kafka.go b/pkg/compute/models/kafka.go index bc7cef1c71..0724b0e6ea 100644 --- a/pkg/compute/models/kafka.go +++ b/pkg/compute/models/kafka.go @@ -20,6 +20,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" @@ -630,7 +630,7 @@ func (manager *SKafkaManager) ListItemExportKeys(ctx context.Context, return q, nil } -//同步Kafka实例状态 +// 同步Kafka实例状态 func (self *SKafka) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) { var openTask = true count, err := taskman.TaskManager.QueryTasksOfObject(self, time.Now().Add(-3*time.Minute), &openTask).CountWithError() diff --git a/pkg/compute/models/kube_clusters.go b/pkg/compute/models/kube_clusters.go index 374804c1be..b3c34f75e2 100644 --- a/pkg/compute/models/kube_clusters.go +++ b/pkg/compute/models/kube_clusters.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/tristate" @@ -30,7 +31,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/kube_node_pools.go b/pkg/compute/models/kube_node_pools.go index 762326c336..9e16563201 100644 --- a/pkg/compute/models/kube_node_pools.go +++ b/pkg/compute/models/kube_node_pools.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/kube_nodes.go b/pkg/compute/models/kube_nodes.go index ca046cecd7..8a974186c6 100644 --- a/pkg/compute/models/kube_nodes.go +++ b/pkg/compute/models/kube_nodes.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/loadbalanceracls.go b/pkg/compute/models/loadbalanceracls.go index 7dd20f89f3..59740f4575 100644 --- a/pkg/compute/models/loadbalanceracls.go +++ b/pkg/compute/models/loadbalanceracls.go @@ -24,6 +24,7 @@ import ( "strings" "unicode" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -38,7 +39,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/loadbalanceragents.go b/pkg/compute/models/loadbalanceragents.go index e6244a8ae8..1461426385 100644 --- a/pkg/compute/models/loadbalanceragents.go +++ b/pkg/compute/models/loadbalanceragents.go @@ -66,9 +66,8 @@ func init() { // TODO // -// - scrub stale backends: Guests with deleted=1 -// - agent configuration params -// +// - scrub stale backends: Guests with deleted=1 +// - agent configuration params type SLoadbalancerAgent struct { db.SStandaloneResourceBase SLoadbalancerClusterResourceBase `width:"36" charset:"ascii" nullable:"false" list:"user" create:"required"` diff --git a/pkg/compute/models/loadbalancerawscachedlbb.go b/pkg/compute/models/loadbalancerawscachedlbb.go index 55d790d19f..b55f2258bf 100644 --- a/pkg/compute/models/loadbalancerawscachedlbb.go +++ b/pkg/compute/models/loadbalancerawscachedlbb.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" "yunion.io/x/sqlchemy" @@ -25,7 +26,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/loadbalancerawscachedlbbg.go b/pkg/compute/models/loadbalancerawscachedlbbg.go index c522590ddc..3dd6d4ad28 100644 --- a/pkg/compute/models/loadbalancerawscachedlbbg.go +++ b/pkg/compute/models/loadbalancerawscachedlbbg.go @@ -21,6 +21,7 @@ import ( "strconv" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -30,7 +31,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/loadbalancerbackendgroups.go b/pkg/compute/models/loadbalancerbackendgroups.go index cbda0b1136..e25c683839 100644 --- a/pkg/compute/models/loadbalancerbackendgroups.go +++ b/pkg/compute/models/loadbalancerbackendgroups.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -33,7 +34,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rand" diff --git a/pkg/compute/models/loadbalancerbackends.go b/pkg/compute/models/loadbalancerbackends.go index 3e1ca7c144..0528055b60 100644 --- a/pkg/compute/models/loadbalancerbackends.go +++ b/pkg/compute/models/loadbalancerbackends.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/loadbalancercachedacls.go b/pkg/compute/models/loadbalancercachedacls.go index 405ed64987..a63158f25d 100644 --- a/pkg/compute/models/loadbalancercachedacls.go +++ b/pkg/compute/models/loadbalancercachedacls.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/loadbalancercachedcertificates.go b/pkg/compute/models/loadbalancercachedcertificates.go index c45ab999ce..0a909f9d04 100644 --- a/pkg/compute/models/loadbalancercachedcertificates.go +++ b/pkg/compute/models/loadbalancercachedcertificates.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/loadbalancercertificates.go b/pkg/compute/models/loadbalancercertificates.go index fcd11846d0..3ab4fa7021 100644 --- a/pkg/compute/models/loadbalancercertificates.go +++ b/pkg/compute/models/loadbalancercertificates.go @@ -23,6 +23,7 @@ import ( "encoding/pem" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -34,7 +35,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" @@ -63,8 +63,8 @@ func init() { // TODO // -// - notify users of cert expiration -// - ca info: self-signed, public ca +// - notify users of cert expiration +// - ca info: self-signed, public ca type SLoadbalancerCertificate struct { db.SSharableVirtualResourceBase db.SExternalizedResourceBase diff --git a/pkg/compute/models/loadbalancerhuaweicachedlbb.go b/pkg/compute/models/loadbalancerhuaweicachedlbb.go index c90ffbd79c..32088e6ba5 100644 --- a/pkg/compute/models/loadbalancerhuaweicachedlbb.go +++ b/pkg/compute/models/loadbalancerhuaweicachedlbb.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -27,7 +28,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/loadbalancerhuaweicachedlbbg.go b/pkg/compute/models/loadbalancerhuaweicachedlbbg.go index ea36fae51c..a060d862e5 100644 --- a/pkg/compute/models/loadbalancerhuaweicachedlbbg.go +++ b/pkg/compute/models/loadbalancerhuaweicachedlbbg.go @@ -20,6 +20,7 @@ import ( "strconv" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -28,7 +29,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/loadbalancerlistenerrules.go b/pkg/compute/models/loadbalancerlistenerrules.go index b6f82a3a33..c1144dcbaa 100644 --- a/pkg/compute/models/loadbalancerlistenerrules.go +++ b/pkg/compute/models/loadbalancerlistenerrules.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/loadbalancerlisteners.go b/pkg/compute/models/loadbalancerlisteners.go index 33d196a2aa..9262ff32d0 100644 --- a/pkg/compute/models/loadbalancerlisteners.go +++ b/pkg/compute/models/loadbalancerlisteners.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -33,7 +34,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" @@ -114,10 +114,10 @@ type SLoadbalancerHTTPRedirect struct { // TODO // -// - CACertificate string -// - Certificate2Id // multiple certificates for rsa, ecdsa -// - Use certificate for tcp listener -// - Customize ciphers? +// - CACertificate string +// - Certificate2Id // multiple certificates for rsa, ecdsa +// - Use certificate for tcp listener +// - Customize ciphers? type SLoadbalancerHTTPSListener struct { SLoadbalancerCertificateResourceBase diff --git a/pkg/compute/models/loadbalanceropenstackcachedlbb.go b/pkg/compute/models/loadbalanceropenstackcachedlbb.go index 2cb8c8dd8f..32c675d34a 100644 --- a/pkg/compute/models/loadbalanceropenstackcachedlbb.go +++ b/pkg/compute/models/loadbalanceropenstackcachedlbb.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" "yunion.io/x/sqlchemy" @@ -24,7 +25,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/loadbalanceropenstackcachedlbbg.go b/pkg/compute/models/loadbalanceropenstackcachedlbbg.go index 73a5a0a22b..fcd91bcdef 100644 --- a/pkg/compute/models/loadbalanceropenstackcachedlbbg.go +++ b/pkg/compute/models/loadbalanceropenstackcachedlbbg.go @@ -20,6 +20,7 @@ import ( "strconv" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -28,7 +29,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/loadbalancerqcloudcachedlbb.go b/pkg/compute/models/loadbalancerqcloudcachedlbb.go index a69837ae11..e94176c8dc 100644 --- a/pkg/compute/models/loadbalancerqcloudcachedlbb.go +++ b/pkg/compute/models/loadbalancerqcloudcachedlbb.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/loadbalancerqcloudcachedlbbg.go b/pkg/compute/models/loadbalancerqcloudcachedlbbg.go index 45f1ca07c8..ac4f24cdfd 100644 --- a/pkg/compute/models/loadbalancerqcloudcachedlbbg.go +++ b/pkg/compute/models/loadbalancerqcloudcachedlbbg.go @@ -20,6 +20,7 @@ import ( "strconv" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -29,7 +30,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/loadbalancers.go b/pkg/compute/models/loadbalancers.go index 76fa601779..f12ec39063 100644 --- a/pkg/compute/models/loadbalancers.go +++ b/pkg/compute/models/loadbalancers.go @@ -21,6 +21,7 @@ import ( "net" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -37,7 +38,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/managedresource.go b/pkg/compute/models/managedresource.go index 69477001bf..ff9af973ab 100644 --- a/pkg/compute/models/managedresource.go +++ b/pkg/compute/models/managedresource.go @@ -19,6 +19,7 @@ import ( "database/sql" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,7 +31,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/appctx" "yunion.io/x/onecloud/pkg/cloudcommon/db" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/miscresources.go b/pkg/compute/models/miscresources.go index ae4eeb455d..07a307ef9c 100644 --- a/pkg/compute/models/miscresources.go +++ b/pkg/compute/models/miscresources.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -27,7 +28,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/modelarts_pool_sku.go b/pkg/compute/models/modelarts_pool_sku.go index 1f5379c499..57937a8932 100644 --- a/pkg/compute/models/modelarts_pool_sku.go +++ b/pkg/compute/models/modelarts_pool_sku.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/modelarts_pools.go b/pkg/compute/models/modelarts_pools.go index d0df88e1b8..267c3fb2a3 100644 --- a/pkg/compute/models/modelarts_pools.go +++ b/pkg/compute/models/modelarts_pools.go @@ -19,6 +19,7 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -30,7 +31,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/mongodb.go b/pkg/compute/models/mongodb.go index 7a1d4abe3a..b913c17b75 100644 --- a/pkg/compute/models/mongodb.go +++ b/pkg/compute/models/mongodb.go @@ -19,6 +19,7 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -33,7 +34,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/billing" diff --git a/pkg/compute/models/mount_targets.go b/pkg/compute/models/mount_targets.go index 1cb33145ee..acd3462819 100644 --- a/pkg/compute/models/mount_targets.go +++ b/pkg/compute/models/mount_targets.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,7 +31,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/nat_skus.go b/pkg/compute/models/nat_skus.go index 951972224d..b396893261 100644 --- a/pkg/compute/models/nat_skus.go +++ b/pkg/compute/models/nat_skus.go @@ -20,6 +20,7 @@ import ( "fmt" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,7 +31,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/natdtable.go b/pkg/compute/models/natdtable.go index 06080461bd..a7eb1b3a18 100644 --- a/pkg/compute/models/natdtable.go +++ b/pkg/compute/models/natdtable.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -28,7 +29,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/natgateways.go b/pkg/compute/models/natgateways.go index c6e95ca269..c97d9280f3 100644 --- a/pkg/compute/models/natgateways.go +++ b/pkg/compute/models/natgateways.go @@ -19,6 +19,7 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -34,7 +35,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/natstable.go b/pkg/compute/models/natstable.go index 168f075a32..9fa5c8e0f0 100644 --- a/pkg/compute/models/natstable.go +++ b/pkg/compute/models/natstable.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -28,7 +29,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/networkaddresses.go b/pkg/compute/models/networkaddresses.go index 39a98a14b3..edaa55c2e9 100644 --- a/pkg/compute/models/networkaddresses.go +++ b/pkg/compute/models/networkaddresses.go @@ -21,6 +21,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,7 +31,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/networkinterfacenetwork.go b/pkg/compute/models/networkinterfacenetwork.go index 52a95b76aa..70b4cef6b6 100644 --- a/pkg/compute/models/networkinterfacenetwork.go +++ b/pkg/compute/models/networkinterfacenetwork.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/networkinterfaces.go b/pkg/compute/models/networkinterfaces.go index 294635af4c..45e928eb72 100644 --- a/pkg/compute/models/networkinterfaces.go +++ b/pkg/compute/models/networkinterfaces.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -27,7 +28,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index 32d73a9adc..b405b6725b 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -24,6 +24,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -43,7 +44,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/regiondrivers.go b/pkg/compute/models/regiondrivers.go index 5a3ef24446..58acca3804 100644 --- a/pkg/compute/models/regiondrivers.go +++ b/pkg/compute/models/regiondrivers.go @@ -18,13 +18,13 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" api "yunion.io/x/onecloud/pkg/apis/compute" "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/mcclient" "yunion.io/x/onecloud/pkg/util/billing" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/route_table_associtaion.go b/pkg/compute/models/route_table_associtaion.go index fe09fcd060..fe18cfa222 100644 --- a/pkg/compute/models/route_table_associtaion.go +++ b/pkg/compute/models/route_table_associtaion.go @@ -17,13 +17,13 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/errors" "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" ) diff --git a/pkg/compute/models/routetable_routesets.go b/pkg/compute/models/routetable_routesets.go index 6aae3c071d..4c0dc4fbc6 100644 --- a/pkg/compute/models/routetable_routesets.go +++ b/pkg/compute/models/routetable_routesets.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/routetables.go b/pkg/compute/models/routetables.go index 37a2ef59da..08050a0796 100644 --- a/pkg/compute/models/routetables.go +++ b/pkg/compute/models/routetables.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -29,7 +30,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/secgroupcache.go b/pkg/compute/models/secgroupcache.go index 15915d143f..35efae14c8 100644 --- a/pkg/compute/models/secgroupcache.go +++ b/pkg/compute/models/secgroupcache.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rand" diff --git a/pkg/compute/models/secgrouprules.go b/pkg/compute/models/secgrouprules.go index c18a725fa5..c0eb9fad23 100644 --- a/pkg/compute/models/secgrouprules.go +++ b/pkg/compute/models/secgrouprules.go @@ -19,6 +19,7 @@ import ( "fmt" "net" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/compute/models/secgroups.go b/pkg/compute/models/secgroups.go index b88eaf87c6..26323074db 100644 --- a/pkg/compute/models/secgroups.go +++ b/pkg/compute/models/secgroups.go @@ -21,6 +21,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -39,7 +40,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/skuresource.go b/pkg/compute/models/skuresource.go index 5292967d9a..843376bff2 100644 --- a/pkg/compute/models/skuresource.go +++ b/pkg/compute/models/skuresource.go @@ -19,6 +19,7 @@ import ( "database/sql" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" @@ -27,7 +28,6 @@ import ( apis "yunion.io/x/onecloud/pkg/apis/compute" "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/httperrors" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/skus.go b/pkg/compute/models/skus.go index f940aaff8b..c7ad47535f 100644 --- a/pkg/compute/models/skus.go +++ b/pkg/compute/models/skus.go @@ -24,6 +24,7 @@ import ( "strconv" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -37,7 +38,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/snapshotpolicy.go b/pkg/compute/models/snapshotpolicy.go index 6e34630f97..2aaab5ae53 100644 --- a/pkg/compute/models/snapshotpolicy.go +++ b/pkg/compute/models/snapshotpolicy.go @@ -20,6 +20,7 @@ import ( "sort" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -33,7 +34,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/snapshotpolicycache.go b/pkg/compute/models/snapshotpolicycache.go index 3e624b3623..6334f737f3 100644 --- a/pkg/compute/models/snapshotpolicycache.go +++ b/pkg/compute/models/snapshotpolicycache.go @@ -20,6 +20,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,7 +31,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/snapshotpolicydisks.go b/pkg/compute/models/snapshotpolicydisks.go index 06c02c0945..a83bc5c180 100644 --- a/pkg/compute/models/snapshotpolicydisks.go +++ b/pkg/compute/models/snapshotpolicydisks.go @@ -390,7 +390,6 @@ func (m *SSnapshotPolicyDiskManager) SyncAttachDisk(ctx context.Context, userCre return errors.Error(buf.String()) } -// func (m *SSnapshotPolicyDiskManager) SyncAttachDiskExt(ctx context.Context, userCred mcclient.TokenCredential, extSnapshotpolicies []string, syncOwnerID mcclient.IIdentityProvider, disk *SDisk, storage *SStorage) error { diff --git a/pkg/compute/models/snapshots.go b/pkg/compute/models/snapshots.go index f0d456e549..528e9d5a92 100644 --- a/pkg/compute/models/snapshots.go +++ b/pkg/compute/models/snapshots.go @@ -20,6 +20,7 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -34,7 +35,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/storagecachedimages.go b/pkg/compute/models/storagecachedimages.go index ec0e42870e..cce72b62eb 100644 --- a/pkg/compute/models/storagecachedimages.go +++ b/pkg/compute/models/storagecachedimages.go @@ -23,6 +23,7 @@ import ( "github.com/serialx/hashring" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/storagecaches.go b/pkg/compute/models/storagecaches.go index 3c27f11524..73e75f4880 100644 --- a/pkg/compute/models/storagecaches.go +++ b/pkg/compute/models/storagecaches.go @@ -22,6 +22,7 @@ import ( "github.com/serialx/hashring" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/imagetools" diff --git a/pkg/compute/models/storages.go b/pkg/compute/models/storages.go index 35525307c7..73ee762911 100644 --- a/pkg/compute/models/storages.go +++ b/pkg/compute/models/storages.go @@ -20,6 +20,7 @@ import ( "fmt" "path" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -34,7 +35,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/syncutils.go b/pkg/compute/models/syncutils.go index a678f8a0b5..beb97a6289 100644 --- a/pkg/compute/models/syncutils.go +++ b/pkg/compute/models/syncutils.go @@ -17,11 +17,11 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/apis" "yunion.io/x/onecloud/pkg/cloudcommon/db" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/tablestores.go b/pkg/compute/models/tablestores.go index 0d41b9c5c5..197e5b1a46 100644 --- a/pkg/compute/models/tablestores.go +++ b/pkg/compute/models/tablestores.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -28,7 +29,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/policy" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/vpc_peering_connections.go b/pkg/compute/models/vpc_peering_connections.go index c1f98343c5..9a9c164e77 100644 --- a/pkg/compute/models/vpc_peering_connections.go +++ b/pkg/compute/models/vpc_peering_connections.go @@ -19,6 +19,7 @@ import ( "database/sql" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/netutils" @@ -27,7 +28,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "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/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/vpcresource.go b/pkg/compute/models/vpcresource.go index 810b64acc7..b181ed7d1a 100644 --- a/pkg/compute/models/vpcresource.go +++ b/pkg/compute/models/vpcresource.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/vpcs.go b/pkg/compute/models/vpcs.go index d0acd35ee9..a124b4d347 100644 --- a/pkg/compute/models/vpcs.go +++ b/pkg/compute/models/vpcs.go @@ -21,6 +21,7 @@ import ( "sort" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -39,7 +40,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/models/waf_instances.go b/pkg/compute/models/waf_instances.go index 8678d03747..cb4c2efedf 100644 --- a/pkg/compute/models/waf_instances.go +++ b/pkg/compute/models/waf_instances.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/waf_ipset_caches.go b/pkg/compute/models/waf_ipset_caches.go index 10e9877b72..c483400f57 100644 --- a/pkg/compute/models/waf_ipset_caches.go +++ b/pkg/compute/models/waf_ipset_caches.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/waf_ipsets.go b/pkg/compute/models/waf_ipsets.go index a5ebb61827..5e433803fa 100644 --- a/pkg/compute/models/waf_ipsets.go +++ b/pkg/compute/models/waf_ipsets.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/sqlchemy" @@ -24,7 +25,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "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/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/waf_regexset_caches.go b/pkg/compute/models/waf_regexset_caches.go index 28822f5815..699bf87a07 100644 --- a/pkg/compute/models/waf_regexset_caches.go +++ b/pkg/compute/models/waf_regexset_caches.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/waf_regexsets.go b/pkg/compute/models/waf_regexsets.go index b55132da24..e28654dc8c 100644 --- a/pkg/compute/models/waf_regexsets.go +++ b/pkg/compute/models/waf_regexsets.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/sqlchemy" @@ -24,7 +25,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "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/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/waf_rule_group_caches.go b/pkg/compute/models/waf_rule_group_caches.go index 31068fa1e3..31024262a8 100644 --- a/pkg/compute/models/waf_rule_group_caches.go +++ b/pkg/compute/models/waf_rule_group_caches.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/waf_rule_groups.go b/pkg/compute/models/waf_rule_groups.go index 671594576b..7dcb5e0163 100644 --- a/pkg/compute/models/waf_rule_groups.go +++ b/pkg/compute/models/waf_rule_groups.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/stringutils2" diff --git a/pkg/compute/models/waf_rule_statements.go b/pkg/compute/models/waf_rule_statements.go index e252cacb8e..fad2ce14b8 100644 --- a/pkg/compute/models/waf_rule_statements.go +++ b/pkg/compute/models/waf_rule_statements.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" ) diff --git a/pkg/compute/models/waf_rules.go b/pkg/compute/models/waf_rules.go index 202a69a9df..af6d5c93b5 100644 --- a/pkg/compute/models/waf_rules.go +++ b/pkg/compute/models/waf_rules.go @@ -17,6 +17,7 @@ package models import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/compare" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/rbacutils" diff --git a/pkg/compute/models/wires.go b/pkg/compute/models/wires.go index b7c0579d56..c69203efa8 100644 --- a/pkg/compute/models/wires.go +++ b/pkg/compute/models/wires.go @@ -20,6 +20,7 @@ import ( "fmt" "sort" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -37,7 +38,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/compute/models/zones.go b/pkg/compute/models/zones.go index 740c224093..273677eeaf 100644 --- a/pkg/compute/models/zones.go +++ b/pkg/compute/models/zones.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "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/onecloud/pkg/mcclient" diff --git a/pkg/compute/options/options.go b/pkg/compute/options/options.go index d6fd300c7a..b65122f8fd 100644 --- a/pkg/compute/options/options.go +++ b/pkg/compute/options/options.go @@ -15,11 +15,11 @@ package options import ( + "yunion.io/x/cloudmux/pkg/multicloud/esxi" "yunion.io/x/log" common_options "yunion.io/x/onecloud/pkg/cloudcommon/options" "yunion.io/x/onecloud/pkg/cloudcommon/pending_delete" - "yunion.io/x/onecloud/pkg/multicloud/esxi" ) type ComputeOptions struct { diff --git a/pkg/compute/regiondrivers/aliyun.go b/pkg/compute/regiondrivers/aliyun.go index 30c6053809..51f2077af6 100644 --- a/pkg/compute/regiondrivers/aliyun.go +++ b/pkg/compute/regiondrivers/aliyun.go @@ -22,6 +22,7 @@ import ( "time" "unicode" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/regutils" @@ -33,7 +34,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/regiondrivers/aws.go b/pkg/compute/regiondrivers/aws.go index f369923a8d..beea929ea6 100644 --- a/pkg/compute/regiondrivers/aws.go +++ b/pkg/compute/regiondrivers/aws.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -33,7 +34,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/tasks" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/regiondrivers/azure.go b/pkg/compute/regiondrivers/azure.go index 02d072c3ef..f89ea7822a 100644 --- a/pkg/compute/regiondrivers/azure.go +++ b/pkg/compute/regiondrivers/azure.go @@ -17,12 +17,12 @@ package regiondrivers import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/util/secrules" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/regiondrivers/base.go b/pkg/compute/regiondrivers/base.go index 2714134ecf..1c6d6712c0 100644 --- a/pkg/compute/regiondrivers/base.go +++ b/pkg/compute/regiondrivers/base.go @@ -19,6 +19,7 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/secrules" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "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/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/regiondrivers/bingocloud.go b/pkg/compute/regiondrivers/bingocloud.go index cd90e89825..27ac4dd294 100644 --- a/pkg/compute/regiondrivers/bingocloud.go +++ b/pkg/compute/regiondrivers/bingocloud.go @@ -19,11 +19,11 @@ import ( "fmt" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/util/secrules" api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/regiondrivers/ctyun.go b/pkg/compute/regiondrivers/ctyun.go index 8e5a353661..107d72de7f 100644 --- a/pkg/compute/regiondrivers/ctyun.go +++ b/pkg/compute/regiondrivers/ctyun.go @@ -18,12 +18,12 @@ import ( "context" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/util/secrules" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/regiondrivers/google.go b/pkg/compute/regiondrivers/google.go index e5f230bf82..7027a111cb 100644 --- a/pkg/compute/regiondrivers/google.go +++ b/pkg/compute/regiondrivers/google.go @@ -19,6 +19,7 @@ import ( "fmt" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -29,7 +30,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/regiondrivers/huawei.go b/pkg/compute/regiondrivers/huawei.go index 5d2dee8a9a..b659dbefa3 100644 --- a/pkg/compute/regiondrivers/huawei.go +++ b/pkg/compute/regiondrivers/huawei.go @@ -21,6 +21,7 @@ import ( "regexp" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -33,7 +34,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/regiondrivers/jdcloud.go b/pkg/compute/regiondrivers/jdcloud.go index 2482805916..618fe041fa 100644 --- a/pkg/compute/regiondrivers/jdcloud.go +++ b/pkg/compute/regiondrivers/jdcloud.go @@ -15,10 +15,10 @@ package regiondrivers import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/util/secrules" api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" ) diff --git a/pkg/compute/regiondrivers/kvm.go b/pkg/compute/regiondrivers/kvm.go index d7bc4d8341..0275f1ee10 100644 --- a/pkg/compute/regiondrivers/kvm.go +++ b/pkg/compute/regiondrivers/kvm.go @@ -22,6 +22,7 @@ import ( "sort" "strconv" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -35,7 +36,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/compute/regiondrivers/managedvirtual.go b/pkg/compute/regiondrivers/managedvirtual.go index 7225faf8e5..844d258529 100644 --- a/pkg/compute/regiondrivers/managedvirtual.go +++ b/pkg/compute/regiondrivers/managedvirtual.go @@ -21,6 +21,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -33,7 +34,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/regiondrivers/openstack.go b/pkg/compute/regiondrivers/openstack.go index 071cb94131..87ef404deb 100644 --- a/pkg/compute/regiondrivers/openstack.go +++ b/pkg/compute/regiondrivers/openstack.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/regiondrivers/qcloud.go b/pkg/compute/regiondrivers/qcloud.go index 31208c22ef..bcb280278e 100644 --- a/pkg/compute/regiondrivers/qcloud.go +++ b/pkg/compute/regiondrivers/qcloud.go @@ -21,6 +21,7 @@ import ( "strconv" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -32,7 +33,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/regiondrivers/secgroup_aliyun_test.go b/pkg/compute/regiondrivers/secgroup_aliyun_test.go index b603286590..12452ca60c 100644 --- a/pkg/compute/regiondrivers/secgroup_aliyun_test.go +++ b/pkg/compute/regiondrivers/secgroup_aliyun_test.go @@ -17,7 +17,7 @@ package regiondrivers import ( "testing" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) func TestAliyunRuleSync(t *testing.T) { diff --git a/pkg/compute/regiondrivers/secgroup_aws_test.go b/pkg/compute/regiondrivers/secgroup_aws_test.go index 44a7e04318..830227f326 100644 --- a/pkg/compute/regiondrivers/secgroup_aws_test.go +++ b/pkg/compute/regiondrivers/secgroup_aws_test.go @@ -17,7 +17,7 @@ package regiondrivers import ( "testing" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) func TestAwsRuleSync(t *testing.T) { diff --git a/pkg/compute/regiondrivers/secgroup_azure_test.go b/pkg/compute/regiondrivers/secgroup_azure_test.go index 07671364b1..5f3d8656df 100644 --- a/pkg/compute/regiondrivers/secgroup_azure_test.go +++ b/pkg/compute/regiondrivers/secgroup_azure_test.go @@ -17,7 +17,7 @@ package regiondrivers import ( "testing" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) func TestAzureRuleSync(t *testing.T) { diff --git a/pkg/compute/regiondrivers/secgroup_ctyun_test.go b/pkg/compute/regiondrivers/secgroup_ctyun_test.go index 06227fb086..979992db1c 100644 --- a/pkg/compute/regiondrivers/secgroup_ctyun_test.go +++ b/pkg/compute/regiondrivers/secgroup_ctyun_test.go @@ -17,7 +17,7 @@ package regiondrivers import ( "testing" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) func TestCtyunRuleSync(t *testing.T) { diff --git a/pkg/compute/regiondrivers/secgroup_kvm_test.go b/pkg/compute/regiondrivers/secgroup_kvm_test.go index 3f219045e0..e200bba3b1 100644 --- a/pkg/compute/regiondrivers/secgroup_kvm_test.go +++ b/pkg/compute/regiondrivers/secgroup_kvm_test.go @@ -17,7 +17,7 @@ package regiondrivers import ( "testing" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) func TestKvmRuleSync(t *testing.T) { diff --git a/pkg/compute/regiondrivers/secgroup_openstack_test.go b/pkg/compute/regiondrivers/secgroup_openstack_test.go index d5de68a42f..c271092b74 100644 --- a/pkg/compute/regiondrivers/secgroup_openstack_test.go +++ b/pkg/compute/regiondrivers/secgroup_openstack_test.go @@ -17,7 +17,7 @@ package regiondrivers import ( "testing" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) func TestOpenStackRuleSync(t *testing.T) { diff --git a/pkg/compute/regiondrivers/secgroup_qcloud_test.go b/pkg/compute/regiondrivers/secgroup_qcloud_test.go index 601e6b600f..20c448609d 100644 --- a/pkg/compute/regiondrivers/secgroup_qcloud_test.go +++ b/pkg/compute/regiondrivers/secgroup_qcloud_test.go @@ -17,7 +17,7 @@ package regiondrivers import ( "testing" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) func TestQcloudRuleSync(t *testing.T) { diff --git a/pkg/compute/regiondrivers/secgroup_test.go b/pkg/compute/regiondrivers/secgroup_test.go index 88c8af5d09..752b5eb0d9 100644 --- a/pkg/compute/regiondrivers/secgroup_test.go +++ b/pkg/compute/regiondrivers/secgroup_test.go @@ -19,10 +19,9 @@ import ( "sort" "testing" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/util/secrules" "yunion.io/x/pkg/util/stringutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" ) type TestData struct { diff --git a/pkg/compute/regiondrivers/ucloud.go b/pkg/compute/regiondrivers/ucloud.go index b9a863a0f1..45bd6ebdd5 100644 --- a/pkg/compute/regiondrivers/ucloud.go +++ b/pkg/compute/regiondrivers/ucloud.go @@ -17,12 +17,12 @@ package regiondrivers import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/util/secrules" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/validators" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/regiondrivers/zstack.go b/pkg/compute/regiondrivers/zstack.go index 8e0822e7ad..6f6c50e55d 100644 --- a/pkg/compute/regiondrivers/zstack.go +++ b/pkg/compute/regiondrivers/zstack.go @@ -18,11 +18,11 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/util/secrules" api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" diff --git a/pkg/compute/service/service.go b/pkg/compute/service/service.go index de4cf92d00..cfcb87c58e 100644 --- a/pkg/compute/service/service.go +++ b/pkg/compute/service/service.go @@ -21,6 +21,8 @@ import ( "path/filepath" "time" + "yunion.io/x/cloudmux/pkg/multicloud/esxi" + _ "yunion.io/x/cloudmux/pkg/multicloud/loader" "yunion.io/x/log" "yunion.io/x/pkg/errors" _ "yunion.io/x/sqlchemy/backends" @@ -46,8 +48,6 @@ import ( "yunion.io/x/onecloud/pkg/controller/autoscaling" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient/auth" - "yunion.io/x/onecloud/pkg/multicloud/esxi" - _ "yunion.io/x/onecloud/pkg/multicloud/loader" ) func StartService() { diff --git a/pkg/compute/tasks/access_group_cache_delete_task.go b/pkg/compute/tasks/access_group_cache_delete_task.go index f9251a0cfb..fdd31c3457 100644 --- a/pkg/compute/tasks/access_group_cache_delete_task.go +++ b/pkg/compute/tasks/access_group_cache_delete_task.go @@ -31,13 +31,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/access_group_delete_task.go b/pkg/compute/tasks/access_group_delete_task.go index 9ef5c6a25a..b20bb81b6b 100644 --- a/pkg/compute/tasks/access_group_delete_task.go +++ b/pkg/compute/tasks/access_group_delete_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/app_remote_update_task.go b/pkg/compute/tasks/app_remote_update_task.go index 1350ca23b4..1c8fe001d3 100644 --- a/pkg/compute/tasks/app_remote_update_task.go +++ b/pkg/compute/tasks/app_remote_update_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" "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/util/logclient" ) diff --git a/pkg/compute/tasks/cdn_domain_create_task.go b/pkg/compute/tasks/cdn_domain_create_task.go index c32b856bbd..48b126a567 100644 --- a/pkg/compute/tasks/cdn_domain_create_task.go +++ b/pkg/compute/tasks/cdn_domain_create_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -26,7 +27,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/cdn_domain_delete_task.go b/pkg/compute/tasks/cdn_domain_delete_task.go index faff6ca323..d0c8371621 100644 --- a/pkg/compute/tasks/cdn_domain_delete_task.go +++ b/pkg/compute/tasks/cdn_domain_delete_task.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/cdn_domain_remote_update_task.go b/pkg/compute/tasks/cdn_domain_remote_update_task.go index 9210cebfbf..43914af51a 100644 --- a/pkg/compute/tasks/cdn_domain_remote_update_task.go +++ b/pkg/compute/tasks/cdn_domain_remote_update_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" "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/util/logclient" ) diff --git a/pkg/compute/tasks/cloud_account_sync_vmware_net.go b/pkg/compute/tasks/cloud_account_sync_vmware_net.go index dc2085019b..c15eb59683 100644 --- a/pkg/compute/tasks/cloud_account_sync_vmware_net.go +++ b/pkg/compute/tasks/cloud_account_sync_vmware_net.go @@ -19,6 +19,7 @@ import ( "fmt" "sort" + "yunion.io/x/cloudmux/pkg/multicloud/esxi" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -29,7 +30,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" - "yunion.io/x/onecloud/pkg/multicloud/esxi" "yunion.io/x/onecloud/pkg/util/logclient" "yunion.io/x/onecloud/pkg/util/rbacutils" ) diff --git a/pkg/compute/tasks/dbinstance_account_create_task.go b/pkg/compute/tasks/dbinstance_account_create_task.go index 27b4423209..1453447cc8 100644 --- a/pkg/compute/tasks/dbinstance_account_create_task.go +++ b/pkg/compute/tasks/dbinstance_account_create_task.go @@ -18,13 +18,13 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/dbinstance_account_grant_privilege_task.go b/pkg/compute/tasks/dbinstance_account_grant_privilege_task.go index f17d539702..57167f4a50 100644 --- a/pkg/compute/tasks/dbinstance_account_grant_privilege_task.go +++ b/pkg/compute/tasks/dbinstance_account_grant_privilege_task.go @@ -18,13 +18,13 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/dbinstance_account_revoke_privilege_task.go b/pkg/compute/tasks/dbinstance_account_revoke_privilege_task.go index 5a8906e7ee..07c1f84f4a 100644 --- a/pkg/compute/tasks/dbinstance_account_revoke_privilege_task.go +++ b/pkg/compute/tasks/dbinstance_account_revoke_privilege_task.go @@ -18,13 +18,13 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/dbinstance_account_set_privileges_task.go b/pkg/compute/tasks/dbinstance_account_set_privileges_task.go index 815544ab44..ac75f8cb94 100644 --- a/pkg/compute/tasks/dbinstance_account_set_privileges_task.go +++ b/pkg/compute/tasks/dbinstance_account_set_privileges_task.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/dbinstance_backup_delete.go b/pkg/compute/tasks/dbinstance_backup_delete.go index 31b3fd59c6..9102fa106e 100644 --- a/pkg/compute/tasks/dbinstance_backup_delete.go +++ b/pkg/compute/tasks/dbinstance_backup_delete.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/dbinstance_database_create_task.go b/pkg/compute/tasks/dbinstance_database_create_task.go index 7e0c73b7ee..3243c108d0 100644 --- a/pkg/compute/tasks/dbinstance_database_create_task.go +++ b/pkg/compute/tasks/dbinstance_database_create_task.go @@ -18,13 +18,13 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/dbinstance_delete_task.go b/pkg/compute/tasks/dbinstance_delete_task.go index 88e09bf3cd..0e0d73a17f 100644 --- a/pkg/compute/tasks/dbinstance_delete_task.go +++ b/pkg/compute/tasks/dbinstance_delete_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/dbinstance_public_connection_task.go b/pkg/compute/tasks/dbinstance_public_connection_task.go index 251d75d469..503b0d440f 100644 --- a/pkg/compute/tasks/dbinstance_public_connection_task.go +++ b/pkg/compute/tasks/dbinstance_public_connection_task.go @@ -18,13 +18,13 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/dbinstance_reboot_task.go b/pkg/compute/tasks/dbinstance_reboot_task.go index ceb1dff9ba..9c170d2172 100644 --- a/pkg/compute/tasks/dbinstance_reboot_task.go +++ b/pkg/compute/tasks/dbinstance_reboot_task.go @@ -18,13 +18,13 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/dbinstance_recovery_task.go b/pkg/compute/tasks/dbinstance_recovery_task.go index 5b32ac8afc..cf3c06331a 100644 --- a/pkg/compute/tasks/dbinstance_recovery_task.go +++ b/pkg/compute/tasks/dbinstance_recovery_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/dbinstance_renew_task.go b/pkg/compute/tasks/dbinstance_renew_task.go index cf7a294665..3230afdad1 100644 --- a/pkg/compute/tasks/dbinstance_renew_task.go +++ b/pkg/compute/tasks/dbinstance_renew_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/billing" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/compute/tasks/disk_delete_task.go b/pkg/compute/tasks/disk_delete_task.go index 9779fb5a3a..9b3b5a34d7 100644 --- a/pkg/compute/tasks/disk_delete_task.go +++ b/pkg/compute/tasks/disk_delete_task.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/compute/tasks/dnszone_create_task.go b/pkg/compute/tasks/dnszone_create_task.go index 0751300f59..15e0239fd9 100644 --- a/pkg/compute/tasks/dnszone_create_task.go +++ b/pkg/compute/tasks/dnszone_create_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/dnszone_delete_task.go b/pkg/compute/tasks/dnszone_delete_task.go index 3fd8d314da..e781e40e73 100644 --- a/pkg/compute/tasks/dnszone_delete_task.go +++ b/pkg/compute/tasks/dnszone_delete_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/dnszone_sync_vpcs_task.go b/pkg/compute/tasks/dnszone_sync_vpcs_task.go index 86f86483d8..32c2132439 100644 --- a/pkg/compute/tasks/dnszone_sync_vpcs_task.go +++ b/pkg/compute/tasks/dnszone_sync_vpcs_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "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/util/logclient" ) diff --git a/pkg/compute/tasks/dnszonecache_create_task.go b/pkg/compute/tasks/dnszonecache_create_task.go index bd67430b12..d2ec7b0873 100644 --- a/pkg/compute/tasks/dnszonecache_create_task.go +++ b/pkg/compute/tasks/dnszonecache_create_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/dnszonecache_delete_task.go b/pkg/compute/tasks/dnszonecache_delete_task.go index 8523ffa9ca..fe9ea48be2 100644 --- a/pkg/compute/tasks/dnszonecache_delete_task.go +++ b/pkg/compute/tasks/dnszonecache_delete_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/eip_allocate_task.go b/pkg/compute/tasks/eip_allocate_task.go index cd6d42215b..819580e771 100644 --- a/pkg/compute/tasks/eip_allocate_task.go +++ b/pkg/compute/tasks/eip_allocate_task.go @@ -19,6 +19,7 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/eip_deallocate_task.go b/pkg/compute/tasks/eip_deallocate_task.go index f577abcb10..532328ac5a 100644 --- a/pkg/compute/tasks/eip_deallocate_task.go +++ b/pkg/compute/tasks/eip_deallocate_task.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/eip_dissociate_task.go b/pkg/compute/tasks/eip_dissociate_task.go index 0cf1c7e0cb..d369a455ab 100644 --- a/pkg/compute/tasks/eip_dissociate_task.go +++ b/pkg/compute/tasks/eip_dissociate_task.go @@ -18,13 +18,13 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/httperrors" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/compute/tasks/elastic_search_delete_task.go b/pkg/compute/tasks/elastic_search_delete_task.go index 1509296b21..c77ca24925 100644 --- a/pkg/compute/tasks/elastic_search_delete_task.go +++ b/pkg/compute/tasks/elastic_search_delete_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/file_system_remote_update_task.go b/pkg/compute/tasks/file_system_remote_update_task.go index cf76f1db59..414b96d43d 100644 --- a/pkg/compute/tasks/file_system_remote_update_task.go +++ b/pkg/compute/tasks/file_system_remote_update_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/filesystem_create_task.go b/pkg/compute/tasks/filesystem_create_task.go index dda61c35f2..16e5a67504 100644 --- a/pkg/compute/tasks/filesystem_create_task.go +++ b/pkg/compute/tasks/filesystem_create_task.go @@ -33,6 +33,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -41,7 +42,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/filesystem_delete_task.go b/pkg/compute/tasks/filesystem_delete_task.go index 9e44dc2509..4e44277037 100644 --- a/pkg/compute/tasks/filesystem_delete_task.go +++ b/pkg/compute/tasks/filesystem_delete_task.go @@ -32,6 +32,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -39,7 +40,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/global_vpc_create_task.go b/pkg/compute/tasks/global_vpc_create_task.go index 9972510724..81ac184ba7 100644 --- a/pkg/compute/tasks/global_vpc_create_task.go +++ b/pkg/compute/tasks/global_vpc_create_task.go @@ -32,6 +32,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -41,7 +42,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/global_vpc_delete_task.go b/pkg/compute/tasks/global_vpc_delete_task.go index abe029f1f6..944d4f507e 100644 --- a/pkg/compute/tasks/global_vpc_delete_task.go +++ b/pkg/compute/tasks/global_vpc_delete_task.go @@ -32,6 +32,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -39,7 +40,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/guest_create_disk_task.go b/pkg/compute/tasks/guest_create_disk_task.go index 03f88befd9..ae578f85a2 100644 --- a/pkg/compute/tasks/guest_create_disk_task.go +++ b/pkg/compute/tasks/guest_create_disk_task.go @@ -19,6 +19,7 @@ import ( "fmt" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -26,7 +27,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "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" ) diff --git a/pkg/compute/tasks/guest_delete_task.go b/pkg/compute/tasks/guest_delete_task.go index 07924d5288..82eb7f9bc8 100644 --- a/pkg/compute/tasks/guest_delete_task.go +++ b/pkg/compute/tasks/guest_delete_task.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/compute/tasks/guest_live_migrate_task.go b/pkg/compute/tasks/guest_live_migrate_task.go index 41e2b57f96..31a668a908 100644 --- a/pkg/compute/tasks/guest_live_migrate_task.go +++ b/pkg/compute/tasks/guest_live_migrate_task.go @@ -668,7 +668,7 @@ func (self *GuestMigrateTask) markFailed(ctx context.Context, guest *models.SGue }) } -//ManagedGuestMigrateTask +// ManagedGuestMigrateTask func (self *ManagedGuestMigrateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { guest := obj.(*models.SGuest) db.OpsLog.LogEvent(guest, db.ACT_MIGRATING, nil, self.UserCred) @@ -720,7 +720,7 @@ func (self *ManagedGuestMigrateTask) OnMigrateCompleteFailed(ctx context.Context notifyclient.NotifySystemErrorWithCtx(ctx, guest.Id, guest.Name, api.VM_MIGRATE_FAILED, data.String()) } -//ManagedGuestLiveMigrateTask +// ManagedGuestLiveMigrateTask func (self *ManagedGuestLiveMigrateTask) OnInit(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) { guest := obj.(*models.SGuest) db.OpsLog.LogEvent(guest, db.ACT_MIGRATING, nil, self.UserCred) diff --git a/pkg/compute/tasks/guest_syncstatus_task.go b/pkg/compute/tasks/guest_syncstatus_task.go index cc624dac85..f8f319b18c 100644 --- a/pkg/compute/tasks/guest_syncstatus_task.go +++ b/pkg/compute/tasks/guest_syncstatus_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" @@ -24,7 +25,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "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" ) diff --git a/pkg/compute/tasks/inter_vpc_network_add_vpc_task.go b/pkg/compute/tasks/inter_vpc_network_add_vpc_task.go index 5de491a325..97256716df 100644 --- a/pkg/compute/tasks/inter_vpc_network_add_vpc_task.go +++ b/pkg/compute/tasks/inter_vpc_network_add_vpc_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/inter_vpc_network_create_task.go b/pkg/compute/tasks/inter_vpc_network_create_task.go index 57c871a2c8..de33969932 100644 --- a/pkg/compute/tasks/inter_vpc_network_create_task.go +++ b/pkg/compute/tasks/inter_vpc_network_create_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/inter_vpc_network_remove_vpc_task.go b/pkg/compute/tasks/inter_vpc_network_remove_vpc_task.go index 4131593084..cc2c2ab7bb 100644 --- a/pkg/compute/tasks/inter_vpc_network_remove_vpc_task.go +++ b/pkg/compute/tasks/inter_vpc_network_remove_vpc_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/kafka_delete_task.go b/pkg/compute/tasks/kafka_delete_task.go index 1012f7e827..d9e67d4266 100644 --- a/pkg/compute/tasks/kafka_delete_task.go +++ b/pkg/compute/tasks/kafka_delete_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/kube_cluster_delete_task.go b/pkg/compute/tasks/kube_cluster_delete_task.go index 0f53acc61d..379784b30a 100644 --- a/pkg/compute/tasks/kube_cluster_delete_task.go +++ b/pkg/compute/tasks/kube_cluster_delete_task.go @@ -18,13 +18,13 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" "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/util/logclient" ) diff --git a/pkg/compute/tasks/loadbalancer_backendgroup_create_task.go b/pkg/compute/tasks/loadbalancer_backendgroup_create_task.go index a16ca2fc9b..951ada82be 100644 --- a/pkg/compute/tasks/loadbalancer_backendgroup_create_task.go +++ b/pkg/compute/tasks/loadbalancer_backendgroup_create_task.go @@ -18,13 +18,13 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/modelarts_pool_change_config_task.go b/pkg/compute/tasks/modelarts_pool_change_config_task.go index d8ed64f396..afb9a6d79d 100644 --- a/pkg/compute/tasks/modelarts_pool_change_config_task.go +++ b/pkg/compute/tasks/modelarts_pool_change_config_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/modelarts_pool_create_task.go b/pkg/compute/tasks/modelarts_pool_create_task.go index 891a9ef293..62f239b05b 100644 --- a/pkg/compute/tasks/modelarts_pool_create_task.go +++ b/pkg/compute/tasks/modelarts_pool_create_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/modelarts_pool_delete_task.go b/pkg/compute/tasks/modelarts_pool_delete_task.go index 9d3e60ee53..a1441eb80a 100644 --- a/pkg/compute/tasks/modelarts_pool_delete_task.go +++ b/pkg/compute/tasks/modelarts_pool_delete_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/mongodb_delete_task.go b/pkg/compute/tasks/mongodb_delete_task.go index ffecfb0f92..16b99670d6 100644 --- a/pkg/compute/tasks/mongodb_delete_task.go +++ b/pkg/compute/tasks/mongodb_delete_task.go @@ -32,6 +32,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -39,7 +40,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/mongodb_remote_update_task.go b/pkg/compute/tasks/mongodb_remote_update_task.go index d838ca160e..594fe9d84d 100644 --- a/pkg/compute/tasks/mongodb_remote_update_task.go +++ b/pkg/compute/tasks/mongodb_remote_update_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" "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/util/logclient" ) diff --git a/pkg/compute/tasks/mount_target_create_task.go b/pkg/compute/tasks/mount_target_create_task.go index 1c0bbbe0e1..9ac56c0dd0 100644 --- a/pkg/compute/tasks/mount_target_create_task.go +++ b/pkg/compute/tasks/mount_target_create_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/mount_target_syncstatus_task.go b/pkg/compute/tasks/mount_target_syncstatus_task.go index 408347915d..8313a53da1 100644 --- a/pkg/compute/tasks/mount_target_syncstatus_task.go +++ b/pkg/compute/tasks/mount_target_syncstatus_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/nat_create_task.go b/pkg/compute/tasks/nat_create_task.go index f893cb3b86..b56c9221d2 100644 --- a/pkg/compute/tasks/nat_create_task.go +++ b/pkg/compute/tasks/nat_create_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -26,7 +27,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/billing" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/compute/tasks/nat_delete_task.go b/pkg/compute/tasks/nat_delete_task.go index cd4e6e77f0..4620e0903d 100644 --- a/pkg/compute/tasks/nat_delete_task.go +++ b/pkg/compute/tasks/nat_delete_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/nat_renew_task.go b/pkg/compute/tasks/nat_renew_task.go index c13d1a4608..a60faa7c24 100644 --- a/pkg/compute/tasks/nat_renew_task.go +++ b/pkg/compute/tasks/nat_renew_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/billing" "yunion.io/x/onecloud/pkg/util/logclient" diff --git a/pkg/compute/tasks/natdentry_create_task.go b/pkg/compute/tasks/natdentry_create_task.go index 1838bc01f1..0294b886be 100644 --- a/pkg/compute/tasks/natdentry_create_task.go +++ b/pkg/compute/tasks/natdentry_create_task.go @@ -18,13 +18,13 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/natdentry_delete_task.go b/pkg/compute/tasks/natdentry_delete_task.go index 1bf5553555..2e725ddfde 100644 --- a/pkg/compute/tasks/natdentry_delete_task.go +++ b/pkg/compute/tasks/natdentry_delete_task.go @@ -18,13 +18,13 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/natgateway_remote_update_task.go b/pkg/compute/tasks/natgateway_remote_update_task.go index 5321a6f3a4..a6b6ebeab7 100644 --- a/pkg/compute/tasks/natgateway_remote_update_task.go +++ b/pkg/compute/tasks/natgateway_remote_update_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" "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/util/logclient" ) diff --git a/pkg/compute/tasks/natsentry_create_task.go b/pkg/compute/tasks/natsentry_create_task.go index 2b24e58346..774b90b7b5 100644 --- a/pkg/compute/tasks/natsentry_create_task.go +++ b/pkg/compute/tasks/natsentry_create_task.go @@ -18,13 +18,13 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/natsentry_delete_task.go b/pkg/compute/tasks/natsentry_delete_task.go index 311ea352e9..5b6672b561 100644 --- a/pkg/compute/tasks/natsentry_delete_task.go +++ b/pkg/compute/tasks/natsentry_delete_task.go @@ -18,13 +18,13 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/network_delete_task.go b/pkg/compute/tasks/network_delete_task.go index c871cd19f6..a003b0343c 100644 --- a/pkg/compute/tasks/network_delete_task.go +++ b/pkg/compute/tasks/network_delete_task.go @@ -18,6 +18,7 @@ import ( "context" "database/sql" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/route_table_update_task.go b/pkg/compute/tasks/route_table_update_task.go index 79c88212b8..82b9ba71e1 100644 --- a/pkg/compute/tasks/route_table_update_task.go +++ b/pkg/compute/tasks/route_table_update_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/security_group_cache_delete_task.go b/pkg/compute/tasks/security_group_cache_delete_task.go index 93b089306c..642e45ac08 100644 --- a/pkg/compute/tasks/security_group_cache_delete_task.go +++ b/pkg/compute/tasks/security_group_cache_delete_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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" ) diff --git a/pkg/compute/tasks/security_group_delete_task.go b/pkg/compute/tasks/security_group_delete_task.go index ac071a32e2..d7bb4ffa4e 100644 --- a/pkg/compute/tasks/security_group_delete_task.go +++ b/pkg/compute/tasks/security_group_delete_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/security_group_sync_rules_task.go b/pkg/compute/tasks/security_group_sync_rules_task.go index 70e61ff255..2c1ee841a1 100644 --- a/pkg/compute/tasks/security_group_sync_rules_task.go +++ b/pkg/compute/tasks/security_group_sync_rules_task.go @@ -18,13 +18,13 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/server_sku_create_task.go b/pkg/compute/tasks/server_sku_create_task.go index 440964516d..ba4073ff2e 100644 --- a/pkg/compute/tasks/server_sku_create_task.go +++ b/pkg/compute/tasks/server_sku_create_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/server_sku_delete_task.go b/pkg/compute/tasks/server_sku_delete_task.go index 2c88265079..1fb31ca981 100644 --- a/pkg/compute/tasks/server_sku_delete_task.go +++ b/pkg/compute/tasks/server_sku_delete_task.go @@ -19,13 +19,13 @@ import ( "github.com/pkg/errors" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/snapshot_delete_task.go b/pkg/compute/tasks/snapshot_delete_task.go index 6731dfc63d..1942198728 100644 --- a/pkg/compute/tasks/snapshot_delete_task.go +++ b/pkg/compute/tasks/snapshot_delete_task.go @@ -17,6 +17,7 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/vpc_peering_connection_create_task.go b/pkg/compute/tasks/vpc_peering_connection_create_task.go index 05f8ab2c2e..cfaf3556cf 100644 --- a/pkg/compute/tasks/vpc_peering_connection_create_task.go +++ b/pkg/compute/tasks/vpc_peering_connection_create_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/vpc_peering_connection_delete_task.go b/pkg/compute/tasks/vpc_peering_connection_delete_task.go index ffa05d40ba..84c92e52db 100644 --- a/pkg/compute/tasks/vpc_peering_connection_delete_task.go +++ b/pkg/compute/tasks/vpc_peering_connection_delete_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/waf_create_task.go b/pkg/compute/tasks/waf_create_task.go index 5394b2ca89..ecc1187992 100644 --- a/pkg/compute/tasks/waf_create_task.go +++ b/pkg/compute/tasks/waf_create_task.go @@ -18,13 +18,13 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/waf_delete_task.go b/pkg/compute/tasks/waf_delete_task.go index 4103bc341f..4320e53778 100644 --- a/pkg/compute/tasks/waf_delete_task.go +++ b/pkg/compute/tasks/waf_delete_task.go @@ -18,6 +18,7 @@ import ( "context" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" @@ -25,7 +26,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon/db" "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman" "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/logclient" ) diff --git a/pkg/compute/tasks/waf_instance_remote_update_task.go b/pkg/compute/tasks/waf_instance_remote_update_task.go index 0322b3288d..f229bdda70 100644 --- a/pkg/compute/tasks/waf_instance_remote_update_task.go +++ b/pkg/compute/tasks/waf_instance_remote_update_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" "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/util/logclient" ) diff --git a/pkg/compute/tasks/waf_ipset_cache_delete_task.go b/pkg/compute/tasks/waf_ipset_cache_delete_task.go index 47ac74abe9..26274f540b 100644 --- a/pkg/compute/tasks/waf_ipset_cache_delete_task.go +++ b/pkg/compute/tasks/waf_ipset_cache_delete_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/waf_ipset_delete_task.go b/pkg/compute/tasks/waf_ipset_delete_task.go index 843b8eba29..ea793b7331 100644 --- a/pkg/compute/tasks/waf_ipset_delete_task.go +++ b/pkg/compute/tasks/waf_ipset_delete_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/waf_regexset_cache_delete_task.go b/pkg/compute/tasks/waf_regexset_cache_delete_task.go index f992020582..7d0cafcc1a 100644 --- a/pkg/compute/tasks/waf_regexset_cache_delete_task.go +++ b/pkg/compute/tasks/waf_regexset_cache_delete_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/waf_regexset_delete_task.go b/pkg/compute/tasks/waf_regexset_delete_task.go index 922efa8156..2d6e1f5088 100644 --- a/pkg/compute/tasks/waf_regexset_delete_task.go +++ b/pkg/compute/tasks/waf_regexset_delete_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/waf_rule_create_task.go b/pkg/compute/tasks/waf_rule_create_task.go index 3d68b550f6..9400d479a0 100644 --- a/pkg/compute/tasks/waf_rule_create_task.go +++ b/pkg/compute/tasks/waf_rule_create_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/waf_rule_delete_task.go b/pkg/compute/tasks/waf_rule_delete_task.go index 3777dea70c..47cf8c58ad 100644 --- a/pkg/compute/tasks/waf_rule_delete_task.go +++ b/pkg/compute/tasks/waf_rule_delete_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/compute/tasks/waf_rule_update_task.go b/pkg/compute/tasks/waf_rule_update_task.go index 0c66e52b26..d600d5a910 100644 --- a/pkg/compute/tasks/waf_rule_update_task.go +++ b/pkg/compute/tasks/waf_rule_update_task.go @@ -17,13 +17,13 @@ package tasks import ( "context" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" "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/util/logclient" ) diff --git a/pkg/esxi/options/options.go b/pkg/esxi/options/options.go index 4ca02442de..a10156a83a 100644 --- a/pkg/esxi/options/options.go +++ b/pkg/esxi/options/options.go @@ -15,8 +15,9 @@ package options import ( + "yunion.io/x/cloudmux/pkg/multicloud/esxi" + common_options "yunion.io/x/onecloud/pkg/cloudcommon/options" - "yunion.io/x/onecloud/pkg/multicloud/esxi" ) type EsxiOptions struct { diff --git a/pkg/esxi/service/esxi_agent_service.go b/pkg/esxi/service/esxi_agent_service.go index fbddfa7b9d..1c741de61f 100644 --- a/pkg/esxi/service/esxi_agent_service.go +++ b/pkg/esxi/service/esxi_agent_service.go @@ -18,6 +18,7 @@ import ( "os" "path/filepath" + mcesxi "yunion.io/x/cloudmux/pkg/multicloud/esxi" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/appsrv" @@ -31,7 +32,6 @@ import ( "yunion.io/x/onecloud/pkg/hostman/guestfs/fsdriver" "yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient" "yunion.io/x/onecloud/pkg/hostman/hostutils" - mcesxi "yunion.io/x/onecloud/pkg/multicloud/esxi" ) type SExsiAgentService struct { diff --git a/pkg/hostman/guestman/arch/arm.go b/pkg/hostman/guestman/arch/arm.go index 03f45eaf2f..699904d963 100644 --- a/pkg/hostman/guestman/arch/arm.go +++ b/pkg/hostman/guestman/arch/arm.go @@ -33,8 +33,8 @@ type ARM struct { archBase } -// -device scsi-cd,drive=cd0,share-rw=true -// if=none,file=%s,id=cd0,media=cdrom +// -device scsi-cd,drive=cd0,share-rw=true +// if=none,file=%s,id=cd0,media=cdrom func (*ARM) GenerateCdromDesc(osName string, cdrom *desc.SGuestCdrom) { scsiDev := desc.NewScsiDevice("", "scsi-cd", "scsi0-cd0") scsiDev.Options = map[string]string{"share-rw": "true"} diff --git a/pkg/hostman/guestman/arch/x86.go b/pkg/hostman/guestman/arch/x86.go index 1911fe0f02..dd52f4beac 100644 --- a/pkg/hostman/guestman/arch/x86.go +++ b/pkg/hostman/guestman/arch/x86.go @@ -81,7 +81,7 @@ func (*X86) GenerateCdromDesc(osName string, cdrom *desc.SGuestCdrom) { cdrom.Id = id } -//-device floppy,drive=floppy0 -drive id=floppy0,if=none +// -device floppy,drive=floppy0 -drive id=floppy0,if=none func (*X86) GenerateFloppyDesc(osName string, floppy *desc.SGuestFloppy) { var id, devType string var driveOpts map[string]string diff --git a/pkg/hostman/guestman/esxi.go b/pkg/hostman/guestman/esxi.go index 8d91cac877..1810c10595 100644 --- a/pkg/hostman/guestman/esxi.go +++ b/pkg/hostman/guestman/esxi.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/multicloud/esxi" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -26,7 +27,6 @@ import ( "yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient" hostutils "yunion.io/x/onecloud/pkg/hostman/hostutils" "yunion.io/x/onecloud/pkg/hostman/storageman" - "yunion.io/x/onecloud/pkg/multicloud/esxi" ) func (m *SGuestManager) GuestCreateFromEsxi( diff --git a/pkg/hostman/guestman/guesthelper.go b/pkg/hostman/guestman/guesthelper.go index ca68a93b06..86276d8010 100644 --- a/pkg/hostman/guestman/guesthelper.go +++ b/pkg/hostman/guestman/guesthelper.go @@ -15,13 +15,13 @@ package guestman import ( + "yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter" "yunion.io/x/jsonutils" hostapi "yunion.io/x/onecloud/pkg/apis/host" "yunion.io/x/onecloud/pkg/hostman/guestman/desc" "yunion.io/x/onecloud/pkg/hostman/storageman" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/esxi/vcenter" ) type SBaseParms struct { diff --git a/pkg/hostman/guestman/qemu-kvm.go b/pkg/hostman/guestman/qemu-kvm.go index 3bf8411f98..568d98a08a 100644 --- a/pkg/hostman/guestman/qemu-kvm.go +++ b/pkg/hostman/guestman/qemu-kvm.go @@ -263,9 +263,9 @@ func (s *SKVMGuestInstance) GetPid() int { } /* - pid -> running qemu's pid - -1 -> pid file does not exists - -2 -> pid file ok but content does not match any qemu process +pid -> running qemu's pid +-1 -> pid file does not exists +-2 -> pid file ok but content does not match any qemu process */ func (s *SKVMGuestInstance) getPid(pidFile, uuid string) int { if !fileutils2.Exists(pidFile) { diff --git a/pkg/hostman/guestman/qemu/qemu.go b/pkg/hostman/guestman/qemu/qemu.go index 7bc69eb438..2c642b2103 100644 --- a/pkg/hostman/guestman/qemu/qemu.go +++ b/pkg/hostman/guestman/qemu/qemu.go @@ -212,8 +212,8 @@ func (o baseOptions) Nodefconfig() string { /* @subsection -no-kvm-pit-reinjection (since 1.3.0) -The ``-no-kvm-pit-reinjection'' argument is now a -synonym for setting ``-global kvm-pit.lost_tick_policy=discard''. +The “-no-kvm-pit-reinjection” argument is now a +synonym for setting “-global kvm-pit.lost_tick_policy=discard”. */ func (o baseOptions) Global() string { return "-global kvm-pit.lost_tick_policy=discard" diff --git a/pkg/hostman/monitor/qga/qga.go b/pkg/hostman/monitor/qga/qga.go index fced834282..61af285d67 100644 --- a/pkg/hostman/monitor/qga/qga.go +++ b/pkg/hostman/monitor/qga/qga.go @@ -315,9 +315,10 @@ func (qga *QemuGuestAgent) GuestExecCommand( # Since: 2.5 ## { 'struct': 'GuestExecStatus', - 'data': { 'exited': 'bool', '*exitcode': 'int', '*signal': 'int', - '*out-data': 'str', '*err-data': 'str', - '*out-truncated': 'bool', '*err-truncated': 'bool' }} + + 'data': { 'exited': 'bool', '*exitcode': 'int', '*signal': 'int', + '*out-data': 'str', '*err-data': 'str', + '*out-truncated': 'bool', '*err-truncated': 'bool' }} */ type GuestExecStatus struct { Exited bool diff --git a/pkg/hostman/storageman/core.go b/pkg/hostman/storageman/core.go index 25f7500670..a9b03b6f29 100644 --- a/pkg/hostman/storageman/core.go +++ b/pkg/hostman/storageman/core.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/timeutils" @@ -29,7 +30,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/hostman/hostutils" "yunion.io/x/onecloud/pkg/hostman/hostutils/kubelet" "yunion.io/x/onecloud/pkg/hostman/options" diff --git a/pkg/hostman/storageman/disk_agent.go b/pkg/hostman/storageman/disk_agent.go index 2de475c8a1..cd75c5eb22 100644 --- a/pkg/hostman/storageman/disk_agent.go +++ b/pkg/hostman/storageman/disk_agent.go @@ -17,14 +17,14 @@ package storageman import ( "context" + "yunion.io/x/cloudmux/pkg/multicloud/esxi" + "yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/hostman/hostutils" "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/multicloud/esxi/vcenter" ) type SAgentDisk struct { diff --git a/pkg/hostman/storageman/disk_local.go b/pkg/hostman/storageman/disk_local.go index 5ae003ac09..465358b3a3 100644 --- a/pkg/hostman/storageman/disk_local.go +++ b/pkg/hostman/storageman/disk_local.go @@ -22,6 +22,7 @@ import ( "path" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/appctx" "yunion.io/x/onecloud/pkg/cloudcommon/consts" - "yunion.io/x/onecloud/pkg/cloudprovider" deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis" "yunion.io/x/onecloud/pkg/hostman/hostutils" "yunion.io/x/onecloud/pkg/hostman/options" diff --git a/pkg/hostman/storageman/disk_rbd.go b/pkg/hostman/storageman/disk_rbd.go index ebc4e23bb2..6f2a5cbc8c 100644 --- a/pkg/hostman/storageman/disk_rbd.go +++ b/pkg/hostman/storageman/disk_rbd.go @@ -18,6 +18,7 @@ import ( "context" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -26,7 +27,6 @@ import ( "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/appctx" - "yunion.io/x/onecloud/pkg/cloudprovider" deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis" "yunion.io/x/onecloud/pkg/hostman/hostutils" "yunion.io/x/onecloud/pkg/httperrors" diff --git a/pkg/hostman/storageman/diskhandlers/diskhandler.go b/pkg/hostman/storageman/diskhandlers/diskhandler.go index 7d2a6a6ab6..8d194ec1dc 100644 --- a/pkg/hostman/storageman/diskhandlers/diskhandler.go +++ b/pkg/hostman/storageman/diskhandlers/diskhandler.go @@ -19,6 +19,7 @@ import ( "fmt" "net/http" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -27,7 +28,6 @@ import ( "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/appsrv" "yunion.io/x/onecloud/pkg/cloudcommon/workmanager" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/hostman/guestman" "yunion.io/x/onecloud/pkg/hostman/hostutils" "yunion.io/x/onecloud/pkg/hostman/storageman" diff --git a/pkg/hostman/storageman/imagecache_local.go b/pkg/hostman/storageman/imagecache_local.go index cbe5560bdf..988a1d418e 100644 --- a/pkg/hostman/storageman/imagecache_local.go +++ b/pkg/hostman/storageman/imagecache_local.go @@ -24,13 +24,13 @@ import ( "syscall" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis" api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/hostman/hostutils" "yunion.io/x/onecloud/pkg/hostman/storageman/remotefile" "yunion.io/x/onecloud/pkg/mcclient/auth" diff --git a/pkg/hostman/storageman/imagecachemanager_agent.go b/pkg/hostman/storageman/imagecachemanager_agent.go index 912cdd17ca..5c2069a239 100644 --- a/pkg/hostman/storageman/imagecachemanager_agent.go +++ b/pkg/hostman/storageman/imagecachemanager_agent.go @@ -20,16 +20,16 @@ import ( "path/filepath" "reflect" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/esxi" + "yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" comapi "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/hostman/hostutils" - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/multicloud/esxi/vcenter" ) type SAgentImageCacheManager struct { diff --git a/pkg/hostman/storageman/storage_agent.go b/pkg/hostman/storageman/storage_agent.go index f2022093f4..b85711aaa7 100644 --- a/pkg/hostman/storageman/storage_agent.go +++ b/pkg/hostman/storageman/storage_agent.go @@ -22,6 +22,9 @@ import ( "path/filepath" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/esxi" + "yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -30,14 +33,11 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/agent/iagent" - "yunion.io/x/onecloud/pkg/cloudprovider" deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis" "yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient" "yunion.io/x/onecloud/pkg/hostman/hostutils" "yunion.io/x/onecloud/pkg/hostman/options" modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/multicloud/esxi/vcenter" "yunion.io/x/onecloud/pkg/util/procutils" "yunion.io/x/onecloud/pkg/util/qemuimg" ) diff --git a/pkg/hostman/storageman/storage_local.go b/pkg/hostman/storageman/storage_local.go index 89243c7be4..16e4b47f62 100644 --- a/pkg/hostman/storageman/storage_local.go +++ b/pkg/hostman/storageman/storage_local.go @@ -22,6 +22,7 @@ import ( "path" "time" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -31,7 +32,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" hostapi "yunion.io/x/onecloud/pkg/apis/host" "yunion.io/x/onecloud/pkg/cloudcommon/consts" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/hostman/guestman/desc" deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis" "yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient" diff --git a/pkg/hostman/storageman/storage_nas.go b/pkg/hostman/storageman/storage_nas.go index c21928e80e..08fd6c64fe 100644 --- a/pkg/hostman/storageman/storage_nas.go +++ b/pkg/hostman/storageman/storage_nas.go @@ -19,11 +19,11 @@ import ( "fmt" "path" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/hostman/hostutils" modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" ) diff --git a/pkg/hostman/storageman/storage_rbd.go b/pkg/hostman/storageman/storage_rbd.go index 15b3432c2d..748c4bf0a1 100644 --- a/pkg/hostman/storageman/storage_rbd.go +++ b/pkg/hostman/storageman/storage_rbd.go @@ -20,6 +20,7 @@ import ( "os" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( api "yunion.io/x/onecloud/pkg/apis/compute" hostapi "yunion.io/x/onecloud/pkg/apis/host" - "yunion.io/x/onecloud/pkg/cloudprovider" deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis" "yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient" "yunion.io/x/onecloud/pkg/hostman/hostutils" @@ -124,7 +124,7 @@ func (s *SRbdStorage) GetImgsaveBackupPath() string { return "" } -//Tip Configuration values containing :, @, or = can be escaped with a leading \ character. +// Tip Configuration values containing :, @, or = can be escaped with a leading \ character. func (s *SRbdStorage) getStorageConfString() string { conf := []string{} conf = append(conf, "mon_host="+strings.ReplaceAll(s.MonHost, ",", `\;`)) diff --git a/pkg/image/drivers/s3/minio.go b/pkg/image/drivers/s3/minio.go index 76827d71e4..8b5289c71c 100644 --- a/pkg/image/drivers/s3/minio.go +++ b/pkg/image/drivers/s3/minio.go @@ -20,12 +20,12 @@ import ( "io" "os" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/objectstore" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/onecloud/pkg/apis/image" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" ) type Err string diff --git a/pkg/image/models/images.go b/pkg/image/models/images.go index e99f3e05a4..c5955f20cd 100644 --- a/pkg/image/models/images.go +++ b/pkg/image/models/images.go @@ -519,7 +519,7 @@ func (self *SImage) saveSize(newSize, totalSize int64) error { return nil } -//Image always do probe and customize after save from stream +// Image always do probe and customize after save from stream func (self *SImage) SaveImageFromStream(reader io.Reader, totalSize int64, calChecksum bool) error { localPath := self.GetLocalPath("") diff --git a/pkg/keystone/tokens/handlers.go b/pkg/keystone/tokens/handlers.go index 5543ba443c..b37bf13425 100644 --- a/pkg/keystone/tokens/handlers.go +++ b/pkg/keystone/tokens/handlers.go @@ -120,8 +120,8 @@ type VerifyTokenV2Param struct { // // keystone v2验证token API // -// Responses: -// 200: tokens_AuthenticateV2Output +// Responses: +// 200: tokens_AuthenticateV2Output func verifyTokensV2(ctx context.Context, w http.ResponseWriter, r *http.Request) { params, _, _ := appsrv.FetchEnv(ctx, w, r) tokenStr := params[""] @@ -169,8 +169,8 @@ type VerifyTokenV3Param struct { // // keystone v3验证token API // -// Responses: -// 200: tokens_AuthenticateV3Output +// Responses: +// 200: tokens_AuthenticateV3Output func verifyTokensV3(ctx context.Context, w http.ResponseWriter, r *http.Request) { tokenStr := r.Header.Get(api.AUTH_SUBJECT_TOKEN_HEADER) token, err := verifyCommon(ctx, w, tokenStr) diff --git a/pkg/lbagent/utils/configdir.go b/pkg/lbagent/utils/configdir.go index f8539b9fab..eec454d245 100644 --- a/pkg/lbagent/utils/configdir.go +++ b/pkg/lbagent/utils/configdir.go @@ -42,7 +42,7 @@ type ConfigDirManager struct { // TODO // -// - set active +// - set active func NewConfigDirManager(baseDir string) *ConfigDirManager { return &ConfigDirManager{ baseDir: baseDir, diff --git a/pkg/mcclient/modules/compute/mod_buckets.go b/pkg/mcclient/modules/compute/mod_buckets.go index ad32e137b1..3c4c0de09c 100644 --- a/pkg/mcclient/modules/compute/mod_buckets.go +++ b/pkg/mcclient/modules/compute/mod_buckets.go @@ -20,10 +20,10 @@ import ( "net/http" "strconv" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/errors" api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modulebase" "yunion.io/x/onecloud/pkg/mcclient/modules" diff --git a/pkg/mcclient/modules/compute/mod_cloudproviders.go b/pkg/mcclient/modules/compute/mod_cloudproviders.go index 36279963bf..99b170096d 100644 --- a/pkg/mcclient/modules/compute/mod_cloudproviders.go +++ b/pkg/mcclient/modules/compute/mod_cloudproviders.go @@ -21,6 +21,7 @@ import ( "golang.org/x/net/http/httpproxy" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" @@ -28,7 +29,6 @@ import ( "yunion.io/x/pkg/utils" proxyapi "yunion.io/x/onecloud/pkg/apis/cloudcommon/proxy" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modulebase" "yunion.io/x/onecloud/pkg/mcclient/modules" diff --git a/pkg/mcclient/modules/compute/mod_cloudregions.go b/pkg/mcclient/modules/compute/mod_cloudregions.go index 53e7878347..01f48cceda 100644 --- a/pkg/mcclient/modules/compute/mod_cloudregions.go +++ b/pkg/mcclient/modules/compute/mod_cloudregions.go @@ -17,10 +17,10 @@ package compute import ( "sort" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modulebase" "yunion.io/x/onecloud/pkg/mcclient/modules" diff --git a/pkg/mcclient/options/cloudaccounts.go b/pkg/mcclient/options/cloudaccounts.go index dc8c6e9d1a..43ae7ba26f 100644 --- a/pkg/mcclient/options/cloudaccounts.go +++ b/pkg/mcclient/options/cloudaccounts.go @@ -18,10 +18,10 @@ import ( "fmt" "io/ioutil" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" ) type CloudaccountListOptions struct { diff --git a/pkg/monitor/alerting/ticker.go b/pkg/monitor/alerting/ticker.go index 6b44a55c3e..e85fd55b70 100644 --- a/pkg/monitor/alerting/ticker.go +++ b/pkg/monitor/alerting/ticker.go @@ -21,15 +21,15 @@ import ( ) // Ticker is a ticker to power the alerting scheduler. it's like a time.Ticker, except: -// * it doesn't drop ticks for slow receivers, rather, it queues up. so that callers are in control to instrument what's going on. -// * it automatically ticks every second, which is the right thing in our current design -// * it ticks on second marks or very shortly after. this provides a predictable load pattern -// (this shouldn't cause too much load contention issues because the next steps in the pipeline just process at their own pace) -// * the timestamps are used to mark "last datapoint to query for" and as such, are a configurable amount of seconds in the past -// * because we want to allow: +// - it doesn't drop ticks for slow receivers, rather, it queues up. so that callers are in control to instrument what's going on. +// - it automatically ticks every second, which is the right thing in our current design +// - it ticks on second marks or very shortly after. this provides a predictable load pattern +// (this shouldn't cause too much load contention issues because the next steps in the pipeline just process at their own pace) +// - the timestamps are used to mark "last datapoint to query for" and as such, are a configurable amount of seconds in the past +// - because we want to allow: // - a clean "resume where we left off" and "don't yield ticks we already did" // - adjusting offset over time to compensate for storage backing up or getting fast and providing lower latency -// you specify a lastProcessed timestamp as well as an offset at creation, or runtime +// you specify a lastProcessed timestamp as well as an offset at creation, or runtime type Ticker struct { C chan time.Time clock clock.Clock diff --git a/pkg/monitor/notifydrivers/feishu/types.go b/pkg/monitor/notifydrivers/feishu/types.go index 395bf15a72..cba97124a0 100644 --- a/pkg/monitor/notifydrivers/feishu/types.go +++ b/pkg/monitor/notifydrivers/feishu/types.go @@ -95,7 +95,7 @@ const ( MsgTypeInteractive = "interactive" ) -//定义参照: https://open.feishu.cn/open-apis/message/v4/send/ +// 定义参照: https://open.feishu.cn/open-apis/message/v4/send/ type MsgReq struct { OpenId string `json:"open_id,omitempty"` UserId string `json:"user_id,omitempty"` @@ -158,7 +158,7 @@ type MsgPostContentImage struct { Height float64 `json:"height"` } -//机器人消息Card字段数据格式定义 +// 机器人消息Card字段数据格式定义 type Card struct { Config *CardConfig `json:"config,omitempty"` CardLink *CardElementUrl `json:"card_link,omitempty"` diff --git a/pkg/multicloud/aliyun/access_groups.go b/pkg/multicloud/aliyun/access_groups.go deleted file mode 100644 index 4f1bdd7f6c..0000000000 --- a/pkg/multicloud/aliyun/access_groups.go +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - - alierr "github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SAccessGroup struct { - region *SRegion - - RuleCount int - AccessGroupType string - Description string - AccessGroupName string - MountTargetCount int - FileSystemType string -} - -func (self *SAccessGroup) GetName() string { - return self.AccessGroupName -} - -func (self *SAccessGroup) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.GetFileSystemType(), self.AccessGroupName) -} - -func (self *SAccessGroup) GetFileSystemType() string { - return self.FileSystemType -} - -func (self *SAccessGroup) IsDefault() bool { - return self.AccessGroupName == "DEFAULT_CLASSIC_GROUP_NAME" || self.AccessGroupName == "DEFAULT_VPC_GROUP_NAME" -} - -func (self *SAccessGroup) GetDesc() string { - return self.Description -} - -func (self *SAccessGroup) GetMountTargetCount() int { - return self.MountTargetCount -} - -func (self *SAccessGroup) GetNetworkType() string { - return strings.ToLower(self.AccessGroupType) -} - -func (self *SAccessGroup) GetMaxPriority() int { - return 1 -} - -func (self *SAccessGroup) GetMinPriority() int { - return 100 -} - -func (self *SAccessGroup) Delete() error { - return self.region.DeleteAccessGroup(self.FileSystemType, self.AccessGroupName) -} - -func (self *SAccessGroup) GetSupporedUserAccessTypes() []cloudprovider.TUserAccessType { - return []cloudprovider.TUserAccessType{ - cloudprovider.UserAccessTypeAllSquash, - cloudprovider.UserAccessTypeRootSquash, - cloudprovider.UserAccessTypeNoRootSquash, - } -} - -func (self *SAccessGroup) GetRules() ([]cloudprovider.AccessGroupRule, error) { - rules := []SAccessGroupRule{} - num := 1 - for { - part, total, err := self.region.GetAccessGroupRules(self.AccessGroupName, 50, num) - if err != nil { - return nil, errors.Wrapf(err, "GetAccessGroupRules") - } - rules = append(rules, part...) - if len(rules) >= total { - break - } - } - ret := []cloudprovider.AccessGroupRule{} - for i := range rules { - rule := cloudprovider.AccessGroupRule{ - ExternalId: rules[i].AccessRuleId, - Priority: rules[i].Priority, - Source: rules[i].SourceCidrIp, - } - switch rules[i].RWAccess { - case "RDWR": - rule.RWAccessType = cloudprovider.RWAccessTypeRW - case "RDONLY": - rule.RWAccessType = cloudprovider.RWAccessTypeR - } - switch rules[i].UserAccess { - case "no_squash": - rule.UserAccessType = cloudprovider.UserAccessTypeNoRootSquash - case "root_squash": - rule.UserAccessType = cloudprovider.UserAccessTypeRootSquash - case "all_squash": - rule.UserAccessType = cloudprovider.UserAccessTypeAllSquash - } - ret = append(ret, rule) - } - return ret, nil -} - -func (self *SRegion) getAccessGroups(fsType string, pageSize, pageNum int) ([]SAccessGroup, int, error) { - if pageSize < 1 || pageSize > 100 { - pageSize = 50 - } - if pageNum < 1 { - pageNum = 1 - } - params := map[string]string{ - "RegionId": self.RegionId, - "PageSize": fmt.Sprintf("%d", pageSize), - "PageNumber": fmt.Sprintf("%d", pageNum), - "FileSystemType": fsType, - } - resp, err := self.nasRequest("DescribeAccessGroups", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeAccessGroups") - } - - ret := struct { - TotalCount int - AccessGroups struct { - AccessGroup []SAccessGroup - } - }{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - return ret.AccessGroups.AccessGroup, ret.TotalCount, nil -} - -type SAccessGroupRule struct { - RWAccess string - UserAccess string - Priority int - SourceCidrIp string - AccessRuleId string -} - -func (self *SRegion) GetAccessGroupRules(groupName string, pageSize, pageNum int) ([]SAccessGroupRule, int, error) { - if pageSize < 1 || pageSize > 100 { - pageSize = 50 - } - if pageNum < 1 { - pageNum = 1 - } - params := map[string]string{ - "RegionId": self.RegionId, - "AccessGroupName": groupName, - "PageSize": fmt.Sprintf("%d", pageSize), - "PageNumber": fmt.Sprintf("%d", pageNum), - } - resp, err := self.nasRequest("DescribeAccessRules", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeAccessRules") - } - ret := struct { - TotalCount int - AccessRules struct { - AccessRule []SAccessGroupRule - } - }{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - return ret.AccessRules.AccessRule, ret.TotalCount, nil -} - -func (self *SRegion) GetAccessGroups(fsType string) ([]SAccessGroup, error) { - accessGroups := []SAccessGroup{} - num := 1 - for { - part, total, err := self.getAccessGroups(fsType, 50, num) - if err != nil { - if e, ok := errors.Cause(err).(*alierr.ServerError); ok && e.ErrorCode() == "Region.NotSupported" { - return accessGroups, nil - } - return nil, errors.Wrapf(err, "GetAccessGroups") - } - for i := range part { - part[i].FileSystemType = fsType - accessGroups = append(accessGroups, part[i]) - } - if len(accessGroups) >= total { - break - } - } - return accessGroups, nil -} - -func (self *SRegion) GetICloudAccessGroups() ([]cloudprovider.ICloudAccessGroup, error) { - standardAccessGroups, err := self.GetAccessGroups("standard") - if err != nil { - return nil, errors.Wrapf(err, "GetAccessGroups") - } - extremeAccessGroups, err := self.GetAccessGroups("extreme") - if err != nil { - return nil, errors.Wrapf(err, "GetAccessGroups") - } - ret := []cloudprovider.ICloudAccessGroup{} - for _, accessGroups := range [][]SAccessGroup{standardAccessGroups, extremeAccessGroups} { - for i := range accessGroups { - accessGroups[i].region = self - ret = append(ret, &accessGroups[i]) - } - } - return ret, nil -} - -func (self *SRegion) GetICloudAccessGroupById(id string) (cloudprovider.ICloudAccessGroup, error) { - groups, err := self.GetICloudAccessGroups() - if err != nil { - return nil, errors.Wrapf(err, "self.GetICloudAccessGroups") - } - for i := range groups { - if groups[i].GetGlobalId() == id { - return groups[i], nil - } - } - return nil, errors.Wrapf(err, "GetICloudAccessGroupById(%s)", id) -} - -func (self *SRegion) CreateICloudAccessGroup(opts *cloudprovider.SAccessGroup) (cloudprovider.ICloudAccessGroup, error) { - err := self.CreateAccessGroup(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateAccessGroup") - } - return self.GetICloudAccessGroupById(fmt.Sprintf("%s/%s", opts.FileSystemType, opts.Name)) -} - -func (self *SRegion) CreateAccessGroup(opts *cloudprovider.SAccessGroup) error { - params := map[string]string{ - "RegionId": self.RegionId, - "AccessGroupName": opts.Name, - "AccessGroupType": opts.NetworkType, - "FileSystemType": opts.FileSystemType, - } - _, err := self.nasRequest("CreateAccessGroup", params) - return errors.Wrapf(err, "CreateAccessGroup") -} - -func (self *SRegion) DeleteAccessGroup(fsType, name string) error { - params := map[string]string{ - "RegionId": self.RegionId, - "AccessGroupName": name, - "FileSystemType": fsType, - } - _, err := self.nasRequest("DeleteAccessGroup", params) - return errors.Wrapf(err, "DeleteAccessGroup") -} - -func (self *SRegion) DeleteAccessGroupRule(fsType, groupName, ruleId string) error { - params := map[string]string{ - "RegionId": self.RegionId, - "AccessRuleId": ruleId, - "AccessGroupName": groupName, - "FileSystemType": fsType, - } - _, err := self.nasRequest("DeleteAccessRule", params) - return errors.Wrapf(err, "DeleteAccessRule") -} - -func (self *SRegion) CreateAccessGroupRule(source, fsType, groupName string, rwType cloudprovider.TRWAccessType, userType cloudprovider.TUserAccessType, priority int) error { - params := map[string]string{ - "RegionId": self.RegionId, - "SourceCidrIp": source, - "AccessGroupName": groupName, - "Priority": fmt.Sprintf("%d", priority), - "FileSystemType": fsType, - } - switch rwType { - case cloudprovider.RWAccessTypeR: - params["RWAccessType"] = "RDONLY" - case cloudprovider.RWAccessTypeRW: - params["RWAccessType"] = "RDWR" - } - switch userType { - case cloudprovider.UserAccessTypeAllSquash: - params["UserAccessType"] = "all_squash" - case cloudprovider.UserAccessTypeRootSquash: - params["UserAccessType"] = "root_squash" - case cloudprovider.UserAccessTypeNoRootSquash: - params["UserAccessType"] = "no_squash" - } - _, err := self.nasRequest("CreateAccessRule", params) - return errors.Wrapf(err, "CreateAccessRule") -} - -func (self *SAccessGroup) SyncRules(common, added, removed cloudprovider.AccessGroupRuleSet) error { - for _, rule := range removed { - err := self.region.DeleteAccessGroupRule(self.FileSystemType, self.AccessGroupName, rule.ExternalId) - if err != nil { - return errors.Wrapf(err, "DeleteAccessGroupRule") - } - } - for _, rule := range added { - err := self.region.CreateAccessGroupRule(rule.Source, self.FileSystemType, self.AccessGroupName, rule.RWAccessType, rule.UserAccessType, rule.Priority) - if err != nil { - return errors.Wrapf(err, "CreateAccessGroupRule") - } - } - return nil -} diff --git a/pkg/multicloud/aliyun/bucket.go b/pkg/multicloud/aliyun/bucket.go deleted file mode 100644 index 91ea6e7b0b..0000000000 --- a/pkg/multicloud/aliyun/bucket.go +++ /dev/null @@ -1,778 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - "io" - "net/http" - "strconv" - "strings" - "time" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SBucket struct { - multicloud.SBaseBucket - multicloud.AliyunTags - - region *SRegion - - Name string - Location string - CreationDate time.Time - StorageClass string -} - -func (b *SBucket) GetProjectId() string { - return "" -} - -func (b *SBucket) GetGlobalId() string { - return b.Name -} - -func (b *SBucket) GetName() string { - return b.Name -} - -func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - osscli, err := b.getOssClient() - if err != nil { - log.Errorf("b.region.GetOssClient fail %s", err) - return acl - } - aclResp, err := osscli.GetBucketACL(b.Name) - if err != nil { - log.Errorf("osscli.GetBucketACL fail %s", err) - return acl - } - acl = cloudprovider.TBucketACLType(aclResp.ACL) - return acl -} - -func (b *SBucket) GetLocation() string { - return b.Location -} - -func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { - return b.region -} - -func (b *SBucket) GetCreatedAt() time.Time { - return b.CreationDate -} - -func (b *SBucket) GetStorageClass() string { - return b.StorageClass -} - -func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { - ret := []cloudprovider.SBucketAccessUrl{ - { - Url: fmt.Sprintf("%s.%s", b.Name, b.region.getOSSExternalDomain()), - Description: "ExtranetEndpoint", - Primary: true, - }, - { - Url: fmt.Sprintf("%s.%s", b.Name, b.region.getOSSInternalDomain()), - Description: "IntranetEndpoint", - }, - } - return ret -} - -func (b *SBucket) GetStats() cloudprovider.SBucketStats { - stats, err := cloudprovider.GetIBucketStats(b) - if err != nil { - log.Errorf("GetStats fail %s", err) - } - return stats -} - -func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error { - osscli, err := b.region.GetOssClient() - if err != nil { - log.Errorf("b.region.GetOssClient fail %s", err) - return errors.Wrap(err, "b.region.GetOssClient") - } - acl, err := str2Acl(string(aclStr)) - if err != nil { - return errors.Wrap(err, "str2Acl") - } - err = osscli.SetBucketACL(b.Name, acl) - if err != nil { - return errors.Wrap(err, "SetBucketACL") - } - return nil -} - -func (b *SBucket) getOssClient() (*oss.Client, error) { - if b.region.client.GetAccessEnv() == ALIYUN_FINANCE_CLOUDENV { - osscli, err := b.region.GetOssClient() - if err != nil { - return nil, errors.Wrapf(err, "GetOssClient") - } - info, err := osscli.GetBucketInfo(b.Name) - if err != nil { - return nil, errors.Wrapf(err, "GetBucketInfo") - } - if len(info.BucketInfo.ExtranetEndpoint) > 0 { - return b.region.client.getOssClientByEndpoint(info.BucketInfo.ExtranetEndpoint) - } - } - return b.region.GetOssClient() -} - -func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { - result := cloudprovider.SListObjectResult{} - osscli, err := b.region.GetOssClient() - if err != nil { - return result, errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return result, errors.Wrap(err, "Bucket") - } - opts := make([]oss.Option, 0) - if len(prefix) > 0 { - opts = append(opts, oss.Prefix(prefix)) - } - if len(delimiter) > 0 { - opts = append(opts, oss.Delimiter(delimiter)) - } - if len(marker) > 0 { - opts = append(opts, oss.Marker(marker)) - } - if maxCount > 0 { - opts = append(opts, oss.MaxKeys(maxCount)) - } - oResult, err := bucket.ListObjects(opts...) - if err != nil { - return result, errors.Wrap(err, "ListObjects") - } - result.Objects = make([]cloudprovider.ICloudObject, 0) - for _, object := range oResult.Objects { - obj := &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - StorageClass: object.StorageClass, - Key: object.Key, - SizeBytes: object.Size, - ETag: object.ETag, - LastModified: object.LastModified, - }, - } - result.Objects = append(result.Objects, obj) - } - if oResult.CommonPrefixes != nil { - result.CommonPrefixes = make([]cloudprovider.ICloudObject, len(oResult.CommonPrefixes)) - for i, commPrefix := range oResult.CommonPrefixes { - result.CommonPrefixes[i] = &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{Key: commPrefix}, - } - } - } - result.IsTruncated = oResult.IsTruncated - result.NextMarker = oResult.NextMarker - return result, nil -} - -func metaOpts(opts []oss.Option, meta http.Header) []oss.Option { - for k, v := range meta { - if len(v) == 0 { - continue - } - switch http.CanonicalHeaderKey(k) { - case cloudprovider.META_HEADER_CONTENT_TYPE: - opts = append(opts, oss.ContentType(v[0])) - case cloudprovider.META_HEADER_CONTENT_MD5: - opts = append(opts, oss.ContentMD5(v[0])) - case cloudprovider.META_HEADER_CONTENT_LANGUAGE: - opts = append(opts, oss.ContentLanguage(v[0])) - case cloudprovider.META_HEADER_CONTENT_ENCODING: - opts = append(opts, oss.ContentEncoding(v[0])) - case cloudprovider.META_HEADER_CONTENT_DISPOSITION: - opts = append(opts, oss.ContentDisposition(v[0])) - case cloudprovider.META_HEADER_CACHE_CONTROL: - opts = append(opts, oss.CacheControl(v[0])) - default: - opts = append(opts, oss.Meta(http.CanonicalHeaderKey(k), v[0])) - } - } - return opts -} - -func (b *SBucket) PutObject(ctx context.Context, key string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - osscli, err := b.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return errors.Wrap(err, "Bucket") - } - opts := make([]oss.Option, 0) - if sizeBytes > 0 { - opts = append(opts, oss.ContentLength(sizeBytes)) - } - if meta != nil { - opts = metaOpts(opts, meta) - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - acl, err := str2Acl(string(cannedAcl)) - if err != nil { - return errors.Wrap(err, "") - } - opts = append(opts, oss.ObjectACL(acl)) - if len(storageClassStr) > 0 { - storageClass, err := str2StorageClass(storageClassStr) - if err != nil { - return errors.Wrap(err, "str2StorageClass") - } - opts = append(opts, oss.ObjectStorageClass(storageClass)) - } - return bucket.PutObject(key, input, opts...) -} - -func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - osscli, err := b.region.GetOssClient() - if err != nil { - return "", errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return "", errors.Wrap(err, "Bucket") - } - opts := make([]oss.Option, 0) - if meta != nil { - opts = metaOpts(opts, meta) - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - acl, err := str2Acl(string(cannedAcl)) - if err != nil { - return "", errors.Wrap(err, "str2Acl") - } - opts = append(opts, oss.ObjectACL(acl)) - if len(storageClassStr) > 0 { - storageClass, err := str2StorageClass(storageClassStr) - if err != nil { - return "", errors.Wrap(err, "str2StorageClass") - } - opts = append(opts, oss.ObjectStorageClass(storageClass)) - } - result, err := bucket.InitiateMultipartUpload(key, opts...) - if err != nil { - return "", errors.Wrap(err, "bucket.InitiateMultipartUpload") - } - return result.UploadID, nil -} - -func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { - osscli, err := b.region.GetOssClient() - if err != nil { - return "", errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return "", errors.Wrap(err, "Bucket") - } - imur := oss.InitiateMultipartUploadResult{ - Bucket: b.Name, - Key: key, - UploadID: uploadId, - } - part, err := bucket.UploadPart(imur, input, partSize, partIndex) - if err != nil { - return "", errors.Wrap(err, "bucket.UploadPart") - } - if b.region.client.debug { - log.Debugf("upload part key:%s uploadId:%s partIndex:%d etag:%s", key, uploadId, partIndex, part.ETag) - } - return part.ETag, nil -} - -func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { - osscli, err := b.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return errors.Wrap(err, "Bucket") - } - imur := oss.InitiateMultipartUploadResult{ - Bucket: b.Name, - Key: key, - UploadID: uploadId, - } - parts := make([]oss.UploadPart, len(partEtags)) - for i := range partEtags { - parts[i] = oss.UploadPart{ - PartNumber: i + 1, - ETag: partEtags[i], - } - } - result, err := bucket.CompleteMultipartUpload(imur, parts) - if err != nil { - return errors.Wrap(err, "bucket.CompleteMultipartUpload") - } - if b.region.client.debug { - log.Debugf("CompleteMultipartUpload bucket:%s key:%s etag:%s location:%s", result.Bucket, result.Key, result.ETag, result.Location) - } - return nil -} - -func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { - osscli, err := b.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return errors.Wrap(err, "Bucket") - } - imur := oss.InitiateMultipartUploadResult{ - Bucket: b.Name, - Key: key, - UploadID: uploadId, - } - err = bucket.AbortMultipartUpload(imur) - if err != nil { - return errors.Wrap(err, "AbortMultipartUpload") - } - return nil -} - -func (b *SBucket) DeleteObject(ctx context.Context, key string) error { - osscli, err := b.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return errors.Wrap(err, "Bucket") - } - err = bucket.DeleteObject(key) - if err != nil { - return errors.Wrap(err, "DeleteObject") - } - return nil -} - -func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { - if method != "GET" && method != "PUT" && method != "DELETE" { - return "", errors.Error("unsupported method") - } - osscli, err := b.region.GetOssClient() - if err != nil { - return "", errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return "", errors.Wrap(err, "Bucket") - } - urlStr, err := bucket.SignURL(key, oss.HTTPMethod(method), int64(expire/time.Second)) - if err != nil { - return "", errors.Wrap(err, "SignURL") - } - return urlStr, nil -} - -func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - osscli, err := b.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return errors.Wrap(err, "Bucket") - } - opts := make([]oss.Option, 0) - if meta != nil { - opts = metaOpts(opts, meta) - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - acl, err := str2Acl(string(cannedAcl)) - if err != nil { - return errors.Wrap(err, "str2Acl") - } - opts = append(opts, oss.ObjectACL(acl)) - if len(storageClassStr) > 0 { - storageClass, err := str2StorageClass(storageClassStr) - if err != nil { - return errors.Wrap(err, "str2StorageClass") - } - opts = append(opts, oss.ObjectStorageClass(storageClass)) - } - _, err = bucket.CopyObjectFrom(srcBucket, srcKey, destKey, opts...) - if err != nil { - return errors.Wrap(err, "CopyObjectFrom") - } - return nil -} - -func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { - osscli, err := b.region.GetOssClient() - if err != nil { - return nil, errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return nil, errors.Wrap(err, "Bucket") - } - opts := make([]oss.Option, 0) - if rangeOpt != nil { - opts = append(opts, oss.NormalizedRange(rangeOpt.String())) - } - output, err := bucket.GetObject(key, opts...) - if err != nil { - return nil, errors.Wrap(err, "bucket.GetObject") - } - return output, nil -} - -func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partNumber int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { - osscli, err := b.region.GetOssClient() - if err != nil { - return "", errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return "", errors.Wrap(err, "Bucket") - } - imur := oss.InitiateMultipartUploadResult{ - Bucket: b.Name, - Key: key, - UploadID: uploadId, - } - opts := make([]oss.Option, 0) - part, err := bucket.UploadPartCopy(imur, srcBucket, srcKey, srcOffset, srcLength, partNumber, opts...) - if err != nil { - return "", errors.Wrap(err, "bucket.UploadPartCopy") - } - return part.ETag, nil -} - -func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { - if len(websitConf.Index) == 0 { - return errors.Wrap(cloudprovider.ErrNotSupported, "missing Index") - } - if len(websitConf.ErrorDocument) == 0 { - return errors.Wrap(cloudprovider.ErrNotSupported, "missing ErrorDocument") - } - osscli, err := b.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - - err = osscli.SetBucketWebsite(b.Name, websitConf.Index, websitConf.ErrorDocument) - if err != nil { - return errors.Wrapf(err, " osscli.SetBucketWebsite(%s,%s,%s)", b.Name, websitConf.Index, websitConf.ErrorDocument) - } - return nil -} - -func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { - result := cloudprovider.SBucketWebsiteConf{} - osscli, err := b.region.GetOssClient() - if err != nil { - return result, errors.Wrap(err, "GetOssClient") - } - websiteResult, err := osscli.GetBucketWebsite(b.Name) - if err != nil { - if strings.Contains(err.Error(), "NoSuchWebsiteConfiguration") { - return cloudprovider.SBucketWebsiteConf{}, nil - } - return result, errors.Wrapf(err, "osscli.GetBucketWebsite(%s)", b.Name) - } - result.Index = websiteResult.IndexDocument.Suffix - result.ErrorDocument = websiteResult.ErrorDocument.Key - return result, nil -} - -func (b *SBucket) DeleteWebSiteConf() error { - osscli, err := b.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - log.Infof("to be delete") - err = osscli.DeleteBucketWebsite(b.Name) - if err != nil { - return errors.Wrapf(err, "osscli.DeleteBucketWebsite(%s)", b.Name) - } - log.Infof("deleted") - return nil -} - -func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { - if len(rules) == 0 { - return nil - } - osscli, err := b.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - input := []oss.CORSRule{} - for i := range rules { - input = append(input, oss.CORSRule{ - AllowedOrigin: rules[i].AllowedOrigins, - AllowedMethod: rules[i].AllowedMethods, - AllowedHeader: rules[i].AllowedHeaders, - MaxAgeSeconds: rules[i].MaxAgeSeconds, - ExposeHeader: rules[i].ExposeHeaders, - }) - } - - err = osscli.SetBucketCORS(b.Name, input) - if err != nil { - return errors.Wrapf(err, "osscli.SetBucketCORS(%s,%s)", b.Name, jsonutils.Marshal(input).String()) - } - return nil -} - -func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { - osscli, err := b.region.GetOssClient() - if err != nil { - return nil, errors.Wrap(err, "GetOssClient") - } - conf, err := osscli.GetBucketCORS(b.Name) - if err != nil { - if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") { - return nil, errors.Wrapf(err, "osscli.GetBucketCORS(%s)", b.Name) - } - } - result := []cloudprovider.SBucketCORSRule{} - for i := range conf.CORSRules { - result = append(result, cloudprovider.SBucketCORSRule{ - AllowedOrigins: conf.CORSRules[i].AllowedOrigin, - AllowedMethods: conf.CORSRules[i].AllowedMethod, - AllowedHeaders: conf.CORSRules[i].AllowedHeader, - MaxAgeSeconds: conf.CORSRules[i].MaxAgeSeconds, - ExposeHeaders: conf.CORSRules[i].ExposeHeader, - Id: strconv.Itoa(i), - }) - } - return result, nil -} - -func (b *SBucket) DeleteCORS() error { - osscli, err := b.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - - err = osscli.DeleteBucketCORS(b.Name) - if err != nil { - return errors.Wrapf(err, "osscli.DeleteBucketCORS(%s)", b.Name) - } - - return nil -} - -func (b *SBucket) SetReferer(conf cloudprovider.SBucketRefererConf) error { - osscli, err := b.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - if !conf.Enabled { - return errors.Wrapf(cloudprovider.ErrNotSupported, "Disable Refer") - } - - if conf.RefererType == "Black-List" { - return errors.Wrapf(cloudprovider.ErrNotSupported, "Black List") - } - - err = osscli.SetBucketReferer(b.Name, conf.DomainList, conf.AllowEmptyRefer) - if err != nil { - return errors.Wrapf(err, "osscli.SetBucketReferer(%s,%s,%t)", b.Name, conf.DomainList, conf.AllowEmptyRefer) - } - return nil -} - -func (b *SBucket) GetReferer() (cloudprovider.SBucketRefererConf, error) { - result := cloudprovider.SBucketRefererConf{} - osscli, err := b.region.GetOssClient() - if err != nil { - return result, errors.Wrap(err, "GetOssClient") - } - refererResult, err := osscli.GetBucketReferer(b.Name) - if err != nil { - return result, errors.Wrapf(err, "osscli.GetBucketReferer(%s)", b.Name) - } - result = cloudprovider.SBucketRefererConf{ - Enabled: true, - RefererType: "White-List", - DomainList: refererResult.RefererList, - AllowEmptyRefer: refererResult.AllowEmptyReferer, - } - return result, nil -} - -func toAPICdnArea(area string) string { - switch area { - case "domestic": - return api.CDN_DOMAIN_AREA_MAINLAND - case "overseas": - return api.CDN_DOMAIN_AREA_OVERSEAS - case "global": - return api.CDN_DOMAIN_AREA_GLOBAL - default: - return "" - } -} - -func toAPICdnStatus(status string) string { - switch status { - case "online": - return api.CDN_DOMAIN_STATUS_ONLINE - case "offline": - return api.CDN_DOMAIN_STATUS_OFFLINE - case "configuring", "checking", "stopping", "deleting": - return api.CDN_DOMAIN_STATUS_PROCESSING - case "check_failed", "configure_failed": - return api.CDN_DOMAIN_STATUS_REJECTED - default: - return "" - } -} - -func (b *SBucket) GetCdnDomains() ([]cloudprovider.SCdnDomain, error) { - bucketExtUrl := fmt.Sprintf("%s.%s", b.Name, b.region.getOSSExternalDomain()) - cdnDomains, err := b.region.client.DescribeDomainsBySource(bucketExtUrl) - if err != nil { - return nil, errors.Wrapf(err, " b.region.client.DescribeDomainsBySource(%s)", bucketExtUrl) - } - result := []cloudprovider.SCdnDomain{} - for i := range cdnDomains.DomainsData { - if cdnDomains.DomainsData[i].Source == bucketExtUrl { - for j := range cdnDomains.DomainsData[i].Domains.DomainNames { - area := "" - domain, _ := b.region.client.GetCDNDomainByName(cdnDomains.DomainsData[i].Domains.DomainNames[j]) - if domain != nil { - area = domain.Coverage - } - result = append(result, cloudprovider.SCdnDomain{ - Domain: cdnDomains.DomainsData[i].Domains.DomainNames[j], - Status: toAPICdnStatus(cdnDomains.DomainsData[i].DomainInfos.DomainInfo[j].Status), - Cname: cdnDomains.DomainsData[i].DomainInfos.DomainInfo[j].DomainCname, - Area: toAPICdnArea(area), - Origin: bucketExtUrl, - OriginType: api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET, - }) - } - } - } - return result, nil -} - -func (b *SBucket) GetTags() (map[string]string, error) { - osscli, err := b.region.GetOssClient() - if err != nil { - return nil, errors.Wrap(err, "GetOssClient") - } - - tagresult, err := osscli.GetBucketTagging(b.Name) - if err != nil { - return nil, errors.Wrapf(err, "GetBucketTagging %s", b.Name) - } - result := map[string]string{} - for _, tag := range tagresult.Tags { - result[tag.Key] = tag.Value - } - return result, nil -} - -func (b *SBucket) SetTags(tags map[string]string, replace bool) error { - osscli, err := b.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - - err = osscli.DeleteBucketTagging(b.Name) - if err != nil { - return errors.Wrapf(err, "DeleteBucketTagging(%s)", b.Name) - } - - if len(tags) == 0 { - return nil - } - - input := []oss.Tag{} - for k, v := range tags { - input = append(input, oss.Tag{Key: k, Value: v}) - } - - err = osscli.SetBucketTagging(b.Name, oss.Tagging{Tags: input}) - if err != nil { - return errors.Wrapf(err, "osscli.SetBucketTagging(%s)", jsonutils.Marshal(input)) - } - return nil -} - -func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { - osscli, err := b.region.GetOssClient() - if err != nil { - return nil, errors.Wrap(err, "GetOssClient") - } - result := []cloudprovider.SBucketMultipartUploads{} - - ossBucket, err := osscli.Bucket(b.Name) - if err != nil { - return nil, errors.Wrap(err, "osscli.Bucket(b.Name)") - } - - keyMarker := oss.KeyMarker("") - uploadIDMarker := oss.UploadIDMarker("") - for { - output, err := ossBucket.ListMultipartUploads(keyMarker, uploadIDMarker) - if err != nil { - return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") - } - for i := range output.Uploads { - temp := cloudprovider.SBucketMultipartUploads{ - ObjectName: output.Uploads[i].Key, - UploadID: output.Uploads[i].UploadID, - Initiated: output.Uploads[i].Initiated, - } - result = append(result, temp) - } - keyMarker = oss.KeyMarker(output.NextKeyMarker) - uploadIDMarker = oss.UploadIDMarker(output.NextUploadIDMarker) - if !output.IsTruncated { - break - } - } - - return result, nil -} diff --git a/pkg/multicloud/aliyun/business.go b/pkg/multicloud/aliyun/business.go deleted file mode 100644 index daf68f4ede..0000000000 --- a/pkg/multicloud/aliyun/business.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -func (self *SAliyunClient) businessRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - cli, err := self.getDefaultClient() - if err != nil { - return nil, err - } - return jsonRequest(cli, "business.aliyuncs.com", ALIYUN_BSS_API_VERSION, apiName, params, self.debug) -} - -type SAccountBalance struct { - AvailableAmount float64 - AvailableCashAmount float64 - CreditAmount float64 - MybankCreditAmount float64 - Currency string -} - -type SCashCoupon struct { - ApplicableProducts string - ApplicableScenarios string - Balance float64 - CashCouponId string - CashCouponNo string - EffectiveTime time.Time - ExpiryTime time.Time - GrantedTime time.Time - NominalValue float64 - Status string -} - -type SPrepaidCard struct { - PrepaidCardId string - PrepaidCardNo string - GrantedTime time.Time - EffectiveTime time.Time - ExpiryTime time.Time - NominalValue float64 - Balance float64 - ApplicableProducts string - ApplicableScenarios string -} - -func (self *SAliyunClient) QueryAccountBalance() (*SAccountBalance, error) { - body, err := self.businessRequest("QueryAccountBalance", nil) - if err != nil { - // {"RequestId":"5258BDEF-8975-4EB0-9E0C-08D5E54E7981","HostId":"business.aliyuncs.com","Code":"NotAuthorized","Message":"This API is not authorized for caller."} - if isError(err, "NotApplicable") || isError(err, "NotAuthorized") { - return nil, cloudprovider.ErrNoBalancePermission - } - return nil, errors.Wrapf(err, "QueryAccountBalance") - } - balance := SAccountBalance{} - err = body.Unmarshal(&balance, "Data") - if err != nil { - return nil, errors.Wrapf(err, "Unmarshal AccountBalance") - } - return &balance, nil -} - -func (self *SAliyunClient) QueryCashCoupons() ([]SCashCoupon, error) { - params := make(map[string]string) - params["EffectiveOrNot"] = "True" - body, err := self.businessRequest("QueryCashCoupons", params) - if err != nil { - return nil, errors.Wrapf(err, "QueryCashCoupons") - } - coupons := make([]SCashCoupon, 0) - err = body.Unmarshal(&coupons, "Data", "CashCoupon") - if err != nil { - return nil, errors.Wrapf(err, "body.Unmarshal") - } - return coupons, nil -} - -func (self *SAliyunClient) QueryPrepaidCards() ([]SPrepaidCard, error) { - params := make(map[string]string) - params["EffectiveOrNot"] = "True" - body, err := self.businessRequest("QueryPrepaidCards", params) - if err != nil { - return nil, errors.Wrapf(err, "QueryPrepaidCards") - } - cards := make([]SPrepaidCard, 0) - err = body.Unmarshal(&cards, "Data", "PrepaidCard") - if err != nil { - return nil, errors.Wrapf(err, "body.Unmarshal") - } - return cards, nil -} - -func (self *SAliyunClient) SubscribeBillToOSS(bucket string) error { - params := make(map[string]string) - params["SubscribeBucket"] = bucket - params["SubscribeType.0"] = "BillingItemDetailForBillingPeriod" - params["SubscribeType.1"] = "InstanceDetailForBillingPeriod" - body, err := self.businessRequest("SubscribeBillToOSS", params) - if err != nil { - return errors.Wrap(err, "SubscribeBillToOSS") - } - log.Debugf("%s", body) - return nil -} diff --git a/pkg/multicloud/aliyun/cdn.go b/pkg/multicloud/aliyun/cdn.go deleted file mode 100644 index 4bd192c2ce..0000000000 --- a/pkg/multicloud/aliyun/cdn.go +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SCdnDomainNames struct { - DomainNames []string `json:"domainNames"` -} - -type SDomainInfo struct { - DomainCname string `json:"DomainCname"` - Status string `json:"Status"` - CreateTime time.Time `json:"CreateTime"` - UpdateTime time.Time `json:"UpdateTime"` - DomainName string `json:"DomainName"` -} - -type SCdnDomainInfos struct { - DomainInfo []SDomainInfo `json:"domainInfo"` -} - -type SCdnDomainsData struct { - Source string `json:"Source"` - Domains SCdnDomainNames `json:"Domains"` - DomainInfos SCdnDomainInfos `json:"DomainInfos"` -} - -type SCdnDomainsList struct { - DomainsData []SCdnDomainsData `json:"DomainsData"` -} - -type SCdnSource struct { - Port int `json:"Port"` - Weight string `json:"Weight"` - Type string `json:"Type"` - Content string `json:"Content"` - Priority string `json:"Priority"` -} - -type SCdnSources struct { - Source []SCdnSource `json:"Source"` -} - -type SCdnDomain struct { - multicloud.SResourceBase - - client *SAliyunClient - - Cname string `json:"Cname"` - Description string `json:"Description"` - CdnType string `json:"CdnType"` - ResourceGroupID string `json:"ResourceGroupId"` - DomainStatus string `json:"DomainStatus"` - SslProtocol string `json:"SslProtocol"` - DomainName string `json:"DomainName"` - Coverage string `json:"Coverage"` - Sources SCdnSource `json:"Sources"` - GmtModified string `json:"GmtModified"` - Sandbox string `json:"Sandbox"` - GmtCreated time.Time `json:"GmtCreated"` - SourceModels struct { - SourceModel []struct { - Content string - Type string - Port int - Enabled string - Priority int - Weight string - } - } -} - -func (self *SCdnDomain) GetArea() string { - switch self.Coverage { - case "domestic": - return api.CDN_DOMAIN_AREA_MAINLAND - case "global": - return api.CDN_DOMAIN_AREA_GLOBAL - case "overseas": - return api.CDN_DOMAIN_AREA_OVERSEAS - default: - return self.Coverage - } -} - -func (self *SCdnDomain) GetCname() string { - return self.Cname -} - -func (self *SCdnDomain) GetEnabled() bool { - return self.DomainStatus != "offline" -} - -func (self *SCdnDomain) GetId() string { - return self.DomainName -} - -func (self *SCdnDomain) GetGlobalId() string { - return self.DomainName -} - -func (self *SCdnDomain) GetName() string { - return self.DomainName -} - -func (self *SCdnDomain) Refresh() error { - domain, err := self.client.GetCdnDomain(self.DomainName) - if err != nil { - return errors.Wrapf(err, "GetCdnDomain") - } - self.DomainStatus = domain.DomainStatus - return nil -} - -func (self *SCdnDomain) GetTags() (map[string]string, error) { - _, tags, err := self.client.GetRegion("").ListSysAndUserTags(ALIYUN_SERVICE_CDN, "DOMAIN", self.DomainName) - if err != nil { - return nil, errors.Wrapf(err, "ListTags") - } - tagMaps := map[string]string{} - for k, v := range tags { - tagMaps[strings.ToLower(k)] = v - } - return tagMaps, nil -} - -func (self *SCdnDomain) GetSysTags() map[string]string { - tags, _, err := self.client.GetRegion("").ListSysAndUserTags(ALIYUN_SERVICE_CDN, "DOMAIN", self.DomainName) - if err != nil { - return nil - } - tagMaps := map[string]string{} - for k, v := range tags { - tagMaps[strings.ToLower(k)] = v - } - return tagMaps -} - -func (self *SCdnDomain) SetTags(tags map[string]string, replace bool) error { - return self.client.GetRegion("").SetResourceTags(ALIYUN_SERVICE_CDN, "DOMAIN", self.DomainName, tags, replace) -} - -func (self *SCdnDomain) GetOrigins() *cloudprovider.SCdnOrigins { - domain, err := self.client.GetCdnDomain(self.DomainName) - if err != nil { - return nil - } - ret := cloudprovider.SCdnOrigins{} - for _, origin := range domain.SourceModels.SourceModel { - ret = append(ret, cloudprovider.SCdnOrigin{ - Type: origin.Type, - Origin: origin.Content, - Port: origin.Port, - Enabled: origin.Enabled, - Priority: origin.Priority, - }) - } - return &ret -} - -func (self *SCdnDomain) GetServiceType() string { - return self.CdnType -} - -func (self *SCdnDomain) GetStatus() string { - switch self.DomainStatus { - case "online", "offline": - return self.DomainStatus - case "configuring", "checking": - return api.CDN_DOMAIN_STATUS_PROCESSING - case "configure_failed": - return self.DomainStatus - case "check_failed": - return api.CDN_DOMAIN_STATUS_REJECTED - } - return self.DomainStatus -} - -func (self *SCdnDomain) Delete() error { - params := map[string]string{ - "DomainName": self.DomainName, - } - _, err := self.client.cdnRequest("DeleteCdnDomain", params) - return errors.Wrapf(err, "DeleteCdnDomain") -} - -func (self *SAliyunClient) GetICloudCDNDomains() ([]cloudprovider.ICloudCDNDomain, error) { - domains, err := self.GetCdnDomains() - if err != nil { - return nil, errors.Wrapf(err, "GetCdnDomains") - } - ret := []cloudprovider.ICloudCDNDomain{} - for i := range domains { - domains[i].client = self - ret = append(ret, &domains[i]) - } - return ret, nil -} - -func (self *SAliyunClient) GetICloudCDNDomainByName(name string) (cloudprovider.ICloudCDNDomain, error) { - return self.GetCDNDomainByName(name) -} - -func (self *SAliyunClient) GetCDNDomainByName(name string) (*SCdnDomain, error) { - domains, total, err := self.DescribeUserDomains(name, 1, 1) - if err != nil { - return nil, errors.Wrapf(err, "GetCdnDomain") - } - if total == 1 { - domains[0].client = self - return &domains[0], nil - } - if total == 0 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) - } - return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, name) -} - -func (client *SAliyunClient) DescribeDomainsBySource(origin string) (SCdnDomainsList, error) { - sproducts := SCdnDomainsList{} - params := map[string]string{} - params["Action"] = "DescribeDomainsBySource" - params["Sources"] = origin - resp, err := client.cdnRequest("DescribeDomainsBySource", params) - if err != nil { - return sproducts, errors.Wrap(err, "DescribeDomainsBySource") - } - err = resp.Unmarshal(&sproducts, "DomainsList") - if err != nil { - return sproducts, errors.Wrap(err, "resp.Unmarshal") - } - return sproducts, nil -} - -func (self *SAliyunClient) GetCdnDomains() ([]SCdnDomain, error) { - domains := []SCdnDomain{} - for { - part, total, err := self.DescribeUserDomains("", 50, len(domains)/50+1) - if err != nil { - return nil, errors.Wrapf(err, "DescribeUserDomains") - } - domains = append(domains, part...) - if len(domains) >= total || len(part) == 0 { - break - } - } - return domains, nil -} - -func (client *SAliyunClient) DescribeUserDomains(domain string, pageSize, pageNumber int) ([]SCdnDomain, int, error) { - if pageSize < 1 || pageSize > 50 { - pageSize = 50 - } - if pageNumber < 1 { - pageNumber = 1 - } - params := map[string]string{ - "PageSize": fmt.Sprintf("%d", pageSize), - "PageNumber": fmt.Sprintf("%d", pageNumber), - } - if len(domain) > 0 { - params["DomainName"] = domain - params["DomainSearchType"] = "full_match" - } - resp, err := client.cdnRequest("DescribeUserDomains", params) - if err != nil { - return nil, 0, errors.Wrap(err, "DescribeUserDomains") - } - domains := []SCdnDomain{} - err = resp.Unmarshal(&domains, "Domains", "PageData") - if err != nil { - return nil, 0, errors.Wrap(err, "resp.Unmarshal") - } - totalCount, _ := resp.Int("TotalCount") - return domains, int(totalCount), nil -} - -func (self *SAliyunClient) GetCdnDomain(domainName string) (*SCdnDomain, error) { - params := map[string]string{ - "DomainName": domainName, - } - resp, err := self.cdnRequest("DescribeCdnDomainDetail", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeCdnDomainDetail") - } - domain := &SCdnDomain{client: self} - err = resp.Unmarshal(domain, "GetDomainDetailModel") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return domain, nil -} diff --git a/pkg/multicloud/aliyun/charge.go b/pkg/multicloud/aliyun/charge.go deleted file mode 100644 index 5d2504e8cd..0000000000 --- a/pkg/multicloud/aliyun/charge.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "time" - - api "yunion.io/x/onecloud/pkg/apis/billing" -) - -func convertChargeType(ct TChargeType) string { - switch ct { - case PrePaidInstanceChargeType, PrePaidDBInstanceChargeType: - return api.BILLING_TYPE_PREPAID - case PostPaidInstanceChargeType, PostPaidDBInstanceChargeType: - return api.BILLING_TYPE_POSTPAID - default: - return "" - } -} - -func convertExpiredAt(expired time.Time) time.Time { - if !expired.IsZero() { - now := time.Now() - if expired.Sub(now) < time.Hour*24*365*6 { - return expired - } - } - return time.Time{} -} diff --git a/pkg/multicloud/aliyun/cloud_enterprise_network.go b/pkg/multicloud/aliyun/cloud_enterprise_network.go deleted file mode 100644 index 5efbe7cd4a..0000000000 --- a/pkg/multicloud/aliyun/cloud_enterprise_network.go +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "strconv" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SCen struct { - multicloud.SResourceBase - multicloud.AliyunTags - client *SAliyunClient - Status string `json:"Status"` - ProtectionLevel string `json:"ProtectionLevel"` - CenID string `json:"CenId"` - CreationTime string `json:"CreationTime"` - CenBandwidthPackageIds CenBandwidthPackageIds `json:"CenBandwidthPackageIds"` - Name string `json:"Name"` -} - -type SCens struct { - TotalCount int `json:"TotalCount"` - RequestID string `json:"RequestId"` - PageSize int `json:"PageSize"` - PageNumber int `json:"PageNumber"` - Cens sCens `json:"Cens"` -} - -type CenBandwidthPackageIds struct { - CenBandwidthPackageID []string `json:"CenBandwidthPackageId"` -} - -type sCens struct { - Cen []SCen `json:"Cen"` -} - -type SCenChildInstances struct { - PageNumber int `json:"PageNumber"` - ChildInstances sCenChildInstances `json:"ChildInstances"` - TotalCount int `json:"TotalCount"` - PageSize int `json:"PageSize"` - RequestID string `json:"RequestId"` -} - -type SCenChildInstance struct { - Status string `json:"Status"` - ChildInstanceOwnerID string `json:"ChildInstanceOwnerId"` - ChildInstanceID string `json:"ChildInstanceId"` - ChildInstanceRegionID string `json:"ChildInstanceRegionId"` - CenID string `json:"CenId"` - ChildInstanceType string `json:"ChildInstanceType"` -} - -type sCenChildInstances struct { - ChildInstance []SCenChildInstance `json:"ChildInstance"` -} - -type SCenAttachInstanceInput struct { - InstanceType string - InstanceId string - InstanceRegion string - ChildInstanceOwnerId string -} - -func (client *SAliyunClient) DescribeCens(pageNumber int, pageSize int) (SCens, error) { - scens := SCens{} - params := map[string]string{} - params["Action"] = "DescribeCens" - params["PageNumber"] = strconv.Itoa(pageNumber) - params["PageSize"] = strconv.Itoa(pageSize) - resp, err := client.cbnRequest("DescribeCens", params) - if err != nil { - return scens, errors.Wrap(err, "DescribeCens") - } - err = resp.Unmarshal(&scens) - if err != nil { - return scens, errors.Wrap(err, "resp.Unmarshal") - } - return scens, nil -} - -func (client *SAliyunClient) GetAllCens() ([]SCen, error) { - pageNumber := 0 - sCen := []SCen{} - for { - pageNumber++ - cens, err := client.DescribeCens(pageNumber, 20) - if err != nil { - return nil, errors.Wrapf(err, "client.DescribeCens(%d, 20)", pageNumber) - } - sCen = append(sCen, cens.Cens.Cen...) - if len(sCen) >= cens.TotalCount { - break - } - } - for i := 0; i < len(sCen); i++ { - sCen[i].client = client - } - return sCen, nil -} - -func (client *SAliyunClient) CreateCen(opts *cloudprovider.SInterVpcNetworkCreateOptions) (string, error) { - params := map[string]string{} - params["Name"] = opts.Name - params["Description"] = opts.Desc - resp, err := client.cbnRequest("CreateCen", params) - if err != nil { - return "", errors.Wrap(err, "CreateCen") - } - type CentId struct { - CenId string `json:"CenId"` - } - centId := CentId{} - err = resp.Unmarshal(¢Id) - if err != nil { - return "", errors.Wrap(err, "resp.Unmarshal") - } - return centId.CenId, nil -} - -func (client *SAliyunClient) DeleteCen(id string) error { - params := map[string]string{} - params["CenId"] = id - _, err := client.cbnRequest("DeleteCen", params) - if err != nil { - return errors.Wrap(err, "DeleteCen") - } - return nil -} - -func (client *SAliyunClient) DescribeCenAttachedChildInstances(cenId string, pageNumber int, pageSize int) (SCenChildInstances, error) { - scenChilds := SCenChildInstances{} - params := map[string]string{} - params["CenId"] = cenId - params["PageNumber"] = strconv.Itoa(pageNumber) - params["PageSize"] = strconv.Itoa(pageSize) - resp, err := client.cbnRequest("DescribeCenAttachedChildInstances", params) - if err != nil { - return scenChilds, errors.Wrap(err, "DescribeCenAttachedChildInstances") - } - err = resp.Unmarshal(&scenChilds) - if err != nil { - return scenChilds, errors.Wrap(err, "resp.Unmarshal") - } - return scenChilds, nil -} - -func (client *SAliyunClient) GetAllCenAttachedChildInstances(cenId string) ([]SCenChildInstance, error) { - pageNumber := 0 - scenChilds := []SCenChildInstance{} - for { - pageNumber++ - cenChilds, err := client.DescribeCenAttachedChildInstances(cenId, pageNumber, 20) - if err != nil { - return nil, errors.Wrapf(err, "client.DescribeCens(%d, 20)", pageNumber) - } - scenChilds = append(scenChilds, cenChilds.ChildInstances.ChildInstance...) - if len(scenChilds) >= cenChilds.TotalCount { - break - } - } - return scenChilds, nil -} - -func (client *SAliyunClient) AttachCenChildInstance(cenId string, instance SCenAttachInstanceInput) error { - params := map[string]string{} - params["CenId"] = cenId - params["ChildInstanceId"] = instance.InstanceId - params["ChildInstanceRegionId"] = instance.InstanceRegion - params["ChildInstanceType"] = instance.InstanceType - params["ChildInstanceOwnerId"] = instance.ChildInstanceOwnerId - _, err := client.cbnRequest("AttachCenChildInstance", params) - if err != nil { - return errors.Wrap(err, "AttachCenChildInstance") - } - return nil -} - -func (client *SAliyunClient) DetachCenChildInstance(cenId string, instance SCenAttachInstanceInput) error { - params := map[string]string{} - params["CenId"] = cenId - params["ChildInstanceId"] = instance.InstanceId - params["ChildInstanceRegionId"] = instance.InstanceRegion - params["ChildInstanceType"] = instance.InstanceType - params["ChildInstanceOwnerId"] = instance.ChildInstanceOwnerId - _, err := client.cbnRequest("DetachCenChildInstance", params) - if err != nil { - return errors.Wrap(err, "DetachCenChildInstance") - } - return nil -} - -func (self *SCen) GetId() string { - return self.CenID -} - -func (self *SCen) GetName() string { - return self.Name -} - -func (self *SCen) GetGlobalId() string { - return self.GetId() -} - -func (self *SCen) GetStatus() string { - switch self.Status { - case "Creating": - return api.INTER_VPC_NETWORK_STATUS_CREATING - case "Active": - return api.INTER_VPC_NETWORK_STATUS_AVAILABLE - case "Deleting": - return api.INTER_VPC_NETWORK_STATUS_DELETING - default: - return api.INTER_VPC_NETWORK_STATUS_UNKNOWN - } -} - -func (self *SCen) Refresh() error { - scens, err := self.client.GetAllCens() - if err != nil { - return errors.Wrap(err, "self.client.GetAllCens()") - } - for i := range scens { - if scens[i].CenID == self.CenID { - return jsonutils.Update(self, scens[i]) - } - } - return cloudprovider.ErrNotFound -} - -func (self *SCen) GetAuthorityOwnerId() string { - return self.client.ownerId -} - -func (self *SCen) GetICloudVpcIds() ([]string, error) { - childs, err := self.client.GetAllCenAttachedChildInstances(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "self.client.GetAllCenAttachedChildInstances(self.GetId())") - } - vpcIds := []string{} - for i := range childs { - if childs[i].ChildInstanceType == "VPC" { - vpcIds = append(vpcIds, childs[i].ChildInstanceID) - } - } - return vpcIds, nil -} - -func (self *SCen) AttachVpc(opts *cloudprovider.SInterVpcNetworkAttachVpcOption) error { - instance := SCenAttachInstanceInput{ - InstanceType: "VPC", - InstanceId: opts.VpcId, - InstanceRegion: opts.VpcRegionId, - ChildInstanceOwnerId: opts.VpcAuthorityOwnerId, - } - err := self.client.AttachCenChildInstance(self.GetId(), instance) - if err != nil { - return errors.Wrapf(err, "self.client.AttachCenChildInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) - } - return nil -} - -func (self *SCen) DetachVpc(opts *cloudprovider.SInterVpcNetworkDetachVpcOption) error { - instance := SCenAttachInstanceInput{ - InstanceType: "VPC", - InstanceId: opts.VpcId, - InstanceRegion: opts.VpcRegionId, - ChildInstanceOwnerId: opts.VpcAuthorityOwnerId, - } - err := self.client.DetachCenChildInstance(self.GetId(), instance) - if err != nil { - return errors.Wrapf(err, "self.client.DetachCenChildInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) - } - return nil -} - -func (self *SCen) Delete() error { - err := self.client.DeleteCen(self.GetId()) - if err != nil { - return errors.Wrapf(err, "self.client.DeleteCen(%s)", self.GetId()) - } - return nil -} - -func (self *SCen) GetInstanceRouteEntries() ([]SCenRouteEntry, error) { - childInstance, err := self.client.GetAllCenAttachedChildInstances(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "self.client.GetAllCenAttachedChildInstances(self.GetId())") - } - result := []SCenRouteEntry{} - for i := range childInstance { - routes, err := self.client.GetAllCenChildInstanceRouteEntries(self.GetId(), childInstance[i].ChildInstanceID, childInstance[i].ChildInstanceRegionID, childInstance[i].ChildInstanceType) - if err != nil { - return nil, errors.Wrap(err, "self.client.GetAllCenChildInstanceRouteEntries(self.GetId(), childInstance[i].ChildInstanceID, childInstance[i].ChildInstanceRegionID, childInstance[i].ChildInstanceType)") - } - for j := range routes { - // CEN 类型的路由是通过CEN从其他vpc/vbr的路由表中传播过来的 - // 只关注路由的发源 - if routes[j].Type != "CEN" { - routes[j].ChildInstance = &childInstance[i] - result = append(result, routes[j]) - } - } - } - return result, nil -} - -func (self *SCen) GetIRoutes() ([]cloudprovider.ICloudInterVpcNetworkRoute, error) { - result := []cloudprovider.ICloudInterVpcNetworkRoute{} - routeEntries, err := self.GetInstanceRouteEntries() - if err != nil { - return nil, errors.Wrap(err, "self.GetInstanceRouteEntries()") - } - for i := range routeEntries { - result = append(result, &routeEntries[i]) - } - return result, nil -} - -func (self *SCen) EnableRouteEntry(routeId string) error { - idContent := strings.Split(routeId, ":") - if len(idContent) != 2 { - return errors.Wrapf(cloudprovider.ErrNotSupported, "invalid aliyun generated cenRouteId %s", routeId) - } - routeTable := idContent[0] - cidr := idContent[1] - routeEntries, err := self.GetInstanceRouteEntries() - if err != nil { - return errors.Wrap(err, "self.GetInstanceRouteEntries()") - } - routeEntry := SCenRouteEntry{} - for i := range routeEntries { - if routeEntries[i].RouteTableID == routeTable && routeEntries[i].DestinationCidrBlock == cidr { - routeEntry = routeEntries[i] - break - } - } - if routeEntry.GetEnabled() { - return nil - } - err = self.client.PublishRouteEntries(self.GetId(), routeEntry.GetInstanceId(), routeTable, routeEntry.GetInstanceRegionId(), routeEntry.GetInstanceType(), cidr) - if err != nil { - return errors.Wrap(err, "self.client.PublishRouteEntries()") - } - return nil -} - -func (self *SCen) DisableRouteEntry(routeId string) error { - idContent := strings.Split(routeId, ":") - if len(idContent) != 2 { - return errors.Wrapf(cloudprovider.ErrNotSupported, "invalid aliyun generated cenRouteId %s", routeId) - } - routeTable := idContent[0] - cidr := idContent[1] - routeEntries, err := self.GetInstanceRouteEntries() - if err != nil { - return errors.Wrap(err, "self.GetInstanceRouteEntries()") - } - routeEntry := SCenRouteEntry{} - for i := range routeEntries { - if routeEntries[i].RouteTableID == routeTable && routeEntries[i].DestinationCidrBlock == cidr { - routeEntry = routeEntries[i] - break - } - } - if !routeEntry.GetEnabled() { - return nil - } - err = self.client.WithdrawPublishedRouteEntries(self.GetId(), routeEntry.GetInstanceId(), routeTable, routeEntry.GetInstanceRegionId(), routeEntry.GetInstanceType(), cidr) - if err != nil { - return errors.Wrap(err, "self.client.PublishRouteEntries()") - } - return nil -} diff --git a/pkg/multicloud/aliyun/dbinstance.go b/pkg/multicloud/aliyun/dbinstance.go deleted file mode 100644 index 7708f5842f..0000000000 --- a/pkg/multicloud/aliyun/dbinstance.go +++ /dev/null @@ -1,908 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/rand" -) - -type SReadOnlyDBInstanceIds struct { - ReadOnlyDBInstanceId []string -} - -type SDBInstanceId struct { - DBInstanceId []string -} - -type SDBInstanceExtra struct { - DBInstanceId SDBInstanceId -} - -type SDBInstance struct { - multicloud.SDBInstanceBase - - netInfo []SDBInstanceNetwork - - region *SRegion - - AccountMaxQuantity int - AccountType string - CanTempUpgrade bool - Category string - AvailabilityValue string - DBInstanceDescription string - DBInstanceId string - ConnectionMode string - ConnectionString string - ConnectionDomain string - CurrentKernelVersion string - DBInstanceCPU int - CreateTime time.Time - DBInstanceClass string - DBInstanceClassType string - DBInstanceNetType string - DBInstanceStatus string - DBInstanceType string - DBInstanceDiskUsed int64 - DBInstanceStorage int - DBInstanceStorageType string - MasterInstanceId string - DBInstanceMemory int - DBMaxQuantity int - IPType string - LatestKernelVersion string - DispenseMode string - Engine string - EngineVersion string - ExpireTime time.Time - InstanceNetworkType string - LockMode string - LockReason string - MutriORsignle bool - MaintainTime string - MaxConnections int - MaxIOPS int - Port int - PayType TChargeType - ReadOnlyDBInstanceIds SReadOnlyDBInstanceIds - RegionId string - ResourceGroupId string - VSwitchId string - VpcCloudInstanceId string - VpcId string - ZoneId string - Extra SDBInstanceExtra - SecurityIPList string - SecurityIPMode string - SupportCreateSuperAccount string - SupportUpgradeAccountType string - TempUpgradeTimeEnd time.Time - TempUpgradeTimeStart time.Time -} - -func (rds *SDBInstance) GetName() string { - if len(rds.DBInstanceDescription) > 0 { - return rds.DBInstanceDescription - } - return rds.DBInstanceId -} - -func (rds *SDBInstance) GetId() string { - return rds.DBInstanceId -} - -func (rds *SDBInstance) GetGlobalId() string { - return rds.GetId() -} - -// Creating 创建中 -// Running 使用中 -// Deleting 删除中 -// Rebooting 重启中 -// DBInstanceClassChanging 升降级中 -// TRANSING 迁移中 -// EngineVersionUpgrading 迁移版本中 -// TransingToOthers 迁移数据到其他RDS中 -// GuardDBInstanceCreating 生产灾备实例中 -// Restoring 备份恢复中 -// Importing 数据导入中 -// ImportingFromOthers 从其他RDS实例导入数据中 -// DBInstanceNetTypeChanging 内外网切换中 -// GuardSwitching 容灾切换中 -// INS_CLONING 实例克隆中 -func (rds *SDBInstance) GetStatus() string { - switch rds.DBInstanceStatus { - case "Creating", "GuardDBInstanceCreating", "DBInstanceNetTypeChanging", "GuardSwitching", "NET_CREATING", "NET_DELETING": - return api.DBINSTANCE_DEPLOYING - case "DBInstanceClassChanging": - return api.DBINSTANCE_CHANGE_CONFIG - case "Running": - return api.DBINSTANCE_RUNNING - case "Deleting": - return api.DBINSTANCE_DELETING - case "Rebooting": - return api.DBINSTANCE_REBOOTING - case "TRANSING", "EngineVersionUpgrading", "TransingToOthers": - return api.DBINSTANCE_MIGRATING - case "Restoring": - return api.DBINSTANCE_RESTORING - case "Importing", "ImportingFromOthers": - return api.DBINSTANCE_IMPORTING - case "INS_CLONING": - return api.DBINSTANCE_CLONING - default: - log.Errorf("Unknown dbinstance status %s", rds.DBInstanceStatus) - return api.DBINSTANCE_UNKNOWN - } -} - -func (rds *SDBInstance) GetBillingType() string { - return convertChargeType(rds.PayType) -} - -func (rds *SDBInstance) GetExpiredAt() time.Time { - return rds.ExpireTime -} - -func (rds *SDBInstance) GetCreatedAt() time.Time { - return rds.CreateTime -} - -func (rds *SDBInstance) GetStorageType() string { - return rds.DBInstanceStorageType -} - -func (rds *SDBInstance) GetEngine() string { - switch rds.Engine { - case "MySQL": - return api.DBINSTANCE_TYPE_MYSQL - case "SQLServer": - return api.DBINSTANCE_TYPE_SQLSERVER - case "PostgreSQL": - return api.DBINSTANCE_TYPE_POSTGRESQL - case "PPAS": - return api.DBINSTANCE_TYPE_PPAS - case "MariaDB": - return api.DBINSTANCE_TYPE_MARIADB - } - return rds.Engine -} - -func (rds *SDBInstance) GetEngineVersion() string { - return rds.EngineVersion -} - -func (rds *SDBInstance) GetInstanceType() string { - return rds.DBInstanceClass -} - -func (rds *SDBInstance) GetCategory() string { - switch rds.Category { - case "Basic": - return api.ALIYUN_DBINSTANCE_CATEGORY_BASIC - case "HighAvailability": - return api.ALIYUN_DBINSTANCE_CATEGORY_HA - case "AlwaysOn": - return api.ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON - case "Finance": - return api.ALIYUN_DBINSTANCE_CATEGORY_FINANCE - } - return rds.Category -} - -func (rds *SDBInstance) GetVcpuCount() int { - if rds.DBInstanceCPU == 0 { - rds.Refresh() - } - return rds.DBInstanceCPU -} - -func (rds *SDBInstance) GetVmemSizeMB() int { - if rds.DBInstanceMemory == 0 { - rds.Refresh() - } - return rds.DBInstanceMemory -} - -func (rds *SDBInstance) GetDiskSizeGB() int { - if rds.DBInstanceStorage == 0 { - rds.Refresh() - } - return rds.DBInstanceStorage -} - -func (rds *SDBInstance) GetDiskSizeUsedMB() int { - if rds.DBInstanceDiskUsed == 0 { - rds.Refresh() - } - return int(rds.DBInstanceDiskUsed / 1024 / 1024) -} - -func (rds *SDBInstance) GetPort() int { - if rds.Port == 0 { - rds.Refresh() - } - return rds.Port -} - -func (rds *SDBInstance) GetMaintainTime() string { - return rds.MaintainTime -} - -func (rds *SDBInstance) GetIVpcId() string { - return rds.VpcId -} - -func (rds *SDBInstance) Refresh() error { - instance, err := rds.region.GetDBInstanceDetail(rds.DBInstanceId) - if err != nil { - return err - } - return jsonutils.Update(rds, instance) -} - -func (rds *SDBInstance) getZoneId(index int) string { - zoneId := rds.getZone(index) - if len(zoneId) > 0 { - zone, err := rds.region.getZoneById(zoneId) - if err != nil { - log.Errorf("failed to found zone %s for rds %s", zoneId, rds.GetName()) - return "" - } - return zone.GetGlobalId() - } - return "" -} - -func (rds *SDBInstance) GetZone1Id() string { - return rds.getZoneId(1) -} - -func (rds *SDBInstance) GetZone2Id() string { - return rds.getZoneId(2) -} - -func (rds *SDBInstance) GetZone3Id() string { - return rds.getZoneId(3) -} - -func (rds *SDBInstance) GetIOPS() int { - if rds.MaxIOPS == 0 { - rds.Refresh() - } - return rds.MaxIOPS -} - -func (rds *SDBInstance) GetNetworkAddress() string { - return rds.ConnectionDomain -} - -func (rds *SDBInstance) getZone(index int) string { - zoneStr := strings.Replace(rds.ZoneId, ")", "", -1) - zoneInfo := strings.Split(zoneStr, ",") - if len(zoneInfo) < index { - return "" - } - zone := zoneInfo[index-1] - zoneCode := zone[len(zone)-1] - if strings.HasPrefix(rds.ZoneId, fmt.Sprintf("%s-", rds.RegionId)) { - return fmt.Sprintf("%s-%s", rds.RegionId, string(zoneCode)) - } - return fmt.Sprintf("%s%s", rds.RegionId, string(zoneCode)) -} - -func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { - netInfo, err := rds.region.GetDBInstanceNetInfo(rds.DBInstanceId) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceNetInfo") - } - networks := []cloudprovider.SDBInstanceNetwork{} - for _, net := range netInfo { - if net.IPType == "Private" { - network := cloudprovider.SDBInstanceNetwork{} - network.IP = net.IPAddress - network.NetworkId = net.VSwitchId - networks = append(networks, network) - } - } - return networks, nil -} - -func (rds *SDBInstance) fetchNetInfo() error { - if len(rds.netInfo) > 0 { - return nil - } - netInfo, err := rds.region.GetDBInstanceNetInfo(rds.DBInstanceId) - if err != nil { - return errors.Wrap(err, "GetDBInstanceNetInfo") - } - rds.netInfo = netInfo - return nil -} - -func (rds *SDBInstance) GetInternalConnectionStr() string { - err := rds.fetchNetInfo() - if err != nil { - log.Errorf("failed to fetch netInfo error: %v", err) - return "" - } - - str := "" - for _, net := range rds.netInfo { - if net.IPType != "Public" { - if net.IPType == "Private" { - return net.ConnectionString - } else if net.IPType == "Inner" { - str = net.ConnectionString - } - } - } - return str -} - -func (rds *SDBInstance) GetConnectionStr() string { - err := rds.fetchNetInfo() - if err != nil { - log.Errorf("failed to fetch netInfo error: %v", err) - return "" - } - - for _, net := range rds.netInfo { - if net.IPType == "Public" { - return net.ConnectionString - } - } - return "" -} - -func (region *SRegion) GetDBInstances(ids []string, offset int, limit int) ([]SDBInstance, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - body, err := region.rdsRequest("DescribeDBInstances", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "GetDBInstances") - } - instances := []SDBInstance{} - err = body.Unmarshal(&instances, "Items", "DBInstance") - if err != nil { - return nil, 0, errors.Wrapf(err, "GetDBInstances.Unmarshal") - } - total, _ := body.Int("TotalRecordCount") - return instances, int(total), nil -} - -func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { - rds, err := region.GetDBInstanceDetail(instanceId) - if err != nil { - return nil, err - } - rds.region = region - return rds, nil -} - -func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - instances := []SDBInstance{} - for { - part, total, err := region.GetDBInstances([]string{}, len(instances), 50) - if err != nil { - return nil, err - } - instances = append(instances, part...) - if len(instances) >= total { - break - } - } - idbinstances := []cloudprovider.ICloudDBInstance{} - for i := 0; i < len(instances); i++ { - instances[i].region = region - idbinstances = append(idbinstances, &instances[i]) - } - return idbinstances, nil -} - -func (region *SRegion) GetDBInstanceDetail(instanceId string) (*SDBInstance, error) { - if len(instanceId) == 0 { - return nil, cloudprovider.ErrNotFound - } - params := map[string]string{} - params["RegionId"] = region.RegionId - params["DBInstanceId"] = instanceId - body, err := region.rdsRequest("DescribeDBInstanceAttribute", params) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceDetail") - } - instances := []SDBInstance{} - err = body.Unmarshal(&instances, "Items", "DBInstanceAttribute") - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceDetail.Unmarshal") - } - if len(instances) == 1 { - instances[0].region = region - return &instances[0], nil - } - if len(instances) == 0 { - return nil, cloudprovider.ErrNotFound - } - return nil, cloudprovider.ErrDuplicateId -} - -func (region *SRegion) DeleteDBInstance(instanceId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["DBInstanceId"] = instanceId - _, err := region.rdsRequest("DeleteDBInstance", params) - return err -} - -type SDBInstanceWeight struct { -} - -type SDBInstanceWeights struct { - DBInstanceWeight []SDBInstanceWeight -} - -type SsecurityIPGroup struct { -} - -type SSecurityIPGroups struct { - securityIPGroup []SsecurityIPGroup -} - -type SDBInstanceNetwork struct { - ConnectionString string - ConnectionStringType string - DBInstanceWeights SDBInstanceWeights - IPAddress string - IPType string - Port int - SecurityIPGroups SSecurityIPGroups - Upgradeable string - VPCId string - VSwitchId string -} - -func (network *SDBInstanceNetwork) GetGlobalId() string { - return network.IPAddress -} - -func (network *SDBInstanceNetwork) GetINetworkId() string { - return network.VSwitchId -} - -func (network *SDBInstanceNetwork) GetIP() string { - return network.IPAddress -} - -func (region *SRegion) GetDBInstanceNetInfo(instanceId string) ([]SDBInstanceNetwork, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["DBInstanceId"] = instanceId - body, err := region.rdsRequest("DescribeDBInstanceNetInfo", params) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceNetwork") - } - networks := []SDBInstanceNetwork{} - err = body.Unmarshal(&networks, "DBInstanceNetInfos", "DBInstanceNetInfo") - if err != nil { - return nil, err - } - return networks, nil -} - -func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { - parameters, err := rds.region.GetDBInstanceParameters(rds.DBInstanceId) - if err != nil { - return nil, err - } - iparameters := []cloudprovider.ICloudDBInstanceParameter{} - for i := 0; i < len(parameters); i++ { - iparameters = append(iparameters, ¶meters[i]) - } - return iparameters, nil -} - -func (self *SDBInstance) GetSecurityGroupIds() ([]string, error) { - return self.region.GetRdsSecgroupIds(self.DBInstanceId) -} - -func (self *SDBInstance) SetSecurityGroups(ids []string) error { - return self.region.SetRdsSecgroups(self.DBInstanceId, ids) -} - -func (self *SRegion) SetRdsSecgroups(rdsId string, secIds []string) error { - params := map[string]string{ - "DBInstanceId": rdsId, - "SecurityGroupId": strings.Join(secIds, ","), - } - _, err := self.rdsRequest("ModifySecurityGroupConfiguration", params) - if err != nil { - return errors.Wrapf(err, "ModifySecurityGroupConfiguration") - } - return nil -} - -func (self *SRegion) GetRdsSecgroupIds(rdsId string) ([]string, error) { - params := map[string]string{ - "DBInstanceId": rdsId, - } - resp, err := self.rdsRequest("DescribeSecurityGroupConfiguration", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeSecurityGroupConfiguration") - } - items := []struct { - NetworkType string - SecurityGroupId string - RegionId string - }{} - err = resp.Unmarshal(&items, "Items", "EcsSecurityGroupRelation") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - ids := []string{} - for _, item := range items { - ids = append(ids, item.SecurityGroupId) - } - return ids, nil -} - -func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { - backups, err := region.GetIDBInstanceBackups() - if err != nil { - return nil, errors.Wrap(err, "region.GetIDBInstanceBackups") - } - for _, backup := range backups { - if backup.GetGlobalId() == backupId { - return backup, nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (rds *SDBInstance) Reboot() error { - return rds.region.RebootDBInstance(rds.DBInstanceId) -} - -func (rds *SDBInstance) Delete() error { - return rds.region.DeleteDBInstance(rds.DBInstanceId) -} - -func (region *SRegion) RebootDBInstance(instanceId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["DBInstanceId"] = instanceId - _, err := region.rdsRequest("RestartDBInstance", params) - return err -} - -func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { - databases := []SDBInstanceDatabase{} - for { - parts, total, err := rds.region.GetDBInstanceDatabases(rds.DBInstanceId, "", len(databases), 500) - if err != nil { - return nil, err - } - databases = append(databases, parts...) - if len(databases) >= total { - break - } - } - - idatabase := []cloudprovider.ICloudDBInstanceDatabase{} - for i := 0; i < len(databases); i++ { - databases[i].instance = rds - idatabase = append(idatabase, &databases[i]) - } - return idatabase, nil -} - -func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { - accounts := []SDBInstanceAccount{} - for { - parts, total, err := rds.region.GetDBInstanceAccounts(rds.DBInstanceId, len(accounts), 50) - if err != nil { - return nil, err - } - accounts = append(accounts, parts...) - if len(accounts) >= total { - break - } - } - - iaccounts := []cloudprovider.ICloudDBInstanceAccount{} - for i := 0; i < len(accounts); i++ { - accounts[i].instance = rds - iaccounts = append(iaccounts, &accounts[i]) - } - return iaccounts, nil -} - -func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { - return rds.region.ChangeDBInstanceConfig(rds.DBInstanceId, string(rds.PayType), desc) -} - -func (region *SRegion) ChangeDBInstanceConfig(instanceId, payType string, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { - params := map[string]string{ - "RegionId": region.RegionId, - "DBInstanceId": instanceId, - "PayType": payType, - } - if len(desc.InstanceType) > 0 { - params["DBInstanceClass"] = desc.InstanceType - } - if desc.DiskSizeGB > 0 { - params["DBInstanceStorage"] = fmt.Sprintf("%d", desc.DiskSizeGB) - } - - _, err := region.rdsRequest("ModifyDBInstanceSpec", params) - if err != nil { - return errors.Wrap(err, "region.rdsRequest.ModifyDBInstanceSpec") - } - return nil -} - -func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - params := map[string]string{ - "RegionId": region.RegionId, - "Engine": desc.Engine, - "EngineVersion": desc.EngineVersion, - "DBInstanceStorage": fmt.Sprintf("%d", desc.DiskSizeGB), - "DBInstanceNetType": "Intranet", - "PayType": "Postpaid", - "SecurityIPList": "0.0.0.0/0", - "DBInstanceDescription": desc.Name, - "InstanceNetworkType": "VPC", - "VPCId": desc.VpcId, - "VSwitchId": desc.NetworkId, - "DBInstanceStorageType": desc.StorageType, - "DBInstanceClass": desc.InstanceType, - "ZoneId": desc.ZoneId, - "ClientToken": utils.GenRequestId(20), - } - switch desc.Category { - case api.ALIYUN_DBINSTANCE_CATEGORY_HA: - params["Category"] = "HighAvailability" - case api.ALIYUN_DBINSTANCE_CATEGORY_BASIC: - params["Category"] = "Basic" - case api.ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON: - params["Category"] = "AlwaysOn" - case api.ALIYUN_DBINSTANCE_CATEGORY_FINANCE: - params["Category"] = "Finance" - } - - if len(desc.Address) > 0 { - params["PrivateIpAddress"] = desc.Address - } - if len(desc.ProjectId) > 0 { - params["ResourceGroupId"] = desc.ProjectId - } - if desc.BillingCycle != nil { - params["PayType"] = "Prepaid" - if desc.BillingCycle.GetYears() > 0 { - params["Period"] = "Year" - params["UsedTime"] = fmt.Sprintf("%d", desc.BillingCycle.GetYears()) - } else { - params["Period"] = "Month" - params["UsedTime"] = fmt.Sprintf("%d", desc.BillingCycle.GetMonths()) - } - params["AutoRenew"] = "False" - if desc.BillingCycle.AutoRenew { - params["AutoRenew"] = "True" - } - } - - action := "CreateDBInstance" - if len(desc.MasterInstanceId) > 0 { - action = "CreateReadOnlyDBInstance" - params["DBInstanceId"] = desc.MasterInstanceId - } - - resp, err := region.rdsRequest(action, params) - if err != nil { - return nil, errors.Wrapf(err, "rdsRequest") - } - instanceId, err := resp.GetString("DBInstanceId") - if err != nil { - return nil, errors.Wrap(err, `resp.GetString("DBInstanceId")`) - } - region.SetResourceTags(ALIYUN_SERVICE_RDS, "INSTANCE", instanceId, desc.Tags, false) - return region.GetIDBInstanceById(instanceId) -} - -func (rds *SDBInstance) GetMasterInstanceId() string { - if len(rds.MasterInstanceId) > 0 { - return rds.MasterInstanceId - } - rds.Refresh() - return rds.MasterInstanceId -} - -func (region *SRegion) OpenPublicConnection(instanceId string) error { - rds, err := region.GetDBInstanceDetail(instanceId) - if err != nil { - return err - } - params := map[string]string{ - "RegionId": region.RegionId, - "ConnectionStringPrefix": rds.DBInstanceId + rand.String(3), - "DBInstanceId": rds.DBInstanceId, - "Port": fmt.Sprintf("%d", rds.Port), - } - _, err = rds.region.rdsRequest("AllocateInstancePublicConnection", params) - if err != nil { - return errors.Wrap(err, "rdsRequest(AllocateInstancePublicConnection)") - } - return nil -} - -func (rds *SDBInstance) OpenPublicConnection() error { - if url := rds.GetConnectionStr(); len(url) == 0 { - err := rds.region.OpenPublicConnection(rds.DBInstanceId) - if err != nil { - return err - } - rds.netInfo = []SDBInstanceNetwork{} - } - return nil -} - -func (region *SRegion) ClosePublicConnection(instanceId string) error { - netInfo, err := region.GetDBInstanceNetInfo(instanceId) - if err != nil { - return errors.Wrap(err, "GetDBInstanceNetInfo") - } - - for _, net := range netInfo { - if net.IPType == "Public" { - params := map[string]string{ - "RegionId": region.RegionId, - "CurrentConnectionString": net.ConnectionString, - "DBInstanceId": instanceId, - } - _, err = region.rdsRequest("ReleaseInstancePublicConnection", params) - if err != nil { - return errors.Wrap(err, "rdsRequest(ReleaseInstancePublicConnection)") - } - - } - } - return nil - -} - -func (rds *SDBInstance) ClosePublicConnection() error { - return rds.region.ClosePublicConnection(rds.DBInstanceId) -} - -func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { - if len(conf.OriginDBInstanceExternalId) == 0 { - conf.OriginDBInstanceExternalId = rds.DBInstanceId - } - return rds.region.RecoveryDBInstanceFromBackup(conf.OriginDBInstanceExternalId, rds.DBInstanceId, conf.BackupId, conf.Databases) -} - -func (region *SRegion) RecoveryDBInstanceFromBackup(srcId, destId string, backupId string, databases map[string]string) error { - params := map[string]string{ - "RegionId": region.RegionId, - "DBInstanceId": srcId, - "TargetDBInstanceId": destId, - "BackupId": backupId, - "DbNames": jsonutils.Marshal(databases).String(), - } - _, err := region.rdsRequest("RecoveryDBInstance", params) - if err != nil { - return errors.Wrap(err, "rdsRequest.RecoveryDBInstance") - } - return nil -} - -func (rds *SDBInstance) GetProjectId() string { - return rds.ResourceGroupId -} - -func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { - return rds.region.CreateDBInstanceDatabae(rds.DBInstanceId, conf.CharacterSet, conf.Name, conf.Description) -} - -func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { - return rds.region.CreateDBInstanceAccount(rds.DBInstanceId, conf.Name, conf.Password, conf.Description) -} - -func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { - return rds.region.RenewInstance(rds.DBInstanceId, bc) -} - -func (rds *SDBInstance) SetAutoRenew(bc billing.SBillingCycle) error { - month := 1 - if bc.GetMonths() > 0 { - month = bc.GetMonths() - } - return rds.region.ModifyInstanceAutoRenewalAttribute(rds.DBInstanceId, month, bc.AutoRenew) -} - -func (region *SRegion) ModifyInstanceAutoRenewalAttribute(rdsId string, month int, autoRenew bool) error { - params := map[string]string{ - "RegionId": region.RegionId, - "DBInstanceId": rdsId, - "AutoRenew": "False", - "ClientToken": utils.GenRequestId(20), - } - if autoRenew { - params["AutoRenew"] = "True" - params["Duration"] = fmt.Sprintf("%d", month) - } - _, err := region.rdsRequest("ModifyInstanceAutoRenewalAttribute", params) - if err != nil { - return errors.Wrap(err, "ModifyInstanceAutoRenewalAttribute") - } - return nil -} - -func (region *SRegion) RenewDBInstance(instanceId string, bc billing.SBillingCycle) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "Period": fmt.Sprintf("%d", bc.GetMonths()), - "ClientToken": utils.GenRequestId(20), - } - _, err := region.rdsRequest("RenewInstance", params) - return err -} - -func (self *SDBInstance) GetTags() (map[string]string, error) { - _, tags, err := self.region.ListSysAndUserTags(ALIYUN_SERVICE_RDS, "INSTANCE", self.DBInstanceId) - if err != nil { - return nil, errors.Wrapf(err, "ListTags") - } - tagMaps := map[string]string{} - for k, v := range tags { - tagMaps[strings.ToLower(k)] = v - } - return tagMaps, nil -} - -func (self *SDBInstance) GetSysTags() map[string]string { - tags, _, err := self.region.ListSysAndUserTags(ALIYUN_SERVICE_RDS, "INSTANCE", self.DBInstanceId) - if err != nil { - return nil - } - tagMaps := map[string]string{} - for k, v := range tags { - tagMaps[strings.ToLower(k)] = v - } - return tagMaps -} - -func (rds *SDBInstance) SetTags(tags map[string]string, replace bool) error { - return rds.region.SetResourceTags(ALIYUN_SERVICE_RDS, "INSTANCE", rds.GetId(), tags, replace) -} diff --git a/pkg/multicloud/aliyun/dbinstance_account.go b/pkg/multicloud/aliyun/dbinstance_account.go deleted file mode 100644 index 0f327658bc..0000000000 --- a/pkg/multicloud/aliyun/dbinstance_account.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDatabasePrivileges struct { - DatabasePrivilege []SDatabasePrivilege -} - -type SDBInstanceAccount struct { - multicloud.SDBInstanceAccountBase - multicloud.AliyunTags - instance *SDBInstance - - AccountDescription string - AccountName string - AccountStatus string - AccountType string - DBInstanceId string - DatabasePrivileges SDatabasePrivileges - PrivExceeded string -} - -func (account *SDBInstanceAccount) GetName() string { - return account.AccountName -} - -func (account *SDBInstanceAccount) Delete() error { - return account.instance.region.DeleteDBInstanceAccount(account.DBInstanceId, account.AccountName) -} - -func (account *SDBInstanceAccount) RevokePrivilege(database string) error { - return account.instance.region.RevokeDBInstancePrivilege(account.DBInstanceId, account.AccountName, database) -} - -func (region *SRegion) RevokeDBInstancePrivilege(instanceId, account, database string) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "AccountName": account, - "DBName": database, - } - _, err := region.rdsRequest("RevokeAccountPrivilege", params) - return err -} - -func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { - return account.instance.region.GrantDBInstancePrivilege(account.DBInstanceId, account.AccountName, database, privilege) -} - -func (region *SRegion) GrantDBInstancePrivilege(instanceId, account, database, privilege string) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "AccountName": account, - "DBName": database, - } - switch privilege { - case api.DATABASE_PRIVILEGE_R: - params["AccountPrivilege"] = "ReadOnly" - case api.DATABASE_PRIVILEGE_RW: - params["AccountPrivilege"] = "ReadWrite" - case api.DATABASE_PRIVILEGE_DDL: - params["AccountPrivilege"] = "DDLOnly" - case api.DATABASE_PRIVILEGE_DML: - params["AccountPrivilege"] = "DMLOnly" - case api.DATABASE_PRIVILEGE_OWNER: - params["AccountPrivilege"] = "DBOwner" - default: - return fmt.Errorf("Unknown privilege [%s]", privilege) - } - _, err := region.rdsRequest("GrantAccountPrivilege", params) - return err -} - -func (account *SDBInstanceAccount) ResetPassword(password string) error { - return account.instance.region.ResetDBInstanceAccountPassword(account.DBInstanceId, account.AccountName, password, account.AccountType) -} - -func (region *SRegion) ResetDBInstanceAccountPassword(instanceId, account, password, accountType string) error { - action := "ResetAccountPassword" - if accountType == "Super" { - action = "ResetAccount" - } - params := map[string]string{ - "DBInstanceId": instanceId, - "AccountName": account, - "AccountPassword": password, - } - _, err := region.rdsRequest(action, params) - return err -} - -func (account *SDBInstanceAccount) GetStatus() string { - switch account.AccountStatus { - case "Available": - return api.DBINSTANCE_USER_AVAILABLE - case "Unavailable": - return api.DBINSTANCE_USER_UNAVAILABLE - } - return account.AccountStatus -} - -func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { - privileves := []cloudprovider.ICloudDBInstanceAccountPrivilege{} - for i := 0; i < len(account.DatabasePrivileges.DatabasePrivilege); i++ { - account.DatabasePrivileges.DatabasePrivilege[i].account = account - privileves = append(privileves, &account.DatabasePrivileges.DatabasePrivilege[i]) - } - return privileves, nil -} - -func (region *SRegion) GetDBInstanceAccounts(instanceId string, offset int, limit int) ([]SDBInstanceAccount, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := map[string]string{ - "RegionId": region.RegionId, - "PageSize": fmt.Sprintf("%d", limit), - "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), - "DBInstanceId": instanceId, - } - body, err := region.rdsRequest("DescribeAccounts", params) - if err != nil { - return nil, 0, errors.Wrap(err, "DescribeAccounts") - } - accounts := []SDBInstanceAccount{} - err = body.Unmarshal(&accounts, "Accounts", "DBInstanceAccount") - if err != nil { - return nil, 0, errors.Wrap(err, "Unmarshal") - } - total, _ := body.Int("TotalRecordCount") - return accounts, int(total), nil -} - -func (region *SRegion) DeleteDBInstanceAccount(instanceId string, accountName string) error { - params := map[string]string{ - "RegionId": region.RegionId, - "DBInstanceId": instanceId, - "AccountName": accountName, - } - - _, err := region.rdsRequest("DeleteAccount", params) - return err -} - -func (region *SRegion) CreateDBInstanceAccount(instanceId string, name string, password string, desc string) error { - params := map[string]string{ - "RegionId": region.RegionId, - "DBInstanceId": instanceId, - "AccountName": name, - "AccountPassword": password, - "AccountDescription": desc, - } - - _, err := region.rdsRequest("CreateAccount", params) - return err - -} diff --git a/pkg/multicloud/aliyun/dbinstance_backup.go b/pkg/multicloud/aliyun/dbinstance_backup.go deleted file mode 100644 index bc5bed41c4..0000000000 --- a/pkg/multicloud/aliyun/dbinstance_backup.go +++ /dev/null @@ -1,357 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceBackup struct { - multicloud.SDBInstanceBackupBase - multicloud.AliyunTags - region *SRegion - - BackupDBNames string - BackupIntranetDownloadURL string - BackupDownloadURL string - BackupEndTime time.Time - BackupId string - BackupLocation string - BackupMethod string - BackupMode string - BackupScale string - BackupSize int - BackupStartTime time.Time - BackupStatus string - BackupType string - DBInstanceId string - HostInstanceID int - MetaStatus string - StoreStatus string -} - -func (backup *SDBInstanceBackup) GetId() string { - return backup.BackupId -} - -func (backup *SDBInstanceBackup) GetGlobalId() string { - return backup.BackupId -} - -func (backup *SDBInstanceBackup) GetName() string { - return backup.BackupId -} - -func (backup *SDBInstanceBackup) GetStartTime() time.Time { - return backup.BackupStartTime -} - -func (backup *SDBInstanceBackup) GetEndTime() time.Time { - return backup.BackupEndTime -} - -func (backup *SDBInstanceBackup) GetBackupMode() string { - switch backup.BackupMode { - case "Manual": - return api.BACKUP_MODE_MANUAL - default: - return api.BACKUP_MODE_AUTOMATED - } -} - -func (backup *SDBInstanceBackup) GetStatus() string { - switch backup.BackupStatus { - case "Success": - return api.DBINSTANCE_BACKUP_READY - case "Failed": - return api.DBINSTANCE_BACKUP_FAILED - default: - return api.DBINSTANCE_BACKUP_UNKNOWN - } -} - -func (backup *SDBInstanceBackup) GetBackupSizeMb() int { - return backup.BackupSize / 1024 / 1024 -} - -func (backup *SDBInstanceBackup) GetDBNames() string { - return backup.BackupDBNames -} - -func (backup *SDBInstanceBackup) GetEngine() string { - instance, _ := backup.region.GetDBInstanceDetail(backup.DBInstanceId) - if instance != nil { - return instance.Engine - } - return "" -} - -func (backup *SDBInstanceBackup) GetEngineVersion() string { - instance, _ := backup.region.GetDBInstanceDetail(backup.DBInstanceId) - if instance != nil { - return instance.EngineVersion - } - return "" -} - -func (backup *SDBInstanceBackup) GetDBInstanceId() string { - return backup.DBInstanceId -} - -func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string, offset int, limit int) ([]SDBInstanceBackup, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := map[string]string{ - "RegionId": region.RegionId, - "PageSize": fmt.Sprintf("%d", limit), - "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), - "DBInstanceId": instanceId, - } - if len(backupId) > 0 { - params["BackupId"] = backupId - } - body, err := region.rdsRequest("DescribeBackups", params) - if err != nil { - return nil, 0, errors.Wrap(err, "DescribeBackups") - } - backups := []SDBInstanceBackup{} - err = body.Unmarshal(&backups, "Items", "Backup") - if err != nil { - return nil, 0, errors.Wrap(err, "Unmarshal") - } - total, _ := body.Int("TotalRecordCount") - return backups, int(total), nil -} - -func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - dbinstnaces, err := region.GetIDBInstances() - if err != nil { - return nil, err - } - ibackups := []cloudprovider.ICloudDBInstanceBackup{} - for i := 0; i < len(dbinstnaces); i++ { - _dbinstance := dbinstnaces[i].(*SDBInstance) - _ibackup, err := _dbinstance.GetIDBInstanceBackups() - if err != nil { - return nil, errors.Wrapf(err, "_dbinstance(%v).GetIDBInstanceBackups", _dbinstance) - } - ibackups = append(ibackups, _ibackup...) - } - return ibackups, nil -} - -func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - backups := []SDBInstanceBackup{} - for { - parts, total, err := rds.region.GetDBInstanceBackups(rds.DBInstanceId, "", len(backups), 50) - if err != nil { - return nil, err - } - backups = append(backups, parts...) - if len(backups) >= total { - break - } - } - - ibackups := []cloudprovider.ICloudDBInstanceBackup{} - for i := 0; i < len(backups); i++ { - backups[i].region = rds.region - ibackups = append(ibackups, &backups[i]) - } - return ibackups, nil -} - -func (self *SRegion) CreateDBInstanceBackup(rdsId string, databases []string) (string, error) { - rds, err := self.GetDBInstanceDetail(rdsId) - if err != nil { - return "", errors.Wrapf(err, "GetDBInstanceDetail") - } - params := map[string]string{ - "DBInstanceId": rdsId, - } - switch rds.Engine { - case api.DBINSTANCE_TYPE_MYSQL: - if utils.IsInStringArray(rds.EngineVersion, []string{"5.7", "8.0"}) && ((utils.IsInStringArray(rds.GetStorageType(), []string{ - api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_ESSD, - api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD, - }) && rds.GetCategory() == api.ALIYUN_DBINSTANCE_CATEGORY_HA) || - (rds.GetStorageType() == api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD && - rds.GetCategory() == api.ALIYUN_DBINSTANCE_CATEGORY_BASIC)) { - params["BackupMethod"] = "Snapshot" - } else { - params["BackupMethod"] = "Physical" - if len(databases) > 0 { - params["BackupStrategy"] = "db" - params["DBName"] = strings.Join(databases, ",") - params["BackupMethod"] = "Logical" - } - } - case api.DBINSTANCE_TYPE_MARIADB: - params["BackupMethod"] = "Snapshot" - case api.DBINSTANCE_TYPE_SQLSERVER: - params["BackupMethod"] = "Physical" - case api.DBINSTANCE_TYPE_POSTGRESQL: - if rds.GetStorageType() == api.ALIYUN_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD { - params["BackupMethod"] = "Physical" - } else { - params["BackupMethod"] = "Snapshot" - } - case api.DBINSTANCE_TYPE_PPAS: - params["BackupMethod"] = "Physical" - } - body, err := self.rdsRequest("CreateBackup", params) - if err != nil { - return "", errors.Wrap(err, "CreateBackup") - } - jobId, err := body.GetString("BackupJobId") - if err != nil { - return "", errors.Wrap(err, "body.BackupJobId") - } - return self.waitBackupCreateComplete(rds.DBInstanceId, jobId) -} - -func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { - return rds.region.CreateDBInstanceBackup(rds.DBInstanceId, conf.Databases) -} - -func (backup *SDBInstanceBackup) Delete() error { - return backup.region.DeleteDBInstanceBackup(backup.DBInstanceId, backup.BackupId) -} - -func (region *SRegion) DeleteDBInstanceBackup(instanceId string, backupId string) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "BackupId": backupId, - } - _, err := region.rdsRequest("DeleteBackup", params) - return err -} - -type SDBInstanceBackupJob struct { - BackupProgressStatus string - Process string - JobMode string - TaskAction string - BackupStatus string - BackupJobId string - BackupId string -} - -type SDBInstanceBackupJobs struct { - BackupJob []SDBInstanceBackupJob -} - -func (region *SRegion) GetDBInstanceBackupJobs(instanceId, jobId string) (*SDBInstanceBackupJobs, error) { - params := map[string]string{ - "DBInstanceId": instanceId, - "ClientToken": utils.GenRequestId(20), - "BackupMode": "Manual", - } - if len(jobId) > 0 { - params["BackupJobId"] = jobId - } - body, err := region.rdsRequest("DescribeBackupTasks", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeBackupTasks") - } - - jobs := SDBInstanceBackupJobs{} - - err = body.Unmarshal(&jobs, "Items") - if err != nil { - return nil, errors.Wrapf(err, "body.Unmarshal(%s)", body) - } - - return &jobs, nil -} - -func (region *SRegion) waitBackupCreateComplete(instanceId, jobId string) (string, error) { - err := cloudprovider.Wait(time.Second*10, time.Minute*40, func() (bool, error) { - jobs, err := region.GetDBInstanceBackupJobs(instanceId, jobId) - if err != nil { - return false, errors.Wrapf(err, "region.GetDBInstanceBackupJobs(%s, %s)", instanceId, jobId) - } - if len(jobs.BackupJob) == 0 { - return true, nil - } - for _, job := range jobs.BackupJob { - log.Infof("instance %s backup job %s status: %s(%s)", instanceId, jobId, job.BackupStatus, job.Process) - if job.BackupStatus == "Finished" && job.BackupJobId == jobId { - return true, nil - } - if job.BackupStatus == "Failed" && job.BackupJobId == jobId { - return false, fmt.Errorf("instance %s backup job %s failed", instanceId, jobId) - } - } - return false, nil - }) - if err != nil { - return "", errors.Wrapf(err, "wait backup create job") - } - jobs, err := region.GetDBInstanceBackupJobs(instanceId, jobId) - if err != nil { - return "", errors.Wrapf(err, "region.GetDBInstanceBackupJobs(%s, %s)", instanceId, jobId) - } - for _, job := range jobs.BackupJob { - if job.BackupStatus == "Finished" && job.BackupJobId == jobId { - if len(job.BackupId) == 0 { - return "", fmt.Errorf("Missing backup id") - } - return job.BackupId, nil - } - } - return "", fmt.Errorf("failed to found backup job %s backupid", jobId) -} - -func (self *SDBInstanceBackup) GetBackupMethod() cloudprovider.TBackupMethod { - return cloudprovider.TBackupMethod(self.BackupMethod) -} - -func (self *SDBInstanceBackup) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - rdsId, err := self.region.CreateDBInstanceByBackup(self.BackupId, opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateDBInstanceByBackup") - } - return self.region.GetDBInstanceDetail(rdsId) -} - -func (self *SRegion) CreateDBInstanceByBackup(backupId string, opts *cloudprovider.SManagedDBInstanceCreateConfig) (string, error) { - params := map[string]string{ - "DBInstanceId": opts.RdsId, - "DBInstanceStorageType": opts.StorageType, - "PayType": "Postpaid", - "BackupId": backupId, - } - resp, err := self.rdsRequest("CloneDBInstance", params) - if err != nil { - return "", errors.Wrapf(err, "rdsRequest") - } - rdsId, err := resp.GetString("DBInstanceId") - if err != nil { - return "", fmt.Errorf("missing DBInstanceId after CloneDBInstance") - } - return rdsId, nil -} diff --git a/pkg/multicloud/aliyun/dbinstance_database.go b/pkg/multicloud/aliyun/dbinstance_database.go deleted file mode 100644 index 04a32bc84a..0000000000 --- a/pkg/multicloud/aliyun/dbinstance_database.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceDatabase struct { - multicloud.SDBInstanceDatabaseBase - multicloud.AliyunTags - instance *SDBInstance - - CharacterSetName string - DBDescription string - DBInstanceId string - DBName string - DBStatus string - Engine string -} - -func (database *SDBInstanceDatabase) GetId() string { - return database.DBName -} - -func (database *SDBInstanceDatabase) GetGlobalId() string { - return database.DBName -} - -func (database *SDBInstanceDatabase) GetName() string { - return database.DBName -} - -func (database *SDBInstanceDatabase) GetStatus() string { - switch database.DBStatus { - case "Creating": - return api.DBINSTANCE_DATABASE_CREATING - case "Running": - return api.DBINSTANCE_DATABASE_RUNNING - case "Deleting": - return api.DBINSTANCE_DATABASE_DELETING - } - return database.DBStatus -} - -func (database *SDBInstanceDatabase) GetCharacterSet() string { - return database.CharacterSetName -} - -func (database *SDBInstanceDatabase) Delete() error { - return database.instance.region.DeleteDBInstanceDatabase(database.DBInstanceId, database.DBName) -} - -func (region *SRegion) DeleteDBInstanceDatabase(instanceId string, dbName string) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "DBName": dbName, - } - - _, err := region.rdsRequest("DeleteDatabase", params) - return err -} - -func (region *SRegion) CreateDBInstanceDatabae(instanceId, characterSet, dbName, desc string) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "DBName": dbName, - "CharacterSetName": characterSet, - "DBDescription": desc, - } - - _, err := region.rdsRequest("CreateDatabase", params) - return err - -} - -func (region *SRegion) GetDBInstanceDatabases(instanceId, dbName string, offset int, limit int) ([]SDBInstanceDatabase, int, error) { - if limit > 500 || limit <= 0 { - limit = 500 - } - params := map[string]string{ - "RegionId": region.RegionId, - "PageSize": fmt.Sprintf("%d", limit), - "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), - "DBInstanceId": instanceId, - } - if len(dbName) > 0 { - params["DBName"] = dbName - } - body, err := region.rdsRequest("DescribeDatabases", params) - if err != nil { - return nil, 0, errors.Wrap(err, "DescribeDatabases") - } - databases := []SDBInstanceDatabase{} - err = body.Unmarshal(&databases, "Databases", "Database") - if err != nil { - return nil, 0, errors.Wrap(err, "Unmarshal") - } - total, _ := body.Int("TotalRecordCount") - return databases, int(total), nil -} diff --git a/pkg/multicloud/aliyun/dbinstance_privilege.go b/pkg/multicloud/aliyun/dbinstance_privilege.go deleted file mode 100644 index 5826987113..0000000000 --- a/pkg/multicloud/aliyun/dbinstance_privilege.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" -) - -type SDatabasePrivilege struct { - account *SDBInstanceAccount - - AccountPrivilege string - AccountPrivilegeDetail string - DBName string -} - -func (privilege *SDatabasePrivilege) GetGlobalId() string { - return fmt.Sprintf("%s/%s", privilege.account.GetName(), privilege.DBName) -} - -func (privilege *SDatabasePrivilege) GetPrivilege() string { - switch privilege.AccountPrivilege { - case "ReadWrite": - return api.DATABASE_PRIVILEGE_RW - case "ReadOnly": - return api.DATABASE_PRIVILEGE_R - case "DDLOnly": - return api.DATABASE_PRIVILEGE_DDL - case "DMLOnly": - return api.DATABASE_PRIVILEGE_DML - case "DBOwner": - return api.DATABASE_PRIVILEGE_OWNER - case "Custom": - return api.DBINSTANCE_DATABASE_CREATING - } - return privilege.AccountPrivilege -} - -func (privilege *SDatabasePrivilege) GetDBName() string { - return privilege.DBName -} diff --git a/pkg/multicloud/aliyun/disk.go b/pkg/multicloud/aliyun/disk.go deleted file mode 100644 index ae40841934..0000000000 --- a/pkg/multicloud/aliyun/disk.go +++ /dev/null @@ -1,427 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SMountInstances struct { - MountInstance []string -} - -type SDisk struct { - storage *SStorage - multicloud.SDisk - multicloud.AliyunTags - - IOPS int - AttachedTime time.Time - AutoSnapshotPolicyId string - Category string - PerformanceLevel string - CreationTime time.Time - DeleteAutoSnapshot bool - DeleteWithInstance bool - Description string - DetachedTime time.Time - Device string - DiskChargeType TChargeType - DiskId string - DiskName string - EnableAutoSnapshot bool - EnableAutomatedSnapshotPolicy bool - Encrypted bool - ExpiredTime time.Time - ImageId string - InstanceId string - MountInstances SMountInstances - OperationLocks SOperationLocks - Portable bool - ProductCode string - RegionId string - ResourceGroupId string - Size int - SourceSnapshotId string - Status string - Type string - ZoneId string -} - -func (self *SDisk) GetIops() int { - return self.IOPS -} - -func (self *SRegion) GetDisks(instanceId string, zoneId string, category string, diskIds []string, offset int, limit int) ([]SDisk, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - if len(instanceId) > 0 { - params["InstanceId"] = instanceId - } - if len(zoneId) > 0 { - params["ZoneId"] = zoneId - } - if len(category) > 0 { - params["Category"] = category - } - if diskIds != nil && len(diskIds) > 0 { - params["DiskIds"] = jsonutils.Marshal(diskIds).String() - } - - body, err := self.ecsRequest("DescribeDisks", params) - if err != nil { - log.Errorf("GetDisks fail %s", err) - return nil, 0, err - } - - disks := make([]SDisk, 0) - err = body.Unmarshal(&disks, "Disks", "Disk") - if err != nil { - log.Errorf("Unmarshal disk details fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return disks, int(total), nil -} - -func (self *SDisk) GetId() string { - return self.DiskId -} - -func (self *SDisk) Delete(ctx context.Context) error { - _, err := self.storage.zone.region.getDisk(self.DiskId) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - // 未找到disk, 说明disk已经被删除了. 避免回收站中disk-delete循环删除失败 - return nil - } - log.Errorf("Failed to find disk %s when delete: %s", self.DiskId, err) - return err - } - - for { - err := self.storage.zone.region.DeleteDisk(self.DiskId) - if err != nil { - if isError(err, "IncorrectDiskStatus") { - log.Infof("The disk is initializing, try later ...") - time.Sleep(10 * time.Second) - } else { - log.Errorf("DeleteDisk fail: %s", err) - return err - } - } else { - break - } - } - return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes -} - -func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { - return self.storage.zone.region.resizeDisk(self.DiskId, sizeMb) -} - -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) IsEmulated() bool { - return false -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.storage, nil -} - -func (self *SDisk) GetStatus() string { - // In_use Available Attaching Detaching Creating ReIniting All - switch self.Status { - case "Creating", "ReIniting": - return api.DISK_ALLOCATING - default: - return api.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) ResizeDisk(newSize int64) error { - // newSize 单位为 GB. 范围在20 ~2000. 只能往大调。不能调小 - // https://help.aliyun.com/document_detail/25522.html?spm=a2c4g.11174283.6.897.aHwqkS - return self.storage.zone.region.resizeDisk(self.DiskId, newSize) -} - -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 { - switch self.Type { - case "system": - return api.DISK_TYPE_SYS - case "data": - return api.DISK_TYPE_DATA - default: - return api.DISK_TYPE_DATA - } -} - -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 *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, desc string, projectId string) (string, error) { - params := make(map[string]string) - params["ZoneId"] = zoneId - params["DiskName"] = name - if len(desc) > 0 { - params["Description"] = desc - } - params["Encrypted"] = "false" - params["DiskCategory"] = category - if category == api.STORAGE_CLOUD_ESSD_PL2 { - params["DiskCategory"] = api.STORAGE_CLOUD_ESSD - params["PerformanceLevel"] = "PL2" - } - if category == api.STORAGE_CLOUD_ESSD_PL3 { - params["DiskCategory"] = api.STORAGE_CLOUD_ESSD - params["PerformanceLevel"] = "PL3" - } - - if len(projectId) > 0 { - params["ResourceGroupId"] = projectId - } - params["Size"] = fmt.Sprintf("%d", sizeGb) - params["ClientToken"] = utils.GenRequestId(20) - - body, err := self.ecsRequest("CreateDisk", params) - if err != nil { - return "", err - } - return body.GetString("DiskId") -} - -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 { - params := make(map[string]string) - params["DiskId"] = diskId - - _, err := self.ecsRequest("DeleteDisk", params) - return err -} - -func (self *SRegion) resizeDisk(diskId string, sizeMb int64) error { - sizeGb := sizeMb / 1024 - params := make(map[string]string) - params["DiskId"] = diskId - params["NewSize"] = fmt.Sprintf("%d", sizeGb) - - _, err := self.ecsRequest("ResizeDisk", params) - if err != nil { - log.Errorf("resizing disk (%s) to %d GiB failed: %s", diskId, sizeGb, err) - return err - } - - return nil -} - -func (self *SRegion) resetDisk(diskId, snapshotId string) error { - params := make(map[string]string) - params["DiskId"] = diskId - params["SnapshotId"] = snapshotId - _, err := self.ecsRequest("ResetDisk", params) - if err != nil { - log.Errorf("ResetDisk %s to snapshot %s fail %s", diskId, snapshotId, err) - return err - } - - return nil -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { - snapshotId, err := self.storage.zone.region.CreateSnapshot(self.DiskId, name, desc) - if err != nil { - return nil, errors.Wrapf(err, "CreateSnapshot") - } - snapshot, err := self.storage.zone.region.GetISnapshotById(snapshotId) - if err != nil { - return nil, errors.Wrapf(err, "getSnapshot(%s)", snapshotId) - } - err = cloudprovider.WaitStatus(snapshot, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second) - if err != nil { - return nil, errors.Wrapf(err, "cloudprovider.WaitStatus") - } - return snapshot, nil -} - -func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["DiskId"] = diskId - params["SnapshotName"] = name - params["Description"] = desc - - if body, err := self.ecsRequest("CreateSnapshot", params); err != nil { - log.Errorf("CreateSnapshot fail %s", err) - return "", err - } else { - return body.GetString("SnapshotId") - } -} - -func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - return self.storage.zone.region.GetISnapshotById(snapshotId) -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots := make([]SSnapshot, 0) - for { - parts, total, err := self.storage.zone.region.GetSnapshots("", self.DiskId, "", []string{}, 0, 20) - if err != nil { - return nil, errors.Wrapf(err, "GetSnapshots(%s)", self.DiskId) - } - snapshots = append(snapshots, parts...) - if len(snapshots) >= total { - break - } - } - isnapshots := []cloudprovider.ICloudSnapshot{} - for i := 0; i < len(snapshots); i++ { - snapshots[i].region = self.storage.zone.region - isnapshots = append(isnapshots, &snapshots[i]) - } - return isnapshots, nil -} - -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", self.storage.zone.region.resetDisk(self.DiskId, snapshotId) -} - -func (self *SDisk) GetBillingType() string { - return convertChargeType(self.DiskChargeType) -} - -func (self *SDisk) GetCreatedAt() time.Time { - return self.CreationTime -} - -func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { - if len(self.AutoSnapshotPolicyId) == 0 { - return []string{}, nil - } - return []string{self.AutoSnapshotPolicyId}, nil -} - -func (self *SDisk) GetExpiredAt() time.Time { - return convertExpiredAt(self.ExpiredTime) -} - -func (self *SDisk) GetAccessPath() string { - return "" -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - err := self.storage.zone.region.rebuildDisk(self.DiskId) - if err != nil { - if isError(err, "IncorrectInstanceStatus") { - return nil - } - log.Errorf("rebuild disk fail %s", err) - return err - } - return nil -} - -func (self *SRegion) rebuildDisk(diskId string) error { - params := make(map[string]string) - params["DiskId"] = diskId - _, err := self.ecsRequest("ReInitDisk", params) - if err != nil { - log.Errorf("ReInitDisk %s fail %s", diskId, err) - return err - } - return nil -} - -func (self *SDisk) GetProjectId() string { - return self.ResourceGroupId -} diff --git a/pkg/multicloud/aliyun/dns_domain.go b/pkg/multicloud/aliyun/dns_domain.go deleted file mode 100644 index 358e05bce8..0000000000 --- a/pkg/multicloud/aliyun/dns_domain.go +++ /dev/null @@ -1,437 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "strconv" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDomain struct { - multicloud.SResourceBase - multicloud.AliyunTags - client *SAliyunClient - ttlMinValue int64 - PunyCode string `json:"PunyCode"` - VersionCode string `json:"VersionCode"` - InstanceID string `json:"InstanceId"` - AliDomain bool `json:"AliDomain"` - DomainName string `json:"DomainName"` - DomainID string `json:"DomainId"` - DNSServers DNSServers `json:"DnsServers"` - GroupID string `json:"GroupId"` -} - -type SDomains struct { - PageNumber int `json:"PageNumber"` - TotalCount int `json:"TotalCount"` - PageSize int `json:"PageSize"` - // RequestID string `json:"RequestId"` - Domains sDomains `json:"Domains"` -} - -type DNSServers struct { - DNSServer []string `json:"DnsServer"` -} - -type sDomains struct { - Domain []SDomain `json:"Domain"` -} - -// https://help.aliyun.com/document_detail/29758.html?spm=a2c4g.11186623.6.653.2ad93b59euq4oF -type SDNSProduct struct { - client *SAliyunClient - InstanceID string `json:"InstanceId"` - VersionCode string `json:"VersionCode"` - VersionName string `json:"VersionName"` - StartTime int64 `json:"StartTime"` - EndTime int64 `json:"EndTime"` - Domain string `json:"Domain"` - BindCount int64 `json:"BindCount"` - BindUsedCount int64 `json:"BindUsedCount"` - TTLMinValue int64 `json:"TTLMinValue"` - SubDomainLevel int64 `json:"SubDomainLevel"` - DNSSLBCount int64 `json:"DnsSLBCount"` - URLForwardCount int64 `json:"URLForwardCount"` - DDosDefendFlow int64 `json:"DDosDefendFlow"` - DDosDefendQuery int64 `json:"DDosDefendQuery"` - OverseaDDosDefendFlow int64 `json:"OverseaDDosDefendFlow"` - SearchEngineLines string `json:"SearchEngineLines"` - ISPLines string `json:"ISPLines"` - ISPRegionLines string `json:"ISPRegionLines"` - OverseaLine string `json:"OverseaLine"` -} - -type sDNSProducts struct { - DNSProduct []SDNSProduct `json:"DnsProduct"` -} - -type SDNSProducts struct { - // RequestID string `json:"RequestId"` - TotalCount int `json:"TotalCount"` - PageNumber int `json:"PageNumber"` - PageSize int `json:"PageSize"` - DNSProducts sDNSProducts `json:"DnsProducts"` -} - -// https://help.aliyun.com/document_detail/29758.html?spm=a2c4g.11186623.6.653.4b6d6970WphX2t -func (client *SAliyunClient) DescribeDnsProductInstances(pageNumber int, pageSize int) (SDNSProducts, error) { - sproducts := SDNSProducts{} - params := map[string]string{} - params["Action"] = "DescribeDnsProductInstances" - params["PageNumber"] = strconv.Itoa(pageNumber) - params["PageSize"] = strconv.Itoa(pageSize) - resp, err := client.alidnsRequest("DescribeDnsProductInstances", params) - if err != nil { - return sproducts, errors.Wrap(err, "DescribeDnsProductInstances") - } - err = resp.Unmarshal(&sproducts, "DnsProducts") - if err != nil { - return sproducts, errors.Wrap(err, "resp.Unmarshal") - } - return sproducts, nil -} - -func (client *SAliyunClient) GetAllDnsProductInstances() ([]SDNSProduct, error) { - pageNumber := 0 - sproducts := []SDNSProduct{} - for { - pageNumber++ - products, err := client.DescribeDnsProductInstances(pageNumber, 20) - if err != nil { - return nil, errors.Wrapf(err, "client.DescribeDnsProductInstances(%d, 20)", pageNumber) - } - sproducts = append(sproducts, products.DNSProducts.DNSProduct...) - if len(sproducts) >= products.TotalCount { - break - } - } - for i := 0; i < len(sproducts); i++ { - sproducts[i].client = client - } - return sproducts, nil -} - -// https://help.aliyun.com/document_detail/29751.html?spm=a2c4g.11186623.6.638.55563230d00kzJ -func (client *SAliyunClient) DescribeDomains(pageNumber int, pageSize int) (SDomains, error) { - sdomains := SDomains{} - params := map[string]string{} - params["Action"] = "DescribeDomains" - params["PageNumber"] = strconv.Itoa(pageNumber) - params["PageSize"] = strconv.Itoa(pageSize) - resp, err := client.alidnsRequest("DescribeDomains", params) - if err != nil { - return sdomains, errors.Wrap(err, "DescribeDomains") - } - err = resp.Unmarshal(&sdomains) - if err != nil { - return sdomains, errors.Wrap(err, "resp.Unmarshal") - } - return sdomains, nil -} - -func (client *SAliyunClient) GetAllDomains() ([]SDomain, error) { - pageNumber := 0 - sdomains := []SDomain{} - for { - pageNumber += 1 - domains, err := client.DescribeDomains(pageNumber, 20) - if err != nil { - return nil, errors.Wrapf(err, "client.DescribeDomains(%d, 20)", pageNumber) - } - sdomains = append(sdomains, domains.Domains.Domain...) - if len(sdomains) >= domains.TotalCount { - break - } - } - for i := 0; i < len(sdomains); i++ { - sdomains[i].client = client - } - return sdomains, nil -} - -func (client *SAliyunClient) GetPublicICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { - izones := []cloudprovider.ICloudDnsZone{} - sdomains, err := client.GetAllDomains() - if err != nil { - return nil, errors.Wrap(err, "client.GetAllDomains()") - } - for i := 0; i < len(sdomains); i++ { - izones = append(izones, &sdomains[i]) - } - return izones, nil -} - -func (client *SAliyunClient) DescribeDomainInfo(domainName string) (*SDomain, error) { - sdomain := &SDomain{client: client} - params := map[string]string{} - params["Action"] = "DescribeDomainInfo" - params["DomainName"] = domainName - resp, err := client.alidnsRequest("DescribeDomainInfo", params) - if err != nil { - return sdomain, errors.Wrap(err, "DescribeDomainInfo") - } - err = resp.Unmarshal(sdomain) - if err != nil { - return sdomain, errors.Wrap(err, "resp.Unmarshal") - } - return sdomain, nil -} - -func (client *SAliyunClient) GetPublicICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { - izones, err := client.GetPublicICloudDnsZones() - if err != nil { - return nil, errors.Wrapf(err, "client.DescribeDomainInfo(%s)", id) - } - for i := 0; i < len(izones); i++ { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (client *SAliyunClient) AddDomain(domainName string) (*SDomain, error) { - sdomain := &SDomain{client: client} - params := map[string]string{} - params["Action"] = "AddDomain" - params["DomainName"] = domainName - resp, err := client.alidnsRequest("AddDomain", params) - if err != nil { - return sdomain, errors.Wrap(err, "AddDomain") - } - err = resp.Unmarshal(sdomain) - if err != nil { - return sdomain, errors.Wrapf(err, "%s:resp.Unmarshal()", resp) - } - return sdomain, nil -} - -func (client *SAliyunClient) CreatePublicICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { - sdomain, err := client.AddDomain(opts.Name) - if err != nil { - return nil, errors.Wrapf(err, "client.AddDomain(%s)", opts.Name) - } - return sdomain, nil -} - -func (client *SAliyunClient) DeleteDomain(domainName string) error { - params := map[string]string{} - params["Action"] = "DeleteDomain" - params["DomainName"] = domainName - _, err := client.alidnsRequest("DeleteDomain", params) - if err != nil { - return errors.Wrap(err, "DeleteDomain") - } - return nil -} - -func (self *SDomain) GetId() string { - return self.DomainID -} - -func (self *SDomain) GetName() string { - if len(self.PunyCode) > 0 { - return self.PunyCode - } - return self.DomainName -} - -func (self *SDomain) GetGlobalId() string { - return self.GetId() -} - -func (self *SDomain) GetStatus() string { - return api.DNS_ZONE_STATUS_AVAILABLE -} - -func (self *SDomain) Refresh() error { - sdomain, err := self.client.DescribeDomainInfo(self.DomainName) - if err != nil { - return errors.Wrapf(err, "self.client.DescribeDomainInfo(%s)", self.DomainName) - } - return jsonutils.Update(self, sdomain) -} - -func (self *SDomain) GetZoneType() cloudprovider.TDnsZoneType { - return cloudprovider.PublicZone -} -func (self *SDomain) GetOptions() *jsonutils.JSONDict { - return nil -} - -func (self *SDomain) GetICloudVpcIds() ([]string, error) { - return nil, nil -} -func (self *SDomain) AddVpc(vpc *cloudprovider.SPrivateZoneVpc) error { - return cloudprovider.ErrNotSupported -} -func (self *SDomain) RemoveVpc(vpc *cloudprovider.SPrivateZoneVpc) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDomain) GetIDnsRecordSets() ([]cloudprovider.ICloudDnsRecordSet, error) { - irecords := []cloudprovider.ICloudDnsRecordSet{} - records, err := self.client.GetAllDomainRecords(self.DomainName) - if err != nil { - return nil, errors.Wrapf(err, "self.client.GetAllDomainRecords(%s)", self.DomainName) - } - for i := 0; i < len(records); i++ { - irecords = append(irecords, &records[i]) - } - return irecords, nil -} - -func (self *SDomain) SyncDnsRecordSets(common, add, del, update []cloudprovider.DnsRecordSet) error { - for i := 0; i < len(common); i++ { - if len(common[i].Desc) > 0 { - err := self.client.UpdateDomainRecordRemark(common[i].ExternalId, common[i].Desc) - if err != nil { - return errors.Wrapf(err, "UpdateDomainRecordRemark") - } - } - } - for i := 0; i < len(del); i++ { - err := self.client.DeleteDomainRecord(del[i].ExternalId) - if err != nil { - return errors.Wrapf(err, "self.client.DeleteDomainRecord(%s)", del[i].ExternalId) - } - } - - for i := 0; i < len(add); i++ { - recordId, err := self.client.AddDomainRecord(self.DomainName, add[i]) - if err != nil { - return errors.Wrapf(err, "self.client.AddDomainRecord(%s,%s)", self.DomainName, jsonutils.Marshal(add[i]).String()) - } - if !add[i].Enabled { - // Enable: 启用解析 Disable: 暂停解析 - err = self.client.SetDomainRecordStatus(recordId, "Disable") - if err != nil { - return errors.Wrapf(err, "self.client.SetDomainRecordStatus(%s,%t)", recordId, add[i].Enabled) - } - } - if len(add[i].Desc) > 0 { - err = self.client.UpdateDomainRecordRemark(recordId, add[i].Desc) - if err != nil { - return errors.Wrapf(err, "UpdateDomainRecordRemark") - } - } - } - - for i := 0; i < len(update); i++ { - // Enable: 启用解析 Disable: 暂停解析 - status := "Enable" - if !update[i].Enabled { - status = "Disable" - } - err := self.client.SetDomainRecordStatus(update[i].ExternalId, status) - if err != nil { - return errors.Wrapf(err, "self.client.SetDomainRecordStatus(%s,%t)", update[i].ExternalId, update[i].Enabled) - } - domainRecord, err := self.client.DescribeDomainRecordInfo(update[i].ExternalId) - if err != nil { - return errors.Wrapf(err, "self.client.DescribeDomainRecordInfo(%s)", update[i].ExternalId) - } - if !domainRecord.match(update[i]) { - err = self.client.UpdateDomainRecord(update[i]) - if err != nil { - return errors.Wrapf(err, "self.client.UpdateDomainRecord(%s)", jsonutils.Marshal(update[i]).String()) - } - } - if len(update[i].Desc) > 0 { - err = self.client.UpdateDomainRecordRemark(update[i].ExternalId, update[i].Desc) - if err != nil { - return errors.Wrapf(err, "UpdateDomainRecordRemark") - } - } - } - return nil -} - -func (self *SDomain) Delete() error { - return self.client.DeleteDomain(self.DomainName) -} - -func TDnsProductType(productName string) cloudprovider.TDnsProductType { - switch productName { - case "企业旗舰版": - return cloudprovider.DnsProductEnterpriseUltimate - case "企业标准版": - return cloudprovider.DnsProductEnterpriseStandard - case "个人版": - return cloudprovider.DnsProductPersonalProfessional - default: - return cloudprovider.DnsProductFree - } -} - -func (self *SDomain) GetDnsProductType() cloudprovider.TDnsProductType { - sproducts, err := self.client.GetAllDnsProductInstances() - if err != nil { - log.Errorf("self.client.GetAllDnsProductInstances():%s", err) - return cloudprovider.DnsProductFree - } - // https://help.aliyun.com/document_detail/29806.html?spm=a2c4g.11186623.4.1.67728197c8SCN9 - // 免费版,最低600 - self.ttlMinValue = 600 - for i := 0; i < len(sproducts); i++ { - if sproducts[i].Domain == self.DomainName { - return TDnsProductType(sproducts[i].VersionName) - } - } - return cloudprovider.DnsProductFree -} - -func (self *SDomain) fetchTTLMinValue() (int64, error) { - if self.ttlMinValue != 0 { - return self.ttlMinValue, nil - } - sproducts, err := self.client.GetAllDnsProductInstances() - if err != nil { - return 0, errors.Wrap(err, "self.client.GetAllDnsProductInstances()") - } - // https://help.aliyun.com/document_detail/29806.html?spm=a2c4g.11186623.4.1.67728197c8SCN9 - // 免费版,最低600 - self.ttlMinValue = 600 - for i := 0; i < len(sproducts); i++ { - if sproducts[i].Domain == self.DomainName { - self.ttlMinValue = sproducts[i].TTLMinValue - return self.ttlMinValue, nil - } - } - return self.ttlMinValue, nil -} - -func (self *SDomain) GetProperlyTTL(ttl int64) int64 { - ttlMin, err := self.fetchTTLMinValue() - if err != nil { - log.Errorf("self.fetchTTLMinValue():%s", err) - ttlMin = 600 - } - if ttl <= ttlMin { - return ttlMin - } - if ttl > 86400 { - return 86400 - } - return ttl -} diff --git a/pkg/multicloud/aliyun/doc.go b/pkg/multicloud/aliyun/doc.go deleted file mode 100644 index 7e8e797f60..0000000000 --- a/pkg/multicloud/aliyun/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun // import "yunion.io/x/onecloud/pkg/multicloud/aliyun" diff --git a/pkg/multicloud/aliyun/eip.go b/pkg/multicloud/aliyun/eip.go deleted file mode 100644 index c4d533a7a3..0000000000 --- a/pkg/multicloud/aliyun/eip.go +++ /dev/null @@ -1,395 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type TInternetChargeType string - -const ( - InternetChargeByTraffic = TInternetChargeType("PayByTraffic") - InternetChargeByBandwidth = TInternetChargeType("PayByBandwidth") -) - -const ( - EIP_STATUS_ASSOCIATING = "Associating" - EIP_STATUS_UNASSOCIATING = "Unassociating" - EIP_STATUS_INUSE = "InUse" - EIP_STATUS_AVAILABLE = "Available" - - EIP_OPERATION_LOCK_FINANCIAL = "financial" - EIP_OPERATION_LOCK_SECURITY = "security" - - EIP_INSTANCE_TYPE_ECS = "EcsInstance" // (默认值):VPC类型的ECS实例 - EIP_INTANNCE_TYPE_SLB = "SlbInstance" // :VPC类型的SLB实例 - EIP_INSTANCE_TYPE_NAT = "Nat" // :NAT网关 - EIP_INSTANCE_TYPE_HAVIP = "HaVip" // :HAVIP -) - -/* -{ - "AllocationId":"eip-2zeddtan63ou44dtyt9s3", - "AllocationTime":"2019-02-23T06:48:36Z", - "Bandwidth":"100", - "ChargeType":"PostPaid", - "ExpiredTime":"", - "InstanceId":"", - "InstanceType":"", - "InternetChargeType":"PayByTraffic", - "IpAddress":"39.105.131.32", - "OperationLocks":{"LockReason":[]}, - "RegionId":"cn-beijing", - "Status":"Available" -} -*/ - -type SEipAddress struct { - region *SRegion - multicloud.SEipBase - multicloud.AliyunTags - - Name string - AllocationId string - - InternetChargeType TInternetChargeType - - IpAddress string - Status string - - InstanceType string - InstanceId string - Bandwidth int /* Mbps */ - - BusinessStatus string - AllocationTime time.Time - DeletionProtection bool - Descritpion string - ISP string - Mode string - Netmode string - - OperationLocks string - - ChargeType TChargeType - ExpiredTime time.Time - ResourceGroupId string -} - -func (self *SEipAddress) GetId() string { - return self.AllocationId -} - -func (self *SEipAddress) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.IpAddress -} - -func (self *SEipAddress) GetGlobalId() string { - return self.AllocationId -} - -func (self *SEipAddress) GetStatus() string { - switch self.Status { - case EIP_STATUS_AVAILABLE, EIP_STATUS_INUSE: - return api.EIP_STATUS_READY - case EIP_STATUS_ASSOCIATING: - return api.EIP_STATUS_ASSOCIATE - case EIP_STATUS_UNASSOCIATING: - return api.EIP_STATUS_DISSOCIATE - default: - return api.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 { - // fixed Public IP - return true - } else { - return false - } -} - -func (self *SEipAddress) GetIpAddr() string { - return self.IpAddress -} - -func (self *SEipAddress) GetMode() string { - if self.InstanceId == self.AllocationId { - return api.EIP_MODE_INSTANCE_PUBLICIP - } else { - return api.EIP_MODE_STANDALONE_EIP - } -} - -func (self *SEipAddress) GetAssociationType() string { - switch self.InstanceType { - case EIP_INSTANCE_TYPE_ECS, "NetworkInterface": - return api.EIP_ASSOCIATE_TYPE_SERVER - case EIP_INSTANCE_TYPE_NAT: - return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY - case EIP_INTANNCE_TYPE_SLB: - return api.EIP_ASSOCIATE_TYPE_LOADBALANCER - default: - return self.InstanceType - } -} - -func (self *SEipAddress) GetAssociationExternalId() string { - return self.InstanceId -} - -func (self *SEipAddress) GetBillingType() string { - return convertChargeType(self.ChargeType) -} - -func (self *SEipAddress) GetCreatedAt() time.Time { - return self.AllocationTime -} - -func (self *SEipAddress) GetExpiredAt() time.Time { - return convertExpiredAt(self.ExpiredTime) -} - -func (self *SEipAddress) Delete() error { - return self.region.DeallocateEIP(self.AllocationId) -} - -func (self *SEipAddress) GetBandwidth() int { - return self.Bandwidth -} - -func (self *SEipAddress) GetINetworkId() string { - return "" -} - -func (self *SEipAddress) GetInternetChargeType() string { - switch self.InternetChargeType { - case InternetChargeByTraffic: - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - case InternetChargeByBandwidth: - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH - default: - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - } -} - -func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { - err := cloudprovider.Wait(20*time.Second, 60*time.Second, func() (bool, error) { - err := self.region.AssociateEip(self.AllocationId, conf.InstanceId) - if err != nil { - if isError(err, "IncorrectInstanceStatus") { - return false, nil - } - return false, errors.Wrap(err, "region.AssociateEip") - } - return true, nil - }) - err = cloudprovider.WaitStatus(self, api.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, api.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 (region *SRegion) GetEips(eipId string, associatedId, addr string, offset int, limit int) ([]SEipAddress, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - if len(addr) > 0 { - params["EipAddress"] = addr - } - - if len(eipId) > 0 { - params["AllocationId"] = eipId - } - - if len(associatedId) > 0 { - params["AssociatedInstanceId"] = associatedId - for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "ngw-": "Nat", "lb-": "SlbInstance"} { - if strings.HasPrefix(associatedId, prefix) { - params["AssociatedInstanceType"] = instanceType - } - } - } - - body, err := region.vpcRequest("DescribeEipAddresses", params) - if err != nil { - log.Errorf("DescribeEipAddresses fail %s", err) - return nil, 0, err - } - - eips := make([]SEipAddress, 0) - err = body.Unmarshal(&eips, "EipAddresses", "EipAddress") - if err != nil { - log.Errorf("Unmarshal EipAddress details fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - for i := 0; i < len(eips); i += 1 { - eips[i].region = region - } - return eips, int(total), nil -} - -func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { - eips, total, err := region.GetEips(eipId, "", "", 0, 1) - if err != nil { - return nil, err - } - if total != 1 { - return nil, cloudprovider.ErrNotFound - } - return &eips[0], nil -} - -func (region *SRegion) AllocateEIP(name string, bwMbps int, chargeType TInternetChargeType, projectId string) (*SEipAddress, error) { - params := make(map[string]string) - - if len(name) > 0 { - params["Name"] = name - } - params["Bandwidth"] = fmt.Sprintf("%d", bwMbps) - params["InternetChargeType"] = string(chargeType) - params["InstanceChargeType"] = "PostPaid" - params["ClientToken"] = utils.GenRequestId(20) - if len(projectId) > 0 { - params["ResourceGroupId"] = projectId - } - - body, err := region.vpcRequest("AllocateEipAddress", params) - if err != nil { - log.Errorf("AllocateEipAddress fail %s", err) - return nil, err - } - - eipId, err := body.GetString("AllocationId") - if err != nil { - log.Errorf("fail to get AllocationId after EIP allocation??? %s", err) - return nil, err - } - - return region.GetEip(eipId) -} - -func (region *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - var ctype TInternetChargeType - switch opts.ChargeType { - case api.EIP_CHARGE_TYPE_BY_TRAFFIC: - ctype = InternetChargeByTraffic - case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: - ctype = InternetChargeByBandwidth - } - return region.AllocateEIP(opts.Name, opts.BandwidthMbps, ctype, opts.ProjectId) -} - -func (region *SRegion) DeallocateEIP(eipId string) error { - params := make(map[string]string) - params["AllocationId"] = eipId - - _, err := region.vpcRequest("ReleaseEipAddress", params) - if err != nil { - log.Errorf("ReleaseEipAddress fail %s", err) - } - return err -} - -func (region *SRegion) AssociateEip(eipId string, instanceId string) error { - params := make(map[string]string) - params["AllocationId"] = eipId - params["InstanceId"] = instanceId - for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "lb-": "SlbInstance", "ngw-": "Nat"} { - if strings.HasPrefix(instanceId, prefix) { - params["InstanceType"] = instanceType - } - } - - _, err := region.vpcRequest("AssociateEipAddress", params) - return errors.Wrapf(err, "AssociateEipAddress") -} - -func (region *SRegion) DissociateEip(eipId string, instanceId string) error { - params := make(map[string]string) - params["AllocationId"] = eipId - params["InstanceId"] = instanceId - for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "lb-": "SlbInstance", "ngw-": "Nat"} { - if strings.HasPrefix(instanceId, prefix) { - params["InstanceType"] = instanceType - } - } - - _, err := region.vpcRequest("UnassociateEipAddress", params) - if err != nil { - log.Errorf("UnassociateEipAddress fail %s", err) - } - return err -} - -func (region *SRegion) UpdateEipBandwidth(eipId string, bw int) error { - params := make(map[string]string) - params["AllocationId"] = eipId - params["Bandwidth"] = fmt.Sprintf("%d", bw) - - _, err := region.vpcRequest("ModifyEipAddressAttribute", params) - if err != nil { - log.Errorf("ModifyEipAddressAttribute fail %s", err) - } - return err -} - -func (self *SEipAddress) GetProjectId() string { - return self.ResourceGroupId -} diff --git a/pkg/multicloud/aliyun/elastic_search.go b/pkg/multicloud/aliyun/elastic_search.go deleted file mode 100644 index 47bcbe8993..0000000000 --- a/pkg/multicloud/aliyun/elastic_search.go +++ /dev/null @@ -1,373 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElasticSearch struct { - multicloud.SVirtualResourceBase - multicloud.SBillingBase - region *SRegion - - Tags []struct { - TagKey string - TagValue string - } - AdvancedDedicateMaster bool - AdvancedSetting struct { - gcName string - } - AliwsDicts []struct { - FileSize int - Name string - SourceType string - Type string - } - ClientNodeConfiguration struct { - Amount int - Disk int - DiskType string - Spec string - } - InstanceCategory string - CreatedAt time.Time - DedicateMaster bool - Description string - DictList []struct { - FileSize int - Name string - SourceType string - Type string - } - Domain string - ElasticDataNodeConfiguration struct { - Amount int - Disk int - DiskType string - Spec string - } - EnableKibanaPrivateNetwork bool - EnableKibanaPublicNetwork bool - EnablePublic bool - EsConfig map[string]string - EsIPBlacklist []string - EsIPWhitelist []string - EsVersion string - ExtendConfigs []struct { - ConfigType string - Value string - MaintainEndTime string - AliVersion string - } - HaveClientNode bool - HaveKibana bool - InstanceId string - KibanaConfiguration struct { - Amount int - Spec string - } - KibanaDomain string - KibanaIPWhitelist []string - KibanaPort int - KibanaPrivateIPWhitelist []string - MasterConfiguration struct { - Amount int - Disk int - DiskType string - Spec string - } - NetworkConfig struct { - Type string - VpcId string - VsArea string - VswitchId string - } - NodeAmount int - NodeSpec struct { - Disk int - DiskEncryption bool - DiskType string - Spec string - } - PaymentType string - Port int - PrivateNetworkIpWhiteList []string - Protocol string - PublicDomain string - PublicIpWhitelist []string - PublicPort int - ResourceGroupId string - Status string - SynonymsDicts []struct { - FileSize int - Name string - SourceType string - Type string - } - UpdatedAt time.Time - VpcInstanceId string - WarmNode bool - WarmNodeConfiguration struct { - Amount int - Disk int - DiskEncryption bool - DiskType string - Spec string - } - ZoneCount int - ZoneInfos []struct { - status string - zoneId string - } -} - -func (self *SElasticSearch) GetTags() (map[string]string, error) { - ret := map[string]string{} - for _, tag := range self.Tags { - if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") { - continue - } - if len(tag.TagKey) > 0 { - ret[tag.TagKey] = tag.TagValue - } - } - return ret, nil -} - -func (self *SElasticSearch) GetSysTags() map[string]string { - ret := map[string]string{} - for _, tag := range self.Tags { - if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") { - if len(tag.TagKey) > 0 { - ret[tag.TagKey] = tag.TagValue - } - } - } - return ret -} - -func (self *SElasticSearch) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -func (self *SElasticSearch) GetId() string { - return self.InstanceId -} - -func (self *SElasticSearch) GetGlobalId() string { - return self.InstanceId -} - -func (self *SElasticSearch) GetName() string { - if len(self.Description) > 0 { - return self.Description - } - return self.InstanceId -} - -func (self *SElasticSearch) GetDiskSizeGb() int { - return self.NodeSpec.Disk -} - -func (self *SElasticSearch) GetStorageType() string { - return self.NodeSpec.DiskType -} - -func (self *SElasticSearch) GetCategory() string { - return self.InstanceCategory -} - -func (self *SElasticSearch) GetVersion() string { - return strings.Split(self.EsVersion, "_")[0] -} - -func (self *SElasticSearch) GetVpcId() string { - return self.NetworkConfig.VpcId -} - -func (self *SElasticSearch) GetNetworkId() string { - return self.NetworkConfig.VswitchId -} - -func (self *SElasticSearch) GetZoneId() string { - return self.NetworkConfig.VsArea -} - -func (self *SElasticSearch) IsMultiAz() bool { - return self.ZoneCount > 1 -} - -func (self *SElasticSearch) GetVcpuCount() int { - spec, ok := esSpec[self.NodeSpec.Spec] - if ok { - return spec.VcpuCount - } - return 0 -} - -func (self *SElasticSearch) GetVmemSizeGb() int { - spec, ok := esSpec[self.NodeSpec.Spec] - if ok { - return spec.VmemSizeGb - } - return 0 -} - -func (self *SElasticSearch) GetInstanceType() string { - return self.NodeSpec.Spec -} - -func (self *SElasticSearch) Refresh() error { - es, err := self.region.GetElasitcSearch(self.InstanceId) - if err != nil { - return err - } - return jsonutils.Update(self, es) -} - -func (self *SElasticSearch) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SElasticSearch) GetBillingType() string { - return self.PaymentType -} - -func (self *SElasticSearch) GetProjectId() string { - return self.ResourceGroupId -} - -func (self *SElasticSearch) GetStatus() string { - switch self.Status { - case "active": - return api.ELASTIC_SEARCH_STATUS_AVAILABLE - case "activating": - return api.ELASITC_SEARCH_STATUS_CREATING - case "inactive": - return api.ELASTIC_SEARCH_STATUS_UNAVAILABLE - case "invalid": - return api.ELASTIC_SEARCH_STATUS_DELETING - default: - return self.Status - } -} - -func (self *SElasticSearch) GetAccessInfo() (*cloudprovider.ElasticSearchAccessInfo, error) { - return &cloudprovider.ElasticSearchAccessInfo{ - Domain: self.PublicDomain, - PrivateDomain: self.Domain, - Port: self.PublicPort, - PrivatePort: self.Port, - KibanaUrl: self.KibanaDomain, - }, nil -} - -func (self *SRegion) GetIElasticSearchs() ([]cloudprovider.ICloudElasticSearch, error) { - ret := []SElasticSearch{} - for { - part, total, err := self.GetElasticSearchs(100, len(ret)/100+1) - if err != nil { - return nil, errors.Wrapf(err, "GetElasitcSearchs") - } - ret = append(ret, part...) - if len(ret) >= total { - break - } - } - result := []cloudprovider.ICloudElasticSearch{} - for i := range ret { - ret[i].region = self - result = append(result, &ret[i]) - } - return result, nil -} - -func (self *SRegion) GetIElasticSearchById(id string) (cloudprovider.ICloudElasticSearch, error) { - es, err := self.GetElasitcSearch(id) - if err != nil { - return nil, err - } - return es, nil -} - -func (self *SRegion) GetElasticSearchs(size, page int) ([]SElasticSearch, int, error) { - if size < 1 || size > 100 { - size = 100 - } - if page < 1 { - page = 1 - } - params := map[string]string{ - "PathPattern": "/openapi/instances", - "size": fmt.Sprintf("%d", size), - "page": fmt.Sprintf("%d", page), - } - resp, err := self.esRequest("ListInstance", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "ListInstance") - } - ret := []SElasticSearch{} - err = resp.Unmarshal(&ret, "Result") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - totalCount, _ := resp.Int("Headers", "X-Total-Count") - return ret, int(totalCount), nil -} - -func (self *SRegion) GetElasitcSearch(id string) (*SElasticSearch, error) { - if len(id) == 0 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty id") - } - params := map[string]string{ - "PathPattern": fmt.Sprintf("/openapi/instances/%s", id), - } - resp, err := self.esRequest("DescribeInstance", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeInstance") - } - ret := SElasticSearch{region: self} - err = resp.Unmarshal(&ret, "Result") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return &ret, nil -} - -func (self *SElasticSearch) Delete() error { - return self.region.DeleteElasticSearch(self.InstanceId) -} - -func (self *SRegion) DeleteElasticSearch(id string) error { - params := map[string]string{ - "clientToken": utils.GenRequestId(20), - "deleteType": "immediate", - "PathPattern": fmt.Sprintf("/openapi/instances/%s", id), - } - _, err := self.esRequest("DeleteInstance", params) - return errors.Wrapf(err, "DeleteInstance") -} diff --git a/pkg/multicloud/aliyun/elasticcache_account.go b/pkg/multicloud/aliyun/elasticcache_account.go deleted file mode 100644 index 54bd17d459..0000000000 --- a/pkg/multicloud/aliyun/elasticcache_account.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://help.aliyun.com/document_detail/95802.html?spm=a2c4g.11186623.6.746.1d4b302ayCuzXB -type SElasticcacheAccount struct { - multicloud.SElasticcacheAccountBase - multicloud.AliyunTags - - cacheDB *SElasticcache - - AccountStatus string `json:"AccountStatus"` - DatabasePrivileges DatabasePrivileges `json:"DatabasePrivileges"` - InstanceID string `json:"InstanceId"` - AccountName string `json:"AccountName"` - PrivExceeded string `json:"PrivExceeded"` - AccountType string `json:"AccountType"` -} - -type DatabasePrivileges struct { - DatabasePrivilege []DatabasePrivilege `json:"DatabasePrivilege"` -} - -type DatabasePrivilege struct { - AccountPrivilege string `json:"AccountPrivilege"` -} - -func (self *SElasticcacheAccount) GetId() string { - return fmt.Sprintf("%s/%s", self.InstanceID, self.AccountName) -} - -func (self *SElasticcacheAccount) GetName() string { - return self.AccountName -} - -func (self *SElasticcacheAccount) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheAccount) GetStatus() string { - switch strings.ToLower(self.AccountStatus) { - case "unavailable": - return api.ELASTIC_CACHE_ACCOUNT_STATUS_UNAVAILABLE - case "available": - return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE - default: - return self.AccountStatus - } -} - -func (self *SElasticcacheAccount) Refresh() error { - iaccount, err := self.cacheDB.GetICloudElasticcacheAccountByName(self.GetName()) - if err != nil { - return err - } - - err = jsonutils.Update(self, iaccount.(*SElasticcacheAccount)) - if err != nil { - return err - } - - return nil -} - -func (self *SElasticcacheAccount) GetAccountType() string { - if self.AccountName == self.cacheDB.InstanceID { - return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN - } - - switch self.AccountType { - case "Normal": - return api.ELASTIC_CACHE_ACCOUNT_TYPE_NORMAL - case "Super": - return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN - default: - return self.AccountType - } -} - -func (self *SElasticcacheAccount) GetAccountPrivilege() string { - if len(self.DatabasePrivileges.DatabasePrivilege) == 0 { - return "" - } - - privilege := self.DatabasePrivileges.DatabasePrivilege[0].AccountPrivilege - switch privilege { - case "RoleReadOnly": - return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_READ - case "RoleReadWrite": - return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE - case "RoleRepl": - return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_REPL - default: - return privilege - } -} - -// https://help.aliyun.com/document_detail/95941.html?spm=a2c4g.11186623.6.746.523555d8D8Whxq -// https://help.aliyun.com/document_detail/98531.html?spm=5176.11065259.1996646101.searchclickresult.4df474c38Sc2SO -func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { - params := make(map[string]string) - params["InstanceId"] = self.cacheDB.GetId() - params["AccountName"] = self.GetName() - params["AccountPassword"] = input.NewPassword - - err := DoAction(self.cacheDB.region.kvsRequest, "ResetAccountPassword", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.ResetPassword") - } - - if input.NoPasswordAccess != nil { - return cloudprovider.ErrNotSupported - } - - return nil -} - -func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { - if input.Password != nil { - inputPassword := cloudprovider.SCloudElasticCacheAccountResetPasswordInput{} - inputPassword.NewPassword = *input.Password - inputPassword.NoPasswordAccess = input.NoPasswordAccess - err := self.ResetPassword(inputPassword) - if err != nil { - return err - } - } - - if input.Description != nil { - err := self.ModifyAccountDescription(*input.Description) - if err != nil { - return err - } - } - - if input.AccountPrivilege != nil { - err := self.GrantAccountPrivilege(*input.AccountPrivilege) - if err != nil { - return err - } - } - - return nil -} - -// https://help.aliyun.com/document_detail/96020.html?spm=a2c4g.11186623.6.747.5c6f1c717weYEX -func (self *SElasticcacheAccount) ModifyAccountDescription(desc string) error { - params := make(map[string]string) - params["InstanceId"] = self.cacheDB.GetId() - params["AccountName"] = self.GetName() - params["AccountDescription"] = desc - - err := DoAction(self.cacheDB.region.kvsRequest, "ModifyAccountDescription", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.ModifyAccountDescription") - } - - return nil -} - -// https://help.aliyun.com/document_detail/95897.html?spm=a2c4g.11186623.6.745.28576cf9IqM44R -func (self *SElasticcacheAccount) GrantAccountPrivilege(privilege string) error { - params := make(map[string]string) - params["InstanceId"] = self.cacheDB.GetId() - params["AccountName"] = self.GetName() - params["AccountPrivilege"] = privilege - - err := DoAction(self.cacheDB.region.kvsRequest, "GrantAccountPrivilege", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.GrantAccountPrivilege") - } - - return nil -} - -// https://help.aliyun.com/document_detail/95988.html?spm=a2c4g.11186623.6.743.cb291c71D1Hlmu -func (self *SElasticcacheAccount) Delete() error { - params := make(map[string]string) - params["InstanceId"] = self.cacheDB.GetId() - params["AccountName"] = self.GetName() - - err := DoAction(self.cacheDB.region.kvsRequest, "DeleteAccount", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.Delete") - } - - return nil -} diff --git a/pkg/multicloud/aliyun/elasticcache_acl.go b/pkg/multicloud/aliyun/elasticcache_acl.go deleted file mode 100644 index 4313a2897c..0000000000 --- a/pkg/multicloud/aliyun/elasticcache_acl.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElasticcacheAcl struct { - multicloud.SElasticcacheAclBase - multicloud.AliyunTags - - cacheDB *SElasticcache - - SecurityIPList string `json:"SecurityIpList"` - SecurityIPGroupAttribute string `json:"SecurityIpGroupAttribute"` - SecurityIPGroupName string `json:"SecurityIpGroupName"` -} - -func (self *SElasticcacheAcl) GetId() string { - return fmt.Sprintf("%s/%s", self.cacheDB.GetId(), self.SecurityIPGroupName) -} - -func (self *SElasticcacheAcl) GetName() string { - return self.SecurityIPGroupName -} - -func (self *SElasticcacheAcl) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheAcl) GetStatus() string { - return api.ELASTIC_CACHE_ACL_STATUS_AVAILABLE -} - -func (self *SElasticcacheAcl) Refresh() error { - iacl, err := self.cacheDB.GetICloudElasticcacheAcl(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, iacl.(*SElasticcacheAcl)) - if err != nil { - return err - } - - return nil -} - -func (self *SElasticcacheAcl) GetIpList() string { - return self.SecurityIPList -} - -// https://help.aliyun.com/document_detail/61002.html?spm=a2c4g.11186623.6.764.3752782fJpbjxH -func (self *SElasticcacheAcl) Delete() error { - params := make(map[string]string) - params["InstanceId"] = self.cacheDB.GetId() - params["ModifyMode"] = "Delete" - params["SecurityIpGroupName"] = self.GetName() - params["SecurityIps"] = self.SecurityIPList - - err := DoAction(self.cacheDB.region.kvsRequest, "ModifySecurityIps", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAcl.Delete") - } - - return nil -} - -// https://help.aliyun.com/document_detail/61002.html?spm=a2c4g.11186623.6.764.3752782fJpbjxH -func (self *SElasticcacheAcl) UpdateAcl(securityIps string) error { - return self.cacheDB.region.createAcl(self.cacheDB.GetId(), self.GetName(), securityIps) -} - -func (self *SRegion) createAcl(instanceId, aclName, securityIps string) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["SecurityIpGroupName"] = aclName - params["ModifyMode"] = "Cover" - params["SecurityIps"] = securityIps - - err := DoAction(self.kvsRequest, "ModifySecurityIps", params, nil, nil) - if err != nil { - return errors.Wrap(err, "region.UpdateAcl") - } - - return nil -} diff --git a/pkg/multicloud/aliyun/elasticcache_backup.go b/pkg/multicloud/aliyun/elasticcache_backup.go deleted file mode 100644 index 3fb2ac71fc..0000000000 --- a/pkg/multicloud/aliyun/elasticcache_backup.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://help.aliyun.com/document_detail/61081.html?spm=a2c4g.11186623.6.752.3d7630beuL57kI -type SElasticcacheBackup struct { - multicloud.SElasticcacheBackupBase - multicloud.AliyunTags - - cacheDB *SElasticcache - - BackupIntranetDownloadURL string `json:"BackupIntranetDownloadURL"` - BackupType string `json:"BackupType"` - BackupEndTime time.Time `json:"BackupEndTime"` - BackupMethod string `json:"BackupMethod"` - BackupID int64 `json:"BackupId"` - BackupStartTime time.Time `json:"BackupStartTime"` - BackupDownloadURL string `json:"BackupDownloadURL"` - BackupDBNames string `json:"BackupDBNames"` - NodeInstanceID string `json:"NodeInstanceId"` - BackupMode string `json:"BackupMode"` - BackupStatus string `json:"BackupStatus"` - BackupSizeByte int64 `json:"BackupSize"` - EngineVersion string `json:"EngineVersion"` -} - -func (self *SElasticcacheBackup) GetId() string { - return fmt.Sprintf("%d", self.BackupID) -} - -func (self *SElasticcacheBackup) GetName() string { - return self.GetId() -} - -func (self *SElasticcacheBackup) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheBackup) GetStatus() string { - switch self.BackupStatus { - case "Success", "running": - return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS - case "Failed": - return api.ELASTIC_CACHE_BACKUP_STATUS_FAILED - default: - return self.BackupStatus - } -} - -func (self *SElasticcacheBackup) Refresh() error { - ibackup, err := self.cacheDB.GetICloudElasticcacheBackup(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, ibackup.(*SElasticcacheBackup)) - if err != nil { - return err - } - - return nil -} - -func (self *SElasticcacheBackup) GetBackupSizeMb() int { - return int(self.BackupSizeByte / 1024 / 1024) -} - -func (self *SElasticcacheBackup) GetBackupType() string { - switch self.BackupType { - case "FullBackup": - return api.ELASTIC_CACHE_BACKUP_TYPE_FULL - case "IncrementalBackup": - return api.ELASTIC_CACHE_BACKUP_TYPE_INCREMENTAL - default: - return self.BackupType - } -} - -func (self *SElasticcacheBackup) GetBackupMode() string { - switch self.BackupMode { - case "Automated": - return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED - case "Manual": - return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL - default: - return self.BackupMode - } -} - -func (self *SElasticcacheBackup) GetDownloadURL() string { - return self.BackupDownloadURL -} - -func (self *SElasticcacheBackup) GetStartTime() time.Time { - return self.BackupStartTime -} - -func (self *SElasticcacheBackup) GetEndTime() time.Time { - return self.BackupEndTime -} - -func (self *SElasticcacheBackup) Delete() error { - return cloudprovider.ErrNotSupported -} - -// https://help.aliyun.com/document_detail/61083.html?spm=a2c4g.11186623.6.753.216f67ddzpyvTL -func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["BackupId"] = self.GetId() - - // 目前没有查询备份ID的接口,因此,备份ID没什么用 - err := DoAction(self.cacheDB.region.kvsRequest, "RestoreInstance", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.RestoreInstance") - } - - return nil -} diff --git a/pkg/multicloud/aliyun/elasticcache_instance.go b/pkg/multicloud/aliyun/elasticcache_instance.go deleted file mode 100644 index ccaf2bfe75..0000000000 --- a/pkg/multicloud/aliyun/elasticcache_instance.go +++ /dev/null @@ -1,990 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strconv" - "strings" - "time" - - "github.com/aokoli/goutils" - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -// https://help.aliyun.com/document_detail/60933.html?spm=a2c4g.11186623.6.726.38f82ca9U1Gtxw -type SElasticcache struct { - multicloud.SElasticcacheBase - multicloud.AliyunTags - - region *SRegion - attribute *SElasticcacheAttribute - netinfo []SNetInfo - - Config string `json:"Config"` - HasRenewChangeOrder bool `json:"HasRenewChangeOrder"` - InstanceID string `json:"InstanceId"` - UserName string `json:"UserName"` - ArchitectureType string `json:"ArchitectureType"` - ZoneID string `json:"ZoneId"` - PrivateIP string `json:"PrivateIp"` - VSwitchID string `json:"VSwitchId"` - VpcID string `json:"VpcId"` - NetworkType string `json:"NetworkType"` - Qps int64 `json:"QPS"` - PackageType string `json:"PackageType"` - IsRDS bool `json:"IsRds"` - EngineVersion string `json:"EngineVersion"` - ConnectionDomain string `json:"ConnectionDomain"` - InstanceName string `json:"InstanceName"` - ReplacateID string `json:"ReplacateId"` - Bandwidth int64 `json:"Bandwidth"` - ChargeType TChargeType `json:"ChargeType"` - InstanceType string `json:"InstanceType"` - InstanceStatus string `json:"InstanceStatus"` - Port int `json:"Port"` - InstanceClass string `json:"InstanceClass"` - CreateTime time.Time `json:"CreateTime"` - EndTime time.Time `json:"EndTime"` - RegionID string `json:"RegionId"` - NodeType string `json:"NodeType"` - CapacityMB int `json:"Capacity"` - Connections int64 `json:"Connections"` - ResourceGroupId string `json:"ResourceGroupId"` -} - -type SElasticcacheAttribute struct { - Config string `json:"Config"` - HasRenewChangeOrder string `json:"HasRenewChangeOrder"` - InstanceID string `json:"InstanceId"` - ZoneID string `json:"ZoneId"` - ArchitectureType string `json:"ArchitectureType"` - PrivateIP string `json:"PrivateIp"` - VSwitchID string `json:"VSwitchId"` - Engine string `json:"Engine"` - VpcID string `json:"VpcId"` - NetworkType string `json:"NetworkType"` - Qps int64 `json:"QPS"` - PackageType string `json:"PackageType"` - ReplicaID string `json:"ReplicaId"` - IsRDS bool `json:"IsRds"` - MaintainStartTime string `json:"MaintainStartTime"` - VpcAuthMode string `json:"VpcAuthMode"` - ConnectionDomain string `json:"ConnectionDomain"` - EngineVersion string `json:"EngineVersion"` - InstanceName string `json:"InstanceName"` - Bandwidth int64 `json:"Bandwidth"` - ChargeType TChargeType `json:"ChargeType"` - AuditLogRetention string `json:"AuditLogRetention"` - MaintainEndTime string `json:"MaintainEndTime"` - ReplicationMode string `json:"ReplicationMode"` - InstanceType string `json:"InstanceType"` - InstanceStatus string `json:"InstanceStatus"` - Port int64 `json:"Port"` - InstanceClass string `json:"InstanceClass"` - CreateTime time.Time `json:"CreateTime"` - NodeType string `json:"NodeType"` - RegionID string `json:"RegionId"` - AvailabilityValue string `json:"AvailabilityValue"` - CapacityMB int `json:"Capacity"` - Connections int64 `json:"Connections"` - SecurityIPList string `json:"SecurityIPList"` -} - -type SNetInfo struct { - ConnectionString string `json:"ConnectionString"` - Port string `json:"Port"` - DBInstanceNetType string `json:"DBInstanceNetType"` - VPCID string `json:"VPCId"` - VPCInstanceID string `json:"VPCInstanceId"` - IPAddress string `json:"IPAddress"` - IPType string `json:"IPType"` - Upgradeable string `json:"Upgradeable"` - ExpiredTime *string `json:"ExpiredTime,omitempty"` -} - -func (self *SElasticcache) GetId() string { - return self.InstanceID -} - -func (self *SElasticcache) GetName() string { - if len(self.InstanceName) > 0 { - return self.InstanceName - } - - return self.InstanceID -} - -func (self *SElasticcache) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcache) GetStatus() string { - switch self.InstanceStatus { - case "Normal": - return api.ELASTIC_CACHE_STATUS_RUNNING - case "Creating": - return api.ELASTIC_CACHE_STATUS_DEPLOYING - case "Changing": - return api.ELASTIC_CACHE_STATUS_CHANGING - case "Inactive": - return api.ELASTIC_CACHE_STATUS_INACTIVE - case "Flushing": - return api.ELASTIC_CACHE_STATUS_FLUSHING - case "Released": - return api.ELASTIC_CACHE_STATUS_RELEASED - case "Transforming": - return api.ELASTIC_CACHE_STATUS_TRANSFORMING - case "Unavailable": - return api.ELASTIC_CACHE_STATUS_UNAVAILABLE - case "Error": - return api.ELASTIC_CACHE_STATUS_ERROR - case "Migrating": - return api.ELASTIC_CACHE_STATUS_MIGRATING - case "BackupRecovering": - return api.ELASTIC_CACHE_STATUS_BACKUPRECOVERING - case "MinorVersionUpgrading": - return api.ELASTIC_CACHE_STATUS_MINORVERSIONUPGRADING - case "NetworkModifying": - return api.ELASTIC_CACHE_STATUS_NETWORKMODIFYING - case "SSLModifying": - return api.ELASTIC_CACHE_STATUS_SSLMODIFYING - case "MajorVersionUpgrading": - return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING - default: - return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING - } -} - -func (self *SElasticcache) Refresh() error { - cache, err := self.region.GetElasticCacheById(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, cache) - if err != nil { - return err - } - - return nil -} - -func (self *SElasticcache) GetBillingType() string { - return convertChargeType(self.ChargeType) -} - -func (self *SElasticcache) GetCreatedAt() time.Time { - return self.CreateTime -} - -func (self *SElasticcache) GetExpiredAt() time.Time { - return convertExpiredAt(self.EndTime) -} - -func (self *SElasticcache) GetInstanceType() string { - return self.InstanceClass -} - -func (self *SElasticcache) GetCapacityMB() int { - return self.CapacityMB -} - -func (self *SElasticcache) GetArchType() string { - switch self.ArchitectureType { - case "rwsplit": - return api.ELASTIC_CACHE_ARCH_TYPE_RWSPLIT - case "cluster": - return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER - case "standard": - if self.NodeType == "single" { - return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE - } else if self.NodeType == "double" { - return api.ELASTIC_CACHE_ARCH_TYPE_MASTER - } - } - - return "" -} - -func (self *SElasticcache) GetNodeType() string { - return self.NodeType -} - -func (self *SElasticcache) GetEngine() string { - return self.InstanceType -} - -func (self *SElasticcache) GetEngineVersion() string { - return self.EngineVersion -} - -func (self *SElasticcache) GetVpcId() string { - return self.VpcID -} - -func (self *SElasticcache) GetZoneId() string { - zoneId := transZoneIdToEcsZoneId(self.region, "redis", self.ZoneID) - zone, err := self.region.getZoneById(fetchMasterZoneId(zoneId)) - if err != nil { - log.Errorf("failed to find zone for elasticcache %s error: %v", self.GetId(), err) - return "" - } - - return zone.GetGlobalId() -} - -func (self *SElasticcache) GetNetworkType() string { - switch self.NetworkType { - case "VPC": - return api.LB_NETWORK_TYPE_VPC - case "CLASSIC": - return api.LB_NETWORK_TYPE_CLASSIC - default: - return api.LB_NETWORK_TYPE_VPC - } -} - -func (self *SElasticcache) GetNetworkId() string { - return self.VSwitchID -} - -func (self *SElasticcache) GetPrivateDNS() string { - return self.ConnectionDomain -} - -func (self *SElasticcache) GetPrivateIpAddr() string { - return self.PrivateIP -} - -func (self *SElasticcache) GetPrivateConnectPort() int { - return self.Port -} - -func (self *SElasticcache) GetPublicDNS() string { - pub, err := self.GetPublicNetInfo() - if err != nil { - log.Errorf("SElasticcache.GetPublicDNS %s", err) - return "" - } - - if pub != nil { - return pub.ConnectionString - } - - return "" -} - -func (self *SElasticcache) GetPublicIpAddr() string { - pub, err := self.GetPublicNetInfo() - if err != nil { - log.Errorf("SElasticcache.GetPublicIpAddr %s", err) - } - - if pub != nil { - return pub.IPAddress - } - - return "" -} - -func (self *SElasticcache) GetPublicConnectPort() int { - pub, err := self.GetPublicNetInfo() - if err != nil { - log.Errorf("SElasticcache.GetPublicConnectPort %s", err) - } - - if pub != nil { - port, _ := strconv.Atoi(pub.Port) - return port - } - - return 0 -} - -func (self *SElasticcache) GetMaintainStartTime() string { - attr, err := self.GetAttribute() - if err != nil { - log.Errorf("SElasticcache.GetMaintainStartTime %s", err) - } - - if attr != nil { - return attr.MaintainStartTime - } - - return "" -} - -func (self *SElasticcache) GetBandwidth() int { - return int(self.Bandwidth) -} - -func (self *SElasticcache) GetConnections() int { - attr, err := self.GetAttribute() - if err != nil { - log.Errorf("SElasticcache.GetMaintainEndTime %s", err) - } - - if attr != nil { - return int(attr.Connections) - } - return 0 -} - -func (self *SElasticcache) GetMaintainEndTime() string { - attr, err := self.GetAttribute() - if err != nil { - log.Errorf("SElasticcache.GetMaintainEndTime %s", err) - } - - if attr != nil { - return attr.MaintainEndTime - } - - return "" -} - -func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { - accounts, err := self.region.GetElasticCacheAccounts(self.GetId()) - if err != nil { - return nil, err - } - - iaccounts := make([]cloudprovider.ICloudElasticcacheAccount, len(accounts)) - for i := range accounts { - accounts[i].cacheDB = self - iaccounts[i] = &accounts[i] - } - - return iaccounts, nil -} - -func (self *SElasticcache) GetICloudElasticcacheAccountByName(accountName string) (cloudprovider.ICloudElasticcacheAccount, error) { - account, err := self.region.GetElasticCacheAccountByName(self.GetId(), accountName) - if err != nil { - return nil, err - } - - account.cacheDB = self - return account, nil -} - -func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { - acls, err := self.region.GetElasticCacheAcls(self.GetId()) - if err != nil { - return nil, err - } - - iacls := make([]cloudprovider.ICloudElasticcacheAcl, len(acls)) - for i := range acls { - acls[i].cacheDB = self - iacls[i] = &acls[i] - } - - return iacls, nil -} - -func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { - start := self.CreateTime.Format("2006-01-02T15:04Z") - end := time.Now().Format("2006-01-02T15:04Z") - backups, err := self.region.GetElasticCacheBackups(self.GetId(), start, end) - if err != nil { - return nil, err - } - - ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) - for i := range backups { - backups[i].cacheDB = self - ibackups[i] = &backups[i] - } - - return ibackups, nil -} - -func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { - parameters, err := self.region.GetElasticCacheParameters(self.GetId()) - if err != nil { - return nil, err - } - - iparameters := make([]cloudprovider.ICloudElasticcacheParameter, len(parameters)) - for i := range parameters { - parameters[i].cacheDB = self - iparameters[i] = ¶meters[i] - } - - return iparameters, nil -} - -func (self *SElasticcache) GetAttribute() (*SElasticcacheAttribute, error) { - if self.attribute != nil { - return self.attribute, nil - } - - params := make(map[string]string) - params["RegionId"] = self.region.RegionId - params["InstanceId"] = self.GetId() - - rets := []SElasticcacheAttribute{} - err := DoListAll(self.region.kvsRequest, "DescribeInstanceAttribute", params, []string{"Instances", "DBInstanceAttribute"}, &rets) - if err != nil { - return nil, errors.Wrap(err, "elasticcache.GetAttribute") - } - - count := len(rets) - if count >= 1 { - self.attribute = &rets[0] - return self.attribute, nil - } else { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "elasticcache.GetAttribute %s", self.GetId()) - } -} - -func (self *SElasticcache) GetNetInfo() ([]SNetInfo, error) { - params := make(map[string]string) - params["RegionId"] = self.region.RegionId - params["InstanceId"] = self.GetId() - - rets := []SNetInfo{} - err := DoListAll(self.region.kvsRequest, "DescribeDBInstanceNetInfo", params, []string{"NetInfoItems", "InstanceNetInfo"}, &rets) - if err != nil { - return nil, errors.Wrap(err, "elasticcache.GetNetInfo") - } - - self.netinfo = rets - return self.netinfo, nil -} - -// https://help.aliyun.com/document_detail/66742.html?spm=a2c4g.11186623.6.731.54c123d2P02qhk -func (self *SElasticcache) GetPublicNetInfo() (*SNetInfo, error) { - nets, err := self.GetNetInfo() - if err != nil { - return nil, err - } - - for i := range nets { - if nets[i].IPType == "Public" { - return &nets[i], nil - } - } - - return nil, nil -} - -func (self *SRegion) GetElasticCaches(instanceIds []string) ([]SElasticcache, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - if instanceIds != nil && len(instanceIds) > 0 { - params["InstanceIds"] = strings.Join(instanceIds, ",") - } - - ret := []SElasticcache{} - err := DoListAll(self.kvsRequest, "DescribeInstances", params, []string{"Instances", "KVStoreInstance"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCaches") - } - - for i := range ret { - ret[i].region = self - } - - return ret, nil -} - -func (self *SRegion) GetElasticCacheById(instanceId string) (*SElasticcache, error) { - caches, err := self.GetElasticCaches([]string{instanceId}) - if err != nil { - return nil, errors.Wrapf(err, "region.GetElasticCacheById %s", instanceId) - } - - if len(caches) == 1 { - return &caches[0], nil - } else if len(caches) == 0 { - return nil, cloudprovider.ErrNotFound - } else { - return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "region.GetElasticCacheById %s.expect 1 found %d ", instanceId, len(caches)) - } -} - -func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { - ec, err := self.GetElasticCacheById(id) - if err != nil { - return nil, err - } - - return ec, nil -} - -// https://help.aliyun.com/document_detail/95802.html?spm=a2c4g.11186623.6.746.143e782f3Pfkfg -func (self *SRegion) GetElasticCacheAccounts(instanceId string) ([]SElasticcacheAccount, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - - ret := []SElasticcacheAccount{} - err := DoListAll(self.kvsRequest, "DescribeAccounts", params, []string{"Accounts", "Account"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCacheAccounts") - } - - return ret, nil -} - -func (self *SRegion) GetElasticCacheAccountByName(instanceId string, accountName string) (*SElasticcacheAccount, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - params["AccountName"] = accountName - - ret := []SElasticcacheAccount{} - err := DoListAll(self.kvsRequest, "DescribeAccounts", params, []string{"Accounts", "Account"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCacheAccounts") - } - - if len(ret) == 1 { - return &ret[0], nil - } else if len(ret) == 0 { - return nil, cloudprovider.ErrNotFound - } else { - return nil, errors.Wrap(fmt.Errorf("%d account with name %s found", len(ret), accountName), "region.GetElasticCacheAccountByName") - } -} - -// https://help.aliyun.com/document_detail/63889.html?spm=a2c4g.11186623.6.764.3cb43852R7lnoS -func (self *SRegion) GetElasticCacheAcls(instanceId string) ([]SElasticcacheAcl, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - - ret := []SElasticcacheAcl{} - err := DoListAll(self.kvsRequest, "DescribeSecurityIps", params, []string{"SecurityIpGroups", "SecurityIpGroup"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCacheAcls") - } - - return ret, nil -} - -// https://help.aliyun.com/document_detail/61081.html?spm=a2c4g.11186623.6.754.10613852qAbEQV -func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - params["StartTime"] = startTime - params["EndTime"] = endTime - - ret := []SElasticcacheBackup{} - err := DoListAll(self.kvsRequest, "DescribeBackups", params, []string{"Backups", "Backup"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCacheBackups") - } - - return ret, nil -} - -// https://help.aliyun.com/document_detail/93078.html?spm=a2c4g.11186623.6.769.58011975YYL5Gl -func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["DBInstanceId"] = instanceId - - ret := []SElasticcacheParameter{} - err := DoListAll(self.kvsRequest, "DescribeParameters", params, []string{"RunningParameters", "Parameter"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCacheParameters") - } - - return ret, nil -} - -// https://help.aliyun.com/document_detail/60873.html?spm=a2c4g.11174283.6.715.7412dce0qSYemb -func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceClass"] = ec.InstanceType - params["InstanceName"] = ec.InstanceName - params["InstanceType"] = ec.Engine - params["EngineVersion"] = ec.EngineVersion - - if len(ec.Password) > 0 { - params["UserName"] = ec.UserName - params["Password"] = ec.Password - } - - if len(ec.ZoneIds) > 0 { - params["ZoneId"] = transZoneIdFromEcsZoneId(self, "redis", ec.ZoneIds[0]) - } - - if len(ec.PrivateIpAddress) > 0 { - params["PrivateIpAddress"] = ec.PrivateIpAddress - } - - if len(ec.NodeType) > 0 { - switch ec.NodeType { - case "single": - params["NodeType"] = "STAND_ALONE" - case "double": - params["NodeType"] = "MASTER_SLAVE" - } - } - - if len(ec.ProjectId) > 0 { - params["ResourceGroupId"] = ec.ProjectId - } - - params["NetworkType"] = ec.NetworkType - params["VpcId"] = ec.VpcId - params["VSwitchId"] = ec.NetworkId - params["ChargeType"] = "PostPaid" - if ec.BillingCycle != nil { - params["ChargeType"] = "PrePaid" - if ec.BillingCycle.GetMonths() >= 1 && ec.BillingCycle.GetMonths() <= 9 { - params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths()) - } else if ec.BillingCycle.GetMonths() == 12 || ec.BillingCycle.GetMonths() == 24 || ec.BillingCycle.GetMonths() == 36 { - params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths()) - } else { - return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") - } - } - - ret := &SElasticcache{region: self} - err := DoAction(self.kvsRequest, "CreateInstance", params, []string{}, ret) - if err != nil { - return nil, errors.Wrap(err, "region.CreateIElasticcaches") - } - self.SetResourceTags(ALIYUN_SERVICE_KVS, "INSTANCE", ret.InstanceID, ec.Tags, true) - return ret, nil -} - -// https://help.aliyun.com/document_detail/116215.html?spm=a2c4g.11174283.6.736.6b9ddce0c5nsw6 -func (self *SElasticcache) Restart() error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["EffectiveTime"] = "0" // 立即重启 - - err := DoAction(self.region.kvsRequest, "RestartInstance", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.Restart") - } - - return nil -} - -// https://help.aliyun.com/document_detail/60898.html?spm=a2c4g.11186623.6.713.56ec1603KS0xA0 -func (self *SElasticcache) Delete() error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - - err := DoAction(self.region.kvsRequest, "DeleteInstance", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.Delete") - } - - return nil -} - -// https://help.aliyun.com/document_detail/60903.html?spm=a2c4g.11186623.6.711.3f062c92aRJNfw -func (self *SElasticcache) ChangeInstanceSpec(spec string) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["InstanceClass"] = strings.Split(spec, ":")[0] - params["AutoPay"] = "true" // 自动付款 - - err := DoAction(self.region.kvsRequest, "ModifyInstanceSpec", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.ChangeInstanceSpec") - } - - return nil -} - -// https://help.aliyun.com/document_detail/61000.html?spm=a2c4g.11186623.6.730.57d66cb0QlQS86 -func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["MaintainStartTime"] = maintainStartTime - params["MaintainEndTime"] = maintainEndTime - - err := DoAction(self.region.kvsRequest, "ModifyInstanceMaintainTime", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.SetMaintainTime") - } - - return nil -} - -// https://help.aliyun.com/document_detail/125795.html?spm=a2c4g.11186623.6.719.51542b3593cDKO -func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { - if port < 1024 { - port = 6379 - } - - suffix, _ := goutils.RandomAlphabetic(4) - conn := self.GetId() + strings.ToLower(suffix) - - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["Port"] = strconv.Itoa(port) - params["ConnectionStringPrefix"] = conn - - err := DoAction(self.region.kvsRequest, "AllocateInstancePublicConnection", params, nil, nil) - if err != nil { - return "", errors.Wrap(err, "elasticcache.AllocatePublicConnection") - } - - return conn, nil -} - -// https://help.aliyun.com/document_detail/125796.html?spm=a2c4g.11186623.6.720.702a3b23Qayopy -func (self *SElasticcache) ReleasePublicConnection() error { - publicConn := self.GetPublicDNS() - if len(publicConn) == 0 { - log.Debugf("elasticcache.ReleasePublicConnection public connect is empty") - return nil - } - - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["CurrentConnectionString"] = publicConn - - err := DoAction(self.region.kvsRequest, "ReleaseInstancePublicConnection", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.ReleasePublicConnection") - } - - return nil -} - -// https://help.aliyun.com/document_detail/93603.html?spm=a2c4g.11186623.6.732.10666cf9UVgNPb 修改链接地址 - -// https://help.aliyun.com/document_detail/95973.html?spm=a2c4g.11186623.6.742.4698126aH0s4Q5 -func (self *SElasticcache) CreateAccount(input cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["AccountName"] = input.AccountName - params["AccountPassword"] = input.AccountPassword - if len(input.AccountPrivilege) > 0 { - params["AccountPrivilege"] = input.AccountPrivilege - } - - if len(input.Description) > 0 { - params["AccountDescription"] = input.Description - } - - err := DoAction(self.region.kvsRequest, "CreateAccount", params, nil, nil) - if err != nil { - return nil, errors.Wrap(err, "elasticcache.CreateAccount") - } - - return self.GetICloudElasticcacheAccountByName(input.AccountName) -} - -func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { - acl := &SElasticcacheAcl{} - acl.cacheDB = self - acl.SecurityIPGroupName = aclName - acl.SecurityIPList = securityIps - return acl, self.region.createAcl(self.GetId(), aclName, securityIps) -} - -// https://help.aliyun.com/document_detail/61113.html?spm=a2c4g.11186623.6.770.16a61e7admr0xy -func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["Config"] = config.String() - - err := DoAction(self.region.kvsRequest, "ModifyInstanceConfig", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") - } - - return nil -} - -// https://help.aliyun.com/document_detail/61075.html?spm=a2c4g.11186623.6.749.4cba126a2U9xNa -func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - - // 目前没有查询备份ID的接口,因此,备份ID没什么用 - err := DoAction(self.region.kvsRequest, "CreateBackup", params, []string{"BackupJobID"}, nil) - if err != nil { - return nil, errors.Wrap(err, "elasticcache.CreateBackup") - } - - return nil, nil -} - -// https://help.aliyun.com/document_detail/61077.html?spm=a2c4g.11186623.6.750.3d7630be7ziUfg -func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["PreferredBackupPeriod"] = config.PreferredBackupPeriod - params["PreferredBackupTime"] = config.PreferredBackupTime - - err := DoAction(self.region.kvsRequest, "ModifyBackupPolicy", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.UpdateBackupPolicy") - } - - return nil -} - -// https://help.aliyun.com/document_detail/60931.html?spm=a2c4g.11186623.6.728.5c57292920UKx3 -func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - - err := DoAction(self.region.kvsRequest, "FlushInstance", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.FlushInstance") - } - - return nil -} - -// https://help.aliyun.com/document_detail/98531.html?spm=5176.11065259.1996646101.searchclickresult.4df474c38Sc2SO -func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool, password string) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - if noPwdAccess { - params["VpcAuthMode"] = "Close" - } else { - params["VpcAuthMode"] = "Open" - } - - err := DoAction(self.region.kvsRequest, "ModifyInstanceVpcAuthMode", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.UpdateAuthMode") - } - - return nil -} - -func (self *SElasticcache) GetProjectId() string { - return self.ResourceGroupId -} - -func (self *SElasticcache) GetAuthMode() string { - attribute, err := self.GetAttribute() - if err != nil { - log.Errorf("elasticcache.GetAuthMode %s", err) - } - switch attribute.VpcAuthMode { - case "Open": - return "on" - default: - return "off" - } -} - -func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { - segs := strings.Split(accountId, "/") - if len(segs) < 2 { - log.Debugf("elasticcache.GetICloudElasticcacheAccount invalid account id %s", accountId) - return nil, errors.Wrap(cloudprovider.ErrNotFound, "invalid account id") - } - - return self.GetICloudElasticcacheAccountByName(segs[1]) -} - -func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { - acls, err := self.GetICloudElasticcacheAcls() - if err != nil { - return nil, err - } - - for _, acl := range acls { - if acl.GetId() == aclId { - return acl, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { - backups, err := self.GetICloudElasticcacheBackups() - if err != nil { - return nil, err - } - - for _, backup := range backups { - if backup.GetId() == backupId { - return backup, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (instance *SElasticcache) SetTags(tags map[string]string, replace bool) error { - return instance.region.SetResourceTags(ALIYUN_SERVICE_KVS, "INSTANCE", instance.GetId(), tags, replace) -} - -func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { - return errors.Wrap(cloudprovider.ErrNotSupported, "UpdateSecurityGroups") -} - -// https://help.aliyun.com/document_detail/60903.html?spm=a2c4g.11174283.6.877.34653436jn6t4C -// https://help.aliyun.com/document_detail/95584.html?spm=a2c4g.11186623.6.907.60e3292bWsVIOE -// https://help.aliyun.com/document_detail/60909.html?spm=a2c4g.11186623.6.910.17664ce0jfir7F -func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { - month := bc.GetMonths() - if month <= 0 { - return errors.Wrap(fmt.Errorf("month should great than 0"), "GetMonths") - } - - if (month >= 1 && month <= 9) || month == 12 || month == 24 || month == 36 { - return errors.Wrap(fmt.Errorf("month %d is invalid, required: 1~9、12、24、36", month), "GetMonths") - } - - params := map[string]string{} - params["InstanceId"] = self.GetId() - params["Period"] = fmt.Sprintf("%d", month) - params["AutoPay"] = "true" - _, err := self.region.kvsRequest("RenewInstance", params) - if err != nil { - return errors.Wrap(err, "RenewInstance") - } - - return nil -} - -func (self *SElasticcache) SetAutoRenew(bc billing.SBillingCycle) error { - params := map[string]string{} - params["DBInstanceId"] = self.GetId() - params["Duration"] = "1" - params["AutoRenew"] = fmt.Sprintf("%v", bc.AutoRenew) - _, err := self.region.kvsRequest("ModifyInstanceAutoRenewalAttribute", params) - if err != nil { - return errors.Wrap(err, "ModifyInstanceAutoRenewalAttribute") - } - - return nil -} diff --git a/pkg/multicloud/aliyun/elasticcache_parameter.go b/pkg/multicloud/aliyun/elasticcache_parameter.go deleted file mode 100644 index 36f1ec7917..0000000000 --- a/pkg/multicloud/aliyun/elasticcache_parameter.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElasticcacheParameter struct { - multicloud.SElasticcacheParameterBase - multicloud.AliyunTags - - cacheDB *SElasticcache - - ParameterDescription string `json:"ParameterDescription"` - ParameterValue string `json:"ParameterValue"` - ForceRestart string `json:"ForceRestart"` - CheckingCode string `json:"CheckingCode"` - ModifiableStatus string `json:"ModifiableStatus"` - ParameterName string `json:"ParameterName"` -} - -func (self *SElasticcacheParameter) GetId() string { - return fmt.Sprintf("%s/%s", self.cacheDB.InstanceID, self.ParameterName) -} - -func (self *SElasticcacheParameter) GetName() string { - return self.ParameterName -} - -func (self *SElasticcacheParameter) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheParameter) GetStatus() string { - return api.ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE -} - -func (self *SElasticcacheParameter) GetParameterKey() string { - return self.ParameterName -} - -func (self *SElasticcacheParameter) GetParameterValue() string { - return self.ParameterValue -} - -func (self *SElasticcacheParameter) GetParameterValueRange() string { - return self.CheckingCode -} - -func (self *SElasticcacheParameter) GetDescription() string { - return self.ParameterDescription -} - -func (self *SElasticcacheParameter) GetModifiable() bool { - switch self.ModifiableStatus { - case "true": - return true - default: - return false - } -} - -func (self *SElasticcacheParameter) GetForceRestart() bool { - switch self.ForceRestart { - case "true": - return true - default: - return false - } -} diff --git a/pkg/multicloud/aliyun/events.go b/pkg/multicloud/aliyun/events.go deleted file mode 100644 index a65c8de2d6..0000000000 --- a/pkg/multicloud/aliyun/events.go +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "strings" - "time" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - EVENT_REGION_HANGZHOU = "cn-hangzhou" -) - -type SAttributes struct { - CreationDate time.Time - MfaAuthenticated bool -} - -type SSessionContext struct { - Attributes SAttributes -} - -type SUserIdentity struct { - AccessKeyId string - AccountId string - PrincipalId string - SessionContext SSessionContext - Type string - UserName string -} - -type SEvent struct { - region *SRegion - AdditionalEventData map[string]string - ApiVersion string - EventId string - EventName string - EventSource string - EventTime time.Time - EventType string - EventVersion string - RequestId string - RequestParameters map[string]string - ServiceName string - SourceIpAddress string - UserAgent string - UserIdentity SUserIdentity - ResponseElements map[string]string - IsGlobal bool -} - -func (event *SEvent) GetCreatedAt() time.Time { - return event.EventTime -} - -func (event *SEvent) GetName() string { - return event.EventName -} - -func (event *SEvent) GetAction() string { - return event.ServiceName -} - -func (event *SEvent) GetResourceType() string { - return "" -} - -func (event *SEvent) GetRequestId() string { - return event.RequestId -} - -func (event *SEvent) GetRequest() jsonutils.JSONObject { - return jsonutils.Marshal(event) -} - -func (event *SEvent) GetAccount() string { - if account, ok := event.AdditionalEventData["loginAccount"]; ok { - return account - } - if len(event.UserIdentity.AccessKeyId) > 0 { - return event.UserIdentity.AccessKeyId - } - return event.UserIdentity.UserName -} - -func (event *SEvent) GetService() string { - return event.ServiceName -} - -func (event *SEvent) IsSuccess() bool { - return true -} - -func (region *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { - var ( - events []SEvent - err error - token string - _events []SEvent - iEvents []cloudprovider.ICloudEvent - eventRW string - ) - - eventRW = "Write" - if withReadEvent { - eventRW = "" - } - - for { - _events, token, err = region.GetEvents(start, end, token, eventRW, "") - if err != nil { - return nil, errors.Wrap(err, "region.GetEvents") - } - events = append(events, _events...) - if len(token) == 0 || len(_events) == 0 { - break - } - } - - for i := range events { - if events[i].IsGlobal && region.RegionId != ALIYUN_DEFAULT_REGION { - continue - } - if !withReadEvent && strings.HasPrefix(events[i].EventName, "Query") { // QueryInstanceBill QueryBill - continue - } - iEvents = append(iEvents, &events[i]) - } - return iEvents, nil -} - -func (region *SRegion) GetEvents(start time.Time, end time.Time, token string, eventRW string, requestId string) ([]SEvent, string, error) { - params := map[string]string{ - "RegionId": region.RegionId, - } - if !start.IsZero() { - params["StartTime"] = start.Format("2006-01-02T15:04:05Z") - } - if !end.IsZero() { - params["EndTime"] = end.Format("2006-01-02T15:04:05Z") - } - if utils.IsInStringArray(eventRW, []string{"Read", "Write"}) { - params["LookupAttribute.1.Key"] = "EventRW" - params["LookupAttribute.1.Value"] = eventRW - } - if len(token) > 0 { - params["NextToken"] = token - } - if len(requestId) > 0 { - params["Request"] = requestId - } - resp, err := region.trialRequest("LookupEvents", params) - if err != nil { - if strings.Contains(err.Error(), "no such host") { // cn-wulanchabu not support - return []SEvent{}, "", nil - } - return nil, "", err - } - - events := []SEvent{} - err = resp.Unmarshal(&events, "Events") - if err != nil { - return nil, "", err - } - nextToken, _ := resp.GetString("NextToken") - return events, nextToken, nil -} diff --git a/pkg/multicloud/aliyun/filesystem.go b/pkg/multicloud/aliyun/filesystem.go deleted file mode 100644 index aaf73370bf..0000000000 --- a/pkg/multicloud/aliyun/filesystem.go +++ /dev/null @@ -1,362 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SupportedFeatures struct { - SupportedFeature []string -} - -type MountTargets struct { - MountTarget []SMountTarget -} - -type Package struct { -} - -type Packages struct { - Package []Package -} - -type SFileSystem struct { - multicloud.SNasBase - multicloud.AliyunTags - region *SRegion - - Status string - Description string - StorageType string - MountTargetCountLimit int - Ldap string - ZoneId string - // 2021-03-22T10:08:15CST - CreateTime string - MeteredIASize int - SupportedFeatures SupportedFeatures - MountTargets MountTargets - AutoSnapshotPolicyId string - MeteredSize int64 - EncryptType int - Capacity int64 - ProtocolType string - ChargeType string - Packages Packages - ExpiredTime string - FileSystemType string - FileSystemId string - RegionId string -} - -func (self *SFileSystem) GetId() string { - return self.FileSystemId -} - -func (self *SFileSystem) GetGlobalId() string { - return self.FileSystemId -} - -func (self *SFileSystem) GetName() string { - if len(self.Description) > 0 { - return self.Description - } - return self.FileSystemId -} - -func (self *SFileSystem) GetFileSystemType() string { - return self.FileSystemType -} - -func (self *SFileSystem) GetMountTargetCountLimit() int { - return self.MountTargetCountLimit -} - -func (self *SFileSystem) GetStatus() string { - switch self.Status { - case "", "Running": - return api.NAS_STATUS_AVAILABLE - case "Extending": - return api.NAS_STATUS_EXTENDING - case "Stopping", "Stopped": - return api.NAS_STATUS_UNAVAILABLE - case "Pending": - return api.NAS_STATUS_CREATING - default: - return api.NAS_STATUS_UNKNOWN - } -} - -func (self *SFileSystem) GetBillintType() string { - if self.ChargeType == "PayAsYouGo" { - return billing_api.BILLING_TYPE_POSTPAID - } - return billing_api.BILLING_TYPE_PREPAID -} - -func (self *SFileSystem) GetStorageType() string { - return strings.ToLower(self.StorageType) -} - -func (self *SFileSystem) GetProtocol() string { - return self.ProtocolType -} - -func (self *SFileSystem) GetCapacityGb() int64 { - return self.Capacity -} - -func (self *SFileSystem) GetUsedCapacityGb() int64 { - return self.MeteredSize -} - -func (self *SFileSystem) GetZoneId() string { - return self.ZoneId -} - -func (self *SFileSystem) Delete() error { - return self.region.DeleteFileSystem(self.FileSystemId) -} - -func (self *SFileSystem) GetCreatedAt() time.Time { - ret, _ := time.Parse("2006-01-02T15:04:05CST", self.CreateTime) - if !ret.IsZero() { - ret = ret.Add(time.Hour * 8) - } - return ret -} - -func (self *SFileSystem) GetExpiredAt() time.Time { - ret, _ := time.Parse("2006-01-02T15:04:05CST", self.ExpiredTime) - if !ret.IsZero() { - ret = ret.Add(time.Hour * 8) - } - return ret -} - -func (self *SFileSystem) Refresh() error { - fs, err := self.region.GetFileSystem(self.FileSystemId) - if err != nil { - return errors.Wrapf(err, "GetFileSystem(%s)", self.FileSystemId) - } - return jsonutils.Update(self, fs) -} - -func (self *SRegion) GetFileSystems(id string, pageSize, pageNum int) ([]SFileSystem, int, error) { - if pageSize < 1 || pageSize > 100 { - pageSize = 50 - } - if pageNum < 1 { - pageNum = 1 - } - params := map[string]string{ - "RegionId": self.RegionId, - "PageSize": fmt.Sprintf("%d", pageSize), - "PageNumber": fmt.Sprintf("%d", pageNum), - } - if len(id) > 0 { - params["FileSystemId"] = id - } - resp, err := self.nasRequest("DescribeFileSystems", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeFileSystems") - } - ret := struct { - TotalCount int - FileSystems struct { - FileSystem []SFileSystem - } - }{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - return ret.FileSystems.FileSystem, ret.TotalCount, nil -} - -func (self *SRegion) GetICloudFileSystems() ([]cloudprovider.ICloudFileSystem, error) { - nas := []SFileSystem{} - num := 1 - for { - part, total, err := self.GetFileSystems("", 100, num) - if err != nil { - return nil, errors.Wrapf(err, "GetFileSystems") - } - nas = append(nas, part...) - if total <= len(nas) { - break - } - num++ - } - - ret := []cloudprovider.ICloudFileSystem{} - for i := range nas { - nas[i].region = self - ret = append(ret, &nas[i]) - } - return ret, nil -} - -func (self *SRegion) GetFileSystem(id string) (*SFileSystem, error) { - if len(id) == 0 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty id") - } - nas, total, err := self.GetFileSystems(id, 1, 1) - if err != nil { - return nil, errors.Wrapf(err, "GetFileSystems") - } - if total == 1 { - nas[0].region = self - return &nas[0], nil - } - if total == 0 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) - } - return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, id) -} - -func (self *SRegion) GetICloudFileSystemById(id string) (cloudprovider.ICloudFileSystem, error) { - fs, err := self.GetFileSystem(id) - if err != nil { - return nil, errors.Wrapf(err, "self.GetFileSystem") - } - return fs, nil -} - -func (self *SRegion) CreateMountTarget(opts *cloudprovider.SMountTargetCreateOptions) (*SMountTarget, error) { - params := map[string]string{ - "RegionId": self.RegionId, - "FileSystemId": opts.FileSystemId, - "AccessGroupName": strings.TrimPrefix(strings.TrimPrefix(opts.AccessGroupId, "extreme/"), "standard/"), - "NetworkType": utils.Capitalize(opts.NetworkType), - "VpcId": opts.VpcId, - "VSwitchId": opts.NetworkId, - } - resp, err := self.nasRequest("CreateMountTarget", params) - if err != nil { - return nil, errors.Wrapf(err, "CreateMountTarget") - } - ret := struct { - MountTargetDomain string - }{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - mts, _, err := self.GetMountTargets(opts.FileSystemId, ret.MountTargetDomain, 10, 1) - if err != nil { - return nil, errors.Wrapf(err, "self.GetMountTargets") - } - for i := range mts { - if mts[i].MountTargetDomain == ret.MountTargetDomain { - return &mts[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "afeter create with mount domain %s", ret.MountTargetDomain) -} - -func (self *SFileSystem) CreateMountTarget(opts *cloudprovider.SMountTargetCreateOptions) (cloudprovider.ICloudMountTarget, error) { - mt, err := self.region.CreateMountTarget(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateMountTarget") - } - mt.fs = self - return mt, nil -} - -func (self *SRegion) DeleteFileSystem(id string) error { - params := map[string]string{ - "RegionId": self.RegionId, - "FileSystemId": id, - } - _, err := self.nasRequest("DeleteFileSystem", params) - return errors.Wrapf(err, "DeleteFileSystem") -} - -func (self *SRegion) CreateICloudFileSystem(opts *cloudprovider.FileSystemCraeteOptions) (cloudprovider.ICloudFileSystem, error) { - fs, err := self.CreateFileSystem(opts) - if err != nil { - return nil, errors.Wrapf(err, "self.CreateFileSystem") - } - return fs, nil -} - -func (self *SRegion) CreateFileSystem(opts *cloudprovider.FileSystemCraeteOptions) (*SFileSystem, error) { - params := map[string]string{ - "RegionId": self.RegionId, - "ProtocolType": opts.Protocol, - "ZoneId": opts.ZoneId, - "EncryptType": "0", - "FileSystemType": opts.FileSystemType, - "StorageType": opts.StorageType, - "ClientToken": utils.GenRequestId(20), - "Description": opts.Name, - } - - if self.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV { - if opts.FileSystemType == "standard" { - opts.ZoneId = strings.Replace(opts.ZoneId, "cn-shanghai-finance-1", "jr-cn-shanghai-", 1) - opts.ZoneId = strings.Replace(opts.ZoneId, "cn-shenzhen-finance-1", "jr-cn-shenzhen-", 1) - params["ZoneId"] = opts.ZoneId - } - } - - switch opts.FileSystemType { - case "standard": - params["StorageType"] = utils.Capitalize(opts.StorageType) - case "cpfs": - params["ProtocolType"] = "cpfs" - switch opts.StorageType { - case "advance_100": - params["Bandwidth"] = "100" - case "advance_200": - params["Bandwidth"] = "200" - } - case "extreme": - params["Capacity"] = fmt.Sprintf("%d", opts.Capacity) - } - if len(opts.VpcId) > 0 { - params["VpcId"] = opts.VpcId - } - if len(opts.NetworkId) > 0 { - params["VSwitchId"] = opts.NetworkId - } - if opts.BillingCycle != nil { - params["ChargeType"] = "Subscription" - params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetMonths()) - } - resp, err := self.nasRequest("CreateFileSystem", params) - if err != nil { - return nil, errors.Wrapf(err, "CreateFileSystem") - } - fsId, _ := resp.GetString("FileSystemId") - return self.GetFileSystem(fsId) -} - -func (self *SFileSystem) SetTags(tags map[string]string, replace bool) error { - return self.region.SetResourceTags(ALIYUN_SERVICE_NAS, "filesystem", self.FileSystemId, tags, replace) -} diff --git a/pkg/multicloud/aliyun/host.go b/pkg/multicloud/aliyun/host.go deleted file mode 100644 index e743f920ad..0000000000 --- a/pkg/multicloud/aliyun/host.go +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone -} - -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) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms := make([]SInstance, 0) - for { - parts, total, err := self.zone.region.GetInstances(self.zone.ZoneId, nil, len(vms), 50) - if err != nil { - return nil, err - } - vms = append(vms, parts...) - if len(vms) >= total { - break - } - } - 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) VMGlobalId2Id(gid string) string { - return gid -} - -func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) { - id := self.VMGlobalId2Id(gid) - parts, _, err := self.zone.region.GetInstances(self.zone.ZoneId, []string{id}, 0, 1) - if err != nil { - return nil, err - } - if len(parts) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(parts) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - parts[0].host = self - return &parts[0], nil -} - -func (self *SHost) GetId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) GetName() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) -} - -func (self *SHost) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) IsEmulated() bool { - return true -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) Refresh() error { - return nil -} - -func (self *SHost) GetHostStatus() string { - return api.HOST_ONLINE -} - -func (self *SHost) GetEnabled() bool { - return true -} - -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_ALIYUN), "manufacture") - return info -} - -func (self *SHost) GetSN() string { - return "" -} - -func (self *SHost) GetCpuCount() int { - 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 api.DISK_TYPE_HYBRID -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_ALIYUN -} - -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(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - vmId, err := self._createVM(desc.Name, desc.Hostname, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, - desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, - desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, desc.UserData, desc.BillingCycle, - desc.ProjectId, desc.OsType, desc.Tags, desc.SPublicIpInfo) - if err != nil { - return nil, err - } - vm, err := self.GetInstanceById(vmId) - if err != nil { - return nil, errors.Wrapf(err, "GetInstanceById") - } - return vm, nil -} - -func (self *SHost) _createVM(name, hostname string, imgId string, - sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, - vswitchId string, ipAddr string, desc string, passwd string, - dataDisks []cloudprovider.SDiskInfo, publicKey string, secgroupId string, - userData string, bc *billing.SBillingCycle, projectId, osType string, - tags map[string]string, publicIp cloudprovider.SPublicIpInfo, -) (string, error) { - net := self.zone.getNetworkById(vswitchId) - if net == nil { - return "", fmt.Errorf("invalid switch ID %s", vswitchId) - } - if net.wire == nil { - log.Errorf("vsiwtch's wire is empty") - return "", fmt.Errorf("vsiwtch's wire is empty") - } - if net.wire.vpc == nil { - log.Errorf("vsiwtch's wire' vpc is empty") - return "", fmt.Errorf("vsiwtch's wire's vpc is empty") - } - - var err error - keypair := "" - if len(publicKey) > 0 { - keypair, err = self.zone.region.syncKeypair(publicKey) - if err != nil { - return "", err - } - } - - img, err := self.zone.region.GetImage(imgId) - if err != nil { - log.Errorf("GetImage 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(dataDisks)+1) - disks[0].Size = img.Size - if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.Size { - disks[0].Size = sysDisk.SizeGB - } - storage, err := self.zone.getStorageByCategory(sysDisk.StorageType) - if err != nil { - return "", fmt.Errorf("Storage %s not avaiable: %s", sysDisk.StorageType, err) - } - disks[0].Category = storage.storageType - - for i, dataDisk := range dataDisks { - disks[i+1].Size = dataDisk.SizeGB - storage, err := self.zone.getStorageByCategory(dataDisk.StorageType) - if err != nil { - return "", fmt.Errorf("Storage %s not avaiable: %s", dataDisk.StorageType, err) - } - disks[i+1].Category = storage.storageType - } - - if len(instanceType) > 0 { - log.Debugf("Try instancetype : %s", instanceType) - vmId, err := self.zone.region.CreateInstance(name, hostname, imgId, instanceType, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId, osType, tags, publicIp) - if err != nil { - log.Errorf("Failed for %s: %s", instanceType, err) - return "", fmt.Errorf("Failed to create specification %s.%s", instanceType, err.Error()) - } - return vmId, nil - } - - 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) - } - - var vmId string - for _, instType := range instanceTypes { - instanceTypeId := instType.InstanceTypeId - log.Debugf("Try instancetype : %s", instanceTypeId) - vmId, err = self.zone.region.CreateInstance(name, hostname, imgId, instanceTypeId, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId, osType, tags, publicIp) - if err != nil { - log.Errorf("Failed for %s: %s", instanceTypeId, err) - } else { - return vmId, nil - } - } - - return "", fmt.Errorf("Failed to create, %s", err.Error()) -} - -func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (host *SHost) GetIsMaintenance() bool { - return false -} - -func (host *SHost) GetVersion() string { - return ALIYUN_API_VERSION -} diff --git a/pkg/multicloud/aliyun/image.go b/pkg/multicloud/aliyun/image.go deleted file mode 100644 index 313f8ecadc..0000000000 --- a/pkg/multicloud/aliyun/image.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/apis" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type ImageStatusType string - -const ( - ImageStatusCreating ImageStatusType = "Creating" - ImageStatusAvailable ImageStatusType = "Available" - ImageStatusUnAvailable ImageStatusType = "UnAvailable" - ImageStatusCreateFailed ImageStatusType = "CreateFailed" -) - -type ImageOwnerType string - -const ( - ImageOwnerSystem ImageOwnerType = "system" - ImageOwnerSelf ImageOwnerType = "self" - ImageOwnerOthers ImageOwnerType = "others" - ImageOwnerMarketplace ImageOwnerType = "marketplace" -) - -type ImageUsageType string - -const ( - ImageUsageInstance ImageUsageType = "instance" - ImageUsageNone ImageUsageType = "none" -) - -type SImage struct { - multicloud.SImageBase - multicloud.AliyunTags - storageCache *SStoragecache - - // normalized image info - imgInfo *imagetools.ImageInfo - - Architecture string - CreationTime time.Time - Description string - ImageId string - ImageName string - OSName string - OSType string - ImageOwnerAlias ImageOwnerType - IsSupportCloudinit bool - IsSupportIoOptimized bool - Platform string - Size int - Status ImageStatusType - Usage string -} - -func (self *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (self *SImage) GetId() string { - return self.ImageId -} - -func (self *SImage) GetName() string { - if self.ImageOwnerAlias == ImageOwnerSystem { - return self.OSName - } else { - return self.ImageName - } -} - -func (self *SImage) IsEmulated() bool { - return false -} - -func (self *SImage) Delete(ctx context.Context) error { - return self.storageCache.region.DeleteImage(self.ImageId) -} - -func (self *SImage) GetGlobalId() string { - return self.ImageId -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.storageCache -} - -func (self *SImage) GetStatus() string { - switch self.Status { - case ImageStatusCreating: - return api.CACHED_IMAGE_STATUS_SAVING - case ImageStatusAvailable: - return api.CACHED_IMAGE_STATUS_ACTIVE - case ImageStatusUnAvailable: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - case ImageStatusCreateFailed: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - default: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (self *SImage) GetImageStatus() string { - switch self.Status { - case ImageStatusCreating: - return cloudprovider.IMAGE_STATUS_QUEUED - case ImageStatusAvailable: - return cloudprovider.IMAGE_STATUS_ACTIVE - case ImageStatusUnAvailable: - return cloudprovider.IMAGE_STATUS_DELETED - case ImageStatusCreateFailed: - return cloudprovider.IMAGE_STATUS_KILLED - default: - return cloudprovider.IMAGE_STATUS_KILLED - } -} - -func (self *SImage) Refresh() error { - new, err := self.storageCache.region.GetImage(self.ImageId) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - switch self.ImageOwnerAlias { - case ImageOwnerSystem: - return cloudprovider.ImageTypeSystem - case ImageOwnerSelf: - return cloudprovider.ImageTypeCustomized - case ImageOwnerMarketplace: - return cloudprovider.ImageTypeMarket - case ImageOwnerOthers: - return cloudprovider.ImageTypeShared - default: - return cloudprovider.ImageTypeCustomized - } -} - -func (self *SImage) GetSizeByte() int64 { - return int64(self.Size) * 1024 * 1024 * 1024 -} - -func (self *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) -} - -func (self *SImage) GetOsDist() string { - return self.getNormalizedImageInfo().OsDistro -} - -func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if self.imgInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(self.OSName, self.Architecture, self.OSType, self.Platform, "") - self.imgInfo = &imgInfo - } - - return self.imgInfo -} - -func (self *SImage) GetFullOsName() string { - return self.OSName -} - -func (self *SImage) GetOsVersion() string { - return self.getNormalizedImageInfo().OsVersion -} - -func (self *SImage) GetOsLang() string { - return self.getNormalizedImageInfo().OsLang -} - -func (self *SImage) GetOsArch() string { - return self.getNormalizedImageInfo().OsArch -} - -func (self *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return 40 -} - -func (self *SImage) GetImageFormat() string { - return "vhd" -} - -func (self *SImage) GetCreatedAt() time.Time { - return self.CreationTime -} - -type ImageExportTask struct { - ImageId string - RegionId string - // RequestId string - TaskId string -} - -func (self *SRegion) ExportImage(imageId string, bucket *oss.Bucket) (*ImageExportTask, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["ImageId"] = imageId - params["OssBucket"] = bucket.BucketName - params["OssPrefix"] = fmt.Sprintf("%sexport", strings.Replace(imageId, "-", "", -1)) - - if body, err := self.ecsRequest("ExportImage", params); err != nil { - return nil, err - } else { - result := ImageExportTask{} - if err := body.Unmarshal(&result); err != nil { - log.Errorf("unmarshal result error %s", err) - return nil, err - } - return &result, nil - } -} - -// {"ImageId":"m-j6c1qlpa7oebbg1n2k60","RegionId":"cn-hongkong","RequestId":"F8B2F6A1-F6AA-4C92-A54C-C4A309CF811F","TaskId":"t-j6c1qlpa7oebbg1rcl9t"} - -type ImageImportTask struct { - ImageId string - RegionId string - // RequestId string - TaskId string -} - -func (self *SRegion) ImportImage(name string, osArch string, osType string, osDist string, bucket string, key string) (*ImageImportTask, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["ImageName"] = name - if osDist == "RHEL" { - osDist = "CentOS" - } - params["Platform"] = osDist // "Others Linux" - params["OSType"] = osType // "linux" - switch osArch { - case apis.OS_ARCH_I386, apis.OS_ARCH_X86_32: - params["Architecture"] = "i386" - case apis.OS_ARCH_X86, apis.OS_ARCH_X86_64: - params["Architecture"] = "x86_64" - case apis.OS_ARCH_ARM, apis.OS_ARCH_AARCH32, apis.OS_ARCH_AARCH64: - params["Architecture"] = "arm64" - default: - params["Architecture"] = osArch // "x86_64" - } - params["DiskDeviceMapping.1.OSSBucket"] = bucket - params["DiskDeviceMapping.1.OSSObject"] = key - - log.Debugf("Upload image with params %#v", params) - - body, err := self.ecsRequest("ImportImage", params) - if err != nil { - log.Errorf("ImportImage fail %s", err) - return nil, err - } - - log.Infof("%s", body) - result := ImageImportTask{} - err = body.Unmarshal(&result) - if err != nil { - log.Errorf("unmarshal result error %s", err) - return nil, err - } - - return &result, nil -} - -func (self *SRegion) GetImage(imageId string) (*SImage, error) { - images, _, err := self.GetImages("", "", []string{imageId}, "", 0, 1) - if err != nil { - return nil, err - } - if len(images) == 0 { - return nil, cloudprovider.ErrNotFound - } - return &images[0], nil -} - -func (self *SRegion) GetImageByName(name string) (*SImage, error) { - images, _, err := self.GetImages("", "", 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) GetImagesBySnapshot(snapshotId string, offset int, limit int) ([]SImage, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - params["SnapshotId"] = snapshotId - - return self.getImages(params) -} - -func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) { - image, err := self.GetImage(imageId) - if err != nil { - return "", err - } - return image.Status, nil -} - -func (self *SRegion) GetImages(status ImageStatusType, owner ImageOwnerType, imageId []string, name string, offset int, limit int) ([]SImage, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - if len(status) > 0 { - params["Status"] = string(status) - } else { - params["Status"] = "Creating,Available,UnAvailable,CreateFailed" - } - if imageId != nil && len(imageId) > 0 { - params["ImageId"] = strings.Join(imageId, ",") - } - if len(owner) > 0 { - params["ImageOwnerAlias"] = string(owner) - } - - if len(name) > 0 { - params["ImageName"] = name - } - - return self.getImages(params) -} - -func (self *SRegion) getImages(params map[string]string) ([]SImage, int, error) { - body, err := self.ecsRequest("DescribeImages", params) - if err != nil { - log.Errorf("DescribeImages fail %s", err) - return nil, 0, err - } - - images := make([]SImage, 0) - err = body.Unmarshal(&images, "Images", "Image") - if err != nil { - log.Errorf("unmarshal images fail %s", err) - return nil, 0, nil - } - total, _ := body.Int("TotalCount") - return images, int(total), nil -} - -func (self *SRegion) DeleteImage(imageId string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["ImageId"] = imageId - params["Force"] = "true" - - _, err := self.ecsRequest("DeleteImage", params) - if err != nil { - log.Errorf("DeleteImage fail %s", err) - return err - } - return nil -} diff --git a/pkg/multicloud/aliyun/instance.go b/pkg/multicloud/aliyun/instance.go deleted file mode 100644 index 642ffb459e..0000000000 --- a/pkg/multicloud/aliyun/instance.go +++ /dev/null @@ -1,1190 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - "sort" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/pkg/util/seclib" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -const ( - // Running:运行中 - //Starting:启动中 - //Stopping:停止中 - //Stopped:已停止 - - InstanceStatusStopped = "Stopped" - InstanceStatusRunning = "Running" - InstanceStatusStopping = "Stopping" - InstanceStatusStarting = "Starting" -) - -type SDedicatedHostAttribute struct { - DedicatedHostId string - DedicatedHostName string -} - -type SIpAddress struct { - IpAddress []string -} - -type SNetworkInterfaces struct { - NetworkInterface []SNetworkInterface -} - -type SOperationLocks struct { - LockReason []string -} - -type SSecurityGroupIds struct { - SecurityGroupId []string -} - -// {"NatIpAddress":"","PrivateIpAddress":{"IpAddress":["192.168.220.214"]},"VSwitchId":"vsw-2ze9cqwza4upoyujq1thd","VpcId":"vpc-2zer4jy8ix3i8f0coc5uw"} - -type SVpcAttributes struct { - NatIpAddress string - PrivateIpAddress SIpAddress - VSwitchId string - VpcId string -} - -type SInstance struct { - multicloud.SInstanceBase - multicloud.AliyunTags - - host *SHost - - osInfo *imagetools.ImageInfo - - // idisks []cloudprovider.ICloudDisk - - AutoReleaseTime string - ClusterId string - Cpu int - CreationTime time.Time - DedicatedHostAttribute SDedicatedHostAttribute - Description string - DeviceAvailable bool - EipAddress SEipAddress - ExpiredTime time.Time - GPUAmount int - GPUSpec string - HostName string - ImageId string - InnerIpAddress SIpAddress - InstanceChargeType TChargeType - InstanceId string - InstanceName string - InstanceNetworkType string - InstanceType string - InstanceTypeFamily string - InternetChargeType TInternetChargeType - InternetMaxBandwidthIn int - InternetMaxBandwidthOut int - IoOptimized bool - KeyPairName string - Memory int - NetworkInterfaces SNetworkInterfaces - OSName string - OSType string - OperationLocks SOperationLocks - PublicIpAddress SIpAddress - Recyclable bool - RegionId string - ResourceGroupId string - SaleCycle string - SecurityGroupIds SSecurityGroupIds - SerialNumber string - SpotPriceLimit string - SpotStrategy string - StartTime time.Time - Status string - StoppedMode string - VlanId string - VpcAttributes SVpcAttributes - ZoneId string - Throughput int -} - -// {"AutoReleaseTime":"","ClusterId":"","Cpu":1,"CreationTime":"2018-05-23T07:58Z","DedicatedHostAttribute":{"DedicatedHostId":"","DedicatedHostName":""},"Description":"","DeviceAvailable":true,"EipAddress":{"AllocationId":"","InternetChargeType":"","IpAddress":""},"ExpiredTime":"2018-05-30T16:00Z","GPUAmount":0,"GPUSpec":"","HostName":"iZ2ze57isp1ali72tzkjowZ","ImageId":"centos_7_04_64_20G_alibase_201701015.vhd","InnerIpAddress":{"IpAddress":[]},"InstanceChargeType":"PrePaid","InstanceId":"i-2ze57isp1ali72tzkjow","InstanceName":"gaoxianqi-test-7days","InstanceNetworkType":"vpc","InstanceType":"ecs.t5-lc2m1.nano","InstanceTypeFamily":"ecs.t5","InternetChargeType":"PayByBandwidth","InternetMaxBandwidthIn":-1,"InternetMaxBandwidthOut":0,"IoOptimized":true,"Memory":512,"NetworkInterfaces":{"NetworkInterface":[{"MacAddress":"00:16:3e:10:f0:c9","NetworkInterfaceId":"eni-2zecqsagtpztl6x5hu2r","PrimaryIpAddress":"192.168.220.214"}]},"OSName":"CentOS 7.4 64位","OSType":"linux","OperationLocks":{"LockReason":[]},"PublicIpAddress":{"IpAddress":[]},"Recyclable":false,"RegionId":"cn-beijing","ResourceGroupId":"","SaleCycle":"Week","SecurityGroupIds":{"SecurityGroupId":["sg-2zecqsagtpztl6x9zynl"]},"SerialNumber":"df05d9b4-df3d-4400-88d1-5f843f0dd088","SpotPriceLimit":0.000000,"SpotStrategy":"NoSpot","StartTime":"2018-05-23T07:58Z","Status":"Running","StoppedMode":"Not-applicable","VlanId":"","VpcAttributes":{"NatIpAddress":"","PrivateIpAddress":{"IpAddress":["192.168.220.214"]},"VSwitchId":"vsw-2ze9cqwza4upoyujq1thd","VpcId":"vpc-2zer4jy8ix3i8f0coc5uw"},"ZoneId":"cn-beijing-f"} - -func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit int) ([]SInstance, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - if len(zoneId) > 0 { - params["ZoneId"] = zoneId - } - - if ids != nil && len(ids) > 0 { - params["InstanceIds"] = jsonutils.Marshal(ids).String() - } - - body, err := self.ecsRequest("DescribeInstances", params) - if err != nil { - log.Errorf("GetInstances fail %s", err) - return nil, 0, err - } - - instances := make([]SInstance, 0) - err = body.Unmarshal(&instances, "Instances", "Instance") - if err != nil { - log.Errorf("Unmarshal security group details fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return instances, int(total), nil -} - -type SAliyunTag struct { - ResourceId string - ResourceType string - TagKey string - TagValue string -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - return self.SecurityGroupIds.SecurityGroupId, nil -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetId() string { - return self.InstanceId -} - -func (self *SInstance) GetName() string { - if len(self.InstanceName) > 0 { - return self.InstanceName - } - return self.InstanceId -} - -func (self *SInstance) GetHostname() string { - return self.HostName -} - -func (self *SInstance) GetGlobalId() string { - return self.InstanceId -} - -func (self *SInstance) IsEmulated() bool { - return false -} - -func (self *SInstance) GetInstanceType() string { - return self.InstanceType -} - -func (self *SInstance) getVpc() (*SVpc, error) { - return self.host.zone.region.getVpc(self.VpcAttributes.VpcId) -} - -type byAttachedTime []SDisk - -func (a byAttachedTime) Len() int { return len(a) } -func (a byAttachedTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byAttachedTime) Less(i, j int) bool { - switch a[i].GetDiskType() { - case api.DISK_TYPE_SYS: - return true - case api.DISK_TYPE_SWAP: - switch a[j].GetDiskType() { - case api.DISK_TYPE_SYS: - return false - case api.DISK_TYPE_DATA: - return true - } - case api.DISK_TYPE_DATA: - if a[j].GetDiskType() != api.DISK_TYPE_DATA { - return false - } - } - return a[i].AttachedTime.Before(a[j].AttachedTime) -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks := []SDisk{} - for { - part, total, err := self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, len(disks), 50) - if err != nil { - return nil, errors.Wrapf(err, "GetDisks for %s", self.InstanceId) - } - disks = append(disks, part...) - if len(disks) >= total { - break - } - } - - sort.Sort(byAttachedTime(disks)) - - log.Debugf("%s", jsonutils.Marshal(&disks)) - - 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) { - var ( - networkInterfaces = self.NetworkInterfaces.NetworkInterface - nics []cloudprovider.ICloudNic - ) - for _, networkInterface := range networkInterfaces { - nic := SInstanceNic{ - instance: self, - id: networkInterface.NetworkInterfaceId, - ipAddr: networkInterface.PrimaryIpAddress, - macAddr: networkInterface.MacAddress, - } - nics = append(nics, &nic) - } - for _, classicIp := range self.InnerIpAddress.IpAddress { - nic := SInstanceNic{ - instance: self, - id: fmt.Sprintf("%s-%s", self.InstanceId, classicIp), - ipAddr: classicIp, - classic: true, - } - nics = append(nics, &nic) - } - return nics, nil -} - -func (self *SInstance) GetVcpuCount() int { - 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 (ins *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { - if ins.osInfo == nil { - osInfo := imagetools.NormalizeImageInfo(ins.OSName, "", ins.OSType, "", "") - ins.osInfo = &osInfo - } - return ins.osInfo -} - -func (self *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(osprofile.NormalizeOSType(self.OSType)) -} - -func (self *SInstance) GetFullOsName() string { - return self.OSName -} - -func (ins *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(ins.getNormalizedOsInfo().OsBios) -} - -func (ins *SInstance) GetOsArch() string { - return ins.getNormalizedOsInfo().OsArch -} - -func (ins *SInstance) GetOsDist() string { - return ins.getNormalizedOsInfo().OsDistro -} - -func (ins *SInstance) GetOsVersion() string { - return ins.getNormalizedOsInfo().OsVersion -} - -func (ins *SInstance) GetOsLang() string { - return ins.getNormalizedOsInfo().OsLang -} - -func (self *SInstance) GetMachine() string { - return "pc" -} - -func (self *SInstance) GetStatus() string { - // Running:运行中 - //Starting:启动中 - //Stopping:停止中 - //Stopped:已停止 - switch self.Status { - case InstanceStatusRunning: - return api.VM_RUNNING - case InstanceStatusStarting: - return api.VM_STARTING - case InstanceStatusStopping: - return api.VM_STOPPING - case InstanceStatusStopped: - return api.VM_READY - default: - return api.VM_UNKNOWN - } -} - -func (self *SInstance) Refresh() error { - ins, err := self.host.zone.region.GetInstance(self.InstanceId) - if err != nil { - return err - } - return jsonutils.Update(self, ins) -} - -/* -func (self *SInstance) GetRemoteStatus() string { - // Running:运行中 - //Starting:启动中 - //Stopping:停止中 - //Stopped:已停止 - switch self.Status { - case InstanceStatusRunning: - return cloudprovider.CloudVMStatusRunning - case InstanceStatusStarting: - return cloudprovider.CloudVMStatusStopped - case InstanceStatusStopping: - return cloudprovider.CloudVMStatusRunning - case InstanceStatusStopped: - return cloudprovider.CloudVMStatusStopped - default: - return cloudprovider.CloudVMStatusOther - } -} -*/ - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_ALIYUN -} - -func (self *SInstance) StartVM(ctx context.Context) 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(), api.VM_RUNNING) - if self.GetStatus() == api.VM_RUNNING { - return nil - } else if self.GetStatus() == api.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(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - err := self.host.zone.region.StopVM(self.InstanceId, opts.IsForce, opts.StopCharging) - if err != nil { - return err - } - return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - url, err := self.host.zone.region.GetInstanceVNCUrl(self.InstanceId) - if err != nil { - return nil, err - } - passwd := seclib.RandomPassword(6) - err = self.host.zone.region.ModifyInstanceVNCUrlPassword(self.InstanceId, passwd) - if err != nil { - return nil, err - } - ret := &cloudprovider.ServerVncOutput{ - Url: url, - Password: passwd, - Protocol: "aliyun", - InstanceId: self.InstanceId, - Hypervisor: api.HYPERVISOR_ALIYUN, - } - return ret, nil -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return self.host.zone.region.UpdateVM(self.InstanceId, name, self.OSType) -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - var keypairName string - if len(publicKey) > 0 { - var err error - keypairName, err = self.host.zone.region.syncKeypair(publicKey) - if err != nil { - return err - } - } - - return self.host.zone.region.DeployVM(self.InstanceId, name, password, keypairName, deleteKeypair, description) -} - -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - keypair := "" - if len(desc.PublicKey) > 0 { - var err error - keypair, err = self.host.zone.region.syncKeypair(desc.PublicKey) - if err != nil { - return "", err - } - } - diskId, err := self.host.zone.region.ReplaceSystemDisk(self.InstanceId, desc.ImageId, desc.Password, keypair, desc.SysSizeGB) - if err != nil { - return "", err - } - - return diskId, nil -} - -func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - isDowngrade, isPrepaid := false, self.GetBillingType() == billing_api.BILLING_TYPE_PREPAID - if (self.GetVcpuCount() > config.Cpu && config.Cpu > 0) || (self.GetVmemSizeMB() > config.MemoryMB && config.MemoryMB > 0) { - isDowngrade = true - } - - instanceTypes := []string{} - - if len(config.InstanceType) > 0 { - instanceTypes = []string{config.InstanceType} - } else { - specs, err := self.host.zone.region.GetMatchInstanceTypes(config.Cpu, config.MemoryMB, 0, self.ZoneId) - if err != nil { - return errors.Wrapf(err, "GetMatchInstanceTypes") - } - for _, spec := range specs { - instanceTypes = append(instanceTypes, spec.InstanceTypeId) - } - } - - var err error - for _, instanceType := range instanceTypes { - if isPrepaid { - err = self.host.zone.region.ChangePrepaidVMConfig(self.InstanceId, instanceType, isDowngrade) - if err != nil { - log.Errorf("ChangePrepaidVMConfig %s error: %v", instanceType, err) - continue - } - } else { - err = self.host.zone.region.ChangeVMConfig(self.InstanceId, instanceType) - if err != nil { - log.Errorf("ChangeVMConfig %s error: %v", instanceType, err) - continue - } - } - return nil - } - if err != nil { - return errors.Wrapf(err, "ChangeVMConfig") - } - - return fmt.Errorf("Failed to change vm config, specification not supported") -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return self.host.zone.region.AttachDisk(self.InstanceId, diskId) -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return cloudprovider.RetryOnError( - func() error { - return self.host.zone.region.DetachDisk(self.InstanceId, diskId) - }, - []string{ - `"Code":"InvalidOperation.Conflict"`, - }, - 4) -} - -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) CreateInstance(name, hostname string, imageId string, instanceType string, securityGroupId string, - zoneId string, desc string, passwd string, disks []SDisk, vSwitchId string, ipAddr string, - keypair string, userData string, bc *billing.SBillingCycle, projectId, osType string, - tags map[string]string, publicIp cloudprovider.SPublicIpInfo, -) (string, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["ImageId"] = imageId - params["InstanceType"] = instanceType - params["SecurityGroupId"] = securityGroupId - params["ZoneId"] = zoneId - params["InstanceName"] = name - if len(hostname) > 0 { - params["HostName"] = hostname - } - params["Description"] = desc - params["InternetChargeType"] = "PayByTraffic" - params["InternetMaxBandwidthIn"] = "200" - params["InternetMaxBandwidthOut"] = "100" - if publicIp.PublicIpBw > 0 { - params["InternetMaxBandwidthOut"] = fmt.Sprintf("%d", publicIp.PublicIpBw) - } - if publicIp.PublicIpChargeType == cloudprovider.ElasticipChargeTypeByBandwidth { - params["InternetChargeType"] = "PayByBandwidth" - } - if len(passwd) > 0 { - params["Password"] = passwd - } else { - params["PasswordInherit"] = "True" - } - - if len(projectId) > 0 { - params["ResourceGroupId"] = projectId - } - //{"Code":"InvalidSystemDiskCategory.ValueNotSupported","HostId":"ecs.aliyuncs.com","Message":"The specified parameter 'SystemDisk.Category' is not support IoOptimized Instance. Valid Values: cloud_efficiency;cloud_ssd. ","RequestId":"9C9A4E99-5196-42A2-80B6-4762F8F75C90"} - params["IoOptimized"] = "optimized" - for i, d := range disks { - if i == 0 { - params["SystemDisk.Category"] = d.Category - if d.Category == api.STORAGE_CLOUD_ESSD_PL2 { - params["SystemDisk.Category"] = api.STORAGE_CLOUD_ESSD - params["SystemDisk.PerformanceLevel"] = "PL2" - } - if d.Category == api.STORAGE_CLOUD_ESSD_PL3 { - params["SystemDisk.Category"] = api.STORAGE_CLOUD_ESSD - params["SystemDisk.PerformanceLevel"] = "PL3" - } - params["SystemDisk.Size"] = fmt.Sprintf("%d", d.Size) - params["SystemDisk.DiskName"] = d.GetName() - params["SystemDisk.Description"] = d.Description - } else { - params[fmt.Sprintf("DataDisk.%d.Size", i)] = fmt.Sprintf("%d", d.Size) - params[fmt.Sprintf("DataDisk.%d.Category", i)] = d.Category - if d.Category == api.STORAGE_CLOUD_ESSD_PL2 { - params[fmt.Sprintf("DataDisk.%d.Category", i)] = api.STORAGE_CLOUD_ESSD - params[fmt.Sprintf("DataDisk.%d..PerformanceLevel", i)] = "PL2" - } - if d.Category == api.STORAGE_CLOUD_ESSD_PL3 { - params[fmt.Sprintf("DataDisk.%d.Category", i)] = api.STORAGE_CLOUD_ESSD - params[fmt.Sprintf("DataDisk.%d..PerformanceLevel", i)] = "PL3" - } - params[fmt.Sprintf("DataDisk.%d.DiskName", i)] = d.GetName() - params[fmt.Sprintf("DataDisk.%d.Description", i)] = d.Description - params[fmt.Sprintf("DataDisk.%d.Encrypted", i)] = "false" - } - } - params["VSwitchId"] = vSwitchId - params["PrivateIpAddress"] = ipAddr - - if len(keypair) > 0 { - params["KeyPairName"] = keypair - } - - if len(userData) > 0 { - params["UserData"] = userData - } - - if len(tags) > 0 { - tagIdx := 1 - for k, v := range tags { - params[fmt.Sprintf("Tag.%d.Key", tagIdx)] = k - params[fmt.Sprintf("Tag.%d.Value", tagIdx)] = v - tagIdx += 1 - } - } - - if bc != nil { - params["InstanceChargeType"] = "PrePaid" - err := billingCycle2Params(bc, params) - if err != nil { - return "", err - } - if bc.AutoRenew { - params["AutoRenew"] = "true" - params["AutoRenewPeriod"] = "1" - } else { - params["AutoRenew"] = "False" - } - } else { - params["InstanceChargeType"] = "PostPaid" - params["SpotStrategy"] = "NoSpot" - } - - params["ClientToken"] = utils.GenRequestId(20) - - body, err := self.ecsRequest("CreateInstance", params) - if err != nil { - log.Errorf("CreateInstance fail %s", err) - return "", err - } - instanceId, _ := body.GetString("InstanceId") - return instanceId, nil -} - -func (self *SRegion) AllocatePublicIpAddress(instanceId string) (string, error) { - params := map[string]string{ - "InstanceId": instanceId, - } - resp, err := self.ecsRequest("AllocatePublicIpAddress", params) - if err != nil { - return "", errors.Wrapf(err, "AllocatePublicIpAddress") - } - return resp.GetString("IpAddress") -} - -func (self *SInstance) AllocatePublicIpAddress() (string, error) { - return self.host.zone.region.AllocatePublicIpAddress(self.InstanceId) -} - -func (self *SRegion) doStartVM(instanceId string) error { - return self.instanceOperation(instanceId, "StartInstance", nil) -} - -func (self *SRegion) doStopVM(instanceId string, isForce, stopCharging bool) error { - params := make(map[string]string) - if isForce { - params["ForceStop"] = "true" - } else { - params["ForceStop"] = "false" - } - params["StoppedMode"] = "KeepCharging" - if stopCharging { - params["StoppedMode"] = "StopCharging" - } - return self.instanceOperation(instanceId, "StopInstance", params) -} - -func (self *SRegion) doDeleteVM(instanceId string) error { - params := make(map[string]string) - params["TerminateSubscription"] = "true" // terminate expired prepaid instance - params["Force"] = "true" - return self.instanceOperation(instanceId, "DeleteInstance", params) -} - -/*func (self *SRegion) waitInstanceStatus(instanceId string, target string, interval time.Duration, timeout time.Duration) error { - startTime := time.Now() - for time.Now().Sub(startTime) < timeout { - status, err := self.GetInstanceStatus(instanceId) - if err != nil { - return err - } - if status == target { - return nil - } - time.Sleep(interval) - } - return cloudprovider.ErrTimeout -} - -func (self *SInstance) waitStatus(target string, interval time.Duration, timeout time.Duration) error { - return self.host.zone.region.waitInstanceStatus(self.InstanceId, target, interval, timeout) -}*/ - -func (self *SRegion) StartVM(instanceId string) error { - status, err := self.GetInstanceStatus(instanceId) - if err != nil { - log.Errorf("Fail to get instance status on StartVM: %s", err) - return err - } - if status != InstanceStatusStopped { - log.Errorf("StartVM: vm status is %s expect %s", status, InstanceStatusStopped) - return cloudprovider.ErrInvalidStatus - } - return self.doStartVM(instanceId) - // if err != nil { - // return err - // } - // return self.waitInstanceStatus(instanceId, InstanceStatusRunning, time.Second*5, time.Second*180) // 3 minutes to timeout -} - -func (self *SRegion) StopVM(instanceId string, isForce, stopCharging bool) error { - status, err := self.GetInstanceStatus(instanceId) - if err != nil { - log.Errorf("Fail to get instance status on StopVM: %s", err) - return err - } - if status == InstanceStatusStopped { - return nil - } - if status != InstanceStatusRunning { - log.Errorf("StopVM: vm status is %s expect %s", status, InstanceStatusRunning) - return cloudprovider.ErrInvalidStatus - } - return self.doStopVM(instanceId, isForce, stopCharging) - // if err != nil { - // return err - // } - // return self.waitInstanceStatus(instanceId, InstanceStatusStopped, time.Second*10, time.Second*300) // 5 minutes to timeout -} - -func (self *SRegion) DeleteVM(instanceId string) error { - status, err := self.GetInstanceStatus(instanceId) - if err != nil { - log.Errorf("Fail to get instance status on DeleteVM: %s", err) - return err - } - log.Debugf("Instance status on delete is %s", status) - if status != InstanceStatusStopped { - log.Warningf("DeleteVM: vm status is %s expect %s", status, InstanceStatusStopped) - } - return self.doDeleteVM(instanceId) - // if err != nil { - // return err - // } - // err = self.waitInstanceStatus(instanceId, InstanceStatusRunning, time.Second*10, time.Second*300) // 5 minutes to timeout - // if err == cloudprovider.ErrNotFound { - // return nil - // } else if err == nil { - // return cloudprovider.ErrTimeout - // } else { - // return err - // } -} - -func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { - instance, err := self.GetInstance(instanceId) - if err != nil { - return err - } - - // 修改密钥时直接返回 - if deleteKeypair { - err = self.DetachKeyPair(instanceId, instance.KeyPairName) - if err != nil { - return err - } - } - - if len(keypairName) > 0 { - err = self.AttachKeypair(instanceId, keypairName) - if err != nil { - return err - } - } - - params := make(map[string]string) - - // if resetPassword { - // params["Password"] = seclib2.RandomPassword2(12) - // } - // 指定密码的情况下,使用指定的密码 - if len(password) > 0 { - params["Password"] = password - } - - if len(name) > 0 && instance.InstanceName != name { - params["InstanceName"] = name - } - - if len(description) > 0 && instance.Description != description { - params["Description"] = description - } - - if len(params) > 0 { - return self.modifyInstanceAttribute(instanceId, params) - } else { - return nil - } -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - for { - err := self.host.zone.region.DeleteVM(self.InstanceId) - if err != nil { - if isError(err, "IncorrectInstanceStatus.Initializing") { - log.Infof("The instance is initializing, try later ...") - time.Sleep(10 * time.Second) - } else { - log.Errorf("DeleteVM fail: %s", err) - return err - } - } else { - break - } - } - return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes -} - -func (self *SRegion) UpdateVM(instanceId string, name, osType string) error { - /* - api: ModifyInstanceAttribute - https://help.aliyun.com/document_detail/25503.html?spm=a2c4g.11186623.4.1.DrgpjW - */ - params := make(map[string]string) - params["InstanceName"] = name - return self.modifyInstanceAttribute(instanceId, params) -} - -func (self *SRegion) modifyInstanceAttribute(instanceId string, params map[string]string) error { - return self.instanceOperation(instanceId, "ModifyInstanceAttribute", params) -} - -func (self *SRegion) ReplaceSystemDisk(instanceId string, imageId string, passwd string, keypairName string, sysDiskSizeGB int) (string, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - params["ImageId"] = imageId - if len(passwd) > 0 { - params["Password"] = passwd - } else { - params["PasswordInherit"] = "True" - } - if len(keypairName) > 0 { - params["KeyPairName"] = keypairName - } - if sysDiskSizeGB > 0 { - params["SystemDisk.Size"] = fmt.Sprintf("%d", sysDiskSizeGB) - } - body, err := self.ecsRequest("ReplaceSystemDisk", params) - if err != nil { - return "", err - } - // log.Debugf("%s", body.String()) - return body.GetString("DiskId") -} - -func (self *SRegion) ChangePrepaidVMConfig(instanceId string, instanceType string, isDowngrade bool) error { - // todo: support change disk config? - params := make(map[string]string) - params["InstanceType"] = instanceType - params["ClientToken"] = utils.GenRequestId(20) - if isDowngrade { - params["OperatorType"] = "downgrade" - } - err := self.instanceOperation(instanceId, "ModifyPrepayInstanceSpec", params) - if err != nil { - return errors.Wrapf(err, "ModifyPrepayInstanceSpec %s", instanceType) - } - return nil -} - -func (self *SRegion) ChangeVMConfig(instanceId string, instanceType string) error { - // todo: support change disk config? - params := make(map[string]string) - params["InstanceType"] = instanceType - params["ClientToken"] = utils.GenRequestId(20) - err := self.instanceOperation(instanceId, "ModifyInstanceSpec", params) - if err != nil { - return errors.Wrapf(err, "ModifyInstanceSpec %s", instanceType) - } - return nil -} - -func (self *SRegion) DetachDisk(instanceId string, diskId string) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["DiskId"] = diskId - log.Infof("Detach instance %s disk %s", instanceId, diskId) - _, err := self.ecsRequest("DetachDisk", params) - if err != nil { - if strings.Contains(err.Error(), "The specified disk has not been attached on the specified instance") { - return nil - } - return errors.Wrap(err, "DetachDisk") - } - - return nil -} - -func (self *SRegion) AttachDisk(instanceId string, diskId string) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["DiskId"] = diskId - _, err := self.ecsRequest("AttachDisk", params) - if err != nil { - log.Errorf("AttachDisk %s to %s fail %s", diskId, instanceId, err) - return err - } - - return nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - if len(self.EipAddress.IpAddress) > 0 { - return self.host.zone.region.GetEip(self.EipAddress.AllocationId) - } - 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.InstanceType = EIP_INSTANCE_TYPE_ECS - eip.Status = EIP_STATUS_INUSE - eip.AllocationId = self.InstanceId // fixed - eip.AllocationTime = self.CreationTime - eip.Bandwidth = self.InternetMaxBandwidthOut - eip.ResourceGroupId = self.ResourceGroupId - eip.InternetChargeType = self.InternetChargeType - return &eip, nil - } - return nil, nil -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - return self.host.zone.region.AssignSecurityGroup(secgroupId, self.InstanceId) -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - return self.host.zone.region.SetSecurityGroups(secgroupIds, self.InstanceId) -} - -func (self *SInstance) GetBillingType() string { - return convertChargeType(self.InstanceChargeType) -} - -func (self *SInstance) GetCreatedAt() time.Time { - return self.CreationTime -} - -func (self *SInstance) GetExpiredAt() time.Time { - return convertExpiredAt(self.ExpiredTime) -} - -func (self *SInstance) UpdateUserData(userData string) error { - return self.host.zone.region.updateInstance(self.InstanceId, "", "", "", "", userData) -} - -func (self *SInstance) Renew(bc billing.SBillingCycle) error { - return self.host.zone.region.RenewInstance(self.InstanceId, bc) -} - -func (self *SInstance) GetThroughput() int { - return self.Throughput -} - -func (self *SInstance) GetInternetMaxBandwidthOut() int { - return self.InternetMaxBandwidthOut -} - -func billingCycle2Params(bc *billing.SBillingCycle, params map[string]string) error { - if bc.GetMonths() > 0 { - params["PeriodUnit"] = "Month" - params["Period"] = fmt.Sprintf("%d", bc.GetMonths()) - } else if bc.GetWeeks() > 0 { - params["PeriodUnit"] = "Week" - params["Period"] = fmt.Sprintf("%d", bc.GetWeeks()) - } else { - return fmt.Errorf("invalid renew time period %s", bc.String()) - } - return nil -} - -func (region *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - err := billingCycle2Params(&bc, params) - if err != nil { - return err - } - params["ClientToken"] = utils.GenRequestId(20) - _, err = region.ecsRequest("RenewInstance", params) - if err != nil { - log.Errorf("RenewInstance fail %s", err) - return err - } - return nil -} - -func (self *SInstance) GetProjectId() string { - return self.ResourceGroupId -} - -func (self *SInstance) GetError() error { - return nil -} - -func (region *SRegion) ConvertPublicIpToEip(instanceId string) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["RegionId"] = region.RegionId - _, err := region.ecsRequest("ConvertNatPublicIpToEip", params) - return err -} - -func (self *SInstance) ConvertPublicIpToEip() error { - err := self.host.zone.region.ConvertPublicIpToEip(self.InstanceId) - if err != nil { - return errors.Wrapf(err, "ConvertPublicIpToEip") - } - return cloudprovider.Wait(time.Second*5, time.Minute*5, func() (bool, error) { - self.Refresh() - iEip, err := self.GetIEIP() - if err != nil { - return false, errors.Wrapf(err, "GetIEIP") - } - if iEip == nil { - return false, nil - } - if iEip.GetMode() == api.EIP_MODE_STANDALONE_EIP { - return true, self.host.zone.region.VpcMoveResourceGroup("eip", self.ResourceGroupId, iEip.GetId()) - } - return false, nil - }) -} - -func (self *SRegion) VpcMoveResourceGroup(resType, groupId, resId string) error { - params := map[string]string{ - "RegionId": self.RegionId, - "ResourceType": resType, - "NewResourceGroupId": groupId, - "ResourceId": resId, - } - _, err := self.vpcRequest("MoveResourceGroup", params) - return errors.Wrapf(err, "MoveResourceGroup") -} - -// https://help.aliyun.com/document_detail/52843.html -func (region *SRegion) SetInstanceAutoRenew(instanceId string, bc billing.SBillingCycle) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["RegionId"] = region.RegionId - if bc.AutoRenew { - params["RenewalStatus"] = "AutoRenewal" - switch bc.Unit { - case billing.BillingCycleYear: - params["Duration"] = fmt.Sprintf("%d", bc.GetYears()) - params["PeriodUnit"] = "Year" - case billing.BillingCycleMonth: - params["Duration"] = fmt.Sprintf("%d", bc.GetMonths()) - params["PeriodUnit"] = "Month" - case billing.BillingCycleWeek: - params["Duration"] = fmt.Sprintf("%d", bc.GetWeeks()) - params["PeriodUnit"] = "Week" - } - } else { - params["RenewalStatus"] = "Normal" - } - _, err := region.ecsRequest("ModifyInstanceAutoRenewAttribute", params) - return err -} - -type SAutoRenewAttr struct { - Duration int - AutoRenewEnabled bool - RenewalStatus string - PeriodUnit string -} - -func (region *SRegion) GetInstanceAutoRenewAttribute(instanceId string) (*SAutoRenewAttr, error) { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["RegionId"] = region.RegionId - resp, err := region.ecsRequest("DescribeInstanceAutoRenewAttribute", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeInstanceAutoRenewAttribute") - } - attr := []SAutoRenewAttr{} - err = resp.Unmarshal(&attr, "InstanceRenewAttributes", "InstanceRenewAttribute") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - if len(attr) == 1 { - return &attr[0], nil - } - return nil, fmt.Errorf("get %d auto renew info", len(attr)) -} - -func (self *SInstance) IsAutoRenew() bool { - attr, err := self.host.zone.region.GetInstanceAutoRenewAttribute(self.InstanceId) - if err != nil { - log.Errorf("failed to get instance %s auto renew info", self.InstanceId) - return false - } - return attr.AutoRenewEnabled -} - -func (self *SInstance) SetAutoRenew(bc billing.SBillingCycle) error { - return self.host.zone.region.SetInstanceAutoRenew(self.InstanceId, bc) -} - -func (self *SInstance) SetTags(tags map[string]string, replace bool) error { - return self.host.zone.region.SetResourceTags(ALIYUN_SERVICE_ECS, "instance", self.InstanceId, tags, replace) -} - -func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { - params := map[string]string{ - "InstanceId": instanceId, - "ImageName": opts.Name, - "Description": opts.Notes, - "ClientToken": utils.GenRequestId(20), - } - resp, err := self.ecsRequest("CreateImage", params) - if err != nil { - return nil, errors.Wrapf(err, "CreateImage") - } - ret := struct{ ImageId string }{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - image, err := self.GetImage(ret.ImageId) - if err != nil { - return nil, errors.Wrapf(err, "GetImage(%s)", ret.ImageId) - } - image.storageCache = self.getStoragecache() - return image, nil -} - -func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { - image, err := self.host.zone.region.SaveImage(self.InstanceId, opts) - if err != nil { - return nil, errors.Wrapf(err, "SaveImage(%s)", opts.Name) - } - return image, nil -} diff --git a/pkg/multicloud/aliyun/instancenic.go b/pkg/multicloud/aliyun/instancenic.go deleted file mode 100644 index 409543b9c1..0000000000 --- a/pkg/multicloud/aliyun/instancenic.go +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "time" - - alierr "github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors" - "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - instance *SInstance - id string - ipAddr string - macAddr string - - classic bool - - cloudprovider.DummyICloudNic -} - -func (self *SInstanceNic) GetId() string { - return self.id -} - -func (self *SInstanceNic) mustGetId() string { - if self.id == "" { - panic("empty network interface id") - } - return self.id -} - -func (self *SInstanceNic) GetIP() string { - return self.ipAddr -} - -func (self *SInstanceNic) GetMAC() string { - if len(self.macAddr) > 0 { - return self.macAddr - } - ip, _ := netutils.NewIPV4Addr(self.GetIP()) - return ip.ToMac("00:16:") -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return self.classic == true -} - -func (self *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (self *SInstanceNic) GetINetworkId() string { - return self.instance.VpcAttributes.VSwitchId -} - -func (self *SInstanceNic) GetSubAddress() ([]string, error) { - selfId := self.mustGetId() - region := self.instance.host.zone.region - params := map[string]string{ - "RegionId": region.GetId(), - "NetworkInterfaceId.1": selfId, - } - body, err := region.ecsRequest("DescribeNetworkInterfaces", params) - if err != nil { - return nil, err - } - - type DescribeNetworkInterfacesResponse struct { - TotalCount int `json:"TotalCount"` - RequestID string `json:"RequestId"` - PageSize int `json:"PageSize"` - NextToken string `json:"NextToken"` - PageNumber int `json:"PageNumber"` - NetworkInterfaceSets struct { - NetworkInterfaceSet []struct { - Status string `json:"Status"` - PrivateIPAddress string `json:"PrivateIpAddress"` - ZoneID string `json:"ZoneId"` - ResourceGroupID string `json:"ResourceGroupId"` - InstanceID string `json:"InstanceId"` - VSwitchID string `json:"VSwitchId"` - NetworkInterfaceID string `json:"NetworkInterfaceId"` - MacAddress string `json:"MacAddress"` - SecurityGroupIds struct { - SecurityGroupID []string `json:"SecurityGroupId"` - } `json:"SecurityGroupIds"` - Type string `json:"Type"` - Ipv6Sets struct { - Ipv6Set []struct { - Ipv6Address string `json:"Ipv6Address"` - } `json:"Ipv6Set"` - } `json:"Ipv6Sets"` - VpcID string `json:"VpcId"` - OwnerID string `json:"OwnerId"` - AssociatedPublicIP struct { - } `json:"AssociatedPublicIp"` - CreationTime time.Time `json:"CreationTime"` - Tags struct { - Tag []struct { - TagKey string `json:"TagKey"` - TagValue string `json:"TagValue"` - } `json:"Tag"` - } `json:"Tags"` - PrivateIPSets struct { - PrivateIPSet []struct { - PrivateIPAddress string `json:"PrivateIpAddress"` - AssociatedPublicIP struct { - } `json:"AssociatedPublicIp"` - Primary bool `json:"Primary"` - } `json:"PrivateIpSet"` - } `json:"PrivateIpSets"` - } `json:"NetworkInterfaceSet"` - } `json:"NetworkInterfaceSets"` - } - var resp DescribeNetworkInterfacesResponse - if err := body.Unmarshal(&resp); err != nil { - return nil, errors.Wrapf(err, "unmarshal DescribeNetworkInterfacesResponse: %s", body) - } - if got := len(resp.NetworkInterfaceSets.NetworkInterfaceSet); got != 1 { - return nil, errors.Errorf("got %d element(s) in interface set, expect 1", got) - } - var ( - ipAddrs []string - networkInterface = resp.NetworkInterfaceSets.NetworkInterfaceSet[0] - ) - if got := networkInterface.NetworkInterfaceID; got != selfId { - return nil, errors.Errorf("got interface data for %s, expect %s", got, selfId) - } - for _, privateIP := range networkInterface.PrivateIPSets.PrivateIPSet { - if !privateIP.Primary { - ipAddrs = append(ipAddrs, privateIP.PrivateIPAddress) - } - } - return ipAddrs, nil -} - -func (self *SInstanceNic) ipAddrsParams(ipAddrs []string) map[string]string { - region := self.instance.host.zone.region - params := map[string]string{ - "RegionId": region.GetId(), - "NetworkInterfaceId": self.mustGetId(), - } - for i, ipAddr := range ipAddrs { - k := fmt.Sprintf("PrivateIpAddress.%d", i+1) - params[k] = ipAddr - } - return params -} - -func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { - var ( - selfId = self.mustGetId() - instance = self.instance - zone = instance.host.zone - region = zone.region - ) - ecsClient, err := region.getEcsClient() - if err != nil { - return err - } - request := ecs.CreateAssignPrivateIpAddressesRequest() - request.Scheme = "https" - - request.NetworkInterfaceId = selfId - request.PrivateIpAddress = &ipAddrs - resp, err := ecsClient.AssignPrivateIpAddresses(request) - if err != nil { - if aerr, ok := err.(*alierr.ServerError); ok { - if aerr.ErrorCode() == "InvalidOperation.Ipv4CountExceeded" { - return errors.Wrap(cloudprovider.ErrAddressCountExceed, aerr.Message()) - } - } - return errors.Wrapf(err, "AssignPrivateIpAddresses") - } - - allocated := resp.AssignedPrivateIpAddressesSet.PrivateIpSet.PrivateIpAddress - if len(allocated) != len(ipAddrs) { - return errors.Errorf("AssignAddress want %d addresses, got %d", len(ipAddrs), len(allocated)) - } - for i := 0; i < len(ipAddrs); i++ { - ip0 := ipAddrs[i] - ip1 := allocated[i] - if ip0 != ip1 { - return errors.Errorf("AssignAddress address %d does not match: want %s, got %s", i, ip0, ip1) - } - } - return nil -} - -func (self *SInstanceNic) UnassignAddress(ipAddrs []string) error { - var ( - selfId = self.mustGetId() - instance = self.instance - zone = instance.host.zone - region = zone.region - ) - ecsClient, err := region.getEcsClient() - if err != nil { - return err - } - request := ecs.CreateUnassignPrivateIpAddressesRequest() - request.Scheme = "https" - - request.NetworkInterfaceId = selfId - request.PrivateIpAddress = &ipAddrs - resp, err := ecsClient.UnassignPrivateIpAddresses(request) - if err != nil { - if resp.GetHttpStatus() == 404 { - return nil - } - return err - } - return nil -} diff --git a/pkg/multicloud/aliyun/kafka.go b/pkg/multicloud/aliyun/kafka.go deleted file mode 100644 index e1a0dcb30c..0000000000 --- a/pkg/multicloud/aliyun/kafka.go +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SKafka struct { - multicloud.SBillingBase - multicloud.SVirtualResourceBase - multicloud.AliyunTags - region *SRegion - - AllConfig string `json:"AllConfig"` - DeployType int `json:"DeployType"` - SpecType string `json:"SpecType"` - PaidType int `json:"PaidType"` - InstanceId string `json:"InstanceId"` - MsgRetain int `json:"MsgRetain"` - ZoneId string `json:"ZoneId"` - IoMax int `json:"IoMax"` - VSwitchId string `json:"VSwitchId"` - VpcId string `json:"VpcId"` - UpgradeServiceDetailInfo struct { - Current2OpenSourceVersion string `json:"Current2OpenSourceVersion"` - } `json:"UpgradeServiceDetailInfo"` - ServiceStatus int `json:"ServiceStatus"` - Name string `json:"Name"` - TopicNumLimit int `json:"TopicNumLimit"` - DiskSize int `json:"DiskSize"` - RegionId string `json:"RegionId"` - CreateTime int64 `json:"CreateTime"` - SslEndPoint string `json:"SslEndPoint"` - EipMax int `json:"EipMax"` - EndPoint string `json:"EndPoint"` - ExpiredTime int64 `json:"ExpiredTime"` - DiskType int `json:"DiskType"` - SecurityGroup string `json:"SecurityGroup"` -} - -func (self *SKafka) GetName() string { - return self.Name -} - -func (self *SKafka) GetGlobalId() string { - return self.InstanceId -} - -func (self *SKafka) GetId() string { - return self.InstanceId -} - -func (self *SKafka) GetVpcId() string { - return self.VpcId -} - -func (self *SKafka) GetNetworkId() string { - return self.VSwitchId -} - -func (self *SKafka) GetCreatedAt() time.Time { - return time.Unix(self.CreateTime/1000, self.CreateTime%1000) -} - -func (self *SKafka) GetBillingType() string { - if self.PaidType == 0 { - return billing_api.BILLING_TYPE_PREPAID - } - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SKafka) GetInstanceType() string { - return self.SpecType -} - -func (self *SKafka) GetDiskSizeGb() int { - return self.DiskSize -} - -func (self *SKafka) GetVersion() string { - return self.UpgradeServiceDetailInfo.Current2OpenSourceVersion -} - -func (self *SKafka) IsMultiAz() bool { - return false -} - -func (self *SKafka) GetStorageType() string { - switch self.DiskType { - case 0: - return api.STORAGE_CLOUD_EFFICIENCY - case 1: - return api.STORAGE_CLOUD_SSD - } - return "" -} - -func (self *SKafka) GetBandwidthMb() int { - if self.EipMax > 0 { - return self.EipMax - } - return self.IoMax -} - -func (self *SKafka) GetEndpoint() string { - ret := []string{} - if len(self.EndPoint) > 0 { - ret = append(ret, self.EndPoint) - } - if len(self.SslEndPoint) > 0 { - ret = append(ret, self.SslEndPoint) - } - return strings.Join(ret, ",") -} - -func (self *SKafka) GetMsgRetentionMinute() int { - return self.MsgRetain * 60 -} - -func (self *SKafka) GetZoneId() string { - if len(self.ZoneId) > 0 { - return fmt.Sprintf("%s-%s", self.RegionId, strings.TrimPrefix(self.ZoneId, "zone")) - } - return "" -} - -func (self *SKafka) GetStatus() string { - switch self.ServiceStatus { - case 0, 1, 2: - return api.KAFKA_STATUS_CREATING - case 5: - return api.KAFKA_STATUS_AVAILABLE - case 15: - return api.KAFKA_STATUS_UNAVAILABLE - } - return api.KAFKA_STATUS_UNKNOWN -} - -func (self *SKafka) Refresh() error { - kafka, err := self.region.GetKafka(self.InstanceId) - if err != nil { - return errors.Wrapf(err, "GetKafka") - } - return jsonutils.Update(self, kafka) -} - -func (self *SKafka) Delete() error { - return self.region.DeleteKafka(self.InstanceId) -} - -func (self *SRegion) GetICloudKafkaById(id string) (cloudprovider.ICloudKafka, error) { - kafka, err := self.GetKafka(id) - if err != nil { - return nil, errors.Wrapf(err, "GetKafka(%s)", id) - } - return kafka, nil -} - -func (self *SRegion) GetICloudKafkas() ([]cloudprovider.ICloudKafka, error) { - kafkas, err := self.GetKafkas(nil) - if err != nil { - return nil, errors.Wrapf(err, "GetKafkas") - } - ret := []cloudprovider.ICloudKafka{} - for i := range kafkas { - kafkas[i].region = self - ret = append(ret, &kafkas[i]) - } - return ret, nil -} - -func (self *SRegion) GetKafka(id string) (*SKafka, error) { - kafkas, err := self.GetKafkas([]string{id}) - if err != nil { - return nil, errors.Wrapf(err, "GetKafkas") - } - for i := range kafkas { - if kafkas[i].GetGlobalId() == id { - kafkas[i].region = self - return &kafkas[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SRegion) GetKafkas(ids []string) ([]SKafka, error) { - params := map[string]string{} - for idx, id := range ids { - params[fmt.Sprintf("InstanceId.%d", idx)] = id - } - resp, err := self.kafkaRequest("GetInstanceList", params) - if err != nil { - return nil, errors.Wrapf(err, "GetInstanceList") - } - ret := struct { - Code int - Message string - RequestId string - Success bool - InstanceList struct { - InstanceVO []SKafka - } - }{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - if ret.Code != 200 { - return nil, errors.Errorf("message: %s requestId: %s", ret.Message, ret.RequestId) - } - return ret.InstanceList.InstanceVO, nil -} - -func (self *SRegion) DeleteKafka(id string) error { - params := map[string]string{ - "RegionId": self.RegionId, - "InstanceId": id, - } - _, err := self.kafkaRequest("DeleteInstance", params) - return errors.Wrapf(err, "DeleteInstance") -} - -func (self *SRegion) ReleaseKafka(id string) error { - params := map[string]string{ - "RegionId": self.RegionId, - "InstanceId": id, - "ForceDeleteInstance": "true", - } - _, err := self.kafkaRequest("ReleaseInstance", params) - return errors.Wrapf(err, "ReleaseInstance") -} - -func (self *SKafka) GetTopics() ([]cloudprovider.SKafkaTopic, error) { - ret := []cloudprovider.SKafkaTopic{} - pageSize := 100 - for { - part, total, err := self.region.GetKafkaTopics(self.InstanceId, len(ret)/pageSize+1, pageSize) - if err != nil { - return nil, errors.Wrapf(err, "GetKafkaTopics") - } - ret = append(ret, part...) - if len(ret) >= total { - break - } - } - return ret, nil -} - -func (self *SRegion) GetKafkaTopics(id string, page int, pageSize int) ([]cloudprovider.SKafkaTopic, int, error) { - if page < 1 { - page = 1 - } - if pageSize < 1 { - pageSize = 50 - } - params := map[string]string{ - "InstanceId": id, - "CurrentPage": fmt.Sprintf("%d", page), - "PageSize": fmt.Sprintf("%d", pageSize), - } - resp, err := self.kafkaRequest("GetTopicList", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "GetTopicList") - } - result := struct { - Code int - Total int - Message string - TopicList struct { - TopicVO []struct { - CompactTopic bool - CreateTime int - InstanceId string - LocalTopic bool - PartitionNum int - RegionId string - Remark string - Status int - StatusName string - Topic string - } - } - }{} - err = resp.Unmarshal(&result) - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - ret := []cloudprovider.SKafkaTopic{} - for _, topic := range result.TopicList.TopicVO { - ret = append(ret, cloudprovider.SKafkaTopic{ - Id: topic.Topic, - Name: topic.Topic, - Description: topic.Remark, - }) - } - return ret, result.Total, nil -} diff --git a/pkg/multicloud/aliyun/kube_cluster.go b/pkg/multicloud/aliyun/kube_cluster.go deleted file mode 100644 index 287f3b52f6..0000000000 --- a/pkg/multicloud/aliyun/kube_cluster.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SKubeCluster struct { - multicloud.SResourceBase - - region *SRegion - - Name string `json:"name"` - ClusterId string `json:"cluster_id"` - Size int `json:"size"` - RegionId string `json:"region_id"` - State string `json:"state"` - ClusterType string `json:"cluster_type"` - Created time.Time `json:"created"` - Updated time.Time `json:"updated"` - InitVersion string `json:"init_version"` - CurrentVersion string `json:"current_version"` - MetaData string `json:"meta_data"` - ResourceGroupId string `json:"resource_group_id"` - InstanceType string `json:"instance_type"` - VpcId string `json:"vpc_id"` - VswitchId string `json:"vswitch_id"` - VswitchCidr string `json:"vswitch_cidr"` - DataDiskSize int `json:"data_disk_size"` - DataDiskCategory string `json:"data_disk_category"` - SecurityGroupId string `json:"security_group_id"` - Tags []struct { - Key string - Value string - } - ZoneId string `json:"zone_id"` - NetworkMode string `json:"network_mode"` - SubnetCidr string `json:"subnet_cidr"` - MasterURL string `json:"master_url"` - ExternalLoadbalancerId string `json:"external_loadbalancer_id"` - Port int `json:"port"` - NodeStatus string `json:"node_status"` - ClusterHealthy string `json:"cluster_healthy"` - DockerVersion string `json:"docker_version"` - SwarmMode bool `json:"swarm_mode"` - GwBridge string `json:"gw_bridge"` - UpgradeComponents string `json:"upgrade_components"` - NextVersion string `json:"next_version"` - PrivateZone bool `json:"private_zone"` - ServiceDiscoveryTypes string `json:"service_discovery_types"` - PrivateLink bool `json:"private_link"` - Profile string `json:"profile"` - DeletionProtection bool `json:"deletion_protection"` - ClusterSpec string `json:"cluster_spec"` - MaintenanceWindow struct { - Enable bool `json:"enable"` - MaintenanceTime string `json:"maintenance_time"` - Duration string `json:"duration"` - WeeklyPeriod string `json:"weekly_period"` - } `json:"maintenance_window"` - Capabilities string `json:"capabilities"` - EnabledMigration bool `json:"enabled_migration"` - NeedUpdateAgent bool `json:"need_update_agent"` - Outputs string `json:"outputs"` - Parameters string `json:"parameters"` - WorkerRAMRoleName string `json:"worker_ram_role_name"` - MaintenanceInfo string `json:"maintenance_info"` -} - -func (self *SKubeCluster) GetName() string { - return self.Name -} - -func (self *SKubeCluster) GetStatus() string { - switch self.State { - case "initial": - return apis.STATUS_CREATING - case "failed": - return apis.STATUS_CREATE_FAILED - case "deleting", "deleted": - return apis.STATUS_DELETING - case "delete_failed": - return apis.STATUS_DELETE_FAILED - default: - return self.State - } -} - -func (self *SKubeCluster) GetId() string { - return self.ClusterId -} - -func (self *SKubeCluster) GetGlobalId() string { - return self.ClusterId -} - -func (self *SKubeCluster) GetEnabled() bool { - return true -} - -func (self *SKubeCluster) Refresh() error { - cluster, err := self.region.GetKubeCluster(self.ClusterId) - if err != nil { - return errors.Wrapf(err, "GetKubeCluster(%s)", self.ClusterId) - } - return jsonutils.Update(self, cluster) -} - -func (self *SKubeCluster) GetKubeConfig(private bool, expireMinutes int) (*cloudprovider.SKubeconfig, error) { - return self.region.GetKubeConfig(self.ClusterId, private, expireMinutes) -} - -func (self *SKubeCluster) Delete(isRetain bool) error { - return self.region.DeleteKubeCluster(self.ClusterId, isRetain) -} - -func (self *SKubeCluster) GetTags() (map[string]string, error) { - ret := map[string]string{} - for _, tag := range self.Tags { - ret[tag.Key] = tag.Value - } - return ret, nil -} - -func (self *SKubeCluster) GetSysTags() map[string]string { - return nil -} - -func (self *SKubeCluster) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetKubeConfig(clusterId string, private bool, minutes int) (*cloudprovider.SKubeconfig, error) { - params := map[string]string{ - "PathPattern": fmt.Sprintf("/k8s/%s/user_config", clusterId), - "PrivateIpAddress": fmt.Sprintf("%v", private), - } - if minutes >= 15 && minutes <= 4320 { - params["TemporaryDurationMinutes"] = fmt.Sprintf("%d", minutes) - } - resp, err := self.k8sRequest("DescribeClusterUserKubeconfig", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeClusterUserKubeconfig") - } - result := &cloudprovider.SKubeconfig{} - err = resp.Unmarshal(result) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return result, nil -} - -func (self *SRegion) GetKubeClusters(pageSize, pageNumber int) ([]SKubeCluster, int, error) { - if pageSize < 1 || pageSize > 100 { - pageSize = 100 - } - if pageNumber < 1 { - pageNumber = 1 - } - params := map[string]string{ - "page_size": fmt.Sprintf("%d", pageSize), - "page_number": fmt.Sprintf("%d", pageNumber), - "PathPattern": "/api/v1/clusters", - } - resp, err := self.k8sRequest("DescribeClustersV1", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeClustersV1") - } - clusters := []SKubeCluster{} - err = resp.Unmarshal(&clusters, "clusters") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - totalCnt, _ := resp.Int("page_info", "total_count") - return clusters, int(totalCnt), nil -} - -func (self *SRegion) GetICloudKubeClusters() ([]cloudprovider.ICloudKubeCluster, error) { - clusters := []SKubeCluster{} - for { - part, total, err := self.GetKubeClusters(100, len(clusters)/100+1) - if err != nil { - return nil, errors.Wrapf(err, "GetKubeClusters") - } - clusters = append(clusters, part...) - if len(clusters) >= total || len(part) == 0 { - break - } - } - ret := []cloudprovider.ICloudKubeCluster{} - for i := range clusters { - if clusters[i].RegionId == self.RegionId { - clusters[i].region = self - ret = append(ret, &clusters[i]) - } - } - return ret, nil -} - -func (self *SRegion) GetICloudKubeClusterById(id string) (cloudprovider.ICloudKubeCluster, error) { - cluster, err := self.GetKubeCluster(id) - if err != nil { - return nil, errors.Wrapf(err, "GetKubeCluster(%s)", id) - } - if cluster.RegionId != self.RegionId { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s at region %s", id, cluster.RegionId) - } - return cluster, nil -} - -func (self *SRegion) GetKubeCluster(id string) (*SKubeCluster, error) { - params := map[string]string{ - "PathPattern": fmt.Sprintf("/clusters/%s", id), - } - resp, err := self.k8sRequest("DescribeClusterDetail", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeClusterDetail") - } - cluster := &SKubeCluster{region: self} - err = resp.Unmarshal(&cluster) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return cluster, nil -} - -func (self *SRegion) DeleteKubeCluster(id string, isRetain bool) error { - params := map[string]string{ - "PathPattern": fmt.Sprintf("/clusters/%s", id), - } - if isRetain { - params["retain_all_resources"] = "true" - params["keep_slb"] = "true" - } - _, err := self.k8sRequest("DeleteCluster", params) - return errors.Wrapf(err, "DeleteCluster") -} diff --git a/pkg/multicloud/aliyun/kube_node.go b/pkg/multicloud/aliyun/kube_node.go deleted file mode 100644 index 0e76ad35eb..0000000000 --- a/pkg/multicloud/aliyun/kube_node.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SKubeNode struct { - multicloud.SResourceBase - multicloud.AliyunTags - - cluster *SKubeCluster - - HostName string - ImageId string - InstanceChargeType string - InstanceId string - InstanceName string - InstanceRole string - InstanceStatus string - InstanceType string - InstanceTypeFamily string - IpAddress []string - IsAliyunNode bool - NodeName string - NodeStatus string - NodepoolId string - Source string - State string - SpotStrategy string -} - -func (self *SKubeNode) GetGlobalId() string { - return self.NodeName -} - -func (self *SKubeNode) GetId() string { - return self.NodeName -} - -func (self *SKubeNode) GetName() string { - return self.NodeName -} - -func (self *SKubeNode) GetStatus() string { - return self.NodeStatus -} - -func (self *SKubeNode) GetINodePoolId() string { - return self.NodepoolId -} - -func (self *SRegion) GetKubeNodes(clusterId string, pageSize, pageNumber int) ([]SKubeNode, int, error) { - if pageSize < 1 || pageSize > 100 { - pageSize = 100 - } - if pageNumber < 1 { - pageNumber = 1 - } - params := map[string]string{ - "page_size": fmt.Sprintf("%d", pageSize), - "page_number": fmt.Sprintf("%d", pageNumber), - "PathPattern": fmt.Sprintf("/clusters/%s/nodes", clusterId), - } - resp, err := self.k8sRequest("DescribeClusterNodes", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeClusterNodes") - } - nodes := []SKubeNode{} - err = resp.Unmarshal(&nodes, "nodes") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - totalCnt, _ := resp.Int("page", "total_count") - return nodes, int(totalCnt), nil -} - -func (self *SKubeCluster) GetIKubeNodes() ([]cloudprovider.ICloudKubeNode, error) { - nodes := []SKubeNode{} - for { - part, total, err := self.region.GetKubeNodes(self.ClusterId, 100, len(nodes)/100) - if err != nil { - return nil, errors.Wrapf(err, "GetKubeNodes") - } - nodes = append(nodes, part...) - if len(nodes) >= total || len(part) == 0 { - break - } - } - ret := []cloudprovider.ICloudKubeNode{} - for i := range nodes { - nodes[i].cluster = self - ret = append(ret, &nodes[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/aliyun/kube_node_pools.go b/pkg/multicloud/aliyun/kube_node_pools.go deleted file mode 100644 index e8c680a842..0000000000 --- a/pkg/multicloud/aliyun/kube_node_pools.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SKubeNodePool struct { - multicloud.SResourceBase - multicloud.AliyunTags - - cluster *SKubeCluster - - AutoScaling struct { - EipBandwidth int `json:"eip_bandwidth"` - IsBondEip bool `json:"is_bond_eip"` - Enable bool `json:"enable"` - MaxInstances int `json:"max_instances"` - MinInstances int `json:"min_instances"` - Type string `json:"type"` - } `json:"auto_scaling"` - KubernetesConfig struct { - CmsEnabled bool `json:"cms_enabled"` - CpuPolicy string `json:"cpu_policy"` - Runtime string `json:"runtime"` - RuntimeVersion string `json:"runtime_version"` - UserData string `json:"user_data"` - } `json:"kubernetes_config"` - NodepoolInfo struct { - Created string `json:"created"` - IsDefault bool `json:"is_default"` - Name string `json:"name"` - NodepoolId string `json:"nodepool_id"` - RegionId string `json:"region_id"` - ResourceGroupId string `json:"resource_group_id"` - Type string `json:"type"` - Updated string `json:"updated"` - } `json:"nodepool_info"` - ScalingGroup struct { - AutoRenew bool `json:"auto_renew"` - AutoRenewPeriod int `json:"auto_renew_period"` - ImageId string `json:"image_id"` - InstanceChargeType string `json:"instance_charge_type"` - Instance_types []string `json:"instance_types"` - MultiAzPolicy string `json:"multi_az_policy"` - OnDemandBaseCapacity int `json:"on_demand_base_capacity"` - OnDemandPercentageAboveBaseCapacity int `json:"on_demand_percentage_above_base_capacity"` - SpotInstancePools int `json:"spot_instance_pools"` - SpotInstanceRemedy bool `json:"spot_instance_remedy"` - CompensateWithOnDemand bool `json:"compensate_with_on_demand"` - Period int `json:"period"` - PeriodUnit string `json:"period_unit"` - Platform string `json:"platform"` - RamPolicy string `json:"ram_policy"` - SpotStrategy string `json:"spot_strategy"` - SpotPriceLimit []struct { - InstanceType string `json:"instance_type"` - PriceLimit string `json:"price_limit"` - } `json:"spot_price_limit"` - RdsInstances []string `json:"rds_instances"` - ScalingGroupId string `json:"scaling_group_id"` - ScalingPolicy string `json:"scaling_policy"` - SecurityGroupId string `json:"security_group_id"` - SystemDiskCategory string `json:"system_disk_category"` - SystemDiskSize int `json:"system_disk_size"` - VswitchIds []string `json:"vswitch_ids"` - LoginPassword string `json:"login_password"` - KeyPair string `json:"key_pair"` - } `json:"scaling_group"` - Status struct { - FailedNodes string `json:"failed_nodes"` - HealthyNodes string `json:"healthy_nodes"` - InitialNodes string `json:"initial_nodes"` - OfflineNodes string `json:"offline_nodes"` - RemovingNodes string `json:"removing_nodes"` - ServingNodes string `json:"serving_nodes"` - State string `json:"state"` - TotalNodes int `json:"total_nodes"` - } `json:"status"` - TeeConfig struct { - TeeEnable bool `json:"tee_enable"` - } `json:"tee_config"` - Management struct { - Enable bool `json:"enable"` - AutoRepair bool `json:"auto_repair"` - UpgradeConfig struct { - AutoUpgrade bool `json:"auto_upgrade"` - Surge int `json:"surge"` - SurgePercentage int `json:"surge_percentage"` - MaxUnavailable int `json:"max_unavailable"` - } `json:"upgrade_config"` - } `json:"management"` -} - -func (self *SKubeNodePool) GetName() string { - return self.NodepoolInfo.Name -} - -func (self *SKubeNodePool) GetId() string { - return self.NodepoolInfo.NodepoolId -} - -func (self *SKubeNodePool) GetGlobalId() string { - return self.NodepoolInfo.NodepoolId -} - -func (self *SKubeNodePool) GetStatus() string { - return self.Status.State -} - -func (self *SKubeCluster) GetIKubeNodePools() ([]cloudprovider.ICloudKubeNodePool, error) { - pools, err := self.region.GetKubeNodePools(self.ClusterId) - if err != nil { - return nil, errors.Wrapf(err, "GetKubeNodePools") - } - ret := []cloudprovider.ICloudKubeNodePool{} - for i := range pools { - pools[i].cluster = self - ret = append(ret, &pools[i]) - } - return ret, nil -} - -func (self *SRegion) GetKubeNodePools(clusterId string) ([]SKubeNodePool, error) { - params := map[string]string{ - "PathPattern": fmt.Sprintf("/clusters/%s/nodepools", clusterId), - } - resp, err := self.k8sRequest("DescribeClusterNodePools", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeClusterNodePools") - } - pools := []SKubeNodePool{} - err = resp.Unmarshal(&pools, "nodepools") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return pools, nil -} diff --git a/pkg/multicloud/aliyun/latitud_and_longitude.go b/pkg/multicloud/aliyun/latitud_and_longitude.go deleted file mode 100644 index 86f869e19f..0000000000 --- a/pkg/multicloud/aliyun/latitud_and_longitude.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ - "cn-qingdao": api.RegionQingdao, - "cn-beijing": api.RegionBeijing, - "cn-zhangjiakou": api.RegionZhangjiakou, - "cn-huhehaote": api.RegionHuhehaote, - "cn-huhehaote-nebula-1": api.RegionHuhehaote, - "cn-hangzhou": api.RegionHangzhou, - "cn-shanghai": api.RegionShanghai, - "cn-shanghai-finance-1": api.RegionShanghai, - "cn-shenzhen": api.RegionShenzhen, - "cn-shenzhen-finance-1": api.RegionShenzhen, - "cn-hongkong": api.RegionHongkong, - "cn-chengdu": api.RegionChengdu, - "cn-heyuan": api.RegionHeyuan, - "ap-northeast-1": api.RegionTokyo, - "ap-southeast-1": api.RegionSingapore, - "ap-southeast-2": api.RegionSydney, - "ap-southeast-3": api.RegionKualaLumpur, - "ap-southeast-5": api.RegionJakarta, - "ap-south-1": api.RegionMumbai, - "us-east-1": api.RegionVirginia, - "us-west-1": api.RegionSiliconValley, - "eu-west-1": api.RegionLondon, - "me-east-1": api.RegionDubai, - "eu-central-1": api.RegionFrankfurt, - "cn-wulanchabu": api.RegionWulanchabu, - "cn-guangzhou": api.RegionGuangzhou, -} diff --git a/pkg/multicloud/aliyun/loadbalancer.go b/pkg/multicloud/aliyun/loadbalancer.go deleted file mode 100644 index 0da6303623..0000000000 --- a/pkg/multicloud/aliyun/loadbalancer.go +++ /dev/null @@ -1,494 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type ListenerProtocol string - -const ( - ListenerProtocolTCP ListenerProtocol = "tcp" - ListenerProtocolUDP ListenerProtocol = "udp" - ListenerProtocolHTTP ListenerProtocol = "http" - ListenerProtocolHTTPS ListenerProtocol = "https" -) - -type ListenerPorts struct { - ListenerPort []int -} - -type ListenerPortsAndProtocol struct { - ListenerPortAndProtocol []ListenerPortAndProtocol -} - -type ListenerPortAndProtocol struct { - Description string - ListenerPort int - ListenerProtocol ListenerProtocol -} - -type BackendServers struct { - BackendServer []SLoadbalancerDefaultBackend -} - -type SLoadbalancer struct { - multicloud.SLoadbalancerBase - multicloud.AliyunTags - region *SRegion - - LoadBalancerId string //负载均衡实例ID。 - LoadBalancerName string //负载均衡实例的名称。 - LoadBalancerStatus string //负载均衡实例状态:inactive: 此状态的实例监听不会再转发流量。active: 实例创建后,默认状态为active。 locked: 实例已经被锁定。 - Address string //负载均衡实例的服务地址。 - RegionId string //负载均衡实例的地域ID。 - RegionIdAlias string //负载均衡实例的地域名称。 - AddressType string //负载均衡实例的网络类型。 - VSwitchId string //私网负载均衡实例的交换机ID。 - VpcId string //私网负载均衡实例的专有网络ID。 - NetworkType string //私网负载均衡实例的网络类型:vpc:专有网络实例 classic:经典网络实例 - ListenerPorts ListenerPorts - ListenerPortsAndProtocol ListenerPortsAndProtocol - BackendServers BackendServers - CreateTime time.Time //负载均衡实例的创建时间。 - MasterZoneId string //实例的主可用区ID。 - SlaveZoneId string //实例的备可用区ID。 - InternetChargeType TInternetChargeType //公网实例的计费方式。取值:paybybandwidth:按带宽计费 paybytraffic:按流量计费(默认值) 说明 当 PayType参数的值为PrePay时,只支持按带宽计费。 - InternetChargeTypeAlias TInternetChargeType - - PayType string //实例的计费类型,取值:PayOnDemand:按量付费 PrePay:预付费 - ResourceGroupId string //企业资源组ID。 - LoadBalancerSpec string //负载均衡实例的的性能规格 - Bandwidth int //按带宽计费的公网型实例的带宽峰值 -} - -func (lb *SLoadbalancer) GetName() string { - return lb.LoadBalancerName -} - -func (lb *SLoadbalancer) GetId() string { - return lb.LoadBalancerId -} - -func (lb *SLoadbalancer) GetGlobalId() string { - return lb.LoadBalancerId -} - -func (lb *SLoadbalancer) GetStatus() string { - if lb.LoadBalancerStatus == "active" { - return api.LB_STATUS_ENABLED - } - return api.LB_STATUS_DISABLED -} - -func (lb *SLoadbalancer) GetAddress() string { - return lb.Address -} - -func (lb *SLoadbalancer) GetAddressType() string { - return lb.AddressType -} - -func (lb *SLoadbalancer) GetNetworkType() string { - return lb.NetworkType -} - -func (lb *SLoadbalancer) GetNetworkIds() []string { - return []string{lb.VSwitchId} -} - -func (lb *SLoadbalancer) GetZoneId() string { - zone, err := lb.region.getZoneById(transZoneIdToEcsZoneId(lb.region, "elb", lb.MasterZoneId)) - if err != nil { - log.Errorf("failed to find zone for lb %s error: %v", lb.LoadBalancerName, err) - return "" - } - return zone.GetGlobalId() -} - -func (self *SLoadbalancer) GetZone1Id() string { - return "" -} - -func (lb *SLoadbalancer) IsEmulated() bool { - return false -} - -func (lb *SLoadbalancer) GetVpcId() string { - return lb.VpcId -} - -func (lb *SLoadbalancer) Refresh() error { - loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId) - if err != nil { - return err - } - return jsonutils.Update(lb, loadbalancer) -} - -func (region *SRegion) GetLoadbalancers(ids []string) ([]SLoadbalancer, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - if ids != nil && len(ids) > 0 { - params["LoadBalancerId"] = strings.Join(ids, ",") - } - body, err := region.lbRequest("DescribeLoadBalancers", params) - if err != nil { - return nil, err - } - lbs := []SLoadbalancer{} - return lbs, body.Unmarshal(&lbs, "LoadBalancers", "LoadBalancer") -} - -func (region *SRegion) GetLoadbalancerDetail(loadbalancerId string) (*SLoadbalancer, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - body, err := region.lbRequest("DescribeLoadBalancerAttribute", params) - if err != nil { - return nil, err - } - lb := SLoadbalancer{region: region} - return &lb, body.Unmarshal(&lb) -} - -func (lb *SLoadbalancer) Delete(ctx context.Context) error { - params := map[string]string{} - params["RegionId"] = lb.region.RegionId - params["LoadBalancerId"] = lb.LoadBalancerId - _, err := lb.region.lbRequest("DeleteLoadBalancer", params) - return err -} - -func (lb *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - ibackendgroups := []cloudprovider.ICloudLoadbalancerBackendGroup{} - { - backendgroups, err := lb.region.GetLoadbalancerBackendgroups(lb.LoadBalancerId) - if err != nil { - return nil, err - } - - for i := 0; i < len(backendgroups); i++ { - backendgroups[i].lb = lb - ibackendgroups = append(ibackendgroups, &backendgroups[i]) - } - } - { - iDefaultBackendgroup := SLoadbalancerDefaultBackendGroup{lb: lb} - ibackendgroups = append(ibackendgroups, &iDefaultBackendgroup) - - } - { - backendgroups, err := lb.region.GetLoadbalancerMasterSlaveBackendgroups(lb.LoadBalancerId) - if err != nil { - return nil, err - } - for i := 0; i < len(backendgroups); i++ { - backendgroups[i].lb = lb - ibackendgroups = append(ibackendgroups, &backendgroups[i]) - } - } - return ibackendgroups, nil -} - -func (lb *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - switch group.GroupType { - case api.LB_BACKENDGROUP_TYPE_NORMAL: - group, err := lb.region.CreateLoadbalancerBackendGroup(group.Name, lb.LoadBalancerId, group.Backends) - if err != nil { - return nil, err - } - group.lb = lb - return group, nil - case api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE: - group, err := lb.region.CreateLoadbalancerMasterSlaveBackendGroup(group.Name, lb.LoadBalancerId, group.Backends) - if err != nil { - return nil, err - } - group.lb = lb - return group, nil - default: - return nil, fmt.Errorf("Unsupport backendgroup type %s", group.GroupType) - } -} - -func (lb *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - switch listener.ListenerType { - case api.LB_LISTENER_TYPE_TCP: - return lb.region.CreateLoadbalancerTCPListener(lb, listener) - case api.LB_LISTENER_TYPE_UDP: - return lb.region.CreateLoadbalancerUDPListener(lb, listener) - case api.LB_LISTENER_TYPE_HTTP: - return lb.region.CreateLoadbalancerHTTPListener(lb, listener) - case api.LB_LISTENER_TYPE_HTTPS: - return lb.region.CreateLoadbalancerHTTPSListener(lb, listener) - } - return nil, fmt.Errorf("unsupport listener type %s", listener.ListenerType) -} - -func (lb *SLoadbalancer) GetLoadbalancerSpec() string { - if len(lb.LoadBalancerSpec) == 0 { - lb.Refresh() - } - return lb.LoadBalancerSpec -} - -func (lb *SLoadbalancer) GetChargeType() string { - chargeType := lb.InternetChargeType - if len(lb.InternetChargeTypeAlias) > 0 { - chargeType = lb.InternetChargeTypeAlias - } - switch chargeType { - case "paybybandwidth": - return api.LB_CHARGE_TYPE_BY_BANDWIDTH - case "paybytraffic": - return api.LB_CHARGE_TYPE_BY_TRAFFIC - default: - return string(chargeType) - } -} - -func (lb *SLoadbalancer) GetCreatedAt() time.Time { - return lb.CreateTime -} - -func (lb *SLoadbalancer) GetEgressMbps() int { - if lb.Bandwidth < 1 { - return 0 - } - return lb.Bandwidth -} - -func (lb *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - groups, err := lb.GetILoadBalancerBackendGroups() - if err != nil { - return nil, err - } - for i := 0; i < len(groups); i++ { - if groups[i].GetGlobalId() == groupId { - return groups[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (lb *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { - if lb.AddressType == "internet" { - eip := SEipAddress{ - region: lb.region, - IpAddress: lb.Address, - InstanceId: lb.GetGlobalId(), - InstanceType: EIP_INTANNCE_TYPE_SLB, - Status: EIP_STATUS_INUSE, - AllocationId: lb.GetGlobalId(), - AllocationTime: lb.CreateTime, - Bandwidth: lb.Bandwidth, - } - switch lb.GetChargeType() { - case api.LB_CHARGE_TYPE_BY_BANDWIDTH: - eip.InternetChargeType = InternetChargeByBandwidth - case api.LB_CHARGE_TYPE_BY_TRAFFIC: - eip.InternetChargeType = InternetChargeByTraffic - } - return &eip, nil - } - eips, total, err := lb.region.GetEips("", lb.LoadBalancerId, "", 0, 1) - if err != nil { - return nil, errors.Wrapf(err, "lb.region.GetEips(%s)", lb.LoadBalancerId) - } - if total != 1 { - return nil, cloudprovider.ErrNotFound - } - eips[0].region = lb.region - return &eips[0], nil -} - -func (region *SRegion) loadbalancerOperation(loadbalancerId, status string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["LoadBalancerStatus"] = status - _, err := region.lbRequest("SetLoadBalancerStatus", params) - return err -} - -func (lb *SLoadbalancer) Start() error { - if lb.LoadBalancerStatus != "active" { - return lb.region.loadbalancerOperation(lb.LoadBalancerId, "active") - } - return nil -} - -func (lb *SLoadbalancer) Stop() error { - if lb.LoadBalancerStatus != "inactive" { - return lb.region.loadbalancerOperation(lb.LoadBalancerId, "inactive") - } - return nil -} - -func (lb *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { - listener, err := lb.GetILoadBalancerListeners() - if err != nil { - return nil, err - } - for i := 0; i < len(listener); i++ { - if listener[i].GetGlobalId() == listenerId { - return listener[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (lb *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId) - if err != nil { - return nil, err - } - listeners := []cloudprovider.ICloudLoadbalancerListener{} - for _, listenerInfo := range loadbalancer.ListenerPortsAndProtocol.ListenerPortAndProtocol { - switch listenerInfo.ListenerProtocol { - case ListenerProtocolHTTP: - listener, err := lb.region.GetLoadbalancerHTTPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) - if err != nil { - return nil, err - } - listener.lb = lb - listeners = append(listeners, listener) - case ListenerProtocolHTTPS: - listener, err := lb.region.GetLoadbalancerHTTPSListener(lb.LoadBalancerId, listenerInfo.ListenerPort) - if err != nil { - return nil, err - } - listener.lb = lb - listeners = append(listeners, listener) - case ListenerProtocolTCP: - listener, err := lb.region.GetLoadbalancerTCPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) - if err != nil { - return nil, err - } - listener.lb = lb - listeners = append(listeners, listener) - case ListenerProtocolUDP: - listener, err := lb.region.GetLoadbalancerUDPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) - if err != nil { - return nil, err - } - listener.lb = lb - listeners = append(listeners, listener) - default: - return nil, fmt.Errorf("failed to recognize %s type listener", listenerInfo.ListenerProtocol) - } - } - return listeners, nil -} - -func (lb *SLoadbalancer) GetProjectId() string { - return lb.ResourceGroupId -} - -func (lb *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { - return lb.region.SetResourceTags(ALIYUN_SERVICE_SLB, "instance", lb.LoadBalancerId, tags, replace) -} - -// mapping aliyun finance zoneId to aliyun finance ecs zoneId -func transZoneIdToEcsZoneId(region *SRegion, service, zoneId string) string { - if region.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV { - switch service { - case "elb", "redis": - if utils.IsInStringArray(zoneId, []string{"cn-hangzhou-finance-b", "cn-hangzhou-finance-c", "cn-hangzhou-finance-d"}) { - return strings.Replace(zoneId, "-finance", "", -1) - } - default: - return zoneId - } - } - - return zoneId -} - -// mapping aliyun finance ecs zoneId to dest service zone id -func transZoneIdFromEcsZoneId(region *SRegion, service, zoneId string) string { - if region.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV { - switch service { - case "elb", "redis": - if utils.IsInStringArray(zoneId, []string{"cn-hangzhou-b", "cn-hangzhou-c", "cn-hangzhou-d"}) { - return strings.Replace(zoneId, "cn-hangzhou", "cn-hangzhou-finance", -1) - } - default: - return zoneId - } - } - - return zoneId -} - -// mapping aliyun finance regionId to aliyun finance ecs regionId -func transRegionIdToEcsRegionId(region *SRegion, service string) string { - if region.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV { - switch service { - case "redis": - if region.GetId() == "cn-hangzhou-finance" { - return "cn-hangzhou" - } - default: - return region.GetId() - } - } - - return region.GetId() -} - -// mapping aliyun finance regionId from aliyun finance ecs regionId -func transRegionIdFromEcsRegionId(region *SRegion, service string) string { - if region.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV { - switch service { - case "redis": - if region.GetId() == "cn-hangzhou" { - return "cn-hangzhou-finance" - } - default: - return region.GetId() - } - } - - return region.GetId() -} - -func fetchMasterZoneId(zoneId string) string { - // cn-shenzhen-finance-1MAZ2(d,e) - i := strings.Index(zoneId, "MAZ") - if i > 0 { - s := strings.Index(zoneId, "(") - e := strings.Index(zoneId, ",") - if s >= 0 && e >= 0 { - return zoneId[0:i] + zoneId[s+1:e] - } - } - - return zoneId -} diff --git a/pkg/multicloud/aliyun/loadbalanceracl.go b/pkg/multicloud/aliyun/loadbalanceracl.go deleted file mode 100644 index 9b1a180cb4..0000000000 --- a/pkg/multicloud/aliyun/loadbalanceracl.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type AclEntrys struct { - AclEntry []AclEntry -} - -type AclEntry struct { - AclEntryComment string - AclEntryIP string -} - -type SLoadbalancerAcl struct { - multicloud.SResourceBase - multicloud.AliyunTags - region *SRegion - - AclId string - AclName string - - AclEntrys AclEntrys -} - -func (acl *SLoadbalancerAcl) GetAclListenerID() string { - return "" -} - -func (acl *SLoadbalancerAcl) GetName() string { - return acl.AclName -} - -func (acl *SLoadbalancerAcl) GetId() string { - return acl.AclId -} - -func (acl *SLoadbalancerAcl) GetGlobalId() string { - return acl.AclId -} - -func (acl *SLoadbalancerAcl) GetStatus() string { - return "" -} - -func (acl *SLoadbalancerAcl) IsEmulated() bool { - return false -} - -func (acl *SLoadbalancerAcl) Refresh() error { - loadbalancerAcl, err := acl.region.GetLoadbalancerAclDetail(acl.AclId) - if err != nil { - return err - } - return jsonutils.Update(acl, loadbalancerAcl) -} - -func (acl *SLoadbalancerAcl) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { - detail, err := acl.region.GetLoadbalancerAclDetail(acl.AclId) - if err != nil { - log.Errorf("GetLoadbalancerAclDetail %s failed: %v", acl.AclId, err) - return nil - } - entrys := []cloudprovider.SLoadbalancerAccessControlListEntry{} - for _, entry := range detail.AclEntrys.AclEntry { - entrys = append(entrys, cloudprovider.SLoadbalancerAccessControlListEntry{CIDR: entry.AclEntryIP, Comment: entry.AclEntryComment}) - } - return entrys -} - -func (region *SRegion) UpdateAclName(aclId, name string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["AclId"] = aclId - params["AclName"] = name - _, err := region.lbRequest("SetAccessControlListAttribute", params) - return err -} - -func (region *SRegion) RemoveAccessControlListEntry(aclId string, data jsonutils.JSONObject) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["AclId"] = aclId - params["AclEntrys"] = data.String() - _, err := region.lbRequest("RemoveAccessControlListEntry", params) - return err -} - -func (acl *SLoadbalancerAcl) Delete() error { - params := map[string]string{} - params["RegionId"] = acl.region.RegionId - params["AclId"] = acl.AclId - _, err := acl.region.lbRequest("DeleteAccessControlList", params) - return err -} - -func (region *SRegion) GetLoadbalancerAclDetail(aclId string) (*SLoadbalancerAcl, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["AclId"] = aclId - body, err := region.lbRequest("DescribeAccessControlListAttribute", params) - if err != nil { - return nil, err - } - detail := SLoadbalancerAcl{region: region} - return &detail, body.Unmarshal(&detail) -} - -func (region *SRegion) GetLoadBalancerAcls() ([]SLoadbalancerAcl, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - body, err := region.lbRequest("DescribeAccessControlLists", params) - if err != nil { - return nil, err - } - acls := []SLoadbalancerAcl{} - return acls, body.Unmarshal(&acls, "Acls", "Acl") -} - -func (acl *SLoadbalancerAcl) Sync(_acl *cloudprovider.SLoadbalancerAccessControlList) error { - if acl.AclName != _acl.Name { - if err := acl.region.UpdateAclName(acl.AclId, _acl.Name); err != nil { - return err - } - } - entrys := jsonutils.NewArray() - for _, entry := range acl.AclEntrys.AclEntry { - entrys.Add(jsonutils.Marshal(map[string]string{"entry": entry.AclEntryIP, "comment": entry.AclEntryComment})) - } - if entrys.Length() > 0 { - if err := acl.region.RemoveAccessControlListEntry(acl.AclId, entrys); err != nil && !isError(err, "Acl does not have any entry") { - return err - } - } - if len(_acl.Entrys) > 0 { - return acl.region.AddAccessControlListEntry(acl.AclId, _acl.Entrys) - } - return nil -} - -func (acl *SLoadbalancerAcl) GetProjectId() string { - return "" -} diff --git a/pkg/multicloud/aliyun/loadbalancerbackend.go b/pkg/multicloud/aliyun/loadbalancerbackend.go deleted file mode 100644 index ebcc40f59c..0000000000 --- a/pkg/multicloud/aliyun/loadbalancerbackend.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerBackend struct { - multicloud.SResourceBase - multicloud.AliyunTags - lbbg *SLoadbalancerBackendGroup - - ServerId string - Port int - Weight int -} - -func (backend *SLoadbalancerBackend) GetName() string { - return backend.ServerId -} - -func (backend *SLoadbalancerBackend) GetId() string { - return fmt.Sprintf("%s/%s", backend.lbbg.VServerGroupId, backend.ServerId) -} - -func (backend *SLoadbalancerBackend) GetGlobalId() string { - return backend.GetId() -} - -func (backend *SLoadbalancerBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backend *SLoadbalancerBackend) IsEmulated() bool { - return false -} - -func (backend *SLoadbalancerBackend) Refresh() error { - loadbalancerBackends, err := backend.lbbg.lb.region.GetLoadbalancerBackends(backend.lbbg.VServerGroupId) - if err != nil { - return err - } - for _, loadbalancerBackend := range loadbalancerBackends { - if loadbalancerBackend.ServerId == backend.ServerId { - return jsonutils.Update(backend, loadbalancerBackend) - } - } - return cloudprovider.ErrNotFound -} - -func (backend *SLoadbalancerBackend) GetWeight() int { - return backend.Weight -} - -func (backend *SLoadbalancerBackend) GetPort() int { - return backend.Port -} - -func (backend *SLoadbalancerBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (backend *SLoadbalancerBackend) GetBackendRole() string { - return api.LB_BACKEND_ROLE_DEFAULT -} - -func (backend *SLoadbalancerBackend) GetBackendId() string { - return backend.ServerId -} - -func (backend *SLoadbalancerBackend) GetIpAddress() string { - return "" -} - -func (region *SRegion) GetLoadbalancerBackends(backendgroupId string) ([]SLoadbalancerBackend, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["VServerGroupId"] = backendgroupId - body, err := region.lbRequest("DescribeVServerGroupAttribute", params) - if err != nil { - return nil, err - } - backends := []SLoadbalancerBackend{} - return backends, body.Unmarshal(&backends, "BackendServers", "BackendServer") -} - -func (backend *SLoadbalancerBackend) GetProjectId() string { - return backend.lbbg.GetProjectId() -} - -func (backend *SLoadbalancerBackend) SyncConf(ctx context.Context, port, weight int) error { - err := backend.lbbg.lb.region.RemoveBackendVServer(backend.lbbg.lb.LoadBalancerId, backend.lbbg.VServerGroupId, backend.ServerId, backend.Port) - if err != nil { - return err - } - return backend.lbbg.lb.region.AddBackendVServer(backend.lbbg.lb.LoadBalancerId, backend.lbbg.VServerGroupId, backend.ServerId, weight, port) -} diff --git a/pkg/multicloud/aliyun/loadbalancerbackendgroup.go b/pkg/multicloud/aliyun/loadbalancerbackendgroup.go deleted file mode 100644 index c95dbb0ec2..0000000000 --- a/pkg/multicloud/aliyun/loadbalancerbackendgroup.go +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type Rule struct { - RuleId string - RuleName string - Domain string - Url string -} - -type Rules struct { - Rule []Rule -} - -type Listener struct { - Protocol string - Port int -} - -type Listeners struct { - Listener []Listener -} - -type AssociatedObjects struct { - Rules Rules - Listeners Listeners -} - -type SLoadbalancerBackendGroup struct { - multicloud.SResourceBase - multicloud.AliyunTags - lb *SLoadbalancer - - VServerGroupId string - VServerGroupName string - AssociatedObjects AssociatedObjects -} - -func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { - return backendgroup.lb -} - -func (backendgroup *SLoadbalancerBackendGroup) GetLoadbalancerId() string { - return backendgroup.lb.GetId() -} - -func (backendgroup *SLoadbalancerBackendGroup) GetProtocolType() string { - return "" -} - -func (backendgroup *SLoadbalancerBackendGroup) GetScheduler() string { - return "" -} - -func (backendgroup *SLoadbalancerBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerBackendGroup) GetName() string { - return backendgroup.VServerGroupName -} - -func (backendgroup *SLoadbalancerBackendGroup) GetId() string { - return backendgroup.VServerGroupId -} - -func (backendgroup *SLoadbalancerBackendGroup) GetGlobalId() string { - return backendgroup.VServerGroupId -} - -func (backendgroup *SLoadbalancerBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backendgroup *SLoadbalancerBackendGroup) IsDefault() bool { - return false -} - -func (backendgroup *SLoadbalancerBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_NORMAL -} - -func (backendgroup *SLoadbalancerBackendGroup) IsEmulated() bool { - return false -} - -func (backendgroup *SLoadbalancerBackendGroup) Refresh() error { - loadbalancerBackendgroups, err := backendgroup.lb.region.GetLoadbalancerBackendgroups(backendgroup.lb.LoadBalancerId) - if err != nil { - return err - } - for _, loadbalancerBackendgroup := range loadbalancerBackendgroups { - if loadbalancerBackendgroup.VServerGroupId == backendgroup.VServerGroupId { - return jsonutils.Update(backendgroup, loadbalancerBackendgroup) - } - } - return cloudprovider.ErrNotFound -} - -func (region *SRegion) GetLoadbalancerBackendgroups(loadbalancerId string) ([]SLoadbalancerBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - body, err := region.lbRequest("DescribeVServerGroups", params) - if err != nil { - return nil, err - } - backendgroups := []SLoadbalancerBackendGroup{} - return backendgroups, body.Unmarshal(&backendgroups, "VServerGroups", "VServerGroup") -} - -func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := backendgroup.lb.region.GetLoadbalancerBackends(backendgroup.VServerGroupId) - if err != nil { - return nil, err - } - ibackends := []cloudprovider.ICloudLoadbalancerBackend{} - for i := 0; i < len(backends); i++ { - backends[i].lbbg = backendgroup - ibackends = append(ibackends, &backends[i]) - } - return ibackends, nil -} - -func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := backendgroup.GetILoadbalancerBackends() - if err != nil { - return nil, err - } - for i := 0; i < len(backends); i++ { - if backends[i].GetGlobalId() == backendId { - return backends[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) CreateLoadbalancerBackendGroup(name, loadbalancerId string, backends []cloudprovider.SLoadbalancerBackend) (*SLoadbalancerBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["VServerGroupName"] = name - params["LoadBalancerId"] = loadbalancerId - if len(backends) > 0 { - servers := jsonutils.NewArray() - for _, backend := range backends { - servers.Add( - jsonutils.Marshal( - map[string]string{ - "ServerId": backend.ExternalID, - "Port": fmt.Sprintf("%d", backend.Port), - "Weight": fmt.Sprintf("%d", backend.Weight), - }, - )) - } - params["BackendServers"] = servers.String() - } - body, err := region.lbRequest("CreateVServerGroup", params) - if err != nil { - return nil, err - } - groupId, err := body.GetString("VServerGroupId") - if err != nil { - return nil, err - } - return region.GetLoadbalancerBackendgroupById(groupId) -} - -func (region *SRegion) GetLoadbalancerBackendgroupById(groupId string) (*SLoadbalancerBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["VServerGroupId"] = groupId - body, err := region.lbRequest("DescribeVServerGroupAttribute", params) - if err != nil { - return nil, err - } - group := &SLoadbalancerBackendGroup{} - return group, body.Unmarshal(group) -} - -func (region *SRegion) UpdateLoadBalancerBackendGroupName(name, groupId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["VServerGroupId"] = groupId - params["VServerGroupName"] = name - _, err := region.lbRequest("SetVServerGroupAttribute", params) - return err -} - -func (backendgroup *SLoadbalancerBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - if group == nil { - return nil - } - - if backendgroup.VServerGroupName != group.Name { - return backendgroup.lb.region.UpdateLoadBalancerBackendGroupName(backendgroup.VServerGroupId, group.Name) - } - return nil -} - -func (region *SRegion) DeleteLoadBalancerBackendGroup(groupId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["VServerGroupId"] = groupId - _, err := region.lbRequest("DeleteVServerGroup", params) - return err -} - -func (backendgroup *SLoadbalancerBackendGroup) Delete(ctx context.Context) error { - return backendgroup.lb.region.DeleteLoadBalancerBackendGroup(backendgroup.VServerGroupId) -} - -func (region *SRegion) AddBackendVServer(loadbalancerId, backendGroupId, serverId string, weight, port int) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["VServerGroupId"] = backendGroupId - servers := jsonutils.NewArray() - servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Weight": fmt.Sprintf("%d", weight), "Port": fmt.Sprintf("%d", port)})) - params["BackendServers"] = servers.String() - _, err := region.lbRequest("AddVServerGroupBackendServers", params) - return err -} - -func (region *SRegion) RemoveBackendVServer(loadbalancerId, backendgroupId, serverId string, port int) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["VServerGroupId"] = backendgroupId - servers := jsonutils.NewArray() - servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Port": fmt.Sprintf("%d", port)})) - params["BackendServers"] = servers.String() - _, err := region.lbRequest("RemoveVServerGroupBackendServers", params) - return err -} - -func (backendgroup *SLoadbalancerBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - if err := backendgroup.lb.region.AddBackendVServer(backendgroup.lb.LoadBalancerId, backendgroup.VServerGroupId, serverId, weight, port); err != nil { - return nil, err - } - return &SLoadbalancerBackend{lbbg: backendgroup, ServerId: serverId, Weight: weight, Port: port}, nil -} - -func (backendgroup *SLoadbalancerBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { - return backendgroup.lb.region.RemoveBackendVServer(backendgroup.lb.LoadBalancerId, backendgroup.VServerGroupId, serverId, port) -} - -func (backendgroup *SLoadbalancerBackendGroup) GetProjectId() string { - return backendgroup.lb.GetProjectId() -} diff --git a/pkg/multicloud/aliyun/loadbalancerdefaultbackend.go b/pkg/multicloud/aliyun/loadbalancerdefaultbackend.go deleted file mode 100644 index ff62fcfd96..0000000000 --- a/pkg/multicloud/aliyun/loadbalancerdefaultbackend.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerDefaultBackend struct { - multicloud.SResourceBase - multicloud.AliyunTags - lbbg *SLoadbalancerDefaultBackendGroup - - ServerId string - Weight int -} - -func (backend *SLoadbalancerDefaultBackend) GetName() string { - return backend.ServerId -} - -func (backend *SLoadbalancerDefaultBackend) GetId() string { - return fmt.Sprintf("%s/%s", backend.lbbg.lb.LoadBalancerId, backend.ServerId) -} - -func (backend *SLoadbalancerDefaultBackend) GetGlobalId() string { - return backend.GetId() -} - -func (backend *SLoadbalancerDefaultBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backend *SLoadbalancerDefaultBackend) IsEmulated() bool { - return false -} - -func (backend *SLoadbalancerDefaultBackend) Refresh() error { - return nil -} - -func (backend *SLoadbalancerDefaultBackend) GetWeight() int { - return backend.Weight -} - -func (backend *SLoadbalancerDefaultBackend) GetPort() int { - return 0 -} - -func (backend *SLoadbalancerDefaultBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (backend *SLoadbalancerDefaultBackend) GetBackendRole() string { - return api.LB_BACKEND_ROLE_DEFAULT -} - -func (backend *SLoadbalancerDefaultBackend) GetBackendId() string { - return backend.ServerId -} - -func (backend *SLoadbalancerDefaultBackend) GetIpAddress() string { - return "" -} - -func (backend *SLoadbalancerDefaultBackend) GetProjectId() string { - return backend.lbbg.GetProjectId() -} - -func (backend *SLoadbalancerDefaultBackend) SyncConf(ctx context.Context, port, weight int) error { - params := map[string]string{} - params["RegionId"] = backend.lbbg.lb.region.RegionId - params["LoadBalancerId"] = backend.lbbg.lb.LoadBalancerId - loadbalancer, err := backend.lbbg.lb.region.GetLoadbalancerDetail(backend.lbbg.lb.LoadBalancerId) - if err != nil { - return err - } - servers := jsonutils.NewArray() - for i := 0; i < len(loadbalancer.BackendServers.BackendServer); i++ { - _backend := loadbalancer.BackendServers.BackendServer[i] - _backend.lbbg = backend.lbbg - if _backend.GetGlobalId() == backend.GetGlobalId() { - _backend.Weight = weight - } - servers.Add( - jsonutils.Marshal( - map[string]string{ - "ServerId": _backend.ServerId, - "Weight": fmt.Sprintf("%d", _backend.Weight), - }, - )) - } - - params["BackendServers"] = servers.String() - _, err = backend.lbbg.lb.region.lbRequest("SetBackendServers", params) - return err -} diff --git a/pkg/multicloud/aliyun/loadbalancerdefaultbackendgroup.go b/pkg/multicloud/aliyun/loadbalancerdefaultbackendgroup.go deleted file mode 100644 index aee6318435..0000000000 --- a/pkg/multicloud/aliyun/loadbalancerdefaultbackendgroup.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerDefaultBackendGroup struct { - multicloud.SResourceBase - multicloud.AliyunTags - lb *SLoadbalancer -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { - return backendgroup.lb -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetLoadbalancerId() string { - return backendgroup.lb.GetId() -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetProtocolType() string { - return "" -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetScheduler() string { - return "" -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetName() string { - return fmt.Sprintf("%s(%s)-default", backendgroup.lb.LoadBalancerName, backendgroup.lb.Address) -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetId() string { - return fmt.Sprintf("%s/default", backendgroup.lb.LoadBalancerId) -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetGlobalId() string { - return backendgroup.GetId() -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) IsDefault() bool { - return true -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_DEFAULT -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) IsEmulated() bool { - return false -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) Refresh() error { - return nil -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - loadbalancer, err := backendgroup.lb.region.GetLoadbalancerDetail(backendgroup.lb.LoadBalancerId) - if err != nil { - return nil, err - } - ibackends := []cloudprovider.ICloudLoadbalancerBackend{} - for i := 0; i < len(loadbalancer.BackendServers.BackendServer); i++ { - loadbalancer.BackendServers.BackendServer[i].lbbg = backendgroup - ibackends = append(ibackends, &loadbalancer.BackendServers.BackendServer[i]) - } - return ibackends, nil -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := backendgroup.GetILoadbalancerBackends() - if err != nil { - return nil, err - } - for i := 0; i < len(backends); i++ { - if backends[i].GetGlobalId() == backendId { - return backends[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - return cloudprovider.ErrNotSupported -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) Delete(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (region *SRegion) AddBackendServer(loadbalancerId, serverId string, weight, port int) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - servers := jsonutils.NewArray() - servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Weight": fmt.Sprintf("%d", weight)})) - params["BackendServers"] = servers.String() - _, err := region.lbRequest("AddBackendServers", params) - return err -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - if err := backendgroup.lb.region.AddBackendServer(backendgroup.lb.LoadBalancerId, serverId, weight, port); err != nil { - return nil, err - } - return &SLoadbalancerDefaultBackend{lbbg: backendgroup, ServerId: serverId, Weight: weight}, nil -} - -func (region *SRegion) RemoveBackendServer(loadbalancerId, serverId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - servers := jsonutils.NewArray() - servers.Add(jsonutils.NewString(serverId)) - params["BackendServers"] = servers.String() - _, err := region.lbRequest("RemoveBackendServers", params) - return err -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { - return backendgroup.lb.region.RemoveBackendServer(backendgroup.lb.LoadBalancerId, serverId) -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetProjectId() string { - return backendgroup.lb.GetProjectId() -} diff --git a/pkg/multicloud/aliyun/loadbalancerhttplistener.go b/pkg/multicloud/aliyun/loadbalancerhttplistener.go deleted file mode 100644 index 4af50ded42..0000000000 --- a/pkg/multicloud/aliyun/loadbalancerhttplistener.go +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerHTTPListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.AliyunTags - lb *SLoadbalancer - - ListenerPort int // 负载均衡实例前端使用的端口。 - BackendServerPort int // 负载均衡实例后端使用的端口。 - Bandwidth int // 监听的带宽峰值。 - Status string // 当前监听的状态。取值:starting | running | configuring | stopping | stopped - Description string - - XForwardedFor string // 是否开启通过X-Forwarded-For头字段获取访者真实IP。 - XForwardedFor_SLBIP string // 是否通过SLB-IP头字段获取客户端请求的真实IP。 - XForwardedFor_SLBID string // 是否通过SLB-ID头字段获取负载均衡实例ID。 - XForwardedFor_proto string // 是否通过X-Forwarded-Proto头字段获取负载均衡实例的监听协议。 - Scheduler string // 调度算法。 - StickySession string // 是否开启会话保持。 - StickySessionType string // cookie的处理方式。 - CookieTimeout int // Cookie超时时间。 - Cookie string // 服务器上配置的cookie。 - AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) - - AclType string // 访问控制类型: - //white: 仅转发来自所选访问控制策略组中设置的IP地址或地址段的请求,白名单适用于应用只允许特定IP访问的场景。 - //设置白名单存在一定业务风险。一旦设置白名单,就只有白名单中的IP可以访问负载均衡监听。如果开启了白名单访问,但访问策略组中没有添加任何IP,则负载均衡监听会转发全部请求。 - - //black: 来自所选访问控制策略组中设置的IP地址或地址段的所有请求都不会转发,黑名单适用于应用只限制某些特定IP访问的场景。 - //如果开启了黑名单访问,但访问策略组中没有添加任何IP,则负载均衡监听会转发全部请求。 - - //当AclStatus参数的值为on时,该参数必选。 - - AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 - - HealthCheck string // 是否开启健康检查。 - HealthCheckDomain string // 用于健康检查的域名。 - HealthCheckURI string // 用于健康检查的URI。 - HealthyThreshold int // 健康检查阈值。 - UnhealthyThreshold int // 不健康检查阈值。 - HealthCheckTimeout int // 每次健康检查响应的最大超时间,单位为秒。 - HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 - HealthCheckHttpCode string // 健康检查正常的HTTP状态码。 - HealthCheckConnectPort int // 健康检查的端口。 - Gzip string // 是否开启Gzip压缩。 - EnableHttp2 string // 是否开启HTTP/2特性。取值:on(默认值)|off - - Rules Rules //监听下的转发规则列表,具体请参见RuleList。 - ForwardPort int // HTTP至HTTPS的监听转发端口。暂时只支持将HTTP 80访问重定向转发至HTTPS 443。 说明 如果 ListenerForward的值为 off,该参数不显示。 - ListenerForward string // 表示是否开启HTTP至HTTPS的监听转发。on:表示开启 off:表示未开启 - VServerGroupId string // 绑定的服务器组ID -} - -func (listener *SLoadbalancerHTTPListener) GetName() string { - if len(listener.Description) == 0 { - listener.Refresh() - } - if len(listener.Description) > 0 { - return listener.Description - } - return fmt.Sprintf("HTTP:%d", listener.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPListener) GetId() string { - return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPListener) GetGlobalId() string { - return listerner.GetId() -} - -func (listerner *SLoadbalancerHTTPListener) GetStatus() string { - switch listerner.Status { - case "starting", "running": - return api.LB_STATUS_ENABLED - case "configuring", "stopping", "stopped": - return api.LB_STATUS_DISABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (listerner *SLoadbalancerHTTPListener) IsEmulated() bool { - return false -} - -func (listerner *SLoadbalancerHTTPListener) GetEgressMbps() int { - if listerner.Bandwidth < 1 { - return 0 - } - return listerner.Bandwidth -} - -func (listerner *SLoadbalancerHTTPListener) Refresh() error { - lis, err := listerner.lb.region.GetLoadbalancerHTTPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return err - } - return jsonutils.Update(listerner, lis) -} - -func (listerner *SLoadbalancerHTTPListener) GetListenerType() string { - return "http" -} - -func (listerner *SLoadbalancerHTTPListener) GetListenerPort() int { - return listerner.ListenerPort -} - -func (listerner *SLoadbalancerHTTPListener) GetBackendGroupId() string { - if len(listerner.VServerGroupId) == 0 { - listerner.Refresh() - } - return listerner.VServerGroupId -} - -func (listerner *SLoadbalancerHTTPListener) GetBackendServerPort() int { - return listerner.BackendServerPort -} - -func (listerner *SLoadbalancerHTTPListener) GetScheduler() string { - return listerner.Scheduler -} - -func (listerner *SLoadbalancerHTTPListener) GetAclStatus() string { - return listerner.AclStatus -} - -func (listerner *SLoadbalancerHTTPListener) GetAclType() string { - return listerner.AclType -} - -func (listerner *SLoadbalancerHTTPListener) GetAclId() string { - return listerner.AclId -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheck() string { - return listerner.HealthCheck -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckType() string { - return api.LB_HEALTH_CHECK_HTTP -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckDomain() string { - return listerner.HealthCheckDomain -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckURI() string { - return listerner.HealthCheckURI -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckCode() string { - return listerner.HealthCheckHttpCode -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckRise() int { - return listerner.HealthyThreshold -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckFail() int { - return listerner.UnhealthyThreshold -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckTimeout() int { - return listerner.HealthCheckTimeout -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckInterval() int { - return listerner.HealthCheckInterval -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckReq() string { - return "" -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckExp() string { - return "" -} - -func (listerner *SLoadbalancerHTTPListener) GetStickySession() string { - return listerner.StickySession -} - -func (listerner *SLoadbalancerHTTPListener) GetStickySessionType() string { - return listerner.StickySessionType -} - -func (listerner *SLoadbalancerHTTPListener) GetStickySessionCookie() string { - return listerner.Cookie -} - -func (listerner *SLoadbalancerHTTPListener) GetStickySessionCookieTimeout() int { - return listerner.CookieTimeout -} - -func (listerner *SLoadbalancerHTTPListener) XForwardedForEnabled() bool { - if listerner.XForwardedFor == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPListener) GzipEnabled() bool { - if listerner.Gzip == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPListener) GetCertificateId() string { - return "" -} - -func (listerner *SLoadbalancerHTTPListener) GetTLSCipherPolicy() string { - return "" -} - -func (listerner *SLoadbalancerHTTPListener) HTTP2Enabled() bool { - if listerner.EnableHttp2 == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - rules, err := listerner.lb.region.GetLoadbalancerListenerRules(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return nil, err - } - iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} - for i := 0; i < len(rules); i++ { - rules[i].httpListener = listerner - iRules = append(iRules, &rules[i]) - } - return iRules, nil -} - -func (region *SRegion) GetLoadbalancerHTTPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerHTTPListener, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - body, err := region.lbRequest("DescribeLoadBalancerHTTPListenerAttribute", params) - if err != nil { - return nil, err - } - listener := SLoadbalancerHTTPListener{} - return &listener, body.Unmarshal(&listener) -} - -func (region *SRegion) DeleteLoadbalancerListener(loadbalancerId string, listenerPort int) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - _, err := region.lbRequest("DeleteLoadBalancerListener", params) - return err -} - -func (region *SRegion) CreateLoadbalancerHTTPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - params := region.constructBaseCreateListenerParams(lb, listener) - params = region.constructHTTPCreateListenerParams(params, listener) - _, err := region.lbRequest("CreateLoadBalancerHTTPListener", params) - if err != nil { - return nil, err - } - iListener, err := region.GetLoadbalancerHTTPListener(lb.LoadBalancerId, listener.ListenerPort) - if err != nil { - return nil, err - } - iListener.lb = lb - return iListener, nil -} - -func (listerner *SLoadbalancerHTTPListener) Delete(ctx context.Context) error { - return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - _rule := &SLoadbalancerListenerRule{ - Domain: rule.Domain, - Url: rule.Path, - RuleName: rule.Name, - } - if len(rule.BackendGroupID) > 0 { //&& rule.BackendGroupType == api.LB_BACKENDGROUP_TYPE_NORMAL { - _rule.VServerGroupId = rule.BackendGroupID - } - listenerRule, err := listerner.lb.region.CreateLoadbalancerListenerRule(listerner.ListenerPort, listerner.lb.LoadBalancerId, _rule) - if err != nil { - return nil, err - } - listenerRule.httpListener = listerner - return listenerRule, nil -} - -func (listerner *SLoadbalancerHTTPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - rule, err := listerner.lb.region.GetLoadbalancerListenerRule(ruleId) - if err != nil { - return nil, err - } - rule.httpListener = listerner - return rule, nil -} - -func (region *SRegion) startListener(listenerPort int, loadbalancerId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - _, err := region.lbRequest("StartLoadBalancerListener", params) - return err -} - -func (region *SRegion) stopListener(listenerPort int, loadbalancerId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - _, err := region.lbRequest("StopLoadBalancerListener", params) - return err -} - -func (listerner *SLoadbalancerHTTPListener) Start() error { - return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (listerner *SLoadbalancerHTTPListener) Stop() error { - return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (region *SRegion) SyncLoadbalancerHTTPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { - params := region.constructBaseCreateListenerParams(lb, listener) - params = region.constructHTTPCreateListenerParams(params, listener) - _, err := region.lbRequest("SetLoadBalancerHTTPListenerAttribute", params) - return err -} - -func (listerner *SLoadbalancerHTTPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { - return listerner.lb.region.SyncLoadbalancerHTTPListener(listerner.lb, lblis) -} - -func (listerner *SLoadbalancerHTTPListener) GetProjectId() string { - return listerner.lb.GetProjectId() -} - -func (listerner *SLoadbalancerHTTPListener) GetClientIdleTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerHTTPListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/aliyun/loadbalancerhttpslistener.go b/pkg/multicloud/aliyun/loadbalancerhttpslistener.go deleted file mode 100644 index 154dcaf184..0000000000 --- a/pkg/multicloud/aliyun/loadbalancerhttpslistener.go +++ /dev/null @@ -1,409 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerHTTPSListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.AliyunTags - lb *SLoadbalancer - - ListenerPort int // 负载均衡实例前端使用的端口。 - BackendServerPort int // 负载均衡实例后端使用的端口。 - Bandwidth int // 监听的带宽峰值。 - Status string // 当前监听的状态。取值:starting | running | configuring | stopping | stopped - Description string - - XForwardedFor string // 是否开启通过X-Forwarded-For头字段获取访者真实IP。 - XForwardedFor_SLBIP string // 是否通过SLB-IP头字段获取客户端请求的真实IP。 - XForwardedFor_SLBID string // 是否通过SLB-ID头字段获取负载均衡实例ID。 - XForwardedFor_proto string // 是否通过X-Forwarded-Proto头字段获取负载均衡实例的监听协议。 - Scheduler string // 调度算法。 - StickySession string // 是否开启会话保持。 - StickySessionType string // cookie的处理方式。 - CookieTimeout int // Cookie超时时间。 - Cookie string // 服务器上配置的cookie。 - AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) - - AclType string // 访问控制类型 - - AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 - - HealthCheck string // 是否开启健康检查。 - HealthCheckDomain string // 用于健康检查的域名。 - HealthCheckURI string // 用于健康检查的URI。 - HealthyThreshold int // 健康检查阈值。 - UnhealthyThreshold int // 不健康检查阈值。 - HealthCheckTimeout int // 每次健康检查响应的最大超时间,单位为秒。 - HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 - HealthCheckHttpCode string // 健康检查正常的HTTP状态码。 - HealthCheckConnectPort int // 健康检查的端口。 - VServerGroupId string // 绑定的服务器组ID。 - ServerCertificateId string // 服务器证书ID。 - CACertificateId string // CA证书ID。 - Gzip string // 是否开启Gzip压缩。 - Rules Rules //监听下的转发规则列表,具体请参见RuleList。 - DomainExtensions string // 域名扩展列表,具体请参见DomainExtensions。 - EnableHttp2 string // 是否开启HTTP/2特性。取值:on(默认值)|off - - TLSCipherPolicy string // -} - -func (listener *SLoadbalancerHTTPSListener) GetName() string { - if len(listener.Description) == 0 { - listener.Refresh() - } - if len(listener.Description) > 0 { - return listener.Description - } - return fmt.Sprintf("HTTPS:%d", listener.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPSListener) GetId() string { - return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPSListener) GetGlobalId() string { - return listerner.GetId() -} - -func (listerner *SLoadbalancerHTTPSListener) GetStatus() string { - switch listerner.Status { - case "starting", "running": - return api.LB_STATUS_ENABLED - case "configuring", "stopping", "stopped": - return api.LB_STATUS_DISABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (listerner *SLoadbalancerHTTPSListener) IsEmulated() bool { - return false -} - -func (listerner *SLoadbalancerHTTPSListener) GetEgressMbps() int { - if listerner.Bandwidth < 1 { - return 0 - } - return listerner.Bandwidth -} - -func (listerner *SLoadbalancerHTTPSListener) Refresh() error { - lis, err := listerner.lb.region.GetLoadbalancerHTTPSListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return err - } - return jsonutils.Update(listerner, lis) -} - -func (listerner *SLoadbalancerHTTPSListener) GetListenerType() string { - return "https" -} - -func (listerner *SLoadbalancerHTTPSListener) GetListenerPort() int { - return listerner.ListenerPort -} - -func (listerner *SLoadbalancerHTTPSListener) GetBackendGroupId() string { - if len(listerner.VServerGroupId) == 0 { - listerner.Refresh() - } - return listerner.VServerGroupId -} - -func (listerner *SLoadbalancerHTTPSListener) GetBackendServerPort() int { - return listerner.BackendServerPort -} - -func (listerner *SLoadbalancerHTTPSListener) GetScheduler() string { - return listerner.Scheduler -} - -func (listerner *SLoadbalancerHTTPSListener) GetAclStatus() string { - return listerner.AclStatus -} - -func (listerner *SLoadbalancerHTTPSListener) GetAclType() string { - return listerner.AclType -} - -func (listerner *SLoadbalancerHTTPSListener) GetAclId() string { - return listerner.AclId -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheck() string { - return listerner.HealthCheck -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckType() string { - return api.LB_HEALTH_CHECK_HTTP -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckDomain() string { - return listerner.HealthCheckDomain -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckURI() string { - return listerner.HealthCheckURI -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckCode() string { - return listerner.HealthCheckHttpCode -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckRise() int { - return listerner.HealthyThreshold -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckFail() int { - return listerner.UnhealthyThreshold -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckTimeout() int { - return listerner.HealthCheckTimeout -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckInterval() int { - return listerner.HealthCheckInterval -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckReq() string { - return "" -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckExp() string { - return "" -} - -func (listerner *SLoadbalancerHTTPSListener) GetStickySession() string { - return listerner.StickySession -} - -func (listerner *SLoadbalancerHTTPSListener) GetStickySessionType() string { - return listerner.StickySessionType -} - -func (listerner *SLoadbalancerHTTPSListener) GetStickySessionCookie() string { - return listerner.Cookie -} - -func (listerner *SLoadbalancerHTTPSListener) GetStickySessionCookieTimeout() int { - return listerner.CookieTimeout -} - -func (listerner *SLoadbalancerHTTPSListener) XForwardedForEnabled() bool { - if listerner.XForwardedFor == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPSListener) GzipEnabled() bool { - if listerner.Gzip == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPSListener) GetCertificateId() string { - return listerner.ServerCertificateId -} - -func (listerner *SLoadbalancerHTTPSListener) GetTLSCipherPolicy() string { - return listerner.TLSCipherPolicy -} - -func (listerner *SLoadbalancerHTTPSListener) HTTP2Enabled() bool { - if listerner.EnableHttp2 == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPSListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - rules, err := listerner.lb.region.GetLoadbalancerListenerRules(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return nil, err - } - iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} - for i := 0; i < len(rules); i++ { - rules[i].httpsListener = listerner - iRules = append(iRules, &rules[i]) - } - return iRules, nil -} - -func (region *SRegion) GetLoadbalancerHTTPSListener(loadbalancerId string, listenerPort int) (*SLoadbalancerHTTPSListener, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - body, err := region.lbRequest("DescribeLoadBalancerHTTPSListenerAttribute", params) - if err != nil { - return nil, err - } - listener := SLoadbalancerHTTPSListener{} - return &listener, body.Unmarshal(&listener) -} - -func (region *SRegion) constructHTTPCreateListenerParams(params map[string]string, listener *cloudprovider.SLoadbalancerListener) map[string]string { - params["HealthCheck"] = listener.HealthCheck - if listener.HealthCheck == "on" { - if len(listener.HealthCheckURI) == 0 { - params["HealthCheckURI"] = "/" - } - //The HealthCheckTimeout parameter is required. - if listener.HealthCheckTimeout < 1 || listener.HealthCheckTimeout > 300 { - listener.HealthCheckTimeout = 5 - } - params["HealthCheckTimeout"] = fmt.Sprintf("%d", listener.HealthCheckTimeout) - } - - if listener.ClientRequestTimeout < 1 || listener.ClientRequestTimeout > 180 { - listener.ClientRequestTimeout = 60 - } - params["RequestTimeout"] = fmt.Sprintf("%d", listener.ClientRequestTimeout) - - if listener.ClientIdleTimeout < 1 || listener.ClientIdleTimeout > 60 { - listener.ClientIdleTimeout = 15 - } - params["IdleTimeout"] = fmt.Sprintf("%d", listener.ClientIdleTimeout) - - params["StickySession"] = listener.StickySession - params["StickySessionType"] = listener.StickySessionType - params["Cookie"] = listener.StickySessionCookie - if listener.StickySessionCookieTimeout < 1 || listener.StickySessionCookieTimeout > 86400 { - listener.StickySessionCookieTimeout = 500 - } - params["CookieTimeout"] = fmt.Sprintf("%d", listener.StickySessionCookieTimeout) - //params["ForwardPort"] = fmt.Sprintf("%d", listener.ForwardPort) //暂不支持 - params["Gzip"] = "off" - if listener.Gzip { - params["Gzip"] = "on" - } - params["XForwardedFor"] = "off" - if listener.XForwardedFor { - params["XForwardedFor"] = "on" - } - return params -} - -func (region *SRegion) CreateLoadbalancerHTTPSListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - params := region.constructBaseCreateListenerParams(lb, listener) - params = region.constructHTTPCreateListenerParams(params, listener) - params["ServerCertificateId"] = listener.CertificateID - if listener.EnableHTTP2 { - params["EnableHttp2"] = "on" - } else { - params["EnableHttp2"] = "off" - } - - if len(listener.TLSCipherPolicy) > 0 { - params["TLSCipherPolicy"] = listener.TLSCipherPolicy - } - _, err := region.lbRequest("CreateLoadBalancerHTTPSListener", params) - if err != nil { - return nil, err - } - iListener, err := region.GetLoadbalancerHTTPSListener(lb.LoadBalancerId, listener.ListenerPort) - if err != nil { - return nil, err - } - iListener.lb = lb - return iListener, nil -} - -func (listerner *SLoadbalancerHTTPSListener) Delete(ctx context.Context) error { - return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPSListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - _rule := &SLoadbalancerListenerRule{ - Domain: rule.Domain, - Url: rule.Path, - RuleName: rule.Name, - } - if len(rule.BackendGroupID) > 0 { //&& rule.BackendGroupType == api.LB_BACKENDGROUP_TYPE_NORMAL { - _rule.VServerGroupId = rule.BackendGroupID - } - listenerRule, err := listerner.lb.region.CreateLoadbalancerListenerRule(listerner.ListenerPort, listerner.lb.LoadBalancerId, _rule) - if err != nil { - return nil, err - } - listenerRule.httpsListener = listerner - return listenerRule, nil -} - -func (listerner *SLoadbalancerHTTPSListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - rule, err := listerner.lb.region.GetLoadbalancerListenerRule(ruleId) - if err != nil { - return nil, err - } - rule.httpsListener = listerner - return rule, nil -} - -func (listerner *SLoadbalancerHTTPSListener) Start() error { - return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (listerner *SLoadbalancerHTTPSListener) Stop() error { - return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (region *SRegion) SyncLoadbalancerHTTPSListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { - params := region.constructBaseCreateListenerParams(lb, listener) - params = region.constructHTTPCreateListenerParams(params, listener) - params["ServerCertificateId"] = listener.CertificateID - if listener.EnableHTTP2 { - params["EnableHttp2"] = "on" - } else { - params["EnableHttp2"] = "off" - } - - if len(lb.LoadBalancerSpec) > 0 && len(listener.TLSCipherPolicy) > 0 { - params["TLSCipherPolicy"] = listener.TLSCipherPolicy - } - _, err := region.lbRequest("SetLoadBalancerHTTPSListenerAttribute", params) - return err -} - -func (listerner *SLoadbalancerHTTPSListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { - return listerner.lb.region.SyncLoadbalancerHTTPSListener(listerner.lb, lblis) -} - -func (listerner *SLoadbalancerHTTPSListener) GetProjectId() string { - return listerner.lb.GetProjectId() -} - -func (listerner *SLoadbalancerHTTPSListener) GetClientIdleTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerHTTPSListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/aliyun/loadbalancerlistenerrule.go b/pkg/multicloud/aliyun/loadbalancerlistenerrule.go deleted file mode 100644 index 0972599cbc..0000000000 --- a/pkg/multicloud/aliyun/loadbalancerlistenerrule.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerListenerRule struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.AliyunTags - httpListener *SLoadbalancerHTTPListener - httpsListener *SLoadbalancerHTTPSListener - - Domain string `json:"Domain"` - ListenerSync string - RuleId string - RuleName string `json:"RuleName"` - Url string `json:"Url"` - VServerGroupId string `json:"VServerGroupId"` -} - -func (lbr *SLoadbalancerListenerRule) GetName() string { - return lbr.RuleName -} - -func (lbr *SLoadbalancerListenerRule) GetId() string { - return lbr.RuleId -} - -func (lbr *SLoadbalancerListenerRule) GetGlobalId() string { - return lbr.RuleId -} - -func (lbr *SLoadbalancerListenerRule) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancerListenerRule) IsDefault() bool { - return false -} - -func (lbr *SLoadbalancerListenerRule) IsEmulated() bool { - return false -} - -func (lbr *SLoadbalancerListenerRule) getRegion() *SRegion { - if lbr.httpListener != nil { - return lbr.httpListener.lb.region - } else if lbr.httpsListener != nil { - return lbr.httpsListener.lb.region - } - return nil -} - -func (lbr *SLoadbalancerListenerRule) Refresh() error { - region := lbr.getRegion() - if region == nil { - return fmt.Errorf("failed to find listener for rule %s", lbr.RuleName) - } - rule, err := region.GetLoadbalancerListenerRule(lbr.RuleId) - if err != nil { - return err - } - return jsonutils.Update(lbr, rule) -} - -func (lbr *SLoadbalancerListenerRule) GetCondition() string { - return "" -} - -func (lbr *SLoadbalancerListenerRule) GetDomain() string { - return lbr.Domain -} - -func (lbr *SLoadbalancerListenerRule) GetPath() string { - return lbr.Url -} - -func (lbr *SLoadbalancerListenerRule) GetProjectId() string { - if lbr.httpListener != nil { - return lbr.httpListener.GetProjectId() - } else if lbr.httpsListener != nil { - return lbr.httpsListener.GetProjectId() - } - - return "" -} - -func (lbr *SLoadbalancerListenerRule) GetBackendGroupId() string { - return lbr.VServerGroupId -} - -func (region *SRegion) GetLoadbalancerListenerRules(loadbalancerId string, listenerPort int) ([]SLoadbalancerListenerRule, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - body, err := region.lbRequest("DescribeRules", params) - if err != nil { - return nil, err - } - rules := []SLoadbalancerListenerRule{} - return rules, body.Unmarshal(&rules, "Rules", "Rule") -} - -func (lbr *SLoadbalancerListenerRule) Delete(ctx context.Context) error { - if lbr.httpListener != nil { - return lbr.httpListener.lb.region.DeleteLoadbalancerListenerRule(lbr.RuleId) - } - if lbr.httpsListener != nil { - return lbr.httpsListener.lb.region.DeleteLoadbalancerListenerRule(lbr.RuleId) - } - return fmt.Errorf("failed to find listener for listener rule %s", lbr.RuleName) -} - -func (region *SRegion) DeleteLoadbalancerListenerRule(ruleId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["RuleIds"] = fmt.Sprintf(`["%s"]`, ruleId) - _, err := region.lbRequest("DeleteRules", params) - return err -} - -func (region *SRegion) CreateLoadbalancerListenerRule(listenerPort int, loadbalancerId string, _rule *SLoadbalancerListenerRule) (*SLoadbalancerListenerRule, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - params["LoadBalancerId"] = loadbalancerId - _rules := jsonutils.NewArray() - _rules.Add(jsonutils.Marshal(_rule)) - params["RuleList"] = _rules.String() - body, err := region.lbRequest("CreateRules", params) - if err != nil { - return nil, err - } - rules := []SLoadbalancerListenerRule{} - if err := body.Unmarshal(&rules, "Rules", "Rule"); err != nil { - return nil, err - } - for _, rule := range rules { - if rule.RuleName == _rule.RuleName { - return region.GetLoadbalancerListenerRule(rule.RuleId) - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetLoadbalancerListenerRule(ruleId string) (*SLoadbalancerListenerRule, error) { - if len(ruleId) == 0 { - return nil, cloudprovider.ErrNotFound - } - params := map[string]string{} - params["RegionId"] = region.RegionId - params["RuleId"] = ruleId - body, err := region.lbRequest("DescribeRuleAttribute", params) - if err != nil { - return nil, err - } - rule := &SLoadbalancerListenerRule{RuleId: ruleId} - return rule, body.Unmarshal(rule) -} diff --git a/pkg/multicloud/aliyun/loadbalancermasterslavebackend.go b/pkg/multicloud/aliyun/loadbalancermasterslavebackend.go deleted file mode 100644 index 142ddec9b2..0000000000 --- a/pkg/multicloud/aliyun/loadbalancermasterslavebackend.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - "strings" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerMasterSlaveBackend struct { - multicloud.SResourceBase - multicloud.AliyunTags - lbbg *SLoadbalancerMasterSlaveBackendGroup - - ServerId string - Weight int - Port int - ServerType string -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetName() string { - return backend.ServerId -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetId() string { - return fmt.Sprintf("%s/%s", backend.lbbg.MasterSlaveServerGroupId, backend.ServerId) -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetGlobalId() string { - return backend.GetId() -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backend *SLoadbalancerMasterSlaveBackend) IsEmulated() bool { - return false -} - -func (backend *SLoadbalancerMasterSlaveBackend) Refresh() error { - return nil -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetWeight() int { - return backend.Weight -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetPort() int { - return backend.Port -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetBackendRole() string { - return strings.ToLower(backend.ServerType) -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetBackendId() string { - return backend.ServerId -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetIpAddress() string { - return "" -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetProjectId() string { - return backend.lbbg.GetProjectId() -} - -func (backend *SLoadbalancerMasterSlaveBackend) SyncConf(ctx context.Context, port, weight int) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/aliyun/loadbalancermasterslavebackendgroup.go b/pkg/multicloud/aliyun/loadbalancermasterslavebackendgroup.go deleted file mode 100644 index 14e3799622..0000000000 --- a/pkg/multicloud/aliyun/loadbalancermasterslavebackendgroup.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerMasterSlaveBackendGroup struct { - multicloud.SResourceBase - multicloud.AliyunTags - lb *SLoadbalancer - - MasterSlaveServerGroupId string - MasterSlaveServerGroupName string -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetLoadbalancerId() string { - return backendgroup.lb.GetId() -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetProtocolType() string { - return "" -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetScheduler() string { - return "" -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetName() string { - return backendgroup.MasterSlaveServerGroupName -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetId() string { - return backendgroup.MasterSlaveServerGroupId -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetGlobalId() string { - return backendgroup.GetId() -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) IsEmulated() bool { - return false -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Refresh() error { - return nil -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) IsDefault() bool { - return false -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE -} - -func (region *SRegion) GetLoadbalancerMasterSlaveBackendgroups(loadbalancerId string) ([]SLoadbalancerMasterSlaveBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - body, err := region.lbRequest("DescribeMasterSlaveServerGroups", params) - if err != nil { - return nil, err - } - backendgroups := []SLoadbalancerMasterSlaveBackendGroup{} - return backendgroups, body.Unmarshal(&backendgroups, "MasterSlaveServerGroups", "MasterSlaveServerGroup") -} - -func (region *SRegion) GetLoadbalancerMasterSlaveBackends(backendgroupId string) ([]SLoadbalancerMasterSlaveBackend, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["MasterSlaveServerGroupId"] = backendgroupId - body, err := region.lbRequest("DescribeMasterSlaveServerGroupAttribute", params) - if err != nil { - return nil, err - } - backends := []SLoadbalancerMasterSlaveBackend{} - return backends, body.Unmarshal(&backends, "MasterSlaveBackendServers", "MasterSlaveBackendServer") -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := backendgroup.lb.region.GetLoadbalancerMasterSlaveBackends(backendgroup.MasterSlaveServerGroupId) - if err != nil { - return nil, err - } - ibackends := []cloudprovider.ICloudLoadbalancerBackend{} - for i := 0; i < len(backends); i++ { - backends[i].lbbg = backendgroup - ibackends = append(ibackends, &backends[i]) - } - return ibackends, nil -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := backendgroup.GetILoadbalancerBackends() - if err != nil { - return nil, err - } - for i := 0; i < len(backends); i++ { - if backends[i].GetGlobalId() == backendId { - return backends[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) CreateLoadbalancerMasterSlaveBackendGroup(name, loadbalancerId string, backends []cloudprovider.SLoadbalancerBackend) (*SLoadbalancerMasterSlaveBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["MasterSlaveServerGroupName"] = name - params["LoadBalancerId"] = loadbalancerId - if len(backends) != 2 { - return nil, fmt.Errorf("master slave backendgorup must contain two backend") - } - servers := jsonutils.NewArray() - for _, backend := range backends { - serverType := "Slave" - if backend.Index == 0 { - serverType = "Master" - } - servers.Add( - jsonutils.Marshal( - map[string]string{ - "ServerId": backend.ExternalID, - "Port": fmt.Sprintf("%d", backend.Port), - "Weight": fmt.Sprintf("%d", backend.Weight), - "ServerType": serverType, - }, - )) - } - params["MasterSlaveBackendServers"] = servers.String() - body, err := region.lbRequest("CreateMasterSlaveServerGroup", params) - if err != nil { - return nil, err - } - groupId, err := body.GetString("MasterSlaveServerGroupId") - if err != nil { - return nil, err - } - return region.GetLoadbalancerMasterSlaveBackendgroupById(groupId) -} - -func (region *SRegion) GetLoadbalancerMasterSlaveBackendgroupById(groupId string) (*SLoadbalancerMasterSlaveBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["MasterSlaveServerGroupId"] = groupId - params["NeedInstanceDetail"] = "true" - body, err := region.lbRequest("DescribeMasterSlaveServerGroupAttribute", params) - if err != nil { - return nil, err - } - group := &SLoadbalancerMasterSlaveBackendGroup{} - return group, body.Unmarshal(group) -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - return nil -} - -func (region *SRegion) DeleteLoadbalancerMasterSlaveBackendgroup(groupId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["MasterSlaveServerGroupId"] = groupId - _, err := region.lbRequest("DeleteMasterSlaveServerGroup", params) - return err -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Delete(ctx context.Context) error { - return backendgroup.lb.region.DeleteLoadbalancerMasterSlaveBackendgroup(backendgroup.MasterSlaveServerGroupId) -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { - return cloudprovider.ErrNotSupported -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetProjectId() string { - return backendgroup.lb.GetProjectId() -} diff --git a/pkg/multicloud/aliyun/loadbalancerservercertificate.go b/pkg/multicloud/aliyun/loadbalancerservercertificate.go deleted file mode 100644 index 58882be8f2..0000000000 --- a/pkg/multicloud/aliyun/loadbalancerservercertificate.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SubjectAlternativeNames struct { - SubjectAlternativeName []string -} - -type SLoadbalancerServerCertificate struct { - multicloud.SResourceBase - multicloud.AliyunTags - region *SRegion - - ServerCertificateId string // 服务器证书ID。 - ServerCertificateName string // 服务器证书名称。 - Fingerprint string // 服务器证书的指纹。 - CreateTime string // 服务器证书上传的时间。 - CreateTimeStamp uint64 // 服务器证书上传的时间戳。 - IsAliCloudCertificate int // 是否是阿里云证书。0代表不是阿里云证书。 - AliCloudCertificateName string // 阿里云证书名称。 - AliCloudCertificateId string // 阿里云证书ID。 - ExpireTime time.Time // 过期时间。 - ExpireTimeStamp uint64 // 过期时间戳。 - CommonName string // 域名,对应证书的CommonName字段。 - SubjectAlternativeNames SubjectAlternativeNames // 数组格式,返回证书的备用域名列表,对应证书的Subject Alternative Name字段,详情请参见SubjectAlternativeNames。 - ResourceGroupId string // 实例的企业资源组ID - RegionId string // 负载均衡实例的地域。 -} - -func (certificate *SLoadbalancerServerCertificate) GetPublickKey() string { - return "" -} - -func (certificate *SLoadbalancerServerCertificate) GetPrivateKey() string { - return "" -} - -func (certificate *SLoadbalancerServerCertificate) GetName() string { - return certificate.ServerCertificateName -} - -func (certificate *SLoadbalancerServerCertificate) GetId() string { - return certificate.ServerCertificateId -} - -func (certificate *SLoadbalancerServerCertificate) GetGlobalId() string { - return certificate.GetId() -} - -func (certificate *SLoadbalancerServerCertificate) GetStatus() string { - return "" -} - -func (certificate *SLoadbalancerServerCertificate) IsEmulated() bool { - return false -} - -func (certificate *SLoadbalancerServerCertificate) GetCommonName() string { - return certificate.CommonName -} - -func (certificate *SLoadbalancerServerCertificate) GetSubjectAlternativeNames() string { - return strings.Join(certificate.SubjectAlternativeNames.SubjectAlternativeName, ",") -} - -func (certificate *SLoadbalancerServerCertificate) GetFingerprint() string { - return fmt.Sprintf("sha1:%s", strings.Replace(certificate.Fingerprint, ":", "", -1)) -} - -func (certificate *SLoadbalancerServerCertificate) GetExpireTime() time.Time { - return certificate.ExpireTime -} - -func (certificate *SLoadbalancerServerCertificate) Refresh() error { - return nil -} - -func (region *SRegion) UpdateServerCertificateName(certId, name string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["ServerCertificateId"] = certId - params["ServerCertificateName"] = name - _, err := region.lbRequest("SetServerCertificateName", params) - return err -} - -func (certificate *SLoadbalancerServerCertificate) Sync(name string, privateKey string, publicKey string) error { - if certificate.ServerCertificateName != name { - return certificate.region.UpdateServerCertificateName(certificate.ServerCertificateId, name) - } - return nil -} - -func (certificate *SLoadbalancerServerCertificate) Delete() error { - return certificate.region.DeleteServerCertificate(certificate.ServerCertificateId) -} - -func (region *SRegion) DeleteServerCertificate(certId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["ServerCertificateId"] = certId - _, err := region.lbRequest("DeleteServerCertificate", params) - return err -} - -func (region *SRegion) GetLoadbalancerServerCertificates() ([]SLoadbalancerServerCertificate, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - body, err := region.lbRequest("DescribeServerCertificates", params) - if err != nil { - return nil, err - } - certificates := []SLoadbalancerServerCertificate{} - return certificates, body.Unmarshal(&certificates, "ServerCertificates", "ServerCertificate") -} - -func (certificate *SLoadbalancerServerCertificate) GetProjectId() string { - return certificate.ResourceGroupId -} diff --git a/pkg/multicloud/aliyun/loadbalancertcplistener.go b/pkg/multicloud/aliyun/loadbalancertcplistener.go deleted file mode 100644 index a3da489a56..0000000000 --- a/pkg/multicloud/aliyun/loadbalancertcplistener.go +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerTCPListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.AliyunTags - lb *SLoadbalancer - - ListenerPort int // 负载均衡实例前端使用的端口。 - BackendServerPort int // 负载均衡实例后端使用的端口。 - Bandwidth int // 监听的带宽峰值。 - Status string // 当前监听的状态,取值:starting | running | configuring | stopping | stopped - Description string - - Scheduler string // 调度算法。 - VServerGroupId string // 绑定的服务器组ID。 - MasterSlaveServerGroupId string // 绑定的主备服务器组ID。 - AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) - PersistenceTimeout int //是否开启了会话保持。取值为0时,表示没有开启。 - - AclType string // 访问控制类型 - - AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 - - HealthCheck string // 是否开启健康检查。 - HealthCheckType string //TCP协议监听的健康检查方式。取值:tcp | http - HealthyThreshold int // 健康检查阈值。 - UnhealthyThreshold int // 不健康检查阈值。 - HealthCheckConnectTimeout int // 每次健康检查响应的最大超时间,单位为秒。 - HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 - HealthCheckConnectPort int // 健康检查的端口。 -} - -func (listener *SLoadbalancerTCPListener) GetName() string { - if len(listener.Description) == 0 { - listener.Refresh() - } - if len(listener.Description) > 0 { - return listener.Description - } - return fmt.Sprintf("TCP:%d", listener.ListenerPort) -} - -func (listerner *SLoadbalancerTCPListener) GetId() string { - return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerTCPListener) GetGlobalId() string { - return listerner.GetId() -} - -func (listerner *SLoadbalancerTCPListener) GetStatus() string { - switch listerner.Status { - case "starting", "running": - return api.LB_STATUS_ENABLED - case "configuring", "stopping", "stopped": - return api.LB_STATUS_DISABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (listerner *SLoadbalancerTCPListener) GetEgressMbps() int { - if listerner.Bandwidth < 1 { - return 0 - } - return listerner.Bandwidth -} - -func (listerner *SLoadbalancerTCPListener) IsEmulated() bool { - return false -} - -func (listerner *SLoadbalancerTCPListener) Refresh() error { - lis, err := listerner.lb.region.GetLoadbalancerTCPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return err - } - return jsonutils.Update(listerner, lis) -} - -func (listerner *SLoadbalancerTCPListener) GetListenerType() string { - return "tcp" -} -func (listerner *SLoadbalancerTCPListener) GetListenerPort() int { - return listerner.ListenerPort -} - -func (listerner *SLoadbalancerTCPListener) GetBackendGroupId() string { - if len(listerner.VServerGroupId) > 0 { - return listerner.VServerGroupId - } - return listerner.MasterSlaveServerGroupId -} - -func (listerner *SLoadbalancerTCPListener) GetScheduler() string { - return listerner.Scheduler -} - -func (listerner *SLoadbalancerTCPListener) GetAclStatus() string { - return listerner.AclStatus -} - -func (listerner *SLoadbalancerTCPListener) GetAclType() string { - return listerner.AclType -} - -func (listerner *SLoadbalancerTCPListener) GetAclId() string { - return listerner.AclId -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheck() string { - return listerner.HealthCheck -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckType() string { - return listerner.HealthCheckType -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckDomain() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckURI() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckCode() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckRise() int { - return listerner.HealthyThreshold -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckFail() int { - return listerner.UnhealthyThreshold -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckTimeout() int { - return listerner.HealthCheckConnectTimeout -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckInterval() int { - return listerner.HealthCheckInterval -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckReq() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckExp() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetStickySession() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetStickySessionType() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetStickySessionCookie() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetStickySessionCookieTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerTCPListener) XForwardedForEnabled() bool { - return false -} - -func (listerner *SLoadbalancerTCPListener) GzipEnabled() bool { - return false -} - -func (listerner *SLoadbalancerTCPListener) GetCertificateId() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetTLSCipherPolicy() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) HTTP2Enabled() bool { - return false -} - -func (listerner *SLoadbalancerTCPListener) GetBackendServerPort() int { - return listerner.BackendServerPort -} - -func (listerner *SLoadbalancerTCPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - return []cloudprovider.ICloudLoadbalancerListenerRule{}, nil -} - -func (region *SRegion) GetLoadbalancerTCPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerTCPListener, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - body, err := region.lbRequest("DescribeLoadBalancerTCPListenerAttribute", params) - if err != nil { - return nil, err - } - listener := SLoadbalancerTCPListener{} - return &listener, body.Unmarshal(&listener) -} - -func (region *SRegion) constructBaseCreateListenerParams(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) map[string]string { - params := map[string]string{} - params["RegionId"] = region.RegionId - if listener.EgressMbps < 1 { - listener.EgressMbps = -1 - } - params["Bandwidth"] = fmt.Sprintf("%d", listener.EgressMbps) - params["ListenerPort"] = fmt.Sprintf("%d", listener.ListenerPort) - params["LoadBalancerId"] = lb.LoadBalancerId - if len(listener.AccessControlListID) > 0 { - params["AclId"] = listener.AccessControlListID - } - if utils.IsInStringArray(listener.AccessControlListStatus, []string{"on", "off"}) { - params["AclStatus"] = listener.AccessControlListStatus - } - if utils.IsInStringArray(listener.AccessControlListType, []string{"white", "black"}) { - params["AclType"] = listener.AccessControlListType - } - switch listener.BackendGroupType { - case api.LB_BACKENDGROUP_TYPE_NORMAL: - params["VServerGroupId"] = listener.BackendGroupID - params["VServerGroup"] = "on" - case api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE: - params["MasterSlaveServerGroupId"] = listener.BackendGroupID - params["MasterSlaveServerGroup"] = "on" - case api.LB_BACKENDGROUP_TYPE_DEFAULT: - params["BackendServerPort"] = fmt.Sprintf("%d", listener.BackendServerPort) - } - if len(listener.Name) > 0 { - params["Description"] = listener.Name - } - - if utils.IsInStringArray(listener.ListenerType, []string{api.LB_LISTENER_TYPE_TCP, api.LB_LISTENER_TYPE_UDP}) { - if listener.HealthCheckTimeout >= 1 && listener.HealthCheckTimeout <= 300 { - params["HealthCheckConnectTimeout"] = fmt.Sprintf("%d", listener.HealthCheckTimeout) - } - } - switch listener.ListenerType { - case api.LB_LISTENER_TYPE_UDP: - if len(listener.HealthCheckReq) > 0 { - params["healthCheckReq"] = listener.HealthCheckReq - } - if len(listener.HealthCheckExp) > 0 { - params["healthCheckExp"] = listener.HealthCheckExp - } - } - - if len(listener.HealthCheckDomain) > 0 { - params["HealthCheckDomain"] = listener.HealthCheckDomain - } - - if len(listener.HealthCheckHttpCode) > 0 { - params["HealthCheckHttpCode"] = listener.HealthCheckHttpCode - } - - if len(listener.HealthCheckURI) > 0 { - params["HealthCheckURI"] = listener.HealthCheckURI - } - - if listener.HealthCheckRise >= 2 && listener.HealthCheckRise <= 10 { - params["HealthyThreshold"] = fmt.Sprintf("%d", listener.HealthCheckRise) - } - - if listener.HealthCheckFail >= 2 && listener.HealthCheckFail <= 10 { - params["UnhealthyThreshold"] = fmt.Sprintf("%d", listener.HealthCheckFail) - } - - if listener.HealthCheckInterval >= 1 && listener.HealthCheckInterval <= 50 { - params["healthCheckInterval"] = fmt.Sprintf("%d", listener.HealthCheckInterval) - } - - params["Scheduler"] = listener.Scheduler - return params -} - -func (region *SRegion) CreateLoadbalancerTCPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - params := region.constructBaseCreateListenerParams(lb, listener) - _, err := region.lbRequest("CreateLoadBalancerTCPListener", params) - if err != nil { - return nil, err - } - iListener, err := region.GetLoadbalancerTCPListener(lb.LoadBalancerId, listener.ListenerPort) - if err != nil { - return nil, err - } - iListener.lb = lb - return iListener, nil -} - -func (listerner *SLoadbalancerTCPListener) Delete(ctx context.Context) error { - return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerTCPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (listerner *SLoadbalancerTCPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (listerner *SLoadbalancerTCPListener) Start() error { - return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (listerner *SLoadbalancerTCPListener) Stop() error { - return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (region *SRegion) SyncLoadbalancerTCPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { - params := region.constructBaseCreateListenerParams(lb, listener) - _, err := region.lbRequest("SetLoadBalancerTCPListenerAttribute", params) - return err -} - -func (listerner *SLoadbalancerTCPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { - return listerner.lb.region.SyncLoadbalancerTCPListener(listerner.lb, lblis) -} - -func (listerner *SLoadbalancerTCPListener) GetProjectId() string { - return listerner.lb.GetProjectId() -} - -func (listerner *SLoadbalancerTCPListener) GetClientIdleTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerTCPListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/aliyun/loadbalancerudplistener.go b/pkg/multicloud/aliyun/loadbalancerudplistener.go deleted file mode 100644 index 1f1141d201..0000000000 --- a/pkg/multicloud/aliyun/loadbalancerudplistener.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerUDPListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.AliyunTags - lb *SLoadbalancer - - ListenerPort int // 负载均衡实例前端使用的端口。 - BackendServerPort int // 负载均衡实例后端使用的端口。 - Bandwidth int // 监听的带宽峰值。 - Status string // 当前监听的状态,取值:starting | running | configuring | stopping | stopped - Description string - - Scheduler string // 调度算法 - VServerGroupId string // 绑定的服务器组ID。 - MasterSlaveServerGroupId string // 绑定的主备服务器组ID。 - AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) - - AclType string // 访问控制类型: - - AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 - - HealthCheck string // 是否开启健康检查。 - HealthyThreshold int // 健康检查阈值。 - UnhealthyThreshold int // 不健康检查阈值。 - HealthCheckConnectTimeout int // 每次健康检查响应的最大超时间,单位为秒。 - HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 - HealthCheckConnectPort int // 健康检查的端口。 - - HealthCheckExp string // UDP监听健康检查的响应串 - HealthCheckReq string // UDP监听健康检查的请求串 -} - -func (listener *SLoadbalancerUDPListener) GetName() string { - if len(listener.Description) == 0 { - listener.Refresh() - } - if len(listener.Description) > 0 { - return listener.Description - } - return fmt.Sprintf("UDP:%d", listener.ListenerPort) -} - -func (listerner *SLoadbalancerUDPListener) GetId() string { - return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerUDPListener) GetGlobalId() string { - return listerner.GetId() -} - -func (listerner *SLoadbalancerUDPListener) GetStatus() string { - switch listerner.Status { - case "starting", "running": - return api.LB_STATUS_ENABLED - case "configuring", "stopping", "stopped": - return api.LB_STATUS_DISABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (listerner *SLoadbalancerUDPListener) GetEgressMbps() int { - if listerner.Bandwidth < 1 { - return 0 - } - return listerner.Bandwidth -} - -func (listerner *SLoadbalancerUDPListener) IsEmulated() bool { - return false -} - -func (listerner *SLoadbalancerUDPListener) Refresh() error { - lis, err := listerner.lb.region.GetLoadbalancerUDPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return err - } - return jsonutils.Update(listerner, lis) -} - -func (listerner *SLoadbalancerUDPListener) GetListenerType() string { - return "udp" -} - -func (listerner *SLoadbalancerUDPListener) GetListenerPort() int { - return listerner.ListenerPort -} - -func (listerner *SLoadbalancerUDPListener) GetBackendGroupId() string { - if len(listerner.VServerGroupId) > 0 { - return listerner.VServerGroupId - } - return listerner.MasterSlaveServerGroupId -} - -func (listerner *SLoadbalancerUDPListener) GetBackendServerPort() int { - return listerner.BackendServerPort -} - -func (listerner *SLoadbalancerUDPListener) GetScheduler() string { - return listerner.Scheduler -} - -func (listerner *SLoadbalancerUDPListener) GetAclStatus() string { - return listerner.AclStatus -} - -func (listerner *SLoadbalancerUDPListener) GetAclType() string { - return listerner.AclType -} - -func (listerner *SLoadbalancerUDPListener) GetAclId() string { - return listerner.AclId -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheck() string { - return listerner.HealthCheck -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckType() string { - return api.LB_HEALTH_CHECK_UDP -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckDomain() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckURI() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckCode() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckRise() int { - return listerner.HealthyThreshold -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckFail() int { - return listerner.UnhealthyThreshold -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckTimeout() int { - return listerner.HealthCheckConnectTimeout -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckInterval() int { - return listerner.HealthCheckInterval -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckReq() string { - return listerner.HealthCheckReq -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckExp() string { - return listerner.HealthCheckExp -} - -func (listerner *SLoadbalancerUDPListener) GetStickySession() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetStickySessionType() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetStickySessionCookie() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetStickySessionCookieTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerUDPListener) XForwardedForEnabled() bool { - return false -} - -func (listerner *SLoadbalancerUDPListener) GzipEnabled() bool { - return false -} - -func (listerner *SLoadbalancerUDPListener) GetCertificateId() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetTLSCipherPolicy() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) HTTP2Enabled() bool { - return false -} - -func (listerner *SLoadbalancerUDPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - return []cloudprovider.ICloudLoadbalancerListenerRule{}, nil -} - -func (region *SRegion) GetLoadbalancerUDPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerUDPListener, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - body, err := region.lbRequest("DescribeLoadBalancerUDPListenerAttribute", params) - if err != nil { - return nil, err - } - listener := SLoadbalancerUDPListener{} - return &listener, body.Unmarshal(&listener) -} - -func (region *SRegion) CreateLoadbalancerUDPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - params := region.constructBaseCreateListenerParams(lb, listener) - _, err := region.lbRequest("CreateLoadBalancerUDPListener", params) - if err != nil { - return nil, err - } - iListener, err := region.GetLoadbalancerUDPListener(lb.LoadBalancerId, listener.ListenerPort) - if err != nil { - return nil, err - } - iListener.lb = lb - return iListener, nil -} - -func (listerner *SLoadbalancerUDPListener) Delete(ctx context.Context) error { - return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerUDPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (listerner *SLoadbalancerUDPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (listerner *SLoadbalancerUDPListener) Start() error { - return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (listerner *SLoadbalancerUDPListener) Stop() error { - return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (region *SRegion) SyncLoadbalancerUDPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { - params := region.constructBaseCreateListenerParams(lb, listener) - _, err := region.lbRequest("SetLoadBalancerUDPListenerAttribute", params) - return err -} - -func (listerner *SLoadbalancerUDPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { - return listerner.lb.region.SyncLoadbalancerUDPListener(listerner.lb, lblis) -} - -func (listerner *SLoadbalancerUDPListener) GetProjectId() string { - return listerner.lb.GetProjectId() -} - -func (listerner *SLoadbalancerUDPListener) GetClientIdleTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerUDPListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/aliyun/mongodb.go b/pkg/multicloud/aliyun/mongodb.go deleted file mode 100644 index 85354097e3..0000000000 --- a/pkg/multicloud/aliyun/mongodb.go +++ /dev/null @@ -1,523 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "regexp" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SMOngoDBAttribute struct { - // 实例最大IOPS - MaxIops int - ReplicaSets struct { - ReplicaSet []struct { - ConnectionDomain string `json:"ConnectionDomain"` - } - } - MaxConnections int -} - -type SMongoDB struct { - region *SRegion - multicloud.AliyunTags - multicloud.SBillingBase - multicloud.SResourceBase - - ConnectionDomain string `json:"ConnectionDomain"` - NetworkAddress string - ChargeType TChargeType `json:"ChargeType"` - LockMode string `json:"LockMode"` - DBInstanceClass string `json:"DBInstanceClass"` - ResourceGroupId string `json:"ResourceGroupId"` - DBInstanceId string `json:"DBInstanceId"` - ZoneId string `json:"ZoneId"` - MongosList struct { - MongosAttribute []struct { - NodeId string `json:"NodeId"` - NodeClass string `json:"NodeClass"` - } `json:"MongosAttribute"` - } `json:"MongosList"` - DBInstanceDescription string `json:"DBInstanceDescription"` - Engine string `json:"Engine"` - CreationTime time.Time `json:"CreationTime"` - NetworkType string `json:"NetworkType"` - ExpireTime time.Time `json:"ExpireTime"` - DBInstanceType string `json:"DBInstanceType"` - RegionId string `json:"RegionId"` - ShardList struct { - ShardAttribute []struct { - NodeId string `json:"NodeId"` - NodeClass string `json:"NodeClass"` - NodeStorage int `json:"NodeStorage"` - } `json:"ShardAttribute"` - } `json:"ShardList"` - EngineVersion string `json:"EngineVersion"` - DBInstanceStatus string `json:"DBInstanceStatus"` - - DBInstanceStorage int `json:"DBInstanceStorage"` - MaintainStartTime string `json:"MaintainStartTime"` - MaintainEndTime string `json:"MaintainEndTime"` - StorageEngine string `json:"StorageEngine"` - VpcId string `json:"VPCId"` - VSwitchId string `json:"VSwitchId"` - VpcAuthMode string `json:"VpcAuthMode"` - ReplicationFactor string `json:"ReplicationFactor"` -} - -var mongoSpec = map[string]struct { - VcpuCount int - VmemSizeGb int -}{} - -func (self *SMongoDB) GetName() string { - if len(self.DBInstanceDescription) > 0 { - return self.DBInstanceDescription - } - return self.DBInstanceId -} - -func (self *SMongoDB) GetId() string { - return self.DBInstanceId -} - -func (self *SMongoDB) GetGlobalId() string { - return self.DBInstanceId -} - -func (self *SMongoDB) GetStatus() string { - switch self.DBInstanceStatus { - case "Creating": - return api.MONGO_DB_STATUS_CREATING - case "DBInstanceClassChanging": - return api.MONGO_DB_STATUS_CHANGE_CONFIG - case "DBInstanceNetTypeChanging", "EngineVersionUpgrading", "GuardSwitching", "HASwitching", "Importing", "ImportingFromOthers", "LinkSwitching", "MinorVersionUpgrading", "NET_CREATING", "NET_DELETING", "NodeCreating", "NodeDeleting", "Restoring", "SSLModifying", "TempDBInstanceCreating", "Transing", "TransingToOthers": - return api.MONGO_DB_STATUS_DEPLOY - case "Deleting": - return api.MONGO_DB_STATUS_DELETING - case "Rebooting": - return api.MONGO_DB_STATUS_REBOOTING - case "Running": - return api.MONGO_DB_STATUS_RUNNING - default: - return strings.ToLower(self.DBInstanceStatus) - } -} - -func (self *SMongoDB) GetProjectId() string { - return self.ResourceGroupId -} - -func (self *SMongoDB) Refresh() error { - db, err := self.region.GetMongoDB(self.DBInstanceId) - if err != nil { - return errors.Wrapf(err, "GetMongoDB") - } - return jsonutils.Update(self, db) -} - -func (self *SMongoDB) GetCreatedAt() time.Time { - return self.CreationTime -} - -func (self *SMongoDB) GetExpiredAt() time.Time { - return self.ExpireTime -} - -func (self *SMongoDB) GetIpAddr() string { - return "" -} - -func (self *SMongoDB) GetEngine() string { - if len(self.StorageEngine) == 0 { - self.Refresh() - } - return self.StorageEngine -} - -func (self *SMongoDB) GetEngineVersion() string { - return self.EngineVersion -} - -func (self *SMongoDB) GetVpcId() string { - if self.NetworkType != "VPC" { - return "" - } - if len(self.VpcId) == 0 { - self.Refresh() - } - return self.VpcId -} - -func (self *SMongoDB) GetNetworkId() string { - if self.NetworkType != "VPC" { - return "" - } - if len(self.VSwitchId) == 0 { - self.Refresh() - } - return self.VSwitchId -} - -func (self *SMongoDB) GetZoneId() string { - if !strings.Contains(self.ZoneId, ",") { - return self.ZoneId - } - if index := strings.Index(self.ZoneId, ",") - 1; index > 0 { - return fmt.Sprintf("%s-%s", self.region.RegionId, string(self.ZoneId[index])) - } - return "" -} - -func (self *SMongoDB) Delete() error { - return self.region.DeleteMongoDB(self.DBInstanceId) -} - -func (self *SMongoDB) GetBillingType() string { - return convertChargeType(self.ChargeType) -} - -func (self *SMongoDB) GetCategory() string { - return self.DBInstanceType -} - -func (self *SMongoDB) GetDiskSizeMb() int { - if self.DBInstanceStorage == 0 { - self.Refresh() - } - return self.DBInstanceStorage * 1024 -} - -func (self *SMongoDB) GetInstanceType() string { - return self.DBInstanceClass -} - -func (self *SMongoDB) GetMaintainTime() string { - return fmt.Sprintf("%s-%s", self.MaintainStartTime, self.MaintainEndTime) -} - -func (self *SMongoDB) GetPort() int { - return 3717 -} - -func (self *SMongoDB) GetReplicationNum() int { - if len(self.ReplicationFactor) == 0 { - self.Refresh() - } - num, _ := strconv.Atoi(self.ReplicationFactor) - return int(num) -} - -func (self *SMongoDB) GetVcpuCount() int { - self.region.GetchMongoSkus() - sku, ok := self.region.mongoSkus[self.DBInstanceClass] - if ok { - return sku.CpuCount - } - return 0 -} - -func (self *SMongoDB) GetVmemSizeMb() int { - self.region.GetchMongoSkus() - sku, ok := self.region.mongoSkus[self.DBInstanceClass] - if ok { - return sku.MemSizeGb * 1024 - } - return 0 -} - -func (self *SMongoDB) GetIops() int { - iops, _ := self.region.GetIops(self.DBInstanceId) - return iops -} - -func (self *SMongoDB) GetMaxConnections() int { - maxConnection, _ := self.region.GetMaxConnections(self.DBInstanceId) - return maxConnection -} - -func (self *SMongoDB) GetNetworkAddress() string { - addr, _ := self.region.GetNetworkAddress(self.DBInstanceId) - return addr -} - -func (self *SRegion) GetMongoDBsByType(mongoType string) ([]SMongoDB, error) { - dbs := []SMongoDB{} - for { - part, total, err := self.GetMongoDBs(mongoType, 100, len(dbs)/100) - if err != nil { - return nil, errors.Wrapf(err, "GetMongoDB") - } - dbs = append(dbs, part...) - if len(dbs) >= total { - break - } - } - return dbs, nil -} - -func (self *SMongoDB) SetTags(tags map[string]string, replace bool) error { - return self.region.SetResourceTags(ALIYUN_SERVICE_MONGO_DB, "INSTANCE", self.GetId(), tags, replace) -} - -func (self *SRegion) GetICloudMongoDBById(id string) (cloudprovider.ICloudMongoDB, error) { - db, err := self.GetMongoDB(id) - if err != nil { - return nil, errors.Wrapf(err, "GetMongoDB(%s)", id) - } - return db, nil -} - -func (self *SRegion) GetICloudMongoDBs() ([]cloudprovider.ICloudMongoDB, error) { - dbs := []SMongoDB{} - for _, mongoType := range []string{"sharding", "replicate", "serverless"} { - part, err := self.GetMongoDBsByType(mongoType) - if err != nil { - return nil, err - } - dbs = append(dbs, part...) - } - ret := []cloudprovider.ICloudMongoDB{} - for i := range dbs { - dbs[i].region = self - ret = append(ret, &dbs[i]) - } - return ret, nil -} - -func (self *SRegion) GetIops(id string) (int, error) { - ret, err := self.GetMongoDBAttribute(id) - if err != nil { - return 0, errors.Wrapf(err, "DescribeDBInstanceAttribute err") - } - if len(ret) == 0 { - return 0, errors.Wrapf(err, "ret missing err") - } - return ret[0].MaxIops, nil -} - -func (self *SRegion) GetMaxConnections(id string) (int, error) { - ret, err := self.GetMongoDBAttribute(id) - if err != nil { - return 0, errors.Wrapf(err, "DescribeDBInstanceAttribute err") - } - if len(ret) == 0 { - return 0, errors.Wrapf(err, "ret missing err") - } - return ret[0].MaxConnections, nil -} - -func (self *SRegion) GetNetworkAddress(id string) (string, error) { - ret, err := self.GetMongoDBAttribute(id) - if err != nil { - return "", errors.Wrapf(err, "DescribeDBInstanceAttribute err") - } - addrList := make([]string, 0) - for _, v := range ret[0].ReplicaSets.ReplicaSet { - addrList = append(addrList, v.ConnectionDomain) - } - addrs := strings.Join(addrList, ",") - return addrs, nil -} - -func (self *SRegion) GetMongoDBAttribute(id string) ([]SMOngoDBAttribute, error) { - params := map[string]string{ - "Action": "DescribeDBInstanceAttribute", - "DBInstanceId": id, - } - resp, err := self.mongodbRequest("DescribeDBInstanceAttribute", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeDBInstanceAttribute err") - } - ret := []SMOngoDBAttribute{} - err = resp.Unmarshal(&ret, "DBInstances", "DBInstance") - if err != nil { - return nil, errors.Wrapf(err, "unmarshal err") - } - return ret, err -} - -func (self *SRegion) GetMongoDBs(mongoType string, pageSize int, pageNum int) ([]SMongoDB, int, error) { - if pageSize < 1 || pageSize > 100 { - pageSize = 100 - } - if pageNum < 1 { - pageNum = 1 - } - - params := map[string]string{ - "PageSize": fmt.Sprintf("%d", pageSize), - "PageNumber": fmt.Sprintf("%d", pageNum), - } - if len(mongoType) > 0 { - params["DBInstanceType"] = mongoType - } - resp, err := self.mongodbRequest("DescribeDBInstances", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeDBInstances") - } - ret := []SMongoDB{} - err = resp.Unmarshal(&ret, "DBInstances", "DBInstance") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - totalCount, _ := resp.Int("TotalCount") - return ret, int(totalCount), nil -} - -func (self *SRegion) GetMongoDB(id string) (*SMongoDB, error) { - params := map[string]string{ - "DBInstanceId": id, - } - resp, err := self.mongodbRequest("DescribeDBInstanceAttribute", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeDBInstanceAttribute") - } - ret := []SMongoDB{} - err = resp.Unmarshal(&ret, "DBInstances", "DBInstance") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - if len(ret) == 1 { - ret[0].region = self - return &ret[0], nil - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SRegion) DeleteMongoDB(id string) error { - params := map[string]string{ - "DBInstanceId": id, - "ClientToken": utils.GenRequestId(20), - } - _, err := self.mongodbRequest("DeleteDBInstance", params) - return errors.Wrapf(err, "DeleteDBInstance") -} - -type SMongoDBAvaibaleResource struct { - SupportedDBTypes struct { - SupportedDBType []struct { - DbType string - AvailableZones struct { - AvailableZone []struct { - ZoneId string - RegionId string - SupportedEngineVersions struct { - SupportedEngineVersion []struct { - Version string - SupportedEngines struct { - SupportedEngine []struct { - SupportedNodeTypes struct { - SupportedNodeType []struct { - NetworkTypes string - NodeType string - AvailableResources struct { - AvailableResource []struct { - InstanceClassRemark string - InstanceClass string - } - } - } - } - } - } - } - } - } - } - } - } -} - -func (self *SRegion) GetchMongoSkus() (map[string]struct { - CpuCount int - MemSizeGb int -}, error) { - if len(self.mongoSkus) > 0 { - return self.mongoSkus, nil - } - self.mongoSkus = map[string]struct { - CpuCount int - MemSizeGb int - }{} - res, err := self.GetMongoDBAvailableResource() - if err != nil { - return nil, err - } - for _, dbType := range res.SupportedDBTypes.SupportedDBType { - for _, zone := range dbType.AvailableZones.AvailableZone { - for _, version := range zone.SupportedEngineVersions.SupportedEngineVersion { - for _, engine := range version.SupportedEngines.SupportedEngine { - for _, nodeType := range engine.SupportedNodeTypes.SupportedNodeType { - for _, sku := range nodeType.AvailableResources.AvailableResource { - _, ok := self.mongoSkus[sku.InstanceClass] - if !ok { - self.mongoSkus[sku.InstanceClass] = getMongoDBSkuDetails(sku.InstanceClassRemark) - } - } - } - } - } - } - } - return self.mongoSkus, nil -} - -func getMongoDBSkuDetails(remark string) struct { - CpuCount int - MemSizeGb int -} { - ret := struct { - CpuCount int - MemSizeGb int - }{} - r, _ := regexp.Compile(`(\d{1,3})核(\d{1,3})G+`) - result := r.FindSubmatch([]byte(remark)) - if len(result) > 2 { - cpu, _ := strconv.Atoi(string(result[1])) - ret.CpuCount = int(cpu) - mem, _ := strconv.Atoi(string(result[2])) - ret.MemSizeGb = int(mem) - } else { - log.Warningf("not match sku remark %s", remark) - } - return ret -} - -func (self *SRegion) GetMongoDBAvailableResource() (*SMongoDBAvaibaleResource, error) { - params := map[string]string{} - resp, err := self.mongodbRequest("DescribeAvailableResource", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeAvailableResource") - } - ret := &SMongoDBAvaibaleResource{} - err = resp.Unmarshal(ret) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return ret, nil -} diff --git a/pkg/multicloud/aliyun/monitor.go b/pkg/multicloud/aliyun/monitor.go deleted file mode 100644 index 46b569e7b9..0000000000 --- a/pkg/multicloud/aliyun/monitor.go +++ /dev/null @@ -1,634 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - ALIYUN_API_VERSION_METRICS = "2019-01-01" -) - -func (r *SRegion) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { - return r.client.metricsRequest(action, params) -} - -func (self *SAliyunClient) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient("") - if err != nil { - return nil, errors.Wrap(err, "self.getSdkClient") - } - return jsonRequest(client, "metrics.aliyuncs.com", ALIYUN_API_VERSION_METRICS, action, params, self.debug) -} - -type SResourceLabel struct { - Name string `json:"name"` - Value string `json:"value"` -} - -type SResource struct { - Description string `json:"Description"` - Labels string `json:"Labels"` - Namespace string `json:"Namespace"` -} - -func (r *SRegion) DescribeProjectMeta(limit, offset int) (int, []SResource, error) { - params := make(map[string]string) - if limit <= 0 { - limit = 30 - } - params["PageSize"] = strconv.FormatInt(int64(limit), 10) - if offset > 0 { - pageNum := (offset / limit) + 1 - params["PageNumber"] = strconv.FormatInt(int64(pageNum), 10) - } - body, err := r.metricsRequest("DescribeProjectMeta", params) - if err != nil { - return 0, nil, errors.Wrap(err, "r.metricsRequest DescribeProjectMeta") - } - total, _ := body.Int("Total") - res := make([]SResource, 0) - err = body.Unmarshal(&res, "Resources", "Resource") - if err != nil { - return 0, nil, errors.Wrap(err, "body.Unmarshal Resources Resource") - } - return int(total), res, nil -} - -func (r *SRegion) FetchNamespaces() ([]SResource, error) { - resources := make([]SResource, 0) - total := -1 - for total < 0 || len(resources) < total { - ntotal, res, err := r.DescribeProjectMeta(1000, len(resources)) - if err != nil { - return nil, errors.Wrap(err, "r.DescribeProjectMeta") - } - if len(res) == 0 { - break - } - resources = append(resources, res...) - total = ntotal - } - return resources, nil -} - -type SMetricMeta struct { - Description string `json:"Description"` - MetricName string `json:"MetricName"` - Statistics string `json:"Statistics"` - Labels string `json:"Labels"` - Dimensions string `json:"Dimensions"` - Namespace string `json:"Namespace"` - Periods string `json:"Periods"` - Unit string `json:"Unit"` -} - -func (r *SRegion) DescribeMetricMetaList(ns string, limit, offset int) (int, []SMetricMeta, error) { - params := make(map[string]string) - if limit <= 0 { - limit = 30 - } - params["Namespace"] = ns - params["PageSize"] = strconv.FormatInt(int64(limit), 10) - if offset > 0 { - pageNum := (offset / limit) + 1 - params["PageNumber"] = strconv.FormatInt(int64(pageNum), 10) - } - body, err := r.metricsRequest("DescribeMetricMetaList", params) - if err != nil { - return 0, nil, errors.Wrap(err, "r.metricsRequest DescribeMetricMetaList") - } - total, _ := body.Int("TotalCount") - res := make([]SMetricMeta, 0) - err = body.Unmarshal(&res, "Resources", "Resource") - if err != nil { - return 0, nil, errors.Wrap(err, "body.Unmarshal Resources Resource") - } - return int(total), res, nil -} - -func (r *SRegion) FetchMetrics(ns string) ([]SMetricMeta, error) { - metrics := make([]SMetricMeta, 0) - total := -1 - for total < 0 || len(metrics) < total { - ntotal, res, err := r.DescribeMetricMetaList(ns, 1000, len(metrics)) - if err != nil { - return nil, errors.Wrap(err, "r.DescribeMetricMetaList") - } - if len(res) == 0 { - break - } - metrics = append(metrics, res...) - total = ntotal - } - return metrics, nil -} - -func (r *SRegion) DescribeMetricList(name string, ns string, since time.Time, until time.Time, nextToken string, dimensions []SResourceLabel) ([]jsonutils.JSONObject, string, error) { - params := make(map[string]string) - params["MetricName"] = name - params["Namespace"] = ns - params["Length"] = "2000" - if len(nextToken) > 0 { - params["NextToken"] = nextToken - } - if !since.IsZero() { - params["StartTime"] = strconv.FormatInt(since.Unix()*1000, 10) - } - if !until.IsZero() { - params["EndTime"] = strconv.FormatInt(until.Unix()*1000, 10) - } - if len(dimensions) > 0 { - for _, dimension := range dimensions { - params[dimension.Name] = dimension.Value - } - } - body, err := r.metricsRequest("DescribeMetricList", params) - if err != nil { - return nil, "", errors.Wrap(err, "region.MetricRequest") - } - nToken, _ := body.GetString("NextToken") - dataStr, _ := body.GetString("Datapoints") - if len(dataStr) == 0 { - return nil, "", nil - } - dataJson, err := jsonutils.ParseString(dataStr) - if err != nil { - return nil, "", errors.Wrap(err, "jsonutils.ParseString") - } - dataArray, err := dataJson.GetArray() - if err != nil { - return nil, "", errors.Wrap(err, "dataJson.GetArray") - } - return dataArray, nToken, nil -} - -type MetricData struct { - Timestamp int64 - BucketName string - InstanceId string - UserId string - Value float64 - Average float64 - Minimum float64 - Maximum float64 - - Diskname string - Device string - - // k8s - Cluster string - Node string - Pod string -} - -func (d MetricData) GetValue() float64 { - if d.Average > 0 { - return d.Average - } - if d.Maximum > 0 { - return d.Maximum - } - if d.Minimum > 0 { - return d.Minimum - } - if d.Value > 0 { - return d.Value - } - return 0.0 -} - -func (d MetricData) GetTags() map[string]string { - ret := map[string]string{} - if len(d.Device) > 0 { - ret[cloudprovider.METRIC_TAG_DEVICE] = fmt.Sprintf("%s(%s)", d.Device, d.Diskname) - } - return ret -} - -func (self *SAliyunClient) ListMetrics(ns, metricName string, start, end time.Time) ([]MetricData, error) { - result := []MetricData{} - nextToken := "" - for { - part, next, err := self.listMetrics(ns, metricName, nextToken, start, end) - if err != nil { - return nil, errors.Wrap(err, "listMetrics") - } - result = append(result, part...) - if len(next) == 0 { - break - } - nextToken = next - } - return result, nil -} - -func (self *SAliyunClient) listMetrics(ns, metricName, nextToken string, start, end time.Time) ([]MetricData, string, error) { - params := make(map[string]string) - params["MetricName"] = metricName - params["Namespace"] = ns - params["Length"] = "2000" - if len(nextToken) > 0 { - params["NextToken"] = nextToken - } - params["StartTime"] = fmt.Sprintf("%d", start.UnixMilli()) - params["EndTime"] = fmt.Sprintf("%d", end.UnixMilli()) - resp, err := self.metricsRequest("DescribeMetricList", params) - if err != nil { - return nil, "", errors.Wrap(err, "DescribeMetricList") - } - ret := struct { - NextToken string - Datapoints string - }{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, "", errors.Wrapf(err, "resp.Unmarshal") - } - obj, err := jsonutils.ParseString(ret.Datapoints) - if err != nil { - return nil, "", errors.Wrap(err, "jsonutils.ParseString") - } - result := []MetricData{} - err = obj.Unmarshal(&result) - if err != nil { - return nil, "", errors.Wrapf(err, "obj.Unmarshal") - } - return result, ret.NextToken, nil -} - -func (r *SRegion) FetchMetricData(name string, ns string, since time.Time, until time.Time) ([]jsonutils.JSONObject, error) { - data := make([]jsonutils.JSONObject, 0) - nextToken := "" - for { - datArray, next, err := r.DescribeMetricList(name, ns, since, until, nextToken, nil) - if err != nil { - return nil, errors.Wrap(err, "r.DescribeMetricList") - } - data = append(data, datArray...) - if len(next) == 0 { - break - } - nextToken = next - } - return data, nil -} - -func (self *SAliyunClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_BUCKET: - return self.GetOssMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: - return self.GetRedisMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_RDS: - return self.GetRdsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_LB: - return self.GetElbMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_K8S: - return self.GetK8sMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) - } -} - -func (self *SAliyunClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricTags, tagKey := map[string]string{}, "" - switch opts.MetricType { - case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: - metricTags = map[string]string{ - "CPUUtilization": "", - } - case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: - metricTags = map[string]string{ - "InternetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, - "IntranetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - } - tagKey = cloudprovider.METRIC_TAG_NET_TYPE - case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: - metricTags = map[string]string{ - "InternetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, - "IntranetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - } - tagKey = cloudprovider.METRIC_TAG_NET_TYPE - case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: - metricTags = map[string]string{ - "DiskReadBPS": "", - } - case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: - metricTags = map[string]string{ - "DiskWriteBPS": "", - } - case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: - metricTags = map[string]string{ - "DiskReadIOPS": "", - } - case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: - metricTags = map[string]string{ - "DiskWriteIOPS": "", - } - case cloudprovider.VM_METRIC_TYPE_MEM_USAGE: - metricTags = map[string]string{ - "memory_usedutilization": "", - } - case cloudprovider.VM_METRIC_TYPE_DISK_USAGE: - metricTags = map[string]string{ - "diskusage_utilization": "", - } - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) - } - ret := []cloudprovider.MetricValues{} - for metric, tag := range metricTags { - result, err := self.ListMetrics("acs_ecs_dashboard", metric, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("ListMetric(%s) error: %v", metric, err) - continue - } - tags := map[string]string{} - if len(tag) > 0 && len(tagKey) > 0 { - tags[tagKey] = tag - } - for i := range result { - dataTag := result[i].GetTags() - for k, v := range tags { - dataTag[k] = v - } - ret = append(ret, cloudprovider.MetricValues{ - Id: result[i].InstanceId, - MetricType: opts.MetricType, - Values: []cloudprovider.MetricValue{ - { - Timestamp: time.UnixMilli(result[i].Timestamp), - Value: result[i].GetValue(), - Tags: dataTag, - }, - }, - }) - } - } - return ret, nil -} - -func (self *SAliyunClient) GetOssMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricTags, tagKey := map[string]string{}, "" - switch opts.MetricType { - case cloudprovider.BUCKET_METRIC_TYPE_LATECY: - metricTags = map[string]string{ - "GetObjectE2eLatency": cloudprovider.METRIC_TAG_REQUST_GET, - "PostObjectE2eLatency": cloudprovider.METRIC_TAG_REQUST_GET, - } - tagKey = cloudprovider.METRIC_TAG_REQUST - case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_TX: - metricTags = map[string]string{ - "InternetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, - "IntranetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - } - tagKey = cloudprovider.METRIC_TAG_REQUST - case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_RX: - metricTags = map[string]string{ - "InternetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, - "IntranetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - } - tagKey = cloudprovider.METRIC_TAG_NET_TYPE - case cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT: - metricTags = map[string]string{ - "GetObjectCount": cloudprovider.METRIC_TAG_REQUST_GET, - "PostObjectCount": cloudprovider.METRIC_TAG_REQUST_POST, - "ServerErrorCount": cloudprovider.METRIC_TAG_REQUST_5XX, - } - tagKey = cloudprovider.METRIC_TAG_REQUST - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) - } - ret := []cloudprovider.MetricValues{} - for metric, tag := range metricTags { - result, err := self.ListMetrics("acs_oss_dashboard", metric, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("ListMetric(%s) error: %v", metric, err) - continue - } - for i := range result { - ret = append(ret, cloudprovider.MetricValues{ - Id: result[i].BucketName, - MetricType: opts.MetricType, - Values: []cloudprovider.MetricValue{ - { - Timestamp: time.UnixMilli(result[i].Timestamp), - Value: result[i].GetValue(), - Tags: map[string]string{ - tagKey: tag, - }, - }, - }, - }) - } - } - return ret, nil -} - -func (self *SAliyunClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metrics := map[cloudprovider.TMetricType]string{ - cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE: "CpuUsage", - cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE: "MemoryUsage", - cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX: "IntranetIn", - cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX: "IntranetOut", - cloudprovider.REDIS_METRIC_TYPE_USED_CONN: "UsedConnection", - cloudprovider.REDIS_METRIC_TYPE_OPT_SES: "UsedQPS", - cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS: "StandardKeys", - cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE: "UsedMemory", - } - metric, ok := metrics[opts.MetricType] - if !ok { - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) - } - ret := []cloudprovider.MetricValues{} - result, err := self.ListMetrics("acs_kvstore", metric, opts.StartTime, opts.EndTime) - if err != nil { - return nil, errors.Wrapf(err, "ListMetric(%s)", metric) - } - for i := range result { - tags := map[string]string{} - if strings.Contains(result[i].InstanceId, "-db-") { - tags[cloudprovider.METRIC_TAG_NODE] = result[i].InstanceId - idx := strings.Index(result[i].InstanceId, "-db-") - result[i].InstanceId = result[i].InstanceId[:idx] - } - value := cloudprovider.MetricValues{ - Id: result[i].InstanceId, - MetricType: opts.MetricType, - Values: []cloudprovider.MetricValue{ - { - Timestamp: time.UnixMilli(result[i].Timestamp), - Value: result[i].GetValue(), - Tags: tags, - }, - }, - } - ret = append(ret, value) - } - return ret, nil -} - -func (self *SAliyunClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricTags := map[string]string{} - switch opts.MetricType { - case cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: - metricTags = map[string]string{ - "CpuUsage": "", - } - case cloudprovider.RDS_METRIC_TYPE_MEM_USAGE: - metricTags = map[string]string{ - "MemoryUsage": "", - } - case cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: - metricTags = map[string]string{ - "MySQL_NetworkInNew": "", - "SQLServer_NetworkInNew": "", - } - case cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: - metricTags = map[string]string{ - "MySQL_NetworkOutNew": "", - "SQLServer_NetworkOutNew": "", - } - case cloudprovider.RDS_METRIC_TYPE_DISK_USAGE: - metricTags = map[string]string{ - "DiskUsage": "", - } - case cloudprovider.RDS_METRIC_TYPE_CONN_USAGE: - metricTags = map[string]string{ - "ConnectionUsage": "", - } - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) - } - ret := []cloudprovider.MetricValues{} - for metric := range metricTags { - result, err := self.ListMetrics("acs_rds_dashboard", metric, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("ListMetric(%s) error: %v", metric, err) - continue - } - for i := range result { - ret = append(ret, cloudprovider.MetricValues{ - Id: result[i].InstanceId, - MetricType: opts.MetricType, - Values: []cloudprovider.MetricValue{ - { - Timestamp: time.UnixMilli(result[i].Timestamp), - Value: result[i].GetValue(), - }, - }, - }) - } - } - return ret, nil -} - -func (self *SAliyunClient) GetElbMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricTags, tagKey := map[string]string{}, "" - switch opts.MetricType { - case cloudprovider.LB_METRIC_TYPE_NET_BPS_RX: - metricTags = map[string]string{ - "InstanceTrafficRX": "", - } - case cloudprovider.LB_METRIC_TYPE_NET_BPS_TX: - metricTags = map[string]string{ - "InstanceTrafficTX": "", - } - case cloudprovider.LB_METRIC_TYPE_HRSP_COUNT: - metricTags = map[string]string{ - "InstanceStatusCode2xx": cloudprovider.METRIC_TAG_REQUST_2XX, - "InstanceStatusCode3xx": cloudprovider.METRIC_TAG_REQUST_3XX, - "InstanceStatusCode4xx": cloudprovider.METRIC_TAG_REQUST_4XX, - "InstanceStatusCode5xx": cloudprovider.METRIC_TAG_REQUST_5XX, - } - tagKey = cloudprovider.METRIC_TAG_REQUST - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) - } - ret := []cloudprovider.MetricValues{} - for metric, tag := range metricTags { - result, err := self.ListMetrics("acs_slb_dashboard", metric, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("ListMetric(%s) error: %v", metric, err) - continue - } - tags := map[string]string{} - if len(tag) > 0 && len(tagKey) > 0 { - tags[tagKey] = tag - } - for i := range result { - ret = append(ret, cloudprovider.MetricValues{ - Id: result[i].InstanceId, - MetricType: opts.MetricType, - Values: []cloudprovider.MetricValue{ - { - Timestamp: time.UnixMilli(result[i].Timestamp), - Value: result[i].GetValue(), - Tags: tags, - }, - }, - }) - } - } - return ret, nil -} - -func (self *SAliyunClient) GetK8sMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricName := "" - switch opts.MetricType { - case cloudprovider.K8S_NODE_METRIC_TYPE_CPU_USAGE: - metricName = "node.cpu.utilization" - case cloudprovider.K8S_NODE_METRIC_TYPE_MEM_USAGE: - metricName = "node.memory.utilization" - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) - } - result, err := self.ListMetrics("acs_k8s", metricName, opts.StartTime, opts.EndTime) - if err != nil { - return nil, errors.Wrapf(err, "ListMetrics(%s)", metricName) - } - ret := []cloudprovider.MetricValues{} - for i := range result { - tags := map[string]string{} - if len(result[i].Node) > 0 { - tags[cloudprovider.METRIC_TAG_NODE] = result[i].Node - } - ret = append(ret, cloudprovider.MetricValues{ - Id: result[i].Cluster, - MetricType: opts.MetricType, - Values: []cloudprovider.MetricValue{ - { - Timestamp: time.UnixMilli(result[i].Timestamp), - Value: result[i].GetValue(), - Tags: tags, - }, - }, - }) - } - return ret, nil -} diff --git a/pkg/multicloud/aliyun/mount_target.go b/pkg/multicloud/aliyun/mount_target.go deleted file mode 100644 index 98ac893ced..0000000000 --- a/pkg/multicloud/aliyun/mount_target.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type ClientMasterNode struct { - EcsIp string - EcsId string - DefaultPasswd string -} - -type ClientMasterNodes struct { - ClientMasterNode []ClientMasterNode -} - -type SMountTarget struct { - fs *SFileSystem - - Status string - NetworkType string - VswId string - VpcId string - MountTargetDomain string - AccessGroup string - ClientMasterNodes ClientMasterNodes -} - -func (self *SMountTarget) GetGlobalId() string { - return self.MountTargetDomain -} - -func (self *SMountTarget) GetName() string { - return self.MountTargetDomain -} - -func (self *SMountTarget) GetNetworkType() string { - return strings.ToLower(self.NetworkType) -} - -func (self *SMountTarget) GetStatus() string { - switch self.Status { - case "Active": - return api.MOUNT_TARGET_STATUS_AVAILABLE - case "Inactive": - return api.MOUNT_TARGET_STATUS_UNAVAILABLE - case "Pending": - return api.MOUNT_TARGET_STATUS_CREATING - case "Deleting": - return api.MOUNT_TARGET_STATUS_DELETING - default: - return strings.ToLower(self.Status) - } -} - -func (self *SMountTarget) GetVpcId() string { - return self.VpcId -} - -func (self *SMountTarget) GetNetworkId() string { - return self.VswId -} - -func (self *SMountTarget) GetDomainName() string { - return self.MountTargetDomain -} - -func (self *SMountTarget) GetAccessGroupId() string { - return fmt.Sprintf("%s/%s", self.fs.FileSystemType, self.AccessGroup) -} - -func (self *SMountTarget) Delete() error { - return self.fs.region.DeleteMountTarget(self.fs.FileSystemId, self.MountTargetDomain) -} - -func (self *SRegion) GetMountTargets(fsId, domainName string, pageSize, pageNum int) ([]SMountTarget, int, error) { - if pageSize < 1 || pageSize > 100 { - pageSize = 50 - } - if pageNum < 1 { - pageNum = 1 - } - params := map[string]string{ - "RegionId": self.RegionId, - "FileSystemId": fsId, - "PageSize": fmt.Sprintf("%d", pageSize), - "PageNumber": fmt.Sprintf("%d", pageNum), - } - if len(domainName) > 0 { - params["MountTargetDomain"] = domainName - } - resp, err := self.nasRequest("DescribeMountTargets", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeMountTargets") - } - ret := struct { - TotalCount int - MountTargets struct { - MountTarget []SMountTarget - } - }{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - return ret.MountTargets.MountTarget, ret.TotalCount, nil -} - -func (self *SFileSystem) GetMountTargets() ([]cloudprovider.ICloudMountTarget, error) { - targets := []SMountTarget{} - num := 1 - for { - part, total, err := self.region.GetMountTargets(self.FileSystemId, "", 50, num) - if err != nil { - return nil, errors.Wrapf(err, "GetMountTargets") - } - targets = append(targets, part...) - if len(part) >= total { - break - } - } - ret := []cloudprovider.ICloudMountTarget{} - for i := range targets { - targets[i].fs = self - ret = append(ret, &targets[i]) - } - return ret, nil -} - -func (self *SRegion) DeleteMountTarget(fsId, id string) error { - params := map[string]string{ - "RegionId": self.RegionId, - "FileSystemId": fsId, - "MountTargetDomain": id, - } - _, err := self.nasRequest("DeleteMountTarget", params) - return errors.Wrapf(err, "DeleteMountTarget") -} diff --git a/pkg/multicloud/aliyun/natdtable.go b/pkg/multicloud/aliyun/natdtable.go deleted file mode 100644 index 1d843b36de..0000000000 --- a/pkg/multicloud/aliyun/natdtable.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strconv" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SForwardTableEntry struct { - multicloud.SResourceBase - multicloud.AliyunTags - nat *SNatGateway - - ForwardEntryId string - ForwardEntryName string - IpProtocol string - Status string - ExternalIp string - ForwardTableId string - ExternalPort string - InternalPort string - InternalIp string -} - -func (dtable *SForwardTableEntry) GetName() string { - if len(dtable.ForwardEntryName) > 0 { - return dtable.ForwardEntryName - } - return dtable.ForwardEntryId -} - -func (dtable *SForwardTableEntry) GetId() string { - return dtable.ForwardEntryId -} - -func (dtable *SForwardTableEntry) GetGlobalId() string { - return dtable.ForwardEntryId -} - -func (dtable *SForwardTableEntry) GetStatus() string { - switch dtable.Status { - case "Available": - return api.NAT_STAUTS_AVAILABLE - default: - return api.NAT_STATUS_UNKNOWN - } -} - -func (dtable *SForwardTableEntry) GetIpProtocol() string { - return dtable.IpProtocol -} - -func (dtable *SForwardTableEntry) GetExternalIp() string { - return dtable.ExternalIp -} - -func (dtable *SForwardTableEntry) GetExternalPort() int { - port, _ := strconv.Atoi(dtable.ExternalPort) - return port -} - -func (dtable *SForwardTableEntry) GetInternalIp() string { - return dtable.InternalIp -} - -func (dtable *SForwardTableEntry) GetInternalPort() int { - port, _ := strconv.Atoi(dtable.InternalPort) - return port -} - -func (region *SRegion) GetAllDTables(tableId string) ([]SForwardTableEntry, error) { - dtables := []SForwardTableEntry{} - for { - part, total, err := region.GetForwardTableEntries(tableId, len(dtables), 50) - if err != nil { - return nil, err - } - dtables = append(dtables, part...) - if len(dtables) >= total { - break - } - } - return dtables, nil -} - -func (dtable *SForwardTableEntry) Delete() error { - return dtable.nat.vpc.region.DeleteForwardTableEntry(dtable.ForwardTableId, dtable.GetId()) -} - -func (region *SRegion) GetForwardTableEntries(tableId string, offset int, limit int) ([]SForwardTableEntry, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - params["ForwardTableId"] = tableId - - body, err := region.vpcRequest("DescribeForwardTableEntries", params) - if err != nil { - return nil, 0, err - } - - dtables := []SForwardTableEntry{} - err = body.Unmarshal(&dtables, "ForwardTableEntries", "ForwardTableEntry") - if err != nil { - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return dtables, int(total), nil -} - -func (region *SRegion) GetForwardTableEntry(tableID, forwardEntryID string) (SForwardTableEntry, error) { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["ForwardTableId"] = tableID - params["ForwardEntryId"] = forwardEntryID - body, err := region.vpcRequest("DescribeForwardTableEntries", params) - if err != nil { - return SForwardTableEntry{}, err - } - - dtables := []SForwardTableEntry{} - err = body.Unmarshal(&dtables, "ForwardTableEntries", "ForwardTableEntry") - if err != nil { - return SForwardTableEntry{}, err - } - if len(dtables) == 0 { - return SForwardTableEntry{}, cloudprovider.ErrNotFound - } - return dtables[0], nil -} - -func (region *SRegion) DeleteForwardTableEntry(tableId string, entryId string) error { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["ForwardTableId"] = tableId - params["ForwardEntryId"] = entryId - _, err := region.vpcRequest("DeleteForwardEntry", params) - return err -} - -func (region *SRegion) CreateForwardTableEntry(rule cloudprovider.SNatDRule, tableID string) (string, error) { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["ForwardTableId"] = tableID - params["ExternalIp"] = rule.ExternalIP - params["ExternalPort"] = strconv.Itoa(rule.ExternalPort) - params["InternalIp"] = rule.InternalIP - params["InternalPort"] = strconv.Itoa(rule.InternalPort) - params["IpProtocol"] = rule.Protocol - body, err := region.vpcRequest("CreateForwardEntry", params) - if err != nil { - return "", err - } - - entryID, _ := body.GetString("ForwardEntryId") - return entryID, nil -} - -func (dtable *SForwardTableEntry) Refresh() error { - new, err := dtable.nat.vpc.region.GetForwardTableEntry(dtable.ForwardTableId, dtable.ForwardEntryId) - if err != nil { - return err - } - return jsonutils.Update(dtable, new) -} diff --git a/pkg/multicloud/aliyun/natgateway.go b/pkg/multicloud/aliyun/natgateway.go deleted file mode 100644 index 8f388f2faa..0000000000 --- a/pkg/multicloud/aliyun/natgateway.go +++ /dev/null @@ -1,381 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SBandwidthPackageIds struct { - BandwidthPackageId []string -} - -type SForwardTableIds struct { - ForwardTableId []string -} - -type SSnatTableIds struct { - SnatTableId []string -} - -type NatGatewayPrivateInfo struct { - EniInstanceId string - IzNo string - MaxBandwidth int - PrivateIpAddress string - VswitchId string -} - -type SNatGateway struct { - multicloud.SNatGatewayBase - multicloud.AliyunTags - - vpc *SVpc - - BandwidthPackageIds SBandwidthPackageIds - BusinessStatus string - CreationTime time.Time - ExpiredTime time.Time - Description string - ForwardTableIds SForwardTableIds - SnatTableIds SSnatTableIds - InstanceChargeType TChargeType - Name string - NatGatewayId string - RegionId string - Spec string - Status string - VpcId string - NatGatewayPrivateInfo NatGatewayPrivateInfo -} - -func (nat *SNatGateway) GetId() string { - return nat.NatGatewayId -} - -func (nat *SNatGateway) GetGlobalId() string { - return nat.NatGatewayId -} - -func (nat *SNatGateway) GetName() string { - if len(nat.Name) > 0 { - return nat.Name - } - return nat.NatGatewayId -} - -func (nat *SNatGateway) GetStatus() string { - switch nat.Status { - case "Initiating": - return api.NAT_STATUS_ALLOCATE - case "Available": - return api.NAT_STAUTS_AVAILABLE - case "Pending": - return api.NAT_STATUS_DEPLOYING - default: - return api.NAT_STATUS_UNKNOWN - } -} - -func (self *SNatGateway) GetINetworkId() string { - return self.NatGatewayPrivateInfo.VswitchId -} - -func (self *SNatGateway) GetIpAddr() string { - return self.NatGatewayPrivateInfo.PrivateIpAddress -} - -func (self *SNatGateway) GetBandwidthMb() int { - return self.NatGatewayPrivateInfo.MaxBandwidth -} - -func (self *SNatGateway) Delete() error { - return self.vpc.region.DeleteNatGateway(self.NatGatewayId, false) -} - -func (nat *SNatGateway) GetBillingType() string { - return convertChargeType(nat.InstanceChargeType) -} - -func (nat *SNatGateway) GetNatSpec() string { - if len(nat.Spec) == 0 { - return api.ALIYUN_NAT_SKU_DEFAULT - } - return nat.Spec -} - -func (self *SNatGateway) Refresh() error { - nat, total, err := self.vpc.region.GetNatGateways("", self.NatGatewayId, 0, 1) - if err != nil { - return errors.Wrapf(err, "GetNatGateways") - } - if total > 1 { - return errors.Wrapf(cloudprovider.ErrDuplicateId, "get %d natgateways by id %s", total, self.NatGatewayId) - } - if total == 0 { - return errors.Wrapf(cloudprovider.ErrNotFound, self.NatGatewayId) - } - return jsonutils.Update(self, nat[0]) -} - -func (nat *SNatGateway) GetCreatedAt() time.Time { - return nat.CreationTime -} - -func (nat *SNatGateway) GetExpiredAt() time.Time { - return nat.ExpiredTime -} - -func (nat *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips := []SEipAddress{} - for { - parts, total, err := nat.vpc.region.GetEips("", nat.NatGatewayId, "", len(eips), 50) - if err != nil { - return nil, err - } - eips = append(eips, parts...) - if len(eips) >= total { - break - } - } - ieips := []cloudprovider.ICloudEIP{} - for i := 0; i < len(eips); i++ { - eips[i].region = nat.vpc.region - ieips = append(ieips, &eips[i]) - } - return ieips, nil -} - -func (nat *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { - itables := []cloudprovider.ICloudNatDEntry{} - for _, dtableId := range nat.ForwardTableIds.ForwardTableId { - dtables, err := nat.vpc.region.GetAllDTables(dtableId) - if err != nil { - return nil, err - } - for i := 0; i < len(dtables); i++ { - dtables[i].nat = nat - itables = append(itables, &dtables[i]) - } - } - return itables, nil -} - -func (nat *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { - stables, err := nat.getSnatEntries() - if err != nil { - return nil, err - } - itables := []cloudprovider.ICloudNatSEntry{} - for i := 0; i < len(stables); i++ { - stables[i].nat = nat - itables = append(itables, &stables[i]) - } - return itables, nil -} - -func (nat *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { - dNATEntry, err := nat.vpc.region.GetForwardTableEntry(nat.ForwardTableIds.ForwardTableId[0], id) - if err != nil { - return nil, cloudprovider.ErrNotFound - } - dNATEntry.nat = nat - return &dNATEntry, nil -} - -func (nat *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { - sNATEntry, err := nat.vpc.region.GetSNATEntry(nat.SnatTableIds.SnatTableId[0], id) - if err != nil { - return nil, cloudprovider.ErrNotFound - } - sNATEntry.nat = nat - return &sNATEntry, nil -} - -func (nat *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { - entryID, err := nat.vpc.region.CreateForwardTableEntry(rule, nat.ForwardTableIds.ForwardTableId[0]) - if err != nil { - return nil, errors.Wrapf(err, `create dnat rule for nat gateway %q`, nat.GetId()) - } - return nat.GetINatDEntryByID(entryID) -} - -func (nat *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { - entryID, err := nat.vpc.region.CreateSNATTableEntry(rule, nat.SnatTableIds.SnatTableId[0]) - if err != nil { - return nil, errors.Wrapf(err, `create snat rule for nat gateway %q`, nat.GetId()) - } - return nat.GetINatSEntryByID(entryID) -} - -func (self *SRegion) GetNatGateways(vpcId string, natGwId string, offset, limit int) ([]SNatGateway, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - if len(vpcId) > 0 { - params["VpcId"] = vpcId - } - if len(natGwId) > 0 { - params["NatGatewayId"] = natGwId - } - - body, err := self.vpcRequest("DescribeNatGateways", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeNatGateways") - } - - if self.client.debug { - log.Debugf("%s", body.PrettyString()) - } - - gateways := make([]SNatGateway, 0) - err = body.Unmarshal(&gateways, "NatGateways", "NatGateway") - if err != nil { - return nil, 0, errors.Wrapf(err, "body.Unmarshal") - } - total, _ := body.Int("TotalCount") - return gateways, int(total), nil -} - -func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { - nat, err := self.region.CreateNatGateway(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateNatGateway") - } - nat.vpc = self - return nat, nil -} - -func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGateway, error) { - params := map[string]string{ - "RegionId": self.RegionId, - "VpcId": opts.VpcId, - "VSwitchId": opts.NetworkId, - "NatType": "Enhanced", - "Name": opts.Name, - "Description": opts.Desc, - "ClientToken": utils.GenRequestId(20), - "InstanceChargeType": "PostPaid", - "InternetChargeType": "PayBySpec", - } - if len(opts.NatSpec) == 0 || opts.NatSpec == api.ALIYUN_NAT_SKU_DEFAULT { - params["InternetChargeType"] = "PayByLcu" - } else { - params["Spec"] = opts.NatSpec - } - - if opts.BillingCycle != nil { - params["InstanceChargeType"] = "PrePaid" - params["PricingCycle"] = "Month" - params["AutoPay"] = "false" - if opts.BillingCycle.GetYears() > 0 { - params["PricingCycle"] = "Year" - params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetYears()) - } else if opts.BillingCycle.GetMonths() > 0 { - params["PricingCycle"] = "Year" - params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetMonths()) - } - if opts.BillingCycle.AutoRenew { - params["AutoPay"] = "true" - } - } - resp, err := self.vpcRequest("CreateNatGateway", params) - if err != nil { - return nil, errors.Wrapf(err, "CreateNatGateway") - } - natId, err := resp.GetString("NatGatewayId") - if err != nil { - return nil, errors.Wrapf(err, "resp.Get(NatGatewayId)") - } - if len(natId) == 0 { - return nil, errors.Errorf("empty NatGatewayId after created") - } - - var nat *SNatGateway = nil - err = cloudprovider.Wait(time.Second*5, time.Minute*15, func() (bool, error) { - nats, total, err := self.GetNatGateways("", natId, 0, 1) - if err != nil { - return false, errors.Wrapf(err, "GetNatGateways(%s)", natId) - } - if total > 1 { - return false, errors.Wrapf(cloudprovider.ErrDuplicateId, "get %d nats", total) - } - if total == 0 { - return false, errors.Wrapf(cloudprovider.ErrNotFound, "search %s after %s created", opts.Name, natId) - } - nat = &nats[0] - return true, nil - }) - if err != nil { - return nil, errors.Wrapf(err, "cloudprovider.Wait") - } - - return nat, nil -} - -func (self *SRegion) DeleteNatGateway(natId string, isForce bool) error { - params := map[string]string{ - "RegionId": self.RegionId, - "NatGatewayId": natId, - } - if isForce { - params["Force"] = "true" - } - _, err := self.vpcRequest("DeleteNatGateway", params) - return errors.Wrapf(err, "DeleteNatGateway") -} - -func (self *SNatGateway) GetTags() (map[string]string, error) { - _, tags, err := self.vpc.region.ListSysAndUserTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.NatGatewayId) - if err != nil { - return nil, errors.Wrapf(err, "ListTags") - } - tagMaps := map[string]string{} - for k, v := range tags { - tagMaps[strings.ToLower(k)] = v - } - return tagMaps, nil -} - -func (self *SNatGateway) GetSysTags() map[string]string { - tags, _, err := self.vpc.region.ListSysAndUserTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.NatGatewayId) - if err != nil { - return nil - } - tagMaps := map[string]string{} - for k, v := range tags { - tagMaps[strings.ToLower(k)] = v - } - return tagMaps -} - -func (self *SNatGateway) SetTags(tags map[string]string, replace bool) error { - return self.vpc.region.SetResourceTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.GetId(), tags, replace) -} diff --git a/pkg/multicloud/aliyun/natstable.go b/pkg/multicloud/aliyun/natstable.go deleted file mode 100644 index eba3841c47..0000000000 --- a/pkg/multicloud/aliyun/natstable.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSNATTableEntry struct { - multicloud.SResourceBase - multicloud.AliyunTags - nat *SNatGateway - - SnatEntryId string - SnatEntryName string - SnatIp string - SnatTableId string `json:"snat_table_id"` - SourceCIDR string `json:"source_cidr"` - SourceVSwitchId string `json:"source_vswitch_id"` - Status string -} - -func (stable *SSNATTableEntry) GetName() string { - if len(stable.SnatEntryName) > 0 { - return stable.SnatEntryName - } - return stable.SnatEntryId -} - -func (stable *SSNATTableEntry) GetId() string { - return stable.SnatEntryId -} - -func (stable *SSNATTableEntry) GetGlobalId() string { - return stable.SnatEntryId -} - -func (stable *SSNATTableEntry) GetStatus() string { - switch stable.Status { - case "Available": - return api.NAT_STAUTS_AVAILABLE - default: - return api.NAT_STATUS_UNKNOWN - } -} - -func (stable *SSNATTableEntry) GetIP() string { - return stable.SnatIp -} - -func (stable *SSNATTableEntry) GetSourceCIDR() string { - return stable.SourceCIDR -} - -func (stable *SSNATTableEntry) GetNetworkId() string { - return stable.SourceVSwitchId -} - -func (stable *SSNATTableEntry) Delete() error { - return stable.nat.vpc.region.DeleteSnatEntry(stable.SnatTableId, stable.GetId()) -} - -func (self *SRegion) GetSNATEntries(tableId string, offset, limit int) ([]SSNATTableEntry, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - params["SnatTableId"] = tableId - - body, err := self.vpcRequest("DescribeSnatTableEntries", params) - if err != nil { - log.Errorf("DescribeSnatTableEntries fail %s", err) - return nil, 0, err - } - - if self.client.debug { - log.Debugf("%s", body.PrettyString()) - } - - entries := make([]SSNATTableEntry, 0) - err = body.Unmarshal(&entries, "SnatTableEntries", "SnatTableEntry") - if err != nil { - log.Errorf("Unmarshal entries fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return entries, int(total), nil -} - -func (self *SRegion) GetSNATEntry(tableID, SNATEntryID string) (SSNATTableEntry, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SnatTableId"] = tableID - params["SnatEntryId"] = SNATEntryID - - body, err := self.vpcRequest("DescribeSnatTableEntries", params) - if err != nil { - log.Errorf("DescribeSnatTableEntries fail %s", err) - return SSNATTableEntry{}, err - } - - if self.client.debug { - log.Debugf("%s", body.PrettyString()) - } - - entries := make([]SSNATTableEntry, 0) - err = body.Unmarshal(&entries, "SnatTableEntries", "SnatTableEntry") - if err != nil { - log.Errorf("Unmarshal entries fail %s", err) - return SSNATTableEntry{}, err - } - if len(entries) == 0 { - return SSNATTableEntry{}, cloudprovider.ErrNotFound - } - return entries[0], nil - -} - -func (region *SRegion) CreateSNATTableEntry(rule cloudprovider.SNatSRule, tableID string) (string, error) { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["SnatTableId"] = tableID - params["SnatIp"] = rule.ExternalIP - if len(rule.NetworkID) != 0 { - params["SourceVSwitchId"] = rule.NetworkID - } - if len(rule.SourceCIDR) != 0 { - params["SourceCIDR"] = rule.SourceCIDR - } - body, err := region.vpcRequest("CreateSnatEntry", params) - if err != nil { - return "", err - } - - entryID, _ := body.GetString("SnatEntryId") - return entryID, nil -} - -func (region *SRegion) DeleteSnatEntry(tableId string, entryId string) error { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["SnatTableId"] = tableId - params["SnatEntryId"] = entryId - _, err := region.vpcRequest("DeleteSnatEntry", params) - return err -} - -func (nat *SNatGateway) getSnatEntriesForTable(tblId string) ([]SSNATTableEntry, error) { - entries := make([]SSNATTableEntry, 0) - entryTotal := -1 - for entryTotal < 0 || len(entries) < entryTotal { - parts, total, err := nat.vpc.region.GetSNATEntries(tblId, len(entries), 50) - if err != nil { - return nil, err - } - if len(parts) > 0 { - entries = append(entries, parts...) - } - entryTotal = total - } - return entries, nil -} - -func (nat *SNatGateway) getSnatEntries() ([]SSNATTableEntry, error) { - entries := make([]SSNATTableEntry, 0) - for i := range nat.SnatTableIds.SnatTableId { - sentries, err := nat.getSnatEntriesForTable(nat.SnatTableIds.SnatTableId[i]) - if err != nil { - return nil, err - } - entries = append(entries, sentries...) - } - return entries, nil -} - -func (nat *SNatGateway) dissociateWithVswitch(vswitchId string) error { - entries, err := nat.getSnatEntries() - if err != nil { - return err - } - for i := range entries { - log.Debugf("%v", entries[i]) - if entries[i].SourceVSwitchId == vswitchId { - err := nat.vpc.region.DeleteSnatEntry(entries[i].SnatTableId, entries[i].SnatEntryId) - if err != nil { - return err - } - } - } - return nil -} - -func (stable *SSNATTableEntry) Refresh() error { - new, err := stable.nat.vpc.region.GetSNATEntry(stable.SnatTableId, stable.SnatEntryId) - if err != nil { - return err - } - return jsonutils.Update(stable, new) -} diff --git a/pkg/multicloud/aliyun/networkinterfaces.go b/pkg/multicloud/aliyun/networkinterfaces.go deleted file mode 100644 index 297aaf8618..0000000000 --- a/pkg/multicloud/aliyun/networkinterfaces.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SPrivateIp struct { - nic *SNetworkInterface - Primary bool - PrivateIpAddress string -} - -func (ip *SPrivateIp) GetGlobalId() string { - return ip.PrivateIpAddress -} - -func (ip *SPrivateIp) GetINetworkId() string { - return ip.nic.VSwitchId -} - -func (ip *SPrivateIp) GetIP() string { - return ip.PrivateIpAddress -} - -func (ip *SPrivateIp) IsPrimary() bool { - return ip.Primary -} - -type SPrivateIpSets struct { - PrivateIpSet []SPrivateIp -} - -type SNetworkInterface struct { - multicloud.SNetworkInterfaceBase - multicloud.AliyunTags - region *SRegion - - InstanceId string - CreationTime time.Time - MacAddress string - NetworkInterfaceName string - PrivateIpSets SPrivateIpSets - ResourceGroupId string - SecurityGroupIds SSecurityGroupIds - Status string - Type string - VSwitchId string - VpcId string - ZoneId string - NetworkInterfaceId string - PrimaryIpAddress string - PrivateIpAddress string -} - -func (nic *SNetworkInterface) GetName() string { - return nic.NetworkInterfaceName -} - -func (nic *SNetworkInterface) GetId() string { - return nic.NetworkInterfaceId -} - -func (nic *SNetworkInterface) GetGlobalId() string { - return nic.NetworkInterfaceId -} - -func (nic *SNetworkInterface) GetAssociateId() string { - return nic.InstanceId -} - -func (nic *SNetworkInterface) GetAssociateType() string { - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER -} - -func (nic *SNetworkInterface) GetMacAddress() string { - return nic.MacAddress -} - -func (nic *SNetworkInterface) GetStatus() string { - switch nic.Status { - case "Available": - return api.NETWORK_INTERFACE_STATUS_AVAILABLE - } - return nic.Status -} - -func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { - interfaces := []SNetworkInterface{} - for { - parts, total, err := region.GetNetworkInterfaces("", len(interfaces), 50) - if err != nil { - return nil, err - } - interfaces = append(interfaces, parts...) - if len(interfaces) >= total { - break - } - } - ret := []cloudprovider.ICloudNetworkInterface{} - for i := 0; i < len(interfaces); i++ { - // 阿里云实例的弹性网卡已经在guestnetwork同步了 - if len(interfaces[i].InstanceId) == 0 { - interfaces[i].region = region - ret = append(ret, &interfaces[i]) - } - } - return ret, nil -} - -func (nic *SNetworkInterface) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { - address := []cloudprovider.ICloudInterfaceAddress{} - for i := 0; i < len(nic.PrivateIpSets.PrivateIpSet); i++ { - nic.PrivateIpSets.PrivateIpSet[i].nic = nic - address = append(address, &nic.PrivateIpSets.PrivateIpSet[i]) - } - return address, nil -} - -func (region *SRegion) GetNetworkInterfaces(instanceId string, offset int, limit int) ([]SNetworkInterface, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - - params := map[string]string{ - "RegionId": region.RegionId, - "PageSize": fmt.Sprintf("%d", limit), - "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), - } - - if len(instanceId) > 0 { - params["InstanceId"] = instanceId - } - - body, err := region.ecsRequest("DescribeNetworkInterfaces", params) - if err != nil { - return nil, 0, errors.Wrap(err, "DescribeNetworkInterfaces") - } - - interfaces := []SNetworkInterface{} - err = body.Unmarshal(&interfaces, "NetworkInterfaceSets", "NetworkInterfaceSet") - if err != nil { - return nil, 0, errors.Wrap(err, "Unmarshal") - } - total, _ := body.Int("TotalCount") - return interfaces, int(total), nil -} diff --git a/pkg/multicloud/aliyun/objects.go b/pkg/multicloud/aliyun/objects.go deleted file mode 100644 index 56b236d564..0000000000 --- a/pkg/multicloud/aliyun/objects.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "net/http" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - OSS_META_HEADER = "x-oss-meta-" -) - -type SObject struct { - bucket *SBucket - - cloudprovider.SBaseCloudObject -} - -func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { - return o.bucket -} - -func (o *SObject) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - osscli, err := o.bucket.region.GetOssClient() - if err != nil { - log.Errorf("o.bucket.region.GetOssClient error %s", err) - return acl - } - bucket, err := osscli.Bucket(o.bucket.Name) - if err != nil { - log.Errorf("osscli.Bucket error %s", err) - return acl - } - result, err := bucket.GetObjectACL(o.Key) - if err != nil { - log.Errorf("bucket.GetObjectACL error %s", err) - return acl - } - if result.ACL == string(oss.ACLDefault) { - return o.bucket.GetAcl() - } - acl = cloudprovider.TBucketACLType(result.ACL) - return acl -} - -func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { - acl, err := str2Acl(string(aclStr)) - if err != nil { - return errors.Wrap(err, "str2Acl") - } - osscli, err := o.bucket.region.GetOssClient() - if err != nil { - return errors.Wrap(err, "o.bucket.region.GetOssClient") - } - bucket, err := osscli.Bucket(o.bucket.Name) - if err != nil { - return errors.Wrap(err, "osscli.Bucket") - } - err = bucket.SetObjectACL(o.Key, acl) - if err != nil { - return errors.Wrap(err, "bucket.SetObjectACL") - } - return nil -} - -func (o *SObject) GetMeta() http.Header { - if o.Meta != nil { - return o.Meta - } - osscli, err := o.bucket.region.GetOssClient() - if err != nil { - log.Errorf("o.bucket.region.GetOssClient error %s", err) - return nil - } - bucket, err := osscli.Bucket(o.bucket.Name) - if err != nil { - log.Errorf("osscli.Bucket error %s", err) - return nil - } - result, err := bucket.GetObjectDetailedMeta(o.Key) - if err != nil { - log.Errorf("bucket.GetObjectACL error %s", err) - return nil - } - o.Meta = cloudprovider.FetchMetaFromHttpHeader(OSS_META_HEADER, result) - return o.Meta -} - -func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { - return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) -} diff --git a/pkg/multicloud/aliyun/private_zone.go b/pkg/multicloud/aliyun/private_zone.go deleted file mode 100644 index 933776b741..0000000000 --- a/pkg/multicloud/aliyun/private_zone.go +++ /dev/null @@ -1,405 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "strconv" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var allowedTtls = []int64{5, 10, 15, 20, 30, 60, 120, 300, 600, 1800, 3600, 43200, 86400} - -type SPvtzVpc struct { - VpcID string `json:"VpcId"` - RegionName string `json:"RegionName"` - VpcName string `json:"VpcName"` - RegionID string `json:"RegionId"` -} - -type SPvtzBindVpcs struct { - Vpc []SPvtzVpc `json:"Vpc"` -} - -type SPrivateZone struct { - multicloud.SResourceBase - multicloud.AliyunTags - client *SAliyunClient - - // RequestID string `json:"RequestId"` - ZoneID string `json:"ZoneId"` - SlaveDNS string `json:"SlaveDns"` - ResourceGroupID string `json:"ResourceGroupId"` - ProxyPattern string `json:"ProxyPattern"` - CreateTime string `json:"CreateTime"` - Remark string `json:"Remark"` - ZoneName string `json:"ZoneName"` - UpdateTime string `json:"UpdateTime"` - UpdateTimestamp string `json:"UpdateTimestamp"` - RecordCount int `json:"RecordCount"` - CreateTimestamp int64 `json:"CreateTimestamp"` - BindVpcs SPvtzBindVpcs `json:"BindVpcs"` - IsPtr bool `json:"IsPtr"` -} - -// list return -type sPrivateZones struct { - Zone []SPrivateZone `json:"Zone"` -} - -type SPrivateZones struct { - RequestID string `json:"RequestId"` - PageSize int `json:"PageSize"` - PageNumber int `json:"PageNumber"` - TotalPages int `json:"TotalPages"` - TotalItems int `json:"TotalItems"` - Zones sPrivateZones `json:"Zones"` -} - -// https://help.aliyun.com/document_detail/66243.html?spm=a2c4g.11186623.6.580.761357982tMV0Q -func (client *SAliyunClient) DescribeZones(pageNumber int, pageSize int) (SPrivateZones, error) { - sZones := SPrivateZones{} - params := map[string]string{} - params["Action"] = "DescribeZones" - params["PageNumber"] = strconv.Itoa(pageNumber) - params["PageSize"] = strconv.Itoa(pageSize) - resp, err := client.pvtzRequest("DescribeZones", params) - if err != nil { - return sZones, errors.Wrap(err, "DescribeZones") - } - err = resp.Unmarshal(&sZones) - if err != nil { - return sZones, errors.Wrap(err, "resp.Unmarshal") - } - return sZones, nil -} - -// 没有vpc等详细信息 -func (client *SAliyunClient) GetAllZones() ([]SPrivateZone, error) { - pageNumber := 0 - szones := []SPrivateZone{} - for { - pageNumber++ - zones, err := client.DescribeZones(pageNumber, 20) - if err != nil { - return nil, errors.Wrapf(err, "client.DescribeZones(%d, 20)", pageNumber) - } - szones = append(szones, zones.Zones.Zone...) - if len(szones) >= zones.TotalItems { - break - } - } - return szones, nil -} - -func (client *SAliyunClient) GetAllZonesInfo() ([]SPrivateZone, error) { - spvtzs := []SPrivateZone{} - szones, err := client.GetAllZones() - if err != nil { - return nil, errors.Wrap(err, "client.GetAllZones()") - } - for i := 0; i < len(szones); i++ { - spvtz, err := client.DescribeZoneInfo(szones[i].ZoneID) - if err != nil { - return nil, errors.Wrapf(err, "client.DescribeZoneInfo(%s)", szones[i].ZoneID) - } - spvtzs = append(spvtzs, *spvtz) - } - return spvtzs, nil -} - -func (client *SAliyunClient) GetPrivateICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { - izones := []cloudprovider.ICloudDnsZone{} - szones, err := client.GetAllZonesInfo() - if err != nil { - return nil, errors.Wrap(err, "client.GetAllZonesInfo()") - } - for i := 0; i < len(szones); i++ { - izones = append(izones, &szones[i]) - } - return izones, nil -} - -func (client *SAliyunClient) DescribeZoneInfo(zoneId string) (*SPrivateZone, error) { - params := map[string]string{} - params["Action"] = "DescribeZoneInfo" - params["ZoneId"] = zoneId - resp, err := client.pvtzRequest("DescribeZoneInfo", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeZoneInfo") - } - sZone := &SPrivateZone{client: client} - err = resp.Unmarshal(sZone) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return sZone, nil -} - -func (client *SAliyunClient) GetPrivateICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { - pvtzs, err := client.GetAllZones() - if err != nil { - return nil, errors.Wrap(err, "client.GetAllZones()") - } - index := -1 - for i := 0; i < len(pvtzs); i++ { - if pvtzs[i].ZoneID == id { - index = i - break - } - } - if index < 0 || index >= len(pvtzs) { - return nil, cloudprovider.ErrNotFound - } - izone, err := client.DescribeZoneInfo(id) - if err != nil { - return nil, errors.Wrapf(err, "client.DescribeZoneInfo(%s)", id) - } - return izone, nil -} - -func (client *SAliyunClient) DeleteZone(zoneId string) error { - params := map[string]string{} - params["Action"] = "DeleteZone" - params["ZoneId"] = zoneId - _, err := client.pvtzRequest("DeleteZone", params) - if err != nil { - return errors.Wrap(err, "DeleteZone") - } - return nil -} - -func (client *SAliyunClient) AddZone(zoneName string) (string, error) { - params := map[string]string{} - params["Action"] = "AddZone" - params["ZoneName"] = zoneName - ret, err := client.pvtzRequest("AddZone", params) - if err != nil { - return "", errors.Wrap(err, "AddZone") - } - zoneId := "" - return zoneId, ret.Unmarshal(&zoneId, "ZoneId") -} - -func (client *SAliyunClient) CreateZone(opts *cloudprovider.SDnsZoneCreateOptions) (*SPrivateZone, error) { - zoneId, err := client.AddZone(opts.Name) - if err != nil { - return nil, errors.Wrapf(err, "client.AddZone(%s)", opts.Name) - } - err = client.BindZoneVpcs(zoneId, opts.Vpcs) - if err != nil { - return nil, errors.Wrapf(err, " client.BindZoneVpcs(%s,%s)", zoneId, jsonutils.Marshal(opts.Vpcs).String()) - } - return client.DescribeZoneInfo(zoneId) -} - -func (client *SAliyunClient) CreatePrivateICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { - izone, err := client.CreateZone(opts) - if err != nil { - return nil, errors.Wrapf(err, "client.CreateZone(%s)", jsonutils.Marshal(opts).String()) - } - return izone, nil -} - -func (client *SAliyunClient) BindZoneVpc(ZoneId string, vpc *cloudprovider.SPrivateZoneVpc) error { - params := map[string]string{} - params["Action"] = "BindZoneVpc" - params["ZoneId"] = ZoneId - params["Vpcs.1.RegionId"] = vpc.RegionId - params["Vpcs.1.VpcId"] = vpc.Id - _, err := client.pvtzRequest("BindZoneVpc", params) - if err != nil { - return errors.Wrap(err, "BindZoneVpc") - } - return nil -} - -func (client *SAliyunClient) BindZoneVpcs(zoneId string, vpc []cloudprovider.SPrivateZoneVpc) error { - params := map[string]string{} - params["Action"] = "BindZoneVpc" - params["ZoneId"] = zoneId - index := "" - for i := 0; i < len(vpc); i++ { - index = strconv.Itoa(i + 1) - params["Vpcs."+index+".RegionId"] = vpc[i].RegionId - params["Vpcs."+index+".VpcId"] = vpc[i].Id - } - _, err := client.pvtzRequest("BindZoneVpc", params) - if err != nil { - return errors.Wrap(err, "BindZoneVpc") - } - return nil -} - -func (client *SAliyunClient) UnBindZoneVpcs(zoneId string) error { - params := map[string]string{} - params["Action"] = "BindZoneVpc" - params["ZoneId"] = zoneId - _, err := client.pvtzRequest("BindZoneVpc", params) - if err != nil { - return errors.Wrap(err, "BindZoneVpc") - } - return nil -} - -func (self *SPrivateZone) GetId() string { - return self.ZoneID -} - -func (self *SPrivateZone) GetName() string { - return self.ZoneName -} - -func (self *SPrivateZone) GetGlobalId() string { - return self.GetId() -} - -func (self *SPrivateZone) GetStatus() string { - return api.DNS_ZONE_STATUS_AVAILABLE -} - -func (self *SPrivateZone) Refresh() error { - szone, err := self.client.DescribeZoneInfo(self.ZoneID) - if err != nil { - return errors.Wrapf(err, "self.client.DescribeZoneInfo(%s)", self.ZoneID) - } - return jsonutils.Update(self, szone) -} - -func (self *SPrivateZone) GetZoneType() cloudprovider.TDnsZoneType { - return cloudprovider.PrivateZone -} - -func (self *SPrivateZone) GetOptions() *jsonutils.JSONDict { - return nil -} - -func (self *SPrivateZone) GetICloudVpcIds() ([]string, error) { - var ret []string - for i := 0; i < len(self.BindVpcs.Vpc); i++ { - ret = append(ret, self.BindVpcs.Vpc[i].VpcID) - } - return ret, nil -} - -func (self *SPrivateZone) AddVpc(vpc *cloudprovider.SPrivateZoneVpc) error { - vpcs := []cloudprovider.SPrivateZoneVpc{} - for i := 0; i < len(self.BindVpcs.Vpc); i++ { - vpc := cloudprovider.SPrivateZoneVpc{} - vpc.Id = self.BindVpcs.Vpc[i].VpcID - vpc.RegionId = self.BindVpcs.Vpc[i].RegionID - vpcs = append(vpcs, vpc) - } - vpcs = append(vpcs, *vpc) - return self.client.BindZoneVpcs(self.ZoneID, vpcs) -} - -func (self *SPrivateZone) RemoveVpc(vpc *cloudprovider.SPrivateZoneVpc) error { - vpcs := []cloudprovider.SPrivateZoneVpc{} - for i := 0; i < len(self.BindVpcs.Vpc); i++ { - newVpc := cloudprovider.SPrivateZoneVpc{} - if self.BindVpcs.Vpc[i].VpcID == vpc.Id && self.BindVpcs.Vpc[i].RegionID == vpc.RegionId { - continue - } - newVpc.Id = self.BindVpcs.Vpc[i].VpcID - newVpc.RegionId = self.BindVpcs.Vpc[i].RegionID - vpcs = append(vpcs, newVpc) - } - return self.client.BindZoneVpcs(self.ZoneID, vpcs) -} - -func (self *SPrivateZone) GetIDnsRecordSets() ([]cloudprovider.ICloudDnsRecordSet, error) { - zonerecords, err := self.client.GetAllZoneRecords(self.ZoneID) - if err != nil { - return nil, errors.Wrapf(err, "self.client.GetAllZoneRecords(%s)", self.ZoneID) - } - result := []cloudprovider.ICloudDnsRecordSet{} - for i := 0; i < len(zonerecords); i++ { - zonerecords[i].szone = self - result = append(result, &zonerecords[i]) - } - return result, nil -} - -func (self *SPrivateZone) SyncDnsRecordSets(common, add, del, update []cloudprovider.DnsRecordSet) error { - for i := 0; i < len(del); i++ { - err := self.client.DeleteZoneRecord(del[i].ExternalId) - if err != nil { - return errors.Wrapf(err, "self.client.DeleteZoneRecord(%s)", del[i].ExternalId) - } - } - - for i := 0; i < len(add); i++ { - recordId, err := self.client.AddZoneRecord(self.ZoneID, add[i]) - if err != nil { - return errors.Wrapf(err, "self.client.AddZoneRecord(%s,%s)", self.ZoneID, jsonutils.Marshal(add[i]).String()) - } - if !add[i].Enabled { - err = self.client.SetZoneRecordStatus(recordId, "DISABLE") - if err != nil { - return errors.Wrapf(err, "self.client.SetZoneRecordStatus(%s,%t)", recordId, add[i].Enabled) - } - } - } - - for i := 0; i < len(update); i++ { - // ENABLE: 启用解析 DISABLE: 暂停解析 - status := "ENABLE" - if !update[i].Enabled { - status = "DISABLE" - } - err := self.client.SetZoneRecordStatus(update[i].ExternalId, status) - if err != nil { - return errors.Wrapf(err, "self.client.SetZoneRecordStatus(%s,%t)", update[i].ExternalId, update[i].Enabled) - } - err = self.client.UpdateZoneRecord(update[i]) - if err != nil { - return errors.Wrapf(err, "self.client.UpdateZoneRecord(%s)", jsonutils.Marshal(update[i]).String()) - } - } - - return nil -} - -func (self *SPrivateZone) Delete() error { - if len(self.BindVpcs.Vpc) > 0 { - err := self.client.UnBindZoneVpcs(self.ZoneID) - if err != nil { - return errors.Wrapf(err, "self.client.UnBindZoneVpcs(%s)", self.ZoneID) - } - } - return self.client.DeleteZone(self.ZoneID) -} - -func (self *SPrivateZone) GetDnsProductType() cloudprovider.TDnsProductType { - return "" -} - -func (self *SPrivateZone) GetProperlyTTL(ttl int64) int64 { - if ttl < allowedTtls[0] { - return allowedTtls[0] - } - for i := 0; i < len(allowedTtls)-1; i++ { - if ttl > allowedTtls[i] && ttl < allowedTtls[i+1] { - return allowedTtls[i] - } - } - return allowedTtls[len(allowedTtls)-1] -} diff --git a/pkg/multicloud/aliyun/project.go b/pkg/multicloud/aliyun/project.go deleted file mode 100644 index 1858840190..0000000000 --- a/pkg/multicloud/aliyun/project.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SResourceGroup struct { - multicloud.SProjectBase - multicloud.AliyunTags - client *SAliyunClient - - Status string - AccountId string - DisplayName string - Id string - CreateDate time.Time - Name string -} - -func (self *SResourceGroup) GetGlobalId() string { - return self.Id -} - -func (self *SResourceGroup) GetId() string { - return self.Id -} - -func (self *SResourceGroup) GetName() string { - if len(self.DisplayName) > 0 { - return self.DisplayName - } - return self.Name -} - -func (self *SResourceGroup) Refresh() error { - group, err := self.client.GetResourceGroup(self.Id) - if err != nil { - return errors.Wrap(err, "GetResourceGroup") - } - return jsonutils.Update(self, group) -} - -func (self *SResourceGroup) GetStatus() string { - switch self.Status { - case "Creating": - return api.EXTERNAL_PROJECT_STATUS_CREATING - case "OK": - return api.EXTERNAL_PROJECT_STATUS_AVAILABLE - case "Deleted", "Deleting", "PendingDelete": - return api.EXTERNAL_PROJECT_STATUS_DELETING - default: - return api.EXTERNAL_PROJECT_STATUS_UNKNOWN - } -} - -func (self *SAliyunClient) GetResourceGroups(pageNumber int, pageSize int) ([]SResourceGroup, int, error) { - if pageSize <= 0 || pageSize > 100 { - pageSize = 10 - } - if pageNumber <= 0 { - pageNumber = 1 - } - params := map[string]string{ - "PageNumber": fmt.Sprintf("%d", pageNumber), - "PageSize": fmt.Sprintf("%d", pageSize), - } - resp, err := self.rmRequest("ListResourceGroups", params) - if err != nil { - return nil, 0, errors.Wrap(err, "rmRequest.ListResourceGroups") - } - groups := []SResourceGroup{} - err = resp.Unmarshal(&groups, "ResourceGroups", "ResourceGroup") - if err != nil { - return nil, 0, errors.Wrap(err, "resp.Unmarshal") - } - total, _ := resp.Int("TotalCount") - return groups, int(total), nil -} - -func (self *SAliyunClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - group, err := self.CreateResourceGroup(name) - if err != nil { - return nil, errors.Wrap(err, "CreateProject") - } - return group, nil -} - -func (self *SAliyunClient) CreateResourceGroup(name string) (*SResourceGroup, error) { - params := map[string]string{ - "DisplayName": name, - "Name": name, - } - resp, err := self.rmRequest("CreateResourceGroup", params) - if err != nil { - return nil, errors.Wrap(err, "CreateResourceGroup") - } - group := &SResourceGroup{client: self} - err = resp.Unmarshal(group, "ResourceGroup") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - err = cloudprovider.WaitStatus(group, api.EXTERNAL_PROJECT_STATUS_AVAILABLE, time.Second*5, time.Minute*3) - if err != nil { - return nil, errors.Wrap(err, "WaitStatus") - } - return group, nil -} - -func (self *SAliyunClient) GetResourceGroup(id string) (*SResourceGroup, error) { - params := map[string]string{ - "ResourceGroupId": id, - } - resp, err := self.rmRequest("GetResourceGroup", params) - if err != nil { - return nil, err - } - group := &SResourceGroup{client: self} - err = resp.Unmarshal(group, "ResourceGroup") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return group, nil -} diff --git a/pkg/multicloud/aliyun/provider/doc.go b/pkg/multicloud/aliyun/provider/doc.go deleted file mode 100644 index b4cd8ec6b4..0000000000 --- a/pkg/multicloud/aliyun/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/aliyun/provider" diff --git a/pkg/multicloud/aliyun/provider/provider.go b/pkg/multicloud/aliyun/provider/provider.go deleted file mode 100644 index cf9281587c..0000000000 --- a/pkg/multicloud/aliyun/provider/provider.go +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" -) - -type SAliyunProviderFactory struct { - cloudprovider.SPublicCloudBaseProviderFactory -} - -func (self *SAliyunProviderFactory) GetId() string { - return aliyun.CLOUD_PROVIDER_ALIYUN -} - -func (self *SAliyunProviderFactory) GetName() string { - return aliyun.CLOUD_PROVIDER_ALIYUN_CN -} - -func (self *SAliyunProviderFactory) IsCloudeventRegional() bool { - return true -} - -func (self *SAliyunProviderFactory) IsSupportCloudIdService() bool { - return true -} - -func (self *SAliyunProviderFactory) IsSupportCreateCloudgroup() bool { - return true -} - -func (factory *SAliyunProviderFactory) IsSystemCloudpolicyUnified() bool { - return false -} - -func (factory *SAliyunProviderFactory) IsSupportSAMLAuth() bool { - return true -} - -func (self *SAliyunProviderFactory) GetSupportedDnsZoneTypes() []cloudprovider.TDnsZoneType { - return []cloudprovider.TDnsZoneType{ - cloudprovider.PublicZone, - cloudprovider.PrivateZone, - } -} - -func (self *SAliyunProviderFactory) GetSupportedDnsTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType { - return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType{ - cloudprovider.PublicZone: []cloudprovider.TDnsType{ - cloudprovider.DnsTypeA, - cloudprovider.DnsTypeAAAA, - cloudprovider.DnsTypeCAA, - cloudprovider.DnsTypeCNAME, - cloudprovider.DnsTypeMX, - cloudprovider.DnsTypeNS, - cloudprovider.DnsTypeSRV, - cloudprovider.DnsTypeTXT, - cloudprovider.DnsTypePTR, - cloudprovider.DnsTypeFORWARD_URL, - cloudprovider.DnsTypeREDIRECT_URL, - }, - cloudprovider.PrivateZone: []cloudprovider.TDnsType{ - cloudprovider.DnsTypeA, - cloudprovider.DnsTypeAAAA, - cloudprovider.DnsTypeCNAME, - cloudprovider.DnsTypeMX, - cloudprovider.DnsTypeSRV, - cloudprovider.DnsTypeTXT, - cloudprovider.DnsTypePTR, - }, - } -} - -func (self *SAliyunProviderFactory) GetSupportedDnsPolicyTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType { - return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType{ - cloudprovider.PublicZone: []cloudprovider.TDnsPolicyType{ - cloudprovider.DnsPolicyTypeSimple, - cloudprovider.DnsPolicyTypeByCarrier, - cloudprovider.DnsPolicyTypeByGeoLocation, - cloudprovider.DnsPolicyTypeBySearchEngine, - }, - cloudprovider.PrivateZone: []cloudprovider.TDnsPolicyType{ - cloudprovider.DnsPolicyTypeSimple, - }, - } -} - -func (self *SAliyunProviderFactory) GetSupportedDnsPolicyValues() map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue { - return map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue{ - cloudprovider.DnsPolicyTypeByCarrier: []cloudprovider.TDnsPolicyValue{ - cloudprovider.DnsPolicyValueUnicom, - cloudprovider.DnsPolicyValueTelecom, - cloudprovider.DnsPolicyValueChinaMobile, - cloudprovider.DnsPolicyValueCernet, - }, - cloudprovider.DnsPolicyTypeByGeoLocation: []cloudprovider.TDnsPolicyValue{ - cloudprovider.DnsPolicyValueOversea, - }, - cloudprovider.DnsPolicyTypeBySearchEngine: []cloudprovider.TDnsPolicyValue{ - cloudprovider.DnsPolicyValueBaidu, - cloudprovider.DnsPolicyValueGoogle, - cloudprovider.DnsPolicyValueBing, - }, - } -} - -func (self *SAliyunProviderFactory) GetTTLRange(zoneType cloudprovider.TDnsZoneType, productType cloudprovider.TDnsProductType) cloudprovider.TTlRange { - if zoneType == cloudprovider.PublicZone { - if len(productType) > 0 { - switch productType { - case cloudprovider.DnsProductEnterpriseUltimate: - return cloudprovider.TtlRangeAliyunEnterpriseUltimate - case cloudprovider.DnsProductEnterpriseStandard: - return cloudprovider.TtlRangeAliyunEnterpriseStandard - case cloudprovider.DnsProductPersonalProfessional: - return cloudprovider.TtlRangeAliyunPersonal - default: - return cloudprovider.TtlRangeAliyunFree - } - } - return cloudprovider.TtlRangeAliyunFree - } - - if zoneType == cloudprovider.PrivateZone { - return cloudprovider.TtlRangeAliyunPvtz - } - return cloudprovider.TTlRange{} -} - -func (self *SAliyunProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output.AccessUrl = input.Environment - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - return output, nil -} - -func (self *SAliyunProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func validateClientCloudenv(client *aliyun.SAliyunClient) error { - regions := client.GetIRegions() - if len(regions) == 0 { - return nil - } - - isFinanceAccount := false - for i := range regions { - if strings.Contains(regions[i].GetId(), "-finance") { - isFinanceAccount = true - break - } - } - - if isFinanceAccount { - if regions[0].GetCloudEnv() != "FinanceCloud" { - return errors.Wrap(httperrors.ErrInvalidCredential, "aksk is aliyun finance account") - } - } else { - if regions[0].GetCloudEnv() == "FinanceCloud" { - return errors.Wrap(httperrors.ErrInvalidCredential, "aksk is not aliyun finance account") - } - } - - return nil -} - -func (self *SAliyunProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - client, err := aliyun.NewAliyunClient( - aliyun.NewAliyunClientConfig( - cfg.URL, - cfg.Account, - cfg.Secret, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - - err = validateClientCloudenv(client) - if err != nil { - return nil, errors.Wrap(err, "validateClientCloudenv") - } - - return &SAliyunProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SAliyunProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - return map[string]string{ - "ALIYUN_ACCESS_KEY": info.Account, - "ALIYUN_SECRET": info.Secret, - "ALIYUN_REGION": aliyun.ALIYUN_DEFAULT_REGION, - }, nil -} - -func init() { - factory := SAliyunProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SAliyunProvider struct { - cloudprovider.SBaseProvider - client *aliyun.SAliyunClient -} - -func (self *SAliyunProvider) GetSysInfo() (jsonutils.JSONObject, error) { - regions := self.client.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") - info.Add(jsonutils.NewString(aliyun.ALIYUN_API_VERSION), "api_version") - return info, nil -} - -func (self *SAliyunProvider) GetVersion() string { - return aliyun.ALIYUN_API_VERSION -} - -func (self *SAliyunProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SAliyunProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SAliyunProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SAliyunProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(extId) -} - -func (self *SAliyunProvider) GetBalance() (float64, string, error) { - balance, err := self.client.QueryAccountBalance() - if err != nil { - return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, err - } - status := api.CLOUD_PROVIDER_HEALTH_NORMAL - if balance.CreditAmount+balance.MybankCreditAmount <= 0 { - if balance.AvailableAmount < 0 { - status = api.CLOUD_PROVIDER_HEALTH_ARREARS - } else if balance.AvailableAmount < 100 { - status = api.CLOUD_PROVIDER_HEALTH_INSUFFICIENT - } - } - return balance.AvailableAmount, status, nil -} - -func (self *SAliyunProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SAliyunProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return self.client.CreateIProject(name) -} - -func (self *SAliyunProvider) GetStorageClasses(regionId string) []string { - return []string{ - "Standard", "IA", "Archive", - } -} - -func (self *SAliyunProvider) GetBucketCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SAliyunProvider) GetObjectCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SAliyunProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SAliyunProvider) GetIamLoginUrl() string { - return self.client.GetIamLoginUrl() -} - -func (self *SAliyunProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - return self.client.CreateIClouduser(conf) -} - -func (self *SAliyunProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { - return self.client.GetICloudusers() -} - -func (self *SAliyunProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroups() -} - -func (self *SAliyunProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroupByName(name) -} - -func (self *SAliyunProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.client.GetIClouduserByName(name) -} - -func (self *SAliyunProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - return self.client.CreateICloudgroup(name, desc) -} - -func (self *SAliyunProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetISystemCloudpolicies() -} - -func (self *SAliyunProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetICustomCloudpolicies() -} - -func (self *SAliyunProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { - return self.client.CreateICloudpolicy(opts) -} - -func (self *SAliyunProvider) GetSamlEntityId() string { - return cloudprovider.SAML_ENTITY_ID_ALIYUN_ROLE -} - -func (self *SAliyunProvider) GetICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { - izones := []cloudprovider.ICloudDnsZone{} - privateZone, err := self.client.GetPrivateICloudDnsZones() - if err != nil { - return nil, errors.Wrap(err, "self.client.GetPrivateICloudDnsZones()") - } - publicZone, err := self.client.GetPublicICloudDnsZones() - if err != nil { - return nil, errors.Wrap(err, "self.client.GetPrivateICloudDnsZones()") - } - izones = append(izones, privateZone...) - izones = append(izones, publicZone...) - return izones, nil -} -func (self *SAliyunProvider) GetICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { - privateIzone, err := self.client.GetPrivateICloudDnsZoneById(id) - if err == nil { - return privateIzone, nil - } else { - if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - - publicIzone, err := self.client.GetPublicICloudDnsZoneById(id) - if err == nil { - return publicIzone, nil - } else { - if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SAliyunProvider) CreateICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { - if opts.ZoneType == cloudprovider.PrivateZone { - return self.client.CreatePrivateICloudDnsZone(opts) - } else { - return self.client.CreatePublicICloudDnsZone(opts) - } -} - -func (self *SAliyunProvider) GetICloudInterVpcNetworks() ([]cloudprovider.ICloudInterVpcNetwork, error) { - scens, err := self.client.GetAllCens() - if err != nil { - return nil, errors.Wrap(err, "self.client.GetAllCens()") - } - - iVpcNetworks := []cloudprovider.ICloudInterVpcNetwork{} - for i := range scens { - iVpcNetworks = append(iVpcNetworks, &scens[i]) - } - return iVpcNetworks, nil - -} -func (self *SAliyunProvider) GetICloudInterVpcNetworkById(id string) (cloudprovider.ICloudInterVpcNetwork, error) { - iVpcNetwork, err := self.GetICloudInterVpcNetworks() - if err != nil { - return nil, errors.Wrap(err, "self.GetICloudInterVpcNetworks()") - } - for i := range iVpcNetwork { - if iVpcNetwork[i].GetId() == id { - return iVpcNetwork[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} -func (self *SAliyunProvider) CreateICloudInterVpcNetwork(opts *cloudprovider.SInterVpcNetworkCreateOptions) (cloudprovider.ICloudInterVpcNetwork, error) { - cenId, err := self.client.CreateCen(opts) - if err != nil { - return nil, errors.Wrapf(err, "self.client.CreateCen(%s)", jsonutils.Marshal(opts).String()) - } - ivpcNetwork, err := self.GetICloudInterVpcNetworkById(cenId) - if err != nil { - return nil, errors.Wrapf(err, "self.GetICloudInterVpcNetworkById(%s)", cenId) - } - return ivpcNetwork, nil -} - -func (self *SAliyunProvider) GetCloudRegionExternalIdPrefix() string { - return self.client.GetAccessEnv() + "/" -} - -func (self *SAliyunProvider) GetICloudroles() ([]cloudprovider.ICloudrole, error) { - return self.client.GetICloudroles() -} - -func (self *SAliyunProvider) GetICloudroleById(id string) (cloudprovider.ICloudrole, error) { - info := strings.Split(id, "role/") - if len(info) == 2 { - role, err := self.client.GetRole(info[1]) - if err != nil { - return nil, errors.Wrapf(err, "GetRole(%s)", info[1]) - } - return role, nil - } - return nil, fmt.Errorf("invalid role id %s", id) -} - -func (self *SAliyunProvider) CreateICloudrole(opts *cloudprovider.SRoleCreateOptions) (cloudprovider.ICloudrole, error) { - stetement := fmt.Sprintf(`{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Federated":["%s"]},"Condition":{"StringEquals":{"saml:recipient":"https://signin.aliyun.com/saml-role/sso"}}}],"Version":"1"}`, opts.SAMLProvider) - role, err := self.client.CreateRole(opts.Name, stetement, opts.Desc) - if err != nil { - return nil, errors.Wrapf(err, "CreateRole") - } - return role, nil -} - -func (self *SAliyunProvider) GetICloudroleByName(name string) (cloudprovider.ICloudrole, error) { - role, err := self.client.GetRole(name) - if err != nil { - return nil, errors.Wrapf(err, "GetRole(%s)", name) - } - return role, nil -} - -func (self *SAliyunProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { - return self.client.GetICloudSAMLProviders() -} - -func (self *SAliyunProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { - sp, err := self.client.CreateSAMLProvider(opts.Name, opts.Metadata.String(), "") - if err != nil { - return nil, errors.Wrapf(err, "CreateSAMLProvider") - } - return sp, nil -} - -func (self *SAliyunProvider) GetICloudCDNDomains() ([]cloudprovider.ICloudCDNDomain, error) { - return self.client.GetICloudCDNDomains() -} - -func (self *SAliyunProvider) GetICloudCDNDomainByName(name string) (cloudprovider.ICloudCDNDomain, error) { - return self.client.GetICloudCDNDomainByName(name) -} - -func (self *SAliyunProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/aliyun/quota.go b/pkg/multicloud/aliyun/quota.go deleted file mode 100644 index 8c98cd387e..0000000000 --- a/pkg/multicloud/aliyun/quota.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strconv" - "strings" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type ValueItem struct { - Value string - DiskCategory string -} - -type AttributeValues struct { - ValueItem []ValueItem -} - -type SAccountAttributeItem struct { - AttributeValues AttributeValues - AttributeName string -} - -type SQuota struct { - Name string - UsedCount int - MaxCount int -} - -func (q *SQuota) GetGlobalId() string { - return q.Name -} - -func (q *SQuota) GetDesc() string { - return q.Name -} - -func (q *SQuota) GetQuotaType() string { - return q.Name -} - -func (q *SQuota) GetMaxQuotaCount() int { - return q.MaxCount -} - -func (q *SQuota) GetCurrentQuotaUsedCount() int { - return q.UsedCount -} - -func (region *SRegion) GetAccountAttributes() ([]SAccountAttributeItem, error) { - params := map[string]string{ - "RegionId": region.RegionId, - } - resp, err := region.ecsRequest("DescribeAccountAttributes", params) - if err != nil { - return nil, errors.Wrap(err, "ecsRequest") - } - quotas := []SAccountAttributeItem{} - err = resp.Unmarshal("as, "AccountAttributeItems", "AccountAttributeItem") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return quotas, nil -} - -func (region *SRegion) GetQuotas() ([]SQuota, error) { - attrs, err := region.GetAccountAttributes() - if err != nil { - return nil, errors.Wrap(err, "GetAccountAttributes") - } - quotas := map[string]SQuota{} - for _, attr := range attrs { - for _, item := range attr.AttributeValues.ValueItem { - value, err := strconv.ParseInt(item.Value, 10, 64) - if err != nil { - continue - } - used := false - name := attr.AttributeName - if strings.HasPrefix(name, "used-") { - used = true - name = strings.TrimPrefix(name, "used-") - } - if len(item.DiskCategory) > 0 { - name = fmt.Sprintf("%s/%s", name, item.DiskCategory) - } - if _, ok := quotas[name]; !ok { - quotas[name] = SQuota{ - Name: name, - UsedCount: -1, - } - } - quota := quotas[name] - if used { - quota.UsedCount = int(value) - } else { - quota.MaxCount = int(value) - } - quotas[name] = quota - } - } - ret := []SQuota{} - for _, quota := range quotas { - ret = append(ret, quota) - } - return ret, nil -} - -func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { - quotas, err := region.GetQuotas() - if err != nil { - return nil, errors.Wrap(err, "GetQuotas") - } - ret := []cloudprovider.ICloudQuota{} - for i := range quotas { - ret = append(ret, "as[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/aliyun/ram_group.go b/pkg/multicloud/aliyun/ram_group.go deleted file mode 100644 index b572b2d32b..0000000000 --- a/pkg/multicloud/aliyun/ram_group.go +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SGroup struct { - client *SAliyunClient - - Comments string - CreatedDate time.Time - GroupName string - UpdateDate time.Time -} - -type sGroups struct { - Group []SGroup -} - -type SGroups struct { - Groups sGroups - Marker string - IsTruncated bool -} - -func (self *SGroup) GetName() string { - return self.GroupName -} - -func (self *SGroup) GetGlobalId() string { - return self.GroupName -} - -func (self *SGroup) GetDescription() string { - return self.Comments -} - -func (self *SGroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { - ret := []cloudprovider.IClouduser{} - offset := "" - for { - part, err := self.client.ListUsersForGroup(self.GroupName, offset, 1000) - if err != nil { - return nil, errors.Wrapf(err, "ListUsersForGroup") - } - for i := range part.Users.User { - part.Users.User[i].client = self.client - ret = append(ret, &part.Users.User[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SGroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := self.client.ListPoliciesForGroup(self.GroupName) - if err != nil { - return nil, errors.Wrapf(err, "ListPoliciesForGroup") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].PolicyType == POLICY_TYPE_SYSTEM { - policies[i].client = self.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (self *SGroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := self.client.ListPoliciesForGroup(self.GroupName) - if err != nil { - return nil, errors.Wrapf(err, "ListPoliciesForGroup") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].PolicyType == POLICY_TYPE_CUSTOM { - policies[i].client = self.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (self *SGroup) AddUser(name string) error { - return self.client.AddUserToGroup(self.GroupName, name) -} - -func (self *SGroup) RemoveUser(name string) error { - return self.client.RemoveUserFromGroup(self.GroupName, name) -} - -func (self *SGroup) AttachSystemPolicy(policyName string) error { - return self.client.AttachPolicyToGroup(POLICY_TYPE_SYSTEM, policyName, self.GroupName) -} - -func (self *SGroup) AttachCustomPolicy(policyName string) error { - return self.client.AttachPolicyToGroup(POLICY_TYPE_CUSTOM, policyName, self.GroupName) -} - -func (self *SGroup) DetachSystemPolicy(policyName string) error { - return self.client.DetachPolicyFromGroup(POLICY_TYPE_SYSTEM, policyName, self.GroupName) -} - -func (self *SGroup) DetachCustomPolicy(policyName string) error { - return self.client.DetachPolicyFromGroup(POLICY_TYPE_CUSTOM, policyName, self.GroupName) -} - -func (self *SGroup) Delete() error { - return self.client.DeleteGroup(self.GroupName) -} - -func (self *SAliyunClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - group, err := self.GetGroup(name) - if err != nil { - return nil, errors.Wrapf(err, "GetGroup(%s)", name) - } - return group, nil -} - -func (self *SAliyunClient) CreateICloudgroup(name string, desc string) (cloudprovider.ICloudgroup, error) { - group, err := self.CreateGroup(name, desc) - if err != nil { - return nil, errors.Wrapf(err, "CreateGroup") - } - return group, nil -} - -func (self *SAliyunClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - ret := []cloudprovider.ICloudgroup{} - offset := "" - for { - part, err := self.ListGroups(offset, 100) - if err != nil { - return nil, errors.Wrap(err, "ListGroups") - } - for i := range part.Groups.Group { - part.Groups.Group[i].client = self - ret = append(ret, &part.Groups.Group[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SAliyunClient) ListGroups(offset string, limit int) (*SGroups, error) { - if limit < 1 || limit > 1000 { - limit = 1000 - } - params := map[string]string{ - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(offset) > 0 { - params["Marker"] = offset - } - groups := SGroups{} - resp, err := self.ramRequest("ListGroups", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.ListGroups") - } - err = resp.Unmarshal(&groups) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return &groups, nil -} - -// https://help.aliyun.com/document_detail/28732.html?spm=a2c4g.11186623.6.777.580735b2m2xUh8 -func (self *SAliyunClient) ListPoliciesForGroup(groupName string) ([]SPolicy, error) { - params := map[string]string{ - "GroupName": groupName, - } - resp, err := self.ramRequest("ListPoliciesForGroup", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.ListPoliciesForGroup") - } - policies := []SPolicy{} - err = resp.Unmarshal(&policies, "Policies", "Policy") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return policies, nil -} - -func (self *SAliyunClient) ListUsersForGroup(groupName string, offset string, limit int) (*SUsers, error) { - if limit < 1 || limit > 1000 { - limit = 1000 - } - params := map[string]string{ - "GroupName": groupName, - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(offset) > 0 { - params["Marker"] = offset - } - resp, err := self.ramRequest("ListUsersForGroup", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.ListUserForGroup") - } - users := &SUsers{} - err = resp.Unmarshal(users) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return users, nil -} - -func (self *SAliyunClient) DeleteGroup(groupName string) error { - params := map[string]string{ - "GroupName": groupName, - } - _, err := self.ramRequest("DeleteGroup", params) - return err -} - -func (self *SAliyunClient) CreateGroup(groupName, comments string) (*SGroup, error) { - params := map[string]string{ - "GroupName": groupName, - } - if len(comments) > 0 { - params["Comments"] = comments - } - resp, err := self.ramRequest("CreateGroup", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.CreateGroup") - } - group := &SGroup{client: self} - err = resp.Unmarshal(group, "Group") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return group, nil -} - -func (self *SAliyunClient) GetGroup(groupName string) (*SGroup, error) { - params := map[string]string{ - "GroupName": groupName, - } - resp, err := self.ramRequest("GetGroup", params) - if err != nil { - return nil, errors.Wrap(err, "GetGroup") - } - group := &SGroup{client: self} - err = resp.Unmarshal(group, "Group") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return group, nil -} - -func (self *SAliyunClient) RemoveUserFromGroup(groupName, userName string) error { - params := map[string]string{ - "GroupName": groupName, - "UserName": userName, - } - _, err := self.ramRequest("RemoveUserFromGroup", params) - if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrap(err, "RemoveUserFromGroup") - } - return nil -} - -func (self *SAliyunClient) DetachPolicyFromGroup(policyType, policyName, groupName string) error { - params := map[string]string{ - "GroupName": groupName, - "PolicyName": policyName, - "PolicyType": policyType, - } - _, err := self.ramRequest("DetachPolicyFromGroup", params) - if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrap(err, "DetachPolicyFromGroup") - } - return nil -} - -func (self *SAliyunClient) AddUserToGroup(groupName, userName string) error { - params := map[string]string{ - "GroupName": groupName, - "UserName": userName, - } - _, err := self.ramRequest("AddUserToGroup", params) - if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.User.Group") { - return errors.Wrap(err, "AddUserToGroup") - } - return nil -} - -func (self *SAliyunClient) AttachPolicyToGroup(policyType, policyName, groupName string) error { - params := map[string]string{ - "GroupName": groupName, - "PolicyName": policyName, - "PolicyType": policyType, - } - _, err := self.ramRequest("AttachPolicyToGroup", params) - if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.Group.Policy") { - return errors.Wrap(err, "AttachPolicyToGroup") - } - return nil -} diff --git a/pkg/multicloud/aliyun/ram_policy.go b/pkg/multicloud/aliyun/ram_policy.go deleted file mode 100644 index b3d5197eb6..0000000000 --- a/pkg/multicloud/aliyun/ram_policy.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - POLICY_TYPE_SYSTEM = "System" - POLICY_TYPE_CUSTOM = "Custom" -) - -/** - {"AttachmentCount":0, -"CreateDate":"2018-10-12T05:05:16Z", -"DefaultVersion":"v1", -"Description":"只读访问Data Lake Analytics的权限", -"PolicyName":"AliyunDLAReadOnlyAccess", -"PolicyType":"System", -"UpdateDate":"2018-10-12T05:05:16Z"} -*/ - -type SDefaultPolicyVersion struct { - CreateDate time.Time - IsDefaultVersion bool - PolicyDocument string - VersionId string -} - -type SPolicyDetails struct { - Policy SPolicy - DefaultPolicyVersion SDefaultPolicyVersion -} - -type sPolicies struct { - Policy []SPolicy -} - -type SPolicies struct { - Policies sPolicies - Marker string - IsTruncated bool -} - -type SPolicy struct { - client *SAliyunClient - AttachmentCount int - CreateDate time.Time - UpdateDate time.Time - DefaultVersion string - Description string - PolicyName string - PolicyType string -} - -func (policy *SPolicy) GetName() string { - return policy.PolicyName -} - -func (policy *SPolicy) GetDescription() string { - return policy.Description -} - -func (policy *SPolicy) GetGlobalId() string { - return policy.PolicyName -} - -func (policy *SPolicy) UpdateDocument(document *jsonutils.JSONDict) error { - return policy.client.CreatePolicyVersion(policy.PolicyName, document.String(), true) -} - -func (policy *SPolicy) Delete() error { - return policy.client.DeletePolicy(policy.PolicyType, policy.PolicyName) -} - -func (policy *SPolicy) GetDocument() (*jsonutils.JSONDict, error) { - details, err := policy.client.GetPolicy(policy.PolicyType, policy.PolicyName) - if err != nil { - return nil, errors.Wrapf(err, "GetPolicy(%s,%s)", policy.PolicyType, policy.PolicyName) - } - obj, err := jsonutils.Parse([]byte(details.DefaultPolicyVersion.PolicyDocument)) - if err != nil { - return nil, errors.Wrap(err, "jsonutils.Parse") - } - return obj.(*jsonutils.JSONDict), nil -} - -func (self *SAliyunClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - ret := []cloudprovider.ICloudpolicy{} - offset := "" - for { - part, err := self.ListPolicies(POLICY_TYPE_SYSTEM, offset, 1000) - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - for i := range part.Policies.Policy { - part.Policies.Policy[i].client = self - ret = append(ret, &part.Policies.Policy[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SAliyunClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - ret := []cloudprovider.ICloudpolicy{} - offset := "" - for { - part, err := self.ListPolicies(POLICY_TYPE_CUSTOM, offset, 1000) - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - for i := range part.Policies.Policy { - part.Policies.Policy[i].client = self - ret = append(ret, &part.Policies.Policy[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SAliyunClient) AttachPolicyToUser(policyName, policyType, userName string) error { - params := map[string]string{ - "UserName": userName, - "PolicyName": policyName, - "PolicyType": policyType, - } - _, err := self.ramRequest("AttachPolicyToUser", params) - if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.User.Policy") { - return errors.Wrap(err, "AttachPolicyToUser") - } - return nil -} - -func (self *SAliyunClient) DetachPolicyFromUser(policyName, policyType, userName string) error { - if len(policyType) == 0 { - policyType = "System" - } - params := map[string]string{ - "UserName": userName, - "PolicyName": policyName, - "PolicyType": policyType, - } - _, err := self.ramRequest("DetachPolicyFromUser", params) - if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrap(err, "DetachPolicyFromUser") - } - return nil -} - -// https://help.aliyun.com/document_detail/28719.html?spm=a2c4g.11174283.6.764.27055662H6TGg5 -func (self *SAliyunClient) ListPolicies(policyType string, offset string, limit int) (*SPolicies, error) { - if limit < 1 || limit > 1000 { - limit = 1000 - } - params := map[string]string{ - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(policyType) > 0 { - params["PolicyType"] = policyType - } - if len(offset) > 0 { - params["Marker"] = offset - } - - body, err := self.ramRequest("ListPolicies", params) - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - policies := &SPolicies{} - - err = body.Unmarshal(&policies) - if err != nil { - return nil, errors.Wrapf(err, "body.Unmarshal") - } - - return policies, nil -} - -func (self *SAliyunClient) GetPolicy(policyType string, policyName string) (*SPolicyDetails, error) { - params := make(map[string]string) - params["PolicyType"] = policyType - params["PolicyName"] = policyName - - body, err := self.ramRequest("GetPolicy", params) - if err != nil { - if isError(err, "EntityNotExist.Role") { - return nil, cloudprovider.ErrNotFound - } - return nil, err - } - - policy := SPolicyDetails{} - - err = body.Unmarshal(&policy) - if err != nil { - return nil, err - } - - return &policy, nil -} - -type SStatement struct { - Action []string `json:"Action,allowempty"` - Effect string `json:"Effect"` - Resource []string `json:"Resource"` -} - -type SPolicyDocument struct { - Statement []SStatement `json:"Statement,allowempty"` - Version string `json:"Version"` -} - -func (self *SAliyunClient) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { - if opts.Document == nil { - return nil, errors.Error("nil document") - } - policy, err := self.CreatePolicy(opts.Name, opts.Document.String(), opts.Desc) - if err != nil { - return nil, errors.Wrapf(err, "CreatePolicy") - } - return policy, nil -} - -func (self *SAliyunClient) CreatePolicy(name string, document string, desc string) (*SPolicy, error) { - params := make(map[string]string) - params["PolicyName"] = name - params["PolicyDocument"] = document - if len(desc) > 0 { - params["Description"] = desc - } - - body, err := self.ramRequest("CreatePolicy", params) - if err != nil { - return nil, err - } - - policy := SPolicy{client: self} - - err = body.Unmarshal(&policy, "Policy") - if err != nil { - return nil, err - } - - return &policy, nil -} - -func (self *SAliyunClient) DeletePolicy(policyType string, policyName string) error { - params := make(map[string]string) - params["PolicyName"] = policyName - params["PolicyType"] = policyType - - _, err := self.ramRequest("DeletePolicy", params) - return err -} - -func (self *SAliyunClient) DeleteRole(roleName string) error { - params := make(map[string]string) - params["RoleName"] = roleName - - _, err := self.ramRequest("DeleteRole", params) - return err -} - -func (self *SAliyunClient) AttachPolicy2Role(policyType string, policyName string, roleName string) error { - params := make(map[string]string) - params["PolicyType"] = policyType - params["PolicyName"] = policyName - params["RoleName"] = roleName - - _, err := self.ramRequest("AttachPolicyToRole", params) - if err != nil { - return errors.Wrap(err, "AttachPolicyToRole") - } - - return nil -} - -func (self *SAliyunClient) CreatePolicyVersion(name, document string, isDefault bool) error { - params := map[string]string{ - "PolicyName": name, - "PolicyDocument": document, - "RotateStrategy": "DeleteOldestNonDefaultVersionWhenLimitExceeded", - } - if isDefault { - params["SetAsDefault"] = "true" - } - _, err := self.ramRequest("CreatePolicyVersion", params) - return err -} diff --git a/pkg/multicloud/aliyun/ram_role.go b/pkg/multicloud/aliyun/ram_role.go deleted file mode 100644 index 2d560ed569..0000000000 --- a/pkg/multicloud/aliyun/ram_role.go +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type sRoles struct { - Role []SRole -} - -type SRoles struct { - Roles sRoles - Marker string - IsTruncated bool -} - -type SRole struct { - client *SAliyunClient - - Arn string - CreateDate time.Time - Description string - RoleId string - RoleName string - - AssumeRolePolicyDocument string -} - -func (self *SRole) GetGlobalId() string { - return self.Arn -} - -func (self *SRole) GetName() string { - return self.RoleName -} - -func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := self.client.ListPoliciesForRole(self.RoleName) - if err != nil { - return nil, errors.Wrapf(err, "ListPoliciesForRole") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - policies[i].client = self.client - ret = append(ret, &policies[i]) - } - return ret, nil -} - -func (self *SRole) AttachPolicy(policyName string) error { - return self.client.AttachPolicy2Role("System", policyName, self.RoleName) -} - -func (self *SRole) DetachPolicy(policyName string) error { - return self.client.DetachPolicyFromRole("System", policyName, self.RoleName) -} - -func (self *SRole) Delete() error { - return self.client.DeleteRole(self.RoleName) -} - -func (self *SRole) GetDocument() *jsonutils.JSONDict { - role, err := self.client.GetRole(self.RoleName) - if err != nil { - return nil - } - documet, err := jsonutils.Parse([]byte(role.AssumeRolePolicyDocument)) - if err != nil { - return nil - } - return documet.(*jsonutils.JSONDict) -} - -func (self *SRole) GetSAMLProvider() string { - document := self.GetDocument() - if document != nil { - statement, err := document.GetArray("Statement") - if err == nil { - for i := range statement { - if action, _ := statement[i].GetString("Action"); action == "sts:AssumeRole" { - sp, _ := statement[i].GetString("Principal", "Federated") - if len(sp) > 0 { - return sp - } - } - } - } - } - return "" -} - -func (self *SAliyunClient) GetICloudroles() ([]cloudprovider.ICloudrole, error) { - roles := []SRole{} - marker := "" - for { - part, err := self.ListRoles(marker, 1000) - if err != nil { - return nil, errors.Wrapf(err, "ListRoles(%s)", marker) - } - roles = append(roles, part.Roles.Role...) - if len(part.Marker) == 0 { - break - } - marker = part.Marker - } - ret := []cloudprovider.ICloudrole{} - for i := range roles { - roles[i].client = self - ret = append(ret, &roles[i]) - } - return ret, nil -} - -func (self *SAliyunClient) ListRoles(offset string, limit int) (*SRoles, error) { - if limit < 0 || limit > 1000 { - limit = 1000 - } - - params := map[string]string{} - if len(offset) > 0 { - params["Marker"] = offset - } - if limit > 0 { - params["MaxItems"] = fmt.Sprintf("%d", limit) - } - - body, err := self.ramRequest("ListRoles", params) - if err != nil { - return nil, errors.Wrapf(err, "ListRoles") - } - - roles := &SRoles{} - err = body.Unmarshal(roles) - if err != nil { - return nil, errors.Wrap(err, "body.Unmarshal(&") - } - return roles, nil -} - -func (self *SAliyunClient) CreateRole(roleName string, document string, desc string) (*SRole, error) { - params := make(map[string]string) - params["RoleName"] = roleName - params["AssumeRolePolicyDocument"] = document - if len(desc) > 0 { - params["Description"] = desc - } - - body, err := self.ramRequest("CreateRole", params) - if err != nil { - return nil, errors.Wrap(err, "CreateRole") - } - - role := SRole{client: self} - err = body.Unmarshal(&role, "Role") - if err != nil { - return nil, errors.Wrap(err, "body.Unmarshal") - } - - return &role, nil -} - -func (self *SAliyunClient) GetRole(roleName string) (*SRole, error) { - params := make(map[string]string) - params["RoleName"] = roleName - - body, err := self.ramRequest("GetRole", params) - if err != nil { - return nil, errors.Wrap(err, "GetRole") - } - - role := SRole{client: self} - err = body.Unmarshal(&role, "Role") - if err != nil { - return nil, errors.Wrap(err, "body.Unmarshal") - } - - return &role, nil -} - -func (self *SAliyunClient) ListPoliciesForRole(name string) ([]SPolicy, error) { - params := map[string]string{ - "RoleName": name, - } - resp, err := self.ramRequest("ListPoliciesForRole", params) - if err != nil { - return nil, errors.Wrapf(err, "ListPoliciesForRole") - } - policies := []SPolicy{} - err = resp.Unmarshal(&policies, "Policies", "Policy") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return policies, nil -} - -func (self *SAliyunClient) DetachPolicyFromRole(policyType, policyName, roleName string) error { - params := map[string]string{ - "PolicyName": policyName, - "PolicyType": policyType, - "RoleName": roleName, - } - _, err := self.ramRequest("DetachPolicyFromRole", params) - return err -} diff --git a/pkg/multicloud/aliyun/ram_user.go b/pkg/multicloud/aliyun/ram_user.go deleted file mode 100644 index ea3f27a97d..0000000000 --- a/pkg/multicloud/aliyun/ram_user.go +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type sUsers struct { - User []SUser -} - -type SUsers struct { - Users sUsers - Marker string - IsTruncated bool -} - -type SUser struct { - client *SAliyunClient - multicloud.SBaseClouduser - - Comments string - CreateDate time.Time - DisplayName string - Email string - MobilePhone string - UserId string - UserName string -} - -func (user *SUser) GetGlobalId() string { - if len(user.UserId) > 0 { - return user.UserId - } - u, err := user.client.GetUser(user.UserName) - if err != nil { - return "" - } - return u.UserId -} - -func (user *SUser) GetName() string { - return user.UserName -} - -func (user *SUser) GetEmailAddr() string { - return user.Email -} - -func (user *SUser) GetInviteUrl() string { - return "" -} - -func (user *SUser) Delete() error { - groups, err := user.client.ListGroupsForUser(user.UserName) - if err != nil { - return errors.Wrap(err, "ListGroupsForUser") - } - for i := range groups { - err = user.client.RemoveUserFromGroup(groups[i].GroupName, user.UserName) - if err != nil { - return errors.Wrapf(err, "RemoveUserFromGroup %s > %s", groups[i].GroupName, user.UserName) - } - } - policies, err := user.client.ListPoliciesForUser(user.UserName) - if err != nil { - return errors.Wrap(err, "ListPoliciesForUser") - } - for i := range policies { - err = user.client.DetachPolicyFromUser(policies[i].PolicyName, policies[i].PolicyType, user.UserName) - if err != nil { - return errors.Wrapf(err, "DetachPolicyFromUser %s %s %s", policies[i].PolicyName, policies[i].PolicyType, user.UserName) - } - } - return user.client.DeleteClouduser(user.UserName) -} - -func (user *SUser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - groups, err := user.client.ListGroupsForUser(user.UserName) - if err != nil { - return nil, errors.Wrapf(err, "ListGroupsForUser") - } - ret := []cloudprovider.ICloudgroup{} - for i := range groups { - groups[i].client = user.client - ret = append(ret, &groups[i]) - } - return ret, nil -} - -func (user *SUser) UpdatePassword(password string) error { - return user.client.UpdateLoginProfile(user.UserName, password) -} - -func (user *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := user.client.ListPoliciesForUser(user.UserName) - if err != nil { - return nil, errors.Wrap(err, "ListPoliciesForUser") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].PolicyType == "System" { - policies[i].client = user.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (user *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := user.client.ListPoliciesForUser(user.UserName) - if err != nil { - return nil, errors.Wrap(err, "ListPoliciesForUser") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].PolicyType == "Custom" { - policies[i].client = user.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (user *SUser) IsConsoleLogin() bool { - _, err := user.client.GetLoginProfile(user.UserName) - if errors.Cause(err) == cloudprovider.ErrNotFound { - return false - } - return true -} - -func (user *SUser) ResetPassword(password string) error { - return user.client.ResetClouduserPassword(user.UserName, password) -} - -func (user *SUser) AttachSystemPolicy(policyName string) error { - return user.client.AttachPolicyToUser(policyName, POLICY_TYPE_SYSTEM, user.UserName) -} - -func (user *SUser) AttachCustomPolicy(policyName string) error { - return user.client.AttachPolicyToUser(policyName, POLICY_TYPE_CUSTOM, user.UserName) -} - -func (user *SUser) DetachSystemPolicy(policyName string) error { - return user.client.DetachPolicyFromUser(policyName, POLICY_TYPE_SYSTEM, user.UserName) -} - -func (user *SUser) DetachCustomPolicy(policyName string) error { - return user.client.DetachPolicyFromUser(policyName, POLICY_TYPE_CUSTOM, user.UserName) -} - -func (self *SAliyunClient) DeleteClouduser(name string) error { - params := map[string]string{ - "UserName": name, - } - _, err := self.ramRequest("DeleteUser", params) - return err -} - -func (self *SAliyunClient) CreateUser(name, phone, email, comments string) (*SUser, error) { - params := map[string]string{ - "UserName": name, - "DisplayName": name, - } - if len(phone) > 0 { - params["MobilePhone"] = phone - } - if len(email) > 0 { - params["Email"] = email - } - if len(comments) > 0 { - params["Comments"] = comments - } - resp, err := self.ramRequest("CreateUser", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.CreateUser") - } - - user := &SUser{client: self} - err = resp.Unmarshal(user, "User") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return user, nil -} - -func (self *SAliyunClient) ListUsers(offset string, limit int) (*SUsers, error) { - params := map[string]string{} - if len(offset) > 0 { - params["Marker"] = offset - } - if limit > 0 { - params["MaxItems"] = fmt.Sprintf("%d", limit) - } - resp, err := self.ramRequest("ListUsers", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.ListUsers") - } - users := &SUsers{} - err = resp.Unmarshal(users) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return users, nil -} - -func (self *SAliyunClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - user, err := self.CreateUser(conf.Name, conf.MobilePhone, conf.Email, conf.Desc) - if err != nil { - return nil, errors.Wrap(err, "CreateUser") - } - if len(conf.Password) > 0 { - _, err := self.CreateLoginProfile(conf.Name, conf.Password) - if err != nil { - return nil, errors.Wrap(err, "CreateLoginProfile") - } - } - for _, policyId := range conf.ExternalPolicyIds { - err := user.AttachSystemPolicy(policyId) - if err != nil { - log.Errorf("attach policy %s for user %s error: %v", policyId, conf.Name, err) - } - } - return user, nil -} - -func (self *SAliyunClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { - ret := []cloudprovider.IClouduser{} - offset := "" - for { - part, err := self.ListUsers(offset, 100) - if err != nil { - return nil, errors.Wrap(err, "GetCloudusers") - } - for i := range part.Users.User { - part.Users.User[i].client = self - ret = append(ret, &part.Users.User[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SAliyunClient) GetUser(name string) (*SUser, error) { - params := map[string]string{ - "UserName": name, - } - resp, err := self.ramRequest("GetUser", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.CreateUser") - } - user := &SUser{client: self} - err = resp.Unmarshal(user, "User") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return user, nil -} - -func (self *SAliyunClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.GetUser(name) -} - -type SLoginProfile struct { - CreateDate string - MFABindRequired bool - PasswordResetRequired bool - UserName string -} - -func (self *SAliyunClient) GetLoginProfile(name string) (*SLoginProfile, error) { - params := map[string]string{ - "UserName": name, - } - resp, err := self.ramRequest("GetLoginProfile", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.GetLoginProfile") - } - profile := &SLoginProfile{} - err = resp.Unmarshal(profile, "LoginProfile") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return profile, nil -} - -func (self *SAliyunClient) DeleteLoginProfile(name string) error { - params := map[string]string{ - "UserName": name, - } - _, err := self.ramRequest("DeleteLoginProfile", params) - return err -} - -func (self *SAliyunClient) CreateLoginProfile(name, password string) (*SLoginProfile, error) { - params := map[string]string{ - "UserName": name, - "Password": password, - } - resp, err := self.ramRequest("CreateLoginProfile", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.CreateLoginProfile") - } - profile := &SLoginProfile{} - err = resp.Unmarshal(profile, "LoginProfile") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return profile, nil -} - -func (self *SAliyunClient) UpdateLoginProfile(name, password string) error { - params := map[string]string{ - "UserName": name, - "Password": password, - } - _, err := self.ramRequest("UpdateLoginProfile", params) - if err != nil { - return errors.Wrap(err, "ramRequest.CreateLoginProfile") - } - return nil -} - -func (self *SAliyunClient) ResetClouduserPassword(name, password string) error { - _, err := self.GetLoginProfile(name) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - _, err = self.CreateLoginProfile(name, password) - return err - } - return errors.Wrap(err, "GetLoginProfile") - } - return self.UpdateLoginProfile(name, password) -} - -func (self *SAliyunClient) GetIamLoginUrl() string { - params := map[string]string{} - resp, err := self.ramRequest("GetAccountAlias", params) - if err != nil { - log.Errorf("GetAccountAlias error: %v", err) - return "" - } - alias, _ := resp.GetString("AccountAlias") - if len(alias) > 0 { - return fmt.Sprintf("https://signin.aliyun.com/%s.onaliyun.com/login.htm", alias) - } - return "" -} - -// https://help.aliyun.com/document_detail/28707.html?spm=a2c4g.11186623.6.752.f4466bbfVy5j0s -func (self *SAliyunClient) ListGroupsForUser(user string) ([]SGroup, error) { - params := map[string]string{ - "UserName": user, - } - resp, err := self.ramRequest("ListGroupsForUser", params) - if err != nil { - return nil, errors.Wrap(err, "ListGroupsForUser") - } - groups := []SGroup{} - err = resp.Unmarshal(&groups, "Groups", "Group") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return groups, nil -} - -// https://help.aliyun.com/document_detail/28732.html?spm=a2c4g.11186623.6.777.580735b2m2xUh8 -func (self *SAliyunClient) ListPoliciesForUser(user string) ([]SPolicy, error) { - params := map[string]string{ - "UserName": user, - } - resp, err := self.ramRequest("ListPoliciesForUser", params) - if err != nil { - return nil, errors.Wrap(err, "ListPoliciesForUser") - } - policies := []SPolicy{} - err = resp.Unmarshal(&policies, "Policies", "Policy") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return policies, nil -} diff --git a/pkg/multicloud/aliyun/ramimage.go b/pkg/multicloud/aliyun/ramimage.go deleted file mode 100644 index 18cbcb6cae..0000000000 --- a/pkg/multicloud/aliyun/ramimage.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - AliyunECSImageImportRole = "AliyunECSImageImportDefaultRole" - AliyunECSImageImportRoleDocument = `{ -"Statement": [ -{ -"Action": "sts:AssumeRole", -"Effect": "Allow", -"Principal": { - "Service": [ - "ecs.aliyuncs.com" - ] -} -} -], -"Version": "1" -}` - - AliyunECSImageImportRolePolicyType = "System" - AliyunECSImageImportRolePolicy = "AliyunECSImageImportRolePolicy" - AliyunECSImageImportRolePolicyDocument = `{ -"Version": "1", -"Statement": [ -{ -"Action": [ - "oss:GetObject", - "oss:GetBucketLocation" -], -"Resource": "*", -"Effect": "Allow" -} -] -}` -) - -func (self *SAliyunClient) EnableImageImport() error { - _, err := self.GetRole(AliyunECSImageImportRole) - if err != nil { - if errors.Cause(err) != cloudprovider.ErrNotFound { - return err - } - _, err = self.CreateRole(AliyunECSImageImportRole, - AliyunECSImageImportRoleDocument, - "Allow Import External Image from OSS") - if err != nil { - return err - } - } - - _, err = self.GetPolicy(AliyunECSImageImportRolePolicyType, AliyunECSImageImportRolePolicy) - if err != nil { - /*if err != cloudprovider.ErrNotFound { - return err - } - _, err = self.createPolicy(AliyunECSImageImportRolePolicy, - AliyunECSImageImportRolePolicyDocument, - "Allow Import External Image policy") - if err != nil { - return err - }*/ - return err - } - - policies, err := self.ListPoliciesForRole(AliyunECSImageImportRole) - if err != nil { - return err - } - for i := 0; i < len(policies); i += 1 { - if policies[i].PolicyType == AliyunECSImageImportRolePolicyType && - policies[i].PolicyName == AliyunECSImageImportRolePolicy { - return nil // find policy - } - } - - err = self.AttachPolicy2Role(AliyunECSImageImportRolePolicyType, AliyunECSImageImportRolePolicy, AliyunECSImageImportRole) - if err != nil { - return err - } - - return nil -} - -const ( - AliyunECSImageExportRole = "AliyunECSImageExportDefaultRole" - AliyunECSImageExportRoleDocument = `{ - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": [ - "ecs.aliyuncs.com" - ] - } - } - ], - "Version": "1" -}` - - AliyunEmptyRoleDocument = `{ - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": [ - "ecs.aliyuncs.com" - ] - } - } - ], - "Version": "1" -}` - - AliyunECSImageExportRolePolicyType = "System" - AliyunECSImageExportRolePolicy = "AliyunECSImageExportRolePolicy" - AliyunECSImageExportRolePolicyDocument = `{ - "Version": "1", - "Statement": [ - { - "Action": [ - "oss:GetObject", - "oss:PutObject", - "oss:DeleteObject", - "oss:GetBucketLocation", - "oss:AbortMultipartUpload", - "oss:ListMultipartUploads", - "oss:ListParts" - ], - "Resource": "*", - "Effect": "Allow" - } - ] - }` -) - -func (self *SAliyunClient) EnableImageExport() error { - _, err := self.GetRole(AliyunECSImageExportRole) - if err != nil { - if err != cloudprovider.ErrNotFound { - return err - } - _, err = self.CreateRole(AliyunECSImageExportRole, - AliyunECSImageExportRoleDocument, - "Allow Export Import to OSS") - if err != nil { - return err - } - } - - _, err = self.GetPolicy(AliyunECSImageExportRolePolicyType, AliyunECSImageExportRolePolicy) - if err != nil { - /*if err != cloudprovider.ErrNotFound { - return err - } - _, err = self.createPolicy(AliyunECSImageImportRolePolicy, - AliyunECSImageImportRolePolicyDocument, - "Allow Import External Image policy") - if err != nil { - return err - }*/ - return err - } - - policies, err := self.ListPoliciesForRole(AliyunECSImageExportRole) - if err != nil { - return err - } - for i := 0; i < len(policies); i += 1 { - if policies[i].PolicyType == AliyunECSImageExportRolePolicyType && - policies[i].PolicyName == AliyunECSImageExportRolePolicy { - return nil // find policy - } - } - - err = self.AttachPolicy2Role(AliyunECSImageExportRolePolicyType, AliyunECSImageExportRolePolicy, AliyunECSImageExportRole) - if err != nil { - return err - } - - return nil -} diff --git a/pkg/multicloud/aliyun/region.go b/pkg/multicloud/aliyun/region.go deleted file mode 100644 index ad37e08ca7..0000000000 --- a/pkg/multicloud/aliyun/region.go +++ /dev/null @@ -1,1255 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "github.com/aliyun/alibaba-cloud-sdk-go/sdk" - "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" - "github.com/aliyun/aliyun-oss-go-sdk/oss" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/regutils" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - multicloud.SRegion - - client *SAliyunClient - sdkClient *sdk.Client - ossClient *oss.Client - mongoSkus map[string]struct { - CpuCount int - MemSizeGb int - } - - RegionId string - LocalName string - - RegionEndpoint string - - izones []cloudprovider.ICloudZone - - ivpcs []cloudprovider.ICloudVpc - - lbEndpints map[string]string - - storageCache *SStoragecache - - instanceTypes []SInstanceType - - latitude float64 - longitude float64 - fetchLocation bool -} - -func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetClient() *SAliyunClient { - return self.client -} - -func (self *SRegion) getSdkClient() (*sdk.Client, error) { - if self.sdkClient == nil { - cli, err := self.client.getSdkClient(self.RegionId) - if err != nil { - return nil, err - } - self.sdkClient = cli - } - return self.sdkClient, nil -} - -func (self *SRegion) getEcsClient() (*ecs.Client, error) { - sdkClient, err := self.getSdkClient() - if err != nil { - return nil, errors.Wrap(err, "getSdkClient") - } - ecsClient := &ecs.Client{ - Client: *sdkClient, - } - return ecsClient, nil -} - -func (self *SRegion) getOSSExternalDomain() string { - return getOSSExternalDomain(self.RegionId) -} - -func (self *SRegion) getOSSInternalDomain() string { - return getOSSInternalDomain(self.RegionId) -} - -func (self *SRegion) getRegionId() string { - if self.client.cloudEnv == ALIYUN_FINANCE_CLOUDENV { - switch self.RegionId { - case "cn-hangzhou": - return "cn-hzfinance" - case "cn-shanghai-finance-1": - return "cn-shanghai-finance-1-pub" - case "cn-shenzhen-finance-1": - return "cn-szfinance" - } - } - return self.RegionId -} - -func (self *SRegion) GetOssClient() (*oss.Client, error) { - if self.ossClient == nil { - cli, err := self.client.getOssClient(self.getRegionId()) - if err != nil { - return nil, errors.Wrap(err, "self.client.getOssClient") - } - self.ossClient = cli - } - return self.ossClient, nil -} - -func (self *SRegion) ecsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - endpoint := self.RegionEndpoint - if len(endpoint) == 0 { - endpoint = "ecs.aliyuncs.com" - } - params = self.client.SetResourceGropuId(params) - return jsonRequest(client, endpoint, ALIYUN_API_VERSION, apiName, params, self.client.debug) -} - -func (self *SRegion) wafRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - if self.RegionId != "cn-hangzhou" && self.RegionId != "ap-southeast-1" { - return nil, cloudprovider.ErrNotSupported - } - params = self.client.SetResourceGropuId(params) - endpoint := fmt.Sprintf("wafopenapi.%s.aliyuncs.com", self.RegionId) - return jsonRequest(client, endpoint, ALIYUN_WAF_API_VERSION, apiName, params, self.client.debug) -} - -func (self *SRegion) esRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - params = self.client.SetResourceGropuId(params) - domain := fmt.Sprintf("elasticsearch.%s.aliyuncs.com", self.RegionId) - return jsonRequest(client, domain, ALIYUN_ES_API_VERSION, apiName, params, self.client.debug) -} - -func (self *SRegion) kafkaRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - params = self.client.SetResourceGropuId(params) - domain := fmt.Sprintf("alikafka.%s.aliyuncs.com", self.RegionId) - return jsonRequest(client, domain, ALIYUN_KAFKA_API_VERSION, apiName, params, self.client.debug) -} - -func (self *SRegion) rdsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - params = self.client.SetResourceGropuId(params) - return jsonRequest(client, "rds.aliyuncs.com", ALIYUN_RDS_API_VERSION, apiName, params, self.client.debug) -} - -func (self *SRegion) k8sRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - params = self.client.SetResourceGropuId(params) - return jsonRequest(client, fmt.Sprintf("cs.%s.aliyuncs.com", self.RegionId), ALIYUN_K8S_API_VERSION, apiName, params, self.client.debug) -} - -func (self *SRegion) mongodbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - params = self.client.SetResourceGropuId(params) - return jsonRequest(client, "mongodb.aliyuncs.com", ALIYUN_MONGO_DB_API_VERSION, apiName, params, self.client.debug) -} - -func (self *SRegion) vpcRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - params = self.client.SetResourceGropuId(params) - endpoint := self.GetClient().getVpcEndpoint(self.RegionId) - return jsonRequest(client, endpoint, ALIYUN_API_VERSION_VPC, action, params, self.client.debug) -} - -func (self *SRegion) nasRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - switch self.GetCloudEnv() { - case ALIYUN_FINANCE_CLOUDENV: - if strings.Contains(action, "FileSystem") { - if self.RegionId == "cn-hangzhou" { - params["RegionId"] = "cn-hangzhou-dg-a01" - } - } - if strings.Contains(action, "Access") || strings.Contains(action, "MountTarget") { - if self.RegionId == "cn-hangzhou" { - params["RegionId"] = "cn-hangzhou-finance" - } - } - } - - params = self.client.SetResourceGropuId(params) - endpint := self.GetClient().getNasEndpoint(self.RegionId) - return jsonRequest(client, endpint, ALIYUN_NAS_API_VERSION, action, params, self.client.debug) -} - -func (self *SRegion) kvsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - - if _, ok := params["RegionId"]; ok { - params["RegionId"] = transRegionIdFromEcsRegionId(self, "redis") - } - - params = self.client.SetResourceGropuId(params) - return jsonRequest(client, "r-kvstore.aliyuncs.com", ALIYUN_API_VERSION_KVS, action, params, self.client.debug) -} - -type LBRegion struct { - RegionEndpoint string - RegionId string -} - -func (self *SRegion) fetchLBRegions(client *sdk.Client) error { - if len(self.lbEndpints) > 0 { - return nil - } - params := map[string]string{} - result, err := self._lbRequest(client, "DescribeRegions", "slb.aliyuncs.com", params) - if err != nil { - return err - } - self.lbEndpints = map[string]string{} - regions := []LBRegion{} - if err := result.Unmarshal(®ions, "Regions", "Region"); err != nil { - return err - } - for _, region := range regions { - self.lbEndpints[region.RegionId] = region.RegionEndpoint - } - return nil -} - -func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - domain := "slb.aliyuncs.com" - if !utils.IsInStringArray(apiName, []string{"DescribeRegions", "DescribeZones"}) { - if regionId, ok := params["RegionId"]; ok { - if err := self.fetchLBRegions(client); err != nil { - return nil, err - } - endpoint, ok := self.lbEndpints[regionId] - if !ok { - return nil, fmt.Errorf("failed to find endpoint for lb region %s", regionId) - } - domain = endpoint - } - } - params = self.client.SetResourceGropuId(params) - return self._lbRequest(client, apiName, domain, params) -} - -func (self *SRegion) _lbRequest(client *sdk.Client, apiName string, domain string, params map[string]string) (jsonutils.JSONObject, error) { - return jsonRequest(client, domain, ALIYUN_API_VERSION_LB, apiName, params, self.client.debug) -} - -///////////////////////////////////////////////////////////////////////////// -func (self *SRegion) GetId() string { - return self.RegionId -} - -func (self *SRegion) GetName() string { - if self.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV && !strings.Contains(self.LocalName, "金融") { - return fmt.Sprintf("%s %s %s", CLOUD_PROVIDER_ALIYUN_CN, self.LocalName, "金融云") - } else { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_ALIYUN_CN, self.LocalName) - } -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_ALIYUN_EN, self.LocalName) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.RegionId) -} - -func (self *SRegion) IsEmulated() bool { - return false -} - -func (self *SRegion) GetProvider() string { - return CLOUD_PROVIDER_ALIYUN -} - -func (self *SRegion) GetCloudEnv() string { - return self.client.cloudEnv -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - if info, ok := LatitudeAndLongitude[self.RegionId]; ok { - return info - } - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) Refresh() error { - // do nothing - return nil -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if self.izones == nil { - var err error - err = self.fetchInfrastructure() - if err != nil { - return nil, err - } - } - return self.izones, nil -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) getStoragecache() *SStoragecache { - if self.storageCache == nil { - self.storageCache = &SStoragecache{region: self} - } - return self.storageCache -} - -func (self *SRegion) _fetchZones(chargeType TChargeType, spotStrategy SpotStrategyType) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - if len(chargeType) > 0 { - params["InstanceChargeType"] = string(chargeType) - } - if len(spotStrategy) > 0 { - params["SpotStrategy"] = string(spotStrategy) - } - body, err := self.ecsRequest("DescribeZones", params) - if err != nil { - return err - } - - zones := make([]SZone, 0) - err = body.Unmarshal(&zones, "Zones", "Zone") - if err != nil { - return err - } - - self.izones = make([]cloudprovider.ICloudZone, len(zones)) - - for i := 0; i < len(zones); i += 1 { - zones[i].region = self - self.izones[i] = &zones[i] - } - - return nil -} - -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) -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - return self.GetInstance(id) -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return self.getDisk(id) -} - -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) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - ivpcs, err := self.GetIVpcs() - if err != nil { - return nil, err - } - for i := 0; i < len(ivpcs); i += 1 { - if ivpcs[i].GetGlobalId() == id { - return ivpcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) fetchIVpcs() error { - vpcs := make([]SVpc, 0) - for { - part, total, err := self.GetVpcs(nil, len(vpcs), 50) - if err != nil { - return err - } - vpcs = append(vpcs, part...) - if len(vpcs) >= total { - break - } - } - self.ivpcs = make([]cloudprovider.ICloudVpc, len(vpcs)) - for i := 0; i < len(vpcs); i += 1 { - vpcs[i].region = self - self.ivpcs[i] = &vpcs[i] - } - return nil -} - -func (self *SRegion) fetchInfrastructure() error { - err := self._fetchZones(PostPaidInstanceChargeType, NoSpotStrategy) - if err != nil { - return err - } - err = self.fetchIVpcs() - if 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) GetVpcs(vpcId []string, offset int, limit int) ([]SVpc, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - if vpcId != nil && len(vpcId) > 0 { - params["VpcId"] = strings.Join(vpcId, ",") - } - - body, err := self.vpcRequest("DescribeVpcs", params) - if err != nil { - log.Errorf("GetVpcs fail %s", err) - return nil, 0, err - } - - vpcs := make([]SVpc, 0) - err = body.Unmarshal(&vpcs, "Vpcs", "Vpc") - if err != nil { - log.Errorf("Unmarshal vpc fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return vpcs, int(total), 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) GetVRouters(offset int, limit int) ([]SVRouter, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - body, err := self.ecsRequest("DescribeVRouters", params) - if err != nil { - log.Errorf("GetVRouters fail %s", err) - return nil, 0, err - } - - vrouters := make([]SVRouter, 0) - err = body.Unmarshal(&vrouters, "VRouters", "VRouter") - if err != nil { - log.Errorf("Unmarshal vrouter fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return vrouters, int(total), nil -} - -func (self *SRegion) GetRouteTables(ids []string, offset int, limit int) ([]SRouteTable, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - if ids != nil && len(ids) > 0 { - params["RouteTableId"] = strings.Join(ids, ",") - } - - body, err := self.ecsRequest("DescribeRouteTables", params) - if err != nil { - log.Errorf("GetRouteTables fail %s", err) - return nil, 0, err - } - - routetables := make([]SRouteTable, 0) - err = body.Unmarshal(&routetables, "RouteTables", "RouteTable") - if err != nil { - log.Errorf("Unmarshal routetables fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return routetables, int(total), nil -} - -func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, gpu int, zoneId string) ([]SInstanceType, error) { - if self.instanceTypes == nil { - types, err := self.GetInstanceTypes() - if err != nil { - log.Errorf("GetInstanceTypes %s", err) - return nil, err - } - self.instanceTypes = types - } - var available []string - if len(zoneId) > 0 { - zone, err := self.getZoneById(zoneId) - if err != nil { - return nil, err - } - available = zone.AvailableInstanceTypes.InstanceTypes - } - ret := make([]SInstanceType, 0) - for _, t := range self.instanceTypes { - if t.CpuCoreCount == cpu && memMB == t.memoryMB() && gpu == t.GPUAmount { - if available == nil || utils.IsInStringArray(t.InstanceTypeId, available) { - ret = append(ret, t) - } - } - } - return ret, nil -} - -func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, memGB int, storageType string, dataDiskSizesGB []int, vswitchId string, passwd 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(vswitchId) - if net != nil { - desc := &cloudprovider.SManagedVMCreateConfig{ - Name: name, - ExternalImageId: imgId, - SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType}, - Cpu: cpu, - MemoryMB: memGB * 1024, - ExternalNetworkId: vswitchId, - Password: passwd, - DataDisks: []cloudprovider.SDiskInfo{}, - PublicKey: publicKey, - } - for _, sizeGB := range dataDiskSizesGB { - desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType}) - } - inst, err := z.getHost().CreateVM(desc) - if err != nil { - return nil, err - } - return inst.(*SInstance), nil - } - } - return nil, fmt.Errorf("cannot find vswitch %s", vswitchId) -} - -func (self *SRegion) instanceOperation(instanceId string, opname string, extra map[string]string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - if extra != nil && len(extra) > 0 { - for k, v := range extra { - params[k] = v - } - } - _, err := self.ecsRequest(opname, params) - return err -} - -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) GetInstanceVNCUrl(instanceId string) (string, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - body, err := self.ecsRequest("DescribeInstanceVncUrl", params) - if err != nil { - return "", err - } - return body.GetString("VncUrl") -} - -func (self *SRegion) ModifyInstanceVNCUrlPassword(instanceId string, passwd string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - params["VncPassword"] = passwd // must be 6 digital + alphabet - _, err := self.ecsRequest("ModifyInstanceVncPasswd", params) - return err -} - -func (self *SRegion) CreateVpc(opts *cloudprovider.VpcCreateOptions) (*SVpc, error) { - params := make(map[string]string) - if len(opts.CIDR) > 0 { - params["CidrBlock"] = opts.CIDR - } - if len(opts.NAME) > 0 { - params["VpcName"] = opts.NAME - } - if len(opts.Desc) > 0 { - params["Description"] = opts.Desc - } - params["ClientToken"] = utils.GenRequestId(20) - body, err := self.ecsRequest("CreateVpc", params) - if err != nil { - return nil, err - } - vpcId, err := body.GetString("VpcId") - if err != nil { - return nil, err - } - err = self.fetchInfrastructure() - if err != nil { - return nil, err - } - return self.getVpc(vpcId) -} - -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - vpc, err := self.CreateVpc(opts) - if err != nil { - return nil, err - } - return vpc, nil -} - -func (self *SRegion) DeleteVpc(vpcId string) error { - params := make(map[string]string) - params["VpcId"] = vpcId - - _, err := self.ecsRequest("DeleteVpc", params) - return err -} - -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 errors.Cause(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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - iHosts := make([]cloudprovider.ICloudHost, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneHost, err := izones[i].GetIHosts() - if err != nil { - return nil, err - } - iHosts = append(iHosts, iZoneHost...) - } - return iHosts, nil -} - -func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname, userData string) error { - params := make(map[string]string) - params["InstanceId"] = instId - if len(name) > 0 { - params["InstanceName"] = name - } - if len(desc) > 0 { - params["Description"] = desc - } - if len(passwd) > 0 { - params["Password"] = passwd - } - if len(hostname) > 0 { - params["HostName"] = hostname - } - if len(userData) > 0 { - params["UserData"] = userData - } - _, err := self.ecsRequest("ModifyInstanceAttribute", params) - return err -} - -func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error { - return self.updateInstance(instId, "", "", passwd, "", "") -} - -// func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { -// eips, total, err := self.GetSnapshots("", 0, 50) -// if err != nil { -// return nil, err -// } -// for len(eips) < total { -// var parts []SEipAddress -// parts, total, err = self.GetEips("", len(eips), 50) -// if err != nil { -// return nil, err -// } -// eips = append(eips, parts...) -// } -// ret := make([]cloudprovider.ICloudEIP, len(eips)) -// for i := 0; i < len(eips); i += 1 { -// ret[i] = &eips[i] -// } -// return ret, nil -// } - -func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, total, err := self.GetEips("", "", "", 0, 50) - if err != nil { - return nil, err - } - for len(eips) < total { - var parts []SEipAddress - parts, total, err = self.GetEips("", "", "", len(eips), 50) - if err != nil { - return nil, err - } - eips = append(eips, parts...) - } - ret := make([]cloudprovider.ICloudEIP, len(eips)) - for i := 0; i < len(eips); i += 1 { - ret[i] = &eips[i] - } - return ret, nil -} - -func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { - eips, total, err := self.GetEips(eipId, "", "", 0, 1) - 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 (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - secgroup, err := region.GetSecurityGroupDetails(secgroupId) - if err != nil { - return nil, err - } - vpc, err := region.getVpc(secgroup.VpcId) - if err != nil { - return nil, errors.Wrapf(err, "region.getVpc(%s)", secgroup.VpcId) - } - secgroup.vpc = vpc - return secgroup, nil -} - -func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, total, err := region.GetSecurityGroups(opts.VpcId, opts.Name, []string{}, 0, 0) - if err != nil { - return nil, err - } - if total == 0 { - return nil, cloudprovider.ErrNotFound - } - if total > 1 { - return nil, cloudprovider.ErrDuplicateId - } - return &secgroups[0], nil -} - -func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - externalId, err := region.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) - if err != nil { - return nil, err - } - return region.GetISecurityGroupById(externalId) -} - -func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - lbs, err := region.GetLoadbalancers(nil) - if err != nil { - return nil, err - } - ilbs := []cloudprovider.ICloudLoadbalancer{} - for i := 0; i < len(lbs); i++ { - lbs[i].region = region - ilbs = append(ilbs, &lbs[i]) - } - return ilbs, nil -} - -func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { - return region.GetLoadbalancerDetail(loadbalancerId) -} - -func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - certs, err := region.GetLoadbalancerServerCertificates() - if err != nil { - return nil, err - } - for i := 0; i < len(certs); i++ { - if certs[i].GetGlobalId() == certId { - certs[i].region = region - return &certs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["ServerCertificateName"] = cert.Name - params["PrivateKey"] = cert.PrivateKey - params["ServerCertificate"] = cert.Certificate - body, err := region.lbRequest("UploadServerCertificate", params) - if err != nil { - return nil, err - } - certID, err := body.GetString("ServerCertificateId") - if err != nil { - return nil, err - } - return region.GetILoadBalancerCertificateById(certID) -} - -func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { - return region.GetLoadbalancerAclDetail(aclId) -} - -func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { - acls, err := region.GetLoadBalancerAcls() - if err != nil { - return nil, err - } - iAcls := []cloudprovider.ICloudLoadbalancerAcl{} - for i := 0; i < len(acls); i++ { - acls[i].region = region - iAcls = append(iAcls, &acls[i]) - } - return iAcls, nil -} - -func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - certificates, err := region.GetLoadbalancerServerCertificates() - if err != nil { - return nil, err - } - iCertificates := []cloudprovider.ICloudLoadbalancerCertificate{} - for i := 0; i < len(certificates); i++ { - certificates[i].region = region - iCertificates = append(iCertificates, &certificates[i]) - } - return iCertificates, nil -} - -func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerName"] = loadbalancer.Name - if len(loadbalancer.ZoneID) > 0 { - params["MasterZoneId"] = transZoneIdFromEcsZoneId(region, "elb", loadbalancer.ZoneID) - } - - if len(loadbalancer.VpcID) > 0 { - params["VpcId"] = loadbalancer.VpcID - } - - if len(loadbalancer.NetworkIDs) > 0 { - params["VSwitchId"] = loadbalancer.NetworkIDs[0] - } - - if len(loadbalancer.Address) > 0 { - params["Address"] = loadbalancer.Address - } - - if len(loadbalancer.AddressType) > 0 { - params["AddressType"] = loadbalancer.AddressType - } - - if len(loadbalancer.LoadbalancerSpec) > 0 { - params["LoadBalancerSpec"] = loadbalancer.LoadbalancerSpec - } - - if len(loadbalancer.ChargeType) > 0 { - params["InternetChargeType"] = "payby" + loadbalancer.ChargeType - } - - if len(loadbalancer.ProjectId) > 0 { - params["ResourceGroupId"] = loadbalancer.ProjectId - } - - if loadbalancer.ChargeType == api.LB_CHARGE_TYPE_BY_BANDWIDTH && loadbalancer.EgressMbps > 0 { - params["Bandwidth"] = fmt.Sprintf("%d", loadbalancer.EgressMbps) - } - - body, err := region.lbRequest("CreateLoadBalancer", params) - if err != nil { - return nil, err - } - loadBalancerID, err := body.GetString("LoadBalancerId") - if err != nil { - return nil, err - } - region.SetResourceTags(ALIYUN_SERVICE_SLB, "instance", loadBalancerID, loadbalancer.Tags, false) - iLoadbalancer, err := region.GetLoadbalancerDetail(loadBalancerID) - if err != nil { - return nil, err - } - return iLoadbalancer, cloudprovider.WaitStatus(iLoadbalancer, api.LB_STATUS_ENABLED, time.Second*5, time.Minute*5) -} - -func (region *SRegion) AddAccessControlListEntry(aclId string, entrys []cloudprovider.SLoadbalancerAccessControlListEntry) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["AclId"] = aclId - aclArray := jsonutils.NewArray() - for i := 0; i < len(entrys); i++ { - //阿里云AclEntrys参数必须是CIDR格式的。 - if regutils.MatchIPAddr(entrys[i].CIDR) { - entrys[i].CIDR += "/32" - } - aclArray.Add(jsonutils.Marshal(map[string]string{"entry": entrys[i].CIDR, "comment": entrys[i].Comment})) - } - if aclArray.Length() == 0 { - return nil - } - params["AclEntrys"] = aclArray.String() - _, err := region.lbRequest("AddAccessControlListEntry", params) - return err -} - -func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["AclName"] = acl.Name - body, err := region.lbRequest("CreateAccessControlList", params) - if err != nil { - return nil, err - } - aclId, err := body.GetString("AclId") - if err != nil { - return nil, err - } - iAcl, err := region.GetLoadbalancerAclDetail(aclId) - if err != nil { - return nil, err - } - return iAcl, region.AddAccessControlListEntry(aclId, acl.Entrys) -} - -func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - iBuckets, err := region.client.getIBuckets() - if err != nil { - return nil, errors.Wrap(err, "getIBuckets") - } - ret := make([]cloudprovider.ICloudBucket, 0) - for i := range iBuckets { - if iBuckets[i].GetIRegion().GetId() != region.GetId() { - continue - } - ret = append(ret, iBuckets[i]) - } - return ret, nil -} - -func str2StorageClass(storageClassStr string) (oss.StorageClassType, error) { - storageClass := oss.StorageStandard - if strings.EqualFold(storageClassStr, string(oss.StorageStandard)) { - // - } else if strings.EqualFold(storageClassStr, string(oss.StorageIA)) { - storageClass = oss.StorageIA - } else if strings.EqualFold(storageClassStr, string(oss.StorageArchive)) { - storageClass = oss.StorageArchive - } else { - return storageClass, errors.Error("not supported storageClass") - } - return storageClass, nil -} - -func str2Acl(aclStr string) (oss.ACLType, error) { - acl := oss.ACLPrivate - if strings.EqualFold(aclStr, string(oss.ACLPrivate)) { - // private, default - } else if strings.EqualFold(aclStr, string(oss.ACLPublicRead)) { - acl = oss.ACLPublicRead - } else if strings.EqualFold(aclStr, string(oss.ACLPublicReadWrite)) { - acl = oss.ACLPublicReadWrite - } else { - return acl, errors.Error("not supported acl") - } - return acl, nil -} - -func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { - osscli, err := region.GetOssClient() - if err != nil { - return errors.Wrap(err, "region.GetOssClient") - } - opts := make([]oss.Option, 0) - if len(storageClassStr) > 0 { - storageClass, err := str2StorageClass(storageClassStr) - if err != nil { - return err - } - opts = append(opts, oss.StorageClass(storageClass)) - } - if len(aclStr) > 0 { - acl, err := str2Acl(aclStr) - if err != nil { - return err - } - opts = append(opts, oss.ACL(acl)) - } - err = osscli.CreateBucket(name, opts...) - if err != nil { - return errors.Wrap(err, "oss.CreateBucket") - } - region.client.invalidateIBuckets() - return nil -} - -func ossErrorCode(err error) int { - if srvErr, ok := err.(oss.ServiceError); ok { - return srvErr.StatusCode - } - if srvErr, ok := err.(*oss.ServiceError); ok { - return srvErr.StatusCode - } - return -1 -} - -func (region *SRegion) DeleteIBucket(name string) error { - osscli, err := region.GetOssClient() - if err != nil { - return errors.Wrap(err, "region.GetOssClient") - } - err = osscli.DeleteBucket(name) - if err != nil { - if ossErrorCode(err) == 404 { - return nil - } - return errors.Wrap(err, "DeleteBucket") - } - region.client.invalidateIBuckets() - return nil -} - -func (region *SRegion) IBucketExist(name string) (bool, error) { - osscli, err := region.GetOssClient() - if err != nil { - return false, errors.Wrap(err, "region.GetOssClient") - } - exist, err := osscli.IsBucketExist(name) - if err != nil { - return false, errors.Wrap(err, "IsBucketExist") - } - return exist, nil -} - -func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { - osscli, err := region.GetOssClient() - if err != nil { - return nil, errors.Wrap(err, "region.GetOssClient") - } - bi, err := osscli.GetBucketInfo(name) - if err != nil { - return nil, errors.Wrap(err, "Bucket") - } - bInfo := bi.BucketInfo - b := SBucket{ - region: region, - Name: bInfo.Name, - Location: bInfo.Location, - CreationDate: bInfo.CreationDate, - StorageClass: bInfo.StorageClass, - } - return &b, nil -} - -func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { - return region.GetIBucketById(name) -} - -func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { - caches, err := self.GetElasticCaches(nil) - if err != nil { - return nil, err - } - - icaches := make([]cloudprovider.ICloudElasticcache, len(caches)) - for i := range caches { - caches[i].region = self - icaches[i] = &caches[i] - } - - return icaches, nil -} - -func (region *SRegion) GetCapabilities() []string { - return region.client.GetCapabilities() -} - -func (self *SRegion) trialRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - domain := fmt.Sprintf("actiontrail.%s.aliyuncs.com", self.RegionId) - return jsonRequest(client, domain, ALIYUN_API_VERSION_TRIAL, apiName, params, self.client.debug) -} diff --git a/pkg/multicloud/aliyun/resource_tags.go b/pkg/multicloud/aliyun/resource_tags.go deleted file mode 100644 index 441dcea305..0000000000 --- a/pkg/multicloud/aliyun/resource_tags.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -func (self *SRegion) tagRequest(serviceType, action string, params map[string]string) (jsonutils.JSONObject, error) { - switch serviceType { - case ALIYUN_SERVICE_ECS: - return self.ecsRequest(action, params) - case ALIYUN_SERVICE_VPC: - return self.vpcRequest(action, params) - case ALIYUN_SERVICE_RDS: - return self.rdsRequest(action, params) - case ALIYUN_SERVICE_SLB: - return self.lbRequest(action, params) - case ALIYUN_SERVICE_KVS: - return self.kvsRequest(action, params) - case ALIYUN_SERVICE_NAS: - return self.nasRequest(action, params) - case ALIYUN_SERVICE_MONGO_DB: - return self.mongodbRequest(action, params) - case ALIYUN_SERVICE_CDN: - return self.client.cdnRequest(action, params) - default: - return nil, fmt.Errorf("invalid service type") - } -} - -// 资源类型。取值范围: -// disk, instance, image, securitygroup, snapshot -func (self *SRegion) ListTags(serviceType string, resourceType string, resourceId string) ([]SAliyunTag, error) { - tags := []SAliyunTag{} - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["ResourceType"] = resourceType - params["ResourceId.1"] = resourceId - nextToken := "" - for { - if len(nextToken) > 0 { - params["NextToken"] = nextToken - } - resp, err := self.tagRequest(serviceType, "ListTagResources", params) - if err != nil { - return nil, errors.Wrapf(err, "%s ListTagResources %s", serviceType, params) - } - part := []SAliyunTag{} - err = resp.Unmarshal(&part, "TagResources", "TagResource") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - tags = append(tags, part...) - nextToken, _ = resp.GetString("NextToken") - if len(nextToken) == 0 { - break - } - } - return tags, nil -} - -func (self *SRegion) UntagResource(serviceType string, resourceType string, resId string, keys []string) error { - if len(resId) == 0 || len(keys) == 0 { - return nil - } - - params := map[string]string{ - "RegionId": self.RegionId, - "ResourceId.1": resId, - "ResourceType": resourceType, - } - for i, key := range keys { - params[fmt.Sprintf("TagKey.%d", i+1)] = key - } - - _, err := self.tagRequest(serviceType, "UntagResources", params) - return errors.Wrapf(err, "UntagResources %s", params) -} - -func (self *SRegion) SetResourceTags(serviceType string, resourceType string, resId string, tags map[string]string, replace bool) error { - _, _tags, err := self.ListSysAndUserTags(serviceType, resourceType, resId) - if err != nil { - return errors.Wrapf(err, "ListTags") - } - keys, upperKeys := []string{}, []string{} - for k := range tags { - keys = append(keys, k) - upperKeys = append(upperKeys, strings.ToUpper(k)) - } - if replace { - if len(tags) > 0 { - removeKeys := []string{} - for k := range _tags { - if !utils.IsInStringArray(k, keys) { - removeKeys = append(removeKeys, k) - } - } - if len(removeKeys) > 0 { - err := self.UntagResource(serviceType, resourceType, resId, removeKeys) - if err != nil { - return errors.Wrapf(err, "UntagResource") - } - } - } - } else { - removeKeys := []string{} - for k := range _tags { - if !utils.IsInStringArray(k, keys) && utils.IsInStringArray(strings.ToUpper(k), upperKeys) { - removeKeys = append(removeKeys, k) - } - } - if len(removeKeys) > 0 { - err := self.UntagResource(serviceType, resourceType, resId, removeKeys) - if err != nil { - return errors.Wrapf(err, "UntagResource") - } - } - } - return self.TagResource(serviceType, resourceType, resId, tags) -} - -func (self *SRegion) TagResource(serviceType string, resourceType string, resourceId string, tags map[string]string) error { - if len(tags) > 20 { - return errors.Wrap(cloudprovider.ErrNotSupported, "tags count exceed 20 for one request") - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["ResourceType"] = resourceType - params["ResourceId.1"] = resourceId - i := 0 - for k, v := range tags { - if strings.HasPrefix(k, "aliyun") || - strings.HasPrefix(k, "acs:") || - strings.HasPrefix(k, "http://") || - strings.HasPrefix(k, "https://") || - strings.HasPrefix(v, "http://") || - strings.HasPrefix(v, "https://") || - strings.HasPrefix(v, "acs:") { - continue - } - params[fmt.Sprintf("Tag.%d.Key", i+1)] = k - params[fmt.Sprintf("Tag.%d.Value", i+1)] = v - i++ - } - action := "TagResources" - if len(tags) == 0 { - action = "UntagResources" - params["All"] = "true" - } - _, err := self.tagRequest(serviceType, action, params) - if err != nil { - return errors.Wrapf(err, "%s %s %s", action, resourceId, params) - } - return nil -} - -func (self *SRegion) ListSysAndUserTags(serviceType string, resourceType string, resourceId string) (map[string]string, map[string]string, error) { - tags, err := self.ListTags(serviceType, resourceType, resourceId) - if err != nil { - return nil, nil, errors.Wrapf(err, "ListTags(%s, %s)", resourceType, resourceId) - } - sys, user := map[string]string{}, map[string]string{} - for _, tag := range tags { - if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") { - sys[tag.TagKey] = tag.TagValue - continue - } - user[tag.TagKey] = tag.TagValue - } - return sys, user, nil -} diff --git a/pkg/multicloud/aliyun/routetable.go b/pkg/multicloud/aliyun/routetable.go deleted file mode 100644 index e49f9d9090..0000000000 --- a/pkg/multicloud/aliyun/routetable.go +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// {"CreationTime":"2017-03-19T13:37:40Z","RouteEntrys":{"RouteEntry":[{"DestinationCidrBlock":"172.31.32.0/20","InstanceId":"","NextHopType":"local","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"},{"DestinationCidrBlock":"100.64.0.0/10","InstanceId":"","NextHopType":"service","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"}]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","RouteTableType":"System","VRouterId":"vrt-j6c00qrol733dg36iq4qj"} - -type SNextHops struct { - NextHop []string -} - -type SRouteEntry struct { - multicloud.SResourceBase - multicloud.AliyunTags - routeTable *SRouteTable - - RouteTableId string - Type string - DestinationCidrBlock string - NextHopType string - InstanceId string - RouteEntryId string - RouteEntryName string - NextHops SNextHops -} - -func (route *SRouteEntry) GetId() string { - return fmt.Sprintf("%s-%s-%s", route.RouteTableId, route.DestinationCidrBlock, route.NextHopType) -} - -func (route *SRouteEntry) GetName() string { - return route.RouteEntryName -} - -func (route *SRouteEntry) GetGlobalId() string { - return route.GetId() -} - -func (route *SRouteEntry) GetStatus() string { - return api.ROUTE_ENTRY_STATUS_AVAILIABLE -} - -func (route *SRouteEntry) Refresh() error { - return nil -} - -func (route *SRouteEntry) IsEmulated() bool { - return false -} - -// Custom:自定义路由。 System:系统路由。 -func (route *SRouteEntry) GetType() string { - return route.Type -} - -func (route *SRouteEntry) GetCidr() string { - return route.DestinationCidrBlock -} - -func (route *SRouteEntry) GetNextHopType() string { - switch route.NextHopType { - case "Instance": - return api.NEXT_HOP_TYPE_INSTANCE - case "HaVip": - return api.NEXT_HOP_TYPE_HAVIP - case "VpnGateway": - return api.NEXT_HOP_TYPE_VPN - case "NatGateway": - return api.NEXT_HOP_TYPE_NAT - case "NetworkInterface": - return api.NEXT_HOP_TYPE_NETWORK - case "RouterInterface": - return api.NEXT_HOP_TYPE_ROUTER - case "IPv6Gateway": - return api.NEXT_HOP_TYPE_IPV6 - case "InternetGateway": - return api.NEXT_HOP_TYPE_INTERNET - case "Next_HOP_TYPE_EGRESS_INTERNET": - return api.NEXT_HOP_TYPE_EGRESS_INTERNET - default: - return "" - } -} - -func (route *SRouteEntry) GetNextHop() string { - return route.InstanceId -} - -type SRouteEntrys struct { - RouteEntry []*SRouteEntry -} - -type SRouteTable struct { - multicloud.SResourceBase - multicloud.AliyunTags - region *SRegion - vpc *SVpc - routes []cloudprovider.ICloudRoute - - VpcId string - CreationTime time.Time - RouteEntrys SRouteEntrys - VRouterId string - Description string - - RouteTableId string - RouteTableName string - RouteTableType string - RouterId string - RouterType string - VSwitchIds SRouteTableVSwitchIds -} - -type SRouteTableVSwitchIds struct { - VSwitchId []string -} - -type sDescribeRouteTablesResponseRouteTables struct { - RouteTable []SRouteTable -} - -type sDescribeRouteTablesResponse struct { - RouteTables sDescribeRouteTablesResponseRouteTables - TotalCount int -} - -func (self *SRouteTable) GetDescription() string { - return self.Description -} - -func (self *SRouteTable) GetId() string { - return self.RouteTableId -} - -func (self *SRouteTable) GetGlobalId() string { - return self.RouteTableId -} - -func (self *SRouteTable) GetName() string { - return self.RouteTableName -} - -func (self *SRouteTable) GetRegionId() string { - return self.region.RegionId -} - -// VRouter:VPC路由器。 VBR:边界路由器。 -func (self *SRouteTable) GetType() cloudprovider.RouteTableType { - switch self.RouteTableType { - case "System": - return cloudprovider.RouteTableTypeSystem - case "Custom": - return cloudprovider.RouteTableTypeCustom - default: - return cloudprovider.RouteTableTypeSystem - } -} - -func (self *SRouteTable) GetVpcId() string { - return self.VpcId -} - -func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { - if self.routes == nil { - err := self.fetchRoutes() - if err != nil { - return nil, err - } - } - return self.routes, nil -} - -func (self *SRouteTable) GetStatus() string { - return api.ROUTE_TABLE_AVAILABLE -} - -func (self *SRouteTable) IsEmulated() bool { - return false -} - -func (self *SRouteTable) Refresh() error { - return nil -} - -func (self *SRouteTable) fetchRoutes() error { - routes := []*SRouteEntry{} - for { - parts, total, err := self.RemoteGetRoutes(len(routes), 50) - if err != nil { - return err - } - routes = append(routes, parts...) - if len(routes) >= total { - break - } - } - self.routes = make([]cloudprovider.ICloudRoute, len(routes)) - for i := 0; i < len(routes); i++ { - routes[i].routeTable = self - self.routes[i] = routes[i] - } - return nil -} - -func (self *SRouteTable) RemoteGetRoutes(offset int, limit int) ([]*SRouteEntry, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RouteTableId"] = self.RouteTableId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - body, err := self.region.ecsRequest("DescribeRouteTables", params) - if err != nil { - log.Errorf("RemoteGetRoutes fail %s", err) - return nil, 0, err - } - - resp := sDescribeRouteTablesResponse{} - err = body.Unmarshal(&resp) - if err != nil { - log.Errorf("Unmarshal routeEntrys fail %s", err) - return nil, 0, err - } - routeTables := resp.RouteTables.RouteTable - if len(routeTables) != 1 { - return nil, 0, fmt.Errorf("expecting 1 route table, got %d", len(routeTables)) - } - routeTable := routeTables[0] - return routeTable.RouteEntrys.RouteEntry, resp.TotalCount, nil -} - -func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { - result := []cloudprovider.RouteTableAssociation{} - switch self.RouterType { - case "VRouter": - for i := range self.VSwitchIds.VSwitchId { - association := cloudprovider.RouteTableAssociation{ - AssociationId: self.RouteTableId + ":" + self.VSwitchIds.VSwitchId[i], - AssociationType: cloudprovider.RouteTableAssociaToSubnet, - AssociatedResourceId: self.VSwitchIds.VSwitchId[i], - } - result = append(result, association) - } - case "VBR": - association := cloudprovider.RouteTableAssociation{ - AssociationId: self.RouteTableId + ":" + self.RouterId, - AssociationType: cloudprovider.RouteTableAssociaToRouter, - AssociatedResourceId: self.RouterId, - } - result = append(result, association) - } - - return result -} - -func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} - -func (self *SVpc) RemoteGetRouteTableList(offset int, limit int) ([]*SRouteTable, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["VpcId"] = self.VpcId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - body, err := self.region.vpcRequest("DescribeRouteTableList", params) - if err != nil { - log.Errorf("RemoteGetRouteTableList fail %s", err) - return nil, 0, err - } - - routeTables := make([]*SRouteTable, 0) - err = body.Unmarshal(&routeTables, "RouterTableList", "RouterTableListType") - if err != nil { - log.Errorf("Unmarshal routeTables fail %s", err) - return nil, 0, err - } - for _, routeTable := range routeTables { - routeTable.region = self.region - } - total, _ := body.Int("TotalCount") - return routeTables, int(total), nil -} - -func (region *SRegion) AssociateRouteTable(rtableId string, vswitchId string) error { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["RouteTableId"] = rtableId - params["VSwitchId"] = vswitchId - _, err := region.vpcRequest("AssociateRouteTable", params) - return err -} - -func (region *SRegion) UnassociateRouteTable(rtableId string, vswitchId string) error { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["RouteTableId"] = rtableId - params["VSwitchId"] = vswitchId - _, err := region.vpcRequest("UnassociateRouteTable", params) - return err -} - -func (routeTable *SRouteTable) IsSystem() bool { - return strings.ToLower(routeTable.RouteTableType) == "system" -} diff --git a/pkg/multicloud/aliyun/saml_provider.go b/pkg/multicloud/aliyun/saml_provider.go deleted file mode 100644 index 685ef86729..0000000000 --- a/pkg/multicloud/aliyun/saml_provider.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "encoding/base64" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis/cloudid" - api "yunion.io/x/onecloud/pkg/apis/cloudid" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/compute/options" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/httputils" - "yunion.io/x/onecloud/pkg/util/samlutils" -) - -type SAMLProvider struct { - multicloud.SResourceBase - multicloud.AliyunTags - client *SAliyunClient - - Arn string - CreateDate time.Time - Description string - SAMLProviderName string - UpdateDate time.Time - - // base64 - EncodedSAMLMetadataDocument string -} - -func (self *SAMLProvider) GetName() string { - return self.SAMLProviderName -} - -func (self *SAMLProvider) GetGlobalId() string { - return self.Arn -} - -func (self *SAMLProvider) GetId() string { - return self.Arn -} - -func (self *SAMLProvider) GetAuthUrl() string { - input := samlutils.SIdpInitiatedLoginInput{ - EntityID: cloudprovider.SAML_ENTITY_ID_ALIYUN_ROLE, - IdpId: self.client.cpcfg.AccountId, - } - return httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, fmt.Sprintf("sso?%s", jsonutils.Marshal(input).QueryString())) -} - -func (self *SAMLProvider) Delete() error { - return self.client.DeleteSAMLProvider(self.SAMLProviderName) -} - -func (self *SAMLProvider) GetStatus() string { - return api.SAML_PROVIDER_STATUS_AVAILABLE -} - -func (self *SAliyunClient) ListSAMLProviders(marker string, maxItems int) ([]SAMLProvider, string, error) { - if maxItems < 1 || maxItems > 100 { - maxItems = 100 - } - params := map[string]string{ - "MaxItems": fmt.Sprintf("%d", maxItems), - } - if len(marker) > 0 { - params["Marker"] = marker - } - resp, err := self.imsRequest("ListSAMLProviders", params) - if err != nil { - return nil, "", errors.Wrapf(err, "ListSAMLProviders") - } - result := []SAMLProvider{} - err = resp.Unmarshal(&result, "SAMLProviders", "SAMLProvider") - if err != nil { - return nil, "", errors.Wrapf(err, "resp.Unmarshal") - } - marker, _ = resp.GetString("Marker") - return result, marker, nil -} - -func (self *SAliyunClient) DeleteSAMLProvider(name string) error { - params := map[string]string{ - "SAMLProviderName": name, - } - _, err := self.imsRequest("DeleteSAMLProvider", params) - if err != nil { - return errors.Wrapf(err, "DeleteSAMLProvider") - } - return nil -} - -func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { - sp, err := self.client.GetSAMLProvider(self.SAMLProviderName) - if err != nil { - return nil, errors.Wrapf(err, "GetSAMLProvider(%s)", self.SAMLProviderName) - } - metadata, err := base64.StdEncoding.DecodeString(sp.EncodedSAMLMetadataDocument) - if err != nil { - return nil, errors.Wrapf(err, "DecodeString") - } - ret, err := samlutils.ParseMetadata(metadata) - if err != nil { - return nil, errors.Wrapf(err, "ParseMetadata") - } - return &ret, nil -} - -func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { - return self.client.UpdateSAMLProvider(self.SAMLProviderName, metadata.String()) -} - -func (self *SAliyunClient) GetSAMLProvider(name string) (*SAMLProvider, error) { - params := map[string]string{ - "SAMLProviderName": name, - } - resp, err := self.imsRequest("GetSAMLProvider", params) - if err != nil { - return nil, errors.Wrapf(err, "GetSAMLProvider") - } - sp := &SAMLProvider{client: self} - err = resp.Unmarshal(sp, "SAMLProvider") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return sp, nil -} - -func (self *SAliyunClient) UpdateSAMLProvider(name string, metadata string) error { - params := map[string]string{ - "SAMLProviderName": name, - "NewEncodedSAMLMetadataDocument": base64.StdEncoding.EncodeToString([]byte(metadata)), - } - _, err := self.imsRequest("UpdateSAMLProvider", params) - if err != nil { - return errors.Wrapf(err, "GetSAMLProvider") - } - return nil -} - -func (self *SAliyunClient) CreateSAMLProvider(name, metadata, desc string) (*SAMLProvider, error) { - name = strings.ReplaceAll(name, ":", "_") - params := map[string]string{ - "EncodedSAMLMetadataDocument": base64.StdEncoding.EncodeToString([]byte(metadata)), - "SAMLProviderName": name, - } - if len(desc) > 0 { - params["Description"] = desc - } - resp, err := self.imsRequest("CreateSAMLProvider", params) - if err != nil { - return nil, errors.Wrapf(err, "CreateSAMLProvider") - } - sp := &SAMLProvider{client: self} - err = resp.Unmarshal(sp, "SAMLProvider") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return sp, nil -} - -func (self *SAliyunClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { - marker := "" - sps := []SAMLProvider{} - for { - part, _marker, err := self.ListSAMLProviders(marker, 100) - if err != nil { - return nil, errors.Wrapf(err, "ListSAMLProviders") - } - sps = append(sps, part...) - if len(_marker) == 0 { - break - } - marker = _marker - } - ret := []cloudprovider.ICloudSAMLProvider{} - for i := range sps { - sps[i].client = self - ret = append(ret, &sps[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/aliyun/securitygroup.go b/pkg/multicloud/aliyun/securitygroup.go deleted file mode 100644 index 0372b155c6..0000000000 --- a/pkg/multicloud/aliyun/securitygroup.go +++ /dev/null @@ -1,551 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// {"CreationTime":"2017-03-19T13:37:48Z","Description":"System created security group.","SecurityGroupId":"sg-j6cannq0xxj2r9z0yxwl","SecurityGroupName":"sg-j6cannq0xxj2r9z0yxwl","Tags":{"Tag":[]},"VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"} -// {"Description":"System created security group.","InnerAccessPolicy":"Accept","Permissions":{"Permission":[{"CreateTime":"2017-03-19T13:37:54Z","Description":"","DestCidrIp":"","DestGroupId":"","DestGroupName":"","DestGroupOwnerAccount":"","Direction":"ingress","IpProtocol":"ALL","NicType":"intranet","Policy":"Accept","PortRange":"-1/-1","Priority":110,"SourceCidrIp":"0.0.0.0/0","SourceGroupId":"","SourceGroupName":"","SourceGroupOwnerAccount":""},{"CreateTime":"2017-03-19T13:37:55Z","Description":"","DestCidrIp":"0.0.0.0/0","DestGroupId":"","DestGroupName":"","DestGroupOwnerAccount":"","Direction":"egress","IpProtocol":"ALL","NicType":"intranet","Policy":"Accept","PortRange":"-1/-1","Priority":110,"SourceCidrIp":"","SourceGroupId":"","SourceGroupName":"","SourceGroupOwnerAccount":""}]},"RegionId":"cn-hongkong","RequestId":"FBFE0950-5F2D-40DE-8C3C-E5A62AE7F7DA","SecurityGroupId":"sg-j6cannq0xxj2r9z0yxwl","SecurityGroupName":"sg-j6cannq0xxj2r9z0yxwl","VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"} - -type SecurityGroupPermissionNicType string - -const ( - IntranetNicType SecurityGroupPermissionNicType = "intranet" - InternetNicType SecurityGroupPermissionNicType = "internet" -) - -type SPermission struct { - CreateTime time.Time - Description string - DestCidrIp string - DestGroupId string - DestGroupName string - DestGroupOwnerAccount string - Direction string - IpProtocol string - NicType SecurityGroupPermissionNicType - Policy string - PortRange string - Priority int - SourceCidrIp string - SourceGroupId string - SourceGroupName string - SourceGroupOwnerAccount string -} - -type SPermissions struct { - Permission []SPermission -} - -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.AliyunTags - - vpc *SVpc - CreationTime time.Time - Description string - SecurityGroupId string - SecurityGroupName string - VpcId string - InnerAccessPolicy string - Permissions SPermissions - RegionId string -} - -func (self *SSecurityGroup) GetVpcId() string { - return self.VpcId -} - -func (self *SSecurityGroup) GetId() string { - return self.SecurityGroupId -} - -func (self *SSecurityGroup) GetGlobalId() string { - return self.SecurityGroupId -} - -func (self *SSecurityGroup) GetDescription() string { - return self.Description -} - -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - rules := make([]cloudprovider.SecurityRule, 0) - secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) - if err != nil { - return nil, err - } - for _, permission := range secgrp.Permissions.Permission { - rule, err := permission.toRule() - if err != nil { - log.Errorf("convert rule %s for group %s(%s) error: %v", permission.Description, self.SecurityGroupName, self.SecurityGroupId, err) - continue - } - rules = append(rules, rule) - } - return rules, nil -} - -func (self *SSecurityGroup) GetName() string { - if len(self.SecurityGroupName) > 0 { - return self.SecurityGroupName - } - return self.SecurityGroupId -} - -func (self *SSecurityGroup) GetStatus() string { - return "" -} - -func (self *SSecurityGroup) IsEmulated() bool { - return false -} - -func (self *SSecurityGroup) Refresh() error { - group, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) - if err != nil { - return err - } - return jsonutils.Update(self, group) -} - -func (self *SSecurityGroup) GetReferences() ([]cloudprovider.SecurityGroupReference, error) { - references, err := self.vpc.region.DescribeSecurityGroupReferences(self.SecurityGroupId) - if err != nil { - return nil, errors.Wrapf(err, "DescribeSecurityGroupReferences") - } - ret := []cloudprovider.SecurityGroupReference{} - for _, reference := range references { - if reference.SecurityGroupId == self.SecurityGroupId { - for _, sec := range reference.ReferencingSecurityGroups.ReferencingSecurityGroup { - ret = append(ret, cloudprovider.SecurityGroupReference{ - Id: sec.SecurityGroupId, - }) - } - } - } - return ret, nil -} - -type ReferencingSecurityGroup struct { - AliUid string - SecurityGroupId string -} - -type ReferencingSecurityGroups struct { - ReferencingSecurityGroup []ReferencingSecurityGroup -} - -type SecurityGroupReferences struct { - SecurityGroupId string - ReferencingSecurityGroups ReferencingSecurityGroups -} - -func (self *SRegion) DescribeSecurityGroupReferences(id string) ([]SecurityGroupReferences, error) { - params := map[string]string{ - "RegionId": self.RegionId, - "SecurityGroupId.1": id, - } - resp, err := self.ecsRequest("DescribeSecurityGroupReferences", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeSecurityGroupReferences") - } - ret := []SecurityGroupReferences{} - err = resp.Unmarshal(&ret, "SecurityGroupReferences", "SecurityGroupReference") - return ret, errors.Wrapf(err, "resp.Unmarshal") -} - -func (self *SRegion) GetSecurityGroups(vpcId, name string, securityGroupIds []string, offset int, limit int) ([]SSecurityGroup, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - if len(vpcId) > 0 { - params["VpcId"] = vpcId - } - if len(name) > 0 { - params["SecurityGroupName"] = name - } - - if securityGroupIds != nil && len(securityGroupIds) > 0 { - params["SecurityGroupIds"] = jsonutils.Marshal(securityGroupIds).String() - } - - body, err := self.ecsRequest("DescribeSecurityGroups", params) - if err != nil { - log.Errorf("GetSecurityGroups fail %s", err) - return nil, 0, err - } - - secgrps := make([]SSecurityGroup, 0) - err = body.Unmarshal(&secgrps, "SecurityGroups", "SecurityGroup") - if err != nil { - log.Errorf("Unmarshal security groups fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return secgrps, int(total), nil -} - -func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SecurityGroupId"] = secGroupId - - body, err := self.ecsRequest("DescribeSecurityGroupAttribute", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeSecurityGroupAttribute") - } - - secgrp := SSecurityGroup{} - err = body.Unmarshal(&secgrp) - if err != nil { - return nil, errors.Wrap(err, "body.Unmarshal") - } - return &secgrp, nil -} - -func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (string, error) { - params := make(map[string]string) - if len(vpcId) > 0 { - params["VpcId"] = vpcId - } - - if name == "Default" { - name = "Default-copy" - } - - if len(name) > 0 { - params["SecurityGroupName"] = name - } - if len(desc) > 0 { - params["Description"] = desc - } - params["ClientToken"] = utils.GenRequestId(20) - - body, err := self.ecsRequest("CreateSecurityGroup", params) - if err != nil { - return "", errors.Wrap(err, "CreateSecurityGroup") - } - return body.GetString("SecurityGroupId") -} - -func (self *SRegion) modifySecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SecurityGroupId"] = secGrpId - params["NicType"] = string(IntranetNicType) - params["Description"] = rule.Description - params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) - protocol := rule.Protocol - if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { - protocol = "all" - } - params["IpProtocol"] = protocol - if rule.PortStart < 1 && rule.PortEnd < 1 { - if protocol == "udp" || protocol == "tcp" { - params["PortRange"] = "1/65535" - } else { - params["PortRange"] = "-1/-1" - } - } - if rule.Action == secrules.SecurityRuleAllow { - params["Policy"] = "accept" - } else { - params["Policy"] = "drop" - } - params["Priority"] = fmt.Sprintf("%d", rule.Priority) - if rule.Direction == secrules.SecurityRuleIngress { - if rule.IPNet != nil { - params["SourceCidrIp"] = rule.IPNet.String() - } else { - params["SourceCidrIp"] = "0.0.0.0/0" - } - _, err := self.ecsRequest("ModifySecurityGroupRule", params) - return err - } else { // rule.Direction == secrules.SecurityRuleEgress { - //阿里云不支持出方向API接口调用 - return nil - // if rule.IPNet != nil { - // params["DestCidrIp"] = rule.IPNet.String() - // } else { - // params["DestCidrIp"] = "0.0.0.0/0" - // } - // _, err := self.ecsRequest("ModifySecurityGroupRule", params) - // return err - } -} - -func (self *SRegion) modifySecurityGroup(secGrpId string, name string, desc string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SecurityGroupId"] = secGrpId - params["SecurityGroupName"] = name - if len(desc) > 0 { - params["Description"] = desc - } - _, err := self.ecsRequest("ModifySecurityGroupAttribute", params) - return err -} - -func (self *SRegion) AddSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error { - if len(rule.Ports) != 0 { - for _, port := range rule.Ports { - rule.PortStart, rule.PortEnd = port, port - err := self.addSecurityGroupRule(secGrpId, rule) - if err != nil { - return errors.Wrapf(err, "addSecurityGroupRule %s", rule.String()) - } - } - return nil - } - return self.addSecurityGroupRule(secGrpId, rule) -} - -func (self *SRegion) addSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SecurityGroupId"] = secGrpId - params["NicType"] = string(IntranetNicType) - params["Description"] = rule.Description - params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) - protocol := rule.Protocol - if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { - protocol = "all" - } - params["IpProtocol"] = protocol - if rule.PortStart < 1 && rule.PortEnd < 1 { - if protocol == "udp" || protocol == "tcp" { - params["PortRange"] = "1/65535" - } else { - params["PortRange"] = "-1/-1" - } - } - if rule.Action == secrules.SecurityRuleAllow { - params["Policy"] = "accept" - } else { - params["Policy"] = "drop" - } - - // 忽略地址为0.0.0.0/32这样的阿里云规则 - if rule.IPNet.IP.String() == "0.0.0.0" && rule.IPNet.String() != "0.0.0.0/0" && len(rule.PeerSecgroupId) == 0 { - return nil - } - - params["Priority"] = fmt.Sprintf("%d", rule.Priority) - if rule.Direction == secrules.SecurityRuleIngress { - if len(rule.PeerSecgroupId) > 0 { - params["SourceGroupId"] = rule.PeerSecgroupId - } else if rule.IPNet != nil { - params["SourceCidrIp"] = rule.IPNet.String() - } else { - params["SourceCidrIp"] = "0.0.0.0/0" - } - _, err := self.ecsRequest("AuthorizeSecurityGroup", params) - return err - } else { // rule.Direction == secrules.SecurityRuleEgress { - if len(rule.PeerSecgroupId) > 0 { - params["DestGroupId"] = rule.PeerSecgroupId - } else if rule.IPNet != nil { - params["DestCidrIp"] = rule.IPNet.String() - } else { - params["DestCidrIp"] = "0.0.0.0/0" - } - _, err := self.ecsRequest("AuthorizeSecurityGroupEgress", params) - return err - } -} - -func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SecurityGroupId"] = secGrpId - params["NicType"] = string(IntranetNicType) - params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) - protocol := rule.Protocol - if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { - protocol = "all" - } - params["IpProtocol"] = protocol - if rule.PortStart < 1 && rule.PortEnd < 1 { - if protocol == "udp" || protocol == "tcp" { - params["PortRange"] = "1/65535" - } else { - params["PortRange"] = "-1/-1" - } - } - if rule.Action == secrules.SecurityRuleAllow { - params["Policy"] = "accept" - } else { - params["Policy"] = "drop" - } - params["Priority"] = fmt.Sprintf("%d", rule.Priority) - if rule.Direction == secrules.SecurityRuleIngress { - if len(rule.PeerSecgroupId) > 0 { - params["SourceGroupId"] = rule.PeerSecgroupId - } else if rule.IPNet != nil { - params["SourceCidrIp"] = rule.IPNet.String() - } else { - params["SourceCidrIp"] = "0.0.0.0/0" - } - _, err := self.ecsRequest("RevokeSecurityGroup", params) - return err - } else { // rule.Direction == secrules.SecurityRuleEgress { - if len(rule.PeerSecgroupId) > 0 { - params["DestGroupId"] = rule.PeerSecgroupId - } else if rule.IPNet != nil { - params["DestCidrIp"] = rule.IPNet.String() - } else { - params["DestCidrIp"] = "0.0.0.0/0" - } - _, err := self.ecsRequest("RevokeSecurityGroupEgress", params) - return err - } -} - -func (self *SPermission) toRule() (cloudprovider.SecurityRule, error) { - rule := cloudprovider.SecurityRule{ - PeerSecgroupId: self.SourceGroupId, - SecurityRule: secrules.SecurityRule{ - Action: secrules.SecurityRuleDeny, - Direction: secrules.DIR_IN, - Priority: self.Priority, - Description: self.Description, - PortStart: -1, - PortEnd: -1, - }, - } - if strings.ToLower(self.Policy) == "accept" { - rule.Action = secrules.SecurityRuleAllow - } - - cidr := self.SourceCidrIp - if self.Direction == "egress" { - rule.Direction = secrules.DIR_OUT - cidr = self.DestCidrIp - } - if len(self.SourceGroupId) > 0 || len(self.DestGroupId) > 0 { - cidr = "0.0.0.0/0" - rule.PeerSecgroupId = self.SourceGroupId + self.DestGroupId - } - - rule.ParseCIDR(cidr) - - switch strings.ToLower(self.IpProtocol) { - case "tcp", "udp", "icmp": - rule.Protocol = strings.ToLower(self.IpProtocol) - case "all": - rule.Protocol = secrules.PROTO_ANY - default: - return rule, fmt.Errorf("unsupported protocal %s", self.IpProtocol) - } - - port, ports := "", strings.Split(self.PortRange, "/") - if ports[0] == ports[1] { - if ports[0] != "-1" { - port = ports[0] - } - } else if ports[0] != "1" && ports[1] != "65535" { - port = fmt.Sprintf("%s-%s", ports[0], ports[1]) - } - err := rule.ParsePorts(port) - if err != nil { - return rule, errors.Wrapf(err, "ParsePorts(%s)", port) - } - return rule, nil -} - -func (self *SRegion) AssignSecurityGroup(secgroupId, instanceId string) error { - return self.SetSecurityGroups([]string{secgroupId}, instanceId) -} - -func (self *SRegion) SetSecurityGroups(secgroupIds []string, instanceId string) error { - params := map[string]string{"InstanceId": instanceId} - for _, secgroupId := range secgroupIds { - params["SecurityGroupId"] = secgroupId - if _, err := self.ecsRequest("JoinSecurityGroup", params); err != nil { - return err - } - } - instance, err := self.GetInstance(instanceId) - if err != nil { - return err - } - for _, _secgroupId := range instance.SecurityGroupIds.SecurityGroupId { - if !utils.IsInStringArray(_secgroupId, secgroupIds) { - if err := self.leaveSecurityGroup(_secgroupId, instanceId); err != nil { - return err - } - } - } - return nil -} - -func (self *SRegion) leaveSecurityGroup(secgroupId, instanceId string) error { - params := map[string]string{"InstanceId": instanceId, "SecurityGroupId": secgroupId} - _, err := self.ecsRequest("LeaveSecurityGroup", params) - return err -} - -func (self *SRegion) DeleteSecurityGroup(secGrpId string) error { - params := make(map[string]string) - params["SecurityGroupId"] = secGrpId - - _, err := self.ecsRequest("DeleteSecurityGroup", params) - if err != nil { - log.Errorf("Delete security group fail %s", err) - return err - } - return nil -} - -func (self *SSecurityGroup) Delete() error { - return self.vpc.region.DeleteSecurityGroup(self.SecurityGroupId) -} - -func (self *SSecurityGroup) GetProjectId() string { - return "" -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - for _, rule := range append(inDels, outDels...) { - err := self.vpc.region.DelSecurityGroupRule(self.SecurityGroupId, rule) - if err != nil { - return errors.Wrapf(err, "DelSecurityGroupRule(Name:%s priority: %d %s)", rule.Name, rule.Priority, rule.String()) - } - } - for _, rule := range append(inAdds, outAdds...) { - err := self.vpc.region.AddSecurityGroupRules(self.SecurityGroupId, rule) - if err != nil { - return errors.Wrapf(err, "AddSecurityGroupRules(priority: %d %s)", rule.Priority, rule.String()) - } - } - return nil -} diff --git a/pkg/multicloud/aliyun/shell/access_groups.go b/pkg/multicloud/aliyun/shell/access_groups.go deleted file mode 100644 index b937ddacd5..0000000000 --- a/pkg/multicloud/aliyun/shell/access_groups.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NasAccessGroupListOptions struct { - FileSystemType string `choices:"standard|extreme" default:"standard"` - } - shellutils.R(&NasAccessGroupListOptions{}, "access-group-list", "List Nas AccessGroups", func(cli *aliyun.SRegion, args *NasAccessGroupListOptions) error { - ags, err := cli.GetAccessGroups(args.FileSystemType) - if err != nil { - return err - } - printList(ags, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&cloudprovider.SAccessGroup{}, "access-group-create", "Create Nas AccessGroup", func(cli *aliyun.SRegion, args *cloudprovider.SAccessGroup) error { - return cli.CreateAccessGroup(args) - }) - - type AccessGroupDeleteOptions struct { - FileSystemType string - NAME string - } - - shellutils.R(&AccessGroupDeleteOptions{}, "access-group-delete", "Delete AccessGroup", func(cli *aliyun.SRegion, args *AccessGroupDeleteOptions) error { - return cli.DeleteAccessGroup(args.FileSystemType, args.NAME) - }) - - type NasAccessGroupRuleListOptions struct { - GROUP string - PageSize int `help:"page size"` - PageNum int `help:"page num"` - } - - shellutils.R(&NasAccessGroupRuleListOptions{}, "access-group-rule-list", "List Nas AccessGroup Rules", func(cli *aliyun.SRegion, args *NasAccessGroupRuleListOptions) error { - rules, _, err := cli.GetAccessGroupRules(args.GROUP, args.PageSize, args.PageNum) - if err != nil { - return err - } - printList(rules, 0, 0, 0, []string{}) - return nil - }) - - type AccessRuleDeleteOptions struct { - FileSystemType string - GROUP string - RULE_ID string - } - - shellutils.R(&AccessRuleDeleteOptions{}, "access-group-rule-delete", "Delete AccessGroup Rule", func(cli *aliyun.SRegion, args *AccessRuleDeleteOptions) error { - return cli.DeleteAccessGroupRule(args.FileSystemType, args.GROUP, args.RULE_ID) - }) - - type AccessRuleCreateOptions struct { - SOURCE string - FileSystemType string - GroupName string - RwType cloudprovider.TRWAccessType - UserType cloudprovider.TUserAccessType - Priority int - } - - shellutils.R(&AccessRuleCreateOptions{}, "access-group-rule-create", "Delete AccessGroup Rule", func(cli *aliyun.SRegion, args *AccessRuleCreateOptions) error { - return cli.CreateAccessGroupRule(args.SOURCE, args.FileSystemType, args.GroupName, args.RwType, args.UserType, args.Priority) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/bucket.go b/pkg/multicloud/aliyun/shell/bucket.go deleted file mode 100644 index f44f1c4081..0000000000 --- a/pkg/multicloud/aliyun/shell/bucket.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import "yunion.io/x/onecloud/pkg/multicloud/objectstore" - -func init() { - objectstore.S3Shell() -} diff --git a/pkg/multicloud/aliyun/shell/business.go b/pkg/multicloud/aliyun/shell/business.go deleted file mode 100644 index c89edfbc40..0000000000 --- a/pkg/multicloud/aliyun/shell/business.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type AccountBalanceOptions struct { - } - shellutils.R(&AccountBalanceOptions{}, "balance", "Get account balance", func(cli *aliyun.SRegion, args *AccountBalanceOptions) error { - result1, err := cli.GetClient().QueryAccountBalance() - if err != nil { - return err - } - printObject(result1) - - result2, err := cli.GetClient().QueryCashCoupons() - if err != nil { - return err - } - if len(result2) > 0 { - printList(result2, len(result2), 0, 0, nil) - } - - result3, err := cli.GetClient().QueryPrepaidCards() - if err != nil { - return err - } - if len(result3) > 0 { - printList(result3, len(result3), 0, 0, nil) - } - return nil - }) - - type AliyunSubscribeBillOptions struct { - BUCKET string `help:"bucket name to store billing records"` - } - shellutils.R(&AliyunSubscribeBillOptions{}, "subscribe-bill", "Subscribe bill to OSS storage", func(cli *aliyun.SRegion, args *AliyunSubscribeBillOptions) error { - err := cli.GetClient().SubscribeBillToOSS(args.BUCKET) - if err != nil { - return err - } - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/cdn.go b/pkg/multicloud/aliyun/shell/cdn.go deleted file mode 100644 index 5d0be67554..0000000000 --- a/pkg/multicloud/aliyun/shell/cdn.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 Yunion -// -// 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. - -// Copyright 2019 Yunion -// -// 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 -// PageSizeations under the License. - -package shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CdnDomainListOptions struct { - Domain string - PageSize int - PageNumber int - } - shellutils.R(&CdnDomainListOptions{}, "cdn-domain-list", "list cdn domain", func(cli *aliyun.SRegion, args *CdnDomainListOptions) error { - domains, _, err := cli.GetClient().DescribeUserDomains(args.Domain, args.PageSize, args.PageNumber) - if err != nil { - return err - } - printList(domains, 0, 0, 0, []string{}) - return nil - }) - - type CdnDomainShowOptions struct { - DOMAIN string - } - shellutils.R(&CdnDomainShowOptions{}, "cdn-domain-show", "Show cdn domain", func(cli *aliyun.SRegion, args *CdnDomainShowOptions) error { - domain, err := cli.GetClient().GetCdnDomain(args.DOMAIN) - if err != nil { - return err - } - printObject(domain) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/cen_route.go b/pkg/multicloud/aliyun/shell/cen_route.go deleted file mode 100644 index 09ef6fbc6f..0000000000 --- a/pkg/multicloud/aliyun/shell/cen_route.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2019 Yunion -// -// 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. - -// Copyright 2019 Yunion -// -// 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 -// PageSizeations under the License. - -package shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CenRouteListOptions struct { - CENID string - CHILDINSTANCEID string - CHILDINSTANCEREGION string - CHILDINSTANCETYPE string - } - shellutils.R(&CenRouteListOptions{}, "cen-route-list", "List cloud enterprise network route", func(cli *aliyun.SRegion, args *CenRouteListOptions) error { - routes, e := cli.GetClient().GetAllCenChildInstanceRouteEntries(args.CENID, args.CHILDINSTANCEID, args.CHILDINSTANCEREGION, args.CHILDINSTANCETYPE) - if e != nil { - return e - } - printList(routes, len(routes), 1, len(routes), []string{}) - return nil - }) - - type PublishCenRouteOptions struct { - CENID string - CHILDINSTANCEID string - CHILDINSTANCEREGION string - CHILDINSTANCETYPE string - ROUTETABLEID string - CIDR string - } - shellutils.R(&PublishCenRouteOptions{}, "cen-route-publish", "publish cloud enterprise network route", func(cli *aliyun.SRegion, args *PublishCenRouteOptions) error { - e := cli.GetClient().PublishRouteEntries(args.CENID, args.CHILDINSTANCEID, args.ROUTETABLEID, args.CHILDINSTANCEREGION, args.CHILDINSTANCETYPE, args.CIDR) - if e != nil { - return e - } - return nil - }) - - type WithDrawCenRouteOptions struct { - CENID string - CHILDINSTANCEID string - CHILDINSTANCEREGION string - CHILDINSTANCETYPE string - ROUTETABLEID string - CIDR string - } - shellutils.R(&PublishCenRouteOptions{}, "cen-route-withdraw", "withdraw cloud enterprise network route", func(cli *aliyun.SRegion, args *PublishCenRouteOptions) error { - e := cli.GetClient().WithdrawPublishedRouteEntries(args.CENID, args.CHILDINSTANCEID, args.ROUTETABLEID, args.CHILDINSTANCEREGION, args.CHILDINSTANCETYPE, args.CIDR) - if e != nil { - return e - } - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/cloud_enterprise_network.go b/pkg/multicloud/aliyun/shell/cloud_enterprise_network.go deleted file mode 100644 index 4b39eb55cf..0000000000 --- a/pkg/multicloud/aliyun/shell/cloud_enterprise_network.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2019 Yunion -// -// 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. - -// Copyright 2019 Yunion -// -// 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 -// PageSizeations under the License. - -package shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CenListOptions struct { - PageSize int `help:"page size"` - PageNumber int `help:"page PageNumber"` - } - shellutils.R(&CenListOptions{}, "cen-list", "List cloud enterprise network", func(cli *aliyun.SRegion, args *CenListOptions) error { - scens, e := cli.GetClient().DescribeCens(args.PageNumber, args.PageSize) - if e != nil { - return e - } - printList(scens.Cens.Cen, scens.TotalCount, args.PageNumber, args.PageSize, []string{}) - return nil - }) - - type CenChildListOptions struct { - ID string `help:"cen id"` - PageSize int `help:"page size"` - PageNumber int `help:"page PageNumber"` - } - shellutils.R(&CenChildListOptions{}, "cen-child-list", "List cloud enterprise network childs", func(cli *aliyun.SRegion, args *CenChildListOptions) error { - schilds, e := cli.GetClient().DescribeCenAttachedChildInstances(args.ID, args.PageNumber, args.PageSize) - if e != nil { - return e - } - printList(schilds.ChildInstances.ChildInstance, schilds.TotalCount, args.PageNumber, args.PageSize, []string{}) - return nil - }) - - type CenCreateOptions struct { - Name string - Description string - } - shellutils.R(&CenCreateOptions{}, "cen-create", "Create cloud enterprise network", func(cli *aliyun.SRegion, args *CenCreateOptions) error { - opts := cloudprovider.SInterVpcNetworkCreateOptions{} - opts.Name = args.Name - opts.Desc = args.Description - scen, e := cli.GetClient().CreateCen(&opts) - if e != nil { - return e - } - print(scen) - return nil - }) - - type CenDeleteOptions struct { - ID string - } - shellutils.R(&CenDeleteOptions{}, "cen-delete", "delete cloud enterprise network", func(cli *aliyun.SRegion, args *CenDeleteOptions) error { - e := cli.GetClient().DeleteCen(args.ID) - if e != nil { - return e - } - return nil - }) - - type CenAddVpcOptions struct { - ID string - VpcId string - VpcRegionId string - } - shellutils.R(&CenAddVpcOptions{}, "cen-add-vpc", "add vpc to cloud enterprise network", func(cli *aliyun.SRegion, args *CenAddVpcOptions) error { - instance := aliyun.SCenAttachInstanceInput{ - InstanceType: "VPC", - InstanceId: args.VpcId, - InstanceRegion: args.VpcRegionId, - } - - e := cli.GetClient().AttachCenChildInstance(args.ID, instance) - if e != nil { - return e - } - return nil - }) - - type CenRemoveVpcOptions struct { - ID string - VpcId string - VpcRegionId string - } - shellutils.R(&CenRemoveVpcOptions{}, "cen-remove-vpc", "remove vpc to cloud enterprise network", func(cli *aliyun.SRegion, args *CenRemoveVpcOptions) error { - instance := aliyun.SCenAttachInstanceInput{ - InstanceType: "VPC", - InstanceId: args.VpcId, - InstanceRegion: args.VpcRegionId, - } - - e := cli.GetClient().DetachCenChildInstance(args.ID, instance) - if e != nil { - return e - } - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/dbinstance.go b/pkg/multicloud/aliyun/shell/dbinstance.go deleted file mode 100644 index 688380143d..0000000000 --- a/pkg/multicloud/aliyun/shell/dbinstance.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "strings" - - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceListOptions struct { - Id []string `help:"IDs of instances to show"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&DBInstanceListOptions{}, "dbinstance-list", "List dbintances", func(cli *aliyun.SRegion, args *DBInstanceListOptions) error { - instances, total, e := cli.GetDBInstances(args.Id, args.Offset, args.Limit) - if e != nil { - return e - } - printList(instances, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type DBInstanceIdOptions struct { - ID string `help:"ID of instances to show"` - } - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-show", "Show dbintance", func(cli *aliyun.SRegion, args *DBInstanceIdOptions) error { - instance, err := cli.GetDBInstanceDetail(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-secgroup-list", "List dbintance secgroup", func(cli *aliyun.SRegion, args *DBInstanceIdOptions) error { - secgroupIds, err := cli.GetRdsSecgroupIds(args.ID) - if err != nil { - return err - } - fmt.Println(secgroupIds) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-open-public-connection", "Open dbintance public connection", func(cli *aliyun.SRegion, args *DBInstanceIdOptions) error { - return cli.OpenPublicConnection(args.ID) - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-close-public-connection", "Close dbintance public connection", func(cli *aliyun.SRegion, args *DBInstanceIdOptions) error { - return cli.ClosePublicConnection(args.ID) - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-delete", "Delete dbintance", func(cli *aliyun.SRegion, args *DBInstanceIdOptions) error { - return cli.DeleteDBInstance(args.ID) - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-restart", "Restart dbintance", func(cli *aliyun.SRegion, args *DBInstanceIdOptions) error { - return cli.RebootDBInstance(args.ID) - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-network-list", "Show dbintance network info", func(cli *aliyun.SRegion, args *DBInstanceIdOptions) error { - networks, err := cli.GetDBInstanceNetInfo(args.ID) - if err != nil { - return err - } - printList(networks, 0, 0, 0, []string{}) - return nil - }) - - type DBInstanceRecoveryOptions struct { - ID string - TARGET string - BACKUP string - Databases []string - } - - shellutils.R(&DBInstanceRecoveryOptions{}, "dbinstance-recovery", "Recovery dbintance from backup", func(cli *aliyun.SRegion, args *DBInstanceRecoveryOptions) error { - databases := map[string]string{} - for _, database := range args.Databases { - if len(database) > 0 { - dbInfo := strings.Split(database, ":") - if len(dbInfo) == 1 { - databases[dbInfo[0]] = dbInfo[0] - - } else if len(dbInfo) == 2 { - databases[dbInfo[0]] = dbInfo[1] - } else { - return fmt.Errorf("Invalid dbinfo: %s", database) - } - } - } - return cli.RecoveryDBInstanceFromBackup(args.ID, args.TARGET, args.BACKUP, databases) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/dbinstance_account.go b/pkg/multicloud/aliyun/shell/dbinstance_account.go deleted file mode 100644 index 016214e5fe..0000000000 --- a/pkg/multicloud/aliyun/shell/dbinstance_account.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - - type DBInstanceIdExtraOptions struct { - ID string `help:"ID of instances to show"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - - shellutils.R(&DBInstanceIdExtraOptions{}, "dbinstance-account-list", "List dbintance accounts", func(cli *aliyun.SRegion, args *DBInstanceIdExtraOptions) error { - accounts, _, err := cli.GetDBInstanceAccounts(args.ID, args.Offset, args.Limit) - if err != nil { - return err - } - printList(accounts, 0, 0, 0, []string{}) - return nil - }) - - type DBInstanceAccountCreateOptions struct { - INSTANCE string `help:"ID of instances"` - NAME string `help:"account name"` - PASSWORD string `help:"account password"` - Desc string - } - - shellutils.R(&DBInstanceAccountCreateOptions{}, "dbinstance-account-create", "Create dbintance account", func(cli *aliyun.SRegion, args *DBInstanceAccountCreateOptions) error { - return cli.CreateDBInstanceAccount(args.INSTANCE, args.NAME, args.PASSWORD, args.Desc) - }) - - type DBInstanceAccountDeleteOptions struct { - INSTANCE string - NAME string - } - - shellutils.R(&DBInstanceAccountDeleteOptions{}, "dbinstance-account-delete", "Delete dbintance account", func(cli *aliyun.SRegion, args *DBInstanceAccountDeleteOptions) error { - return cli.DeleteDBInstanceAccount(args.INSTANCE, args.NAME) - }) - - type DBInstanceAccountResetOptions struct { - INSTANCE string `help:"ID of instances"` - NAME string `help:"account name"` - PASSWORD string `help:"account password"` - AccountType string `help:"account type" choices:"Normal|Super" default:"Normal"` - } - - shellutils.R(&DBInstanceAccountResetOptions{}, "dbinstance-account-reset-password", "Reset dbintance account password", func(cli *aliyun.SRegion, args *DBInstanceAccountResetOptions) error { - return cli.ResetDBInstanceAccountPassword(args.INSTANCE, args.NAME, args.PASSWORD, args.AccountType) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/dbinstance_backup.go b/pkg/multicloud/aliyun/shell/dbinstance_backup.go deleted file mode 100644 index f81521d106..0000000000 --- a/pkg/multicloud/aliyun/shell/dbinstance_backup.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceBackupJobListOptions struct { - INSTANCE string - JobId string - } - shellutils.R(&DBInstanceBackupJobListOptions{}, "dbinstance-backup-job-list", "Get dbinstance backup jobs", func(cli *aliyun.SRegion, args *DBInstanceBackupJobListOptions) error { - jobs, err := cli.GetDBInstanceBackupJobs(args.INSTANCE, args.JobId) - if err != nil { - return err - } - printObject(jobs) - return nil - }) - - type DBInstanceBackupOptions struct { - INSTANCE string - BACKUP string - } - - shellutils.R(&DBInstanceBackupOptions{}, "dbinstance-backup-delete", "Delete dbinstance backup", func(cli *aliyun.SRegion, args *DBInstanceBackupOptions) error { - return cli.DeleteDBInstanceBackup(args.INSTANCE, args.BACKUP) - }) - - shellutils.R(&DBInstanceBackupOptions{}, "dbinstance-backup-job-list", "Get dbinstance backup jobs", func(cli *aliyun.SRegion, args *DBInstanceBackupOptions) error { - return cli.DeleteDBInstanceBackup(args.INSTANCE, args.BACKUP) - }) - - type DBInstanceIdExtraOptions struct { - ID string `help:"ID of instances to show"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - - shellutils.R(&DBInstanceIdExtraOptions{}, "dbinstance-backup-list", "List dbintance backups", func(cli *aliyun.SRegion, args *DBInstanceIdExtraOptions) error { - backups, _, err := cli.GetDBInstanceBackups(args.ID, "", args.Offset, args.Limit) - if err != nil { - return err - } - printList(backups, 0, 0, 0, []string{}) - return nil - }) - - type DBInstanceBackupCreateOptions struct { - INSTANCE_ID string - Database []string - } - - shellutils.R(&DBInstanceBackupCreateOptions{}, "dbinstance-backup-create", "Create dbintance backup", func(cli *aliyun.SRegion, args *DBInstanceBackupCreateOptions) error { - backupId, err := cli.CreateDBInstanceBackup(args.INSTANCE_ID, args.Database) - if err != nil { - return err - } - fmt.Println("backup id: ", backupId) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/dbinstance_database.go b/pkg/multicloud/aliyun/shell/dbinstance_database.go deleted file mode 100644 index ce1a425bd5..0000000000 --- a/pkg/multicloud/aliyun/shell/dbinstance_database.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - - type DBInstanceIdExtraOptions struct { - ID string `help:"ID of instances to show"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - - shellutils.R(&DBInstanceIdExtraOptions{}, "dbinstance-database-list", "List dbintance databases", func(cli *aliyun.SRegion, args *DBInstanceIdExtraOptions) error { - databases, _, err := cli.GetDBInstanceDatabases(args.ID, "", args.Offset, args.Limit) - if err != nil { - return err - } - printList(databases, 0, 0, 0, []string{}) - return nil - }) - - type DBInstanceDatabaseCreateOptions struct { - INSTANCE string `help:"ID of instances"` - NAME string `help:"database name"` - CHARACTERSET string `help:"character set for database"` - Desc string - } - - shellutils.R(&DBInstanceDatabaseCreateOptions{}, "dbinstance-database-create", "Create dbintance database", func(cli *aliyun.SRegion, args *DBInstanceDatabaseCreateOptions) error { - return cli.CreateDBInstanceDatabae(args.INSTANCE, args.CHARACTERSET, args.NAME, args.Desc) - }) - - type DBInstanceDatabaseDeleteOptions struct { - INSTANCE string - NAME string - } - - shellutils.R(&DBInstanceDatabaseDeleteOptions{}, "dbinstance-database-delete", "Delete dbintance database", func(cli *aliyun.SRegion, args *DBInstanceDatabaseDeleteOptions) error { - return cli.DeleteDBInstanceDatabase(args.INSTANCE, args.NAME) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/disk.go b/pkg/multicloud/aliyun/shell/disk.go deleted file mode 100644 index c02b71499b..0000000000 --- a/pkg/multicloud/aliyun/shell/disk.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "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 *aliyun.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 { - ID string `help:"Instance ID"` - } - shellutils.R(&DiskDeleteOptions{}, "disk-delete", "List disks", func(cli *aliyun.SRegion, args *DiskDeleteOptions) error { - e := cli.DeleteDisk(args.ID) - if e != nil { - return e - } - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/dns_domain.go b/pkg/multicloud/aliyun/shell/dns_domain.go deleted file mode 100644 index c2a8d8c0ea..0000000000 --- a/pkg/multicloud/aliyun/shell/dns_domain.go +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2019 Yunion -// -// 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. - -// Copyright 2019 Yunion -// -// 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 -// PageNumberations under the License. - -package shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DnsProductListOptions struct { - PageNumber int `help:"page size" default:"1"` - PageSize int `help:"page PageSize" default:"20"` - } - shellutils.R(&DnsProductListOptions{}, "dnsproduct-list", "List dnsproduct", func(cli *aliyun.SRegion, args *DnsProductListOptions) error { - //products, e := cli.GetClient().DescribeDnsProductInstances(args.PageNumber, args.PageSize) - products, e := cli.GetClient().GetAllDnsProductInstances() - if e != nil { - return e - } - //printList(products.DNSProducts.DNSProduct, products.TotalCount, args.PageSize, args.PageNumber, []string{}) - printList(products, len(products), args.PageNumber, args.PageSize, []string{}) - return nil - }) - - type DomianListOptions struct { - PageNumber int `help:"page size" default:"1"` - PageSize int `help:"page PageSize" default:"20"` - } - shellutils.R(&DomianListOptions{}, "domain-list", "List Domain", func(cli *aliyun.SRegion, args *DomianListOptions) error { - sdomains, e := cli.GetClient().DescribeDomains(args.PageNumber, args.PageSize) - if e != nil { - return e - } - printList(sdomains.Domains.Domain, sdomains.TotalCount, args.PageNumber, args.PageSize, []string{}) - return nil - }) - - type SDomainCreateOptions struct { - DOMAINNAME string `help:"Domain name"` - } - shellutils.R(&SDomainCreateOptions{}, "domain-create", "Create domain", func(cli *aliyun.SRegion, args *SDomainCreateOptions) error { - hostzones, err := cli.GetClient().AddDomain(args.DOMAINNAME) - if err != nil { - return err - } - printObject(hostzones) - return nil - }) - - type SDomainDeleteOptions struct { - DOMAINNAME string - } - shellutils.R(&SDomainDeleteOptions{}, "domain-delete", "delete domain", func(cli *aliyun.SRegion, args *SDomainDeleteOptions) error { - err := cli.GetClient().DeleteDomain(args.DOMAINNAME) - if err != nil { - return err - } - return nil - }) - - type SDomainShowOptions struct { - DOMAINNAME string - } - shellutils.R(&SDomainShowOptions{}, "domain-show", "Show domain", func(cli *aliyun.SRegion, args *SDomainShowOptions) error { - szone, e := cli.GetClient().DescribeDomainInfo(args.DOMAINNAME) - if e != nil { - return e - } - printObject(szone) - return nil - }) - - type SDomainRecordListOptions struct { - DOMAINNAME string - PageNumber int `help:"page size" default:"1"` - PageSize int `help:"page PageSize" default:"20"` - } - shellutils.R(&SDomainRecordListOptions{}, "domainrecord-list", "List domainrecord", func(cli *aliyun.SRegion, args *SDomainRecordListOptions) error { - srecords, e := cli.GetClient().DescribeDomainRecords(args.DOMAINNAME, args.PageNumber, args.PageSize) - if e != nil { - return e - } - printList(srecords.DomainRecords.Record, srecords.TotalCount, args.PageNumber, args.PageSize, []string{}) - return nil - }) - - type DomainRecordCreateOptions struct { - DOMAINNAME string - NAME string - VALUE string `help:"dns record value"` - TTL int64 `help:"ttl"` - TYPE string `help:"dns type"` - PolicyType string `help:"PolicyType"` - PolicyValue string - } - shellutils.R(&DomainRecordCreateOptions{}, "domainrecord-create", "create domainrecord", func(cli *aliyun.SRegion, args *DomainRecordCreateOptions) error { - opts := cloudprovider.DnsRecordSet{} - opts.DnsName = args.NAME - opts.DnsType = cloudprovider.TDnsType(args.TYPE) - opts.DnsValue = args.VALUE - opts.Ttl = args.TTL - opts.PolicyType = cloudprovider.TDnsPolicyType(args.PolicyType) - - _, err := cli.GetClient().AddDomainRecord(args.DOMAINNAME, opts) - if err != nil { - return err - } - return nil - }) - - type DomainRecordupdateOptions struct { - DOMAINRECORDID string `help:"DOMAINRECORDID"` - NAME string `help:"Domain name"` - VALUE string `help:"dns record value"` - TTL int64 `help:"ttl"` - TYPE string `help:"dns type"` - PolicyType string `help:"PolicyType"` - } - shellutils.R(&DomainRecordupdateOptions{}, "domainrecord-update", "update domainrecord", func(cli *aliyun.SRegion, args *DomainRecordupdateOptions) error { - opts := cloudprovider.DnsRecordSet{} - opts.DnsName = args.NAME - opts.DnsType = cloudprovider.TDnsType(args.TYPE) - opts.DnsValue = args.VALUE - opts.Ttl = args.TTL - opts.ExternalId = args.DOMAINRECORDID - opts.PolicyType = cloudprovider.TDnsPolicyType(args.PolicyType) - err := cli.GetClient().UpdateDomainRecord(opts) - if err != nil { - return err - } - return nil - }) - - type DomainRecordDeleteOptions struct { - DOMAINRECORDID string `help:"DOMAINRECORDID"` - } - shellutils.R(&DomainRecordDeleteOptions{}, "domainrecord-delete", "delete domainrecord", func(cli *aliyun.SRegion, args *DomainRecordDeleteOptions) error { - err := cli.GetClient().DeleteDomainRecord(args.DOMAINRECORDID) - if err != nil { - return err - } - return nil - }) - - type DomainRecordSetStatusOptions struct { - DOMAINRECORDID string `help:"PRIVATEZONEID"` - STATUS string `choices:"Enable|Disable"` - } - shellutils.R(&DomainRecordSetStatusOptions{}, "domainrecord-setstatus", "set domainrecord status", func(cli *aliyun.SRegion, args *DomainRecordSetStatusOptions) error { - - err := cli.GetClient().SetDomainRecordStatus(args.DOMAINRECORDID, args.STATUS) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/doc.go b/pkg/multicloud/aliyun/shell/doc.go deleted file mode 100644 index e544f09879..0000000000 --- a/pkg/multicloud/aliyun/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/aliyun/shell" diff --git a/pkg/multicloud/aliyun/shell/eip.go b/pkg/multicloud/aliyun/shell/eip.go deleted file mode 100644 index 44cbea01e0..0000000000 --- a/pkg/multicloud/aliyun/shell/eip.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - Id string `help:"Eip id"` - AssociateId string `help:"Id of associate resource"` - Addr string `help:"Eip "` - Offset int `help:"List offset"` - Limit int `help:"List limit"` - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *aliyun.SRegion, args *EipListOptions) error { - eips, total, e := cli.GetEips(args.Id, args.AssociateId, args.Addr, args.Offset, args.Limit) - if e != nil { - return e - } - printList(eips, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type EipAllocateOptions struct { - Name string - BW int `help:"Bandwidth limit in Mbps"` - ResourceGroupId string `help:"Resource group Id"` - } - shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *aliyun.SRegion, args *EipAllocateOptions) error { - eip, err := cli.AllocateEIP(args.Name, args.BW, aliyun.InternetChargeByTraffic, args.ResourceGroupId) - 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 *aliyun.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 *aliyun.SRegion, args *EipAssociateOptions) error { - err := cli.AssociateEip(args.ID, args.INSTANCE) - return err - }) - shellutils.R(&EipAssociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *aliyun.SRegion, args *EipAssociateOptions) error { - err := cli.DissociateEip(args.ID, args.INSTANCE) - return err - }) -} diff --git a/pkg/multicloud/aliyun/shell/elasticcache.go b/pkg/multicloud/aliyun/shell/elasticcache.go deleted file mode 100644 index d1b26c8326..0000000000 --- a/pkg/multicloud/aliyun/shell/elasticcache.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElasticcacheListOptions struct { - } - shellutils.R(&ElasticcacheListOptions{}, "elasticcache-list", "List elasticcaches", func(cli *aliyun.SRegion, args *ElasticcacheListOptions) error { - instances, e := cli.GetElasticCaches(nil) - if e != nil { - return e - } - printList(instances, len(instances), 0, 0, []string{}) - return nil - }) - - type ElasticcacheIdOptions struct { - ID string `help:"ID of instances to show"` - } - shellutils.R(&ElasticcacheIdOptions{}, "elasticcache-show", "Show elasticcache", func(cli *aliyun.SRegion, args *ElasticcacheIdOptions) error { - instance, err := cli.GetElasticCacheById(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - type ElasticcacheBackupsListOptions struct { - ID string `help:"ID of instances to show"` - StartTime string `help:"backup start time. format: 2019-03-11T10:00Z"` - EndTime string `help:"backup end time. format: 2019-03-11T10:00Z"` - } - - shellutils.R(&ElasticcacheBackupsListOptions{}, "elasticcache-backup-list", "List elasticcache backups", func(cli *aliyun.SRegion, args *ElasticcacheBackupsListOptions) error { - backups, err := cli.GetElasticCacheBackups(args.ID, args.StartTime, args.EndTime) - if err != nil { - return err - } - printList(backups, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElasticcacheIdOptions{}, "elasticcache-parameter-list", "List elasticcache parameters", func(cli *aliyun.SRegion, args *ElasticcacheIdOptions) error { - parameters, err := cli.GetElasticCacheParameters(args.ID) - if err != nil { - return err - } - printList(parameters, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElasticcacheIdOptions{}, "elasticcache-account-list", "List elasticcache accounts", func(cli *aliyun.SRegion, args *ElasticcacheIdOptions) error { - accounts, err := cli.GetElasticCacheAccounts(args.ID) - if err != nil { - return err - } - printList(accounts, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElasticcacheIdOptions{}, "elasticcache-acl-list", "List elasticcache security ip rules", func(cli *aliyun.SRegion, args *ElasticcacheIdOptions) error { - acls, err := cli.GetElasticCacheAcls(args.ID) - if err != nil { - return err - } - printList(acls, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/elk.go b/pkg/multicloud/aliyun/shell/elk.go deleted file mode 100644 index 1cb4244de0..0000000000 --- a/pkg/multicloud/aliyun/shell/elk.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElkListOptions struct { - Page int - Size int - } - shellutils.R(&ElkListOptions{}, "elastic-search-list", "List elastic searchs", func(cli *aliyun.SRegion, args *ElkListOptions) error { - elks, _, err := cli.GetElasticSearchs(args.Size, args.Page) - if err != nil { - return err - } - printList(elks, 0, 0, 0, nil) - return nil - }) - - type ElkIdOptions struct { - ID string - } - - shellutils.R(&ElkIdOptions{}, "elastic-search-show", "Show elasitc search", func(cli *aliyun.SRegion, args *ElkIdOptions) error { - elk, err := cli.GetElasitcSearch(args.ID) - if err != nil { - return err - } - printObject(elk) - return nil - }) - - shellutils.R(&ElkIdOptions{}, "elastic-search-delete", "Delete elasitc search", func(cli *aliyun.SRegion, args *ElkIdOptions) error { - return cli.DeleteElasticSearch(args.ID) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/events.go b/pkg/multicloud/aliyun/shell/events.go deleted file mode 100644 index cee36cbb59..0000000000 --- a/pkg/multicloud/aliyun/shell/events.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/timeutils" - - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EventListOptions struct { - START string - END string - Token string - EventRW string `choices:"Read|Write|All"` - RequestId string - } - shellutils.R(&EventListOptions{}, "event-list", "List event", func(cli *aliyun.SRegion, args *EventListOptions) error { - start, err := timeutils.ParseTimeStr(args.START) - if err != nil { - return errors.Wrap(err, "timeutils.ParseTimeStr.Start") - } - end, err := timeutils.ParseTimeStr(args.END) - if err != nil { - return errors.Wrap(err, "timeutils.ParseTimeStr.End") - } - events, token, err := cli.GetEvents(start, end, args.Token, args.EventRW, args.RequestId) - if err != nil { - return err - } - fmt.Printf("token: %s", token) - printList(events, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/filesystem.go b/pkg/multicloud/aliyun/shell/filesystem.go deleted file mode 100644 index 9483e62afd..0000000000 --- a/pkg/multicloud/aliyun/shell/filesystem.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type FileSystemListOptions struct { - Id string `help:"FileSystem Id"` - PageSize int `help:"page size"` - PageNum int `help:"page num"` - } - shellutils.R(&FileSystemListOptions{}, "file-system-list", "List FileSystem", func(cli *aliyun.SRegion, args *FileSystemListOptions) error { - nas, _, err := cli.GetFileSystems(args.Id, args.PageSize, args.PageNum) - if err != nil { - return err - } - printList(nas, 0, 0, 0, []string{}) - return nil - }) - - type FileSystemDeleteOptions struct { - ID string `help:"File System ID"` - } - shellutils.R(&FileSystemDeleteOptions{}, "file-system-delete", "Delete filesystem", func(cli *aliyun.SRegion, args *FileSystemDeleteOptions) error { - return cli.DeleteFileSystem(args.ID) - }) - - shellutils.R(&cloudprovider.FileSystemCraeteOptions{}, "file-system-create", "Create filesystem", func(cli *aliyun.SRegion, args *cloudprovider.FileSystemCraeteOptions) error { - fs, err := cli.CreateFileSystem(args) - if err != nil { - return err - } - printObject(fs) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/image.go b/pkg/multicloud/aliyun/shell/image.go deleted file mode 100644 index 99d4f832f3..0000000000 --- a/pkg/multicloud/aliyun/shell/image.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "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:"system|self|others|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 *aliyun.SRegion, args *ImageListOptions) error { - images, total, e := cli.GetImages(aliyun.ImageStatusType(args.Status), aliyun.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 ImageShowOptions struct { - ID string `help:"image ID"` - } - shellutils.R(&ImageShowOptions{}, "image-show", "Show image", func(cli *aliyun.SRegion, args *ImageShowOptions) error { - img, err := cli.GetImage(args.ID) - if err != nil { - return err - } - printObject(img) - return nil - }) - - type ImageDeleteOptions struct { - ID string `help:"ID or Name to delete"` - } - shellutils.R(&ImageDeleteOptions{}, "image-delete", "Delete image", func(cli *aliyun.SRegion, args *ImageDeleteOptions) error { - return cli.DeleteImage(args.ID) - }) - - type ImageCreateOptions struct { - SNAPSHOT string `help:"Snapshot id"` - NAME string `help:"Image name"` - Desc string `help:"Image desc"` - } - shellutils.R(&ImageCreateOptions{}, "image-create", "Create image", func(cli *aliyun.SRegion, args *ImageCreateOptions) error { - imageId, err := cli.CreateImage(args.SNAPSHOT, args.NAME, args.Desc) - if err != nil { - return err - } - fmt.Println(imageId) - return nil - }) - - type ImageExportOptions struct { - ID string `help:"ID or Name to export"` - BUCKET string `help:"Bucket name"` - } - - shellutils.R(&ImageExportOptions{}, "image-export", "Export image", func(cli *aliyun.SRegion, args *ImageExportOptions) error { - oss, err := cli.GetOssClient() - if err != nil { - return err - } - exist, err := oss.IsBucketExist(args.BUCKET) - if err != nil { - return err - } - if !exist { - return fmt.Errorf("not exist bucket %s", args.BUCKET) - } - bucket, err := oss.Bucket(args.BUCKET) - if err != nil { - return err - } - task, err := cli.ExportImage(args.ID, bucket) - if err != nil { - return err - } - printObject(task) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/instance.go b/pkg/multicloud/aliyun/shell/instance.go deleted file mode 100644 index f1edb8b23d..0000000000 --- a/pkg/multicloud/aliyun/shell/instance.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/billing" - "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 *aliyun.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 InstanceCreateOptions 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"` - VSWITCH string `help:"Vswitch ID"` - PASSWD string `help:"password"` - PublicKey string `help:"PublicKey"` - } - shellutils.R(&InstanceCreateOptions{}, "instance-create", "Create a instance", func(cli *aliyun.SRegion, args *InstanceCreateOptions) error { - instance, e := cli.CreateInstanceSimple(args.NAME, args.IMAGE, args.CPU, args.MEMORYGB, args.STORAGE, args.Disk, args.VSWITCH, args.PASSWD, args.PublicKey) - if e != nil { - return e - } - printObject(instance) - return nil - }) - - type InstanceDiskOperationOptions struct { - ID string `help:"instance ID"` - DISK string `help:"disk ID"` - } - - shellutils.R(&InstanceDiskOperationOptions{}, "instance-attach-disk", "Attach a disk to instance", func(cli *aliyun.SRegion, args *InstanceDiskOperationOptions) error { - err := cli.AttachDisk(args.ID, args.DISK) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&InstanceDiskOperationOptions{}, "instance-detach-disk", "Detach a disk to instance", func(cli *aliyun.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 *aliyun.SRegion, args *InstanceOperationOptions) error { - err := cli.StartVM(args.ID) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&InstanceOperationOptions{}, "instance-auto-renew-info", "Show instance auto renew info", func(cli *aliyun.SRegion, args *InstanceOperationOptions) error { - info, err := cli.GetInstanceAutoRenewAttribute(args.ID) - if err != nil { - return err - } - printObject(info) - return nil - }) - - shellutils.R(&InstanceOperationOptions{}, "instance-eip-convert", "Convert instance public ip to eip", func(cli *aliyun.SRegion, args *InstanceOperationOptions) error { - err := cli.ConvertPublicIpToEip(args.ID) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&InstanceOperationOptions{}, "instance-vnc", "Get a instance VNC url", func(cli *aliyun.SRegion, args *InstanceOperationOptions) error { - url, err := cli.GetInstanceVNCUrl(args.ID) - if err != nil { - return err - } - fmt.Println(url) - return nil - }) - - type InstanceStopOptions struct { - ID string `help:"instance ID"` - Force bool `help:"Force stop instance"` - StopCharging bool `help:"Stop Charging"` - } - shellutils.R(&InstanceStopOptions{}, "instance-stop", "Stop a instance", func(cli *aliyun.SRegion, args *InstanceStopOptions) error { - err := cli.StopVM(args.ID, args.Force, args.StopCharging) - if err != nil { - return err - } - return nil - }) - shellutils.R(&InstanceOperationOptions{}, "instance-delete", "Delete a instance", func(cli *aliyun.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 *aliyun.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"` - Password string `help:"pasword"` - Keypair string `help:"keypair name"` - Size int `help:"system disk size in GB"` - } - - shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *aliyun.SRegion, args *InstanceRebuildRootOptions) error { - diskID, err := cli.ReplaceSystemDisk(args.ID, args.Image, args.Password, args.Keypair, args.Size) - if err != nil { - return err - } - fmt.Printf("New diskID is %s", diskID) - return nil - }) - - type InstanceChangeConfigOptions struct { - ID string `help:"instance ID"` - InstanceType string `help:"instance type"` - } - - shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Deploy keypair/password to a stopped virtual server", func(cli *aliyun.SRegion, args *InstanceChangeConfigOptions) error { - err := cli.ChangeVMConfig(args.ID, args.InstanceType) - if err != nil { - return err - } - return nil - }) - - type InstanceUpdatePasswordOptions struct { - ID string `help:"Instance ID"` - PASSWD string `help:"new password"` - } - shellutils.R(&InstanceUpdatePasswordOptions{}, "instance-update-password", "Update instance password", func(cli *aliyun.SRegion, args *InstanceUpdatePasswordOptions) error { - err := cli.UpdateInstancePassword(args.ID, args.PASSWD) - return err - }) - - type InstanceSetAutoRenewOptions struct { - ID string `help:"Instance ID"` - AutoRenew bool `help:"Is auto renew instance"` - Duration string - } - - shellutils.R(&InstanceSetAutoRenewOptions{}, "instance-set-auto-renew", "Set instance auto renew", func(cli *aliyun.SRegion, args *InstanceSetAutoRenewOptions) error { - bc, _ := billing.ParseBillingCycle(args.Duration) - bc.AutoRenew = args.AutoRenew - return cli.SetInstanceAutoRenew(args.ID, bc) - }) - - type InstanceSaveImageOptions struct { - ID string `help:"Instance ID"` - IMAGE_NAME string `help:"Image name"` - Notes string `hlep:"Image desc"` - } - shellutils.R(&InstanceSaveImageOptions{}, "instance-save-image", "Save instance to image", func(cli *aliyun.SRegion, args *InstanceSaveImageOptions) error { - opts := cloudprovider.SaveImageOptions{ - Name: args.IMAGE_NAME, - Notes: args.Notes, - } - image, err := cli.SaveImage(args.ID, &opts) - if err != nil { - return err - } - printObject(image) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/instancetype.go b/pkg/multicloud/aliyun/shell/instancetype.go deleted file mode 100644 index bb746e77c6..0000000000 --- a/pkg/multicloud/aliyun/shell/instancetype.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceTypeListOptions struct { - } - shellutils.R(&InstanceTypeListOptions{}, "instance-type-list", "List intance types", func(cli *aliyun.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 *aliyun.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 - }) -} diff --git a/pkg/multicloud/aliyun/shell/kafka.go b/pkg/multicloud/aliyun/shell/kafka.go deleted file mode 100644 index af24f10ca6..0000000000 --- a/pkg/multicloud/aliyun/shell/kafka.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KafkaListOptions struct { - Ids []string - } - shellutils.R(&KafkaListOptions{}, "kafka-list", "List kafka", func(cli *aliyun.SRegion, args *KafkaListOptions) error { - kafkas, err := cli.GetKafkas(args.Ids) - if err != nil { - return err - } - printList(kafkas, 0, 0, 0, []string{}) - return nil - }) - - type KafkaIdOptions struct { - ID string - } - - shellutils.R(&KafkaIdOptions{}, "kafka-delete", "Delete kafka", func(cli *aliyun.SRegion, args *KafkaIdOptions) error { - return cli.DeleteKafka(args.ID) - }) - - shellutils.R(&KafkaIdOptions{}, "kafka-release", "Release kafka", func(cli *aliyun.SRegion, args *KafkaIdOptions) error { - return cli.ReleaseKafka(args.ID) - }) - - type KafkaTopicListOptions struct { - KafkaIdOptions - Page int - PageSize int - } - - shellutils.R(&KafkaTopicListOptions{}, "kafka-topic-list", "List kafka topic", func(cli *aliyun.SRegion, args *KafkaTopicListOptions) error { - topics, _, err := cli.GetKafkaTopics(args.ID, args.Page, args.PageSize) - if err != nil { - return err - } - printList(topics, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/keypair.go b/pkg/multicloud/aliyun/shell/keypair.go deleted file mode 100644 index ec1026f4c5..0000000000 --- a/pkg/multicloud/aliyun/shell/keypair.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "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 *aliyun.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 *aliyun.SRegion, args *KeyPairImportOptions) error { - keypair, err := cli.ImportKeypair(args.NAME, args.PUBKEY) - if err != nil { - return err - } - printObject(keypair) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/kube_cluster.go b/pkg/multicloud/aliyun/shell/kube_cluster.go deleted file mode 100644 index 069bd6ff86..0000000000 --- a/pkg/multicloud/aliyun/shell/kube_cluster.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KubeClusterListOptions struct { - PageSize int - PageNumber int - } - shellutils.R(&KubeClusterListOptions{}, "kube-cluster-list", "List kube clusters", func(cli *aliyun.SRegion, args *KubeClusterListOptions) error { - clusters, _, err := cli.GetKubeClusters(args.PageSize, args.PageNumber) - if err != nil { - return err - } - printList(clusters, 0, 0, 0, []string{}) - return nil - }) - - type KubeClusterIdOptions struct { - ID string - } - - shellutils.R(&KubeClusterIdOptions{}, "kube-cluster-show", "Show kube cluster", func(cli *aliyun.SRegion, args *KubeClusterIdOptions) error { - cluster, err := cli.GetKubeCluster(args.ID) - if err != nil { - return err - } - printObject(cluster) - return nil - }) - - shellutils.R(&KubeClusterIdOptions{}, "kube-cluster-delete", "Delete kube cluster", func(cli *aliyun.SRegion, args *KubeClusterIdOptions) error { - return cli.DeleteKubeCluster(args.ID, false) - }) - - type KubeClusterKubeconfigOptions struct { - ID string - Private bool - ExpireMinutes int - } - - shellutils.R(&KubeClusterKubeconfigOptions{}, "kube-cluster-kubeconfig", "Get kube cluster kubeconfig", func(cli *aliyun.SRegion, args *KubeClusterKubeconfigOptions) error { - config, err := cli.GetKubeConfig(args.ID, args.Private, args.ExpireMinutes) - if err != nil { - return err - } - printObject(config) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/kube_node.go b/pkg/multicloud/aliyun/shell/kube_node.go deleted file mode 100644 index c7c02d8218..0000000000 --- a/pkg/multicloud/aliyun/shell/kube_node.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KubeNodeListOptions struct { - CLUSTER string - PageSize int - PageNumber int - } - shellutils.R(&KubeNodeListOptions{}, "kube-node-list", "List kube nodes", func(cli *aliyun.SRegion, args *KubeNodeListOptions) error { - nodes, _, err := cli.GetKubeNodes(args.CLUSTER, args.PageSize, args.PageNumber) - if err != nil { - return err - } - printList(nodes, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/kube_node_pools.go b/pkg/multicloud/aliyun/shell/kube_node_pools.go deleted file mode 100644 index 3f3f7bbdab..0000000000 --- a/pkg/multicloud/aliyun/shell/kube_node_pools.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KubeNodePoolListOptions struct { - CLUSTER string - } - shellutils.R(&KubeNodePoolListOptions{}, "kube-node-pool-list", "List kube node pools", func(cli *aliyun.SRegion, args *KubeNodePoolListOptions) error { - pools, err := cli.GetKubeNodePools(args.CLUSTER) - if err != nil { - return err - } - printList(pools, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/loadbalancer.go b/pkg/multicloud/aliyun/shell/loadbalancer.go deleted file mode 100644 index a9e33d071e..0000000000 --- a/pkg/multicloud/aliyun/shell/loadbalancer.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerListOptions struct { - Ids []string `help:"Loadbalancer ids"` - } - shellutils.R(&LoadbalancerListOptions{}, "lb-list", "List loadbalancers", func(cli *aliyun.SRegion, args *LoadbalancerListOptions) error { - lbs, err := cli.GetLoadbalancers(args.Ids) - if err != nil { - return err - } - printList(lbs, len(lbs), 0, 0, []string{}) - return nil - }) - - type LoadbalancerOptions struct { - ID string `help:"ID of loadbalancer"` - } - shellutils.R(&LoadbalancerOptions{}, "lb-show", "Show loadbalancer", func(cli *aliyun.SRegion, args *LoadbalancerOptions) error { - lb, err := cli.GetLoadbalancerDetail(args.ID) - if err != nil { - return err - } - printObject(lb) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/loadbalanceracl.go b/pkg/multicloud/aliyun/shell/loadbalanceracl.go deleted file mode 100644 index 5a071a7f8b..0000000000 --- a/pkg/multicloud/aliyun/shell/loadbalanceracl.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerACLListOptions struct { - } - shellutils.R(&LoadbalancerACLListOptions{}, "lb-acl-list", "List loadbalanceAcls", func(cli *aliyun.SRegion, args *LoadbalancerACLListOptions) error { - acls, err := cli.GetLoadBalancerAcls() - if err != nil { - return err - } - printList(acls, len(acls), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/loadbalancerbackend.go b/pkg/multicloud/aliyun/shell/loadbalancerbackend.go deleted file mode 100644 index 40e86dedaf..0000000000 --- a/pkg/multicloud/aliyun/shell/loadbalancerbackend.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerBackendListOptions struct { - GROUPID string `help:"LoadbalancerBackendgroup ID"` - } - shellutils.R(&LoadbalancerBackendListOptions{}, "lb-backend-list", "List loadbalanceBackends", func(cli *aliyun.SRegion, args *LoadbalancerBackendListOptions) error { - backends, err := cli.GetLoadbalancerBackends(args.GROUPID) - if err != nil { - return err - } - printList(backends, len(backends), 0, 0, []string{}) - return nil - }) - - shellutils.R(&LoadbalancerBackendListOptions{}, "lb-master-slave-backend-list", "List loadbalanceMasterSlaveBackends", func(cli *aliyun.SRegion, args *LoadbalancerBackendListOptions) error { - backends, err := cli.GetLoadbalancerMasterSlaveBackends(args.GROUPID) - if err != nil { - return err - } - printList(backends, len(backends), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/loadbalancerbackendgroup.go b/pkg/multicloud/aliyun/shell/loadbalancerbackendgroup.go deleted file mode 100644 index a0f735cd7e..0000000000 --- a/pkg/multicloud/aliyun/shell/loadbalancerbackendgroup.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerBackendgroupListOptions struct { - ID string `help:"ID of Loadbalancer"` - } - shellutils.R(&LoadbalancerBackendgroupListOptions{}, "lb-backendgroup-list", "List loadbalancerBackendgroups", func(cli *aliyun.SRegion, args *LoadbalancerBackendgroupListOptions) error { - backendgroups, err := cli.GetLoadbalancerBackendgroups(args.ID) - if err != nil { - return err - } - printList(backendgroups, len(backendgroups), 0, 0, []string{}) - return nil - }) - - shellutils.R(&LoadbalancerBackendgroupListOptions{}, "lb-master-slave-backendgroup-list", "List loadbalancerMasterSlaveBackendgroups", func(cli *aliyun.SRegion, args *LoadbalancerBackendgroupListOptions) error { - backendgroups, err := cli.GetLoadbalancerMasterSlaveBackendgroups(args.ID) - if err != nil { - return err - } - printList(backendgroups, len(backendgroups), 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/loadbalancercertificate.go b/pkg/multicloud/aliyun/shell/loadbalancercertificate.go deleted file mode 100644 index 0df965ba07..0000000000 --- a/pkg/multicloud/aliyun/shell/loadbalancercertificate.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerServerCertificateListOptions struct { - } - shellutils.R(&LoadbalancerServerCertificateListOptions{}, "lb-server-certificate-list", "List ServerCertificates", func(cli *aliyun.SRegion, args *LoadbalancerServerCertificateListOptions) error { - serverCertificate, err := cli.GetLoadbalancerServerCertificates() - if err != nil { - return err - } - printList(serverCertificate, len(serverCertificate), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/loadbalancerlistener.go b/pkg/multicloud/aliyun/shell/loadbalancerlistener.go deleted file mode 100644 index 8232cf911f..0000000000 --- a/pkg/multicloud/aliyun/shell/loadbalancerlistener.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerListenerListOptions struct { - ID string `help:"ID of loadbalancer"` - PORT int `help:"PORT of listenerPort"` - } - shellutils.R(&LoadbalancerListenerListOptions{}, "lb-http-listener-show", "Show LoadbalancerHTTPListener", func(cli *aliyun.SRegion, args *LoadbalancerListenerListOptions) error { - listener, err := cli.GetLoadbalancerHTTPListener(args.ID, args.PORT) - if err != nil { - return err - } - printObject(listener) - return nil - }) - - shellutils.R(&LoadbalancerListenerListOptions{}, "lb-https-listener-show", "Show LoadbalancerHTTPSListener", func(cli *aliyun.SRegion, args *LoadbalancerListenerListOptions) error { - listener, err := cli.GetLoadbalancerHTTPSListener(args.ID, args.PORT) - if err != nil { - return err - } - printObject(listener) - return nil - }) - - shellutils.R(&LoadbalancerListenerListOptions{}, "lb-tcp-listener-show", "Show LoadbalancerTCPListener", func(cli *aliyun.SRegion, args *LoadbalancerListenerListOptions) error { - listener, err := cli.GetLoadbalancerTCPListener(args.ID, args.PORT) - if err != nil { - return err - } - printObject(listener) - return nil - }) - - shellutils.R(&LoadbalancerListenerListOptions{}, "lb-udp-listener-show", "Show LoadbalancerUDPListener", func(cli *aliyun.SRegion, args *LoadbalancerListenerListOptions) error { - listener, err := cli.GetLoadbalancerUDPListener(args.ID, args.PORT) - if err != nil { - return err - } - printObject(listener) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/loadbalancerlistenerrule.go b/pkg/multicloud/aliyun/shell/loadbalancerlistenerrule.go deleted file mode 100644 index 09c90d2787..0000000000 --- a/pkg/multicloud/aliyun/shell/loadbalancerlistenerrule.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerListenerRuleListOptions struct { - ID string `help:"ID of loadbalaner"` - PORT int `help:"Port of listener port"` - } - shellutils.R(&LoadbalancerListenerRuleListOptions{}, "lb-listener-rule-list", "List LoadbalancerListenerRules", func(cli *aliyun.SRegion, args *LoadbalancerListenerRuleListOptions) error { - rules, err := cli.GetLoadbalancerListenerRules(args.ID, args.PORT) - if err != nil { - return err - } - printList(rules, len(rules), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/mongodb.go b/pkg/multicloud/aliyun/shell/mongodb.go deleted file mode 100644 index c4a1ab803c..0000000000 --- a/pkg/multicloud/aliyun/shell/mongodb.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "time" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type MongoDBListOptions struct { - MongoType string `choices:"sharding|replicate|serverless"` - Offset int - Limit int - } - shellutils.R(&MongoDBListOptions{}, "mongodb-list", "List mongodb", func(cli *aliyun.SRegion, args *MongoDBListOptions) error { - dbs, _, err := cli.GetMongoDBs(args.MongoType, args.Limit, args.Offset) - if err != nil { - return err - } - printList(dbs, 0, 0, 0, []string{}) - return nil - }) - - type MongoDBIdOptions struct { - ID string - } - - shellutils.R(&MongoDBIdOptions{}, "mongodb-show", "Show mongodb", func(cli *aliyun.SRegion, args *MongoDBIdOptions) error { - db, err := cli.GetMongoDB(args.ID) - if err != nil { - return errors.Wrapf(err, "GetMongoDB(%s)", args.ID) - } - printObject(db) - return nil - - }) - - shellutils.R(&MongoDBIdOptions{}, "mongodb-delete", "Delete mongodb", func(cli *aliyun.SRegion, args *MongoDBIdOptions) error { - return cli.DeleteMongoDB(args.ID) - }) - - type MongoDBBackupListOptions struct { - ID string - START time.Time - END time.Time - PageSize int - PageNumber int - } - - shellutils.R(&MongoDBBackupListOptions{}, "mongodb-backup-list", "List mongodb backups", func(cli *aliyun.SRegion, args *MongoDBBackupListOptions) error { - backups, _, err := cli.GetMongoDBBackups(args.ID, args.START, args.END, args.PageSize, args.PageNumber) - if err != nil { - return err - } - printList(backups, 0, 0, 0, nil) - return nil - }) - - type MongoDBSkuListOptions struct { - } - - shellutils.R(&MongoDBSkuListOptions{}, "mongodb-sku-list", "List mongodb skus", func(cli *aliyun.SRegion, args *MongoDBSkuListOptions) error { - skus, err := cli.GetchMongoSkus() - if err != nil { - return err - } - printObject(skus) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/monitor.go b/pkg/multicloud/aliyun/shell/monitor.go deleted file mode 100644 index 48fe03e8c4..0000000000 --- a/pkg/multicloud/aliyun/shell/monitor.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/util/timeutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/mcclient/modulebase" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/printutils" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NamespaceListOptions struct { - } - shellutils.R(&NamespaceListOptions{}, "namespace-list", "List monbitor metric namespaces", func(cli *aliyun.SRegion, args *NamespaceListOptions) error { - nslist, err := cli.FetchNamespaces() - if err != nil { - return err - } - printList(nslist, 0, 0, 0, nil) - return nil - }) - - type MetricListOptions struct { - NAMESPACE string `help:"namespace"` - } - shellutils.R(&MetricListOptions{}, "metrics-list", "List metrics in a namespace", func(cli *aliyun.SRegion, args *MetricListOptions) error { - metrics, err := cli.FetchMetrics(args.NAMESPACE) - if err != nil { - return err - } - printList(metrics, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics in a namespace", func(cli *aliyun.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric: %s %s %s", metrics[i].Id, metrics[i].MetricType, metrics[i].Unit) - printList(metrics[i].Values, len(metrics[i].Values), 0, 0, []string{}) - } - return nil - }) - - type DescribeMetricListOptions struct { - METRIC string `help:"metric name"` - NAMESPACE string `help:"name space"` - Since string `help:"since, 2019-11-29T11:22:00Z"` - Until string `help:"since, 2019-11-30T11:22:00Z"` - } - shellutils.R(&DescribeMetricListOptions{}, "metric-data-list", "DescribeMetricList", func(cli *aliyun.SRegion, args *DescribeMetricListOptions) error { - var since time.Time - var err error - if len(args.Since) > 0 { - since, err = timeutils.ParseTimeStr(args.Since) - if err != nil { - return err - } - } - var until time.Time - if len(args.Until) > 0 { - until, err = timeutils.ParseTimeStr(args.Until) - if err != nil { - return err - } - } - data, err := cli.FetchMetricData(args.METRIC, args.NAMESPACE, since, until) - if err != nil { - return err - } - result := &modulebase.ListResult{ - Data: data, - Total: len(data), - } - printutils.PrintJSONList(result, nil) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/mount_target.go b/pkg/multicloud/aliyun/shell/mount_target.go deleted file mode 100644 index e29998e0db..0000000000 --- a/pkg/multicloud/aliyun/shell/mount_target.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type MountTargetListOptions struct { - ID string `help:"Id"` - DomainName string - PageSize int `help:"page size"` - PageNum int `help:"page num"` - } - shellutils.R(&MountTargetListOptions{}, "mount-target-list", "List MountTargets", func(cli *aliyun.SRegion, args *MountTargetListOptions) error { - mounts, _, err := cli.GetMountTargets(args.ID, args.DomainName, args.PageSize, args.PageNum) - if err != nil { - return err - } - printList(mounts, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&cloudprovider.SMountTargetCreateOptions{}, "mount-target-create", "Create Nas MountTarget", func(cli *aliyun.SRegion, args *cloudprovider.SMountTargetCreateOptions) error { - mt, err := cli.CreateMountTarget(args) - if err != nil { - return err - } - printObject(mt) - return nil - }) - - type MountTargetDeleteOptions struct { - FILE_SYSTEM_ID string - MOUT_POINT_ID string - } - shellutils.R(&MountTargetDeleteOptions{}, "mount-target-delete", "Delete Nas MountTarget", func(cli *aliyun.SRegion, args *MountTargetDeleteOptions) error { - return cli.DeleteMountTarget(args.FILE_SYSTEM_ID, args.MOUT_POINT_ID) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/natgateway.go b/pkg/multicloud/aliyun/shell/natgateway.go deleted file mode 100644 index acdb51acb4..0000000000 --- a/pkg/multicloud/aliyun/shell/natgateway.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NatGatewayListOptions struct { - VpcId string `help:"Vpc Id"` - NatId string `help:"NatGateway Id"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&NatGatewayListOptions{}, "nat-list", "List NAT gateways", func(cli *aliyun.SRegion, args *NatGatewayListOptions) error { - gws, total, e := cli.GetNatGateways(args.VpcId, args.NatId, args.Offset, args.Limit) - if e != nil { - return e - } - printList(gws, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type NatGatewayDeleteOptions struct { - ID string `help:"Nat Id"` - Force bool `help:"Force Delete Nat"` - } - - shellutils.R(&NatGatewayDeleteOptions{}, "nat-delete", "Delete nat gateways", func(cli *aliyun.SRegion, args *NatGatewayDeleteOptions) error { - return cli.DeleteNatGateway(args.ID, args.Force) - }) - - type NatSEntryListOptions struct { - ID string `help:"SNat Table ID"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&NatSEntryListOptions{}, "snat-entry-list", "List SNAT entries", func(cli *aliyun.SRegion, args *NatSEntryListOptions) error { - entries, total, e := cli.GetSNATEntries(args.ID, args.Offset, args.Limit) - if e != nil { - return e - } - printList(entries, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type NatDEntryListOptions struct { - ID string `help:"DNat Table ID"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&NatDEntryListOptions{}, "dnat-entry-list", "List DNAT entries", func(cli *aliyun.SRegion, args *NatDEntryListOptions) error { - entries, total, e := cli.GetForwardTableEntries(args.ID, args.Offset, args.Limit) - if e != nil { - return e - } - printList(entries, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type SCreateDNatOptions struct { - GatewayID string `help:"Nat Gateway ID" positional:"true"` - Protocol string `help:"Protocol(tcp/udp)" positional:"true"` - ExternalIP string `help:"External IP" positional:"true"` - ExternalPort int `help:"External Port" positional:"true"` - InternalIP string `help:"Internal IP" positional:"true"` - InternalPort int `help:"Nat Gateway ID" positional:"true"` - } - shellutils.R(&SCreateDNatOptions{}, "dnat-entry-create", "Create DNAT entry", func(region *aliyun.SRegion, args *SCreateDNatOptions) error { - rule := cloudprovider.SNatDRule{ - Protocol: args.Protocol, - ExternalIP: args.ExternalIP, - ExternalPort: args.ExternalPort, - InternalIP: args.InternalIP, - InternalPort: args.InternalPort, - } - dnat, err := region.CreateForwardTableEntry(rule, args.GatewayID) - if err != nil { - return err - } - printObject(dnat) - return nil - }) - - type SCreateSNatOptions struct { - GatewayID string `help:"Nat Gateway ID" positional:"true"` - SourceCIDR string `help:"Source cidr" positional:"true"` - ExternalIP string `help:"External IP" positional:"true"` - } - shellutils.R(&SCreateSNatOptions{}, "snat-entry-create", "Create SNAT entry", func(region *aliyun.SRegion, args *SCreateSNatOptions) error { - rule := cloudprovider.SNatSRule{ - SourceCIDR: args.SourceCIDR, - ExternalIP: args.ExternalIP, - } - snat, err := region.CreateSNATTableEntry(rule, args.GatewayID) - if err != nil { - return err - } - printObject(snat) - return nil - }) - - type SShowSNatOptions struct { - TableID string `help:"SNat Table ID" positional:"true"` - NatID string `help:"SNat Entry ID" positional:"true"` - } - shellutils.R(&SShowSNatOptions{}, "snat-entry-show", "show SNAT entry", func(region *aliyun.SRegion, args *SShowSNatOptions) error { - snat, err := region.GetSNATEntry(args.TableID, args.NatID) - if err != nil { - return err - } - printObject(snat) - return nil - }) - - type SShowDNatOptions struct { - TableID string `help:"DNat Table ID" positional:"true"` - NatID string `help:"DNat Entry ID" positional:"true"` - } - shellutils.R(&SShowDNatOptions{}, "dnat-entry-show", "show SNAT entry", func(region *aliyun.SRegion, args *SShowDNatOptions) error { - dnat, err := region.GetForwardTableEntry(args.TableID, args.NatID) - if err != nil { - return err - } - printObject(dnat) - return nil - }) - - type SDeleteSNatOptions struct { - TableID string `help:"DNat Table ID" positional:"true"` - NatID string `help:"SNat Entry ID" positional:"true"` - } - shellutils.R(&SDeleteSNatOptions{}, "snat-entry-delete", "Delete SNAT entry", func(region *aliyun.SRegion, args *SDeleteSNatOptions) error { - err := region.DeleteSnatEntry(args.TableID, args.NatID) - if err != nil { - return err - } - return nil - }) - - type SDeleteDNatOptions struct { - TableID string `help:"DNat Table ID" positional:"true"` - NatID string `help:"DNat Entry ID" positional:"true"` - } - shellutils.R(&SDeleteDNatOptions{}, "dnat-entry-delete", "Delete DNAT entry", func(region *aliyun.SRegion, args *SDeleteDNatOptions) error { - err := region.DeleteForwardTableEntry(args.TableID, args.NatID) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/networkinterface.go b/pkg/multicloud/aliyun/shell/networkinterface.go deleted file mode 100644 index 0ecd5e4784..0000000000 --- a/pkg/multicloud/aliyun/shell/networkinterface.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkInterfaceListOptions struct { - InstanceId string `help:"Id or instance"` - Offset int - Limit int - } - shellutils.R(&NetworkInterfaceListOptions{}, "network-interface-list", "List networkinterfaces", func(cli *aliyun.SRegion, args *NetworkInterfaceListOptions) error { - interfaces, total, err := cli.GetNetworkInterfaces(args.InstanceId, args.Offset, args.Limit) - if err != nil { - return err - } - printList(interfaces, total, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/oss.go b/pkg/multicloud/aliyun/shell/oss.go deleted file mode 100644 index 8d11c8bc26..0000000000 --- a/pkg/multicloud/aliyun/shell/oss.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "os" - "path/filepath" - - osslib "github.com/aliyun/aliyun-oss-go-sdk/oss" - - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/fileutils2" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -type progressListener struct { -} - -func (this *progressListener) ProgressChanged(event *osslib.ProgressEvent) { - switch event.EventType { - case osslib.TransferStartedEvent: - fmt.Printf("\n") - case osslib.TransferDataEvent: - fmt.Printf("Progess: %f%%\r", (float64(event.ConsumedBytes) * 100.0 / float64(event.TotalBytes))) - case osslib.TransferCompletedEvent: - fmt.Printf("Transfer complete!\n") - case osslib.TransferFailedEvent: - fmt.Printf("Transfer failed!\n") - default: - fmt.Printf("Unknonw event type %d\n", event.EventType) - } -} - -func str2AclType(aclStr string) osslib.ACLType { - switch aclStr { - case "public-rw": - return osslib.ACLPublicReadWrite - case "public-read": - return osslib.ACLPublicRead - default: - return osslib.ACLPrivate - } -} - -func init() { - type OssListOptions struct { - } - shellutils.R(&OssListOptions{}, "oss-list", "List OSS buckets", func(cli *aliyun.SRegion, args *OssListOptions) error { - buckets, err := cli.GetIBuckets() - if err != nil { - return err - } - printList(buckets, len(buckets), 0, 50, nil) - return nil - }) - - type OssListBucketOptions struct { - BUCKET string `help:"bucket name"` - } - - shellutils.R(&OssListBucketOptions{}, "oss-list-bucket", "List content of a OSS bucket", func(cli *aliyun.SRegion, args *OssListBucketOptions) error { - oss, err := cli.GetOssClient() - if err != nil { - return err - } - bucket, err := oss.Bucket(args.BUCKET) - if err != nil { - return err - } - result, err := bucket.ListObjects() - if err != nil { - return err - } - printList(result.Objects, len(result.Objects), 0, len(result.Objects), nil) - return nil - }) - - type OssCreateBucketOptions struct { - BUCKET string `help:"bucket name"` - StorageClass string `help:"storage class" choices:"Standard|IA|Archive"` - - Acl string `help:"ACL" choices:"private|public-read|public-read-write"` - } - shellutils.R(&OssCreateBucketOptions{}, "oss-create-bucket", "Create a OSS bucket", func(cli *aliyun.SRegion, args *OssCreateBucketOptions) error { - err := cli.CreateIBucket(args.BUCKET, args.StorageClass, args.Acl) - if err != nil { - return err - } - return nil - }) - - type OssDeleteBucketOptions struct { - BUCKET string `help:"bucket name"` - } - shellutils.R(&OssDeleteBucketOptions{}, "oss-delete-bucket", "Delete a OSS bucket", func(cli *aliyun.SRegion, args *OssDeleteBucketOptions) error { - err := cli.DeleteIBucket(args.BUCKET) - if err != nil { - return err - } - return nil - }) - - type OssUploadOptions struct { - BUCKET string `help:"bucket name"` - KEY string `help:"Object key"` - FILE string `help:"Local file path"` - Progress bool `help:"show progress"` - Acl string `help:"Object ACL" choices:"private|public-read|public-rw"` - } - shellutils.R(&OssUploadOptions{}, "oss-upload", "Upload a file to a OSS bucket", func(cli *aliyun.SRegion, args *OssUploadOptions) error { - oss, err := cli.GetOssClient() - if err != nil { - return err - } - bucket, err := oss.Bucket(args.BUCKET) - if err != nil { - return err - } - - options := make([]osslib.Option, 0) - if args.Progress { - listener := progressListener{} - options = append(options, osslib.Progress(&listener)) - } - if len(args.Acl) > 0 { - options = append(options, osslib.ObjectACL(str2AclType(args.Acl))) - } - if fileutils2.IsFile(args.FILE) { - err = bucket.UploadFile(args.KEY, args.FILE, 4*1024*1024, options...) - return err - } else if fileutils2.IsDir(args.FILE) { - return filepath.Walk(args.FILE, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.Mode().IsRegular() { - rel, _ := filepath.Rel(args.FILE, path) - src := path - dst := filepath.Join(args.KEY, rel) - fmt.Println("upload", src, "to", dst) - uploadErr := bucket.UploadFile(dst, src, - 4*1024*1024, options...) - if uploadErr != nil { - return uploadErr - } - } - return nil - }) - } else { - return fmt.Errorf("Unsupported file type %s", args.FILE) - } - }) - - type OssObjectAclOptions struct { - BUCKET string `help:"bucket name"` - KEY string `help:"object key"` - ACL string `help:"ACL" choices:"private|public-read|public-rw"` - } - shellutils.R(&OssObjectAclOptions{}, "oss-set-acl", "Set acl for a object", func(cli *aliyun.SRegion, args *OssObjectAclOptions) error { - oss, err := cli.GetOssClient() - if err != nil { - return err - } - bucket, err := oss.Bucket(args.BUCKET) - if err != nil { - return err - } - err = bucket.SetObjectACL(args.KEY, str2AclType(args.ACL)) - return err - }) - - type OssDeleteOptions struct { - BUCKET string `help:"bucket name"` - KEY string `help:"Object key"` - } - - shellutils.R(&OssDeleteOptions{}, "oss-delete", "Delete a file from a OSS bucket", func(cli *aliyun.SRegion, args *OssDeleteOptions) error { - oss, err := cli.GetOssClient() - if err != nil { - return err - } - bucket, err := oss.Bucket(args.BUCKET) - if err != nil { - return err - } - err = bucket.DeleteObject(args.KEY) - return err - }) -} diff --git a/pkg/multicloud/aliyun/shell/printutils.go b/pkg/multicloud/aliyun/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/aliyun/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/aliyun/shell/private_zone.go b/pkg/multicloud/aliyun/shell/private_zone.go deleted file mode 100644 index c1da6919bf..0000000000 --- a/pkg/multicloud/aliyun/shell/private_zone.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2019 Yunion -// -// 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. - -// Copyright 2019 Yunion -// -// 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 -// PageSizeations under the License. - -package shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type PrivateZoneListOptions struct { - PageSize int `help:"page size"` - PageNumber int `help:"page PageNumber"` - } - shellutils.R(&PrivateZoneListOptions{}, "privatezone-list", "List privatezone", func(cli *aliyun.SRegion, args *PrivateZoneListOptions) error { - szones, e := cli.GetClient().DescribeZones(args.PageNumber, args.PageSize) - if e != nil { - return e - } - printList(szones.Zones.Zone, szones.TotalItems, args.PageNumber, args.PageSize, []string{}) - return nil - }) - - type PrivateZoneCreateOptions struct { - NAME string `help:"Domain name"` - Type string `choices:"PublicZone|PrivateZone"` - Vpc string `help:"vpc id"` - Region string `help:"region id"` - } - shellutils.R(&PrivateZoneCreateOptions{}, "privatezone-create", "Create privatezone", func(cli *aliyun.SRegion, args *PrivateZoneCreateOptions) error { - opts := cloudprovider.SDnsZoneCreateOptions{} - opts.Name = args.NAME - opts.ZoneType = cloudprovider.TDnsZoneType(args.Type) - if len(args.Vpc) > 0 && len(args.Region) > 0 { - vpc := cloudprovider.SPrivateZoneVpc{} - vpc.Id = args.Vpc - vpc.RegionId = args.Region - opts.Vpcs = []cloudprovider.SPrivateZoneVpc{vpc} - } - hostzones, err := cli.GetClient().CreateZone(&opts) - if err != nil { - return err - } - printObject(hostzones) - return nil - }) - - type PrivateZoneDeleteOptions struct { - PRIVATEZONEID string - } - shellutils.R(&PrivateZoneDeleteOptions{}, "privatezone-delete", "delete privatezone", func(cli *aliyun.SRegion, args *PrivateZoneDeleteOptions) error { - err := cli.GetClient().DeleteZone(args.PRIVATEZONEID) - if err != nil { - return err - } - return nil - }) - - type PrivateZoneShowOptions struct { - ID string `help:"ID or name of privatezone"` - } - shellutils.R(&PrivateZoneShowOptions{}, "privatezone-show", "Show privatezone", func(cli *aliyun.SRegion, args *PrivateZoneShowOptions) error { - szone, e := cli.GetClient().DescribeZoneInfo(args.ID) - if e != nil { - return e - } - printObject(szone) - return nil - }) - - type PrivateZoneAddVpcOptions struct { - PRIVATEZONEID string - VPC string - REGION string - } - shellutils.R(&PrivateZoneAddVpcOptions{}, "privatezone-add-vpc", "associate vpc with privatezone", func(cli *aliyun.SRegion, args *PrivateZoneAddVpcOptions) error { - vpc := cloudprovider.SPrivateZoneVpc{} - vpc.Id = args.VPC - vpc.RegionId = args.REGION - err := cli.GetClient().BindZoneVpc(args.PRIVATEZONEID, &vpc) - if err != nil { - return err - } - return nil - }) - - type PrivateZoneDeleteVpcsOptions struct { - PRIVATEZONEID string - } - shellutils.R(&PrivateZoneDeleteVpcsOptions{}, "privatezone-delete-vpc", "delete vpc with privatezone", func(cli *aliyun.SRegion, args *PrivateZoneDeleteVpcsOptions) error { - err := cli.GetClient().UnBindZoneVpcs(args.PRIVATEZONEID) - if err != nil { - return err - } - return nil - }) - - type PrivateZoneRecordListOptions struct { - ID string `help:"ID or name of privatezone"` - PageSize int `help:"page size"` - PageNumber int `help:"page PageNumber"` - } - shellutils.R(&PrivateZoneRecordListOptions{}, "privatezonerecord-list", "List privatezonerecord", func(cli *aliyun.SRegion, args *PrivateZoneRecordListOptions) error { - srecords, e := cli.GetClient().DescribeZoneRecords(args.ID, args.PageNumber, args.PageSize) - if e != nil { - return e - } - printList(srecords.Records.Record, srecords.TotalItems, args.PageNumber, args.PageSize, []string{}) - return nil - }) - - type PvtzRecordCreateOptions struct { - PRIVATEZONEID string `help:"PRIVATEZONEID"` - NAME string `help:"Domain name"` - VALUE string `help:"dns record value"` - TTL int64 `help:"ttl"` - TYPE string `help:"dns type"` - PolicyType string `help:"PolicyType"` - Identify string `help:"Identify"` - } - shellutils.R(&PvtzRecordCreateOptions{}, "privatezonerecord-create", "create privatezonerecord", func(cli *aliyun.SRegion, args *PvtzRecordCreateOptions) error { - opts := cloudprovider.DnsRecordSet{} - opts.DnsName = args.NAME - opts.DnsType = cloudprovider.TDnsType(args.TYPE) - opts.DnsValue = args.VALUE - opts.Ttl = args.TTL - opts.ExternalId = args.Identify - _, err := cli.GetClient().AddZoneRecord(args.PRIVATEZONEID, opts) - if err != nil { - return err - } - return nil - }) - - type PvtzRecordupdateOptions struct { - PRIVATEZONEID string `help:"PRIVATEZONEID"` - NAME string `help:"Domain name"` - VALUE string `help:"dns record value"` - TTL int64 `help:"ttl"` - TYPE string `help:"dns type"` - Identify string `help:"Identify"` - } - shellutils.R(&PvtzRecordupdateOptions{}, "privatezonerecord-update", "update privatezonerecord", func(cli *aliyun.SRegion, args *PvtzRecordupdateOptions) error { - opts := cloudprovider.DnsRecordSet{} - opts.DnsName = args.NAME - opts.DnsType = cloudprovider.TDnsType(args.TYPE) - opts.DnsValue = args.VALUE - opts.Ttl = args.TTL - opts.ExternalId = args.Identify - err := cli.GetClient().UpdateZoneRecord(opts) - if err != nil { - return err - } - return nil - }) - - type PvtzRecordDeleteOptions struct { - PRIVATEZONERECORDID string `help:"PRIVATEZONEID"` - } - shellutils.R(&PvtzRecordDeleteOptions{}, "privatezonerecord-delete", "delete privatezonerecord", func(cli *aliyun.SRegion, args *PvtzRecordDeleteOptions) error { - err := cli.GetClient().DeleteZoneRecord(args.PRIVATEZONERECORDID) - if err != nil { - return err - } - return nil - }) - - type PvtzRecordSetStatusOptions struct { - PRIVATEZONERECORDID string `help:"PRIVATEZONEID"` - STATUS string `choices:"ENABLE|DISABLE"` - } - shellutils.R(&PvtzRecordSetStatusOptions{}, "privatezonerecord-setstatus", "set privatezonerecord status", func(cli *aliyun.SRegion, args *PvtzRecordSetStatusOptions) error { - - err := cli.GetClient().SetZoneRecordStatus(args.PRIVATEZONERECORDID, args.STATUS) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/quota.go b/pkg/multicloud/aliyun/shell/quota.go deleted file mode 100644 index 8948182c72..0000000000 --- a/pkg/multicloud/aliyun/shell/quota.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type QuotaListOptions struct { - } - shellutils.R(&QuotaListOptions{}, "quota-list", "List quota", func(cli *aliyun.SRegion, args *QuotaListOptions) error { - quotas, err := cli.GetQuotas() - if err != nil { - return err - } - printList(quotas, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/ram_group.go b/pkg/multicloud/aliyun/shell/ram_group.go deleted file mode 100644 index b6a1fca171..0000000000 --- a/pkg/multicloud/aliyun/shell/ram_group.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CloudgroupCreateOptions struct { - NAME string - Comments string - } - - shellutils.R(&CloudgroupCreateOptions{}, "cloud-group-create", "Create Cloud group", func(cli *aliyun.SRegion, args *CloudgroupCreateOptions) error { - group, err := cli.GetClient().CreateGroup(args.NAME, args.Comments) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type CloudgroupListOptions struct { - Offset string - Limit int - } - - shellutils.R(&CloudgroupListOptions{}, "cloud-group-list", "List Cloud groups", func(cli *aliyun.SRegion, args *CloudgroupListOptions) error { - groups, err := cli.GetClient().ListGroups(args.Offset, args.Limit) - if err != nil { - return err - } - printList(groups.Groups.Group, 0, 0, 0, nil) - return nil - }) - - type CloudgroupDeleteOptions struct { - NAME string - } - - shellutils.R(&CloudgroupDeleteOptions{}, "cloud-group-delete", "Delete Cloud group", func(cli *aliyun.SRegion, args *CloudgroupDeleteOptions) error { - return cli.GetClient().DeleteGroup(args.NAME) - }) - - type GroupExtListOptions struct { - GROUP string - Offset string - Limit int - } - shellutils.R(&GroupExtListOptions{}, "cloud-group-user-list", "List Cloud group users", func(cli *aliyun.SRegion, args *GroupExtListOptions) error { - users, err := cli.GetClient().ListUsersForGroup(args.GROUP, args.Offset, args.Limit) - if err != nil { - return err - } - printList(users.Users.User, 0, 0, 0, nil) - return nil - }) - - type GroupUserOptions struct { - GROUP string - USER string - } - - shellutils.R(&GroupUserOptions{}, "cloud-group-remove-user", "Remove user from group", func(cli *aliyun.SRegion, args *GroupUserOptions) error { - return cli.GetClient().RemoveUserFromGroup(args.GROUP, args.USER) - }) - - shellutils.R(&GroupUserOptions{}, "cloud-group-add-user", "Add user to group", func(cli *aliyun.SRegion, args *GroupUserOptions) error { - return cli.GetClient().AddUserToGroup(args.GROUP, args.USER) - }) - - shellutils.R(&GroupExtListOptions{}, "cloud-group-policy-list", "List Cloud group policies", func(cli *aliyun.SRegion, args *GroupExtListOptions) error { - policies, err := cli.GetClient().ListPoliciesForGroup(args.GROUP) - if err != nil { - return err - } - printList(policies, 0, 0, 0, nil) - return nil - }) - - type GroupPolicyOptions struct { - GROUP string - PolicyType string `default:"System" choices:"System|Custom"` - POLICY string - } - - shellutils.R(&GroupPolicyOptions{}, "cloud-group-attach-policy", "Attach policy for group", func(cli *aliyun.SRegion, args *GroupPolicyOptions) error { - return cli.GetClient().AttachPolicyToGroup(args.PolicyType, args.POLICY, args.GROUP) - }) - - shellutils.R(&GroupPolicyOptions{}, "cloud-group-detach-policy", "Detach policy from group", func(cli *aliyun.SRegion, args *GroupPolicyOptions) error { - return cli.GetClient().DetachPolicyFromGroup(args.PolicyType, args.POLICY, args.GROUP) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/ram_policy.go b/pkg/multicloud/aliyun/shell/ram_policy.go deleted file mode 100644 index db07b83962..0000000000 --- a/pkg/multicloud/aliyun/shell/ram_policy.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type GetPolicyOptions struct { - POLICYTYPE string - POLICYNAME string - } - shellutils.R(&GetPolicyOptions{}, "cloud-policy-show", "Show ram policy", func(cli *aliyun.SRegion, args *GetPolicyOptions) error { - policy, err := cli.GetClient().GetPolicy(args.POLICYTYPE, args.POLICYNAME) - if err != nil { - return err - } - printObject(policy) - return nil - }) - - type DeletePolicyOptions struct { - POLICYTYPE string - POLICYNAME string - } - shellutils.R(&DeletePolicyOptions{}, "cloud-policy-delete", "Delete policy", func(cli *aliyun.SRegion, args *DeletePolicyOptions) error { - return cli.GetClient().DeletePolicy(args.POLICYTYPE, args.POLICYNAME) - }) - - type PolicyListOptions struct { - PolicyType string `choices:"System|Custom"` - Offset string - Limit int - } - - shellutils.R(&PolicyListOptions{}, "cloud-policy-list", "List cloud policies", func(cli *aliyun.SRegion, args *PolicyListOptions) error { - policies, err := cli.GetClient().ListPolicies(args.PolicyType, args.Offset, args.Limit) - if err != nil { - return err - } - printList(policies.Policies.Policy, 0, 0, 0, nil) - return nil - }) - - type PolicyCreateOptions struct { - NAME string - DOCUMENT string - Desc string - } - - shellutils.R(&PolicyCreateOptions{}, "cloud-policy-create", "Create ram policy", func(cli *aliyun.SRegion, args *PolicyCreateOptions) error { - policy, err := cli.GetClient().CreatePolicy(args.NAME, args.DOCUMENT, args.Desc) - if err != nil { - return err - } - printObject(policy) - return nil - }) - - type PolicyCreateVersionOptions struct { - NAME string - DOCUMENT string - IsDefault bool - } - - shellutils.R(&PolicyCreateVersionOptions{}, "cloud-policy-version-create", "Create ram policy version", func(cli *aliyun.SRegion, args *PolicyCreateVersionOptions) error { - return cli.GetClient().CreatePolicyVersion(args.NAME, args.DOCUMENT, args.IsDefault) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/ram_role.go b/pkg/multicloud/aliyun/shell/ram_role.go deleted file mode 100644 index 0edd26f1e0..0000000000 --- a/pkg/multicloud/aliyun/shell/ram_role.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ListRolesOptions struct { - Offset string - Limit int - } - shellutils.R(&ListRolesOptions{}, "cloud-role-list", "List ram roles", func(cli *aliyun.SRegion, args *ListRolesOptions) error { - roles, err := cli.GetClient().ListRoles(args.Offset, args.Limit) - if err != nil { - return err - } - printList(roles.Roles.Role, 0, 0, 0, []string{}) - return nil - }) - - type GetRoleOptions struct { - ROLENAME string - } - shellutils.R(&GetRoleOptions{}, "cloud-role-show", "Show ram role", func(cli *aliyun.SRegion, args *GetRoleOptions) error { - role, err := cli.GetClient().GetRole(args.ROLENAME) - if err != nil { - return err - } - printObject(role) - return nil - }) - - type RoleCreateOptions struct { - NAME string - DOCUMENT string - Desc string - } - - shellutils.R(&RoleCreateOptions{}, "cloud-role-create", "Create ram role", func(cli *aliyun.SRegion, args *RoleCreateOptions) error { - role, err := cli.GetClient().CreateRole(args.NAME, args.DOCUMENT, args.Desc) - if err != nil { - return err - } - printObject(role) - return nil - }) - - type RolePolicyOptions struct { - ROLENAME string - POLICYNAME string - POLICYTYPE string `choices:"Custom|System"` - } - - shellutils.R(&RolePolicyOptions{}, "cloud-role-attach-policy", "Attach policy for role", func(cli *aliyun.SRegion, args *RolePolicyOptions) error { - return cli.GetClient().AttachPolicy2Role(args.POLICYTYPE, args.POLICYNAME, args.ROLENAME) - }) - - shellutils.R(&RolePolicyOptions{}, "cloud-role-detach-policy", "Detach policy from role", func(cli *aliyun.SRegion, args *RolePolicyOptions) error { - return cli.GetClient().DetachPolicyFromRole(args.POLICYTYPE, args.POLICYNAME, args.ROLENAME) - }) - - type RolePolicyListOptions struct { - ROLE string - } - - shellutils.R(&RolePolicyListOptions{}, "cloud-role-policy-list", "List cloud role policies", func(cli *aliyun.SRegion, args *RolePolicyListOptions) error { - policies, err := cli.GetClient().ListPoliciesForRole(args.ROLE) - if err != nil { - return err - } - printList(policies, 0, 0, 0, nil) - return nil - }) - - type DeleteRoleOptions struct { - NAME string - } - shellutils.R(&DeleteRoleOptions{}, "cloud-role-delete", "Delete role", func(cli *aliyun.SRegion, args *DeleteRoleOptions) error { - return cli.GetClient().DeleteRole(args.NAME) - }) - - shellutils.R(&ListRolesOptions{}, "enable-image-import", "Enable image import privilege", func(cli *aliyun.SRegion, args *ListRolesOptions) error { - return cli.GetClient().EnableImageImport() - }) - - shellutils.R(&ListRolesOptions{}, "enable-image-export", "Enable image export privilege", func(cli *aliyun.SRegion, args *ListRolesOptions) error { - return cli.GetClient().EnableImageExport() - }) - - type CallerShowOptions struct { - } - - shellutils.R(&CallerShowOptions{}, "caller-show", "Show caller info", func(cli *aliyun.SRegion, args *CallerShowOptions) error { - caller, err := cli.GetClient().GetCallerIdentity() - if err != nil { - return err - } - printObject(caller) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/ram_user.go b/pkg/multicloud/aliyun/shell/ram_user.go deleted file mode 100644 index a82c54419b..0000000000 --- a/pkg/multicloud/aliyun/shell/ram_user.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClouduserCreateOptions struct { - NAME string - MobilePhone string - Comments string - Email string - } - - shellutils.R(&ClouduserCreateOptions{}, "cloud-user-create", "Create Cloud user", func(cli *aliyun.SRegion, args *ClouduserCreateOptions) error { - user, err := cli.GetClient().CreateUser(args.NAME, args.MobilePhone, args.Email, args.Comments) - if err != nil { - return err - } - printObject(user) - return nil - }) - - type ClouduserListOptions struct { - Offset string - Limit int - } - - shellutils.R(&ClouduserListOptions{}, "cloud-user-list", "List Cloud users", func(cli *aliyun.SRegion, args *ClouduserListOptions) error { - users, err := cli.GetClient().ListUsers(args.Offset, args.Limit) - if err != nil { - return err - } - printList(users.Users.User, 0, 0, 0, nil) - return nil - }) - - type UserPolicyListOptions struct { - USER string - } - - shellutils.R(&UserPolicyListOptions{}, "cloud-user-policy-list", "List Cloud user policies", func(cli *aliyun.SRegion, args *UserPolicyListOptions) error { - policies, err := cli.GetClient().ListPoliciesForUser(args.USER) - if err != nil { - return err - } - printList(policies, 0, 0, 0, nil) - return nil - }) - - type ClouduserOptions struct { - NAME string - } - - shellutils.R(&ClouduserOptions{}, "cloud-user-group-list", "List Cloud user groups", func(cli *aliyun.SRegion, args *ClouduserOptions) error { - groups, err := cli.GetClient().ListGroupsForUser(args.NAME) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&ClouduserOptions{}, "cloud-user-delete", "Delete Cloud user", func(cli *aliyun.SRegion, args *ClouduserOptions) error { - return cli.GetClient().DeleteClouduser(args.NAME) - }) - - shellutils.R(&ClouduserOptions{}, "cloud-user-loginprofile", "Get Cloud user loginprofile", func(cli *aliyun.SRegion, args *ClouduserOptions) error { - profile, err := cli.GetClient().GetLoginProfile(args.NAME) - if err != nil { - return err - } - printObject(profile) - return nil - }) - - shellutils.R(&ClouduserOptions{}, "cloud-user-loginprofile-delete", "Delete Cloud user loginprofile", func(cli *aliyun.SRegion, args *ClouduserOptions) error { - return cli.GetClient().DeleteLoginProfile(args.NAME) - }) - - type LoginProfileCreateOptions struct { - NAME string - PASSWORD string - } - - shellutils.R(&LoginProfileCreateOptions{}, "cloud-user-loginprofile-create", "Create Cloud user loginprofile", func(cli *aliyun.SRegion, args *LoginProfileCreateOptions) error { - profile, err := cli.GetClient().CreateLoginProfile(args.NAME, args.PASSWORD) - if err != nil { - return err - } - printObject(profile) - return nil - }) - - shellutils.R(&LoginProfileCreateOptions{}, "cloud-user-rest-password", "Reset Cloud user password", func(cli *aliyun.SRegion, args *LoginProfileCreateOptions) error { - return cli.GetClient().ResetClouduserPassword(args.NAME, args.PASSWORD) - }) - - type ClouduserPolicyOptions struct { - PolicyType string `default:"System" choices:"System|Custom"` - POLICY string - USER string - } - - shellutils.R(&ClouduserPolicyOptions{}, "cloud-user-attach-policy", "Attach policy for user", func(cli *aliyun.SRegion, args *ClouduserPolicyOptions) error { - return cli.GetClient().AttachPolicyToUser(args.POLICY, args.PolicyType, args.USER) - }) - - shellutils.R(&ClouduserPolicyOptions{}, "cloud-user-detach-policy", "Detach policy from user", func(cli *aliyun.SRegion, args *ClouduserPolicyOptions) error { - return cli.GetClient().DetachPolicyFromUser(args.POLICY, args.PolicyType, args.USER) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/region.go b/pkg/multicloud/aliyun/shell/region.go deleted file mode 100644 index 175ce8061f..0000000000 --- a/pkg/multicloud/aliyun/shell/region.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/multicloud/test" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - test.TestShell() - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *aliyun.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/resource_tag.go b/pkg/multicloud/aliyun/shell/resource_tag.go deleted file mode 100644 index ad206a0a6d..0000000000 --- a/pkg/multicloud/aliyun/shell/resource_tag.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "strings" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type TagGetOptions struct { - SERVICE string `help:"service, eg. ecs" choices:"ecs|kvs|rds|vpc|slb"` - RESTYPE string `help:"resource type, eg. instance"` - ID string `help:"resource Id, eg. ins-123xxx"` - } - shellutils.R(&TagGetOptions{}, "tag-list", "List tag of a specific resource", func(cli *aliyun.SRegion, args *TagGetOptions) error { - tags, err := cli.ListTags(args.SERVICE, args.RESTYPE, args.ID) - if err != nil { - return err - } - printObject(tags) - return nil - }) - - type TagOptions struct { - TagGetOptions - KEY string - VALUE string - } - shellutils.R(&TagOptions{}, "tag-resource", "set tags of a specific resource", func(cli *aliyun.SRegion, args *TagOptions) error { - return cli.TagResource(args.SERVICE, args.RESTYPE, args.ID, map[string]string{args.KEY: args.VALUE}) - }) - - type UnTagOptions struct { - TagGetOptions - KEY []string - } - - shellutils.R(&UnTagOptions{}, "untag-resource", "un tags of a specific resource", func(cli *aliyun.SRegion, args *UnTagOptions) error { - return cli.UntagResource(args.SERVICE, args.RESTYPE, args.ID, args.KEY) - }) - - type TagSetOptions struct { - TagGetOptions - VALUES []string - Replace bool - } - - shellutils.R(&TagSetOptions{}, "tag-set", "set tags of a specific resource", func(cli *aliyun.SRegion, args *TagSetOptions) error { - tags := map[string]string{} - for _, value := range args.VALUES { - v := strings.Split(value, ":") - if len(v) != 2 { - return errors.Errorf("invalid tag %s", value) - } - tags[v[0]] = v[1] - } - return cli.SetResourceTags(args.SERVICE, args.RESTYPE, args.ID, tags, args.Replace) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/resourcegroup.go b/pkg/multicloud/aliyun/shell/resourcegroup.go deleted file mode 100644 index 19ff91ea7c..0000000000 --- a/pkg/multicloud/aliyun/shell/resourcegroup.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ResourceGroupListOptions struct { - PageSize int - PageNumber int - } - shellutils.R(&ResourceGroupListOptions{}, "resource-group-list", "List resource group", func(cli *aliyun.SRegion, args *ResourceGroupListOptions) error { - groups, _, err := cli.GetClient().GetResourceGroups(args.PageNumber, args.PageSize) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - type ResourceGroupShowOptions struct { - ID string - } - - shellutils.R(&ResourceGroupShowOptions{}, "resource-group-show", "Show resource group", func(cli *aliyun.SRegion, args *ResourceGroupShowOptions) error { - group, err := cli.GetClient().GetResourceGroup(args.ID) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type ResourceGroupCreateOptions struct { - NAME string - } - - shellutils.R(&ResourceGroupCreateOptions{}, "resource-group-create", "Create resource group", func(cli *aliyun.SRegion, args *ResourceGroupCreateOptions) error { - group, err := cli.GetClient().CreateResourceGroup(args.NAME) - if err != nil { - return err - } - printObject(group) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/routetable.go b/pkg/multicloud/aliyun/shell/routetable.go deleted file mode 100644 index f3c5a29989..0000000000 --- a/pkg/multicloud/aliyun/shell/routetable.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RouteTableListOptions struct { - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&RouteTableListOptions{}, "routetable-list", "List routetables", func(cli *aliyun.SRegion, args *RouteTableListOptions) error { - routetables, total, e := cli.GetRouteTables(nil, args.Offset, args.Limit) - if e != nil { - return e - } - printList(routetables, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type RouteTableShowOptions struct { - ID string `help:"ID or name of routetable"` - } - shellutils.R(&RouteTableShowOptions{}, "routetable-show", "Show routetable", func(cli *aliyun.SRegion, args *RouteTableShowOptions) error { - routetables, _, e := cli.GetRouteTables([]string{args.ID}, 0, 1) - if e != nil { - return e - } - if len(routetables) == 0 { - return fmt.Errorf("No such ID %s", args.ID) - } - printObject(routetables[0]) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/saml_provider.go b/pkg/multicloud/aliyun/shell/saml_provider.go deleted file mode 100644 index d34a8d6bf6..0000000000 --- a/pkg/multicloud/aliyun/shell/saml_provider.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SamlProviderListOptions struct { - Marker string `help:"Marker"` - MaxItems int `help:"Max items"` - } - shellutils.R(&SamlProviderListOptions{}, "saml-provider-list", "List saml provider", func(cli *aliyun.SRegion, args *SamlProviderListOptions) error { - result, _, err := cli.GetClient().ListSAMLProviders(args.Marker, args.MaxItems) - if err != nil { - return err - } - printList(result, 0, 0, 0, []string{}) - return nil - }) - - type SamlProviderDeleteOptions struct { - NAME string `help:"SAML Provider Name"` - } - - shellutils.R(&SamlProviderDeleteOptions{}, "saml-provider-delete", "Delete saml provider", func(cli *aliyun.SRegion, args *SamlProviderDeleteOptions) error { - return cli.GetClient().DeleteSAMLProvider(args.NAME) - }) - - type SAMLProviderCreateOptions struct { - NAME string - METADAT string - Desc string - } - - shellutils.R(&SAMLProviderCreateOptions{}, "saml-provider-create", "Create saml provider", func(cli *aliyun.SRegion, args *SAMLProviderCreateOptions) error { - sp, err := cli.GetClient().CreateSAMLProvider(args.NAME, args.METADAT, args.Desc) - if err != nil { - return err - } - printObject(sp) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/secgroup.go b/pkg/multicloud/aliyun/shell/secgroup.go deleted file mode 100644 index 0b913eb714..0000000000 --- a/pkg/multicloud/aliyun/shell/secgroup.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - VpcId string `help:"VPC ID"` - Name string `help:"Secgroup Name"` - SecurityGroupIds []string `help:"SecurityGroup ids"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security group", func(cli *aliyun.SRegion, args *SecurityGroupListOptions) error { - secgrps, total, e := cli.GetSecurityGroups(args.VpcId, args.Name, args.SecurityGroupIds, args.Offset, args.Limit) - if e != nil { - return e - } - printList(secgrps, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type SecurityGroupIdOptions struct { - ID string `help:"ID or name of security group"` - } - shellutils.R(&SecurityGroupIdOptions{}, "security-group-show", "Show details of a security group", func(cli *aliyun.SRegion, args *SecurityGroupIdOptions) error { - secgrp, err := cli.GetSecurityGroupDetails(args.ID) - if err != nil { - return err - } - printObject(secgrp) - return nil - }) - - shellutils.R(&SecurityGroupIdOptions{}, "security-group-references", "Show references of a security group", func(cli *aliyun.SRegion, args *SecurityGroupIdOptions) error { - references, err := cli.DescribeSecurityGroupReferences(args.ID) - if err != nil { - return err - } - printList(references, 0, 0, 0, nil) - return nil - }) - - type SecurityGroupCreateOptions struct { - NAME string `help:"SecurityGroup name"` - VpcId string `help:"VPC ID"` - Desc string `help:"SecurityGroup description"` - } - - shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create details of a security group", func(cli *aliyun.SRegion, args *SecurityGroupCreateOptions) error { - secgroupId, err := cli.CreateSecurityGroup(args.VpcId, args.NAME, args.Desc) - if err != nil { - return err - } - fmt.Printf("secgroupId: %s", secgroupId) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/snapshot.go b/pkg/multicloud/aliyun/shell/snapshot.go deleted file mode 100644 index 33e84546e2..0000000000 --- a/pkg/multicloud/aliyun/shell/snapshot.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "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 *aliyun.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 *aliyun.SRegion, args *SnapshotDeleteOptions) error { - if err := cli.SnapshotPreDelete(args.ID); err != nil { - return fmt.Errorf("Snapshot PreDelete error: %s", err) - } - 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 *aliyun.SRegion, args *SnapshotCreateOptions) error { - snapshotId, err := cli.CreateSnapshot(args.DiskId, args.Name, args.Desc) - if err != nil { - return err - } - fmt.Println(snapshotId) - return nil - }) - -} diff --git a/pkg/multicloud/aliyun/shell/snapshot_policy.go b/pkg/multicloud/aliyun/shell/snapshot_policy.go deleted file mode 100644 index 501274658e..0000000000 --- a/pkg/multicloud/aliyun/shell/snapshot_policy.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SSnapshotPolicyListOptions struct { - PolicyId string `help:"snapshot policy id"` - Offset int `help:"offset"` - Limit int `help:"limit"` - } - - shellutils.R(&SSnapshotPolicyListOptions{}, "snapshot-policy-list", "list snapshot policy", - func(cli *aliyun.SRegion, args *SSnapshotPolicyListOptions) error { - snapshotPolicis, num, err := cli.GetSnapshotPolicies(args.PolicyId, args.Offset, args.Limit) - if err != nil { - return err - } - printList(snapshotPolicis, num, args.Offset, args.Limit, []string{}) - return nil - }, - ) - - type SSnapshotPolicyDeleteOptions struct { - ID string `help:"snapshot id"` - } - shellutils.R(&SSnapshotPolicyDeleteOptions{}, "snapshot-policy-delete", "delete snapshot policy", - func(cli *aliyun.SRegion, args *SSnapshotPolicyDeleteOptions) error { - err := cli.DeleteSnapshotPolicy(args.ID) - return err - }, - ) - - type SSnapshotPolicyCreateOptions struct { - Name string `help:"snapshot name"` - - RetentionDays int `help:"retention days"` - RepeatWeekdays []int `help:"auto snapshot which days of the week"` - TimePoints []int `help:"auto snapshot which hours of the day"` - } - shellutils.R(&SSnapshotPolicyCreateOptions{}, "snapshot-policy-create", "create snapshot policy", - func(cli *aliyun.SRegion, args *SSnapshotPolicyCreateOptions) error { - input := cloudprovider.SnapshotPolicyInput{ - RetentionDays: args.RetentionDays, - RepeatWeekdays: args.RepeatWeekdays, - TimePoints: args.TimePoints, - PolicyName: args.Name, - } - _, err := cli.CreateSnapshotPolicy(&input) - if err != nil { - return err - } - return nil - }, - ) - - type SSnapshotPolicyApplyOptions struct { - SNAPSHOTPOLICYID string `help:"snapshot policy id"` - DISKID string `help:"disk id"` - } - shellutils.R(&SSnapshotPolicyApplyOptions{}, "snapshot-policy-apply", "apply snapshot policy", - func(cli *aliyun.SRegion, args *SSnapshotPolicyApplyOptions) error { - err := cli.ApplySnapshotPolicyToDisks(args.SNAPSHOTPOLICYID, args.DISKID) - return err - }, - ) - - type SSnapshotPolicyCancelOptions struct { - SNAPSHOTPOLICYID string `help:"snapshot policy id"` - DISKID string `help:"disk id"` - } - shellutils.R(&SSnapshotPolicyCancelOptions{}, "snapshot-policy-cancel", "cancel snapshot policy", - func(cli *aliyun.SRegion, args *SSnapshotPolicyCancelOptions) error { - err := cli.CancelSnapshotPolicyToDisks(args.SNAPSHOTPOLICYID, args.DISKID) - return err - }, - ) -} diff --git a/pkg/multicloud/aliyun/shell/tablestore.go b/pkg/multicloud/aliyun/shell/tablestore.go deleted file mode 100644 index c8ce9f4fe9..0000000000 --- a/pkg/multicloud/aliyun/shell/tablestore.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type TableStoreListOptions struct { - PageSize int `help:"page size" default:"10"` - PageNumber int `help:"page number" default:"1"` - } - shellutils.R(&TableStoreListOptions{}, "tablestore-list", "List tablestores", func(cli *aliyun.SRegion, args *TableStoreListOptions) error { - ret, total, err := cli.GetTablestoreInstances(args.PageSize, args.PageNumber) - if err != nil { - return err - } - printList(ret, total, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/task.go b/pkg/multicloud/aliyun/shell/task.go deleted file mode 100644 index 6f81fef82c..0000000000 --- a/pkg/multicloud/aliyun/shell/task.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type TaskListOptions struct { - TYPE string `help:"Task types, either ImportImage or ExportImage" choices:"ImportImage|ExportImage"` - Task []string `help:"Task ID"` - Status string `help:"Task status" choices:"Finished|Processing|Waiting|Deleted|Paused|Failed"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&TaskListOptions{}, "task-list", "List tasks", func(cli *aliyun.SRegion, args *TaskListOptions) error { - tasks, total, err := cli.GetTasks(aliyun.TaskActionType(args.TYPE), args.Task, aliyun.TaskStatusType(args.Status), args.Offset, args.Limit) - if err != nil { - return err - } - printList(tasks, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type TaskIDOptions struct { - ID string `help:"Task ID"` - } - - shellutils.R(&TaskIDOptions{}, "task-show", "Show task", func(cli *aliyun.SRegion, args *TaskIDOptions) error { - task, err := cli.GetTask(args.ID) - if err != nil { - return err - } - printObject(task) - return nil - }) - - shellutils.R(&TaskIDOptions{}, "cancel-task", "Cancel task", func(cli *aliyun.SRegion, args *TaskIDOptions) error { - return cli.CancelTask(args.ID) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/vpc.go b/pkg/multicloud/aliyun/shell/vpc.go deleted file mode 100644 index 7931609a52..0000000000 --- a/pkg/multicloud/aliyun/shell/vpc.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "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 *aliyun.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 - }) - - type VpcCreateOptions struct { - Name string - Desc string - CIDR string - } - - shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *aliyun.SRegion, args *VpcCreateOptions) error { - opts := cloudprovider.VpcCreateOptions{ - NAME: args.Name, - CIDR: args.CIDR, - Desc: args.Desc, - } - vpc, err := cli.CreateIVpc(&opts) - if err != nil { - return err - } - printObject(vpc) - return nil - }) - - type VpcOptions struct { - ID string `help:"VPC id"` - } - - shellutils.R(&VpcOptions{}, "vpc-delete", "Delete vpc", func(cli *aliyun.SRegion, args *VpcOptions) error { - return cli.DeleteVpc(args.ID) - }) - - type VpcMoveResourceGroup struct { - ResourceType string `choices:"vpc|eip|bandwidthpackage" default:"vpc"` - ResourceGroupId string - ResourceId string - } - - shellutils.R(&VpcMoveResourceGroup{}, "vpc-mv-resource-group", "Delete vpc", func(cli *aliyun.SRegion, args *VpcMoveResourceGroup) error { - return cli.VpcMoveResourceGroup(args.ResourceType, args.ResourceGroupId, args.ResourceId) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/vrouter.go b/pkg/multicloud/aliyun/shell/vrouter.go deleted file mode 100644 index f0a2868557..0000000000 --- a/pkg/multicloud/aliyun/shell/vrouter.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VRouterListOptions struct { - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&VRouterListOptions{}, "vrouter-list", "List vrouters", func(cli *aliyun.SRegion, args *VRouterListOptions) error { - vrouters, total, e := cli.GetVRouters(args.Offset, args.Limit) - if e != nil { - return e - } - printList(vrouters, total, args.Offset, args.Limit, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/vswitch.go b/pkg/multicloud/aliyun/shell/vswitch.go deleted file mode 100644 index c3eff06fe7..0000000000 --- a/pkg/multicloud/aliyun/shell/vswitch.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "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 *aliyun.SRegion, args *VSwitchListOptions) error { - vswitches, total, e := cli.GetVSwitches(nil, "", args.Offset, args.Limit) - if e != nil { - return e - } - printList(vswitches, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type VSwitchShowOptions struct { - ID string `help:"show vswitch details"` - } - shellutils.R(&VSwitchShowOptions{}, "vswitch-show", "Show vswitch details", func(cli *aliyun.SRegion, args *VSwitchShowOptions) error { - vswitch, e := cli.GetVSwitchAttributes(args.ID) - if e != nil { - return e - } - printObject(vswitch) - return nil - }) - - shellutils.R(&VSwitchShowOptions{}, "vswitch-delete", "Show vswitch details", func(cli *aliyun.SRegion, args *VSwitchShowOptions) error { - e := cli.DeleteVSwitch(args.ID) - if e != nil { - return e - } - return nil - }) -} diff --git a/pkg/multicloud/aliyun/shell/waf.go b/pkg/multicloud/aliyun/shell/waf.go deleted file mode 100644 index 91a3da9f7d..0000000000 --- a/pkg/multicloud/aliyun/shell/waf.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type WafShowOptions struct { - } - shellutils.R(&WafShowOptions{}, "waf-instance-show", "Show waf instance", func(cli *aliyun.SRegion, args *WafShowOptions) error { - waf, err := cli.DescribeInstanceSpecInfo() - if err != nil { - return err - } - printObject(waf) - return nil - }) - - type WafIdOptions struct { - ID string - } - - shellutils.R(&WafIdOptions{}, "waf-instance-delete", "Delete waf instance", func(cli *aliyun.SRegion, args *WafIdOptions) error { - return cli.DeleteInstance(args.ID) - }) - - shellutils.R(&WafIdOptions{}, "waf-domain-list", "List waf instance domains", func(cli *aliyun.SRegion, args *WafIdOptions) error { - domains, err := cli.DescribeDomainNames(args.ID) - if err != nil { - return errors.Wrapf(err, "DescribeDomainNames") - } - fmt.Println("domains: ", domains) - return nil - }) - - type WafDomainIdOptions struct { - ID string - DOMAIN string - } - - shellutils.R(&WafDomainIdOptions{}, "waf-domain-show", "Show waf domain", func(cli *aliyun.SRegion, args *WafDomainIdOptions) error { - domain, err := cli.DescribeDomain(args.ID, args.DOMAIN) - if err != nil { - return err - } - printObject(domain) - return nil - }) - - shellutils.R(&WafDomainIdOptions{}, "waf-domain-delete", "Delete waf domain", func(cli *aliyun.SRegion, args *WafDomainIdOptions) error { - return cli.DeleteDomain(args.ID, args.DOMAIN) - }) - -} diff --git a/pkg/multicloud/aliyun/shell/zone.go b/pkg/multicloud/aliyun/shell/zone.go deleted file mode 100644 index 7d82351925..0000000000 --- a/pkg/multicloud/aliyun/shell/zone.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "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 *aliyun.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 - }) -} diff --git a/pkg/multicloud/aliyun/snapshot.go b/pkg/multicloud/aliyun/snapshot.go deleted file mode 100644 index f684e1a7b8..0000000000 --- a/pkg/multicloud/aliyun/snapshot.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SnapshotStatusType string - -const ( - SnapshotStatusAccomplished SnapshotStatusType = "accomplished" - SnapshotStatusProgress SnapshotStatusType = "progressing" - SnapshotStatusFailed SnapshotStatusType = "failed" - - SnapshotTypeSystem string = "System" - SnapshotTypeData string = "Data" -) - -type SSnapshot struct { - multicloud.SResourceBase - multicloud.AliyunTags - region *SRegion - - Progress string - SnapshotId string - SnapshotName string - SourceDiskId string - SourceDiskSize int32 - SourceDiskType string - Status SnapshotStatusType - Usage string - ResourceGroupId string -} - -func (self *SSnapshot) GetId() string { - return self.SnapshotId -} - -func (self *SSnapshot) GetName() string { - return self.SnapshotName -} - -func (self *SSnapshot) GetStatus() string { - if self.Status == SnapshotStatusAccomplished { - return api.SNAPSHOT_READY - } else if self.Status == SnapshotStatusProgress { - return api.SNAPSHOT_CREATING - } else { // if self.Status == SnapshotStatusFailed - return api.SNAPSHOT_FAILED - } -} - -func (self *SSnapshot) GetSizeMb() int32 { - return self.SourceDiskSize * 1024 -} - -func (self *SSnapshot) GetDiskId() string { - return self.SourceDiskId -} - -func (self *SSnapshot) GetDiskType() string { - if self.SourceDiskType == SnapshotTypeSystem { - return api.DISK_TYPE_SYS - } else if self.SourceDiskType == SnapshotTypeData { - return api.DISK_TYPE_DATA - } else { - return "" - } -} - -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) GetGlobalId() string { - return fmt.Sprintf("%s", self.SnapshotId) -} - -func (self *SSnapshot) IsEmulated() bool { - return false -} - -func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, total, err := self.GetSnapshots("", "", "", []string{}, 0, 50) - if err != nil { - return nil, err - } - for len(snapshots) < total { - var parts []SSnapshot - parts, total, err = self.GetSnapshots("", "", "", []string{}, len(snapshots), 50) - if err != nil { - return nil, err - } - snapshots = append(snapshots, parts...) - } - ret := make([]cloudprovider.ICloudSnapshot, len(snapshots)) - for i := 0; i < len(snapshots); i += 1 { - ret[i] = &snapshots[i] - } - return ret, nil -} - -func (self *SSnapshot) Delete() error { - if self.region == nil { - return fmt.Errorf("not init region for snapshot %s", self.SnapshotId) - } - if err := self.region.SnapshotPreDelete(self.SnapshotId); err != nil { - return err - } - return self.region.DeleteSnapshot(self.SnapshotId) -} - -func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - if len(instanceId) > 0 { - params["InstanceId"] = instanceId - } - if len(diskId) > 0 { - params["diskId"] = diskId - } - if len(snapshotName) > 0 { - params["SnapshotName"] = snapshotName - } - if snapshotIds != nil && len(snapshotIds) > 0 { - params["SnapshotIds"] = jsonutils.Marshal(snapshotIds).String() - } - - body, err := self.ecsRequest("DescribeSnapshots", params) - if err != nil { - log.Errorf("GetSnapshots fail %s", err) - return nil, 0, err - } - - snapshots := make([]SSnapshot, 0) - if err := body.Unmarshal(&snapshots, "Snapshots", "Snapshot"); err != nil { - log.Errorf("Unmarshal snapshot details fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - for i := 0; i < len(snapshots); i += 1 { - snapshots[i].region = self - } - return snapshots, int(total), nil -} - -func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) - if err != nil { - return nil, err - } - if total == 0 { - return nil, cloudprovider.ErrNotFound - } else if total > 1 { - return nil, cloudprovider.ErrDuplicateId - } - return &snapshots[0], nil -} - -func (self *SRegion) DeleteSnapshot(snapshotId string) error { - params := make(map[string]string) - params["SnapshotId"] = snapshotId - _, err := self.ecsRequest("DeleteSnapshot", params) - return err -} - -func (self *SSnapshot) GetProjectId() string { - return self.ResourceGroupId -} - -// If snapshot linked images can't be delete -// delete images first -- Aliyun -func (self *SRegion) SnapshotPreDelete(snapshotId string) error { - images, _, err := self.GetImagesBySnapshot(snapshotId, 0, 0) - if err != nil { - return fmt.Errorf("PreDelete get images by snapshot %s error: %s", snapshotId, err) - } - for _, image := range images { - image.storageCache = &SStoragecache{region: self} - if err := image.Delete(context.Background()); err != nil { - return fmt.Errorf("PreDelete image %s error: %s", image.GetId(), err) - } - if err := cloudprovider.WaitDeleted(&image, 3*time.Second, 300*time.Second); err != nil { - return fmt.Errorf("PreDelete waite image %s deleted error: %s", image.GetId(), err) - } - } - return nil -} diff --git a/pkg/multicloud/aliyun/snapshot_policy.go b/pkg/multicloud/aliyun/snapshot_policy.go deleted file mode 100644 index 1c79f99d9d..0000000000 --- a/pkg/multicloud/aliyun/snapshot_policy.go +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "sort" - "strconv" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSnapshotPolicyType string - -const ( - Creating SSnapshotPolicyType = "Creating" - Available SSnapshotPolicyType = "Available" - Normal SSnapshotPolicyType = "Normal" -) - -type SSnapshotPolicy struct { - multicloud.SResourceBase - multicloud.AliyunTags - region *SRegion - - AutoSnapshotPolicyName string - AutoSnapshotPolicyId string - RepeatWeekdays string - TimePoints string - RetentionDays int - Status SSnapshotPolicyType -} - -func (self *SSnapshotPolicy) GetId() string { - return self.AutoSnapshotPolicyId -} - -func (self *SSnapshotPolicy) GetName() string { - return self.AutoSnapshotPolicyName -} - -func (self *SSnapshotPolicy) GetStatus() string { - // XXX: aliyun文档与实际返回值不符 - if self.Status == Normal || self.Status == Available { - return api.SNAPSHOT_POLICY_READY - } else if self.Status == Creating { - return api.SNAPSHOT_POLICY_CREATING - } else { - return api.SNAPSHOT_POLICY_UNKNOWN - } -} - -func (self *SSnapshotPolicy) Refresh() error { - if snapshotPolicies, total, err := self.region.GetSnapshotPolicies(self.AutoSnapshotPolicyId, 0, 1); err != nil { - return err - } else if total != 1 { - return cloudprovider.ErrNotFound - } else if err := jsonutils.Update(self, snapshotPolicies[0]); err != nil { - return err - } - return nil -} - -func (self *SSnapshotPolicy) IsEmulated() bool { - return false -} - -func (self *SSnapshotPolicy) GetGlobalId() string { - return self.AutoSnapshotPolicyId -} - -func (self *SSnapshotPolicy) GetProjectId() string { - return "" -} - -func (self *SSnapshotPolicy) GetRetentionDays() int { - return self.RetentionDays -} - -func sliceAtoi(sa []string) ([]int, error) { - si := make([]int, 0, len(sa)) - for _, a := range sa { - i, err := strconv.Atoi(a) - if err != nil { - return si, err - } - si = append(si, i) - } - return si, nil -} - -func stringToIntDays(days []string) ([]int, error) { - idays, err := sliceAtoi(days) - if err != nil { - return nil, err - } - sort.Ints(idays) - return idays, nil -} - -func parsePolicy(policy string) ([]int, error) { - tp, err := jsonutils.ParseString(policy) - if err != nil { - return nil, fmt.Errorf("Parse policy %s error %s", policy, err) - } - atp, ok := tp.(*jsonutils.JSONArray) - if !ok { - return nil, fmt.Errorf("Policy %s Wrong format", tp) - } - return stringToIntDays(atp.GetStringArray()) -} - -func (self *SSnapshotPolicy) GetRepeatWeekdays() ([]int, error) { - return parsePolicy(self.RepeatWeekdays) -} - -func (self *SSnapshotPolicy) GetTimePoints() ([]int, error) { - return parsePolicy(self.TimePoints) -} - -func (self *SSnapshotPolicy) IsActivated() bool { - return true -} - -func (self *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { - snapshotPolicies, total, err := self.GetSnapshotPolicies("", 0, 50) - if err != nil { - return nil, err - } - for len(snapshotPolicies) < total { - var parts []SSnapshotPolicy - parts, total, err = self.GetSnapshotPolicies("", len(snapshotPolicies), 50) - if err != nil { - return nil, err - } - snapshotPolicies = append(snapshotPolicies, parts...) - } - ret := make([]cloudprovider.ICloudSnapshotPolicy, len(snapshotPolicies)) - for i := 0; i < len(snapshotPolicies); i += 1 { - ret[i] = &snapshotPolicies[i] - } - return ret, nil -} - -func (self *SRegion) GetSnapshotPolicies(policyId string, offset int, limit int) ([]SSnapshotPolicy, int, error) { - params := make(map[string]string) - - params["RegionId"] = self.RegionId - if limit != 0 { - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - } - - if len(policyId) > 0 { - params["AutoSnapshotPolicyId"] = policyId - } - - body, err := self.ecsRequest("DescribeAutoSnapshotPolicyEx", params) - if err != nil { - return nil, 0, fmt.Errorf("GetSnapshotPolicys fail %s", err) - } - - snapshotPolicies := make([]SSnapshotPolicy, 0) - if err := body.Unmarshal(&snapshotPolicies, "AutoSnapshotPolicies", "AutoSnapshotPolicy"); err != nil { - return nil, 0, fmt.Errorf("Unmarshal snapshot policies details fail %s", err) - } - total, _ := body.Int("TotalCount") - for i := 0; i < len(snapshotPolicies); i += 1 { - snapshotPolicies[i].region = self - } - return snapshotPolicies, int(total), nil -} - -func (self *SSnapshotPolicy) Delete() error { - if self.region == nil { - return fmt.Errorf("Not init region for snapshotPolicy %s", self.AutoSnapshotPolicyId) - } - return self.region.DeleteSnapshotPolicy(self.AutoSnapshotPolicyId) -} - -func (self *SRegion) DeleteSnapshotPolicy(snapshotPolicyId string) error { - params := make(map[string]string) - params["autoSnapshotPolicyId"] = snapshotPolicyId - params["regionId"] = self.RegionId - _, err := self.ecsRequest("DeleteAutoSnapshotPolicy", params) - return err -} - -func (self *SRegion) GetISnapshotPolicyById(snapshotPolicyId string) (cloudprovider.ICloudSnapshotPolicy, error) { - policies, _, err := self.GetSnapshotPolicies(snapshotPolicyId, 0, 1) - if err != nil { - return nil, err - } - if len(policies) == 0 { - return nil, cloudprovider.ErrNotFound - } - return &policies[0], nil -} - -func (self *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput) (string, error) { - if input.RepeatWeekdays == nil { - return "", fmt.Errorf("Can't create snapshot policy with nil repeatWeekdays") - } - if input.TimePoints == nil { - return "", fmt.Errorf("Can't create snapshot policy with nil timePoints") - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["repeatWeekdays"] = jsonutils.Marshal(input.GetStringArrayRepeatWeekdays()).String() - params["timePoints"] = jsonutils.Marshal(input.GetStringArrayTimePoints()).String() - params["retentionDays"] = strconv.Itoa(input.RetentionDays) - params["autoSnapshotPolicyName"] = input.PolicyName - if body, err := self.ecsRequest("CreateAutoSnapshotPolicy", params); err != nil { - return "", fmt.Errorf("CreateAutoSnapshotPolicy fail %s", err) - } else { - return body.GetString("AutoSnapshotPolicyId") - } -} - -func (self *SRegion) UpdateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput, snapshotPolicyId string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - if input.RetentionDays != 0 { - params["retentionDays"] = strconv.Itoa(input.RetentionDays) - } - if input.RepeatWeekdays != nil && len(input.RepeatWeekdays) != 0 { - params["repeatWeekdays"] = jsonutils.Marshal(input.GetStringArrayRepeatWeekdays()).String() - } - if input.TimePoints != nil && len(input.TimePoints) != 0 { - params["timePoints"] = jsonutils.Marshal(input.GetStringArrayTimePoints()).String() - } - _, err := self.ecsRequest("ModifyAutoSnapshotPolicyEx", params) - if err != nil { - return fmt.Errorf("ModifyAutoSnapshotPolicyEx Fail %s", err) - } - return nil -} - -//func (self *SRegion) UpdateSnapshotPolicy( -// snapshotPolicyId string, retentionDays *int, -// repeatWeekdays, timePoints *jsonutils.JSONArray, policyName string, -//) error { -// params := make(map[string]string) -// params["RegionId"] = self.RegionId -// if len(policyName) > 0 { -// params["autoSnapshotPolicyName"] = policyName -// } -// if retentionDays != nil { -// params["retentionDays"] = strconv.Itoa(*retentionDays) -// } -// if repeatWeekdays != nil { -// params["repeatWeekdays"] = repeatWeekdays.String() -// } -// if timePoints != nil { -// params["timePoints"] = timePoints.String() -// } -// _, err := self.ecsRequest("ModifyAutoSnapshotPolicyEx", params) -// if err != nil { -// return fmt.Errorf("ModifyAutoSnapshotPolicyEx Fail %s", err) -// } -// return nil -//} - -func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["autoSnapshotPolicyId"] = snapshotPolicyId - diskIds := []string{diskId} - params["diskIds"] = jsonutils.Marshal(diskIds).String() - _, err := self.ecsRequest("ApplyAutoSnapshotPolicy", params) - if err != nil { - return fmt.Errorf("ApplyAutoSnapshotPolicy Fail %s", err) - } - return nil -} - -func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - diskIds := []string{diskId} - params["diskIds"] = jsonutils.Marshal(diskIds).String() - _, err := self.ecsRequest("CancelAutoSnapshotPolicy", params) - if err != nil { - return fmt.Errorf("CancelAutoSnapshotPolicy Fail %s", err) - } - return nil -} diff --git a/pkg/multicloud/aliyun/storage.go b/pkg/multicloud/aliyun/storage.go deleted file mode 100644 index ab7de429ec..0000000000 --- a/pkg/multicloud/aliyun/storage.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright 2019 Yunion -// -// 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. - -// -// 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 aliyun - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - multicloud.SStorageBase - multicloud.AliyunTags - zone *SZone - storageType string -} - -func (self *SStorage) GetId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetName() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetGlobalId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) -} - -func (self *SStorage) IsEmulated() bool { - return true -} - -func (self *SStorage) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks := make([]SDisk, 0) - offset := 0 - storageType := self.storageType - if self.storageType == api.STORAGE_CLOUD_ESSD_PL2 || self.storageType == api.STORAGE_CLOUD_ESSD_PL3 { - storageType = api.STORAGE_CLOUD_ESSD - } - for { - parts, total, err := self.zone.region.GetDisks("", self.zone.GetId(), storageType, nil, offset, 50) - if err != nil { - return nil, errors.Wrapf(err, "GetDisks") - } - performanceLevel := "" - switch self.storageType { - case api.STORAGE_CLOUD_ESSD: - performanceLevel = "PL1" - case api.STORAGE_CLOUD_ESSD_PL2: - performanceLevel = "PL2" - case api.STORAGE_CLOUD_ESSD_PL3: - performanceLevel = "PL3" - } - for _, disk := range parts { - if disk.PerformanceLevel == performanceLevel { - disks = append(disks, disk) - } - } - - offset += len(parts) - - if offset >= 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 models.STORAGE_PUBLIC_CLOUD - return self.storageType -} - -func (self *SStorage) GetMediumType() string { - if strings.Contains(self.storageType, "_ssd") { - return api.DISK_TYPE_SSD - } else { - return api.DISK_TYPE_ROTATE - } -} - -func (self *SStorage) GetCapacityMB() int64 { - return 0 // unlimited -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - conf := jsonutils.NewDict() - return conf -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) Refresh() error { - // do nothing - return nil -} - -func (self *SStorage) GetEnabled() bool { - if utils.IsInStringArray(self.storageType, LOCAL_STORAGES) { - return false - } - return true -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.zone.region.getStoragecache() -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - diskId, err := self.zone.region.CreateDisk(self.zone.ZoneId, self.storageType, conf.Name, conf.SizeGb, conf.Desc, conf.ProjectId) - 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) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - disk, err := self.zone.region.getDisk(idStr) - if err != nil { - return nil, err - } - disk.storage = self - return disk, nil -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - if utils.IsInStringArray(self.storageType, self.zone.getSysDiskCategories()) { - return true - } - return false -} diff --git a/pkg/multicloud/aliyun/storagecache.go b/pkg/multicloud/aliyun/storagecache.go deleted file mode 100644 index d70a766cde..0000000000 --- a/pkg/multicloud/aliyun/storagecache.go +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "context" - "fmt" - "io/ioutil" - "os" - "strings" - "time" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "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" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.AliyunTags - region *SRegion -} - -func (self *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) -} - -func (self *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) -} - -func (self *SStoragecache) GetStatus() string { - return "available" -} - -func (self *SStoragecache) Refresh() error { - return nil -} - -func (self *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetGlobalId()) -} - -func (self *SStoragecache) IsEmulated() bool { - return false -} - -func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - images := make([]SImage, 0) - for { - parts, total, err := self.region.GetImages(ImageStatusType(""), ImageOwnerSelf, nil, "", len(images), 50) - if err != nil { - return nil, errors.Wrapf(err, "GetImages") - } - images = append(images, parts...) - if len(images) >= total { - break - } - } - ret := []cloudprovider.ICloudImage{} - for i := range images { - images[i].storageCache = self - ret = append(ret, &images[i]) - } - return ret, nil -} - -func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - img, err := self.region.GetImage(extId) - if err != nil { - return nil, err - } - img.storageCache = self - return img, nil -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { - if len(image.ExternalId) > 0 { - status, err := self.region.GetImageStatus(image.ExternalId) - if err != nil { - log.Errorf("GetImageStatus error %s", err) - } - // 不能直接删除 ImageStatusCreating 状态的image ,需要先取消importImage Task - if status == ImageStatusCreating { - err := self.region.CancelImageImportTasks() - if err != nil { - log.Errorln(err) - } - } - } - return self.uploadImage(ctx, userCred, image, callback) -} - -func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { - // first upload image to oss - s := auth.GetAdminSession(ctx, options.Options.Region) - - meta, reader, sizeByte, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false) - if err != nil { - return "", err - } - log.Infof("meta data %s", meta) - - bucketName := strings.ToLower(fmt.Sprintf("imgcache-%s-%s", self.region.GetId(), image.ImageId)) - exist, err := self.region.IBucketExist(bucketName) - if err != nil { - return "", errors.Wrapf(err, "IBucketExist(%s)", bucketName) - } - if !exist { - log.Debugf("Bucket %s not exists, to create ...", bucketName) - err = self.region.CreateIBucket(bucketName, "", "") - if err != nil { - return "", errors.Wrapf(err, "CreateIBucket %s", bucketName) - } - } else { - log.Debugf("Bucket %s exists", bucketName) - } - - defer self.region.DeleteIBucket(bucketName) // remove bucket - - bucket, err := self.region.GetIBucketByName(bucketName) - if err != nil { - return "", errors.Wrapf(err, "GetIBucketByName %s", bucketName) - } - log.Debugf("To upload image to bucket %s ...", bucketName) - body := multicloud.NewProgress(sizeByte, 80, reader, callback) - err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeByte, "", "", nil, false) - if err != nil { - return "", errors.Wrapf(err, "UploadObject %s", image.ImageId) - } - - defer bucket.DeleteObject(context.Background(), image.ImageId) // remove object - - imageBaseName := image.ImageId - if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { - imageBaseName = fmt.Sprintf("img%s", image.ImageId) - } - imageName := imageBaseName - nameIdx := 1 - - // check image name, avoid name conflict - for { - _, err = self.region.GetImageByName(imageName) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - break - } else { - return "", err - } - } - imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) - nameIdx += 1 - } - - log.Debugf("Import image %s", imageName) - - // ensure privileges - err = self.region.GetClient().EnableImageImport() - if err != nil { - return "", errors.Wrapf(err, "EnableImageImport") - } - - task, err := self.region.ImportImage(imageName, image.OsArch, image.OsType, image.OsDistribution, bucketName, image.ImageId) - - if err != nil { - return "", errors.Wrapf(err, "ImportImage %s %s", image.ImageId, bucketName) - } - - // timeout: 1hour = 3600 seconds - err = self.region.WaitTaskStatus(ImportImageTask, task.TaskId, TaskStatusFinished, 15*time.Second, 3600*time.Second, 80, 100, callback) - if err != nil { - return task.ImageId, errors.Wrapf(err, "waitTaskStatus") - } - - return task.ImageId, nil -} - -func (self *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - if imageId, err := self.region.createIImage(snapshoutId, 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 - if err := cloudprovider.WaitStatus(iimage[0], cloudprovider.IMAGE_STATUS_ACTIVE, 15*time.Second, 3600*time.Second); err != nil { - return nil, err - } - return iimage[0], nil - } -} - -func (self *SRegion) CheckBucket(bucketName string) (*oss.Bucket, error) { - return self.checkBucket(bucketName) -} - -func (self *SRegion) checkBucket(bucketName string) (*oss.Bucket, error) { - oss, err := self.GetOssClient() - if err != nil { - log.Errorf("GetOssClient err %s", err) - return nil, err - } - if exist, err := oss.IsBucketExist(bucketName); err != nil { - log.Errorf("IsBucketExist err %s", err) - return nil, err - } else if !exist { - log.Debugf("Bucket %s not exists, to create ...", bucketName) - if err := oss.CreateBucket(bucketName); err != nil { - log.Errorf("Create bucket error %s", err) - return nil, err - } - } - log.Debugf("Bucket %s exists", bucketName) - if bucket, err := oss.Bucket(bucketName); err != nil { - log.Errorf("Bucket error %s %s", bucketName, err) - return nil, err - } else { - return bucket, nil - } -} - -func (self *SRegion) CreateImage(snapshoutId, imageName, imageDesc string) (string, error) { - return self.createIImage(snapshoutId, imageName, imageDesc) -} - -func (self *SRegion) createIImage(snapshoutId, imageName, imageDesc string) (string, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["OssBucket"] = strings.ToLower(fmt.Sprintf("imgcache-%s", self.GetId())) - params["SnapshotId"] = snapshoutId - params["ImageName"] = imageName - params["Description"] = imageDesc - - if _, err := self.checkBucket(params["OssBucket"]); err != nil { - return "", err - } - - if body, err := self.ecsRequest("CreateImage", params); err != nil { - log.Errorf("CreateImage fail %s", err) - return "", err - } else { - log.Infof("%s", body) - return body.GetString("ImageId") - } -} - -func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return self.downloadImage(userCred, imageId, extId, path) -} - -// 定义进度条监听器。 -type OssProgressListener struct { -} - -// 定义进度变更事件处理函数。 -func (listener *OssProgressListener) ProgressChanged(event *oss.ProgressEvent) { - switch event.EventType { - case oss.TransferStartedEvent: - log.Debugf("Transfer Started, ConsumedBytes: %d, TotalBytes %d.\n", - event.ConsumedBytes, event.TotalBytes) - case oss.TransferDataEvent: - log.Debugf("\rTransfer Data, ConsumedBytes: %d, TotalBytes %d, %d%%.", - event.ConsumedBytes, event.TotalBytes, event.ConsumedBytes*100/event.TotalBytes) - case oss.TransferCompletedEvent: - log.Debugf("\nTransfer Completed, ConsumedBytes: %d, TotalBytes %d.\n", - event.ConsumedBytes, event.TotalBytes) - case oss.TransferFailedEvent: - log.Debugf("\nTransfer Failed, ConsumedBytes: %d, TotalBytes %d.\n", - event.ConsumedBytes, event.TotalBytes) - default: - } -} - -func (self *SStoragecache) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - err := self.region.GetClient().EnableImageExport() - if err != nil { - log.Errorf("fail to enable export privileges: %s", err) - return nil, err - } - - tmpImageFile, err := ioutil.TempFile(path, extId) - if err != nil { - return nil, err - } - defer tmpImageFile.Close() - defer os.Remove(tmpImageFile.Name()) - bucketName := strings.ToLower(fmt.Sprintf("imgcache-%s", self.region.GetId())) - if bucket, err := self.region.checkBucket(bucketName); err != nil { - return nil, err - } else if _, err := self.region.GetImage(extId); err != nil { - return nil, err - } else if task, err := self.region.ExportImage(extId, bucket); err != nil { - return nil, err - } else if err := self.region.waitTaskStatus(ExportImageTask, task.TaskId, TaskStatusFinished, 15*time.Second, 3600*time.Second); err != nil { - return nil, err - } else if imageList, err := bucket.ListObjects(oss.Prefix(fmt.Sprintf("%sexport", strings.Replace(extId, "-", "", -1)))); err != nil { - return nil, err - } else if len(imageList.Objects) != 1 { - return nil, fmt.Errorf("exported image not find") - } else if err := bucket.DownloadFile(imageList.Objects[0].Key, tmpImageFile.Name(), 12*1024*1024, oss.Routines(3), oss.Progress(&OssProgressListener{})); err != nil { - return nil, err - } else { - s := auth.GetAdminSession(context.Background(), options.Options.Region) - params := jsonutils.Marshal(map[string]string{"image_id": imageId, "disk-format": "raw"}) - if result, err := modules.Images.Upload(s, params, tmpImageFile, imageList.Objects[0].Size); err != nil { - return nil, err - } else { - return result, nil - } - } -} - -func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storageCache := region.getStoragecache() - return []cloudprovider.ICloudStoragecache{storageCache}, nil -} - -func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - storageCache := region.getStoragecache() - if id == storageCache.GetGlobalId() { - return storageCache, nil - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/aliyun/tablestore.go b/pkg/multicloud/aliyun/tablestore.go deleted file mode 100644 index 9c13fd9d0f..0000000000 --- a/pkg/multicloud/aliyun/tablestore.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -func (self *SAliyunClient) otsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - cli, err := self.getDefaultClient() - if err != nil { - return nil, err - } - regionId, _ := params["RegionId"] - params = self.SetResourceGropuId(params) - return jsonRequest(cli, fmt.Sprintf("ots.%s.aliyuncs.com", regionId), ALIYUN_OTS_API_VERSION, apiName, params, self.debug) -} - -func (self *SRegion) otsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["RegionId"] = self.RegionId - return self.client.otsRequest(apiName, params) -} - -type STablestore struct { - multicloud.SResourceBase - multicloud.AliyunTags - region *SRegion - - InstanceName string - Timestamp time.Time -} - -func (self *STablestore) GetGlobalId() string { - return self.InstanceName -} - -func (self *STablestore) GetName() string { - return self.InstanceName -} - -func (self *STablestore) GetId() string { - return self.InstanceName -} - -func (self *STablestore) GetStatus() string { - return api.TABLESTORE_STATUS_RUNNING -} - -func (self *STablestore) GetProjectId() string { - return "" -} - -func (self *SRegion) GetTablestoreInstances(pageSize, pageNumber int) ([]STablestore, int, error) { - params := map[string]string{ - "RegionId": self.RegionId, - "PageSize": fmt.Sprintf("%d", pageSize), - "PageNumber": fmt.Sprintf("%d", pageNumber), - } - resp, err := self.otsRequest("ListInstance", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "ListInstance") - } - total, _ := resp.Int("TotalCount") - ret := []STablestore{} - return ret, int(total), resp.Unmarshal(&ret, "InstanceInfos", "InstanceInfo") -} - -func (self *SRegion) GetICloudTablestores() ([]cloudprovider.ICloudTablestore, error) { - ots, pageNumber := []STablestore{}, 1 - for { - part, total, err := self.GetTablestoreInstances(50, pageNumber) - if err != nil { - return nil, err - } - ots = append(ots, part...) - if len(ots) >= total { - break - } - pageNumber++ - } - ret := []cloudprovider.ICloudTablestore{} - for i := range ots { - ots[i].region = self - ret = append(ret, &ots[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/aliyun/vpc.go b/pkg/multicloud/aliyun/vpc.go deleted file mode 100644 index 48457e0bf3..0000000000 --- a/pkg/multicloud/aliyun/vpc.go +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - VpcAvailable = "Available" - VpcPending = "Pending" -) - -// "CidrBlock":"172.31.0.0/16","CreationTime":"2017-03-19T13:37:40Z","Description":"System created default VPC.","IsDefault":true,"RegionId":"cn-hongkong","Status":"Available","UserCidrs":{"UserCidr":[]},"VRouterId":"vrt-j6c00qrol733dg36iq4qj","VSwitchIds":{"VSwitchId":["vsw-j6c3gig5ub4fmi2veyrus"]},"VpcId":"vpc-j6c86z3sh8ufhgsxwme0q","VpcName":"" - -type SUserCIDRs struct { - UserCidr []string -} - -type SVSwitchIds struct { - VSwitchId []string -} - -type SVpc struct { - multicloud.SVpc - multicloud.AliyunTags - - region *SRegion - - iwires []cloudprovider.ICloudWire - - secgroups []cloudprovider.ICloudSecurityGroup - routeTables []cloudprovider.ICloudRouteTable - - CidrBlock string - CreationTime time.Time - Description string - IsDefault bool - RegionId string - Status string - UserCidrs SUserCIDRs - VRouterId string - VSwitchIds SVSwitchIds - VpcId string - VpcName string -} - -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) IsEmulated() bool { - return false -} - -func (self *SVpc) GetIsDefault() bool { - return self.IsDefault -} - -func (self *SVpc) GetCidrBlock() string { - return self.CidrBlock -} - -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) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -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) 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 - } - } - return nil -} - -func (self *SVpc) fetchVSwitches() error { - switches, total, err := self.region.GetVSwitches(nil, self.VpcId, 0, 50) - if err != nil { - return err - } - if total > len(switches) { - switches, _, err = self.region.GetVSwitches(nil, self.VpcId, 0, total) - if err != nil { - return err - } - } - for i := 0; i < len(switches); i += 1 { - wire := self.getWireByZoneId(switches[i].ZoneId) - if wire != nil { - switches[i].wire = wire - wire.addNetwork(&switches[i]) - } - } - return nil -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - if self.iwires == nil { - err := self.fetchVSwitches() - if err != nil { - return nil, err - } - } - return self.iwires, nil -} - -func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { - if self.iwires == nil { - err := self.fetchVSwitches() - 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) fetchSecurityGroups() error { - secgroups := make([]SSecurityGroup, 0) - for { - parts, total, err := self.region.GetSecurityGroups(self.VpcId, "", []string{}, len(secgroups), 50) - if err != nil { - return err - } - secgroups = append(secgroups, parts...) - if len(secgroups) >= total { - break - } - } - 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 *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) fetchRouteTables() error { - routeTables := make([]*SRouteTable, 0) - for { - parts, total, err := self.RemoteGetRouteTableList(len(routeTables), 50) - if err != nil { - return err - } - routeTables = append(routeTables, parts...) - if len(routeTables) >= total { - break - } - } - self.routeTables = make([]cloudprovider.ICloudRouteTable, len(routeTables)) - for i := 0; i < len(routeTables); i++ { - routeTables[i].vpc = self - self.routeTables[i] = routeTables[i] - } - return nil -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - if self.routeTables == nil { - err := self.fetchRouteTables() - if err != nil { - return nil, err - } - } - return self.routeTables, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - tables, err := self.GetIRouteTables() - if err != nil { - return nil, errors.Wrapf(err, "GetIRouteTables") - } - for i := range tables { - if tables[i].GetGlobalId() == routeTableId { - return tables[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, routeTableId) -} - -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) getNatGateways() ([]SNatGateway, error) { - natgatways := make([]SNatGateway, 0) - gwTotal := -1 - for gwTotal < 0 || len(natgatways) < gwTotal { - parts, total, err := self.region.GetNatGateways(self.VpcId, "", len(natgatways), 50) - if err != nil { - return nil, err - } - if len(parts) > 0 { - natgatways = append(natgatways, parts...) - } - gwTotal = total - } - for i := 0; i < len(natgatways); i += 1 { - natgatways[i].vpc = self - } - return natgatways, nil -} - -func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { - nats := []SNatGateway{} - for { - parts, total, err := self.region.GetNatGateways(self.VpcId, "", len(nats), 50) - if err != nil { - return nil, err - } - nats = append(nats, parts...) - if len(nats) >= total { - break - } - } - inats := []cloudprovider.ICloudNatGateway{} - for i := 0; i < len(nats); i++ { - nats[i].vpc = self - inats = append(inats, &nats[i]) - } - return inats, nil -} - -func (self *SVpc) GetAuthorityOwnerId() string { - return self.region.client.ownerId -} - -func (self *SRegion) GrantInstanceToCen(opts *cloudprovider.SVpcJointInterVpcNetworkOption, instance SCenAttachInstanceInput) error { - params := make(map[string]string) - params["CenId"] = opts.InterVpcNetworkId - params["CenOwnerId"] = opts.NetworkAuthorityOwnerId - - params["InstanceId"] = instance.InstanceId - params["InstanceType"] = instance.InstanceType - params["RegionId"] = instance.InstanceRegion - _, err := self.vpcRequest("GrantInstanceToCen", params) - if err != nil { - return errors.Wrapf(err, `self.vpcRequest("GrantInstanceToCen", %s)`, jsonutils.Marshal(params).String()) - } - return nil -} - -func (self *SVpc) ProposeJoinICloudInterVpcNetwork(opts *cloudprovider.SVpcJointInterVpcNetworkOption) error { - instance := SCenAttachInstanceInput{ - InstanceType: "VPC", - InstanceId: self.GetId(), - InstanceRegion: self.region.GetId(), - } - err := self.region.GrantInstanceToCen(opts, instance) - if err != nil { - return errors.Wrapf(err, "self.region.GrantInstanceToCen(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) - } - return nil -} diff --git a/pkg/multicloud/aliyun/vswitch.go b/pkg/multicloud/aliyun/vswitch.go deleted file mode 100644 index f31adda958..0000000000 --- a/pkg/multicloud/aliyun/vswitch.go +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/util/netutils" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -// {"AvailableIpAddressCount":4091,"CidrBlock":"172.31.32.0/20","CreationTime":"2017-03-19T13:37:44Z","Description":"System created default virtual switch.","IsDefault":true,"Status":"Available","VSwitchId":"vsw-j6c3gig5ub4fmi2veyrus","VSwitchName":"","VpcId":"vpc-j6c86z3sh8ufhgsxwme0q","ZoneId":"cn-hongkong-b"} - -const ( - VSwitchPending = "Pending" - VSwitchAvailable = "Available" -) - -type SCloudResources struct { - CloudResourceSetType []string -} - -type SVSwitch struct { - multicloud.SResourceBase - multicloud.AliyunTags - wire *SWire - - AvailableIpAddressCount int - - CidrBlock string - Ipv6CidrBlock string - CreationTime time.Time - Description string - IsDefault bool - Status string - VSwitchId string - VSwitchName string - VpcId string - ZoneId string - - CloudResources SCloudResources - ResourceGroupId string - RouteTable SRouteTable -} - -func (self *SVSwitch) GetId() string { - return self.VSwitchId -} - -func (self *SVSwitch) GetName() string { - if len(self.VSwitchName) > 0 { - return self.VSwitchName - } - return self.VSwitchId -} - -func (self *SVSwitch) GetGlobalId() string { - return self.VSwitchId -} - -func (self *SVSwitch) IsEmulated() bool { - return false -} - -func (self *SVSwitch) GetStatus() string { - return strings.ToLower(self.Status) -} - -func (self *SVSwitch) Refresh() error { - log.Debugf("vsiwtch refresh %s", self.VSwitchId) - new, err := self.wire.zone.region.GetVSwitchAttributes(self.VSwitchId) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SVSwitch) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SVSwitch) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - return startIp.String() -} - -func (self *SVSwitch) 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 *SVSwitch) GetIpMask() int8 { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - return pref.MaskLen -} - -func (self *SVSwitch) GetGateway() string { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 - endIp = endIp.StepDown() // 254 - return endIp.String() -} - -func (self *SVSwitch) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SVSwitch) GetIsPublic() bool { - // return self.IsDefault - return true -} - -func (self *SVSwitch) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SRegion) createVSwitch(zoneId string, vpcId string, name string, cidr string, desc string) (string, error) { - params := make(map[string]string) - params["ZoneId"] = zoneId - params["VpcId"] = vpcId - params["CidrBlock"] = cidr - params["VSwitchName"] = name - if len(desc) > 0 { - params["Description"] = desc - } - params["ClientToken"] = utils.GenRequestId(20) - - body, err := self.vpcRequest("CreateVSwitch", params) - if err != nil { - return "", err - } - return body.GetString("VSwitchId") -} - -func (self *SRegion) DeleteVSwitch(vswitchId string) error { - params := make(map[string]string) - params["VSwitchId"] = vswitchId - - _, err := self.vpcRequest("DeleteVSwitch", params) - return err -} - -func (self *SVSwitch) Delete() error { - err := self.Refresh() - if err != nil { - log.Errorf("refresh vswitch fail %s", err) - return err - } - if len(self.RouteTable.RouteTableId) > 0 && !self.RouteTable.IsSystem() { - err = self.wire.zone.region.UnassociateRouteTable(self.RouteTable.RouteTableId, self.VSwitchId) - if err != nil { - log.Errorf("unassociate routetable fail %s", err) - return err - } - } - err = self.dissociateWithSNAT() - if err != nil { - log.Errorf("fail to dissociateWithSNAT") - return err - } - err = cloudprovider.Wait(10*time.Second, 60*time.Second, func() (bool, error) { - err := self.wire.zone.region.DeleteVSwitch(self.VSwitchId) - if err != nil { - // delete network immediately after deleting vm on it - // \"Code\":\"DependencyViolation\",\"Message\":\"Specified object has dependent resources.\"} - if isError(err, "DependencyViolation") { - return false, nil - } - return false, err - } else { - return true, nil - } - }) - return err -} - -func (self *SVSwitch) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (self *SRegion) GetVSwitches(ids []string, vpcId string, offset int, limit int) ([]SVSwitch, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - if ids != nil && len(ids) > 0 { - params["VSwitchId"] = strings.Join(ids, ",") - } - if len(vpcId) > 0 { - params["VpcId"] = vpcId - } - - body, err := self.vpcRequest("DescribeVSwitches", params) - if err != nil { - log.Errorf("GetVSwitches fail %s", err) - return nil, 0, err - } - - switches := make([]SVSwitch, 0) - err = body.Unmarshal(&switches, "VSwitches", "VSwitch") - if err != nil { - log.Errorf("Unmarshal vswitches fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return switches, int(total), nil -} - -func (self *SRegion) GetVSwitchAttributes(idstr string) (*SVSwitch, error) { - params := make(map[string]string) - params["VSwitchId"] = idstr - - body, err := self.vpcRequest("DescribeVSwitchAttributes", params) - if err != nil { - log.Errorf("DescribeVSwitchAttributes fail %s", err) - return nil, err - } - if self.client.debug { - log.Debugf("%s", body.PrettyString()) - } - switches := SVSwitch{} - err = body.Unmarshal(&switches) - if err != nil { - log.Errorf("Unmarshal vswitches fail %s", err) - return nil, err - } - return &switches, nil -} - -func (vsw *SVSwitch) dissociateWithSNAT() error { - natgatways, err := vsw.wire.vpc.getNatGateways() - if err != nil { - return err - } - for i := range natgatways { - err = natgatways[i].dissociateWithVswitch(vsw.VSwitchId) - if err != nil { - return err - } - } - return nil -} - -func (self *SVSwitch) GetProjectId() string { - return self.ResourceGroupId -} diff --git a/pkg/multicloud/aliyun/waf.go b/pkg/multicloud/aliyun/waf.go deleted file mode 100644 index ef8a2f7d97..0000000000 --- a/pkg/multicloud/aliyun/waf.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceSpecs struct { - Code int - Value bool -} - -type SWafInstance struct { - Version string - InstanceSpecInfos []SInstanceSpecs - InstanceId string - ExpireTime uint64 -} - -func (self *SRegion) DescribeInstanceSpecInfo() (*SWafInstance, error) { - params := map[string]string{ - "RegionId": self.RegionId, - } - resp, err := self.wafRequest("DescribeInstanceSpecInfo", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeInstanceSpecInfo") - } - ret := &SWafInstance{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - if len(ret.InstanceId) == 0 { - return nil, cloudprovider.ErrNotFound - } - return ret, nil -} - -func (self *SRegion) DeleteInstance(id string) error { - params := map[string]string{ - "RegionId": self.RegionId, - "InstanceId": id, - } - _, err := self.wafRequest("DeleteInstance", params) - return errors.Wrapf(err, "DeleteInstance") -} diff --git a/pkg/multicloud/aliyun/wire.go b/pkg/multicloud/aliyun/wire.go deleted file mode 100644 index a433b291e1..0000000000 --- a/pkg/multicloud/aliyun/wire.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.AliyunTags - 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) IsEmulated() bool { - return true -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SWire) Refresh() error { - return nil -} - -func (self *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.zone.GetGlobalId()) -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -func (self *SWire) addNetwork(vswitch *SVSwitch) { - 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() == vswitch.VSwitchId { - find = true - break - } - } - if !find { - self.inetworks = append(self.inetworks, vswitch) - } -} - -func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - if self.inetworks == nil { - err := self.vpc.fetchVSwitches() - if err != nil { - return nil, err - } - } - return self.inetworks, nil -} - -func (self *SWire) getNetworkById(vswitchId string) *SVSwitch { - 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].(*SVSwitch) - if network.VSwitchId == vswitchId { - return network - } - } - return nil -} - -func (self *SWire) GetBandwidth() int { - return 10000 -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - vswitchId, err := self.zone.region.createVSwitch(self.zone.ZoneId, self.vpc.VpcId, opts.Name, opts.Cidr, opts.Desc) - if err != nil { - log.Errorf("createVSwitch error %s", err) - return nil, err - } - self.inetworks = nil - vswitch := self.getNetworkById(vswitchId) - if vswitch == nil { - log.Errorf("cannot find vswitch after create????") - return nil, cloudprovider.ErrNotFound - } - return vswitch, nil -} - -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 -} diff --git a/pkg/multicloud/aliyun/zone.go b/pkg/multicloud/aliyun/zone.go deleted file mode 100644 index 05a7157326..0000000000 --- a/pkg/multicloud/aliyun/zone.go +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aliyun - -import ( - "fmt" - "strings" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type TChargeType string - -var LOCAL_STORAGES = []string{ - api.STORAGE_LOCAL_HDD_PRO, - api.STORAGE_LOCAL_SSD_PRO, -} - -const ( - PrePaidInstanceChargeType TChargeType = "PrePaid" - PrePaidDBInstanceChargeType TChargeType = "Prepaid" - PostPaidInstanceChargeType TChargeType = "PostPaid" - PostPaidDBInstanceChargeType TChargeType = "Postpaid" - DefaultInstanceChargeType = PostPaidInstanceChargeType -) - -type SpotStrategyType string - -const ( - NoSpotStrategy SpotStrategyType = "NoSpot" - SpotWithPriceLimitStrategy SpotStrategyType = "SpotWithPriceLimit" - SpotAsPriceGoStrategy SpotStrategyType = "SpotAsPriceGo" - DefaultSpotStrategy = NoSpotStrategy -) - -type SDedicatedHostGenerations struct { - DedicatedHostGeneration []string -} - -type SVolumeCategories struct { - VolumeCategories []string -} - -type SSupportedDataDiskCategories struct { - SupportedDataDiskCategory []string -} - -type SSupportedInstanceGenerations struct { - SupportedInstanceGeneration []string -} - -type SSupportedInstanceTypeFamilies struct { - SupportedInstanceTypeFamily []string -} - -type SSupportedInstanceTypes struct { - SupportedInstanceType []string -} - -type SSupportedNetworkTypes struct { - SupportedNetworkCategory []string -} - -type SSupportedSystemDiskCategories struct { - SupportedSystemDiskCategory []string -} - -type SResourcesInfo struct { - DataDiskCategories SSupportedDataDiskCategories - InstanceGenerations SSupportedInstanceGenerations - InstanceTypeFamilies SSupportedInstanceTypeFamilies - InstanceTypes SSupportedInstanceTypes - IoOptimized bool - NetworkTypes SSupportedNetworkTypes - SystemDiskCategories SSupportedSystemDiskCategories -} - -type SResources struct { - ResourcesInfo []SResourcesInfo -} - -type SResourceCreation struct { - ResourceTypes []string -} - -type SInstanceTypes struct { - InstanceTypes []string -} - -type SDiskCategories struct { - DiskCategories []string -} - -type SDedicatedHostTypes struct { - DedicatedHostType []string -} - -type SZone struct { - multicloud.SResourceBase - multicloud.AliyunTags - region *SRegion - - iwires []cloudprovider.ICloudWire - - host *SHost - - istorages []cloudprovider.ICloudStorage - - ZoneId string - LocalName string - DedicatedHostGenerations SDedicatedHostGenerations - AvailableVolumeCategories SVolumeCategories - /* 可供创建的具体资源,AvailableResourcesType 组成的数组 */ - AvailableResources SResources - /* 允许创建的资源类型集合 */ - AvailableResourceCreation SResourceCreation - /* 允许创建的实例规格类型 */ - AvailableInstanceTypes SInstanceTypes - /* 支持的磁盘种类集合 */ - AvailableDiskCategories SDiskCategories - AvailableDedicatedHostTypes SDedicatedHostTypes -} - -func (self *SZone) GetId() string { - return self.ZoneId -} - -func (self *SZone) GetName() string { - if self.region.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV && !strings.Contains(self.LocalName, "金融") { - i := strings.Index(self.LocalName, "可用") - var localname string - if i >= 0 { - localname = self.LocalName[0:i] + "金融云 " + self.LocalName[i:] - } else { - localname = self.LocalName + " 金融云" - } - - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_ALIYUN_CN, localname) - } else { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_ALIYUN_CN, self.LocalName) - } -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) - return table -} - -func (self *SZone) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneId) -} - -func (self *SZone) IsEmulated() bool { - return false -} - -func (self *SZone) GetStatus() string { - if len(self.AvailableResourceCreation.ResourceTypes) == 0 || !utils.IsInStringArray("Instance", self.AvailableResourceCreation.ResourceTypes) { - return api.ZONE_SOLDOUT - } else { - return api.ZONE_ENABLE - } -} - -func (self *SZone) Refresh() error { - // do nothing - return nil -} - -func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SZone) fetchStorages() error { - categories := self.AvailableDiskCategories.DiskCategories - self.istorages = []cloudprovider.ICloudStorage{} - for _, sc := range categories { - storage := SStorage{zone: self, storageType: sc} - self.istorages = append(self.istorages, &storage) - if sc == api.STORAGE_CLOUD_ESSD { - storage_l2 := SStorage{zone: self, storageType: api.STORAGE_CLOUD_ESSD_PL2} - self.istorages = append(self.istorages, &storage_l2) - storage_l3 := SStorage{zone: self, storageType: api.STORAGE_CLOUD_ESSD_PL3} - self.istorages = append(self.istorages, &storage_l3) - } - } - for _, localStorage := range LOCAL_STORAGES { - storage := SStorage{zone: self, storageType: localStorage} - self.istorages = append(self.istorages, &storage) - } - return nil -} - -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 *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - if self.istorages == nil { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "fetchStorages") - } - } - return self.istorages, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - if self.istorages == nil { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "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) getHost() *SHost { - if self.host == nil { - self.host = &SHost{zone: self} - } - return self.host -} - -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) addWire(wire *SWire) { - if self.iwires == nil { - self.iwires = make([]cloudprovider.ICloudWire, 0) - } - self.iwires = append(self.iwires, wire) -} - -func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { - return self.iwires, nil -} - -func (self *SZone) getNetworkById(vswitchId string) *SVSwitch { - 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(vswitchId) - if net != nil { - return net - } - } - return nil -} - -func (self *SZone) getSysDiskCategories() []string { - if len(self.AvailableResources.ResourcesInfo) > 0 { - if utils.IsInStringArray(api.STORAGE_CLOUD_ESSD, self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory) { - self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory = append(self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory, api.STORAGE_CLOUD_ESSD_PL2) - self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory = append(self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory, api.STORAGE_CLOUD_ESSD_PL3) - } - return self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory - } - return nil -} diff --git a/pkg/multicloud/apsara/bucket.go b/pkg/multicloud/apsara/bucket.go deleted file mode 100644 index 9ee1fd5752..0000000000 --- a/pkg/multicloud/apsara/bucket.go +++ /dev/null @@ -1,541 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - "io" - "net/http" - "strconv" - "time" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SBucket struct { - multicloud.SBaseBucket - multicloud.ApsaraTags - - region *SRegion - - Name string - Location string - CreationDate time.Time - StorageClass string - - ExtranetEndpoint string - IntranetEndpoint string - DepartmentInfo -} - -func (b *SBucket) GetGlobalId() string { - return b.Name -} - -func (b *SBucket) GetName() string { - return b.Name -} - -func (self *SBucket) GetOssClient() (*oss.Client, error) { - return self.region.GetOssClient() -} - -func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { - acl := b.region.GetBucketAcl(b.Name) - return cloudprovider.TBucketACLType(acl) -} - -func (self *SRegion) GetBucketAcl(bucket string) string { - params := map[string]string{ - "AccountInfo": "aaa", - "x-acs-instanceid": bucket, - "Params": jsonutils.Marshal(map[string]string{"BucketName": bucket, "acl": "acl"}).String(), - } - resp, err := self.ossRequest("GetBucketAcl", params) - if err != nil { - return "" - } - acl, _ := resp.GetString("Data", "AccessControlPolicy", "AccessControlList", "Grant") - return acl -} - -func (b *SBucket) GetLocation() string { - return b.Location -} - -func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { - return b.region -} - -func (b *SBucket) GetCreatedAt() time.Time { - return b.CreationDate -} - -func (b *SBucket) GetStorageClass() string { - return b.StorageClass -} - -func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { - return []cloudprovider.SBucketAccessUrl{ - { - Url: fmt.Sprintf("%s.%s", b.Name, b.ExtranetEndpoint), - Description: "ExtranetEndpoint", - Primary: true, - }, - } -} - -func (self *SRegion) GetBucketSize(bucket string, department int) (int64, error) { - params := map[string]string{ - "Namespace": "acs_oss_dashboard", - "MetricName": "MeteringStorageUtilization", - "Period": "3600", - "Dimensions": jsonutils.Marshal([]map[string]string{ - {"BucketName": bucket}, - }).String(), - "Department": fmt.Sprintf("%d", department), - "StartTime": strconv.FormatInt(time.Now().Add(time.Hour*-24*2).Unix()*1000, 10), - "EndTime": strconv.FormatInt(time.Now().Unix()*1000, 10), - } - resp, err := self.client.metricsRequest("DescribeMetricList", params) - if err != nil { - return 0, nil - } - datapoints, err := resp.GetString("Datapoints") - if err != nil { - return 0, errors.Wrapf(err, "get datapoints") - } - obj, err := jsonutils.ParseString(datapoints) - if err != nil { - return 0, errors.Wrapf(err, "ParseString") - } - data := []struct { - Timestamp int64 - Value int64 - }{} - obj.Unmarshal(&data) - for i := range data { - return data[i].Value, nil - } - return 0, fmt.Errorf("no storage metric found") -} - -func (b *SBucket) GetStats() cloudprovider.SBucketStats { - ret := cloudprovider.SBucketStats{ - SizeBytes: -1, - ObjectCount: -1, - } - dep, _ := strconv.Atoi(b.Department) - size, _ := b.region.GetBucketSize(b.Name, dep) - if size > 0 { - ret.SizeBytes = size - } - return ret -} - -func (self *SRegion) GetBucketCapacity(bucket string, department int) (int64, error) { - params := map[string]string{ - "Params": jsonutils.Marshal(map[string]string{ - "BucketName": bucket, - "region": self.RegionId, - }).String(), - // 此参数必传,可以设任意值 - "AccountInfo": "aaa", - "Department": fmt.Sprintf("%d", department), - } - resp, err := self.ossRequest("GetBucketStorageCapacity", params) - if err != nil { - return 0, errors.Wrapf(err, "GetBucketStorageCapacity") - } - return resp.Int("Data", "BucketUserQos", "StorageCapacity") -} - -func (b *SBucket) GetLimit() cloudprovider.SBucketStats { - ret := cloudprovider.SBucketStats{ - SizeBytes: -1, - ObjectCount: -1, - } - dep, _ := strconv.Atoi(b.Department) - capa, _ := b.region.GetBucketCapacity(b.Name, dep) - if capa > 0 { - ret.SizeBytes = capa * 1024 * 1024 * 1024 - } - return ret -} - -func (b *SBucket) LimitSupport() cloudprovider.SBucketStats { - return b.GetLimit() -} - -func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error { - osscli, err := b.GetOssClient() - if err != nil { - return errors.Wrap(err, "b.region.GetOssClient") - } - acl, err := str2Acl(string(aclStr)) - if err != nil { - return errors.Wrap(err, "str2Acl") - } - err = osscli.SetBucketACL(b.Name, acl) - if err != nil { - return errors.Wrap(err, "SetBucketACL") - } - return nil -} - -func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { - result := cloudprovider.SListObjectResult{} - osscli, err := b.GetOssClient() - if err != nil { - return result, errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return result, errors.Wrap(err, "Bucket") - } - opts := make([]oss.Option, 0) - if len(prefix) > 0 { - opts = append(opts, oss.Prefix(prefix)) - } - if len(delimiter) > 0 { - opts = append(opts, oss.Delimiter(delimiter)) - } - if len(marker) > 0 { - opts = append(opts, oss.Marker(marker)) - } - if maxCount > 0 { - opts = append(opts, oss.MaxKeys(maxCount)) - } - oResult, err := bucket.ListObjects(opts...) - if err != nil { - return result, errors.Wrap(err, "ListObjects") - } - result.Objects = make([]cloudprovider.ICloudObject, 0) - for _, object := range oResult.Objects { - obj := &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - StorageClass: object.StorageClass, - Key: object.Key, - SizeBytes: object.Size, - ETag: object.ETag, - LastModified: object.LastModified, - }, - } - result.Objects = append(result.Objects, obj) - } - if oResult.CommonPrefixes != nil { - result.CommonPrefixes = make([]cloudprovider.ICloudObject, len(oResult.CommonPrefixes)) - for i, commPrefix := range oResult.CommonPrefixes { - result.CommonPrefixes[i] = &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{Key: commPrefix}, - } - } - } - result.IsTruncated = oResult.IsTruncated - result.NextMarker = oResult.NextMarker - return result, nil -} - -func metaOpts(opts []oss.Option, meta http.Header) []oss.Option { - for k, v := range meta { - if len(v) == 0 { - continue - } - switch http.CanonicalHeaderKey(k) { - case cloudprovider.META_HEADER_CONTENT_TYPE: - opts = append(opts, oss.ContentType(v[0])) - case cloudprovider.META_HEADER_CONTENT_MD5: - opts = append(opts, oss.ContentMD5(v[0])) - case cloudprovider.META_HEADER_CONTENT_LANGUAGE: - opts = append(opts, oss.ContentLanguage(v[0])) - case cloudprovider.META_HEADER_CONTENT_ENCODING: - opts = append(opts, oss.ContentEncoding(v[0])) - case cloudprovider.META_HEADER_CONTENT_DISPOSITION: - opts = append(opts, oss.ContentDisposition(v[0])) - case cloudprovider.META_HEADER_CACHE_CONTROL: - opts = append(opts, oss.CacheControl(v[0])) - default: - opts = append(opts, oss.Meta(http.CanonicalHeaderKey(k), v[0])) - } - } - return opts -} - -func (b *SBucket) PutObject(ctx context.Context, key string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - osscli, err := b.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return errors.Wrap(err, "Bucket") - } - opts := make([]oss.Option, 0) - if sizeBytes > 0 { - opts = append(opts, oss.ContentLength(sizeBytes)) - } - if meta != nil { - opts = metaOpts(opts, meta) - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - acl, err := str2Acl(string(cannedAcl)) - if err != nil { - return errors.Wrap(err, "") - } - opts = append(opts, oss.ObjectACL(acl)) - if len(storageClassStr) > 0 { - storageClass, err := str2StorageClass(storageClassStr) - if err != nil { - return errors.Wrap(err, "str2StorageClass") - } - opts = append(opts, oss.ObjectStorageClass(storageClass)) - } - return bucket.PutObject(key, input, opts...) -} - -func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - osscli, err := b.GetOssClient() - if err != nil { - return "", errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return "", errors.Wrap(err, "Bucket") - } - opts := make([]oss.Option, 0) - if meta != nil { - opts = metaOpts(opts, meta) - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - acl, err := str2Acl(string(cannedAcl)) - if err != nil { - return "", errors.Wrap(err, "str2Acl") - } - opts = append(opts, oss.ObjectACL(acl)) - if len(storageClassStr) > 0 { - storageClass, err := str2StorageClass(storageClassStr) - if err != nil { - return "", errors.Wrap(err, "str2StorageClass") - } - opts = append(opts, oss.ObjectStorageClass(storageClass)) - } - result, err := bucket.InitiateMultipartUpload(key, opts...) - if err != nil { - return "", errors.Wrap(err, "bucket.InitiateMultipartUpload") - } - return result.UploadID, nil -} - -func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { - osscli, err := b.GetOssClient() - if err != nil { - return "", errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return "", errors.Wrap(err, "Bucket") - } - imur := oss.InitiateMultipartUploadResult{ - Bucket: b.Name, - Key: key, - UploadID: uploadId, - } - part, err := bucket.UploadPart(imur, input, partSize, partIndex) - if err != nil { - return "", errors.Wrap(err, "bucket.UploadPart") - } - if b.region.client.debug { - log.Debugf("upload part key:%s uploadId:%s partIndex:%d etag:%s", key, uploadId, partIndex, part.ETag) - } - return part.ETag, nil -} - -func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { - osscli, err := b.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return errors.Wrap(err, "Bucket") - } - imur := oss.InitiateMultipartUploadResult{ - Bucket: b.Name, - Key: key, - UploadID: uploadId, - } - parts := make([]oss.UploadPart, len(partEtags)) - for i := range partEtags { - parts[i] = oss.UploadPart{ - PartNumber: i + 1, - ETag: partEtags[i], - } - } - result, err := bucket.CompleteMultipartUpload(imur, parts) - if err != nil { - return errors.Wrap(err, "bucket.CompleteMultipartUpload") - } - if b.region.client.debug { - log.Debugf("CompleteMultipartUpload bucket:%s key:%s etag:%s location:%s", result.Bucket, result.Key, result.ETag, result.Location) - } - return nil -} - -func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { - osscli, err := b.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return errors.Wrap(err, "Bucket") - } - imur := oss.InitiateMultipartUploadResult{ - Bucket: b.Name, - Key: key, - UploadID: uploadId, - } - err = bucket.AbortMultipartUpload(imur) - if err != nil { - return errors.Wrap(err, "AbortMultipartUpload") - } - return nil -} - -func (b *SBucket) DeleteObject(ctx context.Context, key string) error { - osscli, err := b.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return errors.Wrap(err, "Bucket") - } - err = bucket.DeleteObject(key) - if err != nil { - return errors.Wrap(err, "DeleteObject") - } - return nil -} - -func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { - if method != "GET" && method != "PUT" && method != "DELETE" { - return "", errors.Error("unsupported method") - } - osscli, err := b.GetOssClient() - if err != nil { - return "", errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return "", errors.Wrap(err, "Bucket") - } - urlStr, err := bucket.SignURL(key, oss.HTTPMethod(method), int64(expire/time.Second)) - if err != nil { - return "", errors.Wrap(err, "SignURL") - } - return urlStr, nil -} - -func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - osscli, err := b.GetOssClient() - if err != nil { - return errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return errors.Wrap(err, "Bucket") - } - opts := make([]oss.Option, 0) - if meta != nil { - opts = metaOpts(opts, meta) - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - acl, err := str2Acl(string(cannedAcl)) - if err != nil { - return errors.Wrap(err, "str2Acl") - } - opts = append(opts, oss.ObjectACL(acl)) - if len(storageClassStr) > 0 { - storageClass, err := str2StorageClass(storageClassStr) - if err != nil { - return errors.Wrap(err, "str2StorageClass") - } - opts = append(opts, oss.ObjectStorageClass(storageClass)) - } - _, err = bucket.CopyObjectFrom(srcBucket, srcKey, destKey, opts...) - if err != nil { - return errors.Wrap(err, "CopyObjectFrom") - } - return nil -} - -func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { - osscli, err := b.GetOssClient() - if err != nil { - return nil, errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return nil, errors.Wrap(err, "Bucket") - } - opts := make([]oss.Option, 0) - if rangeOpt != nil { - opts = append(opts, oss.NormalizedRange(rangeOpt.String())) - } - output, err := bucket.GetObject(key, opts...) - if err != nil { - return nil, errors.Wrap(err, "bucket.GetObject") - } - return output, nil -} - -func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partNumber int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { - osscli, err := b.GetOssClient() - if err != nil { - return "", errors.Wrap(err, "GetOssClient") - } - bucket, err := osscli.Bucket(b.Name) - if err != nil { - return "", errors.Wrap(err, "Bucket") - } - imur := oss.InitiateMultipartUploadResult{ - Bucket: b.Name, - Key: key, - UploadID: uploadId, - } - opts := make([]oss.Option, 0) - part, err := bucket.UploadPartCopy(imur, srcBucket, srcKey, srcOffset, srcLength, partNumber, opts...) - if err != nil { - return "", errors.Wrap(err, "bucket.UploadPartCopy") - } - return part.ETag, nil -} diff --git a/pkg/multicloud/apsara/charge.go b/pkg/multicloud/apsara/charge.go deleted file mode 100644 index cb148ab82c..0000000000 --- a/pkg/multicloud/apsara/charge.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "time" - - api "yunion.io/x/onecloud/pkg/apis/billing" -) - -func convertChargeType(ct TChargeType) string { - switch ct { - case PrePaidInstanceChargeType: - return api.BILLING_TYPE_PREPAID - case PostPaidInstanceChargeType, PostPaidDBInstanceChargeType: - return api.BILLING_TYPE_POSTPAID - default: - return "" - } -} - -func convertExpiredAt(expired time.Time) time.Time { - if !expired.IsZero() { - now := time.Now() - if expired.Sub(now) < time.Hour*24*365*6 { - return expired - } - } - return time.Time{} -} diff --git a/pkg/multicloud/apsara/dbinstance.go b/pkg/multicloud/apsara/dbinstance.go deleted file mode 100644 index 396aa8c40b..0000000000 --- a/pkg/multicloud/apsara/dbinstance.go +++ /dev/null @@ -1,802 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/rand" -) - -type SReadOnlyDBInstanceIds struct { - ReadOnlyDBInstanceId []string -} - -type SDBInstanceId struct { - DBInstanceId []string -} - -type SDBInstanceExtra struct { - DBInstanceId SDBInstanceId -} - -type SDBInstance struct { - multicloud.SDBInstanceBase - multicloud.ApsaraTags - - netInfo []SDBInstanceNetwork - - region *SRegion - - AccountMaxQuantity int - AccountType string - CanTempUpgrade bool - Category string - AvailabilityValue string - DBInstanceDescription string - DBInstanceId string - ConnectionMode string - ConnectionString string - CurrentKernelVersion string - DBInstanceCPU int - CreateTime time.Time - DBInstanceClass string - DBInstanceClassType string - DBInstanceNetType string - DBInstanceStatus string - DBInstanceType string - DBInstanceDiskUsed int64 - DBInstanceStorage int - DBInstanceStorageType string - MasterInstanceId string - DBInstanceMemory int - DBMaxQuantity int - IPType string - LatestKernelVersion string - DispenseMode string - Engine string - EngineVersion string - ExpireTime time.Time - InstanceNetworkType string - LockMode string - LockReason string - MutriORsignle bool - MaintainTime string - MaxConnections int - MaxIOPS int - Port int - PayType TChargeType - ReadOnlyDBInstanceIds SReadOnlyDBInstanceIds - RegionId string - VSwitchId string - VpcCloudInstanceId string - VpcId string - ZoneId string - Extra SDBInstanceExtra - SecurityIPList string - SecurityIPMode string - SupportCreateSuperAccount string - SupportUpgradeAccountType string - TempUpgradeTimeEnd time.Time - TempUpgradeTimeStart time.Time - DepartmentInfo -} - -func (rds *SDBInstance) GetName() string { - if len(rds.DBInstanceDescription) > 0 { - return rds.DBInstanceDescription - } - return rds.DBInstanceId -} - -func (rds *SDBInstance) GetId() string { - return rds.DBInstanceId -} - -func (rds *SDBInstance) GetGlobalId() string { - return rds.GetId() -} - -// Creating 创建中 -// Running 使用中 -// Deleting 删除中 -// Rebooting 重启中 -// DBInstanceClassChanging 升降级中 -// TRANSING 迁移中 -// EngineVersionUpgrading 迁移版本中 -// TransingToOthers 迁移数据到其他RDS中 -// GuardDBInstanceCreating 生产灾备实例中 -// Restoring 备份恢复中 -// Importing 数据导入中 -// ImportingFromOthers 从其他RDS实例导入数据中 -// DBInstanceNetTypeChanging 内外网切换中 -// GuardSwitching 容灾切换中 -// INS_CLONING 实例克隆中 -func (rds *SDBInstance) GetStatus() string { - switch rds.DBInstanceStatus { - case "Creating", "GuardDBInstanceCreating", "DBInstanceNetTypeChanging", "GuardSwitching", "NET_CREATING", "NET_DELETING": - return api.DBINSTANCE_DEPLOYING - case "DBInstanceClassChanging": - return api.DBINSTANCE_CHANGE_CONFIG - case "Running": - return api.DBINSTANCE_RUNNING - case "Deleting": - return api.DBINSTANCE_DELETING - case "Rebooting": - return api.DBINSTANCE_REBOOTING - case "TRANSING", "EngineVersionUpgrading", "TransingToOthers": - return api.DBINSTANCE_MIGRATING - case "Restoring": - return api.DBINSTANCE_RESTORING - case "Importing", "ImportingFromOthers": - return api.DBINSTANCE_IMPORTING - case "INS_CLONING": - return api.DBINSTANCE_CLONING - default: - log.Errorf("Unknown dbinstance status %s", rds.DBInstanceStatus) - return api.DBINSTANCE_UNKNOWN - } -} - -func (rds *SDBInstance) GetBillingType() string { - return convertChargeType(rds.PayType) -} - -func (rds *SDBInstance) GetExpiredAt() time.Time { - return rds.ExpireTime -} - -func (rds *SDBInstance) GetCreatedAt() time.Time { - return rds.CreateTime -} - -func (rds *SDBInstance) GetStorageType() string { - return rds.DBInstanceStorageType -} - -func (rds *SDBInstance) GetIops() int { - return rds.MaxIOPS -} - -func (rds *SDBInstance) GetEngine() string { - switch rds.Engine { - case "MySQL": - return api.DBINSTANCE_TYPE_MYSQL - case "SQLServer": - return api.DBINSTANCE_TYPE_SQLSERVER - case "PostgreSQL": - return api.DBINSTANCE_TYPE_POSTGRESQL - case "PPAS": - return api.DBINSTANCE_TYPE_PPAS - case "MariaDB": - return api.DBINSTANCE_TYPE_MARIADB - } - return rds.Engine -} - -func (rds *SDBInstance) GetEngineVersion() string { - return rds.EngineVersion -} - -func (rds *SDBInstance) GetInstanceType() string { - return rds.DBInstanceClass -} - -func (rds *SDBInstance) GetCategory() string { - switch rds.Category { - case "Basic": - return api.ALIYUN_DBINSTANCE_CATEGORY_BASIC - case "HighAvailability": - return api.ALIYUN_DBINSTANCE_CATEGORY_HA - case "AlwaysOn": - return api.ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON - case "Finance": - return api.ALIYUN_DBINSTANCE_CATEGORY_FINANCE - } - return rds.Category -} - -func (rds *SDBInstance) GetVcpuCount() int { - if rds.DBInstanceCPU == 0 { - rds.Refresh() - } - return rds.DBInstanceCPU -} - -func (rds *SDBInstance) GetVmemSizeMB() int { - if rds.DBInstanceMemory == 0 { - rds.Refresh() - } - return rds.DBInstanceMemory -} - -func (rds *SDBInstance) GetDiskSizeGB() int { - if rds.DBInstanceStorage == 0 { - rds.Refresh() - } - return rds.DBInstanceStorage -} - -func (rds *SDBInstance) GetDiskSizeUsedMB() int { - if rds.DBInstanceDiskUsed == 0 { - rds.Refresh() - } - return int(rds.DBInstanceDiskUsed / 1024 / 1024) -} - -func (rds *SDBInstance) GetPort() int { - if rds.Port == 0 { - rds.Refresh() - } - return rds.Port -} - -func (rds *SDBInstance) GetMaintainTime() string { - return rds.MaintainTime -} - -func (rds *SDBInstance) GetIVpcId() string { - return rds.VpcId -} - -func (rds *SDBInstance) Refresh() error { - instance, err := rds.region.GetDBInstanceDetail(rds.DBInstanceId) - if err != nil { - return err - } - return jsonutils.Update(rds, instance) -} - -func (rds *SDBInstance) getZoneId(index int) string { - zoneId := rds.getZone(index) - if len(zoneId) > 0 { - zone, err := rds.region.getZoneById(zoneId) - if err != nil { - log.Errorf("failed to found zone %s for rds %s", zoneId, rds.GetName()) - return "" - } - return zone.GetGlobalId() - } - return "" -} - -func (rds *SDBInstance) GetZone1Id() string { - return rds.getZoneId(1) -} - -func (rds *SDBInstance) GetZone2Id() string { - return rds.getZoneId(2) -} - -func (rds *SDBInstance) GetZone3Id() string { - return rds.getZoneId(3) -} - -func (rds *SDBInstance) getZone(index int) string { - zoneStr := strings.Replace(rds.ZoneId, ")", "", -1) - zoneInfo := strings.Split(zoneStr, ",") - if len(zoneInfo) < index { - return "" - } - zone := zoneInfo[index-1] - zoneCode := zone[len(zone)-1] - if strings.HasPrefix(rds.ZoneId, fmt.Sprintf("%s-", rds.RegionId)) { - return fmt.Sprintf("%s-%s", rds.RegionId, string(zoneCode)) - } - return fmt.Sprintf("%s%s", rds.RegionId, string(zoneCode)) -} - -func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { - netInfo, err := rds.region.GetDBInstanceNetInfo(rds.DBInstanceId) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceNetInfo") - } - networks := []cloudprovider.SDBInstanceNetwork{} - for _, net := range netInfo { - if net.IPType == "Private" { - network := cloudprovider.SDBInstanceNetwork{} - network.IP = net.IPAddress - network.NetworkId = net.VSwitchId - networks = append(networks, network) - } - } - return networks, nil -} - -func (rds *SDBInstance) fetchNetInfo() error { - if len(rds.netInfo) > 0 { - return nil - } - netInfo, err := rds.region.GetDBInstanceNetInfo(rds.DBInstanceId) - if err != nil { - return errors.Wrap(err, "GetDBInstanceNetInfo") - } - rds.netInfo = netInfo - return nil -} - -func (rds *SDBInstance) GetInternalConnectionStr() string { - err := rds.fetchNetInfo() - if err != nil { - log.Errorf("failed to fetch netInfo error: %v", err) - return "" - } - - for _, net := range rds.netInfo { - if net.IPType != "Public" { - return net.ConnectionString - } - } - return "" -} - -func (rds *SDBInstance) GetConnectionStr() string { - err := rds.fetchNetInfo() - if err != nil { - log.Errorf("failed to fetch netInfo error: %v", err) - return "" - } - - for _, net := range rds.netInfo { - if net.IPType == "Public" { - return net.ConnectionString - } - } - return "" -} - -func (region *SRegion) GetDBInstances(ids []string, offset int, limit int) ([]SDBInstance, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - body, err := region.rdsRequest("DescribeDBInstances", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "GetDBInstances") - } - instances := []SDBInstance{} - err = body.Unmarshal(&instances, "Items", "DBInstance") - if err != nil { - return nil, 0, errors.Wrapf(err, "GetDBInstances.Unmarshal") - } - total, _ := body.Int("TotalRecordCount") - return instances, int(total), nil -} - -func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { - rds, err := region.GetDBInstanceDetail(instanceId) - if err != nil { - return nil, err - } - rds.region = region - return rds, nil -} - -func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - instances := []SDBInstance{} - for { - part, total, err := region.GetDBInstances([]string{}, len(instances), 50) - if err != nil { - return nil, err - } - instances = append(instances, part...) - if len(instances) >= total { - break - } - } - idbinstances := []cloudprovider.ICloudDBInstance{} - for i := 0; i < len(instances); i++ { - instances[i].region = region - idbinstances = append(idbinstances, &instances[i]) - } - return idbinstances, nil -} - -func (region *SRegion) GetDBInstanceDetail(instanceId string) (*SDBInstance, error) { - if len(instanceId) == 0 { - return nil, cloudprovider.ErrNotFound - } - params := map[string]string{} - params["RegionId"] = region.RegionId - params["DBInstanceId"] = instanceId - body, err := region.rdsRequest("DescribeDBInstanceAttribute", params) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceDetail") - } - instances := []SDBInstance{} - err = body.Unmarshal(&instances, "Items", "DBInstanceAttribute") - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceDetail.Unmarshal") - } - if len(instances) == 1 { - instances[0].region = region - return &instances[0], nil - } - if len(instances) == 0 { - return nil, cloudprovider.ErrNotFound - } - return nil, cloudprovider.ErrDuplicateId -} - -func (region *SRegion) DeleteDBInstance(instanceId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["DBInstanceId"] = instanceId - _, err := region.rdsRequest("DeleteDBInstance", params) - return err -} - -type SDBInstanceWeight struct { -} - -type SDBInstanceWeights struct { - DBInstanceWeight []SDBInstanceWeight -} - -type SsecurityIPGroup struct { -} - -type SSecurityIPGroups struct { - securityIPGroup []SsecurityIPGroup -} - -type SDBInstanceNetwork struct { - ConnectionString string - ConnectionStringType string - DBInstanceWeights SDBInstanceWeights - IPAddress string - IPType string - Port int - SecurityIPGroups SSecurityIPGroups - Upgradeable string - VPCId string - VSwitchId string -} - -func (network *SDBInstanceNetwork) GetGlobalId() string { - return network.IPAddress -} - -func (network *SDBInstanceNetwork) GetINetworkId() string { - return network.VSwitchId -} - -func (network *SDBInstanceNetwork) GetIP() string { - return network.IPAddress -} - -func (region *SRegion) GetDBInstanceNetInfo(instanceId string) ([]SDBInstanceNetwork, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["DBInstanceId"] = instanceId - body, err := region.rdsRequest("DescribeDBInstanceNetInfo", params) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceNetwork") - } - networks := []SDBInstanceNetwork{} - err = body.Unmarshal(&networks, "DBInstanceNetInfos", "DBInstanceNetInfo") - if err != nil { - return nil, err - } - return networks, nil -} - -func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { - parameters, err := rds.region.GetDBInstanceParameters(rds.DBInstanceId) - if err != nil { - return nil, err - } - iparameters := []cloudprovider.ICloudDBInstanceParameter{} - for i := 0; i < len(parameters); i++ { - iparameters = append(iparameters, ¶meters[i]) - } - return iparameters, nil -} - -func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { - backups, err := region.GetIDBInstanceBackups() - if err != nil { - return nil, errors.Wrap(err, "region.GetIDBInstanceBackups") - } - for _, backup := range backups { - if backup.GetGlobalId() == backupId { - return backup, nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (rds *SDBInstance) Reboot() error { - return rds.region.RebootDBInstance(rds.DBInstanceId) -} - -func (rds *SDBInstance) Delete() error { - return rds.region.DeleteDBInstance(rds.DBInstanceId) -} - -func (region *SRegion) RebootDBInstance(instanceId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["DBInstanceId"] = instanceId - _, err := region.rdsRequest("RestartDBInstance", params) - return err -} - -func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { - databases := []SDBInstanceDatabase{} - for { - parts, total, err := rds.region.GetDBInstanceDatabases(rds.DBInstanceId, "", len(databases), 500) - if err != nil { - return nil, err - } - databases = append(databases, parts...) - if len(databases) >= total { - break - } - } - - idatabase := []cloudprovider.ICloudDBInstanceDatabase{} - for i := 0; i < len(databases); i++ { - databases[i].instance = rds - idatabase = append(idatabase, &databases[i]) - } - return idatabase, nil -} - -func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { - accounts := []SDBInstanceAccount{} - for { - parts, total, err := rds.region.GetDBInstanceAccounts(rds.DBInstanceId, len(accounts), 50) - if err != nil { - return nil, err - } - accounts = append(accounts, parts...) - if len(accounts) >= total { - break - } - } - - iaccounts := []cloudprovider.ICloudDBInstanceAccount{} - for i := 0; i < len(accounts); i++ { - accounts[i].instance = rds - iaccounts = append(iaccounts, &accounts[i]) - } - return iaccounts, nil -} - -func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { - return rds.region.ChangeDBInstanceConfig(rds.DBInstanceId, string(rds.PayType), desc) -} - -func (region *SRegion) ChangeDBInstanceConfig(instanceId, payType string, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { - params := map[string]string{ - "RegionId": region.RegionId, - "DBInstanceId": instanceId, - "PayType": payType, - "DBInstanceClass": desc.InstanceType, - "DBInstanceStorage": fmt.Sprintf("%d", desc.DiskSizeGB), - } - - _, err := region.rdsRequest("ModifyDBInstanceSpec", params) - if err != nil { - return errors.Wrap(err, "region.rdsRequest.ModifyDBInstanceSpec") - } - return nil -} - -func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - params := map[string]string{ - "RegionId": region.RegionId, - "Engine": desc.Engine, - "EngineVersion": desc.EngineVersion, - "DBInstanceStorage": fmt.Sprintf("%d", desc.DiskSizeGB), - "DBInstanceNetType": "Intranet", - "PayType": "Postpaid", - "SecurityIPList": "0.0.0.0/0", - "DBInstanceDescription": desc.Name, - "InstanceNetworkType": "VPC", - "VPCId": desc.VpcId, - "VSwitchId": desc.NetworkId, - "DBInstanceStorageType": desc.StorageType, - "DBInstanceClass": desc.InstanceType, - "ZoneId": desc.ZoneId, - "ClientToken": utils.GenRequestId(20), - } - switch desc.Category { - case api.ALIYUN_DBINSTANCE_CATEGORY_HA: - params["Category"] = "HighAvailability" - case api.ALIYUN_DBINSTANCE_CATEGORY_BASIC: - params["Category"] = "Basic" - case api.ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON: - params["Category"] = "AlwaysOn" - case api.ALIYUN_DBINSTANCE_CATEGORY_FINANCE: - params["Category"] = "Finance" - } - - if len(desc.Address) > 0 { - params["PrivateIpAddress"] = desc.Address - } - if len(desc.ProjectId) > 0 { - params["ResourceGroupId"] = desc.ProjectId - } - if desc.BillingCycle != nil { - params["PayType"] = "Prepaid" - if desc.BillingCycle.GetMonths() > 0 { - params["Period"] = "Month" - params["UsedTime"] = fmt.Sprintf("%d", desc.BillingCycle.GetMonths()) - } else { - params["Period"] = "Year" - params["UsedTime"] = fmt.Sprintf("%d", desc.BillingCycle.GetYears()) - } - params["AutoRenew"] = "False" - } - - action := "CreateDBInstance" - if len(desc.MasterInstanceId) > 0 { - action = "CreateReadOnlyDBInstance" - params["DBInstanceId"] = desc.MasterInstanceId - } - - resp, err := region.rdsRequest(action, params) - if err != nil { - return nil, errors.Wrapf(err, "rdsRequest") - } - instanceId, err := resp.GetString("DBInstanceId") - if err != nil { - return nil, errors.Wrap(err, `resp.GetString("DBInstanceId")`) - } - region.SetResourceTags("rds", "INSTANCE", []string{instanceId}, desc.Tags, false) - return region.GetIDBInstanceById(instanceId) -} - -func (rds *SDBInstance) GetMasterInstanceId() string { - if len(rds.MasterInstanceId) > 0 { - return rds.MasterInstanceId - } - rds.Refresh() - return rds.MasterInstanceId -} - -func (region *SRegion) OpenPublicConnection(instanceId string) error { - rds, err := region.GetDBInstanceDetail(instanceId) - if err != nil { - return err - } - params := map[string]string{ - "RegionId": region.RegionId, - "ConnectionStringPrefix": rds.DBInstanceId + rand.String(3), - "DBInstanceId": rds.DBInstanceId, - "Port": fmt.Sprintf("%d", rds.Port), - } - _, err = rds.region.rdsRequest("AllocateInstancePublicConnection", params) - if err != nil { - return errors.Wrap(err, "rdsRequest(AllocateInstancePublicConnection)") - } - return nil -} - -func (rds *SDBInstance) OpenPublicConnection() error { - if url := rds.GetConnectionStr(); len(url) == 0 { - err := rds.region.OpenPublicConnection(rds.DBInstanceId) - if err != nil { - return err - } - rds.netInfo = []SDBInstanceNetwork{} - } - return nil -} - -func (region *SRegion) ClosePublicConnection(instanceId string) error { - netInfo, err := region.GetDBInstanceNetInfo(instanceId) - if err != nil { - return errors.Wrap(err, "GetDBInstanceNetInfo") - } - - for _, net := range netInfo { - if net.IPType == "Public" { - params := map[string]string{ - "RegionId": region.RegionId, - "CurrentConnectionString": net.ConnectionString, - "DBInstanceId": instanceId, - } - _, err = region.rdsRequest("ReleaseInstancePublicConnection", params) - if err != nil { - return errors.Wrap(err, "rdsRequest(ReleaseInstancePublicConnection)") - } - - } - } - return nil - -} - -func (rds *SDBInstance) ClosePublicConnection() error { - return rds.region.ClosePublicConnection(rds.DBInstanceId) -} - -func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { - if len(conf.OriginDBInstanceExternalId) == 0 { - conf.OriginDBInstanceExternalId = rds.DBInstanceId - } - return rds.region.RecoveryDBInstanceFromBackup(conf.OriginDBInstanceExternalId, rds.DBInstanceId, conf.BackupId, conf.Databases) -} - -func (region *SRegion) RecoveryDBInstanceFromBackup(srcId, destId string, backupId string, databases map[string]string) error { - params := map[string]string{ - "RegionId": region.RegionId, - "DBInstanceId": srcId, - "TargetDBInstanceId": destId, - "BackupId": backupId, - "DbNames": jsonutils.Marshal(databases).String(), - } - _, err := region.rdsRequest("RecoveryDBInstance", params) - if err != nil { - return errors.Wrap(err, "rdsRequest.RecoveryDBInstance") - } - return nil -} - -func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { - return rds.region.CreateDBInstanceDatabae(rds.DBInstanceId, conf.CharacterSet, conf.Name, conf.Description) -} - -func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { - return rds.region.CreateDBInstanceAccount(rds.DBInstanceId, conf.Name, conf.Password, conf.Description) -} - -func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { - return rds.region.RenewInstance(rds.DBInstanceId, bc) -} - -func (region *SRegion) RenewDBInstance(instanceId string, bc billing.SBillingCycle) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "Period": fmt.Sprintf("%d", bc.GetMonths()), - "ClientToken": utils.GenRequestId(20), - } - _, err := region.rdsRequest("RenewInstance", params) - return err -} - -func (rds *SDBInstance) GetTags() (map[string]string, error) { - tags, err := rds.region.ListResourceTags("rds", "INSTANCE", []string{rds.GetId()}) - if err != nil { - return nil, errors.Wrap(err, "rds.region.ListResourceTags") - } - if _, ok := tags[rds.GetId()]; !ok { - return map[string]string{}, nil - } - return *tags[rds.GetId()], nil -} - -func (rds *SDBInstance) SetTags(tags map[string]string, replace bool) error { - return rds.region.SetResourceTags("rds", "INSTANCE", []string{rds.GetId()}, tags, replace) -} diff --git a/pkg/multicloud/apsara/dbinstance_account.go b/pkg/multicloud/apsara/dbinstance_account.go deleted file mode 100644 index b9e06be23a..0000000000 --- a/pkg/multicloud/apsara/dbinstance_account.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDatabasePrivileges struct { - DatabasePrivilege []SDatabasePrivilege -} - -type SDBInstanceAccount struct { - multicloud.SDBInstanceAccountBase - multicloud.ApsaraTags - instance *SDBInstance - - AccountDescription string - AccountName string - AccountStatus string - AccountType string - DBInstanceId string - DatabasePrivileges SDatabasePrivileges - PrivExceeded string -} - -func (account *SDBInstanceAccount) GetName() string { - return account.AccountName -} - -func (account *SDBInstanceAccount) Delete() error { - return account.instance.region.DeleteDBInstanceAccount(account.DBInstanceId, account.AccountName) -} - -func (account *SDBInstanceAccount) RevokePrivilege(database string) error { - return account.instance.region.RevokeDBInstancePrivilege(account.DBInstanceId, account.AccountName, database) -} - -func (region *SRegion) RevokeDBInstancePrivilege(instanceId, account, database string) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "AccountName": account, - "DBName": database, - } - _, err := region.rdsRequest("RevokeAccountPrivilege", params) - return err -} - -func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { - return account.instance.region.GrantDBInstancePrivilege(account.DBInstanceId, account.AccountName, database, privilege) -} - -func (region *SRegion) GrantDBInstancePrivilege(instanceId, account, database, privilege string) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "AccountName": account, - "DBName": database, - } - switch privilege { - case api.DATABASE_PRIVILEGE_R: - params["AccountPrivilege"] = "ReadOnly" - case api.DATABASE_PRIVILEGE_RW: - params["AccountPrivilege"] = "ReadWrite" - case api.DATABASE_PRIVILEGE_DDL: - params["AccountPrivilege"] = "DDLOnly" - case api.DATABASE_PRIVILEGE_DML: - params["AccountPrivilege"] = "DMLOnly" - case api.DATABASE_PRIVILEGE_OWNER: - params["AccountPrivilege"] = "DBOwner" - default: - return fmt.Errorf("Unknown privilege [%s]", privilege) - } - _, err := region.rdsRequest("GrantAccountPrivilege", params) - return err -} - -func (account *SDBInstanceAccount) ResetPassword(password string) error { - return account.instance.region.ResetDBInstanceAccountPassword(account.DBInstanceId, account.AccountName, password, account.AccountType) -} - -func (region *SRegion) ResetDBInstanceAccountPassword(instanceId, account, password, accountType string) error { - action := "ResetAccountPassword" - if accountType == "Super" { - action = "ResetAccount" - } - params := map[string]string{ - "DBInstanceId": instanceId, - "AccountName": account, - "AccountPassword": password, - } - _, err := region.rdsRequest(action, params) - return err -} - -func (account *SDBInstanceAccount) GetStatus() string { - switch account.AccountStatus { - case "Available": - return api.DBINSTANCE_USER_AVAILABLE - case "Unavailable": - return api.DBINSTANCE_USER_UNAVAILABLE - } - return account.AccountStatus -} - -func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { - privileves := []cloudprovider.ICloudDBInstanceAccountPrivilege{} - for i := 0; i < len(account.DatabasePrivileges.DatabasePrivilege); i++ { - account.DatabasePrivileges.DatabasePrivilege[i].account = account - privileves = append(privileves, &account.DatabasePrivileges.DatabasePrivilege[i]) - } - return privileves, nil -} - -func (region *SRegion) GetDBInstanceAccounts(instanceId string, offset int, limit int) ([]SDBInstanceAccount, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := map[string]string{ - "RegionId": region.RegionId, - "PageSize": fmt.Sprintf("%d", limit), - "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), - "DBInstanceId": instanceId, - } - body, err := region.rdsRequest("DescribeAccounts", params) - if err != nil { - return nil, 0, errors.Wrap(err, "DescribeAccounts") - } - accounts := []SDBInstanceAccount{} - err = body.Unmarshal(&accounts, "Accounts", "DBInstanceAccount") - if err != nil { - return nil, 0, errors.Wrap(err, "Unmarshal") - } - total, _ := body.Int("TotalRecordCount") - return accounts, int(total), nil -} - -func (region *SRegion) DeleteDBInstanceAccount(instanceId string, accountName string) error { - params := map[string]string{ - "RegionId": region.RegionId, - "DBInstanceId": instanceId, - "AccountName": accountName, - } - - _, err := region.rdsRequest("DeleteAccount", params) - return err -} - -func (region *SRegion) CreateDBInstanceAccount(instanceId string, name string, password string, desc string) error { - params := map[string]string{ - "RegionId": region.RegionId, - "DBInstanceId": instanceId, - "AccountName": name, - "AccountPassword": password, - "AccountDescription": desc, - } - - _, err := region.rdsRequest("CreateAccount", params) - return err - -} diff --git a/pkg/multicloud/apsara/dbinstance_backup.go b/pkg/multicloud/apsara/dbinstance_backup.go deleted file mode 100644 index a2d0b8fcb7..0000000000 --- a/pkg/multicloud/apsara/dbinstance_backup.go +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strings" - "time" - - "github.com/coredns/coredns/plugin/pkg/log" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceBackup struct { - multicloud.SDBInstanceBackupBase - multicloud.ApsaraTags - region *SRegion - - BackupDBNames string - BackupIntranetDownloadURL string - BackupDownloadURL string - BackupEndTime time.Time - BackupId string - BackupLocation string - BackupMethod string - BackupMode string - BackupScale string - BackupSize int - BackupStartTime time.Time - BackupStatus string - BackupType string - DBInstanceId string - HostInstanceID int - MetaStatus string - StoreStatus string -} - -func (backup *SDBInstanceBackup) GetId() string { - return backup.BackupId -} - -func (backup *SDBInstanceBackup) GetGlobalId() string { - return backup.BackupId -} - -func (backup *SDBInstanceBackup) GetName() string { - return backup.BackupId -} - -func (backup *SDBInstanceBackup) GetStartTime() time.Time { - return backup.BackupStartTime -} - -func (backup *SDBInstanceBackup) GetEndTime() time.Time { - return backup.BackupEndTime -} - -func (backup *SDBInstanceBackup) GetBackupMode() string { - switch backup.BackupMode { - case "Manual": - return api.BACKUP_MODE_MANUAL - default: - return api.BACKUP_MODE_AUTOMATED - } -} - -func (backup *SDBInstanceBackup) GetStatus() string { - switch backup.BackupStatus { - case "Success": - return api.DBINSTANCE_BACKUP_READY - case "Failed": - return api.DBINSTANCE_BACKUP_FAILED - default: - return api.DBINSTANCE_BACKUP_UNKNOWN - } -} - -func (backup *SDBInstanceBackup) GetBackupSizeMb() int { - return backup.BackupSize / 1024 / 1024 -} - -func (backup *SDBInstanceBackup) GetDBNames() string { - return backup.BackupDBNames -} - -func (backup *SDBInstanceBackup) GetEngine() string { - instance, _ := backup.region.GetDBInstanceDetail(backup.DBInstanceId) - if instance != nil { - return instance.Engine - } - return "" -} - -func (backup *SDBInstanceBackup) GetEngineVersion() string { - instance, _ := backup.region.GetDBInstanceDetail(backup.DBInstanceId) - if instance != nil { - return instance.EngineVersion - } - return "" -} - -func (backup *SDBInstanceBackup) GetDBInstanceId() string { - return backup.DBInstanceId -} - -func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string, offset int, limit int) ([]SDBInstanceBackup, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := map[string]string{ - "RegionId": region.RegionId, - "PageSize": fmt.Sprintf("%d", limit), - "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), - "DBInstanceId": instanceId, - } - if len(backupId) > 0 { - params["BackupId"] = backupId - } - body, err := region.rdsRequest("DescribeBackups", params) - if err != nil { - return nil, 0, errors.Wrap(err, "DescribeBackups") - } - backups := []SDBInstanceBackup{} - err = body.Unmarshal(&backups, "Items", "Backup") - if err != nil { - return nil, 0, errors.Wrap(err, "Unmarshal") - } - total, _ := body.Int("TotalRecordCount") - return backups, int(total), nil -} - -func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - dbinstnaces, err := region.GetIDBInstances() - if err != nil { - return nil, err - } - ibackups := []cloudprovider.ICloudDBInstanceBackup{} - for i := 0; i < len(dbinstnaces); i++ { - _dbinstance := dbinstnaces[i].(*SDBInstance) - _ibackup, err := _dbinstance.GetIDBInstanceBackups() - if err != nil { - return nil, errors.Wrapf(err, "_dbinstance(%v).GetIDBInstanceBackups", _dbinstance) - } - ibackups = append(ibackups, _ibackup...) - } - return ibackups, nil -} - -func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - backups := []SDBInstanceBackup{} - for { - parts, total, err := rds.region.GetDBInstanceBackups(rds.DBInstanceId, "", len(backups), 50) - if err != nil { - return nil, err - } - backups = append(backups, parts...) - if len(backups) >= total { - break - } - } - - ibackups := []cloudprovider.ICloudDBInstanceBackup{} - for i := 0; i < len(backups); i++ { - backups[i].region = rds.region - ibackups = append(ibackups, &backups[i]) - } - return ibackups, nil -} - -func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { - params := map[string]string{ - "DBInstanceId": rds.DBInstanceId, - } - switch rds.Engine { - case api.DBINSTANCE_TYPE_MYSQL: - if utils.IsInStringArray(rds.EngineVersion, []string{"5.7", "8.0"}) && ((utils.IsInStringArray(rds.GetStorageType(), []string{ - api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_ESSD, - api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD, - }) && rds.GetCategory() == api.ALIYUN_DBINSTANCE_CATEGORY_HA) || - (rds.GetStorageType() == api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD && - rds.GetCategory() == api.ALIYUN_DBINSTANCE_CATEGORY_BASIC)) { - params["BackupMethod"] = "Snapshot" - } else { - params["BackupMethod"] = "Physical" - if len(conf.Databases) > 0 { - params["BackupStrategy"] = "db" - params["DBName"] = strings.Join(conf.Databases, ",") - params["BackupMethod"] = "Logical" - } - } - case api.DBINSTANCE_TYPE_MARIADB: - params["BackupMethod"] = "Snapshot" - case api.DBINSTANCE_TYPE_SQLSERVER: - params["BackupMethod"] = "Physical" - case api.DBINSTANCE_TYPE_POSTGRESQL: - if rds.GetStorageType() == api.ALIYUN_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD { - params["BackupMethod"] = "Physical" - } else { - params["BackupMethod"] = "Snapshot" - } - case api.DBINSTANCE_TYPE_PPAS: - params["BackupMethod"] = "Physical" - } - body, err := rds.region.rdsRequest("CreateBackup", params) - if err != nil { - return "", errors.Wrap(err, "CreateBackup") - } - jobId, err := body.GetString("BackupJobId") - if err != nil { - return "", errors.Wrap(err, "body.BackupJobId") - } - return "", rds.region.waitBackupCreateComplete(rds.DBInstanceId, jobId) -} - -func (backup *SDBInstanceBackup) Delete() error { - return backup.region.DeleteDBInstanceBackup(backup.DBInstanceId, backup.BackupId) -} - -func (region *SRegion) DeleteDBInstanceBackup(instanceId string, backupId string) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "BackupId": backupId, - } - _, err := region.rdsRequest("DeleteBackup", params) - return err -} - -type SDBInstanceBackupJob struct { - BackupProgressStatus string - Process string - JobMode string - TaskAction string - BackupStatus string - BackupJobId string -} - -type SDBInstanceBackupJobs struct { - BackupJob []SDBInstanceBackupJob -} - -func (region *SRegion) GetDBInstanceBackupJobs(instanceId, jobId string) (*SDBInstanceBackupJobs, error) { - params := map[string]string{ - "DBInstanceId": instanceId, - "ClientToken": utils.GenRequestId(20), - "BackupMode": "Manual", - } - if len(jobId) > 0 { - params["BackupJobId"] = jobId - } - body, err := region.rdsRequest("DescribeBackupTasks", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeBackupTasks") - } - - jobs := SDBInstanceBackupJobs{} - - err = body.Unmarshal(&jobs, "Items") - if err != nil { - return nil, errors.Wrapf(err, "body.Unmarshal(%s)", body) - } - - return &jobs, nil -} - -func (region *SRegion) waitBackupCreateComplete(instanceId, jobId string) error { - for i := 0; i < 20*40; i++ { - jobs, err := region.GetDBInstanceBackupJobs(instanceId, jobId) - if err != nil { - return errors.Wrapf(err, "region.GetDBInstanceBackupJobs(%s, %s)", instanceId, jobId) - } - if len(jobs.BackupJob) == 0 { - return nil - } - for _, job := range jobs.BackupJob { - log.Infof("instance %s backup job %s status: %s(%s)", instanceId, jobId, job.BackupStatus, job.Process) - if job.BackupStatus == "Finished" && job.BackupJobId == jobId { - return nil - } - if job.BackupStatus == "Failed" && job.BackupJobId == jobId { - return fmt.Errorf("instance %s backup job %s failed", instanceId, jobId) - } - } - time.Sleep(time.Second * 3) - } - return fmt.Errorf("timeout for waiting create job complete") -} diff --git a/pkg/multicloud/apsara/dbinstance_database.go b/pkg/multicloud/apsara/dbinstance_database.go deleted file mode 100644 index ddd1174b0a..0000000000 --- a/pkg/multicloud/apsara/dbinstance_database.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceDatabase struct { - multicloud.SDBInstanceDatabaseBase - multicloud.ApsaraTags - instance *SDBInstance - - CharacterSetName string - DBDescription string - DBInstanceId string - DBName string - DBStatus string - Engine string -} - -func (database *SDBInstanceDatabase) GetId() string { - return database.DBName -} - -func (database *SDBInstanceDatabase) GetGlobalId() string { - return database.DBName -} - -func (database *SDBInstanceDatabase) GetName() string { - return database.DBName -} - -func (database *SDBInstanceDatabase) GetStatus() string { - switch database.DBStatus { - case "Creating": - return api.DBINSTANCE_DATABASE_CREATING - case "Running": - return api.DBINSTANCE_DATABASE_RUNNING - case "Deleting": - return api.DBINSTANCE_DATABASE_DELETING - } - return database.DBStatus -} - -func (database *SDBInstanceDatabase) GetCharacterSet() string { - return database.CharacterSetName -} - -func (database *SDBInstanceDatabase) Delete() error { - return database.instance.region.DeleteDBInstanceDatabase(database.DBInstanceId, database.DBName) -} - -func (region *SRegion) DeleteDBInstanceDatabase(instanceId string, dbName string) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "DBName": dbName, - } - - _, err := region.rdsRequest("DeleteDatabase", params) - return err -} - -func (region *SRegion) CreateDBInstanceDatabae(instanceId, characterSet, dbName, desc string) error { - params := map[string]string{ - "DBInstanceId": instanceId, - "DBName": dbName, - "CharacterSetName": characterSet, - "DBDescription": desc, - } - - _, err := region.rdsRequest("CreateDatabase", params) - return err - -} - -func (region *SRegion) GetDBInstanceDatabases(instanceId, dbName string, offset int, limit int) ([]SDBInstanceDatabase, int, error) { - if limit > 500 || limit <= 0 { - limit = 500 - } - params := map[string]string{ - "RegionId": region.RegionId, - "PageSize": fmt.Sprintf("%d", limit), - "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), - "DBInstanceId": instanceId, - } - if len(dbName) > 0 { - params["DBName"] = dbName - } - body, err := region.rdsRequest("DescribeDatabases", params) - if err != nil { - return nil, 0, errors.Wrap(err, "DescribeDatabases") - } - databases := []SDBInstanceDatabase{} - err = body.Unmarshal(&databases, "Databases", "Database") - if err != nil { - return nil, 0, errors.Wrap(err, "Unmarshal") - } - total, _ := body.Int("TotalRecordCount") - return databases, int(total), nil -} diff --git a/pkg/multicloud/apsara/dbinstance_privilege.go b/pkg/multicloud/apsara/dbinstance_privilege.go deleted file mode 100644 index 26c0150ee6..0000000000 --- a/pkg/multicloud/apsara/dbinstance_privilege.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" -) - -type SDatabasePrivilege struct { - account *SDBInstanceAccount - - AccountPrivilege string - AccountPrivilegeDetail string - DBName string -} - -func (privilege *SDatabasePrivilege) GetGlobalId() string { - return fmt.Sprintf("%s/%s", privilege.account.GetName(), privilege.DBName) -} - -func (privilege *SDatabasePrivilege) GetPrivilege() string { - switch privilege.AccountPrivilege { - case "ReadWrite": - return api.DATABASE_PRIVILEGE_RW - case "ReadOnly": - return api.DATABASE_PRIVILEGE_R - case "DDLOnly": - return api.DATABASE_PRIVILEGE_DDL - case "DMLOnly": - return api.DATABASE_PRIVILEGE_DML - case "DBOwner": - return api.DATABASE_PRIVILEGE_OWNER - case "Custom": - return api.DBINSTANCE_DATABASE_CREATING - } - return privilege.AccountPrivilege -} - -func (privilege *SDatabasePrivilege) GetDBName() string { - return privilege.DBName -} diff --git a/pkg/multicloud/apsara/disk.go b/pkg/multicloud/apsara/disk.go deleted file mode 100644 index e3e3a655d5..0000000000 --- a/pkg/multicloud/apsara/disk.go +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SMountInstances struct { - MountInstance []string -} - -type STags struct { - Tag []string -} - -type SDisk struct { - multicloud.SResourceBase - multicloud.ApsaraTags - storage *SStorage - multicloud.SDisk - - AttachedTime time.Time - AutoSnapshotPolicyId string - Category string - PerformanceLevel string - CreationTime time.Time - DeleteAutoSnapshot bool - DeleteWithInstance bool - Description string - DetachedTime time.Time - Device string - DiskChargeType TChargeType - DiskId string - DiskName string - EnableAutoSnapshot bool - EnableAutomatedSnapshotPolicy bool - Encrypted bool - ExpiredTime time.Time - ImageId string - InstanceId string - MountInstances SMountInstances - OperationLocks SOperationLocks - Portable bool - ProductCode string - RegionId string - Size int - SourceSnapshotId string - Status string - Tags STags - Type string - ZoneId string - DepartmentInfo -} - -func (self *SRegion) GetDisks(instanceId string, zoneId string, category string, diskIds []string, offset int, limit int) ([]SDisk, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - if len(instanceId) > 0 { - params["InstanceId"] = instanceId - } - if len(zoneId) > 0 { - params["ZoneId"] = zoneId - } - if len(category) > 0 { - params["Category"] = category - } - if diskIds != nil && len(diskIds) > 0 { - params["DiskIds"] = jsonutils.Marshal(diskIds).String() - } - - body, err := self.ecsRequest("DescribeDisks", params) - if err != nil { - log.Errorf("GetDisks fail %s", err) - return nil, 0, err - } - - disks := make([]SDisk, 0) - err = body.Unmarshal(&disks, "Disks", "Disk") - if err != nil { - log.Errorf("Unmarshal disk details fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return disks, int(total), nil -} - -func (self *SDisk) GetId() string { - return self.DiskId -} - -func (self *SDisk) Delete(ctx context.Context) error { - _, err := self.storage.zone.region.getDisk(self.DiskId) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - // 未找到disk, 说明disk已经被删除了. 避免回收站中disk-delete循环删除失败 - return nil - } - log.Errorf("Failed to find disk %s when delete: %s", self.DiskId, err) - return err - } - - for { - err := self.storage.zone.region.DeleteDisk(self.DiskId) - if err != nil { - if isError(err, "IncorrectDiskStatus") { - log.Infof("The disk is initializing, try later ...") - time.Sleep(10 * time.Second) - } else { - log.Errorf("DeleteDisk fail: %s", err) - return err - } - } else { - break - } - } - return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes -} - -func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { - return self.storage.zone.region.resizeDisk(self.DiskId, sizeMb) -} - -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) IsEmulated() bool { - return false -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.storage, nil -} - -func (self *SDisk) GetStatus() string { - // In_use Available Attaching Detaching Creating ReIniting All - switch self.Status { - case "Creating", "ReIniting": - return api.DISK_ALLOCATING - default: - return api.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) ResizeDisk(newSize int64) error { - // newSize 单位为 GB. 范围在20 ~2000. 只能往大调。不能调小 - // https://help.apsara.com/document_detail/25522.html?spm=a2c4g.11174283.6.897.aHwqkS - return self.storage.zone.region.resizeDisk(self.DiskId, newSize) -} - -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 { - switch self.Type { - case "system": - return api.DISK_TYPE_SYS - case "data": - return api.DISK_TYPE_DATA - default: - return api.DISK_TYPE_DATA - } -} - -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 *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, desc string, projectId string) (string, error) { - params := make(map[string]string) - params["ZoneId"] = zoneId - params["DiskName"] = name - if len(desc) > 0 { - params["Description"] = desc - } - params["Encrypted"] = "false" - params["DiskCategory"] = category - if category == api.STORAGE_CLOUD_ESSD_PL2 { - params["DiskCategory"] = api.STORAGE_CLOUD_ESSD - params["PerformanceLevel"] = "PL2" - } - if category == api.STORAGE_CLOUD_ESSD_PL3 { - params["DiskCategory"] = api.STORAGE_CLOUD_ESSD - params["PerformanceLevel"] = "PL3" - } - - if len(projectId) > 0 { - params["ResourceGroupId"] = projectId - } - params["Size"] = fmt.Sprintf("%d", sizeGb) - params["ClientToken"] = utils.GenRequestId(20) - - body, err := self.ecsRequest("CreateDisk", params) - if err != nil { - return "", err - } - return body.GetString("DiskId") -} - -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 { - params := make(map[string]string) - params["DiskId"] = diskId - - _, err := self.ecsRequest("DeleteDisk", params) - return err -} - -func (self *SRegion) resizeDisk(diskId string, sizeMb int64) error { - sizeGb := sizeMb / 1024 - params := make(map[string]string) - params["DiskId"] = diskId - params["NewSize"] = fmt.Sprintf("%d", sizeGb) - - _, err := self.ecsRequest("ResizeDisk", params) - if err != nil { - log.Errorf("resizing disk (%s) to %d GiB failed: %s", diskId, sizeGb, err) - return err - } - - return nil -} - -func (self *SRegion) resetDisk(diskId, snapshotId string) error { - params := make(map[string]string) - params["DiskId"] = diskId - params["SnapshotId"] = snapshotId - _, err := self.ecsRequest("ResetDisk", params) - if err != nil { - log.Errorf("ResetDisk %s to snapshot %s fail %s", diskId, snapshotId, err) - return err - } - - return nil -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name, 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, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil { - return nil, err - } - return snapshot, nil - } -} - -func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["DiskId"] = diskId - params["SnapshotName"] = name - params["Description"] = desc - - if body, err := self.ecsRequest("CreateSnapshot", params); err != nil { - log.Errorf("CreateSnapshot fail %s", err) - return "", err - } else { - return body.GetString("SnapshotId") - } -} - -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) 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 *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) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", self.storage.zone.region.resetDisk(self.DiskId, snapshotId) -} - -func (self *SDisk) GetBillingType() string { - return convertChargeType(self.DiskChargeType) -} - -func (self *SDisk) GetCreatedAt() time.Time { - return self.CreationTime -} - -func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { - if len(self.AutoSnapshotPolicyId) == 0 { - return []string{}, nil - } - return []string{self.AutoSnapshotPolicyId}, nil -} - -func (self *SDisk) GetExpiredAt() time.Time { - return convertExpiredAt(self.ExpiredTime) -} - -func (self *SDisk) GetAccessPath() string { - return "" -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - err := self.storage.zone.region.rebuildDisk(self.DiskId) - if err != nil { - if isError(err, "IncorrectInstanceStatus") { - return nil - } - log.Errorf("rebuild disk fail %s", err) - return err - } - return nil -} - -func (self *SRegion) rebuildDisk(diskId string) error { - params := make(map[string]string) - params["DiskId"] = diskId - _, err := self.ecsRequest("ReInitDisk", params) - if err != nil { - log.Errorf("ReInitDisk %s fail %s", diskId, err) - return err - } - return nil -} diff --git a/pkg/multicloud/apsara/doc.go b/pkg/multicloud/apsara/doc.go deleted file mode 100644 index 1a15fbd3d1..0000000000 --- a/pkg/multicloud/apsara/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara // import "yunion.io/x/onecloud/pkg/multicloud/apsara" diff --git a/pkg/multicloud/apsara/eip.go b/pkg/multicloud/apsara/eip.go deleted file mode 100644 index 726102242e..0000000000 --- a/pkg/multicloud/apsara/eip.go +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type TInternetChargeType string - -const ( - InternetChargeByTraffic = TInternetChargeType("PayByTraffic") - InternetChargeByBandwidth = TInternetChargeType("PayByBandwidth") -) - -const ( - EIP_STATUS_ASSOCIATING = "Associating" - EIP_STATUS_UNASSOCIATING = "Unassociating" - EIP_STATUS_INUSE = "InUse" - EIP_STATUS_AVAILABLE = "Available" - - EIP_OPERATION_LOCK_FINANCIAL = "financial" - EIP_OPERATION_LOCK_SECURITY = "security" - - EIP_INSTANCE_TYPE_ECS = "EcsInstance" // (默认值):VPC类型的ECS实例 - EIP_INTANNCE_TYPE_SLB = "SlbInstance" // :VPC类型的SLB实例 - EIP_INSTANCE_TYPE_NAT = "Nat" // :NAT网关 - EIP_INSTANCE_TYPE_HAVIP = "HaVip" // :HAVIP -) - -/* -{ - "AllocationId":"eip-2zeddtan63ou44dtyt9s3", - "AllocationTime":"2019-02-23T06:48:36Z", - "Bandwidth":"100", - "ChargeType":"PostPaid", - "ExpiredTime":"", - "InstanceId":"", - "InstanceType":"", - "InternetChargeType":"PayByTraffic", - "IpAddress":"39.105.131.32", - "OperationLocks":{"LockReason":[]}, - "RegionId":"cn-beijing", - "Status":"Available" -} -*/ - -type SEipAddress struct { - region *SRegion - multicloud.SEipBase - multicloud.ApsaraTags - - AllocationId string - - InternetChargeType TInternetChargeType - - IpAddress string - Status string - - InstanceType string - InstanceId string - Bandwidth int /* Mbps */ - - AllocationTime time.Time - - OperationLocks string - - ChargeType TChargeType - ExpiredTime time.Time - DepartmentInfo -} - -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 { - case EIP_STATUS_AVAILABLE, EIP_STATUS_INUSE: - return api.EIP_STATUS_READY - case EIP_STATUS_ASSOCIATING: - return api.EIP_STATUS_ASSOCIATE - case EIP_STATUS_UNASSOCIATING: - return api.EIP_STATUS_DISSOCIATE - default: - return api.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 { - // fixed Public IP - return true - } else { - return false - } -} - -func (self *SEipAddress) GetIpAddr() string { - return self.IpAddress -} - -func (self *SEipAddress) GetMode() string { - if self.InstanceId == self.AllocationId { - return api.EIP_MODE_INSTANCE_PUBLICIP - } else { - return api.EIP_MODE_STANDALONE_EIP - } -} - -func (self *SEipAddress) GetAssociationType() string { - switch self.InstanceType { - case EIP_INSTANCE_TYPE_ECS, "NetworkInterface": - return api.EIP_ASSOCIATE_TYPE_SERVER - case EIP_INSTANCE_TYPE_NAT: - return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY - case EIP_INTANNCE_TYPE_SLB: - return api.EIP_ASSOCIATE_TYPE_LOADBALANCER - default: - return self.InstanceType - } -} - -func (self *SEipAddress) GetAssociationExternalId() string { - return self.InstanceId -} - -func (self *SEipAddress) GetBillingType() string { - return convertChargeType(self.ChargeType) -} - -func (self *SEipAddress) GetCreatedAt() time.Time { - return self.AllocationTime -} - -func (self *SEipAddress) GetExpiredAt() time.Time { - return convertExpiredAt(self.ExpiredTime) -} - -func (self *SEipAddress) Delete() error { - return self.region.DeallocateEIP(self.AllocationId) -} - -func (self *SEipAddress) GetBandwidth() int { - return self.Bandwidth -} - -func (self *SEipAddress) GetINetworkId() string { - return "" -} - -func (self *SEipAddress) GetInternetChargeType() string { - switch self.InternetChargeType { - case InternetChargeByTraffic: - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - case InternetChargeByBandwidth: - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH - default: - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - } -} - -func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { - err := cloudprovider.Wait(20*time.Second, 60*time.Second, func() (bool, error) { - err := self.region.AssociateEip(self.AllocationId, conf.InstanceId) - if err != nil { - if isError(err, "IncorrectInstanceStatus") { - return false, nil - } - return false, errors.Wrap(err, "region.AssociateEip") - } - return true, nil - }) - err = cloudprovider.WaitStatus(self, api.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, api.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 (region *SRegion) GetEips(eipId string, associatedId string, offset int, limit int) ([]SEipAddress, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - if len(eipId) > 0 { - params["AllocationId"] = eipId - } - - if len(associatedId) > 0 { - params["AssociatedInstanceId"] = associatedId - for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "ngw-": "Nat", "lb-": "SlbInstance"} { - if strings.HasPrefix(associatedId, prefix) { - params["AssociatedInstanceType"] = instanceType - } - } - } - - body, err := region.vpcRequest("DescribeEipAddresses", params) - if err != nil { - log.Errorf("DescribeEipAddresses fail %s", err) - return nil, 0, err - } - - eips := make([]SEipAddress, 0) - err = body.Unmarshal(&eips, "EipAddresses", "EipAddress") - if err != nil { - log.Errorf("Unmarshal EipAddress details fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - for i := 0; i < len(eips); i += 1 { - eips[i].region = region - } - return eips, int(total), nil -} - -func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { - eips, total, err := region.GetEips(eipId, "", 0, 1) - if err != nil { - return nil, err - } - if total != 1 { - return nil, cloudprovider.ErrNotFound - } - return &eips[0], nil -} - -func (region *SRegion) AllocateEIP(bwMbps int, chargeType TInternetChargeType, projectId string) (*SEipAddress, error) { - params := make(map[string]string) - - params["Bandwidth"] = fmt.Sprintf("%d", bwMbps) - params["InternetChargeType"] = string(chargeType) - params["InstanceChargeType"] = "PostPaid" - params["ClientToken"] = utils.GenRequestId(20) - if len(projectId) > 0 { - params["ResourceGroup"] = projectId - } - - body, err := region.vpcRequest("AllocateEipAddress", params) - if err != nil { - log.Errorf("AllocateEipAddress fail %s", err) - return nil, err - } - - eipId, err := body.GetString("AllocationId") - if err != nil { - log.Errorf("fail to get AllocationId after EIP allocation??? %s", err) - return nil, err - } - - return region.GetEip(eipId) -} - -func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - var ctype TInternetChargeType - switch eip.ChargeType { - case api.EIP_CHARGE_TYPE_BY_TRAFFIC: - ctype = InternetChargeByTraffic - case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: - ctype = InternetChargeByBandwidth - } - return region.AllocateEIP(eip.BandwidthMbps, ctype, eip.ProjectId) -} - -func (region *SRegion) DeallocateEIP(eipId string) error { - params := make(map[string]string) - params["AllocationId"] = eipId - - _, err := region.ecsRequest("ReleaseEipAddress", params) - if err != nil { - log.Errorf("ReleaseEipAddress fail %s", err) - } - return err -} - -func (region *SRegion) AssociateEip(eipId string, instanceId string) error { - params := make(map[string]string) - params["AllocationId"] = eipId - params["InstanceId"] = instanceId - for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "lb-": "SlbInstance", "ngw-": "Nat"} { - if strings.HasPrefix(instanceId, prefix) { - params["InstanceType"] = instanceType - } - } - - _, err := region.ecsRequest("AssociateEipAddress", params) - if err != nil { - log.Errorf("AssociateEipAddress fail %s", err) - } - return err -} - -func (region *SRegion) DissociateEip(eipId string, instanceId string) error { - params := make(map[string]string) - params["AllocationId"] = eipId - params["InstanceId"] = instanceId - for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "lb-": "SlbInstance", "ngw-": "Nat"} { - if strings.HasPrefix(instanceId, prefix) { - params["InstanceType"] = instanceType - } - } - - _, err := region.ecsRequest("UnassociateEipAddress", params) - if err != nil { - log.Errorf("UnassociateEipAddress fail %s", err) - } - return err -} - -func (region *SRegion) UpdateEipBandwidth(eipId string, bw int) error { - params := make(map[string]string) - params["AllocationId"] = eipId - params["Bandwidth"] = fmt.Sprintf("%d", bw) - - _, err := region.ecsRequest("ModifyEipAddressAttribute", params) - if err != nil { - log.Errorf("ModifyEipAddressAttribute fail %s", err) - } - return err -} diff --git a/pkg/multicloud/apsara/elasticcache_account.go b/pkg/multicloud/apsara/elasticcache_account.go deleted file mode 100644 index f78a3b1894..0000000000 --- a/pkg/multicloud/apsara/elasticcache_account.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://help.apsara.com/document_detail/95802.html?spm=a2c4g.11186623.6.746.1d4b302ayCuzXB -type SElasticcacheAccount struct { - multicloud.SElasticcacheAccountBase - multicloud.ApsaraTags - - cacheDB *SElasticcache - - AccountStatus string `json:"AccountStatus"` - DatabasePrivileges DatabasePrivileges `json:"DatabasePrivileges"` - InstanceID string `json:"InstanceId"` - AccountName string `json:"AccountName"` - PrivExceeded string `json:"PrivExceeded"` - AccountType string `json:"AccountType"` -} - -type DatabasePrivileges struct { - DatabasePrivilege []DatabasePrivilege `json:"DatabasePrivilege"` -} - -type DatabasePrivilege struct { - AccountPrivilege string `json:"AccountPrivilege"` -} - -func (self *SElasticcacheAccount) GetId() string { - return fmt.Sprintf("%s/%s", self.InstanceID, self.AccountName) -} - -func (self *SElasticcacheAccount) GetName() string { - return self.AccountName -} - -func (self *SElasticcacheAccount) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheAccount) GetStatus() string { - switch strings.ToLower(self.AccountStatus) { - case "unavailable": - return api.ELASTIC_CACHE_ACCOUNT_STATUS_UNAVAILABLE - case "available": - return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE - default: - return self.AccountStatus - } -} - -func (self *SElasticcacheAccount) Refresh() error { - iaccount, err := self.cacheDB.GetICloudElasticcacheAccountByName(self.GetName()) - if err != nil { - return err - } - - err = jsonutils.Update(self, iaccount.(*SElasticcacheAccount)) - if err != nil { - return err - } - - return nil -} - -func (self *SElasticcacheAccount) GetAccountType() string { - if self.AccountName == self.cacheDB.InstanceID { - return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN - } - - switch self.AccountType { - case "Normal": - return api.ELASTIC_CACHE_ACCOUNT_TYPE_NORMAL - case "Super": - return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN - default: - return self.AccountType - } -} - -func (self *SElasticcacheAccount) GetAccountPrivilege() string { - if len(self.DatabasePrivileges.DatabasePrivilege) == 0 { - return "" - } - - privilege := self.DatabasePrivileges.DatabasePrivilege[0].AccountPrivilege - switch privilege { - case "RoleReadOnly": - return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_READ - case "RoleReadWrite": - return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE - case "RoleRepl": - return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_REPL - default: - return privilege - } -} - -// https://help.apsara.com/document_detail/95941.html?spm=a2c4g.11186623.6.746.523555d8D8Whxq -// https://help.apsara.com/document_detail/98531.html?spm=5176.11065259.1996646101.searchclickresult.4df474c38Sc2SO -func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { - params := make(map[string]string) - params["InstanceId"] = self.cacheDB.GetId() - params["AccountName"] = self.GetName() - params["AccountPassword"] = input.NewPassword - - err := DoAction(self.cacheDB.region.kvsRequest, "ResetAccountPassword", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.ResetPassword") - } - - if input.NoPasswordAccess != nil { - return cloudprovider.ErrNotSupported - } - - return nil -} - -func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { - if input.Password != nil { - inputPassword := cloudprovider.SCloudElasticCacheAccountResetPasswordInput{} - inputPassword.NewPassword = *input.Password - inputPassword.NoPasswordAccess = input.NoPasswordAccess - err := self.ResetPassword(inputPassword) - if err != nil { - return err - } - } - - if input.Description != nil { - err := self.ModifyAccountDescription(*input.Description) - if err != nil { - return err - } - } - - if input.AccountPrivilege != nil { - err := self.GrantAccountPrivilege(*input.AccountPrivilege) - if err != nil { - return err - } - } - - return nil -} - -// https://help.apsara.com/document_detail/96020.html?spm=a2c4g.11186623.6.747.5c6f1c717weYEX -func (self *SElasticcacheAccount) ModifyAccountDescription(desc string) error { - params := make(map[string]string) - params["InstanceId"] = self.cacheDB.GetId() - params["AccountName"] = self.GetName() - params["AccountDescription"] = desc - - err := DoAction(self.cacheDB.region.kvsRequest, "ModifyAccountDescription", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.ModifyAccountDescription") - } - - return nil -} - -// https://help.apsara.com/document_detail/95897.html?spm=a2c4g.11186623.6.745.28576cf9IqM44R -func (self *SElasticcacheAccount) GrantAccountPrivilege(privilege string) error { - params := make(map[string]string) - params["InstanceId"] = self.cacheDB.GetId() - params["AccountName"] = self.GetName() - params["AccountPrivilege"] = privilege - - err := DoAction(self.cacheDB.region.kvsRequest, "GrantAccountPrivilege", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.GrantAccountPrivilege") - } - - return nil -} - -// https://help.apsara.com/document_detail/95988.html?spm=a2c4g.11186623.6.743.cb291c71D1Hlmu -func (self *SElasticcacheAccount) Delete() error { - params := make(map[string]string) - params["InstanceId"] = self.cacheDB.GetId() - params["AccountName"] = self.GetName() - - err := DoAction(self.cacheDB.region.kvsRequest, "DeleteAccount", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.Delete") - } - - return nil -} diff --git a/pkg/multicloud/apsara/elasticcache_acl.go b/pkg/multicloud/apsara/elasticcache_acl.go deleted file mode 100644 index 771bf6e469..0000000000 --- a/pkg/multicloud/apsara/elasticcache_acl.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElasticcacheAcl struct { - multicloud.SElasticcacheAclBase - multicloud.ApsaraTags - - cacheDB *SElasticcache - - SecurityIPList string `json:"SecurityIpList"` - SecurityIPGroupAttribute string `json:"SecurityIpGroupAttribute"` - SecurityIPGroupName string `json:"SecurityIpGroupName"` -} - -func (self *SElasticcacheAcl) GetId() string { - return fmt.Sprintf("%s/%s", self.cacheDB.GetId(), self.SecurityIPGroupName) -} - -func (self *SElasticcacheAcl) GetName() string { - return self.SecurityIPGroupName -} - -func (self *SElasticcacheAcl) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheAcl) GetStatus() string { - return api.ELASTIC_CACHE_ACL_STATUS_AVAILABLE -} - -func (self *SElasticcacheAcl) Refresh() error { - iacl, err := self.cacheDB.GetICloudElasticcacheAcl(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, iacl.(*SElasticcacheAcl)) - if err != nil { - return err - } - - return nil -} - -func (self *SElasticcacheAcl) GetIpList() string { - return self.SecurityIPList -} - -// https://help.apsara.com/document_detail/61002.html?spm=a2c4g.11186623.6.764.3752782fJpbjxH -func (self *SElasticcacheAcl) Delete() error { - params := make(map[string]string) - params["InstanceId"] = self.cacheDB.GetId() - params["ModifyMode"] = "Delete" - params["SecurityIpGroupName"] = self.GetName() - params["SecurityIps"] = self.SecurityIPList - - err := DoAction(self.cacheDB.region.kvsRequest, "ModifySecurityIps", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAcl.Delete") - } - - return nil -} - -// https://help.apsara.com/document_detail/61002.html?spm=a2c4g.11186623.6.764.3752782fJpbjxH -func (self *SElasticcacheAcl) UpdateAcl(securityIps string) error { - return self.cacheDB.region.createAcl(self.cacheDB.GetId(), self.GetName(), securityIps) -} - -func (self *SRegion) createAcl(instanceId, aclName, securityIps string) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["SecurityIpGroupName"] = aclName - params["ModifyMode"] = "Cover" - params["SecurityIps"] = securityIps - - err := DoAction(self.kvsRequest, "ModifySecurityIps", params, nil, nil) - if err != nil { - return errors.Wrap(err, "region.UpdateAcl") - } - - return nil -} diff --git a/pkg/multicloud/apsara/elasticcache_backup.go b/pkg/multicloud/apsara/elasticcache_backup.go deleted file mode 100644 index 2b7d6c691d..0000000000 --- a/pkg/multicloud/apsara/elasticcache_backup.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://help.apsara.com/document_detail/61081.html?spm=a2c4g.11186623.6.752.3d7630beuL57kI -type SElasticcacheBackup struct { - multicloud.SElasticcacheBackupBase - multicloud.ApsaraTags - - cacheDB *SElasticcache - - BackupIntranetDownloadURL string `json:"BackupIntranetDownloadURL"` - BackupType string `json:"BackupType"` - BackupEndTime time.Time `json:"BackupEndTime"` - BackupMethod string `json:"BackupMethod"` - BackupID int64 `json:"BackupId"` - BackupStartTime time.Time `json:"BackupStartTime"` - BackupDownloadURL string `json:"BackupDownloadURL"` - BackupDBNames string `json:"BackupDBNames"` - NodeInstanceID string `json:"NodeInstanceId"` - BackupMode string `json:"BackupMode"` - BackupStatus string `json:"BackupStatus"` - BackupSizeByte int64 `json:"BackupSize"` - EngineVersion string `json:"EngineVersion"` -} - -func (self *SElasticcacheBackup) GetId() string { - return fmt.Sprintf("%d", self.BackupID) -} - -func (self *SElasticcacheBackup) GetName() string { - return self.GetId() -} - -func (self *SElasticcacheBackup) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheBackup) GetStatus() string { - switch self.BackupStatus { - case "Success", "running": - return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS - case "Failed": - return api.ELASTIC_CACHE_BACKUP_STATUS_FAILED - default: - return self.BackupStatus - } -} - -func (self *SElasticcacheBackup) Refresh() error { - ibackup, err := self.cacheDB.GetICloudElasticcacheBackup(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, ibackup.(*SElasticcacheBackup)) - if err != nil { - return err - } - - return nil -} - -func (self *SElasticcacheBackup) GetBackupSizeMb() int { - return int(self.BackupSizeByte / 1024 / 1024) -} - -func (self *SElasticcacheBackup) GetBackupType() string { - switch self.BackupType { - case "FullBackup": - return api.ELASTIC_CACHE_BACKUP_TYPE_FULL - case "IncrementalBackup": - return api.ELASTIC_CACHE_BACKUP_TYPE_INCREMENTAL - default: - return self.BackupType - } -} - -func (self *SElasticcacheBackup) GetBackupMode() string { - switch self.BackupMode { - case "Automated": - return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED - case "Manual": - return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL - default: - return self.BackupMode - } -} - -func (self *SElasticcacheBackup) GetDownloadURL() string { - return self.BackupDownloadURL -} - -func (self *SElasticcacheBackup) GetStartTime() time.Time { - return self.BackupStartTime -} - -func (self *SElasticcacheBackup) GetEndTime() time.Time { - return self.BackupEndTime -} - -func (self *SElasticcacheBackup) Delete() error { - return cloudprovider.ErrNotSupported -} - -// https://help.apsara.com/document_detail/61083.html?spm=a2c4g.11186623.6.753.216f67ddzpyvTL -func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["BackupId"] = self.GetId() - - // 目前没有查询备份ID的接口,因此,备份ID没什么用 - err := DoAction(self.cacheDB.region.kvsRequest, "RestoreInstance", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.RestoreInstance") - } - - return nil -} diff --git a/pkg/multicloud/apsara/elasticcache_instance.go b/pkg/multicloud/apsara/elasticcache_instance.go deleted file mode 100644 index 64701371be..0000000000 --- a/pkg/multicloud/apsara/elasticcache_instance.go +++ /dev/null @@ -1,941 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strconv" - "strings" - "time" - - "github.com/aokoli/goutils" - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - billingapi "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -// https://help.apsara.com/document_detail/60933.html?spm=a2c4g.11186623.6.726.38f82ca9U1Gtxw -type SElasticcache struct { - multicloud.SElasticcacheBase - multicloud.SBillingBase - multicloud.ApsaraTags - - region *SRegion - attribute *SElasticcacheAttribute - netinfo []SNetInfo - - Config string `json:"Config"` - HasRenewChangeOrder bool `json:"HasRenewChangeOrder"` - InstanceID string `json:"InstanceId"` - UserName string `json:"UserName"` - ArchitectureType string `json:"ArchitectureType"` - ZoneID string `json:"ZoneId"` - PrivateIP string `json:"PrivateIp"` - VSwitchID string `json:"VSwitchId"` - VpcID string `json:"VpcId"` - NetworkType string `json:"NetworkType"` - Qps int64 `json:"QPS"` - PackageType string `json:"PackageType"` - IsRDS bool `json:"IsRds"` - EngineVersion string `json:"EngineVersion"` - ConnectionDomain string `json:"ConnectionDomain"` - InstanceName string `json:"InstanceName"` - ReplacateID string `json:"ReplacateId"` - Bandwidth int64 `json:"Bandwidth"` - ChargeType TChargeType `json:"ChargeType"` - InstanceType string `json:"InstanceType"` - Tags Tags `json:"Tags"` - InstanceStatus string `json:"InstanceStatus"` - Port int `json:"Port"` - InstanceClass string `json:"InstanceClass"` - CreateTime time.Time `json:"CreateTime"` - EndTime time.Time `json:"EndTime"` - RegionID string `json:"RegionId"` - NodeType string `json:"NodeType"` - CapacityMB int `json:"Capacity"` - Connections int64 `json:"Connections"` - - DepartmentInfo -} - -type SElasticcacheAttribute struct { - Config string `json:"Config"` - HasRenewChangeOrder string `json:"HasRenewChangeOrder"` - InstanceID string `json:"InstanceId"` - ZoneID string `json:"ZoneId"` - ArchitectureType string `json:"ArchitectureType"` - PrivateIP string `json:"PrivateIp"` - VSwitchID string `json:"VSwitchId"` - Engine string `json:"Engine"` - VpcID string `json:"VpcId"` - NetworkType string `json:"NetworkType"` - Qps int64 `json:"QPS"` - PackageType string `json:"PackageType"` - ReplicaID string `json:"ReplicaId"` - IsRDS bool `json:"IsRds"` - MaintainStartTime string `json:"MaintainStartTime"` - VpcAuthMode string `json:"VpcAuthMode"` - ConnectionDomain string `json:"ConnectionDomain"` - EngineVersion string `json:"EngineVersion"` - InstanceName string `json:"InstanceName"` - Bandwidth int64 `json:"Bandwidth"` - ChargeType TChargeType `json:"ChargeType"` - AuditLogRetention string `json:"AuditLogRetention"` - MaintainEndTime string `json:"MaintainEndTime"` - ReplicationMode string `json:"ReplicationMode"` - InstanceType string `json:"InstanceType"` - InstanceStatus string `json:"InstanceStatus"` - Tags Tags `json:"Tags"` - Port int64 `json:"Port"` - InstanceClass string `json:"InstanceClass"` - CreateTime time.Time `json:"CreateTime"` - NodeType string `json:"NodeType"` - RegionID string `json:"RegionId"` - AvailabilityValue string `json:"AvailabilityValue"` - CapacityMB int `json:"Capacity"` - Connections int64 `json:"Connections"` - SecurityIPList string `json:"SecurityIPList"` -} - -type SNetInfo struct { - ConnectionString string `json:"ConnectionString"` - Port string `json:"Port"` - DBInstanceNetType string `json:"DBInstanceNetType"` - VPCID string `json:"VPCId"` - VPCInstanceID string `json:"VPCInstanceId"` - IPAddress string `json:"IPAddress"` - IPType string `json:"IPType"` - Upgradeable string `json:"Upgradeable"` - ExpiredTime *string `json:"ExpiredTime,omitempty"` -} - -func (self *SElasticcache) GetId() string { - return self.InstanceID -} - -func (self *SElasticcache) GetName() string { - return self.InstanceName -} - -func (self *SElasticcache) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcache) GetStatus() string { - switch self.InstanceStatus { - case "Normal": - return api.ELASTIC_CACHE_STATUS_RUNNING - case "Creating": - return api.ELASTIC_CACHE_STATUS_DEPLOYING - case "Changing": - return api.ELASTIC_CACHE_STATUS_CHANGING - case "Inactive": - return api.ELASTIC_CACHE_STATUS_INACTIVE - case "Flushing": - return api.ELASTIC_CACHE_STATUS_FLUSHING - case "Released": - return api.ELASTIC_CACHE_STATUS_RELEASED - case "Transforming": - return api.ELASTIC_CACHE_STATUS_TRANSFORMING - case "Unavailable": - return api.ELASTIC_CACHE_STATUS_UNAVAILABLE - case "Error": - return api.ELASTIC_CACHE_STATUS_ERROR - case "Migrating": - return api.ELASTIC_CACHE_STATUS_MIGRATING - case "BackupRecovering": - return api.ELASTIC_CACHE_STATUS_BACKUPRECOVERING - case "MinorVersionUpgrading": - return api.ELASTIC_CACHE_STATUS_MINORVERSIONUPGRADING - case "NetworkModifying": - return api.ELASTIC_CACHE_STATUS_NETWORKMODIFYING - case "SSLModifying": - return api.ELASTIC_CACHE_STATUS_SSLMODIFYING - case "MajorVersionUpgrading": - return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING - default: - return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING - } -} - -func (self *SElasticcache) Refresh() error { - cache, err := self.region.GetElasticCacheById(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, cache) - if err != nil { - return err - } - - return nil -} - -func (self *SElasticcache) GetBillingType() string { - return convertChargeType(self.ChargeType) -} - -func (self *SElasticcache) GetCreatedAt() time.Time { - return self.CreateTime -} - -func (self *SElasticcache) GetExpiredAt() time.Time { - return convertExpiredAt(self.EndTime) -} - -func (self *SElasticcache) GetInstanceType() string { - return self.InstanceClass -} - -func (self *SElasticcache) GetCapacityMB() int { - return self.CapacityMB -} - -func (self *SElasticcache) GetArchType() string { - switch self.ArchitectureType { - case "rwsplit": - return api.ELASTIC_CACHE_ARCH_TYPE_RWSPLIT - case "cluster": - return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER - case "standard": - if self.NodeType == "single" { - return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE - } else if self.NodeType == "double" { - return api.ELASTIC_CACHE_ARCH_TYPE_MASTER - } - } - - return "" -} - -func (self *SElasticcache) GetNodeType() string { - return self.NodeType -} - -func (self *SElasticcache) GetEngine() string { - return self.InstanceType -} - -func (self *SElasticcache) GetEngineVersion() string { - return self.EngineVersion -} - -func (self *SElasticcache) GetVpcId() string { - return self.VpcID -} - -func (self *SElasticcache) GetZoneId() string { - zone, err := self.region.getZoneById(self.ZoneID) - if err != nil { - log.Errorf("failed to find zone for elasticcache %s error: %v", self.GetId(), err) - return "" - } - return zone.GetGlobalId() -} - -func (self *SElasticcache) GetNetworkType() string { - switch self.NetworkType { - case "VPC": - return api.LB_NETWORK_TYPE_VPC - case "CLASSIC": - return api.LB_NETWORK_TYPE_CLASSIC - default: - return api.LB_NETWORK_TYPE_VPC - } -} - -func (self *SElasticcache) GetNetworkId() string { - return self.VSwitchID -} - -func (self *SElasticcache) GetPrivateDNS() string { - return self.ConnectionDomain -} - -func (self *SElasticcache) GetPrivateIpAddr() string { - return self.PrivateIP -} - -func (self *SElasticcache) GetPrivateConnectPort() int { - return self.Port -} - -func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetPublicDNS() string { - pub, err := self.GetPublicNetInfo() - if err != nil { - log.Errorf("SElasticcache.GetPublicDNS %s", err) - return "" - } - - if pub != nil { - return pub.ConnectionString - } - - return "" -} - -func (self *SElasticcache) GetPublicIpAddr() string { - pub, err := self.GetPublicNetInfo() - if err != nil { - log.Errorf("SElasticcache.GetPublicIpAddr %s", err) - } - - if pub != nil { - return pub.IPAddress - } - - return "" -} - -func (self *SElasticcache) GetPublicConnectPort() int { - pub, err := self.GetPublicNetInfo() - if err != nil { - log.Errorf("SElasticcache.GetPublicConnectPort %s", err) - } - - if pub != nil { - port, _ := strconv.Atoi(pub.Port) - return port - } - - return 0 -} - -func (self *SElasticcache) GetMaintainStartTime() string { - attr, err := self.GetAttribute() - if err != nil { - log.Errorf("SElasticcache.GetMaintainStartTime %s", err) - } - - if attr != nil { - return attr.MaintainStartTime - } - - return "" -} - -func (self *SElasticcache) GetMaintainEndTime() string { - attr, err := self.GetAttribute() - if err != nil { - log.Errorf("SElasticcache.GetMaintainEndTime %s", err) - } - - if attr != nil { - return attr.MaintainEndTime - } - - return "" -} - -func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { - accounts, err := self.region.GetElasticCacheAccounts(self.GetId()) - if err != nil { - return nil, err - } - - iaccounts := make([]cloudprovider.ICloudElasticcacheAccount, len(accounts)) - for i := range accounts { - accounts[i].cacheDB = self - iaccounts[i] = &accounts[i] - } - - return iaccounts, nil -} - -func (self *SElasticcache) GetICloudElasticcacheAccountByName(accountName string) (cloudprovider.ICloudElasticcacheAccount, error) { - account, err := self.region.GetElasticCacheAccountByName(self.GetId(), accountName) - if err != nil { - return nil, err - } - - account.cacheDB = self - return account, nil -} - -func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { - acls, err := self.region.GetElasticCacheAcls(self.GetId()) - if err != nil { - return nil, err - } - - iacls := make([]cloudprovider.ICloudElasticcacheAcl, len(acls)) - for i := range acls { - acls[i].cacheDB = self - iacls[i] = &acls[i] - } - - return iacls, nil -} - -func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { - start := self.CreateTime.Format("2006-01-02T15:04Z") - end := time.Now().Format("2006-01-02T15:04Z") - backups, err := self.region.GetElasticCacheBackups(self.GetId(), start, end) - if err != nil { - return nil, err - } - - ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) - for i := range backups { - backups[i].cacheDB = self - ibackups[i] = &backups[i] - } - - return ibackups, nil -} - -func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { - parameters, err := self.region.GetElasticCacheParameters(self.GetId()) - if err != nil { - return nil, err - } - - iparameters := make([]cloudprovider.ICloudElasticcacheParameter, len(parameters)) - for i := range parameters { - parameters[i].cacheDB = self - iparameters[i] = ¶meters[i] - } - - return iparameters, nil -} - -func (self *SElasticcache) GetAttribute() (*SElasticcacheAttribute, error) { - if self.attribute != nil { - return self.attribute, nil - } - - params := make(map[string]string) - params["RegionId"] = self.region.RegionId - params["InstanceId"] = self.GetId() - - rets := []SElasticcacheAttribute{} - err := DoListAll(self.region.kvsRequest, "DescribeInstanceAttribute", params, []string{"Instances", "DBInstanceAttribute"}, &rets) - if err != nil { - return nil, errors.Wrap(err, "elasticcache.GetAttribute") - } - - count := len(rets) - if count >= 1 { - self.attribute = &rets[0] - return self.attribute, nil - } else { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "elasticcache.GetAttribute %s", self.GetId()) - } -} - -func (self *SElasticcache) GetNetInfo() ([]SNetInfo, error) { - params := make(map[string]string) - params["RegionId"] = self.region.RegionId - params["InstanceId"] = self.GetId() - - rets := []SNetInfo{} - err := DoListAll(self.region.kvsRequest, "DescribeDBInstanceNetInfo", params, []string{"NetInfoItems", "InstanceNetInfo"}, &rets) - if err != nil { - return nil, errors.Wrap(err, "elasticcache.GetNetInfo") - } - - self.netinfo = rets - return self.netinfo, nil -} - -// https://help.apsara.com/document_detail/66742.html?spm=a2c4g.11186623.6.731.54c123d2P02qhk -func (self *SElasticcache) GetPublicNetInfo() (*SNetInfo, error) { - nets, err := self.GetNetInfo() - if err != nil { - return nil, err - } - - for i := range nets { - if nets[i].IPType == "Public" { - return &nets[i], nil - } - } - - return nil, nil -} - -func (self *SRegion) GetElasticCaches(instanceIds []string) ([]SElasticcache, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - if instanceIds != nil && len(instanceIds) > 0 { - params["InstanceIds"] = strings.Join(instanceIds, ",") - } - - ret := []SElasticcache{} - err := DoListAll(self.kvsRequest, "DescribeInstances", params, []string{"Instances", "KVStoreInstance"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCaches") - } - - for i := range ret { - ret[i].region = self - } - - return ret, nil -} - -func (self *SRegion) GetElasticCacheById(instanceId string) (*SElasticcache, error) { - caches, err := self.GetElasticCaches([]string{instanceId}) - if err != nil { - return nil, errors.Wrapf(err, "region.GetElasticCacheById %s", instanceId) - } - - if len(caches) == 1 { - return &caches[0], nil - } else if len(caches) == 0 { - return nil, cloudprovider.ErrNotFound - } else { - return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "region.GetElasticCacheById %s.expect 1 found %d ", instanceId, len(caches)) - } -} - -func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { - ec, err := self.GetElasticCacheById(id) - if err != nil { - return nil, err - } - - return ec, nil -} - -// https://help.apsara.com/document_detail/95802.html?spm=a2c4g.11186623.6.746.143e782f3Pfkfg -func (self *SRegion) GetElasticCacheAccounts(instanceId string) ([]SElasticcacheAccount, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - - ret := []SElasticcacheAccount{} - err := DoListAll(self.kvsRequest, "DescribeAccounts", params, []string{"Accounts", "Account"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCacheAccounts") - } - - return ret, nil -} - -func (self *SRegion) GetElasticCacheAccountByName(instanceId string, accountName string) (*SElasticcacheAccount, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - params["AccountName"] = accountName - - ret := []SElasticcacheAccount{} - err := DoListAll(self.kvsRequest, "DescribeAccounts", params, []string{"Accounts", "Account"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCacheAccounts") - } - - if len(ret) == 1 { - return &ret[0], nil - } else if len(ret) == 0 { - return nil, cloudprovider.ErrNotFound - } else { - return nil, errors.Wrap(fmt.Errorf("%d account with name %s found", len(ret), accountName), "region.GetElasticCacheAccountByName") - } -} - -// https://help.apsara.com/document_detail/63889.html?spm=a2c4g.11186623.6.764.3cb43852R7lnoS -func (self *SRegion) GetElasticCacheAcls(instanceId string) ([]SElasticcacheAcl, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - - ret := []SElasticcacheAcl{} - err := DoListAll(self.kvsRequest, "DescribeSecurityIps", params, []string{"SecurityIpGroups", "SecurityIpGroup"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCacheAcls") - } - - return ret, nil -} - -// https://help.apsara.com/document_detail/61081.html?spm=a2c4g.11186623.6.754.10613852qAbEQV -func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - params["StartTime"] = startTime - params["EndTime"] = endTime - - ret := []SElasticcacheBackup{} - err := DoListAll(self.kvsRequest, "DescribeBackups", params, []string{"Backups", "Backup"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCacheBackups") - } - - return ret, nil -} - -// https://help.apsara.com/document_detail/93078.html?spm=a2c4g.11186623.6.769.58011975YYL5Gl -func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["DBInstanceId"] = instanceId - - ret := []SElasticcacheParameter{} - err := DoListAll(self.kvsRequest, "DescribeParameters", params, []string{"RunningParameters", "Parameter"}, &ret) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCacheParameters") - } - - return ret, nil -} - -// https://help.apsara.com/document_detail/60873.html?spm=a2c4g.11174283.6.715.7412dce0qSYemb -func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceClass"] = ec.InstanceType - params["InstanceName"] = ec.InstanceName - params["InstanceType"] = ec.Engine - params["EngineVersion"] = ec.EngineVersion - - if len(ec.Password) > 0 { - params["UserName"] = ec.UserName - params["Password"] = ec.Password - } - - if len(ec.ZoneIds) > 0 { - params["ZoneId"] = ec.ZoneIds[0] - } - - if len(ec.PrivateIpAddress) > 0 { - params["PrivateIpAddress"] = ec.PrivateIpAddress - } - - if len(ec.NodeType) > 0 { - params["NodeType"] = ec.NodeType - } - - if len(ec.ProjectId) > 0 { - params["ResourceGroupId"] = ec.ProjectId - } - - params["NetworkType"] = ec.NetworkType - params["VpcId"] = ec.VpcId - params["VSwitchId"] = ec.NetworkId - params["ChargeType"] = ec.ChargeType - if strings.ToLower(ec.ChargeType) == billingapi.BILLING_TYPE_PREPAID && ec.BillingCycle != nil { - if ec.BillingCycle.GetMonths() >= 1 && ec.BillingCycle.GetMonths() <= 9 { - params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths()) - } else if ec.BillingCycle.GetMonths() == 12 || ec.BillingCycle.GetMonths() == 24 || ec.BillingCycle.GetMonths() == 36 { - params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths()) - } else { - return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") - } - } - - ret := &SElasticcache{} - err := DoAction(self.kvsRequest, "CreateInstance", params, []string{}, ret) - if err != nil { - return nil, errors.Wrap(err, "region.CreateIElasticcaches") - } - self.SetResourceTags("kvs", "INSTANCE", []string{ret.InstanceID}, ec.Tags, false) - - ret.region = self - return ret, nil -} - -// https://help.apsara.com/document_detail/116215.html?spm=a2c4g.11174283.6.736.6b9ddce0c5nsw6 -func (self *SElasticcache) Restart() error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["EffectiveTime"] = "0" // 立即重启 - - err := DoAction(self.region.kvsRequest, "RestartInstance", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.Restart") - } - - return nil -} - -// https://help.apsara.com/document_detail/60898.html?spm=a2c4g.11186623.6.713.56ec1603KS0xA0 -func (self *SElasticcache) Delete() error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - - err := DoAction(self.region.kvsRequest, "DeleteInstance", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.Delete") - } - - return nil -} - -// https://help.apsara.com/document_detail/60903.html?spm=a2c4g.11186623.6.711.3f062c92aRJNfw -func (self *SElasticcache) ChangeInstanceSpec(spec string) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["InstanceClass"] = strings.Split(spec, ":")[0] - params["AutoPay"] = "true" // 自动付款 - - err := DoAction(self.region.kvsRequest, "ModifyInstanceSpec", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.ChangeInstanceSpec") - } - - return nil -} - -// https://help.apsara.com/document_detail/61000.html?spm=a2c4g.11186623.6.730.57d66cb0QlQS86 -func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["MaintainStartTime"] = maintainStartTime - params["MaintainEndTime"] = maintainEndTime - - err := DoAction(self.region.kvsRequest, "ModifyInstanceMaintainTime", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.SetMaintainTime") - } - - return nil -} - -// https://help.apsara.com/document_detail/125795.html?spm=a2c4g.11186623.6.719.51542b3593cDKO -func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { - if port < 1024 { - port = 6379 - } - - suffix, _ := goutils.RandomAlphabetic(4) - conn := self.GetId() + strings.ToLower(suffix) - - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["Port"] = strconv.Itoa(port) - params["ConnectionStringPrefix"] = conn - - err := DoAction(self.region.kvsRequest, "AllocateInstancePublicConnection", params, nil, nil) - if err != nil { - return "", errors.Wrap(err, "elasticcache.AllocatePublicConnection") - } - - return conn, nil -} - -// https://help.apsara.com/document_detail/125796.html?spm=a2c4g.11186623.6.720.702a3b23Qayopy -func (self *SElasticcache) ReleasePublicConnection() error { - publicConn := self.GetPublicDNS() - if len(publicConn) == 0 { - log.Debugf("elasticcache.ReleasePublicConnection public connect is empty") - return nil - } - - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["CurrentConnectionString"] = publicConn - - err := DoAction(self.region.kvsRequest, "ReleaseInstancePublicConnection", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.ReleasePublicConnection") - } - - return nil -} - -// https://help.apsara.com/document_detail/93603.html?spm=a2c4g.11186623.6.732.10666cf9UVgNPb 修改链接地址 - -// https://help.apsara.com/document_detail/95973.html?spm=a2c4g.11186623.6.742.4698126aH0s4Q5 -func (self *SElasticcache) CreateAccount(input cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["AccountName"] = input.AccountName - params["AccountPassword"] = input.AccountPassword - if len(input.AccountPrivilege) > 0 { - params["AccountPrivilege"] = input.AccountPrivilege - } - - if len(input.Description) > 0 { - params["AccountDescription"] = input.Description - } - - err := DoAction(self.region.kvsRequest, "CreateAccount", params, nil, nil) - if err != nil { - return nil, errors.Wrap(err, "elasticcache.CreateAccount") - } - - return self.GetICloudElasticcacheAccountByName(input.AccountName) -} - -func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { - acl := &SElasticcacheAcl{} - acl.cacheDB = self - acl.SecurityIPGroupName = aclName - acl.SecurityIPList = securityIps - return acl, self.region.createAcl(self.GetId(), aclName, securityIps) -} - -// https://help.apsara.com/document_detail/61113.html?spm=a2c4g.11186623.6.770.16a61e7admr0xy -func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["Config"] = config.String() - - err := DoAction(self.region.kvsRequest, "ModifyInstanceConfig", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") - } - - return nil -} - -// https://help.apsara.com/document_detail/61075.html?spm=a2c4g.11186623.6.749.4cba126a2U9xNa -func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - - // 目前没有查询备份ID的接口,因此,备份ID没什么用 - err := DoAction(self.region.kvsRequest, "CreateBackup", params, []string{"BackupJobID"}, nil) - if err != nil { - return nil, errors.Wrap(err, "elasticcache.CreateBackup") - } - - return nil, nil -} - -// https://help.apsara.com/document_detail/61077.html?spm=a2c4g.11186623.6.750.3d7630be7ziUfg -func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - params["PreferredBackupPeriod"] = config.PreferredBackupPeriod - params["PreferredBackupTime"] = config.PreferredBackupTime - - err := DoAction(self.region.kvsRequest, "ModifyBackupPolicy", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.UpdateBackupPolicy") - } - - return nil -} - -// https://help.apsara.com/document_detail/60931.html?spm=a2c4g.11186623.6.728.5c57292920UKx3 -func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - - err := DoAction(self.region.kvsRequest, "FlushInstance", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.FlushInstance") - } - - return nil -} - -// https://help.apsara.com/document_detail/98531.html?spm=5176.11065259.1996646101.searchclickresult.4df474c38Sc2SO -func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool, password string) error { - params := make(map[string]string) - params["InstanceId"] = self.GetId() - if noPwdAccess { - params["VpcAuthMode"] = "Close" - } else { - params["VpcAuthMode"] = "Open" - } - - err := DoAction(self.region.kvsRequest, "ModifyInstanceVpcAuthMode", params, nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.UpdateAuthMode") - } - - return nil -} - -func (self *SElasticcache) GetAuthMode() string { - attribute, err := self.GetAttribute() - if err != nil { - log.Errorf("elasticcache.GetAuthMode %s", err) - } - switch attribute.VpcAuthMode { - case "Open": - return "on" - default: - return "off" - } -} - -func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { - segs := strings.Split(accountId, "/") - if len(segs) < 2 { - return nil, errors.Wrap(fmt.Errorf("%s", accountId), "elasticcache.GetICloudElasticcacheAccount invalid account id ") - } - - return self.GetICloudElasticcacheAccountByName(segs[1]) -} - -func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { - acls, err := self.GetICloudElasticcacheAcls() - if err != nil { - return nil, err - } - - for _, acl := range acls { - if acl.GetId() == aclId { - return acl, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { - backups, err := self.GetICloudElasticcacheBackups() - if err != nil { - return nil, err - } - - for _, backup := range backups { - if backup.GetId() == backupId { - return backup, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (instance *SElasticcache) GetTags() (map[string]string, error) { - tags, err := instance.region.ListResourceTags("kvs", "INSTANCE", []string{instance.GetId()}) - if err != nil { - return nil, errors.Wrap(err, "instance.region.ListResourceTags") - } - if _, ok := tags[instance.GetId()]; !ok { - return map[string]string{}, nil - } - return *tags[instance.GetId()], nil -} - -func (instance *SElasticcache) SetTags(tags map[string]string, replace bool) error { - return instance.region.SetResourceTags(APSARA_PRODUCT_KVSTORE, "INSTANCE", []string{instance.GetId()}, tags, replace) -} - -func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { - return errors.Wrap(cloudprovider.ErrNotSupported, "UpdateSecurityGroups") -} diff --git a/pkg/multicloud/apsara/elasticcache_parameter.go b/pkg/multicloud/apsara/elasticcache_parameter.go deleted file mode 100644 index af13078bb4..0000000000 --- a/pkg/multicloud/apsara/elasticcache_parameter.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElasticcacheParameter struct { - multicloud.SElasticcacheParameterBase - multicloud.ApsaraTags - - cacheDB *SElasticcache - - ParameterDescription string `json:"ParameterDescription"` - ParameterValue string `json:"ParameterValue"` - ForceRestart string `json:"ForceRestart"` - CheckingCode string `json:"CheckingCode"` - ModifiableStatus string `json:"ModifiableStatus"` - ParameterName string `json:"ParameterName"` -} - -func (self *SElasticcacheParameter) GetId() string { - return fmt.Sprintf("%s/%s", self.cacheDB.InstanceID, self.ParameterName) -} - -func (self *SElasticcacheParameter) GetName() string { - return self.ParameterName -} - -func (self *SElasticcacheParameter) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheParameter) GetStatus() string { - return api.ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE -} - -func (self *SElasticcacheParameter) GetParameterKey() string { - return self.ParameterName -} - -func (self *SElasticcacheParameter) GetParameterValue() string { - return self.ParameterValue -} - -func (self *SElasticcacheParameter) GetParameterValueRange() string { - return self.CheckingCode -} - -func (self *SElasticcacheParameter) GetDescription() string { - return self.ParameterDescription -} - -func (self *SElasticcacheParameter) GetModifiable() bool { - switch self.ModifiableStatus { - case "true": - return true - default: - return false - } -} - -func (self *SElasticcacheParameter) GetForceRestart() bool { - switch self.ForceRestart { - case "true": - return true - default: - return false - } -} diff --git a/pkg/multicloud/apsara/host.go b/pkg/multicloud/apsara/host.go deleted file mode 100644 index a1d25778bf..0000000000 --- a/pkg/multicloud/apsara/host.go +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone -} - -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) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms := make([]SInstance, 0) - for { - parts, total, err := self.zone.region.GetInstances(self.zone.ZoneId, nil, len(vms), 50) - if err != nil { - return nil, err - } - vms = append(vms, parts...) - if len(vms) >= total { - break - } - } - 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) VMGlobalId2Id(gid string) string { - return gid -} - -func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) { - id := self.VMGlobalId2Id(gid) - parts, _, err := self.zone.region.GetInstances(self.zone.ZoneId, []string{id}, 0, 1) - if err != nil { - return nil, err - } - if len(parts) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(parts) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - parts[0].host = self - return &parts[0], nil -} - -func (self *SHost) GetId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) GetName() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) -} - -func (self *SHost) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) IsEmulated() bool { - return true -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) Refresh() error { - return nil -} - -func (self *SHost) GetHostStatus() string { - return api.HOST_ONLINE -} - -func (self *SHost) GetEnabled() bool { - return true -} - -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_APSARA), "manufacture") - return info -} - -func (self *SHost) GetSN() string { - return "" -} - -func (self *SHost) GetCpuCount() int { - 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 api.DISK_TYPE_HYBRID -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_APSARA -} - -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(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - vmId, err := self._createVM(desc.Name, desc.Hostname, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, - desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, - desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, desc.UserData, desc.BillingCycle, - desc.ProjectId, desc.OsType, desc.Tags) - if err != nil { - return nil, err - } - vm, err := self.GetInstanceById(vmId) - if err != nil { - return nil, err - } - // err = vm.waitStatus(InstanceStatusStopped, time.Second*10, time.Second*1800) - return vm, err -} - -func (self *SHost) _createVM(name, hostname string, imgId string, - sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, - vswitchId string, ipAddr string, desc string, passwd string, - dataDisks []cloudprovider.SDiskInfo, publicKey string, secgroupId string, - userData string, bc *billing.SBillingCycle, projectId, osType string, - tags map[string]string, -) (string, error) { - net := self.zone.getNetworkById(vswitchId) - if net == nil { - return "", fmt.Errorf("invalid switch ID %s", vswitchId) - } - if net.wire == nil { - log.Errorf("vsiwtch's wire is empty") - return "", fmt.Errorf("vsiwtch's wire is empty") - } - if net.wire.vpc == nil { - log.Errorf("vsiwtch's wire' vpc is empty") - return "", fmt.Errorf("vsiwtch's wire's vpc is empty") - } - - var err error - keypair := "" - if len(publicKey) > 0 { - keypair, err = self.zone.region.syncKeypair(publicKey) - if err != nil { - return "", err - } - } - - img, err := self.zone.region.GetImage(imgId) - if err != nil { - log.Errorf("GetImage 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(dataDisks)+1) - disks[0].Size = img.Size - if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.Size { - disks[0].Size = sysDisk.SizeGB - } - storage, err := self.zone.getStorageByCategory(sysDisk.StorageType) - if err != nil { - return "", fmt.Errorf("Storage %s not avaiable: %s", sysDisk.StorageType, err) - } - disks[0].Category = storage.storageType - - for i, dataDisk := range dataDisks { - disks[i+1].Size = dataDisk.SizeGB - storage, err := self.zone.getStorageByCategory(dataDisk.StorageType) - if err != nil { - return "", fmt.Errorf("Storage %s not avaiable: %s", dataDisk.StorageType, err) - } - disks[i+1].Category = storage.storageType - } - - if len(instanceType) > 0 { - log.Debugf("Try instancetype : %s", instanceType) - vmId, err := self.zone.region.CreateInstance(name, hostname, imgId, instanceType, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId, osType, tags) - if err != nil { - log.Errorf("Failed for %s: %s", instanceType, err) - return "", fmt.Errorf("Failed to create specification %s.%s", instanceType, err.Error()) - } - return vmId, nil - } - - 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) - } - - var vmId string - for _, instType := range instanceTypes { - instanceTypeId := instType.InstanceTypeId - log.Debugf("Try instancetype : %s", instanceTypeId) - vmId, err = self.zone.region.CreateInstance(name, hostname, imgId, instanceTypeId, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId, osType, tags) - if err != nil { - log.Errorf("Failed for %s: %s", instanceTypeId, err) - } else { - return vmId, nil - } - } - - return "", fmt.Errorf("Failed to create, %s", err.Error()) -} - -func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (host *SHost) GetIsMaintenance() bool { - return false -} - -func (host *SHost) GetVersion() string { - return APSARA_API_VERSION -} diff --git a/pkg/multicloud/apsara/image.go b/pkg/multicloud/apsara/image.go deleted file mode 100644 index 00410c1c3c..0000000000 --- a/pkg/multicloud/apsara/image.go +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type ImageStatusType string - -const ( - ImageStatusCreating ImageStatusType = "Creating" - ImageStatusAvailable ImageStatusType = "Available" - ImageStatusUnAvailable ImageStatusType = "UnAvailable" - ImageStatusCreateFailed ImageStatusType = "CreateFailed" -) - -type ImageOwnerType string - -const ( - ImageOwnerSystem ImageOwnerType = "system" - ImageOwnerSelf ImageOwnerType = "self" - ImageOwnerOthers ImageOwnerType = "others" - ImageOwnerMarketplace ImageOwnerType = "marketplace" -) - -type ImageUsageType string - -const ( - ImageUsageInstance ImageUsageType = "instance" - ImageUsageNone ImageUsageType = "none" -) - -type SImage struct { - multicloud.SImageBase - multicloud.ApsaraTags - storageCache *SStoragecache - - // normalized image info - imgInfo *imagetools.ImageInfo - - Architecture string - CreationTime time.Time - Description string - ImageId string - ImageName string - OSName string - OSType string - ImageOwnerAlias ImageOwnerType - IsSupportCloudinit bool - IsSupportIoOptimized bool - Platform string - Size int - Status ImageStatusType - Usage string -} - -func (self *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (self *SImage) GetId() string { - return self.ImageId -} - -func (self *SImage) GetName() string { - if self.ImageOwnerAlias == ImageOwnerSystem { - return self.OSName - } else { - return self.ImageName - } -} - -func (self *SImage) IsEmulated() bool { - return false -} - -func (self *SImage) Delete(ctx context.Context) error { - return self.storageCache.region.DeleteImage(self.ImageId) -} - -func (self *SImage) GetGlobalId() string { - return self.ImageId -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.storageCache -} - -func (self *SImage) GetStatus() string { - switch self.Status { - case ImageStatusCreating: - return api.CACHED_IMAGE_STATUS_SAVING - case ImageStatusAvailable: - return api.CACHED_IMAGE_STATUS_ACTIVE - case ImageStatusUnAvailable: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - case ImageStatusCreateFailed: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - default: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (self *SImage) GetImageStatus() string { - switch self.Status { - case ImageStatusCreating: - return cloudprovider.IMAGE_STATUS_QUEUED - case ImageStatusAvailable: - return cloudprovider.IMAGE_STATUS_ACTIVE - case ImageStatusUnAvailable: - return cloudprovider.IMAGE_STATUS_DELETED - case ImageStatusCreateFailed: - return cloudprovider.IMAGE_STATUS_KILLED - default: - return cloudprovider.IMAGE_STATUS_KILLED - } -} - -func (self *SImage) Refresh() error { - new, err := self.storageCache.region.GetImage(self.ImageId) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - switch self.ImageOwnerAlias { - case ImageOwnerSystem: - return cloudprovider.ImageTypeSystem - case ImageOwnerSelf: - return cloudprovider.ImageTypeCustomized - case ImageOwnerMarketplace: - return cloudprovider.ImageTypeMarket - case ImageOwnerOthers: - return cloudprovider.ImageTypeShared - default: - return cloudprovider.ImageTypeCustomized - } -} - -func (self *SImage) GetSizeByte() int64 { - return int64(self.Size) * 1024 * 1024 * 1024 -} - -func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if self.imgInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(self.OSName, self.Architecture, self.OSType, self.Platform, "") - self.imgInfo = &imgInfo - } - - return self.imgInfo -} - -func (self *SImage) GetFullOsName() string { - return self.OSName -} - -func (self *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) -} - -func (self *SImage) GetOsDist() string { - return self.getNormalizedImageInfo().OsDistro -} - -func (self *SImage) GetOsVersion() string { - return self.getNormalizedImageInfo().OsVersion -} - -func (self *SImage) GetOsLang() string { - return self.getNormalizedImageInfo().OsLang -} - -func (self *SImage) GetOsArch() string { - return self.getNormalizedImageInfo().OsArch -} - -func (self *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return 40 -} - -func (self *SImage) GetImageFormat() string { - return "vhd" -} - -func (self *SImage) GetCreatedAt() time.Time { - return self.CreationTime -} - -type ImageExportTask struct { - ImageId string - RegionId string - // RequestId string - TaskId string -} - -func (self *SRegion) ExportImage(imageId string, bucketName string) (*ImageExportTask, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["ImageId"] = imageId - params["OssBucket"] = bucketName - params["OssPrefix"] = fmt.Sprintf("%sexport", strings.Replace(imageId, "-", "", -1)) - - if body, err := self.ecsRequest("ExportImage", params); err != nil { - return nil, err - } else { - result := ImageExportTask{} - if err := body.Unmarshal(&result); err != nil { - log.Errorf("unmarshal result error %s", err) - return nil, err - } - return &result, nil - } -} - -// {"ImageId":"m-j6c1qlpa7oebbg1n2k60","RegionId":"cn-hongkong","RequestId":"F8B2F6A1-F6AA-4C92-A54C-C4A309CF811F","TaskId":"t-j6c1qlpa7oebbg1rcl9t"} - -type ImageImportTask struct { - ImageId string - RegionId string - // RequestId string - TaskId string -} - -func (self *SRegion) ImportImage(name string, osArch string, osType string, osDist string, bucket string, key string) (*ImageImportTask, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["ImageName"] = name - if osDist == "RHEL" { - osDist = "CentOS" - } - params["Platform"] = osDist // "Others Linux" - params["OSType"] = osType // "linux" - params["Architecture"] = osArch // "x86_64" - params["DiskDeviceMapping.1.OSSBucket"] = bucket - params["DiskDeviceMapping.1.OSSObject"] = key - - log.Debugf("Upload image with params %#v", params) - - body, err := self.ecsRequest("ImportImage", params) - if err != nil { - log.Errorf("ImportImage fail %s", err) - return nil, err - } - - log.Infof("%s", body) - result := ImageImportTask{} - err = body.Unmarshal(&result) - if err != nil { - log.Errorf("unmarshal result error %s", err) - return nil, err - } - - return &result, nil -} - -func (self *SRegion) GetImage(imageId string) (*SImage, error) { - for _, owner := range []ImageOwnerType{ImageOwnerSelf, ImageOwnerSystem} { - images, _, err := self.GetImages("", owner, []string{imageId}, "", 0, 1) - if err != nil { - return nil, err - } - if len(images) == 1 { - return &images[0], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetImageByName(name string) (*SImage, error) { - for _, owner := range []ImageOwnerType{ImageOwnerSelf, ImageOwnerSystem} { - images, _, err := self.GetImages("", owner, nil, name, 0, 1) - if err != nil { - return nil, err - } - if len(images) == 1 { - return &images[0], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetImagesBySnapshot(snapshotId string, offset int, limit int) ([]SImage, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - params["SnapshotId"] = snapshotId - - return self.getImages(params) -} - -func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) { - image, err := self.GetImage(imageId) - if err != nil { - return "", err - } - return image.Status, nil -} - -func (self *SRegion) GetImages(status ImageStatusType, owner ImageOwnerType, imageId []string, name string, offset int, limit int) ([]SImage, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - if len(status) > 0 { - params["Status"] = string(status) - } else { - params["Status"] = "Creating,Available,UnAvailable,CreateFailed" - } - if imageId != nil && len(imageId) > 0 { - params["ImageId"] = strings.Join(imageId, ",") - } - if len(owner) > 0 { - params["ImageOwnerAlias"] = string(owner) - } - - if len(name) > 0 { - params["ImageName"] = name - } - - return self.getImages(params) -} - -func (self *SRegion) getImages(params map[string]string) ([]SImage, int, error) { - body, err := self.ecsRequest("DescribeImages", params) - if err != nil { - log.Errorf("DescribeImages fail %s", err) - return nil, 0, err - } - - images := make([]SImage, 0) - err = body.Unmarshal(&images, "Images", "Image") - if err != nil { - log.Errorf("unmarshal images fail %s", err) - return nil, 0, nil - } - total, _ := body.Int("TotalCount") - return images, int(total), nil -} - -func (self *SRegion) DeleteImage(imageId string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["ImageId"] = imageId - params["Force"] = "true" - - _, err := self.ecsRequest("DeleteImage", params) - if err != nil { - log.Errorf("DeleteImage fail %s", err) - return err - } - return nil -} diff --git a/pkg/multicloud/apsara/instance.go b/pkg/multicloud/apsara/instance.go deleted file mode 100644 index aaaf444fd9..0000000000 --- a/pkg/multicloud/apsara/instance.go +++ /dev/null @@ -1,1043 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - "sort" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/pkg/util/seclib" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -const ( - // Running:运行中 - //Starting:启动中 - //Stopping:停止中 - //Stopped:已停止 - - InstanceStatusStopped = "Stopped" - InstanceStatusRunning = "Running" - InstanceStatusStopping = "Stopping" - InstanceStatusStarting = "Starting" -) - -type SDedicatedHostAttribute struct { - DedicatedHostId string - DedicatedHostName string -} - -type SIpAddress struct { - IpAddress []string -} - -type SNetworkInterfaces struct { - NetworkInterface []SNetworkInterface -} - -type SOperationLocks struct { - LockReason []string -} - -type SSecurityGroupIds struct { - SecurityGroupId []string -} - -// {"NatIpAddress":"","PrivateIpAddress":{"IpAddress":["192.168.220.214"]},"VSwitchId":"vsw-2ze9cqwza4upoyujq1thd","VpcId":"vpc-2zer4jy8ix3i8f0coc5uw"} - -type SVpcAttributes struct { - NatIpAddress string - PrivateIpAddress SIpAddress - VSwitchId string - VpcId string -} - -type SInstance struct { - multicloud.SInstanceBase - multicloud.ApsaraTags - - host *SHost - - osInfo *imagetools.ImageInfo - - // idisks []cloudprovider.ICloudDisk - - AutoReleaseTime string - ClusterId string - Cpu int - CreationTime time.Time - DedicatedHostAttribute SDedicatedHostAttribute - Description string - DeviceAvailable bool - EipAddress SEipAddress - ExpiredTime time.Time - GPUAmount int - GPUSpec string - HostName string - ImageId string - InnerIpAddress SIpAddress - InstanceChargeType TChargeType - InstanceId string - InstanceName string - InstanceNetworkType string - InstanceType string - InstanceTypeFamily string - InternetChargeType TInternetChargeType - InternetMaxBandwidthIn int - InternetMaxBandwidthOut int - IoOptimized bool - KeyPairName string - Memory int - NetworkInterfaces SNetworkInterfaces - OSName string - OSType string - OperationLocks SOperationLocks - PublicIpAddress SIpAddress - Recyclable bool - RegionId string - SaleCycle string - SecurityGroupIds SSecurityGroupIds - SerialNumber string - SpotPriceLimit string - SpotStrategy string - StartTime time.Time - Status string - StoppedMode string - VlanId string - VpcAttributes SVpcAttributes - ZoneId string - - DepartmentInfo -} - -// {"AutoReleaseTime":"","ClusterId":"","Cpu":1,"CreationTime":"2018-05-23T07:58Z","DedicatedHostAttribute":{"DedicatedHostId":"","DedicatedHostName":""},"Description":"","DeviceAvailable":true,"EipAddress":{"AllocationId":"","InternetChargeType":"","IpAddress":""},"ExpiredTime":"2018-05-30T16:00Z","GPUAmount":0,"GPUSpec":"","HostName":"iZ2ze57isp1ali72tzkjowZ","ImageId":"centos_7_04_64_20G_alibase_201701015.vhd","InnerIpAddress":{"IpAddress":[]},"InstanceChargeType":"PrePaid","InstanceId":"i-2ze57isp1ali72tzkjow","InstanceName":"gaoxianqi-test-7days","InstanceNetworkType":"vpc","InstanceType":"ecs.t5-lc2m1.nano","InstanceTypeFamily":"ecs.t5","InternetChargeType":"PayByBandwidth","InternetMaxBandwidthIn":-1,"InternetMaxBandwidthOut":0,"IoOptimized":true,"Memory":512,"NetworkInterfaces":{"NetworkInterface":[{"MacAddress":"00:16:3e:10:f0:c9","NetworkInterfaceId":"eni-2zecqsagtpztl6x5hu2r","PrimaryIpAddress":"192.168.220.214"}]},"OSName":"CentOS 7.4 64位","OSType":"linux","OperationLocks":{"LockReason":[]},"PublicIpAddress":{"IpAddress":[]},"Recyclable":false,"RegionId":"cn-beijing","ResourceGroupId":"","SaleCycle":"Week","SecurityGroupIds":{"SecurityGroupId":["sg-2zecqsagtpztl6x9zynl"]},"SerialNumber":"df05d9b4-df3d-4400-88d1-5f843f0dd088","SpotPriceLimit":0.000000,"SpotStrategy":"NoSpot","StartTime":"2018-05-23T07:58Z","Status":"Running","StoppedMode":"Not-applicable","VlanId":"","VpcAttributes":{"NatIpAddress":"","PrivateIpAddress":{"IpAddress":["192.168.220.214"]},"VSwitchId":"vsw-2ze9cqwza4upoyujq1thd","VpcId":"vpc-2zer4jy8ix3i8f0coc5uw"},"ZoneId":"cn-beijing-f"} - -func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit int) ([]SInstance, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - if len(zoneId) > 0 { - params["ZoneId"] = zoneId - } - - if ids != nil && len(ids) > 0 { - params["InstanceIds"] = jsonutils.Marshal(ids).String() - } - - body, err := self.ecsRequest("DescribeInstances", params) - if err != nil { - log.Errorf("GetInstances fail %s", err) - return nil, 0, err - } - - instances := make([]SInstance, 0) - err = body.Unmarshal(&instances, "Instances", "Instance") - if err != nil { - log.Errorf("Unmarshal security group details fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return instances, int(total), nil -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - return self.SecurityGroupIds.SecurityGroupId, nil -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetId() string { - return self.InstanceId -} - -func (self *SInstance) GetName() string { - if len(self.InstanceName) > 0 { - return self.InstanceName - } - return self.InstanceId -} - -func (self *SInstance) GetHostname() string { - return self.HostName -} - -func (self *SInstance) GetGlobalId() string { - return self.InstanceId -} - -func (self *SInstance) IsEmulated() bool { - return false -} - -func (self *SInstance) GetInstanceType() string { - return self.InstanceType -} - -func (self *SInstance) GetInternetMaxBandwidthOut() int { - return self.InternetMaxBandwidthOut -} - -func (self *SInstance) getVpc() (*SVpc, error) { - return self.host.zone.region.getVpc(self.VpcAttributes.VpcId) -} - -type byAttachedTime []SDisk - -func (a byAttachedTime) Len() int { return len(a) } -func (a byAttachedTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byAttachedTime) Less(i, j int) bool { - switch a[i].GetDiskType() { - case api.DISK_TYPE_SYS: - return true - case api.DISK_TYPE_SWAP: - switch a[j].GetDiskType() { - case api.DISK_TYPE_SYS: - return false - case api.DISK_TYPE_DATA: - return true - } - case api.DISK_TYPE_DATA: - if a[j].GetDiskType() != api.DISK_TYPE_DATA { - return false - } - } - return a[i].AttachedTime.Before(a[j].AttachedTime) -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks := []SDisk{} - for { - part, total, err := self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, len(disks), 50) - if err != nil { - return nil, errors.Wrapf(err, "GetDisks for %s", self.InstanceId) - } - disks = append(disks, part...) - if len(disks) >= total { - break - } - } - - sort.Sort(byAttachedTime(disks)) - - 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) { - var ( - networkInterfaces = self.NetworkInterfaces.NetworkInterface - nics []cloudprovider.ICloudNic - ) - for _, networkInterface := range networkInterfaces { - nic := SInstanceNic{ - instance: self, - id: networkInterface.NetworkInterfaceId, - ipAddr: networkInterface.PrimaryIpAddress, - macAddr: networkInterface.MacAddress, - } - nics = append(nics, &nic) - } - return nics, nil -} - -func (self *SInstance) GetVcpuCount() int { - 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() cloudprovider.TOsType { - return cloudprovider.TOsType(osprofile.NormalizeOSType(self.OSType)) -} - -func (self *SInstance) GetFullOsName() string { - return self.OSName -} - -func (ins *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { - if ins.osInfo == nil { - osInfo := imagetools.NormalizeImageInfo(ins.OSName, "", ins.OSType, "", "") - ins.osInfo = &osInfo - } - return ins.osInfo -} - -func (ins *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(ins.getNormalizedOsInfo().OsBios) -} - -func (ins *SInstance) GetOsArch() string { - return ins.getNormalizedOsInfo().OsArch -} - -func (ins *SInstance) GetOsDist() string { - return ins.getNormalizedOsInfo().OsDistro -} - -func (ins *SInstance) GetOsVersion() string { - return ins.getNormalizedOsInfo().OsVersion -} - -func (ins *SInstance) GetOsLang() string { - return ins.getNormalizedOsInfo().OsLang -} - -func (self *SInstance) GetMachine() string { - return "pc" -} - -func (self *SInstance) GetStatus() string { - // Running:运行中 - //Starting:启动中 - //Stopping:停止中 - //Stopped:已停止 - switch self.Status { - case InstanceStatusRunning: - return api.VM_RUNNING - case InstanceStatusStarting: - return api.VM_STARTING - case InstanceStatusStopping: - return api.VM_STOPPING - case InstanceStatusStopped: - return api.VM_READY - default: - return api.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) GetRemoteStatus() string { - // Running:运行中 - //Starting:启动中 - //Stopping:停止中 - //Stopped:已停止 - switch self.Status { - case InstanceStatusRunning: - return cloudprovider.CloudVMStatusRunning - case InstanceStatusStarting: - return cloudprovider.CloudVMStatusStopped - case InstanceStatusStopping: - return cloudprovider.CloudVMStatusRunning - case InstanceStatusStopped: - return cloudprovider.CloudVMStatusStopped - default: - return cloudprovider.CloudVMStatusOther - } -} -*/ - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_APSARA -} - -func (self *SInstance) StartVM(ctx context.Context) 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(), api.VM_RUNNING) - if self.GetStatus() == api.VM_RUNNING { - return nil - } else if self.GetStatus() == api.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(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - err := self.host.zone.region.StopVM(self.InstanceId, opts.IsForce) - if err != nil { - return err - } - return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - url, err := self.host.zone.region.GetInstanceVNCUrl(self.InstanceId) - if err != nil { - return nil, err - } - passwd := seclib.RandomPassword(6) - err = self.host.zone.region.ModifyInstanceVNCUrlPassword(self.InstanceId, passwd) - if err != nil { - return nil, err - } - ret := &cloudprovider.ServerVncOutput{ - Url: url, - Password: passwd, - Protocol: "apsara", - InstanceId: self.InstanceId, - Hypervisor: api.HYPERVISOR_APSARA, - } - return ret, nil -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return self.host.zone.region.UpdateVM(self.InstanceId, name) -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - var keypairName string - if len(publicKey) > 0 { - var err error - keypairName, err = self.host.zone.region.syncKeypair(publicKey) - if err != nil { - return err - } - } - - return self.host.zone.region.DeployVM(self.InstanceId, name, password, keypairName, deleteKeypair, description) -} - -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - keypair := "" - if len(desc.PublicKey) > 0 { - var err error - keypair, err = self.host.zone.region.syncKeypair(desc.PublicKey) - if err != nil { - return "", err - } - } - diskId, err := self.host.zone.region.ReplaceSystemDisk(self.InstanceId, desc.ImageId, desc.Password, keypair, desc.SysSizeGB) - if err != nil { - return "", err - } - - return diskId, nil -} - -func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - if len(config.InstanceType) > 0 { - return self.host.zone.region.ChangeVMConfig2(self.ZoneId, self.InstanceId, config.InstanceType, nil) - } - return self.host.zone.region.ChangeVMConfig(self.ZoneId, self.InstanceId, config.Cpu, config.MemoryMB, nil) -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return self.host.zone.region.AttachDisk(self.InstanceId, diskId) -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return cloudprovider.RetryOnError( - func() error { - return self.host.zone.region.DetachDisk(self.InstanceId, diskId) - }, - []string{ - `"Code":"InvalidOperation.Conflict"`, - }, - 4) -} - -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) CreateInstance(name, hostname string, imageId string, instanceType string, securityGroupId string, - zoneId string, desc string, passwd string, disks []SDisk, vSwitchId string, ipAddr string, - keypair string, userData string, bc *billing.SBillingCycle, projectId, osType string, - tags map[string]string, -) (string, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["ImageId"] = imageId - params["InstanceType"] = instanceType - params["SecurityGroupId"] = securityGroupId - params["ZoneId"] = zoneId - params["InstanceName"] = name - if len(hostname) > 0 { - params["HostName"] = hostname - } - params["Description"] = desc - params["InternetChargeType"] = "PayByTraffic" - params["InternetMaxBandwidthIn"] = "200" - params["InternetMaxBandwidthOut"] = "100" - if len(passwd) > 0 { - params["Password"] = passwd - } else { - params["PasswordInherit"] = "True" - } - - if len(projectId) > 0 { - params["ResourceGroupId"] = projectId - } - //{"Code":"InvalidSystemDiskCategory.ValueNotSupported","HostId":"ecs.apsaracs.com","Message":"The specified parameter 'SystemDisk.Category' is not support IoOptimized Instance. Valid Values: cloud_efficiency;cloud_ssd. ","RequestId":"9C9A4E99-5196-42A2-80B6-4762F8F75C90"} - params["IoOptimized"] = "optimized" - for i, d := range disks { - if i == 0 { - params["SystemDisk.Category"] = d.Category - if d.Category == api.STORAGE_CLOUD_ESSD_PL2 { - params["SystemDisk.Category"] = api.STORAGE_CLOUD_ESSD - params["SystemDisk.PerformanceLevel"] = "PL2" - } - if d.Category == api.STORAGE_CLOUD_ESSD_PL3 { - params["SystemDisk.Category"] = api.STORAGE_CLOUD_ESSD - params["SystemDisk.PerformanceLevel"] = "PL3" - } - params["SystemDisk.Size"] = fmt.Sprintf("%d", d.Size) - params["SystemDisk.DiskName"] = d.GetName() - params["SystemDisk.Description"] = d.Description - } else { - params[fmt.Sprintf("DataDisk.%d.Size", i)] = fmt.Sprintf("%d", d.Size) - params[fmt.Sprintf("DataDisk.%d.Category", i)] = d.Category - if d.Category == api.STORAGE_CLOUD_ESSD_PL2 { - params[fmt.Sprintf("DataDisk.%d.Category", i)] = api.STORAGE_CLOUD_ESSD - params[fmt.Sprintf("DataDisk.%d..PerformanceLevel", i)] = "PL2" - } - if d.Category == api.STORAGE_CLOUD_ESSD_PL3 { - params[fmt.Sprintf("DataDisk.%d.Category", i)] = api.STORAGE_CLOUD_ESSD - params[fmt.Sprintf("DataDisk.%d..PerformanceLevel", i)] = "PL3" - } - params[fmt.Sprintf("DataDisk.%d.DiskName", i)] = d.GetName() - params[fmt.Sprintf("DataDisk.%d.Description", i)] = d.Description - params[fmt.Sprintf("DataDisk.%d.Encrypted", i)] = "false" - } - } - params["VSwitchId"] = vSwitchId - params["PrivateIpAddress"] = ipAddr - - if len(keypair) > 0 { - params["KeyPairName"] = keypair - } - - if len(userData) > 0 { - params["UserData"] = userData - } - - if len(tags) > 0 { - tagIdx := 0 - for k, v := range tags { - params[fmt.Sprintf("Tag.%d.Key", tagIdx)] = k - params[fmt.Sprintf("Tag.%d.Value", tagIdx)] = v - tagIdx += 1 - } - } - - if bc != nil { - params["InstanceChargeType"] = "PrePaid" - err := billingCycle2Params(bc, params) - if err != nil { - return "", err - } - if bc.AutoRenew { - params["AutoRenew"] = "true" - params["AutoRenewPeriod"] = "1" - } else { - params["AutoRenew"] = "False" - } - } else { - params["InstanceChargeType"] = "PostPaid" - params["SpotStrategy"] = "NoSpot" - } - - params["ClientToken"] = utils.GenRequestId(20) - - body, err := self.ecsRequest("CreateInstance", params) - if err != nil { - log.Errorf("CreateInstance fail %s", err) - return "", err - } - instanceId, _ := body.GetString("InstanceId") - return instanceId, nil -} - -func (self *SRegion) doStartVM(instanceId string) error { - return self.instanceOperation(instanceId, "StartInstance", nil) -} - -func (self *SRegion) doStopVM(instanceId string, isForce bool) error { - params := make(map[string]string) - if isForce { - params["ForceStop"] = "true" - } else { - params["ForceStop"] = "false" - } - params["StoppedMode"] = "KeepCharging" - return self.instanceOperation(instanceId, "StopInstance", params) -} - -func (self *SRegion) doDeleteVM(instanceId string) error { - params := make(map[string]string) - params["TerminateSubscription"] = "true" // terminate expired prepaid instance - params["Force"] = "true" - return self.instanceOperation(instanceId, "DeleteInstance", params) -} - -/*func (self *SRegion) waitInstanceStatus(instanceId string, target string, interval time.Duration, timeout time.Duration) error { - startTime := time.Now() - for time.Now().Sub(startTime) < timeout { - status, err := self.GetInstanceStatus(instanceId) - if err != nil { - return err - } - if status == target { - return nil - } - time.Sleep(interval) - } - return cloudprovider.ErrTimeout -} - -func (self *SInstance) waitStatus(target string, interval time.Duration, timeout time.Duration) error { - return self.host.zone.region.waitInstanceStatus(self.InstanceId, target, interval, timeout) -}*/ - -func (self *SRegion) StartVM(instanceId string) error { - status, err := self.GetInstanceStatus(instanceId) - if err != nil { - log.Errorf("Fail to get instance status on StartVM: %s", err) - return err - } - if status != InstanceStatusStopped { - log.Errorf("StartVM: vm status is %s expect %s", status, InstanceStatusStopped) - return cloudprovider.ErrInvalidStatus - } - return self.doStartVM(instanceId) - // if err != nil { - // return err - // } - // return self.waitInstanceStatus(instanceId, InstanceStatusRunning, time.Second*5, time.Second*180) // 3 minutes to timeout -} - -func (self *SRegion) StopVM(instanceId string, isForce bool) error { - status, err := self.GetInstanceStatus(instanceId) - if err != nil { - log.Errorf("Fail to get instance status on StopVM: %s", err) - return err - } - if status == InstanceStatusStopped { - return nil - } - if status != InstanceStatusRunning { - log.Errorf("StopVM: vm status is %s expect %s", status, InstanceStatusRunning) - return cloudprovider.ErrInvalidStatus - } - return self.doStopVM(instanceId, isForce) - // if err != nil { - // return err - // } - // return self.waitInstanceStatus(instanceId, InstanceStatusStopped, time.Second*10, time.Second*300) // 5 minutes to timeout -} - -func (self *SRegion) DeleteVM(instanceId string) error { - status, err := self.GetInstanceStatus(instanceId) - if err != nil { - log.Errorf("Fail to get instance status on DeleteVM: %s", err) - return err - } - log.Debugf("Instance status on delete is %s", status) - if status != InstanceStatusStopped { - log.Warningf("DeleteVM: vm status is %s expect %s", status, InstanceStatusStopped) - } - return self.doDeleteVM(instanceId) - // if err != nil { - // return err - // } - // err = self.waitInstanceStatus(instanceId, InstanceStatusRunning, time.Second*10, time.Second*300) // 5 minutes to timeout - // if err == cloudprovider.ErrNotFound { - // return nil - // } else if err == nil { - // return cloudprovider.ErrTimeout - // } else { - // return err - // } -} - -func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { - instance, err := self.GetInstance(instanceId) - if err != nil { - return err - } - - // 修改密钥时直接返回 - if deleteKeypair { - err = self.DetachKeyPair(instanceId, instance.KeyPairName) - if err != nil { - return err - } - } - - if len(keypairName) > 0 { - err = self.AttachKeypair(instanceId, keypairName) - if err != nil { - return err - } - } - - params := make(map[string]string) - - // if resetPassword { - // params["Password"] = seclib2.RandomPassword2(12) - // } - // 指定密码的情况下,使用指定的密码 - if len(password) > 0 { - params["Password"] = password - } - - if len(name) > 0 && instance.InstanceName != name { - params["InstanceName"] = name - } - - if len(description) > 0 && instance.Description != description { - params["Description"] = description - } - - if len(params) > 0 { - return self.modifyInstanceAttribute(instanceId, params) - } else { - return nil - } -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - for { - err := self.host.zone.region.DeleteVM(self.InstanceId) - if err != nil { - if isError(err, "IncorrectInstanceStatus.Initializing") { - log.Infof("The instance is initializing, try later ...") - time.Sleep(10 * time.Second) - } else { - log.Errorf("DeleteVM fail: %s", err) - return err - } - } else { - break - } - } - return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes -} - -func (self *SRegion) UpdateVM(instanceId string, name string) error { - /* - api: ModifyInstanceAttribute - https://help.apsara.com/document_detail/25503.html?spm=a2c4g.11186623.4.1.DrgpjW - */ - params := make(map[string]string) - params["InstanceName"] = name - return self.modifyInstanceAttribute(instanceId, params) -} - -func (self *SRegion) modifyInstanceAttribute(instanceId string, params map[string]string) error { - params["x-acs-instanceid"] = instanceId - return self.instanceOperation(instanceId, "ModifyInstanceAttribute", params) -} - -func (self *SRegion) ReplaceSystemDisk(instanceId string, imageId string, passwd string, keypairName string, sysDiskSizeGB int) (string, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - params["ImageId"] = imageId - if len(passwd) > 0 { - params["Password"] = passwd - } else { - params["PasswordInherit"] = "True" - } - if len(keypairName) > 0 { - params["KeyPairName"] = keypairName - } - if sysDiskSizeGB > 0 { - params["SystemDisk.Size"] = fmt.Sprintf("%d", sysDiskSizeGB) - } - params["x-acs-instanceid"] = instanceId - body, err := self.ecsRequest("ReplaceSystemDisk", params) - if err != nil { - return "", err - } - // log.Debugf("%s", body.String()) - return body.GetString("DiskId") -} - -func (self *SRegion) ChangeVMConfig(zoneId string, instanceId string, ncpu int, vmem int, disks []*SDisk) error { - // todo: support change disk config? - params := make(map[string]string) - instanceTypes, e := self.GetMatchInstanceTypes(ncpu, vmem, 0, zoneId) - if e != nil { - return e - } - - for _, instancetype := range instanceTypes { - params["InstanceType"] = instancetype.InstanceTypeId - params["ClientToken"] = utils.GenRequestId(20) - if err := self.instanceOperation(instanceId, "ModifyInstanceSpec", params); 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) ChangeVMConfig2(zoneId string, instanceId string, instanceType string, disks []*SDisk) error { - // todo: support change disk config? - params := make(map[string]string) - params["InstanceType"] = instanceType - params["ClientToken"] = utils.GenRequestId(20) - if err := self.instanceOperation(instanceId, "ModifyInstanceSpec", params); err != nil { - log.Errorf("Failed for %s: %s", instanceType, err) - return fmt.Errorf("Failed to change vm config, specification not supported") - } else { - return nil - } -} - -func (self *SRegion) DetachDisk(instanceId string, diskId string) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["DiskId"] = diskId - log.Infof("Detach instance %s disk %s", instanceId, diskId) - params["x-acs-instanceid"] = instanceId - _, err := self.ecsRequest("DetachDisk", params) - if err != nil { - if strings.Contains(err.Error(), "The specified disk has not been attached on the specified instance") { - return nil - } - return errors.Wrap(err, "DetachDisk") - } - - return nil -} - -func (self *SRegion) AttachDisk(instanceId string, diskId string) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["DiskId"] = diskId - params["x-acs-instanceid"] = instanceId - _, err := self.ecsRequest("AttachDisk", params) - if err != nil { - log.Errorf("AttachDisk %s to %s fail %s", diskId, instanceId, err) - return err - } - - return nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - if len(self.EipAddress.IpAddress) > 0 { - return self.host.zone.region.GetEip(self.EipAddress.AllocationId) - } - 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.InstanceType = EIP_INSTANCE_TYPE_ECS - eip.Status = EIP_STATUS_INUSE - eip.AllocationId = self.InstanceId // fixed - eip.AllocationTime = self.CreationTime - eip.Bandwidth = self.InternetMaxBandwidthOut - eip.InternetChargeType = self.InternetChargeType - return &eip, nil - } - return nil, nil -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - return self.host.zone.region.AssignSecurityGroup(secgroupId, self.InstanceId) -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - return self.host.zone.region.SetSecurityGroups(secgroupIds, self.InstanceId) -} - -func (self *SInstance) GetBillingType() string { - return convertChargeType(self.InstanceChargeType) -} - -func (self *SInstance) GetCreatedAt() time.Time { - return self.CreationTime -} - -func (self *SInstance) GetExpiredAt() time.Time { - return convertExpiredAt(self.ExpiredTime) -} - -func (self *SInstance) UpdateUserData(userData string) error { - return self.host.zone.region.updateInstance(self.InstanceId, "", "", "", "", userData) -} - -func (self *SInstance) Renew(bc billing.SBillingCycle) error { - return self.host.zone.region.RenewInstance(self.InstanceId, bc) -} - -func billingCycle2Params(bc *billing.SBillingCycle, params map[string]string) error { - if bc.GetMonths() > 0 { - params["PeriodUnit"] = "Month" - params["Period"] = fmt.Sprintf("%d", bc.GetMonths()) - } else if bc.GetWeeks() > 0 { - params["PeriodUnit"] = "Week" - params["Period"] = fmt.Sprintf("%d", bc.GetWeeks()) - } else { - return fmt.Errorf("invalid renew time period %s", bc.String()) - } - return nil -} - -func (region *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - err := billingCycle2Params(&bc, params) - if err != nil { - return err - } - params["ClientToken"] = utils.GenRequestId(20) - params["x-acs-instanceid"] = instanceId - _, err = region.ecsRequest("RenewInstance", params) - if err != nil { - log.Errorf("RenewInstance fail %s", err) - return err - } - return nil -} - -func (self *SInstance) GetError() error { - return nil -} - -func (region *SRegion) ConvertPublicIpToEip(instanceId string) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["RegionId"] = region.RegionId - _, err := region.ecsRequest("ConvertNatPublicIpToEip", params) - return err -} - -func (self *SInstance) ConvertPublicIpToEip() error { - return self.host.zone.region.ConvertPublicIpToEip(self.InstanceId) -} - -func (region *SRegion) SetInstanceAutoRenew(instanceId string, autoRenew bool) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["RegionId"] = region.RegionId - if autoRenew { - params["RenewalStatus"] = "AutoRenewal" - params["Duration"] = "1" - } else { - params["RenewalStatus"] = "Normal" - } - params["x-acs-instanceid"] = instanceId - _, err := region.ecsRequest("ModifyInstanceAutoRenewAttribute", params) - return err -} - -type SAutoRenewAttr struct { - Duration int - AutoRenewEnabled bool - RenewalStatus string - PeriodUnit string -} - -func (region *SRegion) GetInstanceAutoRenewAttribute(instanceId string) (*SAutoRenewAttr, error) { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["RegionId"] = region.RegionId - resp, err := region.ecsRequest("DescribeInstanceAutoRenewAttribute", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeInstanceAutoRenewAttribute") - } - attr := []SAutoRenewAttr{} - err = resp.Unmarshal(&attr, "InstanceRenewAttributes", "InstanceRenewAttribute") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - if len(attr) == 1 { - return &attr[0], nil - } - return nil, fmt.Errorf("get %d auto renew info", len(attr)) -} - -func (self *SInstance) IsAutoRenew() bool { - attr, err := self.host.zone.region.GetInstanceAutoRenewAttribute(self.InstanceId) - if err != nil { - log.Errorf("failed to get instance %s auto renew info", self.InstanceId) - return false - } - return attr.AutoRenewEnabled -} - -func (self *SInstance) SetAutoRenew(bc billing.SBillingCycle) error { - return self.host.zone.region.SetInstanceAutoRenew(self.InstanceId, bc.AutoRenew) -} - -func (self *SInstance) SetTags(tags map[string]string, replace bool) error { - return self.host.zone.region.SetResourceTags("ecs", "instance", []string{self.InstanceId}, tags, replace) -} diff --git a/pkg/multicloud/apsara/instancenic.go b/pkg/multicloud/apsara/instancenic.go deleted file mode 100644 index cd73be7397..0000000000 --- a/pkg/multicloud/apsara/instancenic.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - instance *SInstance - id string - ipAddr string - macAddr string - - cloudprovider.DummyICloudNic -} - -func (self *SInstanceNic) GetId() string { - return self.id -} - -func (self *SInstanceNic) GetIP() string { - return self.ipAddr -} - -func (self *SInstanceNic) GetMAC() string { - return self.macAddr -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (self *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (self *SInstanceNic) GetINetworkId() string { - return self.instance.VpcAttributes.VSwitchId -} diff --git a/pkg/multicloud/apsara/instancetype.go b/pkg/multicloud/apsara/instancetype.go deleted file mode 100644 index abd064dbdb..0000000000 --- a/pkg/multicloud/apsara/instancetype.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// {"CpuCoreCount":1,"EniQuantity":1,"GPUAmount":0,"GPUSpec":"","InstanceTypeFamily":"ecs.t1","InstanceTypeId":"ecs.t1.xsmall","LocalStorageCategory":"","MemorySize":0.500000} -// InstanceBandwidthRx":26214400,"InstanceBandwidthTx":26214400,"InstancePpsRx":4500000,"InstancePpsTx":4500000 - -type SInstanceType struct { - multicloud.SResourceBase - multicloud.ApsaraTags - BaselineCredit int - CpuCoreCount int - MemorySize float32 - EniQuantity int // 实例规格支持网卡数量 - GPUAmount int - GPUSpec string - InstanceTypeFamily string - InstanceFamilyLevel string - InstanceTypeId string - LocalStorageCategory string - LocalStorageAmount int - LocalStorageCapacity int64 - InstanceBandwidthRx int - InstanceBandwidthTx int - InstancePpsRx int - InstancePpsTx int -} - -func (self *SRegion) GetInstanceTypes() ([]SInstanceType, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - - body, err := self.client.ascmRequest("DescribeInstanceTypes", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeInstanceTypes") - } - - instanceTypes := make([]SInstanceType, 0) - err = body.Unmarshal(&instanceTypes, "data") - if err != nil { - log.Errorf("Unmarshal instance type details fail %s", err) - return nil, err - } - return instanceTypes, nil -} - -func (self *SInstanceType) memoryMB() int { - return int(self.MemorySize * 1024) -} - -func (self *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { - skus, err := self.GetInstanceTypes() - if err != nil { - return nil, errors.Wrapf(err, "GetInstanceTypes") - } - ret := []cloudprovider.ICloudSku{} - for i := range skus { - ret = append(ret, &skus[i]) - } - return ret, nil -} - -func (self *SInstanceType) GetStatus() string { - return "" -} - -func (self *SInstanceType) Delete() error { - return nil -} - -func (self *SInstanceType) GetName() string { - return self.InstanceTypeId -} - -func (self *SInstanceType) GetId() string { - return self.InstanceTypeId -} - -func (self *SInstanceType) GetGlobalId() string { - return self.InstanceTypeId -} - -func (self *SInstanceType) GetInstanceTypeFamily() string { - return self.InstanceTypeFamily -} - -func (self *SInstanceType) GetInstanceTypeCategory() string { - return self.GetName() -} - -func (self *SInstanceType) GetPrepaidStatus() string { - return api.SkuStatusSoldout -} - -func (self *SInstanceType) GetPostpaidStatus() string { - return api.SkuStatusAvailable -} - -func (self *SInstanceType) GetCpuArch() string { - return "" -} - -func (self *SInstanceType) GetCpuCoreCount() int { - return int(self.CpuCoreCount) -} - -func (self *SInstanceType) GetMemorySizeMB() int { - return int(self.MemorySize * 1024) -} - -func (self *SInstanceType) GetOsName() string { - return "Any" -} - -func (self *SInstanceType) GetSysDiskResizable() bool { - return true -} - -func (self *SInstanceType) GetSysDiskType() string { - return "" -} - -func (self *SInstanceType) GetSysDiskMinSizeGB() int { - return 0 -} - -func (self *SInstanceType) GetSysDiskMaxSizeGB() int { - return 0 -} - -func (self *SInstanceType) GetAttachedDiskType() string { - return "iscsi" -} - -func (self *SInstanceType) GetAttachedDiskSizeGB() int { - return 0 -} - -func (self *SInstanceType) GetAttachedDiskCount() int { - return 0 -} - -func (self *SInstanceType) GetDataDiskTypes() string { - return "" -} - -func (self *SInstanceType) GetDataDiskMaxCount() int { - return 6 -} - -func (self *SInstanceType) GetNicType() string { - return "vpc" -} - -func (self *SInstanceType) GetNicMaxCount() int { - return 1 -} - -func (self *SInstanceType) GetGpuAttachable() bool { - return false -} - -func (self *SInstanceType) GetGpuSpec() string { - return "" -} - -func (self *SInstanceType) GetGpuCount() int { - return 0 -} - -func (self *SInstanceType) GetGpuMaxCount() int { - return 0 -} diff --git a/pkg/multicloud/apsara/ipv6_gateway.go b/pkg/multicloud/apsara/ipv6_gateway.go deleted file mode 100644 index 59d336a869..0000000000 --- a/pkg/multicloud/apsara/ipv6_gateway.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "time" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SIPv6Gateway struct { - multicloud.SResourceBase - multicloud.ApsaraTags - region *SRegion - - Status string `json:"Status"` - Description string `json:"Description"` - InstanceChargeType string `json:"InstanceChargeType"` - Ipv6GatewayId string `json:"Ipv6GatewayId"` - BusinessStatus string `json:"BusinessStatus"` - Name string `json:"Name"` - VpcID string `json:"VpcId"` - ExpiredTime string `json:"ExpiredTime"` - CreationTime time.Time `json:"CreationTime"` - RegionId string `json:"RegionId"` - Spec string `json:"Spec"` - - DepartmentInfo -} - -func (self *SIPv6Gateway) GetGlobalId() string { - return self.Ipv6GatewayId -} - -func (self *SIPv6Gateway) GetId() string { - return self.Ipv6GatewayId -} - -func (self *SIPv6Gateway) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.Ipv6GatewayId -} - -func (self *SIPv6Gateway) GetStatus() string { - return self.Status -} - -func (self *SIPv6Gateway) GetInstanceType() string { - return self.Spec -} - -func (self *SIPv6Gateway) GetCreatedAt() time.Time { - return self.CreationTime -} - -func (self *SRegion) GetIPv6Gateways(vpcId string, pageNumber, pageSize int) ([]SIPv6Gateway, int, error) { - if pageSize < 1 { - pageSize = 50 - } - if pageNumber < 1 { - pageNumber = 1 - } - params := map[string]string{ - "PageSize": fmt.Sprintf("%d", pageSize), - "PageNumber": fmt.Sprintf("%d", 1), - } - if len(vpcId) > 0 { - params["VpcId"] = vpcId - } - resp, err := self.vpcRequest("DescribeIpv6Gateways", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeIpv6Gateways") - } - ret := []SIPv6Gateway{} - err = resp.Unmarshal(&ret, "Ipv6Gateways", "Ipv6Gateway") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - totalCount, _ := resp.Int("TotalCount") - return ret, int(totalCount), nil -} - -func (self *SRegion) GetIPv6Gateway(id string) (*SIPv6Gateway, error) { - params := map[string]string{ - "Ipv6GatewayId": id, - } - resp, err := self.vpcRequest("DescribeIpv6GatewayAttribute", params) - if err != nil { - return nil, err - } - ret := &SIPv6Gateway{region: self} - return ret, resp.Unmarshal(ret) -} - -func (self *SVpc) GetICloudIPv6Gateways() ([]cloudprovider.ICloudIPv6Gateway, error) { - res, pageNumber := []SIPv6Gateway{}, 1 - for { - part, total, err := self.region.GetIPv6Gateways(self.VpcId, pageNumber, 50) - if err != nil { - return nil, err - } - res = append(res, part...) - if len(res) >= total { - break - } - pageNumber++ - } - ret := []cloudprovider.ICloudIPv6Gateway{} - for i := range res { - res[i].region = self.region - ret = append(ret, &res[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/apsara/loadbalancer.go b/pkg/multicloud/apsara/loadbalancer.go deleted file mode 100644 index e6d752b581..0000000000 --- a/pkg/multicloud/apsara/loadbalancer.go +++ /dev/null @@ -1,410 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type ListenerProtocol string - -const ( - ListenerProtocolTCP ListenerProtocol = "tcp" - ListenerProtocolUDP ListenerProtocol = "udp" - ListenerProtocolHTTP ListenerProtocol = "http" - ListenerProtocolHTTPS ListenerProtocol = "https" -) - -type ListenerPorts struct { - ListenerPort []int -} - -type ListenerPortsAndProtocol struct { - ListenerPortAndProtocol []ListenerPortAndProtocol -} - -type ListenerPortAndProtocol struct { - Description string - ListenerPort int - ListenerProtocol ListenerProtocol -} - -type BackendServers struct { - BackendServer []SLoadbalancerDefaultBackend -} - -type SLoadbalancer struct { - multicloud.SLoadbalancerBase - multicloud.ApsaraTags - region *SRegion - - LoadBalancerId string //负载均衡实例ID。 - LoadBalancerName string //负载均衡实例的名称。 - LoadBalancerStatus string //负载均衡实例状态:inactive: 此状态的实例监听不会再转发流量。active: 实例创建后,默认状态为active。 locked: 实例已经被锁定。 - Address string //负载均衡实例的服务地址。 - RegionId string //负载均衡实例的地域ID。 - RegionIdAlias string //负载均衡实例的地域名称。 - AddressType string //负载均衡实例的网络类型。 - VSwitchId string //私网负载均衡实例的交换机ID。 - VpcId string //私网负载均衡实例的专有网络ID。 - NetworkType string //私网负载均衡实例的网络类型:vpc:专有网络实例 classic:经典网络实例 - ListenerPorts ListenerPorts - ListenerPortsAndProtocol ListenerPortsAndProtocol - BackendServers BackendServers - CreateTime time.Time //负载均衡实例的创建时间。 - MasterZoneId string //实例的主可用区ID。 - SlaveZoneId string //实例的备可用区ID。 - InternetChargeType TInternetChargeType //公网实例的计费方式。取值:paybybandwidth:按带宽计费 paybytraffic:按流量计费(默认值) 说明 当 PayType参数的值为PrePay时,只支持按带宽计费。 - PayType string //实例的计费类型,取值:PayOnDemand:按量付费 PrePay:预付费 - LoadBalancerSpec string //负载均衡实例的的性能规格 - Bandwidth int //按带宽计费的公网型实例的带宽峰值 - DepartmentInfo -} - -func (lb *SLoadbalancer) GetName() string { - return lb.LoadBalancerName -} - -func (lb *SLoadbalancer) GetId() string { - return lb.LoadBalancerId -} - -func (lb *SLoadbalancer) GetGlobalId() string { - return lb.LoadBalancerId -} - -func (lb *SLoadbalancer) GetStatus() string { - if lb.LoadBalancerStatus == "active" { - return api.LB_STATUS_ENABLED - } - return api.LB_STATUS_DISABLED -} - -func (lb *SLoadbalancer) GetTags() (map[string]string, error) { - tags, err := lb.region.ListResourceTags("slb", "instance", []string{lb.GetId()}) - if err != nil { - return nil, errors.Wrap(err, "lb.region.ListResourceTags") - } - if _, ok := tags[lb.GetId()]; !ok { - return map[string]string{}, nil - } - return *tags[lb.GetId()], nil -} - -func (lb *SLoadbalancer) GetAddress() string { - return lb.Address -} - -func (lb *SLoadbalancer) GetAddressType() string { - return lb.AddressType -} - -func (lb *SLoadbalancer) GetNetworkType() string { - return lb.NetworkType -} - -func (lb *SLoadbalancer) GetNetworkIds() []string { - return []string{lb.VSwitchId} -} - -func (lb *SLoadbalancer) GetZoneId() string { - zone, err := lb.region.getZoneById(lb.MasterZoneId) - if err != nil { - log.Errorf("failed to find zone for lb %s error: %v", lb.LoadBalancerName, err) - return "" - } - return zone.GetGlobalId() -} - -func (self *SLoadbalancer) GetZone1Id() string { - return "" -} - -func (lb *SLoadbalancer) IsEmulated() bool { - return false -} - -func (lb *SLoadbalancer) GetVpcId() string { - return lb.VpcId -} - -func (lb *SLoadbalancer) Refresh() error { - loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId) - if err != nil { - return err - } - return jsonutils.Update(lb, loadbalancer) -} - -func (region *SRegion) GetLoadbalancers(ids []string) ([]SLoadbalancer, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - if ids != nil && len(ids) > 0 { - params["LoadBalancerId"] = strings.Join(ids, ",") - } - body, err := region.lbRequest("DescribeLoadBalancers", params) - if err != nil { - return nil, err - } - lbs := []SLoadbalancer{} - return lbs, body.Unmarshal(&lbs, "LoadBalancers", "LoadBalancer") -} - -func (region *SRegion) GetLoadbalancerDetail(loadbalancerId string) (*SLoadbalancer, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - body, err := region.lbRequest("DescribeLoadBalancerAttribute", params) - if err != nil { - return nil, err - } - lb := SLoadbalancer{region: region} - return &lb, body.Unmarshal(&lb) -} - -func (lb *SLoadbalancer) Delete(ctx context.Context) error { - params := map[string]string{} - params["RegionId"] = lb.region.RegionId - params["LoadBalancerId"] = lb.LoadBalancerId - _, err := lb.region.lbRequest("DeleteLoadBalancer", params) - return err -} - -func (lb *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - ibackendgroups := []cloudprovider.ICloudLoadbalancerBackendGroup{} - { - backendgroups, err := lb.region.GetLoadbalancerBackendgroups(lb.LoadBalancerId) - if err != nil { - return nil, err - } - - for i := 0; i < len(backendgroups); i++ { - backendgroups[i].lb = lb - ibackendgroups = append(ibackendgroups, &backendgroups[i]) - } - } - { - iDefaultBackendgroup := SLoadbalancerDefaultBackendGroup{lb: lb} - ibackendgroups = append(ibackendgroups, &iDefaultBackendgroup) - - } - { - backendgroups, err := lb.region.GetLoadbalancerMasterSlaveBackendgroups(lb.LoadBalancerId) - if err != nil { - return nil, err - } - for i := 0; i < len(backendgroups); i++ { - backendgroups[i].lb = lb - ibackendgroups = append(ibackendgroups, &backendgroups[i]) - } - } - return ibackendgroups, nil -} - -func (lb *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - switch group.GroupType { - case api.LB_BACKENDGROUP_TYPE_NORMAL: - group, err := lb.region.CreateLoadbalancerBackendGroup(group.Name, lb.LoadBalancerId, group.Backends) - if err != nil { - return nil, err - } - group.lb = lb - return group, nil - case api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE: - group, err := lb.region.CreateLoadbalancerMasterSlaveBackendGroup(group.Name, lb.LoadBalancerId, group.Backends) - if err != nil { - return nil, err - } - group.lb = lb - return group, nil - default: - return nil, fmt.Errorf("Unsupport backendgroup type %s", group.GroupType) - } -} - -func (lb *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - switch listener.ListenerType { - case api.LB_LISTENER_TYPE_TCP: - return lb.region.CreateLoadbalancerTCPListener(lb, listener) - case api.LB_LISTENER_TYPE_UDP: - return lb.region.CreateLoadbalancerUDPListener(lb, listener) - case api.LB_LISTENER_TYPE_HTTP: - return lb.region.CreateLoadbalancerHTTPListener(lb, listener) - case api.LB_LISTENER_TYPE_HTTPS: - return lb.region.CreateLoadbalancerHTTPSListener(lb, listener) - } - return nil, fmt.Errorf("unsupport listener type %s", listener.ListenerType) -} - -func (lb *SLoadbalancer) GetLoadbalancerSpec() string { - if len(lb.LoadBalancerSpec) == 0 { - lb.Refresh() - } - return lb.LoadBalancerSpec -} - -func (lb *SLoadbalancer) GetChargeType() string { - switch lb.InternetChargeType { - case "paybybandwidth": - return api.LB_CHARGE_TYPE_BY_BANDWIDTH - case "paybytraffic": - return api.LB_CHARGE_TYPE_BY_TRAFFIC - } - return "unknown" -} - -func (lb *SLoadbalancer) GetCreatedAt() time.Time { - return lb.CreateTime -} - -func (lb *SLoadbalancer) GetEgressMbps() int { - if lb.Bandwidth < 1 { - return 0 - } - return lb.Bandwidth -} - -func (lb *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - groups, err := lb.GetILoadBalancerBackendGroups() - if err != nil { - return nil, err - } - for i := 0; i < len(groups); i++ { - if groups[i].GetGlobalId() == groupId { - return groups[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (lb *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { - if lb.AddressType == "internet" { - eip := SEipAddress{ - region: lb.region, - IpAddress: lb.Address, - InstanceId: lb.GetGlobalId(), - InstanceType: EIP_INTANNCE_TYPE_SLB, - Status: EIP_STATUS_INUSE, - AllocationId: lb.GetGlobalId(), - AllocationTime: lb.CreateTime, - Bandwidth: lb.Bandwidth, - InternetChargeType: lb.InternetChargeType, - } - return &eip, nil - } - eips, total, err := lb.region.GetEips("", lb.LoadBalancerId, 0, 1) - if err != nil { - return nil, errors.Wrapf(err, "lb.region.GetEips(%s)", lb.LoadBalancerId) - } - if total != 1 { - return nil, cloudprovider.ErrNotFound - } - eips[0].region = lb.region - return &eips[0], nil -} - -func (region *SRegion) loadbalancerOperation(loadbalancerId, status string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["LoadBalancerStatus"] = status - _, err := region.lbRequest("SetLoadBalancerStatus", params) - return err -} - -func (lb *SLoadbalancer) Start() error { - if lb.LoadBalancerStatus != "active" { - return lb.region.loadbalancerOperation(lb.LoadBalancerId, "active") - } - return nil -} - -func (lb *SLoadbalancer) Stop() error { - if lb.LoadBalancerStatus != "inactive" { - return lb.region.loadbalancerOperation(lb.LoadBalancerId, "inactive") - } - return nil -} - -func (lb *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { - listener, err := lb.GetILoadBalancerListeners() - if err != nil { - return nil, err - } - for i := 0; i < len(listener); i++ { - if listener[i].GetGlobalId() == listenerId { - return listener[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (lb *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId) - if err != nil { - return nil, err - } - listeners := []cloudprovider.ICloudLoadbalancerListener{} - for _, listenerInfo := range loadbalancer.ListenerPortsAndProtocol.ListenerPortAndProtocol { - switch listenerInfo.ListenerProtocol { - case ListenerProtocolHTTP: - listener, err := lb.region.GetLoadbalancerHTTPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) - if err != nil { - return nil, err - } - listener.lb = lb - listeners = append(listeners, listener) - case ListenerProtocolHTTPS: - listener, err := lb.region.GetLoadbalancerHTTPSListener(lb.LoadBalancerId, listenerInfo.ListenerPort) - if err != nil { - return nil, err - } - listener.lb = lb - listeners = append(listeners, listener) - case ListenerProtocolTCP: - listener, err := lb.region.GetLoadbalancerTCPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) - if err != nil { - return nil, err - } - listener.lb = lb - listeners = append(listeners, listener) - case ListenerProtocolUDP: - listener, err := lb.region.GetLoadbalancerUDPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) - if err != nil { - return nil, err - } - listener.lb = lb - listeners = append(listeners, listener) - default: - return nil, fmt.Errorf("failed to recognize %s type listener", listenerInfo.ListenerProtocol) - } - } - return listeners, nil -} - -func (lb *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { - return lb.region.SetResourceTags("slb", "instance", []string{lb.LoadBalancerId}, tags, replace) -} diff --git a/pkg/multicloud/apsara/loadbalanceracl.go b/pkg/multicloud/apsara/loadbalanceracl.go deleted file mode 100644 index a11dcb9149..0000000000 --- a/pkg/multicloud/apsara/loadbalanceracl.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type AclEntrys struct { - AclEntry []AclEntry -} - -type AclEntry struct { - AclEntryComment string - AclEntryIP string -} - -type SLoadbalancerAcl struct { - multicloud.SResourceBase - multicloud.ApsaraTags - region *SRegion - - AclId string - AclName string - - AclEntrys AclEntrys - - DepartmentInfo -} - -func (acl *SLoadbalancerAcl) GetAclListenerID() string { - return "" -} - -func (acl *SLoadbalancerAcl) GetName() string { - return acl.AclName -} - -func (acl *SLoadbalancerAcl) GetId() string { - return acl.AclId -} - -func (acl *SLoadbalancerAcl) GetGlobalId() string { - return acl.AclId -} - -func (acl *SLoadbalancerAcl) GetStatus() string { - return "" -} - -func (acl *SLoadbalancerAcl) IsEmulated() bool { - return false -} - -func (acl *SLoadbalancerAcl) Refresh() error { - loadbalancerAcl, err := acl.region.GetLoadbalancerAclDetail(acl.AclId) - if err != nil { - return err - } - return jsonutils.Update(acl, loadbalancerAcl) -} - -func (acl *SLoadbalancerAcl) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { - detail, err := acl.region.GetLoadbalancerAclDetail(acl.AclId) - if err != nil { - log.Errorf("GetLoadbalancerAclDetail %s failed: %v", acl.AclId, err) - return nil - } - entrys := []cloudprovider.SLoadbalancerAccessControlListEntry{} - for _, entry := range detail.AclEntrys.AclEntry { - entrys = append(entrys, cloudprovider.SLoadbalancerAccessControlListEntry{CIDR: entry.AclEntryIP, Comment: entry.AclEntryComment}) - } - return entrys -} - -func (region *SRegion) UpdateAclName(aclId, name string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["AclId"] = aclId - params["AclName"] = name - _, err := region.lbRequest("SetAccessControlListAttribute", params) - return err -} - -func (region *SRegion) RemoveAccessControlListEntry(aclId string, data jsonutils.JSONObject) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["AclId"] = aclId - params["AclEntrys"] = data.String() - _, err := region.lbRequest("RemoveAccessControlListEntry", params) - return err -} - -func (acl *SLoadbalancerAcl) Delete() error { - params := map[string]string{} - params["RegionId"] = acl.region.RegionId - params["AclId"] = acl.AclId - _, err := acl.region.lbRequest("DeleteAccessControlList", params) - return err -} - -func (region *SRegion) GetLoadbalancerAclDetail(aclId string) (*SLoadbalancerAcl, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["AclId"] = aclId - body, err := region.lbRequest("DescribeAccessControlListAttribute", params) - if err != nil { - return nil, err - } - detail := SLoadbalancerAcl{region: region} - return &detail, body.Unmarshal(&detail) -} - -func (region *SRegion) GetLoadBalancerAcls() ([]SLoadbalancerAcl, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - body, err := region.lbRequest("DescribeAccessControlLists", params) - if err != nil { - return nil, err - } - acls := []SLoadbalancerAcl{} - return acls, body.Unmarshal(&acls, "Acls", "Acl") -} - -func (acl *SLoadbalancerAcl) Sync(_acl *cloudprovider.SLoadbalancerAccessControlList) error { - if acl.AclName != _acl.Name { - if err := acl.region.UpdateAclName(acl.AclId, _acl.Name); err != nil { - return err - } - } - entrys := jsonutils.NewArray() - for _, entry := range acl.AclEntrys.AclEntry { - entrys.Add(jsonutils.Marshal(map[string]string{"entry": entry.AclEntryIP, "comment": entry.AclEntryComment})) - } - if entrys.Length() > 0 { - if err := acl.region.RemoveAccessControlListEntry(acl.AclId, entrys); err != nil && !isError(err, "Acl does not have any entry") { - return err - } - } - if len(_acl.Entrys) > 0 { - return acl.region.AddAccessControlListEntry(acl.AclId, _acl.Entrys) - } - return nil -} diff --git a/pkg/multicloud/apsara/loadbalancerbackend.go b/pkg/multicloud/apsara/loadbalancerbackend.go deleted file mode 100644 index b39d96a711..0000000000 --- a/pkg/multicloud/apsara/loadbalancerbackend.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerBackend struct { - multicloud.SResourceBase - multicloud.ApsaraTags - lbbg *SLoadbalancerBackendGroup - - ServerId string - Port int - Weight int - DepartmentInfo -} - -func (backend *SLoadbalancerBackend) GetName() string { - return backend.ServerId -} - -func (backend *SLoadbalancerBackend) GetId() string { - return fmt.Sprintf("%s/%s", backend.lbbg.VServerGroupId, backend.ServerId) -} - -func (backend *SLoadbalancerBackend) GetGlobalId() string { - return backend.GetId() -} - -func (backend *SLoadbalancerBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backend *SLoadbalancerBackend) IsEmulated() bool { - return false -} - -func (backend *SLoadbalancerBackend) Refresh() error { - loadbalancerBackends, err := backend.lbbg.lb.region.GetLoadbalancerBackends(backend.lbbg.VServerGroupId) - if err != nil { - return err - } - for _, loadbalancerBackend := range loadbalancerBackends { - if loadbalancerBackend.ServerId == backend.ServerId { - return jsonutils.Update(backend, loadbalancerBackend) - } - } - return cloudprovider.ErrNotFound -} - -func (backend *SLoadbalancerBackend) GetWeight() int { - return backend.Weight -} - -func (backend *SLoadbalancerBackend) GetPort() int { - return backend.Port -} - -func (backend *SLoadbalancerBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (backend *SLoadbalancerBackend) GetBackendRole() string { - return api.LB_BACKEND_ROLE_DEFAULT -} - -func (backend *SLoadbalancerBackend) GetBackendId() string { - return backend.ServerId -} - -func (backend *SLoadbalancerBackend) GetIpAddress() string { - return "" -} - -func (region *SRegion) GetLoadbalancerBackends(backendgroupId string) ([]SLoadbalancerBackend, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["VServerGroupId"] = backendgroupId - body, err := region.lbRequest("DescribeVServerGroupAttribute", params) - if err != nil { - return nil, err - } - backends := []SLoadbalancerBackend{} - return backends, body.Unmarshal(&backends, "BackendServers", "BackendServer") -} - -func (backend *SLoadbalancerBackend) SyncConf(ctx context.Context, port, weight int) error { - err := backend.lbbg.lb.region.RemoveBackendVServer(backend.lbbg.lb.LoadBalancerId, backend.lbbg.VServerGroupId, backend.ServerId, backend.Port) - if err != nil { - return err - } - return backend.lbbg.lb.region.AddBackendVServer(backend.lbbg.lb.LoadBalancerId, backend.lbbg.VServerGroupId, backend.ServerId, weight, port) -} diff --git a/pkg/multicloud/apsara/loadbalancerbackendgroup.go b/pkg/multicloud/apsara/loadbalancerbackendgroup.go deleted file mode 100644 index 99037d2ea0..0000000000 --- a/pkg/multicloud/apsara/loadbalancerbackendgroup.go +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type Rule struct { - RuleId string - RuleName string - Domain string - Url string -} - -type Rules struct { - Rule []Rule -} - -type Listener struct { - Protocol string - Port int -} - -type Listeners struct { - Listener []Listener -} - -type AssociatedObjects struct { - Rules Rules - Listeners Listeners -} - -type SLoadbalancerBackendGroup struct { - multicloud.SResourceBase - multicloud.ApsaraTags - lb *SLoadbalancer - - VServerGroupId string - VServerGroupName string - AssociatedObjects AssociatedObjects - DepartmentInfo -} - -func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { - return backendgroup.lb -} - -func (backendgroup *SLoadbalancerBackendGroup) GetLoadbalancerId() string { - return backendgroup.lb.GetId() -} - -func (backendgroup *SLoadbalancerBackendGroup) GetProtocolType() string { - return "" -} - -func (backendgroup *SLoadbalancerBackendGroup) GetScheduler() string { - return "" -} - -func (backendgroup *SLoadbalancerBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerBackendGroup) GetName() string { - return backendgroup.VServerGroupName -} - -func (backendgroup *SLoadbalancerBackendGroup) GetId() string { - return backendgroup.VServerGroupId -} - -func (backendgroup *SLoadbalancerBackendGroup) GetGlobalId() string { - return backendgroup.VServerGroupId -} - -func (backendgroup *SLoadbalancerBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backendgroup *SLoadbalancerBackendGroup) IsDefault() bool { - return false -} - -func (backendgroup *SLoadbalancerBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_NORMAL -} - -func (backendgroup *SLoadbalancerBackendGroup) IsEmulated() bool { - return false -} - -func (backendgroup *SLoadbalancerBackendGroup) Refresh() error { - loadbalancerBackendgroups, err := backendgroup.lb.region.GetLoadbalancerBackendgroups(backendgroup.lb.LoadBalancerId) - if err != nil { - return err - } - for _, loadbalancerBackendgroup := range loadbalancerBackendgroups { - if loadbalancerBackendgroup.VServerGroupId == backendgroup.VServerGroupId { - return jsonutils.Update(backendgroup, loadbalancerBackendgroup) - } - } - return cloudprovider.ErrNotFound -} - -func (region *SRegion) GetLoadbalancerBackendgroups(loadbalancerId string) ([]SLoadbalancerBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - body, err := region.lbRequest("DescribeVServerGroups", params) - if err != nil { - return nil, err - } - backendgroups := []SLoadbalancerBackendGroup{} - return backendgroups, body.Unmarshal(&backendgroups, "VServerGroups", "VServerGroup") -} - -func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := backendgroup.lb.region.GetLoadbalancerBackends(backendgroup.VServerGroupId) - if err != nil { - return nil, err - } - ibackends := []cloudprovider.ICloudLoadbalancerBackend{} - for i := 0; i < len(backends); i++ { - backends[i].lbbg = backendgroup - ibackends = append(ibackends, &backends[i]) - } - return ibackends, nil -} - -func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := backendgroup.GetILoadbalancerBackends() - if err != nil { - return nil, err - } - for i := 0; i < len(backends); i++ { - if backends[i].GetGlobalId() == backendId { - return backends[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) CreateLoadbalancerBackendGroup(name, loadbalancerId string, backends []cloudprovider.SLoadbalancerBackend) (*SLoadbalancerBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["VServerGroupName"] = name - params["LoadBalancerId"] = loadbalancerId - if len(backends) > 0 { - servers := jsonutils.NewArray() - for _, backend := range backends { - servers.Add( - jsonutils.Marshal( - map[string]string{ - "ServerId": backend.ExternalID, - "Port": fmt.Sprintf("%d", backend.Port), - "Weight": fmt.Sprintf("%d", backend.Weight), - }, - )) - } - params["BackendServers"] = servers.String() - } - body, err := region.lbRequest("CreateVServerGroup", params) - if err != nil { - return nil, err - } - groupId, err := body.GetString("VServerGroupId") - if err != nil { - return nil, err - } - return region.GetLoadbalancerBackendgroupById(groupId) -} - -func (region *SRegion) GetLoadbalancerBackendgroupById(groupId string) (*SLoadbalancerBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["VServerGroupId"] = groupId - body, err := region.lbRequest("DescribeVServerGroupAttribute", params) - if err != nil { - return nil, err - } - group := &SLoadbalancerBackendGroup{} - return group, body.Unmarshal(group) -} - -func (region *SRegion) UpdateLoadBalancerBackendGroupName(name, groupId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["VServerGroupId"] = groupId - params["VServerGroupName"] = name - _, err := region.lbRequest("SetVServerGroupAttribute", params) - return err -} - -func (backendgroup *SLoadbalancerBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - if group == nil { - return nil - } - - if backendgroup.VServerGroupName != group.Name { - return backendgroup.lb.region.UpdateLoadBalancerBackendGroupName(backendgroup.VServerGroupId, group.Name) - } - return nil -} - -func (region *SRegion) DeleteLoadBalancerBackendGroup(groupId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["VServerGroupId"] = groupId - _, err := region.lbRequest("DeleteVServerGroup", params) - return err -} - -func (backendgroup *SLoadbalancerBackendGroup) Delete(ctx context.Context) error { - return backendgroup.lb.region.DeleteLoadBalancerBackendGroup(backendgroup.VServerGroupId) -} - -func (region *SRegion) AddBackendVServer(loadbalancerId, backendGroupId, serverId string, weight, port int) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["VServerGroupId"] = backendGroupId - servers := jsonutils.NewArray() - servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Weight": fmt.Sprintf("%d", weight), "Port": fmt.Sprintf("%d", port)})) - params["BackendServers"] = servers.String() - _, err := region.lbRequest("AddVServerGroupBackendServers", params) - return err -} - -func (region *SRegion) RemoveBackendVServer(loadbalancerId, backendgroupId, serverId string, port int) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["VServerGroupId"] = backendgroupId - servers := jsonutils.NewArray() - servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Port": fmt.Sprintf("%d", port)})) - params["BackendServers"] = servers.String() - _, err := region.lbRequest("RemoveVServerGroupBackendServers", params) - return err -} - -func (backendgroup *SLoadbalancerBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - if err := backendgroup.lb.region.AddBackendVServer(backendgroup.lb.LoadBalancerId, backendgroup.VServerGroupId, serverId, weight, port); err != nil { - return nil, err - } - return &SLoadbalancerBackend{lbbg: backendgroup, ServerId: serverId, Weight: weight, Port: port}, nil -} - -func (backendgroup *SLoadbalancerBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { - return backendgroup.lb.region.RemoveBackendVServer(backendgroup.lb.LoadBalancerId, backendgroup.VServerGroupId, serverId, port) -} diff --git a/pkg/multicloud/apsara/loadbalancerdefaultbackend.go b/pkg/multicloud/apsara/loadbalancerdefaultbackend.go deleted file mode 100644 index 90f64fe055..0000000000 --- a/pkg/multicloud/apsara/loadbalancerdefaultbackend.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerDefaultBackend struct { - multicloud.SResourceBase - multicloud.ApsaraTags - lbbg *SLoadbalancerDefaultBackendGroup - - ServerId string - Weight int - DepartmentInfo -} - -func (backend *SLoadbalancerDefaultBackend) GetName() string { - return backend.ServerId -} - -func (backend *SLoadbalancerDefaultBackend) GetId() string { - return fmt.Sprintf("%s/%s", backend.lbbg.lb.LoadBalancerId, backend.ServerId) -} - -func (backend *SLoadbalancerDefaultBackend) GetGlobalId() string { - return backend.GetId() -} - -func (backend *SLoadbalancerDefaultBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backend *SLoadbalancerDefaultBackend) IsEmulated() bool { - return false -} - -func (backend *SLoadbalancerDefaultBackend) Refresh() error { - return nil -} - -func (backend *SLoadbalancerDefaultBackend) GetWeight() int { - return backend.Weight -} - -func (backend *SLoadbalancerDefaultBackend) GetPort() int { - return 0 -} - -func (backend *SLoadbalancerDefaultBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (backend *SLoadbalancerDefaultBackend) GetBackendRole() string { - return api.LB_BACKEND_ROLE_DEFAULT -} - -func (backend *SLoadbalancerDefaultBackend) GetBackendId() string { - return backend.ServerId -} - -func (backend *SLoadbalancerDefaultBackend) GetIpAddress() string { - return "" -} - -func (backend *SLoadbalancerDefaultBackend) SyncConf(ctx context.Context, port, weight int) error { - params := map[string]string{} - params["RegionId"] = backend.lbbg.lb.region.RegionId - params["LoadBalancerId"] = backend.lbbg.lb.LoadBalancerId - loadbalancer, err := backend.lbbg.lb.region.GetLoadbalancerDetail(backend.lbbg.lb.LoadBalancerId) - if err != nil { - return err - } - servers := jsonutils.NewArray() - for i := 0; i < len(loadbalancer.BackendServers.BackendServer); i++ { - _backend := loadbalancer.BackendServers.BackendServer[i] - _backend.lbbg = backend.lbbg - if _backend.GetGlobalId() == backend.GetGlobalId() { - _backend.Weight = weight - } - servers.Add( - jsonutils.Marshal( - map[string]string{ - "ServerId": _backend.ServerId, - "Weight": fmt.Sprintf("%d", _backend.Weight), - }, - )) - } - - params["BackendServers"] = servers.String() - _, err = backend.lbbg.lb.region.lbRequest("SetBackendServers", params) - return err -} diff --git a/pkg/multicloud/apsara/loadbalancerdefaultbackendgroup.go b/pkg/multicloud/apsara/loadbalancerdefaultbackendgroup.go deleted file mode 100644 index 84273961b1..0000000000 --- a/pkg/multicloud/apsara/loadbalancerdefaultbackendgroup.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerDefaultBackendGroup struct { - multicloud.SResourceBase - multicloud.ApsaraTags - lb *SLoadbalancer - DepartmentInfo -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { - return backendgroup.lb -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetLoadbalancerId() string { - return backendgroup.lb.GetId() -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetProtocolType() string { - return "" -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetScheduler() string { - return "" -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetName() string { - return fmt.Sprintf("%s(%s)-default", backendgroup.lb.LoadBalancerName, backendgroup.lb.Address) -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetId() string { - return fmt.Sprintf("%s/default", backendgroup.lb.LoadBalancerId) -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetGlobalId() string { - return backendgroup.GetId() -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) IsDefault() bool { - return true -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_DEFAULT -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) IsEmulated() bool { - return false -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) Refresh() error { - return nil -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - loadbalancer, err := backendgroup.lb.region.GetLoadbalancerDetail(backendgroup.lb.LoadBalancerId) - if err != nil { - return nil, err - } - ibackends := []cloudprovider.ICloudLoadbalancerBackend{} - for i := 0; i < len(loadbalancer.BackendServers.BackendServer); i++ { - loadbalancer.BackendServers.BackendServer[i].lbbg = backendgroup - ibackends = append(ibackends, &loadbalancer.BackendServers.BackendServer[i]) - } - return ibackends, nil -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := backendgroup.GetILoadbalancerBackends() - if err != nil { - return nil, err - } - for i := 0; i < len(backends); i++ { - if backends[i].GetGlobalId() == backendId { - return backends[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - return cloudprovider.ErrNotSupported -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) Delete(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (region *SRegion) AddBackendServer(loadbalancerId, serverId string, weight, port int) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - servers := jsonutils.NewArray() - servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Weight": fmt.Sprintf("%d", weight)})) - params["BackendServers"] = servers.String() - _, err := region.lbRequest("AddBackendServers", params) - return err -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - if err := backendgroup.lb.region.AddBackendServer(backendgroup.lb.LoadBalancerId, serverId, weight, port); err != nil { - return nil, err - } - return &SLoadbalancerDefaultBackend{lbbg: backendgroup, ServerId: serverId, Weight: weight}, nil -} - -func (region *SRegion) RemoveBackendServer(loadbalancerId, serverId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - servers := jsonutils.NewArray() - servers.Add(jsonutils.NewString(serverId)) - params["BackendServers"] = servers.String() - _, err := region.lbRequest("RemoveBackendServers", params) - return err -} - -func (backendgroup *SLoadbalancerDefaultBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { - return backendgroup.lb.region.RemoveBackendServer(backendgroup.lb.LoadBalancerId, serverId) -} diff --git a/pkg/multicloud/apsara/loadbalancerhttplistener.go b/pkg/multicloud/apsara/loadbalancerhttplistener.go deleted file mode 100644 index c5849ddc16..0000000000 --- a/pkg/multicloud/apsara/loadbalancerhttplistener.go +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerHTTPListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.ApsaraTags - lb *SLoadbalancer - - ListenerPort int // 负载均衡实例前端使用的端口。 - BackendServerPort int // 负载均衡实例后端使用的端口。 - Bandwidth int // 监听的带宽峰值。 - Status string // 当前监听的状态。取值:starting | running | configuring | stopping | stopped - Description string - - XForwardedFor string // 是否开启通过X-Forwarded-For头字段获取访者真实IP。 - XForwardedFor_SLBIP string // 是否通过SLB-IP头字段获取客户端请求的真实IP。 - XForwardedFor_SLBID string // 是否通过SLB-ID头字段获取负载均衡实例ID。 - XForwardedFor_proto string // 是否通过X-Forwarded-Proto头字段获取负载均衡实例的监听协议。 - Scheduler string // 调度算法。 - StickySession string // 是否开启会话保持。 - StickySessionType string // cookie的处理方式。 - CookieTimeout int // Cookie超时时间。 - Cookie string // 服务器上配置的cookie。 - AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) - - AclType string // 访问控制类型: - //white: 仅转发来自所选访问控制策略组中设置的IP地址或地址段的请求,白名单适用于应用只允许特定IP访问的场景。 - //设置白名单存在一定业务风险。一旦设置白名单,就只有白名单中的IP可以访问负载均衡监听。如果开启了白名单访问,但访问策略组中没有添加任何IP,则负载均衡监听会转发全部请求。 - - //black: 来自所选访问控制策略组中设置的IP地址或地址段的所有请求都不会转发,黑名单适用于应用只限制某些特定IP访问的场景。 - //如果开启了黑名单访问,但访问策略组中没有添加任何IP,则负载均衡监听会转发全部请求。 - - //当AclStatus参数的值为on时,该参数必选。 - - AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 - - HealthCheck string // 是否开启健康检查。 - HealthCheckDomain string // 用于健康检查的域名。 - HealthCheckURI string // 用于健康检查的URI。 - HealthyThreshold int // 健康检查阈值。 - UnhealthyThreshold int // 不健康检查阈值。 - HealthCheckTimeout int // 每次健康检查响应的最大超时间,单位为秒。 - HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 - HealthCheckHttpCode string // 健康检查正常的HTTP状态码。 - HealthCheckConnectPort int // 健康检查的端口。 - Gzip string // 是否开启Gzip压缩。 - EnableHttp2 string // 是否开启HTTP/2特性。取值:on(默认值)|off - - Rules Rules //监听下的转发规则列表,具体请参见RuleList。 - ForwardPort int // HTTP至HTTPS的监听转发端口。暂时只支持将HTTP 80访问重定向转发至HTTPS 443。 说明 如果 ListenerForward的值为 off,该参数不显示。 - ListenerForward string // 表示是否开启HTTP至HTTPS的监听转发。on:表示开启 off:表示未开启 - VServerGroupId string // 绑定的服务器组ID - DepartmentInfo -} - -func (listener *SLoadbalancerHTTPListener) GetName() string { - if len(listener.Description) == 0 { - listener.Refresh() - } - if len(listener.Description) > 0 { - return listener.Description - } - return fmt.Sprintf("HTTP:%d", listener.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPListener) GetId() string { - return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPListener) GetGlobalId() string { - return listerner.GetId() -} - -func (listerner *SLoadbalancerHTTPListener) GetStatus() string { - switch listerner.Status { - case "starting", "running": - return api.LB_STATUS_ENABLED - case "configuring", "stopping", "stopped": - return api.LB_STATUS_DISABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (listerner *SLoadbalancerHTTPListener) IsEmulated() bool { - return false -} - -func (listerner *SLoadbalancerHTTPListener) GetEgressMbps() int { - if listerner.Bandwidth < 1 { - return 0 - } - return listerner.Bandwidth -} - -func (listerner *SLoadbalancerHTTPListener) Refresh() error { - lis, err := listerner.lb.region.GetLoadbalancerHTTPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return err - } - return jsonutils.Update(listerner, lis) -} - -func (listerner *SLoadbalancerHTTPListener) GetListenerType() string { - return "http" -} - -func (listerner *SLoadbalancerHTTPListener) GetListenerPort() int { - return listerner.ListenerPort -} - -func (listerner *SLoadbalancerHTTPListener) GetBackendGroupId() string { - if len(listerner.VServerGroupId) == 0 { - listerner.Refresh() - } - return listerner.VServerGroupId -} - -func (listerner *SLoadbalancerHTTPListener) GetBackendServerPort() int { - return listerner.BackendServerPort -} - -func (listerner *SLoadbalancerHTTPListener) GetScheduler() string { - return listerner.Scheduler -} - -func (listerner *SLoadbalancerHTTPListener) GetAclStatus() string { - return listerner.AclStatus -} - -func (listerner *SLoadbalancerHTTPListener) GetAclType() string { - return listerner.AclType -} - -func (listerner *SLoadbalancerHTTPListener) GetAclId() string { - return listerner.AclId -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheck() string { - return listerner.HealthCheck -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckType() string { - return api.LB_HEALTH_CHECK_HTTP -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckDomain() string { - return listerner.HealthCheckDomain -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckURI() string { - return listerner.HealthCheckURI -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckCode() string { - return listerner.HealthCheckHttpCode -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckRise() int { - return listerner.HealthyThreshold -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckFail() int { - return listerner.UnhealthyThreshold -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckTimeout() int { - return listerner.HealthCheckTimeout -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckInterval() int { - return listerner.HealthCheckInterval -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckReq() string { - return "" -} - -func (listerner *SLoadbalancerHTTPListener) GetHealthCheckExp() string { - return "" -} - -func (listerner *SLoadbalancerHTTPListener) GetStickySession() string { - return listerner.StickySession -} - -func (listerner *SLoadbalancerHTTPListener) GetStickySessionType() string { - return listerner.StickySessionType -} - -func (listerner *SLoadbalancerHTTPListener) GetStickySessionCookie() string { - return listerner.Cookie -} - -func (listerner *SLoadbalancerHTTPListener) GetStickySessionCookieTimeout() int { - return listerner.CookieTimeout -} - -func (listerner *SLoadbalancerHTTPListener) XForwardedForEnabled() bool { - if listerner.XForwardedFor == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPListener) GzipEnabled() bool { - if listerner.Gzip == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPListener) GetCertificateId() string { - return "" -} - -func (listerner *SLoadbalancerHTTPListener) GetTLSCipherPolicy() string { - return "" -} - -func (listerner *SLoadbalancerHTTPListener) HTTP2Enabled() bool { - if listerner.EnableHttp2 == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - rules, err := listerner.lb.region.GetLoadbalancerListenerRules(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return nil, err - } - iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} - for i := 0; i < len(rules); i++ { - rules[i].httpListener = listerner - iRules = append(iRules, &rules[i]) - } - return iRules, nil -} - -func (region *SRegion) GetLoadbalancerHTTPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerHTTPListener, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - body, err := region.lbRequest("DescribeLoadBalancerHTTPListenerAttribute", params) - if err != nil { - return nil, err - } - listener := SLoadbalancerHTTPListener{} - return &listener, body.Unmarshal(&listener) -} - -func (region *SRegion) DeleteLoadbalancerListener(loadbalancerId string, listenerPort int) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - _, err := region.lbRequest("DeleteLoadBalancerListener", params) - return err -} - -func (region *SRegion) CreateLoadbalancerHTTPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - params := region.constructBaseCreateListenerParams(lb, listener) - params = region.constructHTTPCreateListenerParams(params, listener) - _, err := region.lbRequest("CreateLoadBalancerHTTPListener", params) - if err != nil { - return nil, err - } - iListener, err := region.GetLoadbalancerHTTPListener(lb.LoadBalancerId, listener.ListenerPort) - if err != nil { - return nil, err - } - iListener.lb = lb - return iListener, nil -} - -func (listerner *SLoadbalancerHTTPListener) Delete(ctx context.Context) error { - return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - _rule := &SLoadbalancerListenerRule{ - Domain: rule.Domain, - Url: rule.Path, - RuleName: rule.Name, - } - if len(rule.BackendGroupID) > 0 { //&& rule.BackendGroupType == api.LB_BACKENDGROUP_TYPE_NORMAL { - _rule.VServerGroupId = rule.BackendGroupID - } - listenerRule, err := listerner.lb.region.CreateLoadbalancerListenerRule(listerner.ListenerPort, listerner.lb.LoadBalancerId, _rule) - if err != nil { - return nil, err - } - listenerRule.httpListener = listerner - return listenerRule, nil -} - -func (listerner *SLoadbalancerHTTPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - rule, err := listerner.lb.region.GetLoadbalancerListenerRule(ruleId) - if err != nil { - return nil, err - } - rule.httpListener = listerner - return rule, nil -} - -func (region *SRegion) startListener(listenerPort int, loadbalancerId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - _, err := region.lbRequest("StartLoadBalancerListener", params) - return err -} - -func (region *SRegion) stopListener(listenerPort int, loadbalancerId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - _, err := region.lbRequest("StopLoadBalancerListener", params) - return err -} - -func (listerner *SLoadbalancerHTTPListener) Start() error { - return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (listerner *SLoadbalancerHTTPListener) Stop() error { - return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (region *SRegion) SyncLoadbalancerHTTPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { - params := region.constructBaseCreateListenerParams(lb, listener) - params = region.constructHTTPCreateListenerParams(params, listener) - _, err := region.lbRequest("SetLoadBalancerHTTPListenerAttribute", params) - return err -} - -func (listerner *SLoadbalancerHTTPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { - return listerner.lb.region.SyncLoadbalancerHTTPListener(listerner.lb, lblis) -} - -func (listerner *SLoadbalancerHTTPListener) GetClientIdleTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerHTTPListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/apsara/loadbalancerhttpslistener.go b/pkg/multicloud/apsara/loadbalancerhttpslistener.go deleted file mode 100644 index 4a88d4c20d..0000000000 --- a/pkg/multicloud/apsara/loadbalancerhttpslistener.go +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerHTTPSListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.ApsaraTags - lb *SLoadbalancer - - ListenerPort int // 负载均衡实例前端使用的端口。 - BackendServerPort int // 负载均衡实例后端使用的端口。 - Bandwidth int // 监听的带宽峰值。 - Status string // 当前监听的状态。取值:starting | running | configuring | stopping | stopped - Description string - - XForwardedFor string // 是否开启通过X-Forwarded-For头字段获取访者真实IP。 - XForwardedFor_SLBIP string // 是否通过SLB-IP头字段获取客户端请求的真实IP。 - XForwardedFor_SLBID string // 是否通过SLB-ID头字段获取负载均衡实例ID。 - XForwardedFor_proto string // 是否通过X-Forwarded-Proto头字段获取负载均衡实例的监听协议。 - Scheduler string // 调度算法。 - StickySession string // 是否开启会话保持。 - StickySessionType string // cookie的处理方式。 - CookieTimeout int // Cookie超时时间。 - Cookie string // 服务器上配置的cookie。 - AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) - - AclType string // 访问控制类型 - - AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 - - HealthCheck string // 是否开启健康检查。 - HealthCheckDomain string // 用于健康检查的域名。 - HealthCheckURI string // 用于健康检查的URI。 - HealthyThreshold int // 健康检查阈值。 - UnhealthyThreshold int // 不健康检查阈值。 - HealthCheckTimeout int // 每次健康检查响应的最大超时间,单位为秒。 - HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 - HealthCheckHttpCode string // 健康检查正常的HTTP状态码。 - HealthCheckConnectPort int // 健康检查的端口。 - VServerGroupId string // 绑定的服务器组ID。 - ServerCertificateId string // 服务器证书ID。 - CACertificateId string // CA证书ID。 - Gzip string // 是否开启Gzip压缩。 - Rules Rules //监听下的转发规则列表,具体请参见RuleList。 - DomainExtensions string // 域名扩展列表,具体请参见DomainExtensions。 - EnableHttp2 string // 是否开启HTTP/2特性。取值:on(默认值)|off - - TLSCipherPolicy string // - DepartmentInfo -} - -func (listener *SLoadbalancerHTTPSListener) GetName() string { - if len(listener.Description) == 0 { - listener.Refresh() - } - if len(listener.Description) > 0 { - return listener.Description - } - return fmt.Sprintf("HTTPS:%d", listener.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPSListener) GetId() string { - return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPSListener) GetGlobalId() string { - return listerner.GetId() -} - -func (listerner *SLoadbalancerHTTPSListener) GetStatus() string { - switch listerner.Status { - case "starting", "running": - return api.LB_STATUS_ENABLED - case "configuring", "stopping", "stopped": - return api.LB_STATUS_DISABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (listerner *SLoadbalancerHTTPSListener) IsEmulated() bool { - return false -} - -func (listerner *SLoadbalancerHTTPSListener) GetEgressMbps() int { - if listerner.Bandwidth < 1 { - return 0 - } - return listerner.Bandwidth -} - -func (listerner *SLoadbalancerHTTPSListener) Refresh() error { - lis, err := listerner.lb.region.GetLoadbalancerHTTPSListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return err - } - return jsonutils.Update(listerner, lis) -} - -func (listerner *SLoadbalancerHTTPSListener) GetListenerType() string { - return "https" -} - -func (listerner *SLoadbalancerHTTPSListener) GetListenerPort() int { - return listerner.ListenerPort -} - -func (listerner *SLoadbalancerHTTPSListener) GetBackendGroupId() string { - if len(listerner.VServerGroupId) == 0 { - listerner.Refresh() - } - return listerner.VServerGroupId -} - -func (listerner *SLoadbalancerHTTPSListener) GetBackendServerPort() int { - return listerner.BackendServerPort -} - -func (listerner *SLoadbalancerHTTPSListener) GetScheduler() string { - return listerner.Scheduler -} - -func (listerner *SLoadbalancerHTTPSListener) GetAclStatus() string { - return listerner.AclStatus -} - -func (listerner *SLoadbalancerHTTPSListener) GetAclType() string { - return listerner.AclType -} - -func (listerner *SLoadbalancerHTTPSListener) GetAclId() string { - return listerner.AclId -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheck() string { - return listerner.HealthCheck -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckType() string { - return api.LB_HEALTH_CHECK_HTTP -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckDomain() string { - return listerner.HealthCheckDomain -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckURI() string { - return listerner.HealthCheckURI -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckCode() string { - return listerner.HealthCheckHttpCode -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckRise() int { - return listerner.HealthyThreshold -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckFail() int { - return listerner.UnhealthyThreshold -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckTimeout() int { - return listerner.HealthCheckTimeout -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckInterval() int { - return listerner.HealthCheckInterval -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckReq() string { - return "" -} - -func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckExp() string { - return "" -} - -func (listerner *SLoadbalancerHTTPSListener) GetStickySession() string { - return listerner.StickySession -} - -func (listerner *SLoadbalancerHTTPSListener) GetStickySessionType() string { - return listerner.StickySessionType -} - -func (listerner *SLoadbalancerHTTPSListener) GetStickySessionCookie() string { - return listerner.Cookie -} - -func (listerner *SLoadbalancerHTTPSListener) GetStickySessionCookieTimeout() int { - return listerner.CookieTimeout -} - -func (listerner *SLoadbalancerHTTPSListener) XForwardedForEnabled() bool { - if listerner.XForwardedFor == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPSListener) GzipEnabled() bool { - if listerner.Gzip == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPSListener) GetCertificateId() string { - return listerner.ServerCertificateId -} - -func (listerner *SLoadbalancerHTTPSListener) GetTLSCipherPolicy() string { - return listerner.TLSCipherPolicy -} - -func (listerner *SLoadbalancerHTTPSListener) HTTP2Enabled() bool { - if listerner.EnableHttp2 == "on" { - return true - } - return false -} - -func (listerner *SLoadbalancerHTTPSListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - rules, err := listerner.lb.region.GetLoadbalancerListenerRules(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return nil, err - } - iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} - for i := 0; i < len(rules); i++ { - rules[i].httpsListener = listerner - iRules = append(iRules, &rules[i]) - } - return iRules, nil -} - -func (region *SRegion) GetLoadbalancerHTTPSListener(loadbalancerId string, listenerPort int) (*SLoadbalancerHTTPSListener, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - body, err := region.lbRequest("DescribeLoadBalancerHTTPSListenerAttribute", params) - if err != nil { - return nil, err - } - listener := SLoadbalancerHTTPSListener{} - return &listener, body.Unmarshal(&listener) -} - -func (region *SRegion) constructHTTPCreateListenerParams(params map[string]string, listener *cloudprovider.SLoadbalancerListener) map[string]string { - params["HealthCheck"] = listener.HealthCheck - if listener.HealthCheck == "on" { - if len(listener.HealthCheckURI) == 0 { - params["HealthCheckURI"] = "/" - } - //The HealthCheckTimeout parameter is required. - if listener.HealthCheckTimeout < 1 || listener.HealthCheckTimeout > 300 { - listener.HealthCheckTimeout = 5 - } - params["HealthCheckTimeout"] = fmt.Sprintf("%d", listener.HealthCheckTimeout) - } - - if listener.ClientRequestTimeout < 1 || listener.ClientRequestTimeout > 180 { - listener.ClientRequestTimeout = 60 - } - params["RequestTimeout"] = fmt.Sprintf("%d", listener.ClientRequestTimeout) - - if listener.ClientIdleTimeout < 1 || listener.ClientIdleTimeout > 60 { - listener.ClientIdleTimeout = 15 - } - params["IdleTimeout"] = fmt.Sprintf("%d", listener.ClientIdleTimeout) - - params["StickySession"] = listener.StickySession - params["StickySessionType"] = listener.StickySessionType - params["Cookie"] = listener.StickySessionCookie - if listener.StickySessionCookieTimeout < 1 || listener.StickySessionCookieTimeout > 86400 { - listener.StickySessionCookieTimeout = 500 - } - params["CookieTimeout"] = fmt.Sprintf("%d", listener.StickySessionCookieTimeout) - //params["ForwardPort"] = fmt.Sprintf("%d", listener.ForwardPort) //暂不支持 - params["Gzip"] = "off" - if listener.Gzip { - params["Gzip"] = "on" - } - params["XForwardedFor"] = "off" - if listener.XForwardedFor { - params["XForwardedFor"] = "on" - } - return params -} - -func (region *SRegion) CreateLoadbalancerHTTPSListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - params := region.constructBaseCreateListenerParams(lb, listener) - params = region.constructHTTPCreateListenerParams(params, listener) - params["ServerCertificateId"] = listener.CertificateID - if listener.EnableHTTP2 { - params["EnableHttp2"] = "on" - } else { - params["EnableHttp2"] = "off" - } - - if len(listener.TLSCipherPolicy) > 0 { - params["TLSCipherPolicy"] = listener.TLSCipherPolicy - } - _, err := region.lbRequest("CreateLoadBalancerHTTPSListener", params) - if err != nil { - return nil, err - } - iListener, err := region.GetLoadbalancerHTTPSListener(lb.LoadBalancerId, listener.ListenerPort) - if err != nil { - return nil, err - } - iListener.lb = lb - return iListener, nil -} - -func (listerner *SLoadbalancerHTTPSListener) Delete(ctx context.Context) error { - return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerHTTPSListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - _rule := &SLoadbalancerListenerRule{ - Domain: rule.Domain, - Url: rule.Path, - RuleName: rule.Name, - } - if len(rule.BackendGroupID) > 0 { //&& rule.BackendGroupType == api.LB_BACKENDGROUP_TYPE_NORMAL { - _rule.VServerGroupId = rule.BackendGroupID - } - listenerRule, err := listerner.lb.region.CreateLoadbalancerListenerRule(listerner.ListenerPort, listerner.lb.LoadBalancerId, _rule) - if err != nil { - return nil, err - } - listenerRule.httpsListener = listerner - return listenerRule, nil -} - -func (listerner *SLoadbalancerHTTPSListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - rule, err := listerner.lb.region.GetLoadbalancerListenerRule(ruleId) - if err != nil { - return nil, err - } - rule.httpsListener = listerner - return rule, nil -} - -func (listerner *SLoadbalancerHTTPSListener) Start() error { - return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (listerner *SLoadbalancerHTTPSListener) Stop() error { - return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (region *SRegion) SyncLoadbalancerHTTPSListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { - params := region.constructBaseCreateListenerParams(lb, listener) - params = region.constructHTTPCreateListenerParams(params, listener) - params["ServerCertificateId"] = listener.CertificateID - if listener.EnableHTTP2 { - params["EnableHttp2"] = "on" - } else { - params["EnableHttp2"] = "off" - } - - if len(lb.LoadBalancerSpec) > 0 && len(listener.TLSCipherPolicy) > 0 { - params["TLSCipherPolicy"] = listener.TLSCipherPolicy - } - _, err := region.lbRequest("SetLoadBalancerHTTPSListenerAttribute", params) - return err -} - -func (listerner *SLoadbalancerHTTPSListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { - return listerner.lb.region.SyncLoadbalancerHTTPSListener(listerner.lb, lblis) -} - -func (listerner *SLoadbalancerHTTPSListener) GetClientIdleTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerHTTPSListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/apsara/loadbalancerlistenerrule.go b/pkg/multicloud/apsara/loadbalancerlistenerrule.go deleted file mode 100644 index 6f667830ee..0000000000 --- a/pkg/multicloud/apsara/loadbalancerlistenerrule.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerListenerRule struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.ApsaraTags - httpListener *SLoadbalancerHTTPListener - httpsListener *SLoadbalancerHTTPSListener - - Domain string `json:"Domain"` - ListenerSync string - RuleId string - RuleName string `json:"RuleName"` - Url string `json:"Url"` - VServerGroupId string `json:"VServerGroupId"` - DepartmentInfo -} - -func (lbr *SLoadbalancerListenerRule) GetName() string { - return lbr.RuleName -} - -func (lbr *SLoadbalancerListenerRule) GetId() string { - return lbr.RuleId -} - -func (lbr *SLoadbalancerListenerRule) GetGlobalId() string { - return lbr.RuleId -} - -func (lbr *SLoadbalancerListenerRule) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancerListenerRule) IsDefault() bool { - return false -} - -func (lbr *SLoadbalancerListenerRule) IsEmulated() bool { - return false -} - -func (lbr *SLoadbalancerListenerRule) getRegion() *SRegion { - if lbr.httpListener != nil { - return lbr.httpListener.lb.region - } else if lbr.httpsListener != nil { - return lbr.httpsListener.lb.region - } - return nil -} - -func (lbr *SLoadbalancerListenerRule) Refresh() error { - region := lbr.getRegion() - if region == nil { - return fmt.Errorf("failed to find listener for rule %s", lbr.RuleName) - } - rule, err := region.GetLoadbalancerListenerRule(lbr.RuleId) - if err != nil { - return err - } - return jsonutils.Update(lbr, rule) -} - -func (lbr *SLoadbalancerListenerRule) GetCondition() string { - return "" -} - -func (lbr *SLoadbalancerListenerRule) GetDomain() string { - return lbr.Domain -} - -func (lbr *SLoadbalancerListenerRule) GetPath() string { - return lbr.Url -} - -func (lbr *SLoadbalancerListenerRule) GetBackendGroupId() string { - return lbr.VServerGroupId -} - -func (region *SRegion) GetLoadbalancerListenerRules(loadbalancerId string, listenerPort int) ([]SLoadbalancerListenerRule, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - body, err := region.lbRequest("DescribeRules", params) - if err != nil { - return nil, err - } - rules := []SLoadbalancerListenerRule{} - return rules, body.Unmarshal(&rules, "Rules", "Rule") -} - -func (lbr *SLoadbalancerListenerRule) Delete(ctx context.Context) error { - if lbr.httpListener != nil { - return lbr.httpListener.lb.region.DeleteLoadbalancerListenerRule(lbr.RuleId) - } - if lbr.httpsListener != nil { - return lbr.httpsListener.lb.region.DeleteLoadbalancerListenerRule(lbr.RuleId) - } - return fmt.Errorf("failed to find listener for listener rule %s", lbr.RuleName) -} - -func (region *SRegion) DeleteLoadbalancerListenerRule(ruleId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["RuleIds"] = fmt.Sprintf(`["%s"]`, ruleId) - _, err := region.lbRequest("DeleteRules", params) - return err -} - -func (region *SRegion) CreateLoadbalancerListenerRule(listenerPort int, loadbalancerId string, _rule *SLoadbalancerListenerRule) (*SLoadbalancerListenerRule, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - params["LoadBalancerId"] = loadbalancerId - _rules := jsonutils.NewArray() - _rules.Add(jsonutils.Marshal(_rule)) - params["RuleList"] = _rules.String() - body, err := region.lbRequest("CreateRules", params) - if err != nil { - return nil, err - } - rules := []SLoadbalancerListenerRule{} - if err := body.Unmarshal(&rules, "Rules", "Rule"); err != nil { - return nil, err - } - for _, rule := range rules { - if rule.RuleName == _rule.RuleName { - return region.GetLoadbalancerListenerRule(rule.RuleId) - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetLoadbalancerListenerRule(ruleId string) (*SLoadbalancerListenerRule, error) { - if len(ruleId) == 0 { - return nil, cloudprovider.ErrNotFound - } - params := map[string]string{} - params["RegionId"] = region.RegionId - params["RuleId"] = ruleId - body, err := region.lbRequest("DescribeRuleAttribute", params) - if err != nil { - return nil, err - } - rule := &SLoadbalancerListenerRule{RuleId: ruleId} - return rule, body.Unmarshal(rule) -} diff --git a/pkg/multicloud/apsara/loadbalancermasterslavebackend.go b/pkg/multicloud/apsara/loadbalancermasterslavebackend.go deleted file mode 100644 index d1bab474a9..0000000000 --- a/pkg/multicloud/apsara/loadbalancermasterslavebackend.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - "strings" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerMasterSlaveBackend struct { - multicloud.SResourceBase - multicloud.ApsaraTags - lbbg *SLoadbalancerMasterSlaveBackendGroup - - ServerId string - Weight int - Port int - ServerType string - DepartmentInfo -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetName() string { - return backend.ServerId -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetId() string { - return fmt.Sprintf("%s/%s", backend.lbbg.MasterSlaveServerGroupId, backend.ServerId) -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetGlobalId() string { - return backend.GetId() -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backend *SLoadbalancerMasterSlaveBackend) IsEmulated() bool { - return false -} - -func (backend *SLoadbalancerMasterSlaveBackend) Refresh() error { - return nil -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetWeight() int { - return backend.Weight -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetPort() int { - return backend.Port -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetBackendRole() string { - return strings.ToLower(backend.ServerType) -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetBackendId() string { - return backend.ServerId -} - -func (backend *SLoadbalancerMasterSlaveBackend) GetIpAddress() string { - return "" -} - -func (backend *SLoadbalancerMasterSlaveBackend) SyncConf(ctx context.Context, port, weight int) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/apsara/loadbalancermasterslavebackendgroup.go b/pkg/multicloud/apsara/loadbalancermasterslavebackendgroup.go deleted file mode 100644 index 5de290ed38..0000000000 --- a/pkg/multicloud/apsara/loadbalancermasterslavebackendgroup.go +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerMasterSlaveBackendGroup struct { - multicloud.SResourceBase - multicloud.ApsaraTags - lb *SLoadbalancer - - MasterSlaveServerGroupId string - MasterSlaveServerGroupName string - DepartmentInfo -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetLoadbalancerId() string { - return backendgroup.lb.GetId() -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetProtocolType() string { - return "" -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetScheduler() string { - return "" -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - return nil, nil -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetName() string { - return backendgroup.MasterSlaveServerGroupName -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetId() string { - return backendgroup.MasterSlaveServerGroupId -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetGlobalId() string { - return backendgroup.GetId() -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) IsEmulated() bool { - return false -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Refresh() error { - return nil -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) IsDefault() bool { - return false -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE -} - -func (region *SRegion) GetLoadbalancerMasterSlaveBackendgroups(loadbalancerId string) ([]SLoadbalancerMasterSlaveBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - body, err := region.lbRequest("DescribeMasterSlaveServerGroups", params) - if err != nil { - return nil, err - } - backendgroups := []SLoadbalancerMasterSlaveBackendGroup{} - return backendgroups, body.Unmarshal(&backendgroups, "MasterSlaveServerGroups", "MasterSlaveServerGroup") -} - -func (region *SRegion) GetLoadbalancerMasterSlaveBackends(backendgroupId string) ([]SLoadbalancerMasterSlaveBackend, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["MasterSlaveServerGroupId"] = backendgroupId - body, err := region.lbRequest("DescribeMasterSlaveServerGroupAttribute", params) - if err != nil { - return nil, err - } - backends := []SLoadbalancerMasterSlaveBackend{} - return backends, body.Unmarshal(&backends, "MasterSlaveBackendServers", "MasterSlaveBackendServer") -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := backendgroup.lb.region.GetLoadbalancerMasterSlaveBackends(backendgroup.MasterSlaveServerGroupId) - if err != nil { - return nil, err - } - ibackends := []cloudprovider.ICloudLoadbalancerBackend{} - for i := 0; i < len(backends); i++ { - backends[i].lbbg = backendgroup - ibackends = append(ibackends, &backends[i]) - } - return ibackends, nil -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := backendgroup.GetILoadbalancerBackends() - if err != nil { - return nil, err - } - for i := 0; i < len(backends); i++ { - if backends[i].GetGlobalId() == backendId { - return backends[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) CreateLoadbalancerMasterSlaveBackendGroup(name, loadbalancerId string, backends []cloudprovider.SLoadbalancerBackend) (*SLoadbalancerMasterSlaveBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["MasterSlaveServerGroupName"] = name - params["LoadBalancerId"] = loadbalancerId - if len(backends) != 2 { - return nil, fmt.Errorf("master slave backendgorup must contain two backend") - } - servers := jsonutils.NewArray() - for _, backend := range backends { - serverType := "Slave" - if backend.Index == 0 { - serverType = "Master" - } - servers.Add( - jsonutils.Marshal( - map[string]string{ - "ServerId": backend.ExternalID, - "Port": fmt.Sprintf("%d", backend.Port), - "Weight": fmt.Sprintf("%d", backend.Weight), - "ServerType": serverType, - }, - )) - } - params["MasterSlaveBackendServers"] = servers.String() - body, err := region.lbRequest("CreateMasterSlaveServerGroup", params) - if err != nil { - return nil, err - } - groupId, err := body.GetString("MasterSlaveServerGroupId") - if err != nil { - return nil, err - } - return region.GetLoadbalancerMasterSlaveBackendgroupById(groupId) -} - -func (region *SRegion) GetLoadbalancerMasterSlaveBackendgroupById(groupId string) (*SLoadbalancerMasterSlaveBackendGroup, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["MasterSlaveServerGroupId"] = groupId - params["NeedInstanceDetail"] = "true" - body, err := region.lbRequest("DescribeMasterSlaveServerGroupAttribute", params) - if err != nil { - return nil, err - } - group := &SLoadbalancerMasterSlaveBackendGroup{} - return group, body.Unmarshal(group) -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - return nil -} - -func (region *SRegion) DeleteLoadbalancerMasterSlaveBackendgroup(groupId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["MasterSlaveServerGroupId"] = groupId - _, err := region.lbRequest("DeleteMasterSlaveServerGroup", params) - return err -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Delete(ctx context.Context) error { - return backendgroup.lb.region.DeleteLoadbalancerMasterSlaveBackendgroup(backendgroup.MasterSlaveServerGroupId) -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/apsara/loadbalancerservercertificate.go b/pkg/multicloud/apsara/loadbalancerservercertificate.go deleted file mode 100644 index f4b0569029..0000000000 --- a/pkg/multicloud/apsara/loadbalancerservercertificate.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SubjectAlternativeNames struct { - SubjectAlternativeName []string -} - -type SLoadbalancerServerCertificate struct { - multicloud.SResourceBase - multicloud.ApsaraTags - region *SRegion - - ServerCertificateId string // 服务器证书ID。 - ServerCertificateName string // 服务器证书名称。 - Fingerprint string // 服务器证书的指纹。 - CreateTime string // 服务器证书上传的时间。 - CreateTimeStamp uint64 // 服务器证书上传的时间戳。 - IsAliCloudCertificate int // 是否是阿里云证书。0代表不是阿里云证书。 - AliCloudCertificateName string // 阿里云证书名称。 - AliCloudCertificateId string // 阿里云证书ID。 - ExpireTime time.Time // 过期时间。 - ExpireTimeStamp uint64 // 过期时间戳。 - CommonName string // 域名,对应证书的CommonName字段。 - SubjectAlternativeNames SubjectAlternativeNames // 数组格式,返回证书的备用域名列表,对应证书的Subject Alternative Name字段,详情请参见SubjectAlternativeNames。 - RegionId string // 负载均衡实例的地域。 - DepartmentInfo -} - -func (certificate *SLoadbalancerServerCertificate) GetPublickKey() string { - return "" -} - -func (certificate *SLoadbalancerServerCertificate) GetPrivateKey() string { - return "" -} - -func (certificate *SLoadbalancerServerCertificate) GetName() string { - return certificate.ServerCertificateName -} - -func (certificate *SLoadbalancerServerCertificate) GetId() string { - return certificate.ServerCertificateId -} - -func (certificate *SLoadbalancerServerCertificate) GetGlobalId() string { - return certificate.GetId() -} - -func (certificate *SLoadbalancerServerCertificate) GetStatus() string { - return "" -} - -func (certificate *SLoadbalancerServerCertificate) IsEmulated() bool { - return false -} - -func (certificate *SLoadbalancerServerCertificate) GetCommonName() string { - return certificate.CommonName -} - -func (certificate *SLoadbalancerServerCertificate) GetSubjectAlternativeNames() string { - return strings.Join(certificate.SubjectAlternativeNames.SubjectAlternativeName, ",") -} - -func (certificate *SLoadbalancerServerCertificate) GetFingerprint() string { - return fmt.Sprintf("sha1:%s", strings.Replace(certificate.Fingerprint, ":", "", -1)) -} - -func (certificate *SLoadbalancerServerCertificate) GetExpireTime() time.Time { - return certificate.ExpireTime -} - -func (certificate *SLoadbalancerServerCertificate) Refresh() error { - return nil -} - -func (region *SRegion) UpdateServerCertificateName(certId, name string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["ServerCertificateId"] = certId - params["ServerCertificateName"] = name - _, err := region.lbRequest("SetServerCertificateName", params) - return err -} - -func (certificate *SLoadbalancerServerCertificate) Sync(name string, privateKey string, publicKey string) error { - if certificate.ServerCertificateName != name { - return certificate.region.UpdateServerCertificateName(certificate.ServerCertificateId, name) - } - return nil -} - -func (certificate *SLoadbalancerServerCertificate) Delete() error { - return certificate.region.DeleteServerCertificate(certificate.ServerCertificateId) -} - -func (region *SRegion) DeleteServerCertificate(certId string) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["ServerCertificateId"] = certId - _, err := region.lbRequest("DeleteServerCertificate", params) - return err -} - -func (region *SRegion) GetLoadbalancerServerCertificates() ([]SLoadbalancerServerCertificate, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - body, err := region.lbRequest("DescribeServerCertificates", params) - if err != nil { - return nil, err - } - certificates := []SLoadbalancerServerCertificate{} - return certificates, body.Unmarshal(&certificates, "ServerCertificates", "ServerCertificate") -} diff --git a/pkg/multicloud/apsara/loadbalancertcplistener.go b/pkg/multicloud/apsara/loadbalancertcplistener.go deleted file mode 100644 index 2f31096885..0000000000 --- a/pkg/multicloud/apsara/loadbalancertcplistener.go +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerTCPListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.ApsaraTags - lb *SLoadbalancer - - ListenerPort int // 负载均衡实例前端使用的端口。 - BackendServerPort int // 负载均衡实例后端使用的端口。 - Bandwidth int // 监听的带宽峰值。 - Status string // 当前监听的状态,取值:starting | running | configuring | stopping | stopped - Description string - - Scheduler string // 调度算法。 - VServerGroupId string // 绑定的服务器组ID。 - MasterSlaveServerGroupId string // 绑定的主备服务器组ID。 - AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) - PersistenceTimeout int //是否开启了会话保持。取值为0时,表示没有开启。 - - AclType string // 访问控制类型 - - AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 - - HealthCheck string // 是否开启健康检查。 - HealthCheckType string //TCP协议监听的健康检查方式。取值:tcp | http - HealthyThreshold int // 健康检查阈值。 - UnhealthyThreshold int // 不健康检查阈值。 - HealthCheckConnectTimeout int // 每次健康检查响应的最大超时间,单位为秒。 - HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 - HealthCheckConnectPort int // 健康检查的端口。 - DepartmentInfo -} - -func (listener *SLoadbalancerTCPListener) GetName() string { - if len(listener.Description) == 0 { - listener.Refresh() - } - if len(listener.Description) > 0 { - return listener.Description - } - return fmt.Sprintf("TCP:%d", listener.ListenerPort) -} - -func (listerner *SLoadbalancerTCPListener) GetId() string { - return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerTCPListener) GetGlobalId() string { - return listerner.GetId() -} - -func (listerner *SLoadbalancerTCPListener) GetStatus() string { - switch listerner.Status { - case "starting", "running": - return api.LB_STATUS_ENABLED - case "configuring", "stopping", "stopped": - return api.LB_STATUS_DISABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (listerner *SLoadbalancerTCPListener) GetEgressMbps() int { - if listerner.Bandwidth < 1 { - return 0 - } - return listerner.Bandwidth -} - -func (listerner *SLoadbalancerTCPListener) IsEmulated() bool { - return false -} - -func (listerner *SLoadbalancerTCPListener) Refresh() error { - lis, err := listerner.lb.region.GetLoadbalancerTCPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return err - } - return jsonutils.Update(listerner, lis) -} - -func (listerner *SLoadbalancerTCPListener) GetListenerType() string { - return "tcp" -} -func (listerner *SLoadbalancerTCPListener) GetListenerPort() int { - return listerner.ListenerPort -} - -func (listerner *SLoadbalancerTCPListener) GetBackendGroupId() string { - if len(listerner.VServerGroupId) > 0 { - return listerner.VServerGroupId - } - return listerner.MasterSlaveServerGroupId -} - -func (listerner *SLoadbalancerTCPListener) GetScheduler() string { - return listerner.Scheduler -} - -func (listerner *SLoadbalancerTCPListener) GetAclStatus() string { - return listerner.AclStatus -} - -func (listerner *SLoadbalancerTCPListener) GetAclType() string { - return listerner.AclType -} - -func (listerner *SLoadbalancerTCPListener) GetAclId() string { - return listerner.AclId -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheck() string { - return listerner.HealthCheck -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckType() string { - return listerner.HealthCheckType -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckDomain() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckURI() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckCode() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckRise() int { - return listerner.HealthyThreshold -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckFail() int { - return listerner.UnhealthyThreshold -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckTimeout() int { - return listerner.HealthCheckConnectTimeout -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckInterval() int { - return listerner.HealthCheckInterval -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckReq() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetHealthCheckExp() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetStickySession() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetStickySessionType() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetStickySessionCookie() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetStickySessionCookieTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerTCPListener) XForwardedForEnabled() bool { - return false -} - -func (listerner *SLoadbalancerTCPListener) GzipEnabled() bool { - return false -} - -func (listerner *SLoadbalancerTCPListener) GetCertificateId() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) GetTLSCipherPolicy() string { - return "" -} - -func (listerner *SLoadbalancerTCPListener) HTTP2Enabled() bool { - return false -} - -func (listerner *SLoadbalancerTCPListener) GetBackendServerPort() int { - return listerner.BackendServerPort -} - -func (listerner *SLoadbalancerTCPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - return []cloudprovider.ICloudLoadbalancerListenerRule{}, nil -} - -func (region *SRegion) GetLoadbalancerTCPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerTCPListener, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - body, err := region.lbRequest("DescribeLoadBalancerTCPListenerAttribute", params) - if err != nil { - return nil, err - } - listener := SLoadbalancerTCPListener{} - return &listener, body.Unmarshal(&listener) -} - -func (region *SRegion) constructBaseCreateListenerParams(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) map[string]string { - params := map[string]string{} - params["RegionId"] = region.RegionId - if listener.EgressMbps < 1 { - listener.EgressMbps = -1 - } - params["Bandwidth"] = fmt.Sprintf("%d", listener.EgressMbps) - params["ListenerPort"] = fmt.Sprintf("%d", listener.ListenerPort) - params["LoadBalancerId"] = lb.LoadBalancerId - if len(listener.AccessControlListID) > 0 { - params["AclId"] = listener.AccessControlListID - } - if utils.IsInStringArray(listener.AccessControlListStatus, []string{"on", "off"}) { - params["AclStatus"] = listener.AccessControlListStatus - } - if utils.IsInStringArray(listener.AccessControlListType, []string{"white", "black"}) { - params["AclType"] = listener.AccessControlListType - } - switch listener.BackendGroupType { - case api.LB_BACKENDGROUP_TYPE_NORMAL: - params["VServerGroupId"] = listener.BackendGroupID - params["VServerGroup"] = "on" - case api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE: - params["MasterSlaveServerGroupId"] = listener.BackendGroupID - params["MasterSlaveServerGroup"] = "on" - case api.LB_BACKENDGROUP_TYPE_DEFAULT: - params["BackendServerPort"] = fmt.Sprintf("%d", listener.BackendServerPort) - } - if len(listener.Name) > 0 { - params["Description"] = listener.Name - } - - if utils.IsInStringArray(listener.ListenerType, []string{api.LB_LISTENER_TYPE_TCP, api.LB_LISTENER_TYPE_UDP}) { - if listener.HealthCheckTimeout >= 1 && listener.HealthCheckTimeout <= 300 { - params["HealthCheckConnectTimeout"] = fmt.Sprintf("%d", listener.HealthCheckTimeout) - } - } - switch listener.ListenerType { - case api.LB_LISTENER_TYPE_UDP: - if len(listener.HealthCheckReq) > 0 { - params["healthCheckReq"] = listener.HealthCheckReq - } - if len(listener.HealthCheckExp) > 0 { - params["healthCheckExp"] = listener.HealthCheckExp - } - } - - if len(listener.HealthCheckDomain) > 0 { - params["HealthCheckDomain"] = listener.HealthCheckDomain - } - - if len(listener.HealthCheckHttpCode) > 0 { - params["HealthCheckHttpCode"] = listener.HealthCheckHttpCode - } - - if len(listener.HealthCheckURI) > 0 { - params["HealthCheckURI"] = listener.HealthCheckURI - } - - if listener.HealthCheckRise >= 2 && listener.HealthCheckRise <= 10 { - params["HealthyThreshold"] = fmt.Sprintf("%d", listener.HealthCheckRise) - } - - if listener.HealthCheckFail >= 2 && listener.HealthCheckFail <= 10 { - params["UnhealthyThreshold"] = fmt.Sprintf("%d", listener.HealthCheckFail) - } - - if listener.HealthCheckInterval >= 1 && listener.HealthCheckInterval <= 50 { - params["healthCheckInterval"] = fmt.Sprintf("%d", listener.HealthCheckInterval) - } - - params["Scheduler"] = listener.Scheduler - return params -} - -func (region *SRegion) CreateLoadbalancerTCPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - params := region.constructBaseCreateListenerParams(lb, listener) - _, err := region.lbRequest("CreateLoadBalancerTCPListener", params) - if err != nil { - return nil, err - } - iListener, err := region.GetLoadbalancerTCPListener(lb.LoadBalancerId, listener.ListenerPort) - if err != nil { - return nil, err - } - iListener.lb = lb - return iListener, nil -} - -func (listerner *SLoadbalancerTCPListener) Delete(ctx context.Context) error { - return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerTCPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (listerner *SLoadbalancerTCPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (listerner *SLoadbalancerTCPListener) Start() error { - return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (listerner *SLoadbalancerTCPListener) Stop() error { - return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (region *SRegion) SyncLoadbalancerTCPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { - params := region.constructBaseCreateListenerParams(lb, listener) - _, err := region.lbRequest("SetLoadBalancerTCPListenerAttribute", params) - return err -} - -func (listerner *SLoadbalancerTCPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { - return listerner.lb.region.SyncLoadbalancerTCPListener(listerner.lb, lblis) -} - -func (listerner *SLoadbalancerTCPListener) GetClientIdleTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerTCPListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/apsara/loadbalancerudplistener.go b/pkg/multicloud/apsara/loadbalancerudplistener.go deleted file mode 100644 index 72662e56cb..0000000000 --- a/pkg/multicloud/apsara/loadbalancerudplistener.go +++ /dev/null @@ -1,291 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerUDPListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.ApsaraTags - lb *SLoadbalancer - - ListenerPort int // 负载均衡实例前端使用的端口。 - BackendServerPort int // 负载均衡实例后端使用的端口。 - Bandwidth int // 监听的带宽峰值。 - Status string // 当前监听的状态,取值:starting | running | configuring | stopping | stopped - Description string - - Scheduler string // 调度算法 - VServerGroupId string // 绑定的服务器组ID。 - MasterSlaveServerGroupId string // 绑定的主备服务器组ID。 - AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) - - AclType string // 访问控制类型: - - AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 - - HealthCheck string // 是否开启健康检查。 - HealthyThreshold int // 健康检查阈值。 - UnhealthyThreshold int // 不健康检查阈值。 - HealthCheckConnectTimeout int // 每次健康检查响应的最大超时间,单位为秒。 - HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 - HealthCheckConnectPort int // 健康检查的端口。 - - HealthCheckExp string // UDP监听健康检查的响应串 - HealthCheckReq string // UDP监听健康检查的请求串 - DepartmentInfo -} - -func (listener *SLoadbalancerUDPListener) GetName() string { - if len(listener.Description) == 0 { - listener.Refresh() - } - if len(listener.Description) > 0 { - return listener.Description - } - return fmt.Sprintf("UDP:%d", listener.ListenerPort) -} - -func (listerner *SLoadbalancerUDPListener) GetId() string { - return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerUDPListener) GetGlobalId() string { - return listerner.GetId() -} - -func (listerner *SLoadbalancerUDPListener) GetStatus() string { - switch listerner.Status { - case "starting", "running": - return api.LB_STATUS_ENABLED - case "configuring", "stopping", "stopped": - return api.LB_STATUS_DISABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (listerner *SLoadbalancerUDPListener) GetEgressMbps() int { - if listerner.Bandwidth < 1 { - return 0 - } - return listerner.Bandwidth -} - -func (listerner *SLoadbalancerUDPListener) IsEmulated() bool { - return false -} - -func (listerner *SLoadbalancerUDPListener) Refresh() error { - lis, err := listerner.lb.region.GetLoadbalancerUDPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) - if err != nil { - return err - } - return jsonutils.Update(listerner, lis) -} - -func (listerner *SLoadbalancerUDPListener) GetListenerType() string { - return "udp" -} - -func (listerner *SLoadbalancerUDPListener) GetListenerPort() int { - return listerner.ListenerPort -} - -func (listerner *SLoadbalancerUDPListener) GetBackendGroupId() string { - if len(listerner.VServerGroupId) > 0 { - return listerner.VServerGroupId - } - return listerner.MasterSlaveServerGroupId -} - -func (listerner *SLoadbalancerUDPListener) GetBackendServerPort() int { - return listerner.BackendServerPort -} - -func (listerner *SLoadbalancerUDPListener) GetScheduler() string { - return listerner.Scheduler -} - -func (listerner *SLoadbalancerUDPListener) GetAclStatus() string { - return listerner.AclStatus -} - -func (listerner *SLoadbalancerUDPListener) GetAclType() string { - return listerner.AclType -} - -func (listerner *SLoadbalancerUDPListener) GetAclId() string { - return listerner.AclId -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheck() string { - return listerner.HealthCheck -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckType() string { - return api.LB_HEALTH_CHECK_UDP -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckDomain() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckURI() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckCode() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckRise() int { - return listerner.HealthyThreshold -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckFail() int { - return listerner.UnhealthyThreshold -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckTimeout() int { - return listerner.HealthCheckConnectTimeout -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckInterval() int { - return listerner.HealthCheckInterval -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckReq() string { - return listerner.HealthCheckReq -} - -func (listerner *SLoadbalancerUDPListener) GetHealthCheckExp() string { - return listerner.HealthCheckExp -} - -func (listerner *SLoadbalancerUDPListener) GetStickySession() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetStickySessionType() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetStickySessionCookie() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetStickySessionCookieTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerUDPListener) XForwardedForEnabled() bool { - return false -} - -func (listerner *SLoadbalancerUDPListener) GzipEnabled() bool { - return false -} - -func (listerner *SLoadbalancerUDPListener) GetCertificateId() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) GetTLSCipherPolicy() string { - return "" -} - -func (listerner *SLoadbalancerUDPListener) HTTP2Enabled() bool { - return false -} - -func (listerner *SLoadbalancerUDPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - return []cloudprovider.ICloudLoadbalancerListenerRule{}, nil -} - -func (region *SRegion) GetLoadbalancerUDPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerUDPListener, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerId"] = loadbalancerId - params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) - body, err := region.lbRequest("DescribeLoadBalancerUDPListenerAttribute", params) - if err != nil { - return nil, err - } - listener := SLoadbalancerUDPListener{} - return &listener, body.Unmarshal(&listener) -} - -func (region *SRegion) CreateLoadbalancerUDPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - params := region.constructBaseCreateListenerParams(lb, listener) - _, err := region.lbRequest("CreateLoadBalancerUDPListener", params) - if err != nil { - return nil, err - } - iListener, err := region.GetLoadbalancerUDPListener(lb.LoadBalancerId, listener.ListenerPort) - if err != nil { - return nil, err - } - iListener.lb = lb - return iListener, nil -} - -func (listerner *SLoadbalancerUDPListener) Delete(ctx context.Context) error { - return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) -} - -func (listerner *SLoadbalancerUDPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (listerner *SLoadbalancerUDPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (listerner *SLoadbalancerUDPListener) Start() error { - return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (listerner *SLoadbalancerUDPListener) Stop() error { - return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) -} - -func (region *SRegion) SyncLoadbalancerUDPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { - params := region.constructBaseCreateListenerParams(lb, listener) - _, err := region.lbRequest("SetLoadBalancerUDPListenerAttribute", params) - return err -} - -func (listerner *SLoadbalancerUDPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { - return listerner.lb.region.SyncLoadbalancerUDPListener(listerner.lb, lblis) -} - -func (listerner *SLoadbalancerUDPListener) GetClientIdleTimeout() int { - return 0 -} - -func (listerner *SLoadbalancerUDPListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/apsara/monitor.go b/pkg/multicloud/apsara/monitor.go deleted file mode 100644 index d6234988c1..0000000000 --- a/pkg/multicloud/apsara/monitor.go +++ /dev/null @@ -1,457 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - APSARA_API_VERSION_METRICS = "2019-01-01" -) - -func (self *SApsaraClient) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getDefaultClient("") - if err != nil { - return nil, errors.Wrap(err, "getDefaultClient") - } - domain := self.getDomain(APSARA_PRODUCT_METRICS) - return productRequest(client, APSARA_PRODUCT_METRICS, domain, APSARA_API_VERSION_METRICS, action, params, self.debug) -} - -type MetricData struct { - Timestamp int64 - BucketName string - InstanceId string - UserId string - Value float64 - Average float64 - Minimum float64 - Maximum float64 - Diskname string - Device string -} - -func (d MetricData) GetValue() float64 { - if d.Average > 0 { - return d.Average - } - if d.Maximum > 0 { - return d.Maximum - } - if d.Minimum > 0 { - return d.Minimum - } - if d.Value > 0 { - return d.Value - } - return 0.0 -} - -func (d MetricData) GetTags() map[string]string { - ret := map[string]string{} - if len(d.Device) > 0 { - ret[cloudprovider.METRIC_TAG_DEVICE] = fmt.Sprintf("%s(%s)", d.Device, d.Diskname) - } - return ret -} - -func (self *SApsaraClient) ListMetrics(ns, metricName string, start, end time.Time) ([]MetricData, error) { - result := []MetricData{} - nextToken := "" - for { - part, next, err := self.listMetrics(ns, metricName, nextToken, start, end) - if err != nil { - return nil, errors.Wrap(err, "listMetrics") - } - result = append(result, part...) - if len(next) == 0 { - break - } - nextToken = next - } - return result, nil -} - -func (self *SApsaraClient) listMetrics(ns, metricName, nextToken string, start, end time.Time) ([]MetricData, string, error) { - params := make(map[string]string) - params["MetricName"] = metricName - params["Namespace"] = ns - params["Length"] = "2000" - if len(nextToken) > 0 { - params["NextToken"] = nextToken - } - if len(self.organizationId) > 0 { - params["Department"] = self.organizationId - } - params["StartTime"] = fmt.Sprintf("%d", start.UnixMilli()) - params["EndTime"] = fmt.Sprintf("%d", end.UnixMilli()) - resp, err := self.metricsRequest("DescribeMetricList", params) - if err != nil { - return nil, "", errors.Wrap(err, "DescribeMetricList") - } - ret := struct { - NextToken string - Datapoints string - }{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, "", errors.Wrapf(err, "resp.Unmarshal") - } - obj, err := jsonutils.ParseString(ret.Datapoints) - if err != nil { - return nil, "", errors.Wrap(err, "jsonutils.ParseString") - } - result := []MetricData{} - err = obj.Unmarshal(&result) - if err != nil { - return nil, "", errors.Wrapf(err, "obj.Unmarshal") - } - return result, ret.NextToken, nil -} - -func (self *SApsaraClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_BUCKET: - return self.GetOssMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: - return self.GetRedisMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_RDS: - return self.GetRdsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_LB: - return self.GetElbMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) - } -} - -func (self *SApsaraClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricTags, tagKey := map[string]string{}, "" - switch opts.MetricType { - case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: - metricTags = map[string]string{ - "CPUUtilization": "", - } - case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: - metricTags = map[string]string{ - "InternetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, - "IntranetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - } - tagKey = cloudprovider.METRIC_TAG_NET_TYPE - case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: - metricTags = map[string]string{ - "InternetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, - "IntranetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - } - tagKey = cloudprovider.METRIC_TAG_NET_TYPE - case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: - metricTags = map[string]string{ - "DiskReadBPS": "", - } - case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: - metricTags = map[string]string{ - "DiskWriteBPS": "", - } - case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: - metricTags = map[string]string{ - "DiskReadIOPS": "", - } - case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: - metricTags = map[string]string{ - "DiskWriteIOPS": "", - } - case cloudprovider.VM_METRIC_TYPE_MEM_USAGE: - metricTags = map[string]string{ - "memory_usedutilization": "", - } - case cloudprovider.VM_METRIC_TYPE_DISK_USAGE: - metricTags = map[string]string{ - "diskusage_utilization": "", - } - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) - } - ret := []cloudprovider.MetricValues{} - for metric, tag := range metricTags { - result, err := self.ListMetrics("acs_ecs_dashboard", metric, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("ListMetric(%s) error: %v", metric, err) - continue - } - tags := map[string]string{} - if len(tag) > 0 && len(tagKey) > 0 { - tags[tagKey] = tag - } - for i := range result { - dataTag := result[i].GetTags() - for k, v := range tags { - dataTag[k] = v - } - ret = append(ret, cloudprovider.MetricValues{ - Id: result[i].InstanceId, - MetricType: opts.MetricType, - Values: []cloudprovider.MetricValue{ - { - Timestamp: time.UnixMilli(result[i].Timestamp), - Value: result[i].GetValue(), - Tags: dataTag, - }, - }, - }) - } - } - return ret, nil -} - -func (self *SApsaraClient) GetOssMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricTags, tagKey := map[string]string{}, "" - switch opts.MetricType { - case cloudprovider.BUCKET_METRIC_TYPE_LATECY: - metricTags = map[string]string{ - "GetObjectE2eLatency": cloudprovider.METRIC_TAG_REQUST_GET, - "PostObjectE2eLatency": cloudprovider.METRIC_TAG_REQUST_GET, - } - tagKey = cloudprovider.METRIC_TAG_REQUST - case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_TX: - metricTags = map[string]string{ - "InternetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, - "IntranetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - } - tagKey = cloudprovider.METRIC_TAG_REQUST - case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_RX: - metricTags = map[string]string{ - "InternetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, - "IntranetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - } - tagKey = cloudprovider.METRIC_TAG_NET_TYPE - case cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT: - metricTags = map[string]string{ - "GetObjectCount": cloudprovider.METRIC_TAG_REQUST_GET, - "PostObjectCount": cloudprovider.METRIC_TAG_REQUST_POST, - "ServerErrorCount": cloudprovider.METRIC_TAG_REQUST_5XX, - } - tagKey = cloudprovider.METRIC_TAG_REQUST - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) - } - ret := []cloudprovider.MetricValues{} - for metric, tag := range metricTags { - result, err := self.ListMetrics("acs_oss_dashboard", metric, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("ListMetric(%s) error: %v", metric, err) - continue - } - for i := range result { - ret = append(ret, cloudprovider.MetricValues{ - Id: result[i].BucketName, - MetricType: opts.MetricType, - Values: []cloudprovider.MetricValue{ - { - Timestamp: time.UnixMilli(result[i].Timestamp), - Value: result[i].GetValue(), - Tags: map[string]string{ - tagKey: tag, - }, - }, - }, - }) - } - } - return ret, nil -} - -func (self *SApsaraClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricTags, tagKey := map[string]string{}, "" - switch opts.MetricType { - case cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE: - metricTags = map[string]string{ - "CpuUsage": "", - } - case cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE: - metricTags = map[string]string{ - "MemoryUsage": "", - } - case cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX: - metricTags = map[string]string{ - "IntranetIn": "", - } - case cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX: - metricTags = map[string]string{ - "IntranetOut": "", - } - case cloudprovider.REDIS_METRIC_TYPE_USED_CONN: - metricTags = map[string]string{ - "UsedConnection": "", - } - case cloudprovider.REDIS_METRIC_TYPE_OPT_SES: - metricTags = map[string]string{ - "UsedQPS": "", - } - case cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS: - metricTags = map[string]string{ - "Keys": "", - } - case cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS: - metricTags = map[string]string{ - "ExpiredKeys": "", - } - case cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE: - metricTags = map[string]string{ - "UsedMemory": "", - } - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) - } - ret := []cloudprovider.MetricValues{} - for metric, tag := range metricTags { - result, err := self.ListMetrics("acs_kvstore", metric, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("ListMetric(%s) error: %v", metric, err) - continue - } - tags := map[string]string{} - if len(tag) > 0 && len(tagKey) > 0 { - tags[tagKey] = tag - } - for i := range result { - ret = append(ret, cloudprovider.MetricValues{ - Id: result[i].InstanceId, - MetricType: opts.MetricType, - Values: []cloudprovider.MetricValue{ - { - Timestamp: time.UnixMilli(result[i].Timestamp), - Value: result[i].GetValue(), - Tags: tags, - }, - }, - }) - } - } - return ret, nil -} - -func (self *SApsaraClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metrics := map[string]string{} - switch opts.MetricType { - case cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: - metrics = map[string]string{ - "CpuUsage": "", - } - case cloudprovider.RDS_METRIC_TYPE_MEM_USAGE: - metrics = map[string]string{ - "MemoryUsage": "", - } - case cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: - metrics = map[string]string{ - "MySQL_NetworkInNew": "", - "SQLServer_NetworkInNew": "", - } - case cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: - metrics = map[string]string{ - "MySQL_NetworkOutNew": "", - "SQLServer_NetworkOutNew": "", - } - case cloudprovider.RDS_METRIC_TYPE_DISK_USAGE: - metrics = map[string]string{ - "DiskUsage": "", - } - case cloudprovider.RDS_METRIC_TYPE_CONN_USAGE: - metrics = map[string]string{ - "ConnectionUsage": "", - } - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) - } - ret := []cloudprovider.MetricValues{} - for metric := range metrics { - result, err := self.ListMetrics("acs_rds_dashboard", metric, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("ListMetric(%s) error: %v", metric, err) - continue - } - for i := range result { - ret = append(ret, cloudprovider.MetricValues{ - Id: result[i].InstanceId, - MetricType: opts.MetricType, - Values: []cloudprovider.MetricValue{ - { - Timestamp: time.UnixMilli(result[i].Timestamp), - Value: result[i].GetValue(), - }, - }, - }) - } - } - return ret, nil -} - -func (self *SApsaraClient) GetElbMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricTags, tagKey := map[string]string{}, "" - switch opts.MetricType { - case cloudprovider.LB_METRIC_TYPE_NET_BPS_RX: - metricTags = map[string]string{ - "InstanceTrafficRX": "", - } - case cloudprovider.LB_METRIC_TYPE_NET_BPS_TX: - metricTags = map[string]string{ - "InstanceTrafficTX": "", - } - case cloudprovider.LB_METRIC_TYPE_HRSP_COUNT: - metricTags = map[string]string{ - "InstanceStatusCode2xx": cloudprovider.METRIC_TAG_REQUST_2XX, - "InstanceStatusCode3xx": cloudprovider.METRIC_TAG_REQUST_3XX, - "InstanceStatusCode4xx": cloudprovider.METRIC_TAG_REQUST_4XX, - "InstanceStatusCode5xx": cloudprovider.METRIC_TAG_REQUST_5XX, - } - tagKey = cloudprovider.METRIC_TAG_REQUST - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) - } - ret := []cloudprovider.MetricValues{} - for metric, tag := range metricTags { - result, err := self.ListMetrics("acs_slb_dashboard", metric, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("ListMetric(%s) error: %v", metric, err) - continue - } - tags := map[string]string{} - if len(tag) > 0 && len(tagKey) > 0 { - tags[tagKey] = tag - } - for i := range result { - ret = append(ret, cloudprovider.MetricValues{ - Id: result[i].InstanceId, - MetricType: opts.MetricType, - Values: []cloudprovider.MetricValue{ - { - Timestamp: time.UnixMilli(result[i].Timestamp), - Value: result[i].GetValue(), - Tags: tags, - }, - }, - }) - } - } - return ret, nil -} diff --git a/pkg/multicloud/apsara/natdtable.go b/pkg/multicloud/apsara/natdtable.go deleted file mode 100644 index 9f0cc4d8f6..0000000000 --- a/pkg/multicloud/apsara/natdtable.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strconv" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SForwardTableEntry struct { - multicloud.SResourceBase - multicloud.ApsaraTags - nat *SNatGetway - - ForwardEntryId string - ForwardEntryName string - IpProtocol string - Status string - ExternalIp string - ForwardTableId string - ExternalPort string - InternalPort string - InternalIp string -} - -func (dtable *SForwardTableEntry) GetName() string { - if len(dtable.ForwardEntryName) > 0 { - return dtable.ForwardEntryName - } - return dtable.ForwardEntryId -} - -func (dtable *SForwardTableEntry) GetId() string { - return dtable.ForwardEntryId -} - -func (dtable *SForwardTableEntry) GetGlobalId() string { - return dtable.ForwardEntryId -} - -func (dtable *SForwardTableEntry) GetStatus() string { - switch dtable.Status { - case "Available": - return api.NAT_STAUTS_AVAILABLE - default: - return api.NAT_STATUS_UNKNOWN - } -} - -func (dtable *SForwardTableEntry) GetIpProtocol() string { - return dtable.IpProtocol -} - -func (dtable *SForwardTableEntry) GetExternalIp() string { - return dtable.ExternalIp -} - -func (dtable *SForwardTableEntry) GetExternalPort() int { - port, _ := strconv.Atoi(dtable.ExternalPort) - return port -} - -func (dtable *SForwardTableEntry) GetInternalIp() string { - return dtable.InternalIp -} - -func (dtable *SForwardTableEntry) GetInternalPort() int { - port, _ := strconv.Atoi(dtable.InternalPort) - return port -} - -func (region *SRegion) GetAllDTables(tableId string) ([]SForwardTableEntry, error) { - dtables := []SForwardTableEntry{} - for { - part, total, err := region.GetForwardTableEntries(tableId, len(dtables), 50) - if err != nil { - return nil, err - } - dtables = append(dtables, part...) - if len(dtables) >= total { - break - } - } - return dtables, nil -} - -func (dtable *SForwardTableEntry) Delete() error { - return dtable.nat.vpc.region.DeleteForwardTableEntry(dtable.ForwardTableId, dtable.GetId()) -} - -func (region *SRegion) GetForwardTableEntries(tableId string, offset int, limit int) ([]SForwardTableEntry, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - params["ForwardTableId"] = tableId - - body, err := region.vpcRequest("DescribeForwardTableEntries", params) - if err != nil { - return nil, 0, err - } - - dtables := []SForwardTableEntry{} - err = body.Unmarshal(&dtables, "ForwardTableEntries", "ForwardTableEntry") - if err != nil { - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return dtables, int(total), nil -} - -func (region *SRegion) GetForwardTableEntry(tableID, forwardEntryID string) (SForwardTableEntry, error) { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["ForwardTableId"] = tableID - params["ForwardEntryId"] = forwardEntryID - body, err := region.vpcRequest("DescribeForwardTableEntries", params) - if err != nil { - return SForwardTableEntry{}, err - } - - dtables := []SForwardTableEntry{} - err = body.Unmarshal(&dtables, "ForwardTableEntries", "ForwardTableEntry") - if err != nil { - return SForwardTableEntry{}, err - } - if len(dtables) == 0 { - return SForwardTableEntry{}, cloudprovider.ErrNotFound - } - return dtables[0], nil -} - -func (region *SRegion) DeleteForwardTableEntry(tableId string, entryId string) error { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["ForwardTableId"] = tableId - params["ForwardEntryId"] = entryId - _, err := region.vpcRequest("DeleteForwardEntry", params) - return err -} - -func (region *SRegion) CreateForwardTableEntry(rule cloudprovider.SNatDRule, tableID string) (string, error) { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["ForwardTableId"] = tableID - params["ExternalIp"] = rule.ExternalIP - params["ExternalPort"] = strconv.Itoa(rule.ExternalPort) - params["InternalIp"] = rule.InternalIP - params["InternalPort"] = strconv.Itoa(rule.InternalPort) - params["IpProtocol"] = rule.Protocol - body, err := region.vpcRequest("CreateForwardEntry", params) - if err != nil { - return "", err - } - - entryID, _ := body.GetString("ForwardEntryId") - return entryID, nil -} - -func (dtable *SForwardTableEntry) Refresh() error { - new, err := dtable.nat.vpc.region.GetForwardTableEntry(dtable.ForwardTableId, dtable.ForwardEntryId) - if err != nil { - return err - } - return jsonutils.Update(dtable, new) -} diff --git a/pkg/multicloud/apsara/natgateway.go b/pkg/multicloud/apsara/natgateway.go deleted file mode 100644 index d11ca44990..0000000000 --- a/pkg/multicloud/apsara/natgateway.go +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SBandwidthPackageIds struct { - BandwidthPackageId []string -} - -type SForwardTableIds struct { - ForwardTableId []string -} - -type SSnatTableIds struct { - SnatTableId []string -} - -type SNatGetway struct { - multicloud.SNatGatewayBase - multicloud.ApsaraTags - - vpc *SVpc - - BandwidthPackageIds SBandwidthPackageIds - BusinessStatus string - CreationTime time.Time - ExpiredTime time.Time - Description string - ForwardTableIds SForwardTableIds - SnatTableIds SSnatTableIds - InstanceChargeType TChargeType - Name string - NatGatewayId string - RegionId string - Spec string - Status string - VpcId string -} - -func (nat *SNatGetway) GetId() string { - return nat.NatGatewayId -} - -func (nat *SNatGetway) GetGlobalId() string { - return nat.NatGatewayId -} - -func (nat *SNatGetway) GetName() string { - if len(nat.Name) > 0 { - return nat.Name - } - return nat.NatGatewayId -} - -func (self *SNatGetway) GetINetworkId() string { - return "" -} - -func (nat *SNatGetway) GetStatus() string { - switch nat.Status { - case "Initiating": - return api.NAT_STATUS_ALLOCATE - case "Available": - return api.NAT_STAUTS_AVAILABLE - case "Pending": - return api.NAT_STATUS_DEPLOYING - default: - return api.NAT_STATUS_UNKNOWN - } - -} - -func (nat *SNatGetway) GetBillingType() string { - return convertChargeType(nat.InstanceChargeType) -} - -func (nat *SNatGetway) GetNatSpec() string { - return nat.Spec -} - -func (nat *SNatGetway) GetCreatedAt() time.Time { - return nat.CreationTime -} - -func (nat *SNatGetway) GetExpiredAt() time.Time { - return nat.ExpiredTime -} - -func (nat *SNatGetway) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips := []SEipAddress{} - for { - parts, total, err := nat.vpc.region.GetEips("", nat.NatGatewayId, len(eips), 50) - if err != nil { - return nil, err - } - eips = append(eips, parts...) - if len(eips) >= total { - break - } - } - ieips := []cloudprovider.ICloudEIP{} - for i := 0; i < len(eips); i++ { - eips[i].region = nat.vpc.region - ieips = append(ieips, &eips[i]) - } - return ieips, nil -} - -func (nat *SNatGetway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { - itables := []cloudprovider.ICloudNatDEntry{} - for _, dtableId := range nat.ForwardTableIds.ForwardTableId { - dtables, err := nat.vpc.region.GetAllDTables(dtableId) - if err != nil { - return nil, err - } - for i := 0; i < len(dtables); i++ { - dtables[i].nat = nat - itables = append(itables, &dtables[i]) - } - } - return itables, nil -} - -func (nat *SNatGetway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { - stables, err := nat.getSnatEntries() - if err != nil { - return nil, err - } - itables := []cloudprovider.ICloudNatSEntry{} - for i := 0; i < len(stables); i++ { - stables[i].nat = nat - itables = append(itables, &stables[i]) - } - return itables, nil -} - -func (nat *SNatGetway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { - dNATEntry, err := nat.vpc.region.GetForwardTableEntry(nat.ForwardTableIds.ForwardTableId[0], id) - if err != nil { - return nil, cloudprovider.ErrNotFound - } - dNATEntry.nat = nat - return &dNATEntry, nil -} - -func (nat *SNatGetway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { - sNATEntry, err := nat.vpc.region.GetSNATEntry(nat.SnatTableIds.SnatTableId[0], id) - if err != nil { - return nil, cloudprovider.ErrNotFound - } - sNATEntry.nat = nat - return &sNATEntry, nil -} - -func (nat *SNatGetway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { - entryID, err := nat.vpc.region.CreateForwardTableEntry(rule, nat.ForwardTableIds.ForwardTableId[0]) - if err != nil { - return nil, errors.Wrapf(err, `create dnat rule for nat gateway %q`, nat.GetId()) - } - return nat.GetINatDEntryByID(entryID) -} - -func (nat *SNatGetway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { - entryID, err := nat.vpc.region.CreateSNATTableEntry(rule, nat.SnatTableIds.SnatTableId[0]) - if err != nil { - return nil, errors.Wrapf(err, `create snat rule for nat gateway %q`, nat.GetId()) - } - return nat.GetINatSEntryByID(entryID) -} - -func (self *SRegion) GetNatGateways(vpcId string, natGwId string, offset, limit int) ([]SNatGetway, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - if len(vpcId) > 0 { - params["VpcId"] = vpcId - } - if len(natGwId) > 0 { - params["NatGatewayId"] = natGwId - } - - body, err := self.vpcRequest("DescribeNatGateways", params) - if err != nil { - log.Errorf("GetVSwitches fail %s", err) - return nil, 0, err - } - - if self.client.debug { - log.Debugf("%s", body.PrettyString()) - } - - gateways := make([]SNatGetway, 0) - err = body.Unmarshal(&gateways, "NatGateways", "NatGateway") - if err != nil { - log.Errorf("Unmarshal gateways fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return gateways, int(total), nil -} diff --git a/pkg/multicloud/apsara/natstable.go b/pkg/multicloud/apsara/natstable.go deleted file mode 100644 index e53a02b216..0000000000 --- a/pkg/multicloud/apsara/natstable.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSNATTableEntry struct { - multicloud.SResourceBase - multicloud.ApsaraTags - nat *SNatGetway - - SnatEntryId string - SnatEntryName string - SnatIp string - SnatTableId string `json:"snat_table_id"` - SourceCIDR string `json:"source_cidr"` - SourceVSwitchId string `json:"source_vswitch_id"` - Status string -} - -func (stable *SSNATTableEntry) GetName() string { - if len(stable.SnatEntryName) > 0 { - return stable.SnatEntryName - } - return stable.SnatEntryId -} - -func (stable *SSNATTableEntry) GetId() string { - return stable.SnatEntryId -} - -func (stable *SSNATTableEntry) GetGlobalId() string { - return stable.SnatEntryId -} - -func (stable *SSNATTableEntry) GetStatus() string { - switch stable.Status { - case "Available": - return api.NAT_STAUTS_AVAILABLE - default: - return api.NAT_STATUS_UNKNOWN - } -} - -func (stable *SSNATTableEntry) GetIP() string { - return stable.SnatIp -} - -func (stable *SSNATTableEntry) GetSourceCIDR() string { - return stable.SourceCIDR -} - -func (stable *SSNATTableEntry) GetNetworkId() string { - return stable.SourceVSwitchId -} - -func (stable *SSNATTableEntry) Delete() error { - return stable.nat.vpc.region.DeleteSnatEntry(stable.SnatTableId, stable.GetId()) -} - -func (self *SRegion) GetSNATEntries(tableId string, offset, limit int) ([]SSNATTableEntry, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - params["SnatTableId"] = tableId - - body, err := self.vpcRequest("DescribeSnatTableEntries", params) - if err != nil { - log.Errorf("DescribeSnatTableEntries fail %s", err) - return nil, 0, err - } - - if self.client.debug { - log.Debugf("%s", body.PrettyString()) - } - - entries := make([]SSNATTableEntry, 0) - err = body.Unmarshal(&entries, "SnatTableEntries", "SnatTableEntry") - if err != nil { - log.Errorf("Unmarshal entries fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return entries, int(total), nil -} - -func (self *SRegion) GetSNATEntry(tableID, SNATEntryID string) (SSNATTableEntry, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SnatTableId"] = tableID - params["SnatEntryId"] = SNATEntryID - - body, err := self.vpcRequest("DescribeSnatTableEntries", params) - if err != nil { - log.Errorf("DescribeSnatTableEntries fail %s", err) - return SSNATTableEntry{}, err - } - - if self.client.debug { - log.Debugf("%s", body.PrettyString()) - } - - entries := make([]SSNATTableEntry, 0) - err = body.Unmarshal(&entries, "SnatTableEntries", "SnatTableEntry") - if err != nil { - log.Errorf("Unmarshal entries fail %s", err) - return SSNATTableEntry{}, err - } - if len(entries) == 0 { - return SSNATTableEntry{}, cloudprovider.ErrNotFound - } - return entries[0], nil - -} - -func (region *SRegion) CreateSNATTableEntry(rule cloudprovider.SNatSRule, tableID string) (string, error) { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["SnatTableId"] = tableID - params["SnatIp"] = rule.ExternalIP - if len(rule.NetworkID) != 0 { - params["SourceVSwitchId"] = rule.NetworkID - } - if len(rule.SourceCIDR) != 0 { - params["SourceCIDR"] = rule.SourceCIDR - } - body, err := region.vpcRequest("CreateSnatEntry", params) - if err != nil { - return "", err - } - - entryID, _ := body.GetString("SnatEntryId") - return entryID, nil -} - -func (region *SRegion) DeleteSnatEntry(tableId string, entryId string) error { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["SnatTableId"] = tableId - params["SnatEntryId"] = entryId - _, err := region.vpcRequest("DeleteSnatEntry", params) - return err -} - -func (nat *SNatGetway) getSnatEntriesForTable(tblId string) ([]SSNATTableEntry, error) { - entries := make([]SSNATTableEntry, 0) - entryTotal := -1 - for entryTotal < 0 || len(entries) < entryTotal { - parts, total, err := nat.vpc.region.GetSNATEntries(tblId, len(entries), 50) - if err != nil { - return nil, err - } - if len(parts) > 0 { - entries = append(entries, parts...) - } - entryTotal = total - } - return entries, nil -} - -func (nat *SNatGetway) getSnatEntries() ([]SSNATTableEntry, error) { - entries := make([]SSNATTableEntry, 0) - for i := range nat.SnatTableIds.SnatTableId { - sentries, err := nat.getSnatEntriesForTable(nat.SnatTableIds.SnatTableId[i]) - if err != nil { - return nil, err - } - entries = append(entries, sentries...) - } - return entries, nil -} - -func (nat *SNatGetway) dissociateWithVswitch(vswitchId string) error { - entries, err := nat.getSnatEntries() - if err != nil { - return err - } - for i := range entries { - log.Debugf("%v", entries[i]) - if entries[i].SourceVSwitchId == vswitchId { - err := nat.vpc.region.DeleteSnatEntry(entries[i].SnatTableId, entries[i].SnatEntryId) - if err != nil { - return err - } - } - } - return nil -} - -func (stable *SSNATTableEntry) Refresh() error { - new, err := stable.nat.vpc.region.GetSNATEntry(stable.SnatTableId, stable.SnatEntryId) - if err != nil { - return err - } - return jsonutils.Update(stable, new) -} diff --git a/pkg/multicloud/apsara/networkinterfaces.go b/pkg/multicloud/apsara/networkinterfaces.go deleted file mode 100644 index 73a32a1bbd..0000000000 --- a/pkg/multicloud/apsara/networkinterfaces.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SPrivateIp struct { - nic *SNetworkInterface - Primary bool - PrivateIpAddress string -} - -func (ip *SPrivateIp) GetGlobalId() string { - return ip.PrivateIpAddress -} - -func (ip *SPrivateIp) GetINetworkId() string { - return ip.nic.VSwitchId -} - -func (ip *SPrivateIp) GetIP() string { - return ip.PrivateIpAddress -} - -func (ip *SPrivateIp) IsPrimary() bool { - return ip.Primary -} - -type SPrivateIpSets struct { - PrivateIpSet []SPrivateIp -} - -type SNetworkInterface struct { - multicloud.SNetworkInterfaceBase - multicloud.ApsaraTags - region *SRegion - - InstanceId string - CreationTime time.Time - MacAddress string - NetworkInterfaceName string - PrivateIpSets SPrivateIpSets - SecurityGroupIds SSecurityGroupIds - Status string - Type string - VSwitchId string - VpcId string - ZoneId string - NetworkInterfaceId string - PrimaryIpAddress string - PrivateIpAddress string - DepartmentInfo -} - -func (nic *SNetworkInterface) GetName() string { - return nic.NetworkInterfaceName -} - -func (nic *SNetworkInterface) GetId() string { - return nic.NetworkInterfaceId -} - -func (nic *SNetworkInterface) GetGlobalId() string { - return nic.NetworkInterfaceId -} - -func (nic *SNetworkInterface) GetAssociateId() string { - return nic.InstanceId -} - -func (nic *SNetworkInterface) GetAssociateType() string { - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER -} - -func (nic *SNetworkInterface) GetMacAddress() string { - return nic.MacAddress -} - -func (nic *SNetworkInterface) GetStatus() string { - switch nic.Status { - case "Available": - return api.NETWORK_INTERFACE_STATUS_AVAILABLE - } - return nic.Status -} - -func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { - interfaces := []SNetworkInterface{} - for { - parts, total, err := region.GetNetworkInterfaces("", len(interfaces), 50) - if err != nil { - return nil, err - } - interfaces = append(interfaces, parts...) - if len(interfaces) >= total { - break - } - } - ret := []cloudprovider.ICloudNetworkInterface{} - for i := 0; i < len(interfaces); i++ { - // 阿里云实例的弹性网卡已经在guestnetwork同步了 - if len(interfaces[i].InstanceId) == 0 { - interfaces[i].region = region - ret = append(ret, &interfaces[i]) - } - } - return ret, nil -} - -func (nic *SNetworkInterface) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { - address := []cloudprovider.ICloudInterfaceAddress{} - for i := 0; i < len(nic.PrivateIpSets.PrivateIpSet); i++ { - nic.PrivateIpSets.PrivateIpSet[i].nic = nic - address = append(address, &nic.PrivateIpSets.PrivateIpSet[i]) - } - return address, nil -} - -func (region *SRegion) GetNetworkInterfaces(instanceId string, offset int, limit int) ([]SNetworkInterface, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - - params := map[string]string{ - "RegionId": region.RegionId, - "PageSize": fmt.Sprintf("%d", limit), - "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), - } - - if len(instanceId) > 0 { - params["InstanceId"] = instanceId - } - - body, err := region.ecsRequest("DescribeNetworkInterfaces", params) - if err != nil { - return nil, 0, errors.Wrap(err, "DescribeNetworkInterfaces") - } - - interfaces := []SNetworkInterface{} - err = body.Unmarshal(&interfaces, "NetworkInterfaceSets", "NetworkInterfaceSet") - if err != nil { - return nil, 0, errors.Wrap(err, "Unmarshal") - } - total, _ := body.Int("TotalCount") - return interfaces, int(total), nil -} diff --git a/pkg/multicloud/apsara/objects.go b/pkg/multicloud/apsara/objects.go deleted file mode 100644 index 5a15ddf1f2..0000000000 --- a/pkg/multicloud/apsara/objects.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "net/http" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - OSS_META_HEADER = "x-oss-meta-" -) - -type SObject struct { - bucket *SBucket - - cloudprovider.SBaseCloudObject -} - -func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { - return o.bucket -} - -func (o *SObject) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - osscli, err := o.bucket.GetOssClient() - if err != nil { - log.Errorf("o.bucket.region.GetOssClient error %s", err) - return acl - } - bucket, err := osscli.Bucket(o.bucket.Name) - if err != nil { - log.Errorf("osscli.Bucket error %s", err) - return acl - } - result, err := bucket.GetObjectACL(o.Key) - if err != nil { - log.Errorf("bucket.GetObjectACL error %s", err) - return acl - } - if result.ACL == string(oss.ACLDefault) { - return o.bucket.GetAcl() - } - acl = cloudprovider.TBucketACLType(result.ACL) - return acl -} - -func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { - acl, err := str2Acl(string(aclStr)) - if err != nil { - return errors.Wrap(err, "str2Acl") - } - osscli, err := o.bucket.GetOssClient() - if err != nil { - return errors.Wrap(err, "o.bucket.region.GetOssClient") - } - bucket, err := osscli.Bucket(o.bucket.Name) - if err != nil { - return errors.Wrap(err, "osscli.Bucket") - } - err = bucket.SetObjectACL(o.Key, acl) - if err != nil { - return errors.Wrap(err, "bucket.SetObjectACL") - } - return nil -} - -func (o *SObject) GetMeta() http.Header { - if o.Meta != nil { - return o.Meta - } - osscli, err := o.bucket.GetOssClient() - if err != nil { - log.Errorf("o.bucket.GetOssClient error %s", err) - return nil - } - bucket, err := osscli.Bucket(o.bucket.Name) - if err != nil { - log.Errorf("osscli.Bucket error %s", err) - return nil - } - result, err := bucket.GetObjectDetailedMeta(o.Key) - if err != nil { - log.Errorf("bucket.GetObjectACL error %s", err) - return nil - } - o.Meta = cloudprovider.FetchMetaFromHttpHeader(OSS_META_HEADER, result) - return o.Meta -} - -func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { - return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) -} diff --git a/pkg/multicloud/apsara/project.go b/pkg/multicloud/apsara/project.go deleted file mode 100644 index 05f5274fd2..0000000000 --- a/pkg/multicloud/apsara/project.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type DepartmentInfo struct { - Department string - DepartmentName string - ResourceGroup string - ResourceGroupName string - ResourceGroupId string -} - -func (self DepartmentInfo) GetProjectId() string { - return self.ResourceGroup -} - -type SResourceGroup struct { - multicloud.SProjectBase - multicloud.ApsaraTags - client *SApsaraClient - - Creator string - GmtCreated string - Id string - OrganizationId string - OrganizationName string - ResourceGroupName string - RsId string -} - -func (self *SResourceGroup) GetGlobalId() string { - return self.Id -} - -func (self *SResourceGroup) GetId() string { - return self.Id -} - -func (self *SResourceGroup) GetDomainName() string { - return "" -} - -func (self *SResourceGroup) GetDomainId() string { - return "" -} - -func (self *SResourceGroup) GetName() string { - return self.ResourceGroupName -} - -func (self *SResourceGroup) Refresh() error { - return nil -} - -func (self *SResourceGroup) GetStatus() string { - return api.EXTERNAL_PROJECT_STATUS_AVAILABLE -} - -func (self *SApsaraClient) GetResourceGroups(pageNumber int, pageSize int) ([]SResourceGroup, int, error) { - if pageSize <= 0 || pageSize > 100 { - pageSize = 10 - } - if pageNumber <= 0 { - pageNumber = 1 - } - params := map[string]string{ - "PageNumber": fmt.Sprintf("%d", pageNumber), - "PageSize": fmt.Sprintf("%d", pageSize), - } - resp, err := self.ascmRequest("ListResourceGroup", params) - if err != nil { - return nil, 0, errors.Wrap(err, "rmRequest.ListResourceGroup") - } - groups := []SResourceGroup{} - err = resp.Unmarshal(&groups, "data") - if err != nil { - return nil, 0, errors.Wrap(err, "resp.Unmarshal") - } - total, _ := resp.Int("pageInfo", "total") - return groups, int(total), nil -} - -func (self *SApsaraClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - group, err := self.CreateResourceGroup(name) - if err != nil { - return nil, errors.Wrap(err, "CreateProject") - } - return group, nil -} - -func (self *SApsaraClient) CreateResourceGroup(name string) (*SResourceGroup, error) { - params := map[string]string{ - "DisplayName": name, - "Name": name, - } - resp, err := self.ascmRequest("CreateResourceGroup", params) - if err != nil { - return nil, errors.Wrap(err, "CreateResourceGroup") - } - group := &SResourceGroup{client: self} - err = resp.Unmarshal(group, "ResourceGroup") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - err = cloudprovider.WaitStatus(group, api.EXTERNAL_PROJECT_STATUS_AVAILABLE, time.Second*5, time.Minute*3) - if err != nil { - return nil, errors.Wrap(err, "WaitStatus") - } - return group, nil -} - -func (self *SApsaraClient) GetResourceGroup(id string) (*SResourceGroup, error) { - params := map[string]string{ - "ResourceGroupId": id, - } - resp, err := self.ascmRequest("GetResourceGroup", params) - if err != nil { - return nil, err - } - group := &SResourceGroup{client: self} - err = resp.Unmarshal(group, "ResourceGroup") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return group, nil -} diff --git a/pkg/multicloud/apsara/provider/doc.go b/pkg/multicloud/apsara/provider/doc.go deleted file mode 100644 index b7109fc84f..0000000000 --- a/pkg/multicloud/apsara/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/apsara/provider" diff --git a/pkg/multicloud/apsara/provider/provider.go b/pkg/multicloud/apsara/provider/provider.go deleted file mode 100644 index 67ffc175e0..0000000000 --- a/pkg/multicloud/apsara/provider/provider.go +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/apsara" -) - -type SApsaraProviderFactory struct { - cloudprovider.SPrivateCloudBaseProviderFactory -} - -func (self *SApsaraProviderFactory) GetId() string { - return apsara.CLOUD_PROVIDER_APSARA -} - -func (self *SApsaraProviderFactory) GetName() string { - return apsara.CLOUD_PROVIDER_APSARA_CN -} - -func (self *SApsaraProviderFactory) IsMultiTenant() bool { - return true -} - -func (self *SApsaraProviderFactory) IsNeedForceAutoCreateProject() bool { - return true -} - -func (self *SApsaraProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output.Account = input.AccessKeyId - if input.OrganizationId > 0 { - output.Account = fmt.Sprintf("%s/%d", input.AccessKeyId, input.OrganizationId) - } - output.Secret = input.AccessKeySecret - if len(input.Endpoint) == 0 { - return output, httperrors.NewMissingParameterError("endpoint") - } - output.AccessUrl = input.Endpoint - if len(input.DefaultRegion) == 0 { - return output, httperrors.NewMissingParameterError("default_region") - } - return output, nil -} - -func (self *SApsaraProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - account := input.AccessKeyId - if input.OrganizationId > 0 { - account = fmt.Sprintf("%s/%d", input.AccessKeyId, input.OrganizationId) - } - output = cloudprovider.SCloudaccount{ - Account: account, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func (self *SApsaraProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - client, err := apsara.NewApsaraClient( - apsara.NewApsaraClientConfig( - cfg.Account, - cfg.Secret, - cfg.URL, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SApsaraProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SApsaraProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - region := "" - if info.Options != nil { - region, _ = info.Options.GetString("default_region") - } - return map[string]string{ - "APSARA_ACCESS_KEY": info.Account, - "APSARA_SECRET": info.Secret, - "APSARA_ENDPOINT": info.Url, - "APSARA_REGION": region, - }, nil -} - -func init() { - factory := SApsaraProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SApsaraProvider struct { - cloudprovider.SBaseProvider - client *apsara.SApsaraClient -} - -func (self *SApsaraProvider) WithClient(client *apsara.SApsaraClient) *SApsaraProvider { - self.client = client - return self -} - -func (self *SApsaraProvider) GetSysInfo() (jsonutils.JSONObject, error) { - regions := self.client.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") - info.Add(jsonutils.NewString(apsara.APSARA_API_VERSION), "api_version") - return info, nil -} - -func (self *SApsaraProvider) GetVersion() string { - return apsara.APSARA_API_VERSION -} - -func (self *SApsaraProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SApsaraProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SApsaraProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SApsaraProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(extId) -} - -func (self *SApsaraProvider) GetBalance() (float64, string, error) { - return 0, api.CLOUD_PROVIDER_HEALTH_NORMAL, nil -} - -func (self *SApsaraProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SApsaraProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return self.client.CreateIProject(name) -} - -func (self *SApsaraProvider) GetStorageClasses(regionId string) []string { - return []string{ - "Standard", "IA", "Archive", - } -} - -func (self *SApsaraProvider) GetBucketCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SApsaraProvider) GetObjectCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SApsaraProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SApsaraProvider) GetIamLoginUrl() string { - return self.client.GetIamLoginUrl() -} - -func (self *SApsaraProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - return self.client.CreateIClouduser(conf) -} - -func (self *SApsaraProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { - return self.client.GetICloudusers() -} - -func (self *SApsaraProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroups() -} - -func (self *SApsaraProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroupByName(name) -} - -func (self *SApsaraProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.client.GetIClouduserByName(name) -} - -func (self *SApsaraProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - return self.client.CreateICloudgroup(name, desc) -} - -func (self *SApsaraProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetISystemCloudpolicies() -} - -func (self *SApsaraProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetICustomCloudpolicies() -} - -func (self *SApsaraProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { - return self.client.CreateICloudpolicy(opts) -} - -func (self *SApsaraProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/apsara/quota.go b/pkg/multicloud/apsara/quota.go deleted file mode 100644 index 1e553cc1ed..0000000000 --- a/pkg/multicloud/apsara/quota.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strconv" - "strings" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type ValueItem struct { - Value string - DiskCategory string -} - -type AttributeValues struct { - ValueItem []ValueItem -} - -type SAccountAttributeItem struct { - AttributeValues AttributeValues - AttributeName string -} - -type SQuota struct { - Name string - UsedCount int - MaxCount int -} - -func (q *SQuota) GetGlobalId() string { - return q.Name -} - -func (q *SQuota) GetDesc() string { - return q.Name -} - -func (q *SQuota) GetQuotaType() string { - return q.Name -} - -func (q *SQuota) GetMaxQuotaCount() int { - return q.MaxCount -} - -func (q *SQuota) GetCurrentQuotaUsedCount() int { - return q.UsedCount -} - -func (region *SRegion) GetAccountAttributes() ([]SAccountAttributeItem, error) { - params := map[string]string{ - "RegionId": region.RegionId, - } - resp, err := region.ecsRequest("DescribeAccountAttributes", params) - if err != nil { - return nil, errors.Wrap(err, "ecsRequest") - } - quotas := []SAccountAttributeItem{} - err = resp.Unmarshal("as, "AccountAttributeItems", "AccountAttributeItem") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return quotas, nil -} - -func (region *SRegion) GetQuotas() ([]SQuota, error) { - attrs, err := region.GetAccountAttributes() - if err != nil { - return nil, errors.Wrap(err, "GetAccountAttributes") - } - quotas := map[string]SQuota{} - for _, attr := range attrs { - for _, item := range attr.AttributeValues.ValueItem { - value, err := strconv.ParseInt(item.Value, 10, 64) - if err != nil { - continue - } - used := false - name := attr.AttributeName - if strings.HasPrefix(name, "used-") { - used = true - name = strings.TrimPrefix(name, "used-") - } - if len(item.DiskCategory) > 0 { - name = fmt.Sprintf("%s/%s", name, item.DiskCategory) - } - if _, ok := quotas[name]; !ok { - quotas[name] = SQuota{ - Name: name, - UsedCount: -1, - } - } - quota := quotas[name] - if used { - quota.UsedCount = int(value) - } else { - quota.MaxCount = int(value) - } - quotas[name] = quota - } - } - ret := []SQuota{} - for _, quota := range quotas { - ret = append(ret, quota) - } - return ret, nil -} - -func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { - quotas, err := region.GetQuotas() - if err != nil { - return nil, errors.Wrap(err, "GetQuotas") - } - ret := []cloudprovider.ICloudQuota{} - for i := range quotas { - ret = append(ret, "as[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/apsara/ram_group.go b/pkg/multicloud/apsara/ram_group.go deleted file mode 100644 index 520782b3c2..0000000000 --- a/pkg/multicloud/apsara/ram_group.go +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SGroup struct { - client *SApsaraClient - - Comments string - CreatedDate time.Time - GroupName string - UpdateDate time.Time -} - -type sGroups struct { - Group []SGroup -} - -type SGroups struct { - Groups sGroups - Marker string - IsTruncated bool -} - -func (self *SGroup) GetName() string { - return self.GroupName -} - -func (self *SGroup) GetGlobalId() string { - return self.GroupName -} - -func (self *SGroup) GetDescription() string { - return self.Comments -} - -func (self *SGroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { - ret := []cloudprovider.IClouduser{} - offset := "" - for { - part, err := self.client.ListUsersForGroup(self.GroupName, offset, 1000) - if err != nil { - return nil, errors.Wrapf(err, "ListUsersForGroup") - } - for i := range part.Users.User { - part.Users.User[i].client = self.client - ret = append(ret, &part.Users.User[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SGroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := self.client.ListPoliciesForGroup(self.GroupName) - if err != nil { - return nil, errors.Wrapf(err, "ListPoliciesForGroup") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].PolicyType == POLICY_TYPE_SYSTEM { - policies[i].client = self.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (self *SGroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := self.client.ListPoliciesForGroup(self.GroupName) - if err != nil { - return nil, errors.Wrapf(err, "ListPoliciesForGroup") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].PolicyType == POLICY_TYPE_CUSTOM { - policies[i].client = self.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (self *SGroup) AddUser(name string) error { - return self.client.AddUserToGroup(self.GroupName, name) -} - -func (self *SGroup) RemoveUser(name string) error { - return self.client.RemoveUserFromGroup(self.GroupName, name) -} - -func (self *SGroup) AttachSystemPolicy(policyName string) error { - return self.client.AttachPolicyToGroup(POLICY_TYPE_SYSTEM, policyName, self.GroupName) -} - -func (self *SGroup) AttachCustomPolicy(policyName string) error { - return self.client.AttachPolicyToGroup(POLICY_TYPE_CUSTOM, policyName, self.GroupName) -} - -func (self *SGroup) DetachSystemPolicy(policyName string) error { - return self.client.DetachPolicyFromGroup(POLICY_TYPE_SYSTEM, policyName, self.GroupName) -} - -func (self *SGroup) DetachCustomPolicy(policyName string) error { - return self.client.DetachPolicyFromGroup(POLICY_TYPE_CUSTOM, policyName, self.GroupName) -} - -func (self *SGroup) Delete() error { - return self.client.DeleteGroup(self.GroupName) -} - -func (self *SApsaraClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - group, err := self.GetGroup(name) - if err != nil { - return nil, errors.Wrapf(err, "GetGroup(%s)", name) - } - return group, nil -} - -func (self *SApsaraClient) CreateICloudgroup(name string, desc string) (cloudprovider.ICloudgroup, error) { - group, err := self.CreateGroup(name, desc) - if err != nil { - return nil, errors.Wrapf(err, "CreateGroup") - } - return group, nil -} - -func (self *SApsaraClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - ret := []cloudprovider.ICloudgroup{} - offset := "" - for { - part, err := self.ListGroups(offset, 100) - if err != nil { - return nil, errors.Wrap(err, "ListGroups") - } - for i := range part.Groups.Group { - part.Groups.Group[i].client = self - ret = append(ret, &part.Groups.Group[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SApsaraClient) ListGroups(offset string, limit int) (*SGroups, error) { - if limit < 1 || limit > 1000 { - limit = 1000 - } - params := map[string]string{ - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(offset) > 0 { - params["Marker"] = offset - } - groups := SGroups{} - resp, err := self.ramRequest("ListGroups", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.ListGroups") - } - err = resp.Unmarshal(&groups) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return &groups, nil -} - -// https://help.apsara.com/document_detail/28732.html?spm=a2c4g.11186623.6.777.580735b2m2xUh8 -func (self *SApsaraClient) ListPoliciesForGroup(groupName string) ([]SPolicy, error) { - params := map[string]string{ - "GroupName": groupName, - } - resp, err := self.ramRequest("ListPoliciesForGroup", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.ListPoliciesForGroup") - } - policies := []SPolicy{} - err = resp.Unmarshal(&policies, "Policies", "Policy") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return policies, nil -} - -func (self *SApsaraClient) ListUsersForGroup(groupName string, offset string, limit int) (*SUsers, error) { - if limit < 1 || limit > 1000 { - limit = 1000 - } - params := map[string]string{ - "GroupName": groupName, - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(offset) > 0 { - params["Marker"] = offset - } - resp, err := self.ramRequest("ListUsersForGroup", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.ListUserForGroup") - } - users := &SUsers{} - err = resp.Unmarshal(users) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return users, nil -} - -func (self *SApsaraClient) DeleteGroup(groupName string) error { - params := map[string]string{ - "GroupName": groupName, - } - _, err := self.ramRequest("DeleteGroup", params) - return err -} - -func (self *SApsaraClient) CreateGroup(groupName, comments string) (*SGroup, error) { - params := map[string]string{ - "GroupName": groupName, - } - if len(comments) > 0 { - params["Comments"] = comments - } - resp, err := self.ramRequest("CreateGroup", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.CreateGroup") - } - group := &SGroup{client: self} - err = resp.Unmarshal(group, "Group") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return group, nil -} - -func (self *SApsaraClient) GetGroup(groupName string) (*SGroup, error) { - params := map[string]string{ - "GroupName": groupName, - } - resp, err := self.ramRequest("GetGroup", params) - if err != nil { - return nil, errors.Wrap(err, "GetGroup") - } - group := &SGroup{client: self} - err = resp.Unmarshal(group, "Group") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return group, nil -} - -func (self *SApsaraClient) RemoveUserFromGroup(groupName, userName string) error { - params := map[string]string{ - "GroupName": groupName, - "UserName": userName, - } - _, err := self.ramRequest("RemoveUserFromGroup", params) - if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrap(err, "RemoveUserFromGroup") - } - return nil -} - -func (self *SApsaraClient) DetachPolicyFromGroup(policyType, policyName, groupName string) error { - params := map[string]string{ - "GroupName": groupName, - "PolicyName": policyName, - "PolicyType": policyType, - } - _, err := self.ramRequest("DetachPolicyFromGroup", params) - if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrap(err, "DetachPolicyFromGroup") - } - return nil -} - -func (self *SApsaraClient) AddUserToGroup(groupName, userName string) error { - params := map[string]string{ - "GroupName": groupName, - "UserName": userName, - } - _, err := self.ramRequest("AddUserToGroup", params) - if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.User.Group") { - return errors.Wrap(err, "AddUserToGroup") - } - return nil -} - -func (self *SApsaraClient) AttachPolicyToGroup(policyType, policyName, groupName string) error { - params := map[string]string{ - "GroupName": groupName, - "PolicyName": policyName, - "PolicyType": policyType, - } - _, err := self.ramRequest("AttachPolicyToGroup", params) - if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.Group.Policy") { - return errors.Wrap(err, "AttachPolicyToGroup") - } - return nil -} diff --git a/pkg/multicloud/apsara/ram_policy.go b/pkg/multicloud/apsara/ram_policy.go deleted file mode 100644 index d3962ba7d6..0000000000 --- a/pkg/multicloud/apsara/ram_policy.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - POLICY_TYPE_SYSTEM = "System" - POLICY_TYPE_CUSTOM = "Custom" -) - -/** - {"AttachmentCount":0, -"CreateDate":"2018-10-12T05:05:16Z", -"DefaultVersion":"v1", -"Description":"只读访问Data Lake Analytics的权限", -"PolicyName":"ApsaraDLAReadOnlyAccess", -"PolicyType":"System", -"UpdateDate":"2018-10-12T05:05:16Z"} -*/ - -type SDefaultPolicyVersion struct { - CreateDate time.Time - IsDefaultVersion bool - PolicyDocument string - VersionId string -} - -type SPolicyDetails struct { - Policy SPolicy - DefaultPolicyVersion SDefaultPolicyVersion -} - -type sPolicies struct { - Policy []SPolicy -} - -type SPolicies struct { - Policies sPolicies - Marker string - IsTruncated bool -} - -type SPolicy struct { - client *SApsaraClient - AttachmentCount int - CreateDate time.Time - UpdateDate time.Time - DefaultVersion string - Description string - PolicyName string - PolicyType string -} - -func (policy *SPolicy) GetName() string { - return policy.PolicyName -} - -func (policy *SPolicy) GetDescription() string { - return policy.Description -} - -func (policy *SPolicy) GetGlobalId() string { - return policy.PolicyName -} - -func (policy *SPolicy) UpdateDocument(document *jsonutils.JSONDict) error { - return policy.client.CreatePolicyVersion(policy.PolicyName, document.String(), true) -} - -func (policy *SPolicy) Delete() error { - return policy.client.DeletePolicy(policy.PolicyType, policy.PolicyName) -} - -func (policy *SPolicy) GetDocument() (*jsonutils.JSONDict, error) { - details, err := policy.client.GetPolicy(policy.PolicyType, policy.PolicyName) - if err != nil { - return nil, errors.Wrapf(err, "GetPolicy(%s,%s)", policy.PolicyType, policy.PolicyName) - } - obj, err := jsonutils.Parse([]byte(details.DefaultPolicyVersion.PolicyDocument)) - if err != nil { - return nil, errors.Wrap(err, "jsonutils.Parse") - } - return obj.(*jsonutils.JSONDict), nil -} - -func (self *SApsaraClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - ret := []cloudprovider.ICloudpolicy{} - offset := "" - for { - part, err := self.ListPolicies(POLICY_TYPE_SYSTEM, offset, 1000) - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - for i := range part.Policies.Policy { - part.Policies.Policy[i].client = self - ret = append(ret, &part.Policies.Policy[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SApsaraClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - ret := []cloudprovider.ICloudpolicy{} - offset := "" - for { - part, err := self.ListPolicies(POLICY_TYPE_CUSTOM, offset, 1000) - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - for i := range part.Policies.Policy { - part.Policies.Policy[i].client = self - ret = append(ret, &part.Policies.Policy[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SApsaraClient) AttachPolicyToUser(policyName, policyType, userName string) error { - params := map[string]string{ - "UserName": userName, - "PolicyName": policyName, - "PolicyType": policyType, - } - _, err := self.ramRequest("AttachPolicyToUser", params) - if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.User.Policy") { - return errors.Wrap(err, "AttachPolicyToUser") - } - return nil -} - -func (self *SApsaraClient) DetachPolicyFromUser(policyName, policyType, userName string) error { - if len(policyType) == 0 { - policyType = "System" - } - params := map[string]string{ - "UserName": userName, - "PolicyName": policyName, - "PolicyType": policyType, - } - _, err := self.ramRequest("DetachPolicyFromUser", params) - if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrap(err, "DetachPolicyFromUser") - } - return nil -} - -// https://help.apsara.com/document_detail/28719.html?spm=a2c4g.11174283.6.764.27055662H6TGg5 -func (self *SApsaraClient) ListPolicies(policyType string, offset string, limit int) (*SPolicies, error) { - if limit < 1 || limit > 1000 { - limit = 1000 - } - params := map[string]string{ - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(policyType) > 0 { - params["PolicyType"] = policyType - } - if len(offset) > 0 { - params["Marker"] = offset - } - - body, err := self.ramRequest("ListPolicies", params) - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - policies := &SPolicies{} - - err = body.Unmarshal(&policies) - if err != nil { - return nil, errors.Wrapf(err, "body.Unmarshal") - } - - return policies, nil -} - -func (self *SApsaraClient) GetPolicy(policyType string, policyName string) (*SPolicyDetails, error) { - params := make(map[string]string) - params["PolicyType"] = policyType - params["PolicyName"] = policyName - - body, err := self.ramRequest("GetPolicy", params) - if err != nil { - if isError(err, "EntityNotExist.Role") { - return nil, cloudprovider.ErrNotFound - } - return nil, err - } - - policy := SPolicyDetails{} - - err = body.Unmarshal(&policy) - if err != nil { - return nil, err - } - - return &policy, nil -} - -type SStatement struct { - Action []string `json:"Action,allowempty"` - Effect string `json:"Effect"` - Resource []string `json:"Resource"` -} - -type SPolicyDocument struct { - Statement []SStatement `json:"Statement,allowempty"` - Version string `json:"Version"` -} - -func (self *SApsaraClient) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { - if opts.Document == nil { - return nil, errors.Error("nil document") - } - policy, err := self.CreatePolicy(opts.Name, opts.Document.String(), opts.Desc) - if err != nil { - return nil, errors.Wrapf(err, "CreatePolicy") - } - return policy, nil -} - -func (self *SApsaraClient) CreatePolicy(name string, document string, desc string) (*SPolicy, error) { - params := make(map[string]string) - params["PolicyName"] = name - params["PolicyDocument"] = document - if len(desc) > 0 { - params["Description"] = desc - } - - body, err := self.ramRequest("CreatePolicy", params) - if err != nil { - return nil, err - } - - policy := SPolicy{client: self} - - err = body.Unmarshal(&policy, "Policy") - if err != nil { - return nil, err - } - - return &policy, nil -} - -func (self *SApsaraClient) DeletePolicy(policyType string, policyName string) error { - params := make(map[string]string) - params["PolicyName"] = policyName - params["PolicyType"] = policyType - - _, err := self.ramRequest("DeletePolicy", params) - return err -} - -func (self *SApsaraClient) DeleteRole(roleName string) error { - params := make(map[string]string) - params["RoleName"] = roleName - - _, err := self.ramRequest("DeleteRole", params) - return err -} - -func (self *SApsaraClient) AttachPolicy2Role(policyType string, policyName string, roleName string) error { - params := make(map[string]string) - params["PolicyType"] = policyType - params["PolicyName"] = policyName - params["RoleName"] = roleName - - _, err := self.ramRequest("AttachPolicyToRole", params) - if err != nil { - return errors.Wrap(err, "AttachPolicyToRole") - } - - return nil -} - -func (self *SApsaraClient) CreatePolicyVersion(name, document string, isDefault bool) error { - params := map[string]string{ - "PolicyName": name, - "PolicyDocument": document, - "RotateStrategy": "DeleteOldestNonDefaultVersionWhenLimitExceeded", - } - if isDefault { - params["SetAsDefault"] = "true" - } - _, err := self.ramRequest("CreatePolicyVersion", params) - return err -} diff --git a/pkg/multicloud/apsara/ram_user.go b/pkg/multicloud/apsara/ram_user.go deleted file mode 100644 index c0c293afab..0000000000 --- a/pkg/multicloud/apsara/ram_user.go +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type sUsers struct { - User []SUser -} - -type SUsers struct { - Users sUsers - Marker string - IsTruncated bool -} - -type SUser struct { - client *SApsaraClient - multicloud.SBaseClouduser - - Comments string - CreateDate time.Time - DisplayName string - Email string - MobilePhone string - UserId string - UserName string -} - -func (user *SUser) GetEmailAddr() string { - return "" -} - -func (user *SUser) GetInviteUrl() string { - return "" -} - -func (user *SUser) GetGlobalId() string { - if len(user.UserId) > 0 { - return user.UserId - } - u, err := user.client.GetUser(user.UserName) - if err != nil { - return "" - } - return u.UserId -} - -func (user *SUser) GetName() string { - return user.UserName -} - -func (user *SUser) Delete() error { - groups, err := user.client.ListGroupsForUser(user.UserName) - if err != nil { - return errors.Wrap(err, "ListGroupsForUser") - } - for i := range groups { - err = user.client.RemoveUserFromGroup(groups[i].GroupName, user.UserName) - if err != nil { - return errors.Wrapf(err, "RemoveUserFromGroup %s > %s", groups[i].GroupName, user.UserName) - } - } - policies, err := user.client.ListPoliciesForUser(user.UserName) - if err != nil { - return errors.Wrap(err, "ListPoliciesForUser") - } - for i := range policies { - err = user.client.DetachPolicyFromUser(policies[i].PolicyName, policies[i].PolicyType, user.UserName) - if err != nil { - return errors.Wrapf(err, "DetachPolicyFromUser %s %s %s", policies[i].PolicyName, policies[i].PolicyType, user.UserName) - } - } - return user.client.DeleteClouduser(user.UserName) -} - -func (user *SUser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - groups, err := user.client.ListGroupsForUser(user.UserName) - if err != nil { - return nil, errors.Wrapf(err, "ListGroupsForUser") - } - ret := []cloudprovider.ICloudgroup{} - for i := range groups { - groups[i].client = user.client - ret = append(ret, &groups[i]) - } - return ret, nil -} - -func (user *SUser) UpdatePassword(password string) error { - return user.client.UpdateLoginProfile(user.UserName, password) -} - -func (user *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := user.client.ListPoliciesForUser(user.UserName) - if err != nil { - return nil, errors.Wrap(err, "ListPoliciesForUser") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].PolicyType == "System" { - policies[i].client = user.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (user *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := user.client.ListPoliciesForUser(user.UserName) - if err != nil { - return nil, errors.Wrap(err, "ListPoliciesForUser") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].PolicyType == "Custom" { - policies[i].client = user.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (user *SUser) IsConsoleLogin() bool { - _, err := user.client.GetLoginProfile(user.UserName) - if errors.Cause(err) == cloudprovider.ErrNotFound { - return false - } - return true -} - -func (user *SUser) ResetPassword(password string) error { - return user.client.ResetClouduserPassword(user.UserName, password) -} - -func (user *SUser) AttachSystemPolicy(policyName string) error { - return user.client.AttachPolicyToUser(policyName, POLICY_TYPE_SYSTEM, user.UserName) -} - -func (user *SUser) AttachCustomPolicy(policyName string) error { - return user.client.AttachPolicyToUser(policyName, POLICY_TYPE_CUSTOM, user.UserName) -} - -func (user *SUser) DetachSystemPolicy(policyName string) error { - return user.client.DetachPolicyFromUser(policyName, POLICY_TYPE_SYSTEM, user.UserName) -} - -func (user *SUser) DetachCustomPolicy(policyName string) error { - return user.client.DetachPolicyFromUser(policyName, POLICY_TYPE_CUSTOM, user.UserName) -} - -func (self *SApsaraClient) DeleteClouduser(name string) error { - params := map[string]string{ - "UserName": name, - } - _, err := self.ramRequest("DeleteUser", params) - return err -} - -func (self *SApsaraClient) CreateUser(name, phone, email, comments string) (*SUser, error) { - params := map[string]string{ - "UserName": name, - "DisplayName": name, - } - if len(phone) > 0 { - params["MobilePhone"] = phone - } - if len(email) > 0 { - params["Email"] = email - } - if len(comments) > 0 { - params["Comments"] = comments - } - resp, err := self.ramRequest("CreateUser", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.CreateUser") - } - - user := &SUser{client: self} - err = resp.Unmarshal(user, "User") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return user, nil -} - -func (self *SApsaraClient) ListUsers(offset string, limit int) (*SUsers, error) { - params := map[string]string{} - if len(offset) > 0 { - params["Marker"] = offset - } - if limit > 0 { - params["MaxItems"] = fmt.Sprintf("%d", limit) - } - resp, err := self.ramRequest("ListUsers", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.ListUsers") - } - users := &SUsers{} - err = resp.Unmarshal(users) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return users, nil -} - -func (self *SApsaraClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - user, err := self.CreateUser(conf.Name, conf.MobilePhone, conf.Email, conf.Desc) - if err != nil { - return nil, errors.Wrap(err, "CreateUser") - } - if len(conf.Password) > 0 { - _, err := self.CreateLoginProfile(conf.Name, conf.Password) - if err != nil { - return nil, errors.Wrap(err, "CreateLoginProfile") - } - } - for _, policyId := range conf.ExternalPolicyIds { - err := user.AttachSystemPolicy(policyId) - if err != nil { - log.Errorf("attach policy %s for user %s error: %v", policyId, conf.Name, err) - } - } - return user, nil -} - -func (self *SApsaraClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { - ret := []cloudprovider.IClouduser{} - offset := "" - for { - part, err := self.ListUsers(offset, 100) - if err != nil { - return nil, errors.Wrap(err, "GetCloudusers") - } - for i := range part.Users.User { - part.Users.User[i].client = self - ret = append(ret, &part.Users.User[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SApsaraClient) GetUser(name string) (*SUser, error) { - params := map[string]string{ - "UserName": name, - } - resp, err := self.ramRequest("GetUser", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.CreateUser") - } - user := &SUser{client: self} - err = resp.Unmarshal(user, "User") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return user, nil -} - -func (self *SApsaraClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.GetUser(name) -} - -type SLoginProfile struct { - CreateDate string - MFABindRequired bool - PasswordResetRequired bool - UserName string -} - -func (self *SApsaraClient) GetLoginProfile(name string) (*SLoginProfile, error) { - params := map[string]string{ - "UserName": name, - } - resp, err := self.ramRequest("GetLoginProfile", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.GetLoginProfile") - } - profile := &SLoginProfile{} - err = resp.Unmarshal(profile, "LoginProfile") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return profile, nil -} - -func (self *SApsaraClient) DeleteLoginProfile(name string) error { - params := map[string]string{ - "UserName": name, - } - _, err := self.ramRequest("DeleteLoginProfile", params) - return err -} - -func (self *SApsaraClient) CreateLoginProfile(name, password string) (*SLoginProfile, error) { - params := map[string]string{ - "UserName": name, - "Password": password, - } - resp, err := self.ramRequest("CreateLoginProfile", params) - if err != nil { - return nil, errors.Wrap(err, "ramRequest.CreateLoginProfile") - } - profile := &SLoginProfile{} - err = resp.Unmarshal(profile, "LoginProfile") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return profile, nil -} - -func (self *SApsaraClient) UpdateLoginProfile(name, password string) error { - params := map[string]string{ - "UserName": name, - "Password": password, - } - _, err := self.ramRequest("UpdateLoginProfile", params) - if err != nil { - return errors.Wrap(err, "ramRequest.CreateLoginProfile") - } - return nil -} - -func (self *SApsaraClient) ResetClouduserPassword(name, password string) error { - _, err := self.GetLoginProfile(name) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - _, err = self.CreateLoginProfile(name, password) - return err - } - return errors.Wrap(err, "GetLoginProfile") - } - return self.UpdateLoginProfile(name, password) -} - -func (self *SApsaraClient) GetIamLoginUrl() string { - params := map[string]string{} - resp, err := self.ramRequest("GetAccountAlias", params) - if err != nil { - log.Errorf("GetAccountAlias error: %v", err) - return "" - } - alias, _ := resp.GetString("AccountAlias") - if len(alias) > 0 { - return fmt.Sprintf("https://signin.apsara.com/%s.onapsara.com/login.htm", alias) - } - return "" -} - -// https://help.apsara.com/document_detail/28707.html?spm=a2c4g.11186623.6.752.f4466bbfVy5j0s -func (self *SApsaraClient) ListGroupsForUser(user string) ([]SGroup, error) { - params := map[string]string{ - "UserName": user, - } - resp, err := self.ramRequest("ListGroupsForUser", params) - if err != nil { - return nil, errors.Wrap(err, "ListGroupsForUser") - } - groups := []SGroup{} - err = resp.Unmarshal(&groups, "Groups", "Group") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return groups, nil -} - -// https://help.apsara.com/document_detail/28732.html?spm=a2c4g.11186623.6.777.580735b2m2xUh8 -func (self *SApsaraClient) ListPoliciesForUser(user string) ([]SPolicy, error) { - params := map[string]string{ - "UserName": user, - } - resp, err := self.ramRequest("ListPoliciesForUser", params) - if err != nil { - return nil, errors.Wrap(err, "ListPoliciesForUser") - } - policies := []SPolicy{} - err = resp.Unmarshal(&policies, "Policies", "Policy") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return policies, nil -} diff --git a/pkg/multicloud/apsara/ramimage.go b/pkg/multicloud/apsara/ramimage.go deleted file mode 100644 index 0b07d8c884..0000000000 --- a/pkg/multicloud/apsara/ramimage.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - ApsaraECSImageImportRole = "ApsaraECSImageImportDefaultRole" - ApsaraECSImageImportRoleDocument = `{ -"Statement": [ -{ -"Action": "sts:AssumeRole", -"Effect": "Allow", -"Principal": { - "Service": [ - "ecs.apsaracs.com" - ] -} -} -], -"Version": "1" -}` - - ApsaraECSImageImportRolePolicyType = "System" - ApsaraECSImageImportRolePolicy = "ApsaraECSImageImportRolePolicy" - ApsaraECSImageImportRolePolicyDocument = `{ -"Version": "1", -"Statement": [ -{ -"Action": [ - "oss:GetObject", - "oss:GetBucketLocation" -], -"Resource": "*", -"Effect": "Allow" -} -] -}` -) - -func (self *SApsaraClient) EnableImageImport() error { - _, err := self.GetRole(ApsaraECSImageImportRole) - if err != nil { - if err != cloudprovider.ErrNotFound { - return err - } - _, err = self.CreateRole(ApsaraECSImageImportRole, - ApsaraECSImageImportRoleDocument, - "Allow Import External Image from OSS") - if err != nil { - return err - } - } - - _, err = self.GetPolicy(ApsaraECSImageImportRolePolicyType, ApsaraECSImageImportRolePolicy) - if err != nil { - /*if err != cloudprovider.ErrNotFound { - return err - } - _, err = self.createPolicy(ApsaraECSImageImportRolePolicy, - ApsaraECSImageImportRolePolicyDocument, - "Allow Import External Image policy") - if err != nil { - return err - }*/ - return err - } - - policies, err := self.ListPoliciesForRole(ApsaraECSImageImportRole) - if err != nil { - return err - } - for i := 0; i < len(policies); i += 1 { - if policies[i].PolicyType == ApsaraECSImageImportRolePolicyType && - policies[i].PolicyName == ApsaraECSImageImportRolePolicy { - return nil // find policy - } - } - - err = self.AttachPolicy2Role(ApsaraECSImageImportRolePolicyType, ApsaraECSImageImportRolePolicy, ApsaraECSImageImportRole) - if err != nil { - return err - } - - return nil -} - -const ( - ApsaraECSImageExportRole = "ApsaraECSImageExportDefaultRole" - ApsaraECSImageExportRoleDocument = `{ - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": [ - "ecs.apsaracs.com" - ] - } - } - ], - "Version": "1" -}` - - ApsaraEmptyRoleDocument = `{ - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "Service": [ - "ecs.apsaracs.com" - ] - } - } - ], - "Version": "1" -}` - - ApsaraECSImageExportRolePolicyType = "System" - ApsaraECSImageExportRolePolicy = "ApsaraECSImageExportRolePolicy" - ApsaraECSImageExportRolePolicyDocument = `{ - "Version": "1", - "Statement": [ - { - "Action": [ - "oss:GetObject", - "oss:PutObject", - "oss:DeleteObject", - "oss:GetBucketLocation", - "oss:AbortMultipartUpload", - "oss:ListMultipartUploads", - "oss:ListParts" - ], - "Resource": "*", - "Effect": "Allow" - } - ] - }` -) - -func (self *SApsaraClient) EnableImageExport() error { - _, err := self.GetRole(ApsaraECSImageExportRole) - if err != nil { - if err != cloudprovider.ErrNotFound { - return err - } - _, err = self.CreateRole(ApsaraECSImageExportRole, - ApsaraECSImageExportRoleDocument, - "Allow Export Import to OSS") - if err != nil { - return err - } - } - - _, err = self.GetPolicy(ApsaraECSImageExportRolePolicyType, ApsaraECSImageExportRolePolicy) - if err != nil { - /*if err != cloudprovider.ErrNotFound { - return err - } - _, err = self.createPolicy(ApsaraECSImageImportRolePolicy, - ApsaraECSImageImportRolePolicyDocument, - "Allow Import External Image policy") - if err != nil { - return err - }*/ - return err - } - - policies, err := self.ListPoliciesForRole(ApsaraECSImageExportRole) - if err != nil { - return err - } - for i := 0; i < len(policies); i += 1 { - if policies[i].PolicyType == ApsaraECSImageExportRolePolicyType && - policies[i].PolicyName == ApsaraECSImageExportRolePolicy { - return nil // find policy - } - } - - err = self.AttachPolicy2Role(ApsaraECSImageExportRolePolicyType, ApsaraECSImageExportRolePolicy, ApsaraECSImageExportRole) - if err != nil { - return err - } - - return nil -} diff --git a/pkg/multicloud/apsara/region.go b/pkg/multicloud/apsara/region.go deleted file mode 100644 index 8ce864a88e..0000000000 --- a/pkg/multicloud/apsara/region.go +++ /dev/null @@ -1,1100 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strings" - "time" - - "github.com/aliyun/alibaba-cloud-sdk-go/sdk" - "github.com/aliyun/aliyun-oss-go-sdk/oss" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/regutils" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - multicloud.SRegion - - client *SApsaraClient - sdkClient *sdk.Client - - RegionId string - LocalName string - - izones []cloudprovider.ICloudZone - - ivpcs []cloudprovider.ICloudVpc - - lbEndpints map[string]string - - storageCache *SStoragecache - - instanceTypes []SInstanceType - - latitude float64 - longitude float64 - fetchLocation bool - - ossEndpoint string -} - -func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetClient() *SApsaraClient { - return self.client -} - -func (self *SRegion) getSdkClient() (*sdk.Client, error) { - if self.sdkClient == nil { - var err error - self.sdkClient, err = self.GetClient().getDefaultClient(self.RegionId) - if err != nil { - return nil, err - } - } - return self.sdkClient, nil -} - -func (self *SRegion) GetOssClient() (*oss.Client, error) { - if len(self.ossEndpoint) == 0 { - _, err := self.GetBuckets() - if err != nil { - return nil, err - } - if len(self.ossEndpoint) == 0 { - return nil, fmt.Errorf("no available buckets") - } - } - return self.client.getOssClient(self.ossEndpoint) -} - -func (self *SRegion) productRequest(client *sdk.Client, product, domain, apiVersion, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { - params["Product"] = product - return jsonRequest(client, domain, apiVersion, apiName, params, debug) -} - -func (self *SRegion) ossRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["RegionId"] = self.RegionId - return self.client.ossRequest(apiName, params) -} - -func (self *SRegion) ecsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - domain := self.client.getDomain(APSARA_PRODUCT_ECS) - params["Product"] = APSARA_PRODUCT_ECS - return jsonRequest(client, domain, APSARA_API_VERSION, apiName, params, self.client.debug) -} - -func (self *SRegion) rdsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - domain := self.client.getDomain(APSARA_PRODUCT_RDS) - return self.productRequest(client, APSARA_PRODUCT_RDS, domain, APSARA_API_VERION_RDS, apiName, params, self.client.debug) -} - -func (self *SRegion) vpcRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - domain := self.client.getDomain(APSARA_PRODUCT_VPC) - return self.productRequest(client, APSARA_PRODUCT_VPC, domain, APSARA_API_VERSION_VPC, action, params, self.client.debug) -} - -func (self *SRegion) kvsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - domain := self.client.getDomain(APSARA_PRODUCT_KVSTORE) - return self.productRequest(client, APSARA_PRODUCT_KVSTORE, domain, APSARA_API_VERSION_KVS, action, params, self.client.debug) -} - -func (self *SRegion) tagRequest(serviceType string, action string, params map[string]string) (jsonutils.JSONObject, error) { - switch serviceType { - case APSARA_PRODUCT_ECS: - return self.ecsRequest(action, params) - case APSARA_PRODUCT_RDS: - return self.rdsRequest(action, params) - case APSARA_PRODUCT_SLB: - return self.lbRequest(action, params) - case APSARA_PRODUCT_KVSTORE: - return self.kvsRequest(action, params) - default: - return nil, errors.Wrapf(errors.ErrNotSupported, "not support %s service tag", serviceType) - } -} - -func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - client, err := self.getSdkClient() - if err != nil { - return nil, err - } - domain := self.client.getDomain(APSARA_PRODUCT_SLB) - return self.productRequest(client, APSARA_PRODUCT_SLB, domain, APSARA_API_VERSION_LB, apiName, params, self.client.debug) -} - -///////////////////////////////////////////////////////////////////////////// -func (self *SRegion) GetId() string { - return self.RegionId -} - -func (self *SRegion) GetName() string { - switch self.client.cpcfg.Vendor { - case api.CLOUD_PROVIDER_APSARA: - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_APSARA_CN, self.LocalName) - default: - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_APSARA_CN, self.LocalName) - } -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_APSARA_EN, self.LocalName) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_APSARA, self.RegionId) -} - -func (self *SRegion) IsEmulated() bool { - return false -} - -func (self *SRegion) GetProvider() string { - return self.client.cpcfg.Vendor -} - -func (self *SRegion) GetCloudEnv() string { - return "" -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) Refresh() error { - // do nothing - return nil -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if self.izones == nil { - var err error - err = self.fetchInfrastructure() - if err != nil { - return nil, err - } - } - return self.izones, nil -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) getStoragecache() *SStoragecache { - if self.storageCache == nil { - self.storageCache = &SStoragecache{region: self} - } - return self.storageCache -} - -func (self *SRegion) _fetchZones(chargeType TChargeType, spotStrategy SpotStrategyType) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - if len(chargeType) > 0 { - params["InstanceChargeType"] = string(chargeType) - } - if len(spotStrategy) > 0 { - params["SpotStrategy"] = string(spotStrategy) - } - body, err := self.ecsRequest("DescribeZones", params) - if err != nil { - return err - } - - zones := make([]SZone, 0) - err = body.Unmarshal(&zones, "Zones", "Zone") - if err != nil { - return err - } - - self.izones = make([]cloudprovider.ICloudZone, len(zones)) - - for i := 0; i < len(zones); i += 1 { - zones[i].region = self - self.izones[i] = &zones[i] - } - - return nil -} - -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) -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - return self.GetInstance(id) -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return self.getDisk(id) -} - -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) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - ivpcs, err := self.GetIVpcs() - if err != nil { - return nil, err - } - for i := 0; i < len(ivpcs); i += 1 { - if ivpcs[i].GetGlobalId() == id { - return ivpcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) fetchIVpcs() error { - vpcs := make([]SVpc, 0) - for { - part, total, err := self.GetVpcs(nil, len(vpcs), 50) - if err != nil { - return err - } - vpcs = append(vpcs, part...) - if len(vpcs) >= total { - break - } - } - self.ivpcs = make([]cloudprovider.ICloudVpc, len(vpcs)) - for i := 0; i < len(vpcs); i += 1 { - vpcs[i].region = self - self.ivpcs[i] = &vpcs[i] - } - return nil -} - -func (self *SRegion) fetchInfrastructure() error { - err := self._fetchZones(PostPaidInstanceChargeType, NoSpotStrategy) - if err != nil { - return err - } - err = self.fetchIVpcs() - if 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) GetVpcs(vpcId []string, offset int, limit int) ([]SVpc, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - if vpcId != nil && len(vpcId) > 0 { - params["VpcId"] = strings.Join(vpcId, ",") - } - - body, err := self.ecsRequest("DescribeVpcs", params) - if err != nil { - log.Errorf("GetVpcs fail %s", err) - return nil, 0, err - } - - vpcs := make([]SVpc, 0) - err = body.Unmarshal(&vpcs, "Vpcs", "Vpc") - if err != nil { - log.Errorf("Unmarshal vpc fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return vpcs, int(total), 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) GetVRouters(offset int, limit int) ([]SVRouter, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - body, err := self.ecsRequest("DescribeVRouters", params) - if err != nil { - log.Errorf("GetVRouters fail %s", err) - return nil, 0, err - } - - vrouters := make([]SVRouter, 0) - err = body.Unmarshal(&vrouters, "VRouters", "VRouter") - if err != nil { - log.Errorf("Unmarshal vrouter fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return vrouters, int(total), nil -} - -func (self *SRegion) GetRouteTables(ids []string, offset int, limit int) ([]SRouteTable, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - if ids != nil && len(ids) > 0 { - params["RouteTableId"] = strings.Join(ids, ",") - } - - body, err := self.ecsRequest("DescribeRouteTables", params) - if err != nil { - log.Errorf("GetRouteTables fail %s", err) - return nil, 0, err - } - - routetables := make([]SRouteTable, 0) - err = body.Unmarshal(&routetables, "RouteTables", "RouteTable") - if err != nil { - log.Errorf("Unmarshal routetables fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return routetables, int(total), nil -} - -func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, gpu int, zoneId string) ([]SInstanceType, error) { - if self.instanceTypes == nil { - types, err := self.GetInstanceTypes() - if err != nil { - log.Errorf("GetInstanceTypes %s", err) - return nil, err - } - self.instanceTypes = types - } - var available []string - if len(zoneId) > 0 { - zone, err := self.getZoneById(zoneId) - if err != nil { - return nil, err - } - available = zone.AvailableInstanceTypes.InstanceTypes - } - ret := make([]SInstanceType, 0) - for _, t := range self.instanceTypes { - if t.CpuCoreCount == cpu && memMB == t.memoryMB() && gpu == t.GPUAmount { - if available == nil || utils.IsInStringArray(t.InstanceTypeId, available) { - ret = append(ret, t) - } - } - } - return ret, nil -} - -func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, memGB int, storageType string, dataDiskSizesGB []int, vswitchId string, passwd 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(vswitchId) - if net != nil { - desc := &cloudprovider.SManagedVMCreateConfig{ - Name: name, - ExternalImageId: imgId, - SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType}, - Cpu: cpu, - MemoryMB: memGB * 1024, - ExternalNetworkId: vswitchId, - Password: passwd, - DataDisks: []cloudprovider.SDiskInfo{}, - PublicKey: publicKey, - } - for _, sizeGB := range dataDiskSizesGB { - desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType}) - } - inst, err := z.getHost().CreateVM(desc) - if err != nil { - return nil, err - } - return inst.(*SInstance), nil - } - } - return nil, fmt.Errorf("cannot find vswitch %s", vswitchId) -} - -func (self *SRegion) instanceOperation(instanceId string, opname string, extra map[string]string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - if extra != nil && len(extra) > 0 { - for k, v := range extra { - params[k] = v - } - } - _, err := self.ecsRequest(opname, params) - return err -} - -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) GetInstanceVNCUrl(instanceId string) (string, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - body, err := self.ecsRequest("DescribeInstanceVncUrl", params) - if err != nil { - return "", err - } - return body.GetString("VncUrl") -} - -func (self *SRegion) ModifyInstanceVNCUrlPassword(instanceId string, passwd string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["InstanceId"] = instanceId - params["VncPassword"] = passwd // must be 6 digital + alphabet - _, err := self.ecsRequest("ModifyInstanceVncPasswd", params) - return err -} - -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - params := make(map[string]string) - if len(opts.CIDR) > 0 { - params["CidrBlock"] = opts.CIDR - } - if len(opts.NAME) > 0 { - params["VpcName"] = opts.NAME - } - if len(opts.Desc) > 0 { - params["Description"] = opts.Desc - } - params["ClientToken"] = utils.GenRequestId(20) - body, err := self.ecsRequest("CreateVpc", params) - if err != nil { - return nil, err - } - vpcId, err := body.GetString("VpcId") - if err != nil { - return nil, err - } - err = self.fetchInfrastructure() - if err != nil { - return nil, err - } - return self.GetIVpcById(vpcId) -} - -func (self *SRegion) DeleteVpc(vpcId string) error { - params := make(map[string]string) - params["VpcId"] = vpcId - - _, err := self.ecsRequest("DeleteVpc", params) - return err -} - -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) GetIHosts() ([]cloudprovider.ICloudHost, error) { - iHosts := make([]cloudprovider.ICloudHost, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneHost, err := izones[i].GetIHosts() - if err != nil { - return nil, err - } - iHosts = append(iHosts, iZoneHost...) - } - return iHosts, nil -} - -func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname, userData string) error { - params := make(map[string]string) - params["InstanceId"] = instId - if len(name) > 0 { - params["InstanceName"] = name - } - if len(desc) > 0 { - params["Description"] = desc - } - if len(passwd) > 0 { - params["Password"] = passwd - } - if len(hostname) > 0 { - params["HostName"] = hostname - } - if len(userData) > 0 { - params["UserData"] = userData - } - _, err := self.ecsRequest("ModifyInstanceAttribute", params) - return err -} - -func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error { - return self.updateInstance(instId, "", "", passwd, "", "") -} - -// func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { -// eips, total, err := self.GetSnapshots("", 0, 50) -// if err != nil { -// return nil, err -// } -// for len(eips) < total { -// var parts []SEipAddress -// parts, total, err = self.GetEips("", len(eips), 50) -// if err != nil { -// return nil, err -// } -// eips = append(eips, parts...) -// } -// ret := make([]cloudprovider.ICloudEIP, len(eips)) -// for i := 0; i < len(eips); i += 1 { -// ret[i] = &eips[i] -// } -// return ret, nil -// } - -func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, total, err := self.GetEips("", "", 0, 50) - if err != nil { - return nil, err - } - for len(eips) < total { - var parts []SEipAddress - parts, total, err = self.GetEips("", "", len(eips), 50) - if err != nil { - return nil, err - } - eips = append(eips, parts...) - } - ret := make([]cloudprovider.ICloudEIP, len(eips)) - for i := 0; i < len(eips); i += 1 { - ret[i] = &eips[i] - } - return ret, nil -} - -func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { - eips, total, err := self.GetEips(eipId, "", 0, 1) - 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 (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - secgroup, err := region.GetSecurityGroupDetails(secgroupId) - if err != nil { - return nil, err - } - vpc, err := region.getVpc(secgroup.VpcId) - if err != nil { - return nil, errors.Wrapf(err, "region.getVpc(%s)", secgroup.VpcId) - } - secgroup.vpc = vpc - return secgroup, nil -} - -func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, total, err := region.GetSecurityGroups(opts.VpcId, opts.Name, []string{}, 0, 0) - if err != nil { - return nil, err - } - if total == 0 { - return nil, cloudprovider.ErrNotFound - } - if total > 1 { - return nil, cloudprovider.ErrDuplicateId - } - return &secgroups[0], nil -} - -func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - externalId, err := region.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) - if err != nil { - return nil, err - } - return region.GetISecurityGroupById(externalId) -} - -func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - lbs, err := region.GetLoadbalancers(nil) - if err != nil { - return nil, err - } - ilbs := []cloudprovider.ICloudLoadbalancer{} - for i := 0; i < len(lbs); i++ { - lbs[i].region = region - ilbs = append(ilbs, &lbs[i]) - } - return ilbs, nil -} - -func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { - return region.GetLoadbalancerDetail(loadbalancerId) -} - -func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - certs, err := region.GetLoadbalancerServerCertificates() - if err != nil { - return nil, err - } - for i := 0; i < len(certs); i++ { - if certs[i].GetGlobalId() == certId { - certs[i].region = region - return &certs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["ServerCertificateName"] = cert.Name - params["PrivateKey"] = cert.PrivateKey - params["ServerCertificate"] = cert.Certificate - body, err := region.lbRequest("UploadServerCertificate", params) - if err != nil { - return nil, err - } - certID, err := body.GetString("ServerCertificateId") - if err != nil { - return nil, err - } - return region.GetILoadBalancerCertificateById(certID) -} - -func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - certificates, err := region.GetLoadbalancerServerCertificates() - if err != nil { - return nil, err - } - iCertificates := []cloudprovider.ICloudLoadbalancerCertificate{} - for i := 0; i < len(certificates); i++ { - certificates[i].region = region - iCertificates = append(iCertificates, &certificates[i]) - } - return iCertificates, nil -} - -func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["LoadBalancerName"] = loadbalancer.Name - if len(loadbalancer.ZoneID) > 0 { - params["MasterZoneId"] = loadbalancer.ZoneID - } - - if len(loadbalancer.VpcID) > 0 { - params["VpcId"] = loadbalancer.VpcID - } - - if len(loadbalancer.NetworkIDs) > 0 { - params["VSwitchId"] = loadbalancer.NetworkIDs[0] - } - - if len(loadbalancer.Address) > 0 { - params["Address"] = loadbalancer.Address - } - - if len(loadbalancer.AddressType) > 0 { - params["AddressType"] = loadbalancer.AddressType - } - - if len(loadbalancer.LoadbalancerSpec) > 0 { - params["LoadBalancerSpec"] = loadbalancer.LoadbalancerSpec - } - - if len(loadbalancer.ChargeType) > 0 { - params["InternetChargeType"] = "payby" + loadbalancer.ChargeType - } - - if len(loadbalancer.ProjectId) > 0 { - params["ResourceGroupId"] = loadbalancer.ProjectId - } - - if loadbalancer.ChargeType == api.LB_CHARGE_TYPE_BY_BANDWIDTH && loadbalancer.EgressMbps > 0 { - params["Bandwidth"] = fmt.Sprintf("%d", loadbalancer.EgressMbps) - } - - body, err := region.lbRequest("CreateLoadBalancer", params) - if err != nil { - return nil, err - } - loadBalancerID, err := body.GetString("LoadBalancerId") - if err != nil { - return nil, err - } - region.SetResourceTags("slb", "instance", []string{loadBalancerID}, loadbalancer.Tags, false) - iLoadbalancer, err := region.GetLoadbalancerDetail(loadBalancerID) - if err != nil { - return nil, err - } - return iLoadbalancer, cloudprovider.WaitStatus(iLoadbalancer, api.LB_STATUS_ENABLED, time.Second*5, time.Minute*5) -} - -func (region *SRegion) AddAccessControlListEntry(aclId string, entrys []cloudprovider.SLoadbalancerAccessControlListEntry) error { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["AclId"] = aclId - aclArray := jsonutils.NewArray() - for i := 0; i < len(entrys); i++ { - //阿里云AclEntrys参数必须是CIDR格式的。 - if regutils.MatchIPAddr(entrys[i].CIDR) { - entrys[i].CIDR += "/32" - } - aclArray.Add(jsonutils.Marshal(map[string]string{"entry": entrys[i].CIDR, "comment": entrys[i].Comment})) - } - if aclArray.Length() == 0 { - return nil - } - params["AclEntrys"] = aclArray.String() - _, err := region.lbRequest("AddAccessControlListEntry", params) - return err -} - -func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - params := map[string]string{} - params["RegionId"] = region.RegionId - params["AclName"] = acl.Name - body, err := region.lbRequest("CreateAccessControlList", params) - if err != nil { - return nil, err - } - aclId, err := body.GetString("AclId") - if err != nil { - return nil, err - } - iAcl, err := region.GetLoadbalancerAclDetail(aclId) - if err != nil { - return nil, err - } - return iAcl, region.AddAccessControlListEntry(aclId, acl.Entrys) -} - -func (self *SRegion) GetBuckets() ([]SBucket, error) { - resp, err := self.ossRequest("GetService", map[string]string{}) - if err != nil { - return nil, err - } - if !resp.Contains("Data") { - if self.client.cpcfg.UpdatePermission != nil { - self.client.cpcfg.UpdatePermission("oss", "ListBuckets") - } - return []SBucket{}, nil - } - ret := []SBucket{} - err = resp.Unmarshal(&ret, "Data", "ListAllMyBucketsResult", "Buckets", "Bucket") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - if len(ret) > 0 { - self.ossEndpoint = ret[0].IntranetEndpoint - } - return ret, nil -} - -func (self *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - buckets, err := self.GetBuckets() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudBucket{} - for i := range buckets { - buckets[i].region = self - ret = append(ret, &buckets[i]) - } - return ret, nil -} - -func str2StorageClass(storageClassStr string) (oss.StorageClassType, error) { - storageClass := oss.StorageStandard - if strings.EqualFold(storageClassStr, string(oss.StorageStandard)) { - // - } else if strings.EqualFold(storageClassStr, string(oss.StorageIA)) { - storageClass = oss.StorageIA - } else if strings.EqualFold(storageClassStr, string(oss.StorageArchive)) { - storageClass = oss.StorageArchive - } else { - return storageClass, errors.Error("not supported storageClass") - } - return storageClass, nil -} - -func str2Acl(aclStr string) (oss.ACLType, error) { - acl := oss.ACLPrivate - if strings.EqualFold(aclStr, string(oss.ACLPrivate)) { - // private, default - } else if strings.EqualFold(aclStr, string(oss.ACLPublicRead)) { - acl = oss.ACLPublicRead - } else if strings.EqualFold(aclStr, string(oss.ACLPublicReadWrite)) { - acl = oss.ACLPublicReadWrite - } else { - return acl, errors.Error("not supported acl") - } - return acl, nil -} - -func (self *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { - osscli, err := self.GetOssClient() - if err != nil { - return errors.Wrap(err, "region.GetOssClient") - } - opts := make([]oss.Option, 0) - if len(storageClassStr) > 0 { - storageClass, err := str2StorageClass(storageClassStr) - if err != nil { - return err - } - opts = append(opts, oss.StorageClass(storageClass)) - } - if len(aclStr) > 0 { - acl, err := str2Acl(aclStr) - if err != nil { - return err - } - opts = append(opts, oss.ACL(acl)) - } - return osscli.CreateBucket(name, opts...) -} - -func ossErrorCode(err error) int { - if srvErr, ok := err.(oss.ServiceError); ok { - return srvErr.StatusCode - } - if srvErr, ok := err.(*oss.ServiceError); ok { - return srvErr.StatusCode - } - return -1 -} - -func (self *SRegion) DeleteIBucket(name string) error { - cli, err := self.GetOssClient() - if err != nil { - return err - } - return cli.DeleteBucket(name) -} - -func (self *SRegion) GetBucket(name string) (*SBucket, error) { - params := map[string]string{ - "AccountInfo": "aaa", - "x-acs-instanceid": name, - "Params": jsonutils.Marshal(map[string]string{"BucketName": name}).String(), - } - resp, err := self.ossRequest("GetBucketInfo", params) - if err != nil { - return nil, errors.Wrapf(err, "GetBucketInfo") - } - bucket := &SBucket{region: self} - return bucket, resp.Unmarshal(bucket, "Data", "BucketInfo", "Bucket") -} - -func (self *SRegion) IBucketExist(name string) (bool, error) { - _, err := self.GetBucket(name) - if err != nil { - return false, err - } - return true, nil -} - -func (self *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { - buckets, err := self.GetBuckets() - if err != nil { - return nil, err - } - for i := range buckets { - if buckets[i].GetName() == name { - buckets[i].region = self - return &buckets[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) -} - -func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { - return region.GetIBucketById(name) -} - -func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { - caches, err := self.GetElasticCaches(nil) - if err != nil { - return nil, err - } - - icaches := make([]cloudprovider.ICloudElasticcache, len(caches)) - for i := range caches { - caches[i].region = self - icaches[i] = &caches[i] - } - - return icaches, nil -} - -func (region *SRegion) GetCapabilities() []string { - return region.client.GetCapabilities() -} diff --git a/pkg/multicloud/apsara/resource_tags.go b/pkg/multicloud/apsara/resource_tags.go deleted file mode 100644 index 73b08cdd5b..0000000000 --- a/pkg/multicloud/apsara/resource_tags.go +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type STagResource struct { - ResourceType string `json:"ResourceType"` - TagValue string `json:"TagValue"` - ResourceID string `json:"ResourceId"` - TagKey string `json:"TagKey"` -} - -func (self *SRegion) rawListTagResources(serviceType string, resourceType string, resIds []string, token string) ([]STagResource, string, error) { - if len(resIds) > 50 { - return nil, "", errors.Wrap(cloudprovider.ErrNotSupported, "resource count exceed 50 for one request") - } - params := make(map[string]string) - params["ResourceType"] = resourceType - for i := range resIds { - params[fmt.Sprintf("ResourceId.%d", i+1)] = resIds[i] - } - if len(token) != 0 { - params["NextToken"] = token - } - ret, err := self.tagRequest(serviceType, "ListTagResources", params) - if err != nil { - return nil, "", errors.Wrapf(err, `self.tagRequest(%s,"ListTagResources", %s)`, serviceType, jsonutils.Marshal(params).String()) - } - tagResources := []STagResource{} - err = ret.Unmarshal(&tagResources, "TagResources", "TagResource") - if err != nil { - return nil, "", errors.Wrapf(err, "(%s).Unmarshal(&tagResources)", ret.String()) - } - nextToken, _ := ret.GetString("NextToken") - return tagResources, nextToken, nil -} - -func splitStringSlice(resIds []string, stride int) [][]string { - result := [][]string{} - i := 0 - for i < len(resIds)/stride { - result = append(result, resIds[i*stride:i*stride+stride]) - i++ - } - remainder := len(resIds) % stride - if remainder != 0 { - result = append(result, resIds[i*stride:i*stride+remainder]) - } - return result -} - -func splitTags(tags map[string]string, stride int) []map[string]string { - tagsGroups := []map[string]string{} - tagsGroup := map[string]string{} - for k, v := range tags { - tagsGroup[k] = v - if len(tagsGroup) == stride { - tagsGroups = append(tagsGroups, tagsGroup) - tagsGroup = map[string]string{} - } - } - if len(tagsGroup) > 0 { - tagsGroups = append(tagsGroups, tagsGroup) - } - return tagsGroups -} - -func (self *SRegion) ListResourceTags(serviceType string, resourceType string, resIds []string) (map[string]*map[string]string, error) { - tags := make(map[string]*map[string]string) - tagReources := []STagResource{} - nextToken := "" - resIdsGroups := splitStringSlice(resIds, 50) - for i := range resIdsGroups { - for { - _tagResource, nextToken, err := self.rawListTagResources(serviceType, resourceType, resIdsGroups[i], nextToken) - if err != nil { - return nil, errors.Wrapf(err, "self.rawListTagResources(%s,%s,%s)", resourceType, resIds, nextToken) - } - tagReources = append(tagReources, _tagResource...) - if len(_tagResource) == 0 || len(nextToken) == 0 { - break - } - - } - } - for _, r := range tagReources { - if tagMapPtr, ok := tags[r.ResourceID]; !ok { - tagMap := map[string]string{ - r.TagKey: r.TagValue, - } - tags[r.ResourceID] = &tagMap - } else { - tagMap := *tagMapPtr - tagMap[r.TagKey] = r.TagValue - } - } - return tags, nil -} - -func (self *SRegion) rawTagResources(serviceType string, resourceType string, resIds []string, tags map[string]string) error { - if len(resIds) > 50 { - return errors.Wrap(cloudprovider.ErrNotSupported, "resource count exceed 50 for one request") - } - if len(tags) > 20 { - return errors.Wrap(cloudprovider.ErrNotSupported, "tags count exceed 20 for one request") - } - params := make(map[string]string) - params["ResourceType"] = resourceType - for i := range resIds { - params[fmt.Sprintf("ResourceId.%d", i+1)] = resIds[i] - } - i := 0 - for k, v := range tags { - params[fmt.Sprintf("Tag.%d.Key", i+1)] = k - params[fmt.Sprintf("Tag.%d.Value", i+1)] = v - i++ - } - _, err := self.tagRequest(serviceType, "TagResources", params) - if err != nil { - return errors.Wrapf(err, `self.tagRequest(%s,"TagResources", %s)`, serviceType, jsonutils.Marshal(params).String()) - } - return nil -} - -func (self *SRegion) TagResources(serviceType string, resourceType string, resIds []string, tags map[string]string) error { - if len(resIds) == 0 || len(tags) == 0 { - return nil - } - resIdsGroups := splitStringSlice(resIds, 50) - tagsGroups := splitTags(tags, 20) - for i := range resIdsGroups { - for j := range tagsGroups { - err := self.rawTagResources(serviceType, resourceType, resIdsGroups[i], tagsGroups[j]) - if err != nil { - return errors.Wrapf(err, "self.rawTagResources(resourceType, resIdsGroups[i], tagsGroups[i])") - } - } - } - return nil -} - -func (self *SRegion) rawUntagResources(serviceType string, resourceType string, resIds []string, tags []string) error { - if len(resIds) > 50 { - return errors.Wrap(cloudprovider.ErrNotSupported, "resource count exceed 50 for one request") - } - if len(tags) > 20 { - return errors.Wrap(cloudprovider.ErrNotSupported, "tags count exceed 20 for one request") - } - params := make(map[string]string) - params["ResourceType"] = resourceType - for i := range resIds { - params[fmt.Sprintf("ResourceId.%d", i+1)] = resIds[i] - } - for i := range tags { - params[fmt.Sprintf("TagKey.%d", i+1)] = tags[i] - } - _, err := self.tagRequest(serviceType, "UntagResources", params) - if err != nil { - return errors.Wrapf(err, `self.tagRequest(%s,"UntagResources", %s)`, serviceType, jsonutils.Marshal(params).String()) - } - return nil -} - -func (self *SRegion) UntagResources(serviceType string, resourceType string, resIds []string, tags []string) error { - if len(resIds) == 0 || len(tags) == 0 { - return nil - } - resIdsGroups := splitStringSlice(resIds, 50) - tagsGroups := splitStringSlice(tags, 20) - for i := range resIdsGroups { - for j := range tagsGroups { - err := self.rawUntagResources(serviceType, resourceType, resIdsGroups[i], tagsGroups[j]) - if err != nil { - return errors.Wrapf(err, "self.rawTagResources(resourceType, resIdsGroups[i], tagsGroups[i])") - } - } - } - return nil -} - -func (self *SRegion) SetResourceTags(serviceType string, resourceType string, resIds []string, tags map[string]string, replace bool) error { - oldTags, err := self.ListResourceTags(serviceType, resourceType, resIds) - if err != nil { - return errors.Wrapf(err, "self.ListResourceTags(%s,%s)", resourceType, resIds) - } - for i := range resIds { - _, ok := oldTags[resIds[i]] - if !ok { - err := self.TagResources(serviceType, resourceType, []string{resIds[i]}, tags) - if err != nil { - return errors.Wrap(err, "self.TagResources(resourceType, []string{resIds[i]}, tags)") - } - } else { - oldResourceTags := *oldTags[resIds[i]] - addTags := map[string]string{} - for k, v := range tags { - if _, ok := oldResourceTags[k]; !ok { - addTags[k] = v - } else { - if oldResourceTags[k] != v { - addTags[k] = v - } - } - } - delTags := []string{} - if replace { - for k := range oldResourceTags { - if _, ok := tags[k]; !ok { - delTags = append(delTags, k) - } - } - } - err := self.UntagResources(serviceType, resourceType, []string{resIds[i]}, delTags) - if err != nil { - return errors.Wrap(err, "self.UntagResources(resourceType, []string{resIds[i]}, delTags)") - } - err = self.TagResources(serviceType, resourceType, []string{resIds[i]}, addTags) - if err != nil { - return errors.Wrap(err, "self.TagResources(resourceType, []string{resIds[i]}, addTags)") - } - } - } - return nil -} diff --git a/pkg/multicloud/apsara/routetable.go b/pkg/multicloud/apsara/routetable.go deleted file mode 100644 index 460d06f597..0000000000 --- a/pkg/multicloud/apsara/routetable.go +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// {"CreationTime":"2017-03-19T13:37:40Z","RouteEntrys":{"RouteEntry":[{"DestinationCidrBlock":"172.31.32.0/20","InstanceId":"","NextHopType":"local","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"},{"DestinationCidrBlock":"100.64.0.0/10","InstanceId":"","NextHopType":"service","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"}]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","RouteTableType":"System","VRouterId":"vrt-j6c00qrol733dg36iq4qj"} - -type SNextHops struct { - NextHop []string -} - -type SRouteEntry struct { - multicloud.SResourceBase - multicloud.ApsaraTags - routeTable *SRouteTable - - RouteTableId string - Type string - DestinationCidrBlock string - NextHopType string - InstanceId string - RouteEntryId string - RouteEntryName string - NextHops SNextHops -} - -func (route *SRouteEntry) GetId() string { - return route.RouteEntryId -} - -func (route *SRouteEntry) GetName() string { - return route.RouteEntryName -} - -func (route *SRouteEntry) GetGlobalId() string { - return route.GetId() -} - -func (route *SRouteEntry) GetStatus() string { - return "" -} - -func (route *SRouteEntry) Refresh() error { - return nil -} - -func (route *SRouteEntry) IsEmulated() bool { - return false -} - -// Custom:自定义路由。 System:系统路由。 -func (route *SRouteEntry) GetType() string { - return route.Type -} - -func (route *SRouteEntry) GetCidr() string { - return route.DestinationCidrBlock -} - -func (route *SRouteEntry) GetNextHopType() string { - return route.NextHopType -} - -func (route *SRouteEntry) GetNextHop() string { - return route.InstanceId -} - -type SRouteEntrys struct { - RouteEntry []*SRouteEntry -} - -type SRouteTable struct { - multicloud.SResourceBase - multicloud.ApsaraTags - region *SRegion - vpc *SVpc - routes []cloudprovider.ICloudRoute - - VpcId string - CreationTime time.Time - RouteEntrys SRouteEntrys - VRouterId string - Description string - - RouteTableId string - RouteTableName string - RouteTableType string - RouterId string - RouterType string - VSwitchIds SRouteTableVSwitchIds -} - -type SRouteTableVSwitchIds struct { - VSwitchId []string -} - -type sDescribeRouteTablesResponseRouteTables struct { - RouteTable []SRouteTable -} - -type sDescribeRouteTablesResponse struct { - RouteTables sDescribeRouteTablesResponseRouteTables - TotalCount int -} - -func (self *SRouteTable) GetDescription() string { - return self.Description -} - -func (self *SRouteTable) GetId() string { - return self.GetGlobalId() -} - -func (self *SRouteTable) GetGlobalId() string { - return self.RouteTableId -} - -func (self *SRouteTable) GetName() string { - return self.RouteTableName -} - -func (self *SRouteTable) GetRegionId() string { - return self.region.RegionId -} - -// VRouter:VPC路由器。 VBR:边界路由器。 -func (self *SRouteTable) GetType() cloudprovider.RouteTableType { - switch self.RouteTableType { - case "System": - return cloudprovider.RouteTableTypeSystem - case "Custom": - return cloudprovider.RouteTableTypeCustom - default: - return cloudprovider.RouteTableTypeSystem - } -} - -func (self *SRouteTable) GetVpcId() string { - return self.VpcId -} - -func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { - if self.routes == nil { - err := self.fetchRoutes() - if err != nil { - return nil, err - } - } - return self.routes, nil -} - -func (self *SRouteTable) GetStatus() string { - return "" -} - -func (self *SRouteTable) IsEmulated() bool { - return false -} - -func (self *SRouteTable) Refresh() error { - return nil -} - -func (self *SRouteTable) fetchRoutes() error { - routes := make([]*SRouteEntry, 0) - for { - parts, total, err := self.RemoteGetRoutes(len(routes), 50) - if err != nil { - return err - } - routes = append(routes, parts...) - if len(routes) >= total { - break - } - } - self.routes = make([]cloudprovider.ICloudRoute, len(routes)) - for i := 0; i < len(routes); i++ { - routes[i].routeTable = self - self.routes[i] = routes[i] - } - return nil -} - -func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { - result := []cloudprovider.RouteTableAssociation{} - switch self.RouterType { - case "VRouter": - for i := range self.VSwitchIds.VSwitchId { - association := cloudprovider.RouteTableAssociation{ - AssociationId: self.RouteTableId + ":" + self.VSwitchIds.VSwitchId[i], - AssociationType: cloudprovider.RouteTableAssociaToSubnet, - AssociatedResourceId: self.VSwitchIds.VSwitchId[i], - } - result = append(result, association) - } - case "VBR": - association := cloudprovider.RouteTableAssociation{ - AssociationId: self.RouteTableId + ":" + self.RouterId, - AssociationType: cloudprovider.RouteTableAssociaToRouter, - AssociatedResourceId: self.RouterId, - } - result = append(result, association) - } - - return result -} - -func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRouteTable) RemoteGetRoutes(offset int, limit int) ([]*SRouteEntry, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RouteTableId"] = self.RouteTableId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - body, err := self.region.ecsRequest("DescribeRouteTables", params) - if err != nil { - log.Errorf("RemoteGetRoutes fail %s", err) - return nil, 0, err - } - - resp := sDescribeRouteTablesResponse{} - err = body.Unmarshal(&resp) - if err != nil { - log.Errorf("Unmarshal routeEntrys fail %s", err) - return nil, 0, err - } - routeTables := resp.RouteTables.RouteTable - if len(routeTables) != 1 { - return nil, 0, fmt.Errorf("expecting 1 route table, got %d", len(routeTables)) - } - routeTable := routeTables[0] - return routeTable.RouteEntrys.RouteEntry, resp.TotalCount, nil -} - -func (self *SVpc) RemoteGetRouteTableList(offset int, limit int) ([]*SRouteTable, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["VpcId"] = self.VpcId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - body, err := self.region.vpcRequest("DescribeRouteTableList", params) - if err != nil { - log.Errorf("RemoteGetRouteTableList fail %s", err) - return nil, 0, err - } - - routeTables := make([]*SRouteTable, 0) - err = body.Unmarshal(&routeTables, "RouterTableList", "RouterTableListType") - if err != nil { - log.Errorf("Unmarshal routeTables fail %s", err) - return nil, 0, err - } - for _, routeTable := range routeTables { - routeTable.region = self.region - } - total, _ := body.Int("TotalCount") - return routeTables, int(total), nil -} - -func (region *SRegion) AssociateRouteTable(rtableId string, vswitchId string) error { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["RouteTableId"] = rtableId - params["VSwitchId"] = vswitchId - _, err := region.vpcRequest("AssociateRouteTable", params) - return err -} - -func (region *SRegion) UnassociateRouteTable(rtableId string, vswitchId string) error { - params := make(map[string]string) - params["RegionId"] = region.RegionId - params["RouteTableId"] = rtableId - params["VSwitchId"] = vswitchId - _, err := region.vpcRequest("UnassociateRouteTable", params) - return err -} - -func (routeTable *SRouteTable) IsSystem() bool { - return strings.ToLower(routeTable.RouteTableType) == "system" -} diff --git a/pkg/multicloud/apsara/securitygroup.go b/pkg/multicloud/apsara/securitygroup.go deleted file mode 100644 index 61bfe65359..0000000000 --- a/pkg/multicloud/apsara/securitygroup.go +++ /dev/null @@ -1,512 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// {"CreationTime":"2017-03-19T13:37:48Z","Description":"System created security group.","SecurityGroupId":"sg-j6cannq0xxj2r9z0yxwl","SecurityGroupName":"sg-j6cannq0xxj2r9z0yxwl","Tags":{"Tag":[]},"VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"} -// {"Description":"System created security group.","InnerAccessPolicy":"Accept","Permissions":{"Permission":[{"CreateTime":"2017-03-19T13:37:54Z","Description":"","DestCidrIp":"","DestGroupId":"","DestGroupName":"","DestGroupOwnerAccount":"","Direction":"ingress","IpProtocol":"ALL","NicType":"intranet","Policy":"Accept","PortRange":"-1/-1","Priority":110,"SourceCidrIp":"0.0.0.0/0","SourceGroupId":"","SourceGroupName":"","SourceGroupOwnerAccount":""},{"CreateTime":"2017-03-19T13:37:55Z","Description":"","DestCidrIp":"0.0.0.0/0","DestGroupId":"","DestGroupName":"","DestGroupOwnerAccount":"","Direction":"egress","IpProtocol":"ALL","NicType":"intranet","Policy":"Accept","PortRange":"-1/-1","Priority":110,"SourceCidrIp":"","SourceGroupId":"","SourceGroupName":"","SourceGroupOwnerAccount":""}]},"RegionId":"cn-hongkong","RequestId":"FBFE0950-5F2D-40DE-8C3C-E5A62AE7F7DA","SecurityGroupId":"sg-j6cannq0xxj2r9z0yxwl","SecurityGroupName":"sg-j6cannq0xxj2r9z0yxwl","VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"} - -type SecurityGroupPermissionNicType string - -const ( - IntranetNicType SecurityGroupPermissionNicType = "intranet" - InternetNicType SecurityGroupPermissionNicType = "internet" -) - -type SPermission struct { - CreateTime time.Time - Description string - DestCidrIp string - DestGroupId string - DestGroupName string - DestGroupOwnerAccount string - Direction string - IpProtocol string - NicType SecurityGroupPermissionNicType - Policy string - PortRange string - Priority int - SourceCidrIp string - SourceGroupId string - SourceGroupName string - SourceGroupOwnerAccount string -} - -type SPermissions struct { - Permission []SPermission -} - -type Tags struct { - Tag []Tag -} - -type Tag struct { - TagKey string - TagValue string -} - -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.ApsaraTags - - vpc *SVpc - CreationTime time.Time - Description string - SecurityGroupId string - SecurityGroupName string - VpcId string - InnerAccessPolicy string - Permissions SPermissions - RegionId string - Tags Tags - - DepartmentInfo -} - -func (self *SSecurityGroup) GetVpcId() string { - return self.VpcId -} - -func (self *SSecurityGroup) GetTags() (map[string]string, error) { - tags := map[string]string{} - for _, value := range self.Tags.Tag { - tags[value.TagKey] = value.TagValue - } - return tags, nil -} - -func (self *SSecurityGroup) GetId() string { - return self.SecurityGroupId -} - -func (self *SSecurityGroup) GetGlobalId() string { - return self.SecurityGroupId -} - -func (self *SSecurityGroup) GetDescription() string { - return self.Description -} - -func (self *SSecurityGroup) GetCreatedAt() time.Time { - return self.CreationTime -} - -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - rules := make([]cloudprovider.SecurityRule, 0) - secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) - if err != nil { - return nil, err - } - for _, permission := range secgrp.Permissions.Permission { - rule, err := permission.toRule() - if err != nil { - log.Errorf("convert rule %s for group %s(%s) error: %v", permission.Description, self.SecurityGroupName, self.SecurityGroupId, err) - continue - } - rules = append(rules, rule) - } - return rules, nil -} - -func (self *SSecurityGroup) GetName() string { - if len(self.SecurityGroupName) > 0 { - return self.SecurityGroupName - } - return self.SecurityGroupId -} - -func (self *SSecurityGroup) GetStatus() string { - return "" -} - -func (self *SSecurityGroup) IsEmulated() bool { - return false -} - -func (self *SSecurityGroup) Refresh() error { - group, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) - if err != nil { - return err - } - return jsonutils.Update(self, group) -} - -func (self *SRegion) GetSecurityGroups(vpcId, name string, securityGroupIds []string, offset int, limit int) ([]SSecurityGroup, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - if len(vpcId) > 0 { - params["VpcId"] = vpcId - } - if len(name) > 0 { - params["SecurityGroupName"] = name - } - - if securityGroupIds != nil && len(securityGroupIds) > 0 { - params["SecurityGroupIds"] = jsonutils.Marshal(securityGroupIds).String() - } - - body, err := self.ecsRequest("DescribeSecurityGroups", params) - if err != nil { - log.Errorf("GetSecurityGroups fail %s", err) - return nil, 0, err - } - - secgrps := make([]SSecurityGroup, 0) - err = body.Unmarshal(&secgrps, "SecurityGroups", "SecurityGroup") - if err != nil { - log.Errorf("Unmarshal security groups fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return secgrps, int(total), nil -} - -func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SecurityGroupId"] = secGroupId - - body, err := self.ecsRequest("DescribeSecurityGroupAttribute", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeSecurityGroupAttribute") - } - - secgrp := SSecurityGroup{} - err = body.Unmarshal(&secgrp) - if err != nil { - return nil, errors.Wrap(err, "body.Unmarshal") - } - return &secgrp, nil -} - -func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (string, error) { - params := make(map[string]string) - if len(vpcId) > 0 { - params["VpcId"] = vpcId - } - - if name == "Default" { - name = "Default-copy" - } - - if len(name) > 0 { - params["SecurityGroupName"] = name - } - if len(desc) > 0 { - params["Description"] = desc - } - params["ClientToken"] = utils.GenRequestId(20) - - body, err := self.ecsRequest("CreateSecurityGroup", params) - if err != nil { - return "", errors.Wrap(err, "CreateSecurityGroup") - } - return body.GetString("SecurityGroupId") -} - -func (self *SRegion) modifySecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SecurityGroupId"] = secGrpId - params["NicType"] = string(IntranetNicType) - params["Description"] = rule.Description - params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) - protocol := rule.Protocol - if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { - protocol = "all" - } - params["IpProtocol"] = protocol - if rule.PortStart < 1 && rule.PortEnd < 1 { - if protocol == "udp" || protocol == "tcp" { - params["PortRange"] = "1/65535" - } else { - params["PortRange"] = "-1/-1" - } - } - if rule.Action == secrules.SecurityRuleAllow { - params["Policy"] = "accept" - } else { - params["Policy"] = "drop" - } - params["Priority"] = fmt.Sprintf("%d", rule.Priority) - if rule.Direction == secrules.SecurityRuleIngress { - if rule.IPNet != nil { - params["SourceCidrIp"] = rule.IPNet.String() - } else { - params["SourceCidrIp"] = "0.0.0.0/0" - } - _, err := self.ecsRequest("ModifySecurityGroupRule", params) - return err - } else { // rule.Direction == secrules.SecurityRuleEgress { - //阿里云不支持出方向API接口调用 - return nil - // if rule.IPNet != nil { - // params["DestCidrIp"] = rule.IPNet.String() - // } else { - // params["DestCidrIp"] = "0.0.0.0/0" - // } - // _, err := self.ecsRequest("ModifySecurityGroupRule", params) - // return err - } -} - -func (self *SRegion) modifySecurityGroup(secGrpId string, name string, desc string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SecurityGroupId"] = secGrpId - params["SecurityGroupName"] = name - if len(desc) > 0 { - params["Description"] = desc - } - _, err := self.ecsRequest("ModifySecurityGroupAttribute", params) - return err -} - -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 - err := self.addSecurityGroupRule(secGrpId, rule) - if err != nil { - return errors.Wrapf(err, "addSecurityGroupRule %s", rule.String()) - } - } - return nil - } - return self.addSecurityGroupRule(secGrpId, rule) -} - -func (self *SRegion) addSecurityGroupRule(secGrpId string, rule secrules.SecurityRule) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SecurityGroupId"] = secGrpId - params["NicType"] = string(IntranetNicType) - params["Description"] = rule.Description - params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) - protocol := rule.Protocol - if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { - protocol = "all" - } - params["IpProtocol"] = protocol - if rule.PortStart < 1 && rule.PortEnd < 1 { - if protocol == "udp" || protocol == "tcp" { - params["PortRange"] = "1/65535" - } else { - params["PortRange"] = "-1/-1" - } - } - if rule.Action == secrules.SecurityRuleAllow { - params["Policy"] = "accept" - } else { - params["Policy"] = "drop" - } - - // 忽略地址为0.0.0.0/32这样的阿里云规则 - if rule.IPNet.IP.String() == "0.0.0.0" && rule.IPNet.String() != "0.0.0.0/0" { - return nil - } - - params["Priority"] = fmt.Sprintf("%d", rule.Priority) - if rule.Direction == secrules.SecurityRuleIngress { - if rule.IPNet != nil { - params["SourceCidrIp"] = rule.IPNet.String() - } else { - params["SourceCidrIp"] = "0.0.0.0/0" - } - _, err := self.ecsRequest("AuthorizeSecurityGroup", params) - return err - } else { // rule.Direction == secrules.SecurityRuleEgress { - if rule.IPNet != nil { - params["DestCidrIp"] = rule.IPNet.String() - } else { - params["DestCidrIp"] = "0.0.0.0/0" - } - _, err := self.ecsRequest("AuthorizeSecurityGroupEgress", params) - return err - } -} - -func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule secrules.SecurityRule) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["SecurityGroupId"] = secGrpId - params["NicType"] = string(IntranetNicType) - params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) - protocol := rule.Protocol - if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { - protocol = "all" - } - params["IpProtocol"] = protocol - if rule.PortStart < 1 && rule.PortEnd < 1 { - if protocol == "udp" || protocol == "tcp" { - params["PortRange"] = "1/65535" - } else { - params["PortRange"] = "-1/-1" - } - } - if rule.Action == secrules.SecurityRuleAllow { - params["Policy"] = "accept" - } else { - params["Policy"] = "drop" - } - params["Priority"] = fmt.Sprintf("%d", rule.Priority) - if rule.Direction == secrules.SecurityRuleIngress { - if rule.IPNet != nil { - params["SourceCidrIp"] = rule.IPNet.String() - } else { - params["SourceCidrIp"] = "0.0.0.0/0" - } - _, err := self.ecsRequest("RevokeSecurityGroup", params) - return err - } else { // rule.Direction == secrules.SecurityRuleEgress { - if rule.IPNet != nil { - params["DestCidrIp"] = rule.IPNet.String() - } else { - params["DestCidrIp"] = "0.0.0.0/0" - } - _, err := self.ecsRequest("RevokeSecurityGroupEgress", params) - return err - } -} - -func (self *SPermission) toRule() (cloudprovider.SecurityRule, error) { - rule := cloudprovider.SecurityRule{ - SecurityRule: secrules.SecurityRule{ - Action: secrules.SecurityRuleDeny, - Direction: secrules.DIR_IN, - Priority: self.Priority, - Description: self.Description, - PortStart: -1, - PortEnd: -1, - }, - } - if strings.ToLower(self.Policy) == "accept" { - rule.Action = secrules.SecurityRuleAllow - } - - cidr := self.SourceCidrIp - if self.Direction == "egress" { - rule.Direction = secrules.DIR_OUT - cidr = self.DestCidrIp - } - - rule.ParseCIDR(cidr) - - switch strings.ToLower(self.IpProtocol) { - case "tcp", "udp", "icmp": - rule.Protocol = strings.ToLower(self.IpProtocol) - case "all": - rule.Protocol = secrules.PROTO_ANY - default: - return rule, fmt.Errorf("unsupported protocal %s", self.IpProtocol) - } - - port, ports := "", strings.Split(self.PortRange, "/") - if ports[0] == ports[1] { - if ports[0] != "-1" { - port = ports[0] - } - } else if ports[0] != "1" && ports[1] != "65535" { - port = fmt.Sprintf("%s-%s", ports[0], ports[1]) - } - err := rule.ParsePorts(port) - if err != nil { - return rule, errors.Wrapf(err, "ParsePorts(%s)", port) - } - return rule, nil -} - -func (self *SRegion) AssignSecurityGroup(secgroupId, instanceId string) error { - return self.SetSecurityGroups([]string{secgroupId}, instanceId) -} - -func (self *SRegion) SetSecurityGroups(secgroupIds []string, instanceId string) error { - params := map[string]string{"InstanceId": instanceId} - for _, secgroupId := range secgroupIds { - params["SecurityGroupId"] = secgroupId - if _, err := self.ecsRequest("JoinSecurityGroup", params); err != nil { - return err - } - } - instance, err := self.GetInstance(instanceId) - if err != nil { - return err - } - for _, _secgroupId := range instance.SecurityGroupIds.SecurityGroupId { - if !utils.IsInStringArray(_secgroupId, secgroupIds) { - if err := self.leaveSecurityGroup(_secgroupId, instanceId); err != nil { - return err - } - } - } - return nil -} - -func (self *SRegion) leaveSecurityGroup(secgroupId, instanceId string) error { - params := map[string]string{"InstanceId": instanceId, "SecurityGroupId": secgroupId} - _, err := self.ecsRequest("LeaveSecurityGroup", params) - return err -} - -func (self *SRegion) DeleteSecurityGroup(secGrpId string) error { - params := make(map[string]string) - params["SecurityGroupId"] = secGrpId - - _, err := self.ecsRequest("DeleteSecurityGroup", params) - if err != nil { - log.Errorf("Delete security group fail %s", err) - return err - } - return nil -} - -func (self *SSecurityGroup) Delete() error { - return self.vpc.region.DeleteSecurityGroup(self.SecurityGroupId) -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - for _, rule := range append(inDels, outDels...) { - err := self.vpc.region.DelSecurityGroupRule(self.SecurityGroupId, rule.SecurityRule) - if err != nil { - return errors.Wrapf(err, "DelSecurityGroupRule(Name:%s priority: %d %s)", rule.Name, rule.Priority, rule.String()) - } - } - for _, rule := range append(inAdds, outAdds...) { - err := self.vpc.region.AddSecurityGroupRules(self.SecurityGroupId, rule.SecurityRule) - if err != nil { - return errors.Wrapf(err, "AddSecurityGroupRules(priority: %d %s)", rule.Priority, rule.String()) - } - } - return nil -} diff --git a/pkg/multicloud/apsara/shell/bucket.go b/pkg/multicloud/apsara/shell/bucket.go deleted file mode 100644 index aa59e983cb..0000000000 --- a/pkg/multicloud/apsara/shell/bucket.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "strconv" - - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - objectstore.S3Shell() - - type BucketOptions struct { - BUCKET string - } - shellutils.R(&BucketOptions{}, "bucket-show", "Show bucket", func(cli *apsara.SRegion, args *BucketOptions) error { - bucket, e := cli.GetBucket(args.BUCKET) - if e != nil { - return e - } - printObject(bucket) - return nil - }) - - type BucketSizeOptions struct { - } - shellutils.R(&BucketSizeOptions{}, "bucket-size", "Show bucket size", func(cli *apsara.SRegion, args *BucketSizeOptions) error { - buckets, err := cli.GetBuckets() - if err != nil { - return err - } - for i := range buckets { - department, _ := strconv.Atoi(buckets[i].Department) - size, _ := cli.GetBucketSize(buckets[i].Name, department) - capa, _ := cli.GetBucketCapacity(buckets[i].Name, department) - log.Infof("bucket %s size: %dMb capa: %dG", buckets[i].Name, size/1024/1024/1024, capa) - } - return nil - }) - -} diff --git a/pkg/multicloud/apsara/shell/dbinstance.go b/pkg/multicloud/apsara/shell/dbinstance.go deleted file mode 100644 index c975d20015..0000000000 --- a/pkg/multicloud/apsara/shell/dbinstance.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "strings" - - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceListOptions struct { - Id []string `help:"IDs of instances to show"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&DBInstanceListOptions{}, "dbinstance-list", "List dbintances", func(cli *apsara.SRegion, args *DBInstanceListOptions) error { - instances, total, e := cli.GetDBInstances(args.Id, args.Offset, args.Limit) - if e != nil { - return e - } - printList(instances, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type DBInstanceIdOptions struct { - ID string `help:"ID of instances to show"` - } - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-show", "Show dbintance", func(cli *apsara.SRegion, args *DBInstanceIdOptions) error { - instance, err := cli.GetDBInstanceDetail(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-open-public-connection", "Open dbintance public connection", func(cli *apsara.SRegion, args *DBInstanceIdOptions) error { - return cli.OpenPublicConnection(args.ID) - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-close-public-connection", "Close dbintance public connection", func(cli *apsara.SRegion, args *DBInstanceIdOptions) error { - return cli.ClosePublicConnection(args.ID) - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-delete", "Delete dbintance", func(cli *apsara.SRegion, args *DBInstanceIdOptions) error { - return cli.DeleteDBInstance(args.ID) - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-restart", "Restart dbintance", func(cli *apsara.SRegion, args *DBInstanceIdOptions) error { - return cli.RebootDBInstance(args.ID) - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-network-list", "Show dbintance network info", func(cli *apsara.SRegion, args *DBInstanceIdOptions) error { - networks, err := cli.GetDBInstanceNetInfo(args.ID) - if err != nil { - return err - } - printList(networks, 0, 0, 0, []string{}) - return nil - }) - - type DBInstanceRecoveryOptions struct { - ID string - TARGET string - BACKUP string - Databases []string - } - - shellutils.R(&DBInstanceRecoveryOptions{}, "dbinstance-recovery", "Recovery dbintance from backup", func(cli *apsara.SRegion, args *DBInstanceRecoveryOptions) error { - databases := map[string]string{} - for _, database := range args.Databases { - if len(database) > 0 { - dbInfo := strings.Split(database, ":") - if len(dbInfo) == 1 { - databases[dbInfo[0]] = dbInfo[0] - - } else if len(dbInfo) == 2 { - databases[dbInfo[0]] = dbInfo[1] - } else { - return fmt.Errorf("Invalid dbinfo: %s", database) - } - } - } - return cli.RecoveryDBInstanceFromBackup(args.ID, args.TARGET, args.BACKUP, databases) - }) - -} diff --git a/pkg/multicloud/apsara/shell/dbinstance_account.go b/pkg/multicloud/apsara/shell/dbinstance_account.go deleted file mode 100644 index 08731d38cd..0000000000 --- a/pkg/multicloud/apsara/shell/dbinstance_account.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - - type DBInstanceIdExtraOptions struct { - ID string `help:"ID of instances to show"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - - shellutils.R(&DBInstanceIdExtraOptions{}, "dbinstance-account-list", "List dbintance accounts", func(cli *apsara.SRegion, args *DBInstanceIdExtraOptions) error { - accounts, _, err := cli.GetDBInstanceAccounts(args.ID, args.Offset, args.Limit) - if err != nil { - return err - } - printList(accounts, 0, 0, 0, []string{}) - return nil - }) - - type DBInstanceAccountCreateOptions struct { - INSTANCE string `help:"ID of instances"` - NAME string `help:"account name"` - PASSWORD string `help:"account password"` - Desc string - } - - shellutils.R(&DBInstanceAccountCreateOptions{}, "dbinstance-account-create", "Create dbintance account", func(cli *apsara.SRegion, args *DBInstanceAccountCreateOptions) error { - return cli.CreateDBInstanceAccount(args.INSTANCE, args.NAME, args.PASSWORD, args.Desc) - }) - - type DBInstanceAccountDeleteOptions struct { - INSTANCE string - NAME string - } - - shellutils.R(&DBInstanceAccountDeleteOptions{}, "dbinstance-account-delete", "Delete dbintance account", func(cli *apsara.SRegion, args *DBInstanceAccountDeleteOptions) error { - return cli.DeleteDBInstanceAccount(args.INSTANCE, args.NAME) - }) - - type DBInstanceAccountResetOptions struct { - INSTANCE string `help:"ID of instances"` - NAME string `help:"account name"` - PASSWORD string `help:"account password"` - AccountType string `help:"account type" choices:"Normal|Super" default:"Normal"` - } - - shellutils.R(&DBInstanceAccountResetOptions{}, "dbinstance-account-reset-password", "Reset dbintance account password", func(cli *apsara.SRegion, args *DBInstanceAccountResetOptions) error { - return cli.ResetDBInstanceAccountPassword(args.INSTANCE, args.NAME, args.PASSWORD, args.AccountType) - }) - -} diff --git a/pkg/multicloud/apsara/shell/dbinstance_backup.go b/pkg/multicloud/apsara/shell/dbinstance_backup.go deleted file mode 100644 index 4ee2867c27..0000000000 --- a/pkg/multicloud/apsara/shell/dbinstance_backup.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceBackupJobListOptions struct { - INSTANCE string - JobId string - } - shellutils.R(&DBInstanceBackupJobListOptions{}, "dbinstance-backup-job-list", "Get dbinstance backup jobs", func(cli *apsara.SRegion, args *DBInstanceBackupJobListOptions) error { - jobs, err := cli.GetDBInstanceBackupJobs(args.INSTANCE, args.JobId) - if err != nil { - return err - } - printObject(jobs) - return nil - }) - - type DBInstanceBackupOptions struct { - INSTANCE string - BACKUP string - } - - shellutils.R(&DBInstanceBackupOptions{}, "dbinstance-backup-delete", "Delete dbinstance backup", func(cli *apsara.SRegion, args *DBInstanceBackupOptions) error { - return cli.DeleteDBInstanceBackup(args.INSTANCE, args.BACKUP) - }) - - shellutils.R(&DBInstanceBackupOptions{}, "dbinstance-backup-job-list", "Get dbinstance backup jobs", func(cli *apsara.SRegion, args *DBInstanceBackupOptions) error { - return cli.DeleteDBInstanceBackup(args.INSTANCE, args.BACKUP) - }) - - type DBInstanceIdExtraOptions struct { - ID string `help:"ID of instances to show"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - - shellutils.R(&DBInstanceIdExtraOptions{}, "dbinstance-backup-list", "List dbintance backups", func(cli *apsara.SRegion, args *DBInstanceIdExtraOptions) error { - backups, _, err := cli.GetDBInstanceBackups(args.ID, "", args.Offset, args.Limit) - if err != nil { - return err - } - printList(backups, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/apsara/shell/dbinstance_database.go b/pkg/multicloud/apsara/shell/dbinstance_database.go deleted file mode 100644 index 9fe1660542..0000000000 --- a/pkg/multicloud/apsara/shell/dbinstance_database.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - - type DBInstanceIdExtraOptions struct { - ID string `help:"ID of instances to show"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - - shellutils.R(&DBInstanceIdExtraOptions{}, "dbinstance-database-list", "List dbintance databases", func(cli *apsara.SRegion, args *DBInstanceIdExtraOptions) error { - databases, _, err := cli.GetDBInstanceDatabases(args.ID, "", args.Offset, args.Limit) - if err != nil { - return err - } - printList(databases, 0, 0, 0, []string{}) - return nil - }) - - type DBInstanceDatabaseCreateOptions struct { - INSTANCE string `help:"ID of instances"` - NAME string `help:"database name"` - CHARACTERSET string `help:"character set for database"` - Desc string - } - - shellutils.R(&DBInstanceDatabaseCreateOptions{}, "dbinstance-database-create", "Create dbintance database", func(cli *apsara.SRegion, args *DBInstanceDatabaseCreateOptions) error { - return cli.CreateDBInstanceDatabae(args.INSTANCE, args.CHARACTERSET, args.NAME, args.Desc) - }) - - type DBInstanceDatabaseDeleteOptions struct { - INSTANCE string - NAME string - } - - shellutils.R(&DBInstanceDatabaseDeleteOptions{}, "dbinstance-database-delete", "Delete dbintance database", func(cli *apsara.SRegion, args *DBInstanceDatabaseDeleteOptions) error { - return cli.DeleteDBInstanceDatabase(args.INSTANCE, args.NAME) - }) - -} diff --git a/pkg/multicloud/apsara/shell/disk.go b/pkg/multicloud/apsara/shell/disk.go deleted file mode 100644 index c7dfaf0ee0..0000000000 --- a/pkg/multicloud/apsara/shell/disk.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "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 *apsara.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 { - ID string `help:"Instance ID"` - } - shellutils.R(&DiskDeleteOptions{}, "disk-delete", "List disks", func(cli *apsara.SRegion, args *DiskDeleteOptions) error { - e := cli.DeleteDisk(args.ID) - if e != nil { - return e - } - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/doc.go b/pkg/multicloud/apsara/shell/doc.go deleted file mode 100644 index 6aef15a3f8..0000000000 --- a/pkg/multicloud/apsara/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/apsara/shell" diff --git a/pkg/multicloud/apsara/shell/eip.go b/pkg/multicloud/apsara/shell/eip.go deleted file mode 100644 index 235ace3b0a..0000000000 --- a/pkg/multicloud/apsara/shell/eip.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - AssociateId string `help:"Id of associate resource"` - Offset int `help:"List offset"` - Limit int `help:"List limit"` - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *apsara.SRegion, args *EipListOptions) error { - eips, total, e := cli.GetEips("", args.AssociateId, args.Offset, args.Limit) - if e != nil { - return e - } - printList(eips, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type EipAllocateOptions struct { - BW int `help:"Bandwidth limit in Mbps"` - ResourceGroupId string `help:"Resource group Id"` - } - shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *apsara.SRegion, args *EipAllocateOptions) error { - eip, err := cli.AllocateEIP(args.BW, apsara.InternetChargeByTraffic, args.ResourceGroupId) - 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 *apsara.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 *apsara.SRegion, args *EipAssociateOptions) error { - err := cli.AssociateEip(args.ID, args.INSTANCE) - return err - }) - shellutils.R(&EipAssociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *apsara.SRegion, args *EipAssociateOptions) error { - err := cli.DissociateEip(args.ID, args.INSTANCE) - return err - }) -} diff --git a/pkg/multicloud/apsara/shell/elasticcache.go b/pkg/multicloud/apsara/shell/elasticcache.go deleted file mode 100644 index 1064be910f..0000000000 --- a/pkg/multicloud/apsara/shell/elasticcache.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElasticcacheListOptions struct { - } - shellutils.R(&ElasticcacheListOptions{}, "elasticcache-list", "List elasticcaches", func(cli *apsara.SRegion, args *ElasticcacheListOptions) error { - instances, e := cli.GetElasticCaches(nil) - if e != nil { - return e - } - printList(instances, len(instances), 0, 0, []string{}) - return nil - }) - - type ElasticcacheIdOptions struct { - ID string `help:"ID of instances to show"` - } - shellutils.R(&ElasticcacheIdOptions{}, "elasticcache-show", "Show elasticcache", func(cli *apsara.SRegion, args *ElasticcacheIdOptions) error { - instance, err := cli.GetElasticCacheById(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - type ElasticcacheBackupsListOptions struct { - ID string `help:"ID of instances to show"` - StartTime string `help:"backup start time. format: 2019-03-11T10:00Z"` - EndTime string `help:"backup end time. format: 2019-03-11T10:00Z"` - } - - shellutils.R(&ElasticcacheBackupsListOptions{}, "elasticcache-backup-list", "List elasticcache backups", func(cli *apsara.SRegion, args *ElasticcacheBackupsListOptions) error { - backups, err := cli.GetElasticCacheBackups(args.ID, args.StartTime, args.EndTime) - if err != nil { - return err - } - printList(backups, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElasticcacheIdOptions{}, "elasticcache-parameter-list", "List elasticcache parameters", func(cli *apsara.SRegion, args *ElasticcacheIdOptions) error { - parameters, err := cli.GetElasticCacheParameters(args.ID) - if err != nil { - return err - } - printList(parameters, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElasticcacheIdOptions{}, "elasticcache-account-list", "List elasticcache accounts", func(cli *apsara.SRegion, args *ElasticcacheIdOptions) error { - accounts, err := cli.GetElasticCacheAccounts(args.ID) - if err != nil { - return err - } - printList(accounts, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElasticcacheIdOptions{}, "elasticcache-acl-list", "List elasticcache security ip rules", func(cli *apsara.SRegion, args *ElasticcacheIdOptions) error { - acls, err := cli.GetElasticCacheAcls(args.ID) - if err != nil { - return err - } - printList(acls, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/image.go b/pkg/multicloud/apsara/shell/image.go deleted file mode 100644 index 178f8f3761..0000000000 --- a/pkg/multicloud/apsara/shell/image.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "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:"system|self|others|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 *apsara.SRegion, args *ImageListOptions) error { - images, total, e := cli.GetImages(apsara.ImageStatusType(args.Status), apsara.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 ImageShowOptions struct { - ID string `help:"image ID"` - } - shellutils.R(&ImageShowOptions{}, "image-show", "Show image", func(cli *apsara.SRegion, args *ImageShowOptions) error { - img, err := cli.GetImage(args.ID) - if err != nil { - return err - } - printObject(img) - return nil - }) - - type ImageDeleteOptions struct { - ID string `help:"ID or Name to delete"` - } - shellutils.R(&ImageDeleteOptions{}, "image-delete", "Delete image", func(cli *apsara.SRegion, args *ImageDeleteOptions) error { - return cli.DeleteImage(args.ID) - }) - - type ImageCreateOptions struct { - SNAPSHOT string `help:"Snapshot id"` - NAME string `help:"Image name"` - Desc string `help:"Image desc"` - } - shellutils.R(&ImageCreateOptions{}, "image-create", "Create image", func(cli *apsara.SRegion, args *ImageCreateOptions) error { - imageId, err := cli.CreateImage(args.SNAPSHOT, args.NAME, args.Desc) - if err != nil { - return err - } - fmt.Println(imageId) - return nil - }) - - type ImageExportOptions struct { - ID string `help:"ID or Name to export"` - BUCKET string `help:"Bucket name"` - } - - shellutils.R(&ImageExportOptions{}, "image-export", "Export image", func(cli *apsara.SRegion, args *ImageExportOptions) error { - task, err := cli.ExportImage(args.ID, args.BUCKET) - if err != nil { - return err - } - printObject(task) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/instance.go b/pkg/multicloud/apsara/shell/instance.go deleted file mode 100644 index c85d9e6f93..0000000000 --- a/pkg/multicloud/apsara/shell/instance.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "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 *apsara.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 InstanceCreateOptions 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"` - VSWITCH string `help:"Vswitch ID"` - PASSWD string `help:"password"` - PublicKey string `help:"PublicKey"` - } - shellutils.R(&InstanceCreateOptions{}, "instance-create", "Create a instance", func(cli *apsara.SRegion, args *InstanceCreateOptions) error { - instance, e := cli.CreateInstanceSimple(args.NAME, args.IMAGE, args.CPU, args.MEMORYGB, args.STORAGE, args.Disk, args.VSWITCH, args.PASSWD, args.PublicKey) - if e != nil { - return e - } - printObject(instance) - return nil - }) - - type InstanceDiskOperationOptions struct { - ID string `help:"instance ID"` - DISK string `help:"disk ID"` - } - - shellutils.R(&InstanceDiskOperationOptions{}, "instance-attach-disk", "Attach a disk to instance", func(cli *apsara.SRegion, args *InstanceDiskOperationOptions) error { - err := cli.AttachDisk(args.ID, args.DISK) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&InstanceDiskOperationOptions{}, "instance-detach-disk", "Detach a disk to instance", func(cli *apsara.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 *apsara.SRegion, args *InstanceOperationOptions) error { - err := cli.StartVM(args.ID) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&InstanceOperationOptions{}, "instance-auto-renew-info", "Show instance auto renew info", func(cli *apsara.SRegion, args *InstanceOperationOptions) error { - info, err := cli.GetInstanceAutoRenewAttribute(args.ID) - if err != nil { - return err - } - printObject(info) - return nil - }) - - shellutils.R(&InstanceOperationOptions{}, "instance-eip-convert", "Convert instance public ip to eip", func(cli *apsara.SRegion, args *InstanceOperationOptions) error { - err := cli.ConvertPublicIpToEip(args.ID) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&InstanceOperationOptions{}, "instance-vnc", "Get a instance VNC url", func(cli *apsara.SRegion, args *InstanceOperationOptions) error { - url, err := cli.GetInstanceVNCUrl(args.ID) - if err != nil { - return err - } - fmt.Println(url) - 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 *apsara.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 *apsara.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 *apsara.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"` - Password string `help:"pasword"` - Keypair string `help:"keypair name"` - Size int `help:"system disk size in GB"` - } - - shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *apsara.SRegion, args *InstanceRebuildRootOptions) error { - diskID, err := cli.ReplaceSystemDisk(args.ID, args.Image, args.Password, args.Keypair, args.Size) - if err != nil { - return err - } - fmt.Printf("New diskID is %s", diskID) - return nil - }) - - type InstanceChangeConfigOptions struct { - ID string `help:"instance ID"` - InstanceTypeId string `help:"instance type"` - Disk []int `help:"Data disk sizes int GB"` - } - - shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Deploy keypair/password to a stopped virtual server", func(cli *apsara.SRegion, args *InstanceChangeConfigOptions) error { - instance, e := cli.GetInstance(args.ID) - if e != nil { - return e - } - - err := cli.ChangeVMConfig2(instance.ZoneId, args.ID, args.InstanceTypeId, nil) - if err != nil { - return err - } - return nil - }) - - type InstanceUpdatePasswordOptions struct { - ID string `help:"Instance ID"` - PASSWD string `help:"new password"` - } - shellutils.R(&InstanceUpdatePasswordOptions{}, "instance-update-password", "Update instance password", func(cli *apsara.SRegion, args *InstanceUpdatePasswordOptions) error { - err := cli.UpdateInstancePassword(args.ID, args.PASSWD) - return err - }) - - type InstanceSetAutoRenewOptions struct { - ID string `help:"Instance ID"` - AutoRenew bool `help:"Is auto renew instance"` - Duration string - } - - shellutils.R(&InstanceSetAutoRenewOptions{}, "instance-set-auto-renew", "Set instance auto renew", func(cli *apsara.SRegion, args *InstanceSetAutoRenewOptions) error { - return cli.SetInstanceAutoRenew(args.ID, args.AutoRenew) - }) - - type InstanceUpdateNameOptions struct { - ID string `help:"Instance ID"` - NAME string `help:"new name"` - } - shellutils.R(&InstanceUpdateNameOptions{}, "instance-update-name", "Update instance name", func(cli *apsara.SRegion, args *InstanceUpdateNameOptions) error { - return cli.UpdateVM(args.ID, args.NAME) - }) - -} diff --git a/pkg/multicloud/apsara/shell/instancetype.go b/pkg/multicloud/apsara/shell/instancetype.go deleted file mode 100644 index 8e9aebdeb9..0000000000 --- a/pkg/multicloud/apsara/shell/instancetype.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceTypeListOptions struct { - } - shellutils.R(&InstanceTypeListOptions{}, "instance-type-list", "List intance types", func(cli *apsara.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 *apsara.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 - }) -} diff --git a/pkg/multicloud/apsara/shell/ipv6_gateway.go b/pkg/multicloud/apsara/shell/ipv6_gateway.go deleted file mode 100644 index 380d7e8476..0000000000 --- a/pkg/multicloud/apsara/shell/ipv6_gateway.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type IPv6GatewayListOptions struct { - VpcId string - PageSize int `default:"10"` - PageNumber int `default:"1"` - } - shellutils.R(&IPv6GatewayListOptions{}, "ipv6-gateway-list", "List IPv6 gateways", func(cli *apsara.SRegion, args *IPv6GatewayListOptions) error { - gateways, _, err := cli.GetIPv6Gateways(args.VpcId, args.PageNumber, args.PageSize) - if err != nil { - return err - } - printList(gateways, 0, 0, 0, []string{}) - return nil - }) - - type IPv6GatewayIdOptions struct { - ID string - } - - shellutils.R(&IPv6GatewayIdOptions{}, "ipv6-gateway-show", "Show IPv6 gateway", func(cli *apsara.SRegion, args *IPv6GatewayIdOptions) error { - gateway, err := cli.GetIPv6Gateway(args.ID) - if err != nil { - return err - } - printObject(gateway) - return nil - }) - -} diff --git a/pkg/multicloud/apsara/shell/keypair.go b/pkg/multicloud/apsara/shell/keypair.go deleted file mode 100644 index c1e523ea82..0000000000 --- a/pkg/multicloud/apsara/shell/keypair.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "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 *apsara.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 *apsara.SRegion, args *KeyPairImportOptions) error { - keypair, err := cli.ImportKeypair(args.NAME, args.PUBKEY) - if err != nil { - return err - } - printObject(keypair) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/loadbalancer.go b/pkg/multicloud/apsara/shell/loadbalancer.go deleted file mode 100644 index 1effd9f3e8..0000000000 --- a/pkg/multicloud/apsara/shell/loadbalancer.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerListOptions struct { - Ids []string `help:"Loadbalancer ids"` - } - shellutils.R(&LoadbalancerListOptions{}, "lb-list", "List loadbalancers", func(cli *apsara.SRegion, args *LoadbalancerListOptions) error { - lbs, err := cli.GetLoadbalancers(args.Ids) - if err != nil { - return err - } - printList(lbs, len(lbs), 0, 0, []string{}) - return nil - }) - - type LoadbalancerOptions struct { - ID string `help:"ID of loadbalancer"` - } - shellutils.R(&LoadbalancerOptions{}, "lb-show", "Show loadbalancer", func(cli *apsara.SRegion, args *LoadbalancerOptions) error { - lb, err := cli.GetLoadbalancerDetail(args.ID) - if err != nil { - return err - } - printObject(lb) - return nil - }) - -} diff --git a/pkg/multicloud/apsara/shell/loadbalanceracl.go b/pkg/multicloud/apsara/shell/loadbalanceracl.go deleted file mode 100644 index 72d21ddd2f..0000000000 --- a/pkg/multicloud/apsara/shell/loadbalanceracl.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerACLListOptions struct { - } - shellutils.R(&LoadbalancerACLListOptions{}, "lb-acl-list", "List loadbalanceAcls", func(cli *apsara.SRegion, args *LoadbalancerACLListOptions) error { - acls, err := cli.GetLoadBalancerAcls() - if err != nil { - return err - } - printList(acls, len(acls), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/loadbalancerbackend.go b/pkg/multicloud/apsara/shell/loadbalancerbackend.go deleted file mode 100644 index a8f99fb6dc..0000000000 --- a/pkg/multicloud/apsara/shell/loadbalancerbackend.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerBackendListOptions struct { - GROUPID string `help:"LoadbalancerBackendgroup ID"` - } - shellutils.R(&LoadbalancerBackendListOptions{}, "lb-backend-list", "List loadbalanceBackends", func(cli *apsara.SRegion, args *LoadbalancerBackendListOptions) error { - backends, err := cli.GetLoadbalancerBackends(args.GROUPID) - if err != nil { - return err - } - printList(backends, len(backends), 0, 0, []string{}) - return nil - }) - - shellutils.R(&LoadbalancerBackendListOptions{}, "lb-master-slave-backend-list", "List loadbalanceMasterSlaveBackends", func(cli *apsara.SRegion, args *LoadbalancerBackendListOptions) error { - backends, err := cli.GetLoadbalancerMasterSlaveBackends(args.GROUPID) - if err != nil { - return err - } - printList(backends, len(backends), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/loadbalancerbackendgroup.go b/pkg/multicloud/apsara/shell/loadbalancerbackendgroup.go deleted file mode 100644 index db519bc18d..0000000000 --- a/pkg/multicloud/apsara/shell/loadbalancerbackendgroup.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerBackendgroupListOptions struct { - ID string `help:"ID of Loadbalancer"` - } - shellutils.R(&LoadbalancerBackendgroupListOptions{}, "lb-backendgroup-list", "List loadbalancerBackendgroups", func(cli *apsara.SRegion, args *LoadbalancerBackendgroupListOptions) error { - backendgroups, err := cli.GetLoadbalancerBackendgroups(args.ID) - if err != nil { - return err - } - printList(backendgroups, len(backendgroups), 0, 0, []string{}) - return nil - }) - - shellutils.R(&LoadbalancerBackendgroupListOptions{}, "lb-master-slave-backendgroup-list", "List loadbalancerMasterSlaveBackendgroups", func(cli *apsara.SRegion, args *LoadbalancerBackendgroupListOptions) error { - backendgroups, err := cli.GetLoadbalancerMasterSlaveBackendgroups(args.ID) - if err != nil { - return err - } - printList(backendgroups, len(backendgroups), 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/apsara/shell/loadbalancercertificate.go b/pkg/multicloud/apsara/shell/loadbalancercertificate.go deleted file mode 100644 index 3fa87366ca..0000000000 --- a/pkg/multicloud/apsara/shell/loadbalancercertificate.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerServerCertificateListOptions struct { - } - shellutils.R(&LoadbalancerServerCertificateListOptions{}, "lb-server-certificate-list", "List ServerCertificates", func(cli *apsara.SRegion, args *LoadbalancerServerCertificateListOptions) error { - serverCertificate, err := cli.GetLoadbalancerServerCertificates() - if err != nil { - return err - } - printList(serverCertificate, len(serverCertificate), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/loadbalancerlistener.go b/pkg/multicloud/apsara/shell/loadbalancerlistener.go deleted file mode 100644 index 1d28af9444..0000000000 --- a/pkg/multicloud/apsara/shell/loadbalancerlistener.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerListenerListOptions struct { - ID string `help:"ID of loadbalancer"` - PORT int `help:"PORT of listenerPort"` - } - shellutils.R(&LoadbalancerListenerListOptions{}, "lb-http-listener-show", "Show LoadbalancerHTTPListener", func(cli *apsara.SRegion, args *LoadbalancerListenerListOptions) error { - listener, err := cli.GetLoadbalancerHTTPListener(args.ID, args.PORT) - if err != nil { - return err - } - printObject(listener) - return nil - }) - - shellutils.R(&LoadbalancerListenerListOptions{}, "lb-https-listener-show", "Show LoadbalancerHTTPSListener", func(cli *apsara.SRegion, args *LoadbalancerListenerListOptions) error { - listener, err := cli.GetLoadbalancerHTTPSListener(args.ID, args.PORT) - if err != nil { - return err - } - printObject(listener) - return nil - }) - - shellutils.R(&LoadbalancerListenerListOptions{}, "lb-tcp-listener-show", "Show LoadbalancerTCPListener", func(cli *apsara.SRegion, args *LoadbalancerListenerListOptions) error { - listener, err := cli.GetLoadbalancerTCPListener(args.ID, args.PORT) - if err != nil { - return err - } - printObject(listener) - return nil - }) - - shellutils.R(&LoadbalancerListenerListOptions{}, "lb-udp-listener-show", "Show LoadbalancerUDPListener", func(cli *apsara.SRegion, args *LoadbalancerListenerListOptions) error { - listener, err := cli.GetLoadbalancerUDPListener(args.ID, args.PORT) - if err != nil { - return err - } - printObject(listener) - return nil - }) - -} diff --git a/pkg/multicloud/apsara/shell/loadbalancerlistenerrule.go b/pkg/multicloud/apsara/shell/loadbalancerlistenerrule.go deleted file mode 100644 index c8c3f7cb66..0000000000 --- a/pkg/multicloud/apsara/shell/loadbalancerlistenerrule.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerListenerRuleListOptions struct { - ID string `help:"ID of loadbalaner"` - PORT int `help:"Port of listener port"` - } - shellutils.R(&LoadbalancerListenerRuleListOptions{}, "lb-listener-rule-list", "List LoadbalancerListenerRules", func(cli *apsara.SRegion, args *LoadbalancerListenerRuleListOptions) error { - rules, err := cli.GetLoadbalancerListenerRules(args.ID, args.PORT) - if err != nil { - return err - } - printList(rules, len(rules), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/monitor.go b/pkg/multicloud/apsara/shell/monitor.go deleted file mode 100644 index ae42322750..0000000000 --- a/pkg/multicloud/apsara/shell/monitor.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics", func(cli *apsara.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric: %s %s %s", metrics[i].Id, metrics[i].MetricType, metrics[i].Unit) - printList(metrics[i].Values, len(metrics[i].Values), 0, 0, []string{}) - } - return nil - }) - -} diff --git a/pkg/multicloud/apsara/shell/natgateway.go b/pkg/multicloud/apsara/shell/natgateway.go deleted file mode 100644 index 6f743e5179..0000000000 --- a/pkg/multicloud/apsara/shell/natgateway.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NatGatewayListOptions struct { - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&NatGatewayListOptions{}, "natgateway-list", "List NAT gateways", func(cli *apsara.SRegion, args *NatGatewayListOptions) error { - gws, total, e := cli.GetNatGateways("", "", args.Offset, args.Limit) - if e != nil { - return e - } - printList(gws, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type NatSEntryListOptions struct { - ID string `help:"SNat Table ID"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&NatSEntryListOptions{}, "snat-entry-list", "List SNAT entries", func(cli *apsara.SRegion, args *NatSEntryListOptions) error { - entries, total, e := cli.GetSNATEntries(args.ID, args.Offset, args.Limit) - if e != nil { - return e - } - printList(entries, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type NatDEntryListOptions struct { - ID string `help:"DNat Table ID"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&NatDEntryListOptions{}, "dnat-entry-list", "List DNAT entries", func(cli *apsara.SRegion, args *NatDEntryListOptions) error { - entries, total, e := cli.GetForwardTableEntries(args.ID, args.Offset, args.Limit) - if e != nil { - return e - } - printList(entries, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type SCreateDNatOptions struct { - GatewayID string `help:"Nat Gateway ID" positional:"true"` - Protocol string `help:"Protocol(tcp/udp)" positional:"true"` - ExternalIP string `help:"External IP" positional:"true"` - ExternalPort int `help:"External Port" positional:"true"` - InternalIP string `help:"Internal IP" positional:"true"` - InternalPort int `help:"Nat Gateway ID" positional:"true"` - } - shellutils.R(&SCreateDNatOptions{}, "dnat-entry-create", "Create DNAT entry", func(region *apsara.SRegion, args *SCreateDNatOptions) error { - rule := cloudprovider.SNatDRule{ - Protocol: args.Protocol, - ExternalIP: args.ExternalIP, - ExternalPort: args.ExternalPort, - InternalIP: args.InternalIP, - InternalPort: args.InternalPort, - } - dnat, err := region.CreateForwardTableEntry(rule, args.GatewayID) - if err != nil { - return err - } - printObject(dnat) - return nil - }) - - type SCreateSNatOptions struct { - GatewayID string `help:"Nat Gateway ID" positional:"true"` - SourceCIDR string `help:"Source cidr" positional:"true"` - ExternalIP string `help:"External IP" positional:"true"` - } - shellutils.R(&SCreateSNatOptions{}, "snat-entry-create", "Create SNAT entry", func(region *apsara.SRegion, args *SCreateSNatOptions) error { - rule := cloudprovider.SNatSRule{ - SourceCIDR: args.SourceCIDR, - ExternalIP: args.ExternalIP, - } - snat, err := region.CreateSNATTableEntry(rule, args.GatewayID) - if err != nil { - return err - } - printObject(snat) - return nil - }) - - type SShowSNatOptions struct { - TableID string `help:"SNat Table ID" positional:"true"` - NatID string `help:"SNat Entry ID" positional:"true"` - } - shellutils.R(&SShowSNatOptions{}, "snat-entry-show", "show SNAT entry", func(region *apsara.SRegion, args *SShowSNatOptions) error { - snat, err := region.GetSNATEntry(args.TableID, args.NatID) - if err != nil { - return err - } - printObject(snat) - return nil - }) - - type SShowDNatOptions struct { - TableID string `help:"DNat Table ID" positional:"true"` - NatID string `help:"DNat Entry ID" positional:"true"` - } - shellutils.R(&SShowDNatOptions{}, "dnat-entry-show", "show SNAT entry", func(region *apsara.SRegion, args *SShowDNatOptions) error { - dnat, err := region.GetForwardTableEntry(args.TableID, args.NatID) - if err != nil { - return err - } - printObject(dnat) - return nil - }) - - type SDeleteSNatOptions struct { - TableID string `help:"DNat Table ID" positional:"true"` - NatID string `help:"SNat Entry ID" positional:"true"` - } - shellutils.R(&SDeleteSNatOptions{}, "snat-entry-delete", "Delete SNAT entry", func(region *apsara.SRegion, args *SDeleteSNatOptions) error { - err := region.DeleteSnatEntry(args.TableID, args.NatID) - if err != nil { - return err - } - return nil - }) - - type SDeleteDNatOptions struct { - TableID string `help:"DNat Table ID" positional:"true"` - NatID string `help:"DNat Entry ID" positional:"true"` - } - shellutils.R(&SDeleteDNatOptions{}, "dnat-entry-delete", "Delete DNAT entry", func(region *apsara.SRegion, args *SDeleteDNatOptions) error { - err := region.DeleteForwardTableEntry(args.TableID, args.NatID) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/networkinterface.go b/pkg/multicloud/apsara/shell/networkinterface.go deleted file mode 100644 index 708f5f11ef..0000000000 --- a/pkg/multicloud/apsara/shell/networkinterface.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkInterfaceListOptions struct { - InstanceId string `help:"Id or instance"` - Offset int - Limit int - } - shellutils.R(&NetworkInterfaceListOptions{}, "network-interface-list", "List networkinterfaces", func(cli *apsara.SRegion, args *NetworkInterfaceListOptions) error { - interfaces, total, err := cli.GetNetworkInterfaces(args.InstanceId, args.Offset, args.Limit) - if err != nil { - return err - } - printList(interfaces, total, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/printutils.go b/pkg/multicloud/apsara/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/apsara/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/apsara/shell/quota.go b/pkg/multicloud/apsara/shell/quota.go deleted file mode 100644 index 9b4e477b2f..0000000000 --- a/pkg/multicloud/apsara/shell/quota.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type QuotaListOptions struct { - } - shellutils.R(&QuotaListOptions{}, "quota-list", "List quota", func(cli *apsara.SRegion, args *QuotaListOptions) error { - quotas, err := cli.GetQuotas() - if err != nil { - return err - } - printList(quotas, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/ram_group.go b/pkg/multicloud/apsara/shell/ram_group.go deleted file mode 100644 index 51ef4e80ae..0000000000 --- a/pkg/multicloud/apsara/shell/ram_group.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CloudgroupCreateOptions struct { - NAME string - Comments string - } - - shellutils.R(&CloudgroupCreateOptions{}, "cloud-group-create", "Create Cloud group", func(cli *apsara.SRegion, args *CloudgroupCreateOptions) error { - group, err := cli.GetClient().CreateGroup(args.NAME, args.Comments) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type CloudgroupListOptions struct { - Offset string - Limit int - } - - shellutils.R(&CloudgroupListOptions{}, "cloud-group-list", "List Cloud groups", func(cli *apsara.SRegion, args *CloudgroupListOptions) error { - groups, err := cli.GetClient().ListGroups(args.Offset, args.Limit) - if err != nil { - return err - } - printList(groups.Groups.Group, 0, 0, 0, nil) - return nil - }) - - type CloudgroupDeleteOptions struct { - NAME string - } - - shellutils.R(&CloudgroupDeleteOptions{}, "cloud-group-delete", "Delete Cloud group", func(cli *apsara.SRegion, args *CloudgroupDeleteOptions) error { - return cli.GetClient().DeleteGroup(args.NAME) - }) - - type GroupExtListOptions struct { - GROUP string - Offset string - Limit int - } - shellutils.R(&GroupExtListOptions{}, "cloud-group-user-list", "List Cloud group users", func(cli *apsara.SRegion, args *GroupExtListOptions) error { - users, err := cli.GetClient().ListUsersForGroup(args.GROUP, args.Offset, args.Limit) - if err != nil { - return err - } - printList(users.Users.User, 0, 0, 0, nil) - return nil - }) - - type GroupUserOptions struct { - GROUP string - USER string - } - - shellutils.R(&GroupUserOptions{}, "cloud-group-remove-user", "Remove user from group", func(cli *apsara.SRegion, args *GroupUserOptions) error { - return cli.GetClient().RemoveUserFromGroup(args.GROUP, args.USER) - }) - - shellutils.R(&GroupUserOptions{}, "cloud-group-add-user", "Add user to group", func(cli *apsara.SRegion, args *GroupUserOptions) error { - return cli.GetClient().AddUserToGroup(args.GROUP, args.USER) - }) - - shellutils.R(&GroupExtListOptions{}, "cloud-group-policy-list", "List Cloud group policies", func(cli *apsara.SRegion, args *GroupExtListOptions) error { - policies, err := cli.GetClient().ListPoliciesForGroup(args.GROUP) - if err != nil { - return err - } - printList(policies, 0, 0, 0, nil) - return nil - }) - - type GroupPolicyOptions struct { - GROUP string - PolicyType string `default:"System" choices:"System|Custom"` - POLICY string - } - - shellutils.R(&GroupPolicyOptions{}, "cloud-group-attach-policy", "Attach policy for group", func(cli *apsara.SRegion, args *GroupPolicyOptions) error { - return cli.GetClient().AttachPolicyToGroup(args.PolicyType, args.POLICY, args.GROUP) - }) - - shellutils.R(&GroupPolicyOptions{}, "cloud-group-detach-policy", "Detach policy from group", func(cli *apsara.SRegion, args *GroupPolicyOptions) error { - return cli.GetClient().DetachPolicyFromGroup(args.PolicyType, args.POLICY, args.GROUP) - }) - -} diff --git a/pkg/multicloud/apsara/shell/ram_policy.go b/pkg/multicloud/apsara/shell/ram_policy.go deleted file mode 100644 index 2319f280e6..0000000000 --- a/pkg/multicloud/apsara/shell/ram_policy.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type GetPolicyOptions struct { - POLICYTYPE string - POLICYNAME string - } - shellutils.R(&GetPolicyOptions{}, "cloud-policy-show", "Show ram policy", func(cli *apsara.SRegion, args *GetPolicyOptions) error { - policy, err := cli.GetClient().GetPolicy(args.POLICYTYPE, args.POLICYNAME) - if err != nil { - return err - } - printObject(policy) - return nil - }) - - type DeletePolicyOptions struct { - POLICYTYPE string - POLICYNAME string - } - shellutils.R(&DeletePolicyOptions{}, "cloud-policy-delete", "Delete policy", func(cli *apsara.SRegion, args *DeletePolicyOptions) error { - return cli.GetClient().DeletePolicy(args.POLICYTYPE, args.POLICYNAME) - }) - - type PolicyListOptions struct { - PolicyType string `choices:"System|Custom"` - Offset string - Limit int - } - - shellutils.R(&PolicyListOptions{}, "cloud-policy-list", "List cloud policies", func(cli *apsara.SRegion, args *PolicyListOptions) error { - policies, err := cli.GetClient().ListPolicies(args.PolicyType, args.Offset, args.Limit) - if err != nil { - return err - } - printList(policies.Policies.Policy, 0, 0, 0, nil) - return nil - }) - - type PolicyCreateOptions struct { - NAME string - DOCUMENT string - Desc string - } - - shellutils.R(&PolicyCreateOptions{}, "cloud-policy-create", "Create ram policy", func(cli *apsara.SRegion, args *PolicyCreateOptions) error { - policy, err := cli.GetClient().CreatePolicy(args.NAME, args.DOCUMENT, args.Desc) - if err != nil { - return err - } - printObject(policy) - return nil - }) - - type PolicyCreateVersionOptions struct { - NAME string - DOCUMENT string - IsDefault bool - } - - shellutils.R(&PolicyCreateVersionOptions{}, "cloud-policy-version-create", "Create ram policy version", func(cli *apsara.SRegion, args *PolicyCreateVersionOptions) error { - return cli.GetClient().CreatePolicyVersion(args.NAME, args.DOCUMENT, args.IsDefault) - }) - -} diff --git a/pkg/multicloud/apsara/shell/ram_role.go b/pkg/multicloud/apsara/shell/ram_role.go deleted file mode 100644 index 8aff5f041b..0000000000 --- a/pkg/multicloud/apsara/shell/ram_role.go +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ListRolesOptions struct { - Offset string - Limit int - } - shellutils.R(&ListRolesOptions{}, "cloud-role-list", "List ram roles", func(cli *apsara.SRegion, args *ListRolesOptions) error { - roles, err := cli.GetClient().ListRoles(args.Offset, args.Limit) - if err != nil { - return err - } - printList(roles.Roles.Role, 0, 0, 0, []string{}) - return nil - }) - - type GetRoleOptions struct { - ROLENAME string - } - shellutils.R(&GetRoleOptions{}, "cloud-role-show", "Show ram role", func(cli *apsara.SRegion, args *GetRoleOptions) error { - role, err := cli.GetClient().GetRole(args.ROLENAME) - if err != nil { - return err - } - printObject(role) - return nil - }) - - type RolePolicyOptions struct { - ROLENAME string - POLICYNAME string - POLICYTYPE string `choices:"Custom|System"` - } - - shellutils.R(&RolePolicyOptions{}, "cloud-role-attach-policy", "Attach policy for role", func(cli *apsara.SRegion, args *RolePolicyOptions) error { - return cli.GetClient().AttachPolicy2Role(args.POLICYTYPE, args.POLICYNAME, args.ROLENAME) - }) - - shellutils.R(&RolePolicyOptions{}, "cloud-role-detach-policy", "Detach policy from role", func(cli *apsara.SRegion, args *RolePolicyOptions) error { - return cli.GetClient().DetachPolicyFromRole(args.POLICYTYPE, args.POLICYNAME, args.ROLENAME) - }) - - type RolePolicyListOptions struct { - ROLE string - } - - shellutils.R(&RolePolicyListOptions{}, "cloud-role-policy-list", "List cloud role policies", func(cli *apsara.SRegion, args *RolePolicyListOptions) error { - policies, err := cli.GetClient().ListPoliciesForRole(args.ROLE) - if err != nil { - return err - } - printList(policies, 0, 0, 0, nil) - return nil - }) - - type DeleteRoleOptions struct { - NAME string - } - shellutils.R(&DeleteRoleOptions{}, "cloud-role-delete", "Delete role", func(cli *apsara.SRegion, args *DeleteRoleOptions) error { - return cli.GetClient().DeleteRole(args.NAME) - }) - - shellutils.R(&ListRolesOptions{}, "enable-image-import", "Enable image import privilege", func(cli *apsara.SRegion, args *ListRolesOptions) error { - return cli.GetClient().EnableImageImport() - }) - - shellutils.R(&ListRolesOptions{}, "enable-image-export", "Enable image export privilege", func(cli *apsara.SRegion, args *ListRolesOptions) error { - return cli.GetClient().EnableImageExport() - }) - - type CallerShowOptions struct { - } - - shellutils.R(&CallerShowOptions{}, "caller-show", "Show caller info", func(cli *apsara.SRegion, args *CallerShowOptions) error { - caller, err := cli.GetClient().GetCallerIdentity() - if err != nil { - return err - } - printObject(caller) - return nil - }) - -} diff --git a/pkg/multicloud/apsara/shell/ram_user.go b/pkg/multicloud/apsara/shell/ram_user.go deleted file mode 100644 index 990860b2d9..0000000000 --- a/pkg/multicloud/apsara/shell/ram_user.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClouduserCreateOptions struct { - NAME string - MobilePhone string - Comments string - Email string - } - - shellutils.R(&ClouduserCreateOptions{}, "cloud-user-create", "Create Cloud user", func(cli *apsara.SRegion, args *ClouduserCreateOptions) error { - user, err := cli.GetClient().CreateUser(args.NAME, args.MobilePhone, args.Email, args.Comments) - if err != nil { - return err - } - printObject(user) - return nil - }) - - type ClouduserListOptions struct { - Offset string - Limit int - } - - shellutils.R(&ClouduserListOptions{}, "cloud-user-list", "List Cloud users", func(cli *apsara.SRegion, args *ClouduserListOptions) error { - users, err := cli.GetClient().ListUsers(args.Offset, args.Limit) - if err != nil { - return err - } - printList(users.Users.User, 0, 0, 0, nil) - return nil - }) - - type UserPolicyListOptions struct { - USER string - } - - shellutils.R(&UserPolicyListOptions{}, "cloud-user-policy-list", "List Cloud user policies", func(cli *apsara.SRegion, args *UserPolicyListOptions) error { - policies, err := cli.GetClient().ListPoliciesForUser(args.USER) - if err != nil { - return err - } - printList(policies, 0, 0, 0, nil) - return nil - }) - - type ClouduserOptions struct { - NAME string - } - - shellutils.R(&ClouduserOptions{}, "cloud-user-group-list", "List Cloud user groups", func(cli *apsara.SRegion, args *ClouduserOptions) error { - groups, err := cli.GetClient().ListGroupsForUser(args.NAME) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&ClouduserOptions{}, "cloud-user-delete", "Delete Cloud user", func(cli *apsara.SRegion, args *ClouduserOptions) error { - return cli.GetClient().DeleteClouduser(args.NAME) - }) - - shellutils.R(&ClouduserOptions{}, "cloud-user-loginprofile", "Get Cloud user loginprofile", func(cli *apsara.SRegion, args *ClouduserOptions) error { - profile, err := cli.GetClient().GetLoginProfile(args.NAME) - if err != nil { - return err - } - printObject(profile) - return nil - }) - - shellutils.R(&ClouduserOptions{}, "cloud-user-loginprofile-delete", "Delete Cloud user loginprofile", func(cli *apsara.SRegion, args *ClouduserOptions) error { - return cli.GetClient().DeleteLoginProfile(args.NAME) - }) - - type LoginProfileCreateOptions struct { - NAME string - PASSWORD string - } - - shellutils.R(&LoginProfileCreateOptions{}, "cloud-user-loginprofile-create", "Create Cloud user loginprofile", func(cli *apsara.SRegion, args *LoginProfileCreateOptions) error { - profile, err := cli.GetClient().CreateLoginProfile(args.NAME, args.PASSWORD) - if err != nil { - return err - } - printObject(profile) - return nil - }) - - shellutils.R(&LoginProfileCreateOptions{}, "cloud-user-rest-password", "Reset Cloud user password", func(cli *apsara.SRegion, args *LoginProfileCreateOptions) error { - return cli.GetClient().ResetClouduserPassword(args.NAME, args.PASSWORD) - }) - - type ClouduserPolicyOptions struct { - PolicyType string `default:"System" choices:"System|Custom"` - POLICY string - USER string - } - - shellutils.R(&ClouduserPolicyOptions{}, "cloud-user-attach-policy", "Attach policy for user", func(cli *apsara.SRegion, args *ClouduserPolicyOptions) error { - return cli.GetClient().AttachPolicyToUser(args.POLICY, args.PolicyType, args.USER) - }) - - shellutils.R(&ClouduserPolicyOptions{}, "cloud-user-detach-policy", "Detach policy from user", func(cli *apsara.SRegion, args *ClouduserPolicyOptions) error { - return cli.GetClient().DetachPolicyFromUser(args.POLICY, args.PolicyType, args.USER) - }) - -} diff --git a/pkg/multicloud/apsara/shell/region.go b/pkg/multicloud/apsara/shell/region.go deleted file mode 100644 index 254a21eee2..0000000000 --- a/pkg/multicloud/apsara/shell/region.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/multicloud/test" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - test.TestShell() - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *apsara.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/resource_tag.go b/pkg/multicloud/apsara/shell/resource_tag.go deleted file mode 100644 index e09d36c576..0000000000 --- a/pkg/multicloud/apsara/shell/resource_tag.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "strings" - - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type TagGetOptions struct { - SERVICE string `help:"service, eg. ecs"` - RESTYPE string `help:"resource type, eg. instance"` - ID []string `help:"resource Id, eg. ins-123xxx"` - } - shellutils.R(&TagGetOptions{}, "tag-show", "show tag of a specific resource", func(cli *apsara.SRegion, args *TagGetOptions) error { - tags, err := cli.ListResourceTags(args.SERVICE, args.RESTYPE, args.ID) - if err != nil { - return err - } - for id, tag := range tags { - fmt.Println(id, *tag) - } - return nil - }) - - type TagSetOptions struct { - TagGetOptions - Tag []string `help:"tag to set, key:value"` - Replace bool `help:"replace all tags"` - } - shellutils.R(&TagSetOptions{}, "tag-set", "set tags of a specific resource", func(cli *apsara.SRegion, args *TagSetOptions) error { - tags := make(map[string]string) - for _, t := range args.Tag { - parts := strings.Split(t, ":") - tags[parts[0]] = parts[1] - } - err := cli.SetResourceTags(args.SERVICE, args.RESTYPE, args.ID, tags, args.Replace) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/resourcegroup.go b/pkg/multicloud/apsara/shell/resourcegroup.go deleted file mode 100644 index 75715ea17f..0000000000 --- a/pkg/multicloud/apsara/shell/resourcegroup.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ResourceGroupListOptions struct { - PageSize int - PageNumber int - } - shellutils.R(&ResourceGroupListOptions{}, "resource-group-list", "List resource group", func(cli *apsara.SRegion, args *ResourceGroupListOptions) error { - groups, _, err := cli.GetClient().GetResourceGroups(args.PageNumber, args.PageSize) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - type ResourceGroupShowOptions struct { - ID string - } - - shellutils.R(&ResourceGroupShowOptions{}, "resource-group-show", "Show resource group", func(cli *apsara.SRegion, args *ResourceGroupShowOptions) error { - group, err := cli.GetClient().GetResourceGroup(args.ID) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type ResourceGroupCreateOptions struct { - NAME string - } - - shellutils.R(&ResourceGroupCreateOptions{}, "resource-group-create", "Create resource group", func(cli *apsara.SRegion, args *ResourceGroupCreateOptions) error { - group, err := cli.GetClient().CreateResourceGroup(args.NAME) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type OrganizationListOptions struct { - Id string - } - - shellutils.R(&OrganizationListOptions{}, "organization-tree", "List organization tree", func(cli *apsara.SRegion, args *OrganizationListOptions) error { - org, err := cli.GetClient().GetOrganizationTree(args.Id) - if err != nil { - return err - } - printObject(org) - projects := org.GetProject([]string{}) - printList(projects, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&OrganizationListOptions{}, "organization-list", "List organization", func(cli *apsara.SRegion, args *OrganizationListOptions) error { - orgs, err := cli.GetClient().GetOrganizationList() - if err != nil { - return err - } - printList(orgs, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/apsara/shell/routetable.go b/pkg/multicloud/apsara/shell/routetable.go deleted file mode 100644 index 90a975f136..0000000000 --- a/pkg/multicloud/apsara/shell/routetable.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RouteTableListOptions struct { - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&RouteTableListOptions{}, "routetable-list", "List routetables", func(cli *apsara.SRegion, args *RouteTableListOptions) error { - routetables, total, e := cli.GetRouteTables(nil, args.Offset, args.Limit) - if e != nil { - return e - } - printList(routetables, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type RouteTableShowOptions struct { - ID string `help:"ID or name of routetable"` - } - shellutils.R(&RouteTableShowOptions{}, "routetable-show", "Show routetable", func(cli *apsara.SRegion, args *RouteTableShowOptions) error { - routetables, _, e := cli.GetRouteTables([]string{args.ID}, 0, 1) - if e != nil { - return e - } - if len(routetables) == 0 { - return fmt.Errorf("No such ID %s", args.ID) - } - printObject(routetables[0]) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/secgroup.go b/pkg/multicloud/apsara/shell/secgroup.go deleted file mode 100644 index 1537655cfd..0000000000 --- a/pkg/multicloud/apsara/shell/secgroup.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - VpcId string `help:"VPC ID"` - Name string `help:"Secgroup Name"` - SecurityGroupIds []string `help:"SecurityGroup ids"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security group", func(cli *apsara.SRegion, args *SecurityGroupListOptions) error { - secgrps, total, e := cli.GetSecurityGroups(args.VpcId, args.Name, args.SecurityGroupIds, 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 *apsara.SRegion, args *SecurityGroupShowOptions) error { - secgrp, err := cli.GetSecurityGroupDetails(args.ID) - if err != nil { - return err - } - printObject(secgrp) - return nil - }) - - type SecurityGroupCreateOptions struct { - NAME string `help:"SecurityGroup name"` - VpcId string `help:"VPC ID"` - Desc string `help:"SecurityGroup description"` - } - - shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create details of a security group", func(cli *apsara.SRegion, args *SecurityGroupCreateOptions) error { - secgroupId, err := cli.CreateSecurityGroup(args.VpcId, args.NAME, args.Desc) - if err != nil { - return err - } - fmt.Printf("secgroupId: %s", secgroupId) - return nil - }) - -} diff --git a/pkg/multicloud/apsara/shell/snapshot.go b/pkg/multicloud/apsara/shell/snapshot.go deleted file mode 100644 index 946d8fd125..0000000000 --- a/pkg/multicloud/apsara/shell/snapshot.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "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 *apsara.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 *apsara.SRegion, args *SnapshotDeleteOptions) error { - if err := cli.SnapshotPreDelete(args.ID); err != nil { - return fmt.Errorf("Snapshot PreDelete error: %s", err) - } - 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 *apsara.SRegion, args *SnapshotCreateOptions) error { - snapshotId, err := cli.CreateSnapshot(args.DiskId, args.Name, args.Desc) - if err != nil { - return err - } - fmt.Println(snapshotId) - return nil - }) - -} diff --git a/pkg/multicloud/apsara/shell/snapshot_policy.go b/pkg/multicloud/apsara/shell/snapshot_policy.go deleted file mode 100644 index 48aa26256e..0000000000 --- a/pkg/multicloud/apsara/shell/snapshot_policy.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SSnapshotPolicyListOptions struct { - PolicyId string `help:"snapshot policy id"` - Offset int `help:"offset"` - Limit int `help:"limit"` - } - - shellutils.R(&SSnapshotPolicyListOptions{}, "snapshot-policy-list", "list snapshot policy", - func(cli *apsara.SRegion, args *SSnapshotPolicyListOptions) error { - snapshotPolicis, num, err := cli.GetSnapshotPolicies(args.PolicyId, args.Offset, args.Limit) - if err != nil { - return err - } - printList(snapshotPolicis, num, args.Offset, args.Limit, []string{}) - return nil - }, - ) - - type SSnapshotPolicyDeleteOptions struct { - ID string `help:"snapshot id"` - } - shellutils.R(&SSnapshotPolicyDeleteOptions{}, "snapshot-policy-delete", "delete snapshot policy", - func(cli *apsara.SRegion, args *SSnapshotPolicyDeleteOptions) error { - err := cli.DeleteSnapshotPolicy(args.ID) - return err - }, - ) - - type SSnapshotPolicyCreateOptions struct { - Name string `help:"snapshot name"` - - RetentionDays int `help:"retention days"` - RepeatWeekdays []int `help:"auto snapshot which days of the week"` - TimePoints []int `help:"auto snapshot which hours of the day"` - } - shellutils.R(&SSnapshotPolicyCreateOptions{}, "snapshot-policy-create", "create snapshot policy", - func(cli *apsara.SRegion, args *SSnapshotPolicyCreateOptions) error { - input := cloudprovider.SnapshotPolicyInput{ - RetentionDays: args.RetentionDays, - RepeatWeekdays: args.RepeatWeekdays, - TimePoints: args.TimePoints, - PolicyName: args.Name, - } - _, err := cli.CreateSnapshotPolicy(&input) - if err != nil { - return err - } - return nil - }, - ) - - type SSnapshotPolicyApplyOptions struct { - SNAPSHOTPOLICYID string `help:"snapshot policy id"` - DISKID string `help:"disk id"` - } - shellutils.R(&SSnapshotPolicyApplyOptions{}, "snapshot-policy-apply", "apply snapshot policy", - func(cli *apsara.SRegion, args *SSnapshotPolicyApplyOptions) error { - err := cli.ApplySnapshotPolicyToDisks(args.SNAPSHOTPOLICYID, args.DISKID) - return err - }, - ) - - type SSnapshotPolicyCancelOptions struct { - SNAPSHOTPOLICYID string `help:"snapshot policy id"` - DISKID string `help:"disk id"` - } - shellutils.R(&SSnapshotPolicyCancelOptions{}, "snapshot-policy-cancel", "cancel snapshot policy", - func(cli *apsara.SRegion, args *SSnapshotPolicyCancelOptions) error { - err := cli.CancelSnapshotPolicyToDisks(args.SNAPSHOTPOLICYID, args.DISKID) - return err - }, - ) -} diff --git a/pkg/multicloud/apsara/shell/task.go b/pkg/multicloud/apsara/shell/task.go deleted file mode 100644 index 64a963b52b..0000000000 --- a/pkg/multicloud/apsara/shell/task.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type TaskListOptions struct { - TYPE string `help:"Task types, either ImportImage or ExportImage" choices:"ImportImage|ExportImage"` - Task []string `help:"Task ID"` - Status string `help:"Task status" choices:"Finished|Processing|Waiting|Deleted|Paused|Failed"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&TaskListOptions{}, "task-list", "List tasks", func(cli *apsara.SRegion, args *TaskListOptions) error { - tasks, total, err := cli.GetTasks(apsara.TaskActionType(args.TYPE), args.Task, apsara.TaskStatusType(args.Status), args.Offset, args.Limit) - if err != nil { - return err - } - printList(tasks, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type TaskIDOptions struct { - ID string `help:"Task ID"` - } - - shellutils.R(&TaskIDOptions{}, "task-show", "Show task", func(cli *apsara.SRegion, args *TaskIDOptions) error { - task, err := cli.GetTask(args.ID) - if err != nil { - return err - } - printObject(task) - return nil - }) - - shellutils.R(&TaskIDOptions{}, "cancel-task", "Cancel task", func(cli *apsara.SRegion, args *TaskIDOptions) error { - return cli.CancelTask(args.ID) - }) - -} diff --git a/pkg/multicloud/apsara/shell/vpc.go b/pkg/multicloud/apsara/shell/vpc.go deleted file mode 100644 index 84a0b43a1e..0000000000 --- a/pkg/multicloud/apsara/shell/vpc.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "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 *apsara.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 - }) - - type VpcOptions struct { - ID string `help:"VPC id"` - } - - shellutils.R(&VpcOptions{}, "vpc-delete", "Delete vpc", func(cli *apsara.SRegion, args *VpcOptions) error { - return cli.DeleteVpc(args.ID) - }) - -} diff --git a/pkg/multicloud/apsara/shell/vrouter.go b/pkg/multicloud/apsara/shell/vrouter.go deleted file mode 100644 index 927b6abd99..0000000000 --- a/pkg/multicloud/apsara/shell/vrouter.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VRouterListOptions struct { - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&VRouterListOptions{}, "vrouter-list", "List vrouters", func(cli *apsara.SRegion, args *VRouterListOptions) error { - vrouters, total, e := cli.GetVRouters(args.Offset, args.Limit) - if e != nil { - return e - } - printList(vrouters, total, args.Offset, args.Limit, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/vswitch.go b/pkg/multicloud/apsara/shell/vswitch.go deleted file mode 100644 index 668ca10b3a..0000000000 --- a/pkg/multicloud/apsara/shell/vswitch.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "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 *apsara.SRegion, args *VSwitchListOptions) error { - vswitches, total, e := cli.GetVSwitches(nil, "", args.Offset, args.Limit) - if e != nil { - return e - } - printList(vswitches, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type VSwitchShowOptions struct { - ID string `help:"show vswitch details"` - } - shellutils.R(&VSwitchShowOptions{}, "vswitch-show", "Show vswitch details", func(cli *apsara.SRegion, args *VSwitchShowOptions) error { - vswitch, e := cli.GetVSwitchAttributes(args.ID) - if e != nil { - return e - } - printObject(vswitch) - return nil - }) - - shellutils.R(&VSwitchShowOptions{}, "vswitch-delete", "Show vswitch details", func(cli *apsara.SRegion, args *VSwitchShowOptions) error { - e := cli.DeleteVSwitch(args.ID) - if e != nil { - return e - } - return nil - }) -} diff --git a/pkg/multicloud/apsara/shell/zone.go b/pkg/multicloud/apsara/shell/zone.go deleted file mode 100644 index cf6382f34c..0000000000 --- a/pkg/multicloud/apsara/shell/zone.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/apsara" - "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 *apsara.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 - }) -} diff --git a/pkg/multicloud/apsara/snapshot.go b/pkg/multicloud/apsara/snapshot.go deleted file mode 100644 index 8a602ac288..0000000000 --- a/pkg/multicloud/apsara/snapshot.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SnapshotStatusType string - -const ( - SnapshotStatusAccomplished SnapshotStatusType = "accomplished" - SnapshotStatusProgress SnapshotStatusType = "progressing" - SnapshotStatusFailed SnapshotStatusType = "failed" - - SnapshotTypeSystem string = "System" - SnapshotTypeData string = "Data" -) - -type SSnapshot struct { - multicloud.SResourceBase - multicloud.ApsaraTags - region *SRegion - - Progress string - SnapshotId string - SnapshotName string - SourceDiskId string - SourceDiskSize int32 - SourceDiskType string - Status SnapshotStatusType - Usage string - DepartmentInfo -} - -func (self *SSnapshot) GetId() string { - return self.SnapshotId -} - -func (self *SSnapshot) GetName() string { - return self.SnapshotName -} - -func (self *SSnapshot) GetStatus() string { - if self.Status == SnapshotStatusAccomplished { - return api.SNAPSHOT_READY - } else if self.Status == SnapshotStatusProgress { - return api.SNAPSHOT_CREATING - } else { // if self.Status == SnapshotStatusFailed - return api.SNAPSHOT_FAILED - } -} - -func (self *SSnapshot) GetSizeMb() int32 { - return self.SourceDiskSize * 1024 -} - -func (self *SSnapshot) GetDiskId() string { - return self.SourceDiskId -} - -func (self *SSnapshot) GetDiskType() string { - if self.SourceDiskType == SnapshotTypeSystem { - return api.DISK_TYPE_SYS - } else if self.SourceDiskType == SnapshotTypeData { - return api.DISK_TYPE_DATA - } else { - return "" - } -} - -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) GetGlobalId() string { - return fmt.Sprintf("%s", self.SnapshotId) -} - -func (self *SSnapshot) IsEmulated() bool { - return false -} - -func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, total, err := self.GetSnapshots("", "", "", []string{}, 0, 50) - if err != nil { - return nil, err - } - for len(snapshots) < total { - var parts []SSnapshot - parts, total, err = self.GetSnapshots("", "", "", []string{}, len(snapshots), 50) - if err != nil { - return nil, err - } - snapshots = append(snapshots, parts...) - } - ret := make([]cloudprovider.ICloudSnapshot, len(snapshots)) - for i := 0; i < len(snapshots); i += 1 { - ret[i] = &snapshots[i] - } - return ret, nil -} - -func (self *SSnapshot) Delete() error { - if self.region == nil { - return fmt.Errorf("not init region for snapshot %s", self.SnapshotId) - } - if err := self.region.SnapshotPreDelete(self.SnapshotId); err != nil { - return err - } - return self.region.DeleteSnapshot(self.SnapshotId) -} - -func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - - if len(instanceId) > 0 { - params["InstanceId"] = instanceId - } - if len(diskId) > 0 { - params["diskId"] = diskId - } - if len(snapshotName) > 0 { - params["SnapshotName"] = snapshotName - } - if snapshotIds != nil && len(snapshotIds) > 0 { - params["SnapshotIds"] = jsonutils.Marshal(snapshotIds).String() - } - - body, err := self.ecsRequest("DescribeSnapshots", params) - if err != nil { - log.Errorf("GetSnapshots fail %s", err) - return nil, 0, err - } - - snapshots := make([]SSnapshot, 0) - if err := body.Unmarshal(&snapshots, "Snapshots", "Snapshot"); err != nil { - log.Errorf("Unmarshal snapshot details fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - for i := 0; i < len(snapshots); i += 1 { - snapshots[i].region = self - } - return snapshots, int(total), nil -} - -func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) - if err != nil { - return nil, err - } - if total == 0 { - return nil, cloudprovider.ErrNotFound - } else if total > 1 { - return nil, cloudprovider.ErrDuplicateId - } - return &snapshots[0], nil -} - -func (self *SRegion) DeleteSnapshot(snapshotId string) error { - params := make(map[string]string) - params["SnapshotId"] = snapshotId - _, err := self.ecsRequest("DeleteSnapshot", params) - return err -} - -// If snapshot linked images can't be delete -// delete images first -- Apsara -func (self *SRegion) SnapshotPreDelete(snapshotId string) error { - images, _, err := self.GetImagesBySnapshot(snapshotId, 0, 0) - if err != nil { - return fmt.Errorf("PreDelete get images by snapshot %s error: %s", snapshotId, err) - } - for _, image := range images { - image.storageCache = &SStoragecache{region: self} - if err := image.Delete(context.Background()); err != nil { - return fmt.Errorf("PreDelete image %s error: %s", image.GetId(), err) - } - if err := cloudprovider.WaitDeleted(&image, 3*time.Second, 300*time.Second); err != nil { - return fmt.Errorf("PreDelete waite image %s deleted error: %s", image.GetId(), err) - } - } - return nil -} diff --git a/pkg/multicloud/apsara/snapshot_policy.go b/pkg/multicloud/apsara/snapshot_policy.go deleted file mode 100644 index 89b61425dd..0000000000 --- a/pkg/multicloud/apsara/snapshot_policy.go +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "sort" - "strconv" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSnapshotPolicyType string - -const ( - Creating SSnapshotPolicyType = "Creating" - Available SSnapshotPolicyType = "Available" - Normal SSnapshotPolicyType = "Normal" -) - -type SSnapshotPolicy struct { - multicloud.SResourceBase - multicloud.ApsaraTags - region *SRegion - - AutoSnapshotPolicyName string - AutoSnapshotPolicyId string - RepeatWeekdays string - TimePoints string - RetentionDays int - Status SSnapshotPolicyType - DepartmentInfo -} - -func (self *SSnapshotPolicy) GetId() string { - return self.AutoSnapshotPolicyId -} - -func (self *SSnapshotPolicy) GetName() string { - return self.AutoSnapshotPolicyName -} - -func (self *SSnapshotPolicy) GetStatus() string { - // XXX: apsara文档与实际返回值不符 - if self.Status == Normal || self.Status == Available { - return api.SNAPSHOT_POLICY_READY - } else if self.Status == Creating { - return api.SNAPSHOT_POLICY_CREATING - } else { - return api.SNAPSHOT_POLICY_UNKNOWN - } -} - -func (self *SSnapshotPolicy) Refresh() error { - if snapshotPolicies, total, err := self.region.GetSnapshotPolicies(self.AutoSnapshotPolicyId, 0, 1); err != nil { - return err - } else if total != 1 { - return cloudprovider.ErrNotFound - } else if err := jsonutils.Update(self, snapshotPolicies[0]); err != nil { - return err - } - return nil -} - -func (self *SSnapshotPolicy) IsEmulated() bool { - return false -} - -func (self *SSnapshotPolicy) GetGlobalId() string { - return self.AutoSnapshotPolicyId -} - -func (self *SSnapshotPolicy) GetRetentionDays() int { - return self.RetentionDays -} - -func sliceAtoi(sa []string) ([]int, error) { - si := make([]int, 0, len(sa)) - for _, a := range sa { - i, err := strconv.Atoi(a) - if err != nil { - return si, err - } - si = append(si, i) - } - return si, nil -} - -func stringToIntDays(days []string) ([]int, error) { - idays, err := sliceAtoi(days) - if err != nil { - return nil, err - } - sort.Ints(idays) - return idays, nil -} - -func parsePolicy(policy string) ([]int, error) { - tp, err := jsonutils.ParseString(policy) - if err != nil { - return nil, fmt.Errorf("Parse policy %s error %s", policy, err) - } - atp, ok := tp.(*jsonutils.JSONArray) - if !ok { - return nil, fmt.Errorf("Policy %s Wrong format", tp) - } - return stringToIntDays(atp.GetStringArray()) -} - -func (self *SSnapshotPolicy) GetRepeatWeekdays() ([]int, error) { - return parsePolicy(self.RepeatWeekdays) -} - -func (self *SSnapshotPolicy) GetTimePoints() ([]int, error) { - return parsePolicy(self.TimePoints) -} - -func (self *SSnapshotPolicy) IsActivated() bool { - return true -} - -func (self *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { - snapshotPolicies, total, err := self.GetSnapshotPolicies("", 0, 50) - if err != nil { - return nil, err - } - for len(snapshotPolicies) < total { - var parts []SSnapshotPolicy - parts, total, err = self.GetSnapshotPolicies("", len(snapshotPolicies), 50) - if err != nil { - return nil, err - } - snapshotPolicies = append(snapshotPolicies, parts...) - } - ret := make([]cloudprovider.ICloudSnapshotPolicy, len(snapshotPolicies)) - for i := 0; i < len(snapshotPolicies); i += 1 { - ret[i] = &snapshotPolicies[i] - } - return ret, nil -} - -func (self *SRegion) GetSnapshotPolicies(policyId string, offset int, limit int) ([]SSnapshotPolicy, int, error) { - params := make(map[string]string) - - params["RegionId"] = self.RegionId - if limit != 0 { - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - } - - if len(policyId) > 0 { - params["AutoSnapshotPolicyId"] = policyId - } - - body, err := self.ecsRequest("DescribeAutoSnapshotPolicyEx", params) - if err != nil { - return nil, 0, fmt.Errorf("GetSnapshotPolicys fail %s", err) - } - - snapshotPolicies := make([]SSnapshotPolicy, 0) - if err := body.Unmarshal(&snapshotPolicies, "AutoSnapshotPolicies", "AutoSnapshotPolicy"); err != nil { - return nil, 0, fmt.Errorf("Unmarshal snapshot policies details fail %s", err) - } - total, _ := body.Int("TotalCount") - for i := 0; i < len(snapshotPolicies); i += 1 { - snapshotPolicies[i].region = self - } - return snapshotPolicies, int(total), nil -} - -func (self *SSnapshotPolicy) Delete() error { - if self.region == nil { - return fmt.Errorf("Not init region for snapshotPolicy %s", self.AutoSnapshotPolicyId) - } - return self.region.DeleteSnapshotPolicy(self.AutoSnapshotPolicyId) -} - -func (self *SRegion) DeleteSnapshotPolicy(snapshotPolicyId string) error { - params := make(map[string]string) - params["autoSnapshotPolicyId"] = snapshotPolicyId - params["regionId"] = self.RegionId - _, err := self.ecsRequest("DeleteAutoSnapshotPolicy", params) - return err -} - -func (self *SRegion) GetISnapshotPolicyById(snapshotPolicyId string) (cloudprovider.ICloudSnapshotPolicy, error) { - policies, _, err := self.GetSnapshotPolicies(snapshotPolicyId, 0, 1) - if err != nil { - return nil, err - } - if len(policies) == 0 { - return nil, cloudprovider.ErrNotFound - } - return &policies[0], nil -} - -func (self *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput) (string, error) { - if input.RepeatWeekdays == nil { - return "", fmt.Errorf("Can't create snapshot policy with nil repeatWeekdays") - } - if input.TimePoints == nil { - return "", fmt.Errorf("Can't create snapshot policy with nil timePoints") - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["repeatWeekdays"] = jsonutils.Marshal(input.GetStringArrayRepeatWeekdays()).String() - params["timePoints"] = jsonutils.Marshal(input.GetStringArrayTimePoints()).String() - params["retentionDays"] = strconv.Itoa(input.RetentionDays) - params["autoSnapshotPolicyName"] = input.PolicyName - if body, err := self.ecsRequest("CreateAutoSnapshotPolicy", params); err != nil { - return "", fmt.Errorf("CreateAutoSnapshotPolicy fail %s", err) - } else { - return body.GetString("AutoSnapshotPolicyId") - } -} - -func (self *SRegion) UpdateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput, snapshotPolicyId string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - if input.RetentionDays != 0 { - params["retentionDays"] = strconv.Itoa(input.RetentionDays) - } - if input.RepeatWeekdays != nil && len(input.RepeatWeekdays) != 0 { - params["repeatWeekdays"] = jsonutils.Marshal(input.GetStringArrayRepeatWeekdays()).String() - } - if input.TimePoints != nil && len(input.TimePoints) != 0 { - params["timePoints"] = jsonutils.Marshal(input.GetStringArrayTimePoints()).String() - } - _, err := self.ecsRequest("ModifyAutoSnapshotPolicyEx", params) - if err != nil { - return fmt.Errorf("ModifyAutoSnapshotPolicyEx Fail %s", err) - } - return nil -} - -//func (self *SRegion) UpdateSnapshotPolicy( -// snapshotPolicyId string, retentionDays *int, -// repeatWeekdays, timePoints *jsonutils.JSONArray, policyName string, -//) error { -// params := make(map[string]string) -// params["RegionId"] = self.RegionId -// if len(policyName) > 0 { -// params["autoSnapshotPolicyName"] = policyName -// } -// if retentionDays != nil { -// params["retentionDays"] = strconv.Itoa(*retentionDays) -// } -// if repeatWeekdays != nil { -// params["repeatWeekdays"] = repeatWeekdays.String() -// } -// if timePoints != nil { -// params["timePoints"] = timePoints.String() -// } -// _, err := self.ecsRequest("ModifyAutoSnapshotPolicyEx", params) -// if err != nil { -// return fmt.Errorf("ModifyAutoSnapshotPolicyEx Fail %s", err) -// } -// return nil -//} - -func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["autoSnapshotPolicyId"] = snapshotPolicyId - diskIds := []string{diskId} - params["diskIds"] = jsonutils.Marshal(diskIds).String() - _, err := self.ecsRequest("ApplyAutoSnapshotPolicy", params) - if err != nil { - return fmt.Errorf("ApplyAutoSnapshotPolicy Fail %s", err) - } - return nil -} - -func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { - params := make(map[string]string) - params["RegionId"] = self.RegionId - diskIds := []string{diskId} - params["diskIds"] = jsonutils.Marshal(diskIds).String() - _, err := self.ecsRequest("CancelAutoSnapshotPolicy", params) - if err != nil { - return fmt.Errorf("CancelAutoSnapshotPolicy Fail %s", err) - } - return nil -} diff --git a/pkg/multicloud/apsara/storage.go b/pkg/multicloud/apsara/storage.go deleted file mode 100644 index cea4b91b3e..0000000000 --- a/pkg/multicloud/apsara/storage.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2019 Yunion -// -// 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. - -// -// 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 apsara - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - multicloud.SStorageBase - multicloud.ApsaraTags - zone *SZone - storageType string -} - -func (self *SStorage) GetId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetName() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetGlobalId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) -} - -func (self *SStorage) IsEmulated() bool { - return false -} - -func (self *SStorage) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -func (self *SStorage) getDisks() ([]SDisk, error) { - if len(self.zone.disks) > 0 { - return self.zone.disks, nil - } - self.zone.disks = []SDisk{} - for { - part, total, err := self.zone.region.GetDisks("", self.zone.GetId(), "", nil, len(self.zone.disks), 100) - if err != nil { - return nil, errors.Wrapf(err, "GetDisks") - } - self.zone.disks = append(self.zone.disks, part...) - if len(self.zone.disks) >= total { - break - } - } - return self.zone.disks, nil -} - -func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := self.getDisks() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudDisk{} - for i := 0; i < len(disks); i += 1 { - if disks[i].Category == self.storageType { - disks[i].storage = self - ret = append(ret, &disks[i]) - } - } - return ret, nil -} - -func (self *SStorage) GetStorageType() string { - return self.storageType -} - -func (self *SStorage) GetMediumType() string { - if strings.Contains(self.storageType, "_ssd") { - return api.DISK_TYPE_SSD - } else { - return api.DISK_TYPE_ROTATE - } -} - -func (self *SStorage) GetCapacityMB() int64 { - return 0 // unlimited -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - conf := jsonutils.NewDict() - return conf -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) Refresh() error { - // do nothing - return nil -} - -func (self *SStorage) GetEnabled() bool { - return true -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.zone.region.getStoragecache() -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - diskId, err := self.zone.region.CreateDisk(self.zone.ZoneId, self.storageType, conf.Name, conf.SizeGb, conf.Desc, conf.ProjectId) - 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) GetIDiskById(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 - } -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - if utils.IsInStringArray(self.storageType, self.zone.getSysDiskCategories()) { - return true - } - return false -} diff --git a/pkg/multicloud/apsara/storagecache.go b/pkg/multicloud/apsara/storagecache.go deleted file mode 100644 index a8efc52bf0..0000000000 --- a/pkg/multicloud/apsara/storagecache.go +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/aliyun/aliyun-oss-go-sdk/oss" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "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" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.ApsaraTags - region *SRegion - - iimages []cloudprovider.ICloudImage -} - -func (self *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) -} - -func (self *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) -} - -func (self *SStoragecache) GetStatus() string { - return "available" -} - -func (self *SStoragecache) Refresh() error { - return nil -} - -func (self *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetGlobalId()) -} - -func (self *SStoragecache) IsEmulated() bool { - return false -} - -func (self *SStoragecache) getImages(owner ImageOwnerType) ([]SImage, error) { - images := make([]SImage, 0) - for { - parts, total, err := self.region.GetImages(ImageStatusType(""), owner, nil, "", len(images), 50) - if err != nil { - return nil, err - } - images = append(images, parts...) - if len(images) >= total { - break - } - } - return images, nil -} - -func (self *SStoragecache) fetchImages() error { - images := make([]SImage, 0) - for _, owner := range []ImageOwnerType{ImageOwnerSelf, ImageOwnerSystem} { - _images, err := self.getImages(owner) - if err != nil { - return errors.Wrapf(err, "GetImage(%s)", owner) - } - images = append(images, _images...) - } - 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) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - if self.iimages == nil { - err := self.fetchImages() - if err != nil { - return nil, err - } - } - return self.iimages, nil -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - img, err := self.region.GetImage(extId) - if err != nil { - return nil, err - } - img.storageCache = self - return img, nil -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - - if len(image.ExternalId) > 0 { - status, err := self.region.GetImageStatus(image.ExternalId) - if err != nil { - log.Errorf("GetImageStatus error %s", err) - } - log.Debugf("UploadImage: Image external ID %s exists, status %s", image.ExternalId, status) - // 不能直接删除 ImageStatusCreating 状态的image ,需要先取消importImage Task - if status == ImageStatusCreating { - err := self.region.CancelImageImportTasks() - if err != nil { - log.Errorln(err) - } - } - } - - return self.uploadImage(ctx, userCred, image, callback) -} - -func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - // first upload image to oss - s := auth.GetAdminSession(ctx, options.Options.Region) - - meta, reader, sizeByte, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false) - if err != nil { - return "", err - } - log.Infof("meta data %s", meta) - - bucketName := strings.ToLower(fmt.Sprintf("imgcache-%s-%s", self.region.GetId(), image.ImageId)) - exist, err := self.region.IBucketExist(bucketName) - if err != nil { - log.Errorf("IsBucketExist err %s", err) - return "", err - } - if !exist { - log.Debugf("Bucket %s not exists, to create ...", bucketName) - err = self.region.CreateIBucket(bucketName, "", "") - if err != nil { - log.Errorf("Create bucket error %s", err) - return "", err - } - } else { - log.Debugf("Bucket %s exists", bucketName) - } - - defer self.region.DeleteIBucket(bucketName) // remove bucket - - bucket, err := self.region.GetIBucketByName(bucketName) - if err != nil { - log.Errorf("Bucket error %s %s", bucketName, err) - return "", err - } - log.Debugf("To upload image to bucket %s ...", bucketName) - body := multicloud.NewProgress(sizeByte, 80, reader, callback) - err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeByte, "", "", nil, false) - // err = bucket.PutObject(image.ImageId, reader) - if err != nil { - log.Errorf("PutObject error %s %s", image.ImageId, err) - return "", err - } - - defer bucket.DeleteObject(context.Background(), image.ImageId) // remove object - - imageBaseName := image.ImageId - if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { - imageBaseName = fmt.Sprintf("img%s", image.ImageId) - } - imageName := imageBaseName - nameIdx := 1 - - // check image name, avoid name conflict - for { - _, err = self.region.GetImageByName(imageName) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - break - } else { - return "", err - } - } - imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) - nameIdx += 1 - } - - log.Debugf("Import image %s", imageName) - - // ensure privileges - err = self.region.GetClient().EnableImageImport() - if err != nil { - log.Errorf("fail to enable import privileges: %s", err) - return "", err - } - - task, err := self.region.ImportImage(imageName, image.OsArch, image.OsType, image.OsDistribution, bucketName, image.ImageId) - - if err != nil { - log.Errorf("ImportImage error %s %s %s", image.ImageId, bucketName, err) - return "", err - } - - // timeout: 1hour = 3600 seconds - err = self.region.waitTaskStatus(ImportImageTask, task.TaskId, TaskStatusFinished, 15*time.Second, 3600*time.Second) - if err != nil { - log.Errorf("waitTaskStatus %s", err) - return task.ImageId, err - } - - if callback != nil { - callback(100) - } - - return task.ImageId, nil -} - -func (self *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - if imageId, err := self.region.createIImage(snapshoutId, 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 - if err := cloudprovider.WaitStatus(iimage[0], cloudprovider.IMAGE_STATUS_ACTIVE, 15*time.Second, 3600*time.Second); err != nil { - return nil, err - } - return iimage[0], nil - } -} - -func (self *SRegion) CreateImage(snapshoutId, imageName, imageDesc string) (string, error) { - return self.createIImage(snapshoutId, imageName, imageDesc) -} - -func (self *SRegion) createIImage(snapshoutId, imageName, imageDesc string) (string, error) { - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["OssBucket"] = strings.ToLower(fmt.Sprintf("imgcache-%s", self.GetId())) - params["SnapshotId"] = snapshoutId - params["ImageName"] = imageName - params["Description"] = imageDesc - - if body, err := self.ecsRequest("CreateImage", params); err != nil { - log.Errorf("CreateImage fail %s", err) - return "", err - } else { - log.Infof("%s", body) - return body.GetString("ImageId") - } -} - -func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return self.downloadImage(userCred, imageId, extId, path) -} - -// 定义进度条监听器。 -type OssProgressListener struct { -} - -// 定义进度变更事件处理函数。 -func (listener *OssProgressListener) ProgressChanged(event *oss.ProgressEvent) { - switch event.EventType { - case oss.TransferStartedEvent: - log.Debugf("Transfer Started, ConsumedBytes: %d, TotalBytes %d.\n", - event.ConsumedBytes, event.TotalBytes) - case oss.TransferDataEvent: - log.Debugf("\rTransfer Data, ConsumedBytes: %d, TotalBytes %d, %d%%.", - event.ConsumedBytes, event.TotalBytes, event.ConsumedBytes*100/event.TotalBytes) - case oss.TransferCompletedEvent: - log.Debugf("\nTransfer Completed, ConsumedBytes: %d, TotalBytes %d.\n", - event.ConsumedBytes, event.TotalBytes) - case oss.TransferFailedEvent: - log.Debugf("\nTransfer Failed, ConsumedBytes: %d, TotalBytes %d.\n", - event.ConsumedBytes, event.TotalBytes) - default: - } -} - -func (self *SStoragecache) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storageCache := region.getStoragecache() - return []cloudprovider.ICloudStoragecache{storageCache}, nil -} - -func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - storageCache := region.getStoragecache() - if id == storageCache.GetGlobalId() { - return storageCache, nil - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/apsara/vpc.go b/pkg/multicloud/apsara/vpc.go deleted file mode 100644 index f99e4465bb..0000000000 --- a/pkg/multicloud/apsara/vpc.go +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - VpcAvailable = "Available" - VpcPending = "Pending" -) - -// "CidrBlock":"172.31.0.0/16","CreationTime":"2017-03-19T13:37:40Z","Description":"System created default VPC.","IsDefault":true,"RegionId":"cn-hongkong","Status":"Available","UserCidrs":{"UserCidr":[]},"VRouterId":"vrt-j6c00qrol733dg36iq4qj","VSwitchIds":{"VSwitchId":["vsw-j6c3gig5ub4fmi2veyrus"]},"VpcId":"vpc-j6c86z3sh8ufhgsxwme0q","VpcName":"" - -type SUserCIDRs struct { - UserCidr []string -} - -type SVSwitchIds struct { - VSwitchId []string -} - -type SVpc struct { - multicloud.SVpc - multicloud.ApsaraTags - - region *SRegion - - iwires []cloudprovider.ICloudWire - - secgroups []cloudprovider.ICloudSecurityGroup - routeTables []cloudprovider.ICloudRouteTable - - CidrBlock string - CreationTime time.Time - Description string - IsDefault bool - RegionId string - Status string - UserCidrs SUserCIDRs - VRouterId string - VSwitchIds SVSwitchIds - VpcId string - VpcName string - - DepartmentInfo -} - -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) IsEmulated() bool { - return false -} - -func (self *SVpc) GetIsDefault() bool { - return self.IsDefault -} - -func (self *SVpc) GetCidrBlock() string { - return self.CidrBlock -} - -func (self *SVpc) GetStatus() string { - return strings.ToLower(self.Status) -} - -func (self *SVpc) GetCreatedAt() time.Time { - return self.CreationTime -} - -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) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetSysTags() map[string]string { - tags := self.ApsaraTags.GetSysTags() - if len(self.ResourceGroup) > 0 { - tags["ResourceGroup"] = self.ResourceGroup - } - if len(self.ResourceGroupId) > 0 { - tags["ResourceGroupId"] = self.ResourceGroupId - } - if len(self.Department) > 0 { - tags["Department"] = self.Department - } - if len(self.DepartmentName) > 0 { - tags["DepartmentName"] = self.DepartmentName - } - if len(self.ResourceGroupName) > 0 { - groupName := strings.TrimPrefix(self.ResourceGroupName, "ResourceSet(") - groupName = strings.TrimSuffix(groupName, ")") - tags["ResourceGroupName"] = groupName - } - return tags -} - -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) 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 - } - } - return nil -} - -func (self *SVpc) fetchVSwitches() error { - switches, total, err := self.region.GetVSwitches(nil, self.VpcId, 0, 50) - if err != nil { - return err - } - if total > len(switches) { - switches, _, err = self.region.GetVSwitches(nil, self.VpcId, 0, total) - if err != nil { - return err - } - } - for i := 0; i < len(switches); i += 1 { - wire := self.getWireByZoneId(switches[i].ZoneId) - switches[i].wire = wire - wire.addNetwork(&switches[i]) - } - return nil -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - if self.iwires == nil { - err := self.fetchVSwitches() - if err != nil { - return nil, err - } - } - return self.iwires, nil -} - -func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { - if self.iwires == nil { - err := self.fetchVSwitches() - 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) fetchSecurityGroups() error { - secgroups := make([]SSecurityGroup, 0) - for { - parts, total, err := self.region.GetSecurityGroups(self.VpcId, "", []string{}, len(secgroups), 50) - if err != nil { - return err - } - secgroups = append(secgroups, parts...) - if len(secgroups) >= total { - break - } - } - 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 *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) fetchRouteTables() error { - routeTables := make([]*SRouteTable, 0) - for { - parts, total, err := self.RemoteGetRouteTableList(len(routeTables), 50) - if err != nil { - return err - } - routeTables = append(routeTables, parts...) - if len(routeTables) >= total { - break - } - } - self.routeTables = make([]cloudprovider.ICloudRouteTable, len(routeTables)) - for i := 0; i < len(routeTables); i++ { - routeTables[i].vpc = self - self.routeTables[i] = routeTables[i] - } - return nil -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - if self.routeTables == nil { - err := self.fetchRouteTables() - if err != nil { - return nil, err - } - } - return self.routeTables, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotSupported -} - -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) getNatGateways() ([]SNatGetway, error) { - natgatways := make([]SNatGetway, 0) - gwTotal := -1 - for gwTotal < 0 || len(natgatways) < gwTotal { - parts, total, err := self.region.GetNatGateways(self.VpcId, "", len(natgatways), 50) - if err != nil { - return nil, err - } - if len(parts) > 0 { - natgatways = append(natgatways, parts...) - } - gwTotal = total - } - for i := 0; i < len(natgatways); i += 1 { - natgatways[i].vpc = self - } - return natgatways, nil -} - -func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { - nats := []SNatGetway{} - for { - parts, total, err := self.region.GetNatGateways(self.VpcId, "", len(nats), 50) - if err != nil { - return nil, err - } - nats = append(nats, parts...) - if len(nats) >= total { - break - } - } - inats := []cloudprovider.ICloudNatGateway{} - for i := 0; i < len(nats); i++ { - nats[i].vpc = self - inats = append(inats, &nats[i]) - } - return inats, nil -} diff --git a/pkg/multicloud/apsara/vswitch.go b/pkg/multicloud/apsara/vswitch.go deleted file mode 100644 index 724afb0212..0000000000 --- a/pkg/multicloud/apsara/vswitch.go +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/util/netutils" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -// {"AvailableIpAddressCount":4091,"CidrBlock":"172.31.32.0/20","CreationTime":"2017-03-19T13:37:44Z","Description":"System created default virtual switch.","IsDefault":true,"Status":"Available","VSwitchId":"vsw-j6c3gig5ub4fmi2veyrus","VSwitchName":"","VpcId":"vpc-j6c86z3sh8ufhgsxwme0q","ZoneId":"cn-hongkong-b"} - -const ( - VSwitchPending = "Pending" - VSwitchAvailable = "Available" -) - -type SCloudResources struct { - CloudResourceSetType []string -} - -type SVSwitch struct { - multicloud.SResourceBase - multicloud.ApsaraTags - wire *SWire - - AvailableIpAddressCount int - - CidrBlock string - Ipv6CidrBlock string - CreationTime time.Time - Description string - IsDefault bool - Status string - VSwitchId string - VSwitchName string - VpcId string - ZoneId string - - CloudResources SCloudResources - RouteTable SRouteTable - DepartmentInfo -} - -func (self *SVSwitch) GetId() string { - return self.VSwitchId -} - -func (self *SVSwitch) GetName() string { - if len(self.VSwitchName) > 0 { - return self.VSwitchName - } - return self.VSwitchId -} - -func (self *SVSwitch) GetGlobalId() string { - return self.VSwitchId -} - -func (self *SVSwitch) GetCreatedAt() time.Time { - return self.CreationTime -} - -func (self *SVSwitch) GetStatus() string { - return strings.ToLower(self.Status) -} - -func (self *SVSwitch) Refresh() error { - log.Debugf("vsiwtch refresh %s", self.VSwitchId) - new, err := self.wire.zone.region.GetVSwitchAttributes(self.VSwitchId) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SVSwitch) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SVSwitch) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - return startIp.String() -} - -func (self *SVSwitch) 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 *SVSwitch) GetIpMask() int8 { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - return pref.MaskLen -} - -func (self *SVSwitch) GetGateway() string { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 - endIp = endIp.StepDown() // 254 - return endIp.String() -} - -func (self *SVSwitch) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SVSwitch) GetIsPublic() bool { - // return self.IsDefault - return true -} - -func (self *SVSwitch) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SRegion) createVSwitch(zoneId string, vpcId string, name string, cidr string, desc string) (string, error) { - params := make(map[string]string) - params["ZoneId"] = zoneId - params["VpcId"] = vpcId - params["CidrBlock"] = cidr - params["VSwitchName"] = name - if len(desc) > 0 { - params["Description"] = desc - } - params["ClientToken"] = utils.GenRequestId(20) - - body, err := self.vpcRequest("CreateVSwitch", params) - if err != nil { - return "", err - } - return body.GetString("VSwitchId") -} - -func (self *SRegion) DeleteVSwitch(vswitchId string) error { - params := make(map[string]string) - params["VSwitchId"] = vswitchId - - _, err := self.vpcRequest("DeleteVSwitch", params) - return err -} - -func (self *SVSwitch) Delete() error { - err := self.Refresh() - if err != nil { - log.Errorf("refresh vswitch fail %s", err) - return err - } - if len(self.RouteTable.RouteTableId) > 0 && !self.RouteTable.IsSystem() { - err = self.wire.zone.region.UnassociateRouteTable(self.RouteTable.RouteTableId, self.VSwitchId) - if err != nil { - log.Errorf("unassociate routetable fail %s", err) - return err - } - } - err = self.dissociateWithSNAT() - if err != nil { - log.Errorf("fail to dissociateWithSNAT") - return err - } - err = cloudprovider.Wait(10*time.Second, 60*time.Second, func() (bool, error) { - err := self.wire.zone.region.DeleteVSwitch(self.VSwitchId) - if err != nil { - // delete network immediately after deleting vm on it - // \"Code\":\"DependencyViolation\",\"Message\":\"Specified object has dependent resources.\"} - if isError(err, "DependencyViolation") { - return false, nil - } - return false, err - } else { - return true, nil - } - }) - return err -} - -func (self *SVSwitch) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (self *SRegion) GetVSwitches(ids []string, vpcId string, offset int, limit int) ([]SVSwitch, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["RegionId"] = self.RegionId - params["PageSize"] = fmt.Sprintf("%d", limit) - params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) - if ids != nil && len(ids) > 0 { - params["VSwitchId"] = strings.Join(ids, ",") - } - if len(vpcId) > 0 { - params["VpcId"] = vpcId - } - - body, err := self.vpcRequest("DescribeVSwitches", params) - if err != nil { - log.Errorf("GetVSwitches fail %s", err) - return nil, 0, err - } - - switches := make([]SVSwitch, 0) - err = body.Unmarshal(&switches, "VSwitches", "VSwitch") - if err != nil { - log.Errorf("Unmarshal vswitches fail %s", err) - return nil, 0, err - } - total, _ := body.Int("TotalCount") - return switches, int(total), nil -} - -func (self *SRegion) GetVSwitchAttributes(idstr string) (*SVSwitch, error) { - params := make(map[string]string) - params["VSwitchId"] = idstr - - body, err := self.vpcRequest("DescribeVSwitchAttributes", params) - if err != nil { - log.Errorf("DescribeVSwitchAttributes fail %s", err) - return nil, err - } - if self.client.debug { - log.Debugf("%s", body.PrettyString()) - } - switches := SVSwitch{} - err = body.Unmarshal(&switches) - if err != nil { - log.Errorf("Unmarshal vswitches fail %s", err) - return nil, err - } - return &switches, nil -} - -func (vsw *SVSwitch) dissociateWithSNAT() error { - natgatways, err := vsw.wire.vpc.getNatGateways() - if err != nil { - return err - } - for i := range natgatways { - err = natgatways[i].dissociateWithVswitch(vsw.VSwitchId) - if err != nil { - return err - } - } - return nil -} diff --git a/pkg/multicloud/apsara/wire.go b/pkg/multicloud/apsara/wire.go deleted file mode 100644 index a63c0132da..0000000000 --- a/pkg/multicloud/apsara/wire.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.ApsaraTags - 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) IsEmulated() bool { - return true -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SWire) Refresh() error { - return nil -} - -func (self *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.zone.GetGlobalId()) -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -func (self *SWire) addNetwork(vswitch *SVSwitch) { - 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() == vswitch.VSwitchId { - find = true - break - } - } - if !find { - self.inetworks = append(self.inetworks, vswitch) - } -} - -func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - if self.inetworks == nil { - err := self.vpc.fetchVSwitches() - if err != nil { - return nil, err - } - } - return self.inetworks, nil -} - -func (self *SWire) getNetworkById(vswitchId string) *SVSwitch { - 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].(*SVSwitch) - if network.VSwitchId == vswitchId { - return network - } - } - return nil -} - -func (self *SWire) GetBandwidth() int { - return 10000 -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - vswitchId, err := self.zone.region.createVSwitch(self.zone.ZoneId, self.vpc.VpcId, opts.Name, opts.Cidr, opts.Desc) - if err != nil { - log.Errorf("createVSwitch error %s", err) - return nil, err - } - self.inetworks = nil - vswitch := self.getNetworkById(vswitchId) - if vswitch == nil { - log.Errorf("cannot find vswitch after create????") - return nil, cloudprovider.ErrNotFound - } - return vswitch, nil -} - -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 -} diff --git a/pkg/multicloud/apsara/zone.go b/pkg/multicloud/apsara/zone.go deleted file mode 100644 index c45f34255c..0000000000 --- a/pkg/multicloud/apsara/zone.go +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 apsara - -import ( - "fmt" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type TChargeType string - -const ( - PrePaidInstanceChargeType TChargeType = "PrePaid" - PostPaidInstanceChargeType TChargeType = "PostPaid" - PostPaidDBInstanceChargeType TChargeType = "Postpaid" - DefaultInstanceChargeType = PostPaidInstanceChargeType -) - -type SpotStrategyType string - -const ( - NoSpotStrategy SpotStrategyType = "NoSpot" - SpotWithPriceLimitStrategy SpotStrategyType = "SpotWithPriceLimit" - SpotAsPriceGoStrategy SpotStrategyType = "SpotAsPriceGo" - DefaultSpotStrategy = NoSpotStrategy -) - -type SDedicatedHostGenerations struct { - DedicatedHostGeneration []string -} - -type SVolumeCategories struct { - VolumeCategories []string -} - -type SSupportedDataDiskCategories struct { - SupportedDataDiskCategory []string -} - -type SSupportedInstanceGenerations struct { - SupportedInstanceGeneration []string -} - -type SSupportedInstanceTypeFamilies struct { - SupportedInstanceTypeFamily []string -} - -type SSupportedInstanceTypes struct { - SupportedInstanceType []string -} - -type SSupportedNetworkTypes struct { - SupportedNetworkCategory []string -} - -type SSupportedSystemDiskCategories struct { - SupportedSystemDiskCategory []string -} - -type SResourcesInfo struct { - DataDiskCategories SSupportedDataDiskCategories - InstanceGenerations SSupportedInstanceGenerations - InstanceTypeFamilies SSupportedInstanceTypeFamilies - InstanceTypes SSupportedInstanceTypes - IoOptimized bool - NetworkTypes SSupportedNetworkTypes - SystemDiskCategories SSupportedSystemDiskCategories -} - -type SResources struct { - ResourcesInfo []SResourcesInfo -} - -type SResourceCreation struct { - ResourceTypes []string -} - -type SInstanceTypes struct { - InstanceTypes []string -} - -type SDiskCategories struct { - DiskCategories []string -} - -type SDedicatedHostTypes struct { - DedicatedHostType []string -} - -type SZone struct { - multicloud.SResourceBase - multicloud.ApsaraTags - region *SRegion - - iwires []cloudprovider.ICloudWire - - host *SHost - - istorages []cloudprovider.ICloudStorage - - ZoneId string - LocalName string - DedicatedHostGenerations SDedicatedHostGenerations - AvailableVolumeCategories SVolumeCategories - /* 可供创建的具体资源,AvailableResourcesType 组成的数组 */ - AvailableResources SResources - /* 允许创建的资源类型集合 */ - AvailableResourceCreation SResourceCreation - /* 允许创建的实例规格类型 */ - AvailableInstanceTypes SInstanceTypes - /* 支持的磁盘种类集合 */ - AvailableDiskCategories SDiskCategories - AvailableDedicatedHostTypes SDedicatedHostTypes - - disks []SDisk -} - -func (self *SZone) GetId() string { - return self.ZoneId -} - -func (self *SZone) GetName() string { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_APSARA_CN, self.LocalName) -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_APSARA_EN, self.LocalName) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SZone) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneId) -} - -func (self *SZone) IsEmulated() bool { - return false -} - -func (self *SZone) GetStatus() string { - if len(self.AvailableResourceCreation.ResourceTypes) == 0 || !utils.IsInStringArray("Instance", self.AvailableResourceCreation.ResourceTypes) { - return api.ZONE_SOLDOUT - } else { - return api.ZONE_ENABLE - } -} - -func (self *SZone) Refresh() error { - // do nothing - return nil -} - -func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SZone) fetchStorages() error { - categories := self.AvailableDiskCategories.DiskCategories - // if len(self.AvailableResources.ResourcesInfo) > 0 { - // categories = self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory - // } - self.istorages = []cloudprovider.ICloudStorage{} - - for _, sc := range categories { - storage := SStorage{zone: self, storageType: sc} - self.istorages = append(self.istorages, &storage) - if sc == api.STORAGE_CLOUD_ESSD { - storage_l2 := SStorage{zone: self, storageType: api.STORAGE_CLOUD_ESSD_PL2} - self.istorages = append(self.istorages, &storage_l2) - storage_l3 := SStorage{zone: self, storageType: api.STORAGE_CLOUD_ESSD_PL3} - self.istorages = append(self.istorages, &storage_l3) - } - } - return nil -} - -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 *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - if self.istorages == nil { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "fetchStorages") - } - } - return self.istorages, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - if self.istorages == nil { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "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) getHost() *SHost { - if self.host == nil { - self.host = &SHost{zone: self} - } - return self.host -} - -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) addWire(wire *SWire) { - if self.iwires == nil { - self.iwires = make([]cloudprovider.ICloudWire, 0) - } - self.iwires = append(self.iwires, wire) -} - -func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { - return self.iwires, nil -} - -func (self *SZone) getNetworkById(vswitchId string) *SVSwitch { - 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(vswitchId) - if net != nil { - return net - } - } - return nil -} - -func (self *SZone) getSysDiskCategories() []string { - if len(self.AvailableResources.ResourcesInfo) > 0 { - if utils.IsInStringArray(api.STORAGE_CLOUD_ESSD, self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory) { - self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory = append(self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory, api.STORAGE_CLOUD_ESSD_PL2) - self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory = append(self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory, api.STORAGE_CLOUD_ESSD_PL3) - } - return self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory - } - return nil -} diff --git a/pkg/multicloud/aws/aws_test.go b/pkg/multicloud/aws/aws_test.go deleted file mode 100644 index 87964e788b..0000000000 --- a/pkg/multicloud/aws/aws_test.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "testing" -) - -func TestAwsClientConfig(t *testing.T) { - cfg := NewAwsClientConfig("", "", "", "") - if cfg.getAssumeRoleName() != DefaultAssumeRoleName { - t.Errorf("getAssumeRoleName != %s", DefaultAssumeRoleName) - } - cfg = cfg.SetAssumeRole("newRole") - if cfg.getAssumeRoleName() != "newRole" { - t.Errorf("getAssumeRoleName != newRole") - } -} diff --git a/pkg/multicloud/aws/bucket.go b/pkg/multicloud/aws/bucket.go deleted file mode 100644 index 2d5d76e903..0000000000 --- a/pkg/multicloud/aws/bucket.go +++ /dev/null @@ -1,800 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "fmt" - "io" - "net/http" - "net/url" - "strconv" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/s3" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/s3cli" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/fileutils2" -) - -type SBucket struct { - multicloud.SBaseBucket - multicloud.AwsTags - - region *SRegion - - Name string - CreationDate time.Time - Location string - - acl cloudprovider.TBucketACLType -} - -func (b *SBucket) GetProjectId() string { - return "" -} - -func (b *SBucket) GetGlobalId() string { - return b.Name -} - -func (b *SBucket) GetName() string { - return b.Name -} - -func (b *SBucket) GetLocation() string { - return b.Location -} - -func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { - return b.region -} - -func (b *SBucket) GetCreatedAt() time.Time { - return b.CreationDate -} - -func (b *SBucket) GetStorageClass() string { - return "" -} - -func s3ToCannedAcl(acls []*s3.Grant) cloudprovider.TBucketACLType { - switch { - case len(acls) == 1: - if acls[0].Grantee.URI == nil && *acls[0].Permission == s3cli.PERMISSION_FULL_CONTROL { - return cloudprovider.ACLPrivate - } - case len(acls) == 2: - for _, g := range acls { - if *g.Grantee.Type == s3cli.GRANTEE_TYPE_GROUP && *g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_AUTH_USERS && *g.Permission == s3cli.PERMISSION_READ { - return cloudprovider.ACLAuthRead - } - if *g.Grantee.Type == s3cli.GRANTEE_TYPE_GROUP && *g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && *g.Permission == s3cli.PERMISSION_READ { - return cloudprovider.ACLPublicRead - } - } - case len(acls) == 3: - for _, g := range acls { - if *g.Grantee.Type == s3cli.GRANTEE_TYPE_GROUP && *g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && *g.Permission == s3cli.PERMISSION_WRITE { - return cloudprovider.ACLPublicReadWrite - } - } - } - return cloudprovider.ACLUnknown -} - -func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - s3cli, err := b.region.GetS3Client() - if err != nil { - log.Errorf("b.region.GetS3Client fail %s", err) - return acl - } - input := &s3.GetBucketAclInput{} - input.SetBucket(b.Name) - output, err := s3cli.GetBucketAcl(input) - if err != nil { - log.Errorf("s3cli.GetBucketAcl fail %s", err) - return acl - } - return s3ToCannedAcl(output.Grants) -} - -func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error { - s3cli, err := b.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "b.region.GetS3Client") - } - input := &s3.PutBucketAclInput{} - input.SetBucket(b.Name) - input.SetACL(string(aclStr)) - _, err = s3cli.PutBucketAcl(input) - if err != nil { - return errors.Wrap(err, "PutBucketAcl") - } - return nil -} - -func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { - return []cloudprovider.SBucketAccessUrl{ - { - Url: fmt.Sprintf("https://%s.%s", b.Name, b.region.getS3Endpoint()), - Description: "bucket domain", - Primary: true, - }, - { - Url: fmt.Sprintf("https://%s/%s", b.region.getS3Endpoint(), b.Name), - Description: "s3 domain", - }, - } -} - -func (b *SBucket) GetWebsiteUrl() string { - return fmt.Sprintf("http://%s.%s", b.Name, b.region.getS3WebsiteEndpoint()) -} - -func (b *SBucket) GetStats() cloudprovider.SBucketStats { - stats, _ := cloudprovider.GetIBucketStats(b) - return stats -} - -func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { - result := cloudprovider.SListObjectResult{} - s3cli, err := b.region.GetS3Client() - if err != nil { - return result, errors.Wrap(err, "GetS3Client") - } - input := &s3.ListObjectsInput{} - input.SetBucket(b.Name) - if len(prefix) > 0 { - input.SetPrefix(prefix) - } - if len(marker) > 0 { - input.SetMarker(marker) - } - if len(delimiter) > 0 { - input.SetDelimiter(delimiter) - } - if maxCount > 0 { - input.SetMaxKeys(int64(maxCount)) - } - oResult, err := s3cli.ListObjects(input) - if err != nil { - return result, errors.Wrap(err, "ListObjects") - } - result.Objects = make([]cloudprovider.ICloudObject, 0) - for _, object := range oResult.Contents { - obj := &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - StorageClass: *object.StorageClass, - Key: *object.Key, - SizeBytes: *object.Size, - ETag: *object.ETag, - LastModified: *object.LastModified, - }, - } - result.Objects = append(result.Objects, obj) - } - if oResult.CommonPrefixes != nil { - result.CommonPrefixes = make([]cloudprovider.ICloudObject, len(oResult.CommonPrefixes)) - for i, commPrefix := range oResult.CommonPrefixes { - result.CommonPrefixes[i] = &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{Key: *commPrefix.Prefix}, - } - } - } - if oResult.IsTruncated != nil { - result.IsTruncated = *oResult.IsTruncated - } - if oResult.NextMarker != nil { - result.NextMarker = *oResult.NextMarker - } - return result, nil -} - -func (b *SBucket) PutObject(ctx context.Context, key string, body io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - if sizeBytes < 0 { - return errors.Error("content length expected") - } - s3cli, err := b.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - input := &s3.PutObjectInput{} - input.SetBucket(b.Name) - input.SetKey(key) - seeker, err := fileutils2.NewReadSeeker(body, sizeBytes) - if err != nil { - return errors.Wrap(err, "newFakeSeeker") - } - defer seeker.Close() - input.SetBody(seeker) - input.SetContentLength(sizeBytes) - if meta != nil { - metaHdr := make(map[string]*string) - for k, v := range meta { - if len(v) == 0 || len(v[0]) == 0 { - continue - } - switch http.CanonicalHeaderKey(k) { - case cloudprovider.META_HEADER_CACHE_CONTROL: - input.SetCacheControl(v[0]) - case cloudprovider.META_HEADER_CONTENT_TYPE: - input.SetContentType(v[0]) - case cloudprovider.META_HEADER_CONTENT_MD5: - input.SetContentMD5(v[0]) - case cloudprovider.META_HEADER_CONTENT_LANGUAGE: - input.SetContentLanguage(v[0]) - case cloudprovider.META_HEADER_CONTENT_ENCODING: - input.SetContentEncoding(v[0]) - case cloudprovider.META_HEADER_CONTENT_DISPOSITION: - input.SetContentDisposition(v[0]) - default: - metaHdr[k] = &v[0] - } - } - if len(metaHdr) > 0 { - input.SetMetadata(metaHdr) - } - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.SetACL(string(cannedAcl)) - if len(storageClassStr) > 0 { - input.SetStorageClass(storageClassStr) - } - _, err = s3cli.PutObjectWithContext(ctx, input) - if err != nil { - return errors.Wrap(err, "PutObjectWithContext") - } - return nil -} - -func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - s3cli, err := b.region.GetS3Client() - if err != nil { - return "", errors.Wrap(err, "GetS3Client") - } - input := &s3.CreateMultipartUploadInput{} - input.SetBucket(b.Name) - input.SetKey(key) - if meta != nil { - metaHdr := make(map[string]*string) - for k, v := range meta { - if len(v) == 0 || len(v[0]) == 0 { - continue - } - switch http.CanonicalHeaderKey(k) { - case cloudprovider.META_HEADER_CACHE_CONTROL: - input.SetCacheControl(v[0]) - case cloudprovider.META_HEADER_CONTENT_TYPE: - input.SetContentType(v[0]) - case cloudprovider.META_HEADER_CONTENT_LANGUAGE: - input.SetContentLanguage(v[0]) - case cloudprovider.META_HEADER_CONTENT_ENCODING: - input.SetContentEncoding(v[0]) - case cloudprovider.META_HEADER_CONTENT_DISPOSITION: - input.SetContentDisposition(v[0]) - default: - metaHdr[k] = &v[0] - } - } - if len(metaHdr) > 0 { - input.SetMetadata(metaHdr) - } - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.SetACL(string(cannedAcl)) - if len(storageClassStr) > 0 { - input.SetStorageClass(storageClassStr) - } - output, err := s3cli.CreateMultipartUploadWithContext(ctx, input) - if err != nil { - return "", errors.Wrap(err, "CreateMultipartUpload") - } - return *output.UploadId, nil -} - -func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, part io.Reader, partSize int64, offset, totalSize int64) (string, error) { - s3cli, err := b.region.GetS3Client() - if err != nil { - return "", errors.Wrap(err, "GetS3Client") - } - input := &s3.UploadPartInput{} - input.SetBucket(b.Name) - input.SetKey(key) - input.SetUploadId(uploadId) - input.SetPartNumber(int64(partIndex)) - seeker, err := fileutils2.NewReadSeeker(part, partSize) - if err != nil { - return "", errors.Wrap(err, "newFakeSeeker") - } - defer seeker.Close() - input.SetBody(seeker) - input.SetContentLength(partSize) - output, err := s3cli.UploadPartWithContext(ctx, input) - if err != nil { - return "", errors.Wrap(err, "UploadPartWithContext") - } - return *output.ETag, nil -} - -func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { - s3cli, err := b.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - input := &s3.CompleteMultipartUploadInput{} - input.SetBucket(b.Name) - input.SetKey(key) - input.SetUploadId(uploadId) - uploads := &s3.CompletedMultipartUpload{} - parts := make([]*s3.CompletedPart, len(partEtags)) - for i := range partEtags { - parts[i] = &s3.CompletedPart{} - parts[i].SetPartNumber(int64(i + 1)) - parts[i].SetETag(partEtags[i]) - } - uploads.SetParts(parts) - input.SetMultipartUpload(uploads) - _, err = s3cli.CompleteMultipartUploadWithContext(ctx, input) - if err != nil { - return errors.Wrap(err, "CompleteMultipartUploadWithContext") - } - return nil -} - -func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { - s3cli, err := b.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - input := &s3.AbortMultipartUploadInput{} - input.SetBucket(b.Name) - input.SetKey(key) - input.SetUploadId(uploadId) - _, err = s3cli.AbortMultipartUploadWithContext(ctx, input) - if err != nil { - return errors.Wrap(err, "AbortMultipartUploadWithContext") - } - return nil -} - -func (b *SBucket) DeleteObject(ctx context.Context, key string) error { - s3cli, err := b.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - input := &s3.DeleteObjectInput{} - input.SetBucket(b.Name) - input.SetKey(key) - _, err = s3cli.DeleteObjectWithContext(ctx, input) - if err != nil { - return errors.Wrap(err, "DeleteObject") - } - return nil -} - -func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { - s3cli, err := b.region.GetS3Client() - if err != nil { - return "", errors.Wrap(err, "GetS3Client") - } - var request *request.Request - switch method { - case "GET": - input := &s3.GetObjectInput{} - input.SetBucket(b.Name) - input.SetKey(key) - request, _ = s3cli.GetObjectRequest(input) - case "PUT": - input := &s3.PutObjectInput{} - input.SetBucket(b.Name) - input.SetKey(key) - request, _ = s3cli.PutObjectRequest(input) - case "DELETE": - input := &s3.DeleteObjectInput{} - input.SetBucket(b.Name) - input.SetKey(key) - request, _ = s3cli.DeleteObjectRequest(input) - default: - return "", errors.Error("unsupported method") - } - url, _, err := request.PresignRequest(expire) - if err != nil { - return "", errors.Wrap(err, "request.PresignRequest") - } - return url, nil -} - -func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - s3cli, err := b.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - log.Debugf("copy from %s/%s to %s/%s", srcBucket, srcKey, b.Name, destKey) - input := &s3.CopyObjectInput{} - input.SetBucket(b.Name) - input.SetKey(destKey) - input.SetCopySource(fmt.Sprintf("%s/%s", srcBucket, url.PathEscape(srcKey))) - input.SetStorageClass(storageClassStr) - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.SetACL(string(cannedAcl)) - var metaDir string - if meta != nil { - metaHdr := make(map[string]*string) - for k, v := range meta { - if len(v) == 0 || len(v[0]) == 0 { - continue - } - switch http.CanonicalHeaderKey(k) { - case cloudprovider.META_HEADER_CACHE_CONTROL: - input.SetCacheControl(v[0]) - case cloudprovider.META_HEADER_CONTENT_TYPE: - input.SetContentType(v[0]) - case cloudprovider.META_HEADER_CONTENT_LANGUAGE: - input.SetContentLanguage(v[0]) - case cloudprovider.META_HEADER_CONTENT_ENCODING: - input.SetContentEncoding(v[0]) - case cloudprovider.META_HEADER_CONTENT_DISPOSITION: - input.SetContentDisposition(v[0]) - default: - metaHdr[k] = &v[0] - } - } - if len(metaHdr) > 0 { - input.SetMetadata(metaHdr) - } - metaDir = "REPLACE" - } else { - metaDir = "COPY" - } - input.SetMetadataDirective(metaDir) - _, err = s3cli.CopyObject(input) - if err != nil { - return errors.Wrap(err, "CopyObject") - } - return nil -} - -func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { - s3cli, err := b.region.GetS3Client() - if err != nil { - return nil, errors.Wrap(err, "GetS3Client") - } - input := &s3.GetObjectInput{} - input.SetBucket(b.Name) - input.SetKey(key) - if rangeOpt != nil { - input.SetRange(rangeOpt.String()) - } - output, err := s3cli.GetObject(input) - if err != nil { - return nil, errors.Wrap(err, "GetObject") - } - return output.Body, nil -} - -func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partNumber int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { - s3cli, err := b.region.GetS3Client() - if err != nil { - return "", errors.Wrap(err, "GetS3Client") - } - input := &s3.UploadPartCopyInput{} - input.SetBucket(b.Name) - input.SetKey(key) - input.SetUploadId(uploadId) - input.SetPartNumber(int64(partNumber)) - input.SetCopySource(fmt.Sprintf("/%s/%s", srcBucket, url.PathEscape(srcKey))) - if srcLength > 0 { - input.SetCopySourceRange(fmt.Sprintf("bytes=%d-%d", srcOffset, srcOffset+srcLength-1)) - } - output, err := s3cli.UploadPartCopy(input) - if err != nil { - return "", errors.Wrap(err, "s3cli.UploadPartCopy") - } - return *output.CopyPartResult.ETag, nil -} - -func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { - s3cli, err := b.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - s3WebConf := s3.WebsiteConfiguration{} - s3WebConf.SetIndexDocument(&s3.IndexDocument{Suffix: &websitConf.Index}) - s3WebConf.SetErrorDocument(&s3.ErrorDocument{Key: &websitConf.ErrorDocument}) - input := s3.PutBucketWebsiteInput{} - input.SetBucket(b.Name) - input.SetWebsiteConfiguration(&s3WebConf) - _, err = s3cli.PutBucketWebsite(&input) - if err != nil { - return errors.Wrapf(err, "s3cli.PutBucketWebsite(%s)", jsonutils.Marshal(input).String()) - } - return nil -} - -func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { - result := cloudprovider.SBucketWebsiteConf{} - s3cli, err := b.region.GetS3Client() - if err != nil { - return result, errors.Wrap(err, "GetS3Client") - } - input := s3.GetBucketWebsiteInput{} - input.SetBucket(b.Name) - webconfResult, err := s3cli.GetBucketWebsite(&input) - if err != nil { - return result, errors.Wrapf(err, "s3cli.GetBucketWebsite(%s)", b.Name) - } - - if webconfResult.IndexDocument != nil && webconfResult.IndexDocument.Suffix != nil { - result.Index = *webconfResult.IndexDocument.Suffix - } - if webconfResult.ErrorDocument != nil && webconfResult.ErrorDocument.Key != nil { - result.ErrorDocument = *webconfResult.ErrorDocument.Key - } - result.Url = b.GetWebsiteUrl() - return result, nil -} - -func (b *SBucket) DeleteWebSiteConf() error { - s3cli, err := b.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - input := s3.DeleteBucketWebsiteInput{} - input.SetBucket(b.Name) - _, err = s3cli.DeleteBucketWebsite(&input) - if err != nil { - return errors.Wrapf(err, "s3cli.DeleteBucketWebsite(%s)", b.Name) - } - return nil -} - -func InputToAwsApiSliceString(input []string) []*string { - result := []*string{} - for i := range input { - result = append(result, &input[i]) - } - return result -} - -func InputToAwsApiInt64(input int64) *int64 { - return &input -} - -func AwsApiSliceStringToOutput(input []*string) []string { - result := []string{} - for i := range input { - if input[i] != nil { - result = append(result, *input[i]) - } else { - result = append(result, "") - } - } - return result -} - -func AwsApiInt64ToOutput(input *int64) int64 { - if input == nil { - return 0 - } - return *input -} - -func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { - s3cli, err := b.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - opts := []*s3.CORSRule{} - for i := range rules { - opts = append(opts, &s3.CORSRule{ - AllowedOrigins: InputToAwsApiSliceString(rules[i].AllowedOrigins), - AllowedMethods: InputToAwsApiSliceString(rules[i].AllowedMethods), - AllowedHeaders: InputToAwsApiSliceString(rules[i].AllowedHeaders), - MaxAgeSeconds: InputToAwsApiInt64(int64(rules[i].MaxAgeSeconds)), - ExposeHeaders: InputToAwsApiSliceString(rules[i].ExposeHeaders), - }) - } - - input := s3.PutBucketCorsInput{} - input.SetBucket(b.Name) - input.SetCORSConfiguration(&s3.CORSConfiguration{CORSRules: opts}) - _, err = s3cli.PutBucketCors(&input) - if err != nil { - return errors.Wrapf(err, "s3cli.PutBucketCors(%s)", input) - } - return nil -} - -func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { - s3cli, err := b.region.GetS3Client() - if err != nil { - return nil, errors.Wrap(err, "GetS3Client") - } - input := s3.GetBucketCorsInput{} - input.SetBucket(b.Name) - conf, err := s3cli.GetBucketCors(&input) - if err != nil { - if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") { - return nil, errors.Wrapf(err, "s3cli.GetBucketCors(%s)", b.Name) - } - } - if conf == nil { - return nil, nil - } - result := []cloudprovider.SBucketCORSRule{} - for i := range conf.CORSRules { - result = append(result, cloudprovider.SBucketCORSRule{ - AllowedOrigins: AwsApiSliceStringToOutput(conf.CORSRules[i].AllowedOrigins), - AllowedMethods: AwsApiSliceStringToOutput(conf.CORSRules[i].AllowedMethods), - AllowedHeaders: AwsApiSliceStringToOutput(conf.CORSRules[i].AllowedHeaders), - MaxAgeSeconds: int(AwsApiInt64ToOutput(conf.CORSRules[i].MaxAgeSeconds)), - ExposeHeaders: AwsApiSliceStringToOutput(conf.CORSRules[i].ExposeHeaders), - Id: strconv.Itoa(i), - }) - } - return result, nil -} - -func (b *SBucket) DeleteCORS() error { - s3cli, err := b.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - - input := s3.DeleteBucketCorsInput{} - input.SetBucket(b.Name) - _, err = s3cli.DeleteBucketCors(&input) - if err != nil { - return errors.Wrapf(err, "s3cli.DeleteBucketCors(%s)", b.Name) - } - return nil -} - -func (b *SBucket) GetTags() (map[string]string, error) { - s3cli, err := b.region.GetS3Client() - if err != nil { - return nil, errors.Wrap(err, "GetS3Client") - } - tagresult, err := s3cli.GetBucketTagging(&s3.GetBucketTaggingInput{Bucket: &b.Name}) - if err != nil { - if strings.Contains(err.Error(), "NoSuchTagSet") { - return nil, nil - } - return nil, errors.Wrapf(err, "osscli.GetBucketTagging(%s)", b.Name) - } - if tagresult == nil { - return nil, nil - } - result := map[string]string{} - for i := range tagresult.TagSet { - if tagresult.TagSet[i].Key != nil && tagresult.TagSet[i].Value != nil { - result[*tagresult.TagSet[i].Key] = *tagresult.TagSet[i].Value - } - - } - return result, nil -} - -func (b *SBucket) SetTags(tags map[string]string, replace bool) error { - if !replace { - return cloudprovider.ErrNotSupported - } - s3cli, err := b.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - - _, err = s3cli.DeleteBucketTagging(&s3.DeleteBucketTaggingInput{Bucket: &b.Name}) - if err != nil { - return errors.Wrapf(err, "DeleteBucketTagging") - } - - if len(tags) == 0 { - return nil - } - - input := s3.PutBucketTaggingInput{Tagging: &s3.Tagging{}} - input.Bucket = &b.Name - apiTagKeys := []string{} - apiTagValues := []string{} - for k, v := range tags { - apiTagKeys = append(apiTagKeys, k) - apiTagValues = append(apiTagValues, v) - - } - for i := range apiTagKeys { - input.Tagging.TagSet = append(input.Tagging.TagSet, &s3.Tag{Key: &apiTagKeys[i], Value: &apiTagValues[i]}) - } - - _, err = s3cli.PutBucketTagging(&input) - if err != nil { - return errors.Wrapf(err, "obscli.SetBucketTagging(%s)", jsonutils.Marshal(input)) - } - return nil -} - -func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { - s3cli, err := b.region.GetS3Client() - if err != nil { - return nil, errors.Wrap(err, "GetS3Client") - } - result := []cloudprovider.SBucketMultipartUploads{} - - input := s3.ListMultipartUploadsInput{} - input.SetBucket(b.Name) - keyMarker := "" - uploadIDMarker := "" - for { - if len(keyMarker) > 0 { - input.SetKeyMarker(keyMarker) - } - if len(uploadIDMarker) > 0 { - input.SetUploadIdMarker(uploadIDMarker) - } - output, err := s3cli.ListMultipartUploads(&input) - if err != nil { - return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") - } - if output == nil { - return nil, nil - } - for i := range output.Uploads { - temp := cloudprovider.SBucketMultipartUploads{} - if output.Uploads[i].Key != nil { - temp.ObjectName = *output.Uploads[i].Key - } - if output.Uploads[i].Initiator != nil { - temp.Initiator = *output.Uploads[i].Initiator.DisplayName - } - if output.Uploads[i].Initiated != nil { - temp.Initiated = *output.Uploads[i].Initiated - } - if output.Uploads[i].UploadId != nil { - temp.UploadID = *output.Uploads[i].UploadId - } - result = append(result, temp) - } - if output.NextKeyMarker != nil { - keyMarker = *output.NextKeyMarker - } - if output.NextUploadIdMarker != nil { - uploadIDMarker = *output.NextUploadIdMarker - } - - if output.IsTruncated == nil || !*output.IsTruncated { - break - } - } - - return result, nil -} diff --git a/pkg/multicloud/aws/cloudtrail.go b/pkg/multicloud/aws/cloudtrail.go deleted file mode 100644 index c34a11aeed..0000000000 --- a/pkg/multicloud/aws/cloudtrail.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/cloudtrail" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SEventResource struct { - // The name of the resource referenced by the event returned. These are user-created - // names whose values will depend on the environment. For example, the resource - // name might be "auto-scaling-test-group" for an Auto Scaling Group or "i-1234567" - // for an EC2 Instance. - ResourceName string `type:"string"` - - // The type of a resource referenced by the event returned. When the resource - // type cannot be determined, null is returned. Some examples of resource types - // are: Instance for EC2, Trail for CloudTrail, DBInstance for RDS, and AccessKey - // for IAM. To learn more about how to look up and filter events by the resource - // types supported for a service, see Filtering CloudTrail Events (https://docs.aws.amazon.com/awscloudtrail/latest/userguide/view-cloudtrail-events-console.html#filtering-cloudtrail-events). - ResourceType string `type:"string"` -} - -type SEvent struct { - // The AWS access key ID that was used to sign the request. If the request was - // made with temporary security credentials, this is the access key ID of the - // temporary credentials. - AccessKeyId string `type:"string"` - - // A JSON string that contains a representation of the event returned. - CloudTrailEvent string `type:"string"` - - // The CloudTrail ID of the event returned. - EventId string `type:"string"` - - // The name of the event returned. - EventName string `type:"string"` - - // The AWS service that the request was made to. - EventSource string `type:"string"` - - // The date and time of the event returned. - EventTime time.Time `type:"timestamp"` - - // Information about whether the event is a write event or a read event. - ReadOnly string `type:"string"` - - // A list of resources referenced by the event returned. - Resources []SEventResource `type:"list"` - - // A user name or role name of the requester that called the API in the event - // returned. - Username string `type:"string"` -} - -func (self *SEvent) GetName() string { - return self.EventName -} - -func (self *SEvent) GetService() string { - return self.EventSource -} - -func (self *SEvent) GetAction() string { - return self.EventName -} - -func (self *SEvent) GetResourceType() string { - return self.EventSource -} - -func (self *SEvent) GetRequestId() string { - return self.EventId -} - -func (self *SEvent) GetRequest() jsonutils.JSONObject { - obj, _ := jsonutils.Parse([]byte(self.CloudTrailEvent)) - return obj -} - -func (self *SEvent) GetAccount() string { - return fmt.Sprintf("%s(%s)", self.AccessKeyId, self.Username) -} - -func (self *SEvent) IsSuccess() bool { - return !strings.Contains(self.CloudTrailEvent, "errorMessage") -} - -func (self *SEvent) GetCreatedAt() time.Time { - return self.EventTime -} - -func (self *SRegion) getAwsCloudtrailSession() (*session.Session, error) { - session, err := self.getAwsSession() - if err != nil { - return nil, errors.Wrap(err, "client.getDefaultSession()") - } - session.ClientConfig(CLOUD_TRAIL_SERVICE_NAME) - return session, nil -} - -func (self *SRegion) LookupEvents(start, end time.Time, withReadEvent bool) ([]SEvent, error) { - s, err := self.getAwsCloudtrailSession() - if err != nil { - return nil, errors.Wrapf(err, "getAwsCloudtrailSession") - } - client := cloudtrail.New(s) - input := &cloudtrail.LookupEventsInput{LookupAttributes: []*cloudtrail.LookupAttribute{}} - if !start.IsZero() { - input.SetStartTime(start) - } - if !end.IsZero() { - input.SetEndTime(end) - } - if !withReadEvent { - readonly := "ReadOnly" - val := "false" - input.LookupAttributes = append(input.LookupAttributes, &cloudtrail.LookupAttribute{ - AttributeKey: &readonly, - AttributeValue: &val, - }) - } - events := []SEvent{} - nextToken := "" - for { - if len(nextToken) > 0 { - input.SetNextToken(nextToken) - } - var output *cloudtrail.LookupEventsOutput = nil - for { - output, err = client.LookupEvents(input) - if err != nil { - if strings.Contains(err.Error(), "ThrottlingException") { - log.Warningf("LookupEvents ThrottlingException, try after 3 seconds") - time.Sleep(time.Second * 3) - continue - } - return nil, errors.Wrapf(err, "LookupEvents(%s, %s)", start, end) - } - break - } - for i := range output.Events { - err := FillZero(output.Events[i]) - if err != nil { - return nil, errors.Wrapf(err, "FillZero") - } - event := SEvent{} - err = jsonutils.Update(&event, jsonutils.Marshal(output.Events[i])) - if err != nil { - return nil, errors.Wrapf(err, "jsonutils.Update") - } - if strings.Contains(event.CloudTrailEvent, "awsRegion") && !strings.Contains(event.CloudTrailEvent, fmt.Sprintf(`"awsRegion":"%s"`, self.RegionId)) { - continue - } - events = append(events, event) - } - nextToken = "" - if output.NextToken != nil { - nextToken = *output.NextToken - } - if len(nextToken) == 0 { - break - } - } - return events, nil -} - -func (self *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { - events, err := self.LookupEvents(start, end, withReadEvent) - if err != nil { - return nil, errors.Wrapf(err, "LookupEvents(%s, %s)", start, end) - } - ret := []cloudprovider.ICloudEvent{} - for i := range events { - ret = append(ret, &events[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/aws/dbinstance.go b/pkg/multicloud/aws/dbinstance.go deleted file mode 100644 index b321749b5a..0000000000 --- a/pkg/multicloud/aws/dbinstance.go +++ /dev/null @@ -1,655 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBParameterGroup struct { - DBParameterGroupName string `xml:"DBParameterGroupName"` - ParameterApplyStatus string `xml:"ParameterApplyStatus"` -} - -type SOptionGroupMembership struct { - OptionGroupName string `xml:"OptionGroupName"` - Status string `xml:"Status"` -} - -type SEndpoint struct { - HostedZoneId string `xml:"HostedZoneId"` - Address string `xml:"Address"` - Port int `xml:"Port"` -} - -type SSubnetAvailabilityZone struct { - Name string `xml:"Name"` -} - -type SSubnet struct { - SubnetIdentifier string `xml:"SubnetIdentifier"` - SubnetStatus string `xml:"SubnetStatus"` - SubnetAvailabilityZone SSubnetAvailabilityZone `xml:"SubnetAvailabilityZone"` -} - -type SDBSubnetGroup struct { - VpcId string `xml:"VpcId"` - Subnets []SSubnet `xml:"Subnets>Subnet"` - SubnetGroupStatus string `xml:"SubnetGroupStatus"` - DBSubnetGroupDescription string `xml:"DBSubnetGroupDescription"` - DBSubnetGroupName string `xml:"DBSubnetGroupName"` -} - -type SVpcSecurityGroupMembership struct { - VpcSecurityGroupId string `xml:"VpcSecurityGroupId"` - Status string `xml:"Status"` -} - -type SVpcSecurityGroups struct { - VpcSecurityGroupMembership SVpcSecurityGroupMembership `xml:"VpcSecurityGroupMembership"` -} - -type SDBInstance struct { - multicloud.SDBInstanceBase - multicloud.AwsTags - - region *SRegion - - AllocatedStorage int `xml:"AllocatedStorage"` - //AssociatedRoles string `xml:"AssociatedRoles"` - DBParameterGroups []SDBParameterGroup `xml:"DBParameterGroups>DBParameterGroup"` - AvailabilityZone string `xml:"AvailabilityZone"` - DBSecurityGroups string `xml:"DBSecurityGroups"` - EngineVersion string `xml:"EngineVersion"` - MasterUsername string `xml:"MasterUsername"` - InstanceCreateTime time.Time `xml:"InstanceCreateTime"` - DBInstanceClass string `xml:"DBInstanceClass"` - HttpEndpointEnabled bool `xml:"HttpEndpointEnabled"` - //ReadReplicaDBInstanceIdentifiers string `xml:"ReadReplicaDBInstanceIdentifiers"` - MonitoringInterval int `xml:"MonitoringInterval"` - DBInstanceStatus string `xml:"DBInstanceStatus"` - BackupRetentionPeriod int `xml:"BackupRetentionPeriod"` - OptionGroupMemberships []SOptionGroupMembership `xml:"OptionGroupMemberships>OptionGroupMembership"` - CACertificateIdentifier string `xml:"CACertificateIdentifier"` - DbInstancePort int `xml:"DbInstancePort"` - DbiResourceId string `xml:"DbiResourceId"` - PreferredBackupWindow string `xml:"PreferredBackupWindow"` - DeletionProtection bool `xml:"DeletionProtection"` - DBInstanceIdentifier string `xml:"DBInstanceIdentifier"` - DBInstanceArn string `xml:"DBInstanceArn"` - Endpoint SEndpoint `xml:"Endpoint"` - Engine string `xml:"Engine"` - PubliclyAccessible bool `xml:"PubliclyAccessible"` - IAMDatabaseAuthenticationEnabled bool `xml:"IAMDatabaseAuthenticationEnabled"` - PerformanceInsightsEnabled bool `xml:"PerformanceInsightsEnabled"` - DBName string `xml:"DBName"` - MultiAZ bool `xml:"MultiAZ"` - //DomainMemberships string `xml:"DomainMemberships"` - StorageEncrypted bool `xml:"StorageEncrypted"` - DBSubnetGroup SDBSubnetGroup `xml:"DBSubnetGroup"` - VpcSecurityGroups SVpcSecurityGroups `xml:"VpcSecurityGroups"` - LicenseModel string `xml:"LicenseModel"` - PreferredMaintenanceWindow string `xml:"PreferredMaintenanceWindow"` - StorageType string `xml:"StorageType"` - AutoMinorVersionUpgrade bool `xml:"AutoMinorVersionUpgrade"` - CopyTagsToSnapshot bool `xml:"CopyTagsToSnapshot"` -} - -type SDBInstances struct { - DBInstances []SDBInstance `xml:"DBInstances>DBInstance"` - Marker string `xml:"Marker"` -} - -func (rds *SDBInstance) GetName() string { - return rds.DBInstanceIdentifier -} - -func (rds *SDBInstance) GetId() string { - return rds.DbiResourceId -} - -func (rds *SDBInstance) GetGlobalId() string { - return rds.GetId() -} - -// https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/accessing-monitoring.html#Overview.DBInstance.Status -func (rds *SDBInstance) GetStatus() string { - switch rds.DBInstanceStatus { - case "creating", "backing-up": - return api.DBINSTANCE_DEPLOYING - case "available": - return api.DBINSTANCE_RUNNING - case "deleting": - return api.DBINSTANCE_DELETING - case "rebooting": - return api.DBINSTANCE_REBOOTING - default: - log.Errorf("Unknown db instance status: %s", rds.DBInstanceStatus) - return api.DBINSTANCE_UNKNOWN - } -} - -func (rds *SDBInstance) GetBillingType() string { - return billing.BILLING_TYPE_POSTPAID -} - -func (rds *SDBInstance) GetExpiredAt() time.Time { - return time.Time{} -} - -func (rds *SDBInstance) GetCreatedAt() time.Time { - return rds.InstanceCreateTime -} - -func (rds *SDBInstance) Reboot() error { - return rds.region.RebootDBInstance(rds.DBInstanceIdentifier) -} - -func (self *SDBInstance) GetCategory() string { - switch self.Engine { - case "aurora", "aurora-mysql": - return api.DBINSTANCE_TYPE_MYSQL - case "aurora-postgresql": - return api.DBINSTANCE_TYPE_POSTGRESQL - case "oracle-ee", "sqlserver-ee": - return api.AWS_DBINSTANCE_CATEGORY_ENTERPRISE_EDITION - case "oracle-se2": - return api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION_TWO - case "sqlserver-se": - return api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION - case "sqlserver-ex": - return api.AWS_DBINSTANCE_CATEGORY_EXPRESS_EDITION - case "sqlserver-web": - return api.AWS_DBINSTANCE_CATEGORY_WEB_EDITION - default: - if strings.HasPrefix(self.DBInstanceClass, "db.r") || strings.HasPrefix(self.DBInstanceClass, "db.x") || strings.HasPrefix(self.DBInstanceClass, "db.d") { - return api.AWS_DBINSTANCE_CATEGORY_MEMORY_OPTIMIZED - } - return api.AWS_DBINSTANCE_CATEGORY_GENERAL_PURPOSE - } -} - -func (rds *SDBInstance) GetStorageType() string { - return rds.StorageType -} - -func (rds *SDBInstance) GetEngine() string { - if strings.Contains(rds.Engine, "aurora") { - return api.DBINSTANCE_TYPE_AURORA - } - if strings.Contains(rds.Engine, "oracle") { - return api.DBINSTANCE_TYPE_ORACLE - } - if strings.Contains(rds.Engine, "sqlserver") { - return api.DBINSTANCE_TYPE_SQLSERVER - } - for k, v := range map[string]string{ - "mariadb": api.DBINSTANCE_TYPE_MARIADB, - "mysql": api.DBINSTANCE_TYPE_MYSQL, - "postgres": api.DBINSTANCE_TYPE_POSTGRESQL, - } { - if rds.Engine == k { - return v - } - } - return rds.Engine -} - -func (rds *SDBInstance) GetEngineVersion() string { - return rds.EngineVersion -} - -func (rds *SDBInstance) GetInstanceType() string { - return rds.DBInstanceClass -} - -func (rds *SDBInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedDBInstanceChangeConfig) error { - params := map[string]string{ - "DBInstanceIdentifier": rds.DBInstanceIdentifier, - "ApplyImmediately": "true", - } - if config.DiskSizeGB > 0 && rds.GetEngine() != api.DBINSTANCE_TYPE_AURORA { - params["AllocatedStorage"] = fmt.Sprintf("%d", config.DiskSizeGB) - } - if len(config.InstanceType) > 0 { - params["DBInstanceClass"] = config.InstanceType - } - return rds.region.rdsRequest("ModifyDBInstance", params, nil) -} - -func (rds *SDBInstance) GetVcpuCount() int { - if spec, ok := DBInstanceSpecs[rds.DBInstanceClass]; ok { - return spec.VcpuCount - } - return 0 -} - -func (rds *SDBInstance) GetVmemSizeMB() int { - if spec, ok := DBInstanceSpecs[rds.DBInstanceClass]; ok { - return spec.VmemSizeMb - } - return 0 -} - -func (rds *SDBInstance) GetDiskSizeGB() int { - return rds.AllocatedStorage -} - -func (rds *SDBInstance) GetPort() int { - return rds.Endpoint.Port -} - -func (rds *SDBInstance) GetMaintainTime() string { - return rds.PreferredMaintenanceWindow -} - -func (rds *SDBInstance) GetIVpcId() string { - return rds.DBSubnetGroup.VpcId -} - -func (rds *SDBInstance) Refresh() error { - instance, err := rds.region.GetDBInstance(rds.DbiResourceId) - if err != nil { - return err - } - rds.AwsTags = instance.AwsTags - return jsonutils.Update(rds, instance) -} - -func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { - instances, _, err := region.GetDBInstances(instanceId, "") - if err != nil { - return nil, errors.Wrap(err, "GetDBInstances") - } - - if len(instances) == 1 { - if instances[0].DbiResourceId == instanceId { - instances[0].region = region - return &instances[0], nil - } - return nil, cloudprovider.ErrNotFound - } - - if len(instances) == 0 { - return nil, cloudprovider.ErrNotFound - } - - return nil, cloudprovider.ErrDuplicateId -} - -func (rds *SDBInstance) GetZone1Id() string { - if len(rds.AvailabilityZone) > 0 { - zone, err := rds.region.getZoneById(rds.AvailabilityZone) - if err != nil { - log.Errorf("rds.GetIZoneId %s error: %v", rds.DBInstanceIdentifier, err) - return "" - } - return zone.GetGlobalId() - } - return "" -} - -func (rds *SDBInstance) GetZone2Id() string { - return "" -} - -func (rds *SDBInstance) GetZone3Id() string { - return "" -} - -func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { - accounts := []cloudprovider.ICloudDBInstanceAccount{} - if len(rds.MasterUsername) > 0 { - account := &SDBInstanceAccount{instance: rds, AccountName: rds.MasterUsername} - accounts = append(accounts, account) - } - return accounts, nil -} - -func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { - return []cloudprovider.SDBInstanceNetwork{}, nil -} - -func (rds *SDBInstance) GetInternalConnectionStr() string { - return rds.Endpoint.Address -} - -func (rds *SDBInstance) GetConnectionStr() string { - if rds.PubliclyAccessible { - return rds.Endpoint.Address - } - return "" -} - -func (rds *SDBInstance) OpenPublicConnection() error { - params := map[string]string{ - "DBInstanceIdentifier": rds.DBInstanceIdentifier, - "PubliclyAccessible": "true", - } - return rds.region.rdsRequest("ModifyDBInstance", params, nil) -} - -func (rds *SDBInstance) ClosePublicConnection() error { - params := map[string]string{ - "DBInstanceIdentifier": rds.DBInstanceIdentifier, - "PubliclyAccessible": "false", - } - return rds.region.rdsRequest("ModifyDBInstance", params, nil) -} - -func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { - parameters, err := rds.region.GetDBInstanceParameters(rds.DBParameterGroups[0].DBParameterGroupName) - if err != nil { - return nil, errors.Wrap(err, "GetDBInstanceParameters") - } - iparams := []cloudprovider.ICloudDBInstanceParameter{} - for i := 0; i < len(parameters); i++ { - parameters[i].instance = rds - iparams = append(iparams, ¶meters[i]) - } - return iparams, nil -} - -func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { - idatabases := []cloudprovider.ICloudDBInstanceDatabase{} - if len(rds.DBName) > 0 { - database := &SDBInstanceDatabase{DBName: rds.DBName} - idatabases = append(idatabases, database) - } - return idatabases, nil -} - -func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - backups, err := rds.region.GetDBInstanceSnapshots(rds.DBInstanceIdentifier, "") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudDBInstanceBackup{} - for i := range backups { - backups[i].region = rds.region - ret = append(ret, &backups[i]) - } - return ret, nil -} - -func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { - params := map[string]string{ - "DBInstanceIdentifier": rds.DBInstanceIdentifier, - "DBSnapshotIdentifier": conf.Name, - } - ret := struct { - DBSnapshot SDBInstanceSnapshot `xml:"DBSnapshot"` - }{} - err := rds.region.rdsRequest("CreateDBSnapshot", params, &ret) - if err != nil { - return "", err - } - ret.DBSnapshot.region = rds.region - cloudprovider.WaitStatus(&ret.DBSnapshot, api.DBINSTANCE_BACKUP_READY, time.Second*10, time.Hour*2) - return ret.DBSnapshot.GetGlobalId(), nil -} - -func (region *SRegion) GetDBInstances(instanceId, marker string) ([]SDBInstance, string, error) { - instances := SDBInstances{} - params := map[string]string{} - idx := 1 - if len(instanceId) > 0 { - params[fmt.Sprintf("Filters.Filter.%d.Name", idx)] = "dbi-resource-id" - params[fmt.Sprintf("Filters.Filter.%d.Values.Value.1", idx)] = instanceId - } - - if len(marker) > 0 { - params["Marker"] = marker - } - - err := region.rdsRequest("DescribeDBInstances", params, &instances) - if err != nil { - return nil, "", errors.Wrap(err, "DescribeDBInstances") - } - return instances.DBInstances, instances.Marker, nil -} - -func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - idbinstances := []cloudprovider.ICloudDBInstance{} - instances, marker, err := region.GetDBInstances("", "") - if err != nil { - return nil, errors.Wrap(err, "GetDBInstances") - } - for i := 0; i < len(instances); i++ { - instances[i].region = region - idbinstances = append(idbinstances, &instances[i]) - } - for len(marker) > 0 { - instances, marker, err = region.GetDBInstances("", marker) - if err != nil { - return nil, errors.Wrap(err, "GetDBInstances") - } - for i := 0; i < len(instances); i++ { - instances[i].region = region - idbinstances = append(idbinstances, &instances[i]) - } - } - return idbinstances, nil -} - -func (self *SRegion) GetIDBInstanceById(id string) (cloudprovider.ICloudDBInstance, error) { - instances, _, err := self.GetDBInstances(id, "") - if err != nil { - return nil, errors.Wrap(err, "GetDBInstances") - } - - if len(instances) > 1 { - return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, id) - } - - if len(instances) == 0 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) - } - - instances[0].region = self - return &instances[0], nil -} - -func (self *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - params := map[string]string{ - "DBInstanceClass": desc.InstanceType, - "DBInstanceIdentifier": desc.Name, - "EngineVersion": desc.EngineVersion, - "MasterUsername": "admin", - } - if len(desc.Password) > 0 { - params["MasterUserPassword"] = desc.Password - } - - if desc.Engine != api.DBINSTANCE_TYPE_AURORA { - params["StorageType"] = desc.StorageType - params["AllocatedStorage"] = fmt.Sprintf("%d", desc.DiskSizeGB) - for i, sec := range desc.SecgroupIds { - params[fmt.Sprintf("VpcSecurityGroupIds.VpcSecurityGroupId.%d", i+1)] = sec - } - } - if desc.MultiAz { - params["MultiAZ"] = "true" - } - if desc.StorageType == api.STORAGE_IO1_SSD { - params["Iops"] = "3000" - } - switch desc.Engine { - case api.DBINSTANCE_TYPE_MYSQL: - params["Engine"] = "mysql" - case api.DBINSTANCE_TYPE_POSTGRESQL: - params["Engine"] = "postgres" - params["MasterUsername"] = "postgres" - case api.DBINSTANCE_TYPE_MARIADB: - params["Engine"] = "mariadb" - case api.DBINSTANCE_TYPE_SQLSERVER: - params["LicenseModel"] = "license-included" - switch desc.Category { - case api.AWS_DBINSTANCE_CATEGORY_ENTERPRISE_EDITION: - params["Engine"] = "sqlserver-ee" - case api.AWS_DBINSTANCE_CATEGORY_EXPRESS_EDITION: - params["Engine"] = "sqlserver-ex" - params["MultiAZ"] = "false" - case api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION: - params["Engine"] = "sqlserver-se" - case api.AWS_DBINSTANCE_CATEGORY_WEB_EDITION: - params["Engine"] = "sqlserver-web" - params["MultiAZ"] = "false" - default: - return nil, fmt.Errorf("invalid category %s for engine %s", desc.Category, desc.Engine) - } - case api.DBINSTANCE_TYPE_AURORA: - delete(params, "MultiAZ") - switch desc.Category { - case api.DBINSTANCE_TYPE_MYSQL: - params["Engine"] = "aurora" - if !strings.HasPrefix(desc.EngineVersion, "5.6") { - params["Engine"] = "aurora-mysql" - } - case api.DBINSTANCE_TYPE_POSTGRESQL: - params["Engine"] = "aurora-postgresql" - params["MasterUsername"] = "postgres" - default: - return nil, fmt.Errorf("invalid category %s for engine %s", desc.Category, desc.Engine) - } - case api.DBINSTANCE_TYPE_ORACLE: - params["LicenseModel"] = "bring-your-own-license" - switch desc.Category { - case api.AWS_DBINSTANCE_CATEGORY_ENTERPRISE_EDITION: - params["Engine"] = "oracle-ee" - case api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION_TWO: - params["Engine"] = "oracle-se2" - default: - return nil, fmt.Errorf("invalid category %s for engine %s", desc.Category, desc.Engine) - } - } - i := 1 - for k, v := range desc.Tags { - params[fmt.Sprintf("Tags.Tag.%d.Key", i)] = k - params[fmt.Sprintf("Tags.Tag.%d.Value", i)] = v - i++ - } - result := struct { - DBInstance SDBInstance `xml:"DBInstance"` - }{} - result.DBInstance.region = self - return &result.DBInstance, self.rdsRequest("CreateDBInstance", params, &result) -} - -func (self *SDBInstance) Delete() error { - params := map[string]string{ - "DBInstanceIdentifier": self.DBInstanceIdentifier, - "SkipFinalSnapshot": "true", - } - return self.region.rdsRequest("DeleteDBInstance", params, nil) -} - -func (self *SRegion) RebootDBInstance(id string) error { - params := map[string]string{ - "DBInstanceIdentifier": id, - } - return self.rdsRequest("RebootDBInstance", params, nil) -} - -func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error { - oldTags, err := self.region.ListRdsResourceTags(self.DBInstanceArn) - if err != nil { - return errors.Wrapf(err, "ListRdsResourceTags") - } - added, removed := map[string]string{}, map[string]string{} - for k, v := range tags { - oldValue, ok := oldTags[k] - if !ok { - added[k] = v - } else if oldValue != v { - removed[k] = oldValue - added[k] = v - } - } - if replace { - for k, v := range oldTags { - newValue, ok := tags[k] - if !ok { - removed[k] = v - } else if v != newValue { - added[k] = newValue - removed[k] = v - } - } - } - if len(removed) > 0 { - err = self.region.RemoveRdsTagsFromResource(self.DBInstanceArn, removed) - if err != nil { - return errors.Wrapf(err, "RemoveRdsTagsFromResource %s", removed) - } - } - if len(added) > 0 { - return self.region.AddRdsTagsToResource(self.DBInstanceArn, added) - } - return nil -} - -func (self *SRegion) ListRdsResourceTags(arn string) (map[string]string, error) { - params := map[string]string{ - "ResourceName": arn, - } - tags := multicloud.AwsTags{} - err := self.rdsRequest("ListTagsForResource", params, &tags) - if err != nil { - return nil, errors.Wrapf(err, "ListTagsForResource") - } - return tags.GetTags() -} - -func (self *SRegion) AddRdsTagsToResource(arn string, tags map[string]string) error { - if len(tags) == 0 { - return nil - } - params := map[string]string{ - "ResourceName": arn, - } - i := 1 - for k, v := range tags { - params[fmt.Sprintf("Tags.member.%d.Key", i)] = k - params[fmt.Sprintf("Tags.member.%d.Value", i)] = v - } - return self.rdsRequest("AddTagsToResource", params, nil) -} - -func (self *SRegion) RemoveRdsTagsFromResource(arn string, tags map[string]string) error { - if len(tags) == 0 { - return nil - } - params := map[string]string{ - "ResourceName": arn, - } - i := 1 - for k := range tags { - params[fmt.Sprintf("TagKeys.member.%d", i)] = k - } - return self.rdsRequest("RemoveTagsFromResource", params, nil) -} diff --git a/pkg/multicloud/aws/dbinstance_account.go b/pkg/multicloud/aws/dbinstance_account.go deleted file mode 100644 index 0f1522c2ad..0000000000 --- a/pkg/multicloud/aws/dbinstance_account.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceAccount struct { - multicloud.SDBInstanceAccountBase - instance *SDBInstance - - AccountName string -} - -func (account *SDBInstanceAccount) GetName() string { - return account.AccountName -} diff --git a/pkg/multicloud/aws/dbinstance_database.go b/pkg/multicloud/aws/dbinstance_database.go deleted file mode 100644 index 339bd32512..0000000000 --- a/pkg/multicloud/aws/dbinstance_database.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceDatabase struct { - multicloud.SDBInstanceDatabaseBase - multicloud.AwsTags - - DBName string -} - -func (database *SDBInstanceDatabase) GetId() string { - return database.DBName -} - -func (database *SDBInstanceDatabase) GetGlobalId() string { - return database.DBName -} - -func (database *SDBInstanceDatabase) GetName() string { - return database.DBName -} - -func (database *SDBInstanceDatabase) GetStatus() string { - return api.DBINSTANCE_DATABASE_RUNNING -} - -func (database *SDBInstanceDatabase) GetCharacterSet() string { - return "" -} diff --git a/pkg/multicloud/aws/dbinstance_snapshot.go b/pkg/multicloud/aws/dbinstance_snapshot.go deleted file mode 100644 index bb73818deb..0000000000 --- a/pkg/multicloud/aws/dbinstance_snapshot.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceSnapshot struct { - multicloud.SDBInstanceBackupBase - multicloud.AwsTags - region *SRegion - - AllocatedStorage int `xml:"AllocatedStorage"` - AvailabilityZone string `xml:"AvailabilityZone"` - DbiResourceId string `xml:"DbiResourceId"` - DBInstanceIdentifier string `xml:"DBInstanceIdentifier"` - Engine string `xml:"Engine"` - VpcId string `xml:"VpcId"` - PercentProgress int `xml:"PercentProgress"` - IAMDatabaseAuthenticationEnabled bool `xml:"IAMDatabaseAuthenticationEnabled"` - DBSnapshotIdentifier string `xml:"DBSnapshotIdentifier"` - OptionGroupName string `xml:"OptionGroupName"` - EngineVersion string `xml:"EngineVersion"` - MasterUsername string `xml:"MasterUsername"` - SnapshotType string `xml:"SnapshotType"` - InstanceCreateTime time.Time `xml:"InstanceCreateTime"` - DBSnapshotArn string `xml:"DBSnapshotArn"` - Encrypted bool `xml:"Encrypted"` - Port int `xml:"Port"` - LicenseModel string `xml:"LicenseModel"` - SnapshotCreateTime time.Time `xml:"SnapshotCreateTime"` - StorageType string `xml:"StorageType"` - Status string `xml:"Status"` -} - -type SDBInstanceSnapshots struct { - Snapshots []SDBInstanceSnapshot `xml:"DBSnapshots>DBSnapshot"` - Marker string `xml:"Marker"` -} - -func (snapshot *SDBInstanceSnapshot) GetId() string { - return snapshot.DBSnapshotIdentifier -} - -func (snapshot *SDBInstanceSnapshot) GetGlobalId() string { - return snapshot.DBSnapshotIdentifier -} - -func (snapshot *SDBInstanceSnapshot) GetName() string { - return snapshot.DBSnapshotIdentifier -} - -func (snapshot *SDBInstanceSnapshot) GetEngine() string { - return snapshot.Engine -} - -func (snapshot *SDBInstanceSnapshot) GetEngineVersion() string { - return snapshot.EngineVersion -} - -func (snapshot *SDBInstanceSnapshot) GetStartTime() time.Time { - return snapshot.SnapshotCreateTime -} - -func (snapshot *SDBInstanceSnapshot) GetEndTime() time.Time { - return snapshot.SnapshotCreateTime -} - -func (snapshot *SDBInstanceSnapshot) GetBackupMode() string { - switch snapshot.SnapshotType { - case "manual": - return api.BACKUP_MODE_MANUAL - default: - return api.BACKUP_MODE_AUTOMATED - } -} - -func (snapshot *SDBInstanceSnapshot) GetStatus() string { - switch snapshot.Status { - case "available": - return api.DBINSTANCE_BACKUP_READY - default: - log.Errorf("unknown dbinstance snapshot status: %s", snapshot.Status) - return api.DBINSTANCE_BACKUP_UNKNOWN - } -} - -func (self *SDBInstanceSnapshot) Refresh() error { - snap, err := self.region.GetRdsSnapshot(self.DBSnapshotIdentifier) - if err != nil { - return err - } - return jsonutils.Update(self, snap) -} - -func (snapshot *SDBInstanceSnapshot) GetBackupSizeMb() int { - return snapshot.AllocatedStorage * 1024 -} - -func (snapshot *SDBInstanceSnapshot) GetDBNames() string { - return "" -} - -func (snapshot *SDBInstanceSnapshot) GetDBInstanceId() string { - return snapshot.DbiResourceId -} - -func (self *SDBInstanceSnapshot) Delete() error { - return self.region.DeleteRdsSnapshot(self.DBSnapshotIdentifier) -} - -func (self *SRegion) DeleteRdsSnapshot(id string) error { - params := map[string]string{ - "DBSnapshotIdentifier": id, - } - return self.rdsRequest("DeleteDBSnapshot", params, nil) -} - -func (region *SRegion) GetDBInstanceSnapshots(instanceId, backupId string) ([]SDBInstanceSnapshot, error) { - params := map[string]string{} - if len(instanceId) > 0 { - params["DBInstanceIdentifier"] = instanceId - } - if len(backupId) > 0 { - params["DBSnapshotIdentifier"] = backupId - } - ret, marker := []SDBInstanceSnapshot{}, "" - for { - snapshots := SDBInstanceSnapshots{} - params["Marker"] = marker - err := region.rdsRequest("DescribeDBSnapshots", params, &snapshots) - if err != nil { - return nil, errors.Wrap(err, "DescribeDBSnapshots") - } - ret = append(ret, snapshots.Snapshots...) - if len(snapshots.Marker) == 0 { - break - } - marker = snapshots.Marker - } - return ret, nil -} - -func (self *SRegion) GetRdsSnapshot(id string) (*SDBInstanceSnapshot, error) { - if len(id) == 0 { - return nil, cloudprovider.ErrNotFound - } - backups, err := self.GetDBInstanceSnapshots("", id) - if err != nil { - return nil, err - } - if len(backups) == 1 { - backups[0].region = self - return &backups[0], nil - } - if len(backups) == 0 { - return nil, cloudprovider.ErrNotFound - } - return nil, cloudprovider.ErrDuplicateId -} - -func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - snapshots, err := region.GetDBInstanceSnapshots("", "") - if err != nil { - return nil, errors.Wrap(err, "GetDBInstanceSnapshots") - } - isnapshots := []cloudprovider.ICloudDBInstanceBackup{} - for i := 0; i < len(snapshots); i++ { - snapshots[i].region = region - isnapshots = append(isnapshots, &snapshots[i]) - } - return isnapshots, nil -} diff --git a/pkg/multicloud/aws/disk.go b/pkg/multicloud/aws/disk.go deleted file mode 100644 index f4dee136f5..0000000000 --- a/pkg/multicloud/aws/disk.go +++ /dev/null @@ -1,552 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "fmt" - "sort" - "strings" - "time" - - "github.com/aws/aws-sdk-go/service/ec2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SMountInstances struct { - MountInstance []string -} - -type SDisk struct { - storage *SStorage - multicloud.SDisk - multicloud.AwsTags - - RegionId string - ZoneId string // AvailabilityZone - DiskId string // VolumeId - - DiskName string // Tag Name - Size int // Size GB - 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 - - 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) GetIops() int { - return self.Iops -} - -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 api.DISK_ALLOCATING - case "deleting": - return api.DISK_DEALLOC - case "error": - return api.DISK_ALLOC_FAILED - default: - return api.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) GetBillingType() string { - // todo: implement me - return billing.BILLING_TYPE_POSTPAID -} - -func (self *SDisk) GetCreatedAt() time.Time { - return self.CreationTime -} - -func (self *SDisk) GetExpiredAt() time.Time { - return self.ExpiredTime -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.storage, nil -} - -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(ctx context.Context) error { - if _, err := self.storage.zone.region.GetDisk(self.DiskId); err != nil && errors.Cause(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(ctx context.Context, 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, errors.Wrap(err, "CreateSnapshot") - } else if snapshot, err := self.getSnapshot(snapshotId); err != nil { - log.Errorf("getSnapshot %s", snapshotId) - return nil, errors.Wrap(err, "getSnapshot") - } else { - snapshot.region = self.storage.zone.region - if err := cloudprovider.WaitStatus(snapshot, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil { - return nil, errors.Wrap(err, "WaitStatus.snapshot") - } - return snapshot, nil - } -} - -func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - if snapshot, err := self.getSnapshot(snapshotId); err != nil { - return nil, errors.Wrap(err, "getSnapshot") - } 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("GetSnapshots fail %s", err) - return nil, errors.Wrap(err, "GetSnapshots") - } 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(ctx context.Context, newSizeMb int64) error { - err := self.storage.zone.region.resizeDisk(self.DiskId, newSizeMb) - if err != nil { - return err - } - - return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 5*time.Second, 5*time.Second, 90*time.Second) -} - -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return self.storage.zone.region.resetDisk(self.DiskId, snapshotId) -} - -func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) { - if len(snapshotId) == 0 { - return nil, fmt.Errorf("GetSnapshot snapshot id should not be empty.") - } - - if snapshots, total, err := self.storage.zone.region.GetSnapshots("", "", "", []string{snapshotId}, 0, 1); err != nil { - return nil, errors.Wrap(err, "GetSnapshots") - } else if total != 1 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetSnapshots") - } 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)) - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, 0, errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.DescribeVolumes(params) - if err != nil { - return nil, 0, errors.Wrap(err, "DescribeVolumes") - } - - 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 - jsonutils.Update(&disk.AwsTags.TagSet, item.Tags) - 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.Debugf("%s", err) - return nil, 0, err - } - - if disk.Device == instance.RootDeviceName { - disk.Type = api.DISK_TYPE_SYS - disk.ImageId = instance.ImageId - } else { - disk.Type = api.DISK_TYPE_DATA - } - } else { - disk.Type = api.DISK_TYPE_DATA - } - } - - disks = append(disks, disk) - } - - // 系统盘必须放在第零个位置 - sort.Slice(disks, func(i, j int) bool { - if disks[i].Type == api.DISK_TYPE_SYS { - return true - } - - if disks[j].Type != api.DISK_TYPE_SYS && disks[i].Device < disks[j].Device { - return true - } - - return false - }) - - return disks, len(disks), nil -} - -func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { - if len(diskId) == 0 { - // return nil, fmt.Errorf("GetDisk diskId should not be empty.") - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetDisk") - } - disks, total, err := self.GetDisks("", "", "", []string{diskId}, 0, 1) - if err != nil { - if strings.Contains(err.Error(), "InvalidVolume.NotFound") { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetDisks") - } else { - return nil, errors.Wrap(err, "GetDisks") - } - } - if total != 1 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetDisk") - } - 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) - log.Debugf("DeleteDisk with params: %s", params.String()) - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.DeleteVolume(params) - return err -} - -func (self *SRegion) resizeDisk(diskId string, sizeMb int64) error { - // https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/volume_constraints.html - // MBR -> 2 TiB - // GPT -> 16 TiB - // size unit GiB - sizeGb := sizeMb / 1024 - params := &ec2.ModifyVolumeInput{} - if sizeGb > 0 { - params.SetSize(sizeGb) - } 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) - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.ModifyVolume(params) - return err -} - -func (self *SRegion) resetDisk(diskId, snapshotId string) (string, error) { - // 这里实际是回滚快照 - disk, err := self.GetDisk(diskId) - if err != nil { - log.Debugf("resetDisk %s:%s", diskId, err.Error()) - return "", err - } - - params := &ec2.CreateVolumeInput{} - if len(snapshotId) > 0 { - params.SetSnapshotId(snapshotId) - } - params.SetSize(int64(disk.Size)) - params.SetVolumeType(disk.Category) - params.SetAvailabilityZone(disk.ZoneId) - //tags, _ := disk.Tags.GetTagSpecifications() - //params.SetTagSpecifications([]*ec2.TagSpecification{tags}) - - ec2Client, err := self.getEc2Client() - if err != nil { - return "", errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.CreateVolume(params) - if err != nil { - log.Debugf("resetDisk %s: %s", params.String(), err.Error()) - return "", err - } - - // detach disk - if disk.Status == ec2.VolumeStateInUse { - err := self.DetachDisk(disk.InstanceId, diskId) - if err != nil { - log.Debugf("resetDisk %s %s: %s", disk.InstanceId, diskId, err.Error()) - return "", err - } - - err = ec2Client.WaitUntilVolumeAvailable(&ec2.DescribeVolumesInput{VolumeIds: []*string{&diskId}}) - if err != nil { - log.Debugf("resetDisk :%s", err.Error()) - return "", err - } - } - - err = self.AttachDisk(disk.InstanceId, *ret.VolumeId, disk.Device) - if err != nil { - log.Debugf("resetDisk %s %s %s: %s", disk.InstanceId, *ret.VolumeId, disk.Device, err.Error()) - return "", err - } - - // 绑定成功后删除原磁盘 - return StrVal(ret.VolumeId), self.DeleteDisk(diskId) -} - -// io1类型的卷需要指定IOPS参数,最大不超过32000。这里根据aws网站的建议值进行设置 -// io2类型的卷需要指定IOPS参数,最大不超过64000。 -// GenDiskIops Base 100, 卷每增加2G。IOPS增加1。最多到3000 iops -func GenDiskIops(diskType string, sizeGB int) int64 { - if diskType == api.STORAGE_IO1_SSD || diskType == api.STORAGE_IO2_SSD { - iops := int64(100 + sizeGB/2) - if iops < 3000 { - return iops - } else { - return 3000 - } - } - - return 0 -} - -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) - } - - if iops := GenDiskIops(category, sizeGb); iops > 0 { - params.SetIops(iops) - } - - params.SetTagSpecifications([]*ec2.TagSpecification{ec2Tags}) - - ec2Client, err := self.getEc2Client() - if err != nil { - return "", errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.CreateVolume(params) - if err != nil { - return "", err - } - - paramsWait := &ec2.DescribeVolumesInput{} - paramsWait.SetVolumeIds([]*string{ret.VolumeId}) - err = ec2Client.WaitUntilVolumeAvailable(paramsWait) - if err != nil { - return "", err - } - return StrVal(ret.VolumeId), nil -} - -func (disk *SDisk) GetAccessPath() string { - return "" -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - _, err := self.storage.zone.region.resetDisk(self.DiskId, "") - return err -} - -func (self *SDisk) GetProjectId() string { - return "" -} diff --git a/pkg/multicloud/aws/doc.go b/pkg/multicloud/aws/doc.go deleted file mode 100644 index d8fa6b4f43..0000000000 --- a/pkg/multicloud/aws/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws // import "yunion.io/x/onecloud/pkg/multicloud/aws" diff --git a/pkg/multicloud/aws/eip.go b/pkg/multicloud/aws/eip.go deleted file mode 100644 index 9ca58ddf3b..0000000000 --- a/pkg/multicloud/aws/eip.go +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - EIP_STATUS_INUSE = "InUse" - EIP_STATUS_AVAILABLE = "Available" -) - -type SEipAddress struct { - region *SRegion - multicloud.SEipBase - multicloud.AwsTags - - AllocationId string `xml:"allocationId"` - AssociationId string `xml:"associationId"` - CarrierIp string `xml:"carrierIp"` - CustomerOwnedIp string `xml:"customerOwnedIp"` - CustomerOwnedIpv4Pool string `xml:"customerOwnedIpv4Pool"` - Domain string `xml:"domain"` - InstanceId string `xml:"instanceId"` - NetworkBorderGroup string `xml:"networkBorderGroup"` - NetworkInterfaceId string `xml:"networkInterfaceId"` - NetworkInterfaceOwnerId string `xml:"networkInterfaceOwnerId"` - PrivateIpAddress string `xml:"privateIpAddress"` - PublicIp string `xml:"publicIp"` - PublicIpv4Pool string `xml:"publicIpv4Pool"` -} - -func (self *SEipAddress) GetId() string { - return self.AllocationId -} - -func (self *SEipAddress) GetName() string { - name := self.AwsTags.GetName() - if len(name) > 0 { - return name - } - return self.AllocationId -} - -func (self *SEipAddress) GetGlobalId() string { - return self.AllocationId -} - -func (self *SEipAddress) GetStatus() string { - return api.EIP_STATUS_READY -} - -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) GetIpAddr() string { - return self.PublicIp -} - -func (self *SEipAddress) GetMode() string { - if self.InstanceId == self.AllocationId { - return api.EIP_MODE_INSTANCE_PUBLICIP - } - return api.EIP_MODE_STANDALONE_EIP -} - -func (self *SEipAddress) GetAssociationType() string { - if len(self.InstanceId) > 0 { - return api.EIP_ASSOCIATE_TYPE_SERVER - } - if len(self.NetworkInterfaceId) > 0 { - net, err := self.region.GetNetworkInterface(self.NetworkInterfaceId) - if err != nil { - return "" - } - switch net.InterfaceType { - case "nat_gateway": - return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY - default: - return net.InterfaceType - } - } - return "" -} - -func (self *SEipAddress) GetAssociationExternalId() string { - if len(self.InstanceId) > 0 { - return self.InstanceId - } - if len(self.NetworkInterfaceId) > 0 { - net, err := self.region.GetNetworkInterface(self.NetworkInterfaceId) - if err != nil { - return "" - } - switch net.InterfaceType { - case "nat_gateway": - nats, err := self.region.GetNatGateways(nil, net.VpcId, net.SubnetId) - if err != nil { - return "" - } - for i := range nats { - for _, addr := range nats[i].NatGatewayAddresses { - if addr.PublicIp == self.PublicIp { - return nats[i].GetGlobalId() - } - } - } - return "" - } - } - return self.InstanceId -} - -func (self *SEipAddress) GetBandwidth() int { - return 0 -} - -func (self *SEipAddress) GetINetworkId() string { - return "" -} - -func (self *SEipAddress) GetInternetChargeType() string { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC -} - -func (self *SEipAddress) Delete() error { - return self.region.DeallocateEIP(self.AllocationId) -} - -func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { - return self.region.AssociateEip(self.AllocationId, conf.InstanceId) -} - -func (self *SEipAddress) Dissociate() error { - return self.region.DissociateEip(self.AssociationId) -} - -func (self *SEipAddress) ChangeBandwidth(bw int) error { - return self.region.UpdateEipBandwidth(self.AllocationId, bw) -} - -func (self *SRegion) GetEips(id, ip, associateId string) ([]SEipAddress, error) { - params := map[string]string{} - if len(id) > 0 { - params["AllocationId.1"] = id - } - if len(ip) > 0 { - params["PublicIp.1"] = ip - } - idx := 1 - if len(associateId) > 0 { - params[fmt.Sprintf("Filter.%d.Name", idx)] = "association-id" - params[fmt.Sprintf("Filter.%d.Value.1", idx)] = associateId - idx++ - } - result := struct { - AddressesSet []SEipAddress `xml:"addressesSet>item"` - }{} - err := self.ec2Request("DescribeAddresses", params, &result) - if err != nil { - return nil, errors.Wrapf(err, "DescribeAddresses") - } - return result.AddressesSet, nil -} - -func (self *SRegion) GetEip(id string) (*SEipAddress, error) { - eips, err := self.GetEips(id, "", "") - if err != nil { - return nil, errors.Wrapf(err, "GetEips") - } - for i := range eips { - if eips[i].GetGlobalId() == id { - eips[i].region = self - return &eips[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SRegion) GetEipByIpAddress(eipAddress string) (*SEipAddress, error) { - eips, err := self.GetEips("", eipAddress, "") - if err != nil { - return nil, errors.Wrapf(err, "GetEips") - } - for i := range eips { - if eips[i].GetIpAddr() == eipAddress { - eips[i].region = self - return &eips[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, eipAddress) -} - -func (self *SRegion) AllocateEIP(opts *cloudprovider.SEip) (*SEipAddress, error) { - params := map[string]string{ - "Domain": "vpc", - } - if len(opts.Name) > 0 { - params["TagSpecification.1.ResourceType"] = "elastic-ip" - params["TagSpecification.1.Tag.1.Key"] = "Name" - params["TagSpecification.1.Tag.1.Value"] = opts.Name - } - ret := SEipAddress{region: self} - err := self.ec2Request("AllocateAddress", params, &ret) - if err != nil { - return nil, errors.Wrapf(err, "AllocateAddress") - } - return &ret, nil -} - -func (self *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - eip, err := self.AllocateEIP(opts) - if err != nil { - return nil, errors.Wrapf(err, "AllocateEIP") - } - return eip, nil -} - -func (self *SRegion) DeallocateEIP(eipId string) error { - params := map[string]string{ - "AllocationId": eipId, - } - return self.ec2Request("ReleaseAddress", params, nil) -} - -func (self *SRegion) AssociateEip(eipId string, instanceId string) error { - params := map[string]string{ - "AllocationId": eipId, - "InstanceId": instanceId, - } - return self.ec2Request("AssociateAddress", params, nil) -} - -func (self *SRegion) DissociateEip(insId string) error { - params := map[string]string{ - "AssociationId": insId, - } - return self.ec2Request("DisassociateAddress", params, nil) -} - -func (self *SRegion) UpdateEipBandwidth(eipId string, bw int) error { - return cloudprovider.ErrNotSupported -} - -func (self *SEipAddress) GetBillingType() string { - return billing.BILLING_TYPE_POSTPAID -} - -func (self *SEipAddress) GetCreatedAt() time.Time { - return time.Time{} -} - -func (self *SEipAddress) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SEipAddress) GetProjectId() string { - return "" -} diff --git a/pkg/multicloud/aws/host.go b/pkg/multicloud/aws/host.go deleted file mode 100644 index 57ba8cc8df..0000000000 --- a/pkg/multicloud/aws/host.go +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone -} - -func (self *SHost) GetId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) GetName() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) -} - -func (self *SHost) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) Refresh() error { - return nil -} - -func (self *SHost) IsEmulated() bool { - return true -} - -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, errors.Wrap(err, "GetInstances") - } - - 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) { - if len(gid) == 0 { - log.Errorf("GetIVMById guest id is empty") - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIVMById") - } - - ivms, _, err := self.zone.region.GetInstances(self.zone.ZoneId, []string{gid}, 0, 1) - if err != nil { - return nil, errors.Wrap(err, "GetInstances") - } - if len(ivms) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetInstances") - } - 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 api.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() int { - 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 api.DISK_TYPE_HYBRID -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_AWS -} - -func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) { - inst, err := self.zone.region.GetInstance(instanceId) - if err != nil { - log.Errorf("GetInstance %s: %s", instanceId, err) - return nil, errors.Wrap(err, "GetInstance") - } - inst.host = self - return inst, nil -} - -func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.InstanceType, - desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, - desc.PublicKey, desc.ExternalSecgroupId, desc.UserData, desc.Tags) - if err != nil { - return nil, errors.Wrap(err, "_createVM") - } - - vm, err := self.GetInstanceById(vmId) - if err != nil { - log.Errorf("GetInstanceById %s: %s", vmId, err) - return nil, errors.Wrap(err, "GetInstanceById") - } - - return vm, err -} - -func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo, instanceType string, - networkId, ipAddr, desc, passwd string, - dataDisks []cloudprovider.SDiskInfo, publicKey string, secgroupId string, userData string, - tags map[string]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 - var err error - keypair := "" - if len(publicKey) > 0 { - 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 %s fail %s", imgId, 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(dataDisks)+1) - disks[0].Size = img.SizeGB - if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.SizeGB { - disks[0].Size = sysDisk.SizeGB - } - disks[0].Category = sysDisk.StorageType - - for i, dataDisk := range dataDisks { - disks[i+1].Size = dataDisk.SizeGB - disks[i+1].Category = dataDisk.StorageType - } - - // 创建实例 - if len(instanceType) > 0 { - log.Debugf("Try instancetype : %s", instanceType) - vmId, err := self.zone.region.CreateInstance(name, img, instanceType, networkId, secgroupId, self.zone.ZoneId, desc, disks, ipAddr, keypair, userData, tags) - if err != nil { - log.Errorf("Failed for %s: %s", instanceType, err) - return "", fmt.Errorf("Failed to create specification %s.%s", instanceType, err.Error()) - } else { - return vmId, nil - } - } - - return "", fmt.Errorf("Failed to create, instance type should not be empty") -} - -func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SHost) GetIsMaintenance() bool { - return false -} - -func (self *SHost) GetVersion() string { - return AWS_API_VERSION -} diff --git a/pkg/multicloud/aws/iam_group.go b/pkg/multicloud/aws/iam_group.go deleted file mode 100644 index f7b7f87aaf..0000000000 --- a/pkg/multicloud/aws/iam_group.go +++ /dev/null @@ -1,329 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "time" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SGroups struct { - Groups []SGroup `xml:"Groups>member"` - IsTruncated bool `xml:"IsTruncated"` - Marker string `xml:"Marker"` -} - -type SGroup struct { - client *SAwsClient - - Path string `xml:"Path"` - GroupName string `xml:"GroupName"` - GroupId string `xml:"GroupId"` - Arn string `xml:"Arn"` - CreateDate time.Time `xml:"CreateDate"` -} - -func (self *SGroup) GetName() string { - return self.GroupName -} - -func (self *SGroup) GetDescription() string { - return "" -} - -func (self *SGroup) GetGlobalId() string { - return self.GroupName -} - -func (self *SGroup) AddUser(userName string) error { - return self.client.AddUserToGroup(self.GroupName, userName) -} - -func (self *SGroup) RemoveUser(userName string) error { - return self.client.RemoveUserFromGroup(self.GroupName, userName) -} - -func (self *SGroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { - users, err := self.client.ListGroupUsers(self.GroupName) - if err != nil { - return nil, errors.Wrapf(err, "ListGroupUsers") - } - ret := []cloudprovider.IClouduser{} - for i := range users { - users[i].client = self.client - ret = append(ret, &users[i]) - } - return ret, nil -} - -func (self *SGroup) AttachSystemPolicy(policyId string) error { - return self.client.AttachGroupPolicy(self.GroupName, self.client.getIamArn(policyId)) -} - -func (self *SGroup) AttachCustomPolicy(policyId string) error { - return self.client.AttachGroupPolicy(self.GroupName, self.client.getIamArn(policyId)) -} - -func (self *SGroup) DetachSystemPolicy(policyId string) error { - return self.client.DetachGroupPolicy(self.GroupName, self.client.getIamArn(policyId)) -} - -func (self *SGroup) DetachCustomPolicy(policyId string) error { - return self.client.DetachGroupPolicy(self.GroupName, self.client.getIamArn(policyId)) -} - -func (self *SGroup) Delete() error { - return self.client.DeleteGroup(self.GroupName) -} - -func (self *SAwsClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - return self.CreateGroup(name, "") -} - -func (self *SGroup) ListPolicies() ([]SAttachedPolicy, error) { - policies := []SAttachedPolicy{} - offset := "" - for { - part, err := self.client.ListAttachedGroupPolicies(self.GroupName, offset, 1000) - if err != nil { - return nil, errors.Wrapf(err, "ListAttachedGroupPolicies") - } - for i := range part.AttachedPolicies { - part.AttachedPolicies[i].client = self.client - policies = append(policies, part.AttachedPolicies[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return policies, nil -} - -func (self *SGroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := self.ListPolicies() - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - customMaps, err := self.client.GetCustomPolicyMaps() - if err != nil { - return nil, errors.Wrapf(err, "GetCustomPolicyMaps") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - _, ok := customMaps[policies[i].PolicyName] - if !ok { - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (self *SGroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := self.ListPolicies() - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - customMaps, err := self.client.GetCustomPolicyMaps() - if err != nil { - return nil, errors.Wrapf(err, "GetCustomPolicyMaps") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - _, ok := customMaps[policies[i].PolicyName] - if ok { - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (self *SAwsClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - ret := []cloudprovider.ICloudgroup{} - offset := "" - for { - part, err := self.ListGroups(offset, 1000, "") - if err != nil { - return nil, errors.Wrapf(err, "ListGroups") - } - for i := range part.Groups { - part.Groups[i].client = self - ret = append(ret, &part.Groups[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SAwsClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - group, err := self.GetGroup(name, "", 1) - if err != nil { - return nil, errors.Wrapf(err, "GetGroup(%s)", name) - } - group.Group.client = self - return &group.Group, nil -} - -func (self *SAwsClient) ListGroupUsers(groupName string) ([]SUser, error) { - users := []SUser{} - offset := "" - for { - part, err := self.GetGroup(groupName, offset, 1000) - if err != nil { - return nil, errors.Wrap(err, "GetGroup") - } - users = append(users, part.Users...) - offset = part.Marker - if len(offset) == 0 { - break - } - } - return users, nil -} - -func (self *SAwsClient) CreateGroup(name string, path string) (*SGroup, error) { - params := map[string]string{ - "Path": "/", - "GroupName": name, - } - if len(path) > 0 { - params["Path"] = path - } - group := struct { - Group SGroup `xml:"Group"` - }{} - err := self.iamRequest("CreateGroup", params, &group) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.CreateGroup") - } - return &group.Group, nil -} - -func (self *SAwsClient) ListGroups(offset string, limit int, pathPrefix string) (*SGroups, error) { - if limit <= 0 || limit > 1000 { - limit = 1000 - } - params := map[string]string{ - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(offset) > 0 { - params["Marker"] = offset - } - if len(pathPrefix) > 0 { - params["PathPrefix"] = pathPrefix - } - groups := &SGroups{} - err := self.iamRequest("ListGroups", params, groups) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.ListGroups") - } - return groups, nil -} - -func (self *SAwsClient) DeleteGroup(name string) error { - params := map[string]string{ - "GroupName": name, - } - return self.iamRequest("DeleteGroup", params, nil) -} - -type SGroupDetails struct { - Group SGroup `xml:"Group"` - Users []SUser `xml:"Users>member"` - IsTruncated bool `xml:"IsTruncated"` - Marker string `xml:"Marker"` -} - -func (self *SAwsClient) GetGroup(name string, offset string, limit int) (*SGroupDetails, error) { - if limit <= 0 || limit > 1000 { - limit = 1000 - } - params := map[string]string{ - "GroupName": name, - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(offset) > 0 { - params["Marker"] = offset - } - group := &SGroupDetails{} - err := self.iamRequest("GetGroup", params, group) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.GetGroup") - } - return group, nil -} - -func (self *SAwsClient) ListGroupPolicies(name string, offset string, limit int) (*SPolicies, error) { - if limit <= 0 || limit > 1000 { - limit = 1000 - } - - params := map[string]string{ - "GroupName": name, - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(offset) > 0 { - params["Marker"] = offset - } - policies := &SPolicies{} - err := self.iamRequest("ListGroupPolicies", params, policies) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.ListGroupPolicies") - } - return policies, nil -} - -func (self *SAwsClient) AddUserToGroup(groupName, userName string) error { - params := map[string]string{ - "GroupName": groupName, - "UserName": userName, - } - return self.iamRequest("AddUserToGroup", params, nil) -} - -func (self *SAwsClient) RemoveUserFromGroup(groupName, userName string) error { - params := map[string]string{ - "GroupName": groupName, - "UserName": userName, - } - return self.iamRequest("RemoveUserFromGroup", params, nil) -} - -func (self *SAwsClient) AttachGroupPolicy(groupName, policyArn string) error { - params := map[string]string{ - "GroupName": groupName, - "PolicyArn": policyArn, - } - return self.iamRequest("AttachGroupPolicy", params, nil) -} - -func (self *SAwsClient) DetachGroupPolicy(groupName, policyArn string) error { - params := map[string]string{ - "GroupName": groupName, - "PolicyArn": policyArn, - } - err := self.iamRequest("DetachGroupPolicy", params, nil) - if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrap(err, "DetachGroupPolicy") - } - return nil -} diff --git a/pkg/multicloud/aws/iam_policy.go b/pkg/multicloud/aws/iam_policy.go deleted file mode 100644 index a729bccf2d..0000000000 --- a/pkg/multicloud/aws/iam_policy.go +++ /dev/null @@ -1,476 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SPolicies struct { - IsTruncated bool `xml:"IsTruncated"` - Marker string `xml:"Marker"` - Policies []SPolicy `xml:"Policies>member"` -} - -type SPolicy struct { - client *SAwsClient - - PermissionsBoundaryUsageCount int `xml:"PermissionsBoundaryUsageCount"` - PolicyName string `xml:"PolicyName"` - Description string `xml:"Description"` - DefaultVersionId string `xml:"DefaultVersionId"` - PolicyId string `xml:"PolicyId"` - Path string `xml:"Path"` - Arn string `xml:"Arn"` - IsAttachable bool `xml:"IsAttachable"` - AttachmentCount int `xml:"AttachmentCount"` - CreateDate time.Time `xml:"CreateDate"` - UpdateDate time.Time `xml:"UpdateDate"` -} - -func (self *SPolicy) GetName() string { - return self.PolicyName -} - -func (self *SPolicy) GetGlobalId() string { - return self.client.getIamCommonArn(self.Arn) -} - -func (self *SPolicy) GetDescription() string { - policy, err := self.client.GetPolicy(self.Arn) - if err != nil { - return "" - } - return policy.Description -} - -type SUserPolicies struct { - PolicyNames []string `xml:"PolicyNames>member"` - IsTruncated bool `xml:"IsTruncated"` -} - -func (self *SAwsClient) GetCustomPolicyMaps() (map[string]string, error) { - policyMaps := map[string]string{} - offset := "" - for { - part, err := self.ListPolicies(offset, 1000, false, "", "", "Local") - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - for _, policy := range part.Policies { - policyMaps[policy.PolicyName] = policy.PolicyId - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return policyMaps, nil -} - -func (self *SAwsClient) ListUserPolicies(userName string, marker string, maxItems int) (*SUserPolicies, error) { - if maxItems <= 0 || maxItems > 1000 { - maxItems = 1000 - } - params := map[string]string{ - "UserName": userName, - "MaxItems": fmt.Sprintf("%d", maxItems), - } - if len(marker) > 0 { - params["Marker"] = marker - } - policies := SUserPolicies{} - err := self.iamRequest("ListUserPolicies", params, &policies) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.ListUserPolicies") - } - return &policies, nil -} - -func (self *SPolicy) Delete() error { - return self.client.DeletePolicy(self.Arn) -} - -func (self *SPolicy) UpdateDocument(document *jsonutils.JSONDict) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SPolicy) GetDocument() (*jsonutils.JSONDict, error) { - return self.client.GetDocument(self.Arn, self.DefaultVersionId) -} - -func (self *SAwsClient) GetDocument(arn, versionId string) (*jsonutils.JSONDict, error) { - version, err := self.GetPolicyVersion(arn, versionId) - if err != nil { - return nil, errors.Wrapf(err, "GetPolicyVersion(%s, %s)", arn, versionId) - } - document, err := url.PathUnescape(version.Document) - if err != nil { - return nil, errors.Wrapf(err, "url.PathUnescape.document") - } - jsonObj, err := jsonutils.Parse([]byte(document)) - if err != nil { - return nil, errors.Wrap(err, "jsonutils.Parse") - } - return jsonObj.(*jsonutils.JSONDict), nil -} - -func (self *SAwsClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - ret := []cloudprovider.ICloudpolicy{} - marker := "" - for { - part, err := self.ListPolicies(marker, 1000, false, "", "PermissionsPolicy", "AWS") - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - for i := range part.Policies { - part.Policies[i].client = self - ret = append(ret, &part.Policies[i]) - } - marker = part.Marker - if len(marker) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SAwsClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - ret := []cloudprovider.ICloudpolicy{} - marker := "" - for { - part, err := self.ListPolicies(marker, 1000, false, "", "PermissionsPolicy", "Local") - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - for i := range part.Policies { - part.Policies[i].client = self - ret = append(ret, &part.Policies[i]) - } - marker = part.Marker - if len(marker) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -func (self *SAwsClient) ListPolicies(marker string, maxItems int, onlyAttached bool, pathPrefix string, policyUsageFilter string, scope string) (*SPolicies, error) { - if maxItems <= 0 || maxItems > 1000 { - maxItems = 1000 - } - - params := map[string]string{ - "MaxItems": fmt.Sprintf("%d", maxItems), - } - if len(marker) > 0 { - params["Marker"] = marker - } - if onlyAttached { - params["OnlyAttached"] = "true" - } - if len(pathPrefix) > 0 { - params["PathPrefix"] = pathPrefix - } - if len(policyUsageFilter) > 0 { - params["PolicyUsageFilter"] = policyUsageFilter - } - if len(scope) > 0 { - params["Scope"] = scope - } - policies := &SPolicies{} - err := self.iamRequest("ListPolicies", params, policies) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.ListPolicies") - } - return policies, nil -} - -func (self *SAwsClient) ListAttachedUserPolicies(userName string, marker string, maxItems int, pathPrefix string) (*SAttachedPolicies, error) { - if maxItems <= 0 || maxItems > 1000 { - maxItems = 1000 - } - params := map[string]string{ - "MaxItems": fmt.Sprintf("%d", maxItems), - } - if len(marker) > 0 { - params["Marker"] = marker - } - if len(pathPrefix) > 0 { - params["PathPrefix"] = pathPrefix - } - if len(userName) > 0 { - params["UserName"] = userName - } - policies := &SAttachedPolicies{} - err := self.iamRequest("ListAttachedUserPolicies", params, policies) - if err != nil { - return nil, errors.Wrap(err, "ListAttachedUserPolicies") - } - return policies, nil -} - -type SAttachedPolicies struct { - IsTruncated bool `xml:"IsTruncated"` - Marker string `xml:"Marker"` - AttachedPolicies []SAttachedPolicy `xml:"AttachedPolicies>member"` -} - -type SAttachedPolicy struct { - client *SAwsClient - - PolicyName string `xml:"PolicyName"` - PolicyArn string `xml:"PolicyArn"` -} - -func (self *SAttachedPolicy) GetGlobalId() string { - return self.client.getIamCommonArn(self.PolicyArn) -} - -func (self *SAttachedPolicy) GetName() string { - return self.PolicyName -} - -func (self *SAttachedPolicy) GetDescription() string { - return "" -} - -func (self *SAttachedPolicy) UpdateDocument(document *jsonutils.JSONDict) error { - return self.client.CreatePolicyVersion(self.PolicyArn, document.String(), true) -} - -func (self *SAttachedPolicy) GetDocument() (*jsonutils.JSONDict, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SAttachedPolicy) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (self *SAwsClient) ListAttachedGroupPolicies(name string, marker string, maxItems int) (*SAttachedPolicies, error) { - if maxItems <= 0 || maxItems > 1000 { - maxItems = 1000 - } - - params := map[string]string{ - "GroupName": name, - "MaxItems": fmt.Sprintf("%d", maxItems), - } - if len(marker) > 0 { - params["Marker"] = marker - } - policies := &SAttachedPolicies{} - err := self.iamRequest("ListAttachedGroupPolicies", params, policies) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.ListGroupPolicies") - } - return policies, nil -} - -type SPolicyNames struct { - PolicyNames []string `xml:"PolicyNames>member"` - IsTruncated bool `xml:"IsTruncated"` -} - -func (self *SAwsClient) ListRolePolicies(roleName string, marker string, maxItems int) (*SPolicyNames, error) { - if maxItems < 1 || maxItems > 1000 { - maxItems = 1000 - } - params := map[string]string{ - "RoleName": roleName, - "MaxItems": fmt.Sprintf("%d", maxItems), - } - if len(marker) > 0 { - params["Marker"] = marker - } - names := &SPolicyNames{} - err := self.iamRequest("ListRolePolicies", params, names) - if err != nil { - return nil, errors.Wrapf(err, "ListRolePolicies") - } - return names, nil -} - -func (self *SAwsClient) ListAttachedRolePolicies(roleName string, marker string, maxItems int, pathPrefix string) (*SAttachedPolicies, error) { - if maxItems < 1 || maxItems > 1000 { - maxItems = 1000 - } - params := map[string]string{ - "RoleName": roleName, - "MaxItems": fmt.Sprintf("%d", maxItems), - } - if len(marker) > 0 { - params["marker"] = marker - } - policies := &SAttachedPolicies{} - err := self.iamRequest("ListAttachedRolePolicies", params, policies) - if err != nil { - return nil, errors.Wrapf(err, "ListAttachedRolePolicies") - } - return policies, nil -} - -func (self *SAwsClient) AttachRolePolicy(roleName, policyArn string) error { - params := map[string]string{ - "PolicyArn": policyArn, - "RoleName": roleName, - } - return self.iamRequest("AttachRolePolicy", params, nil) -} - -func (self *SAwsClient) DetachRolePolicy(roleName string, policyArn string) error { - params := map[string]string{ - "PolicyArn": policyArn, - "RoleName": roleName, - } - err := self.iamRequest("DetachRolePolicy", params, nil) - if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrap(err, "DetachRolePolicy") - } - return nil -} - -type SPolicyVersion struct { - Document string `xml:"Document"` - IsDefaultVersion bool `xml:"IsDefaultVersion"` - VersionId string `xml:"VersionId"` - CreateDate time.Time `xml:"CreateDate"` -} - -type SPolicyVersions struct { - Versions []SPolicyVersion `xml:"Versions>member"` - IsTruncated bool `xml:"IsTruncated"` - Marker string `xml:"Marker"` -} - -func (self *SAwsClient) ListPolicyVersions(marker string, maxItems int, arn string) (*SPolicyVersions, error) { - if maxItems < 1 || maxItems > 1000 { - maxItems = 1000 - } - params := map[string]string{ - "MaxItems": fmt.Sprintf("%d", maxItems), - "PolicyArn": arn, - } - if len(marker) > 0 { - params["Marker"] = marker - } - versions := &SPolicyVersions{} - err := self.iamRequest("ListPolicyVersions", params, versions) - if err != nil { - return nil, errors.Wrapf(err, "ListPolicyVersions") - } - return versions, nil -} - -func (self *SAwsClient) GetPolicyVersion(arn, versionId string) (*SPolicyVersion, error) { - params := map[string]string{ - "PolicyArn": arn, - "VersionId": versionId, - } - result := struct { - Version SPolicyVersion `xml:"PolicyVersion"` - }{} - err := self.iamRequest("GetPolicyVersion", params, &result) - if err != nil { - return nil, errors.Wrapf(err, "GetPolicyVersion") - } - return &result.Version, nil -} - -func (self *SAwsClient) GetPolicy(arn string) (*SPolicy, error) { - params := map[string]string{ - "PolicyArn": arn, - } - result := struct { - Policy SPolicy `xml:"Policy"` - }{} - err := self.iamRequest("GetPolicy", params, &result) - if err != nil { - return nil, errors.Wrapf(err, "GetPolicy") - } - return &result.Policy, nil -} - -func (self *SAwsClient) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { - policy, err := self.CreatePolicy(opts.Name, opts.Document.String(), "", opts.Desc) - if err != nil { - return nil, errors.Wrapf(err, "CreatePolicy") - } - return policy, nil -} - -func (self *SAwsClient) CreatePolicy(name, document, path, desc string) (*SPolicy, error) { - document = self.convertDocument(document) - params := map[string]string{ - "PolicyName": name, - "PolicyDocument": document, - } - if len(path) > 0 { - params["Path"] = path - } - if len(desc) > 0 { - params["Description"] = desc - } - ret := struct { - Policy SPolicy `xml:"Policy"` - }{} - err := self.iamRequest("CreatePolicy", params, &ret) - if err != nil { - return nil, errors.Wrapf(err, "CreatePolicy") - } - ret.Policy.client = self - return &ret.Policy, nil -} - -func (self *SAwsClient) DeletePolicy(arn string) error { - params := map[string]string{ - "PolicyArn": arn, - } - err := self.iamRequest("DeletePolicy", params, nil) - if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { - return err - } - return nil -} - -func (self *SAwsClient) convertDocument(document string) string { - switch self.GetAccessEnv() { - case api.CLOUD_ACCESS_ENV_AWS_GLOBAL: - return strings.ReplaceAll(document, "arn:aws-cn", "arn:aws") - default: - return strings.ReplaceAll(document, "arn:aws", "arn:aws-cn") - } -} - -func (self *SAwsClient) CreatePolicyVersion(arn, document string, isDefault bool) error { - document = self.convertDocument(document) - params := map[string]string{ - "PolicyArn": arn, - "PolicyDocument": document, - } - if isDefault { - params["SetAsDefault"] = "true" - } - return self.iamRequest("CreatePolicyVersion", params, nil) -} diff --git a/pkg/multicloud/aws/iam_role.go b/pkg/multicloud/aws/iam_role.go deleted file mode 100644 index 911275c21c..0000000000 --- a/pkg/multicloud/aws/iam_role.go +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "net/url" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -var ( - samlRole = `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"sts:AssumeRoleWithSAML","Principal":{"Federated":"%s"},"Condition":{"StringEquals":{"SAML:aud":["%s"]}}}]}` -) - -type SRole struct { - client *SAwsClient - - Path string `xml:"Path"` - AssumeRolePolicyDocument string `xml:"AssumeRolePolicyDocument"` - MaxSessionDuration int `xml:"MaxSessionDuration"` - RoleId string `xml:"RoleId"` - RoleName string `xml:"RoleName"` - Description string `xml:"Description"` - Arn string `xml:"Arn"` - CreateDate time.Time `xml:"CreateDate"` -} - -func (self *SRole) GetGlobalId() string { - return self.Arn -} - -func (self *SRole) GetName() string { - return self.RoleName -} - -func (self *SRole) Delete() error { - return self.client.DeleteRole(self.RoleName) -} - -func (self *SRole) GetDocument() *jsonutils.JSONDict { - data, err := url.QueryUnescape(self.AssumeRolePolicyDocument) - if err != nil { - return nil - } - document, err := jsonutils.Parse([]byte(data)) - if err != nil { - return nil - } - return document.(*jsonutils.JSONDict) -} - -//[{"Action":"sts:AssumeRoleWithSAML","Condition":{"StringEquals":{"SAML:aud":"https://signin.aws.amazon.com/saml"}},"Effect":"Allow","Principal":{"Federated":"arn:aws:iam::879324515906:saml-provider/quxuan"}}] -func (self *SRole) GetSAMLProvider() string { - document := self.GetDocument() - if document != nil { - statement, err := document.GetArray("Statement") - if err == nil { - for i := range statement { - if action, _ := statement[i].GetString("Action"); action == "sts:AssumeRoleWithSAML" { - sp, _ := statement[i].GetString("Principal", "Federated") - if len(sp) > 0 { - return sp - } - } - } - } - } - return "" -} - -func (self *SRole) AttachPolicy(id string) error { - return self.client.AttachRolePolicy(self.RoleName, self.client.getIamArn(id)) -} - -func (self *SRole) DetachPolicy(id string) error { - return self.client.DetachRolePolicy(self.RoleName, self.client.getIamArn(id)) -} - -func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies := []SAttachedPolicy{} - marker := "" - for { - part, err := self.client.ListAttachedRolePolicies(self.RoleName, marker, 100, "") - if err != nil { - return nil, errors.Wrapf(err, "ListAttachedRolePolicies") - } - policies = append(policies, part.AttachedPolicies...) - marker = part.Marker - if len(marker) == 0 { - break - } - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - policies[i].client = self.client - ret = append(ret, &policies[i]) - } - return ret, nil -} - -type SRoles struct { - Roles []SRole `xml:"Roles>member"` - IsTruncated bool `xml:"IsTruncated"` - Marker string `xml:"Marker"` -} - -func (self *SAwsClient) ListRoles(offset string, limit int, prefix string) (*SRoles, error) { - if limit < 1 || limit > 1000 { - limit = 1000 - } - params := map[string]string{ - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(offset) > 0 { - params["Marker"] = offset - } - if len(prefix) > 0 { - params["PathPrefix"] = prefix - } - roles := &SRoles{} - err := self.iamRequest("ListRoles", params, roles) - if err != nil { - return nil, errors.Wrapf(err, "ListRoles") - } - return roles, nil -} - -func (self *SAwsClient) GetRole(roleName string) (*SRole, error) { - params := map[string]string{ - "RoleName": roleName, - } - result := struct { - Role SRole `xml:"Role"` - }{} - err := self.iamRequest("GetRole", params, &result) - if err != nil { - return nil, errors.Wrap(err, "GetRole") - } - return &result.Role, nil -} - -func (self *SAwsClient) DeleteRole(name string) error { - params := map[string]string{ - "RoleName": name, - } - return self.iamRequest("DeleteRole", params, nil) -} - -func (self *SAwsClient) GetICloudroles() ([]cloudprovider.ICloudrole, error) { - roles := []SRole{} - marker := "" - for { - part, err := self.ListRoles(marker, 100, "") - if err != nil { - return nil, errors.Wrapf(err, "ListRoles") - } - roles = append(roles, part.Roles...) - marker = part.Marker - if len(marker) == 0 { - break - } - } - ret := []cloudprovider.ICloudrole{} - for i := range roles { - roles[i].client = self - ret = append(ret, &roles[i]) - } - return ret, nil -} - -func (self *SAwsClient) CreateRole(opts *cloudprovider.SRoleCreateOptions) (*SRole, error) { - if len(opts.SAMLProvider) > 0 { - aud := "https://signin.amazonaws.cn/saml" - if self.GetAccessEnv() == api.CLOUD_ACCESS_ENV_AWS_GLOBAL { - aud = "https://signin.aws.amazon.com/saml" - } - params := map[string]string{ - "RoleName": opts.Name, - "Description": opts.Desc, - "AssumeRolePolicyDocument": fmt.Sprintf(samlRole, opts.SAMLProvider, aud), - } - role := struct { - Role SRole - }{} - err := self.iamRequest("CreateRole", params, &role) - if err != nil { - return nil, errors.Wrapf(err, "CreateRole") - } - role.Role.client = self - return &role.Role, nil - } - return nil, cloudprovider.ErrNotImplemented -} diff --git a/pkg/multicloud/aws/iam_user.go b/pkg/multicloud/aws/iam_user.go deleted file mode 100644 index d43a5c72b2..0000000000 --- a/pkg/multicloud/aws/iam_user.go +++ /dev/null @@ -1,399 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SUsers struct { - Users []SUser `xml:"Users>member"` - IsTruncated bool `xml:"IsTruncated"` - Marker string `xml:"Marker"` -} - -type SUser struct { - client *SAwsClient - multicloud.SBaseClouduser - - UserId string `xml:"UserId"` - Path string `xml:"Path"` - UserName string `xml:"UserName"` - Arn string `xml:"Arn"` - CreateDate time.Time `xml:"CreateDate"` - PasswordLastUsed time.Time `xml:"PasswordLastUsed"` -} - -func (user *SUser) GetEmailAddr() string { - return "" -} - -func (user *SUser) GetInviteUrl() string { - return "" -} - -func (user *SUser) AttachSystemPolicy(policyArn string) error { - return user.client.AttachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) -} - -func (user *SUser) AttachCustomPolicy(policyArn string) error { - return user.client.AttachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) -} - -func (user *SUser) DetachSystemPolicy(policyArn string) error { - return user.client.DetachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) -} - -func (user *SUser) DetachCustomPolicy(policyArn string) error { - return user.client.DetachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) -} - -func (user *SUser) GetGlobalId() string { - return user.UserId -} - -func (user *SUser) GetName() string { - return user.UserName -} - -func (user *SUser) ResetPassword(password string) error { - return user.client.ResetUserPassword(user.UserName, password) -} - -func (user *SUser) IsConsoleLogin() bool { - _, err := user.client.GetLoginProfile(user.UserName) - if errors.Cause(err) == cloudprovider.ErrNotFound { - return false - } - return true -} - -func (user *SUser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - groups, err := user.ListGroups() - if err != nil { - return nil, errors.Wrapf(err, "ListGroups") - } - ret := []cloudprovider.ICloudgroup{} - for i := range groups { - groups[i].client = user.client - ret = append(ret, &groups[i]) - } - return ret, nil -} - -func (self *SUser) ListPolicies() ([]SAttachedPolicy, error) { - policies := []SAttachedPolicy{} - offset := "" - for { - part, err := self.client.ListAttachedUserPolicies(self.UserName, offset, 1000, "") - if err != nil { - return nil, errors.Wrap(err, "ListAttachedUserPolicies") - } - for i := range part.AttachedPolicies { - part.AttachedPolicies[i].client = self.client - policies = append(policies, part.AttachedPolicies[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return policies, nil -} - -func (self *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := self.ListPolicies() - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - customMaps, err := self.client.GetCustomPolicyMaps() - if err != nil { - return nil, errors.Wrapf(err, "GetCustomPolicyMaps") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - _, ok := customMaps[policies[i].PolicyName] - if !ok { - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (self *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := self.ListPolicies() - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - customMaps, err := self.client.GetCustomPolicyMaps() - if err != nil { - return nil, errors.Wrapf(err, "GetCustomPolicyMaps") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - _, ok := customMaps[policies[i].PolicyName] - if ok { - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (user *SUser) ListGroups() ([]SGroup, error) { - groups := []SGroup{} - offset := "" - for { - part, err := user.client.ListGroupsForUser(user.UserName, offset, 1000) - if err != nil { - return nil, errors.Wrap(err, "ListGroupsForUser") - } - groups = append(groups, part.Groups...) - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return groups, nil -} - -func (user *SUser) Delete() error { - groups, err := user.ListGroups() - if err != nil { - return errors.Wrapf(err, "ListGroups") - } - for _, group := range groups { - err = user.client.RemoveUserFromGroup(group.GroupName, user.UserName) - if err != nil { - return errors.Wrap(err, "RemoveUserFromGroup") - } - } - policies, err := user.ListPolicies() - if err != nil { - return errors.Wrapf(err, "ListPolicies") - } - for _, policy := range policies { - err = user.client.DetachUserPolicy(user.UserName, policy.PolicyArn) - if err != nil { - return errors.Wrap(err, "DetachPolicy") - } - } - return user.client.DeleteUser(user.UserName) -} - -func (self *SAwsClient) ListUsers(offset string, limit int, pathPrefix string) (*SUsers, error) { - if limit <= 0 || limit > 1000 { - limit = 1000 - } - params := map[string]string{ - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(offset) > 0 { - params["Marker"] = offset - } - if len(pathPrefix) > 0 { - params["PathPrefix"] = pathPrefix - } - users := &SUsers{} - err := self.iamRequest("ListUsers", params, users) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.ListUsers") - } - return users, nil -} - -func (self *SAwsClient) CreateUser(path string, username string) (*SUser, error) { - params := map[string]string{ - "UserName": username, - } - if len(path) > 0 { - params["Path"] = path - } - user := struct { - User SUser `xml:"User"` - }{} - err := self.iamRequest("CreateUser", params, &user) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.CreateUser") - } - user.User.client = self - return &user.User, nil -} - -func (self *SAwsClient) DeleteUser(name string) error { - self.DeleteLoginProfile(name) - params := map[string]string{ - "UserName": name, - } - return self.iamRequest("DeleteUser", params, nil) -} - -func (self *SAwsClient) AttachUserPolicy(userName string, policyArn string) error { - params := map[string]string{ - "PolicyArn": policyArn, - "UserName": userName, - } - return self.iamRequest("AttachUserPolicy", params, nil) -} - -func (self *SAwsClient) DetachUserPolicy(userName string, policyArn string) error { - params := map[string]string{ - "PolicyArn": policyArn, - "UserName": userName, - } - err := self.iamRequest("DetachUserPolicy", params, nil) - if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrap(err, "DetachUserPolicy") - } - return nil -} - -func (self *SAwsClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - user, err := self.CreateUser("", conf.Name) - if err != nil { - return nil, errors.Wrap(err, "CreateUser") - } - if len(conf.Password) > 0 { - _, err := self.CreateLoginProfile(conf.Name, conf.Password) - if err != nil { - log.Errorf("failed to create loginProfile for user %s error: %v", conf.Name, err) - } - } - return user, nil -} - -func (self *SAwsClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.GetUser(name) -} - -func (self *SAwsClient) GetUser(name string) (*SUser, error) { - user := struct { - User SUser `xml:"User"` - }{} - params := map[string]string{ - "UserName": name, - } - err := self.iamRequest("GetUser", params, &user) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.GetUser") - } - user.User.client = self - return &user.User, nil -} - -func (self *SAwsClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { - ret := []cloudprovider.IClouduser{} - offset := "" - for { - part, err := self.ListUsers(offset, 1000, "") - if err != nil { - return nil, errors.Wrap(err, "ListUsers") - } - for i := range part.Users { - part.Users[i].client = self - ret = append(ret, &part.Users[i]) - } - offset = part.Marker - if len(offset) == 0 || !part.IsTruncated { - break - } - } - return ret, nil -} - -type LoginProfile struct { - UserName string `xml:"UserName"` - CreateDate time.Time `xml:"CreateDate"` -} -type SLoginProfile struct { - LoginProfile LoginProfile `xml:"LoginProfile"` -} - -func (self *SAwsClient) GetLoginProfile(name string) (*SLoginProfile, error) { - params := map[string]string{ - "UserName": name, - } - loginProfix := &SLoginProfile{} - err := self.iamRequest("GetLoginProfile", params, loginProfix) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.GetLoginProfie") - } - return loginProfix, nil -} - -func (self *SAwsClient) DeleteLoginProfile(name string) error { - params := map[string]string{ - "UserName": name, - } - return self.iamRequest("DeleteLoginProfile", params, nil) -} - -func (self *SAwsClient) CreateLoginProfile(name, password string) (*SLoginProfile, error) { - params := map[string]string{ - "UserName": name, - "Password": password, - } - loginProfile := &SLoginProfile{} - err := self.iamRequest("CreateLoginProfile", params, loginProfile) - if err != nil { - return nil, errors.Wrap(err, "iamRequest.GetLoginProfie") - } - return loginProfile, nil -} - -func (self *SAwsClient) UpdateLoginProfile(name, password string) error { - params := map[string]string{ - "UserName": name, - "Password": password, - } - return self.iamRequest("UpdateLoginProfile", params, nil) -} - -func (self *SAwsClient) ResetUserPassword(name, password string) error { - _, err := self.GetLoginProfile(name) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - _, err = self.CreateLoginProfile(name, password) - return err - } - return errors.Wrap(err, "GetLoginProfile") - } - return self.UpdateLoginProfile(name, password) -} - -func (self *SAwsClient) ListGroupsForUser(name string, offset string, limit int) (*SGroups, error) { - if limit < 1 || limit > 1000 { - limit = 1000 - } - params := map[string]string{ - "UserName": name, - "MaxItems": fmt.Sprintf("%d", limit), - } - if len(offset) > 0 { - params["Marker"] = offset - } - groups := &SGroups{} - err := self.iamRequest("ListGroupsForUser", params, groups) - if err != nil { - return nil, errors.Wrap(err, "ListGroupsForUser") - } - return groups, nil -} diff --git a/pkg/multicloud/aws/image.go b/pkg/multicloud/aws/image.go deleted file mode 100644 index 16b5d40814..0000000000 --- a/pkg/multicloud/aws/image.go +++ /dev/null @@ -1,589 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "fmt" - "time" - - "github.com/aws/aws-sdk-go/service/ec2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/timeutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type ImageStatusType string - -const ( - ImageStatusCreating ImageStatusType = "pending" - ImageStatusAvailable ImageStatusType = "available" - ImageStatusCreateFailed ImageStatusType = "failed" - - ImageImportStatusCompleted = "completed" - ImageImportStatusUncompleted = "uncompleted" - ImageImportStatusError = "error" - ImageImportStatusDeleted = "deleted" -) - -type TImageOwnerType string - -const ( - ImageOwnerTypeSystem = TImageOwnerType("system") - ImageOwnerTypeSelf = TImageOwnerType("self") - ImageOwnerTypeOther = TImageOwnerType("other") -) - -var ( - ImageOwnerAll = []TImageOwnerType(nil) - ImageOwnerSelf = []TImageOwnerType{ImageOwnerTypeSelf} - ImageOwnerSystem = []TImageOwnerType{ImageOwnerTypeSystem} - ImageOwnerSelfSystem = []TImageOwnerType{ImageOwnerTypeSystem, ImageOwnerTypeSelf} -) - -type ImageImportTask struct { - multicloud.SResourceBase - region *SRegion - - ImageId string - RegionId string - TaskId string - Status string -} - -type RootDevice struct { - SnapshotId string - Size int // GB - Category string // VolumeType -} - -type SImage struct { - multicloud.SImageBase - multicloud.AwsTags - storageCache *SStoragecache - - // normalized image info - imgInfo *imagetools.ImageInfo - - Architecture string - CreationTime time.Time - Description string - ImageId string - ImageName string - OSType string - ImageType cloudprovider.TImageType - // IsSupportCloudinit bool - EnaSupport bool - Platform string - SizeGB int - Status ImageStatusType - OwnerType string - // Usage string - RootDevice RootDevice - RootDeviceName string - // devices - BlockDevicesNames []string - - Public bool - Hypervisor string - VirtualizationType string - OwnerId string - - ProductCodes []*ec2.ProductCode - - OSVersion string - OSDist string - OSBuildId string -} - -func (self *ImageImportTask) GetId() string { - return self.TaskId -} - -func (self *ImageImportTask) GetName() string { - return self.GetId() -} - -func (self *ImageImportTask) GetGlobalId() string { - return self.GetId() -} - -func (self *ImageImportTask) Refresh() error { - ec2Client, err := self.region.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.DescribeImportImageTasks(&ec2.DescribeImportImageTasksInput{ImportTaskIds: []*string{&self.TaskId}}) - if err != nil { - log.Errorf("DescribeImportImageTasks %s", err) - return errors.Wrap(err, "ImageImportTask.Refresh.DescribeImportImageTasks") - } - - err = FillZero(ret) - if err != nil { - log.Errorf("DescribeImportImageTask.FillZero %s", err) - return errors.Wrap(err, "ImageImportTask.Refresh.FillZero") - } - - // 打印上传进度 - log.Debugf("DescribeImportImage Task %s", ret.String()) - for _, item := range ret.ImportImageTasks { - if StrVal(item.ImportTaskId) == self.TaskId { - self.ImageId = StrVal(item.ImageId) - self.Status = StrVal(item.Status) - } - } - - return nil -} - -func (self *ImageImportTask) IsEmulated() bool { - return true -} - -func (self *ImageImportTask) GetStatus() string { - self.Refresh() - if self.Status == "completed" { - return ImageImportStatusCompleted - } else if self.Status == "deleted" { - return ImageImportStatusDeleted - } else { - return ImageImportStatusUncompleted - } -} - -func (self *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (self *SImage) GetId() string { - return self.ImageId -} - -func (self *SImage) GetName() string { - if len(self.ImageName) > 0 { - return self.ImageName - } - - return self.GetId() -} - -func (self *SImage) GetGlobalId() string { - return self.ImageId -} - -func (self *SImage) GetStatus() string { - switch self.Status { - case ImageStatusCreating: - return api.CACHED_IMAGE_STATUS_CACHING - case ImageStatusAvailable: - return api.CACHED_IMAGE_STATUS_ACTIVE - case ImageStatusCreateFailed: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - default: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (self *SImage) GetImageStatus() string { - switch self.Status { - case ImageStatusCreating: - return cloudprovider.IMAGE_STATUS_QUEUED - case ImageStatusAvailable: - return cloudprovider.IMAGE_STATUS_ACTIVE - case ImageStatusCreateFailed: - return cloudprovider.IMAGE_STATUS_KILLED - default: - return cloudprovider.IMAGE_STATUS_KILLED - } -} - -func (self *SImage) Refresh() error { - new, err := self.storageCache.region.GetImage(self.ImageId) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - return self.ImageType -} - -func (self *SImage) GetSizeByte() int64 { - return int64(self.SizeGB) * 1024 * 1024 * 1024 -} - -func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if self.imgInfo == nil { - imgInfo := imagetools.NormalizeImageInfo("", self.Architecture, self.OSType, self.OSDist, self.OSVersion) - self.imgInfo = &imgInfo - } - return self.imgInfo -} - -func (self *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) -} - -func (self *SImage) GetOsArch() string { - return self.getNormalizedImageInfo().OsArch -} - -func (self *SImage) GetOsDist() string { - return self.getNormalizedImageInfo().OsDistro -} - -func (self *SImage) GetOsVersion() string { - return self.getNormalizedImageInfo().OsVersion -} - -func (self *SImage) GetOsLang() string { - return self.getNormalizedImageInfo().OsLang -} - -func (self *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) -} - -func (self *SImage) GetFullOsName() string { - return self.getNormalizedImageInfo().GetFullOsName() -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return self.SizeGB -} - -func (self *SImage) GetImageFormat() string { - return "vhd" -} - -func (self *SImage) GetCreatedAt() time.Time { - return self.CreationTime -} - -func (self *SImage) IsEmulated() bool { - return false -} - -func (self *SImage) Delete(ctx context.Context) 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) // Linux|Windows - // 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 - %s", name, osDist)) - 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? - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.ImportImage(params) - if err != nil { - return nil, errors.Wrap(err, "ImportImage") - } - log.Debugf("ImportImage task: %s", ret.String()) - return &ImageImportTask{ImageId: StrVal(ret.ImageId), RegionId: self.RegionId, TaskId: *ret.ImportTaskId, Status: StrVal(ret.Status), region: self}, 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) - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.CreateInstanceExportTask(params) - if err != nil { - return nil, errors.Wrap(err, "CreateInstanceExportTask") - } - - return &ImageExportTask{ImageId: imageId, RegionId: self.RegionId, TaskId: *ret.ExportTask.ExportTaskId}, nil -} - -func (self *SRegion) GetImage(imageId string) (*SImage, error) { - if len(imageId) == 0 { - return nil, fmt.Errorf("GetImage image id should not be empty") - } - - images, err := self.getImages("", ImageOwnerAll, []string{imageId}, "", "", nil, "") - if err != nil { - return nil, errors.Wrap(err, "getImages") - } - if len(images) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "getImages") - } - return &images[0], nil -} - -func (self *SRegion) GetImageByName(name string, owners []TImageOwnerType) (*SImage, error) { - if len(name) == 0 { - return nil, fmt.Errorf("image name should not be empty") - } - - images, err := self.getImages("", owners, nil, name, "hvm", nil, "") - if err != nil { - return nil, errors.Wrap(err, "getImages") - } - if len(images) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "getImages") - } - - log.Debugf("%d image found match name %s", len(images), name) - 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 && volume.Ebs != nil && volume.Ebs.VolumeSize != nil { - return int(*volume.Ebs.VolumeSize), nil - } - } - return 0, fmt.Errorf("image size not found: %s", image.String()) -} - -func getLatestImage(images []SImage) SImage { - var latestBuild string - latestBuildIdx := -1 - for i := range images { - if latestBuildIdx < 0 || comapreImageBuildIds(latestBuild, images[i]) < 0 { - latestBuild = images[i].OSBuildId - latestBuildIdx = i - } - } - return images[latestBuildIdx] -} - -func (self *SRegion) GetImages(status ImageStatusType, owners []TImageOwnerType, imageId []string, name string, virtualizationType string, ownerIds []string, volumeType string, latest bool) ([]SImage, error) { - images, err := self.getImages(status, owners, imageId, name, virtualizationType, ownerIds, volumeType) - if err != nil { - return nil, errors.Wrap(err, "getImages") - } - if !latest { - return images, err - } - noVersionImages := make([]SImage, 0) - versionedImages := make(map[string][]SImage) - for i := range images { - key := fmt.Sprintf("%s%s", images[i].OSDist, images[i].OSVersion) - if len(key) == 0 { - noVersionImages = append(noVersionImages, images[i]) - continue - } - if _, ok := versionedImages[key]; !ok { - versionedImages[key] = make([]SImage, 0) - } - versionedImages[key] = append(versionedImages[key], images[i]) - } - for key := range versionedImages { - noVersionImages = append(noVersionImages, getLatestImage(versionedImages[key])) - } - return noVersionImages, nil -} - -func (self *SRegion) getImages(status ImageStatusType, owners []TImageOwnerType, imageId []string, name string, virtualizationType string, ownerIds []string, volumeType string) ([]SImage, 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(virtualizationType) > 0 { - filters = AppendSingleValueFilter(filters, "virtualization-type", virtualizationType) - } - - if len(volumeType) > 0 { - filters = AppendSingleValueFilter(filters, "block-device-mapping.volume-type", volumeType) - } - - filters = AppendSingleValueFilter(filters, "image-type", "machine") - - if len(owners) > 0 || len(ownerIds) > 0 { - params.SetOwners(imageOwnerTypes2Strings(owners, ownerIds)) - } - - if len(imageId) > 0 { - params.SetImageIds(ConvertedList(imageId)) - } - - if len(filters) > 0 { - params.SetFilters(filters) - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.DescribeImages(params) - err = parseNotFoundError(err) - if err != nil { - return nil, errors.Wrap(err, "parseNotFoundError") - } - - images := []SImage{} - for i := range ret.Images { - image := ret.Images[i] - - if err := FillZero(image); err != nil { - return nil, errors.Wrap(err, "FillZero.image") - } - - tagspec := TagSpec{} - tagspec.LoadingEc2Tags(image.Tags) - - size, err := getRootDiskSize(image) - if err != nil { - // fail to get disk size, ignore the image - /// log.Debugln(err) - continue - } - - var rootDevice RootDevice - devicesName := []string{} - 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) - } - - devicesName = append(devicesName, *block.DeviceName) - } - - osType := "" - if StrVal(image.Platform) != "windows" { - osType = "Linux" - } else { - osType = "Windows" - } - - createTime, _ := timeutils.ParseTimeStr(*image.CreationDate) - - name := tagspec.GetNameTag() - if len(name) == 0 && image.Name != nil { - name = *image.Name - } - - sImage := SImage{ - storageCache: self.getStoragecache(), - Architecture: *image.Architecture, - Description: *image.Description, - ImageId: *image.ImageId, - Public: *image.Public, - ImageName: name, - OSType: osType, - // ImageType: *image.ImageType, - OwnerType: *image.ImageOwnerAlias, - EnaSupport: *image.EnaSupport, - Platform: *image.Platform, - RootDeviceName: *image.RootDeviceName, - BlockDevicesNames: devicesName, - Status: ImageStatusType(*image.State), - CreationTime: createTime, - SizeGB: size, - RootDevice: rootDevice, - VirtualizationType: *image.VirtualizationType, - Hypervisor: *image.Hypervisor, - ProductCodes: image.ProductCodes, - OwnerId: *image.OwnerId, - } - sImage.ImageType = getImageType(sImage) - sImage.OSType = getImageOSType(sImage) - sImage.OSDist = getImageOSDist(sImage) - sImage.OSVersion = getImageOSVersion(sImage) - sImage.OSBuildId = getImageOSBuildID(sImage) - images = append(images, sImage) - } - - return images, nil -} - -func (self *SRegion) DeleteImage(imageId string) error { - params := &ec2.DeregisterImageInput{} - params.SetImageId(imageId) - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.DeregisterImage(params) - return errors.Wrap(err, "DeregisterImage") -} - -func (self *SRegion) addTags(resId string, key string, value string) error { - input := &ec2.CreateTagsInput{} - input.SetResources([]*string{&resId}) - tag := ec2.Tag{} - tag.Key = &key - tag.Value = &value - input.SetTags([]*ec2.Tag{&tag}) - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.CreateTags(input) - if err != nil { - return errors.Wrap(err, "CreateTags") - } - return nil -} diff --git a/pkg/multicloud/aws/imageowners_test.go b/pkg/multicloud/aws/imageowners_test.go deleted file mode 100644 index 7b31331051..0000000000 --- a/pkg/multicloud/aws/imageowners_test.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "regexp" - "testing" -) - -func TestImageDistMatch(t *testing.T) { - cases := []struct { - pattern *regexp.Regexp - match string - }{ - {SUSE_SLES, "suse-sles-11-v20161021-hvm-ssd-x86_64"}, - {SUSE_SLES_SP, "suse-sles-11-sp4-v20161021-hvm-ssd-x86_64"}, - {SUSE_SLES_RIGHTLINK, "suse-sles-11-rightscale-v20160804-hvm-ssd-x86_64"}, - {SUSE_SLES_RIGHTLINK_SP, "suse-sles-11-sp4-rightscale-v20160804-hvm-ssd-x86_64"}, - {SUSE_SLES_SAPCAL, "suse-sles-11-sapcal-20150729-hvm-mag-x86_64"}, - {SUSE_SLES_SAPCAL_SP, "suse-sles-11-sp4-sapcal-20150729-hvm-mag-x86_64"}, - {SUSE_SLES_BYOS, "suse-sles-15-byos-v20180806-hvm-ssd-x86_64"}, - {SUSE_SLES_BYOS_SP, "suse-sles-15-sp4-byos-v20180806-hvm-ssd-x86_64"}, - {SUSE_SLES_SAP, "suse-sles-sap-12-v20180706-hvm-ssd-x86_64"}, - {SUSE_SLES_SAP_SP, "suse-sles-sap-12-sp2-v20180706-hvm-ssd-x86_64"}, - {SUSE_SLES_SAP_BYOS, "suse-sles-sap-12-byos-v20180706-hvm-ssd-x86_64"}, - {SUSE_SLES_SAP_BYOS_SP, "suse-sles-sap-12-sp2-byos-v20180706-hvm-ssd-x86_64"}, - {SUSE_CAASP_CLUSTER_BYOS, "suse-caasp-2-1-cluster-byos-v20180815-hvm-ssd-x86_64"}, - {SUSE_CAASP_ADMIN_BYOS, "suse-caasp-2-1-admin-byos-v20180524-hvm-ssd-x86_64"}, - {SUSE_MANAGER_SERVER_BYOS, "suse-manager-3-1-server-byos-v20170627-hvm-ssd-x86_64"}, - {SUSE_MANAGER_PROXY_BYOS, "suse-manager-3-1-proxy-byos-v20180215-hvm-ssd-x86_64"}, - } - for _, c := range cases { - if !c.pattern.MatchString(c.match) { - t.Errorf("not match %s %s", c.pattern, c.match) - } - } -} diff --git a/pkg/multicloud/aws/instance.go b/pkg/multicloud/aws/instance.go deleted file mode 100644 index 89abc907ee..0000000000 --- a/pkg/multicloud/aws/instance.go +++ /dev/null @@ -1,1376 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "encoding/base64" - "fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/service/ec2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/apis" - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/compute/options" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/cloudinit" -) - -const ( - InstanceStatusPending = "pending" - InstanceStatusRunning = "running" - InstanceStatusShutting = "shutting-down" - InstanceStatusTerminated = "terminated" - InstanceStatusStopping = "stopping" - InstanceStatusStopped = "stopped" -) - -type InstanceChargeType string - -type SIpAddress struct { - IpAddress []string -} - -type SSecurityGroupIds struct { - SecurityGroupId []string -} - -type SVpcAttributes struct { - PrivateIpAddress SIpAddress - NetworkId string // subnet id - VpcId string -} - -type SInstance struct { - multicloud.SInstanceBase - - host *SHost - img *SImage - RegionId string - ZoneId string - InstanceId string - ImageId string - - HostName string - InstanceName string - InstanceType string - Cpu int - Memory int // MB - 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 []SNetworkInterface - EipAddress SEipAddress - Disks []string - DeviceNames []string - OSName string - OSType string - Description string - InternetMaxBandwidthOut int - Throughput int - - TagSpec TagSpec - - // 这些貌似都没啥用 - // 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 { - udata := &ec2.BlobAttributeValue{} - udata.SetValue([]byte(userData)) - - input := &ec2.ModifyInstanceAttributeInput{} - input.SetUserData(udata) - input.SetInstanceId(self.GetId()) - ec2Client, err := self.host.zone.region.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.ModifyInstanceAttribute(input) - if err != nil { - return errors.Wrap(err, "ModifyInstanceAttribute") - } - - return nil -} - -func (self *SInstance) GetUserData() (string, error) { - input := &ec2.DescribeInstanceAttributeInput{} - input.SetInstanceId(self.GetId()) - input.SetAttribute("userData") - ec2Client, err := self.host.zone.region.getEc2Client() - if err != nil { - return "", errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.DescribeInstanceAttribute(input) - if err != nil { - return "", err - } - - d := StrVal(ret.UserData.Value) - udata, err := base64.StdEncoding.DecodeString(d) - if err != nil { - return "", fmt.Errorf("GetUserData decode user data %s", err) - } - - return string(udata), nil -} - -func (self *SInstance) GetId() string { - return self.InstanceId -} - -func (self *SInstance) GetName() string { - if len(self.InstanceName) > 0 { - return self.InstanceName - } - - return self.GetId() -} - -func (self *SInstance) GetHostname() string { - return self.GetName() -} - -func (self *SInstance) GetGlobalId() string { - return self.InstanceId -} - -func (self *SInstance) GetStatus() string { - switch self.Status { - case InstanceStatusRunning: - return api.VM_RUNNING - case InstanceStatusPending: // todo: pending ? - return api.VM_STARTING - case InstanceStatusStopping: - return api.VM_STOPPING - case InstanceStatusStopped: - return api.VM_READY - default: - return api.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) GetInstanceType() string { - return self.InstanceType -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - return self.SecurityGroupIds.SecurityGroupId, nil -} - -func (self *SInstance) GetTags() (map[string]string, error) { - return self.TagSpec.GetTags() -} - -func (self *SInstance) GetSysTags() map[string]string { - return map[string]string{} -} - -func (self *SInstance) GetBillingType() string { - // todo: implement me - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SInstance) GetCreatedAt() time.Time { - return self.CreationTime -} - -func (self *SInstance) GetExpiredAt() time.Time { - return self.ExpiredTime -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetThroughput() int { - return self.Throughput -} - -func (self *SInstance) GetInternetMaxBandwidthOut() int { - return self.InternetMaxBandwidthOut -} - -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, errors.Wrap(err, "GetDisks") - } - - 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, errors.Wrap(err, "getStorageByCategory") - } - disks[i].storage = store - idisks[i] = &disks[i] - } - return idisks, nil -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - var ( - networkInterfaces = self.NetworkInterfaces - nics = make([]cloudprovider.ICloudNic, 0) - ) - for _, networkInterface := range networkInterfaces { - nic := SInstanceNic{ - instance: self, - id: networkInterface.NetworkInterfaceId, - ipAddr: networkInterface.PrivateIpAddress, - macAddr: networkInterface.MacAddress, - } - nics = append(nics, &nic) - } - return nics, nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - if len(self.EipAddress.PublicIp) > 0 { - return self.host.zone.region.GetEipByIpAddress(self.EipAddress.PublicIp) - } - if len(self.PublicIpAddress.IpAddress) > 0 { - eip := SEipAddress{region: self.host.zone.region} - eip.region = self.host.zone.region - eip.PublicIp = self.PublicIpAddress.IpAddress[0] - eip.InstanceId = self.InstanceId - eip.AllocationId = self.InstanceId // fixed. AllocationId等于InstanceId即表示为 仿真EIP。 - return &eip, nil - } - return nil, nil -} - -func (self *SInstance) GetVcpuCount() int { - 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() cloudprovider.TOsType { - return cloudprovider.TOsType(osprofile.NormalizeOSType(self.OSType)) -} - -func (self *SInstance) GetFullOsName() string { - return self.OSName -} - -func (self *SInstance) GetBios() cloudprovider.TBiosType { - img, err := self.GetImage() - if err != nil { - log.Errorf("GetImage fail %s", err) - return cloudprovider.BIOS - } - return img.GetBios() -} - -func (self *SInstance) GetOsArch() string { - img, err := self.GetImage() - if err != nil { - log.Errorf("GetImage fail %s", err) - return apis.OS_ARCH_X86_64 - } - return img.GetOsArch() -} - -func (self *SInstance) GetOsDist() string { - img, err := self.GetImage() - if err != nil { - log.Errorf("GetImage fail %s", err) - return "" - } - return img.GetOsDist() -} - -func (self *SInstance) GetOsVersion() string { - img, err := self.GetImage() - if err != nil { - log.Errorf("GetImage fail %s", err) - return "" - } - return img.GetOsVersion() -} - -func (self *SInstance) GetOsLang() string { - img, err := self.GetImage() - if err != nil { - log.Errorf("GetImage fail %s", err) - return "" - } - return img.GetOsLang() -} - -func (self *SInstance) GetMachine() string { - return "pc" -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - return self.SetSecurityGroups([]string{secgroupId}) -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - ids := []*string{} - for i := 0; i < len(secgroupIds); i++ { - ids = append(ids, &secgroupIds[i]) - } - return self.host.zone.region.assignSecurityGroups(ids, self.InstanceId) -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_AWS -} - -func (self *SInstance) StartVM(ctx context.Context) 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 - } - - if self.GetStatus() == api.VM_RUNNING { - return nil - } else if self.GetStatus() == api.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(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - err := self.host.zone.region.StopVM(self.InstanceId, opts.IsForce) - if err != nil { - return err - } - return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - for { - err := self.host.zone.region.DeleteVM(self.InstanceId) - if err != nil && self.Status != InstanceStatusTerminated { - return err - } else { - break - } - } - - params := &ec2.DescribeInstancesInput{InstanceIds: []*string{&self.InstanceId}} - ec2Client, err := self.host.zone.region.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - return ec2Client.WaitUntilInstanceTerminated(params) -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - addTags := map[string]string{} - addTags["Name"] = name - Arn := self.GetArn() - err := self.host.zone.region.TagResources([]string{Arn}, addTags) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.TagResources([]string{%s}, %s)", Arn, jsonutils.Marshal(addTags).String()) - } - return nil -} - -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - udata, err := self.GetUserData() - if err != nil { - return "", err - } - - // compare sysSizeGB - image, err := self.host.zone.region.GetImage(desc.ImageId) - if err != nil { - return "", err - } else { - minSizeGB := image.GetMinOsDiskSizeGb() - if minSizeGB > desc.SysSizeGB { - desc.SysSizeGB = minSizeGB - } - } - - // upload keypair - keypairName := self.KeyPairName - if len(desc.PublicKey) > 0 { - keypairName, err = self.host.zone.region.syncKeypair(desc.PublicKey) - if err != nil { - return "", fmt.Errorf("RebuildRoot.syncKeypair %s", err) - } - } - - userdata := "" - srcOsType := strings.ToLower(string(self.GetOsType())) - destOsType := strings.ToLower(string(image.GetOsType())) - winOS := strings.ToLower(osprofile.OS_TYPE_WINDOWS) - - cloudconfig := &cloudinit.SCloudConfig{} - if srcOsType != winOS && len(udata) > 0 { - _cloudconfig, err := cloudinit.ParseUserDataBase64(udata) - if err != nil { - // 忽略无效的用户数据 - log.Debugf("RebuildRoot invalid instance user data %s", udata) - } else { - cloudconfig = _cloudconfig - } - } - - if (srcOsType != winOS && destOsType != winOS) || (srcOsType == winOS && destOsType != winOS) { - // linux/windows to linux - loginUser := cloudinit.NewUser(api.VM_AWS_DEFAULT_LOGIN_USER) - loginUser.SudoPolicy(cloudinit.USER_SUDO_NOPASSWD) - if len(desc.PublicKey) > 0 { - loginUser.SshKey(desc.PublicKey) - cloudconfig.MergeUser(loginUser) - } else if len(desc.Password) > 0 { - cloudconfig.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON - loginUser.Password(desc.Password) - cloudconfig.MergeUser(loginUser) - } - - userdata = cloudconfig.UserDataBase64() - } else { - // linux/windows to windows - data := "" - if len(desc.Password) > 0 { - cloudconfig.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON - loginUser := cloudinit.NewUser(api.VM_AWS_DEFAULT_WINDOWS_LOGIN_USER) - loginUser.SudoPolicy(cloudinit.USER_SUDO_NOPASSWD) - loginUser.Password(desc.Password) - cloudconfig.MergeUser(loginUser) - data = fmt.Sprintf("%s", cloudconfig.UserDataPowerShell()) - } else { - if len(udata) > 0 { - data = fmt.Sprintf("%s", udata) - } - } - - userdata = base64.StdEncoding.EncodeToString([]byte(data)) - } - - diskId, err := self.host.zone.region.ReplaceSystemDisk(ctx, self.InstanceId, image, desc.SysSizeGB, keypairName, userdata) - if err != nil { - return "", err - } - - return diskId, nil -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username 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(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - if len(config.InstanceType) > 0 { - return self.ChangeConfig2(ctx, config.InstanceType) - } - return errors.Wrap(errors.ErrClient, "Instance.ChangeConfig.InstanceTypeIsEmpty") -} - -func (self *SInstance) ChangeConfig2(ctx context.Context, instanceType string) error { - return self.host.zone.region.ChangeVMConfig2(self.ZoneId, self.InstanceId, instanceType, nil) -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetImage() (*SImage, error) { - if self.img != nil { - return self.img, nil - } - - img, err := self.host.zone.region.GetImage(self.ImageId) - if err != nil { - return nil, errors.Wrap(err, "GetImage") - } - - self.img = img - return self.img, nil -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - img, err := self.GetImage() - if err != nil { - return errors.Wrap(err, "GetImage") - } - - // mix in image block device names - for i := range img.BlockDevicesNames { - if !utils.IsInStringArray(img.BlockDevicesNames[i], self.DeviceNames) { - self.DeviceNames = append(self.DeviceNames, img.BlockDevicesNames[i]) - } - } - - name, err := NextDeviceName(self.DeviceNames) - if err != nil { - return err - } - - err = self.host.zone.region.AttachDisk(self.InstanceId, diskId, name) - if err != nil { - return err - } - - self.DeviceNames = append(self.DeviceNames, name) - return nil -} - -func (self *SInstance) DetachDisk(ctx context.Context, 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) - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, 0, errors.Wrap(err, "getEc2Client") - } - res, err := ec2Client.DescribeInstances(params) - if err != nil { - if strings.Contains(err.Error(), "InvalidInstanceID.NotFound") { - return nil, 0, errors.Wrap(cloudprovider.ErrNotFound, "DescribeInstances") - } else { - return nil, 0, err - } - } - - instances := []SInstance{} - for _, reservation := range res.Reservations { - for _, instance := range reservation.Instances { - if err := FillZero(instance); err != nil { - return nil, 0, err - } - - // 不同步已经terminated的主机 - if *instance.State.Name == ec2.InstanceStateNameTerminated { - continue - } - - 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) - } - } - - networkInterfaces := []SNetworkInterface{} - eipAddress := SEipAddress{} - for _, n := range instance.NetworkInterfaces { - i := SNetworkInterface{ - MacAddress: *n.MacAddress, - NetworkInterfaceId: *n.NetworkInterfaceId, - PrivateIpAddress: *n.PrivateIpAddress, - } - networkInterfaces = append(networkInterfaces, i) - - // todo: 可能有多个EIP的情况。目前只支持一个EIP - if n.Association != nil && StrVal(n.Association.IpOwnerId) != "amazon" { - if eipAddress.PublicIp == "" && len(StrVal(n.Association.PublicIp)) > 0 { - eipAddress.PublicIp = *n.Association.PublicIp - } - } - } - - 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) - } - - publicIpAddress := SIpAddress{} - if len(*instance.PublicIpAddress) > 0 { - publicIpAddress.IpAddress = []string{*instance.PublicIpAddress} - } - - innerIpAddress := SIpAddress{} - if len(*instance.PrivateIpAddress) > 0 { - innerIpAddress.IpAddress = []string{*instance.PrivateIpAddress} - } - - szone, err := self.getZoneById(*instance.Placement.AvailabilityZone) - if err != nil { - log.Errorf("getZoneById %s fail %s", *instance.Placement.AvailabilityZone, err) - return nil, 0, err - } - - osType := "Linux" - if instance.Platform != nil && len(*instance.Platform) > 0 { - osType = *instance.Platform - } - - host := szone.getHost() - vcpu := int(*instance.CpuOptions.CoreCount) * int(*instance.CpuOptions.ThreadsPerCore) - sinstance := SInstance{ - RegionId: self.RegionId, - host: host, - ZoneId: *instance.Placement.AvailabilityZone, - InstanceId: *instance.InstanceId, - ImageId: *instance.ImageId, - InstanceType: *instance.InstanceType, - Cpu: vcpu, - IoOptimized: *instance.EbsOptimized, - KeyPairName: *instance.KeyName, - CreationTime: *instance.LaunchTime, - PublicDNSName: *instance.PublicDnsName, - RootDeviceName: *instance.RootDeviceName, - Status: *instance.State.Name, - InnerIpAddress: innerIpAddress, - PublicIpAddress: publicIpAddress, - EipAddress: eipAddress, - InstanceName: tagspec.GetNameTag(), - Description: tagspec.GetDescTag(), - Disks: disks, - DeviceNames: devicenames, - SecurityGroupIds: secgroups, - NetworkInterfaces: networkInterfaces, - VpcAttributes: vpcattr, - ProductCodes: productCodes, - OSName: osType, // todo: 这里在model层回写OSName信息 - OSType: osType, - - TagSpec: tagspec, - // ExpiredTime: - // VlanId: - // OSType: - } - - instances = append(instances, sinstance) - } - } - - return instances, len(instances), nil -} - -func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) { - if len(instanceId) == 0 { - return nil, fmt.Errorf("GetInstance instanceId should not be empty.") - } - - instances, _, err := self.GetInstances("", []string{instanceId}, 0, 1) - if err != nil { - log.Errorf("GetInstances %s: %s", instanceId, err) - return nil, errors.Wrap(err, "GetInstances") - } - if len(instances) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetInstances") - } - 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) - - ec2Client, err := self.getEc2Client() - if err != nil { - return "", errors.Wrap(err, "getEc2Client") - } - ret, err := 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, image *SImage, instanceType string, SubnetId string, securityGroupId string, - zoneId string, desc string, disks []SDisk, ipAddr string, - keypair string, userData string, ntags map[string]string, -) (string, error) { - var count int64 = 1 - // disk - blockDevices := []*ec2.BlockDeviceMapping{} - for i := range disks { - var ebs ec2.EbsBlockDevice - var deviceName string - var err error - disk := disks[i] - - if i == 0 { - var size int64 - deleteOnTermination := true - size = int64(disk.Size) - ebs = ec2.EbsBlockDevice{ - DeleteOnTermination: &deleteOnTermination, - // 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, - } - - if len(image.RootDeviceName) > 0 { - deviceName = image.RootDeviceName - } else { - deviceName = fmt.Sprintf("/dev/sda1") - } - } else { - var size int64 - size = int64(disk.Size) - ebs = ec2.EbsBlockDevice{ - DeleteOnTermination: &disk.DeleteWithInstance, - Encrypted: &disk.Encrypted, - VolumeSize: &size, - VolumeType: &disk.Category, - } - - deviceName, err = NextDeviceName(image.BlockDevicesNames) - if err != nil { - return "", errors.Wrap(err, "NextDeviceName") - } - } - - if iops := GenDiskIops(disk.Category, disk.Size); iops > 0 { - ebs.SetIops(iops) - } - - blockDevice := &ec2.BlockDeviceMapping{ - DeviceName: &deviceName, - Ebs: &ebs, - } - - blockDevices = append(blockDevices, blockDevice) - } - - // tags - tags := TagSpec{ResourceType: "instance"} - tags.SetNameTag(name) - tags.SetDescTag(desc) - - if len(ntags) > 0 { - for k, v := range ntags { - tags.SetTag(k, v) - } - } - - ec2TagSpec, err := tags.GetTagSpecifications() - if err != nil { - return "", err - } - - imgId := image.GetId() - params := ec2.RunInstancesInput{ - ImageId: &imgId, - InstanceType: &instanceType, - MaxCount: &count, - MinCount: &count, - BlockDeviceMappings: blockDevices, - Placement: &ec2.Placement{AvailabilityZone: &zoneId}, - TagSpecifications: []*ec2.TagSpecification{ec2TagSpec}, - } - params.Monitoring = &ec2.RunInstancesMonitoringEnabled{ - Enabled: &options.Options.EnableAwsMonitorAgent, - } - - // keypair - if len(keypair) > 0 { - params.SetKeyName(keypair) - } - - // user data - if len(userData) > 0 { - params.SetUserData(userData) - } - - // ip address - if len(ipAddr) > 0 { - params.SetPrivateIpAddress(ipAddr) - } - - // subnet id - if len(SubnetId) > 0 { - params.SetSubnetId(SubnetId) - } - - // security group - if len(securityGroupId) > 0 { - params.SetSecurityGroupIds([]*string{&securityGroupId}) - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return "", errors.Wrap(err, "getEc2Client") - } - res, err := ec2Client.RunInstances(¶ms) - 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: %d 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) StartVM(instanceId string) error { - params := &ec2.StartInstancesInput{} - params.SetInstanceIds([]*string{&instanceId}) - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.StartInstances(params) - return errors.Wrap(err, "StartInstances") -} - -func (self *SRegion) StopVM(instanceId string, isForce bool) error { - params := &ec2.StopInstancesInput{} - params.SetInstanceIds([]*string{&instanceId}) - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.StopInstances(params) - return errors.Wrap(err, "StopInstances") -} - -func (self *SRegion) DeleteVM(instanceId string) error { - // 检查删除保护状态.如果已开启则先关闭删除保护再进行删除操作 - protect, err := self.deleteProtectStatusVM(instanceId) - if err != nil { - return err - } - - if protect { - log.Warningf("DeleteVM instance %s which termination protect is in open status", instanceId) - err = self.deleteProtectVM(instanceId, false) - if err != nil { - return err - } - } - - params := &ec2.TerminateInstancesInput{} - params.SetInstanceIds([]*string{&instanceId}) - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.TerminateInstances(params) - return errors.Wrap(err, "TerminateInstances") -} - -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) - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - ec2Tag, _ := tagspec.GetTagSpecifications() - if len(ec2Tag.Tags) > 0 { - params.SetTags(ec2Tag.Tags) - _, err := 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 cloudprovider.ErrNotSupported -} - -func (self *SRegion) ReplaceSystemDisk(ctx context.Context, instanceId string, image *SImage, sysDiskSizeGB int, keypair string, userdata string) (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 == api.DISK_TYPE_SYS { - rootDisk = &disk - break - } - } - - if rootDisk == nil { - return "", fmt.Errorf("can not find root disk of instance %s", instanceId) - } - log.Debugf("ReplaceSystemDisk replace root disk %s", rootDisk.DiskId) - - subnetId := "" - if len(instance.VpcAttributes.NetworkId) > 0 { - subnetId = instance.VpcAttributes.NetworkId - } - - // create tmp server - tempName := fmt.Sprintf("__tmp_%s", instance.GetName()) - _id, err := self.CreateInstance(tempName, - image, - instance.InstanceType, - subnetId, - "", - instance.ZoneId, - instance.Description, - []SDisk{{Size: sysDiskSizeGB, Category: rootDisk.Category}}, - "", - keypair, - userdata, - nil, - ) - if err == nil { - defer self.DeleteVM(_id) - } else { - log.Debugf("ReplaceSystemDisk create temp server failed. %s", err) - return "", fmt.Errorf("ReplaceSystemDisk create temp server failed.") - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return "", errors.Wrap(err, "getEc2Client") - } - - ec2Client.WaitUntilInstanceRunning(&ec2.DescribeInstancesInput{InstanceIds: []*string{&_id}}) - err = self.StopVM(_id, true) - if err != nil { - log.Debugf("ReplaceSystemDisk stop temp server failed %s", err) - return "", fmt.Errorf("ReplaceSystemDisk stop temp server failed") - } - ec2Client.WaitUntilInstanceStopped(&ec2.DescribeInstancesInput{InstanceIds: []*string{&_id}}) - - // detach disks - tempInstance, err := self.GetInstance(_id) - if err != nil { - log.Debugf("ReplaceSystemDisk get temp server failed %s", err) - return "", fmt.Errorf("ReplaceSystemDisk get temp server failed") - } - - err = self.DetachDisk(instance.GetId(), rootDisk.DiskId) - if err != nil { - log.Debugf("ReplaceSystemDisk detach disk %s: %s", rootDisk.DiskId, err) - return "", err - } - - err = self.DetachDisk(tempInstance.GetId(), tempInstance.Disks[0]) - if err != nil { - log.Debugf("ReplaceSystemDisk detach disk %s: %s", tempInstance.Disks[0], err) - return "", err - } - ec2Client.WaitUntilVolumeAvailable(&ec2.DescribeVolumesInput{VolumeIds: []*string{&rootDisk.DiskId}}) - ec2Client.WaitUntilVolumeAvailable(&ec2.DescribeVolumesInput{VolumeIds: []*string{&tempInstance.Disks[0]}}) - - err = self.AttachDisk(instance.GetId(), tempInstance.Disks[0], rootDisk.Device) - if err != nil { - log.Debugf("ReplaceSystemDisk attach disk %s: %s", tempInstance.Disks[0], err) - return "", err - } - ec2Client.WaitUntilInstanceStopped(&ec2.DescribeInstancesInput{InstanceIds: []*string{&instanceId}}) - ec2Client.WaitUntilVolumeInUse(&ec2.DescribeVolumesInput{VolumeIds: []*string{&tempInstance.Disks[0]}}) - - userdataText, err := base64.StdEncoding.DecodeString(userdata) - if err != nil { - return "", errors.Wrap(err, "SRegion.ReplaceSystemDisk.DecodeString") - } - err = instance.UpdateUserData(string(userdataText)) - if err != nil { - log.Debugf("ReplaceSystemDisk update user data %s", err) - return "", fmt.Errorf("ReplaceSystemDisk update user data failed") - } - - err = self.DeleteDisk(rootDisk.DiskId) - if err != nil { - log.Debugf("ReplaceSystemDisk delete old disk %s: %s", rootDisk.DiskId, err) - } - return tempInstance.Disks[0], nil -} - -func (self *SRegion) ChangeVMConfig2(zoneId string, instanceId string, instanceType string, disks []*SDisk) error { - params := &ec2.ModifyInstanceAttributeInput{} - params.SetInstanceId(instanceId) - - t := &ec2.AttributeValue{Value: &instanceType} - params.SetInstanceType(t) - - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.ModifyInstanceAttribute(params) - if err != nil { - return fmt.Errorf("Failed to change vm config, specification not supported. %s", err.Error()) - } else { - return nil - } -} - -func (self *SRegion) DetachDisk(instanceId string, diskId string) error { - params := &ec2.DetachVolumeInput{} - params.SetInstanceId(instanceId) - params.SetVolumeId(diskId) - log.Debugf("DetachDisk %s", params.String()) - - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - _, err = ec2Client.DetachVolume(params) - if err != nil { - if strings.Contains(err.Error(), fmt.Sprintf("'%s'is in the 'available' state", diskId)) { - return nil - } - //InvalidVolume.NotFound: The volume 'vol-0a9eeda0a70a8d7fe' does not exist - if strings.Contains(err.Error(), "InvalidVolume.NotFound") { - return nil - } - return errors.Wrap(err, "ec2Client.DetachVolume") - } - return nil -} - -func (self *SRegion) AttachDisk(instanceId string, diskId string, deviceName string) error { - params := &ec2.AttachVolumeInput{} - params.SetInstanceId(instanceId) - params.SetVolumeId(diskId) - params.SetDevice(deviceName) - log.Debugf("AttachDisk %s", params.String()) - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.AttachVolume(params) - return errors.Wrap(err, "AttachVolume") -} - -func (self *SRegion) deleteProtectStatusVM(instanceId string) (bool, error) { - p := &ec2.DescribeInstanceAttributeInput{} - p.SetInstanceId(instanceId) - p.SetAttribute("disableApiTermination") - ec2Client, err := self.getEc2Client() - if err != nil { - return false, errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.DescribeInstanceAttribute(p) - if err != nil { - return false, err - } - - return *ret.DisableApiTermination.Value, nil -} - -func (self *SRegion) deleteProtectVM(instanceId string, disableDelete bool) error { - p2 := &ec2.ModifyInstanceAttributeInput{ - DisableApiTermination: &ec2.AttributeBooleanValue{Value: &disableDelete}, - InstanceId: &instanceId, - } - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.ModifyInstanceAttribute(p2) - return errors.Wrap(err, "ModifyInstanceAttribute") -} - -func (self *SRegion) getPasswordData(instanceId string) (string, error) { - params := &ec2.GetPasswordDataInput{} - params.SetInstanceId(instanceId) - - ec2Client, err := self.getEc2Client() - if err != nil { - return "", errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.GetPasswordData(params) - if err != nil { - return "", err - } - - return *ret.PasswordData, nil -} - -func (self *SInstance) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetProjectId() string { - return "" -} - -func (self *SInstance) GetError() error { - return nil -} - -func (self *SInstance) SetTags(tags map[string]string, replace bool) error { - ec2Client, err := self.host.zone.region.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - oldTagsJson, err := FetchTags(ec2Client, self.InstanceId) - if err != nil { - return errors.Wrapf(err, "FetchTags(self.host.zone.region.ec2Client, %s)", self.InstanceId) - } - oldTags := map[string]string{} - err = oldTagsJson.Unmarshal(oldTags) - if err != nil { - return errors.Wrapf(err, "(%s).Unmarshal(oldTags)", oldTagsJson.String()) - } - addTags := map[string]string{} - for k, v := range tags { - if strings.HasPrefix(k, "aws:") { - return errors.Wrap(cloudprovider.ErrNotSupported, "The aws: prefix is reserved for AWS use") - } - if _, ok := oldTags[k]; !ok { - addTags[k] = v - } else { - if oldTags[k] != v { - addTags[k] = v - } - } - } - delTags := []string{} - if replace { - for k := range oldTags { - if _, ok := tags[k]; !ok { - if !strings.HasPrefix(k, "aws:") && k != "Name" { - delTags = append(delTags, k) - } - } - } - } - Arn := self.GetArn() - err = self.host.zone.region.UntagResources([]string{Arn}, delTags) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.UntagResources([]string{%s}, %s)", Arn, jsonutils.Marshal(delTags).String()) - } - delete(addTags, "Name") - err = self.host.zone.region.TagResources([]string{Arn}, addTags) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.TagResources([]string{%s}, %s)", Arn, jsonutils.Marshal(addTags).String()) - } - return nil -} - -func (self *SInstance) GetAccountId() string { - identity, err := self.host.zone.region.client.GetCallerIdentity() - if err != nil { - log.Errorf(err.Error() + "self.region.client.GetCallerIdentity()") - return "" - } - return identity.Account -} - -func (self *SInstance) GetArn() string { - partition := "" - switch self.host.zone.region.client.GetAccessEnv() { - case api.CLOUD_ACCESS_ENV_AWS_GLOBAL: - partition = "aws" - case api.CLOUD_ACCESS_ENV_AWS_CHINA: - partition = "aws-cn" - default: - partition = "aws" - } - return fmt.Sprintf("arn:%s:ec2:%s:%s:instance/%s", partition, self.host.zone.region.GetId(), self.GetAccountId(), self.InstanceId) -} - -func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { - params := map[string]string{ - "Description": opts.Notes, - "InstanceId": instanceId, - "Name": opts.Name, - } - ret := struct { - ImageId string `xml:"imageId"` - }{} - err := self.ec2Request("CreateImage", params, &ret) - if err != nil { - return nil, errors.Wrapf(err, "CreateImage") - } - err = cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) { - _, err := self.GetImage(ret.ImageId) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return false, nil - } - return false, errors.Wrapf(err, "GetImage(%s)", ret.ImageId) - } - return true, nil - }) - if err != nil { - return nil, errors.Wrapf(err, "wait for image created") - } - image, err := self.GetImage(ret.ImageId) - if err != nil { - return nil, errors.Wrapf(err, "GetImage(%s)", ret.ImageId) - } - image.storageCache = self.getStoragecache() - return image, nil -} - -func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { - image, err := self.host.zone.region.SaveImage(self.InstanceId, opts) - if err != nil { - return nil, errors.Wrapf(err, "SaveImage") - } - return image, nil -} diff --git a/pkg/multicloud/aws/instancenic.go b/pkg/multicloud/aws/instancenic.go deleted file mode 100644 index e6125f22b1..0000000000 --- a/pkg/multicloud/aws/instancenic.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "strings" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ec2" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - instance *SInstance - - id string - ipAddr string - macAddr string - - cloudprovider.DummyICloudNic -} - -func (self *SInstanceNic) GetId() string { - return self.id -} - -func (self *SInstanceNic) GetIP() string { - return self.ipAddr -} - -func (self *SInstanceNic) GetMAC() string { - return self.macAddr -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (self *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (self *SInstanceNic) GetINetworkId() string { - return self.instance.VpcAttributes.NetworkId -} - -func (self *SInstanceNic) getEc2Client() *ec2.EC2 { - ec2Client, err := self.instance.host.zone.region.getEc2Client() - if err != nil { - return nil - } - return ec2Client -} - -func (self *SInstanceNic) GetSubAddress() ([]string, error) { - var ( - ec2Client = self.getEc2Client() - id = self.GetId() - input = &ec2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: []*string{ - aws.String(id), - }, - } - ) - output, err := ec2Client.DescribeNetworkInterfaces(input) - if err != nil { - return nil, errors.Wrapf(err, "aws ec2 DescribeNetworkInterfaces") - } - if got := len(output.NetworkInterfaces); got != 1 { - return nil, errors.Errorf("got aws %d network interface, want 1", got) - } - networkInterface := output.NetworkInterfaces[0] - if got := aws.StringValue(networkInterface.NetworkInterfaceId); got != id { - return nil, errors.Errorf("got aws network interface %s, want %s", got, id) - } - var ipAddrs []string - for _, privateIp := range networkInterface.PrivateIpAddresses { - if !aws.BoolValue(privateIp.Primary) { - ipAddrs = append(ipAddrs, *privateIp.PrivateIpAddress) - } - } - return ipAddrs, nil -} - -func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { - var ( - ec2Client = self.getEc2Client() - id = self.GetId() - input = &ec2.AssignPrivateIpAddressesInput{ - NetworkInterfaceId: aws.String(id), - PrivateIpAddresses: aws.StringSlice(ipAddrs), - } - ) - _, err := ec2Client.AssignPrivateIpAddresses(input) - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case "PrivateIpAddressLimitExceeded": - return errors.Wrapf(cloudprovider.ErrAddressCountExceed, "aws ec2 AssignPrivateIpAddresses: %v", err) - } - } - return errors.Wrapf(err, "aws ec2 AssignPrivateIpAddresses") - } - return nil -} - -func (self *SInstanceNic) UnassignAddress(ipAddrs []string) error { - var ( - ec2Client = self.getEc2Client() - id = self.GetId() - input = &ec2.UnassignPrivateIpAddressesInput{ - NetworkInterfaceId: aws.String(id), - PrivateIpAddresses: aws.StringSlice(ipAddrs), - } - ) - _, err := ec2Client.UnassignPrivateIpAddresses(input) - if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case "InvalidNetworkInterfaceID.NotFound": - return nil - case "InvalidParameterValue": - msg := aerr.Message() - // "Some of the specified addresses are not assigned to interface eni-xxxxxxxxxxxxxxxxx" - if strings.Contains(msg, " addresses are not assigned to interface ") { - return nil - } - } - } - return errors.Wrapf(err, "aws ec2 UnassignPrivateIpAddresses") - } - return nil -} diff --git a/pkg/multicloud/aws/keypair.go b/pkg/multicloud/aws/keypair.go deleted file mode 100644 index 0d01900e7f..0000000000 --- a/pkg/multicloud/aws/keypair.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "bytes" - "crypto/md5" - "crypto/rsa" - "crypto/x509" - "fmt" - "strconv" - "time" - - "github.com/aokoli/goutils" - "github.com/aws/aws-sdk-go/service/ec2" - "golang.org/x/crypto/ssh" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SKeypair struct { - KeyPairFingerPrint string - KeyPairName string -} - -// 只支持计算Openssh ras 格式公钥转换成DER格式后的MD5。 -func md5Fingerprint(publickey string) (string, error) { - pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publickey)) - if err != nil { - return "", fmt.Errorf("publicKey error %s", err) - } - - der := []byte{} - cryptoPub, ok := pk.(ssh.CryptoPublicKey) - if !ok { - return "", fmt.Errorf("public key trans to crypto public key failed") - } - - switch pk.Type() { - case ssh.KeyAlgoRSA: - rsaPK, ok := cryptoPub.CryptoPublicKey().(*rsa.PublicKey) - if !ok { - return "", fmt.Errorf("crypto public key trans to ras publickey failed") - } - der, err = x509.MarshalPKIXPublicKey(rsaPK) - if err != nil { - return "", fmt.Errorf("MarshalPKIXPublicKey ras publickey failed") - } - default: - return "", fmt.Errorf("unsupport public key format.Only ssh-rsa supported") - } - - var ret bytes.Buffer - fp := md5.Sum(der) - for i, b := range fp { - ret.WriteString(fmt.Sprintf("%02x", b)) - if i < len(fp)-1 { - ret.WriteString(":") - } - } - - return ret.String(), nil -} - -func (self *SRegion) GetKeypairs(finger string, name string, offset int, limit int) ([]SKeypair, int, error) { - params := &ec2.DescribeKeyPairsInput{} - filters := []*ec2.Filter{} - if len(finger) > 0 { - filters = AppendSingleValueFilter(filters, "fingerprint", finger) - } - - if len(name) > 0 { - params.SetKeyNames([]*string{&name}) - } - - if len(filters) > 0 { - params.SetFilters(filters) - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, 0, errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.DescribeKeyPairs(params) - 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 -} - -// Aws貌似不支持ssh-dss格式密钥 -func (self *SRegion) ImportKeypair(name string, pubKey string) (*SKeypair, error) { - params := &ec2.ImportKeyPairInput{} - params.SetKeyName(name) - params.SetPublicKeyMaterial([]byte(pubKey)) - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.ImportKeyPair(params) - if err != nil { - return nil, errors.Wrap(err, "ImportKeyPair") - } 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) { - // https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2-key-pairs.html - fingerprint, err := md5Fingerprint(publicKey) - if err != nil { - return "", err - } - - 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) -} diff --git a/pkg/multicloud/aws/keypair_test.go b/pkg/multicloud/aws/keypair_test.go deleted file mode 100644 index 47cf4bf779..0000000000 --- a/pkg/multicloud/aws/keypair_test.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import "testing" - -type testPublicKey struct { - publickey string - fingerprint string -} - -func TestMd5Fingerprint(t *testing.T) { - rsa := testPublicKey{ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCBBuv9nsAGNpKVulxNc7zHXEEyiTqYU8J6sTfmB9lmrRea/RO/pUJg1ZGlHKLSbZ5h+d4mquASf8K3s3SQtz/4sBHroRijanO16i0Rk6t5kwcIRzaf11NiImImKgwNiCwZyiK2egAfsjDVEi8H+kSRA0N0PMxRfwOEZ/hNtVaNV7/MwkXylOuWUikGvPpm3sRmelfQoS3Hf055WM1m6POgddbjucq9bjQDW1O4dfDkWuX+385EOtfCBPtfeiAcOBBd+qEjmdfxroQwxHXLkZH7rdoS9jss3fi9P/K0ZpBKswKsed2sxKo9NNYfTDN19Kv8NBOW8W7MxN1po/2gvbd/", - "4c:ae:76:94:fb:59:66:8c:a6:07:e2:54:2f:14:19:c5", - } - - testKeys := []testPublicKey{rsa} - - for _, k := range testKeys { - fingerprint, err := md5Fingerprint(k.publickey) - if err != nil { - t.Error(err) - continue - } - - if fingerprint != k.fingerprint { - t.Errorf("ssh-rsa fingerprint is not as expected.%s != %s", fingerprint, k.fingerprint) - continue - } - } -} diff --git a/pkg/multicloud/aws/latitude_and_longitude.go b/pkg/multicloud/aws/latitude_and_longitude.go deleted file mode 100644 index 5e517f8d39..0000000000 --- a/pkg/multicloud/aws/latitude_and_longitude.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -// https://docs.aws.amazon.com/general/latest/gr/rande.html - -var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ - "us-east-1": api.RegionNothVirginia, - "us-east-2": api.RegionOhio, - "us-west-1": api.RegionNorthCalifornia, - "us-west-2": api.RegionOregon, - "ap-south-1": api.RegionMumbai, - "ap-northeast-3": api.RegionOsaka, - "ap-northeast-2": api.RegionSeoul, - "ap-southeast-1": api.RegionSingapore, - "ap-southeast-2": api.RegionSydney, - "ap-northeast-1": api.RegionTokyo, - "ap-east-1": api.RegionHongkong, - "ca-central-1": api.RegionCanadaCentral, - "cn-north-1": api.RegionBeijing, - "cn-northwest-1": api.RegionNingxia, - "eu-central-1": api.RegionFrankfurt, - "eu-west-1": api.RegionIreland, - "eu-west-2": api.RegionLondon, - "eu-west-3": api.RegionParis, - "eu-north-1": api.RegionStockholm, - "sa-east-1": api.RegionSaoPaulo, - "us-gov-west-1": api.RegionUSGOVWest, - - "af-south-1": api.RegionCapeTown, - "me-south-1": api.RegionBahrain, -} diff --git a/pkg/multicloud/aws/loadbalancer.go b/pkg/multicloud/aws/loadbalancer.go deleted file mode 100644 index 0f02c64e59..0000000000 --- a/pkg/multicloud/aws/loadbalancer.go +++ /dev/null @@ -1,516 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "fmt" - "sort" - "strconv" - "strings" - - "github.com/aws/aws-sdk-go/service/elbv2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -/* -https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/Welcome.html -*/ - -type SElb struct { - multicloud.SResourceBase - region *SRegion - - Type string `json:"Type"` - Scheme string `json:"Scheme"` - IPAddressType string `json:"IpAddressType"` - VpcID string `json:"VpcId"` - AvailabilityZones []AvailabilityZone `json:"AvailabilityZones"` - CreatedTime string `json:"CreatedTime"` - CanonicalHostedZoneID string `json:"CanonicalHostedZoneId"` - DNSName string `json:"DNSName"` - SecurityGroups []string `json:"SecurityGroups"` - LoadBalancerName string `json:"LoadBalancerName"` - State State `json:"State"` - LoadBalancerArn string `json:"LoadBalancerArn"` -} - -type AvailabilityZone struct { - LoadBalancerAddresses []LoadBalancerAddress `json:"LoadBalancerAddresses"` - ZoneName string `json:"ZoneName"` - SubnetID string `json:"SubnetId"` -} - -type LoadBalancerAddress struct { - IPAddress string `json:"IpAddress"` - AllocationID string `json:"AllocationId"` -} - -type State struct { - Code string `json:"Code"` -} - -func (self *SElb) GetId() string { - return self.LoadBalancerArn -} - -func (self *SElb) GetName() string { - return self.LoadBalancerName -} - -func (self *SElb) GetGlobalId() string { - return self.GetId() -} - -func (self *SElb) GetStatus() string { - switch self.State.Code { - case "provisioning": - return api.LB_STATUS_INIT - case "active": - return api.LB_STATUS_ENABLED - case "failed": - return api.LB_STATUS_START_FAILED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (self *SElb) Refresh() error { - ielb, err := self.region.GetILoadBalancerById(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, ielb) - if err != nil { - return err - } - - return nil -} - -func (self *SElb) IsEmulated() bool { - return false -} - -func (self *SElb) GetSysTags() map[string]string { - data := map[string]string{} - data["loadbalance_type"] = self.Type - attrs, err := self.region.getElbAttributesById(self.GetId()) - if err != nil { - log.Errorf("SElb GetSysTags %s", err) - return data - } - - for k, v := range attrs { - data[k] = v - } - return data -} - -func (self *SElb) GetTags() (map[string]string, error) { - tags, err := self.region.FetchElbTags(self.LoadBalancerArn) - if err != nil { - return nil, errors.Wrap(err, "self.region.FetchElbTags") - } - return tags, nil -} - -func (self *SElb) GetProjectId() string { - return "" -} - -func (self *SElb) GetAddress() string { - return self.DNSName -} - -func (self *SElb) GetAddressType() string { - switch self.Scheme { - case "internal": - return api.LB_ADDR_TYPE_INTRANET - case "internet-facing": - return api.LB_ADDR_TYPE_INTERNET - default: - return api.LB_ADDR_TYPE_INTRANET - } -} - -func (self *SElb) GetNetworkType() string { - return api.LB_NETWORK_TYPE_VPC -} - -func (self *SElb) GetNetworkIds() []string { - ret := []string{} - for i := range self.AvailabilityZones { - ret = append(ret, self.AvailabilityZones[i].SubnetID) - } - - return ret -} - -func (self *SElb) GetVpcId() string { - return self.VpcID -} - -func (self *SElb) GetZoneId() string { - zones := []string{} - for i := range self.AvailabilityZones { - zones = append(zones, self.AvailabilityZones[i].ZoneName) - } - - sort.Strings(zones) - if len(zones) > 0 { - z, err := self.region.getZoneById(zones[0]) - if err != nil { - log.Infof("getZoneById %s %s", zones[0], err) - return "" - } - - return z.GetGlobalId() - } - - return "" -} - -func (self *SElb) GetZone1Id() string { - return "" -} - -func (self *SElb) GetLoadbalancerSpec() string { - return self.Type -} - -func (self *SElb) GetChargeType() string { - return api.LB_CHARGE_TYPE_BY_TRAFFIC -} - -func (self *SElb) GetEgressMbps() int { - return 0 -} - -func (self *SElb) Delete(ctx context.Context) error { - return self.region.DeleteElb(self.GetId()) -} - -func (self *SElb) Start() error { - return nil -} - -func (self *SElb) Stop() error { - return cloudprovider.ErrNotSupported -} - -func (self *SElb) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - listeners, err := self.region.GetElbListeners(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "GetElbListeners") - } - - ret := make([]cloudprovider.ICloudLoadbalancerListener, len(listeners)) - for i := range listeners { - listeners[i].lb = self - ret[i] = &listeners[i] - } - - return ret, nil -} - -func (self *SElb) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - backendgroups, err := self.region.GetElbBackendgroups(self.GetId(), nil) - if err != nil { - return nil, errors.Wrap(err, "GetElbBackendgroups") - } - - ibackendgroups := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(backendgroups)) - for i := range backendgroups { - backendgroups[i].lb = self - ibackendgroups[i] = &backendgroups[i] - } - - return ibackendgroups, nil -} - -func (self *SElb) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - backendgroup, err := self.region.CreateElbBackendgroup(group) - if err != nil { - return nil, errors.Wrap(err, "CreateElbBackendgroup") - } - - backendgroup.lb = self - return backendgroup, nil -} - -func (self *SElb) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return self.region.GetElbBackendgroup(groupId) -} - -func (self *SElb) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - ret, err := self.region.CreateElbListener(listener) - if err != nil { - return nil, errors.Wrap(err, "CreateElbListener") - } - - ret.lb = self - return ret, nil -} - -func (self *SElb) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { - if listenerId == "" { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerListenerById") - } - - return self.region.GetElbListener(listenerId) -} - -func (self *SElb) GetIEIP() (cloudprovider.ICloudEIP, error) { - return nil, nil -} - -func (self *SRegion) DeleteElb(elbId string) error { - client, err := self.GetElbV2Client() - if err != nil { - return errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DeleteLoadBalancerInput{} - params.SetLoadBalancerArn(elbId) - _, err = client.DeleteLoadBalancer(params) - if err != nil { - return errors.Wrap(err, "DeleteLoadBalancer") - } - - return nil -} - -func (self *SRegion) GetElbBackendgroups(elbId string, backendgroupIds []string) ([]SElbBackendGroup, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DescribeTargetGroupsInput{} - if len(elbId) > 0 { - params.SetLoadBalancerArn(elbId) - } - - if len(backendgroupIds) > 0 { - v := make([]*string, len(backendgroupIds)) - for i := range backendgroupIds { - v[i] = &backendgroupIds[i] - } - - params.SetTargetGroupArns(v) - } - - ret, err := client.DescribeTargetGroups(params) - if err != nil { - return nil, errors.Wrap(err, "DescribeTargetGroups") - } - - backendgroups := []SElbBackendGroup{} - err = unmarshalAwsOutput(ret, "TargetGroups", &backendgroups) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.TargetGroups") - } - - for i := range backendgroups { - backendgroups[i].region = self - } - - return backendgroups, nil -} - -func (self *SRegion) GetElbBackendgroup(backendgroupId string) (*SElbBackendGroup, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DescribeTargetGroupsInput{} - params.SetTargetGroupArns([]*string{&backendgroupId}) - - ret, err := client.DescribeTargetGroups(params) - if err != nil { - if strings.Contains(err.Error(), "TargetGroupNotFound") { - return nil, cloudprovider.ErrNotFound - } - return nil, errors.Wrap(err, "DescribeTargetGroups") - } - - backendgroups := []SElbBackendGroup{} - err = unmarshalAwsOutput(ret, "TargetGroups", &backendgroups) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.TargetGroups") - } - - if len(backendgroups) == 1 { - backendgroups[0].region = self - return &backendgroups[0], nil - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetElbBackendgroup") -} - -func ToAwsHealthCode(s string) string { - ret := []string{} - - segs := strings.Split(s, ",") - for _, seg := range segs { - if seg == api.LB_HEALTH_CHECK_HTTP_CODE_4xx && !utils.IsInStringArray("400-499", ret) { - ret = append(ret, "400-499") - } else if seg == api.LB_HEALTH_CHECK_HTTP_CODE_3xx && !utils.IsInStringArray("300-399", ret) { - ret = append(ret, "300-399") - } else if seg == api.LB_HEALTH_CHECK_HTTP_CODE_2xx && !utils.IsInStringArray("200-299", ret) { - ret = append(ret, "200-299") - } - } - - return strings.Join(ret, ",") -} - -func ToOnecloudHealthCode(s string) string { - ret := []string{} - - segs := strings.Split(s, ",") - for _, seg := range segs { - codes := strings.Split(seg, "-") - for _, code := range codes { - c, _ := strconv.Atoi(code) - if c >= 400 && !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_4xx, ret) { - ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_4xx) - } else if c >= 300 && !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_3xx, ret) { - ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_3xx) - } else if c >= 200 && !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_2xx, ret) { - ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_2xx) - } - } - - if len(codes) == 2 { - min, _ := strconv.Atoi(codes[0]) - max, _ := strconv.Atoi(codes[1]) - - if min >= 200 && max >= 400 { - if !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_3xx, ret) { - ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_3xx) - } - } - } - } - - return strings.Join(ret, ",") -} - -// 目前只支持target type :instance -func (self *SRegion) CreateElbBackendgroup(group *cloudprovider.SLoadbalancerBackendGroup) (*SElbBackendGroup, error) { - params := &elbv2.CreateTargetGroupInput{} - params.SetProtocol(strings.ToUpper(group.ListenType)) - params.SetPort(int64(group.ListenPort)) - params.SetVpcId(group.VpcId) - params.SetName(group.Name) - params.SetTargetType("instance") - if group.HealthCheck != nil { - params.SetHealthCheckPort("traffic-port") - params.SetHealthCheckProtocol(strings.ToUpper(group.HealthCheck.HealthCheckType)) - params.SetHealthCheckIntervalSeconds(int64(group.HealthCheck.HealthCheckInterval)) - params.SetHealthyThresholdCount(int64(group.HealthCheck.HealthCheckRise)) - - if len(group.HealthCheck.HealthCheckURI) > 0 { - params.SetHealthCheckPath(group.HealthCheck.HealthCheckURI) - } - - if utils.IsInStringArray(group.ListenType, []string{api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS}) { - params.SetHealthCheckTimeoutSeconds(int64(group.HealthCheck.HealthCheckTimeout)) - params.SetUnhealthyThresholdCount(int64(group.HealthCheck.HealthCheckFail)) - - codes := ToAwsHealthCode(group.HealthCheck.HealthCheckHttpCode) - if len(codes) > 0 { - matcher := &elbv2.Matcher{} - matcher.SetHttpCode(codes) - params.SetMatcher(matcher) - } - } else { - // tcp & udp 健康检查阈值与不健康阈值需相同 - params.SetUnhealthyThresholdCount(int64(group.HealthCheck.HealthCheckRise)) - } - } - - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - ret, err := client.CreateTargetGroup(params) - if err != nil { - return nil, errors.Wrap(err, "CreateTargetGroup") - } - - backendgroups := []SElbBackendGroup{} - err = unmarshalAwsOutput(ret, "TargetGroups", &backendgroups) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.TargetGroups") - } - - if len(backendgroups) == 1 { - backendgroups[0].region = self - return &backendgroups[0], nil - } - - return nil, fmt.Errorf("CreateElbBackendgroup error: %#v", backendgroups) -} - -func (self *SElb) SetTags(tags map[string]string, replace bool) error { - oldTags, err := self.region.FetchElbTags(self.LoadBalancerArn) - if err != nil { - return errors.Wrapf(err, "self.region.FetchElbTags(%s)", self.LoadBalancerArn) - } - err = self.region.UpdateResourceTags(self.LoadBalancerArn, oldTags, tags, replace) - if err != nil { - return errors.Wrap(err, "self.region.UpdateResourceTags(self.LoadBalancerArn, oldTags, tags, replace)") - } - return nil -} - -func (self *SRegion) FetchElbTags(arn string) (map[string]string, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - params := elbv2.DescribeTagsInput{} - params.SetResourceArns([]*string{&arn}) - output, err := client.DescribeTags(¶ms) - if err != nil { - return nil, errors.Wrapf(err, "client.DescribeTags(%s)", jsonutils.Marshal(params).String()) - } - result := map[string]string{} - for i := range output.TagDescriptions { - if output.TagDescriptions[i].ResourceArn != nil && *output.TagDescriptions[i].ResourceArn == arn { - for j := range output.TagDescriptions[i].Tags { - if output.TagDescriptions[i].Tags[j].Key != nil && output.TagDescriptions[i].Tags[j].Value != nil { - result[*output.TagDescriptions[i].Tags[j].Key] = *output.TagDescriptions[i].Tags[j].Value - } - } - return result, nil - } - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/aws/loadbalancerbackend.go b/pkg/multicloud/aws/loadbalancerbackend.go deleted file mode 100644 index 583088130b..0000000000 --- a/pkg/multicloud/aws/loadbalancerbackend.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbBackend struct { - multicloud.SResourceBase - multicloud.AwsTags - region *SRegion - group *SElbBackendGroup - - Target Target `json:"Target"` - TargetHealth TargetHealth `json:"TargetHealth"` -} - -type Target struct { - ID string `json:"Id"` - Port int `json:"Port"` -} - -type TargetHealth struct { - State string `json:"State"` - Reason string `json:"Reason"` - Description string `json:"Description"` -} - -func (self *SElbBackend) GetId() string { - return fmt.Sprintf("%s::%s::%d", self.group.GetId(), self.Target.ID, self.Target.Port) -} - -func (self *SElbBackend) GetName() string { - return self.GetId() -} - -func (self *SElbBackend) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbBackend) Refresh() error { - return nil -} - -func (self *SElbBackend) IsEmulated() bool { - return false -} - -func (self *SElbBackend) GetProjectId() string { - return "" -} - -func (self *SElbBackend) GetWeight() int { - return 0 -} - -func (self *SElbBackend) GetPort() int { - return self.Target.Port -} - -func (self *SElbBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (self *SElbBackend) GetBackendRole() string { - return api.LB_BACKEND_ROLE_DEFAULT -} - -func (self *SElbBackend) GetBackendId() string { - return self.Target.ID -} - -func (self *SElbBackend) SyncConf(ctx context.Context, port, weight int) error { - return self.region.SyncElbBackend(self.GetId(), self.GetBackendId(), self.Target.Port, port) -} - -func (self *SElbBackend) GetIpAddress() string { - return "" -} - -func (self *SRegion) SyncElbBackend(backendId, serverId string, oldPort, newPort int) error { - err := self.RemoveElbBackend(backendId, serverId, 0, oldPort) - if err != nil { - return err - } - - _, err = self.AddElbBackend(backendId, serverId, 0, newPort) - if err != nil { - return err - } - - return nil -} diff --git a/pkg/multicloud/aws/loadbalancerbackendgroup.go b/pkg/multicloud/aws/loadbalancerbackendgroup.go deleted file mode 100644 index 7e9eb37723..0000000000 --- a/pkg/multicloud/aws/loadbalancerbackendgroup.go +++ /dev/null @@ -1,521 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "fmt" - "strconv" - "strings" - - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbBackendGroup struct { - multicloud.SResourceBase - multicloud.AwsTags - region *SRegion - lb *SElb - - TargetGroupName string `json:"TargetGroupName"` - Protocol string `json:"Protocol"` - Port int64 `json:"Port"` - VpcID string `json:"VpcId"` - TargetType string `json:"TargetType"` - HealthyThresholdCount int `json:"HealthyThresholdCount"` - Matcher Matcher `json:"Matcher"` - UnhealthyThresholdCount int `json:"UnhealthyThresholdCount"` - HealthCheckPath string `json:"HealthCheckPath"` - HealthCheckProtocol string `json:"HealthCheckProtocol"` - HealthCheckPort string `json:"HealthCheckPort"` - HealthCheckIntervalSeconds int `json:"HealthCheckIntervalSeconds"` - HealthCheckTimeoutSeconds int `json:"HealthCheckTimeoutSeconds"` - TargetGroupArn string `json:"TargetGroupArn"` - LoadBalancerArns []string `json:"LoadBalancerArns"` -} - -func (self *SElbBackendGroup) GetLoadbalancerId() string { - if len(self.LoadBalancerArns) > 0 { - return self.LoadBalancerArns[0] - } - - return "" -} - -func (self *SElbBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { - return self.lb -} - -type Matcher struct { - HTTPCode string `json:"HttpCode"` -} - -func (self *SElbBackendGroup) GetId() string { - return self.TargetGroupArn -} - -func (self *SElbBackendGroup) GetName() string { - return self.TargetGroupName -} - -func (self *SElbBackendGroup) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbBackendGroup) Refresh() error { - lbbg, err := self.region.GetElbBackendgroup(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, lbbg) - if err != nil { - return err - } - - return nil -} - -func (self *SElbBackendGroup) IsEmulated() bool { - return false -} - -func (self *SElbBackendGroup) GetSysTags() map[string]string { - data := map[string]string{} - data["port"] = strconv.FormatInt(self.Port, 10) - data["target_type"] = self.TargetType - data["health_check_protocol"] = strings.ToLower(self.HealthCheckProtocol) - data["health_check_interval"] = strconv.Itoa(self.HealthCheckIntervalSeconds) - return data -} - -func (self *SElbBackendGroup) GetProjectId() string { - return "" -} - -func (self *SElbBackendGroup) IsDefault() bool { - return false -} - -func (self *SElbBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_NORMAL -} - -func (self *SElbBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := self.region.GetELbBackends(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "GetELbBackends") - } - - ibackends := make([]cloudprovider.ICloudLoadbalancerBackend, len(backends)) - for i := range backends { - backends[i].region = self.region - backends[i].group = self - ibackends[i] = &backends[i] - } - - return ibackends, nil -} - -func (self *SElbBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - backend, err := self.region.GetELbBackend(backendId) - if err != nil { - return nil, errors.Wrap(err, "GetELbBackend") - } - - backend.group = self - return backend, nil -} - -func (self *SElbBackendGroup) GetProtocolType() string { - switch self.Protocol { - case "TCP": - return api.LB_LISTENER_TYPE_TCP - case "UDP": - return api.LB_LISTENER_TYPE_UDP - case "HTTP": - return api.LB_LISTENER_TYPE_HTTP - case "HTTPS": - return api.LB_LISTENER_TYPE_HTTPS - case "TCP_UDP": - return api.LB_LISTENER_TYPE_TCP_UDP - default: - return "" - } -} - -func (self *SElbBackendGroup) GetScheduler() string { - return "" -} - -func (self *SElbBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - health := &cloudprovider.SLoadbalancerHealthCheck{} - health.HealthCheck = api.LB_BOOL_ON - health.HealthCheckRise = self.HealthyThresholdCount - health.HealthCheckFail = self.UnhealthyThresholdCount - health.HealthCheckInterval = self.HealthCheckIntervalSeconds - health.HealthCheckURI = self.HealthCheckPath - health.HealthCheckType = strings.ToLower(self.HealthCheckProtocol) - health.HealthCheckTimeout = self.HealthCheckTimeoutSeconds - health.HealthCheckHttpCode = ToOnecloudHealthCode(self.Matcher.HTTPCode) - return health, nil -} - -func (self *SElbBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - attrs, err := self.region.GetElbBackendgroupAttributesById(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "GetElbBackendgroupAttributesById") - } - - cookieTime := 0 - if t, ok := attrs["stickiness.lb_cookie.duration_seconds"]; !ok { - cookieTime, err = strconv.Atoi(t) - } - - ret := &cloudprovider.SLoadbalancerStickySession{ - StickySession: attrs["stickiness.enabled"], - StickySessionCookie: "", - StickySessionType: api.LB_STICKY_SESSION_TYPE_INSERT, - StickySessionCookieTimeout: cookieTime, - } - - return ret, nil -} - -func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - backend, err := self.region.AddElbBackend(self.GetId(), serverId, weight, port) - if err != nil { - return nil, errors.Wrap(err, "AddElbBackend") - } - - backend.region = self.region - backend.group = self - return backend, nil -} - -func (self *SElbBackendGroup) RemoveBackendServer(serverId string, weight int, port int) error { - return self.region.RemoveElbBackend(self.GetId(), serverId, weight, port) -} - -func (self *SElbBackendGroup) Delete(ctx context.Context) error { - return self.region.DeleteElbBackendGroup(self.GetId()) -} - -func (self *SElbBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - return self.region.SyncELbBackendGroup(self.GetId(), group) -} - -func (self *SRegion) GetELbBackends(backendgroupId string) ([]SElbBackend, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - group, err := self.GetElbBackendgroup(backendgroupId) - if err != nil { - return nil, errors.Wrap(err, "GetElbBackendgroup") - } - - params := &elbv2.DescribeTargetHealthInput{} - params.SetTargetGroupArn(backendgroupId) - output, err := client.DescribeTargetHealth(params) - if err != nil { - return nil, errors.Wrap(err, "DescribeTargetHealth") - } - - backends := []SElbBackend{} - err = unmarshalAwsOutput(output, "TargetHealthDescriptions", &backends) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.TargetHealthDescriptions") - } - - ret := []SElbBackend{} - for i := range backends { - if !utils.IsInStringArray(backends[i].TargetHealth.Reason, []string{"Target.InvalidState", "Target.NotInUse", "Target.DeregistrationInProgress"}) { - backends[i].region = self - backends[i].group = group - ret = append(ret, backends[i]) - } - } - - return ret, nil -} - -func (self *SRegion) GetELbBackend(backendId string) (*SElbBackend, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - groupId, instanceId, port, err := parseElbBackendId(backendId) - if err != nil { - log.Errorf("parseElbBackendId %s: %s", backendId, err) - return nil, errors.Wrap(err, "parseElbBackendId") - } - - params := &elbv2.DescribeTargetHealthInput{} - desc := &elbv2.TargetDescription{} - desc.SetPort(int64(port)) - desc.SetId(instanceId) - params.SetTargets([]*elbv2.TargetDescription{desc}) - params.SetTargetGroupArn(groupId) - ret, err := client.DescribeTargetHealth(params) - if err != nil { - return nil, errors.Wrap(err, "DescribeTargetHealth") - } - - backends := []SElbBackend{} - err = unmarshalAwsOutput(ret, "TargetHealthDescriptions", &backends) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.TargetHealthDescriptions") - } - - if len(backends) == 1 { - backends[0].region = self - return &backends[0], nil - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetELbBackend") -} - -func parseElbBackendId(id string) (string, string, int, error) { - segs := strings.Split(id, "::") - if len(segs) != 3 { - return "", "", 0, fmt.Errorf("%s is not a valid backend id", id) - } - - port, err := strconv.Atoi(segs[2]) - if err != nil { - return "", "", 0, fmt.Errorf("%s is not a valid backend id, %s", id, err) - } - - return segs[0], segs[1], port, nil -} - -func genElbBackendId(backendgroupId string, serverId string, port int) string { - return strings.Join([]string{backendgroupId, serverId, strconv.Itoa(port)}, "::") -} - -func (self *SRegion) AddElbBackend(backendgroupId, serverId string, weight int, port int) (*SElbBackend, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.RegisterTargetsInput{} - params.SetTargetGroupArn(backendgroupId) - desc := &elbv2.TargetDescription{} - desc.SetId(serverId) - desc.SetPort(int64(port)) - params.SetTargets([]*elbv2.TargetDescription{desc}) - _, err = client.RegisterTargets(params) - if err != nil { - return nil, errors.Wrap(err, "RegisterTargets") - } - - return self.GetELbBackend(genElbBackendId(backendgroupId, serverId, port)) -} - -func (self *SRegion) RemoveElbBackend(backendgroupId, serverId string, weight int, port int) error { - client, err := self.GetElbV2Client() - if err != nil { - return errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DeregisterTargetsInput{} - params.SetTargetGroupArn(backendgroupId) - desc := &elbv2.TargetDescription{} - desc.SetId(serverId) - desc.SetPort(int64(port)) - params.SetTargets([]*elbv2.TargetDescription{desc}) - _, err = client.DeregisterTargets(params) - if err != nil { - return errors.Wrap(err, "DeregisterTargets") - } - - return nil -} - -func (self *SRegion) DeleteElbBackendGroup(backendgroupId string) error { - client, err := self.GetElbV2Client() - if err != nil { - return errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DeleteTargetGroupInput{} - params.SetTargetGroupArn(backendgroupId) - _, err = client.DeleteTargetGroup(params) - if err != nil { - return errors.Wrap(err, "DeleteTargetGroup") - } - - return nil -} - -func (self *SRegion) SyncELbBackendGroup(backendgroupId string, group *cloudprovider.SLoadbalancerBackendGroup) error { - err := self.modifyELbBackendGroup(backendgroupId, group.HealthCheck) - if err != nil { - return errors.Wrap(err, "modifyELbBackendGroup") - } - - err = self.RemoveElbBackends(backendgroupId) - if err != nil { - log.Errorf("RemoveElbBackends %s: %s", backendgroupId, err) - return errors.Wrap(err, "RemoveElbBackends") - } - - return self.AddElbBackends(backendgroupId, group.Backends) -} - -func (self *SRegion) modifyELbBackendGroup(backendgroupId string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) error { - client, err := self.GetElbV2Client() - if err != nil { - return err - } - - params := &elbv2.ModifyTargetGroupInput{} - params.SetTargetGroupArn(backendgroupId) - params.SetHealthCheckProtocol(strings.ToUpper(healthCheck.HealthCheckType)) - params.SetHealthyThresholdCount(int64(healthCheck.HealthCheckRise)) - - if utils.IsInStringArray(healthCheck.HealthCheckType, []string{api.LB_HEALTH_CHECK_HTTP, api.LB_LISTENER_TYPE_HTTPS}) { - params.SetUnhealthyThresholdCount(int64(healthCheck.HealthCheckFail)) - params.SetHealthCheckTimeoutSeconds(int64(healthCheck.HealthCheckTimeout)) - params.SetHealthCheckIntervalSeconds(int64(healthCheck.HealthCheckInterval)) - if len(healthCheck.HealthCheckURI) > 0 { - params.SetHealthCheckPath(healthCheck.HealthCheckURI) - } - - codes := ToAwsHealthCode(healthCheck.HealthCheckHttpCode) - if len(codes) > 0 { - matcher := &elbv2.Matcher{} - matcher.SetHttpCode(codes) - params.SetMatcher(matcher) - } - } - - _, err = client.ModifyTargetGroup(params) - if err != nil { - return errors.Wrap(err, "ModifyTargetGroup") - } - - return nil -} - -func (self *SRegion) RemoveElbBackends(backendgroupId string) error { - client, err := self.GetElbV2Client() - if err != nil { - return err - } - - backends, err := self.GetELbBackends(backendgroupId) - if err != nil { - return errors.Wrap(err, "GetELbBackends") - } - - if len(backends) == 0 { - return nil - } - - targets := []*elbv2.TargetDescription{} - for i := range backends { - target := &elbv2.TargetDescription{} - target.SetId(backends[i].GetBackendId()) - target.SetPort(int64(backends[i].GetPort())) - targets = append(targets, target) - } - - params := &elbv2.DeregisterTargetsInput{} - params.SetTargetGroupArn(backendgroupId) - params.SetTargets(targets) - _, err = client.DeregisterTargets(params) - if err != nil { - return errors.Wrap(err, "DeregisterTargets") - } - - return nil -} - -func (self *SRegion) AddElbBackends(backendgroupId string, backends []cloudprovider.SLoadbalancerBackend) error { - client, err := self.GetElbV2Client() - if err != nil { - return err - } - - if len(backends) == 0 { - return nil - } - - params := &elbv2.RegisterTargetsInput{} - params.SetTargetGroupArn(backendgroupId) - targets := []*elbv2.TargetDescription{} - for i := range backends { - desc := &elbv2.TargetDescription{} - desc.SetId(backends[i].ExternalID) - desc.SetPort(int64(backends[i].Port)) - targets = append(targets, desc) - } - - params.SetTargets(targets) - _, err = client.RegisterTargets(params) - if err != nil { - return errors.Wrap(err, "RegisterTargets") - } - - return nil -} - -func (self *SRegion) GetElbBackendgroupAttributesById(backendgroupId string) (map[string]string, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DescribeTargetGroupAttributesInput{} - params.SetTargetGroupArn(backendgroupId) - - output, err := client.DescribeTargetGroupAttributes(params) - if err != nil { - return nil, errors.Wrap(err, "DescribeTargetGroupAttributes") - } - - attrs := []map[string]string{} - err = unmarshalAwsOutput(output, "Attributes", &attrs) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.Attributes") - } - - ret := map[string]string{} - for i := range attrs { - for k, v := range attrs[i] { - ret[k] = v - } - } - - return ret, nil -} diff --git a/pkg/multicloud/aws/loadbalancercert.go b/pkg/multicloud/aws/loadbalancercert.go deleted file mode 100644 index 66bc41c5e4..0000000000 --- a/pkg/multicloud/aws/loadbalancercert.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "crypto/sha1" - "crypto/x509" - "encoding/pem" - "fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/service/iam" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbCertificate struct { - multicloud.SResourceBase - multicloud.AwsTags - region *SRegion - cert *x509.Certificate - - Path string `json:"Path"` - ServerCertificateName string `json:"ServerCertificateName"` - ServerCertificateID string `json:"ServerCertificateId"` - Arn string `json:"Arn"` - UploadDate time.Time `json:"UploadDate"` - Expiration time.Time `json:"Expiration"` - PublicKey string -} - -func (self *SElbCertificate) GetId() string { - return self.Arn -} - -func (self *SElbCertificate) GetName() string { - return self.ServerCertificateName -} - -func (self *SElbCertificate) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbCertificate) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbCertificate) Refresh() error { - icert, err := self.region.GetILoadBalancerCertificateById(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, icert) - if err != nil { - return err - } - - return nil -} - -func (self *SElbCertificate) IsEmulated() bool { - return false -} - -func (self *SElbCertificate) GetProjectId() string { - return "" -} - -func (self *SElbCertificate) Sync(name, privateKey, publickKey string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SElbCertificate) Delete() error { - return self.region.deleteElbCertificate(self.GetName()) -} - -func (self *SElbCertificate) GetCommonName() string { - cert, err := self.ParsePublicKey() - if err != nil { - return "" - } - - return cert.Issuer.CommonName -} - -func (self *SElbCertificate) GetSubjectAlternativeNames() string { - // todo: fix me - _, err := self.ParsePublicKey() - if err != nil { - return "" - } - - return "" -} - -func (self *SElbCertificate) GetFingerprint() string { - publicKey := self.GetPublickKey() - if len(publicKey) == 0 { - return "" - } - - _fp := sha1.Sum([]byte(publicKey)) - fp := fmt.Sprintf("sha1:% x", _fp) - return strings.Replace(fp, " ", ":", -1) -} - -func (self *SElbCertificate) GetExpireTime() time.Time { - return self.Expiration -} - -func (self *SElbCertificate) GetPublickKey() string { - if self.PublicKey == "" { - ret, err := self.region.getPublicKey(self.GetName()) - if err != nil { - log.Errorf("GetPublickKey %s", err) - return "" - } - - self.PublicKey = ret - } - - return self.PublicKey -} - -func (self *SElbCertificate) GetPrivateKey() string { - return "" -} - -func (self *SElbCertificate) ParsePublicKey() (*x509.Certificate, error) { - if self.cert != nil { - return self.cert, nil - } - - publicKey := self.GetPublickKey() - if len(publicKey) == 0 { - return nil, fmt.Errorf("SElbCertificate ParsePublicKey public key is empty") - } - - block, _ := pem.Decode([]byte(publicKey)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return nil, errors.Wrap(err, "ParseCertificate") - } - - self.cert = cert - return cert, nil -} - -func (self *SRegion) getPublicKey(certName string) (string, error) { - client, err := self.getIamClient() - if err != nil { - return "", err - } - - params := &iam.GetServerCertificateInput{} - params.SetServerCertificateName(certName) - ret, err := client.GetServerCertificate(params) - if err != nil { - return "", err - } - - return StrVal(ret.ServerCertificate.CertificateBody), nil -} - -func (self *SRegion) deleteElbCertificate(certName string) error { - client, err := self.getIamClient() - if err != nil { - return err - } - - params := &iam.DeleteServerCertificateInput{} - params.SetServerCertificateName(certName) - _, err = client.DeleteServerCertificate(params) - if err != nil { - return err - } - - return nil -} diff --git a/pkg/multicloud/aws/loadbalancerlistener.go b/pkg/multicloud/aws/loadbalancerlistener.go deleted file mode 100644 index e1867c3a75..0000000000 --- a/pkg/multicloud/aws/loadbalancerlistener.go +++ /dev/null @@ -1,768 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "encoding/json" - "fmt" - "strconv" - "strings" - "time" - - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.AwsTags - region *SRegion - lb *SElb - group *SElbBackendGroup - - Port int `json:"Port"` - Protocol string `json:"Protocol"` - DefaultActions []DefaultAction `json:"DefaultActions"` - SSLPolicy string `json:"SslPolicy"` - Certificates []Certificate `json:"Certificates"` - LoadBalancerArn string `json:"LoadBalancerArn"` - ListenerArn string `json:"ListenerArn"` -} - -type Certificate struct { - CertificateArn string `json:"CertificateArn"` -} - -type DefaultAction struct { - TargetGroupArn string `json:"TargetGroupArn"` - Type string `json:"Type"` -} - -func (self *SElbListener) GetId() string { - return self.ListenerArn -} - -func (self *SElbListener) GetName() string { - segs := strings.Split(self.ListenerArn, "/") - return segs[len(segs)-1] -} - -func (self *SElbListener) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbListener) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbListener) Refresh() error { - listener, err := self.region.GetElbListener(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, listener) - if err != nil { - return err - } - - return nil -} - -func (self *SElbListener) IsEmulated() bool { - return false -} - -func (self *SElbListener) GetProjectId() string { - return "" -} - -func (self *SElbListener) GetListenerType() string { - switch self.Protocol { - case "TCP": - return api.LB_LISTENER_TYPE_TCP - case "UDP": - return api.LB_LISTENER_TYPE_UDP - case "HTTP": - return api.LB_LISTENER_TYPE_HTTP - case "HTTPS": - return api.LB_LISTENER_TYPE_HTTPS - case "TCP_SSL": - return api.LB_LISTENER_TYPE_TCP - case "TCP_UDP": - return api.LB_LISTENER_TYPE_TCP_UDP - default: - return "" - } -} - -func (self *SElbListener) GetListenerPort() int { - return self.Port -} - -func (self *SElbListener) GetScheduler() string { - // api.LB_SCHEDULER_RR ? - return "" -} - -func (self *SElbListener) GetAclStatus() string { - return api.LB_BOOL_OFF -} - -func (self *SElbListener) GetAclType() string { - return "" -} - -func (self *SElbListener) GetAclId() string { - return "" -} - -func (self *SElbListener) GetEgressMbps() int { - return 0 -} - -func (self *SElbListener) GetHealthCheck() string { - group, err := self.getBackendGroup() - if err != nil { - return "" - } - - health, err := group.GetHealthCheck() - if err != nil { - return "" - } - - return health.HealthCheck -} - -func (self *SElbListener) getBackendGroup() (*SElbBackendGroup, error) { - if self.group != nil { - return self.group, nil - } - - lbbg, err := self.region.GetElbBackendgroup(self.DefaultActions[0].TargetGroupArn) - if err != nil { - return nil, errors.Wrap(err, "GetElbBackendgroup") - } - - self.group = lbbg - return self.group, nil -} - -func (self *SElbListener) GetHealthCheckType() string { - group, err := self.getBackendGroup() - if err != nil { - return "" - } - - health, err := group.GetHealthCheck() - if err != nil { - return "" - } - - return health.HealthCheckType -} - -func (self *SElbListener) GetHealthCheckTimeout() int { - group, err := self.getBackendGroup() - if err != nil { - return 0 - } - - health, err := group.GetHealthCheck() - if err != nil { - return 0 - } - - return health.HealthCheckTimeout -} - -func (self *SElbListener) GetHealthCheckInterval() int { - group, err := self.getBackendGroup() - if err != nil { - return 0 - } - - health, err := group.GetHealthCheck() - if err != nil { - return 0 - } - - return health.HealthCheckInterval -} - -func (self *SElbListener) GetHealthCheckRise() int { - group, err := self.getBackendGroup() - if err != nil { - return 0 - } - - health, err := group.GetHealthCheck() - if err != nil { - return 0 - } - - return health.HealthCheckRise -} - -func (self *SElbListener) GetHealthCheckFail() int { - group, err := self.getBackendGroup() - if err != nil { - return 0 - } - - health, err := group.GetHealthCheck() - if err != nil { - return 0 - } - - return health.HealthCheckFail -} - -func (self *SElbListener) GetHealthCheckReq() string { - group, err := self.getBackendGroup() - if err != nil { - return "" - } - - health, err := group.GetHealthCheck() - if err != nil { - return "" - } - - return health.HealthCheckReq -} - -func (self *SElbListener) GetHealthCheckExp() string { - group, err := self.getBackendGroup() - if err != nil { - return "" - } - - health, err := group.GetHealthCheck() - if err != nil { - return "" - } - - return health.HealthCheckExp -} - -func (self *SElbListener) GetBackendGroupId() string { - return self.DefaultActions[0].TargetGroupArn -} - -func (self *SElbListener) GetBackendServerPort() int { - return 0 -} - -func (self *SElbListener) GetHealthCheckDomain() string { - group, err := self.getBackendGroup() - if err != nil { - return "" - } - - health, err := group.GetHealthCheck() - if err != nil { - return "" - } - - return health.HealthCheckDomain -} - -func (self *SElbListener) GetHealthCheckURI() string { - group, err := self.getBackendGroup() - if err != nil { - return "" - } - - health, err := group.GetHealthCheck() - if err != nil { - return "" - } - - return health.HealthCheckURI -} - -func (self *SElbListener) GetHealthCheckCode() string { - group, err := self.getBackendGroup() - if err != nil { - return "" - } - - health, err := group.GetHealthCheck() - if err != nil { - return "" - } - - return health.HealthCheckHttpCode -} - -func (self *SElbListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - rules, err := self.GetILoadbalancerListenerRules() - if err != nil { - return nil, errors.Wrap(err, "GetILoadbalancerListenerRules") - } else { - if err := self.region.UpdateRulesPriority(rules); err != nil { - return nil, errors.Wrap(err, "UpdateRulesPriority") - } - } - - ret, err := self.region.CreateElbListenerRule(self.GetId(), rule) - if err != nil { - return nil, errors.Wrap(err, "CreateElbListenerRule") - } - - ret.listener = self - ret.region = self.region - return ret, nil -} - -func (self *SElbListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - rule, err := self.region.GetElbListenerRuleById(ruleId) - if err != nil { - return nil, errors.Wrap(err, "GetElbListenerRuleById") - } - - rule.listener = self - return rule, nil -} - -func (self *SElbListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - rules, err := self.region.GetElbListenerRules(self.GetId(), "") - if err != nil { - return nil, errors.Wrap(err, "GetElbListenerRules") - } - - irules := make([]cloudprovider.ICloudLoadbalancerListenerRule, len(rules)) - for i := range rules { - rules[i].listener = self - irules[i] = &rules[i] - } - - return irules, nil -} - -func (self *SElbListener) GetStickySession() string { - group, err := self.getBackendGroup() - if err != nil { - return "" - } - - session, err := group.GetStickySession() - if err != nil { - return "" - } - - return session.StickySession -} - -func (self *SElbListener) GetStickySessionType() string { - group, err := self.getBackendGroup() - if err != nil { - return "" - } - - session, err := group.GetStickySession() - if err != nil { - return "" - } - - return session.StickySessionType -} - -func (self *SElbListener) GetStickySessionCookie() string { - group, err := self.getBackendGroup() - if err != nil { - return "" - } - - session, err := group.GetStickySession() - if err != nil { - return "" - } - - return session.StickySessionCookie -} - -func (self *SElbListener) GetStickySessionCookieTimeout() int { - group, err := self.getBackendGroup() - if err != nil { - return 0 - } - - session, err := group.GetStickySession() - if err != nil { - return 0 - } - - return session.StickySessionCookieTimeout -} - -func (self *SElbListener) XForwardedForEnabled() bool { - return false -} - -func (self *SElbListener) GzipEnabled() bool { - return false -} - -func (self *SElbListener) GetCertificateId() string { - if len(self.Certificates) > 0 { - return self.Certificates[0].CertificateArn - } - - return "" -} - -func (self *SElbListener) GetTLSCipherPolicy() string { - return self.SSLPolicy -} - -func (self *SElbListener) HTTP2Enabled() bool { - return false -} - -func (self *SElbListener) GetClientIdleTimeout() int { - return 0 -} - -func (self *SElbListener) GetBackendConnectTimeout() int { - return 0 -} - -func (self *SElbListener) Start() error { - return nil -} - -func (self *SElbListener) Stop() error { - return cloudprovider.ErrNotSupported -} - -func (self *SElbListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { - return self.region.SyncElbListener(self, listener) -} - -func (self *SElbListener) Delete(ctx context.Context) error { - return self.region.DeleteElbListener(self.GetId()) -} - -func (self *SRegion) GetElbListeners(elbId string) ([]SElbListener, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DescribeListenersInput{} - params.SetLoadBalancerArn(elbId) - ret, err := client.DescribeListeners(params) - if err != nil { - return nil, errors.Wrap(err, "DescribeListeners") - } - - listeners := []SElbListener{} - err = unmarshalAwsOutput(ret, "Listeners", &listeners) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.Listeners") - } - - for i := range listeners { - listeners[i].region = self - } - - return listeners, nil -} - -func unmarshalAwsOutput(output interface{}, respKey string, result interface{}) error { - _ret, err := json.Marshal(output) - if err != nil { - return err - } - - obj, err := jsonutils.Parse(_ret) - if err != nil { - return err - } - - if len(respKey) == 0 { - err = obj.Unmarshal(result) - if err != nil { - return err - } - } else { - err = obj.Unmarshal(result, respKey) - if err != nil { - return err - } - } - - return nil -} - -func (self *SRegion) GetElbListener(listenerId string) (*SElbListener, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DescribeListenersInput{} - params.SetListenerArns([]*string{&listenerId}) - ret, err := client.DescribeListeners(params) - if err != nil { - return nil, errors.Wrap(err, "DescribeListeners") - } - - listeners := []SElbListener{} - err = unmarshalAwsOutput(ret, "Listeners", &listeners) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.Listeners") - } - - if len(listeners) == 1 { - listeners[0].region = self - return &listeners[0], nil - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetElbListener") -} - -func (self *SRegion) CreateElbListener(listener *cloudprovider.SLoadbalancerListener) (*SElbListener, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - listenerType := strings.ToUpper(listener.ListenerType) - params := &elbv2.CreateListenerInput{} - params.SetLoadBalancerArn(listener.LoadbalancerID) - params.SetPort(int64(listener.ListenerPort)) - params.SetProtocol(listenerType) - action := &elbv2.Action{} - action.SetType("forward") - action.SetTargetGroupArn(listener.BackendGroupID) - params.SetDefaultActions([]*elbv2.Action{action}) - if listenerType == "HTTPS" { - cert := &elbv2.Certificate{ - CertificateArn: &listener.CertificateID, - } - - params.SetCertificates([]*elbv2.Certificate{cert}) - params.SetSslPolicy("ELBSecurityPolicy-2016-08") - } - - ret, err := client.CreateListener(params) - if err != nil { - // aws 比较诡异,证书能查询到,但是如果立即创建会报错,这里只能等待一会重试 - time.Sleep(10 * time.Second) - if strings.Contains(err.Error(), "CertificateNotFound") { - ret, err = client.CreateListener(params) - if err != nil { - return nil, errors.Wrap(err, "Region.CreateElbListener.Retry") - } - } else { - return nil, errors.Wrap(err, "Region.CreateElbListener") - } - } - - listeners := []SElbListener{} - err = unmarshalAwsOutput(ret, "Listeners", &listeners) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.Listeners") - } - - if len(listeners) == 1 { - listeners[0].region = self - return &listeners[0], nil - } - - return nil, fmt.Errorf("CreateElbListener err %#v", listeners) -} - -func (self *SRegion) GetElbListenerRules(listenerId string, ruleId string) ([]SElbListenerRule, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DescribeRulesInput{} - if len(listenerId) > 0 { - params.SetListenerArn(listenerId) - } - - if len(ruleId) > 0 { - params.SetRuleArns([]*string{&ruleId}) - } - - ret, err := client.DescribeRules(params) - if err != nil { - return nil, errors.Wrap(err, "DescribeRules") - } - - rules := []SElbListenerRule{} - err = unmarshalAwsOutput(ret, "Rules", &rules) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.Rules") - } - - for i := range rules { - rules[i].region = self - } - - return rules, nil -} - -func (self *SRegion) GetElbListenerRuleById(ruleId string) (*SElbListenerRule, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DescribeRulesInput{} - if len(ruleId) > 0 { - params.SetRuleArns([]*string{&ruleId}) - } - - ret, err := client.DescribeRules(params) - if err != nil { - return nil, errors.Wrap(err, "DescribeRules") - } - - rules := []SElbListenerRule{} - err = unmarshalAwsOutput(ret, "Rules", &rules) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.Rules") - } - - if len(rules) == 1 { - rules[0].region = self - return &rules[0], nil - } else { - log.Errorf("GetElbListenerRuleById %s %d found", ruleId, len(rules)) - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetElbListenerRuleById") - } -} - -func (self *SRegion) DeleteElbListener(listenerId string) error { - client, err := self.GetElbV2Client() - if err != nil { - return err - } - - params := &elbv2.DeleteListenerInput{} - params.SetListenerArn(listenerId) - _, err = client.DeleteListener(params) - if err != nil { - return err - } - - return nil -} - -func (self *SRegion) SyncElbListener(listener *SElbListener, config *cloudprovider.SLoadbalancerListener) error { - client, err := self.GetElbV2Client() - if err != nil { - return err - } - - params := &elbv2.ModifyListenerInput{} - params.SetListenerArn(listener.GetId()) - params.SetPort(int64(config.ListenerPort)) - params.SetProtocol(strings.ToUpper(config.ListenerType)) - action := &elbv2.Action{} - action.SetType("forward") - action.SetTargetGroupArn(config.BackendGroupID) - params.SetDefaultActions([]*elbv2.Action{action}) - - if config.ListenerType == api.LB_LISTENER_TYPE_HTTPS { - cert := &elbv2.Certificate{} - cert.SetCertificateArn(config.CertificateID) - params.SetCertificates([]*elbv2.Certificate{cert}) - } - - _, err = client.ModifyListener(params) - if err != nil { - if strings.Contains(err.Error(), "CertificateNotFound") { - // aws 比较诡异,证书能查询到,但是如果立即创建会报错,这里只能等待一会重试 - time.Sleep(10 * time.Second) - _, err = client.ModifyListener(params) - if err != nil { - return errors.Wrap(err, "SRegion.SyncElbListener.ModifyListener.Retry") - } - } - - return errors.Wrap(err, "SRegion.SyncElbListener.ModifyListener") - } - - hc := &cloudprovider.SLoadbalancerHealthCheck{ - HealthCheckType: config.HealthCheckType, - HealthCheckReq: config.HealthCheckReq, - HealthCheckExp: config.HealthCheckExp, - HealthCheck: config.HealthCheck, - HealthCheckTimeout: config.HealthCheckTimeout, - HealthCheckDomain: config.HealthCheckDomain, - HealthCheckHttpCode: config.HealthCheckHttpCode, - HealthCheckURI: config.HealthCheckURI, - HealthCheckInterval: config.HealthCheckInterval, - HealthCheckRise: config.HealthCheckRise, - HealthCheckFail: config.HealthCheckFail, - } - err = self.modifyELbBackendGroup(config.BackendGroupID, hc) - if err != nil { - return errors.Wrap(err, "region.SyncElbListener.updateELbBackendGroup") - } - - return nil -} - -func (self *SRegion) UpdateRulesPriority(rules []cloudprovider.ICloudLoadbalancerListenerRule) error { - client, err := self.GetElbV2Client() - if err != nil { - return err - } - - ps := []*elbv2.RulePriorityPair{} - for i := range rules { - rule := rules[i].(*SElbListenerRule) - if !rule.IsDefaultRule { - v, _ := strconv.Atoi(rule.Priority) - p := &elbv2.RulePriorityPair{} - p.SetRuleArn(rules[i].GetId()) - p.SetPriority(int64(v + 1)) - - ps = append(ps, p) - } - } - - if len(ps) == 0 { - return nil - } - - params := &elbv2.SetRulePrioritiesInput{} - params.SetRulePriorities(ps) - _, err = client.SetRulePriorities(params) - if err != nil { - return err - } - - return nil -} diff --git a/pkg/multicloud/aws/loadbalancerlistenerrule.go b/pkg/multicloud/aws/loadbalancerlistenerrule.go deleted file mode 100644 index 07cbac226e..0000000000 --- a/pkg/multicloud/aws/loadbalancerlistenerrule.go +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "encoding/json" - "fmt" - "strings" - - "github.com/aws/aws-sdk-go/service/elbv2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbListenerRule struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.AwsTags - listener *SElbListener - region *SRegion - - Priority string `json:"Priority"` - IsDefaultRule bool `json:"IsDefault"` - Actions []Action `json:"Actions"` - RuleArn string `json:"RuleArn"` - Conditions []Condition `json:"Conditions"` -} - -type Action struct { - TargetGroupArn string `json:"TargetGroupArn"` - Type string `json:"Type"` -} - -type Condition struct { - Field string `json:"field"` - HTTPRequestMethodConfig *Config `json:"httpRequestMethodConfig,omitempty"` - Values []string `json:"values"` - SourceIPConfig *Config `json:"sourceIpConfig,omitempty"` - QueryStringConfig *QueryStringConfig `json:"queryStringConfig,omitempty"` - HTTPHeaderConfig *HTTPHeaderConfig `json:"httpHeaderConfig,omitempty"` - PathPatternConfig *Config `json:"pathPatternConfig,omitempty"` - HostHeaderConfig *Config `json:"hostHeaderConfig,omitempty"` -} - -type HTTPHeaderConfig struct { - HTTPHeaderName string `json:"HttpHeaderName"` - Values []string `json:"values"` -} - -type Config struct { - Values []string `json:"values"` -} - -type QueryStringConfig struct { - Values []Query `json:"values"` -} - -type Query struct { - Key string `json:"key"` - Value string `json:"value"` -} - -func (self *SElbListenerRule) GetId() string { - return self.RuleArn -} - -func (self *SElbListenerRule) GetName() string { - segs := strings.Split(self.RuleArn, "/") - return segs[len(segs)-1] -} - -func (self *SElbListenerRule) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbListenerRule) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbListenerRule) Refresh() error { - rule, err := self.region.GetElbListenerRuleById(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, rule) - if err != nil { - return err - } - - return nil -} - -func (self *SElbListenerRule) IsDefault() bool { - return self.IsDefaultRule -} - -func (self *SElbListenerRule) IsEmulated() bool { - return false -} - -func (self *SElbListenerRule) GetProjectId() string { - return "" -} - -func (self *SElbListenerRule) GetDomain() string { - for _, condition := range self.Conditions { - if condition.Field == "host-header" { - return strings.Join(condition.Values, ",") - } - } - - return "" -} - -func (self *SElbListenerRule) GetCondition() string { - conditon, err := json.Marshal(self.Conditions) - if err != nil { - log.Errorf("GetCondition %s", err) - return "" - } - - return string(conditon) -} - -func (self *SElbListenerRule) GetPath() string { - for _, condition := range self.Conditions { - if condition.Field == "path-pattern" { - return strings.Join(condition.Values, ",") - } - } - - return "" -} - -func (self *SElbListenerRule) GetBackendGroupId() string { - for _, action := range self.Actions { - if action.Type == "forward" { - return action.TargetGroupArn - } - } - - return "" -} - -func (self *SElbListenerRule) Delete(ctx context.Context) error { - return self.region.DeleteElbListenerRule(self.GetId()) -} - -func (self *SRegion) DeleteElbListenerRule(ruleId string) error { - client, err := self.GetElbV2Client() - if err != nil { - return err - } - - params := &elbv2.DeleteRuleInput{} - params.SetRuleArn(ruleId) - _, err = client.DeleteRule(params) - if err != nil { - return err - } - - return nil -} - -func (self *SRegion) CreateElbListenerRule(listenerId string, config *cloudprovider.SLoadbalancerListenerRule) (*SElbListenerRule, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - forward := "forward" - action := &elbv2.Action{ - TargetGroupArn: &config.BackendGroupID, - Type: &forward, - } - - condtions, err := parseConditions(config.Condition) - if err != nil { - return nil, errors.Wrap(err, "parseConditions") - } - - params := &elbv2.CreateRuleInput{} - params.SetListenerArn(listenerId) - params.SetActions([]*elbv2.Action{action}) - params.SetConditions(condtions) - params.SetPriority(int64(1)) - ret, err := client.CreateRule(params) - if err != nil { - return nil, errors.Wrap(err, "CreateRule") - } - - if len(ret.Rules) == 0 { - return nil, errors.Wrap(fmt.Errorf("empty rules"), "Region.CreateElbListenerRule.len") - } - - rule := SElbListenerRule{} - err = unmarshalAwsOutput(ret.Rules[0], "", &rule) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.rule") - } - - rule.region = self - return &rule, nil -} - -func parseConditions(conditions string) ([]*elbv2.RuleCondition, error) { - obj, err := jsonutils.ParseString(conditions) - if err != nil { - return nil, errors.Wrap(err, "ParseString.conditions") - } - - conditionArray, ok := obj.(*jsonutils.JSONArray) - if !ok { - return nil, fmt.Errorf("parseConditions invalid condition fromat.") - } - - ret := []*elbv2.RuleCondition{} - cs, _ := conditionArray.GetArray() - for i := range cs { - c, err := parseCondition(cs[i]) - if err != nil { - return nil, errors.Wrap(err, "parseCondition") - } - - ret = append(ret, c) - } - - return ret, nil -} - -func parseCondition(condition jsonutils.JSONObject) (*elbv2.RuleCondition, error) { - conditionDict, ok := condition.(*jsonutils.JSONDict) - if !ok { - return nil, fmt.Errorf("parseCondition invalid condition fromat.") - } - - dict, _ := conditionDict.GetMap() - field, ok := dict["field"] - if !ok { - return nil, fmt.Errorf("parseCondition invalid condition, missing field: %#v", condition) - } - - f, _ := field.GetString() - switch f { - case "http-header": - return parseHttpHeaderCondition(conditionDict) - case "path-pattern": - return parsePathPatternCondition(conditionDict) - case "http-request-method": - return parseRequestModthdCondition(conditionDict) - case "host-header": - return parseHostHeaderCondition(conditionDict) - case "query-string": - return parseQueryStringCondition(conditionDict) - case "source-ip": - return parseSourceIpCondition(conditionDict) - default: - return nil, fmt.Errorf("parseCondition invalid condition key %#v", field) - } -} - -func parseHttpHeaderCondition(conditon *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { - ret := &elbv2.RuleCondition{} - ret.SetField("http-header") - - values, err := conditon.GetMap("httpHeaderConfig") - if err != nil { - return nil, errors.Wrap(err, "GetMap") - } - - name, ok := values["HttpHeaderName"] - if !ok { - return nil, fmt.Errorf("parseHttpHeaderCondition missing filed HttpHeaderName") - } - - nameObj, ok := name.(*jsonutils.JSONString) - if !ok { - return nil, fmt.Errorf("parseHttpHeaderCondition missing invalid data %#v", name) - } - - headname, _ := nameObj.GetString() - config := &elbv2.HttpHeaderConditionConfig{} - config.SetHttpHeaderName(headname) - - vs, ok := values["values"] - if !ok { - return nil, fmt.Errorf("parseHttpHeaderCondition missing filed values") - } - - _vs, err := parseConditionStringArrayValues(vs) - if err != nil { - return nil, errors.Wrap(err, "parseConditionStringArrayValues") - } - config.SetValues(_vs) - ret.SetHttpHeaderConfig(config) - return ret, nil -} - -func parsePathPatternCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { - ret := &elbv2.RuleCondition{} - ret.SetField("path-pattern") - - values, err := condition.GetMap("pathPatternConfig") - if err != nil { - return nil, errors.Wrap(err, "GetMap") - } - - config := &elbv2.PathPatternConditionConfig{} - vs, ok := values["values"] - if !ok { - return nil, fmt.Errorf("parsePathPatternCondition missing filed values") - } - - _vs, err := parseConditionStringArrayValues(vs) - if err != nil { - return nil, errors.Wrap(err, "parseConditionStringArrayValues") - } - config.SetValues(_vs) - ret.SetPathPatternConfig(config) - return ret, nil - -} - -func parseRequestModthdCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { - ret := &elbv2.RuleCondition{} - ret.SetField("http-request-method") - - values, err := condition.GetMap("httpRequestMethodConfig") - if err != nil { - return nil, errors.Wrap(err, "GetMap.httpRequestMethodConfig") - } - - config := &elbv2.HttpRequestMethodConditionConfig{} - vs, ok := values["values"] - if !ok { - return nil, fmt.Errorf("parseRequestModthdCondition missing filed values") - } - - _vs, err := parseConditionStringArrayValues(vs) - if err != nil { - return nil, errors.Wrap(err, "parseConditionStringArrayValues") - } - config.SetValues(_vs) - return ret, nil -} - -func parseHostHeaderCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { - ret := &elbv2.RuleCondition{} - ret.SetField("host-header") - - values, err := condition.GetMap("hostHeaderConfig") - if err != nil { - return nil, errors.Wrap(err, "GetMap.hostHeaderConfig") - } - - config := &elbv2.HostHeaderConditionConfig{} - vs, ok := values["values"] - if !ok { - return nil, fmt.Errorf("parseHostHeaderCondition missing filed values") - } - - _vs, err := parseConditionStringArrayValues(vs) - if err != nil { - return nil, errors.Wrap(err, "parseConditionStringArrayValues") - } - config.SetValues(_vs) - ret.SetHostHeaderConfig(config) - return ret, nil -} - -func parseQueryStringCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { - ret := &elbv2.RuleCondition{} - ret.SetField("query-string") - - values, err := condition.GetMap("queryStringConfig") - if err != nil { - return nil, errors.Wrap(err, "GetMap.queryStringConfig") - } - - config := &elbv2.QueryStringConditionConfig{} - vs, ok := values["values"] - if !ok { - return nil, fmt.Errorf("parseQueryStringCondition missing filed values") - } - - _vs, err := parseConditionDictArrayValues(vs) - if err != nil { - return nil, errors.Wrap(err, "parseConditionDictArrayValues") - } - config.SetValues(_vs) - ret.SetQueryStringConfig(config) - return ret, nil -} - -func parseSourceIpCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { - ret := &elbv2.RuleCondition{} - ret.SetField("source-ip") - - values, err := condition.GetMap("sourceIpConfig") - if err != nil { - return nil, errors.Wrap(err, "GetMap.sourceIpConfig") - } - - config := &elbv2.SourceIpConditionConfig{} - vs, ok := values["values"] - if !ok { - return nil, fmt.Errorf("parseSourceIpCondition missing filed values") - } - - _vs, err := parseConditionStringArrayValues(vs) - if err != nil { - return nil, errors.Wrap(err, "parseConditionStringArrayValues") - } - config.SetValues(_vs) - return ret, nil -} - -func parseConditionStringArrayValues(values jsonutils.JSONObject) ([]*string, error) { - objs, ok := values.(*jsonutils.JSONArray) - if !ok { - return nil, fmt.Errorf("parseConditionStringArrayValues invalid values format, required array: %#v", values) - } - - ret := []*string{} - vs, _ := objs.GetArray() - for i := range vs { - v, ok := vs[i].(*jsonutils.JSONString) - if !ok { - return nil, fmt.Errorf("parseConditionStringArrayValues invalid value, required string: %#v", v) - } - - _v, _ := v.GetString() - ret = append(ret, &_v) - } - - return ret, nil -} - -func parseConditionDictArrayValues(values jsonutils.JSONObject) ([]*elbv2.QueryStringKeyValuePair, error) { - objs, ok := values.(*jsonutils.JSONArray) - if !ok { - return nil, fmt.Errorf("parseConditionDictArrayValues invalid values format, required array: %#v", values) - } - - ret := []*elbv2.QueryStringKeyValuePair{} - vs, _ := objs.GetArray() - for i := range vs { - v, ok := vs[i].(*jsonutils.JSONDict) - if !ok { - return nil, fmt.Errorf("parseConditionDictArrayValues invalid value, required dict: %#v", v) - } - - key, err := v.GetString("key") - if err != nil { - return nil, errors.Wrap(err, "GetString.key") - } - - value, err := v.GetString("value") - if err != nil { - return nil, errors.Wrap(err, "GetString.value") - } - - pair := &elbv2.QueryStringKeyValuePair{} - pair.SetKey(key) - pair.SetValue(value) - ret = append(ret, pair) - } - - return ret, nil -} diff --git a/pkg/multicloud/aws/monitor.go b/pkg/multicloud/aws/monitor.go deleted file mode 100644 index a44bf77a5f..0000000000 --- a/pkg/multicloud/aws/monitor.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -func (self *SAwsClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - if len(opts.ResourceId) == 0 { - return nil, fmt.Errorf("missing resource id") - } - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_RDS: - return self.GetRdsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: - return self.GetRedisMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) - } -} - -func (self *SAwsClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ - cloudprovider.VM_METRIC_TYPE_CPU_USAGE: { - "CPUUtilization": "", - }, - cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: { - "DiskReadOps": "", - "EBSReadOps": cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE, - }, - cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: { - "DiskWriteOps": "", - "EBSWriteOps": cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE, - }, - cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: { - "DiskReadBytes": "", - "EBSReadBytes": cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE, - }, - cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: { - "DiskWriteBytes": "", - "EBSWriteBytes": cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE, - }, - cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: { - "NetworkIn": "", - }, - cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: { - "NetworkOut": "", - }, - } { - part, err := self.getMetrics(opts.RegionExtId, "AWS/EC2", metricType, metricNames, "InstanceId", opts.ResourceId, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("getMetrics error: %v", err) - continue - } - ret = append(ret, part...) - } - return ret, nil -} - -type Datapoint struct { - Average float64 `xml:"Average"` - ExtendedStatistics struct { - Key string `xml:"Key"` - Value string `xml:"Value"` - } `xml:"ExtendedStatistics>entry"` - Maximum float64 `xml:"Maximum"` - Minimum float64 `xml:"Minimum"` - SampleCount float64 `xml:"SampleCount"` - Sum float64 `xml:"Sum"` - Timestamp time.Time `xml:"Timestamp"` - Unit string `xml:"Unit"` -} - -func (self Datapoint) GetValue() float64 { - return self.Average + self.Average + self.Minimum + self.Sum -} - -type Datapoints struct { - Datapoints []Datapoint `xml:"Datapoints>member"` - Label string `xml:"Label"` -} - -func (self *SAwsClient) getMetrics(regionId, ns string, metricType cloudprovider.TMetricType, metrics map[string]string, dimensionName, dimensionValue string, start, end time.Time) ([]cloudprovider.MetricValues, error) { - result := []cloudprovider.MetricValues{} - for metricName, tagValue := range metrics { - params := map[string]string{ - "EndTime": end.Format(time.RFC3339), - "MetricName": metricName, - "Dimensions.member.1.Name": dimensionName, - "Dimensions.member.1.Value": dimensionValue, - "Namespace": ns, - "Period": "1", - "StartTime": start.Format(time.RFC3339), - "Statistics.member.1": "Average", - } - ret := Datapoints{} - err := self.monitorRequest(regionId, "GetMetricStatistics", params, &ret) - if err != nil { - log.Errorf("GetMetricStatistics error: %v", err) - continue - } - metric := cloudprovider.MetricValues{} - metric.Id = dimensionValue - metric.MetricType = metricType - tags := map[string]string{} - idx := strings.Index(tagValue, ":") - if idx > 0 { - tags[tagValue[:idx]] = tagValue[idx+1:] - } - for _, data := range ret.Datapoints { - metricValue := cloudprovider.MetricValue{} - metricValue.Tags = tags - metricValue.Timestamp = data.Timestamp - metricValue.Value = data.GetValue() - metric.Values = append(metric.Values, metricValue) - } - result = append(result, metric) - } - return result, nil -} - -func (self *SAwsClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ - cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: { - "CPUUtilization": "", - }, - cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: { - "NetworkReceiveThroughput": "", - }, - cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: { - "NetworkTransmitThroughput": "", - }, - cloudprovider.RDS_METRIC_TYPE_CONN_COUNT: { - "DatabaseConnections": "", - }, - } { - part, err := self.getMetrics(opts.RegionExtId, "AWS/RDS", metricType, metricNames, "DBInstanceIdentifier", opts.ResourceId, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("getMetrics error: %v", err) - continue - } - ret = append(ret, part...) - } - return ret, nil - -} - -func (self *SAwsClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ - cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE: { - "CPUUtilization": "", - }, - cloudprovider.REDIS_METRIC_TYPE_USED_CONN: { - "CurrConnections": "", - }, - cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS: { - "Reclaimed": "", - }, - } { - part, err := self.getMetrics(opts.RegionExtId, "AWS/ElastiCache", metricType, metricNames, "CacheClusterId", opts.ResourceId, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("getMetrics error: %v", err) - continue - } - ret = append(ret, part...) - } - return ret, nil -} diff --git a/pkg/multicloud/aws/natgateway.go b/pkg/multicloud/aws/natgateway.go deleted file mode 100644 index 9a15de4c20..0000000000 --- a/pkg/multicloud/aws/natgateway.go +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type NatGatewayAddress struct { - AllocationId string `xml:"allocationId"` - NetworkInterfaceId string `xml:"networkInterfaceId"` - PrivateIp string `xml:"privateIp"` - PublicIp string `xml:"publicIp"` -} - -type ProvisionedBandwidth struct { - ProvisionTime time.Time `xml:"provisionTime"` - Provisioned string `xml:"provisioned"` - RequestTime time.Time `xml:"requestTime"` - Requested string `xml:"requested"` - Status string `xml:"status"` -} - -type SNatGateway struct { - multicloud.SNatGatewayBase - multicloud.AwsTags - - region *SRegion - - ConnectivityType string `xml:"connectivityType"` - CreateTime time.Time `xml:"createTime"` - DeleteTime time.Time `xml:"deleteTime"` - FailureCode string `xml:"failureCode"` - FailureMessage string `xml:"failureMessage"` - NatGatewayAddresses []NatGatewayAddress `xml:"natGatewayAddressSet>item"` - NatGatewayId string `xml:"natGatewayId"` - ProvisionedBandwidth ProvisionedBandwidth `xml:"provisionedBandwidth"` - // pending | failed | available | deleting | deleted - State string `xml:"state"` - SubnetId string `xml:"subnetId"` - VpcId string `xml:"vpcId"` -} - -func (self *SNatGateway) GetName() string { - name := self.AwsTags.GetName() - if len(name) > 0 { - return name - } - return self.NatGatewayId -} - -func (self *SNatGateway) GetId() string { - return self.NatGatewayId -} - -func (self *SNatGateway) GetGlobalId() string { - return self.NatGatewayId -} - -func (self *SNatGateway) GetStatus() string { - switch self.State { - case "pending": - return api.NAT_STATUS_ALLOCATE - case "failed": - return api.NAT_STATUS_CREATE_FAILED - case "available": - return api.NAT_STAUTS_AVAILABLE - case "deleting", "deleted": - return api.NAT_STATUS_DELETING - default: - return api.NAT_STATUS_UNKNOWN - } -} - -func (self *SNatGateway) GetNatSpec() string { - return "" -} - -func (self *SNatGateway) Refresh() error { - nat, err := self.region.GetNatGateway(self.NatGatewayId) - if err != nil { - return err - } - return jsonutils.Update(self, nat) -} - -func (self *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, err := self.region.GetEips("", "", self.NatGatewayId) - if err != nil { - return nil, errors.Wrapf(err, "GetEIPs") - } - ret := []cloudprovider.ICloudEIP{} - for i := range eips { - eips[i].region = self.region - ret = append(ret, &eips[i]) - } - return ret, nil -} - -func (self *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { - return []cloudprovider.ICloudNatDEntry{}, nil -} - -func (self *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { - return []cloudprovider.ICloudNatSEntry{}, nil -} - -func (self *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SNatGateway) GetINetworkId() string { - return self.SubnetId -} - -func (self *SNatGateway) GetBandwidthMb() int { - return 0 -} - -func (self *SNatGateway) GetIpAddr() string { - ipAddrs := []string{} - for _, addr := range self.NatGatewayAddresses { - if len(addr.PrivateIp) > 0 { - ipAddrs = append(ipAddrs, addr.PrivateIp) - } - } - return strings.Join(ipAddrs, ",") -} - -func (self *SNatGateway) Delete() error { - return self.region.DeleteNatgateway(self.NatGatewayId) -} - -func (self *SRegion) DeleteNatgateway(id string) error { - params := map[string]string{ - "NatGatewayId": id, - } - return self.ec2Request("DeleteNatGateway", params, nil) -} - -func (self *SRegion) GetNatGateways(ids []string, vpcId, subnetId string) ([]SNatGateway, error) { - params := map[string]string{} - for i, id := range ids { - params[fmt.Sprintf("NatGatewayId.%d", i+1)] = id - } - idx := 1 - if len(vpcId) > 0 { - params[fmt.Sprintf("Filter.%d.Name", idx)] = "vpc-id" - params[fmt.Sprintf("Filter.%d.Value.1", idx)] = vpcId - idx++ - } - if len(subnetId) > 0 { - params[fmt.Sprintf("Filter.%d.Name", idx)] = "subnet-id" - params[fmt.Sprintf("Filter.%d.Value.1", idx)] = subnetId - idx++ - } - params[fmt.Sprintf("Filter.%d.Name", idx)] = "state" - for i, state := range []string{ - "pending", - "failed", - "available", - "deleting", - } { - params[fmt.Sprintf("Filter.%d.Value.%d", idx, i+1)] = state - } - idx++ - ret := []SNatGateway{} - for { - result := struct { - Nats []SNatGateway `xml:"natGatewaySet>item"` - NextToken string `xml:"nextToken"` - }{} - err := self.ec2Request("DescribeNatGateways", params, &result) - if err != nil { - return nil, errors.Wrapf(err, "DescribeNatGateways") - } - ret = append(ret, result.Nats...) - if len(result.NextToken) == 0 || len(result.Nats) == 0 { - break - } - params["NextToken"] = result.NextToken - } - return ret, nil -} - -func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) { - nats, err := self.GetNatGateways([]string{id}, "", "") - if err != nil { - return nil, errors.Wrapf(err, "GetNatGateways") - } - for i := range nats { - if nats[i].GetGlobalId() == id { - nats[i].region = self - return &nats[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { - nats, err := self.region.GetNatGateways(nil, self.VpcId, "") - if err != nil { - return nil, errors.Wrapf(err, "GetINatGateways") - } - ret := []cloudprovider.ICloudNatGateway{} - for i := range nats { - nats[i].region = self.region - ret = append(ret, &nats[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/aws/network.go b/pkg/multicloud/aws/network.go deleted file mode 100644 index de055a9879..0000000000 --- a/pkg/multicloud/aws/network.go +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "strconv" - "strings" - "time" - - "github.com/aws/aws-sdk-go/service/ec2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.AwsTags - 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 { - if len(self.NetworkName) == 0 { - return self.NetworkId - } - - return self.NetworkName -} - -func (self *SNetwork) GetGlobalId() string { - return self.NetworkId -} - -func (self *SNetwork) GetStatus() string { - if self.wire != nil && self.wire.vpc != nil && self.wire.vpc.InstanceTenancy == "dedicated" { - return api.NETWORK_STATUS_UNAVAILABLE - } - - return strings.ToLower(self.Status) -} - -func (self *SNetwork) Refresh() error { - 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) GetSysTags() map[string]string { - data := map[string]string{} - routes, _ := self.wire.vpc.region.GetRouteTablesByNetworkId(self.GetId()) - if len(routes) == 0 { - routes, _ = self.wire.vpc.region.GetRouteTables(self.VpcId, true) - } - - support_eip := false - if len(routes) >= 1 { - for i := range routes[0].Routes { - route := routes[0].Routes[i] - if route.GetNextHopType() == api.NEXT_HOP_TYPE_INTERNET { - support_eip = true - } - } - } - data["support_eip"] = strconv.FormatBool(support_eip) - return data -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -// 每个子网 CIDR 块中的前四个 IP 地址和最后一个 IP 地址无法使用 -func (self *SNetwork) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - startIp = startIp.StepUp() // 2 - startIp = startIp.StepUp() // 3 - startIp = startIp.StepUp() // 4 - return startIp.String() -} - -func (self *SNetwork) GetIpEnd() string { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 - endIp = endIp.StepDown() // 254 - 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 api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetIsPublic() bool { - return true -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -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) - - ec2Client, err := self.getEc2Client() - if err != nil { - return "", errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.CreateSubnet(params) - if err != nil { - return "", err - } else { - paramsTags := &ec2.CreateTagsInput{} - tagspec := TagSpec{ResourceType: "subnet"} - tagspec.SetNameTag(name) - tagspec.SetDescTag(desc) - ec2Tag, _ := tagspec.GetTagSpecifications() - paramsTags.SetResources([]*string{ret.Subnet.SubnetId}) - paramsTags.SetTags(ec2Tag.Tags) - _, err := ec2Client.CreateTags(paramsTags) - if err != nil { - log.Infof("createNetwork write tags failed:%s", err) - } - return *ret.Subnet.SubnetId, nil - } -} - -func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) { - if len(networkId) == 0 { - return nil, fmt.Errorf("GetNetwork networkId should not be empty.") - } - networks, err := self.GetNetwroks([]string{networkId}, "") - if err != nil { - return nil, errors.Wrap(err, "GetNetwroks") - } - if len(networks) != 1 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "getNetwork") - } - return &networks[0], nil -} - -func (self *SRegion) deleteNetwork(networkId string) error { - params := &ec2.DeleteSubnetInput{} - params.SetSubnetId(networkId) - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.DeleteSubnet(params) - return errors.Wrap(err, "DeleteSubnet") -} - -func (self *SRegion) GetNetwroks(ids []string, vpcId string) ([]SNetwork, 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) - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - ret, err := ec2Client.DescribeSubnets(params) - err = parseNotFoundError(err) - if err != nil { - return nil, err - } - - subnets := []SNetwork{} - for i := range ret.Subnets { - item := ret.Subnets[i] - if err := FillZero(item); err != nil { - return nil, err - } - - tagspec := TagSpec{ResourceType: "subnet"} - tagspec.LoadingEc2Tags(item.Tags) - - 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 = tagspec.GetNameTag() - jsonutils.Update(&subnet.AwsTags.TagSet, item.Tags) - subnets = append(subnets, subnet) - } - return subnets, nil -} - -func (self *SNetwork) GetProjectId() string { - return "" -} diff --git a/pkg/multicloud/aws/networkinterface.go b/pkg/multicloud/aws/networkinterface.go deleted file mode 100644 index ce8a2784e2..0000000000 --- a/pkg/multicloud/aws/networkinterface.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "time" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SGroupSet struct { - GroupId string `xml:"groupId"` - GroupName string `xml:"groupName"` -} - -type SPrivateIpAddress struct { - PrivateIpAddress string `xml:"privateIpAddress"` - PrivateDnsName string `xml:"privateDnsName"` - Primary bool `xml:"primary"` -} - -type SAttachment struct { - AttachmentId string `xml:"attachmentId"` - InstanceOwnerId string `xml:"instanceOwnerId"` - DeviceIndex int `xml:"deviceIndex"` - Status string `xml:"status"` - AttachTime time.Time `xml:"attachTime"` - DeleteOnTermination bool `xml:"deleteOnTermination"` -} - -type SNetworkInterface struct { - NetworkInterfaceId string `xml:"networkInterfaceId"` - SubnetId string `xml:"subnetId"` - VpcId string `xml:"vpcId"` - AvailabilityZone string `xml:"availabilityZone"` - Description string `xml:"description"` - OwnerId string `xml:"ownerId"` - RequesterId string `xml:"requesterId"` - RequesterManaged bool `xml:"requesterManaged"` - Status string `xml:"status"` - MacAddress string `xml:"macAddress"` - PrivateIpAddress string `xml:"privateIpAddress"` - PrivateDnsName string `xml:"privateDnsName"` - SourceDestCheck bool `xml:"sourceDestCheck"` - GroupSet []SGroupSet `xml:"groupSet>item"` - Attachment SAttachment `xml:"attachment"` - PrivateIpAddressesSet []SPrivateIpAddress `xml:"privateIpAddressesSet>item"` - InterfaceType string `xml:"interfaceType"` -} - -func (self *SRegion) GetNetworkInterface(id string) (*SNetworkInterface, error) { - nets, err := self.GetNetworkInterfaces(id) - if err != nil { - return nil, errors.Wrapf(err, "GetNetworkInterface") - } - for i := range nets { - if nets[i].NetworkInterfaceId == id { - return &nets[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SRegion) GetNetworkInterfaces(id string) ([]SNetworkInterface, error) { - params := map[string]string{} - if len(id) > 0 { - params["NetworkInterfaceId.1"] = id - } - ret := []SNetworkInterface{} - for { - result := struct { - NetworkInterfaceSet []SNetworkInterface `xml:"networkInterfaceSet>item"` - NextToken string `xml:"nextToken"` - }{} - err := self.ec2Request("DescribeNetworkInterfaces", params, &result) - if err != nil { - return nil, errors.Wrap(err, "DescribeNetworkInterfaces") - } - ret = append(ret, result.NetworkInterfaceSet...) - if len(result.NextToken) == 0 || len(result.NetworkInterfaceSet) == 0 { - break - } - params["NextToken"] = result.NextToken - } - return ret, nil -} diff --git a/pkg/multicloud/aws/organizations.go b/pkg/multicloud/aws/organizations.go deleted file mode 100644 index 991093712a..0000000000 --- a/pkg/multicloud/aws/organizations.go +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/service/organizations" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -/* - * {"arn":"arn:aws:organizations::285906155448:account/o-vgh74bqhdw/285906155448","email":"swordqiu@gmail.com","id":"285906155448","joined_method":"INVITED","joined_timestamp":"2021-02-09T03:55:27.724000Z","name":"qiu jian","status":"ACTIVE"} - */ -type SAccount struct { - ID string `json:"id"` - Name string `json:"name"` - Arn string `json:"arn"` - Email string `json:"email"` - Status string `json:"status"` - - JoinedMethod string `json:"joined_method"` - JoinedTimestamp time.Time `json:"joined_timestamp"` - - IsMaster bool `json:"is_master"` -} - -/* - * { - * Arn: "arn:aws:organizations::031871565791:policy/o-gn75phg8ge/service_control_policy/p-4l9recev", - * AwsManaged: false, - * Description: "Create Preventive SCP Guardrails", - * Id: "p-4l9recev", - * Name: "SCP-PREVENTIVE-GUARDRAILS", - * Type: "SERVICE_CONTROL_POLICY" - * } - */ -type SOrgPolicy struct { - Arn string `json:"arn"` - AwsManaged bool `json:"aws_managed"` - Description string `json:"description"` - Id string `json:"id"` - Name string `json:"name"` - Type string `json:"type"` -} - -const ( - SERVICE_CONTROL_POLICY = "SERVICE_CONTROL_POLICY" - TAG_POLICY = "TAG_POLICY" - BACKUP_POLICY = "BACKUP_POLICY" - AISERVICES_OPT_OUT_POLICY = "AISERVICES_OPT_OUT_POLICY" -) - -func (r *SRegion) ListPolicies(filter string) ([]SOrgPolicy, error) { - orgCli, err := r.getOrganizationClient() - if err != nil { - return nil, errors.Wrap(err, "GetOrganizationClient") - } - var nextToken *string - policies := make([]SOrgPolicy, 0) - - for { - input := organizations.ListPoliciesInput{} - input.SetFilter(filter) - if nextToken != nil { - input.SetNextToken(*nextToken) - } - parts, err := orgCli.ListPolicies(&input) - if err != nil { - return nil, errors.Wrap(err, "ListPolicies") - } - for _, pPtr := range parts.Policies { - p := SOrgPolicy{ - Arn: *pPtr.Arn, - AwsManaged: *pPtr.AwsManaged, - Description: *pPtr.Description, - Id: *pPtr.Id, - Name: *pPtr.Name, - Type: *pPtr.Type, - } - policies = append(policies, p) - } - if parts.NextToken == nil || len(*parts.NextToken) == 0 { - break - } else { - nextToken = parts.NextToken - } - } - return policies, nil -} - -func (r *SRegion) ListPoliciesForTarget(filter string, targetId string) ([]SOrgPolicy, error) { - orgCli, err := r.getOrganizationClient() - if err != nil { - return nil, errors.Wrap(err, "GetOrganizationClient") - } - var nextToken *string - policies := make([]SOrgPolicy, 0) - - for { - input := organizations.ListPoliciesForTargetInput{} - input.SetFilter(filter) - input.SetTargetId(targetId) - if nextToken != nil { - input.SetNextToken(*nextToken) - } - parts, err := orgCli.ListPoliciesForTarget(&input) - if err != nil { - return nil, errors.Wrap(err, "ListPoliciesForTarget") - } - for _, pPtr := range parts.Policies { - p := SOrgPolicy{ - Arn: *pPtr.Arn, - AwsManaged: *pPtr.AwsManaged, - Description: *pPtr.Description, - Id: *pPtr.Id, - Name: *pPtr.Name, - Type: *pPtr.Type, - } - policies = append(policies, p) - } - if parts.NextToken == nil || len(*parts.NextToken) == 0 { - break - } else { - nextToken = parts.NextToken - } - } - return policies, nil -} - -func (r *SRegion) DescribeOrgPolicy(pId string) (jsonutils.JSONObject, error) { - orgCli, err := r.getOrganizationClient() - if err != nil { - return nil, errors.Wrap(err, "GetOrganizationClient") - } - input := organizations.DescribePolicyInput{} - input.SetPolicyId(pId) - output, err := orgCli.DescribePolicy(&input) - if err != nil { - return nil, errors.Wrap(err, "DescribePolicy") - } - content, err := jsonutils.ParseString(*output.Policy.Content) - if err != nil { - return nil, errors.Wrap(err, "ParseJSON") - } - return content, nil -} - -func (r *SRegion) ListAccounts() ([]SAccount, error) { - orgCli, err := r.getOrganizationClient() - if err != nil { - return nil, errors.Wrap(err, "GetOrganizationClient") - } - input := organizations.DescribeOrganizationInput{} - orgOutput, err := orgCli.DescribeOrganization(&input) - if err != nil { - log.Errorf("%#v", err) - return nil, errors.Wrap(err, "DescribeOrganization") - } - - var nextToken *string - accounts := make([]SAccount, 0) - for { - input := organizations.ListAccountsInput{} - if nextToken != nil { - input.NextToken = nextToken - } - parts, err := orgCli.ListAccounts(&input) - if err != nil { - return nil, errors.Wrap(err, "ListAccounts") - } - for _, actPtr := range parts.Accounts { - account := SAccount{ - ID: *actPtr.Id, - Name: *actPtr.Name, - Arn: *actPtr.Arn, - Email: *actPtr.Email, - Status: *actPtr.Status, - JoinedMethod: *actPtr.JoinedMethod, - JoinedTimestamp: *actPtr.JoinedTimestamp, - } - if *orgOutput.Organization.MasterAccountId == *actPtr.Id { - account.IsMaster = true - } - accounts = append(accounts, account) - } - if parts.NextToken == nil || len(*parts.NextToken) == 0 { - break - } else { - nextToken = parts.NextToken - } - } - return accounts, nil -} - -func (self *SAwsClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - defRegion, err := self.getDefaultRegion() - if err != nil { - return nil, errors.Wrapf(err, "getDefaultRegion") - } - accounts, err := defRegion.ListAccounts() - if err != nil { - // find errors - if strings.Contains(err.Error(), "AWSOrganizationsNotInUseException") || strings.Contains(err.Error(), "AccessDeniedException") { - // permission denied, fall back to single account mode - subAccount := cloudprovider.SSubAccount{} - subAccount.Name = self.cpcfg.Name - subAccount.Account = self.accessKey - subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL - return []cloudprovider.SSubAccount{subAccount}, nil - } else { - return nil, errors.Wrap(err, "ListAccounts") - } - } else { - // check if caller is a root caller - caller, _ := self.GetCallerIdentity() - isRootAccount := false - // arn:aws:iam::285906155448:root - if caller != nil && strings.HasSuffix(caller.Arn, ":root") { - log.Debugf("root %s", caller.Arn) - isRootAccount = true - } - subAccounts := []cloudprovider.SSubAccount{} - for _, account := range accounts { - subAccount := cloudprovider.SSubAccount{} - if account.Status == "ACTIVE" { - subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL - } else { - subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_SUSPENDED - } - if account.IsMaster { - subAccount.Name = fmt.Sprintf("%s/%s", account.Name, self.cpcfg.Name) - subAccount.Account = self.accessKey - } else { - if isRootAccount { - log.Warningf("Cannot access non-master account with root account!!") - subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NO_PERMISSION - } - subAccount.Name = fmt.Sprintf("%s/%s", account.Name, account.ID) - subAccount.Account = fmt.Sprintf("%s/%s", self.accessKey, account.ID) - } - subAccounts = append(subAccounts, subAccount) - } - return subAccounts, nil - } -} - -func (r *SRegion) ListParents(childId string) error { - orgCli, err := r.getOrganizationClient() - if err != nil { - return errors.Wrap(err, "GetOrganizationClient") - } - input := organizations.ListParentsInput{} - input.SetChildId(childId) - parents, err := orgCli.ListParents(&input) - if err != nil { - return errors.Wrap(err, "ListParents") - } - log.Debugf("%#v", parents) - return nil -} - -func (r *SRegion) DescribeOrganizationalUnit(ouId string) error { - orgCli, err := r.getOrganizationClient() - if err != nil { - return errors.Wrap(err, "GetOrganizationClient") - } - input := organizations.DescribeOrganizationalUnitInput{} - input.SetOrganizationalUnitId(ouId) - output, err := orgCli.DescribeOrganizationalUnit(&input) - if err != nil { - return errors.Wrap(err, "DescribeOrganizationUnit") - } - log.Debugf("%#v", output) - return nil -} diff --git a/pkg/multicloud/aws/provider/doc.go b/pkg/multicloud/aws/provider/doc.go deleted file mode 100644 index 049cb576d6..0000000000 --- a/pkg/multicloud/aws/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/aws/provider" diff --git a/pkg/multicloud/aws/provider/provider.go b/pkg/multicloud/aws/provider/provider.go deleted file mode 100644 index 9ccdb42945..0000000000 --- a/pkg/multicloud/aws/provider/provider.go +++ /dev/null @@ -1,410 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/aws" -) - -type SAwsProviderFactory struct { - cloudprovider.SPublicCloudBaseProviderFactory -} - -func (self *SAwsProviderFactory) GetId() string { - return aws.CLOUD_PROVIDER_AWS -} - -func (self *SAwsProviderFactory) GetName() string { - return aws.CLOUD_PROVIDER_AWS_CN -} - -func (self *SAwsProviderFactory) IsCloudeventRegional() bool { - return true -} - -func (self *SAwsProviderFactory) GetMaxCloudEventSyncDays() int { - return 1 -} - -func (self *SAwsProviderFactory) GetMaxCloudEventKeepDays() int { - return 90 -} - -func (self *SAwsProviderFactory) IsSupportPrepaidResources() bool { - return false -} - -func (self *SAwsProviderFactory) IsSupportCloudIdService() bool { - return true -} - -func (self *SAwsProviderFactory) IsSupportCreateCloudgroup() bool { - return true -} - -func (factory *SAwsProviderFactory) IsSystemCloudpolicyUnified() bool { - return false -} - -func (factory *SAwsProviderFactory) IsSupportSAMLAuth() bool { - return true -} - -func (self *SAwsProviderFactory) GetSupportedDnsZoneTypes() []cloudprovider.TDnsZoneType { - return []cloudprovider.TDnsZoneType{ - cloudprovider.PublicZone, - cloudprovider.PrivateZone, - } -} - -func (self *SAwsProviderFactory) GetSupportedDnsTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType { - return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType{ - cloudprovider.PublicZone: []cloudprovider.TDnsType{ - cloudprovider.DnsTypeA, - cloudprovider.DnsTypeAAAA, - cloudprovider.DnsTypeCAA, - cloudprovider.DnsTypeCNAME, - cloudprovider.DnsTypeMX, - cloudprovider.DnsTypeNS, - cloudprovider.DnsTypeSRV, - cloudprovider.DnsTypeSOA, - cloudprovider.DnsTypeTXT, - cloudprovider.DnsTypePTR, - cloudprovider.DnsTypeNAPTR, - cloudprovider.DnsTypeSPF, - }, - cloudprovider.PrivateZone: []cloudprovider.TDnsType{ - cloudprovider.DnsTypeA, - cloudprovider.DnsTypeAAAA, - cloudprovider.DnsTypeCAA, - cloudprovider.DnsTypeCNAME, - cloudprovider.DnsTypeMX, - cloudprovider.DnsTypeNS, - cloudprovider.DnsTypeSRV, - cloudprovider.DnsTypeSOA, - cloudprovider.DnsTypeTXT, - cloudprovider.DnsTypePTR, - cloudprovider.DnsTypeNAPTR, - cloudprovider.DnsTypeSPF, - }, - } -} - -func (self *SAwsProviderFactory) GetSupportedDnsPolicyTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType { - return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType{ - cloudprovider.PublicZone: []cloudprovider.TDnsPolicyType{ - cloudprovider.DnsPolicyTypeSimple, - cloudprovider.DnsPolicyTypeByGeoLocation, - cloudprovider.DnsPolicyTypeWeighted, - cloudprovider.DnsPolicyTypeFailover, - cloudprovider.DnsPolicyTypeMultiValueAnswer, - cloudprovider.DnsPolicyTypeLatency, - }, - cloudprovider.PrivateZone: []cloudprovider.TDnsPolicyType{ - cloudprovider.DnsPolicyTypeSimple, - cloudprovider.DnsPolicyTypeWeighted, - cloudprovider.DnsPolicyTypeFailover, - cloudprovider.DnsPolicyTypeMultiValueAnswer, - cloudprovider.DnsPolicyTypeLatency, - }, - } -} - -func (self *SAwsProviderFactory) GetSupportedDnsPolicyValues() map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue { - return map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue{ - cloudprovider.DnsPolicyTypeByGeoLocation: cloudprovider.AwsGeoLocations, - cloudprovider.DnsPolicyTypeLatency: cloudprovider.AwsRegions, - cloudprovider.DnsPolicyTypeFailover: cloudprovider.AwsFailovers, - } -} - -func (factory *SAwsProviderFactory) IsSupportCrossCloudEnvVpcPeering() bool { - return false -} - -func (factory *SAwsProviderFactory) IsSupportCrossRegionVpcPeering() bool { - return true -} - -func (factory *SAwsProviderFactory) IsSupportVpcPeeringVpcCidrOverlap() bool { - return false -} - -func (factory *SAwsProviderFactory) IsSupportModifyRouteTable() bool { - return true -} - -func (self *SAwsProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - if len(input.Environment) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "environment") - } - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - output.AccessUrl = input.Environment - return output, nil -} - -func (self *SAwsProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func parseAccount(account, secret string) (accessKey string, secretKey string, accountId string) { - slash := strings.Index(account, "/") - if slash > 0 { - accessKey = account[:slash] - accountId = account[slash+1:] - } else { - accessKey = account - } - secretKey = secret - return -} - -func (self *SAwsProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - extra := cloudprovider.SAWSExtraOptions{} - if cfg.Options != nil { - cfg.Options.Unmarshal(&extra) - } - accessKey, secret, accountId := parseAccount(cfg.Account, cfg.Secret) - client, err := aws.NewAwsClient( - aws.NewAwsClientConfig( - cfg.URL, accessKey, secret, accountId, - ).SetAssumeRole(extra.AWSAssumeRoleName).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, errors.Wrap(err, "NewAwsClient") - } - return &SAwsProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SAwsProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - accessKey, secret, accountId := parseAccount(info.Account, info.Secret) - return map[string]string{ - "AWS_ACCESS_URL": info.Url, - "AWS_ACCESS_KEY": accessKey, - "AWS_SECRET": secret, - "AWS_REGION": aws.GetDefaultRegionId(info.Url), - "AWS_ACCOUNT_ID": accountId, - }, nil -} - -func init() { - factory := SAwsProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SAwsProvider struct { - cloudprovider.SBaseProvider - client *aws.SAwsClient -} - -func (self *SAwsProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SAwsProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SAwsProvider) GetIamLoginUrl() string { - return self.client.GetIamLoginUrl() -} - -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) GetVersion() string { - return aws.AWS_API_VERSION -} - -func (self *SAwsProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(id) -} - -func (self *SAwsProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SAwsProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SAwsProvider) GetStorageClasses(regionId string) []string { - return []string{ - "STANDARD", - "STANDARD_IA", - "ONEZONE_IA", - "GLACIER", - "DEEP_ARCHIVE", - "INTELLIGENT_TIERING", - } -} - -func (self *SAwsProvider) GetBucketCannedAcls(regionId string) []string { - return self.client.GetBucketCannedAcls() -} - -func (self *SAwsProvider) GetObjectCannedAcls(regionId string) []string { - return self.client.GetObjectCannedAcls() -} - -func (self *SAwsProvider) GetCloudRegionExternalIdPrefix() string { - return self.client.GetAccessEnv() + "/" -} - -func (self *SAwsProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SAwsProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - return self.client.CreateIClouduser(conf) -} - -func (self *SAwsProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { - return self.client.GetICloudusers() -} - -func (self *SAwsProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroups() -} - -func (self *SAwsProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroupByName(name) -} - -func (self *SAwsProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - return self.client.CreateICloudgroup(name, desc) -} - -func (self *SAwsProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetISystemCloudpolicies() -} - -func (self *SAwsProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetICustomCloudpolicies() -} - -func (self *SAwsProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.client.GetIClouduserByName(name) -} - -func (self *SAwsProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { - return self.client.CreateICloudpolicy(opts) -} - -func (self *SAwsProvider) GetSamlEntityId() string { - return self.client.GetSamlEntityId() -} - -func (self *SAwsProvider) GetICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { - return self.client.GetICloudDnsZones() -} - -func (self *SAwsProvider) GetICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { - return self.client.GetHostedZoneById(id) -} - -func (self *SAwsProvider) CreateICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { - return self.client.CreateHostedZone(opts) -} - -func (self *SAwsProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { - return self.client.GetICloudSAMLProviders() -} - -func (self *SAwsProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { - sp, err := self.client.CreateSAMLProvider(opts.Name, opts.Metadata.String()) - if err != nil { - return nil, errors.Wrap(err, "CreateSAMLProvider") - } - return sp, nil -} - -func (self *SAwsProvider) GetICloudroles() ([]cloudprovider.ICloudrole, error) { - return self.client.GetICloudroles() -} - -func (self *SAwsProvider) GetICloudroleById(id string) (cloudprovider.ICloudrole, error) { - roles, err := self.GetICloudroles() - if err != nil { - return nil, errors.Wrapf(err, "GetICloudroles") - } - for i := range roles { - if roles[i].GetGlobalId() == id { - return roles[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SAwsProvider) GetICloudroleByName(name string) (cloudprovider.ICloudrole, error) { - role, err := self.client.GetRole(name) - if err != nil { - return nil, errors.Wrapf(err, "GetRole(%s)", name) - } - return role, nil -} - -func (self *SAwsProvider) CreateICloudrole(opts *cloudprovider.SRoleCreateOptions) (cloudprovider.ICloudrole, error) { - role, err := self.client.CreateRole(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateRole") - } - return role, nil -} - -func (self *SAwsProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/aws/region.go b/pkg/multicloud/aws/region.go deleted file mode 100644 index e2061d3b63..0000000000 --- a/pkg/multicloud/aws/region.go +++ /dev/null @@ -1,1071 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "strings" - "sync" - "time" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/acm" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/aws/aws-sdk-go/service/iam" - "github.com/aws/aws-sdk-go/service/organizations" - "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/wafv2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var ( - lock sync.RWMutex -) - -var RegionLocations = map[string]string{ - "us-east-2": "美国东部(俄亥俄州)", - "us-east-1": "美国东部(弗吉尼亚北部)", - "us-west-1": "美国西部(加利福尼亚北部)", - "us-west-2": "美国西部(俄勒冈)", - "ap-east-1": "亚太区域(香港)", - "ap-south-1": "亚太区域(孟买)", - "ap-northeast-3": "亚太区域(大阪-本地)", - "ap-northeast-2": "亚太区域(首尔)", - "ap-southeast-1": "亚太区域(新加坡)", - "ap-southeast-2": "亚太区域(悉尼)", - "ap-northeast-1": "亚太区域(东京)", - "ca-central-1": "加拿大(中部)", - "cn-north-1": "中国(北京)", - "cn-northwest-1": "中国(宁夏)", - "eu-central-1": "欧洲(法兰克福)", - "eu-west-1": "欧洲(爱尔兰)", - "eu-west-2": "欧洲(伦敦)", - "eu-south-1": "欧洲(米兰)", - "eu-west-3": "欧洲(巴黎)", - "eu-north-1": "欧洲(斯德哥尔摩)", - "me-south-1": "中东(巴林)", - "sa-east-1": "南美洲(圣保罗)", - "us-gov-west-1": "AWS GovCloud(美国西部)", - "us-gov-east-1": "AWS GovCloud(美国东部)", - - "af-south-1": "非洲(开普敦)", -} - -var RegionLocationsEN = map[string]string{ - "us-east-1": "US East (N. Virginia)", - "us-east-2": "US East (Ohio)", - "us-west-1": "US West (N. California)", - "us-west-2": "US West (Oregon)", - "af-south-1": "Africa (Cape Town)", - "ap-east-1": "Asia Pacific (Hong Kong)", - "ap-south-1": "Asia Pacific (Mumbai)", - "ap-northeast-3": "Asia Pacific (Osaka)", - "ap-northeast-2": "Asia Pacific (Seoul)", - "ap-southeast-1": "Asia Pacific (Singapore)", - "ap-southeast-2": "Asia Pacific (Sydney)", - "ap-northeast-1": "Asia Pacific (Tokyo)", - "ca-central-1": "Canada (Central)", - "eu-central-1": "Europe (Frankfurt)", - "eu-west-1": "Europe (Ireland)", - "eu-west-2": "Europe (London)", - "eu-south-1": "Europe (Milan)", - "eu-west-3": "Europe (Paris)", - "eu-north-1": "Europe (Stockholm)", - "me-south-1": "Middle East (Bahrain)", - "sa-east-1": "South America (São Paulo)", - "cn-north-1": "China (Beijing)", - "cn-northwest-1": "China (Ninxia)", - "us-gov-west-1": "AWS GovCloud(US West)", - "us-gov-east-1": "AWS GovCloud(US East)", -} - -const ( - RDS_SERVICE_NAME = "rds" - RDS_SERVICE_ID = "RDS" - - EC2_SERVICE_NAME = "ec2" - EC2_SERVICE_ID = "EC2" - - IAM_SERVICE_NAME = "iam" - IAM_SERVICE_ID = "IAM" - - STS_SERVICE_NAME = "sts" - STS_SERVICE_ID = "STS" - - CLOUDWATCH_SERVICE_NAME = "monitoring" - CLOUDWATCH_SERVICE_ID = "CloudWatch" - - CLOUD_TRAIL_SERVICE_NAME = "CloudTrail" - CLOUD_TRAIL_SERVICE_ID = "cloudtrail" - - ROUTE53_SERVICE_NAME = "route53" - - ELASTICACHE_SERVICE_NAME = "elasticache" -) - -type SRegion struct { - multicloud.SRegion - - client *SAwsClient - ec2Client *ec2.EC2 - iamClient *iam.IAM - s3Client *s3.S3 - elbv2Client *elbv2.ELBV2 - acmClient *acm.ACM - wafClient *wafv2.WAFV2 - organizationClient *organizations.Organizations - resourceGroupTagClient *resourcegroupstaggingapi.ResourceGroupsTaggingAPI - - izones []cloudprovider.ICloudZone - ivpcs []cloudprovider.ICloudVpc - - storageCache *SStoragecache - - RegionEndpoint string - RegionId string // 这里为保持一致沿用阿里云RegionId的叫法, 与AWS RegionName字段对应 -} - -///////////////////////////////////////////////////////////////////////////// -/* 请不要使用这个client(AWS_DEFAULT_REGION)跨region查信息.有可能导致查询返回的信息为空。比如DescribeAvailabilityZones*/ -func (self *SRegion) GetClient() *SAwsClient { - return self.client -} - -func (self *SRegion) getAwsSession() (*session.Session, error) { - return self.client.getAwsSession(self.RegionId, true) -} - -func (self *SRegion) getEc2Client() (*ec2.EC2, error) { - if self.ec2Client == nil { - s, err := self.getAwsSession() - - if err != nil { - return nil, errors.Wrap(err, "getAwsSession") - } - - self.ec2Client = ec2.New(s) - } - - return self.ec2Client, nil -} - -func (self *SRegion) getIamClient() (*iam.IAM, error) { - if self.iamClient == nil { - s, err := self.getAwsSession() - - if err != nil { - return nil, errors.Wrap(err, "getAwsSession") - } - - self.iamClient = iam.New(s) - } - - return self.iamClient, nil -} - -func (self *SRegion) getWafClient() (*wafv2.WAFV2, error) { - if self.wafClient == nil { - s, err := self.getAwsSession() - if err != nil { - return nil, errors.Wrapf(err, "getAwsSession") - } - self.wafClient = wafv2.New(s) - } - return self.wafClient, nil -} - -func (self *SRegion) GetS3Client() (*s3.S3, error) { - if self.s3Client == nil { - s, err := self.getAwsSession() - if err != nil { - return nil, errors.Wrap(err, "getAwsSession") - } - self.s3Client = s3.New(s, - &aws.Config{ - DisableRestProtocolURICleaning: aws.Bool(true), - }) - } - return self.s3Client, nil -} - -func (r *SRegion) getOrganizationClient() (*organizations.Organizations, error) { - if r.organizationClient == nil { - s, err := r.getAwsSession() - if err != nil { - return nil, errors.Wrap(err, "getAwsSession") - } - r.organizationClient = organizations.New(s) - } - return r.organizationClient, nil -} - -func (self *SRegion) getResourceGroupTagClient() (*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, error) { - if self.resourceGroupTagClient == nil { - s, err := self.getAwsSession() - if err != nil { - return nil, errors.Wrap(err, "getAwsSession") - } - self.resourceGroupTagClient = resourcegroupstaggingapi.New(s) - } - return self.resourceGroupTagClient, nil -} - -func (self *SRegion) rdsRequest(apiName string, params map[string]string, retval interface{}) error { - return self.client.request(self.RegionId, RDS_SERVICE_NAME, RDS_SERVICE_ID, "2014-10-31", apiName, params, retval, true) -} - -func (self *SRegion) ec2Request(apiName string, params map[string]string, retval interface{}) error { - return self.client.request(self.RegionId, EC2_SERVICE_NAME, EC2_SERVICE_ID, "2016-11-15", apiName, params, retval, true) -} - -func (self *SAwsClient) monitorRequest(regionId, apiName string, params map[string]string, retval interface{}) error { - return self.request(regionId, CLOUDWATCH_SERVICE_NAME, CLOUDWATCH_SERVICE_ID, "2010-08-01", apiName, params, retval, true) -} - -func (self *SRegion) GetElbV2Client() (*elbv2.ELBV2, error) { - if self.elbv2Client == nil { - s, err := self.getAwsSession() - - if err != nil { - return nil, errors.Wrap(err, "getAwsSession") - } - - self.elbv2Client = elbv2.New(s) - } - - return self.elbv2Client, nil -} - -///////////////////////////////////////////////////////////////////////////// -func (self *SRegion) fetchZones() error { - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - // todo: 这里将过滤出指定region下全部的zones。是否只过滤出可用的zone即可? The state of the Availability Zone (available | information | impaired | unavailable) - zones, err := ec2Client.DescribeAvailabilityZones(&ec2.DescribeAvailabilityZonesInput{}) - if err != nil { - return errors.Wrap(err, "DescribeAvailabilityZones") - } - 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 { - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - vpcs, err := ec2Client.DescribeVpcs(&ec2.DescribeVpcsInput{}) - if err != nil { - return err - } - - self.ivpcs = make([]cloudprovider.ICloudVpc, 0) - for _, vpc := range vpcs.Vpcs { - cidrBlockAssociationSet := []string{} - for i := range vpc.CidrBlockAssociationSet { - cidr := vpc.CidrBlockAssociationSet[i] - if cidr.CidrBlockState.State != nil && *cidr.CidrBlockState.State == "associated" { - cidrBlockAssociationSet = append(cidrBlockAssociationSet, *cidr.CidrBlock) - } - } - - tagspec := TagSpec{ResourceType: "vpc"} - tagspec.LoadingEc2Tags(vpc.Tags) - ivpc := &SVpc{region: self, - CidrBlock: *vpc.CidrBlock, - CidrBlockAssociationSet: cidrBlockAssociationSet, - IsDefault: *vpc.IsDefault, - RegionId: self.RegionId, - Status: *vpc.State, - VpcId: *vpc.VpcId, - VpcName: tagspec.GetNameTag(), - InstanceTenancy: *vpc.InstanceTenancy, - } - jsonutils.Update(&ivpc.AwsTags.TagSet, vpc.Tags) - self.ivpcs = append(self.ivpcs, ivpc) - } - - 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 { - if localName, ok := RegionLocations[self.RegionId]; ok { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_CN, localName) - } - - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_CN, self.RegionId) -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - var en string - if localName, ok := RegionLocationsEN[self.RegionId]; ok { - en = fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_EN, localName) - } else { - en = fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_EN, self.RegionId) - } - - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.RegionId) -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) Refresh() error { - return nil -} - -func (self *SRegion) IsEmulated() bool { - return false -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - if info, ok := LatitudeAndLongitude[self.RegionId]; ok { - return info - } - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if self.izones == nil { - if err := self.fetchInfrastructure(); err != nil { - return nil, errors.Wrap(err, "fetchInfrastructure") - } - } - return self.izones, nil -} - -func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - if self.ivpcs == nil { - err := self.fetchInfrastructure() - if err != nil { - return nil, errors.Wrap(err, "fetchInfrastructure") - } - } - return self.ivpcs, nil -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - return self.GetInstance(id) -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return self.GetDisk(id) -} - -func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, err := self.GetEips("", "", "") - if err != nil { - return nil, errors.Wrap(err, "GetEips") - } - ret := []cloudprovider.ICloudEIP{} - for i := range eips { - eips[i].region = self - ret = append(ret, &eips[i]) - } - return ret, nil -} - -func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, _, err := self.GetSnapshots("", "", "", []string{}, 0, 0) - if err != nil { - return nil, errors.Wrap(err, "GetSnapshots") - } - - 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, errors.Wrap(err, "GetIZones") - } - - for _, zone := range izones { - if zone.GetGlobalId() == id { - return zone, nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIZoneById") -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - ivpcs, err := self.GetIVpcs() - if err != nil { - return nil, errors.Wrap(err, "GetIVpcs") - } - - for _, vpc := range ivpcs { - if vpc.GetGlobalId() == id { - return vpc, nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIVpcById") -} - -func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - izones, err := self.GetIZones() - if err != nil { - return nil, errors.Wrap(err, "GetIZones") - } - for i := 0; i < len(izones); i += 1 { - ihost, err := izones[i].GetIHostById(id) - if err == nil { - return ihost, nil - } else if errors.Cause(err) != cloudprovider.ErrNotFound { - log.Errorf("GetIHostById %s: %s", id, err) - return nil, errors.Wrap(err, "GetIHostById") - } - } - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIHostById") -} - -func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - izones, err := self.GetIZones() - if err != nil { - return nil, errors.Wrap(err, "GetIZones") - } - for i := 0; i < len(izones); i += 1 { - istore, err := izones[i].GetIStorageById(id) - if err == nil { - return istore, nil - } else if errors.Cause(err) != cloudprovider.ErrNotFound { - log.Errorf("GetIStorageById %s: %s", id, err) - return nil, errors.Wrap(err, "GetIStorageById") - } - } - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIStorageById") -} - -func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - iHosts := make([]cloudprovider.ICloudHost, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, errors.Wrap(err, "GetIZones") - } - for i := 0; i < len(izones); i += 1 { - iZoneHost, err := izones[i].GetIHosts() - if err != nil { - return nil, errors.Wrap(err, "GetIHosts") - } - iHosts = append(iHosts, iZoneHost...) - } - return iHosts, nil -} - -func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, errors.Wrap(err, "GetIZones") - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, errors.Wrap(err, "GetIStorages") - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -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, errors.Wrap(cloudprovider.ErrNotFound, "GetIStoragecacheById") - -} - -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - tagspec := TagSpec{ResourceType: "vpc"} - if len(opts.NAME) > 0 { - tagspec.SetNameTag(opts.NAME) - } - - if len(opts.Desc) > 0 { - tagspec.SetDescTag(opts.Desc) - } - - spec, err := tagspec.GetTagSpecifications() - if err != nil { - return nil, errors.Wrap(err, "GetTagSpecifications") - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - // start create vpc - vpc, err := ec2Client.CreateVpc(&ec2.CreateVpcInput{CidrBlock: &opts.CIDR}) - if err != nil { - return nil, errors.Wrap(err, "CreateVpc") - } - - tagsParams := &ec2.CreateTagsInput{Resources: []*string{vpc.Vpc.VpcId}, Tags: spec.Tags} - _, err = ec2Client.CreateTags(tagsParams) - if err != nil { - log.Debugf("CreateIVpc add tag failed %s", err.Error()) - } - - err = self.fetchInfrastructure() - if err != nil { - return nil, errors.Wrap(err, "fetchInfrastructure") - } - return self.GetIVpcById(*vpc.Vpc.VpcId) -} - -func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { - eip, err := self.GetEip(id) - if err != nil { - return nil, errors.Wrap(err, "GetEip") - } - return eip, nil -} - -func (self *SRegion) GetProvider() string { - return CLOUD_PROVIDER_AWS -} - -func (self *SRegion) GetCloudEnv() string { - return self.client.accessUrl -} - -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, errors.Wrap(err, "GetIZones") - } - 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 { - desc := &cloudprovider.SManagedVMCreateConfig{ - Name: name, - ExternalImageId: imgId, - SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType}, - Cpu: cpu, - MemoryMB: memGB * 1024, - ExternalNetworkId: networkId, - DataDisks: []cloudprovider.SDiskInfo{}, - PublicKey: publicKey, - } - for _, sizeGB := range dataDiskSizesGB { - desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType}) - } - inst, err := z.getHost().CreateVM(desc) - if err != nil { - return nil, errors.Wrap(err, "CreateVM") - } - return inst.(*SInstance), nil - } - } - return nil, fmt.Errorf("cannot find vswitch %s", networkId) -} - -func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DescribeLoadBalancersInput{} - ret, err := client.DescribeLoadBalancers(params) - if err != nil { - return nil, errors.Wrap(err, "DescribeLoadBalancers") - } - - result := make([]SElb, 0) - err = unmarshalAwsOutput(ret, "LoadBalancers", &result) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.LoadBalancers") - } - - ielbs := make([]cloudprovider.ICloudLoadbalancer, len(result)) - for i := range result { - result[i].region = self - ielbs[i] = &result[i] - } - - return ielbs, nil -} - -func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DescribeLoadBalancersInput{} - params.SetLoadBalancerArns([]*string{&loadbalancerId}) - ret, err := client.DescribeLoadBalancers(params) - if err != nil { - if strings.Contains(err.Error(), "LoadBalancerNotFound") { - return nil, cloudprovider.ErrNotFound - } - - return nil, errors.Wrap(err, "DescribeLoadBalancers") - } - - elbs := []SElb{} - err = unmarshalAwsOutput(ret, "LoadBalancers", &elbs) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.LoadBalancers") - } - - if len(elbs) == 1 { - elbs[0].region = self - return &elbs[0], nil - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerById") -} - -func (self *SRegion) getElbAttributesById(loadbalancerId string) (map[string]string, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.DescribeLoadBalancerAttributesInput{} - params.SetLoadBalancerArn(loadbalancerId) - output, err := client.DescribeLoadBalancerAttributes(params) - if err != nil { - return nil, errors.Wrap(err, "DescribeLoadBalancerAttributes") - } - - attrs := []map[string]string{} - err = unmarshalAwsOutput(output, "Attributes", &attrs) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.Attributes") - } - - ret := map[string]string{} - for i := range attrs { - for k, v := range attrs[i] { - ret[k] = v - } - } - - return ret, nil -} - -func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - certs, err := self.GetILoadBalancerCertificates() - if err != nil { - return nil, errors.Wrap(err, "GetILoadBalancerCertificates") - } - - for i := range certs { - if certs[i].GetId() == certId { - return certs[i], nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerCertificateById") -} - -func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - client, err := self.getIamClient() - if err != nil { - return nil, errors.Wrap(err, "region.CreateILoadBalancerCertificate.getIamClient") - } - - params := &iam.UploadServerCertificateInput{} - params.SetServerCertificateName(cert.Name) - params.SetPrivateKey(cert.PrivateKey) - params.SetCertificateBody(cert.Certificate) - ret, err := client.UploadServerCertificate(params) - if err != nil { - return nil, errors.Wrap(err, "region.CreateILoadBalancerCertificate.UploadServerCertificate") - } - - // wait upload cert success - err = cloudprovider.Wait(5*time.Second, 30*time.Second, func() (bool, error) { - _, err := self.GetILoadBalancerCertificateById(*ret.ServerCertificateMetadata.Arn) - if err == nil { - return true, nil - } - - if errors.Cause(err) == cloudprovider.ErrNotFound { - return false, nil - } else { - return false, err - } - }) - if err != nil { - return nil, errors.Wrap(err, "region.CreateILoadBalancerCertificate.Wait") - } - - return self.GetILoadBalancerCertificateById(*ret.ServerCertificateMetadata.Arn) -} - -func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - client, err := self.getIamClient() - if err != nil { - return nil, errors.Wrap(err, "getIamClient") - } - - params := &iam.ListServerCertificatesInput{} - ret, err := client.ListServerCertificates(params) - if err != nil { - return nil, errors.Wrap(err, "ListServerCertificates") - } - - certs := []SElbCertificate{} - err = unmarshalAwsOutput(ret, "ServerCertificateMetadataList", &certs) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.ServerCertificateMetadataList") - } - - icerts := make([]cloudprovider.ICloudLoadbalancerCertificate, len(certs)) - for i := range certs { - certs[i].region = self - icerts[i] = &certs[i] - } - - return icerts, nil -} - -func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - client, err := self.GetElbV2Client() - if err != nil { - return nil, errors.Wrap(err, "GetElbV2Client") - } - - params := &elbv2.CreateLoadBalancerInput{} - params.SetName(loadbalancer.Name) - params.SetType(loadbalancer.LoadbalancerSpec) - params.SetIpAddressType("ipv4") - if loadbalancer.AddressType == api.LB_ADDR_TYPE_INTERNET { - params.SetScheme("internet-facing") - } else { - params.SetScheme("internal") - } - - // params.SetSecurityGroups() - params.SetSubnets(ConvertedList(loadbalancer.NetworkIDs)) - - tagInput := []*elbv2.Tag{} - keys := []string{} - values := []string{} - for k, v := range loadbalancer.Tags { - keys = append(keys, k) - values = append(values, v) - } - for i := range keys { - tagInput = append(tagInput, &elbv2.Tag{ - Key: &keys[i], - Value: &values[i], - }) - } - if len(loadbalancer.Tags) > 0 { - params.SetTags(tagInput) - } - - ret, err := client.CreateLoadBalancer(params) - if err != nil { - return nil, errors.Wrap(err, "CreateLoadBalancer") - } - - elbs := []SElb{} - err = unmarshalAwsOutput(ret, "LoadBalancers", &elbs) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput.LoadBalancers") - } - - if len(elbs) == 1 { - elbs[0].region = self - return &elbs[0], nil - } - - return nil, fmt.Errorf("CreateILoadBalancer error %#v", elbs) -} - -func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - iBuckets, err := region.client.getIBuckets() - if err != nil { - return nil, errors.Wrap(err, "getIBuckets") - } - ret := make([]cloudprovider.ICloudBucket, 0) - for i := range iBuckets { - if iBuckets[i].GetLocation() != region.GetId() { - continue - } - ret = append(ret, iBuckets[i]) - } - return ret, nil -} - -func (region *SRegion) CreateIBucket(name string, storageClassStr string, acl string) error { - s3cli, err := region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - input := &s3.CreateBucketInput{} - input.SetBucket(name) - if region.GetId() != DEFAULT_S3_REGION_ID { - location := region.GetId() - input.CreateBucketConfiguration = &s3.CreateBucketConfiguration{} - input.CreateBucketConfiguration.SetLocationConstraint(location) - } - _, err = s3cli.CreateBucket(input) - if err != nil { - return errors.Wrap(err, "CreateBucket") - } - region.client.invalidateIBuckets() - // if *output.Location != region.GetId() { - // log.Warningf("Request location %s != got locaiton %s", region.GetId(), *output.Location) - // } - return nil -} - -func (region *SRegion) DeleteIBucket(name string) error { - s3cli, err := region.GetS3Client() - if err != nil { - return errors.Wrap(err, "GetS3Client") - } - input := &s3.DeleteBucketInput{} - input.Bucket = &name - _, err = s3cli.DeleteBucket(input) - if err != nil { - if region.client.debug { - log.Debugf("%#v %s", err, err) - } - if strings.Index(err.Error(), "NoSuchBucket:") >= 0 { - return nil - } - return errors.Wrap(err, "DeleteBucket") - } - region.client.invalidateIBuckets() - return nil -} - -func (region *SRegion) IBucketExist(name string) (bool, error) { - s3cli, err := region.GetS3Client() - if err != nil { - return false, errors.Wrap(err, "GetS3Client") - } - input := &s3.HeadBucketInput{} - input.Bucket = &name - _, err = s3cli.HeadBucket(input) - if err != nil { - if region.client.debug { - log.Debugf("%#v %s", err, err) - } - if strings.Index(err.Error(), "NotFound:") >= 0 { - return false, nil - } - return false, errors.Wrap(err, "IsBucketExist") - } - return true, nil -} - -func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { - return cloudprovider.GetIBucketById(region, name) -} - -func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { - return region.GetIBucketById(name) -} - -func (region *SRegion) getBaseEndpoint() string { - if len(region.RegionEndpoint) > 4 { - return region.RegionEndpoint[4:] - } - return "" -} - -func (region *SRegion) getS3Endpoint() string { - base := region.getBaseEndpoint() - if len(base) > 0 { - return "s3." + base - } - return "" -} - -func (region *SRegion) getS3WebsiteEndpoint() string { - base := region.getBaseEndpoint() - if len(base) > 0 { - return "s3-website." + base - } - return "" -} - -func (region *SRegion) getEc2Endpoint() string { - return region.RegionEndpoint -} - -func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - backendgroups, err := self.GetElbBackendgroups("", nil) - if err != nil { - return nil, errors.Wrap(err, "GetElbBackendgroups") - } - - ret := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(backendgroups)) - for i := range backendgroups { - ret[i] = &backendgroups[i] - } - - return ret, nil -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, total, err := self.GetSecurityGroups("", "", secgroupId, 0, 1) - if err != nil { - return nil, errors.Wrap(err, "GetSecurityGroups") - } - if total == 0 { - return nil, cloudprovider.ErrNotFound - } - if total > 1 { - return nil, cloudprovider.ErrDuplicateId - } - return &secgroups[0], nil -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, total, err := self.GetSecurityGroups(opts.VpcId, opts.Name, "", 0, 1) - if err != nil { - return nil, errors.Wrap(err, "GetSecurityGroups") - } - if total == 0 { - return nil, cloudprovider.ErrNotFound - } - if total > 1 { - return nil, cloudprovider.ErrDuplicateId - } - return &secgroups[0], nil -} - -func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - groupId, err := self.CreateSecurityGroup(conf.VpcId, conf.Name, "", conf.Desc) - if err != nil { - return nil, errors.Wrap(err, "CreateSecurityGroup") - } - return self.GetISecurityGroupById(groupId) -} - -func (region *SRegion) GetCapabilities() []string { - return region.client.GetCapabilities() -} - -func (region *SRegion) CreateInternetGateway() (cloudprovider.ICloudInternetGateway, error) { - ec2Client, err := region.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - input := ec2.CreateInternetGatewayInput{} - output, err := ec2Client.CreateInternetGateway(&input) - if err != nil { - return nil, errors.Wrap(err, "CreateInternetGateway") - } - - ret := &SInternetGateway{} - ret.region = region - err = unmarshalAwsOutput(output, "InternetGateway", ret) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput") - } - - return ret, nil -} diff --git a/pkg/multicloud/aws/resource_tag.go b/pkg/multicloud/aws/resource_tag.go deleted file mode 100644 index 485668fdad..0000000000 --- a/pkg/multicloud/aws/resource_tag.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "strings" - - "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -func (self *SRegion) TagResources(arns []string, tags map[string]string) error { - if len(tags) == 0 { - return nil - } - client, err := self.getResourceGroupTagClient() - if err != nil { - return errors.Wrap(err, "self.getResourceGroupTagClient()") - } - params := resourcegroupstaggingapi.TagResourcesInput{} - arnInput := []*string{} - for i := range arns { - arnInput = append(arnInput, &arns[i]) - } - tagsInput := make(map[string]*string) - tagValues := []string{} - for k, v := range tags { - tagValues = append(tagValues, v) - tagsInput[k] = &tagValues[len(tagValues)-1] - } - params.SetResourceARNList(arnInput) - params.SetTags(tagsInput) - out, err := client.TagResources(¶ms) - if err != nil { - return errors.Wrapf(err, "client.TagResources(%s)", jsonutils.Marshal(params).String()) - } - if out != nil && len(out.FailedResourcesMap) > 0 { - return errors.Wrapf(cloudprovider.ErrNotSupported, "client.TagResources(%s),error:%s", jsonutils.Marshal(params).String(), jsonutils.Marshal(out).String()) - } - return nil -} - -func (self *SRegion) UntagResources(arns []string, tagKeys []string) error { - if len(tagKeys) == 0 { - return nil - } - client, err := self.getResourceGroupTagClient() - if err != nil { - return errors.Wrap(err, "self.getResourceGroupTagClient()") - } - params := resourcegroupstaggingapi.UntagResourcesInput{} - arnInput := []*string{} - for i := range arns { - arnInput = append(arnInput, &arns[i]) - } - delTagKeysInput := []*string{} - for i := range tagKeys { - delTagKeysInput = append(delTagKeysInput, &tagKeys[i]) - } - params.SetResourceARNList(arnInput) - params.SetTagKeys(delTagKeysInput) - out, err := client.UntagResources(¶ms) - if err != nil { - return errors.Wrapf(err, "client.UntagResources(%s)", jsonutils.Marshal(params).String()) - } - if out != nil && len(out.FailedResourcesMap) > 0 { - return errors.Wrapf(cloudprovider.ErrNotSupported, "client.UntagResources(%s),error:%s", jsonutils.Marshal(params).String(), jsonutils.Marshal(out).String()) - } - return nil -} - -func (self *SRegion) UpdateResourceTags(arn string, oldTags, tags map[string]string, replace bool) error { - addTags := map[string]string{} - for k, v := range tags { - if strings.HasPrefix(k, "aws:") { - return errors.Wrap(cloudprovider.ErrNotSupported, "The aws: prefix is reserved for AWS use") - } - if _, ok := oldTags[k]; !ok { - addTags[k] = v - } else { - if oldTags[k] != v { - addTags[k] = v - } - } - } - delTags := []string{} - if replace { - for k := range oldTags { - if _, ok := tags[k]; !ok { - if !strings.HasPrefix(k, "aws:") { - delTags = append(delTags, k) - } - } - } - } - err := self.UntagResources([]string{arn}, delTags) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.UntagResources([]string{%s}, %s)", arn, jsonutils.Marshal(delTags).String()) - } - err = self.TagResources([]string{arn}, addTags) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.TagResources([]string{%s}, %s)", arn, jsonutils.Marshal(addTags).String()) - } - return nil -} diff --git a/pkg/multicloud/aws/routetable.go b/pkg/multicloud/aws/routetable.go deleted file mode 100644 index 57d62b5df5..0000000000 --- a/pkg/multicloud/aws/routetable.go +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "strings" - - "github.com/aws/aws-sdk-go/service/ec2" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRouteTable struct { - multicloud.SResourceBase - multicloud.AwsTags - region *SRegion - vpc *SVpc - - Associations []Association `json:"Associations"` - PropagatingVgws []string `json:"PropagatingVgws"` - RouteTableID string `json:"RouteTableId"` - Routes []SRoute `json:"Routes"` - VpcID string `json:"VpcId"` - OwnerID string `json:"OwnerId"` -} - -type Association struct { - Main bool `json:"Main"` - RouteTableAssociationID string `json:"RouteTableAssociationId"` - RouteTableID string `json:"RouteTableId"` - GatewayID *string `json:"GatewayId,omitempty"` - SubnetID *string `json:"SubnetId,omitempty"` -} - -func (self *SRouteTable) GetId() string { - return self.RouteTableID -} - -func (self *SRouteTable) GetName() string { - return "" -} - -func (self *SRouteTable) GetGlobalId() string { - return self.GetId() -} - -func (self *SRouteTable) GetStatus() string { - return api.ROUTE_TABLE_AVAILABLE -} - -func (self *SRouteTable) Refresh() error { - ret, err := self.region.GetRouteTable(self.GetId()) - if err != nil { - return errors.Wrap(err, "SRouteTable.Refresh.GetRouteTable") - } - - err = jsonutils.Update(self, ret) - if err != nil { - return errors.Wrap(err, "SRouteTable.Refresh.Update") - } - - return nil -} - -func (self *SRouteTable) IsEmulated() bool { - return false -} - -func (self *SRouteTable) GetDescription() string { - return "" -} - -func (self *SRouteTable) GetRegionId() string { - return self.region.GetId() -} - -func (self *SRouteTable) GetVpcId() string { - return self.VpcID -} - -func (self *SRouteTable) GetType() cloudprovider.RouteTableType { - for i := range self.Associations { - if self.Associations[i].Main { - return cloudprovider.RouteTableTypeSystem - } - } - return cloudprovider.RouteTableTypeCustom -} - -func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { - result := []cloudprovider.RouteTableAssociation{} - for i := range self.Associations { - if self.Associations[i].GatewayID != nil { - association := cloudprovider.RouteTableAssociation{ - AssociationId: self.Associations[i].RouteTableAssociationID, - AssociationType: cloudprovider.RouteTableAssociaToRouter, - AssociatedResourceId: *self.Associations[i].GatewayID, - } - result = append(result, association) - } - if self.Associations[i].SubnetID != nil { - association := cloudprovider.RouteTableAssociation{ - AssociationId: self.Associations[i].RouteTableAssociationID, - AssociationType: cloudprovider.RouteTableAssociaToSubnet, - AssociatedResourceId: *self.Associations[i].SubnetID, - } - result = append(result, association) - } - } - return result -} - -func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { - err := self.region.CreateRoute(self.RouteTableID, route.Destination, route.NextHop) - if err != nil { - return errors.Wrapf(err, "self.region.CreateRoute(%s,%s,%s)", self.RouteTableID, route.Destination, route.NextHop) - } - return nil -} - -func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { - routeInfo := strings.Split(route.RouteId, ":") - if len(routeInfo) != 2 { - return errors.Wrap(cloudprovider.ErrNotSupported, "invalid route info") - } - err := self.region.RemoveRoute(self.RouteTableID, routeInfo[0]) - if err != nil { - return errors.Wrapf(err, "self.region.RemoveRoute(%s,%s)", self.RouteTableID, route.Destination) - } - - err = self.CreateRoute(route) - if err != nil { - return errors.Wrapf(err, "self.CreateRoute(%s)", jsonutils.Marshal(route).String()) - } - return nil -} - -func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { - err := self.region.RemoveRoute(self.RouteTableID, route.Destination) - if err != nil { - return errors.Wrapf(err, "self.region.RemoveRoute(%s,%s)", self.RouteTableID, route.Destination) - } - return nil -} - -func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { - iroutes := make([]cloudprovider.ICloudRoute, len(self.Routes)) - for i := range self.Routes { - self.Routes[i].routetable = self - iroutes[i] = &self.Routes[i] - } - - return iroutes, nil -} - -func (self *SRegion) GetRouteTables(vpcId string, mainRouteOnly bool) ([]SRouteTable, error) { - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - input := &ec2.DescribeRouteTablesInput{} - filters := make([]*ec2.Filter, 0) - filters = AppendSingleValueFilter(filters, "vpc-id", vpcId) - if mainRouteOnly { - filters = AppendSingleValueFilter(filters, "association.main", "true") - } - - input.SetFilters(filters) - - ret, err := ec2Client.DescribeRouteTables(input) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetRouteTables.DescribeRouteTables") - } - - routeTables := make([]SRouteTable, len(ret.RouteTables)) - err = unmarshalAwsOutput(ret, "RouteTables", routeTables) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetRouteTables.unmarshalAwsOutput") - } - - for i := range routeTables { - routeTables[i].region = self - } - - return routeTables, nil -} - -func (self *SRegion) CreateRoute(routeTableId string, DestinationCIDRBlock string, targetId string) error { - input := &ec2.CreateRouteInput{} - input.RouteTableId = &routeTableId - input.DestinationCidrBlock = &DestinationCIDRBlock - segs := strings.Split(targetId, "-") - if len(segs) == 0 { - return fmt.Errorf("invalid aws vpc targetid:%s", targetId) - } - switch segs[0] { - case "i": - input.InstanceId = &targetId - case "igw", "vgw": - input.GatewayId = &targetId - case "pcx": - input.VpcPeeringConnectionId = &targetId - case "eni": - input.NetworkInterfaceId = &targetId - case "nat": - input.NatGatewayId = &targetId - case "eigw": - input.EgressOnlyInternetGatewayId = &targetId - default: - return fmt.Errorf("invalid aws vpc targetid:%s", targetId) - } - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.CreateRoute(input) - if err != nil { - return errors.Wrapf(err, "self.ec2Client.CreateRoute(%s)", jsonutils.Marshal(input).String()) - } - return nil -} - -func (self *SRegion) ReplaceRoute(routeTableId string, DestinationCIDRBlock string, targetId string) error { - input := &ec2.ReplaceRouteInput{} - input.RouteTableId = &routeTableId - input.DestinationCidrBlock = &DestinationCIDRBlock - segs := strings.Split(targetId, "-") - if len(segs) == 0 { - return fmt.Errorf("invalid aws vpc targetid:%s", targetId) - } - switch segs[0] { - case "i": - input.InstanceId = &targetId - case "igw", "vgw": - input.GatewayId = &targetId - case "pcx": - input.VpcPeeringConnectionId = &targetId - case "eni": - input.NetworkInterfaceId = &targetId - case "nat": - input.NatGatewayId = &targetId - case "eigw": - input.EgressOnlyInternetGatewayId = &targetId - default: - return fmt.Errorf("invalid aws vpc targetid:%s", targetId) - } - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.ReplaceRoute(input) - if err != nil { - return errors.Wrapf(err, "self.ec2Client.ReplaceRouteInput(%s)", jsonutils.Marshal(input).String()) - } - return nil -} - -func (self *SRegion) RemoveRoute(routeTableId string, DestinationCIDRBlock string) error { - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - input := &ec2.DeleteRouteInput{} - input.RouteTableId = &routeTableId - input.DestinationCidrBlock = &DestinationCIDRBlock - _, err = ec2Client.DeleteRoute(input) - if err != nil { - return errors.Wrapf(err, "self.ec2Client.DeleteRoute(%s)", jsonutils.Marshal(input).String()) - } - return nil -} - -func (self *SRegion) GetRouteTablesByNetworkId(netId string) ([]SRouteTable, error) { - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - input := &ec2.DescribeRouteTablesInput{} - filter := &ec2.Filter{} - filter.SetName("association.subnet-id") - filter.SetValues([]*string{&netId}) - input.SetFilters([]*ec2.Filter{filter}) - - ret, err := ec2Client.DescribeRouteTables(input) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetRouteTables.DescribeRouteTables") - } - - routeTables := make([]SRouteTable, len(ret.RouteTables)) - err = unmarshalAwsOutput(ret, "RouteTables", routeTables) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetRouteTables.unmarshalAwsOutput") - } - - for i := range routeTables { - routeTables[i].region = self - } - - return routeTables, nil -} - -func (self *SRegion) GetRouteTable(id string) (*SRouteTable, error) { - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - input := &ec2.DescribeRouteTablesInput{} - input.RouteTableIds = []*string{&id} - ret, err := ec2Client.DescribeRouteTables(input) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetRouteTables.DescribeRouteTables") - } - - routeTables := make([]SRouteTable, len(ret.RouteTables)) - err = unmarshalAwsOutput(ret, "RouteTables", routeTables) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetRouteTables.unmarshalAwsOutput") - } - - if len(routeTables) == 1 { - routeTables[0].region = self - return &routeTables[0], nil - } else if len(routeTables) == 0 { - return nil, errors.ErrNotFound - } else { - return nil, errors.ErrDuplicateId - } -} - -func (self *SRegion) DeleteRouteTable(rid string) error { - input := &ec2.DeleteRouteTableInput{} - input.SetRouteTableId(rid) - - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.DeleteRouteTable(input) - if err != nil { - return errors.Wrap(err, "DeleteRouteTable") - } - - return nil -} diff --git a/pkg/multicloud/aws/s3object.go b/pkg/multicloud/aws/s3object.go deleted file mode 100644 index 19b4ba86d4..0000000000 --- a/pkg/multicloud/aws/s3object.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "net/http" - - "github.com/aws/aws-sdk-go/service/s3" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SObject struct { - bucket *SBucket - - cloudprovider.SBaseCloudObject -} - -func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { - return o.bucket -} - -func (o *SObject) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - s3cli, err := o.bucket.region.GetS3Client() - if err != nil { - log.Errorf("o.bucket.region.GetS3Client error %s", err) - return acl - } - input := &s3.GetObjectAclInput{} - input.SetBucket(o.bucket.Name) - input.SetKey(o.Key) - output, err := s3cli.GetObjectAcl(input) - if err != nil { - log.Errorf("s3cli.GetObjectAcl error %s", err) - return acl - } - return s3ToCannedAcl(output.Grants) -} - -func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { - s3cli, err := o.bucket.region.GetS3Client() - if err != nil { - return errors.Wrap(err, "o.bucket.region.GetS3Client") - } - input := &s3.PutObjectAclInput{} - input.SetBucket(o.bucket.Name) - input.SetKey(o.Key) - input.SetACL(string(aclStr)) - _, err = s3cli.PutObjectAcl(input) - if err != nil { - return errors.Wrap(err, "s3cli.PutObjectAcl") - } - return nil -} - -func (o *SObject) GetMeta() http.Header { - if o.Meta != nil { - return o.Meta - } - s3cli, err := o.bucket.region.GetS3Client() - if err != nil { - log.Errorf("o.bucket.region.GetS3Client fail %s", err) - return nil - } - input := &s3.HeadObjectInput{} - input.SetBucket(o.bucket.Name) - input.SetKey(o.Key) - output, err := s3cli.HeadObject(input) - if err != nil { - log.Errorf("s3cli.HeadObject fail %s", err) - return nil - } - ret := http.Header{} - for k, v := range output.Metadata { - if v != nil && len(*v) > 0 { - ret.Add(k, *v) - } - } - if output.CacheControl != nil && len(*output.CacheControl) > 0 { - ret.Set(cloudprovider.META_HEADER_CACHE_CONTROL, *output.CacheControl) - } - if output.ContentType != nil && len(*output.ContentType) > 0 { - ret.Set(cloudprovider.META_HEADER_CONTENT_TYPE, *output.ContentType) - } - if output.ContentDisposition != nil && len(*output.ContentDisposition) > 0 { - ret.Set(cloudprovider.META_HEADER_CONTENT_DISPOSITION, *output.ContentDisposition) - } - if output.ContentEncoding != nil && len(*output.ContentEncoding) > 0 { - ret.Set(cloudprovider.META_HEADER_CONTENT_ENCODING, *output.ContentEncoding) - } - if output.ContentLanguage != nil && len(*output.ContentLanguage) > 0 { - ret.Set(cloudprovider.META_HEADER_CONTENT_LANGUAGE, *output.ContentLanguage) - } - return ret -} - -func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { - return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) -} diff --git a/pkg/multicloud/aws/saml_provider.go b/pkg/multicloud/aws/saml_provider.go deleted file mode 100644 index 1d9ec53a23..0000000000 --- a/pkg/multicloud/aws/saml_provider.go +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "strings" - "time" - "unicode" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis/cloudid" - api "yunion.io/x/onecloud/pkg/apis/cloudid" - compute_api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudid/options" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/httputils" - "yunion.io/x/onecloud/pkg/util/samlutils" -) - -type SAMLProvider struct { - multicloud.SResourceBase - multicloud.AwsTags - client *SAwsClient - - SAMLMetadataDocument string `xml:"SAMLMetadataDocument"` - Arn string `xml:"Arn"` - ValidUntil time.Time `xml:"ValidUntil"` - CreateDate time.Time `xml:"CreateDate"` -} - -func (self *SAMLProvider) GetGlobalId() string { - return self.Arn -} - -func (self *SAMLProvider) GetId() string { - return self.Arn -} - -func (self *SAMLProvider) GetName() string { - if info := strings.Split(self.Arn, "/"); len(info) > 0 { - return info[len(info)-1] - } - return self.Arn -} - -func (self *SAMLProvider) GetStatus() string { - return api.SAML_PROVIDER_STATUS_AVAILABLE -} - -func (self *SAMLProvider) Delete() error { - return self.client.DeleteSAMLProvider(self.Arn) -} - -func (self *SAMLProvider) GetAuthUrl() string { - input := samlutils.SIdpInitiatedLoginInput{ - EntityID: cloudprovider.SAML_ENTITY_ID_AWS_CN, - IdpId: self.client.cpcfg.AccountId, - } - if self.client.GetAccessEnv() == compute_api.CLOUD_ACCESS_ENV_AWS_GLOBAL { - input.EntityID = cloudprovider.SAML_ENTITY_ID_AWS - } - return httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, fmt.Sprintf("sso?%s", jsonutils.Marshal(input).QueryString())) -} - -func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { - saml, err := self.client.GetSAMLProvider(self.Arn) - if err != nil { - return nil, errors.Wrapf(err, "GetSAMLProvider(%s)", self.Arn) - } - metadata, err := samlutils.ParseMetadata([]byte(saml.SAMLMetadataDocument)) - if err != nil { - return nil, errors.Wrapf(err, "ParseMetadata") - } - return &metadata, nil -} - -func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { - _, err := self.client.UpdateSAMLProvider(self.Arn, metadata.String()) - return err -} - -type SAMLProviders struct { - SAMLProviderList []SAMLProvider `xml:"SAMLProviderList>member"` -} - -func (self *SAwsClient) ListSAMLProviders() ([]SAMLProvider, error) { - result := SAMLProviders{} - err := self.iamRequest("ListSAMLProviders", nil, &result) - if err != nil { - return nil, errors.Wrapf(err, "ListSAMLProviders") - } - return result.SAMLProviderList, nil -} - -func (self *SAwsClient) GetSAMLProvider(arn string) (*SAMLProvider, error) { - result := &SAMLProvider{client: self, Arn: arn} - params := map[string]string{"SAMLProviderArn": arn} - err := self.iamRequest("GetSAMLProvider", params, result) - if err != nil { - return nil, errors.Wrapf(err, "GetSAMLProvider") - } - return result, nil -} - -func (self *SAwsClient) DeleteSAMLProvider(arn string) error { - params := map[string]string{"SAMLProviderArn": arn} - return self.iamRequest("DeleteSAMLProvider", params, nil) -} - -func (self *SAwsClient) CreateSAMLProvider(name, metadata string) (*SAMLProvider, error) { - name = func() string { - ret := "" - for _, s := range name { - if unicode.IsLetter(s) || unicode.IsNumber(s) || s == '.' || s == '_' || s == '-' { - ret += string(s) - } else { - ret += "-" - } - } - if len(ret) > 128 { - ret = ret[:128] - } - return ret - }() - params := map[string]string{ - "Name": name, - "SAMLMetadataDocument": metadata, - } - result := struct { - SAMLProviderArn string `xml:"SAMLProviderArn"` - }{} - err := self.iamRequest("CreateSAMLProvider", params, &result) - if err != nil { - return nil, errors.Wrapf(err, "CreateSAMLProvider") - } - return self.GetSAMLProvider(result.SAMLProviderArn) -} - -func (self *SAwsClient) UpdateSAMLProvider(arn, metadata string) (*SAMLProvider, error) { - params := map[string]string{ - "SAMLProviderArn": arn, - "SAMLMetadataDocument": metadata, - } - saml := &SAMLProvider{client: self} - err := self.iamRequest("UpdateSAMLProvider", params, saml) - if err != nil { - return nil, errors.Wrapf(err, "UpdateSAMLProvider") - } - return saml, nil -} - -func (self *SAwsClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { - providers, err := self.ListSAMLProviders() - if err != nil { - return nil, errors.Wrapf(err, "ListSAMLProviders") - } - ret := []cloudprovider.ICloudSAMLProvider{} - for i := range providers { - providers[i].client = self - ret = append(ret, &providers[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/aws/securitygroup.go b/pkg/multicloud/aws/securitygroup.go deleted file mode 100644 index e7e077b548..0000000000 --- a/pkg/multicloud/aws/securitygroup.go +++ /dev/null @@ -1,491 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "math/rand" - "strings" - "time" - - "github.com/aws/aws-sdk-go/service/ec2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.AwsTags - vpc *SVpc - - RegionId string - VpcId string - SecurityGroupId string - Description string - SecurityGroupName string - Permissions []cloudprovider.SecurityRule - - // CreationTime time.Time - // InnerAccessPolicy string -} - -func randomString(prefix string, length int) string { - bytes := []byte("0123456789abcdefghijklmnopqrstuvwxyz") - result := []byte{} - r := rand.New(rand.NewSource(time.Now().UnixNano())) - for i := 0; i < length; i++ { - result = append(result, bytes[r.Intn(len(bytes))]) - } - return prefix + string(result) -} - -func (self *SSecurityGroup) GetId() string { - return self.SecurityGroupId -} - -func (self *SSecurityGroup) GetVpcId() string { - return self.VpcId -} - -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) GetDescription() string { - return self.Description -} - -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) - if err != nil { - return nil, errors.Wrap(err, "GetSecurityGroupDetails") - } - return secgrp.Permissions, nil -} - -func (self *SRegion) addSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error { - if len(rule.Ports) != 0 { - for _, port := range rule.Ports { - rule.PortStart, rule.PortEnd = port, port - err := self.addSecurityGroupRule(secGrpId, rule) - if err != nil { - return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", rule.Priority, rule.String()) - } - } - return nil - } - return self.addSecurityGroupRule(secGrpId, rule) -} - -func (self *SRegion) addSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - 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 = ec2Client.AuthorizeSecurityGroupIngress(params) - } - - if rule.Direction == secrules.SecurityRuleEgress { - params := &ec2.AuthorizeSecurityGroupEgressInput{} - params.SetGroupId(secGrpId) - params.SetIpPermissions(ipPermissions) - _, err = ec2Client.AuthorizeSecurityGroupEgress(params) - } - - if err != nil && strings.Contains(err.Error(), "InvalidPermission.Duplicate") { - log.Debugf("addSecurityGroupRule %s %s", rule.Direction, err.Error()) - return nil - } - - return err -} - -func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - ipPermissions, err := YunionSecRuleToAws(rule) - if err != nil { - return err - } - - if rule.Direction == secrules.SecurityRuleIngress { - params := &ec2.RevokeSecurityGroupIngressInput{} - params.SetGroupId(secGrpId) - params.SetIpPermissions(ipPermissions) - _, err = ec2Client.RevokeSecurityGroupIngress(params) - } - - if rule.Direction == secrules.SecurityRuleEgress { - params := &ec2.RevokeSecurityGroupEgressInput{} - params.SetGroupId(secGrpId) - params.SetIpPermissions(ipPermissions) - _, err = ec2Client.RevokeSecurityGroupEgress(params) - } - - if err != nil { - log.Debugf("delSecurityGroupRule %s %s", rule.Direction, err.Error()) - return err - } - return nil -} - -func (self *SRegion) updateSecurityGroupRuleDescription(secGrpId string, rule cloudprovider.SecurityRule) error { - ipPermissions, err := YunionSecRuleToAws(rule) - if err != nil { - return err - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - if rule.Direction == secrules.SecurityRuleIngress { - params := &ec2.UpdateSecurityGroupRuleDescriptionsIngressInput{} - params.SetGroupId(secGrpId) - params.SetIpPermissions(ipPermissions) - ret, err := 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 := 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) { - ec2Client, err := self.getEc2Client() - if err != nil { - return "", errors.Wrap(err, "getEc2Client") - } - - params := &ec2.CreateSecurityGroupInput{} - params.SetVpcId(vpcId) - // 这里的描述aws 上层代码拼接的描述。并非用户提交的描述,用户描述放置在Yunion本地数据库中。) - if len(desc) == 0 { - desc = "vpc default group" - } - params.SetDescription(desc) - if strings.ToLower(name) == "default" { - name = randomString(fmt.Sprintf("%s-", vpcId), 9) - } - params.SetGroupName(name) - - group, err := ec2Client.CreateSecurityGroup(params) - if err != nil { - return "", err - } - - tagspec := TagSpec{ResourceType: "security-group"} - if len(secgroupIdTag) > 0 { - tagspec.SetTag("id", secgroupIdTag) - } - tagspec.SetNameTag(name) - tagspec.SetDescTag(desc) - tags, _ := tagspec.GetTagSpecifications() - tagParams := &ec2.CreateTagsInput{} - tagParams.SetResources([]*string{group.GroupId}) - tagParams.SetTags(tags.Tags) - _, err = ec2Client.CreateTags(tagParams) - if err != nil { - return "", err - } - - return *group.GroupId, nil -} - -func (self *SRegion) createDefaultSecurityGroup(vpcId string) (string, error) { - name := randomString(fmt.Sprintf("%s-", vpcId), 9) - secId, err := self.CreateSecurityGroup(vpcId, name, "default", "vpc default group") - if err != nil { - return "", err - } - - rule := cloudprovider.SecurityRule{ - SecurityRule: 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) { - if len(secGroupId) == 0 { - return nil, fmt.Errorf("GetSecurityGroupDetails security group id should not be empty.") - } - params := &ec2.DescribeSecurityGroupsInput{} - params.SetGroupIds([]*string{&secGroupId}) - - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.DescribeSecurityGroups(params) - err = parseNotFoundError(err) - if err != nil { - return nil, errors.Wrap(err, "DescribeSecurityGroups") - } - - if len(ret.SecurityGroups) == 1 { - s := ret.SecurityGroups[0] - vpc, err := self.getVpc(*s.VpcId) - if err != nil { - return 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) getSecurityGroupById(vpcId, secgroupId string) (*SSecurityGroup, error) { - if len(secgroupId) == 0 { - return nil, httperrors.NewInputParameterError("security group id should not be empty") - } - - secgroups, total, err := self.GetSecurityGroups(vpcId, "", secgroupId, 0, 0) - if err != nil { - log.Errorf("GetSecurityGroups vpc %s secgroupId %s: %s", vpcId, secgroupId, err) - return nil, errors.Wrap(err, "GetSecurityGroups") - } - - 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}) - - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - _, err = ec2Client.CreateTags(params) - if err != nil { - return errors.Wrap(err, "CreateTags") - } - - return nil -} - -func (self *SRegion) getSecRules(ingress []*ec2.IpPermission, egress []*ec2.IpPermission) []cloudprovider.SecurityRule { - rules := []cloudprovider.SecurityRule{} - for _, p := range ingress { - ret, err := AwsIpPermissionToYunion(secrules.SecurityRuleIngress, *p) - if err != nil { - log.Debugln(err) - } - - for _, rule := range ret { - rules = append(rules, rule) - } - } - - for _, p := range egress { - ret, err := AwsIpPermissionToYunion(secrules.SecurityRuleEgress, *p) - if err != nil { - log.Debugln(err) - } - - for _, rule := range ret { - rules = append(rules, rule) - } - } - - return rules -} - -func (self *SRegion) GetSecurityGroups(vpcId string, name string, secgroupId 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(name) > 0 { - filters = AppendSingleValueFilter(filters, "group-name", name) - } - - if len(secgroupId) > 0 { - params.SetGroupIds([]*string{&secgroupId}) - } - - if len(filters) > 0 { - params.SetFilters(filters) - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, 0, errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.DescribeSecurityGroups(params) - err = parseNotFoundError(err) - 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 -} - -func (self *SSecurityGroup) GetProjectId() string { - return "" -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - for _, r := range append(inDels, outDels...) { - err := self.vpc.region.DelSecurityGroupRule(self.SecurityGroupId, r) - if err != nil { - if strings.Contains(err.Error(), "InvalidPermission.NotFound") { - continue - } - return errors.Wrapf(err, "delSecurityGroupRule %s %d %s", r.Name, r.Priority, r.String()) - } - } - - for _, r := range append(inAdds, outAdds...) { - err := self.vpc.region.addSecurityGroupRules(self.SecurityGroupId, r) - if err != nil { - return errors.Wrapf(err, "addSecurityGroupRules %d %s", r.Priority, r.String()) - } - } - return nil -} - -func (self *SSecurityGroup) Delete() error { - return self.vpc.region.DeleteSecurityGroup(self.SecurityGroupId) -} diff --git a/pkg/multicloud/aws/shell/bucket.go b/pkg/multicloud/aws/shell/bucket.go deleted file mode 100644 index f44f1c4081..0000000000 --- a/pkg/multicloud/aws/shell/bucket.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import "yunion.io/x/onecloud/pkg/multicloud/objectstore" - -func init() { - objectstore.S3Shell() -} diff --git a/pkg/multicloud/aws/shell/cloudtrail.go b/pkg/multicloud/aws/shell/cloudtrail.go deleted file mode 100644 index 645f8cae1e..0000000000 --- a/pkg/multicloud/aws/shell/cloudtrail.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "time" - - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EventListOptions struct { - Start time.Time - End time.Time - WithReadOnly bool - } - shellutils.R(&EventListOptions{}, "event-list", "List events", func(cli *aws.SRegion, args *EventListOptions) error { - events, err := cli.LookupEvents(args.Start, args.End, args.WithReadOnly) - if err != nil { - return err - } - printList(events, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/dbinstance.go b/pkg/multicloud/aws/shell/dbinstance.go deleted file mode 100644 index 98e9523782..0000000000 --- a/pkg/multicloud/aws/shell/dbinstance.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceListOptions struct { - Id string - Marker string - } - shellutils.R(&DBInstanceListOptions{}, "dbinstance-list", "List rds intances", func(cli *aws.SRegion, args *DBInstanceListOptions) error { - instances, _, err := cli.GetDBInstances(args.Id, args.Marker) - if err != nil { - return err - } - printList(instances, 0, 0, 0, []string{}) - return nil - }) - - type DBInstanceIdOptions struct { - ID string - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-show", "Show rds intance", func(cli *aws.SRegion, args *DBInstanceIdOptions) error { - instance, err := cli.GetDBInstance(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-tags-list", "Show rds intance tags", func(cli *aws.SRegion, args *DBInstanceIdOptions) error { - instance, err := cli.ListRdsResourceTags(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - -} diff --git a/pkg/multicloud/aws/shell/dbinstance_parameter.go b/pkg/multicloud/aws/shell/dbinstance_parameter.go deleted file mode 100644 index fec64d1bbb..0000000000 --- a/pkg/multicloud/aws/shell/dbinstance_parameter.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceParameterOptions struct { - NAME string - } - - shellutils.R(&DBInstanceParameterOptions{}, "dbinstance-parameter-show", "Show rds intance parameter", func(cli *aws.SRegion, args *DBInstanceParameterOptions) error { - parameters, err := cli.GetDBInstanceParameters(args.NAME) - if err != nil { - return err - } - printList(parameters, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/aws/shell/dbinstance_snapshot.go b/pkg/multicloud/aws/shell/dbinstance_snapshot.go deleted file mode 100644 index 8d63382999..0000000000 --- a/pkg/multicloud/aws/shell/dbinstance_snapshot.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceSnapshotListOptions struct { - DBInstanceId string - Id string - } - - shellutils.R(&DBInstanceSnapshotListOptions{}, "dbinstance-snapshot-list", "List rds intance snapshots", func(cli *aws.SRegion, args *DBInstanceSnapshotListOptions) error { - snapshots, err := cli.GetDBInstanceSnapshots(args.DBInstanceId, args.Id) - if err != nil { - return err - } - printList(snapshots, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/aws/shell/disk.go b/pkg/multicloud/aws/shell/disk.go deleted file mode 100644 index 70223b41b5..0000000000 --- a/pkg/multicloud/aws/shell/disk.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/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 { - ID string `help:"Disk ID"` - } - shellutils.R(&DiskDeleteOptions{}, "disk-delete", "List disks", func(cli *aws.SRegion, args *DiskDeleteOptions) error { - e := cli.DeleteDisk(args.ID) - if e != nil { - return e - } - return nil - }) - - type TestVolumeTypeAvailableOptions struct { - VOLUME_TYPE string `choices:"gp2|gp3|io1|io2|st1|sc1|standard"` - ZONE_ID string - } - - shellutils.R(&TestVolumeTypeAvailableOptions{}, "test-volume-type", "Test volume type is available", func(cli *aws.SRegion, args *TestVolumeTypeAvailableOptions) error { - ok, e := cli.TestStorageAvailable(args.ZONE_ID, args.VOLUME_TYPE) - if e != nil { - return e - } - fmt.Println(ok) - return nil - }) - -} diff --git a/pkg/multicloud/aws/shell/doc.go b/pkg/multicloud/aws/shell/doc.go deleted file mode 100644 index 4534ca1f80..0000000000 --- a/pkg/multicloud/aws/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/aws/shell" diff --git a/pkg/multicloud/aws/shell/eip.go b/pkg/multicloud/aws/shell/eip.go deleted file mode 100644 index 0b46266dfa..0000000000 --- a/pkg/multicloud/aws/shell/eip.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - Id string - Addr string - AssociateId string - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *aws.SRegion, args *EipListOptions) error { - eips, err := cli.GetEips(args.Id, args.Addr, args.AssociateId) - if err != nil { - return err - } - printList(eips, 0, 0, 0, []string{}) - return nil - }) - - type EipAllocateOptions struct { - Name string - } - shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *aws.SRegion, args *EipAllocateOptions) error { - opts := cloudprovider.SEip{Name: args.Name} - eip, err := cli.AllocateEIP(&opts) - 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 - }) - - type EipDissociateOptions struct { - INSTANCE string `help:"Instance ID"` - } - - shellutils.R(&EipDissociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *aws.SRegion, args *EipDissociateOptions) error { - err := cli.DissociateEip(args.INSTANCE) - return err - }) -} diff --git a/pkg/multicloud/aws/shell/elasticache.go b/pkg/multicloud/aws/shell/elasticache.go deleted file mode 100644 index e606d0c52d..0000000000 --- a/pkg/multicloud/aws/shell/elasticache.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElasticacheClusterListOption struct { - } - shellutils.R(&ElasticacheClusterListOption{}, "elasticacheCluster-list", "List elasticacheCluster", func(cli *aws.SRegion, args *ElasticacheClusterListOption) error { - clusters, e := cli.DescribeElasticacheClusters() - if e != nil { - return e - } - printList(clusters, len(clusters), 0, len(clusters), []string{}) - return nil - }) - - type ElasticacheReplicaGroupListOption struct { - Id string - } - shellutils.R(&ElasticacheReplicaGroupListOption{}, "elasticacheReplicaGroup-list", "List elasticaReplicaGroup", func(cli *aws.SRegion, args *ElasticacheReplicaGroupListOption) error { - clusters, e := cli.DescribeElasticacheReplicationGroups(args.Id) - if e != nil { - return e - } - printList(clusters, len(clusters), 0, len(clusters), []string{}) - return nil - }) - - type ElasticacheSubnetGroupOption struct { - Id string `help:"subnetgroupId"` - } - shellutils.R(&ElasticacheSubnetGroupOption{}, "elasticacheSubnetGroup-show", "List elasticacheSubnetGroup", func(cli *aws.SRegion, args *ElasticacheSubnetGroupOption) error { - subnetGroups, e := cli.DescribeCacheSubnetGroups(args.Id) - if e != nil { - return e - } - printList(subnetGroups, len(subnetGroups), 0, len(subnetGroups), []string{}) - return nil - }) - - type ElasticacheSnapshotOption struct { - ReplicaGroupId string `help:"replicaGroupId"` - SnapshotId string `help:"SnapshotId"` - } - shellutils.R(&ElasticacheSnapshotOption{}, "elasticacheSnapshot-list", "List elasticacheSnapshot", func(cli *aws.SRegion, args *ElasticacheSnapshotOption) error { - snapshots, e := cli.DescribeSnapshots(args.ReplicaGroupId, args.SnapshotId) - if e != nil { - return e - } - printList(snapshots, len(snapshots), 0, len(snapshots), []string{}) - return nil - }) - - type ElasticacheParameterOption struct { - ParameterGroupId string - } - shellutils.R(&ElasticacheParameterOption{}, "elasticacheParameter-list", "List elasticacheParameter", func(cli *aws.SRegion, args *ElasticacheParameterOption) error { - parameters, e := cli.DescribeCacheParameters(args.ParameterGroupId) - if e != nil { - return e - } - printList(parameters, len(parameters), 0, len(parameters), []string{}) - return nil - }) - - type ElasticacheUserOption struct { - Engine string `help:"redis"` - } - shellutils.R(&ElasticacheUserOption{}, "elasticacheUser-list", "List elasticacheUser", func(cli *aws.SRegion, args *ElasticacheUserOption) error { - users, e := cli.DescribeUsers(args.Engine) - if e != nil { - return e - } - printList(users, len(users), 0, len(users), []string{}) - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/hostedzone.go b/pkg/multicloud/aws/shell/hostedzone.go deleted file mode 100644 index 8730d081f0..0000000000 --- a/pkg/multicloud/aws/shell/hostedzone.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type Route53LocationListOptions struct{} - shellutils.R(&Route53LocationListOptions{}, "route53location-list", "List route53location", func(cli *aws.SRegion, args *Route53LocationListOptions) error { - locations, err := cli.GetClient().ListGeoLocations() - if err != nil { - return err - } - printList(locations, len(locations), 0, 20, []string{}) - return nil - }) - - type HostedZoneListOptions struct{} - shellutils.R(&HostedZoneListOptions{}, "hostedzone-list", "List hostedzone", func(cli *aws.SRegion, args *HostedZoneListOptions) error { - hostzones, err := cli.GetClient().GetHostedZones() - if err != nil { - return err - } - printList(hostzones, len(hostzones), 0, 20, []string{}) - return nil - }) - - type HostedZoneCreateOptions struct { - NAME string `help:"Domain name"` - Type string `choices:"PublicZone|PrivateZone"` - Vpc string `help:"vpc id"` - Region string `help:"region id"` - } - shellutils.R(&HostedZoneCreateOptions{}, "hostedzone-create", "Create hostedzone", func(cli *aws.SRegion, args *HostedZoneCreateOptions) error { - opts := cloudprovider.SDnsZoneCreateOptions{} - opts.Name = args.NAME - opts.ZoneType = cloudprovider.TDnsZoneType(args.Type) - if len(args.Vpc) > 0 && len(args.Region) > 0 { - vpc := cloudprovider.SPrivateZoneVpc{} - vpc.Id = args.Vpc - vpc.RegionId = args.Region - opts.Vpcs = []cloudprovider.SPrivateZoneVpc{vpc} - } - hostzones, err := cli.GetClient().CreateHostedZone(&opts) - if err != nil { - return err - } - printObject(hostzones) - return nil - }) - type HostedZoneGetOptions struct { - HOSTEDZONEID string - } - shellutils.R(&HostedZoneGetOptions{}, "hostedzone-show", "get hostedzone by id", func(cli *aws.SRegion, args *HostedZoneGetOptions) error { - - hostedzone, err := cli.GetClient().GetHostedZoneById(args.HOSTEDZONEID) - if err != nil { - return err - } - printObject(hostedzone) - return nil - }) - - type HostedZoneVpcListOptions struct { - HOSTEDZONEID string - } - shellutils.R(&HostedZoneVpcListOptions{}, "hostedzonevpc-list", "List hostedzonevpc", func(cli *aws.SRegion, args *HostedZoneVpcListOptions) error { - vpcs, err := cli.GetClient().GetHostedZoneVpcs(args.HOSTEDZONEID) - if err != nil { - return err - } - printList(vpcs, len(vpcs), 0, 20, []string{}) - return nil - }) - - type HostedZoneAddVpcOptions struct { - HOSTEDZONEID string - VPC string - REGION string - } - shellutils.R(&HostedZoneAddVpcOptions{}, "hostedzone-add-vpc", "associate vpc with hostedzone", func(cli *aws.SRegion, args *HostedZoneAddVpcOptions) error { - - err := cli.GetClient().AssociateVPCWithHostedZone(args.VPC, args.REGION, args.HOSTEDZONEID) - if err != nil { - return err - } - return nil - }) - - type HostedZoneRemoveVpcOptions struct { - HOSTEDZONEID string - VPC string - REGION string - } - shellutils.R(&HostedZoneRemoveVpcOptions{}, "hostedzone-rmvpc", "disassociate vpc with hostedzone", func(cli *aws.SRegion, args *HostedZoneRemoveVpcOptions) error { - - err := cli.GetClient().DisassociateVPCFromHostedZone(args.VPC, args.REGION, args.HOSTEDZONEID) - if err != nil { - return err - } - return nil - }) - - type HostedZoneDeleteOptions struct { - HOSTEDZONEID string - } - shellutils.R(&HostedZoneDeleteOptions{}, "hostedzone-delete", "delete hostedzone", func(cli *aws.SRegion, args *HostedZoneDeleteOptions) error { - err := cli.GetClient().DeleteHostedZone(args.HOSTEDZONEID) - if err != nil { - return err - } - return nil - }) - - type DnsRecordSetListOptions struct { - HOSTEDZONEID string - } - shellutils.R(&DnsRecordSetListOptions{}, "dnsrecordset-list", "List dnsrecordset", func(cli *aws.SRegion, args *DnsRecordSetListOptions) error { - dnsrecordsets, err := cli.GetClient().GetSdnsRecordSets(args.HOSTEDZONEID) - if err != nil { - return err - } - printList(dnsrecordsets, len(dnsrecordsets), 0, 20, []string{}) - return nil - }) - - type DnsRecordSetCreateOptions struct { - HOSTEDZONEID string `help:"HostedzoneId"` - NAME string `help:"Domain name"` - VALUE string `help:"dns record value"` - TTL int64 `help:"ttl"` - TYPE string `help:"dns type"` - PolicyType string `help:"PolicyType"` - Identify string `help:"Identify"` - } - shellutils.R(&DnsRecordSetCreateOptions{}, "dnsrecordset-create", "create dnsrecordset", func(cli *aws.SRegion, args *DnsRecordSetCreateOptions) error { - opts := cloudprovider.DnsRecordSet{} - opts.DnsName = args.NAME - opts.DnsType = cloudprovider.TDnsType(args.TYPE) - opts.DnsValue = args.VALUE - opts.Ttl = args.TTL - opts.ExternalId = args.Identify - err := cli.GetClient().AddDnsRecordSet(args.HOSTEDZONEID, &opts) - if err != nil { - return err - } - return nil - }) - - type DnsRecordSetupdateOptions struct { - HOSTEDZONEID string `help:"HostedzoneId"` - NAME string `help:"Domain name"` - VALUE string `help:"dns record value"` - TTL int64 `help:"ttl"` - TYPE string `help:"dns type"` - Identify string `help:"Identify"` - } - shellutils.R(&DnsRecordSetupdateOptions{}, "dnsrecordset-update", "update dnsrecordset", func(cli *aws.SRegion, args *DnsRecordSetupdateOptions) error { - opts := cloudprovider.DnsRecordSet{} - opts.DnsName = args.NAME - opts.DnsType = cloudprovider.TDnsType(args.TYPE) - opts.DnsValue = args.VALUE - opts.Ttl = args.TTL - opts.ExternalId = args.Identify - err := cli.GetClient().UpdateDnsRecordSet(args.HOSTEDZONEID, &opts) - if err != nil { - return err - } - return nil - }) - - type DnsRecordSetDeleteOptions struct { - HOSTEDZONEID string `help:"HostedzoneId"` - NAME string `help:"Domain name"` - VALUE string `help:"dns record value"` - TTL int64 `help:"ttl"` - TYPE string `help:"dns type"` - Identify string `help:"Identify"` - } - shellutils.R(&DnsRecordSetDeleteOptions{}, "dnsrecordset-delete", "delete dnsrecordset", func(cli *aws.SRegion, args *DnsRecordSetDeleteOptions) error { - opts := cloudprovider.DnsRecordSet{} - opts.DnsName = args.NAME - opts.DnsType = cloudprovider.TDnsType(args.TYPE) - opts.DnsValue = args.VALUE - opts.Ttl = args.TTL - opts.ExternalId = args.Identify - err := cli.GetClient().RemoveDnsRecordSet(args.HOSTEDZONEID, &opts) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/iam_group.go b/pkg/multicloud/aws/shell/iam_group.go deleted file mode 100644 index e0b0e3ab78..0000000000 --- a/pkg/multicloud/aws/shell/iam_group.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CloudgroupListOptions struct { - Offset string - Limit int - PathPrefix string - } - shellutils.R(&CloudgroupListOptions{}, "cloud-group-list", "List cloudgroups", func(cli *aws.SRegion, args *CloudgroupListOptions) error { - groups, err := cli.GetClient().ListGroups(args.Offset, args.Limit, args.PathPrefix) - if err != nil { - return err - } - printList(groups.Groups, 0, 0, 0, nil) - return nil - }) - - type CloudgroupCreateOptions struct { - NAME string - Path string - } - - shellutils.R(&CloudgroupCreateOptions{}, "cloud-group-create", "Create cloudgroup", func(cli *aws.SRegion, args *CloudgroupCreateOptions) error { - group, err := cli.GetClient().CreateGroup(args.NAME, args.Path) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type CloudgroupShowOptions struct { - NAME string - Offset string - Limit int - } - - shellutils.R(&CloudgroupShowOptions{}, "cloud-group-show", "Show cloudgroup details", func(cli *aws.SRegion, args *CloudgroupShowOptions) error { - group, err := cli.GetClient().GetGroup(args.NAME, args.Offset, args.Limit) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type CloudgroupOptions struct { - NAME string - } - - shellutils.R(&CloudgroupOptions{}, "cloud-group-user-list", "List cloudgroup users", func(cli *aws.SRegion, args *CloudgroupOptions) error { - users, err := cli.GetClient().ListGroupUsers(args.NAME) - if err != nil { - return err - } - printList(users, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&CloudgroupOptions{}, "cloud-group-delete", "Delete cloudgroup", func(cli *aws.SRegion, args *CloudgroupOptions) error { - return cli.GetClient().DeleteGroup(args.NAME) - }) - - type CloudgroupPolicyListOptions struct { - NAME string - Offset string - Limit int - } - - shellutils.R(&CloudgroupPolicyListOptions{}, "cloud-group-policy-list", "List cloudgroup policies", func(cli *aws.SRegion, args *CloudgroupPolicyListOptions) error { - policies, err := cli.GetClient().ListGroupPolicies(args.NAME, args.Offset, args.Limit) - if err != nil { - return err - } - printList(policies.Policies, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&CloudgroupPolicyListOptions{}, "cloud-group-attached-policy-list", "List cloudgroup policies", func(cli *aws.SRegion, args *CloudgroupPolicyListOptions) error { - policies, err := cli.GetClient().ListAttachedGroupPolicies(args.NAME, args.Offset, args.Limit) - if err != nil { - return err - } - printList(policies.AttachedPolicies, 0, 0, 0, nil) - return nil - }) - - type GroupUserOptions struct { - GROUP string - USER string - } - - shellutils.R(&GroupUserOptions{}, "cloud-group-add-user", "Add user to cloudgroup", func(cli *aws.SRegion, args *GroupUserOptions) error { - return cli.GetClient().AddUserToGroup(args.GROUP, args.USER) - }) - - shellutils.R(&GroupUserOptions{}, "cloud-group-remove-user", "Remove user from cloudgroup", func(cli *aws.SRegion, args *GroupUserOptions) error { - return cli.GetClient().RemoveUserFromGroup(args.GROUP, args.USER) - }) - - type GroupPolicyOptions struct { - GROUP string - POLICY string - } - - shellutils.R(&GroupPolicyOptions{}, "cloud-group-attach-policy", "Attach policy to cloudgroup", func(cli *aws.SRegion, args *GroupPolicyOptions) error { - return cli.GetClient().AttachGroupPolicy(args.GROUP, args.POLICY) - }) - - shellutils.R(&GroupPolicyOptions{}, "cloud-group-detach-policy", "Detach policy from cloudgroup", func(cli *aws.SRegion, args *GroupPolicyOptions) error { - return cli.GetClient().DetachGroupPolicy(args.GROUP, args.POLICY) - }) - -} diff --git a/pkg/multicloud/aws/shell/iam_policy.go b/pkg/multicloud/aws/shell/iam_policy.go deleted file mode 100644 index afea2a41fe..0000000000 --- a/pkg/multicloud/aws/shell/iam_policy.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type PolicyListOptions struct { - Limit int - Offset string - OnlyAttached bool - PathPrefix string - PolicyUsageFilter string `choices:"PermissionsPolicy|PermissionsBoundary"` - Scope string `choices:"All|AWS|Local"` - } - - shellutils.R(&PolicyListOptions{}, "cloud-policy-list", "List policies", func(cli *aws.SRegion, args *PolicyListOptions) error { - policies, err := cli.GetClient().ListPolicies(args.Offset, args.Limit, args.OnlyAttached, args.PathPrefix, args.PolicyUsageFilter, args.Scope) - if err != nil { - return err - } - printList(policies.Policies, 0, 0, 0, nil) - return nil - }) - - type PolicyVersionListOptions struct { - Offset string - Limit int - ARN string - } - shellutils.R(&PolicyVersionListOptions{}, "cloud-policy-version-list", "List policy versions", func(cli *aws.SRegion, args *PolicyVersionListOptions) error { - versions, err := cli.GetClient().ListPolicyVersions(args.Offset, args.Limit, args.ARN) - if err != nil { - return err - } - printList(versions.Versions, 0, 0, 0, nil) - return nil - }) - - type PolicyVersionOptions struct { - ARN string - VERSION string - } - - shellutils.R(&PolicyVersionOptions{}, "cloud-policy-version-show", "Show policy version details", func(cli *aws.SRegion, args *PolicyVersionOptions) error { - version, err := cli.GetClient().GetPolicyVersion(args.ARN, args.VERSION) - if err != nil { - return err - } - printObject(version) - return nil - }) - - type PolicyArnOptions struct { - ARN string - } - - shellutils.R(&PolicyArnOptions{}, "cloud-policy-show", "Show policy details by policy arn", func(cli *aws.SRegion, args *PolicyArnOptions) error { - policy, err := cli.GetClient().GetPolicy(args.ARN) - if err != nil { - return err - } - printObject(policy) - return nil - }) - - shellutils.R(&PolicyArnOptions{}, "cloud-policy-delete", "Delete policy", func(cli *aws.SRegion, args *PolicyArnOptions) error { - return cli.GetClient().DeletePolicy(args.ARN) - }) - - type PolicyVersionSHowOptions struct { - ARN string - VERSION string - } - - shellutils.R(&PolicyVersionSHowOptions{}, "cloud-policy-version-show", "Show policy version details", func(cli *aws.SRegion, args *PolicyVersionSHowOptions) error { - version, err := cli.GetClient().GetPolicyVersion(args.ARN, args.VERSION) - if err != nil { - return err - } - printObject(version) - return nil - }) - - type PolicyCreateOptions struct { - NAME string - DOCUMENT string - Path string - Desc string - } - - shellutils.R(&PolicyCreateOptions{}, "cloud-policy-create", "Create policy", func(cli *aws.SRegion, args *PolicyCreateOptions) error { - policy, err := cli.GetClient().CreatePolicy(args.NAME, args.DOCUMENT, args.Path, args.Desc) - if err != nil { - return err - } - printObject(policy) - return nil - }) - - type PolicyVersionCreateOptions struct { - ARN string - DOCUMENT string - IsDefault bool - } - - shellutils.R(&PolicyVersionCreateOptions{}, "cloud-policy-version-create", "Create policy version", func(cli *aws.SRegion, args *PolicyVersionCreateOptions) error { - return cli.GetClient().CreatePolicyVersion(args.ARN, args.DOCUMENT, args.IsDefault) - }) - -} diff --git a/pkg/multicloud/aws/shell/iam_role.go b/pkg/multicloud/aws/shell/iam_role.go deleted file mode 100644 index 12e5455857..0000000000 --- a/pkg/multicloud/aws/shell/iam_role.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RoleListOptions struct { - Offset string - Limit int - PathPrefix string - } - shellutils.R(&RoleListOptions{}, "cloud-role-list", "List roles", func(cli *aws.SRegion, args *RoleListOptions) error { - roles, err := cli.GetClient().ListRoles(args.Offset, args.Limit, args.PathPrefix) - if err != nil { - return err - } - printList(roles.Roles, 0, 0, 0, []string{}) - return nil - }) - - type RoleNameOptions struct { - ROLE string - } - - shellutils.R(&RoleNameOptions{}, "cloud-role-show", "Show role", func(cli *aws.SRegion, args *RoleNameOptions) error { - role, err := cli.GetClient().GetRole(args.ROLE) - if err != nil { - return err - } - printObject(role) - document := role.GetDocument() - if document != nil { - printObject(document) - } - return nil - }) - - type RoleAttachPolicyListOptions struct { - ROLE string - Marker string - MaxItems int - PathPrefix string - } - - shellutils.R(&RoleAttachPolicyListOptions{}, "cloud-role-attach-policy-list", "List Role attach policy", func(cli *aws.SRegion, args *RoleAttachPolicyListOptions) error { - policy, err := cli.GetClient().ListAttachedRolePolicies(args.ROLE, args.Marker, args.MaxItems, args.PathPrefix) - if err != nil { - return errors.Wrapf(err, "ListAttachedRolePolicies") - } - printList(policy.AttachedPolicies, 0, 0, 0, nil) - if len(policy.Marker) > 0 { - fmt.Println("marker: ", policy.Marker) - } - return nil - }) - - shellutils.R(&RoleNameOptions{}, "cloud-role-delete", "Delete role", func(cli *aws.SRegion, args *RoleNameOptions) error { - return cli.GetClient().DeleteRole(args.ROLE) - }) - - shellutils.R(&cloudprovider.SRoleCreateOptions{}, "cloud-role-create", "Create role", func(cli *aws.SRegion, args *cloudprovider.SRoleCreateOptions) error { - role, err := cli.GetClient().CreateRole(args) - if err != nil { - return err - } - printObject(role) - return nil - }) - -} diff --git a/pkg/multicloud/aws/shell/iam_user.go b/pkg/multicloud/aws/shell/iam_user.go deleted file mode 100644 index 5653155ca3..0000000000 --- a/pkg/multicloud/aws/shell/iam_user.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClouduserListOptions struct { - Offset string - Limit int - PathPrefix string - } - shellutils.R(&ClouduserListOptions{}, "cloud-user-list", "List cloudusers", func(cli *aws.SRegion, args *ClouduserListOptions) error { - users, err := cli.GetClient().ListUsers(args.Offset, args.Limit, args.PathPrefix) - if err != nil { - return err - } - printList(users.Users, 0, 0, 0, nil) - return nil - }) - - type ClouduserCreateOptions struct { - NAME string - Path string - } - - shellutils.R(&ClouduserCreateOptions{}, "cloud-user-create", "Create clouduser", func(cli *aws.SRegion, args *ClouduserCreateOptions) error { - user, err := cli.GetClient().CreateUser(args.Path, args.NAME) - if err != nil { - return err - } - printObject(user) - return nil - }) - - type ClouduserOptions struct { - NAME string - } - - shellutils.R(&ClouduserOptions{}, "cloud-user-show", "Show clouduser details", func(cli *aws.SRegion, args *ClouduserOptions) error { - user, err := cli.GetClient().GetUser(args.NAME) - if err != nil { - return err - } - printObject(user) - return nil - }) - - shellutils.R(&ClouduserOptions{}, "cloud-user-loginprofile", "Show clouduser loginprofile", func(cli *aws.SRegion, args *ClouduserOptions) error { - profile, err := cli.GetClient().GetLoginProfile(args.NAME) - if err != nil { - return err - } - printObject(profile) - return nil - }) - - shellutils.R(&ClouduserOptions{}, "cloud-user-loginprofile-delete", "Delete clouduser loginprofile", func(cli *aws.SRegion, args *ClouduserOptions) error { - return cli.GetClient().DeleteLoginProfile(args.NAME) - }) - - shellutils.R(&ClouduserOptions{}, "cloud-user-delete", "Delete clouduser", func(cli *aws.SRegion, args *ClouduserOptions) error { - return cli.GetClient().DeleteUser(args.NAME) - }) - - type ClouduserLoginProfileCreateOptions struct { - NAME string - PASSWORD string - } - - shellutils.R(&ClouduserLoginProfileCreateOptions{}, "cloud-user-loginprofile-create", "Create clouduser loginprofile", func(cli *aws.SRegion, args *ClouduserLoginProfileCreateOptions) error { - profile, err := cli.GetClient().CreateLoginProfile(args.NAME, args.PASSWORD) - if err != nil { - return err - } - printObject(profile) - return nil - }) - - shellutils.R(&ClouduserLoginProfileCreateOptions{}, "cloud-user-reset-password", "Reset clouduser password", func(cli *aws.SRegion, args *ClouduserLoginProfileCreateOptions) error { - return cli.GetClient().ResetUserPassword(args.NAME, args.PASSWORD) - }) - - type ClouduserPolicyListOptions struct { - NAME string - Offset string - Limit int - } - - shellutils.R(&ClouduserPolicyListOptions{}, "cloud-user-policy-list", "List clouduser policies", func(cli *aws.SRegion, args *ClouduserPolicyListOptions) error { - policies, err := cli.GetClient().ListUserPolicies(args.NAME, args.Offset, args.Limit) - if err != nil { - return err - } - printObject(policies) - return nil - }) - - type ClouduserAttachedPolicyListOptions struct { - NAME string - Offset string - Limit int - PathPrefix string - } - - shellutils.R(&ClouduserAttachedPolicyListOptions{}, "cloud-user-attached-policy-list", "List clouduser attached policies", func(cli *aws.SRegion, args *ClouduserAttachedPolicyListOptions) error { - policies, err := cli.GetClient().ListAttachedUserPolicies(args.NAME, args.Offset, args.Limit, args.PathPrefix) - if err != nil { - return err - } - printList(policies.AttachedPolicies, 0, 0, 0, nil) - return nil - }) - - type ClouduserPolicyOptions struct { - NAME string - POLICY_ARN string - } - - shellutils.R(&ClouduserPolicyOptions{}, "cloud-user-attach-policy", "Attach policy for clouduser", func(cli *aws.SRegion, args *ClouduserPolicyOptions) error { - return cli.GetClient().AttachUserPolicy(args.NAME, args.POLICY_ARN) - }) - - shellutils.R(&ClouduserPolicyOptions{}, "cloud-user-detach-policy", "Detach policy from clouduser", func(cli *aws.SRegion, args *ClouduserPolicyOptions) error { - return cli.GetClient().DetachUserPolicy(args.NAME, args.POLICY_ARN) - }) - -} diff --git a/pkg/multicloud/aws/shell/image.go b/pkg/multicloud/aws/shell/image.go deleted file mode 100644 index f458580a3c..0000000000 --- a/pkg/multicloud/aws/shell/image.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/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, e.g. self, system or all" choices:"self|system|all"` - VirtualizationType string `help:"virtualization type" choices:"hvm|paravirtual"` - Id []string `help:"Image ID"` - Name string `help:"image name"` - RawOwner []string `help:"raw owner id"` - VolumeType string `help:"image volume type" choices:"gp2|io1|st1|sc1|standard"` - Latest bool `help:"show latest image only"` - } - shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *aws.SRegion, args *ImageListOptions) error { - var owners []aws.TImageOwnerType - switch args.Owner { - case "self": - owners = aws.ImageOwnerSelf - case "system": - owners = aws.ImageOwnerSystem - } - images, e := cli.GetImages(aws.ImageStatusType(args.Status), owners, args.Id, args.Name, args.VirtualizationType, args.RawOwner, args.VolumeType, args.Latest) - if e != nil { - return e - } - printList(images, 0, 0, 0, []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) - }) -} diff --git a/pkg/multicloud/aws/shell/instance.go b/pkg/multicloud/aws/shell/instance.go deleted file mode 100644 index 975eeb84e6..0000000000 --- a/pkg/multicloud/aws/shell/instance.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "context" - "fmt" - "io/ioutil" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/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 InstanceCreateOptions 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(&InstanceCreateOptions{}, "instance-create", "Create a instance", func(cli *aws.SRegion, args *InstanceCreateOptions) 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 { - ctx := context.Background() - img, err := cli.GetImage(args.Image) - if err != nil { - return err - } - - diskID, err := cli.ReplaceSystemDisk(ctx, args.ID, img, args.Size, "", "") - if err != nil { - return err - } - fmt.Printf("New diskID is %s", diskID) - return nil - }) - - type InstanceChangeConfigOptions struct { - ID string `help:"instance ID"` - InstanceTypeId string `help:"instance type"` - 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.ChangeVMConfig2(instance.ZoneId, args.ID, args.InstanceTypeId, nil) - if err != nil { - return err - } - return nil - }) - - type InstanceSaveImageOptions struct { - ID string `help:"Instance ID"` - IMAGE_NAME string `help:"Image name"` - Notes string `hlep:"Image desc"` - } - shellutils.R(&InstanceSaveImageOptions{}, "instance-save-image", "Save instance to image", func(cli *aws.SRegion, args *InstanceSaveImageOptions) error { - opts := cloudprovider.SaveImageOptions{ - Name: args.IMAGE_NAME, - Notes: args.Notes, - } - image, err := cli.SaveImage(args.ID, &opts) - if err != nil { - return err - } - printObject(image) - return nil - }) - -} diff --git a/pkg/multicloud/aws/shell/instancetype.go b/pkg/multicloud/aws/shell/instancetype.go deleted file mode 100644 index d223fef44d..0000000000 --- a/pkg/multicloud/aws/shell/instancetype.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceTypeListOptions struct { - NextMarker string - } - shellutils.R(&InstanceTypeListOptions{}, "instance-type-list", "List intance types", func(cli *aws.SRegion, args *InstanceTypeListOptions) error { - skus, _, err := cli.GetInstanceTypes(args.NextMarker) - if err != nil { - return err - } - printList(skus, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/aws/shell/keypair.go b/pkg/multicloud/aws/shell/keypair.go deleted file mode 100644 index 2cd7e1ca54..0000000000 --- a/pkg/multicloud/aws/shell/keypair.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/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 - }) -} diff --git a/pkg/multicloud/aws/shell/monitor.go b/pkg/multicloud/aws/shell/monitor.go deleted file mode 100644 index 6dee2d3dc7..0000000000 --- a/pkg/multicloud/aws/shell/monitor.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics", func(cli *aws.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric: %s %s %s", metrics[i].Id, metrics[i].MetricType, metrics[i].Unit) - printList(metrics[i].Values, len(metrics[i].Values), 0, 0, []string{}) - } - return nil - }) - -} diff --git a/pkg/multicloud/aws/shell/natgateway.go b/pkg/multicloud/aws/shell/natgateway.go deleted file mode 100644 index 0779f14d5a..0000000000 --- a/pkg/multicloud/aws/shell/natgateway.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NatListOptions struct { - Ids []string - VpcId string - SubnetId string - } - shellutils.R(&NatListOptions{}, "natgateway-list", "List natgateway", func(cli *aws.SRegion, args *NatListOptions) error { - nats, err := cli.GetNatGateways(args.Ids, args.VpcId, args.SubnetId) - if err != nil { - return err - } - printList(nats, 0, 0, 0, nil) - return nil - }) - - type NatIdOptions struct { - ID string - } - - shellutils.R(&NatIdOptions{}, "natgateway-delete", "Delete natgateway", func(cli *aws.SRegion, args *NatIdOptions) error { - return cli.DeleteNatgateway(args.ID) - }) - -} diff --git a/pkg/multicloud/aws/shell/network.go b/pkg/multicloud/aws/shell/network.go deleted file mode 100644 index 62fde3faa3..0000000000 --- a/pkg/multicloud/aws/shell/network.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VSwitchListOptions struct { - Ids []string - VpcId string - } - shellutils.R(&VSwitchListOptions{}, "network-list", "List vswitches", func(cli *aws.SRegion, args *VSwitchListOptions) error { - networks, err := cli.GetNetwroks(args.Ids, args.VpcId) - if err != nil { - return err - } - printList(networks, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/networkinterface.go b/pkg/multicloud/aws/shell/networkinterface.go deleted file mode 100644 index cbbcbfa6cd..0000000000 --- a/pkg/multicloud/aws/shell/networkinterface.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkInterfaceListOptions struct { - Id string - } - shellutils.R(&NetworkInterfaceListOptions{}, "network-interface-list", "List network interfaces", func(cli *aws.SRegion, args *NetworkInterfaceListOptions) error { - interfaces, err := cli.GetNetworkInterfaces(args.Id) - if err != nil { - return err - } - printList(interfaces, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/organizations.go b/pkg/multicloud/aws/shell/organizations.go deleted file mode 100644 index 3e6ead5714..0000000000 --- a/pkg/multicloud/aws/shell/organizations.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type AccountListOptions struct { - } - shellutils.R(&AccountListOptions{}, "account-list", "List accounts", func(cli *aws.SRegion, args *AccountListOptions) error { - accounts, err := cli.ListAccounts() - if err != nil { - return err - } - printList(accounts, 0, 0, 0, []string{}) - return nil - }) - - type OrganizationPoliciesListOptions struct { - FILTER string `json:"filter" choices:"SERVICE_CONTROL_POLICY|TAG_POLICY|BACKUP_POLICY|AISERVICES_OPT_OUT_POLICY"` - } - shellutils.R(&OrganizationPoliciesListOptions{}, "org-policy-list", "List policies of organizations", func(cli *aws.SRegion, args *OrganizationPoliciesListOptions) error { - policies, err := cli.ListPolicies(args.FILTER) - if err != nil { - return err - } - printList(policies, 0, 0, 0, []string{}) - return nil - }) - - type OrganizationPolicyShowOptions struct { - ID string `json:"id"` - } - shellutils.R(&OrganizationPolicyShowOptions{}, "org-policy-show", "Show details of an organizations policy", func(cli *aws.SRegion, args *OrganizationPolicyShowOptions) error { - content, err := cli.DescribeOrgPolicy(args.ID) - if err != nil { - return err - } - fmt.Println(content.PrettyString()) - return nil - }) - - type OrganizationPoliciesListForTargetOptions struct { - OrganizationPoliciesListOptions - TARGET string `json:"target"` - } - shellutils.R(&OrganizationPoliciesListForTargetOptions{}, "org-target-policy-list", "List policies for target of organizations", func(cli *aws.SRegion, args *OrganizationPoliciesListForTargetOptions) error { - policies, err := cli.ListPoliciesForTarget(args.FILTER, args.TARGET) - if err != nil { - return err - } - printList(policies, 0, 0, 0, []string{}) - return nil - }) - - type OrganizationParentsListOptions struct { - ID string `json:"id"` - } - shellutils.R(&OrganizationParentsListOptions{}, "org-parent-list", "List parent nodes of a child node", func(cli *aws.SRegion, args *OrganizationParentsListOptions) error { - err := cli.ListParents(args.ID) - if err != nil { - return err - } - return nil - }) - - type OrganizationalUnitShowOptions struct { - ID string `help:"Id of organizational unit"` - } - shellutils.R(&OrganizationalUnitShowOptions{}, "org-ou-show", "Show details of organizational unit", func(cli *aws.SRegion, args *OrganizationalUnitShowOptions) error { - err := cli.DescribeOrganizationalUnit(args.ID) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/printutils.go b/pkg/multicloud/aws/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/aws/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/aws/shell/region.go b/pkg/multicloud/aws/shell/region.go deleted file mode 100644 index 22a8ab61fc..0000000000 --- a/pkg/multicloud/aws/shell/region.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/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, err := cli.GetClient().GetRegions() - if err != nil { - return err - } - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/reservedinstance.go b/pkg/multicloud/aws/shell/reservedinstance.go deleted file mode 100644 index 6a67ac4d55..0000000000 --- a/pkg/multicloud/aws/shell/reservedinstance.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ReservedInstanceListOptions 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(&ReservedInstanceListOptions{}, "reserved-instance-list", "List intances", func(cli *aws.SRegion, args *ReservedInstanceListOptions) error { - e := cli.GetReservedInstance() - if e != nil { - return e - } - - e = cli.GetReservedHostOfferings() - if e != nil { - return e - } - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/resource_tag.go b/pkg/multicloud/aws/shell/resource_tag.go deleted file mode 100644 index 2a02516067..0000000000 --- a/pkg/multicloud/aws/shell/resource_tag.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "strings" - - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type TagAddOptions struct { - ARN []string `help:"aws resource name"` - Tag []string `help:"tag to set, key:value"` - } - shellutils.R(&TagAddOptions{}, "tag-add", "add tags", func(cli *aws.SRegion, args *TagAddOptions) error { - tags := make(map[string]string) - for _, t := range args.Tag { - parts := strings.Split(t, ":") - tags[parts[0]] = parts[1] - } - e := cli.TagResources(args.ARN, tags) - if e != nil { - return e - } - return nil - }) - - type UnTagOptions struct { - ARN []string `help:"aws resource name"` - Tag []string `help:"tag to set, key"` - } - shellutils.R(&UnTagOptions{}, "tag-del", "untag intances", func(cli *aws.SRegion, args *UnTagOptions) error { - e := cli.UntagResources(args.ARN, args.Tag) - if e != nil { - return e - } - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/routetable.go b/pkg/multicloud/aws/shell/routetable.go deleted file mode 100644 index c81886ad33..0000000000 --- a/pkg/multicloud/aws/shell/routetable.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RouteTableListOptions struct { - VpcId string `help:"vpc id"` - MainOnly bool - } - shellutils.R(&RouteTableListOptions{}, "routetable-list", "List route tables", func(cli *aws.SRegion, args *RouteTableListOptions) error { - routetables, err := cli.GetRouteTables(args.VpcId, args.MainOnly) - if err != nil { - printObject(err) - return nil - } - - printList(routetables, 0, 0, 0, nil) - return nil - }) - - type RouteCreateOptions struct { - ROUTETABLEID string `help:"routetable id"` - CIDRBLOCK string - TARGETID string - } - shellutils.R(&RouteCreateOptions{}, "route-create", "create route", func(cli *aws.SRegion, args *RouteCreateOptions) error { - err := cli.CreateRoute(args.ROUTETABLEID, args.CIDRBLOCK, args.TARGETID) - if err != nil { - return err - } - return nil - }) - - type RouteReplaceOptions struct { - ROUTETABLEID string `help:"routetable id"` - CIDRBLOCK string - TARGETID string - } - shellutils.R(&RouteReplaceOptions{}, "route-replace", "replace route", func(cli *aws.SRegion, args *RouteReplaceOptions) error { - err := cli.ReplaceRoute(args.ROUTETABLEID, args.CIDRBLOCK, args.TARGETID) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/s3.go b/pkg/multicloud/aws/shell/s3.go deleted file mode 100644 index 4fc026b485..0000000000 --- a/pkg/multicloud/aws/shell/s3.go +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "os" - - "github.com/aws/aws-sdk-go/service/s3" - - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/printutils" - "yunion.io/x/onecloud/pkg/util/shellutils" - "yunion.io/x/onecloud/pkg/util/streamutils" -) - -func init() { - type S3BucketListOptions struct { - } - shellutils.R(&S3BucketListOptions{}, "s3-list", "List all buckets", func(cli *aws.SRegion, args *S3BucketListOptions) error { - buckets, err := cli.GetIBuckets() - if err != nil { - return err - } - printList(buckets, 0, 0, 0, nil) - printutils.PrintGetterList(buckets, nil) - return nil - }) - - type S3CreateBucketOptions struct { - BUCKET string `help:"bucket name"` - } - shellutils.R(&S3CreateBucketOptions{}, "s3-create-bucket", "Create a bucket", func(cli *aws.SRegion, args *S3CreateBucketOptions) error { - err := cli.CreateIBucket(args.BUCKET, "", "") - if err != nil { - return err - } - return nil - }) - - type S3DeleteBucketOptions struct { - BUCKET string `help:"bucket name"` - } - shellutils.R(&S3DeleteBucketOptions{}, "s3-delete-bucket", "Delete a bucket", func(cli *aws.SRegion, args *S3DeleteBucketOptions) error { - err := cli.DeleteIBucket(args.BUCKET) - if err != nil { - return err - } - return nil - }) - - type S3ListObjectOptions struct { - BUCKET string - Prefix string - Marker string - Limit int64 `help:"list limit" default:"20"` - } - shellutils.R(&S3ListObjectOptions{}, "s3-list-objects", "List objects in a bucket", func(cli *aws.SRegion, args *S3ListObjectOptions) error { - s3cli, err := cli.GetS3Client() - if err != nil { - return err - } - input := &s3.ListObjectsInput{} - input = input.SetBucket(args.BUCKET) - if args.Limit > 0 { - input = input.SetMaxKeys(args.Limit) - } - if len(args.Prefix) > 0 { - input = input.SetPrefix(args.Prefix) - } - if len(args.Marker) > 0 { - input = input.SetMarker(args.Marker) - } - - output, err := s3cli.ListObjects(input) - if err != nil { - return err - } - printList(output.Contents, 0, 0, 0, nil) - if output.IsTruncated != nil && *output.IsTruncated { - fmt.Println("More ...") - } - return nil - }) - - type S3DownloadObjectOptions struct { - BUCKET string `help:"Bucket name"` - OBJECT string `help:"Object key"` - Output string `help:"Location of output file"` - } - shellutils.R(&S3DownloadObjectOptions{}, "s3-download", "Download an object in a bucket", func(cli *aws.SRegion, args *S3DownloadObjectOptions) error { - s3cli, err := cli.GetS3Client() - if err != nil { - return err - } - input := &s3.GetObjectInput{} - input = input.SetBucket(args.BUCKET).SetKey(args.OBJECT) - output, err := s3cli.GetObject(input) - if err != nil { - return err - } - var fio *os.File - if len(args.Output) > 0 { - fio, err = os.Create(args.Output) - if err != nil { - return err - } - defer fio.Close() - } else { - fio = os.Stdout - } - prop, err := streamutils.StreamPipe(output.Body, fio, true, nil) - if err != nil { - return err - } - if len(args.Output) > 0 { - fmt.Printf("File: %s Size: %d Chksum: %s\n", args.Output, prop.Size, prop.CheckSum) - } - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/saml_provider.go b/pkg/multicloud/aws/shell/saml_provider.go deleted file mode 100644 index 544624e879..0000000000 --- a/pkg/multicloud/aws/shell/saml_provider.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SAMLProviderListOptions struct { - } - shellutils.R(&SAMLProviderListOptions{}, "saml-provider-list", "List saml providers", func(cli *aws.SRegion, args *SAMLProviderListOptions) error { - samls, err := cli.GetClient().ListSAMLProviders() - if err != nil { - return err - } - printList(samls, 0, 0, 0, []string{}) - return nil - }) - - type SAMLProviderArnOptions struct { - ARN string - } - - shellutils.R(&SAMLProviderArnOptions{}, "saml-provider-show", "Show saml provider", func(cli *aws.SRegion, args *SAMLProviderArnOptions) error { - saml, err := cli.GetClient().GetSAMLProvider(args.ARN) - if err != nil { - return err - } - printObject(saml) - return nil - }) - - shellutils.R(&SAMLProviderArnOptions{}, "saml-provider-delete", "Delete saml provider", func(cli *aws.SRegion, args *SAMLProviderArnOptions) error { - return cli.GetClient().DeleteSAMLProvider(args.ARN) - }) - - type SAMLProviderCreateOptions struct { - NAME string - METADATA string - } - - shellutils.R(&SAMLProviderCreateOptions{}, "saml-provider-create", "Create saml provider", func(cli *aws.SRegion, args *SAMLProviderCreateOptions) error { - saml, err := cli.GetClient().CreateSAMLProvider(args.NAME, args.METADATA) - if err != nil { - return err - } - printObject(saml) - return nil - }) - - type SAMLProviderUpdateOptions struct { - ARN string - METADATA string - } - - shellutils.R(&SAMLProviderUpdateOptions{}, "saml-provider-update", "Update saml provider", func(cli *aws.SRegion, args *SAMLProviderUpdateOptions) error { - saml, err := cli.GetClient().UpdateSAMLProvider(args.ARN, args.METADATA) - if err != nil { - return err - } - printObject(saml) - return nil - }) - -} diff --git a/pkg/multicloud/aws/shell/secgroup.go b/pkg/multicloud/aws/shell/secgroup.go deleted file mode 100644 index 8cb531fd43..0000000000 --- a/pkg/multicloud/aws/shell/secgroup.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - VpcId string `help:"VPC ID"` - Name string `help:"Secgroup name"` - 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.Name, "", 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 - }) - - type SecurityGroupCreateOptions struct { - VPC string `help:"vpcId"` - NAME string `help:"group name"` - DESC string `help:"group desc"` - Tag string `help:"group tag"` - } - shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create security group", func(cli *aws.SRegion, args *SecurityGroupCreateOptions) error { - id, err := cli.CreateSecurityGroup(args.VPC, args.NAME, args.Tag, args.DESC) - if err != nil { - return err - } - fmt.Println(id) - return nil - }) - - type SecurityGroupRuleDeleteOption struct { - SECGROUP_ID string - RULE string - } - - shellutils.R(&SecurityGroupRuleDeleteOption{}, "security-group-rule-delete", "Delete security group rule", func(cli *aws.SRegion, args *SecurityGroupRuleDeleteOption) error { - rule, err := secrules.ParseSecurityRule(args.RULE) - if err != nil { - return errors.Wrapf(err, "ParseSecurityRule(%s)", args.RULE) - } - return cli.DelSecurityGroupRule(args.SECGROUP_ID, cloudprovider.SecurityRule{SecurityRule: *rule}) - }) - -} diff --git a/pkg/multicloud/aws/shell/snapshot.go b/pkg/multicloud/aws/shell/snapshot.go deleted file mode 100644 index 1df64a6f88..0000000000 --- a/pkg/multicloud/aws/shell/snapshot.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/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 - }) - -} diff --git a/pkg/multicloud/aws/shell/sts.go b/pkg/multicloud/aws/shell/sts.go deleted file mode 100644 index c7fe0538e8..0000000000 --- a/pkg/multicloud/aws/shell/sts.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CallerIdentityOptions struct { - } - shellutils.R(&CallerIdentityOptions{}, "caller-identity-show", "Show caller identity", func(cli *aws.SRegion, args *CallerIdentityOptions) error { - identity, err := cli.GetClient().GetCallerIdentity() - if err != nil { - return err - } - printObject(identity) - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/vpc.go b/pkg/multicloud/aws/shell/vpc.go deleted file mode 100644 index efb41180f9..0000000000 --- a/pkg/multicloud/aws/shell/vpc.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - VpcIds []string - } - shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *aws.SRegion, args *VpcListOptions) error { - vpcs, err := cli.GetVpcs(args.VpcIds) - if err != nil { - return err - } - printList(vpcs, 0, 0, 0, []string{}) - return nil - }) - - type VpcPeeringConnectionListOptions struct { - VPCID string - } - shellutils.R(&VpcPeeringConnectionListOptions{}, "vpc-peering-connection-list", "List vpcPeeringConnections", func(cli *aws.SRegion, args *VpcPeeringConnectionListOptions) error { - vpcPCs, err := cli.DescribeVpcPeeringConnections(args.VPCID) - if err != nil { - return err - } - printList(vpcPCs, len(vpcPCs), len(vpcPCs), len(vpcPCs), []string{}) - return nil - }) - - type VpcPeeringConnectionShowOptions struct { - ID string - } - shellutils.R(&VpcPeeringConnectionShowOptions{}, "vpc-peering-connection-show", "show vpcPeeringConnections", func(cli *aws.SRegion, args *VpcPeeringConnectionShowOptions) error { - vpcPC, err := cli.GetVpcPeeringConnectionById(args.ID) - if err != nil { - return err - } - printObject(vpcPC) - return nil - }) - - type VpcPeeringConnectionCreateOptions struct { - NAME string - VPCID string - PEERVPCID string - PEERACCOUNTID string - PEERREGIONID string - Desc string - } - shellutils.R(&VpcPeeringConnectionCreateOptions{}, "vpc-peering-connection-create", "create vpcPeeringConnection", func(cli *aws.SRegion, args *VpcPeeringConnectionCreateOptions) error { - opts := cloudprovider.VpcPeeringConnectionCreateOptions{} - opts.Desc = args.Desc - opts.Name = args.NAME - opts.PeerAccountId = args.PEERACCOUNTID - opts.PeerRegionId = args.PEERREGIONID - opts.PeerVpcId = args.PEERVPCID - - vpcPC, err := cli.CreateVpcPeeringConnection(args.VPCID, &opts) - if err != nil { - return err - } - printObject(vpcPC) - return nil - }) - - type VpcPeeringConnectionAcceptOptions struct { - ID string - } - shellutils.R(&VpcPeeringConnectionAcceptOptions{}, "vpc-peering-connection-accept", "accept vpcPeeringConnection", func(cli *aws.SRegion, args *VpcPeeringConnectionAcceptOptions) error { - vpcPC, err := cli.AcceptVpcPeeringConnection(args.ID) - if err != nil { - return err - } - printObject(vpcPC) - return nil - }) - - type VpcPeeringConnectionDeleteOptions struct { - ID string - } - shellutils.R(&VpcPeeringConnectionDeleteOptions{}, "vpc-peering-connection-delete", "delete vpcPeeringConnection", func(cli *aws.SRegion, args *VpcPeeringConnectionDeleteOptions) error { - err := cli.DeleteVpcPeeringConnection(args.ID) - if err != nil { - return err - } - return nil - }) - - type VpcPeeringConnectionRouteDeleteOptions struct { - ID string - } - shellutils.R(&VpcPeeringConnectionAcceptOptions{}, "vpc-peering-connection-route-delete", "delete vpc-peering-connection route", func(cli *aws.SRegion, args *VpcPeeringConnectionAcceptOptions) error { - err := cli.DeleteVpcPeeringConnectionRoute(args.ID) - if err != nil { - printObject(err) - return err - } - return nil - }) -} diff --git a/pkg/multicloud/aws/shell/waf.go b/pkg/multicloud/aws/shell/waf.go deleted file mode 100644 index 85e95160ba..0000000000 --- a/pkg/multicloud/aws/shell/waf.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "io/ioutil" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aws" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type WafRuleGroupListOptions struct { - Scope string `choices:"CLOUDFRONT|REGIONAL" default:"REGIONAL"` - } - - shellutils.R(&WafRuleGroupListOptions{}, "waf-managed-rule-group-list", "List waf managed rule group", func(cli *aws.SRegion, args *WafRuleGroupListOptions) error { - groups, err := cli.ListAvailableManagedRuleGroups(args.Scope) - if err != nil { - return err - } - printList(groups, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&WafRuleGroupListOptions{}, "waf-rule-group-list", "List waf rule group", func(cli *aws.SRegion, args *WafRuleGroupListOptions) error { - groups, err := cli.ListRuleGroups(args.Scope) - if err != nil { - return err - } - printList(groups, 0, 0, 0, []string{}) - return nil - }) - - type WafRuleGroupShowOptions struct { - ID string - NAME string - SCOPE string - } - - shellutils.R(&WafRuleGroupShowOptions{}, "waf-rule-group-show", "Show waf rule group", func(cli *aws.SRegion, args *WafRuleGroupShowOptions) error { - group, err := cli.GetRuleGroup(args.ID, args.NAME, args.SCOPE) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type WafManagedRuleGroupShowOptions struct { - NAME string - SCOPE string - VendorName string `default:"AWS"` - } - - shellutils.R(&WafManagedRuleGroupShowOptions{}, "waf-managed-rule-group-show", "Show waf rule group", func(cli *aws.SRegion, args *WafManagedRuleGroupShowOptions) error { - group, err := cli.DescribeManagedRuleGroup(args.NAME, args.SCOPE, args.VendorName) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type RuleGroupDeleteOptions struct { - ID string - NAME string - SCOPE string - LOCK_TOKEN string - } - - shellutils.R(&RuleGroupDeleteOptions{}, "waf-rule-group-delete", "Delete waf ip set", func(cli *aws.SRegion, args *RuleGroupDeleteOptions) error { - return cli.DeleteRuleGroup(args.ID, args.NAME, args.SCOPE, args.LOCK_TOKEN) - }) - - type IPSetListOptions struct { - Scope string `choices:"CLOUDFRONT|REGIONAL" default:"REGIONAL"` - } - - shellutils.R(&IPSetListOptions{}, "waf-ipset-list", "List waf ip sets", func(cli *aws.SRegion, args *IPSetListOptions) error { - ipsets, err := cli.ListIPSets(args.Scope) - if err != nil { - return err - } - printList(ipsets, 0, 0, 0, []string{}) - return nil - }) - - type WafIPSetShowOptions struct { - ID string - NAME string - SCOPE string - } - - shellutils.R(&WafIPSetShowOptions{}, "waf-ipset-show", "Show waf ip sets", func(cli *aws.SRegion, args *WafIPSetShowOptions) error { - ipset, err := cli.GetIPSet(args.ID, args.NAME, args.SCOPE) - if err != nil { - return err - } - printObject(ipset) - return nil - }) - - type WafIPSetDeleteOptions struct { - ID string - NAME string - SCOPE string - LOCK_TOKEN string - } - - shellutils.R(&WafIPSetDeleteOptions{}, "waf-ipset-delete", "Delete waf ip set", func(cli *aws.SRegion, args *WafIPSetDeleteOptions) error { - return cli.DeleteIPSet(args.ID, args.NAME, args.SCOPE, args.LOCK_TOKEN) - }) - - type WafListOptions struct { - Scope string `choices:"CLOUDFRONT|REGIONAL" default:"REGIONAL"` - } - - shellutils.R(&WafListOptions{}, "waf-list", "List web acls", func(cli *aws.SRegion, args *WafListOptions) error { - acls, err := cli.ListWebACLs(args.Scope) - if err != nil { - return err - } - printList(acls, 0, 0, 0, []string{}) - return nil - }) - - type WafShowOptions struct { - ID string - NAME string - SCOPE string - } - - shellutils.R(&WafShowOptions{}, "waf-show", "Show web acl", func(cli *aws.SRegion, args *WafShowOptions) error { - webAcl, err := cli.GetWebAcl(args.ID, args.NAME, args.SCOPE) - if err != nil { - return err - } - printObject(webAcl) - return nil - }) - - type WafDeleteOptions struct { - ID string - NAME string - SCOPE string - LOCK_TOKEN string - } - - shellutils.R(&WafDeleteOptions{}, "waf-delete", "Delete web acl", func(cli *aws.SRegion, args *WafDeleteOptions) error { - return cli.DeleteWebAcl(args.ID, args.NAME, args.SCOPE, args.LOCK_TOKEN) - }) - - type WafResourceListOptions struct { - ResType string `choices:"APPLICATION_LOAD_BALANCER|API_GATEWAY|APPSYNC"` - ARN string - } - - shellutils.R(&WafResourceListOptions{}, "waf-res-list", "List web acl resource", func(cli *aws.SRegion, args *WafResourceListOptions) error { - res, err := cli.ListResourcesForWebACL(args.ResType, args.ARN) - if err != nil { - return err - } - fmt.Println("res:", res) - return nil - }) - - type WafAddRuleOptions struct { - WafShowOptions - - RULE_FILE string - } - - shellutils.R(&WafAddRuleOptions{}, "waf-add-rule", "Add web acl rule", func(cli *aws.SRegion, args *WafAddRuleOptions) error { - waf, err := cli.GetWebAcl(args.ID, args.NAME, args.SCOPE) - if err != nil { - return errors.Wrapf(err, "GetWebAcl") - } - data, err := ioutil.ReadFile(args.RULE_FILE) - if err != nil { - return errors.Wrapf(err, "ReadFile") - } - params, err := jsonutils.Parse(data) - if err != nil { - return errors.Wrapf(err, "Parse") - } - rule := &cloudprovider.SWafRule{} - params.Unmarshal(rule) - _, err = waf.AddRule(rule) - return err - }) - -} diff --git a/pkg/multicloud/aws/shell/zone.go b/pkg/multicloud/aws/shell/zone.go deleted file mode 100644 index 5f61ff2a54..0000000000 --- a/pkg/multicloud/aws/shell/zone.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/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 - }) -} diff --git a/pkg/multicloud/aws/snapshot.go b/pkg/multicloud/aws/snapshot.go deleted file mode 100644 index 7c4a1d2ba2..0000000000 --- a/pkg/multicloud/aws/snapshot.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "strings" - - "github.com/aws/aws-sdk-go/service/ec2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SnapshotStatusType string - -const ( - SnapshotStatusAccomplished SnapshotStatusType = "completed" - SnapshotStatusProgress SnapshotStatusType = "pending" - SnapshotStatusFailed SnapshotStatusType = "error" -) - -type SSnapshot struct { - multicloud.SResourceBase - multicloud.AwsTags - region *SRegion - - Progress string - SnapshotId string - SnapshotName string - SourceDiskId string - SourceDiskSize int32 - SourceDiskType string - Status SnapshotStatusType - Usage string - //TagSpec TagSpec -} - -func (self *SSnapshot) GetDiskType() string { - // todo: self.SourceDiskType - return "" -} - -func (self *SSnapshot) GetId() string { - return self.SnapshotId -} - -func (self *SSnapshot) GetName() string { - if len(self.SnapshotName) == 0 { - return self.SnapshotId - } - - 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 api.SNAPSHOT_READY - } else if self.Status == SnapshotStatusProgress { - return api.SNAPSHOT_CREATING - } else { // if self.Status == SnapshotStatusFailed - return api.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 errors.Wrap(cloudprovider.ErrNotFound, "GetSnapshots") - } else if err := jsonutils.Update(self, snapshots[0]); err != nil { - return err - } - return nil -} - -func (self *SSnapshot) IsEmulated() bool { - return false -} - -func (self *SSnapshot) GetSizeMb() int32 { - return self.SourceDiskSize * 1024 -} - -func (self *SSnapshot) GetDiskId() string { - return self.SourceDiskId -} - -func (self *SSnapshot) Delete() error { - return self.region.DeleteSnapshot(self.SnapshotId) -} - -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) - } - - if len(snapshotName) > 0 { - filters = AppendSingleValueFilter(filters, "tag:Name", snapshotName) - } - - if len(filters) > 0 { - params.SetFilters(filters) - } - - if len(snapshotIds) > 0 { - params.SetSnapshotIds(ConvertedList(snapshotIds)) - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, 0, errors.Wrap(err, "getEc2Client") - } - ret, err := ec2Client.DescribeSnapshots(params) - err = parseNotFoundError(err) - if err != nil { - if strings.Contains(err.Error(), "InvalidSnapshot.NotFound") { - return nil, 0, errors.Wrap(cloudprovider.ErrNotFound, "parseNotFoundError") - } - - return nil, 0, err - } - - snapshots := []SSnapshot{} - for _, item := range ret.Snapshots { - if err := FillZero(item); err != nil { - return nil, 0, err - } - - tagspec := TagSpec{ResourceType: "snapshot"} - tagspec.LoadingEc2Tags(item.Tags) - - 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 - snapshot.SnapshotName = tagspec.GetNameTag() - jsonutils.Update(&snapshot.AwsTags.TagSet, item.Tags) - 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, errors.Wrap(err, "GetSnapshots") - } else if total != 1 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetSnapshots") - } 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) - log.Debugf("CreateSnapshots with params %s", params) - ec2Client, err := self.getEc2Client() - if err != nil { - return "", errors.Wrap(err, "getEc2Client") - } - - ret, err := ec2Client.CreateSnapshot(params) - if err != nil { - return "", errors.Wrap(err, "CreateSnapshot") - } - return StrVal(ret.SnapshotId), nil -} - -func (self *SRegion) DeleteSnapshot(snapshotId string) error { - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - params := &ec2.DeleteSnapshotInput{} - params.SetSnapshotId(snapshotId) - _, err = ec2Client.DeleteSnapshot(params) - return errors.Wrap(err, "DeleteSnapshot") -} - -func (self *SSnapshot) GetProjectId() string { - return "" -} diff --git a/pkg/multicloud/aws/storage.go b/pkg/multicloud/aws/storage.go deleted file mode 100644 index df24617ca8..0000000000 --- a/pkg/multicloud/aws/storage.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - multicloud.SStorageBase - multicloud.STagBase - zone *SZone - storageType string -} - -func (self *SStorage) GetId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetName() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetGlobalId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) -} - -func (self *SStorage) GetStatus() string { - if self.storageType == api.STORAGE_IO2_SSD { - regionId := self.zone.region.RegionId - // hard code - if utils.IsInStringArray(regionId, []string{ - "sa-east-1", - "eu-west-3", - "ap-northeast-3", - "ap-southeast-3", - "af-south-1", - - "cn-northwest-1", - "cn-north-1", - }) { - return api.STORAGE_OFFLINE - } - } - return api.STORAGE_ONLINE -} - -func (self *SStorage) Refresh() error { - return nil -} - -func (self *SStorage) IsEmulated() bool { - return true -} - -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, errors.Wrap(err, "GetDisks") - } - 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 == api.STORAGE_GP2_SSD || self.storageType == api.STORAGE_IO1_SSD || self.storageType == api.STORAGE_IO2_SSD { - return api.DISK_TYPE_SSD - } else { - return api.DISK_TYPE_ROTATE - } -} - -func (self *SStorage) GetCapacityMB() int64 { - return 0 // unlimited -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - conf := jsonutils.NewDict() - return conf -} - -func (self *SStorage) GetEnabled() bool { - return true -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - diskId, err := self.zone.region.CreateDisk(self.zone.ZoneId, self.storageType, conf.Name, conf.SizeGb, "", conf.Desc) - if err != nil { - log.Errorf("createDisk fail %s", err) - return nil, errors.Wrap(err, "CreateDisk") - } - disk, err := self.zone.region.GetDisk(diskId) - if err != nil { - log.Errorf("getDisk %s fail %s", diskId, err) - return nil, errors.Wrap(err, "GetDisk") - } - disk.storage = self - return disk, nil -} - -func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - if disk, err := self.zone.region.GetDisk(idStr); err != nil { - log.Errorf("GetDisk %s: %s", idStr, err) - return nil, errors.Wrap(err, "GetDisk") - } else { - disk.storage = self - return disk, nil - } -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} diff --git a/pkg/multicloud/aws/storagecache.go b/pkg/multicloud/aws/storagecache.go deleted file mode 100644 index a0448f7158..0000000000 --- a/pkg/multicloud/aws/storagecache.go +++ /dev/null @@ -1,496 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "context" - "fmt" - "strings" - "time" - - "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/pkg/errors" - - "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" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.AwsTags - region *SRegion -} - -func (self *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) -} - -func (self *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) -} - -func (self *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, 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) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - images, err := self.region.GetImages("", ImageOwnerSelf, nil, "", "hvm", nil, "", true) - if err != nil { - return nil, errors.Wrapf(err, "GetImages") - } - ret := []cloudprovider.ICloudImage{} - for i := 0; i < len(images); i += 1 { - images[i].storageCache = self - ret = append(ret, &images[i]) - } - return ret, nil -} - -func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - if len(extId) == 0 { - return nil, fmt.Errorf("GetIImageById image id should not be empty") - } - - part, err := self.region.GetImage(extId) - if err != nil { - log.Errorf("GetImage %s %s", extId, err) - return nil, errors.Wrap(err, "GetImage") - } - part.storageCache = self - return part, nil -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - imageId, err := self.region.createIImage(snapshotId, imageName, imageDesc) - if err != nil { - log.Errorf("createIImage %s %s %s: %s", snapshotId, imageName, imageDesc, err) - return nil, errors.Wrap(err, "createIImage") - } - image, err := self.region.GetImage(imageId) - if err != nil { - log.Errorf("GetImage %s: %s", imageId, err) - return nil, errors.Wrap(err, "GetImage") - } - 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, errors.Wrap(err, "WaitStatus.iimage") - } - 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(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return self.uploadImage(ctx, userCred, image, callback) - -} - -func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - err := self.region.initVmimport() - if err != nil { - return "", errors.Wrap(err, "initVmimport") - } - - bucketName := GetBucketName(self.region.GetId(), image.ImageId) - - exist, err := self.region.IBucketExist(bucketName) - if err != nil { - return "", errors.Wrap(err, "IBucketExist") - } - - if !exist { - err = self.region.CreateIBucket(bucketName, "", "") - if err != nil { - return "", errors.Wrap(err, "CreateIBucket") - } - } - - defer self.region.DeleteIBucket(bucketName) - - s := auth.GetAdminSession(ctx, options.Options.Region) - meta, reader, sizeBytes, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) - if err != nil { - return "", errors.Wrap(err, "Images.Download") - } - log.Debugf("Images meta data %s", meta) - - diskFormat, _ := meta.GetString("disk_format") - - bucket, err := self.region.GetIBucketByName(bucketName) - if err != nil { - return "", errors.Wrap(err, "GetIBucketByName") - } - body := multicloud.NewProgress(sizeBytes, 80, reader, callback) - err = cloudprovider.UploadObject(ctx, bucket, image.ImageId, 0, body, sizeBytes, "", "", nil, false) - if err != nil { - return "", errors.Wrap(err, "cloudprovider.UploadObject") - } - - defer bucket.DeleteObject(ctx, image.ImageId) - - imageBaseName := image.ImageId - if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { - imageBaseName = fmt.Sprintf("img%s", image.ImageId) - } - imageName := imageBaseName - nameIdx := 1 - - // check image name, avoid name conflict - for { - _, err = self.region.GetImageByName(imageName, ImageOwnerSelf) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - break - } else { - return "", err - } - } - - imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) - nameIdx += 1 - log.Debugf("uploadImage Match remote name %s", imageName) - } - - task, err := self.region.ImportImage(imageName, image.OsArch, image.OsType, image.OsDistribution, diskFormat, bucketName, image.ImageId) - - if err != nil { - log.Errorf("ImportImage error %s %s %s", image.ImageId, bucketName, err) - return "", err - } - - err = cloudprovider.Wait(2*time.Minute, 4*time.Hour, func() (bool, error) { - status := task.GetStatus() - if status == ImageImportStatusDeleted { - return false, errors.Wrap(errors.ErrInvalidStatus, "SStoragecache.ImageImportStatusDeleted") - } - - if status == ImageImportStatusCompleted { - return true, nil - } - - return false, nil - }) - if err != nil { - return "", errors.Wrap(err, "SStoragecache.Wait") - } - - // add name tag - self.region.addTags(task.ImageId, "Name", image.ImageId) - if callback != nil { - callback(100) - } - return task.ImageId, nil -} - -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 := GetBucketName(self.region.GetId(), imageId) - if err := self.region.checkBucket(bucketName); err != nil { - log.Errorf("checkBucket %s: %s", bucketName, err) - return nil, errors.Wrap(err, "checkBucket") - } - - instanceId, err := self.region.GetInstanceIdByImageId(extId) - if err != nil { - log.Errorf("GetInstanceIdByImageId %s: %s", extId, err) - return nil, errors.Wrap(err, "GetInstanceIdByImageId") - } - - ec2Client, err := self.region.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - task, err := self.region.ExportImage(instanceId, imageId) - if err != nil { - log.Errorf("ExportImage %s %s: %s", instanceId, imageId, err) - return nil, errors.Wrap(err, "ExportImage") - } - - taskParams := &ec2.DescribeExportTasksInput{} - taskParams.SetExportTaskIds([]*string{&task.TaskId}) - if err := ec2Client.WaitUntilExportTaskCompleted(taskParams); err != nil { - log.Errorf("WaitUntilExportTaskCompleted %#v %s", taskParams, err) - return nil, errors.Wrap(err, "WaitUntilExportTaskCompleted") - } - - s3Client, err := self.region.GetS3Client() - if err != nil { - return nil, errors.Wrap(err, "GetS3Client") - } - - i := &s3.GetObjectInput{} - i.SetBucket(bucketName) - i.SetKey(fmt.Sprintf("%s.%s", task.TaskId, "ova")) - ret, err := s3Client.GetObject(i) - if err != nil { - log.Errorf("GetObject %#v: %s", i, err) - return nil, errors.Wrap(err, "GetObject") - } - - s := auth.GetAdminSession(context.Background(), 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, errors.Wrap(err, "Images.Images") - } 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 { - log.Errorf("IsBucketExist %s: %s", bucketName, err) - return errors.Wrap(err, "IsBucketExist") - } - - 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, errors.Wrap(err, "IsBucketExist.GetS3Client") - } - - params := &s3.ListBucketsInput{} - ret, err := s3Client.ListBuckets(params) - if err != nil { - return false, errors.Wrap(err, "ListBuckets") - } - - for _, bucket := range ret.Buckets { - if bucket.Name != nil && *bucket.Name == bucketName { - return true, nil - } - } - - return false, nil -} - -func (self *SRegion) GetBucketRegionId(bucketName string) (string, error) { - s3Client, err := self.GetS3Client() - if err != nil { - return "", err - } - - params := &s3.GetBucketLocationInput{Bucket: &bucketName} - ret, err := s3Client.GetBucketLocation(params) - if err != nil { - return "", err - } - - return StrVal(ret.LocationConstraint), 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-*")) - params.SetPolicyName(policyName) - params.SetRoleName(roleName) - _, err = iamClient.PutRolePolicy(params) - return err - } -} - -func (self *SRegion) initVmimport() error { - if err := self.initVmimportRole(); err != nil { - return err - } - - if err := self.initVmimportRolePolicy(); 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) - - ec2Client, err := self.getEc2Client() - if err != nil { - return "", errors.Wrap(err, "getEc2Client") - } - ret, err := 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 -} - -func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storageCache := region.getStoragecache() - return []cloudprovider.ICloudStoragecache{storageCache}, nil -} diff --git a/pkg/multicloud/aws/utils.go b/pkg/multicloud/aws/utils.go deleted file mode 100644 index 8d88ace00e..0000000000 --- a/pkg/multicloud/aws/utils.go +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "net" - "reflect" - "sort" - "strings" - - "github.com/aws/aws-sdk-go/service/ec2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -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) GetTags() (map[string]string, error) { - ret := map[string]string{} - for k, v := range self.Tags { - if k == "Name" || k == "Description" { - continue - } - ret[k] = v - } - return ret, nil -} - -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 i := range list { - if len(list[i]) > 0 { - result = append(result, &list[i]) - } - } - - return result -} - -func GetBucketName(regionId string, imageId string) string { - return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), imageId) -} - -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 -} - -// SecurityRuleSet to allow list -// 将安全组规则全部转换为等价的allow规则 -func SecurityRuleSetToAllowSet(srs secrules.SecurityRuleSet) secrules.SecurityRuleSet { - inRuleSet := secrules.SecurityRuleSet{} - outRuleSet := secrules.SecurityRuleSet{} - - for _, rule := range srs { - if rule.Direction == secrules.SecurityRuleIngress { - inRuleSet = append(inRuleSet, rule) - } - - if rule.Direction == secrules.SecurityRuleEgress { - outRuleSet = append(outRuleSet, rule) - } - } - - sort.Sort(inRuleSet) - sort.Sort(outRuleSet) - - inRuleSet = inRuleSet.AllowList() - outRuleSet = outRuleSet.AllowList() - - ret := secrules.SecurityRuleSet{} - ret = append(ret, inRuleSet...) - ret = append(ret, outRuleSet...) - return ret -} - -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 cloudprovider.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 cloudprovider.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 i := range r.Ports { - port := r.Ports[i] - 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) ([]cloudprovider.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 := []cloudprovider.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 cloudprovider.SecurityRule - if isAllPorts { - rule = cloudprovider.SecurityRule{ - SecurityRule: secrules.SecurityRule{ - Action: secrules.SecurityRuleAllow, - IPNet: ipNet, - Protocol: protocol, - Direction: direction, - Priority: 1, - Description: StrVal(ip.Description), - }, - } - } else { - rule = cloudprovider.SecurityRule{ - SecurityRule: 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 -} - -// YunionSecRuleToAws 不能保证无损转换 -// 规则描述如果包含中文等字符,将被丢弃掉 -func YunionSecRuleToAws(rule cloudprovider.SecurityRule) ([]*ec2.IpPermission, error) { - iprange := rule.IPNet.String() - if iprange == "" { - return nil, fmt.Errorf("YunionSecRuleToAws ignored ipnet should not be empty") - } - - ipranges := []*ec2.IpRange{} - ipranges = append(ipranges, &ec2.IpRange{CidrIp: &iprange}) - - portranges := yunionPortRangeToAws(rule) - protocol := yunionProtocolToAws(rule) - permissions := []*ec2.IpPermission{} - if rule.Protocol != secrules.PROTO_ANY { - for i := range portranges { - port := portranges[i] - permission := ec2.IpPermission{ - FromPort: &port.Start, - IpProtocol: &protocol, - IpRanges: ipranges, - ToPort: &port.End, - } - - permissions = append(permissions, &permission) - } - } else { - permissions = append(permissions, &ec2.IpPermission{ - IpProtocol: &protocol, - IpRanges: ipranges, - }) - } - - 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%c", byte(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%c", byte(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 -} - -// error -func parseNotFoundError(err error) error { - if err == nil { - return nil - } - - if strings.Contains(err.Error(), ".NotFound") { - return errors.Wrap(cloudprovider.ErrNotFound, "parseNotFoundError") - } else { - return err - } -} diff --git a/pkg/multicloud/aws/vpc.go b/pkg/multicloud/aws/vpc.go deleted file mode 100644 index dec6b5c6a6..0000000000 --- a/pkg/multicloud/aws/vpc.go +++ /dev/null @@ -1,723 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - "strings" - "time" - - "github.com/aws/aws-sdk-go/service/ec2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SUserCIDRs struct { - UserCidr []string -} - -type SVpc struct { - multicloud.SVpc - multicloud.AwsTags - - region *SRegion - - iwires []cloudprovider.ICloudWire - secgroups []cloudprovider.ICloudSecurityGroup - - RegionId string - VpcId string - VpcName string - CidrBlock string - CidrBlockAssociationSet []string - IsDefault bool - Status string - InstanceTenancy 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 { - // 目前不支持专用主机 - if self.InstanceTenancy == "dedicated" { - return api.VPC_STATUS_UNAVAILABLE - } - 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) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetIsDefault() bool { - return self.IsDefault -} - -func (self *SVpc) GetCidrBlock() string { - return strings.Join(self.CidrBlockAssociationSet, ",") -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - if self.iwires == nil { - err := self.fetchNetworks() - if err != nil { - return nil, errors.Wrap(err, "fetchNetworks") - } - } - return self.iwires, nil -} - -func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - if self.secgroups == nil { - err := self.fetchSecurityGroups() - if err != nil { - return nil, errors.Wrap(err, "fetchSecurityGroups") - } - } - return self.secgroups, nil -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - tables, err := self.region.GetRouteTables(self.GetId(), false) - if err != nil { - return nil, errors.Wrap(err, "SVpc.GetIRouteTables") - } - - itables := make([]cloudprovider.ICloudRouteTable, len(tables)) - for i := range tables { - tables[i].vpc = self - itables[i] = &tables[i] - } - - return itables, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - routeTable, err := self.region.GetRouteTable(routeTableId) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetRouteTable(routeTableId:%s)", routeTableId) - } - routeTable.vpc = self - return routeTable, nil -} - -/* -Deletes the specified VPC. You must detach or delete all gateways and resources that are associated with -the VPC before you can delete it. For example, you must terminate all instances running in the VPC, -delete all security groups associated with the VPC (except the default one), -delete all route tables associated with the VPC (except the default one), and so on. -*/ -func (self *SVpc) Delete() error { - err := self.DeleteInternetGateways() - if err != nil { - return errors.Wrap(err, "DeleteInternetGateways") - } - - // 删除路由表. todo: 3.7版本路由表开放之后,需要同步状态到平台 - rts, err := self.GetIRouteTables() - if err != nil { - return errors.Wrap(err, "GetIRouteTables") - } - - for i := range rts { - // 主路由表不允许删除 - rt := rts[i].(*SRouteTable) - if len(rt.Associations) > 0 { - if rt.Associations[0].Main { - log.Debugf("Delete.RouteTable skipped main route table %s(%s)", rt.GetName(), rt.GetId()) - continue - } - } - - err = self.region.DeleteRouteTable(rts[i].GetId()) - if err != nil { - return errors.Wrap(err, "DeleteRouteTable") - } - } - - 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, errors.Wrap(err, "fetchNetworks") - } - } - for i := 0; i < len(self.iwires); i += 1 { - if self.iwires[i].GetGlobalId() == wireId { - return self.iwires[i], nil - } - } - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIWireById") -} - -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) - if err != nil { - return errors.Wrapf(err, "GetNetwroks(%s)", self.VpcId) - } - - 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 { - if len(self.VpcId) == 0 { - return fmt.Errorf("fetchSecurityGroups vpc id is empty") - } - - secgroups, _, err := self.region.GetSecurityGroups(self.VpcId, "", "", 0, 0) - if err != nil { - return errors.Wrap(err, "GetSecurityGroups") - } - - 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 *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPCs, err := self.getRequesterVpcPeeringConnections() - if err != nil { - return nil, errors.Wrap(err, "self.getSVpcPeeringConnections()") - } - ret := []cloudprovider.ICloudVpcPeeringConnection{} - for i := range svpcPCs { - ret = append(ret, svpcPCs[i]) - } - return ret, nil -} - -func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPCs, err := self.getAccepterVpcPeeringConnections() - if err != nil { - return nil, errors.Wrap(err, "self.getAccepterVpcPeeringConnections()") - } - ret := []cloudprovider.ICloudVpcPeeringConnection{} - for i := range svpcPCs { - ret = append(ret, svpcPCs[i]) - } - return ret, nil -} - -func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { - vpcPc, err := self.getSVpcPeeringConnectionById(id) - if err != nil { - return nil, errors.Wrapf(err, "getSVpcPeeringConnectionById(%s)", id) - } - return vpcPc, nil -} - -func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { - return self.createSVpcPeeringConnection(opts) -} - -func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { - return self.acceptSVpcPeeringConnection(id) -} - -func (self *SVpc) GetAuthorityOwnerId() string { - identity, err := self.region.client.GetCallerIdentity() - if err != nil { - log.Errorf(err.Error() + "self.region.client.GetCallerIdentity()") - return "" - } - return identity.Account -} - -func (self *SVpc) getSVpcPeeringConnectionById(id string) (*SVpcPeeringConnection, error) { - vpcPC, err := self.region.GetVpcPeeringConnectionById(id) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetVpcPeeringConnectionById(%s)", id) - } - if vpcPC.Status.Code != nil && (*vpcPC.Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleted || - *vpcPC.Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleting) { - return nil, cloudprovider.ErrNotFound - } - svpcPC := SVpcPeeringConnection{} - svpcPC.vpc = self - svpcPC.vpcPC = vpcPC - return &svpcPC, nil -} - -func (self *SVpc) getRequesterVpcPeeringConnections() ([]*SVpcPeeringConnection, error) { - vpcPCs, err := self.region.DescribeRequesterVpcPeeringConnections(self.VpcId) - if err != nil { - return nil, errors.Wrap(err, "self.region.DescribeRequesterVpcPeeringConnections()") - } - ivpcPCs := []*SVpcPeeringConnection{} - for i := range vpcPCs { - if vpcPCs[i].Status.Code != nil && (*vpcPCs[i].Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleted || - *vpcPCs[i].Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleting) { - continue - } - svpcPC := SVpcPeeringConnection{} - svpcPC.vpc = self - svpcPC.vpcPC = vpcPCs[i] - ivpcPCs = append(ivpcPCs, &svpcPC) - } - return ivpcPCs, nil -} - -func (self *SVpc) getAccepterVpcPeeringConnections() ([]*SVpcPeeringConnection, error) { - vpcPCs, err := self.region.DescribeAccepterVpcPeeringConnections(self.VpcId) - if err != nil { - return nil, errors.Wrap(err, "self.region.DescribeAccepterVpcPeeringConnections()") - } - ivpcPCs := []*SVpcPeeringConnection{} - for i := range vpcPCs { - if vpcPCs[i].Status.Code != nil && (*vpcPCs[i].Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleted || - *vpcPCs[i].Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleting) { - continue - } - svpcPC := SVpcPeeringConnection{} - svpcPC.vpc = self - svpcPC.vpcPC = vpcPCs[i] - ivpcPCs = append(ivpcPCs, &svpcPC) - } - return ivpcPCs, nil -} - -func (self *SVpc) createSVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPeeringConnection, error) { - svpcPC := SVpcPeeringConnection{} - vpcPC, err := self.region.CreateVpcPeeringConnection(self.VpcId, opts) - if err != nil { - return nil, errors.Wrapf(err, " self.region.CreateVpcPeeringConnection(%s,%s)", self.VpcId, jsonutils.Marshal(opts).String()) - } - svpcPC.vpc = self - svpcPC.vpcPC = vpcPC - err = cloudprovider.WaitMultiStatus(&svpcPC, []string{api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT, - api.VPC_PEERING_CONNECTION_STATUS_ACTIVE, - api.VPC_PEERING_CONNECTION_STATUS_DELETING}, 5*time.Second, 60*time.Second) - if err != nil { - return nil, errors.Wrap(err, "cloudprovider.WaitMultiStatus") - } - if svpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_DELETING { - return nil, errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcpeeringconnection:%s invalidate status", jsonutils.Marshal(svpcPC.vpcPC).String()) - } - return &svpcPC, nil -} - -func (self *SVpc) acceptSVpcPeeringConnection(id string) error { - svpcPC, err := self.getSVpcPeeringConnectionById(id) - if err != nil { - return errors.Wrapf(err, "self.getSVpcPeeringConnectionById(%s)", id) - } - // 其他region 创建的连接请求,有短暂的provisioning状态 - err = cloudprovider.WaitMultiStatus(svpcPC, []string{api.VPC_PEERING_CONNECTION_STATUS_ACTIVE, - api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT, - api.VPC_PEERING_CONNECTION_STATUS_DELETING}, 5*time.Second, 60*time.Second) - if err != nil { - return errors.Wrap(err, "cloudprovider.WaitMultiStatus") - } - if svpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_DELETING { - return errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcpeeringconnection:%s invalidate status", jsonutils.Marshal(svpcPC.vpcPC).String()) - } - - if svpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT { - _, err := self.region.AcceptVpcPeeringConnection(id) - if err != nil { - return errors.Wrapf(err, "self.region.AcceptVpcPeeringConnection(%s)", id) - } - } - err = cloudprovider.WaitMultiStatus(svpcPC, []string{api.VPC_PEERING_CONNECTION_STATUS_ACTIVE, - api.VPC_PEERING_CONNECTION_STATUS_DELETING}, 5*time.Second, 60*time.Second) - if err != nil { - return errors.Wrap(err, "cloudprovider.WaitMultiStatus") - } - if svpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_DELETING { - return errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcpeeringconnection:%s invalidate status", jsonutils.Marshal(svpcPC.vpcPC).String()) - } - return nil -} - -func (self *SVpc) IsSupportSetExternalAccess() bool { - return true -} - -func (self *SVpc) GetExternalAccessMode() string { - igws, err := self.region.GetInternetGateways(self.GetId()) - if err != nil { - log.Errorf("GetExternalAccessMode.GetInternetGateways %s", err) - } - - if len(igws) > 0 { - return api.VPC_EXTERNAL_ACCESS_MODE_EIP - } - - return api.VPC_EXTERNAL_ACCESS_MODE_NONE -} - -func (self *SVpc) AttachInternetGateway(igwId string) error { - ec2Client, err := self.region.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - input := ec2.AttachInternetGatewayInput{} - input.SetInternetGatewayId(igwId) - input.SetVpcId(self.GetId()) - - _, err = ec2Client.AttachInternetGateway(&input) - if err != nil { - return errors.Wrap(err, "AttachInternetGateway") - } - - err = self.AddDefaultInternetGatewayRoute(igwId) - if err != nil { - return errors.Wrap(err, "AddDefaultInternetGatewayRoute") - } - - return nil -} - -func (self *SVpc) AddDefaultInternetGatewayRoute(igwId string) error { - rt, err := self.GetMainRouteTable() - if err != nil { - return errors.Wrap(err, "GetMainRouteTable") - } - - defaultRoute := cloudprovider.RouteSet{} - defaultRoute.NextHop = igwId - defaultRoute.Destination = "0.0.0.0/0" - err = rt.CreateRoute(defaultRoute) - if err != nil { - return errors.Wrap(err, "CreateRoute") - } - - return nil -} - -func (self *SVpc) GetMainRouteTable() (*SRouteTable, error) { - rt, err := self.region.GetRouteTables(self.GetId(), true) - if err != nil { - return nil, errors.Wrap(err, "GetRouteTables") - } - - if len(rt) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotSupported, "GetMainRouteTable") - } - - return &rt[0], nil -} - -func (self *SVpc) DetachInternetGateways() error { - igws, err := self.region.GetInternetGateways(self.GetId()) - if err != nil { - return errors.Wrap(err, "GetInternetGateways") - } - - if len(igws) > 0 { - for i := range igws { - err = self.DetachInternetGateway(igws[i].GetId()) - if err != nil { - return errors.Wrap(err, "DetachInternetGateway") - } - } - } - - return nil -} - -func (self *SVpc) DetachInternetGateway(igwId string) error { - ec2Client, err := self.region.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - input := ec2.DetachInternetGatewayInput{} - input.SetInternetGatewayId(igwId) - input.SetVpcId(self.GetId()) - - _, err = ec2Client.DetachInternetGateway(&input) - if err != nil { - return errors.Wrap(err, "DetachInternetGateway") - } - - return nil -} - -func (self *SVpc) DeleteInternetGateway(igwId string) error { - ec2Client, err := self.region.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - input := ec2.DeleteInternetGatewayInput{} - input.SetInternetGatewayId(igwId) - - _, err = ec2Client.DeleteInternetGateway(&input) - if err != nil { - return errors.Wrap(err, "DeleteInternetGateway") - } - - return nil -} - -func (self *SVpc) DeleteInternetGateways() error { - igws, err := self.region.GetInternetGateways(self.GetId()) - if err != nil { - return errors.Wrap(err, "GetInternetGateways") - } - - if len(igws) > 0 { - for i := range igws { - err = self.DetachInternetGateway(igws[i].GetId()) - if err != nil { - return errors.Wrap(err, "DetachInternetGateway") - } - - err = self.DeleteInternetGateway(igws[i].GetId()) - if err != nil { - return errors.Wrap(err, "DeleteInternetGateway") - } - } - } - - return nil -} - -func (self *SRegion) getVpc(vpcId string) (*SVpc, error) { - if len(vpcId) == 0 { - return nil, fmt.Errorf("GetVpc vpc id should not be empty.") - } - - vpcs, err := self.GetVpcs([]string{vpcId}) - if err != nil { - return nil, errors.Wrap(err, "GetVpcs") - } - if len(vpcs) != 1 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "getVpc") - } - vpcs[0].region = self - return &vpcs[0], nil -} - -func (self *SRegion) revokeSecurityGroup(secgroupId, instanceId string, keep bool) error { - // todo : keep ? 直接使用assignSecurityGroup 即可? - return nil -} - -func (self *SRegion) assignSecurityGroup(secgroupId, instanceId string) error { - return self.assignSecurityGroups([]*string{&secgroupId}, instanceId) -} - -func (self *SRegion) assignSecurityGroups(secgroupIds []*string, instanceId string) error { - instance, err := self.GetInstance(instanceId) - if err != nil { - return errors.Wrap(err, "GetInstance") - } - - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - for _, eth := range instance.NetworkInterfaces { - params := &ec2.ModifyNetworkInterfaceAttributeInput{} - params.SetNetworkInterfaceId(eth.NetworkInterfaceId) - params.SetGroups(secgroupIds) - - _, err := ec2Client.ModifyNetworkInterfaceAttribute(params) - if err != nil { - return err - } - } - - return nil -} - -func (self *SRegion) DeleteSecurityGroup(secGrpId string) error { - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - params := &ec2.DeleteSecurityGroupInput{} - params.SetGroupId(secGrpId) - - _, err = ec2Client.DeleteSecurityGroup(params) - return errors.Wrap(err, "DeleteSecurityGroup") -} - -func (self *SRegion) DeleteVpc(vpcId string) error { - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - params := &ec2.DeleteVpcInput{} - params.SetVpcId(vpcId) - - _, err = ec2Client.DeleteVpc(params) - return errors.Wrap(err, "DeleteVpc") -} - -func (self *SRegion) GetVpcs(vpcId []string) ([]SVpc, error) { - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - params := &ec2.DescribeVpcsInput{} - if len(vpcId) > 0 { - params.SetVpcIds(ConvertedList(vpcId)) - } - - ret, err := ec2Client.DescribeVpcs(params) - err = parseNotFoundError(err) - if err != nil { - return nil, err - } - - vpcs := []SVpc{} - for _, item := range ret.Vpcs { - if err := FillZero(item); err != nil { - return nil, err - } - cidrBlockAssociationSet := []string{} - for i := range item.CidrBlockAssociationSet { - cidr := item.CidrBlockAssociationSet[i] - if cidr.CidrBlockState.State != nil && *cidr.CidrBlockState.State == "associated" { - cidrBlockAssociationSet = append(cidrBlockAssociationSet, *cidr.CidrBlock) - } - } - - tagspec := TagSpec{ResourceType: "vpc"} - tagspec.LoadingEc2Tags(item.Tags) - - vpc := SVpc{ - region: self, - RegionId: self.RegionId, - VpcId: *item.VpcId, - VpcName: tagspec.GetNameTag(), - CidrBlock: *item.CidrBlock, - CidrBlockAssociationSet: cidrBlockAssociationSet, - IsDefault: *item.IsDefault, - Status: *item.State, - InstanceTenancy: *item.InstanceTenancy, - } - jsonutils.Update(&vpc.AwsTags.TagSet, item.Tags) - vpcs = append(vpcs, vpc) - } - - return vpcs, nil -} - -func (self *SRegion) GetInternetGateways(vpcId string) ([]SInternetGateway, error) { - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - input := ec2.DescribeInternetGatewaysInput{} - filters := make([]*ec2.Filter, 0) - if len(vpcId) > 0 { - filters = AppendSingleValueFilter(filters, "attachment.vpc-id", vpcId) - } - - if len(filters) > 0 { - input.SetFilters(filters) - } - output, err := ec2Client.DescribeInternetGateways(&input) - if err != nil { - return nil, errors.Wrap(err, "DescribeInternetGateways") - } - - igws := make([]SInternetGateway, len(output.InternetGateways)) - err = unmarshalAwsOutput(output, "InternetGateways", &igws) - if err != nil { - return nil, errors.Wrap(err, "unmarshalAwsOutput") - } - - for i := range igws { - igws[i].region = self - } - - return igws, nil -} diff --git a/pkg/multicloud/aws/vpc_peering_connection.go b/pkg/multicloud/aws/vpc_peering_connection.go deleted file mode 100644 index de7c32c122..0000000000 --- a/pkg/multicloud/aws/vpc_peering_connection.go +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "github.com/aws/aws-sdk-go/service/ec2" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -func (self *SRegion) DescribeVpcPeeringConnections(vpcId string) ([]*ec2.VpcPeeringConnection, error) { - result := []*ec2.VpcPeeringConnection{} - requestvpcPCs, err := self.DescribeRequesterVpcPeeringConnections(vpcId) - if err != nil { - return nil, errors.Wrapf(err, "self.DescribeRequesterVpcPeeringConnections(%s)", vpcId) - } - result = append(result, requestvpcPCs...) - acceptvpcPCs, err := self.DescribeAccepterVpcPeeringConnections(vpcId) - if err != nil { - return nil, errors.Wrapf(err, "self.DescribeRequesterVpcPeeringConnections(%s)", vpcId) - } - result = append(result, acceptvpcPCs...) - return result, nil -} - -func (self *SRegion) DescribeRequesterVpcPeeringConnections(vpcId string) ([]*ec2.VpcPeeringConnection, error) { - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - params := ec2.DescribeVpcPeeringConnectionsInput{} - result := []*ec2.VpcPeeringConnection{} - var maxResult int64 = 20 - params.MaxResults = &maxResult - filter := ec2.Filter{} - filter.Values = []*string{&vpcId} - // request peeringConnection - filterName := "requester-vpc-info.vpc-id" - - filter.Name = &filterName - params.Filters = []*ec2.Filter{&filter} - for { - ret, err := ec2Client.DescribeVpcPeeringConnections(¶ms) - if err != nil { - return nil, errors.Wrapf(err, "self.ec2Client.DescribeVpcPeeringConnections(%s)", jsonutils.Marshal(params).String()) - } - result = append(result, ret.VpcPeeringConnections...) - if ret.NextToken == nil { - break - } - params.NextToken = ret.NextToken - } - return result, nil -} - -func (self *SRegion) DescribeAccepterVpcPeeringConnections(vpcId string) ([]*ec2.VpcPeeringConnection, error) { - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - params := ec2.DescribeVpcPeeringConnectionsInput{} - result := []*ec2.VpcPeeringConnection{} - var maxResult int64 = 20 - params.MaxResults = &maxResult - filter := ec2.Filter{} - filter.Values = []*string{&vpcId} - // accept peeringConnection - filterName := "accepter-vpc-info.vpc-id" - filter.Name = &filterName - params.Filters = []*ec2.Filter{&filter} - for { - ret, err := ec2Client.DescribeVpcPeeringConnections(¶ms) - if err != nil { - return nil, errors.Wrapf(err, "self.ec2Client.DescribeVpcPeeringConnections(%s)", jsonutils.Marshal(params).String()) - } - result = append(result, ret.VpcPeeringConnections...) - if ret.NextToken == nil { - break - } - params.NextToken = ret.NextToken - } - return result, nil -} - -func (self *SRegion) GetVpcPeeringConnectionById(Id string) (*ec2.VpcPeeringConnection, error) { - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - params := ec2.DescribeVpcPeeringConnectionsInput{} - result := []*ec2.VpcPeeringConnection{} - var maxResult int64 = 20 - params.MaxResults = &maxResult - filter := ec2.Filter{} - filter.Values = []*string{&Id} - filterName := "vpc-peering-connection-id" - filter.Name = &filterName - params.Filters = []*ec2.Filter{&filter} - for { - ret, err := ec2Client.DescribeVpcPeeringConnections(¶ms) - if err != nil { - return nil, errors.Wrapf(err, "self.ec2Client.DescribeVpcPeeringConnections(%s)", jsonutils.Marshal(params).String()) - } - result = append(result, ret.VpcPeeringConnections...) - if ret.NextToken == nil { - break - } - params.NextToken = ret.NextToken - } - if len(result) < 1 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetVpcPeeringConnectionById(%s)", Id) - } - if len(result) > 1 { - return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "GetVpcPeeringConnectionById(%s)", Id) - } - return result[0], nil -} - -func (self *SRegion) CreateVpcPeeringConnection(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*ec2.VpcPeeringConnection, error) { - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - params := ec2.CreateVpcPeeringConnectionInput{} - params.VpcId = &vpcId - params.PeerVpcId = &opts.PeerVpcId - params.PeerRegion = &opts.PeerRegionId - params.PeerOwnerId = &opts.PeerAccountId - ret, err := ec2Client.CreateVpcPeeringConnection(¶ms) - if err != nil { - return nil, errors.Wrapf(err, "self.ec2Client.CreateVpcPeeringConnection(%s)", jsonutils.Marshal(params).String()) - } - // add tags - tagParams := ec2.CreateTagsInput{} - tagParams.Resources = []*string{ret.VpcPeeringConnection.VpcPeeringConnectionId} - nametag := "Name" - desctag := "Description" - tagParams.Tags = []*ec2.Tag{{Key: &nametag, Value: &opts.Name}, {Key: &desctag, Value: &opts.Desc}} - _, err = ec2Client.CreateTags(&tagParams) - if err != nil { - return nil, errors.Wrapf(err, "self.ec2Client.CreateTags(%s)", jsonutils.Marshal(tagParams).String()) - } - ret.VpcPeeringConnection.Tags = tagParams.Tags - return ret.VpcPeeringConnection, nil -} - -func (self *SRegion) DeleteVpcPeeringConnection(vpcPeeringConnectionId string) error { - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - params := ec2.DeleteVpcPeeringConnectionInput{} - params.VpcPeeringConnectionId = &vpcPeeringConnectionId - _, err = ec2Client.DeleteVpcPeeringConnection(¶ms) - if err != nil { - return errors.Wrapf(err, "self.ec2Client.DeleteVpcPeeringConnection(%s)", jsonutils.Marshal(params).String()) - } - return nil -} - -func (self *SRegion) AcceptVpcPeeringConnection(vpcPeeringConnectionId string) (*ec2.VpcPeeringConnection, error) { - ec2Client, err := self.getEc2Client() - if err != nil { - return nil, errors.Wrap(err, "getEc2Client") - } - - params := ec2.AcceptVpcPeeringConnectionInput{} - params.VpcPeeringConnectionId = &vpcPeeringConnectionId - ret, err := ec2Client.AcceptVpcPeeringConnection(¶ms) - if err != nil { - return nil, errors.Wrapf(err, "self.ec2Client.AcceptVpcPeeringConnection(%s)", jsonutils.Marshal(params).String()) - } - return ret.VpcPeeringConnection, nil -} - -func (self *SRegion) DeleteVpcPeeringConnectionRoute(vpcPeeringConnectionId string) error { - ec2Client, err := self.getEc2Client() - if err != nil { - return errors.Wrap(err, "getEc2Client") - } - - input := &ec2.DescribeRouteTablesInput{} - filters := make([]*ec2.Filter, 0) - filters = AppendSingleValueFilter(filters, "association.main", "true") - filters = AppendSingleValueFilter(filters, "route.vpc-peering-connection-id", vpcPeeringConnectionId) - input.SetFilters(filters) - routeTables := []*ec2.RouteTable{} - for { - ret, err := ec2Client.DescribeRouteTables(input) - if err != nil { - return errors.Wrap(err, "SRegion.GetRouteTables.DescribeRouteTables") - } - routeTables = append(routeTables, ret.RouteTables...) - input.NextToken = ret.NextToken - if ret.NextToken == nil { - break - } - } - for i := range routeTables { - if routeTables[i] != nil && routeTables[i].RouteTableId != nil && routeTables[i].Routes != nil { - for j := range routeTables[i].Routes { - if routeTables[i].Routes[j] != nil && - routeTables[i].Routes[j].VpcPeeringConnectionId != nil && - *routeTables[i].Routes[j].VpcPeeringConnectionId == vpcPeeringConnectionId && - routeTables[i].Routes[j].DestinationCidrBlock != nil { - err := self.RemoveRoute(*routeTables[i].RouteTableId, *routeTables[i].Routes[j].DestinationCidrBlock) - if err != nil { - return errors.Wrapf(err, "self.RemoveRoute(%s,%s)", *routeTables[i].RouteTableId, *routeTables[i].Routes[j].DestinationCidrBlock) - } - } - } - } - } - return nil -} - -type SVpcPeeringConnection struct { - multicloud.SResourceBase - multicloud.AwsTags - vpc *SVpc - vpcPC *ec2.VpcPeeringConnection -} - -func (self *SVpcPeeringConnection) GetId() string { - if self.vpcPC.VpcPeeringConnectionId != nil { - return *self.vpcPC.VpcPeeringConnectionId - } - return "" -} - -// tags? -func (self *SVpcPeeringConnection) GetName() string { - for i := range self.vpcPC.Tags { - if self.vpcPC.Tags[i] != nil && self.vpcPC.Tags[i].Key != nil && - *self.vpcPC.Tags[i].Key == "Name" && self.vpcPC.Tags[i].Value != nil { - return *self.vpcPC.Tags[i].Value - } - } - return self.GetId() -} - -func (self *SVpcPeeringConnection) GetGlobalId() string { - return self.GetId() -} - -func (self *SVpcPeeringConnection) GetStatus() string { - if self.vpcPC.Status.Code != nil { - switch *self.vpcPC.Status.Code { - case ec2.VpcPeeringConnectionStateReasonCodeInitiatingRequest, ec2.VpcPeeringConnectionStateReasonCodeProvisioning: - return api.VPC_PEERING_CONNECTION_STATUS_CREATING - case ec2.VpcPeeringConnectionStateReasonCodePendingAcceptance: - return api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT - case ec2.VpcPeeringConnectionStateReasonCodeActive: - return api.VPC_PEERING_CONNECTION_STATUS_ACTIVE - case ec2.VpcPeeringConnectionStateReasonCodeDeleted, ec2.VpcPeeringConnectionStateReasonCodeDeleting: - return api.VPC_PEERING_CONNECTION_STATUS_DELETING - default: - return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN - } - } - return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN -} - -func (self *SVpcPeeringConnection) Refresh() error { - vpcPC, err := self.vpc.region.GetVpcPeeringConnectionById(self.GetId()) - if err != nil { - return errors.Wrapf(err, "self.vpc.region.GetVpcPeeringConnectionById(%s)", self.GetId()) - } - self.vpcPC = vpcPC - return nil -} - -func (self *SVpcPeeringConnection) GetPeerVpcId() string { - if self.vpcPC.AccepterVpcInfo != nil { - if self.vpcPC.AccepterVpcInfo.VpcId != nil { - return *self.vpcPC.AccepterVpcInfo.VpcId - } - } - return "" -} - -func (self *SVpcPeeringConnection) GetPeerAccountId() string { - if self.vpcPC.AccepterVpcInfo != nil { - if self.vpcPC.AccepterVpcInfo.OwnerId != nil { - return *self.vpcPC.AccepterVpcInfo.OwnerId - } - } - return "" -} - -func (self *SVpcPeeringConnection) Delete() error { - err := self.vpc.region.DeleteVpcPeeringConnection(self.GetId()) - if err != nil { - return errors.Wrapf(err, "self.region.DeleteVpcPeeringConnection(%s)", self.GetId()) - } - return nil -} - -func (self *SVpcPeeringConnection) GetEnabled() bool { - return true -} diff --git a/pkg/multicloud/aws/waf.go b/pkg/multicloud/aws/waf.go deleted file mode 100644 index d6ff6896c5..0000000000 --- a/pkg/multicloud/aws/waf.go +++ /dev/null @@ -1,545 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "strconv" - "strings" - - "github.com/aws/aws-sdk-go/service/wafv2" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - SCOPE_REGIONAL = "REGIONAL" - SCOPE_CLOUDFRONT = "CLOUDFRONT" -) - -var ( - WAF_SCOPES = []string{ - SCOPE_REGIONAL, - SCOPE_CLOUDFRONT, - } -) - -type SWafRule struct { - Action struct { - Block struct { - } `json:"Block"` - } `json:"Action"` - Name string `json:"Name"` -} - -type SVisibilityConfig struct { - CloudWatchMetricsEnabled bool - MetricName string - SampledRequestsEnabled bool -} - -type SWebAcl struct { - multicloud.SResourceBase - multicloud.AwsTags - region *SRegion - *wafv2.WebACL - - scope string - LockToken string -} - -func (self *SRegion) ListWebACLs(scope string) ([]SWebAcl, error) { - if scope == SCOPE_CLOUDFRONT && self.RegionId != "us-east-1" { - return []SWebAcl{}, nil - } - client, err := self.getWafClient() - if err != nil { - return nil, errors.Wrapf(err, "getWafClient") - } - ret := []SWebAcl{} - input := wafv2.ListWebACLsInput{} - input.SetScope(scope) - for { - resp, err := client.ListWebACLs(&input) - if err != nil { - return nil, errors.Wrapf(err, "ListWebACLs") - } - part := []SWebAcl{} - jsonutils.Update(&part, resp.WebACLs) - ret = append(ret, part...) - if resp.NextMarker == nil || len(*resp.NextMarker) == 0 { - break - } - input.SetNextMarker(*resp.NextMarker) - } - return ret, nil -} - -func (self *SRegion) GetWebAcl(id, name, scope string) (*SWebAcl, error) { - client, err := self.getWafClient() - if err != nil { - return nil, errors.Wrapf(err, "getWafClient") - } - input := wafv2.GetWebACLInput{} - input.SetId(id) - input.SetName(name) - input.SetScope(scope) - resp, err := client.GetWebACL(&input) - if err != nil { - if _, ok := err.(*wafv2.WAFNonexistentItemException); ok { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, err.Error()) - } - return nil, errors.Wrapf(err, "GetWebAcl") - } - ret := &SWebAcl{region: self, scope: scope, WebACL: resp.WebACL, LockToken: *resp.LockToken} - return ret, nil -} - -func (self *SRegion) DeleteWebAcl(id, name, scope, lockToken string) error { - client, err := self.getWafClient() - if err != nil { - return errors.Wrapf(err, "getWafClient") - } - input := wafv2.DeleteWebACLInput{} - input.SetId(id) - input.SetName(name) - input.SetScope(scope) - input.SetLockToken(lockToken) - _, err = client.DeleteWebACL(&input) - return errors.Wrapf(err, "DeleteWebACL") -} - -func (self *SRegion) ListResourcesForWebACL(resType, arn string) ([]string, error) { - client, err := self.getWafClient() - if err != nil { - return nil, errors.Wrapf(err, "getWafClient") - } - input := wafv2.ListResourcesForWebACLInput{} - input.SetResourceType(resType) - input.SetWebACLArn(arn) - resp, err := client.ListResourcesForWebACL(&input) - if err != nil { - return nil, errors.Wrapf(err, "ListResourcesForWebACL") - } - ret := []string{} - for _, id := range resp.ResourceArns { - ret = append(ret, *id) - } - return ret, nil -} - -func (self *SRegion) GetICloudWafInstanceById(id string) (cloudprovider.ICloudWafInstance, error) { - idInfo := strings.Split(id, "/") - if len(idInfo) != 4 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "invalid arn %s", id) - } - scope := SCOPE_CLOUDFRONT - if strings.HasSuffix(idInfo[0], "regional") { - scope = SCOPE_REGIONAL - } - ins, err := self.GetWebAcl(idInfo[3], idInfo[2], scope) - if err != nil { - return nil, errors.Wrapf(err, "GetWebAcl(%s, %s, %s)", idInfo[3], idInfo[2], scope) - } - return ins, nil -} - -func (self *SRegion) GetICloudWafInstances() ([]cloudprovider.ICloudWafInstance, error) { - ret := []cloudprovider.ICloudWafInstance{} - for _, scope := range WAF_SCOPES { - ins, err := self.ListWebACLs(scope) - if err != nil { - return nil, errors.Wrapf(err, "ListWebACLs") - } - for i := range ins { - ins[i].region = self - ins[i].scope = scope - ret = append(ret, &ins[i]) - } - } - return ret, nil -} - -func (self *SWebAcl) GetEnabled() bool { - return true -} - -func (self *SWebAcl) GetGlobalId() string { - return *self.ARN -} - -func (self *SWebAcl) GetName() string { - return *self.Name -} - -func (self *SWebAcl) GetId() string { - return *self.ARN -} - -func (self *SWebAcl) GetWafType() cloudprovider.TWafType { - if self.scope == SCOPE_CLOUDFRONT { - return cloudprovider.WafTypeCloudFront - } - return cloudprovider.WafTypeRegional -} - -func (self *SWebAcl) GetStatus() string { - return api.WAF_STATUS_AVAILABLE -} - -func (self *SWebAcl) GetDefaultAction() *cloudprovider.DefaultAction { - ret := &cloudprovider.DefaultAction{} - if self.WebACL.DefaultAction == nil { - self.Refresh() - } - if self.WebACL.DefaultAction != nil { - action := self.WebACL.DefaultAction - if action.Allow != nil { - ret.Action = cloudprovider.WafActionAllow - } else if action.Block != nil { - ret.Action = cloudprovider.WafActionBlock - } - } - return ret -} - -func (self *SWebAcl) Refresh() error { - acl, err := self.region.GetWebAcl(*self.Id, *self.Name, self.scope) - if err != nil { - return errors.Wrapf(err, "GetWebAcl") - } - self.WebACL = acl.WebACL - return jsonutils.Update(self, acl) -} - -func (self *SWebAcl) Delete() error { - return self.region.DeleteWebAcl(*self.Id, *self.Name, self.scope, self.LockToken) -} - -func (self *SRegion) CreateICloudWafInstance(opts *cloudprovider.WafCreateOptions) (cloudprovider.ICloudWafInstance, error) { - waf, err := self.CreateWebAcl(opts.Name, opts.Desc, opts.Type, opts.DefaultAction) - if err != nil { - return nil, errors.Wrapf(err, "CreateWebAcl") - } - return waf, nil -} - -func (self *SRegion) CreateWebAcl(name, desc string, wafType cloudprovider.TWafType, action *cloudprovider.DefaultAction) (*SWebAcl, error) { - input := wafv2.CreateWebACLInput{} - input.SetName(name) - if len(desc) > 0 { - input.SetDescription(desc) - } - switch wafType { - case cloudprovider.WafTypeRegional, cloudprovider.WafTypeCloudFront: - input.SetScope(strings.ToUpper(string(wafType))) - default: - return nil, errors.Errorf("invalid waf type %s", wafType) - } - if action != nil { - defaultAction := wafv2.DefaultAction{} - switch action.Action { - case cloudprovider.WafActionAllow: - defaultAction.Allow = &wafv2.AllowAction{} - case cloudprovider.WafActionBlock: - defaultAction.Block = &wafv2.BlockAction{} - } - input.SetDefaultAction(&defaultAction) - } - visib := &wafv2.VisibilityConfig{} - visib.SetSampledRequestsEnabled(true) - visib.SetCloudWatchMetricsEnabled(true) - visib.SetMetricName(name) - input.SetVisibilityConfig(visib) - client, err := self.getWafClient() - if err != nil { - return nil, errors.Wrapf(err, "getWafClient") - } - output, err := client.CreateWebACL(&input) - if err != nil { - return nil, errors.Wrapf(err, "CreateWebAcl") - } - return self.GetWebAcl(*output.Summary.Id, name, *input.Scope) -} - -func reverseConvertField(opts cloudprovider.SWafStatement) *wafv2.FieldToMatch { - ret := &wafv2.FieldToMatch{} - switch opts.MatchField { - case cloudprovider.WafMatchFieldBody: - body := &wafv2.Body{} - ret.SetBody(body) - case cloudprovider.WafMatchFieldJsonBody: - case cloudprovider.WafMatchFieldMethod: - method := &wafv2.Method{} - ret.SetMethod(method) - case cloudprovider.WafMatchFieldQuery: - switch opts.MatchFieldKey { - case "SingleArgument": - query := &wafv2.SingleQueryArgument{} - ret.SetSingleQueryArgument(query) - case "AllArguments": - query := &wafv2.AllQueryArguments{} - ret.SetAllQueryArguments(query) - default: - query := &wafv2.QueryString{} - ret.SetQueryString(query) - } - case cloudprovider.WafMatchFiledHeader: - head := &wafv2.SingleHeader{} - head.SetName(opts.MatchFieldKey) - ret.SetSingleHeader(head) - case cloudprovider.WafMatchFiledUriPath: - uri := &wafv2.UriPath{} - ret.SetUriPath(uri) - } - return ret -} - -func reverseConvertStatement(statement cloudprovider.SWafStatement) *wafv2.Statement { - ret := &wafv2.Statement{} - trans := []*wafv2.TextTransformation{} - if statement.Transformations != nil { - for i, tran := range *statement.Transformations { - t := &wafv2.TextTransformation{} - switch tran { - case cloudprovider.WafTextTransformationNone: - t.SetType(wafv2.TextTransformationTypeNone) - case cloudprovider.WafTextTransformationLowercase: - t.SetType(wafv2.TextTransformationTypeLowercase) - case cloudprovider.WafTextTransformationCmdLine: - t.SetType(wafv2.TextTransformationTypeCmdLine) - case cloudprovider.WafTextTransformationUrlDecode: - t.SetType(wafv2.TextTransformationTypeUrlDecode) - case cloudprovider.WafTextTransformationHtmlEntityDecode: - t.SetType(wafv2.TextTransformationTypeHtmlEntityDecode) - case cloudprovider.WafTextTransformationCompressWithSpace: - t.SetType(wafv2.TextTransformationTypeCompressWhiteSpace) - } - t.SetPriority(int64(i)) - trans = append(trans, t) - } - } - rules := []*wafv2.ExcludedRule{} - if statement.ExcludeRules != nil { - for _, r := range *statement.ExcludeRules { - name := r.Name - rules = append(rules, &wafv2.ExcludedRule{ - Name: &name, - }) - } - } - field := reverseConvertField(statement) - switch statement.Type { - case cloudprovider.WafStatementTypeRate: - rate := &wafv2.RateBasedStatement{} - limit := int(0) - if statement.MatchFieldValues != nil && len(*statement.MatchFieldValues) == 1 { - limit, _ = strconv.Atoi((*statement.MatchFieldValues)[0]) - } - rate.SetLimit(int64(limit)) - fd := &wafv2.ForwardedIPConfig{} - if len(statement.ForwardedIPHeader) > 0 { - fd.SetHeaderName(statement.ForwardedIPHeader) - rate.SetForwardedIPConfig(fd) - } - ret.SetRateBasedStatement(rate) - case cloudprovider.WafStatementTypeIPSet: - ipset := &wafv2.IPSetReferenceStatement{} - ipset.SetARN(statement.IPSetId) - fd := &wafv2.IPSetForwardedIPConfig{} - if len(statement.ForwardedIPHeader) > 0 { - fd.SetHeaderName(statement.ForwardedIPHeader) - ipset.SetIPSetForwardedIPConfig(fd) - } - ret.SetIPSetReferenceStatement(ipset) - case cloudprovider.WafStatementTypeXssMatch: - xss := &wafv2.XssMatchStatement{} - if len(trans) > 0 { - xss.SetTextTransformations(trans) - } - field := &wafv2.FieldToMatch{} - xss.SetFieldToMatch(field) - xss.SetTextTransformations(trans) - ret.SetXssMatchStatement(xss) - case cloudprovider.WafStatementTypeSize: - size := &wafv2.SizeConstraintStatement{} - size.SetFieldToMatch(field) - value := int(0) - if statement.MatchFieldValues != nil && len(*statement.MatchFieldValues) == 1 { - value, _ = strconv.Atoi((*statement.MatchFieldValues)[0]) - } - size.SetSize(int64(value)) - ret.SetSizeConstraintStatement(size) - case cloudprovider.WafStatementTypeGeoMatch: - geo := &wafv2.GeoMatchStatement{} - values := []*string{} - if statement.MatchFieldValues != nil { - for i := range *statement.MatchFieldValues { - v := (*statement.MatchFieldValues)[i] - values = append(values, &v) - } - geo.SetCountryCodes(values) - } - fd := &wafv2.ForwardedIPConfig{} - if len(statement.ForwardedIPHeader) > 0 { - fd.SetHeaderName(statement.ForwardedIPHeader) - geo.SetForwardedIPConfig(fd) - } - ret.SetGeoMatchStatement(geo) - case cloudprovider.WafStatementTypeRegexSet: - regex := &wafv2.RegexPatternSetReferenceStatement{} - regex.SetARN(statement.RegexSetId) - if len(trans) > 0 { - regex.SetTextTransformations(trans) - } - regex.SetFieldToMatch(field) - ret.SetRegexPatternSetReferenceStatement(regex) - case cloudprovider.WafStatementTypeByteMatch: - bm := &wafv2.ByteMatchStatement{} - if len(trans) > 0 { - bm.SetTextTransformations(trans) - } - bm.SetSearchString([]byte(statement.SearchString)) - if len(statement.Operator) > 0 { - bm.SetPositionalConstraint(string(statement.Operator)) - } - bm.SetFieldToMatch(field) - ret.SetByteMatchStatement(bm) - case cloudprovider.WafStatementTypeRuleGroup: - rg := &wafv2.RuleGroupReferenceStatement{} - rg.SetARN(statement.RuleGroupId) - if len(rules) > 0 { - rg.SetExcludedRules(rules) - } - ret.SetRuleGroupReferenceStatement(rg) - case cloudprovider.WafStatementTypeSqliMatch: - sqli := &wafv2.SqliMatchStatement{} - if len(trans) > 0 { - sqli.SetTextTransformations(trans) - } - sqli.SetFieldToMatch(field) - ret.SetSqliMatchStatement(sqli) - case cloudprovider.WafStatementTypeLabelMatch: - case cloudprovider.WafStatementTypeManagedRuleGroup: - rg := &wafv2.ManagedRuleGroupStatement{} - rg.SetName(statement.ManagedRuleGroupName) - rg.SetVendorName("aws") - if len(rules) > 0 { - rg.SetExcludedRules(rules) - } - ret.SetManagedRuleGroupStatement(rg) - } - return ret -} - -func (self *SWebAcl) AddRule(opts *cloudprovider.SWafRule) (cloudprovider.ICloudWafRule, error) { - input := &wafv2.UpdateWebACLInput{} - input.SetLockToken(self.LockToken) - input.SetId(*self.Id) - input.SetName(*self.Name) - input.SetScope(self.scope) - input.SetDescription(*self.Description) - input.SetDefaultAction(self.DefaultAction) - input.SetVisibilityConfig(self.WebACL.VisibilityConfig) - rules := self.Rules - rule := &wafv2.Rule{} - rule.SetName(opts.Name) - rule.SetPriority(int64(opts.Priority)) - action := &wafv2.RuleAction{} - if opts.Action != nil { - switch opts.Action.Action { - case cloudprovider.WafActionAllow: - allow := &wafv2.AllowAction{} - action.SetAllow(allow) - case cloudprovider.WafActionBlock: - block := &wafv2.BlockAction{} - action.SetBlock(block) - case cloudprovider.WafActionCount: - count := &wafv2.CountAction{} - action.SetCount(count) - } - } - rule.SetAction(action) - visib := &wafv2.VisibilityConfig{} - visib.SetSampledRequestsEnabled(false) - visib.SetCloudWatchMetricsEnabled(true) - visib.SetMetricName(opts.Name) - rule.SetVisibilityConfig(visib) - statement := &wafv2.Statement{} - switch opts.StatementCondition { - case cloudprovider.WafStatementConditionOr: - ss := &wafv2.OrStatement{} - for _, s := range opts.Statements { - ss.Statements = append(ss.Statements, reverseConvertStatement(s)) - } - statement.SetOrStatement(ss) - case cloudprovider.WafStatementConditionAnd: - ss := &wafv2.AndStatement{} - for _, s := range opts.Statements { - ss.Statements = append(ss.Statements, reverseConvertStatement(s)) - } - statement.SetAndStatement(ss) - case cloudprovider.WafStatementConditionNot: - ss := &wafv2.NotStatement{} - for _, s := range opts.Statements { - ss.SetStatement(reverseConvertStatement(s)) - break - } - statement.SetNotStatement(ss) - case cloudprovider.WafStatementConditionNone: - for _, s := range opts.Statements { - statement = reverseConvertStatement(s) - break - } - } - rule.SetStatement(statement) - rules = append(rules, rule) - input.SetRules(rules) - client, err := self.region.getWafClient() - if err != nil { - return nil, errors.Wrapf(err, "getWafClient") - } - _, err = client.UpdateWebACL(input) - if err != nil { - return nil, errors.Wrapf(err, "UpdateWebACL") - } - ret := &sWafRule{waf: self, Rule: rule} - return ret, nil -} - -func (self *SWebAcl) GetCloudResources() ([]cloudprovider.SCloudResource, error) { - ret := []cloudprovider.SCloudResource{} - if self.scope != SCOPE_REGIONAL { - return ret, nil - } - for _, resType := range []string{"APPLICATION_LOAD_BALANCER", "API_GATEWAY", "APPSYNC"} { - resIds, err := self.region.ListResourcesForWebACL(resType, *self.ARN) - if err != nil { - return nil, errors.Wrapf(err, "ListResourcesForWebACL(%s, %s)", resType, *self.ARN) - } - for _, resId := range resIds { - ret = append(ret, cloudprovider.SCloudResource{ - Id: resId, - Name: resId, - Type: resType, - }) - } - } - return ret, nil -} diff --git a/pkg/multicloud/aws/wire.go b/pkg/multicloud/aws/wire.go deleted file mode 100644 index ea856fdf2d..0000000000 --- a/pkg/multicloud/aws/wire.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.AwsTags - 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 api.WIRE_STATUS_AVAILABLE -} - -func (self *SWire) Refresh() error { - return nil -} - -func (self *SWire) IsEmulated() bool { - return true -} - -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, errors.Wrap(err, "fetchNetworks") - } - } - 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, errors.Wrap(err, "GetINetworks") - } - for i := 0; i < len(networks); i += 1 { - if networks[i].GetGlobalId() == netid { - return networks[i], nil - } - } - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetINetworkById") -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - networkId, err := self.zone.region.createNetwork(self.zone.ZoneId, self.vpc.VpcId, opts.Name, opts.Cidr, opts.Desc) - if err != nil { - log.Errorf("createNetwork error %s", err) - return nil, errors.Wrap(err, "createNetwork") - } - self.inetworks = nil - network := self.getNetworkById(networkId) - if network == nil { - log.Errorf("cannot find network after create????") - return nil, errors.Wrap(cloudprovider.ErrNotFound, "getNetworkById") - } - 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) - } -} diff --git a/pkg/multicloud/aws/zone.go b/pkg/multicloud/aws/zone.go deleted file mode 100644 index 3556044465..0000000000 --- a/pkg/multicloud/aws/zone.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 aws - -import ( - "fmt" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var StorageTypes = []string{ - api.STORAGE_GP2_SSD, - api.STORAGE_GP3_SSD, - api.STORAGE_IO1_SSD, - api.STORAGE_IO2_SSD, - api.STORAGE_ST1_HDD, - api.STORAGE_SC1_HDD, - api.STORAGE_STANDARD_HDD, -} - -type SZone struct { - multicloud.SResourceBase - multicloud.AwsTags - region *SRegion - host *SHost - - iwires []cloudprovider.ICloudWire - - ZoneId string // 沿用阿里云ZoneId,对应Aws ZoneName - LocalName string - State 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) 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) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_EN, self.LocalName) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -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 api.ZONE_SOLDOUT - } else { - return api.ZONE_ENABLE - } -} - -func (self *SZone) Refresh() error { - return nil -} - -func (self *SZone) IsEmulated() bool { - return false -} - -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, errors.Wrap(cloudprovider.ErrNotFound, "GetIHostById") -} - -func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - ret := []cloudprovider.ICloudStorage{} - for i := range StorageTypes { - storage := &SStorage{zone: self, storageType: StorageTypes[i]} - ret = append(ret, storage) - } - return ret, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storages, err := self.GetIStorages() - if err != nil { - return nil, err - } - for i := 0; i < len(storages); i += 1 { - if storages[i].GetGlobalId() == id { - return storages[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "not found %s", id) -} - -func (self *SZone) getStorageByCategory(category string) (*SStorage, error) { - storages, err := self.GetIStorages() - if err != nil { - return nil, errors.Wrap(err, "GetIStorages") - } - 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, errors.Wrap(err, "GetIZones") - } - 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) -} - -func (self *SRegion) TestStorageAvailable(zoneId, storageType string) (bool, error) { - params := map[string]string{ - "AvailabilityZone": zoneId, - "ClientToken": utils.GenRequestId(20), - "DryRun": "true", - "Size": "125", - "VolumeType": storageType, - } - iops, ok := map[string]string{ - api.STORAGE_GP3_SSD: "3000", - api.STORAGE_IO1_SSD: "100", - api.STORAGE_IO2_SSD: "100", - }[storageType] - if ok { - params["Iops"] = iops - } - ret := struct{}{} - err := self.ec2Request("CreateVolume", params, &ret) - if err != nil { - if e, ok := err.(*sAwsError); ok && e.Errors.Code == "DryRunOperation" { - return true, nil - } - return false, errors.Wrapf(err, "CreateVolume") - } - return true, nil -} diff --git a/pkg/multicloud/azure/app_gateways.go b/pkg/multicloud/azure/app_gateways.go deleted file mode 100644 index 7343461625..0000000000 --- a/pkg/multicloud/azure/app_gateways.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "net/url" - "strings" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SGatewayipconfiguration struct { - Name string `json:"name"` - ID string `json:"id"` - Etag string `json:"etag"` - Properties struct { - Provisioningstate string `json:"provisioningState"` - Subnet struct { - ID string `json:"id"` - } `json:"subnet"` - } `json:"properties"` - Type string `json:"type"` -} - -type SFrontendipconfiguration struct { - Name string `json:"name"` - ID string `json:"id"` - Etag string `json:"etag"` - Type string `json:"type"` - Properties struct { - Provisioningstate string `json:"provisioningState"` - Privateipallocationmethod string `json:"privateIPAllocationMethod"` - PublicIPAddress struct { - ID string - } - PrivateIPAddress string - Subnet struct { - ID string `json:"id"` - } `json:"subnet"` - Httplisteners []struct { - ID string `json:"id"` - } `json:"httpListeners"` - } `json:"properties"` -} - -type SFrontendport struct { - Name string `json:"name"` - ID string `json:"id"` - Etag string `json:"etag"` - Properties struct { - Provisioningstate string `json:"provisioningState"` - Port int `json:"port"` - Httplisteners []struct { - ID string `json:"id"` - } `json:"httpListeners"` - } `json:"properties"` - Type string `json:"type"` -} - -type SBackendaddresspool struct { - Name string `json:"name"` - ID string `json:"id"` - Etag string `json:"etag"` - Properties struct { - Provisioningstate string `json:"provisioningState"` - Backendaddresses []interface{} `json:"backendAddresses"` - Requestroutingrules []struct { - ID string `json:"id"` - } `json:"requestRoutingRules"` - } `json:"properties"` - Type string `json:"type"` -} - -type SBackendhttpsettingscollection struct { - Name string `json:"name"` - ID string `json:"id"` - Etag string `json:"etag"` - Properties struct { - Provisioningstate string `json:"provisioningState"` - Port int `json:"port"` - Protocol string `json:"protocol"` - Cookiebasedaffinity string `json:"cookieBasedAffinity"` - Pickhostnamefrombackendaddress bool `json:"pickHostNameFromBackendAddress"` - Requesttimeout int `json:"requestTimeout"` - Requestroutingrules []struct { - ID string `json:"id"` - } `json:"requestRoutingRules"` - } `json:"properties"` - Type string `json:"type"` -} - -type SHttplistener struct { - Name string `json:"name"` - ID string `json:"id"` - Etag string `json:"etag"` - Properties struct { - Provisioningstate string `json:"provisioningState"` - Frontendipconfiguration struct { - ID string `json:"id"` - } `json:"frontendIPConfiguration"` - Frontendport struct { - ID string `json:"id"` - } `json:"frontendPort"` - Protocol string `json:"protocol"` - Requireservernameindication bool `json:"requireServerNameIndication"` - Requestroutingrules []struct { - ID string `json:"id"` - } `json:"requestRoutingRules"` - } `json:"properties"` - Type string `json:"type"` -} - -type SRequestroutingrule struct { - Name string `json:"name"` - ID string `json:"id"` - Etag string `json:"etag"` - Properties struct { - Provisioningstate string `json:"provisioningState"` - Ruletype string `json:"ruleType"` - Httplistener struct { - ID string `json:"id"` - } `json:"httpListener"` - Backendaddresspool struct { - ID string `json:"id"` - } `json:"backendAddressPool"` - Backendhttpsettings struct { - ID string `json:"id"` - } `json:"backendHttpSettings"` - } `json:"properties"` - Type string `json:"type"` -} - -type SApplicationGatewayProperties struct { - Provisioningstate string `json:"provisioningState"` - Resourceguid string `json:"resourceGuid"` - Sku struct { - Name string `json:"name"` - Tier string `json:"tier"` - Capacity string `json:"capacity"` - } `json:"sku"` - Operationalstate string `json:"operationalState"` - Gatewayipconfigurations []SGatewayipconfiguration `json:"gatewayIPConfigurations"` - Sslcertificates []interface{} `json:"sslCertificates"` - Authenticationcertificates []interface{} `json:"authenticationCertificates"` - Frontendipconfigurations []SFrontendipconfiguration `json:"frontendIPConfigurations"` - Frontendports []SFrontendport `json:"frontendPorts"` - Backendaddresspools []SBackendaddresspool `json:"backendAddressPools"` - Backendhttpsettingscollection []SBackendhttpsettingscollection `json:"backendHttpSettingsCollection"` - Httplisteners []SHttplistener `json:"httpListeners"` - Urlpathmaps []interface{} `json:"urlPathMaps"` - Requestroutingrules []SRequestroutingrule `json:"requestRoutingRules"` - Probes []interface{} `json:"probes"` - Redirectconfigurations []interface{} `json:"redirectConfigurations"` - Webapplicationfirewallconfiguration struct { - Enabled bool `json:"enabled"` - Firewallmode string `json:"firewallMode"` - Rulesettype string `json:"ruleSetType"` - Rulesetversion string `json:"ruleSetVersion"` - Disabledrulegroups []interface{} `json:"disabledRuleGroups"` - Requestbodycheck bool `json:"requestBodyCheck"` - } `json:"webApplicationFirewallConfiguration"` - Enablehttp2 bool `json:"enableHttp2"` -} - -type SApplicationGateway struct { - region *SRegion - multicloud.SResourceBase - multicloud.AzureTags - - Name string `json:"name"` - Id string `json:"id"` - Etag string `json:"etag"` - Type string `json:"type"` - Location string `json:"location"` - Properties SApplicationGatewayProperties `json:"properties"` -} - -func (self *SApplicationGateway) GetName() string { - return self.Name -} - -func (self *SApplicationGateway) GetId() string { - return self.Id -} - -func (self *SApplicationGateway) GetGlobalId() string { - return strings.ToLower(self.Id) -} - -func (self *SRegion) ListAppGateways() ([]SApplicationGateway, error) { - apps := []SApplicationGateway{} - err := self.list("Microsoft.Network/applicationGateways", url.Values{}, &apps) - if err != nil { - return nil, errors.Wrapf(err, "list") - } - return apps, nil -} - -func (self *SRegion) GetApplicationGateway(id string) (*SApplicationGateway, error) { - ret := &SApplicationGateway{region: self} - return ret, self.get(id, url.Values{}, ret) -} diff --git a/pkg/multicloud/azure/app_service_plan.go b/pkg/multicloud/azure/app_service_plan.go deleted file mode 100644 index dcb6940e2a..0000000000 --- a/pkg/multicloud/azure/app_service_plan.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SAppServicePlan struct { - multicloud.AzureTags - region *SRegion - - Properties SAppServicePlanProperties - ID string - Kind string - Location string - Name string - Type string - Sku SSkuDescription -} - -type SAppServicePlanProperties struct { - FreeOfferExpirationTime string - GeoRegion string - HostingEnvironmentProfile SHostingEnvironmentProfile - HyperV bool - IsSpot bool - MaximumElasticWorkerCount int - MaximumNumberOfWorkers int - NumberOfSites int - PerSiteScaling bool - // 应用服务环境的预配状态 - ProvisioningState string - Reserved bool - ResourceGroup string - SpotExpirationTime string - // Creating Pending Ready - Status string - Subscription string - TargetWorkerCount int - TargetWorkerSizeId int - WorkerTierName string -} - -type SHostingEnvironmentProfile struct { - ID string - Name string - Type string -} - -type SSkuDescription struct { - Capabilities []SCapability - Capacity int - Family string - locations []string - Name string - Size string - SkuCapacity SSkuCapacity - Tier string -} - -type SCapability struct { - Name string - Reason string - Value string -} - -type SSkuCapacity struct { - Default int - Maximum int - Minimum int - ScaleType string -} - -func (r *SRegion) GetAppServicePlanWithCache(id string) (*SAppServicePlan, error) { - if r.appServicePlans == nil { - plans, err := r.GetAppServicePlans() - if err != nil { - return nil, err - } - appServicePlans := make(map[string]*SAppServicePlan, len(plans)) - for i := range plans { - appServicePlans[plans[i].ID] = &plans[i] - } - r.appServicePlans = appServicePlans - } - if ret, ok := r.appServicePlans[id]; ok { - return ret, nil - } - return r.GetAppServicePlan(id) -} - -func (r *SRegion) GetAppServicePlans() ([]SAppServicePlan, error) { - result := []SAppServicePlan{} - resource := "Microsoft.Web/serverfarms" - err := r.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) - if err != nil { - return nil, err - } - for i := range result { - result[i].region = r - } - return result, nil -} - -func (r *SRegion) GetAppServicePlan(planId string) (*SAppServicePlan, error) { - asp := &SAppServicePlan{region: r} - params := url.Values{"api-version": []string{"2019-08-01"}} - return asp, r.get(planId, params, asp) -} - -type SServerFarmSku struct { - ResourceType string - Sku SSkuSpec - Capacity SSkuCapacity -} - -type SSkuSpec struct { - Name string - Tier string -} - -func (asp *SAppServicePlan) GetSkus() ([]SServerFarmSku, error) { - result := []SServerFarmSku{} - resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/serverfarms/%s/skus", asp.region.client._subscriptionId(), asp.Properties.ResourceGroup, asp.Name) - err := asp.region.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) - if err != nil { - return nil, err - } - return result, nil -} - -type SAppServicePlanVnet struct { - Id string - Name string - Properties SASPVnetProperties -} - -type SASPVnetProperties struct { - VnetResourceId string -} - -func (asp *SAppServicePlan) GetNetworks() ([]SNetwork, error) { - vnets, err := asp.GetVnets() - if err != nil { - return nil, errors.Wrap(err, "unable to get Vnets") - } - networks := make([]SNetwork, 0, len(vnets)) - for i := range vnets { - network, err := asp.region.GetNetwork(vnets[i].Properties.VnetResourceId) - if err != nil { - return nil, errors.Wrap(err, "unable to get Network") - } - networks = append(networks, *network) - } - return networks, nil -} - -func (asp *SAppServicePlan) GetVnets() ([]SAppServicePlanVnet, error) { - result := []SAppServicePlanVnet{} - resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/serverfarms/%s/virtualNetworkConnections", asp.region.client._subscriptionId(), asp.Properties.ResourceGroup, asp.Name) - err := asp.region.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) - if err != nil { - return nil, err - } - return result, nil -} - -type SSkuInfos struct { - ResourceType string - Skus []SResourceSku -} - -func (r *SRegion) GetAppServiceSkus() ([]SSkuInfos, error) { - result := []SSkuInfos{} - resource := "Microsoft.Web/skus" - err := r.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) - if err != nil { - return nil, err - } - return result, err -} diff --git a/pkg/multicloud/azure/cloudgroup.go b/pkg/multicloud/azure/cloudgroup.go deleted file mode 100644 index ad459dbc17..0000000000 --- a/pkg/multicloud/azure/cloudgroup.go +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SCloudgroup struct { - client *SAzureClient - - Id string - DeletionTimestamp string - Description string - DirSyncEnabled string - DisplayName string - LastDirSyncTime string - Mail string - MailNickname string - MailEnabled bool - ProxyAddresses []string -} - -func (group *SCloudgroup) GetName() string { - return group.DisplayName -} - -func (group *SCloudgroup) GetGlobalId() string { - return group.Id -} - -func (group *SCloudgroup) GetDescription() string { - return group.Description -} - -func (group *SCloudgroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := group.client.GetCloudpolicies(group.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetCloudpolicies(%s)", group.Id) - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].Properties.Type == "BuiltInRole" { - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (group *SCloudgroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := group.client.GetCloudpolicies(group.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetCloudpolicies(%s)", group.Id) - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].Properties.Type != "BuiltInRole" { - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (group *SCloudgroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { - users, err := group.client.ListGroupMemebers(group.Id) - if err != nil { - return nil, errors.Wrap(err, "ListGroupMemebers") - } - ret := []cloudprovider.IClouduser{} - for i := range users { - users[i].client = group.client - ret = append(ret, &users[i]) - } - return ret, nil -} - -func (group *SCloudgroup) AddUser(name string) error { - return group.client.AddGroupUser(group.Id, name) -} - -func (group *SCloudgroup) RemoveUser(name string) error { - return group.client.RemoveGroupUser(group.Id, name) -} - -func (group *SCloudgroup) AttachSystemPolicy(policyId string) error { - return group.client.AssignPolicy(group.Id, policyId, "") -} - -func (group *SCloudgroup) AttachCustomPolicy(policyId string) error { - return group.client.AssignPolicy(group.Id, policyId, "") -} - -func (group *SCloudgroup) DetachSystemPolicy(policyId string) error { - assignments, err := group.client.GetAssignments(group.Id) - if err != nil { - return errors.Wrapf(err, "GetAssignments(%s)", group.Id) - } - for _, assignment := range assignments { - role, err := group.client.GetRole(assignment.Properties.RoleDefinitionId) - if err != nil { - return errors.Wrapf(err, "GetRule(%s)", assignment.Properties.RoleDefinitionId) - } - if role.Properties.RoleName == policyId { - return group.client.gdel(assignment.Id) - } - } - return nil -} - -func (group *SCloudgroup) DetachCustomPolicy(policyId string) error { - return group.DetachSystemPolicy(policyId) -} - -func (group *SCloudgroup) Delete() error { - return group.client.DeleteGroup(group.Id) -} - -func (self *SAzureClient) GetCloudgroups(name string) ([]SCloudgroup, error) { - groups := []SCloudgroup{} - params := url.Values{} - if len(name) > 0 { - params.Set("$filter", fmt.Sprintf("displayName eq '%s'", name)) - } - err := self.glist("groups", params, &groups) - if err != nil { - return nil, err - } - return groups, nil -} - -func (self *SAzureClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - groups, err := self.GetCloudgroups("") - if err != nil { - return nil, errors.Wrap(err, "GetCloudgroups") - } - ret := []cloudprovider.ICloudgroup{} - for i := range groups { - groups[i].client = self - ret = append(ret, &groups[i]) - } - return ret, nil -} - -func (self *SAzureClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - groups, err := self.GetCloudgroups(name) - if err != nil { - return nil, errors.Wrapf(err, "GetCloudgroups(%s)", name) - } - if len(groups) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(groups) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - groups[0].client = self - return &groups[0], nil -} - -func (self *SAzureClient) ListGroupMemebers(id string) ([]SClouduser, error) { - users := []SClouduser{} - resource := fmt.Sprintf("groups/%s/members", id) - err := self.glist(resource, nil, &users) - if err != nil { - return nil, err - } - return users, nil -} - -func (self *SAzureClient) DeleteGroup(id string) error { - return self.gdel(fmt.Sprintf("groups/%s", id)) -} - -func (self *SAzureClient) CreateGroup(name, desc string) (*SCloudgroup, error) { - params := map[string]interface{}{ - "displayName": name, - "mailEnabled": false, - "securityEnabled": true, - } - nickName := "" - for _, s := range name { - if s >= 0 && s <= 127 { - nickName += string(s) - } - } - params["mailNickname"] = nickName - if len(desc) > 0 { - params["Description"] = desc - } - group := SCloudgroup{client: self} - err := self.gcreate("groups", jsonutils.Marshal(params), &group) - if err != nil { - return nil, errors.Wrap(err, "Create") - } - return &group, nil -} - -func (self *SAzureClient) RemoveGroupUser(id, userName string) error { - user, err := self.GetClouduser(userName) - if err != nil { - return errors.Wrapf(err, "GetCloudusers(%s)", userName) - } - return self.gdel(fmt.Sprintf("/groups/%s/members/%s/$ref", id, user.Id)) -} - -func (self *SAzureClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - group, err := self.CreateGroup(name, desc) - if err != nil { - return nil, errors.Wrap(err, "CreateGroup") - } - group.client = self - return group, nil -} - -func (self *SAzureClient) AddGroupUser(id, userName string) error { - user, err := self.GetClouduser(userName) - if err != nil { - return errors.Wrapf(err, "GetCloudusers(%s)", userName) - } - resource := fmt.Sprintf("groups/%s/members/$ref", id) - params := map[string]string{ - "@odata.id": fmt.Sprintf("https://graph.microsoft.com/v1.0/directoryObjects/%s", user.Id), - } - err = self.gcreate(resource, jsonutils.Marshal(params), nil) - if err != nil && !strings.Contains(err.Error(), "One or more added object references already exist for the following modified properties") { - return err - } - return nil -} diff --git a/pkg/multicloud/azure/cloudpolicy.go b/pkg/multicloud/azure/cloudpolicy.go deleted file mode 100644 index 6670d07c61..0000000000 --- a/pkg/multicloud/azure/cloudpolicy.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/stringutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SPermission struct { - Actions []string - NotActions []string - DataActions []string - NotDataActions []string -} - -type SRoleProperties struct { - RoleName string - Type string - Description string - AssignableScopes []string - Permissions []SPermission -} - -type SCloudpolicy struct { - Id string - Type string - Name string - Properties SRoleProperties -} - -func (role *SCloudpolicy) GetName() string { - return role.Properties.RoleName -} - -func (role *SCloudpolicy) GetGlobalId() string { - return role.Properties.RoleName -} - -func (role *SCloudpolicy) GetDescription() string { - return role.Properties.Description -} - -func (role *SCloudpolicy) UpdateDocument(document *jsonutils.JSONDict) error { - return cloudprovider.ErrNotImplemented -} - -func (role *SCloudpolicy) GetDocument() (*jsonutils.JSONDict, error) { - return jsonutils.Marshal(role.Properties).(*jsonutils.JSONDict), nil -} - -func (role *SCloudpolicy) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (cli *SAzureClient) GetRoles(name, policyType string) ([]SCloudpolicy, error) { - ret := []SCloudpolicy{} - filter := []string{} - if len(name) > 0 { - filter = append(filter, fmt.Sprintf("roleName eq '%s'", name)) - } - if len(policyType) > 0 { - filter = append(filter, fmt.Sprintf("Type eq '%s'", policyType)) - } - params := url.Values{} - if len(filter) > 0 { - params.Set("$filter", strings.Join(filter, " and ")) - } - resource := "Microsoft.Authorization/roleDefinitions" - err := cli.list(resource, params, &ret) - if err != nil { - return nil, errors.Wrap(err, "list") - } - return ret, nil -} - -func (cli *SAzureClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - roles, err := cli.GetRoles("", "BuiltInRole") - if err != nil { - return nil, errors.Wrap(err, "GetRoles") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range roles { - ret = append(ret, &roles[i]) - } - return ret, nil -} - -func (cli *SAzureClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - roles, err := cli.GetRoles("", "CustomRole") - if err != nil { - return nil, errors.Wrap(err, "GetRoles") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range roles { - ret = append(ret, &roles[i]) - } - return ret, nil -} - -func (cli *SAzureClient) AssignPolicy(objectId, roleName, subscriptionId string) error { - roles, err := cli.GetRoles(roleName, "") - if err != nil { - return errors.Wrapf(err, "GetRoles(%s)", roleName) - } - if len(roles) == 0 { - return errors.Wrap(cloudprovider.ErrNotFound, roleName) - } - if len(roles) > 1 { - return errors.Wrap(cloudprovider.ErrDuplicateId, roleName) - } - body := map[string]interface{}{ - "properties": map[string]interface{}{ - "roleDefinitionId": roles[0].Id, - "principalId": objectId, - }, - } - subscriptionIds := []string{} - if len(subscriptionId) == 0 { - for _, subscription := range cli.subscriptions { - subscriptionIds = append(subscriptionIds, subscription.SubscriptionId) - } - } - for _, subscriptionId := range subscriptionIds { - resource := fmt.Sprintf("subscriptions/%s/providers/Microsoft.Authorization/roleAssignments/%s", subscriptionId, stringutils.UUID4()) - _, err = cli.put(resource, jsonutils.Marshal(body)) - if err != nil { - if e, ok := err.(*AzureResponseError); ok && e.AzureError.Code == "ReadOnlyDisabledSubscription" || e.AzureError.Code == "PrincipalNotFound" { - continue - } - return errors.Wrapf(err, "AssignPolicy %s for subscription %s", roleName, subscriptionId) - } - } - return nil -} - -type SAssignmentProperties struct { - RoleDefinitionId string - PrincipalId string - PrincipalType string - Scope string -} - -type SAssignment struct { - Id string - Name string - Type string - Properties SAssignmentProperties -} - -func (cli *SAzureClient) GetAssignments(objectId string) ([]SAssignment, error) { - ret := []SAssignment{} - params := url.Values{} - if len(objectId) > 0 { - params.Set("$filter", fmt.Sprintf("principalId eq '%s'", objectId)) - } - resource := "Microsoft.Authorization/roleAssignments" - err := cli.list(resource, params, &ret) - if err != nil { - return nil, errors.Wrap(err, "list") - } - return ret, nil -} - -func (cli *SAzureClient) GetRole(roleId string) (*SCloudpolicy, error) { - role := &SCloudpolicy{} - err := cli.get(roleId, nil, role) - if err != nil { - return nil, errors.Wrapf(err, "GetRole(%s)", roleId) - } - return role, nil -} - -func (cli *SAzureClient) GetCloudpolicies(objectId string) ([]SCloudpolicy, error) { - assignments, err := cli.GetAssignments(objectId) - if err != nil { - return nil, errors.Wrapf(err, "GetAssignments(%s)", objectId) - } - ret := []SCloudpolicy{} - for _, assignment := range assignments { - role, err := cli.GetRole(assignment.Properties.RoleDefinitionId) - if err != nil { - return nil, errors.Wrapf(err, "GetRule(%s)", assignment.Properties.RoleDefinitionId) - } - ret = append(ret, *role) - } - return ret, nil -} diff --git a/pkg/multicloud/azure/clouduser.go b/pkg/multicloud/azure/clouduser.go deleted file mode 100644 index aab89f893f..0000000000 --- a/pkg/multicloud/azure/clouduser.go +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -type SClouduserPasswordProfile struct { - Password string - forceChangePasswordNextLogin bool - enforceChangePasswordPolicy bool -} - -type SClouduser struct { - client *SAzureClient - multicloud.SBaseClouduser - - OdataType string `json:"odata.type"` - ObjectType string - Id string - DeletionTimestamp string - AccountEnabled bool - AgeGroup string - City string - CompanyName string - ConsentProvidedForMinor string - Country string - CreatedDateTime time.Time - CreationType string - Department string - DirSyncEnabled string - DisplayName string - EmployeeId string - FacsimileTelephoneNumber string - GivenName string - ImmutableId string - IsCompromised string - JobTitle string - LastDirSyncTime string - LegalAgeGroupClassification string - Mail string - MailNickname string - Mobile string - OnPremisesDistinguishedName string - OnPremisesSecurityIdentifier string - PasswordPolicies string - PasswordProfile SClouduserPasswordProfile - PhysicalDeliveryOfficeName string - PostalCode string - PreferredLanguage string - RefreshTokensValidFromDateTime time.Time - ShowInAddressList string - SipProxyAddress string - State string - StreetAddress string - Surname string - TelephoneNumber string - ThumbnailPhotoOdataMediaEditLink string `json:"thumbnailPhoto@odata.mediaEditLink"` - UsageLocation string - UserPrincipalName string - UserState string - UserStateChangedOn string - UserType string - - inviteRedeemUrl string -} - -func (user *SClouduser) GetName() string { - return user.UserPrincipalName -} - -func (user *SClouduser) GetGlobalId() string { - return user.Id -} - -func (user *SClouduser) GetEmailAddr() string { - return user.Mail -} - -func (user *SClouduser) GetInviteUrl() string { - return user.inviteRedeemUrl -} - -func (user *SClouduser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := user.client.GetCloudpolicies(user.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetCloudpolicies(%s)", user.Id) - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].Properties.Type == "BuiltInRole" { - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (user *SClouduser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := user.client.GetCloudpolicies(user.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetCloudpolicies(%s)", user.Id) - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].Properties.Type != "BuiltInRole" { - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (user *SClouduser) AttachSystemPolicy(policyId string) error { - for _, subscription := range user.client.subscriptions { - err := user.client.AssignPolicy(user.Id, policyId, subscription.SubscriptionId) - if err != nil { - return errors.Wrapf(err, "AssignPolicy for subscription %s", subscription.SubscriptionId) - } - } - return nil -} - -func (user *SClouduser) AttachCustomPolicy(policyId string) error { - for _, subscription := range user.client.subscriptions { - err := user.client.AssignPolicy(user.Id, policyId, subscription.SubscriptionId) - if err != nil { - return errors.Wrapf(err, "AssignPolicy for subscription %s", subscription.SubscriptionId) - } - } - return nil -} - -func (user *SClouduser) DetachSystemPolicy(policyId string) error { - assignments, err := user.client.GetAssignments(user.Id) - if err != nil { - return errors.Wrapf(err, "GetAssignments(%s)", user.Id) - } - for _, assignment := range assignments { - role, err := user.client.GetRole(assignment.Properties.RoleDefinitionId) - if err != nil { - return errors.Wrapf(err, "GetRule(%s)", assignment.Properties.RoleDefinitionId) - } - if role.Properties.RoleName == policyId { - return user.client.gdel(assignment.Id) - } - } - return nil -} - -func (user *SClouduser) DetachCustomPolicy(policyId string) error { - return user.DetachSystemPolicy(policyId) -} - -func (user *SClouduser) IsConsoleLogin() bool { - return true -} - -// 需要当前应用有User administrator权限 -func (user *SClouduser) Delete() error { - return user.client.DeleteClouduser(user.UserPrincipalName) -} - -func (user *SClouduser) ResetPassword(password string) error { - return user.client.ResetClouduserPassword(user.Id, password) -} - -func (user *SClouduser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - groups, err := user.client.GetUserGroups(user.Id) - if err != nil { - return nil, errors.Wrap(err, "GetUserGroups") - } - ret := []cloudprovider.ICloudgroup{} - for i := range groups { - groups[i].client = user.client - ret = append(ret, &groups[i]) - } - return ret, nil -} - -func (self *SAzureClient) GetUserGroups(userId string) ([]SCloudgroup, error) { - resource := fmt.Sprintf("users/%s/memberOf", userId) - groups := []SCloudgroup{} - err := self.glist(resource, url.Values{}, &groups) - return groups, err -} - -func (self *SAzureClient) ResetClouduserPassword(id, password string) error { - body := jsonutils.Marshal(map[string]interface{}{ - "passwordPolicies": "DisablePasswordExpiration, DisableStrongPassword", - "passwordProfile": map[string]interface{}{ - "password": password, - }, - }) - resource := fmt.Sprintf("%s/users/%s", self.tenantId, id) - _, err := self.gpatch(resource, body) - return err -} - -func (self *SAzureClient) GetClouduser(name string) (*SClouduser, error) { - users, err := self.GetCloudusers() - if err != nil { - return nil, err - } - for i := range users { - if users[i].DisplayName == name || users[i].UserPrincipalName == name { - users[i].client = self - return &users[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SAzureClient) GetCloudusers() ([]SClouduser, error) { - users := []SClouduser{} - params := url.Values{} - err := self.glist("users", params, &users) - if err != nil { - return nil, err - } - return users, nil -} - -func (self *SAzureClient) DeleteClouduser(id string) error { - _, err := self.msGraphRequest(string(httputils.DELETE), "users/"+id, nil) - return err -} - -func (self *SAzureClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { - users, err := self.ListGraphUsers() - if err != nil { - return nil, errors.Wrap(err, "ListGraphUsers") - } - ret := []cloudprovider.IClouduser{} - for i := range users { - users[i].client = self - ret = append(ret, &users[i]) - } - return ret, nil -} - -func (self *SAzureClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - user, err := self.GetClouduser(name) - if err != nil { - return nil, errors.Wrap(err, "GetCloudusers") - } - return user, nil -} - -func (self *SAzureClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - if conf.UserType == "Guest" { - return self.InviteUser(conf.Email) - } - return self.CreateClouduser(conf.Name, conf.Password) -} - -type SDomain struct { - Name string - AuthenticationType string - AvailabilityStatus string - IsAdminManaged bool - IsDefault bool - IsDefaultForCloudRedirections bool - IsInitial bool - IsRoot bool - IsVerified bool - ForceDeleteState string - State string - PasswordValidityPeriodInDays string - PasswordNotificationWindowInDays string -} - -func (self *SAzureClient) GetDomains() ([]SDomain, error) { - domains := []SDomain{} - err := self.glist("domains", nil, &domains) - if err != nil { - return nil, errors.Wrap(err, "glist") - } - return domains, nil -} - -func (self *SAzureClient) GetDefaultDomain() (string, error) { - users, err := self.ListGraphUsers() - if err != nil { - return "", errors.Wrapf(err, "ListGraphUsers") - } - for i := range users { - idx := strings.Index(users[i].UserPrincipalName, "@") - if idx > -1 { - return users[i].UserPrincipalName[idx+1:], nil - } - } - return "", cloudprovider.ErrNotFound -} - -func (self *SAzureClient) CreateClouduser(name, password string) (*SClouduser, error) { - passwordProfile := map[string]interface{}{ - "password": "Lomo1824", - } - if len(password) > 0 { - passwordProfile["password"] = password - } - params := map[string]interface{}{ - "accountEnabled": true, - "displayName": name, - "mailNickname": name, - "passwordProfile": passwordProfile, - "userPrincipalName": name, - } - domain, err := self.GetDefaultDomain() - if err != nil { - return nil, errors.Wrap(err, "GetDefaultDomain") - } - params["userPrincipalName"] = fmt.Sprintf("%s@%s", name, domain) - user := SClouduser{client: self} - resp, err := self.msGraphRequest(string(httputils.POST), "users", jsonutils.Marshal(params)) - if err != nil { - return nil, errors.Wrap(err, "Create") - } - err = resp.Unmarshal(&user) - if err != nil { - return nil, err - } - return &user, nil -} - -func (self *SAzureClient) ListGraphUsers() ([]SClouduser, error) { - resp, err := self.msGraphRequest("GET", "users", nil) - if err != nil { - return nil, errors.Wrapf(err, "msGraphRequest.users") - } - users := []SClouduser{} - err = resp.Unmarshal(&users, "value") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return users, nil -} diff --git a/pkg/multicloud/azure/concurrent/doc.go b/pkg/multicloud/azure/concurrent/doc.go deleted file mode 100644 index 21e8857f5d..0000000000 --- a/pkg/multicloud/azure/concurrent/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 concurrent // import "yunion.io/x/onecloud/pkg/multicloud/azure/concurrent" diff --git a/pkg/multicloud/azure/dbinstance.go b/pkg/multicloud/azure/dbinstance.go deleted file mode 100644 index af82711e0f..0000000000 --- a/pkg/multicloud/azure/dbinstance.go +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceVirtualNetworkRule struct { - ID string `json:"id"` - Name string `json:"name"` - Type string `json:"type"` - Properties SDBInstanceVirtualNetworkRuleProperties `json:"properties"` -} - -type SDBInstanceVirtualNetworkRuleProperties struct { - IgnoreMissingVnetServiceEndpoint bool `json:"ignoreMissingVnetServiceEndpoint"` - State string `json:"state"` - VirtualNetworkSubnetID string `json:"virtualNetworkSubnetId"` -} - -type SDBInstanceSku struct { - Name string `json:"name"` - Tier string `json:"tier"` - Family string `json:"family"` - Capacity int `json:"capacity"` -} - -type SDBInstanceStorageProfile struct { - StorageMB int `json:"storageMB"` - BackupRetentionDays int `json:"backupRetentionDays"` - StorageIops int `json:"storageIops"` - GeoRedundantBackup string `json:"geoRedundantBackup"` -} - -type SDBInstanceDelegatedSubnetArguments struct { - SubnetArmResourceId string `json:"subnetArmResourceId"` -} - -type SDBInstanceProperties struct { - AdministratorLogin string `json:"administratorLogin"` - StorageProfile SDBInstanceStorageProfile `json:"storageProfile"` - Version string `json:"version"` - SslEnforcement string `json:"sslEnforcement"` - UserVisibleState string `json:"userVisibleState"` - FullyQualifiedDomainName string `json:"fullyQualifiedDomainName"` - EarliestRestoreDate time.Time `json:"earliestRestoreDate"` - - ReplicationRole string `json:"replicationRole"` - MasterServerId string `json:"masterServerId"` - ReplicaCapacity int `json:"replicaCapacity"` - DelegatedSubnetArguments SDBInstanceDelegatedSubnetArguments `json:"delegatedSubnetArguments"` -} - -type SDBInstance struct { - region *SRegion - multicloud.SDBInstanceBase - multicloud.AzureTags - Sku SDBInstanceSku `json:"sku"` - Properties SDBInstanceProperties `json:"properties"` - Location string `json:"location"` - ID string `json:"id"` - Name string `json:"name"` - Type string `json:"type"` -} - -func (self *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - instanceTypes := []string{ - "Microsoft.DBForMariaDB/servers", - "Microsoft.DBforMySQL/servers", - "Microsoft.DBforMySQL/flexibleServers", - "Microsoft.DBforPostgreSQL/servers", - "Microsoft.DBforPostgreSQL/flexibleServers", - } - DBInstances := []SDBInstance{} - for i := range instanceTypes { - instances, err := self.ListDBInstance(instanceTypes[i]) - if err != nil { - if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, errors.Wrap(err, "self.ListDBInstance()") - } - } - DBInstances = append(DBInstances, instances...) - } - result := []cloudprovider.ICloudDBInstance{} - for i := range DBInstances { - DBInstances[i].region = self - result = append(result, &DBInstances[i]) - } - sqlServers, err := self.ListSQLServer() - if err != nil { - return nil, errors.Wrapf(err, "ListSQLServer") - } - for i := range sqlServers { - sqlServers[i].region = self - result = append(result, &sqlServers[i]) - } - managedSQLServers, err := self.ListManagedSQLServer() - if err != nil { - return nil, errors.Wrapf(err, "ListManagedSQLServer") - } - for i := range managedSQLServers { - managedSQLServers[i].region = self - result = append(result, &managedSQLServers[i]) - } - return result, nil -} - -func (self *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { - if strings.Index(strings.ToLower(instanceId), "microsoft.sql/servers") > 0 { - return self.GetSQLServer(instanceId) - } - if strings.Index(strings.ToLower(instanceId), "microsoft.sql/managedinstances") > 0 { - return self.GetManagedSQLServer(instanceId) - } - rds, err := self.GetDBInstanceById(instanceId) - if err != nil { - return nil, errors.Wrapf(err, "self.get(%s, url.Values{}, &newrds)", instanceId) - } - return rds, nil -} - -func (self *SRegion) GetDBInstanceById(instanceId string) (*SDBInstance, error) { - rds := SDBInstance{} - err := self.get(instanceId, url.Values{}, &rds) - if err != nil { - return nil, errors.Wrapf(err, "self.get(%s, url.Values{}, &newrds)", instanceId) - } - rds.region = self - return &rds, nil -} - -func (self *SRegion) ListDBInstance(instanceType string) ([]SDBInstance, error) { - result := []SDBInstance{} - err := self.list(instanceType, url.Values{}, &result) - if err != nil { - return nil, errors.Wrapf(err, "list(%s)", instanceType) - } - for i := range result { - result[i].region = self - } - return result, nil -} - -func (self *SRegion) ListDBInstanceReplica(Id string) ([]SDBInstance, error) { - type replicas struct { - Value []SDBInstance - } - result := replicas{} - err := self.get(fmt.Sprintf("%s/replicas", Id), url.Values{}, &result) - if err != nil { - return nil, errors.Wrapf(err, "get(%s)", Id) - } - for i := range result.Value { - result.Value[i].region = self - } - return result.Value, nil -} - -func (self *SRegion) ListDBInstanceVirtualNetworkRule(Id string) ([]SDBInstanceVirtualNetworkRule, error) { - type networksRules struct { - Value []SDBInstanceVirtualNetworkRule - } - result := networksRules{} - err := self.get(fmt.Sprintf("%s/virtualNetworkRules", Id), url.Values{}, &result) - if err != nil { - return nil, errors.Wrapf(err, "get(%s)", Id) - } - return result.Value, nil -} - -func (rds *SDBInstance) GetName() string { - return rds.Name -} - -func (rds *SDBInstance) GetId() string { - return strings.ToLower(rds.ID) -} - -func (rds *SDBInstance) GetGlobalId() string { - return rds.GetId() -} - -func (rds *SDBInstance) GetStatus() string { - return api.DBINSTANCE_RUNNING -} - -func (self *SDBInstance) GetProjectId() string { - return getResourceGroup(self.ID) -} - -func (rds *SDBInstance) GetExpiredAt() time.Time { - return time.Time{} -} - -func (rds *SDBInstance) GetStorageType() string { - switch rds.Sku.Tier { - case "Basic": - return api.STORAGE_AZURE_BASIC - case "General Purpose": - return api.STORAGE_AZURE_GENERAL_PURPOSE - case "Memory Optimized": - return api.STORAGE_AZURE_GENERAL_PURPOSE - default: - return api.STORAGE_AZURE_BASIC - } -} - -func (rds *SDBInstance) Refresh() error { - newrds := SDBInstance{} - err := rds.region.get(rds.ID, url.Values{}, &newrds) - if err != nil { - return errors.Wrapf(err, "rds.region.get(%s, url.Values{}, &newdb)", rds.ID) - } - - err = jsonutils.Update(rds, newrds) - if err != nil { - return err - } - rds.Tags = newrds.Tags - return nil -} - -func (rds *SDBInstance) GetMasterInstanceId() string { - if len(rds.Properties.MasterServerId) > 0 { - return strings.ToLower(rds.Properties.MasterServerId) - } - return "" -} - -func (rds *SDBInstance) GetPort() int { - switch rds.GetEngine() { - case api.DBINSTANCE_TYPE_POSTGRESQL: - return 5432 - case api.DBINSTANCE_TYPE_MYSQL: - return 3306 - case api.DBINSTANCE_TYPE_MARIADB: - return 3306 - default: - return 0 - } -} - -func (rds *SDBInstance) GetEngine() string { - databaseType := strings.Split(rds.Type, "/") - switch databaseType[0] { - case "Microsoft.DBforPostgreSQL": - return api.DBINSTANCE_TYPE_POSTGRESQL - case "Microsoft.DBforMySQL": - return api.DBINSTANCE_TYPE_MYSQL - case "Microsoft.DBforMariaDB": - return api.DBINSTANCE_TYPE_MARIADB - default: - return "" - } -} - -func (rds *SDBInstance) GetEngineVersion() string { - return rds.Properties.Version -} - -func (rds *SDBInstance) GetInstanceType() string { - return rds.Sku.Name -} - -func (rds *SDBInstance) GetVcpuCount() int { - return rds.Sku.Capacity -} - -func (rds *SDBInstance) GetVmemSizeMB() int { - if strings.Contains(rds.Type, "server") { - switch rds.Sku.Tier { - case "Basic": - return rds.Sku.Capacity * 2 * 1024 - case "General Purpose": - return rds.Sku.Capacity * 5 * 1024 - case "GeneralPurpose": - return int(float32(rds.Sku.Capacity) * 5.2 * 1024) - case "Memory Optimized": - return rds.Sku.Capacity * 10 * 1024 - default: - return 0 - } - } - return 0 -} - -func (rds *SDBInstance) GetDiskSizeGB() int { - return rds.Properties.StorageProfile.StorageMB / 1024 -} - -func (rds *SDBInstance) GetCategory() string { - return rds.Sku.Tier -} - -func (rds *SDBInstance) GetMaintainTime() string { - return "" -} - -func (rds *SDBInstance) GetConnectionStr() string { - return rds.Properties.FullyQualifiedDomainName -} - -// func (rds *SDBInstance) GetInternalConnectionStr() string - -func (rds *SDBInstance) GetIVpcId() string { - splited := strings.Split(rds.Properties.DelegatedSubnetArguments.SubnetArmResourceId, "/subnets") - return splited[0] -} - -func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { - result := []cloudprovider.SDBInstanceNetwork{} - delegateNet := cloudprovider.SDBInstanceNetwork{NetworkId: rds.Properties.DelegatedSubnetArguments.SubnetArmResourceId} - result = append(result, delegateNet) - return result, nil -} - -func (rds *SDBInstance) GetZone1Id() string { - return "" -} - -func (rds *SDBInstance) GetZone2Id() string { - return "" -} - -func (rds *SDBInstance) GetZone3Id() string { - return "" -} - -func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { - configs, err := rds.region.ListDBInstanceConfiguration(rds.ID) - if err != nil { - return nil, errors.Wrapf(err, "rds.region.ListDBInstanceConfiguration(%s)", rds.ID) - } - result := []cloudprovider.ICloudDBInstanceParameter{} - for i := range configs { - result = append(result, &configs[i]) - } - return result, nil -} - -func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { - db, err := rds.region.ListSDBInstanceDatabase(rds.ID) - if err != nil { - return nil, errors.Wrapf(err, "rds.region.ListSDBInstanceDatabase(%s)", rds.ID) - } - result := []cloudprovider.ICloudDBInstanceDatabase{} - for i := range db { - result = append(result, &db[i]) - } - return result, nil -} - -func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { - accounts := []cloudprovider.ICloudDBInstanceAccount{} - if len(rds.Properties.AdministratorLogin) > 0 { - account := &SDBInstanceAccount{instance: rds, AccountName: rds.Properties.AdministratorLogin} - accounts = append(accounts, account) - } - return accounts, nil -} - -func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - return []cloudprovider.ICloudDBInstanceBackup{}, nil -} - -func (rds *SDBInstance) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error { - if !replace { - for k, v := range self.Tags { - if _, ok := tags[k]; !ok { - tags[k] = v - } - } - } - _, err := self.region.client.SetTags(self.ID, tags) - if err != nil { - return errors.Wrapf(err, "self.region.client.SetTags(%s,%s)", self.ID, jsonutils.Marshal(tags).String()) - } - return nil -} diff --git a/pkg/multicloud/azure/dbinstance_account.go b/pkg/multicloud/azure/dbinstance_account.go deleted file mode 100644 index 3582e9d258..0000000000 --- a/pkg/multicloud/azure/dbinstance_account.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import "yunion.io/x/onecloud/pkg/multicloud" - -type SDBInstanceAccount struct { - multicloud.SDBInstanceAccountBase - multicloud.AzureTags - instance *SDBInstance - - AccountName string -} - -func (account *SDBInstanceAccount) GetName() string { - return account.AccountName + "@" + account.instance.Name -} diff --git a/pkg/multicloud/azure/dbinstance_database.go b/pkg/multicloud/azure/dbinstance_database.go deleted file mode 100644 index b2fa24fb7a..0000000000 --- a/pkg/multicloud/azure/dbinstance_database.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceDatabase struct { - region *SRegion - multicloud.SDBInstanceDatabaseBase - multicloud.AzureTags - ID string `json:"id"` - Name string `json:"name"` - Type string `json:"type"` - Properties SDBInstanceDatabaseProperties `json:"properties"` -} - -type SDBInstanceDatabaseProperties struct { - Charset string `json:"charset"` - Collation string `json:"collation"` -} - -func (self *SRegion) ListSDBInstanceDatabase(Id string) ([]SDBInstanceDatabase, error) { - type databases struct { - Value []SDBInstanceDatabase - } - - result := databases{} - err := self.get(fmt.Sprintf("%s/databases", Id), url.Values{}, &result) - if err != nil { - return nil, errors.Wrapf(err, "get(%s/databases)", Id) - } - return result.Value, nil -} - -func (database *SDBInstanceDatabase) GetCharacterSet() string { - return database.Properties.Charset -} - -func (database *SDBInstanceDatabase) GetName() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetGlobalId() string { - return strings.ToLower(database.ID) -} - -func (database *SDBInstanceDatabase) GetId() string { - return strings.ToLower(database.ID) -} - -func (database *SDBInstanceDatabase) IsEmulated() bool { - return false -} - -func (database *SDBInstanceDatabase) Refresh() error { - newdb := SDBInstanceDatabase{} - err := database.region.get(database.ID, url.Values{}, &newdb) - if err != nil { - return errors.Wrapf(err, "database.region.get(%s, url.Values{}, &newdb)", database.ID) - } - - return jsonutils.Update(database, newdb) -} - -func (database *SDBInstanceDatabase) GetStatus() string { - return api.DBINSTANCE_DATABASE_RUNNING -} diff --git a/pkg/multicloud/azure/disk.go b/pkg/multicloud/azure/disk.go deleted file mode 100644 index 15a2e1fc6c..0000000000 --- a/pkg/multicloud/azure/disk.go +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "context" - "fmt" - "net/url" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type DiskSku struct { - Name string `json:"name,omitempty"` - Tier string `json:"tier,omitempty"` -} - -type ImageDiskReference struct { - ID string - Lun int32 `json:"lun,omitempty"` -} - -type CreationData struct { - CreateOption string `json:"createOption,omitempty"` - StorageAccountID string - // ImageReference *ImageDiskReference `json:"imageReference,omitempty"` - ImageReference *ImageReference `json:"imageReference,omitempty"` - SourceURI string `json:"sourceUri,omitempty"` - SourceResourceID string `json:"sourceResourceId,omitempty"` -} - -type TAzureInt32 string - -func (ai TAzureInt32) Int32() int32 { - num, _ := strconv.Atoi(strings.Trim(string(ai), "\t")) - return int32(num) -} - -type DiskProperties struct { - TimeCreated time.Time `json:"timeCreated,omitempty"` - OsType string `json:"osType,omitempty"` - CreationData CreationData `json:"creationData,omitempty"` - DiskSizeGB TAzureInt32 `json:"diskSizeGB,omitempty"` - ProvisioningState string `json:"provisioningState,omitempty"` - DiskState string `json:"diskState,omitempty"` -} - -type SDisk struct { - storage *SStorage - multicloud.SDisk - multicloud.AzureTags - - ManagedBy string `json:"managedBy,omitempty"` - Sku DiskSku `json:"sku,omitempty"` - Zones []string `json:"zones,omitempty"` - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Type string `json:"type,omitempty"` - Location string `json:"location,omitempty"` - Properties DiskProperties `json:"properties,omitempty"` -} - -func (self *SRegion) CreateDisk(storageType string, name string, sizeGb int32, imageId, snapshotId, resourceGroup string) (*SDisk, error) { - params := jsonutils.Marshal(map[string]interface{}{ - "Name": name, - "Location": self.Name, - "Sku": map[string]string{ - "Name": storageType, - }, - "Type": "Microsoft.Compute/disks", - }).(*jsonutils.JSONDict) - properties := map[string]interface{}{ - "CreationData": map[string]string{ - "CreateOption": "Empty", - }, - "DiskSizeGB": sizeGb, - } - if len(imageId) > 0 { - image, err := self.GetImageById(imageId) - if err != nil { - return nil, errors.Wrapf(err, "GetImageById(%s)", imageId) - } - // 通过镜像创建的磁盘只能传ID参数,不能通过sku,offer等参数创建. - imageId, err := self.getOfferedImageId(&image) - if err != nil { - return nil, errors.Wrapf(err, "getOfferedImageId") - } - properties = map[string]interface{}{ - "CreationData": map[string]interface{}{ - "CreateOption": "FromImage", - "ImageReference": map[string]string{ - "Id": imageId, - }, - }, - } - } else if len(snapshotId) > 0 { - properties = map[string]interface{}{ - "CreationData": map[string]interface{}{ - "CreateOption": "Copy", - "sourceResourceId": snapshotId, - }, - } - } - params.Add(jsonutils.Marshal(properties), "Properties") - disk := &SDisk{} - return disk, self.create(resourceGroup, params, disk) -} - -func (self *SRegion) DeleteDisk(diskId string) error { - return cloudprovider.Wait(time.Second*5, time.Minute*5, func() (bool, error) { - err := self.del(diskId) - if err == nil { - return true, nil - } - // Disk vdisk_stress-testvm-azure-1-1_1555940308395625000 is attached to VM /subscriptions/d4f0ec08-3e28-4ae5-bdf9-3dc7c5b0eeca/resourceGroups/Default/providers/Microsoft.Compute/virtualMachines/stress-testvm-azure-1. - // 更换系统盘后,数据未刷新会出现如上错误,多尝试几次即可 - if strings.Contains(err.Error(), "is attached to VM") { - return false, nil - } - return false, err - }) -} - -func (self *SRegion) ResizeDisk(diskId string, sizeGb int32) error { - disk, err := self.GetDisk(diskId) - if err != nil { - return err - } - disk.Properties.DiskSizeGB = TAzureInt32(fmt.Sprintf("%d", sizeGb)) - disk.Properties.ProvisioningState = "" - return self.update(jsonutils.Marshal(disk), nil) -} - -func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { - disk := SDisk{} - return &disk, self.get(diskId, url.Values{}, &disk) -} - -func (self *SRegion) GetDisks() ([]SDisk, error) { - disks := []SDisk{} - err := self.list("Microsoft.Compute/disks", url.Values{}, &disks) - if err != nil { - return nil, err - } - return disks, nil -} - -func (self *SDisk) GetTags() (map[string]string, error) { - return self.Tags, nil -} - -func (self *SDisk) GetStatus() string { - // 为了不统计这种磁盘挂载率, 单独设置一个状态 - if self.Properties.DiskState == "ActiveSAS" { - return self.Properties.DiskState - } - status := self.Properties.ProvisioningState - switch status { - case "Updating": - return api.DISK_ALLOCATING - case "Succeeded": - return api.DISK_READY - default: - log.Errorf("Unknow azure disk %s status: %s", self.ID, status) - return api.DISK_UNKNOWN - } -} - -func (self *SDisk) GetId() string { - return self.ID -} - -func (self *SDisk) Refresh() error { - disk, err := self.storage.zone.region.GetDisk(self.ID) - if err != nil { - return errors.Wrapf(err, "GetDisk(%s)", self.ID) - } - return jsonutils.Update(self, disk) -} - -func (self *SDisk) Delete(ctx context.Context) error { - return self.storage.zone.region.DeleteDisk(self.ID) -} - -func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { - return self.storage.zone.region.ResizeDisk(self.ID, int32(sizeMb/1024)) -} - -func (self *SDisk) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.ID -} - -func (self *SDisk) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SDisk) IsEmulated() bool { - return false -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.storage, nil -} - -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) GetDiskFormat() string { - return "vhd" -} - -func (self *SDisk) GetDiskSizeMB() int { - return int(self.Properties.DiskSizeGB.Int32()) * 1024 -} - -func (self *SDisk) GetIsAutoDelete() bool { - return false -} - -func (self *SDisk) GetTemplateId() string { - if self.Properties.CreationData.ImageReference != nil { - return self.Properties.CreationData.ImageReference.ID - } - return "" -} - -func (self *SDisk) GetDiskType() string { - if len(self.Properties.OsType) > 0 { - return api.DISK_TYPE_SYS - } - return api.DISK_TYPE_DATA -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := self.storage.zone.region.CreateSnapshot(self.ID, name, desc) - if err != nil { - return nil, errors.Wrapf(err, "CreateSnapshot") - } - return snapshot, nil -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := self.storage.zone.region.ListSnapshots() - if err != nil { - return nil, errors.Wrapf(err, "ListSnapshots") - } - ret := []cloudprovider.ICloudSnapshot{} - for i := range snapshots { - if strings.ToLower(snapshots[i].Properties.CreationData.SourceResourceID) == strings.ToLower(self.ID) { - snapshots[i].region = self.storage.zone.region - ret = append(ret, &snapshots[i]) - } - } - return ret, nil -} - -func (self *SDisk) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SDisk) GetCreatedAt() time.Time { - return self.Properties.TimeCreated -} - -func (self *SDisk) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - if self.Properties.DiskState != "Unattached" { - return "", fmt.Errorf("Azure reset disk needs to be done in the Unattached state, current status: %s", self.Properties.DiskState) - } - disk, err := self.storage.zone.region.CreateDisk(self.Sku.Name, self.Name, 0, "", snapshotId, self.GetProjectId()) - if err != nil { - return "", errors.Wrap(err, "CreateDisk") - } - err = self.storage.zone.region.DeleteDisk(self.ID) - if err != nil { - log.Warningf("delete old disk %s error: %v", self.ID, err) - } - return disk.ID, nil -} - -func (disk *SDisk) GetAccessPath() string { - return "" -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - // TODO - return cloudprovider.ErrNotSupported -} - -func (self *SDisk) GetProjectId() string { - return getResourceGroup(self.ID) -} diff --git a/pkg/multicloud/azure/doc.go b/pkg/multicloud/azure/doc.go deleted file mode 100644 index 6e3089e52a..0000000000 --- a/pkg/multicloud/azure/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure // import "yunion.io/x/onecloud/pkg/multicloud/azure" diff --git a/pkg/multicloud/azure/eip.go b/pkg/multicloud/azure/eip.go deleted file mode 100644 index d0f3df0054..0000000000 --- a/pkg/multicloud/azure/eip.go +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type PublicIPAddressSku struct { - Name string -} - -type IPConfigurationPropertiesFormat struct { - PrivateIPAddress string -} - -type IPConfiguration struct { - Name string - ID string -} - -type PublicIPAddressPropertiesFormat struct { - PublicIPAddressVersion string `json:"publicIPAddressVersion,omitempty"` - IPAddress string `json:"ipAddress,omitempty"` - PublicIPAllocationMethod string `json:"publicIPAllocationMethod,omitempty"` - ProvisioningState string `json:"provisioningState,omitempty"` - IPConfiguration IPConfiguration `json:"ipConfiguration,omitempty"` -} - -type SEipAddress struct { - region *SRegion - multicloud.SEipBase - multicloud.AzureTags - - ID string - Name string - Location string - Properties PublicIPAddressPropertiesFormat `json:"properties,omitempty"` - Type string - Sku *PublicIPAddressSku -} - -func (self *SRegion) AllocateEIP(name, projectId string) (*SEipAddress, error) { - params := map[string]interface{}{ - "Location": self.Name, - "Name": name, - "Properties": map[string]string{ - "PublicIPAddressVersion": "IPv4", - "PublicIPAllocationMethod": "Static", - }, - "Type": "Microsoft.Network/publicIPAddresses", - } - eip := &SEipAddress{region: self} - err := self.create(projectId, jsonutils.Marshal(params), eip) - if err != nil { - return nil, err - } - return eip, cloudprovider.WaitStatus(eip, api.EIP_STATUS_READY, 10*time.Second, 300*time.Second) -} - -func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - return region.AllocateEIP(eip.Name, eip.ProjectId) -} - -func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { - eip := SEipAddress{region: region} - return &eip, region.get(eipId, url.Values{}, &eip) -} - -func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { - return self.region.AssociateEip(self.ID, conf.InstanceId) -} - -func (region *SRegion) AssociateEip(eipId string, instanceId string) error { - instance, err := region.GetInstance(instanceId) - if err != nil { - return err - } - if len(instance.Properties.NetworkProfile.NetworkInterfaces) > 0 { - nic, err := region.GetNetworkInterface(instance.Properties.NetworkProfile.NetworkInterfaces[0].ID) - if err != nil { - return err - } - if len(nic.Properties.IPConfigurations) > 0 { - nic.Properties.IPConfigurations[0].Properties.PublicIPAddress = &PublicIPAddress{ID: eipId} - return region.update(jsonutils.Marshal(nic), nil) - } - return fmt.Errorf("network interface with no IPConfigurations") - } - return fmt.Errorf("Instance with no interface") -} - -func (region *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { - return region.GetEip(eipId) -} - -func (self *SEipAddress) ChangeBandwidth(bw int) error { - return cloudprovider.ErrNotSupported -} - -func (self *SEipAddress) Delete() error { - self.Dissociate() //避免eip挂载在弹性网卡之上,导致删除失败 - return self.region.DeallocateEIP(self.ID) -} - -func (region *SRegion) DeallocateEIP(eipId string) error { - return cloudprovider.Wait(time.Second*5, time.Minute*5, func() (bool, error) { - err := region.del(eipId) - if err == nil { - return true, nil - } - // {"error":{"code":"PublicIPAddressCannotBeDeleted","details":[],"message":"Public IP address /subscriptions/d4f0ec08-3e28-4ae5-bdf9-3dc7c5b0eeca/resourceGroups/Default/providers/Microsoft.Network/publicIPAddresses/eip-for-test-wwl can not be deleted since it is still allocated to resource /subscriptions/d4f0ec08-3e28-4ae5-bdf9-3dc7c5b0eeca/resourceGroups/Default/providers/Microsoft.Network/networkInterfaces/test-wwl-ipconfig."}} - // 刚解绑eip后可能数据未刷新,需要再次尝试 - if strings.Contains(err.Error(), "it is still allocated to resource") { - return false, nil - } - return false, errors.Wrapf(err, "del(%s)", eipId) - }) -} - -func (self *SEipAddress) Dissociate() error { - return self.region.DissociateEip(self.ID) -} - -func (region *SRegion) DissociateEip(eipId string) error { - eip, err := region.GetEip(eipId) - if err != nil { - return errors.Wrapf(err, "GetEip(%s)", eipId) - } - interfaceId := eip.Properties.IPConfiguration.ID - if strings.Index(interfaceId, "/ipConfigurations/") > 0 { - interfaceId = strings.Split(interfaceId, "/ipConfigurations/")[0] - } - nic, err := region.GetNetworkInterface(interfaceId) - if err != nil { - return err - } - for i := 0; i < len(nic.Properties.IPConfigurations); i++ { - if nic.Properties.IPConfigurations[i].Properties.PublicIPAddress != nil && nic.Properties.IPConfigurations[i].Properties.PublicIPAddress.ID == eipId { - nic.Properties.IPConfigurations[i].Properties.PublicIPAddress = nil - break - } - } - return region.update(jsonutils.Marshal(nic), nil) -} - -func (self *SEipAddress) GetAssociationExternalId() string { - if self.GetAssociationType() == api.EIP_ASSOCIATE_TYPE_SERVER { - info := strings.Split(self.Properties.IPConfiguration.ID, "/") - nic, _ := self.region.GetNetworkInterface(strings.Join(info[:len(info)-2], "/")) - if nic != nil { - return strings.ToLower(nic.Properties.VirtualMachine.ID) - } - } - return "" -} - -func (self *SEipAddress) GetAssociationType() string { - if len(self.Properties.IPConfiguration.ID) == 0 { - return "" - } - if info := strings.Split(self.Properties.IPConfiguration.ID, "/"); len(info) > 7 { - resType := strings.ToLower(info[7]) - if utils.IsInStringArray(resType, []string{"networkinterfaces"}) { - return api.EIP_ASSOCIATE_TYPE_SERVER - } - return resType - } - return "" -} - -func (self *SEipAddress) GetBandwidth() int { - return 0 -} - -func (self *SEipAddress) GetINetworkId() string { - return "" -} - -func (self *SEipAddress) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SEipAddress) GetId() string { - return self.ID -} - -func (self *SEipAddress) GetInternetChargeType() string { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC -} - -func (self *SEipAddress) GetIpAddr() string { - return self.Properties.IPAddress -} - -func (self *SEipAddress) GetMode() string { - if self.IsEmulated() { - return api.EIP_MODE_INSTANCE_PUBLICIP - } - return api.EIP_MODE_STANDALONE_EIP -} - -func (self *SEipAddress) GetName() string { - return self.Name -} - -func (self *SEipAddress) GetStatus() string { - switch self.Properties.ProvisioningState { - case "Succeeded", "": - return api.EIP_STATUS_READY - case "Updating": - return api.EIP_STATUS_ALLOCATE - default: - log.Errorf("Unknown eip status: %s", self.Properties.ProvisioningState) - return api.EIP_STATUS_UNKNOWN - } -} - -func (self *SEipAddress) IsEmulated() bool { - if strings.ToLower(self.Properties.PublicIPAllocationMethod) == "Dynamic" || len(self.Properties.IPAddress) == 0 { - return true - } - return false -} - -func (self *SEipAddress) Refresh() error { - eip, err := self.region.GetEip(self.ID) - if err != nil { - return err - } - return jsonutils.Update(self, eip) -} - -func (self *SEipAddress) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SEipAddress) GetCreatedAt() time.Time { - return time.Time{} -} - -func (self *SEipAddress) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SEipAddress) GetProjectId() string { - return getResourceGroup(self.ID) -} diff --git a/pkg/multicloud/azure/enrollment_account.go b/pkg/multicloud/azure/enrollment_account.go deleted file mode 100644 index 467276c00b..0000000000 --- a/pkg/multicloud/azure/enrollment_account.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SEnrollmentAccountProperties struct { - PrincipalName string - OfferTypes []string -} - -type SEnrollmentAccount struct { - Id string - Name string - Type string - Properties SEnrollmentAccountProperties -} - -func (cli *SAzureClient) GetEnrollmentAccounts() ([]cloudprovider.SEnrollmentAccount, error) { - accounts := []SEnrollmentAccount{} - err := cli.list("providers/Microsoft.Billing/enrollmentAccounts", nil, &accounts) - if err != nil { - return nil, err - } - eas := []cloudprovider.SEnrollmentAccount{} - for i := range accounts { - ea := cloudprovider.SEnrollmentAccount{ - Id: accounts[i].Name, - Name: accounts[i].Properties.PrincipalName, - Type: accounts[i].Type, - } - eas = append(eas, ea) - } - return eas, nil -} - -func (cli *SAzureClient) CreateSubscription(name string, eaId string, offerType string) error { - appId, err := cli.GetAppObjectId() - if err != nil { - log.Errorf("GetAppObjectId error: %v", err) - } - owners := []map[string]string{} - if len(appId) > 0 { - owners = append(owners, map[string]string{"objectId": appId}) - } - body := map[string]interface{}{ - "displayName": name, - "offerType": offerType, - "owners": owners, - } - resource := fmt.Sprintf("providers/Microsoft.Billing/enrollmentAccounts/%s/providers/Microsoft.Subscription/createSubscription", eaId) - _, err = cli.post(resource, jsonutils.Marshal(body)) - return err -} - -type SServicePrincipal struct { - AppId string - ObjectId string -} - -func (cli *SAzureClient) GetAppObjectId() (string, error) { - result, err := cli.ListServicePrincipal(cli.clientId) - if err != nil { - return "", errors.Wrap(err, "ListServicePrincipal") - } - if len(result) == 1 { - return result[0].ObjectId, nil - } - return "", nil -} - -func (cli *SAzureClient) ListServicePrincipal(appId string) ([]SServicePrincipal, error) { - params := url.Values{} - if len(appId) > 0 { - params.Set("$filter", fmt.Sprintf(`appId eq '%s'`, cli.clientId)) - } - result := []SServicePrincipal{} - return result, cli.glist("servicePrincipals", params, &result) -} diff --git a/pkg/multicloud/azure/event.go b/pkg/multicloud/azure/event.go deleted file mode 100644 index ff9ab09c55..0000000000 --- a/pkg/multicloud/azure/event.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SAuthorization struct { - Action string - Scope string -} - -type SClaims struct { - Aud string - Iss string - Iat string - Nbf string - Exp string - Aio string - Appid string - Appidacr string - Uti string - Ver string -} - -type SLocalized struct { - Value string - LocalizedValue string -} - -type SEvent struct { - region *SRegion - - Authorization SAuthorization - Channels string - Claims SClaims - CorrelationId string - Description string - EventDataId string - EventName SLocalized - Category SLocalized - Level string - ResourceGroupName string - ResourceProviderName SLocalized - ResourceId string - ResourceType SLocalized - OperationId string - OperationName SLocalized - Properties string - Status SLocalized - SubStatus SLocalized - Caller string - EventTimestamp time.Time - SubmissionTimestamp time.Time - SubscriptionId string - TenantId string - ID string - Name string -} - -func (event *SEvent) GetName() string { - return event.ResourceId -} - -func (event *SEvent) GetService() string { - return event.ResourceProviderName.Value -} - -func (event *SEvent) GetAction() string { - return event.OperationName.Value -} - -func (event *SEvent) GetResourceType() string { - return event.ResourceType.Value -} - -func (event *SEvent) GetRequestId() string { - return event.CorrelationId -} - -func (event *SEvent) GetRequest() jsonutils.JSONObject { - return jsonutils.Marshal(event) -} - -func (event *SEvent) GetAccount() string { - return event.Claims.Appid -} - -func (event *SEvent) IsSuccess() bool { - return event.Status.Value != "Failed" -} - -func (event *SEvent) GetCreatedAt() time.Time { - return event.EventTimestamp -} - -func (region *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { - events, err := region.GetEvents(start, end) - if err != nil { - return nil, err - } - iEvents := []cloudprovider.ICloudEvent{} - for i := range events { - read := false - for _, k := range []string{"read", "listKeys"} { - if strings.Contains(events[i].Authorization.Action, k) { - read = true - break - } - } - if withReadEvent || !read { - iEvents = append(iEvents, &events[i]) - } - } - return iEvents, nil -} - -func (region *SRegion) GetEvents(start time.Time, end time.Time) ([]SEvent, error) { - events := []SEvent{} - if start.IsZero() { - start = time.Now().AddDate(0, 0, -7) - } - if end.IsZero() { - end = time.Now() - } - params := url.Values{} - params.Set("$filter", fmt.Sprintf("eventTimestamp ge '%s' and eventTimestamp le '%s' and eventChannels eq 'Admin, Operation' and levels eq 'Critical,Error,Warning,Informational'", start.Format("2006-01-02T15:04:05Z"), end.Format("2006-01-02T15:04:05Z"))) - resource := fmt.Sprintf("microsoft.insights/eventtypes/management/values") - err := region.client.list(resource, params, &events) - if err != nil { - return nil, err - } - return events, nil -} diff --git a/pkg/multicloud/azure/host.go b/pkg/multicloud/azure/host.go deleted file mode 100644 index 65f3ff903f..0000000000 --- a/pkg/multicloud/azure/host.go +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/seclib2" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone -} - -func (self *SHost) GetId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) GetName() string { - return fmt.Sprintf("%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId) -} - -func (self *SHost) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId) -} - -func (self *SHost) IsEmulated() bool { - return true -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) Refresh() error { - return nil -} - -func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - nic, err := self.zone.region.CreateNetworkInterface(desc.ProjectId, fmt.Sprintf("%s-ipconfig", desc.NameEn), desc.IpAddr, desc.ExternalNetworkId, desc.ExternalSecgroupId) - if err != nil { - return nil, errors.Wrapf(err, "CreateNetworkInterface") - } - - instance, err := self.zone.region._createVM(desc, nic.ID) - if err != nil { - self.zone.region.DeleteNetworkInterface(nic.ID) - return nil, err - } - instance.host = self - return instance, nil -} - -func (self *SRegion) _createVM(desc *cloudprovider.SManagedVMCreateConfig, nicId string) (*SInstance, error) { - image, err := self.GetImageById(desc.ExternalImageId) - if err != nil { - return nil, errors.Wrapf(err, "GetImageById(%s)", desc.ExternalImageId) - } - - if len(desc.Password) == 0 { - //Azure创建必须要设置密码 - desc.Password = seclib2.RandomPassword2(12) - } - - if image.Properties.ProvisioningState != ImageStatusAvailable { - return nil, fmt.Errorf("image %s not ready status: %s", desc.ExternalImageId, image.Properties.ProvisioningState) - } - if !utils.IsInStringArray(desc.OsType, []string{osprofile.OS_TYPE_LINUX, osprofile.OS_TYPE_WINDOWS}) { - desc.OsType = string(image.GetOsType()) - } - computeName := desc.Hostname - for _, k := range "`~!@#$%^&*()=+_[]{}\\|;:.'\",<>/?" { - computeName = strings.Replace(computeName, string(k), "", -1) - } - if len(computeName) > 15 { - computeName = computeName[:15] - } - osProfile := map[string]string{ - "ComputerName": computeName, - "AdminUsername": api.VM_AZURE_DEFAULT_LOGIN_USER, - "AdminPassword": desc.Password, - } - if len(desc.UserData) > 0 { - osProfile["CustomData"] = desc.UserData - } - params := jsonutils.Marshal(map[string]interface{}{ - "Name": desc.NameEn, - "Location": self.Name, - "Properties": map[string]interface{}{ - "HardwareProfile": map[string]string{ - "VMSize": "", - }, - "OsProfile": osProfile, - "NetworkProfile": map[string]interface{}{ - "NetworkInterfaces": []map[string]string{ - map[string]string{ - "Id": nicId, - }, - }, - }, - "StorageProfile": map[string]interface{}{ - "ImageReference": image.getImageReference(), - "OsDisk": map[string]interface{}{ - "Name": fmt.Sprintf("vdisk_%s_%d", desc.Name, time.Now().UnixNano()), - "Caching": "ReadWrite", - "ManagedDisk": map[string]string{ - "StorageAccountType": desc.SysDisk.StorageType, - }, - "CreateOption": "FromImage", - "DiskSizeGB": desc.SysDisk.SizeGB, - "OsType": desc.OsType, - }, - }, - }, - "Type": "Microsoft.Compute/virtualMachines", - }).(*jsonutils.JSONDict) - if len(desc.PublicKey) > 0 && desc.OsType == osprofile.OS_TYPE_LINUX { - linuxConfiguration := map[string]interface{}{ - "DisablePasswordAuthentication": false, - "SSH": map[string]interface{}{ - "PublicKeys": []map[string]string{ - map[string]string{ - "KeyData": desc.PublicKey, - "Path": fmt.Sprintf("/home/%s/.ssh/authorized_keys", api.VM_AZURE_DEFAULT_LOGIN_USER), - }, - }, - }, - } - params.Add(jsonutils.Marshal(linuxConfiguration), "Properties", "OsProfile", "LinuxConfiguration") - } - if len(desc.Tags) > 0 { - params.Add(jsonutils.Marshal(desc.Tags), "tags") - } - - dataDisks := jsonutils.NewArray() - for i := 0; i < len(desc.DataDisks); i++ { - dataDisk := jsonutils.Marshal(map[string]interface{}{ - "Name": fmt.Sprintf("vdisk_%s_%d", desc.Name, time.Now().UnixNano()), - "DiskSizeGB": desc.DataDisks[i].SizeGB, - "CreateOption": "Empty", - "ManagedDisk": map[string]string{ - "StorageAccountType": desc.DataDisks[i].StorageType, - }, - "Lun": i, - }) - dataDisks.Add(dataDisk) - } - if dataDisks.Length() > 0 { - params.Add(dataDisks, "Properties", "StorageProfile", "DataDisks") - } - - instance := &SInstance{} - if len(desc.InstanceType) > 0 { - params.Add(jsonutils.NewString(desc.InstanceType), "Properties", "HardwareProfile", "VMSize") - log.Debugf("Try HardwareProfile : %s", desc.InstanceType) - err = self.create(desc.ProjectId, params, instance) - if err != nil { - return nil, errors.Wrapf(err, "create") - } - return instance, nil - } - - for _, profile := range self.getHardwareProfile(desc.Cpu, desc.MemoryMB) { - params.Add(jsonutils.NewString(profile), "Properties", "HardwareProfile", "VMSize") - log.Debugf("Try HardwareProfile : %s", profile) - err = self.create(desc.ProjectId, params, &instance) - if err != nil { - for _, key := range []string{`"code":"InvalidParameter"`, `"code":"NicInUse"`} { - if strings.Contains(err.Error(), key) { - return nil, err - } - } - log.Errorf("Failed for %s: %s", profile, err) - continue - } - return instance, nil - } - if err != nil { - return nil, err - } - return nil, fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB) -} - -func (self *SHost) GetAccessIp() string { - return "" -} - -func (self *SHost) GetAccessMac() string { - return "" -} - -func (self *SHost) GetCpuCount() int { - 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) GetEnabled() bool { - return true -} - -func (self *SHost) GetHostStatus() string { - return api.HOST_ONLINE -} -func (self *SHost) GetNodeCount() int8 { - return 0 -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_AZURE -} - -func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return self.zone.GetIStorageById(id) -} - -func (self *SHost) GetSysInfo() jsonutils.JSONObject { - info := jsonutils.NewDict() - info.Add(jsonutils.NewString(CLOUD_PROVIDER_AZURE), "manufacture") - return info -} - -func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - return self.zone.getIStorages(), nil -} - -func (self *SHost) GetIVMById(instanceId string) (cloudprovider.ICloudVM, error) { - instance, err := self.zone.region.GetInstance(instanceId) - if err != nil { - return nil, err - } - instance.host = self - return instance, nil -} - -func (self *SHost) GetStorageSizeMB() int { - return 0 -} - -func (self *SHost) GetStorageType() string { - return api.DISK_TYPE_HYBRID -} - -func (self *SHost) GetSN() string { - return "" -} - -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms, err := self.zone.region.GetInstances() - if err != nil { - return nil, err - } - ivms := make([]cloudprovider.ICloudVM, len(vms)) - for i := 0; i < len(vms); i++ { - vms[i].host = self - ivms[i] = &vms[i] - log.Debugf("find vm %s for host %s", vms[i].GetName(), self.GetName()) - } - return ivms, nil -} - -func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - return self.zone.GetIWires() -} - -func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (host *SHost) GetIsMaintenance() bool { - return false -} - -func (host *SHost) GetVersion() string { - return AZURE_API_VERSION -} diff --git a/pkg/multicloud/azure/image.go b/pkg/multicloud/azure/image.go deleted file mode 100644 index 9455c60077..0000000000 --- a/pkg/multicloud/azure/image.go +++ /dev/null @@ -1,607 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "context" - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/apis" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type ImageStatusType string - -const ( - ImageStatusCreating ImageStatusType = "Creating" - ImageStatusAvailable ImageStatusType = "Succeeded" - ImageStatusUnAvailable ImageStatusType = "UnAvailable" - ImageStatusCreateFailed ImageStatusType = "CreateFailed" -) - -type OperatingSystemStateTypes string - -type ImageOSDisk struct { - OsType string `json:"osType,omitempty"` - OsState string `json:"osState,omitempty"` - Snapshot *SubResource `json:"snapshot,omitempty"` - ManagedDisk *SubResource - BlobURI string `json:"blobUri,omitempty"` - Caching string `json:"caching,omitempty"` - DiskSizeGB int32 `json:"diskSizeGB,omitzero"` - StorageAccountType string `json:"storageAccountType,omitempty"` - OperatingSystem string `json:"operatingSystem,omitempty"` -} - -type ImageDataDisk struct { - Lun int32 - Snapshot SubResource - ManagedDisk SubResource - BlobURI string - Caching string - DiskSizeGB int32 `json:"diskSizeGB,omitzero"` - StorageAccountType string -} - -type ImageStorageProfile struct { - OsDisk ImageOSDisk `json:"osDisk,omitempty"` - DataDisks []ImageDataDisk `json:"dataDisks,omitempty"` - ZoneResilient bool `json:"zoneResilient,omitfalse"` -} - -type SAutomaticOSUpgradeProperties struct { - AutomaticOSUpgradeSupported bool -} - -type ImageProperties struct { - SourceVirtualMachine *SubResource - StorageProfile ImageStorageProfile `json:"storageProfile,omitempty"` - ProvisioningState ImageStatusType - HyperVGeneration string `json:"hyperVGeneration,omitempty"` -} - -type SImage struct { - multicloud.SImageBase - multicloud.AzureTags - storageCache *SStoragecache - - Properties ImageProperties `json:"properties,omitempty"` - ID string `json:"id,omitempty"` - Name string - Type string - Location string - - Publisher string - Offer string - Sku string - Version string - - ImageType cloudprovider.TImageType -} - -func (self *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (self *SImage) GetSysTags() map[string]string { - data := map[string]string{} - osType := string(self.Properties.StorageProfile.OsDisk.OsType) - if len(osType) > 0 { - data["os_name"] = osType - } - return data -} - -func (self *SImage) GetId() string { - return self.ID -} - -func (self *SImage) GetName() string { - return self.Name -} - -func (self *SImage) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SImage) GetStatus() string { - switch self.Properties.ProvisioningState { - case "created": - return api.CACHED_IMAGE_STATUS_CACHING - case "Succeeded": - return api.CACHED_IMAGE_STATUS_ACTIVE - default: - log.Errorf("Unknow image status: %s", self.Properties.ProvisioningState) - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (self *SImage) GetImageStatus() string { - switch self.Properties.ProvisioningState { - case "created": - return cloudprovider.IMAGE_STATUS_QUEUED - case "Succeeded": - return cloudprovider.IMAGE_STATUS_ACTIVE - default: - log.Errorf("Unknow image status: %s", self.Properties.ProvisioningState) - return cloudprovider.IMAGE_STATUS_KILLED - } -} - -func (self *SImage) Refresh() error { - image, err := self.storageCache.region.GetImageById(self.ID) - if err != nil { - return err - } - return jsonutils.Update(self, image) -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - return cloudprovider.TImageType(self.ImageType) -} - -func (self *SImage) GetSizeByte() int64 { - return int64(self.Properties.StorageProfile.OsDisk.DiskSizeGB) * 1024 * 1024 * 1024 -} - -func (i *SImage) GetFullOsName() string { - return "" -} - -func (self *SImage) GetOsType() cloudprovider.TOsType { - osType := self.Properties.StorageProfile.OsDisk.OsType - if len(osType) == 0 { - osType = publisherGetOsType(self.Publisher) - } - return cloudprovider.TOsType(osType) -} - -func (self *SImage) GetOsArch() string { - if self.GetImageType() == cloudprovider.ImageTypeCustomized { - return apis.OS_ARCH_X86_64 - } - return publisherGetOsArch(self.Publisher, self.Offer, self.Sku, self.Version) -} - -func (self *SImage) GetOsDist() string { - if self.GetImageType() == cloudprovider.ImageTypeCustomized { - return "" - } - return publisherGetOsDist(self.Publisher, self.Offer, self.Sku, self.Version) -} - -func (self *SImage) GetOsVersion() string { - return publisherGetOsVersion(self.Publisher, self.Offer, self.Sku, self.Version) -} - -func (self *SImage) GetOsLang() string { - return "" -} - -func (i *SImage) GetBios() cloudprovider.TBiosType { - if i.Properties.HyperVGeneration == "V2" { - return cloudprovider.UEFI - } else { - return cloudprovider.BIOS - } -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - if self.Properties.StorageProfile.OsDisk.DiskSizeGB > 0 { - return int(self.Properties.StorageProfile.OsDisk.DiskSizeGB) - } - return 30 -} - -func (self *SImage) GetImageFormat() string { - return "vhd" -} - -func (self *SImage) GetCreatedAt() time.Time { - return time.Time{} -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.storageCache -} - -func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) { - if image, err := self.GetImageById(imageId); err != nil { - return "", err - } else { - return image.Properties.ProvisioningState, nil - } -} - -func isPrivateImageID(imageId string) bool { - return strings.HasPrefix(strings.ToLower(imageId), "/subscriptions/") -} - -func (self *SRegion) GetImageById(imageId string) (SImage, error) { - if isPrivateImageID(imageId) { - return self.getPrivateImage(imageId) - } else { - return self.getOfferedImage(imageId) - } -} - -func (self *SRegion) getPrivateImage(imageId string) (SImage, error) { - image := SImage{} - err := self.get(imageId, url.Values{}, &image) - if err != nil { - return image, err - } - return image, nil -} - -func (self *SRegion) CreateImageByBlob(imageName, osType, blobURI string, diskSizeGB int32) (*SImage, error) { - if diskSizeGB < 1 || diskSizeGB > 4095 { - diskSizeGB = 30 - } - image := SImage{ - Name: imageName, - Location: self.Name, - Properties: ImageProperties{ - StorageProfile: ImageStorageProfile{ - OsDisk: ImageOSDisk{ - OsType: osType, - OsState: "Generalized", - BlobURI: blobURI, - DiskSizeGB: diskSizeGB, - }, - }, - }, - Type: "Microsoft.Compute/images", - } - return &image, self.create("", jsonutils.Marshal(image), &image) -} - -func (self *SRegion) CreateImage(snapshotId, imageName, osType, imageDesc string) (*SImage, error) { - image := SImage{ - Name: imageName, - Location: self.Name, - Properties: ImageProperties{ - StorageProfile: ImageStorageProfile{ - OsDisk: ImageOSDisk{ - OsType: osType, - OsState: "Generalized", - Snapshot: &SubResource{ - ID: snapshotId, - }, - }, - }, - }, - Type: "Microsoft.Compute/images", - } - return &image, self.create("", jsonutils.Marshal(image), &image) -} - -func (self *SRegion) getOfferedImages(publishersFilter []string, offersFilter []string, skusFilter []string, verFilter []string, imageType cloudprovider.TImageType, latestVer bool) ([]SImage, error) { - images := make([]SImage, 0) - idMap, err := self.GetOfferedImageIDs(publishersFilter, offersFilter, skusFilter, verFilter, latestVer) - if err != nil { - return nil, err - } - for id, _image := range idMap { - image, err := self.getOfferedImage(id) - if err == nil { - image.ImageType = imageType - image.Properties.StorageProfile.OsDisk.DiskSizeGB = int32(_image.Properties.OsDiskImage.SizeInGb) - image.Properties.StorageProfile.OsDisk.OsType = _image.Properties.OsDiskImage.OperatingSystem - image.Properties.HyperVGeneration = _image.Properties.HyperVGeneration - images = append(images, image) - } - } - return images, nil -} - -func (self *SRegion) GetOfferedImageIDs(publishersFilter []string, offersFilter []string, skusFilter []string, verFilter []string, latestVer bool) (map[string]SAzureImageResource, error) { - idMap := map[string]SAzureImageResource{} - publishers, err := self.GetImagePublishers(toLowerStringArray(publishersFilter)) - if err != nil { - return nil, err - } - for _, publisher := range publishers { - offers, err := self.getImageOffers(publisher, toLowerStringArray(offersFilter)) - if err != nil { - log.Errorf("failed to found offers for publisher %s error: %v", publisher, err) - if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, errors.Wrap(err, "getImageOffers") - } - continue - } - for _, offer := range offers { - skus, err := self.getImageSkus(publisher, offer, toLowerStringArray(skusFilter)) - if err != nil { - if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, errors.Wrap(err, "getImageSkus") - } - log.Errorf("failed to found skus for publisher %s offer %s error: %v", publisher, offer, err) - continue - } - for _, sku := range skus { - verFilter = toLowerStringArray(verFilter) - vers, err := self.getImageVersions(publisher, offer, sku, verFilter, latestVer) - if err != nil { - if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, errors.Wrap(err, "getImageVersions") - } - log.Errorf("failed to found publisher %s offer %s sku %s version error: %v", publisher, offer, sku, err) - continue - } - for _, ver := range vers { - idStr := strings.Join([]string{publisher, offer, sku, ver}, "/") - image, err := self.getImageDetail(publisher, offer, sku, ver) - if err != nil { - return nil, err - } - idMap[idStr] = image - } - } - } - } - return idMap, nil -} - -func (self *SRegion) getPrivateImages() ([]SImage, error) { - result := []SImage{} - images := []SImage{} - err := self.client.list("Microsoft.Compute/images", url.Values{}, &images) - if err != nil { - return nil, err - } - for i := 0; i < len(images); i++ { - if images[i].Location == self.Name { - images[i].ImageType = cloudprovider.ImageTypeCustomized - result = append(result, images[i]) - } - } - return result, nil -} - -func toLowerStringArray(input []string) []string { - output := make([]string, len(input)) - for i := range input { - output[i] = strings.ToLower(input[i]) - } - return output -} - -func (self *SRegion) GetImages(imageType cloudprovider.TImageType) ([]SImage, error) { - images := make([]SImage, 0) - if len(imageType) == 0 { - ret, _ := self.getPrivateImages() - if len(ret) > 0 { - images = append(images, ret...) - } - ret, _ = self.getOfferedImages(knownPublishers, nil, nil, nil, cloudprovider.ImageTypeSystem, true) - if len(ret) > 0 { - images = append(images, ret...) - } - return images, nil - } - switch imageType { - case cloudprovider.ImageTypeCustomized: - return self.getPrivateImages() - case cloudprovider.ImageTypeSystem: - return self.getOfferedImages(knownPublishers, nil, nil, nil, cloudprovider.ImageTypeSystem, true) - default: - return self.getOfferedImages(nil, nil, nil, nil, cloudprovider.ImageTypeMarket, true) - } -} - -func (self *SRegion) DeleteImage(imageId string) error { - return self.del(imageId) -} - -func (self *SImage) GetBlobUri() string { - return self.Properties.StorageProfile.OsDisk.BlobURI -} - -func (self *SImage) Delete(ctx context.Context) error { - return self.storageCache.region.DeleteImage(self.ID) -} - -type SOsDiskImage struct { - OperatingSystem string `json:"operatingSystem"` - SizeInGb int `json:"sizeInGb"` -} - -type SAzureImageResourceProperties struct { - ReplicaType string `json:"replicaType"` - OsDiskImage SOsDiskImage `json:"osDiskImage"` - HyperVGeneration string `json:"hyperVGeneration,omitempty"` -} - -type SAzureImageResource struct { - Id string - Name string - Location string - Properties SAzureImageResourceProperties -} - -func (region *SRegion) GetImagePublishers(filter []string) ([]string, error) { - publishers := make([]SAzureImageResource, 0) - // TODO - err := region.client.list(fmt.Sprintf("Microsoft.Compute/locations/%s/publishers", region.Name), url.Values{}, &publishers) - if err != nil { - return nil, err - } - ret := make([]string, 0) - for i := range publishers { - if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(publishers[i].Name), filter) { - ret = append(ret, publishers[i].Name) - } - } - return ret, nil -} - -func (region *SRegion) getImageOffers(publisher string, filter []string) ([]string, error) { - ret := make([]string, 0) - if driver, ok := publisherDrivers[strings.ToLower(publisher)]; ok { - offers := driver.GetOffers() - if len(offers) > 0 { - for _, offer := range offers { - if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(offer), filter) { - ret = append(ret, offer) - } - } - return offers, nil - } - } else { - log.Warningf("failed to get publisher %s driver", publisher) - } - offers := make([]SAzureImageResource, 0) - err := region.client.list(fmt.Sprintf("Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers", region.Name, publisher), url.Values{}, &offers) - if err != nil { - return nil, err - } - for i := range offers { - if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(offers[i].Name), filter) { - ret = append(ret, offers[i].Name) - } - } - return ret, nil -} - -func (region *SRegion) getImageSkus(publisher string, offer string, filter []string) ([]string, error) { - ret := make([]string, 0) - if driver, ok := publisherDrivers[strings.ToLower(publisher)]; ok { - skus := driver.GetSkus(offer) - if len(skus) > 0 { - for _, sku := range skus { - if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(sku), filter) { - ret = append(ret, sku) - } - } - return ret, nil - } - } - skus := make([]SAzureImageResource, 0) - err := region.client.list(fmt.Sprintf("Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers/%s/skus", region.Name, publisher, offer), url.Values{}, &skus) - if err != nil { - return nil, err - } - for i := range skus { - if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(skus[i].Name), filter) { - ret = append(ret, skus[i].Name) - } - } - return ret, nil -} - -func (region *SRegion) getImageVersions(publisher string, offer string, sku string, filter []string, latestVer bool) ([]string, error) { - vers := make([]SAzureImageResource, 0) - resource := fmt.Sprintf("Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers/%s/skus/%s/versions", region.Name, publisher, offer, sku) - params := url.Values{} - if latestVer { - params.Set("$top", "1") - params.Set("orderby", "name desc") - } - err := region.client.list(resource, params, &vers) - if err != nil { - return nil, err - } - ret := make([]string, 0) - for i := range vers { - if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(vers[i].Name), filter) { - ret = append(ret, vers[i].Name) - } - } - return ret, nil -} - -func (region *SRegion) getImageDetail(publisher string, offer string, sku string, version string) (SAzureImageResource, error) { - image := SAzureImageResource{} - id := "/Subscriptions/" + region.client.subscriptionId + - "/Providers/Microsoft.Compute/locations/" + region.Name + - "/publishers/" + publisher + - "/artifacttypes/vmimage/offers/" + offer + - "/skus/" + sku + - "/versions/" + version - return image, region.get(id, url.Values{}, &image) -} - -func (region *SRegion) getOfferedImage(offerId string) (SImage, error) { - image := SImage{} - - parts := strings.Split(offerId, "/") - if len(parts) < 4 { - return image, fmt.Errorf("invalid image ID %s", offerId) - } - publisher := parts[0] - offer := parts[1] - sku := parts[2] - version := parts[3] - for _publish := range publisherDrivers { - if strings.ToLower(_publish) == publisher { - publisher = _publish - break - } - } - image.ID = offerId - image.Location = region.Name - image.Type = "Microsoft.Compute/vmimage" - image.Name = publisherGetName(publisher, offer, sku, version) - image.Publisher = publisher - image.Offer = offer - image.Sku = sku - image.Version = version - image.Properties.ProvisioningState = ImageStatusAvailable - _image, err := region.getImageDetail(publisher, offer, sku, version) - if err == nil { - image.Properties.StorageProfile.OsDisk.DiskSizeGB = int32(_image.Properties.OsDiskImage.SizeInGb) - image.Properties.StorageProfile.OsDisk.OperatingSystem = _image.Properties.OsDiskImage.OperatingSystem - image.Properties.HyperVGeneration = _image.Properties.HyperVGeneration - } - return image, nil -} - -func (region *SRegion) getOfferedImageId(image *SImage) (string, error) { - if isPrivateImageID(image.ID) { - return image.ID, nil - } - _image, err := region.getImageDetail(image.Publisher, image.Offer, image.Sku, image.Version) - if err != nil { - log.Errorf("failed to get offered image ID from %s error: %v", jsonutils.Marshal(image).PrettyString(), err) - return "", err - } - return _image.Id, nil -} - -func (image *SImage) getImageReference() ImageReference { - if isPrivateImageID(image.ID) { - return ImageReference{ - ID: image.ID, - } - } else { - return ImageReference{ - Sku: image.Sku, - Publisher: image.Publisher, - Version: image.Version, - Offer: image.Offer, - } - } -} diff --git a/pkg/multicloud/azure/instance.go b/pkg/multicloud/azure/instance.go deleted file mode 100644 index 27c0348e20..0000000000 --- a/pkg/multicloud/azure/instance.go +++ /dev/null @@ -1,1122 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "context" - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - - "yunion.io/x/onecloud/pkg/apis" - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/version" -) - -const ( - DEFAULT_EXTENSION_NAME = "enablevmaccess" -) - -type HardwareProfile struct { - VMSize string `json:"vmSize,omitempty"` -} - -type ImageReference struct { - Publisher string `json:"publisher,omitempty"` - Offer string `json:"offer,omitempty"` - Sku string `json:"sku,omitempty"` - Version string `json:"version,omitempty"` - ID string `json:"id,omitempty"` -} - -type VirtualHardDisk struct { - Uri string `json:"uri,omitempty"` -} - -type ManagedDiskParameters struct { - StorageAccountType string `json:"storageAccountType,omitempty"` - ID string -} - -type StorageProfile struct { - ImageReference ImageReference `json:"imageReference,omitempty"` - OsDisk SOsDisk `json:"osDisk,omitempty"` - DataDisks []SDataDisk `json:"dataDisks,allowempty"` -} - -type SSHPublicKey struct { - Path string `json:"path,omitempty"` - KeyData string `json:"keyData,omitempty"` -} - -type SSHConfiguration struct { - PublicKeys []SSHPublicKey `json:"publicKeys,omitempty"` -} - -type LinuxConfiguration struct { - DisablePasswordAuthentication bool `json:"disablePasswordAuthentication,omitempty"` - SSH *SSHConfiguration `json:"ssh,omitempty"` -} - -type VaultCertificate struct { - CertificateURL string `json:"certificateURL,omitempty"` - CertificateStore string `json:"certificateStore,omitempty"` -} - -type VaultSecretGroup struct { - SourceVault SubResource `json:"sourceVault,omitempty"` - VaultCertificates []VaultCertificate `json:"vaultCertificates,omitempty"` -} - -type OsProfile struct { - ComputerName string `json:"computerName,omitempty"` - AdminUsername string `json:"adminUsername,omitempty"` - AdminPassword string `json:"adminPassword,omitempty"` - CustomData string `json:"customData,omitempty"` - LinuxConfiguration *LinuxConfiguration `json:"linuxConfiguration,omitempty"` - Secrets []VaultSecretGroup `json:"secrets,omitempty"` -} - -type NetworkInterfaceReference struct { - ID string -} - -type NetworkProfile struct { - NetworkInterfaces []NetworkInterfaceReference `json:"networkInterfaces,omitempty"` -} - -type Statuses struct { - Code string - Level string - DisplayStatus string `json:"displayStatus,omitempty"` - Message string - //Time time.Time -} - -type SVMAgent struct { - VmAgentVersion string `json:"vmAgentVersion,omitempty"` - Statuses []Statuses `json:"statuses,omitempty"` -} - -type SExtension struct { - Name string - Type string - TypeHandlerVersion string `json:"typeHandlerVersion,omitempty"` - Statuses []Statuses `json:"statuses,omitempty"` -} - -type VirtualMachineInstanceView struct { - Statuses []Statuses `json:"statuses,omitempty"` - VMAgent SVMAgent `json:"vmAgent,omitempty"` - Extensions []SExtension `json:"extensions,omitempty"` -} - -type DomainName struct { - Id string - Name string - Type string -} - -type DebugProfile struct { - BootDiagnosticsEnabled *bool `json:"bootDiagnosticsEnabled,omitempty"` - ConsoleScreenshotBlobUri string `json:"consoleScreenshotBlobUri,omitempty"` - SerialOutputBlobUri string `json:"serialOutputBlobUri,omitempty"` -} - -type VirtualMachineProperties struct { - ProvisioningState string `json:"provisioningState,omitempty"` - InstanceView *VirtualMachineInstanceView `json:"instanceView,omitempty"` - DomainName *DomainName `json:"domainName,omitempty"` - HardwareProfile HardwareProfile `json:"hardwareProfile,omitempty"` - NetworkProfile NetworkProfile `json:"networkProfile,omitempty"` - StorageProfile StorageProfile `json:"storageProfile,omitempty"` - DebugProfile *DebugProfile `json:"debugProfile,omitempty"` - OsProfile OsProfile `json:"osProfile,omitempty"` - VmId string `json:"vmId,omitempty"` - TimeCreated time.Time `json:"timeCreated,omitempty"` -} - -type SExtensionResourceProperties struct { - AutoUpgradeMinorVersion bool - ProvisioningState string - Publisher string - Type string - TypeHandlerVersion string -} - -type SExtensionResource struct { - Id string - Name string - Type string - Location string - - Properties SExtensionResourceProperties -} - -type SInstance struct { - multicloud.SInstanceBase - multicloud.AzureTags - host *SHost - - Properties VirtualMachineProperties - ID string - Name string - Type string - Location string - vmSize *SVMSize - - Resources []SExtensionResource -} - -func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) { - instance := SInstance{} - params := url.Values{} - params.Set("$expand", "instanceView") - return &instance, self.get(instanceId, params, &instance) -} - -func (self *SRegion) GetInstanceScaleSets() ([]SInstance, error) { - instance := []SInstance{} - return instance, self.client.list("Microsoft.Compute/virtualMachineScaleSets", url.Values{}, &instance) -} - -func (self *SRegion) GetInstances() ([]SInstance, error) { - result := []SInstance{} - resource := fmt.Sprintf("Microsoft.Compute/locations/%s/virtualMachines", self.Name) - err := self.client.list(resource, url.Values{}, &result) - if err != nil { - return nil, err - } - return result, nil -} - -func (self *SRegion) doDeleteVM(instanceId string) error { - return self.del(instanceId) -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - secgroupIds := []string{} - if nics, err := self.getNics(); err == nil { - for _, nic := range nics { - if len(nic.Properties.NetworkSecurityGroup.ID) > 0 { - secgroupIds = append(secgroupIds, strings.ToLower(nic.Properties.NetworkSecurityGroup.ID)) - } - } - } - return secgroupIds, nil -} - -func (self *SInstance) GetSysTags() map[string]string { - data := map[string]string{} - if osDistribution := self.Properties.StorageProfile.ImageReference.Publisher; len(osDistribution) > 0 { - data["os_distribution"] = osDistribution - } - if loginAccount := self.Properties.OsProfile.AdminUsername; len(loginAccount) > 0 { - data["login_account"] = loginAccount - } - if loginKey := self.Properties.OsProfile.AdminPassword; len(loginKey) > 0 { - data["login_key"] = loginKey - } - for _, res := range self.Resources { - if strings.HasSuffix(strings.ToLower(res.Id), "databricksbootstrap") { - data[apis.IS_SYSTEM] = "true" - break - } - } - return data -} - -func (self *SInstance) GetTags() (map[string]string, error) { - return self.Tags, nil -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_AZURE -} - -func (self *SInstance) GetInstanceType() string { - return self.Properties.HardwareProfile.VMSize -} - -func (self *SInstance) WaitVMAgentReady() error { - status := "" - err := cloudprovider.Wait(time.Second*5, time.Minute*5, func() (bool, error) { - if self.Properties.InstanceView == nil { - self.Refresh() - return false, nil - } - - for _, vmAgent := range self.Properties.InstanceView.VMAgent.Statuses { - status = vmAgent.DisplayStatus - if status == "Ready" { - break - } - log.Debugf("vmAgent %s status: %s waite for ready", self.Properties.InstanceView.VMAgent.VmAgentVersion, vmAgent.DisplayStatus) - } - if status == "Ready" { - return true, nil - } - return false, self.Refresh() - }) - if err != nil { - return errors.Wrapf(err, "waitting vmAgent ready, current status: %s", status) - } - return nil - -} - -func (self *SInstance) WaitEnableVMAccessReady() error { - if self.Properties.InstanceView == nil { - return fmt.Errorf("instance may not install VMAgent or VMAgent not running") - } - if len(self.Properties.InstanceView.VMAgent.VmAgentVersion) > 0 { - return self.WaitVMAgentReady() - } - - for _, extension := range self.Properties.InstanceView.Extensions { - if extension.Name == "enablevmaccess" { - displayStatus := "" - for _, status := range extension.Statuses { - displayStatus = status.DisplayStatus - if displayStatus == "Provisioning succeeded" { - return nil - } - } - return self.host.zone.region.deleteExtension(self.ID, "enablevmaccess") - } - } - - return fmt.Errorf("instance may not install VMAgent or VMAgent not running") -} - -func (self *SInstance) getNics() ([]SInstanceNic, error) { - nics := []SInstanceNic{} - for _, _nic := range self.Properties.NetworkProfile.NetworkInterfaces { - nic, err := self.host.zone.region.GetNetworkInterface(_nic.ID) - if err != nil { - return nil, errors.Wrapf(err, "GetNetworkInterface(%s)", _nic.ID) - } - nic.instance = self - nics = append(nics, *nic) - } - return nics, nil -} - -func (self *SInstance) Refresh() error { - instance, err := self.host.zone.region.GetInstance(self.ID) - if err != nil { - return err - } - err = jsonutils.Update(self, instance) - if err != nil { - return err - } - self.Tags = instance.Tags - return nil -} - -func (self *SInstance) GetStatus() string { - if self.Properties.InstanceView == nil { - err := self.Refresh() - if err != nil { - log.Errorf("failed to get status for instance %s", self.Name) - return api.VM_UNKNOWN - } - } - for _, statuses := range self.Properties.InstanceView.Statuses { - if code := strings.Split(statuses.Code, "/"); len(code) == 2 { - if code[0] == "PowerState" { - switch code[1] { - case "stopped", "deallocated": - return api.VM_READY - case "running": - return api.VM_RUNNING - case "stopping": - return api.VM_STOPPING - case "starting": - return api.VM_STARTING - case "deleting": - return api.VM_DELETING - default: - log.Errorf("Unknow instance status %s", code[1]) - return api.VM_UNKNOWN - } - } - } - if statuses.Level == "Error" { - log.Errorf("Find error code: [%s] message: %s", statuses.Code, statuses.Message) - } - } - return api.VM_UNKNOWN -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return self.host.zone.region.AttachDisk(self.ID, diskId) -} - -func (region *SRegion) AttachDisk(instanceId, diskId string) error { - instance, err := region.GetInstance(instanceId) - if err != nil { - return errors.Wrapf(err, "GetInstance(%s)", instanceId) - } - lunMaps := map[int32]bool{} - dataDisks := jsonutils.NewArray() - for _, disk := range instance.Properties.StorageProfile.DataDisks { - if disk.ManagedDisk != nil && strings.ToLower(disk.ManagedDisk.ID) == strings.ToLower(diskId) { - return nil - } - lunMaps[disk.Lun] = true - dataDisks.Add(jsonutils.Marshal(disk)) - } - lun := func() int32 { - idx := int32(0) - for { - if _, ok := lunMaps[idx]; !ok { - return idx - } - idx++ - } - }() - dataDisks.Add(jsonutils.Marshal(map[string]interface{}{ - "Lun": lun, - "CreateOption": "Attach", - "ManagedDisk": map[string]string{ - "Id": diskId, - }, - })) - params := jsonutils.NewDict() - params.Add(dataDisks, "Properties", "StorageProfile", "DataDisks") - params.Add(jsonutils.Marshal(instance.Properties.StorageProfile.OsDisk), "Properties", "StorageProfile", "OsDisk") - _, err = region.patch(instanceId, params) - return err -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return self.host.zone.region.DetachDisk(self.ID, diskId) -} - -func (region *SRegion) DetachDisk(instanceId, diskId string) error { - instance, err := region.GetInstance(instanceId) - if err != nil { - return errors.Wrapf(err, "GetInstance(%s)", instanceId) - } - diskMaps := map[string]bool{} - dataDisks := jsonutils.NewArray() - for _, disk := range instance.Properties.StorageProfile.DataDisks { - if disk.ManagedDisk != nil { - diskMaps[strings.ToLower(disk.ManagedDisk.ID)] = true - if strings.ToLower(disk.ManagedDisk.ID) == strings.ToLower(diskId) { - continue - } - } - dataDisks.Add(jsonutils.Marshal(disk)) - } - if _, ok := diskMaps[strings.ToLower(diskId)]; !ok { - log.Warningf("not find disk %s with instance %s", diskId, instance.Name) - return nil - } - params := jsonutils.NewDict() - params.Add(dataDisks, "Properties", "StorageProfile", "DataDisks") - params.Add(jsonutils.Marshal(instance.Properties.StorageProfile.OsDisk), "Properties", "StorageProfile", "OsDisk") - _, err = region.patch(instanceId, params) - return err -} - -func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - if len(config.InstanceType) > 0 { - return self.host.zone.region.ChangeConfig(self.ID, config.InstanceType) - } - var err error - for _, vmSize := range self.host.zone.region.getHardwareProfile(config.Cpu, config.MemoryMB) { - log.Debugf("Try HardwareProfile : %s", vmSize) - err = self.host.zone.region.ChangeConfig(self.ID, vmSize) - if err == nil { - return nil - } - } - if err != nil { - return errors.Wrap(err, "ChangeConfig") - } - return fmt.Errorf("Failed to change vm config, specification not supported") -} - -func (self *SRegion) ChangeConfig(instanceId, instanceType string) error { - params := map[string]interface{}{ - "Properties": map[string]interface{}{ - "HardwareProfile": map[string]string{ - "vmSize": instanceType, - }, - }, - } - log.Debugf("Try HardwareProfile : %s", instanceType) - _, err := self.patch(instanceId, jsonutils.Marshal(params)) - return err -} - -func (region *SRegion) ChangeVMConfig(ctx context.Context, instanceId string, ncpu int, vmem int) error { - instacen, err := region.GetInstance(instanceId) - if err != nil { - return err - } - return instacen.ChangeConfig(ctx, &cloudprovider.SManagedVMChangeConfig{Cpu: ncpu, MemoryMB: vmem}) -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - if len(publicKey) > 0 || len(password) > 0 { - // 先判断系统是否安装了vmAgent,然后等待扩展准备完成后再重置密码 - err := self.WaitEnableVMAccessReady() - if err != nil { - return err - } - } - return self.host.zone.region.DeployVM(ctx, self.ID, string(self.GetOsType()), name, password, publicKey, deleteKeypair, description) -} - -type VirtualMachineExtensionProperties struct { - Publisher string `json:"publisher,omitempty"` - Type string `json:"type,omitempty"` - TypeHandlerVersion string `json:"typeHandlerVersion,omitempty"` - ProtectedSettings interface{} `json:"protectedSettings,omitempty"` - Settings interface{} `json:"settings,omitempty"` -} - -type SVirtualMachineExtension struct { - Location string `json:"location,omitempty"` - Properties VirtualMachineExtensionProperties `json:"properties,omitempty"` -} - -func (region *SRegion) execOnLinux(instanceId string, command string) error { - extension := SVirtualMachineExtension{ - Location: region.Name, - Properties: VirtualMachineExtensionProperties{ - Publisher: "Microsoft.Azure.Extensions", - Type: "CustomScript", - TypeHandlerVersion: "2.0", - Settings: map[string]string{"commandToExecute": command}, - }, - } - resource := fmt.Sprintf("%s/extensions/CustomScript", instanceId) - _, err := region.put(resource, jsonutils.Marshal(extension)) - return err -} - -func (region *SRegion) resetOvsEnv(instanceId string) error { - ovsEnv, err := region.getOvsEnv(instanceId) - if err != nil { - return err - } - err = region.execOnLinux(instanceId, fmt.Sprintf(`echo '%s' > /var/lib/waagent/ovf-env.xml`, ovsEnv)) - if err != nil { - return err - } - return region.execOnLinux(instanceId, "systemctl restart wagent") -} - -func (region *SRegion) deleteExtension(instanceId, extensionName string) error { - return region.del(fmt.Sprintf("%s/extensions/%s", instanceId, extensionName)) -} -func (region *SRegion) resetLoginInfo(osType, instanceId string, setting map[string]interface{}) error { - // https://github.com/Azure/azure-linux-extensions/blob/master/VMAccess/README.md - handlerVersion := "1.5" - properties := map[string]interface{}{ - "Publisher": "Microsoft.OSTCExtensions", - "Type": "VMAccessForLinux", - "TypeHandlerVersion": handlerVersion, - "Settings": map[string]string{}, - "protectedSettings": setting, - - "autoUpgradeMinorVersion": true, - } - if osType == osprofile.OS_TYPE_WINDOWS { - // https://github.com/Azure/azure-cli/blob/dev/src/azure-cli/azure/cli/command_modules/vm/custom.py - handlerVersion = "2.4" - properties["TypeHandlerVersion"] = handlerVersion - properties["Publisher"] = "Microsoft.Compute" - properties["Type"] = "VMAccessAgent" - } - params := map[string]interface{}{ - "Location": region.Name, - "Properties": properties, - } - instance, err := region.GetInstance(instanceId) - if err != nil { - return errors.Wrapf(err, "GetInstance(%s)", instanceId) - } - for _, extension := range instance.Resources { - if extension.Name == "enablevmaccess" { - if version.GT(extension.Properties.TypeHandlerVersion, handlerVersion) { - properties["TypeHandlerVersion"] = extension.Properties.TypeHandlerVersion - break - } - } - } - resource := fmt.Sprintf("%s/extensions/enablevmaccess", instanceId) - _, err = region.put(resource, jsonutils.Marshal(params)) - if err != nil { - switch osType { - case osprofile.OS_TYPE_WINDOWS: - return err - default: - err = region.deleteExtension(instanceId, "enablevmaccess") - if err != nil { - return err - } - err = region.resetOvsEnv(instanceId) - if err != nil { - return err - } - resource := fmt.Sprintf("%s/extensions/enablevmaccess", instanceId) - _, err = region.put(resource, jsonutils.Marshal(params)) - return err - } - } - err = cloudprovider.Wait(time.Second*5, time.Minute*5, func() (bool, error) { - instance, err := region.GetInstance(instanceId) - if err != nil { - return false, errors.Wrapf(err, "GetInstance(%s)", instanceId) - } - for _, extension := range instance.Resources { - if extension.Name == "enablevmaccess" { - if extension.Properties.ProvisioningState == "Succeeded" { - return true, nil - } - log.Debugf("enablevmaccess status %s expect Succeeded", extension.Properties.ProvisioningState) - if extension.Properties.ProvisioningState == "Failed" { - if instance.Properties.InstanceView != nil { - for _, info := range instance.Properties.InstanceView.Extensions { - if info.Name == "enablevmaccess" && len(info.Statuses) > 0 { - return false, fmt.Errorf("details: %s", jsonutils.Marshal(info.Statuses)) - } - } - } - return false, fmt.Errorf("reset passwod failed") - } - } - } - return false, nil - }) - if err != nil { - return errors.Wrapf(err, "wait for enablevmaccess error: %v", err) - } - return nil -} - -func (region *SRegion) resetPublicKey(osType, instanceId string, username, publicKey string) error { - setting := map[string]interface{}{ - "username": username, - "ssh_key": publicKey, - } - return region.resetLoginInfo(osType, instanceId, setting) -} - -func (region *SRegion) resetPassword(osType, instanceId, username, password string) error { - setting := map[string]interface{}{ - "username": username, - "password": password, - } - return region.resetLoginInfo(osType, instanceId, setting) -} - -func (region *SRegion) DeployVM(ctx context.Context, instanceId, osType, name, password, publicKey string, deleteKeypair bool, description string) error { - instance, err := region.GetInstance(instanceId) - if err != nil { - return err - } - if deleteKeypair { - return nil - } - if len(publicKey) > 0 { - return region.resetPublicKey(osType, instanceId, instance.Properties.OsProfile.AdminUsername, publicKey) - } - if len(password) > 0 { - return region.resetPassword(osType, instanceId, instance.Properties.OsProfile.AdminUsername, password) - } - return nil -} - -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - cpu := self.GetVcpuCount() - memoryMb := self.GetVmemSizeMB() - opts := &cloudprovider.ServerStopOptions{ - IsForce: true, - } - self.StopVM(ctx, opts) - return self.host.zone.region.ReplaceSystemDisk(self, cpu, memoryMb, desc.ImageId, desc.Password, desc.PublicKey, desc.SysSizeGB) -} - -func (region *SRegion) ReplaceSystemDisk(instance *SInstance, cpu int, memoryMb int, imageId, passwd, publicKey string, sysSizeGB int) (string, error) { - log.Debugf("ReplaceSystemDisk %s image: %s", instance.ID, imageId) - storageType := instance.Properties.StorageProfile.OsDisk.ManagedDisk.StorageAccountType - if len(storageType) == 0 { - _disk, err := region.GetDisk(instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID) - if err != nil { - return "", err - } - storageType = _disk.Sku.Name - } - image, err := region.GetImageById(imageId) - if err != nil { - return "", errors.Wrapf(err, "GetImageById(%s)", imageId) - } - if minOsDiskSizeGB := image.GetMinOsDiskSizeGb(); minOsDiskSizeGB > sysSizeGB { - sysSizeGB = minOsDiskSizeGB - } - osType := instance.Properties.StorageProfile.OsDisk.OsType - // https://support.microsoft.com/zh-cn/help/4018933/the-default-size-of-windows-server-images-in-azure-is-changed-from-128 - // windows默认系统盘是128G, 若重装系统时,系统盘小于128G,则会出现 {"error":{"code":"ResizeDiskError","message":"Disk size reduction is not supported. Current size is 137438953472 bytes, requested size is 33285996544 bytes.","target":"osDisk.diskSizeGB"}} 错误 - if osType == osprofile.OS_TYPE_WINDOWS && sysSizeGB < 128 { - sysSizeGB = 128 - } - nicId := instance.Properties.NetworkProfile.NetworkInterfaces[0].ID - nic, err := region.GetNetworkInterface(nicId) - if err != nil { - return "", errors.Wrapf(err, "GetNetworkInterface(%s)", nicId) - } - if len(nic.Properties.IPConfigurations) == 0 { - return "", fmt.Errorf("failed to find networkId for nic %s", nicId) - } - networkId := nic.Properties.IPConfigurations[0].Properties.Subnet.ID - - nic, err = region.CreateNetworkInterface("", fmt.Sprintf("%s-temp-ifconfig", instance.Name), "", networkId, "") - if err != nil { - return "", errors.Wrapf(err, "CreateNetworkInterface") - } - - newInstance, err := region.CreateInstanceSimple(instance.Name+"-rebuild", imageId, osType, cpu, memoryMb, sysSizeGB, storageType, []int{}, nic.ID, passwd, publicKey) - newInstance.host = instance.host - cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) { - err = newInstance.WaitVMAgentReady() - if err != nil { - log.Warningf("WaitVMAgentReady for %s error: %v", newInstance.Name, err) - return false, nil - } - return true, nil - }) - - opts := &cloudprovider.ServerStopOptions{ - IsForce: true, - } - newInstance.StopVM(context.Background(), opts) - - pruneDiskId := instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID - newDiskId := newInstance.Properties.StorageProfile.OsDisk.ManagedDisk.ID - - err = newInstance.deleteVM(context.TODO(), true) - if err != nil { - log.Warningf("delete vm %s error: %v", newInstance.ID, err) - } - - defer func() { - if len(pruneDiskId) > 0 { - err := cloudprovider.Wait(time.Second*3, time.Minute, func() (bool, error) { - err = region.DeleteDisk(pruneDiskId) - if err != nil { - log.Errorf("delete prune disk %s error: %v", pruneDiskId, err) - return false, nil - } - return true, nil - }) - if err != nil { - log.Errorf("timeout for delete prune disk %s", pruneDiskId) - } - } - }() - - //交换系统盘 - params := map[string]interface{}{ - "Id": instance.ID, - "Location": instance.Location, - "Properties": map[string]interface{}{ - "StorageProfile": map[string]interface{}{ - "OsDisk": map[string]interface{}{ - "createOption": "FromImage", - "ManagedDisk": map[string]interface{}{ - "Id": newDiskId, - "storageAccountType": nil, - }, - "osType": osType, - "DiskSizeGB": nil, - }, - }, - }, - } - err = region.update(jsonutils.Marshal(params), nil) - if err != nil { - // 更新失败,需要删除新建的系统盘 - pruneDiskId = newDiskId - return "", errors.Wrapf(err, "region.update") - } - return strings.ToLower(newDiskId), nil -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetId() string { - return self.ID -} - -func (self *SInstance) GetName() string { - return self.Name -} - -func (self *SInstance) GetHostname() string { - return self.Name -} - -func (self *SInstance) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SRegion) DeleteVM(instanceId string) error { - return self.doDeleteVM(instanceId) -} - -func (self *SInstance) deleteVM(ctx context.Context, keepSysDisk bool) error { - sysDiskId := "" - if self.Properties.StorageProfile.OsDisk.ManagedDisk != nil { - sysDiskId = self.Properties.StorageProfile.OsDisk.ManagedDisk.ID - } - err := self.host.zone.region.DeleteVM(self.ID) - if err != nil { - return err - } - if len(sysDiskId) > 0 && !keepSysDisk { - err := self.host.zone.region.DeleteDisk(sysDiskId) - if err != nil { - return err - } - } - - nics, err := self.getNics() - if err != nil { - return err - } - for _, nic := range nics { - if err := nic.Delete(); err != nil { - if err != cloudprovider.ErrNotFound { - return err - } - } - } - return nil -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - return self.deleteVM(ctx, false) -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks := []cloudprovider.ICloudDisk{} - self.Properties.StorageProfile.OsDisk.region = self.host.zone.region - disks = append(disks, &self.Properties.StorageProfile.OsDisk) - for i := range self.Properties.StorageProfile.DataDisks { - self.Properties.StorageProfile.DataDisks[i].region = self.host.zone.region - disks = append(disks, &self.Properties.StorageProfile.DataDisks[i]) - } - return disks, nil -} - -func (self *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(osprofile.NormalizeOSType(string(self.Properties.StorageProfile.OsDisk.OsType))) -} - -func (self *SInstance) GetFullOsName() string { - return self.Properties.StorageProfile.ImageReference.Offer -} - -func (self *SInstance) GetBios() cloudprovider.TBiosType { - return "BIOS" -} - -func (i *SInstance) GetOsDist() string { - return "" -} - -func (i *SInstance) GetOsVersion() string { - return "" -} - -func (i *SInstance) GetOsLang() string { - return "" -} - -func (i *SInstance) GetOsArch() string { - return apis.OS_ARCH_X86_64 -} - -func (self *SRegion) getOvsEnv(instanceId string) (string, error) { - instance, err := self.GetInstance(instanceId) - if err != nil { - return "", err - } - kms := map[string]string{ - "AzureGermanCloud": "kms.core.cloudapi.de", - "AzureChinaCloud": "kms.core.chinacloudapi.cn", - "AzureUSGovernmentCloud": "kms.core.usgovcloudapi.net", - "AzurePublicCloud": "kms.core.windows.net", - } - kmsServer := "kms.core.chinacloudapi.cn" - if _kmsServer, ok := kms[self.client.envName]; ok { - kmsServer = _kmsServer - } - return fmt.Sprintf(` - - - 1.0 - - LinuxProvisioningConfiguration - %s - false - %s - REDACTED - - - - 1.0 - - %s - true - - true - true - false - false - - - `, instance.Properties.OsProfile.AdminUsername, instance.Properties.OsProfile.ComputerName, kmsServer), nil -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nics := make([]cloudprovider.ICloudNic, 0) - _nics, err := self.getNics() - if err != nil { - return nil, err - } - for i := 0; i < len(_nics); i++ { - _nics[i].instance = self - nics = append(nics, &_nics[i]) - } - return nics, nil -} - -func (self *SInstance) GetMachine() string { - return "pc" -} - -func (self *SInstance) GetBootOrder() string { - return "dcn" -} - -func (self *SInstance) GetVga() string { - return "std" -} - -func (self *SInstance) GetVdi() string { - return "vnc" -} - -func (self *SInstance) fetchVMSize() error { - if self.vmSize == nil { - vmSize, err := self.host.zone.region.getVMSize(self.Properties.HardwareProfile.VMSize) - if err != nil { - return err - } - self.vmSize = vmSize - } - return nil -} - -func (self *SInstance) GetVcpuCount() int { - err := self.fetchVMSize() - if err != nil { - log.Errorf("fetchVMSize error: %v", err) - return 0 - } - return self.vmSize.NumberOfCores -} - -func (self *SInstance) GetVmemSizeMB() int { - err := self.fetchVMSize() - if err != nil { - log.Errorf("fetchVMSize error: %v", err) - return 0 - } - return int(self.vmSize.MemoryInMB) -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) StartVM(instanceId string) error { - _, err := self.perform(instanceId, "start", nil) - return err -} - -func (self *SInstance) StartVM(ctx context.Context) error { - if err := self.host.zone.region.StartVM(self.ID); err != nil { - return err - } - self.host.zone.region.patch(self.ID, jsonutils.Marshal(self)) - return cloudprovider.WaitStatus(self, api.VM_RUNNING, 10*time.Second, 300*time.Second) -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - err := self.host.zone.region.StopVM(self.ID, opts.IsForce) - if err != nil { - return err - } - self.host.zone.region.patch(self.ID, jsonutils.Marshal(self)) - return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) -} - -func (self *SRegion) StopVM(instanceId string, isForce bool) error { - _, err := self.perform(instanceId, "deallocate", nil) - return err -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - nics, err := self.getNics() - if err != nil { - return nil, err - } - for _, nic := range nics { - for _, ip := range nic.Properties.IPConfigurations { - if ip.Properties.PublicIPAddress != nil && len(ip.Properties.PublicIPAddress.ID) > 0 { - eip, err := self.host.zone.region.GetEip(ip.Properties.PublicIPAddress.ID) - if err != nil { - return nil, errors.Wrapf(err, "GetEip(%s)", ip.Properties.PublicIPAddress.ID) - } - if len(eip.Properties.IPAddress) > 0 { - return eip, nil - } - } - } - } - return nil, nil -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - return self.host.zone.region.SetSecurityGroup(self.ID, secgroupId) -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - if len(secgroupIds) == 1 { - return self.host.zone.region.SetSecurityGroup(self.ID, secgroupIds[0]) - } - return fmt.Errorf("Unexpect segroup count %d", len(secgroupIds)) -} - -func (self *SInstance) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SInstance) GetCreatedAt() time.Time { - return self.Properties.TimeCreated -} - -func (self *SInstance) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetProjectId() string { - return getResourceGroup(self.ID) -} - -func (self *SInstance) GetError() error { - if self.Properties.InstanceView != nil { - for _, status := range self.Properties.InstanceView.Statuses { - if status.Code == "ProvisioningState/failed/AllocationFailed" { - return errors.Errorf("%s %s", status.Code, status.Message) - } - } - } - return nil -} - -func (self *SRegion) SaveImage(osType, diskId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { - params := map[string]interface{}{ - "Location": self.Name, - "Name": opts.Name, - "Properties": map[string]interface{}{ - "storageProfile": map[string]interface{}{ - "osDisk": map[string]interface{}{ - "osType": osType, - "managedDisk": map[string]string{ - "id": diskId, - }, - "osState": "Generalized", - }, - }, - }, - "Type": "Microsoft.Compute/images", - } - image := &SImage{storageCache: self.getStoragecache()} - err := self.create("", jsonutils.Marshal(params), image) - if err != nil { - return nil, errors.Wrapf(err, "create image") - } - return image, nil -} - -func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { - if self.Properties.StorageProfile.OsDisk.ManagedDisk == nil { - return nil, fmt.Errorf("invalid os disk for save image") - } - image, err := self.host.zone.region.SaveImage(string(self.GetOsType()), self.Properties.StorageProfile.OsDisk.ManagedDisk.ID, opts) - if err != nil { - return nil, errors.Wrapf(err, "SaveImage") - } - return image, nil -} - -func (self *SInstance) SetTags(tags map[string]string, replace bool) error { - if !replace { - for k, v := range self.Tags { - if _, ok := tags[k]; !ok { - tags[k] = v - } - } - } - _, err := self.host.zone.region.client.SetTags(self.ID, tags) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.client.SetTags(%s,%s)", self.ID, jsonutils.Marshal(tags).String()) - } - return nil -} diff --git a/pkg/multicloud/azure/instancenic.go b/pkg/multicloud/azure/instancenic.go deleted file mode 100644 index d54cc36540..0000000000 --- a/pkg/multicloud/azure/instancenic.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type PublicIPAddress struct { - ID string - Name string - Location string - Properties PublicIPAddressPropertiesFormat -} - -type InterfaceIPConfigurationPropertiesFormat struct { - PrivateIPAddress string `json:"privateIPAddress,omitempty"` - PrivateIPAddressVersion string `json:"privateIPAddressVersion,omitempty"` - PrivateIPAllocationMethod string `json:"privateIPAllocationMethod,omitempty"` - Subnet SNetwork `json:"subnet,omitempty"` - Primary bool `json:"primary,omitempty"` - PublicIPAddress *PublicIPAddress `json:"publicIPAddress,omitempty"` -} - -type InterfaceIPConfiguration struct { - Properties InterfaceIPConfigurationPropertiesFormat `json:"properties,omitempty"` - Name string - ID string -} - -type InterfacePropertiesFormat struct { - NetworkSecurityGroup SSecurityGroup `json:"networkSecurityGroup,omitempty"` - IPConfigurations []InterfaceIPConfiguration `json:"ipConfigurations,omitempty"` - MacAddress string `json:"macAddress,omitempty"` - Primary bool `json:"primary,omitempty"` - VirtualMachine SubResource `json:"virtualMachine,omitempty"` -} - -type SInstanceNic struct { - multicloud.SResourceBase - multicloud.AzureTags - - instance *SInstance - ID string - Name string - Type string - Location string - Properties InterfacePropertiesFormat `json:"properties,omitempty"` - - cloudprovider.DummyICloudNic -} - -func (self *SInstanceNic) GetIP() string { - if len(self.Properties.IPConfigurations) > 0 { - return self.Properties.IPConfigurations[0].Properties.PrivateIPAddress - } - return "" -} - -func (region *SRegion) DeleteNetworkInterface(interfaceId string) error { - return region.del(interfaceId) -} - -func (self *SInstanceNic) Delete() error { - return self.instance.host.zone.region.DeleteNetworkInterface(self.ID) -} - -func (self *SInstanceNic) GetMAC() string { - mac := self.Properties.MacAddress - return strings.Replace(strings.ToLower(mac), "-", ":", -1) -} - -func (self *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (self *SInstanceNic) updateSecurityGroup(secgroupId string) error { - region := self.instance.host.zone.region - if len(secgroupId) > 0 { - self.Properties.NetworkSecurityGroup = SSecurityGroup{ID: secgroupId} - } - return region.update(jsonutils.Marshal(self), nil) -} - -func (self *SInstanceNic) revokeSecurityGroup() error { - return self.updateSecurityGroup("") -} - -func (self *SInstanceNic) assignSecurityGroup(secgroupId string) error { - return self.updateSecurityGroup(secgroupId) -} - -func (self *SInstanceNic) GetINetworkId() string { - if len(self.Properties.IPConfigurations) > 0 { - return strings.ToLower(self.Properties.IPConfigurations[0].Properties.Subnet.ID) - } - return "" -} - -func (self *SRegion) GetNetworkInterface(interfaceId string) (*SInstanceNic, error) { - instancenic := SInstanceNic{} - return &instancenic, self.get(interfaceId, url.Values{}, &instancenic) -} - -func (self *SRegion) GetNetworkInterfaces() ([]SInstanceNic, error) { - interfaces := []SInstanceNic{} - err := self.list("Microsoft.Network/networkInterfaces", url.Values{}, &interfaces) - if err != nil { - return nil, err - } - return interfaces, nil -} - -func (self *SRegion) CreateNetworkInterface(resourceGroup string, nicName string, ipAddr string, subnetId string, secgrpId string) (*SInstanceNic, error) { - allocMethod := "Static" - if len(ipAddr) == 0 { - allocMethod = "Dynamic" - } - params := jsonutils.Marshal(map[string]interface{}{ - "Name": nicName, - "Location": self.Name, - "Properties": map[string]interface{}{ - "IPConfigurations": []map[string]interface{}{ - map[string]interface{}{ - "Name": nicName, - "Properties": map[string]interface{}{ - "PrivateIPAddress": ipAddr, - "PrivateIPAddressVersion": "IPv4", - "PrivateIPAllocationMethod": allocMethod, - "Subnet": map[string]string{ - "Id": subnetId, - }, - }, - }, - }, - }, - "Type": "Microsoft.Network/networkInterfaces", - }).(*jsonutils.JSONDict) - if len(secgrpId) > 0 { - params.Add(jsonutils.Marshal(map[string]string{"id": secgrpId}), "Properties", "NetworkSecurityGroup") - } - nic := SInstanceNic{} - return &nic, self.create(resourceGroup, params, &nic) -} - -func (self *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { - nics, err := self.GetNetworkInterfaces() - if err != nil { - return nil, errors.Wrapf(err, "GetNetworkInterfaces") - } - ret := []cloudprovider.ICloudNetworkInterface{} - for i := range nics { - if len(nics[i].Properties.VirtualMachine.ID) > 0 { - continue - } - ret = append(ret, &nics[i]) - } - return ret, nil -} - -func (self *SInstanceNic) GetAssociateId() string { - return "" -} - -func (self *SInstanceNic) GetAssociateType() string { - return "" -} - -func (self *SInstanceNic) GetId() string { - return self.ID -} - -func (self *SInstanceNic) GetName() string { - return self.Name -} - -func (self *SInstanceNic) GetStatus() string { - return api.NETWORK_INTERFACE_STATUS_AVAILABLE -} - -func (self *SInstanceNic) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SInstanceNic) GetMacAddress() string { - return self.Properties.MacAddress -} - -func (self *SInstanceNic) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { - addrs := []cloudprovider.ICloudInterfaceAddress{} - for i := range self.Properties.IPConfigurations { - addrs = append(addrs, &self.Properties.IPConfigurations[i]) - } - return addrs, nil -} - -func (self *InterfaceIPConfiguration) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *InterfaceIPConfiguration) GetINetworkId() string { - return strings.ToLower(self.Properties.Subnet.ID) -} - -func (self *InterfaceIPConfiguration) GetIP() string { - return self.Properties.PrivateIPAddress -} - -func (self *InterfaceIPConfiguration) IsPrimary() bool { - return self.Properties.Primary -} diff --git a/pkg/multicloud/azure/kube_cluster.go b/pkg/multicloud/azure/kube_cluster.go deleted file mode 100644 index 242497ca5f..0000000000 --- a/pkg/multicloud/azure/kube_cluster.go +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "encoding/base64" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SKubeCluster struct { - multicloud.SResourceBase - multicloud.AzureTags - region *SRegion - - Id string `json:"id"` - Location string `json:"location"` - Name string `json:"name"` - Type string `json:"type"` - Properties struct { - ProvisioningState string `json:"provisioningState"` - PowerState struct { - Code string `json:"code"` - } `json:"powerState"` - KubernetesVersion string `json:"kubernetesVersion"` - DNSPrefix string `json:"dnsPrefix"` - Fqdn string `json:"fqdn"` - AzurePortalFQDN string `json:"azurePortalFQDN"` - AgentPoolProfiles []SKubeNodePool `json:"agentPoolProfiles"` - ServicePrincipalProfile struct { - ClientId string `json:"clientId"` - } `json:"servicePrincipalProfile"` - AddonProfiles struct { - Azurepolicy struct { - Enabled bool `json:"enabled"` - Config string `json:"config"` - } `json:"azurepolicy"` - HTTPApplicationRouting struct { - Enabled bool `json:"enabled"` - Config struct { - HTTPApplicationRoutingZoneName string `json:"HTTPApplicationRoutingZoneName"` - } `json:"config"` - } `json:"httpApplicationRouting"` - OmsAgent struct { - Enabled bool `json:"enabled"` - Config struct { - LogAnalyticsWorkspaceResourceId string `json:"logAnalyticsWorkspaceResourceId"` - } `json:"config"` - Identity struct { - ResourceId string `json:"resourceId"` - ClientId string `json:"clientId"` - ObjectId string `json:"objectId"` - } `json:"identity"` - } `json:"omsAgent"` - } `json:"addonProfiles"` - NodeResourceGroup string `json:"nodeResourceGroup"` - EnableRBAC bool `json:"enableRBAC"` - NetworkProfile struct { - NetworkPlugin string `json:"networkPlugin"` - LoadBalancerSku string `json:"loadBalancerSku"` - LoadBalancerProfile struct { - ManagedOutboundIPs struct { - Count int `json:"count"` - } `json:"managedOutboundIPs"` - EffectiveOutboundIPs []struct { - Id string `json:"id"` - } `json:"effectiveOutboundIPs"` - } `json:"loadBalancerProfile"` - PodCidr string `json:"podCidr"` - ServiceCidr string `json:"serviceCidr"` - DNSServiceIP string `json:"dnsServiceIP"` - DockerBridgeCidr string `json:"dockerBridgeCidr"` - OutboundType string `json:"outboundType"` - } `json:"networkProfile"` - MaxAgentPools int `json:"maxAgentPools"` - APIServerAccessProfile struct { - EnablePrivateCluster bool `json:"enablePrivateCluster"` - } `json:"apiServerAccessProfile"` - IdentityProfile struct { - Kubeletidentity struct { - ResourceId string `json:"resourceId"` - ClientId string `json:"clientId"` - ObjectId string `json:"objectId"` - } `json:"kubeletidentity"` - } `json:"identityProfile"` - } `json:"properties"` - Identity struct { - Type string `json:"type"` - PrincipalId string `json:"principalId"` - TenantId string `json:"tenantId"` - } `json:"identity"` - Sku struct { - Name string `json:"name"` - Tier string `json:"tier"` - } `json:"sku"` -} - -func (self *SKubeCluster) GetName() string { - return self.Name -} - -func (self *SKubeCluster) GetId() string { - return self.Id -} - -func (self *SKubeCluster) GetGlobalId() string { - return strings.ToLower(self.Id) -} - -func (self *SKubeCluster) Refresh() error { - cluster, err := self.region.GetKubeCluster(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, cluster) -} - -func (self *SKubeCluster) GetStatus() string { - return strings.ToLower(self.Properties.PowerState.Code) -} - -func (self *SKubeCluster) Delete(isRetain bool) error { - return self.region.Delete(self.Id) -} - -func (self *SKubeCluster) GetEnabled() bool { - return true -} - -func (self *SKubeCluster) GetIKubeNodes() ([]cloudprovider.ICloudKubeNode, error) { - return []cloudprovider.ICloudKubeNode{}, nil -} - -func (self *SKubeCluster) GetIKubeNodePools() ([]cloudprovider.ICloudKubeNodePool, error) { - ret := []cloudprovider.ICloudKubeNodePool{} - for i := range self.Properties.AgentPoolProfiles { - self.Properties.AgentPoolProfiles[i].cluster = self - ret = append(ret, &self.Properties.AgentPoolProfiles[i]) - } - return ret, nil -} - -func (self *SKubeCluster) GetKubeConfig(private bool, expireMinute int) (*cloudprovider.SKubeconfig, error) { - return self.region.GetKubeConfig(self.Id) -} - -func (self *SRegion) GetICloudKubeClusters() ([]cloudprovider.ICloudKubeCluster, error) { - clusters, err := self.GetKubeClusters() - if err != nil { - return nil, errors.Wrapf(err, "GetKubClusters") - } - ret := []cloudprovider.ICloudKubeCluster{} - for i := range clusters { - clusters[i].region = self - ret = append(ret, &clusters[i]) - } - return ret, nil -} - -func (self *SRegion) GetICloudKubeClusterById(id string) (cloudprovider.ICloudKubeCluster, error) { - cluster, err := self.GetKubeCluster(id) - if err != nil { - return nil, errors.Wrapf(err, "GetKubeCluster(%s)", id) - } - return cluster, nil -} - -func (self *SRegion) GetKubeCluster(id string) (*SKubeCluster, error) { - ret := &SKubeCluster{region: self} - return ret, self.get(id, nil, ret) -} - -func (self *SRegion) GetKubeClusters() ([]SKubeCluster, error) { - clusters := []SKubeCluster{} - return clusters, self.list("Microsoft.ContainerService/managedClusters", nil, &clusters) -} - -func (self *SRegion) GetKubeConfig(id string) (*cloudprovider.SKubeconfig, error) { - resp, err := self.perform(id, "listClusterAdminCredential", nil) - if err != nil { - return nil, errors.Wrapf(err, "listClusterAdminCredential") - } - ret := struct { - Kubeconfigs []struct { - Name string - Value string - } - }{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - if len(ret.Kubeconfigs) == 0 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty kubeconfig") - } - result := &cloudprovider.SKubeconfig{} - config, err := base64.StdEncoding.DecodeString(ret.Kubeconfigs[0].Value) - if err != nil { - return nil, errors.Wrapf(err, "base64.decode") - } - result.Config = string(config) - return result, err -} diff --git a/pkg/multicloud/azure/kube_node_pools.go b/pkg/multicloud/azure/kube_node_pools.go deleted file mode 100644 index 90116b296f..0000000000 --- a/pkg/multicloud/azure/kube_node_pools.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "strings" - - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SKubeNodePool struct { - multicloud.SResourceBase - multicloud.AzureTags - - cluster *SKubeCluster - - Name string `json:"name"` - Count int `json:"count"` - VMSize string `json:"vmSize"` - OsDiskSizeGB int `json:"osDiskSizeGB"` - OsDiskType string `json:"osDiskType"` - KubeletDiskType string `json:"kubeletDiskType"` - MaxPods int `json:"maxPods"` - Type string `json:"type"` - EnableAutoScaling bool `json:"enableAutoScaling"` - ProvisioningState string `json:"provisioningState"` - PowerState struct { - Code string `json:"code"` - } `json:"powerState"` - OrchestratorVersion string `json:"orchestratorVersion"` - Mode string `json:"mode"` - OsType string `json:"osType"` - OsSKU string `json:"osSKU"` - NodeImageVersion string `json:"nodeImageVersion"` - EnableFIPS bool `json:"enableFIPS"` -} - -func (self *SKubeNodePool) GetName() string { - return self.Name -} - -func (self *SKubeNodePool) GetId() string { - return self.Name -} - -func (self *SKubeNodePool) GetGlobalId() string { - return self.Name -} - -func (self *SKubeNodePool) GetStatus() string { - return strings.ToLower(self.PowerState.Code) -} diff --git a/pkg/multicloud/azure/loadbalancer.go b/pkg/multicloud/azure/loadbalancer.go deleted file mode 100644 index c4734d8e98..0000000000 --- a/pkg/multicloud/azure/loadbalancer.go +++ /dev/null @@ -1,751 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "context" - "strconv" - "strings" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancer struct { - multicloud.SResourceBase - region *SRegion - eips []cloudprovider.ICloudEIP - lbbgs []cloudprovider.ICloudLoadbalancerBackendGroup - listeners []cloudprovider.ICloudLoadbalancerListener - - Name string `json:"name"` - ID string `json:"id"` - Etag string `json:"etag"` - Type string `json:"type"` - Tags map[string]string `json:"tags"` - Location string `json:"location"` - Properties SLoadbalancerProperties `json:"properties"` - Sku Sku `json:"sku"` -} - -func (self *SLoadbalancer) GetId() string { - return self.ID -} - -func (self *SLoadbalancer) GetName() string { - return self.Name -} - -func (self *SLoadbalancer) GetGlobalId() string { - return strings.ToLower(self.GetId()) -} - -func (self *SLoadbalancer) GetStatus() string { - switch self.Properties.ProvisioningState { - case "Deleting": - return api.LB_STATUS_DELETING - case "Failed": - return api.LB_STATUS_START_FAILED - case "Updating": - return api.LB_SYNC_CONF - } - - switch self.Properties.OperationalState { - case "Running": - return api.LB_STATUS_ENABLED - case "Stopped": - return api.LB_STATUS_DISABLED - case "Starting", "Stopping": - return api.LB_SYNC_CONF - default: - if self.Properties.ProvisioningState == "Succeeded" { - return api.LB_STATUS_ENABLED - } - - return api.LB_STATUS_UNKNOWN - } -} - -func (self *SLoadbalancer) Refresh() error { - lb, err := self.region.GetILoadBalancerById(self.GetId()) - if err != nil { - return errors.Wrap(err, "GetILoadBalancerById.Refresh") - } - - err = jsonutils.Update(self, lb) - if err != nil { - return errors.Wrap(err, "jsonutils.Update") - } - - self.eips = nil - self.lbbgs = nil - self.listeners = nil - return nil -} - -func (self *SLoadbalancer) IsEmulated() bool { - return false -} - -func (self *SLoadbalancer) GetSysTags() map[string]string { - data := map[string]string{} - data["loadbalance_type"] = self.Type - data["capacity"] = self.Properties.Sku.Capacity - data["max_capacity"] = strconv.Itoa(self.Properties.AutoscaleConfiguration.MaxCapacity) - data["min_capacity"] = strconv.Itoa(self.Properties.AutoscaleConfiguration.MinCapacity) - data["properties"] = jsonutils.Marshal(self.Properties).String() - return data -} - -func (self *SLoadbalancer) GetTags() (map[string]string, error) { - return self.Tags, nil -} - -func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -func (self *SLoadbalancer) GetProjectId() string { - return getResourceGroup(self.ID) -} - -func (self *SLoadbalancer) getAddresses() [][]string { - ret := [][]string{[]string{}, []string{}} - for _, fip := range self.Properties.FrontendIPConfigurations { - eip := fip.Properties.PublicIPAddress - if eip != nil && len(eip.Properties.IPAddress) > 0 { - ret[0] = append(ret[0], fip.Properties.PublicIPAddress.Properties.IPAddress) - continue - } - - if len(fip.Properties.PrivateIPAddress) > 0 { - ret[1] = append(ret[1], fip.Properties.PrivateIPAddress) - continue - } - } - - return ret -} - -func (self *SLoadbalancer) GetAddress() string { - ips := self.getAddresses() - if len(ips[0]) > 0 { - return ips[0][0] - } else if len(ips[1]) > 0 { - return ips[1][0] - } else { - return "" - } -} - -func (self *SLoadbalancer) GetAddressType() string { - ips := self.getAddresses() - if len(ips[0]) > 0 { - return api.LB_ADDR_TYPE_INTERNET - } else if len(ips[1]) > 0 { - return api.LB_ADDR_TYPE_INTRANET - } else { - return api.LB_ADDR_TYPE_INTRANET - } -} - -func (self *SLoadbalancer) GetNetworkType() string { - return api.LB_NETWORK_TYPE_VPC -} - -func (self *SLoadbalancer) getNetworkIds() []string { - ret := []string{} - for _, fip := range self.Properties.FrontendIPConfigurations { - subnet := fip.Properties.Subnet - if len(subnet.ID) > 0 { - ret = append(ret, subnet.ID) - } - } - - return ret -} - -func (self *SLoadbalancer) getLbbgNetworkIds() []string { - ret := []string{} - for _, b := range self.Properties.BackendAddressPools { - bips := b.Properties.BackendIPConfigurations - if len(bips) > 0 { - for _, ip := range bips { - if strings.Contains(ip.ID, "Microsoft.Network/networkInterfaces") { - nic, _ := self.region.GetNetworkInterface(strings.Split(ip.ID, "/ipConfigurations")[0]) - if nic != nil && len(nic.Properties.IPConfigurations) > 0 { - ipc := nic.Properties.IPConfigurations[0] - if len(ipc.Properties.Subnet.ID) > 0 { - return []string{ipc.Properties.Subnet.ID} - } - } - } - } - } - } - - return ret -} - -func (self *SLoadbalancer) GetNetworkIds() []string { - return self.getNetworkIds() -} - -func (self *SLoadbalancer) GetVpcId() string { - if self.Type == "Microsoft.Network/loadBalancers" { - subnets := self.GetNetworkIds() - if len(subnets) == 0 { - subnets = self.getLbbgNetworkIds() - } - - if len(subnets) > 0 { - network, err := self.region.GetNetwork(subnets[0]) - if network != nil { - return strings.Split(network.GetId(), "/subnets")[0] - } - - log.Errorf("GetNetwork %s: %s", subnets[0], err) - } - } else { - gips := self.Properties.GatewayIPConfigurations - for i := range gips { - netId := gips[i].Properties.Subnet.ID - if len(netId) > 0 { - network, err := self.region.GetNetwork(netId) - if network != nil { - return strings.Split(network.GetId(), "/subnets")[0] - } - log.Errorf("GetNetwork %s: %s", netId, err) - } - } - } - - return "" -} - -func (self *SLoadbalancer) GetZoneId() string { - ips := self.Properties.FrontendIPConfigurations - if len(ips) > 0 && len(ips[0].Zones) > 0 { - return ips[0].Zones[0] - } - - return "" -} - -func (self *SLoadbalancer) GetZone1Id() string { - ips := self.Properties.FrontendIPConfigurations - if len(ips) > 0 && len(ips[0].Zones) > 1 { - return ips[0].Zones[1] - } - - return "" -} - -func (self *SLoadbalancer) GetLoadbalancerSpec() string { - if len(self.Properties.Sku.Name) > 0 { - return self.Properties.Sku.Name - } - - if len(self.Sku.Name) > 0 { - return self.Sku.Name - } - return "" -} - -func (self *SLoadbalancer) GetChargeType() string { - return api.LB_CHARGE_TYPE_BY_TRAFFIC -} - -func (self *SLoadbalancer) GetEgressMbps() int { - return 0 -} - -func (self *SLoadbalancer) getEipIds() []string { - ret := []string{} - for _, fip := range self.Properties.FrontendIPConfigurations { - eip := fip.Properties.PublicIPAddress - if eip != nil && len(eip.ID) > 0 { - ret = append(ret, eip.ID) - continue - } - } - - return ret -} - -func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { - ieips, err := self.GetIEIPS() - if err != nil { - return nil, errors.Wrap(err, "GetIEIPS") - } - - if len(ieips) > 0 { - return self.eips[0], nil - } - - return nil, nil -} - -func (self *SLoadbalancer) GetIEIPById(eipId string) (cloudprovider.ICloudEIP, error) { - ieips, err := self.GetIEIPS() - if err != nil { - return nil, errors.Wrap(err, "GetIEIPS") - } - - for i := range ieips { - if ieips[i].GetId() == eipId { - return ieips[i], nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, eipId) -} - -func (self *SLoadbalancer) GetIEIPS() ([]cloudprovider.ICloudEIP, error) { - if self.eips != nil { - return self.eips, nil - } - - eips := self.getEipIds() - ieips := make([]cloudprovider.ICloudEIP, 0) - for i := range eips { - ieip, err := self.region.GetIEipById(eips[i]) - if err != nil { - return nil, errors.Wrap(err, "GetIEIP") - } - ieips = append(ieips, ieip) - } - - if len(ieips) > 0 { - self.eips = ieips - } - - return self.eips, nil -} - -func (self *SLoadbalancer) Delete(ctx context.Context) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Delete") -} - -func (self *SLoadbalancer) Start() error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Start") -} - -func (self *SLoadbalancer) Stop() error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Stop") -} - -/* -应用型LB: urlPathMaps(defaultBackendAddressPool+defaultBackendHttpSettings+requestRoutingRules+httpListeners)= Onecloud监听器 -4层LB: loadBalancingRules(前端) = Onecloud监听器 -*/ -func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - if self.listeners != nil { - return self.listeners, nil - } - - var err error - if self.Type == "Microsoft.Network/applicationGateways" { - self.listeners, err = self.getAppLBListeners() - } else { - self.listeners, err = self.getNetworkLBListeners() - } - - return self.listeners, err -} - -func (self *SLoadbalancer) getFrontendIPConfiguration(id string) *FrontendIPConfiguration { - fips := self.Properties.FrontendIPConfigurations - for i := range fips { - if fips[i].ID == id { - return &fips[i] - } - } - log.Debugf("getFrontendIPConfiguration %s not found", id) - return nil -} - -func (self *SLoadbalancer) getHttpListener(id string) *HTTPListener { - ss := self.Properties.HTTPListeners - for i := range ss { - if ss[i].ID == id { - return &ss[i] - } - - for j := range ss[i].Properties.RequestRoutingRules { - if ss[i].Properties.RequestRoutingRules[j].ID == id { - return &ss[i] - } - } - } - log.Debugf("getHttpListener %s not found", id) - return nil -} - -func (self *SLoadbalancer) getBackendAddressPool(id string) *BackendAddressPool { - ss := self.Properties.BackendAddressPools - for i := range ss { - if ss[i].ID == id { - return &ss[i] - } - } - log.Debugf("getBackendAddressPool %s not found", id) - return nil -} - -func (self *SLoadbalancer) getBackendHTTPSettingsCollection(id string) *BackendHTTPSettingsCollection { - ss := self.Properties.BackendHTTPSettingsCollection - for i := range ss { - if ss[i].ID == id { - return &ss[i] - } - } - log.Debugf("getBackendHTTPSettingsCollection %s not found", id) - return nil -} - -func (self *SLoadbalancer) getRedirectConfiguration(id string) *RedirectConfiguration { - ss := self.Properties.RedirectConfigurations - for i := range ss { - if ss[i].ID == id { - return &ss[i] - } - } - log.Debugf("getRedirectConfiguration %s not found", id) - return nil -} - -func (self *SLoadbalancer) getProbe(id string) *Probe { - ss := self.Properties.Probes - for i := range ss { - if ss[i].ID == id { - return &ss[i] - } - } - log.Debugf("getProbe %s not found", id) - return nil -} - -func (self *SLoadbalancer) getFrontendPort(id string) *FrontendPort { - ss := self.Properties.FrontendPorts - for i := range ss { - if ss[i].ID == id { - return &ss[i] - } - } - log.Debugf("getFrontendPort %s not found", id) - return nil -} - -func (self *SLoadbalancer) getRequestRoutingRule(id string) *RequestRoutingRule { - ss := self.Properties.RequestRoutingRules - for i := range ss { - if ss[i].ID == id { - return &ss[i] - } - } - log.Debugf("getRequestRoutingRule %s not found", id) - return nil -} - -func (self *SLoadbalancer) getURLPathMap(id string) *URLPathMap { - ss := self.Properties.URLPathMaps - for i := range ss { - if ss[i].ID == id { - return &ss[i] - } - } - log.Debugf("getURLPathMap %s not found", id) - return nil -} - -/* -应用型LB: urlPathMaps(defaultBackendAddressPool+defaultBackendHttpSettings+requestRoutingRules+httpListeners)= Onecloud监听器 -*/ -func (self *SLoadbalancer) getAppLBListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - lbls := []cloudprovider.ICloudLoadbalancerListener{} - for i := range self.Properties.RequestRoutingRules { - r := self.Properties.RequestRoutingRules[i] - uid := strings.Replace(r.ID, "requestRoutingRules", "urlPathMaps", 1) - u := self.getURLPathMap(uid) - lbl := self.getAppLBListener(&r, u) - if lbl != nil { - lbls = append(lbls, lbl) - } - } - - return lbls, nil -} - -func (self *SLoadbalancer) getAppLBListener(r *RequestRoutingRule, u *URLPathMap) *SLoadBalancerListener { - var redirect *RedirectConfiguration - var listener *HTTPListener - var fp *FrontendIPConfiguration - var fpp *FrontendPort - // frontendPort, frontendIPConfiguration, sslCertificate, requestRoutingRules - listener = self.getHttpListener(r.Properties.HTTPListener.ID) - // frontendPorts - fp = self.getFrontendIPConfiguration(listener.Properties.FrontendIPConfiguration.ID) - fpp = self.getFrontendPort(listener.Properties.FrontendPort.ID) - // 配置有异常?? - if fpp == nil || listener == nil { - return nil - } - - lbbgId := r.Properties.BackendAddressPool.ID - lbbgSettingId := r.Properties.BackendHTTPSettings.ID - provisioningState := "Succeeded" - rules := make([]PathRule, 0) - var backendGroup *BackendAddressPool - var backendSetting *BackendHTTPSettingsCollection - var backendPort int - var healthcheck *Probe - if u != nil { - provisioningState = u.Properties.ProvisioningState - rules = u.Properties.PathRules - if u.Properties.DefaultRedirectConfiguration != nil { - redirect = self.getRedirectConfiguration(u.Properties.DefaultRedirectConfiguration.ID) - } - - if len(lbbgId) == 0 && u.Properties.DefaultBackendAddressPool != nil { - lbbgId = u.Properties.DefaultBackendAddressPool.ID - } - - if len(lbbgSettingId) == 0 && u.Properties.DefaultBackendHTTPSettings != nil { - lbbgSettingId = u.Properties.DefaultBackendHTTPSettings.ID - } - } - - if len(lbbgId) > 0 { - backendGroup = self.getBackendAddressPool(lbbgId) - } - - if len(lbbgSettingId) > 0 { - backendSetting = self.getBackendHTTPSettingsCollection(lbbgSettingId) - backendPort = backendSetting.Properties.Port - } - - if backendSetting != nil && backendSetting.Properties.Probe != nil { - healthcheck = self.getProbe(backendSetting.Properties.Probe.ID) - } - - return &SLoadBalancerListener{ - lb: self, - fp: fp, - listener: listener, - backendSetting: backendSetting, - backendGroup: backendGroup, - redirect: redirect, - healthcheck: healthcheck, - Name: r.Name, - ID: r.ID, - ProvisioningState: provisioningState, - IPVersion: "", - Protocol: listener.Properties.Protocol, - LoadDistribution: "", - FrontendPort: fpp.Properties.Port, - BackendPort: backendPort, - ClientIdleTimeout: 0, - EnableFloatingIP: false, - EnableTcpReset: false, - rules: rules, - } -} - -func (self *SLoadbalancer) getNetworkLBListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - lbls := []cloudprovider.ICloudLoadbalancerListener{} - for i := range self.Properties.LoadBalancingRules { - u := self.Properties.LoadBalancingRules[i] - lbl := self.getNetworkLBListener(&u) - lbls = append(lbls, &lbl) - } - - return lbls, nil -} - -func (self *SLoadbalancer) getNetworkLBListener(u *LoadBalancingRule) SLoadBalancerListener { - fp := self.getFrontendIPConfiguration(u.Properties.FrontendIPConfiguration.ID) - backendGroup := self.getBackendAddressPool(u.Properties.BackendAddressPool.ID) - healthcheck := self.getProbe(u.Properties.Probe.ID) - - return SLoadBalancerListener{ - lb: self, - fp: fp, - backendGroup: backendGroup, - healthcheck: healthcheck, - Name: u.Name, - ID: u.ID, - ProvisioningState: u.Properties.ProvisioningState, - IPVersion: "", - Protocol: u.Properties.Protocol, - LoadDistribution: u.Properties.LoadDistribution, - FrontendPort: u.Properties.FrontendPort, - BackendPort: u.Properties.BackendPort, - ClientIdleTimeout: u.Properties.IdleTimeoutInMinutes * 60, - EnableFloatingIP: u.Properties.EnableFloatingIP, - EnableTcpReset: u.Properties.EnableTCPReset, - } -} - -// 应用型LB: HTTP 设置 + 后端池 = onecloud 后端服务器组 -// 4层LB: loadBalancingRules(backendPort)+ 后端池 = onecloud 后端服务器组 -func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - if self.lbbgs != nil { - return self.lbbgs, nil - } - - lbls, err := self.GetILoadBalancerListeners() - if err != nil { - return nil, errors.Wrap(err, "GetILoadBalancerListeners") - } - - bgIds := []string{} - ilbbgs := []cloudprovider.ICloudLoadbalancerBackendGroup{} - for i := range lbls { - lbl := lbls[i].(*SLoadBalancerListener) - if lbl.backendGroup == nil { - continue - } - - bg := SLoadbalancerBackendGroup{ - lb: self, - Pool: *lbl.backendGroup, - DefaultPort: lbl.BackendPort, - HttpSettings: lbl.backendSetting, - BackendIps: lbl.backendGroup.Properties.BackendIPConfigurations, - } - - if !utils.IsInStringArray(bg.GetId(), bgIds) { - bgIds = append(bgIds, bg.GetId()) - ilbbgs = append(ilbbgs, &bg) - } - - // sync rules lbbg - if utils.IsInStringArray(lbl.GetListenerType(), []string{api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS}) { - rules, err := lbl.GetILoadbalancerListenerRules() - if err != nil { - return nil, errors.Wrap(err, "GetILoadbalancerListenerRules") - } - - for j := range rules { - rule := rules[j].(*SLoadbalancerListenerRule) - if rule.lbbg != nil && !utils.IsInStringArray(rule.lbbg.GetId(), bgIds) { - bgIds = append(bgIds, bg.GetId()) - ilbbgs = append(ilbbgs, &bg) - } - } - } - } - - self.lbbgs = ilbbgs - return ilbbgs, nil -} - -func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - lbbgs, err := self.GetILoadBalancerBackendGroups() - if err != nil { - return nil, errors.Wrap(err, "GetILoadBalancerBackendGroups") - } - - for i := range lbbgs { - if lbbgs[i].GetId() == groupId { - return lbbgs[i], nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerBackendGroupById") -} - -func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "CreateILoadBalancerBackendGroup") -} - -func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "CreateILoadBalancerListener") -} - -func (self *SLoadbalancer) getNetworkLBListenerById(id string) (cloudprovider.ICloudLoadbalancerListener, error) { - for i := range self.Properties.LoadBalancingRules { - u := self.Properties.LoadBalancingRules[i] - if u.ID == id { - lbl := self.getNetworkLBListener(&u) - return &lbl, nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "getNetworkLBListenerById") -} - -func (self *SLoadbalancer) getAppLBListenerById(id string) (cloudprovider.ICloudLoadbalancerListener, error) { - for i := range self.Properties.RequestRoutingRules { - r := self.Properties.RequestRoutingRules[i] - if r.ID == id { - u := self.getURLPathMap(strings.Replace(r.ID, "requestRoutingRules", "urlPathMaps", 1)) - return self.getAppLBListener(&r, u), nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "getAppLBListenerById") -} - -func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { - if self.Type == "Microsoft.Network/applicationGateways" { - return self.getAppLBListenerById(listenerId) - } else { - return self.getNetworkLBListenerById(listenerId) - } -} - -func (self *SLoadbalancer) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - icerts := []cloudprovider.ICloudLoadbalancerCertificate{} - ssl := self.Properties.SSLCertificates - for i := range ssl { - s := ssl[i] - cert := SLoadbalancerCert{ - lb: self, - Name: s.Name, - ID: s.ID, - PublicKey: s.Properties.PublicCertData, - } - - icerts = append(icerts, &cert) - } - - return icerts, nil -} - -func (self *SLoadbalancer) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - ssl := self.Properties.SSLCertificates - for i := range ssl { - s := ssl[i] - if s.ID == certId { - return &SLoadbalancerCert{ - lb: self, - Name: s.Name, - ID: s.ID, - PublicKey: s.Properties.PublicCertData, - }, nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerCertificateById") -} diff --git a/pkg/multicloud/azure/loadbalancerbackend.go b/pkg/multicloud/azure/loadbalancerbackend.go deleted file mode 100644 index 23aac3d9ff..0000000000 --- a/pkg/multicloud/azure/loadbalancerbackend.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "context" - "strconv" - "strings" - - "github.com/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerBackend struct { - multicloud.SResourceBase - - lbbg *SLoadbalancerBackendGroup - // networkInterfaces 通过接口地址反查虚拟机地址 - Name string `json:"name"` - ID string `json:"id"` - Type string `json:"type"` - BackendPort int - BackendIP string -} - -func (self *SLoadbalancerBackend) GetId() string { - return self.ID + "::" + strconv.Itoa(self.BackendPort) -} - -func (self *SLoadbalancerBackend) GetName() string { - return self.Name -} - -func (self *SLoadbalancerBackend) GetGlobalId() string { - return strings.ToLower(self.GetId()) -} - -func (self *SLoadbalancerBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancerBackend) GetSysTags() map[string]string { - return nil -} - -func (self *SLoadbalancerBackend) GetTags() (map[string]string, error) { - return nil, nil -} - -func (self *SLoadbalancerBackend) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -func (self *SLoadbalancerBackend) GetProjectId() string { - return getResourceGroup(self.ID) -} - -func (self *SLoadbalancerBackend) GetWeight() int { - return 0 -} - -func (self *SLoadbalancerBackend) GetPort() int { - return self.BackendPort -} - -func (self *SLoadbalancerBackend) GetBackendType() string { - return self.Type -} - -func (self *SLoadbalancerBackend) GetBackendRole() string { - return api.LB_BACKEND_ROLE_DEFAULT -} - -func (self *SLoadbalancerBackend) GetBackendId() string { - return self.ID -} - -func (self *SLoadbalancerBackend) GetIpAddress() string { - return self.BackendIP -} - -func (self *SLoadbalancerBackend) SyncConf(ctx context.Context, port, weight int) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SyncConf") -} diff --git a/pkg/multicloud/azure/loadbalancerbackendgroup.go b/pkg/multicloud/azure/loadbalancerbackendgroup.go deleted file mode 100644 index f298a60949..0000000000 --- a/pkg/multicloud/azure/loadbalancerbackendgroup.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "context" - "fmt" - "strconv" - "strings" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// todo: 虚拟机规模集不支持 -// 注: 因为与onecloud后端服务器组存在配置差异,不支持同步未关联的后端服务器组 -// 应用型LB: HTTP 设置 + 后端池 = onecloud 后端服务器组 -// 4层LB: loadBalancingRules(backendPort)+ 后端池 = onecloud 后端服务器组 -type SLoadbalancerBackendGroup struct { - multicloud.SResourceBase - lb *SLoadbalancer - lbbs []cloudprovider.ICloudLoadbalancerBackend - - Pool BackendAddressPool - DefaultPort int - HttpSettings *BackendHTTPSettingsCollection - - BackendIps []BackendIPConfiguration -} - -func (self *SLoadbalancerBackendGroup) GetId() string { - return self.Pool.ID + "::" + strconv.Itoa(self.DefaultPort) -} - -func (self *SLoadbalancerBackendGroup) GetName() string { - if self.HttpSettings != nil { - return self.Pool.Name + "::" + self.HttpSettings.Name - } - - return self.Pool.Name + "::" + strconv.Itoa(self.DefaultPort) -} - -func (self *SLoadbalancerBackendGroup) GetGlobalId() string { - return strings.ToLower(self.GetId()) -} - -func (self *SLoadbalancerBackendGroup) GetStatus() string { - switch self.Pool.Properties.ProvisioningState { - case "Succeeded": - return api.LB_STATUS_ENABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (self *SLoadbalancerBackendGroup) Refresh() error { - lbbg, err := self.lb.GetILoadBalancerBackendGroupById(self.GetId()) - if err != nil { - return errors.Wrap(err, "GetILoadBalancerBackendGroupById") - } - - err = jsonutils.Update(self, lbbg) - if err != nil { - return errors.Wrap(err, "refresh.Update") - } - - self.lbbs = nil - return nil -} - -func (self *SLoadbalancerBackendGroup) IsEmulated() bool { - return true -} - -func (self *SLoadbalancerBackendGroup) GetSysTags() map[string]string { - return nil -} - -func (self *SLoadbalancerBackendGroup) GetTags() (map[string]string, error) { - return map[string]string{}, nil -} - -func (self *SLoadbalancerBackendGroup) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -func (self *SLoadbalancerBackendGroup) GetProjectId() string { - return getResourceGroup(self.GetId()) -} - -func (self *SLoadbalancerBackendGroup) IsDefault() bool { - return false -} - -func (self *SLoadbalancerBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_NORMAL -} - -func (self *SLoadbalancerBackendGroup) GetLoadbalancerId() string { - return self.lb.GetId() -} - -func (self *SLoadbalancerBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - if self.lbbs != nil { - return self.lbbs, nil - } - - var ret []cloudprovider.ICloudLoadbalancerBackend - ips := self.Pool.Properties.BackendIPConfigurations - for i := range ips { - ip := ips[i] - nic, err := self.lb.region.GetNetworkInterface(strings.Split(ip.ID, "/ipConfigurations")[0]) - if err != nil { - return nil, errors.Wrap(err, "GetNetworkInterface") - } - - if len(nic.Properties.VirtualMachine.ID) == 0 { - continue - } - - name := nic.Properties.VirtualMachine.Name - vid := nic.Properties.VirtualMachine.ID - if len(name) == 0 && len(vid) > 0 { - segs := strings.Split(vid, "/virtualMachines/") - name = segs[len(segs)-1] - } - bg := SLoadbalancerBackend{ - SResourceBase: multicloud.SResourceBase{}, - lbbg: self, - Name: name, - ID: vid, - Type: api.LB_BACKEND_GUEST, - BackendPort: self.DefaultPort, - } - - ret = append(ret, &bg) - } - - ips2 := self.Pool.Properties.BackendAddresses - for i := range ips2 { - name := fmt.Sprintf("ip-%s", ips2[i].IPAddress) - bg := SLoadbalancerBackend{ - SResourceBase: multicloud.SResourceBase{}, - lbbg: self, - Name: name, - ID: fmt.Sprintf("%s-%s", self.GetId(), name), - Type: api.LB_BACKEND_IP, - BackendIP: ips2[i].IPAddress, - BackendPort: self.DefaultPort, - } - - ret = append(ret, &bg) - } - - self.lbbs = ret - return ret, nil -} - -func (self *SLoadbalancerBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - lbbs, err := self.GetILoadbalancerBackends() - if err != nil { - return nil, errors.Wrap(err, "GetILoadbalancerBackends") - } - - for i := range lbbs { - if lbbs[i].GetId() == backendId { - return lbbs[i], nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadbalancerBackendById") -} - -func (self *SLoadbalancerBackendGroup) GetProtocolType() string { - return "" -} - -func (self *SLoadbalancerBackendGroup) GetScheduler() string { - return "" -} - -func (self *SLoadbalancerBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - return nil, nil -} - -func (self *SLoadbalancerBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - return nil, nil -} - -func (self *SLoadbalancerBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "AddBackendServer") -} - -func (self *SLoadbalancerBackendGroup) RemoveBackendServer(serverId string, weight int, port int) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "RemoveBackendServer") -} - -func (self *SLoadbalancerBackendGroup) Delete(ctx context.Context) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Delete") -} - -func (self *SLoadbalancerBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Sync") -} diff --git a/pkg/multicloud/azure/loadbalancercert.go b/pkg/multicloud/azure/loadbalancercert.go deleted file mode 100644 index 979d443728..0000000000 --- a/pkg/multicloud/azure/loadbalancercert.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "bytes" - "crypto/sha1" - "crypto/x509" - "encoding/pem" - "fmt" - "strings" - "time" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerCert struct { - multicloud.SResourceBase - lb *SLoadbalancer - cert *x509.Certificate - Name string `json:"name"` - ID string `json:"id"` - PublicKey string `json:"public_key"` -} - -func (self *SLoadbalancerCert) GetId() string { - return self.ID -} - -func (self *SLoadbalancerCert) GetName() string { - return self.Name -} - -func (self *SLoadbalancerCert) GetGlobalId() string { - return strings.ToLower(self.GetId()) -} - -func (self *SLoadbalancerCert) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancerCert) Refresh() error { - cert, err := self.lb.GetILoadBalancerCertificateById(self.GetId()) - if err != nil { - return errors.Wrap(err, "GetILoadBalancerCertificateById") - } - - err = jsonutils.Update(self, cert) - if err != nil { - return errors.Wrap(err, "Update") - } - - return nil -} - -func (self *SLoadbalancerCert) IsEmulated() bool { - return false -} - -func (self *SLoadbalancerCert) GetSysTags() map[string]string { - return nil -} - -func (self *SLoadbalancerCert) GetTags() (map[string]string, error) { - return nil, nil -} - -func (self *SLoadbalancerCert) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -func (self *SLoadbalancerCert) GetProjectId() string { - return getResourceGroup(self.GetId()) -} - -func (self *SLoadbalancerCert) Sync(name, privateKey, publickKey string) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Sync") -} - -func (self *SLoadbalancerCert) Delete() error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Delete") -} - -func (self *SLoadbalancerCert) ParsePublicKey() (*x509.Certificate, error) { - if self.cert != nil { - return self.cert, nil - } - - publicKey := self.GetPublickKey() - if len(publicKey) == 0 { - return nil, fmt.Errorf("SElbCertificate ParsePublicKey public key is empty") - } - - block, _ := pem.Decode([]byte(publicKey)) - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return nil, errors.Wrap(err, "ParseCertificate") - } - - self.cert = cert - return cert, nil -} - -func (self *SLoadbalancerCert) GetCommonName() string { - cert, err := self.ParsePublicKey() - if err != nil { - return "" - } - - return cert.Issuer.CommonName -} - -func (self *SLoadbalancerCert) GetSubjectAlternativeNames() string { - _, err := self.ParsePublicKey() - if err != nil { - return "" - } - - return "" -} - -func (self *SLoadbalancerCert) GetFingerprint() string { - publicKey := self.GetPublickKey() - if len(publicKey) == 0 { - return "" - } - - _fp := sha1.Sum([]byte(publicKey)) - fp := fmt.Sprintf("sha1:% x", _fp) - return strings.Replace(fp, " ", ":", -1) -} - -func (self *SLoadbalancerCert) GetExpireTime() time.Time { - cert, err := self.ParsePublicKey() - if err != nil { - return time.Time{} - } - - return cert.NotAfter -} - -func (self *SLoadbalancerCert) GetPublickKey() string { - if len(self.PublicKey) > 0 { - var pk bytes.Buffer - pk.WriteString("-----BEGIN CERTIFICATE-----\r\n") - content := bytes.NewBufferString(self.PublicKey) - for { - l := content.Next(64) - if len(l) == 64 { - pk.WriteString(fmt.Sprintf("%s\r\n", l)) - } else { - pk.WriteString(fmt.Sprintf("%s\r\n", l)) - break - } - } - pk.WriteString("-----END CERTIFICATE-----") - return pk.String() - } - - return "" -} - -func (self *SLoadbalancerCert) GetPrivateKey() string { - return "" -} diff --git a/pkg/multicloud/azure/loadbalancerlistener.go b/pkg/multicloud/azure/loadbalancerlistener.go deleted file mode 100644 index a1b03aecda..0000000000 --- a/pkg/multicloud/azure/loadbalancerlistener.go +++ /dev/null @@ -1,600 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "context" - "net/url" - "regexp" - "strconv" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// todo: 目前不支持 入站 NAT 规则 -// todo: HTTP 设置(端口+协议,其余信息丢弃) + 后端池 = onecloud 路径的路由 的 onecloud 后端服务器组 -/* -应用型LB: urlPathMaps(defaultBackendAddressPool+defaultBackendHttpSettings+requestRoutingRules+httpListeners)= Onecloud监听器 -4层LB: loadBalancingRules(前端) = Onecloud监听器 -*/ -type SLoadBalancerListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - - lb *SLoadbalancer - lbrs []cloudprovider.ICloudLoadbalancerListenerRule - - /* - IPVersion string - FrontendIP string // 前端IP - FrontendIPId string // 前端IP ID - */ - fp *FrontendIPConfiguration - - /* - Protocol string // 监听协议 - HostName string // 监听器 监听域名 - FrontendPort int // 前端端口 - */ - listener *HTTPListener - - /* - Protocol string // 后端协议 - BackendPort int // 后端端口 - IdleTimeoutInMinutes int // 空闲超时(分钟) - LoadDistribution string // 会话保持方法SourceIP|SourceIPProtocol - CookieBasedAffinity string // cookies 关联 - CookieName string // cookie 名称 - EnabledConnectionDraining bool // 排出超时这应用于通过 API 调用从后端池明确删除的后端实例,以及运行状况探测报告的运行不正常的实例。 - ConnectionDrainingSec int // 排出超时时长(秒) - RequestTimeout int // 请求超时时间(秒) - probe // 健康检查 - */ - backendSetting *BackendHTTPSettingsCollection - - // - backendGroup *BackendAddressPool - - /* - redirectType string // 重定向类型 - targetListener // 重定向到监听 - */ - redirect *RedirectConfiguration - - /* - "protocol": "Http", - "host": "baidu.com", - "path": "/test", - "interval": 30, - "timeout": 30, - "unhealthyThreshold": 3, - "pickHostNameFromBackendHttpSettings": false, - "minServers": 0, - "match": { - "body": "500", - "statusCodes": [ - "200-399" - ] - }, - */ - healthcheck *Probe - - Name string - ID string - ProvisioningState string - IPVersion string - Protocol string // 监听协议 - LoadDistribution string // 调度算法 - FrontendPort int // 前端端口 - BackendPort int // 后端端口 - ClientIdleTimeout int // 客户端连接超时 - EnableFloatingIP bool // 浮动 IP - EnableTcpReset bool - - rules []PathRule -} - -func (self *SLoadBalancerListener) GetId() string { - return self.ID -} - -func (self *SLoadBalancerListener) GetName() string { - return self.Name -} - -func (self *SLoadBalancerListener) GetGlobalId() string { - return strings.ToLower(self.GetId()) -} - -func (self *SLoadBalancerListener) GetStatus() string { - switch self.ProvisioningState { - case "Succeeded", "Updating", "Deleting": - return api.LB_STATUS_ENABLED - case "Failed": - return api.LB_STATUS_DISABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (self *SLoadBalancerListener) Refresh() error { - lbl, err := self.lb.GetILoadBalancerListenerById(self.GetId()) - if err != nil { - return errors.Wrap(err, "GetILoadBalancerListenerById") - } - - err = jsonutils.Update(self, lbl) - if err != nil { - return errors.Wrap(err, "refresh.Update") - } - - self.lbrs = nil - return nil -} - -func (self *SLoadBalancerListener) IsEmulated() bool { - return false -} - -func (self *SLoadBalancerListener) GetSysTags() map[string]string { - return nil -} - -func (self *SLoadBalancerListener) GetTags() (map[string]string, error) { - if self.fp != nil { - if self.fp.Properties.PublicIPAddress != nil && len(self.fp.Properties.PublicIPAddress.ID) > 0 { - eip, _ := self.lb.GetIEIPById(self.fp.Properties.PublicIPAddress.ID) - if eip != nil { - return map[string]string{"FrontendIP": eip.GetIpAddr()}, nil - } - } - - if len(self.fp.Properties.PrivateIPAddress) > 0 { - return map[string]string{"FrontendIP": self.fp.Properties.PrivateIPAddress}, nil - } - } - - return map[string]string{}, nil -} - -func (self *SLoadBalancerListener) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -func (self *SLoadBalancerListener) GetProjectId() string { - return getResourceGroup(self.GetId()) -} - -func (self *SLoadBalancerListener) GetListenerType() string { - switch strings.ToLower(self.Protocol) { - case "tcp": - return api.LB_LISTENER_TYPE_TCP - case "udp": - return api.LB_LISTENER_TYPE_UDP - case "http": - return api.LB_LISTENER_TYPE_HTTP - case "https": - return api.LB_LISTENER_TYPE_HTTPS - default: - return "" - } -} - -func (self *SLoadBalancerListener) GetListenerPort() int { - return int(self.FrontendPort) -} - -func (self *SLoadBalancerListener) GetScheduler() string { - switch self.LoadDistribution { - case "SourceIPProtocol", "SourceIP": - return api.LB_SCHEDULER_SCH - default: - return "" - } -} - -func (self *SLoadBalancerListener) GetAclStatus() string { - return api.LB_BOOL_OFF -} - -func (self *SLoadBalancerListener) GetAclType() string { - return "" -} - -func (self *SLoadBalancerListener) GetAclId() string { - return "" -} - -func (self *SLoadBalancerListener) GetEgressMbps() int { - return 0 -} - -func (self *SLoadBalancerListener) GetHealthCheck() string { - // if self.probe != nil - if self.healthcheck != nil { - return api.LB_BOOL_ON - } - - return api.LB_BOOL_OFF -} - -func (self *SLoadBalancerListener) GetHealthCheckType() string { - if self.healthcheck == nil { - return "" - } - switch strings.ToLower(self.healthcheck.Properties.Protocol) { - case "tcp": - return api.LB_HEALTH_CHECK_TCP - case "udp": - return api.LB_HEALTH_CHECK_UDP - case "http": - return api.LB_HEALTH_CHECK_HTTP - case "https": - return api.LB_HEALTH_CHECK_HTTPS - default: - return "" - } -} - -func (self *SLoadBalancerListener) GetHealthCheckTimeout() int { - if self.healthcheck == nil { - return 0 - } - switch self.GetHealthCheckType() { - case api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS: - return self.healthcheck.Properties.Timeout - } - - return self.healthcheck.Properties.IntervalInSeconds -} - -func (self *SLoadBalancerListener) GetHealthCheckInterval() int { - if self.healthcheck == nil { - return 0 - } - switch self.GetHealthCheckType() { - case api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS: - if self.healthcheck.Properties.Interval > 0 { - return self.healthcheck.Properties.Interval - } - } - - return self.healthcheck.Properties.IntervalInSeconds -} - -func (self *SLoadBalancerListener) GetHealthCheckRise() int { - return 0 -} - -func (self *SLoadBalancerListener) GetHealthCheckFail() int { - if self.healthcheck == nil { - return 0 - } - switch self.GetHealthCheckType() { - case api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS: - if self.healthcheck.Properties.UnhealthyThreshold > 0 { - return self.healthcheck.Properties.UnhealthyThreshold - } - } - - return self.healthcheck.Properties.NumberOfProbes -} - -func (self *SLoadBalancerListener) GetHealthCheckReq() string { - return "" -} - -func (self *SLoadBalancerListener) GetHealthCheckExp() string { - return "" -} - -func (self *SLoadBalancerListener) GetBackendGroupId() string { - if self.backendGroup != nil { - return self.backendGroup.ID + "::" + strconv.Itoa(self.BackendPort) - } - - return "" -} - -func (self *SLoadBalancerListener) GetBackendServerPort() int { - return self.BackendPort -} - -func (self *SLoadBalancerListener) GetHealthCheckDomain() string { - if self.healthcheck == nil { - return "" - } - switch self.GetHealthCheckType() { - case api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS: - return self.healthcheck.Properties.Host - } - - return "" -} - -func (self *SLoadBalancerListener) GetHealthCheckURI() string { - if self.healthcheck == nil { - return "" - } - switch self.GetHealthCheckType() { - case api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS: - return self.healthcheck.Properties.Path - } - - return "" -} - -/* -todo: 和onecloud code不兼容? -与此处输入的 HTTP 状态代码或代码范围相匹配的响应将被视为成功。请输入逗号分隔的代码列表(例如 200, 201)或者输入一个代码范围(例如 220-226) -*/ -func (self *SLoadBalancerListener) GetHealthCheckCode() string { - return "" -} - -func (self *SLoadBalancerListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "CreateILoadBalancerListenerRule") -} - -func (self *SLoadBalancerListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - lbrs, err := self.GetILoadbalancerListenerRules() - if err != nil { - return nil, errors.Wrap(err, "GetILoadbalancerListenerRules") - } - - for i := range lbrs { - if lbrs[i].GetId() == ruleId { - return lbrs[i], nil - } - } - - return nil, errors.Wrap(err, "GetILoadBalancerListenerRuleById") -} - -func (self *SLoadBalancerListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - if self.lbrs != nil { - return self.lbrs, nil - } - - irules := []cloudprovider.ICloudLoadbalancerListenerRule{} - for i := range self.rules { - r := self.rules[i] - var redirect *RedirectConfiguration - var lbbg *SLoadbalancerBackendGroup - if r.Properties.RedirectConfiguration != nil { - redirect = self.lb.getRedirectConfiguration(r.Properties.RedirectConfiguration.ID) - } else { - if r.Properties.BackendAddressPool == nil || r.Properties.BackendHTTPSettings == nil { - continue - } - - pool := self.lb.getBackendAddressPool(r.Properties.BackendAddressPool.ID) - if pool == nil { - log.Debugf("getBackendAddressPool %s not found", r.Properties.BackendAddressPool.ID) - continue - } - backsetting := self.lb.getBackendHTTPSettingsCollection(r.Properties.BackendHTTPSettings.ID) - if backsetting == nil { - log.Debugf("getBackendHTTPSettingsCollection %s not found", r.Properties.BackendHTTPSettings.ID) - continue - } - - lbbg = &SLoadbalancerBackendGroup{ - lb: self.lb, - Pool: *pool, - DefaultPort: backsetting.Properties.Port, - HttpSettings: backsetting, - BackendIps: pool.Properties.BackendIPConfigurations, - } - } - - domain := "" - if self.listener != nil { - domain = self.listener.Properties.HostName - } - - rule := SLoadbalancerListenerRule{ - SResourceBase: multicloud.SResourceBase{}, - listener: self, - lbbg: lbbg, - redirect: redirect, - Name: r.Name, - ID: r.ID, - Domain: domain, - Properties: r.Properties, - } - irules = append(irules, &rule) - } - - return irules, nil -} - -func (self *SLoadBalancerListener) GetStickySession() string { - if self.backendSetting == nil { - return api.LB_BOOL_OFF - } - - if self.backendSetting.Properties.CookieBasedAffinity == "Enabled" { - return api.LB_BOOL_ON - } else { - return api.LB_BOOL_OFF - } -} - -func (self *SLoadBalancerListener) GetStickySessionType() string { - if self.GetStickySession() == api.LB_BOOL_ON { - return api.LB_STICKY_SESSION_TYPE_INSERT - } - return "" -} - -func (self *SLoadBalancerListener) GetStickySessionCookie() string { - if self.backendSetting == nil { - return "" - } - - return self.backendSetting.Properties.AffinityCookieName -} - -func (self *SLoadBalancerListener) GetStickySessionCookieTimeout() int { - if self.backendSetting == nil { - return 0 - } - - if self.backendSetting.Properties.ConnectionDraining.Enabled { - _sec := strings.TrimSpace(self.backendSetting.Properties.ConnectionDraining.DrainTimeoutInSEC) - sec, _ := strconv.ParseInt(_sec, 10, 64) - return int(sec) - } - - return 0 -} - -func (self *SLoadBalancerListener) XForwardedForEnabled() bool { - return false -} - -func (self *SLoadBalancerListener) GzipEnabled() bool { - return false -} - -func (self *SLoadBalancerListener) GetCertificateId() string { - if self.listener != nil { - return self.listener.Properties.SSLCertificate.ID - } - - return "" -} - -func (self *SLoadBalancerListener) GetTLSCipherPolicy() string { - return "" -} - -func (self *SLoadBalancerListener) HTTP2Enabled() bool { - return self.lb.Properties.EnableHttp2 -} - -func (self *SLoadBalancerListener) Start() error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Start") -} - -func (self *SLoadBalancerListener) Stop() error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Stop") -} - -func (self *SLoadBalancerListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Sync") -} - -func (self *SLoadBalancerListener) Delete(ctx context.Context) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Delete") -} - -func (self *SLoadBalancerListener) GetRedirect() string { - if self.redirect != nil { - return api.LB_REDIRECT_RAW - } - - return api.LB_REDIRECT_OFF -} - -func (self *SLoadBalancerListener) GetRedirectCode() int64 { - if self.redirect == nil { - return 0 - } - - switch self.redirect.Properties.RedirectType { - case "Permanent": - return api.LB_REDIRECT_CODE_301 - case "Found": - return api.LB_REDIRECT_CODE_302 - case "Temporary", "SeeOther": - return api.LB_REDIRECT_CODE_307 - default: - return 0 - } -} - -func (self *SLoadBalancerListener) getRedirectUrl() *url.URL { - if self.redirect == nil { - return nil - } - - if len(self.redirect.Properties.TargetUrl) == 0 { - return nil - } - - _url := self.redirect.Properties.TargetUrl - if matched, _ := regexp.MatchString("^\\w{0,5}://", _url); !matched { - _url = "http://" + _url - } - - u, err := url.Parse(_url) - if err != nil { - log.Debugf("url Parse %s : %s", self.redirect.Properties.TargetUrl, err) - return nil - } - - return u -} -func (self *SLoadBalancerListener) GetRedirectScheme() string { - u := self.getRedirectUrl() - if u == nil { - return "" - } - - return strings.ToLower(u.Scheme) -} - -func (self *SLoadBalancerListener) GetRedirectHost() string { - u := self.getRedirectUrl() - if u == nil { - if self.redirect != nil && len(self.redirect.Properties.TargetListener.ID) > 0 { - segs := strings.Split(self.redirect.Properties.TargetListener.ID, "/") - return segs[len(segs)-1] - } - return "" - } - - return u.Host -} - -func (self *SLoadBalancerListener) GetRedirectPath() string { - u := self.getRedirectUrl() - if u == nil { - return "" - } - - return u.Path -} - -func (self *SLoadBalancerListener) GetClientIdleTimeout() int { - return self.ClientIdleTimeout -} - -func (self *SLoadBalancerListener) GetBackendConnectTimeout() int { - if self.backendSetting == nil { - return 0 - } - - return self.backendSetting.Properties.RequestTimeout -} diff --git a/pkg/multicloud/azure/loadbalancerlistenerrule.go b/pkg/multicloud/azure/loadbalancerlistenerrule.go deleted file mode 100644 index 911ff6990a..0000000000 --- a/pkg/multicloud/azure/loadbalancerlistenerrule.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "context" - "net/url" - "regexp" - "strings" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerListenerRule struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - - listener *SLoadBalancerListener - lbbg *SLoadbalancerBackendGroup - redirect *RedirectConfiguration - // urlPathMaps -> pathRules - Name string `json:"name"` - ID string `json:"id"` - Domain string `json:"domain"` - Properties PathRuleProperties `json:"properties"` -} - -func (self *SLoadbalancerListenerRule) GetId() string { - return self.ID -} - -func (self *SLoadbalancerListenerRule) GetName() string { - return self.Name -} - -func (self *SLoadbalancerListenerRule) GetGlobalId() string { - return strings.ToLower(self.GetId()) -} - -func (self *SLoadbalancerListenerRule) GetStatus() string { - switch self.Properties.ProvisioningState { - case "Succeeded": - return api.LB_STATUS_ENABLED - case "Failed": - return api.LB_STATUS_DISABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (self *SLoadbalancerListenerRule) GetSysTags() map[string]string { - return nil -} - -func (self *SLoadbalancerListenerRule) GetTags() (map[string]string, error) { - return nil, nil -} - -func (self *SLoadbalancerListenerRule) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -func (self *SLoadbalancerListenerRule) GetProjectId() string { - return getResourceGroup(self.GetId()) -} - -func (self *SLoadbalancerListenerRule) IsDefault() bool { - return false -} - -func (self *SLoadbalancerListenerRule) GetDomain() string { - return self.Domain -} - -func (self *SLoadbalancerListenerRule) GetPath() string { - if len(self.Properties.Paths) > 0 { - return self.Properties.Paths[0] - } - - return "" -} - -func (self *SLoadbalancerListenerRule) GetCondition() string { - return "" -} - -func (self *SLoadbalancerListenerRule) GetBackendGroupId() string { - if self.lbbg != nil { - return self.lbbg.GetId() - } - - return "" -} - -func (self *SLoadbalancerListenerRule) Delete(ctx context.Context) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "Delete") -} - -func (self *SLoadbalancerListenerRule) GetRedirect() string { - if self.redirect != nil { - return api.LB_REDIRECT_RAW - } - - return api.LB_REDIRECT_OFF -} - -func (self *SLoadbalancerListenerRule) GetRedirectCode() int64 { - if self.redirect == nil { - return 0 - } - - switch self.redirect.Properties.RedirectType { - case "Permanent": - return api.LB_REDIRECT_CODE_301 - case "Found": - return api.LB_REDIRECT_CODE_302 - case "Temporary", "SeeOther": - return api.LB_REDIRECT_CODE_307 - default: - return 0 - } -} - -func (self *SLoadbalancerListenerRule) getRedirectUrl() *url.URL { - if self.redirect == nil { - return nil - } - - if len(self.redirect.Properties.TargetUrl) == 0 { - return nil - } - - _url := self.redirect.Properties.TargetUrl - if matched, _ := regexp.MatchString("^\\w{0,5}://", _url); !matched { - _url = "http://" + _url - } - - u, err := url.Parse(_url) - if err != nil { - log.Debugf("url Parse %s : %s", self.redirect.Properties.TargetUrl, err) - return nil - } - - return u -} -func (self *SLoadbalancerListenerRule) GetRedirectScheme() string { - u := self.getRedirectUrl() - if u == nil { - return "" - } - - return strings.ToLower(u.Scheme) -} - -func (self *SLoadbalancerListenerRule) GetRedirectHost() string { - u := self.getRedirectUrl() - if u == nil { - if self.redirect != nil && len(self.redirect.Properties.TargetListener.ID) > 0 { - segs := strings.Split(self.redirect.Properties.TargetListener.ID, "/") - return segs[len(segs)-1] - } - return "" - } - - return u.Host -} - -func (self *SLoadbalancerListenerRule) GetRedirectPath() string { - u := self.getRedirectUrl() - if u == nil { - return "" - } - - return u.Path -} diff --git a/pkg/multicloud/azure/monitor.go b/pkg/multicloud/azure/monitor.go deleted file mode 100644 index 2771e7b2b7..0000000000 --- a/pkg/multicloud/azure/monitor.go +++ /dev/null @@ -1,506 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "context" - "fmt" - "net/http" - "net/url" - "strconv" - "strings" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/timeutils" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -type ResponseMetirc struct { - // Cost - The integer value representing the cost of the query, for data case. - Cost float64 `json:"cost,omitempty"` - // Timespan - The timespan for which the data was retrieved. Its value consists of two datetimes concatenated, separated by '/'. This may be adjusted in the future and returned back from what was originally requested. - Timespan string `json:"timespan,omitempty"` - // Interval - The interval (window size) for which the metric data was returned in. This may be adjusted in the future and returned back from what was originally requested. This is not present if a metadata request was made. - Interval string `json:"interval,omitempty"` - // Namespace - The namespace of the metrics been queried - Namespace string `json:"namespace,omitempty"` - // Resourceregion - The region of the resource been queried for metrics. - Resourceregion string `json:"resourceregion,omitempty"` - // Value - the value of the collection. - Value []Metric `json:"value,omitempty"` -} - -// Metric the result data of a query. -type Metric struct { - // ID - the metric Id. - ID string `json:"id,omitempty"` - // Type - the resource type of the metric resource. - Type string `json:"type,omitempty"` - // Name - the name and the display name of the metric, i.e. it is localizable string. - Name LocalizableString `json:"name,omitempty"` - // Unit - the unit of the metric. Possible values include: 'UnitCount', 'UnitBytes', 'UnitSeconds', 'UnitCountPerSecond', 'UnitBytesPerSecond', 'UnitPercent', 'UnitMilliSeconds', 'UnitByteSeconds', 'UnitUnspecified', 'UnitCores', 'UnitMilliCores', 'UnitNanoCores', 'UnitBitsPerSecond' - Unit string `json:"unit,omitempty"` - // Timeseries - the time series returned when a data query is performed. - Timeseries []TimeSeriesElement `json:"timeseries,omitempty"` -} - -type TimeSeriesElement struct { - // Metadatavalues - the metadata values returned if $filter was specified in the call. - Metadatavalues []MetadataValue `json:"metadatavalues,omitempty"` - // Data - An array of data points representing the metric values. This is only returned if a result type of data is specified. - Data []MetricValue `json:"data,omitempty"` -} - -type MetadataValue struct { - // Name - the name of the metadata. - Name LocalizableString `json:"name,omitempty"` - // Value - the value of the metadata. - Value string `json:"value,omitempty"` -} - -type LocalizableString struct { - // Value - the invariant value. - Value string `json:"value,omitempty"` - // LocalizedValue - the locale specific value. - LocalizedValue string `json:"localizedValue,omitempty"` -} - -type MetricValue struct { - // TimeStamp - the timestamp for the metric value in ISO 8601 format. - TimeStamp time.Time `json:"timeStamp,omitempty"` - // Average - the average value in the time range. - Average float64 `json:"average,omitempty"` - // Minimum - the least value in the time range. - Minimum float64 `json:"minimum,omitempty"` - // Maximum - the greatest value in the time range. - Maximum float64 `json:"maximum,omitempty"` - // Total - the sum of all of the values in the time range. - Total float64 `json:"total,omitempty"` - // Count - the number of samples in the time range. Can be used to determine the number of values that contributed to the average value. - Count float64 `json:"count,omitempty"` -} - -func (self MetricValue) GetValue() float64 { - if self.Average > 0 { - return self.Average - } - if self.Total > 0 { - return self.Total - } - if self.Count > 0 { - return self.Count - } - if self.Minimum > 0 { - return self.Minimum - } - return self.Maximum -} - -const ( - RDS_TYPE_SERVERS = "servers" - RDS_TYPE_FLEXIBLE_SERVERS = "flexibleServers" -) - -// https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/metrics-supported -func (self *SAzureClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_RDS: - return self.GetRdsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: - return self.GetRedisMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_LB: - return self.GetLbMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_K8S: - return self.GetK8sMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) - } -} - -type AzureTableMetricDataValue struct { - Timestamp time.Time - Average float64 - Count float64 - CounterName string - DeploymentId string - Host string - Total float64 - Maximum float64 - Minimum float64 -} - -func (self AzureTableMetricDataValue) GetValue() float64 { - if self.Average > 0 { - return self.Average - } - if self.Count > 0 { - return self.Count - } - if self.Minimum > 0 { - return self.Minimum - } - return self.Maximum -} - -type AzureTableMetricData struct { - Value []AzureTableMetricDataValue -} - -func (self *SAzureClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricnamespace := "Microsoft.Compute/virtualMachines" - metricnames := "Percentage CPU,Network In Total,Network Out Total,Disk Read Bytes,Disk Write Bytes,Disk Read Operations/Sec,Disk Write Operations/Sec" - if strings.Contains(opts.ResourceId, "microsoft.classiccompute/virtualmachines") { - metricnamespace = "microsoft.classiccompute/virtualmachines" - } - ret, err := self.getMetricValues(opts.ResourceId, metricnamespace, metricnames, nil, "", opts.StartTime, opts.EndTime) - if err != nil { - return nil, err - } - - for metricType, names := range map[cloudprovider.TMetricType][]string{ - cloudprovider.VM_METRIC_TYPE_MEM_USAGE: {"/builtin/memory/percentusedmemory", "\\Memory\\% Committed Bytes In Use"}, - cloudprovider.VM_METRIC_TYPE_DISK_USAGE: {"/builtin/filesystem/percentusedspace", "\\LogicalDisk(_Total)\\% Free Space"}, - } { - filters := []string{} - for _, name := range names { - filter := fmt.Sprintf("name.value eq '%s'", name) - filters = append(filters, filter) - } - metricDefinitions, err := self.getMetricDefinitions(opts.ResourceId, strings.Join(filters, " or ")) - if err != nil { - log.Errorf("getMetricDefinitions error: %v", err) - continue - } - metric := cloudprovider.MetricValues{} - metric.MetricType = metricType - header := http.Header{} - header.Set("accept", "application/json;odata=minimalmetadata") - for _, definition := range metricDefinitions.Value { - for _, tables := range definition.MetricAvailabilities { - if tables.TimeGrain != "PT1M" { - continue - } - for _, table := range tables.Location.TableInfo { - if table.EndTime.Before(opts.EndTime) { - continue - } - url := fmt.Sprintf("%s%s%s", tables.Location.TableEndpoint, table.TableName, table.SasToken) - _, resp, err := httputils.JSONRequest(httputils.GetDefaultClient(), context.Background(), httputils.GET, url, header, nil, self.debug) - if err != nil { - log.Errorf("request %s error: %v", url, err) - continue - } - values := &AzureTableMetricData{} - resp.Unmarshal(values) - for _, v := range values.Value { - name := strings.ReplaceAll(v.CounterName, `\\`, `\`) - if !utils.IsInStringArray(name, names) { - continue - } - if v.Timestamp.After(opts.StartTime) && v.Timestamp.Before(opts.EndTime) { - value := v.GetValue() - if metricType == cloudprovider.VM_METRIC_TYPE_DISK_USAGE && strings.Contains(strings.ToLower(name), "free") { - value = 100 - value - } - metric.Values = append(metric.Values, cloudprovider.MetricValue{ - Timestamp: v.Timestamp, - Value: value, - }) - } - } - } - } - } - if len(metric.Values) > 0 { - ret = append(ret, metric) - } - } - - if len(opts.OsType) == 0 || strings.Contains(strings.ToLower(opts.OsType), "win") { - workspaces, err := self.GetLoganalyticsWorkspaces() - if err != nil { - return ret, nil - } - winmetric := cloudprovider.MetricValues{} - winmetric.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_USAGE - winmetric.Values = []cloudprovider.MetricValue{} - for i := range workspaces { - data, err := self.GetInstanceDiskUsage(workspaces[i].SLoganalyticsWorkspaceProperties.CustomerId, opts.ResourceId, opts.StartTime, opts.EndTime) - if err != nil { - continue - } - for i := range data { - for j := range data[i].Rows { - if len(data[i].Rows[j]) == 5 { - date, device, free := data[i].Rows[j][0], data[i].Rows[j][1], data[i].Rows[j][2] - dataTime, err := timeutils.ParseTimeStr(date) - if err != nil { - continue - } - if dataTime.Second() > 15 { - continue - } - freeSize, err := strconv.ParseFloat(free, 64) - if err != nil { - continue - } - winmetric.Values = append(winmetric.Values, cloudprovider.MetricValue{ - Timestamp: dataTime, - Value: 100 - freeSize, - Tags: map[string]string{cloudprovider.METRIC_TAG_DEVICE: device}, - }) - } - } - } - } - if len(winmetric.Values) > 0 { - ret = append(ret, winmetric) - } - } - - return ret, nil -} - -func (self *SAzureClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricnamespace := "Microsoft.Cache/redis" - metricnames := "percentProcessorTime,usedmemorypercentage,connectedclients,operationsPerSecond,alltotalkeys,expiredkeys,usedmemory" - return self.getMetricValues(opts.ResourceId, metricnamespace, metricnames, nil, "", opts.StartTime, opts.EndTime) -} - -func (self *SAzureClient) GetLbMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricnamespace := "Microsoft.Network/loadBalancers" - metricnames := "SnatConnectionCount,UsedSnatPorts" - return self.getMetricValues(opts.ResourceId, metricnamespace, metricnames, nil, "", opts.StartTime, opts.EndTime) -} - -func (self *SAzureClient) GetK8sMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricnamespace := "Microsoft.ContainerService/managedClusters" - metricnames := "node_cpu_usage_percentage,node_memory_rss_percentage,node_disk_usage_percentage,node_network_in_bytes,node_network_out_bytes" - filter := fmt.Sprintf("node eq '*'") - return self.getMetricValues(opts.ResourceId, metricnamespace, metricnames, nil, filter, opts.StartTime, opts.EndTime) -} - -func (self *SAzureClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - metricnamespace, metricnames := "", "" - rdsType := RDS_TYPE_SERVERS - if strings.Contains(opts.ResourceId, strings.ToLower(RDS_TYPE_FLEXIBLE_SERVERS)) { - rdsType = RDS_TYPE_FLEXIBLE_SERVERS - } - switch opts.Engine { - case api.DBINSTANCE_TYPE_MYSQL: - metricnamespace = fmt.Sprintf("Microsoft.DBforMySQL/%s", rdsType) - metricnames = "cpu_percent,memory_percent,storage_percent,network_bytes_ingress,network_bytes_egress,io_consumption_percent,connections_failed,active_connections" - case api.DBINSTANCE_TYPE_MARIADB: - metricnamespace = "Microsoft.DBforMariaDB/servers" - metricnames = "cpu_percent,memory_percent,storage_percent,network_bytes_ingress,network_bytes_egress,io_consumption_percent,connections_failed,active_connections" - case api.DBINSTANCE_TYPE_SQLSERVER: - metricnamespace = "Microsoft.Sql/servers/databases" - metricnames = "cpu_percent,connection_successful,sqlserver_process_memory_percent,connection_successful,connection_failed" - result := struct { - Value []SSQLServerDatabase - }{} - err := self.get(opts.ResourceId+"/databases", url.Values{}, &result) - if err != nil { - return nil, err - } - for i := range result.Value { - if result.Value[i].Name == "master" { - continue - } - metrics, err := self.getMetricValues(result.Value[i].ID, metricnamespace, metricnames, map[string]string{cloudprovider.METRIC_TAG_DATABASE: result.Value[i].Name}, "", opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("error: %v", err) - continue - } - for j := range metrics { - metrics[j].Id = opts.ResourceId - ret = append(ret, metrics[j]) - } - } - return ret, nil - case api.DBINSTANCE_TYPE_POSTGRESQL: - metricnamespace = fmt.Sprintf("Microsoft.DBforPostgreSQL/%s", rdsType) - metricnames = "cpu_percent,memory_percent,storage_percent,network_bytes_ingress,network_bytes_egress,io_consumption_percent,connections_failed,active_connections" - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, opts.Engine) - } - return self.getMetricValues(opts.ResourceId, metricnamespace, metricnames, nil, "", opts.StartTime, opts.EndTime) -} - -type MetrifDefinitions struct { - Id string - Value []MetrifDefinition -} - -type MetrifDefinition struct { - Name struct { - Value string - LocalizedValue string - } - Category string - Unit string - PrimaryAggregationType string - ResourceUri string - ResourceId string - MetricAvailabilities []struct { - TimeGrain string - Retention string - Location struct { - TableEndpoint string - TableInfo []struct { - TableName string - StartTime time.Time - EndTime time.Time - SasToken string - SasTokenExpirationTime string - } - PartitionKey string - } - } - Id string -} - -func (self *SAzureClient) getMetricDefinitions(resourceId, filter string) (*MetrifDefinitions, error) { - params := url.Values{} - params.Set("api-version", "2015-07-01") - resource := fmt.Sprintf("%s/providers/microsoft.insights/metricDefinitions", resourceId) - if len(filter) > 0 { - params.Set("$filter", filter) - } - result := &MetrifDefinitions{} - err := self.get(resource, params, &result) - if err != nil { - return nil, err - } - return result, nil -} - -func (self *SAzureClient) getMetricValues(resourceId, metricnamespace, metricnames string, metricTag map[string]string, filter string, startTime, endTime time.Time) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - params := url.Values{} - params.Set("interval", "PT1M") - params.Set("api-version", "2018-01-01") - params.Set("timespan", startTime.UTC().Format(time.RFC3339)+"/"+endTime.UTC().Format(time.RFC3339)) - resource := fmt.Sprintf("%s/providers/microsoft.insights/metrics", resourceId) - params.Set("aggregation", "Average,Count,Maximum,Total") - params.Set("metricnamespace", metricnamespace) - params.Set("metricnames", metricnames) - if len(filter) > 0 { - params.Set("$filter", filter) - } - elements := ResponseMetirc{} - err := self.get(resource, params, &elements) - if err != nil { - return ret, err - } - for i := range elements.Value { - element := elements.Value[i] - metric := cloudprovider.MetricValues{ - Unit: element.Unit, - } - switch element.Name.Value { - case "cpu_percent": - metric.MetricType = cloudprovider.RDS_METRIC_TYPE_CPU_USAGE - case "memory_percent", "sqlserver_process_memory_percent": - metric.MetricType = cloudprovider.RDS_METRIC_TYPE_MEM_USAGE - case "storage_percent": - metric.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_USAGE - case "network_bytes_ingress": - metric.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX - case "network_bytes_egress": - metric.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX - case "io_consumption_percent": - metric.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_IO_PERCENT - case "connections_failed", "connection_failed": - metric.MetricType = cloudprovider.RDS_METRIC_TYPE_CONN_FAILED - case "active_connections", "connection_successful": - metric.MetricType = cloudprovider.RDS_METRIC_TYPE_CONN_ACTIVE - case "Percentage CPU": - metric.MetricType = cloudprovider.VM_METRIC_TYPE_CPU_USAGE - case "Network In Total": - metric.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_RX - case "Network Out Total": - metric.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_TX - case "Disk Read Bytes": - metric.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS - case "Disk Write Bytes": - metric.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS - case "Disk Read Operations/Sec": - metric.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS - case "Disk Write Operations/Sec": - metric.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS - case "percentProcessorTime": - metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE - case "usedmemorypercentage": - metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE - case "connectedclients": - metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_USED_CONN - case "operationsPerSecond": - metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_OPT_SES - case "alltotalkeys": - metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS - case "expiredkeys": - metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS - case "usedmemory": - metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE - case "SnatConnectionCount": - metric.MetricType = cloudprovider.LB_METRIC_TYPE_SNAT_PORT - case "UsedSnatPorts": - metric.MetricType = cloudprovider.LB_METRIC_TYPE_SNAT_CONN_COUNT - case "node_cpu_usage_percentage": - metric.MetricType = cloudprovider.K8S_NODE_METRIC_TYPE_CPU_USAGE - case "node_memory_rss_percentage": - metric.MetricType = cloudprovider.K8S_NODE_METRIC_TYPE_MEM_USAGE - case "node_disk_usage_percentage": - metric.MetricType = cloudprovider.K8S_NODE_METRIC_TYPE_DISK_USAGE - case "node_network_in_bytes": - metric.MetricType = cloudprovider.K8S_NODE_METRIC_TYPE_NET_BPS_RX - case "node_network_out_bytes": - metric.MetricType = cloudprovider.K8S_NODE_METRIC_TYPE_NET_BPS_TX - default: - log.Warningf("incognizance metric type %s", element.Name.Value) - continue - } - for _, timeserie := range element.Timeseries { - tags := map[string]string{} - for _, metadata := range timeserie.Metadatavalues { - if metadata.Name.Value == "node" { //k8s node - tags[cloudprovider.METRIC_TAG_NODE] = metadata.Value - } - } - for k, v := range metricTag { - tags[k] = v - } - for _, data := range timeserie.Data { - metric.Values = append(metric.Values, cloudprovider.MetricValue{ - Timestamp: data.TimeStamp, - Value: data.GetValue(), - Tags: tags, - }) - } - } - ret = append(ret, metric) - } - return ret, nil -} diff --git a/pkg/multicloud/azure/network.go b/pkg/multicloud/azure/network.go deleted file mode 100644 index 343390f933..0000000000 --- a/pkg/multicloud/azure/network.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.AzureTags - wire *SWire - - //AvailableIpAddressCount int `json:"availableIpAddressCount,omitempty"` - ID string - Name string - Properties SubnetPropertiesFormat - AddressPrefix string `json:"addressPrefix,omitempty"` -} - -func (self *SNetwork) GetTags() (map[string]string, error) { - return self.Tags, nil -} - -func (self *SNetwork) GetId() string { - return self.ID -} - -func (self *SNetwork) GetName() string { - return self.Name -} - -func (self *SNetwork) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SNetwork) GetStatus() string { - return api.NETWORK_STATUS_AVAILABLE -} - -func (self *SNetwork) Delete() error { - return self.wire.vpc.region.del(self.ID) -} - -func (self *SNetwork) GetGateway() string { - pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) - endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 - endIp = endIp.StepDown() // 254 - return endIp.String() -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetIpEnd() string { - pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) - endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 - endIp = endIp.StepDown() // 254 - return endIp.String() -} - -func (self *SNetwork) GetIpMask() int8 { - pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) - return pref.MaskLen -} - -// https://docs.microsoft.com/en-us/azure/virtual-network/virtual-networks-faq -func (self *SNetwork) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - startIp = startIp.StepUp() // 2 - startIp = startIp.StepUp() // 3 - startIp = startIp.StepUp() // 4 - return startIp.String() -} - -func (self *SNetwork) GetIsPublic() bool { - return true -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) Refresh() error { - network, err := self.wire.zone.region.GetNetwork(self.ID) - if err != nil { - return err - } - return jsonutils.Update(self, network) -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (self *SNetwork) GetProjectId() string { - return getResourceGroup(self.ID) -} diff --git a/pkg/multicloud/azure/progress/doc.go b/pkg/multicloud/azure/progress/doc.go deleted file mode 100644 index 5d94baf1ad..0000000000 --- a/pkg/multicloud/azure/progress/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 progress // import "yunion.io/x/onecloud/pkg/multicloud/azure/progress" diff --git a/pkg/multicloud/azure/provider/doc.go b/pkg/multicloud/azure/provider/doc.go deleted file mode 100644 index c6b1e2bff4..0000000000 --- a/pkg/multicloud/azure/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/azure/provider" diff --git a/pkg/multicloud/azure/provider/provider.go b/pkg/multicloud/azure/provider/provider.go deleted file mode 100644 index b60d52a793..0000000000 --- a/pkg/multicloud/azure/provider/provider.go +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/azure" -) - -type SAzureProviderFactory struct { - cloudprovider.SPublicCloudBaseProviderFactory -} - -func (self *SAzureProviderFactory) GetId() string { - return azure.CLOUD_PROVIDER_AZURE -} - -func (self *SAzureProviderFactory) GetName() string { - return azure.CLOUD_PROVIDER_AZURE_CN -} - -func (self *SAzureProviderFactory) GetMaxCloudEventKeepDays() int { - return 90 -} - -func (self *SAzureProviderFactory) GetMaxCloudEventSyncDays() int { - return 7 -} - -func (self *SAzureProviderFactory) IsCloudeventRegional() bool { - return false -} - -func (self *SAzureProviderFactory) IsSupportSAMLAuth() bool { - return true -} - -func (self *SAzureProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { - return fmt.Errorf("Changing %s bandwidth is not supported", azure.CLOUD_PROVIDER_AZURE) -} - -func (self *SAzureProviderFactory) IsSupportPrepaidResources() bool { - return false -} - -func (self *SAzureProviderFactory) IsSupportCloudIdService() bool { - return true -} - -func (self *SAzureProviderFactory) IsSupportCreateCloudgroup() bool { - return true -} - -func (self *SAzureProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.DirectoryId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "directory_id") - } - if len(input.ClientId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "client_id") - } - if len(input.ClientSecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "client_secret") - } - if len(input.Environment) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "environment") - } - output.Account = input.DirectoryId - output.Secret = fmt.Sprintf("%s/%s", input.ClientId, input.ClientSecret) - output.AccessUrl = input.Environment - return output, nil -} - -func (self *SAzureProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.ClientId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "client_id") - } - if len(input.ClientSecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "client_secret") - } - output = cloudprovider.SCloudaccount{ - Account: cloudaccount, - Secret: fmt.Sprintf("%s/%s", input.ClientId, input.ClientSecret), - } - return output, nil -} - -func parseAccount(account, secret string) (tenantId string, appId string, appKey string, subId string) { - clientInfo := strings.Split(secret, "/") - accountInfo := strings.Split(account, "/") - tenantId = accountInfo[0] - if len(accountInfo) > 1 { - subId = strings.Join(accountInfo[1:], "/") - } - appId = clientInfo[0] - if len(clientInfo) > 1 { - appKey = strings.Join(clientInfo[1:], "/") - } - return -} - -func (self *SAzureProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - tenantId, appId, appKey, subId := parseAccount(cfg.Account, cfg.Secret) - if client, err := azure.NewAzureClient( - azure.NewAzureClientConfig( - cfg.URL, tenantId, appId, appKey, - ).SubscriptionId(subId).CloudproviderConfig(cfg), - ); err != nil { - return nil, err - } else { - return &SAzureProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil - } -} - -func (self *SAzureProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - tenantId, appId, appKey, subId := parseAccount(info.Account, info.Secret) - defaultRegion := "" - switch info.Url { - case "AzurePublicCloud": - defaultRegion = "eastus" - case "AzureChinaCloud": - defaultRegion = "chinaeast2" - } - return map[string]string{ - "AZURE_DIRECTORY_ID": tenantId, - "AZURE_SUBSCRIPTION_ID": subId, - "AZURE_APPLICATION_ID": appId, - "AZURE_APPLICATION_KEY": appKey, - "AZURE_REGION_ID": defaultRegion, - "AZURE_CLOUD_ENV": info.Url, - }, nil -} - -func init() { - factory := SAzureProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SAzureProvider struct { - cloudprovider.SBaseProvider - client *azure.SAzureClient -} - -func (self *SAzureProvider) GetSysInfo() (jsonutils.JSONObject, error) { - regions := self.client.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") - info.Add(jsonutils.NewString(azure.AZURE_API_VERSION), "api_version") - return info, nil -} - -func (self *SAzureProvider) GetVersion() string { - return azure.AZURE_API_VERSION -} - -func (self *SAzureProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SAzureProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SAzureProvider) GetIamLoginUrl() string { - return self.client.GetIamLoginUrl() -} - -func (self *SAzureProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SAzureProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(id) -} - -func (self *SAzureProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SAzureProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SAzureProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return self.client.CreateIProject(name) -} - -func (self *SAzureProvider) GetStorageClasses(regionId string) []string { - sc, err := self.client.GetStorageClasses(regionId) - if err != nil { - log.Errorf("Fail to find storage classes: %s", err) - return nil - } - return sc -} - -func (self *SAzureProvider) GetBucketCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLPublicRead), - } -} - -func (self *SAzureProvider) GetObjectCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLPublicRead), - } -} - -func (self *SAzureProvider) GetCloudRegionExternalIdPrefix() string { - return self.client.GetAccessEnv() + "/" -} - -func (self *SAzureProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SAzureProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - return self.client.CreateIClouduser(conf) -} - -func (self *SAzureProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { - return self.client.GetICloudusers() -} - -func (self *SAzureProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.client.GetIClouduserByName(name) -} - -func (self *SAzureProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroups() -} - -func (self *SAzureProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - return self.client.CreateICloudgroup(name, desc) -} - -func (self *SAzureProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroupByName(name) -} - -func (self *SAzureProvider) GetEnrollmentAccounts() ([]cloudprovider.SEnrollmentAccount, error) { - return self.client.GetEnrollmentAccounts() -} - -func (self *SAzureProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetISystemCloudpolicies() -} - -func (self *SAzureProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetICustomCloudpolicies() -} - -func (self *SAzureProvider) CreateSubscription(input cloudprovider.SubscriptionCreateInput) error { - return self.client.CreateSubscription(input.Name, input.EnrollmentAccountId, input.OfferType) -} - -// fake func -func (self *SAzureProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { - return self.client.CreateSAMLProvider(opts) -} - -func (self *SAzureProvider) GetSamlEntityId() string { - return cloudprovider.SAML_ENTITY_ID_AZURE -} - -func (self *SAzureProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/azure/rds_sqlserver.go b/pkg/multicloud/azure/rds_sqlserver.go deleted file mode 100644 index 0fdaa43737..0000000000 --- a/pkg/multicloud/azure/rds_sqlserver.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SPrivateendpointconnection struct { - ID string `json:"id"` - Properties struct { - Provisioningstate string `json:"provisioningState"` - Privateendpoint struct { - ID string `json:"id"` - } `json:"privateEndpoint"` - Privatelinkserviceconnectionstate struct { - Status string `json:"status"` - Description string `json:"description"` - Actionsrequired string `json:"actionsRequired"` - } `json:"privateLinkServiceConnectionState"` - } `json:"properties"` -} - -type SSQLServer struct { - region *SRegion - multicloud.SDBInstanceBase - multicloud.AzureTags - - dbs []SSQLServerDatabase - - Kind string `json:"kind"` - Properties struct { - Administratorlogin string `json:"administratorLogin"` - Version string `json:"version"` - State string `json:"state"` - Fullyqualifieddomainname string `json:"fullyQualifiedDomainName"` - Privateendpointconnections []SPrivateendpointconnection `json:"privateEndpointConnections"` - Publicnetworkaccess string `json:"publicNetworkAccess"` - } `json:"properties"` - Location string `json:"location"` - ID string `json:"id"` - Name string `json:"name"` - Type string `json:"type"` -} - -func (self *SRegion) ListSQLServer() ([]SSQLServer, error) { - rds := []SSQLServer{} - err := self.list("Microsoft.Sql/servers", url.Values{}, &rds) - if err != nil { - return nil, errors.Wrapf(err, "list") - } - return rds, nil -} - -func (self *SRegion) GetSQLServer(id string) (*SSQLServer, error) { - rds := &SSQLServer{region: self} - return rds, self.get(id, url.Values{}, rds) -} - -func (self *SSQLServer) GetDiskSizeGB() int { - dbs, err := self.fetchDatabase() - if err != nil { - return 0 - } - sizeMb := 0 - for _, db := range dbs { - sizeMb += db.GetDiskSizeMb() - } - return sizeMb / 1024 -} - -func (self *SSQLServer) GetEngine() string { - return api.DBINSTANCE_TYPE_SQLSERVER -} - -func (self *SSQLServer) GetEngineVersion() string { - return self.Properties.Version -} - -func (self *SSQLServer) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SSQLServer) GetProjectId() string { - return getResourceGroup(self.ID) -} - -func (self *SSQLServer) GetCategory() string { - return api.AZURE_DBINSTANCE_CATEGORY_BASIC -} - -func (self *SSQLServer) GetIVpcId() string { - return "" -} - -func (self *SSQLServer) GetId() string { - return self.ID -} - -func (self *SSQLServer) GetInstanceType() string { - return "" -} - -func (self *SSQLServer) GetMaintainTime() string { - return "" -} - -func (self *SSQLServer) GetName() string { - return self.Name -} - -func (self *SSQLServer) GetPort() int { - return 1433 -} - -func (self *SSQLServer) GetStatus() string { - switch self.Properties.State { - case "Ready": - return api.DBINSTANCE_RUNNING - default: - return self.Properties.State - } -} - -func (self *SSQLServer) GetStorageType() string { - return api.AZURE_DBINSTANCE_STORAGE_TYPE_DEFAULT -} - -func (self *SSQLServer) fetchDatabase() ([]SSQLServerDatabase, error) { - if len(self.dbs) > 0 { - return self.dbs, nil - } - var err error - self.dbs, err = self.region.GetSQLServerDatabases(self.ID) - return self.dbs, err -} - -func (self *SSQLServer) GetVcpuCount() int { - dbs, err := self.fetchDatabase() - if err != nil { - return 0 - } - vcpu := 0 - for _, db := range dbs { - vcpu += db.GetVcpuCount() - } - return vcpu -} - -func (self *SSQLServer) GetVmemSizeMB() int { - dbs, err := self.fetchDatabase() - if err != nil { - return 0 - } - mem := 0 - for _, db := range dbs { - mem += db.GetVmemSizeMb() - } - return mem -} - -func (self *SSQLServer) GetSysTags() map[string]string { - dtu := self.GetDTU() - if dtu > 0 { - return map[string]string{"DTU": fmt.Sprintf("%d", dtu)} - } - return nil -} - -func (self *SSQLServer) GetDTU() int { - dbs, err := self.fetchDatabase() - if err != nil { - return 0 - } - dtu := 0 - for _, db := range dbs { - dtu += db.GetDTU() - } - return dtu -} - -func (self *SSQLServer) GetZone1Id() string { - return "" -} - -func (self *SSQLServer) GetZone2Id() string { - return "" -} - -func (self *SSQLServer) GetZone3Id() string { - return "" -} - -func (self *SSQLServer) GetConnectionStr() string { - return self.Properties.Fullyqualifieddomainname -} diff --git a/pkg/multicloud/azure/redis.go b/pkg/multicloud/azure/redis.go deleted file mode 100644 index 53673b2b07..0000000000 --- a/pkg/multicloud/azure/redis.go +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRedisCache struct { - multicloud.SElasticcacheBase - multicloud.AzureTags - - region *SRegion - ID string `json:"id"` - Location string `json:"location"` - Name string `json:"name"` - Type string `json:"type"` - Properties struct { - Provisioningstate string `json:"provisioningState"` - Redisversion string `json:"redisVersion"` - Sku struct { - Name string `json:"name"` - Family string `json:"family"` - Capacity int `json:"capacity"` - } `json:"sku"` - Enablenonsslport bool `json:"enableNonSslPort"` - Instances []struct { - Sslport int `json:"sslPort"` - Shardid int `json:"shardId"` - Ismaster bool `json:"isMaster"` - } `json:"instances"` - Publicnetworkaccess string `json:"publicNetworkAccess"` - Redisconfiguration struct { - Maxclients string `json:"maxclients"` - MaxmemoryReserved string `json:"maxmemory-reserved"` - MaxfragmentationmemoryReserved string `json:"maxfragmentationmemory-reserved"` - MaxmemoryDelta string `json:"maxmemory-delta"` - } `json:"redisConfiguration"` - Accesskeys interface{} `json:"accessKeys"` - Hostname string `json:"hostName"` - Port int `json:"port"` - Sslport int `json:"sslPort"` - Shardcount int `json:"shardCount"` - SubnetId string `json:"subnetId"` - StaticIP string `json:"staticIP"` - Linkedservers []interface{} `json:"linkedServers"` - } `json:"properties"` -} - -func (self *SRegion) GetRedisCache(id string) (*SRedisCache, error) { - cache := &SRedisCache{region: self} - return cache, self.get(id, url.Values{}, cache) -} - -func (self *SRegion) GetRedisCaches() ([]SRedisCache, error) { - redis := []SRedisCache{} - err := self.list("Microsoft.Cache/redis", url.Values{}, &redis) - if err != nil { - return nil, errors.Wrapf(err, "list") - } - return redis, nil -} - -func (self *SRedisCache) GetId() string { - return self.ID -} - -func (self *SRedisCache) GetName() string { - return self.Name -} - -func (self *SRedisCache) GetProjectId() string { - return getResourceGroup(self.ID) -} - -func (self *SRedisCache) GetStatus() string { - switch self.Properties.Provisioningstate { - case "Creating": - return api.ELASTIC_CACHE_STATUS_DEPLOYING - case "Deleting": - return api.ELASTIC_CACHE_STATUS_DELETING - case "Disabled": - return api.ELASTIC_CACHE_STATUS_INACTIVE - case "Failed": - return api.ELASTIC_CACHE_STATUS_CREATE_FAILED - case "Linking": - return api.ELASTIC_CACHE_STATUS_RUNNING - case "Provisioning": - return api.ELASTIC_CACHE_STATUS_RUNNING - case "RecoveringScaleFailure": - return api.ELASTIC_CACHE_STATUS_CHANGE_FAILED - case "Scaling": - return api.ELASTIC_CACHE_STATUS_CHANGING - case "Succeeded": - return api.ELASTIC_CACHE_STATUS_RUNNING - case "Unlinking": - return api.ELASTIC_CACHE_STATUS_RUNNING - case "Unprovisioning": - return api.ELASTIC_CACHE_STATUS_RUNNING - case "Updating": - return api.ELASTIC_CACHE_STATUS_RUNNING - default: - return strings.ToLower(self.Properties.Provisioningstate) - } -} - -func (self *SRedisCache) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SRedisCache) GetInstanceType() string { - return self.Properties.Sku.Name -} - -func (self *SRedisCache) GetCapacityMB() int { - switch self.Properties.Sku.Family { - case "P": - switch self.Properties.Sku.Capacity { - case 1: - return 6 * 1024 - case 2: - return 13 * 1024 - case 3: - return 26 * 1024 - case 4: - return 53 * 1024 - case 5: - return 120 * 1024 - } - case "C": - switch self.Properties.Sku.Capacity { - case 0: - return 250 - case 1: - return 1024 - case 2: - return 2.5 * 1024 - case 3: - return 6 * 1024 - case 4: - return 13 * 1024 - case 5: - return 26 * 1024 - case 6: - return 53 * 1024 - } - } - return 0 -} - -func (self *SRedisCache) GetArchType() string { - if self.Properties.Sku.Family == "P" { - return api.ELASTIC_CACHE_ARCH_TYPE_MASTER - } - return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE -} - -func (self *SRedisCache) GetNodeType() string { - switch len(self.Properties.Instances) { - case 1: - return api.ELASTIC_CACHE_NODE_TYPE_SINGLE - case 2: - return api.ELASTIC_CACHE_NODE_TYPE_DOUBLE - case 3: - return api.ELASTIC_CACHE_NODE_TYPE_THREE - case 4: - return api.ELASTIC_CACHE_NODE_TYPE_FOUR - case 5: - return api.ELASTIC_CACHE_NODE_TYPE_FIVE - case 6: - return api.ELASTIC_CACHE_NODE_TYPE_SIX - } - return fmt.Sprintf("%d", self.Properties.Shardcount) -} - -func (self *SRedisCache) GetEngine() string { - return "Redis" -} - -func (self *SRedisCache) GetEngineVersion() string { - return self.Properties.Redisversion -} - -func (self *SRedisCache) GetVpcId() string { - if len(self.Properties.SubnetId) > 0 { - info := strings.Split(self.Properties.SubnetId, "/") - if len(info) > 2 { - return strings.Join(info[:len(info)-2], "/") - } - } - return "" -} - -func (self *SRedisCache) GetZoneId() string { - return self.region.getZone().GetGlobalId() -} - -func (self *SRedisCache) GetNetworkType() string { - if len(self.Properties.SubnetId) > 0 { - return api.LB_NETWORK_TYPE_VPC - } - return api.LB_NETWORK_TYPE_CLASSIC -} - -func (self *SRedisCache) GetNetworkId() string { - return strings.ToLower(self.Properties.SubnetId) -} - -func (self *SRedisCache) GetPrivateDNS() string { - return "" -} - -func (self *SRedisCache) GetPrivateIpAddr() string { - return self.Properties.StaticIP -} - -func (self *SRedisCache) GetPrivateConnectPort() int { - return self.Properties.Port -} - -func (self *SRedisCache) GetPublicDNS() string { - return self.Properties.Hostname -} - -func (self *SRedisCache) GetPublicIpAddr() string { - return "" -} - -func (self *SRedisCache) GetPublicConnectPort() int { - return self.Properties.Sslport -} - -func (self *SRedisCache) GetMaintainStartTime() string { - return "" -} - -func (self *SRedisCache) GetMaintainEndTime() string { - return "" -} - -func (self *SRedisCache) AllocatePublicConnection(port int) (string, error) { - return "", errors.Wrapf(cloudprovider.ErrNotImplemented, "AllocatePublicConnection") -} - -func (self *SRedisCache) ChangeInstanceSpec(spec string) error { - return errors.Wrapf(cloudprovider.ErrNotImplemented, "ChangeInstanceSpec") -} - -func (self *SRedisCache) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "CreateAccount") -} - -func (self *SRedisCache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "CreateAcl") -} - -func (self *SRedisCache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "CreateBackup") -} - -func (self *SRedisCache) Delete() error { - return self.region.Delete(self.ID) -} - -func (self *SRedisCache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { - return errors.Wrapf(cloudprovider.ErrNotSupported, "FlushInstance") -} - -func (self *SRedisCache) GetAuthMode() string { - return "on" -} - -func (self *SRedisCache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetICloudElasticcacheAccounts") -} - -func (self *SRedisCache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { - acls, err := self.region.GetRedisAcls(self.ID) - if err != nil { - return nil, errors.Wrapf(err, "GetRedisAcls") - } - ret := []cloudprovider.ICloudElasticcacheAcl{} - for i := range acls { - acls[i].redis = self - ret = append(ret, &acls[i]) - } - return ret, nil -} - -func (self *SRedisCache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { - acl, err := self.region.GetRedisAcl(aclId) - if err != nil { - return nil, errors.Wrapf(err, "GetRedisAcl") - } - acl.redis = self - return acl, nil -} - -func (self *SRedisCache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { - return []cloudprovider.ICloudElasticcacheBackup{}, nil -} - -func (self *SRedisCache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { - return []cloudprovider.ICloudElasticcacheParameter{}, nil -} - -func (self *SRedisCache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SRedisCache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SRedisCache) GetSecurityGroupIds() ([]string, error) { - return []string{}, nil -} - -func (self *SRedisCache) ReleasePublicConnection() error { - return cloudprovider.ErrNotSupported -} - -func (self *SRedisCache) Restart() error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRedisCache) SetMaintainTime(start, end string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRedisCache) UpdateAuthMode(noPasswordAccess bool, password string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRedisCache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRedisCache) UpdateInstanceParameters(config jsonutils.JSONObject) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRedisCache) UpdateSecurityGroups(secgroupIds []string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { - redis, err := self.GetRedisCaches() - if err != nil { - return nil, errors.Wrapf(err, "GetRedisCaches") - } - ret := []cloudprovider.ICloudElasticcache{} - for i := range redis { - redis[i].region = self - ret = append(ret, &redis[i]) - } - switch self.client.GetAccessEnv() { - // 国际区才有企业版 - case api.CLOUD_ACCESS_ENV_AZURE_GLOBAL: - enterpriseRedis, err := self.GetEnterpriseRedisCaches() - if err != nil { - return nil, errors.Wrapf(err, "GetEnterpriseRedisCaches") - } - for i := range enterpriseRedis { - enterpriseRedis[i].region = self - ret = append(ret, &enterpriseRedis[i]) - } - } - return ret, nil -} - -func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { - id = strings.ToLower(id) - if strings.Index(id, "microsoft.cache/redis") > 0 { - return self.GetRedisCache(id) - } else if strings.Index(id, "Microsoft.Cache/redisEnterprise") > 0 { - return self.GetEnterpriseRedisCache(id) - } else { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) - } -} diff --git a/pkg/multicloud/azure/region.go b/pkg/multicloud/azure/region.go deleted file mode 100644 index 8e68f2f4c8..0000000000 --- a/pkg/multicloud/azure/region.go +++ /dev/null @@ -1,731 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strconv" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVMSize struct { - //MaxDataDiskCount int32 `json:"maxDataDiskCount,omitempty"` //Unmarshal会出错 - MemoryInMB int32 `json:"memoryInMB,omitempty"` - NumberOfCores int `json:"numberOfCores,omitempty"` - Name string - OsDiskSizeInMB int32 `json:"osDiskSizeInMB,omitempty"` - ResourceDiskSizeInMB int32 `json:"resourceDiskSizeInMB,omitempty"` -} - -type SRegion struct { - multicloud.SRegion - client *SAzureClient - - storageCache *SStoragecache - appServicePlans map[string]*SAppServicePlan - - ID string - Name string - DisplayName string - Latitude string - Longitude string -} - -func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotImplemented -} - -///////////////////////////////////////////////////////////////////////////// -func (self *SRegion) Refresh() error { - // do nothing - return nil -} - -func (self *SRegion) GetClient() *SAzureClient { - return self.client -} - -func (self *SRegion) ListVmSizes() ([]SVMSize, error) { - result := []SVMSize{} - resource := fmt.Sprintf("Microsoft.Compute/locations/%s/vmSizes", self.Name) - return result, self.client.list(resource, url.Values{}, &result) -} - -func (self *SRegion) getHardwareProfile(cpu, memMB int) []string { - vmSizes, err := self.ListVmSizes() - if err != nil { - return []string{} - } - result := []string{} - for i := range vmSizes { - if vmSizes[i].MemoryInMB == int32(memMB) && vmSizes[i].NumberOfCores == cpu { - result = append(result, vmSizes[i].Name) - } - } - return result -} - -func (self *SRegion) getVMSize(name string) (*SVMSize, error) { - vmSizes, err := self.ListVmSizes() - if err != nil { - return nil, errors.Wrapf(err, "ListVmSizes") - } - for i := range vmSizes { - if vmSizes[i].Name == name { - return &vmSizes[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) -} - -func (self *SRegion) GetId() string { - return self.Name -} - -func (self *SRegion) GetName() string { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AZURE_CN, self.DisplayName) -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_AZURE_EN, self.DisplayName) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.Name) -} - -func (self *SRegion) IsEmulated() bool { - return false -} - -func (self *SRegion) GetProvider() string { - return CLOUD_PROVIDER_AZURE -} - -func (self *SRegion) GetCloudEnv() string { - return self.client.envName -} - -func (self *SRegion) trimGeographicString(geographic string) string { - return strings.TrimFunc(geographic, func(r rune) bool { - return !((r >= '0' && r <= '9') || r == '.' || r == '-') - }) -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - info := cloudprovider.SGeographicInfo{} - if geographicInfo, ok := AzureGeographicInfo[self.Name]; ok { - info = geographicInfo - } - - self.Latitude = self.trimGeographicString(self.Latitude) - self.Longitude = self.trimGeographicString(self.Longitude) - - latitude, err := strconv.ParseFloat(self.Latitude, 32) - if err != nil { - log.Errorf("Parse azure region %s latitude %s error: %v", self.Name, self.Latitude, err) - } else { - info.Latitude = float32(latitude) - } - - longitude, err := strconv.ParseFloat(self.Longitude, 32) - if err != nil { - log.Errorf("Parse azure region %s longitude %s error: %v", self.Name, self.Longitude, err) - } else { - info.Longitude = float32(longitude) - } - return info -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - vpc := SVpc{ - region: self, - Name: opts.NAME, - Location: self.Name, - Properties: VirtualNetworkPropertiesFormat{ - AddressSpace: AddressSpace{ - AddressPrefixes: []string{opts.CIDR}, - }, - }, - Type: "Microsoft.Network/virtualNetworks", - } - return &vpc, self.create("", jsonutils.Marshal(vpc), &vpc) -} - -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) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - return self.GetInstance(id) -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return self.GetDisk(id) -} - -func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - iHosts := make([]cloudprovider.ICloudHost, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneHost, err := izones[i].GetIHosts() - if err != nil { - return nil, err - } - iHosts = append(iHosts, iZoneHost...) - } - return iHosts, nil -} - -func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - if storageCache.GetGlobalId() == id { - return self.storageCache, 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 i := 0; i < len(ivpcs); i++ { - if ivpcs[i].GetGlobalId() == id { - return ivpcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - if izones, err := self.GetIZones(); err != nil { - return nil, err - } else { - for i := 0; i < len(izones); i += 1 { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) getZone() *SZone { - return &SZone{region: self, Name: self.Name} -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - return []cloudprovider.ICloudZone{self.getZone()}, nil -} - -func (self *SRegion) getStoragecache() *SStoragecache { - if self.storageCache == nil { - self.storageCache = &SStoragecache{region: self} - } - return self.storageCache -} - -func (self *SRegion) ListVpcs() ([]SVpc, error) { - result := []SVpc{} - err := self.list("Microsoft.Network/virtualNetworks", url.Values{}, &result) - if err != nil { - return nil, errors.Wrapf(err, "list") - } - return result, nil -} - -func (self *SRegion) ListClassicVpcs() ([]SClassicVpc, error) { - result := []SClassicVpc{} - err := self.list("Microsoft.ClassicNetwork/virtualNetworks", url.Values{}, &result) - if err != nil { - return nil, errors.Wrapf(err, "ListClassicVpcs") - } - return result, nil -} - -func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - vpcs, err := self.ListVpcs() - if err != nil { - return nil, errors.Wrapf(err, "ListVpcs") - } - classicVpcs, err := self.ListClassicVpcs() - if err != nil { - return nil, errors.Wrapf(err, "ListClassicVpcs") - } - ret := []cloudprovider.ICloudVpc{} - for i := range vpcs { - vpcs[i].region = self - ret = append(ret, &vpcs[i]) - } - for i := range classicVpcs { - classicVpcs[i].region = self - ret = append(ret, &classicVpcs[i]) - } - return ret, nil -} - -func (self *SRegion) CreateInstanceSimple(name string, imgId, osType string, cpu int, memMb int, sysDiskSizeGB int, storageType string, dataDiskSizesGB []int, nicId string, passwd string, publicKey string) (*SInstance, error) { - desc := &cloudprovider.SManagedVMCreateConfig{ - Name: name, - ExternalImageId: imgId, - SysDisk: cloudprovider.SDiskInfo{SizeGB: sysDiskSizeGB, StorageType: storageType}, - Cpu: cpu, - MemoryMB: memMb, - Password: passwd, - DataDisks: []cloudprovider.SDiskInfo{}, - PublicKey: publicKey, - OsType: osType, - } - if len(passwd) > 0 { - desc.Password = passwd - } - for _, sizeGB := range dataDiskSizesGB { - desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType}) - } - return self._createVM(desc, nicId) -} - -func (region *SRegion) GetEips() ([]SEipAddress, error) { - eips := []SEipAddress{} - err := region.client.list("Microsoft.Network/publicIPAddresses", url.Values{}, &eips) - if err != nil { - return nil, err - } - result := []SEipAddress{} - for i := 0; i < len(eips); i++ { - if eips[i].Location == region.Name { - eips[i].region = region - result = append(result, eips[i]) - } - } - return result, nil -} - -func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, err := region.GetEips() - if err != nil { - return nil, errors.Wrapf(err, "GetEips") - } - classicEips, err := region.GetClassicEips() - if err != nil { - return nil, errors.Wrapf(err, "GetClassicEips") - } - ieips := []cloudprovider.ICloudEIP{} - for i := 0; i < len(eips); i++ { - if len(eips[i].GetIpAddr()) == 0 { - continue - } - _, err := netutils.NewIPV4Addr(eips[i].GetIpAddr()) - if err != nil { - continue - } - eips[i].region = region - ieips = append(ieips, &eips[i]) - } - for i := 0; i < len(classicEips); i++ { - if len(classicEips[i].GetIpAddr()) == 0 { - continue - } - _, err := netutils.NewIPV4Addr(eips[i].GetIpAddr()) - if err != nil { - continue - } - classicEips[i].region = region - ieips = append(ieips, &classicEips[i]) - } - return ieips, nil -} - -func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - if strings.Contains(strings.ToLower(secgroupId), "microsoft.classicnetwork") { - return region.GetClassicSecurityGroupDetails(secgroupId) - } - return region.GetSecurityGroupDetails(secgroupId) -} - -func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - if strings.Contains(strings.ToLower(opts.VpcId), "microsoft.classicnetwork") { - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "not support classic secgroup") - } - resource := fmt.Sprintf("subscriptions/%s/resourcegroups/%s/providers/microsoft.network/networksecuritygroups/%s", region.client.subscriptionId, opts.ProjectId, opts.Name) - secgroup := &SSecurityGroup{region: region} - err := region.get(resource, url.Values{}, secgroup) - if err != nil { - return nil, errors.Wrapf(err, "get(%s)", resource) - } - return secgroup, nil -} - -func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - if conf.VpcId == "classic" { - return region.CreateClassicSecurityGroup(conf.Name) - } - return region.CreateSecurityGroup(conf.Name) -} - -func (region *SRegion) getIAppLBs() ([]cloudprovider.ICloudLoadbalancer, error) { - lbs := []SLoadbalancer{} - params := url.Values{} - params.Set("api-version", "2021-02-01") - err := region.list("Microsoft.Network/applicationGateways", params, &lbs) - if err != nil { - return nil, errors.Wrapf(err, "list") - } - - ilbs := make([]cloudprovider.ICloudLoadbalancer, len(lbs)) - for i := range lbs { - lbs[i].region = region - ilbs[i] = &lbs[i] - } - - return ilbs, nil -} - -func (region *SRegion) getINetworkLBs() ([]cloudprovider.ICloudLoadbalancer, error) { - lbs := []SLoadbalancer{} - params := url.Values{} - params.Set("api-version", "2021-02-01") - err := region.list("Microsoft.Network/loadBalancers", params, &lbs) - if err != nil { - return nil, errors.Wrapf(err, "list") - } - - ilbs := make([]cloudprovider.ICloudLoadbalancer, len(lbs)) - for i := range lbs { - lbs[i].region = region - ilbs[i] = &lbs[i] - } - - return ilbs, nil -} - -func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - appLbs, err := region.getIAppLBs() - if err != nil { - return nil, errors.Wrap(err, "GetIAppLBs") - } - - netLbs, err := region.getINetworkLBs() - if err != nil { - return nil, errors.Wrap(err, "GetINetworkLBs") - } - - lbs := []cloudprovider.ICloudLoadbalancer{} - lbs = append(lbs, appLbs...) - lbs = append(lbs, netLbs...) - return lbs, nil -} - -func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { - lb := SLoadbalancer{} - params := url.Values{} - params.Set("api-version", "2021-02-01") - err := region.get(loadbalancerId, params, &lb) - if err != nil { - return nil, errors.Wrapf(err, "get") - } - - lb.region = region - return &lb, nil -} - -func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, errors.Wrap(cloudprovider.ErrNotSupported, "GetILoadBalancerAclById") -} - -func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - segs := strings.Split(certId, "/sslCertificates") - if len(segs[0]) > 0 { - lb, err := region.GetILoadBalancerById(segs[0]) - if err != nil { - return nil, errors.Wrap(err, "GetILoadBalancerById") - } - - return lb.(*SLoadbalancer).GetILoadBalancerCertificateById(certId) - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerCertificateById") -} - -func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - lbs, err := region.GetILoadBalancers() - if err != nil { - return nil, errors.Wrap(err, "GetILoadBalancers") - } - - certs := []cloudprovider.ICloudLoadbalancerCertificate{} - for i := range lbs { - _certs, err := lbs[i].(*SLoadbalancer).GetILoadBalancerCertificates() - if err != nil { - return nil, errors.Wrap(err, "GetILoadBalancerCertificates") - } - certs = append(certs, _certs...) - } - - return certs, nil -} - -func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "CreateILoadBalancerCertificate") -} - -func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, errors.Wrap(cloudprovider.ErrNotSupported, "GetILoadBalancerAcls") -} - -func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "GetILoadBalancerCertificates") -} - -func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "CreateILoadBalancerAcl") -} - -func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - accounts, err := region.ListStorageAccounts() - if err != nil { - return nil, errors.Wrapf(err, "ListStorageAccounts") - } - ret := make([]cloudprovider.ICloudBucket, 0) - for i := range accounts { - ret = append(ret, &accounts[i]) - } - return ret, nil -} - -func (region *SRegion) CreateIBucket(name string, storageClassStr string, acl string) error { - _, err := region.createStorageAccount(name, storageClassStr) - if err != nil { - return errors.Wrapf(err, "region.createStorageAccount name=%s storageClass=%s acl=%s", name, storageClassStr, acl) - } - return nil -} - -func (region *SRegion) DeleteIBucket(name string) error { - accounts, err := region.listStorageAccounts() - if err != nil { - return errors.Wrap(err, "ListStorageAccounts") - } - for i := range accounts { - if accounts[i].Name == name { - err = region.del(accounts[i].ID) - if err != nil { - return errors.Wrapf(err, "region.del") - } - return nil - } - } - return nil -} - -func (region *SRegion) IBucketExist(name string) (bool, error) { - return region.checkStorageAccountNameExist(name) -} - -func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { - return cloudprovider.GetIBucketById(region, name) -} - -func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { - return region.GetIBucketById(name) -} - -func (region *SRegion) GetCapabilities() []string { - return region.client.GetCapabilities() -} - -func (self *SRegion) get(resource string, params url.Values, retVal interface{}) error { - return self.client.get(resource, params, retVal) -} - -func (self *SRegion) Show(resource string) (jsonutils.JSONObject, error) { - ret := jsonutils.NewDict() - err := self.get(resource, url.Values{}, ret) - if err != nil { - return nil, err - } - return ret, nil -} - -func (self *SRegion) del(resource string) error { - return self.client.del(resource) -} - -func (self *SRegion) Delete(resource string) error { - return self.del(resource) -} - -func (self *SRegion) checkResourceGroup(resourceGroup string) (string, error) { - if len(resourceGroup) == 0 { - resourceGroup = "Default" - } - resourceGroups, err := self.client.ListResourceGroups() - if err != nil { - return "", errors.Wrapf(err, "ListResourceGroups") - } - - for i := range resourceGroups { - proj := resourceGroups[i] - if strings.ToLower(proj.GetName()) == strings.ToLower(resourceGroup) || - proj.GetGlobalId() == resourceGroup || - (strings.Contains(resourceGroup, "/") && strings.HasSuffix(proj.GetGlobalId(), resourceGroup)) { - return resourceGroup, nil - } - } - _, err = self.CreateResourceGroup(resourceGroup) - return resourceGroup, err -} - -type sInfo struct { - Location string `json:"Location"` - Name string `json:"Name"` - Type string `json:"Type"` -} - -func (self *SRegion) createInfo(body jsonutils.JSONObject) (sInfo, error) { - info := sInfo{} - err := body.Unmarshal(&info) - if err != nil { - return info, errors.Wrapf(err, "body.Unmarshal") - } - if len(info.Name) == 0 { - return info, fmt.Errorf("Missing name params") - } - if len(info.Type) == 0 { - return info, fmt.Errorf("Missing type params") - } - return info, nil -} - -func (self *SRegion) create(resourceGroup string, _body jsonutils.JSONObject, retVal interface{}) error { - body := _body.(*jsonutils.JSONDict) - info, err := self.createInfo(_body) - if err != nil { - return errors.Wrapf(err, "createInfo") - } - resourceGroup, err = self.checkResourceGroup(resourceGroup) - if err != nil { - return errors.Wrapf(err, "checkResourceGroup(%s)", resourceGroup) - } - info.Name, err = self.client.getUniqName(resourceGroup, info.Type, info.Name) - if err != nil { - return errors.Wrapf(err, "getUniqName") - } - info.Location = self.Name - body.Update(jsonutils.Marshal(info)) - body.Remove("location") - body.Remove("name") - body.Remove("type") - return self.client.create(resourceGroup, info.Type, info.Name, body, retVal) -} - -func (self *SRegion) update(body jsonutils.JSONObject, retVal interface{}) error { - return self.client.update(body, retVal) -} - -func (self *SRegion) perform(id, action string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.client.perform(id, action, body) -} - -func (self *SRegion) put(resource string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.client.put(resource, body) -} - -func (self *SRegion) patch(resource string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.client.patch(resource, body) -} - -func (self *SRegion) list(resource string, params url.Values, retVal interface{}) error { - result := []jsonutils.JSONObject{} - err := self.client.list(resource, params, &result) - if err != nil { - return errors.Wrapf(err, "client.list") - } - ret := []jsonutils.JSONObject{} - for i := range result { - location, _ := result[i].GetString("location") - if len(location) == 0 || strings.ToLower(self.Name) == strings.ToLower(strings.Replace(location, " ", "", -1)) { - ret = append(ret, result[i]) - } - } - return jsonutils.Update(retVal, ret) -} diff --git a/pkg/multicloud/azure/resourcegroup.go b/pkg/multicloud/azure/resourcegroup.go deleted file mode 100644 index 863846dd15..0000000000 --- a/pkg/multicloud/azure/resourcegroup.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type GroupProperties struct { - ProvisioningState string -} - -type SResourceGroup struct { - multicloud.SProjectBase - multicloud.AzureTags - client *SAzureClient - - ID string - Name string - Location string - Properties GroupProperties - ManagedBy string - subId string -} - -func (self *SRegion) GetResourceGroupDetail(groupName string) (*SResourceGroup, error) { - resourceGroup := SResourceGroup{client: self.client, subId: self.client._subscriptionId()} - idStr := fmt.Sprintf("subscriptions/%s/resourcegroups/%s", self.client._subscriptionId(), groupName) - return &resourceGroup, self.get(idStr, url.Values{}, &resourceGroup) -} - -// not support update, resource group name is immutable??? -func (self *SRegion) UpdateResourceGroup(groupName string, newName string) error { - resourceGroup := SResourceGroup{Name: newName, client: self.client, subId: self.client._subscriptionId()} - resource := fmt.Sprintf("subscriptions/%s/resourcegroups/%s", self.client.subscriptionId, groupName) - _, err := self.client.patch(resource, jsonutils.Marshal(&resourceGroup)) - return err -} - -func (self *SRegion) CreateResourceGroup(groupName string) (jsonutils.JSONObject, error) { - resourceGroup := SResourceGroup{Location: self.Name, client: self.client, subId: self.client._subscriptionId()} - idStr := fmt.Sprintf("subscriptions/%s/resourcegroups/%s", self.client._subscriptionId(), groupName) - return self.client.put(idStr, jsonutils.Marshal(resourceGroup)) -} - -func (self *SRegion) DeleteResourceGroup(groupName string) error { - idStr := fmt.Sprintf("subscriptions/%s/resourcegroups/%s", self.client._subscriptionId(), groupName) - return self.del(idStr) -} - -func (r *SResourceGroup) GetName() string { - return r.Name -} - -func (r *SResourceGroup) GetId() string { - return r.ID -} - -func (self *SResourceGroup) GetAccountId() string { - return fmt.Sprintf("%s/%s", self.client.tenantId, self.subId) -} - -func (r *SResourceGroup) GetGlobalId() string { - return strings.ToLower(fmt.Sprintf("%s/%s", r.subId, r.Name)) -} - -func (r *SResourceGroup) GetStatus() string { - return api.EXTERNAL_PROJECT_STATUS_AVAILABLE -} diff --git a/pkg/multicloud/azure/saml_provider.go b/pkg/multicloud/azure/saml_provider.go deleted file mode 100644 index 475e146bdc..0000000000 --- a/pkg/multicloud/azure/saml_provider.go +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis/cloudid" - api "yunion.io/x/onecloud/pkg/apis/cloudid" - compute_api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudid/options" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/httputils" - "yunion.io/x/onecloud/pkg/util/samlutils" -) - -type SAMLProvider struct { - multicloud.SResourceBase - multicloud.AzureTags - client *SAzureClient - - Name string - Metadata samlutils.EntityDescriptor -} - -func (self *SAMLProvider) Delete() error { - return nil -} - -func (self *SAMLProvider) GetGlobalId() string { - return strings.TrimPrefix(options.Options.ApiServer, "https://") -} - -func (self *SAMLProvider) GetId() string { - return options.Options.ApiServer -} - -func (self *SAMLProvider) GetName() string { - return self.Name -} - -func (self *SAMLProvider) GetStatus() string { - return api.SAML_PROVIDER_STATUS_AVAILABLE -} - -func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { - return nil -} - -func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { - return &self.Metadata, nil -} - -func (self *SAMLProvider) GetAuthUrl() string { - input := samlutils.SIdpInitiatedLoginInput{ - EntityID: cloudprovider.SAML_ENTITY_ID_AZURE, - IdpId: self.client.cpcfg.AccountId, - } - if self.client.GetAccessEnv() != compute_api.CLOUD_ACCESS_ENV_AZURE_GLOBAL { - return "" - } - return httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, fmt.Sprintf("sso?%s", jsonutils.Marshal(input).QueryString())) -} - -func (self *SAzureClient) ListSAMLProviders() ([]SAMLProvider, error) { - _, err := self.msGraphRequest("GET", "identityProviders", nil) - if err != nil { - return nil, err - } - return []SAMLProvider{}, nil -} - -func (self *SAzureClient) InviteUser(email string) (*SClouduser, error) { - body := jsonutils.Marshal(map[string]string{ - "invitedUserEmailAddress": email, - "inviteRedirectUrl": fmt.Sprintf("https://portal.azure.com/%s?login_hint=%s", self.tenantId, email), - }) - resp, err := self.msGraphRequest("POST", "invitations", body) - if err != nil { - return nil, errors.Wrapf(err, "msGraphRequest.invitations") - } - inviteUrl, _ := resp.GetString("inviteRedeemUrl") - err = cloudprovider.Wait(time.Second*2, time.Minute, func() (bool, error) { - users, err := self.ListGraphUsers() - if err != nil { - return false, errors.Wrapf(err, "GetCloudusers") - } - for i := range users { - users[i].inviteRedeemUrl = inviteUrl - if users[i].GetEmailAddr() == email { - return true, nil - } - } - return false, nil - }) - if err != nil { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "after invite %s", email) - } - users, err := self.ListGraphUsers() - if err != nil { - return nil, errors.Wrapf(err, "GetCloudusers") - } - for i := range users { - users[i].inviteRedeemUrl = inviteUrl - if users[i].GetEmailAddr() == email { - return &users[i], nil - } - } - - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "after invite %s", email) -} - -func (self *SAzureClient) CreateSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (*SAMLProvider, error) { - return &SAMLProvider{ - client: self, - Name: opts.Name, - Metadata: opts.Metadata, - }, nil -} diff --git a/pkg/multicloud/azure/securitygroup.go b/pkg/multicloud/azure/securitygroup.go deleted file mode 100644 index 076e1b109d..0000000000 --- a/pkg/multicloud/azure/securitygroup.go +++ /dev/null @@ -1,489 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net" - "net/url" - "strconv" - "strings" - "unicode" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/regutils" - "yunion.io/x/pkg/util/secrules" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SecurityRulePropertiesFormat struct { - Description string `json:"description,omitempty"` - Protocol string `json:"protocol,omitempty"` - SourcePortRange string `json:"sourcePortRange,omitempty"` - DestinationPortRange string `json:"destinationPortRange,omitempty"` - SourceAddressPrefix string `json:"sourceAddressPrefix,omitempty"` - SourceAddressPrefixes []string `json:"sourceAddressPrefixes,omitempty"` - DestinationAddressPrefix string `json:"destinationAddressPrefix,omitempty"` - DestinationAddressPrefixes []string `json:"destinationAddressPrefixes,omitempty"` - SourcePortRanges []string `json:"sourcePortRanges,omitempty"` - DestinationPortRanges []string `json:"destinationPortRanges,omitempty"` - Access string `json:"access,omitempty"` // Allow or Deny - Priority int32 `json:"priority,omitempty"` - Direction string `json:"direction,omitempty"` //Inbound or Outbound - ProvisioningState string `json:"-"` -} -type SecurityRules struct { - Properties SecurityRulePropertiesFormat - Name string - ID string -} - -type Interface struct { - ID string -} - -type SecurityGroupPropertiesFormat struct { - SecurityRules []SecurityRules `json:"securityRules,omitempty"` - DefaultSecurityRules []SecurityRules `json:"defaultSecurityRules,omitempty"` - NetworkInterfaces *[]Interface `json:"networkInterfaces,omitempty"` - Subnets *[]SNetwork `json:"subnets,omitempty"` - ProvisioningState string //Possible values are: 'Updating', 'Deleting', and 'Failed' -} -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.AzureTags - - region *SRegion - Properties *SecurityGroupPropertiesFormat `json:"properties,omitempty"` - ID string - Name string - Location string - Type string -} - -func parseCIDR(cidr string) (*net.IPNet, error) { - if cidr == "*" || strings.ToLower(cidr) == "internet" { - cidr = "0.0.0.0/0" - } - if strings.Index(cidr, "/") > 0 { - _, ipnet, err := net.ParseCIDR(cidr) - return ipnet, err - } - ip := net.ParseIP(cidr) - if ip == nil { - return nil, fmt.Errorf("Parse ip %s error", cidr) - } - return &net.IPNet{IP: ip, Mask: net.CIDRMask(32, 32)}, nil -} - -type rulePorts struct { - ports []int - portStart int - portEnd int -} - -func parsePorts(ports string) (rulePorts, error) { - result := rulePorts{ - portStart: -1, - portEnd: -1, - ports: []int{}, - } - if ports == "*" { - return result, nil - } else if strings.Index(ports, ",") > 0 { - for _, _port := range strings.Split(ports, ",") { - port, err := strconv.Atoi(_port) - if err != nil { - msg := fmt.Sprintf("parse rule port %s error: %v", ports, err) - log.Errorf(msg) - return result, fmt.Errorf(msg) - } - result.ports = append(result.ports, port) - } - } else if strings.Index(ports, "-") > 0 { - _ports := strings.Split(ports, "-") - if len(_ports) == 2 { - portStart, err := strconv.Atoi(_ports[0]) - if err != nil { - msg := fmt.Sprintf("parse rule port %s error: %v", ports, err) - log.Errorf(msg) - return result, fmt.Errorf(msg) - } - result.portStart = portStart - portEnd, err := strconv.Atoi(_ports[1]) - if err != nil { - msg := fmt.Sprintf("parse rule port %s error: %v", ports, err) - log.Errorf(msg) - return result, fmt.Errorf(msg) - } - result.portEnd = portEnd - } - } else { - _port, err := strconv.Atoi(ports) - if err != nil { - msg := fmt.Sprintf("parse rule port %s error: %v", ports, err) - log.Errorf(msg) - return result, fmt.Errorf(msg) - } - result.ports = append(result.ports, _port) - } - return result, nil -} - -func paresPortsWithIpNet(port string, ports []string, ip string, ips []string) ([]rulePorts, []*net.IPNet, error) { - portsResult, ipResult := []rulePorts{}, []*net.IPNet{} - if len(port) > 0 { - _ports, err := parsePorts(port) - if err != nil { - return nil, nil, err - } - portsResult = append(portsResult, _ports) - } else if len(ports) > 0 { - for i := 0; i < len(ports); i++ { - _ports, err := parsePorts(ports[i]) - if err != nil { - return nil, nil, err - } - portsResult = append(portsResult, _ports) - } - } - - if len(ip) > 0 { - ipnet, err := parseCIDR(ip) - if err != nil { - return nil, nil, err - } - ipResult = append(ipResult, ipnet) - } else if len(ips) > 0 { - for i := 0; i < len(ips); i++ { - ipnet, err := parseCIDR(ips[i]) - if err != nil { - return nil, nil, err - } - ipResult = append(ipResult, ipnet) - } - } - return portsResult, ipResult, nil -} - -func (self *SecurityRulePropertiesFormat) toRules() ([]cloudprovider.SecurityRule, error) { - result := []cloudprovider.SecurityRule{} - rule := cloudprovider.SecurityRule{ - SecurityRule: secrules.SecurityRule{ - Action: secrules.TSecurityRuleAction(strings.ToLower(self.Access)), - Direction: secrules.TSecurityRuleDirection(strings.Replace(strings.ToLower(self.Direction), "bound", "", -1)), - Protocol: strings.ToLower(self.Protocol), - Priority: int(self.Priority), - Description: self.Description, - }} - - if rule.Protocol == "*" { - rule.Protocol = "any" - } - - addressPrefix, addressPrefixes := "", []string{} - if rule.Direction == secrules.DIR_IN { - addressPrefix, addressPrefixes = self.SourceAddressPrefix, self.SourceAddressPrefixes - } else { - addressPrefix, addressPrefixes = self.DestinationAddressPrefix, self.DestinationAddressPrefixes - } - - if strings.ToLower(addressPrefix) == "internet" || addressPrefix == "*" { - addressPrefix = "0.0.0.0/0" - } - - if !regutils.MatchIPAddr(addressPrefix) && !regutils.MatchCIDR(addressPrefix) && len(addressPrefixes) == 0 { - return nil, nil - } - - ports, ips, err := paresPortsWithIpNet(self.DestinationPortRange, self.DestinationPortRanges, addressPrefix, addressPrefixes) - if err != nil { - return nil, err - } - - for i := 0; i < len(ips); i++ { - rule.IPNet = ips[i] - for j := 0; j < len(ports); j++ { - rule.Ports = ports[j].ports - rule.PortStart = ports[j].portStart - rule.PortEnd = ports[j].portEnd - err := rule.ValidateRule() - if err != nil && err != secrules.ErrInvalidPriority { - return nil, err - } - result = append(result, rule) - } - } - - return result, nil -} - -func (self *SecurityRulePropertiesFormat) String() string { - rules, err := self.toRules() - if err != nil { - log.Errorf("convert secrules error: %v", err) - return "" - } - result := []string{} - for i := 0; i < len(rules); i++ { - result = append(result, rules[i].String()) - } - return strings.Join(result, ";") -} - -func (self *SSecurityGroup) GetId() string { - return self.ID -} - -func (self *SSecurityGroup) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SSecurityGroup) GetDescription() string { - return "" -} - -func (self *SSecurityGroup) GetName() string { - return self.Name -} - -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - rules := make([]cloudprovider.SecurityRule, 0) - if self.Properties == nil || self.Properties.SecurityRules == nil { - return rules, nil - } - for _, _rule := range self.Properties.SecurityRules { - secRules, err := _rule.Properties.toRules() - if err != nil { - return nil, errors.Wrap(err, "_rule.Properties.toRules") - } - for i := range secRules { - secRules[i].Name = _rule.Name - rules = append(rules, secRules[i]) - } - } - return rules, nil -} - -func (self *SSecurityGroup) GetStatus() string { - return "" -} - -func (self *SSecurityGroup) IsEmulated() bool { - return false -} - -func (self *SSecurityGroup) GetVpcId() string { - return "normal" -} - -func (region *SRegion) CreateSecurityGroup(secName string) (*SSecurityGroup, error) { - if secName == "Default" { - secName = "Default-copy" - } - secgroup := &SSecurityGroup{region: region} - params := map[string]string{ - "Name": secName, - "Type": "Microsoft.Network/networkSecurityGroups", - "Location": region.Name, - } - return secgroup, region.create("", jsonutils.Marshal(params), secgroup) -} - -func (region *SRegion) ListSecgroups() ([]SSecurityGroup, error) { - secgroups := []SSecurityGroup{} - err := region.list("Microsoft.Network/networkSecurityGroups", url.Values{}, &secgroups) - if err != nil { - return nil, errors.Wrapf(err, "list") - } - return secgroups, nil -} - -func (region *SRegion) GetSecurityGroupDetails(secgroupId string) (*SSecurityGroup, error) { - secgroup := SSecurityGroup{region: region} - return &secgroup, region.get(secgroupId, url.Values{}, &secgroup) -} - -func (self *SSecurityGroup) Refresh() error { - sec, err := self.region.GetSecurityGroupDetails(self.ID) - if err != nil { - return err - } - return jsonutils.Update(self, sec) -} - -func convertRulePort(rule cloudprovider.SecurityRule) []string { - ports := []string{} - if len(rule.Ports) > 0 { - for i := 0; i < len(rule.Ports); i++ { - ports = append(ports, fmt.Sprintf("%d", rule.Ports[i])) - } - return ports - } - if rule.PortStart > 0 && rule.PortEnd < 65535 { - if rule.PortStart == rule.PortEnd { - return []string{fmt.Sprintf("%d", rule.PortStart)} - } - ports = append(ports, fmt.Sprintf("%d-%d", rule.PortStart, rule.PortEnd)) - } - return ports -} - -func convertSecurityGroupRule(rule cloudprovider.SecurityRule) *SecurityRules { - if len(rule.Name) == 0 { - rule.Name = fmt.Sprintf("%s_%d", rule.String(), rule.Priority) - } - rule.Name = func(name string) string { - // 名称必须以字母或数字开头,以字母、数字或下划线结尾,并且只能包含字母、数字、下划线、句点或连字符 - for _, s := range name { - if !(unicode.IsDigit(s) || unicode.IsLetter(s) || s == '.' || s == '-' || s == '_') { - name = strings.ReplaceAll(name, string(s), "_") - } - } - if !unicode.IsDigit(rune(name[0])) && !unicode.IsLetter(rune(name[0])) { - name = fmt.Sprintf("r_%s", name) - } - last := len(name) - 1 - if !unicode.IsDigit(rune(name[last])) && !unicode.IsLetter(rune(name[last])) && name[last] != '_' { - name = fmt.Sprintf("%s_", name) - } - return name - }(rule.Name) - destRule := SecurityRules{ - Name: rule.Name, - Properties: SecurityRulePropertiesFormat{ - Access: utils.Capitalize(string(rule.Action)), - Priority: int32(rule.Priority), - Protocol: "*", - Direction: utils.Capitalize((string(rule.Direction) + "bound")), - Description: rule.Description, - DestinationAddressPrefix: "*", - DestinationPortRanges: convertRulePort(rule), - SourcePortRange: "*", - SourceAddressPrefix: "*", - DestinationPortRange: "*", - }, - } - if rule.Protocol != secrules.PROTO_ANY { - destRule.Properties.Protocol = utils.Capitalize(rule.Protocol) - } - - if len(destRule.Properties.DestinationPortRanges) > 0 { - destRule.Properties.DestinationPortRange = "" - } - - ipAddr := "*" - if rule.IPNet != nil { - ipAddr = rule.IPNet.String() - } - if rule.Direction == secrules.DIR_IN { - destRule.Properties.SourceAddressPrefix = ipAddr - } else { - destRule.Properties.DestinationAddressPrefix = ipAddr - } - return &destRule -} - -func (region *SRegion) AttachSecurityToInterfaces(secgroupId string, nicIds []string) error { - for _, nicId := range nicIds { - nic, err := region.GetNetworkInterface(nicId) - if err != nil { - return err - } - nic.Properties.NetworkSecurityGroup = SSecurityGroup{ID: secgroupId} - if err := region.update(jsonutils.Marshal(nic), nil); err != nil { - return err - } - } - return nil -} - -func (region *SRegion) SetSecurityGroup(instanceId, secgroupId string) error { - instance, err := region.GetInstance(instanceId) - if err != nil { - return err - } - nicIds := []string{} - for _, nic := range instance.Properties.NetworkProfile.NetworkInterfaces { - nicIds = append(nicIds, nic.ID) - } - return region.AttachSecurityToInterfaces(secgroupId, nicIds) -} - -func (self *SSecurityGroup) GetProjectId() string { - return getResourceGroup(self.ID) -} - -func (self *SSecurityGroup) Delete() error { - if self.Properties != nil && self.Properties.NetworkInterfaces != nil { - for _, nic := range *self.Properties.NetworkInterfaces { - nic, err := self.region.GetNetworkInterface(nic.ID) - if err != nil { - return err - } - if err := self.region.update(jsonutils.Marshal(nic), nil); err != nil { - return err - } - } - } - return self.region.del(self.ID) -} - -func (self *SSecurityGroup) SetRules(rules []cloudprovider.SecurityRule) error { - names := []string{} - securityRules := []SecurityRules{} - for i := 0; i < len(rules); i++ { - rule := convertSecurityGroupRule(rules[i]) - if rule != nil { - for { - if !utils.IsInStringArray(rule.Name, names) { - names = append(names, rule.Name) - break - } - rule.Name = fmt.Sprintf("%s_", rule.Name) - } - securityRules = append(securityRules, *rule) - } - } - if self.Properties == nil { - self.Properties = &SecurityGroupPropertiesFormat{} - } - self.Properties.SecurityRules = securityRules - self.Properties.ProvisioningState = "" - return self.region.update(jsonutils.Marshal(self), nil) -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - for i := range common { - switch common[i].Direction { - case secrules.DIR_IN: - inAdds = append(inAdds, common[i]) - case secrules.DIR_OUT: - outAdds = append(outAdds, common[i]) - default: - return fmt.Errorf("invalid rule %s direction %s", common[i].String(), common[i].Direction) - } - } - // Azure 不允许同方向的规则优先级相同 - inRules := cloudprovider.SortUniqPriority(inAdds) - outRules := cloudprovider.SortUniqPriority(outAdds) - rules := append(inRules, outRules...) - return self.SetRules(rules) -} diff --git a/pkg/multicloud/azure/service.go b/pkg/multicloud/azure/service.go deleted file mode 100644 index b7ab368d74..0000000000 --- a/pkg/multicloud/azure/service.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SServices struct { - Value []SService `json:"value,omitempty"` -} - -type SService struct { - ID string `json:"id,omitempty"` - Namespace string `json:"namespace,omitempty"` - RegistrationState string `json:"registrationState,omitempty"` - ResourceTypes []ResourceType `json:"resourceTypes,omitempty"` -} - -type ResourceType struct { - ApiVersions []string `json:"apiVersions,omitempty"` - Capabilities string `json:"capabilities,omitempty"` - Locations []string `json:"locations,omitempty"` - ResourceType string `json:"resourceType,omitempty"` -} - -func (self *SAzureClient) ListServices() ([]SService, error) { - services := []SService{} - return services, self.list("providers", url.Values{}, &services) -} - -func (self *SAzureClient) GetSercice(serviceType string) (*SService, error) { - service := SService{} - return &service, self.get("providers/"+serviceType, url.Values{}, &service) -} - -func (self *SAzureClient) serviceOperation(serviceType, operation string) error { - resource := fmt.Sprintf("subscriptions/%s/providers/%s", self.subscriptionId, serviceType) - _, err := self.perform(resource, operation, nil) - return err -} - -func (self *SAzureClient) waitServiceStatus(serviceType, status string) error { - return cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) { - services, err := self.ListServices() - if err != nil { - return false, errors.Wrapf(err, "ListServices") - } - for _, service := range services { - if strings.ToLower(service.Namespace) == strings.ToLower(serviceType) { - if service.RegistrationState == status { - return true, nil - } - log.Debugf("service %s status: %s expect %s", serviceType, service.RegistrationState, status) - } - } - return false, nil - }) -} - -func (self *SAzureClient) ServiceRegister(serviceType string) error { - err := self.serviceOperation(serviceType, "register") - if err != nil { - return errors.Wrapf(err, "serviceOperation(%s)", "register") - } - return self.waitServiceStatus(serviceType, "Registered") -} - -func (self *SAzureClient) ServiceUnRegister(serviceType string) error { - err := self.serviceOperation(serviceType, "unregister") - if err != nil { - return errors.Wrapf(err, "serviceOperation(%s)", "unregister") - } - return self.waitServiceStatus(serviceType, "NotRegistered") -} diff --git a/pkg/multicloud/azure/shell/account.go b/pkg/multicloud/azure/shell/account.go deleted file mode 100644 index 3e71b750c5..0000000000 --- a/pkg/multicloud/azure/shell/account.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type AccountListOptions struct { - } - shellutils.R(&AccountListOptions{}, "account-list", "List sub account", func(cli *azure.SRegion, args *AccountListOptions) error { - if accounts, err := cli.GetClient().GetSubAccounts(); err != nil { - return err - } else { - printObject(accounts) - return nil - } - }) -} diff --git a/pkg/multicloud/azure/shell/app_gateways.go b/pkg/multicloud/azure/shell/app_gateways.go deleted file mode 100644 index 58eedcb0c3..0000000000 --- a/pkg/multicloud/azure/shell/app_gateways.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type AppGatewayListOptions struct { - } - shellutils.R(&AppGatewayListOptions{}, "app-gateway-list", "List app gateways", func(cli *azure.SRegion, args *AppGatewayListOptions) error { - apps, err := cli.ListAppGateways() - if err != nil { - return err - } - printList(apps, len(apps), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/azure/shell/app_service_plan.go b/pkg/multicloud/azure/shell/app_service_plan.go deleted file mode 100644 index bb8fe095c6..0000000000 --- a/pkg/multicloud/azure/shell/app_service_plan.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type AppServicePlanListOptions struct { - } - shellutils.R(&AppServicePlanListOptions{}, "app-service-plan-list", "List app service plan", func(cli *azure.SRegion, args *AppServicePlanListOptions) error { - appServicePlans, err := cli.GetAppServicePlans() - if err != nil { - return err - } - fmt.Printf("sku: %s\n", jsonutils.Marshal(appServicePlans[0].Sku)) - printList(appServicePlans, len(appServicePlans), 0, 0, []string{}) - return nil - }) - type AppServicePlanShowOptions struct { - ID string - } - shellutils.R(&AppServicePlanShowOptions{}, "app-service-plan-show", "Show app service plan", func(cli *azure.SRegion, args *AppServicePlanShowOptions) error { - appServicePlan, err := cli.GetAppServicePlan(args.ID) - if err != nil { - return err - } - printObject(appServicePlan) - return nil - }) - shellutils.R(&AppServicePlanListOptions{}, "autoscale-setting-list", "List autoscale setting in app service plan", func(cli *azure.SRegion, args *AppServicePlanListOptions) error { - appServicePlans, err := cli.GetAutoscaleSettingResources() - if err != nil { - return err - } - printList(appServicePlans, len(appServicePlans), 0, 0, []string{}) - return nil - }) - shellutils.R(&AppServicePlanShowOptions{}, "app-service-sku-list", "List sku usable in app service plan", func(cli *azure.SRegion, args *AppServicePlanShowOptions) error { - appServicePlan, err := cli.GetAppServicePlan(args.ID) - if err != nil { - return err - } - skus, err := appServicePlan.GetSkus() - if err != nil { - return err - } - printList(skus, len(skus), 0, 0, []string{}) - return nil - }) - shellutils.R(&AppServicePlanShowOptions{}, "app-service-network-list", "List network connected with app service plan", func(cli *azure.SRegion, args *AppServicePlanShowOptions) error { - appServicePlan, err := cli.GetAppServicePlan(args.ID) - if err != nil { - return err - } - networks, err := appServicePlan.GetNetworks() - if err != nil { - return err - } - printList(networks, len(networks), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/azure/shell/bucket.go b/pkg/multicloud/azure/shell/bucket.go deleted file mode 100644 index 9482e9f16d..0000000000 --- a/pkg/multicloud/azure/shell/bucket.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/objectstore" -) - -func init() { - objectstore.S3Shell() -} diff --git a/pkg/multicloud/azure/shell/cloudgroup.go b/pkg/multicloud/azure/shell/cloudgroup.go deleted file mode 100644 index 14cc2314e1..0000000000 --- a/pkg/multicloud/azure/shell/cloudgroup.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CloudgroupListOptions struct { - Name string - } - shellutils.R(&CloudgroupListOptions{}, "cloud-group-list", "List cloudgroups", func(cli *azure.SRegion, args *CloudgroupListOptions) error { - groups, err := cli.GetClient().GetCloudgroups(args.Name) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - type CloudgroupUserListOptions struct { - ID string - } - - shellutils.R(&CloudgroupUserListOptions{}, "cloud-group-user-list", "List group cloudusers", func(cli *azure.SRegion, args *CloudgroupUserListOptions) error { - users, err := cli.GetClient().ListGroupMemebers(args.ID) - if err != nil { - return err - } - printList(users, 0, 0, 0, nil) - return nil - }) - - type CloudgroupIdOptions struct { - ID string - } - - shellutils.R(&CloudgroupIdOptions{}, "cloud-group-delete", "Delete cloudgroup", func(cli *azure.SRegion, args *CloudgroupIdOptions) error { - return cli.GetClient().DeleteGroup(args.ID) - }) - - type CloudgroupCreateOptions struct { - NAME string - Desc string - } - - shellutils.R(&CloudgroupCreateOptions{}, "cloud-group-create", "Create cloudgroup", func(cli *azure.SRegion, args *CloudgroupCreateOptions) error { - group, err := cli.GetClient().CreateGroup(args.NAME, args.Desc) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type CloudgroupUserOptions struct { - ID string - USER_NAME string - } - - shellutils.R(&CloudgroupUserOptions{}, "cloud-group-remove-user", "Remove user from cloudgroup", func(cli *azure.SRegion, args *CloudgroupUserOptions) error { - return cli.GetClient().RemoveGroupUser(args.ID, args.USER_NAME) - }) - - shellutils.R(&CloudgroupUserOptions{}, "cloud-group-add-user", "Add user to cloudgroup", func(cli *azure.SRegion, args *CloudgroupUserOptions) error { - return cli.GetClient().AddGroupUser(args.ID, args.USER_NAME) - }) - -} diff --git a/pkg/multicloud/azure/shell/cloudpolicy.go b/pkg/multicloud/azure/shell/cloudpolicy.go deleted file mode 100644 index c33c706a44..0000000000 --- a/pkg/multicloud/azure/shell/cloudpolicy.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CloudpolicyListOptions struct { - Name string - PolicyType string `choices:"CustomRole|BuiltInRole"` - } - shellutils.R(&CloudpolicyListOptions{}, "cloud-policy-list", "List cloudpolicies", func(cli *azure.SRegion, args *CloudpolicyListOptions) error { - roles, err := cli.GetClient().GetRoles(args.Name, args.PolicyType) - if err != nil { - return err - } - printList(roles, 0, 0, 0, nil) - return nil - }) - - type CloudpolicyAssignOption struct { - OBJECT string - ROLE string - SubscriptionId string - } - - shellutils.R(&CloudpolicyAssignOption{}, "cloud-policy-assign-object", "Assign cloudpolicy for object", func(cli *azure.SRegion, args *CloudpolicyAssignOption) error { - return cli.GetClient().AssignPolicy(args.OBJECT, args.ROLE, args.SubscriptionId) - }) - - type AssignmentListOption struct { - ObjectId string - } - - shellutils.R(&AssignmentListOption{}, "assignment-list", "List role assignments", func(cli *azure.SRegion, args *AssignmentListOption) error { - assignments, err := cli.GetClient().GetAssignments(args.ObjectId) - if err != nil { - return err - } - printList(assignments, 0, 0, 0, nil) - return nil - }) - - type AssignmentIdOption struct { - ID string - } - - shellutils.R(&AssignmentIdOption{}, "assignment-delete", "Delete role assignment", func(cli *azure.SRegion, args *AssignmentIdOption) error { - return cli.GetClient().GDelete(args.ID) - }) - - type ObjectPolicyListOptions struct { - OBJECT string - } - - shellutils.R(&ObjectPolicyListOptions{}, "object-policy-list", "List object policies", func(cli *azure.SRegion, args *ObjectPolicyListOptions) error { - policies, err := cli.GetClient().GetCloudpolicies(args.OBJECT) - if err != nil { - return err - } - printList(policies, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/clouduser.go b/pkg/multicloud/azure/shell/clouduser.go deleted file mode 100644 index 8ea289efe3..0000000000 --- a/pkg/multicloud/azure/shell/clouduser.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClouduserListOptions struct { - } - shellutils.R(&ClouduserListOptions{}, "cloud-user-list", "List cloudusers", func(cli *azure.SRegion, args *ClouduserListOptions) error { - users, err := cli.GetClient().GetCloudusers() - if err != nil { - return err - } - printList(users, 0, 0, 0, nil) - return nil - }) - - type ClouduserIdOptions struct { - ID string - } - - shellutils.R(&ClouduserIdOptions{}, "cloud-user-delete", "Delete clouduser", func(cli *azure.SRegion, args *ClouduserIdOptions) error { - return cli.GetClient().DeleteClouduser(args.ID) - }) - - shellutils.R(&ClouduserIdOptions{}, "cloud-user-group-list", "List clouduser groups", func(cli *azure.SRegion, args *ClouduserIdOptions) error { - groups, err := cli.GetClient().GetUserGroups(args.ID) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - type ClouduserCreateOptions struct { - NAME string - Password string - } - - shellutils.R(&ClouduserCreateOptions{}, "cloud-user-create", "Create clouduser", func(cli *azure.SRegion, args *ClouduserCreateOptions) error { - user, err := cli.GetClient().CreateClouduser(args.NAME, args.Password) - if err != nil { - return err - } - printObject(user) - return nil - }) - - type ClouduserResetPasswordOptions struct { - NAME string - PASSWORD string - } - - shellutils.R(&ClouduserResetPasswordOptions{}, "cloud-user-reset-password", "Reset clouduser password", func(cli *azure.SRegion, args *ClouduserResetPasswordOptions) error { - return cli.GetClient().ResetClouduserPassword(args.NAME, args.PASSWORD) - }) - - type DomainListOptions struct { - } - - shellutils.R(&DomainListOptions{}, "domain-list", "List domains", func(cli *azure.SRegion, args *DomainListOptions) error { - domains, err := cli.GetClient().GetDomains() - if err != nil { - return err - } - printList(domains, 0, 0, 0, nil) - return nil - }) - - type GroupUserList struct { - } - - shellutils.R(&GroupUserList{}, "graph-user-list", "List graph users", func(cli *azure.SRegion, args *GroupUserList) error { - users, err := cli.GetClient().ListGraphUsers() - if err != nil { - return err - } - printObject(users) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/dbinstance.go b/pkg/multicloud/azure/shell/dbinstance.go deleted file mode 100644 index 6fc5706345..0000000000 --- a/pkg/multicloud/azure/shell/dbinstance.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceListOptions struct { - TYPE string `help:"dbinstance type" choices:"Microsoft.DBForMariaDB/servers|Microsoft.DBforMySQL/servers|Microsoft.DBforMySQL/flexibleServers|Microsoft.DBforPostgreSQL/servers|Microsoft.DBforPostgreSQL/flexibleServers|Microsoft.Sql/servers|Microsoft.Sql/managedInstances"` - } - shellutils.R(&DBInstanceListOptions{}, "dbinstance-list", "List rds intances", func(cli *azure.SRegion, args *DBInstanceListOptions) error { - instances, err := cli.ListDBInstance(args.TYPE) - if err != nil { - return err - } - printList(instances, 0, 0, len(instances), []string{}) - return nil - }) - - type DBInstanceIdOptions struct { - ID string - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-show", "Show rds intance", func(cli *azure.SRegion, args *DBInstanceIdOptions) error { - instance, err := cli.GetDBInstanceById(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/dbinstance_databases.go b/pkg/multicloud/azure/shell/dbinstance_databases.go deleted file mode 100644 index 420892bd27..0000000000 --- a/pkg/multicloud/azure/shell/dbinstance_databases.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceDatabasesOptions struct { - ID string - } - - shellutils.R(&DBInstanceDatabasesOptions{}, "dbinstance-database-show", "Show rds intance database", func(cli *azure.SRegion, args *DBInstanceDatabasesOptions) error { - databases, err := cli.ListSDBInstanceDatabase(args.ID) - if err != nil { - return err - } - printList(databases, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/dbinstance_networkRules.go b/pkg/multicloud/azure/shell/dbinstance_networkRules.go deleted file mode 100644 index 3158952d46..0000000000 --- a/pkg/multicloud/azure/shell/dbinstance_networkRules.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceNetworkOptions struct { - ID string - } - - shellutils.R(&DBInstanceNetworkOptions{}, "dbinstance-network-show", "Show rds intance networks", func(cli *azure.SRegion, args *DBInstanceNetworkOptions) error { - networks, err := cli.ListDBInstanceVirtualNetworkRule(args.ID) - if err != nil { - return err - } - printList(networks, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/dbinstance_paraments.go b/pkg/multicloud/azure/shell/dbinstance_paraments.go deleted file mode 100644 index cd5446861f..0000000000 --- a/pkg/multicloud/azure/shell/dbinstance_paraments.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceParameterOptions struct { - ID string - } - - shellutils.R(&DBInstanceParameterOptions{}, "dbinstance-parameter-show", "Show rds intance parameter", func(cli *azure.SRegion, args *DBInstanceParameterOptions) error { - parameters, err := cli.ListDBInstanceConfiguration(args.ID) - if err != nil { - return err - } - printList(parameters, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/disk.go b/pkg/multicloud/azure/shell/disk.go deleted file mode 100644 index f0c0e9e0fc..0000000000 --- a/pkg/multicloud/azure/shell/disk.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - } - shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *azure.SRegion, args *DiskListOptions) error { - disks, err := cli.GetDisks() - if err != nil { - return err - } - printList(disks, len(disks), 0, 0, []string{}) - return nil - }) - - type DiskCreateOptions struct { - NAME string `help:"Disk name"` - STORAGETYPE string `help:"Storage type" choices:"Standard_LRS|Premium_LRS|StandardSSD_LRS"` - SizeGb int32 `help:"Disk size"` - Image string `help:"Image id"` - SnapshotId string `help:"Create disk by snapshot"` - ResourceGroup string `help:"ResourceGroup Name"` - } - - shellutils.R(&DiskCreateOptions{}, "disk-create", "Create disk", func(cli *azure.SRegion, args *DiskCreateOptions) error { - disk, err := cli.CreateDisk(args.STORAGETYPE, args.NAME, args.SizeGb, args.Image, args.SnapshotId, args.ResourceGroup) - if err != nil { - return err - } - printObject(disk) - return nil - }) - - type DiskOptions struct { - ID string `help:"Disk ID"` - } - - shellutils.R(&DiskOptions{}, "disk-show", "Show disk", func(cli *azure.SRegion, args *DiskOptions) error { - disk, err := cli.GetDisk(args.ID) - if err != nil { - return err - } - printObject(disk) - return nil - }) - - shellutils.R(&DiskOptions{}, "classic-disk-show", "Show classic disk", func(cli *azure.SRegion, args *DiskOptions) error { - disk, err := cli.GetClassicDisk(args.ID) - if err != nil { - return err - } - printObject(disk) - return nil - }) - - shellutils.R(&DiskOptions{}, "disk-delete", "Delete disks", func(cli *azure.SRegion, args *DiskOptions) error { - return cli.DeleteDisk(args.ID) - }) - - type DiskResizeOptions struct { - ID string `help:"Disk ID"` - SIZE int32 `help:"Disk SizeGb"` - } - - shellutils.R(&DiskResizeOptions{}, "disk-resize", "Delete disks", func(cli *azure.SRegion, args *DiskResizeOptions) error { - return cli.ResizeDisk(args.ID, args.SIZE) - }) -} diff --git a/pkg/multicloud/azure/shell/doc.go b/pkg/multicloud/azure/shell/doc.go deleted file mode 100644 index df40009423..0000000000 --- a/pkg/multicloud/azure/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/azure/shell" diff --git a/pkg/multicloud/azure/shell/eip.go b/pkg/multicloud/azure/shell/eip.go deleted file mode 100644 index e0c62c8483..0000000000 --- a/pkg/multicloud/azure/shell/eip.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - Classic bool `help:"List classic eips"` - Offset int `help:"List offset"` - Limit int `help:"List limit"` - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *azure.SRegion, args *EipListOptions) error { - if args.Classic { - eips, err := cli.GetClassicEips() - if err != nil { - return err - } - printList(eips, len(eips), args.Offset, args.Limit, []string{}) - return nil - } else { - eips, err := cli.GetEips() - if err != nil { - return err - } - printList(eips, len(eips), args.Offset, args.Limit, []string{}) - return nil - } - }) - - type EipAllocateOptions struct { - NAME string `help:"Eip Name"` - ResourceGroup string `help:"ResourceGroup Name"` - } - shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *azure.SRegion, args *EipAllocateOptions) error { - if eip, err := cli.AllocateEIP(args.NAME, args.ResourceGroup); err != nil { - return err - } else { - printObject(eip) - return nil - } - }) - - type EipReleaseOptions struct { - ID string `help:"EIP allocation ID"` - } - shellutils.R(&EipReleaseOptions{}, "eip-delete", "Release an EIP", func(cli *azure.SRegion, args *EipReleaseOptions) error { - return cli.DeallocateEIP(args.ID) - }) - - type EipShowOptions struct { - ID string `help:"EIP ID"` - } - shellutils.R(&EipShowOptions{}, "eip-show", "Show an EIP", func(cli *azure.SRegion, args *EipShowOptions) error { - if eip, err := cli.GetEip(args.ID); err != nil { - return err - } else { - printObject(eip) - return nil - } - }) - - type EipAssociateOptions struct { - ID string `help:"EIP allocation ID"` - INSTANCE string `help:"Instance ID"` - } - shellutils.R(&EipAssociateOptions{}, "eip-associate", "Associate an EIP", func(cli *azure.SRegion, args *EipAssociateOptions) error { - err := cli.AssociateEip(args.ID, args.INSTANCE) - return err - }) - - type EipDissociateOptions struct { - ID string `help:"EIP allocation ID"` - } - - shellutils.R(&EipDissociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *azure.SRegion, args *EipDissociateOptions) error { - err := cli.DissociateEip(args.ID) - return err - }) -} diff --git a/pkg/multicloud/azure/shell/enrollment_account.go b/pkg/multicloud/azure/shell/enrollment_account.go deleted file mode 100644 index df198f0b9f..0000000000 --- a/pkg/multicloud/azure/shell/enrollment_account.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EnrollmentAccountListOptions struct { - } - shellutils.R(&EnrollmentAccountListOptions{}, "enrollment-account-list", "List enrollment accounts", func(cli *azure.SRegion, args *EnrollmentAccountListOptions) error { - accounts, err := cli.GetClient().GetEnrollmentAccounts() - if err != nil { - return err - } - printList(accounts, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/azure/shell/event.go b/pkg/multicloud/azure/shell/event.go deleted file mode 100644 index 2a2c2bf18f..0000000000 --- a/pkg/multicloud/azure/shell/event.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "time" - - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EventListOptions struct { - Start time.Time - End time.Time - } - shellutils.R(&EventListOptions{}, "event-list", "List events", func(cli *azure.SRegion, args *EventListOptions) error { - events, err := cli.GetEvents(args.Start, args.End) - if err != nil { - return err - } - printList(events, len(events), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/azure/shell/image.go b/pkg/multicloud/azure/shell/image.go deleted file mode 100644 index bd47e650f8..0000000000 --- a/pkg/multicloud/azure/shell/image.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "sort" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - ImageType string `help:"image type" choices:"customized|system|shared|market"` - } - shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *azure.SRegion, args *ImageListOptions) error { - images, err := cli.GetImages(cloudprovider.TImageType(args.ImageType)) - if err != nil { - return err - } - printList(images, len(images), 0, 0, []string{}) - return nil - }) - - type ImagePublishersOptions struct { - } - shellutils.R(&ImagePublishersOptions{}, "image-publisher-list", "List image providers", func(cli *azure.SRegion, args *ImagePublishersOptions) error { - providers, err := cli.GetImagePublishers(nil) - if err != nil { - return err - } - sort.Strings(providers) - fmt.Println(providers) - return nil - }) - - type ImageOfferedIDOptions struct { - Publisher []string `help:"publisher candidates"` - Offer []string `help:"offer candidates"` - Sku []string `help:"sku candidates"` - Version []string `help:"version candidates"` - Latest bool `help:"show latest version only"` - } - shellutils.R(&ImageOfferedIDOptions{}, "public-image-id-list", "List image providers", func(cli *azure.SRegion, args *ImageOfferedIDOptions) error { - idList, err := cli.GetOfferedImageIDs(args.Publisher, args.Offer, args.Sku, args.Version, args.Latest) - if err != nil { - return err - } - //sort.Strings(idList) - for id, image := range idList { - fmt.Printf("id: %s detail: %v\n", id, image) - } - return nil - }) - - type ImageCreateOptions struct { - NAME string `helo:"Image name"` - OSTYPE string `helo:"Operation system" choices:"Linux|Windows"` - Snapshot string `help:"Snapshot ID"` - BlobUri string `helo:"page blob uri"` - DiskSize int32 `helo:"Image size"` - Desc string `help:"Image desc"` - } - - shellutils.R(&ImageCreateOptions{}, "image-create", "Create image", func(cli *azure.SRegion, args *ImageCreateOptions) error { - if len(args.Snapshot) > 0 { - if image, err := cli.CreateImage(args.Snapshot, args.NAME, args.OSTYPE, args.Desc); err != nil { - return err - } else { - printObject(image) - return nil - } - } else { - if image, err := cli.CreateImageByBlob(args.NAME, args.OSTYPE, args.BlobUri, args.DiskSize); err != nil { - return err - } else { - printObject(image) - return nil - } - } - }) - - type ImageIdOptions struct { - ID string `helo:"Image ID"` - } - - shellutils.R(&ImageIdOptions{}, "image-delete", "Delete image", func(cli *azure.SRegion, args *ImageIdOptions) error { - return cli.DeleteImage(args.ID) - }) - - shellutils.R(&ImageIdOptions{}, "image-show", "Delete image", func(cli *azure.SRegion, args *ImageIdOptions) error { - image, err := cli.GetImageById(args.ID) - if err != nil { - return err - } - printObject(image) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/instance.go b/pkg/multicloud/azure/shell/instance.go deleted file mode 100644 index efd87772f5..0000000000 --- a/pkg/multicloud/azure/shell/instance.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "context" - "fmt" - "strings" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - Classic bool `help:"List classic instance"` - ScaleSets bool `help:"List Scale Sets instance"` - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List intances", func(cli *azure.SRegion, args *InstanceListOptions) error { - instances, err := cli.GetInstances() - if err != nil { - return err - } - printList(instances, len(instances), 0, 0, []string{}) - return nil - }) - - shellutils.R(&InstanceListOptions{}, "classic-instance-list", "List classic instance", func(cli *azure.SRegion, args *InstanceListOptions) error { - instances, err := cli.GetClassicInstances() - if err != nil { - return err - } - printList(instances, len(instances), 0, 0, []string{}) - return nil - }) - - type SClassicInstacneIdOptions struct { - ID string - } - - shellutils.R(&SClassicInstacneIdOptions{}, "classic-instance-disk-list", "List classic instance disks", func(cli *azure.SRegion, args *SClassicInstacneIdOptions) error { - disks, err := cli.GetClassicInstanceDisks(args.ID) - if err != nil { - return err - } - printList(disks, len(disks), 0, 0, []string{}) - return nil - }) - - shellutils.R(&InstanceListOptions{}, "instance-scaleset-list", "List classic instance", func(cli *azure.SRegion, args *InstanceListOptions) error { - instances, err := cli.GetInstanceScaleSets() - if err != nil { - return err - } - printList(instances, len(instances), 0, 0, []string{}) - return nil - }) - - type InstanceSizeListOptions struct { - } - - shellutils.R(&InstanceSizeListOptions{}, "instance-size-list", "List intances", func(cli *azure.SRegion, args *InstanceSizeListOptions) error { - vmSizes, err := cli.ListVmSizes() - if err != nil { - return err - } - printList(vmSizes, 0, 0, 0, nil) - return nil - }) - shellutils.R(&InstanceSizeListOptions{}, "resource-sku-list", "List resource sku", func(cli *azure.SRegion, args *InstanceSizeListOptions) error { - skus, err := cli.GetClient().ListResourceSkus() - if err != nil { - return err - } - printList(skus, len(skus), 0, 0, []string{}) - return nil - }) - - type InstanceCreateOptions struct { - NAME string `help:"Name of instance"` - IMAGE string `help:"image ID"` - CPU int `help:"CPU count"` - MEMORYMB int `help:"MemoryMb"` - InstanceType string `help:"Instance Type"` - SYSDISKSIZEGB int `help:"System Disk Size"` - Disk []int `help:"Data disk sizes int GB"` - STORAGE string `help:"Storage type"` - NETWORK string `help:"Network ID"` - PASSWD string `help:"password"` - PublicKey string `help:"PublicKey"` - OsType string `help:"Operation system type" choices:"Linux|Windows"` - } - shellutils.R(&InstanceCreateOptions{}, "instance-create", "Create a instance", func(cli *azure.SRegion, args *InstanceCreateOptions) error { - instance, e := cli.CreateInstanceSimple(args.NAME, args.IMAGE, args.OsType, args.CPU, args.MEMORYMB, args.SYSDISKSIZEGB, args.STORAGE, args.Disk, args.NETWORK, args.PASSWD, args.PublicKey) - if e != nil { - return e - } - printObject(instance) - return nil - }) - - type InstanceOptions struct { - ID string `help:"Instance ID"` - } - shellutils.R(&InstanceOptions{}, "instance-show", "Show intance detail", func(cli *azure.SRegion, args *InstanceOptions) error { - if instance, err := cli.GetInstance(args.ID); err != nil { - return err - } else { - printObject(instance) - return nil - } - }) - - shellutils.R(&InstanceOptions{}, "instance-start", "Start intance", func(cli *azure.SRegion, args *InstanceOptions) error { - return cli.StartVM(args.ID) - }) - - shellutils.R(&InstanceOptions{}, "instance-delete", "Delete intance", func(cli *azure.SRegion, args *InstanceOptions) error { - return cli.DeleteVM(args.ID) - }) - - shellutils.R(&InstanceOptions{}, "instance-stop", "Stop intance", func(cli *azure.SRegion, args *InstanceOptions) error { - return cli.StopVM(args.ID, true) - }) - - type InstanceRebuildOptions struct { - ID string `help:"Instance ID"` - CPU int `help:"Instance CPU core"` - MEMORYMB int `help:"Instance Memory MB"` - IMAGE string `help:"Image ID"` - Password string `help:"pasword"` - PublicKey string `help:"Public Key"` - Size int `help:"system disk size in GB"` - } - shellutils.R(&InstanceRebuildOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *azure.SRegion, args *InstanceRebuildOptions) error { - instance, err := cli.GetInstance(args.ID) - if err != nil { - return err - } - diskId, err := cli.ReplaceSystemDisk(instance, args.CPU, args.MEMORYMB, args.IMAGE, args.Password, args.PublicKey, args.Size) - if err != nil { - return err - } - fmt.Printf("New diskId is %s", diskId) - return nil - }) - - type InstanceDiskOptions struct { - ID string `help:"Instance ID"` - DISK string `help:"Disk ID"` - } - shellutils.R(&InstanceDiskOptions{}, "instance-attach-disk", "Attach a disk to intance", func(cli *azure.SRegion, args *InstanceDiskOptions) error { - return cli.AttachDisk(args.ID, args.DISK) - }) - - shellutils.R(&InstanceDiskOptions{}, "instance-detach-disk", "Attach a disk to intance", func(cli *azure.SRegion, args *InstanceDiskOptions) error { - return cli.DetachDisk(args.ID, args.DISK) - }) - - type InstanceConfigOptions struct { - ID string `help:"Instance ID"` - INSTANCE_TYPE string `help:"Instance Vm Size"` - } - - shellutils.R(&InstanceConfigOptions{}, "instance-change-config", "Attach a disk to intance", func(cli *azure.SRegion, args *InstanceConfigOptions) error { - return cli.ChangeConfig(args.ID, args.INSTANCE_TYPE) - }) - - type InstanceDeployOptions struct { - ID string `help:"Instance ID"` - OsType string `help:"Instance Os Type" choices:"Linux|Windows" default:"Linux"` - Password string `help:"Password for instance"` - PublicKey string `helo:"Deploy ssh_key for instance"` - } - - shellutils.R(&InstanceDeployOptions{}, "instance-reset-password", "Reset intance password", func(cli *azure.SRegion, args *InstanceDeployOptions) error { - return cli.DeployVM(context.Background(), args.ID, args.OsType, "", args.Password, args.PublicKey, false, "") - }) - - type InstanceSecurityGroupOptions struct { - ID string `help:"Instance ID"` - SecurityGroup string `help:"Security Group ID or Name"` - } - - shellutils.R(&InstanceSecurityGroupOptions{}, "instance-set-secgrp", "Attach a disk to intance", func(cli *azure.SRegion, args *InstanceSecurityGroupOptions) error { - return cli.SetSecurityGroup(args.ID, args.SecurityGroup) - }) - - type InstanceSaveImageOptions struct { - DISK_ID string `help:"Instance Os Disk ID"` - IMAGE_NAME string `help:"Image name"` - Notes string `hlep:"Image desc"` - OsType string `help:"Os Type" choices:"Linux|Windows" default:"Linux"` - } - shellutils.R(&InstanceSaveImageOptions{}, "instance-save-image", "Save instance to image", func(cli *azure.SRegion, args *InstanceSaveImageOptions) error { - opts := cloudprovider.SaveImageOptions{ - Name: args.IMAGE_NAME, - Notes: args.Notes, - } - image, err := cli.SaveImage(args.OsType, args.DISK_ID, &opts) - if err != nil { - return err - } - printObject(image) - return nil - }) - - shellutils.R(&InstanceOptions{}, "instance-get-tags", "get intance tags", func(cli *azure.SRegion, args *InstanceOptions) error { - tags, err := cli.GetClient().GetTags(args.ID) - if err != nil { - return err - } - printObject(tags) - return nil - }) - - type InstanceSetTagsOptions struct { - ID string `help:"Instance ID"` - Tags []string - } - shellutils.R(&InstanceSetTagsOptions{}, "instance-set-tags", "set intance metadata", func(cli *azure.SRegion, args *InstanceSetTagsOptions) error { - tags := map[string]string{} - for i := range args.Tags { - splited := strings.Split(args.Tags[i], "=") - if len(splited) == 2 { - tags[splited[0]] = splited[1] - } - } - result, err := cli.GetClient().SetTags(args.ID, tags) - if err != nil { - return err - } - printObject(result) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/kube_cluster.go b/pkg/multicloud/azure/shell/kube_cluster.go deleted file mode 100644 index cc814e838b..0000000000 --- a/pkg/multicloud/azure/shell/kube_cluster.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KubeClusterListOptions struct { - } - shellutils.R(&KubeClusterListOptions{}, "kube-cluster-list", "List kube cluster", func(cli *azure.SRegion, args *KubeClusterListOptions) error { - clusters, err := cli.GetKubeClusters() - if err != nil { - return err - } - printList(clusters, len(clusters), 0, 0, []string{}) - return nil - }) - - type KubeClusterIdOptions struct { - ID string - } - - shellutils.R(&KubeClusterIdOptions{}, "kube-cluster-kubeconfig", "Show kubeconfg", func(cli *azure.SRegion, args *KubeClusterIdOptions) error { - config, err := cli.GetKubeConfig(args.ID) - if err != nil { - return err - } - printObject(config) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/loadbalancer.go b/pkg/multicloud/azure/shell/loadbalancer.go deleted file mode 100644 index 1ee48a9d42..0000000000 --- a/pkg/multicloud/azure/shell/loadbalancer.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "strings" - - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerListOptions struct { - } - shellutils.R(&LoadbalancerListOptions{}, "lb-list", "List loadbalancers", func(cli *azure.SRegion, args *LoadbalancerListOptions) error { - lbs, err := cli.GetILoadBalancers() - if err != nil { - return err - } - printList(lbs, len(lbs), 0, 0, []string{}) - return nil - }) - - type LoadbalancerOptions struct { - ID string `help:"ID of loadbalancer"` - } - shellutils.R(&LoadbalancerOptions{}, "lb-show", "Show loadbalancer", func(cli *azure.SRegion, args *LoadbalancerOptions) error { - lb, err := cli.GetILoadBalancerById(args.ID) - if err != nil { - return err - } - printObject(lb) - return nil - }) - - shellutils.R(&LoadbalancerListOptions{}, "lbcert-list", "List loadbalancers certs", func(cli *azure.SRegion, args *LoadbalancerListOptions) error { - certs, err := cli.GetILoadBalancerCertificates() - if err != nil { - return err - } - printList(certs, len(certs), 0, 0, []string{}) - return nil - }) - - type LoadbalancerCertOptions struct { - ID string `help:"ID of loadbalancer cert"` - } - - shellutils.R(&LoadbalancerCertOptions{}, "lbcert-show", "Show loadbalancer cert", func(cli *azure.SRegion, args *LoadbalancerCertOptions) error { - cert, err := cli.GetILoadBalancerCertificateById(args.ID) - if err != nil { - return err - } - printObject(cert) - return nil - }) - - shellutils.R(&LoadbalancerOptions{}, "lbl-list", "List loadbalancer listeners", func(cli *azure.SRegion, args *LoadbalancerOptions) error { - lb, err := cli.GetILoadBalancerById(args.ID) - if err != nil { - return err - } - lbl, err := lb.GetILoadBalancerListeners() - if err != nil { - return err - } - printList(lbl, len(lbl), 0, 0, []string{}) - return nil - }) - - shellutils.R(&LoadbalancerOptions{}, "lbbg-list", "List loadbalancer listeners", func(cli *azure.SRegion, args *LoadbalancerOptions) error { - lb, err := cli.GetILoadBalancerById(args.ID) - if err != nil { - return err - } - lbbgs, err := lb.GetILoadBalancerBackendGroups() - if err != nil { - return err - } - printList(lbbgs, len(lbbgs), 0, 0, []string{}) - return nil - }) - - type LoadbalancerBackendOptions struct { - BGID string `help:"ID of loadbalancer backendgroup"` - } - shellutils.R(&LoadbalancerBackendOptions{}, "lbb-list", "List loadbalancer listeners", func(cli *azure.SRegion, args *LoadbalancerBackendOptions) error { - lb, err := cli.GetILoadBalancerById(strings.Split(args.BGID, "/backendAddressPools")[0]) - if err != nil { - return err - } - lbbg, err := lb.GetILoadBalancerBackendGroupById(args.BGID) - if err != nil { - return err - } - - lbbs, err := lbbg.GetILoadbalancerBackends() - if err != nil { - return err - } - - printList(lbbs, len(lbbs), 0, 0, []string{}) - return nil - }) - - type LoadbalancerRuleOptions struct { - LISTENID string `help:"ID of loadbalancer listener"` - } - shellutils.R(&LoadbalancerRuleOptions{}, "lbr-list", "List loadbalancer listener rules", func(cli *azure.SRegion, args *LoadbalancerRuleOptions) error { - lbId := "" - if strings.Index(args.LISTENID, "/requestRoutingRules") > 0 { - lbId = strings.Split(args.LISTENID, "/requestRoutingRules")[0] - } else { - return nil - } - lb, err := cli.GetILoadBalancerById(lbId) - if err != nil { - return err - } - lbl, err := lb.GetILoadBalancerListenerById(args.LISTENID) - if err != nil { - return err - } - - lbrs, err := lbl.GetILoadbalancerListenerRules() - if err != nil { - return err - } - - printList(lbrs, len(lbrs), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/azure/shell/loganalytics.go b/pkg/multicloud/azure/shell/loganalytics.go deleted file mode 100644 index 486e9139a8..0000000000 --- a/pkg/multicloud/azure/shell/loganalytics.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "time" - - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoganalyticsWorkspaceListOptions struct { - } - shellutils.R(&LoganalyticsWorkspaceListOptions{}, "loganalytics-workspace-list", "List loganalytics workspaces", func(cli *azure.SRegion, args *LoganalyticsWorkspaceListOptions) error { - workspaces, err := cli.GetClient().GetLoganalyticsWorkspaces() - if err != nil { - return err - } - printList(workspaces, len(workspaces), 0, 0, []string{}) - return nil - }) - - type DiskUsageListOptions struct { - WORKSPACE_ID string - NAME string - START time.Time - END time.Time - } - - shellutils.R(&DiskUsageListOptions{}, "disk-usage-list", "List disk usage", func(cli *azure.SRegion, args *DiskUsageListOptions) error { - usage, err := cli.GetClient().GetInstanceDiskUsage(args.WORKSPACE_ID, args.NAME, args.START, args.END) - if err != nil { - return err - } - printList(usage, len(usage), 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/monitor.go b/pkg/multicloud/azure/shell/monitor.go deleted file mode 100644 index 004b0cb4ee..0000000000 --- a/pkg/multicloud/azure/shell/monitor.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerListOptions struct { - } - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics", func(cli *azure.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric: %s %s %s", metrics[i].Id, metrics[i].MetricType, metrics[i].Unit) - printList(metrics[i].Values, len(metrics[i].Values), 0, 0, []string{}) - } - return nil - }) -} diff --git a/pkg/multicloud/azure/shell/network.go b/pkg/multicloud/azure/shell/network.go deleted file mode 100644 index 5cbc2d3857..0000000000 --- a/pkg/multicloud/azure/shell/network.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkListOptions struct { - VPC string `help:"Vpc Id"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&NetworkListOptions{}, "network-list", "List networks", func(cli *azure.SRegion, args *NetworkListOptions) error { - vpc, err := cli.GetVpc(args.VPC) - if err != nil { - return err - } - networks := vpc.GetNetworks() - printList(networks, len(networks), args.Offset, args.Limit, []string{}) - return nil - }) - - type NetworkCreateOptions struct { - VPC string - NAME string - CIDR string - } - - shellutils.R(&NetworkCreateOptions{}, "network-create", "Create network", func(cli *azure.SRegion, args *NetworkCreateOptions) error { - network, err := cli.CreateNetwork(args.VPC, args.NAME, args.CIDR, "") - if err != nil { - return err - } - printObject(network) - return nil - }) - - type NetworkInterfaceListOptions struct { - } - - shellutils.R(&NetworkInterfaceListOptions{}, "network-interface-list", "List network interface", func(cli *azure.SRegion, args *NetworkInterfaceListOptions) error { - nics, err := cli.GetNetworkInterfaces() - if err != nil { - return err - } - printList(nics, len(nics), 0, 0, []string{}) - return nil - }) - - type NetworkInterfaceOptions struct { - ID string `help:"Network ineterface ID"` - } - - shellutils.R(&NetworkInterfaceOptions{}, "network-interface-show", "Show network interface", func(cli *azure.SRegion, args *NetworkInterfaceOptions) error { - nic, err := cli.GetNetworkInterface(args.ID) - if err != nil { - return err - } - printObject(nic) - return nil - }) - - type NetworkInterfaceCreateOptions struct { - ResourceGroup string `help:"ResourceGroup Name"` - NAME string `help:"Nic interface name"` - IP string `help:"Nic private ip address"` - NETWORK string `help:"Netowrk ID"` - SecurityGroup string `help:"SecurityGroup ID"` - } - - shellutils.R(&NetworkInterfaceCreateOptions{}, "network-interface-create", "Create network interface", func(cli *azure.SRegion, args *NetworkInterfaceCreateOptions) error { - nic, err := cli.CreateNetworkInterface(args.ResourceGroup, args.NAME, args.IP, args.NETWORK, args.SecurityGroup) - if err != nil { - return err - } - printObject(nic) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/policy.go b/pkg/multicloud/azure/shell/policy.go deleted file mode 100644 index c9a23ca9d0..0000000000 --- a/pkg/multicloud/azure/shell/policy.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type PolicyListOptions struct { - } - shellutils.R(&PolicyListOptions{}, "policy-definition-list", "List policy definitions", func(cli *azure.SRegion, args *PolicyListOptions) error { - definitions, err := cli.GetClient().GetPolicyDefinitions() - if err != nil { - return err - } - printList(definitions, len(definitions), 0, 0, []string{}) - return nil - }) - - type PolicyAssignmentListOptions struct { - DefinitionId string - } - - shellutils.R(&PolicyAssignmentListOptions{}, "policy-assignment-list", "List policy assignment", func(cli *azure.SRegion, args *PolicyAssignmentListOptions) error { - assignments, err := cli.GetClient().GetPolicyAssignments(args.DefinitionId) - if err != nil { - return err - } - printList(assignments, len(assignments), 0, 0, []string{}) - return nil - }) - - type PolicyIdOptions struct { - ID string - } - - shellutils.R(&PolicyIdOptions{}, "policy-definition-show", "Show policy definition", func(cli *azure.SRegion, args *PolicyIdOptions) error { - definition, err := cli.GetClient().GetPolicyDefinition(args.ID) - if err != nil { - return err - } - printObject(definition) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/printutils.go b/pkg/multicloud/azure/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/azure/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/azure/shell/redis.go b/pkg/multicloud/azure/shell/redis.go deleted file mode 100644 index fdbb6388ca..0000000000 --- a/pkg/multicloud/azure/shell/redis.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RedisListOptions struct { - } - shellutils.R(&RedisListOptions{}, "redis-list", "List redis", func(cli *azure.SRegion, args *RedisListOptions) error { - redis, err := cli.GetRedisCaches() - if err != nil { - return err - } - printList(redis, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&RedisListOptions{}, "enterprise-redis-list", "List enterprise redis", func(cli *azure.SRegion, args *RedisListOptions) error { - redis, err := cli.GetEnterpriseRedisCaches() - if err != nil { - return err - } - printList(redis, 0, 0, 0, nil) - return nil - }) - - type RedisIdOptions struct { - ID string - } - shellutils.R(&RedisIdOptions{}, "redis-acl-list", "List redis acls", func(cli *azure.SRegion, args *RedisIdOptions) error { - acls, err := cli.GetRedisAcls(args.ID) - if err != nil { - return err - } - printList(acls, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/region.go b/pkg/multicloud/azure/shell/region.go deleted file mode 100644 index deec4b9013..0000000000 --- a/pkg/multicloud/azure/shell/region.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *azure.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) - - type ResourceIdOptions struct { - ID string `help:"resource id"` - } - shellutils.R(&ResourceIdOptions{}, "delete", "delete resource", func(cli *azure.SRegion, args *ResourceIdOptions) error { - return cli.Delete(args.ID) - }) - - shellutils.R(&ResourceIdOptions{}, "show", "Show resource", func(cli *azure.SRegion, args *ResourceIdOptions) error { - ret, err := cli.Show(args.ID) - if err != nil { - return err - } - printObject(ret) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/resourcegroup.go b/pkg/multicloud/azure/shell/resourcegroup.go deleted file mode 100644 index b1721c9190..0000000000 --- a/pkg/multicloud/azure/shell/resourcegroup.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ResourceGroupListOptions struct { - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&ResourceGroupListOptions{}, "resource-group-list", "List group", func(cli *azure.SRegion, args *ResourceGroupListOptions) error { - groups, err := cli.GetClient().ListResourceGroups() - if err != nil { - return err - } - printList(groups, len(groups), 0, 0, []string{}) - return nil - }) - - type ResourceGroupOptions struct { - GROUP string `help:"ResourceGrop Name"` - } - - shellutils.R(&ResourceGroupOptions{}, "resource-group-show", "Show group detail", func(cli *azure.SRegion, args *ResourceGroupOptions) error { - if group, err := cli.GetResourceGroupDetail(args.GROUP); err != nil { - return err - } else { - printObject(group) - return nil - } - }) - - shellutils.R(&ResourceGroupOptions{}, "resource-group-create", "Create resource group", func(cli *azure.SRegion, args *ResourceGroupOptions) error { - resp, err := cli.CreateResourceGroup(args.GROUP) - if err != nil { - return err - } - printObject(resp) - return nil - }) - - shellutils.R(&ResourceGroupOptions{}, "resource-group-delete", "Delete resource group", func(cli *azure.SRegion, args *ResourceGroupOptions) error { - err := cli.DeleteResourceGroup(args.GROUP) - if err != nil { - return err - } - return nil - }) - - type ResourceGroupUpdateOptions struct { - GROUP string `help:"Name of resource group to update"` - NAME string `help:"New name of resource group"` - } - shellutils.R(&ResourceGroupUpdateOptions{}, "resource-group-update", "Update resource group detail", func(cli *azure.SRegion, args *ResourceGroupUpdateOptions) error { - err := cli.UpdateResourceGroup(args.GROUP, args.NAME) - if err != nil { - return err - } - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/saml_provider.go b/pkg/multicloud/azure/shell/saml_provider.go deleted file mode 100644 index 58073c6d5b..0000000000 --- a/pkg/multicloud/azure/shell/saml_provider.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SAMLProviderListOptions struct { - } - shellutils.R(&SAMLProviderListOptions{}, "saml-provider-list", "List regions", func(cli *azure.SRegion, args *SAMLProviderListOptions) error { - sps, err := cli.GetClient().ListSAMLProviders() - if err != nil { - return err - } - printList(sps, 0, 0, 0, nil) - return nil - }) - - type SInvitateUser struct { - EMAIL string - } - - shellutils.R(&SInvitateUser{}, "invite-user", "Invitate user", func(cli *azure.SRegion, args *SInvitateUser) error { - user, err := cli.GetClient().InviteUser(args.EMAIL) - if err != nil { - return err - } - printObject(user) - fmt.Println("invite url: ", user.GetInviteUrl()) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/secgroup.go b/pkg/multicloud/azure/shell/secgroup.go deleted file mode 100644 index a870117494..0000000000 --- a/pkg/multicloud/azure/shell/secgroup.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security group", func(cli *azure.SRegion, args *SecurityGroupListOptions) error { - secgrps, err := cli.ListSecgroups() - if err != nil { - return err - } - printList(secgrps, len(secgrps), 0, 0, []string{}) - return nil - }) - - type SecurityGroupOptions struct { - ID string `help:"ID or name of security group"` - } - shellutils.R(&SecurityGroupOptions{}, "security-group-show", "Show details of a security group", func(cli *azure.SRegion, args *SecurityGroupOptions) error { - if secgrp, err := cli.GetSecurityGroupDetails(args.ID); err != nil { - return err - } else { - printObject(secgrp) - return nil - } - }) - - shellutils.R(&SecurityGroupOptions{}, "security-group-rule-list", "List security group rules", func(cli *azure.SRegion, args *SecurityGroupOptions) error { - if secgroup, err := cli.GetSecurityGroupDetails(args.ID); err != nil { - return err - } else if rules, err := secgroup.GetRules(); err != nil { - return err - } else { - printList(rules, len(rules), 0, 30, []string{}) - return nil - } - }) - - type SecurityGroupCreateOptions struct { - NAME string `help:"Security Group name"` - Classic bool `help:"Create classic Security Group"` - } - - shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create security group", func(cli *azure.SRegion, args *SecurityGroupCreateOptions) error { - if args.Classic { - secgrp, err := cli.CreateClassicSecurityGroup(args.NAME) - if err != nil { - return err - } - printObject(secgrp) - return nil - } - secgrp, err := cli.CreateSecurityGroup(args.NAME) - if err != nil { - return err - } - printObject(secgrp) - return nil - }) -} diff --git a/pkg/multicloud/azure/shell/service.go b/pkg/multicloud/azure/shell/service.go deleted file mode 100644 index c9a10429ba..0000000000 --- a/pkg/multicloud/azure/shell/service.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ServiceListOptions struct { - } - shellutils.R(&ServiceListOptions{}, "service-list", "List providers", func(cli *azure.SRegion, args *ServiceListOptions) error { - services, err := cli.GetClient().ListServices() - if err != nil { - return err - } - printList(services, len(services), 0, 0, []string{}) - return nil - }) - - type ServiceOptions struct { - NAME string `help:"Name for service register"` - } - - shellutils.R(&ServiceOptions{}, "service-register", "Register service", func(cli *azure.SRegion, args *ServiceOptions) error { - return cli.GetClient().ServiceRegister(args.NAME) - }) - - shellutils.R(&ServiceOptions{}, "service-unregister", "Unregister service", func(cli *azure.SRegion, args *ServiceOptions) error { - return cli.GetClient().ServiceUnRegister(args.NAME) - }) - - shellutils.R(&ServiceOptions{}, "service-show", "Show service detail", func(cli *azure.SRegion, args *ServiceOptions) error { - service, err := cli.GetClient().GetSercice(args.NAME) - if err != nil { - return err - } - printObject(service) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/snapshot.go b/pkg/multicloud/azure/shell/snapshot.go deleted file mode 100644 index 0532e5bea4..0000000000 --- a/pkg/multicloud/azure/shell/snapshot.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SnapshotListOptions struct { - } - shellutils.R(&SnapshotListOptions{}, "snapshot-list", "List snapshot", func(cli *azure.SRegion, args *SnapshotListOptions) error { - snapshots, err := cli.ListSnapshots() - if err != nil { - return err - } - printList(snapshots, len(snapshots), 0, 0, []string{}) - return nil - }) - - type SnapshotCreateOptions struct { - DISK string `help:"SourceID"` - NAME string `help:"Snapshot name"` - Desc string `help:"Snapshot description"` - } - - shellutils.R(&SnapshotCreateOptions{}, "snapshot-create", "Create snapshot", func(cli *azure.SRegion, args *SnapshotCreateOptions) error { - snapshot, err := cli.CreateSnapshot(args.DISK, args.NAME, args.Desc) - if err != nil { - return err - } - printObject(snapshot) - return nil - }) - - type SnapshotOptions struct { - ID string `help:"Snapshot ID"` - } - - shellutils.R(&SnapshotOptions{}, "snapshot-delete", "Delete snapshot", func(cli *azure.SRegion, args *SnapshotOptions) error { - return cli.DeleteSnapshot(args.ID) - }) - - shellutils.R(&SnapshotOptions{}, "snapshot-show", "List snapshot", func(cli *azure.SRegion, args *SnapshotOptions) error { - snapshot, err := cli.GetSnapshot(args.ID) - if err != nil { - return err - } - printObject(snapshot) - return nil - }) - - shellutils.R(&SnapshotOptions{}, "snapshot-grant-access", "Grant access for snapshot", func(cli *azure.SRegion, args *SnapshotOptions) error { - if uri, err := cli.GrantAccessSnapshot(args.ID); err != nil { - return err - } else { - fmt.Printf("download link %s", uri) - return nil - } - }) - -} diff --git a/pkg/multicloud/azure/shell/storageaccount.go b/pkg/multicloud/azure/shell/storageaccount.go deleted file mode 100644 index bd6bc06cf2..0000000000 --- a/pkg/multicloud/azure/shell/storageaccount.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type StorageAccountListOptions struct { - } - shellutils.R(&StorageAccountListOptions{}, "storage-account-list", "List storage account", func(cli *azure.SRegion, args *StorageAccountListOptions) error { - accounts, err := cli.ListStorageAccounts() - if err != nil { - return err - } - printList(accounts, len(accounts), 0, 0, []string{}) - return nil - }) - - shellutils.R(&StorageAccountListOptions{}, "classic-storage-account-list", "List classic storage account", func(cli *azure.SRegion, args *StorageAccountListOptions) error { - accounts, err := cli.ListClassicStorageAccounts() - if err != nil { - return err - } - printList(accounts, len(accounts), 0, 0, []string{}) - return nil - }) - - type StorageAccountOptions struct { - ID string `help:"StorageAccount ID"` - } - - shellutils.R(&StorageAccountOptions{}, "classic-storage-account-show", "Show storage account detail", func(cli *azure.SRegion, args *StorageAccountOptions) error { - account, err := cli.GetClassicStorageAccount(args.ID) - if err != nil { - return err - } - printObject(account) - return nil - }) - - shellutils.R(&StorageAccountOptions{}, "storage-account-delete", "Delete storage account", func(cli *azure.SRegion, args *StorageAccountOptions) error { - return cli.DeleteStorageAccount(args.ID) - }) - - shellutils.R(&StorageAccountOptions{}, "storage-account-show", "Show storage account detail", func(cli *azure.SRegion, args *StorageAccountOptions) error { - account, err := cli.GetStorageAccountDetail(args.ID) - if err != nil { - return err - } - printObject(account) - return nil - }) - - shellutils.R(&StorageAccountOptions{}, "storage-account-key", "Get storage account key", func(cli *azure.SRegion, args *StorageAccountOptions) error { - if key, err := cli.GetStorageAccountKey(args.ID); err != nil { - return err - } else { - fmt.Printf("Key: %s", key) - return nil - } - }) - - shellutils.R(&StorageAccountOptions{}, "storage-container-list", "Get list of containers of a storage account", func(cli *azure.SRegion, args *StorageAccountOptions) error { - account, err := cli.GetStorageAccountDetail(args.ID) - if err != nil { - return err - } - containers, err := account.GetContainers() - if err != nil { - return err - } - printList(containers, len(containers), 0, 0, nil) - return nil - }) - - type StorageAccountCreateContainerOptions struct { - ACCOUNT string `help:"storage account ID"` - CONTAINER string `help:"name of container to create"` - } - shellutils.R(&StorageAccountCreateContainerOptions{}, "storage-container-create", "Create a container in a storage account", func(cli *azure.SRegion, args *StorageAccountCreateContainerOptions) error { - account, err := cli.GetStorageAccountDetail(args.ACCOUNT) - if err != nil { - return err - } - container, err := account.CreateContainer(args.CONTAINER) - if err != nil { - return err - } - printObject(container) - return nil - }) - - shellutils.R(&StorageAccountCreateContainerOptions{}, "storage-container-list-objects", "Create a container in a storage account", func(cli *azure.SRegion, args *StorageAccountCreateContainerOptions) error { - account, err := cli.GetStorageAccountDetail(args.ACCOUNT) - if err != nil { - return err - } - container, err := account.GetContainer(args.CONTAINER) - if err != nil { - return err - } - blobs, err := container.ListAllFiles(nil) - if err != nil { - return err - } - printList(blobs, len(blobs), 0, 0, nil) - return nil - }) - - type StorageAccountUploadOptions struct { - ACCOUNT string `help:"storage account ID"` - CONTAINER string `help:"name of container to create"` - FILE string `help:"local file to upload"` - } - shellutils.R(&StorageAccountUploadOptions{}, "storage-container-upload", "Upload a container in a storage account", func(cli *azure.SRegion, args *StorageAccountUploadOptions) error { - account, err := cli.GetStorageAccountDetail(args.ACCOUNT) - if err != nil { - return err - } - container, err := account.GetContainer(args.CONTAINER) - if err != nil { - return err - } - url, err := container.UploadFile(args.FILE, nil) - if err != nil { - return err - } - fmt.Println(url) - return nil - }) - - type StorageAccountCreateOptions struct { - NAME string `help:"StorageAccount NAME"` - } - - shellutils.R(&StorageAccountCreateOptions{}, "storage-account-create", "Create a storage account", func(cli *azure.SRegion, args *StorageAccountCreateOptions) error { - if account, err := cli.CreateStorageAccount(args.NAME); err != nil { - return err - } else { - printObject(account) - return nil - } - }) - - type StorageAccountCheckeOptions struct { - } - - shellutils.R(&StorageAccountCheckeOptions{}, "storage-uniq-name", "Get a uniqel storage account name", func(cli *azure.SRegion, args *StorageAccountCheckeOptions) error { - uniqName, err := cli.GetUniqStorageAccountName() - if err != nil { - return err - } - fmt.Println(uniqName) - return nil - }) - - type SStorageAccountSkuOptions struct { - } - shellutils.R(&SStorageAccountSkuOptions{}, "storage-account-skus", "List skus of storage account", func(cli *azure.SRegion, args *SStorageAccountSkuOptions) error { - skus, err := cli.GetStorageAccountSkus() - if err != nil { - return err - } - printList(skus, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/azure/shell/subscription.go b/pkg/multicloud/azure/shell/subscription.go deleted file mode 100644 index 16d4b6d394..0000000000 --- a/pkg/multicloud/azure/shell/subscription.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SubscriptionListOptions struct { - } - shellutils.R(&SubscriptionListOptions{}, "subscription-list", "List subscriptions", func(cli *azure.SRegion, args *SubscriptionListOptions) error { - subscriptions, err := cli.GetClient().ListSubscriptions() - if err != nil { - return err - } - printList(subscriptions, 0, 0, 0, nil) - return nil - }) - - type SubscriptionCreateOptions struct { - NAME string - OfferType string `choices:"MS-AZR-0017P|MS-AZR-0148P" default:"MS-AZR-0017P"` - EAID string `help:"Enrollment accounts id"` - } - - shellutils.R(&SubscriptionCreateOptions{}, "subscription-create", "Create subscription", func(cli *azure.SRegion, args *SubscriptionCreateOptions) error { - return cli.GetClient().CreateSubscription(args.NAME, args.EAID, args.OfferType) - }) - - type ServicePrincipalListOptions struct { - AppId string - } - - shellutils.R(&ServicePrincipalListOptions{}, "sp-list", "List service principal", func(cli *azure.SRegion, args *ServicePrincipalListOptions) error { - sp, err := cli.GetClient().ListServicePrincipal(args.AppId) - if err != nil { - return err - } - printList(sp, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/usage.go b/pkg/multicloud/azure/shell/usage.go deleted file mode 100644 index 19914223d2..0000000000 --- a/pkg/multicloud/azure/shell/usage.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type UsageListOptions struct { - TYPE string `choices:"Microsoft.Network|Microsoft.Compute|Microsoft.Storage"` - } - shellutils.R(&UsageListOptions{}, "usage-list", "List usage", func(cli *azure.SRegion, args *UsageListOptions) error { - usage, err := cli.GetUsage(args.TYPE) - if err != nil { - return err - } - printList(usage, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/vpc.go b/pkg/multicloud/azure/shell/vpc.go deleted file mode 100644 index 4af981f017..0000000000 --- a/pkg/multicloud/azure/shell/vpc.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/azure" - "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 *azure.SRegion, args *VpcListOptions) error { - vpcs, err := cli.ListVpcs() - if err != nil { - return err - } - printList(vpcs, len(vpcs), args.Offset, args.Limit, []string{}) - return nil - }) - - type VpcOptions struct { - ID string `help:"vpc ID"` - } - - shellutils.R(&VpcOptions{}, "vpc-show", "Show vpc details", func(cli *azure.SRegion, args *VpcOptions) error { - vpc, err := cli.GetVpc(args.ID) - if err != nil { - return err - } - printObject(vpc) - return nil - }) - - shellutils.R(&VpcOptions{}, "vpc-delete", "Delete vpc", func(cli *azure.SRegion, args *VpcOptions) error { - return cli.DeleteVpc(args.ID) - }) - - type VpcCreateOptions struct { - NAME string `help:"vpc Name"` - CIDR string `help:"vpc cidr"` - Desc string `help:"vpc description"` - } - - shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *azure.SRegion, args *VpcCreateOptions) error { - opts := &cloudprovider.VpcCreateOptions{ - NAME: args.NAME, - CIDR: args.CIDR, - Desc: args.Desc, - } - vpc, err := cli.CreateIVpc(opts) - if err != nil { - return err - } - printObject(vpc) - return nil - }) -} diff --git a/pkg/multicloud/azure/shell/waf.go b/pkg/multicloud/azure/shell/waf.go deleted file mode 100644 index b3b3b2d200..0000000000 --- a/pkg/multicloud/azure/shell/waf.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RuleGroupListOptions struct { - } - shellutils.R(&RuleGroupListOptions{}, "waf-rule-group-list", "List waf rule groups", func(cli *azure.SRegion, args *RuleGroupListOptions) error { - groups, err := cli.ListAppWafManagedRuleGroup() - if err != nil { - return err - } - printList(groups, len(groups), 0, 0, []string{}) - return nil - }) - - type FrontDoorPolicyListOptions struct { - RESOURCE_GROUP string - } - shellutils.R(&FrontDoorPolicyListOptions{}, "front-door-policy-list", "List front door policies", func(cli *azure.SRegion, args *FrontDoorPolicyListOptions) error { - policies, err := cli.ListFrontDoorWafs(args.RESOURCE_GROUP) - if err != nil { - return err - } - printList(policies, 0, 0, 0, []string{}) - return nil - }) - - type AppGatewayWafListOptions struct { - } - - shellutils.R(&AppGatewayWafListOptions{}, "app-gateway-waf-list", "List app gateway wafs", func(cli *azure.SRegion, args *AppGatewayWafListOptions) error { - wafs, err := cli.ListAppWafs() - if err != nil { - return err - } - printList(wafs, 0, 0, 0, []string{}) - return nil - }) - - type AppGatewayWafRuleGroupListOptions struct { - } - - shellutils.R(&AppGatewayWafRuleGroupListOptions{}, "app-gateway-waf-rule-group-list", "List app gateway wafs", func(cli *azure.SRegion, args *AppGatewayWafRuleGroupListOptions) error { - group, err := cli.ListAppWafManagedRuleGroup() - if err != nil { - return err - } - printList(group, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/azure/shell/web_app.go b/pkg/multicloud/azure/shell/web_app.go deleted file mode 100644 index 912bb97a4e..0000000000 --- a/pkg/multicloud/azure/shell/web_app.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/azure" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type AppSiteListOptions struct { - } - shellutils.R(&AppSiteListOptions{}, "app-site-list", "List app service plan", func(cli *azure.SRegion, args *AppSiteListOptions) error { - ass, err := cli.GetAppSites() - if err != nil { - return err - } - printList(ass, len(ass), 0, 0, []string{}) - return nil - }) - type AppSiteShowOptions struct { - ID string - } - shellutils.R(&AppSiteShowOptions{}, "app-site-show", "Show app service plan", func(cli *azure.SRegion, args *AppSiteShowOptions) error { - as, err := cli.GetAppSite(args.ID) - if err != nil { - return err - } - printObject(as) - return nil - }) - shellutils.R(&AppSiteShowOptions{}, "app-site-deployment-list", "List sku usable in app service plan", func(cli *azure.SRegion, args *AppSiteShowOptions) error { - as, err := cli.GetAppSite(args.ID) - if err != nil { - return err - } - deployments, err := as.GetDeployments() - if err != nil { - return err - } - printList(deployments, len(deployments), 0, 0, []string{}) - return nil - }) - shellutils.R(&AppSiteShowOptions{}, "app-site-slot-list", "List slots ofr App site", func(cli *azure.SRegion, args *AppSiteShowOptions) error { - as, err := cli.GetAppSite(args.ID) - if err != nil { - return err - } - slots, err := as.GetSlots() - if err != nil { - return err - } - printList(slots, len(slots), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/azure/snapshot.go b/pkg/multicloud/azure/snapshot.go deleted file mode 100644 index 2f42e3dc43..0000000000 --- a/pkg/multicloud/azure/snapshot.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SnapshotSku struct { - Name string - Tier string -} - -type SSnapshot struct { - multicloud.SResourceBase - multicloud.AzureTags - region *SRegion - - ID string - Name string - Location string - ManagedBy string - Sku *SnapshotSku - Properties DiskProperties - Type string -} - -func (self *SSnapshot) GetId() string { - return self.ID -} - -func (self *SSnapshot) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SSnapshot) GetName() string { - return self.Name -} - -func (self *SSnapshot) GetStatus() string { - switch self.Properties.ProvisioningState { - case "Succeeded": - return api.SNAPSHOT_READY - default: - log.Errorf("Unknow azure snapshot %s status: %s", self.ID, self.Properties.ProvisioningState) - return api.SNAPSHOT_UNKNOWN - } -} - -func (self *SRegion) CreateSnapshot(diskId, name, desc string) (*SSnapshot, error) { - params := map[string]interface{}{ - "Name": name, - "Location": self.Name, - "Properties": map[string]interface{}{ - "CreationData": map[string]string{ - "CreateOption": "Copy", - "SourceResourceID": diskId, - }, - }, - "Type": "Microsoft.Compute/snapshots", - } - snapshot := &SSnapshot{region: self} - return snapshot, self.create("", jsonutils.Marshal(params), snapshot) -} - -func (self *SSnapshot) Delete() error { - return self.region.DeleteSnapshot(self.ID) -} - -func (self *SSnapshot) GetSizeMb() int32 { - return self.Properties.DiskSizeGB.Int32() * 1024 -} - -func (self *SRegion) DeleteSnapshot(snapshotId string) error { - return self.del(snapshotId) -} - -type AccessURIOutput struct { - AccessSas string -} - -type AccessProperties struct { - Output AccessURIOutput -} - -type AccessURI struct { - Name string - Properties AccessProperties -} - -func (self *SRegion) GrantAccessSnapshot(snapshotId string) (string, error) { - params := map[string]interface{}{ - "access": "Read", - "durationInSeconds": 3600 * 24, - } - body, err := self.perform(snapshotId, "beginGetAccess", jsonutils.Marshal(params)) - if err != nil { - return "", err - } - accessURI := AccessURI{} - return accessURI.Properties.Output.AccessSas, body.Unmarshal(&accessURI) -} - -func (self *SSnapshot) Refresh() error { - snapshot, err := self.region.GetSnapshot(self.ID) - if err != nil { - return err - } - return jsonutils.Update(self, snapshot) -} - -func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - return self.GetSnapshot(snapshotId) -} - -func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := self.ListSnapshots() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudSnapshot{} - for i := range snapshots { - snapshots[i].region = self - ret = append(ret, &snapshots[i]) - } - return ret, nil -} - -func (self *SSnapshot) GetDiskId() string { - return strings.ToLower(self.Properties.CreationData.SourceResourceID) -} - -func (self *SSnapshot) GetDiskType() string { - return "" -} - -func (self *SSnapshot) GetProjectId() string { - return getResourceGroup(self.ID) -} - -func (region *SRegion) GetSnapshot(snapshotId string) (*SSnapshot, error) { - snapshot := SSnapshot{region: region} - return &snapshot, region.get(snapshotId, url.Values{}, &snapshot) -} - -func (region *SRegion) ListSnapshots() ([]SSnapshot, error) { - result := []SSnapshot{} - err := region.list("Microsoft.Compute/snapshots", url.Values{}, &result) - if err != nil { - return nil, err - } - return result, nil -} diff --git a/pkg/multicloud/azure/storage.go b/pkg/multicloud/azure/storage.go deleted file mode 100644 index c1ca184986..0000000000 --- a/pkg/multicloud/azure/storage.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type Capabilitie struct { - Name string - Value string -} - -const ( - STORAGE_STD_LRS = "Standard_LRS" - STORAGE_PRE_LRS = "Premium_LRS" - STORAGE_STD_SSD = "StandardSSD_LRS" -) - -var STORAGETYPES = []string{STORAGE_STD_LRS, STORAGE_PRE_LRS, STORAGE_STD_SSD} - -type SStorage struct { - multicloud.SStorageBase - multicloud.AzureTags - zone *SZone - - storageType string - ResourceType string - Tier string - Kind string - Locations []string - Capabilities []Capabilitie -} - -func (self *SStorage) GetId() string { - return fmt.Sprintf("%s/%s", self.zone.GetGlobalId(), strings.ToLower(self.storageType)) -} - -func (self *SStorage) GetName() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, strings.ToLower(self.storageType)) -} - -func (self *SStorage) GetGlobalId() string { - return fmt.Sprintf("%s/%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId, strings.ToLower(self.storageType)) -} - -func (self *SStorage) IsEmulated() bool { - return true -} - -func (self *SStorage) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -func (self *SStorage) GetEnabled() bool { - return true -} - -func (self *SStorage) GetCapacityMB() int64 { - return 0 // unlimited -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - disk, err := self.zone.region.CreateDisk(self.storageType, conf.Name, int32(conf.SizeGb), "", "", conf.ProjectId) - if err != nil { - return nil, err - } - disk.storage = self - return disk, nil -} - -func (self *SStorage) GetIDiskById(diskId string) (cloudprovider.ICloudDisk, error) { - if disk, err := self.zone.region.GetDisk(diskId); err != nil { - return nil, err - } else { - disk.storage = self - return disk, nil - } -} - -func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := self.zone.region.GetDisks() - if err != nil { - return nil, err - } - idisks := make([]cloudprovider.ICloudDisk, 0) - for i := 0; i < len(disks); i++ { - storageType := strings.ToLower(string(disks[i].Sku.Name)) - if storageType == strings.ToLower(self.storageType) { - disks[i].storage = self - idisks = append(idisks, &disks[i]) - } - } - return idisks, nil -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.zone.region.getStoragecache() -} - -func (self *SStorage) GetMediumType() string { - if strings.HasPrefix(self.storageType, "premium") { - return api.DISK_TYPE_SSD - } - return api.DISK_TYPE_ROTATE -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - conf := jsonutils.NewDict() - return conf -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) GetStorageType() string { - return strings.ToLower(self.storageType) -} - -func (self *SStorage) Refresh() error { - // do nothing - return nil -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} diff --git a/pkg/multicloud/azure/storageaccount.go b/pkg/multicloud/azure/storageaccount.go deleted file mode 100644 index 03cf4fe605..0000000000 --- a/pkg/multicloud/azure/storageaccount.go +++ /dev/null @@ -1,1305 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "context" - "encoding/base64" - "fmt" - "io" - "math/rand" - "net/http" - "net/url" - "path" - "strconv" - "strings" - "time" - - "github.com/Azure/azure-sdk-for-go/storage" - azureenv "github.com/Azure/go-autorest/autorest/azure" - "github.com/Microsoft/azure-vhd-utils/vhdcore/common" - "github.com/Microsoft/azure-vhd-utils/vhdcore/diskstream" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SContainer struct { - storageaccount *SStorageAccount - Name string -} - -type SSku struct { - Name string - Tier string - Kind string - ResourceType string -} - -type Identity struct { - PrincipalID string - TenantID string - Type string -} - -type SStorageEndpoints struct { - Blob string - Queue string - Table string - File string -} - -type AccountProperties struct { - //normal - PrimaryEndpoints SStorageEndpoints `json:"primaryEndpoints,omitempty"` - ProvisioningState string - PrimaryLocation string - SecondaryEndpoints SStorageEndpoints `json:"secondaryEndpoints,omitempty"` - SecondaryLocation string - //CreationTime time.Time - AccessTier string `json:"accessTier,omitempty"` - EnableHTTPSTrafficOnly *bool `json:"supportsHttpsTrafficOnly,omitempty"` - IsHnsEnabled bool `json:"isHnsEnabled,omitempty"` - AzureFilesAadIntegration bool `json:"azureFilesAadIntegration,omitempty"` -} - -type SStorageAccount struct { - multicloud.SBaseBucket - multicloud.AzureTags - - region *SRegion - - accountKey string - - Sku SSku `json:"sku,omitempty"` - Kind string `json:"kind,omitempty"` - Identity *Identity - Location string `json:"location,omitempty"` - ID string `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Type string `json:"type,omitempty"` - - Properties AccountProperties `json:"properties"` -} - -func (self *SRegion) listStorageAccounts() ([]SStorageAccount, error) { - accounts := []SStorageAccount{} - err := self.list("Microsoft.Storage/storageAccounts", url.Values{}, &accounts) - if err != nil { - return nil, errors.Wrapf(err, "list") - } - result := []SStorageAccount{} - for i := range accounts { - accounts[i].region = self - result = append(result, accounts[i]) - } - return result, nil -} - -func (self *SRegion) ListStorageAccounts() ([]SStorageAccount, error) { - return self.listStorageAccounts() -} - -func randomString(prefix string, length int) string { - bytes := []byte("0123456789abcdefghijklmnopqrstuvwxyz") - result := []byte{} - r := rand.New(rand.NewSource(time.Now().UnixNano())) - for i := 0; i < length; i++ { - result = append(result, bytes[r.Intn(len(bytes))]) - } - return prefix + string(result) -} - -func (self *SRegion) GetUniqStorageAccountName() (string, error) { - for i := 0; i < 20; i++ { - name := randomString("storage", 8) - exist, err := self.checkStorageAccountNameExist(name) - if err == nil && !exist { - return name, nil - } - } - return "", fmt.Errorf("failed to found uniq storage name") -} - -type sNameAvailableOutput struct { - NameAvailable bool `json:"nameAvailable"` - Reason string `json:"reason"` - Message string `json:"message"` -} - -func (self *SRegion) checkStorageAccountNameExist(name string) (bool, error) { - ok, err := self.client.CheckNameAvailability("Microsoft.Storage/storageAccounts", name) - if err != nil { - return false, errors.Wrapf(err, "CheckNameAvailability(%s)", name) - } - return !ok, nil -} - -type SStorageAccountSku struct { - ResourceType string `json:"resourceType"` - Name string `json:"name"` - Tier string `json:"tier"` - Kind string `json:"kind"` - Locations []string `json:"locations"` - Capabilities []struct { - Name string `json:"name"` - Value string `json:"value"` - } `json:"capabilities"` - Restrictions []struct { - Type string `json:"type"` - Values []string `json:"values"` - ReasonCode string `json:"reasonCode"` - } `json:"restrictions"` -} - -func (self *SRegion) GetStorageAccountSkus() ([]SStorageAccountSku, error) { - skus := make([]SStorageAccountSku, 0) - err := self.client.list("Microsoft.Storage/skus", url.Values{}, &skus) - if err != nil { - return nil, errors.Wrap(err, "List") - } - ret := make([]SStorageAccountSku, 0) - for i := range skus { - if utils.IsInStringArray(self.GetId(), skus[i].Locations) { - ret = append(ret, skus[i]) - } - } - return ret, nil -} - -func (self *SRegion) getStorageAccountSkuByName(name string) (*SStorageAccountSku, error) { - skus, err := self.GetStorageAccountSkus() - if err != nil { - return nil, errors.Wrap(err, "getStorageAccountSkus") - } - for _, kind := range []string{ - "StorageV2", - "Storage", - } { - for i := range skus { - if skus[i].Name == name && skus[i].Kind == kind { - return &skus[i], nil - } - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) createStorageAccount(name string, skuName string) (*SStorageAccount, error) { - storageKind := "Storage" - if len(skuName) > 0 { - sku, err := self.getStorageAccountSkuByName(skuName) - if err != nil { - return nil, errors.Wrap(err, "getStorageAccountSkuByName") - } - skuName = sku.Name - storageKind = sku.Kind - } else { - skuName = "Standard_GRS" - } - storageaccount := SStorageAccount{ - region: self, - Location: self.Name, - Sku: SSku{ - Name: skuName, - }, - Kind: storageKind, - Properties: AccountProperties{ - IsHnsEnabled: true, - AzureFilesAadIntegration: true, - }, - Name: name, - Type: "Microsoft.Storage/storageAccounts", - } - - err := self.create("", jsonutils.Marshal(storageaccount), &storageaccount) - if err != nil { - return nil, errors.Wrap(err, "Create") - } - return &storageaccount, nil -} - -func (self *SRegion) CreateStorageAccount(storageAccount string) (*SStorageAccount, error) { - account, err := self.getStorageAccountID(storageAccount) - if err == nil { - return account, nil - } - if errors.Cause(err) == cloudprovider.ErrNotFound { - uniqName, err := self.GetUniqStorageAccountName() - if err != nil { - return nil, errors.Wrapf(err, "GetUniqStorageAccountName") - } - storageaccount := SStorageAccount{ - region: self, - Sku: SSku{ - Name: "Standard_GRS", - }, - Location: self.Name, - Kind: "Storage", - Properties: AccountProperties{ - IsHnsEnabled: true, - AzureFilesAadIntegration: true, - }, - Name: uniqName, - Type: "Microsoft.Storage/storageAccounts", - } - storageaccount.Tags = map[string]string{"id": storageAccount} - return &storageaccount, self.create("", jsonutils.Marshal(storageaccount), &storageaccount) - } - return nil, err -} - -func (self *SRegion) getStorageAccountID(storageAccount string) (*SStorageAccount, error) { - accounts, err := self.ListStorageAccounts() - if err != nil { - return nil, errors.Wrapf(err, "ListStorageAccounts") - } - for i := 0; i < len(accounts); i++ { - for k, v := range accounts[i].Tags { - if k == "id" && v == storageAccount { - accounts[i].region = self - return &accounts[i], nil - } - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetStorageAccountDetail(accountId string) (*SStorageAccount, error) { - account := SStorageAccount{region: self} - err := self.get(accountId, url.Values{}, &account) - if err != nil { - return nil, err - } - return &account, nil -} - -type AccountKeys struct { - KeyName string - Permissions string - Value string -} - -func (self *SRegion) GetStorageAccountKey(accountId string) (string, error) { - body, err := self.perform(accountId, "listKeys", nil) - if err != nil { - return "", err - } - if body.Contains("keys") { - keys := []AccountKeys{} - err = body.Unmarshal(&keys, "keys") - if err != nil { - return "", err - } - for _, key := range keys { - if strings.ToLower(key.Permissions) == "full" { - return key.Value, nil - } - } - return "", fmt.Errorf("not find storageaccount %s key", accountId) - } - return body.GetString("primaryKey") -} - -func (self *SRegion) DeleteStorageAccount(accountId string) error { - return self.del(accountId) -} - -func (self *SRegion) ListClassicStorageAccounts() ([]SStorageAccount, error) { - accounts := make([]SStorageAccount, 0) - err := self.list("Microsoft.ClassicStorage/storageAccounts", url.Values{}, &accounts) - if err != nil { - return nil, err - } - return accounts, nil -} - -func (self *SRegion) GetClassicStorageAccount(id string) (*SStorageAccount, error) { - account := &SStorageAccount{} - err := self.get(id, url.Values{}, account) - if err != nil { - return nil, errors.Wrapf(err, "get(%s)", id) - } - return account, nil -} - -func (self *SStorageAccount) GetAccountKey() (accountKey string, err error) { - if len(self.accountKey) > 0 { - return self.accountKey, nil - } - self.accountKey, err = self.region.GetStorageAccountKey(self.ID) - return self.accountKey, err -} - -func (self *SStorageAccount) getBlobServiceClient() (*storage.BlobStorageClient, error) { - accessKey, err := self.GetAccountKey() - if err != nil { - return nil, err - } - env, err := azureenv.EnvironmentFromName(self.region.client.envName) - if err != nil { - return nil, errors.Wrapf(err, "azureenv.EnvironmentFromName(%s)", self.region.client.envName) - } - client, err := storage.NewBasicClientOnSovereignCloud(self.Name, accessKey, env) - if err != nil { - return nil, err - } - srv := client.GetBlobService() - return &srv, nil -} - -func (self *SStorageAccount) CreateContainer(containerName string) (*SContainer, error) { - blobService, err := self.getBlobServiceClient() - if err != nil { - return nil, errors.Wrap(err, "getBlobServiceClient") - } - containerRef := blobService.GetContainerReference(containerName) - err = containerRef.Create(&storage.CreateContainerOptions{}) - if err != nil { - return nil, errors.Wrap(err, "Create") - } - container := SContainer{ - storageaccount: self, - Name: containerName, - } - return &container, nil -} - -func (self *SStorageAccount) GetContainers() ([]SContainer, error) { - blobService, err := self.getBlobServiceClient() - if err != nil { - return nil, errors.Wrap(err, "getBlobServiceClient") - } - result, err := blobService.ListContainers(storage.ListContainersParameters{}) - if err != nil { - return nil, err - } - containers := []SContainer{} - err = jsonutils.Update(&containers, result.Containers) - if err != nil { - return nil, err - } - for i := 0; i < len(containers); i++ { - containers[i].storageaccount = self - } - return containers, nil -} - -func (self *SStorageAccount) GetContainer(name string) (*SContainer, error) { - containers, err := self.GetContainers() - if err != nil { - return nil, err - } - for i := range containers { - if containers[i].Name == name { - return &containers[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SContainer) ListAllFiles(include *storage.IncludeBlobDataset) ([]storage.Blob, error) { - blobs := make([]storage.Blob, 0) - var marker string - for { - result, err := self.ListFiles("", marker, "", 5000, include) - if err != nil { - return nil, errors.Wrap(err, "ListFiles") - } - if len(result.Blobs) > 0 { - blobs = append(blobs, result.Blobs...) - } - if len(result.NextMarker) == 0 { - break - } else { - marker = result.NextMarker - } - } - return blobs, nil -} - -func (self *SContainer) ListFiles(prefix string, marker string, delimiter string, maxCount int, include *storage.IncludeBlobDataset) (storage.BlobListResponse, error) { - var result storage.BlobListResponse - blobService, err := self.storageaccount.getBlobServiceClient() - if err != nil { - return result, errors.Wrap(err, "getBlobServiceClient") - } - params := storage.ListBlobsParameters{Include: include} - if len(prefix) > 0 { - params.Prefix = prefix - } - if len(marker) > 0 { - params.Marker = marker - } - if len(delimiter) > 0 { - params.Delimiter = delimiter - } - if maxCount > 0 { - params.MaxResults = uint(maxCount) - } - result, err = blobService.GetContainerReference(self.Name).ListBlobs(params) - if err != nil { - return result, err - } - return result, nil -} - -func (self *SContainer) getContainerRef() (*storage.Container, error) { - blobService, err := self.storageaccount.getBlobServiceClient() - if err != nil { - return nil, errors.Wrap(err, "getBlobServiceClient") - } - return blobService.GetContainerReference(self.Name), nil -} - -func (self *SContainer) Delete(fileName string) error { - containerRef, err := self.getContainerRef() - if err != nil { - return err - } - blobRef := containerRef.GetBlobReference(fileName) - _, err = blobRef.DeleteIfExists(&storage.DeleteBlobOptions{}) - return err -} - -func (self *SContainer) CopySnapshot(snapshotId, fileName string) (*storage.Blob, error) { - containerRef, err := self.getContainerRef() - if err != nil { - return nil, err - } - blobRef := containerRef.GetBlobReference(fileName) - uri, err := self.storageaccount.region.GrantAccessSnapshot(snapshotId) - if err != nil { - return nil, err - } - err = blobRef.Copy(uri, &storage.CopyOptions{}) - if err != nil { - return nil, err - } - return blobRef, blobRef.GetProperties(&storage.GetBlobPropertiesOptions{}) -} - -func setBlobRefMeta(blobRef *storage.Blob, meta http.Header) (bool, bool) { - propChanged := false - metaChanged := false - for k, v := range meta { - if len(v) == 0 || len(v[0]) == 0 { - continue - } - switch http.CanonicalHeaderKey(k) { - case cloudprovider.META_HEADER_CACHE_CONTROL: - blobRef.Properties.CacheControl = v[0] - propChanged = true - case cloudprovider.META_HEADER_CONTENT_TYPE: - blobRef.Properties.ContentType = v[0] - propChanged = true - case cloudprovider.META_HEADER_CONTENT_MD5: - blobRef.Properties.ContentMD5 = v[0] - propChanged = true - case cloudprovider.META_HEADER_CONTENT_ENCODING: - blobRef.Properties.ContentEncoding = v[0] - propChanged = true - case cloudprovider.META_HEADER_CONTENT_LANGUAGE: - blobRef.Properties.ContentLanguage = v[0] - propChanged = true - case cloudprovider.META_HEADER_CONTENT_DISPOSITION: - blobRef.Properties.ContentDisposition = v[0] - propChanged = true - default: - if blobRef.Metadata == nil { - blobRef.Metadata = storage.BlobMetadata{} - } - blobRef.Metadata[k] = v[0] - metaChanged = true - } - } - return propChanged, metaChanged -} - -func (self *SContainer) UploadStream(key string, reader io.Reader, meta http.Header) error { - blobService, err := self.storageaccount.getBlobServiceClient() - if err != nil { - return errors.Wrap(err, "getBlobServiceClient") - } - containerRef := blobService.GetContainerReference(self.Name) - blobRef := containerRef.GetBlobReference(key) - blobRef.Properties.BlobType = storage.BlobTypeBlock - if meta != nil { - setBlobRefMeta(blobRef, meta) - } - return blobRef.CreateBlockBlobFromReader(reader, &storage.PutBlobOptions{}) -} - -func (self *SContainer) SignUrl(method string, key string, expire time.Duration) (string, error) { - blobService, err := self.storageaccount.getBlobServiceClient() - if err != nil { - return "", errors.Wrap(err, "getBlobServiceClient") - } - containerRef := blobService.GetContainerReference(self.Name) - sas := storage.BlobSASOptions{} - sas.Start = time.Now() - sas.Expiry = sas.Start.Add(expire) - sas.UseHTTPS = true - switch method { - case "GET": - sas.Read = true - case "PUT": - sas.Read = true - sas.Add = true - sas.Create = true - sas.Write = true - case "DELETE": - sas.Read = true - sas.Write = true - sas.Delete = true - default: - return "", errors.Error("unsupport method") - } - blobRef := containerRef.GetBlobReference(key) - return blobRef.GetSASURI(sas) -} - -func (self *SContainer) UploadFile(filePath string, callback func(progress float32)) (string, error) { - blobService, err := self.storageaccount.getBlobServiceClient() - if err != nil { - return "", errors.Wrap(err, "getBlobServiceClient") - } - containerRef := blobService.GetContainerReference(self.Name) - - err = ensureVHDSanity(filePath) - if err != nil { - return "", err - } - diskStream, err := diskstream.CreateNewDiskStream(filePath) - if err != nil { - return "", err - } - defer diskStream.Close() - blobName := path.Base(filePath) - blobRef := containerRef.GetBlobReference(blobName) - blobRef.Properties.ContentLength = diskStream.GetSize() - err = blobRef.PutPageBlob(&storage.PutBlobOptions{}) - if err != nil { - return "", err - } - var rangesToSkip []*common.IndexRange - uploadableRanges, err := LocateUploadableRanges(diskStream, rangesToSkip, DefaultReadBlockSize) - if err != nil { - return "", err - } - uploadableRanges, err = DetectEmptyRanges(diskStream, uploadableRanges) - if err != nil { - return "", err - } - - cxt := &DiskUploadContext{ - VhdStream: diskStream, - UploadableRanges: uploadableRanges, - AlreadyProcessedBytes: common.TotalRangeLength(rangesToSkip), - BlobServiceClient: *blobService, - ContainerName: self.Name, - BlobName: blobName, - Parallelism: 3, - Resume: false, - MD5Hash: []byte(""), //localMetaData.FileMetaData.MD5Hash, - } - - if err := Upload(cxt, callback); err != nil { - return "", err - } - return blobRef.GetURL(), nil -} - -func (self *SContainer) getAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - containerRef, err := self.getContainerRef() - if err != nil { - log.Errorf("getContainerRef fail %s", err) - return acl - } - output, err := containerRef.GetPermissions(nil) - if err != nil { - log.Errorf("containerRef.GetPermissions fail %s", err) - return acl - } - switch output.AccessType { - case storage.ContainerAccessTypePrivate: - acl = cloudprovider.ACLPrivate - case storage.ContainerAccessTypeContainer: - acl = cloudprovider.ACLPublicRead - } - return acl -} - -func (self *SContainer) setAcl(aclStr cloudprovider.TBucketACLType) error { - perm := storage.ContainerPermissions{} - switch aclStr { - case cloudprovider.ACLPublicRead: - perm.AccessType = storage.ContainerAccessTypeContainer - case cloudprovider.ACLPrivate: - perm.AccessType = storage.ContainerAccessTypePrivate - default: - return errors.Error("unsupported ACL:" + string(aclStr)) - } - containerRef, err := self.getContainerRef() - if err != nil { - return errors.Wrap(err, "getContainerRef") - } - err = containerRef.SetPermissions(perm, nil) - if err != nil { - return errors.Wrap(err, "SetPermissions") - } - return nil -} - -func (self *SStorageAccount) UploadFile(containerName string, filePath string, callback func(progress float32)) (string, error) { - container, err := self.getOrCreateContainer(containerName, true) - if err != nil { - return "", errors.Wrap(err, "getOrCreateContainer") - } - return container.UploadFile(filePath, callback) -} - -func (self *SStorageAccount) getOrCreateContainer(containerName string, create bool) (*SContainer, error) { - containers, err := self.GetContainers() - if err != nil { - return nil, errors.Wrap(err, "GetContainers") - } - var container *SContainer - find := false - for i := 0; i < len(containers); i++ { - if containers[i].Name == containerName { - container = &containers[i] - find = true - break - } - } - if !find { - if !create { - return nil, cloudprovider.ErrNotFound - } - container, err = self.CreateContainer(containerName) - if err != nil { - return nil, errors.Wrap(err, "CreateContainer") - } - } - return container, nil -} - -func (self *SStorageAccount) UploadStream(containerName string, key string, reader io.Reader, meta http.Header) error { - container, err := self.getOrCreateContainer(containerName, true) - if err != nil { - return errors.Wrap(err, "getOrCreateContainer") - } - return container.UploadStream(key, reader, meta) -} - -func (b *SStorageAccount) MaxPartSizeBytes() int64 { - return 100 * 1000 * 1000 -} - -func (b *SStorageAccount) MaxPartCount() int { - return 50000 -} - -func (b *SStorageAccount) GetTags() (map[string]string, error) { - return b.Tags, nil -} - -func (b *SStorageAccount) GetProjectId() string { - return getResourceGroup(b.ID) -} - -func (b *SStorageAccount) GetGlobalId() string { - return b.Name -} - -func (b *SStorageAccount) GetName() string { - return b.Name -} - -func (b *SStorageAccount) GetLocation() string { - return b.Location -} - -func (b *SStorageAccount) GetIRegion() cloudprovider.ICloudRegion { - return b.region -} - -func (b *SStorageAccount) GetCreatedAt() time.Time { - return time.Time{} -} - -func (b *SStorageAccount) GetStorageClass() string { - return b.Sku.Tier -} - -// get the common ACL of all containers -func (b *SStorageAccount) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - containers, err := b.GetContainers() - if err != nil { - log.Errorf("GetContainers error %s", err) - return acl - } - for i := range containers { - aclC := containers[i].getAcl() - if i == 0 { - if aclC != acl { - acl = aclC - } - } else if aclC != acl { - acl = cloudprovider.ACLPrivate - } - } - return acl -} - -func (b *SStorageAccount) SetAcl(aclStr cloudprovider.TBucketACLType) error { - containers, err := b.GetContainers() - if err != nil { - return errors.Wrap(err, "GetContainers") - } - for i := range containers { - err = containers[i].setAcl(aclStr) - if err != nil { - return errors.Wrap(err, "containers.setAcl") - } - } - return nil -} - -func getDesc(prefix, name string) string { - if len(prefix) > 0 { - return prefix + "-" + name - } else { - return name - } -} - -func (ep SStorageEndpoints) getUrls(prefix string) []cloudprovider.SBucketAccessUrl { - ret := make([]cloudprovider.SBucketAccessUrl, 0) - if len(ep.Blob) > 0 { - ret = append(ret, cloudprovider.SBucketAccessUrl{ - Url: ep.Blob, - Description: getDesc(prefix, "blob"), - Primary: true, - }) - } - if len(ep.Queue) > 0 { - ret = append(ret, cloudprovider.SBucketAccessUrl{ - Url: ep.Queue, - Description: getDesc(prefix, "queue"), - }) - } - if len(ep.Table) > 0 { - ret = append(ret, cloudprovider.SBucketAccessUrl{ - Url: ep.Table, - Description: getDesc(prefix, "table"), - }) - } - if len(ep.File) > 0 { - ret = append(ret, cloudprovider.SBucketAccessUrl{ - Url: ep.File, - Description: getDesc(prefix, "file"), - }) - } - return ret -} - -func (b *SStorageAccount) GetAccessUrls() []cloudprovider.SBucketAccessUrl { - primary := b.Properties.PrimaryEndpoints.getUrls("") - secondary := b.Properties.SecondaryEndpoints.getUrls("secondary") - if len(secondary) > 0 { - primary = append(primary, secondary...) - } - return primary -} - -func (b *SStorageAccount) GetStats() cloudprovider.SBucketStats { - stats, _ := cloudprovider.GetIBucketStats(b) - return stats -} - -func getBlobRefMeta(blob *storage.Blob) http.Header { - meta := http.Header{} - for k, v := range blob.Metadata { - meta.Add(k, v) - } - if len(blob.Properties.CacheControl) > 0 { - meta.Set(cloudprovider.META_HEADER_CACHE_CONTROL, blob.Properties.CacheControl) - } - if len(blob.Properties.ContentType) > 0 { - meta.Set(cloudprovider.META_HEADER_CONTENT_TYPE, blob.Properties.ContentType) - } - if len(blob.Properties.ContentDisposition) > 0 { - meta.Set(cloudprovider.META_HEADER_CONTENT_DISPOSITION, blob.Properties.ContentDisposition) - } - if len(blob.Properties.ContentLanguage) > 0 { - meta.Set(cloudprovider.META_HEADER_CONTENT_LANGUAGE, blob.Properties.ContentLanguage) - } - if len(blob.Properties.ContentEncoding) > 0 { - meta.Set(cloudprovider.META_HEADER_CONTENT_ENCODING, blob.Properties.ContentEncoding) - } - if len(blob.Properties.ContentMD5) > 0 { - meta.Set(cloudprovider.META_HEADER_CONTENT_MD5, blob.Properties.ContentMD5) - } - return meta -} - -func (b *SStorageAccount) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { - result := cloudprovider.SListObjectResult{} - containers, err := b.GetContainers() - if err != nil { - return result, errors.Wrap(err, "GetContainers") - } - result.Objects = make([]cloudprovider.ICloudObject, 0) - result.CommonPrefixes = make([]cloudprovider.ICloudObject, 0) - for i := 0; i < len(containers); i += 1 { - container := containers[i] - matchLen := len(container.Name) - if matchLen > len(prefix) { - matchLen = len(prefix) - } - var subMarker string - if len(marker) < len(container.Name) { - if marker > container.Name { - continue - } - subMarker = "" - } else { - containerMarker := marker[:len(container.Name)] - if containerMarker > container.Name { - continue - } - subMarker = marker[len(container.Name)+1:] - } - if marker > container.Name { - continue - } - if maxCount <= 0 { - break - } - // container name matches prefix - if container.Name[:matchLen] == prefix[:matchLen] && (len(prefix) <= len(container.Name) || strings.HasPrefix(prefix, container.Name+"/")) { - if delimiter == "/" && len(prefix) == 0 { - // populate CommonPrefixes - o := &SObject{ - container: &container, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - Key: container.Name + "/", - }, - } - result.CommonPrefixes = append(result.CommonPrefixes, o) - maxCount -= 1 - } else if delimiter == "/" && prefix == container.Name+delimiter { - // do nothing - } else if len(prefix) <= len(container.Name)+1 { - // returns contain names only - o := &SObject{ - container: &container, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - Key: container.Name + "/", - }, - } - result.Objects = append(result.Objects, o) - maxCount -= 1 - } - if delimiter == "" || len(prefix) >= len(container.Name)+1 { - subPrefix := "" - if len(prefix) >= len(container.Name)+1 { - subPrefix = prefix[len(container.Name)+1:] - } - oResult, err := container.ListFiles(subPrefix, subMarker, delimiter, maxCount, nil) - if err != nil { - return result, errors.Wrap(err, "ListFiles") - } - for i := range oResult.Blobs { - blob := oResult.Blobs[i] - o := &SObject{ - container: &container, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - Key: container.Name + "/" + blob.Name, - SizeBytes: blob.Properties.ContentLength, - StorageClass: "", - ETag: blob.Properties.Etag, - LastModified: time.Time(blob.Properties.LastModified), - }, - } - result.Objects = append(result.Objects, o) - maxCount -= 1 - if maxCount == 0 { - break - } - result.NextMarker = blob.Name - } - for i := range oResult.BlobPrefixes { - o := &SObject{ - container: &container, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - Key: container.Name + "/" + oResult.BlobPrefixes[i], - }, - } - result.CommonPrefixes = append(result.CommonPrefixes, o) - maxCount -= 1 - } - if len(oResult.NextMarker) > 0 { - result.NextMarker = container.Name + "/" + oResult.NextMarker - result.IsTruncated = true - break - } - } - } - } - return result, nil -} - -func splitKey(key string) (string, string, error) { - slashPos := strings.IndexByte(key, '/') - if slashPos <= 0 { - return "", "", errors.Wrap(httperrors.ErrForbidden, "cannot put object to root") - } - containerName := key[:slashPos] - key = key[slashPos+1:] - return containerName, key, nil -} - -func splitKeyAndBlob(path string) (string, string, error) { - containerName, key, err := splitKey(path) - if err != nil { - return "", "", errors.Wrapf(err, "splitKey: %s", path) - } - if len(key) == 0 { - return "", "", errors.Error("empty blob path") - } - return containerName, key, nil -} - -func (b *SStorageAccount) PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - containerName, blob, err := splitKey(key) - if err != nil { - return errors.Wrap(err, "splitKey") - } - if len(blob) > 0 { - // put blob - err = b.UploadStream(containerName, blob, reader, meta) - if err != nil { - return errors.Wrap(err, "UploadStream") - } - } else { - // create container - if sizeBytes > 0 { - return errors.Wrap(httperrors.ErrForbidden, "not allow to create blob outsize of container") - } - _, err = b.getOrCreateContainer(containerName, true) - if err != nil { - return errors.Wrap(err, "getOrCreateContainer") - } - } - return nil -} - -func (b *SStorageAccount) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - containerName, blob, err := splitKeyAndBlob(key) - if err != nil { - return "", errors.Wrap(err, "splitKey") - } - container, err := b.getOrCreateContainer(containerName, true) - if err != nil { - return "", errors.Wrap(err, "getOrCreateContainer") - } - containerRef, err := container.getContainerRef() - if err != nil { - return "", errors.Wrap(err, "getContainerRef") - } - blobRef := containerRef.GetBlobReference(blob) - if meta != nil { - setBlobRefMeta(blobRef, meta) - } - err = blobRef.CreateBlockBlob(&storage.PutBlobOptions{}) - if err != nil { - return "", errors.Wrap(err, "CreateBlockBlob") - } - uploadId, err := blobRef.AcquireLease(-1, "", nil) - if err != nil { - return "", errors.Wrap(err, "blobRef.AcquireLease") - } - - return uploadId, nil -} - -func partIndex2BlockId(partIndex int) string { - return base64.URLEncoding.EncodeToString([]byte(strconv.FormatInt(int64(partIndex), 10))) -} - -func (b *SStorageAccount) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { - containerName, blob, err := splitKeyAndBlob(key) - if err != nil { - return "", errors.Wrap(err, "splitKey") - } - container, err := b.getOrCreateContainer(containerName, true) - if err != nil { - return "", errors.Wrap(err, "getOrCreateContainer") - } - containerRef, err := container.getContainerRef() - if err != nil { - return "", errors.Wrap(err, "getContainerRef") - } - blobRef := containerRef.GetBlobReference(blob) - - opts := &storage.PutBlockOptions{} - opts.LeaseID = uploadId - - blockId := partIndex2BlockId(partIndex) - err = blobRef.PutBlockWithLength(blockId, uint64(partSize), input, opts) - if err != nil { - return "", errors.Wrap(err, "PutBlockWithLength") - } - - return blockId, nil -} - -func (b *SStorageAccount) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, blockIds []string) error { - containerName, blob, err := splitKeyAndBlob(key) - if err != nil { - return errors.Wrap(err, "splitKey") - } - container, err := b.getOrCreateContainer(containerName, true) - if err != nil { - return errors.Wrap(err, "getOrCreateContainer") - } - containerRef, err := container.getContainerRef() - if err != nil { - return errors.Wrap(err, "getContainerRef") - } - blobRef := containerRef.GetBlobReference(blob) - - blocks := make([]storage.Block, len(blockIds)) - for i := range blockIds { - blocks[i] = storage.Block{ - ID: blockIds[i], - Status: storage.BlockStatusLatest, - } - } - opts := &storage.PutBlockListOptions{} - opts.LeaseID = uploadId - err = blobRef.PutBlockList(blocks, opts) - if err != nil { - return errors.Wrap(err, "PutBlockList") - } - - err = blobRef.ReleaseLease(uploadId, nil) - if err != nil { - return errors.Wrap(err, "ReleaseLease") - } - - return nil -} - -func (b *SStorageAccount) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { - containerName, blob, err := splitKeyAndBlob(key) - if err != nil { - return errors.Wrap(err, "splitKey") - } - container, err := b.getOrCreateContainer(containerName, false) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return errors.Wrap(err, "getOrCreateContainer") - } - containerRef, err := container.getContainerRef() - if err != nil { - return errors.Wrap(err, "getContainerRef") - } - - blobRef := containerRef.GetBlobReference(blob) - err = blobRef.ReleaseLease(uploadId, nil) - if err != nil { - return errors.Wrap(err, "ReleaseLease") - } - - opts := &storage.DeleteBlobOptions{} - deleteSnapshots := true - opts.DeleteSnapshots = &deleteSnapshots - _, err = blobRef.DeleteIfExists(opts) - if err != nil { - return errors.Wrap(err, "DeleteIfExists") - } - - return nil -} - -func (b *SStorageAccount) DeleteObject(ctx context.Context, key string) error { - containerName, blob, err := splitKey(key) - if err != nil { - return errors.Wrap(err, "splitKey") - } - blobService, err := b.getBlobServiceClient() - if err != nil { - return errors.Wrap(err, "getBlobServiceClient") - } - containerRef := blobService.GetContainerReference(containerName) - if len(blob) > 0 { - // delete object - blobRef := containerRef.GetBlobReference(blob) - _, err = blobRef.DeleteIfExists(nil) - if err != nil { - return errors.Wrap(err, "blobRef.DeleteIfExists") - } - } else { - // delete container - _, err = containerRef.DeleteIfExists(nil) - if err != nil { - return errors.Wrap(err, "containerRef.DeleteIfExists") - } - } - return nil -} - -func (b *SStorageAccount) GetTempUrl(method string, key string, expire time.Duration) (string, error) { - containerName, blob, err := splitKeyAndBlob(key) - if err != nil { - return "", errors.Wrap(err, "splitKey") - } - container, err := b.getOrCreateContainer(containerName, false) - if err != nil { - return "", errors.Wrap(err, "getOrCreateContainer") - } - return container.SignUrl(method, blob, expire) -} - -func (b *SStorageAccount) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - srcIBucket, err := b.region.GetIBucketByName(srcBucket) - if err != nil { - return errors.Wrap(err, "GetIBucketByName") - } - srcAccount := srcIBucket.(*SStorageAccount) - srcContName, srcBlob, err := splitKeyAndBlob(srcKey) - if err != nil { - return errors.Wrap(err, "src splitKey") - } - srcCont, err := srcAccount.getOrCreateContainer(srcContName, false) - if err != nil { - return errors.Wrap(err, "src getOrCreateContainer") - } - srcContRef, err := srcCont.getContainerRef() - if err != nil { - return errors.Wrap(err, "src getContainerRef") - } - srcBlobRef := srcContRef.GetBlobReference(srcBlob) - - containerName, blobName, err := splitKeyAndBlob(destKey) - if err != nil { - return errors.Wrap(err, "dest splitKey") - } - container, err := b.getOrCreateContainer(containerName, true) - if err != nil { - return errors.Wrap(err, "dest getOrCreateContainer") - } - containerRef, err := container.getContainerRef() - if err != nil { - return errors.Wrap(err, "dest getContainerRef") - } - blobRef := containerRef.GetBlobReference(blobName) - if meta != nil { - setBlobRefMeta(blobRef, meta) - } - opts := &storage.CopyOptions{} - err = blobRef.Copy(srcBlobRef.GetURL(), opts) - if err != nil { - return errors.Wrap(err, "blboRef.Copy") - } - return nil -} - -func (b *SStorageAccount) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { - containerName, blob, err := splitKeyAndBlob(key) - if err != nil { - return nil, errors.Wrap(err, "splitKey") - } - container, err := b.getOrCreateContainer(containerName, false) - if err != nil { - return nil, errors.Wrap(err, "getOrCreateContainer") - } - containerRef, err := container.getContainerRef() - if err != nil { - return nil, errors.Wrap(err, "container.getContainerRef") - } - blobRef := containerRef.GetBlobReference(blob) - if rangeOpt != nil { - opts := &storage.GetBlobRangeOptions{} - opts.Range = &storage.BlobRange{ - Start: uint64(rangeOpt.Start), - End: uint64(rangeOpt.End), - } - return blobRef.GetRange(opts) - } else { - opts := &storage.GetBlobOptions{} - return blobRef.Get(opts) - } -} - -func (b *SStorageAccount) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { - srcIBucket, err := b.region.GetIBucketByName(srcBucket) - if err != nil { - return "", errors.Wrap(err, "GetIBucketByName") - } - srcAccount := srcIBucket.(*SStorageAccount) - srcContName, srcBlob, err := splitKeyAndBlob(srcKey) - if err != nil { - return "", errors.Wrap(err, "src splitKey") - } - srcCont, err := srcAccount.getOrCreateContainer(srcContName, false) - if err != nil { - return "", errors.Wrap(err, "src getOrCreateContainer") - } - srcContRef, err := srcCont.getContainerRef() - if err != nil { - return "", errors.Wrap(err, "src getContainerRef") - } - srcBlobRef := srcContRef.GetBlobReference(srcBlob) - - containerName, blob, err := splitKeyAndBlob(key) - if err != nil { - return "", errors.Wrap(err, "splitKey") - } - container, err := b.getOrCreateContainer(containerName, true) - if err != nil { - return "", errors.Wrap(err, "getOrCreateContainer") - } - containerRef, err := container.getContainerRef() - if err != nil { - return "", errors.Wrap(err, "getContainerRef") - } - blobRef := containerRef.GetBlobReference(blob) - - opts := &storage.PutBlockFromURLOptions{} - opts.LeaseID = uploadId - - blockId := partIndex2BlockId(partIndex) - err = blobRef.PutBlockFromURL(blockId, srcBlobRef.GetURL(), srcOffset, uint64(srcLength), opts) - if err != nil { - return "", errors.Wrap(err, "PutBlockFromUrl") - } - - return blockId, nil -} diff --git a/pkg/multicloud/azure/storagecache.go b/pkg/multicloud/azure/storagecache.go deleted file mode 100644 index 4a4b758d75..0000000000 --- a/pkg/multicloud/azure/storagecache.go +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "context" - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "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" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/fileutils2" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -const ( - DefaultStorageAccount string = "image" - DefaultContainer string = "image-cache" - - DefaultReadBlockSize int64 = 4 * 1024 * 1024 -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.AzureTags - region *SRegion -} - -func (self *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) -} - -func (self *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) -} - -func (self *SStoragecache) GetStatus() string { - return "available" -} - -func (self *SStoragecache) Refresh() error { - return nil -} - -func (self *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetGlobalId()) -} - -func (self *SStoragecache) IsEmulated() bool { - return false -} - -func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - images, err := self.region.GetImages(cloudprovider.ImageTypeCustomized) - if err != nil { - return nil, errors.Wrapf(err, "GetImages") - } - ret := []cloudprovider.ICloudImage{} - for i := 0; i < len(images); i++ { - images[i].storageCache = self - ret = append(ret, &images[i]) - } - return ret, nil -} - -func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - img, err := self.region.GetImageById(extId) - if err != nil { - return nil, err - } - img.storageCache = self - return &img, nil -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - err := os.MkdirAll(options.Options.TempPath, os.ModePerm) - if err != nil { - log.Warningf("failed to create tmp path %s error: %v", options.Options.TempPath, err) - } - return self.uploadImage(ctx, userCred, image, options.Options.TempPath, callback) -} - -func (self *SStoragecache) checkStorageAccount() (*SStorageAccount, error) { - storageaccounts, err := self.region.ListStorageAccounts() - if err != nil { - return nil, errors.Wrap(err, "ListStorageAccounts") - } - if len(storageaccounts) == 0 { - storageaccount, err := self.region.CreateStorageAccount(self.region.Name) - if err != nil { - return nil, errors.Wrap(err, "CreateStorageAccount") - } - return storageaccount, nil - } - for i := 0; i < len(storageaccounts); i++ { - if id, ok := storageaccounts[i].Tags["id"]; ok && id == self.region.Name { - return &storageaccounts[i], nil - } - } - - storageaccount := &storageaccounts[0] - if storageaccount.Tags == nil { - storageaccount.Tags = map[string]string{} - } - storageaccount.Tags["id"] = self.region.Name - err = self.region.update(jsonutils.Marshal(storageaccount), nil) - if err != nil { - return nil, errors.Wrapf(err, "Update(%s)", jsonutils.Marshal(storageaccount).String()) - } - return storageaccount, nil -} - -func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, tmpPath string, callback func(progress float32)) (string, error) { - s := auth.GetAdminSession(ctx, options.Options.Region) - meta, reader, sizeBytes, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VHD), false) - if err != nil { - return "", err - } - // { - // "checksum":"d0ab0450979977c6ada8d85066a6e484", - // "container_format":"bare", - // "created_at":"2018-08-10T04:18:07", - // "deleted":"False", - // "disk_format":"vhd", - // "id":"64189033-3ad4-413c-b074-6bf0b6be8508", - // "is_public":"False", - // "min_disk":"0", - // "min_ram":"0", - // "name":"centos-7.3.1611-20180104.vhd", - // "owner":"5124d80475434da8b41fee48d5be94df", - // "properties":{ - // "os_arch":"x86_64", - // "os_distribution":"CentOS", - // "os_type":"Linux", - // "os_version":"7.3.1611-VHD" - // }, - // "protected":"False", - // "size":"2028505088", - // "status":"active", - // "updated_at":"2018-08-10T04:20:59" - // } - log.Infof("meta data %s", meta) - - imageNameOnBlob, _ := meta.GetString("name") - if !strings.HasSuffix(imageNameOnBlob, ".vhd") { - imageNameOnBlob = fmt.Sprintf("%s.vhd", imageNameOnBlob) - } - tmpFile := fmt.Sprintf("%s/%s", tmpPath, imageNameOnBlob) - defer os.Remove(tmpFile) - f, err := os.Create(tmpFile) - if err != nil { - return "", errors.Wrap(err, "os.Create(tmpFile)") - } - defer f.Close() - - // 下载占33% - r := multicloud.NewProgress(sizeBytes, 33, reader, callback) - if _, err := io.Copy(f, r); err != nil { - return "", errors.Wrap(err, "io.Copy(f, reader)") - } - - storageaccount, err := self.checkStorageAccount() - if err != nil { - return "", errors.Wrap(err, "self.checkStorageAccount") - } - - blobURI, err := storageaccount.UploadFile("image-cache", tmpFile, callback) - if err != nil { - return "", errors.Wrap(err, "storageaccount.UploadFile") - } - - // size, _ := meta.Int("size") - - img, err := self.region.CreateImageByBlob(image.ImageId, image.OsType, blobURI, int32(sizeBytes>>30)) - if err != nil { - return "", errors.Wrap(err, "CreateImageByBlob") - } - if callback != nil { - callback(100) - } - return img.GetGlobalId(), nil -} - -func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - if image, err := self.region.CreateImage(snapshotId, imageName, osType, imageDesc); err != nil { - return nil, err - } else { - image.storageCache = self - return image, nil - } -} - -func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return self.downloadImage(userCred, imageId, extId, path) -} - -func (self *SStoragecache) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - // TODO: need to fix scenarios where image is a public image - // XXX Qiu Jian - if image, err := self.region.getPrivateImage(extId); err != nil { - return nil, err - } else if snapshotId := image.Properties.StorageProfile.OsDisk.Snapshot.ID; len(snapshotId) == 0 { - return nil, cloudprovider.ErrNotFound - } else if uri, err := self.region.GrantAccessSnapshot(snapshotId); err != nil { - return nil, err - } else if resp, err := http.Get(uri); err != nil { - return nil, err - } else { - tmpImageFile, err := ioutil.TempFile(path, "temp") - if err != nil { - return nil, err - } - defer tmpImageFile.Close() - defer os.Remove(tmpImageFile.Name()) - { - sf := fileutils2.NewSparseFileWriter(tmpImageFile) - data := make([]byte, DefaultReadBlockSize) - written := int64(0) - for { - n, err := resp.Body.Read(data) - if n > 0 { - if n, err := sf.Write(data); err != nil { - return nil, err - } else { - written += int64(n) - } - } else if err == io.EOF { - if written <= resp.ContentLength { - return nil, fmt.Errorf("got eof: expecting %d bytes, got %d", resp.ContentLength, written) - } - break - } else { - return nil, err - } - } - if err := sf.PreClose(); err != nil { - return nil, err - } - } - - if _, err := tmpImageFile.Seek(0, os.SEEK_SET); err != nil { - return nil, errors.Wrap(err, "seek") - } - s := auth.GetAdminSession(context.Background(), options.Options.Region) - params := jsonutils.Marshal(map[string]string{"image_id": imageId, "disk-format": "raw"}) - if result, err := modules.Images.Upload(s, params, tmpImageFile, resp.ContentLength); err != nil { - return nil, err - } else { - return result, nil - } - - } -} - -func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storageCache := region.getStoragecache() - return []cloudprovider.ICloudStoragecache{storageCache}, nil -} diff --git a/pkg/multicloud/azure/subscription.go b/pkg/multicloud/azure/subscription.go deleted file mode 100644 index c5521ac945..0000000000 --- a/pkg/multicloud/azure/subscription.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "net/url" - - api "yunion.io/x/onecloud/pkg/apis/compute" -) - -type SSubscription struct { - SubscriptionId string `json:"subscriptionId"` - State string - DisplayName string `json:"displayName"` -} - -func (self *SSubscription) GetHealthStatus() string { - if self.State == "Enabled" { - return api.CLOUD_PROVIDER_HEALTH_NORMAL - } - return api.CLOUD_PROVIDER_HEALTH_SUSPENDED -} - -func (self *SAzureClient) ListSubscriptions() ([]SSubscription, error) { - result := []SSubscription{} - err := self.list("subscriptions", url.Values{}, &result) - return result, err -} diff --git a/pkg/multicloud/azure/usage.go b/pkg/multicloud/azure/usage.go deleted file mode 100644 index 041611f52e..0000000000 --- a/pkg/multicloud/azure/usage.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type UsageName struct { - Value string - LocalizedValue string -} - -// {"value":[{"unit":"Count","currentValue":0,"limit":250,"name":{"value":"StorageAccounts","localizedValue":"Storage Accounts"}}]} -type SUsage struct { - Unit string - CurrentValue int - Limit int - Name UsageName -} - -func (u *SUsage) GetGlobalId() string { - return strings.ToLower(u.Name.Value) -} - -func (u *SUsage) GetQuotaType() string { - return u.Name.Value -} - -func (u *SUsage) GetDesc() string { - return u.Name.LocalizedValue -} - -func (u *SUsage) GetMaxQuotaCount() int { - return u.Limit -} - -func (u *SUsage) GetCurrentQuotaUsedCount() int { - return u.CurrentValue -} - -func (region *SRegion) GetUsage(resourceType string) ([]SUsage, error) { - usage := []SUsage{} - resource := fmt.Sprintf("%s/locations/%s/usages", resourceType, region.Name) - err := region.client.list(resource, url.Values{}, &usage) - if err != nil { - return nil, errors.Wrapf(err, "ListAll(%s)", resource) - } - return usage, nil -} - -func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { - ret := []cloudprovider.ICloudQuota{} - for _, resourceType := range []string{"Microsoft.Network", "Microsoft.Storage", "Microsoft.Compute"} { - usages, err := region.GetUsage(resourceType) - if err != nil { - return nil, errors.Wrap(err, "GetUsage") - } - for i := range usages { - ret = append(ret, &usages[i]) - } - } - return ret, nil -} diff --git a/pkg/multicloud/azure/vpc.go b/pkg/multicloud/azure/vpc.go deleted file mode 100644 index 9180723eca..0000000000 --- a/pkg/multicloud/azure/vpc.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type AddressSpace struct { - AddressPrefixes []string `json:"addressPrefixes,omitempty"` -} - -type SubnetPropertiesFormat struct { - AddressPrefix string `json:"addressPrefix,omitempty"` - //ProvisioningState string -} - -type VirtualNetworkPropertiesFormat struct { - ProvisioningState string - Status string - VirtualNetworkSiteName string - AddressSpace AddressSpace `json:"addressSpace,omitempty"` - Subnets []SNetwork `json:"subnets,omitempty"` -} - -type SVpc struct { - multicloud.SVpc - multicloud.AzureTags - region *SRegion - - ID string - Name string - Etag string - Type string - Location string - Properties VirtualNetworkPropertiesFormat `json:"properties,omitempty"` -} - -func (self *SVpc) GetTags() (map[string]string, error) { - return self.Tags, nil -} - -func (self *SVpc) GetId() string { - return self.ID -} - -func (self *SVpc) GetName() string { - return self.Name -} - -func (self *SVpc) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SVpc) IsEmulated() bool { - return false -} - -func (self *SVpc) GetIsDefault() bool { - return true -} - -func (self *SVpc) GetCidrBlock() string { - if len(self.Properties.AddressSpace.AddressPrefixes) > 0 { - return self.Properties.AddressSpace.AddressPrefixes[0] - } - return "" -} - -func (self *SVpc) Delete() error { - return self.region.DeleteVpc(self.ID) -} - -func (self *SRegion) DeleteVpc(vpcId string) error { - return self.del(vpcId) -} - -func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := self.region.ListSecgroups() - if err != nil { - return nil, errors.Wrapf(err, "ListSecgroups") - } - ret := []cloudprovider.ICloudSecurityGroup{} - for i := range secgroups { - secgroups[i].region = self.region - ret = append(ret, &secgroups[i]) - } - return ret, nil -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - rts := []cloudprovider.ICloudRouteTable{} - return rts, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { - wire := self.getWire() - if wire.GetGlobalId() != wireId { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, wireId) - } - return wire, nil -} - -func (self *SVpc) getWire() *SWire { - zone := self.region.getZone() - return &SWire{zone: zone, vpc: self} -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - return []cloudprovider.ICloudWire{self.getWire()}, nil -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetStatus() string { - if strings.ToLower(self.Properties.ProvisioningState) == "succeeded" { - return "available" - } - return "disabled" -} - -func (region *SRegion) GetVpc(vpcId string) (*SVpc, error) { - vpc := SVpc{region: region} - return &vpc, region.get(vpcId, url.Values{}, &vpc) -} - -func (self *SVpc) Refresh() error { - vpc, err := self.region.GetVpc(self.ID) - if err != nil { - return err - } - return jsonutils.Update(self, vpc) -} - -func (self *SVpc) GetNetworks() []SNetwork { - return self.Properties.Subnets -} - -func (self *SRegion) GetNetwork(networkId string) (*SNetwork, error) { - network := SNetwork{} - return &network, self.get(networkId, url.Values{}, &network) -} diff --git a/pkg/multicloud/azure/waf.go b/pkg/multicloud/azure/waf.go deleted file mode 100644 index 3eb8c9b1ae..0000000000 --- a/pkg/multicloud/azure/waf.go +++ /dev/null @@ -1,656 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SMatchvariable struct { - Variablename string `json:"variableName"` - Selector string `json:"selector"` -} - -type SMatchcondition struct { - Matchvariables []SMatchvariable `json:"matchVariables"` - Operator string `json:"operator"` - Negationconditon bool `json:"negationConditon"` - Matchvalues []string `json:"matchValues"` - Transforms []string `json:"transforms"` -} - -type CustomRule struct { - waf *SAppGatewayWaf - - Name string `json:"name"` - Priority int `json:"priority"` - Ruletype string `json:"ruleType"` - //RateLimitThreshold *int `json:"rateLimitThreshold"` - Matchconditions []SMatchcondition `json:"matchConditions"` - Action string `json:"action"` -} - -func (self *CustomRule) GetName() string { - return self.Name -} - -func (self *CustomRule) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.waf.GetGlobalId(), self.GetName()) -} - -func (self *CustomRule) GetDesc() string { - return "" -} - -func (self *CustomRule) GetPriority() int { - return self.Priority -} - -func (self *CustomRule) Delete() error { - rules := []CustomRule{} - for _, rule := range self.waf.Properties.Customrules { - if rule.Name != self.Name { - rules = append(rules, rule) - } - } - self.waf.Properties.Customrules = rules - return self.waf.region.update(jsonutils.Marshal(self.waf), nil) -} - -func wafMatchFieldAndKeyLocal2Cloud(opts cloudprovider.SWafStatement) ([]SMatchvariable, error) { - ret := []SMatchvariable{} - switch opts.MatchField { - case cloudprovider.WafMatchFieldQuery: - ret = append(ret, SMatchvariable{ - Variablename: "QueryString", - }) - case cloudprovider.WafMatchFieldMethod: - ret = append(ret, SMatchvariable{ - Variablename: "RequestMethod", - }) - case cloudprovider.WafMatchFiledUriPath: - ret = append(ret, SMatchvariable{ - Variablename: "RequestUri", - }) - case cloudprovider.WafMatchFiledHeader: - ret = append(ret, SMatchvariable{ - Variablename: "RequestHeaders", - Selector: opts.MatchFieldKey, - }) - case cloudprovider.WafMatchFiledPostArgs: - ret = append(ret, SMatchvariable{ - Variablename: "PostArgs", - Selector: opts.MatchFieldKey, - }) - case cloudprovider.WafMatchFieldBody: - ret = append(ret, SMatchvariable{ - Variablename: "RequestBody", - }) - case cloudprovider.WafMatchFiledCookie: - ret = append(ret, SMatchvariable{ - Variablename: "RequestCookies", - Selector: opts.MatchFieldKey, - }) - default: - return ret, fmt.Errorf("unsupported match filed %s", opts.MatchField) - } - return ret, nil -} - -func wafMatchFieldAndKeyCloud2Local(v SMatchvariable) (cloudprovider.TWafMatchField, string, error) { - switch v.Variablename { - case "QueryString": - return cloudprovider.WafMatchFieldQuery, v.Selector, nil - case "RequestMethod": - return cloudprovider.WafMatchFieldMethod, "", nil - case "RequestUri": - return cloudprovider.WafMatchFiledUriPath, "", nil - case "RequestHeaders": - return cloudprovider.WafMatchFiledHeader, v.Selector, nil - case "PostArgs": - return cloudprovider.WafMatchFiledPostArgs, v.Selector, nil - case "RequestBody": - return cloudprovider.WafMatchFieldBody, "", nil - case "RequestCookies": - return cloudprovider.WafMatchFiledCookie, v.Selector, nil - case "RemoteAddr": - return cloudprovider.WafMatchFiledHeader, v.Selector, nil - default: - return "", "", fmt.Errorf("invalid variablename %s", v.Variablename) - } -} - -func wafStatementLocal2Cloud(opts cloudprovider.SWafStatement) (SMatchcondition, error) { - ret := SMatchcondition{} - if opts.Transformations != nil { - for _, tran := range *opts.Transformations { - ret.Transforms = append(ret.Transforms, string(tran)) - } - } - if opts.MatchFieldValues != nil { - ret.Matchvalues = *opts.MatchFieldValues - } - ret.Negationconditon = opts.Negation - ret.Operator = string(opts.Operator) - var err error - switch opts.Type { - case cloudprovider.WafStatementTypeIPSet: - ret.Operator = "IPMatch" - ret.Matchvariables = []SMatchvariable{ - SMatchvariable{ - Variablename: "RemoteAddr", - }, - } - case cloudprovider.WafStatementTypeGeoMatch: - ret.Operator = "GeoMatch" - if len(opts.ForwardedIPHeader) == 0 { - ret.Matchvariables = []SMatchvariable{ - SMatchvariable{ - Variablename: "RemoteAddr", - }, - } - } else { - ret.Matchvariables = []SMatchvariable{ - SMatchvariable{ - Variablename: "RequestHeaders", - Selector: opts.ForwardedIPHeader, - }, - } - } - case cloudprovider.WafStatementTypeSize: - switch opts.Operator { - case "LT": - ret.Operator = "LessThan" - case "LE": - ret.Operator = "LessThanOrEqual" - case "GT": - ret.Operator = "GreaterThan" - default: - return ret, fmt.Errorf("invalid operator %s for %s", opts.Operator, opts.Type) - } - ret.Matchvariables, err = wafMatchFieldAndKeyLocal2Cloud(opts) - if err != nil { - return ret, errors.Wrapf(err, "wafMatchFieldAndKeyLocal2Cloud") - } - case cloudprovider.WafStatementTypeByteMatch: - switch opts.Operator { - case "Contains", "EndsWith", "Regex": - case "StartsWith": - ret.Operator = "BeginsWith" - case "Exactly": - ret.Operator = "Equal" - default: - return ret, fmt.Errorf("invalid operator %s for %s", opts.Operator, opts.Type) - } - ret.Matchvariables, err = wafMatchFieldAndKeyLocal2Cloud(opts) - if err != nil { - return ret, errors.Wrapf(err, "wafMatchFieldAndKeyLocal2Cloud") - } - } - return ret, nil -} - -func wafRuleLocal2Cloud(opts *cloudprovider.SWafRule) (*CustomRule, error) { - ret := &CustomRule{} - ret.Name = opts.Name - ret.Priority = opts.Priority - ret.Ruletype = "MatchRule" - ret.Matchconditions = []SMatchcondition{} - for _, s := range opts.Statements { - cds, err := wafStatementLocal2Cloud(s) - if err != nil { - return nil, errors.Wrapf(err, "wafStatementLocal2Cloud") - } - ret.Matchconditions = append(ret.Matchconditions, cds) - } - ret.Action = "Block" - if opts.Action != nil { - ret.Action = string(opts.Action.Action) - } - return ret, nil -} - -func (self *CustomRule) Update(opts *cloudprovider.SWafRule) error { - rules := []CustomRule{} - for _, rule := range self.waf.Properties.Customrules { - if rule.Name != self.Name { - rules = append(rules, rule) - } else { - rule, err := wafRuleLocal2Cloud(opts) - if err != nil { - return errors.Wrapf(err, "wafRuleLocal2Cloud") - } - rules = append(rules, *rule) - } - } - self.waf.Properties.Customrules = rules - return self.waf.region.update(jsonutils.Marshal(self.waf), nil) -} - -func (self *CustomRule) GetAction() *cloudprovider.DefaultAction { - return &cloudprovider.DefaultAction{ - Action: cloudprovider.TWafAction(self.Action), - } -} - -func (self *CustomRule) GetStatementCondition() cloudprovider.TWafStatementCondition { - return cloudprovider.WafStatementConditionAnd -} - -func (self *CustomRule) GetStatements() ([]cloudprovider.SWafStatement, error) { - ret := []cloudprovider.SWafStatement{} - for _, condition := range self.Matchconditions { - trans := cloudprovider.TextTransformations{} - for _, tran := range condition.Transforms { - trans = append(trans, cloudprovider.TWafTextTransformation(tran)) - } - values := cloudprovider.TWafMatchFieldValues(condition.Matchvalues) - statement := cloudprovider.SWafStatement{ - Negation: condition.Negationconditon, - Transformations: &trans, - MatchFieldValues: &values, - } - switch condition.Operator { - case "IPMatch": - statement.Type = cloudprovider.WafStatementTypeIPSet - case "GeoMatch": - statement.Type = cloudprovider.WafStatementTypeGeoMatch - case "LessThan": - statement.Type = cloudprovider.WafStatementTypeSize - statement.Operator = cloudprovider.WafOperatorLT - case "LessThanOrEqual": - statement.Type = cloudprovider.WafStatementTypeSize - statement.Operator = cloudprovider.WafOperatorLE - case "GreaterThan": - statement.Type = cloudprovider.WafStatementTypeSize - statement.Operator = cloudprovider.WafOperatorGT - case "BeginsWith": - statement.Type = cloudprovider.WafStatementTypeByteMatch - statement.Operator = cloudprovider.WafOperatorStartsWith - case "Contains", "EndsWith", "Regex": - statement.Type = cloudprovider.WafStatementTypeByteMatch - statement.Operator = cloudprovider.TWafOperator(condition.Operator) - case "Equal": - statement.Type = cloudprovider.WafStatementTypeByteMatch - statement.Operator = cloudprovider.WafOperatorExactly - default: - statement.Type = cloudprovider.WafStatementTypeByteMatch - } - - var err error - for _, v := range condition.Matchvariables { - statement.MatchField, statement.MatchFieldKey, err = wafMatchFieldAndKeyCloud2Local(v) - if err != nil { - log.Errorf("wafMatchFieldAndKeyCloud2Local %s error: %v", v, err) - continue - } - ret = append(ret, statement) - } - } - return ret, nil -} - -type ManagedRule struct { - Rulesettype string `json:"ruleSetType"` - Rulesetversion string `json:"ruleSetVersion"` -} - -type ManagedRules struct { - waf *SAppGatewayWaf - Managedrulesets []ManagedRule `json:"managedRuleSets"` -} - -func (self *ManagedRules) GetName() string { - return fmt.Sprintf("%s Managed rules", self.waf.GetName()) -} - -func (self *ManagedRules) GetGlobalId() string { - return self.waf.GetGlobalId() -} - -func (self *ManagedRules) GetDesc() string { - return "" -} - -func (self *ManagedRules) GetPriority() int { - return 0 -} - -func (self *ManagedRules) GetAction() *cloudprovider.DefaultAction { - return nil -} - -func (self *ManagedRules) Delete() error { - return cloudprovider.ErrNotSupported -} - -func (self *ManagedRules) Update(opts *cloudprovider.SWafRule) error { - rules := []ManagedRule{} - for _, s := range opts.Statements { - if len(s.ManagedRuleGroupName) == 0 { - return fmt.Errorf("missing managed rule group name") - } - names := strings.Split(s.ManagedRuleGroupName, "_") - if len(names) != 2 { - return fmt.Errorf("invalid managed rule group name %s", s.ManagedRuleGroupName) - } - rules = append(rules, ManagedRule{ - Rulesettype: names[0], - Rulesetversion: names[1], - }) - } - if len(rules) == 0 { - return fmt.Errorf("missing statements") - } - self.waf.Properties.Managedrules = ManagedRules{ - Managedrulesets: rules, - } - return self.waf.region.update(jsonutils.Marshal(self.waf), nil) -} - -func (self *ManagedRules) GetStatementCondition() cloudprovider.TWafStatementCondition { - return cloudprovider.WafStatementConditionAnd -} - -func (self *ManagedRules) GetStatements() ([]cloudprovider.SWafStatement, error) { - ret := []cloudprovider.SWafStatement{} - for i := range self.Managedrulesets { - ruleGroupName := fmt.Sprintf("%s_%s", self.Managedrulesets[i].Rulesettype, self.Managedrulesets[i].Rulesetversion) - ret = append(ret, cloudprovider.SWafStatement{ - ManagedRuleGroupName: ruleGroupName, - Type: cloudprovider.WafStatementTypeManagedRuleGroup, - RuleGroupId: ruleGroupName, - }) - } - return ret, nil -} - -type SAppGatewayWaf struct { - multicloud.SResourceBase - multicloud.AzureTags - region *SRegion - - Name string `json:"name"` - ID string `json:"id"` - Type string `json:"type"` - Location string `json:"location"` - Properties struct { - ApplicationGateways []SApplicationGateway - HttpListeners []struct { - Id string - } - PathBasedRules []struct { - Id string - } - Resourcestate string `json:"resourceState"` - Provisioningstate string `json:"provisioningState"` - Policysettings struct { - State string `json:"state"` - Mode string `json:"mode"` - Maxrequestbodysizeinkb int `json:"maxRequestBodySizeInKb"` - Fileuploadlimitinmb int `json:"fileUploadLimitInMb"` - Requestbodycheck bool `json:"requestBodyCheck"` - } `json:"policySettings"` - Customrules []CustomRule `json:"customRules"` - Managedrules ManagedRules `json:"managedRules"` - } `json:"properties"` -} - -func (self *SAppGatewayWaf) GetEnabled() bool { - return self.Properties.Policysettings.State == "Enabled" -} - -func (self *SAppGatewayWaf) GetName() string { - return self.Name -} - -func (self *SAppGatewayWaf) GetId() string { - return self.ID -} - -func (self *SAppGatewayWaf) GetGlobalId() string { - return strings.ToLower(self.ID) -} - -func (self *SAppGatewayWaf) Delete() error { - return self.region.del(self.ID) -} - -func (self *SAppGatewayWaf) GetWafType() cloudprovider.TWafType { - return cloudprovider.WafTypeAppGateway -} - -func (self *SAppGatewayWaf) AddRule(opts *cloudprovider.SWafRule) (cloudprovider.ICloudWafRule, error) { - rule, err := wafRuleLocal2Cloud(opts) - if err != nil { - return nil, errors.Wrapf(err, "wafRuleLocal2Cloud") - } - rule.waf = self - self.Properties.Customrules = append(self.Properties.Customrules, *rule) - err = self.region.update(jsonutils.Marshal(self), nil) - if err != nil { - return nil, errors.Wrapf(err, "update") - } - return rule, nil -} - -func (self *SAppGatewayWaf) GetStatus() string { - switch self.Properties.Provisioningstate { - case "Deleting": - return api.WAF_STATUS_DELETING - case "Failed": - return api.WAF_STATUS_CREATE_FAILED - case "Succeeded": - return api.WAF_STATUS_AVAILABLE - case "Updating": - return api.WAF_STATUS_UPDATING - default: - return self.Properties.Provisioningstate - } -} - -func (self *SAppGatewayWaf) GetRules() ([]cloudprovider.ICloudWafRule, error) { - ret := []cloudprovider.ICloudWafRule{} - for i := range self.Properties.Customrules { - self.Properties.Customrules[i].waf = self - ret = append(ret, &self.Properties.Customrules[i]) - } - self.Properties.Managedrules.waf = self - ret = append(ret, &self.Properties.Managedrules) - return ret, nil -} - -func (self *SAppGatewayWaf) Refresh() error { - waf, err := self.region.GetAppGatewayWaf(self.ID) - if err != nil { - return errors.Wrapf(err, "GetAppGatewayWa") - } - return jsonutils.Update(self, waf) -} - -func (self *SAppGatewayWaf) GetDefaultAction() *cloudprovider.DefaultAction { - return &cloudprovider.DefaultAction{ - Action: cloudprovider.TWafAction(self.Properties.Policysettings.Mode), - } -} - -func (self *SRegion) ListAppWafs() ([]SAppGatewayWaf, error) { - ret := []SAppGatewayWaf{} - err := self.list("Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies", url.Values{}, &ret) - if err != nil { - return nil, errors.Wrapf(err, "list") - } - return ret, nil -} - -type SAppWafRuleGroup struct { - Name string `json:"name"` - ID string `json:"id"` - Type string `json:"type"` - Properties struct { - Provisioningstate string `json:"provisioningState"` - Rulesettype string `json:"ruleSetType"` - Rulesetversion string `json:"ruleSetVersion"` - Rulegroups []struct { - Rulegroupname string `json:"ruleGroupName"` - Description string `json:"description"` - Rules []struct { - Ruleid int `json:"ruleId"` - Description string `json:"description"` - } `json:"rules"` - } `json:"ruleGroups"` - } `json:"properties"` -} - -func (self *SRegion) CreateICloudWafInstance(opts *cloudprovider.WafCreateOptions) (cloudprovider.ICloudWafInstance, error) { - switch opts.Type { - case cloudprovider.WafTypeAppGateway: - return self.CreateAppWafInstance(opts.Name, opts.DefaultAction) - default: - return nil, errors.Wrapf(cloudprovider.ErrNoSuchProvder, "invalid waf type %s", opts.Type) - } -} - -func (self *SRegion) GetICloudWafInstanceById(id string) (cloudprovider.ICloudWafInstance, error) { - if strings.Contains(id, "microsoft.network/applicationgatewaywebapplicationfirewallpolicies") { - return self.GetAppGatewayWaf(id) - } - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, id) -} - -func (self *SRegion) CreateAppWafInstance(name string, action *cloudprovider.DefaultAction) (*SAppGatewayWaf, error) { - mode := cloudprovider.WafActionDetection - if action != nil { - switch action.Action { - case cloudprovider.WafActionDetection, cloudprovider.WafActionPrevention: - mode = action.Action - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "invalid action %s", action.Action) - } - } - params := map[string]interface{}{ - "Type": "Microsoft.Network/applicationGatewayWebApplicationFirewallPolicies", - "Name": name, - "Location": self.Name, - "properties": map[string]interface{}{ - "customRules": []string{}, - "policySettings": map[string]interface{}{ - "fileUploadLimitInMb": 100, - "maxRequestBodySizeInKb": 128, - "mode": mode, - "requestBodyCheck": true, - "state": "Enabled", - }, - "managedRules": map[string]interface{}{ - "exclusions": []string{}, - "managedRuleSets": []map[string]interface{}{ - map[string]interface{}{ - "ruleSetType": "OWASP", - "ruleSetVersion": "3.1", - "ruleGroupOverrides": []string{}, - }, - }, - }, - }, - } - ret := &SAppGatewayWaf{region: self} - err := self.create("", jsonutils.Marshal(params), ret) - if err != nil { - return nil, err - } - return ret, nil -} - -func (self *SRegion) GetAppGatewayWaf(id string) (*SAppGatewayWaf, error) { - res := &SAppGatewayWaf{region: self} - return res, self.get(id, nil, &res) -} - -func (self *SRegion) ListAppWafManagedRuleGroup() ([]SAppWafRuleGroup, error) { - ret := []SAppWafRuleGroup{} - err := self.list("Microsoft.Network/applicationGatewayAvailableWafRuleSets", url.Values{}, &ret) - if err != nil { - return nil, errors.Wrapf(err, "list") - } - return ret, nil -} - -func (self *SRegion) GetICloudWafInstances() ([]cloudprovider.ICloudWafInstance, error) { - wafs, err := self.ListAppWafs() - if err != nil { - return nil, errors.Wrapf(err, "ListAppWafs") - } - ret := []cloudprovider.ICloudWafInstance{} - for i := range wafs { - wafs[i].region = self - ret = append(ret, &wafs[i]) - } - return ret, nil -} - -func (self *SAppGatewayWaf) GetCloudResources() ([]cloudprovider.SCloudResource, error) { - ret := []cloudprovider.SCloudResource{} - for _, ag := range self.Properties.ApplicationGateways { - ret = append(ret, cloudprovider.SCloudResource{ - Id: ag.Id, - Name: ag.Id[strings.LastIndex(ag.Id, "/")+1:], - Type: "Application Gateway", - CanDissociate: true, - }) - } - for _, lis := range self.Properties.HttpListeners { - ret = append(ret, cloudprovider.SCloudResource{ - Id: lis.Id, - Name: lis.Id[strings.LastIndex(lis.Id, "/")+1:], - Type: "HTTP Listener", - CanDissociate: true, - }) - } - for _, route := range self.Properties.PathBasedRules { - ret = append(ret, cloudprovider.SCloudResource{ - Id: route.Id, - Name: route.Id[strings.LastIndex(route.Id, "/")+1:], - Type: "Route Path", - CanDissociate: true, - }) - - } - return ret, nil -} - -func (self *SAppGatewayWaf) SetTags(tags map[string]string, replace bool) error { - if !replace { - for k, v := range self.Tags { - if _, ok := tags[k]; !ok { - tags[k] = v - } - } - } - _, err := self.region.client.SetTags(self.ID, tags) - if err != nil { - return errors.Wrapf(err, "SetTags") - } - return nil -} diff --git a/pkg/multicloud/azure/web_app.go b/pkg/multicloud/azure/web_app.go deleted file mode 100644 index 304769a7dd..0000000000 --- a/pkg/multicloud/azure/web_app.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SAppSite struct { - multicloud.SResourceBase - multicloud.AzureTags - region *SRegion - appServicePlan *SAppServicePlan - - Properties SAppSiteProperties - Id string - Name string - Kind string - Location string - Type string - - stack *string -} - -type SAppSiteProperties struct { - AvailabilityState string - DefaultHostName string - Enabled bool - EnabledHostNames []string - HostNameSslStates []SHostNameSslState - HostNames []string - HttpsOnly bool - OutboundIpAddresses string - ResourceGroup string - ServerFarmId string - SiteConfig SSiteConfig - State string -} - -type SSiteConfig struct { - // TODO -} - -type SHostNameSslState struct { - HostType string - Name string - SslState string - Thumbprint string - ToUpdate bool - VirtualIP string -} - -func (r *SRegion) GetAppSites() ([]SAppSite, error) { - result := []SAppSite{} - resource := "Microsoft.Web/sites" - err := r.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) - if err != nil { - return nil, err - } - for i := range result { - result[i].region = r - } - return result, nil -} - -func (r *SRegion) GetICloudApps() ([]cloudprovider.ICloudApp, error) { - ass, err := r.GetAppSites() - if err != nil { - return nil, err - } - apps := make([]cloudprovider.ICloudApp, 0, len(ass)) - for i := range ass { - apps = append(apps, &SApp{ - SAppSite: ass[i], - }) - } - return apps, nil -} - -func (r *SRegion) GetICloudAppById(id string) (cloudprovider.ICloudApp, error) { - as, err := r.GetAppSite(id) - if err != nil { - return nil, err - } - return &SApp{ - SAppSite: *as, - }, nil -} - -func (as *SAppSite) GetSlots() ([]SAppSite, error) { - result := []SAppSite{} - resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/slots", as.region.client.subscriptionId, as.Properties.ResourceGroup, as.Name) - err := as.region.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) - if err != nil { - return nil, err - } - return result, nil -} - -func (r *SRegion) GetAppSite(siteId string) (*SAppSite, error) { - as := &SAppSite{region: r} - params := url.Values{"api-version": []string{"2019-08-01"}} - return as, r.get(siteId, params, as) -} - -func (as *SAppSite) GetAppServicePlan() (*SAppServicePlan, error) { - if as.appServicePlan != nil { - return as.appServicePlan, nil - } - plan, err := as.region.GetAppServicePlanWithCache(as.Properties.ServerFarmId) - if err != nil { - return nil, errors.Wrap(err, "unable to get AppServicePlan") - } - as.appServicePlan = plan - return plan, nil -} - -type SDeployment struct { - ID string - Name string - Kind string - Type string - Properties SDeploymentProperties -} - -type SDeploymentProperties struct { - Active bool - Author string - AuthorEmail string - Deployer string - Details string - EndTime string - Message string - StartTime string - Status string -} - -func (as *SAppSite) GetDeployments() ([]SDeployment, error) { - result := []SDeployment{} - resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/deployments", as.region.client._subscriptionId(), as.Properties.ResourceGroup, as.Name) - err := as.region.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) - if err != nil { - return nil, err - } - return result, nil -} - -type SStringDictionary struct { - Id string - Kind string - Name string - Type string - Properties map[string]string -} - -func (as *SAppSite) GetStack() (string, error) { - if as.stack != nil { - return *as.stack, nil - } - // result := SStringDictionary{} - resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/config/metadata", as.region.client.subscriptionId, as.Properties.ResourceGroup, as.Name) - - params := url.Values{} - params.Set("api-version", "2019-08-01") - path := resource + "/list" - response, err := as.region.client.jsonRequest("POST", path, nil, params, true) - if err != nil { - return "", err - } - stack, err := response.GetString("properties", "CURRENT_STACK") - if err != nil { - return "", errors.Wrapf(err, "unable to parse response correctly, response: %s", response) - } - as.stack = &stack - return stack, nil -} - -func (as *SAppSite) GetId() string { - return as.Id -} - -func (as *SAppSite) GetName() string { - return as.Name -} - -func (as *SAppSite) GetGlobalId() string { - return strings.ToLower(as.Id) -} - -func (as *SAppSite) GetStatus() string { - return "ready" -} - -func (as *SAppSite) GetProjectId() string { - return strings.ToLower(as.Properties.ResourceGroup) -} - -type SApp struct { - SAppSite -} - -type SAppEnvironment struct { - multicloud.SResourceBase - multicloud.AzureTags - SAppSite -} - -func (ae *SAppEnvironment) GetInstanceType() (string, error) { - asp, err := ae.SAppSite.GetAppServicePlan() - if err != nil { - return "", err - } - return asp.Sku.Name, nil -} - -func (ae *SAppEnvironment) GetInstanceNumber() (int, error) { - asp, err := ae.SAppSite.GetAppServicePlan() - if err != nil { - return 0, err - } - return asp.Sku.Capacity, nil -} - -func (a *SApp) GetEnvironments() ([]cloudprovider.ICloudAppEnvironment, error) { - sites, err := a.SAppSite.GetSlots() - if err != nil { - return nil, err - } - aes := make([]cloudprovider.ICloudAppEnvironment, 0, len(sites)+1) - aes = append(aes, &SAppEnvironment{ - SAppSite: a.SAppSite, - }) - for i := range sites { - sites[i].region = a.region - aes = append(aes, &SAppEnvironment{ - SAppSite: sites[i], - }) - } - return aes, nil -} - -var techStacks = map[string]string{ - "dotnet": ".NET", - "dotnetcore": ".NET Core", - "aspdotnet": "ASP.NET", - "node": "Node", - "python": "Python", - "php": "PHP", - "ruby": "Ruby", - "java": "Java", - "javacontainers": "Jave Containers", -} - -func (a *SApp) GetTechStack() string { - if strings.Contains(a.SAppSite.Kind, "container") { - return "Docker container" - } - stack, err := a.GetStack() - if err != nil { - log.Errorf("unable to GetStack: %v", err) - } - if s, ok := techStacks[stack]; ok { - return s - } - return stack -} - -func (a *SApp) GetType() string { - return "web" -} - -func (a *SApp) GetKind() string { - return a.Kind -} - -func (a *SApp) GetOsType() cloudprovider.TOsType { - if strings.Contains(a.Kind, "linux") { - return cloudprovider.OsTypeLinux - } - return cloudprovider.OsTypeWindows -} - -func (self *SApp) SetTags(tags map[string]string, replace bool) error { - if !replace { - for k, v := range self.Tags { - if _, ok := tags[k]; !ok { - tags[k] = v - } - } - } - _, err := self.region.client.SetTags(self.Id, tags) - if err != nil { - return errors.Wrapf(err, "SetTags") - } - return nil -} diff --git a/pkg/multicloud/azure/wire.go b/pkg/multicloud/azure/wire.go deleted file mode 100644 index 74220303cb..0000000000 --- a/pkg/multicloud/azure/wire.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.AzureTags - - zone *SZone - vpc *SVpc - inetworks []cloudprovider.ICloudNetwork -} - -func (self *SWire) GetId() string { - return fmt.Sprintf("%s/%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId, self.vpc.GetName()) -} - -func (self *SWire) GetGlobalId() string { - return strings.ToLower(self.GetId()) -} - -func (self *SWire) GetName() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.vpc.GetName()) -} - -func (self *SWire) IsEmulated() bool { - return true -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SRegion) CreateNetwork(vpcId, name string, cidr string, desc string) (*SNetwork, error) { - params := map[string]interface{}{ - "Name": name, - "Properties": map[string]interface{}{ - "AddressPrefix": cidr, - }, - } - resource := fmt.Sprintf("%s/subnets/%s", vpcId, name) - network := &SNetwork{} - resp, err := self.put(resource, jsonutils.Marshal(params)) - if err != nil { - return nil, errors.Wrapf(err, "put(%s)", resource) - } - err = resp.Unmarshal(network) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return network, nil -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - network, err := self.zone.region.CreateNetwork(self.vpc.ID, opts.Name, opts.Cidr, opts.Desc) - if err != nil { - return nil, err - } - network.wire = self - return network, 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() == strings.ToLower(netid) { - return networks[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, netid) -} - -func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - ret := []cloudprovider.ICloudNetwork{} - networks := self.vpc.GetNetworks() - for i := range networks { - networks[i].wire = self - ret = append(ret, &networks[i]) - } - return ret, nil -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - return self.zone -} diff --git a/pkg/multicloud/azure/zone.go b/pkg/multicloud/azure/zone.go deleted file mode 100644 index 7d0ad2813e..0000000000 --- a/pkg/multicloud/azure/zone.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 azure - -import ( - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SZone struct { - multicloud.SResourceBase - multicloud.AzureTags - region *SRegion - - Name string -} - -func (self *SZone) GetId() string { - return self.region.client.cpcfg.Id -} - -func (self *SZone) GetName() string { - return self.region.GetName() -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - return self.region.GetI18n() -} - -func (self *SZone) GetGlobalId() string { - return self.region.GetGlobalId() -} - -func (self *SZone) IsEmulated() bool { - return true -} - -func (self *SZone) GetStatus() string { - return api.ZONE_ENABLE -} - -func (self *SZone) Refresh() error { - // do nothing - return nil -} - -func (self *SZone) getHost() *SHost { - return &SHost{zone: self} -} - -func (self *SZone) getClassicHost() *SClassicHost { - return &SClassicHost{zone: self} -} - -func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SZone) ListStorageTypes() []SStorage { - storages := []SStorage{} - for _, storageType := range STORAGETYPES { - storage := SStorage{zone: self, storageType: storageType} - storages = append(storages, storage) - } - return storages -} - -func (self *SRegion) ListClassicStorageTypes() []SClassicStorage { - storages := []SClassicStorage{} - for _, storageType := range []string{STORAGE_LRS, STORAGE_GRS} { - storage := SClassicStorage{AccountType: storageType, region: self} - storages = append(storages, storage) - } - return storages -} - -func (self *SZone) GetIClassicStorages() []cloudprovider.ICloudStorage { - ret := []cloudprovider.ICloudStorage{} - storages := self.region.ListClassicStorageTypes() - for i := range storages { - ret = append(ret, &storages[i]) - } - return ret -} - -func (self *SZone) getIStorages() []cloudprovider.ICloudStorage { - ret := []cloudprovider.ICloudStorage{} - storages := self.ListStorageTypes() - for i := range storages { - storages[i].zone = self - ret = append(ret, &storages[i]) - } - return ret -} - -func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - ret := self.getIStorages() - ret = append(ret, self.GetIClassicStorages()...) - return ret, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storages, err := self.GetIStorages() - if err != nil { - return nil, errors.Wrapf(err, "GetIStorages") - } - for i := range storages { - if storages[i].GetGlobalId() == id { - return storages[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - hosts, err := self.GetIHosts() - if err != nil { - return nil, errors.Wrapf(err, "GetIHosts") - } - for i := range hosts { - if hosts[i].GetGlobalId() == id { - return hosts[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - return []cloudprovider.ICloudHost{self.getHost(), self.getClassicHost()}, nil -} - -func (self *SZone) GetIClassicWires() ([]cloudprovider.ICloudWire, error) { - wires := []cloudprovider.ICloudWire{} - classicVpcs, err := self.region.ListClassicVpcs() - if err != nil { - return nil, errors.Wrapf(err, "ListClassicVpcs") - } - for i := range classicVpcs { - classicVpcs[i].region = self.region - wire := &SClassicWire{vpc: &classicVpcs[i], zone: self} - wires = append(wires, wire) - } - return wires, nil -} - -func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { - vpcs, err := self.region.ListVpcs() - if err != nil { - return nil, errors.Wrapf(err, "ListVpcs") - } - wires := []cloudprovider.ICloudWire{} - for i := range vpcs { - vpcs[i].region = self.region - wire := &SWire{vpc: &vpcs[i], zone: self} - wires = append(wires, wire) - } - classWires, err := self.GetIClassicWires() - if err != nil { - return nil, errors.Wrapf(err, "GetIClassicWires") - } - wires = append(wires, classWires...) - return wires, nil -} diff --git a/pkg/multicloud/bingocloud/cluster.go b/pkg/multicloud/bingocloud/cluster.go deleted file mode 100644 index 9175f2314a..0000000000 --- a/pkg/multicloud/bingocloud/cluster.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SCluster struct { - multicloud.SResourceBase - multicloud.STagBase - - region *SRegion - - ClusterControllerSet []struct { - Address string - Role string - } - ClusterId string - ClusterName string - CreateVolumeMode string - ExtendDiskMode string - Hypervisor string - MaxVolumeStorage string - SchedPolicy string - Status string -} - -func (self *SCluster) GetGlobalId() string { - return self.ClusterId -} - -func (self *SCluster) GetId() string { - return self.ClusterId -} - -func (self *SCluster) GetName() string { - return self.ClusterName -} - -func (self *SCluster) GetStatus() string { - if self.Status == "available" { - return api.ZONE_ENABLE - } - return api.ZONE_DISABLE -} - -func (self *SCluster) GetI18n() cloudprovider.SModelI18nTable { - return cloudprovider.SModelI18nTable{} -} - -func (self *SCluster) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - clusters, err := self.GetClusters() - if err != nil { - return nil, errors.Wrapf(err, "GetClusters") - } - ret := []cloudprovider.ICloudZone{} - for i := range clusters { - clusters[i].region = self - ret = append(ret, &clusters[i]) - } - return ret, nil -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - zones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := range zones { - if zones[i].GetGlobalId() == id { - return zones[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SRegion) GetClusters() ([]SCluster, error) { - resp, err := self.invoke("DescribeClusters", nil) - if err != nil { - return nil, err - } - ret := []SCluster{} - return ret, resp.Unmarshal(&ret, "clusterSet") -} diff --git a/pkg/multicloud/bingocloud/disk.go b/pkg/multicloud/bingocloud/disk.go deleted file mode 100644 index f40fe484c6..0000000000 --- a/pkg/multicloud/bingocloud/disk.go +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "context" - "fmt" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDisk struct { - multicloud.BingoTags - multicloud.SDisk - - storage *SStorage - - AttachmentSet []AttachmentSet `json:"attachmentSet"` - AvailabilityZone string `json:"availabilityZone"` - CreateTime string `json:"createTime"` - Description string `json:"description"` - DetachBehavior string `json:"detachBehavior"` - Goal string `json:"goal"` - Iops string `json:"iops"` - IsDeductQuota string `json:"isDeductQuota"` - IsEncrypt string `json:"isEncrypt"` - IsForSleepInst string `json:"isForSleepInst"` - IsMirrorVolume string `json:"isMirrorVolume"` - IsMultiAttach string `json:"isMultiAttach"` - IsOneInst string `json:"isOneInst"` - IsRoot string `json:"isRoot"` - Location string `json:"location"` - MirrorFrom string `json:"mirrorFrom"` - MirrorProcess string `json:"mirrorProcess"` - MirrorStatus string `json:"mirrorStatus"` - NodeId string `json:"nodeId"` - Owner string `json:"owner"` - Passphrase string `json:"passphrase"` - Readonly string `json:"readonly"` - Size int `json:"size"` - SnapshotId string `json:"snapshotId"` - Status string `json:"status"` - StorageId string `json:"storageId"` - VolumeId string `json:"volumeId"` - VolumeName string `json:"volumeName"` -} - -type AttachmentSet struct { - AttachTime string `json:"attachTime"` - Cache string `json:"cache"` - DeleteOnTermination string `json:"deleteOnTermination"` - Device string `json:"device"` - InstanceId string `json:"instanceId"` - Status string `json:"status"` - VolumeId string `json:"volumeId"` -} - -func (self *SDisk) GetName() string { - return self.VolumeName -} - -func (self *SDisk) GetId() string { - return self.VolumeId -} - -func (self *SDisk) GetGlobalId() string { - return self.GetId() -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.storage, nil -} - -func (self *SDisk) GetIStorageId() string { - return self.StorageId -} - -func (self *SDisk) GetDiskFormat() string { - return "raw" -} - -func (self *SDisk) GetDiskSizeMB() int { - return self.Size * 1024 -} - -func (self *SDisk) GetIsAutoDelete() bool { - return self.IsRoot == "true" -} - -func (self *SDisk) GetTemplateId() string { - return "" -} - -func (self *SDisk) GetDiskType() string { - if self.IsRoot == "true" { - return api.DISK_TYPE_SYS - } - return api.DISK_TYPE_DATA -} - -func (self *SDisk) GetFsFormat() string { - return "" -} - -func (self *SDisk) GetIsNonPersistent() bool { - return false -} - -func (self *SDisk) GetDriver() string { - return "virtio" -} - -func (self *SDisk) GetCacheMode() string { - return "none" -} - -func (self *SDisk) GetMountpoint() string { - for _, att := range self.AttachmentSet { - return att.Device - } - return "" -} - -func (self *SDisk) GetAccessPath() string { - return "" -} - -func (self *SDisk) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { - return []string{}, nil -} - -func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", cloudprovider.ErrNotImplemented -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SDisk) GetStatus() string { - switch self.Status { - case "available", "in-use": - return api.DISK_READY - default: - return self.Status - } -} - -func (self *SRegion) GetDisks(id string, maxResult int, nextToken string) ([]SDisk, string, error) { - params := map[string]string{} - idx := 1 - if len(id) > 0 { - params[fmt.Sprintf("Filter.%d.Name", idx)] = "volume-id" - params[fmt.Sprintf("Filter.%d.Value.1", idx)] = id - idx++ - } - - if len(nextToken) > 0 { - params["nextToken"] = nextToken - } - if maxResult > 0 { - params["maxRecords"] = fmt.Sprintf("%d", maxResult) - } - resp, err := self.invoke("DescribeVolumes", params) - if err != nil { - return nil, "", err - } - ret := struct { - NextToken string - VolumeSet []SDisk - }{} - resp.Unmarshal(&ret) - return ret.VolumeSet, ret.NextToken, nil -} - -func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - part, nextToken, err := self.cluster.region.GetDisks("", MAX_RESULT, "") - if err != nil { - return nil, err - } - disks := []SDisk{} - disks = append(disks, part...) - for len(nextToken) > 0 { - part, nextToken, err = self.cluster.region.GetDisks("", MAX_RESULT, nextToken) - if err != nil { - return nil, err - } - disks = append(disks, part...) - } - ret := []cloudprovider.ICloudDisk{} - for i := range disks { - if disks[i].StorageId == self.StorageId { - disks[i].storage = self - ret = append(ret, &disks[i]) - } - } - return ret, nil -} - -func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - disk, err := self.cluster.region.GetDisk(id) - if err != nil { - return nil, err - } - if disk.StorageId != self.StorageId { - return nil, cloudprovider.ErrNotFound - } - disk.storage = self - return disk, nil -} - -func (self *SRegion) GetDisk(id string) (*SDisk, error) { - disks, _, err := self.GetDisks(id, 1, "") - if err != nil { - return nil, err - } - for i := range disks { - if disks[i].GetGlobalId() == id { - return &disks[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} diff --git a/pkg/multicloud/bingocloud/doc.go b/pkg/multicloud/bingocloud/doc.go deleted file mode 100644 index 05e67d3dc0..0000000000 --- a/pkg/multicloud/bingocloud/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud // import "yunion.io/x/onecloud/pkg/multicloud/bingocloud" diff --git a/pkg/multicloud/bingocloud/eip.go b/pkg/multicloud/bingocloud/eip.go deleted file mode 100644 index ac2e925de8..0000000000 --- a/pkg/multicloud/bingocloud/eip.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SEip struct { - multicloud.SEipBase - multicloud.BingoTags - - region *SRegion - - AddressId string - AddressType string - Bandtype string - Bandwidth int - CanAssociate bool - InstanceId string - Owner string - PublicIp string - SubnetId string - VpcId string -} - -func (self *SEip) GetId() string { - return self.PublicIp -} - -func (self *SEip) GetGlobalId() string { - return self.PublicIp -} - -func (self *SEip) GetName() string { - return self.PublicIp -} - -func (self *SEip) GetIpAddr() string { - return self.PublicIp -} - -func (self *SEip) GetMode() string { - return api.EIP_MODE_STANDALONE_EIP -} - -func (self *SEip) GetINetworkId() string { - return self.SubnetId -} - -func (self *SEip) GetAssociationType() string { - if len(self.InstanceId) > 0 { - return api.EIP_ASSOCIATE_TYPE_SERVER - } - return "" -} - -func (self *SEip) GetAssociationExternalId() string { - return self.InstanceId -} - -func (self *SEip) GetBandwidth() int { - return self.Bandwidth -} - -func (self *SEip) GetInternetChargeType() string { - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH -} - -func (self *SEip) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (self *SEip) Associate(conf *cloudprovider.AssociateConfig) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SEip) Dissociate() error { - return cloudprovider.ErrNotImplemented -} - -func (self *SEip) ChangeBandwidth(bw int) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SEip) GetProjectId() string { - return "" -} - -func (self *SEip) GetStatus() string { - return api.EIP_STATUS_READY -} - -func (self *SRegion) GetEips(ip, instanceId, nextToken string) ([]SEip, string, error) { - params := map[string]string{} - if len(ip) > 0 { - params["publicIp"] = ip - } - if len(nextToken) > 0 { - params["nextToken"] = nextToken - } - - idx := 1 - if len(instanceId) > 0 { - params[fmt.Sprintf("Filter.%d.Name", idx)] = "instance-id" - params[fmt.Sprintf("Filter.%d.Value.1", idx)] = instanceId - idx++ - } - - resp, err := self.invoke("DescribeAddresses", params) - if err != nil { - return nil, "", errors.Wrapf(err, "DescribeAddresses") - } - ret := struct { - AddressesSet []SEip - NextToken string - }{} - resp.Unmarshal(&ret) - return ret.AddressesSet, ret.NextToken, nil -} - -func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - part, nextToken, err := self.GetEips("", "", "") - if err != nil { - return nil, err - } - eips := []SEip{} - eips = append(eips, part...) - for len(nextToken) > 0 { - part, nextToken, err = self.GetEips("", "", nextToken) - if err != nil { - return nil, err - } - eips = append(eips, part...) - } - ret := []cloudprovider.ICloudEIP{} - for i := range eips { - eips[i].region = self - ret = append(ret, &eips[i]) - } - return ret, nil -} - -func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { - eips, _, err := self.GetEips(id, "", "") - if err != nil { - return nil, err - } - for i := range eips { - if eips[i].GetGlobalId() == id { - eips[i].region = self - return &eips[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} diff --git a/pkg/multicloud/bingocloud/image.go b/pkg/multicloud/bingocloud/image.go deleted file mode 100644 index 07f26687be..0000000000 --- a/pkg/multicloud/bingocloud/image.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "context" - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SImage struct { - multicloud.SResourceBase - multicloud.BingoTags - cache *SStoragecache - - imageInfo *imagetools.ImageInfo - - Architecture string `json:"architecture"` - BlockDeviceMapping string `json:"blockDeviceMapping"` - Bootloader string `json:"bootloader"` - Clonemode string `json:"clonemode"` - ClusterId string `json:"clusterId"` - Contentmode string `json:"contentmode"` - DefaultStorageId string `json:"defaultStorageId"` - Description string `json:"description"` - DiskBus string `json:"diskBus"` - ExtendDisk string `json:"extendDisk"` - Features string `json:"features"` - Hypervisor string `json:"hypervisor"` - ImageId string `json:"imageId"` - ImageLocation string `json:"imageLocation"` - ImageOwnerId string `json:"imageOwnerId"` - ImagePath string `json:"imagePath"` - ImageSize int64 `json:"imageSize"` - ImageState string `json:"imageState"` - ImageType string `json:"imageType"` - IsBareMetal string `json:"isBareMetal"` - IsPublic bool `json:"isPublic"` - KernelId string `json:"kernelId"` - Name string `json:"name"` - OsId string `json:"osId"` - OSName string `json:"osName"` - Platform string `json:"platform"` - RamdiskId string `json:"ramdiskId"` - RootDeviceName string `json:"rootDeviceName"` - RootDeviceType string `json:"rootDeviceType"` - ScheduleTags string `json:"scheduleTags"` - Shared string `json:"shared"` - Sharemode string `json:"sharemode"` - StateReason string `json:"stateReason"` - StorageId string `json:"storageId"` -} - -func (self *SImage) GetId() string { - return self.ImageId -} - -func (self *SImage) GetGlobalId() string { - return self.GetId() -} - -func (self *SImage) GetName() string { - return self.Name -} - -func (self *SImage) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.cache -} - -func (self *SImage) GetSizeByte() int64 { - return self.ImageSize -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - if self.IsPublic { - return cloudprovider.ImageTypeSystem - } - return cloudprovider.ImageTypeCustomized -} - -func (self *SImage) GetImageStatus() string { - return "" -} - -func (i *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if i.imageInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(i.OSName, i.Architecture, i.Platform, "", "") - i.imageInfo = &imgInfo - } - return i.imageInfo -} - -func (i *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(i.getNormalizedImageInfo().OsType) -} - -func (i *SImage) GetFullOsName() string { - return i.OSName -} - -func (i *SImage) GetOsArch() string { - return i.getNormalizedImageInfo().OsArch -} - -func (i *SImage) GetOsDist() string { - return i.getNormalizedImageInfo().OsDistro -} - -func (i *SImage) GetOsVersion() string { - return i.getNormalizedImageInfo().OsVersion -} - -func (i *SImage) GetOsLang() string { - return i.getNormalizedImageInfo().OsLang -} - -func (i *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(i.getNormalizedImageInfo().OsBios) -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return 0 -} - -func (self *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (self *SImage) GetImageFormat() string { - return "raw" -} - -func (self *SImage) GetCreatedAt() time.Time { - return time.Time{} -} - -func (self *SImage) UEFI() bool { - return self.Bootloader == "uefi" -} - -func (self *SImage) GetPublicScope() rbacutils.TRbacScope { - if self.Shared == "true" { - return rbacutils.ScopeSystem - } - return rbacutils.ScopeDomain -} - -func (self *SImage) GetSubImages() []cloudprovider.SSubImage { - return []cloudprovider.SSubImage{} -} - -func (self *SImage) GetProjectId() string { - return "" -} - -func (self *SImage) GetStatus() string { - switch self.ImageState { - case "available": - return api.CACHED_IMAGE_STATUS_ACTIVE - default: - return self.ImageState - } -} - -func (self *SRegion) GetImages(id, nextToken string) ([]SImage, string, error) { - params := map[string]string{} - if len(id) > 0 { - params["imageId"] = id - } - if len(nextToken) > 0 { - params["nextToken"] = nextToken - } - resp, err := self.invoke("DescribeImages", params) - if err != nil { - return nil, "", err - } - ret := struct { - NextToken string - ImagesSet []SImage - }{} - resp.Unmarshal(&ret) - return ret.ImagesSet, ret.NextToken, nil -} - -func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - part, nextToken, err := self.region.GetImages("", "") - if err != nil { - return nil, err - } - images := []SImage{} - images = append(images, part...) - for len(nextToken) > 0 { - part, nextToken, err = self.region.GetImages("", nextToken) - if err != nil { - return nil, err - } - images = append(images, part...) - } - ret := []cloudprovider.ICloudImage{} - for i := range images { - if images[i].StorageId == self.storageId { - images[i].cache = self - ret = append(ret, &images[i]) - } - } - return ret, nil -} - -func (self *SStoragecache) GetIImageById(id string) (cloudprovider.ICloudImage, error) { - images, _, err := self.region.GetImages(id, "") - if err != nil { - return nil, err - } - for i := range images { - if images[i].GetGlobalId() == id && images[i].StorageId == self.storageId { - images[i].cache = self - return &images[i], nil - } - } - - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} diff --git a/pkg/multicloud/bingocloud/instance.go b/pkg/multicloud/bingocloud/instance.go deleted file mode 100644 index 46e7b3f8e1..0000000000 --- a/pkg/multicloud/bingocloud/instance.go +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/onecloud/pkg/apis" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SInstance struct { - multicloud.BingoTags - multicloud.SInstanceBase - node *SNode - - ReservationId string `json:"reservationId"` - OwnerId string - GroupSet []struct { - GroupId string - GroupName string - } - InstancesSet struct { - InstanceId string `json:"instanceId"` - InstanceName string `json:"instanceName"` - HostName string `json:"hostName"` - ImageId string `json:"imageId"` - InstanceState struct { - Code int `json:"code"` - Name string `json:"name"` - PendingProgress string `json:"pendingProgress"` - } `json:"instanceState"` - PrivateDNSName string `json:"privateDnsName"` - DNSName string `json:"dnsName"` - PrivateIPAddress string `json:"privateIpAddress"` - PrivateIPAddresses string `json:"privateIpAddresses"` - IPAddress string `json:"ipAddress"` - NifInfo string `json:"nifInfo"` - KeyName string `json:"keyName"` - AmiLaunchIndex int `json:"amiLaunchIndex"` - ProductCodesSet []struct { - ProductCode string `json:"productCode"` - } `json:"productCodesSet"` - InstanceType string `json:"instanceType"` - VmtypeCPU int `json:"vmtype_cpu"` - VmtypeMem int `json:"vmtype_mem"` - VmtypeDisk int `json:"vmtype_disk"` - VmtypeGpu int `json:"vmtype_gpu"` - VmtypeSsd int `json:"vmtype_ssd"` - VmtypeHdd int `json:"vmtype_hdd"` - VmtypeHba int `json:"vmtype_hba"` - VmtypeSriov int `json:"vmtype_sriov"` - LaunchTime time.Time `json:"launchTime"` - RootDeviceType string `json:"rootDeviceType"` - HostAddress string `json:"hostAddress"` - Platform string `json:"platform"` - UseCompactMode bool `json:"useCompactMode"` - ExtendDisk bool `json:"extendDisk"` - Placement struct { - AvailabilityZone string `json:"availabilityZone"` - } `json:"placement"` - Namespace string `json:"namespace"` - KernelId string `json:"kernelId"` - RamdiskId string `json:"ramdiskId"` - OperName string `json:"operName"` - OperProgress int `json:"operProgress"` - Features string `json:"features"` - Monitoring struct { - State string `json:"state"` - } `json:"monitoring"` - SubnetId string `json:"subnetId"` - VpcId string `json:"vpcId"` - StorageId string `json:"storageId"` - DisableAPITermination bool `json:"disableApiTermination"` - Vncdisabled bool `json:"vncdisabled"` - StartTime time.Time `json:"startTime"` - CustomStatus string `json:"customStatus"` - SystemStatus int `json:"systemStatus"` - NetworkStatus int `json:"networkStatus"` - ScheduleTags string `json:"scheduleTags"` - StorageScheduleTags string `json:"storageScheduleTags"` - IsEncrypt bool `json:"isEncrypt"` - IsImported bool `json:"isImported"` - Ec2Version string `json:"ec2Version"` - Passphrase string `json:"passphrase"` - DrsEnabled bool `json:"drs_enabled"` - LaunchPriority int `json:"launchPriority"` - CPUPriority int `json:"cpuPriority"` - MemPriority int `json:"memPriority"` - CPUQuota int `json:"cpuQuota"` - AutoMigrate bool `json:"autoMigrate"` - DrMirrorId string `json:"drMirrorId"` - BlockDeviceMapping []struct { - DeviceName string `json:"deviceName"` - Ebs struct { - AttachTime time.Time `json:"attachTime"` - DeleteOnTermination bool `json:"deleteOnTermination"` - Status string `json:"status"` - VolumeId string `json:"volumeId"` - Size int `json:"size"` - } `json:"ebs"` - } `json:"blockDeviceMapping"` - EnableLiveScaleup bool `json:"enableLiveScaleup"` - ImageBytes int64 `json:"imageBytes"` - StatusReason string `json:"statusReason"` - Hypervisor string `json:"hypervisor"` - Bootloader string `json:"bootloader"` - BmMachineId string `json:"bmMachineId"` - } -} - -func (self *SInstance) GetId() string { - return self.InstancesSet.InstanceId -} - -func (self *SInstance) GetGlobalId() string { - return self.GetId() -} - -func (self *SInstance) GetName() string { - if len(self.InstancesSet.InstanceName) > 0 { - return self.InstancesSet.InstanceName - } - return self.GetId() -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - ret := []string{} - for _, sec := range self.GroupSet { - ret = append(ret, sec.GroupId) - } - return ret, nil -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) GetVcpuCount() int { - return self.InstancesSet.VmtypeCPU -} - -func (self *SInstance) GetVmemSizeMB() int { - return self.InstancesSet.VmtypeMem -} - -func (self *SInstance) GetBootOrder() string { - return "cdn" -} - -func (self *SInstance) GetVga() string { - return "" -} - -func (self *SInstance) GetVdi() string { - return "" -} - -func (self *SInstance) GetOsArch() string { - return apis.OS_ARCH_X86_64 -} - -func (self *SInstance) GetOsType() cloudprovider.TOsType { - if self.InstancesSet.Platform == "linux" { - return cloudprovider.OsTypeLinux - } - return cloudprovider.OsTypeWindows -} - -func (self *SInstance) GetFullOsName() string { - return "" -} - -func (self *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(self.InstancesSet.Bootloader) -} - -func (i *SInstance) GetOsDist() string { - return "" -} - -func (i *SInstance) GetOsVersion() string { - return "" -} - -func (i *SInstance) GetOsLang() string { - return "" -} - -func (self *SInstance) GetMachine() string { - return "" -} - -func (self *SInstance) GetInstanceType() string { - return self.InstancesSet.InstanceType -} - -func (self *SInstance) GetError() error { - return nil -} - -func (self *SInstance) GetHostname() string { - return self.InstancesSet.HostName -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.node -} - -func (self *SInstance) GetIHostId() string { - info := strings.Split(self.InstancesSet.HostAddress, "@") - if len(info) == 2 { - return info[1] - } - return "" -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_BINGO_CLOUD -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - storages, err := self.node.cluster.region.getStorages() - if err != nil { - return nil, err - } - storageMaps := map[string]SStorage{} - for i := range storages { - storageMaps[storages[i].StorageId] = storages[i] - } - ret := []cloudprovider.ICloudDisk{} - for _, _disk := range self.InstancesSet.BlockDeviceMapping { - disk, err := self.node.cluster.region.GetDisk(_disk.Ebs.VolumeId) - if err != nil { - return nil, err - } - storage, ok := storageMaps[disk.StorageId] - if ok { - storage.cluster = self.node.cluster - disk.storage = &storage - ret = append(ret, disk) - } - } - return ret, nil -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nics, err := self.node.cluster.region.GetInstanceNics(self.InstancesSet.InstanceId) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNic{} - for i := range nics { - ret = append(ret, &nics[i]) - } - return ret, nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - eips, _, err := self.node.cluster.region.GetEips("", self.InstancesSet.InstanceId, "") - if err != nil { - return nil, err - } - for i := range eips { - eips[i].region = self.node.cluster.region - return &eips[i], nil - } - return nil, nil -} - -func (self *SInstance) GetProjectId() string { - return "" -} - -func (self *SInstance) GetStatus() string { - switch self.InstancesSet.InstanceState.Name { - case "stopped": - return api.VM_READY - default: - return self.InstancesSet.InstanceState.Name - } -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - return "", cloudprovider.ErrNotImplemented -} - -func (self *SInstance) StartVM(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetInstances(id, nodeId string, maxResult int, nextToken string) ([]SInstance, string, error) { - params := map[string]string{} - if maxResult > 0 { - params["maxRecords"] = fmt.Sprintf("%d", maxResult) - } - if len(nextToken) > 0 { - params["nextToken"] = nextToken - } - - idx := 1 - if len(nodeId) > 0 { - params[fmt.Sprintf("Filter.%d.Name", idx)] = "node-id" - params[fmt.Sprintf("Filter.%d.Value.1", idx)] = nodeId - idx++ - } - - if len(id) > 0 { - params[fmt.Sprintf("Filter.%d.Name", idx)] = "instance-id" - params[fmt.Sprintf("Filter.%d.Value.1", idx)] = id - idx++ - } - - resp, err := self.invoke("DescribeInstances", params) - if err != nil { - return nil, "", err - } - result := struct { - NextToken string - ReservationSet []SInstance - }{} - err = resp.Unmarshal(&result) - if err != nil { - return nil, "", err - } - return result.ReservationSet, result.NextToken, nil -} diff --git a/pkg/multicloud/bingocloud/instancenic.go b/pkg/multicloud/bingocloud/instancenic.go deleted file mode 100644 index 66a52c323d..0000000000 --- a/pkg/multicloud/bingocloud/instancenic.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import "yunion.io/x/onecloud/pkg/cloudprovider" - -type SInstanceNic struct { - Association string `json:"association"` - Attachment struct { - AttachTime string `json:"attachTime"` - AttachmentId string `json:"attachmentId"` - DeleteOnTermination string `json:"deleteOnTermination"` - DeviceIndex string `json:"deviceIndex"` - InstanceId string `json:"instanceId"` - InstanceOwnerId string `json:"instanceOwnerId"` - Status string `json:"status"` - } `json:"attachment"` - AvailabilityZone string `json:"availabilityZone"` - Description string `json:"description"` - FirstPacketLimit string `json:"firstPacketLimit"` - MACAddress string `json:"macAddress"` - Model string `json:"model"` - NetworkInterfaceId string `json:"networkInterfaceId"` - NoMatchPort string `json:"noMatchPort"` - OwnerId string `json:"ownerId"` - PrivateDNSName string `json:"privateDnsName"` - PrivateIPAddress string `json:"privateIpAddress"` - PrivateIPAddressesSet []struct { - Association string `json:"association"` - Primary string `json:"primary"` - PrivateDNSName string `json:"privateDnsName"` - PrivateIPAddress string `json:"privateIpAddress"` - } `json:"privateIpAddressesSet"` - RequesterManaged string `json:"requesterManaged"` - SourceDestCheck string `json:"sourceDestCheck"` - Status string `json:"status"` - SubnetId string `json:"subnetId"` - VpcId string `json:"vpcId"` -} - -func (self *SInstanceNic) GetId() string { - return self.NetworkInterfaceId -} - -func (self *SInstanceNic) GetIP() string { - return self.PrivateIPAddress -} - -func (self *SInstanceNic) GetMAC() string { - return self.MACAddress -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (self *SInstanceNic) GetDriver() string { - return self.Model -} - -func (self *SInstanceNic) GetINetworkId() string { - return self.SubnetId -} - -func (self *SInstanceNic) GetSubAddress() ([]string, error) { - ret := []string{} - for _, ip := range self.PrivateIPAddressesSet { - if ip.PrivateIPAddress != self.PrivateIPAddress { - ret = append(ret, ip.PrivateIPAddress) - } - } - return ret, nil -} - -func (self *SInstanceNic) AssignNAddress(count int) ([]string, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstanceNic) UnassignAddress(ipAddrs []string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetInstanceNics(insId string) ([]SInstanceNic, error) { - params := map[string]string{} - if len(insId) > 0 { - params["instanceId"] = insId - } - resp, err := self.invoke("DescribeNetworkInterfaces", params) - if err != nil { - return nil, err - } - ret := struct { - NetworkInterfaceSet []SInstanceNic - }{} - resp.Unmarshal(&ret) - return ret.NetworkInterfaceSet, nil -} diff --git a/pkg/multicloud/bingocloud/monitor.go b/pkg/multicloud/bingocloud/monitor.go deleted file mode 100644 index 5eb41feb2b..0000000000 --- a/pkg/multicloud/bingocloud/monitor.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "fmt" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type MetricOutput struct { - Datapoints Datapoints - ObjName string - Period int64 -} - -type DatapointMember struct { - Average float64 - Maximum float64 - Minimum float64 - SampleCount float64 - Sum float64 - Timestamp time.Time - Unit string -} - -func (self DatapointMember) GetValue() float64 { - return self.Average + self.Maximum + self.Minimum + self.Sum -} - -type Datapoints struct { - Member []DatapointMember -} - -func (self *SBingoCloudClient) DescribeMetricList(ns, metricNm, dimensionName, dimensionValue string, since time.Time, until time.Time) (*MetricOutput, error) { - params := map[string]string{} - params["Namespace"] = ns - params["MetricName"] = metricNm - params["Dimensions.member.1.Name"] = dimensionName - params["Dimensions.member.1.Value"] = dimensionValue - params["StartTime"] = since.Format(time.RFC3339) - params["EndTime"] = until.Format(time.RFC3339) - params["Statistics.member.1"] = "Average" - params["Period"] = "60" - resp, err := self.invoke("GetMetricStatistics", params) - if err != nil { - return nil, errors.Wrap(err, "GetMetricStatistics err") - } - ret := &MetricOutput{} - return ret, resp.Unmarshal(ret, "GetMetricStatisticsResult") -} - -func (self *SBingoCloudClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - if len(opts.ResourceId) == 0 { - return nil, fmt.Errorf("missing resourceId") - } - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_HOST: - return self.GetHostMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) - } -} - -func (self *SBingoCloudClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - for metricType, metricName := range map[cloudprovider.TMetricType]string{ - cloudprovider.VM_METRIC_TYPE_CPU_USAGE: "CPUUtilization", - cloudprovider.VM_METRIC_TYPE_MEM_USAGE: "MemeryUsage", - cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: "NetworkIn", - cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: "NetworkOut", - cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: "DiskReadBytes", - cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: "DiskWriteBytes", - cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: "DiskReadOps", - cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: "DiskWriteOps", - } { - data, err := self.DescribeMetricList("AWS/EC2", metricName, "InstanceId", opts.ResourceId, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("DescribeMetricList error: %v", err) - continue - } - metric := cloudprovider.MetricValues{} - metric.Id = opts.ResourceId - metric.MetricType = metricType - for _, value := range data.Datapoints.Member { - metricValue := cloudprovider.MetricValue{} - metricValue.Timestamp = value.Timestamp - metricValue.Value = value.GetValue() - metric.Values = append(metric.Values, metricValue) - } - ret = append(ret, metric) - } - return ret, nil -} - -func (self *SBingoCloudClient) GetHostMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - for metricType, metricName := range map[cloudprovider.TMetricType]string{ - cloudprovider.VM_METRIC_TYPE_CPU_USAGE: "CPUUtilization", - cloudprovider.VM_METRIC_TYPE_MEM_USAGE: "MemeryUsage", - cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: "NetworkIn", - cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: "NetworkOut", - cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: "DiskReadBytes", - cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: "DiskWriteBytes", - cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: "DiskReadOps", - cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: "DiskWriteOps", - } { - data, err := self.DescribeMetricList("AWS/HOST", metricName, "HostId", opts.ResourceId, opts.StartTime, opts.EndTime) - if err != nil { - log.Errorf("DescribeMetricList error: %v", err) - continue - } - metric := cloudprovider.MetricValues{} - metric.Id = opts.ResourceId - metric.MetricType = metricType - for _, value := range data.Datapoints.Member { - metricValue := cloudprovider.MetricValue{} - metricValue.Timestamp = value.Timestamp - metricValue.Value = value.GetValue() - metric.Values = append(metric.Values, metricValue) - } - ret = append(ret, metric) - } - return ret, nil - -} diff --git a/pkg/multicloud/bingocloud/network.go b/pkg/multicloud/bingocloud/network.go deleted file mode 100644 index 602f8feb69..0000000000 --- a/pkg/multicloud/bingocloud/network.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "fmt" - "strings" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.STagBase - wire *SWire - - CidrBlock string `json:"cidrBlock"` - MapPublicIPOnLaunch string `json:"mapPublicIpOnLaunch"` - RouterId string `json:"routerId"` - NetworkFrom string `json:"networkFrom"` - NetworkNode string `json:"networkNode"` - IsManagedNetwork string `json:"isManagedNetwork"` - SubnetName string `json:"subnetName"` - NetworkMask string `json:"networkMask"` - NetName string `json:"netName"` - Index string `json:"index"` - VpcIsPublic string `json:"vpcIsPublic"` - Description string `json:"description"` - MicroSegmentation string `json:"microSegmentation"` - State string `json:"state"` - DefaultForAz string `json:"defaultForAz"` - Router string `json:"router"` - Active string `json:"active"` - VpcShared string `json:"vpcShared"` - DvswitchName string `json:"dvswitchName"` - AvailableIPAddressCount string `json:"availableIpAddressCount"` - VlanNum string `json:"vlanNum"` - RouterCc2 string `json:"router_cc2"` - ResStatus string `json:"res_status"` - IPAddressCount string `json:"ipAddressCount"` - RouterCc string `json:"router_cc"` - VpcId string `json:"vpcId"` - NetworkTo string `json:"networkTo"` - Broadcast string `json:"broadcast"` - UserName string `json:"userName"` - IPVersion string `json:"ipVersion"` - AvailabilityZone string `json:"availabilityZone"` - Network string `json:"network"` - RouterMac string `json:"router_mac"` - CheckIP string `json:"checkIp"` - FloatingPool string `json:"floatingPool"` - StaticPool string `json:"staticPool"` - DvsPortGroup string `json:"dvsPortGroup"` - SubnetId string `json:"subnetId"` -} - -func (self *SNetwork) GetId() string { - return self.SubnetId -} - -func (self *SNetwork) GetGlobalId() string { - return self.SubnetId -} - -func (self *SNetwork) GetName() string { - if len(self.SubnetName) > 0 { - return self.SubnetName - } - return self.SubnetId -} - -func (self *SNetwork) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 300 -} - -func (self *SNetwork) GetGateway() string { - prefix, err := netutils.NewIPV4Prefix(self.CidrBlock) - if err == nil { - return prefix.Address.StepUp().String() - } - return "" -} - -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) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetProjectId() string { - return "" -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetStatus() string { - return strings.ToLower(self.State) -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - networks, err := self.vpc.region.GetNetworks("", self.cluster.ClusterId, self.vpc.VpcId) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNetwork{} - for i := range networks { - networks[i].wire = self - ret = append(ret, &networks[i]) - } - return ret, nil -} - -func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { - networks, err := self.GetINetworks() - if err != nil { - return nil, err - } - for i := range networks { - if networks[i].GetGlobalId() == id { - return networks[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SRegion) GetNetworks(id, clusterId, vpcId string) ([]SNetwork, error) { - params := map[string]string{} - if len(id) > 0 { - params["subnetId"] = id - } - idx := 1 - if len(clusterId) > 0 { - params[fmt.Sprintf("Filter.%d.Name", idx)] = "availability-zone" - params[fmt.Sprintf("Filter.%d.Value.1", idx)] = clusterId - idx++ - } - if len(vpcId) > 0 { - params[fmt.Sprintf("Filter.%d.Name", idx)] = "vpc-id" - params[fmt.Sprintf("Filter.%d.Value.1", idx)] = vpcId - idx++ - } - resp, err := self.invoke("DescribeSubnets", params) - if err != nil { - return nil, err - } - networks := []SNetwork{} - return networks, resp.Unmarshal(&networks, "subnetSet") -} diff --git a/pkg/multicloud/bingocloud/node.go b/pkg/multicloud/bingocloud/node.go deleted file mode 100644 index e34ba602ae..0000000000 --- a/pkg/multicloud/bingocloud/node.go +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNode struct { - multicloud.SHostBase - multicloud.STagBase - - cluster *SCluster - - ClusterId string - CpuCores int - CpuMax int - CpuModel string - CpuNode int - CpuSockets int - CpuUsed int - DiskMax int - DiskNode int - DiskUsed int - MemNode int - MemoryMax int - MemoryUsed int - NodeId string - NodeName string - ScheduleTags string - Status string -} - -func (self *SRegion) GetNodes(clusterId, nodeId string) ([]SNode, error) { - params := map[string]string{} - if len(clusterId) > 0 { - params["clusterId"] = clusterId - } - if len(clusterId) > 0 { - params["nodeId"] = nodeId - } - resp, err := self.invoke("DescribeNodes", params) - if err != nil { - return nil, err - } - ret := []SNode{} - return ret, resp.Unmarshal(&ret, "nodeSet") -} - -func (self *SNode) GetId() string { - return self.NodeId -} - -func (self *SNode) GetGlobalId() string { - return self.NodeId -} - -func (self *SNode) GetName() string { - return self.NodeName -} - -func (self *SNode) GetAccessIp() string { - info := strings.Split(self.NodeId, "@") - if len(info) == 2 { - return info[1] - } - return "" -} - -func (self *SNode) GetAccessMac() string { - return "" -} - -func (self *SNode) GetSysInfo() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (self *SNode) GetSN() string { - return "" -} - -func (self *SNode) GetCpuCount() int { - return self.CpuNode -} - -func (self *SNode) GetNodeCount() int8 { - return int8(self.CpuSockets) -} - -func (self *SNode) GetCpuDesc() string { - return self.CpuModel -} - -func (self *SNode) GetCpuMhz() int { - return 0 -} - -func (self *SNode) GetCpuCmtbound() float32 { - if self.CpuMax > self.CpuNode { - return float32(self.CpuMax) / float32(self.CpuNode) - } - return 1 -} - -func (self *SNode) GetMemSizeMB() int { - return self.MemNode -} - -func (self *SNode) GetMemCmtbound() float32 { - if self.MemoryMax > self.MemNode { - return float32(self.MemoryMax) / float32(self.MemNode) - } - return 1 -} - -func (self *SNode) GetReservedMemoryMb() int { - return 0 -} - -func (self *SNode) GetStorageSizeMB() int { - if self.DiskMax > 0 { - return self.DiskMax * 1024 - } - return self.DiskNode * 1024 -} - -func (self *SNode) GetStorageType() string { - return api.STORAGE_LOCAL_SSD -} - -func (self *SNode) GetNodeType() string { - return api.HOST_TYPE_BINGO_CLOUD -} - -func (self *SNode) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SNode) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - return self.cluster.GetIStorages() -} - -func (self *SNode) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return self.cluster.GetIStorageById(id) -} - -func (self *SNode) GetEnabled() bool { - return true -} - -func (self *SNode) GetNodeStatus() string { - if self.Status == "available" { - return api.HOST_ONLINE - } - return api.HOST_OFFLINE -} - -func (self *SNode) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SNode) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms := []SInstance{} - part, nextToken, err := self.cluster.region.GetInstances("", self.NodeId, MAX_RESULT, "") - vms = append(vms, part...) - for len(nextToken) > 0 { - part, nextToken, err = self.cluster.region.GetInstances("", self.NodeId, MAX_RESULT, nextToken) - if err != nil { - return nil, err - } - vms = append(vms, part...) - } - ret := []cloudprovider.ICloudVM{} - for i := range vms { - vms[i].node = self - ret = append(ret, &vms[i]) - } - return ret, nil -} - -func (self *SNode) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vms, _, err := self.cluster.region.GetInstances(id, self.NodeId, 1, "") - if err != nil { - return nil, err - } - for i := range vms { - if vms[i].GetGlobalId() == id { - vms[i].node = self - return &vms[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SNode) GetIWires() ([]cloudprovider.ICloudWire, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SNode) GetSchedtags() ([]string, error) { - return []string{}, nil -} - -func (self *SNode) GetIsMaintenance() bool { - return self.Status == "maintain" -} - -func (self *SNode) GetVersion() string { - return "" -} - -func (self *SNode) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SNode) GetHostStatus() string { - if self.Status != "available" { - return api.HOST_OFFLINE - } - return api.HOST_ONLINE -} - -func (self *SNode) GetHostType() string { - return api.HOST_TYPE_BINGO_CLOUD -} - -func (self *SCluster) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - nodes, err := self.region.GetNodes(self.ClusterId, id) - if err != nil { - return nil, err - } - for i := range nodes { - if nodes[i].GetGlobalId() == id { - nodes[i].cluster = self - return &nodes[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SCluster) GetIHosts() ([]cloudprovider.ICloudHost, error) { - nodes, err := self.region.GetNodes(self.ClusterId, "") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudHost{} - for i := range nodes { - nodes[i].cluster = self - ret = append(ret, &nodes[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/bingocloud/provider/doc.go b/pkg/multicloud/bingocloud/provider/doc.go deleted file mode 100644 index b282736698..0000000000 --- a/pkg/multicloud/bingocloud/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/bingocloud/provider" diff --git a/pkg/multicloud/bingocloud/provider/provider.go b/pkg/multicloud/bingocloud/provider/provider.go deleted file mode 100644 index adcf9d502a..0000000000 --- a/pkg/multicloud/bingocloud/provider/provider.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" -) - -type SBingoCloudProviderFactory struct { - cloudprovider.SPrivateCloudBaseProviderFactory -} - -func (self *SBingoCloudProviderFactory) GetId() string { - return bingocloud.CLOUD_PROVIDER_BINGO_CLOUD -} - -func (self *SBingoCloudProviderFactory) GetName() string { - return bingocloud.CLOUD_PROVIDER_BINGO_CLOUD -} - -func (self *SBingoCloudProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { - return fmt.Errorf("Changing %s bandwidth is not supported", bingocloud.CLOUD_PROVIDER_BINGO_CLOUD) -} - -func (self *SBingoCloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - if len(input.Endpoint) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "endpoint") - } - output.AccessUrl = input.Endpoint - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - return output, nil -} - -func (self *SBingoCloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func (self *SBingoCloudProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - client, err := bingocloud.NewBingoCloudClient( - bingocloud.NewBingoCloudClientConfig( - cfg.URL, cfg.Account, cfg.Secret, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SBingoCloudProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SBingoCloudProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - return map[string]string{ - "BINGO_CLOUD_ENDPOINT": info.Url, - "BINGO_CLOUD_ACCESS_KEY": info.Account, - "BINGO_CLOUD_SECRET_KEY": info.Secret, - }, nil -} - -func init() { - factory := SBingoCloudProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SBingoCloudProvider struct { - cloudprovider.SBaseProvider - client *bingocloud.SBingoCloudClient -} - -func (self *SBingoCloudProvider) GetSysInfo() (jsonutils.JSONObject, error) { - return jsonutils.NewDict(), nil -} - -func (self *SBingoCloudProvider) GetVersion() string { - return "2009-08-15" -} - -func (self *SBingoCloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SBingoCloudProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SBingoCloudProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SBingoCloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(id) -} - -func (self *SBingoCloudProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SBingoCloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return []cloudprovider.ICloudProject{}, nil -} - -func (self *SBingoCloudProvider) GetStorageClasses(regionId string) []string { - return nil -} - -func (self *SBingoCloudProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (self *SBingoCloudProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (self *SBingoCloudProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SBingoCloudProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/bingocloud/region.go b/pkg/multicloud/bingocloud/region.go deleted file mode 100644 index 1bafd3de0b..0000000000 --- a/pkg/multicloud/bingocloud/region.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - multicloud.SRegion - multicloud.SRegionEipBase - multicloud.SRegionLbBase - multicloud.SRegionOssBase - multicloud.SRegionSecurityGroupBase - multicloud.SRegionVpcBase - multicloud.SRegionZoneBase - - client *SBingoCloudClient - - RegionId string - RegionName string - Hypervisor string - NetworkMode string - RegionEndpoint string -} - -func (self *SRegion) GetId() string { - return self.RegionId -} - -func (self *SRegion) GetName() string { - return self.RegionName -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_BINGO_CLOUD, self.RegionId) -} - -func (self *SRegion) GetClient() *SBingoCloudClient { - return self.client -} - -func (self *SRegion) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - return cloudprovider.SModelI18nTable{} -} - -func (self *SRegion) GetProvider() string { - return api.CLOUD_PROVIDER_BINGO_CLOUD -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) GetCloudEnv() string { - return "" -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) invoke(action string, params map[string]string) (jsonutils.JSONObject, error) { - return self.client.invoke(action, params) -} - -func (self *SBingoCloudClient) GetRegions() ([]SRegion, error) { - resp, err := self.invoke("DescribeRegions", nil) - if err != nil { - return nil, err - } - ret := []SRegion{} - err = resp.Unmarshal(&ret, "regionInfo") - if err != nil { - return nil, err - } - return ret, nil -} - -func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storages := []SStorage{} - part, nextToken, err := self.GetStorages("") - if err != nil { - return nil, err - } - storages = append(storages, part...) - for len(nextToken) > 0 { - part, nextToken, err = self.GetStorages(nextToken) - if err != nil { - return nil, err - } - storages = append(storages, part...) - } - ret := []cloudprovider.ICloudStoragecache{} - for i := range storages { - cache := SStoragecache{ - region: self, - storageName: storages[i].StorageName, - storageId: storages[i].StorageId, - } - ret = append(ret, &cache) - } - return ret, nil -} - -func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - caches, err := self.GetIStoragecaches() - if err != nil { - return nil, err - } - for i := range caches { - if caches[i].GetGlobalId() == id { - return caches[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - zones, err := self.GetIZones() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudHost{} - for i := range zones { - hosts, err := zones[i].GetIHosts() - if err != nil { - return nil, err - } - ret = append(ret, hosts...) - } - return ret, nil -} - -func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - zones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := range zones { - hosts, err := zones[i].GetIHosts() - if err != nil { - return nil, err - } - for i := range hosts { - if hosts[i].GetGlobalId() == id { - return hosts[i], nil - } - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} diff --git a/pkg/multicloud/bingocloud/secgroup.go b/pkg/multicloud/bingocloud/secgroup.go deleted file mode 100644 index abd2ab084b..0000000000 --- a/pkg/multicloud/bingocloud/secgroup.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSecurityGroup struct { - multicloud.SResourceBase - multicloud.BingoTags - region *SRegion - - ComplexIPPermissions string `json:"complexIpPermissions"` - ComplexIPPermissionsEgress string `json:"complexIpPermissionsEgress"` - DisplayName string `json:"displayName"` - GroupDescription string `json:"groupDescription"` - GroupId string `json:"groupId"` - GroupName string `json:"groupName"` - IPPermissionType string `json:"ipPermissionType"` - IPPermissions string `json:"ipPermissions"` - IPPermissionsEgress []IPPermissionsEgress `json:"ipPermissionsEgress"` - OwnerId string `json:"ownerId"` -} - -type IPPermissionsEgress struct { - BoundType string `json:"boundType"` - Description string `json:"description"` - FromPort int `json:"fromPort"` - IPProtocol string `json:"ipProtocol"` - Groups []struct { - GroupId string - GroupName string - } `json:"groups"` - IPRanges []struct { - CIdRIP string `json:"cidrIp"` - } `json:"ipRanges"` - L2Accept string `json:"l2Accept"` - PermissionId string `json:"permissionId"` - Policy string `json:"policy"` - ToPort int `json:"toPort"` -} - -func (self *SSecurityGroup) GetId() string { - return self.GroupId -} - -func (self *SSecurityGroup) GetGlobalId() string { - return self.GetId() -} - -func (self *SSecurityGroup) GetName() string { - return self.GroupName -} - -func (self *SSecurityGroup) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (self *SSecurityGroup) GetDescription() string { - return self.GroupDescription -} - -func (self *SSecurityGroup) GetProjectId() string { - return "" -} - -func (self *SSecurityGroup) GetReferences() ([]cloudprovider.SecurityGroupReference, error) { - return []cloudprovider.SecurityGroupReference{}, nil -} - -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - ret := []cloudprovider.SecurityRule{} - for _, _rule := range self.IPPermissionsEgress { - if len(_rule.Groups) > 0 { - continue - } - rule := cloudprovider.SecurityRule{} - rule.Direction = secrules.DIR_IN - rule.Priority = 1 - rule.Action = secrules.SecurityRuleAllow - rule.Protocol = secrules.PROTO_ANY - rule.Description = _rule.Description - if _rule.BoundType == "Out" { - rule.Direction = secrules.DIR_OUT - } - if _rule.Policy == "DROP" { - rule.Action = secrules.SecurityRuleDeny - } - if _rule.IPProtocol != "all" { - rule.Protocol = _rule.IPProtocol - } - if rule.Protocol == secrules.PROTO_TCP || rule.Protocol == secrules.PROTO_UDP { - rule.PortStart, rule.PortEnd = _rule.FromPort, _rule.ToPort - } - - for _, ip := range _rule.IPRanges { - if ip.CIdRIP == "::/0" { - ip.CIdRIP = "0.0.0.0/0" - } - rule.ParseCIDR(ip.CIdRIP) - err := rule.ValidateRule() - if err != nil { - return nil, err - } - ret = append(ret, rule) - } - } - return ret, nil -} - -func (self *SSecurityGroup) GetVpcId() string { - return api.NORMAL_VPC_ID -} - -func (self *SSecurityGroup) GetStatus() string { - return api.SECGROUP_STATUS_READY -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetSecurityGroups(id, name, nextToken string) ([]SSecurityGroup, string, error) { - params := map[string]string{} - if len(id) > 0 { - params["groupId"] = id - } - if len(name) > 0 { - params["groupName"] = name - } - if len(nextToken) > 0 { - params["nextToken"] = nextToken - } - resp, err := self.invoke("DescribeSecurityGroups", params) - if err != nil { - return nil, "", err - } - ret := struct { - SecurityGroupInfo []SSecurityGroup - NextToken string - }{} - resp.Unmarshal(&ret) - return ret.SecurityGroupInfo, ret.NextToken, nil -} - -func (self *SRegion) GetISecurityGroupById(id string) (cloudprovider.ICloudSecurityGroup, error) { - groups, _, err := self.GetSecurityGroups(id, "", "") - if err != nil { - return nil, err - } - for i := range groups { - if groups[i].GetGlobalId() == id { - groups[i].region = self - return &groups[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - groups, _, err := self.GetSecurityGroups("", opts.Name, "") - if err != nil { - return nil, err - } - for i := range groups { - if groups[i].GetName() == opts.Name { - groups[i].region = self - return &groups[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/bingocloud/shell/cluster.go b/pkg/multicloud/bingocloud/shell/cluster.go deleted file mode 100644 index ee2151e584..0000000000 --- a/pkg/multicloud/bingocloud/shell/cluster.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClusterListOptions struct { - } - shellutils.R(&ClusterListOptions{}, "cluster-list", "List clusters", func(cli *bingocloud.SRegion, args *ClusterListOptions) error { - clusters, err := cli.GetClusters() - if err != nil { - return err - } - printList(clusters, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/shell/disk.go b/pkg/multicloud/bingocloud/shell/disk.go deleted file mode 100644 index 53b508cc15..0000000000 --- a/pkg/multicloud/bingocloud/shell/disk.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - Id string - MaxResult int - NextToken string - } - shellutils.R(&DiskListOptions{}, "disk-list", "list disks", func(cli *bingocloud.SRegion, args *DiskListOptions) error { - vms, _, err := cli.GetDisks(args.Id, args.MaxResult, args.NextToken) - if err != nil { - return err - } - printList(vms, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/shell/doc.go b/pkg/multicloud/bingocloud/shell/doc.go deleted file mode 100644 index 627924306f..0000000000 --- a/pkg/multicloud/bingocloud/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/bingocloud/shell" diff --git a/pkg/multicloud/bingocloud/shell/eip.go b/pkg/multicloud/bingocloud/shell/eip.go deleted file mode 100644 index 48d26f5762..0000000000 --- a/pkg/multicloud/bingocloud/shell/eip.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - Ip string - InstanceId string - NextToken string - } - shellutils.R(&EipListOptions{}, "eip-list", "list eips", func(cli *bingocloud.SRegion, args *EipListOptions) error { - eips, _, err := cli.GetEips(args.Ip, args.InstanceId, args.NextToken) - if err != nil { - return err - } - printList(eips, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/shell/host.go b/pkg/multicloud/bingocloud/shell/host.go deleted file mode 100644 index 1c12b95d96..0000000000 --- a/pkg/multicloud/bingocloud/shell/host.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type HostListOptions struct { - NextToken string - } - shellutils.R(&HostListOptions{}, "host-list", "List hosts", func(cli *bingocloud.SRegion, args *HostListOptions) error { - hosts, _, err := cli.GetHosts(args.NextToken) - if err != nil { - return err - } - printList(hosts, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/shell/image.go b/pkg/multicloud/bingocloud/shell/image.go deleted file mode 100644 index b3d1bb17ae..0000000000 --- a/pkg/multicloud/bingocloud/shell/image.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - Id string - NextToken string - } - shellutils.R(&ImageListOptions{}, "image-list", "list images", func(cli *bingocloud.SRegion, args *ImageListOptions) error { - images, _, err := cli.GetImages(args.Id, args.NextToken) - if err != nil { - return err - } - printList(images, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/shell/instance.go b/pkg/multicloud/bingocloud/shell/instance.go deleted file mode 100644 index 07a78f9445..0000000000 --- a/pkg/multicloud/bingocloud/shell/instance.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - Id string - NodeId string - MaxResult int - NextToken string - } - shellutils.R(&InstanceListOptions{}, "instance-list", "list instances", func(cli *bingocloud.SRegion, args *InstanceListOptions) error { - vms, _, err := cli.GetInstances(args.Id, args.NodeId, args.MaxResult, args.NextToken) - if err != nil { - return err - } - printList(vms, 0, 0, 0, []string{}) - return nil - }) - - type InstanceNicListOptions struct { - InstanceId string - } - - shellutils.R(&InstanceNicListOptions{}, "instance-nic-list", "list instance nics", func(cli *bingocloud.SRegion, args *InstanceNicListOptions) error { - nics, err := cli.GetInstanceNics(args.InstanceId) - if err != nil { - return err - } - printList(nics, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/bingocloud/shell/monitor.go b/pkg/multicloud/bingocloud/shell/monitor.go deleted file mode 100644 index d5587be826..0000000000 --- a/pkg/multicloud/bingocloud/shell/monitor.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics", func(cli *bingocloud.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric: %s %s %s", metrics[i].Id, metrics[i].MetricType, metrics[i].Unit) - printList(metrics[i].Values, len(metrics[i].Values), 0, 0, []string{}) - } - return nil - }) - -} diff --git a/pkg/multicloud/bingocloud/shell/network.go b/pkg/multicloud/bingocloud/shell/network.go deleted file mode 100644 index 8000c69b01..0000000000 --- a/pkg/multicloud/bingocloud/shell/network.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkListOptions struct { - Id string - ZoneId string - VpcId string - } - shellutils.R(&NetworkListOptions{}, "network-list", "List networks", func(cli *bingocloud.SRegion, args *NetworkListOptions) error { - networks, err := cli.GetNetworks(args.Id, args.ZoneId, args.VpcId) - if err != nil { - return err - } - printList(networks, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/shell/node.go b/pkg/multicloud/bingocloud/shell/node.go deleted file mode 100644 index f785b6a151..0000000000 --- a/pkg/multicloud/bingocloud/shell/node.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NodeListOptions struct { - ClusterId string - NodeId string - } - shellutils.R(&NodeListOptions{}, "node-list", "List nodes", func(cli *bingocloud.SRegion, args *NodeListOptions) error { - nodes, err := cli.GetNodes(args.ClusterId, args.NodeId) - if err != nil { - return err - } - printList(nodes, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/shell/printutils.go b/pkg/multicloud/bingocloud/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/bingocloud/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/bingocloud/shell/region.go b/pkg/multicloud/bingocloud/shell/region.go deleted file mode 100644 index 1e40bf176a..0000000000 --- a/pkg/multicloud/bingocloud/shell/region.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *bingocloud.SRegion, args *RegionListOptions) error { - regions, err := cli.GetClient().GetRegions() - if err != nil { - return err - } - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/shell/secgroup.go b/pkg/multicloud/bingocloud/shell/secgroup.go deleted file mode 100644 index 61e1a2866d..0000000000 --- a/pkg/multicloud/bingocloud/shell/secgroup.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - Id string - Name string - NextToken string - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security-groups", func(cli *bingocloud.SRegion, args *SecurityGroupListOptions) error { - groups, _, err := cli.GetSecurityGroups(args.Id, args.Name, args.NextToken) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/shell/storage.go b/pkg/multicloud/bingocloud/shell/storage.go deleted file mode 100644 index 39a4a978c1..0000000000 --- a/pkg/multicloud/bingocloud/shell/storage.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type StorageListOptions struct { - NextToken string - } - shellutils.R(&StorageListOptions{}, "storage-list", "List storages", func(cli *bingocloud.SRegion, args *StorageListOptions) error { - storages, _, err := cli.GetStorages(args.NextToken) - if err != nil { - return err - } - printList(storages, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/shell/vpc.go b/pkg/multicloud/bingocloud/shell/vpc.go deleted file mode 100644 index 691b420294..0000000000 --- a/pkg/multicloud/bingocloud/shell/vpc.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - Id string - } - shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *bingocloud.SRegion, args *VpcListOptions) error { - vpcs, err := cli.GetVpcs(args.Id) - if err != nil { - return err - } - printList(vpcs, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/shell/zone.go b/pkg/multicloud/bingocloud/shell/zone.go deleted file mode 100644 index 9c2bf14c5b..0000000000 --- a/pkg/multicloud/bingocloud/shell/zone.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/bingocloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - } - shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *bingocloud.SRegion, args *ZoneListOptions) error { - zones, err := cli.GetZones() - if err != nil { - return err - } - printList(zones, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/bingocloud/storage.go b/pkg/multicloud/bingocloud/storage.go deleted file mode 100644 index f38706fdc3..0000000000 --- a/pkg/multicloud/bingocloud/storage.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - multicloud.STagBase - multicloud.SStorageBase - cluster *SCluster - - StorageId string `json:"storageId"` - Location string `json:"location"` - UsedBy string `json:"usedBy"` - SpaceUsed int64 `json:"spaceUsed"` - StorageName string `json:"storageName"` - FileFormat string `json:"fileFormat"` - Disabled string `json:"disabled"` - SpaceMax int64 `json:"spaceMax"` - StorageType string `json:"storageType"` - DrCloudId string `json:"drCloudId"` - ParameterSet []struct { - Name string - Value string - } `json:"parameterSet"` - ClusterId string `json:"clusterId"` - IsDRStorage string `json:"isDRStorage"` - ResUsage string `json:"resUsage"` - ScheduleTags string `json:"scheduleTags"` -} - -func (self *SStorage) GetName() string { - return self.StorageName -} - -func (self *SStorage) GetId() string { - return self.StorageId -} - -func (self *SStorage) GetGlobalId() string { - return self.GetId() -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStorage) DisableSync() bool { - return false -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return &SStoragecache{storageId: self.StorageId, storageName: self.StorageName, region: self.cluster.region} -} - -func (self *SStorage) GetIZone() cloudprovider.ICloudZone { - return self.cluster -} - -func (self *SStorage) GetStorageType() string { - return self.StorageType -} - -func (self *SStorage) GetMediumType() string { - return api.DISK_TYPE_SSD -} - -func (self *SStorage) GetCapacityMB() int64 { - return self.SpaceMax * 1024 -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return self.SpaceUsed * 1024 -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - return jsonutils.Marshal(self.ParameterSet) -} - -func (self *SStorage) GetEnabled() bool { - return self.Disabled == "false" -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} - -func (self *SRegion) GetStorages(nextToken string) ([]SStorage, string, error) { - params := map[string]string{} - if len(nextToken) > 0 { - params["nextToken"] = nextToken - } - resp, err := self.invoke("DescribeStorages", params) - if err != nil { - return nil, "", err - } - ret := struct { - NextToken string - StorageSet []SStorage - }{} - resp.Unmarshal(&ret) - return ret.StorageSet, ret.NextToken, nil -} - -func (self *SCluster) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storages, err := self.GetIStorages() - if err != nil { - return nil, err - } - for i := range storages { - if storages[i].GetGlobalId() == id { - return storages[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SCluster) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := self.region.getStorages() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStorage{} - for i := range storages { - storages[i].cluster = self - ret = append(ret, &storages[i]) - } - return ret, nil -} - -func (self *SRegion) getStorages() ([]SStorage, error) { - storages := []SStorage{} - part, nextToken, err := self.GetStorages("") - if err != nil { - return nil, err - } - storages = append(storages, part...) - for len(nextToken) > 0 { - part, nextToken, err = self.GetStorages(nextToken) - if err != nil { - return nil, err - } - storages = append(storages, part...) - } - return storages, nil -} diff --git a/pkg/multicloud/bingocloud/storagecache.go b/pkg/multicloud/bingocloud/storagecache.go deleted file mode 100644 index b2b34e1207..0000000000 --- a/pkg/multicloud/bingocloud/storagecache.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.STagBase - - region *SRegion - storageId string - storageName string -} - -func (self *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", self.region.GetGlobalId(), self.storageId) -} - -func (self *SStoragecache) GetGlobalId() string { - return self.GetId() -} - -func (self *SStoragecache) GetName() string { - return self.storageName -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -func (self *SStoragecache) GetStatus() string { - return "available" -} - -func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { - return "", cloudprovider.ErrNotImplemented -} diff --git a/pkg/multicloud/bingocloud/vpc.go b/pkg/multicloud/bingocloud/vpc.go deleted file mode 100644 index ddb96f2b5f..0000000000 --- a/pkg/multicloud/bingocloud/vpc.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - multicloud.STagBase - - region *SRegion - - RequestId string `json:"requestId"` - VlanNum string `json:"vlanNum"` - AsGateway string `json:"asGateway"` - DhcpOptionsId string `json:"dhcpOptionsId"` - VpcName string `json:"vpcName"` - OwnerId string `json:"ownerId"` - WanCode string `json:"wanCode"` - Shared string `json:"shared"` - SubnetPolicy string `json:"subnetPolicy"` - Description string `json:"description"` - VpcId string `json:"vpcId"` - IsPublicNetwork string `json:"isPublicNetwork"` - GatewayId string `json:"gatewayId"` - IsDefault string `json:"isDefault"` - Provider string `json:"provider"` - State string `json:"state"` - CidrBlock string `json:"cidrBlock"` - InstanceTenancy string `json:"instanceTenancy"` -} - -func (self *SVpc) GetId() string { - return self.VpcId -} - -func (self *SVpc) GetGlobalId() string { - return self.VpcId -} - -func (self *SVpc) GetName() string { - return self.VpcName -} - -func (self *SVpc) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (self *SVpc) GetCidrBlock() string { - return self.CidrBlock -} - -func (self *SVpc) GetIRouteTableById(id string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - part, nextToken, err := self.region.GetSecurityGroups("", "", "") - if err != nil { - return nil, err - } - groups := []SSecurityGroup{} - groups = append(groups, part...) - for len(nextToken) > 0 { - part, nextToken, err = self.region.GetSecurityGroups("", "", nextToken) - if err != nil { - return nil, err - } - groups = append(groups, part...) - } - ret := []cloudprovider.ICloudSecurityGroup{} - for i := range groups { - groups[i].region = self.region - ret = append(ret, &groups[i]) - } - return ret, nil -} - -func (self *SVpc) GetIsDefault() bool { - return self.IsDefault == "true" -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetStatus() string { - switch self.State { - case "available": - return api.VPC_STATUS_AVAILABLE - default: - return self.State - } -} - -func (self *SRegion) GetVpcs(id string) ([]SVpc, error) { - params := map[string]string{} - if len(id) > 0 { - params["vpcId"] = id - } - resp, err := self.invoke("DescribeVpcs", params) - if err != nil { - return nil, err - } - vpcs := []SVpc{} - return vpcs, resp.Unmarshal(&vpcs, "vpcSet") -} - -func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - vpcs, err := self.GetVpcs("") - if err != nil { - return nil, errors.Wrapf(err, "GetVpcs") - } - ret := []cloudprovider.ICloudVpc{} - for i := range vpcs { - vpcs[i].region = self - ret = append(ret, &vpcs[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/bingocloud/wire.go b/pkg/multicloud/bingocloud/wire.go deleted file mode 100644 index ed729ca1b7..0000000000 --- a/pkg/multicloud/bingocloud/wire.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 bingocloud - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.STagBase - multicloud.SResourceBase - - cluster *SCluster - vpc *SVpc -} - -func (self *SWire) GetId() string { - return fmt.Sprintf("%s/%s", self.vpc.GetGlobalId(), self.cluster.GetGlobalId()) -} - -func (self *SWire) GetGlobalId() string { - return self.GetId() -} - -func (self *SWire) GetName() string { - return fmt.Sprintf("%s-%s", self.vpc.GetName(), self.cluster.GetName()) -} - -func (self *SWire) GetBandwidth() int { - return 1000 -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) IsEmulated() bool { - return true -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - return self.cluster -} - -func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { - wires, err := self.GetIWires() - if err != nil { - return nil, err - } - for i := range wires { - if wires[i].GetGlobalId() == id { - return wires[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - clusters, err := self.region.GetClusters() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudWire{} - for i := range clusters { - wire := &SWire{ - vpc: self, - cluster: &clusters[i], - } - ret = append(ret, wire) - } - return ret, nil -} diff --git a/pkg/multicloud/cloudpods/disk.go b/pkg/multicloud/cloudpods/disk.go deleted file mode 100644 index 8b408e4de5..0000000000 --- a/pkg/multicloud/cloudpods/disk.go +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDisk struct { - multicloud.SVirtualResourceBase - multicloud.SBillingBase - multicloud.CloudpodsTags - region *SRegion - - api.DiskDetails - guestDisk *api.GuestDiskDetails -} - -func (self *SDisk) GetId() string { - return self.Id -} - -func (self *SDisk) GetGlobalId() string { - return self.Id -} - -func (self *SDisk) GetName() string { - return self.Name -} - -func (self *SDisk) GetStatus() string { - return self.Status -} - -func (self *SDisk) GetIops() int { - return 0 -} - -func (self *SDisk) Refresh() error { - disk, err := self.region.GetDisk(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, disk) -} - -func (self *SDisk) GetDiskFormat() string { - return self.DiskFormat -} - -func (self *SDisk) GetDiskSizeMB() int { - return self.DiskSize -} - -func (self *SDisk) GetIsAutoDelete() bool { - return self.AutoDelete -} - -func (self *SDisk) GetTemplateId() string { - return self.TemplateId -} - -func (self *SDisk) GetDiskType() string { - return self.DiskType -} - -func (self *SDisk) GetFsFormat() string { - return self.FsFormat -} - -func (self *SDisk) GetIsNonPersistent() bool { - return self.Nonpersistent -} - -func (self *SDisk) fetchGuestDisk() error { - if self.guestDisk != nil { - return nil - } - if len(self.Guests) > 0 { - gds, err := self.region.GetGuestDisks("", self.Id) - if err != nil { - return err - } - for i := range gds { - self.guestDisk = &gds[i] - break - } - } - return nil -} - -func (self *SDisk) GetDriver() string { - self.fetchGuestDisk() - if self.guestDisk != nil { - return self.guestDisk.Driver - } - return "" -} - -func (self *SDisk) GetCacheMode() string { - self.fetchGuestDisk() - if self.guestDisk != nil { - return self.guestDisk.CacheMode - } - return "" -} - -func (self *SDisk) GetMountpoint() string { - self.fetchGuestDisk() - if self.guestDisk != nil { - return self.guestDisk.Mountpoint - } - return "" -} - -func (self *SDisk) GetAccessPath() string { - return self.AccessPath -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := self.region.GetSnapshots(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudSnapshot{} - for i := range snapshots { - snapshots[i].region = self.region - ret = append(ret, &snapshots[i]) - } - return ret, nil -} - -func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { - ret := []string{} - for _, policy := range self.Snapshotpolicies { - ret = append(ret, policy.Id) - } - return ret, nil -} - -func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { - input := api.DiskResizeInput{} - input.Size = fmt.Sprintf("%dM", sizeMb) - _, err := self.region.perform(&modules.Disks, self.Id, "resize", input) - return err -} - -func (self *SDisk) Reset(ctx context.Context, snapId string) (string, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(snapId), "snapshot") - _, err := self.region.perform(&modules.Disks, self.Id, "disk-reset", params) - return self.Id, err -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SDisk) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SDisk) GetExpiredAt() time.Time { - return self.ExpiredAt -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - input := api.SnapshotCreateInput{} - input.Name = name - input.Description = desc - input.DiskId = self.Id - input.ProjectId = self.TenantId - snapshot := &SSnapshot{region: self.region} - return snapshot, self.region.create(&modules.Snapshots, input, snapshot) -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - storage, err := self.region.GetStorage(self.StorageId) - if err != nil { - return nil, err - } - return storage, nil -} - -func (self *SDisk) GetIStorageId() string { - return self.StorageId -} - -func (self *SDisk) Delete(ctx context.Context) error { - return self.region.cli.delete(&modules.Disks, self.Id) -} - -func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := self.region.GetDisks(self.Id, "") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudDisk{} - for i := range disks { - disks[i].region = self.region - ret = append(ret, &disks[i]) - } - return ret, nil -} - -func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - disk, err := self.region.GetDisk(id) - if err != nil { - return nil, err - } - return disk, nil -} - -func (self *SStorage) CreateIDisk(opts *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - input := api.DiskCreateInput{ - DiskConfig: &api.DiskConfig{}, - } - input.Name = opts.Name - input.Description = opts.Desc - input.SizeMb = opts.SizeGb * 1024 - input.Storage = self.Id - input.ProjectId = opts.ProjectId - disk := &SDisk{region: self.region} - return disk, self.region.create(&modules.Disks, input, disk) -} - -func (self *SRegion) GetDisk(id string) (*SDisk, error) { - disk := &SDisk{region: self} - return disk, self.cli.get(&modules.Disks, id, nil, disk) -} - -func (self *SRegion) GetDisks(storageId, serverId string) ([]SDisk, error) { - params := map[string]interface{}{} - if len(storageId) > 0 { - params["storage_id"] = storageId - } - if len(serverId) > 0 { - params["server_id"] = serverId - } - disks := []SDisk{} - return disks, self.list(&modules.Disks, params, &disks) -} - -func (self *SRegion) GetGuestDisks(guestId string, diskId string) ([]api.GuestDiskDetails, error) { - params := map[string]interface{}{ - "scope": "system", - } - if len(guestId) > 0 { - params["server_id"] = guestId - } - if len(diskId) > 0 { - params["disk_id"] = diskId - } - ret := []api.GuestDiskDetails{} - resp, err := modules.Serverdisks.List(self.cli.s, jsonutils.Marshal(params)) - if err != nil { - return nil, err - } - return ret, jsonutils.Update(&ret, resp.Data) -} diff --git a/pkg/multicloud/cloudpods/doc.go b/pkg/multicloud/cloudpods/doc.go deleted file mode 100644 index 7b24c902e4..0000000000 --- a/pkg/multicloud/cloudpods/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods // import "yunion.io/x/onecloud/pkg/multicloud/cloudpods" diff --git a/pkg/multicloud/cloudpods/eip.go b/pkg/multicloud/cloudpods/eip.go deleted file mode 100644 index 430c0f2621..0000000000 --- a/pkg/multicloud/cloudpods/eip.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SEip struct { - multicloud.SVirtualResourceBase - multicloud.SBillingBase - multicloud.CloudpodsTags - region *SRegion - - api.ElasticipDetails -} - -func (self *SEip) GetName() string { - return self.Name -} - -func (self *SEip) GetId() string { - return self.Id -} - -func (self *SEip) GetGlobalId() string { - return self.Id -} - -func (self *SEip) GetProjectId() string { - return self.TenantId -} - -func (self *SEip) GetStatus() string { - return self.Status -} - -func (self *SEip) Refresh() error { - eip, err := self.region.GetEip(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, eip) -} - -func (self *SEip) GetBillingType() string { - return self.BillingType -} - -func (self *SEip) GetIpAddr() string { - return self.IpAddr -} - -func (self *SEip) GetINetworkId() string { - return self.NetworkId -} - -func (self *SEip) GetAssociationType() string { - return self.AssociateType -} - -func (self *SEip) GetAssociationExternalId() string { - return self.AssociateId -} - -func (self *SEip) GetBandwidth() int { - return self.Bandwidth -} - -func (self *SEip) GetInternetChargeType() string { - return self.ChargeType -} - -func (self *SEip) Delete() error { - return self.region.cli.delete(&modules.Elasticips, self.Id) -} - -func (self *SEip) IsAutoRenew() bool { - return self.AutoRenew -} - -func (self *SEip) Associate(opts *cloudprovider.AssociateConfig) error { - input := api.ElasticipAssociateInput{} - input.InstanceType = opts.AssociateType - input.InstanceId = opts.InstanceId - switch opts.AssociateType { - case api.EIP_ASSOCIATE_TYPE_SERVER: - default: - return cloudprovider.ErrNotImplemented - } - _, err := self.region.perform(&modules.Elasticips, self.Id, "associate", input) - return err -} - -func (self *SEip) Dissociate() error { - _, err := self.region.perform(&modules.Elasticips, self.Id, "dissociate", nil) - return err -} - -func (self *SEip) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SEip) GetExpiredAt() time.Time { - return self.ExpiredAt -} - -func (self *SEip) GetMode() string { - return self.Mode -} - -func (self *SEip) ChangeBandwidth(bw int) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { - eip, err := self.GetEip(id) - if err != nil { - return nil, err - } - return eip, nil -} - -func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, err := self.GetEips("") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudEIP{} - for i := range eips { - eips[i].region = self - ret = append(ret, &eips[i]) - } - return ret, nil -} - -func (self *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - input := api.SElasticipCreateInput{} - input.Name = opts.Name - input.CloudregionId = self.Id - input.ChargeType = opts.ChargeType - input.BandwidthMb = opts.BandwidthMbps - input.ProjectId = opts.ProjectId - input.NetworkId = opts.NetworkExternalId - input.BgpType = opts.BGPType - input.IpAddr = opts.IP - eip := &SEip{region: self} - return eip, self.create(&modules.Elasticips, input, eip) -} - -func (self *SRegion) GetEips(associateId string) ([]SEip, error) { - eips := []SEip{} - params := map[string]interface{}{} - if len(associateId) > 0 { - params["associate_id"] = associateId - } - return eips, self.list(&modules.Elasticips, params, &eips) -} - -func (self *SRegion) GetEip(id string) (*SEip, error) { - eip := &SEip{region: self} - return eip, self.cli.get(&modules.Elasticips, id, nil, eip) -} diff --git a/pkg/multicloud/cloudpods/host.go b/pkg/multicloud/cloudpods/host.go deleted file mode 100644 index 6275b52fa6..0000000000 --- a/pkg/multicloud/cloudpods/host.go +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/tristate" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone - - api.HostDetails -} - -func (self *SHost) GetGlobalId() string { - return self.Id -} - -func (self *SHost) GetId() string { - return self.Id -} - -func (self *SHost) GetName() string { - return self.Name -} - -func (self *SHost) GetStatus() string { - return self.Status -} - -func (self *SHost) GetAccessIp() string { - return self.AccessIp -} - -func (self *SHost) GetOvnVersion() string { - return self.OvnVersion -} - -func (self *SHost) Refresh() error { - host, err := self.zone.region.GetHost(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, host) -} - -func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - wires, err := self.zone.region.GetWires("", self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudWire{} - for i := range wires { - vpc, _ := self.zone.region.GetVpc(wires[i].VpcId) - wires[i].vpc = vpc - ret = append(ret, &wires[i]) - } - return ret, nil -} - -func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := self.zone.region.GetStorages("", self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStorage{} - for i := range storages { - storages[i].region = self.zone.region - ret = append(ret, &storages[i]) - } - return ret, nil -} - -func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storage, err := self.zone.region.GetStorage(id) - if err != nil { - return nil, err - } - return storage, nil -} - -func (self *SHost) GetEnabled() bool { - return self.Enabled != nil && *self.Enabled -} - -func (self *SHost) GetHostStatus() string { - return self.HostStatus -} - -func (self *SHost) GetAccessMac() string { - return self.AccessMac -} - -func (self *SHost) GetSysInfo() jsonutils.JSONObject { - return jsonutils.Marshal(self.SysInfo) -} - -func (self *SHost) GetSN() string { - return self.SN -} - -func (self *SHost) GetCpuCount() int { - return self.CpuCount -} - -func (self *SHost) GetNodeCount() int8 { - return int8(self.NodeCount) -} - -func (self *SHost) GetCpuDesc() string { - return self.CpuDesc -} - -func (self *SHost) GetCpuMhz() int { - return self.CpuMhz -} - -func (self *SHost) GetCpuCmtbound() float32 { - return self.CpuCmtbound -} - -func (self *SHost) GetMemSizeMB() int { - return self.MemSize -} - -func (self *SHost) GetMemCmtbound() float32 { - return self.MemCmtbound -} - -func (self *SHost) GetReservedMemoryMb() int { - return self.MemReserved -} - -func (self *SHost) GetStorageSizeMB() int { - return self.StorageSize -} - -func (self *SHost) GetStorageType() string { - return self.StorageType -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_CLOUDPODS -} - -func (self *SHost) GetIsMaintenance() bool { - return self.IsMaintenance -} - -func (self *SHost) GetVersion() string { - return self.Version -} - -func (self *SHost) GetSchedtags() ([]string, error) { - ret := []string{} - for _, tag := range self.Schedtags { - ret = append(ret, tag.Name) - } - return ret, nil -} - -type SHostNic struct { - api.HostnetworkDetails -} - -func (self *SHostNic) GetDriver() string { - return "" -} - -func (self *SHostNic) GetDevice() string { - return "" -} - -func (self *SHostNic) GetMac() string { - return self.MacAddr -} - -func (self *SHostNic) GetIndex() int8 { - return int8(self.RowId) -} - -func (self *SHostNic) IsLinkUp() tristate.TriState { - return tristate.True -} - -func (self *SHostNic) GetMtu() int32 { - return 0 -} - -func (self *SHostNic) GetNicType() string { - return self.NicType -} - -func (self *SHostNic) GetBridge() string { - return "" -} - -func (self *SHostNic) GetIpAddr() string { - return self.IpAddr -} - -func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - nics := []SHostNic{} - params := map[string]interface{}{ - "scope": "system", - "details": "true", - } - resp, err := modules.Baremetalnetworks.ListDescendent(self.zone.region.cli.s, self.Id, jsonutils.Marshal(params)) - if err != nil { - return nil, err - } - err = jsonutils.Update(&nics, resp.Data) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudHostNetInterface{} - for i := range nics { - ret = append(ret, &nics[i]) - } - return ret, nil -} - -func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - hypervisor := api.HOSTTYPE_HYPERVISOR[self.HostType] - ins, err := self.zone.region.CreateInstance(self.Id, hypervisor, opts) - if err != nil { - return nil, err - } - ins.host = self - return ins, nil -} - -func (self *SRegion) GetHost(id string) (*SHost, error) { - host := &SHost{} - return host, self.cli.get(&modules.Hosts, id, nil, host) -} - -func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - host, err := self.region.GetHost(id) - if err != nil { - return nil, err - } - host.zone = self - return host, nil -} - -func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - hosts, err := self.region.GetHosts(self.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetHosts") - } - ret := []cloudprovider.ICloudHost{} - for i := range hosts { - hosts[i].zone = self - ret = append(ret, &hosts[i]) - } - return ret, nil -} - -func (self *SRegion) GetHosts(zoneId string) ([]SHost, error) { - params := map[string]interface{}{ - "baremetal": false, - } - if len(zoneId) > 0 { - params["zone_id"] = zoneId - } - ret := []SHost{} - return ret, self.list(&modules.Hosts, params, &ret) -} diff --git a/pkg/multicloud/cloudpods/image.go b/pkg/multicloud/cloudpods/image.go deleted file mode 100644 index 1895542947..0000000000 --- a/pkg/multicloud/cloudpods/image.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "context" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/image" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/esxi/options" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/mcclient/auth" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SImage struct { - multicloud.SImageBase - multicloud.CloudpodsTags - cache *SStoragecache - - api.ImageDetails -} - -func (self *SImage) GetProjectId() string { - return self.TenantId -} - -func (self *SImage) GetName() string { - return self.Name -} - -func (self *SImage) GetId() string { - return self.Id -} - -func (self *SImage) GetGlobalId() string { - return self.Id -} - -func (self *SImage) GetStatus() string { - return self.Status -} - -func (self *SImage) Delete(ctx context.Context) error { - return self.cache.region.cli.delete(&modules.Images, self.Id) -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.cache -} - -func (self *SImage) GetSizeByte() int64 { - return self.Size -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - if self.IsStandard != nil && *self.IsStandard { - return cloudprovider.ImageTypeSystem - } - return cloudprovider.ImageTypeCustomized -} - -func (self *SImage) GetImageStatus() string { - return self.Status -} - -func (self *SImage) GetOsType() cloudprovider.TOsType { - osType, ok := self.Properties["os_type"] - if ok { - return cloudprovider.TOsType(osType) - } - return cloudprovider.OsTypeLinux -} - -func (self *SImage) GetOsDist() string { - osDist, ok := self.Properties["os_distribution"] - if ok { - return osDist - } - return "" -} - -func (self *SImage) GetOsVersion() string { - osVer, ok := self.Properties["os_version"] - if ok { - return osVer - } - return "" -} - -func (self *SImage) GetOsArch() string { - osArch, ok := self.Properties["os_arch"] - if ok { - return osArch - } - return "" -} - -func (self *SImage) GetOsLang() string { - osLang, ok := self.Properties["os_language"] - if ok { - return osLang - } - return "" -} - -func (self *SImage) GetBios() cloudprovider.TBiosType { - uefi, ok := self.Properties["uefi_support"] - if ok && utils.ToBool(uefi) { - return cloudprovider.UEFI - } - return cloudprovider.BIOS -} - -func (img *SImage) GetFullOsName() string { - imgInfo := imagetools.NormalizeImageInfo("", img.GetOsArch(), string(img.GetOsType()), img.GetOsDist(), img.GetOsVersion()) - return imgInfo.GetFullOsName() -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return int(self.MinDiskMB / 1024) -} - -func (self *SImage) GetMinRamSizeMb() int { - return int(self.MinRamMB) -} - -func (self *SImage) GetImageFormat() string { - return self.DiskFormat -} - -func (self *SImage) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SImage) Refresh() error { - image, err := self.cache.region.GetImage(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, image) -} - -func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - images, err := self.region.GetImages() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudImage{} - for i := range images { - images[i].cache = self - ret = append(ret, &images[i]) - } - return ret, nil -} - -func (self *SRegion) GetImages() ([]SImage, error) { - params := map[string]interface{}{ - "is_guest_image": false, - } - images := []SImage{} - return images, self.list(&modules.Images, params, &images) -} - -func (self *SRegion) GetImage(id string) (*SImage, error) { - image := &SImage{} - resp, err := modules.Images.GetById(self.cli.s, id, nil) - if err != nil { - return nil, err - } - return image, resp.Unmarshal(image) -} - -func (self *SRegion) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, opts *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - s := auth.GetAdminSession(ctx, options.Options.Region) - - meta, reader, sizeByte, err := modules.Images.Download(s, opts.ImageId, string(qemuimg.QCOW2), false) - if err != nil { - return "", err - } - log.Infof("meta data %s", meta) - - params := map[string]interface{}{ - "name": opts.ImageName, - "properties": map[string]string{ - "os_type": opts.OsType, - "os_distribution": opts.OsDistribution, - "os_arch": opts.OsArch, - "os_version": opts.OsVersion, - }, - } - - body := multicloud.NewProgress(sizeByte, 90, reader, callback) - resp, err := modules.Images.Upload(self.cli.s, jsonutils.Marshal(params), body, sizeByte) - if err != nil { - return "", err - } - return resp.GetString("id") -} diff --git a/pkg/multicloud/cloudpods/instance.go b/pkg/multicloud/cloudpods/instance.go deleted file mode 100644 index 37edff0d14..0000000000 --- a/pkg/multicloud/cloudpods/instance.go +++ /dev/null @@ -1,565 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/apis" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/mcclient/modules/identity" - "yunion.io/x/onecloud/pkg/mcclient/modules/logger" - "yunion.io/x/onecloud/pkg/mcclient/modules/monitor" - "yunion.io/x/onecloud/pkg/mcclient/modules/webconsole" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SInstance struct { - multicloud.SInstanceBase - multicloud.CloudpodsTags - - host *SHost - api.ServerDetails -} - -func (self *SInstance) GetName() string { - return self.Name -} - -func (self *SInstance) GetHostname() string { - return self.Hostname -} - -func (self *SInstance) GetId() string { - return self.Id -} - -func (self *SInstance) GetGlobalId() string { - return self.Id -} - -func (self *SInstance) GetStatus() string { - return self.Status -} - -func (self *SInstance) Refresh() error { - ins, err := self.host.zone.region.GetInstance(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, ins) -} - -func (self *SInstance) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SInstance) GetExpiredAt() time.Time { - return self.ExpiredAt -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetIHostId() string { - return self.HostId -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := self.host.zone.region.GetDisks("", self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudDisk{} - for i := range disks { - disks[i].region = self.host.zone.region - ret = append(ret, &disks[i]) - } - return ret, nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - if len(self.Eip) > 0 { - eips, err := self.host.zone.region.GetEips(self.Id) - if err != nil { - return nil, err - } - for i := range eips { - eips[i].region = self.host.zone.region - return &eips[i], nil - } - return nil, cloudprovider.ErrNotFound - } - return nil, nil -} - -func (self *SInstance) GetVcpuCount() int { - return self.VcpuCount -} - -func (self *SInstance) GetVmemSizeMB() int { - return self.VmemSize -} - -func (self *SInstance) GetBootOrder() string { - return self.BootOrder -} - -func (self *SInstance) GetVga() string { - return self.Vga -} - -func (self *SInstance) GetVdi() string { - return self.Vdi -} - -func (self *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(self.OsType) -} - -func (self *SInstance) GetFullOsName() string { - return self.OsName -} - -func (self *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(self.Bios) -} - -func (ins *SInstance) GetOsDist() string { - val, ok := ins.Metadata["os_distribution"] - if ok { - return val - } - return "" -} - -func (ins *SInstance) GetOsVersion() string { - val, ok := ins.Metadata["os_version"] - if ok { - return val - } - return "" -} - -func (ins *SInstance) GetOsLang() string { - val, ok := ins.Metadata["os_language"] - if ok { - return val - } - return "" -} - -func (ins *SInstance) GetOsArch() string { - return ins.OsArch -} - -func (self *SInstance) GetMachine() string { - return self.Machine -} - -func (self *SInstance) GetInstanceType() string { - return self.InstanceType -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - ret := []string{} - for _, sec := range self.Secgroups { - ret = append(ret, sec.Id) - } - return ret, nil -} - -func (self *SInstance) GetProjectId() string { - return self.TenantId -} - -func (self *SInstance) AssignSecurityGroup(id string) error { - input := api.GuestAssignSecgroupInput{} - input.SecgroupId = id - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "assign-secgroup", input) - return err -} - -func (self *SInstance) SetSecurityGroups(ids []string) error { - if self.Hypervisor == api.HYPERVISOR_ESXI { - return nil - } - input := api.GuestSetSecgroupInput{} - input.SecgroupIds = ids - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "set-secgroup", input) - return err -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_CLOUDPODS -} - -func (self *SInstance) StartVM(ctx context.Context) error { - if self.Status == api.VM_RUNNING { - return nil - } - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "start", nil) - return err -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - if self.Status == api.VM_READY { - return nil - } - input := api.ServerStopInput{} - input.IsForce = opts.IsForce - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "stop", input) - return err -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - if self.DisableDelete != nil && *self.DisableDelete { - input := api.ServerUpdateInput{} - disableDelete := false - input.DisableDelete = &disableDelete - self.host.zone.region.cli.update(&modules.Servers, self.Id, input) - } - return self.host.zone.region.cli.delete(&modules.Servers, self.Id) -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - if self.Name != name { - input := api.ServerUpdateInput{} - input.Name = name - self.host.zone.region.cli.update(&modules.Servers, self.Id, input) - return cloudprovider.WaitMultiStatus(self, []string{api.VM_READY, api.VM_RUNNING}, time.Second*5, time.Minute*3) - } - return nil -} - -func (self *SInstance) UpdateUserData(userData string) error { - input := api.ServerUserDataInput{} - input.UserData = userData - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "user-data", input) - return err -} - -func (self *SInstance) RebuildRoot(ctx context.Context, opts *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - input := api.ServerRebuildRootInput{} - input.ImageId = opts.ImageId - input.Password = opts.Password - if len(opts.PublicKey) > 0 { - keypairId, err := self.host.zone.region.syncKeypair(self.Name, opts.PublicKey) - if err != nil { - return "", errors.Wrapf(err, "syncKeypair") - } - input.KeypairId = keypairId - } - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "rebuild-root", input) - if err != nil { - return "", err - } - return self.DisksInfo[0].Id, nil -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - input := api.ServerDeployInput{} - input.Password = password - if len(publicKey) > 0 { - keypairId, err := self.host.zone.region.syncKeypair(name, publicKey) - if err != nil { - return errors.Wrapf(err, "syncKeypair") - } - input.KeypairId = keypairId - } - - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "deploy", input) - if err != nil { - return errors.Wrapf(err, "deploy") - } - return cloudprovider.WaitMultiStatus(self, []string{api.VM_READY, api.VM_RUNNING}, time.Second*5, time.Minute*3) -} - -func (self *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error { - input := api.ServerChangeConfigInput{} - input.VmemSize = fmt.Sprintf("%dM", opts.MemoryMB) - input.VcpuCount = opts.Cpu - input.InstanceType = opts.InstanceType - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "change-config", input) - return err -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - s := self.host.zone.region.cli.s - resp, err := webconsole.WebConsole.DoServerConnect(s, self.Id, nil) - if err != nil { - return nil, errors.Wrapf(err, "DoServerConnect") - } - result := &cloudprovider.ServerVncOutput{ - Protocol: "cloudpods", - InstanceId: self.Id, - InstanceName: self.Name, - Hypervisor: api.HYPERVISOR_CLOUDPODS, - } - err = resp.Unmarshal(&result) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - resp, err = identity.ServicesV3.GetSpecific(s, "common", "config", nil) - if err != nil { - return nil, errors.Wrapf(err, "GetSpecific") - } - result.ApiServer, _ = resp.GetString("config", "default", "api_server") - return result, nil -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - input := api.ServerAttachDiskInput{} - input.DiskId = diskId - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "attachdisk", input) - return err -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - input := api.ServerDetachDiskInput{} - input.DiskId = diskId - input.KeepDisk = true - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "detachdisk", input) - return err -} - -func (self *SInstance) MigrateVM(hostId string) error { - input := api.GuestMigrateInput{} - input.PreferHost = hostId - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "migrate", input) - return err -} - -func (self *SInstance) LiveMigrateVM(hostId string) error { - input := api.GuestLiveMigrateInput{} - input.PreferHost = hostId - skipCpuCheck := true - input.SkipCpuCheck = &skipCpuCheck - _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "live-migrate", input) - return err -} - -func (self *SInstance) GetError() error { - if utils.IsInStringArray(self.Status, []string{api.VM_DISK_FAILED, api.VM_SCHEDULE_FAILED, api.VM_NETWORK_FAILED}) { - return fmt.Errorf("vm create failed with status %s", self.Status) - } - if self.Status == api.VM_DEPLOY_FAILED { - params := map[string]interface{}{"obj_id": self.Id, "success": false} - actions := []apis.OpsLogDetails{} - self.host.zone.region.list(&logger.Actions, params, &actions) - if len(actions) > 0 { - return fmt.Errorf(actions[0].Notes) - } - return fmt.Errorf("vm create failed with status %s", self.Status) - } - return nil -} - -func (self *SInstance) CreateInstanceSnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudInstanceSnapshot, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SInstance) GetInstanceSnapshot(idStr string) (cloudprovider.ICloudInstanceSnapshot, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SInstance) GetInstanceSnapshots() ([]cloudprovider.ICloudInstanceSnapshot, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SInstance) ResetToInstanceSnapshot(ctx context.Context, idStr string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { - return self.host.zone.region.SaveImage(self.Id, opts.Name, opts.Notes) -} - -func (self *SRegion) SaveImage(id, imageName, notes string) (*SImage, error) { - input := api.ServerSaveImageInput{} - input.GenerateName = imageName - input.Notes = notes - resp, err := self.perform(&modules.Servers, id, "save-image", input) - if err != nil { - return nil, err - } - imageId, err := resp.GetString("image_id") - if err != nil { - return nil, err - } - caches, err := self.GetStoragecaches() - if err != nil { - return nil, errors.Wrapf(err, "GetStoragecaches") - } - if len(caches) == 0 { - return nil, fmt.Errorf("no storage cache found") - } - caches[0].region = self - image, err := self.GetImage(imageId) - if err != nil { - return nil, err - } - image.cache = &caches[0] - return image, nil -} - -func (self *SInstance) AllocatePublicIpAddress() (string, error) { - return "", cloudprovider.ErrNotImplemented -} - -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - servers, err := self.zone.region.GetInstances(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudVM{} - for i := range servers { - servers[i].host = self - ret = append(ret, &servers[i]) - } - return ret, nil -} - -func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - ins, err := self.zone.region.GetInstance(id) - if err != nil { - return nil, err - } - ins.host = self - return ins, nil -} - -func (self *SRegion) GetInstance(id string) (*SInstance, error) { - ins := &SInstance{} - return ins, self.cli.get(&modules.Servers, id, nil, ins) -} - -func (self *SRegion) GetInstances(hostId string) ([]SInstance, error) { - params := map[string]interface{}{} - if len(hostId) > 0 { - params["host_id"] = hostId - } - ret := []SInstance{} - return ret, self.list(&modules.Servers, params, &ret) -} - -func (self *SRegion) CreateInstance(hostId, hypervisor string, opts *cloudprovider.SManagedVMCreateConfig) (*SInstance, error) { - input := api.ServerCreateInput{ - ServerConfigs: &api.ServerConfigs{}, - } - input.Name = opts.Name - input.Hostname = opts.Hostname - input.Description = opts.Description - input.InstanceType = opts.InstanceType - input.VcpuCount = opts.Cpu - input.VmemSize = opts.MemoryMB - input.Password = opts.Password - input.PublicIpBw = opts.PublicIpBw - input.PublicIpChargeType = string(opts.PublicIpChargeType) - input.ProjectId = opts.ProjectId - input.Metadata = opts.Tags - input.UserData = opts.UserData - input.PreferHost = hostId - input.Hypervisor = hypervisor - if len(input.UserData) > 0 { - input.EnableCloudInit = true - } - input.Secgroups = opts.ExternalSecgroupIds - if opts.BillingCycle != nil { - input.Duration = opts.BillingCycle.String() - } - input.Disks = append(input.Disks, &api.DiskConfig{ - Index: 0, - ImageId: opts.ExternalImageId, - DiskType: api.DISK_TYPE_SYS, - SizeMb: opts.SysDisk.SizeGB * 1024, - Backend: opts.SysDisk.StorageType, - Storage: opts.SysDisk.StorageExternalId, - }) - for idx, disk := range opts.DataDisks { - input.Disks = append(input.Disks, &api.DiskConfig{ - Index: idx + 1, - DiskType: api.DISK_TYPE_DATA, - SizeMb: disk.SizeGB * 1024, - Backend: disk.StorageType, - Storage: disk.StorageExternalId, - }) - } - input.Networks = append(input.Networks, &api.NetworkConfig{ - Index: 0, - Network: opts.ExternalNetworkId, - Address: opts.IpAddr, - }) - ins := &SInstance{} - return ins, self.create(&modules.Servers, input, ins) -} - -type SMetricData struct { - Id string `json:"id"` - Time time.Time `json:"time"` - Value float64 `json:"value"` -} - -func (cli *SCloudpodsClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - brandArr := []string{"OneCloud", "VMware"} - metrics := []SMetricData{} - for i := 0; i < len(brandArr); i++ { - params := map[string]interface{}{ - "metric_name": opts.MetricType, - "tags": map[string]interface{}{ - "brand": brandArr[i], - }, - } - onecloudObj, err := monitor.UnifiedMonitorManager.Get(cli.s, "simple-query", jsonutils.Marshal(params)) - if err != nil { - return nil, err - } - tmp := []SMetricData{} - onecloudObj.Unmarshal(&tmp, "values") - metrics = append(metrics, tmp...) - } - - idWithMetric := map[string][]cloudprovider.MetricValue{} - for _, v := range metrics { - if _, isExist := idWithMetric[v.Id]; !isExist { - idWithMetric[v.Id] = []cloudprovider.MetricValue{{ - Timestamp: v.Time, - Value: v.Value}} - } else { - idWithMetric[v.Id] = append(idWithMetric[v.Id], cloudprovider.MetricValue{ - Timestamp: v.Time, - Value: v.Value}) - } - } - - res := []cloudprovider.MetricValues{} - for _, metric := range metrics { - res = append(res, cloudprovider.MetricValues{ - Id: metric.Id, - MetricType: opts.MetricType, - Values: idWithMetric[metric.Id], - }) - } - return res, nil -} diff --git a/pkg/multicloud/cloudpods/instancenic.go b/pkg/multicloud/cloudpods/instancenic.go deleted file mode 100644 index 21b6594a38..0000000000 --- a/pkg/multicloud/cloudpods/instancenic.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SInstanceNic struct { - multicloud.SResourceBase - ins *SInstance - - api.GuestnetworkDetails -} - -func (self *SInstanceNic) GetId() string { - return fmt.Sprintf("%d", self.RowId) -} - -func (self *SInstanceNic) GetIP() string { - return self.IpAddr -} - -func (self *SInstanceNic) GetDriver() string { - return self.Driver -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (self *SInstanceNic) GetMAC() string { - return self.MacAddr -} - -func (self *SInstanceNic) GetSubAddress() ([]string, error) { - return []string{}, nil -} - -func (self *SInstanceNic) AssignNAddress(count int) ([]string, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstanceNic) UnassignAddress(IpAddrs []string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstanceNic) GetINetworkId() string { - return self.NetworkId -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nics, err := self.host.zone.region.GetGuestnetworks(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNic{} - for i := range nics { - nics[i].ins = self - ret = append(ret, &nics[i]) - } - return ret, nil -} - -func (self *SRegion) GetGuestnetworks(serverId string) ([]SInstanceNic, error) { - ret := []SInstanceNic{} - params := map[string]interface{}{ - "scope": "system", - } - if len(serverId) > 0 { - params["server_id"] = serverId - } - resp, err := modules.Servernetworks.List(self.cli.s, jsonutils.Marshal(params)) - if err != nil { - return nil, err - } - return ret, jsonutils.Update(&ret, resp.Data) -} diff --git a/pkg/multicloud/cloudpods/network.go b/pkg/multicloud/cloudpods/network.go deleted file mode 100644 index 652d5f4ec8..0000000000 --- a/pkg/multicloud/cloudpods/network.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.CloudpodsTags - wire *SWire - - api.NetworkDetails -} - -func (self *SNetwork) GetName() string { - return self.Name -} - -func (self *SNetwork) GetId() string { - return self.Id -} - -func (self *SNetwork) GetGlobalId() string { - return self.Id -} - -func (self *SNetwork) GetStatus() string { - return self.Status -} - -func (self *SNetwork) Delete() error { - return self.wire.vpc.region.cli.delete(&modules.Networks, self.Id) -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetIpStart() string { - return self.GuestIpStart -} - -func (self *SNetwork) GetIpEnd() string { - return self.GuestIpEnd -} - -func (self *SNetwork) GetIpMask() int8 { - return int8(self.GuestIpMask) -} - -func (self *SNetwork) GetGateway() string { - return self.GuestGateway -} - -func (self *SNetwork) GetServerType() string { - return self.ServerType -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.TRbacScope(self.PublicScope) -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return self.AllocTimoutSeconds -} - -func (self *SNetwork) GetProjectId() string { - return self.TenantId -} - -func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - networks, err := self.vpc.region.GetNetworks(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNetwork{} - for i := range networks { - networks[i].wire = self - ret = append(ret, &networks[i]) - } - return ret, nil -} - -func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { - net, err := self.vpc.region.GetNetwork(id) - if err != nil { - return nil, errors.Wrapf(err, "GetNetwork(%s)", id) - } - net.wire = self - return net, nil -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - input := api.NetworkCreateInput{} - input.Name = opts.Name - input.Description = opts.Desc - input.GuestIpPrefix = opts.Cidr - input.WireId = self.Id - input.ProjectId = opts.ProjectId - network := &SNetwork{wire: self} - return network, self.vpc.region.create(&modules.Networks, input, network) -} - -func (self *SRegion) GetNetworks(wireId string) ([]SNetwork, error) { - networks := []SNetwork{} - params := map[string]interface{}{} - if len(wireId) > 0 { - params["wire_id"] = wireId - } - return networks, self.list(&modules.Networks, params, &networks) -} - -func (self *SRegion) GetNetwork(id string) (*SNetwork, error) { - network := &SNetwork{} - return network, self.cli.get(&modules.Networks, id, nil, network) -} diff --git a/pkg/multicloud/cloudpods/project.go b/pkg/multicloud/cloudpods/project.go deleted file mode 100644 index 407af1a385..0000000000 --- a/pkg/multicloud/cloudpods/project.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "yunion.io/x/onecloud/pkg/apis/compute" - api "yunion.io/x/onecloud/pkg/apis/identity" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SProject struct { - multicloud.SProjectBase - multicloud.CloudpodsTags - - cli *SCloudpodsClient - - api.ProjectDetails -} - -func (self *SProject) GetName() string { - return self.Name -} - -func (self *SProject) GetId() string { - return self.Id -} - -func (self *SProject) GetGlobalId() string { - return self.Id -} - -func (self *SProject) GetStatus() string { - return compute.EXTERNAL_PROJECT_STATUS_AVAILABLE -} - -func (self *SCloudpodsClient) GetProjects() ([]SProject, error) { - ret := []SProject{} - params := map[string]interface{}{ - "scope": "system", - "limit": 1024, - } - return ret, self.list(&modules.Projects, params, &ret) -} - -func (self *SCloudpodsClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { - projects, err := self.GetProjects() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudProject{} - for i := range projects { - projects[i].cli = self - ret = append(ret, &projects[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/cloudpods/provider/doc.go b/pkg/multicloud/cloudpods/provider/doc.go deleted file mode 100644 index 36e967dc9e..0000000000 --- a/pkg/multicloud/cloudpods/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/cloudpods/provider" diff --git a/pkg/multicloud/cloudpods/provider/provider.go b/pkg/multicloud/cloudpods/provider/provider.go deleted file mode 100644 index 3cddcf95fe..0000000000 --- a/pkg/multicloud/cloudpods/provider/provider.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" -) - -type SCloudpodsProviderFactory struct { - cloudprovider.SPrivateCloudBaseProviderFactory -} - -func (self *SCloudpodsProviderFactory) GetId() string { - return cloudpods.CLOUD_PROVIDER_CLOUDPODS -} - -func (self *SCloudpodsProviderFactory) GetName() string { - return cloudpods.CLOUD_PROVIDER_CLOUDPODS -} - -func (self *SCloudpodsProviderFactory) IsNeedForceAutoCreateProject() bool { - return true -} - -func (self *SCloudpodsProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - ret := cloudprovider.SCloudaccount{} - if len(input.AuthUrl) == 0 { - return ret, httperrors.NewMissingParameterError("auth_url") - } - ret.AccessUrl = input.AuthUrl - if len(input.AccessKeyId) == 0 { - return ret, httperrors.NewMissingParameterError("access_key_id") - } - ret.Account = input.AccessKeyId - if len(input.AccessKeySecret) == 0 { - return ret, httperrors.NewMissingParameterError("access_key_secret") - } - ret.Secret = input.AccessKeySecret - return ret, nil -} - -func (self *SCloudpodsProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - ret := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return ret, httperrors.NewMissingParameterError("access_key_id") - } - ret.Account = input.AccessKeyId - if len(input.AccessKeySecret) == 0 { - return ret, httperrors.NewMissingParameterError("access_key_secret") - } - ret.Secret = input.AccessKeySecret - return ret, nil -} - -func (self *SCloudpodsProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - client, err := cloudpods.NewCloudpodsClient( - cloudpods.NewCloudpodsClientConfig( - cfg.URL, - cfg.Account, - cfg.Secret, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SCloudpodsProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SCloudpodsProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - return map[string]string{ - "CLOUDPODS_AUTH_URL": info.Url, - "CLOUDPODS_ACCESS_KEY": info.Account, - "CLOUDPODS_ACCESS_SECRET": info.Secret, - }, nil -} - -func init() { - factory := SCloudpodsProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SCloudpodsProvider struct { - cloudprovider.SBaseProvider - client *cloudpods.SCloudpodsClient -} - -func (self *SCloudpodsProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SCloudpodsProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SCloudpodsProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (self *SCloudpodsProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SCloudpodsProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SCloudpodsProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(extId) -} - -func (self *SCloudpodsProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SCloudpodsProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (self *SCloudpodsProvider) GetStorageClasses(regionId string) []string { - return nil -} - -func (self *SCloudpodsProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SCloudpodsProvider) GetSysInfo() (jsonutils.JSONObject, error) { - return jsonutils.NewDict(), nil -} - -func (self *SCloudpodsProvider) GetVersion() string { - return self.client.GetVersion() -} - -func (provider *SCloudpodsProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return provider.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/cloudpods/region.go b/pkg/multicloud/cloudpods/region.go deleted file mode 100644 index 4220961bbf..0000000000 --- a/pkg/multicloud/cloudpods/region.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - multicloud.SRegion - multicloud.SRegionOssBase - multicloud.SRegionLbBase - multicloud.SRegionSecurityGroupBase - cli *SCloudpodsClient - - api.CloudregionDetails -} - -func (self *SRegion) GetClient() *SCloudpodsClient { - return self.cli -} - -func (self *SRegion) GetId() string { - return self.Id -} - -func (self *SRegion) GetName() string { - return fmt.Sprintf("%s-%s", self.cli.cpcfg.Name, self.Name) -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s/%s", CLOUD_PROVIDER_CLOUDPODS, self.cli.cpcfg.Id, self.Name) -} - -func (self *SRegion) GetStatus() string { - return self.Status -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) - return table -} - -func (self *SRegion) GetCapabilities() []string { - return self.cli.GetCapabilities() -} - -func (self *SRegion) GetCloudEnv() string { - return api.CLOUD_ENV_PRIVATE_CLOUD -} - -func (self *SRegion) GetProvider() string { - return api.CLOUD_PROVIDER_CLOUDPODS -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - return cloudprovider.SGeographicInfo{ - Latitude: self.Latitude, - Longitude: self.Longitude, - City: self.City, - CountryCode: self.CountryCode, - } -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - ins, err := self.GetInstance(id) - if err != nil { - return nil, err - } - return ins, nil -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - disk, err := self.GetDisk(id) - if err != nil { - return nil, err - } - return disk, nil -} - -func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - host, err := self.GetHost(id) - if err != nil { - return nil, err - } - if host.CloudregionId != self.Id { - return nil, cloudprovider.ErrNotFound - } - zone, err := self.GetZone(host.ZoneId) - if err != nil { - return nil, err - } - host.zone = zone - return host, nil -} - -func (self *SRegion) create(manager ModelManager, params interface{}, retVal interface{}) error { - return self.cli.create(manager, params, retVal) -} - -func (self *SRegion) perform(manager ModelManager, id, action string, params interface{}) (jsonutils.JSONObject, error) { - return self.cli.perform(manager, id, action, params) -} - -func (self *SRegion) list(manager ModelManager, params map[string]interface{}, retVal interface{}) error { - if params == nil { - params = map[string]interface{}{} - } - params["cloudregion_id"] = self.Id - return self.cli.list(manager, params, retVal) -} diff --git a/pkg/multicloud/cloudpods/secgroup.go b/pkg/multicloud/cloudpods/secgroup.go deleted file mode 100644 index e2f934d44f..0000000000 --- a/pkg/multicloud/cloudpods/secgroup.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "fmt" - "strings" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSecurityGroup struct { - multicloud.SResourceBase - multicloud.CloudpodsTags - region *SRegion - - api.SecgroupDetails -} - -func (self *SSecurityGroup) GetName() string { - return self.Name -} - -func (self *SSecurityGroup) GetDescription() string { - return self.Description -} - -func (self *SSecurityGroup) GetId() string { - return self.Id -} - -func (self *SSecurityGroup) GetGlobalId() string { - return self.Id -} - -func (self *SSecurityGroup) GetStatus() string { - return self.Status -} - -func (self *SSecurityGroup) GetProjectId() string { - return self.TenantId -} - -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - ret := []cloudprovider.SecurityRule{} - for _, r := range self.Rules { - if len(r.PeerSecgroupId) > 0 { - continue - } - rule := cloudprovider.SecurityRule{ExternalId: r.Id} - rule.Action = secrules.TSecurityRuleAction(r.Action) - rule.Priority = int(r.Priority) - rule.Protocol = r.Protocol - rule.Description = r.Description - rule.Direction = secrules.TSecurityRuleDirection(r.Direction) - rule.ParseCIDR(r.CIDR) - rule.ParsePorts(r.Ports) - ret = append(ret, rule) - } - return ret, nil -} - -func (self *SSecurityGroup) GetVpcId() string { - return api.NORMAL_VPC_ID -} - -func (self *SSecurityGroup) GetReferences() ([]cloudprovider.SecurityGroupReference, error) { - params := map[string]interface{}{ - "secgroup_id": self.Id, - } - servers := []SInstance{} - err := self.region.list(&modules.Servers, params, &servers) - if err != nil { - return nil, err - } - ret := []cloudprovider.SecurityGroupReference{} - for i := range servers { - ret = append(ret, cloudprovider.SecurityGroupReference{ - Id: servers[i].Id, - Name: servers[i].Name, - }) - } - return ret, nil -} - -func (self *SRegion) DeleteSecRule(id string) error { - return self.cli.delete(&modules.SecGroupRules, id) -} - -func (self *SRegion) CreateSecRule(secId string, rule cloudprovider.SecurityRule) error { - input := api.SSecgroupRuleCreateInput{} - input.SecgroupId = secId - input.Priority = &rule.Priority - input.Action = string(rule.Action) - input.Protocol = rule.Protocol - input.Direction = string(rule.Direction) - input.Description = rule.Description - if rule.IPNet != nil { - input.CIDR = rule.IPNet.String() - } - - if len(rule.Ports) > 0 { - ports := []string{} - for _, port := range rule.Ports { - ports = append(ports, fmt.Sprintf("%d", port)) - } - input.Ports = strings.Join(ports, ",") - } else if rule.PortStart > 0 && rule.PortEnd > 0 { - input.Ports = fmt.Sprintf("%d-%d", rule.PortStart, rule.PortEnd) - } - ret := struct{}{} - return self.create(&modules.SecGroupRules, input, &ret) -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - for _, r := range append(inDels, outDels...) { - err := self.region.DeleteSecRule(r.Id) - if err != nil { - return errors.Wrapf(err, "delete rule %s", r.Id) - } - } - for _, r := range append(inAdds, outAdds...) { - err := self.region.CreateSecRule(self.Id, r) - if err != nil { - return errors.Wrapf(err, "create rule %s", r) - } - } - return nil -} - -func (self *SSecurityGroup) Delete() error { - return self.region.cli.delete(&modules.SecGroups, self.Id) -} - -func (self *SRegion) GetSecurityGroups() ([]SSecurityGroup, error) { - params := map[string]interface{}{ - "cloud_env": "onpremise", - } - ret := []SSecurityGroup{} - return ret, self.cli.list(&modules.SecGroups, params, &ret) -} - -func (self *SRegion) GetSecurityGroup(id string) (*SSecurityGroup, error) { - secgroup := &SSecurityGroup{region: self} - return secgroup, self.cli.get(&modules.SecGroups, id, nil, secgroup) -} - -func (self *SRegion) CreateISecurityGroup(opts *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - params := map[string]interface{}{ - "name": opts.Name, - "description": opts.Desc, - "rules": opts.Rules, - } - if len(opts.ProjectId) > 0 { - params["project_id"] = opts.ProjectId - } - secgroup := &SSecurityGroup{region: self} - return secgroup, self.create(&modules.SecGroups, params, secgroup) -} - -func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := self.region.GetSecurityGroups() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudSecurityGroup{} - for i := range secgroups { - secgroups[i].region = self.region - ret = append(ret, &secgroups[i]) - } - return ret, nil -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - secgroup, err := self.GetSecurityGroup(secgroupId) - if err != nil { - return nil, err - } - return secgroup, nil -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroup, err := self.GetSecurityGroup(opts.Name) - if err != nil { - return nil, err - } - return secgroup, nil -} diff --git a/pkg/multicloud/cloudpods/shell/disk.go b/pkg/multicloud/cloudpods/shell/disk.go deleted file mode 100644 index 8444cb53c9..0000000000 --- a/pkg/multicloud/cloudpods/shell/disk.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - StorageId string - ServerId string - } - shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *cloudpods.SRegion, args *DiskListOptions) error { - disks, err := cli.GetDisks(args.StorageId, args.ServerId) - if err != nil { - return err - } - printList(disks, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/cloudpods/shell/doc.go b/pkg/multicloud/cloudpods/shell/doc.go deleted file mode 100644 index 165c93f2ee..0000000000 --- a/pkg/multicloud/cloudpods/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/cloudpods/shell" diff --git a/pkg/multicloud/cloudpods/shell/hosts.go b/pkg/multicloud/cloudpods/shell/hosts.go deleted file mode 100644 index 8aacb852a2..0000000000 --- a/pkg/multicloud/cloudpods/shell/hosts.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type HostListOptions struct { - ZoneId string - } - shellutils.R(&HostListOptions{}, "host-list", "List hosts", func(cli *cloudpods.SRegion, args *HostListOptions) error { - hosts, err := cli.GetHosts(args.ZoneId) - if err != nil { - return err - } - printList(hosts, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/cloudpods/shell/image.go b/pkg/multicloud/cloudpods/shell/image.go deleted file mode 100644 index f8dca198dc..0000000000 --- a/pkg/multicloud/cloudpods/shell/image.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - } - shellutils.R(&ImageListOptions{}, "image-list", "List instances", func(cli *cloudpods.SRegion, args *ImageListOptions) error { - images, err := cli.GetImages() - if err != nil { - return err - } - printList(images, 0, 0, 0, nil) - return nil - }) - - type ImageIdOptions struct { - ID string - } - - shellutils.R(&ImageIdOptions{}, "image-show", "Show instance", func(cli *cloudpods.SRegion, args *ImageIdOptions) error { - image, err := cli.GetImage(args.ID) - if err != nil { - return err - } - printObject(image) - return nil - }) - -} diff --git a/pkg/multicloud/cloudpods/shell/instance.go b/pkg/multicloud/cloudpods/shell/instance.go deleted file mode 100644 index 4816d0fbb6..0000000000 --- a/pkg/multicloud/cloudpods/shell/instance.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - HostId string - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List instances", func(cli *cloudpods.SRegion, args *InstanceListOptions) error { - instances, err := cli.GetInstances(args.HostId) - if err != nil { - return err - } - printList(instances, 0, 0, 0, nil) - return nil - }) - - type InstanceIdOptions struct { - ID string - } - - shellutils.R(&InstanceIdOptions{}, "instance-show", "Show instance", func(cli *cloudpods.SRegion, args *InstanceIdOptions) error { - instance, err := cli.GetInstance(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - type InstanceSaveImageOptions struct { - ID string - NAME string - Note string - } - - shellutils.R(&InstanceSaveImageOptions{}, "instance-save-image", "Save instance image", func(cli *cloudpods.SRegion, args *InstanceSaveImageOptions) error { - image, err := cli.SaveImage(args.ID, args.NAME, args.Note) - if err != nil { - return err - } - printObject(image) - return nil - }) - - shellutils.R(&cloudprovider.MetricListOptions{}, "instance-monitor-list", "Instance Monitor List", func(cli *cloudpods.SRegion, opts *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(opts) - if err != nil { - return err - } - printList(metrics, len(metrics), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/cloudpods/shell/network.go b/pkg/multicloud/cloudpods/shell/network.go deleted file mode 100644 index f58d442581..0000000000 --- a/pkg/multicloud/cloudpods/shell/network.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkListOptions struct { - WireId string - } - shellutils.R(&NetworkListOptions{}, "network-list", "List networks", func(cli *cloudpods.SRegion, args *NetworkListOptions) error { - networks, err := cli.GetNetworks(args.WireId) - if err != nil { - return err - } - printList(networks, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/cloudpods/shell/printutils.go b/pkg/multicloud/cloudpods/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/cloudpods/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/cloudpods/shell/region.go b/pkg/multicloud/cloudpods/shell/region.go deleted file mode 100644 index 1fba9a5aa7..0000000000 --- a/pkg/multicloud/cloudpods/shell/region.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *cloudpods.SRegion, args *RegionListOptions) error { - regions, err := cli.GetClient().GetRegions() - if err != nil { - return err - } - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/cloudpods/shell/secgroup.go b/pkg/multicloud/cloudpods/shell/secgroup.go deleted file mode 100644 index e9ac3c3844..0000000000 --- a/pkg/multicloud/cloudpods/shell/secgroup.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security-groups", func(cli *cloudpods.SRegion, args *SecurityGroupListOptions) error { - groups, err := cli.GetSecurityGroups() - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - type SecurityGroupIdOptions struct { - ID string - } - shellutils.R(&SecurityGroupIdOptions{}, "security-group-show", "Show security group", func(cli *cloudpods.SRegion, args *SecurityGroupIdOptions) error { - group, err := cli.GetSecurityGroup(args.ID) - if err != nil { - return err - } - printObject(group) - return nil - }) - -} diff --git a/pkg/multicloud/cloudpods/shell/vpc.go b/pkg/multicloud/cloudpods/shell/vpc.go deleted file mode 100644 index 905a02c467..0000000000 --- a/pkg/multicloud/cloudpods/shell/vpc.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - } - shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *cloudpods.SRegion, args *VpcListOptions) error { - vpcs, err := cli.GetVpcs() - if err != nil { - return err - } - printList(vpcs, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/cloudpods/shell/wire.go b/pkg/multicloud/cloudpods/shell/wire.go deleted file mode 100644 index 2f2d03f3cc..0000000000 --- a/pkg/multicloud/cloudpods/shell/wire.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type WireListOptions struct { - VpcId string - HostId string - } - shellutils.R(&WireListOptions{}, "wire-list", "List wires", func(cli *cloudpods.SRegion, args *WireListOptions) error { - wires, err := cli.GetWires(args.VpcId, args.HostId) - if err != nil { - return err - } - printList(wires, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/cloudpods/shell/zones.go b/pkg/multicloud/cloudpods/shell/zones.go deleted file mode 100644 index 2184535e57..0000000000 --- a/pkg/multicloud/cloudpods/shell/zones.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/cloudpods" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - } - shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *cloudpods.SRegion, args *ZoneListOptions) error { - zones, err := cli.GetZones() - if err != nil { - return err - } - printList(zones, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/cloudpods/sku.go b/pkg/multicloud/cloudpods/sku.go deleted file mode 100644 index da125d4b8b..0000000000 --- a/pkg/multicloud/cloudpods/sku.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SServerSku struct { - multicloud.SResourceBase - multicloud.CloudpodsTags - region *SRegion - - api.ServerSkuDetails -} - -func (self *SServerSku) GetName() string { - return self.Name -} - -func (self *SServerSku) GetId() string { - return self.Id -} - -func (self *SServerSku) GetGlobalId() string { - return self.Id -} - -func (self *SServerSku) GetStatus() string { - return self.Status -} - -func (self *SServerSku) GetInstanceTypeFamily() string { - return self.InstanceTypeFamily -} - -func (self *SServerSku) GetInstanceTypeCategory() string { - return self.InstanceTypeCategory -} - -func (self *SServerSku) GetPrepaidStatus() string { - return self.PrepaidStatus -} - -func (self *SServerSku) GetPostpaidStatus() string { - return self.PostpaidStatus -} - -func (self *SServerSku) GetCpuArch() string { - return "x86" -} - -func (self *SServerSku) GetCpuCoreCount() int { - return self.CpuCoreCount -} - -func (self *SServerSku) GetMemorySizeMB() int { - return self.MemorySizeMB -} - -func (self *SServerSku) GetOsName() string { - return self.OsName -} - -func (self *SServerSku) GetSysDiskResizable() bool { - return self.SysDiskResizable != nil && *self.SysDiskResizable -} - -func (self *SServerSku) GetSysDiskType() string { - return self.SysDiskType -} - -func (self *SServerSku) GetSysDiskMinSizeGB() int { - return self.SysDiskMinSizeGB -} - -func (self *SServerSku) GetSysDiskMaxSizeGB() int { - return self.SysDiskMaxSizeGB -} - -func (self *SServerSku) GetAttachedDiskType() string { - return self.AttachedDiskType -} - -func (self *SServerSku) GetAttachedDiskSizeGB() int { - return self.AttachedDiskSizeGB -} - -func (self *SServerSku) GetAttachedDiskCount() int { - return self.AttachedDiskCount -} - -func (self *SServerSku) GetDataDiskTypes() string { - return self.DataDiskTypes -} - -func (self *SServerSku) GetDataDiskMaxCount() int { - return self.DataDiskMaxCount -} - -func (self *SServerSku) GetNicType() string { - return self.NicType -} - -func (self *SServerSku) GetNicMaxCount() int { - return self.NicMaxCount -} - -func (self *SServerSku) GetGpuAttachable() bool { - return self.GpuAttachable != nil && *self.GpuAttachable -} - -func (self *SServerSku) GetGpuSpec() string { - return self.GpuSpec -} - -func (self *SServerSku) GetGpuCount() int { - return self.GpuCount -} - -func (self *SServerSku) GetGpuMaxCount() int { - return self.GpuMaxCount -} - -func (self *SServerSku) Delete() error { - return self.region.cli.delete(&modules.ServerSkus, self.Id) -} - -func (self *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { - skus, err := self.GetServerSkus() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudSku{} - for i := range skus { - skus[i].region = self - ret = append(ret, &skus[i]) - } - return ret, nil -} - -func (self *SRegion) GetServerSkus() ([]SServerSku, error) { - skus := []SServerSku{} - return skus, self.list(&modules.ServerSkus, nil, &skus) -} diff --git a/pkg/multicloud/cloudpods/snapshot.go b/pkg/multicloud/cloudpods/snapshot.go deleted file mode 100644 index e841ae3257..0000000000 --- a/pkg/multicloud/cloudpods/snapshot.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSnapshot struct { - multicloud.SVirtualResourceBase - multicloud.CloudpodsTags - region *SRegion - - api.SnapshotDetails -} - -func (self *SSnapshot) GetName() string { - return self.Name -} - -func (self *SSnapshot) GetId() string { - return self.Id -} - -func (self *SSnapshot) GetGlobalId() string { - return self.Id -} - -func (self *SSnapshot) GetStatus() string { - return self.Status -} - -func (self *SSnapshot) GetProjectId() string { - return self.TenantId -} - -func (self *SSnapshot) GetSizeMb() int32 { - return int32(self.Size) -} - -func (self *SSnapshot) GetDiskId() string { - return self.DiskId -} - -func (self *SSnapshot) GetDiskType() string { - return self.DiskType -} - -func (self *SSnapshot) Delete() error { - return self.region.cli.delete(&modules.Snapshots, self.Id) -} - -func (self *SSnapshot) Refresh() error { - snapshot, err := self.region.GetSnapshot(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, snapshot) -} - -func (self *SRegion) GetSnapshots(diskId string) ([]SSnapshot, error) { - ret := []SSnapshot{} - params := map[string]interface{}{} - if len(diskId) > 0 { - params["disk_id"] = diskId - } - return ret, self.list(&modules.Snapshots, params, &ret) -} - -func (self *SRegion) GetSnapshot(id string) (*SSnapshot, error) { - snapshot := &SSnapshot{region: self} - return snapshot, self.cli.get(&modules.Snapshots, id, nil, snapshot) -} - -func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := self.GetSnapshots("") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudSnapshot{} - for i := range snapshots { - snapshots[i].region = self - ret = append(ret, &snapshots[i]) - } - return ret, nil -} - -func (self *SRegion) GetISnapshotById(id string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := self.GetSnapshot(id) - if err != nil { - return nil, err - } - return snapshot, nil -} diff --git a/pkg/multicloud/cloudpods/storage.go b/pkg/multicloud/cloudpods/storage.go deleted file mode 100644 index 851588fdb9..0000000000 --- a/pkg/multicloud/cloudpods/storage.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - multicloud.SStorageBase - region *SRegion - - api.StorageDetails -} - -func (self *SStorage) GetId() string { - return self.Id -} - -func (self *SStorage) GetGlobalId() string { - return self.Id -} - -func (self *SStorage) GetName() string { - return self.Name -} - -func (self *SStorage) GetStatus() string { - return self.Status -} - -func (self *SStorage) GetIZone() cloudprovider.ICloudZone { - zone, err := self.region.GetZone(self.ZoneId) - if err != nil { - return nil - } - return zone -} - -func (self *SStorage) GetMediumType() string { - return self.MediumType -} - -func (self *SStorage) GetCapacityMB() int64 { - return self.Capacity -} - -func (self *SStorage) GetStorageType() string { - return self.StorageType -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return self.ActualCapacityUsed -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - return self.StorageConf -} - -func (self *SStorage) GetEnabled() bool { - return self.Enabled != nil && *self.Enabled -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - if len(self.StoragecacheId) == 0 { - return nil - } - cache, _ := self.region.GetStoragecache(self.StoragecacheId) - return cache -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - return self.SStorage.IsSysDiskStore != nil && *self.SStorage.IsSysDiskStore -} - -func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := self.region.GetStorages(self.Id, "") - if err != nil { - return nil, errors.Wrapf(err, "GetStorages") - } - ret := []cloudprovider.ICloudStorage{} - for i := range storages { - storages[i].region = self.region - ret = append(ret, &storages[i]) - } - return ret, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return self.region.GetIStorageById(id) -} - -func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storage, err := self.GetStorage(id) - if err != nil { - return nil, err - } - storage.region = self - return storage, nil -} - -func (self *SRegion) GetStorage(id string) (*SStorage, error) { - storage := &SStorage{region: self} - return storage, self.cli.get(&modules.Storages, id, nil, storage) -} - -func (self *SRegion) GetStorages(zoneId, hostId string) ([]SStorage, error) { - params := map[string]interface{}{} - if len(zoneId) > 0 { - params["zone_id"] = zoneId - } - if len(hostId) > 0 { - params["host_id"] = hostId - } - storages := []SStorage{} - return storages, self.list(&modules.Storages, params, &storages) -} diff --git a/pkg/multicloud/cloudpods/storagecache.go b/pkg/multicloud/cloudpods/storagecache.go deleted file mode 100644 index 0396f179ea..0000000000 --- a/pkg/multicloud/cloudpods/storagecache.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "context" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.CloudpodsTags - region *SRegion - - api.StoragecacheDetails -} - -func (self *SStoragecache) GetName() string { - return self.Name -} - -func (self *SStoragecache) GetId() string { - return self.Id -} - -func (self *SStoragecache) GetGlobalId() string { - return self.Id -} - -func (self *SStoragecache) GetStatus() string { - return "available" -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetIImageById(id string) (cloudprovider.ICloudImage, error) { - image, err := self.region.GetImage(id) - if err != nil { - return nil, err - } - image.cache = self - return image, nil -} - -func (self *SStoragecache) GetPath() string { - return self.Path -} - -func (self *SStoragecache) CreateIImage(snapshotId, name, osType, desc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, opts *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - id, err := self.region.UploadImage(ctx, userCred, opts, callback) - if err != nil { - return "", errors.Wrapf(err, "UploadImage") - } - image, err := self.GetIImageById(id) - if err != nil { - return "", errors.Wrapf(err, "GetIImageById(%s)", id) - } - err = cloudprovider.WaitStatus(image, cloudprovider.IMAGE_STATUS_ACTIVE, time.Second*5, time.Minute*10) - if err != nil { - return "", errors.Wrapf(err, "WaitStatus") - } - if callback != nil { - callback(100) - } - return id, nil -} - -func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - caches, err := self.GetStoragecaches() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStoragecache{} - for i := range caches { - caches[i].region = self - ret = append(ret, &caches[i]) - } - return ret, nil -} - -func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - cache, err := self.GetStoragecache(id) - if err != nil { - return nil, err - } - return cache, nil -} - -func (self *SRegion) GetStoragecaches() ([]SStoragecache, error) { - caches := []SStoragecache{} - return caches, self.list(&compute.Storagecaches, nil, &caches) -} - -func (self *SRegion) GetStoragecache(id string) (*SStoragecache, error) { - cache := &SStoragecache{region: self} - return cache, self.cli.get(&compute.Storagecaches, id, nil, cache) -} diff --git a/pkg/multicloud/cloudpods/vpc.go b/pkg/multicloud/cloudpods/vpc.go deleted file mode 100644 index f77ac9aab3..0000000000 --- a/pkg/multicloud/cloudpods/vpc.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - multicloud.CloudpodsTags - region *SRegion - - api.VpcDetails -} - -func (self *SVpc) GetName() string { - return self.Name -} - -func (self *SVpc) GetId() string { - return self.Id -} - -func (self *SVpc) GetGlobalId() string { - return self.Id -} - -func (self *SVpc) GetStatus() string { - return self.Status -} - -func (self *SVpc) Refresh() error { - vpc, err := self.region.GetVpc(self.Id) - if err != nil { - return errors.Wrapf(err, "GetVpc(%s)", self.Id) - } - return jsonutils.Update(self, vpc) -} - -func (self *SVpc) GetCidrBlock() string { - return self.CidrBlock -} - -func (self *SVpc) GetIRouteTableById(id string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SVpc) GetIsDefault() bool { - return self.IsDefault -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetExternalAccessMode() string { - return self.ExternalAccessMode -} - -func (self *SVpc) Delete() error { - return self.region.cli.delete(&modules.Vpcs, self.Id) -} - -func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - vpcs, err := self.GetVpcs() - if err != nil { - return nil, errors.Wrapf(err, "GetVpcs") - } - ret := []cloudprovider.ICloudVpc{} - for i := range vpcs { - vpcs[i].region = self - ret = append(ret, &vpcs[i]) - } - return ret, nil -} - -func (self *SVpc) CreateIWire(opts *cloudprovider.SWireCreateOptions) (cloudprovider.ICloudWire, error) { - wire, err := self.region.CreateWire(opts, self.Id, self.DomainId, self.PublicScope, self.IsPublic) - if err != nil { - return nil, err - } - wire.vpc = self - return wire, nil -} - -func (self *SRegion) CreateWire(opts *cloudprovider.SWireCreateOptions, vpcId, domainId, publicScope string, isPublic bool) (*SWire, error) { - input := api.WireCreateInput{} - input.GenerateName = opts.Name - input.Mtu = opts.Mtu - input.Bandwidth = opts.Bandwidth - input.VpcId = vpcId - input.DomainId = domainId - input.PublicScope = publicScope - input.IsPublic = &isPublic - input.ZoneId = opts.ZoneId - t := true - input.IsEmulated = &t - wire := &SWire{} - return wire, self.create(&modules.Wires, input, wire) -} - -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - input := api.VpcCreateInput{} - input.Name = opts.NAME - input.Description = opts.Desc - input.CidrBlock = opts.CIDR - input.CloudregionId = self.Id - vpc := &SVpc{region: self} - return vpc, self.create(&modules.Vpcs, input, vpc) -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - vpc, err := self.GetVpc(id) - if err != nil { - return nil, errors.Wrapf(err, "GetVpc(%s)", id) - } - return vpc, nil -} - -func (self *SRegion) GetVpcs() ([]SVpc, error) { - vpcs := []SVpc{} - return vpcs, self.list(&modules.Vpcs, nil, &vpcs) -} - -func (self *SRegion) GetVpc(id string) (*SVpc, error) { - vpc := &SVpc{region: self} - return vpc, self.cli.get(&modules.Vpcs, id, nil, vpc) -} diff --git a/pkg/multicloud/cloudpods/wire.go b/pkg/multicloud/cloudpods/wire.go deleted file mode 100644 index 6c9608f092..0000000000 --- a/pkg/multicloud/cloudpods/wire.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.CloudpodsTags - multicloud.SResourceBase - - vpc *SVpc - - api.WireDetails -} - -func (self *SWire) GetId() string { - return self.Id -} - -func (self *SWire) GetGlobalId() string { - return self.Id -} - -func (self *SWire) GetName() string { - return self.Name -} - -func (self *SWire) GetStatus() string { - return self.Status -} - -func (self *SWire) GetBandwidth() int { - return self.Bandwidth -} - -func (self *SWire) IsEmulated() bool { - return self.SWire.IsEmulated -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - if len(self.ZoneId) == 0 { - return nil - } - zone, err := self.vpc.region.GetZone(self.ZoneId) - if err != nil { - return nil - } - return zone -} - -func (self *SWire) Refresh() error { - wire, err := self.vpc.region.GetWire(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, wire) -} - -func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { - wire, err := self.region.GetWire(id) - if err != nil { - return nil, errors.Wrapf(err, "GetWire(%s)", id) - } - wire.vpc = self - return wire, nil -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - wires, err := self.region.GetWires(self.Id, "") - if err != nil { - return nil, errors.Wrapf(err, "GetWires") - } - ret := []cloudprovider.ICloudWire{} - for i := range wires { - wires[i].vpc = self - ret = append(ret, &wires[i]) - } - return ret, nil -} - -func (self *SRegion) GetWires(vpcId, hostId string) ([]SWire, error) { - wires := []SWire{} - params := map[string]interface{}{"cloud_env": ""} - if len(vpcId) > 0 { - params["vpc_id"] = vpcId - } - if len(hostId) > 0 { - params["host_id"] = hostId - } - return wires, self.list(&modules.Wires, params, &wires) -} - -func (self *SRegion) GetWire(id string) (*SWire, error) { - wire := &SWire{} - return wire, self.cli.get(&modules.Wires, id, nil, wire) -} diff --git a/pkg/multicloud/cloudpods/zone.go b/pkg/multicloud/cloudpods/zone.go deleted file mode 100644 index c6b2bf6c04..0000000000 --- a/pkg/multicloud/cloudpods/zone.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 cloudpods - -import ( - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SZone struct { - multicloud.SResourceBase - multicloud.CloudpodsTags - region *SRegion - - api.ZoneDetails -} - -func (self *SZone) GetId() string { - return self.Id -} - -func (self *SZone) GetGlobalId() string { - return self.Id -} - -func (self *SZone) GetName() string { - return self.Name -} - -func (self *SZone) GetStatus() string { - return self.Status -} - -func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) - return table -} - -func (self *SRegion) GetZones() ([]SZone, error) { - zones := []SZone{} - return zones, self.list(&modules.Zones, nil, &zones) -} - -func (self *SRegion) GetZone(id string) (*SZone, error) { - zone := &SZone{region: self} - return zone, self.cli.get(&modules.Zones, id, nil, &zone) -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - zone, err := self.GetZone(id) - if err != nil { - return nil, err - } - return zone, nil -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - zones, err := self.GetZones() - if err != nil { - return nil, errors.Wrapf(err, "GetZones") - } - ret := []cloudprovider.ICloudZone{} - for i := range zones { - zones[i].region = self - ret = append(ret, &zones[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/clouduser.go b/pkg/multicloud/clouduser.go deleted file mode 100644 index 23e222d1a3..0000000000 --- a/pkg/multicloud/clouduser.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 multicloud - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SBaseClouduser struct { -} - -func (self *SBaseClouduser) CreateAccessKey(name string) (*cloudprovider.SAccessKey, error) { - return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "base CreateAccessKey") -} - -func (self *SBaseClouduser) GetAccessKeys() ([]cloudprovider.SAccessKey, error) { - return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "base GetAccessKeys") -} - -func (self *SBaseClouduser) DeleteAccessKey(accesskey string) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "base DeleteAccessKey") -} diff --git a/pkg/multicloud/ctyun/disk.go b/pkg/multicloud/ctyun/disk.go deleted file mode 100644 index aa35963be1..0000000000 --- a/pkg/multicloud/ctyun/disk.go +++ /dev/null @@ -1,599 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "context" - "fmt" - "strconv" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// http://ctyun-api-url/apiproxy/v3/ondemand/queryVolumes -type SDisk struct { - storage *SStorage - multicloud.SDisk - multicloud.CtyunTags - multicloud.SBillingBase - - diskDetails *DiskDetails - - ID string `json:"id"` - Status string `json:"status"` - Name string `json:"name"` - CreatedAt int64 `json:"created_at"` - UpdatedAt string `json:"updated_at"` - Multiattach bool `json:"multiattach"` - ReplicationStatus string `json:"replication_status"` - SizeGB int64 `json:"size"` - Metadata Metadata `json:"metadata"` - VolumeType string `json:"volume_type"` - UserID string `json:"user_id"` - Shareable bool `json:"shareable"` - Encrypted bool `json:"encrypted"` - Bootable string `json:"bootable"` - AvailabilityZone string `json:"availability_zone"` - Attachments []Attachment `json:"attachments"` - MasterOrderID string `json:"masterOrderId"` - WorkOrderResourceID string `json:"workOrderResourceId"` - ExpireTime int64 `json:"expireTime"` - IsFreeze int64 `json:"isFreeze"` -} - -type Attachment struct { - VolumeID string `json:"volume_id"` - AttachmentID string `json:"attachment_id"` - AttachedAt string `json:"attached_at"` - ServerID string `json:"server_id"` - Device string `json:"device"` - ID string `json:"id"` -} - -type Metadata struct { - OrderID string `json:"orderID"` - AttachedMode string `json:"attached_mode"` - ResourceSpecCode string `json:"resourceSpecCode"` - ProductID string `json:"productID"` - Readonly string `json:"readonly"` -} - -type DiskDetails struct { - ID string `json:"id"` - ResEbsID string `json:"resEbsId"` - Size int64 `json:"size"` - Name string `json:"name"` - RegionID string `json:"regionId"` - AccountID string `json:"accountId"` - UserID string `json:"userId"` - HostID string `json:"hostId"` - OrderID string `json:"orderId"` - Status int64 `json:"status"` - Type string `json:"type"` - VolumeStatus int64 `json:"volumeStatus"` - CreateDate int64 `json:"createDate"` - DueDate int64 `json:"dueDate"` - ZoneID string `json:"zoneId"` - ZoneName string `json:"zoneName"` - IsSysVolume int64 `json:"isSysVolume"` - IsPackaged int64 `json:"isPackaged"` - WorkOrderResourceID string `json:"workOrderResourceId"` - IsFreeze int64 `json:"isFreeze"` -} - -func (self *SDisk) GetBillingType() string { - if self.ExpireTime > 0 { - return billing_api.BILLING_TYPE_PREPAID - } - - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SDisk) GetCreatedAt() time.Time { - return time.Unix(self.CreatedAt/1000, 0) -} - -func (self *SDisk) GetExpiredAt() time.Time { - if self.ExpireTime == 0 { - return time.Time{} - } - - return time.Unix(self.ExpireTime/1000, 0) -} - -func (self *SDisk) GetId() string { - return self.ID -} - -func (self *SDisk) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - - return self.ID -} - -func (self *SDisk) GetGlobalId() string { - return self.GetId() -} - -func (self *SDisk) GetStatus() string { - switch self.Status { - case "creating", "downloading": - return api.DISK_ALLOCATING - case "available", "in-use": - return api.DISK_READY - case "error": - return api.DISK_ALLOC_FAILED - case "attaching": - return api.DISK_ATTACHING - case "detaching": - return api.DISK_DETACHING - case "restoring-backup": - return api.DISK_REBUILD - case "backing-up": - return api.DISK_BACKUP_STARTALLOC - case "error_restoring": - return api.DISK_BACKUP_ALLOC_FAILED - case "uploading": - return api.DISK_SAVING - case "extending": - return api.DISK_RESIZING - case "error_extending": - return api.DISK_ALLOC_FAILED - case "deleting": - return api.DISK_DEALLOC - case "error_deleting": - return api.DISK_DEALLOC_FAILED - case "rollbacking": - return api.DISK_REBUILD - case "error_rollbacking": - return api.DISK_UNKNOWN - default: - return api.DISK_UNKNOWN - } -} - -func (self *SDisk) Refresh() error { - new, err := self.storage.zone.region.GetDisk(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SDisk) IsEmulated() bool { - return false -} - -func (self *SDisk) GetSysTags() map[string]string { - data := map[string]string{} - data["hypervisor"] = api.HYPERVISOR_CTYUN - return data -} - -func (self *SDisk) GetProjectId() string { - return "" -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.storage, nil -} - -func (self *SDisk) GetIStorageId() string { - return self.storage.GetId() -} - -func (self *SDisk) GetDiskFormat() string { - return "vhd" -} - -func (self *SDisk) GetDiskSizeMB() int { - return int(self.SizeGB * 1024) -} - -func (self *SDisk) GetIsAutoDelete() bool { - if len(self.Attachments) == 0 { - return false - } - - if self.Bootable == "true" { - return true - } - - return false -} - -func (self *SDisk) GetTemplateId() string { - if len(self.Attachments) > 0 && len(self.Attachments[0].ServerID) > 0 { - server, err := self.storage.zone.region.GetVMById(self.Attachments[0].ServerID) - if err != nil { - log.Errorf("SDisk.GetTemplateId %s", err) - return "" - } - - image, err := server.GetImage() - if err != nil { - log.Errorf("SDisk.GetImage %s", err) - return "" - } - - return image.GetId() - } - - return "" -} - -func (self *SDisk) GetDiskType() string { - if self.Bootable == "true" { - return api.DISK_TYPE_SYS - } else { - return api.DISK_TYPE_DATA - } -} - -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 { - if len(self.Attachments) > 0 { - return self.Attachments[0].Device - } - - return "" -} - -func (self *SDisk) GetAccessPath() string { - return "" -} - -func (self *SDisk) Delete(ctx context.Context) error { - _, err := self.storage.zone.region.DeleteDisk(self.GetId()) - if err != nil { - return errors.Wrap(err, "SDisk.Delete") - } - - return nil -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotSupported -} - -// POST http://ctyun-api-url/apiproxy/v3/ondemand/createVBS -func (self *SDisk) GetISnapshot(idStr string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotFound -} - -// no snapshot api opened -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - return []cloudprovider.ICloudSnapshot{}, nil -} - -// POST http://ctyun-api-url/apiproxy/v3/ondemand/updateDiskBackupPolicy -func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { - return []string{}, nil -} - -func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { - jobId, err := self.storage.zone.region.ResizeDisk(self.GetId(), strconv.Itoa(int(newSizeMB/1024))) - if err != nil { - return errors.Wrap(err, "Disk.Resize") - } - - err = cloudprovider.Wait(10*time.Second, 1800*time.Second, func() (b bool, err error) { - statusJson, err := self.storage.zone.region.GetVolumeJob(jobId) - // ctyun 偶尔会报客户端错误,其实job已经到后台执行了 - if err != nil { - log.Debugf("Ctyun.SDisk.Resize.GetVolumeJob %s", err) - return false, nil - } - - if status, _ := statusJson.GetString("status"); status == "SUCCESS" { - return true, nil - } else if status == "FAILED" { - return false, fmt.Errorf("Resize job %s failed", jobId) - } else { - return false, nil - } - }) - if err != nil { - return errors.Wrap(err, "Disk.Resize.Wait") - } - - return nil -} - -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDisk) GetDiskDetails() (*DiskDetails, error) { - if self.diskDetails != nil { - return self.diskDetails, nil - } - - details, err := self.storage.zone.region.GetDiskDetailByDiskId(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "SDisk.GetDiskDetails.GetDiskDetailByDiskId") - } - - self.diskDetails = details - return self.diskDetails, nil -} - -func (self *SRegion) GetDisks() ([]SDisk, error) { - params := map[string]string{ - "regionId": self.GetId(), - } - - resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVolumes", params) - if err != nil { - return nil, errors.Wrap(err, "Region.GetDisks.DoGet") - } - - disks := make([]SDisk, 0) - err = resp.Unmarshal(&disks, "returnObj", "volumes") - if err != nil { - return nil, errors.Wrap(err, "Region.GetDisks.Unmarshal") - } - - for i := range disks { - izone, err := self.GetIZoneById(getZoneGlobalId(self, disks[i].AvailabilityZone)) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetDisk.GetIZoneById") - } - - disks[i].storage = &SStorage{ - zone: izone.(*SZone), - storageType: disks[i].VolumeType, - } - } - - return disks, nil -} - -func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { - params := map[string]string{ - "regionId": self.GetId(), - "volumeId": diskId, - } - - resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVolumes", params) - if err != nil { - return nil, errors.Wrap(err, "Region.GetDisk.DoGet") - } - - disks := make([]SDisk, 0) - err = resp.Unmarshal(&disks, "returnObj", "volumes") - if err != nil { - return nil, errors.Wrap(err, "Region.GetDisks.Unmarshal") - } - - if len(disks) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetDisk") - } else if len(disks) == 1 { - izone, err := self.GetIZoneById(getZoneGlobalId(self, disks[0].AvailabilityZone)) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetDisk.GetIZoneById") - } - - disks[0].storage = &SStorage{ - zone: izone.(*SZone), - storageType: disks[0].VolumeType, - } - - return &disks[0], nil - } else { - return nil, errors.Wrap(cloudprovider.ErrDuplicateId, "SRegion.GetDisk") - } -} - -func (self *SRegion) GetDiskDetailByDiskId(diskId string) (*DiskDetails, error) { - params := map[string]string{ - "volumeId": diskId, - "regionId": self.GetId(), - } - - resp, err := self.client.DoGet("/apiproxy/v3/queryDataDiskDetail", params) - if err != nil { - return nil, errors.Wrap(err, "Region.GetDiskDetailByDiskId.DoGet") - } - - disk := &DiskDetails{} - err = resp.Unmarshal(disk, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "Region.GetDiskDetailByDiskId.Unmarshal") - } - - return disk, nil -} - -func (self *SRegion) CreateDisk(zoneId, name, diskType, size string) (*SDisk, error) { - diskParams := jsonutils.NewDict() - diskParams.Set("regionId", jsonutils.NewString(self.GetId())) - diskParams.Set("zoneId", jsonutils.NewString(zoneId)) - diskParams.Set("name", jsonutils.NewString(name)) - diskParams.Set("type", jsonutils.NewString(diskType)) - diskParams.Set("size", jsonutils.NewString(size)) - diskParams.Set("count", jsonutils.NewString("1")) - - params := map[string]jsonutils.JSONObject{ - "createVolumeInfo": diskParams, - } - - disks, err := self.GetDisks() - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateDisk.GetDisks") - } - - diskIds := []string{} - for i := range disks { - diskIds = append(diskIds, disks[i].GetId()) - } - - _, err = self.client.DoPost("/apiproxy/v3/ondemand/createVolume", params) - if err != nil { - return nil, errors.Wrap(err, "Region.CreateDisk.DoPost") - } - - // 查询job结果一直报错,目前先用替代办法查找新硬盘ID,可能不准确。后续需要替换其它方法 - diskId := "" - cloudprovider.Wait(3*time.Second, 300*time.Second, func() (b bool, err error) { - disks, err := self.GetDisks() - if err != nil { - return false, err - } - - for i := range disks { - if !utils.IsInStringArray(disks[i].GetId(), diskIds) { - diskId = disks[i].GetId() - return true, nil - } - } - - return false, nil - }) - - return self.GetDisk(diskId) -} - -func (self *SRegion) CreateDiskBackup(name, volumeId, desc string) (string, error) { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "volumeId": jsonutils.NewString(volumeId), - "name": jsonutils.NewString(name), - "description": jsonutils.NewString(desc), - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/createVBS", params) - if err != nil { - return "", errors.Wrap(err, "Region.CreateDiskBackup.DoPost") - } - - var jobId string - err = resp.Unmarshal(&jobId, "returnObj", "data") - if err != nil { - return "", errors.Wrap(err, "Region.CreateDiskBackup.Unmarshal") - } - - return jobId, nil -} - -func (self *SRegion) DeleteDisk(volumeId string) (string, error) { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "volumeId": jsonutils.NewString(volumeId), - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/deleteVolume", params) - if err != nil { - msg, _ := resp.GetString("message") - return "", errors.Wrap(fmt.Errorf(msg), "SRegion.DeleteDisk.DoPost") - } - - var jobId string - err = resp.Unmarshal(&jobId, "returnObj", "data") - if err != nil { - return "", errors.Wrap(err, "SRegion.DeleteDisk.Unmarshal") - } - - return jobId, nil -} - -func (self *SRegion) ResizeDisk(volumeId string, newSizeGB string) (string, error) { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "volumeId": jsonutils.NewString(volumeId), - "newSize": jsonutils.NewString(newSizeGB), - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/expandVolumeSize", params) - if err != nil { - return "", errors.Wrap(err, "SRegion.ResizeDisk.DoPost") - } - - var ok bool - err = resp.Unmarshal(&ok, "returnObj", "status") - if !ok { - msg, _ := resp.GetString("message") - return "", errors.Wrap(fmt.Errorf(msg), "SRegion.ResizeDisk.JobFailed") - } - - var jobId string - err = resp.Unmarshal(&jobId, "returnObj", "data") - if err != nil { - return "", errors.Wrap(err, "SRegion.ResizeDisk.Unmarshal") - } - - return jobId, nil -} - -func (self *SRegion) RestoreDisk(volumeId, backupId string) (string, error) { - diskBackupParams := jsonutils.NewDict() - diskBackupParams.Set("regionId", jsonutils.NewString(self.GetId())) - diskBackupParams.Set("backupId", jsonutils.NewString(backupId)) - diskBackupParams.Set("volumeId", jsonutils.NewString(volumeId)) - - params := map[string]jsonutils.JSONObject{ - "diskBackup": diskBackupParams, - } - - resp, err := self.client.DoPost("/apiproxy/v3/restoreDiskBackup", params) - if err != nil { - return "", errors.Wrap(err, "SRegion.RestoreDisk.DoPost") - } - - var ok bool - err = resp.Unmarshal(&ok, "returnObj", "status") - if !ok { - msg, _ := resp.GetString("message") - return "", errors.Wrap(fmt.Errorf(msg), "SRegion.RestoreDisk.JobFailed") - } - - var jobId string - err = resp.Unmarshal(&jobId, "returnObj", "data") - if err != nil { - return "", errors.Wrap(err, "SRegion.RestoreDisk.Unmarshal") - } - - return jobId, nil -} diff --git a/pkg/multicloud/ctyun/doc.go b/pkg/multicloud/ctyun/doc.go deleted file mode 100644 index 248fc0df82..0000000000 --- a/pkg/multicloud/ctyun/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun // import "yunion.io/x/onecloud/pkg/multicloud/ctyun" diff --git a/pkg/multicloud/ctyun/eip.go b/pkg/multicloud/ctyun/eip.go deleted file mode 100644 index f5fb8d0417..0000000000 --- a/pkg/multicloud/ctyun/eip.go +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SEip struct { - region *SRegion - multicloud.SEipBase - multicloud.CtyunTags - - IPVersion int64 `json:"ip_version"` - BandwidthShareType string `json:"bandwidth_share_type"` - Type string `json:"type"` - PrivateIPAddress string `json:"private_ip_address"` - EnterpriseProjectID string `json:"enterprise_project_id"` - Status string `json:"status"` - PublicIPAddress string `json:"public_ip_address"` - ID string `json:"id"` - TenantID string `json:"tenant_id"` - Profile Profile `json:"profile"` - BandwidthName string `json:"bandwidth_name"` - BandwidthID string `json:"bandwidth_id"` - PortID string `json:"port_id"` - BandwidthSize int `json:"bandwidth_size"` - CreateTime int64 `json:"create_time"` - MasterOrderID string `json:"masterOrderId"` - WorkOrderResourceID string `json:"workOrderResourceId"` - ExpireTime int64 `json:"expireTime"` - IsFreeze int64 `json:"isFreeze"` -} - -func (self *SEip) GetBillingType() string { - if len(self.MasterOrderID) > 0 { - return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SEip) GetCreatedAt() time.Time { - return time.Unix(self.CreateTime/1000, 0) -} - -func (self *SEip) GetExpiredAt() time.Time { - if self.ExpireTime == 0 { - return time.Time{} - } - - return time.Unix(self.ExpireTime/1000, 0) -} - -func (self *SEip) GetId() string { - return self.ID -} - -func (self *SEip) GetName() string { - return self.BandwidthName -} - -func (self *SEip) GetGlobalId() string { - return self.GetId() -} - -func (self *SEip) GetStatus() string { - switch self.Status { - case "ACTIVE", "DOWN": - return api.EIP_STATUS_READY - case "ERROR": - return api.EIP_STATUS_ALLOCATE_FAIL - default: - return api.EIP_STATUS_UNKNOWN - } -} - -func (self *SEip) Refresh() error { - if self.IsEmulated() { - return nil - } - new, err := self.region.GetEip(self.ID) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SEip) IsEmulated() bool { - return false -} - -func (self *SEip) GetProjectId() string { - return "" -} - -func (self *SEip) GetIpAddr() string { - return self.PublicIPAddress -} - -func (self *SEip) GetMode() string { - return api.EIP_MODE_STANDALONE_EIP -} - -func (self *SEip) GetINetworkId() string { - return "" -} - -func (self *SEip) GetAssociationType() string { - orders, err := self.region.GetOrder(self.WorkOrderResourceID) - if err != nil { - // bugfix: 由于没有接口可以返向查询出关联的device,这里默认关联的是server? - if len(self.PortID) > 0 || len(self.PrivateIPAddress) > 0 { - return api.EIP_ASSOCIATE_TYPE_SERVER - } - - log.Errorf("SEip.GetAssociationType %s", err) - return "" - } - - for i := range orders { - order := orders[i] - if strings.Contains(order.ResourceType, "LOADBALANCER") { - return api.EIP_ASSOCIATE_TYPE_LOADBALANCER - } else { - return api.EIP_ASSOCIATE_TYPE_SERVER - } - } - - return "" -} - -// eip查询接口未返回 绑定的实例ID/网卡port id。导致不能正常找出关联的主机 -func (self *SEip) GetAssociationExternalId() string { - vms, err := self.region.GetVMs() - if err != nil { - log.Errorf("SEip.GetAssociationExternalId.GetVMs %s", err) - return "" - } - - for i := range vms { - vm := vms[i] - nics, err := self.region.GetNics(vm.GetId()) - if err != nil { - log.Errorf("SEip.GetAssociationExternalId.GetNics %s", err) - return "" - } - - for _, nic := range nics { - if nic.PortID == self.PortID { - return vm.GetGlobalId() - } - } - } - - return "" -} - -// http://ctyun-api-url/apiproxy/v3/queryNetworkDetail -func (self *SEip) GetBandwidth() int { - return self.BandwidthSize -} - -func (self *SEip) GetInternetChargeType() string { - // todo: fix me - return "" -} - -func (self *SEip) Delete() error { - return self.region.DeleteEip(self.GetId()) -} - -func (self *SEip) Associate(conf *cloudprovider.AssociateConfig) error { - nics, err := self.region.GetNics(conf.InstanceId) - if err != nil { - return errors.Wrap(err, "Eip.Associate.GetNics") - } - - if len(nics) == 0 { - return errors.Wrap(fmt.Errorf("no network card found"), "Eip.Associate.GetINics") - } - - return self.region.AssociateEip(self.GetId(), nics[0].PortID) -} - -func (self *SEip) Dissociate() error { - err := self.region.DissociateEip(self.GetId()) - if err != nil { - return err - } - - err = cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 5*time.Second, 10*time.Second, 180*time.Second) - return errors.Wrap(err, "SEip.Dissociate") -} - -func (self *SEip) ChangeBandwidth(bw int) error { - return self.region.ChangeBandwidthEip(self.GetName(), self.GetId(), strconv.Itoa(bw)) -} - -type Profile struct { - OrderID string `json:"order_id"` - RegionID string `json:"region_id"` - UserID string `json:"user_id"` - ProductID string `json:"product_id"` -} - -func (self *SRegion) GetEips() ([]SEip, error) { - params := map[string]string{ - "regionId": self.GetId(), - } - - eips := make([]SEip, 0) - resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryIps", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetEips.DoGet") - } - - err = resp.Unmarshal(&eips, "returnObj", "publicips") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetEips.Unmarshal") - } - - for i := range eips { - eips[i].region = self - } - - return eips, nil -} - -func (self *SRegion) GetEip(eipId string) (*SEip, error) { - params := map[string]string{ - "regionId": self.GetId(), - "publicIpId": eipId, - } - - eips := make([]SEip, 0) - resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryIps", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetEip.DoGet") - } - - err = resp.Unmarshal(&eips, "returnObj", "publicips") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetEip.Unmarshal") - } - - if len(eips) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetEip") - } else if len(eips) == 1 { - eips[0].region = self - return &eips[0], nil - } else { - return nil, errors.Wrap(cloudprovider.ErrDuplicateId, "SRegion.GetEip") - } -} - -func (self *SRegion) CreateEip(zoneId, name, size, shareType, chargeType string) (*SEip, error) { - eipParams := jsonutils.NewDict() - eipParams.Set("regionId", jsonutils.NewString(self.GetId())) - eipParams.Set("zoneId", jsonutils.NewString(zoneId)) - eipParams.Set("name", jsonutils.NewString(name)) - eipParams.Set("type", jsonutils.NewString("5_telcom")) - eipParams.Set("size", jsonutils.NewString(size)) - eipParams.Set("shareType", jsonutils.NewString(shareType)) - eipParams.Set("chargeMode", jsonutils.NewString(chargeType)) - - params := map[string]jsonutils.JSONObject{ - "createIpInfo": eipParams, - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/createIp", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateEip.DoPost") - } - - eipId, err := resp.GetString("returnObj", "id") - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateEip.GetEipId") - } - - return self.GetEip(eipId) -} - -func (self *SRegion) DeleteEip(publicIpId string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "publicIpId": jsonutils.NewString(publicIpId), - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/deleteIp", params) - if err != nil { - return errors.Wrap(err, "SRegion.DeleteEip.DoPost") - } - - var ok bool - err = resp.Unmarshal(&ok, "returnObj") - if !ok { - msg, _ := resp.GetString("message") - return errors.Wrap(fmt.Errorf(msg), "SRegion.DeleteEip.JobFailed") - } - - return nil -} - -// 这里networkCardId 实际指的是port id -func (self *SRegion) AssociateEip(publicIpId, networkCardId string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "publicIpId": jsonutils.NewString(publicIpId), - "networkCardId": jsonutils.NewString(networkCardId), - } - - _, err := self.client.DoPost("/apiproxy/v3/ondemand/bindIp", params) - if err != nil { - return errors.Wrap(err, "SRegion.AssociateEip.DoPost") - } - - return nil -} - -func (self *SRegion) DissociateEip(publicIpId string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "publicIpId": jsonutils.NewString(publicIpId), - } - - _, err := self.client.DoPost("/apiproxy/v3/ondemand/unbindIp", params) - if err != nil { - return errors.Wrap(err, "SRegion.DissociateEip.DoPost") - } - - return nil -} - -type SBandwidth struct { - PublicipInfo []PublicipInfo `json:"publicip_info"` - EnterpriseProjectID string `json:"enterprise_project_id"` - Name string `json:"name"` - ID string `json:"id"` - ShareType string `json:"share_type"` - Size int64 `json:"size"` - TenantID string `json:"tenant_id"` - ChargeMode string `json:"charge_mode"` - BandwidthType string `json:"bandwidth_type"` -} - -type PublicipInfo struct { - PublicipType string `json:"publicip_type"` - PublicipAddress string `json:"publicip_address"` - IPVersion int64 `json:"ip_version"` - PublicipID string `json:"publicip_id"` -} - -func (self *SRegion) ChangeBandwidthEip(name, publicIpId, sizeMb string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "publicIpId": jsonutils.NewString(publicIpId), - "name": jsonutils.NewString(name), - "size": jsonutils.NewString(sizeMb), - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/upgradeNetwork", params) - if err != nil { - return errors.Wrap(err, "SRegion.ChangeBandwidthEip.DoPost") - } - - bandwidth := SBandwidth{} - err = resp.Unmarshal(&bandwidth, "returnObj") - if err != nil { - return errors.Wrap(err, "SRegion.ChangeBandwidthEip.Unmarshal") - } - - return nil -} diff --git a/pkg/multicloud/ctyun/host.go b/pkg/multicloud/ctyun/host.go deleted file mode 100644 index 9d1c4e70ab..0000000000 --- a/pkg/multicloud/ctyun/host.go +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone - - projectId string -} - -func (self *SHost) GetId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) GetName() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) -} - -func (self *SHost) GetGlobalId() string { - return self.GetId() -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) Refresh() error { - return nil -} - -func (self *SHost) IsEmulated() bool { - return true -} - -// http://ctyun-api-url/apiproxy/v3/ondemand/queryVMs -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms, err := self.zone.region.GetVMs() - if err != nil { - return nil, errors.Wrap(err, "SHost.GetVMs") - } - - ivms := make([]cloudprovider.ICloudVM, len(vms)) - for i := range vms { - ivms[i] = &vms[i] - } - - return ivms, nil -} - -// http://ctyun-api-url/apiproxy/v3/ondemand/queryVMDetail -// http://ctyun-api-url/apiproxy/v3/queryVMDetail -func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - return self.zone.region.GetIVMById(id) -} - -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 api.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(api.CLOUD_PROVIDER_CTYUN), "manufacture") - return info -} - -func (self *SHost) GetSN() string { - return "" -} - -func (self *SHost) GetCpuCount() int { - 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 api.DISK_TYPE_HYBRID -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_CTYUN -} - -func (self *SHost) GetIsMaintenance() bool { - return false -} - -func (self *SHost) GetVersion() string { - return CTYUN_API_VERSION -} - -func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - network, err := self.zone.region.GetNetwork(desc.ExternalNetworkId) - if err != nil { - return nil, errors.Wrap(err, "Host.CreateVM.GetNetwork") - } - - // 镜像及硬盘配置 - img, err := self.zone.region.GetImage(desc.ExternalImageId) - if err != nil { - return nil, errors.Wrap(err, "SHost.CreateVM.GetImage") - } - - rootDiskSize := int(img.MinDisk) - if desc.SysDisk.SizeGB > rootDiskSize { - rootDiskSize = desc.SysDisk.SizeGB - } - - jobId, err := self.zone.region.CreateInstance(self.zone.GetId(), desc.Name, desc.ExternalImageId, desc.OsType, desc.InstanceType, network.VpcID, desc.ExternalNetworkId, desc.ExternalSecgroupId, desc.Password, desc.SysDisk.StorageType, rootDiskSize, desc.DataDisks) - if err != nil { - return nil, errors.Wrap(err, "Host.CreateVM.CreateInstance") - } - - vmId := "" - err = cloudprovider.Wait(10*time.Second, 600*time.Second, func() (b bool, err error) { - statusJson, err := self.zone.region.GetJob(jobId) - if err != nil { - if strings.Contains(err.Error(), "job fail") { - return false, err - } - - return false, nil - } - - if status, _ := statusJson.GetString("status"); status == "SUCCESS" { - jobs, err := statusJson.GetArray("entities", "sub_jobs") - if err != nil { - return false, err - } - - if len(jobs) > 0 { - vmId, err = jobs[0].GetString("entities", "server_id") - if err != nil { - return false, err - } - } else { - return false, fmt.Errorf("CreateVM empty sub jobs") - } - return true, nil - } else if status == "FAILED" { - return false, fmt.Errorf("CreateVM job %s failed", jobId) - } else { - return false, nil - } - }) - if err != nil { - return nil, errors.Wrap(err, "SHost.CreateVM.Wait") - } - - return self.zone.region.GetVMById(vmId) -} - -func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) getVMs(vmId string) ([]SInstance, error) { - params := map[string]string{ - "regionId": self.GetId(), - } - - if len(vmId) > 0 { - params["vmId"] = vmId - } - - resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVMs", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.getVMs.DoGet") - } - - ret := make([]SInstance, 0) - err = resp.Unmarshal(&ret, "returnObj", "servers") - if err != nil { - return nil, errors.Wrap(err, "SRegion.getVMs.Unmarshal") - } - - for i := range ret { - izone, err := self.GetIZoneById(getZoneGlobalId(self, ret[i].OSEXTAZAvailabilityZone)) - if err != nil { - return nil, errors.Wrap(err, "SRegion.getVMs.GetIZoneById") - } - - ret[i].host = &SHost{ - zone: izone.(*SZone), - } - } - - return ret, nil -} - -func (self *SRegion) GetVMs() ([]SInstance, error) { - return self.getVMs("") -} - -func (self *SRegion) GetVMById(vmId string) (*SInstance, error) { - if len(vmId) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetVMById.EmptyVmID") - } - - vms, err := self.getVMs(vmId) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetVMById") - } - - if len(vms) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetVMById") - } else if len(vms) == 1 { - izone, err := self.GetIZoneById(getZoneGlobalId(self, vms[0].OSEXTAZAvailabilityZone)) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetVMById.GetIZoneById") - } - - vms[0].host = &SHost{ - zone: izone.(*SZone), - } - return &vms[0], nil - } else { - return nil, errors.Wrap(cloudprovider.ErrDuplicateId, "SRegion.GetVMById") - } -} diff --git a/pkg/multicloud/ctyun/image.go b/pkg/multicloud/ctyun/image.go deleted file mode 100644 index beef53a31b..0000000000 --- a/pkg/multicloud/ctyun/image.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "context" - "strconv" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -const ( - ImageOwnerPublic string = "gold" // 公共镜像:gold - ImageOwnerSelf string = "private" // 私有镜像:private - ImageOwnerShared string = "shared" // 共享镜像:shared -) - -// http://ctyun-api-url/apiproxy/v3/order/getImages -type SImage struct { - multicloud.SImageBase - multicloud.CtyunTags - storageCache *SStoragecache - - // normalized image info - imgInfo *imagetools.ImageInfo - - ID string `json:"id"` - OSType string `json:"osType"` - Platform string `json:"platform"` - Name string `json:"name"` - OSBit int64 `json:"osBit"` - OSVersion string `json:"osVersion"` - MinRAM int64 `json:"minRam"` - MinDisk int64 `json:"minDisk"` - ImageType string `json:"imageType"` - Virtual bool `json:"virtual"` -} - -func (self *SImage) GetCreatedAt() time.Time { - return time.Time{} -} - -func (self *SImage) GetId() string { - return self.ID -} - -func (self *SImage) GetName() string { - return self.Name -} - -func (self *SImage) GetGlobalId() string { - return self.GetId() -} - -func (self *SImage) GetStatus() string { - return api.CACHED_IMAGE_STATUS_ACTIVE -} - -func (self *SImage) Refresh() error { - new, err := self.storageCache.region.GetImage(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SImage) IsEmulated() bool { - return false -} - -func (self *SImage) Delete(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.storageCache -} - -func (self *SImage) GetSizeByte() int64 { - return self.MinDisk * 1024 * 1024 * 1024 -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - switch self.ImageType { - case "gold": - return cloudprovider.ImageTypeSystem - case "private": - return cloudprovider.ImageTypeCustomized - case "shared": - return cloudprovider.ImageTypeShared - default: - return cloudprovider.ImageTypeCustomized - } -} - -func (self *SImage) GetImageStatus() string { - return cloudprovider.IMAGE_STATUS_ACTIVE -} - -func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if self.imgInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(self.OSVersion, strconv.Itoa(int(self.OSBit)), self.OSType, self.Platform, self.OSVersion) - self.imgInfo = &imgInfo - } - return self.imgInfo -} - -func (self *SImage) GetFullOsName() string { - return self.getNormalizedImageInfo().GetFullOsName() -} - -func (self *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) -} - -func (self *SImage) GetOsDist() string { - return self.getNormalizedImageInfo().OsDistro -} - -func (self *SImage) GetOsVersion() string { - return self.getNormalizedImageInfo().OsVersion -} - -func (self *SImage) GetOsLang() string { - return self.getNormalizedImageInfo().OsLang -} - -func (self *SImage) GetOsArch() string { - return self.getNormalizedImageInfo().OsArch -} - -func (self *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return int(self.MinDisk) -} - -func (self *SImage) GetMinRamSizeMb() int { - return int(self.MinRAM) -} - -func (self *SImage) GetImageFormat() string { - return "" -} - -func (self *SImage) GetCreateTime() time.Time { - return time.Time{} -} - -func (self *SRegion) GetImages(imageType string) ([]SImage, error) { - params := map[string]string{ - "regionId": self.GetId(), - "imageType": imageType, - } - - resp, err := self.client.DoGet("/apiproxy/v3/order/getImages", params) - if err != nil { - return nil, errors.Wrap(err, "Region.GetImages.DoGet") - } - - images := make([]SImage, 0) - err = resp.Unmarshal(&images, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "Region.GetImages.Unmarshal") - } - - for i := range images { - images[i].storageCache = &SStoragecache{ - region: self, - } - } - - return images, nil -} - -func (self *SRegion) GetImage(imageId string) (*SImage, error) { - images, err := self.GetImages("") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetImage.GetImages") - } - - for i := range images { - if images[i].GetId() == imageId { - images[i].storageCache = &SStoragecache{ - region: self, - } - - return &images[i], nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetImage") -} diff --git a/pkg/multicloud/ctyun/instance.go b/pkg/multicloud/ctyun/instance.go deleted file mode 100644 index 11e3add1bb..0000000000 --- a/pkg/multicloud/ctyun/instance.go +++ /dev/null @@ -1,1306 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SInstance struct { - multicloud.SInstanceBase - multicloud.CtyunTags - multicloud.SBillingBase - - host *SHost - image *SImage - - vmDetails *InstanceDetails - - HostID string `json:"hostId"` - ID string `json:"id"` - Name string `json:"name"` - Status string `json:"status"` - TenantID string `json:"tenant_id"` - Metadata Metadata `json:"metadata"` - Image Image `json:"image"` - Flavor FlavorObj `json:"flavor"` - Addresses map[string][]Address `json:"addresses"` - UserID string `json:"user_id"` - Created time.Time `json:"created"` - DueDate *time.Time `json:"dueDate"` - SecurityGroups []SecurityGroup `json:"security_groups"` - OSEXTAZAvailabilityZone string `json:"OS-EXT-AZ:availability_zone"` - OSExtendedVolumesVolumesAttached []Volume `json:"os-extended-volumes:volumes_attached"` - MasterOrderId string `json:"masterOrderId"` -} - -type InstanceDetails struct { - HostID string `json:"hostId"` - Name string `json:"name"` - Status string `json:"status"` - PrivateIPS []PrivateIP `json:"privateIps"` - PublicIPS []PublicIP `json:"publicIps"` - Volumes []Volume `json:"volumes"` - Created string `json:"created"` - FlavorObj FlavorObj `json:"flavorObj"` -} - -type Address struct { - Addr string `json:"addr"` - OSEXTIPSType string `json:"OS-EXT-IPS:type"` - Version int64 `json:"version"` - OSEXTIPSMACMACAddr string `json:"OS-EXT-IPS-MAC:mac_addr"` -} - -type Image struct { - Id string `json:"id"` -} - -type SecurityGroup struct { - Name string `json:"name"` -} - -type FlavorObj struct { - Name string `json:"name"` - CPUNum int `json:"cpuNum"` - MemSize int `json:"memSize"` - ID string `json:"id"` -} - -type PrivateIP struct { - ID string `json:"id"` - Address string `json:"address"` -} - -type PublicP struct { - ID string `json:"id"` - Address string `json:"address"` - Bandwidth string `json:"bandwidth"` -} - -func (self *SInstance) GetBillingType() string { - if self.DueDate != nil { - return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SInstance) GetCreatedAt() time.Time { - return self.Created -} - -func (self *SInstance) GetExpiredAt() time.Time { - if self.DueDate == nil { - return time.Time{} - } - - return *self.DueDate -} - -func (self *SInstance) GetId() string { - return self.ID -} - -func (self *SInstance) GetName() string { - return self.Name -} - -func (self *SInstance) GetHostname() string { - return self.Name -} - -func (self *SInstance) GetGlobalId() string { - return self.GetId() -} - -func (self *SInstance) GetStatus() string { - switch self.Status { - case "RUNNING", "ACTIVE": - return api.VM_RUNNING - case "RESTARTING", "BUILD", "RESIZE", "VERIFY_RESIZE": - return api.VM_STARTING - case "STOPPING", "HARD_REBOOT": - return api.VM_STOPPING - case "STOPPED", "SHUTOFF": - return api.VM_READY - default: - return api.VM_UNKNOWN - } -} - -func (self *SInstance) Refresh() error { - new, err := self.host.zone.region.GetVMById(self.GetId()) - if err != nil { - return err - } - - new.host = self.host - if err != nil { - return err - } - - if new.Status == "DELETED" { - log.Debugf("Instance already terminated.") - return cloudprovider.ErrNotFound - } - - // update details - detail, err := self.host.zone.region.GetVMDetails(self.GetId()) - if err != nil { - return errors.Wrap(err, "SInstance.Refresh.GetDetails") - } - - self.vmDetails = detail - return jsonutils.Update(self, new) -} - -func (self *SInstance) IsEmulated() bool { - return false -} - -func (self *SInstance) GetProjectId() string { - return "" -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -// GET http://ctyun-api-url/apiproxy/v3/queryDataDiskByVMId -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - details, err := self.GetDetails() - if err != nil { - return nil, errors.Wrap(err, "SInstance.GetIDisks.GetDetails") - } - - disks := []SDisk{} - for i := range details.Volumes { - volume := details.Volumes[i] - disk, err := self.host.zone.region.GetDisk(volume.ID) - if err != nil { - return nil, errors.Wrap(err, "SInstance.GetIDisks.GetDisk") - } - - disks = append(disks, *disk) - } - - for i := 0; i < len(disks); i += 1 { - // 将系统盘放到第0个位置 - if disks[i].Bootable == "true" { - _temp := disks[0] - disks[0] = disks[i] - disks[i] = _temp - } - } - - idisks := make([]cloudprovider.ICloudDisk, len(disks)) - for i := range disks { - disk := disks[i] - idisks[i] = &disk - } - - return idisks, nil -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nics, err := self.host.zone.region.GetNics(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "SInstance.GetINics") - } - - inics := make([]cloudprovider.ICloudNic, len(nics)) - for i := range nics { - inics[i] = &nics[i] - } - - return inics, nil -} - -// GET http://ctyun-api-urlapiproxy/v3/queryNetworkByVMId -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - detail, err := self.GetDetails() - if err != nil { - return nil, errors.Wrap(err, "SInstance.GetIEIP.GetDetails") - } - - if len(detail.PublicIPS) > 0 { - return self.host.zone.region.GetEip(detail.PublicIPS[0].ID) - } - - return nil, nil -} - -func (self *SInstance) GetDetails() (*InstanceDetails, error) { - if self.vmDetails != nil { - return self.vmDetails, nil - } - - detail, err := self.host.zone.region.GetVMDetails(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "SInstance.GetDetails") - } - - self.vmDetails = detail - return self.vmDetails, nil -} - -func (self *SInstance) GetVcpuCount() int { - details, err := self.GetDetails() - if err == nil { - return details.FlavorObj.CPUNum - } - - return self.Flavor.CPUNum -} - -func (self *SInstance) GetVmemSizeMB() int { - details, err := self.GetDetails() - if err == nil { - return details.FlavorObj.MemSize * 1024 - } - - return self.Flavor.MemSize * 1024 -} - -func (self *SInstance) GetBootOrder() string { - return "dcn" -} - -func (self *SInstance) GetVga() string { - return "std" -} - -func (self *SInstance) GetVdi() string { - return "vnc" -} - -func (self *SInstance) GetImage() (*SImage, error) { - if self.image != nil { - return self.image, nil - } - - image, err := self.host.zone.region.GetImage(self.Image.Id) - if err != nil { - return nil, errors.Wrap(err, "SInstance.GetImage") - } - - self.image = image - return self.image, nil -} - -func (self *SInstance) GetOsType() cloudprovider.TOsType { - image, err := self.GetImage() - if err != nil { - log.Errorf("SInstance.Image %s", err) - return cloudprovider.OsTypeLinux - } - return image.GetOsType() -} - -func (self *SInstance) GetFullOsName() string { - image, err := self.GetImage() - if err != nil { - log.Errorf("SInstance.Image %s", err) - return "" - } - return image.GetFullOsName() -} - -func (self *SInstance) GetBios() cloudprovider.TBiosType { - image, err := self.GetImage() - if err != nil { - log.Errorf("SInstance.Image %s", err) - return cloudprovider.BIOS - } - return image.GetBios() -} - -func (self *SInstance) GetOsArch() string { - image, err := self.GetImage() - if err != nil { - log.Errorf("SInstance.Image %s", err) - return "" - } - return image.GetOsArch() -} - -func (self *SInstance) GetOsDist() string { - image, err := self.GetImage() - if err != nil { - log.Errorf("SInstance.Image %s", err) - return "" - } - return image.GetOsDist() -} - -func (self *SInstance) GetOsVersion() string { - image, err := self.GetImage() - if err != nil { - log.Errorf("SInstance.Image %s", err) - return "" - } - return image.GetOsVersion() -} - -func (self *SInstance) GetOsLang() string { - image, err := self.GetImage() - if err != nil { - log.Errorf("SInstance.Image %s", err) - return "" - } - return image.GetOsLang() -} - -func (self *SInstance) GetMachine() string { - return "pc" -} - -func (self *SInstance) GetInstanceType() string { - return self.Flavor.ID -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - if len(self.SecurityGroups) == 0 { - return []string{}, nil - } - - if len(self.MasterOrderId) > 0 { - return self.getSecurityGroupIdsByMasterOrderId(self.MasterOrderId) - } - - secgroups, err := self.host.zone.region.GetSecurityGroups("") - if err != nil { - return nil, errors.Wrap(err, "SInstance.GetSecurityGroupIds.GetSecurityGroups") - } - - names := []string{} - for i := range self.SecurityGroups { - names = append(names, self.SecurityGroups[i].Name) - } - - ids := []string{} - for i := range secgroups { - // todo: bugfix 如果安全组重名比较尴尬 - if utils.IsInStringArray(secgroups[i].Name, names) { - ids = append(ids, secgroups[i].ResSecurityGroupID) - } - } - - return ids, nil -} - -func (self *SInstance) getSecurityGroupIdsByMasterOrderId(orderId string) ([]string, error) { - orders, err := self.host.zone.region.GetOrder(self.MasterOrderId) - if err != nil { - return nil, errors.Wrap(err, "SInstance.GetSecurityGroupIds.GetOrder") - } - - if len(orders) == 0 { - return nil, nil - } - - for i := range orders { - secgroups := orders[i].ResourceConfigMap.SecurityGroups - if len(secgroups) > 0 { - ids := []string{} - for j := range secgroups { - ids = append(ids, secgroups[j].ID) - } - - return ids, nil - } - } - - return nil, nil -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - return self.host.zone.region.AssignSecurityGroup(self.GetId(), secgroupId) -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - currentIds, err := self.GetSecurityGroupIds() - if err != nil { - return errors.Wrap(err, "GetSecurityGroupIds") - } - - adds := []string{} - for i := range secgroupIds { - if !utils.IsInStringArray(secgroupIds[i], currentIds) { - adds = append(adds, secgroupIds[i]) - } - } - - for i := range adds { - err := self.host.zone.region.AssignSecurityGroup(self.GetId(), adds[i]) - if err != nil { - return errors.Wrap(err, "Instance.SetSecurityGroups") - } - } - - removes := []string{} - for i := range currentIds { - if !utils.IsInStringArray(currentIds[i], secgroupIds) { - removes = append(removes, currentIds[i]) - } - } - - for i := range removes { - err := self.host.zone.region.UnsignSecurityGroup(self.GetId(), removes[i]) - if err != nil { - return errors.Wrap(err, "Instance.SetSecurityGroups") - } - } - - return nil -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_CTYUN -} - -func (self *SInstance) StartVM(ctx context.Context) error { - err := self.host.zone.region.StartVM(self.GetId()) - if err != nil { - return errors.Wrap(err, "Instance.StartVM") - } - - err = cloudprovider.WaitStatus(self, api.VM_RUNNING, 5*time.Second, 300*time.Second) - if err != nil { - return errors.Wrap(err, "Instance.StartVM.WaitStatus") - } - return nil -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - err := self.host.zone.region.StopVM(self.GetId()) - if err != nil { - return errors.Wrap(err, "Instance.StopVM") - } - - err = cloudprovider.WaitStatus(self, api.VM_READY, 5*time.Second, 300*time.Second) - if err != nil { - return errors.Wrap(err, "Instance.StopVM.WaitStatus") - } - return nil -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - err := self.host.zone.region.DeleteVM(self.GetId()) - if err != nil { - return errors.Wrap(err, "SInstance.DeleteVM") - } - - err = cloudprovider.WaitDeleted(self, 10*time.Second, 180*time.Second) - if err != nil { - return errors.Wrap(err, "Instance.DeleteVM.WaitDeleted") - } - return nil -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - currentImage, err := self.GetImage() - if err != nil { - return "", errors.Wrap(err, "Instance.RebuildRoot") - } - - publicKeyName := "" - if len(config.PublicKey) > 0 { - publicKeyName, err = self.host.zone.region.syncKeypair(config.PublicKey) - if err != nil { - return "", errors.Wrap(err, "Instance.RebuildRoot.syncKeypair") - } - } - - jobId := "" - if currentImage.GetId() != config.ImageId { - jobId, err = self.host.zone.region.SwitchVMOs(self.GetId(), config.Password, publicKeyName, config.ImageId) - if err != nil { - return "", errors.Wrap(err, "SInstance.RebuildRoot.SwitchVMOs") - } - } else { - jobId, err = self.host.zone.region.RebuildVM(self.GetId(), config.Password, publicKeyName) - if err != nil { - return "", errors.Wrap(err, "SInstance.RebuildRoot.RebuildVM") - } - } - - err = cloudprovider.Wait(10*time.Second, 1800*time.Second, func() (b bool, err error) { - statusJson, err := self.host.zone.region.GetJob(jobId) - if err != nil { - if strings.Contains(err.Error(), "job fail") { - return false, err - } - - return false, nil - } - - if status, _ := statusJson.GetString("status"); status == "SUCCESS" { - return true, nil - } else if status == "FAILED" { - return false, fmt.Errorf("RebuildRoot job %s failed", jobId) - } else { - return false, nil - } - }) - if err != nil { - return "", errors.Wrap(err, "Instance.RebuildRoot.Wait") - } - - err = self.Refresh() - if err != nil { - return "", err - } - - idisks, err := self.GetIDisks() - if err != nil { - return "", err - } - - if len(idisks) == 0 { - return "", fmt.Errorf("server %s has no volume attached.", self.GetId()) - } - - return idisks[0].GetId(), nil -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - if len(password) == 0 { - return cloudprovider.ErrNotSupported - } - - // 只支持重置密码 - return self.host.zone.region.ResetVMPassword(self.GetId(), password) -} - -func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - jobId, err := self.host.zone.region.ChangeVMConfig(self.GetId(), config.InstanceType) - if err != nil { - return errors.Wrap(err, "Instance.ChangeConfig") - } - - err = cloudprovider.Wait(10*time.Second, 1800*time.Second, func() (b bool, err error) { - statusJson, err := self.host.zone.region.GetJob(jobId) - if err != nil { - if strings.Contains(err.Error(), "job fail") { - return false, err - } - - return false, nil - } - - if status, _ := statusJson.GetString("status"); status == "SUCCESS" { - return true, nil - } else if status == "FAILED" { - return false, fmt.Errorf("ChangeConfig job %s failed", jobId) - } else { - return false, nil - } - }) - if err != nil { - return errors.Wrap(err, "Instance.ChangeConfig.Wait") - } - - return nil -} - -// http://ctyun-api-url/apiproxy/v3/queryVncUrl -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - url, err := self.host.zone.region.GetInstanceVNCUrl(self.GetId()) - if err != nil { - return nil, err - } - ret := &cloudprovider.ServerVncOutput{ - Url: url, - Protocol: "ctyun", - InstanceId: self.GetId(), - Hypervisor: api.HYPERVISOR_CTYUN, - } - return ret, nil -} - -func (self *SInstance) NextDeviceName() (string, error) { - details, err := self.GetDetails() - if err != nil { - return "", errors.Wrap(err, "SInstance.NextDeviceName.GetDetails") - } - - disks := []*SDisk{} - for i := range details.Volumes { - disk, err := self.host.zone.region.GetDisk(details.Volumes[i].ID) - if err != nil { - return "", errors.Wrap(err, "SInstance.NextDeviceName.GetDisk") - } - - disks = append(disks, disk) - } - - prefix := "s" - if len(disks) > 0 && strings.Contains(disks[0].GetMountpoint(), "/vd") { - prefix = "v" - } - - currents := []string{} - for _, disk := range disks { - currents = append(currents, strings.ToLower(disk.GetMountpoint())) - } - - for i := 0; i < 25; i++ { - device := fmt.Sprintf("/dev/%sd%s", prefix, string([]byte{byte(98 + i)})) - if ok, _ := utils.InStringArray(device, currents); !ok { - return device, nil - } - } - - return "", fmt.Errorf("disk devicename out of index, current deivces: %s", currents) -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - device, err := self.NextDeviceName() - if err != nil { - return errors.Wrap(err, "Instance.AttachDisk.NextDeviceName") - } - - _, err = self.host.zone.region.AttachDisk(self.GetId(), diskId, device) - if err != nil { - return errors.Wrap(err, "Instance.AttachDisk") - } - - disk, err := self.host.zone.region.GetDisk(diskId) - if err != nil { - return errors.Wrap(err, "AttachDisk.GetDisk") - } - - err = cloudprovider.WaitStatusWithDelay(disk, api.DISK_READY, 10*time.Second, 5*time.Second, 180*time.Second) - if err != nil { - return errors.Wrap(err, "Instance.DetachDisk.WaitStatusWithDelay") - } - - if disk.Status != "in-use" { - return errors.Wrap(fmt.Errorf("disk status %s", disk.Status), "Instance.DetachDisk.Status") - } - - return nil -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - disk, err := self.host.zone.region.GetDisk(diskId) - if err != nil { - return errors.Wrap(err, "DetachDisk.Wait") - } - - if len(disk.Attachments) == 0 { - return errors.Wrap(err, "Instance.DetachDisk") - } - - _, err = self.host.zone.region.DetachDisk(self.GetId(), diskId, disk.Attachments[0].Device) - if err != nil { - return errors.Wrap(err, "Instance.DetachDisk") - } - - err = cloudprovider.WaitStatusWithDelay(disk, api.DISK_READY, 10*time.Second, 5*time.Second, 180*time.Second) - if err != nil { - return errors.Wrap(err, "Instance.DetachDisk.WaitStatusWithDelay") - } - - if disk.Status != "available" { - return errors.Wrap(fmt.Errorf("disk status %s", disk.Status), "Instance.DetachDisk.Status") - } - - return nil -} - -func (self *SInstance) Renew(bc billing.SBillingCycle) error { - _, err := self.host.zone.region.RenewVM(self.GetId(), &bc) - if err != nil { - return errors.Wrap(err, "Instance.Renew.RenewVM") - } - - return nil -} - -func (self *SInstance) GetError() error { - return nil -} - -type SDiskDetails struct { - HostID string `json:"hostId"` - Name string `json:"name"` - Status string `json:"status"` - PrivateIPS []PrivateIP `json:"privateIps"` - PublicIPS []PublicIP `json:"publicIps"` - Volumes []Volume `json:"volumes"` - Created string `json:"created"` - FlavorObj FlavorObj `json:"flavorObj"` -} - -type PublicIP struct { - ID string `json:"id"` - Address string `json:"address"` - Bandwidth string `json:"bandwidth"` -} - -type Volume struct { - ID string `json:"id"` - Status string `json:"status"` - Type string `json:"type"` - Size string `json:"size"` - Name string `json:"name"` - Bootable bool `json:"bootable"` -} - -func (self *SRegion) GetVMDetails(vmId string) (*InstanceDetails, error) { - params := map[string]string{ - "regionId": self.GetId(), - "vmId": vmId, - } - - resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVMDetail", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetVMDetails.DoGet") - } - - details := &InstanceDetails{} - err = resp.Unmarshal(details, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetVMDetails.Unmarshal") - } - - return details, nil -} - -type SVncInfo struct { - Type string `json:"type"` - URL string `json:"url"` -} - -func (self *SRegion) GetInstanceVNCUrl(vmId string) (string, error) { - params := map[string]string{ - "regionId": self.GetId(), - "vmId": vmId, - } - - resp, err := self.client.DoGet("/apiproxy/v3/queryVncUrl", params) - if err != nil { - return "", errors.Wrap(err, "") - } - - ret := SVncInfo{} - err = resp.Unmarshal(&ret, "returnObj", "console") - if err != nil { - return "", errors.Wrap(err, "") - } - - return ret.URL, nil -} - -/* -创建主机接口目前没有绑定密钥的参数选项,不支持绑定密码。 -但是重装系统接口支持绑定密钥 -*/ -func (self *SRegion) CreateInstance(zoneId, name, imageId, osType, flavorRef, vpcid, subnetId, secGroupId, adminPass, volumetype string, volumeSize int, dataDisks []cloudprovider.SDiskInfo) (string, error) { - rootParams := jsonutils.NewDict() - rootParams.Set("volumetype", jsonutils.NewString(volumetype)) - if volumeSize > 0 { - rootParams.Set("size", jsonutils.NewInt(int64(volumeSize))) - } - - nicParams := jsonutils.NewArray() - nicParam := jsonutils.NewDict() - nicParam.Set("subnet_id", jsonutils.NewString(subnetId)) - nicParams.Add(nicParam) - - secgroupParams := jsonutils.NewArray() - secgroupParam := jsonutils.NewDict() - secgroupParam.Set("id", jsonutils.NewString(secGroupId)) - secgroupParams.Add(secgroupParam) - - extParams := jsonutils.NewDict() - extParams.Set("regionID", jsonutils.NewString(self.GetId())) - - serverParams := jsonutils.NewDict() - serverParams.Set("availability_zone", jsonutils.NewString(zoneId)) - serverParams.Set("name", jsonutils.NewString(name)) - serverParams.Set("imageRef", jsonutils.NewString(imageId)) - serverParams.Set("root_volume", rootParams) - serverParams.Set("flavorRef", jsonutils.NewString(flavorRef)) - serverParams.Set("osType", jsonutils.NewString(osType)) - serverParams.Set("vpcid", jsonutils.NewString(vpcid)) - serverParams.Set("security_groups", secgroupParams) - serverParams.Set("nics", nicParams) - serverParams.Set("adminPass", jsonutils.NewString(adminPass)) - serverParams.Set("count", jsonutils.NewString("1")) - serverParams.Set("extendparam", extParams) - - if dataDisks != nil && len(dataDisks) > 0 { - dataDisksParams := jsonutils.NewArray() - for i := range dataDisks { - dataDiskParams := jsonutils.NewDict() - dataDiskParams.Set("volumetype", jsonutils.NewString(dataDisks[i].StorageType)) - dataDiskParams.Set("size", jsonutils.NewInt(int64(dataDisks[i].SizeGB))) - dataDisksParams.Add(dataDiskParams) - } - - serverParams.Set("data_volumes", dataDisksParams) - } - - vmParams := jsonutils.NewDict() - vmParams.Set("server", serverParams) - - params := map[string]jsonutils.JSONObject{ - "createVMInfo": vmParams, - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/createVM", params) - if err != nil { - return "", errors.Wrap(err, "SRegion.CreateInstance.DoPost") - } - - var ok bool - err = resp.Unmarshal(&ok, "returnObj", "status") - if !ok { - msg, _ := resp.GetString("returnObj", "message") - return "", errors.Wrap(fmt.Errorf(msg), "SRegion.CreateInstance.JobFailed") - } - - var jobId string - err = resp.Unmarshal(&jobId, "returnObj", "data") - if err != nil { - return "", errors.Wrap(err, "SRegion.CreateInstance.Unmarshal") - } - - return jobId, nil -} - -// vm & nic job -func (self *SRegion) GetJob(jobId string) (jsonutils.JSONObject, error) { - params := map[string]string{ - "regionId": self.GetId(), - "jobId": jobId, - } - - resp, err := self.client.DoGet("/apiproxy/v3/queryJobStatus", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetJob.DoGet") - } - - ret := jsonutils.NewDict() - err = resp.Unmarshal(&ret, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetJob.Unmarshal") - } - - return ret, nil -} - -// 查询云硬盘备份JOB状态信息 -func (self *SRegion) GetVbsJob(jobId string) (jsonutils.JSONObject, error) { - params := map[string]string{ - "regionId": self.GetId(), - "jobId": jobId, - } - - resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVbsJob", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetVbsJob.DoGet") - } - - ret := jsonutils.NewDict() - err = resp.Unmarshal(&ret, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetVbsJob.Unmarshal") - } - - return ret, nil -} - -// 查询云硬盘JOB状态信息 -func (self *SRegion) GetVolumeJob(jobId string) (jsonutils.JSONObject, error) { - params := map[string]string{ - "regionId": self.GetId(), - "jobId": jobId, - } - - resp, err := self.client.DoGet("/apiproxy/v3/queryVolumeJob", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetVolumeJob.DoGet") - } - - ret := jsonutils.NewDict() - err = resp.Unmarshal(&ret, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetVolumeJob.Unmarshal") - } - - return ret, nil -} - -// POST http://ctyun-api-url/apiproxy/v3/addSecurityGroup 绑定安全组 -func (self *SRegion) AssignSecurityGroup(vmId, securityGroupRuleId string) error { - securityParams := jsonutils.NewDict() - securityParams.Set("regionId", jsonutils.NewString(self.GetId())) - securityParams.Set("vmId", jsonutils.NewString(vmId)) - securityParams.Set("securityGroupRuleId", jsonutils.NewString(securityGroupRuleId)) - - params := map[string]jsonutils.JSONObject{ - "securityGroup": securityParams, - } - - _, err := self.client.DoPost("/apiproxy/v3/addSecurityGroup", params) - if err != nil { - return errors.Wrap(err, "SRegion.AssignSecurityGroup.DoPost") - } - - return nil -} - -// POST http://ctyun-api-url/apiproxy/v3/removeSecurityGroup 解绑安全组 -func (self *SRegion) UnsignSecurityGroup(vmId, securityGroupRuleId string) error { - securityParams := jsonutils.NewDict() - securityParams.Set("regionId", jsonutils.NewString(self.GetId())) - securityParams.Set("vmId", jsonutils.NewString(vmId)) - securityParams.Set("securityGroupRuleId", jsonutils.NewString(securityGroupRuleId)) - - params := map[string]jsonutils.JSONObject{ - "securityGroup": securityParams, - } - - _, err := self.client.DoPost("/apiproxy/v3/removeSecurityGroup", params) - if err != nil { - return errors.Wrap(err, "SRegion.UnsignSecurityGroup.DoPost") - } - - return nil -} - -func (self *SRegion) StartVM(vmId string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "vmId": jsonutils.NewString(vmId), - } - - _, err := self.client.DoPost("/apiproxy/v3/ondemand/startVM", params) - if err != nil { - return errors.Wrap(err, "SRegion.StartVm.DoPost") - } - - return nil -} - -func (self *SRegion) StopVM(vmId string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "vmId": jsonutils.NewString(vmId), - } - - _, err := self.client.DoPost("/apiproxy/v3/ondemand/stopVM", params) - if err != nil { - return errors.Wrap(err, "SRegion.StopVM.DoPost") - } - - return nil -} - -func (self *SRegion) DeleteVM(vmId string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "vmId": jsonutils.NewString(vmId), - } - - _, err := self.client.DoPost("/apiproxy/v3/ondemand/deleteVM", params) - if err != nil { - return errors.Wrap(err, "SRegion.DeleteVM.DoPost") - } - - return nil -} - -func (self *SRegion) RestartVM(vmId string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "vmId": jsonutils.NewString(vmId), - "type": jsonutils.NewString("SOFT"), - } - - _, err := self.client.DoPost("/apiproxy/v3/ondemand/restartVM", params) - if err != nil { - return errors.Wrap(err, "SRegion.RestartVM.DoPost") - } - - return nil -} - -func (self *SRegion) SwitchVMOs(vmId, adminPass, keyName, imageRef string) (string, error) { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "vmId": jsonutils.NewString(vmId), - "imageRef": jsonutils.NewString(imageRef), - } - - if len(keyName) > 0 { - params["keyName"] = jsonutils.NewString(keyName) - } else if len(adminPass) > 0 { - params["adminPass"] = jsonutils.NewString(adminPass) - } else { - return "", errors.Wrap(fmt.Errorf("require public key or password"), "SRegion.SwitchVMOs") - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/switchSys", params) - if err != nil { - return "", errors.Wrap(err, "SRegion.SwitchVMOs.DoPost") - } - - var ok bool - err = resp.Unmarshal(&ok, "returnObj", "status") - if !ok { - msg, _ := resp.GetString("returnObj", "message") - return "", errors.Wrap(fmt.Errorf(msg), "SRegion.SwitchVMOs.JobFailed") - } - - var jobId string - err = resp.Unmarshal(&jobId, "returnObj", "data") - if err != nil { - return "", errors.Wrap(err, "SRegion.SwitchVMOs.Unmarshal") - } - - return jobId, nil -} - -func (self *SRegion) RebuildVM(vmId, adminPass, keyName string) (string, error) { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "vmId": jsonutils.NewString(vmId), - } - - if len(keyName) > 0 { - params["keyName"] = jsonutils.NewString(keyName) - } else if len(adminPass) > 0 { - params["adminPass"] = jsonutils.NewString(adminPass) - } else { - return "", errors.Wrap(fmt.Errorf("require public key or password"), "SRegion.RebuildVM") - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/reInstallSys", params) - if err != nil { - return "", errors.Wrap(err, "SRegion.RebuildVM.DoPost") - } - - var ok bool - err = resp.Unmarshal(&ok, "returnObj", "status") - if !ok { - msg, _ := resp.GetString("returnObj", "message") - return "", errors.Wrap(fmt.Errorf(msg), "SRegion.RebuildVM.JobFailed") - } - - var jobId string - err = resp.Unmarshal(&jobId, "returnObj", "data") - if err != nil { - return "", errors.Wrap(err, "SRegion.RebuildVM.Unmarshal") - } - - return jobId, nil -} - -func (self *SRegion) AttachDisk(vmId, volumeId, device string) (string, error) { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "volumeId": jsonutils.NewString(volumeId), - "vmId": jsonutils.NewString(vmId), - "device": jsonutils.NewString(device), - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/attachVolume", params) - if err != nil { - return "", errors.Wrap(err, "SRegion.AttachDisk.DoPost") - } - - var ok bool - err = resp.Unmarshal(&ok, "returnObj", "status") - if !ok { - msg, _ := resp.GetString("returnObj", "message") - return "", errors.Wrap(fmt.Errorf(msg), "SRegion.AttachDisk.JobFailed") - } - - var jobId string - err = resp.Unmarshal(&jobId, "returnObj", "data") - if err != nil { - return "", errors.Wrap(err, "SRegion.AttachDisk.Unmarshal") - } - - return jobId, nil -} - -func (self *SRegion) DetachDisk(vmId, volumeId, device string) (string, error) { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "volumeId": jsonutils.NewString(volumeId), - "vmId": jsonutils.NewString(vmId), - "device": jsonutils.NewString(device), - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/uninstallVolume", params) - if err != nil { - return "", errors.Wrap(err, "SRegion.DetachDisk.DoPost") - } - - var ok bool - err = resp.Unmarshal(&ok, "returnObj", "status") - if !ok { - msg, _ := resp.GetString("returnObj", "message") - return "", errors.Wrap(fmt.Errorf(msg), "SRegion.DetachDisk.JobFailed") - } - - var jobId string - err = resp.Unmarshal(&jobId, "returnObj", "data") - if err != nil { - return "", errors.Wrap(err, "SRegion.DetachDisk.Unmarshal") - } - - return jobId, nil -} - -func (self *SRegion) ChangeVMConfig(vmId, flavorId string) (string, error) { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "vmId": jsonutils.NewString(vmId), - "flavorId": jsonutils.NewString(flavorId), - } - - resp, err := self.client.DoPost("/apiproxy/v3/ondemand/upgradeVM", params) - if err != nil { - return "", errors.Wrap(err, "SRegion.ChangeVMConfig.DoPost") - } - - var ok bool - err = resp.Unmarshal(&ok, "returnObj", "status") - if !ok { - msg, _ := resp.GetString("returnObj", "message") - return "", errors.Wrap(fmt.Errorf(msg), "SRegion.ChangeVMConfig.JobFailed") - } - - var jobId string - err = resp.Unmarshal(&jobId, "returnObj", "data") - if err != nil { - return "", errors.Wrap(err, "SRegion.ChangeVMConfig.Unmarshal") - } - - return jobId, nil -} - -// POST http://ctyun-api-url/apiproxy/v3/order/placeRenewOrder 续订 -func (self *SRegion) RenewVM(vmId string, bc *billing.SBillingCycle) ([]string, error) { - if bc == nil { - return nil, errors.Wrap(fmt.Errorf("SBillingCycle is nil"), "Region.RenewVM") - } - - resourcePackage := jsonutils.NewDict() - month := bc.GetMonths() - switch { - case month <= 11: - resourcePackage.Set("cycleCount", jsonutils.NewString(strconv.Itoa(month))) - resourcePackage.Set("cycleType", jsonutils.NewString("3")) - case month == 12: - resourcePackage.Set("cycleCount", jsonutils.NewString("1")) - resourcePackage.Set("cycleType", jsonutils.NewString("5")) - case month == 24: - resourcePackage.Set("cycleCount", jsonutils.NewString("1")) - resourcePackage.Set("cycleType", jsonutils.NewString("6")) - case month == 36: - resourcePackage.Set("cycleCount", jsonutils.NewString("1")) - resourcePackage.Set("cycleType", jsonutils.NewString("7")) - default: - return nil, errors.Wrap(fmt.Errorf("unsupported month duration %d. expected 1~11, 12, 24, 36", month), "Region.RenewVM") - } - - vmIds := jsonutils.NewArray() - vmIds.Add(jsonutils.NewString(vmId)) - resourcePackage.Set("resourceIds", vmIds) - - params := map[string]jsonutils.JSONObject{ - "resourceDetailJson": resourcePackage, - } - - resp, err := self.client.DoPost("/apiproxy/v3/order/placeRenewOrder", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.RenewVM.DoPost") - } - - var ok bool - err = resp.Unmarshal(&ok, "returnObj", "submitted") - if !ok { - msg, _ := resp.GetString("returnObj", "message") - return nil, errors.Wrap(fmt.Errorf(msg), "SRegion.RenewVM.JobFailed") - } - - type OrderPlacedEventsElement struct { - ErrorMessage string `json:"errorMessage"` - Submitted bool `json:"submitted"` - NewOrderID string `json:"newOrderId"` - NewOrderNo string `json:"newOrderNo"` - TotalPrice int64 `json:"totalPrice"` - } - - orders := []OrderPlacedEventsElement{} - err = resp.Unmarshal(&orders, "returnObj", "orderPlacedEvents") - if err != nil { - return nil, errors.Wrap(err, "SRegion.RenewVM.Unmarshal") - } - - orderIds := []string{} - for i := range orders { - orderIds = append(orderIds, orders[i].NewOrderID) - } - - return orderIds, nil -} - -func (self *SRegion) ResetVMPassword(vmId, password string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "vmId": jsonutils.NewString(vmId), - "password": jsonutils.NewString(password), - } - - _, err := self.client.DoPost("/apiproxy/v3/resetVmPassword", params) - if err != nil { - return errors.Wrap(err, "SRegion.ResetVMPassword.DoPost") - } - - return nil -} diff --git a/pkg/multicloud/ctyun/instancenic.go b/pkg/multicloud/ctyun/instancenic.go deleted file mode 100644 index 3f3ce9a545..0000000000 --- a/pkg/multicloud/ctyun/instancenic.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - instance *SInstance - FixedIPS []FixedIP `json:"fixed_ips"` - PortState string `json:"port_state"` - PortID string `json:"port_id"` - MACAddr string `json:"mac_addr"` - NetID string `json:"net_id"` - - cloudprovider.DummyICloudNic -} - -type FixedIP struct { - IPAddress string `json:"ip_address"` - SubnetID string `json:"subnet_id"` -} - -func (self *SInstanceNic) GetIP() string { - if len(self.FixedIPS) == 0 { - return "" - } - - return self.FixedIPS[0].IPAddress -} - -func (self *SInstanceNic) GetMAC() string { - return self.MACAddr -} - -func (self *SInstanceNic) GetId() string { - return "" -} - -func (self *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (self *SInstanceNic) GetINetworkId() string { - return self.NetID -} - -func (self *SRegion) GetNics(vmId string) ([]SInstanceNic, error) { - params := map[string]string{ - "regionId": self.GetId(), - "vmId": vmId, - } - - resp, err := self.client.DoGet("/apiproxy/v3/queryNetworkCards", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetNics.DoGet") - } - - ret := make([]SInstanceNic, 0) - err = resp.Unmarshal(&ret, "returnObj", "interfaceAttachments") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetNics.Unmarshal") - } - - for i := range ret { - ins, err := self.GetVMById(vmId) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetNics") - } - - ret[i].instance = ins - } - - return ret, nil -} diff --git a/pkg/multicloud/ctyun/latitud_and_longitude.go b/pkg/multicloud/ctyun/latitud_and_longitude.go deleted file mode 100644 index 215a0ef1b8..0000000000 --- a/pkg/multicloud/ctyun/latitud_and_longitude.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ - "cn-beijing1": {Latitude: 39.997743, Longitude: 116.304542, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-hz1": {Latitude: 30.274084, Longitude: 120.155067, City: api.CITY_HANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-gslz1": {Latitude: 36.0613769373, Longitude: 103.8341600069, City: api.CITY_LAN_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-sxty1": {Latitude: 37.8705857132, Longitude: 112.5506634865, City: api.CITY_TAI_YUAN, CountryCode: api.COUNTRY_CODE_CN}, - "cn-sh1": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-gz1": {Latitude: 26.6470035286, Longitude: 106.6302113880, City: api.CITY_GUI_YANG, CountryCode: api.COUNTRY_CODE_CN}, - "cn-sdqd1": {Latitude: 36.067108, Longitude: 120.382607, City: api.CITY_QING_DAO, CountryCode: api.COUNTRY_CODE_CN}, - "cn-tj1": {Latitude: 39.0850853357, Longitude: 117.1993482089, City: api.CITY_TIAN_JIN, CountryCode: api.COUNTRY_CODE_CN}, - "cn-xjcj1": {Latitude: 43.8266013700, Longitude: 87.6168405804, City: api.CITY_WU_LU_MU_QI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-cq1": {Latitude: 29.431585, Longitude: 106.912254, City: api.CITY_CHONG_QING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-gxnn1": {Latitude: 22.8167372565, Longitude: 108.3669005333, City: api.CITY_NAN_NING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-hazz1": {Latitude: 34.7533581487, Longitude: 113.6313915479, City: api.CITY_ZHENG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-ynkm1": {Latitude: 24.8796595146, Longitude: 102.8332118852, City: api.CITY_KUN_MING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-xian1": {Latitude: 34.3412614674, Longitude: 108.9398165260, City: api.CITY_XI_AN, CountryCode: api.COUNTRY_CODE_CN}, - "cn-hihk1": {Latitude: 20.0442268036, Longitude: 110.1998910288, City: api.CITY_HAI_KOU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-ahwh1": {Latitude: 31.3524675159, Longitude: 118.4331307290, City: api.CITY_WU_HU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-fz1": {Latitude: 26.0741979397, Longitude: 119.2964466153, City: api.CITY_FU_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-nmhh1": {Latitude: 40.842358, Longitude: 111.749992, City: api.CITY_HU_HE_HAO_TE, CountryCode: api.COUNTRY_CODE_CN}, - "cn-shanghai2": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-snxy1": {Latitude: 34.3412614674, Longitude: 108.9398165260, City: api.CITY_XI_AN, CountryCode: api.COUNTRY_CODE_CN}, - "cn-hbwh1": {Latitude: 30.5927599029, Longitude: 114.3052387810, City: api.CITY_WU_HAN, CountryCode: api.COUNTRY_CODE_CN}, - "cn-hncs1": {Latitude: 28.2277765095, Longitude: 112.9388453666, City: api.CITY_CHANG_SHA, CountryCode: api.COUNTRY_CODE_CN}, - "cn-guangzhou2": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-guizhou2": {Latitude: 26.6470035286, Longitude: 106.6302113880, City: api.CITY_GUI_YANG, CountryCode: api.COUNTRY_CODE_CN}, - "cn-jssz1": {Latitude: 31.2983479333, Longitude: 120.5831894861, City: api.CITY_SU_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-sccd1": {Latitude: 30.572815, Longitude: 104.066803, City: api.CITY_CHENG_DU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-guangzhou3": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-shanghai3": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-neimeng4": {Latitude: 40.842358, Longitude: 111.749992, City: api.CITY_HU_HE_HAO_TE, CountryCode: api.COUNTRY_CODE_CN}, - "cn-beijing3": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-baoding1": {Latitude: 38.8739745619, Longitude: 115.4646082830, City: api.CITY_BAO_DING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-nj2": {Latitude: 32.0584065670, Longitude: 118.7964897811, City: api.CITY_NAN_JING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-gdgz1": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-bj1": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-bj4": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-neimeng5": {Latitude: 40.842358, Longitude: 111.749992, City: api.CITY_HU_HE_HAO_TE, CountryCode: api.COUNTRY_CODE_CN}, - "cn-shanghai5": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-sh6": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-gdfs2": {Latitude: 23.0218629843, Longitude: 113.1219225896, City: api.CITY_FO_SHAN, CountryCode: api.COUNTRY_CODE_CN}, -} diff --git a/pkg/multicloud/ctyun/network.go b/pkg/multicloud/ctyun/network.go deleted file mode 100644 index 52d6239128..0000000000 --- a/pkg/multicloud/ctyun/network.go +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "fmt" - "strconv" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.CtyunTags - vpc *SVpc - wire *SWire - - CIDR string `json:"cidr"` - FirstDcn string `json:"firstDcn"` - Gateway string `json:"gateway"` - Name string `json:"name"` - NeutronSubnetID string `json:"neutronSubnetId"` - RegionID string `json:"regionId"` - ResVLANID string `json:"resVlanId"` - SecondDcn string `json:"secondDcn"` - VLANStatus string `json:"vlanStatus"` - VpcID string `json:"vpcId"` - ZoneID string `json:"zoneId"` - ZoneName string `json:"zoneName"` -} - -func (self *SNetwork) GetId() string { - return self.ResVLANID -} - -func (self *SNetwork) GetName() string { - return self.Name -} - -func (self *SNetwork) GetGlobalId() string { - return self.GetId() -} - -func (self *SNetwork) GetStatus() string { - switch self.VLANStatus { - case "ACTIVE", "UNKNOWN": - return api.NETWORK_STATUS_AVAILABLE - case "ERROR": - return api.NETWORK_STATUS_UNKNOWN - default: - return api.NETWORK_STATUS_UNKNOWN - } -} - -func (self *SNetwork) Refresh() error { - log.Debugf("network refresh %s", self.GetId()) - new, err := self.wire.region.GetNetwork(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SNetwork) IsEmulated() bool { - return false -} - -func (self *SNetwork) GetProjectId() string { - return "" -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - startIp = startIp.StepUp() // 2 - return startIp.String() -} - -func (self *SNetwork) GetIpEnd() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - 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.CIDR) - return pref.MaskLen -} - -func (self *SNetwork) GetGateway() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - return startIp.String() -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetIsPublic() bool { - return true -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) Delete() error { - return self.vpc.region.DeleteNetwork(self.vpc.GetId(), self.GetId()) -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 120 -} - -func (self *SRegion) GetNetwroks(vpcId string) ([]SNetwork, error) { - querys := map[string]string{ - "regionId": self.GetId(), - } - if len(vpcId) > 0 { - querys["vpcId"] = vpcId - } - - networks := make([]SNetwork, 0) - resp, err := self.client.DoGet("/apiproxy/v3/getSubnets", querys) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetNetwroks.DoGet") - } - - err = resp.Unmarshal(&networks, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetNetwroks.Unmarshal") - } - - for i := range networks { - vpc, err := self.GetVpc(networks[i].VpcID) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetNetwork.GetVpc") - } - networks[i].vpc = vpc - - networks[i].wire = &SWire{ - region: self, - vpc: vpc, - } - - networks[i].wire.addNetwork(&networks[i]) - } - - return networks, err -} - -func (self *SRegion) getNetwork(subnetId string) (*SNetwork, error) { - querys := map[string]string{ - "subnetId": subnetId, - "regionId": self.GetId(), - } - - resp, err := self.client.DoGet("/apiproxy/v3/querySubnetDetail", querys) - if err != nil { - return nil, errors.Wrap(err, "SRegion.getNetwork.DoGet") - } - - network := &SNetwork{} - err = resp.Unmarshal(network, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "SRegion.getNetwork.Unmarshal") - } - - return network, nil -} - -func (self *SRegion) GetNetwork(subnetId string) (*SNetwork, error) { - network, err := self.getNetwork(subnetId) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetNetwork.getNetwork") - } - - vpc, err := self.GetVpc(network.VpcID) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetNetwork.GetVpc") - } - network.vpc = vpc - - network.wire = &SWire{ - region: self, - vpc: vpc, - } - - network.wire.addNetwork(network) - return network, err -} - -func (self *SRegion) CreateNetwork(vpcId, zoneId, name, cidr, dhcpEnable string) (*SNetwork, error) { - gateway, err := getDefaultGateWay(cidr) - if err != nil { - return nil, err - } - - networkParams := jsonutils.NewDict() - networkParams.Set("regionId", jsonutils.NewString(self.GetId())) - networkParams.Set("zoneId", jsonutils.NewString(zoneId)) - networkParams.Set("name", jsonutils.NewString(name)) - networkParams.Set("cidr", jsonutils.NewString(cidr)) - networkParams.Set("gatewayIp", jsonutils.NewString(gateway)) - networkParams.Set("dhcpEnable", jsonutils.NewString(dhcpEnable)) - networkParams.Set("vpcId", jsonutils.NewString(vpcId)) - // DNS地址,如果主机需要访问公网就需要填写该值,不填写就不能使用DNS解析 - // networkParams.Set("primaryDns", jsonutils.NewString(primaryDns)) - // networkParams.Set("secondaryDns", jsonutils.NewString(secondaryDns)) - - params := map[string]jsonutils.JSONObject{ - "jsonStr": networkParams, - } - - resp, err := self.client.DoPost("/apiproxy/v3/createSubnet", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateNetwork.DoPost") - } - - netId, err := resp.GetString("returnObj", "id") - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateNetwork.GetString") - } - - err = cloudprovider.WaitCreated(10*time.Second, 180*time.Second, func() bool { - network, err := self.getNetwork(netId) - if err != nil { - log.Debugf("SRegion.CreateNetwork.getNetwork") - return false - } - - if len(network.VpcID) == 0 { - return false - } else { - return true - } - }) - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateNetwork.GetVpc") - } - - return self.GetNetwork(netId) -} - -func (self *SRegion) DeleteNetwork(vpcId, subnetId string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "vpcId": jsonutils.NewString(vpcId), - "subnetId": jsonutils.NewString(subnetId), - } - - resp, err := self.client.DoPost("/apiproxy/v3/deleteSubnet", params) - if err != nil { - return errors.Wrap(err, "SRegion.DeleteNetwork.DoPost") - } - - var statusCode int - err = resp.Unmarshal(&statusCode, "statusCode") - if statusCode != 800 { - return errors.Wrap(fmt.Errorf(strconv.Itoa(statusCode)), "SRegion.DeleteNetwork.Failed") - } - - return nil -} diff --git a/pkg/multicloud/ctyun/project.go b/pkg/multicloud/ctyun/project.go deleted file mode 100644 index 70768deb2d..0000000000 --- a/pkg/multicloud/ctyun/project.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "strings" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" -) - -// GET http://ctyun-api-url/apiproxy/v3/ondemand/queryProjectIds -type SProject struct { - Enabled bool `json:"enabled"` - Name string `json:"name"` - Description string `json:"description"` - ID string `json:"id"` -} - -func (self *SProject) GetRegionID() string { - return strings.Split(self.Name, "_")[1] -} - -func (self *SProject) GetHealthStatus() string { - if self.Enabled { - return api.CLOUD_PROVIDER_HEALTH_NORMAL - } - - return api.CLOUD_PROVIDER_HEALTH_SUSPENDED -} - -func (self *SCtyunClient) FetchProjects() ([]SProject, error) { - client, err := NewSCtyunClient( - NewSCtyunClientConfig( - self.accessKey, self.accessSecret, self.options, - ).Debug(self.debug), - ) - if err != nil { - return nil, errors.Wrap(err, "CtyunClient.FetchProjects") - } - projects := make([]SProject, 0) - resp, err := client.DoGet("/apiproxy/v3/ondemand/queryProjectIds", map[string]string{}) - if err != nil { - return nil, errors.Wrap(err, "CtyunClient.FetchProjects.DoGet") - } - - err = resp.Unmarshal(&projects, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "CtyunClient.FetchProjects.Unmarshal") - } - - return projects, err -} - -func (self *SRegion) FetchProjects() ([]SProject, error) { - return self.client.FetchProjects() -} diff --git a/pkg/multicloud/ctyun/provider/doc.go b/pkg/multicloud/ctyun/provider/doc.go deleted file mode 100644 index ac70700dd9..0000000000 --- a/pkg/multicloud/ctyun/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/ctyun/provider" diff --git a/pkg/multicloud/ctyun/provider/provider.go b/pkg/multicloud/ctyun/provider/provider.go deleted file mode 100644 index c1620441a0..0000000000 --- a/pkg/multicloud/ctyun/provider/provider.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/ctyun" -) - -type SCtyunProviderFactory struct { - cloudprovider.SPublicCloudBaseProviderFactory -} - -func (self *SCtyunProviderFactory) GetId() string { - return ctyun.CLOUD_PROVIDER_CTYUN -} - -func (self *SCtyunProviderFactory) GetName() string { - return ctyun.CLOUD_PROVIDER_CTYUN_CN -} - -func (self *SCtyunProviderFactory) IsSupportPrepaidResources() bool { - return true -} - -func (self *SCtyunProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - if len(input.Environment) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "environment") - } - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - output.AccessUrl = input.Environment - return output, nil -} - -func (self *SCtyunProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func (self *SCtyunProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - segs := strings.Split(cfg.Account, "/") - projectId := "" - account := cfg.Account - if len(segs) == 2 { - projectId = segs[1] - account = segs[0] - } - - options := cloudprovider.SCtyunExtraOptions{} - if cfg.Options != nil { - err := cfg.Options.Unmarshal(&options) - if err != nil { - log.Debugf("cfg.Options.Unmarshal %s", err) - } - } - - client, err := ctyun.NewSCtyunClient( - ctyun.NewSCtyunClientConfig( - account, cfg.Secret, &options, - ).ProjectId(projectId).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SCtyunProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SCtyunProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - ret := map[string]string{ - "CTYUN_ACCESS_URL": info.Url, - "CTYUN_ACCESS_KEY": info.Account, - "CTYUN_SECRET": info.Secret, - "CTYUN_REGION": ctyun.CTYUN_DEFAULT_REGION, - } - - options := cloudprovider.SCtyunExtraOptions{} - if info.Options != nil { - err := info.Options.Unmarshal(&options) - if err != nil { - log.Debugf("info.Options.Unmarshal %s", err) - } - } - if len(options.CrmBizId) > 0 { - ret["CTYUN_CRM_BIZ_ID"] = options.CrmBizId - } - - return ret, nil -} - -func init() { - factory := SCtyunProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SCtyunProvider struct { - cloudprovider.SBaseProvider - client *ctyun.SCtyunClient -} - -func (self *SCtyunProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SCtyunProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SCtyunProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SCtyunProvider) GetSysInfo() (jsonutils.JSONObject, error) { - regions := self.client.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") - info.Add(jsonutils.NewString(ctyun.CTYUN_API_VERSION), "api_version") - return info, nil -} - -func (self *SCtyunProvider) GetVersion() string { - return ctyun.CTYUN_API_VERSION -} - -func (self *SCtyunProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(id) -} - -func (self *SCtyunProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SCtyunProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SCtyunProvider) GetStorageClasses(regionId string) []string { - return []string{ - "STANDARD", "WARM", "COLD", - } -} - -func (self *SCtyunProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (self *SCtyunProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (self *SCtyunProvider) GetCloudRegionExternalIdPrefix() string { - return self.client.GetCloudRegionExternalIdPrefix() -} - -func (self *SCtyunProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} diff --git a/pkg/multicloud/ctyun/region.go b/pkg/multicloud/ctyun/region.go deleted file mode 100644 index a501f61672..0000000000 --- a/pkg/multicloud/ctyun/region.go +++ /dev/null @@ -1,488 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "fmt" - "strconv" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - cloudprovider.SFakeOnPremiseRegion - multicloud.SRegion - multicloud.SNoObjectStorageRegion - - client *SCtyunClient - storageCache *SStoragecache - - // - initialled bool - - RegionName string - Description string `json:"description"` - ID string `json:"id"` - ParentRegionID string `json:"parent_region_id"` - Type string `json:"type"` - - izones []cloudprovider.ICloudZone - ivpcs []cloudprovider.ICloudVpc -} - -func (self *SRegion) fetchIVpcs() error { - vpcs, err := self.GetVpcs() - if err != nil { - return errors.Wrap(err, "SRegion.fetchIVpcs") - } - - self.ivpcs = make([]cloudprovider.ICloudVpc, 0) - for i := range vpcs { - vpc := vpcs[i] - vpc.region = self - self.ivpcs = append(self.ivpcs, &vpc) - } - - return nil -} - -func (self *SRegion) fetchInfrastructure() error { - if err := self.fetchIVpcs(); err != nil { - return err - } - - for i := 0; i < len(self.ivpcs); i += 1 { - vpc := self.ivpcs[i].(*SVpc) - wire := SWire{region: self, vpc: vpc} - vpc.addWire(&wire) - - for j := 0; j < len(self.izones); j += 1 { - zone := self.izones[j].(*SZone) - zone.addWire(&wire) - } - - vpc.fetchNetworks() - } - return nil -} - -func (self *SRegion) GetVpcs() ([]SVpc, error) { - vpcs := make([]SVpc, 0) - params := map[string]string{ - "regionId": self.GetId(), - } - - resp, err := self.client.DoGet("/apiproxy/v3/getVpcs", params) - if err != nil { - return nil, err - } - - err = resp.Unmarshal(&vpcs, "returnObj") - if err != nil { - return nil, err - } - - return vpcs, nil -} - -func (self *SRegion) CreateVpc(name, cidr string) (*SVpc, error) { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "name": jsonutils.NewString(name), - "cidr": jsonutils.NewString(cidr), - } - resp, err := self.client.DoPost("/apiproxy/v3/createVPC", params) - if err != nil { - return nil, err - } - - vpc := &SVpc{} - err = resp.Unmarshal(vpc, "returnObj") - if err != nil { - return nil, err - } - - vpc.ResVpcID, _ = resp.GetString("returnObj", "id") - vpc.region = self - return vpc, nil -} - -func (self *SRegion) GetClient() *SCtyunClient { - return self.client -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - return self.GetSecurityGroupDetails(secgroupId) -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - segroups, err := self.GetSecurityGroups(opts.VpcId) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetISecurityGroupByName.GetSecurityGroups") - } - - for i := range segroups { - if segroups[i].Name == opts.Name { - return &segroups[i], nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetISecurityGroupByName.GetSecurityGroups") -} - -func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - secgroup, err := self.CreateSecurityGroup(conf.VpcId, conf.Name) - if err != nil { - return nil, errors.Wrap(err, "Region.CreateISecurityGroup") - } - - return secgroup, nil -} - -func (self *SRegion) GetId() string { - return self.ID -} - -func (self *SRegion) GetName() string { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_CTYUN_CN, self.RegionName) -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_CTYUN_EN, self.RegionName) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.ID) -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) Refresh() error { - return nil -} - -func (self *SRegion) IsEmulated() bool { - return false -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - if info, ok := LatitudeAndLongitude[self.ID]; ok { - return info - } - return cloudprovider.SGeographicInfo{} -} - -// http://ctyun-api-url/apiproxy/v3/order/getZoneConfig -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if self.izones == nil || self.initialled == false { - var err error - err = self.fetchInfrastructure() - if err != nil { - return nil, err - } - - self.initialled = true - } - return self.izones, nil -} - -// http://ctyun-api-url/apiproxy/v3/getVpcs -// http://ctyun-api-url/apiproxy/v3/getVpcs -func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - if self.ivpcs == nil || self.initialled == false { - err := self.fetchInfrastructure() - if err != nil { - return nil, err - } - - self.initialled = true - } - return self.ivpcs, nil -} - -// http://ctyun-api-url/apiproxy/v3/ondemand/queryIps -func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, err := self.GetEips() - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetIEips.GetEips") - } - - ieips := make([]cloudprovider.ICloudEIP, len(eips)) - for i := range eips { - ieips[i] = &eips[i] - } - - return ieips, nil -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - ivpcs, err := self.GetIVpcs() - if err != nil { - return nil, err - } - for i := 0; i < len(ivpcs); i += 1 { - if ivpcs[i].GetGlobalId() == id { - return ivpcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { - return self.GetEip(id) -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - return self.GetVMById(id) -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return self.GetDisk(id) -} - -func (self *SRegion) DeleteSecurityGroup(securityGroupId string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "securityGroupId": jsonutils.NewString(securityGroupId), - } - - resp, err := self.client.DoPost("/apiproxy/v3/deleteSecurityGroup", params) - if err != nil { - return errors.Wrap(err, "SRegion.DeleteSecurityGroup.DoPost") - } - - var statusCode int - err = resp.Unmarshal(&statusCode, "statusCode") - if statusCode != 800 { - return errors.Wrap(fmt.Errorf(strconv.Itoa(statusCode)), "SRegion.DeleteSecurityGroup.JobFailed") - } - - return nil -} - -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - return self.CreateVpc(opts.NAME, opts.CIDR) -} - -func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - zones, err := self.GetIZones() - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateEIP.GetIZones") - } - - if len(zones) == 0 { - return nil, errors.Wrap(errors.ErrNotFound, "SRegion.CreateEIP.GetIZones") - } - - return self.CreateEip(zones[0].GetId(), eip.Name, strconv.Itoa(eip.BandwidthMbps), "PER", eip.ChargeType) -} - -func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - return []cloudprovider.ICloudSnapshot{}, nil -} - -func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) CreateSnapshotPolicy(*cloudprovider.SnapshotPolicyInput) (string, error) { - return "", cloudprovider.ErrNotImplemented -} - -func (self *SRegion) UpdateSnapshotPolicy(*cloudprovider.SnapshotPolicyInput, string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRegion) DeleteSnapshotPolicy(policyId string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { - polices, err := self.GetDiskBackupPolices() - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetISnapshotPolicies.GetDiskBackupPolices") - } - - ipolices := make([]cloudprovider.ICloudSnapshotPolicy, len(polices)) - for i := range polices { - ipolices[i] = &polices[i] - } - - return ipolices, nil -} - -func (self *SRegion) GetISnapshotPolicyById(snapshotPolicyId string) (cloudprovider.ICloudSnapshotPolicy, error) { - return self.GetDiskBackupPolicy(snapshotPolicyId) -} - -func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - iHosts := make([]cloudprovider.ICloudHost, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneHost, err := izones[i].GetIHosts() - if err != nil { - return nil, err - } - iHosts = append(iHosts, iZoneHost...) - } - return iHosts, nil -} - -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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - return []cloudprovider.ICloudStoragecache{storageCache}, nil -} - -func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - if storageCache.GetGlobalId() == id { - return storageCache, nil - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetProvider() string { - return api.CLOUD_PROVIDER_CTYUN -} - -func (self *SRegion) GetInstances(instanceId string) ([]SInstance, error) { - params := map[string]string{ - "regionId": self.GetId(), - } - - if len(instanceId) > 0 { - params["instanceId"] = instanceId - } - - resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVMs", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetInstances.DoGet") - } - - ret := make([]SInstance, 0) - err = resp.Unmarshal(&ret, "returnObj", "servers") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetInstances.Unmarshal") - } - - return ret, nil -} - -func (self *SRegion) GetInstanceFlavors() ([]FlavorObj, error) { - params := map[string]string{ - "regionId": self.GetId(), - } - - resp, err := self.client.DoGet("/apiproxy/v3/order/getFlavors", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetInstanceFlavors.DoGet") - } - - ret := make([]FlavorObj, 0) - err = resp.Unmarshal(&ret, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetInstanceFlavors.Unmarshal") - } - - return ret, nil -} - -func (region *SRegion) GetCapabilities() []string { - return region.client.GetCapabilities() -} diff --git a/pkg/multicloud/ctyun/securitygroup.go b/pkg/multicloud/ctyun/securitygroup.go deleted file mode 100644 index 4120be45cf..0000000000 --- a/pkg/multicloud/ctyun/securitygroup.go +++ /dev/null @@ -1,364 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "fmt" - "net" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - apis "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.CtyunTags - region *SRegion - - ResSecurityGroupID string `json:"resSecurityGroupId"` - Name string `json:"name"` - AccountID string `json:"accountId"` - UserID string `json:"userId"` - RegionID string `json:"regionId"` - ZoneID string `json:"zoneId"` - VpcID string `json:"vpcId"` - CreateDate int64 `json:"createDate"` - Status int64 `json:"status"` -} - -func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error { - return self.DeleteSecurityGroupRule(secGrpRuleId) -} - -func (self *SRegion) AddSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error { - direction := "" - if rule.Direction == secrules.SecurityRuleIngress { - direction = "ingress" - } else { - direction = "egress" - } - - protocal := rule.Protocol - if rule.Protocol == secrules.PROTO_ANY { - protocal = "" - } - - // imcp协议默认为any - if rule.Protocol == secrules.PROTO_ICMP { - return self.addSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String()) - } - - if len(rule.Ports) > 0 { - for _, port := range rule.Ports { - portStr := fmt.Sprintf("%d", port) - err := self.addSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String()) - if err != nil { - return err - } - } - } else { - portStart := fmt.Sprintf("%d", rule.PortStart) - portEnd := fmt.Sprintf("%d", rule.PortEnd) - err := self.addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String()) - if err != nil { - return err - } - } - - return nil -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - for _, r := range append(inDels, outDels...) { - err := self.region.delSecurityGroupRule(r.ExternalId) - if err != nil { - return errors.Wrapf(err, "delSecurityGroupRule(%s)", r.ExternalId) - } - } - for _, r := range append(inAdds, outAdds...) { - err := self.region.AddSecurityGroupRules(self.ResSecurityGroupID, r) - if err != nil { - return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String()) - } - } - return nil -} - -func (self *SSecurityGroup) Delete() error { - return self.region.DeleteSecurityGroup(self.GetId()) -} - -func (self *SSecurityGroup) GetId() string { - return self.ResSecurityGroupID -} - -func (self *SSecurityGroup) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.ResSecurityGroupID -} - -func (self *SSecurityGroup) GetGlobalId() string { - return self.GetId() -} - -func (self *SSecurityGroup) GetStatus() string { - return "" -} - -func (self *SSecurityGroup) Refresh() error { - if new, err := self.region.GetSecurityGroupDetails(self.GetId()); err != nil { - return err - } else { - return jsonutils.Update(self, new) - } -} - -func (self *SSecurityGroup) IsEmulated() bool { - return false -} - -func (self *SSecurityGroup) GetDescription() string { - return "" -} - -// 判断是否兼容云端安全组规则 -func compatibleSecurityGroupRule(r SSecurityGroupRule) bool { - // 忽略了源地址是安全组的规则 - if len(r.RemoteGroupId) > 0 { - return false - } - - // 忽略IPV6 - if r.Ethertype == "IPv6" { - return false - } - - return true -} - -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - _rules, err := self.region.GetSecurityGroupRules(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "SSecurityGroup.GetRules.GetSecurityGroupRules") - } - - rules := make([]cloudprovider.SecurityRule, 0) - for _, r := range _rules { - if !compatibleSecurityGroupRule(r) { - continue - } - - rule, err := self.GetSecurityRule(r) - if err != nil { - return rules, err - } - - rules = append(rules, rule) - } - - return rules, nil -} - -func (self *SSecurityGroup) GetSecurityRule(remoteRule SSecurityGroupRule) (cloudprovider.SecurityRule, error) { - var err error - var direction secrules.TSecurityRuleDirection - if remoteRule.Direction == "ingress" { - direction = secrules.SecurityRuleIngress - } else { - direction = secrules.SecurityRuleEgress - } - - protocol := secrules.PROTO_ANY - if remoteRule.Protocol != "" { - protocol = remoteRule.Protocol - } - - var portStart int - var portEnd int - if protocol == secrules.PROTO_ICMP { - portStart = -1 - portEnd = -1 - } else { - portStart = int(remoteRule.PortRangeMin) - portEnd = int(remoteRule.PortRangeMax) - } - - ipNet := &net.IPNet{} - if len(remoteRule.RemoteIPPrefix) > 0 { - _, ipNet, err = net.ParseCIDR(remoteRule.RemoteIPPrefix) - } else { - _, ipNet, err = net.ParseCIDR("0.0.0.0/0") - } - - if err != nil { - return cloudprovider.SecurityRule{}, err - } - - rule := cloudprovider.SecurityRule{ - ExternalId: remoteRule.ID, - SecurityRule: secrules.SecurityRule{ - Priority: 1, - Action: secrules.SecurityRuleAllow, - IPNet: ipNet, - Protocol: protocol, - Direction: direction, - PortStart: portStart, - PortEnd: portEnd, - Ports: nil, - Description: remoteRule.Description, - }, - } - - err = rule.ValidateRule() - return rule, err -} - -func (self *SSecurityGroup) GetVpcId() string { - return apis.NORMAL_VPC_ID -} - -func (self *SRegion) GetSecurityGroupDetails(groupId string) (*SSecurityGroup, error) { - params := map[string]string{ - "regionId": self.GetId(), - "securityGroupId": groupId, - } - - resp, err := self.client.DoGet("/apiproxy/v3/querySecurityGroupDetail", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetSecurityGroupDetails") - } - - ret := &SSecurityGroup{} - err = resp.Unmarshal(&ret, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetSecurityGroupDetails.Unmarshal") - } - - ret.region = self - return ret, nil -} - -func (self *SRegion) GetSecurityGroups(vpcId string) ([]SSecurityGroup, error) { - params := map[string]string{ - "regionId": self.GetId(), - } - - if len(vpcId) > 0 { - params["vpcId"] = vpcId - } - - resp, err := self.client.DoGet("/apiproxy/v3/getSecurityGroups", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetSecurityGroups") - } - - ret := make([]SSecurityGroup, 0) - err = resp.Unmarshal(&ret, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetSecurityGroups.Unmarshal") - } - - for i := range ret { - ret[i].region = self - } - - return ret, nil -} - -func (self *SRegion) CreateSecurityGroup(vpcId, name string) (*SSecurityGroup, error) { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "name": jsonutils.NewString(name), - } - - if len(vpcId) > 0 && vpcId != apis.NORMAL_VPC_ID { - params["vpcId"] = jsonutils.NewString(vpcId) - } - - resp, err := self.client.DoPost("/apiproxy/v3/createSecurityGroup", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.DoPost") - } - - secgroupId, err := resp.GetString("returnObj", "id") - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.GetSecgroupId") - } - - secgroup, err := self.GetSecurityGroupDetails(secgroupId) - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.GetISecurityGroupById") - } - - secgroup.region = self - return secgroup, nil -} - -func (self *SRegion) DeleteSecurityGroupRule(securityGroupRuleId string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "securityGroupRuleId": jsonutils.NewString(securityGroupRuleId), - } - - _, err := self.client.DoPost("/apiproxy/v3/deleteSecurityGroupRule", params) - if err != nil { - return errors.Wrap(err, "SRegion.DeleteSecurityGroupRule.DoPost") - } - - return err -} - -func (self *SRegion) addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error { - secgroupObj := jsonutils.NewDict() - secgroupObj.Add(jsonutils.NewString(self.GetId()), "regionId") - secgroupObj.Add(jsonutils.NewString(secGrpId), "securityGroupId") - secgroupObj.Add(jsonutils.NewString(direction), "direction") - secgroupObj.Add(jsonutils.NewString(ipNet), "remoteIpPrefix") - secgroupObj.Add(jsonutils.NewString("IPv4"), "ethertype") - // 端口为空或者1-65535 - if len(portStart) > 0 && portStart != "0" && portStart != "-1" { - secgroupObj.Add(jsonutils.NewString(portStart), "portRangeMin") - } - if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" { - secgroupObj.Add(jsonutils.NewString(portEnd), "portRangeMax") - } - if len(protocol) > 0 { - secgroupObj.Add(jsonutils.NewString(protocol), "protocol") - } - - params := map[string]jsonutils.JSONObject{ - "jsonStr": secgroupObj, - } - - resp, err := self.client.DoPost("/apiproxy/v3/createSecurityGroupRule", params) - if err != nil { - return errors.Wrap(err, "SRegion.DoPost") - } - - rule := SSecurityGroupRule{} - err = resp.Unmarshal(&rule, "returnObj") - if err != nil { - return errors.Wrap(err, "SRegion.Unmarshal") - } - - return nil -} diff --git a/pkg/multicloud/ctyun/shell/crm.go b/pkg/multicloud/ctyun/shell/crm.go deleted file mode 100644 index de9a1e39f6..0000000000 --- a/pkg/multicloud/ctyun/shell/crm.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VCrmUserOptions struct { - Type string `json:"type"` - CrmBizId string `json:"crm_biz_id"` - AccountId string `json:"account_id"` - } - shellutils.R(&VCrmUserOptions{}, "crm-user-show", "Show crm user", func(cli *ctyun.SRegion, args *VCrmUserOptions) error { - user, e := cli.GetCrmUser(args.Type, args.CrmBizId, args.AccountId) - if e != nil { - return e - } - printObject(user) - return nil - }) -} diff --git a/pkg/multicloud/ctyun/shell/disk.go b/pkg/multicloud/ctyun/shell/disk.go deleted file mode 100644 index d20e778fbf..0000000000 --- a/pkg/multicloud/ctyun/shell/disk.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "context" - - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VDiskListOptions struct { - } - shellutils.R(&VDiskListOptions{}, "disk-list", "List disks", func(cli *ctyun.SRegion, args *VDiskListOptions) error { - disks, e := cli.GetDisks() - if e != nil { - return e - } - printList(disks, 0, 0, 0, nil) - return nil - }) - - type DiskCreateOptions struct { - ZoneId string `help:"zone id"` - Name string `help:"disk name"` - DiskType string `help:"disk type" choice:"SSD|SAS|SATA"` - Size string `help:"disk size"` - } - shellutils.R(&DiskCreateOptions{}, "disk-create", "Create disk", func(cli *ctyun.SRegion, args *DiskCreateOptions) error { - disk, e := cli.CreateDisk(args.ZoneId, args.Name, args.DiskType, args.Size) - if e != nil { - return e - } - printObject(disk) - return nil - }) - - type DiskResizeOptions struct { - DiskId string `help:"disk id"` - Size int64 `help:"disk size GB"` - } - shellutils.R(&DiskResizeOptions{}, "disk-resize", "Resize disk", func(cli *ctyun.SRegion, args *DiskResizeOptions) error { - disk, err := cli.GetDisk(args.DiskId) - if err != nil { - return err - } - - e := disk.Resize(context.Background(), args.Size*1024) - if e != nil { - return e - } - printObject(disk) - return nil - }) - - type VDiskRestoreOptions struct { - DiskId string `help:"disk id"` - SnapshotId string `help:"snapshot id"` - } - shellutils.R(&VDiskRestoreOptions{}, "disk-restore", "Restore disk", func(cli *ctyun.SRegion, args *VDiskRestoreOptions) error { - disk, err := cli.GetDisk(args.DiskId) - if err != nil { - return err - } - - _, e := disk.Reset(context.Background(), args.SnapshotId) - if e != nil { - return e - } - printObject(disk) - return nil - }) -} diff --git a/pkg/multicloud/ctyun/shell/diskbackuppolicy.go b/pkg/multicloud/ctyun/shell/diskbackuppolicy.go deleted file mode 100644 index 79f3adff23..0000000000 --- a/pkg/multicloud/ctyun/shell/diskbackuppolicy.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VPolicyListOptions struct { - } - shellutils.R(&VPolicyListOptions{}, "policy-list", "List polices", func(cli *ctyun.SRegion, args *VPolicyListOptions) error { - polices, e := cli.GetDiskBackupPolices() - if e != nil { - return e - } - printList(polices, 0, 0, 0, nil) - return nil - }) - - type PolicyCreateOptions struct { - Name string `help:"policy name"` - StartTime string `help:"startTime"` - Frequency string `help:"frequency"` - RententionNum string `help:"rententionNum"` - FirstBackup string `help:"firstBackup"` - Status string `help:"status"` - } - shellutils.R(&PolicyCreateOptions{}, "policy-create", "Create policy", func(cli *ctyun.SRegion, args *PolicyCreateOptions) error { - e := cli.CreateDiskBackupPolicy(args.Name, args.StartTime, args.Frequency, args.RententionNum, args.FirstBackup, args.Status) - if e != nil { - return e - } - - return nil - }) - - type BindingDiskBackupPolicyOptions struct { - PolicyId string `help:"policy id"` - ResourceId string `help:"resource id"` - ResourceType string `help:"resource type"` - } - shellutils.R(&BindingDiskBackupPolicyOptions{}, "policy-bind", "Binding policy", func(cli *ctyun.SRegion, args *BindingDiskBackupPolicyOptions) error { - e := cli.BindingDiskBackupPolicy(args.PolicyId, args.ResourceId, args.ResourceType) - if e != nil { - return e - } - - return nil - }) - - type UnBindDiskBackupPolicyOptions struct { - PolicyId string `help:"policy id"` - ResourceId string `help:"resourceId"` - } - shellutils.R(&UnBindDiskBackupPolicyOptions{}, "policy-unbind", "Unbind policy", func(cli *ctyun.SRegion, args *UnBindDiskBackupPolicyOptions) error { - e := cli.UnBindDiskBackupPolicy(args.PolicyId, args.ResourceId) - if e != nil { - return e - } - - return nil - }) -} diff --git a/pkg/multicloud/ctyun/shell/doc.go b/pkg/multicloud/ctyun/shell/doc.go deleted file mode 100644 index f81b052869..0000000000 --- a/pkg/multicloud/ctyun/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/ctyun/shell" diff --git a/pkg/multicloud/ctyun/shell/eip.go b/pkg/multicloud/ctyun/shell/eip.go deleted file mode 100644 index 7bd41a1e03..0000000000 --- a/pkg/multicloud/ctyun/shell/eip.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VEipListOptions struct { - } - shellutils.R(&VEipListOptions{}, "eip-list", "List eips", func(cli *ctyun.SRegion, args *VEipListOptions) error { - eips, e := cli.GetEips() - if e != nil { - return e - } - printList(eips, 0, 0, 0, nil) - return nil - }) - - type EipCreateOptions struct { - ZoneId string `help:"zone id"` - Name string `help:"eip name"` - Size string `help:"size"` - ShareType string `help:"share type" choice:"PER|WHOLE"` - ChargeMode string `help:"charge mode" choice:"bandwidth|traffic"` - } - shellutils.R(&EipCreateOptions{}, "eip-create", "Create eip", func(cli *ctyun.SRegion, args *EipCreateOptions) error { - eip, e := cli.CreateEip(args.ZoneId, args.Name, args.Size, args.ShareType, args.ChargeMode) - if e != nil { - return e - } - printObject(eip) - return nil - }) -} diff --git a/pkg/multicloud/ctyun/shell/image.go b/pkg/multicloud/ctyun/shell/image.go deleted file mode 100644 index 0416207eec..0000000000 --- a/pkg/multicloud/ctyun/shell/image.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VImageListOptions struct { - ImageType string `help:"image type" choices:"gold|private|shared"` - } - shellutils.R(&VImageListOptions{}, "image-list", "List images", func(cli *ctyun.SRegion, args *VImageListOptions) error { - images, e := cli.GetImages(args.ImageType) - if e != nil { - return e - } - printList(images, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ctyun/shell/instance.go b/pkg/multicloud/ctyun/shell/instance.go deleted file mode 100644 index 17fc784a79..0000000000 --- a/pkg/multicloud/ctyun/shell/instance.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - Id string `help:"ID of instance to show"` - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List intances", func(cli *ctyun.SRegion, args *InstanceListOptions) error { - instances, e := cli.GetInstances(args.Id) - if e != nil { - return e - } - printList(instances, 0, 0, 0, []string{}) - return nil - }) - - type InstanceCreateOptions struct { - ZoneId string `help:"zone ID of instance"` - NAME string `help:"name of instance"` - ADMINPASS string `help:"admin password of instance"` - ImageId string `help:"image Id of instance"` - OsType string `help:"Os type of image"` - VolumeType string `help:"volume type of instance"` - VolumeSize int `help:"volume size(GB) of instance"` - Flavor string `help:"Flavor of instance"` - VpcId string `help:"Vpc of instance"` - SubnetId string `help:"subnet Id of instance"` - SecGroupId string `help:"security group Id of instance"` - } - - shellutils.R(&InstanceCreateOptions{}, "instance-create", "Create intance", func(cli *ctyun.SRegion, args *InstanceCreateOptions) error { - _, e := cli.CreateInstance(args.ZoneId, args.NAME, args.ImageId, args.OsType, args.Flavor, args.VpcId, args.SubnetId, args.SecGroupId, args.ADMINPASS, args.VolumeType, args.VolumeSize, nil) - if e != nil { - return e - } - - return nil - }) -} diff --git a/pkg/multicloud/ctyun/shell/job.go b/pkg/multicloud/ctyun/shell/job.go deleted file mode 100644 index 8fa407a48e..0000000000 --- a/pkg/multicloud/ctyun/shell/job.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VJobShowOptions struct { - JOBID string `help:"Job ID"` - } - shellutils.R(&VJobShowOptions{}, "job-show", "Show job", func(cli *ctyun.SRegion, args *VJobShowOptions) error { - job, e := cli.GetJob(args.JOBID) - if e != nil { - return e - } - printObject(job) - return nil - }) - - shellutils.R(&VJobShowOptions{}, "vbs-job-show", "Show vbs job", func(cli *ctyun.SRegion, args *VJobShowOptions) error { - job, e := cli.GetVbsJob(args.JOBID) - if e != nil { - return e - } - printObject(job) - return nil - }) - - shellutils.R(&VJobShowOptions{}, "volume-job-show", "Show volume job", func(cli *ctyun.SRegion, args *VJobShowOptions) error { - job, e := cli.GetVolumeJob(args.JOBID) - if e != nil { - return e - } - printObject(job) - return nil - }) -} diff --git a/pkg/multicloud/ctyun/shell/network.go b/pkg/multicloud/ctyun/shell/network.go deleted file mode 100644 index e2b7460eef..0000000000 --- a/pkg/multicloud/ctyun/shell/network.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VNetworkListOptions struct { - Vpc string `help:"Vpc ID"` - } - shellutils.R(&VNetworkListOptions{}, "subnet-list", "List subnets", func(cli *ctyun.SRegion, args *VNetworkListOptions) error { - vswitches, e := cli.GetNetwroks(args.Vpc) - if e != nil { - return e - } - printList(vswitches, 0, 0, 0, nil) - return nil - }) - - type NetworkCreateOptions struct { - VpcId string `help:"vpc id"` - ZoneId string `help:"zone id"` - Name string `help:"subnet name"` - Cidr string `help:"cidr"` - GatewayIp string `help:"gateway ip"` - DhcpEnable string `help:"gateway ip" choice:"true|false"` - } - shellutils.R(&NetworkCreateOptions{}, "subnet-create", "Create subnet", func(cli *ctyun.SRegion, args *NetworkCreateOptions) error { - vpc, e := cli.CreateNetwork(args.VpcId, args.ZoneId, args.Name, args.Cidr, args.DhcpEnable) - if e != nil { - return e - } - printObject(vpc) - return nil - }) -} diff --git a/pkg/multicloud/ctyun/shell/printutils.go b/pkg/multicloud/ctyun/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/ctyun/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/ctyun/shell/project.go b/pkg/multicloud/ctyun/shell/project.go deleted file mode 100644 index ad760cf49d..0000000000 --- a/pkg/multicloud/ctyun/shell/project.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VProjectListOptions struct { - } - shellutils.R(&VProjectListOptions{}, "project-list", "List projects", func(cli *ctyun.SRegion, args *VProjectListOptions) error { - projects, e := cli.FetchProjects() - if e != nil { - return e - } - printList(projects, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ctyun/shell/region.go b/pkg/multicloud/ctyun/shell/region.go deleted file mode 100644 index 8061444c4a..0000000000 --- a/pkg/multicloud/ctyun/shell/region.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *ctyun.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ctyun/shell/secgroup.go b/pkg/multicloud/ctyun/shell/secgroup.go deleted file mode 100644 index cd5d9400b9..0000000000 --- a/pkg/multicloud/ctyun/shell/secgroup.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VSecurityGroupListOptions struct { - Vpc string `help:"Vpc ID"` - } - shellutils.R(&VSecurityGroupListOptions{}, "secgroup-list", "List secgroups", func(cli *ctyun.SRegion, args *VSecurityGroupListOptions) error { - secgroups, e := cli.GetSecurityGroups(args.Vpc) - if e != nil { - return e - } - printList(secgroups, 0, 0, 0, nil) - return nil - }) - - type VSecurityGroupRuleListOptions struct { - Group string `help:"Security Group ID"` - } - shellutils.R(&VSecurityGroupRuleListOptions{}, "secrule-list", "List secgroup rules", func(cli *ctyun.SRegion, args *VSecurityGroupRuleListOptions) error { - secrules, e := cli.GetSecurityGroupRules(args.Group) - if e != nil { - return e - } - printList(secrules, 0, 0, 0, nil) - return nil - }) - - type SecurityGroupCreateOptions struct { - VpcId string `help:"vpc id"` - Name string `help:"secgroup name"` - } - shellutils.R(&SecurityGroupCreateOptions{}, "secgroup-create", "Create secgroup", func(cli *ctyun.SRegion, args *SecurityGroupCreateOptions) error { - vpc, e := cli.CreateSecurityGroup(args.VpcId, args.Name) - if e != nil { - return e - } - printObject(vpc) - return nil - }) - - type SecurityGroupRuleCreateOptions struct { - GROUP string `help:"secgroup id"` - RULE string - } - shellutils.R(&SecurityGroupRuleCreateOptions{}, "secrule-create", "Create secgroup rule", func(cli *ctyun.SRegion, args *SecurityGroupRuleCreateOptions) error { - rule, err := secrules.ParseSecurityRule(args.RULE) - if err != nil { - return errors.Wrap(err, "ParseSecurityRule") - } - return cli.AddSecurityGroupRules(args.GROUP, cloudprovider.SecurityRule{SecurityRule: *rule}) - }) -} diff --git a/pkg/multicloud/ctyun/shell/vpc.go b/pkg/multicloud/ctyun/shell/vpc.go deleted file mode 100644 index fa308bd820..0000000000 --- a/pkg/multicloud/ctyun/shell/vpc.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ctyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - } - shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *ctyun.SRegion, args *VpcListOptions) error { - vpcs, e := cli.GetVpcs() - if e != nil { - return e - } - printList(vpcs, 0, 0, 0, nil) - return nil - }) - - type VpcCreateOptions struct { - NAME string `help:"vpc name"` - CIDR string `help:"10.0.0.0/8~10.255.255.0/24或者172.16.0.0/12 ~ 172.31.255.0/24或者192.168.0.0/16 ~ 192.168.255.0/24"` - } - shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *ctyun.SRegion, args *VpcCreateOptions) error { - vpc, e := cli.CreateVpc(args.NAME, args.CIDR) - if e != nil { - return e - } - printObject(vpc) - return nil - }) -} diff --git a/pkg/multicloud/ctyun/storage.go b/pkg/multicloud/ctyun/storage.go deleted file mode 100644 index 7ed7ac7f5b..0000000000 --- a/pkg/multicloud/ctyun/storage.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "fmt" - "strconv" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var StorageTypes = []string{ - api.STORAGE_CTYUN_SAS, - api.STORAGE_CTYUN_SATA, - api.STORAGE_CTYUN_SSD, -} - -type SStorage struct { - multicloud.SStorageBase - multicloud.CtyunTags - zone *SZone - storageType string -} - -func (self *SStorage) GetId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) -} - -func (self *SStorage) GetName() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetGlobalId() string { - return self.GetId() -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) Refresh() error { - return nil -} - -func (self *SStorage) IsEmulated() bool { - return true -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.zone.region.getStoragecache() -} - -func (self *SStorage) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -// http://ctyun-api-url/apiproxy/v3/ondemand/queryVolumes -// http://ctyun-api-url/apiproxy/v3/queryDataDisks -func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := self.zone.region.GetDisks() - if err != nil { - return nil, err - } - - // 按storage type 过滤出disk - filtedDisks := make([]SDisk, 0) - for i := range disks { - disk := disks[i] - if disk.VolumeType == self.storageType && disk.AvailabilityZone == self.zone.GetId() { - filtedDisks = append(filtedDisks, disk) - } - } - - idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) - for i := 0; i < len(filtedDisks); i += 1 { - filtedDisks[i].storage = self - idisks[i] = &filtedDisks[i] - } - return idisks, nil -} - -func (self *SStorage) GetStorageType() string { - return self.storageType -} - -func (self *SStorage) GetMediumType() string { - if self.storageType == api.STORAGE_CTYUN_SSD { - return api.DISK_TYPE_SSD - } else { - return api.DISK_TYPE_ROTATE - } -} - -func (self *SStorage) GetCapacityMB() int64 { - return 0 -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (self *SStorage) GetEnabled() bool { - return true -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - disk, err := self.zone.region.CreateDisk(self.zone.GetId(), conf.Name, self.GetStorageType(), strconv.Itoa(conf.SizeGb)) - if err != nil { - return nil, errors.Wrap(err, "Storage.CreateIDisk.CreateDisk") - } - - return disk, nil -} - -func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - if len(idStr) == 0 { - log.Debugf("GetIDiskById disk id should not be empty") - return nil, cloudprovider.ErrNotFound - } - - if disk, err := self.zone.region.GetDisk(idStr); err != nil { - return nil, err - } else { - disk.storage = self - return disk, nil - } -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} - -func (self *SRegion) getStoragecache() *SStoragecache { - if self.storageCache == nil { - self.storageCache = &SStoragecache{region: self} - } - return self.storageCache -} diff --git a/pkg/multicloud/ctyun/storagecache.go b/pkg/multicloud/ctyun/storagecache.go deleted file mode 100644 index a1544b2cf7..0000000000 --- a/pkg/multicloud/ctyun/storagecache.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "context" - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.CtyunTags - region *SRegion -} - -func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, update func(progress float32)) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func GetBucketName(regionId string, imageId string) string { - return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), imageId) -} - -func (self *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) -} - -func (self *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) -} - -func (self *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, 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) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - imagesSelf, err := self.region.GetImages(ImageOwnerSelf) - if err != nil { - return nil, errors.Wrapf(err, "GetImages") - } - ret := []cloudprovider.ICloudImage{} - for i := range imagesSelf { - imagesSelf[i].storageCache = self - ret = append(ret, &imagesSelf[i]) - } - return ret, nil -} - -func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - image, err := self.region.GetImage(extId) - if err != nil { - return nil, errors.Wrap(err, "SStoragecache.GetIImageById.GetImage") - } - - image.storageCache = self - return image, err -} - -func (self *SStoragecache) GetPath() string { - return "" -} diff --git a/pkg/multicloud/ctyun/vpc.go b/pkg/multicloud/ctyun/vpc.go deleted file mode 100644 index c504c8e9cb..0000000000 --- a/pkg/multicloud/ctyun/vpc.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - multicloud.CtyunTags - - region *SRegion - - iwires []cloudprovider.ICloudWire - secgroups []cloudprovider.ICloudSecurityGroup - - ResVpcID string `json:"resVpcId"` - Name string `json:"name"` - CIDR string `json:"cidr"` - ZoneID string `json:"zoneId"` - ZoneName string `json:"zoneName"` - VpcStatus string `json:"vpcStatus"` - RegionID string `json:"regionId"` - CreateDate int64 `json:"createDate"` -} - -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.ResVpcID -} - -func (self *SVpc) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.ResVpcID -} - -func (self *SVpc) GetGlobalId() string { - return self.GetId() -} - -func (self *SVpc) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} - -func (self *SVpc) Refresh() error { - new, err := self.region.GetVpc(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SVpc) IsEmulated() bool { - return false -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetIsDefault() bool { - return false -} - -func (self *SVpc) GetCidrBlock() string { - return self.CIDR -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - if self.iwires == nil { - err := self.fetchNetworks() - if err != nil { - return nil, err - } - } - return self.iwires, nil -} - -// http://ctyun-api-url/apiproxy/v3/getSecurityGroupRules -// http://ctyun-api-url/apiproxy/v3/getSecurityGroups -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) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - rts := []cloudprovider.ICloudRouteTable{} - return rts, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) Delete() error { - return self.region.DeleteVpc(self.GetId()) -} - -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) fetchSecurityGroups() error { - secgroups, err := self.region.GetSecurityGroups("") - if err != nil { - return err - } - - self.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) - for i := 0; i < len(secgroups); i++ { - self.secgroups[i] = &secgroups[i] - } - - return nil -} - -func (self *SVpc) getWireByRegionId(regionId string) *SWire { - if len(regionId) == 0 { - return nil - } - - for i := 0; i < len(self.iwires); i++ { - wire := self.iwires[i].(*SWire) - - if wire.region.GetId() == regionId { - return wire - } - } - - return nil -} - -func (self *SVpc) fetchNetworks() error { - networks, err := self.region.GetNetwroks(self.GetId()) - if err != nil { - return err - } - - if len(networks) == 0 { - self.iwires = []cloudprovider.ICloudWire{&SWire{region: self.region, vpc: self}} - return nil - } - - for i := 0; i < len(networks); i += 1 { - wire := self.getWireByRegionId(self.region.GetId()) - networks[i].wire = wire - wire.addNetwork(&networks[i]) - } - - return nil -} - -func (self *SRegion) GetVpc(vpcId string) (*SVpc, error) { - params := map[string]string{ - "vpcId": vpcId, - "regionId": self.GetId(), - } - - vpc := &SVpc{} - resp, err := self.client.DoGet("/apiproxy/v3/queryVPCDetail", params) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetVpc.DoGet") - } - - if id, _ := resp.GetString("returnObj", "resVpcId"); len(id) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetVpc.GetID") - } - - err = resp.Unmarshal(vpc, "returnObj") - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetVpc.Unmarshal") - } - - vpc.region = self - return vpc, nil -} - -func (self *SRegion) DeleteVpc(vpcId string) error { - params := map[string]jsonutils.JSONObject{ - "regionId": jsonutils.NewString(self.GetId()), - "vpcId": jsonutils.NewString(vpcId), - } - - _, err := self.client.DoPost("/apiproxy/v3/deleteVPC", params) - if err != nil { - return errors.Wrap(err, "SRegion.DeleteVpc.DoPost") - } - - return nil -} diff --git a/pkg/multicloud/ctyun/wire.go b/pkg/multicloud/ctyun/wire.go deleted file mode 100644 index 489bcb266b..0000000000 --- a/pkg/multicloud/ctyun/wire.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.CtyunTags - region *SRegion - vpc *SVpc - - inetworks []cloudprovider.ICloudNetwork -} - -func (self *SWire) GetId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) -} - -func (self *SWire) GetName() string { - return self.GetId() -} - -func (self *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SWire) Refresh() error { - return nil -} - -func (self *SWire) IsEmulated() bool { - return true -} - -// http://ctyun-api-url/apiproxy/v3/queryVPCDetail -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - return nil -} - -// http://ctyun-api-url/apiproxy/v3/getSubnets -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 getDefaultGateWay(cidr string) (string, error) { - pref, err := netutils.NewIPV4Prefix(cidr) - if err != nil { - return "", errors.Wrap(err, "getDefaultGateWay.NewIPV4Prefix") - } - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - return startIp.String(), nil -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - var ZoneId string - if len(self.inetworks) > 0 { - ZoneId = self.inetworks[0].(*SNetwork).ZoneID - } else { - if len(self.region.izones) > 0 { - ZoneId = self.region.izones[0].GetId() - } else { - return nil, fmt.Errorf("SWire.CreateINetwork region %s zone is empty", self.region.GetName()) - } - } - network, err := self.region.CreateNetwork(self.vpc.GetId(), ZoneId, opts.Name, opts.Cidr, "true") - if err != nil { - return nil, errors.Wrap(err, "SWire.CreateINetwork.CreateNetwork") - } - - return network, 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.GetId() { - find = true - break - } - } - if !find { - self.inetworks = append(self.inetworks, network) - } -} diff --git a/pkg/multicloud/ctyun/zone.go b/pkg/multicloud/ctyun/zone.go deleted file mode 100644 index 0edc451ede..0000000000 --- a/pkg/multicloud/ctyun/zone.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ctyun - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SZone struct { - multicloud.SResourceBase - multicloud.CtyunTags - region *SRegion - host *SHost - - iwires []cloudprovider.ICloudWire - istorages []cloudprovider.ICloudStorage - /* 支持的磁盘种类集合 */ - storageTypes []string - - RegionID string `json:"regionId"` - ZoneID string `json:"zoneId"` - ZoneName string `json:"zoneName"` - ZoneType string `json:"zoneType"` -} - -func getZoneGlobalId(region *SRegion, zoneId string) string { - return fmt.Sprintf("%s/%s", region.GetGlobalId(), zoneId) -} - -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) GetId() string { - return self.ZoneID -} - -func (self *SZone) GetName() string { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_CTYUN_CN, self.ZoneID) -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(self.ZoneID) - return table -} - -func (self *SZone) GetGlobalId() string { - return getZoneGlobalId(self.region, self.GetId()) -} - -func (self *SZone) GetStatus() string { - return "enable" -} - -func (self *SZone) Refresh() error { - return nil -} - -func (self *SZone) IsEmulated() bool { - return false -} - -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 { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "fetchStorages") - } - } - return self.istorages, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - if self.istorages == nil { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "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) getHost() *SHost { - if self.host == nil { - self.host = &SHost{zone: self} - } - return self.host -} - -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) getStorageType() { - if len(self.storageTypes) == 0 { - self.storageTypes = StorageTypes - } -} - -func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { - return self.iwires, nil -} diff --git a/pkg/multicloud/doc.go b/pkg/multicloud/doc.go deleted file mode 100644 index ad57b3cd07..0000000000 --- a/pkg/multicloud/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 multicloud // import "yunion.io/x/onecloud/pkg/multicloud" diff --git a/pkg/multicloud/ecloud/client.go b/pkg/multicloud/ecloud/client.go deleted file mode 100644 index 5cec1484d3..0000000000 --- a/pkg/multicloud/ecloud/client.go +++ /dev/null @@ -1,322 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "bytes" - "context" - "crypto/sha256" - "encoding/hex" - "fmt" - "io/ioutil" - "net/http" - "net/url" - "os" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -const ( - CLOUD_PROVIDER_ECLOUD = api.CLOUD_PROVIDER_ECLOUD - CLOUD_PROVIDER_ECLOUD_CN = "移动云" - CLOUD_PROVIDER_ECLOUD_EN = "Ecloud" - CLOUD_API_VERSION = "2016-12-05" - - ECLOUD_DEFAULT_REGION = "beijing-1" -) - -type SEcloudClientConfig struct { - cpcfg cloudprovider.ProviderConfig - signer ISigner - - debug bool -} - -func NewEcloudClientConfig(signer ISigner) *SEcloudClientConfig { - cfg := &SEcloudClientConfig{ - signer: signer, - } - return cfg -} - -func (cfg *SEcloudClientConfig) SetCloudproviderConfig(cpcfg cloudprovider.ProviderConfig) *SEcloudClientConfig { - cfg.cpcfg = cpcfg - return cfg -} - -func (cfg *SEcloudClientConfig) SetDebug(debug bool) *SEcloudClientConfig { - cfg.debug = debug - return cfg -} - -type SEcloudClient struct { - *SEcloudClientConfig - - httpClient *http.Client - iregions []cloudprovider.ICloudRegion -} - -func NewEcloudClient(cfg *SEcloudClientConfig) (*SEcloudClient, error) { - httpClient := cfg.cpcfg.AdaptiveTimeoutHttpClient() - return &SEcloudClient{ - SEcloudClientConfig: cfg, - httpClient: httpClient, - }, nil -} - -func (self *SEcloudClient) GetAccessEnv() string { - return api.CLOUD_ACCESS_ENV_ECLOUD_CHINA -} - -func (ec *SEcloudClient) fetchRegions() { - regions := make([]SRegion, 0, len(regionList)) - for id, name := range regionList { - region := SRegion{} - region.ID = id - region.Name = name - region.client = ec - regions = append(regions, region) - } - iregions := make([]cloudprovider.ICloudRegion, len(regions)) - for i := range iregions { - iregions[i] = ®ions[i] - } - ec.iregions = iregions - return -} - -func (ec *SEcloudClient) TryConnect() error { - iregions := ec.GetIRegions() - if len(iregions) == 0 { - return fmt.Errorf("no invalid region for ecloud") - } - _, err := iregions[0].GetIZones() - if err != nil { - return errors.Wrap(err, "try to connect failed") - } - return nil -} - -func (ec *SEcloudClient) GetIRegions() []cloudprovider.ICloudRegion { - if ec.iregions == nil { - ec.fetchRegions() - } - return ec.iregions -} - -func (ec *SEcloudClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - iregions := ec.GetIRegions() - for i := range iregions { - if iregions[i].GetGlobalId() == id { - return iregions[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (ec *SEcloudClient) GetRegionById(id string) (*SRegion, error) { - iregions := ec.GetIRegions() - for i := range iregions { - if iregions[i].GetId() == id { - return iregions[i].(*SRegion), nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (ec *SEcloudClient) GetCapabilities() []string { - caps := []string{ - cloudprovider.CLOUD_CAPABILITY_COMPUTE + cloudprovider.READ_ONLY_SUFFIX, - cloudprovider.CLOUD_CAPABILITY_NETWORK + cloudprovider.READ_ONLY_SUFFIX, - cloudprovider.CLOUD_CAPABILITY_EIP + cloudprovider.READ_ONLY_SUFFIX, - } - return caps -} - -func (ec *SEcloudClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - subAccount := cloudprovider.SSubAccount{} - subAccount.Name = ec.cpcfg.Name - subAccount.Account = ec.signer.GetAccessKeyId() - subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL - return []cloudprovider.SSubAccount{subAccount}, nil -} - -func (ec *SEcloudClient) GetAccountId() string { - return ec.signer.GetAccessKeyId() -} - -func (ec *SEcloudClient) GetCloudRegionExternalIdPrefix() string { - return CLOUD_PROVIDER_ECLOUD -} - -func (ec *SEcloudClient) completeSingParams(request IRequest) (err error) { - queryParams := request.GetQueryParams() - queryParams["AccessKey"] = ec.signer.GetAccessKeyId() - queryParams["Version"] = request.GetVersion() - queryParams["Timestamp"] = request.GetTimestamp() - queryParams["SignatureMethod"] = ec.signer.GetName() - queryParams["SignatureVersion"] = ec.signer.GetVersion() - queryParams["SignatureNonce"] = ec.signer.GetNonce() - return -} - -func (ec *SEcloudClient) buildStringToSign(request IRequest) string { - signParams := request.GetQueryParams() - queryString := getUrlFormedMap(signParams) - queryString = strings.Replace(queryString, "+", "%20", -1) - queryString = strings.Replace(queryString, "*", "%2A", -1) - queryString = strings.Replace(queryString, "%7E", "~", -1) - shaString := sha256.Sum256([]byte(queryString)) - summaryQuery := hex.EncodeToString(shaString[:]) - serverPath := strings.Replace(request.GetServerPath(), "/", "%2F", -1) - return fmt.Sprintf("%s\n%s\n%s", request.GetMethod(), serverPath, summaryQuery) -} - -func (ec *SEcloudClient) doGet(ctx context.Context, r IRequest, result interface{}) error { - r.SetMethod("GET") - data, err := ec.request(ctx, r) - if err != nil { - return err - } - return data.Unmarshal(result) -} - -func (ec *SEcloudClient) doList(ctx context.Context, r IRequest, result interface{}) error { - r.SetMethod("GET") - // TODO Paging query - data, err := ec.request(ctx, r) - if err != nil { - return err - } - var ( - datas *jsonutils.JSONArray - ok bool - ) - - if datas, ok = data.(*jsonutils.JSONArray); !ok { - if !data.Contains("content") { - return ErrMissKey{ - Key: "content", - Jo: data, - } - } - content, _ := data.Get("content") - datas, ok = content.(*jsonutils.JSONArray) - if !ok { - return fmt.Errorf("The return result should be an array, but:\n%s", content) - } - } - return datas.Unmarshal(result) -} - -func (ec *SEcloudClient) request(ctx context.Context, r IRequest) (jsonutils.JSONObject, error) { - jrbody, err := ec.doRequest(ctx, r) - if err != nil { - return nil, err - } - return r.ForMateResponseBody(jrbody) -} - -func (ec *SEcloudClient) doRequest(ctx context.Context, r IRequest) (jsonutils.JSONObject, error) { - // sign - ec.completeSingParams(r) - signature := ec.signer.Sign(ec.buildStringToSign(r), "BC_SIGNATURE&") - query := r.GetQueryParams() - query["Signature"] = signature - header := r.GetHeaders() - header["Content-Type"] = "application/json" - var urlStr string - port := r.GetPort() - if len(port) > 0 { - urlStr = fmt.Sprintf("%s://%s:%s%s", r.GetScheme(), r.GetEndpoint(), port, r.GetServerPath()) - } else { - urlStr = fmt.Sprintf("%s://%s%s", r.GetScheme(), r.GetEndpoint(), r.GetServerPath()) - } - queryString := getUrlFromedMapUnescaped(r.GetQueryParams()) - if len(queryString) > 0 { - urlStr = urlStr + "?" + queryString - } - resp, err := httputils.Request( - ec.httpClient, - ctx, - httputils.THttpMethod(r.GetMethod()), - urlStr, - convertHeader(header), - r.GetBodyReader(), - ec.debug, - ) - defer httputils.CloseResponse(resp) - if err != nil { - return nil, err - } - rbody, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, errors.Wrap(err, "unable to read body of response") - } - if ec.debug { - fmt.Fprintf(os.Stderr, "Response body: %s\n", string(rbody)) - } - rbody = bytes.TrimSpace(rbody) - - var jrbody jsonutils.JSONObject - if len(rbody) > 0 && (rbody[0] == '{' || rbody[0] == '[') { - var err error - jrbody, err = jsonutils.Parse(rbody) - if err != nil { - return nil, errors.Wrapf(err, "unable to parsing json: %s", rbody) - } - } - return jrbody, nil -} - -type ErrMissKey struct { - Key string - Jo jsonutils.JSONObject -} - -func (mk ErrMissKey) Error() string { - return fmt.Sprintf("The response body should contain the %q key, but it doesn't. It is:\n%s", mk.Key, mk.Jo) -} - -func convertHeader(mh map[string]string) http.Header { - header := http.Header{} - for k, v := range mh { - header.Add(k, v) - } - return header -} - -func getUrlFromedMapUnescaped(source map[string]string) string { - kvs := make([]string, 0, len(source)) - for k, v := range source { - kvs = append(kvs, fmt.Sprintf("%s=%s", k, v)) - } - return strings.Join(kvs, "&") -} - -func getUrlFormedMap(source map[string]string) (urlEncoded string) { - urlEncoder := url.Values{} - for key, value := range source { - urlEncoder.Add(key, value) - } - urlEncoded = urlEncoder.Encode() - return -} diff --git a/pkg/multicloud/ecloud/client_test.go b/pkg/multicloud/ecloud/client_test.go deleted file mode 100644 index 78494bdae1..0000000000 --- a/pkg/multicloud/ecloud/client_test.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "testing" -) - -type signerMock struct { - SRamRoleSigner -} - -func (s *signerMock) GetNonce() string { - return "9d81ffbeaaf7477390db5df577bb3299" -} - -type requestMock struct { - SBaseRequest -} - -func (r *requestMock) GetTimestamp() string { - return "2017-01-11T15:15:11Z" -} - -func TestBuildStringToSing(t *testing.T) { - signer := &signerMock{SRamRoleSigner: *NewRamRoleSigner("testid", "testsecret")} - client, _ := NewEcloudClient(NewEcloudClientConfig(signer)) - request := &requestMock{ - SBaseRequest: SBaseRequest{ - Method: "GET", - ServerPath: "/api/keypair", - QueryParams: map[string]string{}, - Headers: map[string]string{}, - Content: []byte{}, - }, - } - client.completeSingParams(request) - stringToSign := client.buildStringToSign(request) - want := `GET -%2Fapi%2Fkeypair -25fb697a06bc8a16a0a2549460f5cba35aded3818e15f088e4e17cd394aa07af` - if stringToSign != want { - t.Fatalf("want:\n%s, get:\n%s", want, stringToSign) - } -} diff --git a/pkg/multicloud/ecloud/disk.go b/pkg/multicloud/ecloud/disk.go deleted file mode 100644 index fb9131e221..0000000000 --- a/pkg/multicloud/ecloud/disk.go +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "context" - "fmt" - "time" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDisk struct { - storage *SStorage - // TODO instance - - multicloud.SDisk - multicloud.EcloudTags - multicloud.SBillingBase - SZoneRegionBase - SCreateTime - - ManualAttr SDiskManualAttr - - // 硬盘可挂载主机类型 - AttachServerTypes []string - AvailabilityZone string - BackupId string - Description string - ID string - IsDelete bool - IsShare bool - // 磁盘所在集群的ID - Metadata string - Name string - OperationFlag string - // 硬盘挂在主机ID列表 - ServerId []string - SizeGB int `json:"size"` - SourceVolumeId string - Status string - Type string - VolumeType string - Iscsi bool - ProductType string -} - -type SDiskManualAttr struct { - IsVirtual bool - TempalteId string - ServerId string -} - -func (d *SDisk) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (d *SDisk) GetExpiredAt() time.Time { - return time.Time{} -} - -func (d *SDisk) GetId() string { - return d.ID -} - -func (d *SDisk) GetName() string { - return d.Name -} - -func (d *SDisk) GetGlobalId() string { - return d.ID -} - -func (d *SDisk) GetCreatedAt() time.Time { - return d.SCreateTime.GetCreatedAt() -} - -func (d *SDisk) GetStatus() string { - if d.IsDelete { - // TODO - return "" - } - switch d.Status { - case "available", "in-use": - return api.DISK_READY - case "attaching": - return api.DISK_ATTACHING - case "backing_up": - return api.DISK_BACKUP_STARTALLOC - case "creating", "downloading": - return api.DISK_ALLOCATING - case "deleting": - return api.DISK_DEALLOC - case "uploading": - return api.DISK_SAVING - case "error": - return api.DISK_ALLOC_FAILED - case "error_deleting": - return api.DISK_DEALLOC_FAILED - case "restoring_backup": - return api.DISK_REBUILD - case "detaching": - return api.DISK_DETACHING - case "extending": - return api.DISK_RESIZING - case "error_extending": - return api.DISK_RESIZE_FAILED - case "error_restoring", "unrecognized": - return api.DISK_UNKNOWN - default: - return api.DISK_UNKNOWN - } -} - -func (d *SDisk) Refresh() error { - return nil -} - -func (d *SDisk) IsEmulated() bool { - return false -} - -func (s *SDisk) GetSysTags() map[string]string { - data := map[string]string{} - data["hypervisor"] = api.HYPERVISOR_ECLOUD - return data -} - -func (s *SDisk) GetProjectId() string { - return "" -} - -func (s *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return s.storage, nil -} - -func (s *SDisk) GetDiskFormat() string { - return "vhd" -} - -func (s *SDisk) GetDiskSizeMB() int { - return s.SizeGB * 1024 -} - -func (s *SDisk) GetIsAutoDelete() bool { - if s.GetDiskType() == api.DISK_TYPE_SYS { - return true - } - return false -} - -func (s *SDisk) GetTemplateId() string { - return s.ManualAttr.TempalteId -} - -func (s *SDisk) GetDiskType() string { - if s.ManualAttr.IsVirtual { - return api.DISK_TYPE_SYS - } - return api.DISK_TYPE_DATA -} - -func (s *SDisk) GetFsFormat() string { - return "" -} - -func (s *SDisk) GetIsNonPersistent() bool { - return false -} - -func (s *SDisk) GetDriver() string { - return "scsi" -} - -func (s *SDisk) GetCacheMode() string { - return "none" -} - -func (s *SDisk) GetMountpoint() string { - return "" -} - -func (s *SDisk) GetAccessPath() string { - return "" -} - -func (s *SDisk) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (s *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (s *SDisk) GetISnapshot(id string) (cloudprovider.ICloudSnapshot, error) { - parentId, isSystem := s.ID, false - if s.ManualAttr.IsVirtual { - parentId, isSystem = s.ManualAttr.ServerId, true - } - snapshots, err := s.storage.zone.region.GetSnapshots(id, parentId, isSystem) - if err != nil { - return nil, err - } - if len(snapshots) == 0 { - return nil, cloudprovider.ErrNotFound - } - return &snapshots[0], nil -} - -func (s *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - parentId, isSystem := s.ID, false - if s.ManualAttr.IsVirtual { - parentId, isSystem = s.ManualAttr.ServerId, true - } - snapshots, err := s.storage.zone.region.GetSnapshots("", parentId, isSystem) - if err != nil { - return nil, err - } - isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) - for i := range snapshots { - isnapshots[i] = &snapshots[i] - } - return isnapshots, nil -} - -func (s *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { - return []string{}, nil -} - -func (s *SDisk) Resize(ctx context.Context, newSizeMB int64) error { - return cloudprovider.ErrNotImplemented -} - -func (s *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", cloudprovider.ErrNotImplemented -} - -func (s *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (s *SRegion) GetDisks() ([]SDisk, error) { - request := NewNovaRequest(NewApiRequest(s.ID, "/api/v2/volume/volume/volume/list/with/server", nil, nil)) - disks := make([]SDisk, 0, 5) - err := s.client.doList(context.Background(), request, &disks) - if err != nil { - return nil, err - } - return disks, nil -} - -func (s *SRegion) GetDisk(id string) (*SDisk, error) { - // TODO - request := NewNovaRequest(NewApiRequest(s.ID, fmt.Sprintf("/api/v2/volume/volume/volumeDetail/%s", id), nil, nil)) - var disk SDisk - err := s.client.doGet(context.Background(), request, &disk) - if err != nil { - return nil, err - } - return &disk, nil -} diff --git a/pkg/multicloud/ecloud/doc.go b/pkg/multicloud/ecloud/doc.go deleted file mode 100644 index 90f7091b10..0000000000 --- a/pkg/multicloud/ecloud/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud // import "yunion.io/x/onecloud/pkg/multicloud/ecloud" diff --git a/pkg/multicloud/ecloud/eip.go b/pkg/multicloud/ecloud/eip.go deleted file mode 100644 index 53ef87f429..0000000000 --- a/pkg/multicloud/ecloud/eip.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "context" - "fmt" - "time" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SEip struct { - region *SRegion - multicloud.SEipBase - multicloud.EcloudTags - - BandWidthMbSize int - BandWidthType string - BindType string - // 使用,未使用 - Bound bool - // bandwidthCharge, trafficCharge - ChargeModeEnum string - CreateTime time.Time - Frozen bool - // 备案状态 - IcpStatus string - Id string - IpType string - Ipv6 string - Name string //公网IPv4地址 - NicName string - PortNetworkId string - Region string - ResourceId string - RouterId string - // BINDING, UNBOUND, FROZEN - Status string -} - -func (e *SEip) GetId() string { - return e.Id -} - -func (e *SEip) GetName() string { - return e.Name -} - -func (e *SEip) GetGlobalId() string { - return e.Id -} - -func (e *SEip) GetStatus() string { - switch e.Status { - case "BINDING", "UNBOUND": - return api.EIP_STATUS_READY - default: - return api.EIP_STATUS_UNKNOWN - } -} - -func (e *SEip) Refresh() error { - return cloudprovider.ErrNotImplemented -} - -func (e *SEip) IsEmulated() bool { - return false -} - -func (e *SEip) GetIpAddr() string { - return e.Name -} - -func (e *SEip) GetMode() string { - return api.EIP_MODE_STANDALONE_EIP -} - -func (e *SEip) GetAssociationType() string { - switch e.BindType { - case "vm": - return api.EIP_ASSOCIATE_TYPE_SERVER - case "snat", "dnat": - return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY - case "elb": - return api.EIP_ASSOCIATE_TYPE_LOADBALANCER - default: - return e.BindType - } -} - -func (e *SEip) GetAssociationExternalId() string { - return e.ResourceId -} - -func (e *SEip) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (e *SEip) GetCreatedAt() time.Time { - return e.CreateTime -} - -func (e *SEip) GetExpiredAt() time.Time { - return time.Time{} -} - -func (e *SEip) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (e *SEip) GetBandwidth() int { - return e.BandWidthMbSize -} - -func (e *SEip) GetINetworkId() string { - return e.PortNetworkId -} - -func (e *SEip) GetInternetChargeType() string { - switch e.ChargeModeEnum { - // bandwidthCharge, trafficCharge - case "trafficCharge": - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - case "bandwidthCharge": - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH - default: - return "unknown" - } -} - -func (e *SEip) Associate(conf *cloudprovider.AssociateConfig) error { - return cloudprovider.ErrNotImplemented -} - -func (e *SEip) Dissociate() error { - return cloudprovider.ErrNotImplemented -} - -func (e *SEip) ChangeBandwidth(bw int) error { - return cloudprovider.ErrNotImplemented -} - -func (e *SEip) GetProjectId() string { - return "" -} - -func (r *SRegion) GetEipById(id string) (*SEip, error) { - var eip SEip - request := NewConsoleRequest(r.ID, fmt.Sprintf("/api/v2/floatingIp/getRespWithBw/%s", id), nil, nil) - err := r.client.doGet(context.Background(), request, &eip) - if err != nil { - return nil, err - } - return &eip, nil -} diff --git a/pkg/multicloud/ecloud/host.go b/pkg/multicloud/ecloud/host.go deleted file mode 100644 index b58f2f82b2..0000000000 --- a/pkg/multicloud/ecloud/host.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone -} - -func (h *SHost) GetId() string { - return fmt.Sprintf("%s-%s", h.zone.region.client.cpcfg.Id, h.zone.GetId()) -} - -func (h *SHost) GetName() string { - return fmt.Sprintf("%s-%s", h.zone.region.client.cpcfg.Name, h.zone.GetId()) -} - -func (h *SHost) GetGlobalId() string { - return h.GetId() -} - -func (h *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (h *SHost) Refresh() error { - return nil -} - -func (h *SHost) IsEmulated() bool { - return true -} - -func (h *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - zoneRegion := h.zone.Region - vms, err := h.zone.region.GetInstances(zoneRegion) - if err != nil { - return nil, errors.Wrap(err, "SHost.GetVMs") - } - ivms := make([]cloudprovider.ICloudVM, len(vms)) - for i := range vms { - vms[i].host = h - ivms[i] = &vms[i] - } - return ivms, nil -} - -func (h *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := h.zone.region.GetInstanceById(id) - if err != nil { - return nil, err - } - vm.host = h - return vm, nil -} - -func (h *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - return nil, nil -} - -func (h *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - return h.zone.GetIStorages() -} - -func (h *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return h.zone.GetIStorageById(id) -} - -func (h *SHost) GetEnabled() bool { - return true -} - -func (h *SHost) GetHostStatus() string { - return api.HOST_ONLINE -} - -func (h *SHost) GetAccessIp() string { - return "" -} - -func (h *SHost) GetAccessMac() string { - return "" -} - -func (h *SHost) GetSysInfo() jsonutils.JSONObject { - info := jsonutils.NewDict() - info.Add(jsonutils.NewString(api.CLOUD_PROVIDER_ECLOUD), "manufacture") - return info -} - -func (h *SHost) GetSN() string { - return "" -} - -func (h *SHost) GetCpuCount() int { - return 0 -} - -func (h *SHost) GetNodeCount() int8 { - return 0 -} - -func (h *SHost) GetCpuDesc() string { - return "" -} - -func (h *SHost) GetCpuMhz() int { - return 0 -} - -func (h *SHost) GetMemSizeMB() int { - return 0 -} - -func (h *SHost) GetStorageSizeMB() int { - return 0 -} - -func (h *SHost) GetStorageType() string { - return api.DISK_TYPE_HYBRID -} - -func (h *SHost) GetHostType() string { - return api.HOST_TYPE_ECLOUD -} - -func (h *SHost) GetIsMaintenance() bool { - return false -} - -func (h *SHost) GetVersion() string { - return CLOUD_API_VERSION -} - -func (h *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (h *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (h *SRegion) GetVMs() ([]SInstance, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (h *SRegion) GetVMById(vmId string) (*SInstance, error) { - return nil, cloudprovider.ErrNotImplemented -} diff --git a/pkg/multicloud/ecloud/image.go b/pkg/multicloud/ecloud/image.go deleted file mode 100644 index 3e2218d608..0000000000 --- a/pkg/multicloud/ecloud/image.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type SImage struct { - multicloud.SImageBase - multicloud.EcloudTags - SZoneRegionBase - - storageCache *SStoragecache - imgInfo *imagetools.ImageInfo - - ImageId string - ServerId string - ImageAlias string - Name string - Url string - SrourceImageId string - Status string - SizeMb int `json:"size"` - IsPublic int - CreateTime time.Time - Note string - OsType string - MinDiskGB int `json:"minDisk"` - ImageType string - PublicImageType string - BackupType string - BackupWay string - SnapshotId string - OsName string -} - -func (r *SRegion) GetImage(imageId string) (*SImage, error) { - request := NewNovaRequest(NewApiRequest(r.ID, fmt.Sprintf("/api/v2/image/%s", imageId), nil, nil)) - var image SImage - err := r.client.doGet(context.Background(), request, &image) - if err != nil { - return nil, err - } - return &image, nil -} - -func (r *SRegion) GetImages(isPublic bool) ([]SImage, error) { - if isPublic { - return nil, cloudprovider.ErrNotImplemented - } - request := NewNovaRequest(NewApiRequest(r.ID, "/api/v2/image", nil, nil)) - images := make([]SImage, 0, 5) - err := r.client.doList(context.Background(), request, &images) - if err != nil { - return nil, err - } - return images, nil -} - -func (i *SImage) GetCreatedAt() time.Time { - return i.CreateTime -} - -func (i *SImage) GetId() string { - return i.ImageId -} - -func (i *SImage) GetName() string { - return i.Name -} - -func (i *SImage) GetGlobalId() string { - return i.ImageId -} - -func (i *SImage) GetStatus() string { - switch i.Status { - case "active": - return api.CACHED_IMAGE_STATUS_ACTIVE - case "queued": - return api.CACHED_IMAGE_STATUS_INIT - case "saving": - return api.CACHED_IMAGE_STATUS_SAVING - case "caching": - return api.CACHED_IMAGE_STATUS_CACHING - case "pending_delete": - return api.CACHED_IMAGE_STATUS_DELETING - default: - return api.CACHED_IMAGE_STATUS_UNKNOWN - } -} - -func (i *SImage) Refresh() error { - new, err := i.storageCache.region.GetImage(i.GetId()) - if err != nil { - return err - } - return jsonutils.Update(i, new) -} - -func (i *SImage) IsEmulated() bool { - return false -} - -func (i *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if i.imgInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(i.OsName, "", i.OsType, "", "") - i.imgInfo = &imgInfo - } - return i.imgInfo -} - -func (i *SImage) GetFullOsName() string { - return i.OsName -} - -func (i *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(i.getNormalizedImageInfo().OsType) -} - -func (i *SImage) GetOsArch() string { - return i.getNormalizedImageInfo().OsArch -} - -func (i *SImage) GetOsDist() string { - return i.getNormalizedImageInfo().OsDistro -} - -func (i *SImage) GetOsVersion() string { - return i.getNormalizedImageInfo().OsVersion -} - -func (i *SImage) GetOsLang() string { - return i.getNormalizedImageInfo().OsLang -} - -func (i *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(i.getNormalizedImageInfo().OsBios) -} - -func (i *SImage) GetMinOsDiskSizeGb() int { - return i.MinDiskGB -} - -func (i *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (i *SImage) GetImageFormat() string { - return "" -} - -func (self *SImage) Delete(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return nil -} - -func (self *SImage) GetSizeByte() int64 { - return int64(self.SizeMb) * 1024 * 1024 -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - if self.IsPublic == 1 { - return cloudprovider.ImageTypeSystem - } - return cloudprovider.ImageTypeCustomized -} - -func (self *SImage) GetImageStatus() string { - return cloudprovider.IMAGE_STATUS_ACTIVE -} diff --git a/pkg/multicloud/ecloud/instance.go b/pkg/multicloud/ecloud/instance.go deleted file mode 100644 index 20cd1ca5e1..0000000000 --- a/pkg/multicloud/ecloud/instance.go +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/sets" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SNovaRequest struct { - SApiRequest -} - -func NewNovaRequest(ar *SApiRequest) *SNovaRequest { - return &SNovaRequest{ - SApiRequest: *ar, - } -} - -func (nr *SNovaRequest) GetPort() string { - if nr.RegionId == "guangzhou-2" { - return "" - } - return nr.SApiRequest.GetPort() -} - -type SInstance struct { - multicloud.SInstanceBase - multicloud.EcloudTags - multicloud.SBillingBase - SZoneRegionBase - SCreateTime - - nicComplete bool - host *SHost - image *SImage - - sysDisk cloudprovider.ICloudDisk - dataDisks []cloudprovider.ICloudDisk - - Id string - Name string - Vcpu int - Vmemory int - KeyName string - ImageRef string - ImageName string - ImageOsType string - FlavorRef string - SystemDiskSizeGB int `json:"vdisk"` - SystemDiskId string - ServerType string - ServerVmType string - EcStatus string - BootVolumeType string - Deleted int - Visible bool - Region string - PortDetail []SInstanceNic -} - -func (i *SInstance) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (i *SInstance) GetExpiredAt() time.Time { - return time.Time{} -} - -func (i *SInstance) GetId() string { - return i.Id -} - -func (i *SInstance) GetName() string { - return i.Name -} - -func (i *SInstance) GetHostname() string { - return i.Name -} - -func (i *SInstance) GetGlobalId() string { - return i.GetId() -} - -func (i *SInstance) GetStatus() string { - switch i.EcStatus { - case "active": - return api.VM_RUNNING - case "suspended", "paused": - return api.VM_SUSPEND - case "build", "rebuild", "resize", "verify_resize", "revert_resize", "password": - return api.VM_STARTING - case "reboot", "hard_reboot": - return api.VM_STOPPING - case "stopped", "shutoff": - return api.VM_READY - case "migrating": - return api.VM_MIGRATING - case "backuping": - return api.VM_BACKUP_CREATING - default: - return api.VM_UNKNOWN - } -} - -func (i *SInstance) Refresh() error { - // TODO - return nil -} - -func (i *SInstance) IsEmulated() bool { - return false -} - -func (self *SInstance) GetBootOrder() string { - return "dcn" -} - -func (self *SInstance) GetVga() string { - return "std" -} - -func (self *SInstance) GetVdi() string { - return "vnc" -} - -func (i *SInstance) GetImage() (*SImage, error) { - if i.image != nil { - return i.image, nil - } - image, err := i.host.zone.region.GetImage(i.ImageRef) - if err != nil { - return nil, err - } - i.image = image - return i.image, nil -} - -func (i *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(i.ImageOsType) -} - -func (i *SInstance) GetFullOsName() string { - image, err := i.GetImage() - if err != nil { - return "" - } - return image.GetFullOsName() -} - -func (i *SInstance) GetBios() cloudprovider.TBiosType { - image, err := i.GetImage() - if err != nil { - return cloudprovider.BIOS - } - return image.GetBios() -} - -func (i *SInstance) GetOsArch() string { - image, err := i.GetImage() - if err != nil { - return "" - } - return image.GetOsArch() -} - -func (i *SInstance) GetOsDist() string { - image, err := i.GetImage() - if err != nil { - return "" - } - return image.GetOsDist() -} - -func (i *SInstance) GetOsVersion() string { - image, err := i.GetImage() - if err != nil { - return "" - } - return image.GetOsVersion() -} - -func (i *SInstance) GetOsLang() string { - image, err := i.GetImage() - if err != nil { - return "" - } - return image.GetOsLang() -} - -func (i *SInstance) GetMachine() string { - return "pc" -} - -func (i *SInstance) GetInstanceType() string { - return i.FlavorRef -} - -func (in *SInstance) GetProjectId() string { - return "" -} - -func (in *SInstance) GetIHost() cloudprovider.ICloudHost { - return in.host -} - -func (in *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - if in.sysDisk == nil { - in.fetchSysDisk() - } - if in.dataDisks == nil { - err := in.fetchDataDisks() - if err != nil { - return nil, err - } - } - return append([]cloudprovider.ICloudDisk{in.sysDisk}, in.dataDisks...), nil -} - -func (in *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - if !in.nicComplete { - err := in.makeNicComplete() - if err != nil { - return nil, errors.Wrap(err, "unable to make nics complete") - } - in.nicComplete = true - } - inics := make([]cloudprovider.ICloudNic, len(in.PortDetail)) - for i := range in.PortDetail { - in.PortDetail[i].instance = in - inics[i] = &in.PortDetail[i] - } - return inics, nil -} - -func (in *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - if !in.nicComplete { - err := in.makeNicComplete() - if err != nil { - return nil, errors.Wrap(err, "unable to make nics complete") - } - in.nicComplete = true - } - var eipId string - for i := range in.PortDetail { - if len(in.PortDetail[i].IpId) > 0 { - eipId = in.PortDetail[i].IpId - break - } - } - if len(eipId) == 0 { - return nil, nil - } - return in.host.zone.region.GetEipById(eipId) -} - -func (in *SInstance) GetSecurityGroupIds() ([]string, error) { - if !in.nicComplete { - err := in.makeNicComplete() - if err != nil { - return nil, errors.Wrap(err, "unable to make nics complete") - } - in.nicComplete = true - } - ret := sets.NewString() - for i := range in.PortDetail { - for _, group := range in.PortDetail[i].SecurityGroups { - ret.Insert(group.Id) - } - } - return ret.UnsortedList(), nil -} - -func (in *SInstance) GetVcpuCount() int { - return in.Vcpu -} - -func (in *SInstance) GetVmemSizeMB() int { - return in.Vmemory -} - -func (in *SInstance) AssignSecurityGroup(id string) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) SetSecurityGroups(ids []string) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) GetHypervisor() string { - return api.HYPERVISOR_ECLOUD -} - -func (in *SInstance) StartVM(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - return "", cloudprovider.ErrNotImplemented -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - return errors.ErrNotImplemented -} - -func (in *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - url, err := in.host.zone.region.GetInstanceVNCUrl(in.GetId()) - if err != nil { - return nil, err - } - ret := &cloudprovider.ServerVncOutput{ - Url: url, - Protocol: "ecloud", - InstanceId: in.GetId(), - Hypervisor: api.HYPERVISOR_ECLOUD, - } - return ret, nil -} - -func (in *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) GetError() error { - return nil -} - -func (in *SInstance) fetchSysDisk() { - storage, _ := in.host.zone.getStorageByType(api.STORAGE_ECLOUD_SYSTEM) - disk := SDisk{ - storage: storage, - ManualAttr: SDiskManualAttr{ - IsVirtual: true, - TempalteId: in.ImageRef, - ServerId: in.Id, - }, - SCreateTime: in.SCreateTime, - SZoneRegionBase: in.SZoneRegionBase, - ServerId: []string{in.Id}, - IsShare: false, - IsDelete: false, - SizeGB: in.SystemDiskSizeGB, - ID: in.SystemDiskId, - Name: fmt.Sprintf("%s-root", in.Name), - Status: "in-use", - Type: api.STORAGE_ECLOUD_SYSTEM, - } - in.sysDisk = &disk - return -} - -func (in *SInstance) fetchDataDisks() error { - request := NewNovaRequest(NewApiRequest(in.host.zone.region.ID, "/api/v2/volume/volume/mount/list", - map[string]string{"serverId": in.Id}, nil)) - disks := make([]SDisk, 0, 5) - err := in.host.zone.region.client.doList(context.Background(), request, &disks) - if err != nil { - return err - } - idisks := make([]cloudprovider.ICloudDisk, len(disks)) - for i := range idisks { - storageType := disks[i].Type - storage, err := in.host.zone.getStorageByType(storageType) - if err != nil { - return errors.Wrapf(err, "unable to fetch storage with stoageType %s", storageType) - } - disks[i].storage = storage - idisks[i] = &disks[i] - } - in.dataDisks = idisks - return nil -} - -func (in *SInstance) makeNicComplete() error { - routerIds := sets.NewString() - nics := make(map[string]*SInstanceNic, len(in.PortDetail)) - for i := range in.PortDetail { - nic := &in.PortDetail[i] - routerIds.Insert(nic.RouterId) - nics[nic.PortId] = nic - } - for _, routerId := range routerIds.UnsortedList() { - request := NewConsoleRequest(in.host.zone.region.ID, fmt.Sprintf("/api/vpc/%s/nic", routerId), - map[string]string{ - "resourceId": in.Id, - }, nil, - ) - completeNics := make([]SInstanceNic, 0, len(nics)/2) - err := in.host.zone.region.client.doList(context.Background(), request, &completeNics) - if err != nil { - return errors.Wrapf(err, "unable to get nics with instance %s in vpc %s", in.Id, routerId) - } - for i := range completeNics { - id := completeNics[i].Id - nic, ok := nics[id] - if !ok { - continue - } - nic.SInstanceNicDetail = completeNics[i].SInstanceNicDetail - } - } - return nil -} - -func (r *SRegion) findHost(zoneRegion string) (*SHost, error) { - zone, err := r.FindZone(zoneRegion) - if err != nil { - return nil, err - } - return &SHost{ - zone: zone, - }, nil -} - -func (r *SRegion) GetInstancesWithHost(zoneRegion string) ([]SInstance, error) { - instances, err := r.GetInstances(zoneRegion) - if err != nil { - return nil, err - } - for i := range instances { - host, _ := r.findHost(instances[i].Region) - instances[i].host = host - } - return instances, nil -} - -func (r *SRegion) GetInstances(zoneRegion string) ([]SInstance, error) { - return r.getInstances(zoneRegion, "") -} - -func (r *SRegion) getInstances(zoneRegion string, serverId string) ([]SInstance, error) { - query := map[string]string{ - "serverTypes": "VM", - "productTypes": "NORMAL,AUTOSCALING,VO,CDN,PAAS_MASTER,PAAS_SLAVE,VCPE,EMR,LOGAUDIT", - //"productTypes": "NORMAL", - "visible": "true", - } - if len(serverId) > 0 { - query["serverId"] = serverId - } - if len(zoneRegion) > 0 { - query["region"] = zoneRegion - } - request := NewNovaRequest(NewApiRequest(r.ID, "/api/v2/server/web/with/network", query, nil)) - var instances []SInstance - err := r.client.doList(context.Background(), request, &instances) - if err != nil { - return nil, err - } - return instances, nil -} - -func (r *SRegion) GetInstanceById(id string) (*SInstance, error) { - instances, err := r.getInstances("", id) - if err != nil { - return nil, err - } - if len(instances) == 0 { - return nil, cloudprovider.ErrNotFound - } - instance := &instances[0] - host, err := r.findHost(instance.Region) - if err == nil { - instance.host = host - } - return instance, nil -} - -func (r *SRegion) GetInstanceVNCUrl(instanceId string) (string, error) { - request := NewNovaRequest(NewApiRequest(r.ID, fmt.Sprintf("/api/server/%s/vnc", instanceId), nil, nil)) - var url string - err := r.client.doGet(context.Background(), request, &url) - if err != nil { - return "", err - } - return url, nil -} diff --git a/pkg/multicloud/ecloud/instancenic.go b/pkg/multicloud/ecloud/instancenic.go deleted file mode 100644 index 2e10c09fcc..0000000000 --- a/pkg/multicloud/ecloud/instancenic.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "time" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - cloudprovider.DummyICloudNic - SInstanceNicDetail - - instance *SInstance - - Id string - PrivateIp string - FipAddress string - FipBandwidthSize int - PortId string - PortName string - FixedIpDetails []SFixedIpDetail - RouterId string -} - -type SInstanceNicDetail struct { - MacAddress string - SecurityGroups []SSecurityGroupRef - Status int - ResourceId string - CreaetTime time.Time - PublicIp string - IpId string - NetworkId string -} - -type SSecurityGroupRef struct { - Id string - Name string -} - -type SFixedIpDetail struct { - IpAddress string - IpVersion string - PublicIp string - BandWidthSize int - BandWidthType string - SubnetId string - SubnetName string -} - -func (in *SInstanceNic) GetIP() string { - return in.PrivateIp -} - -func (in *SInstanceNic) GetMAC() string { - return in.MacAddress -} - -func (in *SInstanceNic) GetId() string { - return in.PortId -} - -func (in *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (in *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (in *SInstanceNic) GetINetworkId() string { - return in.NetworkId -} diff --git a/pkg/multicloud/ecloud/latitud_and_longitude.go b/pkg/multicloud/ecloud/latitud_and_longitude.go deleted file mode 100644 index 6797926571..0000000000 --- a/pkg/multicloud/ecloud/latitud_and_longitude.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ - "guangzhou-2": {Latitude: 23.129110, Longitude: 113.264381, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "beijing-1": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, - "hunan-1": {Latitude: 28.2277765095, Longitude: 112.9388453666, City: api.CITY_CHANG_SHA, CountryCode: api.COUNTRY_CODE_CN}, - "wuxi-1": {Latitude: 31.2983479333, Longitude: 120.5831894861, City: api.CITY_SU_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "dongguan-1": {Latitude: 23.129110, Longitude: 113.264381, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "yaan-1": {Latitude: 30.572815, Longitude: 104.066803, City: api.CITY_CHENG_DU, CountryCode: api.COUNTRY_CODE_CN}, - "zhengzhou-1": {Latitude: 34.7533581487, Longitude: 113.6313915479, City: api.CITY_ZHENG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "beijing-2": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, - "zhuzhou-1": {Latitude: 28.2277765095, Longitude: 112.9388453666, City: api.CITY_CHANG_SHA, CountryCode: api.COUNTRY_CODE_CN}, - "jinan-1": {Latitude: 36.64889911073425, Longitude: 117.11905617575435, City: api.CITY_JI_NAM, CountryCode: api.COUNTRY_CODE_CN}, - "xian-1": {Latitude: 34.3412614674, Longitude: 108.9398165260, City: api.CITY_XI_AN, CountryCode: api.COUNTRY_CODE_CN}, - "shanghai-1": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "chongqing-1": {Latitude: 29.431585, Longitude: 106.912254, City: api.CITY_CHONG_QING, CountryCode: api.COUNTRY_CODE_CN}, - "ningbo-1": {Latitude: 30.274084, Longitude: 120.155067, City: api.CITY_HANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "tianjin-1": {Latitude: 39.0850853357, Longitude: 117.1993482089, City: api.CITY_TIAN_JIN, CountryCode: api.COUNTRY_CODE_CN}, - "jilin-1": {Latitude: 43.87120919729674, Longitude: 125.3111129463539, City: api.CITY_CHANG_CHUN, CountryCode: api.COUNTRY_CODE_CN}, - "hubei-1": {Latitude: 32.009075721852206, Longitude: 112.13485327119795, City: api.CITY_XIANG_YANG, CountryCode: api.COUNTRY_CODE_CN}, - "jiangxi-1": {Latitude: 28.66278309381472, Longitude: 115.82816199879247, City: api.CITY_NAN_CHANG, CountryCode: api.COUNTRY_CODE_CN}, - "gansu-1": {Latitude: 36.0613769373, Longitude: 103.8341600069, City: api.CITY_LAN_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "shanxi-1": {Latitude: 37.8705857132, Longitude: 112.5506634865, City: api.CITY_TAI_YUAN, CountryCode: api.COUNTRY_CODE_CN}, - "liaoning-1": {Latitude: 41.78937667917192, Longitude: 123.43099727316815, City: api.CITY_SHEN_YANG, CountryCode: api.COUNTRY_CODE_CN}, - "yunnan-2": {Latitude: 24.8796595146, Longitude: 102.8332118852, City: api.CITY_KUN_MING, CountryCode: api.COUNTRY_CODE_CN}, - "hebei-1": {Latitude: 38.044044256466684, Longitude: 114.50225031469532, City: api.CITY_SHI_JIA_ZHUANG, CountryCode: api.COUNTRY_CODE_CN}, - "fujian-1": {Latitude: 24.478556505708365, Longitude: 118.0875755539503, City: api.CITY_XIA_MEN, CountryCode: api.COUNTRY_CODE_CN}, - "guangxi-1": {Latitude: 22.8167372565, Longitude: 108.3669005333, City: api.CITY_NAN_NING, CountryCode: api.COUNTRY_CODE_CN}, - "anhui-1": {Latitude: 32.62657438299575, Longitude: 116.99779954519057, City: api.CITY_HUAI_NAN, CountryCode: api.COUNTRY_CODE_CN}, - "huhehaote-1": {Latitude: 40.842358, Longitude: 111.749992, City: api.CITY_HU_HE_HAO_TE, CountryCode: api.COUNTRY_CODE_CN}, - "guiyang-1": {Latitude: 26.6470035286, Longitude: 106.6302113880, City: api.CITY_GUI_YANG, CountryCode: api.COUNTRY_CODE_CN}, -} diff --git a/pkg/multicloud/ecloud/monitor.go b/pkg/multicloud/ecloud/monitor.go deleted file mode 100644 index ea6c7154df..0000000000 --- a/pkg/multicloud/ecloud/monitor.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "context" - "strconv" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/timeutils" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" -) - -const ( - MONITOR_FETCH_REQUEST_ACTION = "v1.dawn.monitor.fetch" - MONITOR_PRODUCT_REQUEST_ACTION = "v1.dawn.monitor.products" - - MONITOR_FETCH_SERVER_PATH = "/api/edw/edw/api" - - REQUEST_SUCCESS_CODE = "000000" -) - -var ( - noMetricRegion = []string{"guangzhou-2", "beijing-1", "hunan-1"} - - portRegionMap = map[string][]string{ - "8443": {"wuxi-1", "dongguan-1", "yaan-1", "zhengzhou-1", "beijing-2", "zhuzhou-1", "jinan-1", - "xian-1", "shanghai-1", "chongqing-1", "ningbo-1"}, - "18080": {"tianjin-1", "jilin-1", "hubei-1", "jiangxi-1", "gansu-1", "shanxi-1", "liaoning-1", - "yunnan-2", "hebei-1", "fujian-1", "guangxi-1", "anhui-1", "huhehaote-1", "guiyang-1"}, - } -) - -type Metric struct { - Name string `json:"MetricName"` -} - -type MetricData struct { - Entitys []Entity `json:"entity"` -} - -type Entity struct { - ResourceID string `json:"resourceId"` - MetricName string `json:"metricName"` - MetricNameCN string `json:"metricNameCn"` - Unit string `json:"unit"` - MaxValue int64 `json:"maxValue"` - AvgValue int64 `json:"avgValue"` - MinValue int64 `json:"minValue"` - Granularity string `json:"granularity"` - PolymerizeType string `json:"polymerizeType"` - SelectedMetricItem interface{} `json:"selectedMetricItem"` - MetricItems interface{} `json:"metricItems"` - IsChildnode bool `json:"isChildnode"` - Datapoints []Datapoint `json:"datapoints"` -} - -type Datapoint []string - -type SMonitorRequest struct { - SApiRequest -} - -func NewMonitorRequest(regionId string, serverPath string, query map[string]string, data jsonutils.JSONObject) *SMonitorRequest { - apiRequest := NewApiRequest(regionId, serverPath, query, data) - return &SMonitorRequest{*apiRequest} -} - -func (rr *SMonitorRequest) GetPort() string { - for port, regions := range portRegionMap { - if utils.IsInStringArray(rr.GetRegionId(), regions) { - return port - } - } - return "8443" -} - -func (br *SMonitorRequest) ForMateResponseBody(jrbody jsonutils.JSONObject) (jsonutils.JSONObject, error) { - code, _ := jrbody.GetString("code") - if code != REQUEST_SUCCESS_CODE { - message, _ := jrbody.(*jsonutils.JSONDict).GetString("message") - return nil, httperrors.NewBadRequestError("rep body code is :%s, message:%s,body:%v", code, message, jrbody) - } - if jrbody == nil || !jrbody.Contains("entity") { - return nil, ErrMissKey{ - Key: "entity", - Jo: jrbody, - } - } - return jrbody, nil -} - -func (self *SEcloudClient) DescribeMetricList(regionId, productType string, metrics []Metric, resourceId string, - since time.Time, until time.Time) (MetricData, error) { - metricData := MetricData{ - Entitys: make([]Entity, 0), - } - params := map[string]string{ - "eAction": MONITOR_FETCH_REQUEST_ACTION, - } - getBody := jsonutils.NewDict() - getBody.Set("startTime", jsonutils.NewString(since.Format(timeutils.MysqlTimeFormat))) - getBody.Set("endTime", jsonutils.NewString(until.Format(timeutils.MysqlTimeFormat))) - getBody.Set("productType", jsonutils.NewString(productType)) - getBody.Set("resourceId", jsonutils.NewString(resourceId)) - getBody.Set("metrics", jsonutils.Marshal(&metrics)) - request := NewMonitorRequest(regionId, MONITOR_FETCH_SERVER_PATH, params, getBody) - err := self.doGet(context.Background(), request, &metricData) - if err != nil { - return metricData, errors.Wrap(err, "client doGet error") - } - return metricData, nil -} - -func (r *SRegion) GetProductTypes() (jsonutils.JSONObject, error) { - params := map[string]string{ - "eAction": MONITOR_PRODUCT_REQUEST_ACTION, - } - request := NewMonitorRequest(r.ID, MONITOR_FETCH_SERVER_PATH, params, nil) - rtn := jsonutils.NewDict() - err := r.client.doGet(context.Background(), request, rtn) - if err != nil { - return nil, errors.Wrap(err, "client doGet error") - } - return rtn, nil -} - -func (self *SEcloudClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) - } -} - -func (self *SEcloudClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metrics := map[string]cloudprovider.TMetricType{ - "cpu_util": cloudprovider.VM_METRIC_TYPE_CPU_USAGE, - "memory.util": cloudprovider.VM_METRIC_TYPE_MEM_USAGE, - "disk.device.read.requests.rate": cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS, - "disk.device.write.requests.rate": cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS, - "disk.device.read.bytes.rate": cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS, - "disk.device.write.bytes.rate": cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS, - "network.incoming.bytes": cloudprovider.VM_METRIC_TYPE_NET_BPS_RX, - "network.outgoing.bytes": cloudprovider.VM_METRIC_TYPE_NET_BPS_TX, - } - metricNames := []Metric{} - for metric := range metrics { - metricNames = append(metricNames, Metric{ - Name: metric, - }) - } - if utils.IsInStringArray(opts.RegionExtId, noMetricRegion) { - return []cloudprovider.MetricValues{}, nil - } - data, err := self.DescribeMetricList(opts.RegionExtId, "vm", metricNames, opts.ResourceId, opts.StartTime, opts.EndTime) - if err != nil { - return nil, errors.Wrapf(err, "DescribeMetricList") - } - ret := []cloudprovider.MetricValues{} - for _, value := range data.Entitys { - metric := cloudprovider.MetricValues{} - metric.Id = opts.ResourceId - metricType, ok := metrics[value.MetricName] - if !ok { - continue - } - metric.MetricType = metricType - for _, points := range value.Datapoints { - if len(points) != 2 { - continue - } - metricValue := cloudprovider.MetricValue{} - pointTime, err := strconv.ParseInt(points[1], 10, 64) - if err != nil { - continue - } - metricValue.Timestamp = time.Unix(pointTime, 0) - metricValue.Value, err = strconv.ParseFloat(points[0], 64) - if err != nil { - continue - } - metric.Values = append(metric.Values, metricValue) - } - ret = append(ret, metric) - } - return ret, nil -} diff --git a/pkg/multicloud/ecloud/network.go b/pkg/multicloud/ecloud/network.go deleted file mode 100644 index 306ccd0ecb..0000000000 --- a/pkg/multicloud/ecloud/network.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "context" - - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.EcloudTags - SZoneRegionBase - - wire *SWire - - Id string - Name string - Shared bool - Enabled bool - EcStatus string - Subnets []SSubnet -} - -type SSubnet struct { - Id string - Name string - NetworkId string - Region string - GatewayIp string - EnableDHCP bool - Cidr string - IpVersion string -} - -func (n *SNetwork) GetId() string { - return n.Id -} - -func (n *SNetwork) GetName() string { - return n.Name -} - -func (n *SNetwork) GetGlobalId() string { - return n.Id -} - -func (n *SNetwork) GetStatus() string { - switch n.EcStatus { - case "ACTIVE": - return api.NETWORK_STATUS_AVAILABLE - case "DOWN", "BUILD", "ERROR": - return api.NETWORK_STATUS_UNAVAILABLE - case "PENDING_DELETE": - return api.NETWORK_STATUS_DELETING - case "PENDING_CREATE", "PENDING_UPDATE": - return api.NETWORK_STATUS_PENDING - default: - return api.NETWORK_STATUS_UNKNOWN - } -} - -func (n *SNetwork) Refresh() error { - return nil - // nn, err := n.wire.vpc.region.GetNetworkById(n.wire.vpc.RouterId, n.wire.zone.Region, n.GetId()) - // if err != nil { - // return err - // } - // return jsonutils.Update(n, nn) -} - -func (n *SNetwork) IsEmulated() bool { - return false -} - -func (n *SNetwork) GetProjectId() string { - return "" -} - -func (n *SNetwork) GetIWire() cloudprovider.ICloudWire { - return n.wire -} - -func (n *SNetwork) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(n.Cidr()) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - startIp = startIp.StepUp() // 2 - return startIp.String() -} - -func (n *SNetwork) GetIpEnd() string { - pref, _ := netutils.NewIPV4Prefix(n.Cidr()) - endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 - endIp = endIp.StepDown() // 254 - return endIp.String() -} - -func (n *SNetwork) Cidr() string { - return n.Subnets[0].Cidr -} - -func (n *SNetwork) GetIpMask() int8 { - pref, _ := netutils.NewIPV4Prefix(n.Cidr()) - return pref.MaskLen -} - -func (n *SNetwork) GetGateway() string { - return n.Subnets[0].GatewayIp -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetIsPublic() bool { - return true -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 120 -} - -func (r *SRegion) GetNetworks(routerId, zoneRegion string) ([]SNetwork, error) { - queryParams := map[string]string{ - "networkTypeEnum": "VM", - } - if len(routerId) > 0 { - queryParams["routerId"] = routerId - } - if len(zoneRegion) > 0 { - queryParams["region"] = zoneRegion - } - request := NewConsoleRequest(r.ID, "/api/v2/netcenter/network/NetworkResps", queryParams, nil) - networks := make([]SNetwork, 0) - err := r.client.doList(context.Background(), request, &networks) - if err != nil { - return nil, err - } - return networks, nil -} - -func (r *SRegion) GetNetworkById(routerId, zoneRegion, netId string) (*SNetwork, error) { - queryParams := map[string]string{ - "rangeInNetworkIds": netId, - "networkTypeEnum": "VM", - } - if len(routerId) > 0 { - queryParams["routerId"] = routerId - } - if len(zoneRegion) > 0 { - queryParams["region"] = zoneRegion - } - request := NewConsoleRequest(r.ID, "/api/v2/netcenter/network/NetworkResps", queryParams, nil) - networks := make([]SNetwork, 0, 1) - err := r.client.doList(context.Background(), request, &networks) - if err != nil { - return nil, err - } - if len(networks) == 0 { - return nil, cloudprovider.ErrNotFound - } - return &networks[0], nil -} diff --git a/pkg/multicloud/ecloud/provider/doc.go b/pkg/multicloud/ecloud/provider/doc.go deleted file mode 100644 index aa1a44ede1..0000000000 --- a/pkg/multicloud/ecloud/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/ecloud/provider" diff --git a/pkg/multicloud/ecloud/provider/provider.go b/pkg/multicloud/ecloud/provider/provider.go deleted file mode 100644 index 8138095321..0000000000 --- a/pkg/multicloud/ecloud/provider/provider.go +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/ecloud" -) - -type SEcloudProviderFactory struct { - cloudprovider.SPublicCloudBaseProviderFactory -} - -func (f *SEcloudProviderFactory) GetId() string { - return ecloud.CLOUD_PROVIDER_ECLOUD -} - -func (f *SEcloudProviderFactory) GetName() string { - return ecloud.CLOUD_PROVIDER_ECLOUD_CN -} - -func (f *SEcloudProviderFactory) IsSupportPrepaidResources() bool { - return true -} - -func (f *SEcloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - return output, nil -} - -func (f *SEcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func (f *SEcloudProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - segs := strings.Split(cfg.Account, "/") - account := cfg.Account - if len(segs) == 2 { - account = segs[0] - } - - client, err := ecloud.NewEcloudClient( - ecloud.NewEcloudClientConfig( - ecloud.NewRamRoleSigner(account, cfg.Secret), - ).SetCloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - err = client.TryConnect() - if err != nil { - return nil, err - } - return &SEcloudProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(f), - client: client, - }, nil -} - -func (f *SEcloudProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - return map[string]string{ - "ECLOUD_ACCESS_URL": info.Url, - "ECLOUD_ACCESS_KEY": info.Account, - "ECLOUD_SECRET": info.Secret, - "ECLOUD_REGION": ecloud.ECLOUD_DEFAULT_REGION, - }, nil -} - -func init() { - factory := SEcloudProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SEcloudProvider struct { - cloudprovider.SBaseProvider - client *ecloud.SEcloudClient -} - -func (p *SEcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return p.client.GetSubAccounts() -} - -func (p *SEcloudProvider) GetAccountId() string { - return p.client.GetAccountId() -} - -func (p *SEcloudProvider) GetIRegions() []cloudprovider.ICloudRegion { - return p.client.GetIRegions() -} - -func (p *SEcloudProvider) GetSysInfo() (jsonutils.JSONObject, error) { - iregions := p.client.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(iregions))), "region_count") - info.Add(jsonutils.NewString(ecloud.CLOUD_API_VERSION), "api_version") - return info, nil -} - -func (p *SEcloudProvider) GetVersion() string { - return ecloud.CLOUD_API_VERSION -} - -func (p *SEcloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - iregion, err := p.client.GetIRegionById(id) - if err != nil { - return nil, err - } - if iregion == nil { - return nil, cloudprovider.ErrNotFound - } - return iregion, nil -} - -func (p *SEcloudProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (p *SEcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (p *SEcloudProvider) GetStorageClasses(regionId string) []string { - // TODO - return nil -} - -func (p *SEcloudProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (p *SEcloudProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (p *SEcloudProvider) GetCloudRegionExternalIdPrefix() string { - return p.client.GetCloudRegionExternalIdPrefix() -} - -func (p *SEcloudProvider) GetCapabilities() []string { - return p.client.GetCapabilities() -} - -func (self *SEcloudProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/ecloud/region.go b/pkg/multicloud/ecloud/region.go deleted file mode 100644 index 6cd57f0ab1..0000000000 --- a/pkg/multicloud/ecloud/region.go +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "context" - "fmt" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var regionList = map[string]string{ - "guangzhou-2": "华南-广州2", - "beijing-1": "华北-北京1", - "hunan-1": "华中-长沙1", - "wuxi-1": "华东-苏州", - "dongguan-1": "华南-广州3", - "yaan-1": "西南-成都", - "zhengzhou-1": "华中-郑州", - "beijing-2": "华北-北京3", - "zhuzhou-1": "华中-长沙2", - "jinan-1": "华东-济南", - "xian-1": "西北-西安", - "shanghai-1": "华东-上海1", - "chongqing-1": "西南-重庆", - "ningbo-1": "华东-杭州", - "tianjin-1": "天津-天津", - "jilin-1": "吉林-长春", - "hubei-1": "湖北-襄阳", - "jiangxi-1": "江西-南昌", - "gansu-1": "甘肃-兰州", - "shanxi-1": "山西-太原", - "liaoning-1": "辽宁-沈阳", - "yunnan-2": "云南-昆明2", - "hebei-1": "河北-石家庄", - "fujian-1": "福建-厦门", - "guangxi-1": "广西-南宁", - "anhui-1": "安徽-淮南", - "huhehaote-1": "华北-呼和浩特", - "guiyang-1": "西南-贵阳", -} - -type SRegion struct { - cloudprovider.SFakeOnPremiseRegion - multicloud.SRegion - multicloud.SNoObjectStorageRegion - - client *SEcloudClient - storageCache *SStoragecache - - ID string `json:"id"` - Name string `json:"Name"` - - izones []cloudprovider.ICloudZone - ivpcs []cloudprovider.ICloudVpc -} - -func (r *SRegion) GetId() string { - return r.ID -} - -func (r *SRegion) GetName() string { - return r.Name -} - -func (r *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", r.client.GetAccessEnv(), r.ID) -} - -func (r *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (r *SRegion) Refresh() error { - // err := r.fetchZones() - // if err != nil { - // return err - // } - // return r.fetchVpcs() - return nil -} - -func (r *SRegion) IsEmulated() bool { - return false -} - -func (r *SRegion) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_ECLOUD_EN, r.Name) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(r.GetName()).CN(r.GetName()).EN(en) - return table -} - -// GetLatitude() float32 -// GetLongitude() float32 -func (r *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - if info, ok := LatitudeAndLongitude[r.ID]; ok { - return info - } - return cloudprovider.SGeographicInfo{} -} - -func (r *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if r.izones == nil { - err := r.fetchZones() - if err != nil { - return nil, err - } - } - return r.izones, nil -} - -func (r *SRegion) fetchZones() error { - request := NewNovaRequest(NewApiRequest(r.ID, "/api/v2/region", - map[string]string{"component": "NOVA"}, nil)) - zones := make([]SZone, 0) - err := r.client.doList(context.Background(), request, &zones) - if err != nil { - return err - } - izones := make([]cloudprovider.ICloudZone, len(zones)) - for i := range zones { - zones[i].region = r - zones[i].host = &SHost{ - zone: &zones[i], - } - izones[i] = &zones[i] - } - r.izones = izones - return nil -} - -func (r *SRegion) fetchVpcs() error { - vpcs, err := r.getVpcs() - if err != nil { - return err - } - ivpcs := make([]cloudprovider.ICloudVpc, len(vpcs)) - for i := range vpcs { - ivpcs[i] = &vpcs[i] - } - r.ivpcs = ivpcs - return nil -} - -func (r *SRegion) getVpcs() ([]SVpc, error) { - request := NewConsoleRequest(r.ID, "/api/v2/netcenter/vpc", nil, nil) - vpcs := make([]SVpc, 0) - err := r.client.doList(context.Background(), request, &vpcs) - if err != nil { - return nil, err - } - for i := range vpcs { - vpcs[i].region = r - } - return vpcs, err -} - -func (r *SRegion) getVpcById(id string) (*SVpc, error) { - request := NewConsoleRequest(r.ID, fmt.Sprintf("/api/v2/netcenter/vpc/%s", id), nil, nil) - vpc := SVpc{} - err := r.client.doGet(context.Background(), request, &vpc) - if err != nil { - return nil, err - } - vpc.region = r - return &vpc, err -} - -func (r *SRegion) getVpcByRouterId(id string) (*SVpc, error) { - request := NewConsoleRequest(r.ID, fmt.Sprintf("/api/v2/netcenter/vpc/router/%s", id), nil, nil) - vpc := SVpc{} - err := r.client.doGet(context.Background(), request, &vpc) - if err != nil { - return nil, err - } - vpc.region = r - return &vpc, err -} - -func (r *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - if r.ivpcs == nil { - err := r.fetchVpcs() - if err != nil { - return nil, err - } - } - return r.ivpcs, nil -} - -func (r *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (r *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - vpc, err := r.getVpcById(id) - if err != nil { - return nil, err - } - vpc.region = r - return vpc, nil -} - -func (r *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := r.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (r *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (r *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := r.GetInstanceById(id) - if err != nil { - return nil, err - } - zone, err := r.FindZone(vm.Region) - if err != nil { - return nil, err - } - vm.host = &SHost{ - zone: zone, - } - return vm, nil -} - -func (r *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return r.GetDisk(id) -} - -func (r *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - izones, err := r.GetIZones() - if err != nil { - return nil, err - } - iHosts := make([]cloudprovider.ICloudHost, 0, len(izones)) - for i := range izones { - hosts, err := izones[i].GetIHosts() - if err != nil { - return nil, err - } - iHosts = append(iHosts, hosts...) - } - return iHosts, nil -} - -func (r *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - hosts, err := r.GetIHosts() - if err != nil { - return nil, err - } - for i := range hosts { - if hosts[i].GetGlobalId() == id { - return hosts[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (r *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := r.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -func (r *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - istores, err := r.GetIStorages() - if err != nil { - return nil, err - } - for i := range istores { - if istores[i].GetGlobalId() == id { - return istores[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (r *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - sc := r.getStoragecache() - return []cloudprovider.ICloudStoragecache{sc}, nil -} - -func (r *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - storageCache := r.getStoragecache() - if storageCache.GetGlobalId() == id { - return storageCache, nil - } - return nil, cloudprovider.ErrNotFound -} - -func (r *SRegion) GetProvider() string { - return api.CLOUD_PROVIDER_ECLOUD -} - -func (r *SRegion) GetCapabilities() []string { - return r.client.GetCapabilities() -} - -func (r *SRegion) GetClient() *SEcloudClient { - return r.client -} - -func (r *SRegion) FindZone(zoneRegion string) (*SZone, error) { - izones, err := r.GetIZones() - if err != nil { - return nil, errors.Wrap(err, "unable to GetZones") - } - findZone := func(zoneRegion string) *SZone { - for i := range izones { - zone := izones[i].(*SZone) - if zone.Region == zoneRegion { - return zone - } - } - return nil - } - return findZone(zoneRegion), nil -} diff --git a/pkg/multicloud/ecloud/shell/disk.go b/pkg/multicloud/ecloud/shell/disk.go deleted file mode 100644 index cf3cea0316..0000000000 --- a/pkg/multicloud/ecloud/shell/disk.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ecloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VDiskListOptions struct { - } - shellutils.R(&VDiskListOptions{}, "disk-list", "List disks", func(cli *ecloud.SRegion, args *VDiskListOptions) error { - disks, e := cli.GetDisks() - if e != nil { - return e - } - printList(disks, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ecloud/shell/doc.go b/pkg/multicloud/ecloud/shell/doc.go deleted file mode 100644 index c505eaa625..0000000000 --- a/pkg/multicloud/ecloud/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/ecloud/shell" diff --git a/pkg/multicloud/ecloud/shell/image.go b/pkg/multicloud/ecloud/shell/image.go deleted file mode 100644 index 71344c8495..0000000000 --- a/pkg/multicloud/ecloud/shell/image.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ecloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VImageListOptions struct { - Public bool - } - shellutils.R(&VImageListOptions{}, "image-list", "List images", func(cli *ecloud.SRegion, args *VImageListOptions) error { - images, e := cli.GetImages(args.Public) - if e != nil { - return e - } - printList(images, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ecloud/shell/instance.go b/pkg/multicloud/ecloud/shell/instance.go deleted file mode 100644 index 79e4b3bac2..0000000000 --- a/pkg/multicloud/ecloud/shell/instance.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ecloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List intances", func(cli *ecloud.SRegion, args *InstanceListOptions) error { - instances, e := cli.GetInstancesWithHost("") - if e != nil { - return e - } - printList(instances, 0, 0, 0, []string{}) - return nil - }) - type InstanceShowOptions struct { - ID string - } - shellutils.R(&InstanceShowOptions{}, "instance-show", "Show intances", func(cli *ecloud.SRegion, args *InstanceShowOptions) error { - instance, e := cli.GetInstanceById(args.ID) - if e != nil { - return e - } - printObject(instance) - return nil - }) - shellutils.R(&InstanceShowOptions{}, "instance-nic-list", "List intance nics", func(cli *ecloud.SRegion, args *InstanceShowOptions) error { - instance, e := cli.GetInstanceById(args.ID) - if e != nil { - return e - } - nics, err := instance.GetINics() - if err != nil { - return err - } - printList(nics, 0, 0, 0, []string{}) - return nil - }) - shellutils.R(&InstanceShowOptions{}, "instance-disk-list", "List intance disks", func(cli *ecloud.SRegion, args *InstanceShowOptions) error { - instance, e := cli.GetInstanceById(args.ID) - if e != nil { - return e - } - disks, err := instance.GetIDisks() - if err != nil { - return err - } - printList(disks, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/ecloud/shell/monitor.go b/pkg/multicloud/ecloud/shell/monitor.go deleted file mode 100644 index 15e9822ef2..0000000000 --- a/pkg/multicloud/ecloud/shell/monitor.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/ecloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type PListOptions struct { - } - shellutils.R(&PListOptions{}, "server-producttype-list", "List productTypes", func(cli *ecloud.SRegion, - args *PListOptions) error { - prod, e := cli.GetProductTypes() - if e != nil { - return e - } - printObject(prod) - return nil - }) - - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics", func(cli *ecloud.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric: %s %s %s", metrics[i].Id, metrics[i].MetricType, metrics[i].Unit) - printList(metrics[i].Values, len(metrics[i].Values), 0, 0, []string{}) - } - return nil - }) - -} diff --git a/pkg/multicloud/ecloud/shell/network.go b/pkg/multicloud/ecloud/shell/network.go deleted file mode 100644 index 51a9fc4339..0000000000 --- a/pkg/multicloud/ecloud/shell/network.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ecloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VNetworkListOptions struct { - VpcId string `help:"Vpc ID"` - } - shellutils.R(&VNetworkListOptions{}, "subnet-list", "List subnets", func(cli *ecloud.SRegion, args *VNetworkListOptions) error { - ivpc, err := cli.GetIVpcById(args.VpcId) - if err != nil { - return err - } - vpc := ivpc.(*ecloud.SVpc) - networks, e := cli.GetNetworks(vpc.RouterId, "") - if e != nil { - return e - } - printList(networks, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ecloud/shell/printutils.go b/pkg/multicloud/ecloud/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/ecloud/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/ecloud/shell/region.go b/pkg/multicloud/ecloud/shell/region.go deleted file mode 100644 index a4bc43d35d..0000000000 --- a/pkg/multicloud/ecloud/shell/region.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ecloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *ecloud.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetIRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) - shellutils.R(&RegionListOptions{}, "zone-list", "List zones", func(cli *ecloud.SRegion, args *RegionListOptions) error { - zones, err := cli.GetIZones() - if err != nil { - return err - } - printList(zones, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ecloud/shell/vpc.go b/pkg/multicloud/ecloud/shell/vpc.go deleted file mode 100644 index cb0b44461a..0000000000 --- a/pkg/multicloud/ecloud/shell/vpc.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ecloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - } - shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *ecloud.SRegion, args *VpcListOptions) error { - vpcs, err := cli.GetIVpcs() - if err != nil { - return err - } - printList(vpcs, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ecloud/snapshot.go b/pkg/multicloud/ecloud/snapshot.go deleted file mode 100644 index 472c680183..0000000000 --- a/pkg/multicloud/ecloud/snapshot.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "context" - "strings" - "time" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSnapshot struct { - multicloud.SResourceBase - multicloud.EcloudTags - region *SRegion - SCreateTime - - BackupType string - CreateBy string - Description string - EcType string - Id string - Name string - Size int - VolumeId string - VolumeType string - Status string - IsSystem bool - SystemDisk string -} - -func (s *SSnapshot) GetId() string { - return s.Id -} - -func (s *SSnapshot) GetName() string { - return s.Name -} - -func (s *SSnapshot) GetStatus() string { - switch strings.ToLower(s.Status) { - case "available", "in_use", "active": - return api.SNAPSHOT_READY - case "creating", "attaching", "backing_up", "saving", "queued": - return api.SNAPSHOT_CREATING - case "deleting": - return api.SNAPSHOT_DELETING - case "error_deleting": - return api.SNAPSHOT_DELETE_FAILED - case "error": - return api.SNAPSHOT_FAILED - default: - return api.SNAPSHOT_UNKNOWN - } -} - -func (s *SSnapshot) GetSizeMb() int32 { - return int32(s.Size) -} - -func (s *SSnapshot) GetDiskId() string { - if s.IsSystem { - return s.SystemDisk - } - return s.VolumeId -} - -func (s *SSnapshot) GetCreatedAt() time.Time { - return s.SCreateTime.GetCreatedAt() -} - -func (s *SSnapshot) GetDiskType() string { - if s.IsSystem { - return api.DISK_TYPE_SYS - } - return api.DISK_TYPE_DATA -} - -func (s *SSnapshot) GetGlobalId() string { - return s.Id -} - -func (s *SSnapshot) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (s *SSnapshot) GetProjectId() string { - return "" -} - -func (s *SRegion) GetSnapshots(snapshotId string, parentId string, isSystem bool) ([]SSnapshot, error) { - var apiRequest *SApiRequest - query := map[string]string{} - if len(snapshotId) > 0 { - query["backupId"] = snapshotId - } - if isSystem { - if len(parentId) > 0 { - query["serverId"] = parentId - } - apiRequest = NewApiRequest(s.ID, "/api/v2/vmBackup", query, nil) - } else { - if len(parentId) > 0 { - query["volumeId"] = parentId - } - apiRequest = NewApiRequest(s.ID, "/api/v2/volume/volumebackup", query, nil) - } - request := NewNovaRequest(apiRequest) - snapshots := make([]SSnapshot, 0) - err := s.client.doList(context.Background(), request, &snapshots) - if err != nil { - return nil, err - } - return snapshots, nil -} diff --git a/pkg/multicloud/ecloud/storage.go b/pkg/multicloud/ecloud/storage.go deleted file mode 100644 index 65a827302c..0000000000 --- a/pkg/multicloud/ecloud/storage.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var storageTypes = []string{ - api.STORAGE_ECLOUD_CAPEBS, - api.STORAGE_ECLOUD_EBS, - api.STORAGE_ECLOUD_SSD, - api.STORAGE_ECLOUD_SSDEBS, - // special storage - api.STORAGE_ECLOUD_SYSTEM, -} - -type SStorage struct { - multicloud.SStorageBase - multicloud.EcloudTags - zone *SZone - storageType string -} - -func (s *SStorage) GetId() string { - return fmt.Sprintf("%s-%s-%s", s.zone.region.client.cpcfg.Id, s.zone.GetGlobalId(), s.storageType) -} - -func (s *SStorage) GetName() string { - return fmt.Sprintf("%s-%s-%s", s.zone.region.client.cpcfg.Name, s.zone.GetId(), s.storageType) -} - -func (s *SStorage) GetGlobalId() string { - return s.GetId() -} - -func (s *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (s *SStorage) Refresh() error { - return nil -} - -func (s *SStorage) IsEmulated() bool { - return true -} - -func (s *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return s.zone.region.getStoragecache() -} - -func (s *SStorage) GetIZone() cloudprovider.ICloudZone { - return s.zone -} - -func (s *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - if s.storageType == api.STORAGE_ECLOUD_SYSTEM { - return nil, nil - } - disks, err := s.zone.region.GetDisks() - if err != nil { - return nil, err - } - - // 按storage type 过滤出disk - filtedDisks := make([]SDisk, 0) - for i := range disks { - disk := disks[i] - if disk.Type == s.storageType && disk.Region == s.zone.Region { - filtedDisks = append(filtedDisks, disk) - } - } - - idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) - for i := 0; i < len(filtedDisks); i += 1 { - filtedDisks[i].storage = s - idisks[i] = &filtedDisks[i] - } - return idisks, nil -} - -func (s *SStorage) GetStorageType() string { - return s.storageType -} - -func (s *SStorage) GetMediumType() string { - if s.storageType == api.STORAGE_ECLOUD_SSD { - return api.DISK_TYPE_SSD - } else { - return api.DISK_TYPE_ROTATE - } -} - -func (s *SStorage) GetCapacityMB() int64 { - return 0 -} - -func (s *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (s *SStorage) GetStorageConf() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (s *SStorage) GetEnabled() bool { - return true -} - -func (s *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (s *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - if len(idStr) == 0 { - return nil, cloudprovider.ErrNotFound - } - - if disk, err := s.zone.region.GetDisk(idStr); err != nil { - return nil, err - } else { - disk.storage = s - return disk, nil - } -} - -func (s *SStorage) GetMountPoint() string { - return "" -} - -func (s *SStorage) IsSysDiskStore() bool { - return true -} - -func (s *SStorage) DisableSync() bool { - if s.storageType == api.STORAGE_ECLOUD_SYSTEM { - return true - } - return s.SStorageBase.DisableSync() -} - -func (s *SRegion) getStoragecache() *SStoragecache { - if s.storageCache == nil { - s.storageCache = &SStoragecache{region: s} - } - return s.storageCache -} diff --git a/pkg/multicloud/ecloud/storagecache.go b/pkg/multicloud/ecloud/storagecache.go deleted file mode 100644 index 1ad0925c8e..0000000000 --- a/pkg/multicloud/ecloud/storagecache.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.EcloudTags - region *SRegion -} - -func (sc *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (sc *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (sc *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (sc *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", sc.region.client.cpcfg.Id, sc.region.GetId()) -} - -func (sc *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", sc.region.client.cpcfg.Name, sc.region.GetId()) -} - -func (sc *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", sc.region.client.cpcfg.Id, sc.region.GetGlobalId()) -} - -func (sc *SStoragecache) GetStatus() string { - return "available" -} - -func (sc *SStoragecache) Refresh() error { - return nil -} - -func (sc *SStoragecache) IsEmulated() bool { - return false -} - -func (sc *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (sc *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - imagesSelf, err := sc.region.GetImages(false) - if err != nil { - return nil, errors.Wrapf(err, "GetImages") - } - ret := []cloudprovider.ICloudImage{} - for i := range imagesSelf { - imagesSelf[i].storageCache = sc - ret = append(ret, &imagesSelf[i]) - } - return ret, nil -} - -func (sc *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - image, err := sc.region.GetImage(extId) - if err != nil { - return nil, errors.Wrap(err, "SStoragecache.GetIImageById.GetImage") - } - - image.storageCache = sc - return image, err -} - -func (sc *SStoragecache) GetPath() string { - return "" -} diff --git a/pkg/multicloud/ecloud/vpc.go b/pkg/multicloud/ecloud/vpc.go deleted file mode 100644 index dc5a04bbfb..0000000000 --- a/pkg/multicloud/ecloud/vpc.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - multicloud.EcloudTags - - region *SRegion - iwires []cloudprovider.ICloudWire - - // wires - // secgroups - - Id string - Name string - Region string - EcStatus string - RouterId string - Scale string - UserId string - UserName string -} - -func (v *SVpc) GetId() string { - return v.Id -} - -func (v *SVpc) GetName() string { - return v.Name -} - -func (v *SVpc) GetGlobalId() string { - return v.GetId() -} - -func (v *SVpc) GetStatus() string { - switch v.EcStatus { - case "ACTIVE": - return api.VPC_STATUS_AVAILABLE - case "DOWN", "BUILD", "ERROR": - return api.VPC_STATUS_UNAVAILABLE - case "PENDING_DELETE": - return api.VPC_STATUS_DELETING - case "PENDING_CREATE", "PENDING_UPDATE": - return api.VPC_STATUS_PENDING - default: - return api.VPC_STATUS_UNKNOWN - } -} - -func (v *SVpc) Refresh() error { - n, err := v.region.getVpcById(v.Id) - if err != nil { - return err - } - return jsonutils.Update(v, n) - // TODO? v.fetchWires() -} - -func (v *SVpc) IsEmulated() bool { - return false -} - -func (v *SVpc) GetRegion() cloudprovider.ICloudRegion { - return v.region -} - -func (v *SVpc) GetIsDefault() bool { - return false -} - -func (v *SVpc) GetCidrBlock() string { - return "" -} - -func (v *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - if v.iwires == nil { - err := v.fetchWires() - if err != nil { - return nil, err - } - } - return v.iwires, nil -} - -func (v *SVpc) fetchWires() error { - networks, err := v.region.GetNetworks(v.RouterId, "") - if err != nil { - return err - } - izones, err := v.region.GetIZones() - if err != nil { - return errors.Wrap(err, "unable to GetZones") - } - findZone := func(zoneRegion string) *SZone { - for i := range izones { - zone := izones[i].(*SZone) - if zone.Region == zoneRegion { - return zone - } - } - return nil - } - zoneRegion2Wire := map[string]*SWire{} - for i := range networks { - zoneRegion := networks[i].Region - zone := findZone(zoneRegion) - var ( - wire *SWire - ok bool - ) - if wire, ok = zoneRegion2Wire[zoneRegion]; !ok { - wire = &SWire{ - vpc: v, - zone: zone, - } - zoneRegion2Wire[zoneRegion] = wire - } - wire.inetworks = append(wire.inetworks, &networks[i]) - } - iwires := make([]cloudprovider.ICloudWire, 0, len(zoneRegion2Wire)) - for _, wire := range zoneRegion2Wire { - iwires = append(iwires, wire) - } - v.iwires = iwires - return nil -} - -func (v *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - return nil, nil -} - -func (v *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (v *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, nil -} - -func (v *SVpc) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (v *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { - iwires, err := v.GetIWires() - if err != nil { - return nil, err - } - for i := range iwires { - if iwires[i].GetGlobalId() == wireId { - return iwires[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/ecloud/wire.go b/pkg/multicloud/ecloud/wire.go deleted file mode 100644 index 927b09ee99..0000000000 --- a/pkg/multicloud/ecloud/wire.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.EcloudTags - vpc *SVpc - zone *SZone - inetworks []cloudprovider.ICloudNetwork -} - -func (w *SWire) GetId() string { - return fmt.Sprintf("%s-%s", w.vpc.GetId(), w.vpc.region.GetId()) -} - -func (w *SWire) GetName() string { - return w.GetId() -} - -func (w *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", w.vpc.GetGlobalId(), w.vpc.region.GetGlobalId()) -} - -func (w *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (w *SWire) Refresh() error { - return nil - // TODO? w.fetchNetworks() -} - -func (w *SWire) IsEmulated() bool { - return true -} - -func (w *SWire) GetIVpc() cloudprovider.ICloudVpc { - return w.vpc -} - -func (w *SWire) GetIZone() cloudprovider.ICloudZone { - return w.zone -} - -func (w *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - if w.inetworks == nil { - err := w.fetchNetworks() - if err != nil { - return nil, err - } - } - return w.inetworks, nil -} - -func (w *SWire) GetBandwidth() int { - return 10000 -} - -func (w *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { - n, err := w.vpc.region.GetNetworkById(w.vpc.RouterId, w.zone.Region, netid) - if err != nil { - return nil, err - } - n.wire = w - return n, nil -} - -func (w *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - return nil, nil -} - -func (w *SWire) CreateNetworks() (*SNetwork, error) { - // data := jsonutils.NewDict() - // req := jsonutils.NewDict() - // req.Set("availabilityZoneHints", jsonutils.NewString("RegionOne")) - // req.Set("networkName", jsonutils.NewString("zyone")) - // req.Set("networkTypeEnum", jsonutils.NewString("VM")) - // req.Set("region", jsonutils.NewString("RegionOne")) - // req.Set("routerId", jsonutils.NewString(w.vpc.RouterId)) - // subnet := jsonutils.NewDict() - // subnet.Set("cidr", jsonutils.NewString("192.168.46.0/24")) - // subnet.Set("ipVersion", jsonutils.NewString("4")) - // subnet.Set("subnetName", jsonutils.NewString("zyone")) - // req.Set("subnets", jsonutils.NewArray(subnet)) - // data.Set("networkCreateReq", req) - // fmt.Printf("data:\n%s", data.PrettyString()) - // request := NewConsoleRequest(w.vpc.region.ID, "/api/v2/netcenter/network", nil, req) - // request.SetMethod("POST") - // resp, err := w.vpc.region.client.request(context.Background(), request) - // if err != nil { - // return nil, err - // } - // fmt.Printf("resp:%s", resp) - // return nil, nil - return nil, cloudprovider.ErrNotImplemented -} - -func (w *SWire) GetNetworkById(netId string) (*SNetwork, error) { - n, err := w.vpc.region.GetNetworkById(w.vpc.RouterId, w.zone.Region, netId) - if err != nil { - return nil, err - } - n.wire = w - return n, nil -} - -func (w *SWire) fetchNetworks() error { - networks, err := w.vpc.region.GetNetworks(w.vpc.RouterId, w.zone.Region) - if err != nil { - return err - } - inetworks := make([]cloudprovider.ICloudNetwork, len(networks)) - for i := range networks { - networks[i].wire = w - inetworks[i] = &networks[i] - } - w.inetworks = inetworks - return nil -} diff --git a/pkg/multicloud/ecloud/zone.go b/pkg/multicloud/ecloud/zone.go deleted file mode 100644 index 043e4e48fd..0000000000 --- a/pkg/multicloud/ecloud/zone.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ecloud - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SZone struct { - multicloud.SResourceBase - multicloud.EcloudTags - region *SRegion - host *SHost - - istorages []cloudprovider.ICloudStorage - - ID string `json:"id"` - Name string `json:"name"` - Region string `json:"region"` - Deleted bool - Visible bool -} - -func (z *SZone) GetId() string { - return z.ID -} - -func (z *SZone) GetName() string { - //return fmt.Sprintf("%s %s", CLOUD_PROVIDER_ECLOUD_CN, z.Name) - return z.Name -} - -func (z *SZone) GetGlobalId() string { - return fmt.Sprintf("%s/%s", z.region.GetGlobalId(), z.ID) -} - -func (z *SZone) GetStatus() string { - if z.Deleted || !z.Visible { - return "disable" - } - return "enable" -} - -func (z *SZone) Refresh() error { - return nil -} - -func (z *SZone) IsEmulated() bool { - return false -} - -func (z *SZone) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(z.GetName()).CN(z.GetName()).EN(fmt.Sprintf("%s %s", CLOUD_PROVIDER_ECLOUD_EN, z.Name)) - return table -} - -func (z *SZone) GetIRegion() cloudprovider.ICloudRegion { - return z.region -} - -func (z *SZone) getHost() cloudprovider.ICloudHost { - if z.host == nil { - z.host = &SHost{ - zone: z, - } - } - return z.host -} - -func (z *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - return []cloudprovider.ICloudHost{z.getHost()}, nil -} - -func (z *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - host := z.getHost() - if host.GetGlobalId() == id { - return host, nil - } - return nil, cloudprovider.ErrNotFound -} - -func (z *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - if z.istorages == nil { - err := z.fetchStorages() - if err != nil { - return nil, err - } - } - return z.istorages, nil -} - -func (z *SZone) fetchStorages() error { - istorages := make([]cloudprovider.ICloudStorage, len(storageTypes)) - for i := range istorages { - istorages[i] = &SStorage{ - zone: z, - storageType: storageTypes[i], - } - } - z.istorages = istorages - return nil -} - -func (z *SZone) getStorageByType(t string) (*SStorage, error) { - istorages, err := z.GetIStorages() - if err != nil { - return nil, err - } - for i := range istorages { - if istorages[i].GetStorageType() == t { - return istorages[i].(*SStorage), nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (z *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - istorages, err := z.GetIStorages() - if err != nil { - return nil, err - } - for i := range istorages { - if istorages[i].GetGlobalId() == id { - return istorages[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -type SZoneRegionBase struct { - Region string -} diff --git a/pkg/multicloud/esxi/cluster.go b/pkg/multicloud/esxi/cluster.go deleted file mode 100644 index 46de59ed49..0000000000 --- a/pkg/multicloud/esxi/cluster.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "context" - "fmt" - - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SCluster struct { - SManagedObject -} - -func NewCluster(manager *SESXiClient, cluster *mo.ClusterComputeResource, dc *SDatacenter) *SCluster { - return &SCluster{SManagedObject: newManagedObject(manager, cluster, dc)} -} - -func (cluster *SCluster) ListResourcePools() ([]mo.ResourcePool, error) { - var pools, result []mo.ResourcePool - err := cluster.manager.scanMObjects(cluster.object.Entity().Self, RESOURCEPOOL_PROPS, &pools) - if err != nil { - return nil, errors.Wrap(err, "scanMObjects") - } - for i := range pools { - if pools[i].Parent.Type == "ClusterComputeResource" { - continue - } - result = append(result, pools[i]) - } - return result, nil -} - -func (cluster *SCluster) getDefaultResourcePool() (mo.ResourcePool, error) { - pools := []mo.ResourcePool{} - err := cluster.manager.scanMObjects(cluster.object.Entity().Self, RESOURCEPOOL_PROPS, &pools) - if err != nil { - return mo.ResourcePool{}, errors.Wrap(err, "scanMObjects") - } - for i := range pools { - if pools[i].Parent.Type == "ClusterComputeResource" { - return pools[i], nil - } - } - return mo.ResourcePool{}, cloudprovider.ErrNotFound -} - -func (cluster *SCluster) CreateResourcePool(name string) (*mo.ResourcePool, error) { - if len(name) == 0 { - return nil, errors.Error("empty name str") - } - root, err := cluster.getDefaultResourcePool() - if err != nil { - return nil, errors.Wrap(err, "getDefaultResourcePool") - } - pool := object.NewResourcePool(cluster.manager.client.Client, root.Reference()) - pool.InventoryPath = fmt.Sprintf("/%s/host/%s/Resources", cluster.datacenter.GetName(), cluster.GetName()) - _, err = pool.Create(context.Background(), name, types.DefaultResourceConfigSpec()) - if err != nil { - return nil, errors.Wrap(err, "pool.Create") - } - - pools, err := cluster.ListResourcePools() - if err != nil { - return nil, errors.Wrap(err, "listResourcePools") - } - for i := range pools { - p := NewResourcePool(cluster.manager, &pools[i], cluster.datacenter) - if p.GetName() == name { - return &pools[i], nil - } - } - return nil, errors.Wrap(cloudprovider.ErrNotFound, "AfterCreate") -} - -func (cluster *SCluster) SyncResourcePool(name string) (*mo.ResourcePool, error) { - pools, err := cluster.ListResourcePools() - if err != nil { - return nil, errors.Wrap(err, "ListResourcePools") - } - for i := range pools { - if pools[i].Entity().Name == name { - return &pools[i], nil - } - } - return cluster.CreateResourcePool(name) -} - -func (cluster *SCluster) getoCluster() *mo.ClusterComputeResource { - return cluster.object.(*mo.ClusterComputeResource) -} diff --git a/pkg/multicloud/esxi/datacenter.go b/pkg/multicloud/esxi/datacenter.go deleted file mode 100644 index 30de8900c7..0000000000 --- a/pkg/multicloud/esxi/datacenter.go +++ /dev/null @@ -1,596 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "regexp" - "strings" - - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/property" - "github.com/vmware/govmomi/view" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/sets" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -var DATACENTER_PROPS = []string{"name", "parent", "datastore", "network"} - -type SDatacenter struct { - SManagedObject - - ihosts []cloudprovider.ICloudHost - istorages []cloudprovider.ICloudStorage - inetworks []IVMNetwork - iresoucePool []cloudprovider.ICloudProject - clusters []*SCluster - - Name string -} - -func newDatacenter(manager *SESXiClient, dc *mo.Datacenter) *SDatacenter { - obj := SDatacenter{SManagedObject: newManagedObject(manager, dc, nil)} - obj.datacenter = &obj - return &obj -} - -func (dc *SDatacenter) isDefaultDc() bool { - if dc.object == &defaultDc { - return true - } - return false -} - -func (dc *SDatacenter) getDatacenter() *mo.Datacenter { - return dc.object.(*mo.Datacenter) -} - -func (dc *SDatacenter) getObjectDatacenter() *object.Datacenter { - if dc.isDefaultDc() { - return nil - } - return object.NewDatacenter(dc.manager.client.Client, dc.object.Reference()) -} - -func (dc *SDatacenter) scanResourcePool() error { - if dc.iresoucePool == nil { - pools, err := dc.listResourcePools() - if err != nil { - return errors.Wrap(err, "listResourcePools") - } - dc.iresoucePool = []cloudprovider.ICloudProject{} - for i := 0; i < len(pools); i++ { - p := NewResourcePool(dc.manager, &pools[i], dc) - dc.iresoucePool = append(dc.iresoucePool, p) - } - } - return nil -} - -func (dc *SDatacenter) scanHosts() error { - if dc.ihosts == nil { - var hosts []mo.HostSystem - if dc.isDefaultDc() { - err := dc.manager.scanAllMObjects(HOST_SYSTEM_PROPS, &hosts) - if err != nil { - return errors.Wrap(err, "dc.manager.scanAllMObjects") - } - } else { - err := dc.manager.scanMObjects(dc.object.Entity().Self, HOST_SYSTEM_PROPS, &hosts) - if err != nil { - return errors.Wrap(err, "dc.manager.scanMObjects") - } - } - dc.ihosts = make([]cloudprovider.ICloudHost, 0) - for i := 0; i < len(hosts); i += 1 { - h := NewHost(dc.manager, &hosts[i], dc) - if h != nil { - dc.ihosts = append(dc.ihosts, h) - } - } - } - return nil -} - -func (dc *SDatacenter) GetResourcePools() ([]cloudprovider.ICloudProject, error) { - err := dc.scanResourcePool() - if err != nil { - return nil, errors.Wrap(err, "dc.scanResourcePool") - } - return dc.iresoucePool, nil -} - -func (dc *SDatacenter) listResourcePools() ([]mo.ResourcePool, error) { - var pools, result []mo.ResourcePool - err := dc.manager.scanMObjects(dc.object.Entity().Self, RESOURCEPOOL_PROPS, &pools) - if err != nil { - return nil, errors.Wrap(err, "scanMObjects") - } - for i := range pools { - if pools[i].Parent.Type == "ClusterComputeResource" { - continue - } - result = append(result, pools[i]) - } - return result, nil -} - -func (dc *SDatacenter) ListClusters() ([]*SCluster, error) { - return dc.listClusters() -} - -func (dc *SDatacenter) GetCluster(cluster string) (*SCluster, error) { - clusters, err := dc.ListClusters() - if err != nil { - return nil, errors.Wrap(err, "ListClusters") - } - for i := range clusters { - if clusters[i].GetName() == cluster { - return clusters[i], nil - } - - } - return nil, cloudprovider.ErrNotFound -} - -func (dc *SDatacenter) listClusters() ([]*SCluster, error) { - if dc.clusters != nil { - return dc.clusters, nil - } - clusters := []mo.ClusterComputeResource{} - err := dc.manager.scanMObjects(dc.object.Entity().Self, RESOURCEPOOL_PROPS, &clusters) - if err != nil { - return nil, errors.Wrap(err, "scanMObjects") - } - ret := []*SCluster{} - for i := range clusters { - c := NewCluster(dc.manager, &clusters[i], dc) - ret = append(ret, c) - } - return ret, nil -} - -func (dc *SDatacenter) GetIHosts() ([]cloudprovider.ICloudHost, error) { - err := dc.scanHosts() - if err != nil { - return nil, errors.Wrap(err, "dc.scanHosts") - } - return dc.ihosts, nil -} - -func (dc *SDatacenter) scanDatastores() error { - if dc.istorages == nil { - var stores []mo.Datastore - if dc.isDefaultDc() { - err := dc.manager.scanAllMObjects(DATASTORE_PROPS, &stores) - if err != nil { - return errors.Wrap(err, "dc.manager.scanAllMObjects") - } - } else { - dsList := dc.getDatacenter().Datastore - if dsList != nil { - err := dc.manager.references2Objects(dsList, DATASTORE_PROPS, &stores) - if err != nil { - return errors.Wrap(err, "dc.manager.references2Objects") - } - } - } - dc.istorages = make([]cloudprovider.ICloudStorage, 0) - for i := 0; i < len(stores); i += 1 { - ds := NewDatastore(dc.manager, &stores[i], dc) - dsId := ds.GetGlobalId() - if len(dsId) > 0 { - dc.istorages = append(dc.istorages, ds) - } - } - } - return nil -} - -func (dc *SDatacenter) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - err := dc.scanDatastores() - if err != nil { - return nil, errors.Wrap(err, "dc.scanDatastores") - } - return dc.istorages, nil -} - -func (dc *SDatacenter) GetIHostByMoId(idstr string) (cloudprovider.ICloudHost, error) { - ihosts, err := dc.GetIHosts() - if err != nil { - return nil, errors.Wrap(err, "dc.GetIHosts") - } - for i := 0; i < len(ihosts); i += 1 { - if ihosts[i].GetId() == idstr { - return ihosts[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (dc *SDatacenter) GetIStorageByMoId(idstr string) (cloudprovider.ICloudStorage, error) { - istorages, err := dc.GetIStorages() - if err != nil { - return nil, errors.Wrap(err, "dc.GetIStorages") - } - for i := 0; i < len(istorages); i += 1 { - if istorages[i].GetId() == idstr { - return istorages[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (dc *SDatacenter) getDcObj() *object.Datacenter { - if dc.isDefaultDc() { - return nil - } - return object.NewDatacenter(dc.manager.client.Client, dc.object.Reference()) -} - -func (dc *SDatacenter) fetchMoVms(filter property.Filter, props []string) ([]mo.VirtualMachine, error) { - odc := dc.getObjectDatacenter() - root := odc.Reference() - var movms []mo.VirtualMachine - err := dc.manager.scanMObjectsWithFilter(root, props, &movms, filter) - if err != nil { - return nil, errors.Wrap(err, "scanMObjectsWithFilter") - } - return movms, nil -} - -func (dc *SDatacenter) moVms2Vm(movms []mo.VirtualMachine, all *bool) ([]*SVirtualMachine, error) { - // avoid applying new memory and copying - vms := make([]*SVirtualMachine, 0, len(movms)) - for i := range movms { - if (all != nil && *all) || !strings.HasPrefix(movms[i].Name, api.ESXI_IMAGE_CACHE_TMP_PREFIX) { - vm := NewVirtualMachine(dc.manager, &movms[i], dc) - // must - if vm == nil { - continue - } - vms = append(vms, vm) - } - } - return vms, nil -} - -func (dc *SDatacenter) fetchFakeTemplateVMs(movms []mo.VirtualMachine, regex string) ([]*SVirtualMachine, error) { - var ( - tNameRegex *regexp.Regexp - err error - ) - if len(regex) == 0 { - tNameRegex = tempalteNameRegex - } else { - tNameRegex, err = regexp.Compile(regex) - if err != nil { - return nil, errors.Wrap(err, "generate regexp") - } - } - objs := make([]types.ManagedObjectReference, 0) - for i := range movms { - name := movms[i].Name - if tNameRegex != nil && tNameRegex.MatchString(name) { - objs = append(objs, movms[i].Reference()) - } - } - if len(objs) == 0 { - return nil, nil - } - return dc.fetchVms(objs, false) -} - -func (dc *SDatacenter) fetchVmsFromCache(vmRefs []types.ManagedObjectReference) ([]*SVirtualMachine, error) { - vmRefSet := sets.NewString() - for i := range vmRefs { - vmRefSet.Insert(vmRefs[i].String()) - } - ihosts, err := dc.GetIHosts() - if err != nil { - return nil, err - } - ret := make([]*SVirtualMachine, 0, len(vmRefs)) - for i := range ihosts { - ivms, err := ihosts[i].GetIVMs() - if err != nil { - return nil, err - } - for i := range ivms { - vm := ivms[i].(*SVirtualMachine) - s := vm.getVirtualMachine().Self.String() - if vmRefSet.Has(s) { - ret = append(ret, vm) - vmRefSet.Delete(s) - } - } - } - return ret, nil -} - -func (dc *SDatacenter) fetchVms(vmRefs []types.ManagedObjectReference, all bool) ([]*SVirtualMachine, error) { - var movms []mo.VirtualMachine - if vmRefs != nil { - err := dc.manager.references2Objects(vmRefs, VIRTUAL_MACHINE_PROPS, &movms) - if err != nil { - return nil, errors.Wrap(err, "dc.manager.references2Objects") - } - } - return dc.moVms2Vm(movms, &all) -} - -func (dc *SDatacenter) fetchHosts_(vmRefs []types.ManagedObjectReference, all bool) ([]*SHost, error) { - var movms []mo.HostSystem - if vmRefs != nil { - err := dc.manager.references2Objects(vmRefs, VIRTUAL_MACHINE_PROPS, &movms) - if err != nil { - return nil, errors.Wrap(err, "dc.manager.references2Objects") - } - } - - // avoid applying new memory and copying - vms := make([]*SHost, 0, len(movms)) - for i := range movms { - if all || !strings.HasPrefix(movms[i].Entity().Name, api.ESXI_IMAGE_CACHE_TMP_PREFIX) { - vms = append(vms, NewHost(dc.manager, &movms[i], dc)) - } - } - return vms, nil -} - -func (dc *SDatacenter) FetchVMs() ([]*SVirtualMachine, error) { - return dc.fetchVMsWithFilter(property.Filter{}) -} - -func (dc *SDatacenter) FetchNoTemplateVMs() ([]*SVirtualMachine, error) { - filter := property.Filter{} - filter["config.template"] = false - return dc.fetchVMsWithFilter(filter) -} - -func (dc *SDatacenter) FetchFakeTempateVMs(regex string) ([]*SVirtualMachine, error) { - filter := property.Filter{} - filter["summary.runtime.powerState"] = types.VirtualMachinePowerStatePoweredOff - movms, err := dc.fetchMoVms(filter, []string{"name"}) - if err != nil { - return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines") - } - return dc.fetchFakeTemplateVMs(movms, regex) -} - -func (dc *SDatacenter) fetchVMsWithFilter(filter property.Filter) ([]*SVirtualMachine, error) { - movms, err := dc.fetchMoVms(filter, VIRTUAL_MACHINE_PROPS) - if err != nil { - return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines") - } - ret, err := dc.moVms2Vm(movms, nil) - if err != nil { - return nil, errors.Wrap(err, "unable to convert mo.VirtualMachine to VirtualMachine") - } - return ret, err -} - -func (dc *SDatacenter) FetchNoTemplateVMEntityReferens() ([]types.ManagedObjectReference, error) { - filter := property.Filter{} - filter["config.template"] = false - odc := dc.getObjectDatacenter() - root := odc.Reference() - m := view.NewManager(dc.manager.client.Client) - v, err := m.CreateContainerView(dc.manager.context, root, []string{"VirtualMachine"}, true) - if err != nil { - return nil, err - } - defer func() { - _ = v.Destroy(dc.manager.context) - }() - objs, err := v.Find(dc.manager.context, []string{"VirtualMachine"}, filter) - if err != nil { - return nil, err - } - return objs, nil -} - -func (dc *SDatacenter) FetchNoTemplateHostEntityReferens() ([]types.ManagedObjectReference, error) { - filter := property.Filter{} - odc := dc.getObjectDatacenter() - root := odc.Reference() - m := view.NewManager(dc.manager.client.Client) - v, err := m.CreateContainerView(dc.manager.context, root, []string{"HostSystem"}, true) - if err != nil { - return nil, err - } - defer func() { - _ = v.Destroy(dc.manager.context) - }() - objs, err := v.Find(dc.manager.context, []string{"HostSystem"}, filter) - if err != nil { - return nil, err - } - return objs, nil -} - -func (dc *SDatacenter) fetchHosts(filter property.Filter) ([]*SHost, error) { - odc := dc.getObjectDatacenter() - root := odc.Reference() - m := view.NewManager(dc.manager.client.Client) - v, err := m.CreateContainerView(dc.manager.context, root, []string{"HostSystem"}, true) - if err != nil { - return nil, err - } - defer func() { - _ = v.Destroy(dc.manager.context) - }() - objs, err := v.Find(dc.manager.context, []string{"HostSystem"}, filter) - if err != nil { - return nil, err - } - hosts, err := dc.fetchHosts_(objs, false) - return hosts, err -} - -func (dc *SDatacenter) FetchTemplateVMs() ([]*SVirtualMachine, error) { - filter := property.Filter{} - filter["config.template"] = true - return dc.fetchVMsWithFilter(filter) -} - -func (dc *SDatacenter) FetchTemplateVMById(id string) (*SVirtualMachine, error) { - filter := property.Filter{} - filter["config.template"] = true - filter["summary.config.uuid"] = id - vms, err := dc.fetchVMsWithFilter(filter) - if err != nil { - return nil, err - } - if len(vms) == 0 { - return nil, errors.ErrNotFound - } - return vms[0], nil -} - -func (dc *SDatacenter) FetchVMById(id string) (*SVirtualMachine, error) { - filter := property.Filter{} - filter["summary.config.uuid"] = id - vms, err := dc.fetchVMsWithFilter(filter) - if err != nil { - return nil, err - } - if len(vms) == 0 { - return nil, errors.ErrNotFound - } - return vms[0], nil -} - -func (dc *SDatacenter) fetchDatastores(datastoreRefs []types.ManagedObjectReference) ([]cloudprovider.ICloudStorage, error) { - var dss []mo.Datastore - if datastoreRefs != nil { - err := dc.manager.references2Objects(datastoreRefs, DATASTORE_PROPS, &dss) - if err != nil { - return nil, errors.Wrap(err, "dc.manager.references2Objects") - } - } - - retDatastores := make([]cloudprovider.ICloudStorage, 0, len(dss)) - for i := range dss { - retDatastores = append(retDatastores, NewDatastore(dc.manager, &dss[i], dc)) - } - return retDatastores, nil -} - -func (dc *SDatacenter) scanNetworks() error { - if dc.inetworks == nil { - if dc.isDefaultDc() { - return dc.scanDefaultNetworks() - } else { - return dc.scanDcNetworks() - } - } - return nil -} - -func (dc *SDatacenter) scanDefaultNetworks() error { - dc.inetworks = make([]IVMNetwork, 0) - err := dc.scanAllDvPortgroups() - if err != nil { - return errors.Wrap(err, "dc.scanAllDvPortgroups") - } - err = dc.scanAllNetworks() - if err != nil { - return errors.Wrap(err, "dc.scanAllNetworks") - } - return nil -} - -func (dc *SDatacenter) scanAllDvPortgroups() error { - var dvports []mo.DistributedVirtualPortgroup - - err := dc.manager.scanAllMObjects(DVPORTGROUP_PROPS, &dvports) - if err != nil { - return errors.Wrap(err, "dc.manager.scanAllMObjects mo.DistributedVirtualPortgroup") - } - for i := range dvports { - net := NewDistributedVirtualPortgroup(dc.manager, &dvports[i], dc) - dc.inetworks = append(dc.inetworks, net) - } - return nil -} - -func (dc *SDatacenter) scanAllNetworks() error { - var nets []mo.Network - - err := dc.manager.scanAllMObjects(NETWORK_PROPS, &nets) - if err != nil { - return errors.Wrap(err, "dc.manager.scanAllMObjects mo.Network") - } - for i := range nets { - net := NewNetwork(dc.manager, &nets[i], dc) - dc.inetworks = append(dc.inetworks, net) - } - return nil -} - -func (dc *SDatacenter) scanDcNetworks() error { - dc.inetworks = make([]IVMNetwork, 0) - - netMOBs := dc.getDatacenter().Network - for i := range netMOBs { - dvport := mo.DistributedVirtualPortgroup{} - err := dc.manager.reference2Object(netMOBs[i], DVPORTGROUP_PROPS, &dvport) - if err == nil { - net := NewDistributedVirtualPortgroup(dc.manager, &dvport, dc) - dc.inetworks = append(dc.inetworks, net) - } else { - net := mo.Network{} - err = dc.manager.reference2Object(netMOBs[i], NETWORK_PROPS, &net) - if err == nil { - vnet := NewNetwork(dc.manager, &net, dc) - dc.inetworks = append(dc.inetworks, vnet) - } else { - return errors.Wrap(err, "dc.manager.reference2Object") - } - } - } - return nil -} - -func (dc *SDatacenter) GetNetworks() ([]IVMNetwork, error) { - err := dc.scanNetworks() - if err != nil { - return nil, errors.Wrap(err, "dc.scanNetworks") - } - return dc.inetworks, nil -} - -func (dc *SDatacenter) GetTemplateVMs() ([]*SVirtualMachine, error) { - hosts, err := dc.GetIHosts() - if err != nil { - return nil, errors.Wrap(err, "SDatacenter.GetIHosts") - } - templateVms := make([]*SVirtualMachine, 5) - for _, ihost := range hosts { - host := ihost.(*SHost) - tvms, err := host.GetTemplateVMs() - if err != nil { - return nil, errors.Wrap(err, "host.GetTemplateVMs") - } - templateVms = append(templateVms, tvms...) - } - return templateVms, nil -} diff --git a/pkg/multicloud/esxi/doc.go b/pkg/multicloud/esxi/doc.go deleted file mode 100644 index ddd8f7eda8..0000000000 --- a/pkg/multicloud/esxi/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi // import "yunion.io/x/onecloud/pkg/multicloud/esxi" diff --git a/pkg/multicloud/esxi/host.go b/pkg/multicloud/esxi/host.go deleted file mode 100644 index d4406ab697..0000000000 --- a/pkg/multicloud/esxi/host.go +++ /dev/null @@ -1,1769 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "context" - "fmt" - "regexp" - "strings" - - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/types" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - "yunion.io/x/pkg/util/regutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var ( - hostConfigProps = []string{"config.network", "config.storageDevice"} - hostSummaryProps = []string{"summary.runtime", "summary.hardware", "summary.config.product", "summary.managementServerIp"} - hostHardWareProps = []string{"hardware.systemInfo"} -) - -var HOST_SYSTEM_PROPS []string - -func init() { - HOST_SYSTEM_PROPS = []string{"name", "parent", "vm", "datastore", "network"} - HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostConfigProps...) - HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostSummaryProps...) - HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostHardWareProps...) -} - -type SHostStorageAdapterInfo struct { - Device string - Model string - Driver string - Pci string - Drivers []*SHostStorageDriverInfo - Enclosure int -} - -type SHostStorageDriverInfo struct { - CN string - Name string - Model string - Vendor string - Revision string - Status string - SSD bool - Dev string - Size int - Slot int -} - -type SHostStorageEnclosureInfo struct { - CN string - Name string - Model string - Vendor string - Revision string - Status string -} - -type SHostStorageInfo struct { - Adapter int - Driver string - Index int - Model string - Rotate bool - Status string - Size int -} - -type SHost struct { - multicloud.SHostBase - SManagedObject - - masterIp string - - nicInfo []SHostNicInfo - storageInfo []SHostStorageInfo - datastores []cloudprovider.ICloudStorage - storageCache *SDatastoreImageCache - vms []cloudprovider.ICloudVM - parent *mo.ComputeResource - networks []IVMNetwork - tempalteVMs []*SVirtualMachine -} - -func NewHost(manager *SESXiClient, host *mo.HostSystem, dc *SDatacenter) *SHost { - if host.Config == nil { - log.Errorf("empty host config %s", host.Name) - return nil - } - return &SHost{SManagedObject: newManagedObject(manager, host, dc)} -} - -var ( - ip4addrPattern = regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`) -) - -func formatName(name string) string { - if ip4addrPattern.MatchString(name) { - return strings.Replace(name, ".", "-", -1) - } else { - dotPos := strings.IndexByte(name, '.') - if dotPos > 0 && !regutils.MatchIP4Addr(name) { - name = name[:dotPos] - } - return name - } -} - -func (self *SHost) GetName() string { - return formatName(self.SManagedObject.GetName()) -} - -func (self *SHost) GetSchedtags() ([]string, error) { - clusters, err := self.datacenter.listClusters() - if err != nil { - return nil, err - } - cpName := self.datacenter.manager.cpcfg.Name - reference := self.GetoHostSystem().Reference() - tags := make([]string, 0, 1) - oDatacenter := self.datacenter.getDatacenter() -Loop: - for i := range clusters { - oc := clusters[i].getoCluster() - if len(oc.Host) == 0 { - continue - } - for _, h := range oc.Host { - if h == reference { - tags = append(tags, fmt.Sprintf("cluster:/%s/%s/%s", cpName, oDatacenter.Name, oc.Name)) - continue Loop - } - } - } - return tags, nil -} - -func (self *SHost) getHostSystem() *mo.HostSystem { - return self.object.(*mo.HostSystem) -} - -func (self *SHost) GetGlobalId() string { - return self.GetAccessIp() -} - -func (self *SHost) GetStatus() string { - /* - HostSystemPowerStatePoweredOn = HostSystemPowerState("poweredOn") - HostSystemPowerStatePoweredOff = HostSystemPowerState("poweredOff") - HostSystemPowerStateStandBy = HostSystemPowerState("standBy") - HostSystemPowerStateUnknown = HostSystemPowerState("unknown") - */ - switch self.getHostSystem().Summary.Runtime.PowerState { - case types.HostSystemPowerStatePoweredOn: - return api.HOST_STATUS_RUNNING - case types.HostSystemPowerStatePoweredOff: - return api.HOST_STATUS_READY - default: - return api.HOST_STATUS_UNKNOWN - } -} - -func (self *SHost) Refresh() error { - base := self.SManagedObject - var moObj mo.HostSystem - err := self.manager.reference2Object(self.object.Reference(), HOST_SYSTEM_PROPS, &moObj) - if err != nil { - return err - } - base.object = &moObj - *self = SHost{} - self.SManagedObject = base - return nil -} - -func (self *SHost) IsEmulated() bool { - return false -} - -func (self *SHost) fetchVMs(all bool) error { - if self.vms != nil { - return nil - } - - dc, err := self.GetDatacenter() - if err != nil { - return err - } - - var vms []*SVirtualMachine - hostVms := self.getHostSystem().Vm - if len(hostVms) == 0 { - // log.Errorf("host VMs are nil!!!!!") - return nil - } - - vms, err = dc.fetchVms(hostVms, all) - if err != nil { - return err - } - for _, vm := range vms { - if vm.IsTemplate() { - self.tempalteVMs = append(self.tempalteVMs, vm) - } else { - self.vms = append(self.vms, vm) - } - } - return nil -} - -func (self *SHost) GetIVMs2() ([]cloudprovider.ICloudVM, error) { - err := self.fetchVMs(true) - if err != nil { - return nil, err - } - return self.vms, nil -} - -func (self *SHost) GetTemplateVMs() ([]*SVirtualMachine, error) { - err := self.fetchVMs(false) - if err != nil { - return nil, errors.Wrap(err, "SHost.fetchVMs") - } - return self.tempalteVMs, nil -} - -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - err := self.fetchVMs(false) - if err != nil { - return nil, err - } - return self.vms, nil -} - -func (self *SHost) GetTemplateVMById(id string) (*SVirtualMachine, error) { - id = self.manager.getPrivateId(id) - temVms, err := self.GetTemplateVMs() - if err != nil { - return nil, err - } - for i := range temVms { - if temVms[i].GetGlobalId() == id { - return temVms[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - id = self.manager.getPrivateId(id) - - vms, err := self.GetIVMs() - if err != nil { - return nil, err - } - for i := 0; i < len(vms); i += 1 { - if vms[i].GetGlobalId() == id { - return vms[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - return self.GetDataStores() -} - -func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - istorages, err := self.GetIStorages() - if err != nil { - return nil, err - } - for i := 0; i < len(istorages); i += 1 { - if istorages[i].GetGlobalId() == id { - return istorages[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHost) GetEnabled() bool { - if self.getHostSystem().Summary.Runtime.InMaintenanceMode { - return false - } - return true -} - -func (self *SHost) GetHostStatus() string { - /* - HostSystemConnectionStateConnected = HostSystemConnectionState("connected") - HostSystemConnectionStateNotResponding = HostSystemConnectionState("notResponding") - HostSystemConnectionStateDisconnected = HostSystemConnectionState("disconnected") - */ - if self.getHostSystem().Summary.Runtime.InMaintenanceMode { - return api.HOST_OFFLINE - } - switch self.getHostSystem().Summary.Runtime.ConnectionState { - case types.HostSystemConnectionStateConnected: - return api.HOST_ONLINE - default: - return api.HOST_OFFLINE - } -} - -func findHostNicByMac(nicInfoList []SHostNicInfo, mac string) *SHostNicInfo { - for i := 0; i < len(nicInfoList); i += 1 { - if nicInfoList[i].Mac == mac { - return &nicInfoList[i] - } - } - return nil -} - -func (self *SHost) getAdminNic() *SHostNicInfo { - nics := self.getNicInfo(false) - for i := 0; i < len(nics); i += 1 { - if nics[i].NicType == api.NIC_TYPE_ADMIN { - return &nics[i] - } - } - for i := 0; i < len(nics); i += 1 { - if len(nics[i].IpAddr) > 0 { - return &nics[i] - } - } - return nil -} - -func (self *SHost) getNicInfo(debug bool) []SHostNicInfo { - if self.nicInfo == nil { - self.nicInfo = self.fetchNicInfo(debug) - } - return self.nicInfo -} - -func mask2len(mask string) int8 { - maskAddr, _ := netutils.NewIPV4Addr(mask) - return netutils.Mask2Len(maskAddr) -} - -func (self *SHost) isVnicAdmin(nic types.HostVirtualNic) bool { - if len(self.masterIp) > 0 { - if self.masterIp == nic.Spec.Ip.IpAddress { - return true - } else { - return false - } - } - exist, err := self.manager.IsHostIpExists(nic.Spec.Ip.IpAddress) - if err != nil { - log.Errorf("IsHostIpExists %s fail %s", nic.Spec.Ip.IpAddress, err) - return false - } - if exist { - self.masterIp = nic.Spec.Ip.IpAddress - return true - } - return false -} - -func (self *SHost) fetchNicInfo(debug bool) []SHostNicInfo { - moHost := self.getHostSystem() - - if moHost.Config == nil || moHost.Config.Network == nil { - return nil - } - - if debug { - log.Debugf("%s", jsonutils.Marshal(moHost.Config.Network).PrettyString()) - } - - nicInfoList := make([]SHostNicInfo, 0) - - for i, nic := range moHost.Config.Network.Pnic { - info := SHostNicInfo{} - info.Dev = nic.Device - info.Driver = nic.Driver - info.Mac = netutils.FormatMacAddr(nic.Mac) - info.Index = int8(i) - info.LinkUp = false - nicInfoList = append(nicInfoList, info) - } - - vnics := make([]types.HostVirtualNic, 0) - if len(moHost.Config.Network.Vnic) > 0 { - vnics = append(vnics, moHost.Config.Network.Vnic...) - } - if len(moHost.Config.Network.ConsoleVnic) > 0 { - vnics = append(vnics, moHost.Config.Network.ConsoleVnic...) - } - - for _, nic := range vnics { - mac := netutils.FormatMacAddr(nic.Spec.Mac) - pnic := findHostNicByMac(nicInfoList, mac) - if pnic != nil { - // findMaster = true - pnic.IpAddr = nic.Spec.Ip.IpAddress - pnic.IpAddrPrefixLen = mask2len(nic.Spec.Ip.SubnetMask) - if nic.Spec.Ip.IpV6Config != nil && len(nic.Spec.Ip.IpV6Config.IpV6Address) > 0 { - pnic.IpAddr6 = nic.Spec.Ip.IpV6Config.IpV6Address[0].IpAddress - pnic.IpAddr6PrefixLen = int8(nic.Spec.Ip.IpV6Config.IpV6Address[0].PrefixLength) - } - if self.isVnicAdmin(nic) { - pnic.NicType = api.NIC_TYPE_ADMIN - } - pnic.LinkUp = true - pnic.Mtu = nic.Spec.Mtu - if nic.Spec.DistributedVirtualPort != nil { - pnic.DVPortGroup = nic.Spec.DistributedVirtualPort.PortgroupKey - } - } else { - info := SHostNicInfo{} - info.Dev = nic.Device - info.Driver = "vmkernel" - info.Mac = mac - info.Index = int8(len(nicInfoList)) - info.LinkUp = true - info.IpAddr = nic.Spec.Ip.IpAddress - info.IpAddrPrefixLen = mask2len(nic.Spec.Ip.SubnetMask) - if nic.Spec.Ip.IpV6Config != nil && len(nic.Spec.Ip.IpV6Config.IpV6Address) > 0 { - info.IpAddr6 = nic.Spec.Ip.IpV6Config.IpV6Address[0].IpAddress - info.IpAddr6PrefixLen = int8(nic.Spec.Ip.IpV6Config.IpV6Address[0].PrefixLength) - } - info.Mtu = nic.Spec.Mtu - if self.isVnicAdmin(nic) { - info.NicType = api.NIC_TYPE_ADMIN - } - if nic.Spec.DistributedVirtualPort != nil { - info.DVPortGroup = nic.Spec.DistributedVirtualPort.PortgroupKey - } - nicInfoList = append(nicInfoList, info) - } - } - - return nicInfoList -} - -func (self *SHost) GetAccessIp() string { - adminNic := self.getAdminNic() - if adminNic != nil { - return adminNic.IpAddr - } - return "" -} - -func (self *SHost) GetAccessMac() string { - adminNic := self.getAdminNic() - if adminNic != nil { - return adminNic.Mac - } - return "" -} - -type SSysInfo struct { - Manufacture string - Model string - SerialNumber string -} - -func (self *SHost) GetSysInfo() jsonutils.JSONObject { - sysinfo := SSysInfo{} - host := self.getHostSystem() - sysinfo.Manufacture = host.Summary.Hardware.Vendor - sysinfo.Model = host.Summary.Hardware.Model - if host.Hardware != nil { - sysinfo.SerialNumber = host.Hardware.SystemInfo.SerialNumber - } - return jsonutils.Marshal(&sysinfo) -} - -func (self *SHost) GetSN() string { - host := self.getHostSystem() - if host.Hardware != nil { - return host.Hardware.SystemInfo.SerialNumber - } - return "" -} - -func (self *SHost) GetCpuCount() int { - return int(self.getHostSystem().Summary.Hardware.NumCpuThreads) -} - -func (self *SHost) GetNodeCount() int8 { - return int8(self.getHostSystem().Summary.Hardware.NumCpuPkgs) -} - -func (self *SHost) GetCpuDesc() string { - return self.getHostSystem().Summary.Hardware.CpuModel -} - -func (self *SHost) GetCpuMhz() int { - return int(self.getHostSystem().Summary.Hardware.CpuMhz) -} - -func (self *SHost) GetMemSizeMB() int { - return int(self.getHostSystem().Summary.Hardware.MemorySize / 1024 / 1024) -} - -func (self *SHost) GetStorageInfo() []SHostStorageInfo { - if self.storageInfo == nil { - self.storageInfo = self.getStorageInfo() - } - return self.storageInfo -} - -func (self *SHost) getStorageInfo() []SHostStorageInfo { - diskSlots := make(map[int]SHostStorageInfo) - list := self.getStorages() - for i := 0; i < len(list); i += 1 { - for j := 0; j < len(list[i].Drivers); j += 1 { - drv := list[i].Drivers[j] - info := SHostStorageInfo{ - Adapter: 0, - Driver: "Linux", - Index: drv.Slot, - Model: strings.TrimSpace(fmt.Sprintf("%s %s", drv.Vendor, drv.Model)), - Rotate: !drv.SSD, - Status: drv.Status, - Size: drv.Size, - } - diskSlots[info.Index] = info - } - } - disks := make([]SHostStorageInfo, 0) - idx := 0 - for { - if info, ok := diskSlots[idx]; ok { - disks = append(disks, info) - idx += 1 - } else { - break - } - } - return disks -} - -func (self *SHost) getStorages() []*SHostStorageAdapterInfo { - adapterList := make([]*SHostStorageAdapterInfo, 0) - adapterTable := make(map[string]*SHostStorageAdapterInfo) - driversTable := make(map[string]*SHostStorageDriverInfo, 0) - enclosuresTable := make(map[string]*SHostStorageEnclosureInfo, 0) - moHost := self.getHostSystem() - - for i := 0; i < len(moHost.Config.StorageDevice.HostBusAdapter); i += 1 { - ad := moHost.Config.StorageDevice.HostBusAdapter[i] - adinfo := ad.GetHostHostBusAdapter() - if adinfo == nil { - log.Errorf("fail to GetHostHostBusAdapter") - continue - } - info := SHostStorageAdapterInfo{} - info.Device = adinfo.Device - info.Model = strings.TrimSpace(adinfo.Model) - info.Driver = adinfo.Driver - info.Pci = adinfo.Pci - info.Drivers = make([]*SHostStorageDriverInfo, 0) - info.Enclosure = -1 - - adapterTable[adinfo.Key] = &info - adapterList = append(adapterList, &info) - } - - for i := 0; i < len(moHost.Config.StorageDevice.ScsiLun); i += 1 { - drv := moHost.Config.StorageDevice.ScsiLun[i] - lunInfo := drv.GetScsiLun() - if lunInfo == nil { - log.Errorf("fail to GetScsiLun") - continue - } - - if lunInfo.DeviceType == "disk" { - scsiDisk := drv.(*types.HostScsiDisk) - info := SHostStorageDriverInfo{} - info.CN = scsiDisk.CanonicalName - info.Name = scsiDisk.DisplayName - info.Model = strings.TrimSpace(scsiDisk.Model) - info.Vendor = strings.TrimSpace(scsiDisk.Vendor) - info.Revision = scsiDisk.Revision - info.Status = scsiDisk.OperationalState[0] - if scsiDisk.Ssd != nil && *scsiDisk.Ssd { - info.SSD = true - } - info.Dev = scsiDisk.DevicePath - info.Size = int(int64(scsiDisk.Capacity.BlockSize) * scsiDisk.Capacity.Block / 1024 / 1024) - - driversTable[scsiDisk.Key] = &info - } else if lunInfo.DeviceType == "enclosure" { - enclosuresTable[lunInfo.Key] = &SHostStorageEnclosureInfo{ - CN: lunInfo.CanonicalName, - Name: lunInfo.DisplayName, - Model: strings.TrimSpace(lunInfo.Model), - Vendor: strings.TrimSpace(lunInfo.Vendor), - Revision: lunInfo.Revision, - Status: lunInfo.OperationalState[0], - } - } - } - for i := 0; i < len(moHost.Config.StorageDevice.ScsiTopology.Adapter); i += 1 { - ad := moHost.Config.StorageDevice.ScsiTopology.Adapter[i] - adapter := adapterTable[ad.Adapter] - for j := 0; j < len(ad.Target); j += 1 { - t := ad.Target[j] - key := t.Lun[0].ScsiLun - if _, ok := enclosuresTable[key]; ok { - adapter.Enclosure = int(t.Target) - } else if _, ok := driversTable[key]; ok { - driver := driversTable[key] - driver.Slot = int(t.Target) - adapter.Drivers = append(adapter.Drivers, driver) - } - } - } - return adapterList -} - -func (self *SHost) GetStorageSizeMB() int { - storages, err := self.GetIStorages() - if err != nil { - log.Errorf("SHost.GetStorageSizeMB: SHost.GetIStorages: %s", err) - return 0 - } - var size int64 - for _, stor := range storages { - size += stor.GetCapacityMB() - } - return int(size) -} - -func (self *SHost) GetStorageType() string { - ssd := 0 - rotate := 0 - storages := self.GetStorageInfo() - for i := 0; i < len(storages); i += 1 { - if storages[i].Rotate { - rotate += 1 - } else { - ssd += 1 - } - } - if ssd == 0 && rotate > 0 { - return api.DISK_TYPE_ROTATE - } else if ssd > 0 && rotate == 0 { - return api.DISK_TYPE_SSD - } else { - return api.DISK_TYPE_HYBRID - } -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_ESXI -} - -func (self *SHost) GetIsMaintenance() bool { - moHost := self.getHostSystem() - return moHost.Summary.Runtime.InMaintenanceMode -} - -func (self *SHost) GetVersion() string { - moHost := self.getHostSystem() - about := moHost.Summary.Config.Product - return fmt.Sprintf("%s-%s", about.Version, about.Build) -} - -func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - return nil, cloudprovider.ErrNotImplemented -} - -type SCreateVMParam struct { - Name string - Uuid string - OsName string - Cpu int - Mem int - Bios string - Cdrom SCdromInfo - Disks []SDiskInfo - Nics []jsonutils.JSONObject - ResourcePool string - InstanceSnapshotInfo SEsxiInstanceSnapshotInfo -} - -type SEsxiInstanceSnapshotInfo struct { - InstanceSnapshotId string - InstanceId string -} - -type SCdromInfo struct { - ImageId string - Path string - Name string - Size string -} - -type SDiskInfo struct { - ImagePath string - Size int64 - DiskId string - Driver string - ImageInfo SEsxiImageInfo - StorageId string -} - -type SEsxiImageInfo struct { - ImageType string - ImageExternalId string - StorageCacheHostIp string -} - -func (self *SHost) CreateVM2(ctx context.Context, ds *SDatastore, params SCreateVMParam) (needDeploy bool, vm *SVirtualMachine, err error) { - needDeploy = true - var temvm *SVirtualMachine - if len(params.InstanceSnapshotInfo.InstanceSnapshotId) > 0 { - temvm, err = self.manager.SearchVM(params.InstanceSnapshotInfo.InstanceId) - if err != nil { - err = errors.Wrapf(err, "can't find vm %q, please sync status for vm or sync cloudaccount", params.InstanceSnapshotInfo.InstanceId) - } - var isp cloudprovider.ICloudInstanceSnapshot - isp, err = temvm.GetInstanceSnapshot(params.InstanceSnapshotInfo.InstanceSnapshotId) - if err != nil { - err = errors.Wrap(err, "unable to GetInstanceSnapshot") - return - } - sp := isp.(*SVirtualMachineSnapshot) - vm, err = self.CloneVM(ctx, temvm, &sp.snapshotTree.Snapshot, ds, params) - return - } - if len(params.Disks) == 0 { - err = errors.Error("empty disk config") - return - } - imageInfo := params.Disks[0].ImageInfo - if imageInfo.ImageType == string(cloudprovider.ImageTypeSystem) { - temvm, err = self.manager.SearchTemplateVM(imageInfo.ImageExternalId) - if err != nil { - err = errors.Wrapf(err, "SEsxiClient.SearchTemplateVM for image %q", imageInfo.ImageExternalId) - return - } - vm, err = self.CloneVM(ctx, temvm, nil, ds, params) - return - } - return self.DoCreateVM(ctx, ds, params) -} - -func (self *SHost) needScsi(disks []SDiskInfo) bool { - if len(disks) == 0 { - return false - } - for i := range disks { - driver := disks[i].Driver - if driver == "" || driver == "scsi" || driver == "pvscsi" { - return true - } - } - return false -} - -func (self *SHost) addDisks(ctx context.Context, dc *SDatacenter, ds *SDatastore, disks []SDiskInfo, uuid string, objectVm *object.VirtualMachine) (*SVirtualMachine, error) { - getVM := func() (*SVirtualMachine, error) { - var moVM mo.VirtualMachine - err := self.manager.reference2Object(objectVm.Reference(), VIRTUAL_MACHINE_PROPS, &moVM) - if err != nil { - return nil, errors.Wrap(err, "fail to fetch virtual machine just created") - } - - evm := NewVirtualMachine(self.manager, &moVM, self.datacenter) - if evm == nil { - return nil, errors.Error("create successfully but unable to NewVirtualMachine") - } - return evm, nil - } - - if len(disks) == 0 { - return getVM() - } - - var ( - scsiIdx = 0 - ideIdx = 0 - ide1un = 0 - ide2un = 1 - unitNumber = 0 - ctrlKey = 0 - ) - deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 1) - // add disks - var rootDiskSizeMb int64 - for i, disk := range disks { - imagePath := disk.ImagePath - var size = disk.Size - if len(imagePath) == 0 { - if size == 0 { - size = 30 * 1024 - } - } else { - var err error - imagePath, err = self.FileUrlPathToDsPath(imagePath) - if err != nil { - return nil, errors.Wrapf(err, "SHost.FileUrlPathToDsPath") - } - newImagePath := fmt.Sprintf("[%s] %s/%s.vmdk", ds.GetRelName(), uuid, uuid) - - err = self.copyVirtualDisk(imagePath, newImagePath, disk.Driver) - if err != nil { - return nil, err - } - imagePath = newImagePath - rootDiskSizeMb = size - } - uuid, driver := disk.DiskId, "scsi" - if len(disk.Driver) > 0 { - driver = disk.Driver - } - if driver == "scsi" || driver == "pvscsi" { - if self.isVersion50() { - driver = "scsi" - } - ctrlKey = 1000 - unitNumber = scsiIdx - scsiIdx += 1 - if scsiIdx == 7 { - scsiIdx++ - } - } else { - ideno := ideIdx % 2 - if ideno == 0 { - unitNumber = ideIdx/2 + ide1un - } else { - unitNumber = ideIdx/2 + ide2un - } - ctrlKey = 200 + ideno - ideIdx += 1 - } - var tds *SDatastore - var err error - if disk.StorageId != "" { - tds, err = self.FindDataStoreById(disk.StorageId) - if err != nil { - return nil, errors.Wrapf(err, "unable to find ds %s from host %s", disk.StorageId, self.masterIp) - } - } else { - tds = ds - } - log.Debugf("ds: %s, size: %d, image path: %s, uuid: %s, index: %d, ctrlKey: %d, driver: %s, key: %d.", tds.getDatastoreObj().String(), size, imagePath, uuid, unitNumber, ctrlKey, disk.Driver, 2000+i) - spec := addDevSpec(NewDiskDev(size, SDiskConfig{ - SizeMb: size, - Uuid: uuid, - ControllerKey: int32(ctrlKey), - UnitNumber: int32(unitNumber), - Key: int32(2000 + i), - ImagePath: imagePath, - IsRoot: i == 0, - Datastore: tds, - })) - if len(imagePath) == 0 { - spec.FileOperation = "create" - } - deviceChange = append(deviceChange, spec) - } - log.Infof("deviceChange: %s", jsonutils.Marshal(deviceChange)) - - configSpec := types.VirtualMachineConfigSpec{} - configSpec.DeviceChange = deviceChange - task, err := objectVm.Reconfigure(ctx, configSpec) - if err != nil { - return nil, errors.Wrap(err, "unable to reconfigure") - } - err = task.Wait(ctx) - if err != nil { - return nil, errors.Wrap(err, "task.Wait") - } - - evm, err := getVM() - if err != nil { - return nil, err - } - - // resize root disk - if rootDiskSizeMb > 0 && int64(evm.vdisks[0].GetDiskSizeMB()) != rootDiskSizeMb { - err = evm.vdisks[0].Resize(ctx, rootDiskSizeMb) - if err != nil { - return evm, errors.Wrap(err, "resize for root disk") - } - } - return evm, nil -} - -func (self *SHost) copyVirtualDisk(srcPath, dstPath, diskDriver string) error { - dm := object.NewVirtualDiskManager(self.manager.client.Client) - spec := &types.VirtualDiskSpec{ - DiskType: "thin", - } - switch diskDriver { - case "", "scsi", "pvscsi": - spec.AdapterType = "lsiLogic" - default: - spec.AdapterType = "ide" - } - task, err := dm.CopyVirtualDisk(self.manager.context, srcPath, self.datacenter.getDcObj(), dstPath, self.datacenter.getDcObj(), spec, true) - if err != nil { - return errors.Wrap(err, "unable to CopyVirtualDisk") - } - err = task.Wait(self.manager.context) - if err == nil { - return nil - } - errStr := strings.ToLower(err.Error()) - if !strings.Contains(errStr, "the requested operation is not implemented by the server") { - return errors.Wrap(err, "wait CopyVirtualDiskTask") - } - task, err = dm.CopyVirtualDisk(self.manager.context, srcPath, self.datacenter.getDcObj(), dstPath, self.datacenter.getDcObj(), nil, true) - if err != nil { - return errors.Wrap(err, "unable to CopyVirtualDisk") - } - err = task.Wait(self.manager.context) - if err != nil { - return errors.Wrap(err, "wait CopyVirtualDiskTask") - } - return nil -} - -func (self *SHost) DoCreateVM(ctx context.Context, ds *SDatastore, params SCreateVMParam) (needDeploy bool, vm *SVirtualMachine, err error) { - needDeploy = true - deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 5) - - // uuid first - name := params.Name - if len(params.Uuid) != 0 { - name = params.Uuid - } - datastorePath := fmt.Sprintf("[%s] ", ds.GetRelName()) - - firmware := "" - if len(params.Bios) != 0 { - if params.Bios == "BIOS" { - firmware = "bios" - } else if params.Bios == "UEFI" { - firmware = "efi" - } - } - - guestId := "rhel6_64Guest" - if params.OsName == "Windows" { - guestId = "windows7Server64Guest" - } - - version := "vmx-10" - if self.isVersion50() { - version = "vmx-08" - } - - spec := types.VirtualMachineConfigSpec{ - Name: name, - Version: version, - Uuid: params.Uuid, - GuestId: guestId, - NumCPUs: int32(params.Cpu), - MemoryMB: int64(params.Mem), - Firmware: firmware, - } - spec.Files = &types.VirtualMachineFileInfo{ - VmPathName: datastorePath, - } - - deviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 0))) - deviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 1))) - deviceChange = append(deviceChange, addDevSpec(NewSVGADev(500, 100))) - - if self.needScsi(params.Disks) { - driver := "pvscsi" - if self.isVersion50() { - driver = "scsi" - } - deviceChange = append(deviceChange, addDevSpec(NewSCSIDev(1000, 100, driver))) - } - cdromPath := params.Cdrom.Path - if len(cdromPath) > 0 { - needDeploy = false - cdromPath, err = self.FileUrlPathToDsPath(cdromPath) - if err != nil { - err = errors.Wrapf(err, "SHost.FileUrlPathToDsPath for cdrom path") - return - } - } - deviceChange = append(deviceChange, addDevSpec(NewCDROMDev(cdromPath, 16000, 201))) - - // add usb to support mouse - usbController := addDevSpec(NewUSBController(nil)) - deviceChange = append(deviceChange, usbController) - - nics := params.Nics - for _, nic := range nics { - index, _ := nic.Int("index") - mac, _ := nic.GetString("mac") - bridge, _ := nic.GetString("bridge") - driver := "e1000" - if nic.Contains("driver") { - driver, _ = nic.GetString("driver") - } - if self.isVersion50() { - driver = "e1000" - } - var vlanId int64 = 1 - if nic.Contains("vlan") { - vlanId, _ = nic.Int("vlan") - } - dev, err := NewVNICDev(self, mac, driver, bridge, int32(vlanId), 4000, 100, int32(index)) - if err != nil { - return needDeploy, nil, errors.Wrap(err, "NewVNICDev") - } - deviceChange = append(deviceChange, addDevSpec(dev)) - } - - spec.DeviceChange = deviceChange - dc, err := self.GetDatacenter() - if err != nil { - err = errors.Wrapf(err, "SHost.GetDatacenter for host '%s'", self.GetId()) - return - } - // get vmFloder - folders, err := dc.getObjectDatacenter().Folders(ctx) - if err != nil { - err = errors.Wrap(err, "object.DataCenter.Folders") - return - } - vmFolder := folders.VmFolder - resourcePool, err := self.SyncResourcePool(params.ResourcePool) - if err != nil { - err = errors.Wrap(err, "SyncResourcePool") - return - } - task, err := vmFolder.CreateVM(ctx, spec, resourcePool, self.GetoHostSystem()) - if err != nil { - err = errors.Wrap(err, "VmFolder.Create") - return - } - - info, err := task.WaitForResult(ctx, nil) - if err != nil { - err = errors.Wrap(err, "Task.WaitForResult") - return - } - vmRef := info.Result.(types.ManagedObjectReference) - objectVM := object.NewVirtualMachine(self.manager.client.Client, vmRef) - vm, err = self.addDisks(ctx, dc, ds, params.Disks, params.Uuid, objectVM) - return -} - -// If snapshot is not nil, params.Disks will be ignored -func (host *SHost) CloneVM(ctx context.Context, from *SVirtualMachine, snapshot *types.ManagedObjectReference, ds *SDatastore, params SCreateVMParam) (*SVirtualMachine, error) { - ovm := from.getVmObj() - - deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 3) - - addDeviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 3) - - // change nic if set - if params.Nics != nil && len(params.Nics) > 0 { - // get origin nics - originNics := make([]types.BaseVirtualDevice, 0, 1) - for _, nic := range from.vnics { - originNics = append(originNics, nic.getVirtualEthernetCard()) - } - nicIndex := 0 - nics := params.Nics - for _, nic := range nics { - index, _ := nic.Int("index") - mac, _ := nic.GetString("mac") - bridge, _ := nic.GetString("bridge") - driver := "e1000" - if nic.Contains("driver") { - driver, _ = nic.GetString("driver") - } - if host.isVersion50() { - driver = "e1000" - } - var vlanId int64 = 1 - if nic.Contains("vlan") { - vlanId, _ = nic.Int("vlan") - } - dev, err := NewVNICDev(host, mac, driver, bridge, int32(vlanId), 4000, 100, int32(index)) - if err != nil { - return nil, errors.Wrap(err, "NewVNICDev") - } - op := types.VirtualDeviceConfigSpecOperationAdd - if nicIndex < len(originNics) { - // edit - op = types.VirtualDeviceConfigSpecOperationEdit - host.changeNic(originNics[nicIndex], dev) - dev = originNics[nicIndex] - deviceChange = append(deviceChange, &types.VirtualDeviceConfigSpec{ - Operation: op, - Device: dev, - }) - } else { - addDeviceChange = append(addDeviceChange, &types.VirtualDeviceConfigSpec{ - Operation: op, - Device: dev, - }) - } - nicIndex += 1 - } - } - - if len(params.Disks) > 0 && snapshot == nil { - driver := params.Disks[0].Driver - if driver == "scsi" || driver == "pvscsi" { - scsiDevs, err := from.FindController(ctx, "scsi") - if err != nil { - return nil, errors.Wrap(err, "SVirtualMachine.FindController") - } - if len(scsiDevs) == 0 { - key := from.FindMinDiffKey(1000) - driver := "pvscsi" - if host.isVersion50() { - driver = "scsi" - } - addDeviceChange = append(deviceChange, addDevSpec(NewSCSIDev(key, 100, driver))) - } - } else { - ideDevs, err := from.FindController(ctx, "ide") - if err != nil { - return nil, errors.Wrap(err, "SVirtualMachine.FindController") - } - if len(ideDevs) == 0 { - // add ide driver - addDeviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 0))) - addDeviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 1))) - } - } - } - - dc, err := host.GetDatacenter() - if err != nil { - return nil, errors.Wrapf(err, "SHost.GetDatacenter for host '%s'", host.GetId()) - } - // get vmFloder - folders, err := dc.getObjectDatacenter().Folders(ctx) - if err != nil { - return nil, errors.Wrap(err, "object.DataCenter.Folders") - } - resourcePool, err := host.SyncResourcePool(params.ResourcePool) - if err != nil { - return nil, errors.Wrap(err, "SyncResourcePool") - } - - folderref := folders.VmFolder.Reference() - poolref := resourcePool.Reference() - hostref := host.GetoHostSystem().Reference() - dsref := ds.getDatastoreObj().Reference() - relocateSpec := types.VirtualMachineRelocateSpec{ - DeviceChange: deviceChange, - Folder: &folderref, - Pool: &poolref, - Host: &hostref, - Datastore: &dsref, - } - cloneSpec := &types.VirtualMachineCloneSpec{ - PowerOn: false, - Template: false, - Location: relocateSpec, - Snapshot: snapshot, - } - - // uuid first - name := params.Name - if len(params.Uuid) != 0 { - name = params.Uuid - } - spec := types.VirtualMachineConfigSpec{ - Name: name, - Uuid: params.Uuid, - NumCPUs: int32(params.Cpu), - MemoryMB: int64(params.Mem), - } - cloneSpec.Config = &spec - task, err := ovm.Clone(ctx, folders.VmFolder, name, *cloneSpec) - if err != nil { - return nil, errors.Wrap(err, "object.VirtualMachine.Clone") - } - info, err := task.WaitForResult(ctx, nil) - if err != nil { - return nil, errors.Wrap(err, "Task.WaitForResult") - } - - var moVM mo.VirtualMachine - err = host.manager.reference2Object(info.Result.(types.ManagedObjectReference), VIRTUAL_MACHINE_PROPS, &moVM) - if err != nil { - return nil, errors.Wrap(err, "fail to fetch virtual machine just created") - } - - vm := NewVirtualMachine(host.manager, &moVM, host.datacenter) - if vm == nil { - return nil, errors.Error("clone successfully but unable to NewVirtualMachine") - } - - if snapshot != nil { - return vm, nil - } - - deviceChange = addDeviceChange - // adjust disk - var i int - if len(params.Disks) > 0 { - // resize system disk - sysDiskSize := params.Disks[0].Size - if sysDiskSize == 0 { - sysDiskSize = 30 * 1024 - } - if int64(vm.vdisks[0].GetDiskSizeMB()) != sysDiskSize { - vdisk := vm.vdisks[0].getVirtualDisk() - originSize := vdisk.CapacityInKB - vdisk.CapacityInKB = sysDiskSize * 1024 - spec := &types.VirtualDeviceConfigSpec{} - spec.Operation = types.VirtualDeviceConfigSpecOperationEdit - spec.Device = vdisk - deviceChange = append(deviceChange, spec) - log.Infof("resize system disk: %dGB => %dGB", originSize/1024/1024, sysDiskSize/1024) - } - // resize existed disk - for i = 1; i < len(params.Disks); i++ { - if i >= len(vm.vdisks) { - break - } - wantDisk := params.Disks[i] - vdisk := vm.vdisks[i] - modisk := vdisk.getVirtualDisk() - if wantDisk.Size <= int64(vdisk.GetDiskSizeMB()) { - continue - } - originSize := modisk.CapacityInKB - modisk.CapacityInKB = wantDisk.Size * 1024 - spec := &types.VirtualDeviceConfigSpec{} - spec.Operation = types.VirtualDeviceConfigSpecOperationEdit - spec.Device = vdisk.dev - deviceChange = append(deviceChange, spec) - log.Infof("resize No.%d data disk: %dGB => %dGB", i, originSize/1024/1024, wantDisk.Size/1024) - } - // remove extra disk - for ; i < len(vm.vdisks); i++ { - vdisk := vm.vdisks[i] - spec := &types.VirtualDeviceConfigSpec{} - spec.Operation = types.VirtualDeviceConfigSpecOperationRemove - spec.Device = vdisk.dev - spec.FileOperation = types.VirtualDeviceConfigSpecFileOperationDestroy - deviceChange = append(deviceChange, spec) - log.Infof("remove No.%d data disk", i) - } - if len(deviceChange) > 0 { - spec = types.VirtualMachineConfigSpec{} - spec.DeviceChange = deviceChange - task, err = vm.getVmObj().Reconfigure(ctx, spec) - if err != nil { - return vm, errors.Wrap(err, "Reconfigure to resize disks") - } - err = task.Wait(ctx) - if err != nil { - return vm, errors.Wrap(err, "Wait task to resize disks") - } - } - } - // add data disk - for ; i < len(params.Disks); i++ { - size := params.Disks[i].Size - if size == 0 { - size = 30 * 1024 - } - uuid := params.Disks[i].DiskId - driver := params.Disks[i].Driver - opts := &cloudprovider.GuestDiskCreateOptions{ - SizeMb: int(size), - UUID: uuid, - Driver: driver, - StorageId: params.Disks[i].StorageId, - } - _, err := vm.CreateDisk(ctx, opts) - if err != nil { - log.Errorf("unable to add No.%d disk for vm %s", i, vm.GetId()) - return vm, nil - } - } - return vm, nil -} - -func (host *SHost) changeNic(device types.BaseVirtualDevice, update types.BaseVirtualDevice) { - current := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() - changed := update.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() - - current.Backing = changed.Backing - if changed.MacAddress != "" { - current.MacAddress = changed.MacAddress - } - if changed.AddressType != "" { - current.AddressType = changed.AddressType - } -} - -func (host *SHost) isVersion50() bool { - version := host.GetVersion() - if strings.HasPrefix(version, "5.") { - return true - } - return false -} - -func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return host.GetIHostNicsInternal(false) -} - -func (host *SHost) GetIHostNicsInternal(debug bool) ([]cloudprovider.ICloudHostNetInterface, error) { - nics := host.getNicInfo(debug) - inics := make([]cloudprovider.ICloudHostNetInterface, len(nics)) - for i := 0; i < len(nics); i += 1 { - inics[i] = &nics[i] - } - return inics, nil -} - -func (host *SHost) getLocalStorageCache() (*SDatastoreImageCache, error) { - if host.storageCache == nil { - sc, err := host.newLocalStorageCache() - if err != nil { - return nil, err - } - host.storageCache = sc - } - return host.storageCache, nil -} - -func (host *SHost) newLocalStorageCache() (*SDatastoreImageCache, error) { - ctx := context.Background() - - istorages, err := host.GetIStorages() - if err != nil { - return nil, err - } - var errmsg string - var cacheDs *SDatastore - var maxDs *SDatastore - var maxCapacity int64 - for i := 0; i < len(istorages); i += 1 { - ds := istorages[i].(*SDatastore) - if !ds.isLocalVMFS() { - continue - } - _, err := ds.CheckFile(ctx, IMAGE_CACHE_DIR_NAME) - if err != nil { - if errors.Cause(err) != cloudprovider.ErrNotFound { - // return nil, err - if len(errmsg) > 0 { - errmsg += "," - } - errmsg += err.Error() - } else if maxCapacity < ds.GetCapacityMB() { - maxCapacity = ds.GetCapacityMB() - maxDs = ds - } - } else { - cacheDs = ds - break - } - } - if cacheDs == nil { - // if no existing image cache dir found, use the one with maximal capacilty - cacheDs = maxDs - } - - if cacheDs == nil { - return nil, fmt.Errorf(errmsg) - } - - return &SDatastoreImageCache{ - datastore: cacheDs, - host: host, - }, nil -} - -func (host *SHost) GetManagementServerIp() string { - return host.getHostSystem().Summary.ManagementServerIp -} - -func (host *SHost) IsManagedByVCenter() bool { - return len(host.getHostSystem().Summary.ManagementServerIp) > 0 -} - -func (host *SHost) FindDataStoreById(id string) (*SDatastore, error) { - datastores, err := host.GetDataStores() - if err != nil { - return nil, err - } - for i := range datastores { - if datastores[i].GetGlobalId() == id { - return datastores[i].(*SDatastore), nil - } - } - return nil, fmt.Errorf("no such datastore %s", id) -} - -func (host *SHost) GetDataStores() ([]cloudprovider.ICloudStorage, error) { - err := host.fetchDatastores() - if err != nil { - return nil, err - } - return host.datastores, nil -} - -func (host *SHost) fetchDatastores() error { - if host.datastores != nil { - return nil - } - - dc, err := host.GetDatacenter() - if err != nil { - return err - } - dss := host.getHostSystem().Datastore - var datastores []mo.Datastore - err = host.manager.references2Objects(dss, DATASTORE_PROPS, &datastores) - if err != nil { - return err - } - host.datastores = make([]cloudprovider.ICloudStorage, 0) - for i := 0; i < len(datastores); i += 1 { - ds := NewDatastore(host.manager, &datastores[i], dc) - dsId := ds.GetGlobalId() - if len(dsId) > 0 { - host.datastores = append(host.datastores, ds) - } - } - return nil -} - -func (host *SHost) FileUrlPathToDsPath(path string) (string, error) { - var newPath string - dss, err := host.GetDataStores() - if err != nil { - return newPath, err - } - for _, ds := range dss { - rds := ds.(*SDatastore) - log.Debugf("rds: %s", rds.GetUrl()) - if strings.HasPrefix(path, rds.GetUrl()) { - newPath = fmt.Sprintf("[%s] %s", rds.GetRelName(), path[len(rds.GetUrl()):]) - break - } - } - if len(newPath) == 0 { - return newPath, fmt.Errorf("path '%s' don't belong any datastore of host '%s'", path, host.GetName()) - } - return newPath, nil -} - -func (host *SHost) FindNetworkByVlanID(vlanID int32) (IVMNetwork, error) { - if host.IsActiveVlanID(vlanID) { - net, err := host.findBasicNetwork(vlanID) - if err != nil { - return nil, errors.Wrap(err, "findBasicNetwork error") - } - if net != nil { - return net, nil - } - - // no found in basic network - dvpg, err := host.findVlanDVPG(vlanID) - if err != nil { - return nil, errors.Wrap(err, "findVlanDVPG") - } - return dvpg, nil - } - n, err := host.findBasicNetwork(vlanID) - if err != nil { - return nil, errors.Wrap(err, "find Basic network") - } - if n != nil { - return n, err - } - return host.findNovlanDVPG() -} - -// IsActiveVlanID will detect if vlanID is active that means vlanID in (1, 4095). -func (host *SHost) IsActiveVlanID(vlanID int32) bool { - if vlanID > 1 && vlanID < 4095 { - return true - } - return false -} - -func (host *SHost) findBasicNetwork(vlanID int32) (IVMNetwork, error) { - nets, err := host.getBasicNetworks() - if err != nil { - return nil, err - } - if len(nets) == 0 { - return nil, nil - } - if !host.IsActiveVlanID(vlanID) { - return nets[0], nil - } - for i := range nets { - if nets[i].GetVlanId() == vlanID { - return nets[i], nil - } - } - return nil, nil -} - -func (host *SHost) getBasicNetworks() ([]IVMNetwork, error) { - nets, err := host.GetNetworks() - if err != nil { - return nil, errors.Wrap(err, "GetNetworks") - } - ret := make([]IVMNetwork, 0) - for i := range nets { - if net, ok := nets[i].(*SNetwork); ok { - ret = append(ret, net) - } - } - return ret, nil -} - -func (host *SHost) GetNetworks() ([]IVMNetwork, error) { - if host.networks != nil { - return host.networks, nil - } - netMobs := host.getHostSystem().Network - netPortMobs := make([]types.ManagedObjectReference, 0) - netNetMobs := make([]types.ManagedObjectReference, 0) - - for i := range netMobs { - log.Debugf("type: %s value: %s", netMobs[i].Type, netMobs[i].Value) - if netMobs[i].Type == "DistributedVirtualPortgroup" { - netPortMobs = append(netPortMobs, netMobs[i]) - } else { - netNetMobs = append(netNetMobs, netMobs[i]) - } - } - - nets := make([]IVMNetwork, 0) - - if len(netPortMobs) > 0 { - moPorts := make([]mo.DistributedVirtualPortgroup, 0) - err := host.manager.references2Objects(netPortMobs, DVPORTGROUP_PROPS, &moPorts) - if err != nil { - return nil, errors.Wrap(err, "references2Objects") - } - for i := range moPorts { - port := NewDistributedVirtualPortgroup(host.manager, &moPorts[i], host.datacenter) - nets = append(nets, port) - } - } - if len(netNetMobs) > 0 { - moNets := make([]mo.Network, 0) - err := host.manager.references2Objects(netNetMobs, NETWORK_PROPS, &moNets) - if err != nil { - return nil, errors.Wrap(err, "references2Objects") - } - for i := range moNets { - net := NewNetwork(host.manager, &moNets[i], host.datacenter) - nets = append(nets, net) - } - } - - // network map - netMap := make(map[string]IVMNetwork) - for i := range nets { - netMap[nets[i].GetName()] = nets[i] - } - - // fetch all portgroup - portgroups := host.getHostSystem().Config.Network.Portgroup - for _, pg := range portgroups { - net, ok := netMap[pg.Spec.Name] - if !ok { - log.Infof("SNetwork corresponding to the portgroup whose name is %s could not be found", pg.Spec.Name) - continue - } - net.SetHostPortGroup(pg) - } - host.networks = nets - return host.networks, nil -} - -func (host *SHost) findNovlanDVPG() (*SDistributedVirtualPortgroup, error) { - nets, err := host.datacenter.GetNetworks() - if err != nil { - return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks") - } - for _, net := range nets { - dvpg, ok := net.(*SDistributedVirtualPortgroup) - if !ok || !dvpg.ContainHost(host) || len(dvpg.GetActivePorts()) == 0 { - continue - } - nvlan := dvpg.GetVlanId() - if !host.IsActiveVlanID(nvlan) { - return dvpg, nil - } - } - return nil, nil -} - -func (host *SHost) findDVPGById(id string) (*SDistributedVirtualPortgroup, error) { - nets, err := host.datacenter.GetNetworks() - if err != nil { - return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks") - } - for _, net := range nets { - if dvpg, ok := net.(*SDistributedVirtualPortgroup); ok && dvpg.GetId() == id { - return dvpg, nil - } - } - return nil, nil -} - -func (host *SHost) findVlanDVPG(vlanId int32) (*SDistributedVirtualPortgroup, error) { - nets, err := host.datacenter.GetNetworks() - if err != nil { - return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks") - } - for _, net := range nets { - dvpg, ok := net.(*SDistributedVirtualPortgroup) - if !ok || len(dvpg.GetActivePorts()) == 0 { - continue - } - nvlan := dvpg.GetVlanId() - if nvlan == vlanId { - if dvpg.ContainHost(host) { - return dvpg, nil - } - msg := "Find dvpg with correct vlan but it didn't contain this host" - log.Debugf(msg) - // add host to dvg - // err := dvpg.AddHostToDVS(host) - // if err != nil { - // return nil, errors.Wrapf(err, "dvpg %s add host to dvs error", dvpg.GetName()) - // } - continue - } - } - return nil, nil -} - -func (host *SHost) GetoHostSystem() *object.HostSystem { - return object.NewHostSystem(host.manager.client.Client, host.getHostSystem().Reference()) -} - -func (host *SHost) GetResourcePool() (*object.ResourcePool, error) { - var err error - if host.parent == nil { - host.parent, err = host.getParent() - if err != nil { - return nil, err - } - } - return object.NewResourcePool(host.manager.client.Client, *host.parent.ResourcePool), nil -} - -func (host *SHost) getParent() (*mo.ComputeResource, error) { - var mcr *mo.ComputeResource - var parent interface{} - - moHost := host.getHostSystem() - - switch moHost.Parent.Type { - case "ComputeResource": - mcr = new(mo.ComputeResource) - parent = mcr - case "ClusterComputeResource": - mcc := new(mo.ClusterComputeResource) - mcr = &mcc.ComputeResource - parent = mcc - default: - return nil, errors.Error(fmt.Sprintf("unknown host parent type: %s", moHost.Parent.Type)) - } - - err := host.manager.reference2Object(*moHost.Parent, []string{"name", "resourcePool"}, parent) - if err != nil { - return nil, errors.Wrap(err, "SESXiClient.reference2Object") - } - return mcr, nil -} - -func (host *SHost) GetResourcePools() ([]mo.ResourcePool, error) { - cluster, err := host.GetCluster() - if err != nil { - return nil, errors.Wrap(err, "GetCluster") - } - return cluster.ListResourcePools() -} - -func (host *SHost) GetCluster() (*SCluster, error) { - cluster, err := host.getCluster() - if err != nil { - return nil, errors.Wrap(err, "getCluster") - } - return NewCluster(host.manager, cluster, host.datacenter), nil -} - -func (host *SHost) SyncResourcePool(name string) (*object.ResourcePool, error) { - cluster, err := host.GetCluster() - if err != nil { - log.Errorf("failed to get host %s cluster info: %v", host.GetName(), err) - return host.GetResourcePool() - } - pool, err := cluster.SyncResourcePool(name) - if err != nil { - log.Errorf("failed to sync resourcePool(%s) for cluster %s error: %v", name, cluster.GetName(), err) - return host.GetResourcePool() - } - return object.NewResourcePool(host.manager.client.Client, pool.Reference()), nil -} - -func (host *SHost) getCluster() (*mo.ClusterComputeResource, error) { - moHost := host.getHostSystem() - if moHost.Parent.Type != "ClusterComputeResource" { - return nil, fmt.Errorf("host %s parent is not the cluster resource", host.GetName()) - } - cluster := &mo.ClusterComputeResource{} - err := host.manager.reference2Object(*moHost.Parent, []string{"name", "resourcePool"}, cluster) - if err != nil { - return nil, errors.Wrap(err, "SESXiClient.reference2Object") - } - return cluster, nil -} - -func (host *SHost) GetSiblingHosts() ([]*SHost, error) { - rp, err := host.getParent() - if err != nil { - return nil, err - } - moHosts := make([]mo.HostSystem, 0, len(rp.Host)) - err = host.manager.references2Objects(rp.Host, HOST_SYSTEM_PROPS, &moHosts) - if err != nil { - return nil, errors.Wrap(err, "SESXiClient.references2Objects") - } - - ret := make([]*SHost, len(moHosts)) - for i := range moHosts { - ret[i] = NewHost(host.manager, &moHosts[i], host.datacenter) - } - return ret, nil -} diff --git a/pkg/multicloud/esxi/host_test.go b/pkg/multicloud/esxi/host_test.go deleted file mode 100644 index dfafb1db0b..0000000000 --- a/pkg/multicloud/esxi/host_test.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "testing" -) - -func TestFormatName(t *testing.T) { - cases := []struct { - In string - Want string - }{ - { - In: "esxi-172.16.23.1", - Want: "esxi-172-16-23-1", - }, - { - In: "esxi6.yunion.cn", - Want: "esxi6", - }, - } - for _, c := range cases { - got := formatName(c.In) - if got != c.Want { - t.Errorf("got: %s want %s", got, c.Want) - } - } -} diff --git a/pkg/multicloud/esxi/image.go b/pkg/multicloud/esxi/image.go deleted file mode 100644 index b7ec49d320..0000000000 --- a/pkg/multicloud/esxi/image.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "context" - "path" - "strings" - "time" - - "github.com/vmware/govmomi/object" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type SImage struct { - multicloud.SImageBase - multicloud.STagBase - cache *SDatastoreImageCache - filename string - size int64 - createAt time.Time - - imageInfo *imagetools.ImageInfo -} - -func (self *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (self *SImage) getDatacenter() *object.Datacenter { - return self.cache.datastore.datacenter.getDcObj() -} - -func (self *SImage) getFullFilename() string { - return self.cache.datastore.getPathString(self.filename) -} - -func (self *SImage) GetId() string { - idstr := path.Base(self.filename) - if strings.HasSuffix(idstr, ".vmdk") { - idstr = idstr[:len(idstr)-5] - } - return strings.ToLower(idstr) -} - -func (self *SImage) GetName() string { - return self.GetId() -} - -func (self *SImage) GetGlobalId() string { - return self.GetId() -} - -func (self *SImage) GetStatus() string { - dm := object.NewVirtualDiskManager(self.cache.datastore.manager.client.Client) - ctx := context.Background() - _, err := dm.QueryVirtualDiskInfo(ctx, self.getFullFilename(), self.getDatacenter(), true) - if err != nil { - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } - return api.CACHED_IMAGE_STATUS_ACTIVE -} - -func (self *SImage) GetImageStatus() string { - status := self.GetStatus() - if status == api.CACHED_IMAGE_STATUS_ACTIVE { - return cloudprovider.IMAGE_STATUS_ACTIVE - } - return cloudprovider.IMAGE_STATUS_DELETED -} - -func (self *SImage) Refresh() error { - return nil -} - -func (self *SImage) IsEmulated() bool { - return false -} - -func (self *SImage) Delete(ctx context.Context) error { - return self.cache.datastore.DeleteVmdk(ctx, self.filename) -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.cache -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - return cloudprovider.ImageTypeCustomized -} - -func (self *SImage) GetSizeByte() int64 { - return self.size -} - -func (img *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if img.imageInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(img.filename, "", "", "", "") - img.imageInfo = &imgInfo - } - return img.imageInfo -} - -func (img *SImage) GetFullOsName() string { - return img.filename -} - -func (img *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(img.getNormalizedImageInfo().OsType) -} - -func (img *SImage) GetOsArch() string { - return img.getNormalizedImageInfo().OsArch -} - -func (img *SImage) GetOsDist() string { - return img.getNormalizedImageInfo().OsDistro -} - -func (img *SImage) GetOsVersion() string { - return img.getNormalizedImageInfo().OsVersion -} - -func (img *SImage) GetOsLang() string { - return img.getNormalizedImageInfo().OsLang -} - -func (img *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(img.getNormalizedImageInfo().OsBios) -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return int(self.GetSizeByte() / 1024 / 1024 / 1024) -} - -func (self *SImage) GetImageFormat() string { - return "vmdk" -} - -func (self *SImage) GetCreatedAt() time.Time { - return self.createAt -} diff --git a/pkg/multicloud/esxi/manager.go b/pkg/multicloud/esxi/manager.go deleted file mode 100644 index 5a665dbb39..0000000000 --- a/pkg/multicloud/esxi/manager.go +++ /dev/null @@ -1,743 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "bytes" - "context" - "fmt" - "net/http" - "net/http/httputil" - "net/url" - "reflect" - "strings" - "sync" - - xj "github.com/basgys/goxml2json" - "github.com/fatih/color" - "github.com/vmware/govmomi" - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/property" - "github.com/vmware/govmomi/session" - "github.com/vmware/govmomi/view" - "github.com/vmware/govmomi/vim25" - "github.com/vmware/govmomi/vim25/methods" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/soap" - "github.com/vmware/govmomi/vim25/types" - "moul.io/http2curl/v2" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/esxi/vcenter" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -const ( - CLOUD_PROVIDER_VMWARE = api.CLOUD_PROVIDER_VMWARE -) - -var ( - defaultDc mo.Datacenter - - defaultDcId = "esxi-default-datacenter" -) - -func init() { - defaultDc.ManagedEntity.Name = "Datacenter" - defaultDc.ManagedEntity.ExtensibleManagedObject.Self.Type = "Datacenter" - defaultDc.ManagedEntity.ExtensibleManagedObject.Self.Value = defaultDcId -} - -type ESXiClientConfig struct { - cpcfg cloudprovider.ProviderConfig - - host string - port int - account string - password string - - managed bool - debug bool - format string -} - -func NewESXiClientConfig(host string, port int, account, password string) *ESXiClientConfig { - cfg := &ESXiClientConfig{ - host: host, - port: port, - account: account, - password: password, - } - return cfg -} - -func (cfg *ESXiClientConfig) CloudproviderConfig(cpcfg cloudprovider.ProviderConfig) *ESXiClientConfig { - cfg.cpcfg = cpcfg - return cfg -} - -func (cfg *ESXiClientConfig) Debug(debug bool) *ESXiClientConfig { - cfg.debug = debug - return cfg -} - -func (cfg *ESXiClientConfig) Format(format string) *ESXiClientConfig { - cfg.format = format - return cfg -} - -func (cfg *ESXiClientConfig) Managed(managed bool) *ESXiClientConfig { - cfg.managed = managed - return cfg -} - -type SESXiClient struct { - *ESXiClientConfig - - cloudprovider.SFakeOnPremiseRegion - multicloud.SRegion - multicloud.SNoObjectStorageRegion - - client *govmomi.Client - context context.Context - - datacenters []*SDatacenter - networkQueryMap *sync.Map -} - -func NewESXiClient(cfg *ESXiClientConfig) (*SESXiClient, error) { - cfg.Managed(true) - return NewESXiClient2(cfg) -} - -func NewESXiClient2(cfg *ESXiClientConfig) (*SESXiClient, error) { - cli := &SESXiClient{ - ESXiClientConfig: cfg, - context: context.Background(), - } - - err := cli.connect() - if err != nil { - return nil, err - } - - if !cli.IsVCenter() { - err := cli.checkHostManagedByVCenter() - if err != nil { - if cfg.managed { - cli.disconnect() - return nil, err - } else { - log.Warningf("%s", err) - } - } - } - return cli, nil -} - -func NewESXiClientFromJson(ctx context.Context, input jsonutils.JSONObject) (*SESXiClient, *vcenter.SVCenterAccessInfo, error) { - accessInfo := new(vcenter.SVCenterAccessInfo) - err := input.Unmarshal(accessInfo) - if err != nil { - return nil, nil, errors.Wrapf(err, "unmarshal SVCenterAccessInfo: %s", input) - } - c, err := NewESXiClientFromAccessInfo(ctx, accessInfo) - return c, accessInfo, err -} - -func NewESXiClientFromAccessInfo(ctx context.Context, accessInfo *vcenter.SVCenterAccessInfo) (*SESXiClient, error) { - if len(accessInfo.VcenterId) > 0 { - tmp, err := utils.DescryptAESBase64(accessInfo.VcenterId, accessInfo.Password) - if err == nil { - accessInfo.Password = tmp - } - } - client, err := NewESXiClient( - NewESXiClientConfig( - accessInfo.Host, - accessInfo.Port, - accessInfo.Account, - accessInfo.Password, - ).Managed(true), - ) - if err != nil { - return nil, err - } - if ctx == nil { - ctx = context.Background() - } - client.context = ctx - return client, nil -} - -func (cli *SESXiClient) getUrl() string { - if cli.port == 443 || cli.port == 0 { - return fmt.Sprintf("https://%s", cli.host) - } else { - return fmt.Sprintf("https://%s:%d", cli.host, cli.port) - } -} - -func (cli *SESXiClient) url() string { - return fmt.Sprintf("%s/sdk", cli.getUrl()) -} - -var ( - red = color.New(color.FgRed, color.Bold).PrintlnFunc() - green = color.New(color.FgGreen, color.Bold).PrintlnFunc() - yellow = color.New(color.FgYellow, color.Bold).PrintlnFunc() - cyan = color.New(color.FgHiCyan, color.Bold).PrintlnFunc() -) - -func (cli *SESXiClient) connect() error { - u, err := url.Parse(cli.url()) - if err != nil { - return fmt.Errorf("Illegal url %s: %s", cli.url(), err) - } - - var govmcli *govmomi.Client - { - insecure := true - soapCli := soap.NewClient(u, insecure) - httpClient := &soapCli.Client - transport := httputils.GetAdaptiveTransport(true) - transport.Proxy = cli.cpcfg.ProxyFunc - httpClient.Transport = cloudprovider.GetCheckTransport(transport, func(req *http.Request) (func(resp *http.Response), error) { - if cli.debug { - dump, _ := httputil.DumpRequestOut(req, false) - yellow(string(dump)) - // 忽略掉上传文件的请求,避免大量日志输出 - if req.Header.Get("Content-Type") != "application/octet-stream" { - curlCmd, _ := http2curl.GetCurlCommand(req) - cyan("CURL:", curlCmd, "\n") - } - } - respCheck := func(resp *http.Response) { - if cli.debug { - dump, _ := httputil.DumpResponse(resp, true) - body := string(dump) - if cli.format == "json" { - obj, err := xj.Convert(bytes.NewReader(dump)) - if err == nil { - body = string(obj.String()) - } - } - if resp.StatusCode < 300 { - green(body) - } else if resp.StatusCode < 400 { - yellow(body) - } else { - red(body) - } - } - } - return respCheck, nil - }) - vimCli, err := vim25.NewClient(cli.context, soapCli) - if err != nil { - return err - } - govmcli = &govmomi.Client{ - Client: vimCli, - SessionManager: session.NewManager(vimCli), - } - } - - userinfo := url.UserPassword(cli.account, cli.password) - - err = govmcli.Login(cli.context, userinfo) - if err != nil { - return err - } - - cli.client = govmcli - - defaultDc.ManagedEntity.Parent = &cli.client.ServiceContent.RootFolder - - return nil -} - -func (cli *SESXiClient) disconnect() error { - if cli.client != nil { - return cli.client.Logout(cli.context) - } - return nil -} - -func (cli *SESXiClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - err := cli.connect() - if err != nil { - return nil, err - } - subAccount := cloudprovider.SSubAccount{ - Account: cli.account, - Name: cli.cpcfg.Name, - HealthStatus: api.CLOUD_PROVIDER_HEALTH_NORMAL, - } - return []cloudprovider.SSubAccount{subAccount}, nil -} - -func (cli *SESXiClient) GetAccountId() string { - return fmt.Sprintf("%s@%s:%d", cli.account, cli.host, cli.port) -} - -func (cli *SESXiClient) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(cli.GetName()).CN(cli.GetName()) - return table -} - -func (cli *SESXiClient) GetVersion() string { - return cli.client.ServiceContent.About.Version -} - -func (cli *SESXiClient) About() jsonutils.JSONObject { - about := jsonutils.Marshal(&cli.client.ServiceContent.About) - aboutDict := about.(*jsonutils.JSONDict) - aboutDict.Add(jsonutils.NewString(cli.getEndpointType()), "endpoint_type") - return aboutDict -} - -func (cli *SESXiClient) getEndpointType() string { - if cli.IsVCenter() { - return "VCenter" - } else { - return "ESXi" - } -} - -func (cli *SESXiClient) GetUUID() string { - about := cli.client.ServiceContent.About - return about.InstanceUuid -} - -func (cli *SESXiClient) fetchDatacentersFromHosts() error { - var hosts []mo.HostSystem - err := cli.scanAllMObjects(HOST_SYSTEM_PROPS, &hosts) - if err != nil { - return errors.Wrap(err, "cli.scanAllMObjects host") - } - dcList := make([]*SDatacenter, 0) - for i := 0; i < len(hosts); i += 1 { - me := newManagedObject(cli, &hosts[i], nil) - dcme := me.findInParents("Datacenter") - if dcme == nil { - return cloudprovider.ErrNotFound - } - _, err := findDatacenterByMoId(dcList, dcme.Self.Value) - if err == nil { - continue - } - var moDc mo.Datacenter - err = cli.reference2Object(dcme.Self, DATACENTER_PROPS, &moDc) - if err != nil { - return errors.Wrap(err, "cli.reference2Object") - } - dc, err := cli.newDatacenterFromMo(&moDc) - if err != nil { - return errors.Wrap(err, "cli.newDatacenterFromMo") - } - dcList = append(dcList, dc) - } - cli.datacenters = dcList - return nil -} - -func (cli *SESXiClient) fetchFakeDatacenter() error { - dc, err := cli.newDatacenterFromMo(&defaultDc) - if err != nil { - return errors.Wrap(err, "newDatacenterFromMo") - } - cli.datacenters = []*SDatacenter{dc} - return nil -} - -func (cli *SESXiClient) fetchDatacenters() error { - var dcs []mo.Datacenter - err := cli.scanAllMObjects(DATACENTER_PROPS, &dcs) - if err != nil { - // log.Debugf("cli.scanAllMObjects datacenter fail %s, try cli.fetchDatacentersFromHosts", err) - // err := cli.fetchDatacentersFromHosts() - // if err != nil { - log.Debugf("cli.fetchDatacentersFromHosts fail %s, try cli.fetchFakeDatacenter", err) - return cli.fetchFakeDatacenter() - // } - } - cli.datacenters = make([]*SDatacenter, len(dcs)) - for i := 0; i < len(dcs); i += 1 { - dc, err := cli.newDatacenterFromMo(&dcs[i]) - if err != nil { - return errors.Wrap(err, "cli.newDatacenterFromMo") - } - cli.datacenters[i] = dc - } - return nil -} - -func (cli *SESXiClient) newDatacenterFromMo(mo *mo.Datacenter) (*SDatacenter, error) { - dc := newDatacenter(cli, mo) - err := dc.scanHosts() - if err != nil { - return nil, errors.Wrap(err, "dc.scanHosts") - } - // err = dc.scanDatastores() - // if err != nil { - // return nil, errors.Wrap(err, "dc.scanDatastores") - // } - return dc, nil -} - -func (cli *SESXiClient) scanAllMObjects(props []string, dst interface{}) error { - return cli.scanMObjects(cli.client.ServiceContent.RootFolder, props, dst) -} - -func (cli *SESXiClient) SearchVM(id string) (*SVirtualMachine, error) { - filter := property.Filter{} - filter["summary.config.uuid"] = id - var movms []mo.VirtualMachine - err := cli.scanMObjectsWithFilter(cli.client.ServiceContent.RootFolder, VIRTUAL_MACHINE_PROPS, &movms, filter) - if err != nil { - return nil, err - } - if len(movms) == 0 { - return nil, errors.ErrNotFound - } - vm := NewVirtualMachine(cli, &movms[0], nil) - dc, err := vm.fetchDatacenter() - if err != nil { - return nil, errors.Wrap(err, "fetchDatacenter") - } - vm.datacenter = dc - return vm, nil -} - -func (cli *SESXiClient) SearchTemplateVM(id string) (*SVirtualMachine, error) { - filter := property.Filter{} - uuid := toTemplateUuid(id) - filter["summary.config.uuid"] = uuid - var movms []mo.VirtualMachine - err := cli.scanMObjectsWithFilter(cli.client.ServiceContent.RootFolder, VIRTUAL_MACHINE_PROPS, &movms, filter) - if err != nil { - return nil, err - } - if len(movms) == 0 { - return nil, errors.ErrNotFound - } - vm := NewVirtualMachine(cli, &movms[0], nil) - if !vm.IsTemplate() { - return nil, errors.ErrNotFound - } - dc, err := vm.fetchDatacenter() - if err != nil { - return nil, errors.Wrap(err, "fetchDatacenter") - } - vm.datacenter = dc - return vm, nil -} - -func (cli *SESXiClient) scanMObjectsWithFilter(folder types.ManagedObjectReference, props []string, dst interface{}, filter property.Filter) error { - dstValue := reflect.Indirect(reflect.ValueOf(dst)) - dstType := dstValue.Type() - dstEleType := dstType.Elem() - - resType := dstEleType.Name() - m := view.NewManager(cli.client.Client) - - v, err := m.CreateContainerView(cli.context, folder, []string{resType}, true) - if err != nil { - return errors.Wrapf(err, "m.CreateContainerView %s", resType) - } - - defer v.Destroy(cli.context) - - err = v.RetrieveWithFilter(cli.context, []string{resType}, props, dst, filter) - if err != nil { - // hack - if strings.Contains(err.Error(), "object references is empty") { - return nil - } - return errors.Wrapf(err, "v.RetrieveWithFilter %s", resType) - } - - return nil -} - -func (cli *SESXiClient) scanMObjects(folder types.ManagedObjectReference, props []string, dst interface{}) error { - dstValue := reflect.Indirect(reflect.ValueOf(dst)) - dstType := dstValue.Type() - dstEleType := dstType.Elem() - - resType := dstEleType.Name() - m := view.NewManager(cli.client.Client) - - v, err := m.CreateContainerView(cli.context, folder, []string{resType}, true) - if err != nil { - return errors.Wrapf(err, "m.CreateContainerView %s", resType) - } - - defer v.Destroy(cli.context) - - err = v.Retrieve(cli.context, []string{resType}, props, dst) - if err != nil { - return errors.Wrapf(err, "v.Retrieve %s", resType) - } - - return nil -} - -func (cli *SESXiClient) references2Objects(refs []types.ManagedObjectReference, props []string, dst interface{}) error { - pc := property.DefaultCollector(cli.client.Client) - err := pc.Retrieve(cli.context, refs, props, dst) - if err != nil { - log.Errorf("pc.Retrieve fail %s", err) - return err - } - return nil -} - -func (cli *SESXiClient) reference2Object(ref types.ManagedObjectReference, props []string, dst interface{}) error { - pc := property.DefaultCollector(cli.client.Client) - err := pc.RetrieveOne(cli.context, ref, props, dst) - if err != nil { - return errors.Wrap(err, "pc.RetrieveOne") - } - return nil -} - -func (cli *SESXiClient) GetDatacenters() ([]*SDatacenter, error) { - if cli.datacenters == nil { - err := cli.fetchDatacenters() - if err != nil { - return nil, err - } - } - return cli.datacenters, nil -} - -func (cli *SESXiClient) FindDatacenterByMoId(dcId string) (*SDatacenter, error) { - dcs, err := cli.GetDatacenters() - if err != nil { - return nil, err - } - return findDatacenterByMoId(dcs, dcId) -} - -func findDatacenterByMoId(dcs []*SDatacenter, dcId string) (*SDatacenter, error) { - for i := 0; i < len(dcs); i += 1 { - if dcs[i].GetId() == dcId { - return dcs[i], nil - } - // defaultDcId means no premision to get datacenter, so return fake dc - if dcs[i].GetId() == defaultDcId { - return dcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (cli *SESXiClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { - dcs, err := cli.GetDatacenters() - if err != nil { - return nil, errors.Wrap(err, "GetDatacenters") - } - ret := []cloudprovider.ICloudProject{} - for i := 0; i < len(dcs); i++ { - iprojects, err := dcs[i].GetResourcePools() - if err != nil { - return nil, errors.Wrap(err, "GetResourcePools") - } - ret = append(ret, iprojects...) - } - return ret, nil -} - -func (cli *SESXiClient) FindHostByMoId(moId string) (cloudprovider.ICloudHost, error) { - dcs, err := cli.GetDatacenters() - if err != nil { - return nil, err - } - for i := 0; i < len(dcs); i += 1 { - ihost, err := dcs[i].GetIHostByMoId(moId) - if err == nil { - return ihost, nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (cli *SESXiClient) getPrivateId(idStr string) string { - if len(cli.cpcfg.Id) > 0 && strings.HasPrefix(idStr, cli.cpcfg.Id) { - idStr = idStr[len(cli.cpcfg.Id)+1:] - } - return idStr -} - -func (cli *SESXiClient) checkHostManagedByVCenter() error { - host, err := cli.FindHostByIp(cli.host) - if err != nil { - if errors.Cause(err) == errors.ErrNotFound { - // host might be behind a NAT - return nil - } - return errors.Wrap(err, "cli.FindHostByIp") - } - if host.IsManagedByVCenter() { - return fmt.Errorf("ESXi host is managed by vcenter %s, please connect to vcenter instead for full management functions!", host.GetManagementServerIp()) - } - return nil -} - -func (cli *SESXiClient) IsHostIpExists(hostIp string) (bool, error) { - searchIndex := object.NewSearchIndex(cli.client.Client) - - hostRef, err := searchIndex.FindByIp(cli.context, nil, cli.getPrivateId(hostIp), false) - if err != nil { - log.Errorf("searchIndex.FindByIp fail %s", err) - return false, err - } - if hostRef == nil { - return false, nil - } - return true, nil -} - -func (cli *SESXiClient) FindHostByIp(hostIp string) (*SHost, error) { - searchIndex := object.NewSearchIndex(cli.client.Client) - - hostRef, err := searchIndex.FindByIp(cli.context, nil, cli.getPrivateId(hostIp), false) - if err != nil { - log.Errorf("searchIndex.FindByIp fail %s", err) - return nil, errors.Wrap(err, "searchIndex.FindByIp") - } - - if hostRef == nil { - return nil, errors.Wrapf(errors.ErrNotFound, "cannot find %s", cli.getPrivateId(hostIp)) - } - - var host mo.HostSystem - err = cli.reference2Object(hostRef.Reference(), HOST_SYSTEM_PROPS, &host) - if err != nil { - log.Errorf("reference2Object fail %s", err) - return nil, errors.Wrap(err, "cli.reference2Object") - } - - h := NewHost(cli, &host, nil) - if h == nil { - return nil, errors.Wrap(errors.ErrInvalidStatus, "empty host mo") - } - return h, nil -} - -func (cli *SESXiClient) acquireCloneTicket() (string, error) { - manager := session.NewManager(cli.client.Client) - return manager.AcquireCloneTicket(cli.context) -} - -func (cli *SESXiClient) IsVCenter() bool { - return cli.client.Client.IsVC() -} - -func (cli *SESXiClient) IsValid() bool { - return cli.client.Client.Valid() -} - -func (cli *SESXiClient) GetCapabilities() []string { - caps := []string{ - cloudprovider.CLOUD_CAPABILITY_PROJECT, - cloudprovider.CLOUD_CAPABILITY_COMPUTE, - // cloudprovider.CLOUD_CAPABILITY_NETWORK, - // cloudprovider.CLOUD_CAPABILITY_LOADBALANCER, - // cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE, - // cloudprovider.CLOUD_CAPABILITY_RDS, - // cloudprovider.CLOUD_CAPABILITY_CACHE, - // cloudprovider.CLOUD_CAPABILITY_EVENT, - } - return caps -} - -func (cli *SESXiClient) FindVMByPrivateID(idstr string) (*SVirtualMachine, error) { - searchIndex := object.NewSearchIndex(cli.client.Client) - instanceUuid := true - vmRef, err := searchIndex.FindByUuid(cli.context, nil, idstr, true, &instanceUuid) - if err != nil { - return nil, errors.Wrap(err, "searchIndex.FindByUuid fail") - } - if vmRef == nil { - return nil, fmt.Errorf("cannot find %s", idstr) - } - var vm mo.VirtualMachine - err = cli.reference2Object(vmRef.Reference(), VIRTUAL_MACHINE_PROPS, &vm) - if err != nil { - return nil, errors.Wrap(err, "reference2Object fail") - } - - ret := NewVirtualMachine(cli, &vm, nil) - if ret == nil { - return nil, errors.Error("invalid vm") - } - return ret, nil -} - -func (cli *SESXiClient) DoExtendDiskOnline(_vm *SVirtualMachine, _disk *SVirtualDisk, newSizeMb int64) error { - disk := _disk.getVirtualDisk() - disk.CapacityInKB = newSizeMb * 1024 - devSepc := types.VirtualDeviceConfigSpec{Operation: types.VirtualDeviceConfigSpecOperationEdit, Device: disk} - spec := types.VirtualMachineConfigSpec{DeviceChange: []types.BaseVirtualDeviceConfigSpec{&devSepc}} - vm := object.NewVirtualMachine(cli.client.Client, _vm.getVirtualMachine().Reference()) - task, err := vm.Reconfigure(cli.context, spec) - if err != nil { - return errors.Wrapf(err, "vm reconfigure failed") - } - return task.Wait(cli.context) -} - -func (cli *SESXiClient) ExtendDisk(url string, newSizeMb int64) error { - param := types.ExtendVirtualDisk_Task{ - This: *cli.client.Client.ServiceContent.VirtualDiskManager, - Name: url, - NewCapacityKb: newSizeMb * 1024, - } - response, err := methods.ExtendVirtualDisk_Task(cli.context, cli.client, ¶m) - if err != nil { - return errors.Wrapf(err, "extend virtualdisk task failed") - } - log.Debugf("extend virtual disk task response: %s", response.Returnval.String()) - return nil -} - -func (cli *SESXiClient) CopyDisk(ctx context.Context, src, dst string, isForce bool) error { - dm := object.NewVirtualDiskManager(cli.client.Client) - task, err := dm.CopyVirtualDisk(ctx, src, nil, dst, nil, nil, isForce) - if err != nil { - return errors.Wrap(err, "CopyVirtualDisk") - } - return task.Wait(ctx) -} - -func (cli *SESXiClient) MoveDisk(ctx context.Context, src, dst string, isForce bool) error { - dm := object.NewVirtualDiskManager(cli.client.Client) - task, err := dm.MoveVirtualDisk(ctx, src, nil, dst, nil, isForce) - if err != nil { - return errors.Wrap(err, "MoveVirtualDisk") - } - return task.Wait(ctx) -} diff --git a/pkg/multicloud/esxi/manager_test.go b/pkg/multicloud/esxi/manager_test.go deleted file mode 100644 index bc3c593413..0000000000 --- a/pkg/multicloud/esxi/manager_test.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -// TODO: rewrite this test -/* -import "testing" - -func TestNewClient(t *testing.T) { - cli, err := NewESXiClient("", "", "10.168.222.104", 443, "root", "123@Vmware") - - if err != nil { - t.Errorf("%s", err) - } else { - t.Logf("%s", cli.About()) - - cli.fetchDatacenters() - - host, err := cli.FindHostByIp("10.168.222.104") - if err != nil { - t.Errorf("find_host_by_ip %s", err) - } else { - t.Logf("host %s %s", host.GetAccessIp(), host.GetName()) - } - } -}*/ diff --git a/pkg/multicloud/esxi/mobase_test.go b/pkg/multicloud/esxi/mobase_test.go deleted file mode 100644 index 1cdac87150..0000000000 --- a/pkg/multicloud/esxi/mobase_test.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import "testing" - -func TestReverseArray(t *testing.T) { - a := []int{1, 2, 3, 4, 5} - - reverseArray(a) - t.Logf("%#v", a) - - b := []string{"1", "2", "3", "4", "5"} - reverseArray(b) - t.Logf("%#v", b) -} diff --git a/pkg/multicloud/esxi/monitor.go b/pkg/multicloud/esxi/monitor.go deleted file mode 100644 index 0f4a4e9263..0000000000 --- a/pkg/multicloud/esxi/monitor.go +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "fmt" - "time" - - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/performance" - "github.com/vmware/govmomi/view" - "github.com/vmware/govmomi/vim25/types" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - MONTYPE_HOSTSYSTEM = "HostSystem" - MONTYPE_VIRTUALMACHINE = "VirtualMachine" -) - -func (self *SESXiClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricName := "" - switch opts.MetricType { - case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: - metricName = "cpu.usage.average" - case cloudprovider.VM_METRIC_TYPE_MEM_USAGE: - metricName = "mem.usage.average" - case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: - metricName = "net.bytesRx.average" - case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: - metricName = "net.bytesTx.average" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: - metricName = "disk.read.average" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: - metricName = "disk.write.average" - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) - } - return self.getEcsMetrics(metricName, opts.MetricType, opts.StartTime, opts.EndTime) -} - -func (self *SESXiClient) getEcsMetrics(metricName string, metricType cloudprovider.TMetricType, start, end time.Time) ([]cloudprovider.MetricValues, error) { - m := view.NewManager(self.client.Client) - v, err := m.CreateContainerView(self.context, self.client.Client.ServiceContent.RootFolder, nil, true) - if err != nil { - return nil, errors.Wrapf(err, "CreateContainerView") - } - vms, err := v.Find(self.context, []string{MONTYPE_VIRTUALMACHINE}, nil) - if err != nil { - return nil, err - } - perfManager := performance.NewManager(self.client.Client) - counterInfo, err := perfManager.CounterInfoByName(self.context) - if err != nil { - return nil, errors.Wrapf(err, "CounterInfoByName") - } - - counter, ok := counterInfo[metricName] - if !ok { - return nil, fmt.Errorf("not found %s", metricName) - } - - queries := []types.PerfQuerySpec{} - for i := range vms { - query := types.PerfQuerySpec{ - Entity: vms[i].Reference(), - MetricId: []types.PerfMetricId{ - { - CounterId: counter.Key, - }, - }, - Format: "normal", - IntervalId: 20, - StartTime: &start, - EndTime: &end, - } - queries = append(queries, query) - } - - sample, err := perfManager.Query(self.context, queries) - if err != nil { - return nil, err - } - - result, err := perfManager.ToMetricSeries(self.context, sample) - if err != nil { - return nil, err - } - - ret := []cloudprovider.MetricValues{} - for _, metric := range result { - vm := object.NewVirtualMachine(self.client.Client, metric.Entity) - metricValue := cloudprovider.MetricValues{} - metricValue.MetricType = metricType - metricValue.Id = vm.UUID(self.context) - if len(metric.Value) == 0 { - continue - } - for i, v := range metric.SampleInfo { - if v.Timestamp.Second() != 0 { - continue - } - var value float64 - if len(metric.Value[0].Value) > i { - value = float64(metric.Value[0].Value[i]) - } - switch counter.UnitInfo.GetElementDescription().Key { - case "percent": - value = value / 100.0 - case "kiloBytesPerSecond": - value = value * 1024.0 - default: - log.Errorf("unknow unit: %s", counter.UnitInfo.GetElementDescription().Key) - } - metricValue.Values = append(metricValue.Values, cloudprovider.MetricValue{ - Timestamp: v.Timestamp, - Value: value, - }) - } - ret = append(ret, metricValue) - } - return ret, nil -} - -func (self *SESXiClient) GetHostMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricName := "" - switch opts.MetricType { - case cloudprovider.HOST_METRIC_TYPE_CPU_USAGE: - metricName = "cpu.usage.average" - case cloudprovider.HOST_METRIC_TYPE_MEM_USAGE: - metricName = "mem.usage.average" - case cloudprovider.HOST_METRIC_TYPE_NET_BPS_RX: - metricName = "net.received.average" - case cloudprovider.HOST_METRIC_TYPE_NET_BPS_TX: - metricName = "net.transmitted.average" - case cloudprovider.HOST_METRIC_TYPE_DISK_IO_READ_BPS: - metricName = "disk.read.average" - case cloudprovider.HOST_METRIC_TYPE_DISK_IO_WRITE_BPS: - metricName = "disk.write.average" - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) - } - return self.getHostMetrics(metricName, opts.MetricType, opts.StartTime, opts.EndTime) -} - -func (self *SESXiClient) getHostMetrics(metricName string, metricType cloudprovider.TMetricType, start, end time.Time) ([]cloudprovider.MetricValues, error) { - m := view.NewManager(self.client.Client) - v, err := m.CreateContainerView(self.context, self.client.Client.ServiceContent.RootFolder, nil, true) - if err != nil { - return nil, errors.Wrapf(err, "CreateContainerView") - } - vms, err := v.Find(self.context, []string{"HostSystem"}, nil) - if err != nil { - return nil, err - } - perfManager := performance.NewManager(self.client.Client) - counterInfo, err := perfManager.CounterInfoByName(self.context) - if err != nil { - return nil, errors.Wrapf(err, "CounterInfoByName") - } - - counter, ok := counterInfo[metricName] - if !ok { - return nil, fmt.Errorf("not found %s", metricName) - } - keys := []types.PerfMetricId{} - for _, v := range counterInfo { - keys = append(keys, types.PerfMetricId{ - CounterId: v.Key, - }) - } - - queries := []types.PerfQuerySpec{} - for i := range vms { - query := types.PerfQuerySpec{ - Entity: vms[i].Reference(), - MetricId: []types.PerfMetricId{ - { - CounterId: counter.Key, - }, - }, - Format: "normal", - IntervalId: 0, - StartTime: &start, - EndTime: &end, - } - queries = append(queries, query) - } - - sample, err := perfManager.Query(self.context, queries) - if err != nil { - return nil, err - } - - result, err := perfManager.ToMetricSeries(self.context, sample) - if err != nil { - return nil, err - } - - dcs, err := self.GetDatacenters() - if err != nil { - return nil, err - } - hostMap := map[string]string{} - for i := range dcs { - if dcs[i] == nil { - continue - } - part, err := dcs[i].GetIHosts() - if err != nil { - continue - } - for j := range part { - host := part[j].(*SHost) - hostMap[host.GetId()] = host.GetGlobalId() - } - } - - ret := []cloudprovider.MetricValues{} - for _, metric := range result { - metricValue := cloudprovider.MetricValues{} - metricValue.MetricType = metricType - hostId, ok := hostMap[metric.Entity.Value] - if !ok { - continue - } - metricValue.Id = hostId - if len(metric.Value) == 0 { - continue - } - for i, v := range metric.SampleInfo { - if v.Timestamp.Second() != 0 { - continue - } - var value float64 - if len(metric.Value[0].Value) > i { - value = float64(metric.Value[0].Value[i]) - } - switch counter.UnitInfo.GetElementDescription().Key { - case "percent": - value = value / 100.0 - case "kiloBytesPerSecond": - value = value * 1024.0 - default: - log.Errorf("unknow unit: %s", counter.UnitInfo.GetElementDescription().Key) - } - metricValue.Values = append(metricValue.Values, cloudprovider.MetricValue{ - Timestamp: v.Timestamp, - Value: value, - }) - } - ret = append(ret, metricValue) - } - return ret, nil -} - -func (self *SESXiClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_HOST: - return self.GetHostMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) - } -} - -func (self *SESXiClient) GetMetricTypes() (jsonutils.JSONObject, error) { - perfManager := performance.NewManager(self.client.Client) - counterInfo, err := perfManager.CounterInfoByName(self.context) - if err != nil { - return nil, errors.Wrapf(err, "CounterInfoByName") - } - return jsonutils.Marshal(counterInfo), nil -} diff --git a/pkg/multicloud/esxi/provider/doc.go b/pkg/multicloud/esxi/provider/doc.go deleted file mode 100644 index bb6b855ac4..0000000000 --- a/pkg/multicloud/esxi/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/esxi/provider" diff --git a/pkg/multicloud/esxi/provider/provider.go b/pkg/multicloud/esxi/provider/provider.go deleted file mode 100644 index 9d234ec11f..0000000000 --- a/pkg/multicloud/esxi/provider/provider.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "fmt" - "net/url" - "strconv" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/regutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/esxi" -) - -type SESXiProviderFactory struct { - cloudprovider.SPremiseBaseProviderFactory -} - -func (self *SESXiProviderFactory) GetId() string { - return esxi.CLOUD_PROVIDER_VMWARE -} - -func (self *SESXiProviderFactory) GetName() string { - return esxi.CLOUD_PROVIDER_VMWARE -} - -func (self *SESXiProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { - return fmt.Errorf("Changing %s bandwidth is not supported", esxi.CLOUD_PROVIDER_VMWARE) -} - -func (self *SESXiProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.Username) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "username") - } - if len(input.Password) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "password") - } - if len(input.Host) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "host") - } - if !regutils.MatchIPAddr(input.Host) && !regutils.MatchDomainName(input.Host) { - return output, errors.Wrap(httperrors.ErrInputParameter, "host should be ip or domain name") - } - output.AccessUrl = fmt.Sprintf("https://%s:%d/sdk", input.Host, input.Port) - if input.Port == 0 || input.Port == 443 { - output.AccessUrl = fmt.Sprintf("https://%s/sdk", input.Host) - } - output.Account = input.Username - output.Secret = input.Password - return output, nil -} - -func (self *SESXiProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.Username) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "username") - } - if len(input.Password) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "password") - } - output = cloudprovider.SCloudaccount{ - Account: input.Username, - Secret: input.Password, - } - return output, nil -} - -func parseHostPort(host string, defPort int) (string, int, error) { - colonPos := strings.IndexByte(host, ':') - if colonPos > 0 { - h := host[:colonPos] - p, err := strconv.Atoi(host[colonPos+1:]) - if err != nil { - log.Errorf("Invalid host %s", host) - return "", 0, err - } - if p == 0 { - p = defPort - } - return h, p, nil - } else { - return host, defPort, nil - } -} - -func (self *SESXiProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - parts, err := url.Parse(cfg.URL) - if err != nil { - return nil, err - } - host, port, err := parseHostPort(parts.Host, 443) - if err != nil { - return nil, err - } - - client, err := esxi.NewESXiClient( - esxi.NewESXiClientConfig( - host, port, cfg.Account, cfg.Secret, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SESXiProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SESXiProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - parts, err := url.Parse(info.Url) - if err != nil { - return nil, err - } - host, port, err := parseHostPort(parts.Host, 443) - if err != nil { - return nil, err - } - - return map[string]string{ - "VMWARE_HOST": host, - "VMWARE_PORT": fmt.Sprintf("%d", port), - "VMWARE_ACCOUNT": info.Account, - "VMWARE_PASSWORD": info.Secret, - }, nil -} - -func (self *SESXiProviderFactory) GetAccountIdEqualizer() func(origin, now string) bool { - return func(origin, now string) bool { - if len(now) == 0 { - return true - } - originUserName, nowUserName := origin, now - index1 := strings.Index(origin, "@") - index2 := strings.Index(now, "@") - if index1 != -1 { - originUserName = originUserName[:index1] - } - if index2 != -1 { - nowUserName = nowUserName[:index2] - } - return originUserName == nowUserName - } -} - -func init() { - factory := SESXiProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SESXiProvider struct { - cloudprovider.SBaseProvider - client *esxi.SESXiClient -} - -func (self *SESXiProvider) GetSysInfo() (jsonutils.JSONObject, error) { - return self.client.About(), nil -} - -func (self *SESXiProvider) GetVersion() string { - return self.client.GetVersion() -} - -func (self *SESXiProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SESXiProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SESXiProvider) GetIRegions() []cloudprovider.ICloudRegion { - return nil -} - -func (self *SESXiProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SESXiProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SESXiProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { - return self.client, nil -} - -func (self *SESXiProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SESXiProvider) GetStorageClasses(regionId string) []string { - return nil -} - -func (self *SESXiProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (self *SESXiProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (self *SESXiProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SESXiProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/esxi/resourcepool.go b/pkg/multicloud/esxi/resourcepool.go deleted file mode 100644 index 8a7fbaaed8..0000000000 --- a/pkg/multicloud/esxi/resourcepool.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "net/url" - "strings" - - "github.com/vmware/govmomi/vim25/mo" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var RESOURCEPOOL_PROPS = []string{"name", "parent", "host"} - -type SResourcePool struct { - multicloud.SProjectBase - multicloud.STagBase - SManagedObject -} - -func (pool *SResourcePool) GetGlobalId() string { - return pool.GetId() -} - -func (pool *SResourcePool) GetStatus() string { - return api.EXTERNAL_PROJECT_STATUS_AVAILABLE -} - -func (pool *SResourcePool) GetName() string { - path := pool.GetPath() - if len(path) > 5 { - path = path[5:] - } - name := []string{} - for _, _name := range path { - p, _ := url.PathUnescape(_name) - name = append([]string{p}, name...) - } - return strings.Join(name, "/") -} - -func NewResourcePool(manager *SESXiClient, rp *mo.ResourcePool, dc *SDatacenter) *SResourcePool { - return &SResourcePool{SManagedObject: newManagedObject(manager, rp, dc)} -} diff --git a/pkg/multicloud/esxi/shell/cluster.go b/pkg/multicloud/esxi/shell/cluster.go deleted file mode 100644 index 17b7fd40b6..0000000000 --- a/pkg/multicloud/esxi/shell/cluster.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClusterListOptions struct { - DATACENTER string `help:"List clusters in datacenter"` - } - shellutils.R(&ClusterListOptions{}, "cluster-list", "List all clusters", func(cli *esxi.SESXiClient, args *ClusterListOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - clusters, err := dc.ListClusters() - if err != nil { - return err - } - printList(clusters, nil) - return nil - }) - - type ClusterPoolListOptions struct { - DATACENTER string `help:"List clusters in datacenter"` - CLUSTER string `help:"List cluster resource pool"` - } - - shellutils.R(&ClusterPoolListOptions{}, "cluster-pool-list", "List all cluster resource pool", func(cli *esxi.SESXiClient, args *ClusterPoolListOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - cluster, err := dc.GetCluster(args.CLUSTER) - if err != nil { - return err - } - pools, err := cluster.ListResourcePools() - if err != nil { - return errors.Wrap(err, "ListResourcePools") - } - printList(pools, nil) - return nil - }) - - type ClusterPoolSyncOptions struct { - DATACENTER string `help:"List clusters in datacenter"` - CLUSTER string `help:"List cluster resource pool"` - Name string `help:"Resource pool name"` - } - - shellutils.R(&ClusterPoolSyncOptions{}, "cluster-pool-sync", "Sync cluster resource pool", func(cli *esxi.SESXiClient, args *ClusterPoolSyncOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - cluster, err := dc.GetCluster(args.CLUSTER) - if err != nil { - return err - } - pool, err := cluster.SyncResourcePool(args.Name) - if err != nil { - return errors.Wrap(err, "SyncResourcePool") - } - printObject(pool) - return nil - }) - -} diff --git a/pkg/multicloud/esxi/shell/datacenter.go b/pkg/multicloud/esxi/shell/datacenter.go deleted file mode 100644 index a7ce27d047..0000000000 --- a/pkg/multicloud/esxi/shell/datacenter.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DatacenterListOptions struct { - } - shellutils.R(&DatacenterListOptions{}, "dc-list", "List all datacenters", func(cli *esxi.SESXiClient, args *DatacenterListOptions) error { - dcs, err := cli.GetDatacenters() - if err != nil { - return err - } - printList(dcs, nil) - return nil - }) -} diff --git a/pkg/multicloud/esxi/shell/doc.go b/pkg/multicloud/esxi/shell/doc.go deleted file mode 100644 index 72e8debf93..0000000000 --- a/pkg/multicloud/esxi/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/esxi/shell" diff --git a/pkg/multicloud/esxi/shell/host.go b/pkg/multicloud/esxi/shell/host.go deleted file mode 100644 index 8aa61ac2fa..0000000000 --- a/pkg/multicloud/esxi/shell/host.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type HostListOptions struct { - DATACENTER string `help:"List hosts in datacenter"` - } - shellutils.R(&HostListOptions{}, "host-list", "List hosts in datacenter", func(cli *esxi.SESXiClient, args *HostListOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - hosts, err := dc.GetIHosts() - if err != nil { - return err - } - printList(hosts, nil) - return nil - }) - - type HostShowOptions struct { - IP string `help:"Host IP"` - - Debug bool `help:"show debug info"` - } - shellutils.R(&HostShowOptions{}, "host-show", "Show details of a host by IP", func(cli *esxi.SESXiClient, args *HostShowOptions) error { - host, err := cli.FindHostByIp(args.IP) - if err != nil { - return err - } - printObject(host) - return nil - }) - - shellutils.R(&HostShowOptions{}, "host-storages", "Show all storages of a given host", func(cli *esxi.SESXiClient, args *HostShowOptions) error { - host, err := cli.FindHostByIp(args.IP) - if err != nil { - return err - } - storages, err := host.GetIStorages() - if err != nil { - return err - } - printList(storages, nil) - return nil - }) - - shellutils.R(&HostShowOptions{}, "host-nics", "Show all nics of a given host", func(cli *esxi.SESXiClient, args *HostShowOptions) error { - host, err := cli.FindHostByIp(args.IP) - if err != nil { - return err - } - nics, err := host.GetIHostNicsInternal(args.Debug) - if err != nil { - return err - } - printList(nics, nil) - return nil - }) - - shellutils.R(&HostShowOptions{}, "host-network", "Show all network of a given host", func(cli *esxi.SESXiClient, - args *HostShowOptions) error { - host, err := cli.FindHostByIp(args.IP) - if err != nil { - return err - } - networks, err := host.GetNetworks() - if err != nil { - return err - } - printList(networks, nil) - return nil - }) - - shellutils.R(&HostShowOptions{}, "host-cluster", "Show host cluster", func(cli *esxi.SESXiClient, - args *HostShowOptions) error { - host, err := cli.FindHostByIp(args.IP) - if err != nil { - return err - } - cluster, err := host.GetCluster() - if err != nil { - return err - } - printObject(cluster) - return nil - }) - - shellutils.R(&HostShowOptions{}, "host-pool-list", "List host pools", func(cli *esxi.SESXiClient, - args *HostShowOptions) error { - host, err := cli.FindHostByIp(args.IP) - if err != nil { - return err - } - pool, err := host.GetResourcePool() - if err != nil { - return err - } - printObject(pool) - return nil - }) -} diff --git a/pkg/multicloud/esxi/shell/ip.go b/pkg/multicloud/esxi/shell/ip.go deleted file mode 100644 index 44a2321a3e..0000000000 --- a/pkg/multicloud/esxi/shell/ip.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "sort" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type IPListOption struct { - Host bool `help:"List only host ips"` - Vm bool `help:"List only vm ips"` - Cidr string `help:"Filter ips in this cidr, such as 192.168.10.0/24"` - } - shellutils.R(&IPListOption{}, "ip-list", "List all ip", func(cli *esxi.SESXiClient, args *IPListOption) error { - host, vm := args.Host, args.Vm - if !host && !vm { - host, vm = true, true - } - var cidr netutils.IPV4Prefix - var err error - if len(args.Cidr) > 0 { - cidr, err = netutils.NewIPV4Prefix(args.Cidr) - if err != nil { - return errors.Wrap(err, "unable to parse cidr") - } - } - list := make([]IPDetails, 0, 5) - if host { - hostIps, _, err := cli.AllHostIP() - if err != nil { - return errors.Wrap(err, "AllHostIP") - } - for n, ip := range hostIps { - ipaddr, err := netutils.NewIPV4Addr(ip) - if err != nil { - return errors.Wrapf(err, "NewIPV4Addr for ip %s", ip) - } - if len(args.Cidr) > 0 && !cidr.Contains(ipaddr) { - continue - } - list = append(list, IPDetails{ - Name: n, - Type: "host", - Ip: ip, - Ipaddr: ipaddr, - }) - } - } - if vm { - vmipinfos, err := cli.VMIP2() - if err != nil { - return errors.Wrap(err, "VMIP2") - } - //split - for i := range vmipinfos { - for _, macip := range vmipinfos[i].MacIps { - mac := macip.Mac - if len(macip.IPs) == 0 { - list = append(list, IPDetails{ - Name: vmipinfos[i].Name, - Mac: mac, - Uuid: vmipinfos[i].Uuid, - Moid: vmipinfos[i].Moid, - PowerState: vmipinfos[i].PowerState, - Type: "vm", - Ip: "", - Ipaddr: 0, - }) - continue - } - ip := macip.IPs[0] - ipaddr, err := netutils.NewIPV4Addr(ip) - if err != nil { - return errors.Wrapf(err, "NewIPV4Addr for ip %s", ip) - } - if len(args.Cidr) > 0 && !cidr.Contains(ipaddr) { - continue - } - - list = append(list, IPDetails{ - Name: vmipinfos[i].Name, - Mac: mac, - Uuid: vmipinfos[i].Uuid, - Moid: vmipinfos[i].Moid, - PowerState: vmipinfos[i].PowerState, - Type: "vm", - Ip: ip, - Ipaddr: ipaddr, - }) - } - } - - } - sort.Slice(list, func(i, j int) bool { - return list[i].Ipaddr < list[j].Ipaddr - }) - printList(list, []string{"name", "type", "ip", "mac", "Power_State", "uuid", "moid"}) - return nil - }) -} - -type IPDetails struct { - Moid string - PowerState string - Uuid string - Name string - Type string - Ip string - Mac string - Ipaddr netutils.IPV4Addr -} - -func (i IPDetails) GetMoid() string { - return i.Moid -} -func (i IPDetails) GetPowerState() string { - return i.PowerState -} -func (i IPDetails) GetUuid() string { - return i.Uuid -} -func (i IPDetails) GetMac() string { - return i.Mac -} -func (i IPDetails) GetName() string { - return i.Name -} - -func (i IPDetails) GetType() string { - return i.Type -} - -func (i IPDetails) GetIp() string { - return i.Ip -} diff --git a/pkg/multicloud/esxi/shell/monitor.go b/pkg/multicloud/esxi/shell/monitor.go deleted file mode 100644 index c94e00ebff..0000000000 --- a/pkg/multicloud/esxi/shell/monitor.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics in a namespace", func(cli *esxi.SESXiClient, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric %s %s", metrics[i].Id, metrics[i].MetricType) - printList(metrics[i].Values, nil) - } - return nil - }) - - type SMetricTypeShowOptions struct { - } - - shellutils.R(&SMetricTypeShowOptions{}, "metric-type-show", "List metrics", func(cli *esxi.SESXiClient, args *SMetricTypeShowOptions) error { - metrics, err := cli.GetMetricTypes() - if err != nil { - return err - } - printObject(metrics) - return nil - }) - -} diff --git a/pkg/multicloud/esxi/shell/network.go b/pkg/multicloud/esxi/shell/network.go deleted file mode 100644 index a5ec78adc9..0000000000 --- a/pkg/multicloud/esxi/shell/network.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkListOptions struct { - DATACENTER string `help:"List datastores in datacenter"` - } - shellutils.R(&NetworkListOptions{}, "network-list", "List networks in datacenter", func(cli *esxi.SESXiClient, args *NetworkListOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - nets, err := dc.GetNetworks() - if err != nil { - return err - } - printList(nets, nil) - return nil - }) -} diff --git a/pkg/multicloud/esxi/shell/resourcepool.go b/pkg/multicloud/esxi/shell/resourcepool.go deleted file mode 100644 index c1aabc1ac8..0000000000 --- a/pkg/multicloud/esxi/shell/resourcepool.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ResourcePoolListOptions struct { - DATACENTER string `help:"List resource pool in datacenter"` - } - shellutils.R(&ResourcePoolListOptions{}, "resource-pool-list", "List all resource pools", func(cli *esxi.SESXiClient, args *ResourcePoolListOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - pools, err := dc.GetResourcePools() - if err != nil { - return err - } - printList(pools, nil) - return nil - }) - - type ResourcePoolCreateOptions struct { - DATACENTER string `help:"Create resource pool in datacenter"` - CLUSTER string `help:"Cluster name"` - NAME string `help:"Resource pool name"` - } - - shellutils.R(&ResourcePoolCreateOptions{}, "resource-pool-create", "Create resource pool", func(cli *esxi.SESXiClient, args *ResourcePoolCreateOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - cluster, err := dc.GetCluster(args.CLUSTER) - if err != nil { - return errors.Wrap(err, "GetCluster") - } - pool, err := cluster.CreateResourcePool(args.NAME) - if err != nil { - return err - } - printObject(pool) - return nil - }) -} diff --git a/pkg/multicloud/esxi/shell/store.go b/pkg/multicloud/esxi/shell/store.go deleted file mode 100644 index 0aa0fb4243..0000000000 --- a/pkg/multicloud/esxi/shell/store.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "context" - "fmt" - "os" - - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/util/printutils" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func getDatastore(cli *esxi.SESXiClient, dcId string, dsId string) (*esxi.SDatastore, error) { - dc, err := cli.FindDatacenterByMoId(dcId) - if err != nil { - return nil, err - } - ds, err := dc.GetIStorageByMoId(dsId) - if err != nil { - return nil, err - } - return ds.(*esxi.SDatastore), nil -} - -func init() { - type DatastoreListOptions struct { - DATACENTER string `help:"List datastores in datacenter"` - } - shellutils.R(&DatastoreListOptions{}, "ds-list", "List datastores in datacenter", func(cli *esxi.SESXiClient, args *DatastoreListOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - ds, err := dc.GetIStorages() - if err != nil { - return err - } - printList(ds, nil) - return nil - }) - - type DatastoreShowOptions struct { - DATACENTER string `help:"Datacenter"` - DSID string `help:"Datastore ID"` - } - shellutils.R(&DatastoreShowOptions{}, "ds-show", "Show details of a datastore", func(cli *esxi.SESXiClient, args *DatastoreShowOptions) error { - ds, err := getDatastore(cli, args.DATACENTER, args.DSID) - if err != nil { - return err - } - printObject(ds) - return nil - }) - - shellutils.R(&DatastoreShowOptions{}, "ds-cache-show", "Show details of a datastore image cache", func(cli *esxi.SESXiClient, args *DatastoreShowOptions) error { - ds, err := getDatastore(cli, args.DATACENTER, args.DSID) - if err != nil { - return err - } - cache := ds.GetIStoragecache() - printObject(cache) - return nil - }) - - shellutils.R(&DatastoreShowOptions{}, "ds-cache-list", "Show image list of a datastore image cache", func(cli *esxi.SESXiClient, args *DatastoreShowOptions) error { - ds, err := getDatastore(cli, args.DATACENTER, args.DSID) - if err != nil { - return err - } - cache := ds.GetIStoragecache() - images, err := cache.GetICloudImages() - if err != nil { - return err - } - printList(images, []string{}) - return nil - }) - - type DatastoreListDirOptions struct { - DATACENTER string `help:"Datacenter"` - DSID string `help:"Datastore ID"` - DIR string `help:"directory"` - } - shellutils.R(&DatastoreListDirOptions{}, "ds-list-dir", "List directory of a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { - dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) - if err != nil { - return err - } - ctx := context.Background() - fileList, err := dsObj.ListDir(ctx, args.DIR) - if err != nil { - return err - } - printutils.PrintInterfaceList(fileList, 0, 0, 0, []string{"Name", "Date", "Size"}) - return nil - }) - - shellutils.R(&DatastoreListDirOptions{}, "ds-check-file", "Check file status in a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { - dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) - if err != nil { - return err - } - ctx := context.Background() - file, err := dsObj.CheckFile(ctx, args.DIR) - if err != nil { - return err - } - printutils.PrintInterfaceObject(file) - return nil - }) - - shellutils.R(&DatastoreListDirOptions{}, "ds-delete-file", "Delete file in a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { - dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) - if err != nil { - return err - } - ctx := context.Background() - err = dsObj.Delete(ctx, args.DIR) - if err != nil { - return err - } - fmt.Println("success") - return nil - }) - - shellutils.R(&DatastoreListDirOptions{}, "ds-check-vmdk", "Check vmdk file status in a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { - dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) - if err != nil { - return err - } - ctx := context.Background() - err = dsObj.CheckVmdk(ctx, args.DIR) - if err != nil { - return err - } - fmt.Println("valid") - return nil - }) - - shellutils.R(&DatastoreListDirOptions{}, "ds-delete-vmdk", "Delete vmdk file from a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { - dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) - if err != nil { - return err - } - ctx := context.Background() - err = dsObj.DeleteVmdk(ctx, args.DIR) - if err != nil { - return err - } - fmt.Println("success") - return nil - }) - - shellutils.R(&DatastoreListDirOptions{}, "ds-mkdir", "Delete vmdk directory from a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { - dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) - if err != nil { - return err - } - err = dsObj.MakeDir(args.DIR) - if err != nil { - return err - } - fmt.Println("Make dir success") - return nil - }) - - shellutils.R(&DatastoreListDirOptions{}, "ds-rmdir", "Remove vmdk directory from a datastore", func(cli *esxi.SESXiClient, args *DatastoreListDirOptions) error { - dsObj, err := getDatastore(cli, args.DATACENTER, args.DSID) - if err != nil { - return err - } - ctx := context.Background() - err = dsObj.RemoveDir(ctx, args.DIR) - if err != nil { - return err - } - fmt.Println("Remove dir success") - return nil - }) - - type DatastoreDownloadOptions struct { - DATACENTER string `help:"Datacenter"` - DSID string `help:"Datastore ID"` - DIR string `help:"directory"` - LOCAL string `help:"local file"` - } - shellutils.R(&DatastoreDownloadOptions{}, "ds-download", "Download file from a datastore", func(cli *esxi.SESXiClient, args *DatastoreDownloadOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - ds, err := dc.GetIStorageByMoId(args.DSID) - if err != nil { - return err - } - ctx := context.Background() - dsObj := ds.(*esxi.SDatastore) - - file, err := os.Create(args.LOCAL) - if err != nil { - return err - } - defer file.Close() - - err = dsObj.Download(ctx, args.DIR, file) - if err != nil { - return err - } - - return nil - }) - - shellutils.R(&DatastoreDownloadOptions{}, "ds-upload", "Upload local file to datastore", func(cli *esxi.SESXiClient, args *DatastoreDownloadOptions) error { - dc, err := cli.FindDatacenterByMoId(args.DATACENTER) - if err != nil { - return err - } - ds, err := dc.GetIStorageByMoId(args.DSID) - if err != nil { - return err - } - ctx := context.Background() - dsObj := ds.(*esxi.SDatastore) - - file, err := os.Open(args.LOCAL) - if err != nil { - return err - } - defer file.Close() - - err = dsObj.Upload(ctx, args.DIR, file) - if err != nil { - return err - } - - return nil - }) - -} diff --git a/pkg/multicloud/esxi/shell/utils.go b/pkg/multicloud/esxi/shell/utils.go deleted file mode 100644 index d65f357863..0000000000 --- a/pkg/multicloud/esxi/shell/utils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import "yunion.io/x/onecloud/pkg/util/printutils" - -func printList(data interface{}, columns []string) { - printutils.PrintInterfaceList(data, 0, 0, 0, columns) -} - -func printObject(obj interface{}) { - printutils.PrintGetterObject(obj) -} diff --git a/pkg/multicloud/esxi/shell/virtualmachine.go b/pkg/multicloud/esxi/shell/virtualmachine.go deleted file mode 100644 index 56d3dd9af6..0000000000 --- a/pkg/multicloud/esxi/shell/virtualmachine.go +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "context" - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/esxi" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VirtualMachineListOptions struct { - Datacenter string `help:"Datacenter"` - HostIP string `help:"HostIP"` - FakeRegex string `help:"regex for fake template' name"` - Datastore string `help:"Datastore"` - Template bool `help:"Whether it is tempalte virtual machine, default:false"` - } - shellutils.R(&VirtualMachineListOptions{}, "vm-list", "List vms of a host", func(cli *esxi.SESXiClient, args *VirtualMachineListOptions) error { - var ( - vms []*esxi.SVirtualMachine - err error - ) - switch { - case len(args.HostIP) > 0: - host, err := cli.FindHostByIp(args.HostIP) - if err != nil { - return err - } - if args.Template { - vms, err := host.GetTemplateVMs() - if err != nil { - return err - } - printList(vms, []string{}) - return nil - } - vms, err := host.GetIVMs2() - if err != nil { - return err - } - printList(vms, []string{}) - return nil - case len(args.Datacenter) > 0: - var fetcher esxi.VMFetcher - if len(args.Datastore) > 0 { - ds, err := getDatastore(cli, args.Datacenter, args.Datastore) - if err != nil { - return err - } - fetcher = ds - } else { - dc, err := cli.FindDatacenterByMoId(args.Datacenter) - if err != nil { - return errors.Wrap(err, "FindDatacenterByMoId") - } - fetcher = dc - } - if args.Template { - if len(args.FakeRegex) > 0 { - fmt.Printf("regex: %s\n", args.FakeRegex) - vms, err = fetcher.FetchFakeTempateVMs(args.FakeRegex) - if err != nil { - return errors.Wrap(err, "FetchFakeTempateVMs") - } - } else { - vms, err = fetcher.FetchTemplateVMs() - if err != nil { - return errors.Wrap(err, "FetchTemplateVMs") - } - } - } else { - vms, err = fetcher.FetchNoTemplateVMs() - if err != nil { - return errors.Wrap(err, "FetchNoTemplateVMs") - } - } - default: - return fmt.Errorf("Both Datacenter and HostIP cannot be empty") - } - printList(vms, []string{}) - return nil - }) - - type VirtualMachineCloneOptions struct { - HOSTIP string `help:"Host IP"` - TEMPLATEID string `help:"id of template ma"` - NAME string `help:"New VM's name'"` - Uuid string `help:"Uuid of new VM"` - CpuNum int `help:"Number of CPU"` - MemSize int `help:"Size of Memory(MB)"` - } - shellutils.R(&VirtualMachineCloneOptions{}, "vm-clone", "Clone vm", func(cli *esxi.SESXiClient, - args *VirtualMachineCloneOptions) error { - host, err := cli.FindHostByIp(args.HOSTIP) - if err != nil { - return err - } - idss, err := host.GetDataStores() - if err != nil { - return err - } - if len(idss) == 0 { - return fmt.Errorf("no datastore") - } - temVm, err := host.GetTemplateVMById(args.TEMPLATEID) - if err != nil { - return err - } - createParams := esxi.SCreateVMParam{ - Name: args.NAME, - Uuid: args.Uuid, - Cpu: args.CpuNum, - Mem: args.MemSize, - } - vm, err := host.CloneVM(context.Background(), temVm, nil, idss[0].(*esxi.SDatastore), createParams) - if err != nil { - return errors.Wrap(err, "SHost.CloneVMFromTemplate") - } - printObject(vm) - return nil - }) - - type VirtualMachineShowOptions struct { - Datacenter string `help:"Datacenter"` - HostIP string `help:"Host IP"` - VMID string `help:"VM ID"` - } - getVM := func(cli *esxi.SESXiClient, args *VirtualMachineShowOptions) (*esxi.SVirtualMachine, error) { - var vm *esxi.SVirtualMachine - switch { - case len(args.HostIP) > 0: - host, err := cli.FindHostByIp(args.HostIP) - if err != nil { - return nil, errors.Wrap(err, "FindHostByIp") - } - ivm, err := host.GetIVMById(args.VMID) - if err != nil && errors.Cause(err) != errors.ErrNotFound { - return nil, err - } - if err != nil { - vm, err = host.GetTemplateVMById(args.VMID) - if err != nil { - return nil, errors.Wrap(err, "GetTemplateVMById") - } - } - vm = ivm.(*esxi.SVirtualMachine) - case len(args.Datacenter) > 0: - dc, err := cli.FindDatacenterByMoId(args.Datacenter) - if err != nil { - return nil, errors.Wrap(err, "FindDatacenterByMoId") - } - vm, err = dc.FetchVMById(args.VMID) - if err != nil { - return nil, errors.Wrap(err, "FetchVMById") - } - default: - return nil, fmt.Errorf("Both Datacenter and HostIP cannot be empty") - } - return vm, nil - } - shellutils.R(&VirtualMachineShowOptions{}, "vm-show", "Show vm details", func(cli *esxi.SESXiClient, args *VirtualMachineShowOptions) error { - vm, err := getVM(cli, args) - if err != nil { - return err - } - printObject(vm) - return nil - }) - - shellutils.R(&VirtualMachineShowOptions{}, "vm-nics", "Show vm nics details", func(cli *esxi.SESXiClient, args *VirtualMachineShowOptions) error { - vm, err := getVM(cli, args) - if err != nil { - return err - } - vmnics, err := vm.GetINics() - if err != nil { - return err - } - printList(vmnics, []string{}) - return nil - }) - - shellutils.R(&VirtualMachineShowOptions{}, "vm-snapshots", "Show vm snapshots details", func(cli *esxi.SESXiClient, args *VirtualMachineShowOptions) error { - vm, err := getVM(cli, args) - if err != nil { - return err - } - vmsps, err := vm.GetInstanceSnapshots() - if err != nil { - return err - } - printList(vmsps, []string{}) - return nil - }) - - type VirtualMachineSnapshotCreateOptions struct { - VirtualMachineShowOptions - NAME string `help:"Name of snapshot"` - Desc string `help:"Description of snapshot"` - } - shellutils.R(&VirtualMachineSnapshotCreateOptions{}, "vm-snapshot-create", "Create vm snapshot", func(cli *esxi.SESXiClient, args *VirtualMachineSnapshotCreateOptions) error { - vm, err := getVM(cli, &args.VirtualMachineShowOptions) - if err != nil { - return err - } - sp, err := vm.CreateInstanceSnapshot(context.Background(), args.NAME, args.Desc) - if err != nil { - return err - } - printObject(sp) - return nil - }) - - type VirtualMachineSnapshotOptions struct { - VirtualMachineShowOptions - ID string `help:"ID of snapshot"` - } - shellutils.R(&VirtualMachineSnapshotOptions{}, "vm-snapshot-delete", "Delete vm snapshot", func(cli *esxi.SESXiClient, args *VirtualMachineSnapshotOptions) error { - vm, err := getVM(cli, &args.VirtualMachineShowOptions) - if err != nil { - return err - } - sp, err := vm.GetInstanceSnapshot(args.ID) - if err != nil { - return err - } - err = sp.Delete() - if err != nil { - return err - } - return nil - }) - shellutils.R(&VirtualMachineSnapshotOptions{}, "vm-snapshot-reset", "Reset vm to snapshot", func(cli *esxi.SESXiClient, args *VirtualMachineSnapshotOptions) error { - vm, err := getVM(cli, &args.VirtualMachineShowOptions) - if err != nil { - return err - } - err = vm.ResetToInstanceSnapshot(context.Background(), args.ID) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&VirtualMachineShowOptions{}, "vm-disks", "Show vm disks details", func(cli *esxi.SESXiClient, args *VirtualMachineShowOptions) error { - vm, err := getVM(cli, args) - if err != nil { - return err - } - vmdisks, err := vm.GetIDisks() - if err != nil { - return err - } - printList(vmdisks, []string{}) - return nil - }) - - type VirtualMachineDiskResizeOptions struct { - VirtualMachineShowOptions - DISKIDX int `help:"disk index"` - SIZEGB int64 `help:"new size of disk"` - } - shellutils.R(&VirtualMachineDiskResizeOptions{}, "vm-disk-resize", "Resize a vm disk", func(cli *esxi.SESXiClient, args *VirtualMachineDiskResizeOptions) error { - vm, err := getVM(cli, &args.VirtualMachineShowOptions) - if err != nil { - return err - } - vmdisks, err := vm.GetIDisks() - if err != nil { - return err - } - if args.DISKIDX < 0 || args.DISKIDX >= len(vmdisks) { - return fmt.Errorf("Out of index: %d", args.DISKIDX) - } - disk := vmdisks[args.DISKIDX] - ctx := context.Background() - return disk.Resize(ctx, args.SIZEGB*1024) - }) - - shellutils.R(&VirtualMachineShowOptions{}, "vm-vnc", "Show vm VNC details", func(cli *esxi.SESXiClient, args *VirtualMachineShowOptions) error { - vm, err := getVM(cli, args) - if err != nil { - return err - } - info, err := vm.GetVNCInfo(nil) - if err != nil { - return err - } - printObject(info) - return nil - }) - - shellutils.R(&VirtualMachineShowOptions{}, "vm-vmrc", "Show vm VMRC connection", func(cli *esxi.SESXiClient, args *VirtualMachineShowOptions) error { - vm, err := getVM(cli, args) - if err != nil { - return err - } - info, err := vm.GetVmrcInfo() - if err != nil { - return err - } - printObject(info) - return nil - }) - - shellutils.R(&VirtualMachineShowOptions{}, "vm-webmks", "Show vm webmks connection", func(cli *esxi.SESXiClient, args *VirtualMachineShowOptions) error { - vm, err := getVM(cli, args) - if err != nil { - return err - } - info, err := vm.GetWebmksInfo() - if err != nil { - return err - } - printObject(info) - return nil - }) - - shellutils.R(&VirtualMachineShowOptions{}, "vm-file-status", "Show vm files details", func(cli *esxi.SESXiClient, args *VirtualMachineShowOptions) error { - vm, err := getVM(cli, args) - if err != nil { - return err - } - err = vm.CheckFileInfo(context.Background()) - if err != nil { - return err - } - return nil - }) - -} diff --git a/pkg/multicloud/esxi/snapshot.go b/pkg/multicloud/esxi/snapshot.go deleted file mode 100644 index 667e532516..0000000000 --- a/pkg/multicloud/esxi/snapshot.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "fmt" - - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/vim25/methods" - "github.com/vmware/govmomi/vim25/types" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVirtualMachineSnapshot struct { - multicloud.SResourceBase - multicloud.STagBase - snapshotTree types.VirtualMachineSnapshotTree - vm *SVirtualMachine -} - -func NewSnapshot(st types.VirtualMachineSnapshotTree) *SVirtualMachineSnapshot { - return &SVirtualMachineSnapshot{ - snapshotTree: st, - } -} - -func (s *SVirtualMachineSnapshot) GetId() string { - return moRefId(s.snapshotTree.Snapshot) -} - -func (s *SVirtualMachineSnapshot) GetName() string { - return s.snapshotTree.Name -} - -func (s *SVirtualMachineSnapshot) GetDescription() string { - return s.snapshotTree.Description -} - -func (s *SVirtualMachineSnapshot) GetGlobalId() string { - return fmt.Sprintf("%s-%d", s.vm.GetGlobalId(), s.snapshotTree.Id) -} - -func (s *SVirtualMachineSnapshot) GetStatus() string { - return api.INSTANCE_SNAPSHOT_READY -} - -func (s *SVirtualMachineSnapshot) Refresh() error { - return nil -} - -func (s *SVirtualMachineSnapshot) IsEmulated() bool { - return false -} - -func (s *SVirtualMachineSnapshot) GetProjectId() string { - return s.vm.GetProjectId() -} - -func (s *SVirtualMachineSnapshot) Delete() error { - cTrue := true - req := types.RemoveSnapshot_Task{ - This: s.snapshotTree.Snapshot.Reference(), - RemoveChildren: false, - Consolidate: &cTrue, - } - res, err := methods.RemoveSnapshot_Task(s.vm.manager.context, s.vm.manager.client.Client, &req) - if err != nil { - return errors.Wrap(err, "RemoveSnapshot_Task") - } - return object.NewTask(s.vm.manager.client.Client, res.Returnval).Wait(s.vm.manager.context) -} diff --git a/pkg/multicloud/esxi/storage.go b/pkg/multicloud/esxi/storage.go deleted file mode 100644 index 3232ee9e0d..0000000000 --- a/pkg/multicloud/esxi/storage.go +++ /dev/null @@ -1,1198 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "bytes" - "context" - "encoding/binary" - "fmt" - "io" - "io/ioutil" - "math/rand" - "net/http" - "net/url" - "os" - "path" - "path/filepath" - "regexp" - "strconv" - "strings" - "text/template" - "time" - "unicode" - - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/ovf" - "github.com/vmware/govmomi/property" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/progress" - "github.com/vmware/govmomi/vim25/soap" - "github.com/vmware/govmomi/vim25/types" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/vmdkutils" -) - -var DATASTORE_PROPS = []string{"name", "parent", "info", "summary", "host", "vm"} - -type SDatastore struct { - multicloud.SStorageBase - SManagedObject - - // vms []cloudprovider.ICloudVM - - ihosts []cloudprovider.ICloudHost - idisks []cloudprovider.ICloudDisk - - storageCache *SDatastoreImageCache -} - -func NewDatastore(manager *SESXiClient, ds *mo.Datastore, dc *SDatacenter) *SDatastore { - return &SDatastore{SManagedObject: newManagedObject(manager, ds, dc)} -} - -func (self *SDatastore) getDatastore() *mo.Datastore { - return self.object.(*mo.Datastore) -} - -func (self *SDatastore) GetGlobalId() string { - volId, err := self.getVolumeId() - if err != nil { - log.Errorf("get datastore global ID error %s", err) - } - return volId -} - -func (self *SDatastore) GetName() string { - volName, err := self.getVolumeName() - if err != nil { - log.Fatalf("datastore get name error %s", err) - } - return fmt.Sprintf("%s-%s", self.getVolumeType(), volName) -} - -func (self *SDatastore) GetRelName() string { - return self.getDatastore().Info.GetDatastoreInfo().Name -} - -func (self *SDatastore) GetCapacityMB() int64 { - moStore := self.getDatastore() - return moStore.Summary.Capacity / 1024 / 1024 -} - -func (self *SDatastore) GetCapacityUsedMB() int64 { - moStore := self.getDatastore() - return self.GetCapacityMB() - moStore.Summary.FreeSpace/1024/1024 -} - -func (self *SDatastore) GetEnabled() bool { - return true -} - -func (self *SDatastore) GetStatus() string { - if self.getDatastore().Summary.Accessible { - return api.STORAGE_ONLINE - } else { - return api.STORAGE_OFFLINE - } -} - -func (self *SDatastore) Refresh() error { - base := self.SManagedObject - var moObj mo.Datastore - err := self.manager.reference2Object(self.object.Reference(), DATASTORE_PROPS, &moObj) - if err != nil { - return err - } - base.object = &moObj - *self = SDatastore{} - self.SManagedObject = base - return nil -} - -func (self *SDatastore) IsEmulated() bool { - return false -} - -func (self *SDatastore) getVolumeId() (string, error) { - moStore := self.getDatastore() - switch fsInfo := moStore.Info.(type) { - case *types.VmfsDatastoreInfo: - if fsInfo.Vmfs.Local == nil || *fsInfo.Vmfs.Local { - host, err := self.getLocalHost() - if err == nil { - return fmt.Sprintf("%s:%s", host.GetAccessIp(), fsInfo.Vmfs.Uuid), nil - } - } - return fsInfo.Vmfs.Uuid, nil - case *types.NasDatastoreInfo: - return fmt.Sprintf("%s:%s", fsInfo.Nas.RemoteHost, fsInfo.Nas.RemotePath), nil - } - if moStore.Summary.Type == "vsan" { - vsanId := moStore.Summary.Url - vsanId = vsanId[strings.Index(vsanId, "vsan:"):] - endIdx := len(vsanId) - for ; endIdx >= 0 && vsanId[endIdx-1] == '/'; endIdx -= 1 { - } - return vsanId[:endIdx], nil - } - log.Fatalf("unsupported volume type %#v", moStore.Info) - return "", cloudprovider.ErrNotImplemented -} - -func (self *SDatastore) getVolumeType() string { - return self.getDatastore().Summary.Type -} - -func (self *SDatastore) getVolumeName() (string, error) { - moStore := self.getDatastore() - - if self.isLocalVMFS() { - host, err := self.getLocalHost() - if err != nil { - return "", err - } - return fmt.Sprintf("%s-%s", host.GetAccessIp(), moStore.Info.GetDatastoreInfo().Name), nil - } - dc, err := self.GetDatacenter() - if err != nil { - return "", nil - } - return fmt.Sprintf("%s-%s", dc.GetName(), moStore.Info.GetDatastoreInfo().Name), nil -} - -func (self *SDatastore) getAttachedHosts() ([]cloudprovider.ICloudHost, error) { - ihosts := make([]cloudprovider.ICloudHost, 0) - - moStore := self.getDatastore() - for i := 0; i < len(moStore.Host); i += 1 { - idstr := moRefId(moStore.Host[i].Key) - host, err := self.datacenter.GetIHostByMoId(idstr) - if err != nil { - return nil, err - } - ihosts = append(ihosts, host) - } - - return ihosts, nil -} - -func (self *SDatastore) getCachedAttachedHosts() ([]cloudprovider.ICloudHost, error) { - if self.ihosts == nil { - var err error - self.ihosts, err = self.getAttachedHosts() - if err != nil { - return nil, err - } - } - return self.ihosts, nil -} - -func (self *SDatastore) GetAttachedHosts() ([]cloudprovider.ICloudHost, error) { - return self.getCachedAttachedHosts() -} - -func (self *SDatastore) getLocalHost() (cloudprovider.ICloudHost, error) { - hosts, err := self.GetAttachedHosts() - if err != nil { - return nil, errors.Wrap(err, "self.GetAttachedHosts") - } - if len(hosts) == 1 { - return hosts[0], nil - } - return nil, cloudprovider.ErrInvalidStatus -} - -func (self *SDatastore) GetIStoragecache() cloudprovider.ICloudStoragecache { - if self.isLocalVMFS() { - ihost, err := self.getLocalHost() - if err != nil { - log.Errorf("GetIStoragecache getLocalHost fail %s", err) - return nil - } - host := ihost.(*SHost) - sc, err := host.getLocalStorageCache() - if err != nil { - log.Errorf("GetIStoragecache getLocalStorageCache fail %s", err) - return nil - } - return sc - } else { - return self.getStorageCache() - } -} - -func (self *SDatastore) getStorageCache() *SDatastoreImageCache { - if self.storageCache == nil { - self.storageCache = &SDatastoreImageCache{ - datastore: self, - } - } - return self.storageCache -} - -func (self *SDatastore) GetIZone() cloudprovider.ICloudZone { - return nil -} - -func (self *SDatastore) FetchNoTemplateVMs() ([]*SVirtualMachine, error) { - mods := self.getDatastore() - filter := property.Filter{} - filter["datastore"] = mods.Reference() - return self.datacenter.fetchVMsWithFilter(filter) -} - -func (self *SDatastore) FetchTemplateVMs() ([]*SVirtualMachine, error) { - mods := self.getDatastore() - filter := property.Filter{} - filter["config.template"] = true - filter["datastore"] = mods.Reference() - return self.datacenter.fetchVMsWithFilter(filter) -} - -func (self *SDatastore) FetchTemplateVMById(id string) (*SVirtualMachine, error) { - mods := self.getDatastore() - filter := property.Filter{} - uuid := toTemplateUuid(id) - filter["summary.config.uuid"] = uuid - filter["config.template"] = true - filter["datastore"] = mods.Reference() - vms, err := self.datacenter.fetchVMsWithFilter(filter) - if err != nil { - return nil, err - } - if len(vms) == 0 { - return nil, errors.ErrNotFound - } - return vms[0], nil -} - -func (self *SDatastore) FetchFakeTempateVMById(id string, regex string) (*SVirtualMachine, error) { - mods := self.getDatastore() - filter := property.Filter{} - uuid := toTemplateUuid(id) - filter["summary.config.uuid"] = uuid - filter["datastore"] = mods.Reference() - filter["summary.runtime.powerState"] = types.VirtualMachinePowerStatePoweredOff - filter["config.template"] = false - movms, err := self.datacenter.fetchMoVms(filter, []string{"name"}) - if err != nil { - return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines") - } - vms, err := self.datacenter.fetchFakeTemplateVMs(movms, regex) - if err != nil { - return nil, err - } - if len(vms) == 0 { - return nil, errors.ErrNotFound - } - return vms[0], nil -} - -func (self *SDatastore) FetchFakeTempateVMs(regex string) ([]*SVirtualMachine, error) { - mods := self.getDatastore() - filter := property.Filter{} - filter["datastore"] = mods.Reference() - filter["summary.runtime.powerState"] = types.VirtualMachinePowerStatePoweredOff - filter["config.template"] = false - movms, err := self.datacenter.fetchMoVms(filter, []string{"name"}) - if err != nil { - return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines") - } - return self.datacenter.fetchFakeTemplateVMs(movms, regex) -} - -func (self *SDatastore) getVMs() ([]cloudprovider.ICloudVM, error) { - dc, err := self.GetDatacenter() - if err != nil { - log.Errorf("SDatastore GetDatacenter fail %s", err) - return nil, err - } - vms := self.getDatastore().Vm - if len(vms) == 0 { - return nil, nil - } - svms, err := dc.fetchVmsFromCache(vms) - if err != nil { - return nil, err - } - ret := make([]cloudprovider.ICloudVM, len(svms)) - for i := range svms { - ret[i] = svms[i] - } - return ret, err -} - -func (self *SDatastore) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - vms, err := self.getVMs() - if err != nil { - log.Errorf("self.getVMs fail %s", err) - return nil, err - } - for i := 0; i < len(vms); i += 1 { - vm := vms[i].(*SVirtualMachine) - disk, err := vm.GetIDiskById(idStr) - if err == nil { - return disk, nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SDatastore) fetchDisks() error { - vms, err := self.getVMs() - if err != nil { - return err - } - allDisks := make([]cloudprovider.ICloudDisk, 0) - for i := 0; i < len(vms); i += 1 { - disks, err := vms[i].GetIDisks() - if err != nil { - return err - } - allDisks = append(allDisks, disks...) - } - self.idisks = allDisks - return nil -} - -func (self *SDatastore) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - if self.idisks != nil { - return self.idisks, nil - } - err := self.fetchDisks() - if err != nil { - return nil, err - } - return self.idisks, nil -} - -func (self *SDatastore) isLocalVMFS() bool { - moStore := self.getDatastore() - switch vmfsInfo := moStore.Info.(type) { - case *types.VmfsDatastoreInfo: - if vmfsInfo.Vmfs.Local == nil || *vmfsInfo.Vmfs.Local == true { - _, err := self.getLocalHost() - if err == nil { - return true - } - } - } - return false -} - -func (self *SDatastore) GetStorageType() string { - moStore := self.getDatastore() - t := strings.ToLower(moStore.Summary.Type) - switch t { - case "vmfs": - if self.isLocalVMFS() { - return api.STORAGE_LOCAL - } else { - return api.STORAGE_NAS - } - case "nfs", "nfs41": - return api.STORAGE_NFS - case "vsan": - return api.STORAGE_VSAN - case "cifs": - return api.STORAGE_CIFS - default: - log.Fatalf("unsupported datastore type %s", moStore.Summary.Type) - return "" - } -} - -func (self *SDatastore) GetMediumType() string { - moStore := self.getDatastore() - vmfsInfo, ok := moStore.Info.(*types.VmfsDatastoreInfo) - if ok && vmfsInfo.Vmfs.Ssd != nil && *vmfsInfo.Vmfs.Ssd { - return api.DISK_TYPE_SSD - } - return api.DISK_TYPE_ROTATE -} - -func (self *SDatastore) GetStorageConf() jsonutils.JSONObject { - conf := jsonutils.NewDict() - conf.Add(jsonutils.NewString(self.GetName()), "name") - conf.Add(jsonutils.NewString(self.GetGlobalId()), "id") - conf.Add(jsonutils.NewString(self.GetDatacenterPathString()), "dc_path") - volId, err := self.getVolumeId() - if err != nil { - log.Errorf("getVaolumeId fail %s", err) - } - conf.Add(jsonutils.NewString(volId), "volume_id") - - volType := self.getVolumeType() - conf.Add(jsonutils.NewString(volType), "volume_type") - - volName, err := self.getVolumeName() - if err != nil { - log.Errorf("getVaolumeName fail %s", err) - } - conf.Add(jsonutils.NewString(volName), "volume_name") - return conf -} - -const dsPrefix = "ds://" - -func (self *SDatastore) GetUrl() string { - url := self.getDatastore().Info.GetDatastoreInfo().Url - if strings.HasPrefix(url, dsPrefix) { - url = url[len(dsPrefix):] - } - return url -} - -func (self *SDatastore) GetMountPoint() string { - return self.GetUrl() -} - -func (self *SDatastore) HasFile(remotePath string) bool { - dsName := fmt.Sprintf("[%s]", self.SManagedObject.GetName()) - if strings.HasPrefix(remotePath, dsName) { - return true - } else { - return false - } -} - -func (self *SDatastore) cleanPath(remotePath string) string { - dsName := fmt.Sprintf("[%s]", self.SManagedObject.GetName()) - dsUrl := self.GetUrl() - if strings.HasPrefix(remotePath, dsName) { - remotePath = remotePath[len(dsName):] - } else if strings.HasPrefix(remotePath, dsUrl) { - remotePath = remotePath[len(dsUrl):] - } - return strings.TrimSpace(remotePath) -} - -func pathEscape(path string) string { - segs := strings.Split(path, "/") - for i := 0; i < len(segs); i += 1 { - segs[i] = url.PathEscape(segs[i]) - } - return strings.Join(segs, "/") -} - -func (self *SDatastore) GetPathUrl(remotePath string) string { - remotePath = self.cleanPath(remotePath) - if len(remotePath) == 0 || remotePath[0] != '/' { - remotePath = fmt.Sprintf("/%s", remotePath) - } - httpUrl := fmt.Sprintf("%s/folder%s", self.getManagerUri(), pathEscape(remotePath)) - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(self.SManagedObject.GetName()), "dsName") - params.Add(jsonutils.NewString(self.GetDatacenterPathString()), "dcPath") - - return fmt.Sprintf("%s?%s", httpUrl, params.QueryString()) -} - -func (self *SDatastore) getPathString(path string) string { - for len(path) > 0 && path[0] == '/' { - path = path[1:] - } - return fmt.Sprintf("[%s] %s", self.SManagedObject.GetName(), path) -} - -func (self *SDatastore) GetFullPath(remotePath string) string { - remotePath = self.cleanPath(remotePath) - return path.Join(self.GetUrl(), remotePath) -} - -func (self *SDatastore) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SDatastore) FileGetContent(ctx context.Context, remotePath string) ([]byte, error) { - url := self.GetPathUrl(remotePath) - - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - - var bytes []byte - - err = self.manager.client.Do(ctx, req, func(resp *http.Response) error { - if resp.StatusCode == 404 { - return cloudprovider.ErrNotFound - } - if resp.StatusCode >= 400 { - return fmt.Errorf("%s", resp.Status) - } - cont, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - bytes = cont - return nil - }) - - return bytes, err -} - -type SDatastoreFileInfo struct { - Url string - Name string - Date time.Time - FileType string - Size uint64 -} - -const ( - fileListPattern = `(?P[^<]+)<\/a>(?P[^<]+)(?P[^<]+)` - fileDateFormat = "02-Jan-2006 15:04" - fileDateFormat2 = "Mon, 2 Jan 2006 15:04:05 GMT" -) - -var ( - fileListRegexp = regexp.MustCompile(fileListPattern) -) - -func (self *SDatastore) ListDir(ctx context.Context, remotePath string) ([]SDatastoreFileInfo, error) { - listContent, err := self.FileGetContent(ctx, remotePath) - if err != nil { - return nil, err - } - ret := make([]SDatastoreFileInfo, 0) - matches := fileListRegexp.FindAllStringSubmatch(string(listContent), -1) - for r := 0; r < len(matches); r += 1 { - url := strings.TrimSpace(matches[r][1]) - name := strings.TrimSpace(matches[r][2]) - dateStr := strings.TrimSpace(matches[r][3]) - sizeStr := strings.TrimSpace(matches[r][4]) - var ftype string - var size uint64 - if sizeStr == "-" { - ftype = "dir" - size = 0 - } else { - ftype = "file" - size, _ = strconv.ParseUint(sizeStr, 10, 64) - } - date, err := time.Parse(fileDateFormat, dateStr) - if err != nil { - return nil, err - } - info := SDatastoreFileInfo{ - Url: url, - Name: name, - FileType: ftype, - Size: size, - Date: date, - } - ret = append(ret, info) - } - - return ret, nil -} - -func (self *SDatastore) listPath(b *object.HostDatastoreBrowser, path string, spec types.HostDatastoreBrowserSearchSpec) ([]types.HostDatastoreBrowserSearchResults, error) { - ctx := context.TODO() - - path = self.getDatastoreObj().Path(path) - - search := b.SearchDatastore - - task, err := search(ctx, path, &spec) - if err != nil { - return nil, err - } - - info, err := task.WaitForResult(ctx, nil) - if err != nil { - return nil, err - } - - switch r := info.Result.(type) { - case types.HostDatastoreBrowserSearchResults: - return []types.HostDatastoreBrowserSearchResults{r}, nil - case types.ArrayOfHostDatastoreBrowserSearchResults: - return r.HostDatastoreBrowserSearchResults, nil - default: - return nil, errors.Error(fmt.Sprintf("unknown result type: %T", r)) - } - -} - -func (self *SDatastore) ListPath(ctx context.Context, remotePath string) ([]types.HostDatastoreBrowserSearchResults, error) { - //types.HostDatastoreBrowserSearchResults - ds := self.getDatastoreObj() - - b, err := ds.Browser(ctx) - if err != nil { - return nil, err - } - - ret := make([]types.HostDatastoreBrowserSearchResults, 0) - - spec := types.HostDatastoreBrowserSearchSpec{ - MatchPattern: []string{"*"}, - Details: &types.FileQueryFlags{ - FileType: true, - FileSize: true, - FileOwner: types.NewBool(true), // TODO: omitempty is generated, but seems to be required - Modification: true, - }, - } - - for i := 0; ; i++ { - r, err := self.listPath(b, remotePath, spec) - if err != nil { - // Treat the argument as a match pattern if not found as directory - if i == 0 && types.IsFileNotFound(err) || isInvalid(err) { - spec.MatchPattern[0] = path.Base(remotePath) - remotePath = path.Dir(remotePath) - continue - } - if types.IsFileNotFound(err) { - return nil, errors.ErrNotFound - } - return nil, err - } - if i == 1 && len(r) == 1 && len(r[0].File) == 0 { - return nil, errors.ErrNotFound - } - for n := range r { - ret = append(ret, r[n]) - } - break - } - return ret, nil -} - -func isInvalid(err error) bool { - if f, ok := err.(types.HasFault); ok { - switch f.Fault().(type) { - case *types.InvalidArgument: - return true - } - } - - return false -} - -func (self *SDatastore) CheckFile(ctx context.Context, remotePath string) (*SDatastoreFileInfo, error) { - url := self.GetPathUrl(remotePath) - - req, err := http.NewRequest("HEAD", url, nil) - if err != nil { - return nil, err - } - - var size uint64 - var date time.Time - - err = self.manager.client.Do(ctx, req, func(resp *http.Response) error { - if resp.StatusCode >= 400 { - if resp.StatusCode == 404 { - return cloudprovider.ErrNotFound - } - return fmt.Errorf("%s", resp.Status) - } - sizeStr := resp.Header.Get("Content-Length") - size, _ = strconv.ParseUint(sizeStr, 10, 64) - - dateStr := resp.Header.Get("Date") - date, _ = time.Parse(fileDateFormat2, dateStr) - return nil - }) - - if err != nil { - return nil, err - } - return &SDatastoreFileInfo{Date: date, Size: size}, nil -} - -func (self *SDatastore) Download(ctx context.Context, remotePath string, writer io.Writer) error { - url := self.GetPathUrl(remotePath) - - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return err - } - - err = self.manager.client.Do(ctx, req, func(resp *http.Response) error { - if resp.StatusCode >= 400 { - return fmt.Errorf("%s", resp.Status) - } - buffer := make([]byte, 4096) - for { - rn, re := resp.Body.Read(buffer) - if rn > 0 { - wo := 0 - for wo < rn { - wn, we := writer.Write(buffer[wo:rn]) - if we != nil { - return we - } - wo += wn - } - } - if re != nil { - if re != io.EOF { - return re - } else { - break - } - } - } - return nil - }) - - return err -} - -func (self *SDatastore) Upload(ctx context.Context, remotePath string, body io.Reader) error { - url := self.GetPathUrl(remotePath) - - req, err := http.NewRequest("PUT", url, body) - if err != nil { - return err - } - - err = self.manager.client.Do(ctx, req, func(resp *http.Response) error { - if resp.StatusCode >= 400 { - return fmt.Errorf("%s", resp.Status) - } - _, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - // log.Debugf("upload respose %s", buffer) - return nil - }) - - return err -} - -func (self *SDatastore) FilePutContent(ctx context.Context, remotePath string, content string) error { - return self.Upload(ctx, remotePath, strings.NewReader(content)) -} - -// Delete2 can delete file from this Datastore. -// isNamespace: remotePath is uuid of namespace on vsan datastore -// force: ignore nonexistent files and arguments -func (self *SDatastore) Delete2(ctx context.Context, remotePath string, isNamespace, force bool) error { - var err error - ds := self.getDatastoreObj() - dc := self.datacenter.getObjectDatacenter() - if isNamespace { - nm := object.NewDatastoreNamespaceManager(self.manager.client.Client) - err = nm.DeleteDirectory(ctx, dc, remotePath) - } else { - fm := ds.NewFileManager(dc, force) - err = fm.Delete(ctx, remotePath) - } - - if err != nil && types.IsFileNotFound(err) && force { - // Ignore error - return nil - } - return err -} - -func (self *SDatastore) Delete(ctx context.Context, remotePath string) error { - url := self.GetPathUrl(remotePath) - - req, err := http.NewRequest("DELETE", url, nil) - if err != nil { - return err - } - - err = self.manager.client.Do(ctx, req, func(resp *http.Response) error { - if resp.StatusCode >= 400 { - return fmt.Errorf("%s", resp.Status) - } - _, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - // log.Debugf("delete respose %s", buffer) - return nil - }) - - return err -} - -func (self *SDatastore) DeleteVmdk(ctx context.Context, remotePath string) error { - info, err := self.CheckFile(ctx, remotePath) - if err != nil { - return err - } - if info.Size > 4096 { - return fmt.Errorf("not a valid vmdk file") - } - vmdkContent, err := self.FileGetContent(ctx, remotePath) - if err != nil { - return err - } - vmdkInfo, err := vmdkutils.Parse(string(vmdkContent)) - if err != nil { - return err - } - err = self.Delete(ctx, remotePath) - if err != nil { - return err - } - if len(vmdkInfo.ExtentFile) > 0 { - err = self.Delete(ctx, path.Join(path.Dir(remotePath), vmdkInfo.ExtentFile)) - if err != nil { - return err - } - } - return nil -} - -func (self *SDatastore) GetVmdkInfo(ctx context.Context, remotePath string) (*vmdkutils.SVMDKInfo, error) { - vmdkContent, err := self.FileGetContent(ctx, remotePath) - if err != nil { - return nil, err - } - return vmdkutils.Parse(string(vmdkContent)) -} - -func (self *SDatastore) CheckVmdk(ctx context.Context, remotePath string) error { - dm := object.NewVirtualDiskManager(self.manager.client.Client) - - dc, err := self.GetDatacenter() - if err != nil { - return err - } - - dcObj := dc.getObjectDatacenter() - - infoList, err := dm.QueryVirtualDiskInfo(ctx, self.getPathString(remotePath), dcObj, true) - if err != nil { - return err - } - - log.Debugf("%#v", infoList) - return nil -} - -func (self *SDatastore) getDatastoreObj() *object.Datastore { - od := object.NewDatastore(self.manager.client.Client, self.getDatastore().Self) - od.DatacenterPath = self.GetDatacenterPathString() - od.InventoryPath = fmt.Sprintf("%s/%s", od.DatacenterPath, self.SManagedObject.GetName()) - return od -} - -func (self *SDatastore) MakeDir(remotePath string) error { - remotePath = self.cleanPath(remotePath) - - m := object.NewFileManager(self.manager.client.Client) - path := fmt.Sprintf("[%s] %s", self.GetRelName(), remotePath) - return m.MakeDirectory(self.manager.context, path, self.datacenter.getObjectDatacenter(), true) -} - -func (self *SDatastore) RemoveDir(ctx context.Context, remotePath string) error { - dnm := object.NewDatastoreNamespaceManager(self.manager.client.Client) - - remotePath = self.GetFullPath(remotePath) - - dc, err := self.GetDatacenter() - if err != nil { - return err - } - - dcObj := dc.getObjectDatacenter() - - return dnm.DeleteDirectory(ctx, dcObj, remotePath) -} - -// CheckDirC will check that Dir 'remotePath' is exist, if not, create one. -func (self *SDatastore) CheckDirC(remotePath string) error { - _, err := self.CheckFile(self.manager.context, remotePath) - if err == nil { - return nil - } - if errors.Cause(err) != cloudprovider.ErrNotFound { - return err - } - return self.MakeDir(remotePath) - -} - -func (self *SDatastore) IsSysDiskStore() bool { - return true -} - -func (self *SDatastore) MoveVmdk(ctx context.Context, srcPath string, dstPath string) error { - dm := object.NewVirtualDiskManager(self.manager.client.Client) - defer dm.Destroy(ctx) - - srcUrl := self.GetPathUrl(srcPath) - dstUrl := self.GetPathUrl(dstPath) - task, err := dm.MoveVirtualDisk(ctx, srcUrl, nil, dstUrl, nil, true) - if err != nil { - return err - } - return task.Wait(ctx) -} - -// domainName will abandon the rune which should't disapear -func (self *SDatastore) domainName(name string) string { - var b bytes.Buffer - for _, r := range name { - if b.Len() == 0 { - if unicode.IsLetter(r) { - b.WriteRune(r) - } - } else { - if unicode.IsDigit(r) || unicode.IsLetter(r) || r == '-' { - b.WriteRune(r) - } - } - } - return strings.TrimRight(b.String(), "-") -} - -// ImportVMDK will upload local vmdk 'diskFile' to the 'remotePath' of remote datastore -func (self *SDatastore) ImportVMDK(ctx context.Context, diskFile, remotePath string, host *SHost) error { - name := fmt.Sprintf("yunioncloud.%s%d", self.domainName(remotePath)[:20], rand.Int()) - vm, err := self.ImportVM(ctx, diskFile, name, host) - if err != nil { - return errors.Wrap(err, "SDatastore.ImportVM") - } - - defer func() { - task, err := vm.Destroy(ctx) - if err != nil { - log.Errorf("vm.Destory: %s", err) - return - } - - if err = task.Wait(ctx); err != nil { - log.Errorf("task.Wait: %s", err) - } - }() - - // check if 'image_cache' is esixt - err = self.CheckDirC("image_cache") - if err != nil { - return errors.Wrap(err, "SDatastore.CheckDirC") - } - - fm := self.getDatastoreObj().NewFileManager(self.datacenter.getObjectDatacenter(), true) - - // if image_cache not exist - return fm.Move(ctx, fmt.Sprintf("[%s] %s/%s.vmdk", self.GetRelName(), name, name), fmt.Sprintf("[%s] %s", - self.GetRelName(), remotePath)) -} - -func (self *SDatastore) ImportISO(ctx context.Context, isoFile, remotePath string, host *SHost) error { - p := soap.DefaultUpload - ds := self.getDatastoreObj() - return ds.UploadFile(ctx, isoFile, remotePath, &p) -} - -var ( - ErrInvalidFormat = errors.Error("vmdk: invalid format (must be streamOptimized)") -) - -// info is used to inspect a vmdk and generate an ovf template -type info struct { - Header struct { - MagicNumber uint32 - Version uint32 - Flags uint32 - Capacity uint64 - } - - Capacity uint64 - Size int64 - Name string - ImportName string -} - -// stat looks at the vmdk header to make sure the format is streamOptimized and -// extracts the disk capacity required to properly generate the ovf descriptor. -func stat(name string) (*info, error) { - f, err := os.Open(name) - if err != nil { - return nil, err - } - - var ( - di info - buf bytes.Buffer - ) - - _, err = io.CopyN(&buf, f, int64(binary.Size(di.Header))) - fi, _ := f.Stat() - _ = f.Close() - if err != nil { - return nil, err - } - - err = binary.Read(&buf, binary.LittleEndian, &di.Header) - if err != nil { - return nil, err - } - - if di.Header.MagicNumber != 0x564d444b { // SPARSE_MAGICNUMBER - return nil, ErrInvalidFormat - } - - if di.Header.Flags&(1<<16) == 0 { // SPARSEFLAG_COMPRESSED - // Needs to be converted, for example: - // vmware-vdiskmanager -r src.vmdk -t 5 dst.vmdk - // qemu-img convert -O vmdk -o subformat=streamOptimized src.vmdk dst.vmdk - return nil, ErrInvalidFormat - } - - di.Capacity = di.Header.Capacity * 512 // VMDK_SECTOR_SIZE - di.Size = fi.Size() - di.Name = filepath.Base(name) - di.ImportName = strings.TrimSuffix(di.Name, ".vmdk") - - return &di, nil -} - -// ovf returns an expanded descriptor template -func (di *info) ovf() (string, error) { - var buf bytes.Buffer - - tmpl, err := template.ParseFiles("/opt/yunion/share/vmware/ovf.xml") - if err != nil { - return "", err - } - - err = tmpl.Execute(&buf, di) - if err != nil { - return "", err - } - - return buf.String(), nil -} - -// ImportParams contains the set of optional params to the Import function. -// Note that "optional" may depend on environment, such as ESX or vCenter. -type ImportParams struct { - Path string - Logger progress.Sinker - Type types.VirtualDiskType - Force bool - Datacenter *object.Datacenter - Pool *object.ResourcePool - Folder *object.Folder - Host *object.HostSystem -} - -// ImportVM will import a vm by uploading a local vmdk -func (self *SDatastore) ImportVM(ctx context.Context, diskFile, name string, host *SHost) (*object.VirtualMachine, error) { - - var ( - c = self.manager.client.Client - datastore = self.getDatastoreObj() - ) - - m := ovf.NewManager(c) - - disk, err := stat(diskFile) - if err != nil { - return nil, errors.Wrap(err, "stat") - } - - disk.ImportName = name - - // Expand the ovf template - descriptor, err := disk.ovf() - if err != nil { - return nil, errors.Wrap(err, "disk.ovf") - } - - folders, err := self.datacenter.getObjectDatacenter().Folders(ctx) - if err != nil { - return nil, errors.Wrap(err, "Folders") - } - pool, err := host.GetResourcePool() - if err != nil { - return nil, errors.Wrap(err, "getResourcePool") - } - - kind := types.VirtualDiskTypeThin - - params := types.OvfCreateImportSpecParams{ - DiskProvisioning: string(kind), - EntityName: disk.ImportName, - } - - spec, err := m.CreateImportSpec(ctx, descriptor, pool, datastore, params) - if err != nil { - return nil, err - } - if spec.Error != nil { - return nil, errors.Error(spec.Error[0].LocalizedMessage) - } - - lease, err := pool.ImportVApp(ctx, spec.ImportSpec, folders.VmFolder, host.GetoHostSystem()) - if err != nil { - return nil, err - } - - info, err := lease.Wait(ctx, spec.FileItem) - if err != nil { - return nil, err - } - - f, err := os.Open(diskFile) - if err != nil { - return nil, err - } - - lr := newLeaseLogger("upload vmdk", 5) - - lr.Log() - defer lr.End() - - opts := soap.Upload{ - ContentLength: disk.Size, - Progress: lr, - } - - u := lease.StartUpdater(ctx, info) - defer u.Done() - - item := info.Items[0] // we only have 1 disk to upload - - err = lease.Upload(ctx, item, f, opts) - - _ = f.Close() - - if err != nil { - return nil, errors.Wrap(err, "lease.Upload") - } - - if err = lease.Complete(ctx); err != nil { - log.Debugf("lease complete error: %s, sleep 1s and try again", err) - time.Sleep(time.Second) - if err = lease.Complete(ctx); err != nil { - return nil, errors.Wrap(err, "lease.Complete") - } - } - - return object.NewVirtualMachine(c, info.Entity), nil -} diff --git a/pkg/multicloud/esxi/storagecache.go b/pkg/multicloud/esxi/storagecache.go deleted file mode 100644 index abd0263941..0000000000 --- a/pkg/multicloud/esxi/storagecache.go +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "context" - "fmt" - "path" - "regexp" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - IMAGE_CACHE_DIR_NAME = "image_cache" -) - -type SDatastoreImageCache struct { - multicloud.SResourceBase - multicloud.STagBase - datastore *SDatastore - host *SHost -} - -type EsxiOptions struct { - ReasonableCIDREsxi string `help:"Reasonable CIDR in esxi, such as '10.0.0.0/8'" defautl:""` - TemplateNameRegex string `help:"Regex of template name"` -} - -var tempalteNameRegex *regexp.Regexp - -func InitEsxiConfig(opt EsxiOptions) error { - var err error - if len(opt.TemplateNameRegex) != 0 { - tempalteNameRegex, err = regexp.Compile(opt.TemplateNameRegex) - if err != nil { - return errors.Wrap(err, "regexp.Compile") - } - } - return initVMIPV4Filter(opt.ReasonableCIDREsxi) -} - -func (self *SDatastoreImageCache) GetId() string { - if self.host != nil { - return self.host.GetGlobalId() - } else { - return self.datastore.GetGlobalId() - } -} - -func (self *SDatastoreImageCache) GetName() string { - if self.host != nil { - return fmt.Sprintf("storage-cache-%s", self.host.GetName()) - } else { - return fmt.Sprintf("storage-cache-%s", self.datastore.GetName()) - } -} - -func (self *SDatastoreImageCache) GetGlobalId() string { - return self.GetId() -} - -func (self *SDatastoreImageCache) GetStatus() string { - return "available" -} - -func (self *SDatastoreImageCache) Refresh() error { - return nil -} - -func (self *SDatastoreImageCache) IsEmulated() bool { - return false -} - -func (self *SDatastoreImageCache) GetPath() string { - return path.Join(self.datastore.GetMountPoint(), IMAGE_CACHE_DIR_NAME) -} - -func (self *SDatastoreImageCache) getTempalteVMs() ([]*SVirtualMachine, error) { - return self.datastore.FetchTemplateVMs() -} - -func (self *SDatastoreImageCache) getFakeTempateVMs() ([]*SVirtualMachine, error) { - if tempalteNameRegex == nil { - return nil, nil - } - return self.datastore.FetchFakeTempateVMs("") -} - -func (self *SDatastoreImageCache) GetIImageInImagecache() ([]cloudprovider.ICloudImage, error) { - ctx := context.Background() - ret := make([]cloudprovider.ICloudImage, 0, 2) - files, err := self.datastore.ListDir(ctx, IMAGE_CACHE_DIR_NAME) - if errors.Cause(err) == errors.ErrNotFound { - return ret, nil - } - if err != nil { - log.Errorf("GetIImages ListDir fail %s", err) - return ret, nil - } - - validFilenames := make(map[string]bool) - - for i := 0; i < len(files); i += 1 { - filename := path.Join(IMAGE_CACHE_DIR_NAME, files[i].Name) - if err := self.datastore.CheckVmdk(ctx, filename); err != nil { - continue - } - vmdkInfo, err := self.datastore.GetVmdkInfo(ctx, filename) - if err != nil { - continue - } - image := SImage{ - cache: self, - filename: filename, - size: vmdkInfo.Size(), - createAt: files[i].Date, - } - ret = append(ret, &image) - vmdkName := files[i].Name - vmdkExtName := fmt.Sprintf("%s-flat.vmdk", vmdkName[:len(vmdkName)-5]) - validFilenames[vmdkName] = true - validFilenames[vmdkExtName] = true - } - - log.Debugf("storage cache contains %#v", validFilenames) - // cleanup storage cache!!! - for i := 0; i < len(files); i += 1 { - if _, ok := validFilenames[files[i].Name]; !ok { - log.Debugf("delete invalid vmdk file %s!!!", files[i].Name) - self.datastore.Delete(ctx, path.Join(IMAGE_CACHE_DIR_NAME, files[i].Name)) - } - } - - return ret, nil -} - -var ErrTimeConsuming = errors.Error("time consuming") - -func (self *SDatastoreImageCache) getTemplateVMsFromCache() ([]*SVirtualMachine, error) { - ihosts, err := self.datastore.datacenter.GetIHosts() - if err != nil { - return nil, err - } - dsRef := self.datastore.getDatastore().Self - ret := make([]*SVirtualMachine, 0) - for i := range ihosts { - tvms := ihosts[i].(*SHost).tempalteVMs - if tvms == nil { - return nil, ErrTimeConsuming - } - for _, vm := range tvms { - dss := vm.getVirtualMachine().Datastore - for _, ds := range dss { - if ds == dsRef { - ret = append(ret, vm) - break - } - } - } - } - return ret, nil -} - -func (self *SDatastoreImageCache) GetIImageInTemplateVMs() ([]cloudprovider.ICloudImage, error) { - ret := make([]cloudprovider.ICloudImage, 0, 2) - log.Infof("start to GetIImages") - - datastore := self.datastore - if datastore.datacenter.ihosts != nil { - vms, err := self.getTemplateVMsFromCache() - if err == nil { - for i := range vms { - ret = append(ret, NewVMTemplate(vms[i], self)) - } - return ret, nil - } - } - realTemplates, err := self.getTempalteVMs() - if err != nil { - return nil, errors.Wrap(err, "getTemplateVMs") - } - fakeTemplates, err := self.getFakeTempateVMs() - if err != nil { - return nil, errors.Wrap(err, "getFakeTempateVMs") - } - - for i := range realTemplates { - ret = append(ret, NewVMTemplate(realTemplates[i], self)) - } - for i := range fakeTemplates { - ret = append(ret, NewVMTemplate(fakeTemplates[i], self)) - } - - log.Infof("get templates successfully") - log.Debugf("fake template name: ") - for i := range fakeTemplates { - log.Debugf("%s ", fakeTemplates[i].GetName()) - } - log.Debugf("real template name: ") - for i := range realTemplates { - log.Debugf("%s ", realTemplates[i].GetName()) - } - return ret, nil -} - -func (self *SDatastoreImageCache) GetIImageInTemplateVMsById(id string) (cloudprovider.ICloudImage, error) { - if tempalteNameRegex != nil { - vm, err := self.datastore.FetchFakeTempateVMById(id, "") - log.Infof("FetchFakeTempateVMById: %v, %v", vm, err) - if err == nil { - return NewVMTemplate(vm, self), nil - } - if errors.Cause(err) != errors.ErrNotFound { - return nil, err - } - } - vm, err := self.datastore.FetchTemplateVMById(id) - if err == nil { - return NewVMTemplate(vm, self), nil - } - return nil, err -} - -func (self *SDatastoreImageCache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SDatastoreImageCache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - images1, err := self.GetIImageInTemplateVMs() - if err != nil { - return nil, err - } - return images1, nil - // images2, err := self.GetIImageInImagecache() - // if err != nil { - // return nil, err - // } - // return append(images1, images2...), nil -} - -func (self *SDatastoreImageCache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - // check templatevms - image, err := self.GetIImageInTemplateVMsById(extId) - if err == nil { - return image, nil - } - if errors.Cause(err) != errors.ErrNotFound { - return nil, err - } - log.Infof("start to GetIImageInImagecache") - images, err := self.GetIImageInImagecache() - if err != nil { - return nil, err - } - for i := 0; i < len(images); i += 1 { - if images[i].GetGlobalId() == extId { - return images[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SDatastoreImageCache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SDatastoreImageCache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SDatastoreImageCache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return "", cloudprovider.ErrNotImplemented -} diff --git a/pkg/multicloud/esxi/utils_test.go b/pkg/multicloud/esxi/utils_test.go deleted file mode 100644 index e6a260bc5a..0000000000 --- a/pkg/multicloud/esxi/utils_test.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import "testing" - -func TestInitValue(t *testing.T) { - type testStruct struct { - member1 int - member2 string - Member3 int - Member4 string - } - - dst := testStruct{} - - dst.member1 = 1 - dst.member2 = "2" - dst.Member3 = 3 - dst.Member4 = "4" - - pDst := &dst - t.Logf("%p %#v", pDst, pDst) - - *pDst = testStruct{} - - t.Logf("%p %#v", pDst, pDst) - - new := testStruct{} - if dst != new { - t.Errorf("dst != new") - } -} diff --git a/pkg/multicloud/esxi/vcenter/doc.go b/pkg/multicloud/esxi/vcenter/doc.go deleted file mode 100644 index be6c19349c..0000000000 --- a/pkg/multicloud/esxi/vcenter/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 vcenter // import "yunion.io/x/onecloud/pkg/multicloud/esxi/vcenter" diff --git a/pkg/multicloud/esxi/virtualmachine.go b/pkg/multicloud/esxi/virtualmachine.go deleted file mode 100644 index e8ba358289..0000000000 --- a/pkg/multicloud/esxi/virtualmachine.go +++ /dev/null @@ -1,1534 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 esxi - -import ( - "context" - "fmt" - "reflect" - "sort" - "strings" - "time" - - "github.com/vmware/govmomi/nfc" - "github.com/vmware/govmomi/object" - "github.com/vmware/govmomi/vim25/methods" - "github.com/vmware/govmomi/vim25/mo" - "github.com/vmware/govmomi/vim25/soap" - "github.com/vmware/govmomi/vim25/types" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - "yunion.io/x/pkg/util/reflectutils" - "yunion.io/x/pkg/util/regutils" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - cloudtypes "yunion.io/x/onecloud/pkg/cloudcommon/types" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/imagetools" - "yunion.io/x/onecloud/pkg/util/netutils2" - "yunion.io/x/onecloud/pkg/util/version" -) - -var ( - vmSummaryProps = []string{"summary.runtime.powerState", "summary.config.uuid", "summary.config.memorySizeMB", "summary.config.numCpu"} - // vmConfigProps = []string{"config.template", "config.alternateGuestName", "config.hardware", "config.guestId", "config.guestFullName", "config.firmware", "config.version", "config.createDate"} - vmGuestProps = []string{"guest.net", "guest.guestState", "guest.toolsStatus", "guest.toolsRunningStatus", "guest.toolsVersion"} - vmLayoutExProps = []string{"layoutEx.file"} -) - -var VIRTUAL_MACHINE_PROPS = []string{"name", "parent", "resourcePool", "snapshot", "config"} - -func init() { - VIRTUAL_MACHINE_PROPS = append(VIRTUAL_MACHINE_PROPS, vmSummaryProps...) - // VIRTUAL_MACHINE_PROPS = append(VIRTUAL_MACHINE_PROPS, vmConfigProps...) - VIRTUAL_MACHINE_PROPS = append(VIRTUAL_MACHINE_PROPS, vmGuestProps...) -} - -type SVirtualMachine struct { - multicloud.SInstanceBase - multicloud.STagBase - SManagedObject - - vnics []SVirtualNIC - vdisks []SVirtualDisk - vga SVirtualVGA - cdroms []SVirtualCdrom - devs map[int32]SVirtualDevice - ihost cloudprovider.ICloudHost - snapshots []SVirtualMachineSnapshot - - guestIps map[string]string - - osInfo *imagetools.ImageInfo -} - -type VMFetcher interface { - FetchNoTemplateVMs() ([]*SVirtualMachine, error) - FetchTemplateVMs() ([]*SVirtualMachine, error) - FetchFakeTempateVMs(string) ([]*SVirtualMachine, error) -} - -type byDiskType []SVirtualDisk - -func (d byDiskType) Len() int { return len(d) } -func (d byDiskType) Swap(i, j int) { d[i], d[j] = d[j], d[i] } -func (d byDiskType) Less(i, j int) bool { - if d[i].GetDiskType() == api.DISK_TYPE_SYS { - return true - } - return false -} - -func NewVirtualMachine(manager *SESXiClient, vm *mo.VirtualMachine, dc *SDatacenter) *SVirtualMachine { - svm := &SVirtualMachine{SManagedObject: newManagedObject(manager, vm, dc)} - err := svm.fetchHardwareInfo() - if err != nil { - log.Errorf("NewVirtualMachine: %v", err) - return nil - } - return svm -} - -func (self *SVirtualMachine) GetSecurityGroupIds() ([]string, error) { - return []string{}, cloudprovider.ErrNotSupported -} - -func (self *SVirtualMachine) GetSysTags() map[string]string { - meta := map[string]string{} - meta["datacenter"] = self.GetDatacenterPathString() - rp, _ := self.getResourcePool() - if rp != nil { - rpPath := rp.GetPath() - rpOffset := -1 - for i := range rpPath { - if rpPath[i] == "Resources" { - if i > 0 { - meta["cluster"] = rpPath[i-1] - rpOffset = i - } - } else if rpOffset >= 0 && i > rpOffset { - meta[fmt.Sprintf("pool%d", i-rpOffset-1)] = rpPath[i] - } - } - } - return meta -} - -func (self *SVirtualMachine) getVirtualMachine() *mo.VirtualMachine { - return self.object.(*mo.VirtualMachine) -} - -func (self *SVirtualMachine) GetGlobalId() string { - return self.getUuid() -} - -func (self *SVirtualMachine) GetHostname() string { - return self.GetName() -} - -func (self *SVirtualMachine) GetStatus() string { - // err := self.CheckFileInfo(context.Background()) - // if err != nil { - // return api.VM_UNKNOWN - // } - vm := object.NewVirtualMachine(self.manager.client.Client, self.getVirtualMachine().Self) - state, err := vm.PowerState(self.manager.context) - if err != nil { - return api.VM_UNKNOWN - } - switch state { - case types.VirtualMachinePowerStatePoweredOff: - return api.VM_READY - case types.VirtualMachinePowerStatePoweredOn: - return api.VM_RUNNING - case types.VirtualMachinePowerStateSuspended: - return api.VM_SUSPEND - default: - return api.VM_UNKNOWN - } -} - -func (self *SVirtualMachine) Refresh() error { - base := self.SManagedObject - var moObj mo.VirtualMachine - err := self.manager.reference2Object(self.object.Reference(), VIRTUAL_MACHINE_PROPS, &moObj) - if err != nil { - return err - } - base.object = &moObj - *self = SVirtualMachine{} - self.SManagedObject = base - self.fetchHardwareInfo() - return nil -} - -func (self *SVirtualMachine) IsEmulated() bool { - return false -} - -func (self *SVirtualMachine) GetInstanceType() string { - return "" -} - -func (self *SVirtualMachine) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SVirtualMachine) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - return "", cloudprovider.ErrNotImplemented -} - -func (self *SVirtualMachine) DoRebuildRoot(ctx context.Context, imagePath string, uuid string) error { - if len(self.vdisks) == 0 { - return errors.ErrNotFound - } - return self.rebuildDisk(ctx, &self.vdisks[0], imagePath) -} - -func (self *SVirtualMachine) rebuildDisk(ctx context.Context, disk *SVirtualDisk, imagePath string) error { - uuid := disk.GetId() - sizeMb := disk.GetDiskSizeMB() - diskKey := disk.getKey() - ctlKey := disk.getControllerKey() - unitNumber := *disk.dev.GetVirtualDevice().UnitNumber - - err := self.doDetachAndDeleteDisk(ctx, disk) - if err != nil { - return err - } - return self.createDiskInternal(ctx, SDiskConfig{ - SizeMb: int64(sizeMb), - Uuid: uuid, - ControllerKey: ctlKey, - UnitNumber: unitNumber, - Key: diskKey, - ImagePath: imagePath, - IsRoot: len(imagePath) > 0, - }, false) -} - -func (self *SVirtualMachine) UpdateVM(ctx context.Context, name string) error { - return cloudprovider.ErrNotImplemented -} - -// TODO: detach disk to a separate directory, so as to keep disk independent of VM - -func (self *SVirtualMachine) DetachDisk(ctx context.Context, diskId string) error { - vdisk, err := self.GetIDiskById(diskId) - if err != nil { - return err - } - return self.doDetachDisk(ctx, vdisk.(*SVirtualDisk), false) -} - -func (self *SVirtualMachine) AttachDisk(ctx context.Context, diskId string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SVirtualMachine) getUuid() string { - return self.getVirtualMachine().Summary.Config.Uuid -} - -func (self *SVirtualMachine) GetIHost() cloudprovider.ICloudHost { - if self.ihost == nil { - self.ihost = self.getIHost() - } - return self.ihost -} - -func (self *SVirtualMachine) getIHost() cloudprovider.ICloudHost { - vm := self.getVmObj() - - hostsys, err := vm.HostSystem(self.manager.context) - if err != nil { - log.Errorf("fail to find host system for vm %s", err) - return nil - } - ihost, err := self.manager.FindHostByMoId(moRefId(hostsys.Reference())) - if err != nil { - log.Errorf("fail to find host %s for vm %s???", hostsys.Name(), self.GetName()) - return nil - } - return ihost -} - -func (self *SVirtualMachine) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - idisks := make([]cloudprovider.ICloudDisk, len(self.vdisks)) - for i := 0; i < len(self.vdisks); i += 1 { - idisks[i] = &(self.vdisks[i]) - } - return idisks, nil -} - -func (self *SVirtualMachine) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - for i := 0; i < len(self.vdisks); i += 1 { - if self.vdisks[i].MatchId(idStr) { - return &self.vdisks[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SVirtualMachine) GetINics() ([]cloudprovider.ICloudNic, error) { - inics := make([]cloudprovider.ICloudNic, len(self.vnics)) - for i := 0; i < len(self.vnics); i += 1 { - inics[i] = &(self.vnics[i]) - } - return inics, nil -} - -func (self *SVirtualMachine) GetIEIP() (cloudprovider.ICloudEIP, error) { - return nil, nil -} - -func (self *SVirtualMachine) GetVcpuCount() int { - return int(self.getVirtualMachine().Summary.Config.NumCpu) -} - -func (self *SVirtualMachine) GetVmemSizeMB() int { - return int(self.getVirtualMachine().Summary.Config.MemorySizeMB) -} - -func (self *SVirtualMachine) GetBootOrder() string { - return "cdn" -} - -func (self *SVirtualMachine) GetVga() string { - return "vga" -} - -func (self *SVirtualMachine) GetVdi() string { - return "vmrc" -} - -func (self *SVirtualMachine) GetGuestFamily() string { - moVM := self.getVirtualMachine() - return moVM.Config.AlternateGuestName -} - -func (self *SVirtualMachine) GetGuestId() string { - moVM := self.getVirtualMachine() - return moVM.Config.GuestId -} - -func (self *SVirtualMachine) GetGuestFullName() string { - moVM := self.getVirtualMachine() - return moVM.Config.GuestFullName -} - -func (self *SVirtualMachine) GetGuestState() string { - moVM := self.getVirtualMachine() - return moVM.Guest.GuestState -} - -func (self *SVirtualMachine) GetGuestToolsStatus() string { - moVM := self.getVirtualMachine() - return string(moVM.Guest.ToolsStatus) -} - -func (self *SVirtualMachine) isToolsOk() bool { - switch self.getVirtualMachine().Guest.ToolsStatus { - case types.VirtualMachineToolsStatusToolsNotInstalled: - return false - case types.VirtualMachineToolsStatusToolsNotRunning: - return false - } - return true -} - -func (self *SVirtualMachine) GetGuestToolsRunningStatus() string { - moVM := self.getVirtualMachine() - return string(moVM.Guest.ToolsRunningStatus) -} - -func (vm *SVirtualMachine) getNormalizedOsInfo() *imagetools.ImageInfo { - if vm.osInfo == nil { - if osInfo, ok := GuestOsInfo[vm.GetGuestId()]; ok { - osInfo := imagetools.NormalizeImageInfo("", string(osInfo.OsArch), string(osInfo.OsType), osInfo.OsDistribution, osInfo.OsVersion) - vm.osInfo = &osInfo - } else { - osInfo := imagetools.NormalizeImageInfo("", "", "", "", "") - vm.osInfo = &osInfo - } - } - return vm.osInfo -} - -func (vm *SVirtualMachine) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(vm.getNormalizedOsInfo().OsType) -} - -func (vm *SVirtualMachine) GetFullOsName() string { - return vm.getNormalizedOsInfo().GetFullOsName() -} - -func (vm *SVirtualMachine) GetOsDist() string { - return vm.getNormalizedOsInfo().OsDistro -} - -func (vm *SVirtualMachine) GetOsVersion() string { - return vm.getNormalizedOsInfo().OsVersion -} - -func (vm *SVirtualMachine) GetOsLang() string { - return vm.getNormalizedOsInfo().OsLang -} - -func (vm *SVirtualMachine) GetOsArch() string { - return vm.getNormalizedOsInfo().OsArch -} - -func (vm *SVirtualMachine) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(vm.getBios()) -} - -func (vm *SVirtualMachine) getBios() string { - // self.obj.config.firmware - switch vm.getVirtualMachine().Config.Firmware { - case "efi": - return "UEFI" - case "bios": - return "BIOS" - default: - return "BIOS" - } -} - -func (self *SVirtualMachine) GetMachine() string { - return "pc" -} - -func (self *SVirtualMachine) GetHypervisor() string { - return api.HYPERVISOR_ESXI -} - -func (self *SVirtualMachine) getVmObj() *object.VirtualMachine { - return object.NewVirtualMachine(self.manager.client.Client, self.getVirtualMachine().Self) -} - -// ideopotent start -func (self *SVirtualMachine) StartVM(ctx context.Context) error { - if self.GetStatus() == api.VM_RUNNING { - return nil - } - return self.startVM(ctx) -} - -func (self *SVirtualMachine) startVM(ctx context.Context) error { - ihost := self.GetIHost() - if ihost == nil { - return errors.Wrap(httperrors.ErrInvalidStatus, "no valid host") - } - - lockman.LockRawObject(ctx, "host", ihost.GetGlobalId()) - defer lockman.ReleaseRawObject(ctx, "host", ihost.GetGlobalId()) - - err := self.makeNicsStartConnected(ctx) - if err != nil { - log.Errorf("self.makeNicsStartConnected %s", err) - return err - } - - vm := self.getVmObj() - - task, err := vm.PowerOn(ctx) - if err != nil { - log.Errorf("vm.PowerOn %s", err) - return err - } - err = task.Wait(ctx) - if err != nil { - log.Errorf("task.Wait %s", err) - return err - } - return nil -} - -func (self *SVirtualMachine) makeNicsStartConnected(ctx context.Context) error { - spec := types.VirtualMachineConfigSpec{} - spec.DeviceChange = make([]types.BaseVirtualDeviceConfigSpec, len(self.vnics)) - for i := 0; i < len(self.vnics); i += 1 { - spec.DeviceChange[i] = makeNicStartConnected(&self.vnics[i]) - } - - vm := self.getVmObj() - - task, err := vm.Reconfigure(ctx, spec) - if err != nil { - return err - } - return task.Wait(ctx) -} - -func makeNicStartConnected(nic *SVirtualNIC) *types.VirtualDeviceConfigSpec { - editSpec := types.VirtualDeviceConfigSpec{} - editSpec.Operation = types.VirtualDeviceConfigSpecOperationEdit - editSpec.FileOperation = "" - editSpec.Device = nic.dev - editSpec.Device.GetVirtualDevice().Connectable.StartConnected = true - return &editSpec -} - -func (self *SVirtualMachine) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - if self.GetStatus() == api.VM_READY { - return nil - } - if !opts.IsForce && self.isToolsOk() { - return self.shutdownVM(ctx) - } else { - return self.poweroffVM(ctx) - } -} - -func (self *SVirtualMachine) SuspendVM(ctx context.Context) error { - vm := self.getVmObj() - task, err := vm.Suspend(ctx) - if err != nil { - return err - } - return task.Wait(ctx) -} - -func (self *SVirtualMachine) ResumeVM(ctx context.Context) error { - if self.GetStatus() == api.VM_RUNNING { - return nil - } - vm := self.getVmObj() - - task, err := vm.PowerOn(ctx) - if err != nil { - return errors.Wrap(err, "VM.PowerOn") - } - err = task.Wait(ctx) - if err != nil { - return errors.Wrap(err, "Task.Wait after VM.PowerOn") - } - return nil -} - -func (self *SVirtualMachine) poweroffVM(ctx context.Context) error { - vm := self.getVmObj() - - task, err := vm.PowerOff(ctx) - if err != nil { - return err - } - return task.Wait(ctx) -} - -func (self *SVirtualMachine) shutdownVM(ctx context.Context) error { - vm := self.getVmObj() - - err := vm.ShutdownGuest(ctx) - if err != nil { - return err - } - return err -} - -func (self *SVirtualMachine) doDestroy(ctx context.Context) error { - vm := self.getVmObj() - task, err := vm.Destroy(ctx) - if err != nil { - return errors.Wrap(err, "unable to destroy vm") - } - return task.Wait(ctx) -} - -func (self *SVirtualMachine) doDelete(ctx context.Context) error { - // detach all disks first - for i := range self.vdisks { - err := self.doDetachAndDeleteDisk(ctx, &self.vdisks[i]) - if err != nil { - return errors.Wrap(err, "doDetachAndDeteteDisk") - } - } - - return self.doDestroy(ctx) -} - -func (self *SVirtualMachine) doUnregister(ctx context.Context) error { - vm := self.getVmObj() - - err := vm.Unregister(ctx) - if err != nil { - log.Errorf("vm.Unregister(ctx) fail %s", err) - return err - } - return nil -} - -func (self *SVirtualMachine) DeleteVM(ctx context.Context) error { - err := self.CheckFileInfo(ctx) - if err != nil { - return self.doUnregister(ctx) - } - return self.doDestroy(ctx) -} - -func (self *SVirtualMachine) doDetachAndDeleteDisk(ctx context.Context, vdisk *SVirtualDisk) error { - return self.doDetachDisk(ctx, vdisk, true) -} - -func (self *SVirtualMachine) doDetachDisk(ctx context.Context, vdisk *SVirtualDisk, remove bool) error { - removeSpec := types.VirtualDeviceConfigSpec{} - removeSpec.Operation = types.VirtualDeviceConfigSpecOperationRemove - removeSpec.Device = vdisk.dev - - spec := types.VirtualMachineConfigSpec{} - spec.DeviceChange = []types.BaseVirtualDeviceConfigSpec{&removeSpec} - - vm := self.getVmObj() - - task, err := vm.Reconfigure(ctx, spec) - if err != nil { - log.Errorf("vm.Reconfigure fail %s", err) - return err - } - - err = task.Wait(ctx) - if err != nil { - log.Errorf("task.Wait(ctx) fail %s", err) - return err - } - - if !remove { - return nil - } - return vdisk.Delete(ctx) -} - -func (self *SVirtualMachine) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - hostVer := self.GetIHost().GetVersion() - if version.GE(hostVer, "6.5") { - info, err := self.acquireWebmksTicket("webmks") - if err == nil { - return info, nil - } - } - return self.acquireVmrcUrl() -} - -func (self *SVirtualMachine) GetVmrcInfo() (*cloudprovider.ServerVncOutput, error) { - return self.acquireVmrcUrl() -} - -func (self *SVirtualMachine) GetWebmksInfo() (*cloudprovider.ServerVncOutput, error) { - return self.acquireWebmksTicket("webmks") -} - -func (self *SVirtualMachine) acquireWebmksTicket(ticketType string) (*cloudprovider.ServerVncOutput, error) { - vm := object.NewVirtualMachine(self.manager.client.Client, self.getVirtualMachine().Self) - ticket, err := vm.AcquireTicket(self.manager.context, ticketType) - if err != nil { - return nil, err - } - - host := ticket.Host - if len(host) == 0 { - host = self.manager.host - } - port := ticket.Port - if port == 0 { - port = int32(self.manager.port) - } - if port == 0 { - port = 443 - } - ret := &cloudprovider.ServerVncOutput{ - Url: fmt.Sprintf("wss://%s:%d/ticket/%s", host, port, ticket.Ticket), - Protocol: "wmks", - Hypervisor: api.HYPERVISOR_ESXI, - } - return ret, nil -} - -func (self *SVirtualMachine) acquireVmrcUrl() (*cloudprovider.ServerVncOutput, error) { - ticket, err := self.manager.acquireCloneTicket() - if err != nil { - return nil, err - } - port := self.manager.port - if port == 0 { - port = 443 - } - ret := &cloudprovider.ServerVncOutput{ - Url: fmt.Sprintf("vmrc://clone:%s@%s:%d/?moid=%s", ticket, self.manager.host, port, self.GetId()), - Protocol: "vmrc", - } - return ret, nil -} - -func (self *SVirtualMachine) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - return self.doChangeConfig(ctx, int32(config.Cpu), int64(config.MemoryMB), "", "") -} - -func (self *SVirtualMachine) GetVersion() string { - return self.getVirtualMachine().Config.Version -} - -func (self *SVirtualMachine) doChangeConfig(ctx context.Context, ncpu int32, vmemMB int64, guestId string, version string) error { - changed := false - configSpec := types.VirtualMachineConfigSpec{} - if int(ncpu) != self.GetVcpuCount() { - configSpec.NumCPUs = ncpu - changed = true - } - if int(vmemMB) != self.GetVmemSizeMB() { - configSpec.MemoryMB = vmemMB - changed = true - } - if len(guestId) > 0 && guestId != self.GetGuestId() { - configSpec.GuestId = guestId - changed = true - } - if len(version) > 0 && version != self.GetVersion() { - configSpec.Version = version - changed = true - } - if !changed { - return nil - } - - vm := self.getVmObj() - - task, err := vm.Reconfigure(ctx, configSpec) - if err != nil { - return err - } - err = task.Wait(ctx) - if err != nil { - return err - } - return self.Refresh() -} - -func (self *SVirtualMachine) AssignSecurityGroup(secgroupId string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SVirtualMachine) SetSecurityGroups(secgroupIds []string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SVirtualMachine) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SVirtualMachine) GetCreatedAt() time.Time { - moVM := self.getVirtualMachine() - ctm := moVM.Config.CreateDate - if ctm != nil { - return *ctm - } else { - return time.Time{} - } -} - -func (self *SVirtualMachine) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SVirtualMachine) UpdateUserData(userData string) error { - return nil -} - -func (self *SVirtualMachine) fetchHardwareInfo() error { - self.vnics = make([]SVirtualNIC, 0) - self.vdisks = make([]SVirtualDisk, 0) - self.cdroms = make([]SVirtualCdrom, 0) - self.devs = make(map[int32]SVirtualDevice) - - moVM := self.getVirtualMachine() - - // MAX_TRIES := 3 - // for tried := 0; tried < MAX_TRIES && (moVM == nil || moVM.Config == nil || moVM.Config.Hardware.Device == nil); tried += 1 { - // time.Sleep(time.Second) - // } - - if moVM == nil || moVM.Config == nil || moVM.Config.Hardware.Device == nil { - return fmt.Errorf("invalid vm") - } - - // sort devices via their Key - devices := moVM.Config.Hardware.Device - sort.Slice(devices, func(i, j int) bool { - return devices[i].GetVirtualDevice().Key < devices[j].GetVirtualDevice().Key - }) - for i := 0; i < len(devices); i += 1 { - dev := devices[i] - devType := reflect.Indirect(reflect.ValueOf(dev)).Type() - - etherType := reflect.TypeOf((*types.VirtualEthernetCard)(nil)).Elem() - diskType := reflect.TypeOf((*types.VirtualDisk)(nil)).Elem() - vgaType := reflect.TypeOf((*types.VirtualMachineVideoCard)(nil)).Elem() - cdromType := reflect.TypeOf((*types.VirtualCdrom)(nil)).Elem() - - if reflectutils.StructContains(devType, etherType) { - self.vnics = append(self.vnics, NewVirtualNIC(self, dev, len(self.vnics))) - } else if reflectutils.StructContains(devType, diskType) { - self.vdisks = append(self.vdisks, NewVirtualDisk(self, dev, len(self.vdisks))) - } else if reflectutils.StructContains(devType, vgaType) { - self.vga = NewVirtualVGA(self, dev, 0) - } else if reflectutils.StructContains(devType, cdromType) { - self.cdroms = append(self.cdroms, NewVirtualCdrom(self, dev, len(self.cdroms))) - } - vdev := NewVirtualDevice(self, dev, 0) - self.devs[vdev.getKey()] = vdev - } - self.rigorous() - sort.Sort(byDiskType(self.vdisks)) - return nil -} - -func (self *SVirtualMachine) rigorous() { - hasRoot := false - for i := range self.vdisks { - if self.vdisks[i].IsRoot { - hasRoot = true - break - } - } - if !hasRoot && len(self.vdisks) > 0 { - self.vdisks[0].IsRoot = true - } -} - -func (self *SVirtualMachine) getVdev(key int32) SVirtualDevice { - return self.devs[key] -} - -func (self *SVirtualMachine) fetchGuestIps() map[string]string { - guestIps := make(map[string]string) - moVM := self.getVirtualMachine() - for _, net := range moVM.Guest.Net { - mac := netutils.FormatMacAddr(net.MacAddress) - for _, ip := range net.IpAddress { - if regutils.MatchIP4Addr(ip) { - if !vmIPV4Filter.Contains(ip) { - continue - } - guestIps[mac] = ip - break - } - } - } - return guestIps -} - -func (self *SVirtualMachine) getGuestIps() map[string]string { - if self.guestIps == nil { - self.guestIps = self.fetchGuestIps() - } - return self.guestIps -} - -func (self *SVirtualMachine) GetIps() []string { - ips := make([]string, 0) - for _, ip := range self.getGuestIps() { - ips = append(ips, ip) - } - return ips -} - -func (self *SVirtualMachine) GetVGADevice() string { - return fmt.Sprintf("%s", self.vga.String()) -} - -var ( - driverTable = map[string][]string{ - "sata": {"ahci"}, - "scsi": {"parascsi", "lsilogic", "lsilogicsas", "buslogic"}, - "pvscsi": {"parascsi"}, - "ide": {"ide"}, - } -) - -func (self *SVirtualMachine) getDevsByDriver(driver string) []SVirtualDevice { - devs := make([]SVirtualDevice, 0) - for _, drv := range self.devs { - if strings.HasSuffix(drv.GetDriver(), fmt.Sprintf("%scontroller", driver)) { - devs = append(devs, drv) - } - } - return devs -} - -func minDevKey(devs []SVirtualDevice) int32 { - var minKey int32 = -1 - for i := 0; i < len(devs); i += 1 { - if minKey < 0 || minKey > devs[i].getKey() { - minKey = devs[i].getKey() - } - } - return minKey -} - -func minDiskKey(devs []SVirtualDisk) int32 { - var minKey int32 = -1 - for i := 0; i < len(devs); i += 1 { - if minKey < 0 || minKey > devs[i].getKey() { - minKey = devs[i].getKey() - } - } - return minKey -} - -func (self *SVirtualMachine) FindController(ctx context.Context, driver string) ([]SVirtualDevice, error) { - aliasDrivers, ok := driverTable[driver] - if !ok { - return nil, fmt.Errorf("Unsupported disk driver %s", driver) - } - var devs []SVirtualDevice - for _, alias := range aliasDrivers { - devs = self.getDevsByDriver(alias) - if len(devs) > 0 { - break - } - } - return devs, nil -} - -func (self *SVirtualMachine) FindDiskByDriver(drivers ...string) []SVirtualDisk { - disks := make([]SVirtualDisk, 0) - for i := range self.vdisks { - if utils.IsInStringArray(self.vdisks[i].GetDriver(), drivers) { - disks = append(disks, self.vdisks[i]) - } - } - return disks -} - -func (self *SVirtualMachine) devNumWithCtrlKey(ctrlKey int32) int { - n := 0 - for _, dev := range self.devs { - if dev.getControllerKey() == ctrlKey { - n++ - } - } - return n -} - -func (self *SVirtualMachine) getLayoutEx() *types.VirtualMachineFileLayoutEx { - vm := self.getVirtualMachine() - if vm.LayoutEx != nil { - return vm.LayoutEx - } - var nvm mo.VirtualMachine - err := self.manager.reference2Object(vm.Self, vmLayoutExProps, &nvm) - if err != nil { - log.Errorf("unable to fetch LayoutEx.File from vc: %v", err) - } - vm.LayoutEx = nvm.LayoutEx - return vm.LayoutEx -} - -func (self *SVirtualMachine) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) { - if opts.Driver == "pvscsi" { - opts.Driver = "scsi" - } - var ds *SDatastore - var err error - if opts.StorageId != "" { - ihost := self.getIHost() - if ihost == nil { - return "", fmt.Errorf("unable to get host of virtualmachine %s", self.GetName()) - } - ds, err = ihost.(*SHost).FindDataStoreById(opts.StorageId) - if err != nil { - return "", errors.Wrapf(err, "unable to find datastore %s", opts.StorageId) - } - } - devs, err := self.FindController(ctx, opts.Driver) - if err != nil { - return "", err - } - if len(devs) == 0 { - return "", self.createDriverAndDisk(ctx, ds, opts.SizeMb, opts.UUID, opts.Driver) - } - numDevBelowCtrl := make([]int, len(devs)) - for i := range numDevBelowCtrl { - numDevBelowCtrl[i] = self.devNumWithCtrlKey(devs[i].getKey()) - } - - // find the min one - ctrlKey := devs[0].getKey() - unitNumber := numDevBelowCtrl[0] - for i := 1; i < len(numDevBelowCtrl); i++ { - if numDevBelowCtrl[i] >= unitNumber { - continue - } - ctrlKey = devs[i].getKey() - unitNumber = numDevBelowCtrl[i] - } - diskKey := self.FindMinDiffKey(2000) - - // By default, the virtual SCSI controller is assigned to virtual device node (z:7), - // so that device node is unavailable for hard disks or other devices. - if unitNumber >= 7 && opts.Driver == "scsi" { - unitNumber++ - } - - return "", self.createDiskInternal(ctx, SDiskConfig{ - SizeMb: int64(opts.SizeMb), - Uuid: opts.UUID, - UnitNumber: int32(unitNumber), - ControllerKey: ctrlKey, - Key: diskKey, - Datastore: ds, - }, true) -} - -// createDriverAndDisk will create a driver and disk associated with the driver -func (self *SVirtualMachine) createDriverAndDisk(ctx context.Context, ds *SDatastore, sizeMb int, uuid string, driver string) error { - if driver != "scsi" && driver != "pvscsi" { - return fmt.Errorf("Driver %s is not supported", driver) - } - - deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 2) - - // find a suitable key for scsi or pvscsi driver - scsiKey := self.FindMinDiffKey(1000) - deviceChange = append(deviceChange, addDevSpec(NewSCSIDev(scsiKey, 100, driver))) - - // find a suitable key for disk - diskKey := self.FindMinDiffKey(2000) - - if diskKey == scsiKey { - // unarrivelable - log.Errorf("there is no suitable key between 1000 and 2000???!") - } - - return self.createDiskWithDeviceChange(ctx, deviceChange, - SDiskConfig{ - SizeMb: int64(sizeMb), - Uuid: uuid, - ControllerKey: scsiKey, - UnitNumber: 0, - Key: scsiKey, - ImagePath: "", - IsRoot: false, - Datastore: ds, - }, true) -} - -func (self *SVirtualMachine) copyRootDisk(ctx context.Context, imagePath string) (string, error) { - layoutEx := self.getLayoutEx() - if layoutEx == nil || len(layoutEx.File) == 0 { - return "", fmt.Errorf("invalid LayoutEx") - } - file := layoutEx.File[0].Name - // find stroage - host := self.GetIHost() - storages, err := host.GetIStorages() - if err != nil { - return "", errors.Wrap(err, "host.GetIStorages") - } - var datastore *SDatastore - for i := range storages { - ds := storages[i].(*SDatastore) - if ds.HasFile(file) { - datastore = ds - break - } - } - if datastore == nil { - return "", fmt.Errorf("can't find storage associated with vm %q", self.GetName()) - } - path := datastore.cleanPath(file) - vmDir := strings.Split(path, "/")[0] - // TODO find a non-conflicting path - newImagePath := datastore.getPathString(fmt.Sprintf("%s/%s.vmdk", vmDir, vmDir)) - - fm := datastore.getDatastoreObj().NewFileManager(datastore.datacenter.getObjectDatacenter(), true) - err = fm.Copy(ctx, imagePath, newImagePath) - if err != nil { - return "", errors.Wrap(err, "unable to copy system disk") - } - return newImagePath, nil -} - -func (self *SVirtualMachine) createDiskWithDeviceChange(ctx context.Context, deviceChange []types.BaseVirtualDeviceConfigSpec, config SDiskConfig, check bool) error { - var err error - // copy disk - if len(config.ImagePath) > 0 { - config.IsRoot = true - config.ImagePath, err = self.copyRootDisk(ctx, config.ImagePath) - if err != nil { - return errors.Wrap(err, "unable to copyRootDisk") - } - } - - devSpec := NewDiskDev(int64(config.SizeMb), config) - spec := addDevSpec(devSpec) - if len(config.ImagePath) == 0 { - spec.FileOperation = types.VirtualDeviceConfigSpecFileOperationCreate - } - configSpec := types.VirtualMachineConfigSpec{} - configSpec.DeviceChange = append(deviceChange, spec) - - vmObj := self.getVmObj() - - task, err := vmObj.Reconfigure(ctx, configSpec) - if err != nil { - return err - } - err = task.Wait(ctx) - if err != nil { - return err - } - if !check { - return nil - } - oldDiskCnt := len(self.vdisks) - maxTries := 60 - for tried := 0; tried < maxTries; tried += 1 { - time.Sleep(time.Second) - self.Refresh() - if len(self.vdisks) > oldDiskCnt { - return nil - } - } - return cloudprovider.ErrTimeout -} - -func (self *SVirtualMachine) createDiskInternal(ctx context.Context, config SDiskConfig, check bool) error { - - return self.createDiskWithDeviceChange(ctx, nil, config, check) -} - -func (self *SVirtualMachine) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (self *SVirtualMachine) GetProjectId() string { - pool, err := self.getResourcePool() - if err != nil { - return "" - } - if pool != nil { - return pool.GetId() - } - return "" -} - -func (self *SVirtualMachine) GetError() error { - return nil -} - -func (self *SVirtualMachine) getResourcePool() (*SResourcePool, error) { - vm := self.getVirtualMachine() - morp := mo.ResourcePool{} - if vm.ResourcePool == nil { - return nil, errors.Error("nil resource pool") - } - err := self.manager.reference2Object(*vm.ResourcePool, RESOURCEPOOL_PROPS, &morp) - if err != nil { - return nil, errors.Wrap(err, "self.manager.reference2Object") - } - rp := NewResourcePool(self.manager, &morp, self.datacenter) - return rp, nil -} - -func (self *SVirtualMachine) CheckFileInfo(ctx context.Context) error { - layoutEx := self.getLayoutEx() - if layoutEx != nil && len(layoutEx.File) > 0 { - file := layoutEx.File[0] - host := self.GetIHost() - storages, err := host.GetIStorages() - if err != nil { - return errors.Wrap(err, "host.GetIStorages") - } - for i := range storages { - ds := storages[i].(*SDatastore) - if ds.HasFile(file.Name) { - _, err := ds.CheckFile(ctx, file.Name) - if err != nil { - return errors.Wrap(err, "ds.CheckFile") - } - break - } - } - } - return nil -} - -func (self *SVirtualMachine) DoRename(ctx context.Context, name string) error { - task, err := self.getVmObj().Rename(ctx, name) - if err != nil { - return errors.Wrap(err, "object.VirtualMachine.Rename") - } - return task.Wait(ctx) -} - -func (self *SVirtualMachine) GetMoid() string { - return self.getVirtualMachine().Self.Value -} - -func (self *SVirtualMachine) GetToolsVersion() string { - return self.getVirtualMachine().Guest.ToolsVersion -} - -func (self *SVirtualMachine) DoCustomize(ctx context.Context, params jsonutils.JSONObject) error { - spec := new(types.CustomizationSpec) - - ipSettings := new(types.CustomizationGlobalIPSettings) - domain := "local" - if params.Contains("domain") { - domain, _ = params.GetString("domain") - } - ipSettings.DnsSuffixList = []string{domain} - - // deal nics - nics, _ := params.GetArray("nics") - serverNics := make([]cloudtypes.SServerNic, len(nics)) - for i := range nics { - var nicType cloudtypes.SServerNic - nics[i].Unmarshal(&nicType) - serverNics[i] = nicType - } - - // find dnsServerList - for i := range serverNics { - dnsList := netutils2.GetNicDns(&serverNics[i]) - if len(dnsList) != 0 { - ipSettings.DnsServerList = dnsList - } - } - spec.GlobalIPSettings = *ipSettings - - maps := make([]types.CustomizationAdapterMapping, 0, len(nics)) - for _, nic := range serverNics { - conf := types.CustomizationAdapterMapping{} - conf.MacAddress = nic.Mac - if len(conf.MacAddress) == 0 { - conf.MacAddress = "9e:46:27:21:a2:b2" - } - - conf.Adapter = types.CustomizationIPSettings{} - fixedIp := new(types.CustomizationFixedIp) - fixedIp.IpAddress = nic.Ip - if len(fixedIp.IpAddress) == 0 { - fixedIp.IpAddress = "10.168.26.23" - } - conf.Adapter.Ip = fixedIp - maskLen := nic.Masklen - if maskLen == 0 { - maskLen = 24 - } - mask := netutils2.Netlen2Mask(maskLen) - conf.Adapter.SubnetMask = mask - - if len(nic.Gateway) != 0 { - conf.Adapter.Gateway = []string{nic.Gateway} - } - dnsList := netutils2.GetNicDns(&nic) - if len(dnsList) != 0 { - conf.Adapter.DnsServerList = dnsList - dns := nic.Domain - if len(dns) == 0 { - dns = "local" - } - conf.Adapter.DnsDomain = dns - } - maps = append(maps, conf) - } - spec.NicSettingMap = maps - - var ( - osName string - name = "yunionhost" - ) - if params.Contains("os_name") { - osName, _ = params.GetString("os_name") - } - if params.Contains("name") { - name, _ = params.GetString("name") - } - if osName == "Linux" { - linuxPrep := types.CustomizationLinuxPrep{ - HostName: &types.CustomizationFixedName{Name: name}, - Domain: domain, - TimeZone: "Asia/Shanghai", - } - spec.Identity = &linuxPrep - } else if osName == "Windows" { - sysPrep := types.CustomizationSysprep{ - GuiUnattended: types.CustomizationGuiUnattended{ - TimeZone: 210, - AutoLogon: false, - }, - UserData: types.CustomizationUserData{ - FullName: "Administrator", - OrgName: "Yunion", - ProductId: "", - ComputerName: &types.CustomizationFixedName{ - Name: name, - }, - }, - Identification: types.CustomizationIdentification{}, - } - spec.Identity = &sysPrep - } - log.Infof("customize spec: %#v", spec) - task, err := self.getVmObj().Customize(ctx, *spec) - if err != nil { - return errors.Wrap(err, "object.VirtualMachine.Customize") - } - return task.Wait(ctx) -} - -func (self *SVirtualMachine) ExportTemplate(ctx context.Context, idx int, diskPath string) error { - lease, err := self.getVmObj().Export(ctx) - if err != nil { - return errors.Wrap(err, "esxi.SVirtualMachine.DoExportTemplate") - } - info, err := lease.Wait(ctx, nil) - if err != nil { - return errors.Wrap(err, "lease.Wait") - } - - u := lease.StartUpdater(ctx, info) - defer u.Done() - - if idx >= len(info.Items) { - return errors.Error(fmt.Sprintf("No such Device whose index is %d", idx)) - } - - lr := newLeaseLogger("download vmdk", 5) - lr.Log() - defer lr.End() - - // filter vmdk item - vmdkItems := make([]nfc.FileItem, 0, len(info.Items)/2) - for i := range info.Items { - if strings.HasSuffix(info.Items[i].Path, ".vmdk") { - vmdkItems = append(vmdkItems, info.Items[i]) - } else { - log.Infof("item.Path does not end in '.vmdk': %#v", info.Items[i]) - } - } - - log.Debugf("download to %s start...", diskPath) - err = lease.DownloadFile(ctx, diskPath, vmdkItems[idx], soap.Download{Progress: lr}) - if err != nil { - return errors.Wrap(err, "lease.DownloadFile") - } - - err = lease.Complete(ctx) - if err != nil { - return errors.Wrap(err, "lease.Complete") - } - log.Debugf("download to %s finish", diskPath) - return nil -} - -func (self *SVirtualMachine) GetSerialOutput(port int) (string, error) { - return "", cloudprovider.ErrNotImplemented -} - -func (self *SVirtualMachine) ConvertPublicIpToEip() error { - return cloudprovider.ErrNotSupported -} - -func (self *SVirtualMachine) IsAutoRenew() bool { - return false -} - -func (self *SVirtualMachine) SetAutoRenew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (self *SVirtualMachine) FindMinDiffKey(limit int32) int32 { - if self.devs == nil { - self.fetchHardwareInfo() - } - devKeys := make([]int32, 0, len(self.devs)) - for key := range self.devs { - devKeys = append(devKeys, key) - } - sort.Slice(devKeys, func(i int, j int) bool { - return devKeys[i] < devKeys[j] - }) - for _, key := range devKeys { - switch { - case key < limit: - case key == limit: - limit += 1 - case key > limit: - return limit - } - } - return limit -} - -func (self *SVirtualMachine) relocate(hostId string) error { - var targetHs *mo.HostSystem - if hostId == "" { - return errors.Wrap(fmt.Errorf("require hostId"), "relocate") - } - ihost, err := self.manager.GetIHostById(hostId) - if err != nil { - return errors.Wrap(err, "self.manager.GetIHostById(hostId)") - } - targetHs = ihost.(*SHost).object.(*mo.HostSystem) - if len(targetHs.Datastore) < 1 { - return errors.Wrap(fmt.Errorf("target host has no datastore"), "relocate") - } - ctx := self.manager.context - config := types.VirtualMachineRelocateSpec{} - hrs := targetHs.Reference() - config.Host = &hrs - config.Datastore = &targetHs.Datastore[0] - task, err := self.getVmObj().Relocate(ctx, config, types.VirtualMachineMovePriorityDefaultPriority) - if err != nil { - log.Errorf("vm.Migrate %s", err) - return errors.Wrap(err, "SVirtualMachine Migrate") - } - err = task.Wait(ctx) - if err != nil { - log.Errorf("task.Wait %s", err) - return errors.Wrap(err, "task.wait") - } - return nil -} - -func (self *SVirtualMachine) MigrateVM(hostId string) error { - return self.relocate(hostId) -} - -func (self *SVirtualMachine) LiveMigrateVM(hostId string) error { - return self.relocate(hostId) -} - -func (self *SVirtualMachine) GetIHostId() string { - ctx := self.manager.context - hs, err := self.getVmObj().HostSystem(ctx) - if err != nil { - log.Errorf("get HostSystem %s", err) - return "" - } - var moHost mo.HostSystem - err = self.manager.reference2Object(hs.Reference(), HOST_SYSTEM_PROPS, &moHost) - if err != nil { - log.Errorf("hostsystem reference2Object %s", err) - return "" - } - shost := NewHost(self.manager, &moHost, nil) - return shost.GetGlobalId() -} - -func (self *SVirtualMachine) IsTemplate() bool { - movm := self.getVirtualMachine() - if tempalteNameRegex != nil && tempalteNameRegex.MatchString(self.GetName()) && movm.Summary.Runtime.PowerState == types.VirtualMachinePowerStatePoweredOff { - return true - } - return movm.Config != nil && movm.Config.Template -} - -func (self *SVirtualMachine) fetchSnapshots() { - movm := self.getVirtualMachine() - if movm.Snapshot == nil { - return - } - self.snapshots = self.extractSnapshots(movm.Snapshot.RootSnapshotList, make([]SVirtualMachineSnapshot, 0, len(movm.Snapshot.RootSnapshotList))) -} - -func (self *SVirtualMachine) extractSnapshots(tree []types.VirtualMachineSnapshotTree, snapshots []SVirtualMachineSnapshot) []SVirtualMachineSnapshot { - for i := range tree { - snapshots = append(snapshots, SVirtualMachineSnapshot{ - snapshotTree: tree[i], - vm: self, - }) - snapshots = self.extractSnapshots(tree[i].ChildSnapshotList, snapshots) - } - return snapshots -} - -func (self *SVirtualMachine) GetInstanceSnapshots() ([]cloudprovider.ICloudInstanceSnapshot, error) { - if self.snapshots == nil { - self.fetchSnapshots() - } - ret := make([]cloudprovider.ICloudInstanceSnapshot, 0, len(self.snapshots)) - for i := range self.snapshots { - ret = append(ret, &self.snapshots[i]) - } - return ret, nil -} - -func (self *SVirtualMachine) GetInstanceSnapshot(idStr string) (cloudprovider.ICloudInstanceSnapshot, error) { - if self.snapshots == nil { - self.fetchSnapshots() - } - for i := range self.snapshots { - if self.snapshots[i].GetGlobalId() == idStr { - // copyone - sp := self.snapshots[i] - return &sp, nil - } - } - return nil, errors.ErrNotFound -} - -func (self *SVirtualMachine) CreateInstanceSnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudInstanceSnapshot, error) { - ovm := self.getVmObj() - task, err := ovm.CreateSnapshot(ctx, name, desc, false, false) - if err != nil { - return nil, errors.Wrap(err, "CreateSnapshot") - } - info, err := task.WaitForResult(ctx, nil) - if err != nil { - return nil, errors.Wrap(err, "task.Wait") - } - sp := info.Result.(types.ManagedObjectReference) - err = self.Refresh() - if err != nil { - return nil, errors.Wrap(err, "create successfully") - } - self.fetchSnapshots() - for i := range self.snapshots { - if self.snapshots[i].snapshotTree.Snapshot == sp { - // copyone - sp := self.snapshots[i] - return &sp, nil - } - } - return nil, errors.Wrap(errors.ErrNotFound, "create successfully") -} - -func (self *SVirtualMachine) ResetToInstanceSnapshot(ctx context.Context, idStr string) error { - cloudIsp, err := self.GetInstanceSnapshot(idStr) - if err != nil { - return errors.Wrap(err, "GetInstanceSnapshot") - } - isp := cloudIsp.(*SVirtualMachineSnapshot) - req := types.RevertToSnapshot_Task{ - This: isp.snapshotTree.Snapshot.Reference(), - } - res, err := methods.RevertToSnapshot_Task(ctx, self.manager.client.Client, &req) - if err != nil { - return errors.Wrap(err, "RevertToSnapshot_Task") - } - return object.NewTask(self.manager.client.Client, res.Returnval).Wait(ctx) -} diff --git a/pkg/multicloud/google/bucket.go b/pkg/multicloud/google/bucket.go deleted file mode 100644 index 5063db297f..0000000000 --- a/pkg/multicloud/google/bucket.go +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "context" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "strings" - "time" - - "cloud.google.com/go/storage" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLifecycleRuleAction struct { - Type string -} - -type SLifecycleRuleCondition struct { - Age int -} - -type SLifecycleRule struct { - Action SLifecycleRuleAction - Condition SLifecycleRuleCondition -} - -type SBucketPolicyOnly struct { - Enabled bool -} - -type SUniformBucketLevelAccess struct { - Enabled bool -} - -type SIamConfiguration struct { - BucketPolicyOnly SBucketPolicyOnly - UniformBucketLevelAccess SUniformBucketLevelAccess -} - -type SLifecycle struct { - Rule []SLifecycleRule -} - -type SBucket struct { - multicloud.SBaseBucket - multicloud.GoogleTags - - region *SRegion - - Kind string - SelfLink string - Name string - ProjectNumber string - Metageneration string - Location string - StorageClass string - Etag string - TimeCreated time.Time - Updated time.Time - Lifecycle SLifecycle - IamConfiguration SIamConfiguration - LocationType string -} - -func (b *SBucket) GetProjectId() string { - return b.region.GetProjectId() -} - -func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { - iam, err := b.region.GetBucketIam(b.Name) - if err != nil { - return cloudprovider.ACLUnknown - } - acl := cloudprovider.ACLPrivate - allUsers := []SBucketBinding{} - allAuthUsers := []SBucketBinding{} - for _, binding := range iam.Bindings { - if utils.IsInStringArray("allUsers", binding.Members) { - allUsers = append(allUsers, binding) - } - if utils.IsInStringArray("allAuthenticatedUsers", binding.Members) { - allAuthUsers = append(allAuthUsers, binding) - } - } - - for _, binding := range allUsers { - switch binding.Role { - case "roles/storage.admin", "roles/storage.objectAdmin": - acl = cloudprovider.ACLPublicReadWrite - case "roles/storage.objectViewer": - if acl != cloudprovider.ACLPublicReadWrite { - acl = cloudprovider.ACLPublicRead - } - } - } - - for _, binding := range allAuthUsers { - switch binding.Role { - case "roles/storage.admin", "roles/storage.objectAdmin", "roles/storage.objectViewer": - acl = cloudprovider.ACLAuthRead - } - } - return acl -} - -func (region *SRegion) SetBucketAcl(bucket string, acl cloudprovider.TBucketACLType) error { - iam, err := region.GetBucketIam(bucket) - if err != nil { - return errors.Wrap(err, "GetBucketIam") - } - bindings := []SBucketBinding{} - for _, binding := range iam.Bindings { - if !utils.IsInStringArray(string(storage.AllUsers), binding.Members) && !utils.IsInStringArray(string(storage.AllAuthenticatedUsers), binding.Members) { - bindings = append(bindings, binding) - } - } - switch acl { - case cloudprovider.ACLPrivate: - if len(bindings) == len(iam.Bindings) { - return nil - } - case cloudprovider.ACLAuthRead: - bindings = append(bindings, SBucketBinding{ - Role: "roles/storage.objectViewer", - Members: []string{"allAuthenticatedUsers"}, - }) - case cloudprovider.ACLPublicRead: - bindings = append(bindings, SBucketBinding{ - Role: "roles/storage.objectViewer", - Members: []string{"allUsers"}, - }) - case cloudprovider.ACLPublicReadWrite: - bindings = append(bindings, SBucketBinding{ - Role: "roles/storage.objectAdmin", - Members: []string{"allUsers"}, - }) - default: - return fmt.Errorf("unknown acl %s", acl) - } - iam.Bindings = bindings - _, err = region.SetBucketIam(bucket, iam) - if err != nil { - return errors.Wrap(err, "SetBucketIam") - } - return nil - -} - -func (b *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error { - return b.region.SetBucketAcl(b.Name, acl) -} - -func (b *SBucket) GetGlobalId() string { - return b.Name -} - -func (b *SBucket) GetName() string { - return b.Name -} - -func (b *SBucket) GetLocation() string { - return strings.ToLower(b.Location) -} - -func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { - return b.region -} - -func (b *SBucket) GetCreatedAt() time.Time { - return b.TimeCreated -} - -func (b *SBucket) GetStorageClass() string { - return b.StorageClass -} - -func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { - return []cloudprovider.SBucketAccessUrl{ - { - Url: fmt.Sprintf("https://www.googleapis.com/storage/v1/b/%s", b.Name), - Description: "bucket domain", - Primary: true, - }, - { - Url: fmt.Sprintf("https://www.googleapis.com/upload/storage/v1/b/%s/o", b.Name), - Description: "object upload endpoint", - }, - { - Url: fmt.Sprintf("https://www.googleapis.com/batch/storage/v1/b/%s", b.Name), - Description: "batch operation", - }, - } -} - -func (b *SBucket) GetStats() cloudprovider.SBucketStats { - stats, _ := cloudprovider.GetIBucketStats(b) - return stats -} - -func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { - resource := fmt.Sprintf("b/%s/o?uploadType=resumable&upload_id=%s", b.Name, uploadId) - return b.region.client.storageAbortUpload(resource) -} - -func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { - resource := fmt.Sprintf("b/%s/o/%s", b.Name, url.PathEscape(key)) - err := b.region.StorageGet(resource, nil) - if err != nil { - return errors.Wrapf(err, "failed to get object %s", key) - } - return nil -} - -func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - resource := fmt.Sprintf("b/%s/o/%s", srcBucket, url.PathEscape(srcKey)) - action := fmt.Sprintf("copyTo/b/%s/o/%s", b.Name, url.PathEscape(destKey)) - err := b.region.StorageDo(resource, action, nil, nil) - if err != nil { - return errors.Wrap(err, "CopyObject") - } - err = b.region.SetObjectAcl(b.Name, destKey, cannedAcl) - if err != nil { - return errors.Wrapf(err, "AddObjectAcl(%s)", cannedAcl) - } - err = b.region.SetObjectMeta(b.Name, destKey, meta) - if err != nil { - return errors.Wrap(err, "SetObjectMeta") - } - return nil -} - -func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partNumber int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (region *SRegion) DeleteObject(bucket, key string) error { - resource := fmt.Sprintf("b/%s/o/%s", bucket, url.PathEscape(key)) - return region.StorageDelete(resource) -} - -func (b *SBucket) DeleteObject(ctx context.Context, key string) error { - return b.region.DeleteObject(b.Name, key) -} - -func (region *SRegion) DownloadObjectRange(bucket, object string, start, end int64) (io.ReadCloser, error) { - resource := fmt.Sprintf("b/%s/o/%s?alt=media", bucket, url.PathEscape(object)) - header := http.Header{} - if start <= 0 { - if end > 0 { - header.Set("Range", fmt.Sprintf("bytes=0-%d", end)) - } else { - header.Set("Range", "bytes=-1") - } - } else { - if end > start { - header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end)) - } else { - header.Set("Range", fmt.Sprintf("bytes=%d-", start)) - } - } - return region.client.storageDownload(resource, header) -} - -func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { - return b.region.DownloadObjectRange(b.Name, key, rangeOpt.Start, rangeOpt.End) -} - -func (region *SRegion) SingedUrl(bucket, key string, method string, expire time.Duration) (string, error) { - if expire > time.Hour*24*7 { - return "", fmt.Errorf(`Expiration Time can\'t be longer than 604800 seconds (7 days)`) - } - opts := &storage.SignedURLOptions{ - Scheme: storage.SigningSchemeV4, - Method: method, - GoogleAccessID: region.client.clientEmail, - PrivateKey: []byte(region.client.privateKey), - Expires: time.Now().Add(expire), - } - switch method { - case "GET": - case "PUT": - opts.Headers = []string{"Content-Type:application/octet-stream"} - default: - return "", errors.Wrapf(cloudprovider.ErrNotSupported, "Not support method %s", method) - } - return storage.SignedURL(bucket, key, opts) - -} - -func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { - return b.region.SingedUrl(b.Name, key, method, expire) -} - -func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { - result := cloudprovider.SListObjectResult{} - objs, err := b.region.GetObjects(b.Name, prefix, marker, delimiter, maxCount) - if err != nil { - return result, errors.Wrap(err, "GetObjects") - } - result.NextMarker = objs.NextPageToken - log.Errorf("obj count: %d", len(objs.Items)) - result.Objects = []cloudprovider.ICloudObject{} - result.CommonPrefixes = []cloudprovider.ICloudObject{} - for i := range objs.Items { - if strings.HasSuffix(objs.Items[i].Name, "/") { - continue - } - objs.Items[i].bucket = b - result.Objects = append(result.Objects, &objs.Items[i]) - } - for i := range objs.Prefixes { - obj := &SObject{ - bucket: b, - Name: objs.Prefixes[i], - } - result.CommonPrefixes = append(result.CommonPrefixes, obj) - } - return result, nil -} - -func (region *SRegion) NewMultipartUpload(bucket, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - body := map[string]string{"name": key} - if len(storageClassStr) > 0 { - body["storageClass"] = storageClassStr - } - for k := range meta { - switch k { - case cloudprovider.META_HEADER_CONTENT_TYPE: - body["contentType"] = meta.Get(k) - case cloudprovider.META_HEADER_CONTENT_ENCODING: - body["contentEncoding"] = meta.Get(k) - case cloudprovider.META_HEADER_CONTENT_DISPOSITION: - body["contentDisposition"] = meta.Get(k) - case cloudprovider.META_HEADER_CONTENT_LANGUAGE: - body["contentLanguage"] = meta.Get(k) - case cloudprovider.META_HEADER_CACHE_CONTROL: - body["cacheControl"] = meta.Get(k) - default: - body[fmt.Sprintf("metadata.%s", k)] = meta.Get(k) - } - } - switch cannedAcl { - case cloudprovider.ACLPrivate: - case cloudprovider.ACLAuthRead: - body["predefinedAcl"] = "authenticatedRead" - case cloudprovider.ACLPublicRead: - body["predefinedAcl"] = "publicRead" - case cloudprovider.ACLPublicReadWrite: - return "", cloudprovider.ErrNotSupported - } - resource := fmt.Sprintf("b/%s/o?uploadType=resumable", bucket) - input := strings.NewReader(jsonutils.Marshal(body).String()) - header := http.Header{} - header.Set("Content-Type", "application/json; charset=UTF-8") - header.Set("Content-Length", fmt.Sprintf("%d", input.Len())) - resp, err := region.client.storageUpload(resource, header, input) - if err != nil { - return "", errors.Wrap(err, "storageUpload") - } - defer resp.Body.Close() - location := resp.Header.Get("Location") - query, err := url.ParseQuery(location) - if err != nil { - return "", errors.Wrapf(err, "url.ParseQuery(%s)", location) - } - return query.Get("upload_id"), nil -} - -func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - return b.region.NewMultipartUpload(b.Name, key, cannedAcl, storageClassStr, meta) -} - -func (region *SRegion) UploadPart(bucket, uploadId string, partIndex int, offset int64, part io.Reader, partSize int64, totalSize int64) error { - resource := fmt.Sprintf("b/%s/o?uploadType=resumable&upload_id=%s", bucket, uploadId) - header := http.Header{} - header.Set("Content-Length", fmt.Sprintf("%d", partSize)) - header.Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", offset, offset+partSize-1, totalSize)) - resp, err := region.client.storageUploadPart(resource, header, part) - if err != nil { - return errors.Wrap(err, "storageUploadPart") - } - if resp.StatusCode >= 500 { - content, _ := ioutil.ReadAll(resp.Body) - return fmt.Errorf("status code: %d %s", resp.StatusCode, content) - } - defer resp.Body.Close() - return nil -} - -func (region *SRegion) CheckUploadRange(bucket string, uploadId string) error { - resource := fmt.Sprintf("b/%s/o?uploadType=resumable&upload_id=%s", bucket, uploadId) - header := http.Header{} - header.Set("Content-Range", "bytes */*") - resp, err := region.client.storageUploadPart(resource, header, nil) - if err != nil { - return errors.Wrap(err, "storageUploadPart") - } - defer resp.Body.Close() - - content, err := ioutil.ReadAll(resp.Body) - if err != nil { - return errors.Wrap(err, "ReadAll") - } - fmt.Println("content: ", string(content)) - for k, v := range resp.Header { - fmt.Println("k: ", k, "v: ", v) - } - fmt.Println("status code: ", resp.StatusCode) - return nil -} - -func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, part io.Reader, partSize int64, offset, totalSize int64) (string, error) { - return "", b.region.UploadPart(b.Name, uploadId, partIndex, offset, part, partSize, totalSize) -} - -func (b *SBucket) PutObject(ctx context.Context, key string, body io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - return b.region.PutObject(b.Name, key, body, sizeBytes, cannedAcl, meta) -} - -func (region *SRegion) GetBucket(name string) (*SBucket, error) { - resource := "b/" + name - bucket := &SBucket{} - err := region.StorageGet(resource, bucket) - if err != nil { - return nil, errors.Wrap(err, "GetBucket") - } - return bucket, nil -} - -func (region *SRegion) GetBuckets(maxResults int, pageToken string) ([]SBucket, error) { - buckets := []SBucket{} - params := map[string]string{ - "project": region.GetProjectId(), - } - err := region.StorageList("b", params, maxResults, pageToken, &buckets) - if err != nil { - return nil, err - } - return buckets, nil -} - -func (region *SRegion) CreateBucket(name string, storageClass string, acl cloudprovider.TBucketACLType) (*SBucket, error) { - body := map[string]interface{}{ - "name": name, - "location": region.Name, - } - if len(storageClass) > 0 { - body["storageClass"] = storageClass - } - params := url.Values{} - params.Set("predefinedDefaultObjectAcl", "private") - switch acl { - case cloudprovider.ACLPrivate, cloudprovider.ACLUnknown: - params.Set("predefinedAcl", "private") - case cloudprovider.ACLAuthRead: - params.Set("predefinedAcl", "authenticatedRead") - case cloudprovider.ACLPublicRead: - params.Set("predefinedAcl", "publicRead") - case cloudprovider.ACLPublicReadWrite: - params.Set("predefinedAcl", "publicReadWrite") - } - params.Set("project", region.GetProjectId()) - bucket := &SBucket{} - resource := fmt.Sprintf("b?%s", params.Encode()) - err := region.StorageInsert(resource, jsonutils.Marshal(body), bucket) - if err != nil { - return nil, err - } - return bucket, nil -} - -func (region *SRegion) UploadObject(bucket string, params url.Values, header http.Header, input io.Reader) error { - resource := fmt.Sprintf("b/%s/o", bucket) - if len(params) > 0 { - resource = fmt.Sprintf("%s?%s", resource, params.Encode()) - } - resp, err := region.client.storageUpload(resource, header, input) - if err != nil { - return errors.Wrap(err, "storageUpload") - } - defer resp.Body.Close() - return nil -} - -func (region *SRegion) PutObject(bucket string, name string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, meta http.Header) error { - params := url.Values{} - params.Set("name", name) - params.Set("uploadType", "media") - header := http.Header{} - header.Set("Content-Length", fmt.Sprintf("%v", sizeBytes)) - err := region.UploadObject(bucket, params, header, input) - if err != nil { - return errors.Wrap(err, "UploadObject") - } - err = region.SetObjectAcl(bucket, name, cannedAcl) - if err != nil { - return errors.Wrap(err, "SetObjectAcl") - } - return region.SetObjectMeta(bucket, name, meta) -} - -func (region *SRegion) DeleteBucket(name string) error { - return region.StorageDelete("b/" + name) -} diff --git a/pkg/multicloud/google/dbinstance.go b/pkg/multicloud/google/dbinstance.go deleted file mode 100644 index 393cc907fa..0000000000 --- a/pkg/multicloud/google/dbinstance.go +++ /dev/null @@ -1,636 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -var ( - EngineVersions = map[string]GoogleSQLVersion{ - "MYSQL_5_5": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.5"}, - "MYSQL_5_6": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.6"}, - "MYSQL_5_7": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.7"}, - "POSTGRES_9_6": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "9.6"}, - "POSTGRES_10": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "10"}, - "POSTGRES_11": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "11"}, - "POSTGRES_12": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "12"}, - "SQLSERVER_2017_STANDARD": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Standard"}, - "SQLSERVER_2017_ENTERPRISE": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Enterprise"}, - "SQLSERVER_2017_EXPRESS": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Express"}, - "SQLSERVER_2017_WEB": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Web"}, - } - InstanceTypes = map[string]GoogleSQLType{ - "db-f1-micro": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 614}, - "db-g1-small": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 1740}, - "D0": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 512}, - "D1": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 1024}, - "D2": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 2048}, - "D4": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 5120}, - "D8": GoogleSQLType{VcpuCount: 2, VmemSizeMb: 10240}, - "D16": GoogleSQLType{VcpuCount: 4, VmemSizeMb: 10240}, - "D32": GoogleSQLType{VcpuCount: 8, VmemSizeMb: 10240}, - } -) - -type GoogleSQLType struct { - VcpuCount int - VmemSizeMb int -} - -type GoogleSQLVersion struct { - Engine string - Version string -} - -type SDBInstanceLocationPreference struct { - Zone string - Kind string -} - -type SDBInstanceMaintenanceWindow struct { - Kind string - Hour int - Day int -} - -type SDBInstanceBackupConfiguration struct { - StartTime string - Kind string - Enabled bool - BinaryLogEnabled bool -} - -type SAuthorizedNetwork struct { - Value string - Kind string - Name string -} - -type SDBInstanceSettingIpConfiguration struct { - PrivateNetwork string - AuthorizedNetworks []SAuthorizedNetwork - Ipv4Enabled bool -} - -type SDBInstanceSetting struct { - AuthorizedGaeApplications []string - Tier string - Kind string - AvailabilityType string - PricingPlan string - ReplicationType string - ActivationPolicy string - IpConfiguration SDBInstanceSettingIpConfiguration - LocationPreference SDBInstanceLocationPreference - DataDiskType string - MaintenanceWindow SDBInstanceMaintenanceWindow - BackupConfiguration SDBInstanceBackupConfiguration - SettingsVersion string - StorageAutoResizeLimit string - StorageAutoResize bool - DataDiskSizeGb int - DatabaseFlags []SDBInstanceParameter - UserLabels map[string]string -} - -type SDBInstanceIpAddress struct { - Type string - IpAddress string -} - -type SDBInstanceCaCert struct { - Kind string - CertSerialNumber string - Cert string - CommonName string - Sha1Fingerprint string - Instance string - CreateTime time.Time - ExpirationTime time.Time -} - -type SDBInstance struct { - multicloud.SDBInstanceBase - region *SRegion - - Kind string - State string - DatabaseVersion string - Settings SDBInstanceSetting - Etag string - MasterInstanceName string - IpAddresses []SDBInstanceIpAddress - ServerCaCert SDBInstanceCaCert - InstanceType string - Project string - ServiceAccountEmailAddress string - BackendType string - SelfLink string - ConnectionName string - Name string - Region string - GceZone string -} - -func (region *SRegion) GetDBInstances(maxResults int, pageToken string) ([]SDBInstance, error) { - instances := []SDBInstance{} - params := map[string]string{"filter": "region=" + region.Name} - err := region.RdsList("instances", params, maxResults, pageToken, &instances) - if err != nil { - return nil, errors.Wrap(err, "RdsList") - } - return instances, nil -} - -func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { - instance := SDBInstance{region: region} - err := region.rdsGet(instanceId, &instance) - if err != nil { - return nil, errors.Wrap(err, "RdsGet") - } - return &instance, nil -} - -func (rds *SDBInstance) GetName() string { - return rds.Name -} - -func (rds *SDBInstance) GetId() string { - return rds.SelfLink -} - -func (rds *SDBInstance) GetGlobalId() string { - return strings.TrimPrefix(rds.SelfLink, fmt.Sprintf("%s/%s/", GOOGLE_DBINSTANCE_DOMAIN, GOOGLE_DBINSTANCE_API_VERSION)) -} - -func (rds *SDBInstance) GetProjectId() string { - return rds.region.GetProjectId() -} - -func (rds *SDBInstance) IsEmulated() bool { - return false -} - -func (rds *SDBInstance) GetStatus() string { - switch rds.State { - case "RUNNABLE": - return api.DBINSTANCE_RUNNING - case "PENDING_CREATE": - return api.DBINSTANCE_DEPLOYING - case "MAINTENANCE": - return api.DBINSTANCE_MAINTENANCE - case "FAILED": - return api.DBINSTANCE_CREATE_FAILED - case "UNKNOWN_STATE", "SUSPENDED": - return api.DBINSTANCE_UNKNOWN - } - return rds.State -} - -func (rds *SDBInstance) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (rds *SDBInstance) GetCreatedAt() time.Time { - return rds.ServerCaCert.CreateTime -} - -func (rds *SDBInstance) GetExpiredAt() time.Time { - return time.Time{} -} - -func (rds *SDBInstance) GetMasterInstanceId() string { - if len(rds.MasterInstanceName) > 0 { - if master := strings.Split(rds.MasterInstanceName, ":"); len(master) == 2 { - return fmt.Sprintf("projects/%s/instances/%s", master[0], master[1]) - } - } - return "" -} - -func (rds *SDBInstance) GetSecurityGroupId() string { - return "" -} - -func (rds *SDBInstance) Refresh() error { - instance, err := rds.region.GetDBInstance(rds.SelfLink) - if err != nil { - return errors.Wrapf(err, "GetDBInstance(%s)", rds.SelfLink) - } - return jsonutils.Update(rds, instance) -} - -func (rds *SDBInstance) GetPort() int { - switch rds.GetEngine() { - case api.DBINSTANCE_TYPE_MYSQL: - return 3306 - case api.DBINSTANCE_TYPE_POSTGRESQL: - return 5432 - case api.DBINSTANCE_TYPE_SQLSERVER: - return 1433 - default: - return 0 - } -} - -func (rds *SDBInstance) GetEngine() string { - if e, ok := EngineVersions[rds.DatabaseVersion]; ok { - return e.Engine - } - return rds.DatabaseVersion -} - -func (rds *SDBInstance) GetEngineVersion() string { - if e, ok := EngineVersions[rds.DatabaseVersion]; ok { - return e.Version - } - return rds.DatabaseVersion -} - -func (rds *SDBInstance) GetInstanceType() string { - return rds.Settings.Tier -} - -func (rds *SDBInstance) GetVcpuCount() int { - if t, ok := InstanceTypes[rds.Settings.Tier]; ok { - return t.VcpuCount - } - numStr := "" - if strings.HasPrefix(rds.Settings.Tier, "db-n1-standard-") { - numStr = strings.TrimPrefix(rds.Settings.Tier, "db-n1-standard-") - } else if strings.HasPrefix(rds.Settings.Tier, "db-n1-highmem-") { - numStr = strings.TrimPrefix(rds.Settings.Tier, "db-n1-highmem-") - } else { - numStr = strings.TrimPrefix(rds.Settings.Tier, "db-custom-") - numStr = strings.Split(numStr, "-")[0] - } - cpu, _ := strconv.ParseInt(numStr, 10, 32) - return int(cpu) -} - -func (rds *SDBInstance) GetVmemSizeMB() int { - if t, ok := InstanceTypes[rds.Settings.Tier]; ok { - return t.VmemSizeMb - } - if strings.HasPrefix(rds.Settings.Tier, "db-custom-") { - info := strings.Split(rds.Settings.Tier, "-") - numStr := info[len(info)-1] - mem, _ := strconv.ParseInt(numStr, 10, 32) - return int(mem) - } else if strings.HasPrefix(rds.Settings.Tier, "db-n1-standard-") { - return rds.GetVcpuCount() * 3840 - } else if strings.HasPrefix(rds.Settings.Tier, "db-n1-highmem-") { - return rds.GetVcpuCount() * 3840 * 2 - } - return 0 -} - -func (rds *SDBInstance) GetDiskSizeGB() int { - return rds.Settings.DataDiskSizeGb -} - -func (rds *SDBInstance) GetCategory() string { - switch rds.Settings.AvailabilityType { - case "REGIONAL": - return api.GOOGLE_DBINSTANCE_CATEGORY_REGIONAL - default: - return api.GOOGLE_DBINSTANCE_CATEGORY_ZONAL - } -} - -func (rds *SDBInstance) GetStorageType() string { - return rds.Settings.DataDiskType -} - -func (rds *SDBInstance) GetMaintainTime() string { - startTime := (rds.Settings.MaintenanceWindow.Hour + 8) % 24 - startDay := (rds.Settings.MaintenanceWindow.Day + 1) % 7 - return fmt.Sprintf("%s %02d:00 - %02d:00", time.Weekday(startDay).String(), startTime, startTime+1) -} - -func (rds *SDBInstance) GetConnectionStr() string { - for _, ip := range rds.IpAddresses { - if ip.Type == "PRIMARY" { - return ip.IpAddress - } - } - return "" -} - -func (rds *SDBInstance) GetInternalConnectionStr() string { - ret := []string{rds.ConnectionName} - for _, ip := range rds.IpAddresses { - if ip.Type == "PRIVATE" { - ret = append(ret, ip.IpAddress) - } - } - return strings.Join(ret, ",") -} - -func (rds *SDBInstance) GetZone1Id() string { - zones, err := rds.region.GetIZones() - if err != nil { - log.Errorf("failed to found rds %s zone %s", rds.Name, rds.GceZone) - return "" - } - for _, zone := range zones { - if zone.GetId() == rds.GceZone { - return zone.GetGlobalId() - } - } - return "" -} - -func (rds *SDBInstance) GetZone2Id() string { - return "" -} - -func (rds *SDBInstance) GetZone3Id() string { - return "" -} - -func (rds *SDBInstance) GetIVpcId() string { - return "" -} - -func (rds *SDBInstance) GetDBNetwork() (*cloudprovider.SDBInstanceNetwork, error) { - return nil, nil -} - -func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { - ret := []cloudprovider.ICloudDBInstanceParameter{} - for i := range rds.Settings.DatabaseFlags { - rds.Settings.DatabaseFlags[i].rds = rds - ret = append(ret, &rds.Settings.DatabaseFlags[i]) - } - return ret, nil -} - -func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { - databases, err := rds.region.GetDBInstanceDatabases(rds.Name) - if err != nil { - return nil, errors.Wrap(err, "GetDBInstanceDatabases") - } - ret := []cloudprovider.ICloudDBInstanceDatabase{} - for i := range databases { - databases[i].rds = rds - ret = append(ret, &databases[i]) - } - return ret, nil -} - -func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { - accounts, err := rds.region.GetDBInstanceAccounts(rds.Name) - if err != nil { - return nil, errors.Wrap(err, "GetDBInstanceAccounts") - } - ret := []cloudprovider.ICloudDBInstanceAccount{} - for i := range accounts { - accounts[i].rds = rds - ret = append(ret, &accounts[i]) - } - return ret, nil -} - -func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - backups, err := rds.region.GetDBInstanceBackups(rds.Name) - if err != nil { - return nil, errors.Wrap(err, "GetDBInstanceBackups") - } - ret := []cloudprovider.ICloudDBInstanceBackup{} - for i := range backups { - backups[i].rds = rds - ret = append(ret, &backups[i]) - } - return ret, nil -} - -func (region *SRegion) ChangeDBInstanceConfig(instanceId string, diskSizeGb int, instanceType string) error { - rds, err := region.GetDBInstance(instanceId) - if err != nil { - return errors.Wrapf(err, "GetDBInstance(%s)", instanceId) - } - body := map[string]interface{}{} - settings := map[string]interface{}{} - if len(instanceType) > 0 && instanceType != rds.GetInstanceType() { - settings["tier"] = instanceType - } - if diskSizeGb > 0 && diskSizeGb != rds.GetDiskSizeGB() { - settings["dataDiskSizeGb"] = diskSizeGb - } - if len(settings) == 0 { - return nil - } - body["settings"] = settings - return region.rdsPatch(rds.SelfLink, jsonutils.Marshal(body)) -} - -func (rds *SDBInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedDBInstanceChangeConfig) error { - return rds.region.ChangeDBInstanceConfig(rds.SelfLink, config.DiskSizeGB, config.InstanceType) -} - -func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (region *SRegion) DBInstancePublicConnectionOperation(instanceId string, open bool) error { - ipConfiguration := map[string]interface{}{ - "ipv4Enabled": open, - } - if open { - ipConfiguration["authorizedNetworks"] = []map[string]string{ - map[string]string{ - "name": "White list", - "value": "0.0.0.0/0", - }, - } - } - body := map[string]interface{}{ - "settings": map[string]interface{}{ - "ipConfiguration": ipConfiguration, - }, - } - return region.rdsPatch(instanceId, jsonutils.Marshal(body)) -} - -func (rds *SDBInstance) OpenPublicConnection() error { - return rds.region.DBInstancePublicConnectionOperation(rds.SelfLink, true) -} - -func (rds *SDBInstance) ClosePublicConnection() error { - return rds.region.DBInstancePublicConnectionOperation(rds.SelfLink, false) -} - -func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { - return rds.region.CreateDatabase(rds.SelfLink, conf.Name, conf.CharacterSet) -} - -func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { - return rds.region.CreateDBInstanceAccount(rds.SelfLink, conf.Name, conf.Password, "%") -} - -func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { - err := rds.region.CreateDBInstanceBackup(rds.SelfLink, conf.Name, conf.Description) - if err != nil { - return "", errors.Wrap(err, "CreateIBackup") - } - return "", nil -} - -func (region *SRegion) RecoverFromBackup(instanceName, dest string, backupId string) error { - backup, err := region.GetDBInstanceBackup(backupId) - if err != nil { - return errors.Wrap(err, "GetDBInstanceBackup") - } - body := map[string]interface{}{ - "restoreBackupContext": map[string]string{ - "backupRunId": backup.Id, - "instanceId": instanceName, - "project": region.client.projectId, - }, - } - return region.rdsDo(dest, "restoreBackup", nil, jsonutils.Marshal(body)) -} - -func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { - instanceName := rds.Name - if len(conf.OriginDBInstanceExternalId) > 0 { - instance, err := rds.region.GetDBInstance(conf.OriginDBInstanceExternalId) - if err != nil { - return errors.Wrapf(err, "GetInstance(%s)", conf.OriginDBInstanceExternalId) - } - instanceName = instance.Name - } - return rds.region.RecoverFromBackup(instanceName, rds.SelfLink, conf.BackupId) -} - -func (rds *SDBInstance) Reboot() error { - return rds.region.rdsDo(rds.SelfLink, "restart", nil, nil) -} - -func (rds *SDBInstance) Delete() error { - return rds.region.DeleteDBInstance(rds.SelfLink) -} - -func (region *SRegion) DeleteDBInstance(id string) error { - return region.rdsDelete(id) -} - -func (region *SRegion) CreateRds(name, engine, databaseVersion, category, instanceType, storageType string, diskSizeGb int, vpcId, zoneId, password string) (*SDBInstance, error) { - settings := map[string]interface{}{ - "tier": instanceType, - "storageAutoResize": true, - "dataDiskType": storageType, - "dataDiskSizeGb": diskSizeGb, - } - if utils.IsInStringArray(category, []string{api.GOOGLE_DBINSTANCE_CATEGORY_REGIONAL, api.GOOGLE_DBINSTANCE_CATEGORY_ZONAL}) { - settings["availabilityType"] = strings.ToUpper(category) - backupConfiguration := map[string]interface{}{ - "enabled": true, - "startTime": "19:00", - } - if engine == api.DBINSTANCE_TYPE_MYSQL { - backupConfiguration["binaryLogEnabled"] = true - } - settings["backupConfiguration"] = backupConfiguration - } - ipConfiguration := map[string]interface{}{ - "ipv4Enabled": true, - } - ipConfiguration["authorizedNetworks"] = []map[string]string{ - map[string]string{ - "name": "White list", - "value": "0.0.0.0/0", - }, - } - settings["ipConfiguration"] = ipConfiguration - body := map[string]interface{}{ - "databaseVersion": databaseVersion, - "name": name, - "region": region.Name, - "settings": settings, - "backendType": "SECOND_GEN", - "instanceType": "CLOUD_SQL_INSTANCE", - } - if len(zoneId) > 0 { - settings["locationPreference"] = map[string]string{ - "zone": zoneId, - } - } - if len(password) > 0 { - body["rootPassword"] = password - } - rds := SDBInstance{region: region} - err := region.rdsInsert("instances", jsonutils.Marshal(body), &rds) - if err != nil { - if e, ok := errors.Cause(err).(*gError); ok && e.ErrorInfo.Code == 409 { //The instance or operation is not in an appropriate state to handle the request - return nil, fmt.Errorf("the name %s is unavailable because it was used recently", name) - } - return nil, errors.Wrap(err, "rdsInsert") - } - return &rds, nil -} - -func (region *SRegion) CreateDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (*SDBInstance, error) { - desc.EngineVersion = strings.ToUpper(desc.EngineVersion) - desc.EngineVersion = strings.Replace(desc.EngineVersion, ".", "_", -1) - desc.EngineVersion = strings.Replace(desc.EngineVersion, " ", "_", -1) - if desc.Engine == api.DBINSTANCE_TYPE_POSTGRESQL { - desc.Engine = "POSTGRES" - } - databaseVersion := fmt.Sprintf("%s_%s", strings.ToUpper(desc.Engine), desc.EngineVersion) - if _, ok := EngineVersions[databaseVersion]; !ok { - return nil, fmt.Errorf("Unsupport %s version %s", desc.Engine, desc.EngineVersion) - } - rds, err := region.CreateRds(desc.Name, desc.Engine, databaseVersion, desc.Category, desc.InstanceType, desc.StorageType, desc.DiskSizeGB, desc.VpcId, desc.ZoneId, desc.Password) - if err != nil { - return nil, errors.Wrapf(err, "CreateRds") - } - return rds, nil -} - -func (self *SDBInstance) GetTags() (map[string]string, error) { - return self.Settings.UserLabels, nil -} - -func (self *SDBInstance) GetSysTags() map[string]string { - return nil -} - -func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error { - params := map[string]interface{}{ - "settings": map[string]interface{}{ - "userLabels": tags, - }, - } - err := self.region.rdsPatch(self.GetId(), jsonutils.Marshal(params)) - return errors.Wrapf(err, "rdsPatch") -} diff --git a/pkg/multicloud/google/dbinstance_account.go b/pkg/multicloud/google/dbinstance_account.go deleted file mode 100644 index 1337ca7583..0000000000 --- a/pkg/multicloud/google/dbinstance_account.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSqlserverUserDetails struct { - ServerRoles []string -} - -type SDBInstanceAccount struct { - multicloud.SDBInstanceAccountBase - multicloud.GoogleTags - rds *SDBInstance - - Kind string - Etag string - Name string - Host string - Instance string - SelfLink string - Project string - SqlserverUserDetails SSqlserverUserDetails -} - -func (region *SRegion) GetDBInstanceAccounts(instance string) ([]SDBInstanceAccount, error) { - accounts := []SDBInstanceAccount{} - params := map[string]string{} - resource := fmt.Sprintf("instances/%s/users", instance) - err := region.RdsListAll(resource, params, &accounts) - if err != nil { - return nil, errors.Wrap(err, "RdsListAll") - } - return accounts, nil -} - -func (region *SRegion) GetDBInstanceAccount(id string) (*SDBInstanceAccount, error) { - account := &SDBInstanceAccount{} - err := region.rdsGet(id, account) - if err != nil { - return nil, errors.Wrap(err, "rdsGet") - } - return account, nil -} - -func (region *SRegion) DeleteDBInstanceAccount(instanceName, user, host string) error { - resource := fmt.Sprintf("projects/%s/instances/%s/users?name=%s&host=%s", region.GetProjectId(), instanceName, url.PathEscape(user), url.PathEscape(host)) - return region.rdsDelete(resource) -} - -func (account *SDBInstanceAccount) Delete() error { - return account.rds.region.DeleteDBInstanceAccount(account.rds.Name, account.Name, account.Host) -} - -func (account *SDBInstanceAccount) GetHost() string { - return account.Host -} - -func (account *SDBInstanceAccount) GetName() string { - return account.Name -} - -func (account *SDBInstanceAccount) Refresh() error { - _account, err := account.rds.region.GetDBInstanceAccount(account.SelfLink) - if err != nil { - return errors.Wrap(err, "GetDBInstanceAccount") - } - return jsonutils.Update(account, _account) -} - -func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { - return []cloudprovider.ICloudDBInstanceAccountPrivilege{}, nil -} - -func (account *SDBInstanceAccount) ResetPassword(password string) error { - params := map[string]string{ - "host": account.Host, - "name": account.Name, - } - resource := fmt.Sprintf("instances/%s/users", account.rds.Name) - body := map[string]string{ - "password": password, - } - return account.rds.region.rdsUpdate(resource, params, jsonutils.Marshal(body)) -} - -func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { - return cloudprovider.ErrNotSupported -} - -func (account *SDBInstanceAccount) RevokePrivilege(database string) error { - return cloudprovider.ErrNotSupported -} - -func (region *SRegion) CreateDBInstanceAccount(instanceId string, name, password, host string) error { - body := map[string]interface{}{ - "name": name, - "password": password, - } - if len(host) > 0 { - body["host"] = host - } - return region.rdsDo(instanceId, "users", nil, jsonutils.Marshal(body)) -} diff --git a/pkg/multicloud/google/dbinstance_backup.go b/pkg/multicloud/google/dbinstance_backup.go deleted file mode 100644 index 89ec9fc1bd..0000000000 --- a/pkg/multicloud/google/dbinstance_backup.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type OperationError struct { - Kind string - Code string - Message string -} - -type SDBInstanceBackup struct { - multicloud.SDBInstanceBackupBase - multicloud.GoogleTags - rds *SDBInstance - - Kind string - Status string - EnqueuedTime string - Id string - StartTime time.Time - EndTime time.Time - Type string - Description string - WindowStartTime time.Time - Instance string - SelfLink string - Location string - Error OperationError -} - -func (region *SRegion) GetDBInstanceBackups(instanceId string) ([]SDBInstanceBackup, error) { - backups := []SDBInstanceBackup{} - params := map[string]string{} - resource := fmt.Sprintf("instances/%s/backupRuns", instanceId) - err := region.RdsListAll(resource, params, &backups) - if err != nil { - return nil, errors.Wrap(err, "RdsListAll") - } - return backups, nil -} - -func (region *SRegion) GetDBInstanceBackup(backupId string) (*SDBInstanceBackup, error) { - backup := SDBInstanceBackup{} - err := region.rdsGet(backupId, &backup) - if err != nil { - return nil, errors.Wrap(err, "RdsGet") - } - rds, err := region.GetDBInstance(strings.TrimSuffix(backup.SelfLink, fmt.Sprintf("/%s", backup.Id))) - if err != nil { - return nil, errors.Wrap(err, "GetDBInstance") - } - backup.rds = rds - return &backup, nil -} - -func (backup *SDBInstanceBackup) GetName() string { - return backup.Id -} - -func (backup *SDBInstanceBackup) GetId() string { - return backup.SelfLink -} - -func (backup *SDBInstanceBackup) GetGlobalId() string { - return strings.TrimPrefix(backup.SelfLink, fmt.Sprintf("%s/%s/", GOOGLE_DBINSTANCE_DOMAIN, GOOGLE_DBINSTANCE_API_VERSION)) -} - -func (backup *SDBInstanceBackup) GetProjectId() string { - return backup.rds.GetProjectId() -} - -func (backup *SDBInstanceBackup) Refresh() error { - _backup, err := backup.rds.region.GetDBInstanceBackup(backup.SelfLink) - if err != nil { - return errors.Wrap(err, "GetDBInstanceBackup") - } - return jsonutils.Update(backup, _backup) -} - -func (backup *SDBInstanceBackup) GetStatus() string { - switch backup.Status { - case "SQL_BACKUP_RUN_STATUS_UNSPECIFIED": - return api.DBINSTANCE_BACKUP_UNKNOWN - case "ENQUEUED": - return api.DBINSTANCE_BACKUP_CREATING - case "FAILED": - return api.DBINSTANCE_BACKUP_FAILED - case "SUCCESSFUL", "OVERDUE", "RUNNING", "SKIPPED", "DELETION_PENDING": - return api.DBINSTANCE_BACKUP_READY - case "DELETION_FAILED", "DELETED": - return api.DBINSTANCE_BACKUP_DELETING - } - return backup.Status -} - -func (backup *SDBInstanceBackup) IsEmulated() bool { - return false -} - -func (backup *SDBInstanceBackup) GetEngine() string { - return backup.rds.GetEngine() -} - -func (backup *SDBInstanceBackup) GetEngineVersion() string { - return backup.rds.GetEngineVersion() -} - -func (backup *SDBInstanceBackup) GetDBInstanceId() string { - return backup.rds.GetGlobalId() -} - -func (backup *SDBInstanceBackup) GetStartTime() time.Time { - return backup.StartTime -} - -func (backup *SDBInstanceBackup) GetEndTime() time.Time { - return backup.EndTime -} - -func (backup *SDBInstanceBackup) GetBackupSizeMb() int { - return 0 -} - -func (backup *SDBInstanceBackup) GetDBNames() string { - return "" -} - -func (backup *SDBInstanceBackup) GetBackupMode() string { - switch backup.Type { - case "AUTOMATED": - return api.BACKUP_MODE_AUTOMATED - default: - return api.BACKUP_MODE_MANUAL - } -} - -func (backup *SDBInstanceBackup) Delete() error { - return backup.rds.region.rdsDelete(backup.SelfLink) -} - -func (region *SRegion) CreateDBInstanceBackup(instanceId string, name, desc string) error { - body := map[string]interface{}{ - "name": name, - "description": desc, - } - return region.rdsDo(instanceId, "backupRuns", nil, jsonutils.Marshal(body)) -} diff --git a/pkg/multicloud/google/dbinstance_database.go b/pkg/multicloud/google/dbinstance_database.go deleted file mode 100644 index 7fd6bf9f89..0000000000 --- a/pkg/multicloud/google/dbinstance_database.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSqlserverDatabaseDetails struct { - CompatibilityLevel int - RecoveryModel string -} - -type SDBInstanceDatabase struct { - multicloud.SResourceBase - multicloud.GoogleTags - rds *SDBInstance - Kind string - Collation string - Etag string - Name string - Instance string - SelfLink string - Charset string - Project string - SqlserverDatabaseDetails SSqlserverDatabaseDetails -} - -func (region *SRegion) GetDBInstanceDatabases(instance string) ([]SDBInstanceDatabase, error) { - databases := []SDBInstanceDatabase{} - params := map[string]string{} - resource := fmt.Sprintf("instances/%s/databases", instance) - err := region.RdsListAll(resource, params, &databases) - if err != nil { - return nil, errors.Wrap(err, "RdsListAll") - } - return databases, nil -} - -func (region *SRegion) DeleteDBInstanceDatabase(id string) error { - return region.rdsDelete(id) -} - -func (database *SDBInstanceDatabase) Delete() error { - return database.rds.region.DeleteDBInstanceDatabase(database.SelfLink) -} - -func (database *SDBInstanceDatabase) GetCharacterSet() string { - return database.Charset -} - -func (database *SDBInstanceDatabase) GetGlobalId() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetId() string { - return database.SelfLink -} - -func (database *SDBInstanceDatabase) GetName() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetStatus() string { - return api.DBINSTANCE_DATABASE_RUNNING -} - -func (database *SDBInstanceDatabase) IsEmulated() bool { - return false -} - -func (database *SDBInstanceDatabase) Refresh() error { - _database := SDBInstanceDatabase{} - err := database.rds.region.rdsGet(database.SelfLink, &_database) - if err != nil { - return errors.Wrap(err, "rdsGet") - } - return jsonutils.Update(database, _database) -} - -func (region *SRegion) CreateDatabase(instanceId string, name, charset string) error { - body := map[string]interface{}{ - "charset": charset, - "name": name, - } - return region.rdsDo(instanceId, "databases", nil, jsonutils.Marshal(body)) -} diff --git a/pkg/multicloud/google/disk.go b/pkg/multicloud/google/disk.go deleted file mode 100644 index 50be5571f0..0000000000 --- a/pkg/multicloud/google/disk.go +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - - billing "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDisk struct { - storage *SStorage - SResourceBase - multicloud.SDisk - multicloud.GoogleTags - - ProvisionedIops int - CreationTimestamp time.Time - SizeGB int - Zone string - Status string - Type string - SourceImage string - LastAttachTimestamp time.Time - LastDetachTimestamp time.Time - LabelFingerprint string - PhysicalBlockSizeBytes string - ResourcePolicies []string - Users []string - Kind string - autoDelete bool - boot bool - index int -} - -func (region *SRegion) GetDisks(zone string, storageType string, maxResults int, pageToken string) ([]SDisk, error) { - disks := []SDisk{} - if len(zone) == 0 { - return nil, fmt.Errorf("zone params can not be empty") - } - params := map[string]string{} - if len(storageType) > 0 { - params["filter"] = fmt.Sprintf(`type="%s/%s/projects/%s/zones/%s/diskTypes/%s"`, GOOGLE_COMPUTE_DOMAIN, GOOGLE_API_VERSION, region.GetProjectId(), zone, storageType) - } - return disks, region.List(fmt.Sprintf("zones/%s/disks", zone), params, maxResults, pageToken, &disks) -} - -func (region *SRegion) GetDisk(id string) (*SDisk, error) { - disk := &SDisk{} - return disk, region.Get("disks", id, disk) -} - -func (disk *SDisk) GetStatus() string { - switch disk.Status { - case "READY": - return api.DISK_READY - case "CREATING": - return api.DISK_ALLOCATING - case "RESTORING": - return api.DISK_RESET - case "FAILED": - return api.DISK_ALLOC_FAILED - case "DELETING": - return api.DISK_DEALLOC - default: - return api.DISK_UNKNOWN - } -} - -func (disk *SDisk) IsEmulated() bool { - return false -} - -func (disk *SDisk) Refresh() error { - _disk, err := disk.storage.zone.region.GetDisk(disk.Id) - if err != nil { - return err - } - return jsonutils.Update(disk, _disk) -} - -func (disk *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return disk.storage, nil -} - -func (disk *SDisk) GetIStorageId() string { - return disk.storage.GetGlobalId() -} - -func (disk *SDisk) GetDiskFormat() string { - return "raw" -} - -func (disk *SDisk) GetDiskSizeMB() int { - return disk.SizeGB * 1024 -} - -func (disk *SDisk) GetIsAutoDelete() bool { - if len(disk.Users) == 0 { - return false - } - return disk.autoDelete -} - -func (disk *SDisk) GetTemplateId() string { - return disk.SourceImage -} - -func (disk *SDisk) GetDiskType() string { - if disk.boot && len(disk.Users) > 0 { - return api.DISK_TYPE_SYS - } - return api.DISK_TYPE_DATA -} - -func (disk *SDisk) GetFsFormat() string { - return "" -} - -func (disk *SDisk) GetIsNonPersistent() bool { - return false -} - -func (disk *SDisk) GetDriver() string { - return "scsi" -} - -func (disk *SDisk) GetCacheMode() string { - return "none" -} - -func (disk *SDisk) GetMountpoint() string { - return "" -} - -func (disk *SDisk) GetAccessPath() string { - return "" -} - -func (disk *SDisk) GetIops() int { - return disk.ProvisionedIops -} - -func (disk *SDisk) Delete(ctx context.Context) error { - return disk.storage.zone.region.Delete(disk.SelfLink) -} - -func (disk *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := disk.storage.zone.region.CreateSnapshot(disk.SelfLink, name, desc) - if err != nil { - return nil, err - } - snapshot.region = disk.storage.zone.region - return snapshot, nil -} - -func (disk *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := disk.storage.zone.region.GetSnapshots(disk.SelfLink, 0, "") - if err != nil { - return nil, err - } - isnapshots := []cloudprovider.ICloudSnapshot{} - for i := range snapshots { - snapshots[i].region = disk.storage.zone.region - isnapshots = append(isnapshots, &snapshots[i]) - } - return isnapshots, nil -} - -func (disk *SDisk) GetISnapshot(id string) (cloudprovider.ICloudSnapshot, error) { - return disk.storage.zone.region.GetSnapshot(id) -} - -func (disk *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { - result := []string{} - for _, policy := range disk.ResourcePolicies { - globalId := strings.TrimPrefix(policy, fmt.Sprintf("%s/%s/", GOOGLE_COMPUTE_DOMAIN, GOOGLE_API_VERSION)) - result = append(result, globalId) - } - return result, nil -} - -func (disk *SDisk) Resize(ctx context.Context, newSizeMB int64) error { - return disk.storage.zone.region.ResizeDisk(disk.SelfLink, int(newSizeMB>>10)) -} - -func (disk *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (disk *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (disk *SDisk) GetBillingType() string { - return billing.BILLING_TYPE_POSTPAID -} - -func (disk *SDisk) GetCreatedAt() time.Time { - return disk.CreationTimestamp -} - -func (disk *SDisk) GetExpiredAt() time.Time { - return time.Time{} -} - -func (disk *SDisk) GetProjectId() string { - return disk.storage.zone.region.GetProjectId() -} - -func (region *SRegion) CreateDisk(name string, sizeGb int, zone string, storageType string, image string, desc string) (*SDisk, error) { - if !strings.HasPrefix(storageType, GOOGLE_COMPUTE_DOMAIN) { - storageType = fmt.Sprintf("projects/%s/zones/%s/diskTypes/%s", region.GetProjectId(), zone, storageType) - } - body := map[string]interface{}{ - "name": name, - "description": desc, - // https://www.googleapis.com/compute/v1/projects/my-project-15390453537169/zones/us-west2-c/diskTypes/pd-standard - // projects/my-project-15390453537169/zones/us-west2-c/diskTypes/pd-standard - "type": storageType, - } - if len(image) > 0 { - body["sourceImage"] = image - } else { - body["sizeGb"] = sizeGb - } - disk := &SDisk{} - resource := fmt.Sprintf("zones/%s/disks", zone) - err := region.Insert(resource, jsonutils.Marshal(body), disk) - if err != nil { - return nil, err - } - return disk, nil -} - -func (region *SRegion) ResizeDisk(id string, sizeGb int) error { - body := map[string]int{ - "sizeGb": sizeGb, - } - return region.Do(id, "resize", nil, jsonutils.Marshal(body)) -} - -func (self *SRegion) CreateSnapshot(diskId string, name string, desc string) (*SSnapshot, error) { - body := map[string]string{ - "name": name, - "description": desc, - } - err := self.Do(diskId, "createSnapshot", nil, jsonutils.Marshal(body)) - if err != nil { - return nil, err - } - snapshot := &SSnapshot{region: self} - return snapshot, self.GetBySelfId(fmt.Sprintf("projects/%s/global/snapshots/%s", self.GetProjectId(), name), snapshot) -} diff --git a/pkg/multicloud/google/doc.go b/pkg/multicloud/google/doc.go deleted file mode 100644 index c86aac10fa..0000000000 --- a/pkg/multicloud/google/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google // import "yunion.io/x/onecloud/pkg/multicloud/google" diff --git a/pkg/multicloud/google/eip.go b/pkg/multicloud/google/eip.go deleted file mode 100644 index c5ee48d6bf..0000000000 --- a/pkg/multicloud/google/eip.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SAddress struct { - region *SRegion - SResourceBase - multicloud.SEipBase - multicloud.GoogleTags - instanceId string - - CreationTimestamp time.Time - Description string - Address string - Status string - Region string - Users []string - NetworkTier string - AddressType string - Kind string -} - -func (region *SRegion) GetEips(address string, maxResults int, pageToken string) ([]SAddress, error) { - eips := []SAddress{} - params := map[string]string{} - if len(address) > 0 { - params["filter"] = fmt.Sprintf(`address="%s"`, address) - } - resource := fmt.Sprintf("regions/%s/addresses", region.Name) - return eips, region.List(resource, params, maxResults, pageToken, &eips) -} - -func (region *SRegion) GetEip(id string) (*SAddress, error) { - eip := &SAddress{region: region} - return eip, region.Get("addresses", id, eip) -} - -func (addr *SAddress) GetStatus() string { - switch addr.Status { - case "RESERVING": - return api.EIP_STATUS_ASSOCIATE - case "RESERVED": - return api.EIP_STATUS_READY - case "IN_USE": - return api.EIP_STATUS_READY - default: - log.Errorf("Unknown eip status: %s", addr.Status) - return api.EIP_STATUS_UNKNOWN - } -} - -func (addr *SAddress) GetProjectId() string { - return addr.region.GetProjectId() -} - -func (addr *SAddress) IsEmulated() bool { - return len(addr.instanceId) > 0 -} - -func (addr *SAddress) GetCreatedAt() time.Time { - return addr.CreationTimestamp -} - -func (addr *SAddress) GetExpiredAt() time.Time { - return time.Time{} -} - -func (addr *SAddress) GetBillingType() string { - return billing.BILLING_TYPE_POSTPAID -} - -func (self *SAddress) Refresh() error { - if self.IsEmulated() { - return nil - } - addr, err := self.region.GetEip(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, addr) -} - -func (addr *SAddress) GetIpAddr() string { - return addr.Address -} - -func (addr *SAddress) GetMode() string { - if addr.IsEmulated() { - return api.EIP_MODE_INSTANCE_PUBLICIP - } - return api.EIP_MODE_STANDALONE_EIP -} - -func (addr *SAddress) GetINetworkId() string { - return "" -} - -func (addr *SAddress) GetAssociationType() string { - if len(addr.GetAssociationExternalId()) > 0 { - return api.EIP_ASSOCIATE_TYPE_SERVER - } - return "" -} - -func (addr *SAddress) GetAssociationExternalId() string { - if len(addr.instanceId) > 0 { - return addr.instanceId - } - if len(addr.Users) > 0 { - res := &SResourceBase{} - err := addr.region.GetBySelfId(addr.Users[0], res) - if err != nil { - return "" - } - return res.GetGlobalId() - } - return "" -} - -func (addr *SAddress) GetBandwidth() int { - return 0 -} - -func (addr *SAddress) GetInternetChargeType() string { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC -} - -func (addr *SAddress) Delete() error { - return addr.region.Delete(addr.SelfLink) -} - -func (addr *SAddress) Associate(conf *cloudprovider.AssociateConfig) error { - return addr.region.AssociateInstanceEip(conf.InstanceId, addr.Address) -} - -func (addr *SAddress) Dissociate() error { - if len(addr.Users) > 0 { - return addr.region.DissociateInstanceEip(addr.Users[0], addr.Address) - } - return nil -} - -func (addr *SAddress) ChangeBandwidth(bw int) error { - return cloudprovider.ErrNotSupported -} - -func (region *SRegion) CreateEip(name string, desc string) (*SAddress, error) { - body := map[string]string{ - "name": name, - "description": desc, - } - resource := fmt.Sprintf("regions/%s/addresses", region.Name) - addr := &SAddress{region: region} - err := region.Insert(resource, jsonutils.Marshal(body), addr) - if err != nil { - return nil, err - } - return addr, nil -} - -func (region *SRegion) AssociateInstanceEip(instanceId string, eip string) error { - instance, err := region.GetInstance(instanceId) - if err != nil { - return errors.Wrap(err, "region.GetInstance") - } - for _, networkInterface := range instance.NetworkInterfaces { - body := map[string]interface{}{ - "type": "ONE_TO_ONE_NAT", - "name": "External NAT", - "natIP": eip, - } - params := map[string]string{"networkInterface": networkInterface.Name} - return region.Do(instance.SelfLink, "addAccessConfig", params, jsonutils.Marshal(body)) - } - return fmt.Errorf("no valid networkinterface to associate") -} - -func (self *SRegion) DissociateInstanceEip(instanceId string, eip string) error { - instance := SInstance{} - err := self.GetBySelfId(instanceId, &instance) - if err != nil { - return errors.Wrap(err, "region.GetInstance") - } - for _, networkInterface := range instance.NetworkInterfaces { - for _, accessConfig := range networkInterface.AccessConfigs { - if accessConfig.NatIP == eip { - body := map[string]string{} - params := map[string]string{ - "networkInterface": networkInterface.Name, - "accessConfig": accessConfig.Name, - } - return self.Do(instance.SelfLink, "deleteAccessConfig", params, jsonutils.Marshal(body)) - } - } - } - return nil -} diff --git a/pkg/multicloud/google/globalnetwork.go b/pkg/multicloud/google/globalnetwork.go deleted file mode 100644 index 0978d914a0..0000000000 --- a/pkg/multicloud/google/globalnetwork.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SGlobalNetwork struct { - multicloud.GoogleTags - SResourceBase - - client *SGoogleClient - - CreationTimestamp time.Time - Description string - AutoCreateSubnetworks bool - Subnetworks []string - RoutingConfig map[string]string - Kind string -} - -func (self *SGlobalNetwork) GetStatus() string { - return api.GLOBAL_VPC_STATUS_AVAILABLE -} - -func (self *SGlobalNetwork) IsEmulated() bool { - return false -} - -func (self *SGlobalNetwork) Delete() error { - return self.client.ecsDelete(self.SelfLink, nil) -} - -func (self *SGlobalNetwork) GetCreatedAt() time.Time { - return self.CreationTimestamp -} - -func (self *SGlobalNetwork) Refresh() error { - gvpc, err := self.client.GetGlobalNetwork(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, gvpc) -} - -func (cli *SGoogleClient) GetGlobalNetwork(id string) (*SGlobalNetwork, error) { - net := &SGlobalNetwork{client: cli} - return net, cli.ecsGet("global/networks", id, net) -} - -func (self *SGoogleClient) GetICloudGlobalVpcById(id string) (cloudprovider.ICloudGlobalVpc, error) { - return self.GetGlobalNetwork(id) -} - -func (cli *SGoogleClient) GetGlobalNetworks(maxResults int, pageToken string) ([]SGlobalNetwork, error) { - networks := []SGlobalNetwork{} - params := map[string]string{} - resource := "global/networks" - if maxResults == 0 && len(pageToken) == 0 { - err := cli.ecsListAll(resource, params, &networks) - if err != nil { - return nil, errors.Wrap(err, "ecsListAll") - } - return networks, nil - } - resp, err := cli.ecsList(resource, params) - if err != nil { - return nil, errors.Wrap(err, "ecsList") - } - if resp.Contains("items") { - err = resp.Unmarshal(&networks, "items") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - } - return networks, nil -} - -func (self *SGoogleClient) CreateGlobalNetwork(name string, desc string) (*SGlobalNetwork, error) { - body := map[string]interface{}{ - "name": name, - "description": desc, - "autoCreateSubnetworks": false, - "mtu": 1460, - "routingConfig": map[string]string{ - "routingMode": "REGIONAL", - }, - } - globalnetwork := &SGlobalNetwork{client: self} - err := self.Insert("global/networks", jsonutils.Marshal(body), globalnetwork) - if err != nil { - return nil, errors.Wrap(err, "self.Insert") - } - return globalnetwork, nil -} - -func (self *SGoogleClient) CreateICloudGlobalVpc(opts *cloudprovider.GlobalVpcCreateOptions) (cloudprovider.ICloudGlobalVpc, error) { - gvpc, err := self.CreateGlobalNetwork(opts.NAME, opts.Desc) - if err != nil { - return nil, errors.Wrapf(err, "CreateICloudGlobalVpc") - } - return gvpc, nil -} - -func (self *SGoogleClient) GetICloudGlobalVpcs() ([]cloudprovider.ICloudGlobalVpc, error) { - gvpcs, err := self.GetGlobalNetworks(0, "") - if err != nil { - return nil, errors.Wrapf(err, "GetGlobalNetworks") - } - ret := []cloudprovider.ICloudGlobalVpc{} - for i := range gvpcs { - gvpcs[i].client = self - ret = append(ret, &gvpcs[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/google/host.go b/pkg/multicloud/google/host.go deleted file mode 100644 index 8b623f5363..0000000000 --- a/pkg/multicloud/google/host.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SHost struct { - multicloud.SHostBase - - zone *SZone -} - -func (host *SHost) GetId() string { - return host.zone.GetGlobalId() -} - -func (host *SHost) GetGlobalId() string { - return host.GetId() -} - -func (host *SHost) GetName() string { - return fmt.Sprintf("%s-%s", host.zone.region.client.cpcfg.Name, host.zone.GetName()) -} - -func (host *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - return host.zone.GetIStorages() -} - -func (host *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return host.zone.GetIStorageById(id) -} - -func (host *SHost) IsEmulated() bool { - return true -} - -func (host *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (host *SHost) Refresh() error { - return nil -} - -func (host *SHost) GetHostStatus() string { - return api.HOST_ONLINE -} - -func (host *SHost) GetEnabled() bool { - return true -} - -func (host *SHost) GetAccessIp() string { - return "" -} - -func (host *SHost) GetAccessMac() string { - return "" -} - -func (host *SHost) GetSysInfo() jsonutils.JSONObject { - info := jsonutils.NewDict() - info.Add(jsonutils.NewString(CLOUD_PROVIDER_GOOGLE), "manufacture") - return info -} - -func (host *SHost) GetSN() string { - return "" -} - -func (host *SHost) GetCpuCount() int { - return 0 -} - -func (host *SHost) GetNodeCount() int8 { - return 0 -} - -func (host *SHost) GetCpuDesc() string { - return "" -} - -func (host *SHost) GetCpuMhz() int { - return 0 -} - -func (host *SHost) GetMemSizeMB() int { - return 0 -} - -func (host *SHost) GetStorageSizeMB() int { - return 0 -} - -func (host *SHost) GetStorageType() string { - return api.DISK_TYPE_HYBRID -} - -func (host *SHost) GetHostType() string { - return api.HOST_TYPE_GOOGLE -} - -func (host *SHost) GetWire() *SWire { - vpc := &SVpc{region: host.zone.region} - return &SWire{vpc: vpc} -} - -func (host *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - ivpcs, err := host.zone.region.GetIVpcs() - if err != nil { - return nil, errors.Wrap(err, "region.GetIVpcs") - } - iwires := []cloudprovider.ICloudWire{} - for i := range ivpcs { - _iwires, err := ivpcs[i].GetIWires() - if err != nil { - return nil, errors.Wrap(err, "ivpcs[i].GetIWires") - } - iwires = append(iwires, _iwires...) - } - return iwires, nil -} - -func (host *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - instances, err := host.zone.region.GetInstances(host.zone.Name, 0, "") - if err != nil { - return nil, err - } - iVMs := []cloudprovider.ICloudVM{} - for i := range instances { - instances[i].host = host - iVMs = append(iVMs, &instances[i]) - } - return iVMs, nil -} - -func (host *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - instance, err := host.zone.region.GetInstance(id) - if err != nil { - return nil, err - } - if instance.Zone != host.zone.SelfLink { - return nil, cloudprovider.ErrNotFound - } - instance.host = host - return instance, nil -} - -func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - instance, err := host.zone.region._createVM(host.zone.Name, desc) - if err != nil { - return nil, err - } - instance.host = host - return instance, nil -} - -func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (host *SHost) GetIsMaintenance() bool { - return false -} - -func (host *SHost) GetVersion() string { - return GOOGLE_API_VERSION -} diff --git a/pkg/multicloud/google/image.go b/pkg/multicloud/google/image.go deleted file mode 100644 index 7116d8262f..0000000000 --- a/pkg/multicloud/google/image.go +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type GuestOsFeature struct { - Type string -} - -type SDeprecated struct { - State string - Replacement string - Deprecated bool -} - -type SImage struct { - multicloud.SImageBase - multicloud.GoogleTags - storagecache *SStoragecache - SResourceBase - Name string - SelfLink string - Id string - - // normalized image info - imgInfo *imagetools.ImageInfo - - CreationTimestamp time.Time - Description string - SourceType string - RawDisk map[string]string - Deprecated SDeprecated - Status string - ArchiveSizeBytes int64 - DiskSizeGb int - Licenses []string - Family string - LabelFingerprint string - GuestOsFeatures []GuestOsFeature - LicenseCodes []string - StorageLocations []string - Kind string -} - -func (self *SImage) GetId() string { - return self.SelfLink -} - -func (self *SImage) GetGlobalId() string { - return strings.TrimPrefix(self.SelfLink, fmt.Sprintf("%s/%s/", GOOGLE_COMPUTE_DOMAIN, GOOGLE_API_VERSION)) -} - -func (self *SImage) GetName() string { - return self.Name -} - -func (region *SRegion) SetProjectId(id string) { - region.client.projectId = id -} - -func (region *SRegion) GetAllAvailableImages() ([]SImage, error) { - images := []SImage{} - projectId := region.client.projectId - for _, project := range []string{ - "centos-cloud", - "ubuntu-os-cloud", - "windows-cloud", - "windows-sql-cloud", - "suse-cloud", - "suse-sap-cloud", - "rhel-cloud", - "rhel-sap-cloud", - "cos-cloud", - "coreos-cloud", - "debian-cloud", - projectId, - } { - _images, err := region.GetImages(project, 0, "") - if err != nil { - return nil, err - } - for _, image := range _images { - if image.Deprecated.State == "" { - images = append(images, image) - } - } - } - return images, nil -} - -func (region *SRegion) GetImages(project string, maxResults int, pageToken string) ([]SImage, error) { - images := []SImage{} - resource := "global/images" - params := map[string]string{} - if len(project) > 0 { - region.SetProjectId(project) - } - return images, region.List(resource, params, maxResults, pageToken, &images) -} - -func (region *SRegion) GetImage(id string) (*SImage, error) { - image := &SImage{} - return image, region.GetBySelfId(id, image) -} - -func (image *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (image *SImage) GetStatus() string { - switch image.Status { - case "READY": - return api.CACHED_IMAGE_STATUS_ACTIVE - case "FAILED": - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - case "PENDING": - return api.CACHED_IMAGE_STATUS_SAVING - default: - log.Errorf("Unknown image status: %s", image.Status) - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (image *SImage) GetImageStatus() string { - switch image.Status { - case "READY": - return cloudprovider.IMAGE_STATUS_ACTIVE - case "FAILED": - return cloudprovider.IMAGE_STATUS_KILLED - case "PENDING": - return cloudprovider.IMAGE_STATUS_QUEUED - default: - return cloudprovider.IMAGE_STATUS_KILLED - } -} - -func (image *SImage) Refresh() error { - _image, err := image.storagecache.region.GetImage(image.SelfLink) - if err != nil { - return err - } - return jsonutils.Update(image, _image) -} - -func (image *SImage) GetImageType() cloudprovider.TImageType { - if strings.Index(image.SelfLink, image.storagecache.region.GetProjectId()) >= 0 { - return cloudprovider.ImageTypeCustomized - } - return cloudprovider.ImageTypeSystem -} - -func (image *SImage) GetSizeByte() int64 { - return image.ArchiveSizeBytes -} - -func (image *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if image.imgInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(image.Name, "", "", "", "") - image.imgInfo = &imgInfo - } - - return image.imgInfo -} - -func (image *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(image.getNormalizedImageInfo().OsType) -} - -func (image *SImage) GetOsDist() string { - return image.getNormalizedImageInfo().OsDistro -} - -func (image *SImage) GetOsVersion() string { - return image.getNormalizedImageInfo().OsVersion -} - -func (image *SImage) GetOsLang() string { - return image.getNormalizedImageInfo().OsLang -} - -func (image *SImage) GetOsArch() string { - return image.getNormalizedImageInfo().OsArch -} - -func (image *SImage) GetFullOsName() string { - return image.Name -} - -func (image *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(image.getNormalizedImageInfo().OsBios) -} - -func (image *SImage) GetMinOsDiskSizeGb() int { - return image.DiskSizeGb -} - -func (image *SImage) GetCreatedAt() time.Time { - return image.CreationTimestamp -} - -func (image *SImage) GetImageFormat() string { - return "raw" -} - -func (image *SImage) IsEmulated() bool { - return false -} - -func (image *SImage) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (image *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return image.storagecache -} - -func (region *SRegion) CreateImage(name string, desc string, bucketName string, sourceFile string) (*SImage, error) { - body := map[string]interface{}{ - "timeout": "7200s", - "steps": []struct { - Args []string - Name string - }{ - { - Args: []string{ - fmt.Sprintf("-source_file=gs://%s/%s", bucketName, sourceFile), - "-data_disk", - "-timeout=7056s", - "-image_name=" + name, - "-no_guest_environment", - "-client_id=onecloud", - "-description=" + desc, - }, - Name: "gcr.io/compute-image-tools/gce_vm_image_import:release", - }, - }, - "tags": []string{"gce-daisy", "gce-daisy-image-import"}, - } - err := region.CloudbuildInsert(jsonutils.Marshal(body)) - if err != nil { - return nil, err - } - return region.GetImage(fmt.Sprintf("projects/%s/global/images/%s", region.GetProjectId(), name)) -} diff --git a/pkg/multicloud/google/instance.go b/pkg/multicloud/google/instance.go deleted file mode 100644 index 98e289d79e..0000000000 --- a/pkg/multicloud/google/instance.go +++ /dev/null @@ -1,998 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/fileutils" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/cloudinit" - "yunion.io/x/onecloud/pkg/util/encode" - "yunion.io/x/onecloud/pkg/util/imagetools" - "yunion.io/x/onecloud/pkg/util/pinyinutils" -) - -const ( - METADATA_SSH_KEYS = "ssh-keys" - METADATA_STARTUP_SCRIPT = "startup-script" - METADATA_POWER_SHELL = "sysprep-specialize-script-ps1" - METADATA_STARTUP_SCRIPT_POWER_SHELL = "windows-startup-script-ps1" -) - -type AccessConfig struct { - Type string - Name string - NatIP string - NetworkTier string - Kind string -} - -type InstanceDisk struct { - Type string - Mode string - Source string - DeviceName string - Index int - Boot bool - AutoDelete bool - Licenses []string - Interface string - GuestOsFeatures []GuestOsFeature - Kind string -} - -type ServiceAccount struct { - Email string - scopes []string -} - -type SInstanceTag struct { - Items []string - Fingerprint string -} - -type SMetadataItem struct { - Key string - Value string -} - -type SMetadata struct { - Fingerprint string - Items []SMetadataItem -} - -type SInstance struct { - multicloud.SInstanceBase - multicloud.GoogleTags - host *SHost - SResourceBase - - osInfo *imagetools.ImageInfo - - CreationTimestamp time.Time - Description string - Tags SInstanceTag - MachineType string - Status string - Zone string - CanIpForward bool - NetworkInterfaces []SNetworkInterface - Disks []InstanceDisk - Metadata SMetadata - ServiceAccounts []ServiceAccount - Scheduling map[string]interface{} - CpuPlatform string - LabelFingerprint string - StartRestricted bool - DeletionProtection bool - Kind string - - guestCpus int - memoryMb int - machineType string -} - -func (region *SRegion) GetInstances(zone string, maxResults int, pageToken string) ([]SInstance, error) { - instances := []SInstance{} - params := map[string]string{} - if len(zone) == 0 { - return nil, fmt.Errorf("zone params can not be empty") - } - resource := fmt.Sprintf("zones/%s/instances", zone) - return instances, region.List(resource, params, maxResults, pageToken, &instances) -} - -func (region *SRegion) GetInstance(id string) (*SInstance, error) { - instance := &SInstance{} - return instance, region.Get("instances", id, instance) -} - -func (instance *SInstance) GetHostname() string { - return instance.GetName() -} - -func (instance *SInstance) fetchMachineType() error { - if instance.guestCpus > 0 || instance.memoryMb > 0 || len(instance.machineType) > 0 { - return nil - } - machinetype := SMachineType{} - err := instance.host.zone.region.GetBySelfId(instance.MachineType, &machinetype) - if err != nil { - return err - } - instance.guestCpus = machinetype.GuestCpus - instance.memoryMb = machinetype.MemoryMb - instance.machineType = machinetype.Name - return nil -} - -func (self *SInstance) Refresh() error { - instance, err := self.host.zone.region.GetInstance(self.Id) - if err != nil { - return err - } - err = jsonutils.Update(self, instance) - if err != nil { - return err - } - instance.Labels = self.Labels - return nil -} - -//PROVISIONING, STAGING, RUNNING, STOPPING, STOPPED, SUSPENDING, SUSPENDED, and TERMINATED. -func (instance *SInstance) GetStatus() string { - switch instance.Status { - case "PROVISIONING": - return api.VM_DEPLOYING - case "STAGING": - return api.VM_STARTING - case "RUNNING": - return api.VM_RUNNING - case "STOPPING": - return api.VM_STOPPING - case "STOPPED": - return api.VM_READY - case "SUSPENDING": - return api.VM_SUSPENDING - case "SUSPENDED": - return api.VM_SUSPEND - case "TERMINATED": - return api.VM_READY - default: - return api.VM_UNKNOWN - } -} - -func (instance *SInstance) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (instance *SInstance) GetCreatedAt() time.Time { - return instance.CreationTimestamp -} - -func (instance *SInstance) GetExpiredAt() time.Time { - return time.Time{} -} - -func (instance *SInstance) GetProjectId() string { - return instance.host.zone.region.GetProjectId() -} - -func (instance *SInstance) GetIHost() cloudprovider.ICloudHost { - return instance.host -} - -func (instance *SInstance) GetIHostId() string { - return instance.host.GetGlobalId() -} - -func (instance *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - idisks := []cloudprovider.ICloudDisk{} - for _, disk := range instance.Disks { - _disk := &SDisk{} - err := instance.host.zone.region.GetBySelfId(disk.Source, _disk) - if err != nil { - return nil, errors.Wrap(err, "GetDisk") - } - storage, err := instance.host.zone.region.GetStorage(_disk.Type) - if err != nil { - return nil, errors.Wrap(err, "GetStorage") - } - storage.zone = instance.host.zone - _disk.storage = storage - _disk.autoDelete = disk.AutoDelete - _disk.boot = disk.Boot - _disk.index = disk.Index - idisks = append(idisks, _disk) - } - return idisks, nil -} - -func (instance *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nics := []cloudprovider.ICloudNic{} - for i := range instance.NetworkInterfaces { - instance.NetworkInterfaces[i].instance = instance - nics = append(nics, &instance.NetworkInterfaces[i]) - } - return nics, nil -} - -func (instance *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - for _, networkinterface := range instance.NetworkInterfaces { - for _, conf := range networkinterface.AccessConfigs { - if len(conf.NatIP) > 0 { - eips, err := instance.host.zone.region.GetEips(conf.NatIP, 0, "") - if err != nil { - return nil, errors.Wrapf(err, "region.GetEip(%s)", conf.NatIP) - } - if len(eips) == 1 { - eips[0].region = instance.host.zone.region - return &eips[0], nil - } - eip := &SAddress{ - region: instance.host.zone.region, - Status: "IN_USE", - Address: conf.NatIP, - instanceId: instance.Id, - } - eip.Id = instance.Id - eip.SelfLink = instance.SelfLink - return eip, nil - } - } - } - return nil, nil -} - -func (instance *SInstance) GetVcpuCount() int { - instance.fetchMachineType() - return instance.guestCpus -} - -func (instance *SInstance) GetVmemSizeMB() int { - instance.fetchMachineType() - return instance.memoryMb -} - -func (instance *SInstance) GetBootOrder() string { - return "cdn" -} - -func (instance *SInstance) GetVga() string { - return "std" -} - -func (instance *SInstance) GetVdi() string { - return "vnc" -} - -func (instance *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(instance.getNormalizedOsInfo().OsType) -} - -func (instance *SInstance) getValidLicense() string { - for _, disk := range instance.Disks { - if disk.Index == 0 { - for _, license := range disk.Licenses { - if len(license) > 0 { - return license - } - } - } - } - return "" -} - -func (instance *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { - if instance.osInfo != nil { - return instance.osInfo - } - osinfo := imagetools.NormalizeImageInfo(instance.getValidLicense(), "", "", "", "") - instance.osInfo = &osinfo - return instance.osInfo -} - -func (instance *SInstance) GetFullOsName() string { - return instance.getValidLicense() -} - -func (instance *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(instance.getNormalizedOsInfo().OsBios) -} - -func (instance *SInstance) GetOsArch() string { - return instance.getNormalizedOsInfo().OsArch -} - -func (instance *SInstance) GetOsDist() string { - return instance.getNormalizedOsInfo().OsDistro -} - -func (instance *SInstance) GetOsVersion() string { - return instance.getNormalizedOsInfo().OsVersion -} - -func (instance *SInstance) GetOsLang() string { - return instance.getNormalizedOsInfo().OsLang -} - -func (instance *SInstance) GetMachine() string { - return "pc" -} - -func (instance *SInstance) GetInstanceType() string { - instance.fetchMachineType() - return instance.machineType -} - -func (instance *SInstance) AssignSecurityGroup(id string) error { - for _, secgrpType := range []string{SECGROUP_TYPE_TAG, SECGROUP_TYPE_SERVICE_ACCOUNT} { - if strings.Contains(id, fmt.Sprintf("/%s/", secgrpType)) { - idx := strings.LastIndex(id, "/") + 1 - if idx <= 0 { - return fmt.Errorf("invalid secgroup %s with id %s", secgrpType, id) - } - secgroup := id[idx:] - switch secgrpType { - case SECGROUP_TYPE_TAG: - tag := strings.ToLower(secgroup) - if !utils.IsInStringArray(tag, instance.Tags.Items) { - instance.Tags.Items = append(instance.Tags.Items, tag) - return instance.host.zone.region.SetResourceTags(instance.SelfLink, instance.Tags) - } - case SECGROUP_TYPE_SERVICE_ACCOUNT: - if len(instance.ServiceAccounts) > 0 { - return fmt.Errorf("instance %s has already set serviceAccount %s", instance.Name, instance.ServiceAccounts[0].Email) - } - return instance.host.zone.region.SetServiceAccount(instance.SelfLink, secgroup) - } - } - } - return fmt.Errorf("unknown secgroup type %s", id) -} - -func (instance *SInstance) GetSecurityGroupIds() ([]string, error) { - secgroupIds := []string{} - isecgroups := []cloudprovider.ICloudSecurityGroup{} - for _, networkinterface := range instance.NetworkInterfaces { - vpc := SVpc{region: instance.host.zone.region} - err := instance.host.zone.region.GetBySelfId(networkinterface.Subnetwork, &vpc) - if err != nil { - return nil, errors.Wrap(err, "GetGlobalNetwork") - } - _isecgroups, err := vpc.GetISecurityGroups() - if err != nil { - return nil, errors.Wrap(err, "vpc.GetISecurityGroups") - } - isecgroups = append(isecgroups, _isecgroups...) - for _, isecgroup := range _isecgroups { - if len(instance.ServiceAccounts) > 0 && isecgroup.GetName() == instance.ServiceAccounts[0].Email { - secgroupIds = append(secgroupIds, isecgroup.GetGlobalId()) - } - gvpcInfo := strings.Split(vpc.Network, "/") - gvpcName := gvpcInfo[len(gvpcInfo)-1] - if isecgroup.GetName() == gvpcName && !strings.Contains(isecgroup.GetGlobalId(), fmt.Sprintf("/%s/", SECGROUP_TYPE_TAG)) { - secgroupIds = append(secgroupIds, isecgroup.GetGlobalId()) - } - } - } - if len(instance.NetworkInterfaces) == 1 { - for _, secgroup := range isecgroups { - if utils.IsInStringArray(secgroup.GetName(), instance.Tags.Items) && strings.Contains(secgroup.GetGlobalId(), fmt.Sprintf("/%s/", SECGROUP_TYPE_TAG)) { - secgroupIds = append(secgroupIds, secgroup.GetGlobalId()) - } - } - } - return secgroupIds, nil -} - -func (instance *SInstance) SetSecurityGroups(ids []string) error { - secgroups := map[string][]string{} - for _, id := range ids { - for _, secgrpType := range []string{SECGROUP_TYPE_TAG, SECGROUP_TYPE_SERVICE_ACCOUNT} { - if strings.Contains(id, fmt.Sprintf("/%s/", secgrpType)) { - idx := strings.LastIndex(id, "/") + 1 - if idx <= 0 { - return fmt.Errorf("invalid secgroup %s with id %s", secgrpType, id) - } - secgroup := id[idx:] - if len(secgroup) == 0 { - return fmt.Errorf("invalid secgroup %s with id %s", secgrpType, id) - } - if _, ok := secgroups[secgrpType]; !ok { - secgroups[secgrpType] = []string{} - } - if !utils.IsInStringArray(secgroup, secgroups[secgrpType]) { - secgroups[secgrpType] = append(secgroups[secgrpType], secgroup) - } - } - } - } - if tags, ok := secgroups[SECGROUP_TYPE_TAG]; ok && len(tags) > 0 { - for _, tag := range tags { - tag = strings.ToLower(tag) - if !utils.IsInStringArray(tag, instance.Tags.Items) { - instance.Tags.Items = append(instance.Tags.Items, tag) - } - } - err := instance.host.zone.region.SetResourceTags(instance.SelfLink, instance.Tags) - if err != nil { - return errors.Wrap(err, "SetTags") - } - } - if serviceAccounts, ok := secgroups[SECGROUP_TYPE_SERVICE_ACCOUNT]; ok && len(serviceAccounts) > 0 { - if len(serviceAccounts) > 1 { - return fmt.Errorf("can not set multi service account for google instance") - } - return instance.host.zone.region.SetServiceAccount(instance.SelfLink, serviceAccounts[0]) - } - return nil -} - -func (instance *SInstance) GetHypervisor() string { - return api.HYPERVISOR_GOOGLE -} - -func (instance *SInstance) StartVM(ctx context.Context) error { - return instance.host.zone.region.StartInstance(instance.SelfLink) -} - -func (instance *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - return instance.host.zone.region.StopInstance(instance.SelfLink) -} - -func (instance *SInstance) DeleteVM(ctx context.Context) error { - return instance.host.zone.region.Delete(instance.SelfLink) -} - -func (instance *SInstance) UpdateVM(ctx context.Context, name string) error { - return cloudprovider.ErrNotSupported -} - -func (instance *SInstance) UpdateUserData(userData string) error { - items := []SMetadataItem{} - for _, item := range instance.Metadata.Items { - if item.Key != METADATA_STARTUP_SCRIPT && item.Key != METADATA_POWER_SHELL && item.Key != METADATA_STARTUP_SCRIPT_POWER_SHELL { - items = append(items, item) - } - } - if len(userData) > 0 { - items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT, Value: userData}) - items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT_POWER_SHELL, Value: userData}) - items = append(items, SMetadataItem{Key: METADATA_POWER_SHELL, Value: userData}) - } - instance.Metadata.Items = items - return instance.host.zone.region.SetMetadata(instance.SelfLink, instance.Metadata) -} - -func (instance *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - diskId, err := instance.host.zone.region.RebuildRoot(instance.Id, desc.ImageId, desc.SysSizeGB) - if err != nil { - return "", errors.Wrap(err, "region.RebuildRoot") - } - return diskId, instance.DeployVM(ctx, "", desc.Account, desc.Password, desc.PublicKey, false, "") -} - -func (instance *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - conf := cloudinit.SCloudConfig{} - user := cloudinit.NewUser(username) - if len(password) > 0 { - user.Password(password) - } - if len(publicKey) > 0 { - user.SshKey(publicKey) - } - if len(password) > 0 || len(publicKey) > 0 { - conf.MergeUser(user) - items := []SMetadataItem{} - instance.Refresh() - for _, item := range instance.Metadata.Items { - if item.Key != METADATA_STARTUP_SCRIPT_POWER_SHELL && item.Key != METADATA_STARTUP_SCRIPT { - items = append(items, item) - } - } - items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT_POWER_SHELL, Value: conf.UserDataPowerShell()}) - items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT, Value: conf.UserDataScript()}) - instance.Metadata.Items = items - return instance.host.zone.region.SetMetadata(instance.SelfLink, instance.Metadata) - } - return nil -} - -func (instance *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - return instance.host.zone.region.ChangeInstanceConfig(instance.SelfLink, instance.host.zone.Name, config.InstanceType, config.Cpu, config.MemoryMB) -} - -func (instance *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (instance *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return instance.host.zone.region.AttachDisk(instance.SelfLink, diskId, false) -} - -func (instance *SInstance) DetachDisk(ctx context.Context, diskId string) error { - _disk, err := instance.host.zone.region.GetDisk(diskId) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return errors.Wrapf(err, "GetDisk(%s)", diskId) - } - for _, disk := range instance.Disks { - if disk.Source == _disk.SelfLink { - return instance.host.zone.region.DetachDisk(instance.SelfLink, disk.DeviceName) - } - } - return nil -} - -func (instance *SInstance) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (instance *SInstance) GetError() error { - return nil -} - -func getDiskInfo(disk string) (cloudprovider.SDiskInfo, error) { - result := cloudprovider.SDiskInfo{} - diskInfo := strings.Split(disk, ":") - for _, d := range diskInfo { - if utils.IsInStringArray(d, []string{api.STORAGE_GOOGLE_PD_STANDARD, api.STORAGE_GOOGLE_PD_SSD, api.STORAGE_GOOGLE_LOCAL_SSD, api.STORAGE_GOOGLE_PD_BALANCED}) { - result.StorageType = d - } else if memSize, err := fileutils.GetSizeMb(d, 'M', 1024); err == nil { - result.SizeGB = memSize >> 10 - } else { - result.Name = d - } - } - if len(result.StorageType) == 0 { - result.StorageType = api.STORAGE_GOOGLE_PD_STANDARD - } - - if result.SizeGB == 0 { - return result, fmt.Errorf("Missing disk size") - } - return result, nil -} - -func (region *SRegion) CreateInstance(zone, name, desc, instanceType string, cpu, memoryMb int, networkId string, ipAddr, imageId string, disks []string) (*SInstance, error) { - if len(instanceType) == 0 && (cpu == 0 || memoryMb == 0) { - return nil, fmt.Errorf("Missing instanceType or cpu &memory info") - } - if len(disks) == 0 { - return nil, fmt.Errorf("Missing disk info") - } - sysDisk, err := getDiskInfo(disks[0]) - if err != nil { - return nil, errors.Wrap(err, "getDiskInfo.sys") - } - dataDisks := []cloudprovider.SDiskInfo{} - for _, d := range disks[1:] { - dataDisk, err := getDiskInfo(d) - if err != nil { - return nil, errors.Wrapf(err, "getDiskInfo(%s)", d) - } - dataDisks = append(dataDisks, dataDisk) - } - conf := &cloudprovider.SManagedVMCreateConfig{ - Name: name, - Description: desc, - ExternalImageId: imageId, - Cpu: cpu, - MemoryMB: memoryMb, - ExternalNetworkId: networkId, - IpAddr: ipAddr, - SysDisk: sysDisk, - DataDisks: dataDisks, - } - return region._createVM(zone, conf) -} - -func (region *SRegion) getSecgroupByIds(ids []string) (map[string][]string, error) { - secgroups := map[string][]string{} - for _, id := range ids { - for _, secgrpType := range []string{SECGROUP_TYPE_TAG, SECGROUP_TYPE_SERVICE_ACCOUNT} { - if strings.Contains(id, fmt.Sprintf("/%s/", secgrpType)) { - idx := strings.LastIndex(id, "/") + 1 - if idx <= 0 { - return nil, fmt.Errorf("invalid secgroup %s for %s", id, secgrpType) - } - secgroup := id[idx:] - if len(secgroup) == 0 { - return nil, fmt.Errorf("invalid secgroup %s for %s", id, secgrpType) - } - if _, ok := secgroups[secgrpType]; !ok { - secgroups[secgrpType] = []string{} - } - if !utils.IsInStringArray(secgroup, secgroups[secgrpType]) { - secgroups[secgrpType] = append(secgroups[secgrpType], secgroup) - } - } - } - } - return secgroups, nil -} - -func (region *SRegion) _createVM(zone string, desc *cloudprovider.SManagedVMCreateConfig) (*SInstance, error) { - vpc, err := region.GetVpc(desc.ExternalNetworkId) - if err != nil { - return nil, errors.Wrap(err, "region.GetNetwork") - } - secgroups, err := region.getSecgroupByIds(desc.ExternalSecgroupIds) - if err != nil { - return nil, errors.Wrap(err, "getSecgroupByIds") - } - serviceAccounts, ok := secgroups[SECGROUP_TYPE_SERVICE_ACCOUNT] - if ok && len(serviceAccounts) > 1 { - return nil, fmt.Errorf("Security groups are distributed across multiple service accounts") - } - if len(desc.InstanceType) == 0 { - desc.InstanceType = fmt.Sprintf("custom-%d-%d", desc.Cpu, desc.MemoryMB) - } - disks := []map[string]interface{}{} - if len(desc.SysDisk.Name) == 0 { - desc.SysDisk.Name = fmt.Sprintf("vdisk-%s-%d", desc.Name, time.Now().UnixNano()) - } - nameConv := func(name string) string { - name = strings.Replace(name, "_", "-", -1) - name = pinyinutils.Text2Pinyin(name) - return strings.ToLower(name) - } - disks = append(disks, map[string]interface{}{ - "boot": true, - "initializeParams": map[string]interface{}{ - "diskName": nameConv(desc.SysDisk.Name), - "sourceImage": desc.ExternalImageId, - "diskSizeGb": desc.SysDisk.SizeGB, - "diskType": fmt.Sprintf("zones/%s/diskTypes/%s", zone, desc.SysDisk.StorageType), - }, - "autoDelete": true, - }) - for _, disk := range desc.DataDisks { - if len(disk.Name) == 0 { - disk.Name = fmt.Sprintf("vdisk-%s-%d", desc.Name, time.Now().UnixNano()) - } - disks = append(disks, map[string]interface{}{ - "boot": false, - "initializeParams": map[string]interface{}{ - "diskName": nameConv(disk.Name), - "diskSizeGb": disk.SizeGB, - "diskType": fmt.Sprintf("zones/%s/diskTypes/%s", zone, disk.StorageType), - }, - "autoDelete": true, - }) - } - networkInterface := map[string]string{ - "network": vpc.Network, - "subnetwork": vpc.SelfLink, - } - if len(desc.IpAddr) > 0 { - networkInterface["networkIp"] = desc.IpAddr - } - params := map[string]interface{}{ - "name": desc.NameEn, - "description": desc.Description, - "machineType": fmt.Sprintf("zones/%s/machineTypes/%s", zone, desc.InstanceType), - "networkInterfaces": []map[string]string{ - networkInterface, - }, - "disks": disks, - } - - labels := map[string]string{} - for k, v := range desc.Tags { - labels[encode.EncodeGoogleLabel(k)] = encode.EncodeGoogleLabel(v) - } - - if len(labels) > 0 { - params["labels"] = labels - } - - if tags, ok := secgroups[SECGROUP_TYPE_TAG]; ok && len(tags) > 0 { - for i := range tags { - tags[i] = strings.ToLower(tags[i]) - } - params["tags"] = map[string][]string{ - "items": tags, - } - } - if len(desc.UserData) > 0 { - params["metadata"] = map[string]interface{}{ - "items": []struct { - Key string - Value string - }{ - { - Key: METADATA_STARTUP_SCRIPT, - Value: desc.UserData, - }, - { - Key: METADATA_POWER_SHELL, - Value: desc.UserData, - }, - }, - } - } - if len(serviceAccounts) > 0 { - params["serviceAccounts"] = []struct { - Email string - Scopes []string - }{ - { - Email: serviceAccounts[0], - Scopes: []string{ - "https://www.googleapis.com/auth/devstorage.read_only", - "https://www.googleapis.com/auth/logging.write", - "https://www.googleapis.com/auth/monitoring.write", - "https://www.googleapis.com/auth/servicecontrol", - "https://www.googleapis.com/auth/service.management.readonly", - "https://www.googleapis.com/auth/trace.append", - }, - }, - } - } - log.Debugf("create google instance params: %s", jsonutils.Marshal(params).String()) - instance := &SInstance{} - resource := fmt.Sprintf("zones/%s/instances", zone) - err = region.Insert(resource, jsonutils.Marshal(params), instance) - if err != nil { - return nil, err - } - return instance, nil -} - -func (region *SRegion) StartInstance(id string) error { - params := map[string]string{} - return region.Do(id, "start", nil, jsonutils.Marshal(params)) -} - -func (region *SRegion) StopInstance(id string) error { - params := map[string]string{} - return region.Do(id, "stop", nil, jsonutils.Marshal(params)) -} - -func (region *SRegion) ResetInstance(id string) error { - params := map[string]string{} - return region.Do(id, "reset", nil, jsonutils.Marshal(params)) -} - -func (region *SRegion) DetachDisk(instanceId, deviceName string) error { - body := map[string]string{} - params := map[string]string{"deviceName": deviceName} - return region.Do(instanceId, "detachDisk", params, jsonutils.Marshal(body)) -} - -func (instance *SInstance) GetSerialOutput(port int) (string, error) { - return instance.host.zone.region.GetSerialPortOutput(instance.SelfLink, port) -} - -func (region *SRegion) GetSerialPortOutput(id string, port int) (string, error) { - _content, content, next := "", "", 0 - var err error = nil - for { - _content, next, err = region.getSerialPortOutput(id, port, next) - if err != nil { - return content, err - } - content += _content - if len(_content) == 0 { - break - } - } - return content, nil -} - -func (region *SRegion) getSerialPortOutput(id string, port int, start int) (string, int, error) { - resource := fmt.Sprintf("%s/serialPort?port=%d&start=%d", id, port, start) - result := struct { - Contents string - Start int - Next int - }{} - err := region.GetBySelfId(resource, &result) - if err != nil { - return "", result.Next, errors.Wrap(err, "") - } - return result.Contents, result.Next, nil -} - -func (self *SRegion) AttachDisk(instanceId, diskId string, boot bool) error { - disk, err := self.GetDisk(diskId) - if err != nil { - return errors.Wrapf(err, "GetDisk(%s)", diskId) - } - body := map[string]interface{}{ - "source": disk.SelfLink, - "boot": boot, - } - if boot { - body["autoDelete"] = true - } - params := map[string]string{} - return self.Do(instanceId, "attachDisk", params, jsonutils.Marshal(body)) -} - -func (region *SRegion) ChangeInstanceConfig(id string, zone string, instanceType string, cpu int, memoryMb int) error { - if len(instanceType) == 0 { - instanceType = fmt.Sprintf("custom-%d-%d", cpu, memoryMb) - } - params := map[string]string{ - "machineType": fmt.Sprintf("zones/%s/machineTypes/%s", zone, instanceType), - } - return region.Do(id, "setMachineType", nil, jsonutils.Marshal(params)) -} - -func (region *SRegion) SetMetadata(id string, metadata SMetadata) error { - return region.Do(id, "setMetadata", nil, jsonutils.Marshal(metadata)) -} - -func (region *SRegion) SetResourceTags(id string, tags SInstanceTag) error { - return region.Do(id, "setTags", nil, jsonutils.Marshal(tags)) -} - -func (region *SRegion) SetServiceAccount(id string, email string) error { - body := map[string]interface{}{ - "email": email, - "scopes": []string{ - "https://www.googleapis.com/auth/devstorage.read_only", - "https://www.googleapis.com/auth/logging.write", - "https://www.googleapis.com/auth/monitoring.write", - "https://www.googleapis.com/auth/servicecontrol", - "https://www.googleapis.com/auth/service.management.readonly", - "https://www.googleapis.com/auth/trace.append", - }, - } - return region.Do(id, "setsetServiceAccount", nil, jsonutils.Marshal(body)) -} - -func (region *SRegion) RebuildRoot(instanceId string, imageId string, sysDiskSizeGb int) (string, error) { - oldDisk, diskType, deviceName := "", api.STORAGE_GOOGLE_PD_STANDARD, "" - instance, err := region.GetInstance(instanceId) - if err != nil { - return "", errors.Wrap(err, "region.GetInstance") - } - for _, disk := range instance.Disks { - if disk.Boot { - oldDisk = disk.Source - deviceName = disk.DeviceName - break - } - } - - if len(oldDisk) > 0 { - disk := &SDisk{} - err := region.GetBySelfId(oldDisk, disk) - if err != nil { - return "", errors.Wrap(err, "region.GetDisk") - } - diskType = disk.Type - if sysDiskSizeGb == 0 { - sysDiskSizeGb = disk.SizeGB - } - } - - zone, err := region.GetZone(instance.Zone) - if err != nil { - return "", errors.Wrap(err, "region.GetZone") - } - - diskName := fmt.Sprintf("vdisk-%s-%d", instance.Name, time.Now().UnixNano()) - disk, err := region.CreateDisk(diskName, sysDiskSizeGb, zone.Name, diskType, imageId, "create for replace instance system disk") - if err != nil { - return "", errors.Wrap(err, "region.CreateDisk.systemDisk") - } - - if len(deviceName) > 0 { - err = region.DetachDisk(instance.SelfLink, deviceName) - if err != nil { - defer region.Delete(disk.SelfLink) - return "", errors.Wrap(err, "region.DetachDisk") - } - } - - err = region.AttachDisk(instance.SelfLink, disk.Id, true) - if err != nil { - if len(oldDisk) > 0 { - defer region.AttachDisk(instance.SelfLink, oldDisk, true) - } - defer region.Delete(disk.SelfLink) - return "", errors.Wrap(err, "region.AttachDisk.newSystemDisk") - } - - if len(oldDisk) > 0 { - defer region.Delete(oldDisk) - } - return disk.GetGlobalId(), nil -} - -func (self *SRegion) SaveImage(diskId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { - params := map[string]interface{}{ - "name": opts.Name, - "description": opts.Notes, - "sourceDisk": diskId, - } - image := &SImage{} - err := self.Insert("global/images", jsonutils.Marshal(params), image) - if err != nil { - return nil, errors.Wrapf(err, "Insert") - } - image.storagecache = self.getStoragecache() - return image, nil -} - -func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { - for i := range self.Disks { - if self.Disks[0].Index == 0 { - image, err := self.host.zone.region.SaveImage(self.Disks[i].Source, opts) - if err != nil { - return nil, errors.Wrapf(err, "SaveImage") - } - return image, nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "no valid system disk found") -} - -func (region *SRegion) SetLabels(id string, _labels map[string]string, labelFingerprint string) error { - labels := map[string]string{} - for k, v := range _labels { - labels[encode.EncodeGoogleLabel(k)] = encode.EncodeGoogleLabel(v) - } - params := map[string]interface{}{ - "labels": labels, - "labelFingerprint": labelFingerprint, - } - err := region.Do(id, "setLabels", nil, jsonutils.Marshal(params)) - if err != nil { - return errors.Wrapf(err, `region.Do(%s, "setLabels", nil, %s)`, id, jsonutils.Marshal(params).String()) - } - return nil -} - -func (self *SInstance) SetTags(tags map[string]string, replace bool) error { - if !replace { - oldTags, _ := self.GetTags() - for k, v := range oldTags { - if _, ok := tags[k]; !ok { - tags[k] = v - } - } - } - err := self.Refresh() - if err != nil { - return errors.Wrap(err, "self.Refresh()") - } - err = self.host.zone.region.SetLabels(self.SelfLink, tags, self.LabelFingerprint) - if err != nil { - return errors.Wrapf(err, ` self.host.zone.region.SsetLabels()`) - } - return nil -} diff --git a/pkg/multicloud/google/instancenic.go b/pkg/multicloud/google/instancenic.go deleted file mode 100644 index 5001d018f8..0000000000 --- a/pkg/multicloud/google/instancenic.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "yunion.io/x/pkg/util/netutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SNetworkInterface struct { - instance *SInstance - - Network string - Subnetwork string - NetworkIP string - Name string - AccessConfigs []AccessConfig - Fingerprint string - Kind string - - cloudprovider.DummyICloudNic -} - -func (nic *SNetworkInterface) GetId() string { - return "" -} - -func (nic *SNetworkInterface) GetIP() string { - return nic.NetworkIP -} - -func (nic *SNetworkInterface) GetMAC() string { - ip, _ := netutils.NewIPV4Addr(nic.NetworkIP) - return ip.ToMac("42:01:") -} - -func (nic *SNetworkInterface) GetDriver() string { - return "virtio" -} - -func (nic *SNetworkInterface) InClassicNetwork() bool { - return false -} - -func (nic *SNetworkInterface) GetINetworkId() string { - vpc := &SVpc{region: nic.instance.host.zone.region} - err := nic.instance.host.zone.region.GetBySelfId(nic.Subnetwork, vpc) - if err != nil { - return "" - } - return vpc.Id -} diff --git a/pkg/multicloud/google/latitude_and_longitude.go b/pkg/multicloud/google/latitude_and_longitude.go deleted file mode 100644 index ddaee27de9..0000000000 --- a/pkg/multicloud/google/latitude_and_longitude.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ - "asia-east1": api.RegionTaiwan, - "asia-east2": api.RegionHongkong, - "asia-northeast1": api.RegionTokyo, - "asia-northeast2": api.RegionOsaka, - "asia-northeast3": api.RegionSeoul, - "asia-south1": api.RegionMumbai, - "asia-south2": api.RegionDelhi, - "asia-southeast1": api.RegionSingapore, - "asia-southeast2": api.RegionJakarta, - "australia-southeast1": api.RegionSydney, - "australia-southeast2": api.RegionMelbourne, - - "europe-north1": api.RegionFinland, - "europe-west1": api.RegionBelgium, - "europe-west2": api.RegionLondon, - "europe-west3": api.RegionFrankfurt, - "europe-west4": api.RegionHolland, - "europe-west6": api.RegionZurich, - "europe-central2": api.RegionWarsaw, - - "northamerica-northeast1": api.RegionMontreal, - "northamerica-northeast2": api.RegionToronto, - "southamerica-east1": api.RegionSaoPaulo, - "us-central1": api.RegionIowa, - "us-east1": api.RegionCarolina, - "us-east4": api.RegionNothVirginia, - "us-west1": api.RegionOregon, - "us-west2": api.RegionLosAngeles, - "us-west3": api.RegionSaltLakeCity, - "us-west4": api.RegionLasVegas, - "southamerica-west1": api.RegionSantiago, -} - -var RegionNames = map[string]string{ - "asia-east1": "台湾", - "asia-east2": "香港", - "asia-northeast1": "东京", - "asia-northeast2": "大阪", - "asia-northeast3": "首尔", - "asia-south1": "孟买", - "asia-south2": "德里", - "asia-southeast1": "新加坡", - "asia-southeast2": "雅加达", - "australia-southeast1": "悉尼", - "australia-southeast2": "墨尔本", - - "europe-north1": "芬兰", - "europe-west1": "比利时", - "europe-west2": "伦敦", - "europe-west3": "法兰克福", - "europe-west4": "荷兰", - "europe-west6": "苏黎世", - "europe-central2": "华沙", - - "northamerica-northeast1": "蒙特利尔", - "northamerica-northeast2": "多伦多", - "southamerica-east1": "圣保罗", - "southamerica-west1": "圣地亚哥", - "us-central1": "爱荷华", - "us-east1": "南卡罗来纳州", - "us-east4": "北弗吉尼亚", - "us-west1": "俄勒冈州", - "us-west2": "洛杉矶", - "us-west3": "盐湖城", - "us-west4": "拉斯维加斯", - - // Multi-region - "us": "美国的多区域", - "eu": "欧盟的多区域", - "asia": "亚洲的多区域", - - // Dual-region - "nam4": "爱荷华和南卡罗来纳", - "eur4": "荷兰和芬兰", -} diff --git a/pkg/multicloud/google/loadbalancer.go b/pkg/multicloud/google/loadbalancer.go deleted file mode 100644 index a1c3628dce..0000000000 --- a/pkg/multicloud/google/loadbalancer.go +++ /dev/null @@ -1,480 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -// 全球负载均衡 https://cloud.google.com/compute/docs/reference/rest/v1/globalAddresses/list -// 区域负载均衡 https://cloud.google.com/compute/docs/reference/rest/v1/addresses -// https://cloud.google.com/compute/docs/reference/rest/v1/targetHttpProxies/get -// https://cloud.google.com/compute/docs/reference/rest/v1/targetGrpcProxies/get -// https://cloud.google.com/compute/docs/reference/rest/v1/targetHttpsProxies/get -// https://cloud.google.com/compute/docs/reference/rest/v1/targetSslProxies/get -// https://cloud.google.com/compute/docs/reference/rest/v1/targetTcpProxies/get - -type SLoadbalancer struct { - SResourceBase - region *SRegion - urlMap *SUrlMap // http & https LB - backendServices []SBackendServices // tcp & udp LB. 或者 http & https 后端 - instanceGroups []SInstanceGroup - healthChecks []HealthChecks - - forwardRules []SForwardingRule // 服务IP地址 - isHttpLb bool // 标记是否为http/https lb -} - -func (self *SLoadbalancer) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancer) Refresh() error { - lb, err := self.region.GetLoadbalancer(self.GetGlobalId()) - if err != nil { - return errors.Wrap(err, "GetLoadbalancer") - } - - err = jsonutils.Update(self, &lb) - if err != nil { - return errors.Wrap(err, "Refresh.Update") - } - - self.healthChecks = nil - self.instanceGroups = nil - self.forwardRules = nil - if self.isHttpLb { - bss, err := self.GetBackendServices() - if err != nil { - return errors.Wrap(err, "GetForwardingRules") - } - self.backendServices = bss - } - return nil -} - -func (self *SLoadbalancer) IsEmulated() bool { - return true -} - -func (self *SLoadbalancer) GetSysTags() map[string]string { - frs, err := self.GetForwardingRules() - if err != nil { - return nil - } - - ips := []string{} - for i := range frs { - if len(frs[i].IPAddress) > 0 { - ips = append(ips, frs[i].IPAddress) - } - } - data := map[string]string{} - data["FrontendIPs"] = strings.Join(ips, ",") - return data -} - -func (self *SLoadbalancer) GetTags() (map[string]string, error) { - return map[string]string{}, nil -} - -func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetCreatedAt() time.Time { - return time.Time{} -} - -func (self *SLoadbalancer) GetProjectId() string { - return self.region.GetProjectId() -} - -/* -对应forwardingRules地址,存在多个前端IP的情况下,只展示按拉丁字母排序最前的一个地址。其他地址需要到详情中查看 -External -Internal -InternalManaged -InternalSelfManaged -Invalid -UndefinedLoadBalancingScheme -*/ -func (self *SLoadbalancer) GetAddress() string { - frs, err := self.GetForwardingRules() - if err != nil { - log.Errorf("GetAddress.GetForwardingRules %s", err) - } - - for i := range frs { - sche := strings.ToLower(frs[i].LoadBalancingScheme) - if !utils.IsInStringArray(sche, []string{"invalid", "undefinedloadbalancingscheme"}) { - return frs[i].IPAddress - } - } - - return "" -} - -func (self *SLoadbalancer) GetAddressType() string { - frs, err := self.GetForwardingRules() - if err != nil { - return api.LB_ADDR_TYPE_INTRANET - } - - for i := range frs { - sche := strings.ToLower(frs[i].LoadBalancingScheme) - if !utils.IsInStringArray(sche, []string{"invalid", "undefinedloadbalancingscheme"}) { - if sche == "external" { - return api.LB_ADDR_TYPE_INTERNET - } else { - return api.LB_ADDR_TYPE_INTRANET - } - } - } - - return api.LB_ADDR_TYPE_INTERNET -} - -func (self *SLoadbalancer) GetNetworkType() string { - return api.LB_NETWORK_TYPE_VPC -} - -func (self *SLoadbalancer) GetNetworkIds() []string { - igs, err := self.GetInstanceGroups() - if err != nil { - log.Errorf("GetInstanceGroups %s", err) - return nil - } - - selfLinks := make([]string, 0) - networkIds := make([]string, 0) - for i := range igs { - if utils.IsInStringArray(igs[i].Subnetwork, selfLinks) { - selfLinks = append(selfLinks, igs[i].Subnetwork) - network := SResourceBase{ - Name: "", - SelfLink: igs[i].Network, - } - networkIds = append(networkIds, network.GetGlobalId()) - } - } - - return networkIds -} - -func (self *SLoadbalancer) GetVpcId() string { - networkIds := self.GetNetworkIds() - if len(networkIds) == 0 { - return "" - } - if len(networkIds) >= 1 { - vpc, err := self.region.GetVpc(networkIds[0]) - if err == nil && vpc != nil { - return vpc.GetGlobalId() - } - } - return "" -} - -func (self *SLoadbalancer) GetZoneId() string { - igs, err := self.GetInstanceGroups() - if err != nil { - log.Errorf("GetInstanceGroups %s", err) - return "" - } - - for i := range igs { - if len(igs[i].Zone) > 0 { - zone := SResourceBase{ - Name: "", - SelfLink: igs[i].Zone, - } - - return zone.GetGlobalId() - } - } - - return "" -} - -func (self *SLoadbalancer) GetZone1Id() string { - return "" -} - -func (self *SLoadbalancer) GetLoadbalancerSpec() string { - if self.isHttpLb { - return "regional_http_lb" - } - - return fmt.Sprintf("regional_%s", strings.ToLower(self.backendServices[0].Protocol)) -} - -func (self *SLoadbalancer) GetChargeType() string { - return api.LB_CHARGE_TYPE_BY_TRAFFIC -} - -func (self *SLoadbalancer) GetEgressMbps() int { - return 0 -} - -func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { - frs, err := self.GetForwardingRules() - if err != nil { - log.Errorf("GetAddress.GetForwardingRules %s", err) - } - - for i := range frs { - if strings.ToLower(frs[i].LoadBalancingScheme) == "external" { - eips, err := self.region.GetEips(frs[i].IPAddress, 0, "") - if err != nil { - log.Errorf("GetEips %s", err) - } - - if len(eips) > 0 { - return &eips[0], nil - } - } - } - - return nil, nil -} - -func (self *SLoadbalancer) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SLoadbalancer) Start() error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) Stop() error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - lbls, err := self.GetLoadbalancerListeners() - if err != nil { - return nil, errors.Wrap(err, "GetLoadbalancerListeners") - } - - ilbls := make([]cloudprovider.ICloudLoadbalancerListener, len(lbls)) - for i := range lbls { - ilbls[i] = &lbls[i] - } - - return ilbls, nil -} - -func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - lbbgs, err := self.GetLoadbalancerBackendGroups() - if err != nil { - return nil, errors.Wrap(err, "GetLoadbalancerBackendGroups") - } - - ilbbgs := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(lbbgs)) - for i := range lbbgs { - ilbbgs[i] = &lbbgs[i] - } - - return ilbbgs, nil -} - -func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - lbbgs, err := self.GetLoadbalancerBackendGroups() - if err != nil { - return nil, errors.Wrap(err, "GetLoadbalancerBackendGroups") - } - - for i := range lbbgs { - if lbbgs[i].GetGlobalId() == groupId { - return &lbbgs[i], nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { - lbls, err := self.GetLoadbalancerListeners() - if err != nil { - return nil, errors.Wrap(err, "GetLoadbalancerBackendGroups") - } - - for i := range lbls { - if lbls[i].GetGlobalId() == listenerId { - return &lbls[i], nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -// GET https://compute.googleapis.com/compute/v1/projects/{project}/aggregated/targetHttpProxies 前端监听 -// tcp lb backend type: backend service -func (self *SRegion) GetRegionalTcpLoadbalancers() ([]SLoadbalancer, error) { - bss, err := self.GetRegionalBackendServices("protocol eq TCP") - if err != nil { - return nil, errors.Wrap(err, "GetRegionalBackendServices") - } - - lbs := make([]SLoadbalancer, len(bss)) - for i := range bss { - lbs[i] = SLoadbalancer{ - region: self, - SResourceBase: SResourceBase{ - Name: bss[i].Name, - SelfLink: bss[i].SelfLink, - }, - urlMap: nil, - backendServices: []SBackendServices{bss[i]}, - forwardRules: nil, - } - } - - return lbs, nil -} - -// udp lb backend type: backend service -func (self *SRegion) GetRegionalUdpLoadbalancers() ([]SLoadbalancer, error) { - bss, err := self.GetRegionalBackendServices("protocol eq UDP") - if err != nil { - return nil, errors.Wrap(err, "GetRegionalBackendServices") - } - - lbs := make([]SLoadbalancer, len(bss)) - for i := range bss { - lbs[i] = SLoadbalancer{ - region: self, - SResourceBase: SResourceBase{ - Name: bss[i].Name, - SelfLink: bss[i].SelfLink, - }, - urlMap: nil, - backendServices: []SBackendServices{bss[i]}, - forwardRules: nil, - } - } - - return lbs, nil -} - -// http&https lb: urlmaps -func (self *SRegion) GetRegionalHTTPLoadbalancers() ([]SLoadbalancer, error) { - ums, err := self.GetRegionalUrlMaps("") - if err != nil { - return nil, errors.Wrap(err, "GetRegionalUrlMaps") - } - - lbs := make([]SLoadbalancer, len(ums)) - for i := range ums { - lbs[i] = SLoadbalancer{ - region: self, - SResourceBase: SResourceBase{ - Name: ums[i].Name, - SelfLink: ums[i].SelfLink, - }, - urlMap: &ums[i], - backendServices: nil, - forwardRules: nil, - isHttpLb: true, - } - } - - return lbs, nil -} - -func (self *SRegion) GetRegionalLoadbalancers() ([]SLoadbalancer, error) { - lbs := make([]SLoadbalancer, 0) - funcs := []func() ([]SLoadbalancer, error){self.GetRegionalHTTPLoadbalancers, self.GetRegionalTcpLoadbalancers, self.GetRegionalUdpLoadbalancers} - for i := range funcs { - _lbs, err := funcs[i]() - if err != nil { - return nil, errors.Wrap(err, "GetRegionalLoadbalancers") - } - lbs = append(lbs, _lbs...) - } - - return lbs, nil -} - -func (self *SRegion) GetLoadbalancer(resourceId string) (SLoadbalancer, error) { - lb := SLoadbalancer{} - var err error - if strings.Contains(resourceId, "/urlMaps/") { - ret := SUrlMap{} - err = self.GetBySelfId(resourceId, &ret) - lb.isHttpLb = true - lb.urlMap = &ret - lb.SResourceBase = SResourceBase{ - Name: ret.Name, - SelfLink: ret.SelfLink, - } - } else { - ret := SBackendServices{} - err = self.GetBySelfId(resourceId, &ret) - lb.backendServices = []SBackendServices{ret} - lb.SResourceBase = SResourceBase{ - Name: ret.Name, - SelfLink: ret.SelfLink, - } - } - - if err != nil { - return lb, errors.Wrapf(err, "get") - } - - lb.region = self - return lb, nil -} - -func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - lbs, err := self.GetRegionalLoadbalancers() - if err != nil { - return nil, errors.Wrap(err, "GetRegionalLoadbalancers") - } - ilbs := []cloudprovider.ICloudLoadbalancer{} - for i := range lbs { - ilbs = append(ilbs, &lbs[i]) - } - return ilbs, nil -} - -func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { - lb, err := self.GetLoadbalancer(loadbalancerId) - if err != nil { - return nil, errors.Wrap(err, "GetLoadbalancer") - } - return &lb, nil -} diff --git a/pkg/multicloud/google/loadbalancer_backend.go b/pkg/multicloud/google/loadbalancer_backend.go deleted file mode 100644 index 337de0392e..0000000000 --- a/pkg/multicloud/google/loadbalancer_backend.go +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SLoadbalancerBackend struct { - lbbg *SLoadBalancerBackendGroup - - backendService SBackendServices // - instanceGroup SInstanceGroup // 实例组 - Backend SInstanceGroupInstance // backend - - Port int `json:"port"` -} - -func (self *SLoadbalancerBackend) GetId() string { - return fmt.Sprintf("%s::%s::%s::%d", self.lbbg.GetGlobalId(), self.instanceGroup.GetGlobalId(), self.GetBackendId(), self.Port) -} - -func (self *SLoadbalancerBackend) GetName() string { - segs := strings.Split(self.Backend.Instance, "/") - name := "" - if len(segs) > 0 { - name = segs[len(segs)-1] - } - return fmt.Sprintf("%s::%s::%d", self.instanceGroup.GetName(), name, self.Port) -} - -func (self *SLoadbalancerBackend) GetGlobalId() string { - return self.GetId() -} - -func (self *SLoadbalancerBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancerBackend) Refresh() error { - return nil -} - -func (self *SLoadbalancerBackend) IsEmulated() bool { - return true -} - -func (self *SLoadbalancerBackend) GetSysTags() map[string]string { - return nil -} - -func (self *SLoadbalancerBackend) GetTags() (map[string]string, error) { - return nil, nil -} - -func (self *SLoadbalancerBackend) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancerBackend) GetProjectId() string { - return self.lbbg.GetProjectId() -} - -func (self *SLoadbalancerBackend) GetWeight() int { - return 0 -} - -func (self *SLoadbalancerBackend) GetPort() int { - return self.Port -} - -func (self *SLoadbalancerBackend) GetCreatedAt() time.Time { - return time.Time{} -} - -func (self *SLoadbalancerBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (self *SLoadbalancerBackend) GetBackendRole() string { - return api.LB_BACKEND_ROLE_DEFAULT -} - -func (self *SLoadbalancerBackend) GetBackendId() string { - r := SResourceBase{ - Name: "", - SelfLink: self.Backend.Instance, - } - return r.GetGlobalId() -} - -func (self *SLoadbalancerBackend) GetIpAddress() string { - return "" -} - -func (self *SLoadbalancerBackend) SyncConf(ctx context.Context, port, weight int) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadBalancerBackendGroup) GetLoadbalancerBackends() ([]SLoadbalancerBackend, error) { - if self.backends != nil { - return self.backends, nil - } - - _igs, err := self.lb.GetInstanceGroupsMap() - if err != nil { - return nil, errors.Wrap(err, "GetInstanceGroupsMap") - } - - igs := make([]SInstanceGroup, 0) - for i := range self.backendService.Backends { - backend := self.backendService.Backends[i] - if v, ok := _igs[backend.Group]; ok { - igs = append(igs, v) - } - } - - ret := make([]SLoadbalancerBackend, 0) - for i := range igs { - ig := igs[i] - // http lb - if self.lb.isHttpLb { - for j := range ig.NamedPorts { - np := ig.NamedPorts[j] - if np.Name != self.backendService.PortName { - continue - } - - bs, err := ig.GetInstances() - if err != nil { - return nil, errors.Wrap(err, "GetInstances") - } - - for n := range bs { - backend := SLoadbalancerBackend{ - lbbg: self, - backendService: self.backendService, - instanceGroup: ig, - Backend: bs[n], - Port: int(np.Port), - } - - ret = append(ret, backend) - } - } - } else { - // tcp & udp lb - bs, err := ig.GetInstances() - if err != nil { - return nil, errors.Wrap(err, "GetInstances") - } - - frs, err := self.lb.GetForwardingRules() - if err != nil { - return nil, errors.Wrap(err, "GetForwardingRules") - } - - for m := range frs { - fr := frs[m] - for p := range fr.Ports { - port, _ := strconv.Atoi(fr.Ports[p]) - if port <= 0 { - continue - } - - for n := range bs { - backend := SLoadbalancerBackend{ - lbbg: self, - backendService: self.backendService, - instanceGroup: ig, - Backend: bs[n], - Port: port, - } - - ret = append(ret, backend) - } - } - } - } - } - - self.backends = ret - return ret, nil -} diff --git a/pkg/multicloud/google/loadbalancer_backendgroup.go b/pkg/multicloud/google/loadbalancer_backendgroup.go deleted file mode 100644 index 387841bf36..0000000000 --- a/pkg/multicloud/google/loadbalancer_backendgroup.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "context" - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SLoadBalancerBackendGroup struct { - lb *SLoadbalancer - backends []SLoadbalancerBackend - - backendService SBackendServices // - - Id string `json:"id"` - Name string `json:"name"` -} - -func (self *SLoadBalancerBackendGroup) GetId() string { - return self.Id -} - -func (self *SLoadBalancerBackendGroup) GetName() string { - return self.Name -} - -func (self *SLoadBalancerBackendGroup) GetGlobalId() string { - return self.backendService.GetGlobalId() -} - -func (self *SLoadBalancerBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadBalancerBackendGroup) Refresh() error { - return nil -} - -func (self *SLoadBalancerBackendGroup) IsEmulated() bool { - return true -} - -func (self *SLoadBalancerBackendGroup) GetSysTags() map[string]string { - return nil -} - -func (self *SLoadBalancerBackendGroup) GetTags() (map[string]string, error) { - return nil, nil -} - -func (self *SLoadBalancerBackendGroup) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadBalancerBackendGroup) GetProjectId() string { - return self.lb.GetProjectId() -} - -func (self *SLoadBalancerBackendGroup) IsDefault() bool { - return false -} - -func (self *SLoadBalancerBackendGroup) GetCreatedAt() time.Time { - return time.Time{} -} - -func (self *SLoadBalancerBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_NORMAL -} - -func (self *SLoadBalancerBackendGroup) GetLoadbalancerId() string { - return self.lb.GetGlobalId() -} - -func (self *SLoadBalancerBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := self.GetLoadbalancerBackends() - if err != nil { - return nil, errors.Wrap(err, "GetLoadbalancerBackends") - } - - ibackends := make([]cloudprovider.ICloudLoadbalancerBackend, len(backends)) - for i := range backends { - ibackends[i] = &backends[i] - } - - return ibackends, nil -} - -func (self *SLoadBalancerBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := self.GetLoadbalancerBackends() - if err != nil { - return nil, errors.Wrap(err, "GetLoadbalancerBackends") - } - - for i := range backends { - if backends[i].GetGlobalId() == backendId { - return &backends[i], nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SLoadBalancerBackendGroup) GetProtocolType() string { - return "" -} - -func (self *SLoadBalancerBackendGroup) GetScheduler() string { - return "" -} - -func (self *SLoadBalancerBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - return nil, nil -} - -func (self *SLoadBalancerBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - return nil, nil -} - -func (self *SLoadBalancerBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SLoadBalancerBackendGroup) RemoveBackendServer(serverId string, weight int, port int) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadBalancerBackendGroup) Delete(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadBalancerBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetLoadbalancerBackendGroups() ([]SLoadBalancerBackendGroup, error) { - bss, err := self.GetBackendServices() - if err != nil { - return nil, errors.Wrap(err, "GetBackendServices") - } - - ret := make([]SLoadBalancerBackendGroup, 0) - for i := range bss { - group := SLoadBalancerBackendGroup{ - lb: self, - backendService: bss[i], - Id: bss[i].GetId(), - Name: bss[i].GetName(), - } - - ret = append(ret, group) - } - - return ret, nil -} diff --git a/pkg/multicloud/google/loadbalancer_cert.go b/pkg/multicloud/google/loadbalancer_cert.go deleted file mode 100644 index d1926dd0fa..0000000000 --- a/pkg/multicloud/google/loadbalancer_cert.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "crypto/sha256" - "crypto/x509" - "encoding/hex" - "encoding/pem" - "strings" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SLoadbalancerCertificate struct { - region *SRegion - SResourceBase - cert *x509.Certificate - - ID string `json:"id"` - CreationTimestamp string `json:"creationTimestamp"` - Certificate string `json:"certificate"` - SelfManaged SelfManaged `json:"selfManaged"` - Type string `json:"type"` - ExpireTime time.Time `json:"expireTime"` - Region string `json:"region"` - Kind string `json:"kind"` -} - -type SelfManaged struct { - Certificate string `json:"certificate"` -} - -func (self *SLoadbalancerCertificate) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancerCertificate) Refresh() error { - return nil -} - -func (self *SLoadbalancerCertificate) IsEmulated() bool { - return false -} - -func (self *SLoadbalancerCertificate) GetCreatedAt() time.Time { - return time.Time{} -} - -func (self *SLoadbalancerCertificate) GetSysTags() map[string]string { - return nil -} - -func (self *SLoadbalancerCertificate) GetTags() (map[string]string, error) { - return nil, nil -} - -func (self *SLoadbalancerCertificate) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancerCertificate) GetProjectId() string { - return self.region.GetProjectId() -} - -func (self *SLoadbalancerCertificate) Sync(name, privateKey, publickKey string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancerCertificate) Delete() error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancerCertificate) GetCommonName() string { - c := self.getCert() - if c == nil { - return "" - } - return c.Subject.CommonName -} - -func (self *SLoadbalancerCertificate) GetSubjectAlternativeNames() string { - c := self.getCert() - if c == nil { - return "" - } - - names := []string{} - for i := range c.Extensions { - names = append(names, string(c.Extensions[i].Value)) - } - - return strings.Join(names, ",") -} - -func (self *SLoadbalancerCertificate) getCert() *x509.Certificate { - if self.cert != nil { - return self.cert - } - - p, _ := pem.Decode([]byte(self.Certificate)) - c, err := x509.ParseCertificate(p.Bytes) - if err != nil { - log.Errorf("get certificate %s(%s): %s", self.Name, self.GetId(), err) - return nil - } - - self.cert = c - return c -} - -func (self *SLoadbalancerCertificate) GetFingerprint() string { - c := self.getCert() - if c == nil { - return "" - } - d := sha256.Sum256(c.Raw) - return api.LB_TLS_CERT_FINGERPRINT_ALGO_SHA256 + ":" + hex.EncodeToString(d[:]) -} - -func (self *SLoadbalancerCertificate) GetExpireTime() time.Time { - return self.ExpireTime -} - -func (self *SLoadbalancerCertificate) GetPublickKey() string { - return "" -} - -func (self *SLoadbalancerCertificate) GetPrivateKey() string { - return "" -} - -func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - certs, err := self.GetRegionalSslCertificates("") - if err != nil { - return nil, errors.Wrap(err, "GetRegionalSslCertificates") - } - - icerts := make([]cloudprovider.ICloudLoadbalancerCertificate, len(certs)) - for i := range certs { - icerts[i] = &certs[i] - } - - return icerts, nil -} - -func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - ret := SLoadbalancerCertificate{} - err := self.GetBySelfId(certId, &ret) - if err != nil { - return nil, errors.Wrap(err, "Get") - } - ret.region = self - return &ret, nil -} diff --git a/pkg/multicloud/google/loadbalancer_listener.go b/pkg/multicloud/google/loadbalancer_listener.go deleted file mode 100644 index 7a7000e443..0000000000 --- a/pkg/multicloud/google/loadbalancer_listener.go +++ /dev/null @@ -1,596 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SLoadbalancerListener struct { - lb *SLoadbalancer - rules []SLoadbalancerListenerRule - forwardRule SForwardingRule // 服务IP地址 - backendService SBackendServices // - httpProxy *STargetHttpProxy // http - httpsProxy *STargetHttpsProxy // https - healthChecks []HealthChecks - - ForwardRuleName string `json:"forward_rule_name"` - BackendServiceName string `json:"backend_service_name"` - Protocol string `json:"protocol"` - Port string `json:"port"` // 监听端口 -} - -func (self *SLoadbalancerListener) GetId() string { - return fmt.Sprintf("%s::%s::%s", self.forwardRule.GetGlobalId(), self.backendService.GetGlobalId(), self.Port) -} - -func (self *SLoadbalancerListener) GetName() string { - return fmt.Sprintf("%s::%s::%s", self.forwardRule.GetName(), self.backendService.GetName(), self.Port) -} - -func (self *SLoadbalancerListener) GetGlobalId() string { - return self.GetId() -} - -func (self *SLoadbalancerListener) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancerListener) Refresh() error { - return nil -} - -func (self *SLoadbalancerListener) IsEmulated() bool { - return true -} - -func (self *SLoadbalancerListener) GetCreatedAt() time.Time { - return time.Time{} -} - -func (self *SLoadbalancerListener) GetSysTags() map[string]string { - return nil -} - -func (self *SLoadbalancerListener) GetTags() (map[string]string, error) { - if len(self.forwardRule.IPAddress) > 0 { - return map[string]string{"FrontendIP": self.forwardRule.IPAddress}, nil - } - - return map[string]string{}, nil -} - -func (self *SLoadbalancerListener) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancerListener) GetProjectId() string { - return self.lb.GetProjectId() -} - -func (self *SLoadbalancerListener) GetListenerType() string { - return self.Protocol -} - -func (self *SLoadbalancerListener) GetListenerPort() int { - port, err := strconv.Atoi(self.Port) - if err != nil { - log.Errorf("GetListenerPort %s", err) - return 0 - } - - return port -} - -/* -在本地范围内使用的负载均衡算法。可能的值为: - -ROUND_ROBIN:这是一个简单的策略,其中按循环顺序选择每个健康的后端。这是默认设置。 -LEAST_REQUEST:一种 O(1) 算法,它选择两个随机的健康主机并选择具有较少活动请求的主机。 -RING_HASH:环/模散列负载均衡器对后端实现一致的散列。该算法的特性是从一组 N 个主机中添加/删除一个主机只会影响 1/N 的请求。 -RANDOM:负载均衡器随机选择一个健康的主机。 -ORIGINAL_DESTINATION:根据客户端连接元数据选择后端主机,即在连接被重定向到负载均衡器之前,连接被打开到与传入连接的目标地址相同的地址。 -MAGLEV:用作环形哈希负载均衡器的替代品。Maglev 不如环哈希稳定,但具有更快的表查找构建时间和主机选择时间。有关磁悬浮的更多信息,请参阅https://ai.google/research/pubs/pub44824 -此字段适用于: - -service_protocol 设置为 HTTP、HTTPS 或 HTTP2,并且 load_balancing_scheme 设置为 INTERNAL_MANAGED 的区域后端服务。 -load_balancing_scheme 设置为 INTERNAL_SELF_MANAGED 的全局后端服务。 -如果 sessionAffinity 不为 NONE,并且该字段未设置为 MAGLEV 或 RING_HASH,则会话亲缘性设置不会生效。 - -当后端服务被绑定到目标 gRPC 代理且 validateForProxyless 字段设置为 true 的 URL 映射引用时,仅支持默认的 ROUND_ROBIN 策略。 -*/ -// todo: fix me ??? -func (self *SLoadbalancerListener) GetScheduler() string { - switch self.backendService.LocalityLBPolicy { - case "ROUND_ROBIN": - return api.LB_SCHEDULER_RR - case "LEAST_REQUEST": - return api.LB_SCHEDULER_WLC - case "RING_HASH": - return api.LB_SCHEDULER_QCH - case "ORIGINAL_DESTINATION": - return api.LB_SCHEDULER_SCH - case "MAGLEV": - return api.LB_SCHEDULER_MH - default: - return "" - } -} - -func (self *SLoadbalancerListener) GetAclStatus() string { - return api.LB_BOOL_OFF -} - -func (self *SLoadbalancerListener) GetAclType() string { - return "" -} - -func (self *SLoadbalancerListener) GetAclId() string { - return "" -} - -func (self *SLoadbalancerListener) GetEgressMbps() int { - return 0 -} - -func (self *SLoadbalancerListener) GetBackendGroupId() string { - return self.backendService.GetGlobalId() -} - -func (self *SLoadbalancerListener) GetBackendServerPort() int { - igs, err := self.GetInstanceGroups() - if err != nil { - log.Errorf("GetInstanceGroups %s", err) - return 0 - } - - for i := range igs { - for j := range igs[i].NamedPorts { - if igs[i].NamedPorts[j].Name == self.backendService.PortName { - return int(igs[i].NamedPorts[j].Port) - } - } - } - - return 0 -} - -func (self *SLoadbalancerListener) GetClientIdleTimeout() int { - return int(self.backendService.ConnectionDraining.DrainingTimeoutSEC) -} - -func (self *SLoadbalancerListener) GetBackendConnectTimeout() int { - return int(self.backendService.TimeoutSEC) -} - -func (self *SLoadbalancerListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SLoadbalancerListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - rules, err := self.GetLoadbalancerListenerRules() - if err != nil { - return nil, errors.Wrap(err, "GetLoadbalancerListenerRules") - } - - for i := range rules { - if rules[i].GetGlobalId() == ruleId { - return &rules[i], nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SLoadbalancerListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - rules, err := self.GetLoadbalancerListenerRules() - if err != nil { - return nil, errors.Wrap(err, "GetLoadbalancerListenerRules") - } - - irules := make([]cloudprovider.ICloudLoadbalancerListenerRule, len(rules)) - for i := range rules { - irules[i] = &rules[i] - } - - return irules, nil -} - -func (self *SLoadbalancerListener) GetStickySession() string { - if self.backendService.SessionAffinity == "NONE" { - return api.LB_BOOL_OFF - } else { - return api.LB_BOOL_ON - } -} - -/* -https://cloud.google.com/load-balancing/docs/backend-service#sessionAffinity -区域级外部 HTTP(S) 负载均衡器: - 无 (NONE) - 客户端 IP (CLIENT_IP) - 生成的 Cookie (GENERATED_COOKIE) - 标头字段 (HEADER_FIELD) - HTTP Cookie (HTTP_COOKIE) -*/ -func (self *SLoadbalancerListener) GetStickySessionType() string { - switch self.backendService.SessionAffinity { - case "HTTP_COOKIE": - return api.LB_STICKY_SESSION_TYPE_SERVER - case "GENERATED_COOKIE": - return api.LB_STICKY_SESSION_TYPE_INSERT - } - return self.backendService.SessionAffinity -} - -func (self *SLoadbalancerListener) GetStickySessionCookie() string { - return self.backendService.ConsistentHash.HTTPCookie.Name -} - -func (self *SLoadbalancerListener) GetStickySessionCookieTimeout() int { - if len(self.backendService.ConsistentHash.HTTPCookie.TTL.Seconds) == 0 { - return 0 - } - - sec, err := strconv.Atoi(self.backendService.ConsistentHash.HTTPCookie.TTL.Seconds) - if err != nil { - log.Debugf("GetStickySessionCookieTimeout %s", err) - return 0 - } - - return sec -} - -// https://cloud.google.com/load-balancing/docs/https -func (self *SLoadbalancerListener) XForwardedForEnabled() bool { - return true -} - -// https://cloud.google.com/load-balancing/docs/https/troubleshooting-ext-https-lbs -func (self *SLoadbalancerListener) GzipEnabled() bool { - return false -} - -func (self *SLoadbalancerListener) GetCertificateId() string { - if self.httpsProxy != nil && len(self.httpsProxy.SSLCertificates) > 0 { - cert := SResourceBase{ - Name: "", - SelfLink: self.httpsProxy.SSLCertificates[0], - } - return cert.GetGlobalId() - } - - return "" -} - -func (self *SLoadbalancerListener) GetTLSCipherPolicy() string { - return "" -} - -// https://cloud.google.com/load-balancing/docs/https/troubleshooting-ext-https-lbs -func (self *SLoadbalancerListener) HTTP2Enabled() bool { - return true -} - -// todo: fix me route -// 高级配置才有重定向,具体怎么解析? -func (self *SLoadbalancerListener) GetRedirect() string { - //self.lb.urlMap.PathMatchers[0].RouteRules[0].URLRedirect - return "" -} - -func (self *SLoadbalancerListener) GetRedirectCode() int64 { - return 0 -} - -func (self *SLoadbalancerListener) GetRedirectScheme() string { - return "" -} - -func (self *SLoadbalancerListener) GetRedirectHost() string { - return "" -} - -func (self *SLoadbalancerListener) GetRedirectPath() string { - return "" -} - -func (self *SLoadbalancerListener) GetHealthCheck() string { - if len(self.backendService.HealthChecks) > 0 { - return api.LB_BOOL_ON - } else { - return api.LB_BOOL_OFF - } -} - -func (self *SLoadbalancerListener) GetHealthChecks() []HealthChecks { - if self.healthChecks != nil { - return self.healthChecks - } - - hcm, err := self.lb.GetHealthCheckMaps() - if err != nil { - log.Errorf("GetHealthCheckMaps %s", err) - return nil - } - ret := make([]HealthChecks, 0) - for i := range self.backendService.HealthChecks { - hc := self.backendService.HealthChecks[i] - if _, ok := hcm[hc]; ok { - ret = append(ret, hcm[hc]) - } - } - - self.healthChecks = ret - return ret -} - -func (self *SLoadbalancerListener) GetHealthCheckType() string { - hcs := self.GetHealthChecks() - if hcs == nil { - return "" - } - - switch strings.ToLower(hcs[0].Type) { - case "tcp": - return api.LB_HEALTH_CHECK_TCP - case "udp": - return api.LB_HEALTH_CHECK_UDP - case "http", "http2": - return api.LB_HEALTH_CHECK_HTTP - case "https", "ssl": - return api.LB_HEALTH_CHECK_HTTPS - default: - return "" - } -} - -func (self *SLoadbalancerListener) GetHealthCheckTimeout() int { - hcs := self.GetHealthChecks() - if hcs == nil { - return 0 - } - - return int(hcs[0].TimeoutSEC) -} - -func (self *SLoadbalancerListener) GetHealthCheckInterval() int { - hcs := self.GetHealthChecks() - if hcs == nil { - return 0 - } - - return int(hcs[0].CheckIntervalSEC) -} - -func (self *SLoadbalancerListener) GetHealthCheckRise() int { - hcs := self.GetHealthChecks() - if hcs == nil { - return 0 - } - - return int(hcs[0].HealthyThreshold) -} - -func (self *SLoadbalancerListener) GetHealthCheckFail() int { - hcs := self.GetHealthChecks() - if hcs == nil { - return 0 - } - - return int(hcs[0].UnhealthyThreshold) -} - -func (self *SLoadbalancerListener) GetHealthCheckReq() string { - return "" -} - -func (self *SLoadbalancerListener) GetHealthCheckExp() string { - return "" -} - -func (self *SLoadbalancerListener) GetHealthCheckDomain() string { - hcs := self.GetHealthChecks() - if hcs == nil { - return "" - } - switch hcs[0].Type { - case "HTTPS": - return hcs[0].HTTPSHealthCheck.Host - case "HTTP2": - return hcs[0].Http2HealthCheck.Host - case "HTTP": - return hcs[0].HTTPHealthCheck.Host - default: - return "" - } -} - -func (self *SLoadbalancerListener) GetHealthCheckURI() string { - hcs := self.GetHealthChecks() - if hcs == nil { - return "" - } - switch hcs[0].Type { - case "HTTPS": - return hcs[0].HTTPSHealthCheck.RequestPath - case "HTTP2": - return hcs[0].Http2HealthCheck.RequestPath - case "HTTP": - return hcs[0].HTTPHealthCheck.RequestPath - default: - return "" - } -} - -func (self *SLoadbalancerListener) GetHealthCheckCode() string { - return "" -} - -func (self *SLoadbalancerListener) Start() error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancerListener) Stop() error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancerListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancerListener) Delete(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancerListener) GetInstanceGroups() ([]SInstanceGroup, error) { - igs, err := self.lb.GetInstanceGroupsMap() - if err != nil { - return nil, errors.Wrap(err, "GetInstanceGroups") - } - - ret := make([]SInstanceGroup, 0) - for i := range self.backendService.Backends { - b := self.backendService.Backends[i] - if ig, ok := igs[b.Group]; ok { - ret = append(ret, ig) - } - } - - return ret, nil -} - -func (self *SLoadbalancer) GetLoadbalancerListeners() ([]SLoadbalancerListener, error) { - if self.urlMap != nil { - return self.GetHTTPLoadbalancerListeners() - } else { - return self.GetNetworkLoadbalancerListeners() - } -} - -func (self *SLoadbalancer) GetHTTPLoadbalancerListeners() ([]SLoadbalancerListener, error) { - frs, err := self.GetForwardingRules() - if err != nil { - return nil, errors.Wrap(err, "GetForwardingRules") - } - - _hps, err := self.GetTargetHttpProxies() - if err != nil { - return nil, errors.Wrap(err, "GetTargetHttpProxies") - } - - hps := make(map[string]STargetHttpProxy, 0) - for i := range _hps { - hps[_hps[i].SelfLink] = _hps[i] - } - - _hsps, err := self.GetTargetHttpsProxies() - if err != nil { - return nil, errors.Wrap(err, "GetTargetHttpsProxies") - } - - hsps := make(map[string]STargetHttpsProxy, 0) - for i := range _hsps { - hsps[_hsps[i].SelfLink] = _hsps[i] - } - - bss, err := self.GetBackendServices() - if err != nil { - return nil, errors.Wrap(err, "GetBackendServices") - } - - lbls := make([]SLoadbalancerListener, 0) - for i := range frs { - fr := frs[i] - for j := range bss { - bs := bss[j] - port := "80" - protocol := "http" - var hp STargetHttpProxy - var hsp STargetHttpsProxy - if fr.PortRange == "443-443" { - port = "443" - hsp = hsps[fr.Target] - protocol = "https" - } else if fr.PortRange == "8080-8080" { - port = "8080" - hp = hps[fr.Target] - } else { - hp = hps[fr.Target] - } - - lbl := SLoadbalancerListener{ - lb: self, - forwardRule: fr, - backendService: bs, - httpProxy: &hp, - httpsProxy: &hsp, - ForwardRuleName: fr.GetName(), - BackendServiceName: bs.GetName(), - Protocol: protocol, - Port: port, - } - lbls = append(lbls, lbl) - } - } - - return lbls, nil -} - -func (self *SLoadbalancer) GetNetworkLoadbalancerListeners() ([]SLoadbalancerListener, error) { - frs, err := self.GetForwardingRules() - if err != nil { - return nil, errors.Wrap(err, "GetForwardingRules") - } - - bss, err := self.GetBackendServices() - if err != nil { - return nil, errors.Wrap(err, "GetBackendServices") - } - - lbls := make([]SLoadbalancerListener, 0) - for i := range frs { - fr := frs[i] - for j := range bss { - bs := bss[j] - for n := range fr.Ports { - lbl := SLoadbalancerListener{ - lb: self, - forwardRule: fr, - backendService: bs, - ForwardRuleName: fr.GetName(), - BackendServiceName: bs.GetName(), - Protocol: strings.ToLower(fr.IPProtocol), - Port: fr.Ports[n], - } - - lbls = append(lbls, lbl) - } - } - } - - return lbls, nil -} diff --git a/pkg/multicloud/google/loadbalancer_listenerrule.go b/pkg/multicloud/google/loadbalancer_listenerrule.go deleted file mode 100644 index b621dd996e..0000000000 --- a/pkg/multicloud/google/loadbalancer_listenerrule.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "context" - "fmt" - "strings" - "time" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SLoadbalancerListenerRule struct { - lbl *SLoadbalancerListener - pathMatcher PathMatcher - pathRule PathRule - backendService SBackendServices - - ListenerName string `json:"listener_name"` - BackendServiceName string `json:"backend_service_name"` - Domain string `json:"domain"` - Path string `json:"path"` - Port string `json:"Port"` -} - -func (self *SLoadbalancerListenerRule) GetId() string { - return fmt.Sprintf("%s::%s::%s", self.lbl.GetGlobalId(), self.Domain, strings.Join(self.pathRule.Paths, ",")) -} - -func (self *SLoadbalancerListenerRule) GetName() string { - return fmt.Sprintf("%s::%s::%s", self.lbl.GetName(), self.Domain, strings.Join(self.pathRule.Paths, ",")) -} - -func (self *SLoadbalancerListenerRule) GetGlobalId() string { - return self.GetId() -} - -func (self *SLoadbalancerListenerRule) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancerListenerRule) Refresh() error { - return nil -} - -func (self *SLoadbalancerListenerRule) IsEmulated() bool { - return true -} - -func (self *SLoadbalancerListenerRule) GetCreatedAt() time.Time { - return time.Time{} -} - -func (self *SLoadbalancerListenerRule) GetSysTags() map[string]string { - return nil -} - -func (self *SLoadbalancerListenerRule) GetTags() (map[string]string, error) { - return nil, nil -} - -func (self *SLoadbalancerListenerRule) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancerListenerRule) GetProjectId() string { - return self.lbl.GetProjectId() -} - -func (self *SLoadbalancerListenerRule) GetRedirect() string { - return "" -} - -func (self *SLoadbalancerListenerRule) GetRedirectCode() int64 { - return 0 -} - -func (self *SLoadbalancerListenerRule) GetRedirectScheme() string { - return "" -} - -func (self *SLoadbalancerListenerRule) GetRedirectHost() string { - return "" -} - -func (self *SLoadbalancerListenerRule) GetRedirectPath() string { - return "" -} - -func (self *SLoadbalancerListenerRule) IsDefault() bool { - return false -} - -func (self *SLoadbalancerListenerRule) GetDomain() string { - return self.Domain -} - -func (self *SLoadbalancerListenerRule) GetPath() string { - return self.Path -} - -func (self *SLoadbalancerListenerRule) GetCondition() string { - return "" -} - -func (self *SLoadbalancerListenerRule) GetBackendGroupId() string { - return self.backendService.GetGlobalId() -} - -func (self *SLoadbalancerListenerRule) Delete(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancerListener) GetLoadbalancerListenerRules() ([]SLoadbalancerListenerRule, error) { - if !self.lb.isHttpLb { - return nil, nil - } - - if self.rules != nil { - return self.rules, nil - } - - hostRules := self.lb.urlMap.HostRules - pathMatchers := self.lb.urlMap.PathMatchers - - pmm := make(map[string]PathMatcher, 0) - for i := range pathMatchers { - name := pathMatchers[i].Name - pmm[name] = pathMatchers[i] - } - - ret := make([]SLoadbalancerListenerRule, 0) - for _, rule := range hostRules { - pm, ok := pmm[rule.PathMatcher] - if !ok { - continue - } - - for i := range rule.Hosts { - host := rule.Hosts[i] - for j := range pm.PathRules { - pr := pm.PathRules[j] - - if pr.Service != self.backendService.GetId() { - continue - } - - r := SLoadbalancerListenerRule{ - lbl: self, - backendService: self.backendService, - BackendServiceName: self.backendService.GetName(), - pathMatcher: pm, - pathRule: pr, - - ListenerName: self.GetName(), - Domain: host, - Path: strings.Join(pr.Paths, ","), - Port: self.Port, - } - - ret = append(ret, r) - } - } - } - - self.rules = ret - return ret, nil -} diff --git a/pkg/multicloud/google/machinetype.go b/pkg/multicloud/google/machinetype.go deleted file mode 100644 index 83941ba261..0000000000 --- a/pkg/multicloud/google/machinetype.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "time" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SMachineType struct { - Id string - CreationTimestamp time.Time - Name string - Description string - GuestCpus int - MemoryMb int - ImageSpaceGb int - MaximumPersistentDisks int - MaximumPersistentDisksSizeGb int - Zone string - SelfLink string - IsSharedCpu bool - Kind string -} - -func (region *SRegion) GetMachineTypes(zone string, maxResults int, pageToken string) ([]SMachineType, error) { - machines := []SMachineType{} - params := map[string]string{} - if len(zone) == 0 { - return nil, cloudprovider.ErrNotFound - } - resource := fmt.Sprintf("zones/%s/machineTypes", zone) - return machines, region.List(resource, params, maxResults, pageToken, &machines) -} - -func (region *SRegion) GetMachineType(id string) (*SMachineType, error) { - machine := &SMachineType{} - err := region.client.ecsGet("machineTypes", id, machine) - if err != nil { - return nil, err - } - return machine, nil -} diff --git a/pkg/multicloud/google/monitor.go b/pkg/multicloud/google/monitor.go deleted file mode 100644 index 121131f029..0000000000 --- a/pkg/multicloud/google/monitor.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type MetricDataValue struct { - DoubleValue float64 - Int64Value float64 -} - -func (self *MetricDataValue) GetValue() float64 { - return self.DoubleValue + self.Int64Value -} - -type MetricData struct { - Resource struct { - Labels struct { - InstanceId string - } - } - MetricKind string - ValueType string - Points []struct { - Interval struct { - StartTime time.Time - EndTime time.Time - } - Value MetricDataValue - } -} - -func (self *SGoogleClient) GetMonitorData(metricName string, since time.Time, until time.Time) (*jsonutils.JSONArray, error) { - params := map[string]string{ - "filter": fmt.Sprintf(`metric.type="%s"`, metricName), - "interval.startTime": since.Format(time.RFC3339), - "interval.endTime": until.Format(time.RFC3339), - } - resource := fmt.Sprintf("%s/%s/%s", "projects", self.projectId, "timeSeries") - timeSeries, err := self.monitorListAll(resource, params) - if err != nil { - return nil, err - } - return timeSeries, nil -} - -func (self *SGoogleClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) - } -} - -func (self *SGoogleClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metricName := "" - switch opts.MetricType { - case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: - metricName = "compute.googleapis.com/instance/cpu/utilization" - case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: - metricName = "compute.googleapis.com/instance/network/received_bytes_count" - case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: - metricName = "compute.googleapis.com/instance/network/sent_bytes_count" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: - metricName = "compute.googleapis.com/instance/disk/read_bytes_count" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: - metricName = "compute.googleapis.com/instance/disk/write_bytes_count" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: - metricName = "compute.googleapis.com/instance/disk/read_ops_count" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: - metricName = "compute.googleapis.com/instance/disk/write_ops_count" - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) - } - metrics, err := self.GetMonitorData(metricName, opts.StartTime, opts.EndTime) - if err != nil { - return nil, errors.Wrapf(err, "GetMonitorData") - } - data := []MetricData{} - err = metrics.Unmarshal(&data) - if err != nil { - return nil, errors.Wrapf(err, "metrics.Unmarshal") - } - ret := []cloudprovider.MetricValues{} - for i := range data { - value := cloudprovider.MetricValues{} - value.Id = data[i].Resource.Labels.InstanceId - value.MetricType = opts.MetricType - for j := range data[i].Points { - metricValue := cloudprovider.MetricValue{} - metricValue.Timestamp = data[i].Points[j].Interval.StartTime - metricValue.Value = data[i].Points[j].Value.GetValue() - value.Values = append(value.Values, metricValue) - } - ret = append(ret, value) - } - return ret, nil -} diff --git a/pkg/multicloud/google/network.go b/pkg/multicloud/google/network.go deleted file mode 100644 index bc1606b32f..0000000000 --- a/pkg/multicloud/google/network.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "time" - - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.GoogleTags - wire *SWire -} - -func (network *SNetwork) GetProjectId() string { - return network.wire.vpc.region.GetProjectId() -} - -func (self *SNetwork) GetName() string { - return self.wire.vpc.GetName() -} - -func (self *SNetwork) GetId() string { - return self.wire.vpc.GetId() -} - -func (self *SNetwork) GetGlobalId() string { - return self.wire.vpc.GetGlobalId() -} - -func (self *SNetwork) Refresh() error { - return self.wire.vpc.Refresh() -} - -func (network *SNetwork) IsEmulated() bool { - return false -} - -func (network *SNetwork) GetStatus() string { - return api.NETWORK_INTERFACE_STATUS_AVAILABLE -} - -func (network *SNetwork) GetCreatedAt() time.Time { - return time.Time{} -} - -func (network *SNetwork) Delete() error { - return network.wire.vpc.Delete() -} - -func (network *SNetwork) GetAllocTimeoutSeconds() int { - return 300 -} - -func (network *SNetwork) GetIWire() cloudprovider.ICloudWire { - return network.wire -} - -func (self *SNetwork) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.wire.vpc.IpCidrRange) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - return startIp.String() -} - -func (self *SNetwork) GetIpEnd() string { - pref, _ := netutils.NewIPV4Prefix(self.wire.vpc.IpCidrRange) - endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 - endIp = endIp.StepDown() // 254 - return endIp.String() -} - -func (self *SNetwork) GetIpMask() int8 { - pref, _ := netutils.NewIPV4Prefix(self.wire.vpc.IpCidrRange) - return pref.MaskLen -} - -func (self *SNetwork) GetGateway() string { - return self.wire.vpc.GatewayAddress -} - -func (network *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (network *SNetwork) GetIsPublic() bool { - return true -} - -func (network *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} diff --git a/pkg/multicloud/google/project.go b/pkg/multicloud/google/project.go deleted file mode 100644 index bc16104944..0000000000 --- a/pkg/multicloud/google/project.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SProject struct { - multicloud.SProjectBase - multicloud.GoogleTags - Name string - CreateTime time.Time - LifecycleState string - ProjectId string - ProjectNumber string -} - -func (cli *SGoogleClient) GetProject(id string) (*SProject, error) { - project := &SProject{} - resp, err := cli.managerGet(id) - if err != nil { - return nil, errors.Wrap(err, "managerGet") - } - err = resp.Unmarshal(project) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return project, nil -} - -func (cli *SGoogleClient) GetProjects() ([]SProject, error) { - nextPageToken := "" - params := map[string]string{} - result := []SProject{} - for { - if len(nextPageToken) > 0 { - params["pageToken"] = nextPageToken - } - resp, err := cli.managerList("projects", params) - if err != nil { - return nil, errors.Wrap(err, "managerList") - } - _result := []SProject{} - if resp.Contains("projects") { - err = resp.Unmarshal(&_result, "projects") - if err != nil { - return nil, errors.Wrap(err, "data.Unmarshal") - } - } - result = append(result, _result...) - nextPageToken, _ = resp.GetString("nextPageToken") - if len(nextPageToken) == 0 || len(_result) == 0 { - break - } - } - return result, nil -} - -func (p *SProject) GetName() string { - return p.Name -} - -func (p *SProject) GetId() string { - return p.ProjectId -} - -func (p *SProject) GetGlobalId() string { - return p.ProjectId -} - -func (p *SProject) GetStatus() string { - return api.EXTERNAL_PROJECT_STATUS_AVAILABLE -} - -func (p *SProject) Refresh() error { - return nil -} - -func (p *SProject) IsEmulated() bool { - return false -} diff --git a/pkg/multicloud/google/provider/doc.go b/pkg/multicloud/google/provider/doc.go deleted file mode 100644 index 83aa7a1e10..0000000000 --- a/pkg/multicloud/google/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/google/provider" diff --git a/pkg/multicloud/google/provider/provider.go b/pkg/multicloud/google/provider/provider.go deleted file mode 100644 index 7b3676ab74..0000000000 --- a/pkg/multicloud/google/provider/provider.go +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/google" -) - -type SGoogleProviderFactory struct { - cloudprovider.SPublicCloudBaseProviderFactory -} - -func (self *SGoogleProviderFactory) GetId() string { - return google.CLOUD_PROVIDER_GOOGLE -} - -func (self *SGoogleProviderFactory) GetName() string { - return google.CLOUD_PROVIDER_GOOGLE_CN -} - -func (self *SGoogleProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { - return nil -} - -func (self *SGoogleProviderFactory) IsSupportPrepaidResources() bool { - return false -} - -func (self *SGoogleProviderFactory) IsClouduserSupportPassword() bool { - return false -} - -func (factory *SGoogleProviderFactory) IsCloudpolicyWithSubscription() bool { - return true -} - -func (factory *SGoogleProviderFactory) IsClouduserpolicyWithSubscription() bool { - return true -} - -func (factory *SGoogleProviderFactory) IsSupportCloudIdService() bool { - return true -} - -func (factory *SGoogleProviderFactory) IsClouduserNeedInitPolicy() bool { - return true -} - -func (factory *SGoogleProviderFactory) IsSupportResetClouduserPassword() bool { - return false -} - -func (factory *SGoogleProviderFactory) GetClouduserMinPolicyCount() int { - return 1 -} - -func (self *SGoogleProviderFactory) IsClouduserBelongCloudprovider() bool { - return true -} - -func (self *SGoogleProviderFactory) NeedSyncSkuFromCloud() bool { - return false -} - -func (self *SGoogleProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - for key, value := range map[string]string{ - "client_email": input.GCPClientEmail, - "project_id": input.GCPProjectId, - "private_key_id": input.GCPPrivateKeyId, - "private_key": input.GCPPrivateKey, - } { - if len(value) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, key) - } - } - output.Account = fmt.Sprintf("%s/%s", input.GCPProjectId, input.GCPClientEmail) - output.Secret = fmt.Sprintf("%s/%s", input.GCPPrivateKeyId, input.GCPPrivateKey) - return output, nil -} - -func (self *SGoogleProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - projectID, clientEmail := "", "" - accountInfo := strings.Split(cloudaccount, "/") - if len(accountInfo) == 2 { - projectID, clientEmail = accountInfo[0], accountInfo[1] - } - - for key, value := range map[string]string{ - "private_key_id": input.GCPPrivateKeyId, - "private_key": input.GCPPrivateKey, - } { - if len(value) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, key) - } - } - if len(input.GCPClientEmail) == 0 { - input.GCPClientEmail = clientEmail - } - - if len(input.GCPProjectId) == 0 { - input.GCPProjectId = projectID - } - - output = cloudprovider.SCloudaccount{ - Account: fmt.Sprintf("%s/%s", input.GCPProjectId, input.GCPClientEmail), - Secret: fmt.Sprintf("%s/%s", input.GCPPrivateKeyId, input.GCPPrivateKey), - } - return output, nil -} - -func (self *SGoogleProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - privateKeyID, privateKey := "", "" - privateKeyInfo := strings.Split(cfg.Secret, "/") - if len(privateKeyInfo) < 2 { - return nil, fmt.Errorf("Missing privateKeyID or privateKey for google cloud") - } - privateKeyID = privateKeyInfo[0] - privateKey = strings.Join(privateKeyInfo[1:], "/") - projectID, clientEmail := "", "" - accountInfo := strings.Split(cfg.Account, "/") - if len(accountInfo) < 2 { - return nil, fmt.Errorf("Invalid projectID or client email for google cloud %s", cfg.Account) - } - projectID, clientEmail = accountInfo[0], accountInfo[1] - - client, err := google.NewGoogleClient( - google.NewGoogleClientConfig( - projectID, clientEmail, privateKeyID, privateKey, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SGoogleProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func parseAccount(account, secret string) (projectId string, clientEmail string, privateKey string, privateKeyId string) { - accountInfo := strings.Split(account, "/") - if len(accountInfo) == 2 { - projectId, clientEmail = accountInfo[0], accountInfo[1] - } - secretInfo := strings.Split(secret, "/") - if len(secretInfo) >= 2 { - privateKeyId, privateKey = secretInfo[0], strings.Join(secretInfo[1:], "/") - } - return -} - -func (self *SGoogleProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - projectId, clientEmail, privateKey, privateKeyId := parseAccount(info.Account, info.Secret) - return map[string]string{ - "GOOGLE_CLIENT_EMAIL": clientEmail, - "GOOGLE_PROJECT_ID": projectId, - "GOOGLE_PRIVATE_KEY_ID": privateKeyId, - "GOOGLE_PRIVATE_KEY": privateKey, - }, nil -} - -func init() { - factory := SGoogleProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SGoogleProvider struct { - cloudprovider.SBaseProvider - client *google.SGoogleClient -} - -func (self *SGoogleProvider) GetSysInfo() (jsonutils.JSONObject, error) { - regions := self.client.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") - info.Add(jsonutils.NewString(google.GOOGLE_API_VERSION), "api_version") - return info, nil -} - -func (self *SGoogleProvider) GetVersion() string { - return google.GOOGLE_API_VERSION -} - -func (self *SGoogleProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SGoogleProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SGoogleProvider) GetIamLoginUrl() string { - return "https://console.cloud.google.com" -} - -func (self *SGoogleProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SGoogleProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(extId) -} - -func (self *SGoogleProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SGoogleProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SGoogleProvider) GetStorageClasses(regionId string) []string { - return []string{ - "STANDARD", "NEARLINE", "COLDLINE", "ARCHIVE", - } -} - -func (self *SGoogleProvider) GetBucketCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLAuthRead), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SGoogleProvider) GetObjectCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLAuthRead), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SGoogleProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SGoogleProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { - return self.client.GetICloudusers() -} - -func (self *SGoogleProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - return []cloudprovider.ICloudgroup{}, nil -} - -func (self *SGoogleProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SGoogleProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetISystemCloudpolicies() -} - -func (self *SGoogleProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetICustomCloudpolicies() -} - -func (self *SGoogleProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - return self.client.CreateIClouduser(conf) -} - -func (self *SGoogleProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.client.GetIClouduserByName(name) -} - -func (self *SGoogleProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { - return self.client.CreateICloudpolicy(opts) -} - -func (self *SGoogleProvider) GetSamlEntityId() string { - return cloudprovider.SAML_ENTITY_ID_GOOGLE -} - -func (self *SGoogleProvider) GetICloudGlobalVpcs() ([]cloudprovider.ICloudGlobalVpc, error) { - return self.client.GetICloudGlobalVpcs() -} - -func (self *SGoogleProvider) GetICloudGlobalVpcById(id string) (cloudprovider.ICloudGlobalVpc, error) { - return self.client.GetICloudGlobalVpcById(id) -} - -func (self *SGoogleProvider) CreateICloudGlobalVpc(opts *cloudprovider.GlobalVpcCreateOptions) (cloudprovider.ICloudGlobalVpc, error) { - return self.client.CreateICloudGlobalVpc(opts) -} - -func (self *SGoogleProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/google/quota.go b/pkg/multicloud/google/quota.go deleted file mode 100644 index 45e735b6e5..0000000000 --- a/pkg/multicloud/google/quota.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "strings" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SQuota struct { - Metric string - Limit int - Usage int - Owner string -} - -func (q *SQuota) GetGlobalId() string { - return strings.ToLower(q.Metric) -} - -func (q *SQuota) GetName() string { - return q.Metric -} - -func (q *SQuota) GetDesc() string { - return q.Metric -} - -func (q *SQuota) GetQuotaType() string { - return q.Metric -} - -func (q *SQuota) GetMaxQuotaCount() int { - return q.Limit -} - -func (q *SQuota) GetCurrentQuotaUsedCount() int { - return q.Usage -} - -func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { - ret := []cloudprovider.ICloudQuota{} - for i := range region.Quotas { - ret = append(ret, ®ion.Quotas[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/google/region.go b/pkg/multicloud/google/region.go deleted file mode 100644 index dbae3041b4..0000000000 --- a/pkg/multicloud/google/region.go +++ /dev/null @@ -1,833 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - cloudprovider.SFakeOnPremiseRegion - multicloud.SRegion - client *SGoogleClient - - capabilities []string - Quotas []SQuota - - Description string - ID string - Kind string - Name string - Status string - SelfLink string - CreationTimestamp time.Time -} - -func (region *SRegion) GetClient() *SGoogleClient { - return region.client -} - -func (region *SRegion) GetName() string { - if name, ok := RegionNames[region.Name]; ok { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_GOOGLE_CN, name) - } - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_GOOGLE_CN, region.Name) -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_GOOGLE, self.Name) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (region *SRegion) GetId() string { - return region.Name -} - -func (region *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_GOOGLE, region.Name) -} - -func (region *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - if geoInfo, ok := LatitudeAndLongitude[region.Name]; ok { - return geoInfo - } - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetCreatedAt() time.Time { - return self.CreationTimestamp -} - -func (region *SRegion) GetProvider() string { - return CLOUD_PROVIDER_GOOGLE -} - -func (region *SRegion) GetStatus() string { - if region.Status == "UP" || utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return api.CLOUD_REGION_STATUS_INSERVER - } - return api.CLOUD_REGION_STATUS_OUTOFSERVICE -} - -func (region *SRegion) CreateIBucket(name string, storageClassStr string, acl string) error { - _, err := region.CreateBucket(name, storageClassStr, cloudprovider.TBucketACLType(acl)) - return err -} - -func (region *SRegion) DeleteIBucket(name string) error { - return region.DeleteBucket(name) -} - -func (region *SRegion) IBucketExist(name string) (bool, error) { - //{"error":{"code":403,"details":"200420163731-compute@developer.gserviceaccount.com does not have storage.buckets.get access to test."}} - //{"error":{"code":404,"details":"Not Found"}} - _, err := region.GetBucket(name) - if err == nil { - return true, nil - } - if errors.Cause(err) == cloudprovider.ErrNotFound || strings.Contains(err.Error(), "storage.buckets.get access") { - return false, nil - } - return false, err -} - -func (region *SRegion) GetIBucketById(id string) (cloudprovider.ICloudBucket, error) { - return cloudprovider.GetIBucketById(region, id) -} - -func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { - return region.GetIBucketById(name) -} - -func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - iBuckets, err := region.client.getIBuckets() - if err != nil { - return nil, errors.Wrap(err, "getIBuckets") - } - ret := []cloudprovider.ICloudBucket{} - for i := range iBuckets { - if iBuckets[i].GetLocation() != region.GetId() { - continue - } - ret = append(ret, iBuckets[i]) - } - return ret, nil -} - -func (region *SRegion) IsEmulated() bool { - return false -} - -func (region *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return []cloudprovider.ICloudZone{}, nil - } - zones, err := region.GetZones(region.Name, 0, "") - if err != nil { - return nil, err - } - izones := []cloudprovider.ICloudZone{} - for i := 0; i < len(zones); i++ { - zones[i].region = region - izones = append(izones, &zones[i]) - } - return izones, nil -} - -func (region *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotFound - } - - zones, err := region.GetIZones() - if err != nil { - return nil, err - } - for i := range zones { - if zones[i].GetGlobalId() == id { - return zones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - if utils.IsInStringArray(self.Name, MultiRegions) || utils.IsInStringArray(self.Name, DualRegions) { - return []cloudprovider.ICloudVpc{}, nil - } - vpcs, err := self.GetVpcs() - if err != nil { - return nil, errors.Wrapf(err, "GetVpcs") - } - ret := []cloudprovider.ICloudVpc{} - for i := range vpcs { - vpcs[i].region = self - ret = append(ret, &vpcs[i]) - } - return ret, nil -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - vpc, err := self.GetVpc(id) - if err != nil { - return nil, errors.Wrapf(err, "GetVpc") - } - return vpc, nil -} - -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - if utils.IsInStringArray(self.Name, MultiRegions) || utils.IsInStringArray(self.Name, DualRegions) { - return nil, cloudprovider.ErrNotSupported - } - gvpc, err := self.client.GetGlobalNetwork(opts.GlobalVpcExternalId) - if err != nil { - return nil, errors.Wrapf(err, "GetGlobalNetwork") - } - return self.CreateVpc(opts.NAME, gvpc.SelfLink, opts.CIDR, opts.Desc) -} - -func (region *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotFound - } - - storage, err := region.GetStorage(id) - if err != nil { - return nil, err - } - zone, err := region.GetZone(storage.Zone) - if err != nil { - return nil, errors.Wrapf(err, "region.GetZone(%s)", storage.Zone) - } - zone.region = region - storage.zone = zone - return storage, nil -} - -func (region *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotFound - } - - izones, err := region.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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetProjectId() string { - return region.client.projectId -} - -func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return []cloudprovider.ICloudEIP{}, nil - } - - eips, err := region.GetEips("", 0, "") - if err != nil { - return nil, err - } - ieips := []cloudprovider.ICloudEIP{} - for i := range eips { - eips[i].region = region - ieips = append(ieips, &eips[i]) - } - return ieips, nil -} - -func (region *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotFound - } - - ivm, err := region.GetInstance(id) - if err != nil { - return nil, err - } - zone, err := region.GetZone(ivm.Zone) - if err != nil { - return nil, errors.Wrapf(err, "GetZone(%s)", ivm.Zone) - } - ivm.host = &SHost{zone: zone} - return ivm, nil -} - -func (region *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotFound - } - - disk, err := region.GetDisk(id) - if err != nil { - return nil, err - } - return disk, nil -} - -func (region *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotFound - } - - eip, err := region.GetEip(id) - if err != nil { - return nil, err - } - return eip, nil -} - -func (region *SRegion) fetchSnapshots() error { - if len(region.client.snapshots) > 0 { - return nil - } - region.client.snapshots = map[string][]SSnapshot{} - snapshots, err := region.GetSnapshots("", 0, "") - if err != nil { - return err - } - regionNames := []string{} - for _, region := range region.client.iregions { - regionNames = append(regionNames, region.GetId()) - } - for _, snapshot := range snapshots { - for _, location := range snapshot.StorageLocations { - _regionName := "" - if utils.IsInStringArray(location, regionNames) { - _regionName = location - } else { - for _, regionName := range regionNames { - if strings.HasPrefix(regionName, location) { - _regionName = regionName - break - } - } - } - if len(_regionName) > 0 { - if _, ok := region.client.snapshots[_regionName]; !ok { - region.client.snapshots[_regionName] = []SSnapshot{} - } - region.client.snapshots[_regionName] = append(region.client.snapshots[_regionName], snapshot) - break - } - - } - } - return nil -} - -func (region *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return []cloudprovider.ICloudSnapshot{}, nil - } - - region.fetchSnapshots() - isnapshots := []cloudprovider.ICloudSnapshot{} - if snapshots, ok := region.client.snapshots[region.Name]; ok { - for i := range snapshots { - snapshots[i].region = region - isnapshots = append(isnapshots, &snapshots[i]) - } - } - return isnapshots, nil -} - -func (region *SRegion) GetISnapshotById(id string) (cloudprovider.ICloudSnapshot, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotFound - } - - snapshot, err := region.GetSnapshot(id) - if err != nil { - return nil, err - } - return snapshot, nil -} - -func (region *SRegion) rdsDelete(id string) error { - operation := &SOperation{} - err := region.client.rdsDelete(id, operation) - if err != nil { - return errors.Wrap(err, "client.rdsDelete") - } - _, err = region.WaitRdsOperation(operation.SelfLink, id, "delete") - if err != nil { - return errors.Wrapf(err, "region.WaitRdsOperation(%s)", operation.SelfLink) - } - return nil -} - -func (region *SRegion) rdsDo(id string, action string, params map[string]string, body jsonutils.JSONObject) error { - opId, err := region.client.rdsDo(id, action, params, body) - if err != nil { - return err - } - if strings.Index(opId, "/operations/") > 0 { - _, err = region.WaitRdsOperation(opId, id, action) - return err - } - return nil -} - -func (region *SRegion) rdsPatch(id string, body jsonutils.JSONObject) error { - opId, err := region.client.rdsPatch(id, body) - if err != nil { - return err - } - if strings.Index(opId, "/operations/") > 0 { - _, err = region.WaitRdsOperation(opId, id, "update") - return err - } - return nil -} - -func (region *SRegion) rdsUpdate(id string, params map[string]string, body jsonutils.JSONObject) error { - opId, err := region.client.rdsUpdate(id, params, body) - if err != nil { - return err - } - if strings.Index(opId, "/operations/") > 0 { - _, err = region.WaitRdsOperation(opId, id, "update") - return err - } - return nil -} - -func (region *SRegion) rdsGet(resource string, retval interface{}) error { - return region.client.rdsGet(resource, retval) -} - -func (region *SRegion) rdsInsert(resource string, body jsonutils.JSONObject, retval interface{}) error { - operation := SOperation{} - err := region.client.rdsInsert(resource, body, &operation) - if err != nil { - return errors.Wrap(err, "rdsInsert") - } - resourceId, err := region.WaitRdsOperation(operation.SelfLink, resource, "insert") - if err != nil { - return errors.Wrapf(err, "region.WaitRdsOperation(%s)", operation.SelfLink) - } - return region.rdsGet(resourceId, retval) -} - -func (region *SRegion) RdsListAll(resource string, params map[string]string, retval interface{}) error { - return region.client.rdsListAll(resource, params, retval) -} - -func (region *SRegion) RdsList(resource string, params map[string]string, maxResults int, pageToken string, retval interface{}) error { - if maxResults == 0 && len(pageToken) == 0 { - return region.RdsListAll(resource, params, retval) - } - if params == nil { - params = map[string]string{} - } - params["maxResults"] = fmt.Sprintf("%d", maxResults) - params["pageToken"] = pageToken - resp, err := region.client.rdsList(resource, params) - if err != nil { - return errors.Wrap(err, "billingList") - } - if resp.Contains("items") && retval != nil { - err = resp.Unmarshal(retval, "items") - if err != nil { - return errors.Wrap(err, "resp.Unmarshal") - } - } - return nil -} - -func (region *SRegion) BillingList(resource string, params map[string]string, pageSize int, pageToken string, retval interface{}) error { - if pageSize == 0 && len(pageToken) == 0 { - return region.BillingListAll(resource, params, retval) - } - if params == nil { - params = map[string]string{} - } - params["pageSize"] = fmt.Sprintf("%d", pageSize) - params["pageToken"] = pageToken - resp, err := region.client.billingList(resource, params) - if err != nil { - return errors.Wrap(err, "billingList") - } - if resp.Contains("skus") && retval != nil { - err = resp.Unmarshal(retval, "skus") - if err != nil { - return errors.Wrap(err, "resp.Unmarshal") - } - } - return nil -} - -func (region *SRegion) BillingListAll(resource string, params map[string]string, retval interface{}) error { - return region.client.billingListAll(resource, params, retval) -} - -func (region *SRegion) ListAll(resource string, params map[string]string, retval interface{}) error { - return region.listAll("GET", resource, params, retval) -} - -func (region *SRegion) listAll(method string, resource string, params map[string]string, retval interface{}) error { - return region.client._ecsListAll(method, resource, params, retval) -} - -func (region *SRegion) List(resource string, params map[string]string, maxResults int, pageToken string, retval interface{}) error { - if maxResults == 0 && len(pageToken) == 0 { - return region.ListAll(resource, params, retval) - } - if params == nil { - params = map[string]string{} - } - params["maxResults"] = fmt.Sprintf("%d", maxResults) - params["pageToken"] = pageToken - resp, err := region.client.ecsList(resource, params) - if err != nil { - return errors.Wrap(err, "ecsList") - } - if resp.Contains("items") && retval != nil { - err = resp.Unmarshal(retval, "items") - if err != nil { - return errors.Wrap(err, "resp.Unmarshal") - } - } - return nil -} - -func (region *SRegion) Get(resourceType, id string, retval interface{}) error { - return region.client.ecsGet(resourceType, id, retval) -} - -func (self *SGoogleClient) GetBySelfId(id string, retval interface{}) error { - resp, err := jsonRequest(self.client, "GET", GOOGLE_COMPUTE_DOMAIN, GOOGLE_API_VERSION, id, nil, nil, self.debug) - if err != nil { - return err - } - if retval != nil { - return resp.Unmarshal(retval) - } - return nil -} - -func (self *SRegion) GetBySelfId(id string, retval interface{}) error { - return self.client.GetBySelfId(id, retval) -} - -func (region *SRegion) StorageListAll(resource string, params map[string]string, retval interface{}) error { - return region.client.storageListAll(resource, params, retval) -} - -func (region *SRegion) StorageList(resource string, params map[string]string, maxResults int, pageToken string, retval interface{}) error { - if maxResults == 0 && len(pageToken) == 0 { - return region.client.storageListAll(resource, params, retval) - } - if params == nil { - params = map[string]string{} - } - params["maxResults"] = fmt.Sprintf("%d", maxResults) - params["pageToken"] = pageToken - resp, err := region.client.storageList(resource, params) - if err != nil { - return errors.Wrap(err, "storageList") - } - if resp.Contains("items") && retval != nil { - err = resp.Unmarshal(retval, "items") - if err != nil { - return errors.Wrap(err, "resp.Unmarshal") - } - } - return nil -} - -func (region *SRegion) StorageGet(id string, retval interface{}) error { - return region.client.storageGet(id, retval) -} - -func (region *SRegion) StoragePut(id string, body jsonutils.JSONObject, retval interface{}) error { - return region.client.storagePut(id, body, retval) -} - -func (region *SRegion) StorageDo(id string, action string, params map[string]string, body jsonutils.JSONObject) error { - opId, err := region.client.storageDo(id, action, params, body) - if err != nil { - return err - } - if strings.Index(opId, "/operations/") > 0 { - _, err = region.client.WaitOperation(opId, id, action) - return err - } - return nil -} - -func (region *SRegion) Do(id string, action string, params map[string]string, body jsonutils.JSONObject) error { - opId, err := region.client.ecsDo(id, action, params, body) - if err != nil { - return err - } - if strings.Index(opId, "/operations/") > 0 { - _, err = region.client.WaitOperation(opId, id, action) - return err - } - return nil -} - -func (region *SRegion) Patch(id string, action string, params map[string]string, body jsonutils.JSONObject) error { - opId, err := region.client.ecsPatch(id, action, params, body) - if err != nil { - return err - } - if strings.Index(opId, "/operations/") > 0 { - _, err = region.client.WaitOperation(opId, id, action) - return err - } - return nil -} - -func (region *SRegion) StorageDelete(id string) error { - return region.client.storageDelete(id, nil) -} - -func (region *SRegion) Delete(id string) error { - operation := &SOperation{} - err := region.client.ecsDelete(id, operation) - if err != nil { - return errors.Wrap(err, "client.ecsDelete") - } - _, err = region.client.WaitOperation(operation.SelfLink, id, "delete") - if err != nil { - return errors.Wrapf(err, "region.WaitOperation(%s)", operation.SelfLink) - } - return nil -} - -func (region *SRegion) StorageInsert(resource string, body jsonutils.JSONObject, retval interface{}) error { - return region.client.storageInsert(resource, body, retval) -} - -func (region *SRegion) CloudbuildInsert(body jsonutils.JSONObject) error { - result := &struct { - Name string - }{} - resource := fmt.Sprintf("projects/%s/builds", region.GetProjectId()) - err := region.client.cloudbuildInsert(resource, body, result) - if err != nil { - return errors.Wrap(err, "insert") - } - err = cloudprovider.Wait(time.Second*10, time.Minute*40, func() (bool, error) { - operation, err := region.GetCloudbuildOperation(result.Name) - if err != nil { - return false, errors.Wrapf(err, "region.GetCloudbuildOperation(%s)", result.Name) - } - status := operation.Metadata.Build.Status - log.Debugf("cloudbuild %s status: %s", result.Name, status) - if status == "FAILURE" { - return false, fmt.Errorf("cloudbuild failed error log: %s", operation.Metadata.Build.LogUrl) - } - if status == "SUCCESS" { - return true, nil - } - return false, nil - }) - if err != nil { - return errors.Wrap(err, "cloudprovider.Wait") - } - return nil -} - -func (region *SRegion) cloudbuildGet(id string, retval interface{}) error { - return region.client.cloudbuildGet(id, retval) -} - -func (self *SGoogleClient) Insert(resource string, body jsonutils.JSONObject, retval interface{}) error { - operation := &SOperation{} - err := self.ecsInsert(resource, body, operation) - if err != nil { - return err - } - resourceId, err := self.WaitOperation(operation.SelfLink, resource, "insert") - if err != nil { - return errors.Wrapf(err, "region.WaitOperation(%s)", operation.SelfLink) - } - return self.GetBySelfId(resourceId, retval) -} - -func (self *SRegion) Insert(resource string, body jsonutils.JSONObject, retval interface{}) error { - return self.client.Insert(resource, body, retval) -} - -func (region *SRegion) fetchResourcePolicies() ([]SResourcePolicy, error) { - if len(region.client.resourcepolices) > 0 { - return region.client.resourcepolices, nil - } - policies, err := region.GetResourcePolicies(0, "") - if err != nil { - return nil, err - } - region.client.resourcepolices = policies - return policies, nil -} - -func (region *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return []cloudprovider.ICloudSnapshotPolicy{}, nil - } - - policies, err := region.fetchResourcePolicies() - if err != nil { - return nil, err - } - ipolicies := []cloudprovider.ICloudSnapshotPolicy{} - for i := range policies { - policies[i].region = region - if utils.IsInStringArray(region.Name, policies[i].SnapshotSchedulePolicy.SnapshotProperties.StorageLocations) { - ipolicies = append(ipolicies, &policies[i]) - } - } - return ipolicies, nil -} - -func (region *SRegion) GetISnapshotPolicyById(id string) (cloudprovider.ICloudSnapshotPolicy, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotFound - } - - policy, err := region.GetResourcePolicy(id) - if err != nil { - return nil, err - } - if !strings.Contains(region.Name, policy.SnapshotSchedulePolicy.SnapshotProperties.StorageLocations[0]) { - return nil, cloudprovider.ErrNotFound - } - return policy, nil -} - -func (region *SRegion) CreateEIP(args *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotSupported - } - - eip, err := region.CreateEip(args.Name, "") - if err != nil { - return nil, err - } - return eip, nil -} - -func (region *SRegion) GetCapabilities() []string { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return []string{cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE} - } - if region.capabilities == nil { - return region.client.GetCapabilities() - } - return region.capabilities -} - -func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return []cloudprovider.ICloudDBInstance{}, nil - } - - instances, err := region.GetDBInstances(0, "") - if err != nil { - return nil, errors.Wrap(err, "GetDBInstances") - } - ret := []cloudprovider.ICloudDBInstance{} - for i := range instances { - instances[i].region = region - ret = append(ret, &instances[i]) - } - return ret, nil -} - -func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotFound - } - - instance, err := region.GetDBInstance(instanceId) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstance(%s)", instanceId) - } - return instance, nil -} - -func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return []cloudprovider.ICloudDBInstanceBackup{}, nil - } - - instances, err := region.GetDBInstances(0, "") - if err != nil { - return nil, errors.Wrap(err, "GetDBInstances") - } - ret := []cloudprovider.ICloudDBInstanceBackup{} - for i := range instances { - instances[i].region = region - backups, err := region.GetDBInstanceBackups(instances[i].Name) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceBackups(%s)", instances[i].Name) - } - for j := range backups { - backups[j].rds = &instances[i] - ret = append(ret, &backups[j]) - } - } - return ret, nil -} - -func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotFound - } - - backup, err := region.GetDBInstanceBackup(backupId) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceBackup(%s)", backupId) - } - return backup, nil -} - -func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { - return nil, cloudprovider.ErrNotSupported - } - - rds, err := region.CreateDBInstance(desc) - if err != nil { - return nil, errors.Wrap(err, "CreateDBInstance") - } - return rds, nil -} diff --git a/pkg/multicloud/google/resourcepolicy.go b/pkg/multicloud/google/resourcepolicy.go deleted file mode 100644 index 5dfe8c9a67..0000000000 --- a/pkg/multicloud/google/resourcepolicy.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDailySchedule struct { - DaysInCycle int - StartTime string - Duration string -} - -type SDayOfWeek struct { - Day string - StartTime string - Duration string -} - -type SHourlySchedule struct { - HoursInCycle int - StartTime string - Duration string -} - -type SWeeklySchedule struct { - DayOfWeeks []SDayOfWeek -} - -type SSchedule struct { - WeeklySchedule SWeeklySchedule - DailySchedule SDailySchedule - HourlySchedule SHourlySchedule -} - -type SRetentionPolicy struct { - MaxRetentionDays int - OnSourceDiskDelete string -} - -type SSnapshotProperties struct { - StorageLocations []string - GuestFlush bool -} - -type SSnapshotSchedulePolicy struct { - Schedule SSchedule - RetentionPolicy SRetentionPolicy - SnapshotProperties SSnapshotProperties -} - -type SResourcePolicy struct { - region *SRegion - SResourceBase - multicloud.GoogleTags - - CreationTimestamp time.Time - Region string - Status string - Kind string - SnapshotSchedulePolicy SSnapshotSchedulePolicy `json:"snapshotSchedulePolicy"` -} - -func (region *SRegion) GetResourcePolicies(maxResults int, pageToken string) ([]SResourcePolicy, error) { - policies := []SResourcePolicy{} - resource := fmt.Sprintf("regions/%s/resourcePolicies", region.Name) - params := map[string]string{} - return policies, region.List(resource, params, maxResults, pageToken, &policies) -} - -func (region *SRegion) GetResourcePolicy(id string) (*SResourcePolicy, error) { - policy := &SResourcePolicy{region: region} - return policy, region.Get("resourcePolicies", id, policy) -} - -func (policy *SResourcePolicy) GetStatus() string { - switch policy.Status { - case "READY": - return api.SNAPSHOT_POLICY_READY - default: - log.Errorf("unknown policy status %s", policy.Status) - return api.SNAPSHOT_POLICY_UNKNOWN - } -} - -func (policy *SResourcePolicy) GetCreatedAt() time.Time { - return policy.CreationTimestamp -} - -func (policy *SResourcePolicy) Refresh() error { - _policy, err := policy.region.GetResourcePolicy(policy.Id) - if err != nil { - return err - } - return jsonutils.Update(policy, _policy) -} - -func (policy *SResourcePolicy) IsEmulated() bool { - return false -} - -func (policy *SResourcePolicy) GetProjectId() string { - return policy.region.GetProjectId() -} - -func (policy *SResourcePolicy) GetRetentionDays() int { - return policy.SnapshotSchedulePolicy.RetentionPolicy.MaxRetentionDays -} - -func (policy *SResourcePolicy) GetRepeatWeekdays() ([]int, error) { - result := []int{1, 2, 3, 4, 5, 6, 7} - if len(policy.SnapshotSchedulePolicy.Schedule.WeeklySchedule.DayOfWeeks) > 0 { - return nil, fmt.Errorf("current not support dayOfWeeks") - } - if policy.SnapshotSchedulePolicy.Schedule.HourlySchedule.HoursInCycle != 0 { - return nil, fmt.Errorf("current not support hourlySchedule") - } - return result, nil -} - -func (policy *SResourcePolicy) GetTimePoints() ([]int, error) { - result := []int{} - if len(policy.SnapshotSchedulePolicy.Schedule.DailySchedule.StartTime) == 0 { - return nil, fmt.Errorf("current only support dailySchedule") - } - if startInfo := strings.Split(policy.SnapshotSchedulePolicy.Schedule.DailySchedule.StartTime, ":"); len(startInfo) >= 2 { - point, err := strconv.Atoi(startInfo[0]) - if err != nil { - return nil, errors.Wrapf(err, "convert %s", policy.SnapshotSchedulePolicy.Schedule.DailySchedule.StartTime) - } - result = append(result, point) - if startInfo[1] != "00" { - result = append(result, point+1) - } - } - return result, nil -} - -func (policy *SResourcePolicy) IsActivated() bool { - return true -} diff --git a/pkg/multicloud/google/s3object.go b/pkg/multicloud/google/s3object.go deleted file mode 100644 index 79add045df..0000000000 --- a/pkg/multicloud/google/s3object.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2019 Yunion -// -// 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. - -// Copyright 2019 Yunion - -// -// 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 google - -import ( - "context" - "fmt" - "net/http" - "net/url" - "strings" - "time" - - "cloud.google.com/go/storage" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SBucketObjects struct { - Prefixes []string - Items []SObject - NextPageToken string -} - -type SObject struct { - bucket *SBucket - - Id string - Name string - SelfLink string - MediaLink string - Bucket string - Generation string - Metageneration string - ContentType string - ContentEncoding string - ContentDisposition string - ContentLanguage string - CacheControl string - StorageClass string - Size int64 - Md5Hash string - Metadata map[string]string - Crc32c string - Etag string - TimeCreated time.Time - Updated time.Time - TimeStorageClassUpdated time.Time -} - -func (region *SRegion) GetObjects(bucket string, prefix string, nextPageToken string, delimiter string, maxCount int) (*SBucketObjects, error) { - if maxCount <= 0 { - maxCount = 20 - } - resource := fmt.Sprintf("b/%s/o", bucket) - params := map[string]string{"maxResults": fmt.Sprintf("%d", maxCount)} - if len(prefix) > 0 { - params["prefix"] = prefix - } - if len(delimiter) > 0 { - params["delimiter"] = delimiter - } - if len(nextPageToken) > 0 { - params["pageToken"] = nextPageToken - } - objs := SBucketObjects{} - resp, err := region.client.storageList(resource, params) - if err != nil { - return nil, errors.Wrap(err, "storageList") - } - err = resp.Unmarshal(&objs) - if err != nil { - return nil, errors.Wrap(err, "Unmarshal") - } - return &objs, nil -} - -func (region *SRegion) ConvertAcl(acls []GCSAcl) cloudprovider.TBucketACLType { - ret := cloudprovider.ACLPrivate - for _, acl := range acls { - if acl.Entity == string(storage.AllUsers) { - if acl.Role == string(storage.RoleOwner) || acl.Role == string(storage.RoleWriter) { - ret = cloudprovider.ACLPublicReadWrite - } - if acl.Role == string(storage.RoleReader) && ret != cloudprovider.ACLPublicReadWrite { - ret = cloudprovider.ACLPublicRead - } - } - if !(ret == cloudprovider.ACLPublicRead || ret == cloudprovider.ACLPublicReadWrite) && acl.Entity == string(storage.AllAuthenticatedUsers) { - ret = cloudprovider.ACLAuthRead - } - } - return ret -} - -func (o *SObject) GetAcl() cloudprovider.TBucketACLType { - if strings.HasSuffix(o.Name, "/") { - return cloudprovider.ACLPrivate - } - acls, err := o.bucket.region.GetObjectAcl(o.bucket.Name, o.Name) - if err != nil { - log.Errorf("failed to get object %s acls error: %v", o.Name, err) - return cloudprovider.ACLUnknown - } - return o.bucket.region.ConvertAcl(acls) -} - -func (o *SObject) SetAcl(acl cloudprovider.TBucketACLType) error { - return o.bucket.region.SetObjectAcl(o.bucket.Name, o.Name, acl) -} - -func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { - return o.bucket -} - -func (o *SObject) GetKey() string { - return o.Name -} - -func (o *SObject) GetSizeBytes() int64 { - return o.Size -} - -func (o *SObject) GetLastModified() time.Time { - return o.Updated -} - -func (o *SObject) GetStorageClass() string { - return o.StorageClass -} - -func (o *SObject) GetETag() string { - return o.Etag -} - -func (o *SObject) GetMeta() http.Header { - meta := http.Header{} - for k, v := range o.Metadata { - meta.Set(k, v) - } - for k, v := range map[string]string{ - cloudprovider.META_HEADER_CONTENT_TYPE: o.ContentType, - cloudprovider.META_HEADER_CONTENT_ENCODING: o.ContentEncoding, - cloudprovider.META_HEADER_CONTENT_DISPOSITION: o.ContentDisposition, - cloudprovider.META_HEADER_CONTENT_LANGUAGE: o.ContentLanguage, - cloudprovider.META_HEADER_CACHE_CONTROL: o.CacheControl, - } { - meta.Set(k, v) - } - return meta -} - -func (region *SRegion) SetObjectMeta(bucket, object string, meta http.Header) error { - body := map[string]string{} - for k := range meta { - switch k { - case cloudprovider.META_HEADER_CONTENT_TYPE: - body["contentType"] = meta.Get(k) - case cloudprovider.META_HEADER_CONTENT_ENCODING: - body["contentEncoding"] = meta.Get(k) - case cloudprovider.META_HEADER_CONTENT_DISPOSITION: - body["contentDisposition"] = meta.Get(k) - case cloudprovider.META_HEADER_CONTENT_LANGUAGE: - body["contentLanguage"] = meta.Get(k) - case cloudprovider.META_HEADER_CACHE_CONTROL: - body["cacheControl"] = meta.Get(k) - default: - body[fmt.Sprintf("metadata.%s", k)] = meta.Get(k) - } - } - resource := fmt.Sprintf("b/%s/o/%s", bucket, url.PathEscape(object)) - return region.StoragePut(resource, jsonutils.Marshal(body), nil) -} - -func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { - return o.bucket.region.SetObjectMeta(o.bucket.Name, o.Name, meta) -} diff --git a/pkg/multicloud/google/securitygroup.go b/pkg/multicloud/google/securitygroup.go deleted file mode 100644 index ecf988b0c2..0000000000 --- a/pkg/multicloud/google/securitygroup.go +++ /dev/null @@ -1,429 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - SECGROUP_TYPE_SERVICE_ACCOUNT = "serviceAccount" - SECGROUP_TYPE_TAG = "tag" -) - -type SFirewallAction struct { - IPProtocol string - Ports []string -} - -type SFirewall struct { - Id string - CreationTimestamp time.Time - Name string - Description string - Network string - Priority int - SourceRanges []string - DestinationRanges []string - TargetServiceAccounts []string - TargetTags []string - Allowed []SFirewallAction - Denied []SFirewallAction - Direction string - Disabled bool - SelfLink string - Kind string -} - -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.GoogleTags - gvpc *SGlobalNetwork - - ServiceAccount string - Tag string -} - -func (self *SGoogleClient) GetFirewalls(network string, maxResults int, pageToken string) ([]SFirewall, error) { - firewalls := []SFirewall{} - params := map[string]string{"filter": "disabled = false"} - resource := "global/firewalls" - if len(network) > 0 { - params["filter"] = fmt.Sprintf(`(disabled = false) AND (network="%s")`, network) - } - return firewalls, self._ecsListAll("GET", resource, params, &firewalls) -} - -func (self *SGoogleClient) GetFirewall(id string) (*SFirewall, error) { - firewall := &SFirewall{} - return firewall, self.ecsGet("global/firewalls", id, firewall) -} - -func (firewall *SFirewall) _toRules(action secrules.TSecurityRuleAction) ([]cloudprovider.SecurityRule, error) { - rules := []cloudprovider.SecurityRule{} - list := firewall.Allowed - if action == secrules.SecurityRuleDeny { - list = firewall.Denied - } - for _, allow := range list { - rule := cloudprovider.SecurityRule{ - ExternalId: firewall.SelfLink, - SecurityRule: secrules.SecurityRule{ - Action: action, - Direction: secrules.DIR_IN, - Priority: firewall.Priority, - }, - } - if firewall.Direction == "EGRESS" { - rule.Direction = secrules.DIR_OUT - } - switch allow.IPProtocol { - case "tcp", "udp", "icmp": - rule.Protocol = allow.IPProtocol - case "all": - rule.Protocol = secrules.PROTO_ANY - default: - return nil, fmt.Errorf("unsupport protocol %s", allow.IPProtocol) - } - ipRanges := firewall.SourceRanges - if rule.Direction == secrules.DIR_OUT { - ipRanges = firewall.DestinationRanges - } - for _, ipRange := range ipRanges { - rule.ParseCIDR(ipRange) - ports := []int{} - for _, port := range allow.Ports { - if strings.Index(port, "-") > 0 { - port = strings.Replace(port, "0-", "1-", 1) - err := rule.ParsePorts(port) - if err != nil { - return nil, errors.Wrapf(err, "Parse port %s", port) - } - rules = append(rules, rule) - } else { - _port, err := strconv.Atoi(port) - if err != nil { - return nil, errors.Wrapf(err, "Atio port %s", port) - } - ports = append(ports, _port) - } - } - if len(ports) > 0 { - rule.Ports = ports - rule.PortStart = -1 - rule.PortEnd = -1 - rules = append(rules, rule) - } - if len(allow.Ports) == 0 { - rule.Ports = []int{} - rule.PortStart = -1 - rule.PortEnd = -1 - rules = append(rules, rule) - } - } - } - return rules, nil -} - -func (firewall *SFirewall) toRules() ([]cloudprovider.SecurityRule, error) { - rules := []cloudprovider.SecurityRule{} - _rules, err := firewall._toRules(secrules.SecurityRuleAllow) - if err != nil { - return nil, err - } - rules = append(rules, _rules...) - _rules, err = firewall._toRules(secrules.SecurityRuleDeny) - if err != nil { - return nil, err - } - rules = append(rules, _rules...) - return rules, nil -} - -func (secgroup *SSecurityGroup) GetId() string { - return secgroup.gvpc.GetGlobalId() -} - -func (secgroup *SSecurityGroup) GetGlobalId() string { - if len(secgroup.Tag) > 0 { - return fmt.Sprintf("%s/%s/%s", secgroup.GetId(), SECGROUP_TYPE_TAG, secgroup.Tag) - } - if len(secgroup.ServiceAccount) > 0 { - return fmt.Sprintf("%s/%s/%s", secgroup.GetId(), SECGROUP_TYPE_SERVICE_ACCOUNT, secgroup.ServiceAccount) - } - return secgroup.GetId() -} - -func (secgroup *SSecurityGroup) GetDescription() string { - return "" -} - -func (secgroup *SSecurityGroup) GetName() string { - if len(secgroup.Tag) > 0 { - return secgroup.Tag - } - if len(secgroup.ServiceAccount) > 0 { - return secgroup.ServiceAccount - } - return secgroup.gvpc.Name -} - -func (secgroup *SSecurityGroup) GetStatus() string { - return "" -} - -func (secgroup *SSecurityGroup) IsEmulated() bool { - return false -} - -func (secgroup *SSecurityGroup) Refresh() error { - return nil -} - -func (secgroup *SSecurityGroup) Delete() error { - rules, err := secgroup.GetRules() - if err != nil { - return errors.Wrap(err, "GetRules") - } - for _, rule := range rules { - err = secgroup.gvpc.client.DeleteSecgroupRule(rule) - if err != nil { - return errors.Wrapf(err, "DeleteSecgroupRule(%s)", rule.Description) - } - } - return nil -} - -func (secgroup *SSecurityGroup) GetProjectId() string { - return "" -} - -func (secgroup *SSecurityGroup) GetVpcId() string { - return secgroup.gvpc.GetGlobalId() -} - -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - _firewalls, err := self.gvpc.client.GetFirewalls(self.gvpc.SelfLink, 0, "") - if err != nil { - return nil, err - } - firewalls := []SFirewall{} - for _, firewall := range _firewalls { - if len(self.Tag) > 0 && utils.IsInStringArray(self.Tag, firewall.TargetTags) { - firewalls = append(firewalls, firewall) - } else if len(self.ServiceAccount) > 0 && utils.IsInStringArray(self.ServiceAccount, firewall.TargetServiceAccounts) { - firewalls = append(firewalls, firewall) - } else { - if len(self.Tag) == 0 && len(self.ServiceAccount) == 0 && len(firewall.TargetServiceAccounts) == 0 && len(firewall.TargetTags) == 0 { - firewalls = append(firewalls, firewall) - } - } - } - rules := []cloudprovider.SecurityRule{} - for _, firewall := range firewalls { - if firewall.Priority == 65535 { // skip 65535 rule, because it not work - continue - } - _rules, err := firewall.toRules() - if err != nil { - return nil, err - } - rules = append(rules, _rules...) - } - return rules, nil -} - -func (self *SGoogleClient) DeleteSecgroupRule(rule cloudprovider.SecurityRule) error { - firwall, err := self.GetFirewall(rule.ExternalId) - if err != nil { - return errors.Wrap(err, "region.GetFirewall") - } - currentRule, err := firwall.toRules() - if err != nil { - return errors.Wrap(err, "firwall.toRules") - } - if len(currentRule) > 1 { - for _, _rule := range currentRule { - if _rule.String() != rule.String() { - for _, tag := range firwall.TargetTags { - err = self.CreateSecurityGroupRule(_rule, firwall.Network, tag, "") - if err != nil { - return errors.Wrap(err, "region.CreateSecurityGroupRule") - } - } - for _, serviceAccount := range firwall.TargetServiceAccounts { - err = self.CreateSecurityGroupRule(_rule, firwall.Network, "", serviceAccount) - if err != nil { - return errors.Wrap(err, "region.CreateSecurityGroupRule") - } - } - if len(firwall.TargetTags)+len(firwall.TargetServiceAccounts) == 0 { - err = self.CreateSecurityGroupRule(_rule, firwall.Network, "", "") - if err != nil { - return errors.Wrap(err, "region.CreateSecurityGroupRule") - } - } - } - } - } - return self.ecsDelete(firwall.SelfLink, nil) -} - -func (secgroup *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - for _, r := range append(inDels, outDels...) { - err := secgroup.gvpc.client.DeleteSecgroupRule(r) - if err != nil { - return errors.Wrap(err, "DeleteSecgroupRule") - } - } - for _, r := range append(inAdds, outAdds...) { - err := secgroup.gvpc.client.CreateSecurityGroupRule(r, secgroup.gvpc.SelfLink, secgroup.Tag, secgroup.ServiceAccount) - if err != nil { - return errors.Wrapf(err, "CreateSecurityGroupRule(%s)", r.String()) - } - } - return nil -} - -func (region *SRegion) GetISecurityGroupById(id string) (cloudprovider.ICloudSecurityGroup, error) { - vpcs, err := region.GetIVpcs() - if err != nil { - return nil, errors.Wrap(err, "GetIVpcs") - } - - for _, vpc := range vpcs { - secgroups, err := vpc.GetISecurityGroups() - if err != nil { - return nil, errors.Wrap(err, "GetISecurityGroups") - } - for _, secgroup := range secgroups { - if secgroup.GetGlobalId() == id { - return secgroup, nil - } - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - ivpc, err := region.GetIVpcById(opts.VpcId) - if err != nil { - return nil, err - } - secgroups, err := ivpc.GetISecurityGroups() - if err != nil { - return nil, errors.Wrap(err, "ivpc.GetISecurityGroups") - } - for _, secgroup := range secgroups { - if strings.ToLower(secgroup.GetName()) == strings.ToLower(opts.Name) { - return secgroup, nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SGoogleClient) CreateSecurityGroupRule(rule cloudprovider.SecurityRule, vpcId string, tag string, serviceAccount string) error { - name := fmt.Sprintf("%s-%d", rule.String(), rule.Priority) - if len(tag) > 0 { - name = fmt.Sprintf("%s-%s", tag, name) - } - if len(serviceAccount) > 0 { - name = fmt.Sprintf("%s-%s", serviceAccount, name) - } - - body := map[string]interface{}{ - "name": strings.ToLower(name), - "priority": rule.Priority, - "network": vpcId, - "direction": "INGRESS", - } - if len(tag) > 0 { - body["targetTags"] = []string{strings.ToLower(tag)} - } - if len(serviceAccount) > 0 { - body["targetServiceAccounts"] = []string{serviceAccount} - } - if rule.Direction == secrules.DIR_OUT { - body["direction"] = "EGRESS" - } else { - body["sourceRanges"] = []string{rule.IPNet.String()} - } - - protocol := strings.ToLower(rule.Protocol) - if protocol == secrules.PROTO_ANY { - protocol = "all" - } - - ports := []string{} - if len(rule.Ports) > 0 { - for _, port := range rule.Ports { - ports = append(ports, fmt.Sprintf("%d", port)) - } - } else if rule.PortStart > 0 && rule.PortEnd > 0 { - if rule.PortStart == rule.PortEnd { - ports = append(ports, fmt.Sprintf("%d", rule.PortStart)) - } else { - ports = append(ports, fmt.Sprintf("%d-%d", rule.PortStart, rule.PortEnd)) - } - } - - actionInfo := []struct { - IPProtocol string - Ports []string - }{ - { - IPProtocol: protocol, - Ports: ports, - }, - } - - if rule.Action == secrules.SecurityRuleDeny { - body["denied"] = actionInfo - } else { - body["allowed"] = actionInfo - } - - firwall := &SFirewall{} - err := self.Insert("global/firewalls", jsonutils.Marshal(body), firwall) - if err != nil { - if strings.Index(err.Error(), "already exists") >= 0 { - return nil - } - return errors.Wrap(err, "region.Insert") - } - return nil -} - -func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - gvpc, err := region.client.GetGlobalNetwork(conf.VpcId) - if err != nil { - return nil, errors.Wrapf(err, "region.GetIVpcById(%s)", conf.VpcId) - } - - secgroup := &SSecurityGroup{gvpc: gvpc, Tag: strings.ToLower(conf.Name)} - return secgroup, nil -} diff --git a/pkg/multicloud/google/shell/bigquery.go b/pkg/multicloud/google/shell/bigquery.go deleted file mode 100644 index ce04a6d952..0000000000 --- a/pkg/multicloud/google/shell/bigquery.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type BigQueryOptions struct { - SQL string `help:"sql to query"` - } - shellutils.R(&BigQueryOptions{}, "gcp-bigquery", "Exec bigquery", func(cli *google.SRegion, args *BigQueryOptions) error { - results, err := cli.BigQuery(args.SQL) - if err != nil { - return err - } - - printList(results, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/google/shell/bucket.go b/pkg/multicloud/google/shell/bucket.go deleted file mode 100644 index c75c59b42a..0000000000 --- a/pkg/multicloud/google/shell/bucket.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type BucketListOptions struct { - MaxResults int - PageToken string - } - - shellutils.R(&BucketListOptions{}, "bucket-list", "List buckets", func(cli *google.SRegion, args *BucketListOptions) error { - buckets, err := cli.GetBuckets(args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(buckets, 0, 0, 0, nil) - return nil - }) - - type BucketCreateOptions struct { - NAME string - StorageClass string `choices:"STANDARD|NEARLINE|COLDLINE"` - Acl string `choices:"private|authenticated-read|public-read|public-read-write"` - } - - shellutils.R(&BucketCreateOptions{}, "bucket-create", "Create buckets", func(cli *google.SRegion, args *BucketCreateOptions) error { - bucket, err := cli.CreateBucket(args.NAME, args.StorageClass, cloudprovider.TBucketACLType(args.Acl)) - if err != nil { - return err - } - printObject(bucket) - return nil - }) - - type BucketNameOptions struct { - NAME string - } - - shellutils.R(&BucketNameOptions{}, "bucket-show", "Show bucket", func(cli *google.SRegion, args *BucketNameOptions) error { - bucket, err := cli.GetBucket(args.NAME) - if err != nil { - return err - } - printObject(bucket) - return nil - }) - - shellutils.R(&BucketNameOptions{}, "bucket-delete", "Delete bucket", func(cli *google.SRegion, args *BucketNameOptions) error { - return cli.DeleteBucket(args.NAME) - }) - - shellutils.R(&BucketNameOptions{}, "bucket-acl-list", "Show bucket acls", func(cli *google.SRegion, args *BucketNameOptions) error { - acls, err := cli.GetBucketAcl(args.NAME) - if err != nil { - return err - } - printList(acls, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&BucketNameOptions{}, "bucket-iam-show", "Show bucket iam", func(cli *google.SRegion, args *BucketNameOptions) error { - iam, err := cli.GetBucketIam(args.NAME) - if err != nil { - return err - } - printObject(iam) - return nil - }) - - type BucketAclOptions struct { - BUCKET string - ACL string - } - - shellutils.R(&BucketAclOptions{}, "bucket-acl-set", "Set bucket acl", func(cli *google.SRegion, args *BucketAclOptions) error { - return cli.SetBucketAcl(args.BUCKET, cloudprovider.TBucketACLType(args.ACL)) - }) - -} diff --git a/pkg/multicloud/google/shell/cloudbuild.go b/pkg/multicloud/google/shell/cloudbuild.go deleted file mode 100644 index 4c62b62f58..0000000000 --- a/pkg/multicloud/google/shell/cloudbuild.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CloudbuildOperationShowOptions struct { - NAME string - } - - shellutils.R(&CloudbuildOperationShowOptions{}, "cloud-build-operation-show", "Show cloudbuild operation", func(cli *google.SRegion, args *CloudbuildOperationShowOptions) error { - operation, err := cli.GetCloudbuildOperation(args.NAME) - if err != nil { - return err - } - printObject(operation) - return nil - }) -} diff --git a/pkg/multicloud/google/shell/dbinstance.go b/pkg/multicloud/google/shell/dbinstance.go deleted file mode 100644 index abb5152f2a..0000000000 --- a/pkg/multicloud/google/shell/dbinstance.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceListOptions struct { - MaxResults int - PageToken string - } - shellutils.R(&DBInstanceListOptions{}, "dbinstance-list", "List dbinstances", func(cli *google.SRegion, args *DBInstanceListOptions) error { - instances, err := cli.GetDBInstances(args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(instances, 0, 0, 0, nil) - return nil - }) - - type DBInstanceIdOptions struct { - INSTANCE string - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-show", "Show dbinstance", func(cli *google.SRegion, args *DBInstanceIdOptions) error { - instance, err := cli.GetDBInstance(args.INSTANCE) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-close-public-connection", "Close dbinstance public connection", func(cli *google.SRegion, args *DBInstanceIdOptions) error { - return cli.DBInstancePublicConnectionOperation(args.INSTANCE, false) - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-open-public-connection", "Open dbinstance public connection", func(cli *google.SRegion, args *DBInstanceIdOptions) error { - return cli.DBInstancePublicConnectionOperation(args.INSTANCE, true) - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-delete", "Delete dbinstance", func(cli *google.SRegion, args *DBInstanceIdOptions) error { - return cli.DeleteDBInstance(args.INSTANCE) - }) - - type DBInstanceCreateOptions struct { - NAME string - ENGINE string - DATABASEVERSION string - Category string `default:"Zonal" choices:"Zonal|Regional"` - INSTANCE_TYPE string - STORAGE_TYPE string - DISK_SIZE_GB int - VpcId string - ZoneId string - Password string - } - - shellutils.R(&DBInstanceCreateOptions{}, "dbinstance-create", "Create dbinstance", func(cli *google.SRegion, args *DBInstanceCreateOptions) error { - instance, err := cli.CreateRds(args.NAME, args.ENGINE, args.DATABASEVERSION, args.Category, args.INSTANCE_TYPE, args.STORAGE_TYPE, args.DISK_SIZE_GB, args.VpcId, args.ZoneId, args.Password) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - type DBInstanceChangeConfigOptions struct { - INSTANCE string - DiskSizeGb int - InstnaceType string - } - - shellutils.R(&DBInstanceChangeConfigOptions{}, "dbinstance-change-config", "Change dbinstance config", func(cli *google.SRegion, args *DBInstanceChangeConfigOptions) error { - return cli.ChangeDBInstanceConfig(args.INSTANCE, args.DiskSizeGb, args.InstnaceType) - }) - - type DBInstanceRecoveryOptions struct { - NAME string - TARGET string - BACKUP string - } - - shellutils.R(&DBInstanceRecoveryOptions{}, "dbinstance-restore", "restore dbinstance from backup", func(cli *google.SRegion, args *DBInstanceRecoveryOptions) error { - return cli.RecoverFromBackup(args.NAME, args.TARGET, args.BACKUP) - }) - -} diff --git a/pkg/multicloud/google/shell/dbinstance_account.go b/pkg/multicloud/google/shell/dbinstance_account.go deleted file mode 100644 index 9e9e5b166e..0000000000 --- a/pkg/multicloud/google/shell/dbinstance_account.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceAccountListOptions struct { - RDS string - } - shellutils.R(&DBInstanceAccountListOptions{}, "dbinstance-account-list", "List dbinstance account", func(cli *google.SRegion, args *DBInstanceAccountListOptions) error { - accounts, err := cli.GetDBInstanceAccounts(args.RDS) - if err != nil { - return err - } - printList(accounts, 0, 0, 0, nil) - return nil - }) - - type DBInstanceAccountCreateOptions struct { - RDS string - NAME string - PASSWORD string - Host string - } - shellutils.R(&DBInstanceAccountCreateOptions{}, "dbinstance-account-create", "Create dbinstance account", func(cli *google.SRegion, args *DBInstanceAccountCreateOptions) error { - return cli.CreateDBInstanceAccount(args.RDS, args.NAME, args.PASSWORD, args.Host) - }) -} diff --git a/pkg/multicloud/google/shell/dbinstance_backup.go b/pkg/multicloud/google/shell/dbinstance_backup.go deleted file mode 100644 index 58ed4aef25..0000000000 --- a/pkg/multicloud/google/shell/dbinstance_backup.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceBackupListOptions struct { - RDS string - } - shellutils.R(&DBInstanceBackupListOptions{}, "dbinstance-backup-list", "List dbinstance backup", func(cli *google.SRegion, args *DBInstanceBackupListOptions) error { - backups, err := cli.GetDBInstanceBackups(args.RDS) - if err != nil { - return err - } - printList(backups, 0, 0, 0, nil) - return nil - }) - - type DBInstanceBackupCreateOptions struct { - RDS string - NAME string - Desc string - } - - shellutils.R(&DBInstanceBackupCreateOptions{}, "dbinstance-backup-create", "Create dbinstance backup", func(cli *google.SRegion, args *DBInstanceBackupCreateOptions) error { - return cli.CreateDBInstanceBackup(args.RDS, args.NAME, args.Desc) - }) -} diff --git a/pkg/multicloud/google/shell/dbinstance_database.go b/pkg/multicloud/google/shell/dbinstance_database.go deleted file mode 100644 index 217b13f019..0000000000 --- a/pkg/multicloud/google/shell/dbinstance_database.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceDatabaseListOptions struct { - RDS string - } - shellutils.R(&DBInstanceDatabaseListOptions{}, "dbinstance-database-list", "List dbinstance database", func(cli *google.SRegion, args *DBInstanceDatabaseListOptions) error { - databases, err := cli.GetDBInstanceDatabases(args.RDS) - if err != nil { - return err - } - printList(databases, 0, 0, 0, nil) - return nil - }) - - type DBInstanceDatabaseCreateOptions struct { - RDS string - NAME string - CHARSET string - } - - shellutils.R(&DBInstanceDatabaseCreateOptions{}, "dbinstance-database-create", "Create dbinstance database", func(cli *google.SRegion, args *DBInstanceDatabaseCreateOptions) error { - return cli.CreateDatabase(args.RDS, args.NAME, args.CHARSET) - }) - -} diff --git a/pkg/multicloud/google/shell/disk.go b/pkg/multicloud/google/shell/disk.go deleted file mode 100644 index 7e818220f4..0000000000 --- a/pkg/multicloud/google/shell/disk.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - ZONE string - StorageType string - MaxResults int - PageToken string - } - shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *google.SRegion, args *DiskListOptions) error { - disks, err := cli.GetDisks(args.ZONE, args.StorageType, args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(disks, 0, 0, 0, nil) - return nil - }) - - type DiskIdOptions struct { - ID string - } - shellutils.R(&DiskIdOptions{}, "disk-show", "Show disk", func(cli *google.SRegion, args *DiskIdOptions) error { - disk, err := cli.GetDisk(args.ID) - if err != nil { - return err - } - printObject(disk) - return nil - }) - - shellutils.R(&DiskIdOptions{}, "disk-delete", "Delete disk", func(cli *google.SRegion, args *DiskIdOptions) error { - return cli.Delete(args.ID) - }) - - type DiskCreateOptions struct { - NAME string - Desc string - ZONE string - SIZE_GB int - Image string - STORAGE_TYPE string `choices:"pd-standard|pd-ssd"` - } - - shellutils.R(&DiskCreateOptions{}, "disk-create", "Create disks", func(cli *google.SRegion, args *DiskCreateOptions) error { - disk, err := cli.CreateDisk(args.NAME, args.SIZE_GB, args.ZONE, args.STORAGE_TYPE, args.Image, args.Desc) - if err != nil { - return err - } - printObject(disk) - return nil - }) - - type DiskResizeOptions struct { - ID string - SIZE_GB int - } - - shellutils.R(&DiskResizeOptions{}, "disk-resize", "Resize disk", func(cli *google.SRegion, args *DiskResizeOptions) error { - return cli.ResizeDisk(args.ID, args.SIZE_GB) - }) - - type RegionDiskListOptions struct { - StorageType string - MaxResults int - PageToken string - } - shellutils.R(&RegionDiskListOptions{}, "region-disk-list", "List region disks", func(cli *google.SRegion, args *RegionDiskListOptions) error { - disks, err := cli.GetRegionDisks(args.StorageType, args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(disks, 0, 0, 0, nil) - return nil - }) - - type RegionDiskShowOptions struct { - ID string - } - shellutils.R(&RegionDiskShowOptions{}, "region-disk-show", "Show region disk", func(cli *google.SRegion, args *RegionDiskShowOptions) error { - disk, err := cli.GetRegionDisk(args.ID) - if err != nil { - return err - } - printObject(disk) - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/doc.go b/pkg/multicloud/google/shell/doc.go deleted file mode 100644 index 0cfa0144c9..0000000000 --- a/pkg/multicloud/google/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/google/shell" diff --git a/pkg/multicloud/google/shell/eip.go b/pkg/multicloud/google/shell/eip.go deleted file mode 100644 index f1f58bd99f..0000000000 --- a/pkg/multicloud/google/shell/eip.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - Address string - MaxResults int - PageToken string - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *google.SRegion, args *EipListOptions) error { - eips, err := cli.GetEips(args.Address, args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(eips, 0, 0, 0, nil) - return nil - }) - - type EipIdOptions struct { - ID string - } - shellutils.R(&EipIdOptions{}, "eip-show", "Show eip", func(cli *google.SRegion, args *EipIdOptions) error { - eip, err := cli.GetEip(args.ID) - if err != nil { - return err - } - printObject(eip) - return nil - }) - - shellutils.R(&EipIdOptions{}, "eip-delete", "Delete eip", func(cli *google.SRegion, args *EipIdOptions) error { - return cli.Delete(args.ID) - }) - - type EipCreateOptions struct { - NAME string - Desc string - } - - shellutils.R(&EipCreateOptions{}, "eip-create", "Create eip", func(cli *google.SRegion, args *EipCreateOptions) error { - eip, err := cli.CreateEip(args.NAME, args.Desc) - if err != nil { - return err - } - printObject(eip) - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/firewall.go b/pkg/multicloud/google/shell/firewall.go deleted file mode 100644 index bcb7afbe8a..0000000000 --- a/pkg/multicloud/google/shell/firewall.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type FirewallListOptions struct { - Network string - MaxResults int - PageToken string - } - shellutils.R(&FirewallListOptions{}, "firewall-list", "List firewalls", func(cli *google.SRegion, args *FirewallListOptions) error { - firewalls, err := cli.GetClient().GetFirewalls(args.Network, args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(firewalls, 0, 0, 0, nil) - return nil - }) - - type FirewallShowOptions struct { - ID string - } - shellutils.R(&FirewallShowOptions{}, "firewall-show", "Show firewall", func(cli *google.SRegion, args *FirewallShowOptions) error { - firewall, err := cli.GetClient().GetFirewall(args.ID) - if err != nil { - return err - } - printObject(firewall) - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/globalnetwork.go b/pkg/multicloud/google/shell/globalnetwork.go deleted file mode 100644 index 8059bf073e..0000000000 --- a/pkg/multicloud/google/shell/globalnetwork.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type GlobalNetworkListOptions struct { - MaxResults int - PageToken string - } - shellutils.R(&GlobalNetworkListOptions{}, "global-network-list", "List globalnetworks", func(cli *google.SRegion, args *GlobalNetworkListOptions) error { - globalnetworks, err := cli.GetClient().GetGlobalNetworks(args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(globalnetworks, 0, 0, 0, nil) - return nil - }) - - type GlobalNetworkShowOptions struct { - ID string - } - shellutils.R(&GlobalNetworkShowOptions{}, "global-network-show", "Show globalnetwork", func(cli *google.SRegion, args *GlobalNetworkShowOptions) error { - globalnetwork, err := cli.GetClient().GetGlobalNetwork(args.ID) - if err != nil { - return err - } - printObject(globalnetwork) - return nil - }) - - type GlobalNetworkCreateOptions struct { - NAME string - Desc string - } - - shellutils.R(&GlobalNetworkCreateOptions{}, "global-network-create", "Create globalnetwork", func(cli *google.SRegion, args *GlobalNetworkCreateOptions) error { - globalnetwork, err := cli.GetClient().CreateGlobalNetwork(args.NAME, args.Desc) - if err != nil { - return err - } - printObject(globalnetwork) - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/iam.go b/pkg/multicloud/google/shell/iam.go deleted file mode 100644 index 1f2edec701..0000000000 --- a/pkg/multicloud/google/shell/iam.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - - type RoleShowOptions struct { - } - shellutils.R(&RoleShowOptions{}, "iam-policy-show", "Show project policy", func(cli *google.SRegion, args *RoleShowOptions) error { - policy, err := cli.GetClient().GetIamPolicy() - if err != nil { - return err - } - printObject(policy) - return nil - }) - - type ClouduserListOptions struct { - } - shellutils.R(&ClouduserListOptions{}, "cloud-user-list", "List cloudusers", func(cli *google.SRegion, args *ClouduserListOptions) error { - policy, err := cli.GetClient().GetIamPolicy() - if err != nil { - return err - } - users, err := policy.GetICloudusers() - if err != nil { - return err - } - printList(users, 0, 0, 0, nil) - return nil - }) - - type RoleListOptions struct { - ProjectId string - } - - shellutils.R(&RoleListOptions{}, "cloud-role-list", "List roles", func(cli *google.SRegion, args *RoleListOptions) error { - roles, err := cli.GetClient().GetRoles(args.ProjectId) - if err != nil { - return err - } - printList(roles, 0, 0, 0, nil) - return nil - }) - - type RoleIdOption struct { - ID string - } - - shellutils.R(&RoleIdOption{}, "cloud-role-show", "Show role details", func(cli *google.SRegion, args *RoleIdOption) error { - role, err := cli.GetClient().GetRole(args.ID) - if err != nil { - return err - } - printObject(role) - return nil - }) - - type ClouduserOptions struct { - USER string - ROLES []string - } - - shellutils.R(&ClouduserOptions{}, "cloud-user-add", "Add user to project", func(cli *google.SRegion, args *ClouduserOptions) error { - policy, err := cli.GetClient().GetIamPolicy() - if err != nil { - return err - } - return policy.AttachPolicy(args.USER, args.ROLES) - }) - - type ClouduserDetachRoleOptions struct { - USER string - ROLE string - } - - shellutils.R(&ClouduserDetachRoleOptions{}, "cloud-user-detach-role", "Detach role for clouduser", func(cli *google.SRegion, args *ClouduserDetachRoleOptions) error { - policy, err := cli.GetClient().GetIamPolicy() - if err != nil { - return err - } - return policy.DetachPolicy(args.USER, args.ROLE) - }) - - type ClouduserDeleteOptions struct { - USER string - } - - shellutils.R(&ClouduserDeleteOptions{}, "cloud-user-delete", "Delete clouduseruser from project", func(cli *google.SRegion, args *ClouduserDeleteOptions) error { - policy, err := cli.GetClient().GetIamPolicy() - if err != nil { - return err - } - return policy.DeleteUser(args.USER) - }) - - type RoleDeleteOptions struct { - NAME string - } - - shellutils.R(&RoleDeleteOptions{}, "cloud-role-delete", "Delete role", func(cli *google.SRegion, args *RoleDeleteOptions) error { - return cli.GetClient().DeleteRole(args.NAME) - }) - - type RoleCreateOptons struct { - NAME string - Desc string - PERMISSIONS []string - } - - shellutils.R(&RoleCreateOptons{}, "cloud-role-create", "Create role", func(cli *google.SRegion, args *RoleCreateOptons) error { - role, err := cli.GetClient().CreateRole(args.PERMISSIONS, args.NAME, args.Desc) - if err != nil { - return err - } - printObject(role) - return nil - }) - - type RoleUpdateOptions struct { - ID string - PERMISSIONS []string - } - - shellutils.R(&RoleUpdateOptions{}, "cloud-role-update", "Update role", func(cli *google.SRegion, args *RoleUpdateOptions) error { - return cli.GetClient().UpdateRole(args.ID, args.PERMISSIONS) - }) - -} diff --git a/pkg/multicloud/google/shell/image.go b/pkg/multicloud/google/shell/image.go deleted file mode 100644 index ff3cf9d197..0000000000 --- a/pkg/multicloud/google/shell/image.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - Project string `choices:"centos-cloud|ubuntu-os-cloud|windows-cloud|windows-sql-cloud|suse-cloud|suse-sap-cloud|rhel-cloud|rhel-sap-cloud|cos-cloud|debian-cloud"` - MaxResults int - PageToken string - } - shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *google.SRegion, args *ImageListOptions) error { - images, err := cli.GetImages(args.Project, args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(images, 0, 0, 0, nil) - return nil - }) - - type ImageShowOptions struct { - ID string - } - shellutils.R(&ImageShowOptions{}, "image-show", "Show image", func(cli *google.SRegion, args *ImageShowOptions) error { - image, err := cli.GetImage(args.ID) - if err != nil { - return err - } - printObject(image) - return nil - }) - - type ImageCreateOptions struct { - NAME string - Desc string - BUCKET string - FILE string - } - - shellutils.R(&ImageCreateOptions{}, "image-create", "Create image", func(cli *google.SRegion, args *ImageCreateOptions) error { - image, err := cli.CreateImage(args.NAME, args.Desc, args.BUCKET, args.FILE) - if err != nil { - return err - } - printObject(image) - return nil - }) -} diff --git a/pkg/multicloud/google/shell/instance.go b/pkg/multicloud/google/shell/instance.go deleted file mode 100644 index a1a0e4cbf6..0000000000 --- a/pkg/multicloud/google/shell/instance.go +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "strings" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - ZONE string - MaxResults int - PageToken string - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List instances", func(cli *google.SRegion, args *InstanceListOptions) error { - instances, err := cli.GetInstances(args.ZONE, args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(instances, 0, 0, 0, nil) - return nil - }) - - type InstanceIdOptions struct { - ID string - } - shellutils.R(&InstanceIdOptions{}, "instance-show", "Show instance", func(cli *google.SRegion, args *InstanceIdOptions) error { - instance, err := cli.GetInstance(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - shellutils.R(&InstanceIdOptions{}, "instance-delete", "Delete instance", func(cli *google.SRegion, args *InstanceIdOptions) error { - return cli.Delete(args.ID) - }) - - shellutils.R(&InstanceIdOptions{}, "instance-start", "Start instance", func(cli *google.SRegion, args *InstanceIdOptions) error { - return cli.StartInstance(args.ID) - }) - - shellutils.R(&InstanceIdOptions{}, "instance-stop", "Stop instance", func(cli *google.SRegion, args *InstanceIdOptions) error { - return cli.StopInstance(args.ID) - }) - - shellutils.R(&InstanceIdOptions{}, "instance-reset", "Reset instance", func(cli *google.SRegion, args *InstanceIdOptions) error { - return cli.ResetInstance(args.ID) - }) - - type InstanceEipOptions struct { - ID string - EIP string `help:"eip address"` - } - - shellutils.R(&InstanceEipOptions{}, "instance-dissociate-eip", "Dissociate instance eip", func(cli *google.SRegion, args *InstanceEipOptions) error { - return cli.DissociateInstanceEip(args.ID, args.EIP) - }) - - shellutils.R(&InstanceEipOptions{}, "instance-associate-eip", "Associate instance eip", func(cli *google.SRegion, args *InstanceEipOptions) error { - return cli.AssociateInstanceEip(args.ID, args.EIP) - }) - - type InstanceDetachDiskOptions struct { - ID string - DeviceName string - } - - shellutils.R(&InstanceDetachDiskOptions{}, "instance-detach-disk", "Detach instance disk", func(cli *google.SRegion, args *InstanceDetachDiskOptions) error { - return cli.DetachDisk(args.ID, args.DeviceName) - }) - - type InstanceSetPublicKeyOptions struct { - ID string - PublicKey string - } - - shellutils.R(&InstanceSetPublicKeyOptions{}, "instance-set-publickey", "Set instance public key", func(cli *google.SRegion, args *InstanceSetPublicKeyOptions) error { - instance, err := cli.GetInstance(args.ID) - if err != nil { - return errors.Wrap(err, "cli.GetInstance") - } - items := []google.SMetadataItem{} - for _, item := range instance.Metadata.Items { - if item.Key != google.METADATA_SSH_KEYS { - items = append(items, item) - } - } - if len(args.PublicKey) > 0 { - items = append(items, google.SMetadataItem{Key: google.METADATA_SSH_KEYS, Value: "root:" + args.PublicKey}) - } - instance.Metadata.Items = items - return cli.SetMetadata(args.ID, instance.Metadata) - }) - - type InstanceAttachDiskOptions struct { - ID string - DISK string - Boot bool - } - - type InstanceSerialOutput struct { - ID string - PORT int - } - - shellutils.R(&InstanceSerialOutput{}, "instance-serial-output", "Get instance serial output", func(cli *google.SRegion, args *InstanceSerialOutput) error { - content, err := cli.GetSerialPortOutput(args.ID, args.PORT) - if err != nil { - return err - } - fmt.Printf("content: %s\n", content) - return nil - }) - - shellutils.R(&InstanceAttachDiskOptions{}, "instance-attach-disk", "Attach instance disk", func(cli *google.SRegion, args *InstanceAttachDiskOptions) error { - return cli.AttachDisk(args.ID, args.DISK, args.Boot) - }) - - type InstanceRebuildRootOptions struct { - ID string - IMAGE string - DiskSizeGb int - } - - shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Rebuild instance root", func(cli *google.SRegion, args *InstanceRebuildRootOptions) error { - diskId, err := cli.RebuildRoot(args.ID, args.IMAGE, args.DiskSizeGb) - if err != nil { - return err - } - fmt.Println(diskId) - return nil - }) - - type InstanceChangeConfigOptions struct { - ID string - ZONE string - InstanceType string - Cpu int - MemoryMb int - } - - shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Change instance config", func(cli *google.SRegion, args *InstanceChangeConfigOptions) error { - return cli.ChangeInstanceConfig(args.ID, args.ZONE, args.InstanceType, args.Cpu, args.MemoryMb) - }) - - type InstanceCreateOptions struct { - NAME string - ZONE string - IMAGE string - InstanceType string - Cpu int - MemoryMb int - NETWORK string - IpAddr string - Desc string - DISKS []string `nargs:"+"` - } - - shellutils.R(&InstanceCreateOptions{}, "instance-create", "Create instance", func(cli *google.SRegion, args *InstanceCreateOptions) error { - instance, err := cli.CreateInstance(args.ZONE, args.NAME, args.Desc, args.InstanceType, args.Cpu, args.MemoryMb, args.NETWORK, args.IpAddr, args.IMAGE, args.DISKS) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - type InstanceSaveImageOptions struct { - DISK_ID string `help:"Instance System disk ID"` - IMAGE_NAME string `help:"Image name"` - Notes string `hlep:"Image desc"` - } - shellutils.R(&InstanceSaveImageOptions{}, "instance-save-image", "Save instance to image", func(cli *google.SRegion, args *InstanceSaveImageOptions) error { - opts := cloudprovider.SaveImageOptions{ - Name: args.IMAGE_NAME, - Notes: args.Notes, - } - image, err := cli.SaveImage(args.DISK_ID, &opts) - if err != nil { - return err - } - printObject(image) - return nil - }) - - type InstanceSetTagsOptions struct { - ID string `help:"Instance ID"` - Tags []string - } - shellutils.R(&InstanceSetTagsOptions{}, "instance-set-tags", "get intance metadata", func(cli *google.SRegion, args *InstanceSetTagsOptions) error { - tags := map[string]string{} - for i := range args.Tags { - splited := strings.Split(args.Tags[i], "=") - if len(splited) == 2 { - tags[splited[0]] = splited[1] - } - } - instance, err := cli.GetInstance(args.ID) - if err != nil { - return errors.Wrap(err, "cli.GetInstance") - } - err = cli.SetLabels(args.ID, tags, instance.LabelFingerprint) - if err != nil { - return err - } - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/loadbalancer.go b/pkg/multicloud/google/shell/loadbalancer.go deleted file mode 100644 index b8c9a311fd..0000000000 --- a/pkg/multicloud/google/shell/loadbalancer.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElbListOptions struct { - } - shellutils.R(&ElbListOptions{}, "lb-list", "List loadbalancers", func(cli *google.SRegion, args *ElbListOptions) error { - elbs, err := cli.GetRegionalLoadbalancers() - if err != nil { - return err - } - - printList(elbs, len(elbs), 0, 0, []string{}) - return nil - }) - - type ElbShowOptions struct { - RESOURCEID string `json:"resourceid"` - } - shellutils.R(&ElbShowOptions{}, "lb-bss", "List all loadbalancer backend services", func(cli *google.SRegion, args *ElbShowOptions) error { - lb, err := cli.GetLoadbalancer(args.RESOURCEID) - if err != nil { - return err - } - - elbs, err := lb.GetBackendServices() - if err != nil { - return err - } - - printList(elbs, len(elbs), 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElbShowOptions{}, "lb-frs", "List all loadbalancer forward rules", func(cli *google.SRegion, args *ElbShowOptions) error { - lb, err := cli.GetLoadbalancer(args.RESOURCEID) - if err != nil { - return err - } - - elbs, err := lb.GetForwardingRules() - if err != nil { - return err - } - - printList(elbs, len(elbs), 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElbShowOptions{}, "lb-http", "List loadbalancer https proxies", func(cli *google.SRegion, args *ElbShowOptions) error { - elb, err := cli.GetLoadbalancer(args.RESOURCEID) - if err != nil { - return err - } - - hps, e := elb.GetTargetHttpProxies() - if e != nil { - return e - } - printList(hps, len(hps), 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElbShowOptions{}, "lb-https", "List loadbalancer https proxies", func(cli *google.SRegion, args *ElbShowOptions) error { - elb, err := cli.GetLoadbalancer(args.RESOURCEID) - if err != nil { - return err - } - - hps, e := elb.GetTargetHttpsProxies() - if e != nil { - return e - } - printList(hps, len(hps), 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElbShowOptions{}, "lb-igs", "List all loadbalancer instance groups", func(cli *google.SRegion, args *ElbShowOptions) error { - elb, err := cli.GetLoadbalancer(args.RESOURCEID) - if err != nil { - return err - } - - hps, e := elb.GetInstanceGroups() - if e != nil { - return e - } - printList(hps, len(hps), 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElbShowOptions{}, "lbl-list", "List all loadbalancer listeners", func(cli *google.SRegion, args *ElbShowOptions) error { - elb, err := cli.GetLoadbalancer(args.RESOURCEID) - if err != nil { - return err - } - - hps, e := elb.GetLoadbalancerListeners() - if e != nil { - return e - } - printList(hps, len(hps), 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElbShowOptions{}, "lblr-list", "List all loadbalancer listener rules", func(cli *google.SRegion, args *ElbShowOptions) error { - elb, err := cli.GetLoadbalancer(args.RESOURCEID) - if err != nil { - return err - } - - hps, e := elb.GetLoadbalancerListeners() - if e != nil { - return e - } - - rules := make([]google.SLoadbalancerListenerRule, 0) - - for i := range hps { - _rules, ee := hps[i].GetLoadbalancerListenerRules() - if e != nil { - return ee - } - - rules = append(rules, _rules...) - } - - printList(rules, len(rules), 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElbShowOptions{}, "lbbg-list", "List all loadbalancer backendgroups", func(cli *google.SRegion, args *ElbShowOptions) error { - lb, err := cli.GetLoadbalancer(args.RESOURCEID) - if err != nil { - return err - } - - lbbg, e := lb.GetLoadbalancerBackendGroups() - if e != nil { - return e - } - - printList(lbbg, len(lbbg), 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElbShowOptions{}, "lbb-list", "List all loadbalancer backends", func(cli *google.SRegion, args *ElbShowOptions) error { - lb, err := cli.GetLoadbalancer(args.RESOURCEID) - if err != nil { - return err - } - - lbbg, e := lb.GetLoadbalancerBackendGroups() - if e != nil { - return e - } - - lbbs := make([]google.SLoadbalancerBackend, 0) - for i := range lbbg { - backends, err := lbbg[i].GetLoadbalancerBackends() - if err != nil { - return err - } - - lbbs = append(lbbs, backends...) - } - - printList(lbbs, len(lbbs), 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElbShowOptions{}, "lbhc-list", "List all loadbalancer health checks", func(cli *google.SRegion, args *ElbShowOptions) error { - lb, err := cli.GetLoadbalancer(args.RESOURCEID) - if err != nil { - return err - } - - hcs, e := lb.GetHealthChecks() - if e != nil { - return e - } - - printList(hcs, len(hcs), 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElbListOptions{}, "cert-list", "List region certificates", func(cli *google.SRegion, args *ElbListOptions) error { - certs, err := cli.GetRegionalSslCertificates("") - if err != nil { - return err - } - - printList(certs, len(certs), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/google/shell/machinetype.go b/pkg/multicloud/google/shell/machinetype.go deleted file mode 100644 index 243797fd82..0000000000 --- a/pkg/multicloud/google/shell/machinetype.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type MachineTypeListOptions struct { - ZONE string - MaxResults int - PageToken string - } - shellutils.R(&MachineTypeListOptions{}, "machine-type-list", "List machinetypes", func(cli *google.SRegion, args *MachineTypeListOptions) error { - machinetypes, err := cli.GetMachineTypes(args.ZONE, args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(machinetypes, 0, 0, 0, nil) - return nil - }) - - type MachineTypeShowOptions struct { - ID string - } - shellutils.R(&MachineTypeShowOptions{}, "machine-type-show", "Show machinetype", func(cli *google.SRegion, args *MachineTypeShowOptions) error { - machinetype, err := cli.GetMachineType(args.ID) - if err != nil { - return err - } - printObject(machinetype) - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/monitor.go b/pkg/multicloud/google/shell/monitor.go deleted file mode 100644 index 187aee0b4d..0000000000 --- a/pkg/multicloud/google/shell/monitor.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics", func(cli *google.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric: %s %s %s", metrics[i].Id, metrics[i].MetricType, metrics[i].Unit) - printList(metrics[i].Values, len(metrics[i].Values), 0, 0, []string{}) - } - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/network.go b/pkg/multicloud/google/shell/network.go deleted file mode 100644 index a8cbd7eeb6..0000000000 --- a/pkg/multicloud/google/shell/network.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkListOptions struct { - } - shellutils.R(&NetworkListOptions{}, "vpc-list", "List networks", func(cli *google.SRegion, args *NetworkListOptions) error { - networks, err := cli.GetVpcs() - if err != nil { - return err - } - printList(networks, 0, 0, 0, nil) - return nil - }) - - type NetworkIdOptions struct { - ID string - } - - shellutils.R(&NetworkIdOptions{}, "vpc-show", "Show network", func(cli *google.SRegion, args *NetworkIdOptions) error { - vpc, err := cli.GetVpc(args.ID) - if err != nil { - return err - } - printObject(vpc) - return nil - }) - - shellutils.R(&NetworkIdOptions{}, "vpc-delete", "Delete network", func(cli *google.SRegion, args *NetworkIdOptions) error { - return cli.Delete(args.ID) - }) - - type NetworkCreateOptions struct { - NAME string - VPC string - CIDR string - Desc string - } - - shellutils.R(&NetworkCreateOptions{}, "vpc-create", "Create network", func(cli *google.SRegion, args *NetworkCreateOptions) error { - network, err := cli.CreateVpc(args.NAME, args.VPC, args.CIDR, args.Desc) - if err != nil { - return err - } - printObject(network) - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/object.go b/pkg/multicloud/google/shell/object.go deleted file mode 100644 index dc61c74e64..0000000000 --- a/pkg/multicloud/google/shell/object.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "time" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ObjectPutOptions struct { - BUCKET string - FILE string - ContentType string - StorageType string `choices:"STANDARD|NEARLINE|COLDLINE|ARCHIVE"` - Acl string `choices:"private|public-read|public-read-write|authenticated-read"` - } - - shellutils.R(&ObjectPutOptions{}, "object-upload", "Upload object to buckets", func(cli *google.SRegion, args *ObjectPutOptions) error { - file, err := os.Open(args.FILE) - if err != nil { - return errors.Wrap(err, "so.Open") - } - stat, err := file.Stat() - if err != nil { - return errors.Wrap(err, "file.Stat") - } - header := http.Header{} - if len(args.ContentType) > 0 { - header.Set("Content-Type", args.ContentType) - } - if stat.Size() <= cloudprovider.MAX_PUT_OBJECT_SIZEBYTES { - return cli.PutObject(args.BUCKET, args.FILE, file, stat.Size(), cloudprovider.TBucketACLType(args.Acl), header) - } - uploadId, err := cli.NewMultipartUpload(args.BUCKET, args.FILE, cloudprovider.TBucketACLType(args.Acl), args.StorageType, http.Header{}) - if err != nil { - return errors.Wrap(err, "NewMultipartUpload") - } - fmt.Println("uploadId: ", uploadId) - offset := int64(0) - partSize := cloudprovider.MAX_PUT_OBJECT_SIZEBYTES - count := stat.Size() / int64(partSize) - if stat.Size()%int64(partSize) > 0 { - count += 1 - } - for i := 0; i < int(count); i++ { - err := cli.UploadPart(args.BUCKET, uploadId, 0, int64(offset), io.LimitReader(file, int64(partSize)), int64(partSize), stat.Size()) - if err != nil { - return errors.Wrap(err, "UploadPart") - } - offset += partSize - if int64(offset+partSize) > stat.Size() { - partSize = stat.Size() % int64(partSize) - } - } - return nil - }) - - type ObjectListOptions struct { - BUCKET string - Prefix string - Delimiter string - NextPageToken string - MaxResult int - } - - shellutils.R(&ObjectListOptions{}, "object-list", "List object from bucket", func(cli *google.SRegion, args *ObjectListOptions) error { - objs, err := cli.GetObjects(args.BUCKET, args.Prefix, args.NextPageToken, args.Delimiter, args.MaxResult) - if err != nil { - return err - } - printList(objs.Items, 0, 0, 0, nil) - return nil - }) - - type ObjectUrlOptions struct { - BUCKET string - OBJECT string - METHOD string - Hour int - } - - shellutils.R(&ObjectUrlOptions{}, "object-url", "Object temp url", func(cli *google.SRegion, args *ObjectUrlOptions) error { - url, err := cli.SingedUrl(args.BUCKET, args.OBJECT, args.METHOD, time.Duration(args.Hour)*time.Hour) - if err != nil { - return err - } - fmt.Println(url) - return nil - }) - - type ObjectOptions struct { - BUCKET string - OBJECT string - } - - shellutils.R(&ObjectOptions{}, "object-acl-list", "List Object acl", func(cli *google.SRegion, args *ObjectOptions) error { - acls, err := cli.GetObjectAcl(args.BUCKET, args.OBJECT) - if err != nil { - return err - } - printList(acls, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&ObjectOptions{}, "object-delete", "Delete Object", func(cli *google.SRegion, args *ObjectOptions) error { - return cli.DeleteObject(args.BUCKET, args.OBJECT) - }) - - type ObjectDownloadOptions struct { - BUCKET string - OBJECT string - Start int64 - End int64 - } - - shellutils.R(&ObjectDownloadOptions{}, "object-download", "Download Object", func(cli *google.SRegion, args *ObjectDownloadOptions) error { - data, err := cli.DownloadObjectRange(args.BUCKET, args.OBJECT, args.Start, args.End) - if err != nil { - return errors.Wrap(err, "DownloadObjectRange") - } - content, err := ioutil.ReadAll(data) - if err != nil { - return errors.Wrap(err, "ioutil.ReadAll") - } - return ioutil.WriteFile(args.OBJECT, content, 0644) - }) - - type ObjectUploadCheckOptions struct { - BUCKET string - UPLOADID string - } - - shellutils.R(&ObjectUploadCheckOptions{}, "object-upload-check", "Upload object to buckets", func(cli *google.SRegion, args *ObjectUploadCheckOptions) error { - return cli.CheckUploadRange(args.BUCKET, args.UPLOADID) - }) - -} diff --git a/pkg/multicloud/google/shell/printutils.go b/pkg/multicloud/google/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/google/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/google/shell/project.go b/pkg/multicloud/google/shell/project.go deleted file mode 100644 index 2ef5cc5712..0000000000 --- a/pkg/multicloud/google/shell/project.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ProjectListOptions struct { - MaxResults int - PageToken string - } - shellutils.R(&ProjectListOptions{}, "project-list", "List projects", func(cli *google.SRegion, args *ProjectListOptions) error { - projects, err := cli.GetClient().GetProjects() - if err != nil { - return err - } - printList(projects, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/google/shell/region.go b/pkg/multicloud/google/shell/region.go deleted file mode 100644 index 6442250ffb..0000000000 --- a/pkg/multicloud/google/shell/region.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *google.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/google/shell/resourcepolicy.go b/pkg/multicloud/google/shell/resourcepolicy.go deleted file mode 100644 index 3d6ee48c0c..0000000000 --- a/pkg/multicloud/google/shell/resourcepolicy.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ResourcePolicyListOptions struct { - Disk string - MaxResults int - PageToken string - } - shellutils.R(&ResourcePolicyListOptions{}, "resource-policy-list", "List resourcepolicys", func(cli *google.SRegion, args *ResourcePolicyListOptions) error { - resourcepolicys, err := cli.GetResourcePolicies(args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(resourcepolicys, 0, 0, 0, nil) - return nil - }) - - type ResourcePolicyShowOptions struct { - ID string - } - shellutils.R(&ResourcePolicyShowOptions{}, "resource-policy-show", "Show resourcepolicy", func(cli *google.SRegion, args *ResourcePolicyShowOptions) error { - resourcepolicy, err := cli.GetResourcePolicy(args.ID) - if err != nil { - return err - } - printObject(resourcepolicy) - return nil - }) - - type ListOrganizationOptions struct{} - shellutils.R(&ListOrganizationOptions{}, "organization-list", "List organizaitons", func(cli *google.SRegion, args *ListOrganizationOptions) error { - orgs, err := cli.GetClient().ListOrganizations() - if err != nil { - return err - } - printList(orgs, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/skubilling.go b/pkg/multicloud/google/shell/skubilling.go deleted file mode 100644 index febdf955cd..0000000000 --- a/pkg/multicloud/google/shell/skubilling.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "io/ioutil" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SkuBillingListOptions struct { - PageSize int - PageToken string - } - shellutils.R(&SkuBillingListOptions{}, "sku-billing-list", "List sku billing", func(cli *google.SRegion, args *SkuBillingListOptions) error { - billings, err := cli.ListSkuBilling(args.PageSize, args.PageToken) - if err != nil { - return err - } - printList(billings, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&SkuBillingListOptions{}, "compute-sku-billing-list", "List sku billing", func(cli *google.SRegion, args *SkuBillingListOptions) error { - billings, err := cli.ListSkuBilling(args.PageSize, args.PageToken) - if err != nil { - return err - } - info := cli.GetSkuRateInfo(billings) - fmt.Println(jsonutils.Marshal(info).PrettyString()) - return nil - }) - - type SkuEstimate struct { - RATE_FAILE string - SKU string - REGION string - CPU int - MEMORY_MB int - } - - shellutils.R(&SkuEstimate{}, "sku-estimate", "Estimate sku price", func(cli *google.SRegion, args *SkuEstimate) error { - data, err := ioutil.ReadFile(args.RATE_FAILE) - if err != nil { - return errors.Wrap(err, "ioutil.ReadFile") - } - rate := google.SRateInfo{} - j, err := jsonutils.Parse(data) - if err != nil { - return errors.Wrap(err, "jsonutils.Parse") - } - err = jsonutils.Update(&rate, j) - if err != nil { - return errors.Wrap(err, "jsonutils.Update") - } - result, err := rate.GetSkuPrice(args.REGION, args.SKU, args.CPU, args.MEMORY_MB) - if err != nil { - return errors.Wrap(err, "GetSkuPrice") - } - fmt.Printf("result: %s\n", jsonutils.Marshal(result).PrettyString()) - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/snapshot.go b/pkg/multicloud/google/shell/snapshot.go deleted file mode 100644 index 6973f6d6a2..0000000000 --- a/pkg/multicloud/google/shell/snapshot.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SnapshotListOptions struct { - Disk string - MaxResults int - PageToken string - } - shellutils.R(&SnapshotListOptions{}, "snapshot-list", "List snapshots", func(cli *google.SRegion, args *SnapshotListOptions) error { - snapshots, err := cli.GetSnapshots(args.Disk, args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(snapshots, 0, 0, 0, nil) - return nil - }) - - type SnapshotIdOptions struct { - ID string - } - shellutils.R(&SnapshotIdOptions{}, "snapshot-show", "Show snapshot", func(cli *google.SRegion, args *SnapshotIdOptions) error { - snapshot, err := cli.GetSnapshot(args.ID) - if err != nil { - return err - } - printObject(snapshot) - return nil - }) - - shellutils.R(&SnapshotIdOptions{}, "snapshot-delete", "Delete snapshot", func(cli *google.SRegion, args *SnapshotIdOptions) error { - return cli.Delete(args.ID) - }) - - type SnapshotCreateOptions struct { - NAME string - Desc string - DISK string - } - - shellutils.R(&SnapshotCreateOptions{}, "snapshot-create", "Create snapshot", func(cli *google.SRegion, args *SnapshotCreateOptions) error { - snapshot, err := cli.CreateSnapshot(args.DISK, args.NAME, args.Desc) - if err != nil { - return err - } - printObject(snapshot) - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/storage.go b/pkg/multicloud/google/shell/storage.go deleted file mode 100644 index 88020878e9..0000000000 --- a/pkg/multicloud/google/shell/storage.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type StorageListOptions struct { - ZONE string - MaxResults int - PageToken string - } - shellutils.R(&StorageListOptions{}, "storage-list", "List storages", func(cli *google.SRegion, args *StorageListOptions) error { - storages, err := cli.GetStorages(args.ZONE, args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(storages, 0, 0, 0, nil) - return nil - }) - - type StorageShowOptions struct { - ID string - } - shellutils.R(&StorageShowOptions{}, "storage-show", "Show storage", func(cli *google.SRegion, args *StorageShowOptions) error { - storage, err := cli.GetStorage(args.ID) - if err != nil { - return err - } - printObject(storage) - return nil - }) - - type RegionStorageListOptions struct { - MaxResults int - PageToken string - } - shellutils.R(&RegionStorageListOptions{}, "region-storage-list", "List region storages", func(cli *google.SRegion, args *RegionStorageListOptions) error { - storages, err := cli.GetRegionStorages(args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(storages, 0, 0, 0, nil) - return nil - }) - - type RegionStorageShowOptions struct { - ID string - } - shellutils.R(&RegionStorageShowOptions{}, "region-storage-show", "Show region storage", func(cli *google.SRegion, args *RegionStorageShowOptions) error { - storage, err := cli.GetRegionStorage(args.ID) - if err != nil { - return err - } - printObject(storage) - return nil - }) - -} diff --git a/pkg/multicloud/google/shell/zone.go b/pkg/multicloud/google/shell/zone.go deleted file mode 100644 index 1de9c52648..0000000000 --- a/pkg/multicloud/google/shell/zone.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/google" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - RegionId string - MaxResults int - PageToken string - } - shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *google.SRegion, args *ZoneListOptions) error { - zones, err := cli.GetZones(args.RegionId, args.MaxResults, args.PageToken) - if err != nil { - return err - } - printList(zones, 0, 0, 0, nil) - return nil - }) - - type ZoneShowOptions struct { - ID string - } - shellutils.R(&ZoneShowOptions{}, "zone-show", "Show zones", func(cli *google.SRegion, args *ZoneShowOptions) error { - zone, err := cli.GetZone(args.ID) - if err != nil { - return err - } - printObject(zone) - return nil - }) - -} diff --git a/pkg/multicloud/google/sku.go b/pkg/multicloud/google/sku.go deleted file mode 100644 index d638df9e82..0000000000 --- a/pkg/multicloud/google/sku.go +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" -) - -type SkuBillingCatetory struct { - ServiceDisplayName string - ResourceFamily string - ResourceGroup string - UsageType string -} - -type SkuPricingInfo struct { - Summary string - PricingExpression SPricingExpression - currencyConversionRate int - EffectiveTime time.Time -} - -type SPricingExpression struct { - UsageUnit string - UsageUnitDescription string - BaseUnit string - BaseUnitDescription string - BaseUnitConversionFactor string - DisplayQuantity int - TieredRates []STieredRate -} - -type STieredRate struct { - StartUsageAmount int - UnitPrice SUnitPrice -} - -type SUnitPrice struct { - CurrencyCode string - Units string - Nanos int -} - -type SSkuBilling struct { - Name string - SkuId string - Description string - Category SkuBillingCatetory - ServiceRegions []string - PricingInfo []SkuPricingInfo - ServiceProviderName string -} - -func (region *SRegion) ListSkuBilling(pageSize int, pageToken string) ([]SSkuBilling, error) { - skus := []SSkuBilling{} - params := map[string]string{} - err := region.BillingList("services/6F81-5844-456A/skus", params, pageSize, pageToken, &skus) - if err != nil { - return nil, err - } - return skus, nil -} - -type SRateInfo struct { - // region: europe-north1 - // family: Compute, Storage, Network - // resource: CPU, Ram, Gpu, N1Standard - // category: custome, predefine, optimized - // startUsageAmount: - // map[region]map[family]map[resource]map[category]map[startUsageAmount][money] - - Info map[string]map[string]map[string]map[string]map[string]float64 -} - -func (region *SRegion) GetSkuRateInfo(skus []SSkuBilling) SRateInfo { - result := SRateInfo{ - Info: map[string]map[string]map[string]map[string]map[string]float64{}, - } - for _, sku := range skus { - if sku.ServiceProviderName == "Google" && - sku.Category.ServiceDisplayName == "Compute Engine" && - utils.IsInStringArray(sku.Category.ResourceFamily, []string{"Compute", "Storage"}) && - sku.Category.UsageType == "OnDemand" { - for _, region := range sku.ServiceRegions { - if _, ok := result.Info[region]; !ok { - result.Info[region] = map[string]map[string]map[string]map[string]float64{} - } - if _, ok := result.Info[region][sku.Category.ResourceFamily]; !ok { - result.Info[region][sku.Category.ResourceFamily] = map[string]map[string]map[string]float64{} - } - if sku.Category.ResourceGroup == "N1Standard" { - if strings.Index(sku.Description, "Core") > 0 { - sku.Category.ResourceGroup = "CPU" - } else if strings.Index(sku.Description, "Ram") > 0 { - sku.Category.ResourceGroup = "RAM" - } - } - if !utils.IsInStringArray(sku.Category.ResourceGroup, []string{"F1Micro", "G1Small", "CPU", "RAM", "PDStandard", "SSD", "LocalSSD", "f1-micro", "g1-small"}) { - continue - } - if utils.IsInStringArray(sku.Category.ResourceGroup, []string{"PDStandard", "SSD"}) && strings.Index(sku.Description, "Regional") >= 0 { - continue - } - convers := map[string]string{ - "PDStandard": api.STORAGE_GOOGLE_PD_STANDARD, - "SSD": api.STORAGE_GOOGLE_PD_SSD, - "LocalSSD": api.STORAGE_GOOGLE_LOCAL_SSD, - "F1Micro": "f1-micro", - "G1Small": "g1-small", - } - if group, ok := convers[sku.Category.ResourceGroup]; ok { - sku.Category.ResourceGroup = group - } - - if _, ok := result.Info[region][sku.Category.ResourceFamily][sku.Category.ResourceGroup]; !ok { - result.Info[region][sku.Category.ResourceFamily][sku.Category.ResourceGroup] = map[string]map[string]float64{} - } - description := strings.ToLower(sku.Description) - if strings.Contains("sole", description) { //单租户 - continue - } - category := "" - keys := []string{"memory optimized", "memory-optimized", "compute optimized", "n1 predefined", "n2 instance", "n2 custom extended", "custom extended", "n2 custom", "custom instance"} - categories := map[string]string{ - "memory optimized": "ultramem", - "memory-optimized": "memory-optimized", - "compute optimized": "compute-optimized", - - "n1 predefined": "n1-predefined", - "n2 instance": "n2-instance", - - "n2 custom extended": "n2-custom-extended", - "custom extended": "custom-extended", - - "n2 custom": "n2-custom", //cpu ram - "custom instance": "custom-instance", //cpu - } - for _, key := range keys { - _category := categories[key] - if strings.Contains(description, key) { - category = _category - break - } - } - if utils.IsInStringArray(sku.Category.ResourceGroup, []string{api.STORAGE_GOOGLE_PD_STANDARD, api.STORAGE_GOOGLE_PD_SSD, api.STORAGE_GOOGLE_LOCAL_SSD, "f1-micro", "g1-small"}) { - category = sku.Category.ResourceGroup - } - if len(category) == 0 { - continue - } - if _, ok := result.Info[region][sku.Category.ResourceFamily][sku.Category.ResourceGroup][category]; !ok { - result.Info[region][sku.Category.ResourceFamily][sku.Category.ResourceGroup][category] = map[string]float64{} - } - for _, priceInfo := range sku.PricingInfo { - for _, price := range priceInfo.PricingExpression.TieredRates { - result.Info[region][sku.Category.ResourceFamily][sku.Category.ResourceGroup][category][fmt.Sprintf("%d", price.StartUsageAmount)] = float64(price.UnitPrice.Nanos) / 1000000000 - } - } - } - } - } - return result -} - -func (rate *SRateInfo) GetDiscount(sku string) []float64 { - if strings.Index(sku, "custom") < 0 && strings.HasPrefix(sku, "c") || strings.Index(sku, "n2") >= 0 { - return []float64{0, 0.15, 0.25, 0.4} - } - return []float64{0, 0.2, 0.4, 0.6} -} - -func (rate *SRateInfo) GetSkuType(sku string) (string, error) { - if strings.Index(sku, "custom") >= 0 { - cpuType := "custom-instance" - if strings.HasPrefix(sku, "n2") { - cpuType = "n2-custom" - } - return cpuType, nil - } - if strings.HasPrefix(sku, "n1") { - return "n1-predefined", nil - } - if strings.HasPrefix(sku, "n2") { - return "n2-instance", nil - } - if strings.HasPrefix(sku, "c") { - return "compute-optimized", nil - } - if strings.HasPrefix(sku, "m") { - return "memory-optimized", nil - } - return "", fmt.Errorf("failed to found sku %s type", sku) -} - -func (rate *SRateInfo) GetCpuPrice(regionId, cpuType string) (float64, error) { - computePrice, err := rate.GetComputePrice(regionId) - if err != nil { - return 0, errors.Wrap(err, "GetComputePrice") - } - - _cpuPrice, ok := computePrice["CPU"] - if !ok { - return 0, fmt.Errorf("failed to found region %s compute cpu price info", regionId) - } - - cpuPrice, ok := _cpuPrice[cpuType] - if !ok { - return 0, fmt.Errorf("failed to found region %s compute %s cpu price info", regionId, cpuType) - } - return cpuPrice["0"], nil -} - -func (rate *SRateInfo) GetExtendMemoryGb(sku string, cpu int, memoryMb int) float64 { - maxMemoryGb := 0.0 - if strings.Index(sku, "custom") >= 0 { - maxMemoryGb = float64(cpu) * 6.5 - if strings.Index(sku, "n2") >= 0 { - maxMemoryGb = float64(cpu) * 8 - } - } - if float64(memoryMb)/1024 > maxMemoryGb { - return float64(memoryMb)/1024 - maxMemoryGb - } - return 0.0 -} - -func (rate *SRateInfo) GetMemoryPrice(regionId string, memoryType string) (float64, error) { - computePrice, err := rate.GetComputePrice(regionId) - if err != nil { - return 0, errors.Wrap(err, "GetComputePrice") - } - - _memoryPrice, ok := computePrice["RAM"] - if !ok { - return 0, fmt.Errorf("failed to found region %s compute memory price info", regionId) - } - - memoryPrice, ok := _memoryPrice[memoryType] - if !ok { - return 0, fmt.Errorf("failed to found region %s compute %s memory price info", regionId, memoryType) - } - return memoryPrice["0"], nil -} - -func (rate *SRateInfo) GetComputePrice(regionId string) (map[string]map[string]map[string]float64, error) { - regionPrice, ok := rate.Info[regionId] - if !ok { - return nil, fmt.Errorf("failed to found region %s price info", regionId) - } - computePrice, ok := regionPrice["Compute"] - if !ok { - return nil, fmt.Errorf("failed to found region %s compute price info", regionId) - } - return computePrice, nil -} - -func (rate *SRateInfo) GetSharedSkuPrice(regionId string, sku string) (float64, error) { - computePrice, err := rate.GetComputePrice(regionId) - if err != nil { - return 0.0, errors.Wrap(err, "GetComputePrice") - } - if _sharedSku, ok := computePrice[sku]; ok { - if sharedSku, ok := _sharedSku[sku]; ok { - return sharedSku["0"], nil - } - } - return 0.0, fmt.Errorf("sku is not shared sku") -} - -func (rate *SRateInfo) GetSkuPrice(regionId string, sku string, cpu, memoryMb int) (struct { - Hour float64 - Month float64 - Year float64 -}, error) { - result := struct { - Hour float64 - Month float64 - Year float64 - }{} - - discount := rate.GetDiscount(sku) - - price, err := rate.GetSharedSkuPrice(regionId, sku) - if err != nil { - skuType, err := rate.GetSkuType(sku) - if err != nil { - return result, errors.Wrap(err, "GetSkuType") - } - - cpuPrice, err := rate.GetCpuPrice(regionId, skuType) - if err != nil { - return result, errors.Wrap(err, "price.GetCpuPrice") - } - - price += float64(cpu) * cpuPrice - log.Debugf("cpu price: %f", cpuPrice) - - extendMemoryGb := rate.GetExtendMemoryGb(sku, cpu, memoryMb) - memoryMb = int(float64(memoryMb) - 1024*extendMemoryGb) - - memoryPrice, err := rate.GetMemoryPrice(regionId, skuType) - if err != nil { - return result, errors.Wrap(err, "GetMemoryPrice") - } - - price += memoryPrice * float64(memoryMb/1024) - log.Debugf("ramPrice: %f", memoryPrice) - - if extendMemoryGb > 0 { - memoryType := "custom-extended" - if strings.HasPrefix(sku, "n2") { - memoryType = "n2-custom-extended" - } - extendPrice, err := rate.GetMemoryPrice(regionId, memoryType) - if err != nil { - return result, errors.Wrap(err, "GetMemoryPrice.Extend") - } - price += extendPrice * float64(extendMemoryGb) - log.Debugf("extendPrice: %f", extendPrice) - } - } - - log.Debugf("totalPrice: %f", price) - - result.Month = 182.5 * price - result.Month += 182.5 * (1 - discount[1]) * price - result.Month += 182.5 * (1 - discount[2]) * price - result.Month += 172.49999999999997 * (1 - discount[3]) * price - result.Hour = result.Month / 30 / 24 - result.Year = result.Month * 12 - return result, nil -} diff --git a/pkg/multicloud/google/snapshot.go b/pkg/multicloud/google/snapshot.go deleted file mode 100644 index a55da17011..0000000000 --- a/pkg/multicloud/google/snapshot.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSnapshot struct { - region *SRegion - SResourceBase - multicloud.GoogleTags - - CreationTimestamp time.Time - Status string - SourceDisk string - SourceDiskId string - DiskSizeGb int32 - StorageBytes int - StorageBytesStatus string - Licenses []string - LabelFingerprint string - LicenseCodes []string - StorageLocations []string - Kind string -} - -func (region *SRegion) GetSnapshots(disk string, maxResults int, pageToken string) ([]SSnapshot, error) { - snapshots := []SSnapshot{} - params := map[string]string{} - if len(disk) > 0 { - params["filter"] = fmt.Sprintf(`sourceDisk="%s"`, disk) - } - resource := "global/snapshots" - return snapshots, region.List(resource, params, maxResults, pageToken, &snapshots) -} - -func (region *SRegion) GetSnapshot(id string) (*SSnapshot, error) { - snapshot := &SSnapshot{region: region} - return snapshot, region.Get("global/snapshots", id, snapshot) -} - -//CREATING, DELETING, FAILED, READY, or UPLOADING -func (snapshot *SSnapshot) GetStatus() string { - switch snapshot.Status { - case "CREATING": - return api.SNAPSHOT_CREATING - case "DELETING": - return api.SNAPSHOT_DELETING - case "FAILED": - return api.SNAPSHOT_UNKNOWN - case "READY", "UPLOADING": - return api.SNAPSHOT_READY - default: - return api.SNAPSHOT_UNKNOWN - } -} - -func (snapshot *SSnapshot) IsEmulated() bool { - return false -} - -func (self *SSnapshot) GetCreatedAt() time.Time { - return self.CreationTimestamp -} - -func (snapshot *SSnapshot) Refresh() error { - _snapshot, err := snapshot.region.GetSnapshot(snapshot.Id) - if err != nil { - return err - } - return jsonutils.Update(snapshot, _snapshot) -} - -func (snapshot *SSnapshot) GetSizeMb() int32 { - return snapshot.DiskSizeGb * 1024 -} - -func (snapshot *SSnapshot) GetDiskId() string { - return snapshot.SourceDisk -} - -func (snapshot *SSnapshot) GetDiskType() string { - if len(snapshot.Licenses) > 0 { - return api.DISK_TYPE_SYS - } - return api.DISK_TYPE_DATA -} - -func (snapshot *SSnapshot) Delete() error { - return snapshot.region.Delete(snapshot.SelfLink) -} - -func (snapshot *SSnapshot) GetProjectId() string { - return snapshot.region.GetProjectId() -} diff --git a/pkg/multicloud/google/storage.go b/pkg/multicloud/google/storage.go deleted file mode 100644 index d058deeb41..0000000000 --- a/pkg/multicloud/google/storage.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - zone *SZone - SResourceBase - multicloud.GoogleTags - - CreationTimestamp time.Time - Description string - ValidDiskSize string - Zone string - DefaultDiskSizeGb string - Kind string -} - -func (region *SRegion) GetStorages(zone string, maxResults int, pageToken string) ([]SStorage, error) { - storages := []SStorage{} - if len(zone) == 0 { - return nil, fmt.Errorf("zone params can not be empty") - } - resource := fmt.Sprintf("zones/%s/diskTypes", zone) - params := map[string]string{} - return storages, region.List(resource, params, maxResults, pageToken, &storages) -} - -func (region *SRegion) GetStorage(id string) (*SStorage, error) { - storage := &SStorage{} - return storage, region.GetBySelfId(id, storage) -} - -func (storage *SStorage) GetName() string { - return storage.Description -} - -func (storage *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (storage *SStorage) IsEmulated() bool { - return true -} - -func (self *SStorage) GetCreatedAt() time.Time { - return time.Time{} -} - -func (storage *SStorage) Refresh() error { - _storage, err := storage.zone.region.GetStorage(storage.SelfLink) - if err != nil { - return err - } - return jsonutils.Update(storage, _storage) -} - -func (storage *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return storage.zone.region.getStoragecache() -} - -func (storage *SStorage) GetIZone() cloudprovider.ICloudZone { - return storage.zone -} - -func (storage *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := storage.zone.region.GetDisks(storage.zone.Name, storage.Name, 0, "") - if err != nil { - return nil, err - } - idisks := []cloudprovider.ICloudDisk{} - for i := range disks { - disks[i].storage = storage - idisks = append(idisks, &disks[i]) - } - return idisks, nil -} - -func (storage *SStorage) GetStorageType() string { - return storage.Name -} - -func (storage *SStorage) GetMediumType() string { - return api.DISK_TYPE_SSD -} - -func (storage *SStorage) GetCapacityMB() int64 { - return 0 -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (storage *SStorage) GetStorageConf() jsonutils.JSONObject { - return jsonutils.Marshal(map[string]string{ - "ValidDiskSize": storage.ValidDiskSize, - "DefaultDiskSizeGb": storage.DefaultDiskSizeGb, - }) -} - -func (storage *SStorage) GetEnabled() bool { - return true -} - -func (storage *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - disk, err := storage.zone.region.GetDisk(id) - if err != nil { - return nil, err - } - disk.storage = storage - return disk, nil -} - -func (storage *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - disk, err := storage.zone.region.CreateDisk(conf.Name, conf.SizeGb, storage.zone.Name, storage.Name, "", conf.Desc) - if err != nil { - return nil, err - } - disk.storage = storage - return disk, nil -} - -func (storage *SStorage) GetMountPoint() string { - return "" -} - -func (storage *SStorage) IsSysDiskStore() bool { - return storage.Name != api.STORAGE_GOOGLE_LOCAL_SSD -} - -func (storage *SStorage) DisableSync() bool { - return false -} diff --git a/pkg/multicloud/google/storagecache.go b/pkg/multicloud/google/storagecache.go deleted file mode 100644 index 34e6dcb7dc..0000000000 --- a/pkg/multicloud/google/storagecache.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "context" - "fmt" - "strings" - "unicode" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/image/options" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/mcclient/auth" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.GoogleTags - region *SRegion - - iimages []cloudprovider.ICloudImage -} - -func (cache *SStoragecache) GetId() string { - return cache.region.client.cpcfg.Id -} - -func (cache *SStoragecache) GetName() string { - return cache.region.client.cpcfg.Name -} - -func (cache *SStoragecache) GetStatus() string { - return "available" -} - -func (cache *SStoragecache) Refresh() error { - return nil -} - -func (cache *SStoragecache) GetGlobalId() string { - return cache.region.client.cpcfg.Id -} - -func (cache *SStoragecache) IsEmulated() bool { - return true -} - -func (cache *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (cache *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - images, err := cache.region.GetImages(cache.region.client.projectId, 1000, "") - if err != nil { - return nil, errors.Wrapf(err, "GetImages") - } - ret := []cloudprovider.ICloudImage{} - for i := range images { - images[i].storagecache = cache - ret = append(ret, &images[i]) - } - return ret, nil -} - -func (cache *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - image, err := cache.region.GetImage(extId) - if err != nil { - return nil, err - } - return image, nil -} - -func (cache *SStoragecache) GetPath() string { - return "" -} - -func (cache *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return cache.uploadImage(ctx, userCred, image, callback) -} - -func (region *SRegion) checkAndCreateBucket(bucketName string) (*SBucket, error) { - bucket, err := region.GetBucket(bucketName) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - bucket, err = region.CreateBucket(bucketName, "", cloudprovider.ACLPrivate) - if err != nil { - return nil, errors.Wrapf(err, "region.CreateBucket(%s)", bucketName) - } - } else { - return nil, errors.Wrapf(err, "region.StorageGet(%s)", bucketName) - } - } - return bucket, nil -} - -func (cache *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - s := auth.GetAdminSession(ctx, options.Options.Region) - - meta, reader, sizeBytes, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false) - if err != nil { - return "", err - } - log.Infof("meta data %s", meta) - - info := struct { - Id string - Name string - Size int64 - Description string - }{} - meta.Unmarshal(&info) - - bucketName := fmt.Sprintf("imagecache-%s", info.Id) - bucket, err := cache.region.checkAndCreateBucket(bucketName) - if err != nil { - return "", errors.Wrapf(err, "checkAndCreateBucket(%s)", bucketName) - } - - defer cache.region.DeleteBucket(bucket.Name) - - log.Debugf("To upload image to bucket %s ...", bucketName) - body := multicloud.NewProgress(sizeBytes, 80, reader, callback) - err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeBytes, "", "", nil, false) - if err != nil { - return "", errors.Wrap(err, "UploadObjectWithProgress") - } - - images, err := cache.region.GetImages(cache.region.GetProjectId(), 0, "") - if err != nil { - return "", errors.Wrap(err, "region.GetImages") - } - imageNames := []string{} - for _, image := range images { - imageNames = append(imageNames, image.Name) - } - - imageName := "img-" - for _, s := range strings.ToLower(info.Name) { - if unicode.IsDigit(s) || unicode.IsLetter(s) || s == '-' { - imageName = fmt.Sprintf("%s%c", imageName, s) - } else { - imageName = fmt.Sprintf("%s-", imageName) - } - } - - baseName := imageName - for i := 0; i < 30; i++ { - if !utils.IsInStringArray(imageName, imageNames) { - break - } - imageName = fmt.Sprintf("%s-%d", baseName, i) - } - - _image, err := cache.region.CreateImage(imageName, info.Description, bucketName, info.Name) - if err != nil { - return "", errors.Wrap(err, "region.CreateImage") - } - - if callback != nil { - callback(100) - } - - return _image.GetGlobalId(), nil -} - -func (cache *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (cache *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - cache := &SStoragecache{region: region} - return []cloudprovider.ICloudStoragecache{cache}, nil -} - -func (region *SRegion) getStoragecache() *SStoragecache { - return &SStoragecache{region: region} -} - -func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - cache := region.getStoragecache() - if id == cache.GetGlobalId() { - return cache, nil - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/google/vpc.go b/pkg/multicloud/google/vpc.go deleted file mode 100644 index dc459ecdd3..0000000000 --- a/pkg/multicloud/google/vpc.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - multicloud.GoogleTags - SResourceBase - - region *SRegion - - CreationTimestamp time.Time - Network string - IpCidrRange string - Region string - GatewayAddress string - Status string - AvailableCpuPlatforms []string - PrivateIpGoogleAccess bool - Fingerprint string - Purpose string - Kind string -} - -func (self *SVpc) GetGlobalVpcId() string { - gvpc := &SGlobalNetwork{} - err := self.region.GetBySelfId(self.Network, gvpc) - if err != nil { - return "" - } - return gvpc.Id -} - -func (self *SVpc) Refresh() error { - vpc, err := self.region.GetVpc(self.Id) - if err != nil { - return errors.Wrapf(err, "GetVpc") - } - return jsonutils.Update(self, vpc) -} - -func (self *SRegion) GetVpc(id string) (*SVpc, error) { - vpc := &SVpc{region: self} - return vpc, self.Get("subnetworks", id, vpc) -} - -func (vpc *SVpc) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} - -func (vpc *SVpc) Delete() error { - return vpc.region.Delete(vpc.SelfLink) -} - -func (vpc *SVpc) GetCidrBlock() string { - return vpc.IpCidrRange -} - -func (vpc *SVpc) IsEmulated() bool { - return false -} - -func (vpc *SVpc) GetIsDefault() bool { - return false -} - -func (vpc *SVpc) GetRegion() cloudprovider.ICloudRegion { - return vpc.region -} - -func (vpc *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (vpc *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - firewalls, err := vpc.region.client.GetFirewalls(vpc.Network, 0, "") - if err != nil { - return nil, errors.Wrap(err, "GetFirewalls") - } - gvpc := &SGlobalNetwork{client: vpc.region.client} - err = vpc.region.GetBySelfId(vpc.Network, gvpc) - if err != nil { - return nil, errors.Wrapf(err, "GetGlobalNetwork") - } - isecgroups := []cloudprovider.ICloudSecurityGroup{} - allInstance := false - tags := []string{} - for _, firewall := range firewalls { - if len(firewall.TargetServiceAccounts) > 0 { - secgroup := &SSecurityGroup{gvpc: gvpc, ServiceAccount: firewall.TargetServiceAccounts[0]} - isecgroups = append(isecgroups, secgroup) - } else if len(firewall.TargetTags) > 0 && !utils.IsInStringArray(firewall.TargetTags[0], tags) { - secgroup := &SSecurityGroup{gvpc: gvpc, Tag: firewall.TargetTags[0]} - tags = append(tags, firewall.TargetTags[0]) - isecgroups = append(isecgroups, secgroup) - } else if !allInstance { - secgroup := &SSecurityGroup{gvpc: gvpc} - isecgroups = append(isecgroups, secgroup) - allInstance = true - } - } - return isecgroups, nil -} - -func (vpc *SVpc) getWire() *SWire { - return &SWire{vpc: vpc} -} - -func (vpc *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - wire := vpc.getWire() - return []cloudprovider.ICloudWire{wire}, nil -} - -func (vpc *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { - if id != vpc.getWire().GetGlobalId() { - return nil, cloudprovider.ErrNotFound - } - return &SWire{vpc: vpc}, nil -} - -func (self *SRegion) CreateVpc(name string, gvpcId string, cidr string, desc string) (*SVpc, error) { - body := map[string]interface{}{ - "name": name, - "description": desc, - "network": gvpcId, - "ipCidrRange": cidr, - } - resource := fmt.Sprintf("regions/%s/subnetworks", self.Name) - vpc := &SVpc{region: self} - err := self.Insert(resource, jsonutils.Marshal(body), vpc) - if err != nil { - return nil, err - } - return vpc, nil -} - -func (self *SRegion) GetVpcs() ([]SVpc, error) { - vpcs := []SVpc{} - resource := fmt.Sprintf("regions/%s/subnetworks", self.Name) - return vpcs, self.List(resource, nil, 0, "", &vpcs) -} diff --git a/pkg/multicloud/google/wire.go b/pkg/multicloud/google/wire.go deleted file mode 100644 index e314f563ff..0000000000 --- a/pkg/multicloud/google/wire.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.GoogleTags - vpc *SVpc -} - -func (wire *SWire) GetId() string { - return wire.vpc.GetGlobalId() -} - -func (wire *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", wire.GetId(), wire.vpc.region.Name) -} - -func (wire *SWire) GetName() string { - return wire.vpc.GetName() -} - -func (wire *SWire) GetCreatedAt() time.Time { - return time.Time{} -} - -func (wire *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (wire *SWire) GetIVpc() cloudprovider.ICloudVpc { - return wire.vpc -} - -func (wire *SWire) GetIZone() cloudprovider.ICloudZone { - return nil -} - -func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - network := SNetwork{wire: self} - return []cloudprovider.ICloudNetwork{&network}, nil -} - -func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { - networks, err := self.GetINetworks() - if err != nil { - return nil, errors.Wrapf(err, "GetINetwork") - } - for i := range networks { - if networks[i].GetGlobalId() == id { - return networks[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (wire *SWire) GetBandwidth() int { - return 0 -} - -func (wire *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (wire *SWire) IsEmulated() bool { - return true -} - -func (wire *SWire) Refresh() error { - return nil -} diff --git a/pkg/multicloud/google/zone.go b/pkg/multicloud/google/zone.go deleted file mode 100644 index 444efedb5f..0000000000 --- a/pkg/multicloud/google/zone.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 google - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SZone struct { - multicloud.SResourceBase - multicloud.GoogleTags - region *SRegion - - Description string - ID string - Kind string - Name string - Region string - SelfLink string - AvailableCpuPlatforms []string - Status string -} - -func (region *SRegion) GetZone(id string) (*SZone, error) { - zone := &SZone{region: region} - return zone, region.GetBySelfId(id, zone) -} - -func (region *SRegion) GetZones(regionId string, maxResults int, pageToken string) ([]SZone, error) { - zones := []SZone{} - params := map[string]string{} - if len(regionId) > 0 { - params["filter"] = fmt.Sprintf(`region="%s/%s/projects/%s/regions/%s"`, GOOGLE_COMPUTE_DOMAIN, GOOGLE_API_VERSION, region.GetProjectId(), regionId) - } - resource := "zones" - return zones, region.List(resource, params, maxResults, pageToken, &zones) -} - -func (zone *SZone) GetName() string { - return zone.Name -} - -func (zone *SZone) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(zone.GetName()).CN(zone.GetName()) - return table -} - -func (zone *SZone) GetGlobalId() string { - return fmt.Sprintf("%s/%s", zone.region.GetGlobalId(), zone.Name) -} - -func (zone *SZone) GetId() string { - return zone.Name -} - -func (zone *SZone) GetIHostById(hostId string) (cloudprovider.ICloudHost, error) { - if hostId != zone.getHost().GetGlobalId() { - return nil, cloudprovider.ErrNotFound - } - return &SHost{zone: zone}, nil -} - -func (zone *SZone) getHost() *SHost { - return &SHost{zone: zone} -} - -func (zone *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - host := zone.getHost() - return []cloudprovider.ICloudHost{host}, nil -} - -func (zone *SZone) GetIRegion() cloudprovider.ICloudRegion { - return zone.region -} - -func (zone *SZone) GetIStorageById(storageId string) (cloudprovider.ICloudStorage, error) { - storage, err := zone.region.GetStorage(storageId) - if err != nil { - return nil, err - } - storage.zone = zone - return storage, nil -} - -func (zone *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := zone.region.GetStorages(zone.Name, 0, "") - if err != nil { - return nil, err - } - istorages := []cloudprovider.ICloudStorage{} - for i := range storages { - storages[i].zone = zone - istorages = append(istorages, &storages[i]) - } - return istorages, nil -} - -func (zone *SZone) IsEmulated() bool { - return false -} - -func (zone *SZone) Refresh() error { - return nil -} - -func (zone *SZone) GetStatus() string { - if zone.Status == "UP" { - return api.ZONE_ENABLE - } - return api.ZONE_SOLDOUT -} diff --git a/pkg/multicloud/hcs/bucket.go b/pkg/multicloud/hcs/bucket.go deleted file mode 100644 index b35c5c56d4..0000000000 --- a/pkg/multicloud/hcs/bucket.go +++ /dev/null @@ -1,803 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - "fmt" - "io" - "net/http" - "strconv" - "strings" - "time" - - "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - "yunion.io/x/s3cli" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SBucket struct { - multicloud.SBaseBucket - multicloud.HuaweiTags - - region *SRegion - - Name string - Location string - CreationDate time.Time -} - -func (b *SBucket) GetProjectId() string { - resp, err := b.region.HeadBucket(b.Name) - if err != nil { - return "" - } - epid, _ := resp.ResponseHeaders["epid"] - if len(epid) > 0 { - return epid[0] - } - return "" -} - -func (b *SBucket) GetGlobalId() string { - return b.Name -} - -func (b *SBucket) GetName() string { - return b.Name -} - -func (b *SBucket) GetLocation() string { - return b.Location -} - -func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { - return b.region -} - -func (b *SBucket) GetCreateAt() time.Time { - return b.CreationDate -} - -func (b *SBucket) GetStorageClass() string { - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("b.region.getOBSClient error %s", err) - return "" - } - output, err := obscli.GetBucketStoragePolicy(b.Name) - if err != nil { - log.Errorf("obscli.GetBucketStoragePolicy error %s", err) - return "" - } - return output.StorageClass -} - -func obsAcl2CannedAcl(acls []obs.Grant) cloudprovider.TBucketACLType { - switch { - case len(acls) == 1: - if acls[0].Grantee.URI == "" && acls[0].Permission == s3cli.PERMISSION_FULL_CONTROL { - return cloudprovider.ACLPrivate - } - case len(acls) == 2: - for _, g := range acls { - if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_AUTH_USERS && g.Permission == s3cli.PERMISSION_READ { - return cloudprovider.ACLAuthRead - } - if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_READ { - return cloudprovider.ACLPublicRead - } - } - case len(acls) == 3: - for _, g := range acls { - if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_WRITE { - return cloudprovider.ACLPublicReadWrite - } - } - } - return cloudprovider.ACLUnknown -} - -func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("b.region.getOBSClient error %s", err) - return acl - } - output, err := obscli.GetBucketAcl(b.Name) - if err != nil { - log.Errorf("obscli.GetBucketAcl error %s", err) - return acl - } - acl = obsAcl2CannedAcl(output.Grants) - return acl -} - -func (b *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "b.region.getOBSClient") - } - input := &obs.SetBucketAclInput{} - input.Bucket = b.Name - input.ACL = obs.AclType(string(acl)) - _, err = obscli.SetBucketAcl(input) - if err != nil { - return errors.Wrap(err, "obscli.SetBucketAcl") - } - return nil -} - -func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { - return []cloudprovider.SBucketAccessUrl{ - { - Url: fmt.Sprintf("https://%s.%s", b.Name, b.region.getOBSEndpoint()), - Description: "bucket url", - Primary: true, - }, - { - Url: fmt.Sprintf("https://%s/%s", b.region.getOBSEndpoint(), b.Name), - Description: "obs url", - }, - } -} - -func (b *SBucket) GetStats() cloudprovider.SBucketStats { - stats := cloudprovider.SBucketStats{} - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("b.region.getOBSClient error %s", err) - stats.SizeBytes = -1 - stats.ObjectCount = -1 - return stats - } - output, err := obscli.GetBucketStorageInfo(b.Name) - if err != nil { - log.Errorf("obscli.GetBucketStorageInfo error %s", err) - stats.SizeBytes = -1 - stats.ObjectCount = -1 - return stats - } - stats.SizeBytes = output.Size - stats.ObjectCount = output.ObjectNumber - return stats -} - -func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { - result := cloudprovider.SListObjectResult{} - obscli, err := b.region.getOBSClient() - if err != nil { - return result, errors.Wrap(err, "GetOBSClient") - } - input := &obs.ListObjectsInput{} - input.Bucket = b.Name - if len(prefix) > 0 { - input.Prefix = prefix - } - if len(marker) > 0 { - input.Marker = marker - } - if len(delimiter) > 0 { - input.Delimiter = delimiter - } - if maxCount > 0 { - input.MaxKeys = maxCount - } - oResult, err := obscli.ListObjects(input) - if err != nil { - return result, errors.Wrap(err, "ListObjects") - } - result.Objects = make([]cloudprovider.ICloudObject, 0) - for _, object := range oResult.Contents { - obj := &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - StorageClass: string(object.StorageClass), - Key: object.Key, - SizeBytes: object.Size, - ETag: object.ETag, - LastModified: object.LastModified, - }, - } - result.Objects = append(result.Objects, obj) - } - if oResult.CommonPrefixes != nil { - result.CommonPrefixes = make([]cloudprovider.ICloudObject, 0) - for _, commonPrefix := range oResult.CommonPrefixes { - obj := &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - Key: commonPrefix, - }, - } - result.CommonPrefixes = append(result.CommonPrefixes, obj) - } - } - result.IsTruncated = oResult.IsTruncated - result.NextMarker = oResult.NextMarker - return result, nil -} - -func (b *SBucket) PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.PutObjectInput{} - input.Bucket = b.Name - input.Key = key - input.Body = reader - - if sizeBytes > 0 { - input.ContentLength = sizeBytes - } - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return err - } - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.ACL = obs.AclType(string(cannedAcl)) - if meta != nil { - val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) - if len(val) > 0 { - input.ContentType = val - } - val = meta.Get(cloudprovider.META_HEADER_CONTENT_MD5) - if len(val) > 0 { - input.ContentMD5 = val - } - extraMeta := make(map[string]string) - for k, v := range meta { - if utils.IsInStringArray(k, []string{ - cloudprovider.META_HEADER_CONTENT_TYPE, - cloudprovider.META_HEADER_CONTENT_MD5, - }) { - continue - } - if len(v[0]) > 0 { - extraMeta[k] = v[0] - } - } - input.Metadata = extraMeta - } - _, err = obscli.PutObject(input) - if err != nil { - return errors.Wrap(err, "PutObject") - } - return nil -} - -func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - - input := &obs.InitiateMultipartUploadInput{} - input.Bucket = b.Name - input.Key = key - if meta != nil { - val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) - if len(val) > 0 { - input.ContentType = val - } - extraMeta := make(map[string]string) - for k, v := range meta { - if utils.IsInStringArray(k, []string{ - cloudprovider.META_HEADER_CONTENT_TYPE, - }) { - continue - } - if len(v[0]) > 0 { - extraMeta[k] = v[0] - } - } - input.Metadata = extraMeta - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.ACL = obs.AclType(string(cannedAcl)) - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return "", errors.Wrap(err, "str2StorageClass") - } - } - output, err := obscli.InitiateMultipartUpload(input) - if err != nil { - return "", errors.Wrap(err, "InitiateMultipartUpload") - } - - return output.UploadId, nil -} - -func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, part io.Reader, partSize int64, offset, totalSize int64) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - - input := &obs.UploadPartInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - input.PartNumber = partIndex - input.PartSize = partSize - input.Body = part - output, err := obscli.UploadPart(input) - if err != nil { - return "", errors.Wrap(err, "UploadPart") - } - - return output.ETag, nil -} - -func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.CompleteMultipartUploadInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - parts := make([]obs.Part, len(partEtags)) - for i := range partEtags { - parts[i] = obs.Part{ - PartNumber: i + 1, - ETag: partEtags[i], - } - } - input.Parts = parts - _, err = obscli.CompleteMultipartUpload(input) - if err != nil { - return errors.Wrap(err, "CompleteMultipartUpload") - } - - return nil -} - -func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - input := &obs.AbortMultipartUploadInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - - _, err = obscli.AbortMultipartUpload(input) - if err != nil { - return errors.Wrap(err, "AbortMultipartUpload") - } - - return nil -} - -func (b *SBucket) DeleteObject(ctx context.Context, key string) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.DeleteObjectInput{} - input.Bucket = b.Name - input.Key = key - _, err = obscli.DeleteObject(input) - if err != nil { - return errors.Wrap(err, "DeleteObject") - } - return nil -} - -func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - input := obs.CreateSignedUrlInput{} - input.Bucket = b.Name - input.Key = key - input.Expires = int(expire / time.Second) - switch method { - case "GET": - input.Method = obs.HttpMethodGet - case "PUT": - input.Method = obs.HttpMethodPut - case "DELETE": - input.Method = obs.HttpMethodDelete - default: - return "", errors.Error("unsupported method") - } - output, err := obscli.CreateSignedUrl(&input) - return output.SignedUrl, nil -} - -func (b *SBucket) LimitSupport() cloudprovider.SBucketStats { - return cloudprovider.SBucketStats{ - SizeBytes: 1, - ObjectCount: -1, - } -} - -func (b *SBucket) GetLimit() cloudprovider.SBucketStats { - stats := cloudprovider.SBucketStats{} - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("getOBSClient error %s", err) - return stats - } - output, err := obscli.GetBucketQuota(b.Name) - if err != nil { - return stats - } - stats.SizeBytes = output.Quota - return stats -} - -func (b *SBucket) SetLimit(limit cloudprovider.SBucketStats) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "getOBSClient") - } - input := &obs.SetBucketQuotaInput{} - input.Bucket = b.Name - input.Quota = limit.SizeBytes - _, err = obscli.SetBucketQuota(input) - if err != nil { - return errors.Wrap(err, "SetBucketQuota") - } - return nil -} - -func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.CopyObjectInput{} - input.Bucket = b.Name - input.Key = destKey - input.CopySourceBucket = srcBucket - input.CopySourceKey = srcKey - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return err - } - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.ACL = obs.AclType(string(cannedAcl)) - if meta != nil { - val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) - if len(val) > 0 { - input.ContentType = val - } - extraMeta := make(map[string]string) - for k, v := range meta { - if utils.IsInStringArray(k, []string{ - cloudprovider.META_HEADER_CONTENT_TYPE, - }) { - continue - } - if len(v[0]) > 0 { - extraMeta[k] = v[0] - } - } - input.Metadata = extraMeta - input.MetadataDirective = obs.ReplaceMetadata - } else { - input.MetadataDirective = obs.CopyMetadata - } - _, err = obscli.CopyObject(input) - if err != nil { - return errors.Wrap(err, "obscli.CopyObject") - } - return nil -} - -func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - input := &obs.GetObjectInput{} - input.Bucket = b.Name - input.Key = key - if rangeOpt != nil { - input.RangeStart = rangeOpt.Start - input.RangeEnd = rangeOpt.End - } - output, err := obscli.GetObject(input) - if err != nil { - return nil, errors.Wrap(err, "obscli.GetObject") - } - return output.Body, nil -} - -func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - input := &obs.CopyPartInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - input.PartNumber = partIndex - input.CopySourceBucket = srcBucket - input.CopySourceKey = srcKey - input.CopySourceRangeStart = srcOffset - input.CopySourceRangeEnd = srcOffset + srcLength - 1 - output, err := obscli.CopyPart(input) - if err != nil { - return "", errors.Wrap(err, "CopyPart") - } - return output.ETag, nil -} - -func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - obsWebConf := obs.SetBucketWebsiteConfigurationInput{} - obsWebConf.Bucket = b.Name - obsWebConf.BucketWebsiteConfiguration = obs.BucketWebsiteConfiguration{ - IndexDocument: obs.IndexDocument{Suffix: websitConf.Index}, - ErrorDocument: obs.ErrorDocument{Key: websitConf.ErrorDocument}, - } - _, err = obscli.SetBucketWebsiteConfiguration(&obsWebConf) - if err != nil { - return errors.Wrap(err, "obscli.SetBucketWebsiteConfiguration(&obsWebConf)") - } - return nil -} - -func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { - result := cloudprovider.SBucketWebsiteConf{} - obscli, err := b.region.getOBSClient() - if err != nil { - return result, errors.Wrap(err, "GetOBSClient") - } - out, err := obscli.GetBucketWebsiteConfiguration(b.Name) - if out == nil { - return result, nil - } - result.Index = out.IndexDocument.Suffix - result.ErrorDocument = out.ErrorDocument.Key - result.Url = fmt.Sprintf("https://%s.obs-website.%s.myhuaweicloud.com", b.Name, b.region.GetId()) - return result, nil -} - -func (b *SBucket) DeleteWebSiteConf() error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - _, err = obscli.DeleteBucketWebsiteConfiguration(b.Name) - if err != nil { - return errors.Wrapf(err, "obscli.DeleteBucketWebsiteConfiguration(%s)", b.Name) - } - return nil -} - -func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - opts := []obs.CorsRule{} - for i := range rules { - opts = append(opts, obs.CorsRule{ - AllowedOrigin: rules[i].AllowedOrigins, - AllowedMethod: rules[i].AllowedMethods, - AllowedHeader: rules[i].AllowedHeaders, - MaxAgeSeconds: rules[i].MaxAgeSeconds, - ExposeHeader: rules[i].ExposeHeaders, - }) - } - - input := obs.SetBucketCorsInput{} - input.Bucket = b.Name - input.BucketCors.CorsRules = opts - _, err = obscli.SetBucketCors(&input) - if err != nil { - return errors.Wrapf(err, "obscli.SetBucketCors(%s)", jsonutils.Marshal(input).String()) - } - return nil -} - -func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - conf, err := obscli.GetBucketCors(b.Name) - if err != nil { - if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") { - return nil, errors.Wrapf(err, "obscli.GetBucketCors(%s)", b.Name) - } - } - if conf == nil { - return nil, nil - } - result := []cloudprovider.SBucketCORSRule{} - for i := range conf.CorsRules { - result = append(result, cloudprovider.SBucketCORSRule{ - AllowedOrigins: conf.CorsRules[i].AllowedOrigin, - AllowedMethods: conf.CorsRules[i].AllowedMethod, - AllowedHeaders: conf.CorsRules[i].AllowedHeader, - MaxAgeSeconds: conf.CorsRules[i].MaxAgeSeconds, - ExposeHeaders: conf.CorsRules[i].ExposeHeader, - Id: strconv.Itoa(i), - }) - } - return result, nil -} - -func (b *SBucket) DeleteCORS() error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - _, err = obscli.DeleteBucketCors(b.Name) - if err != nil { - return errors.Wrapf(err, "obscli.DeleteBucketCors(%s)", b.Name) - } - return nil -} - -func (b *SBucket) GetTags() (map[string]string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - tagresult, err := obscli.GetBucketTagging(b.Name) - if err != nil { - if strings.Contains(err.Error(), "404") { - return nil, nil - } - return nil, errors.Wrapf(err, "osscli.GetBucketTagging(%s)", b.Name) - } - result := map[string]string{} - for i := range tagresult.Tags { - result[tagresult.Tags[i].Key] = tagresult.Tags[i].Value - } - return result, nil -} - -func (b *SBucket) SetTags(tags map[string]string, replace bool) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - _, err = obscli.DeleteBucketTagging(b.Name) - if err != nil { - return errors.Wrapf(err, "DeleteBucketTagging") - } - - if len(tags) == 0 { - return nil - } - - input := obs.SetBucketTaggingInput{BucketTagging: obs.BucketTagging{}} - input.Bucket = b.Name - for k, v := range tags { - input.BucketTagging.Tags = append(input.BucketTagging.Tags, obs.Tag{Key: k, Value: v}) - } - - _, err = obscli.SetBucketTagging(&input) - if err != nil { - return errors.Wrapf(err, "obscli.SetBucketTagging(%s)", jsonutils.Marshal(input).String()) - } - return nil -} - -func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - result := []cloudprovider.SBucketMultipartUploads{} - - input := obs.ListMultipartUploadsInput{Bucket: b.Name} - keyMarker := "" - uploadIDMarker := "" - for { - if len(keyMarker) > 0 { - input.KeyMarker = keyMarker - } - if len(uploadIDMarker) > 0 { - input.UploadIdMarker = uploadIDMarker - } - - output, err := obscli.ListMultipartUploads(&input) - if err != nil { - return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") - } - for i := range output.Uploads { - temp := cloudprovider.SBucketMultipartUploads{ - ObjectName: output.Uploads[i].Key, - UploadID: output.Uploads[i].UploadId, - Initiator: output.Uploads[i].Initiator.DisplayName, - Initiated: output.Uploads[i].Initiated, - } - result = append(result, temp) - } - keyMarker = output.NextKeyMarker - uploadIDMarker = output.NextUploadIdMarker - if !output.IsTruncated { - break - } - } - - return result, nil -} - -func (self *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { - return self.CreateBucket(name, storageClassStr, aclStr) -} - -func (self *SRegion) CreateBucket(name string, storageClassStr string, aclStr string) error { - obsClient, err := self.getOBSClient() - if err != nil { - return errors.Wrap(err, "self.getOBSClient") - } - input := &obs.CreateBucketInput{} - input.Bucket = name - input.Location = self.GetId() - if len(aclStr) > 0 { - if strings.EqualFold(aclStr, string(obs.AclPrivate)) { - input.ACL = obs.AclPrivate - } else if strings.EqualFold(aclStr, string(obs.AclPublicRead)) { - input.ACL = obs.AclPublicRead - } else if strings.EqualFold(aclStr, string(obs.AclPublicReadWrite)) { - input.ACL = obs.AclPublicReadWrite - } else { - return errors.Error("unsupported acl") - } - } - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return err - } - } - _, err = obsClient.CreateBucket(input) - if err != nil { - return errors.Wrap(err, "obsClient.CreateBucket") - } - return nil -} diff --git a/pkg/multicloud/hcs/dbinstance.go b/pkg/multicloud/hcs/dbinstance.go deleted file mode 100644 index db781c9119..0000000000 --- a/pkg/multicloud/hcs/dbinstance.go +++ /dev/null @@ -1,706 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -type SBackupStrategy struct { - KeepDays int - StartTime string -} - -type SDatastore struct { - Type string - Version string -} - -type SHa struct { - ReplicationMode string -} - -type SNonde struct { - AvailabilityZone string - Id string - Name string - Role string - Staus string -} - -type SVolume struct { - Size int - Type string -} - -type SRelatedInstance struct { - Id string - Type string -} - -type SDBInstance struct { - multicloud.SDBInstanceBase - multicloud.HuaweiTags - region *SRegion - - flavorCache []SDBInstanceFlavor - - BackupStrategy SBackupStrategy - Created string //time.Time - Datastore SDatastore - DbUserName string - DIskEncryptionId string - FlavorRef string - Ha SHa - Id string - MaintenanceWindow string - Name string - Nodes []SNonde - Port int - PrivateIps []string - PublicIps []string - Region string - RelatedInstance []SRelatedInstance - SecurityGroupId string - Status string - SubnetId string - SwitchStrategy string - TimeZone string - Type string - Updated string //time.Time - Volume SVolume - VpcId string - EnterpriseProjectId string -} - -func (region *SRegion) GetDBInstances() ([]SDBInstance, error) { - dbinstances := []SDBInstance{} - err := region.rdsList("instances", nil, nil) - return dbinstances, err -} - -func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { - if len(instanceId) == 0 { - return nil, cloudprovider.ErrNotFound - } - instance := SDBInstance{region: region} - res := &SDBInstance{} - err := region.rdsGet(fmt.Sprintf("instance/%s", instanceId), res) - return &instance, err -} - -func (rds *SDBInstance) GetName() string { - return rds.Name -} - -func (rds *SDBInstance) GetId() string { - return rds.Id -} - -func (rds *SDBInstance) GetGlobalId() string { - return rds.GetId() -} - -// 值为“BUILD”,表示实例正在创建。 -// 值为“ACTIVE”,表示实例正常。 -// 值为“FAILED”,表示实例异常。 -// 值为“FROZEN”,表示实例冻结。 -// 值为“MODIFYING”,表示实例正在扩容。 -// 值为“REBOOTING”,表示实例正在重启。 -// 值为“RESTORING”,表示实例正在恢复。 -// 值为“MODIFYING INSTANCE TYPE”,表示实例正在转主备。 -// 值为“SWITCHOVER”,表示实例正在主备切换。 -// 值为“MIGRATING”,表示实例正在迁移。 -// 值为“BACKING UP”,表示实例正在进行备份。 -// 值为“MODIFYING DATABASE PORT”,表示实例正在修改数据库端口。 -// 值为“STORAGE FULL”,表示实例磁盘空间满。 - -func (rds *SDBInstance) GetStatus() string { - switch rds.Status { - case "BUILD", "MODIFYING", "MODIFYING INSTANCE TYPE", "SWITCHOVER", "MODIFYING DATABASE PORT": - return api.DBINSTANCE_DEPLOYING - case "ACTIVE": - return api.DBINSTANCE_RUNNING - case "FAILED", "FROZEN", "STORAGE FULL": - return api.DBINSTANCE_UNKNOWN - case "REBOOTING": - return api.DBINSTANCE_REBOOTING - case "RESTORING": - return api.DBINSTANCE_RESTORING - case "MIGRATING": - return api.DBINSTANCE_MIGRATING - case "BACKING UP": - return api.DBINSTANCE_BACKING_UP - } - return rds.Status -} - -func (rds *SDBInstance) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (rds *SDBInstance) GetSecurityGroupIds() ([]string, error) { - return []string{rds.SecurityGroupId}, nil -} - -func (rds *SDBInstance) fetchFlavor() error { - if len(rds.flavorCache) > 0 { - return nil - } - flavors, err := rds.region.GetDBInstanceFlavors(rds.Datastore.Type, rds.Datastore.Version) - if err != nil { - return err - } - rds.flavorCache = flavors - return nil -} - -func (rds *SDBInstance) GetExpiredAt() time.Time { - return time.Time{} -} - -func (rds *SDBInstance) GetStorageType() string { - return rds.Volume.Type -} - -func (rds *SDBInstance) GetCreatedAt() time.Time { - t, err := time.Parse("2006-01-02T15:04:05Z0700", rds.Created) - if err != nil { - return time.Time{} - } - return t -} - -func (rds *SDBInstance) GetEngine() string { - return rds.Datastore.Type -} - -func (rds *SDBInstance) GetEngineVersion() string { - return rds.Datastore.Version -} - -func (rds *SDBInstance) GetInstanceType() string { - return rds.FlavorRef -} - -func (rds *SDBInstance) GetCategory() string { - switch rds.Type { - case "Single": - return api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE - case "Ha": - return api.HUAWEI_DBINSTANCE_CATEGORY_HA - case "Replica": - return api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA - } - return rds.Type -} - -func (rds *SDBInstance) GetVcpuCount() int { - err := rds.fetchFlavor() - if err != nil { - log.Errorf("failed to fetch flavors: %v", err) - return 0 - } - for _, flavor := range rds.flavorCache { - if flavor.SpecCode == rds.FlavorRef { - return flavor.Vcpus - } - } - return 0 -} - -func (rds *SDBInstance) GetVmemSizeMB() int { - err := rds.fetchFlavor() - if err != nil { - log.Errorf("failed to fetch flavors: %v", err) - return 0 - } - for _, flavor := range rds.flavorCache { - if flavor.SpecCode == rds.FlavorRef { - return flavor.Ram * 1024 - } - } - return 0 -} - -func (rds *SDBInstance) GetDiskSizeGB() int { - return rds.Volume.Size -} - -func (rds *SDBInstance) GetPort() int { - return rds.Port -} - -func (rds *SDBInstance) GetMaintainTime() string { - return rds.MaintenanceWindow -} - -func (rds *SDBInstance) GetIVpcId() string { - return rds.VpcId -} - -func (rds *SDBInstance) GetProjectId() string { - return rds.EnterpriseProjectId -} - -func (rds *SDBInstance) Refresh() error { - instance, err := rds.region.GetDBInstance(rds.Id) - if err != nil { - return err - } - return jsonutils.Update(rds, instance) -} - -func (rds *SDBInstance) GetZone1Id() string { - return rds.GetZoneIdByRole("master") -} - -func (rds *SDBInstance) GetZoneIdByRole(role string) string { - // for _, node := range rds.Nodes { - // if node.Role == role { - // zone, err := rds.region.getZoneById(node.AvailabilityZone) - // if err != nil { - // log.Errorf("failed to found zone %s for rds %s error: %v", node.AvailabilityZone, rds.Name, err) - // return "" - // } - // return zone.GetGlobalId() - // } - // } - return "" -} - -func (rds *SDBInstance) GetZone2Id() string { - return rds.GetZoneIdByRole("slave") -} - -func (rds *SDBInstance) GetZone3Id() string { - return "" -} - -type SRdsNetwork struct { - SubnetId string - IP string -} - -func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { - ret := []cloudprovider.SDBInstanceNetwork{} - for _, ip := range rds.PrivateIps { - network := cloudprovider.SDBInstanceNetwork{ - IP: ip, - NetworkId: rds.SubnetId, - } - ret = append(ret, network) - } - return ret, nil -} - -func (rds *SDBInstance) GetInternalConnectionStr() string { - for _, ip := range rds.PrivateIps { - return ip - } - return "" -} - -func (rds *SDBInstance) GetConnectionStr() string { - for _, ip := range rds.PublicIps { - return ip - } - return "" -} - -func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { - dbinstance, err := region.GetDBInstance(instanceId) - if err != nil { - log.Errorf("failed to get dbinstance by id %s error: %v", instanceId, err) - } - return dbinstance, err -} - -func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - instances, err := region.GetDBInstances() - if err != nil { - return nil, errors.Wrapf(err, "region.GetDBInstances()") - } - idbinstances := []cloudprovider.ICloudDBInstance{} - for i := 0; i < len(instances); i++ { - instances[i].region = region - idbinstances = append(idbinstances, &instances[i]) - } - return idbinstances, nil -} - -func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { - parameters, err := rds.region.GetDBInstanceParameters(rds.Id) - if err != nil { - return nil, err - } - iparameters := []cloudprovider.ICloudDBInstanceParameter{} - for i := 0; i < len(parameters); i++ { - iparameters = append(iparameters, ¶meters[i]) - } - return iparameters, nil -} - -func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { - databases, err := rds.region.GetDBInstanceDatabases(rds.Id) - if err != nil { - return nil, errors.Wrap(err, "rds.region.GetDBInstanceDatabases(rds.Id)") - } - - idatabase := []cloudprovider.ICloudDBInstanceDatabase{} - for i := 0; i < len(databases); i++ { - databases[i].instance = rds - idatabase = append(idatabase, &databases[i]) - } - return idatabase, nil -} - -func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { - accounts, err := rds.region.GetDBInstanceAccounts(rds.Id) - if err != nil { - return nil, errors.Wrap(err, "rds.region.GetDBInstanceAccounts(rds.Id)") - } - - user := "root" - if rds.GetEngine() == api.DBINSTANCE_TYPE_SQLSERVER { - user = "rduser" - } - - accounts = append(accounts, SDBInstanceAccount{ - Name: user, - instance: rds, - }) - - iaccounts := []cloudprovider.ICloudDBInstanceAccount{} - for i := 0; i < len(accounts); i++ { - accounts[i].instance = rds - iaccounts = append(iaccounts, &accounts[i]) - } - return iaccounts, nil -} - -func (rds *SDBInstance) Delete() error { - return rds.region.DeleteDBInstance(rds.Id) -} - -func (region *SRegion) DeleteDBInstance(instanceId string) error { - err := region.client.rdsDelete(region.Id, instanceId) - return err -} - -func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - zoneIds := []string{} - zones, err := region.GetIZones() - if err != nil { - return nil, err - } - for _, zone := range zones { - zoneIds = append(zoneIds, zone.GetId()) - } - - if len(desc.SecgroupIds) == 0 { - return nil, fmt.Errorf("Missing secgroupId") - } - - params := map[string]interface{}{ - "region": region.Id, - "name": desc.Name, - "datastore": map[string]string{ - "type": desc.Engine, - "version": desc.EngineVersion, - }, - "password": desc.Password, - "volume": map[string]interface{}{ - "type": desc.StorageType, - "size": desc.DiskSizeGB, - }, - "vpc_id": desc.VpcId, - "subnet_id": desc.NetworkId, - "security_group_id": desc.SecgroupIds[0], - } - - if len(desc.ProjectId) > 0 { - params["enterprise_project_id"] = desc.ProjectId - } - - if len(desc.MasterInstanceId) > 0 { - params["replica_of_id"] = desc.MasterInstanceId - delete(params, "security_group_id") - } - - if len(desc.RdsId) > 0 && len(desc.BackupId) > 0 { - params["restore_point"] = map[string]interface{}{ - "backup_id": desc.BackupId, - "instance_id": desc.RdsId, - "type": "backup", - } - } - - switch desc.Category { - case api.HUAWEI_DBINSTANCE_CATEGORY_HA: - switch desc.Engine { - case api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL: - params["ha"] = map[string]string{ - "mode": "Ha", - "replication_mode": "async", - } - case api.DBINSTANCE_TYPE_SQLSERVER: - params["ha"] = map[string]string{ - "mode": "Ha", - "replication_mode": "sync", - } - } - case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE: - case api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA: - } - - if desc.BillingCycle != nil { - periodType := "month" - periodNum := desc.BillingCycle.GetMonths() - if desc.BillingCycle.GetYears() > 0 { - periodType = "year" - periodNum = desc.BillingCycle.GetYears() - } - params["charge_info"] = map[string]interface{}{ - "charge_mode": "prePaid", - "period_type": periodType, - "period_num": periodNum, - "is_auto_renew": false, - } - } - params["flavor_ref"] = desc.InstanceType - params["availability_zone"] = desc.ZoneId - resp, err := region.client.request(httputils.POST, region.client._url("instance", "v3", region.Id, "instance"), nil, params) - if err != nil { - return nil, errors.Wrapf(err, "Create") - } - - instance := &SDBInstance{region: region} - err = resp.Unmarshal(instance, "instance") - if err != nil { - return nil, errors.Wrap(err, `resp.Unmarshal(&instance, "instance")`) - } - if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { - err = cloudprovider.Wait(10*time.Second, 20*time.Minute, func() (bool, error) { - - job, err := region.client.request(httputils.POST, region.client._url(fmt.Sprintf("instance/%s", jobId), "v3", region.Id, "instance"), nil, params) - if err != nil { - return false, nil - } - status, _ := job.GetString("status") - process, _ := job.GetString("process") - log.Debugf("create dbinstance job %s status: %s process: %s", jobId, status, process) - if status == "Completed" { - return true, nil - } - if status == "Failed" { - return false, fmt.Errorf("create failed") - } - return false, nil - }) - } - return instance, err -} - -func (rds *SDBInstance) Reboot() error { - // return rds.region.RebootDBInstance(rds.Id) - return nil -} - -func (rds *SDBInstance) OpenPublicConnection() error { - return fmt.Errorf("Huawei current not support this operation") - //return rds.region.PublicConnectionAction(rds.Id, "openRC") -} - -func (rds *SDBInstance) ClosePublicConnection() error { - return fmt.Errorf("Huawei current not support this operation") - //return rds.region.PublicConnectionAction(rds.Id, "closeRC") -} - -func (region *SRegion) PublicConnectionAction(instanceId string, action string) error { - return cloudprovider.ErrNotImplemented - /*resp, err := region.ecsClient.DBInstance.PerformAction2(action, instanceId, nil, "") - if err != nil { - return errors.Wrapf(err, "rds.%s", action) - } - - if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { - err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { - job := struct { - Status string - Process string - }{} - query := url.Values{} - query.Add("id", jobId) - err := region.rdsJobGet("jobs", query, job) - if err != nil { - log.Errorf("failed to get job %s info error: %v", jobId, err) - return false - } - if job.Status == "Completed" { - return true - } - log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, job.Status, job.Process) - return false - }) - } - - return nil - */ -} - -func (region *SRegion) RebootDBInstance(instanceId string) error { - return cloudprovider.ErrNotImplemented - /*params := jsonutils.Marshal(map[string]interface{}{ - "restart": map[string]string{}, - }) - resp, err := region.ecsClient.DBInstance.PerformAction2("action", instanceId, params, "") - if err != nil { - return err - } - if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { - err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { - job := struct { - Status string - Process string - }{} - query := url.Values{} - query.Add("id", jobId) - err := region.rdsJobGet("jobs", query, job) - if err != nil { - log.Errorf("failed to get job %s info error: %v", jobId, err) - return false - } - if job.Status == "Completed" { - return true - } - log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, job.Status, job.Process) - return false - }) - } - return err*/ -} - -func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { - return rds.region.CreateDBInstanceAccount(rds.Id, conf.Name, conf.Password) -} - -func (region *SRegion) CreateDBInstanceAccount(instanceId, account, password string) error { - params := map[string]interface{}{ - "name": account, - "password": password, - } - - err := region.rdsCreate(fmt.Sprintf("instances/%s/db_user", instanceId), params, nil) - return err -} - -func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { - return rds.region.CreateDBInstanceDatabase(rds.Id, conf.Name, conf.CharacterSet) -} - -func (region *SRegion) CreateDBInstanceDatabase(instanceId, database, characterSet string) error { - params := map[string]interface{}{ - "name": database, - "character_set": characterSet, - } - err := region.rdsCreate(fmt.Sprintf("instances/%s/database", instanceId), params, nil) - return err -} - -func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { - return rds.region.ChangeDBInstanceConfig(rds.Id, desc.InstanceType, desc.DiskSizeGB) -} - -func (region *SRegion) ChangeDBInstanceConfig(instanceId string, instanceType string, diskSizeGb int) error { - instance, err := region.GetIDBInstanceById(instanceId) - if err != nil { - return errors.Wrapf(err, "region.GetIDBInstanceById(%s)", instanceId) - } - - if len(instanceType) > 0 { - params := map[string]interface{}{ - "resize_flavor": map[string]string{ - "spec_code": instanceType, - }, - } - err := region.rdsPerform(fmt.Sprintf("instances/%s", instanceId), "action", params, nil) - if err != nil { - return errors.Wrap(err, "resize_flavor") - } - cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) - } - if diskSizeGb > 0 { - params := map[string]interface{}{ - "enlarge_volume": map[string]int{ - "size": diskSizeGb, - }, - } - err := region.rdsPerform(fmt.Sprintf("instances/%s", instanceId), "action", params, nil) - if err != nil { - return errors.Wrap(err, "enlarge_volume") - } - cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) - } - return nil -} - -func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { - if len(conf.OriginDBInstanceExternalId) == 0 { - conf.OriginDBInstanceExternalId = rds.Id - } - return rds.region.RecoveryDBInstanceFromBackup(rds.Id, conf.OriginDBInstanceExternalId, conf.BackupId, conf.Databases) -} - -func (region *SRegion) RecoveryDBInstanceFromBackup(target, origin string, backupId string, databases map[string]string) error { - source := map[string]interface{}{ - "type": "backup", - "backup_id": backupId, - } - if len(origin) > 0 { - source["instance_id"] = origin - } - if len(databases) > 0 { - source["database_name"] = databases - } - params := map[string]interface{}{ - "source": source, - "target": map[string]string{ - "instance_id": target, - }, - } - err := region.rdsPerform("instance", "recovery", params, nil) - if err != nil { - return errors.Wrap(err, "dbinstance.recovery") - } - return nil -} - -func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/hcs/dbinstance_account.go b/pkg/multicloud/hcs/dbinstance_account.go deleted file mode 100644 index 9717eeaddd..0000000000 --- a/pkg/multicloud/hcs/dbinstance_account.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceAccount struct { - multicloud.SDBInstanceAccountBase - multicloud.HuaweiTags - instance *SDBInstance - Name string -} - -func (account *SDBInstanceAccount) GetName() string { - return account.Name -} - -func (account *SDBInstanceAccount) Delete() error { - return account.instance.region.rdsDelete(fmt.Sprintf("%s/db_user/%s", account.instance.Id, account.Name)) -} - -func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { - privileges, err := account.instance.region.GetDBInstancePrivileges(account.instance.Id, account.Name) - if err != nil { - return nil, err - } - iprivileves := []cloudprovider.ICloudDBInstanceAccountPrivilege{} - for i := 0; i < len(privileges); i++ { - privileges[i].account = account - iprivileves = append(iprivileves, &privileges[i]) - } - return iprivileves, nil -} - -func (region *SRegion) GetDBInstanceAccounts(instanceId string) ([]SDBInstanceAccount, error) { - accounts := []SDBInstanceAccount{} - err := region.rdsList(fmt.Sprintf("instances/%s/db_user/detail", instanceId), nil, accounts) - if err != nil { - return nil, err - } - return accounts, nil -} - -func (region *SRegion) GetDBInstancePrivileges(instanceId string, username string) ([]SDatabasePrivilege, error) { - query := url.Values{} - query.Add("iser-name", username) - privileges := []SDatabasePrivilege{} - err := region.rdsList(fmt.Sprintf("instances/%s/db_user/database", instanceId), query, privileges) - if err != nil { - return nil, err - } - return privileges, nil -} - -func (account *SDBInstanceAccount) RevokePrivilege(database string) error { - return account.instance.region.RevokeDBInstancePrivilege(account.instance.Id, account.Name, database) -} - -func (region *SRegion) RevokeDBInstancePrivilege(instanceId string, account, database string) error { - params := map[string]interface{}{ - "db_name": database, - "users": []map[string]interface{}{ - map[string]interface{}{ - "name": account, - }, - }, - } - return region.rdsDBPrivilegesDelete(fmt.Sprintf("instances/%s/db_privilege", instanceId), params) -} - -func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { - return account.instance.region.GrantDBInstancePrivilege(account.instance.Id, account.Name, database, privilege) -} - -func (region *SRegion) GrantDBInstancePrivilege(instanceId string, account, database string, privilege string) error { - readonly := false - switch privilege { - case api.DATABASE_PRIVILEGE_R: - readonly = true - case api.DATABASE_PRIVILEGE_RW: - default: - return fmt.Errorf("Unknown privilege %s", privilege) - } - params := map[string]interface{}{ - "db_name": database, - "users": []map[string]interface{}{ - map[string]interface{}{ - "name": account, - "readonly": readonly, - }, - }, - } - resp := &struct { - Resp string - }{} - err := region.rdsDBPrivilegesGrant(fmt.Sprintf("instances/%s/db_privilege", instanceId), params, resp) - return err -} - -func (account *SDBInstanceAccount) ResetPassword(password string) error { - return account.instance.region.ResetDBInstanceAccountPassword(account.instance.Id, account.Name, password) -} - -func (region *SRegion) ResetDBInstanceAccountPassword(instanceId, account, password string) error { - return fmt.Errorf("The API does not exist or has not been published in the environment") -} diff --git a/pkg/multicloud/hcs/dbinstance_backup.go b/pkg/multicloud/hcs/dbinstance_backup.go deleted file mode 100644 index 3afb8d08bc..0000000000 --- a/pkg/multicloud/hcs/dbinstance_backup.go +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceBackup struct { - multicloud.SDBInstanceBackupBase - multicloud.HuaweiTags - region *SRegion - - BeginTime string - Datastore SDatastore - EndTime string - Id string - InstanceId string - Name string - Size int - Status string - Type string -} - -func (backup *SDBInstanceBackup) GetId() string { - return backup.Id -} - -func (backup *SDBInstanceBackup) GetGlobalId() string { - return backup.Id -} - -func (backup *SDBInstanceBackup) GetName() string { - return backup.Name -} - -func (backup *SDBInstanceBackup) GetEngine() string { - return backup.Datastore.Type -} - -func (backup *SDBInstanceBackup) GetEngineVersion() string { - return backup.Datastore.Version -} - -func (backup *SDBInstanceBackup) GetStartTime() time.Time { - //2019-08-05T08:00:02+0000 - t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.BeginTime) - if err != nil { - return time.Time{} - } - return t -} - -func (backup *SDBInstanceBackup) GetEndTime() time.Time { - t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.EndTime) - if err != nil { - return time.Time{} - } - return t -} - -func (backup *SDBInstanceBackup) GetBackupMode() string { - switch backup.Type { - case "manual": - return api.BACKUP_MODE_MANUAL - default: - return api.BACKUP_MODE_AUTOMATED - } -} - -func (backup *SDBInstanceBackup) GetStatus() string { - switch backup.Status { - case "COMPLETED": - return api.DBINSTANCE_BACKUP_READY - case "FAILED": - return api.DBINSTANCE_BACKUP_FAILED - case "BUILDING": - return api.DBINSTANCE_BACKUP_CREATING - case "DELETING": - return api.DBINSTANCE_BACKUP_DELETING - default: - return api.DBINSTANCE_BACKUP_UNKNOWN - } -} - -func (backup *SDBInstanceBackup) GetBackupSizeMb() int { - return backup.Size / 1024 -} - -func (backup *SDBInstanceBackup) GetDBNames() string { - return "" -} - -func (backup *SDBInstanceBackup) Delete() error { - return backup.region.DeleteDBInstanceBackup(backup.Id) -} - -func (region *SRegion) DeleteDBInstanceBackup(backupId string) error { - err := region.rdsDelete(fmt.Sprintf("backups/%s", backupId)) - return err -} - -func (backup *SDBInstanceBackup) GetDBInstanceId() string { - return backup.InstanceId -} - -func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string) ([]SDBInstanceBackup, error) { - query := url.Values{} - query.Add("instance_id", instanceId) - if len(backupId) > 0 { - query.Add("backup_id", backupId) - } - backups := []SDBInstanceBackup{} - err := region.rdsList("offsite-backups", query, backups) - if err != nil { - return nil, err - } - return backups, nil -} - -func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - dbinstnaces, err := region.GetIDBInstances() - if err != nil { - return nil, err - } - ibackups := []cloudprovider.ICloudDBInstanceBackup{} - for i := 0; i < len(dbinstnaces); i++ { - _dbinstance := dbinstnaces[i].(*SDBInstance) - _ibackup, err := _dbinstance.GetIDBInstanceBackups() - if err != nil { - return nil, errors.Wrapf(err, "_dbinstance(%v).GetIDBInstanceBackups", _dbinstance) - } - ibackups = append(ibackups, _ibackup...) - } - return ibackups, nil -} - -func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { - backups, err := region.GetIDBInstanceBackups() - if err != nil { - return nil, errors.Wrap(err, "region.GetIDBInstanceBackups") - } - for _, backup := range backups { - if backup.GetGlobalId() == backupId { - return backup, nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - backups, err := rds.region.GetDBInstanceBackups(rds.Id, "") - if err != nil { - return nil, err - } - - ibackups := []cloudprovider.ICloudDBInstanceBackup{} - for i := 0; i < len(backups); i++ { - backups[i].region = rds.region - ibackups = append(ibackups, &backups[i]) - } - return ibackups, nil -} - -func (backup *SDBInstanceBackup) Refresh() error { - backups, err := backup.region.GetDBInstanceBackups(backup.InstanceId, backup.Id) - if err != nil { - return err - } - if len(backups) == 0 { - return cloudprovider.ErrNotFound - } - return jsonutils.Update(backup, backups[0]) -} - -func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { - backupId, err := rds.region.CreateDBInstanceBackup(rds.Id, conf.Name, conf.Description, conf.Databases) - if err != nil { - return "", err - } - backup, err := rds.region.GetIDBInstanceBackupById(backupId) - if err != nil { - return "", errors.Wrap(err, "region.GetIDBInstanceBackupById") - } - cloudprovider.WaitStatus(backup, api.DBINSTANCE_BACKUP_READY, time.Second*3, time.Minute*30) - return backupId, nil -} - -func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, descrition string, databases []string) (string, error) { - params := map[string]interface{}{ - "instance_id": instanceId, - "name": name, - "description": descrition, - } - if len(databases) > 0 { - dbs := []map[string]string{} - for _, database := range databases { - dbs = append(dbs, map[string]string{"name": database}) - } - params["databases"] = dbs - } - backup := SDBInstanceBackup{} - err := region.rdsCreate("backups", params, backup) - if err != nil { - return "", errors.Wrap(err, "DBInstanceBackup.Create") - } - backupId := backup.Id - if err != nil { - return "", errors.Wrap(err, "resp.GetBackupId") - } - return backupId, nil -} - -func (self *SDBInstanceBackup) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - opts.BackupId = self.Id - return self.region.CreateIDBInstance(opts) -} diff --git a/pkg/multicloud/hcs/dbinstance_database.go b/pkg/multicloud/hcs/dbinstance_database.go deleted file mode 100644 index 5c06d6317f..0000000000 --- a/pkg/multicloud/hcs/dbinstance_database.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceDatabase struct { - instance *SDBInstance - multicloud.SDBInstanceDatabaseBase - multicloud.HuaweiTags - - Name string - CharacterSet string -} - -func (database *SDBInstanceDatabase) GetId() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetGlobalId() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetName() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetStatus() string { - return api.DBINSTANCE_DATABASE_RUNNING -} - -func (database *SDBInstanceDatabase) GetCharacterSet() string { - return database.CharacterSet -} - -func (database *SDBInstanceDatabase) Delete() error { - return database.instance.region.DeleteDBInstanceDatabase(database.instance.Id, database.Name) -} - -func (region *SRegion) DeleteDBInstanceDatabase(instanceId, database string) error { - resource := fmt.Sprintf("instances/%s/database/%s", instanceId, database) - err := region.rdsDelete(resource) - return err -} - -// rds查询数据库列表 -func (region *SRegion) GetDBInstanceDatabases(instanceId string) ([]SDBInstanceDatabase, error) { - resource := fmt.Sprintf("%s/database/detail", instanceId) - databases := []SDBInstanceDatabase{} - err := region.rdsList(resource, nil, databases) - if err != nil { - return nil, err - } - return databases, nil -} diff --git a/pkg/multicloud/hcs/dbinstance_privilege.go b/pkg/multicloud/hcs/dbinstance_privilege.go deleted file mode 100644 index 19ba785528..0000000000 --- a/pkg/multicloud/hcs/dbinstance_privilege.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" -) - -type SDatabasePrivilege struct { - account *SDBInstanceAccount - - Name string - Readonly bool -} - -func (privilege *SDatabasePrivilege) GetGlobalId() string { - return fmt.Sprintf("%s/%s", privilege.account.Name, privilege.Name) -} - -func (privilege *SDatabasePrivilege) GetPrivilege() string { - if privilege.Readonly { - return api.DATABASE_PRIVILEGE_R - } - return api.DATABASE_PRIVILEGE_RW -} - -func (privilege *SDatabasePrivilege) GetDBName() string { - return privilege.Name -} diff --git a/pkg/multicloud/hcs/dbinstance_skus.go b/pkg/multicloud/hcs/dbinstance_skus.go deleted file mode 100644 index ffa779f24d..0000000000 --- a/pkg/multicloud/hcs/dbinstance_skus.go +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SDBInstanceSku struct { - Vcpus int - Ram int //单位GB - SpecCode string - InstanceMode string //实例模型 - - StorageType string - Az1 string - Az2 string - Engine string - EngineVersion string -} - -func (self *SDBInstanceSku) GetName() string { - return self.SpecCode -} - -func (self *SDBInstanceSku) GetGlobalId() string { - return fmt.Sprintf("%s-%s-%s-%s-%s-%s", self.Engine, self.EngineVersion, self.InstanceMode, self.SpecCode, self.StorageType, self.GetZoneId()) -} - -func (self *SDBInstanceSku) GetCategory() string { - return self.InstanceMode -} - -func (self *SDBInstanceSku) GetDiskSizeStep() int { - return 10 -} - -func (self *SDBInstanceSku) GetIOPS() int { - return 0 -} - -func (self *SDBInstanceSku) GetTPS() int { - return 0 -} - -func (self *SDBInstanceSku) GetZone1Id() string { - return self.Az1 -} - -func (self *SDBInstanceSku) GetZone2Id() string { - return self.Az2 -} - -func (self *SDBInstanceSku) GetZone3Id() string { - return "" -} - -func (self *SDBInstanceSku) GetZoneId() string { - zones := []string{} - for _, zone := range []string{self.Az1, self.Az2} { - if len(zone) > 0 { - zones = append(zones, zone) - } - } - return strings.Join(zones, ",") -} - -func (self *SDBInstanceSku) GetMaxConnections() int { - return 0 -} - -func (self *SDBInstanceSku) GetMaxDiskSizeGb() int { - return 4000 -} - -func (self *SDBInstanceSku) GetMinDiskSizeGb() int { - return 40 -} - -func (self *SDBInstanceSku) GetVcpuCount() int { - return self.Vcpus -} - -func (self *SDBInstanceSku) GetVmemSizeMb() int { - return self.Ram * 1024 -} - -func (self *SDBInstanceSku) GetStorageType() string { - return self.StorageType -} - -func (sku *SDBInstanceSku) GetEngine() string { - return sku.Engine -} - -func (sku *SDBInstanceSku) GetEngineVersion() string { - return sku.EngineVersion -} - -func (self *SDBInstanceSku) GetStatus() string { - return api.DBINSTANCE_SKU_AVAILABLE -} - -func (sku *SDBInstanceSku) GetQPS() int { - return 0 -} - -type SDBInstanceFlavor struct { - Vcpus int - Ram int //单位GB - SpecCode string - InstanceMode string //实例模型 - - StorageType string - AzStatus map[string]string - Engine string - EngineVersion string -} - -func (self *SDBInstanceFlavor) GetISkus() []cloudprovider.ICloudDBInstanceSku { - ret := []cloudprovider.ICloudDBInstanceSku{} - switch self.InstanceMode { - case api.HUAWEI_DBINSTANCE_CATEGORY_HA: - for az1, status1 := range self.AzStatus { - if status1 != "normal" { - continue - } - for az2, status2 := range self.AzStatus { - if status2 != "normal" { - continue - } - sku := &SDBInstanceSku{ - Vcpus: self.Vcpus, - Ram: self.Ram, - SpecCode: self.SpecCode, - InstanceMode: self.InstanceMode, - StorageType: self.StorageType, - Az1: az1, - Az2: az2, - Engine: self.Engine, - EngineVersion: self.EngineVersion, - } - ret = append(ret, sku) - } - } - case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE: - for az, status := range self.AzStatus { - if status != "normal" { - continue - } - sku := &SDBInstanceSku{ - Vcpus: self.Vcpus, - Ram: self.Ram, - SpecCode: self.SpecCode, - InstanceMode: self.InstanceMode, - StorageType: self.StorageType, - Az1: az, - Engine: self.Engine, - EngineVersion: self.EngineVersion, - } - ret = append(ret, sku) - } - } - return ret -} - -func (self *SRegion) GetIDBInstanceSkus() ([]cloudprovider.ICloudDBInstanceSku, error) { - skus, err := self.GetDBInstanceSkus() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudDBInstanceSku{} - for i := range skus { - ret = append(ret, skus[i].GetISkus()...) - } - return ret, nil -} - -type SDBInstanceDatastore struct { - Id string - Name string -} - -func (self *SRegion) GetDBInstanceSkus() ([]SDBInstanceFlavor, error) { - skus := []SDBInstanceFlavor{} - for _, engine := range []string{api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL, api.DBINSTANCE_TYPE_SQLSERVER} { - stores, err := self.GetDBInstanceDatastores(engine) - if err != nil { - return nil, err - } - for _, version := range stores { - storages, err := self.GetDBInstanceStorages(engine, version.Name) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceStorages(%s,%s)", engine, version.Name) - } - flavors, err := self.GetDBInstanceFlavors(engine, version.Name) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceFlavors(%s, %s)", engine, version.Name) - } - for i := range flavors { - flavors[i].Engine = engine - flavors[i].EngineVersion = version.Name - for j := range storages { - flavors[i].StorageType = storages[j].Name - flavors[i].AzStatus = storages[j].AzStatus - skus = append(skus, flavors[i]) - } - } - } - } - return skus, nil -} - -// rds规格信息 -func (region *SRegion) GetDBInstanceFlavors(engine string, version string) ([]SDBInstanceFlavor, error) { - flavors := []SDBInstanceFlavor{} - query := url.Values{} - query.Add("version_name", version) - resource := fmt.Sprintf("%s/%s", "flavor", engine) - err := region.rdsList(resource, query, flavors) - if err != nil { - return nil, err - } - return flavors, nil -} - -// rds数据库引擎版本信息 -func (region *SRegion) GetDBInstanceDatastores(engine string) ([]SDBInstanceDatastore, error) { - stores := []SDBInstanceDatastore{} - resource := fmt.Sprintf("%s/%s", "datastores", engine) - err := region.rdsList(resource, nil, stores) - if err != nil { - return nil, err - } - return stores, nil -} - -type SDBInstanceStorage struct { - Name string - AzStatus map[string]string -} - -// rds数据库磁盘类型 -func (region *SRegion) GetDBInstanceStorages(engine, engineVersion string) ([]SDBInstanceStorage, error) { - storages := []SDBInstanceStorage{} - resource := fmt.Sprintf("%s/%s", "storage-type", engine) - query := url.Values{} - query.Add("version_name", engineVersion) - err := region.rdsList(resource, query, storages) - if err != nil { - return nil, err - } - return storages, nil -} diff --git a/pkg/multicloud/hcs/disk.go b/pkg/multicloud/hcs/disk.go deleted file mode 100644 index 784cf8d0ed..0000000000 --- a/pkg/multicloud/hcs/disk.go +++ /dev/null @@ -1,438 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -/* -华为云云硬盘 -======创建========== -1.磁盘只能挂载到同一可用区的云服务器内,创建后不支持更换可用区 -2.计费模式 包年包月/按需计费 -3.*支持自动备份 - - -共享盘 和 普通盘:https://support.huaweicloud.com/productdesc-evs/zh-cn_topic_0032860759.html -根据是否支持挂载至多台云服务器可以将云硬盘分为非共享云硬盘和共享云硬盘。 -一个非共享云硬盘只能挂载至一台云服务器,而一个共享云硬盘可以同时挂载至多台云服务器。 -单个共享云硬盘最多可同时挂载给16个云服务器。目前,共享云硬盘只适用于数据盘,不支持系统盘。 -*/ - -type Attachment struct { - ServerId string `json:"server_id"` - AttachmentId string `json:"attachment_id"` - AttachedAt string `json:"attached_at"` - HostName string `json:"host_name"` - VolumeId string `json:"volume_id"` - Device string `json:"device"` - Id string `json:"id"` -} - -type DiskMeta struct { - ResourceSpecCode string `json:"resourceSpecCode"` - Billing string `json:"billing"` - ResourceType string `json:"resourceType"` - AttachedMode string `json:"attached_mode"` - Readonly string `json:"readonly"` -} - -type VolumeImageMetadata struct { - QuickStart string `json:"__quick_start"` - ContainerFormat string `json:"container_format"` - MinRAM string `json:"min_ram"` - ImageName string `json:"image_name"` - ImageId string `json:"image_id"` - OSType string `json:"__os_type"` - OSFeatureList string `json:"__os_feature_list"` - MinDisk string `json:"min_disk"` - SupportKVM string `json:"__support_kvm"` - VirtualEnvType string `json:"virtual_env_type"` - SizeGB string `json:"size"` - OSVersion string `json:"__os_version"` - OSBit string `json:"__os_bit"` - SupportKVMHi1822Hiovs string `json:"__support_kvm_hi1822_hiovs"` - SupportXen string `json:"__support_xen"` - Description string `json:"__description"` - Imagetype string `json:"__imagetype"` - DiskFormat string `json:"disk_format"` - ImageSourceType string `json:"__image_source_type"` - Checksum string `json:"checksum"` - Isregistered string `json:"__isregistered"` - HwVifMultiqueueEnabled string `json:"hw_vif_multiqueue_enabled"` - Platform string `json:"__platform"` -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0124881427.html -type SDisk struct { - multicloud.SDisk - multicloud.HuaweiDiskTags - //details *SResourceDetail - - region *SRegion - - Id string `json:"id"` - Name string `json:"name"` - Status string `json:"status"` - Attachments []Attachment `json:"attachments"` - Description string `json:"description"` - SizeGB int `json:"size"` - Metadata DiskMeta `json:"metadata"` - Encrypted bool `json:"encrypted"` - Bootable string `json:"bootable"` - Multiattach bool `json:"multiattach"` - AvailabilityZone string `json:"availability_zone"` - SourceVolid string `json:"source_volid"` - SnapshotId string `json:"snapshot_id"` - CreatedAt time.Time `json:"created_at"` - VolumeType string `json:"volume_type"` - VolumeImageMetadata VolumeImageMetadata `json:"volume_image_metadata"` - ReplicationStatus string `json:"replication_status"` - UserId string `json:"user_id"` - ConsistencygroupId string `json:"consistencygroup_id"` - UpdatedAt string `json:"updated_at"` - EnterpriseProjectId string - - ExpiredTime time.Time -} - -func (self *SDisk) GetId() string { - return self.Id -} - -func (self *SDisk) GetName() string { - if len(self.Name) == 0 { - return self.Id - } - - return self.Name -} - -func (self *SDisk) GetGlobalId() string { - return self.Id -} - -func (self *SDisk) GetStatus() string { - // https://support.huaweicloud.com/api-evs/zh-cn_topic_0051803385.html - switch self.Status { - case "creating", "downloading": - return api.DISK_ALLOCATING - case "available", "in-use": - return api.DISK_READY - case "error": - return api.DISK_ALLOC_FAILED - case "attaching": - return api.DISK_ATTACHING - case "detaching": - return api.DISK_DETACHING - case "restoring-backup": - return api.DISK_REBUILD - case "backing-up": - return api.DISK_BACKUP_STARTALLOC // ? - case "error_restoring": - return api.DISK_BACKUP_ALLOC_FAILED - case "uploading": - return api.DISK_SAVING //? - case "extending": - return api.DISK_RESIZING - case "error_extending": - return api.DISK_ALLOC_FAILED // ? - case "deleting": - return api.DISK_DEALLOC //? - case "error_deleting": - return api.DISK_DEALLOC_FAILED // ? - case "rollbacking": - return api.DISK_REBUILD - case "error_rollbacking": - return api.DISK_UNKNOWN - default: - return api.DISK_UNKNOWN - } -} - -func (self *SDisk) Refresh() error { - ret, err := self.region.GetDisk(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, ret) -} - -func (self *SDisk) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SDisk) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return nil, cloudprovider.ErrNotImplemented - // return self.storage, nil -} - -func (self *SDisk) GetDiskFormat() string { - return "vhd" -} - -func (self *SDisk) GetDiskSizeMB() int { - return int(self.SizeGB * 1024) -} - -func (self *SDisk) GetIsAutoDelete() bool { - return false -} - -func (self *SDisk) GetTemplateId() string { - return self.VolumeImageMetadata.ImageId -} - -// Bootable 表示硬盘是否为启动盘。 -// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) -func (self *SDisk) GetDiskType() string { - if self.Bootable == "true" { - return api.DISK_TYPE_SYS - } - return api.DISK_TYPE_DATA -} - -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 { - if len(self.Attachments) > 0 { - return self.Attachments[0].Device - } - return "" -} - -func (self *SDisk) GetMountServerId() string { - if len(self.Attachments) > 0 { - return self.Attachments[0].ServerId - } - return "" -} - -func (self *SDisk) GetAccessPath() string { - return "" -} - -func (self *SDisk) Delete(ctx context.Context) error { - return self.region.DeleteDisk(self.Id) -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - snap, err := self.region.CreateSnapshot(self.Id, name, desc) - if err != nil { - return nil, err - } - return snap, nil -} - -func (self *SDisk) GetISnapshot(id string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := self.region.GetSnapshot(id) - if err != nil { - return nil, err - } - return snapshot, nil -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := self.region.GetSnapshots(self.Id, "") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudSnapshot{} - for i := 0; i < len(snapshots); i++ { - snapshots[i].region = self.region - ret = append(ret, &snapshots[i]) - } - return ret, nil -} - -func (self *SDisk) Resize(ctx context.Context, sizeMB int64) error { - return self.region.ResizeDisk(self.GetId(), sizeMB/1024) -} - -func (self *SDisk) Detach() error { - return self.region.DetachDisk(self.GetMountServerId(), self.GetId()) -} - -func (self *SDisk) Attach(device string) error { - return self.region.AttachDisk(self.GetMountServerId(), self.GetId(), device) -} - -// 在线卸载磁盘 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0036046828.html -// 对于挂载在系统盘盘位(也就是“/dev/sda”或“/dev/vda”挂载点)上的磁盘,当前仅支持离线卸载 -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - mountpoint := self.GetMountpoint() - if len(mountpoint) > 0 { - err := self.Detach() - if err != nil { - return "", err - } - } - - err := self.region.ResetDisk(self.Id, snapshotId) - if err != nil { - return self.Id, err - } - err = cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 300*time.Second) - if err != nil { - return "", err - } - if len(mountpoint) > 0 { - err := self.Attach(mountpoint) - if err != nil { - return "", err - } - } - return self.Id, nil -} - -// 华为云不支持重置 -func (self *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetDisk(id string) (*SDisk, error) { - ret := &SDisk{region: self} - res := fmt.Sprintf("volumes/%s", id) - return ret, self.evsGet(res, ret) -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762430.html -func (self *SRegion) GetDisks(zoneId string) ([]SDisk, error) { - params := url.Values{} - if len(zoneId) > 0 { - params.Set("availability_zone", zoneId) - } - disks := []SDisk{} - return disks, self.evsList("volumes/detail", params, &disks) -} - -func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, snapshotId string, desc string, projectId string) (*SDisk, error) { - volume := map[string]interface{}{ - "name": name, - "availability_zone": zoneId, - "description": desc, - "volume_type": category, - "size": sizeGb, - } - if len(snapshotId) > 0 { - volume["snapshot_id"] = snapshotId - } - if len(projectId) > 0 { - volume["enterprise_project_id"] = projectId - } - params := map[string]interface{}{ - "volume": volume, - } - ret := &SDisk{region: self} - return ret, self.evsCreate("volumes", params, ret) -} - -func (self *SRegion) DeleteDisk(id string) error { - res := fmt.Sprintf("volumes/%s", id) - return self.evsDelete(res) -} - -func (self *SRegion) ResizeDisk(id string, sizeGb int64) error { - params := map[string]interface{}{ - "os_extend": map[string]interface{}{ - "new_size": sizeGb, - }, - } - res := fmt.Sprintf("volumes/%s", id) - return self.evsPerform(res, "action", params) -} - -func (self *SRegion) ResetDisk(diskId, snapshotId string) error { - params := map[string]interface{}{ - "volume_id": diskId, - } - res := fmt.Sprintf("os-vendor-snapshots/%s", snapshotId) - return self.evsPerform(res, "rollback", params) -} - -func (self *SDisk) GetProjectId() string { - return self.EnterpriseProjectId -} - -func (self *SRegion) DetachDisk(instanceId string, diskId string) error { - res := fmt.Sprintf("servers/%s/os-volume_attachments/%s", instanceId, diskId) - return self.delete("ecs", "v2", res) -} - -func (self *SRegion) AttachDisk(instanceId string, diskId string, device string) error { - params := map[string]interface{}{ - "volumeAttachment": map[string]interface{}{ - "volumeId": instanceId, - "device": device, - }, - } - res := fmt.Sprintf("servers/%s/os-volume_attachments", instanceId) - return self.perform("ecs", "v2", res, "action", params, nil) -} - -type SDiskType struct { - ExtraSpecs ExtraSpecs `json:"extra_specs"` - Name string `json:"name"` - QosSpecsId string `json:"qos_specs_id"` - Id string `json:"id"` - IsPublic bool `json:"is_public"` -} - -func (self *SDiskType) IsAvaliableInZone(zoneId string) bool { - if strings.Contains(self.ExtraSpecs.HwAvailabilityZone, zoneId) { - return true - } - return false -} - -type ExtraSpecs struct { - VolumeBackendName string `json:"volume_backend_name"` - HwAvailabilityZone string `json:"HW:availability-zone"` -} - -func (self *SRegion) GetDiskTypes() ([]SDiskType, error) { - ret := []SDiskType{} - return ret, self.get("evs", "v3", "types", &ret) -} diff --git a/pkg/multicloud/hcs/doc.go b/pkg/multicloud/hcs/doc.go deleted file mode 100644 index d68c43049b..0000000000 --- a/pkg/multicloud/hcs/doc.go +++ /dev/null @@ -1 +0,0 @@ -package hcs // import "yunion.io/x/onecloud/pkg/multicloud/hcs" diff --git a/pkg/multicloud/hcs/eip.go b/pkg/multicloud/hcs/eip.go deleted file mode 100644 index 2200eb6350..0000000000 --- a/pkg/multicloud/hcs/eip.go +++ /dev/null @@ -1,434 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type TInternetChargeType string - -const ( - InternetChargeByTraffic = TInternetChargeType("traffic") - InternetChargeByBandwidth = TInternetChargeType("bandwidth") -) - -type Bandwidth struct { - Id string `json:"id"` - Name string `json:"name"` - Size int64 `json:"size"` - ShareType string `json:"share_type"` - PublicipInfo []PublicipInfo `json:"publicip_info"` - TenantId string `json:"tenant_id"` - BandwidthType string `json:"bandwidth_type"` - ChargeMode string `json:"charge_mode"` - BillingInfo string `json:"billing_info"` - EnterpriseProjectId string `json:"enterprise_project_id"` -} - -type PublicipInfo struct { - PublicipId string `json:"publicip_id"` - PublicipAddress string `json:"publicip_address"` - PublicipType string `json:"publicip_type"` - IPVersion int64 `json:"ip_version"` -} - -type SProfile struct { - UserId string `json:"user_id"` - ProductId string `json:"product_id"` - RegionId string `json:"region_id"` - OrderId string `json:"order_id"` -} - -type SEip struct { - multicloud.SEipBase - multicloud.HcsTags - - region *SRegion - port *Port - - Alias string - Id string `json:"id"` - Status string `json:"status"` - Profile *SProfile `json:"profile,omitempty"` - Type string `json:"type"` - PublicIPAddress string `json:"public_ip_address"` - PrivateIPAddress string `json:"private_ip_address"` - TenantId string `json:"tenant_id"` - CreateTime time.Time `json:"create_time"` - BandwidthId string `json:"bandwidth_id"` - BandwidthShareType string `json:"bandwidth_share_type"` - BandwidthSize int64 `json:"bandwidth_size"` - BandwidthName string `json:"bandwidth_name"` - EnterpriseProjectId string `json:"enterprise_project_id"` - IPVersion int64 `json:"ip_version"` - PortId string `json:"port_id"` -} - -func (self *SEip) GetId() string { - return self.Id -} - -func (self *SEip) GetName() string { - if len(self.Alias) > 0 { - return self.Alias - } - return self.PublicIPAddress -} - -func (self *SEip) GetGlobalId() string { - return self.Id -} - -func (self *SEip) GetStatus() string { - // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html - switch self.Status { - case "ACTIVE", "DOWN", "ELB": - return api.EIP_STATUS_READY - case "PENDING_CREATE", "NOTIFYING": - return api.EIP_STATUS_ALLOCATE - case "BINDING": - return api.EIP_STATUS_ALLOCATE - case "BIND_ERROR": - return api.EIP_STATUS_ALLOCATE_FAIL - case "PENDING_DELETE", "NOTIFY_DELETE": - return api.EIP_STATUS_DEALLOCATE - default: - return api.EIP_STATUS_UNKNOWN - } -} - -func (self *SEip) Refresh() error { - if self.IsEmulated() { - return nil - } - new, err := self.region.GetEip(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SEip) IsEmulated() bool { - return false -} - -func (self *SEip) GetIpAddr() string { - return self.PublicIPAddress -} - -func (self *SEip) GetMode() string { - return api.EIP_MODE_STANDALONE_EIP -} - -func (self *SEip) GetPort() *Port { - if len(self.PortId) == 0 { - return nil - } - - if self.port != nil { - return self.port - } - - port, err := self.region.GetPort(self.PortId) - if err != nil { - return nil - } - self.port = port - return self.port -} - -func (self *SEip) GetAssociationType() string { - if len(self.PortId) == 0 { - return "" - } - port, err := self.region.GetPort(self.PortId) - if err != nil { - log.Errorf("Get eip %s port %s error: %v", self.Id, self.PortId, err) - return "" - } - - if strings.HasPrefix(port.DeviceOwner, "compute") { - return api.EIP_ASSOCIATE_TYPE_SERVER - } - - switch port.DeviceOwner { - case "neutron:LOADBALANCER", "neutron:LOADBALANCERV2": - return api.EIP_ASSOCIATE_TYPE_LOADBALANCER - case "network:nat_gateway": - return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY - default: - return port.DeviceOwner - } -} - -func (self *SEip) GetAssociationExternalId() string { - // network/0273a359d61847fc83405926c958c746/ext-floatingips?tenantId=0273a359d61847fc83405926c958c746&limit=2000 - // 只能通过 port id 反查device id. - if len(self.PortId) > 0 { - port, _ := self.region.GetPort(self.PortId) - return port.DeviceId - } - return "" -} - -func (self *SEip) GetBandwidth() int { - return int(self.BandwidthSize) // Mb -} - -func (self *SEip) GetINetworkId() string { - return "" -} - -func (self *SEip) GetInternetChargeType() string { - // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090603.html - bandwidth, err := self.region.GetEipBandwidth(self.BandwidthId) - if err != nil { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - } - if bandwidth.ChargeMode == "traffic" { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - } - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH -} - -func (self *SEip) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SEip) GetCreatedAt() time.Time { - return self.CreateTime -} - -func (self *SEip) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SEip) Delete() error { - return self.region.DeallocateEIP(self.Id) -} - -func (self *SEip) Associate(conf *cloudprovider.AssociateConfig) error { - portId, err := self.region.GetInstancePortId(conf.InstanceId) - if err != nil { - return err - } - - if len(self.PortId) > 0 { - if self.PortId == portId { - return nil - } - - return fmt.Errorf("eip %s aready associate with port %s", self.GetId(), self.PortId) - } - - err = self.region.AssociateEipWithPortId(self.Id, portId) - if err != nil { - return err - } - - err = cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 10*time.Second, 10*time.Second, 180*time.Second) - return err -} - -func (self *SEip) Dissociate() error { - err := self.region.DissociateEip(self.Id) - if err != nil { - return err - } - return cloudprovider.WaitStatus(self, api.EIP_STATUS_READY, 10*time.Second, 180*time.Second) -} - -func (self *SEip) ChangeBandwidth(bw int) error { - return self.region.UpdateEipBandwidth(self.BandwidthId, bw) -} - -func (self *SRegion) GetInstancePortId(instanceId string) (string, error) { - // 目前只绑定一个网卡 - // todo: 还需要按照ports状态进行过滤 - ports, err := self.GetPorts(instanceId) - if err != nil { - return "", err - } - - if len(ports) == 0 { - return "", fmt.Errorf("AssociateEip instance %s port is empty", instanceId) - } - - return ports[0].Id, nil -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html -func (self *SRegion) AllocateEIP(name string, bwMbps int, chargeType TInternetChargeType, bgpType string, projectId string) (*SEip, error) { - params := map[string]interface{}{ - "bandwidth": map[string]interface{}{ - "name": name, - "size": bwMbps, - "share_type": "PER", - "charge_mode": chargeType, - }, - "publicip": map[string]interface{}{ - "type": bgpType, - "ip_version": 4, - "alias": name, - }, - } - if len(projectId) > 0 { - params["enterprise_project_id"] = projectId - } - eip := &SEip{region: self} - return eip, self.vpcCreate("publicips", params, eip) -} - -func (self *SRegion) GetEip(eipId string) (*SEip, error) { - eip := &SEip{region: self} - return eip, self.vpcGet("publicips/"+eipId, eip) -} - -func (self *SRegion) DeallocateEIP(eipId string) error { - return self.vpcDelete("publicips/" + eipId) -} - -func (self *SRegion) AssociateEip(eipId string, instanceId string) error { - portId, err := self.GetInstancePortId(instanceId) - if err != nil { - return err - } - return self.AssociateEipWithPortId(eipId, portId) -} - -func (self *SRegion) AssociateEipWithPortId(eipId string, portId string) error { - params := map[string]interface{}{ - "publicip": map[string]interface{}{ - "port_id": portId, - }, - } - return self.vpcUpdate("publicips/"+eipId, params) -} - -func (self *SRegion) DissociateEip(eipId string) error { - return self.AssociateEipWithPortId(eipId, "") -} - -func (self *SRegion) UpdateEipBandwidth(bandwidthId string, bw int) error { - params := map[string]interface{}{ - "bandwidth": map[string]interface{}{ - "size": bw, - }, - } - return self.vpcUpdate("bandwidths/"+bandwidthId, params) -} - -func (self *SRegion) GetEipBandwidth(id string) (*Bandwidth, error) { - ret := &Bandwidth{} - return ret, self.vpcGet("bandwidths/"+id, ret) -} - -func (self *SEip) GetProjectId() string { - return self.EnterpriseProjectId -} - -func (self *SRegion) GetEips(portId string, addrs []string) ([]SEip, error) { - query := url.Values{} - for _, addr := range addrs { - query.Add("public_ip_address", addr) - } - if len(portId) > 0 { - query.Set("port_id", portId) - } - eips := []SEip{} - return eips, self.vpcList("publicips", query, &eips) -} - -type SEipType struct { - Id string - Type string - Name string - Group string -} - -func (self *SRegion) GetEipTypes() ([]SEipType, error) { - query := url.Values{} - ret := []SEipType{} - return ret, self.vpcList("publicip_types", query, &ret) -} - -func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, err := self.GetEips("", nil) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudEIP{} - for i := 0; i < len(eips); i += 1 { - eips[i].region = self - ret = append(ret, &eips[i]) - } - return ret, nil -} - -func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { - eip, err := self.GetEip(id) - if err != nil { - return nil, err - } - return eip, nil -} - -func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - var ctype TInternetChargeType - switch eip.ChargeType { - case api.EIP_CHARGE_TYPE_BY_TRAFFIC: - ctype = InternetChargeByTraffic - case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: - ctype = InternetChargeByBandwidth - } - - // todo: 如何避免hardcode。集成到cloudmeta服务中? - if len(eip.BGPType) == 0 { - types, err := self.GetEipTypes() - if err != nil { - return nil, errors.Wrapf(err, "GetEipTypes") - } - if len(types) > 0 { - eip.BGPType = types[0].Type - } - } - - // 华为云EIP名字最大长度64 - if len(eip.Name) > 64 { - eip.Name = eip.Name[:64] - } - - ieip, err := self.AllocateEIP(eip.Name, eip.BandwidthMbps, ctype, eip.BGPType, eip.ProjectId) - ieip.region = self - if err != nil { - return nil, err - } - - err = cloudprovider.WaitStatus(ieip, api.EIP_STATUS_READY, 5*time.Second, 60*time.Second) - return ieip, err -} diff --git a/pkg/multicloud/hcs/host.go b/pkg/multicloud/hcs/host.go deleted file mode 100644 index a0d367bd9e..0000000000 --- a/pkg/multicloud/hcs/host.go +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone -} - -func (self *SHost) GetId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) GetName() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) -} - -func (self *SHost) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) IsEmulated() bool { - return true -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms, err := self.zone.region.GetInstances("") - if err != nil { - return nil, err - } - - ret := []cloudprovider.ICloudVM{} - for i := range vms { - if vms[i].OSEXTAZAvailabilityZone == self.zone.GetId() { - vms[i].host = self - ret = append(ret, &vms[i]) - } - } - return ret, nil -} - -func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.zone.region.GetInstance(id) - if err != nil { - return nil, err - } - vm.host = self - return vm, 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 api.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_HCS), "manufacture") - return info -} - -func (self *SHost) GetSN() string { - return "" -} - -func (self *SHost) GetCpuCount() int { - 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 api.DISK_TYPE_HYBRID -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_HCS -} - -func (self *SHost) GetIsMaintenance() bool { - return false -} - -func (self *SHost) GetVersion() string { - return HCS_API_VERSION -} - -func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - vm, err := self._createVM( - desc.Name, desc.ExternalImageId, desc.SysDisk, - desc.Cpu, desc.MemoryMB, desc.InstanceType, - desc.ExternalNetworkId, desc.IpAddr, - desc.Description, desc.Account, - desc.Password, desc.DataDisks, - desc.PublicKey, desc.ExternalSecgroupId, - desc.UserData, desc.BillingCycle, desc.ProjectId, desc.Tags) - if err != nil { - return nil, err - } - return vm, err -} - -func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, - networkId string, ipAddr string, desc string, account string, passwd string, - diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string, - userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (*SInstance, error) { - net, err := self.zone.region.GetNetwork(networkId) - if err != nil { - return nil, errors.Wrapf(err, "GetNetwork(%s)", networkId) - } - - keypair := "" - if len(publicKey) > 0 { - keypair, err = self.zone.region.syncKeypair(publicKey) - if err != nil { - return nil, err - } - } - - // 镜像及硬盘配置 - img, err := self.zone.region.GetImage(imgId) - if err != nil { - return nil, errors.Wrapf(err, "GetImage(%s)", imgId) - } - // passwd, windows机型直接使用密码比较方便 - if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(passwd) > 0 { - keypair = "" - } - - if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) { - if u, err := updateWindowsUserData(userData, img.OSVersion, account, passwd); err == nil { - userData = u - } else { - return nil, errors.Wrap(err, "SHost.CreateVM.updateWindowsUserData") - } - } - - if sysDisk.SizeGB > 0 && sysDisk.SizeGB < img.SizeGB { - sysDisk.SizeGB = img.SizeGB - } - - // 创建实例 - if len(instanceType) > 0 { - log.Debugf("Try instancetype : %s", instanceType) - vm, err := self.zone.region.CreateInstance(name, imgId, instanceType, networkId, secgroupId, - net.VpcId, self.zone.GetId(), desc, sysDisk, diskSizes, ipAddr, keypair, - passwd, userData, bc, projectId, tags) - if err != nil { - return nil, fmt.Errorf("create %s failed:%v", instanceType, err) - } - return vm, nil - } - - // 匹配实例类型 - instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, self.zone.GetId()) - if err != nil { - return nil, err - } - if len(instanceTypes) == 0 { - return nil, fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB) - } - - var vm *SInstance - for _, instType := range instanceTypes { - instanceTypeId := instType.Name - log.Debugf("Try instancetype : %s", instanceTypeId) - vm, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupId, - net.VpcId, self.zone.GetId(), desc, sysDisk, diskSizes, ipAddr, keypair, - passwd, userData, bc, projectId, tags) - if err != nil { - log.Errorf("Failed for %s: %s", instanceTypeId, err) - } else { - return vm, nil - } - } - - return nil, fmt.Errorf("create failed: %v", err) -} diff --git a/pkg/multicloud/hcs/image.go b/pkg/multicloud/hcs/image.go deleted file mode 100644 index ed8bdeff10..0000000000 --- a/pkg/multicloud/hcs/image.go +++ /dev/null @@ -1,466 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/apis" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type TImageOwnerType string - -const ( - ImageOwnerPublic TImageOwnerType = "gold" // 公共镜像:gold - ImageOwnerSelf TImageOwnerType = "private" // 私有镜像:private - ImageOwnerShared TImageOwnerType = "shared" // 共享镜像:shared - - EnvFusionCompute = "FusionCompute" - EnvIronic = "Ironic" -) - -const ( - ImageStatusQueued = "queued" // queued:表示镜像元数据已经创建成功,等待上传镜像文件。 - ImageStatusSaving = "saving" // saving:表示镜像正在上传文件到后端存储。 - ImageStatusDeleted = "deleted" // deleted:表示镜像已经删除。 - ImageStatusKilled = "killed" // killed:表示镜像上传错误。 - ImageStatusActive = "active" // active:表示镜像可以正常使用 -) - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091565.html -type SImage struct { - multicloud.SImageBase - multicloud.HuaweiTags - cache *SStoragecache - - // normalized image info - imgInfo *imagetools.ImageInfo - - Schema string `json:"schema"` - MinDiskGB int64 `json:"min_disk"` - CreatedAt time.Time `json:"created_at"` - ImageSourceType string `json:"__image_source_type"` - ContainerFormat string `json:"container_format"` - File string `json:"file"` - UpdatedAt time.Time `json:"updated_at"` - Protected bool `json:"protected"` - Checksum string `json:"checksum"` - Id string `json:"id"` - Isregistered string `json:"__isregistered"` - MinRamMB int `json:"min_ram"` - Lazyloading string `json:"__lazyloading"` - Owner string `json:"owner"` - OSType string `json:"__os_type"` - Imagetype string `json:"__imagetype"` - Visibility string `json:"visibility"` - VirtualEnvType string `json:"virtual_env_type"` - Platform string `json:"__platform"` - SizeGB int `json:"size"` - ImageSize int64 `json:"__image_size"` - OSBit string `json:"__os_bit"` - OSVersion string `json:"__os_version"` - Architecture string - Name string `json:"name"` - Self string `json:"self"` - DiskFormat string `json:"disk_format"` - Status string `json:"status"` - SupportKVMFPGAType string `json:"__support_kvm_fpga_type"` - SupportKVMNVMEHIGHIO string `json:"__support_nvme_highio"` - SupportLargeMemory string `json:"__support_largememory"` - SupportDiskIntensive string `json:"__support_diskintensive"` - SupportHighPerformance string `json:"__support_highperformance"` - SupportXENGPUType string `json:"__support_xen_gpu_type"` - SupportKVMGPUType string `json:"__support_kvm_gpu_type"` - SupportGPUT4 string `json:"__support_gpu_t4"` - SupportKVMAscend310 string `json:"__support_kvm_ascend_310"` - SupportArm string `json:"__support_arm"` -} - -func (self *SImage) GetMinRamSizeMb() int { - return self.MinRamMB -} - -func (self *SImage) GetId() string { - return self.Id -} - -func (self *SImage) GetName() string { - return self.Name -} - -func (self *SImage) GetGlobalId() string { - return self.Id -} - -func (self *SImage) GetStatus() string { - switch self.Status { - case ImageStatusQueued: - return api.CACHED_IMAGE_STATUS_CACHING - case ImageStatusActive: - return api.CACHED_IMAGE_STATUS_ACTIVE - case ImageStatusKilled: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - default: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (self *SImage) GetImageStatus() string { - switch self.Status { - case ImageStatusQueued: - return cloudprovider.IMAGE_STATUS_QUEUED - case ImageStatusActive: - return cloudprovider.IMAGE_STATUS_ACTIVE - case ImageStatusKilled: - return cloudprovider.IMAGE_STATUS_KILLED - default: - return cloudprovider.IMAGE_STATUS_KILLED - } -} - -func (self *SImage) Refresh() error { - ret, err := self.cache.region.GetImage(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, ret) -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - switch self.Imagetype { - case "gold": - return cloudprovider.ImageTypeSystem - case "private": - return cloudprovider.ImageTypeCustomized - case "shared": - return cloudprovider.ImageTypeShared - default: - return cloudprovider.ImageTypeCustomized - } -} - -func (self *SImage) GetSizeByte() int64 { - return int64(self.MinDiskGB) * 1024 * 1024 * 1024 -} - -func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if self.imgInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(self.ImageSourceType, self.Architecture, self.OSType, self.Platform, "") - self.imgInfo = &imgInfo - } - - return self.imgInfo -} - -func (self *SImage) GetFullOsName() string { - return self.ImageSourceType -} - -func (self *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) -} - -func (self *SImage) GetOsDist() string { - return self.getNormalizedImageInfo().OsDistro -} - -func (self *SImage) GetOsVersion() string { - return self.getNormalizedImageInfo().OsVersion -} - -func (self *SImage) GetOsLang() string { - return self.getNormalizedImageInfo().OsLang -} - -func (self *SImage) GetOsArch() string { - return self.getNormalizedImageInfo().OsArch -} - -func (self *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return int(self.MinDiskGB) -} - -func (self *SImage) GetImageFormat() string { - return self.DiskFormat -} - -func (self *SImage) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SImage) IsEmulated() bool { - return false -} - -func (self *SImage) Delete(ctx context.Context) error { - return self.cache.region.DeleteImage(self.GetId()) -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.cache -} - -func (self *SRegion) GetImage(imageId string) (*SImage, error) { - image := &SImage{cache: self.getStoragecache()} - res := fmt.Sprintf("images/%s", imageId) - return image, self.imsGet(res, image) -} - -func excludeImage(image SImage) bool { - if image.VirtualEnvType == "Ironic" { - return true - } - - if len(image.SupportDiskIntensive) > 0 { - return true - } - - if len(image.SupportKVMFPGAType) > 0 || len(image.SupportKVMAscend310) > 0 { - return true - } - - if len(image.SupportKVMGPUType) > 0 { - return true - } - - if len(image.SupportKVMNVMEHIGHIO) > 0 { - return true - } - - if len(image.SupportGPUT4) > 0 { - return true - } - - if len(image.SupportXENGPUType) > 0 { - return true - } - - if len(image.SupportHighPerformance) > 0 { - return true - } - - if len(image.SupportArm) > 0 { - return true - } - - return false -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0060804959.html -func (self *SRegion) GetImages(status string, imagetype TImageOwnerType, name string, envType string) ([]SImage, error) { - params := url.Values{} - if len(status) > 0 { - params.Set("status", status) - } - - if len(imagetype) > 0 { - params.Set("__imagetype", string(imagetype)) - if imagetype == ImageOwnerPublic { - params.Set("protected", "True") - } - } - if len(envType) > 0 { - params.Set("virtual_env_type", envType) - } - - if len(name) > 0 { - params.Set("name", name) - } - - images := []SImage{} - err := self.imsList("images", params, &images) - if err != nil { - return nil, err - } - - // 排除掉需要特定镜像才能创建的实例类型 - // https://support.huaweicloud.com/eu-west-0-api-ims/zh-cn_topic_0031617666.html#ZH-CN_TOPIC_0031617666__table48545918250 - // https://support.huaweicloud.com/productdesc-ecs/zh-cn_topic_0088142947.html - filtedImages := make([]SImage, 0) - for i := range images { - if !excludeImage(images[i]) { - filtedImages = append(filtedImages, images[i]) - } - } - return filtedImages, err -} - -func (self *SRegion) DeleteImage(imageId string) error { - res := fmt.Sprintf("images/%s", imageId) - return self.imsDelete(res) -} - -func (self *SRegion) GetImageByName(name string) (*SImage, error) { - if len(name) == 0 { - return nil, fmt.Errorf("image name should not be empty") - } - images, err := self.GetImages("", TImageOwnerType(""), name, "") - if err != nil { - return nil, err - } - if len(images) == 0 { - return nil, cloudprovider.ErrNotFound - } - log.Debugf("%d image found match name %s", len(images), name) - return &images[0], nil -} - -/* https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html - os version 取值范围: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html - 用于创建私有镜像的源云服务器系统盘大小大于等于40GB且不超过1024GB。 - 目前支持vhd,zvhd、raw,qcow2 - todo: 考虑使用镜像快速导入。 https://support.huaweicloud.com/api-ims/zh-cn_topic_0133188204.html - 使用OBS文件创建镜像 - - * openstack原生接口支持的格式:https://support.huaweicloud.com/api-ims/zh-cn_topic_0031615566.html -*/ -func (self *SRegion) ImportImageJob(name string, osDist string, osVersion string, osArch string, bucket string, key string, minDiskGB int64) error { - os_version, err := stdVersion(osDist, osVersion, osArch) - log.Debugf("%s %s %s: %s.min_disk %d GB", osDist, osVersion, osArch, os_version, minDiskGB) - if err != nil { - log.Debugln(err) - } - - image_url := fmt.Sprintf("%s:%s", bucket, key) - params := map[string]interface{}{ - "name": name, - "image_url": image_url, - "os_version": os_version, - "is_config_init": true, - "is_config": true, - "min_disk": minDiskGB, - } - return self.imsPerform("cloudimage", "action", params, nil) -} - -func formatVersion(osDist string, osVersion string) (string, error) { - err := fmt.Errorf("unsupport version %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osVersion) - dist := strings.ToLower(osDist) - if dist == "ubuntu" || dist == "redhat" || dist == "centos" || dist == "oracle" || dist == "euleros" { - parts := strings.Split(osVersion, ".") - if len(parts) < 2 { - return "", err - } - - return parts[0] + "." + parts[1], nil - } - - if dist == "debian" { - parts := strings.Split(osVersion, ".") - if len(parts) < 3 { - return "", err - } - - return parts[0] + "." + parts[1] + "." + parts[2], nil - } - - if dist == "fedora" || dist == "windows" || dist == "suse" { - parts := strings.Split(osVersion, ".") - if len(parts) < 1 { - return "", err - } - - return parts[0], nil - } - - if dist == "opensuse" { - parts := strings.Split(osVersion, ".") - if len(parts) == 0 { - return "", err - } - - if len(parts) == 1 { - return parts[0], nil - } - - if len(parts) >= 2 { - return parts[0] + "." + parts[1], nil - } - } - - return "", err -} - -// todo: 如何保持同步更新 -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html -func stdVersion(osDist string, osVersion string, osArch string) (string, error) { - // 架构 - arch := "" - switch osArch { - case "64", apis.OS_ARCH_X86_64: - arch = "64bit" - case "32", apis.OS_ARCH_X86_32: - arch = "32bit" - default: - return "", fmt.Errorf("unsupported arch %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osArch) - } - - _dist := strings.Split(strings.TrimSpace(osDist), " ")[0] - _dist = strings.ToLower(_dist) - // 版本 - ver, err := formatVersion(_dist, osVersion) - if err != nil { - return "", err - } - - // 操作系统 - dist := "" - - switch _dist { - case "ubuntu": - return fmt.Sprintf("Ubuntu %s server %s", ver, arch), nil - case "redhat": - dist = "Redhat Linux Enterprise" - case "centos": - dist = "CentOS" - case "fedora": - dist = "Fedora" - case "debian": - dist = "Debian GNU/Linux" - case "windows": - dist = "Windows Server" - case "oracle": - dist = "Oracle Linux Server release" - case "suse": - dist = "SUSE Linux Enterprise Server" - case "opensuse": - dist = "OpenSUSE" - case "euleros": - dist = "EulerOS" - default: - return "", fmt.Errorf("unsupported os %s. reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", dist) - } - - return fmt.Sprintf("%s %s %s", dist, ver, arch), nil -} - -func (self *SImage) UEFI() bool { - return false -} diff --git a/pkg/multicloud/hcs/instance.go b/pkg/multicloud/hcs/instance.go deleted file mode 100644 index 1f0951c732..0000000000 --- a/pkg/multicloud/hcs/instance.go +++ /dev/null @@ -1,1114 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - "encoding/base64" - "fmt" - "net/url" - "sort" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/apis" - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/cloudinit" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -const ( - InstanceStatusRunning = "ACTIVE" - InstanceStatusTerminated = "DELETED" - InstanceStatusStopped = "SHUTOFF" -) - -type IpAddress struct { - Version string `json:"version"` - Addr string `json:"addr"` - OSEXTIPSMACMACAddr string `json:"OS-EXT-IPS-MAC:mac_addr"` - OSEXTIPSPortId string `json:"OS-EXT-IPS:port_id"` - OSEXTIPSType string `json:"OS-EXT-IPS:type"` -} - -type Flavor struct { - Disk string `json:"disk"` - Vcpus string `json:"vcpus"` - RAM string `json:"ram"` - Id string `json:"id"` - Name string `json:"name"` -} - -type Image struct { - Id string `json:"id"` -} - -type VMMetadata struct { - MeteringImageId string `json:"metering.image_id"` - MeteringImagetype string `json:"metering.imagetype"` - MeteringOrderId string `json:"metering.order_id"` - MeteringResourcespeccode string `json:"metering.resourcespeccode"` - ImageName string `json:"image_name"` - OSBit string `json:"os_bit"` - VpcId string `json:"vpc_id"` - MeteringResourcetype string `json:"metering.resourcetype"` - CascadedInstanceExtrainfo string `json:"cascaded.instance_extrainfo"` - OSType string `json:"os_type"` - ChargingMode string `json:"charging_mode"` -} - -type OSExtendedVolumesVolumesAttached struct { - Device string `json:"device"` - BootIndex string `json:"bootIndex"` - Id string `json:"id"` - DeleteOnTermination string `json:"delete_on_termination"` -} - -type OSSchedulerHints struct { -} - -type SecurityGroup struct { - Name string `json:"name"` -} - -type SysTag struct { - Key string `json:"key"` - Value string `json:"value"` -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html -// https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0100166287.html v1.1 支持创建包年/包月的弹性云服务器 -type SInstance struct { - multicloud.SInstanceBase - multicloud.HuaweiTags - - host *SHost - - osInfo *imagetools.ImageInfo - - Id string `json:"id"` - Name string `json:"name"` - Addresses map[string][]IpAddress `json:"addresses"` - Flavor Flavor `json:"flavor"` - AccessIPv4 string `json:"accessIPv4"` - AccessIPv6 string `json:"accessIPv6"` - Status string `json:"status"` - Progress string `json:"progress"` - HostId string `json:"hostId"` - Image Image `json:"image"` - Updated string `json:"updated"` - Created time.Time `json:"created"` - Metadata VMMetadata `json:"metadata"` - Description string `json:"description"` - Locked bool `json:"locked"` - ConfigDrive string `json:"config_drive"` - TenantId string `json:"tenant_id"` - UserId string `json:"user_id"` - KeyName string `json:"key_name"` - - OSExtendedVolumesVolumesAttached []OSExtendedVolumesVolumesAttached `json:"os-extended-volumes:volumes_attached"` - OSEXTSTSTaskState string `json:"OS-EXT-STS:task_state"` - OSEXTSTSPowerState int64 `json:"OS-EXT-STS:power_state"` - OSEXTSTSVMState string `json:"OS-EXT-STS:vm_state"` - OSEXTSRVATTRHost string `json:"OS-EXT-SRV-ATTR:host"` - OSEXTSRVATTRInstanceName string `json:"OS-EXT-SRV-ATTR:instance_name"` - OSEXTSRVATTRHypervisorHostname string `json:"OS-EXT-SRV-ATTR:hypervisor_hostname"` - OSDCFDiskConfig string `json:"OS-DCF:diskConfig"` - OSEXTAZAvailabilityZone string `json:"OS-EXT-AZ:availability_zone"` - OSSchedulerHints OSSchedulerHints `json:"os:scheduler_hints"` - OSEXTSRVATTRRootDeviceName string `json:"OS-EXT-SRV-ATTR:root_device_name"` - OSEXTSRVATTRRamdiskId string `json:"OS-EXT-SRV-ATTR:ramdisk_id"` - EnterpriseProjectId string `json:"enterprise_project_id"` - OSEXTSRVATTRUserData string `json:"OS-EXT-SRV-ATTR:user_data"` - OSSRVUSGLaunchedAt time.Time `json:"OS-SRV-USG:launched_at"` - OSEXTSRVATTRKernelId string `json:"OS-EXT-SRV-ATTR:kernel_id"` - OSEXTSRVATTRLaunchIndex int64 `json:"OS-EXT-SRV-ATTR:launch_index"` - HostStatus string `json:"host_status"` - OSEXTSRVATTRReservationId string `json:"OS-EXT-SRV-ATTR:reservation_id"` - OSEXTSRVATTRHostname string `json:"OS-EXT-SRV-ATTR:hostname"` - OSSRVUSGTerminatedAt time.Time `json:"OS-SRV-USG:terminated_at"` - SysTags []SysTag `json:"sys_tags"` - SecurityGroups []SecurityGroup `json:"security_groups"` -} - -func compareSet(currentSet []string, newSet []string) (add []string, remove []string, keep []string) { - sort.Strings(currentSet) - sort.Strings(newSet) - - i, j := 0, 0 - for i < len(currentSet) || j < len(newSet) { - if i < len(currentSet) && j < len(newSet) { - if currentSet[i] == newSet[j] { - keep = append(keep, currentSet[i]) - i += 1 - j += 1 - } else if currentSet[i] < newSet[j] { - remove = append(remove, currentSet[i]) - i += 1 - } else { - add = append(add, newSet[j]) - j += 1 - } - } else if i >= len(currentSet) { - add = append(add, newSet[j]) - j += 1 - } else if j >= len(newSet) { - remove = append(remove, currentSet[i]) - i += 1 - } - } - - return add, remove, keep -} - -// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) -func isBootDisk(server *SInstance, disk *SDisk) bool { - if disk.GetDiskType() != api.DISK_TYPE_SYS { - return false - } - - for _, attachment := range disk.Attachments { - if attachment.ServerId == server.GetId() && attachment.Device == server.OSEXTSRVATTRRootDeviceName { - return true - } - } - - return false -} - -func (self *SInstance) GetId() string { - return self.Id -} - -func (self *SInstance) GetHostname() string { - return self.OSEXTSRVATTRHostname -} - -func (self *SInstance) GetName() string { - return self.Name -} - -func (self *SInstance) GetGlobalId() string { - return self.Id -} - -func (self *SInstance) GetStatus() string { - switch self.Status { - case "ACTIVE": - return api.VM_RUNNING - case "MIGRATING", "REBUILD", "BUILD", "RESIZE", "VERIFY_RESIZE": // todo: pending ? - return api.VM_STARTING - case "REBOOT", "HARD_REBOOT": - return api.VM_STOPPING - case "SHUTOFF": - return api.VM_READY - default: - return api.VM_UNKNOWN - } -} - -func (self *SInstance) Refresh() error { - ret, err := self.host.zone.region.GetInstance(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, ret) -} - -func (self *SInstance) GetInstanceType() string { - return self.Flavor.Id -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - secgroups, err := self.host.zone.region.GetInstanceSecrityGroups(self.Id) - if err != nil { - return nil, err - } - ret := []string{} - for i := range secgroups { - ret = append(ret, secgroups[i].Id) - } - return ret, nil -} - -// https://support.huaweicloud.com/api-ecs/ecs_02_1002.html -// key 相同时value不会替换 -func (self *SRegion) CreateServerTags(instanceId string, tags map[string]string) error { - params := map[string]interface{}{ - "action": "create", - } - - tagsObj := []map[string]string{} - for k, v := range tags { - tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) - } - params["tags"] = tagsObj - - res := fmt.Sprintf("cloudservers/%s", instanceId) - return self.perform("ecs", "v1", res, "tags/action", params, nil) -} - -// https://support.huaweicloud.com/api-ecs/ecs_02_1003.html -func (self *SRegion) DeleteServerTags(instanceId string, tagsKey []string) error { - params := map[string]interface{}{ - "action": "delete", - } - tagsObj := []map[string]string{} - for _, k := range tagsKey { - tagsObj = append(tagsObj, map[string]string{"key": k}) - } - params["tags"] = tagsObj - res := fmt.Sprintf("cloudservers/%s", instanceId) - return self.perform("ecs", "v1", res, "tags/action", params, nil) -} - -func (self *SInstance) SetTags(tags map[string]string, replace bool) error { - existedTags, err := self.GetTags() - if err != nil { - return errors.Wrap(err, "self.GetTags()") - } - deleteTagsKey := []string{} - for k := range existedTags { - if replace { - deleteTagsKey = append(deleteTagsKey, k) - } else { - if _, ok := tags[k]; ok { - deleteTagsKey = append(deleteTagsKey, k) - } - } - } - if len(deleteTagsKey) > 0 { - err := self.host.zone.region.DeleteServerTags(self.GetId(), deleteTagsKey) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.DeleteServerTags(%s,%s)", self.GetId(), deleteTagsKey) - } - } - if len(tags) > 0 { - err := self.host.zone.region.CreateServerTags(self.GetId(), tags) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.CreateServerTags(%s,%s)", self.GetId(), jsonutils.Marshal(tags).String()) - } - } - return nil -} - -func (self *SInstance) GetBillingType() string { - // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html - // charging_mode “0”:按需计费 “1”:按包年包月计费 - if self.Metadata.ChargingMode == "1" { - return billing_api.BILLING_TYPE_PREPAID - } - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SInstance) GetCreatedAt() time.Time { - return self.Created -} - -// charging_mode “0”:按需计费 “1”:按包年包月计费 -func (self *SInstance) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - attached := self.OSExtendedVolumesVolumesAttached - disks := make([]SDisk, 0) - for _, vol := range attached { - disk, err := self.host.zone.region.GetDisk(vol.Id) - if err != nil { - return nil, err - } - - disks = append(disks, *disk) - } - - ret := []cloudprovider.ICloudDisk{} - for i := 0; i < len(disks); i += 1 { - disks[i].region = self.host.zone.region - if isBootDisk(self, &disks[i]) { - ret = append([]cloudprovider.ICloudDisk{&disks[i]}, ret...) - } else { - ret = append(ret, &disks[i]) - } - } - return ret, nil -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nics := make([]cloudprovider.ICloudNic, 0) - for _, ipAddresses := range self.Addresses { - for _, ipAddress := range ipAddresses { - if ipAddress.OSEXTIPSType == "fixed" { - nic := SInstanceNic{ - instance: self, - ipAddr: ipAddress.Addr, - macAddr: ipAddress.OSEXTIPSMACMACAddr, - } - nics = append(nics, &nic) - } - } - } - return nics, nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - ips := make([]string, 0) - for _, addresses := range self.Addresses { - for _, address := range addresses { - if address.OSEXTIPSType != "fixed" && !strings.HasPrefix(address.Addr, "100.") { - ips = append(ips, address.Addr) - } - } - } - - if len(ips) == 0 { - return nil, nil - } - - eips, err := self.host.zone.region.GetEips("", ips) - if err != nil { - return nil, err - } - if len(eips) > 0 { - eips[0].region = self.host.zone.region - return &eips[0], nil - } - return nil, nil -} - -func (self *SInstance) GetVcpuCount() int { - cpu, _ := strconv.Atoi(self.Flavor.Vcpus) - return cpu -} - -func (self *SInstance) GetVmemSizeMB() int { - mem, _ := strconv.Atoi(self.Flavor.RAM) - return int(mem) -} - -func (self *SInstance) GetBootOrder() string { - return "dcn" -} - -func (self *SInstance) GetVga() string { - return "std" -} - -func (self *SInstance) GetVdi() string { - return "vnc" -} - -func (self *SInstance) GetOSArch() string { - if len(self.Image.Id) > 0 { - image, err := self.host.zone.region.GetImage(self.Image.Id) - if err == nil { - return image.GetOsArch() - } - - log.Debugf("GetOSArch.GetImage %s: %s", self.Image.Id, err) - } - - t := self.GetInstanceType() - if len(t) > 0 { - if strings.HasPrefix(t, "k") { - return apis.OS_ARCH_AARCH64 - } - } - - return apis.OS_ARCH_X86 -} - -func (self *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(osprofile.NormalizeOSType(self.Metadata.OSType)) -} - -func (self *SInstance) GetOSName() string { - return self.Metadata.ImageName -} - -func (i *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { - if i.osInfo == nil { - osInfo := imagetools.NormalizeImageInfo(i.Metadata.ImageName, "", i.Metadata.OSType, "", "") - i.osInfo = &osInfo - } - return i.osInfo -} - -func (self *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.BIOS -} - -func (i *SInstance) GetOsDist() string { - return i.getNormalizedOsInfo().OsDistro -} - -func (i *SInstance) GetOsVersion() string { - return i.getNormalizedOsInfo().OsVersion -} - -func (i *SInstance) GetOsLang() string { - return i.getNormalizedOsInfo().OsLang -} - -func (self *SInstance) GetFullOsName() string { - return self.Metadata.ImageName -} - -func (self *SInstance) GetMachine() string { - return "pc" -} - -func (self *SInstance) GetOsArch() string { - if flavor, err := self.host.zone.region.GetICloudSku(self.Flavor.Id); err == nil { - return flavor.GetCpuArch() - } else { - log.Debugf("GetOSArch.GetICloudSku %s: %s", self.Flavor.Id, err) - } - - t := self.GetInstanceType() - if len(t) > 0 { - if strings.HasPrefix(t, "k") { - return apis.OS_ARCH_AARCH64 - } - } - - return apis.OS_ARCH_X86 -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - return self.SetSecurityGroups([]string{secgroupId}) -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - currentSecgroups, err := self.GetSecurityGroupIds() - if err != nil { - return err - } - - add, remove, _ := compareSet(currentSecgroups, secgroupIds) - err = self.host.zone.region.AssignSecurityGroups(add, self.GetId()) - if err != nil { - return err - } - return self.host.zone.region.UnassignSecurityGroups(remove, self.GetId()) -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_HCS -} - -func (self *SInstance) StartVM(ctx context.Context) error { - if self.Status == InstanceStatusRunning { - return nil - } - - 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 - } - - if self.GetStatus() == api.VM_RUNNING { - return nil - } else if self.GetStatus() == api.VM_READY { - err := self.host.zone.region.StartVM(self.GetId()) - if err != nil { - return err - } - } - time.Sleep(interval) - } - return cloudprovider.ErrTimeout -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - if self.Status == InstanceStatusStopped { - return nil - } - - if self.Status == InstanceStatusTerminated { - log.Debugf("Instance already terminated.") - return nil - } - - err := self.host.zone.region.StopVM(self.GetId(), opts.IsForce) - if err != nil { - return err - } - return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - return self.host.zone.region.DeleteVM(self.GetId()) -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return self.host.zone.region.UpdateVM(self.GetId(), name) -} - -// https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0032380449.html -// 创建云服务器过程中注入用户数据。支持注入文本、文本文件或gzip文件。 -// 注入内容,需要进行base64格式编码。注入内容(编码之前的内容)最大长度32KB。 -// 对于Linux弹性云服务器,adminPass参数传入时,user_data参数不生效。 -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html 使用原镜像重装 -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html 更换系统盘操作系统 -// 不支持调整系统盘大小 -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - publicKeyName := "" - var err error - if len(desc.PublicKey) > 0 { - publicKeyName, err = self.host.zone.region.syncKeypair(desc.PublicKey) - if err != nil { - return "", err - } - } - - image, err := self.host.zone.region.GetImage(desc.ImageId) - if err != nil { - return "", errors.Wrap(err, "SInstance.RebuildRoot.GetImage") - } - - // Password存在的情况下,windows 系统直接使用密码 - if strings.ToLower(image.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(desc.Password) > 0 { - publicKeyName = "" - } - - userData, err := updateUserData(self.OSEXTSRVATTRUserData, image.OSVersion, desc.Account, desc.Password, desc.PublicKey) - if err != nil { - return "", errors.Wrap(err, "SInstance.RebuildRoot.updateUserData") - } - - if self.Metadata.MeteringImageId == desc.ImageId { - err = self.host.zone.region.RebuildRoot(ctx, self.UserId, self.GetId(), desc.Password, publicKeyName, userData) - if err != nil { - return "", err - } - } else { - err = self.host.zone.region.ChangeRoot(ctx, self.UserId, self.GetId(), desc.ImageId, desc.Password, publicKeyName, userData) - if err != nil { - return "", err - } - } - - idisks, err := self.GetIDisks() - if err != nil { - return "", err - } - - if len(idisks) == 0 { - return "", fmt.Errorf("server %s has no volume attached.", self.GetId()) - } - - return idisks[0].GetId(), nil -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return self.host.zone.region.DeployVM(self.GetId(), name, password, publicKey, deleteKeypair, description) -} - -func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - instanceTypes := []string{} - if len(config.InstanceType) > 0 { - instanceTypes = []string{config.InstanceType} - } else { - flavors, err := self.host.zone.region.GetMatchInstanceTypes(config.Cpu, config.MemoryMB, self.OSEXTAZAvailabilityZone) - if err != nil { - return errors.Wrapf(err, "GetMatchInstanceTypes") - } - for _, flavor := range flavors { - instanceTypes = append(instanceTypes, flavor.Id) - } - } - var err error - for _, instanceType := range instanceTypes { - err = self.host.zone.region.ChangeVMConfig(self.GetId(), instanceType) - if err != nil { - log.Warningf("ChangeVMConfig %s for %s error: %v", self.GetId(), instanceType, err) - } else { - return cloudprovider.WaitStatusWithDelay(self, api.VM_READY, 15*time.Second, 15*time.Second, 180*time.Second) - } - } - if err != nil { - return errors.Wrapf(err, "ChangeVMConfig") - } - return fmt.Errorf("Failed to change vm config, specification not supported") -} - -// todo:// 返回jsonobject感觉很诡异。不能直接知道内部细节 -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - return self.host.zone.region.GetInstanceVNCUrl(self.GetId()) -} - -func (self *SInstance) NextDeviceName() (string, error) { - prefix := "s" - if strings.Contains(self.OSEXTSRVATTRRootDeviceName, "/vd") { - prefix = "v" - } - - currents := []string{} - for _, item := range self.OSExtendedVolumesVolumesAttached { - currents = append(currents, strings.ToLower(item.Device)) - } - - for i := 0; i < 25; i++ { - device := fmt.Sprintf("/dev/%sd%s", prefix, string([]byte{byte(98 + i)})) - if ok, _ := utils.InStringArray(device, currents); !ok { - return device, nil - } - } - - return "", fmt.Errorf("disk devicename out of index, current deivces: %s", currents) -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - device, err := self.NextDeviceName() - if err != nil { - return errors.Wrap(err, "Instance.AttachDisk.NextDeviceName") - } - - err = self.host.zone.region.AttachDisk(self.GetId(), diskId, device) - if err != nil { - return errors.Wrap(err, "Instance.AttachDisk.AttachDisk") - } - - return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { - disk, err := self.host.zone.region.GetDisk(diskId) - if err != nil { - log.Debugf("Instance.AttachDisk.GetDisk %s", err) - return false, nil - } - - if disk.Status == "in-use" { - return true, nil - } - - return false, nil - }) -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - err := self.host.zone.region.DetachDisk(self.GetId(), diskId) - if err != nil { - return errors.Wrap(err, "Instance.DetachDisk") - } - - return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { - disk, err := self.host.zone.region.GetDisk(diskId) - if err != nil { - log.Debugf("Instance.DetachDisk.GetDisk %s", err) - return false, nil - } - - if disk.Status == "available" { - return true, nil - } - - return false, nil - }) -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148850.html -func (self *SRegion) GetInstances(ip string) ([]SInstance, error) { - params := url.Values{} - if len(ip) > 0 { - params.Set("ip", ip) - } - params.Set("offset", "1") - ret := []SInstance{} - return ret, self.list("ecs", "v1", "cloudservers/detail", params, &ret) -} - -func (self *SRegion) GetInstance(id string) (*SInstance, error) { - ret := &SInstance{} - res := fmt.Sprintf("cloudservers/%s", id) - return ret, self.get("ecs", "v1", res, ret) -} -func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, subnetId string, - securityGroupId string, vpcId string, zoneId string, desc string, sysDisk cloudprovider.SDiskInfo, dataDisks []cloudprovider.SDiskInfo, ipAddr string, - keypair string, passwd string, userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (*SInstance, error) { - diskParams := []map[string]interface{}{} - for _, disk := range dataDisks { - diskParams = append(diskParams, map[string]interface{}{ - "volumetype": disk.StorageType, - "size": disk.SizeGB, - }) - } - params := map[string]interface{}{ - "availability_zone": zoneId, - "name": name, - "flavorRef": instanceType, - "imageRef": imageId, - "description": desc, - "count": 1, - "tenancy": "0", - "region_id": self.Id, - "operate_type": "apply", - "service_type": "ecs", - "tenantId": self.client.projectId, - "project_id": self.client.projectId, - "nics": []map[string]interface{}{ - { - "subnet_id": subnetId, - "ip_address": ipAddr, - "binding:profile": map[string]interface{}{ - "disable_security_groups": false, - }, - }, - }, - "security_groups": []map[string]interface{}{ - { - "id": securityGroupId, - }, - }, - "vpcid": vpcId, - "metadata": map[string]string{}, - "root_volume": map[string]interface{}{ - "volumetype": sysDisk.StorageType, - "size": sysDisk.SizeGB, - }, - "data_volumes": diskParams, - "extendparam": map[string]interface{}{ - "enterprise_project_id": projectId, - "regionID": self.Id, - }, - } - - if len(keypair) > 0 { - params["key_name"] = keypair - } else { - params["adminPass"] = passwd - } - - if len(userData) > 0 { - params["user_data"] = userData - } - tagParams := []map[string]interface{}{} - for k, v := range tags { - tagParams = append(tagParams, map[string]interface{}{ - "key": k, - "value": v, - }) - } - params["server_tags"] = tagParams - body := map[string]interface{}{ - "server": params, - } - job := &SJob{} - err := self.client.create("ecs", "v1.1", self.Id, "cloudservers", body, job) - if err != nil { - return nil, err - } - for _, sub := range job.Entities.SubJobs { - if len(sub.Entities.ServerId) > 0 { - return self.GetInstance(sub.Entities.ServerId) - } - } - return nil, fmt.Errorf("no server id returned with job %s", jsonutils.Marshal(job)) -} - -func (self *SRegion) AssignSecurityGroups(secgroupIds []string, instanceId string) error { - return cloudprovider.ErrNotImplemented -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067161717.html -func (self *SRegion) UnassignSecurityGroups(secgroupIds []string, instanceId string) error { - return cloudprovider.ErrNotImplemented -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212207.html -func (self *SRegion) StartVM(id string) error { - params := map[string]interface{}{ - "os-start": map[string]string{}, - } - res := fmt.Sprintf("servers/%s", id) - return self.ecsPerform(res, "action", params, nil) -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212651.html -func (self *SRegion) StopVM(id string, isForce bool) error { - params := map[string]interface{}{ - "os-stop": map[string]string{}, - } - res := fmt.Sprintf("servers/%s", id) - return self.ecsPerform(res, "action", params, nil) -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212679.html -// 只删除主机。弹性IP和数据盘需要单独删除 -func (self *SRegion) DeleteVM(id string) error { - params := map[string]interface{}{ - "delete_publicip": false, - "delete_volume": false, - "servers": []struct { - Id string - }{ - {Id: id}, - }, - } - return self.perform("ecs", "v1", "cloudservers", "delete", params, nil) -} - -func (self *SRegion) UpdateVM(instanceId, name string) error { - params := map[string]interface{}{ - "server": map[string]string{ - "name": name, - }, - } - return self.update("ecs", "v2.1", "servers/"+instanceId, params) -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html -// 返回job id -func (self *SRegion) RebuildRoot(ctx context.Context, userId, instanceId, passwd, publicKeyName, userData string) error { - reInstall := map[string]interface{}{} - if len(publicKeyName) > 0 { - reInstall["keyname"] = publicKeyName - } else if len(passwd) > 0 { - reInstall["adminpass"] = passwd - } else { - return fmt.Errorf("both password and publicKey are empty.") - } - if len(userId) > 0 { - reInstall["userid"] = userId - } - metadata := map[string]interface{}{} - if len(userData) > 0 { - metadata["user_data"] = userData - } - reInstall["metadata"] = metadata - - params := map[string]interface{}{ - "os-reinstall": reInstall, - } - return self.ecsPerform("cloudservers/"+instanceId, "reinstallos", params, nil) -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html -// 返回job id -func (self *SRegion) ChangeRoot(ctx context.Context, userId, instanceId, imageId, passwd, publicKeyName, userData string) error { - osChange := map[string]interface{}{} - if len(publicKeyName) > 0 { - osChange["keyname"] = publicKeyName - } else if len(passwd) > 0 { - osChange["adminpass"] = passwd - } else { - return fmt.Errorf("both password and publicKey are empty.") - } - if len(userId) > 0 { - osChange["userid"] = userId - } - metadata := map[string]interface{}{} - if len(userData) > 0 { - metadata["user_data"] = userData - } - osChange["metadata"] = metadata - osChange["imageid"] = imageId - params := map[string]interface{}{ - "os-change": osChange, - } - return self.ecsPerform("cloudservers/"+instanceId, "changeos", params, nil) -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212692.html -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0110109377.html -// 一键式重置密码 需要安装安装一键式重置密码插件 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0068095385.html -// 目前不支持直接重置密钥 -func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { - if len(name) > 0 { - err := self.UpdateVM(instanceId, name) - if err != nil { - return err - } - } - - if len(password) > 0 { - params := map[string]interface{}{ - "reset-password": map[string]interface{}{ - "new_password": password, - }, - } - return self.perform("ecs", "v1", "cloudservers/"+instanceId, "os-reset-password", params, nil) - } - return nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212653.html -func (self *SRegion) ChangeVMConfig(instanceId string, instanceType string) error { - params := map[string]interface{}{ - "resize": map[string]interface{}{ - "flavorRef": instanceType, - }, - } - return self.perform("ecs", "v1.1", "cloudservers/"+instanceId, "resize", params, nil) -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0142763126.html 微版本2.6及以上? -// https://support.huaweicloud.com/api-ecs/ecs_02_0208.html -func (self *SRegion) GetInstanceVNCUrl(instanceId string) (*cloudprovider.ServerVncOutput, error) { - params := map[string]interface{}{ - "remote_console": map[string]interface{}{ - "type": "novnc", - "protocol": "vnc", - }, - } - ret := &cloudprovider.ServerVncOutput{} - err := self.perform("ecs", "v1", "cloudservers/"+instanceId, "remote_console", params, ret) - if err != nil { - return nil, err - } - ret.Hypervisor = api.HYPERVISOR_HUAWEI - ret.Protocol = "huawei" - return ret, nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817702.html -func (self *SRegion) GetInstanceSecrityGroups(instanceId string) ([]SSecurityGroup, error) { - ret := []SSecurityGroup{} - return ret, self.get("ecs", "v2.1", "servers/"+instanceId+"/os-security-groups", &ret) -} - -func (self *SInstance) GetProjectId() string { - return self.EnterpriseProjectId -} - -func (self *SInstance) GetError() error { - return nil -} - -func updateUserData(userData, osVersion, username, password, publicKey string) (string, error) { - winOS := strings.ToLower(osprofile.OS_TYPE_WINDOWS) - osVersion = strings.ToLower(osVersion) - config := &cloudinit.SCloudConfig{} - if len(userData) > 0 { - if strings.Contains(osVersion, winOS) { - if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { - config = _config - } else { - log.Debugf("updateWindowsUserData invalid userdata %s", userData) - } - } else { - if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { - config = _config - } else { - return "", fmt.Errorf("updateLinuxUserData invalid userdata %s", userData) - } - } - } - - user := cloudinit.NewUser(username) - config.RemoveUser(user) - config.DisableRoot = 0 - if len(password) > 0 { - config.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON - user.Password(password) - config.MergeUser(user) - } - - if len(publicKey) > 0 { - user.SshKey(publicKey) - config.MergeUser(user) - } - - if strings.Contains(osVersion, winOS) { - userData, err := updateWindowsUserData(config.UserDataPowerShell(), osVersion, username, password) - if err != nil { - return "", errors.Wrap(err, "updateUserData.updateWindowsUserData") - } - return userData, nil - } else { - return config.UserDataBase64(), nil - } -} - -func updateWindowsUserData(userData string, osVersion string, username, password string) (string, error) { - // Windows Server 2003, Windows Vista, Windows Server 2008, Windows Server 2003 R2, Windows Server 2000, Windows Server 2012, Windows Server 2003 with SP1, Windows 8 - oldVersions := []string{"2000", "2003", "2008", "2012", "Vista"} - isOldVersion := false - for i := range oldVersions { - if strings.Contains(osVersion, oldVersions[i]) { - isOldVersion = true - } - } - - shells := "" - if isOldVersion { - shells += fmt.Sprintf("rem cmd\n") - if username == "Administrator" { - shells += fmt.Sprintf("net user %s %s\n", username, password) - } else { - shells += fmt.Sprintf("net user %s %s /add\n", username, password) - shells += fmt.Sprintf("net localgroup administrators %s /add\n", username) - } - - shells += fmt.Sprintf("net user %s /active:yes", username) - } else { - if !strings.HasPrefix(userData, "#ps1") { - shells = fmt.Sprintf("#ps1\n%s", userData) - } - } - - return base64.StdEncoding.EncodeToString([]byte(shells)), nil -} - -func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { - params := map[string]interface{}{ - "name": opts.Name, - "instance_id": instanceId, - } - if len(opts.Notes) > 0 { - params["description"] = func() string { - opts.Notes = strings.ReplaceAll(opts.Notes, "<", "") - opts.Notes = strings.ReplaceAll(opts.Notes, ">", "") - opts.Notes = strings.ReplaceAll(opts.Notes, "\n", "") - if len(opts.Notes) > 1024 { - opts.Notes = opts.Notes[:1024] - } - return opts.Notes - }() - } - ret := &SImage{cache: &SStoragecache{region: self}} - return ret, self.perform("ims", "v2", "cloudimages", "action", params, ret) -} - -func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { - image, err := self.host.zone.region.SaveImage(self.Id, opts) - if err != nil { - return nil, errors.Wrapf(err, "SaveImage") - } - return image, nil -} diff --git a/pkg/multicloud/hcs/instancenic.go b/pkg/multicloud/hcs/instancenic.go deleted file mode 100644 index 76a09558c7..0000000000 --- a/pkg/multicloud/hcs/instancenic.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -// =========================================== -type Interface struct { - PortState string `json:"port_state"` - FixedIPS []FixedIP `json:"fixed_ips"` - NetId string `json:"net_id"` // 网络Id. 与 SNetwork里的Id对应。统一使用这个Id - PortId string `json:"port_id"` - MACAddr string `json:"mac_addr"` -} - -type FixedIP struct { - SubnetId string `json:"subnet_id"` // 子网Id, 与SNetwork中的 neutron_subnet_id对应. 注意!!! 并不是SNetwork Id。 - IPAddress string `json:"ip_address"` -} - -type SInstanceNic struct { - instance *SInstance - ipAddr string - macAddr string - - cloudprovider.DummyICloudNic -} - -func (self *SInstanceNic) GetId() string { - return "" -} - -func (self *SInstanceNic) GetIP() string { - return self.ipAddr -} - -func (self *SInstanceNic) GetMAC() string { - return self.macAddr -} - -func (self *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (self *SInstanceNic) GetINetworkId() string { - instanceId := self.instance.GetId() - subnets, _ := self.instance.host.zone.region.GetInstanceInterfaces(instanceId) - for i := range subnets { - return subnets[i].NetId - } - return "" -} - -type SInstanceInterface struct { - NetId string - PortId string - MacAddr string - PortState string - FixedIps []struct { - SubnetId string - IpAddress string - } -} - -func (self *SRegion) GetInstanceInterfaces(instanceId string) ([]SInstanceInterface, error) { - ret := []SInstanceInterface{} - return ret, self.get("ecs", "v2.1", "servers/"+instanceId+"/os-interface", &ret) -} diff --git a/pkg/multicloud/hcs/instancetype.go b/pkg/multicloud/hcs/instancetype.go deleted file mode 100644 index 3de89094d8..0000000000 --- a/pkg/multicloud/hcs/instancetype.go +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212656.html -type SInstanceType struct { - multicloud.SResourceBase - multicloud.HcsTags - - Id string `json:"id"` - Name string `json:"name"` - Vcpus int `json:"vcpus"` - RamMB int `json:"ram"` // 内存大小 - OSExtraSpecs OSExtraSpecs `json:"os_extra_specs"` // 扩展规格 -} - -type OSExtraSpecs struct { - EcsPerformancetype string `json:"ecs:performancetype"` - EcsGeneration string `json:"ecs:generation"` - EcsInstanceArchitecture string `json:"ecs:instance_architecture"` -} - -func (self *SInstanceType) GetId() string { - return self.Id -} - -func (self *SInstanceType) GetName() string { - return self.Id -} - -func (self *SInstanceType) GetGlobalId() string { - return self.Id -} - -func (self *SInstanceType) GetInstanceTypeFamily() string { - if len(self.OSExtraSpecs.EcsGeneration) > 0 { - return self.OSExtraSpecs.EcsGeneration - } - return strings.Split(self.Name, ".")[0] -} - -func (self *SInstanceType) GetStatus() string { - return "" -} - -func (self *SInstanceType) GetInstanceTypeCategory() string { - return self.OSExtraSpecs.EcsPerformancetype -} - -func (self *SInstanceType) GetPrepaidStatus() string { - return api.SkuStatusSoldout -} - -func (self *SInstanceType) GetPostpaidStatus() string { - return api.SkuStatusAvailable -} - -func (self *SInstanceType) GetCpuArch() string { - if len(self.OSExtraSpecs.EcsInstanceArchitecture) > 0 { - if strings.HasPrefix(self.OSExtraSpecs.EcsInstanceArchitecture, "arm") { - return apis.OS_ARCH_AARCH64 - } - return apis.OS_ARCH_X86 - } - return "" -} - -func (self *SInstanceType) GetCpuCoreCount() int { - return self.Vcpus -} - -func (self *SInstanceType) GetMemorySizeMB() int { - return self.RamMB -} - -func (self *SInstanceType) GetOsName() string { - return "" -} - -func (self *SInstanceType) GetSysDiskResizable() bool { - return false -} - -func (self *SInstanceType) GetSysDiskType() string { - return "" -} - -func (self *SInstanceType) GetSysDiskMinSizeGB() int { - return 0 -} - -func (self *SInstanceType) GetSysDiskMaxSizeGB() int { - return 0 -} - -func (self *SInstanceType) GetAttachedDiskType() string { - return "" -} - -func (self *SInstanceType) GetAttachedDiskSizeGB() int { - return 0 -} - -func (self *SInstanceType) GetAttachedDiskCount() int { - return 0 -} - -func (self *SInstanceType) GetDataDiskTypes() string { - return "" -} - -func (self *SInstanceType) GetDataDiskMaxCount() int { - return 0 -} - -func (self *SInstanceType) GetNicType() string { - return "" -} - -func (self *SInstanceType) GetNicMaxCount() int { - return 0 -} - -func (self *SInstanceType) GetGpuAttachable() bool { - return self.OSExtraSpecs.EcsPerformancetype == "gpu" -} - -func (self *SInstanceType) GetGpuSpec() string { - if self.OSExtraSpecs.EcsPerformancetype == "gpu" { - return self.OSExtraSpecs.EcsGeneration - } - - return "" -} - -func (self *SInstanceType) GetGpuCount() int { - if self.OSExtraSpecs.EcsPerformancetype == "gpu" { - return 1 - } - - return 0 -} - -func (self *SInstanceType) GetGpuMaxCount() int { - if self.OSExtraSpecs.EcsPerformancetype == "gpu" { - return 1 - } - - return 0 -} - -func (self *SInstanceType) Delete() error { - return nil -} - -func (self *SRegion) GetchInstanceTypes(zoneId string) ([]SInstanceType, error) { - query := url.Values{} - if len(zoneId) > 0 { - query.Set("availability_zone", zoneId) - } - ret := []SInstanceType{} - return ret, self.list("ecs", "v1", "cloudservers/flavors", query, &ret) -} - -func (self *SRegion) GetchInstanceType(id string) (*SInstanceType, error) { - ret := &SInstanceType{} - res := fmt.Sprintf("flavors/%s", id) - return ret, self.get("ecs", "v2", res, &ret) -} - -func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, zoneId string) ([]SInstanceType, error) { - instanceTypes, err := self.GetchInstanceTypes(zoneId) - if err != nil { - return nil, err - } - - ret := make([]SInstanceType, 0) - for _, t := range instanceTypes { - // cpu & mem & disk都匹配才行 - if t.Vcpus == cpu && t.RamMB == memMB { - ret = append(ret, t) - } - } - - return ret, nil -} - -func (self *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { - flavors, err := self.GetchInstanceTypes("") - if err != nil { - return nil, errors.Wrap(err, "fetchInstanceTypes") - } - ret := []cloudprovider.ICloudSku{} - for i := range flavors { - ret = append(ret, &flavors[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/hcs/job.go b/pkg/multicloud/hcs/job.go deleted file mode 100644 index 62e158c51c..0000000000 --- a/pkg/multicloud/hcs/job.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - TASK_SUCCESS = "SUCCESS" - TASK_FAIL = "FAIL" -) - -type SJob struct { - Status string `json:"status"` - Entities struct { - SubJobsJotal int - ImageId string - ServerId string - SubJobs []SJob - } `json:"entities"` - JobId string `json:"job_id"` - JobType string `json:"job_type"` - BeginTime string `json:"begin_time"` - EndTime string `json:"end_time"` - ErrorCode string `json:"error_code"` - FailReason string `json:"fail_reason"` -} - -func (self *SJob) GetIds() []string { - ret := []string{} - if len(self.Entities.ImageId) > 0 { - ret = append(ret, self.Entities.ImageId) - } - if len(self.Entities.ServerId) > 0 { - ret = append(ret, self.Entities.ServerId) - } - for _, sub := range self.Entities.SubJobs { - if len(sub.Entities.ServerId) > 0 { - ret = append(ret, sub.Entities.ServerId) - } - } - return ret -} - -func (self *SHcsClient) waitJobSuccess(serviceType, regionId string, jobId string, interval time.Duration, timeout time.Duration) (*SJob, error) { - start := time.Now() - var job *SJob - var err error - for time.Now().Sub(start) < timeout { - job, err = self.GetJob(serviceType, regionId, jobId) - if err != nil { - return nil, err - } - log.Infof("wait %s job %s(%s) status: %s", serviceType, job.JobId, job.JobType, job.Status) - if job.Status == TASK_SUCCESS { - return job, nil - } - reason := []string{job.FailReason} - for _, subJob := range job.Entities.SubJobs { - if len(subJob.FailReason) > 0 { - reason = append(reason, subJob.FailReason) - } - } - if job.Status == TASK_FAIL { - return nil, fmt.Errorf("job %s failed reason %s", jobId, strings.Join(reason, ";")) - } - time.Sleep(interval) - } - return nil, errors.Wrapf(cloudprovider.ErrTimeout, "wait job %s", jsonutils.Marshal(job)) -} - -func (self *SHcsClient) GetJob(service, regionId string, jobId string) (*SJob, error) { - resp, err := self._getJob(service, regionId, jobId) - if err != nil { - return nil, err - } - ret := &SJob{} - return ret, resp.Unmarshal(ret) - -} - -func (self *SRegion) GetJob(service string, jobId string) (*SJob, error) { - return self.client.GetJob(service, self.Id, jobId) -} diff --git a/pkg/multicloud/hcs/loadbalancer.go b/pkg/multicloud/hcs/loadbalancer.go deleted file mode 100644 index 2892231f7c..0000000000 --- a/pkg/multicloud/hcs/loadbalancer.go +++ /dev/null @@ -1,601 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - "fmt" - "net/url" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var LB_ALGORITHM_MAP = map[string]string{ - api.LB_SCHEDULER_WRR: "ROUND_ROBIN", - api.LB_SCHEDULER_WLC: "LEAST_CONNECTIONS", - api.LB_SCHEDULER_SCH: "SOURCE_IP", -} - -var LB_PROTOCOL_MAP = map[string]string{ - api.LB_LISTENER_TYPE_HTTP: "HTTP", - api.LB_LISTENER_TYPE_HTTPS: "TERMINATED_HTTPS", - api.LB_LISTENER_TYPE_UDP: "UDP", - api.LB_LISTENER_TYPE_TCP: "TCP", -} - -var LBBG_PROTOCOL_MAP = map[string]string{ - api.LB_LISTENER_TYPE_HTTP: "HTTP", - api.LB_LISTENER_TYPE_HTTPS: "HTTP", - api.LB_LISTENER_TYPE_UDP: "UDP", - api.LB_LISTENER_TYPE_TCP: "TCP", -} - -var LB_STICKY_SESSION_MAP = map[string]string{ - api.LB_STICKY_SESSION_TYPE_INSERT: "HTTP_COOKIE", - api.LB_STICKY_SESSION_TYPE_SERVER: "APP_COOKIE", -} - -var LB_HEALTHCHECK_TYPE_MAP = map[string]string{ - api.LB_HEALTH_CHECK_HTTP: "HTTP", - api.LB_HEALTH_CHECK_TCP: "TCP", - api.LB_HEALTH_CHECK_UDP: "UDP_CONNECT", -} - -type SLoadbalancer struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - subnet *SNetwork - eip *SEip - - Description string `json:"description"` - ProvisioningStatus string `json:"provisioning_status"` - TenantId string `json:"tenant_id"` - ProjectId string `json:"project_id"` - AdminStateUp bool `json:"admin_state_up"` - Provider string `json:"provider"` - Pools []Pool `json:"pools"` - Listeners []Listener `json:"listeners"` - VipPortId string `json:"vip_port_id"` - OperatingStatus string `json:"operating_status"` - VipAddress string `json:"vip_address"` - VipSubnetId string `json:"vip_subnet_id"` - Id string `json:"id"` - Name string `json:"name"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` -} - -type Listener struct { - Id string `json:"id"` -} - -type Pool struct { - Id string `json:"id"` -} - -func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { - if self.GetEip() == nil { - return nil, nil - } - - return self.eip, nil -} - -func (self *SLoadbalancer) GetId() string { - return self.Id -} - -func (self *SLoadbalancer) GetName() string { - return self.Name -} - -func (self *SLoadbalancer) GetGlobalId() string { - return self.Id -} - -func (self *SLoadbalancer) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancer) Refresh() error { - lb, err := self.region.GetLoadbalancer(self.GetId()) - if err != nil { - return err - } - - return jsonutils.Update(self, lb) -} - -func (self *SLoadbalancer) IsEmulated() bool { - return false -} - -func (self *SLoadbalancer) GetProjectId() string { - return self.ProjectId -} - -func (self *SLoadbalancer) GetAddress() string { - return self.VipAddress -} - -// todo: api.LB_ADDR_TYPE_INTERNET? -func (self *SLoadbalancer) GetAddressType() string { - return api.LB_ADDR_TYPE_INTRANET -} - -func (self *SLoadbalancer) GetNetworkType() string { - return api.LB_NETWORK_TYPE_VPC -} - -func (self *SLoadbalancer) GetNetworkIds() []string { - net := self.GetNetwork() - if net != nil { - return []string{net.GetId()} - } - - return []string{} -} - -func (self *SLoadbalancer) GetNetwork() *SNetwork { - if self.subnet == nil { - port, err := self.region.GetPort(self.VipPortId) - if err == nil { - net, err := self.region.GetNetwork(port.NetworkId) - if err == nil { - self.subnet = net - } else { - log.Debugf("huawei.SLoadbalancer.getNetwork %s", err) - } - } else { - log.Debugf("huawei.SLoadbalancer.GetPort %s", err) - } - } - - return self.subnet -} - -func (self *SLoadbalancer) GetEip() *SEip { - if self.eip == nil { - eips, _ := self.region.GetEips(self.VipPortId, nil) - for i := range eips { - self.eip = &eips[i] - } - } - return self.eip -} - -func (self *SLoadbalancer) GetVpcId() string { - net := self.GetNetwork() - if net != nil { - return net.VpcId - } - - return "" -} - -func (self *SLoadbalancer) GetZoneId() string { - net := self.GetNetwork() - if net != nil { - z, err := self.region.GetZoneById(net.AvailabilityZone) - if err != nil { - log.Infof("getZoneById %s %s", net.AvailabilityZone, err) - return "" - } - - return z.GetGlobalId() - } - - return "" -} - -func (self *SLoadbalancer) GetZone1Id() string { - return "" -} - -func (self *SLoadbalancer) GetLoadbalancerSpec() string { - return "" -} - -func (self *SLoadbalancer) GetChargeType() string { - eip := self.GetEip() - if eip != nil { - return eip.GetInternetChargeType() - } - - return api.EIP_CHARGE_TYPE_BY_TRAFFIC -} - -func (self *SLoadbalancer) GetEgressMbps() int { - eip := self.GetEip() - if eip != nil { - return eip.GetBandwidth() - } - - return 0 -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0141008275.html -func (self *SLoadbalancer) Delete(ctx context.Context) error { - return self.region.DeleteLoadBalancer(self.GetId()) -} - -func (self *SLoadbalancer) Start() error { - return nil -} - -func (self *SLoadbalancer) Stop() error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - ret, err := self.region.GetLoadBalancerListeners(self.GetId()) - if err != nil { - return nil, err - } - - iret := make([]cloudprovider.ICloudLoadbalancerListener, 0) - for i := range ret { - listener := ret[i] - listener.lb = self - iret = append(iret, &listener) - } - - return iret, nil -} - -func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - ret, err := self.region.GetLoadBalancerBackendGroups(self.GetId()) - if err != nil { - return nil, err - } - - iret := make([]cloudprovider.ICloudLoadbalancerBackendGroup, 0) - for i := range ret { - bg := ret[i] - bg.lb = self - bg.region = self.region - iret = append(iret, &bg) - } - - return iret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561549.html -func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - ret, err := self.region.CreateLoadBalancerBackendGroup(group) - ret.lb = self - return &ret, err -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561563.html -func (self *SLoadbalancer) CreateHealthCheck(backendGroupId string, healthcheck *cloudprovider.SLoadbalancerHealthCheck) error { - _, err := self.region.CreateLoadBalancerHealthCheck(backendGroupId, healthcheck) - return err -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561548.html -func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - ret := &SElbBackendGroup{lb: self, region: self.region} - return ret, self.region.lbGet("lbaas/pools/"+groupId, ret) -} - -func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - ret, err := self.region.CreateLoadBalancerListener(listener) - if err != nil { - return nil, err - } - - ret.lb = self - return &ret, nil -} - -func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { - ret := &SElbListener{lb: self} - return ret, self.region.lbGet("lbaas/listeners/"+listenerId, ret) -} - -func (self *SRegion) GetLoadbalancer(id string) (*SLoadbalancer, error) { - ret := &SLoadbalancer{region: self} - return ret, self.lbGet("lbaas/loadbalancers/"+id, ret) -} - -func (self *SRegion) DeleteLoadBalancer(elbId string) error { - resource := fmt.Sprintf("lbaas/loadbalancers/%s", elbId) - return self.lbDelete(resource) -} - -func (self *SRegion) GetLoadBalancerListeners(lbId string) ([]SElbListener, error) { - ret := []SElbListener{} - params := url.Values{} - if len(lbId) > 0 { - params.Set("loadbalancer_id", lbId) - } - return ret, self.lbList("lbaas/listeners", params, &ret) -} - -func (self *SRegion) CreateLoadBalancerListener(listener *cloudprovider.SLoadbalancerListener) (SElbListener, error) { - params := map[string]interface{}{ - "name": listener.Name, - "description": listener.Description, - "protocol": LB_PROTOCOL_MAP[listener.ListenerType], - "protocol_port": listener.ListenerPort, - "loadbalancer_id": listener.LoadbalancerID, - "http2_enable": listener.EnableHTTP2, - } - if len(listener.BackendGroupID) > 0 { - params["default_pool_id"] = listener.BackendGroupID - } - - if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { - params["default_tls_container_ref"] = listener.CertificateID - } - - if listener.XForwardedFor { - params["insert_headers"] = map[string]interface{}{ - "X-Forwarded-ELB-IP": listener.XForwardedFor, - } - } - - ret := SElbListener{} - err := self.lbCreate("lbaas/listeners", map[string]interface{}{"listener": params}, &ret) - if err != nil { - return ret, err - } - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html -func (self *SRegion) GetLoadBalancerBackendGroups(elbId string) ([]SElbBackendGroup, error) { - query := url.Values{} - if len(elbId) > 0 { - query.Set("loadbalancer_id", elbId) - } - - ret := []SElbBackendGroup{} - return ret, self.lbList("lbaas/pools", query, &ret) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html -func (self *SRegion) CreateLoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (SElbBackendGroup, error) { - ret := SElbBackendGroup{region: self} - var protocol, scheduler string - if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { - return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) - } else { - scheduler = s - } - - if t, ok := LBBG_PROTOCOL_MAP[group.ListenType]; !ok { - return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported listener type %s", group.ListenType) - } else { - protocol = t - } - - params := map[string]interface{}{ - "project_id": self.client.projectId, - "name": group.Name, - "protocol": protocol, - "lb_algorithm": scheduler, - } - - if len(group.ListenerID) > 0 { - params["listener_id"] = group.ListenerID - } else if len(group.LoadbalancerID) > 0 { - params["loadbalancer_id"] = group.LoadbalancerID - } else { - return ret, fmt.Errorf("CreateLoadBalancerBackendGroup one of listener id / loadbalancer id must be specified") - } - - if group.StickySession != nil { - s := map[string]interface{}{} - timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) - if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { - s["type"] = "SOURCE_IP" - if timeout > 0 { - s["persistence_timeout"] = timeout - } - } else { - s["type"] = LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType] - if len(group.StickySession.StickySessionCookie) > 0 { - s["cookie_name"] = group.StickySession.StickySessionCookie - } else { - if timeout > 0 { - s["persistence_timeout"] = timeout - } - } - } - params["session_persistence"] = s - } - err := self.lbCreate("lbaas/pools", map[string]interface{}{"pool": params}, &ret) - if err != nil { - return ret, err - } - - if group.HealthCheck != nil { - _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) - if err != nil { - return ret, err - } - } - - return ret, nil -} - -func (self *SRegion) CreateLoadBalancerHealthCheck(backendGroupId string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { - params := map[string]interface{}{ - "delay": healthCheck.HealthCheckInterval, - "max_retries": healthCheck.HealthCheckRise, - "pool_id": backendGroupId, - "timeout": healthCheck.HealthCheckTimeout, - "type": LB_HEALTHCHECK_TYPE_MAP[healthCheck.HealthCheckType], - } - if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { - if len(healthCheck.HealthCheckDomain) > 0 { - params["domain_name"] = healthCheck.HealthCheckDomain - } - - if len(healthCheck.HealthCheckURI) > 0 { - params["url_path"] = healthCheck.HealthCheckURI - } - - if len(healthCheck.HealthCheckHttpCode) > 0 { - params["expected_codes"] = ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode) - } - } - - ret := SElbHealthCheck{region: self} - err := self.lbCreate("lbaas/healthmonitors", map[string]interface{}{"healthmonitor": params}, &ret) - if err != nil { - return ret, err - } - - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561564.html -func (self *SRegion) UpdateLoadBalancerHealthCheck(healthCheckId string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { - params := map[string]interface{}{ - "delay": healthCheck.HealthCheckInterval, - "max_retries": healthCheck.HealthCheckRise, - "timeout": healthCheck.HealthCheckTimeout, - } - if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { - if len(healthCheck.HealthCheckDomain) > 0 { - params["domain_name"] = healthCheck.HealthCheckDomain - } - - if len(healthCheck.HealthCheckURI) > 0 { - params["url_path"] = healthCheck.HealthCheckURI - } - - if len(healthCheck.HealthCheckHttpCode) > 0 { - params["expected_codes"] = ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode) - } - } - - ret := SElbHealthCheck{region: self} - res := "lbaas/healthmonitors/" + healthCheckId - err := self.lbUpdate(res, map[string]interface{}{"healthmonitor": params}) - if err != nil { - return ret, err - } - return ret, self.lbGet(res, &ret) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561565.html -func (self *SRegion) DeleteLoadbalancerHealthCheck(healthCheckId string) error { - return self.lbDelete("lbaas/healthmonitors/" + healthCheckId) -} - -func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) lbGet(resource string, retVal interface{}) error { - return self.client.get("vpc", "v2.0", self.Id, resource, retVal) -} - -func (self *SRegion) lbList(resource string, params url.Values, retVal interface{}) error { - return self.list("vpc", "v2.0", resource, params, retVal) -} - -func (self *SRegion) lbDelete(resource string) error { - return self.delete("vpc", "v2.0", resource) -} - -func (self *SRegion) lbCreate(resource string, params map[string]interface{}, retVal interface{}) error { - return self.create("vpc", "v2.0", resource, params, retVal) -} - -func (self *SRegion) lbUpdate(resource string, params map[string]interface{}) error { - return self.update("vpc", "v2.0", resource, params) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561535.html -func (self *SRegion) CreateLoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (*SLoadbalancer, error) { - subnet, err := self.GetNetwork(loadbalancer.NetworkIDs[0]) - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateLoadBalancer.getNetwork") - } - - params := map[string]interface{}{ - "name": loadbalancer.Name, - "vip_subnet_id": subnet.NeutronSubnetId, - "tenant_id": self.client.projectId, - } - if len(loadbalancer.Address) > 0 { - params["vip_address"] = loadbalancer.Address - } - ret := &SLoadbalancer{region: self} - err = self.lbCreate("lbaas/loadbalancers", map[string]interface{}{"loadbalancer": params}, ret) - if err != nil { - return nil, err - } - - // 创建公网类型ELB - if len(loadbalancer.EipID) > 0 { - err := self.AssociateEipWithPortId(loadbalancer.EipID, ret.VipPortId) - if err != nil { - return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.AssociateEipWithPortId") - } - } - return ret, nil -} - -func (self *SRegion) GetLoadBalancers() ([]SLoadbalancer, error) { - lbs := []SLoadbalancer{} - params := url.Values{} - return lbs, self.lbList("lbaas/loadbalancers", params, &lbs) -} - -func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - elbs, err := self.GetLoadBalancers() - if err != nil { - return nil, err - } - - ret := []cloudprovider.ICloudLoadbalancer{} - for i := range elbs { - elbs[i].region = self - ret = append(ret, &elbs[i]) - } - - return ret, nil -} - -func (self *SRegion) GetILoadBalancerById(id string) (cloudprovider.ICloudLoadbalancer, error) { - elb, err := self.GetLoadbalancer(id) - if err != nil { - return nil, err - } - return elb, nil -} - -func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - ret, err := self.CreateLoadBalancer(loadbalancer) - if err != nil { - return nil, err - } - - return ret, nil -} diff --git a/pkg/multicloud/hcs/loadbalancer_acl.go b/pkg/multicloud/hcs/loadbalancer_acl.go deleted file mode 100644 index 4fbebf301a..0000000000 --- a/pkg/multicloud/hcs/loadbalancer_acl.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "net/url" - "strings" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbACL struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - - Id string `json:"id"` - ListenerId string `json:"listener_id"` - TenantId string `json:"tenant_id"` - EnableWhitelist bool `json:"enable_whitelist"` - Whitelist string `json:"whitelist"` -} - -func (self *SElbACL) GetAclListenerID() string { - return self.ListenerId -} - -func (self *SElbACL) GetId() string { - return self.Id -} - -func (self *SElbACL) GetName() string { - return self.Id -} - -func (self *SElbACL) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbACL) GetStatus() string { - if self.EnableWhitelist { - return api.LB_BOOL_ON - } - - return api.LB_BOOL_OFF -} - -func (self *SElbACL) Refresh() error { - acl, err := self.region.GetLoadBalancerAcl(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, acl) -} - -func (self *SElbACL) IsEmulated() bool { - return false -} - -func (self *SElbACL) GetProjectId() string { - return "" -} - -func (self *SElbACL) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { - ret := []cloudprovider.SLoadbalancerAccessControlListEntry{} - for _, cidr := range strings.Split(self.Whitelist, ",") { - ret = append(ret, cloudprovider.SLoadbalancerAccessControlListEntry{CIDR: cidr}) - } - - return ret -} - -func (self *SElbACL) Sync(acl *cloudprovider.SLoadbalancerAccessControlList) error { - whiteList := "" - cidrs := []string{} - for _, entry := range acl.Entrys { - cidrs = append(cidrs, entry.CIDR) - } - whiteList = strings.Join(cidrs, ",") - params := map[string]interface{}{ - "whitelist": whiteList, - "enable_whitelist": acl.AccessControlEnable, - } - return self.region.lbUpdate("lbaas/whitelists/"+self.GetId(), map[string]interface{}{"whitelist": params}) -} - -func (self *SElbACL) Delete() error { - return self.region.lbDelete("lbaas/whitelists/" + self.GetId()) -} - -func (self *SRegion) GetLoadBalancerAcl(aclId string) (*SElbACL, error) { - ret := &SElbACL{region: self} - return ret, self.lbGet("lbaas/whitelists/"+aclId, ret) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561582.html -func (self *SRegion) GetLoadBalancerAcls(listenerId string) ([]SElbACL, error) { - query := url.Values{} - if len(listenerId) > 0 { - query.Set("listener_id", listenerId) - } - ret := []SElbACL{} - return ret, self.lbList("lbaas/whitelists", query, &ret) -} - -func (self *SRegion) CreateLoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (*SElbACL, error) { - params := map[string]interface{}{ - "listener_id": acl.ListenerId, - } - if len(acl.Entrys) > 0 { - whitelist := []string{} - for i := range acl.Entrys { - whitelist = append(whitelist, acl.Entrys[i].CIDR) - } - params["enable_whitelist"] = acl.AccessControlEnable - params["whitelist"] = strings.Join(whitelist, ",") - } else { - params["enable_whitelist"] = false - } - ret := &SElbACL{region: self} - return ret, self.lbCreate("lbaas/whitelists", map[string]interface{}{"whitelist": params}, ret) -} - -func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - ret, err := self.CreateLoadBalancerAcl(acl) - if err != nil { - return nil, err - } - - return ret, nil -} - -func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { - acl, err := self.GetLoadBalancerAcl(aclId) - if err != nil { - return nil, err - } - return acl, nil -} diff --git a/pkg/multicloud/hcs/loadbalancer_backend.go b/pkg/multicloud/hcs/loadbalancer_backend.go deleted file mode 100644 index 3d26822da3..0000000000 --- a/pkg/multicloud/hcs/loadbalancer_backend.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbBackend struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - lb *SLoadbalancer - backendGroup *SElbBackendGroup - - Name string `json:"name"` - Weight int `json:"weight"` - AdminStateUp bool `json:"admin_state_up"` - SubnetId string `json:"subnet_id"` - TenantId string `json:"tenant_id"` - ProjectId string `json:"project_id"` - Address string `json:"address"` - ProtocolPort int `json:"protocol_port"` - OperatingStatus string `json:"operating_status"` - Id string `json:"id"` -} - -func (self *SElbBackend) GetId() string { - return self.Id -} - -func (self *SElbBackend) GetName() string { - return self.Name -} - -func (self *SElbBackend) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbBackend) Refresh() error { - backend, err := self.region.GetElbBackend(self.backendGroup.GetId(), self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, backend) -} - -func (self *SElbBackend) IsEmulated() bool { - return false -} - -func (self *SElbBackend) GetProjectId() string { - return "" -} - -func (self *SElbBackend) GetWeight() int { - return self.Weight -} - -func (self *SElbBackend) GetPort() int { - return self.ProtocolPort -} - -func (self *SElbBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (self *SElbBackend) GetBackendRole() string { - return api.LB_BACKEND_ROLE_DEFAULT -} - -func (self *SElbBackend) GetBackendId() string { - i, err := self.lb.region.getInstanceByIP(self.Address) - if err != nil { - log.Errorf("ElbBackend GetBackendId %s", err) - } - - if i != nil { - return i.GetId() - } - - return "" -} - -func (self *SElbBackend) GetIpAddress() string { - return "" -} - -func (self *SElbBackend) SyncConf(ctx context.Context, port, weight int) error { - if port > 0 { - log.Warningf("Elb backend SyncConf unsupport modify port") - } - - params := map[string]interface{}{ - "weight": weight, - } - res := fmt.Sprintf("lbaas/pools/%s/members/%s", self.backendGroup.GetId(), self.Id) - return self.region.lbUpdate(res, map[string]interface{}{"member": params}) -} - -func (self *SRegion) getInstanceByIP(ip string) (*SInstance, error) { - instances, err := self.GetInstances(ip) - if err != nil { - return nil, errors.Wrapf(err, "GetInstance(%s)", ip) - } - for i := range instances { - return &instances[i], nil - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetElbBackend(pool, id string) (*SElbBackend, error) { - res := fmt.Sprintf("lbaas/pools/%s/members/%s", pool, id) - ret := &SElbBackend{region: self} - return ret, self.lbGet(res, ret) -} diff --git a/pkg/multicloud/hcs/loadbalancer_backendgroup.go b/pkg/multicloud/hcs/loadbalancer_backendgroup.go deleted file mode 100644 index 5a71b14b61..0000000000 --- a/pkg/multicloud/hcs/loadbalancer_backendgroup.go +++ /dev/null @@ -1,490 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbBackendGroup struct { - multicloud.SResourceBase - multicloud.HuaweiTags - lb *SLoadbalancer - region *SRegion - - LBAlgorithm string `json:"lb_algorithm"` - Protocol string `json:"protocol"` - Description string `json:"description"` - AdminStateUp bool `json:"admin_state_up"` - Loadbalancers []Listener `json:"loadbalancers"` - TenantId string `json:"tenant_id"` - ProjectId string `json:"project_id"` - Listeners []Listener `json:"listeners"` - Id string `json:"id"` - Name string `json:"name"` - HealthMonitorId string `json:"healthmonitor_id"` - SessionPersistence StickySession `json:"session_persistence"` -} - -func (self *SElbBackendGroup) GetLoadbalancerId() string { - return self.lb.GetId() -} - -func (self *SElbBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { - return self.lb -} - -type StickySession struct { - Type string `json:"type"` - CookieName string `json:"cookie_name"` - PersistenceTimeout int `json:"persistence_timeout"` -} - -func (self *SElbBackendGroup) GetProtocolType() string { - switch self.Protocol { - case "TCP": - return api.LB_LISTENER_TYPE_TCP - case "UDP": - return api.LB_LISTENER_TYPE_UDP - case "HTTP": - return api.LB_LISTENER_TYPE_HTTP - default: - return "" - } -} - -func (self *SElbBackendGroup) GetScheduler() string { - switch self.LBAlgorithm { - case "ROUND_ROBIN": - return api.LB_SCHEDULER_WRR - case "LEAST_CONNECTIONS": - return api.LB_SCHEDULER_WLC - case "SOURCE_IP": - return api.LB_SCHEDULER_SCH - default: - return "" - } -} - -func ToHuaweiHealthCheckHttpCode(c string) string { - c = strings.TrimSpace(c) - segs := strings.Split(c, ",") - ret := []string{} - for _, seg := range segs { - seg = strings.TrimLeft(seg, "http_") - seg = strings.TrimSpace(seg) - seg = strings.Replace(seg, "xx", "00", -1) - ret = append(ret, seg) - } - - return strings.Join(ret, ",") -} - -func ToOnecloudHealthCheckHttpCode(c string) string { - c = strings.TrimSpace(c) - segs := strings.Split(c, ",") - ret := []string{} - for _, seg := range segs { - seg = strings.TrimSpace(seg) - seg = strings.Replace(seg, "00", "xx", -1) - seg = "http_" + seg - ret = append(ret, seg) - } - - return strings.Join(ret, ",") -} - -func (self *SElbBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - if len(self.HealthMonitorId) == 0 { - return nil, nil - } - - health, err := self.region.GetLoadBalancerHealthCheck(self.HealthMonitorId) - if err != nil { - return nil, err - } - - var healthCheckType string - switch health.Type { - case "TCP": - healthCheckType = api.LB_HEALTH_CHECK_TCP - case "UDP_CONNECT": - healthCheckType = api.LB_HEALTH_CHECK_UDP - case "HTTP": - healthCheckType = api.LB_HEALTH_CHECK_HTTP - default: - healthCheckType = "" - } - - ret := cloudprovider.SLoadbalancerHealthCheck{ - HealthCheckType: healthCheckType, - HealthCheckTimeout: health.Timeout, - HealthCheckDomain: health.DomainName, - HealthCheckURI: health.URLPath, - HealthCheckInterval: health.Delay, - HealthCheckRise: health.MaxRetries, - HealthCheckHttpCode: ToOnecloudHealthCheckHttpCode(health.ExpectedCodes), - } - - return &ret, nil -} - -func (self *SElbBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - if len(self.SessionPersistence.Type) == 0 { - return nil, nil - } - - var stickySessionType string - switch self.SessionPersistence.Type { - case "SOURCE_IP": - stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT - case "HTTP_COOKIE": - stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT - case "APP_COOKIE": - stickySessionType = api.LB_STICKY_SESSION_TYPE_SERVER - } - - ret := cloudprovider.SLoadbalancerStickySession{ - StickySession: api.LB_BOOL_ON, - StickySessionCookie: self.SessionPersistence.CookieName, - StickySessionType: stickySessionType, - StickySessionCookieTimeout: self.SessionPersistence.PersistenceTimeout * 60, - } - - return &ret, nil -} - -func (self *SElbBackendGroup) GetId() string { - return self.Id -} - -func (self *SElbBackendGroup) GetName() string { - return self.Name -} - -func (self *SElbBackendGroup) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbBackendGroup) Refresh() error { - ret, err := self.lb.region.GetLoadBalancerBackendGroupId(self.GetId()) - if err != nil { - return err - } - ret.lb = self.lb - - err = jsonutils.Update(self, ret) - if err != nil { - return err - } - - return nil -} - -func (self *SElbBackendGroup) IsEmulated() bool { - return false -} - -func (self *SElbBackendGroup) GetProjectId() string { - return self.ProjectId -} - -func (self *SElbBackendGroup) IsDefault() bool { - return false -} - -func (self *SElbBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_NORMAL -} - -func (self *SElbBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - ret, err := self.region.GetLoadBalancerBackends(self.GetId()) - if err != nil { - return nil, err - } - - iret := []cloudprovider.ICloudLoadbalancerBackend{} - for i := range ret { - backend := ret[i] - backend.lb = self.lb - backend.backendGroup = self - - iret = append(iret, &backend) - } - - return iret, nil -} - -func (self *SElbBackendGroup) GetILoadbalancerBackendById(serverId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - backend, err := self.region.GetElbBackend(self.GetId(), serverId) - if err != nil { - return nil, err - } - backend.lb = self.lb - backend.backendGroup = self - return backend, nil -} - -func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - instance, err := self.lb.region.GetInstance(serverId) - if err != nil { - return nil, err - } - - nics, err := instance.GetINics() - if err != nil { - return nil, err - } else if len(nics) == 0 { - return nil, fmt.Errorf("AddBackendServer %s no network interface found", serverId) - } - - subnets, err := self.lb.region.GetInstanceInterfaces(instance.GetId()) - if err != nil { - return nil, err - } else if len(subnets) == 0 { - return nil, fmt.Errorf("AddBackendServer %s no subnet found", serverId) - } - - net, err := self.lb.region.GetNetwork(subnets[0].NetId) - if err != nil { - return nil, err - } - - backend, err := self.region.AddLoadBalancerBackend(self.GetId(), net.NeutronSubnetId, nics[0].GetIP(), port, weight) - if err != nil { - return nil, err - } - - backend.lb = self.lb - backend.backendGroup = self - return backend, nil -} - -func (self *SElbBackendGroup) RemoveBackendServer(backendId string, weight int, port int) error { - ibackend, err := self.GetILoadbalancerBackendById(backendId) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - - return errors.Wrap(err, "ElbBackendGroup.GetILoadbalancerBackendById") - } - - err = self.region.RemoveLoadBalancerBackend(self.GetId(), backendId) - if err != nil { - return errors.Wrap(err, "ElbBackendGroup.RemoveBackendServer") - } - - return cloudprovider.WaitDeleted(ibackend, 2*time.Second, 30*time.Second) -} - -func (self *SElbBackendGroup) Delete(ctx context.Context) error { - if len(self.HealthMonitorId) > 0 { - err := self.region.DeleteLoadbalancerHealthCheck(self.HealthMonitorId) - if err != nil { - return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadbalancerHealthCheck") - } - } - - // 删除后端服务器组的同时,删除掉无效的后端服务器数据 - { - backends, err := self.region.getLoadBalancerAdminStateDownBackends(self.GetId()) - if err != nil { - return errors.Wrap(err, "SElbBackendGroup.Delete.getLoadBalancerAdminStateDownBackends") - } - - for i := range backends { - backend := backends[i] - err := self.RemoveBackendServer(backend.GetId(), backend.GetPort(), backend.GetWeight()) - if err != nil { - return errors.Wrap(err, "SElbBackendGroup.Delete.RemoveBackendServer") - } - } - } - - err := self.region.DeleteLoadBalancerBackendGroup(self.GetId()) - if err != nil { - return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadBalancerBackendGroup") - } - - return cloudprovider.WaitDeleted(self, 2*time.Second, 30*time.Second) -} - -func (self *SElbBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - if group == nil { - return nil - } - - _, err := self.region.UpdateLoadBalancerBackendGroup(self.GetId(), group) - return err -} - -func (self *SRegion) GetLoadBalancerBackendGroupId(backendGroupId string) (*SElbBackendGroup, error) { - ret := &SElbBackendGroup{region: self} - res := fmt.Sprintf("lbaas/pools/" + backendGroupId) - return ret, self.lbGet(res, ret) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561550.html -func (self *SRegion) UpdateLoadBalancerBackendGroup(backendGroupId string, group *cloudprovider.SLoadbalancerBackendGroup) (*SElbBackendGroup, error) { - params := map[string]interface{}{ - "name": group.Name, - } - var scheduler string - if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { - return nil, fmt.Errorf("UpdateLoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) - } else { - scheduler = s - } - params["lb_algorithm"] = scheduler - - if group.StickySession == nil || group.StickySession.StickySession == api.LB_BOOL_OFF { - params["session_persistence"] = jsonutils.JSONNull - } else { - s := map[string]interface{}{} - timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) - if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { - s["type"] = "SOURCE_IP" - if timeout > 0 { - s["persistence_timeout"] = timeout - } - } else { - s["type"] = LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType] - if len(group.StickySession.StickySessionCookie) > 0 { - s["cookie_name"] = group.StickySession.StickySessionCookie - } else { - if timeout > 0 { - s["persistence_timeout"] = timeout - } - } - } - params["session_persistence"] = s - } - err := self.lbUpdate("lbaas/pools/"+backendGroupId, map[string]interface{}{"pool": params}) - if err != nil { - return nil, err - } - - ret, err := self.GetLoadBalancerBackendGroupId(backendGroupId) - if err != nil { - return nil, err - } - - if group.HealthCheck == nil && len(ret.HealthMonitorId) > 0 { - err := self.DeleteLoadbalancerHealthCheck(ret.HealthMonitorId) - if err != nil { - return ret, errors.Wrap(err, "DeleteLoadbalancerHealthCheck") - } - } - - if group.HealthCheck != nil { - if len(ret.HealthMonitorId) == 0 { - _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) - if err != nil { - return ret, errors.Wrap(err, "CreateLoadBalancerHealthCheck") - } - } else { - _, err := self.UpdateLoadBalancerHealthCheck(ret.HealthMonitorId, group.HealthCheck) - if err != nil { - return ret, errors.Wrap(err, "UpdateLoadBalancerHealthCheck") - } - } - } - - ret.region = self - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561551.html -func (self *SRegion) DeleteLoadBalancerBackendGroup(id string) error { - return self.lbDelete("lbaas/pools/" + id) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561556.html -func (self *SRegion) AddLoadBalancerBackend(backendGroupId, subnetId, ipaddr string, port, weight int) (*SElbBackend, error) { - params := map[string]interface{}{ - "address": ipaddr, - "protocol_port": port, - "subnet_id": subnetId, - "weight": weight, - } - ret := &SElbBackend{} - return ret, self.lbCreate(fmt.Sprintf("lbaas/pools/%s/members", backendGroupId), map[string]interface{}{"member": params}, ret) -} - -func (self *SRegion) RemoveLoadBalancerBackend(lbbgId string, backendId string) error { - return self.lbDelete(fmt.Sprintf("lbaas/pools/%s/members/%s", lbbgId, backendId)) -} - -func (self *SRegion) getLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { - res := fmt.Sprintf("lbaas/pools/%s/members", backendGroupId) - ret := []SElbBackend{} - return ret, self.lbList(res, url.Values{}, &ret) -} - -func (self *SRegion) GetLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { - ret, err := self.getLoadBalancerBackends(backendGroupId) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetLoadBalancerBackends.getLoadBalancerBackends") - } - - // 过滤掉服务器已经被删除的backend。原因是运管平台查询不到已删除的服务器记录,导致同步出错。产生肮数据。 - filtedRet := []SElbBackend{} - for i := range ret { - if ret[i].AdminStateUp { - backend := ret[i] - filtedRet = append(filtedRet, backend) - } - } - - return filtedRet, nil -} - -func (self *SRegion) getLoadBalancerAdminStateDownBackends(backendGroupId string) ([]SElbBackend, error) { - ret, err := self.getLoadBalancerBackends(backendGroupId) - if err != nil { - return nil, errors.Wrap(err, "SRegion.getLoadBalancerAdminStateDownBackends.getLoadBalancerBackends") - } - - filtedRet := []SElbBackend{} - for i := range ret { - if !ret[i].AdminStateUp { - backend := ret[i] - filtedRet = append(filtedRet, backend) - } - } - - return filtedRet, nil -} - -func (self *SRegion) GetLoadBalancerHealthCheck(healthCheckId string) (*SElbHealthCheck, error) { - ret := &SElbHealthCheck{region: self} - return ret, self.lbGet("lbaas/healthmonitors/"+healthCheckId, ret) -} diff --git a/pkg/multicloud/hcs/loadbalancer_cert.go b/pkg/multicloud/hcs/loadbalancer_cert.go deleted file mode 100644 index c98ff1d66f..0000000000 --- a/pkg/multicloud/hcs/loadbalancer_cert.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "crypto/sha1" - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbCert struct { - multicloud.SResourceBase - multicloud.HcsTags - region *SRegion - - Certificate string `json:"certificate"` - CreateTime time.Time `json:"create_time"` - ExpireTime time.Time `json:"expire_time"` - Description string `json:"description"` - Domain string `json:"domain"` - ID string `json:"id"` - AdminStateUp bool `json:"admin_state_up"` - TenantID string `json:"tenant_id"` - Name string `json:"name"` - PrivateKey string `json:"private_key"` - Type string `json:"type"` - UpdateTime time.Time `json:"update_time"` -} - -func (self *SElbCert) GetPublickKey() string { - return self.Certificate -} - -func (self *SElbCert) GetPrivateKey() string { - return self.PrivateKey -} - -func (self *SElbCert) GetId() string { - return self.ID -} - -func (self *SElbCert) GetName() string { - return self.Name -} - -func (self *SElbCert) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbCert) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbCert) Refresh() error { - cert, err := self.region.GetLoadBalancerCertificate(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, cert) -} - -func (self *SElbCert) IsEmulated() bool { - return false -} - -func (self *SElbCert) GetProjectId() string { - return "" -} - -func (self *SElbCert) Sync(name, privateKey, publickKey string) error { - params := map[string]interface{}{ - "name": name, - "private_key": privateKey, - "certificate": publickKey, - } - return self.region.lbUpdate("lbaas/certificates/"+self.GetId(), params) -} - -func (self *SElbCert) Delete() error { - return self.region.lbDelete("lbaas/certificates/" + self.GetId()) -} - -func (self *SElbCert) GetCommonName() string { - return self.Domain -} - -func (self *SElbCert) GetSubjectAlternativeNames() string { - return self.Domain -} - -func (self *SElbCert) GetFingerprint() string { - _fp := sha1.Sum([]byte(self.Certificate)) - fp := fmt.Sprintf("sha1:% x", _fp) - return strings.Replace(fp, " ", ":", -1) -} - -func (self *SElbCert) GetExpireTime() time.Time { - return self.ExpireTime -} - -func (self *SRegion) GetLoadBalancerCertificate(id string) (*SElbCert, error) { - ret := &SElbCert{region: self} - err := self.lbGet("lbaas/certificates/"+id, ret) - if err != nil { - return nil, err - } - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/elb_qy_zs_0001.html -func (self *SRegion) CreateLoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (*SElbCert, error) { - params := map[string]interface{}{ - "name": cert.Name, - "private_key": cert.PrivateKey, - "certificate": cert.Certificate, - } - ret := &SElbCert{region: self} - err := self.lbCreate("lbaas/certificates", params, ret) - if err != nil { - return nil, err - } - return ret, nil -} - -func (self *SRegion) GetLoadBalancerCertificates() ([]SElbCert, error) { - ret := []SElbCert{} - err := self.lbList("lbaas/certificates", url.Values{}, &ret) - if err != nil { - return nil, err - } - return ret, nil -} - -func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - ret, err := self.GetLoadBalancerCertificates() - if err != nil { - return nil, err - } - - iret := make([]cloudprovider.ICloudLoadbalancerCertificate, len(ret)) - for i := range ret { - ret[i].region = self - iret[i] = &ret[i] - } - return iret, nil -} - -func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - ret, err := self.CreateLoadBalancerCertificate(cert) - if err != nil { - return nil, err - } - return ret, nil -} - -func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - cert, err := self.GetLoadBalancerCertificate(certId) - if err != nil { - return nil, err - } - return cert, nil -} diff --git a/pkg/multicloud/hcs/loadbalancer_listener.go b/pkg/multicloud/hcs/loadbalancer_listener.go deleted file mode 100644 index 712bedf242..0000000000 --- a/pkg/multicloud/hcs/loadbalancer_listener.go +++ /dev/null @@ -1,643 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - "fmt" - "net/url" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type InsertHeaders struct { - XForwardedELBIP bool `json:"X-Forwarded-ELB-IP"` -} - -type Loadbalancer struct { - Id string `json:"id"` -} - -type SElbListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.HuaweiTags - lb *SLoadbalancer - acl *SElbACL - backendgroup *SElbBackendGroup - - ProtocolPort int `json:"protocol_port"` - Protocol string `json:"protocol"` - Description string `json:"description"` - AdminStateUp bool `json:"admin_state_up"` - Http2Enable bool `json:"http2_enable"` - Loadbalancers []Loadbalancer `json:"loadbalancers"` - TenantId string `json:"tenant_id"` - ProjectId string `json:"project_id"` - ConnectionLimit int `json:"connection_limit"` - DefaultPoolId string `json:"default_pool_id"` - Id string `json:"id"` - Name string `json:"name"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - InsertHeaders InsertHeaders `json:"insert_headers"` - DefaultTlsContainerRef string `json:"default_tls_container_ref"` -} - -func (self *SElbListener) GetId() string { - return self.Id -} - -func (self *SElbListener) GetName() string { - return self.Name -} - -func (self *SElbListener) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbListener) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbListener) Refresh() error { - ilistener, err := self.lb.GetILoadBalancerListenerById(self.GetId()) - if err != nil { - return err - } - - listener := ilistener.(*SElbListener) - listener.lb = self.lb - err = jsonutils.Update(self, listener) - if err != nil { - return err - } - - return nil -} - -func (self *SElbListener) IsEmulated() bool { - return false -} - -func (self *SElbListener) GetProjectId() string { - return self.ProjectId -} - -func (self *SElbListener) GetListenerType() string { - switch self.Protocol { - case "TCP": - return api.LB_LISTENER_TYPE_TCP - case "UDP": - return api.LB_LISTENER_TYPE_UDP - case "HTTP": - return api.LB_LISTENER_TYPE_HTTP - case "TERMINATED_HTTPS": - return api.LB_LISTENER_TYPE_HTTPS - case "HTTPS": - return api.LB_LISTENER_TYPE_HTTPS - default: - return "" - } -} - -func (self *SElbListener) GetListenerPort() int { - return self.ProtocolPort -} - -func (self *SElbListener) GetBackendGroup() (*SElbBackendGroup, error) { - if self.backendgroup == nil { - lbbgId := self.GetBackendGroupId() - if len(lbbgId) > 0 { - lbbg, err := self.lb.GetILoadBalancerBackendGroupById(lbbgId) - if err != nil { - return nil, err - } - - self.backendgroup = lbbg.(*SElbBackendGroup) - } - } - - return self.backendgroup, nil -} - -func (self *SElbListener) GetScheduler() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetScheduler %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - return lbbg.GetScheduler() -} - -func (self *SElbListener) GetAcl() (*SElbACL, error) { - if self.acl != nil { - return self.acl, nil - } - - acls, err := self.lb.region.GetLoadBalancerAcls(self.GetId()) - if err != nil { - return nil, err - } - - if len(acls) == 0 { - return nil, nil - } else { - self.acl = &acls[0] - return &acls[0], nil - } -} - -func (self *SElbListener) GetAclStatus() string { - acl, err := self.GetAcl() - if err != nil { - log.Debugf("GetAclStatus %s", err) - return "" - } - - if acl != nil && acl.EnableWhitelist { - return api.LB_BOOL_ON - } - - return api.LB_BOOL_OFF -} - -func (self *SElbListener) GetAclType() string { - return api.LB_ACL_TYPE_WHITE -} - -func (self *SElbListener) GetAclId() string { - acl, err := self.GetAcl() - if err != nil { - log.Debugf("GetAclStatus %s", err) - return "" - } - - if acl == nil { - return "" - } - - return acl.GetId() -} - -func (self *SElbListener) GetEgressMbps() int { - return 0 -} - -func (self *SElbListener) GetHealthCheck() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheck %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheck %s", err.Error()) - } - - if health != nil { - return api.LB_BOOL_ON - } else { - return api.LB_BOOL_OFF - } -} - -func (self *SElbListener) GetHealthCheckType() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) - } - - if health != nil { - return health.HealthCheckType - } - - return "" -} - -func (self *SElbListener) GetHealthCheckTimeout() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) - } - - if health != nil { - return health.HealthCheckTimeout - } - - return 0 -} - -func (self *SElbListener) GetHealthCheckInterval() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) - } - - if health != nil { - return health.HealthCheckInterval - } - - return 0 -} - -func (self *SElbListener) GetHealthCheckRise() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) - } - - if health != nil { - return health.HealthCheckRise - } else { - return 0 - } -} - -func (self *SElbListener) GetHealthCheckFail() int { - return 0 -} - -func (self *SElbListener) GetHealthCheckReq() string { - return "" -} - -func (self *SElbListener) GetHealthCheckExp() string { - return "" -} - -func (self *SElbListener) GetBackendGroupId() string { - return self.DefaultPoolId -} - -func (self *SElbListener) GetBackendServerPort() int { - return 0 -} - -func (self *SElbListener) GetHealthCheckDomain() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) - } - - if health != nil { - return health.HealthCheckDomain - } - - return "" -} - -func (self *SElbListener) GetHealthCheckURI() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) - } - - if health != nil { - return health.HealthCheckURI - } - - return "" -} - -func (self *SElbListener) GetHealthCheckCode() string { - return "" -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html -func (self *SElbListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - l7policy, err := self.lb.region.CreateLoadBalancerPolicy(self.GetId(), rule) - if err != nil { - return nil, err - } - - l7policy.region = self.lb.region - l7policy.lb = self.lb - l7policy.listener = self - return l7policy, nil -} - -func (self *SElbListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - ret := &SElbListenerPolicy{region: self.lb.region, lb: self.lb, listener: self} - return ret, self.lb.region.lbGet("lbaas/l7policies/"+ruleId, ret) -} - -func (self *SElbListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - ret, err := self.lb.region.GetLoadBalancerPolicies(self.GetId()) - if err != nil { - return nil, err - } - - iret := []cloudprovider.ICloudLoadbalancerListenerRule{} - for i := range ret { - rule := ret[i] - rule.listener = self - rule.lb = self.lb - rule.region = self.lb.region - iret = append(iret, &rule) - } - - return iret, nil -} - -func (self *SElbListener) GetStickySession() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySession %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySession %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySession - } - - return "" -} - -func (self *SElbListener) GetStickySessionType() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySessionType %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySessionType %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySessionType - } - - return "" -} - -func (self *SElbListener) GetStickySessionCookie() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySessionCookie - } - - return "" -} - -func (self *SElbListener) GetStickySessionCookieTimeout() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySessionCookieTimeout - } - - return 0 -} - -func (self *SElbListener) XForwardedForEnabled() bool { - return self.InsertHeaders.XForwardedELBIP -} - -func (self *SElbListener) GzipEnabled() bool { - return false -} - -func (self *SElbListener) GetCertificateId() string { - return self.DefaultTlsContainerRef -} - -func (self *SElbListener) GetTLSCipherPolicy() string { - return "" -} - -func (self *SElbListener) HTTP2Enabled() bool { - return self.Http2Enable -} - -func (self *SElbListener) Start() error { - return nil -} - -func (self *SElbListener) Stop() error { - return cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561544.html -/* -default_pool_id有如下限制: -不能更新为其他监听器的default_pool。 -不能更新为其他监听器的关联的转发策略所使用的pool。 -default_pool_id对应的后端云服务器组的protocol和监听器的protocol有如下关系: -监听器的protocol为TCP时,后端云服务器组的protocol必须为TCP。 -监听器的protocol为UDP时,后端云服务器组的protocol必须为UDP。 -监听器的protocol为HTTP或TERMINATED_HTTPS时,后端云服务器组的protocol必须为HTTP。 -*/ -func (self *SElbListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { - return self.lb.region.UpdateLoadBalancerListener(self.GetId(), listener) -} - -func (self *SElbListener) Delete(ctx context.Context) error { - return self.lb.region.lbDelete("lbaas/listeners/" + self.GetId()) -} - -func (self *SRegion) UpdateLoadBalancerListener(listenerId string, listener *cloudprovider.SLoadbalancerListener) error { - params := map[string]interface{}{ - "name": listener.Name, - "description": listener.Description, - "http2_enable": listener.EnableHTTP2, - "default_pool_id": jsonutils.JSONNull, - } - if len(listener.BackendGroupID) > 0 { - params["default_pool_id"] = listener.BackendGroupID - } - - if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { - params["default_tls_container_ref"] = listener.CertificateID - } - - if listener.XForwardedFor { - params["insert_headers"] = map[string]interface{}{ - "X-Forwarded-ELB-IP": listener.XForwardedFor, - } - } - return self.lbUpdate("elb/listeners/"+listenerId, map[string]interface{}{"listener": params}) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295315.html -func (self *SRegion) GetLoadBalancerPolicies(listenerId string) ([]SElbListenerPolicy, error) { - query := url.Values{} - if len(listenerId) > 0 { - query.Set("listener_id", listenerId) - } - - ret := []SElbListenerPolicy{} - return ret, self.lbList("lbaas/l7policies", query, &ret) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0116649234.html -func (self *SRegion) GetLoadBalancerPolicyRules(policyId string) ([]SElbListenerPolicyRule, error) { - ret := []SElbListenerPolicyRule{} - return ret, self.lbList(fmt.Sprintf("lbaas/l7policies/%s/rules", policyId), url.Values{}, &ret) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html -func (self *SRegion) CreateLoadBalancerPolicy(listenerId string, rule *cloudprovider.SLoadbalancerListenerRule) (*SElbListenerPolicy, error) { - ret := &SElbListenerPolicy{} - params := map[string]interface{}{ - "name": rule.Name, - "listener_id": listenerId, - "action": "REDIRECT_TO_POOL", - "redirect_pool_id": rule.BackendGroupID, - } - err := self.lbCreate("lbaas/l7policies", map[string]interface{}{"l7policy": params}, ret) - if err != nil { - return nil, err - } - if len(rule.Domain) > 0 { - params := map[string]interface{}{ - "type": "HOST_NAME", - "value": rule.Domain, - "compare_type": "EQUAL_TO", - } - err := self.lbCreate(fmt.Sprintf("lbaas/l7policies/%s/rules", ret.GetId()), map[string]interface{}{"rule": params}, nil) - if err != nil { - return ret, err - } - } - - if len(rule.Path) > 0 { - params := map[string]interface{}{ - "type": "PATH", - "value": rule.Path, - "compare_type": "EQUAL_TO", - } - err := self.lbCreate(fmt.Sprintf("lbaas/l7policies/%s/rules", ret.GetId()), map[string]interface{}{"rule": params}, nil) - if err != nil { - return ret, err - } - } - - return ret, nil -} - -func (self *SElbListener) GetClientIdleTimeout() int { - return 0 -} - -func (self *SElbListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/hcs/loadbalancer_listener_rule.go b/pkg/multicloud/hcs/loadbalancer_listener_rule.go deleted file mode 100644 index 65e6d80775..0000000000 --- a/pkg/multicloud/hcs/loadbalancer_listener_rule.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbListenerPolicy struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.HuaweiTags - region *SRegion - lb *SLoadbalancer - listener *SElbListener - - RedirectPoolId string `json:"redirect_pool_id"` - RedirectListenerId *string `json:"redirect_listener_id"` - Description string `json:"description"` - AdminStateUp bool `json:"admin_state_up"` - Rules []Rule `json:"rules"` - TenantId string `json:"tenant_id"` - ProjectId string `json:"project_id"` - ListenerId string `json:"listener_id"` - RedirectURL *string `json:"redirect_url"` - ProvisioningStatus string `json:"provisioning_status"` - Action string `json:"action"` - Position int64 `json:"position"` - Id string `json:"id"` - Name string `json:"name"` -} - -type Rule struct { - Id string `json:"id"` -} - -type SElbListenerPolicyRule struct { - region *SRegion - policy *SElbListenerPolicy - - CompareType string `json:"compare_type"` - ProvisioningStatus string `json:"provisioning_status"` - AdminStateUp bool `json:"admin_state_up"` - TenantId string `json:"tenant_id"` - ProjectId string `json:"project_id"` - Invert bool `json:"invert"` - Value string `json:"value"` - Key interface{} `json:"key"` - Type string `json:"type"` - Id string `json:"id"` -} - -func (self *SElbListenerPolicy) GetId() string { - return self.Id -} - -func (self *SElbListenerPolicy) GetName() string { - return self.Name -} - -func (self *SElbListenerPolicy) GetGlobalId() string { - return self.GetId() -} - -// 负载均衡没有启用禁用操作 -func (self *SElbListenerPolicy) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbListenerPolicy) Refresh() error { - res := "lbaas/l7policies/" + self.Id - ret := &SElbListenerPolicy{} - err := self.lb.region.lbGet(res, ret) - if err != nil { - return err - } - return jsonutils.Update(self, ret) -} - -func (self *SElbListenerPolicy) IsDefault() bool { - return false -} - -func (self *SElbListenerPolicy) IsEmulated() bool { - return false -} - -func (self *SElbListenerPolicy) GetProjectId() string { - return "" -} - -func (self *SElbListenerPolicy) GetRules() ([]SElbListenerPolicyRule, error) { - ret, err := self.region.GetLoadBalancerPolicyRules(self.GetId()) - if err != nil { - return nil, err - } - - for i := range ret { - ret[i].region = self.lb.region - ret[i].policy = self - } - - return ret, nil -} - -func (self *SElbListenerPolicy) GetDomain() string { - rules, err := self.GetRules() - if err != nil { - log.Errorf("loadbalancer rule GetDomain %s", err) - } - - for i := range rules { - if rules[i].Type == "HOST_NAME" { - return rules[i].Value - } - } - - return "" -} - -func (self *SElbListenerPolicy) GetCondition() string { - return "" -} - -func (self *SElbListenerPolicy) GetPath() string { - rules, err := self.GetRules() - if err != nil { - log.Errorf("loadbalancer rule GetPath %s", err) - } - - for i := range rules { - if rules[i].Type == "PATH" { - return rules[i].Value - } - } - - return "" -} - -func (self *SElbListenerPolicy) GetBackendGroupId() string { - return self.RedirectPoolId -} - -func (self *SElbListenerPolicy) Delete(ctx context.Context) error { - return self.region.DeleteLoadBalancerPolicy(self.GetId()) -} - -func (self *SRegion) DeleteLoadBalancerPolicy(policyId string) error { - return self.lbDelete("lbaas/l7policies/" + policyId) -} diff --git a/pkg/multicloud/hcs/monitor.go b/pkg/multicloud/hcs/monitor.go deleted file mode 100644 index b6d690a2d1..0000000000 --- a/pkg/multicloud/hcs/monitor.go +++ /dev/null @@ -1,494 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -type MetricData struct { - Namespace string - MetricName string - Dimensions []struct { - Name string - Value string - } - Datapoints []struct { - Average float64 - Timestamp int64 - } - Unit string -} - -func (self *SHcsClient) monitorPost(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - url := self._url("ces", "V1.0", self.defaultRegion, resource) - return self.request(httputils.POST, url, nil, params) -} - -func (self *SHcsClient) getServerMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - params := map[string]interface{}{ - "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), - "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), - "period": "1", - "filter": "average", - } - metrics := []interface{}{} - namespace, dimesionName, metricNames := "SYS.ECS", "instance_id", []string{ - "cpu_util", - "network_incoming_bytes_aggregate_rate", - "network_outgoing_bytes_aggregate_rate", - "disk_read_bytes_rate", - "disk_write_bytes_rate", - "disk_read_requests_rate", - "disk_write_requests_rate", - } - for _, metricName := range metricNames { - metrics = append(metrics, map[string]interface{}{ - "namespace": namespace, - "metric_name": metricName, - "dimensions": []map[string]string{ - { - "name": dimesionName, - "value": opts.ResourceId, - }, - }, - }) - } - params["metrics"] = metrics - resp, err := self.monitorPost("batch-query-metric-data", params) - if err != nil { - return nil, err - } - metricData := []MetricData{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].MetricName { - case "cpu_util": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_CPU_USAGE - case "network_incoming_bytes_aggregate_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_RX - tags = map[string]string{"net_type": "internet"} - case "network_outgoing_bytes_aggregate_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_TX - tags = map[string]string{"net_type": "internet"} - case "disk_read_bytes_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS - case "disk_write_bytes_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS - case "disk_read_requests_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS - case "disk_write_requests_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - metricValue := cloudprovider.MetricValue{ - Value: value.Average, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHcsClient) getRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - params := map[string]interface{}{ - "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), - "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), - "period": "1", - "filter": "average", - } - metrics := []interface{}{} - namespace, dimesionName, metricNames := "SYS.DCS", "dcs_instance_id", []string{ - "cpu_usage", - "memory_usage", - "instantaneous_input_kbps", - "instantaneous_output_kbps", - "connected_clients", - "instantaneous_ops", - "keys", - "expires", - "used_memory_dataset", - } - for _, metricName := range metricNames { - metrics = append(metrics, map[string]interface{}{ - "namespace": namespace, - "metric_name": metricName, - "dimensions": []map[string]string{ - { - "name": dimesionName, - "value": opts.ResourceId, - }, - }, - }) - } - params["metrics"] = metrics - resp, err := self.monitorPost("batch-query-metric-data", params) - if err != nil { - return nil, err - } - metricData := []MetricData{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].MetricName { - case "cpu_usage": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE - case "memory_usage": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE - case "instantaneous_input_kbps": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX - case "instantaneous_output_kbps": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX - case "connected_clients": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_USED_CONN - case "instantaneous_ops": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_OPT_SES - case "keys": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS - case "expires": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS - case "used_memory_dataset": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - metricValue := cloudprovider.MetricValue{ - Value: value.Average, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHcsClient) getRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - params := map[string]interface{}{ - "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), - "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), - "period": "1", - "filter": "average", - } - metrics := []interface{}{} - namespace, dimesionName, metricNames := "SYS.RDS", "rds_cluster_id", []string{ - "rds001_cpu_util", - "rds002_mem_util", - "rds004_bytes_in", - "rds004_bytes_in", - "rds005_bytes_out", - "rds039_disk_util", - "rds049_disk_read_throughput", - "rds050_disk_write_throughput", - "rds006_conn_count", - "rds008_qps", - "rds009_tps", - "rds013_innodb_reads", - "rds014_innodb_writes", - } - switch opts.Engine { - case api.DBINSTANCE_TYPE_POSTGRESQL: - dimesionName = "postgresql_cluster_id" - case api.DBINSTANCE_TYPE_SQLSERVER: - dimesionName = "rds_cluster_sqlserver_id" - } - - for _, metricName := range metricNames { - metrics = append(metrics, map[string]interface{}{ - "namespace": namespace, - "metric_name": metricName, - "dimensions": []map[string]string{ - { - "name": dimesionName, - "value": opts.ResourceId, - }, - }, - }) - } - params["metrics"] = metrics - resp, err := self.monitorPost("batch-query-metric-data", params) - if err != nil { - return nil, err - } - metricData := []MetricData{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].MetricName { - case "rds001_cpu_util": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_CPU_USAGE - case "rds002_mem_util": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_MEM_USAGE - case "rds004_bytes_in": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX - case "rds005_bytes_out": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX - case "rds039_disk_util": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_USAGE - case "rds049_disk_read_throughput": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_READ_BPS - case "rds050_disk_write_throughput": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_WRITE_BPS - case "rds006_conn_count": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_CONN_COUNT - case "rds008_qps": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_QPS - case "rds009_tps": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_TPS - case "rds013_innodb_reads": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_INNODB_READ_BPS - case "rds014_innodb_writes": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_INNODB_WRITE_BPS - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - metricValue := cloudprovider.MetricValue{ - Value: value.Average, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHcsClient) getBucketMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - params := map[string]interface{}{ - "from": opts.StartTime.UnixMilli(), - "to": opts.EndTime.UnixMilli(), - "period": "1", - "filter": "average", - } - metrics := []interface{}{} - namespace, dimesionName, metricNames := "SYS.OBS", "bucket_name", []string{ - "download_bytes", - "upload_bytes", - "first_byte_latency", - "get_request_count", - "request_count_4xx", - "request_count_5xx", - } - - for _, metricName := range metricNames { - metrics = append(metrics, map[string]interface{}{ - "namespace": namespace, - "metric_name": metricName, - "dimensions": []map[string]string{ - { - "name": dimesionName, - "value": opts.ResourceId, - }, - }, - }) - } - params["metrics"] = metrics - resp, err := self.monitorPost("batch-query-metric-data", params) - if err != nil { - return nil, err - } - metricData := []MetricData{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].MetricName { - case "download_bytes": - ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_TX - case "upload_bytes": - ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_RX - case "first_byte_latency": - ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_LATECY - tags = map[string]string{"request": "get"} - case "get_request_count": - ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT - tags = map[string]string{"request": "get"} - case "request_count_4xx": - ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT - tags = map[string]string{"request": "4xx"} - case "request_count_5xx": - ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT - tags = map[string]string{"request": "5xx"} - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - metricValue := cloudprovider.MetricValue{ - Value: value.Average, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHcsClient) getLoadbalancerMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - params := map[string]interface{}{ - "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), - "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), - "period": "1", - "filter": "average", - } - metrics := []interface{}{} - namespace, dimesionName, metricNames := "SYS.ELB", "lb_instance_id", []string{ - "m7_in_Bps", - "m8_out_Bps", - "mc_l7_http_2xx", - "md_l7_http_3xx", - "me_l7_http_4xx", - "mf_l7_http_5xx", - } - - for _, metricName := range metricNames { - metrics = append(metrics, map[string]interface{}{ - "namespace": namespace, - "metric_name": metricName, - "dimensions": []map[string]string{ - { - "name": dimesionName, - "value": opts.ResourceId, - }, - }, - }) - } - params["metrics"] = metrics - resp, err := self.monitorPost("batch-query-metric-data", params) - if err != nil { - return nil, err - } - metricData := []MetricData{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].MetricName { - case "m7_in_Bps": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_NET_BPS_RX - case "m8_out_Bps": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_NET_BPS_TX - case "mc_l7_http_2xx": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT - tags = map[string]string{"request": "2xx"} - case "md_l7_http_3xx": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT - tags = map[string]string{"request": "3xx"} - case "md_l7_http_4xx": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT - tags = map[string]string{"request": "4xx"} - case "md_l7_http_5xx": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT - tags = map[string]string{"request": "5xx"} - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - metricValue := cloudprovider.MetricValue{ - Value: value.Average, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHcsClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.getServerMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: - return self.getRedisMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_RDS: - return self.getRdsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_BUCKET: - return self.getBucketMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_LB: - return self.getLoadbalancerMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) - } -} diff --git a/pkg/multicloud/hcs/natdtable.go b/pkg/multicloud/hcs/natdtable.go deleted file mode 100644 index 44e4917ad8..0000000000 --- a/pkg/multicloud/hcs/natdtable.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNatDEntry struct { - multicloud.SResourceBase - multicloud.HcsTags - gateway *SNatGateway - - Id string `json:"id"` - NatGatewayId string `json:"nat_gateway_id"` - Protocol string `json:"protocol"` - Status string `json:"status"` - ExternalIP string `json:"floating_ip_address"` - ExternalPort int `json:"external_service_port"` - InternalIP string `json:"private_ip"` - InternalPort int `json:"internal_service_port"` - PortId string `json:"port_id"` - AdminStateUp bool `json:"admin_state_up"` -} - -func (nat *SNatDEntry) GetId() string { - return nat.Id -} - -func (nat *SNatDEntry) GetName() string { - // No name so return id - return nat.GetId() -} - -func (nat *SNatDEntry) GetGlobalId() string { - return nat.GetId() -} - -func (nat *SNatDEntry) GetStatus() string { - return NatResouceStatusTransfer(nat.Status) -} - -func (nat *SNatDEntry) GetIpProtocol() string { - return nat.Protocol -} - -func (nat *SNatDEntry) GetExternalIp() string { - return nat.ExternalIP -} - -func (nat *SNatDEntry) GetExternalPort() int { - return nat.ExternalPort -} - -func (nat *SNatDEntry) GetInternalIp() string { - return nat.InternalIP -} - -func (nat *SNatDEntry) GetInternalPort() int { - return nat.InternalPort -} - -func (nat *SNatDEntry) Delete() error { - return nat.gateway.region.DeleteNatDEntry(nat.GetId()) -} - -// getNatSTable return all snat rules of gateway -func (gateway *SNatGateway) getNatDTable() ([]SNatDEntry, error) { - ret, err := gateway.region.GetNatDTable(gateway.GetId()) - if err != nil { - return nil, err - } - for i := range ret { - ret[i].gateway = gateway - } - return ret, nil -} - -func (self *SRegion) GetNatDTable(natGatewayId string) ([]SNatDEntry, error) { - query := url.Values{} - query.Set("nat_gateway_id", natGatewayId) - ret := []SNatDEntry{} - err := self.list("nat", "v2.0", "dnat_rules", query, &ret) - if err != nil { - return nil, err - } - for i := range ret { - nat := &ret[i] - if len(nat.InternalIP) == 0 { - port, err := self.GetPort(nat.PortId) - if err != nil { - return nil, errors.Wrapf(err, `get port info for transfer to ip of port_id %q error`, nat.PortId) - } - nat.InternalIP = port.FixedIps[0].IpAddress - } - } - return ret, nil -} - -func (self *SRegion) DeleteNatDEntry(entryId string) error { - return self.delete("nat", "v2.0", "dnat_rules/"+entryId) -} - -func (nat *SNatDEntry) Refresh() error { - ret, err := nat.gateway.region.GetNatDEntry(nat.Id) - if err != nil { - return err - } - return jsonutils.Update(nat, ret) -} - -func (self *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayId string) (*SNatDEntry, error) { - params := make(map[string]interface{}) - params["nat_gateway_id"] = gatewayId - params["private_ip"] = rule.InternalIP - params["internal_service_port"] = rule.InternalPort - params["floating_ip_id"] = rule.ExternalIPID - params["external_service_port"] = rule.ExternalPort - params["protocol"] = rule.Protocol - - packParams := map[string]interface{}{ - "dnat_rule": params, - } - ret := &SNatDEntry{} - return ret, self.create("nat", "v2.0", "dnat_rules", packParams, ret) -} - -func (self *SRegion) GetNatDEntry(id string) (*SNatDEntry, error) { - ret := &SNatDEntry{} - return ret, self.get("nat", "v2.0", "dnat_rules/"+id, ret) -} diff --git a/pkg/multicloud/hcs/natgateway.go b/pkg/multicloud/hcs/natgateway.go deleted file mode 100644 index 3b384a42f9..0000000000 --- a/pkg/multicloud/hcs/natgateway.go +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNatGateway struct { - multicloud.SNatGatewayBase - multicloud.HcsTags - region *SRegion - - Id string - Name string - Description string - Spec string - Status string - InternalNetworkId string - CreatedTime string `json:"created_at"` -} - -func (gateway *SNatGateway) GetId() string { - return gateway.Id -} - -func (gateway *SNatGateway) GetName() string { - return gateway.Name -} - -func (gateway *SNatGateway) GetGlobalId() string { - return gateway.GetId() -} - -func (gateway *SNatGateway) GetStatus() string { - return NatResouceStatusTransfer(gateway.Status) -} - -func (self *SNatGateway) Delete() error { - return self.region.DeleteNatGateway(self.Id) -} - -func (self *SNatGateway) Refresh() error { - nat, err := self.region.GetNatGateway(self.Id) - if err != nil { - return errors.Wrapf(err, "GetNatGateway(%s)", self.Id) - } - return jsonutils.Update(self, nat) -} - -func (self *SNatGateway) GetINetworkId() string { - return self.InternalNetworkId -} - -func (gateway *SNatGateway) GetNatSpec() string { - switch gateway.Spec { - case "1": - return api.NAT_SPEC_SMALL - case "2": - return api.NAT_SPEC_MIDDLE - case "3": - return api.NAT_SPEC_LARGE - case "4": - return api.NAT_SPEC_XLARGE - } - return gateway.Spec -} - -func (gateway *SNatGateway) GetDescription() string { - return gateway.Description -} - -func (gateway *SNatGateway) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (gateway *SNatGateway) GetCreatedAt() time.Time { - t, _ := time.Parse("2006-01-02 15:04:05.000000", gateway.CreatedTime) - return t -} - -func (gateway *SNatGateway) GetExpiredAt() time.Time { - return time.Time{} -} - -func (gateway *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { - IEips, err := gateway.region.GetIEips() - if err != nil { - return nil, errors.Wrapf(err, `get all Eips of region %q error`, gateway.region.GetId()) - } - dNatTables, err := gateway.GetINatDTable() - if err != nil { - return nil, errors.Wrapf(err, `get all DNatTable of gateway %q error`, gateway.GetId()) - } - sNatTables, err := gateway.GetINatSTable() - if err != nil { - return nil, errors.Wrapf(err, `get all SNatTable of gateway %q error`, gateway.GetId()) - } - - // Get natIPSet of nat rules - natIPSet := make(map[string]struct{}) - for _, snat := range sNatTables { - natIPSet[snat.GetIP()] = struct{}{} - } - for _, dnat := range dNatTables { - natIPSet[dnat.GetExternalIp()] = struct{}{} - } - - // Add Eip whose GetIpAddr() in natIPSet to ret - ret := make([]cloudprovider.ICloudEIP, 0, 2) - for i := range IEips { - if _, ok := natIPSet[IEips[i].GetIpAddr()]; ok { - ret = append(ret, IEips[i]) - } - } - return ret, nil -} - -func (gateway *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { - dNatTable, err := gateway.getNatDTable() - if err != nil { - return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) - } - ret := make([]cloudprovider.ICloudNatDEntry, len(dNatTable)) - for i := range dNatTable { - ret[i] = &dNatTable[i] - } - return ret, nil -} - -func (gateway *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { - sNatTable, err := gateway.getNatSTable() - if err != nil { - return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) - } - ret := make([]cloudprovider.ICloudNatSEntry, len(sNatTable)) - for i := range sNatTable { - ret[i] = &sNatTable[i] - } - return ret, nil -} - -func (gateway *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { - dnat, err := gateway.region.CreateNatDEntry(rule, gateway.GetId()) - if err != nil { - return nil, err - } - dnat.gateway = gateway - return dnat, nil -} - -func (gateway *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { - snat, err := gateway.region.CreateNatSEntry(rule, gateway.GetId()) - if err != nil { - return nil, err - } - snat.gateway = gateway - return snat, nil -} - -func (gateway *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { - dnat, err := gateway.region.GetNatDEntry(id) - if err != nil { - return nil, err - } - dnat.gateway = gateway - return dnat, nil -} - -func (gateway *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { - snat, err := gateway.region.GetNatSEntry(id) - if err != nil { - return nil, err - } - snat.gateway = gateway - return snat, nil -} - -func (self *SRegion) GetNatGateways(vpcId string) ([]SNatGateway, error) { - query := url.Values{} - if len(vpcId) > 0 { - query.Set("router_id", vpcId) - } - ret := []SNatGateway{} - return ret, self.list("nat", "v2.0", "nat_gateways", query, &ret) -} - -func NatResouceStatusTransfer(status string) string { - // In Huawei Cloud, there are isx resource status of Nat, "ACTIVE", "PENDING_CREATE", - // "PENDING_UPDATE", "PENDING_DELETE", "EIP_FREEZED", "INACTIVE". - switch status { - case "ACTIVE": - return api.NAT_STAUTS_AVAILABLE - case "PENDING_CREATE": - return api.NAT_STATUS_ALLOCATE - case "PENDING_UPDATE", "PENDING_DELETE": - return api.NAT_STATUS_DEPLOYING - default: - return api.NAT_STATUS_UNKNOWN - } -} - -func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) { - ret := &SNatGateway{region: self} - return ret, self.get("nat", "v2.0", "nat_gateways/"+id, ret) -} - -func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { - nat, err := self.region.CreateNatGateway(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateNatGateway") - } - return nat, nil -} - -func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGateway, error) { - spec := "" - switch strings.ToLower(opts.NatSpec) { - case api.NAT_SPEC_SMALL: - spec = "1" - case api.NAT_SPEC_MIDDLE: - spec = "2" - case api.NAT_SPEC_LARGE: - spec = "3" - case api.NAT_SPEC_XLARGE: - spec = "4" - } - params := map[string]interface{}{ - "nat_gateway": map[string]interface{}{ - "name": opts.Name, - "description": opts.Desc, - "router_id": opts.VpcId, - "internal_network_id": opts.NetworkId, - "spec": spec, - }, - } - ret := SNatGateway{region: self} - return &ret, self.create("nat", "v2.0", "nat_gateways", params, &ret) -} - -func (self *SRegion) DeleteNatGateway(id string) error { - return self.delete("nat", "v2.0", "nat_gateways/"+id) -} diff --git a/pkg/multicloud/hcs/natstable.go b/pkg/multicloud/hcs/natstable.go deleted file mode 100644 index 52babbc98e..0000000000 --- a/pkg/multicloud/hcs/natstable.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNatSEntry struct { - multicloud.SResourceBase - multicloud.HuaweiTags - gateway *SNatGateway - - Id string `json:"id"` - NatGatewayId string `json:"nat_gateway_id"` - NetworkId string `json:"network_id"` - SourceCIDR string `json:"cidr"` - Status string `json:"status"` - SNatIP string `json:"floating_ip_address"` - AdminStateUp bool `json:"admin_state_up"` -} - -func (nat *SNatSEntry) GetId() string { - return nat.Id -} - -func (nat *SNatSEntry) GetName() string { - // Snat rule has no name in Huawei Cloud, so return Id - return nat.GetId() -} - -func (nat *SNatSEntry) GetGlobalId() string { - return nat.GetId() -} - -func (nat *SNatSEntry) GetStatus() string { - return NatResouceStatusTransfer(nat.Status) -} - -func (nat *SNatSEntry) GetIP() string { - return nat.SNatIP -} - -func (nat *SNatSEntry) GetSourceCIDR() string { - return nat.SourceCIDR -} - -func (nat *SNatSEntry) GetNetworkId() string { - return nat.NetworkId -} - -func (nat *SNatSEntry) Delete() error { - return nat.gateway.region.DeleteNatSEntry(nat.GetId()) -} - -// getNatSTable return all snat rules of gateway -func (gateway *SNatGateway) getNatSTable() ([]SNatSEntry, error) { - ret, err := gateway.region.GetNatSTable(gateway.GetId()) - if err != nil { - return nil, err - } - for i := range ret { - ret[i].gateway = gateway - } - return ret, nil -} - -func (self *SRegion) GetNatSTable(natGatewayId string) ([]SNatSEntry, error) { - query := url.Values{} - query.Set("nat_gateway_id", natGatewayId) - ret := []SNatSEntry{} - err := self.list("nat", "v2.0", "snat_rules", query, &ret) - if err != nil { - return nil, err - } - for i := range ret { - nat := &ret[i] - if len(nat.SourceCIDR) != 0 { - continue - } - net, err := self.GetNetwork(nat.NetworkId) - if err != nil { - return nil, errors.Wrapf(err, "GetNetwork(%s)", nat.NetworkId) - } - nat.SourceCIDR = net.CIDR - } - return ret, nil -} - -func (self *SRegion) DeleteNatSEntry(entryId string) error { - return self.delete("nat", "v2.0", "snat_rules/"+entryId) -} - -func (nat *SNatSEntry) Refresh() error { - ret, err := nat.gateway.region.GetNatSEntry(nat.Id) - if err != nil { - return err - } - return jsonutils.Update(nat, ret) -} - -func (self *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayId string) (*SNatSEntry, error) { - params := make(map[string]interface{}) - params["nat_gateway_id"] = gatewayId - if len(rule.NetworkID) != 0 { - params["network_id"] = rule.NetworkID - } - if len(rule.SourceCIDR) != 0 { - params["cidr"] = rule.SourceCIDR - } - params["floating_ip_id"] = rule.ExternalIPID - - packParams := map[string]interface{}{ - "snat_rule": params, - } - - ret := &SNatSEntry{} - return ret, self.create("nat", "v2.0", "snat_rules", packParams, ret) -} - -func (self *SRegion) GetNatSEntry(id string) (*SNatSEntry, error) { - ret := &SNatSEntry{} - return ret, self.get("nat", "v2.0", "snat_rules/"+id, ret) -} diff --git a/pkg/multicloud/hcs/network.go b/pkg/multicloud/hcs/network.go deleted file mode 100644 index e390923436..0000000000 --- a/pkg/multicloud/hcs/network.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -/* -Subnets -*/ - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html -type SNetwork struct { - multicloud.SResourceBase - multicloud.HcsTags - wire *SWire - - AvailabilityZone string `json:"availability_zone"` - CIDR string `json:"cidr"` - DHCPEnable bool `json:"dhcp_enable"` - DNSList []string `json:"dnsList"` - GatewayIP string `json:"gateway_ip"` - Id string `json:"id"` - Ipv6Enable bool `json:"ipv6_enable"` - Name string `json:"name"` - NeutronNetworkId string `json:"neutron_network_id"` - NeutronSubnetId string `json:"neutron_subnet_id"` - PrimaryDNS string `json:"primary_dns"` - SecondaryDNS string `json:"secondary_dns"` - Status string `json:"status"` - VpcId string `json:"vpc_id"` -} - -func (self *SNetwork) GetId() string { - return self.Id -} - -func (self *SNetwork) GetName() string { - if len(self.Name) == 0 { - return self.Id - } - return self.Name -} - -func (self *SNetwork) GetGlobalId() string { - return self.Id -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090591.html -func (self *SNetwork) GetStatus() string { - switch self.Status { - case "ACTIVE", "UNKNOWN": - return api.NETWORK_STATUS_AVAILABLE // ? todo: // UNKNOWN - case "ERROR": - return api.NETWORK_STATUS_UNKNOWN - default: - return api.NETWORK_STATUS_UNKNOWN - } -} - -func (self *SNetwork) Refresh() error { - ret, err := self.wire.region.GetNetwork(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, ret) -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - startIp = startIp.StepUp() // 2 - return startIp.String() -} - -func (self *SNetwork) GetIpEnd() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - 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.CIDR) - return pref.MaskLen -} - -func (self *SNetwork) GetGateway() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - return startIp.String() -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetIsPublic() bool { - return true -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) Delete() error { - return self.wire.region.DeleteNetwork(self.Id) -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (self *SRegion) GetNetwork(id string) (*SNetwork, error) { - ret := &SNetwork{} - res := fmt.Sprintf("subnets/%s", id) - return ret, self.vpcGet(res, ret) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090592.html -func (self *SRegion) GetNetwroks(vpcId string) ([]SNetwork, error) { - params := url.Values{} - if len(vpcId) > 0 { - params.Set("vpc_id", vpcId) - } - ret := []SNetwork{} - return ret, self.vpcList("subnets", params, &ret) -} - -func (self *SRegion) DeleteNetwork(id string) error { - res := fmt.Sprintf("subnets/%s", id) - return self.vpcDelete(res) -} - -func (self *SNetwork) GetProjectId() string { - return self.wire.vpc.EnterpriseProjectId -} diff --git a/pkg/multicloud/hcs/object.go b/pkg/multicloud/hcs/object.go deleted file mode 100644 index a58e83af02..0000000000 --- a/pkg/multicloud/hcs/object.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - "net/http" - - "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SObject struct { - bucket *SBucket - - cloudprovider.SBaseCloudObject -} - -func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { - return o.bucket -} - -func (o *SObject) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - obscli, err := o.bucket.region.getOBSClient() - if err != nil { - log.Errorf("o.bucket.region.GetOssClient error %s", err) - return acl - } - input := &obs.GetObjectAclInput{} - input.Bucket = o.bucket.Name - input.Key = o.Key - output, err := obscli.GetObjectAcl(input) - if err != nil { - log.Errorf("GetObjectAcl error: %v", err) - return acl - } - acl = obsAcl2CannedAcl(output.Grants) - return acl -} - -func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { - obscli, err := o.bucket.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "o.bucket.region.getOBSClient") - } - input := &obs.SetObjectAclInput{} - input.Bucket = o.bucket.Name - input.Key = o.Key - input.ACL = obs.AclType(string(aclStr)) - _, err = obscli.SetObjectAcl(input) - if err != nil { - return errors.Wrap(err, "obscli.SetObjectAcl") - } - return nil -} - -func (o *SObject) GetMeta() http.Header { - if o.Meta != nil { - return o.Meta - } - obscli, err := o.bucket.region.getOBSClient() - if err != nil { - log.Errorf("getOBSClient fail %s", err) - return nil - } - input := &obs.GetObjectMetadataInput{} - input.Bucket = o.bucket.Name - input.Key = o.Key - output, err := obscli.GetObjectMetadata(input) - if err != nil { - log.Errorf("obscli.GetObjectMetadata fail %s", err) - return nil - } - meta := http.Header{} - for k, v := range output.Metadata { - meta.Add(k, v) - } - if len(output.ContentType) > 0 { - meta.Add(cloudprovider.META_HEADER_CONTENT_TYPE, output.ContentType) - } - o.Meta = meta - return meta -} - -func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { - return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) -} diff --git a/pkg/multicloud/hcs/port.go b/pkg/multicloud/hcs/port.go deleted file mode 100644 index dee0ea3c49..0000000000 --- a/pkg/multicloud/hcs/port.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SFixedIP struct { - IpAddress string - SubnetId string - NetworkId string -} - -func (fixip *SFixedIP) GetGlobalId() string { - return fixip.IpAddress -} - -func (fixip *SFixedIP) GetIP() string { - return fixip.IpAddress -} - -func (fixip *SFixedIP) GetINetworkId() string { - return fixip.NetworkId -} - -func (fixip *SFixedIP) IsPrimary() bool { - return true -} - -type Port struct { - multicloud.SNetworkInterfaceBase - multicloud.HuaweiTags - region *SRegion - Id string `json:"id"` - Name string `json:"name"` - Status string `json:"status"` - AdminStateUp string `json:"admin_state_up"` - DNSName string `json:"dns_name"` - MACAddress string `json:"mac_address"` - NetworkId string `json:"network_id"` - TenantId string `json:"tenant_id"` - DeviceId string `json:"device_id"` - DeviceOwner string `json:"device_owner"` - BindingVnicType string `json:"binding:vnic_type"` - FixedIps []SFixedIP -} - -func (port *Port) GetName() string { - if len(port.Name) > 0 { - return port.Name - } - return port.Id -} - -func (port *Port) GetId() string { - return port.Id -} - -func (port *Port) GetGlobalId() string { - return port.Id -} - -func (port *Port) GetMacAddress() string { - return port.MACAddress -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html -func (port *Port) GetAssociateType() string { - switch port.DeviceOwner { - case "compute:nova": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER - case "network:router_gateway", "network:router_interface", "network:router_interface_distributed": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_RESERVED - case "network:dhcp": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_DHCP - case "neutron:LOADBALANCERV2": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_LOADBALANCER - case "neutron:VIP_PORT": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_VIP - default: - if strings.HasPrefix(port.DeviceOwner, "compute:") { - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER - } - } - return port.DeviceOwner -} - -func (port *Port) GetAssociateId() string { - return port.DeviceId -} - -func (port *Port) GetStatus() string { - switch port.Status { - case "ACTIVE", "DOWN": - return api.NETWORK_INTERFACE_STATUS_AVAILABLE - case "BUILD": - return api.NETWORK_INTERFACE_STATUS_CREATING - } - return port.Status -} - -func (port *Port) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { - address := []cloudprovider.ICloudInterfaceAddress{} - for i := 0; i < len(port.FixedIps); i++ { - port.FixedIps[i].NetworkId = port.NetworkId - address = append(address, &port.FixedIps[i]) - } - return address, nil -} - -func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { - ports, err := region.GetPorts("") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNetworkInterface{} - for i := 0; i < len(ports); i++ { - if len(ports[i].DeviceId) == 0 || !utils.IsInStringArray(ports[i].DeviceOwner, []string{"compute:CCI", "compute:nova", "neutron:LOADBALANCERV2"}) { - ports[i].region = region - ret = append(ret, &ports[i]) - } - } - return ret, nil -} - -func (self *SRegion) GetPort(id string) (*Port, error) { - port := &Port{} - res := fmt.Sprintf("ports/%s", id) - return port, self.vpcGet(res, port) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html -func (self *SRegion) GetPorts(instanceId string) ([]Port, error) { - ports := []Port{} - params := url.Values{} - if len(instanceId) > 0 { - params.Set("device_id", instanceId) - } - return ports, self.vpcList("ports", params, &ports) -} diff --git a/pkg/multicloud/hcs/project.go b/pkg/multicloud/hcs/project.go deleted file mode 100644 index 53b03039bd..0000000000 --- a/pkg/multicloud/hcs/project.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "strings" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SProject struct { - Id string - Name string - DomainId string - Description bool - Enabled bool - ParentId string - IsDomain bool -} - -func (self *SProject) GetHealthStatus() string { - if self.Enabled { - return api.CLOUD_PROVIDER_HEALTH_NORMAL - } - return api.CLOUD_PROVIDER_HEALTH_SUSPENDED -} - -func (self *SHcsClient) GetProjects() ([]SProject, error) { - if len(self.projects) > 0 { - return self.projects, nil - } - resp, err := self.iamGet("v3/projects", nil) - if err != nil { - return nil, err - } - self.projects = []SProject{} - return self.projects, resp.Unmarshal(&self.projects, "projects") -} - -func (self *SHcsClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - projects, err := self.GetProjects() - if err != nil { - return nil, err - } - - ret := make([]cloudprovider.SSubAccount, 0) - for i := range projects { - project := projects[i] - // name 为MOS的project是华为云内部的一个特殊project。不需要同步到本地 - if strings.ToLower(project.Name) == "mos" { - continue - } - s := cloudprovider.SSubAccount{ - Name: fmt.Sprintf("%s-%s", self.cpcfg.Name, project.Name), - Account: fmt.Sprintf("%s/%s", self.accessKey, project.Id), - HealthStatus: project.GetHealthStatus(), - DefaultProjectId: "0", - } - for j := range self.regions { - region := self.regions[j] - if strings.Contains(project.Name, region.Id) { - s.Desc = region.Locales.ZhCN - break - } - } - ret = append(ret, s) - } - return ret, nil -} - -func (self *SHcsClient) GetProjectById(id string) (*SProject, error) { - projects, err := self.GetProjects() - if err != nil { - return nil, err - } - for i := range projects { - if projects[i].Id == id { - return &projects[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} diff --git a/pkg/multicloud/hcs/provider/doc.go b/pkg/multicloud/hcs/provider/doc.go deleted file mode 100644 index dc40ffd062..0000000000 --- a/pkg/multicloud/hcs/provider/doc.go +++ /dev/null @@ -1 +0,0 @@ -package provider // import "yunion.io/x/onecloud/pkg/multicloud/hcs/provider" diff --git a/pkg/multicloud/hcs/provider/provider.go b/pkg/multicloud/hcs/provider/provider.go deleted file mode 100644 index 1ceff245aa..0000000000 --- a/pkg/multicloud/hcs/provider/provider.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/hcs" -) - -type SHcsProviderFactory struct { - cloudprovider.SPrivateCloudBaseProviderFactory -} - -func (self *SHcsProviderFactory) GetId() string { - return hcs.CLOUD_PROVIDER_HCS -} - -func (self *SHcsProviderFactory) GetName() string { - return hcs.CLOUD_PROVIDER_HCS_CN -} - -func (self *SHcsProviderFactory) IsCloudeventRegional() bool { - return true -} - -func (self *SHcsProviderFactory) GetMaxCloudEventSyncDays() int { - return 7 -} - -func (self *SHcsProviderFactory) GetMaxCloudEventKeepDays() int { - return 7 -} - -func (factory *SHcsProviderFactory) IsSupportModifyRouteTable() bool { - return true -} - -func (factory *SHcsProviderFactory) IsSupportSAMLAuth() bool { - return false -} - -func (self *SHcsProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - if len(input.AuthUrl) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "auth_url") - } - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - output.AccessUrl = input.AuthUrl - return output, nil -} - -func (self *SHcsProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func parseAccount(account string) (accessKey string, projectId string) { - segs := strings.Split(account, "/") - if len(segs) == 2 { - accessKey = segs[0] - projectId = segs[1] - } else { - accessKey = account - projectId = "" - } - return -} - -func (self *SHcsProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - accessKey, projectId := parseAccount(cfg.Account) - client, err := hcs.NewHcsClient( - hcs.NewHcsConfig( - accessKey, cfg.Secret, projectId, cfg.URL, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SHcsProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SHcsProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - accessKey, projectId := parseAccount(info.Account) - return map[string]string{ - "HCS_AUTH_URL": info.Url, - "HCS_ACCESS_KEY": accessKey, - "HCS_SECRET": info.Secret, - "HCS_PROJECT_ID": projectId, - }, nil -} - -func init() { - factory := SHcsProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SHcsProvider struct { - cloudprovider.SBaseProvider - client *hcs.SHcsClient -} - -func (self *SHcsProvider) GetVersion() string { - return "" -} - -func (self *SHcsProvider) GetSysInfo() (jsonutils.JSONObject, error) { - regions := self.client.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") - info.Add(jsonutils.NewString(hcs.HCS_API_VERSION), "api_version") - return info, nil -} - -func (self *SHcsProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SHcsProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - region, err := self.client.GetRegion(id) - if err != nil { - return nil, err - } - return region, nil -} - -func (self *SHcsProvider) GetBalance() (float64, string, error) { - return 0, api.CLOUD_PROVIDER_HEALTH_NORMAL, nil -} - -func (self *SHcsProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SHcsProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SHcsProvider) GetCloudRegionExternalIdPrefix() string { - return self.client.GetCloudRegionExternalIdPrefix() -} - -func (self *SHcsProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return []cloudprovider.ICloudProject{}, nil -} - -func (self *SHcsProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SHcsProvider) GetStorageClasses(regionId string) []string { - return []string{ - "STANDARD", "WARM", "COLD", - } -} - -func (self *SHcsProvider) GetBucketCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLAuthRead), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SHcsProvider) GetObjectCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLAuthRead), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SHcsProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} diff --git a/pkg/multicloud/hcs/redis.go b/pkg/multicloud/hcs/redis.go deleted file mode 100644 index a6022870b6..0000000000 --- a/pkg/multicloud/hcs/redis.go +++ /dev/null @@ -1,608 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html -type SElasticcache struct { - multicloud.SElasticcacheBase - multicloud.HcsTags - - region *SRegion - - Name string `json:"name"` - Engine string `json:"engine"` - CapacityGB int `json:"capacity"` - IP string `json:"ip"` - DomainName string `json:"domainName"` - Port int `json:"port"` - Status string `json:"status"` - Libos bool `json:"libos"` - Description string `json:"description"` - Task string `json:"task"` - MaxMemoryMB int `json:"max_memory"` - UsedMemoryMB int `json:"used_memory"` - InstanceId string `json:"instance_id"` - ResourceSpecCode string `json:"resource_spec_code"` - EngineVersion string `json:"engine_version"` - InternalVersion string `json:"internal_version"` - ChargingMode int `json:"charging_mode"` - CapacityMinor string `json:"capacity_minor"` - VpcId string `json:"vpc_id"` - VpcName string `json:"vpc_name"` - TaskStatus string `json:"task_status"` - CreatedAt string `json:"created_at"` - ErrorCode string `json:"error_code"` - UserId string `json:"user_id"` - UserName string `json:"user_name"` - MaintainBegin string `json:"maintain_begin"` - MaintainEnd string `json:"maintain_end"` - NoPasswordAccess string `json:"no_password_access"` - AccessUser string `json:"access_user"` - EnablePublicip bool `json:"enable_publicip"` - PublicipId string `json:"publicip_id"` - PublicipAddress string `json:"publicip_address"` - EnableSSL bool `json:"enable_ssl"` - ServiceUpgrade bool `json:"service_upgrade"` - ServiceTaskId string `json:"service_task_id"` - IsFree string `json:"is_free"` - EnterpriseProjectId string `json:"enterprise_project_id"` - AvailableZones []string `json:"available_zones"` - SubnetId string `json:"subnet_id"` - SecurityGroupId string `json:"security_group_id"` - BackendAddrs []string `json:"backend_addrs"` - ProductId string `json:"product_id"` - SecurityGroupName string `json:"security_group_name"` - SubnetName string `json:"subnet_name"` - OrderId string `json:"order_id"` - SubnetCIdR string `json:"subnet_cidr"` - InstanceBackupPolicy string `json:"instance_backup_policy"` - EnterpriseProjectName string `json:"enterprise_project_name"` -} - -func (self *SElasticcache) GetId() string { - return self.InstanceId -} - -func (self *SElasticcache) GetName() string { - return self.Name -} - -func (self *SElasticcache) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcache) GetProjectId() string { - return self.EnterpriseProjectId -} - -func (self *SElasticcache) Refresh() error { - cache, err := self.region.GetElasticCache(self.GetId()) - if err != nil { - return errors.Wrap(err, "Elasticcache.Refresh.GetElasticCache") - } - - err = jsonutils.Update(self, cache) - if err != nil { - return errors.Wrap(err, "Elasticcache.Refresh.Update") - } - - return nil -} - -func (self *SElasticcache) GetStatus() string { - switch self.Status { - case "RUNNING": - return api.ELASTIC_CACHE_STATUS_RUNNING - case "CREATING": - return api.ELASTIC_CACHE_STATUS_DEPLOYING - case "CREATEFAILED": - return api.ELASTIC_CACHE_STATUS_CREATE_FAILED - case "ERROR": - return api.ELASTIC_CACHE_STATUS_ERROR - case "RESTARTING": - return api.ELASTIC_CACHE_STATUS_RESTARTING - case "FROZEN": - return api.ELASTIC_CACHE_STATUS_UNAVAILABLE - case "EXTENDING": - return api.ELASTIC_CACHE_STATUS_CHANGING - case "RESTORING": - return api.ELASTIC_CACHE_STATUS_TRANSFORMING // ? - case "FLUSHING": - return api.ELASTIC_CACHE_STATUS_FLUSHING - } - - return "" -} - -func (self *SElasticcache) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SElasticcache) GetCreatedAt() time.Time { - var createtime time.Time - if len(self.CreatedAt) > 0 { - createtime, _ = time.Parse("2006-01-02T15:04:05.000Z", self.CreatedAt) - } - - return createtime -} - -func (self *SElasticcache) GetInstanceType() string { - return self.ResourceSpecCode -} - -func (self *SElasticcache) GetCapacityMB() int { - return self.CapacityGB * 1024 -} - -func (self *SElasticcache) GetArchType() string { - if strings.Contains(self.ResourceSpecCode, "single") { - return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE - } - if strings.Contains(self.ResourceSpecCode, "ha") { - return api.ELASTIC_CACHE_ARCH_TYPE_MASTER - } - if strings.Contains(self.ResourceSpecCode, "cluster") { - return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER - } - if strings.Contains(self.ResourceSpecCode, "proxy") { - return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER - } - return "" -} - -func (self *SElasticcache) GetNodeType() string { - // single(单副本) | double(双副本) - if strings.Contains(self.ResourceSpecCode, "single") { - return "single" - } - return "double" -} - -func (self *SElasticcache) GetEngine() string { - return self.Engine -} - -func (self *SElasticcache) GetEngineVersion() string { - return self.EngineVersion -} - -func (self *SElasticcache) GetVpcId() string { - return self.VpcId -} - -func (self *SElasticcache) GetZoneId() string { - if len(self.AvailableZones) > 0 { - zone, err := self.region.GetZoneById(self.AvailableZones[0]) - if err != nil { - log.Errorf("elasticcache.GetZoneId %s", err) - return "" - } - return zone.GetGlobalId() - } - return "" -} - -func (self *SElasticcache) GetNetworkType() string { - return api.LB_NETWORK_TYPE_VPC -} - -func (self *SElasticcache) GetNetworkId() string { - return self.SubnetId -} - -func (self *SElasticcache) GetPrivateDNS() string { - return self.DomainName -} - -func (self *SElasticcache) GetPrivateIpAddr() string { - return self.IP -} - -func (self *SElasticcache) GetPrivateConnectPort() int { - return self.Port -} - -func (self *SElasticcache) GetPublicDNS() string { - return self.PublicipAddress -} - -func (self *SElasticcache) GetPublicIpAddr() string { - return self.PublicipAddress -} - -func (self *SElasticcache) GetPublicConnectPort() int { - return self.Port -} - -func (self *SElasticcache) GetMaintainStartTime() string { - return self.MaintainBegin -} - -func (self *SElasticcache) GetMaintainEndTime() string { - return self.MaintainEnd -} - -func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { - iaccounts := []cloudprovider.ICloudElasticcacheAccount{} - iaccount := &SElasticcacheAccount{cacheDB: self} - iaccounts = append(iaccounts, iaccount) - return iaccounts, nil -} - -func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { - // 华为云使用安全组做访问控制。目前未支持 - return []cloudprovider.ICloudElasticcacheAcl{}, nil -} - -func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { - start := self.GetCreatedAt().Format("20060102150405") - end := time.Now().Format("20060102150405") - backups, err := self.region.GetElasticCacheBackups(self.GetId(), start, end) - if err != nil { - return nil, err - } - - ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) - for i := range backups { - backups[i].cacheDB = self - ibackups[i] = &backups[i] - } - - return ibackups, nil -} - -func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { - parameters, err := self.region.GetElasticCacheParameters(self.GetId()) - if err != nil { - return nil, err - } - - iparameters := make([]cloudprovider.ICloudElasticcacheParameter, len(parameters)) - for i := range parameters { - parameters[i].cacheDB = self - iparameters[i] = ¶meters[i] - } - - return iparameters, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html -func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) { - params := url.Values{} - params.Set("beginTime", startTime) - params.Set("endTime", endTime) - res := fmt.Sprintf("instances/%s/backups", instanceId) - ret := []SElasticcacheBackup{} - return ret, self.redisList(res, params, &ret) -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html -func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { - params := url.Values{} - res := fmt.Sprintf("instances/%s/configs", instanceId) - ret := []SElasticcacheParameter{} - return ret, self.redisList(res, params, &ret) -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423044.html -func (self *SRegion) GetElasticCaches() ([]SElasticcache, error) { - params := url.Values{} - ret := []SElasticcache{} - return ret, self.redisList("instances", params, &ret) -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html -func (self *SRegion) GetElasticCache(instanceId string) (*SElasticcache, error) { - cache := &SElasticcache{region: self} - res := fmt.Sprintf("instances/%s", instanceId) - return cache, self.redisGet(res, cache) -} - -func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { - ec, err := self.GetElasticCache(id) - if err != nil { - return nil, errors.Wrapf(err, "GetElasticCache(%s)", id) - } - return ec, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423047.html -func (self *SRegion) zoneNameToDcsZoneIds(zoneIds []string) ([]string, error) { - type Z struct { - Id string `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - Port string `json:"port"` - ResourceAvailability string `json:"resource_availability"` - } - - rs := []Z{} - err := self.redisList("availableZones", url.Values{}, &rs) - if err != nil { - return nil, errors.Wrapf(err, "availableZones") - } - zoneMap := map[string]string{} - for i := range rs { - if rs[i].ResourceAvailability == "true" { - zoneMap[rs[i].Code] = rs[i].Id - } - } - - ret := []string{} - for _, zone := range zoneIds { - if id, ok := zoneMap[zone]; ok { - ret = append(ret, id) - } else { - return nil, errors.Wrap(fmt.Errorf("zone %s not found or not available", zone), "region.zoneNameToDcsZoneIds") - } - } - - return ret, nil -} - -func (self *SRegion) CreateElasticcache(opts *cloudprovider.SCloudElasticCacheInput) (*SElasticcache, error) { - params := map[string]interface{}{ - "name": opts.InstanceName, - "engine": opts.Engine, - "engine_version": opts.EngineVersion, - "capacity": opts.CapacityGB, - "vpc_id": opts.VpcId, - "subnet_id": opts.NetworkId, - "product_id": opts.InstanceType, - "spec_code": opts.InstanceType, - "available_zones": opts.ZoneIds, - "no_password_access": true, - "enable_publicip": false, - } - if len(opts.SecurityGroupIds) > 0 { - params["security_group_id"] = opts.SecurityGroupIds[0] - } - - if len(opts.ProjectId) > 0 { - params["enterprise_project_id"] = opts.ProjectId - } - - if len(opts.Password) > 0 { - params["no_password_access"] = false - params["password"] = opts.Password - if opts.Engine == "Memcache" { - params["access_user"] = opts.UserName - } - } - - if len(opts.EipId) > 0 { - params["enable_publicip"] = true - params["publicip_id"] = opts.EipId - } - - if len(opts.PrivateIpAddress) > 0 { - params["private_ip"] = opts.PrivateIpAddress - } - - if len(opts.MaintainBegin) > 0 { - params["maintain_begin"] = opts.MaintainBegin - params["maintain_end"] = opts.MaintainEnd - } - - ret := struct { - InstanceId string - }{} - err := self.redisCreate("instances", params, &ret) - if err != nil { - return nil, errors.Wrap(err, "redisCreate") - } - return self.GetElasticCache(ret.InstanceId) -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423019.html -func (self *SRegion) CreateIElasticcaches(opts *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { - cache, err := self.CreateElasticcache(opts) - if err != nil { - return nil, err - } - return cache, nil -} - -func (self *SElasticcache) Restart() error { - return nil -} - -func (self *SElasticcache) Delete() error { - return self.region.DeleteElasticcache(self.InstanceId) -} - -func (self *SRegion) DeleteElasticcache(id string) error { - res := fmt.Sprintf("instances/%s", id) - return self.redisDelete(res) -} - -func (self *SElasticcache) ChangeInstanceSpec(spec string) error { - return cloudprovider.ErrNotImplemented -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html -func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { - return cloudprovider.ErrNotImplemented -} - -// https://support.huaweicloud.com/usermanual-dcs/dcs-zh-ug-180314001.html -// 目前只有Redis3.0版本密码模式的实例支持通过公网访问Redis实例,其他版本暂不支持公网访问。 -// todo: 目前没找到api -func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -// todo: 目前没找到api -func (self *SElasticcache) ReleasePublicConnection() error { - return cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { - return nil, cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html - -func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423029.html -func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { - return cloudprovider.ErrNotImplemented -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423033.html -func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func backupPeriodTrans(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) *jsonutils.JSONArray { - segs := strings.Split(config.PreferredBackupPeriod, ",") - ret := jsonutils.NewArray() - for _, seg := range segs { - switch seg { - case "Monday": - ret.Add(jsonutils.NewString("1")) - case "Tuesday": - ret.Add(jsonutils.NewString("2")) - case "Wednesday": - ret.Add(jsonutils.NewString("3")) - case "Thursday": - ret.Add(jsonutils.NewString("4")) - case "Friday": - ret.Add(jsonutils.NewString("5")) - case "Saturday": - ret.Add(jsonutils.NewString("6")) - case "Sunday": - ret.Add(jsonutils.NewString("7")) - } - } - - return ret -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html -func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { - return nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html -// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 -func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { - return nil -} - -// SElasticcacheAccount => ResetPassword -func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool, password string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetAuthMode() string { - switch self.NoPasswordAccess { - case "true": - return "off" - default: - return "on" - } -} - -func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { - accounts, err := self.GetICloudElasticcacheAccounts() - if err != nil { - return nil, errors.Wrap(err, "Elasticcache.GetICloudElasticcacheAccount.Accounts") - } - - for i := range accounts { - account := accounts[i] - if account.GetGlobalId() == accountId { - return account, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { - backups, err := self.GetICloudElasticcacheBackups() - if err != nil { - return nil, err - } - - for _, backup := range backups { - if backup.GetId() == backupId { - return backup, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (instance *SElasticcache) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { - return errors.Wrap(cloudprovider.ErrNotSupported, "UpdateSecurityGroups") -} - -func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) SetAutoRenew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { - caches, err := self.GetElasticCaches() - if err != nil { - return nil, err - } - - ret := []cloudprovider.ICloudElasticcache{} - for i := range caches { - caches[i].region = self - ret = append(ret, &caches[i]) - } - - return ret, nil -} diff --git a/pkg/multicloud/hcs/region.go b/pkg/multicloud/hcs/region.go deleted file mode 100644 index 7958bd3f65..0000000000 --- a/pkg/multicloud/hcs/region.go +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - "strings" - - "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - multicloud.HcsTags - multicloud.SRegion - multicloud.SRegionEipBase - multicloud.SRegionOssBase - multicloud.SRegionLbBase - multicloud.SRegionVpcBase - multicloud.SRegionZoneBase - multicloud.SRegionSecurityGroupBase - - obsClient *obs.ObsClient // 对象存储client.请勿直接引用。 - - client *SHcsClient - - Id string - CloudInfras []string - Description string - Locales struct { - EnUS string `json:"en-us"` - ZhCN string `json:"zh-cn"` - } - ParentRegionId string -} - -func (self *SRegion) GetClient() *SHcsClient { - return self.client -} - -func (self *SRegion) GetId() string { - return self.Id -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_HCS, self.Id) -} - -func (self *SRegion) GetName() string { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HCS_CN, self.Locales.ZhCN) -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HCS_EN, self.Locales.EnUS) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SRegion) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SRegion) GetCloudEnv() string { - return "" -} - -func (self *SRegion) GetProvider() string { - return CLOUD_PROVIDER_HCS -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) ecsList(resource string, query url.Values, retVal interface{}) error { - return self.client.ecsList(self.Id, resource, query, retVal) -} - -func (self *SRegion) ecsGet(resource string, retVal interface{}) error { - return self.client.ecsGet(self.Id, resource, retVal) -} - -func (self *SRegion) ecsDelete(resource string) error { - return self.client.ecsDelete(self.Id, resource) -} - -func (self *SRegion) ecsCreate(resource string, body map[string]interface{}, retVal interface{}) error { - return self.client.ecsCreate(self.Id, resource, body, retVal) -} - -func (self *SRegion) ecsPerform(resource, action string, params map[string]interface{}, retVal interface{}) error { - return self.client.ecsPerform(self.Id, resource, action, params, retVal) -} - -func (region *SRegion) rdsList(resource string, query url.Values, retVal interface{}) error { - return region.client.rdsList(region.Id, resource, query, retVal) -} - -func (region *SRegion) rdsGet(resource string, retVal interface{}) error { - return region.client.rdsGet(region.Id, resource, retVal) -} - -func (region *SRegion) rdsDelete(resource string) error { - return region.client.rdsDelete(region.Id, resource) -} - -func (region *SRegion) rdsCreate(resource string, body map[string]interface{}, retVal interface{}) error { - return region.client.rdsCreate(region.Id, resource, body, retVal) -} - -func (self *SRegion) rdsPerform(resource, action string, params map[string]interface{}, retVal interface{}) error { - return self.client.rdsPerform(self.Id, resource, action, params, retVal) -} - -func (region *SRegion) rdsJobGet(resource string, query url.Values, retVal interface{}) error { - return region.client.rdsJobGet(region.Id, resource, query, retVal) -} - -func (region *SRegion) rdsDBPrivilegesDelete(resource string, params map[string]interface{}) error { - return region.client.rdsDBPrivvilegesDelete(region.Id, resource, params) -} - -func (region *SRegion) rdsDBPrivilegesGrant(resource string, params map[string]interface{}, retVal interface{}) error { - return region.client.rdsDBPrivilegesGrant(region.Id, resource, params, retVal) -} - -func (self *SRegion) perform(product, version, resource, action string, params map[string]interface{}, retVal interface{}) error { - return self.client.perform(product, version, self.Id, resource, action, params, retVal) -} - -func (self *SRegion) create(product, version, resource string, body map[string]interface{}, retVal interface{}) error { - return self.client.create(product, version, self.Id, resource, body, retVal) -} - -func (self *SRegion) delete(product, version, resource string) error { - return self.client.delete(product, version, self.Id, resource) -} - -func (self *SRegion) list(product, version, resource string, query url.Values, retVal interface{}) error { - return self.client.list(product, version, self.Id, resource, query, retVal) -} - -func (self *SRegion) get(product, version, resource string, retVal interface{}) error { - return self.client.get(product, version, self.Id, resource, retVal) -} -func (self *SRegion) update(product, version, resource string, params map[string]interface{}) error { - return self.client.update(product, version, self.Id, resource, params) -} - -func (self *SRegion) evsList(resource string, query url.Values, retVal interface{}) error { - return self.client.evsList(self.Id, resource, query, retVal) -} - -func (self *SRegion) evsGet(resource string, retVal interface{}) error { - return self.client.evsGet(self.Id, resource, retVal) -} - -func (self *SRegion) evsDelete(resource string) error { - return self.client.evsDelete(self.Id, resource) -} - -func (self *SRegion) evsPerform(resource, action string, params map[string]interface{}) error { - return self.client.evsPerform(self.Id, resource, action, params) -} - -func (self *SRegion) evsCreate(resource string, body map[string]interface{}, retVal interface{}) error { - return self.client.evsCreate(self.Id, resource, body, retVal) -} - -func (self *SRegion) vpcList(resource string, query url.Values, retVal interface{}) error { - return self.client.vpcList(self.Id, resource, query, retVal) -} - -func (self *SRegion) vpcCreate(resource string, body map[string]interface{}, retVal interface{}) error { - return self.client.vpcCreate(self.Id, resource, body, retVal) -} - -func (self *SRegion) vpcGet(resource string, retVal interface{}) error { - return self.client.vpcGet(self.Id, resource, retVal) -} - -func (self *SRegion) vpcUpdate(resource string, params map[string]interface{}) error { - return self.client.vpcUpdate(self.Id, resource, params) -} - -func (self *SRegion) vpcDelete(resource string) error { - return self.client.vpcDelete(self.Id, resource) -} - -func (self *SRegion) imsList(resource string, query url.Values, retVal interface{}) error { - return self.client.imsList(self.Id, resource, query, retVal) -} - -func (self *SRegion) imsCreate(resource string, body map[string]interface{}, retVal interface{}) error { - return self.client.imsCreate(self.Id, resource, body, retVal) -} - -func (self *SRegion) imsGet(resource string, retVal interface{}) error { - return self.client.imsGet(self.Id, resource, retVal) -} - -func (self *SRegion) imsUpdate(resource string, params map[string]interface{}) error { - return self.client.imsUpdate(self.Id, resource, params) -} - -func (self *SRegion) imsDelete(resource string) error { - return self.client.imsDelete(self.Id, resource) -} - -func (self *SRegion) imsPerform(resource, action string, params map[string]interface{}, retVal interface{}) error { - return self.client.imsPerform(self.Id, resource, action, params, retVal) -} - -func (self *SRegion) redisList(resource string, query url.Values, retVal interface{}) error { - return self.client.dcsList(self.Id, resource, query, retVal) -} - -func (self *SRegion) redisCreate(resource string, body map[string]interface{}, retVal interface{}) error { - return self.client.dcsCreate(self.Id, resource, body, retVal) -} - -func (self *SRegion) redisGet(resource string, retVal interface{}) error { - return self.client.dcsGet(self.Id, resource, retVal) -} - -func (self *SRegion) redisUpdate(resource string, params map[string]interface{}) error { - return self.client.dcsUpdate(self.Id, resource, params) -} - -func (self *SRegion) redisDelete(resource string) error { - return self.client.dcsDelete(self.Id, resource) -} - -func (self *SRegion) redisPerform(resource, action string, params map[string]interface{}, retVal interface{}) error { - return self.client.dcsPerform(self.Id, resource, action, params, retVal) -} - -func (self *SRegion) GetICloudSku(skuId string) (cloudprovider.ICloudSku, error) { - sku, err := self.GetchInstanceType(skuId) - if err != nil { - return nil, err - } - return sku, nil -} - -func (self *SRegion) getOBSClient() (*obs.ObsClient, error) { - if self.obsClient == nil { - obsClient, err := self.client.getOBSClient(self.GetId()) - if err != nil { - return nil, err - } - self.obsClient = obsClient - } - return self.obsClient, nil -} - -func (self *SRegion) HeadBucket(name string) (*obs.BaseModel, error) { - obsClient, err := self.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "region.getOBSClient") - } - return obsClient.HeadBucket(name) -} - -func (self *SRegion) getOBSEndpoint() string { - return self.client.getOBSEndpoint(self.GetId()) -} - -func str2StorageClass(storageClassStr string) (obs.StorageClassType, error) { - if strings.EqualFold(storageClassStr, string(obs.StorageClassStandard)) { - return obs.StorageClassStandard, nil - } else if strings.EqualFold(storageClassStr, string(obs.StorageClassWarm)) { - return obs.StorageClassWarm, nil - } else if strings.EqualFold(storageClassStr, string(obs.StorageClassCold)) { - return obs.StorageClassCold, nil - } else { - return obs.StorageClassStandard, errors.Error("unsupported storageClass") - } -} - -func (self *SRegion) GetBuckets() ([]SBucket, error) { - buckets, err := self.client.GetBuckets() - if err != nil { - return nil, err - } - ret := []SBucket{} - for i := range buckets { - if buckets[i].region.GetGlobalId() == self.GetGlobalId() { - ret = append(ret, buckets[i]) - } - } - return ret, nil -} - -func (self *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - buckets, err := self.GetBuckets() - if err != nil { - return nil, errors.Wrap(err, "GetBuckets") - } - ret := make([]cloudprovider.ICloudBucket, 0) - for i := range buckets { - ret = append(ret, &buckets[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/hcs/routetables.go b/pkg/multicloud/hcs/routetables.go deleted file mode 100644 index b7be1a328c..0000000000 --- a/pkg/multicloud/hcs/routetables.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var hoptypes = map[string]string{ - api.NEXT_HOP_TYPE_VPCPEERING: "peering", - api.NEXT_HOP_TYPE_INSTANCE: "ecs", - api.NEXT_HOP_TYPE_NAT: "nat", - api.NEXT_HOP_TYPE_HAVIP: "vip", - api.NEXT_HOP_TYPE_NETWORK: "eni", - api.NEXT_HOP_TYPE_INTERVPCNETWORK: "cc", -} - -type SRoute struct { - multicloud.SResourceBase - multicloud.HuaweiTags - - Type string `json:"type"` - Destination string `json:"destination"` - Nexthop string `json:"nexthop"` - Description string `json:"description,omitempty"` -} - -func (self *SRoute) GetCidr() string { - return self.Destination -} - -func (self *SRoute) GetGlobalId() string { - return self.GetId() -} - -func (self *SRoute) GetId() string { - return fmt.Sprintf("%s:%s:%s", self.Type, self.Nexthop, self.Destination) -} - -func (self *SRoute) GetName() string { - return "" -} - -func (route *SRoute) GetStatus() string { - return api.ROUTE_ENTRY_STATUS_AVAILIABLE -} - -func (route *SRoute) GetType() string { - if route.Type != "local" { - return api.ROUTE_ENTRY_TYPE_CUSTOM - } - return api.ROUTE_ENTRY_TYPE_SYSTEM -} - -func (self *SRoute) GetNextHopType() string { - for k, v := range hoptypes { - if v == self.Type { - return k - } - } - return self.Type -} - -type Subnet struct { - Id string `json:"id"` -} - -type SRouteTable struct { - multicloud.SResourceBase - multicloud.HuaweiTags - vpc *SVpc - - Id string `json:"id"` - Name string `json:"name"` - Routes []SRoute `json:"routes"` - Subnets []Subnet `json:"subnets"` - VpcId string `json:"vpc_id"` - Default bool `json:"default"` - TenantId string `json:"tenant_id"` -} - -func (self *SRouteTable) GetDescription() string { - return "" -} - -func (self *SRouteTable) GetGlobalId() string { - return self.Id -} - -func (self *SRouteTable) GetId() string { - return self.Id -} - -func (self *SRouteTable) GetName() string { - return self.Name -} - -func (self *SRouteTable) GetRegionId() string { - return self.vpc.region.GetId() -} - -func (self *SRouteTable) GetVpcId() string { - return self.VpcId -} - -func (self *SRouteTable) GetType() cloudprovider.RouteTableType { - return cloudprovider.RouteTableTypeSystem -} - -func (self *SRouteTable) GetStatus() string { - return api.ROUTE_TABLE_AVAILABLE -} - -func (self *SRouteTable) Refresh() error { - rtb, err := self.vpc.region.GetRouteTable(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, rtb) -} - -func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { - if len(self.Routes) == 0 { - err := self.Refresh() - if err != nil { - return nil, err - } - } - ret := []cloudprovider.ICloudRoute{} - for i := range self.Routes { - ret = append(ret, &self.Routes[i]) - } - return ret, nil -} - -func (self *SRoute) GetNextHop() string { - return self.Nexthop -} - -func (self *SRegion) GetRouteTables(vpcId string) ([]SRouteTable, error) { - params := url.Values{} - if len(vpcId) > 0 { - params.Set("vpc_id", vpcId) - } - rtbs := []SRouteTable{} - return rtbs, self.list("vpc", "v2.0", "vpc/routes", params, &rtbs) -} - -func (self *SRegion) GetRouteTable(id string) (*SRouteTable, error) { - tb := &SRouteTable{} - return tb, self.get("vpc", "v2.0", "vpc/routes/"+id, tb) -} - -func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { - routeType, ok := hoptypes[route.NextHopType] - if !ok { - return errors.Wrapf(cloudprovider.ErrNotSupported, route.NextHopType) - } - params := map[string]interface{}{ - "routes": map[string]interface{}{ - "add": []map[string]interface{}{ - { - "type": routeType, - "destination": route.Destination, - "nexthop": route.NextHop, - }, - }, - }, - } - return self.vpc.region.create("vpc", "v2.0", "vpc/routes", params, nil) -} - -func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { - if len(route.RouteId) > 0 { - return self.vpc.region.delete("vpc", "v2.0", "vpc/routes/"+route.RouteId) - } - return fmt.Errorf("missing route id") -} - -func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { - err := self.RemoveRoute(route) - if err != nil { - return errors.Wrap(err, "self.RemoveRoute(route)") - } - err = self.CreateRoute(route) - if err != nil { - return errors.Wrap(err, "self.CreateRoute(route)") - } - return nil -} - -func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { - return []cloudprovider.RouteTableAssociation{} -} diff --git a/pkg/multicloud/hcs/securitygroup.go b/pkg/multicloud/hcs/securitygroup.go deleted file mode 100644 index 12d098ba8e..0000000000 --- a/pkg/multicloud/hcs/securitygroup.go +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SecurityGroupRule struct { - Direction string `json:"direction"` - Ethertype string `json:"ethertype"` - Id string `json:"id"` - Description string `json:"description"` - SecurityGroupId string `json:"security_group_id"` - RemoteGroupId string `json:"remote_group_id"` -} - -type SecurityGroupRuleDetail struct { - Direction string `json:"direction"` - Ethertype string `json:"ethertype"` - Id string `json:"id"` - Description string `json:"description"` - PortRangeMax int64 `json:"port_range_max"` - PortRangeMin int64 `json:"port_range_min"` - Protocol string `json:"protocol"` - RemoteGroupId string `json:"remote_group_id"` - RemoteIPPrefix string `json:"remote_ip_prefix"` - SecurityGroupId string `json:"security_group_id"` - TenantId string `json:"tenant_id"` -} - -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.HcsTags - region *SRegion - - Id string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - VpcId string `json:"vpc_id"` - EnterpriseProjectId string `json:"enterprise_project_id "` - SecurityGroupRules []SecurityGroupRule `json:"security_group_rules"` -} - -// 判断是否兼容云端安全组规则 -func compatibleSecurityGroupRule(r SecurityGroupRule) bool { - // 忽略了源地址是安全组的规则 - if len(r.RemoteGroupId) > 0 { - return false - } - - // 忽略IPV6 - if r.Ethertype == "IPv6" { - return false - } - - return true -} - -func (self *SSecurityGroup) GetId() string { - return self.Id -} - -func (self *SSecurityGroup) GetVpcId() string { - return self.VpcId -} - -func (self *SSecurityGroup) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.Id -} - -func (self *SSecurityGroup) GetGlobalId() string { - return self.Id -} - -func (self *SSecurityGroup) GetStatus() string { - return "" -} - -func (self *SSecurityGroup) Refresh() error { - if new, err := self.region.GetSecurityGroupDetails(self.GetId()); err != nil { - return err - } else { - return jsonutils.Update(self, new) - } -} - -func (self *SSecurityGroup) IsEmulated() bool { - return false -} - -func (self *SSecurityGroup) GetDescription() string { - if self.Description == self.VpcId { - return "" - } - return self.Description -} - -// todo: 这里需要优化查询太多了 -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - rules := make([]cloudprovider.SecurityRule, 0) - for _, r := range self.SecurityGroupRules { - if !compatibleSecurityGroupRule(r) { - continue - } - - rule, err := self.GetSecurityRule(r.Id) - if err != nil { - return rules, err - } - - rules = append(rules, rule) - } - - return rules, nil -} - -func (self *SSecurityGroup) GetSecurityRule(ruleId string) (cloudprovider.SecurityRule, error) { - remoteRule := SecurityGroupRuleDetail{} - err := self.region.vpcGet("security-group-rules/"+ruleId, &remoteRule) - if err != nil { - return cloudprovider.SecurityRule{}, err - } - - var direction secrules.TSecurityRuleDirection - if remoteRule.Direction == "ingress" { - direction = secrules.SecurityRuleIngress - } else { - direction = secrules.SecurityRuleEgress - } - - protocol := secrules.PROTO_ANY - if remoteRule.Protocol != "" { - protocol = remoteRule.Protocol - } - - var portStart int - var portEnd int - if protocol == secrules.PROTO_ICMP { - portStart = -1 - portEnd = -1 - } else { - portStart = int(remoteRule.PortRangeMin) - portEnd = int(remoteRule.PortRangeMax) - } - - ipNet := &net.IPNet{} - if len(remoteRule.RemoteIPPrefix) > 0 { - _, ipNet, err = net.ParseCIDR(remoteRule.RemoteIPPrefix) - } else { - _, ipNet, err = net.ParseCIDR("0.0.0.0/0") - } - - if err != nil { - return cloudprovider.SecurityRule{}, err - } - - rule := cloudprovider.SecurityRule{ - ExternalId: ruleId, - SecurityRule: secrules.SecurityRule{ - Priority: 1, - Action: secrules.SecurityRuleAllow, - IPNet: ipNet, - Protocol: protocol, - Direction: direction, - PortStart: portStart, - PortEnd: portEnd, - Ports: nil, - Description: remoteRule.Description, - }, - } - - err = rule.ValidateRule() - return rule, err -} - -func (self *SRegion) GetSecurityGroupDetails(id string) (*SSecurityGroup, error) { - ret := &SSecurityGroup{region: self} - return ret, self.vpcGet("security-groups/"+id, ret) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090617.html -func (self *SRegion) GetSecurityGroups(vpcId string) ([]SSecurityGroup, error) { - query := url.Values{} - if len(vpcId) > 0 && !utils.IsInStringArray(vpcId, []string{"default", api.NORMAL_VPC_ID}) { // vpc_id = default or normal 时报错 '{"code":"VPC.0601","message":"Query security groups error vpcId is invalid."}' - query.Set("vpc_id", vpcId) - } - ret := []SSecurityGroup{} - return ret, self.vpcList("security-groups", query, &ret) -} - -func (self *SSecurityGroup) GetProjectId() string { - return "" -} - -func (self *SSecurityGroup) Delete() error { - return self.region.DeleteSecurityGroup(self.Id) -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - for _, r := range append(inDels, outDels...) { - err := self.region.DeleteSecurityGroupRule(r.ExternalId) - if err != nil { - return errors.Wrapf(err, "delSecurityGroupRule(%s %s)", r.ExternalId, r.String()) - } - } - for _, r := range append(inAdds, outAdds...) { - err := self.region.CreateSecurityGroupRule(self.Id, r) - if err != nil { - return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String()) - } - } - return nil -} - -func (self *SRegion) DeleteSecurityGroup(id string) error { - return self.vpcDelete("security-groups/" + id) -} - -func (self *SRegion) DeleteSecurityGroupRule(ruleId string) error { - return self.vpcDelete("security-group-rules/" + ruleId) -} - -func (self *SRegion) CreateSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { - direction := "" - if rule.Direction == secrules.SecurityRuleIngress { - direction = "ingress" - } else { - direction = "egress" - } - - protocal := rule.Protocol - if rule.Protocol == secrules.PROTO_ANY { - protocal = "" - } - - // imcp协议默认为any - if rule.Protocol == secrules.PROTO_ICMP { - return self.AddSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String()) - } - - if len(rule.Ports) > 0 { - for _, port := range rule.Ports { - portStr := fmt.Sprintf("%d", port) - err := self.AddSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String()) - if err != nil { - return err - } - } - } else { - portStart := fmt.Sprintf("%d", rule.PortStart) - portEnd := fmt.Sprintf("%d", rule.PortEnd) - err := self.AddSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String()) - if err != nil { - return err - } - } - return nil -} - -func (self *SRegion) AddSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error { - rule := map[string]interface{}{ - "security_group_id": secGrpId, - "direction": direction, - "remote_ip_prefix": ipNet, - "ethertype": "IPV4", - } - if len(portStart) > 0 && portStart != "0" && portStart != "-1" { - rule["port_range_min"] = portStart - } - if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" { - rule["port_range_max"] = portEnd - } - if len(protocol) > 0 { - rule["protocol"] = protocol - } - params := map[string]interface{}{ - "security_group_rule": rule, - } - return self.vpcCreate("security-group-rules", params, nil) -} - -func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (*SSecurityGroup, error) { - params := map[string]interface{}{ - "security_group": map[string]interface{}{ - "name": name, - "vpc_id": vpcId, - }, - } - ret := &SSecurityGroup{region: self} - return ret, self.vpcCreate("security-groups", params, ret) -} - -func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - return self.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - return self.GetSecurityGroupDetails(secgroupId) -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := self.GetSecurityGroups(opts.VpcId) - if err != nil { - return nil, err - } - for i := range secgroups { - if secgroups[i].GetName() == opts.Name { - secgroups[i].region = self - return &secgroups[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "vpc:%s, name:%s", opts.VpcId, opts.Name) -} diff --git a/pkg/multicloud/hcs/shell/bucket.go b/pkg/multicloud/hcs/shell/bucket.go deleted file mode 100644 index b0db22ba42..0000000000 --- a/pkg/multicloud/hcs/shell/bucket.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type BucketListOptions struct { - } - shellutils.R(&BucketListOptions{}, "bucket-list", "List buckets", func(cli *hcs.SRegion, args *BucketListOptions) error { - buckets, err := cli.GetBuckets() - if err != nil { - return err - } - printList(buckets, 0, 0, 0, nil) - return nil - }) - - type BucketCreateOptions struct { - NAME string - Storage string `default:"STANDARD" choices:"STANDARD|WARM|COLD"` - Acl string `default:"private" choices:"private|public-read|public-read-write"` - } - shellutils.R(&BucketCreateOptions{}, "bucket-create", "Create bucket", func(cli *hcs.SRegion, args *BucketCreateOptions) error { - return cli.CreateBucket(args.NAME, args.Storage, args.Acl) - }) - -} diff --git a/pkg/multicloud/hcs/shell/dbinstance.go b/pkg/multicloud/hcs/shell/dbinstance.go deleted file mode 100644 index 6e871dd6a9..0000000000 --- a/pkg/multicloud/hcs/shell/dbinstance.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceListOptions struct { - } - shellutils.R(&DBInstanceListOptions{}, "dbinstance-list", "List dbinstances", func(cli *huawei.SRegion, args *DBInstanceListOptions) error { - dbinstances, err := cli.GetDBInstances() - if err != nil { - return err - } - printList(dbinstances, 0, 0, 0, nil) - return nil - }) - - type DBInstanceIdOptions struct { - ID string `help:"DBInstance ID"` - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-open-public-connection", "Open dbinstance public connection", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - return cli.PublicConnectionAction(args.ID, "openRC") - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-close-public-connection", "Close dbinstance public connection", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - return cli.PublicConnectionAction(args.ID, "closeRC") - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-show", "Show dbinstance", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - dbinstance, err := cli.GetDBInstance(args.ID) - if err != nil { - return err - } - printObject(dbinstance) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-parameter-list", "Show dbinstance parameters", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - parameters, err := cli.GetDBInstanceParameters(args.ID) - if err != nil { - return err - } - printList(parameters, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-backup-list", "Show dbinstance backups", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - backups, err := cli.GetDBInstanceBackups(args.ID, "") - if err != nil { - return err - } - printList(backups, 0, 0, 0, nil) - return nil - }) - - type DBInstanceFlavorListOption struct { - ENGINE string `help:"DBInstance engine" choices:"MySQL|SQLServer|PostgreSQL"` - VERSION string `help:"DBInstance engine version" choices:"5.6|5.7|9.5|9.6|10.0|2014 SE|2014 EE|2016 SE|2016 EE|2008 R2 EE|2008 R2 WEB|2014 WEB|2016 WEB"` - } - - shellutils.R(&DBInstanceFlavorListOption{}, "dbinstance-flavor-list", "Show dbinstance backups", func(cli *huawei.SRegion, args *DBInstanceFlavorListOption) error { - flavors, err := cli.GetDBInstanceFlavors(args.ENGINE, args.VERSION) - if err != nil { - return err - } - printList(flavors, 0, 0, 0, nil) - return nil - }) - - type DBInstanceChangeConfigOptions struct { - INSTANCE string - InstanceType string - DiskSizeGB int - } - - shellutils.R(&DBInstanceChangeConfigOptions{}, "dbinstance-change-config", "Change dbinstance config", func(cli *huawei.SRegion, args *DBInstanceChangeConfigOptions) error { - return cli.ChangeDBInstanceConfig(args.INSTANCE, args.InstanceType, args.DiskSizeGB) - }) - -} diff --git a/pkg/multicloud/hcs/shell/dbinstance_account.go b/pkg/multicloud/hcs/shell/dbinstance_account.go deleted file mode 100644 index 60375c0793..0000000000 --- a/pkg/multicloud/hcs/shell/dbinstance_account.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceIdOptions struct { - ID string `help:"DBInstance ID"` - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-account-list", "Show dbinstance accounts", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - accounts, err := cli.GetDBInstanceAccounts(args.ID) - if err != nil { - return err - } - printList(accounts, 0, 0, 0, nil) - return nil - }) - - type DBInstanceAccountDeleteOptions struct { - INSTANCE string - ACCOUNT string - } - - shellutils.R(&DBInstanceAccountDeleteOptions{}, "dbinstance-account-delete", "Delete dbinstance account", func(cli *huawei.SRegion, args *DBInstanceAccountDeleteOptions) error { - return cli.DeleteDBInstanceAccount(args.INSTANCE, args.ACCOUNT) - }) - - type DBInstanceAccountCreateOptions struct { - INSTANCE string - ACCOUNT string - PASSWORD string - } - - shellutils.R(&DBInstanceAccountCreateOptions{}, "dbinstance-account-create", "Create dbinstance account", func(cli *huawei.SRegion, args *DBInstanceAccountCreateOptions) error { - return cli.CreateDBInstanceAccount(args.INSTANCE, args.ACCOUNT, args.PASSWORD) - }) - - type DBInstanceAccountRevokePrivilegeOptions struct { - INSTANCE string - ACCOUNT string - DATABASE string - } - - shellutils.R(&DBInstanceAccountRevokePrivilegeOptions{}, "dbinstance-account-revoke-provilege", "Revoke dbinstance account privilege", func(cli *huawei.SRegion, args *DBInstanceAccountRevokePrivilegeOptions) error { - return cli.RevokeDBInstancePrivilege(args.INSTANCE, args.ACCOUNT, args.DATABASE) - }) - - type DBInstanceAccountGrantPrivilegeOptions struct { - INSTANCE string - ACCOUNT string - DATABASE string - PRIVILEGE string `help:"database privilege" choices:"r|rw"` - } - - shellutils.R(&DBInstanceAccountGrantPrivilegeOptions{}, "dbinstance-account-grant-provilege", "Grant dbinstance account privilege", func(cli *huawei.SRegion, args *DBInstanceAccountGrantPrivilegeOptions) error { - return cli.GrantDBInstancePrivilege(args.INSTANCE, args.ACCOUNT, args.DATABASE, args.PRIVILEGE) - }) - -} diff --git a/pkg/multicloud/hcs/shell/dbinstance_database.go b/pkg/multicloud/hcs/shell/dbinstance_database.go deleted file mode 100644 index afea978b93..0000000000 --- a/pkg/multicloud/hcs/shell/dbinstance_database.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceIdOptions struct { - INSTANCE string `help:"DBInstance ID"` - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-database-list", "Show dbinstance databases", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - databases, err := cli.GetDBInstanceDatabases(args.INSTANCE) - if err != nil { - return err - } - printList(databases, 0, 0, 0, nil) - return nil - }) - - type DBInstanceDatabaseDeleteOptions struct { - INSTANCE string - DATABASE string - } - - shellutils.R(&DBInstanceDatabaseDeleteOptions{}, "dbinstance-database-delete", "Delete dbinstance database", func(cli *huawei.SRegion, args *DBInstanceDatabaseDeleteOptions) error { - return cli.DeleteDBInstanceDatabase(args.INSTANCE, args.DATABASE) - }) - - type DBInstanceDatabaseCreateOptions struct { - INSTANCE string - DATABASE string - CHARACTER_SET string - } - - shellutils.R(&DBInstanceDatabaseCreateOptions{}, "dbinstance-database-create", "Create dbinstance database", func(cli *huawei.SRegion, args *DBInstanceDatabaseCreateOptions) error { - return cli.CreateDBInstanceDatabase(args.INSTANCE, args.DATABASE, args.CHARACTER_SET) - }) - -} diff --git a/pkg/multicloud/hcs/shell/dbinstance_skus.go b/pkg/multicloud/hcs/shell/dbinstance_skus.go deleted file mode 100644 index b95310dca4..0000000000 --- a/pkg/multicloud/hcs/shell/dbinstance_skus.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceDatastoreOptions struct { - ENGINE string `help:"DBInstance Engine" choices:"MySQL|PostgreSQL|SQLServer"` - } - - shellutils.R(&DBInstanceDatastoreOptions{}, "dbinstance-datastore-list", "List dbinstance datastores", func(cli *huawei.SRegion, args *DBInstanceDatastoreOptions) error { - stores, err := cli.GetDBInstanceDatastores(args.ENGINE) - if err != nil { - return err - } - printList(stores, 0, 0, 0, nil) - return nil - }) - - type DBInstanceSkuListOptions struct { - } - - shellutils.R(&DBInstanceSkuListOptions{}, "dbinstance-sku-list", "List dbinstance datastores", func(cli *huawei.SRegion, args *DBInstanceSkuListOptions) error { - skus, err := cli.GetDBInstanceSkus() - if err != nil { - return err - } - printList(skus, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/hcs/shell/disk.go b/pkg/multicloud/hcs/shell/disk.go deleted file mode 100644 index 5b71cf6b9b..0000000000 --- a/pkg/multicloud/hcs/shell/disk.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - Zone string `help:"Zone ID"` - } - shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *hcs.SRegion, args *DiskListOptions) error { - disks, e := cli.GetDisks(args.Zone) - if e != nil { - return e - } - printList(disks, 0, 0, 0, nil) - return nil - }) - - type DiskCreateOptions struct { - ZONE string - STORAGE_TYPE string - NAME string - SIZE_GB int - SnapshotId string - Desc string - ProjectId string - } - - shellutils.R(&DiskCreateOptions{}, "disk-create", "Create disk", func(cli *hcs.SRegion, args *DiskCreateOptions) error { - disk, e := cli.CreateDisk(args.ZONE, args.STORAGE_TYPE, args.NAME, args.SIZE_GB, args.SnapshotId, args.Desc, args.ProjectId) - if e != nil { - return e - } - printObject(disk) - return nil - }) - - type DiskIdOptions struct { - ID string `help:"Disk ID"` - } - - shellutils.R(&DiskIdOptions{}, "disk-delete", "Delete disks", func(cli *hcs.SRegion, args *DiskIdOptions) error { - e := cli.DeleteDisk(args.ID) - if e != nil { - return e - } - return nil - }) - - shellutils.R(&DiskIdOptions{}, "disk-show", "Show disks", func(cli *hcs.SRegion, args *DiskIdOptions) error { - disk, e := cli.GetDisk(args.ID) - if e != nil { - return e - } - printObject(disk) - return nil - }) - - shellutils.R(&DiskListOptions{}, "disk-types", "List disk types", func(cli *hcs.SRegion, args *DiskListOptions) error { - ret, e := cli.GetDiskTypes() - if e != nil { - return e - } - printList(ret, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcs/shell/doc.go b/pkg/multicloud/hcs/shell/doc.go deleted file mode 100644 index cdd19d8399..0000000000 --- a/pkg/multicloud/hcs/shell/doc.go +++ /dev/null @@ -1 +0,0 @@ -package shell // import "yunion.io/x/onecloud/pkg/multicloud/hcs/shell" diff --git a/pkg/multicloud/hcs/shell/eip.go b/pkg/multicloud/hcs/shell/eip.go deleted file mode 100644 index 41d1b12b42..0000000000 --- a/pkg/multicloud/hcs/shell/eip.go +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - PortId string - Address []string - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *hcs.SRegion, args *EipListOptions) error { - eips, err := cli.GetEips(args.PortId, args.Address) - if err != nil { - return nil - } - printList(eips, 0, 0, 0, nil) - return nil - }) - - type EipTypeListOptions struct { - } - - shellutils.R(&EipTypeListOptions{}, "eip-type-list", "List eip types", func(cli *hcs.SRegion, args *EipTypeListOptions) error { - types, err := cli.GetEipTypes() - if err != nil { - return nil - } - printList(types, 0, 0, 0, nil) - return nil - }) - - type EipAllocateOptions struct { - NAME string `help:"eip name"` - BW int `help:"Bandwidth limit in Mbps"` - BGP string `help:"bgp type"` - ChargeType string `help:"eip charge type" default:"traffic" choices:"traffic|bandwidth"` - ProjectId string - } - shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *hcs.SRegion, args *EipAllocateOptions) error { - eip, err := cli.AllocateEIP(args.NAME, args.BW, hcs.TInternetChargeType(args.ChargeType), args.BGP, args.ProjectId) - 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 *hcs.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 *hcs.SRegion, args *EipAssociateOptions) error { - return cli.AssociateEip(args.ID, args.INSTANCE) - }) - - type EipDissociateOptions struct { - ID string `help:"EIP allocation ID"` - } - - shellutils.R(&EipDissociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *hcs.SRegion, args *EipDissociateOptions) error { - return cli.DissociateEip(args.ID) - }) - -} diff --git a/pkg/multicloud/hcs/shell/image.go b/pkg/multicloud/hcs/shell/image.go deleted file mode 100644 index 70a7023b2c..0000000000 --- a/pkg/multicloud/hcs/shell/image.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - Status string `help:"image status type" choices:"queued|saving|deleted|killed|active"` - Owner string `help:"Owner type" choices:"gold|private|shared"` - // Id []string `help:"Image ID"` - Name string `help:"image name"` - // Marker string `help:"marker"` - // Limit int `help:"page Limit"` - Env string `help:"virtualization env, e.g. FusionCompute, Ironic" choices:"FusionCompute|Ironic"` - } - shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *hcs.SRegion, args *ImageListOptions) error { - images, e := cli.GetImages(args.Status, hcs.TImageOwnerType(args.Owner), args.Name, args.Env) - if e != nil { - return e - } - printList(images, 0, 0, 0, []string{}) - return nil - }) - - type ImageDeleteOptions struct { - ID string `help:"ID or Name to delete"` - } - shellutils.R(&ImageDeleteOptions{}, "image-delete", "Delete image", func(cli *hcs.SRegion, args *ImageDeleteOptions) error { - return cli.DeleteImage(args.ID) - }) - - shellutils.R(&ImageDeleteOptions{}, "image-show", "Show image", func(cli *hcs.SRegion, args *ImageDeleteOptions) error { - img, err := cli.GetImage(args.ID) - if err != nil { - return err - } - printObject(img) - return nil - }) -} diff --git a/pkg/multicloud/hcs/shell/instance.go b/pkg/multicloud/hcs/shell/instance.go deleted file mode 100644 index d6dd34115d..0000000000 --- a/pkg/multicloud/hcs/shell/instance.go +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "context" - "fmt" - "strconv" - "strings" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - Ip string - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List intances", func(cli *hcs.SRegion, args *InstanceListOptions) error { - instances, e := cli.GetInstances(args.Ip) - if e != nil { - return e - } - printList(instances, 0, 0, 0, nil) - 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 *hcs.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 *hcs.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 *hcs.SRegion, args *InstanceOperationOptions) error { - err := cli.StartVM(args.ID) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&InstanceOperationOptions{}, "instance-interface-list", "List instance interface", func(cli *hcs.SRegion, args *InstanceOperationOptions) error { - ret, err := cli.GetInstanceInterfaces(args.ID) - if err != nil { - return err - } - printList(ret, 0, 0, 0, nil) - 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 *hcs.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 *hcs.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 *hcs.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"` - UserId string `help:"instance user ID"` - Image string `help:"Image ID"` - Password string `help:"admin password"` - PublicKeyName string `help:"public key name"` - UserData string `help:"cloud-init user data"` - } - - shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *hcs.SRegion, args *InstanceRebuildRootOptions) error { - ctx := context.Background() - return cli.ChangeRoot(ctx, args.UserId, args.ID, args.Image, args.Password, args.PublicKeyName, args.UserData) - }) - - type InstanceChangeConfigOptions struct { - ID string `help:"instance ID"` - InstanceType string `help:"instance type"` - } - - shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Deploy keypair/password to a stopped virtual server", func(cli *hcs.SRegion, args *InstanceChangeConfigOptions) error { - err := cli.ChangeVMConfig(args.ID, args.InstanceType) - if err != nil { - return err - } - return nil - }) - - type InstanceSaveImageOptions struct { - ID string `help:"Instance ID"` - IMAGE_NAME string `help:"Image name"` - Notes string `hlep:"Image desc"` - } - shellutils.R(&InstanceSaveImageOptions{}, "instance-save-image", "Save instance to image", func(cli *hcs.SRegion, args *InstanceSaveImageOptions) error { - opts := cloudprovider.SaveImageOptions{ - Name: args.IMAGE_NAME, - Notes: args.Notes, - } - image, err := cli.SaveImage(args.ID, &opts) - if err != nil { - return err - } - printObject(image) - return nil - }) - - type InstanceSetTagsOptions struct { - ID string `help:"Instance ID"` - Tags []string - } - shellutils.R(&InstanceSetTagsOptions{}, "instance-set-tags", "get intance metadata", func(cli *hcs.SRegion, args *InstanceSetTagsOptions) error { - tags := map[string]string{} - for i := range args.Tags { - splited := strings.Split(args.Tags[i], "=") - if len(splited) == 2 { - tags[splited[0]] = splited[1] - } - } - err := cli.CreateServerTags(args.ID, tags) - if err != nil { - return err - } - return nil - }) - - type InstanceDelTagsOptions struct { - ID string `help:"Instance ID"` - Tags []string - } - shellutils.R(&InstanceDelTagsOptions{}, "instance-del-tags", "del intance metadata", func(cli *hcs.SRegion, args *InstanceDelTagsOptions) error { - - err := cli.DeleteServerTags(args.ID, args.Tags) - if err != nil { - return err - } - return nil - }) - - type InstanceUpdateNameOptions struct { - ID string `help:"Instance ID"` - Name string - } - shellutils.R(&InstanceUpdateNameOptions{}, "instance-set-name", "set intance name", func(cli *hcs.SRegion, args *InstanceUpdateNameOptions) error { - - err := cli.UpdateVM(args.ID, args.Name) - if err != nil { - return err - } - return nil - }) - - type InstanceCreateOptions struct { - NAME string - IMAGE_ID string - INSTANCE_TYPE string - NETWORK_ID string - IpAddr string - Secgroup string `default:"default"` - VPC_ID string - ZONE_ID string - Desc string - Keypair string - Password string - UserData string - ProjectId string - DISKS []string - } - shellutils.R(&InstanceCreateOptions{}, "instance-create", "create instance", func(cli *hcs.SRegion, args *InstanceCreateOptions) error { - sysDisk := cloudprovider.SDiskInfo{} - dataDisks := []cloudprovider.SDiskInfo{} - for i, disk := range args.DISKS { - info := strings.Split(args.DISKS[i], ":") - if len(info) != 2 { - return fmt.Errorf("invalid disk %s", disk) - } - if i == 0 { - sysDisk.StorageType = info[0] - sysDisk.SizeGB, _ = strconv.Atoi(info[1]) - } else { - dataDisk := cloudprovider.SDiskInfo{} - dataDisk.StorageType = info[0] - dataDisk.SizeGB, _ = strconv.Atoi(info[1]) - dataDisks = append(dataDisks, dataDisk) - } - } - vm, err := cli.CreateInstance(args.NAME, args.IMAGE_ID, args.INSTANCE_TYPE, args.NETWORK_ID, args.Secgroup, args.VPC_ID, args.ZONE_ID, args.Desc, sysDisk, dataDisks, args.IpAddr, args.Keypair, args.Password, args.UserData, nil, args.ProjectId, nil) - if err != nil { - return err - } - printObject(vm) - return nil - }) -} diff --git a/pkg/multicloud/hcs/shell/instancetype.go b/pkg/multicloud/hcs/shell/instancetype.go deleted file mode 100644 index 61756de7fd..0000000000 --- a/pkg/multicloud/hcs/shell/instancetype.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceMatchOptions struct { - Zone string `help:"Test in zone"` - } - shellutils.R(&InstanceMatchOptions{}, "instance-type-list", "Select matching instance types", func(cli *hcs.SRegion, args *InstanceMatchOptions) error { - instanceTypes, e := cli.GetchInstanceTypes(args.Zone) - if e != nil { - return e - } - printList(instanceTypes, 0, 0, 0, []string{}) - return nil - }) - - type InstanceTypeIdOptions struct { - ID string - } - - shellutils.R(&InstanceTypeIdOptions{}, "instance-type-show", "show instance type", func(cli *hcs.SRegion, args *InstanceTypeIdOptions) error { - ret, e := cli.GetchInstanceType(args.ID) - if e != nil { - return e - } - printObject(ret) - return nil - }) - -} diff --git a/pkg/multicloud/hcs/shell/job.go b/pkg/multicloud/hcs/shell/job.go deleted file mode 100644 index 4713d47e59..0000000000 --- a/pkg/multicloud/hcs/shell/job.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type JobShowOptions struct { - ID string - Service string - } - shellutils.R(&JobShowOptions{}, "job-show", "show job", func(cli *hcs.SRegion, args *JobShowOptions) error { - job, err := cli.GetJob(args.Service, args.ID) - if err != nil { - return err - } - printObject(job) - return nil - }) -} diff --git a/pkg/multicloud/hcs/shell/keypair.go b/pkg/multicloud/hcs/shell/keypair.go deleted file mode 100644 index 07d5d7a785..0000000000 --- a/pkg/multicloud/hcs/shell/keypair.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KeyPairListOptions struct { - } - shellutils.R(&KeyPairListOptions{}, "keypair-list", "List keypairs", func(cli *hcs.SRegion, args *KeyPairListOptions) error { - keypairs, e := cli.GetKeypairs() - if e != nil { - return e - } - printList(keypairs, 0, 0, 0, []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 *hcs.SRegion, args *KeyPairImportOptions) error { - keypair, err := cli.ImportKeypair(args.NAME, args.PUBKEY) - if err != nil { - return err - } - printObject(keypair) - return nil - }) -} diff --git a/pkg/multicloud/hcs/shell/lb.go b/pkg/multicloud/hcs/shell/lb.go deleted file mode 100644 index 34e430199d..0000000000 --- a/pkg/multicloud/hcs/shell/lb.go +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElbListOptions struct { - } - shellutils.R(&ElbListOptions{}, "elb-list", "List loadbalancers", func(cli *hcs.SRegion, args *ElbListOptions) error { - elbs, err := cli.GetILoadBalancers() - if err != nil { - return err - } - printList(elbs, len(elbs), 0, 0, []string{}) - return nil - }) - - type ElbCreateOptions struct { - Name string `help:"loadblancer name"` - SUBNET string `help:"subnet id"` - PrivateIP string `help:"loadbalancer private ip address"` - EipID string `help:"loadbalancer public ip id"` - } - shellutils.R(&ElbCreateOptions{}, "elb-create", "create loadbalancer", func(cli *hcs.SRegion, args *ElbCreateOptions) error { - loadbalancer := &cloudprovider.SLoadbalancer{ - Name: args.Name, - NetworkIDs: []string{args.SUBNET}, - EipID: args.EipID, - Address: args.PrivateIP, - } - - elb, err := cli.CreateLoadBalancer(loadbalancer) - if err != nil { - return err - } - - printObject(elb) - return nil - }) - - type ElbIdOptions struct { - ID string `help:"loadblancer id"` - } - shellutils.R(&ElbIdOptions{}, "elb-delete", "delete loadbalancer", func(cli *hcs.SRegion, args *ElbIdOptions) error { - err := cli.DeleteLoadBalancer(args.ID) - if err != nil { - return err - } - - return nil - }) - - shellutils.R(&ElbIdOptions{}, "elb-show", "show loadbalancer", func(cli *hcs.SRegion, args *ElbIdOptions) error { - lb, err := cli.GetLoadbalancer(args.ID) - if err != nil { - return err - } - printObject(lb) - return nil - }) - - type ElbListenerListOptions struct { - ElbID string `help:"loadblancer id"` - } - shellutils.R(&ElbListenerListOptions{}, "elb-listener-list", "list loadbalancer listener", func(cli *hcs.SRegion, args *ElbListenerListOptions) error { - listeners, err := cli.GetLoadBalancerListeners(args.ElbID) - if err != nil { - return err - } - - printList(listeners, len(listeners), 0, 0, []string{}) - return nil - }) - - type ElbListenerCreateOptions struct { - Name string `help:"listener name"` - Desc string `help:"listener Description"` - Http2 bool `help:"http2 enable status"` - PoolID string `help:"default backend group id"` - CertId string `help:"default certification id"` - XForwardedFor bool `help:"XForwardedFor enable status"` - LISTENER_TYPE string `help:"listener type" choices:"tcp|udp|http|https"` - LISTENER_PORT int `help:"listener port"` - ELB_ID string `help:"loadbalancer id"` - } - shellutils.R(&ElbListenerCreateOptions{}, "elb-listener-create", "create loadbalancer listener", func(cli *hcs.SRegion, args *ElbListenerCreateOptions) error { - input := &cloudprovider.SLoadbalancerListener{ - Name: args.Name, - LoadbalancerID: args.ELB_ID, - ListenerType: args.LISTENER_TYPE, - ListenerPort: args.LISTENER_PORT, - BackendGroupID: args.PoolID, - EnableHTTP2: args.Http2, - CertificateID: args.CertId, - Description: args.Desc, - XForwardedFor: args.XForwardedFor, - } - listener, err := cli.CreateLoadBalancerListener(input) - if err != nil { - return err - } - - printObject(listener) - return nil - }) - - type ElbListenerUpdateOptions struct { - Name string `help:"listener name"` - Desc string `help:"listener Description"` - Http2 bool `help:"http2 enable status"` - PoolID string `help:"default backend group id"` - CertId string `help:"default certification id"` - XForwardedFor bool `help:"XForwardedFor enable status"` - LISTENER_ID string `help:"listener id"` - } - shellutils.R(&ElbListenerUpdateOptions{}, "elb-listener-update", "update loadbalancer listener", func(cli *hcs.SRegion, args *ElbListenerUpdateOptions) error { - input := &cloudprovider.SLoadbalancerListener{ - Name: args.Name, - BackendGroupID: args.PoolID, - EnableHTTP2: args.Http2, - CertificateID: args.CertId, - Description: args.Desc, - XForwardedFor: args.XForwardedFor, - } - - err := cli.UpdateLoadBalancerListener(args.LISTENER_ID, input) - if err != nil { - return err - } - - return nil - }) - - type ElbBackendGroupListOptions struct { - ElbID string `help:"loadbalancer id"` - } - shellutils.R(&ElbBackendGroupListOptions{}, "elb-backend-group-list", "List backend groups", func(cli *hcs.SRegion, args *ElbBackendGroupListOptions) error { - elbbg, err := cli.GetLoadBalancerBackendGroups(args.ElbID) - if err != nil { - return err - } - - printList(elbbg, len(elbbg), 0, 0, []string{}) - return nil - }) - - type ElbBackendGroupCreateOptions struct { - Name string `help:"backend group name"` - Desc string `help:"backend group description"` - PROTOCOL string `help:"backend group protocol" choices:"tcp|udp|http"` - ALGORITHM string `help:"backend group algorithm" choices:"rr|wlc|sch"` - ListenerID string `help:"listener id to binding"` - ElbID string `help:"loadbalancer id belong to"` - StickySessionType string `help:"sticky session type" choices:"insert|server"` - StickySessionCookieName string `help:"sticky session cookie name"` - StickySessionTimeout int `help:"sticky session timeout. udp/tcp 1~60. http 1~1440"` - HealthCheck bool `help:"enable health check"` - HealthCheckType string `help:"health check type protocol" choices:"tcp|udp|http"` - HealthCheckTimeout int `help:"health check timeout"` - HealthCheckDomain string `help:"health check domain"` - HealthCheckURI string `help:"health check uri path"` - HealthCheckInterval int `help:"health check interval"` - HealthCheckRise int `help:"health check max retries"` - } - shellutils.R(&ElbBackendGroupCreateOptions{}, "elb-backend-group-create", "Create backend groups", func(cli *hcs.SRegion, args *ElbBackendGroupCreateOptions) error { - var health *cloudprovider.SLoadbalancerHealthCheck - if args.HealthCheck { - health = &cloudprovider.SLoadbalancerHealthCheck{ - HealthCheckType: args.HealthCheckType, - HealthCheckTimeout: args.HealthCheckTimeout, - HealthCheckDomain: args.HealthCheckDomain, - HealthCheckURI: args.HealthCheckURI, - HealthCheckInterval: args.HealthCheckInterval, - HealthCheckRise: args.HealthCheckRise, - } - } - - var sticky *cloudprovider.SLoadbalancerStickySession - if len(args.StickySessionType) > 0 { - sticky = &cloudprovider.SLoadbalancerStickySession{ - StickySessionCookie: args.StickySessionCookieName, - StickySessionType: args.StickySessionType, - StickySessionCookieTimeout: args.StickySessionTimeout, - } - } - - group := &cloudprovider.SLoadbalancerBackendGroup{ - Name: args.Name, - LoadbalancerID: args.ElbID, - ListenerID: args.ListenerID, - ListenType: args.PROTOCOL, - Scheduler: args.ALGORITHM, - StickySession: sticky, - HealthCheck: health, - } - - elbbg, err := cli.CreateLoadBalancerBackendGroup(group) - if err != nil { - return err - } - - printObject(elbbg) - return nil - }) - - type ElbBackendGroupUpdateOptions struct { - POOL_ID string `help:"backend group id"` - Name string `help:"backend group name"` - } - shellutils.R(&ElbBackendGroupUpdateOptions{}, "elb-backend-group-update", "Update backend groups", func(cli *hcs.SRegion, args *ElbBackendGroupUpdateOptions) error { - group := &cloudprovider.SLoadbalancerBackendGroup{ - Name: args.Name, - } - - elbbg, err := cli.UpdateLoadBalancerBackendGroup(args.POOL_ID, group) - if err != nil { - return err - } - - printObject(elbbg) - return nil - }) - - type ElbBackendGroupDeleteOptions struct { - POOL_ID string `help:"backend group id"` - } - shellutils.R(&ElbBackendGroupDeleteOptions{}, "elb-backend-group-delete", "Delete backend group", func(cli *hcs.SRegion, args *ElbBackendGroupDeleteOptions) error { - err := cli.DeleteLoadBalancerBackendGroup(args.POOL_ID) - if err != nil { - return err - } - - return nil - }) - - type ElbBackendAddOptions struct { - Name string `help:"backend name"` - POOL_ID string `help:"backend group id"` - SUBNET_ID string `help:"instance subnet id"` - ADDRESS string `help:"instance ip address"` - PORT int `help:"backend protocol port [1,65535]"` - Weight int `help:"backend weight [0,100]" default:"1"` - } - shellutils.R(&ElbBackendAddOptions{}, "elb-backend-add", "Add backend to backendgroup", func(cli *hcs.SRegion, args *ElbBackendAddOptions) error { - elbb, err := cli.AddLoadBalancerBackend(args.POOL_ID, args.SUBNET_ID, args.ADDRESS, args.PORT, args.Weight) - if err != nil { - return err - } - - printObject(elbb) - return nil - }) - - type ElbBackendListOptions struct { - POOL_ID string `help:"backend group id"` - } - shellutils.R(&ElbBackendListOptions{}, "elb-backend-list", "list backend", func(cli *hcs.SRegion, args *ElbBackendListOptions) error { - elbb, err := cli.GetLoadBalancerBackends(args.POOL_ID) - if err != nil { - return err - } - - printList(elbb, len(elbb), 0, 0, []string{}) - return nil - }) - - type ElbListenerPolicyListOptions struct { - ListenerID string `help:"listener id"` - } - shellutils.R(&ElbListenerPolicyListOptions{}, "elb-listener-policy-list", "List listener policies", func(cli *hcs.SRegion, args *ElbListenerPolicyListOptions) error { - elblp, err := cli.GetLoadBalancerPolicies(args.ListenerID) - if err != nil { - return err - } - - printList(elblp, len(elblp), 0, 0, []string{}) - return nil - }) - - type ElbListenerPolicyCreateOptions struct { - LISTENER_ID string `help:"listener id"` - Name string `help:"policy name"` - Domain string `help:"policy domain"` - Path string `help:"policy path"` - PoolID string `help:"backend group name"` - } - shellutils.R(&ElbListenerPolicyCreateOptions{}, "elb-listener-policy-create", "Create listener policy", func(cli *hcs.SRegion, args *ElbListenerPolicyCreateOptions) error { - rule := &cloudprovider.SLoadbalancerListenerRule{ - Name: args.Name, - Domain: args.Domain, - Path: args.Path, - BackendGroupID: args.PoolID, - } - - elblp, err := cli.CreateLoadBalancerPolicy(args.LISTENER_ID, rule) - if err != nil { - return err - } - - printObject(elblp) - return nil - }) - - type ElbListenerPolicyDeleteOptions struct { - POLICY_ID string `help:"policy id"` - } - shellutils.R(&ElbListenerPolicyDeleteOptions{}, "elb-listener-policy-delete", "Delete listener policy", func(cli *hcs.SRegion, args *ElbListenerPolicyDeleteOptions) error { - err := cli.DeleteLoadBalancerPolicy(args.POLICY_ID) - if err != nil { - return err - } - - return nil - }) - - type ElbListenerPolicyRuleListOptions struct { - POLICY_ID string `help:"policy id"` - } - shellutils.R(&ElbListenerPolicyRuleListOptions{}, "elb-listener-policyrule-list", "List listener policy rules", func(cli *hcs.SRegion, args *ElbListenerPolicyRuleListOptions) error { - elblpr, err := cli.GetLoadBalancerPolicyRules(args.POLICY_ID) - if err != nil { - return err - } - - printList(elblpr, len(elblpr), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/hcs/shell/monitor.go b/pkg/multicloud/hcs/shell/monitor.go deleted file mode 100644 index 2ebfabd5fa..0000000000 --- a/pkg/multicloud/hcs/shell/monitor.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics", func(cli *hcs.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric: %s %s %s", metrics[i].Id, metrics[i].MetricType, metrics[i].Unit) - printList(metrics[i].Values, len(metrics[i].Values), 0, 0, []string{}) - } - return nil - }) - -} diff --git a/pkg/multicloud/hcs/shell/natgateway.go b/pkg/multicloud/hcs/shell/natgateway.go deleted file mode 100644 index 55b0915d51..0000000000 --- a/pkg/multicloud/hcs/shell/natgateway.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NatGatewayOptions struct { - NatGatewayId string `help:"Nat Gateway Id"` - VpcId string `help:"Vpc Id"` - } - shellutils.R(&NatGatewayOptions{}, "nat-list", "List nat gateway", func(region *hcs.SRegion, args *NatGatewayOptions) error { - natGateways, err := region.GetNatGateways(args.VpcId) - if err != nil { - return err - } - printList(natGateways, 0, 0, 0, nil) - return nil - }) - - type NatGatewayIdOptions struct { - Id string `help:"Nat Id"` - } - - shellutils.R(&NatGatewayIdOptions{}, "nat-delete", "Delete nat gateways", func(cli *hcs.SRegion, args *NatGatewayIdOptions) error { - return cli.DeleteNatGateway(args.Id) - }) - - shellutils.R(&NatGatewayIdOptions{}, "nat-show", "Show nat gateways", func(cli *hcs.SRegion, args *NatGatewayIdOptions) error { - nat, err := cli.GetNatGateway(args.Id) - if err != nil { - return err - } - printObject(nat) - return nil - }) - - type SCreateDNatOptions struct { - GatewayId string `help:"Nat Gateway Id" positional:"true"` - Protocol string `help:"Protocol(tcp/udp)" positional:"true"` - ExternalIPId string `help:"External IP Id" positional:"true"` - ExternalPort int `help:"External Port" positional:"true"` - InternalIP string `help:"Internal IP" positional:"true"` - InternalPort int `help:"Nat Gateway Id" positional:"true"` - } - shellutils.R(&SCreateDNatOptions{}, "dnat-create", "Create dnat", func(region *hcs.SRegion, args *SCreateDNatOptions) error { - rule := cloudprovider.SNatDRule{ - Protocol: args.Protocol, - ExternalIPID: args.ExternalIPId, - ExternalPort: args.ExternalPort, - InternalIP: args.InternalIP, - InternalPort: args.InternalPort, - } - dnat, err := region.CreateNatDEntry(rule, args.GatewayId) - if err != nil { - return err - } - printObject(dnat) - return nil - }) - - type SCreateSNatOptions struct { - GatewayId string `help:"Nat Gateway Id" positional:"true"` - SourceCIDR string `help:"Source cidr" positional:"true"` - ExternalIPId string `help:"External IP Id" positional:"true"` - } - shellutils.R(&SCreateSNatOptions{}, "snat-create", "Create snat", func(region *hcs.SRegion, args *SCreateSNatOptions) error { - rule := cloudprovider.SNatSRule{ - SourceCIDR: args.SourceCIDR, - ExternalIPID: args.ExternalIPId, - } - snat, err := region.CreateNatSEntry(rule, args.GatewayId) - if err != nil { - return err - } - printObject(snat) - return nil - }) - - type SShowSNatOptions struct { - NatId string `help:"SNat Id" positional:"true"` - } - shellutils.R(&SShowSNatOptions{}, "snat-show", "Show snat", func(region *hcs.SRegion, args *SShowSNatOptions) error { - snat, err := region.GetNatSEntry(args.NatId) - if err != nil { - return err - } - printObject(snat) - return nil - }) - - type SShowDNatOptions struct { - NatId string `help:"DNat Id" positional:"true"` - } - shellutils.R(&SShowDNatOptions{}, "dnat-show", "Show dnat", func(region *hcs.SRegion, args *SShowDNatOptions) error { - dnat, err := region.GetNatDEntry(args.NatId) - if err != nil { - return err - } - printObject(dnat) - return nil - }) - - type SDeleteSNatOptions struct { - NatId string `help:"SNat Id" positional:"true"` - } - shellutils.R(&SDeleteSNatOptions{}, "snat-delete", "Delete snat", func(region *hcs.SRegion, args *SDeleteSNatOptions) error { - err := region.DeleteNatSEntry(args.NatId) - if err != nil { - return err - } - return nil - }) - - type SDeleteDNatOptions struct { - NatId string `help:"DNat Id" positional:"true"` - } - shellutils.R(&SDeleteDNatOptions{}, "dnat-delete", "Delete dnat", func(region *hcs.SRegion, args *SDeleteDNatOptions) error { - err := region.DeleteNatDEntry(args.NatId) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/hcs/shell/network.go b/pkg/multicloud/hcs/shell/network.go deleted file mode 100644 index e59e030ec9..0000000000 --- a/pkg/multicloud/hcs/shell/network.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkListOptions struct { - Vpc string `help:"Vpc ID"` - } - shellutils.R(&NetworkListOptions{}, "network-list", "List subnets", func(cli *hcs.SRegion, args *NetworkListOptions) error { - networks, e := cli.GetNetwroks(args.Vpc) - if e != nil { - return e - } - printList(networks, 0, 0, 0, nil) - return nil - }) - - type NetworkIdOptions struct { - ID string - } - - shellutils.R(&NetworkIdOptions{}, "network-show", "Show subnets", func(cli *hcs.SRegion, args *NetworkIdOptions) error { - network, e := cli.GetNetwork(args.ID) - if e != nil { - return e - } - printObject(network) - return nil - }) - -} diff --git a/pkg/multicloud/hcs/shell/port.go b/pkg/multicloud/hcs/shell/port.go deleted file mode 100644 index 5760c136d2..0000000000 --- a/pkg/multicloud/hcs/shell/port.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type PortListOptions struct { - InstanceId string - } - shellutils.R(&PortListOptions{}, "port-list", "List ports", func(cli *hcs.SRegion, args *PortListOptions) error { - ports, err := cli.GetPorts(args.InstanceId) - if err != nil { - return err - } - printList(ports, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/hcs/shell/printutils.go b/pkg/multicloud/hcs/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/hcs/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/hcs/shell/project.go b/pkg/multicloud/hcs/shell/project.go deleted file mode 100644 index 86ceba6e7a..0000000000 --- a/pkg/multicloud/hcs/shell/project.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ProjectListOptions struct { - } - shellutils.R(&ProjectListOptions{}, "project-list", "List projects", func(cli *hcs.SRegion, args *ProjectListOptions) error { - regions, err := cli.GetClient().GetProjects() - if err != nil { - return err - } - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcs/shell/redis.go b/pkg/multicloud/hcs/shell/redis.go deleted file mode 100644 index 89bc5dbdaa..0000000000 --- a/pkg/multicloud/hcs/shell/redis.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElasticcacheListOptions struct { - } - shellutils.R(&ElasticcacheListOptions{}, "redis-list", "List elasticcaches", func(cli *hcs.SRegion, args *ElasticcacheListOptions) error { - instances, e := cli.GetElasticCaches() - if e != nil { - return e - } - printList(instances, len(instances), 0, 0, []string{}) - return nil - }) - - type ElasitccacheInstanceTypeListOptions struct { - } - - shellutils.R(&ElasitccacheInstanceTypeListOptions{}, "redis-instance-type-list", "List elasticcache instancetypes", func(cli *hcs.SRegion, args *ElasitccacheInstanceTypeListOptions) error { - ret, e := cli.GetRedisInstnaceTypes() - if e != nil { - return e - } - printList(ret, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&cloudprovider.SCloudElasticCacheInput{}, "redis-create", "Create elasticcache", func(cli *hcs.SRegion, args *cloudprovider.SCloudElasticCacheInput) error { - instance, e := cli.CreateElasticcache(args) - if e != nil { - return e - } - printObject(instance) - return nil - }) - - type ElasticcacheIdOptions struct { - ID string `help:"ID of instances to show"` - } - shellutils.R(&ElasticcacheIdOptions{}, "redis-show", "Show elasticcache", func(cli *hcs.SRegion, args *ElasticcacheIdOptions) error { - instance, err := cli.GetElasticCache(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - shellutils.R(&ElasticcacheIdOptions{}, "redis-delete", "Delete elasticcache", func(cli *hcs.SRegion, args *ElasticcacheIdOptions) error { - return cli.DeleteElasticcache(args.ID) - }) - - type ElasticcacheBackupsListOptions struct { - ID string `help:"ID of instances to show"` - StartTime string `help:"backup start time. format: 20060102150405"` - EndTime string `help:"backup end time. format: 20060102150405 "` - } - - shellutils.R(&ElasticcacheBackupsListOptions{}, "redis-backup-list", "List elasticcache backups", func(cli *hcs.SRegion, args *ElasticcacheBackupsListOptions) error { - backups, err := cli.GetElasticCacheBackups(args.ID, args.StartTime, args.EndTime) - if err != nil { - return err - } - printList(backups, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElasticcacheIdOptions{}, "redis-parameter-list", "List elasticcache parameters", func(cli *hcs.SRegion, args *ElasticcacheIdOptions) error { - parameters, err := cli.GetElasticCacheParameters(args.ID) - if err != nil { - return err - } - printList(parameters, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/hcs/shell/region.go b/pkg/multicloud/hcs/shell/region.go deleted file mode 100644 index 2182317e83..0000000000 --- a/pkg/multicloud/hcs/shell/region.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *hcs.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcs/shell/securitygroup.go b/pkg/multicloud/hcs/shell/securitygroup.go deleted file mode 100644 index c0e91e3b37..0000000000 --- a/pkg/multicloud/hcs/shell/securitygroup.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - VpcId string `help:"VPC ID"` - Name string `help:"Secgroup name"` - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security group", func(cli *hcs.SRegion, args *SecurityGroupListOptions) error { - secgrps, e := cli.GetSecurityGroups(args.VpcId) - if e != nil { - return e - } - printList(secgrps, 0, 0, 0, nil) - 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 *hcs.SRegion, args *SecurityGroupShowOptions) error { - secgrp, err := cli.GetSecurityGroupDetails(args.ID) - if err != nil { - return err - } - printObject(secgrp) - return nil - }) - - type SecurityGroupCreateOptions struct { - NAME string `help:"secgroup name"` - VPC string `help:"ID of VPC"` - Desc string `help:"description"` - } - shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create security group", func(cli *hcs.SRegion, args *SecurityGroupCreateOptions) error { - result, err := cli.CreateSecurityGroup(args.VPC, args.NAME, args.Desc) - if err != nil { - return err - } - printObject(result) - return nil - }) - - type SecurityGroupRuleIdOptions struct { - ID string - } - - shellutils.R(&SecurityGroupRuleIdOptions{}, "security-group-rule-delete", "Delete security group rule", func(cli *hcs.SRegion, args *SecurityGroupRuleIdOptions) error { - return cli.DeleteSecurityGroupRule(args.ID) - }) - - type SecurityGroupRuleCreateOptions struct { - SECGROUP_ID string - RULE string - } - - shellutils.R(&SecurityGroupRuleCreateOptions{}, "security-group-rule-create", "Create security group rule", func(cli *hcs.SRegion, args *SecurityGroupRuleCreateOptions) error { - _rule, err := secrules.ParseSecurityRule(args.RULE) - if err != nil { - return errors.Wrapf(err, "invalid rule %s", args.RULE) - } - rule := cloudprovider.SecurityRule{ - SecurityRule: *_rule, - } - return cli.CreateSecurityGroupRule(args.SECGROUP_ID, rule) - }) - -} diff --git a/pkg/multicloud/hcs/shell/snapshot.go b/pkg/multicloud/hcs/shell/snapshot.go deleted file mode 100644 index d6570705b8..0000000000 --- a/pkg/multicloud/hcs/shell/snapshot.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SnapshotListOptions struct { - DiskId string `help:"Disk ID"` - Name string `help:"Snapshot Name"` - } - shellutils.R(&SnapshotListOptions{}, "snapshot-list", "List snapshot", func(cli *hcs.SRegion, args *SnapshotListOptions) error { - snapshots, err := cli.GetSnapshots(args.DiskId, args.Name) - if err != nil { - return err - } - printList(snapshots, 0, 0, 0, nil) - return nil - }) - - type SnapshotIdOptions struct { - ID string `help:"Snapshot ID"` - } - - shellutils.R(&SnapshotIdOptions{}, "snapshot-delete", "Delete snapshot", func(cli *hcs.SRegion, args *SnapshotIdOptions) error { - return cli.DeleteSnapshot(args.ID) - }) - - shellutils.R(&SnapshotIdOptions{}, "snapshot-show", "Show snapshot", func(cli *hcs.SRegion, args *SnapshotIdOptions) error { - ret, err := cli.GetSnapshot(args.ID) - if err != nil { - return err - } - printObject(ret) - return nil - }) - - 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 *hcs.SRegion, args *SnapshotCreateOptions) error { - _, err := cli.CreateSnapshot(args.DiskId, args.Name, args.Desc) - return err - }) -} diff --git a/pkg/multicloud/hcs/shell/vpc.go b/pkg/multicloud/hcs/shell/vpc.go deleted file mode 100644 index ba9257882a..0000000000 --- a/pkg/multicloud/hcs/shell/vpc.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - } - shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *hcs.SRegion, args *VpcListOptions) error { - vpcs, err := cli.GetVpcs() - if err != nil { - return nil - } - printList(vpcs, 0, 0, 0, nil) - return nil - }) - - type VpcCreateOptions struct { - NAME string - CIDR string - Desc string - } - - shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *hcs.SRegion, args *VpcCreateOptions) error { - vpc, err := cli.CreateVpc(args.NAME, args.CIDR, args.Desc) - if err != nil { - return err - } - printObject(vpc) - return nil - }) - - type VpcIdOption struct { - ID string - } - - shellutils.R(&VpcIdOption{}, "vpc-delete", "Delete vpc", func(cli *hcs.SRegion, args *VpcIdOption) error { - return cli.DeleteVpc(args.ID) - }) - -} diff --git a/pkg/multicloud/hcs/shell/vpc_peer.go b/pkg/multicloud/hcs/shell/vpc_peer.go deleted file mode 100644 index b4010cd71c..0000000000 --- a/pkg/multicloud/hcs/shell/vpc_peer.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcPeerListOptions struct { - VpcId string - } - shellutils.R(&VpcPeerListOptions{}, "vpc-peer-list", "List vpc peers", func(cli *hcs.SRegion, args *VpcPeerListOptions) error { - peers, err := cli.GetVpcPeerings(args.VpcId) - if err != nil { - return nil - } - printList(peers, 0, 0, 0, nil) - return nil - }) - - type VpcPeerIdOption struct { - ID string - } - - shellutils.R(&VpcPeerIdOption{}, "vpc-peer-show", "Show vpc peer", func(cli *hcs.SRegion, args *VpcPeerIdOption) error { - ret, err := cli.GetVpcPeering(args.ID) - if err != nil { - return err - } - printObject(ret) - return nil - }) - - shellutils.R(&VpcPeerIdOption{}, "vpc-peer-delete", "Delete vpc peer", func(cli *hcs.SRegion, args *VpcPeerIdOption) error { - return cli.DeleteVpcPeering(args.ID) - }) - -} diff --git a/pkg/multicloud/hcs/shell/zone.go b/pkg/multicloud/hcs/shell/zone.go deleted file mode 100644 index e4ddf4a1af..0000000000 --- a/pkg/multicloud/hcs/shell/zone.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcs" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - } - shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *hcs.SRegion, args *ZoneListOptions) error { - zones, err := cli.GetZones() - if err != nil { - return nil - } - printList(zones, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcs/snapshot.go b/pkg/multicloud/hcs/snapshot.go deleted file mode 100644 index f765f34dc2..0000000000 --- a/pkg/multicloud/hcs/snapshot.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -/* -限制: -https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html -1. 从快照创建云硬盘时,volume_type字段必须和快照源云硬盘保持一致。 -2. 当指定的云硬盘类型在avaliability_zone内不存在时,则创建云硬盘失败。 -*/ - -type SnapshotStatusType string - -const ( - SnapshotStatusCreating SnapshotStatusType = "creating" - SnapshotStatusAvailable SnapshotStatusType = "available" // 云硬盘快照创建成功,可以使用。 - SnapshotStatusError SnapshotStatusType = "error" // 云硬盘快照在创建过程中出现错误。 - SnapshotStatusDeleting SnapshotStatusType = "deleting" // 云硬盘快照处于正在删除的过程中。 - SnapshotStatusErrorDeleting SnapshotStatusType = "error_deleting" // 云硬盘快照在删除过程中出现错误 - SnapshotStatusRollbacking SnapshotStatusType = "rollbacking" // 云硬盘快照处于正在回滚数据的过程中。 - SnapshotStatusBackingUp SnapshotStatusType = "backing-up" // 通过快照创建备份,快照状态就会变为backing-up -) - -type Metadata struct { - SystemEnableActive string `json:"__system__enableActive"` // 如果为true。则表明是系统盘快照 -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html -type SSnapshot struct { - multicloud.SResourceBase - multicloud.HcsTags - region *SRegion - - Metadata Metadata `json:"metadata"` - CreatedAt string `json:"created_at"` - Description string `json:"description"` - Id string `json:"id"` - Name string `json:"name"` - OSExtendedSnapshotAttributesProgress string `json:"os-extended-snapshot-attributes:progress"` - OSExtendedSnapshotAttributesProjectId string `json:"os-extended-snapshot-attributes:project_id"` - Size int32 `json:"size"` // GB - Status string `json:"status"` - UpdatedAt string `json:"updated_at"` - VolumeId string `json:"volume_id"` -} - -func (self *SSnapshot) GetId() string { - return self.Id -} - -func (self *SSnapshot) GetName() string { - return self.Name -} - -func (self *SSnapshot) GetGlobalId() string { - return self.Id -} - -func (self *SSnapshot) GetStatus() string { - switch SnapshotStatusType(self.Status) { - case SnapshotStatusAvailable: - return api.SNAPSHOT_READY - case SnapshotStatusCreating: - return api.SNAPSHOT_CREATING - case SnapshotStatusDeleting: - return api.SNAPSHOT_DELETING - case SnapshotStatusErrorDeleting, SnapshotStatusError: - return api.SNAPSHOT_FAILED - case SnapshotStatusRollbacking: - return api.SNAPSHOT_ROLLBACKING - default: - return api.SNAPSHOT_UNKNOWN - } -} - -func (self *SSnapshot) Refresh() error { - ret, err := self.region.GetSnapshot(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, ret) -} - -func (self *SSnapshot) GetSizeMb() int32 { - return self.Size * 1024 -} - -func (self *SSnapshot) GetDiskId() string { - return self.VolumeId -} - -func (self *SSnapshot) GetDiskType() string { - if self.Metadata.SystemEnableActive == "true" { - return api.DISK_TYPE_SYS - } - return api.DISK_TYPE_DATA -} - -func (self *SSnapshot) Delete() error { - return self.region.DeleteSnapshot(self.Id) -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408627.html -func (self *SRegion) GetSnapshots(diskId string, name string) ([]SSnapshot, error) { - params := url.Values{} - if len(diskId) > 0 { - params.Set("volume_id", diskId) - } - - if len(name) > 0 { - params.Set("name", name) - } - ret := []SSnapshot{} - return ret, self.evsList("snapshots", params, &ret) -} - -func (self *SRegion) GetSnapshot(id string) (*SSnapshot, error) { - ret := &SSnapshot{region: self} - res := fmt.Sprintf("snapshots/%s", id) - return ret, self.evsGet(res, ret) -} - -// 不能删除以autobk_snapshot_为前缀的快照。 -// 当快照状态为available、error状态时,才可以删除。 -func (self *SRegion) DeleteSnapshot(id string) error { - res := fmt.Sprintf("snapshots/%s", id) - return self.evsDelete(res) -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html -// 目前已设置force字段。云硬盘处于挂载状态时,能强制创建快照。 -func (self *SRegion) CreateSnapshot(diskId, name, desc string) (*SSnapshot, error) { - params := map[string]interface{}{ - "snapshot": map[string]interface{}{ - "name": name, - "description": desc, - "volume_id": diskId, - "force": true, - }, - } - ret := &SSnapshot{region: self} - return ret, self.evsCreate("snapshots", params, ret) -} - -func (self *SSnapshot) GetProjectId() string { - return "" -} - -func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := self.GetSnapshots("", "") - if err != nil { - return nil, errors.Wrapf(err, "GetSnapshots") - } - ret := []cloudprovider.ICloudSnapshot{} - for i := 0; i < len(snapshots); i += 1 { - snapshots[i].region = self - ret = append(ret, &snapshots[i]) - } - return ret, nil -} - -func (self *SRegion) GetISnapshotById(id string) (cloudprovider.ICloudSnapshot, error) { - ret, err := self.GetSnapshot(id) - if err != nil { - return nil, err - } - return ret, nil -} diff --git a/pkg/multicloud/hcs/storage.go b/pkg/multicloud/hcs/storage.go deleted file mode 100644 index 26400473e8..0000000000 --- a/pkg/multicloud/hcs/storage.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - multicloud.SStorageBase - multicloud.HuaweiTags - - zone *SZone - storageType string // volume_type 目前支持“SSD”,“SAS”和“SATA”三种 -} - -func (self *SStorage) GetId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetName() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetGlobalId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - cache := &SStoragecache{region: self.zone.region} - return cache -} - -func (self *SStorage) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := self.zone.region.GetDisks(self.zone.GetId()) - if err != nil { - return nil, err - } - - // 按storage type 过滤出disk - filtedDisks := make([]SDisk, 0) - for i := range disks { - disk := disks[i] - if disk.VolumeType == self.storageType { - filtedDisks = append(filtedDisks, disk) - } - } - - idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) - for i := 0; i < len(filtedDisks); i += 1 { - filtedDisks[i].region = self.zone.region - idisks[i] = &filtedDisks[i] - } - return idisks, nil -} - -func (self *SStorage) GetStorageType() string { - return self.storageType -} - -func (self *SStorage) GetMediumType() string { - if self.storageType == api.STORAGE_HUAWEI_SSD { - return api.DISK_TYPE_SSD - } - return api.DISK_TYPE_ROTATE -} - -func (self *SStorage) GetCapacityMB() int64 { - return 0 // unlimited -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - conf := jsonutils.NewDict() - return conf -} - -func (self *SStorage) GetEnabled() bool { - return true -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - disk, err := self.zone.region.CreateDisk(self.zone.GetId(), self.storageType, conf.Name, conf.SizeGb, "", conf.Desc, conf.ProjectId) - if err != nil { - return nil, errors.Wrapf(err, "CreateDisk") - } - return disk, nil -} - -func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - disk, err := self.zone.region.GetDisk(id) - if err != nil { - return nil, err - } - return disk, nil -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} diff --git a/pkg/multicloud/hcs/storagecache.go b/pkg/multicloud/hcs/storagecache.go deleted file mode 100644 index e3fb0e6dc9..0000000000 --- a/pkg/multicloud/hcs/storagecache.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "context" - "fmt" - "math" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "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" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion -} - -func GetBucketName(regionId string, imageId string) string { - return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), imageId) -} - -func (self *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) -} - -func (self *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) -} - -func (self *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetGlobalId()) -} - -func (self *SStoragecache) GetStatus() string { - return "available" -} - -func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - imagesSelf, err := self.region.GetImages("", ImageOwnerSelf, "", EnvFusionCompute) - if err != nil { - return nil, errors.Wrapf(err, "GetImages") - } - - ret := []cloudprovider.ICloudImage{} - for i := range imagesSelf { - imagesSelf[i].cache = self - ret = append(ret, &imagesSelf[i]) - } - return ret, nil -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - image, err := self.region.GetImage(extId) - if err != nil { - return nil, errors.Wrap(err, "self.region.GetImage") - } - image.cache = self - return image, nil -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -// 目前支持使用vhd、zvhd、vmdk、qcow2、raw、zvhd2、vhdx、qcow、vdi或qed格式镜像文件创建私有镜像。 -// 快速通道功能可快速完成镜像制作,但镜像文件需转换为raw或zvhd2格式并完成镜像优化。 -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0083905788.html -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.cache = self - iimage := make([]cloudprovider.ICloudImage, 1) - iimage[0] = image - 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) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return self.uploadImage(ctx, userCred, image, callback) -} - -func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - bucketName := GetBucketName(self.region.GetId(), image.ImageId) - - exist, _ := self.region.IBucketExist(bucketName) - if !exist { - err := self.region.CreateIBucket(bucketName, "", "") - if err != nil { - return "", errors.Wrap(err, "CreateIBucket") - } - } - defer self.region.DeleteIBucket(bucketName) - - // upload to huawei cloud - s := auth.GetAdminSession(ctx, options.Options.Region) - meta, reader, sizeByte, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) - if err != nil { - return "", errors.Wrap(err, "Images.Download") - } - log.Debugf("Images meta data %s", meta) - - minDiskMB, _ := meta.Int("min_disk") - minDiskGB := int64(math.Ceil(float64(minDiskMB) / 1024)) - // 在使用OBS桶的外部镜像文件制作镜像时生效且为必选字段。取值为40~1024GB。 - if minDiskGB < 40 { - minDiskGB = 40 - } else if minDiskGB > 1024 { - minDiskGB = 1024 - } - - bucket, err := self.region.GetIBucketByName(bucketName) - if err != nil { - return "", errors.Wrapf(err, "GetIBucketByName %s", bucketName) - } - - body := multicloud.NewProgress(sizeByte, 95, reader, callback) - err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeByte, "", "", nil, false) - if err != nil { - return "", errors.Wrap(err, "cloudprovider.UploadObject") - } - - defer bucket.DeleteObject(context.Background(), image.ImageId) - - // check image name, avoid name conflict - imageBaseName := image.ImageId - if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { - imageBaseName = fmt.Sprintf("img%s", image.ImageId) - } - imageName := imageBaseName - nameIdx := 1 - - for { - _, err = self.region.GetImageByName(imageName) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - break - } else { - return "", err - } - } - - imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) - nameIdx += 1 - log.Debugf("uploadImage Match remote name %s", imageName) - } - - err = self.region.ImportImageJob(imageName, image.OsDistribution, image.OsVersion, image.OsArch, bucketName, image.ImageId, int64(minDiskGB)) - if err != nil { - return "", errors.Wrapf(err, "ImportImageJob") - } - - if callback != nil { - callback(100) - } - return "", cloudprovider.ErrNotImplemented -} - -func (self *SRegion) getStoragecache() *SStoragecache { - return &SStoragecache{region: self} -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html -func (self *SRegion) createIImage(snapshotId, imageName, imageDesc string) (string, error) { - snapshot, err := self.GetSnapshot(snapshotId) - if err != nil { - return "", err - } - - disk, err := self.GetDisk(snapshot.VolumeId) - if err != nil { - return "", err - } - - if disk.GetDiskType() != api.DISK_TYPE_SYS { - return "", fmt.Errorf("disk type err, expected disk type %s", api.DISK_TYPE_SYS) - } - - if len(disk.Attachments) == 0 { - return "", fmt.Errorf("disk is not attached.") - } - - params := map[string]interface{}{ - "name": imageName, - "description": imageDesc, - "instance_id": disk.Attachments[0].ServerId, - } - - ret := struct { - ImageId string - }{} - err = self.imsPerform("cloudimages", "action", params, &ret) - if err != nil { - return "", err - } - return ret.ImageId, nil -} - -func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - return []cloudprovider.ICloudStoragecache{storageCache}, nil -} - -func (self *SRegion) GetIStoragecacheById(idstr string) (cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - if storageCache.GetGlobalId() == idstr { - return storageCache, nil - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/hcs/vpc.go b/pkg/multicloud/hcs/vpc.go deleted file mode 100644 index 407c67c275..0000000000 --- a/pkg/multicloud/hcs/vpc.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - multicloud.HcsTags - - region *SRegion - - Id string - Name string - CIDR string - Status string - EnterpriseProjectId string -} - -func (self *SRegion) GetVpcs() ([]SVpc, error) { - ret := []SVpc{} - return ret, self.vpcList("vpcs", nil, &ret) -} - -func (self *SVpc) GetId() string { - return self.Id -} - -func (self *SVpc) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.Id -} - -func (self *SVpc) GetGlobalId() string { - return self.Id -} - -func (self *SVpc) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} - -func (self *SVpc) Refresh() error { - ret, err := self.region.GetVpc(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, ret) -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetIsDefault() bool { - return false -} - -func (self *SVpc) GetCidrBlock() string { - return self.CIDR -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - wire := &SWire{region: self.region, vpc: self} - return []cloudprovider.ICloudWire{wire}, nil -} - -func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { - wires, err := self.GetIWires() - if err != nil { - return nil, err - } - for i := range wires { - if wires[i].GetGlobalId() == id { - return wires[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := self.region.GetSecurityGroups(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudSecurityGroup{} - for i := range secgroups { - secgroups[i].region = self.region - ret = append(ret, &secgroups[i]) - } - return ret, nil -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - rtbs, err := self.region.GetRouteTables(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudRouteTable{} - for i := range rtbs { - rtbs[i].vpc = self - ret = append(ret, &rtbs[i]) - } - return ret, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - rtb, err := self.region.GetRouteTable(routeTableId) - if err != nil { - return nil, err - } - rtb.vpc = self - return rtb, nil -} - -func (self *SVpc) Delete() error { - return self.region.DeleteVpc(self.GetId()) -} - -func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { - nats, err := self.region.GetNatGateways(self.GetId()) - if err != nil { - return nil, err - } - ret := make([]cloudprovider.ICloudNatGateway, len(nats)) - for i := 0; i < len(nats); i++ { - nats[i].region = self.region - ret[i] = &nats[i] - } - return ret, nil -} - -func (self *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPCs, err := self.getVpcPeeringConnections() - if err != nil { - return nil, errors.Wrap(err, "self.getVpcPeeringConnections()") - } - ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} - for i := range svpcPCs { - ivpcPCs = append(ivpcPCs, &svpcPCs[i]) - } - return ivpcPCs, nil -} - -func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPCs, err := self.getAccepterVpcPeeringConnections() - if err != nil { - return nil, errors.Wrap(err, "self.getAccepterVpcPeeringConnections()") - } - ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} - for i := range svpcPCs { - ivpcPCs = append(ivpcPCs, &svpcPCs[i]) - } - return ivpcPCs, nil -} - -func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPC, err := self.getVpcPeeringConnectionById(id) - if err != nil { - return nil, errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) - } - return svpcPC, nil -} - -func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPC, err := self.region.CreateVpcPeering(self.GetId(), opts) - if err != nil { - return nil, errors.Wrapf(err, "self.region.CreateVpcPeering(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) - } - svpcPC.vpc = self - return svpcPC, nil -} - -func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { - vpcPC, err := self.getVpcPeeringConnectionById(id) - if err != nil { - return errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) - } - if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_ACTIVE { - return nil - } - if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN { - return errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcPC: %s", jsonutils.Marshal(vpcPC).String()) - } - err = self.region.AcceptVpcPeering(id) - if err != nil { - return errors.Wrapf(err, "self.region.AcceptVpcPeering(%s)", id) - } - return nil -} - -func (self *SVpc) GetAuthorityOwnerId() string { - return self.region.client.projectId -} - -func (self *SRegion) GetVpc(id string) (*SVpc, error) { - vpc := &SVpc{region: self} - res := fmt.Sprintf("vpcs/%s", id) - return vpc, self.vpcGet(res, vpc) -} - -func (self *SRegion) DeleteVpc(id string) error { - if id != "default" { - secgroups, err := self.GetSecurityGroups(id) - if err != nil { - return errors.Wrap(err, "GetSecurityGroups") - } - for _, secgroup := range secgroups { - err = self.DeleteSecurityGroup(secgroup.Id) - if err != nil { - return errors.Wrapf(err, "DeleteSecurityGroup(%s)", secgroup.Id) - } - } - } - res := fmt.Sprintf("vpcs/%s", id) - return self.vpcDelete(res) -} - -func (self *SRegion) CreateVpc(name, cidr, desc string) (*SVpc, error) { - params := map[string]interface{}{ - "vpc": map[string]string{ - "name": name, - "cidr": cidr, - "description": desc, - }, - } - vpc := &SVpc{region: self} - return vpc, self.vpcCreate("vpcs", params, vpc) -} - -func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - vpcs, err := self.GetVpcs() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudVpc{} - for i := range vpcs { - vpcs[i].region = self - ret = append(ret, &vpcs[i]) - } - return ret, nil -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - vpc, err := self.GetVpc(id) - if err != nil { - return nil, err - } - vpc.region = self - return vpc, nil -} - -func (self *SVpc) getVpcPeeringConnections() ([]SVpcPeering, error) { - svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) - } - vpcPCs := []SVpcPeering{} - for i := range svpcPeerings { - if svpcPeerings[i].GetVpcId() == self.GetId() { - svpcPeerings[i].vpc = self - vpcPCs = append(vpcPCs, svpcPeerings[i]) - } - } - return vpcPCs, nil -} - -func (self *SVpc) getAccepterVpcPeeringConnections() ([]SVpcPeering, error) { - svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) - } - vpcPCs := []SVpcPeering{} - for i := range svpcPeerings { - if svpcPeerings[i].GetPeerVpcId() == self.GetId() { - svpcPeerings[i].vpc = self - vpcPCs = append(vpcPCs, svpcPeerings[i]) - } - } - return vpcPCs, nil -} - -func (self *SVpc) getVpcPeeringConnectionById(id string) (*SVpcPeering, error) { - svpcPC, err := self.region.GetVpcPeering(id) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetVpcPeering(%s)", id) - } - svpcPC.vpc = self - return svpcPC, nil -} diff --git a/pkg/multicloud/hcs/vpc_peering.go b/pkg/multicloud/hcs/vpc_peering.go deleted file mode 100644 index 5025cf5da3..0000000000 --- a/pkg/multicloud/hcs/vpc_peering.go +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type RequestVpcInfo struct { - VpcId string `json:"vpc_id"` - TenantId string `json:"tenant_id"` -} - -type AcceptVpcInfo struct { - VpcId string `json:"vpc_id"` - TenantId string `json:"tenant_id"` -} - -type SVpcPeering struct { - multicloud.SResourceBase - multicloud.HuaweiTags - vpc *SVpc - - RequestVpcInfo RequestVpcInfo `json:"request_vpc_info"` - AcceptVpcInfo AcceptVpcInfo `json:"accept_vpc_info"` - Name string `json:"name"` - Id string `json:"id"` - Status string `json:"status"` -} - -func (self *SRegion) GetVpcPeerings(vpcId string) ([]SVpcPeering, error) { - params := url.Values{} - if len(vpcId) > 0 { - params.Set("vpc_id", vpcId) - } - ret := []SVpcPeering{} - return ret, self.list("vpc", "v2.0", "vpc/peerings", params, &ret) -} - -func (self *SRegion) GetVpcPeering(id string) (*SVpcPeering, error) { - ret := SVpcPeering{} - resource := fmt.Sprintf("vpc/peerings/%s", id) - return &ret, self.get("vpc", "v2.0", resource, &ret) -} - -func (self *SRegion) CreateVpcPeering(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPeering, error) { - params := map[string]interface{}{ - "peering": map[string]interface{}{ - "name": opts.Name, - "request_vpc_info": map[string]interface{}{ - "vpc_id": vpcId, - "tenant_id": self.client.projectId, - }, - "accept_vpc_info": map[string]interface{}{ - "vpc_id": opts.PeerVpcId, - "tenant_id": opts.PeerAccountId, - }, - }, - } - ret := &SVpcPeering{} - return ret, self.create("vpc", "v2.0", "vpc/peerings", params, ret) -} - -func (self *SRegion) AcceptVpcPeering(id string) error { - res := fmt.Sprintf("vpc/peerings/%s/accept", id) - return self.update("vpc", "v2.0", res, nil) -} - -func (self *SRegion) DeleteVpcPeering(id string) error { - res := fmt.Sprintf("vpc/peerings/%s", id) - return self.delete("vpc", "v2.0", res) -} - -func (self *SVpcPeering) GetId() string { - return self.Id -} - -func (self *SVpcPeering) GetName() string { - return self.Name -} - -func (self *SVpcPeering) GetGlobalId() string { - return self.GetId() -} - -func (self *SVpcPeering) GetStatus() string { - switch self.Status { - case "PENDING_ACCEPTANCE": - return api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT - case "ACTIVE": - return api.VPC_PEERING_CONNECTION_STATUS_ACTIVE - default: - return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN - } -} - -func (self *SVpcPeering) Refresh() error { - peer, err := self.vpc.region.GetVpcPeering(self.Id) - if err != nil { - return errors.Wrapf(err, "self.region.GetVpcPeering(%s)", self.Id) - } - return jsonutils.Update(self, peer) -} - -func (self *SVpcPeering) GetVpcId() string { - return self.RequestVpcInfo.VpcId -} - -func (self *SVpcPeering) GetPeerVpcId() string { - return self.AcceptVpcInfo.VpcId -} - -func (self *SVpcPeering) GetPeerAccountId() string { - return self.AcceptVpcInfo.TenantId -} - -func (self *SVpcPeering) GetEnabled() bool { - return true -} - -func (self *SVpcPeering) Delete() error { - return self.vpc.region.DeleteVpcPeering(self.Id) -} diff --git a/pkg/multicloud/hcs/wire.go b/pkg/multicloud/hcs/wire.go deleted file mode 100644 index d9742e9407..0000000000 --- a/pkg/multicloud/hcs/wire.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// 华为云的子网有点特殊。子网在整个region可用。 -type SWire struct { - multicloud.SResourceBase - multicloud.HcsTags - region *SRegion - vpc *SVpc -} - -func (self *SWire) GetId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) -} - -func (self *SWire) GetName() string { - return self.GetId() -} - -func (self *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - return nil -} - -func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - nets, err := self.region.GetNetwroks(self.vpc.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNetwork{} - for i := range nets { - nets[i].wire = self - ret = append(ret, &nets[i]) - } - return ret, nil -} - -func (self *SWire) GetBandwidth() int { - return 10000 -} - -func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { - net, err := self.region.GetNetwork(id) - if err != nil { - return nil, err - } - net.wire = self - return net, nil -} - -/* -华为云子网可用区,类似一个zone标签。即使指定了zone子网在整个region依然是可用。 -通过华为web控制台创建子网需要指定可用区。这里是不指定的。 -*/ -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - net, err := self.region.CreateNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc) - if err != nil { - return nil, errors.Wrapf(err, "CreateNetwork") - } - net.wire = self - return net, nil -} - -func getDefaultGateWay(cidr string) (string, error) { - pref, err := netutils.NewIPV4Prefix(cidr) - if err != nil { - return "", errors.Wrap(err, "getDefaultGateWay.NewIPV4Prefix") - } - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - return startIp.String(), nil -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html -// cidr 掩码长度不能大于28 -func (self *SRegion) CreateNetwork(vpcId string, name string, cidr string, desc string) (*SNetwork, error) { - gateway, err := getDefaultGateWay(cidr) - if err != nil { - return nil, err - } - - params := map[string]interface{}{ - "subnet": map[string]interface{}{ - "name": name, - "vpc_id": vpcId, - "cidr": cidr, - "gateway_ip": gateway, - }, - } - ret := &SNetwork{} - return ret, self.vpcCreate("subnets", params, ret) -} diff --git a/pkg/multicloud/hcs/zone.go b/pkg/multicloud/hcs/zone.go deleted file mode 100644 index 7ea1dd01a3..0000000000 --- a/pkg/multicloud/hcs/zone.go +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcs - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SZone struct { - multicloud.SResourceBase - multicloud.HcsTags - - region *SRegion - ZoneName string - ZoneState struct { - Available bool - } -} - -func (self *SRegion) GetZones() ([]SZone, error) { - zones := []SZone{} - return zones, self.ecsList("os-availability-zone", nil, &zones) -} - -func (self *SZone) getStorageType() ([]string, error) { - return self.region.GetZoneSupportedDiskTypes(self.GetId()) -} - -func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) { - dts, err := self.GetDiskTypes() - if err != nil { - return nil, errors.Wrap(err, "GetDiskTypes") - } - - ret := []string{} - for i := range dts { - if dts[i].IsAvaliableInZone(zoneId) { - ret = append(ret, dts[i].Name) - } - } - return ret, nil -} - -func (self *SZone) GetId() string { - return self.ZoneName -} - -func (self *SZone) GetName() string { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HCS_CN, self.ZoneName) -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HCS_EN, self.ZoneName) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SZone) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneName) -} - -func (self *SZone) GetStatus() string { - return api.ZONE_ENABLE -} - -func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - host := &SHost{zone: self} - return []cloudprovider.ICloudHost{host}, nil -} - -func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - host := &SHost{zone: self} - if host.GetGlobalId() == id { - return host, nil - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := self.getStorageType() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStorage{} - for i := range storages { - ret = append(ret, &SStorage{zone: self, storageType: storages[i]}) - } - return ret, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storages, err := self.GetIStorages() - if err != nil { - return nil, err - } - for i := 0; i < len(storages); i += 1 { - if storages[i].GetGlobalId() == id { - return storages[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { - vpcs, err := self.region.GetVpcs() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudWire{} - for i := range vpcs { - wire := &SWire{region: self.region, vpc: &vpcs[i]} - ret = append(ret, wire) - } - return ret, nil -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - zones, err := self.GetZones() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudZone{} - for i := 0; i < len(zones); i++ { - zones[i].region = self - ret = append(ret, &zones[i]) - } - if len(zones) == 0 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "no availabe zone found") - } - return ret, nil -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - if izones[i].GetGlobalId() == id { - return izones[i], 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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetZoneById(id string) (*SZone, error) { - zones, err := self.GetZones() - if err != nil { - return nil, err - } - for i := 0; i < len(zones); i += 1 { - zones[i].region = self - if zones[i].GetId() == id || zones[i].GetGlobalId() == id { - return &zones[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} diff --git a/pkg/multicloud/hcso/bucket.go b/pkg/multicloud/hcso/bucket.go deleted file mode 100644 index 0975c474d5..0000000000 --- a/pkg/multicloud/hcso/bucket.go +++ /dev/null @@ -1,773 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - "fmt" - "io" - "net/http" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - "yunion.io/x/s3cli" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/huawei/obs" -) - -type SBucket struct { - multicloud.SBaseBucket - multicloud.HuaweiTags - - region *SRegion - - Name string - Location string - CreationDate time.Time -} - -func (b *SBucket) GetProjectId() string { - resp, err := b.region.HeadBucket(b.Name) - if err != nil { - return "" - } - epid, _ := resp.ResponseHeaders["epid"] - if len(epid) > 0 { - return epid[0] - } - return "" -} - -func (b *SBucket) GetGlobalId() string { - return b.Name -} - -func (b *SBucket) GetName() string { - return b.Name -} - -func (b *SBucket) GetLocation() string { - return b.Location -} - -func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { - return b.region -} - -func (b *SBucket) GetCreatedAt() time.Time { - return b.CreationDate -} - -/* - service returned error: Status=405 Method Not Allowed, Code=MethodNotAllowed, - Message=The specified method is not allowed against this resource., - RequestId=00000175B0E9D138440B9EF092DF8A7A -https://support.huaweicloud.com/productdesc-modelarts/modelarts_01_0017.html -*/ -func (b *SBucket) GetStorageClass() string { - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("b.region.getOBSClient error %s", err) - return "" - } - output, err := obscli.GetBucketStoragePolicy(b.Name) - if err != nil { - log.Errorf("obscli.GetBucketStoragePolicy error %s", err) - return "" - } - return output.StorageClass -} - -func obsAcl2CannedAcl(acls []obs.Grant) cloudprovider.TBucketACLType { - switch { - case len(acls) == 1: - if acls[0].Grantee.URI == "" && acls[0].Permission == s3cli.PERMISSION_FULL_CONTROL { - return cloudprovider.ACLPrivate - } - case len(acls) == 2: - for _, g := range acls { - if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_AUTH_USERS && g.Permission == s3cli.PERMISSION_READ { - return cloudprovider.ACLAuthRead - } - if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_READ { - return cloudprovider.ACLPublicRead - } - } - case len(acls) == 3: - for _, g := range acls { - if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_WRITE { - return cloudprovider.ACLPublicReadWrite - } - } - } - return cloudprovider.ACLUnknown -} - -func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("b.region.getOBSClient error %s", err) - return acl - } - output, err := obscli.GetBucketAcl(b.Name) - if err != nil { - log.Errorf("obscli.GetBucketAcl error %s", err) - return acl - } - acl = obsAcl2CannedAcl(output.Grants) - return acl -} - -func (b *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "b.region.getOBSClient") - } - input := &obs.SetBucketAclInput{} - input.Bucket = b.Name - input.ACL = obs.AclType(string(acl)) - _, err = obscli.SetBucketAcl(input) - if err != nil { - return errors.Wrap(err, "obscli.SetBucketAcl") - } - return nil -} - -func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { - return []cloudprovider.SBucketAccessUrl{ - { - Url: fmt.Sprintf("https://%s.%s", b.Name, b.region.getOBSEndpoint()), - Description: "bucket url", - Primary: true, - }, - { - Url: fmt.Sprintf("https://%s/%s", b.region.getOBSEndpoint(), b.Name), - Description: "obs url", - }, - } -} - -func (b *SBucket) GetStats() cloudprovider.SBucketStats { - stats := cloudprovider.SBucketStats{} - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("b.region.getOBSClient error %s", err) - stats.SizeBytes = -1 - stats.ObjectCount = -1 - return stats - } - output, err := obscli.GetBucketStorageInfo(b.Name) - if err != nil { - log.Errorf("obscli.GetBucketStorageInfo error %s", err) - stats.SizeBytes = -1 - stats.ObjectCount = -1 - return stats - } - stats.SizeBytes = output.Size - stats.ObjectCount = output.ObjectNumber - return stats -} - -func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { - result := cloudprovider.SListObjectResult{} - obscli, err := b.region.getOBSClient() - if err != nil { - return result, errors.Wrap(err, "GetOBSClient") - } - input := &obs.ListObjectsInput{} - input.Bucket = b.Name - if len(prefix) > 0 { - input.Prefix = prefix - } - if len(marker) > 0 { - input.Marker = marker - } - if len(delimiter) > 0 { - input.Delimiter = delimiter - } - if maxCount > 0 { - input.MaxKeys = maxCount - } - oResult, err := obscli.ListObjects(input) - if err != nil { - return result, errors.Wrap(err, "ListObjects") - } - result.Objects = make([]cloudprovider.ICloudObject, 0) - for _, object := range oResult.Contents { - obj := &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - StorageClass: string(object.StorageClass), - Key: object.Key, - SizeBytes: object.Size, - ETag: object.ETag, - LastModified: object.LastModified, - }, - } - result.Objects = append(result.Objects, obj) - } - if oResult.CommonPrefixes != nil { - result.CommonPrefixes = make([]cloudprovider.ICloudObject, 0) - for _, commonPrefix := range oResult.CommonPrefixes { - obj := &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - Key: commonPrefix, - }, - } - result.CommonPrefixes = append(result.CommonPrefixes, obj) - } - } - result.IsTruncated = oResult.IsTruncated - result.NextMarker = oResult.NextMarker - return result, nil -} - -func (b *SBucket) PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.PutObjectInput{} - input.Bucket = b.Name - input.Key = key - input.Body = reader - - if sizeBytes > 0 { - input.ContentLength = sizeBytes - } - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return err - } - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.ACL = obs.AclType(string(cannedAcl)) - if meta != nil { - val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) - if len(val) > 0 { - input.ContentType = val - } - val = meta.Get(cloudprovider.META_HEADER_CONTENT_MD5) - if len(val) > 0 { - input.ContentMD5 = val - } - extraMeta := make(map[string]string) - for k, v := range meta { - if utils.IsInStringArray(k, []string{ - cloudprovider.META_HEADER_CONTENT_TYPE, - cloudprovider.META_HEADER_CONTENT_MD5, - }) { - continue - } - if len(v[0]) > 0 { - extraMeta[k] = v[0] - } - } - input.Metadata = extraMeta - } - _, err = obscli.PutObject(input) - if err != nil { - return errors.Wrap(err, "PutObject") - } - return nil -} - -func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - - input := &obs.InitiateMultipartUploadInput{} - input.Bucket = b.Name - input.Key = key - if meta != nil { - val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) - if len(val) > 0 { - input.ContentType = val - } - extraMeta := make(map[string]string) - for k, v := range meta { - if utils.IsInStringArray(k, []string{ - cloudprovider.META_HEADER_CONTENT_TYPE, - }) { - continue - } - if len(v[0]) > 0 { - extraMeta[k] = v[0] - } - } - input.Metadata = extraMeta - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.ACL = obs.AclType(string(cannedAcl)) - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return "", errors.Wrap(err, "str2StorageClass") - } - } - output, err := obscli.InitiateMultipartUpload(input) - if err != nil { - return "", errors.Wrap(err, "InitiateMultipartUpload") - } - - return output.UploadId, nil -} - -func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, part io.Reader, partSize int64, offset, totalSize int64) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - - input := &obs.UploadPartInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - input.PartNumber = partIndex - input.PartSize = partSize - input.Body = part - output, err := obscli.UploadPart(input) - if err != nil { - return "", errors.Wrap(err, "UploadPart") - } - - return output.ETag, nil -} - -func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.CompleteMultipartUploadInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - parts := make([]obs.Part, len(partEtags)) - for i := range partEtags { - parts[i] = obs.Part{ - PartNumber: i + 1, - ETag: partEtags[i], - } - } - input.Parts = parts - _, err = obscli.CompleteMultipartUpload(input) - if err != nil { - return errors.Wrap(err, "CompleteMultipartUpload") - } - - return nil -} - -func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - input := &obs.AbortMultipartUploadInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - - _, err = obscli.AbortMultipartUpload(input) - if err != nil { - return errors.Wrap(err, "AbortMultipartUpload") - } - - return nil -} - -func (b *SBucket) DeleteObject(ctx context.Context, key string) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.DeleteObjectInput{} - input.Bucket = b.Name - input.Key = key - _, err = obscli.DeleteObject(input) - if err != nil { - return errors.Wrap(err, "DeleteObject") - } - return nil -} - -func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - input := obs.CreateSignedUrlInput{} - input.Bucket = b.Name - input.Key = key - input.Expires = int(expire / time.Second) - switch method { - case "GET": - input.Method = obs.HttpMethodGet - case "PUT": - input.Method = obs.HttpMethodPut - case "DELETE": - input.Method = obs.HttpMethodDelete - default: - return "", errors.Error("unsupported method") - } - output, err := obscli.CreateSignedUrl(&input) - return output.SignedUrl, nil -} - -func (b *SBucket) LimitSupport() cloudprovider.SBucketStats { - return cloudprovider.SBucketStats{ - SizeBytes: 1, - ObjectCount: -1, - } -} - -func (b *SBucket) GetLimit() cloudprovider.SBucketStats { - stats := cloudprovider.SBucketStats{} - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("getOBSClient error %s", err) - return stats - } - output, err := obscli.GetBucketQuota(b.Name) - if err != nil { - return stats - } - stats.SizeBytes = output.Quota - return stats -} - -func (b *SBucket) SetLimit(limit cloudprovider.SBucketStats) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "getOBSClient") - } - input := &obs.SetBucketQuotaInput{} - input.Bucket = b.Name - input.Quota = limit.SizeBytes - _, err = obscli.SetBucketQuota(input) - if err != nil { - return errors.Wrap(err, "SetBucketQuota") - } - return nil -} - -func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.CopyObjectInput{} - input.Bucket = b.Name - input.Key = destKey - input.CopySourceBucket = srcBucket - input.CopySourceKey = srcKey - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return err - } - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.ACL = obs.AclType(string(cannedAcl)) - if meta != nil { - val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) - if len(val) > 0 { - input.ContentType = val - } - extraMeta := make(map[string]string) - for k, v := range meta { - if utils.IsInStringArray(k, []string{ - cloudprovider.META_HEADER_CONTENT_TYPE, - }) { - continue - } - if len(v[0]) > 0 { - extraMeta[k] = v[0] - } - } - input.Metadata = extraMeta - input.MetadataDirective = obs.ReplaceMetadata - } else { - input.MetadataDirective = obs.CopyMetadata - } - _, err = obscli.CopyObject(input) - if err != nil { - return errors.Wrap(err, "obscli.CopyObject") - } - return nil -} - -func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - input := &obs.GetObjectInput{} - input.Bucket = b.Name - input.Key = key - if rangeOpt != nil { - input.RangeStart = rangeOpt.Start - input.RangeEnd = rangeOpt.End - } - output, err := obscli.GetObject(input) - if err != nil { - return nil, errors.Wrap(err, "obscli.GetObject") - } - return output.Body, nil -} - -func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - input := &obs.CopyPartInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - input.PartNumber = partIndex - input.CopySourceBucket = srcBucket - input.CopySourceKey = srcKey - input.CopySourceRangeStart = srcOffset - input.CopySourceRangeEnd = srcOffset + srcLength - 1 - output, err := obscli.CopyPart(input) - if err != nil { - return "", errors.Wrap(err, "CopyPart") - } - return output.ETag, nil -} - -func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - obsWebConf := obs.SetBucketWebsiteConfigurationInput{} - obsWebConf.Bucket = b.Name - obsWebConf.BucketWebsiteConfiguration = obs.BucketWebsiteConfiguration{ - IndexDocument: obs.IndexDocument{Suffix: websitConf.Index}, - ErrorDocument: obs.ErrorDocument{Key: websitConf.ErrorDocument}, - } - _, err = obscli.SetBucketWebsiteConfiguration(&obsWebConf) - if err != nil { - return errors.Wrap(err, "obscli.SetBucketWebsiteConfiguration(&obsWebConf)") - } - return nil -} - -func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { - result := cloudprovider.SBucketWebsiteConf{} - obscli, err := b.region.getOBSClient() - if err != nil { - return result, errors.Wrap(err, "GetOBSClient") - } - out, err := obscli.GetBucketWebsiteConfiguration(b.Name) - if out == nil { - return result, nil - } - result.Index = out.IndexDocument.Suffix - result.ErrorDocument = out.ErrorDocument.Key - endpoint := b.region.client.endpoints.GetEndpoint(b.region.client.cpcfg.DefaultRegion, "obs-website", b.region.GetId()) - result.Url = fmt.Sprintf("https://%s.%s", b.Name, endpoint) - return result, nil -} - -func (b *SBucket) DeleteWebSiteConf() error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - _, err = obscli.DeleteBucketWebsiteConfiguration(b.Name) - if err != nil { - return errors.Wrapf(err, "obscli.DeleteBucketWebsiteConfiguration(%s)", b.Name) - } - return nil -} - -func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - opts := []obs.CorsRule{} - for i := range rules { - opts = append(opts, obs.CorsRule{ - AllowedOrigin: rules[i].AllowedOrigins, - AllowedMethod: rules[i].AllowedMethods, - AllowedHeader: rules[i].AllowedHeaders, - MaxAgeSeconds: rules[i].MaxAgeSeconds, - ExposeHeader: rules[i].ExposeHeaders, - }) - } - - input := obs.SetBucketCorsInput{} - input.Bucket = b.Name - input.BucketCors.CorsRules = opts - _, err = obscli.SetBucketCors(&input) - if err != nil { - return errors.Wrapf(err, "obscli.SetBucketCors(%s)", jsonutils.Marshal(input).String()) - } - return nil -} - -func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - conf, err := obscli.GetBucketCors(b.Name) - if err != nil { - if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") { - return nil, errors.Wrapf(err, "obscli.GetBucketCors(%s)", b.Name) - } - } - if conf == nil { - return nil, nil - } - result := []cloudprovider.SBucketCORSRule{} - for i := range conf.CorsRules { - result = append(result, cloudprovider.SBucketCORSRule{ - AllowedOrigins: conf.CorsRules[i].AllowedOrigin, - AllowedMethods: conf.CorsRules[i].AllowedMethod, - AllowedHeaders: conf.CorsRules[i].AllowedHeader, - MaxAgeSeconds: conf.CorsRules[i].MaxAgeSeconds, - ExposeHeaders: conf.CorsRules[i].ExposeHeader, - Id: strconv.Itoa(i), - }) - } - return result, nil -} - -func (b *SBucket) DeleteCORS() error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - _, err = obscli.DeleteBucketCors(b.Name) - if err != nil { - return errors.Wrapf(err, "obscli.DeleteBucketCors(%s)", b.Name) - } - return nil -} - -func (b *SBucket) GetTags() (map[string]string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - tagresult, err := obscli.GetBucketTagging(b.Name) - if err != nil { - if strings.Contains(err.Error(), "404") { - return nil, nil - } - return nil, errors.Wrapf(err, "osscli.GetBucketTagging(%s)", b.Name) - } - result := map[string]string{} - for i := range tagresult.Tags { - result[tagresult.Tags[i].Key] = tagresult.Tags[i].Value - } - return result, nil -} - -func (b *SBucket) SetTags(tags map[string]string, replace bool) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - _, err = obscli.DeleteBucketTagging(b.Name) - if err != nil { - return errors.Wrapf(err, "DeleteBucketTagging") - } - - if len(tags) == 0 { - return nil - } - - input := obs.SetBucketTaggingInput{BucketTagging: obs.BucketTagging{}} - input.Bucket = b.Name - for k, v := range tags { - input.BucketTagging.Tags = append(input.BucketTagging.Tags, obs.Tag{Key: k, Value: v}) - } - - _, err = obscli.SetBucketTagging(&input) - if err != nil { - return errors.Wrapf(err, "obscli.SetBucketTagging(%s)", jsonutils.Marshal(input).String()) - } - return nil -} - -func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - result := []cloudprovider.SBucketMultipartUploads{} - - input := obs.ListMultipartUploadsInput{Bucket: b.Name} - keyMarker := "" - uploadIDMarker := "" - for { - if len(keyMarker) > 0 { - input.KeyMarker = keyMarker - } - if len(uploadIDMarker) > 0 { - input.UploadIdMarker = uploadIDMarker - } - - output, err := obscli.ListMultipartUploads(&input) - if err != nil { - return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") - } - for i := range output.Uploads { - temp := cloudprovider.SBucketMultipartUploads{ - ObjectName: output.Uploads[i].Key, - UploadID: output.Uploads[i].UploadId, - Initiator: output.Uploads[i].Initiator.DisplayName, - Initiated: output.Uploads[i].Initiated, - } - result = append(result, temp) - } - keyMarker = output.NextKeyMarker - uploadIDMarker = output.NextUploadIdMarker - if !output.IsTruncated { - break - } - } - - return result, nil -} diff --git a/pkg/multicloud/hcso/client/auth/credentials/doc.go b/pkg/multicloud/hcso/client/auth/credentials/doc.go deleted file mode 100644 index 31f6d5e737..0000000000 --- a/pkg/multicloud/hcso/client/auth/credentials/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 credentials // import "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth/credentials" diff --git a/pkg/multicloud/hcso/client/auth/doc.go b/pkg/multicloud/hcso/client/auth/doc.go deleted file mode 100644 index 20494bbc20..0000000000 --- a/pkg/multicloud/hcso/client/auth/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 auth // import "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth" diff --git a/pkg/multicloud/hcso/client/auth/signer.go b/pkg/multicloud/hcso/client/auth/signer.go deleted file mode 100644 index 123eadc2f9..0000000000 --- a/pkg/multicloud/hcso/client/auth/signer.go +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 auth - -import ( - "crypto/md5" - "crypto/sha256" - "encoding/hex" - "fmt" - "io/ioutil" - "sort" - "strings" - "time" - - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth/credentials" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth/signers" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/requests" -) - -type Signer interface { - GetName() string // 签名算法名称 - GetAccessKeyId() (accessKeyId string, err error) // 签名access key - GetSecretKey() (secretKey string, err error) // access secret - Sign(stringToSign, secretSuffix string) string // 生成签名结果 -} - -func NewSignerWithCredential(credential Credential) (signer Signer, err error) { - switch instance := credential.(type) { - case *credentials.AccessKeyCredential: - return signers.NewAccessKeySigner(instance), nil - default: - return nil, fmt.Errorf("unsupported credential error") - } -} - -// 对request进行签名 -func Sign(request requests.IRequest, signer Signer) (err error) { - return signRequest(request, signer) -} - -func signRequest(request requests.IRequest, signer Signer) error { - // https://support.huaweicloud.com/api-dis/dis_02_0508.html - // requestTime - reqTime := time.Now() - // 添加 必须的Headers - fillRequiredHeaders(request, reqTime) - // 计算CanonicalRequest - canonicalRequest := canonicalRequest(request) - // stringToSign - credentialScope := strings.Join([]string{ - formattedSignTime(reqTime, "Date"), - request.GetRegionId(), - request.GetProduct(), - "sdk_request", - }, "/") - stringToSign := strings.Join([]string{"SDK-HMAC-SHA256", - formattedSignTime(reqTime, "DateTime"), - credentialScope, - hashSha256([]byte(canonicalRequest)), - }, "\n") - // 计算SigningKey - secret, _ := signer.GetSecretKey() - signKey := getSigningKey(secret, formattedSignTime(reqTime, "Date"), - request.GetRegionId(), request.GetProduct()) - // 计算Signature - signature := signer.Sign(stringToSign, signKey) - accesskey, _ := signer.GetAccessKeyId() - addAuthorizationHeader(request, accesskey, credentialScope, signature) - return nil -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0132456728.html -// X-Project-Id 如果是专属云场景采用AK/SK 认证方式的接口请求或者多project场景采用AK/SK认证的接口请求则该字段必选。 -func fillRequiredHeaders(request requests.IRequest, t time.Time) { - request.AddHeaderParam("HOST", request.GetHost()) - request.AddHeaderParam("X-Sdk-Date", formattedSignTime(t, "DateTime")) - if len(request.GetProjectId()) > 0 { - request.AddHeaderParam("X-Project-Id", request.GetProjectId()) - } - return -} - -func buildRequestStringToSign(request requests.IRequest) string { - return "" -} - -func formattedSignTime(t time.Time, format string) string { - switch format { - case "Date": - return t.UTC().Format("20060102") - case "DateTime": - return t.UTC().Format("20060102T150405Z") - default: - return t.UTC().Format("20060102T150405Z") - } -} - -func contentSha256(request requests.IRequest) string { - method := strings.ToUpper(request.GetMethod()) - content := []byte{} - body := request.GetBodyReader() - content, _ = ioutil.ReadAll(body) - if method == "POST" { - if len(content) == 0 { - // other http method use query as content - content = []byte(request.BuildQueries()) - } - } - - return hashSha256(content) -} - -func hashSha256(msg []byte) string { - sh256 := sha256.New() - sh256.Write(msg) - - return hex.EncodeToString(sh256.Sum(nil)) -} - -func canonicalRequest(request requests.IRequest) string { - sha256 := contentSha256(request) - uri := request.GetURI() - if !strings.HasSuffix(uri, "/") { - uri = uri + "/" - } - - return strings.Join([]string{ - request.GetMethod(), - uri, - canonicalQueryString(request), - canonicalHeaders(request), - canonicalHeaderNames(request), - sha256, - }, "\n") -} - -func sortedHeaderNames(request requests.IRequest) []string { - headers := request.GetHeaders() - keys := make([]string, 0) - for k := range headers { - keys = append(keys, k) - } - - sort.Slice(keys, func(i, j int) bool { - return strings.ToLower(keys[i]) < strings.ToLower(keys[j]) - }) - - return keys -} - -func canonicalQueryString(request requests.IRequest) string { - if strings.ToUpper(request.GetMethod()) != "POST" { - return request.BuildQueries() - } - - return "" -} - -func canonicalHeaders(request requests.IRequest) string { - keys := sortedHeaderNames(request) - headers := request.GetHeaders() - ret := []string{} - for _, k := range keys { - ret = append(ret, strings.ToLower(k)+":"+strings.TrimSpace(headers[k])) - } - - return strings.Join(ret, "\n") + "\n" -} - -func canonicalHeaderNames(request requests.IRequest) string { - keys := sortedHeaderNames(request) - ret := strings.Join(keys, ";") - return strings.ToLower(ret) -} - -var SigningKeyCache = map[string][]byte{} - -func getSigningKey(secretKey, date, regionId, service string) string { - joinedKey := strings.Join([]string{secretKey, date, regionId, service}, "") - cacheKey := fmt.Sprintf("%x", md5.Sum([]byte(joinedKey))) - if v, ok := SigningKeyCache[cacheKey]; ok { - return string(v) - } - - ret := []byte("SDK" + secretKey) - for _, k := range []string{date, regionId, service, "sdk_request"} { - ret = signers.HmacSha256(k, ret) - } - - SigningKeyCache[cacheKey] = ret - return string(ret) -} - -func addAuthorizationHeader(request requests.IRequest, accessKey, credentialScope, signature string) { - auth := "SDK-HMAC-SHA256" + " " + strings.Join([]string{ - "Credential=" + accessKey + "/" + credentialScope, - "SignedHeaders=" + canonicalHeaderNames(request), - "Signature=" + signature, - }, ", ") - - request.AddHeaderParam("Authorization", auth) -} diff --git a/pkg/multicloud/hcso/client/auth/signers/doc.go b/pkg/multicloud/hcso/client/auth/signers/doc.go deleted file mode 100644 index af594488de..0000000000 --- a/pkg/multicloud/hcso/client/auth/signers/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 signers // import "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth/signers" diff --git a/pkg/multicloud/hcso/client/auth/signers/signer_access_key.go b/pkg/multicloud/hcso/client/auth/signers/signer_access_key.go deleted file mode 100644 index 32fe76084d..0000000000 --- a/pkg/multicloud/hcso/client/auth/signers/signer_access_key.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 signers - -import ( - "crypto/hmac" - "crypto/sha256" - "encoding/hex" - - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth/credentials" -) - -type AccessKeySigner struct { - credential *credentials.AccessKeyCredential -} - -func (signer *AccessKeySigner) GetName() string { - return "HmacSha256" -} - -func (signer *AccessKeySigner) GetAccessKeyId() (accessKeyId string, err error) { - return signer.credential.AccessKeyId, nil -} - -func (signer *AccessKeySigner) GetSecretKey() (secretKey string, err error) { - return signer.credential.AccessKeySecret, nil -} - -func (signer *AccessKeySigner) Sign(stringToSign, secretSuffix string) string { - return hex.EncodeToString(HmacSha256(stringToSign, []byte(secretSuffix))) -} - -func HmacSha256(data string, key []byte) []byte { - mac := hmac.New(sha256.New, key) - mac.Write([]byte(data)) - return mac.Sum(nil) -} - -func NewAccessKeySigner(credential *credentials.AccessKeyCredential) *AccessKeySigner { - return &AccessKeySigner{ - credential: credential, - } -} diff --git a/pkg/multicloud/hcso/client/client.go b/pkg/multicloud/hcso/client/client.go deleted file mode 100644 index f93fe21631..0000000000 --- a/pkg/multicloud/hcso/client/client.go +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 client - -import ( - "net/http" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth/credentials" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/modules" -) - -type Client struct { - cfg *SClientConfig - // 标记初始化状态 - init bool - - Bandwidths *modules.SBandwidthManager - Credentials *modules.SCredentialManager - Disks *modules.SDiskManager - Domains *modules.SDomainManager - Eips *modules.SEipManager - Endpoints *modules.SEndpointManager - Services *modules.SServiceManager - Elasticcache *modules.SElasticcacheManager - DcsAvailableZone *modules.SDcsAvailableZoneManager - Flavors *modules.SFlavorManager - Images *modules.SImageManager - OpenStackImages *modules.SImageManager - Interface *modules.SInterfaceManager - Jobs *modules.SJobManager - Keypairs *modules.SKeypairManager - Elb *modules.SLoadbalancerManager - ElbBackend *modules.SElbBackendManager - ElbBackendGroup *modules.SElbBackendGroupManager - ElbListeners *modules.SElbListenersManager - ElbCertificates *modules.SElbCertificatesManager - ElbHealthCheck *modules.SElbHealthCheckManager - ElbL7policies *modules.SElbL7policiesManager - ElbPolicies *modules.SElbPoliciesManager - ElbWhitelist *modules.SElbWhitelistManager - Port *modules.SPortManager - Projects *modules.SProjectManager - Regions *modules.SRegionManager - SecurityGroupRules *modules.SSecgroupRuleManager - SecurityGroups *modules.SSecurityGroupManager - NovaSecurityGroups *modules.SSecurityGroupManager - Servers *modules.SServerManager - ServersV2 *modules.SServerManager - NovaServers *modules.SServerManager - Snapshots *modules.SSnapshotManager - OsSnapshots *modules.SSnapshotManager - Subnets *modules.SSubnetManager - Users *modules.SUserManager - Vpcs *modules.SVpcManager - Zones *modules.SZoneManager - VpcRoutes *modules.SVpcRouteManager - SNatRules *modules.SNatSRuleManager - DNatRules *modules.SNatDRuleManager - NatGateways *modules.SNatGatewayManager - VpcPeerings *modules.SVpcPeeringManager - DBInstance *modules.SDBInstanceManager - DBInstanceBackup *modules.SDBInstanceBackupManager - DBInstanceFlavor *modules.SDBInstanceFlavorManager - DBInstanceDatastore *modules.SDBInstanceDatastoreManager - DBInstanceStorage *modules.SDBInstanceStorageManager - DBInstanceJob *modules.SDBInstanceJobManager - Traces *modules.STraceManager - CloudEye *modules.SCloudEyeManager - Quotas *modules.SQuotaManager - EnterpriseProjects *modules.SEnterpriseProjectManager - Roles *modules.SRoleManager - Groups *modules.SGroupManager - SAMLProviders *modules.SAMLProviderManager - SAMLProviderMappings *modules.SAMLProviderMappingManager - SfsTurbos *modules.SfsTurboManager -} - -type SClientConfig struct { - signer auth.Signer - endpoints *cloudprovider.SHCSOEndpoints - regionId string - domainId string - projectId string - defaultRegion string - - debug bool -} - -func (self *SClientConfig) GetSigner() auth.Signer { - return self.signer -} - -func (self *SClientConfig) GetEndpoints() *cloudprovider.SHCSOEndpoints { - return self.endpoints -} - -func (self *SClientConfig) GetDefaultRegion() string { - return self.defaultRegion -} - -func (self *SClientConfig) GetRegionId() string { - return self.regionId -} - -func (self *SClientConfig) GetDomainId() string { - return self.domainId -} - -func (self *SClientConfig) GetProjectId() string { - return self.projectId -} - -func (self *SClientConfig) GetDebug() bool { - return self.debug -} - -func (self *Client) SetHttpClient(httpClient *http.Client) { - self.Credentials.SetHttpClient(httpClient) - self.Servers.SetHttpClient(httpClient) - self.ServersV2.SetHttpClient(httpClient) - self.NovaServers.SetHttpClient(httpClient) - self.Snapshots.SetHttpClient(httpClient) - self.OsSnapshots.SetHttpClient(httpClient) - self.Images.SetHttpClient(httpClient) - self.OpenStackImages.SetHttpClient(httpClient) - self.Projects.SetHttpClient(httpClient) - self.Regions.SetHttpClient(httpClient) - self.Zones.SetHttpClient(httpClient) - self.Vpcs.SetHttpClient(httpClient) - self.Eips.SetHttpClient(httpClient) - self.Elasticcache.SetHttpClient(httpClient) - self.DcsAvailableZone.SetHttpClient(httpClient) - self.Disks.SetHttpClient(httpClient) - self.Domains.SetHttpClient(httpClient) - self.Keypairs.SetHttpClient(httpClient) - self.Elb.SetHttpClient(httpClient) - self.ElbBackend.SetHttpClient(httpClient) - self.ElbBackendGroup.SetHttpClient(httpClient) - self.ElbListeners.SetHttpClient(httpClient) - self.ElbCertificates.SetHttpClient(httpClient) - self.ElbHealthCheck.SetHttpClient(httpClient) - self.ElbL7policies.SetHttpClient(httpClient) - self.ElbPolicies.SetHttpClient(httpClient) - self.ElbWhitelist.SetHttpClient(httpClient) - self.SecurityGroupRules.SetHttpClient(httpClient) - self.SecurityGroups.SetHttpClient(httpClient) - self.NovaSecurityGroups.SetHttpClient(httpClient) - self.Subnets.SetHttpClient(httpClient) - self.Users.SetHttpClient(httpClient) - self.Interface.SetHttpClient(httpClient) - self.Jobs.SetHttpClient(httpClient) - self.Bandwidths.SetHttpClient(httpClient) - self.Port.SetHttpClient(httpClient) - self.Flavors.SetHttpClient(httpClient) - self.VpcRoutes.SetHttpClient(httpClient) - self.SNatRules.SetHttpClient(httpClient) - self.DNatRules.SetHttpClient(httpClient) - self.NatGateways.SetHttpClient(httpClient) - self.DBInstance.SetHttpClient(httpClient) - self.DBInstanceBackup.SetHttpClient(httpClient) - self.DBInstanceFlavor.SetHttpClient(httpClient) - self.DBInstanceJob.SetHttpClient(httpClient) - self.Traces.SetHttpClient(httpClient) - self.CloudEye.SetHttpClient(httpClient) - self.EnterpriseProjects.SetHttpClient(httpClient) - self.Roles.SetHttpClient(httpClient) - self.Groups.SetHttpClient(httpClient) - self.SAMLProviders.SetHttpClient(httpClient) - self.SAMLProviderMappings.SetHttpClient(httpClient) - self.SfsTurbos.SetHttpClient(httpClient) - self.Endpoints.SetHttpClient(httpClient) - self.Services.SetHttpClient(httpClient) -} - -func (self *Client) InitWithAccessKey(regionId, domainId, projectId, accessKey, secretKey string, debug bool, defaultRegion string, endpoints *cloudprovider.SHCSOEndpoints) error { - // accessKey signer - credential := &credentials.AccessKeyCredential{ - AccessKeyId: accessKey, - AccessKeySecret: secretKey, - } - - // 从signer中初始化 - signer, err := auth.NewSignerWithCredential(credential) - if err != nil { - return err - } - self.cfg = &SClientConfig{ - signer: signer, - endpoints: endpoints, - regionId: regionId, - defaultRegion: defaultRegion, - domainId: domainId, - projectId: projectId, - debug: debug, - } - - // 初始化 resource manager - self.initManagers() - return err -} - -func (self *Client) initManagers() { - if !self.init { - self.Servers = modules.NewServerManager(self.cfg) - self.ServersV2 = modules.NewServerV2Manager(self.cfg) - self.NovaServers = modules.NewNovaServerManager(self.cfg) - self.Snapshots = modules.NewSnapshotManager(self.cfg) - self.OsSnapshots = modules.NewOsSnapshotManager(self.cfg) - self.Images = modules.NewImageManager(self.cfg) - self.OpenStackImages = modules.NewOpenstackImageManager(self.cfg) - self.Projects = modules.NewProjectManager(self.cfg) - self.Regions = modules.NewRegionManager(self.cfg) - self.Zones = modules.NewZoneManager(self.cfg) - self.Vpcs = modules.NewVpcManager(self.cfg) - self.Eips = modules.NewEipManager(self.cfg) - self.Elasticcache = modules.NewElasticcacheManager(self.cfg) - self.DcsAvailableZone = modules.NewDcsAvailableZoneManager(self.cfg) - self.Disks = modules.NewDiskManager(self.cfg) - self.Domains = modules.NewDomainManager(self.cfg) - self.Keypairs = modules.NewKeypairManager(self.cfg) - self.Elb = modules.NewLoadbalancerManager(self.cfg) - self.ElbBackend = modules.NewElbBackendManager(self.cfg) - self.ElbBackendGroup = modules.NewElbBackendGroupManager(self.cfg) - self.ElbListeners = modules.NewElbListenersManager(self.cfg) - self.ElbCertificates = modules.NewElbCertificatesManager(self.cfg) - self.ElbHealthCheck = modules.NewElbHealthCheckManager(self.cfg) - self.ElbL7policies = modules.NewElbL7policiesManager(self.cfg) - self.ElbPolicies = modules.NewElbPoliciesManager(self.cfg) - self.ElbWhitelist = modules.NewElbWhitelistManager(self.cfg) - self.SecurityGroupRules = modules.NewSecgroupRuleManager(self.cfg) - self.SecurityGroups = modules.NewSecurityGroupManager(self.cfg) - self.NovaSecurityGroups = modules.NewNovaSecurityGroupManager(self.cfg) - self.Subnets = modules.NewSubnetManager(self.cfg) - self.Users = modules.NewUserManager(self.cfg) - self.Interface = modules.NewInterfaceManager(self.cfg) - self.Jobs = modules.NewJobManager(self.cfg) - self.Bandwidths = modules.NewBandwidthManager(self.cfg) - self.Credentials = modules.NewCredentialManager(self.cfg) - self.Port = modules.NewPortManager(self.cfg) - self.Flavors = modules.NewFlavorManager(self.cfg) - self.VpcRoutes = modules.NewVpcRouteManager(self.cfg) - self.SNatRules = modules.NewNatSManager(self.cfg) - self.DNatRules = modules.NewNatDManager(self.cfg) - self.NatGateways = modules.NewNatGatewayManager(self.cfg) - self.VpcPeerings = modules.NewVpcPeeringManager(self.cfg) - self.DBInstance = modules.NewDBInstanceManager(self.cfg) - self.DBInstanceBackup = modules.NewDBInstanceBackupManager(self.cfg) - self.DBInstanceFlavor = modules.NewDBInstanceFlavorManager(self.cfg) - self.DBInstanceStorage = modules.NewDBInstanceStorageManager(self.cfg) - self.DBInstanceDatastore = modules.NewDBInstanceDatastoreManager(self.cfg) - self.DBInstanceJob = modules.NewDBInstanceJobManager(self.cfg) - self.Traces = modules.NewTraceManager(self.cfg) - self.CloudEye = modules.NewCloudEyeManager(self.cfg) - self.Quotas = modules.NewQuotaManager(self.cfg) - self.EnterpriseProjects = modules.NewEnterpriseProjectManager(self.cfg) - self.Roles = modules.NewRoleManager(self.cfg) - self.Groups = modules.NewGroupManager(self.cfg) - self.SAMLProviders = modules.NewSAMLProviderManager(self.cfg) - self.SAMLProviderMappings = modules.NewSAMLProviderMappingManager(self.cfg) - self.SfsTurbos = modules.NewSfsTurboManager(self.cfg) - self.Endpoints = modules.NewEndpointManager(self.cfg) - self.Services = modules.NewServiceManager(self.cfg) - } - - self.init = true -} - -func NewClientWithAccessKey(regionId, domainId, projectId, accessKey, secretKey string, debug bool, defaultRegion string, endpoints *cloudprovider.SHCSOEndpoints) (*Client, error) { - c := &Client{} - err := c.InitWithAccessKey(regionId, domainId, projectId, accessKey, secretKey, debug, defaultRegion, endpoints) - return c, err -} diff --git a/pkg/multicloud/hcso/client/doc.go b/pkg/multicloud/hcso/client/doc.go deleted file mode 100644 index 4461387962..0000000000 --- a/pkg/multicloud/hcso/client/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 client // import "yunion.io/x/onecloud/pkg/multicloud/hcso/client" diff --git a/pkg/multicloud/hcso/client/manager/doc.go b/pkg/multicloud/hcso/client/manager/doc.go deleted file mode 100644 index 78e2f6d077..0000000000 --- a/pkg/multicloud/hcso/client/manager/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 manager // import "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" diff --git a/pkg/multicloud/hcso/client/manager/manager.go b/pkg/multicloud/hcso/client/manager/manager.go deleted file mode 100644 index 2fcc947d6d..0000000000 --- a/pkg/multicloud/hcso/client/manager/manager.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 manager - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type IManagerContext interface { - GetPath() string -} - -type IBaseManager interface { - Version() string - KeyString() string - ServiceType() string - GetColumns() []string -} - -type IManager interface { - IBaseManager - // 获取资源列表 GET /cloudservers/? - List(queries map[string]string) (*responses.ListResult, error) - // 根据上文获取资源列表 GET /cloudservers//nics? - ListInContext(ctx IManagerContext, queries map[string]string) (*responses.ListResult, error) - ListInContextWithSpec(ctx IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error) - - // 查询单个资源 GET /cloudservers/? - Get(id string, queries map[string]string) (jsonutils.JSONObject, error) - // 根据上文获取资源查询单个资源 GET /cloudservers//nics/? - GetInContext(ctx IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error) - - // 创建单个资源 POST /cloudservers - Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文创建单个资源 POST /cloudservers//nics/ - CreateInContext(ctx IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 异步任务创建 POST /cloudservers. 返回异步任务 job_id。 todo:// 后续考虑返回一个task对象 - AsyncCreate(params jsonutils.JSONObject) (string, error) - - // 更新单个资源 PUT /cloudservers/ - Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文更新单个资源 PUT /cloudservers//nics/ - UpdateInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文和spec更新单个资源 PUT /v2.1/{project_id}/servers/{server_id}/os-reset-password - UpdateInContextWithSpec(ctx IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) - - // 删除单个资源 DELETE /cloudservers/ - Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文删除单个资源 DELETE /cloudservers//nics/ - DeleteInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文和spec删除单个资源 - DeleteInContextWithSpec(ctx IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) - // 批量执行操作 POST /cloudservers/ - // BatchPerformAction(action string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 执行操作 POST /cloudservers// - PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) -} - -type IManagerConfig interface { - GetSigner() auth.Signer - GetEndpoints() *cloudprovider.SHCSOEndpoints - GetRegionId() string - GetDomainId() string - GetProjectId() string - GetDebug() bool - - GetDefaultRegion() string -} diff --git a/pkg/multicloud/hcso/client/modules/doc.go b/pkg/multicloud/hcso/client/modules/doc.go deleted file mode 100644 index 5be57ed8fc..0000000000 --- a/pkg/multicloud/hcso/client/modules/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules // import "yunion.io/x/onecloud/pkg/multicloud/hcso/client/modules" diff --git a/pkg/multicloud/hcso/client/modules/manager_base.go b/pkg/multicloud/hcso/client/modules/manager_base.go deleted file mode 100644 index b747488864..0000000000 --- a/pkg/multicloud/hcso/client/modules/manager_base.go +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "context" - "fmt" - "net/http" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/requests" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -type IRequestHook interface { - Process(r requests.IRequest) -} - -type SBaseManager struct { - cfg manager.IManagerConfig - httpClient *http.Client - requestHook IRequestHook // 用于对request做特殊处理。非必要请不要使用!!!。目前只有port接口用到。 - - columns []string - debug bool -} - -type sThrottlingThreshold struct { - locked bool - lockTime time.Time -} - -func (t *sThrottlingThreshold) CheckingLock() { - if !t.locked { - return - } - - for { - if t.lockTime.Sub(time.Now()).Seconds() < 0 { - return - } - log.Debugf("throttling threshold has been reached. release at %s", t.lockTime) - time.Sleep(5 * time.Second) - } -} - -func (t *sThrottlingThreshold) Lock() { - // 锁定至少15秒 - t.locked = true - t.lockTime = time.Now().Add(15 * time.Second) -} - -var ThrottlingLock = sThrottlingThreshold{locked: false, lockTime: time.Time{}} - -func NewBaseManager2(cfg manager.IManagerConfig, requesthk IRequestHook) SBaseManager { - return SBaseManager{ - cfg: cfg, - httpClient: httputils.GetDefaultClient(), - debug: cfg.GetDebug(), - requestHook: requesthk, - } -} - -func NewBaseManager(cfg manager.IManagerConfig) SBaseManager { - return NewBaseManager2(cfg, nil) -} - -func (self *SBaseManager) GetColumns() []string { - return self.columns -} - -func (self *SBaseManager) SetHttpClient(httpClient *http.Client) { - self.httpClient = httpClient -} - -func (self *SBaseManager) _list(request requests.IRequest, responseKey string) (*responses.ListResult, error) { - _, body, err := self.jsonRequest(request) - if err != nil { - return nil, err - } - if body == nil { - log.Warningf("empty response") - return &responses.ListResult{}, nil - } - - rets, err := body.GetArray(responseKey) - if err != nil { - return nil, err - } - total, _ := body.Int("count") - // if err != nil { - // total = int64(len(rets)) - //} - - //if total == 0 { - // total = int64(len(rets)) - //} - - limit := 0 - if v, exists := request.GetQueryParams()["limit"]; exists { - limit, _ = strconv.Atoi(v) - } - - offset := 0 - if v, exists := request.GetQueryParams()["offset"]; exists { - offset, _ = strconv.Atoi(v) - } - - return &responses.ListResult{ - Data: rets, - Total: int(total), - Limit: limit, - Offset: offset, - }, nil -} - -func (self *SBaseManager) _do(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) { - _, resp, e := self.jsonRequest(request) - if e != nil { - return nil, e - } - - if resp == nil { // no reslt - return jsonutils.NewDict(), nil - } - - if len(responseKey) == 0 { - return resp, nil - } - - ret, e := resp.Get(responseKey) - if e != nil { - return nil, e - } - - return ret, nil -} - -func (self *SBaseManager) _get(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) { - return self._do(request, responseKey) -} - -type HuaweiClientError struct { - Code int - Errorcode []string - err error - Details string - ErrorCode string -} - -func (ce *HuaweiClientError) Error() string { - return jsonutils.Marshal(ce).String() -} - -func (ce *HuaweiClientError) ParseErrorFromJsonResponse(statusCode int, body jsonutils.JSONObject) error { - if body != nil { - body.Unmarshal(ce) - } - if ce.Code == 0 { - ce.Code = statusCode - } - if len(ce.Details) == 0 && body != nil { - ce.Details = body.String() - } - return ce -} - -func (self *SBaseManager) jsonRequest(request requests.IRequest) (http.Header, jsonutils.JSONObject, error) { - ThrottlingLock.CheckingLock() - ctx := context.Background() - // hook request - if self.requestHook != nil { - self.requestHook.Process(request) - } - // 拼接、编译、签名 requests here。 - err := self.buildRequestWithSigner(request, self.cfg.GetSigner()) - if err != nil { - return nil, nil, err - } - header := http.Header{} - for k, v := range request.GetHeaders() { - header.Set(k, v) - } - - var jsonBody jsonutils.JSONObject - content := request.GetContent() - if len(content) > 0 { - jsonBody, err = jsonutils.Parse(content) - if err != nil { - return nil, nil, fmt.Errorf("not a json body") - } - } - - client := httputils.NewJsonClient(self.httpClient) - req := httputils.NewJsonRequest(httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), jsonBody) - req.SetHeader(header) - resp := &HuaweiClientError{} - const MAX_RETRY = 3 - retry := MAX_RETRY - for { - h, b, e := client.Send(ctx, req, resp, self.debug) - if e == nil { - return h, b, nil - } - - log.Errorf("[%s] %s body: %v error: %v", req.GetHttpMethod(), req.GetUrl(), jsonBody, e) - - switch err := e.(type) { - case *HuaweiClientError: - if err.ErrorCode == "APIGW.0301" { - return h, b, errors.Wrapf(httperrors.ErrInvalidAccessKey, e.Error()) - } else if err.Code == 499 && retry > 0 && request.GetMethod() == "GET" { - retry -= 1 - time.Sleep(3 * time.Second * time.Duration(MAX_RETRY-retry)) - } else if (err.Code == 404 || strings.Contains(err.Details, "could not be found") || - strings.Contains(err.Error(), "Not Found") || - strings.Contains(err.Details, "does not exist")) && request.GetMethod() != "POST" { - return h, b, errors.Wrap(cloudprovider.ErrNotFound, err.Error()) - } else if err.Code == 429 && retry > 0 { - // 当前请求过多。 - ThrottlingLock.Lock() - retry -= 1 - time.Sleep(15 * time.Second) - } else { - return h, b, e - } - default: - return h, b, e - } - } -} - -func (self *SBaseManager) rawRequest(request requests.IRequest) (*http.Response, error) { - ctx := context.Background() - // 拼接、编译requests here。 - header := http.Header{} - for k, v := range request.GetHeaders() { - header.Set(k, v) - } - return httputils.Request(self.httpClient, ctx, httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), header, request.GetBodyReader(), self.debug) -} - -func (self *SBaseManager) buildRequestWithSigner(request requests.IRequest, signer auth.Signer) error { - return auth.Sign(request, signer) -} diff --git a/pkg/multicloud/hcso/client/modules/manager_resource.go b/pkg/multicloud/hcso/client/modules/manager_resource.go deleted file mode 100644 index 6e344e2371..0000000000 --- a/pkg/multicloud/hcso/client/modules/manager_resource.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/requests" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type ServiceNameType string - -const ( - ServiceNameECS ServiceNameType = "ecs" // 弹性云服务 - ServiceNameCCE ServiceNameType = "cce" // 云容器服务 - ServiceNameAS ServiceNameType = "as" // 弹性伸缩服务 - ServiceNameIAM ServiceNameType = "iam" // 统一身份认证服务 - ServiceNameIMS ServiceNameType = "ims" // 镜像服务 - ServiceNameCSBS ServiceNameType = "csbs" // 云服务器备份服务 - ServiceNameCCI ServiceNameType = "cci" // 云容器实例 CCI - ServiceNameBMS ServiceNameType = "bms" // 裸金属服务器 - ServiceNameEVS ServiceNameType = "evs" // 云硬盘 EVS - ServiceNameVBS ServiceNameType = "vbs" // 云硬盘备份 VBS - ServiceNameOBS ServiceNameType = "obs" // 对象存储服务 OBS - ServiceNameVPC ServiceNameType = "vpc" // 虚拟私有云 VPC - ServiceNameELB ServiceNameType = "elb" // 弹性负载均衡 ELB - ServiceNameBSS ServiceNameType = "bss" // 合作伙伴运营能力 - ServiceNameNAT ServiceNameType = "nat" // Nat网关 NAT - ServiceNameDCS ServiceNameType = "dcs" // 分布式缓存服务 - ServiceNameRDS ServiceNameType = "rds" // 关系型数据库 RDS - ServiceNameCTS ServiceNameType = "cts" // 云审计服务 - ServiceNameCES ServiceNameType = "ces" // 监控服务 CloudEye - ServiceNameEPS ServiceNameType = "eps" // 企业项目 - - ServiceNameSFSTurbo ServiceNameType = "sfs-turbo" // 文件系统 -) - -type SManagerContext struct { - InstanceManager manager.IManager - InstanceId string -} - -func (self *SManagerContext) GetPath() string { - path := self.InstanceManager.KeyString() - if len(self.InstanceId) > 0 { - path += fmt.Sprintf("/%s", url.PathEscape(self.InstanceId)) - } - - return path -} - -type SResourceManager struct { - SBaseManager - ctx manager.IManagerContext - ServiceName ServiceNameType // 服务名称: ecs - Region string // 区域: cn-north-1 - DomainId string - ProjectId string // 项目ID: uuid - version string // api 版本号 - Keyword string // 资源名称单数。构建URL时使用 - KeywordPlural string // 资源名称复数形式。构建URL时使用 - - ResourceKeyword string // 资源名称。url中使用 -} - -func getContent(params jsonutils.JSONObject) string { - if params == nil { - return "" - } - - return params.String() -} - -func (self *SResourceManager) Version() string { - return self.version -} - -func (self *SResourceManager) KeyString() string { - return self.ResourceKeyword -} - -func (self *SResourceManager) ServiceType() string { - return string(self.ServiceName) -} - -func (self *SResourceManager) GetEndpoint() string { - return self.cfg.GetEndpoints().GetEndpoint(self.cfg.GetDefaultRegion(), self.ServiceType(), self.Region) -} - -func (self *SResourceManager) GetColumns() []string { - return []string{} -} - -func (self *SResourceManager) SetDomainId(domainId string) { - self.DomainId = domainId -} - -func (self *SResourceManager) getReourcePath(ctx manager.IManagerContext, rid string, spec string) string { - segs := []string{} - if ctx != nil { - segs = append(segs, ctx.GetPath()) - } - - segs = append(segs, self.KeyString()) - - if len(rid) > 0 { - segs = append(segs, url.PathEscape(rid)) - } - - if len(spec) > 0 { - specSegs := strings.Split(spec, "/") - for _, specSeg := range specSegs { - segs = append(segs, url.PathEscape(specSeg)) - } - } - - return strings.Join(segs, "/") -} - -func (self *SResourceManager) newRequest(method, rid, spec string, ctx manager.IManagerContext) *requests.SRequest { - resourcePath := self.getReourcePath(ctx, rid, spec) - return requests.NewResourceRequest(self.GetEndpoint(), method, string(self.ServiceName), self.version, self.Region, self.ProjectId, resourcePath) -} - -func (self *SResourceManager) List(queries map[string]string) (*responses.ListResult, error) { - return self.ListInContext(self.ctx, queries) -} - -func (self *SResourceManager) ListInContext(ctx manager.IManagerContext, queries map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(ctx, "", queries, self.KeywordPlural) -} - -func (self *SResourceManager) ListInContextWithSpec(ctx manager.IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error) { - request := self.newRequest("GET", "", spec, ctx) - for k, v := range queries { - request.AddQueryParam(k, v) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._list(request, responseKey) -} - -func (self *SResourceManager) Get(id string, queries map[string]string) (jsonutils.JSONObject, error) { - return self.GetInContext(self.ctx, id, queries) -} - -func (self *SResourceManager) GetInContext(ctx manager.IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error) { - return self.GetInContextWithSpec(ctx, id, "", queries, self.Keyword) -} - -func (self *SResourceManager) GetInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("GET", id, spec, ctx) - for k, v := range queries { - request.AddQueryParam(k, v) - } - - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._get(request, responseKey) -} - -func (self *SResourceManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.CreateInContext(self.ctx, params) -} - -func (self *SResourceManager) CreateInContext(ctx manager.IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.CreateInContextWithSpec(ctx, "", params, self.Keyword) -} - -func (self *SResourceManager) CreateInContextWithSpec(ctx manager.IManagerContext, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("POST", "", spec, ctx) - request.SetContent([]byte(params.String())) - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { - return "", fmt.Errorf("not supported") -} - -func (self *SResourceManager) Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.UpdateInContext(self.ctx, id, params) -} - -func (self *SResourceManager) UpdateInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.UpdateInContextWithSpec(ctx, id, "", params, self.Keyword) -} - -func (self *SResourceManager) UpdateInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("PUT", id, spec, ctx) - content := getContent(params) - if len(content) > 0 { - request.SetContent([]byte(content)) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) Patch(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.PatchInContext(self.ctx, id, params) -} - -func (self *SResourceManager) PatchInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.PatchInContextWithSpec(ctx, id, "", params, self.Keyword) -} - -func (self *SResourceManager) PatchInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("PATCH", id, spec, ctx) - content := getContent(params) - if len(content) > 0 { - request.SetContent([]byte(content)) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.DeleteInContext(self.ctx, id, params) -} - -func (self *SResourceManager) DeleteInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.DeleteInContextWithSpec(ctx, id, "", nil, params, "") -} - -func (self *SResourceManager) DeleteInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("DELETE", id, spec, ctx) - for k, v := range queries { - request.AddQueryParam(k, v) - } - - content := getContent(params) - if len(content) > 0 { - request.SetContent([]byte(content)) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.PerformAction2(action, id, params, self.Keyword) -} - -func (self *SResourceManager) PerformAction2(action string, id string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("POST", id, action, nil) - request.SetContent([]byte(getContent(params))) - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) SetVersion(v string) { - self.version = v -} - -func (self *SResourceManager) versionedURL(path string) string { - return "" -} - -// todo: Init a manager with environment variables -func (self *SResourceManager) Init() error { - return nil -} diff --git a/pkg/multicloud/hcso/client/modules/mod_ces.go b/pkg/multicloud/hcso/client/modules/mod_ces.go deleted file mode 100644 index 91112b97ec..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_ces.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/requests" - hw_mod "yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules" -) - -type SCloudEyeManager struct { - SResourceManager -} - -func NewCloudEyeManager(cfg manager.IManagerConfig) *SCloudEyeManager { - return &SCloudEyeManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameCES, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "V1.0", - Keyword: "", - KeywordPlural: "metrics", - ResourceKeyword: "metrics", - }} -} - -func (ces *SCloudEyeManager) ListMetrics() ([]hw_mod.SMetricMeta, error) { - metrics := make([]hw_mod.SMetricMeta, 0) - next := "" - for { - marker, data, err := ces.listMetricsInternal(next) - if err != nil { - return nil, errors.Wrap(err, "ces.listMetricsInternal") - } - if len(data) == 0 { - break - } - metrics = append(metrics, data...) - next = marker - } - return metrics, nil -} - -func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []hw_mod.SMetricMeta, error) { - request := requests.NewResourceRequest(ces.GetEndpoint(), "GET", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, ces.ResourceKeyword) - request.AddQueryParam("limit", "1000") - if len(start) > 0 { - request.AddQueryParam("start", start) - } - _, resp, err := ces.jsonRequest(request) - if err != nil { - return "", nil, errors.Wrap(err, "ces.jsonRequest") - } - marker, _ := resp.GetString("meta_data", "marker") - metrics := make([]hw_mod.SMetricMeta, 0) - err = resp.Unmarshal(&metrics, "metrics") - if err != nil { - return "", nil, errors.Wrap(err, "resp.Unmarshal metrics") - } - return marker, metrics, nil -} - -type SBatchQueryMetricDataInput struct { - Metrics []hw_mod.SMetric `json:"metrics"` - - From int64 `json:"from"` - To int64 `json:"to"` - Period string `json:"period"` - Filter string `json:"filter"` -} - -func (ces *SCloudEyeManager) GetMetricsData(metrics []hw_mod.SMetricMeta, since time.Time, until time.Time) ([]hw_mod.SMetricData, error) { - if len(metrics) > 10 { - return nil, errors.Wrap(httperrors.ErrTooLarge, "request more than 10 metrics") - } - metricReq := make([]hw_mod.SMetric, len(metrics)) - for i := range metrics { - metricReq[i] = metrics[i].SMetric - } - request := requests.NewResourceRequest(ces.GetEndpoint(), "POST", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, "batch-query-metric-data") - input := SBatchQueryMetricDataInput{ - Metrics: metricReq, - From: since.Unix() * 1000, - To: until.Unix() * 1000, - Period: "1", - Filter: "average", - } - body := jsonutils.Marshal(&input).String() - request.SetContent([]byte(body)) - _, resp, err := ces.jsonRequest(request) - if err != nil { - return nil, errors.Wrap(err, "ces.jsonRequest") - } - //log.Debugf("%s", resp) - result := make([]hw_mod.SMetricData, 0) - err = resp.Unmarshal(&result, "metrics") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return result, nil -} diff --git a/pkg/multicloud/hcso/client/modules/mod_credential.go b/pkg/multicloud/hcso/client/modules/mod_credential.go deleted file mode 100644 index 4614920e5f..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_credential.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SCredentialManager struct { - SResourceManager -} - -func NewCredentialManager(cfg manager.IManagerConfig) *SCredentialManager { - return &SCredentialManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v3.0", - Keyword: "credential", - KeywordPlural: "credentials", - - ResourceKeyword: "OS-CREDENTIAL/credentials", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_dbinstance.go b/pkg/multicloud/hcso/client/modules/mod_dbinstance.go deleted file mode 100644 index d70e82bdf1..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_dbinstance.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type SDBInstanceManager struct { - SResourceManager -} - -func NewDBInstanceManager(cfg manager.IManagerConfig) *SDBInstanceManager { - return &SDBInstanceManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "", - KeywordPlural: "instances", - - ResourceKeyword: "instances", - }} -} - -func (self *SDBInstanceManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - if len(id) == 0 { - return nil, cloudprovider.ErrNotFound - } - resp, err := self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "") - if err != nil { - return nil, err - } - instances, err := resp.GetArray("instances") - if err != nil { - return nil, err - } - if len(instances) == 0 { - return nil, cloudprovider.ErrNotFound - } else if len(instances) == 1 { - return instances[0], nil - } - return nil, cloudprovider.ErrDuplicateId -} - -func (self *SDBInstanceManager) ListParameters(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListParameters missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/configurations", id), queries, "configuration_parameters") -} - -func (self *SDBInstanceManager) ListDatabases(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListDatabases missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/database/detail", id), queries, "databases") -} - -func (self *SDBInstanceManager) ListAccounts(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListAccounts missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/detail", id), queries, "users") -} - -func (self *SDBInstanceManager) ListPrivileges(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListPrivileges missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/database", id), queries, "databases") -} diff --git a/pkg/multicloud/hcso/client/modules/mod_dbinstance_backup.go b/pkg/multicloud/hcso/client/modules/mod_dbinstance_backup.go deleted file mode 100644 index bd290b60b5..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_dbinstance_backup.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SDBInstanceBackupManager struct { - SResourceManager -} - -func NewDBInstanceBackupManager(cfg manager.IManagerConfig) *SDBInstanceBackupManager { - return &SDBInstanceBackupManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "backup", - KeywordPlural: "backups", - - ResourceKeyword: "backups", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_dbinstance_flavor.go b/pkg/multicloud/hcso/client/modules/mod_dbinstance_flavor.go deleted file mode 100644 index e9a1b26501..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_dbinstance_flavor.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SDBInstanceFlavorManager struct { - SResourceManager -} - -func NewDBInstanceFlavorManager(cfg manager.IManagerConfig) *SDBInstanceFlavorManager { - return &SDBInstanceFlavorManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "flavor", - KeywordPlural: "flavor", - - ResourceKeyword: "flavors", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_dbinstance_job.go b/pkg/multicloud/hcso/client/modules/mod_dbinstance_job.go deleted file mode 100644 index 8617a1e96b..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_dbinstance_job.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SDBInstanceJobManager struct { - SResourceManager -} - -func NewDBInstanceJobManager(cfg manager.IManagerConfig) *SDBInstanceJobManager { - return &SDBInstanceJobManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "", - KeywordPlural: "", - - ResourceKeyword: "jobs", - }} -} - -func (self *SDBInstanceJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - return self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "job") -} diff --git a/pkg/multicloud/hcso/client/modules/mod_disks.go b/pkg/multicloud/hcso/client/modules/mod_disks.go deleted file mode 100644 index a664ea67b1..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_disks.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type SDiskManager struct { - SResourceManager -} - -func NewDiskManager(cfg manager.IManagerConfig) *SDiskManager { - return &SDiskManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEVS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "volume", - KeywordPlural: "volumes", - - ResourceKeyword: "cloudvolumes", - }} -} - -func (self *SDiskManager) List(querys map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -// https://support.huaweicloud.com/api-evs/evs_04_2003.html -func (self *SDiskManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { - origin_version := self.version - self.version = "v2.1" - defer func() { self.version = origin_version }() - - ret, err := self.CreateInContextWithSpec(nil, "", params, "") - if err != nil { - log.Debugf("AsyncCreate %s", err) - return "", err - } - - log.Debugf("AsyncCreate result %s", ret.String()) - // 按需机器 - jobId, err := ret.GetString("job_id") - if err == nil { - return jobId, nil - } - - // 包年包月机器 - return ret.GetString("order_id") -} - -// https://support.huaweicloud.com/api-evs/evs_04_2003.html -func (self *SDiskManager) GetDiskTypes() (*responses.ListResult, error) { - originKeyword := self.ResourceKeyword - self.ResourceKeyword = "" - defer func() { self.ResourceKeyword = originKeyword }() - return self.ListInContextWithSpec(self.ctx, "types", nil, "volume_types") -} diff --git a/pkg/multicloud/hcso/client/modules/mod_dnat_rules.go b/pkg/multicloud/hcso/client/modules/mod_dnat_rules.go deleted file mode 100644 index 8e9f9323b3..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_dnat_rules.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SNatDRuleManager struct { - SResourceManager -} - -func NewNatDManager(cfg manager.IManagerConfig) *SNatDRuleManager { - man := &SNatDRuleManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameNAT, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "dnat_rule", - KeywordPlural: "dnat_rules", - - ResourceKeyword: "dnat_rules", - }} - if len(cfg.GetProjectId()) > 0 { - man.requestHook = &sProjectHook{cfg.GetProjectId()} - } - return man -} diff --git a/pkg/multicloud/hcso/client/modules/mod_domains.go b/pkg/multicloud/hcso/client/modules/mod_domains.go deleted file mode 100644 index 688080f367..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_domains.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type SDomainManager struct { - SResourceManager -} - -func NewDomainManager(cfg manager.IManagerConfig) *SDomainManager { - m := &SDomainManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v3/auth", - Keyword: "domain", - KeywordPlural: "domains", - - ResourceKeyword: "domains", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} - -func (manager *SDomainManager) DeleteRole(domainId string, groupId, roleId string) error { - if len(domainId) == 0 { - return fmt.Errorf("missing domainId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - manager.SetVersion("v3") - defer manager.SetVersion("v3/auth") - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.DeleteInContextWithSpec(nil, domainId, res, nil, nil, "") - if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return err -} - -func (manager *SDomainManager) ListRoles(domainId string, groupId string) (*responses.ListResult, error) { - if len(domainId) == 0 { - return nil, fmt.Errorf("missing domainId") - } - if len(groupId) == 0 { - return nil, fmt.Errorf("missing groupId") - } - manager.SetVersion("v3") - defer manager.SetVersion("v3/auth") - res := fmt.Sprintf("%s/groups/%s/roles", domainId, groupId) - return manager.ListInContextWithSpec(nil, res, nil, "roles") -} - -func (manager *SDomainManager) AddRole(domainId string, groupId, roleId string) error { - if len(domainId) == 0 { - return fmt.Errorf("missing domainId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - manager.SetVersion("v3") - defer manager.SetVersion("v3/auth") - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.UpdateInContextWithSpec(nil, domainId, res, nil, "") - return err -} diff --git a/pkg/multicloud/hcso/client/modules/mod_elasticcache.go b/pkg/multicloud/hcso/client/modules/mod_elasticcache.go deleted file mode 100644 index 351a93f09f..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_elasticcache.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type SElasticcacheManager struct { - SResourceManager -} - -type SDcsAvailableZoneManager struct { - SResourceManager -} - -func NewElasticcacheManager(cfg manager.IManagerConfig) *SElasticcacheManager { - return &SElasticcacheManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameDCS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1.0", - Keyword: "", - KeywordPlural: "instances", - - ResourceKeyword: "instances", - }} -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html -func (self *SElasticcacheManager) ListBackups(queries map[string]string) (*responses.ListResult, error) { - var spec string - if id, _ := queries["instance_id"]; len(id) == 0 { - return nil, fmt.Errorf("SElasticcacheManager.ListBackups missing parameter instance_id") - } else { - spec = fmt.Sprintf("%s/backups", id) - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, spec, queries, "backup_record_response") -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html -func (self *SElasticcacheManager) ListParameters(queries map[string]string) (*responses.ListResult, error) { - var spec string - if id, _ := queries["instance_id"]; len(id) == 0 { - return nil, fmt.Errorf("SElasticcacheManager.ListParameters missing parameter instance_id") - } else { - spec = fmt.Sprintf("%s/configs", id) - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, spec, queries, "redis_config") -} - -func (self *SElasticcacheManager) Restart(instanceId string) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") - params.Add(jsonutils.NewString("restart"), "action") - return self.UpdateInContextWithSpec(nil, "", "status", params, "") -} - -// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 -func (self *SElasticcacheManager) Flush(instanceId string) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") - params.Add(jsonutils.NewString("flush"), "action") - return self.UpdateInContextWithSpec(nil, "", "status", params, "") -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html -func (self *SElasticcacheManager) RestoreInstance(instanceId string, backupId string) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewArray(jsonutils.NewString(backupId)), "backup_id") - - return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/restores", instanceId), params, "") -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html -func (self *SElasticcacheManager) ChangeInstanceSpec(instanceId string, specCode string, newCapacity int64) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Set("new_capacity", jsonutils.NewInt(newCapacity)) - params.Set("spec_code", jsonutils.NewString(specCode)) - - return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/extend", instanceId), params, "") -} - -func NewDcsAvailableZoneManager(cfg manager.IManagerConfig) *SDcsAvailableZoneManager { - return &SDcsAvailableZoneManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameDCS, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v1.0", - Keyword: "available_zone", - KeywordPlural: "available_zones", - - ResourceKeyword: "availableZones", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_enterpriceprojects.go b/pkg/multicloud/hcso/client/modules/mod_enterpriceprojects.go deleted file mode 100644 index e169ece474..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_enterpriceprojects.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SEnterpriseProjectManager struct { - SResourceManager -} - -func NewEnterpriseProjectManager(cfg manager.IManagerConfig) *SEnterpriseProjectManager { - m := &SEnterpriseProjectManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEPS, - Region: "", - ProjectId: "", - version: "v1.0", - Keyword: "enterprise_project", - KeywordPlural: "enterprise_projects", - - ResourceKeyword: "enterprise-projects", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/pkg/multicloud/hcso/client/modules/mod_flavors.go b/pkg/multicloud/hcso/client/modules/mod_flavors.go deleted file mode 100644 index 88ba90a6d8..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_flavors.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SFlavorManager struct { - SResourceManager -} - -func NewFlavorManager(cfg manager.IManagerConfig) *SFlavorManager { - return &SFlavorManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "flavor", - KeywordPlural: "flavors", - - ResourceKeyword: "cloudservers/flavors", // 这个接口有点特殊,实际只用到了list一个方法。为了简便直接把cloudservers附上。 - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_groups.go b/pkg/multicloud/hcso/client/modules/mod_groups.go deleted file mode 100644 index 737e2e595d..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_groups.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SGroupManager struct { - SResourceManager -} - -func NewGroupManager(cfg manager.IManagerConfig) *SGroupManager { - m := &SGroupManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v3", - Keyword: "group", - KeywordPlural: "groups", - - ResourceKeyword: "groups", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/pkg/multicloud/hcso/client/modules/mod_images.go b/pkg/multicloud/hcso/client/modules/mod_images.go deleted file mode 100644 index bdc60ec868..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_images.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/requests" -) - -type SImageManager struct { - SResourceManager -} - -type imageProject struct { - projectId string -} - -// image创建接口若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊) -// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID -func (self *imageProject) Process(request requests.IRequest) { - request.AddHeaderParam("X-Project-Id", self.projectId) -} - -func NewImageManager(cfg manager.IManagerConfig) *SImageManager { - var requestHook imageProject - if len(cfg.GetProjectId()) > 0 { - requestHook = imageProject{projectId: cfg.GetProjectId()} - } - - return &SImageManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager2(cfg, &requestHook), - ServiceName: ServiceNameIMS, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2", - Keyword: "image", - KeywordPlural: "images", - - ResourceKeyword: "cloudimages", - }} -} - -//https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091566.html -func (self *SImageManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - if querys == nil { - querys = make(map[string]string, 0) - } - - querys["id"] = id - // 这里默认使用private - // if t, exists := querys["__imagetype"]; !exists || len(t) == 0 { - // querys["__imagetype"] = "private" - // } - - ret, err := self.ListInContext(nil, querys) - if err != nil { - return nil, err - } - - if ret.Data == nil || len(ret.Data) == 0 { - return nil, httperrors.NewNotFoundError("image %s not found", id) - } - - return ret.Data[0], nil -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092108.html -// 删除image只能用这个manager -func NewOpenstackImageManager(cfg manager.IManagerConfig) *SImageManager { - var requestHook imageProject - if len(cfg.GetProjectId()) > 0 { - requestHook = imageProject{projectId: cfg.GetProjectId()} - } - - return &SImageManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager2(cfg, &requestHook), - ServiceName: ServiceNameIMS, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2", - Keyword: "image", - KeywordPlural: "images", - - ResourceKeyword: "images", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_interface.go b/pkg/multicloud/hcso/client/modules/mod_interface.go deleted file mode 100644 index af521091f8..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_interface.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SInterfaceManager struct { - SResourceManager -} - -// 不建议使用 -func NewInterfaceManager(cfg manager.IManagerConfig) *SInterfaceManager { - return &SInterfaceManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "interfaceAttachment", - KeywordPlural: "interfaceAttachments", - - ResourceKeyword: "os-interface", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_jobs.go b/pkg/multicloud/hcso/client/modules/mod_jobs.go deleted file mode 100644 index c77846a9c4..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_jobs.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type SJobManager struct { - SResourceManager -} - -func NewJobManager(cfg manager.IManagerConfig) *SJobManager { - return &SJobManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: "", - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "", - KeywordPlural: "", - - ResourceKeyword: "jobs", - }} -} - -func (self *SJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - processedQuery, err := self.processQueryParam(querys) - if err != nil { - return nil, err - } - - return self.GetInContext(nil, id, processedQuery) -} - -func (self *SJobManager) List(querys map[string]string) (*responses.ListResult, error) { - processedQuery, err := self.processQueryParam(querys) - if err != nil { - return nil, err - } - return self.ListInContext(nil, processedQuery) -} - -// 兼容查询不同ServiceName服务的Job做的特殊处理。 -func (self *SJobManager) processQueryParam(querys map[string]string) (map[string]string, error) { - service_type, exists := querys["service_type"] - if !exists { - return querys, fmt.Errorf("must specific query parameter `service_type`. e.g. ecs|ims|iam") - } - - self.ServiceName = ServiceNameType(service_type) - delete(querys, "service_type") - return querys, nil -} diff --git a/pkg/multicloud/hcso/client/modules/mod_keypairs.go b/pkg/multicloud/hcso/client/modules/mod_keypairs.go deleted file mode 100644 index b55d570ea5..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_keypairs.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SKeypairManager struct { - SResourceManager -} - -func NewKeypairManager(cfg manager.IManagerConfig) *SKeypairManager { - return &SKeypairManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "keypair", - KeywordPlural: "keypairs", - - ResourceKeyword: "os-keypairs", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_mapping.go b/pkg/multicloud/hcso/client/modules/mod_mapping.go deleted file mode 100644 index c0deaeab69..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_mapping.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SAMLProviderMappingManager struct { - SResourceManager -} - -func NewSAMLProviderMappingManager(cfg manager.IManagerConfig) *SAMLProviderMappingManager { - m := &SAMLProviderMappingManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v3/OS-FEDERATION", - Keyword: "mapping", - KeywordPlural: "mappings", - - ResourceKeyword: "mappings", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/pkg/multicloud/hcso/client/modules/mod_natgateway.go b/pkg/multicloud/hcso/client/modules/mod_natgateway.go deleted file mode 100644 index 8405112b61..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_natgateway.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/requests" -) - -type SNatGatewayManager struct { - SResourceManager -} - -type sProjectHook struct { - projectId string -} - -func (self *sProjectHook) Process(request requests.IRequest) { - request.AddHeaderParam("X-Project-Id", self.projectId) -} - -func NewNatGatewayManager(cfg manager.IManagerConfig) *SNatGatewayManager { - man := &SNatGatewayManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameNAT, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "nat_gateway", - KeywordPlural: "nat_gateways", - - ResourceKeyword: "nat_gateways", - }} - if len(cfg.GetProjectId()) > 0 { - man.requestHook = &sProjectHook{cfg.GetProjectId()} - } - return man -} diff --git a/pkg/multicloud/hcso/client/modules/mod_port.go b/pkg/multicloud/hcso/client/modules/mod_port.go deleted file mode 100644 index c3c17fb87e..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_port.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/requests" -) - -type SPortManager struct { - SResourceManager -} - -type portProject struct { - projectId string -} - -// port接口查询时若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊) -// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID -func (self *portProject) Process(request requests.IRequest) { - request.AddHeaderParam("X-Project-Id", self.projectId) -} - -func NewPortManager(cfg manager.IManagerConfig) *SPortManager { - var requestHook portProject - if len(cfg.GetProjectId()) > 0 { - requestHook = portProject{projectId: cfg.GetProjectId()} - } - - return &SPortManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager2(cfg, &requestHook), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "port", - KeywordPlural: "ports", - - ResourceKeyword: "ports", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_projects.go b/pkg/multicloud/hcso/client/modules/mod_projects.go deleted file mode 100644 index 334402ef5c..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_projects.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type SProjectManager struct { - SResourceManager -} - -func NewProjectManager(cfg manager.IManagerConfig) *SProjectManager { - m := &SProjectManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v3", - Keyword: "project", - KeywordPlural: "projects", - - ResourceKeyword: "projects", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} - -func (manager *SProjectManager) ListRoles(projectId, groupId string) (*responses.ListResult, error) { - if len(projectId) == 0 { - return nil, fmt.Errorf("missing projectId") - } - if len(groupId) == 0 { - return nil, fmt.Errorf("missing groupId") - } - res := fmt.Sprintf("%s/groups/%s/roles", projectId, groupId) - return manager.ListInContextWithSpec(nil, res, nil, "roles") -} - -func (manager *SProjectManager) DeleteProjectRole(projectId, groupId, roleId string) error { - if len(projectId) == 0 { - return fmt.Errorf("missing projectId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.DeleteInContextWithSpec(nil, projectId, res, nil, nil, "") - if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return err -} - -func (manager *SProjectManager) AddProjectRole(projectId string, groupId, roleId string) error { - if len(projectId) == 0 { - return fmt.Errorf("missing projectId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.UpdateInContextWithSpec(nil, projectId, res, nil, "") - return err -} diff --git a/pkg/multicloud/hcso/client/modules/mod_quotas.go b/pkg/multicloud/hcso/client/modules/mod_quotas.go deleted file mode 100644 index ac0915fb54..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_quotas.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SQuotaManager struct { - SResourceManager -} - -func NewQuotaManager(cfg manager.IManagerConfig) *SQuotaManager { - return &SQuotaManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEVS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "quotas", - KeywordPlural: "quotas", - - ResourceKeyword: "quotas", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_regions.go b/pkg/multicloud/hcso/client/modules/mod_regions.go deleted file mode 100644 index 96a2bf6650..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_regions.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SRegionManager struct { - SResourceManager -} - -func NewRegionManager(cfg manager.IManagerConfig) *SRegionManager { - return &SRegionManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v3", - Keyword: "region", - KeywordPlural: "regions", - - ResourceKeyword: "regions", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_roles.go b/pkg/multicloud/hcso/client/modules/mod_roles.go deleted file mode 100644 index 7a131cec47..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_roles.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SRoleManager struct { - SResourceManager -} - -func NewRoleManager(cfg manager.IManagerConfig) *SRoleManager { - m := &SRoleManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v3", - Keyword: "role", - KeywordPlural: "roles", - - ResourceKeyword: "roles", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/pkg/multicloud/hcso/client/modules/mod_saml_provider.go b/pkg/multicloud/hcso/client/modules/mod_saml_provider.go deleted file mode 100644 index a026aa83d1..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_saml_provider.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SAMLProviderManager struct { - SResourceManager -} - -func NewSAMLProviderManager(cfg manager.IManagerConfig) *SAMLProviderManager { - m := &SAMLProviderManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v3/OS-FEDERATION", - Keyword: "identity_provider", - KeywordPlural: "identity_providers", - - ResourceKeyword: "identity_providers", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/pkg/multicloud/hcso/client/modules/mod_secgroup_rules.go b/pkg/multicloud/hcso/client/modules/mod_secgroup_rules.go deleted file mode 100644 index 73889e276e..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_secgroup_rules.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SSecgroupRuleManager struct { - SResourceManager -} - -func NewSecgroupRuleManager(cfg manager.IManagerConfig) *SSecgroupRuleManager { - return &SSecgroupRuleManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "security_group_rule", - KeywordPlural: "security_group_rules", - - ResourceKeyword: "security-group-rules", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_secgroups.go b/pkg/multicloud/hcso/client/modules/mod_secgroups.go deleted file mode 100644 index 624a6ec2f4..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_secgroups.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SSecurityGroupManager struct { - SResourceManager -} - -func NewSecurityGroupManager(cfg manager.IManagerConfig) *SSecurityGroupManager { - return &SSecurityGroupManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "security_group", - KeywordPlural: "security_groups", - - ResourceKeyword: "security-groups", - }} -} - -func NewNovaSecurityGroupManager(cfg manager.IManagerConfig) *SSecurityGroupManager { - return &SSecurityGroupManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2.1", - Keyword: "security_group", - KeywordPlural: "security_groups", - - ResourceKeyword: "os-security-groups", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_servers.go b/pkg/multicloud/hcso/client/modules/mod_servers.go deleted file mode 100644 index 0fdac628b0..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_servers.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - "strconv" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type SServerManager struct { - SResourceManager -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212668.html -// v.1.1 新增支持创建包年/包月的弹性云服务器。!!但是不支持查询等调用 https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html -func NewServerManager(cfg manager.IManagerConfig) *SServerManager { - return &SServerManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "server", - KeywordPlural: "servers", - - ResourceKeyword: "cloudservers", - }} -} - -func (self *SServerManager) List(querys map[string]string) (*responses.ListResult, error) { - if offset, exists := querys["offset"]; !exists { - // 华为云分页参数各式各样。cloudserver offset从1开始。部分其他接口从0开始。 - // 另外部分接口使用pager分页 或者 maker分页 - querys["offset"] = "1" - } else { - n, err := strconv.Atoi(offset) - if err != nil { - return nil, fmt.Errorf("offset is invalid: %s", offset) - } - querys["offset"] = strconv.Itoa(n + 1) - } - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -/* -返回job id 或者 order id - -https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html -创建按需的弹性云服务 ——> job_id 任务ID (返回数据uuid举例:"70a599e0-31e7-49b7-b260-868f441e862b") -包年包月机器 --> order_id (返回数据举例: "CS1711152257C60TL") -*/ -func (self *SServerManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { - origin_version := self.version - self.version = "v1.1" - defer func() { self.version = origin_version }() - - ret, err := self.CreateInContextWithSpec(nil, "", params, "") - if err != nil { - log.Debugf("AsyncCreate %s", err) - return "", err - } - - log.Debugf("AsyncCreate result %s", ret.String()) - // 按需机器 - jobId, err := ret.GetString("job_id") - if err == nil { - return jobId, nil - } - - // 包年包月机器 - return ret.GetString("order_id") -} - -func (self *SServerManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return nil, fmt.Errorf("not supported.please use AsyncCreate") -} - -// 不推荐使用这个manager -func NewNovaServerManager(cfg manager.IManagerConfig) *SServerManager { - return &SServerManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2.1", - Keyword: "server", - KeywordPlural: "servers", - - ResourceKeyword: "servers", - }} -} - -// 重装弹性云服务器操作系统(安装Cloud-init),请用这个manager -func NewServerV2Manager(cfg manager.IManagerConfig) *SServerManager { - return &SServerManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "server", - KeywordPlural: "servers", - - ResourceKeyword: "cloudservers", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_sfs.go b/pkg/multicloud/hcso/client/modules/mod_sfs.go deleted file mode 100644 index 8e77901859..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_sfs.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type SfsTurboManager struct { - SResourceManager -} - -func NewSfsTurboManager(cfg manager.IManagerConfig) *SfsTurboManager { - return &SfsTurboManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameSFSTurbo, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "", - KeywordPlural: "shares", - - ResourceKeyword: "sfs-turbo/shares", - }} -} - -func (self *SfsTurboManager) List(querys map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -func (self *SfsTurboManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.CreateInContextWithSpec(self.ctx, "", params, "") -} diff --git a/pkg/multicloud/hcso/client/modules/mod_snapshots.go b/pkg/multicloud/hcso/client/modules/mod_snapshots.go deleted file mode 100644 index 86a7cdd71b..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_snapshots.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type SSnapshotManager struct { - SResourceManager -} - -func NewSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager { - return &SSnapshotManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEVS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "snapshot", - KeywordPlural: "snapshots", - - ResourceKeyword: "snapshots", - }} -} - -func (self *SSnapshotManager) List(querys map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html -// 回滚快照只能用这个manger。其他情况请不要使用 -// 另外,香港-亚太还支持另外一个接口。https://support.huaweicloud.com/api-evs/zh-cn_topic_0142374138.html -func NewOsSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager { - return &SSnapshotManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEVS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "snapshot", - KeywordPlural: "snapshots", - - ResourceKeyword: "os-vendor-snapshots", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_snat_rules.go b/pkg/multicloud/hcso/client/modules/mod_snat_rules.go deleted file mode 100644 index ba9d1fcb2c..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_snat_rules.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SNatSRuleManager struct { - SResourceManager -} - -func NewNatSManager(cfg manager.IManagerConfig) *SNatSRuleManager { - man := &SNatSRuleManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameNAT, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "snat_rule", - KeywordPlural: "snat_rules", - - ResourceKeyword: "snat_rules", - }} - if len(cfg.GetProjectId()) > 0 { - man.requestHook = &sProjectHook{cfg.GetProjectId()} - } - return man -} diff --git a/pkg/multicloud/hcso/client/modules/mod_subnets.go b/pkg/multicloud/hcso/client/modules/mod_subnets.go deleted file mode 100644 index 786cc8b2eb..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_subnets.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SSubnetManager struct { - SResourceManager -} - -func NewSubnetManager(cfg manager.IManagerConfig) *SSubnetManager { - return &SSubnetManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "subnet", - KeywordPlural: "subnets", - - ResourceKeyword: "subnets", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_traces.go b/pkg/multicloud/hcso/client/modules/mod_traces.go deleted file mode 100644 index 71bd4bc951..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_traces.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type STraceManager struct { - SResourceManager -} - -func NewTraceManager(cfg manager.IManagerConfig) *STraceManager { - return &STraceManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameCTS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2.0", - Keyword: "trace", - KeywordPlural: "traces", - - ResourceKeyword: "system/trace", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_users.go b/pkg/multicloud/hcso/client/modules/mod_users.go deleted file mode 100644 index a37956619e..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_users.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" -) - -type SUserManager struct { - SResourceManager -} - -func NewUserManager(cfg manager.IManagerConfig) *SUserManager { - user := &SUserManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v3.0/OS-USER", - Keyword: "user", - KeywordPlural: "users", - - ResourceKeyword: "users", - }} - user.SetDomainId(cfg.GetDomainId()) - return user -} - -func (self *SUserManager) List(querys map[string]string) (*responses.ListResult, error) { - self.SetVersion("v3") - return self.SResourceManager.List(querys) -} - -func (self *SUserManager) Delete(id string) (jsonutils.JSONObject, error) { - self.SetVersion("v3") - return self.SResourceManager.Delete(id, nil) -} - -func (self *SUserManager) ResetPassword(id, password string) error { - params := map[string]interface{}{ - "user": map[string]string{ - "password": password, - }, - } - _, err := self.SResourceManager.Update(id, jsonutils.Marshal(params)) - return err -} - -func (self *SUserManager) ListGroups(userId string) (*responses.ListResult, error) { - self.SetVersion("v3") - return self.SResourceManager.ListInContextWithSpec(nil, fmt.Sprintf("%s/groups", userId), nil, "groups") -} diff --git a/pkg/multicloud/hcso/client/modules/mod_vpc_peerings.go b/pkg/multicloud/hcso/client/modules/mod_vpc_peerings.go deleted file mode 100644 index c06c173de3..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_vpc_peerings.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SVpcPeeringManager struct { - SResourceManager -} - -func NewVpcPeeringManager(cfg manager.IManagerConfig) *SVpcPeeringManager { - return &SVpcPeeringManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "peering", - KeywordPlural: "peerings", - - ResourceKeyword: "vpc/peerings", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_vpc_routes.go b/pkg/multicloud/hcso/client/modules/mod_vpc_routes.go deleted file mode 100644 index 6f1fe97135..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_vpc_routes.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SVpcRouteManager struct { - SResourceManager -} - -func NewVpcRouteManager(cfg manager.IManagerConfig) *SVpcRouteManager { - return &SVpcRouteManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - // the url should not include the field "projectid" in huawei cloud api v2.0 - ProjectId: "", - version: "v2.0", - Keyword: "route", - KeywordPlural: "routes", - - ResourceKeyword: "vpc/routes", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_vpcs.go b/pkg/multicloud/hcso/client/modules/mod_vpcs.go deleted file mode 100644 index f0133887ea..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_vpcs.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SVpcManager struct { - SResourceManager -} - -func NewVpcManager(cfg manager.IManagerConfig) *SVpcManager { - return &SVpcManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "vpc", - KeywordPlural: "vpcs", - - ResourceKeyword: "vpcs", - }} -} diff --git a/pkg/multicloud/hcso/client/modules/mod_zones.go b/pkg/multicloud/hcso/client/modules/mod_zones.go deleted file mode 100644 index 05d79116b1..0000000000 --- a/pkg/multicloud/hcso/client/modules/mod_zones.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" -) - -type SZoneManager struct { - SResourceManager -} - -func NewZoneManager(cfg manager.IManagerConfig) *SZoneManager { - return &SZoneManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "availabilityZoneInfo", - KeywordPlural: "availabilityZoneInfo", - - ResourceKeyword: "os-availability-zone", - }} -} diff --git a/pkg/multicloud/hcso/client/requests/doc.go b/pkg/multicloud/hcso/client/requests/doc.go deleted file mode 100644 index b6c70dcf5b..0000000000 --- a/pkg/multicloud/hcso/client/requests/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 requests // import "yunion.io/x/onecloud/pkg/multicloud/hcso/client/requests" diff --git a/pkg/multicloud/hcso/client/responses/doc.go b/pkg/multicloud/hcso/client/responses/doc.go deleted file mode 100644 index a6621472b0..0000000000 --- a/pkg/multicloud/hcso/client/responses/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 responses // import "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" diff --git a/pkg/multicloud/hcso/client/responses/responses_test.go b/pkg/multicloud/hcso/client/responses/responses_test.go deleted file mode 100644 index 8cd532ddba..0000000000 --- a/pkg/multicloud/hcso/client/responses/responses_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 responses - -import ( - "testing" - - "yunion.io/x/jsonutils" -) - -func TestTransColonToDot(t *testing.T) { - raw := `{"A:b::C": "1:2:3", "A": true, "B": ["1:2", ":", "c"], "D:E": true}` - obj, err := jsonutils.ParseString(raw) - if err != nil { - t.Fatalf("json parse: %v", err) - } - gotj, err := TransColonToDot(obj) - if err != nil { - t.Fatalf("trans: %v", err) - } - wantj, _ := jsonutils.ParseString(`{"A":true,"A.b..C":"1:2:3","B":["1:2",":","c"],"D.E":true}`) - if !wantj.Equals(gotj) { - t.Errorf("trans failed, want:\n%s\ngot:\n%s", wantj, gotj) - } -} diff --git a/pkg/multicloud/hcso/cloudgroup.go b/pkg/multicloud/hcso/cloudgroup.go deleted file mode 100644 index 033e566161..0000000000 --- a/pkg/multicloud/hcso/cloudgroup.go +++ /dev/null @@ -1,446 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SCloudgroup struct { - client *SHuaweiClient - Name string - Description string - Id string - CreateTime string -} - -func (group *SCloudgroup) GetName() string { - return group.Name -} - -func (group *SCloudgroup) GetDescription() string { - return group.Description -} - -func (group *SCloudgroup) GetGlobalId() string { - return group.Id -} - -func (group *SCloudgroup) Delete() error { - return group.client.DeleteGroup(group.Id) -} - -func (group *SCloudgroup) AddUser(name string) error { - user, err := group.client.GetIClouduserByName(name) - if err != nil { - return errors.Wrap(err, "GetIClouduserByName") - } - return group.client.AddUserToGroup(group.Id, user.GetGlobalId()) -} - -func (group *SCloudgroup) RemoveUser(name string) error { - user, err := group.client.GetIClouduserByName(name) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return errors.Wrapf(err, "GetIClouduserByName(%s)", name) - } - return group.client.RemoveUserFromGroup(group.Id, user.GetGlobalId()) -} - -func (group *SCloudgroup) DetachSystemPolicy(roleId string) error { - return group.client.DetachGroupRole(group.Id, roleId) -} - -func (group *SCloudgroup) DetachCustomPolicy(roleId string) error { - return group.client.DetachGroupCustomRole(group.Id, roleId) -} - -func (group *SCloudgroup) AttachSystemPolicy(roleId string) error { - return group.client.AttachGroupRole(group.Id, roleId) -} - -func (group *SCloudgroup) AttachCustomPolicy(roleId string) error { - return group.client.AttachGroupCustomRole(group.Id, roleId) -} - -func (group *SCloudgroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - roles, err := group.client.GetGroupRoles(group.Id) - if err != nil { - return nil, errors.Wrap(err, "GetGroupRoles") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range roles { - _, err := group.client.GetRole(roles[i].GetName()) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - continue - } - return nil, errors.Wrapf(err, "GetRole(%s)", roles[i].GetName()) - } - ret = append(ret, &roles[i]) - } - return ret, nil -} - -func (group *SCloudgroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - roles, err := group.client.GetGroupRoles(group.Id) - if err != nil { - return nil, errors.Wrap(err, "GetGroupRoles") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range roles { - _, err := group.client.GetCustomRole(roles[i].GetName()) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - continue - } - return nil, errors.Wrapf(err, "GetRole(%s)", roles[i].GetName()) - } - ret = append(ret, &roles[i]) - } - return ret, nil -} - -func (group *SCloudgroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { - users, err := group.client.GetGroupUsers(group.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.IClouduser{} - for i := range users { - users[i].client = group.client - ret = append(ret, &users[i]) - } - return ret, nil -} - -func (self *SHuaweiClient) GetGroups(domainId, name string) ([]SCloudgroup, error) { - params := map[string]string{} - if len(domainId) > 0 { - params["domain_id"] = self.ownerId - } - if len(name) > 0 { - params["name"] = name - } - - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - groups := []SCloudgroup{} - err = doListAllWithNextLink(client.Groups.List, params, &groups) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return groups, nil -} - -func (self *SHuaweiClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - groups, err := self.GetGroups("", "") - if err != nil { - return nil, errors.Wrap(err, "GetGroup") - } - ret := []cloudprovider.ICloudgroup{} - for i := range groups { - if groups[i].Name != "admin" { - groups[i].client = self - ret = append(ret, &groups[i]) - } - } - return ret, nil -} - -func (self *SHuaweiClient) GetGroupUsers(groupId string) ([]SClouduser, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - resp, err := client.Groups.ListInContextWithSpec(nil, fmt.Sprintf("%s/users", groupId), nil, "users") - if err != nil { - return nil, errors.Wrap(err, "") - } - users := []SClouduser{} - err = jsonutils.Update(&users, resp.Data) - if err != nil { - return nil, errors.Wrap(err, "jsonutils.Update") - } - return users, nil -} - -func (self *SHuaweiClient) GetGroupRoles(groupId string) ([]SRole, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - resp, err := client.Domains.ListRoles(self.ownerId, groupId) - if err != nil { - return nil, errors.Wrap(err, "ListRoles") - } - roles := []SRole{} - err = jsonutils.Update(&roles, resp.Data) - if err != nil { - return nil, errors.Wrap(err, "jsonutils.Update") - } - return roles, nil -} - -func (self *SHuaweiClient) CreateGroup(name, desc string) (*SCloudgroup, error) { - params := map[string]string{ - "name": name, - } - if len(desc) > 0 { - params["description"] = desc - } - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - group := SCloudgroup{client: self} - err = DoCreate(client.Groups.Create, jsonutils.Marshal(map[string]interface{}{"group": params}), &group) - if err != nil { - return nil, errors.Wrap(err, "DoCreate") - } - return &group, nil -} - -func (self *SHuaweiClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - group, err := self.CreateGroup(name, desc) - if err != nil { - return nil, errors.Wrap(err, "CreateGroup") - } - return group, nil -} - -func (self *SHuaweiClient) DeleteGroup(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - return DoDeleteWithSpec(client.Groups.DeleteInContextWithSpec, nil, id, "", nil, nil) -} - -func (self *SHuaweiClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - groups, err := self.GetGroups(self.ownerId, name) - if err != nil { - return nil, errors.Wrap(err, "GetGroups") - } - if len(groups) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(groups) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - groups[0].client = self - return &groups[0], nil -} - -func (self *SHuaweiClient) AddUserToGroup(groupId, userId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.Groups.UpdateInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, "") - return err -} - -func (self *SHuaweiClient) RemoveUserFromGroup(groupId, userId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.Groups.DeleteInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, nil, "") - return err -} - -func (self *SHuaweiClient) DetachGroupRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - role, err := self.GetRole(roleId) - if err != nil { - return errors.Wrapf(err, "GetRole(%s)", roleId) - } - if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.DeleteRole(self.ownerId, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "DeleteRole") - } - if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.DeleteProjectRole(self.GetMosProjectId(), groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "DeleteProjectRole") - } - } - } - if role.Type == "XA" || role.Type == "AA" { - projects, err := self.GetProjects() - if err != nil { - return errors.Wrapf(err, "GetProjects") - } - for _, project := range projects { - err = client.Projects.DeleteProjectRole(project.ID, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "DeleteProjectRole") - } - } - } - return nil -} - -func (self *SHuaweiClient) DetachGroupCustomRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - role, err := self.GetCustomRole(roleId) - if err != nil { - return errors.Wrapf(err, "GetCustomRole(%s)", roleId) - } - if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.DeleteRole(self.ownerId, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "DeleteRole") - } - if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.DeleteProjectRole(self.GetMosProjectId(), groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "DeleteProjectRole") - } - } - } - if role.Type == "XA" || role.Type == "AA" { - projects, err := self.GetProjects() - if err != nil { - return errors.Wrapf(err, "GetProjects") - } - for _, project := range projects { - err = client.Projects.DeleteProjectRole(project.ID, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "DeleteProjectRole") - } - } - } - return nil -} - -func (self *SHuaweiClient) GetCustomRole(name string) (*SRole, error) { - roles, err := self.GetCustomRoles() - if err != nil { - return nil, errors.Wrapf(err, "GetCustomRoles(%s)", name) - } - for i := range roles { - if roles[i].DisplayName == name { - return &roles[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) -} - -func (self *SHuaweiClient) GetRole(name string) (*SRole, error) { - roles, err := self.GetRoles("", "") - if err != nil { - return nil, errors.Wrapf(err, "GetRoles(%s)", name) - } - for i := range roles { - if roles[i].DisplayName == name { - return &roles[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) -} - -func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - role, err := self.GetRole(roleId) - if err != nil { - return errors.Wrapf(err, "GetRole(%s)", roleId) - } - if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.AddRole(self.ownerId, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddRole") - } - if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddProjectRole") - } - } - } - if role.Type == "XA" || role.Type == "AA" { - projects, err := self.GetProjects() - if err != nil { - return errors.Wrapf(err, "GetProjects") - } - for _, project := range projects { - err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddProjectRole") - } - } - } - return nil -} - -func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - role, err := self.GetCustomRole(roleId) - if err != nil { - return errors.Wrapf(err, "GetRole(%s)", roleId) - } - if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.AddRole(self.ownerId, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddRole") - } - if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddProjectRole") - } - } - } - if role.Type == "XA" || role.Type == "AA" { - projects, err := self.GetProjects() - if err != nil { - return errors.Wrapf(err, "GetProjects") - } - for _, project := range projects { - err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddProjectRole") - } - } - } - return nil -} diff --git a/pkg/multicloud/hcso/clouduser.go b/pkg/multicloud/hcso/clouduser.go deleted file mode 100644 index 5e16165e72..0000000000 --- a/pkg/multicloud/hcso/clouduser.go +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/modules" -) - -type SLink struct { - Next string - Previous string - Self string -} - -type SClouduser struct { - client *SHuaweiClient - - Description string - DomainId string - Enabled bool - ForceResetPwd bool - Id string - LastProjectId string - Links SLink - Name string - PasswordExpiresAt string - PwdStatus bool -} - -func (user *SClouduser) GetGlobalId() string { - return user.Id -} - -func (user *SClouduser) GetName() string { - return user.Name -} - -func (user *SClouduser) GetEmailAddr() string { - return "" -} - -func (user *SClouduser) GetInviteUrl() string { - return "" -} - -func (user *SClouduser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return []cloudprovider.ICloudpolicy{}, nil -} - -func (user *SClouduser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return []cloudprovider.ICloudpolicy{}, nil -} - -func (user *SClouduser) AttachSystemPolicy(policyType string) error { - return cloudprovider.ErrNotSupported -} - -func (user *SClouduser) AttachCustomPolicy(policyType string) error { - return cloudprovider.ErrNotSupported -} - -func (user *SClouduser) DetachSystemPolicy(policyId string) error { - return cloudprovider.ErrNotSupported -} - -func (user *SClouduser) DetachCustomPolicy(policyId string) error { - return cloudprovider.ErrNotSupported -} - -func (user *SClouduser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - groups, err := user.client.ListUserGroups(user.Id) - if err != nil { - return nil, errors.Wrap(err, "Users.ListGroups") - } - ret := []cloudprovider.ICloudgroup{} - for i := range groups { - groups[i].client = user.client - ret = append(ret, &groups[i]) - } - return ret, nil -} - -func (user *SClouduser) Delete() error { - return user.client.DeleteClouduser(user.Id) -} - -func (user *SClouduser) IsConsoleLogin() bool { - return user.Enabled == true -} - -func (user *SClouduser) ResetPassword(password string) error { - return user.client.ResetClouduserPassword(user.Id, password) -} - -func (self *SHuaweiClient) DeleteClouduser(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.Users.Delete(id) - return err -} - -func (self *SHuaweiClient) ListUserGroups(userId string) ([]SCloudgroup, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - result, err := client.Users.ListGroups(userId) - if err != nil { - return nil, errors.Wrap(err, "Users.ListGroups") - } - groups := []SCloudgroup{} - err = jsonutils.Update(&groups, result.Data) - if err != nil { - return nil, errors.Wrap(err, "jsonutils.Update") - } - return groups, nil -} - -func (self *SHuaweiClient) GetCloudusers(name string) ([]SClouduser, error) { - params := map[string]string{} - if len(name) > 0 { - params["name"] = name - } - users := []SClouduser{} - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - err = doListAllWithOffset(client.Users.List, params, &users) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return users, nil -} - -func (self *SHuaweiClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { - users, err := self.GetCloudusers("") - if err != nil { - return nil, errors.Wrap(err, "GetCloudusers") - } - iUsers := []cloudprovider.IClouduser{} - for i := range users { - if users[i].Name != self.ownerName { - users[i].client = self - iUsers = append(iUsers, &users[i]) - } - } - return iUsers, nil -} - -func (self *SHuaweiClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - users, err := self.GetCloudusers(name) - if err != nil { - return nil, errors.Wrapf(err, "GetCloudusers(%s)", name) - } - if len(users) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(users) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - users[0].client = self - return &users[0], nil -} - -func (self *SHuaweiClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - return self.CreateClouduser(conf.Name, conf.Password, conf.Desc) -} - -func (self *SHuaweiClient) CreateClouduser(name, password, desc string) (*SClouduser, error) { - params := map[string]string{ - "name": name, - "domain_id": self.ownerId, - } - if len(password) > 0 { - params["password"] = password - } - if len(desc) > 0 { - params["description"] = desc - } - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - user := SClouduser{client: self} - err = DoCreate(client.Users.Create, jsonutils.Marshal(map[string]interface{}{"user": params}), &user) - if err != nil { - ce, ok := err.(*modules.HuaweiClientError) - if ok && len(ce.Errorcode) > 0 && ce.Errorcode[0] == "1101" { - return nil, errors.Wrap(err, `IAM user name. The length is between 5 and 32. The first digit is not a number. Special characters can only contain the '_' '-' or ' '`) //https://support.huaweicloud.com/api-iam/iam_08_0015.html - } - return nil, errors.Wrap(err, "DoCreate") - } - return &user, nil -} - -func (self *SHuaweiClient) ResetClouduserPassword(id, password string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - return client.Users.ResetPassword(id, password) -} - -type SAccessKey struct { - client *SHuaweiClient - - AccessKey string `json:"access"` - Secret string `json:"secret"` - Description string `json:"description"` - Status string `json:"status"` - CreatedAt time.Time `json:"create_time"` -} - -func (self *SHuaweiClient) GetAKSK(id string) ([]cloudprovider.SAccessKey, error) { - obj, err := self.getAKSKList(id) - if err != nil { - return nil, errors.Wrap(err, "SHuaweiClient.getAKSKList") - } - aks := make([]SAccessKey, 0) - obj.Unmarshal(&aks, "credentials") - res := make([]cloudprovider.SAccessKey, len(aks)) - for i := 0; i < len(aks); i++ { - res[i].Name = aks[i].Description - res[i].AccessKey = aks[i].AccessKey - res[i].Secret = aks[i].Secret - res[i].Status = aks[i].Status - res[i].CreatedAt = aks[i].CreatedAt - } - return res, nil -} - -func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKey, error) { - params := map[string]interface{}{ - "credential": map[string]interface{}{ - "user_id": id, - "description": name, - }, - } - obj, err := self.createAKSK(params) - if err != nil { - return nil, errors.Wrap(err, "SHuaweiClient.createAKSK") - } - ak := SAccessKey{} - obj.Unmarshal(&ak, "credential") - res := cloudprovider.SAccessKey{ - Name: ak.Description, - AccessKey: ak.AccessKey, - Secret: ak.Secret, - } - return &res, nil -} - -func (self *SHuaweiClient) DeleteAKSK(accessKey string) error { - _, err := self.deleteAKSK(accessKey) - return err -} - -func (user *SClouduser) DeleteAccessKey(accessKey string) error { - err := user.client.DeleteAKSK(accessKey) - if err != nil { - return errors.Wrap(err, "SHuaweiClient.deleteAKSK") - } - return nil -} - -func (user *SClouduser) CreateAccessKey(name string) (*cloudprovider.SAccessKey, error) { - return user.client.CreateAKSK(user.Id, name) -} - -func (user *SClouduser) GetAccessKeys() ([]cloudprovider.SAccessKey, error) { - return user.client.GetAKSK(user.Id) -} diff --git a/pkg/multicloud/hcso/dbinstance.go b/pkg/multicloud/hcso/dbinstance.go deleted file mode 100644 index e1d6a2e51b..0000000000 --- a/pkg/multicloud/hcso/dbinstance.go +++ /dev/null @@ -1,693 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - "fmt" - "time" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SBackupStrategy struct { - KeepDays int - StartTime string -} - -type SDatastore struct { - Type string - Version string -} - -type SHa struct { - ReplicationMode string -} - -type SNonde struct { - AvailabilityZone string - Id string - Name string - Role string - Staus string -} - -type SVolume struct { - Size int - Type string -} - -type SRelatedInstance struct { - Id string - Type string -} - -type SDBInstance struct { - multicloud.SDBInstanceBase - multicloud.HuaweiTags - region *SRegion - - flavorCache []SDBInstanceFlavor - - BackupStrategy SBackupStrategy - Created string //time.Time - Datastore SDatastore - DbUserName string - DIskEncryptionId string - FlavorRef string - Ha SHa - Id string - MaintenanceWindow string - Name string - Nodes []SNonde - Port int - PrivateIps []string - PublicIps []string - Region string - RelatedInstance []SRelatedInstance - SecurityGroupId string - Status string - SubnetId string - SwitchStrategy string - TimeZone string - Type string - Updated string //time.Time - Volume SVolume - VpcId string - EnterpriseProjectId string -} - -func (region *SRegion) GetDBInstances() ([]SDBInstance, error) { - params := map[string]string{} - dbinstances := []SDBInstance{} - err := doListAllWithOffset(region.ecsClient.DBInstance.List, params, &dbinstances) - return dbinstances, err -} - -func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { - if len(instanceId) == 0 { - return nil, cloudprovider.ErrNotFound - } - instance := SDBInstance{region: region} - err := DoGet(region.ecsClient.DBInstance.Get, instanceId, nil, &instance) - return &instance, err -} - -func (rds *SDBInstance) GetName() string { - return rds.Name -} - -func (rds *SDBInstance) GetId() string { - return rds.Id -} - -func (rds *SDBInstance) GetGlobalId() string { - return rds.GetId() -} - -// 值为“BUILD”,表示实例正在创建。 -// 值为“ACTIVE”,表示实例正常。 -// 值为“FAILED”,表示实例异常。 -// 值为“FROZEN”,表示实例冻结。 -// 值为“MODIFYING”,表示实例正在扩容。 -// 值为“REBOOTING”,表示实例正在重启。 -// 值为“RESTORING”,表示实例正在恢复。 -// 值为“MODIFYING INSTANCE TYPE”,表示实例正在转主备。 -// 值为“SWITCHOVER”,表示实例正在主备切换。 -// 值为“MIGRATING”,表示实例正在迁移。 -// 值为“BACKING UP”,表示实例正在进行备份。 -// 值为“MODIFYING DATABASE PORT”,表示实例正在修改数据库端口。 -// 值为“STORAGE FULL”,表示实例磁盘空间满。 - -func (rds *SDBInstance) GetStatus() string { - switch rds.Status { - case "BUILD", "MODIFYING", "MODIFYING INSTANCE TYPE", "SWITCHOVER", "MODIFYING DATABASE PORT": - return api.DBINSTANCE_DEPLOYING - case "ACTIVE": - return api.DBINSTANCE_RUNNING - case "FAILED", "FROZEN", "STORAGE FULL": - return api.DBINSTANCE_UNKNOWN - case "REBOOTING": - return api.DBINSTANCE_REBOOTING - case "RESTORING": - return api.DBINSTANCE_RESTORING - case "MIGRATING": - return api.DBINSTANCE_MIGRATING - case "BACKING UP": - return api.DBINSTANCE_BACKING_UP - } - return rds.Status -} - -func (rds *SDBInstance) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (rds *SDBInstance) GetSecurityGroupIds() ([]string, error) { - return []string{rds.SecurityGroupId}, nil -} - -func (rds *SDBInstance) fetchFlavor() error { - if len(rds.flavorCache) > 0 { - return nil - } - flavors, err := rds.region.GetDBInstanceFlavors(rds.Datastore.Type, rds.Datastore.Version) - if err != nil { - return err - } - rds.flavorCache = flavors - return nil -} - -func (rds *SDBInstance) GetExpiredAt() time.Time { - return time.Time{} -} - -func (rds *SDBInstance) GetStorageType() string { - return rds.Volume.Type -} - -func (rds *SDBInstance) GetCreatedAt() time.Time { - t, err := time.Parse("2006-01-02T15:04:05Z0700", rds.Created) - if err != nil { - return time.Time{} - } - return t -} - -func (rds *SDBInstance) GetEngine() string { - return rds.Datastore.Type -} - -func (rds *SDBInstance) GetEngineVersion() string { - return rds.Datastore.Version -} - -func (rds *SDBInstance) GetInstanceType() string { - return rds.FlavorRef -} - -func (rds *SDBInstance) GetCategory() string { - switch rds.Type { - case "Single": - return api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE - case "Ha": - return api.HUAWEI_DBINSTANCE_CATEGORY_HA - case "Replica": - return api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA - } - return rds.Type -} - -func (rds *SDBInstance) GetVcpuCount() int { - err := rds.fetchFlavor() - if err != nil { - log.Errorf("failed to fetch flavors: %v", err) - return 0 - } - for _, flavor := range rds.flavorCache { - if flavor.SpecCode == rds.FlavorRef { - return flavor.Vcpus - } - } - return 0 -} - -func (rds *SDBInstance) GetVmemSizeMB() int { - err := rds.fetchFlavor() - if err != nil { - log.Errorf("failed to fetch flavors: %v", err) - return 0 - } - for _, flavor := range rds.flavorCache { - if flavor.SpecCode == rds.FlavorRef { - return flavor.Ram * 1024 - } - } - return 0 -} - -func (rds *SDBInstance) GetDiskSizeGB() int { - return rds.Volume.Size -} - -func (rds *SDBInstance) GetPort() int { - return rds.Port -} - -func (rds *SDBInstance) GetMaintainTime() string { - return rds.MaintenanceWindow -} - -func (rds *SDBInstance) GetIVpcId() string { - return rds.VpcId -} - -func (rds *SDBInstance) GetProjectId() string { - return rds.EnterpriseProjectId -} - -func (rds *SDBInstance) Refresh() error { - instance, err := rds.region.GetDBInstance(rds.Id) - if err != nil { - return err - } - return jsonutils.Update(rds, instance) -} - -func (rds *SDBInstance) GetZone1Id() string { - return rds.GetZoneIdByRole("master") -} - -func (rds *SDBInstance) GetZoneIdByRole(role string) string { - for _, node := range rds.Nodes { - if node.Role == role { - zone, err := rds.region.getZoneById(node.AvailabilityZone) - if err != nil { - log.Errorf("failed to found zone %s for rds %s error: %v", node.AvailabilityZone, rds.Name, err) - return "" - } - return zone.GetGlobalId() - } - } - return "" -} - -func (rds *SDBInstance) GetZone2Id() string { - return rds.GetZoneIdByRole("slave") -} - -func (rds *SDBInstance) GetZone3Id() string { - return "" -} - -type SRdsNetwork struct { - SubnetId string - IP string -} - -func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { - ret := []cloudprovider.SDBInstanceNetwork{} - for _, ip := range rds.PrivateIps { - network := cloudprovider.SDBInstanceNetwork{ - IP: ip, - NetworkId: rds.SubnetId, - } - ret = append(ret, network) - } - return ret, nil -} - -func (rds *SDBInstance) GetInternalConnectionStr() string { - for _, ip := range rds.PrivateIps { - return ip - } - return "" -} - -func (rds *SDBInstance) GetConnectionStr() string { - for _, ip := range rds.PublicIps { - return ip - } - return "" -} - -func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { - dbinstance, err := region.GetDBInstance(instanceId) - if err != nil { - log.Errorf("failed to get dbinstance by id %s error: %v", instanceId, err) - } - return dbinstance, err -} - -func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - instances, err := region.GetDBInstances() - if err != nil { - return nil, errors.Wrapf(err, "region.GetDBInstances()") - } - idbinstances := []cloudprovider.ICloudDBInstance{} - for i := 0; i < len(instances); i++ { - instances[i].region = region - idbinstances = append(idbinstances, &instances[i]) - } - return idbinstances, nil -} - -func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { - parameters, err := rds.region.GetDBInstanceParameters(rds.Id) - if err != nil { - return nil, err - } - iparameters := []cloudprovider.ICloudDBInstanceParameter{} - for i := 0; i < len(parameters); i++ { - iparameters = append(iparameters, ¶meters[i]) - } - return iparameters, nil -} - -func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { - databases, err := rds.region.GetDBInstanceDatabases(rds.Id) - if err != nil { - return nil, errors.Wrap(err, "rds.region.GetDBInstanceDatabases(rds.Id)") - } - - idatabase := []cloudprovider.ICloudDBInstanceDatabase{} - for i := 0; i < len(databases); i++ { - databases[i].instance = rds - idatabase = append(idatabase, &databases[i]) - } - return idatabase, nil -} - -func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { - accounts, err := rds.region.GetDBInstanceAccounts(rds.Id) - if err != nil { - return nil, errors.Wrap(err, "rds.region.GetDBInstanceAccounts(rds.Id)") - } - - user := "root" - if rds.GetEngine() == api.DBINSTANCE_TYPE_SQLSERVER { - user = "rduser" - } - - accounts = append(accounts, SDBInstanceAccount{ - Name: user, - instance: rds, - }) - - iaccounts := []cloudprovider.ICloudDBInstanceAccount{} - for i := 0; i < len(accounts); i++ { - accounts[i].instance = rds - iaccounts = append(iaccounts, &accounts[i]) - } - return iaccounts, nil -} - -func (rds *SDBInstance) Delete() error { - return rds.region.DeleteDBInstance(rds.Id) -} - -func (region *SRegion) DeleteDBInstance(instanceId string) error { - _, err := region.ecsClient.DBInstance.Delete(instanceId, nil) - return err -} - -func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - zoneIds := []string{} - zones, err := region.GetIZones() - if err != nil { - return nil, err - } - for _, zone := range zones { - zoneIds = append(zoneIds, zone.GetId()) - } - - if len(desc.SecgroupIds) == 0 { - return nil, fmt.Errorf("Missing secgroupId") - } - - params := map[string]interface{}{ - "region": region.ID, - "name": desc.Name, - "datastore": map[string]string{ - "type": desc.Engine, - "version": desc.EngineVersion, - }, - "password": desc.Password, - "volume": map[string]interface{}{ - "type": desc.StorageType, - "size": desc.DiskSizeGB, - }, - "vpc_id": desc.VpcId, - "subnet_id": desc.NetworkId, - "security_group_id": desc.SecgroupIds[0], - } - - if len(desc.ProjectId) > 0 { - params["enterprise_project_id"] = desc.ProjectId - } - - if len(desc.MasterInstanceId) > 0 { - params["replica_of_id"] = desc.MasterInstanceId - delete(params, "security_group_id") - } - - if len(desc.RdsId) > 0 && len(desc.BackupId) > 0 { - params["restore_point"] = map[string]interface{}{ - "backup_id": desc.BackupId, - "instance_id": desc.RdsId, - "type": "backup", - } - } - - switch desc.Category { - case api.HUAWEI_DBINSTANCE_CATEGORY_HA: - switch desc.Engine { - case api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL: - params["ha"] = map[string]string{ - "mode": "Ha", - "replication_mode": "async", - } - case api.DBINSTANCE_TYPE_SQLSERVER: - params["ha"] = map[string]string{ - "mode": "Ha", - "replication_mode": "sync", - } - } - case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE: - case api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA: - } - - if desc.BillingCycle != nil { - periodType := "month" - periodNum := desc.BillingCycle.GetMonths() - if desc.BillingCycle.GetYears() > 0 { - periodType = "year" - periodNum = desc.BillingCycle.GetYears() - } - params["charge_info"] = map[string]interface{}{ - "charge_mode": "prePaid", - "period_type": periodType, - "period_num": periodNum, - "is_auto_renew": false, - } - } - params["flavor_ref"] = desc.InstanceType - params["availability_zone"] = desc.ZoneId - resp, err := region.ecsClient.DBInstance.Create(jsonutils.Marshal(params)) - if err != nil { - return nil, errors.Wrapf(err, "Create") - } - - instance := &SDBInstance{region: region} - err = resp.Unmarshal(instance, "instance") - if err != nil { - return nil, errors.Wrap(err, `resp.Unmarshal(&instance, "instance")`) - } - if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { - err = cloudprovider.Wait(10*time.Second, 20*time.Minute, func() (bool, error) { - job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) - if err != nil { - return false, nil - } - status, _ := job.GetString("status") - process, _ := job.GetString("process") - log.Debugf("create dbinstance job %s status: %s process: %s", jobId, status, process) - if status == "Completed" { - return true, nil - } - if status == "Failed" { - return false, fmt.Errorf("create failed") - } - return false, nil - }) - } - return instance, err -} - -func (rds *SDBInstance) Reboot() error { - return rds.region.RebootDBInstance(rds.Id) -} - -func (rds *SDBInstance) OpenPublicConnection() error { - return fmt.Errorf("Huawei current not support this operation") - //return rds.region.PublicConnectionAction(rds.Id, "openRC") -} - -func (rds *SDBInstance) ClosePublicConnection() error { - return fmt.Errorf("Huawei current not support this operation") - //return rds.region.PublicConnectionAction(rds.Id, "closeRC") -} - -func (region *SRegion) PublicConnectionAction(instanceId string, action string) error { - resp, err := region.ecsClient.DBInstance.PerformAction2(action, instanceId, nil, "") - if err != nil { - return errors.Wrapf(err, "rds.%s", action) - } - - if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { - err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { - job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) - if err != nil { - log.Errorf("failed to get job %s info error: %v", jobId, err) - return false - } - status, _ := job.GetString("status") - process, _ := job.GetString("process") - if status == "Completed" { - return true - } - log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, status, process) - return false - }) - } - - return nil - -} - -func (region *SRegion) RebootDBInstance(instanceId string) error { - params := jsonutils.Marshal(map[string]interface{}{ - "restart": map[string]string{}, - }) - resp, err := region.ecsClient.DBInstance.PerformAction2("action", instanceId, params, "") - if err != nil { - return err - } - if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { - err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { - job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) - if err != nil { - log.Errorf("failed to get job %s info error: %v", jobId, err) - return false - } - status, _ := job.GetString("status") - process, _ := job.GetString("process") - if status == "Completed" { - return true - } - log.Debugf("reboot dbinstance job %s status: %s process: %s", jobId, status, process) - return false - }) - } - return err -} - -func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { - return rds.region.CreateDBInstanceAccount(rds.Id, conf.Name, conf.Password) -} - -func (region *SRegion) CreateDBInstanceAccount(instanceId, account, password string) error { - params := map[string]string{ - "name": account, - "password": password, - } - _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/db_user", instanceId), jsonutils.Marshal(params), "") - return err -} - -func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { - return rds.region.CreateDBInstanceDatabase(rds.Id, conf.Name, conf.CharacterSet) -} - -func (region *SRegion) CreateDBInstanceDatabase(instanceId, database, characterSet string) error { - params := map[string]string{ - "name": database, - "character_set": characterSet, - } - _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/database", instanceId), jsonutils.Marshal(params), "") - return err -} - -func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { - return rds.region.ChangeDBInstanceConfig(rds.Id, desc.InstanceType, desc.DiskSizeGB) -} - -func (region *SRegion) ChangeDBInstanceConfig(instanceId string, instanceType string, diskSizeGb int) error { - instance, err := region.GetIDBInstanceById(instanceId) - if err != nil { - return errors.Wrapf(err, "region.GetIDBInstanceById(%s)", instanceId) - } - - if len(instanceType) > 0 { - params := map[string]map[string]string{ - "resize_flavor": map[string]string{ - "spec_code": instanceType, - }, - } - _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) - if err != nil { - return errors.Wrap(err, "resize_flavor") - } - cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) - } - if diskSizeGb > 0 { - params := map[string]map[string]int{ - "enlarge_volume": map[string]int{ - "size": diskSizeGb, - }, - } - _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) - if err != nil { - return errors.Wrap(err, "enlarge_volume") - } - cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) - } - return nil -} - -func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { - if len(conf.OriginDBInstanceExternalId) == 0 { - conf.OriginDBInstanceExternalId = rds.Id - } - return rds.region.RecoveryDBInstanceFromBackup(rds.Id, conf.OriginDBInstanceExternalId, conf.BackupId, conf.Databases) -} - -func (region *SRegion) RecoveryDBInstanceFromBackup(target, origin string, backupId string, databases map[string]string) error { - source := map[string]interface{}{ - "type": "backup", - "backup_id": backupId, - } - if len(origin) > 0 { - source["instance_id"] = origin - } - if len(databases) > 0 { - source["database_name"] = databases - } - params := map[string]interface{}{ - "source": source, - "target": map[string]string{ - "instance_id": target, - }, - } - _, err := region.ecsClient.DBInstance.PerformAction("", "recovery", jsonutils.Marshal(params)) - if err != nil { - return errors.Wrap(err, "dbinstance.recovery") - } - return nil -} - -func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/hcso/dbinstance_account.go b/pkg/multicloud/hcso/dbinstance_account.go deleted file mode 100644 index 28e13d9fe0..0000000000 --- a/pkg/multicloud/hcso/dbinstance_account.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceAccount struct { - multicloud.SDBInstanceAccountBase - multicloud.HuaweiTags - instance *SDBInstance - Name string -} - -func (account *SDBInstanceAccount) GetName() string { - return account.Name -} - -func (account *SDBInstanceAccount) Delete() error { - return account.instance.region.DeleteDBInstanceAccount(account.instance.Id, account.Name) -} - -func (region *SRegion) DeleteDBInstanceAccount(instanceId string, account string) error { - return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, fmt.Sprintf("db_user/%s", account), nil, nil) -} - -func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { - privileges, err := account.instance.region.GetDBInstancePrivvileges(account.instance.Id, account.Name) - if err != nil { - return nil, err - } - iprivileves := []cloudprovider.ICloudDBInstanceAccountPrivilege{} - for i := 0; i < len(privileges); i++ { - privileges[i].account = account - iprivileves = append(iprivileves, &privileges[i]) - } - return iprivileves, nil -} - -func (region *SRegion) GetDBInstanceAccounts(instanceId string) ([]SDBInstanceAccount, error) { - params := map[string]string{ - "instance_id": instanceId, - } - accounts := []SDBInstanceAccount{} - err := doListAllWithPage(region.ecsClient.DBInstance.ListAccounts, params, &accounts) - if err != nil { - return nil, err - } - return accounts, nil -} - -func (region *SRegion) GetDBInstancePrivvileges(instanceId string, username string) ([]SDatabasePrivilege, error) { - params := map[string]string{ - "instance_id": instanceId, - "user-name": username, - } - privileges := []SDatabasePrivilege{} - err := doListAllWithPage(region.ecsClient.DBInstance.ListPrivileges, params, &privileges) - if err != nil { - return nil, err - } - return privileges, nil -} - -func (account *SDBInstanceAccount) RevokePrivilege(database string) error { - return account.instance.region.RevokeDBInstancePrivilege(account.instance.Id, account.Name, database) -} - -func (region *SRegion) RevokeDBInstancePrivilege(instanceId string, account, database string) error { - params := map[string]interface{}{ - "db_name": database, - "users": []map[string]interface{}{ - map[string]interface{}{ - "name": account, - }, - }, - } - return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, "db_privilege", nil, jsonutils.Marshal(params)) -} - -func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { - return account.instance.region.GrantDBInstancePrivilege(account.instance.Id, account.Name, database, privilege) -} - -func (region *SRegion) GrantDBInstancePrivilege(instanceId string, account, database string, privilege string) error { - readonly := false - switch privilege { - case api.DATABASE_PRIVILEGE_R: - readonly = true - case api.DATABASE_PRIVILEGE_RW: - default: - return fmt.Errorf("Unknown privilege %s", privilege) - } - params := map[string]interface{}{ - "db_name": database, - "users": []map[string]interface{}{ - map[string]interface{}{ - "name": account, - "readonly": readonly, - }, - }, - } - _, err := region.ecsClient.DBInstance.PerformAction("db_privilege", instanceId, jsonutils.Marshal(params)) - return err -} - -func (account *SDBInstanceAccount) ResetPassword(password string) error { - return account.instance.region.ResetDBInstanceAccountPassword(account.instance.Id, account.Name, password) -} - -func (region *SRegion) ResetDBInstanceAccountPassword(instanceId, account, password string) error { - return fmt.Errorf("The API does not exist or has not been published in the environment") -} diff --git a/pkg/multicloud/hcso/dbinstance_backup.go b/pkg/multicloud/hcso/dbinstance_backup.go deleted file mode 100644 index 30f9d9e5b9..0000000000 --- a/pkg/multicloud/hcso/dbinstance_backup.go +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceBackup struct { - multicloud.SDBInstanceBackupBase - multicloud.HuaweiTags - region *SRegion - - BeginTime string - Datastore SDatastore - EndTime string - Id string - InstanceId string - Name string - Size int - Status string - Type string -} - -func (backup *SDBInstanceBackup) GetId() string { - return backup.Id -} - -func (backup *SDBInstanceBackup) GetGlobalId() string { - return backup.Id -} - -func (backup *SDBInstanceBackup) GetName() string { - return backup.Name -} - -func (backup *SDBInstanceBackup) GetEngine() string { - return backup.Datastore.Type -} - -func (backup *SDBInstanceBackup) GetEngineVersion() string { - return backup.Datastore.Version -} - -func (backup *SDBInstanceBackup) GetStartTime() time.Time { - //2019-08-05T08:00:02+0000 - t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.BeginTime) - if err != nil { - return time.Time{} - } - return t -} - -func (backup *SDBInstanceBackup) GetEndTime() time.Time { - t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.EndTime) - if err != nil { - return time.Time{} - } - return t -} - -func (backup *SDBInstanceBackup) GetBackupMode() string { - switch backup.Type { - case "manual": - return api.BACKUP_MODE_MANUAL - default: - return api.BACKUP_MODE_AUTOMATED - } -} - -func (backup *SDBInstanceBackup) GetStatus() string { - switch backup.Status { - case "COMPLETED": - return api.DBINSTANCE_BACKUP_READY - case "FAILED": - return api.DBINSTANCE_BACKUP_FAILED - case "BUILDING": - return api.DBINSTANCE_BACKUP_CREATING - case "DELETING": - return api.DBINSTANCE_BACKUP_DELETING - default: - return api.DBINSTANCE_BACKUP_UNKNOWN - } -} - -func (backup *SDBInstanceBackup) GetBackupSizeMb() int { - return backup.Size / 1024 -} - -func (backup *SDBInstanceBackup) GetDBNames() string { - return "" -} - -func (backup *SDBInstanceBackup) Delete() error { - return backup.region.DeleteDBInstanceBackup(backup.Id) -} - -func (region *SRegion) DeleteDBInstanceBackup(backupId string) error { - _, err := region.ecsClient.DBInstanceBackup.Delete(backupId, nil) - return err -} - -func (backup *SDBInstanceBackup) GetDBInstanceId() string { - return backup.InstanceId -} - -func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string) ([]SDBInstanceBackup, error) { - params := map[string]string{ - "instance_id": instanceId, - } - if len(backupId) > 0 { - params["backup_id"] = backupId - } - backups := []SDBInstanceBackup{} - err := doListAllWithOffset(region.ecsClient.DBInstanceBackup.List, params, &backups) - if err != nil { - return nil, err - } - return backups, nil -} - -func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - dbinstnaces, err := region.GetIDBInstances() - if err != nil { - return nil, err - } - ibackups := []cloudprovider.ICloudDBInstanceBackup{} - for i := 0; i < len(dbinstnaces); i++ { - _dbinstance := dbinstnaces[i].(*SDBInstance) - _ibackup, err := _dbinstance.GetIDBInstanceBackups() - if err != nil { - return nil, errors.Wrapf(err, "_dbinstance(%v).GetIDBInstanceBackups", _dbinstance) - } - ibackups = append(ibackups, _ibackup...) - } - return ibackups, nil -} - -func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { - backups, err := region.GetIDBInstanceBackups() - if err != nil { - return nil, errors.Wrap(err, "region.GetIDBInstanceBackups") - } - for _, backup := range backups { - if backup.GetGlobalId() == backupId { - return backup, nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - backups, err := rds.region.GetDBInstanceBackups(rds.Id, "") - if err != nil { - return nil, err - } - - ibackups := []cloudprovider.ICloudDBInstanceBackup{} - for i := 0; i < len(backups); i++ { - backups[i].region = rds.region - ibackups = append(ibackups, &backups[i]) - } - return ibackups, nil -} - -func (backup *SDBInstanceBackup) Refresh() error { - backups, err := backup.region.GetDBInstanceBackups(backup.InstanceId, backup.Id) - if err != nil { - return err - } - if len(backups) == 0 { - return cloudprovider.ErrNotFound - } - return jsonutils.Update(backup, backups[0]) -} - -func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { - backupId, err := rds.region.CreateDBInstanceBackup(rds.Id, conf.Name, conf.Description, conf.Databases) - if err != nil { - return "", err - } - backup, err := rds.region.GetIDBInstanceBackupById(backupId) - if err != nil { - return "", errors.Wrap(err, "region.GetIDBInstanceBackupById") - } - cloudprovider.WaitStatus(backup, api.DBINSTANCE_BACKUP_READY, time.Second*3, time.Minute*30) - return backupId, nil -} - -func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, descrition string, databases []string) (string, error) { - params := map[string]interface{}{ - "instance_id": instanceId, - "name": name, - "description": descrition, - } - if len(databases) > 0 { - dbs := []map[string]string{} - for _, database := range databases { - dbs = append(dbs, map[string]string{"name": database}) - } - params["databases"] = dbs - } - resp, err := region.ecsClient.DBInstanceBackup.Create(jsonutils.Marshal(params)) - if err != nil { - return "", errors.Wrap(err, "DBInstanceBackup.Create") - } - backupId, err := resp.GetString("id") - if err != nil { - return "", errors.Wrap(err, "resp.GetBackupId") - } - return backupId, nil -} - -func (self *SDBInstanceBackup) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - opts.BackupId = self.Id - return self.region.CreateIDBInstance(opts) -} diff --git a/pkg/multicloud/hcso/dbinstance_database.go b/pkg/multicloud/hcso/dbinstance_database.go deleted file mode 100644 index 6cc9d5b7df..0000000000 --- a/pkg/multicloud/hcso/dbinstance_database.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceDatabase struct { - instance *SDBInstance - multicloud.SDBInstanceDatabaseBase - multicloud.HuaweiTags - - Name string - CharacterSet string -} - -func (database *SDBInstanceDatabase) GetId() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetGlobalId() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetName() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetStatus() string { - return api.DBINSTANCE_DATABASE_RUNNING -} - -func (database *SDBInstanceDatabase) GetCharacterSet() string { - return database.CharacterSet -} - -func (database *SDBInstanceDatabase) Delete() error { - return database.instance.region.DeleteDBInstanceDatabase(database.instance.Id, database.Name) -} - -func (region *SRegion) DeleteDBInstanceDatabase(instanceId, database string) error { - _, err := region.ecsClient.DBInstance.DeleteInContextWithSpec(nil, instanceId, fmt.Sprintf("database/%s", database), nil, nil, "") - return err -} - -func (region *SRegion) GetDBInstanceDatabases(instanceId string) ([]SDBInstanceDatabase, error) { - params := map[string]string{ - "instance_id": instanceId, - } - databases := []SDBInstanceDatabase{} - err := doListAllWithPage(region.ecsClient.DBInstance.ListDatabases, params, &databases) - if err != nil { - return nil, err - } - return databases, nil -} diff --git a/pkg/multicloud/hcso/dbinstance_privilege.go b/pkg/multicloud/hcso/dbinstance_privilege.go deleted file mode 100644 index ae8b754c96..0000000000 --- a/pkg/multicloud/hcso/dbinstance_privilege.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" -) - -type SDatabasePrivilege struct { - account *SDBInstanceAccount - - Name string - Readonly bool -} - -func (privilege *SDatabasePrivilege) GetGlobalId() string { - return fmt.Sprintf("%s/%s", privilege.account.Name, privilege.Name) -} - -func (privilege *SDatabasePrivilege) GetPrivilege() string { - if privilege.Readonly { - return api.DATABASE_PRIVILEGE_R - } - return api.DATABASE_PRIVILEGE_RW -} - -func (privilege *SDatabasePrivilege) GetDBName() string { - return privilege.Name -} diff --git a/pkg/multicloud/hcso/dbinstance_skus.go b/pkg/multicloud/hcso/dbinstance_skus.go deleted file mode 100644 index 08181612fb..0000000000 --- a/pkg/multicloud/hcso/dbinstance_skus.go +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SDBInstanceSku struct { - Vcpus int - Ram int //单位GB - SpecCode string - InstanceMode string //实例模型 - - StorageType string - Az1 string - Az2 string - Engine string - EngineVersion string -} - -func (self *SDBInstanceSku) GetName() string { - return self.SpecCode -} - -func (self *SDBInstanceSku) GetGlobalId() string { - return fmt.Sprintf("%s-%s-%s-%s-%s-%s", self.Engine, self.EngineVersion, self.InstanceMode, self.SpecCode, self.StorageType, self.GetZoneId()) -} - -func (self *SDBInstanceSku) GetCategory() string { - return self.InstanceMode -} - -func (self *SDBInstanceSku) GetDiskSizeStep() int { - return 10 -} - -func (self *SDBInstanceSku) GetIOPS() int { - return 0 -} - -func (self *SDBInstanceSku) GetTPS() int { - return 0 -} - -func (self *SDBInstanceSku) GetZone1Id() string { - return self.Az1 -} - -func (self *SDBInstanceSku) GetZone2Id() string { - return self.Az2 -} - -func (self *SDBInstanceSku) GetZone3Id() string { - return "" -} - -func (self *SDBInstanceSku) GetZoneId() string { - zones := []string{} - for _, zone := range []string{self.Az1, self.Az2} { - if len(zone) > 0 { - zones = append(zones, zone) - } - } - return strings.Join(zones, ",") -} - -func (self *SDBInstanceSku) GetMaxConnections() int { - return 0 -} - -func (self *SDBInstanceSku) GetMaxDiskSizeGb() int { - return 4000 -} - -func (self *SDBInstanceSku) GetMinDiskSizeGb() int { - return 40 -} - -func (self *SDBInstanceSku) GetVcpuCount() int { - return self.Vcpus -} - -func (self *SDBInstanceSku) GetVmemSizeMb() int { - return self.Ram * 1024 -} - -func (self *SDBInstanceSku) GetStorageType() string { - return self.StorageType -} - -func (sku *SDBInstanceSku) GetEngine() string { - return sku.Engine -} - -func (sku *SDBInstanceSku) GetEngineVersion() string { - return sku.EngineVersion -} - -func (self *SDBInstanceSku) GetStatus() string { - return api.DBINSTANCE_SKU_AVAILABLE -} - -func (sku *SDBInstanceSku) GetQPS() int { - return 0 -} - -type SDBInstanceFlavor struct { - Vcpus int - Ram int //单位GB - SpecCode string - InstanceMode string //实例模型 - - StorageType string - AzStatus map[string]string - Engine string - EngineVersion string -} - -func (self *SDBInstanceFlavor) GetISkus() []cloudprovider.ICloudDBInstanceSku { - ret := []cloudprovider.ICloudDBInstanceSku{} - switch self.InstanceMode { - case api.HUAWEI_DBINSTANCE_CATEGORY_HA: - for az1, status1 := range self.AzStatus { - if status1 != "normal" { - continue - } - for az2, status2 := range self.AzStatus { - if status2 != "normal" { - continue - } - sku := &SDBInstanceSku{ - Vcpus: self.Vcpus, - Ram: self.Ram, - SpecCode: self.SpecCode, - InstanceMode: self.InstanceMode, - StorageType: self.StorageType, - Az1: az1, - Az2: az2, - Engine: self.Engine, - EngineVersion: self.EngineVersion, - } - ret = append(ret, sku) - } - } - case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE: - for az, status := range self.AzStatus { - if status != "normal" { - continue - } - sku := &SDBInstanceSku{ - Vcpus: self.Vcpus, - Ram: self.Ram, - SpecCode: self.SpecCode, - InstanceMode: self.InstanceMode, - StorageType: self.StorageType, - Az1: az, - Engine: self.Engine, - EngineVersion: self.EngineVersion, - } - ret = append(ret, sku) - } - } - return ret -} - -func (self *SRegion) GetIDBInstanceSkus() ([]cloudprovider.ICloudDBInstanceSku, error) { - skus, err := self.GetDBInstanceSkus() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudDBInstanceSku{} - for i := range skus { - ret = append(ret, skus[i].GetISkus()...) - } - return ret, nil -} - -type SDBInstanceDatastore struct { - Id string - Name string -} - -func (self *SRegion) GetDBInstanceSkus() ([]SDBInstanceFlavor, error) { - skus := []SDBInstanceFlavor{} - for _, engine := range []string{api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL, api.DBINSTANCE_TYPE_SQLSERVER} { - stores, err := self.GetDBInstanceDatastores(engine) - if err != nil { - return nil, err - } - for _, version := range stores { - storages, err := self.GetDBInstanceStorages(engine, version.Name) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceStorages(%s,%s)", engine, version.Name) - } - flavors, err := self.GetDBInstanceFlavors(engine, version.Name) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstanceFlavors(%s, %s)", engine, version.Name) - } - for i := range flavors { - flavors[i].Engine = engine - flavors[i].EngineVersion = version.Name - for j := range storages { - flavors[i].StorageType = storages[j].Name - flavors[i].AzStatus = storages[j].AzStatus - skus = append(skus, flavors[i]) - } - } - } - } - return skus, nil -} - -func (region *SRegion) GetDBInstanceFlavors(engine string, version string) ([]SDBInstanceFlavor, error) { - flavors := []SDBInstanceFlavor{} - resp, err := region.ecsClient.DBInstanceFlavor.ListInContextWithSpec(nil, engine, map[string]string{"version_name": version}, "flavors") - if err != nil { - return nil, err - } - return flavors, jsonutils.Update(&flavors, resp.Data) -} - -func (region *SRegion) GetDBInstanceDatastores(engine string) ([]SDBInstanceDatastore, error) { - stores := []SDBInstanceDatastore{} - resp, err := region.ecsClient.DBInstanceDatastore.ListInContextWithSpec(nil, engine, nil, region.ecsClient.DBInstanceDatastore.KeywordPlural) - if err != nil { - return nil, err - } - return stores, jsonutils.Update(&stores, resp.Data) -} - -type SDBInstanceStorage struct { - Name string - AzStatus map[string]string -} - -func (region *SRegion) GetDBInstanceStorages(engine, engineVersion string) ([]SDBInstanceStorage, error) { - storages := []SDBInstanceStorage{} - resp, err := region.ecsClient.DBInstanceStorage.ListInContextWithSpec(nil, engine, map[string]string{"version_name": engineVersion}, region.ecsClient.DBInstanceStorage.KeywordPlural) - if err != nil { - return nil, err - } - return storages, jsonutils.Update(&storages, resp.Data) -} diff --git a/pkg/multicloud/hcso/disk.go b/pkg/multicloud/hcso/disk.go deleted file mode 100644 index 2eadedc1ab..0000000000 --- a/pkg/multicloud/hcso/disk.go +++ /dev/null @@ -1,533 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -/* -华为云云硬盘 -======创建========== -1.磁盘只能挂载到同一可用区的云服务器内,创建后不支持更换可用区 -2.计费模式 包年包月/按需计费 -3.*支持自动备份 - - -共享盘 和 普通盘:https://support.huaweicloud.com/productdesc-evs/zh-cn_topic_0032860759.html -根据是否支持挂载至多台云服务器可以将云硬盘分为非共享云硬盘和共享云硬盘。 -一个非共享云硬盘只能挂载至一台云服务器,而一个共享云硬盘可以同时挂载至多台云服务器。 -单个共享云硬盘最多可同时挂载给16个云服务器。目前,共享云硬盘只适用于数据盘,不支持系统盘。 -*/ - -type Attachment struct { - ServerID string `json:"server_id"` - AttachmentID string `json:"attachment_id"` - AttachedAt string `json:"attached_at"` - HostName string `json:"host_name"` - VolumeID string `json:"volume_id"` - Device string `json:"device"` - ID string `json:"id"` -} - -type DiskMeta struct { - ResourceSpecCode string `json:"resourceSpecCode"` - Billing string `json:"billing"` - ResourceType string `json:"resourceType"` - AttachedMode string `json:"attached_mode"` - Readonly string `json:"readonly"` -} - -type VolumeImageMetadata struct { - QuickStart string `json:"__quick_start"` - ContainerFormat string `json:"container_format"` - MinRAM string `json:"min_ram"` - ImageName string `json:"image_name"` - ImageID string `json:"image_id"` - OSType string `json:"__os_type"` - OSFeatureList string `json:"__os_feature_list"` - MinDisk string `json:"min_disk"` - SupportKVM string `json:"__support_kvm"` - VirtualEnvType string `json:"virtual_env_type"` - SizeGB string `json:"size"` - OSVersion string `json:"__os_version"` - OSBit string `json:"__os_bit"` - SupportKVMHi1822Hiovs string `json:"__support_kvm_hi1822_hiovs"` - SupportXen string `json:"__support_xen"` - Description string `json:"__description"` - Imagetype string `json:"__imagetype"` - DiskFormat string `json:"disk_format"` - ImageSourceType string `json:"__image_source_type"` - Checksum string `json:"checksum"` - Isregistered string `json:"__isregistered"` - HwVifMultiqueueEnabled string `json:"hw_vif_multiqueue_enabled"` - Platform string `json:"__platform"` -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0124881427.html -type SDisk struct { - storage *SStorage - multicloud.SDisk - multicloud.HuaweiDiskTags - details *SResourceDetail - - ID string `json:"id"` - Name string `json:"name"` - Status string `json:"status"` - Attachments []Attachment `json:"attachments"` - Description string `json:"description"` - SizeGB int `json:"size"` - Metadata DiskMeta `json:"metadata"` - Encrypted bool `json:"encrypted"` - Bootable string `json:"bootable"` - Multiattach bool `json:"multiattach"` - AvailabilityZone string `json:"availability_zone"` - SourceVolid string `json:"source_volid"` - SnapshotID string `json:"snapshot_id"` - CreatedAt time.Time `json:"created_at"` - VolumeType string `json:"volume_type"` - VolumeImageMetadata VolumeImageMetadata `json:"volume_image_metadata"` - ReplicationStatus string `json:"replication_status"` - UserID string `json:"user_id"` - ConsistencygroupID string `json:"consistencygroup_id"` - UpdatedAt string `json:"updated_at"` - EnterpriseProjectId string - - ExpiredTime time.Time -} - -func (self *SDisk) GetId() string { - return self.ID -} - -func (self *SDisk) GetName() string { - if len(self.Name) == 0 { - return self.ID - } - - return self.Name -} - -func (self *SDisk) GetGlobalId() string { - return self.ID -} - -func (self *SDisk) GetStatus() string { - // https://support.huaweicloud.com/api-evs/zh-cn_topic_0051803385.html - switch self.Status { - case "creating", "downloading": - return api.DISK_ALLOCATING - case "available", "in-use": - return api.DISK_READY - case "error": - return api.DISK_ALLOC_FAILED - case "attaching": - return api.DISK_ATTACHING - case "detaching": - return api.DISK_DETACHING - case "restoring-backup": - return api.DISK_REBUILD - case "backing-up": - return api.DISK_BACKUP_STARTALLOC // ? - case "error_restoring": - return api.DISK_BACKUP_ALLOC_FAILED - case "uploading": - return api.DISK_SAVING //? - case "extending": - return api.DISK_RESIZING - case "error_extending": - return api.DISK_ALLOC_FAILED // ? - case "deleting": - return api.DISK_DEALLOC //? - case "error_deleting": - return api.DISK_DEALLOC_FAILED // ? - case "rollbacking": - return api.DISK_REBUILD - case "error_rollbacking": - return api.DISK_UNKNOWN - default: - return api.DISK_UNKNOWN - } -} - -func (self *SDisk) Refresh() error { - new, err := self.storage.zone.region.GetDisk(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SDisk) IsEmulated() bool { - return false -} - -func (self *SDisk) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SDisk) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SDisk) GetExpiredAt() time.Time { - var expiredTime time.Time - return expiredTime -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.storage, nil -} - -func (self *SDisk) GetDiskFormat() string { - // self.volume_type ? - return "vhd" -} - -func (self *SDisk) GetDiskSizeMB() int { - return int(self.SizeGB * 1024) -} - -func (self *SDisk) checkAutoDelete(attachments []Attachment) bool { - autodelete := false - for _, attach := range attachments { - if len(attach.ServerID) > 0 { - // todo : 忽略错误?? - vm, err := self.storage.zone.region.GetInstanceByID(attach.ServerID) - if err != nil { - volumes := vm.OSExtendedVolumesVolumesAttached - for _, vol := range volumes { - if vol.ID == self.ID && strings.ToLower(vol.DeleteOnTermination) == "true" { - autodelete = true - } - } - } - - break - } - } - - return autodelete -} - -func (self *SDisk) GetIsAutoDelete() bool { - if len(self.Attachments) > 0 { - return self.checkAutoDelete(self.Attachments) - } - - return false -} - -func (self *SDisk) GetTemplateId() string { - return self.VolumeImageMetadata.ImageID -} - -// Bootable 表示硬盘是否为启动盘。 -// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) -func (self *SDisk) GetDiskType() string { - if self.Bootable == "true" { - return api.DISK_TYPE_SYS - } else { - return api.DISK_TYPE_DATA - } -} - -func (self *SDisk) GetFsFormat() string { - return "" -} - -func (self *SDisk) GetIsNonPersistent() bool { - return false -} - -func (self *SDisk) GetDriver() string { - // https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762431.html - // scsi or vbd? - // todo: implement me - return "scsi" -} - -func (self *SDisk) GetCacheMode() string { - return "none" -} - -func (self *SDisk) GetMountpoint() string { - if len(self.Attachments) > 0 { - return self.Attachments[0].Device - } - - return "" -} - -func (self *SDisk) GetMountServerId() string { - if len(self.Attachments) > 0 { - return self.Attachments[0].ServerID - } - - return "" -} - -func (self *SDisk) GetAccessPath() string { - return "" -} - -func (self *SDisk) Delete(ctx context.Context) error { - disk, err := self.storage.zone.region.GetDisk(self.GetId()) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return err - } - if disk.Status != "deleting" { - // 等待硬盘ready - cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 60*time.Second) - err := self.storage.zone.region.DeleteDisk(self.GetId()) - if err != nil { - return err - } - } - - return cloudprovider.WaitDeleted(self, 10*time.Second, 120*time.Second) -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - if snapshotId, err := self.storage.zone.region.CreateSnapshot(self.GetId(), 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, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil { - return nil, err - } - return snapshot, nil - } -} - -func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) { - snapshot, err := self.storage.zone.region.GetSnapshotById(snapshotId) - return &snapshot, err -} - -func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := self.getSnapshot(snapshotId) - return snapshot, err -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := self.storage.zone.region.GetSnapshots(self.ID, "") - if err != nil { - return nil, err - } - - isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) - for i := 0; i < len(snapshots); i++ { - isnapshots[i] = &snapshots[i] - } - return isnapshots, nil -} - -func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { - err := cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 60*time.Second) - if err != nil { - return err - } - - sizeGb := newSizeMB / 1024 - err = self.storage.zone.region.resizeDisk(self.GetId(), sizeGb) - if err != nil { - return err - } - - return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 15*time.Second, 5*time.Second, 60*time.Second) -} - -func (self *SDisk) Detach() error { - err := self.storage.zone.region.DetachDisk(self.GetMountServerId(), self.GetId()) - if err != nil { - log.Debugf("detach server %s disk %s failed: %s", self.GetMountServerId(), self.GetId(), err) - return err - } - - return cloudprovider.WaitCreated(5*time.Second, 60*time.Second, func() bool { - err := self.Refresh() - if err != nil { - log.Debugln(err) - return false - } - - if self.Status == "available" { - return true - } - - return false - }) -} - -func (self *SDisk) Attach(device string) error { - err := self.storage.zone.region.AttachDisk(self.GetMountServerId(), self.GetId(), device) - if err != nil { - log.Debugf("attach server %s disk %s failed: %s", self.GetMountServerId(), self.GetId(), err) - return err - } - - return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 10*time.Second, 5*time.Second, 60*time.Second) -} - -// 在线卸载磁盘 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0036046828.html -// 对于挂载在系统盘盘位(也就是“/dev/sda”或“/dev/vda”挂载点)上的磁盘,当前仅支持离线卸载 -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - mountpoint := self.GetMountpoint() - if len(mountpoint) > 0 { - err := self.Detach() - if err != nil { - return "", err - } - } - - diskId, err := self.storage.zone.region.resetDisk(self.GetId(), snapshotId) - if err != nil { - return diskId, err - } - - err = cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 300*time.Second) - if err != nil { - return "", err - } - - if len(mountpoint) > 0 { - err := self.Attach(mountpoint) - if err != nil { - return "", err - } - } - - return diskId, nil -} - -// 华为云不支持重置 -func (self *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { - if len(diskId) == 0 { - return nil, cloudprovider.ErrNotFound - } - var disk SDisk - err := DoGet(self.ecsClient.Disks.Get, diskId, nil, &disk) - return &disk, err -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762430.html -func (self *SRegion) GetDisks(zoneId string) ([]SDisk, error) { - queries := map[string]string{} - if len(zoneId) > 0 { - queries["availability_zone"] = zoneId - } - - disks := make([]SDisk, 0) - err := doListAllWithOffset(self.ecsClient.Disks.List, queries, &disks) - return disks, err -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html -func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, snapshotId string, desc string, projectId string) (string, error) { - params := jsonutils.NewDict() - volumeObj := jsonutils.NewDict() - volumeObj.Add(jsonutils.NewString(name), "name") - volumeObj.Add(jsonutils.NewString(zoneId), "availability_zone") - volumeObj.Add(jsonutils.NewString(desc), "description") - volumeObj.Add(jsonutils.NewString(category), "volume_type") - volumeObj.Add(jsonutils.NewInt(int64(sizeGb)), "size") - if len(snapshotId) > 0 { - volumeObj.Add(jsonutils.NewString(snapshotId), "snapshot_id") - } - if len(projectId) > 0 { - volumeObj.Add(jsonutils.NewString(projectId), "enterprise_project_id") - } - - params.Add(volumeObj, "volume") - // 目前只支持创建按需资源,返回job id。 如果创建包年包月资源则返回order id - _id, err := self.ecsClient.Disks.AsyncCreate(params) - if err != nil { - log.Debugf("AsyncCreate with params: %s", params) - return "", errors.Wrap(err, "AsyncCreate") - } - - // 按需计费 - volumeId, err := self.GetTaskEntityID(self.ecsClient.Disks.ServiceType(), _id, "volume_id") - if err != nil { - return "", errors.Wrap(err, "GetAllSubTaskEntityIDs") - } - - if len(volumeId) == 0 { - return "", errors.Errorf("CreateInstance job %s result is emtpy", _id) - } else { - return volumeId, nil - } -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762428.html -// 默认删除云硬盘关联的所有快照 -func (self *SRegion) DeleteDisk(diskId string) error { - return DoDeleteWithSpec(self.ecsClient.Disks.DeleteInContextWithSpec, nil, diskId, "", nil, nil) -} - -/* -扩容状态为available的云硬盘时,没有约束限制。 -扩容状态为in-use的云硬盘时,有以下约束: -不支持共享云硬盘,即multiattach参数值必须为false。 -云硬盘所挂载的云服务器状态必须为ACTIVE、PAUSED、SUSPENDED、SHUTOFF才支持扩容 -*/ -func (self *SRegion) resizeDisk(diskId string, sizeGB int64) error { - params := jsonutils.NewDict() - osExtendObj := jsonutils.NewDict() - osExtendObj.Add(jsonutils.NewInt(sizeGB), "new_size") // GB - params.Add(osExtendObj, "os-extend") - _, err := self.ecsClient.Disks.PerformAction2("action", diskId, params, "") - return err -} - -/* -https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html -只支持快照回滚到源云硬盘,不支持快照回滚到其它指定云硬盘。 -只有云硬盘状态处于“available”或“error_rollbacking”状态才允许快照回滚到源云硬盘。 -*/ -func (self *SRegion) resetDisk(diskId, snapshotId string) (string, error) { - params := jsonutils.NewDict() - rollbackObj := jsonutils.NewDict() - rollbackObj.Add(jsonutils.NewString(diskId), "volume_id") - params.Add(rollbackObj, "rollback") - _, err := self.ecsClient.OsSnapshots.PerformAction2("rollback", snapshotId, params, "") - return diskId, err -} - -func (self *SDisk) GetProjectId() string { - return self.EnterpriseProjectId -} diff --git a/pkg/multicloud/hcso/doc.go b/pkg/multicloud/hcso/doc.go deleted file mode 100644 index fdc6ab1b71..0000000000 --- a/pkg/multicloud/hcso/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso // import huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" diff --git a/pkg/multicloud/hcso/eip.go b/pkg/multicloud/hcso/eip.go deleted file mode 100644 index b989fed049..0000000000 --- a/pkg/multicloud/hcso/eip.go +++ /dev/null @@ -1,401 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type TInternetChargeType string - -const ( - InternetChargeByTraffic = TInternetChargeType("traffic") - InternetChargeByBandwidth = TInternetChargeType("bandwidth") -) - -type Bandwidth struct { - ID string `json:"id"` - Name string `json:"name"` - Size int64 `json:"size"` - ShareType string `json:"share_type"` - PublicipInfo []PublicipInfo `json:"publicip_info"` - TenantID string `json:"tenant_id"` - BandwidthType string `json:"bandwidth_type"` - ChargeMode string `json:"charge_mode"` - BillingInfo string `json:"billing_info"` - EnterpriseProjectID string `json:"enterprise_project_id"` -} - -type PublicipInfo struct { - PublicipID string `json:"publicip_id"` - PublicipAddress string `json:"publicip_address"` - PublicipType string `json:"publicip_type"` - IPVersion int64 `json:"ip_version"` -} - -type SProfile struct { - UserID string `json:"user_id"` - ProductID string `json:"product_id"` - RegionID string `json:"region_id"` - OrderID string `json:"order_id"` -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html -type SEipAddress struct { - region *SRegion - port *Port - multicloud.SEipBase - multicloud.HuaweiTags - - ID string `json:"id"` - Status string `json:"status"` - Profile *SProfile `json:"profile,omitempty"` - Type string `json:"type"` - PublicIPAddress string `json:"public_ip_address"` - PrivateIPAddress string `json:"private_ip_address"` - TenantID string `json:"tenant_id"` - CreateTime time.Time `json:"create_time"` - BandwidthID string `json:"bandwidth_id"` - BandwidthShareType string `json:"bandwidth_share_type"` - BandwidthSize int64 `json:"bandwidth_size"` - BandwidthName string `json:"bandwidth_name"` - EnterpriseProjectID string `json:"enterprise_project_id"` - IPVersion int64 `json:"ip_version"` - PortId string `json:"port_id"` - EnterpriseProjectId string -} - -func (self *SEipAddress) GetId() string { - return self.ID -} - -func (self *SEipAddress) GetName() string { - if len(self.BandwidthName) == 0 { - return self.BandwidthName - } - - return self.PublicIPAddress -} - -func (self *SEipAddress) GetGlobalId() string { - return self.ID -} - -func (self *SEipAddress) GetStatus() string { - // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html - switch self.Status { - case "ACTIVE", "DOWN", "ELB": - return api.EIP_STATUS_READY - case "PENDING_CREATE", "NOTIFYING": - return api.EIP_STATUS_ALLOCATE - case "BINDING": - return api.EIP_STATUS_ALLOCATE - case "BIND_ERROR": - return api.EIP_STATUS_ALLOCATE_FAIL - case "PENDING_DELETE", "NOTIFY_DELETE": - return api.EIP_STATUS_DEALLOCATE - default: - return api.EIP_STATUS_UNKNOWN - } -} - -func (self *SEipAddress) Refresh() error { - if self.IsEmulated() { - return nil - } - new, err := self.region.GetEip(self.ID) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SEipAddress) IsEmulated() bool { - return false -} - -func (self *SEipAddress) GetIpAddr() string { - return self.PublicIPAddress -} - -func (self *SEipAddress) GetMode() string { - return api.EIP_MODE_STANDALONE_EIP -} - -func (self *SEipAddress) GetPort() *Port { - if len(self.PortId) == 0 { - return nil - } - - if self.port != nil { - return self.port - } - - port, err := self.region.GetPort(self.PortId) - if err != nil { - return nil - } else { - self.port = &port - } - - return self.port -} - -func (self *SEipAddress) GetAssociationType() string { - if len(self.PortId) == 0 { - return "" - } - port, err := self.region.GetPort(self.PortId) - if err != nil { - log.Errorf("Get eip %s port %s error: %v", self.ID, self.PortId, err) - return "" - } - - switch port.DeviceOwner { - case "neutron:LOADBALANCER", "neutron:LOADBALANCERV2": - return api.EIP_ASSOCIATE_TYPE_LOADBALANCER - case "network:nat_gateway": - return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY - default: - return port.DeviceOwner - } -} - -func (self *SEipAddress) GetAssociationExternalId() string { - // network/0273a359d61847fc83405926c958c746/ext-floatingips?tenantId=0273a359d61847fc83405926c958c746&limit=2000 - // 只能通过 port id 反查device id. - if len(self.PortId) > 0 { - port, _ := self.region.GetPort(self.PortId) - return port.DeviceID - } - return "" -} - -func (self *SEipAddress) GetBandwidth() int { - return int(self.BandwidthSize) // Mb -} - -func (self *SEipAddress) GetINetworkId() string { - return "" -} - -func (self *SEipAddress) GetInternetChargeType() string { - // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090603.html - bandwidth, err := self.region.GetEipBandwidth(self.BandwidthID) - if err != nil { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - } - - if bandwidth.ChargeMode != "traffic" { - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH - } else { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - } -} - -func (self *SEipAddress) GetBillingType() string { - if self.Profile == nil { - return billing_api.BILLING_TYPE_POSTPAID - } else { - return billing_api.BILLING_TYPE_PREPAID - } -} - -func (self *SEipAddress) GetCreatedAt() time.Time { - return self.CreateTime -} - -func (self *SEipAddress) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SEipAddress) Delete() error { - return self.region.DeallocateEIP(self.ID) -} - -func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { - portId, err := self.region.GetInstancePortId(conf.InstanceId) - if err != nil { - return err - } - - if len(self.PortId) > 0 { - if self.PortId == portId { - return nil - } - - return fmt.Errorf("eip %s aready associate with port %s", self.GetId(), self.PortId) - } - - err = self.region.AssociateEipWithPortId(self.ID, portId) - if err != nil { - return err - } - - err = cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 10*time.Second, 10*time.Second, 180*time.Second) - return err -} - -func (self *SEipAddress) Dissociate() error { - if len(self.PortId) == 0 { - return nil - } - port, err := self.region.GetPort(self.PortId) - if err != nil { - return errors.Wrapf(err, "GetPort(%s)", self.PortId) - } - - err = self.region.DissociateEip(self.ID, port.DeviceID) - if err != nil { - return errors.Wrapf(err, "DissociateEip") - } - err = cloudprovider.WaitStatus(self, api.EIP_STATUS_READY, 10*time.Second, 180*time.Second) - return err -} - -func (self *SEipAddress) ChangeBandwidth(bw int) error { - return self.region.UpdateEipBandwidth(self.BandwidthID, bw) -} - -func (self *SRegion) GetInstancePortId(instanceId string) (string, error) { - // 目前只绑定一个网卡 - // todo: 还需要按照ports状态进行过滤 - ports, err := self.GetPorts(instanceId) - if err != nil { - return "", err - } - - if len(ports) == 0 { - return "", fmt.Errorf("AssociateEip instance %s port is empty", instanceId) - } - - return ports[0].ID, nil -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html -func (self *SRegion) AllocateEIP(name string, bwMbps int, chargeType TInternetChargeType, bgpType string, projectId string) (*SEipAddress, error) { - paramsStr := ` -{ - "publicip": { - "type": "%s", - "ip_version": 4 - }, - "bandwidth": { - "name": "%s", - "size": %d, - "share_type": "PER", - "charge_mode": "%s" - } -} -` - if len(bgpType) == 0 { - return nil, fmt.Errorf("AllocateEIP bgp type should not be empty") - } - paramsStr = fmt.Sprintf(paramsStr, bgpType, name, bwMbps, chargeType) - _params, _ := jsonutils.ParseString(paramsStr) - params := _params.(*jsonutils.JSONDict) - if len(projectId) > 0 { - params.Set("enterprise_project_id", jsonutils.NewString(projectId)) - } - eip := SEipAddress{} - err := DoCreate(self.ecsClient.Eips.Create, params, &eip) - return &eip, err -} - -func (self *SRegion) GetEip(eipId string) (*SEipAddress, error) { - var eip SEipAddress - err := DoGet(self.ecsClient.Eips.Get, eipId, nil, &eip) - eip.region = self - return &eip, err -} - -func (self *SRegion) DeallocateEIP(eipId string) error { - _, err := self.ecsClient.Eips.Delete(eipId, nil) - return err -} - -func (self *SRegion) AssociateEip(eipId string, instanceId string) error { - portId, err := self.GetInstancePortId(instanceId) - if err != nil { - return err - } - return self.AssociateEipWithPortId(eipId, portId) -} - -func (self *SRegion) AssociateEipWithPortId(eipId string, portId string) error { - params := jsonutils.NewDict() - publicIPObj := jsonutils.NewDict() - publicIPObj.Add(jsonutils.NewString(portId), "port_id") - params.Add(publicIPObj, "publicip") - - _, err := self.ecsClient.Eips.Update(eipId, params) - return err -} - -func (self *SRegion) DissociateEip(eipId string, instanceId string) error { - eip, err := self.GetEip(eipId) - if err != nil { - return err - } - - // 已经是解绑状态 - if eip.Status == "DOWN" { - return nil - } - - remoteInstanceId := eip.GetAssociationExternalId() - if remoteInstanceId != instanceId { - return fmt.Errorf("eip %s associate with another instance %s", eipId, remoteInstanceId) - } - - paramsStr := `{"publicip":{"port_id":null}}` - params, _ := jsonutils.ParseString(paramsStr) - _, err = self.ecsClient.Eips.Update(eipId, params) - return err -} - -func (self *SRegion) UpdateEipBandwidth(bandwidthId string, bw int) error { - paramStr := `{ - "bandwidth": - { - "size": %d - } - }` - - paramStr = fmt.Sprintf(paramStr, bw) - params, _ := jsonutils.ParseString(paramStr) - _, err := self.ecsClient.Bandwidths.Update(bandwidthId, params) - return err -} - -func (self *SRegion) GetEipBandwidth(bandwidthId string) (Bandwidth, error) { - bandwidth := Bandwidth{} - err := DoGet(self.ecsClient.Bandwidths.Get, bandwidthId, nil, &bandwidth) - return bandwidth, err -} - -func (self *SEipAddress) GetProjectId() string { - return self.EnterpriseProjectId -} diff --git a/pkg/multicloud/hcso/elasticcache_account.go b/pkg/multicloud/hcso/elasticcache_account.go deleted file mode 100644 index 404ef9d4e5..0000000000 --- a/pkg/multicloud/hcso/elasticcache_account.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElasticcacheAccount struct { - multicloud.SElasticcacheAccountBase - multicloud.HuaweiTags - - cacheDB *SElasticcache -} - -func (self *SElasticcacheAccount) GetId() string { - return fmt.Sprintf("%s/root", self.cacheDB.InstanceID) -} - -func (self *SElasticcacheAccount) GetName() string { - if len(self.cacheDB.AccessUser) > 0 { - return self.cacheDB.AccessUser - } - - return "root" -} - -func (self *SElasticcacheAccount) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheAccount) GetStatus() string { - return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE -} - -func (self *SElasticcacheAccount) GetAccountType() string { - return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN -} - -func (self *SElasticcacheAccount) GetAccountPrivilege() string { - return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html -// 未找到关闭密码的开放api, 不支持开启/关闭密码访问 -// https://console.huaweicloud.com/dcs/rest/v2/41f6bfe48d7f4455b7754f7c1b11ae34/instances/26db46e2-c7d8-4b5e-bd36-b5278d2fe17c/password/reset -// new_password: "26db46e2!" -// no_password_access: false -func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { - if input.OldPassword == nil { - return fmt.Errorf("elasticcacheAccount.ResetPassword.input OldPassword should not be empty") - } - - type ResetPasswordResult struct { - Result string `json:"result"` - Message string `json:"message"` - } - - result := ResetPasswordResult{} - params := jsonutils.NewDict() - params.Set("old_password", jsonutils.NewString(*input.OldPassword)) - params.Set("new_password", jsonutils.NewString(input.NewPassword)) - err := DoUpdateWithSpec2(self.cacheDB.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.cacheDB.GetId(), "password", params, &result) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.ResetPassword") - } - - if result.Result != "success" { - return errors.Wrap(fmt.Errorf(result.Message), "elasticcacheAccount.ResetPassword") - } - - return nil -} - -func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { - if input.Password != nil { - inputPassword := cloudprovider.SCloudElasticCacheAccountResetPasswordInput{} - inputPassword.NewPassword = *input.Password - inputPassword.OldPassword = input.OldPassword - inputPassword.NoPasswordAccess = input.NoPasswordAccess - return self.ResetPassword(inputPassword) - } - - return nil -} - -func (self *SElasticcacheAccount) Delete() error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/hcso/elasticcache_backup.go b/pkg/multicloud/hcso/elasticcache_backup.go deleted file mode 100644 index 38f483862c..0000000000 --- a/pkg/multicloud/hcso/elasticcache_backup.go +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html -type SElasticcacheBackup struct { - multicloud.SElasticcacheBackupBase - multicloud.HuaweiTags - - cacheDB *SElasticcache - - Status string `json:"status"` - Remark string `json:"remark"` - Period string `json:"period"` - Progress string `json:"progress"` - SizeByte int64 `json:"size"` - InstanceID string `json:"instance_id"` - BackupID string `json:"backup_id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - ExecutionAt time.Time `json:"execution_at"` - BackupType string `json:"backup_type"` - BackupName string `json:"backup_name"` - ErrorCode string `json:"error_code"` - IsSupportRestore string `json:"is_support_restore"` -} - -func (self *SElasticcacheBackup) GetId() string { - return self.BackupID -} - -func (self *SElasticcacheBackup) GetName() string { - return self.BackupName -} - -func (self *SElasticcacheBackup) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheBackup) Refresh() error { - cache, err := self.cacheDB.GetICloudElasticcacheBackup(self.GetId()) - if err != nil { - return errors.Wrap(err, "ElasticcacheBackup.Refresh.GetICloudElasticcacheBackup") - } - - err = jsonutils.Update(self, cache) - if err != nil { - return errors.Wrap(err, "ElasticcacheBackup.Refresh.Update") - } - - return nil -} - -func (self *SElasticcacheBackup) GetStatus() string { - switch self.Status { - case "waiting", "backuping": - return api.ELASTIC_CACHE_BACKUP_STATUS_CREATING - case "succeed": - return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS - case "failed": - return api.ELASTIC_CACHE_BACKUP_STATUS_FAILED - case "expired": - return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_EXPIRED - case "deleted": - return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_DELETED - default: - return self.Status - } -} - -func (self *SElasticcacheBackup) GetBackupSizeMb() int { - return int(self.SizeByte / 1024 / 1024) -} - -func (self *SElasticcacheBackup) GetBackupType() string { - switch self.BackupType { - case "manual": - return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL - case "auto": - return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED - default: - return self.BackupType - } - -} - -func (self *SElasticcacheBackup) GetBackupMode() string { - return "" -} - -func (self *SElasticcacheBackup) GetDownloadURL() string { - return "" -} - -func (self *SElasticcacheBackup) GetStartTime() time.Time { - return self.CreatedAt -} - -func (self *SElasticcacheBackup) GetEndTime() time.Time { - return self.UpdatedAt -} - -func (self *SElasticcacheBackup) Delete() error { - return cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html -func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { - _, err := self.cacheDB.region.ecsClient.Elasticcache.RestoreInstance(instanceId, self.GetId()) - if err != nil { - return nil - } - - return nil -} diff --git a/pkg/multicloud/hcso/elasticcache_instance.go b/pkg/multicloud/hcso/elasticcache_instance.go deleted file mode 100644 index 6db08b78df..0000000000 --- a/pkg/multicloud/hcso/elasticcache_instance.go +++ /dev/null @@ -1,751 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html -type SElasticcache struct { - multicloud.SElasticcacheBase - multicloud.HuaweiTags - - region *SRegion - - Name string `json:"name"` - Engine string `json:"engine"` - CapacityGB int `json:"capacity"` - IP string `json:"ip"` - DomainName string `json:"domainName"` - Port int `json:"port"` - Status string `json:"status"` - Libos bool `json:"libos"` - Description string `json:"description"` - Task string `json:"task"` - MaxMemoryMB int `json:"max_memory"` - UsedMemoryMB int `json:"used_memory"` - InstanceID string `json:"instance_id"` - ResourceSpecCode string `json:"resource_spec_code"` - EngineVersion string `json:"engine_version"` - InternalVersion string `json:"internal_version"` - ChargingMode int `json:"charging_mode"` - CapacityMinor string `json:"capacity_minor"` - VpcID string `json:"vpc_id"` - VpcName string `json:"vpc_name"` - TaskStatus string `json:"task_status"` - CreatedAt string `json:"created_at"` - ErrorCode string `json:"error_code"` - UserID string `json:"user_id"` - UserName string `json:"user_name"` - MaintainBegin string `json:"maintain_begin"` - MaintainEnd string `json:"maintain_end"` - NoPasswordAccess string `json:"no_password_access"` - AccessUser string `json:"access_user"` - EnablePublicip bool `json:"enable_publicip"` - PublicipID string `json:"publicip_id"` - PublicipAddress string `json:"publicip_address"` - EnableSSL bool `json:"enable_ssl"` - ServiceUpgrade bool `json:"service_upgrade"` - ServiceTaskID string `json:"service_task_id"` - IsFree string `json:"is_free"` - EnterpriseProjectID string `json:"enterprise_project_id"` - AvailableZones []string `json:"available_zones"` - SubnetID string `json:"subnet_id"` - SecurityGroupID string `json:"security_group_id"` - BackendAddrs []string `json:"backend_addrs"` - ProductID string `json:"product_id"` - SecurityGroupName string `json:"security_group_name"` - SubnetName string `json:"subnet_name"` - OrderID string `json:"order_id"` - SubnetCIDR string `json:"subnet_cidr"` - InstanceBackupPolicy string `json:"instance_backup_policy"` - EnterpriseProjectName string `json:"enterprise_project_name"` -} - -func (self *SElasticcache) GetId() string { - return self.InstanceID -} - -func (self *SElasticcache) GetName() string { - return self.Name -} - -func (self *SElasticcache) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcache) GetProjectId() string { - return self.EnterpriseProjectID -} - -func (self *SElasticcache) Refresh() error { - cache, err := self.region.GetElasticCache(self.GetId()) - if err != nil { - return errors.Wrap(err, "Elasticcache.Refresh.GetElasticCache") - } - - err = jsonutils.Update(self, cache) - if err != nil { - return errors.Wrap(err, "Elasticcache.Refresh.Update") - } - - return nil -} - -func (self *SElasticcache) GetStatus() string { - switch self.Status { - case "RUNNING": - return api.ELASTIC_CACHE_STATUS_RUNNING - case "CREATING": - return api.ELASTIC_CACHE_STATUS_DEPLOYING - case "CREATEFAILED": - return api.ELASTIC_CACHE_STATUS_CREATE_FAILED - case "ERROR": - return api.ELASTIC_CACHE_STATUS_ERROR - case "RESTARTING": - return api.ELASTIC_CACHE_STATUS_RESTARTING - case "FROZEN": - return api.ELASTIC_CACHE_STATUS_UNAVAILABLE - case "EXTENDING": - return api.ELASTIC_CACHE_STATUS_CHANGING - case "RESTORING": - return api.ELASTIC_CACHE_STATUS_TRANSFORMING // ? - case "FLUSHING": - return api.ELASTIC_CACHE_STATUS_FLUSHING - } - - return "" -} - -func (self *SElasticcache) GetBillingType() string { - // charging_mode “0”:按需计费 “1”:按包年包月计费 - if self.ChargingMode == 1 { - return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SElasticcache) GetCreatedAt() time.Time { - var createtime time.Time - if len(self.CreatedAt) > 0 { - createtime, _ = time.Parse("2006-01-02T15:04:05.000Z", self.CreatedAt) - } - - return createtime -} - -func (self *SElasticcache) GetExpiredAt() time.Time { - var expiredTime time.Time - return expiredTime -} - -func (self *SElasticcache) GetInstanceType() string { - // todo: ?? - return self.ResourceSpecCode -} - -func (self *SElasticcache) GetCapacityMB() int { - return self.CapacityGB * 1024 -} - -func (self *SElasticcache) GetArchType() string { - /* - 资源规格标识。 - - dcs.single_node:表示实例类型为单机 - dcs.master_standby:表示实例类型为主备 - dcs.cluster:表示实例类型为集群 - */ - if strings.Contains(self.ResourceSpecCode, "single") { - return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE - } else if strings.Contains(self.ResourceSpecCode, "ha") { - return api.ELASTIC_CACHE_ARCH_TYPE_MASTER - } else if strings.Contains(self.ResourceSpecCode, "cluster") { - return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER - } else if strings.Contains(self.ResourceSpecCode, "proxy") { - return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER - } - - return "" -} - -func (self *SElasticcache) GetNodeType() string { - // single(单副本) | double(双副本) - if strings.Contains(self.ResourceSpecCode, "single") { - return "single" - } else { - return "double" - } -} - -func (self *SElasticcache) GetEngine() string { - return self.Engine -} - -func (self *SElasticcache) GetEngineVersion() string { - return self.EngineVersion -} - -func (self *SElasticcache) GetVpcId() string { - return self.VpcID -} - -func (self *SElasticcache) GetZoneId() string { - if len(self.AvailableZones) > 0 { - zone, err := self.region.getZoneById(self.AvailableZones[0]) - if err != nil { - log.Errorf("elasticcache.GetZoneId %s", err) - return "" - } - - return zone.GetGlobalId() - } - - return "" -} - -func (self *SElasticcache) GetNetworkType() string { - return api.LB_NETWORK_TYPE_VPC -} - -func (self *SElasticcache) GetNetworkId() string { - return self.SubnetID -} - -func (self *SElasticcache) GetPrivateDNS() string { - return self.DomainName -} - -func (self *SElasticcache) GetPrivateIpAddr() string { - return self.IP -} - -func (self *SElasticcache) GetPrivateConnectPort() int { - return self.Port -} - -func (self *SElasticcache) GetPublicDNS() string { - return self.PublicipAddress -} - -func (self *SElasticcache) GetPublicIpAddr() string { - return self.PublicipAddress -} - -func (self *SElasticcache) GetPublicConnectPort() int { - return self.Port -} - -func (self *SElasticcache) GetMaintainStartTime() string { - return self.MaintainBegin -} - -func (self *SElasticcache) GetMaintainEndTime() string { - return self.MaintainEnd -} - -func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { - iaccounts := []cloudprovider.ICloudElasticcacheAccount{} - iaccount := &SElasticcacheAccount{cacheDB: self} - iaccounts = append(iaccounts, iaccount) - return iaccounts, nil -} - -func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { - // 华为云使用安全组做访问控制。目前未支持 - return []cloudprovider.ICloudElasticcacheAcl{}, nil -} - -func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { - start := self.GetCreatedAt().Format("20060102150405") - end := time.Now().Format("20060102150405") - backups, err := self.region.GetElasticCacheBackups(self.GetId(), start, end) - if err != nil { - return nil, err - } - - ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) - for i := range backups { - backups[i].cacheDB = self - ibackups[i] = &backups[i] - } - - return ibackups, nil -} - -func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { - parameters, err := self.region.GetElasticCacheParameters(self.GetId()) - if err != nil { - return nil, err - } - - iparameters := make([]cloudprovider.ICloudElasticcacheParameter, len(parameters)) - for i := range parameters { - parameters[i].cacheDB = self - iparameters[i] = ¶meters[i] - } - - return iparameters, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html -func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) { - params := make(map[string]string) - params["instance_id"] = instanceId - params["beginTime"] = startTime - params["endTime"] = endTime - - backups := make([]SElasticcacheBackup, 0) - err := doListAll(self.ecsClient.Elasticcache.ListBackups, params, &backups) - if err != nil { - return nil, err - } - - return backups, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html -func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { - params := make(map[string]string) - params["instance_id"] = instanceId - - parameters := make([]SElasticcacheParameter, 0) - err := doListAll(self.ecsClient.Elasticcache.ListParameters, params, ¶meters) - if err != nil { - return nil, err - } - - return parameters, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423044.html -func (self *SRegion) GetElasticCaches() ([]SElasticcache, error) { - params := make(map[string]string) - caches := make([]SElasticcache, 0) - err := doListAll(self.ecsClient.Elasticcache.List, params, &caches) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCaches") - } - - for i := range caches { - cache, err := self.GetElasticCache(caches[i].GetId()) - if err != nil { - return nil, err - } else { - caches[i] = *cache - } - - caches[i].region = self - } - - return caches, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html -func (self *SRegion) GetElasticCache(instanceId string) (*SElasticcache, error) { - cache := SElasticcache{} - err := DoGet(self.ecsClient.Elasticcache.Get, instanceId, nil, &cache) - if err != nil { - return nil, errors.Wrapf(err, "region.GetElasticCache %s", instanceId) - } - - cache.region = self - return &cache, nil -} - -func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { - ec, err := self.GetElasticCache(id) - if err != nil { - return nil, errors.Wrap(err, "region.GetIElasticCacheById.GetElasticCache") - } - - return ec, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423047.html -func (self *SRegion) zoneNameToDcsZoneIds(zoneIds []string) ([]string, error) { - type Z struct { - ID string `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - Port string `json:"port"` - ResourceAvailability string `json:"resource_availability"` - } - - rs := []Z{} - err := doListAll(self.ecsClient.DcsAvailableZone.List, nil, &rs) - if err != nil { - return nil, errors.Wrap(err, "region.zoneNameToDcsZoneIds") - } - - zoneMap := map[string]string{} - for i := range rs { - if rs[i].ResourceAvailability == "true" { - zoneMap[rs[i].Code] = rs[i].ID - } - } - - ret := []string{} - for _, zone := range zoneIds { - if id, ok := zoneMap[zone]; ok { - ret = append(ret, id) - } else { - return nil, errors.Wrap(fmt.Errorf("zone %s not found or not available", zone), "region.zoneNameToDcsZoneIds") - } - } - - return ret, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423019.html -func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { - params := jsonutils.NewDict() - params.Set("name", jsonutils.NewString(ec.InstanceName)) - params.Set("engine", jsonutils.NewString(ec.Engine)) - params.Set("engine_version", jsonutils.NewString(ec.EngineVersion)) - params.Set("capacity", jsonutils.NewInt(ec.CapacityGB)) - params.Set("vpc_id", jsonutils.NewString(ec.VpcId)) - if len(ec.SecurityGroupIds) > 0 { - params.Set("security_group_id", jsonutils.NewString(ec.SecurityGroupIds[0])) - } - params.Set("subnet_id", jsonutils.NewString(ec.NetworkId)) - params.Set("product_id", jsonutils.NewString(ec.InstanceType)) - zones, err := self.zoneNameToDcsZoneIds(ec.ZoneIds) - if err != nil { - return nil, err - } - params.Set("available_zones", jsonutils.NewStringArray(zones)) - - if len(ec.ProjectId) > 0 { - params.Set("enterprise_project_id", jsonutils.NewString(ec.ProjectId)) - } - - if len(ec.Password) > 0 { - params.Set("no_password_access", jsonutils.NewString("false")) - params.Set("password", jsonutils.NewString(ec.Password)) - - // todo: 这里换成常量 - if ec.Engine == "Memcache" { - params.Set("access_user", jsonutils.NewString(ec.UserName)) - } - } else { - params.Set("no_password_access", jsonutils.NewString("true")) - } - - if len(ec.EipId) > 0 { - params.Set("enable_publicip", jsonutils.NewString("true")) - params.Set("publicip_id", jsonutils.NewString(ec.EipId)) - // enable_ssl - } else { - params.Set("enable_publicip", jsonutils.NewString("false")) - } - - if len(ec.PrivateIpAddress) > 0 { - params.Set("private_ip", jsonutils.NewString(ec.PrivateIpAddress)) - } - - if len(ec.MaintainBegin) > 0 { - params.Set("maintain_begin", jsonutils.NewString(ec.MaintainBegin)) - params.Set("maintain_end", jsonutils.NewString(ec.MaintainEnd)) - } - - if strings.ToLower(ec.ChargeType) == billing_api.BILLING_TYPE_PREPAID && ec.BillingCycle != nil { - bssParam := jsonutils.NewDict() - bssParam.Set("charging_mode", jsonutils.NewString("prePaid")) - bssParam.Set("is_auto_pay", jsonutils.NewString("true")) - bssParam.Set("is_auto_renew", jsonutils.NewString(fmt.Sprintf("%v", ec.BillingCycle.AutoRenew))) - if ec.BillingCycle.GetMonths() >= 1 && ec.BillingCycle.GetMonths() >= 9 { - bssParam.Set("period_type", jsonutils.NewString("month")) - bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetMonths()))) - } else if ec.BillingCycle.GetYears() >= 1 && ec.BillingCycle.GetYears() <= 3 { - bssParam.Set("period_type", jsonutils.NewString("year")) - bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetYears()))) - } else { - return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") - } - - params.Set("bss_param", bssParam) - } - - ret := &SElasticcache{} - err = DoCreate(self.ecsClient.Elasticcache.Create, params, ret) - if err != nil { - return nil, errors.Wrap(err, "region.CreateIElasticcaches") - } - - ret.region = self - return ret, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html -func (self *SElasticcache) Restart() error { - resp, err := self.region.ecsClient.Elasticcache.Restart(self.GetId()) - if err != nil { - return errors.Wrap(err, "elasticcache.Restart") - } - - rets, err := resp.GetArray("results") - if err != nil { - return errors.Wrap(err, "elasticcache.results") - } - - for _, r := range rets { - if ret, _ := r.GetString("result"); ret != "success" { - return fmt.Errorf("elasticcache.Restart failed") - } - } - - return nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423022.html -func (self *SElasticcache) Delete() error { - err := DoDelete(self.region.ecsClient.Elasticcache.Delete, self.GetId(), nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.Delete") - } - - return nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html -func (self *SElasticcache) ChangeInstanceSpec(spec string) error { - segs := strings.Split(spec, ":") - if len(segs) < 2 { - return fmt.Errorf("elasticcache.ChangeInstanceSpec invalid sku %s", spec) - } - - if !strings.HasPrefix(segs[1], "m") || !strings.HasSuffix(segs[1], "g") { - return fmt.Errorf("elasticcache.ChangeInstanceSpec sku %s memeory size is invalid.", spec) - } - - newCapacity := segs[1][1 : len(segs[1])-1] - capacity, err := strconv.Atoi(newCapacity) - if err != nil { - return errors.Wrap(fmt.Errorf("invalid sku capacity %s", spec), "Elasticcache.ChangeInstanceSpec") - } - - _, err = self.region.ecsClient.Elasticcache.ChangeInstanceSpec(self.GetId(), segs[0], int64(capacity)) - if err != nil { - return errors.Wrap(err, "elasticcache.ChangeInstanceSpec") - } - - return nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html -func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { - params := jsonutils.NewDict() - params.Set("maintain_begin", jsonutils.NewString(maintainStartTime)) - params.Set("maintain_end", jsonutils.NewString(maintainEndTime)) - err := DoUpdate(self.region.ecsClient.Elasticcache.Update, self.GetId(), params, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.SetMaintainTime") - } - - return nil -} - -// https://support.huaweicloud.com/usermanual-dcs/dcs-zh-ug-180314001.html -// 目前只有Redis3.0版本密码模式的实例支持通过公网访问Redis实例,其他版本暂不支持公网访问。 -// todo: 目前没找到api -func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -// todo: 目前没找到api -func (self *SElasticcache) ReleasePublicConnection() error { - return cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { - return nil, cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html - -func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423029.html -func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { - params := jsonutils.NewDict() - params.Set("redis_config", config) - err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) - if err != nil { - return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") - } - - return nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423033.html -func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func backupPeriodTrans(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) *jsonutils.JSONArray { - segs := strings.Split(config.PreferredBackupPeriod, ",") - ret := jsonutils.NewArray() - for _, seg := range segs { - switch seg { - case "Monday": - ret.Add(jsonutils.NewString("1")) - case "Tuesday": - ret.Add(jsonutils.NewString("2")) - case "Wednesday": - ret.Add(jsonutils.NewString("3")) - case "Thursday": - ret.Add(jsonutils.NewString("4")) - case "Friday": - ret.Add(jsonutils.NewString("5")) - case "Saturday": - ret.Add(jsonutils.NewString("6")) - case "Sunday": - ret.Add(jsonutils.NewString("7")) - } - } - - return ret -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html -func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { - params := jsonutils.NewDict() - policy := jsonutils.NewDict() - policy.Set("save_days", jsonutils.NewInt(int64(config.BackupReservedDays))) - policy.Set("backup_type", jsonutils.NewString(config.BackupType)) - plan := jsonutils.NewDict() - backTime := strings.ReplaceAll(config.PreferredBackupTime, "Z", "") - backupPeriod := backupPeriodTrans(config) - plan.Set("begin_at", jsonutils.NewString(backTime)) - plan.Set("period_type", jsonutils.NewString("weekly")) - plan.Set("backup_at", backupPeriod) - policy.Set("periodical_backup_plan", plan) - params.Set("instance_backup_policy", policy) - err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) - if err != nil { - return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") - } - - return nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html -// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 -func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { - resp, err := self.region.ecsClient.Elasticcache.Flush(self.GetId()) - if err != nil { - return errors.Wrap(err, "elasticcache.FlushInstance") - } - - rets, err := resp.GetArray("results") - if err != nil { - return errors.Wrap(err, "elasticcache.FlushInstance") - } - - for _, r := range rets { - if ret, _ := r.GetString("result"); ret != "success" { - return fmt.Errorf("elasticcache.FlushInstance failed") - } - } - - return nil -} - -// SElasticcacheAccount => ResetPassword -func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool, password string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetAuthMode() string { - switch self.NoPasswordAccess { - case "true": - return "off" - default: - return "on" - } -} - -func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { - accounts, err := self.GetICloudElasticcacheAccounts() - if err != nil { - return nil, errors.Wrap(err, "Elasticcache.GetICloudElasticcacheAccount.Accounts") - } - - for i := range accounts { - account := accounts[i] - if account.GetGlobalId() == accountId { - return account, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { - backups, err := self.GetICloudElasticcacheBackups() - if err != nil { - return nil, err - } - - for _, backup := range backups { - if backup.GetId() == backupId { - return backup, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (instance *SElasticcache) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { - return errors.Wrap(cloudprovider.ErrNotSupported, "UpdateSecurityGroups") -} - -func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) SetAutoRenew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/hcso/elasticcache_parameter.go b/pkg/multicloud/hcso/elasticcache_parameter.go deleted file mode 100644 index 99d974ce97..0000000000 --- a/pkg/multicloud/hcso/elasticcache_parameter.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html -type SElasticcacheParameter struct { - multicloud.SElasticcacheParameterBase - multicloud.HuaweiTags - - cacheDB *SElasticcache - - Description string `json:"description"` - ParamID int64 `json:"param_id"` - ParamName string `json:"param_name"` - ParamValue string `json:"param_value"` - DefaultValue string `json:"default_value"` - ValueType string `json:"value_type"` - ValueRange string `json:"value_range"` -} - -func (self *SElasticcacheParameter) GetId() string { - return fmt.Sprintf("%d", self.ParamID) -} - -func (self *SElasticcacheParameter) GetName() string { - return self.ParamName -} - -func (self *SElasticcacheParameter) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.cacheDB.InstanceID, self.GetId()) -} - -func (self *SElasticcacheParameter) GetStatus() string { - return api.ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE -} - -func (self *SElasticcacheParameter) GetParameterKey() string { - return self.ParamName -} - -func (self *SElasticcacheParameter) GetParameterValue() string { - return self.ParamValue -} - -func (self *SElasticcacheParameter) GetParameterValueRange() string { - return self.Description -} - -func (self *SElasticcacheParameter) GetDescription() string { - return self.ValueRange -} - -func (self *SElasticcacheParameter) GetModifiable() bool { - return true -} - -func (self *SElasticcacheParameter) GetForceRestart() bool { - return false -} diff --git a/pkg/multicloud/hcso/enterpriceprojects.go b/pkg/multicloud/hcso/enterpriceprojects.go deleted file mode 100644 index ddbce0c503..0000000000 --- a/pkg/multicloud/hcso/enterpriceprojects.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://support.huaweicloud.com/api-em/zh-cn_topic_0121230880.html -type SEnterpriseProject struct { - multicloud.SProjectBase - multicloud.HuaweiTags - - Id string - Name string - Description string - Status int - CreatedAt time.Time - UpdatedAt time.Time -} - -func (self *SHuaweiClient) GetEnterpriseProjects() ([]SEnterpriseProject, error) { - projects := []SEnterpriseProject{} - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - err = doListAllWithOffset(client.EnterpriseProjects.List, map[string]string{}, &projects) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return projects, nil -} - -func (ep *SEnterpriseProject) GetId() string { - return ep.Id -} - -func (ep *SEnterpriseProject) GetGlobalId() string { - return ep.Id -} - -func (ep *SEnterpriseProject) GetStatus() string { - if ep.Status == 1 { - return api.EXTERNAL_PROJECT_STATUS_AVAILABLE - } - return api.EXTERNAL_PROJECT_STATUS_UNAVAILABLE -} - -func (ep *SEnterpriseProject) GetName() string { - return ep.Name -} - -func (self *SHuaweiClient) CreateExterpriseProject(name, desc string) (*SEnterpriseProject, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - params := map[string]string{ - "name": name, - } - if len(desc) > 0 { - params["description"] = desc - } - resp, err := client.EnterpriseProjects.Create(jsonutils.Marshal(params)) - if err != nil { - if strings.Contains(err.Error(), "EPS.0004") { - return nil, cloudprovider.ErrNotSupported - } - return nil, errors.Wrap(err, "EnterpriseProjects.Create") - } - project := &SEnterpriseProject{} - err = resp.Unmarshal(&project) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return project, nil -} - -func (self *SHuaweiClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return self.CreateExterpriseProject(name, "") -} - -func (self *SHuaweiClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { - projects, err := self.GetEnterpriseProjects() - if err != nil { - return nil, errors.Wrap(err, "GetProjects") - } - ret := []cloudprovider.ICloudProject{} - for i := range projects { - ret = append(ret, &projects[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/hcso/host.go b/pkg/multicloud/hcso/host.go deleted file mode 100644 index ef6ad4da22..0000000000 --- a/pkg/multicloud/hcso/host.go +++ /dev/null @@ -1,349 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone - vms []SInstance - - // 华为私有云没有直接列出host的接口,所有账号下的host都是通过VM反向解析出来的 - // 当账号下没有虚拟机时,如果没有host,会导致调度找不到可用的HOST。 - // 因此,为了避免上述情况始终会在每个zone下返回一台虚拟的host - IsFake bool - projectId string - Id string - Name string -} - -func (self *SHost) GetId() string { - return self.Id -} - -func (self *SHost) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - - return self.Id -} - -func (self *SHost) GetGlobalId() string { - return self.Id -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) Refresh() error { - _, err := self.getVMs() - return errors.Wrap(err, "getVMs") -} - -func (self *SHost) IsEmulated() bool { - return self.IsFake -} - -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - var vms []SInstance - var err error - if self.vms != nil { - vms = self.vms - } else { - vms, err = self.getVMs() - if err != nil { - return nil, err - } - } - - ret := make([]cloudprovider.ICloudVM, len(vms)) - for i := range vms { - vm := vms[i] - vm.host = self - ret[i] = &vm - } - - return ret, nil -} - -func (self *SHost) getVMs() ([]SInstance, error) { - vms, err := self.zone.region.GetInstances() - if err != nil { - return nil, errors.Wrap(err, "GetInstances") - } - - ret := []SInstance{} - for i := range vms { - vm := vms[i] - if vm.OSEXTAZAvailabilityZone == self.GetId() && vm.HostID == self.GetId() { - vm.host = self - ret = append(ret, vm) - } - } - - self.vms = ret - return ret, nil -} - -func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.zone.region.GetInstanceByID(id) - if vm.HostID != self.GetId() { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetInstanceByID") - } - - vm.host = self - return &vm, err -} - -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 api.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_HUAWEI), "manufacture") - info.Add(jsonutils.NewString(self.GetId()), "id") - info.Add(jsonutils.NewString(self.GetName()), "name") - return info -} - -func (self *SHost) GetSN() string { - return "" -} - -func (self *SHost) GetCpuCount() int { - 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 api.DISK_TYPE_HYBRID -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_HCSO -} - -func (self *SHost) GetIsMaintenance() bool { - return false -} - -func (self *SHost) GetVersion() string { - return HUAWEI_API_VERSION -} - -func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) { - instance, err := self.zone.region.GetInstanceByID(instanceId) - if err != nil { - return nil, err - } - - if instance.HostID != self.GetId() { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetInstanceByID") - } - - instance.host = self - return &instance, nil -} - -func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - vmId, err := self._createVM( - desc.Name, desc.ExternalImageId, desc.SysDisk, - desc.Cpu, desc.MemoryMB, desc.InstanceType, - desc.ExternalNetworkId, desc.IpAddr, - desc.Description, desc.Account, - desc.Password, desc.DataDisks, - desc.PublicKey, desc.ExternalSecgroupId, - desc.UserData, desc.BillingCycle, desc.ProjectId, desc.Tags) - if err != nil { - return nil, err - } - - // VM实际调度到的host, 可能不是当前host.因此需要改写host信息 - vm, err := self.zone.region.GetIVMById(vmId) - if err != nil { - return nil, err - } - - return vm, err -} - -func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, - networkId string, ipAddr string, desc string, account string, passwd string, - diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string, - userData string, bc *billing.SBillingCycle, projectId string, tags map[string]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") - } - - // 同步keypair - var err error - keypair := "" - if len(publicKey) > 0 { - 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 %s fail %s", imgId, err) - return "", err - } - if img.Status != ImageStatusActive { - log.Errorf("image %s status %s", imgId, img.Status) - return "", fmt.Errorf("image not ready") - } - // passwd, windows机型直接使用密码比较方便 - if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(passwd) > 0 { - keypair = "" - } - - if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) { - if u, err := updateWindowsUserData(userData, img.OSVersion, account, passwd); err == nil { - userData = u - } else { - return "", errors.Wrap(err, "SHost.CreateVM.updateWindowsUserData") - } - } - - disks := make([]SDisk, len(diskSizes)+1) - disks[0].SizeGB = img.SizeGB - if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.SizeGB { - disks[0].SizeGB = sysDisk.SizeGB - } - disks[0].VolumeType = sysDisk.StorageType - - for i, dataDisk := range diskSizes { - disks[i+1].SizeGB = dataDisk.SizeGB - disks[i+1].VolumeType = dataDisk.StorageType - } - - _, err = self.zone.region.GetSecurityGroupDetails(secgroupId) - if err != nil { - return "", errors.Wrap(err, "SHost.CreateVM.GetSecurityGroupDetails") - } - - // 创建实例 - if len(instanceType) > 0 { - log.Debugf("Try instancetype : %s", instanceType) - vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) - if err != nil { - log.Errorf("Failed for %s: %s", instanceType, err) - return "", fmt.Errorf("create %s failed:%s", instanceType, ErrMessage(err)) - } else { - return vmId, nil - } - } - - // 匹配实例类型 - instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, self.zone.GetId()) - if err != nil { - return "", err - } - if len(instanceTypes) == 0 { - return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB) - } - - var vmId string - for _, instType := range instanceTypes { - instanceTypeId := instType.Name - log.Debugf("Try instancetype : %s", instanceTypeId) - vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) - if err != nil { - log.Errorf("Failed for %s: %s", instanceTypeId, err) - } else { - return vmId, nil - } - } - - return "", fmt.Errorf("create failed: %s", ErrMessage(err)) -} diff --git a/pkg/multicloud/hcso/huawei.go b/pkg/multicloud/hcso/huawei.go deleted file mode 100644 index 0ed13d4450..0000000000 --- a/pkg/multicloud/hcso/huawei.go +++ /dev/null @@ -1,554 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "net/http" - "strings" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/timeutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth/credentials" - "yunion.io/x/onecloud/pkg/multicloud/huawei/obs" -) - -/* -待解决问题: -2.VM密码登录不成功(ubuntu不行,centos可以) -3.实例绑定eip 查不出来eip? -*/ - -const ( - CLOUD_PROVIDER_HUAWEI = api.CLOUD_PROVIDER_HCSO - CLOUD_PROVIDER_HUAWEI_CN = "华为云Stack" - CLOUD_PROVIDER_HUAWEI_EN = "HCSO" - - HUAWEI_API_VERSION = "" -) - -var HUAWEI_REGION_CACHES = map[string]userRegionsCache{} - -type userRegionsCache struct { - UserId string - ExpireAt time.Time - Regions []SRegion -} - -type HuaweiClientConfig struct { - cpcfg cloudprovider.ProviderConfig - endpoints *cloudprovider.SHCSOEndpoints - - projectId string // 华为云项目ID. - accessKey string - accessSecret string - - debug bool -} - -func NewHuaweiClientConfig(accessKey, accessSecret, projectId string, endpoints *cloudprovider.SHCSOEndpoints) *HuaweiClientConfig { - cfg := &HuaweiClientConfig{ - projectId: projectId, - accessKey: accessKey, - accessSecret: accessSecret, - endpoints: endpoints, - } - - return cfg -} - -func (cfg *HuaweiClientConfig) CloudproviderConfig(cpcfg cloudprovider.ProviderConfig) *HuaweiClientConfig { - cfg.cpcfg = cpcfg - return cfg -} - -func (cfg *HuaweiClientConfig) Debug(debug bool) *HuaweiClientConfig { - cfg.debug = debug - return cfg -} - -type SHuaweiClient struct { - *HuaweiClientConfig - - signer auth.Signer - - isMainProject bool // whether the project is the main project in the region - - ownerId string - ownerName string - ownerCreateTime time.Time - - iregions []cloudprovider.ICloudRegion - iBuckets []cloudprovider.ICloudBucket - - projects []SProject - regions []SRegion - - httpClient *http.Client -} - -// 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成,通过"/"分割。 -// 初次导入Subaccount时,参数account对应cloudaccounts表中的account字段,即accesskey。此时projectID为空, -// 只能进行同步子账号、查询region列表等projectId无关的操作。 -func NewHuaweiClient(cfg *HuaweiClientConfig) (*SHuaweiClient, error) { - client := SHuaweiClient{ - HuaweiClientConfig: cfg, - } - - err := client.init() - if err != nil { - return nil, err - } - return &client, nil -} - -func (self *SHuaweiClient) init() error { - err := self.fetchRegions() - if err != nil { - return err - } - err = self.initSigner() - if err != nil { - return errors.Wrap(err, "initSigner") - } - err = self.initOwner() - if err != nil { - return errors.Wrap(err, "fetchOwner") - } - if self.debug { - log.Debugf("OwnerId: %s name: %s", self.ownerId, self.ownerName) - } - return nil -} - -func (self *SHuaweiClient) initSigner() error { - var err error - cred := credentials.NewAccessKeyCredential(self.accessKey, self.accessKey) - self.signer, err = auth.NewSignerWithCredential(cred) - if err != nil { - return err - } - return nil -} - -func (self *SHuaweiClient) newRegionAPIClient(regionId string) (*client.Client, error) { - cli, err := client.NewClientWithAccessKey(regionId, self.ownerId, self.projectId, self.accessKey, self.accessSecret, self.debug, self.cpcfg.DefaultRegion, self.endpoints) - if err != nil { - return nil, err - } - - httpClient := self.cpcfg.AdaptiveTimeoutHttpClient() - ts, _ := httpClient.Transport.(*http.Transport) - httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { - if self.cpcfg.ReadOnly { - if req.Method == "GET" { - return nil, nil - } - return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) - } - return nil, nil - }) - cli.SetHttpClient(httpClient) - - return cli, nil -} - -func (self *SHuaweiClient) newGeneralAPIClient() (*client.Client, error) { - cli, err := client.NewClientWithAccessKey(self.cpcfg.DefaultRegion, self.ownerId, "", self.accessKey, self.accessSecret, self.debug, self.cpcfg.DefaultRegion, self.endpoints) - if err != nil { - return nil, err - } - - httpClient := self.cpcfg.AdaptiveTimeoutHttpClient() - ts, _ := httpClient.Transport.(*http.Transport) - httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { - if self.cpcfg.ReadOnly { - if req.Method == "GET" { - return nil, nil - } - return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) - } - return nil, nil - }) - cli.SetHttpClient(httpClient) - - return cli, nil -} - -func (self *SHuaweiClient) fetchRegions() error { - huawei, _ := self.newGeneralAPIClient() - if self.regions == nil { - userId, err := self.GetUserId() - if err != nil { - return errors.Wrap(err, "GetUserId") - } - - if regionsCache, ok := HUAWEI_REGION_CACHES[userId]; !ok || regionsCache.ExpireAt.Sub(time.Now()).Seconds() > 0 { - regions := make([]SRegion, 0) - err := doListAll(huawei.Regions.List, nil, ®ions) - if err != nil { - return errors.Wrap(err, "Regions.List") - } - - HUAWEI_REGION_CACHES[userId] = userRegionsCache{ExpireAt: time.Now().Add(24 * time.Hour), UserId: userId, Regions: regions} - } - - self.regions = HUAWEI_REGION_CACHES[userId].Regions - } - - filtedRegions := make([]SRegion, 0) - if len(self.projectId) > 0 { - project, err := self.GetProjectById(self.projectId) - if err != nil { - return err - } - - regionId := strings.Split(project.Name, "_")[0] - for _, region := range self.regions { - if region.ID == regionId { - filtedRegions = append(filtedRegions, region) - } - } - if regionId == project.Name { - self.isMainProject = true - } - } else { - filtedRegions = self.regions - } - - self.iregions = make([]cloudprovider.ICloudRegion, len(filtedRegions)) - for i := 0; i < len(filtedRegions); i += 1 { - filtedRegions[i].client = self - _, err := filtedRegions[i].getECSClient() - if err != nil { - return err - } - self.iregions[i] = &filtedRegions[i] - } - return nil -} - -func (self *SHuaweiClient) invalidateIBuckets() { - self.iBuckets = nil -} - -func (self *SHuaweiClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) { - if self.iBuckets == nil { - err := self.fetchBuckets() - if err != nil { - return nil, errors.Wrap(err, "fetchBuckets") - } - } - return self.iBuckets, nil -} - -func getOBSEndpoint(regionId string) string { - return fmt.Sprintf("obs.%s.myhuaweicloud.com", regionId) -} - -func (client *SHuaweiClient) getOBSClient(regionId string) (*obs.ObsClient, error) { - endpoint := client.endpoints.GetEndpoint(client.cpcfg.DefaultRegion, "obs", regionId) - return obs.New(client.accessKey, client.accessSecret, endpoint) -} - -func (self *SHuaweiClient) fetchBuckets() error { - obscli, err := self.getOBSClient(self.cpcfg.DefaultRegion) - if err != nil { - return errors.Wrap(err, "getOBSClient") - } - input := &obs.ListBucketsInput{QueryLocation: true} - output, err := obscli.ListBuckets(input) - if err != nil { - return errors.Wrap(err, "obscli.ListBuckets") - } - self.ownerId = output.Owner.ID - - ret := make([]cloudprovider.ICloudBucket, 0) - for i := range output.Buckets { - bInfo := output.Buckets[i] - region, err := self.getIRegionByRegionId(bInfo.Location) - if err != nil { - log.Errorf("fail to find region %s", bInfo.Location) - continue - } - b := SBucket{ - region: region.(*SRegion), - - Name: bInfo.Name, - Location: bInfo.Location, - CreationDate: bInfo.CreationDate, - } - ret = append(ret, &b) - } - self.iBuckets = ret - return nil -} - -func (self *SHuaweiClient) GetCloudRegionExternalIdPrefix() string { - if len(self.projectId) > 0 { - return self.iregions[0].GetGlobalId() - } else { - return CLOUD_PROVIDER_HUAWEI - } -} - -func (self *SHuaweiClient) UpdateAccount(accessKey, secret string) error { - if self.accessKey != accessKey || self.accessSecret != secret { - self.accessKey = accessKey - self.accessSecret = secret - return self.fetchRegions() - } else { - return nil - } -} - -func (self *SHuaweiClient) 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 *SHuaweiClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - projects, err := self.fetchProjects() - if err != nil { - return nil, err - } - - // https://support.huaweicloud.com/api-iam/zh-cn_topic_0074171149.html - subAccounts := make([]cloudprovider.SSubAccount, 0) - for i := range projects { - project := projects[i] - // name 为MOS的project是华为云内部的一个特殊project。不需要同步到本地 - if strings.ToLower(project.Name) == "mos" { - continue - } - - s := cloudprovider.SSubAccount{ - Name: fmt.Sprintf("%s-%s", self.cpcfg.Name, project.Name), - Account: fmt.Sprintf("%s/%s", self.accessKey, project.ID), - HealthStatus: project.GetHealthStatus(), - } - - subAccounts = append(subAccounts, s) - } - - return subAccounts, nil -} - -func (client *SHuaweiClient) GetAccountId() string { - return client.ownerId -} - -func (client *SHuaweiClient) GetIamLoginUrl() string { - return fmt.Sprintf("https://auth.huaweicloud.com/authui/login.html?account=%s#/login", client.ownerName) -} - -func (self *SHuaweiClient) GetIRegions() []cloudprovider.ICloudRegion { - return self.iregions -} - -func (self *SHuaweiClient) getIRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) { - for i := 0; i < len(self.iregions); i += 1 { - log.Debugf("%d ID: %s", i, self.iregions[i].GetId()) - if self.iregions[i].GetId() == id { - return self.iregions[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHuaweiClient) 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 *SHuaweiClient) GetRegion(regionId string) *SRegion { - if len(regionId) == 0 { - regionId = self.cpcfg.DefaultRegion - } - - for i := 0; i < len(self.iregions); i += 1 { - if self.iregions[i].GetId() == regionId { - return self.iregions[i].(*SRegion) - } - } - return nil -} - -func (self *SHuaweiClient) 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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHuaweiClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - for i := 0; i < len(self.iregions); i += 1 { - ivpc, err := self.iregions[i].GetIVpcById(id) - if err == nil { - return ivpc, nil - } else if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHuaweiClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - for i := 0; i < len(self.iregions); i += 1 { - istorage, err := self.iregions[i].GetIStorageById(id) - if err == nil { - return istorage, nil - } else if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -// 总账户余额 -type SAccountBalance struct { - AvailableAmount float64 - CreditAmount float64 - DesignatedAmount float64 -} - -// 账户余额 -// https://support.huaweicloud.com/api-oce/zh-cn_topic_0109685133.html -type SBalance struct { - Amount float64 `json:"amount"` - Currency string `json:"currency"` - AccountID string `json:"account_id"` - AccountType int64 `json:"account_type"` - DesignatedAmount float64 `json:"designated_amount,omitempty"` - CreditAmount float64 `json:"credit_amount,omitempty"` - MeasureUnit int64 `json:"measure_unit"` -} - -func (self *SHuaweiClient) GetVersion() string { - return HUAWEI_API_VERSION -} - -func (self *SHuaweiClient) GetAccessEnv() string { - return "" -} - -func (self *SHuaweiClient) GetCapabilities() []string { - caps := []string{ - cloudprovider.CLOUD_CAPABILITY_PROJECT, - cloudprovider.CLOUD_CAPABILITY_COMPUTE, - cloudprovider.CLOUD_CAPABILITY_NETWORK, - cloudprovider.CLOUD_CAPABILITY_EIP, - cloudprovider.CLOUD_CAPABILITY_LOADBALANCER, - // cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE, - cloudprovider.CLOUD_CAPABILITY_QUOTA + cloudprovider.READ_ONLY_SUFFIX, - cloudprovider.CLOUD_CAPABILITY_RDS, - cloudprovider.CLOUD_CAPABILITY_CACHE, - cloudprovider.CLOUD_CAPABILITY_EVENT, - cloudprovider.CLOUD_CAPABILITY_CLOUDID, - cloudprovider.CLOUD_CAPABILITY_SAML_AUTH, - cloudprovider.CLOUD_CAPABILITY_NAT, - cloudprovider.CLOUD_CAPABILITY_NAS, - cloudprovider.CLOUD_CAPABILITY_MODELARTES, - } - // huawei objectstore is shared across projects(subscriptions) - // to avoid multiple project access the same bucket - // only main project is allow to access objectstore bucket - if self.isMainProject { - caps = append(caps, cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE) - } - return caps -} - -func (self *SHuaweiClient) GetUserId() (string, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetUserId.newGeneralAPIClient") - } - - type cred struct { - UserId string `json:"user_id"` - } - - ret := &cred{} - err = DoGet(client.Credentials.Get, self.accessKey, nil, ret) - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetUserId.DoGet") - } - - return ret.UserId, nil -} - -// owner id == domain_id == account id -func (self *SHuaweiClient) GetOwnerId() (string, error) { - userId, err := self.GetUserId() - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.GetUserId") - } - - client, err := self.newGeneralAPIClient() - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.newGeneralAPIClient") - } - - type user struct { - DomainId string `json:"domain_id"` - Name string `json:"name"` - CreateTime string - } - - ret := &user{} - err = DoGet(client.Users.Get, userId, nil, ret) - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.DoGet") - } - self.ownerName = ret.Name - // 2021-02-02 02:43:28.0 - self.ownerCreateTime, _ = timeutils.ParseTimeStr(strings.TrimSuffix(ret.CreateTime, ".0")) - return ret.DomainId, nil -} - -func (self *SHuaweiClient) GetSamlEntityId() string { - return fmt.Sprintf("auth.%s", self.endpoints.EndpointDomain) -} - -func (self *SHuaweiClient) initOwner() error { - ownerId, err := self.GetOwnerId() - if err != nil { - return errors.Wrap(err, "SHuaweiClient.initOwner") - } - - self.ownerId = ownerId - return nil -} diff --git a/pkg/multicloud/hcso/image.go b/pkg/multicloud/hcso/image.go deleted file mode 100644 index ec42616874..0000000000 --- a/pkg/multicloud/hcso/image.go +++ /dev/null @@ -1,469 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type TImageOwnerType string - -const ( - ImageOwnerPublic TImageOwnerType = "gold" // 公共镜像:gold - ImageOwnerSelf TImageOwnerType = "private" // 私有镜像:private - ImageOwnerShared TImageOwnerType = "shared" // 共享镜像:shared - - EnvFusionCompute = "FusionCompute" - EnvIronic = "Ironic" -) - -const ( - ImageStatusQueued = "queued" // queued:表示镜像元数据已经创建成功,等待上传镜像文件。 - ImageStatusSaving = "saving" // saving:表示镜像正在上传文件到后端存储。 - ImageStatusDeleted = "deleted" // deleted:表示镜像已经删除。 - ImageStatusKilled = "killed" // killed:表示镜像上传错误。 - ImageStatusActive = "active" // active:表示镜像可以正常使用 -) - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091565.html -type SImage struct { - multicloud.SImageBase - multicloud.HuaweiTags - storageCache *SStoragecache - - // normalized image info - imgInfo *imagetools.ImageInfo - - Schema string `json:"schema"` - MinDiskGB int64 `json:"min_disk"` - CreatedAt time.Time `json:"created_at"` - ImageSourceType string `json:"__image_source_type"` - ContainerFormat string `json:"container_format"` - File string `json:"file"` - UpdatedAt time.Time `json:"updated_at"` - Protected bool `json:"protected"` - Checksum string `json:"checksum"` - ID string `json:"id"` - Isregistered string `json:"__isregistered"` - MinRamMB int `json:"min_ram"` - Lazyloading string `json:"__lazyloading"` - Owner string `json:"owner"` - OSType string `json:"__os_type"` - Imagetype string `json:"__imagetype"` - Visibility string `json:"visibility"` - VirtualEnvType string `json:"virtual_env_type"` - Platform string `json:"__platform"` - SizeGB int `json:"size"` - ImageSize int64 `json:"__image_size"` - OSBit string `json:"__os_bit"` - OSVersion string `json:"__os_version"` - Name string `json:"name"` - Self string `json:"self"` - DiskFormat string `json:"disk_format"` - Status string `json:"status"` - SupportKVMFPGAType string `json:"__support_kvm_fpga_type"` - SupportKVMNVMEHIGHIO string `json:"__support_nvme_highio"` - SupportLargeMemory string `json:"__support_largememory"` - SupportDiskIntensive string `json:"__support_diskintensive"` - SupportHighPerformance string `json:"__support_highperformance"` - SupportXENGPUType string `json:"__support_xen_gpu_type"` - SupportKVMGPUType string `json:"__support_kvm_gpu_type"` - SupportGPUT4 string `json:"__support_gpu_t4"` - SupportKVMAscend310 string `json:"__support_kvm_ascend_310"` - SupportArm string `json:"__support_arm"` -} - -func (self *SImage) GetMinRamSizeMb() int { - return self.MinRamMB -} - -func (self *SImage) GetId() string { - return self.ID -} - -func (self *SImage) GetName() string { - return self.Name -} - -func (self *SImage) GetGlobalId() string { - return self.ID -} - -func (self *SImage) GetStatus() string { - switch self.Status { - case ImageStatusQueued: - return api.CACHED_IMAGE_STATUS_CACHING - case ImageStatusActive: - return api.CACHED_IMAGE_STATUS_ACTIVE - case ImageStatusKilled: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - default: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (self *SImage) GetImageStatus() string { - switch self.Status { - case ImageStatusQueued: - return cloudprovider.IMAGE_STATUS_QUEUED - case ImageStatusActive: - return cloudprovider.IMAGE_STATUS_ACTIVE - case ImageStatusKilled: - return cloudprovider.IMAGE_STATUS_KILLED - default: - return cloudprovider.IMAGE_STATUS_KILLED - } -} - -func (self *SImage) Refresh() error { - new, err := self.storageCache.region.GetImage(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - switch self.Imagetype { - case "gold": - return cloudprovider.ImageTypeSystem - case "private": - return cloudprovider.ImageTypeCustomized - case "shared": - return cloudprovider.ImageTypeShared - default: - return cloudprovider.ImageTypeCustomized - } -} - -func (self *SImage) GetSizeByte() int64 { - return int64(self.MinDiskGB) * 1024 * 1024 * 1024 -} - -func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if self.imgInfo == nil { - arch := "x86" - if strings.ToLower(self.SupportArm) == "true" { - arch = "arm" - } - imgInfo := imagetools.NormalizeImageInfo(self.ImageSourceType, arch, self.OSType, self.Platform, "") - self.imgInfo = &imgInfo - } - - return self.imgInfo -} - -func (self *SImage) GetFullOsName() string { - return self.ImageSourceType -} - -func (self *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) -} - -func (self *SImage) GetOsDist() string { - return self.getNormalizedImageInfo().OsDistro -} - -func (self *SImage) GetOsVersion() string { - return self.getNormalizedImageInfo().OsVersion -} - -func (self *SImage) GetOsLang() string { - return self.getNormalizedImageInfo().OsLang -} - -func (self *SImage) GetOsArch() string { - return self.getNormalizedImageInfo().OsArch -} - -func (i *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(i.getNormalizedImageInfo().OsBios) -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return int(self.MinDiskGB) -} - -func (self *SImage) GetImageFormat() string { - return self.DiskFormat -} - -func (self *SImage) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SImage) IsEmulated() bool { - return false -} - -func (self *SImage) Delete(ctx context.Context) error { - return self.storageCache.region.DeleteImage(self.GetId()) -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.storageCache -} - -func (self *SRegion) GetImage(imageId string) (*SImage, error) { - image := &SImage{} - err := DoGet(self.ecsClient.Images.Get, imageId, nil, image) - if err != nil { - return nil, errors.Wrap(err, "DoGet") - } - return image, nil -} - -func excludeImage(image SImage) bool { - if image.VirtualEnvType == "Ironic" { - return true - } - - if len(image.SupportDiskIntensive) > 0 { - return true - } - - if len(image.SupportKVMFPGAType) > 0 || len(image.SupportKVMAscend310) > 0 { - return true - } - - if len(image.SupportKVMGPUType) > 0 { - return true - } - - if len(image.SupportKVMNVMEHIGHIO) > 0 { - return true - } - - if len(image.SupportGPUT4) > 0 { - return true - } - - if len(image.SupportXENGPUType) > 0 { - return true - } - - if len(image.SupportHighPerformance) > 0 { - return true - } - - return false -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0060804959.html -func (self *SRegion) GetImages(status string, imagetype TImageOwnerType, name string, envType string) ([]SImage, error) { - queries := map[string]string{} - if len(status) > 0 { - queries["status"] = status - } - - if len(imagetype) > 0 { - queries["__imagetype"] = string(imagetype) - if imagetype == ImageOwnerPublic { - queries["protected"] = "True" - } - } - if len(envType) > 0 { - queries["virtual_env_type"] = envType - } - - if len(name) > 0 { - queries["name"] = name - } - - images := make([]SImage, 0) - err := doListAllWithMarker(self.ecsClient.Images.List, queries, &images) - - // 排除掉需要特定镜像才能创建的实例类型 - // https://support.huaweicloud.com/eu-west-0-api-ims/zh-cn_topic_0031617666.html#ZH-CN_TOPIC_0031617666__table48545918250 - // https://support.huaweicloud.com/productdesc-ecs/zh-cn_topic_0088142947.html - filtedImages := make([]SImage, 0) - for i := range images { - if !excludeImage(images[i]) { - filtedImages = append(filtedImages, images[i]) - } - } - - return filtedImages, err -} - -func (self *SRegion) DeleteImage(imageId string) error { - return DoDelete(self.ecsClient.OpenStackImages.Delete, imageId, nil, nil) -} - -func (self *SRegion) GetImageByName(name string) (*SImage, error) { - if len(name) == 0 { - return nil, fmt.Errorf("image name should not be empty") - } - - images, err := self.GetImages("", TImageOwnerType(""), name, "") - if err != nil { - return nil, err - } - if len(images) == 0 { - return nil, cloudprovider.ErrNotFound - } - - log.Debugf("%d image found match name %s", len(images), name) - return &images[0], nil -} - -/* https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html - os version 取值范围: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html - 用于创建私有镜像的源云服务器系统盘大小大于等于40GB且不超过1024GB。 - 目前支持vhd,zvhd、raw,qcow2 - todo: 考虑使用镜像快速导入。 https://support.huaweicloud.com/api-ims/zh-cn_topic_0133188204.html - 使用OBS文件创建镜像 - - * openstack原生接口支持的格式:https://support.huaweicloud.com/api-ims/zh-cn_topic_0031615566.html -*/ -func (self *SRegion) ImportImageJob(name string, osDist string, osVersion string, osArch string, bucket string, key string, minDiskGB int64) (string, error) { - os_version, err := stdVersion(osDist, osVersion, osArch) - log.Debugf("%s %s %s: %s.min_disk %d GB", osDist, osVersion, osArch, os_version, minDiskGB) - if err != nil { - log.Debugln(err) - } - - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(name), "name") - image_url := fmt.Sprintf("%s:%s", bucket, key) - params.Add(jsonutils.NewString(image_url), "image_url") - if len(os_version) > 0 { - params.Add(jsonutils.NewString(os_version), "os_version") - } - params.Add(jsonutils.NewBool(true), "is_config_init") - params.Add(jsonutils.NewBool(true), "is_config") - params.Add(jsonutils.NewInt(minDiskGB), "min_disk") - - ret, err := self.ecsClient.Images.PerformAction2("action", "", params, "") - if err != nil { - return "", err - } - - return ret.GetString("job_id") -} - -func formatVersion(osDist string, osVersion string) (string, error) { - err := fmt.Errorf("unsupport version %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osVersion) - dist := strings.ToLower(osDist) - if dist == "ubuntu" || dist == "redhat" || dist == "centos" || dist == "oracle" || dist == "euleros" { - parts := strings.Split(osVersion, ".") - if len(parts) < 2 { - return "", err - } - - return parts[0] + "." + parts[1], nil - } - - if dist == "debian" { - parts := strings.Split(osVersion, ".") - if len(parts) < 3 { - return "", err - } - - return parts[0] + "." + parts[1] + "." + parts[2], nil - } - - if dist == "fedora" || dist == "windows" || dist == "suse" { - parts := strings.Split(osVersion, ".") - if len(parts) < 1 { - return "", err - } - - return parts[0], nil - } - - if dist == "opensuse" { - parts := strings.Split(osVersion, ".") - if len(parts) == 0 { - return "", err - } - - if len(parts) == 1 { - return parts[0], nil - } - - if len(parts) >= 2 { - return parts[0] + "." + parts[1], nil - } - } - - return "", err -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html -func stdVersion(osDist string, osVersion string, osArch string) (string, error) { - // 架构 - arch := "" - switch osArch { - case "64", apis.OS_ARCH_X86_64, apis.OS_ARCH_AARCH64, apis.OS_ARCH_ARM: - arch = "64bit" - case "32", apis.OS_ARCH_X86_32, apis.OS_ARCH_AARCH32: - arch = "32bit" - default: - return "", fmt.Errorf("unsupported arch %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osArch) - } - - _dist := strings.Split(strings.TrimSpace(osDist), " ")[0] - _dist = strings.ToLower(_dist) - // 版本 - ver, err := formatVersion(_dist, osVersion) - if err != nil { - return "", err - } - - // 操作系统 - dist := "" - - switch _dist { - case "ubuntu": - return fmt.Sprintf("Ubuntu %s server %s", ver, arch), nil - case "redhat": - dist = "Redhat Linux Enterprise" - case "centos": - dist = "CentOS" - case "fedora": - dist = "Fedora" - case "debian": - dist = "Debian GNU/Linux" - case "windows": - dist = "Windows Server" - case "oracle": - dist = "Oracle Linux Server release" - case "suse": - dist = "SUSE Linux Enterprise Server" - case "opensuse": - dist = "OpenSUSE" - case "euleros": - dist = "EulerOS" - default: - return "", fmt.Errorf("unsupported os %s. reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", dist) - } - - return fmt.Sprintf("%s %s %s", dist, ver, arch), nil -} diff --git a/pkg/multicloud/hcso/instance.go b/pkg/multicloud/hcso/instance.go deleted file mode 100644 index e6cb87d89d..0000000000 --- a/pkg/multicloud/hcso/instance.go +++ /dev/null @@ -1,1466 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - "encoding/base64" - "fmt" - "sort" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/apis" - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/modules" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/cloudinit" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -const ( - InstanceStatusRunning = "ACTIVE" - InstanceStatusTerminated = "DELETED" - InstanceStatusStopped = "SHUTOFF" -) - -type IpAddress struct { - Version string `json:"version"` - Addr string `json:"addr"` - OSEXTIPSMACMACAddr string `json:"OS-EXT-IPS-MAC:mac_addr"` - OSEXTIPSPortID string `json:"OS-EXT-IPS:port_id"` - OSEXTIPSType string `json:"OS-EXT-IPS:type"` -} - -type Flavor struct { - Disk string `json:"disk"` - Vcpus string `json:"vcpus"` - RAM string `json:"ram"` - ID string `json:"id"` - Name string `json:"name"` -} - -type Image struct { - ID string `json:"id"` -} - -type VMMetadata struct { - MeteringImageID string `json:"metering.image_id"` - MeteringImagetype string `json:"metering.imagetype"` - MeteringResourcespeccode string `json:"metering.resourcespeccode"` - ImageName string `json:"image_name"` - OSBit string `json:"os_bit"` - VpcID string `json:"vpc_id"` - MeteringResourcetype string `json:"metering.resourcetype"` - CascadedInstanceExtrainfo string `json:"cascaded.instance_extrainfo"` - OSType string `json:"os_type"` - ChargingMode string `json:"charging_mode"` -} - -type OSExtendedVolumesVolumesAttached struct { - Device string `json:"device"` - BootIndex string `json:"bootIndex"` - ID string `json:"id"` - DeleteOnTermination string `json:"delete_on_termination"` -} - -type OSSchedulerHints struct { -} - -type SecurityGroup struct { - Name string `json:"name"` -} - -type SysTag struct { - Key string `json:"key"` - Value string `json:"value"` -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html -// https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0100166287.html v1.1 支持创建包年/包月的弹性云服务器 -type SInstance struct { - multicloud.SInstanceBase - multicloud.HuaweiTags - - host *SHost - - osInfo *imagetools.ImageInfo - - ID string `json:"id"` - Name string `json:"name"` - Addresses map[string][]IpAddress `json:"addresses"` - Flavor Flavor `json:"flavor"` - AccessIPv4 string `json:"accessIPv4"` - AccessIPv6 string `json:"accessIPv6"` - Status string `json:"status"` - Progress string `json:"progress"` - HostID string `json:"hostId"` - Updated string `json:"updated"` - Created time.Time `json:"created"` - Metadata VMMetadata `json:"metadata"` - Description string `json:"description"` - Locked bool `json:"locked"` - ConfigDrive string `json:"config_drive"` - TenantID string `json:"tenant_id"` - UserID string `json:"user_id"` - KeyName string `json:"key_name"` - - OSExtendedVolumesVolumesAttached []OSExtendedVolumesVolumesAttached `json:"os-extended-volumes:volumes_attached"` - OSEXTSTSTaskState string `json:"OS-EXT-STS:task_state"` - OSEXTSTSPowerState int64 `json:"OS-EXT-STS:power_state"` - OSEXTSTSVMState string `json:"OS-EXT-STS:vm_state"` - OSEXTSRVATTRHost string `json:"OS-EXT-SRV-ATTR:host"` - OSEXTSRVATTRInstanceName string `json:"OS-EXT-SRV-ATTR:instance_name"` - OSEXTSRVATTRHypervisorHostname string `json:"OS-EXT-SRV-ATTR:hypervisor_hostname"` - OSDCFDiskConfig string `json:"OS-DCF:diskConfig"` - OSEXTAZAvailabilityZone string `json:"OS-EXT-AZ:availability_zone"` - OSSchedulerHints OSSchedulerHints `json:"os:scheduler_hints"` - OSEXTSRVATTRRootDeviceName string `json:"OS-EXT-SRV-ATTR:root_device_name"` - OSEXTSRVATTRRamdiskID string `json:"OS-EXT-SRV-ATTR:ramdisk_id"` - EnterpriseProjectID string `json:"enterprise_project_id"` - OSEXTSRVATTRUserData string `json:"OS-EXT-SRV-ATTR:user_data"` - OSSRVUSGLaunchedAt time.Time `json:"OS-SRV-USG:launched_at"` - OSEXTSRVATTRKernelID string `json:"OS-EXT-SRV-ATTR:kernel_id"` - OSEXTSRVATTRLaunchIndex int64 `json:"OS-EXT-SRV-ATTR:launch_index"` - HostStatus string `json:"host_status"` - OSEXTSRVATTRReservationID string `json:"OS-EXT-SRV-ATTR:reservation_id"` - OSEXTSRVATTRHostname string `json:"OS-EXT-SRV-ATTR:hostname"` - OSSRVUSGTerminatedAt time.Time `json:"OS-SRV-USG:terminated_at"` - SysTags []SysTag `json:"sys_tags"` - SecurityGroups []SecurityGroup `json:"security_groups"` - EnterpriseProjectId string -} - -func compareSet(currentSet []string, newSet []string) (add []string, remove []string, keep []string) { - sort.Strings(currentSet) - sort.Strings(newSet) - - i, j := 0, 0 - for i < len(currentSet) || j < len(newSet) { - if i < len(currentSet) && j < len(newSet) { - if currentSet[i] == newSet[j] { - keep = append(keep, currentSet[i]) - i += 1 - j += 1 - } else if currentSet[i] < newSet[j] { - remove = append(remove, currentSet[i]) - i += 1 - } else { - add = append(add, newSet[j]) - j += 1 - } - } else if i >= len(currentSet) { - add = append(add, newSet[j]) - j += 1 - } else if j >= len(newSet) { - remove = append(remove, currentSet[i]) - i += 1 - } - } - - return add, remove, keep -} - -// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) -func isBootDisk(server *SInstance, disk *SDisk) bool { - if disk.GetDiskType() != api.DISK_TYPE_SYS { - return false - } - - for _, attachment := range disk.Attachments { - if attachment.ServerID == server.GetId() && attachment.Device == server.OSEXTSRVATTRRootDeviceName { - return true - } - } - - return false -} - -func (self *SInstance) GetId() string { - return self.ID -} - -func (self *SInstance) GetName() string { - return self.Name -} - -func (self *SInstance) GetHostname() string { - return self.OSEXTSRVATTRHostname -} - -func (self *SInstance) GetGlobalId() string { - return self.ID -} - -func (self *SInstance) GetStatus() string { - switch self.Status { - case "ACTIVE": - return api.VM_RUNNING - case "MIGRATING", "REBUILD", "BUILD", "RESIZE", "VERIFY_RESIZE": // todo: pending ? - return api.VM_STARTING - case "REBOOT", "HARD_REBOOT": - return api.VM_STOPPING - case "SHUTOFF": - return api.VM_READY - default: - return api.VM_UNKNOWN - } -} - -func (self *SInstance) Refresh() error { - new, err := self.host.zone.region.GetInstanceByID(self.GetId()) - new.host = self.host - if err != nil { - return err - } - - if new.Status == InstanceStatusTerminated { - log.Debugf("Instance already terminated.") - return cloudprovider.ErrNotFound - } - - err = jsonutils.Update(self, new) - if err != nil { - return err - } - return nil -} - -func (self *SInstance) IsEmulated() bool { - return false -} - -func (self *SInstance) GetInstanceType() string { - return self.Flavor.ID -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - return self.host.zone.region.GetInstanceSecrityGroupIds(self.GetId()) -} - -// https://support.huaweicloud.com/api-ecs/ecs_02_1002.html -// key 相同时value不会替换 -func (self *SRegion) CreateServerTags(instanceId string, tags map[string]string) error { - params := map[string]interface{}{ - "action": "create", - } - - tagsObj := []map[string]string{} - for k, v := range tags { - tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) - } - params["tags"] = tagsObj - - _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") - return err -} - -// https://support.huaweicloud.com/api-ecs/ecs_02_1003.html -func (self *SRegion) DeleteServerTags(instanceId string, tagsKey []string) error { - params := map[string]interface{}{ - "action": "delete", - } - tagsObj := []map[string]string{} - for _, k := range tagsKey { - tagsObj = append(tagsObj, map[string]string{"key": k}) - } - params["tags"] = tagsObj - - _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") - return err -} - -func (self *SInstance) SetTags(tags map[string]string, replace bool) error { - existedTags, err := self.GetTags() - if err != nil { - return errors.Wrap(err, "self.GetTags()") - } - deleteTagsKey := []string{} - for k := range existedTags { - if replace { - deleteTagsKey = append(deleteTagsKey, k) - } else { - if _, ok := tags[k]; ok { - deleteTagsKey = append(deleteTagsKey, k) - } - } - } - if len(deleteTagsKey) > 0 { - err := self.host.zone.region.DeleteServerTags(self.GetId(), deleteTagsKey) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.DeleteServerTags(%s,%s)", self.GetId(), deleteTagsKey) - } - } - if len(tags) > 0 { - err := self.host.zone.region.CreateServerTags(self.GetId(), tags) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.CreateServerTags(%s,%s)", self.GetId(), jsonutils.Marshal(tags).String()) - } - } - return nil -} - -func (self *SInstance) GetBillingType() string { - // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html - // charging_mode “0”:按需计费 “1”:按包年包月计费 - if self.Metadata.ChargingMode == "1" { - return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SInstance) GetCreatedAt() time.Time { - return self.Created -} - -// charging_mode “0”:按需计费 “1”:按包年包月计费 -func (self *SInstance) GetExpiredAt() time.Time { - var expiredTime time.Time - return expiredTime -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetIHostId() string { - return self.host.GetGlobalId() -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - err := self.Refresh() - if err != nil { - return nil, err - } - - attached := self.OSExtendedVolumesVolumesAttached - disks := make([]SDisk, 0) - for _, vol := range attached { - disk, err := self.host.zone.region.GetDisk(vol.ID) - if err != nil { - return nil, err - } - - disks = append(disks, *disk) - } - - idisks := make([]cloudprovider.ICloudDisk, len(disks)) - for i := 0; i < len(disks); i += 1 { - storage, err := self.host.zone.getStorageByCategory(disks[i].VolumeType) - if err != nil { - return nil, err - } - disks[i].storage = storage - idisks[i] = &disks[i] - // 将系统盘放到第0个位置 - if isBootDisk(self, &disks[i]) { - _temp := idisks[0] - idisks[0] = &disks[i] - idisks[i] = _temp - } - } - return idisks, nil -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nics := make([]cloudprovider.ICloudNic, 0) - - // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html - // OS-EXT-IPS.type - // todo: 这里没有区分是IPv4 还是 IPv6。统一当IPv4处理了.可能会引发错误 - for _, ipAddresses := range self.Addresses { - for _, ipAddress := range ipAddresses { - if ipAddress.OSEXTIPSType == "fixed" { - nic := SInstanceNic{ - instance: self, - ipAddr: ipAddress.Addr, - macAddr: ipAddress.OSEXTIPSMACMACAddr, - } - nics = append(nics, &nic) - } - } - } - return nics, nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - ips := make([]string, 0) - for _, addresses := range self.Addresses { - for _, address := range addresses { - if address.OSEXTIPSType != "fixed" && !strings.HasPrefix(address.Addr, "100.") { - ips = append(ips, address.Addr) - } - } - } - - if len(ips) == 0 { - return nil, nil - } - - eips, err := self.host.zone.region.GetEips() - if err != nil { - return nil, err - } - - for _, eip := range eips { - if eip.PublicIPAddress == ips[0] { - return &eip, nil - } - } - - return nil, nil -} - -func (self *SInstance) GetVcpuCount() int { - cpu, _ := strconv.Atoi(self.Flavor.Vcpus) - return cpu -} - -func (self *SInstance) GetVmemSizeMB() int { - mem, _ := strconv.Atoi(self.Flavor.RAM) - return int(mem) -} - -func (self *SInstance) GetBootOrder() string { - return "dcn" -} - -func (self *SInstance) GetVga() string { - return "std" -} - -func (self *SInstance) GetVdi() string { - return "vnc" -} - -func (self *SInstance) GetOsArch() string { - if flavor, err := self.host.zone.region.GetICloudSku(self.Flavor.ID); err == nil { - return flavor.GetCpuArch() - } else { - log.Debugf("GetOSArch.GetICloudSku %s: %s", self.Flavor.ID, err) - } - - t := self.GetInstanceType() - if len(t) > 0 { - if strings.HasPrefix(t, "k") { - return apis.OS_ARCH_AARCH64 - } - } - - return apis.OS_ARCH_X86 -} - -func (self *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(osprofile.NormalizeOSType(self.Metadata.OSType)) -} - -func (self *SInstance) GetFullOsName() string { - return self.Metadata.ImageName -} - -func (i *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { - if i.osInfo == nil { - osInfo := imagetools.NormalizeImageInfo(i.Metadata.ImageName, "", i.Metadata.OSType, "", "") - i.osInfo = &osInfo - } - return i.osInfo -} - -func (i *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(i.getNormalizedOsInfo().OsBios) -} - -func (i *SInstance) GetOsDist() string { - return i.getNormalizedOsInfo().OsDistro -} - -func (i *SInstance) GetOsVersion() string { - return i.getNormalizedOsInfo().OsVersion -} - -func (i *SInstance) GetOsLang() string { - return i.getNormalizedOsInfo().OsLang -} - -func (self *SInstance) GetMachine() string { - return "pc" -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - return self.SetSecurityGroups([]string{secgroupId}) -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - currentSecgroups, err := self.host.zone.region.GetInstanceSecrityGroupIds(self.GetId()) - if err != nil { - return err - } - - add, remove, _ := compareSet(currentSecgroups, secgroupIds) - err = self.host.zone.region.assignSecurityGroups(add, self.GetId()) - if err != nil { - return err - } - - return self.host.zone.region.unassignSecurityGroups(remove, self.GetId()) -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_HCSO -} - -func (self *SInstance) StartVM(ctx context.Context) error { - if self.Status == InstanceStatusRunning { - return nil - } - - 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 - } - - if self.GetStatus() == api.VM_RUNNING { - return nil - } else if self.GetStatus() == api.VM_READY { - err := self.host.zone.region.StartVM(self.GetId()) - if err != nil { - return err - } - } - time.Sleep(interval) - } - return cloudprovider.ErrTimeout -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - if self.Status == InstanceStatusStopped { - return nil - } - - if self.Status == InstanceStatusTerminated { - log.Debugf("Instance already terminated.") - return nil - } - - err := self.host.zone.region.StopVM(self.GetId(), opts.IsForce) - if err != nil { - return err - } - return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - if self.Status == InstanceStatusTerminated { - return nil - } - - for { - err := self.host.zone.region.DeleteVM(self.GetId()) - if err != nil && self.Status != InstanceStatusTerminated { - log.Errorf("DeleteVM fail: %s", err) - return err - } else { - break - } - } - - return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return self.host.zone.region.UpdateVM(self.GetId(), name) -} - -// https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0032380449.html -// 创建云服务器过程中注入用户数据。支持注入文本、文本文件或gzip文件。 -// 注入内容,需要进行base64格式编码。注入内容(编码之前的内容)最大长度32KB。 -// 对于Linux弹性云服务器,adminPass参数传入时,user_data参数不生效。 -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html 使用原镜像重装 -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html 更换系统盘操作系统 -// 不支持调整系统盘大小 -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - var err error - var jobId string - - publicKeyName := "" - if len(desc.PublicKey) > 0 { - publicKeyName, err = self.host.zone.region.syncKeypair(desc.PublicKey) - if err != nil { - return "", err - } - } - - image, err := self.host.zone.region.GetImage(desc.ImageId) - if err != nil { - return "", errors.Wrap(err, "SInstance.RebuildRoot.GetImage") - } - - // Password存在的情况下,windows 系统直接使用密码 - if strings.ToLower(image.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(desc.Password) > 0 { - publicKeyName = "" - } - - userData, err := updateUserData(self.OSEXTSRVATTRUserData, image.OSVersion, desc.Account, desc.Password, desc.PublicKey) - if err != nil { - return "", errors.Wrap(err, "SInstance.RebuildRoot.updateUserData") - } - - if self.Metadata.MeteringImageID == desc.ImageId { - jobId, err = self.host.zone.region.RebuildRoot(ctx, self.UserID, self.GetId(), desc.Password, publicKeyName, userData) - if err != nil { - return "", err - } - } else { - jobId, err = self.host.zone.region.ChangeRoot(ctx, self.UserID, self.GetId(), desc.ImageId, desc.Password, publicKeyName, userData) - if err != nil { - return "", err - } - } - - err = self.host.zone.region.waitTaskStatus(self.host.zone.region.ecsClient.Servers.ServiceType(), jobId, TASK_SUCCESS, 15*time.Second, 900*time.Second) - if err != nil { - log.Errorf("RebuildRoot task error %s", err) - return "", err - } - - err = self.Refresh() - if err != nil { - return "", err - } - - idisks, err := self.GetIDisks() - if err != nil { - return "", err - } - - if len(idisks) == 0 { - return "", fmt.Errorf("server %s has no volume attached.", self.GetId()) - } - - return idisks[0].GetId(), nil -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return self.host.zone.region.DeployVM(self.GetId(), name, password, publicKey, deleteKeypair, description) -} - -func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - instanceTypes := []string{} - if len(config.InstanceType) > 0 { - instanceTypes = []string{config.InstanceType} - } else { - flavors, err := self.host.zone.region.GetMatchInstanceTypes(config.Cpu, config.MemoryMB, self.OSEXTAZAvailabilityZone) - if err != nil { - return errors.Wrapf(err, "GetMatchInstanceTypes") - } - for _, flavor := range flavors { - instanceTypes = append(instanceTypes, flavor.ID) - } - } - var err error - for _, instanceType := range instanceTypes { - err = self.host.zone.region.ChangeVMConfig(self.GetId(), instanceType) - if err != nil { - log.Warningf("ChangeVMConfig %s for %s error: %v", self.GetId(), instanceType, err) - } else { - return cloudprovider.WaitStatusWithDelay(self, api.VM_READY, 15*time.Second, 15*time.Second, 180*time.Second) - } - } - if err != nil { - return errors.Wrapf(err, "ChangeVMConfig") - } - return fmt.Errorf("Failed to change vm config, specification not supported") -} - -// todo:// 返回jsonobject感觉很诡异。不能直接知道内部细节 -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - return self.host.zone.region.GetInstanceVNCUrl(self.GetId()) -} - -func (self *SInstance) NextDeviceName() (string, error) { - prefix := "s" - if strings.Contains(self.OSEXTSRVATTRRootDeviceName, "/vd") { - prefix = "v" - } - - currents := []string{} - for _, item := range self.OSExtendedVolumesVolumesAttached { - currents = append(currents, strings.ToLower(item.Device)) - } - - for i := 0; i < 25; i++ { - device := fmt.Sprintf("/dev/%sd%s", prefix, string([]byte{byte(98 + i)})) - if ok, _ := utils.InStringArray(device, currents); !ok { - return device, nil - } - } - - return "", fmt.Errorf("disk devicename out of index, current deivces: %s", currents) -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - device, err := self.NextDeviceName() - if err != nil { - return errors.Wrap(err, "Instance.AttachDisk.NextDeviceName") - } - - err = self.host.zone.region.AttachDisk(self.GetId(), diskId, device) - if err != nil { - return errors.Wrap(err, "Instance.AttachDisk.AttachDisk") - } - - return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { - disk, err := self.host.zone.region.GetDisk(diskId) - if err != nil { - log.Debugf("Instance.AttachDisk.GetDisk %s", err) - return false, nil - } - - if disk.Status == "in-use" { - return true, nil - } - - return false, nil - }) -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - err := self.host.zone.region.DetachDisk(self.GetId(), diskId) - if err != nil { - return errors.Wrap(err, "Instance.DetachDisk") - } - - return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { - disk, err := self.host.zone.region.GetDisk(diskId) - if err != nil { - log.Debugf("Instance.DetachDisk.GetDisk %s", err) - return false, nil - } - - if disk.Status == "available" { - return true, nil - } - - return false, nil - }) -} - -func (self *SInstance) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148850.html -func (self *SRegion) GetInstances() ([]SInstance, error) { - queries := make(map[string]string) - - if len(self.client.projectId) > 0 { - queries["project_id"] = self.client.projectId - } - - instances := make([]SInstance, 0) - err := doListAllWithPagerOffset(self.ecsClient.Servers.List, queries, &instances) - return instances, err -} - -func (self *SRegion) GetInstanceByID(instanceId string) (SInstance, error) { - instance := SInstance{} - err := DoGet(self.ecsClient.Servers.Get, instanceId, nil, &instance) - if instance.Status == "DELETED" { - return instance, errors.Wrap(cloudprovider.ErrNotFound, "GetInstanceByID") - } - return instance, err -} - -func (self *SRegion) GetInstanceByIds(ids []string) ([]SInstance, int, error) { - instances := make([]SInstance, 0) - for _, instanceId := range ids { - instance, err := self.GetInstanceByID(instanceId) - if err != nil { - return nil, 0, err - } - instances = append(instances, instance) - } - - return instances, len(instances), nil -} - -/* -系统盘大小取值范围:1-1024 GB,且必须不小于镜像min_disk. -*/ -type SServerCreate struct { - AvailabilityZone string `json:"availability_zone"` - Name string `json:"name"` - ImageRef string `json:"imageRef"` - RootVolume RootVolume `json:"root_volume"` - DataVolumes []DataVolume `json:"data_volumes"` - FlavorRef string `json:"flavorRef"` - UserData string `json:"user_data"` - Vpcid string `json:"vpcid"` - SecurityGroups []SecGroup `json:"security_groups"` - Nics []NIC `json:"nics"` - KeyName string `json:"key_name"` - AdminPass string `json:"adminPass"` - Count int64 `json:"count"` - Extendparam ServerExtendparam `json:"extendparam"` - ServerTags []ServerTag `json:"server_tags"` - Description string `json:"description"` -} - -type DataVolume struct { - Volumetype string `json:"volumetype"` - SizeGB int `json:"size"` - Extendparam *DataVolumeExtendparam `json:"extendparam,omitempty"` - Multiattach *bool `json:"multiattach,omitempty"` - HwPassthrough *string `json:"hw:passthrough,omitempty"` -} - -type DataVolumeExtendparam struct { - SnapshotID string `json:"snapshotId"` -} - -type ServerExtendparam struct { - ChargingMode string `json:"chargingMode"` // 计费模式 prePaid|postPaid - PeriodType string `json:"periodType"` // 周期类型:month|year - PeriodNum string `json:"periodNum"` // 订购周期数:periodType=month(周期类型为月)时,取值为[1,9]。periodType=year(周期类型为年)时,取值为1。 - IsAutoRenew string `json:"isAutoRenew"` // 是否自动续订 true|false - IsAutoPay string `json:"isAutoPay"` // 是否自动从客户的账户中支付 true|false - RegionID string `json:"regionID"` - EnterpriseProjectId string `json:"enterprise_project_id,omitempty"` -} - -type NIC struct { - SubnetID string `json:"subnet_id"` // 网络ID. 与 SNetwork里的ID对应。统一使用这个ID - IpAddress string `json:"ip_address"` -} - -type RootVolume struct { - Volumetype string `json:"volumetype"` - SizeGB int `json:"size"` -} - -type SecGroup struct { - ID string `json:"id"` -} - -type ServerTag struct { - Key string `json:"key"` - Value string `json:"value"` -} - -/* -包月机器退订规则: https://support.huaweicloud.com/usermanual-billing/zh-cn_topic_0083138805.html -5天无理由全额退订:新购资源(不包含续费资源)在开通的五天内且退订次数不超过10次(每账号每年10次)的符合5天无理由全额退订。 -非5天无理由退订:不符合5天无理由全额退订条件的退订,都属于非5天无理由退订。非5天无理由退订,不限制退订次数,但需要收取退订手续费。 - -退订资源的方法: https://support.huaweicloud.com/usermanual-billing/zh-cn_topic_0072297197.html -*/ -func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, SubnetId string, - securityGroupId string, vpcId string, zoneId string, desc string, disks []SDisk, ipAddr string, - keypair string, publicKey string, passwd string, userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (string, error) { - params := SServerCreate{} - params.AvailabilityZone = zoneId - params.Name = name - params.FlavorRef = instanceType - params.ImageRef = imageId - params.Description = desc - params.Count = 1 - params.Nics = []NIC{{SubnetID: SubnetId, IpAddress: ipAddr}} - params.SecurityGroups = []SecGroup{{ID: securityGroupId}} - params.Vpcid = vpcId - - for i, disk := range disks { - if i == 0 { - params.RootVolume.Volumetype = disk.VolumeType - params.RootVolume.SizeGB = disk.SizeGB - } else { - dataVolume := DataVolume{} - dataVolume.Volumetype = disk.VolumeType - dataVolume.SizeGB = disk.SizeGB - params.DataVolumes = append(params.DataVolumes, dataVolume) - } - } - - if len(projectId) > 0 { - params.Extendparam.EnterpriseProjectId = projectId - } - - // billing type - if bc != nil { - params.Extendparam.ChargingMode = PRE_PAID - if bc.GetMonths() <= 9 { - params.Extendparam.PeriodNum = strconv.Itoa(bc.GetMonths()) - params.Extendparam.PeriodType = "month" - } else { - params.Extendparam.PeriodNum = strconv.Itoa(bc.GetYears()) - params.Extendparam.PeriodType = "year" - } - - params.Extendparam.RegionID = self.GetId() - if bc.AutoRenew { - params.Extendparam.IsAutoRenew = "true" - } else { - params.Extendparam.IsAutoRenew = "false" - } - params.Extendparam.IsAutoPay = "true" - } else { - params.Extendparam.ChargingMode = POST_PAID - } - - // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212668.html#ZH-CN_TOPIC_0020212668__table761103195216 - if len(keypair) > 0 { - params.KeyName = keypair - } else { - params.AdminPass = passwd - } - - if len(userData) > 0 { - params.UserData = userData - } - - if len(tags) > 0 { - serverTags := []ServerTag{} - for k, v := range tags { - serverTags = append(serverTags, ServerTag{Key: k, Value: v}) - } - params.ServerTags = serverTags - } - - serverObj := jsonutils.Marshal(params) - createParams := jsonutils.NewDict() - createParams.Add(serverObj, "server") - _id, err := self.ecsClient.Servers.AsyncCreate(createParams) - if err != nil { - return "", err - } - - var ids []string - if params.Extendparam.ChargingMode == POST_PAID { - // 按需计费 - ids, err = self.GetAllSubTaskEntityIDs(self.ecsClient.Servers.ServiceType(), _id, "server_id") - } else { - // 包年包月 - return "", errors.Wrap(cloudprovider.ErrNotSupported, "CreateInstance") - } - - if err != nil { - return "", err - } else if len(ids) == 0 { - return "", fmt.Errorf("CreateInstance job %s result is emtpy", _id) - } else if len(ids) == 1 { - return ids[0], nil - } else { - return "", fmt.Errorf("CreateInstance job %s mutliple instance id returned. %s", _id, ids) - } -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067161469.html -// 添加多个安全组时,建议最多为弹性云服务器添加5个安全组。 -// todo: 确认是否需要先删除,再进行添加操作 -func (self *SRegion) assignSecurityGroups(secgroupIds []string, instanceId string) error { - _, err := self.GetInstanceByID(instanceId) - if err != nil { - return err - } - - for i := range secgroupIds { - secId := secgroupIds[i] - params := jsonutils.NewDict() - secgroupObj := jsonutils.NewDict() - secgroupObj.Add(jsonutils.NewString(secId), "name") - params.Add(secgroupObj, "addSecurityGroup") - - _, err := self.ecsClient.NovaServers.PerformAction("action", instanceId, params) - if err != nil { - return err - } - } - return nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067161717.html -func (self *SRegion) unassignSecurityGroups(secgroupIds []string, instanceId string) error { - for i := range secgroupIds { - secId := secgroupIds[i] - params := jsonutils.NewDict() - secgroupObj := jsonutils.NewDict() - secgroupObj.Add(jsonutils.NewString(secId), "name") - params.Add(secgroupObj, "removeSecurityGroup") - - _, err := self.ecsClient.NovaServers.PerformAction("action", instanceId, params) - if err != nil { - return err - } - } - return nil -} - -func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) { - instance, err := self.GetInstanceByID(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: %s", err) - return err - } - if status != remoteStatus { - log.Errorf("instanceStatusChecking: vm status is %s expect %s", remoteStatus, status) - return cloudprovider.ErrInvalidStatus - } - - return nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212207.html -func (self *SRegion) StartVM(instanceId string) error { - rstatus, err := self.GetInstanceStatus(instanceId) - if err != nil { - return err - } - - if rstatus == InstanceStatusRunning { - return nil - } - - if rstatus != InstanceStatusStopped { - log.Errorf("instanceStatusChecking: vm status is %s expect %s", rstatus, InstanceStatusStopped) - return cloudprovider.ErrInvalidStatus - } - - params := jsonutils.NewDict() - startObj := jsonutils.NewDict() - serversObj := jsonutils.NewArray() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(instanceId), "id") - serversObj.Add(serverObj) - startObj.Add(serversObj, "servers") - params.Add(startObj, "os-start") - _, err = self.ecsClient.Servers.PerformAction2("action", "", params, "") - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212651.html -func (self *SRegion) StopVM(instanceId string, isForce bool) error { - rstatus, err := self.GetInstanceStatus(instanceId) - if err != nil { - return err - } - - if rstatus == InstanceStatusStopped { - return nil - } - - if rstatus != InstanceStatusRunning { - log.Errorf("instanceStatusChecking: vm status is %s expect %s", rstatus, InstanceStatusRunning) - return cloudprovider.ErrInvalidStatus - } - - params := jsonutils.NewDict() - stopObj := jsonutils.NewDict() - serversObj := jsonutils.NewArray() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(instanceId), "id") - serversObj.Add(serverObj) - stopObj.Add(serversObj, "servers") - if isForce { - stopObj.Add(jsonutils.NewString("HARD"), "type") - } else { - stopObj.Add(jsonutils.NewString("SOFT"), "type") - } - params.Add(stopObj, "os-stop") - _, err = self.ecsClient.Servers.PerformAction2("action", "", params, "") - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212679.html -// 只删除主机。弹性IP和数据盘需要单独删除 -func (self *SRegion) DeleteVM(instanceId string) error { - remoteStatus, err := self.GetInstanceStatus(instanceId) - if err != nil { - return err - } - - if remoteStatus != InstanceStatusStopped { - log.Errorf("DeleteVM vm status is %s expect %s", remoteStatus, InstanceStatusStopped) - return cloudprovider.ErrInvalidStatus - } - - params := jsonutils.NewDict() - serversObj := jsonutils.NewArray() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(instanceId), "id") - serversObj.Add(serverObj) - params.Add(serversObj, "servers") - params.Add(jsonutils.NewBool(false), "delete_publicip") - params.Add(jsonutils.NewBool(false), "delete_volume") - - _, err = self.ecsClient.Servers.PerformAction2("delete", "", params, "") - return err -} - -func (self *SRegion) UpdateVM(instanceId, name string) error { - params := jsonutils.NewDict() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(name), "name") - params.Add(serverObj, "server") - - _, err := self.ecsClient.Servers.Update(instanceId, params) - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html -// 返回job id -func (self *SRegion) RebuildRoot(ctx context.Context, userId, instanceId, passwd, publicKeyName, userData string) (string, error) { - params := jsonutils.NewDict() - reinstallObj := jsonutils.NewDict() - - if len(publicKeyName) > 0 { - reinstallObj.Add(jsonutils.NewString(publicKeyName), "keyname") - } else if len(passwd) > 0 { - reinstallObj.Add(jsonutils.NewString(passwd), "adminpass") - } else { - return "", fmt.Errorf("both password and publicKey are empty.") - } - - if len(userData) > 0 { - meta := jsonutils.NewDict() - meta.Add(jsonutils.NewString(userData), "user_data") - reinstallObj.Add(meta, "metadata") - } - - if len(userId) > 0 { - reinstallObj.Add(jsonutils.NewString(userId), "userid") - } - - params.Add(reinstallObj, "os-reinstall") - ret, err := self.ecsClient.ServersV2.PerformAction2("reinstallos", instanceId, params, "") - if err != nil { - return "", err - } - - return ret.GetString("job_id") -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html -// 返回job id -func (self *SRegion) ChangeRoot(ctx context.Context, userId, instanceId, imageId, passwd, publicKeyName, userData string) (string, error) { - params := jsonutils.NewDict() - changeOsObj := jsonutils.NewDict() - - if len(publicKeyName) > 0 { - changeOsObj.Add(jsonutils.NewString(publicKeyName), "keyname") - } else if len(passwd) > 0 { - changeOsObj.Add(jsonutils.NewString(passwd), "adminpass") - } else { - return "", fmt.Errorf("both password and publicKey are empty.") - } - - if len(userData) > 0 { - meta := jsonutils.NewDict() - meta.Add(jsonutils.NewString(userData), "user_data") - changeOsObj.Add(meta, "metadata") - } - - if len(userId) > 0 { - changeOsObj.Add(jsonutils.NewString(userId), "userid") - } - - changeOsObj.Add(jsonutils.NewString(imageId), "imageid") - params.Add(changeOsObj, "os-change") - - ret, err := self.ecsClient.ServersV2.PerformAction2("changeos", instanceId, params, "") - if err != nil { - return "", err - } - - return ret.GetString("job_id") -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212692.html -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0110109377.html -// 一键式重置密码 需要安装安装一键式重置密码插件 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0068095385.html -// 目前不支持直接重置密钥 -func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { - serverObj := jsonutils.NewDict() - if len(name) > 0 { - serverObj.Add(jsonutils.NewString(name), "name") - } - - // if len(description) > 0 { - // serverObj.Add(jsonutils.NewString(description), "description") - // } - - if serverObj.Size() > 0 { - params := jsonutils.NewDict() - params.Add(serverObj, "server") - // 这里华为返回的image字段是字符串。和SInstance的定义的image是字典结构不一致。 - err := DoUpdate(self.ecsClient.NovaServers.Update, instanceId, params, nil) - if err != nil { - return err - } - } - - if len(password) > 0 { - params := jsonutils.NewDict() - passwdObj := jsonutils.NewDict() - passwdObj.Add(jsonutils.NewString(password), "new_password") - params.Add(passwdObj, "reset-password") - - err := DoUpdateWithSpec(self.ecsClient.NovaServers.UpdateInContextWithSpec, instanceId, "os-reset-password", params) - if err != nil { - return err - } - } - - return nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212653.html -func (self *SRegion) ChangeVMConfig(instanceId string, instanceType string) error { - self.ecsClient.Servers.SetVersion("v1.1") - defer self.ecsClient.Servers.SetVersion("v1") - - params := jsonutils.NewDict() - resizeObj := jsonutils.NewDict() - resizeObj.Add(jsonutils.NewString(instanceType), "flavorRef") - params.Add(resizeObj, "resize") - _, err := self.ecsClient.Servers.PerformAction2("resize", instanceId, params, "") - return errors.Wrapf(err, "PerformAction2(resize)") -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0142763126.html 微版本2.6及以上? -// https://support.huaweicloud.com/api-ecs/ecs_02_0208.html -func (self *SRegion) GetInstanceVNCUrl(instanceId string) (*cloudprovider.ServerVncOutput, error) { - params := jsonutils.NewDict() - vncObj := jsonutils.NewDict() - vncObj.Add(jsonutils.NewString("novnc"), "type") - vncObj.Add(jsonutils.NewString("vnc"), "protocol") - params.Add(vncObj, "remote_console") - - resp, err := self.ecsClient.Servers.PerformAction2("remote_console", instanceId, params, "remote_console") - if err != nil { - return nil, err - } - - ret := &cloudprovider.ServerVncOutput{ - Hypervisor: api.HYPERVISOR_HCSO, - } - resp.Unmarshal(ret) - ret.Protocol = "huawei" - return ret, nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022472987.html -// XEN平台虚拟机device为必选参数。 -func (self *SRegion) AttachDisk(instanceId string, diskId string, device string) error { - params := jsonutils.NewDict() - volumeObj := jsonutils.NewDict() - volumeObj.Add(jsonutils.NewString(diskId), "volumeId") - if len(device) > 0 { - volumeObj.Add(jsonutils.NewString(device), "device") - } - - params.Add(volumeObj, "volumeAttachment") - - _, err := self.ecsClient.Servers.PerformAction2("attachvolume", instanceId, params, "") - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022472988.html -// 默认非强制卸载。delete_flag=0 -func (self *SRegion) DetachDisk(instanceId string, diskId string) error { - path := fmt.Sprintf("detachvolume/%s", diskId) - err := DoDeleteWithSpec(self.ecsClient.Servers.DeleteInContextWithSpec, nil, instanceId, path, nil, nil) - //volume a2091934-2669-4fca-8eb4-a950c1836b3c is not in server 49b053d2-f798-432f-af55-76eb6ef2c769 attach volume list => 磁盘已经被卸载了 - if err != nil && strings.Contains(err.Error(), fmt.Sprintf("is not in server")) && strings.Contains(err.Error(), fmt.Sprintf("attach volume list")) { - return nil - } - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817702.html -func (self *SRegion) GetInstanceSecrityGroupIds(instanceId string) ([]string, error) { - if len(instanceId) == 0 { - return nil, fmt.Errorf("GetInstanceSecrityGroups instanceId is empty") - } - - securitygroups := make([]SSecurityGroup, 0) - ctx := &modules.SManagerContext{InstanceManager: self.ecsClient.NovaServers, InstanceId: instanceId} - err := DoListInContext(self.ecsClient.NovaSecurityGroups.ListInContext, ctx, nil, &securitygroups) - if err != nil { - return nil, err - } - - securitygroupIds := []string{} - for _, secgroup := range securitygroups { - securitygroupIds = append(securitygroupIds, secgroup.GetId()) - } - - return securitygroupIds, nil -} - -func (self *SInstance) GetProjectId() string { - return self.EnterpriseProjectId -} - -func (self *SInstance) GetError() error { - return nil -} - -func updateUserData(userData, osVersion, username, password, publicKey string) (string, error) { - winOS := strings.ToLower(osprofile.OS_TYPE_WINDOWS) - osVersion = strings.ToLower(osVersion) - config := &cloudinit.SCloudConfig{} - if strings.Contains(osVersion, winOS) { - if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { - config = _config - } else { - log.Debugf("updateWindowsUserData invalid userdata %s", userData) - } - } else { - if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { - config = _config - } else { - return "", fmt.Errorf("updateLinuxUserData invalid userdata %s", userData) - } - } - - user := cloudinit.NewUser(username) - config.RemoveUser(user) - config.DisableRoot = 0 - if len(password) > 0 { - config.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON - user.Password(password) - config.MergeUser(user) - } - - if len(publicKey) > 0 { - user.SshKey(publicKey) - config.MergeUser(user) - } - - if strings.Contains(osVersion, winOS) { - userData, err := updateWindowsUserData(config.UserDataPowerShell(), osVersion, username, password) - if err != nil { - return "", errors.Wrap(err, "updateUserData.updateWindowsUserData") - } - return userData, nil - } else { - return config.UserDataBase64(), nil - } -} - -func updateWindowsUserData(userData string, osVersion string, username, password string) (string, error) { - // Windows Server 2003, Windows Vista, Windows Server 2008, Windows Server 2003 R2, Windows Server 2000, Windows Server 2012, Windows Server 2003 with SP1, Windows 8 - oldVersions := []string{"2000", "2003", "2008", "2012", "Vista"} - isOldVersion := false - for i := range oldVersions { - if strings.Contains(osVersion, oldVersions[i]) { - isOldVersion = true - } - } - - shells := "" - if isOldVersion { - shells += fmt.Sprintf("rem cmd\n") - if username == "Administrator" { - shells += fmt.Sprintf("net user %s %s\n", username, password) - } else { - shells += fmt.Sprintf("net user %s %s /add\n", username, password) - shells += fmt.Sprintf("net localgroup administrators %s /add\n", username) - } - - shells += fmt.Sprintf("net user %s /active:yes", username) - } else { - if !strings.HasPrefix(userData, "#ps1") { - shells = fmt.Sprintf("#ps1\n%s", userData) - } - } - - return base64.StdEncoding.EncodeToString([]byte(shells)), nil -} - -func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { - params := map[string]string{ - "name": opts.Name, - "instance_id": instanceId, - } - if len(opts.Notes) > 0 { - params["description"] = func() string { - opts.Notes = strings.ReplaceAll(opts.Notes, "<", "") - opts.Notes = strings.ReplaceAll(opts.Notes, ">", "") - opts.Notes = strings.ReplaceAll(opts.Notes, "\n", "") - if len(opts.Notes) > 1024 { - opts.Notes = opts.Notes[:1024] - } - return opts.Notes - }() - } - resp, err := self.ecsClient.Images.CreateInContextWithSpec(nil, "action", jsonutils.Marshal(params), "") - if err != nil { - return nil, errors.Wrapf(err, "Images.Create") - } - jobId, err := resp.GetString("job_id") - if err != nil { - return nil, errors.Wrapf(err, "resp.GetString(job_id)") - } - err = self.waitTaskStatus(self.ecsClient.Images.ServiceType(), jobId, TASK_SUCCESS, 15*time.Second, 10*time.Minute) - if err != nil { - return nil, errors.Wrapf(err, "waitTaskStatus") - } - imageId, err := self.GetTaskEntityID(self.ecsClient.Images.ServiceType(), jobId, "image_id") - if err != nil { - return nil, errors.Wrapf(err, "GetTaskEntityID") - } - image, err := self.GetImage(imageId) - if err != nil { - return nil, errors.Wrapf(err, "GetImage(%s)", imageId) - } - image.storageCache = self.getStoragecache() - return image, nil -} - -func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { - image, err := self.host.zone.region.SaveImage(self.ID, opts) - if err != nil { - return nil, errors.Wrapf(err, "SaveImage") - } - return image, nil -} diff --git a/pkg/multicloud/hcso/instancenic.go b/pkg/multicloud/hcso/instancenic.go deleted file mode 100644 index 6b1e5f6d4c..0000000000 --- a/pkg/multicloud/hcso/instancenic.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/modules" -) - -// =========================================== -type Interface struct { - PortState string `json:"port_state"` - FixedIPS []FixedIP `json:"fixed_ips"` - NetID string `json:"net_id"` // 网络ID. 与 SNetwork里的ID对应。统一使用这个ID - PortID string `json:"port_id"` - MACAddr string `json:"mac_addr"` -} - -/* -subnet: {id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233", name: "subnet-149c", cidr: "192.168.0.0/24",…} -availability_zone: "cn-north-1b" -cidr: "192.168.0.0/24" -dhcp_enable: true -dnsList: ["100.125.1.250", "100.125.21.250"] -gateway_ip: "192.168.0.1" -id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233" -ipv6_enable: false -name: "subnet-149c" -neutron_network_id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233" -neutron_subnet_id: "81fcfaa0-8e73-4472-9eba-3b2b7736d3a7" -primary_dns: "100.125.1.250" -secondary_dns: "100.125.21.250" -status: "ACTIVE" -tags: [] -vpc_id: "877f1feb-3dc8-4c2d-92e9-0d94fd7d79dd"} -*/ -type FixedIP struct { - SubnetID string `json:"subnet_id"` // 子网ID, 与SNetwork中的 neutron_subnet_id对应. 注意!!! 并不是SNetwork ID。 - IPAddress string `json:"ip_address"` -} - -// =========================================== - -type SInstanceNic struct { - instance *SInstance - ipAddr string - macAddr string - - cloudprovider.DummyICloudNic -} - -func (self *SInstanceNic) GetId() string { - return "" -} - -func (self *SInstanceNic) GetIP() string { - return self.ipAddr -} - -func (self *SInstanceNic) GetMAC() string { - return self.macAddr -} - -func (self *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (self *SInstanceNic) GetINetworkId() string { - instanceId := self.instance.GetId() - subnets, err := self.instance.host.zone.region.getSubnetIdsByInstanceId(instanceId) - if err != nil || len(subnets) == 0 { - log.Errorf("getSubnetIdsByInstanceId error: %s", err.Error()) - return "" - } - return subnets[0] -} - -func (self *SRegion) getSubnetIdsByInstanceId(instanceId string) ([]string, error) { - ctx := &modules.SManagerContext{InstanceManager: self.ecsClient.NovaServers, InstanceId: instanceId} - interfaces := make([]Interface, 0) - err := DoListInContext(self.ecsClient.Interface.ListInContext, ctx, nil, &interfaces) - if err != nil { - return nil, err - } - - subnets := make([]string, 0) - for _, i := range interfaces { - subnets = append(subnets, i.NetID) - } - - return subnets, nil -} diff --git a/pkg/multicloud/hcso/instancetype.go b/pkg/multicloud/hcso/instancetype.go deleted file mode 100644 index 46645fc635..0000000000 --- a/pkg/multicloud/hcso/instancetype.go +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "strconv" - "strings" - - "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212656.html -type SInstanceType struct { - multicloud.SResourceBase - ID string `json:"id"` - Name string `json:"name"` - Vcpus string `json:"vcpus"` - RamMB int `json:"ram"` // 内存大小 - Disk string `json:"disk"` - Swap string `json:"swap"` - OSFLVEXTDATAEphemeral int64 `json:"OS-FLV-EXT-DATA:ephemeral"` - RxtxFactor int64 `json:"rxtx_factor"` - OSFLVDISABLEDDisabled bool `json:"OS-FLV-DISABLED:disabled"` - OSFlavorAccessIsPublic bool `json:"os-flavor-access:is_public"` - OSExtraSpecs OSExtraSpecs `json:"os_extra_specs"` // 扩展规格 -} - -type OSExtraSpecs struct { - EcsPerformancetype string `json:"ecs:performancetype"` - EcsGeneration string `json:"ecs:generation"` - EcsInstanceArchitecture string `json:"ecs:instance_architecture"` -} - -var FLAVOR_FAMILY_CATEGORY_MAP = map[string]string{ - "s1": "通用型I代", - "s2": "通用型II代", - "s3": "通用型S3", - "sn3": "通用型", - "s6": "通用型S6", - "p1": "GPU P1型", - "pi1": "GPU Pi1型", - "p2v": "GPU P2v型", - "t6": "通用型T6", - "m1": "内存优化型I代", - "m2": "内存优化型II代", - "m3": "内存优化型", - "m3ne": "内存优化M3ne型", - "h1": "高性能计算型I代", - "h2": "高性能计算型II代", - "h3": "高性能计算型", - "hc2": "高性能计算HC2型", - "hi3": "超高性能计算型", - "d1": "密集存储型I代", - "d2": "密集存储型II代", - "d3": "磁盘增强型", - "g1": "GPU加速型I代", - "g2": "GPU加速型II代", - "g3": "GPU加速型III代", - "f1": "FPGA高性能型", - "f2": "FPGA通用型", - "fp1": "FPGA FP1型", - "fp1c": "FPGA FP1C型", - "ai1": "人工智能Ai1型", - "c1": "通用计算增强C1型", - "c2": "通用计算增强C2型", - "c3": "通用计算增强C3型", - "c3ne": "通用计算增强C3ne型", - "c6": "通用计算增强C6型", - "e1": "大内存E1型", - "e2": "大内存E2型", - "et2": "大内存ET2型", - "e3": "大内存E3型", - "i3": "超高I/O型", - "kc1": "鲲鹏通用计算增强型", - "km1": "鲲鹏内存优化型", - "ki1": "鲲鹏超高I/O型", - "kai1s": "鲲鹏AI推理加速型", -} - -func getFlavorCategory(family string) string { - ret, ok := FLAVOR_FAMILY_CATEGORY_MAP[family] - if ok { - return ret - } - - return family -} - -func getFlavorLocalCategory(family string) string { - switch family { - case "s1", "s2", "s3", "sn3", "s6", "t6": - return "general-purpose" - case "c1", "c2", "c3", "c3ne", "c6", "h1", "h2", "h3", "hc2", "hi3", "kc1": - return "compute-optimized" - case "m1", "m2", "m3", "m3ne", "e1", "e2", "et2", "e3", "km1": - return "memory-optimized" - case "d1", "d2", "d3": - return "storage-optimized" - case "p1", "pi1", "p2v", "g1", "g2", "g3": - return "gpu-compute" - default: - return "others" - } -} - -func (self *SInstanceType) GetId() string { - return self.ID -} - -func (self *SInstanceType) GetName() string { - return self.ID -} - -func (self *SInstanceType) GetGlobalId() string { - return self.ID -} - -func (self *SInstanceType) GetStatus() string { - return "" -} - -func (self *SInstanceType) Refresh() error { - return nil -} - -func (self *SInstanceType) IsEmulated() bool { - return false -} - -func (self *SInstanceType) GetSysTags() map[string]string { - return nil -} - -func (self *SInstanceType) GetTags() (map[string]string, error) { - return nil, nil -} - -func (self *SInstanceType) SetTags(tags map[string]string, replace bool) error { - return nil -} - -func (self *SInstanceType) GetInstanceTypeFamily() string { - if len(self.OSExtraSpecs.EcsGeneration) > 0 { - return self.OSExtraSpecs.EcsGeneration - } else { - return strings.Split(self.ID, ".")[0] - } -} - -func (self *SInstanceType) GetInstanceTypeCategory() string { - return getFlavorCategory(self.GetInstanceTypeFamily()) -} - -func (self *SInstanceType) GetPrepaidStatus() string { - return "available" -} - -func (self *SInstanceType) GetPostpaidStatus() string { - return "available" -} - -// https://support.huaweicloud.com/productdesc-ecs/ecs_01_0066.html -// https://support.huaweicloud.com/ecs_faq/ecs_faq_0105.html -func (self *SInstanceType) GetCpuArch() string { - if len(self.OSExtraSpecs.EcsInstanceArchitecture) > 0 { - if strings.ToLower(self.OSExtraSpecs.EcsInstanceArchitecture) == "arm64" { - return apis.OS_ARCH_AARCH64 - } - - if strings.HasPrefix(self.OSExtraSpecs.EcsInstanceArchitecture, "arm") { - return apis.OS_ARCH_AARCH64 - } - } - - if strings.HasPrefix(self.ID, "k") { - return apis.OS_ARCH_AARCH64 - } - - return apis.OS_ARCH_X86 -} - -func (self *SInstanceType) GetCpuCoreCount() int { - count, err := strconv.Atoi(self.Vcpus) - if err == nil { - return count - } - return 0 -} - -func (self *SInstanceType) GetMemorySizeMB() int { - return self.RamMB -} - -func (self *SInstanceType) GetOsName() string { - return "" -} - -func (self *SInstanceType) GetSysDiskResizable() bool { - return false -} - -func (self *SInstanceType) GetSysDiskType() string { - return "" -} - -func (self *SInstanceType) GetSysDiskMinSizeGB() int { - return 0 -} - -func (self *SInstanceType) GetSysDiskMaxSizeGB() int { - return 0 -} - -func (self *SInstanceType) GetAttachedDiskType() string { - return "" -} - -func (self *SInstanceType) GetAttachedDiskSizeGB() int { - return 0 -} - -func (self *SInstanceType) GetAttachedDiskCount() int { - return 0 -} - -func (self *SInstanceType) GetDataDiskTypes() string { - return "" -} - -func (self *SInstanceType) GetDataDiskMaxCount() int { - return 0 -} - -func (self *SInstanceType) GetNicType() string { - return "" -} - -func (self *SInstanceType) GetNicMaxCount() int { - return 0 -} - -func (self *SInstanceType) GetGpuAttachable() bool { - return self.OSExtraSpecs.EcsPerformancetype == "gpu" -} - -func (self *SInstanceType) GetGpuSpec() string { - if self.OSExtraSpecs.EcsPerformancetype == "gpu" { - return self.OSExtraSpecs.EcsGeneration - } - - return "" -} - -func (self *SInstanceType) GetGpuCount() int { - if self.OSExtraSpecs.EcsPerformancetype == "gpu" { - return 1 - } - - return 0 -} - -func (self *SInstanceType) GetGpuMaxCount() int { - if self.OSExtraSpecs.EcsPerformancetype == "gpu" { - return 1 - } - - return 0 -} - -func (self *SInstanceType) Delete() error { - return nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212656.html -func (self *SRegion) fetchInstanceTypes(zoneId string) ([]SInstanceType, error) { - querys := map[string]string{} - if len(zoneId) > 0 { - querys["availability_zone"] = zoneId - } - - instanceTypes := make([]SInstanceType, 0) - err := doListAll(self.ecsClient.Flavors.List, querys, &instanceTypes) - return instanceTypes, err -} - -func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, zoneId string) ([]SInstanceType, error) { - instanceTypes, err := self.fetchInstanceTypes(zoneId) - if err != nil { - return nil, err - } - - ret := make([]SInstanceType, 0) - for _, t := range instanceTypes { - // cpu & mem & disk都匹配才行 - if t.Vcpus == strconv.Itoa(cpu) && t.RamMB == memMB { - ret = append(ret, t) - } - } - - return ret, nil -} diff --git a/pkg/multicloud/hcso/latitud_and_longitude.go b/pkg/multicloud/hcso/latitud_and_longitude.go deleted file mode 100644 index 74d4ff2477..0000000000 --- a/pkg/multicloud/hcso/latitud_and_longitude.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -// China: https://developer.huaweicloud.com/endpoint -// International: https://developer-intl.huaweicloud.com/endpoint -// ref: https://countrycode.org -var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ - "cn-east-2": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-east-3": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-north-1": {Latitude: 39.997743, Longitude: 116.304542, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-north-4": {Latitude: 39.997743, Longitude: 116.304542, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-south-1": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-south-2": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "ap-southeast-1": {Latitude: 22.396428, Longitude: 114.109497, City: api.CITY_HONG_KONG, CountryCode: api.COUNTRY_CODE_CN}, - "ap-southeast-2": {Latitude: 13.7563309, Longitude: 100.5017651, City: api.CITY_BANGKOK, CountryCode: api.COUNTRY_CODE_TH}, - "ap-southeast-3": {Latitude: 1.360386, Longitude: 103.821195, City: api.CITY_SINGAPORE, CountryCode: api.COUNTRY_CODE_SG}, - "eu-west-0": {Latitude: 48.856614, Longitude: 2.3522219, City: api.CITY_PARIS, CountryCode: api.COUNTRY_CODE_FR}, - "cn-northeast-1": {Latitude: 38.91400300000001, Longitude: 121.614682, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-southwest-2": {Latitude: 26.6470035286, Longitude: 106.6302113880, City: api.CITY_GUI_YANG, CountryCode: api.COUNTRY_CODE_CN}, - "af-south-1": {Latitude: -26.1714537, Longitude: 27.8999389, City: api.CITY_JOHANNESBURG, CountryCode: api.COUNTRY_CODE_ZA}, - "sa-brazil-1": {Latitude: -23.5505199, Longitude: -46.6333094, City: api.CITY_SAO_PAULO, CountryCode: api.COUNTRY_CODE_BR}, - "na-mexico-1": {Latitude: 55.1182908, Longitude: 141.0377645, City: api.CITY_MEXICO, CountryCode: api.COUNTRY_CODE_MX}, - "la-south-2": {Latitude: -33.45206, Longitude: -70.676031, City: api.CITY_SANTIAGO, CountryCode: api.COUNTRY_CODE_CL}, - "cn-north-9": {Latitude: 41.0178713, Longitude: 113.094978, City: api.CITY_NEI_MENG_GU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-north-219": {Latitude: 39.997743, Longitude: 116.304542, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, -} diff --git a/pkg/multicloud/hcso/loadbalancer.go b/pkg/multicloud/hcso/loadbalancer.go deleted file mode 100644 index a634248f25..0000000000 --- a/pkg/multicloud/hcso/loadbalancer.go +++ /dev/null @@ -1,553 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var LB_ALGORITHM_MAP = map[string]string{ - api.LB_SCHEDULER_WRR: "ROUND_ROBIN", - api.LB_SCHEDULER_WLC: "LEAST_CONNECTIONS", - api.LB_SCHEDULER_SCH: "SOURCE_IP", -} - -var LB_PROTOCOL_MAP = map[string]string{ - api.LB_LISTENER_TYPE_HTTP: "HTTP", - api.LB_LISTENER_TYPE_HTTPS: "TERMINATED_HTTPS", - api.LB_LISTENER_TYPE_UDP: "UDP", - api.LB_LISTENER_TYPE_TCP: "TCP", -} - -var LBBG_PROTOCOL_MAP = map[string]string{ - api.LB_LISTENER_TYPE_HTTP: "HTTP", - api.LB_LISTENER_TYPE_HTTPS: "HTTP", - api.LB_LISTENER_TYPE_UDP: "UDP", - api.LB_LISTENER_TYPE_TCP: "TCP", -} - -var LB_STICKY_SESSION_MAP = map[string]string{ - api.LB_STICKY_SESSION_TYPE_INSERT: "HTTP_COOKIE", - api.LB_STICKY_SESSION_TYPE_SERVER: "APP_COOKIE", -} - -var LB_HEALTHCHECK_TYPE_MAP = map[string]string{ - api.LB_HEALTH_CHECK_HTTP: "HTTP", - api.LB_HEALTH_CHECK_TCP: "TCP", - api.LB_HEALTH_CHECK_UDP: "UDP_CONNECT", -} - -type SLoadbalancer struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - subnet *SNetwork - eip *SEipAddress - - Description string `json:"description"` - ProvisioningStatus string `json:"provisioning_status"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - AdminStateUp bool `json:"admin_state_up"` - Provider string `json:"provider"` - Pools []Pool `json:"pools"` - Listeners []Listener `json:"listeners"` - VipPortID string `json:"vip_port_id"` - OperatingStatus string `json:"operating_status"` - VipAddress string `json:"vip_address"` - VipSubnetID string `json:"vip_subnet_id"` - ID string `json:"id"` - Name string `json:"name"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` -} - -type Listener struct { - ID string `json:"id"` -} - -type Pool struct { - ID string `json:"id"` -} - -func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { - if self.GetEip() == nil { - return nil, nil - } - - return self.eip, nil -} - -func (self *SLoadbalancer) GetId() string { - return self.ID -} - -func (self *SLoadbalancer) GetName() string { - return self.Name -} - -func (self *SLoadbalancer) GetGlobalId() string { - return self.ID -} - -func (self *SLoadbalancer) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancer) Refresh() error { - lb, err := self.region.GetLoadbalancer(self.GetId()) - if err != nil { - return err - } - - return jsonutils.Update(self, lb) -} - -func (self *SLoadbalancer) IsEmulated() bool { - return false -} - -func (self *SLoadbalancer) GetProjectId() string { - return self.ProjectID -} - -func (self *SLoadbalancer) GetAddress() string { - return self.VipAddress -} - -// todo: api.LB_ADDR_TYPE_INTERNET? -func (self *SLoadbalancer) GetAddressType() string { - return api.LB_ADDR_TYPE_INTRANET -} - -func (self *SLoadbalancer) GetNetworkType() string { - return api.LB_NETWORK_TYPE_VPC -} - -func (self *SLoadbalancer) GetNetworkIds() []string { - net := self.GetNetwork() - if net != nil { - return []string{net.GetId()} - } - - return []string{} -} - -func (self *SLoadbalancer) GetNetwork() *SNetwork { - if self.subnet == nil { - port, err := self.region.GetPort(self.VipPortID) - if err == nil { - net, err := self.region.getNetwork(port.NetworkID) - if err == nil { - self.subnet = net - } else { - log.Debugf("huawei.SLoadbalancer.getNetwork %s", err) - } - } else { - log.Debugf("huawei.SLoadbalancer.GetPort %s", err) - } - } - - return self.subnet -} - -func (self *SLoadbalancer) GetEip() *SEipAddress { - if self.eip == nil { - eips, _ := self.region.GetEips() - for i := range eips { - eip := &eips[i] - if eip.PortId == self.VipPortID { - self.eip = eip - } - } - } - - return self.eip -} - -func (self *SLoadbalancer) GetVpcId() string { - net := self.GetNetwork() - if net != nil { - return net.VpcID - } - - return "" -} - -func (self *SLoadbalancer) GetZoneId() string { - net := self.GetNetwork() - if net != nil { - z, err := self.region.getZoneById(net.AvailabilityZone) - if err != nil { - log.Infof("getZoneById %s %s", net.AvailabilityZone, err) - return "" - } - - return z.GetGlobalId() - } - - return "" -} - -func (self *SLoadbalancer) GetZone1Id() string { - return "" -} - -func (self *SLoadbalancer) GetLoadbalancerSpec() string { - return "" -} - -func (self *SLoadbalancer) GetChargeType() string { - eip := self.GetEip() - if eip != nil { - return eip.GetInternetChargeType() - } - - return api.EIP_CHARGE_TYPE_BY_TRAFFIC -} - -func (self *SLoadbalancer) GetEgressMbps() int { - eip := self.GetEip() - if eip != nil { - return eip.GetBandwidth() - } - - return 0 -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0141008275.html -func (self *SLoadbalancer) Delete(ctx context.Context) error { - return self.region.DeleteLoadBalancer(self.GetId()) -} - -func (self *SLoadbalancer) Start() error { - return nil -} - -func (self *SLoadbalancer) Stop() error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - ret, err := self.region.GetLoadBalancerListeners(self.GetId()) - if err != nil { - return nil, err - } - - iret := make([]cloudprovider.ICloudLoadbalancerListener, 0) - for i := range ret { - listener := ret[i] - listener.lb = self - iret = append(iret, &listener) - } - - return iret, nil -} - -func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - ret, err := self.region.GetLoadBalancerBackendGroups(self.GetId()) - if err != nil { - return nil, err - } - - iret := make([]cloudprovider.ICloudLoadbalancerBackendGroup, 0) - for i := range ret { - bg := ret[i] - bg.lb = self - iret = append(iret, &bg) - } - - return iret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561549.html -func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - ret, err := self.region.CreateLoadBalancerBackendGroup(group) - ret.lb = self - return &ret, err -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561563.html -func (self *SLoadbalancer) CreateHealthCheck(backendGroupId string, healthcheck *cloudprovider.SLoadbalancerHealthCheck) error { - _, err := self.region.CreateLoadBalancerHealthCheck(backendGroupId, healthcheck) - return err -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561548.html -func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - ret := &SElbBackendGroup{} - err := DoGet(self.region.ecsClient.ElbBackendGroup.Get, groupId, nil, ret) - if err != nil { - return nil, err - } - - ret.lb = self - ret.region = self.region - return ret, nil -} - -func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - ret, err := self.region.CreateLoadBalancerListener(listener) - if err != nil { - return nil, err - } - - ret.lb = self - return &ret, nil -} - -func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { - ret := &SElbListener{} - err := DoGet(self.region.ecsClient.ElbListeners.Get, listenerId, nil, ret) - if err != nil { - return nil, err - } - - ret.lb = self - return ret, nil -} - -func (self *SRegion) GetLoadbalancer(lgId string) (SLoadbalancer, error) { - elb := SLoadbalancer{} - err := DoGet(self.ecsClient.Elb.Get, lgId, nil, &elb) - if err != nil { - return elb, err - } - - return elb, nil -} - -func (self *SRegion) DeleteLoadBalancer(elbId string) error { - return DoDelete(self.ecsClient.Elb.Delete, elbId, nil, nil) -} - -func (self *SRegion) GetLoadBalancerListeners(lbId string) ([]SElbListener, error) { - params := map[string]string{} - if len(lbId) > 0 { - params["loadbalancer_id"] = lbId - } - - ret := make([]SElbListener, 0) - err := doListAll(self.ecsClient.ElbListeners.List, params, &ret) - if err != nil { - return nil, err - } - - return ret, nil -} - -func (self *SRegion) CreateLoadBalancerListener(listener *cloudprovider.SLoadbalancerListener) (SElbListener, error) { - params := jsonutils.NewDict() - listenerObj := jsonutils.NewDict() - listenerObj.Set("name", jsonutils.NewString(listener.Name)) - listenerObj.Set("description", jsonutils.NewString(listener.Description)) - listenerObj.Set("protocol", jsonutils.NewString(LB_PROTOCOL_MAP[listener.ListenerType])) - listenerObj.Set("protocol_port", jsonutils.NewInt(int64(listener.ListenerPort))) - listenerObj.Set("loadbalancer_id", jsonutils.NewString(listener.LoadbalancerID)) - listenerObj.Set("http2_enable", jsonutils.NewBool(listener.EnableHTTP2)) - if len(listener.BackendGroupID) > 0 { - listenerObj.Set("default_pool_id", jsonutils.NewString(listener.BackendGroupID)) - } - - if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { - listenerObj.Set("default_tls_container_ref", jsonutils.NewString(listener.CertificateID)) - } - - if listener.XForwardedFor { - insertObj := jsonutils.NewDict() - insertObj.Set("X-Forwarded-ELB-IP", jsonutils.NewBool(listener.XForwardedFor)) - listenerObj.Set("insert_headers", insertObj) - } - params.Set("listener", listenerObj) - ret := SElbListener{} - err := DoCreate(self.ecsClient.ElbListeners.Create, params, &ret) - if err != nil { - return ret, err - } - - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html -func (self *SRegion) GetLoadBalancerBackendGroups(elbId string) ([]SElbBackendGroup, error) { - params := map[string]string{} - if len(elbId) > 0 { - params["loadbalancer_id"] = elbId - } - - ret := make([]SElbBackendGroup, 0) - err := doListAll(self.ecsClient.ElbBackendGroup.List, params, &ret) - if err != nil { - return nil, err - } - - for i := range ret { - ret[i].region = self - } - - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html -func (self *SRegion) CreateLoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (SElbBackendGroup, error) { - ret := SElbBackendGroup{} - var protocol, scheduler string - if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { - return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) - } else { - scheduler = s - } - - if t, ok := LBBG_PROTOCOL_MAP[group.ListenType]; !ok { - return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported listener type %s", group.ListenType) - } else { - protocol = t - } - - params := jsonutils.NewDict() - poolObj := jsonutils.NewDict() - poolObj.Set("project_id", jsonutils.NewString(self.client.projectId)) - poolObj.Set("name", jsonutils.NewString(group.Name)) - poolObj.Set("protocol", jsonutils.NewString(protocol)) - poolObj.Set("lb_algorithm", jsonutils.NewString(scheduler)) - - if len(group.ListenerID) > 0 { - poolObj.Set("listener_id", jsonutils.NewString(group.ListenerID)) - } else if len(group.LoadbalancerID) > 0 { - poolObj.Set("loadbalancer_id", jsonutils.NewString(group.LoadbalancerID)) - } else { - return ret, fmt.Errorf("CreateLoadBalancerBackendGroup one of listener id / loadbalancer id must be specified") - } - - if group.StickySession != nil { - s := jsonutils.NewDict() - timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) - if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { - s.Set("type", jsonutils.NewString("SOURCE_IP")) - if timeout > 0 { - s.Set("persistence_timeout", jsonutils.NewInt(timeout)) - } - } else { - s.Set("type", jsonutils.NewString(LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType])) - if len(group.StickySession.StickySessionCookie) > 0 { - s.Set("cookie_name", jsonutils.NewString(group.StickySession.StickySessionCookie)) - } else { - if timeout > 0 { - s.Set("persistence_timeout", jsonutils.NewInt(timeout)) - } - } - } - - poolObj.Set("session_persistence", s) - } - params.Set("pool", poolObj) - err := DoCreate(self.ecsClient.ElbBackendGroup.Create, params, &ret) - if err != nil { - return ret, err - } - - if group.HealthCheck != nil { - _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) - if err != nil { - return ret, err - } - } - - ret.region = self - return ret, nil -} - -func (self *SRegion) CreateLoadBalancerHealthCheck(backendGroupID string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { - params := jsonutils.NewDict() - healthObj := jsonutils.NewDict() - healthObj.Set("delay", jsonutils.NewInt(int64(healthCheck.HealthCheckInterval))) - healthObj.Set("max_retries", jsonutils.NewInt(int64(healthCheck.HealthCheckRise))) - healthObj.Set("pool_id", jsonutils.NewString(backendGroupID)) - healthObj.Set("timeout", jsonutils.NewInt(int64(healthCheck.HealthCheckTimeout))) - healthObj.Set("type", jsonutils.NewString(LB_HEALTHCHECK_TYPE_MAP[healthCheck.HealthCheckType])) - if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { - if len(healthCheck.HealthCheckDomain) > 0 { - healthObj.Set("domain_name", jsonutils.NewString(healthCheck.HealthCheckDomain)) - } - - if len(healthCheck.HealthCheckURI) > 0 { - healthObj.Set("url_path", jsonutils.NewString(healthCheck.HealthCheckURI)) - } - - if len(healthCheck.HealthCheckHttpCode) > 0 { - healthObj.Set("expected_codes", jsonutils.NewString(ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode))) - } - } - params.Set("healthmonitor", healthObj) - - ret := SElbHealthCheck{} - err := DoCreate(self.ecsClient.ElbHealthCheck.Create, params, &ret) - if err != nil { - return ret, err - } - - ret.region = self - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561564.html -func (self *SRegion) UpdateLoadBalancerHealthCheck(healthCheckID string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { - params := jsonutils.NewDict() - healthObj := jsonutils.NewDict() - healthObj.Set("delay", jsonutils.NewInt(int64(healthCheck.HealthCheckInterval))) - healthObj.Set("max_retries", jsonutils.NewInt(int64(healthCheck.HealthCheckRise))) - healthObj.Set("timeout", jsonutils.NewInt(int64(healthCheck.HealthCheckTimeout))) - if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { - if len(healthCheck.HealthCheckDomain) > 0 { - healthObj.Set("domain_name", jsonutils.NewString(healthCheck.HealthCheckDomain)) - } - - if len(healthCheck.HealthCheckURI) > 0 { - healthObj.Set("url_path", jsonutils.NewString(healthCheck.HealthCheckURI)) - } - - if len(healthCheck.HealthCheckHttpCode) > 0 { - healthObj.Set("expected_codes", jsonutils.NewString(ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode))) - } - } - params.Set("healthmonitor", healthObj) - - ret := SElbHealthCheck{} - err := DoUpdate(self.ecsClient.ElbHealthCheck.Update, healthCheckID, params, &ret) - if err != nil { - return ret, err - } - - ret.region = self - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561565.html -func (self *SRegion) DeleteLoadbalancerHealthCheck(healthCheckID string) error { - return DoDelete(self.ecsClient.ElbHealthCheck.Delete, healthCheckID, nil, nil) -} - -func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/hcso/loadbalancer_acl.go b/pkg/multicloud/hcso/loadbalancer_acl.go deleted file mode 100644 index 43da0d0fbb..0000000000 --- a/pkg/multicloud/hcso/loadbalancer_acl.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "strings" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbACL struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - - ID string `json:"id"` - ListenerID string `json:"listener_id"` - TenantID string `json:"tenant_id"` - EnableWhitelist bool `json:"enable_whitelist"` - Whitelist string `json:"whitelist"` -} - -func (self *SElbACL) GetAclListenerID() string { - return self.ListenerID -} - -func (self *SElbACL) GetId() string { - return self.ID -} - -func (self *SElbACL) GetName() string { - return self.ID -} - -func (self *SElbACL) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbACL) GetStatus() string { - if self.EnableWhitelist { - return api.LB_BOOL_ON - } - - return api.LB_BOOL_OFF -} - -func (self *SElbACL) Refresh() error { - acl, err := self.region.GetLoadBalancerAclById(self.GetId()) - if err != nil { - return err - } - - err = jsonutils.Update(self, acl) - if err != nil { - return err - } - - return nil -} - -func (self *SElbACL) IsEmulated() bool { - return false -} - -func (self *SElbACL) GetProjectId() string { - return "" -} - -func (self *SElbACL) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { - ret := []cloudprovider.SLoadbalancerAccessControlListEntry{} - for _, cidr := range strings.Split(self.Whitelist, ",") { - ret = append(ret, cloudprovider.SLoadbalancerAccessControlListEntry{CIDR: cidr}) - } - - return ret -} - -func (self *SElbACL) Sync(acl *cloudprovider.SLoadbalancerAccessControlList) error { - whiteList := "" - cidrs := []string{} - for _, entry := range acl.Entrys { - cidrs = append(cidrs, entry.CIDR) - } - - whiteList = strings.Join(cidrs, ",") - - params := jsonutils.NewDict() - whiteListObj := jsonutils.NewDict() - whiteListObj.Set("whitelist", jsonutils.NewString(whiteList)) - whiteListObj.Set("enable_whitelist", jsonutils.NewBool(acl.AccessControlEnable)) - params.Set("whitelist", whiteListObj) - return DoUpdate(self.region.ecsClient.ElbWhitelist.Update, self.GetId(), params, nil) -} - -func (self *SElbACL) Delete() error { - return DoDelete(self.region.ecsClient.ElbWhitelist.Delete, self.GetId(), nil, nil) -} diff --git a/pkg/multicloud/hcso/loadbalancer_backend.go b/pkg/multicloud/hcso/loadbalancer_backend.go deleted file mode 100644 index a7fef32f3a..0000000000 --- a/pkg/multicloud/hcso/loadbalancer_backend.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbBackend struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - lb *SLoadbalancer - backendGroup *SElbBackendGroup - - Name string `json:"name"` - Weight int `json:"weight"` - AdminStateUp bool `json:"admin_state_up"` - SubnetID string `json:"subnet_id"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - Address string `json:"address"` - ProtocolPort int `json:"protocol_port"` - OperatingStatus string `json:"operating_status"` - ID string `json:"id"` -} - -func (self *SElbBackend) GetId() string { - return self.ID -} - -func (self *SElbBackend) GetName() string { - return self.Name -} - -func (self *SElbBackend) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbBackend) Refresh() error { - m := self.lb.region.ecsClient.ElbBackend - err := m.SetBackendGroupId(self.backendGroup.GetId()) - if err != nil { - return err - } - - backend := SElbBackend{} - err = DoGet(m.Get, self.GetId(), nil, &backend) - if err != nil { - return err - } - - backend.lb = self.lb - backend.backendGroup = self.backendGroup - err = jsonutils.Update(self, backend) - if err != nil { - return err - } - - return nil -} - -func (self *SElbBackend) IsEmulated() bool { - return false -} - -func (self *SElbBackend) GetProjectId() string { - return "" -} - -func (self *SElbBackend) GetWeight() int { - return self.Weight -} - -func (self *SElbBackend) GetPort() int { - return self.ProtocolPort -} - -func (self *SElbBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (self *SElbBackend) GetBackendRole() string { - return api.LB_BACKEND_ROLE_DEFAULT -} - -func (self *SElbBackend) GetBackendId() string { - i, err := self.lb.region.getInstanceByIP(self.Address) - if err != nil { - log.Errorf("ElbBackend GetBackendId %s", err) - } - - if i != nil { - return i.GetId() - } - - return "" -} - -func (self *SElbBackend) GetIpAddress() string { - return "" -} - -func (self *SElbBackend) SyncConf(ctx context.Context, port, weight int) error { - if port > 0 { - log.Warningf("Elb backend SyncConf unsupport modify port") - } - - params := jsonutils.NewDict() - memberObj := jsonutils.NewDict() - memberObj.Set("weight", jsonutils.NewInt(int64(weight))) - params.Set("member", memberObj) - err := self.lb.region.ecsClient.ElbBackend.SetBackendGroupId(self.backendGroup.GetId()) - if err != nil { - return err - } - return DoUpdate(self.lb.region.ecsClient.ElbBackend.Update, self.GetId(), params, nil) -} - -func (self *SRegion) getInstanceByIP(privateIP string) (*SInstance, error) { - queries := make(map[string]string) - - if len(self.client.projectId) > 0 { - queries["project_id"] = self.client.projectId - } - - if len(privateIP) > 0 { - queries["ip"] = privateIP - } - - instances := make([]SInstance, 0) - err := doListAllWithOffset(self.ecsClient.Servers.List, queries, &instances) - if err != nil { - return nil, err - } - - if len(instances) == 1 { - return &instances[0], nil - } else if len(instances) > 1 { - log.Warningf("SRegion.getInstanceByIP %s result: multiple server find", privateIP) - return &instances[0], nil - } - - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/hcso/loadbalancer_backendgroup.go b/pkg/multicloud/hcso/loadbalancer_backendgroup.go deleted file mode 100644 index e5ea22f95a..0000000000 --- a/pkg/multicloud/hcso/loadbalancer_backendgroup.go +++ /dev/null @@ -1,541 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbBackendGroup struct { - multicloud.SResourceBase - multicloud.HuaweiTags - lb *SLoadbalancer - region *SRegion - - LBAlgorithm string `json:"lb_algorithm"` - Protocol string `json:"protocol"` - Description string `json:"description"` - AdminStateUp bool `json:"admin_state_up"` - Loadbalancers []Listener `json:"loadbalancers"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - Listeners []Listener `json:"listeners"` - ID string `json:"id"` - Name string `json:"name"` - HealthMonitorID string `json:"healthmonitor_id"` - SessionPersistence StickySession `json:"session_persistence"` -} - -func (self *SElbBackendGroup) GetLoadbalancerId() string { - return self.lb.GetId() -} - -func (self *SElbBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { - return self.lb -} - -type StickySession struct { - Type string `json:"type"` - CookieName string `json:"cookie_name"` - PersistenceTimeout int `json:"persistence_timeout"` -} - -func (self *SElbBackendGroup) GetProtocolType() string { - switch self.Protocol { - case "TCP": - return api.LB_LISTENER_TYPE_TCP - case "UDP": - return api.LB_LISTENER_TYPE_UDP - case "HTTP": - return api.LB_LISTENER_TYPE_HTTP - default: - return "" - } -} - -func (self *SElbBackendGroup) GetScheduler() string { - switch self.LBAlgorithm { - case "ROUND_ROBIN": - return api.LB_SCHEDULER_WRR - case "LEAST_CONNECTIONS": - return api.LB_SCHEDULER_WLC - case "SOURCE_IP": - return api.LB_SCHEDULER_SCH - default: - return "" - } -} - -func ToHuaweiHealthCheckHttpCode(c string) string { - c = strings.TrimSpace(c) - segs := strings.Split(c, ",") - ret := []string{} - for _, seg := range segs { - seg = strings.TrimLeft(seg, "http_") - seg = strings.TrimSpace(seg) - seg = strings.Replace(seg, "xx", "00", -1) - ret = append(ret, seg) - } - - return strings.Join(ret, ",") -} - -func ToOnecloudHealthCheckHttpCode(c string) string { - c = strings.TrimSpace(c) - segs := strings.Split(c, ",") - ret := []string{} - for _, seg := range segs { - seg = strings.TrimSpace(seg) - seg = strings.Replace(seg, "00", "xx", -1) - seg = "http_" + seg - ret = append(ret, seg) - } - - return strings.Join(ret, ",") -} - -func (self *SElbBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - if len(self.HealthMonitorID) == 0 { - return nil, nil - } - - health, err := self.region.GetLoadBalancerHealthCheck(self.HealthMonitorID) - if err != nil { - return nil, err - } - - var healthCheckType string - switch health.Type { - case "TCP": - healthCheckType = api.LB_HEALTH_CHECK_TCP - case "UDP_CONNECT": - healthCheckType = api.LB_HEALTH_CHECK_UDP - case "HTTP": - healthCheckType = api.LB_HEALTH_CHECK_HTTP - default: - healthCheckType = "" - } - - ret := cloudprovider.SLoadbalancerHealthCheck{ - HealthCheckType: healthCheckType, - HealthCheckTimeout: health.Timeout, - HealthCheckDomain: health.DomainName, - HealthCheckURI: health.URLPath, - HealthCheckInterval: health.Delay, - HealthCheckRise: health.MaxRetries, - HealthCheckHttpCode: ToOnecloudHealthCheckHttpCode(health.ExpectedCodes), - } - - return &ret, nil -} - -func (self *SElbBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - if len(self.SessionPersistence.Type) == 0 { - return nil, nil - } - - var stickySessionType string - switch self.SessionPersistence.Type { - case "SOURCE_IP": - stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT - case "HTTP_COOKIE": - stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT - case "APP_COOKIE": - stickySessionType = api.LB_STICKY_SESSION_TYPE_SERVER - } - - ret := cloudprovider.SLoadbalancerStickySession{ - StickySession: api.LB_BOOL_ON, - StickySessionCookie: self.SessionPersistence.CookieName, - StickySessionType: stickySessionType, - StickySessionCookieTimeout: self.SessionPersistence.PersistenceTimeout * 60, - } - - return &ret, nil -} - -func (self *SElbBackendGroup) GetId() string { - return self.ID -} - -func (self *SElbBackendGroup) GetName() string { - return self.Name -} - -func (self *SElbBackendGroup) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbBackendGroup) Refresh() error { - ret, err := self.lb.region.GetLoadBalancerBackendGroupId(self.GetId()) - if err != nil { - return err - } - ret.lb = self.lb - - err = jsonutils.Update(self, ret) - if err != nil { - return err - } - - return nil -} - -func (self *SElbBackendGroup) IsEmulated() bool { - return false -} - -func (self *SElbBackendGroup) GetProjectId() string { - return self.ProjectID -} - -func (self *SElbBackendGroup) IsDefault() bool { - return false -} - -func (self *SElbBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_NORMAL -} - -func (self *SElbBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - ret, err := self.region.GetLoadBalancerBackends(self.GetId()) - if err != nil { - return nil, err - } - - iret := []cloudprovider.ICloudLoadbalancerBackend{} - for i := range ret { - backend := ret[i] - backend.lb = self.lb - backend.backendGroup = self - - iret = append(iret, &backend) - } - - return iret, nil -} - -func (self *SElbBackendGroup) GetILoadbalancerBackendById(serverId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - m := self.lb.region.ecsClient.ElbBackend - err := m.SetBackendGroupId(self.GetId()) - if err != nil { - return nil, err - } - - backend := SElbBackend{} - err = DoGet(m.Get, serverId, nil, &backend) - if err != nil { - return nil, err - } - - backend.lb = self.lb - backend.backendGroup = self - return &backend, nil -} - -func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - instance, err := self.lb.region.GetInstanceByID(serverId) - if err != nil { - return nil, err - } - - nics, err := instance.GetINics() - if err != nil { - return nil, err - } else if len(nics) == 0 { - return nil, fmt.Errorf("AddBackendServer %s no network interface found", serverId) - } - - subnets, err := self.lb.region.getSubnetIdsByInstanceId(instance.GetId()) - if err != nil { - return nil, err - } else if len(subnets) == 0 { - return nil, fmt.Errorf("AddBackendServer %s no subnet found", serverId) - } - - net, err := self.lb.region.getNetwork(subnets[0]) - if err != nil { - return nil, err - } - - backend, err := self.region.AddLoadBalancerBackend(self.GetId(), net.NeutronSubnetID, nics[0].GetIP(), port, weight) - if err != nil { - return nil, err - } - - backend.lb = self.lb - backend.backendGroup = self - return &backend, nil -} - -func (self *SElbBackendGroup) RemoveBackendServer(backendId string, weight int, port int) error { - ibackend, err := self.GetILoadbalancerBackendById(backendId) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - - return errors.Wrap(err, "ElbBackendGroup.GetILoadbalancerBackendById") - } - - err = self.region.RemoveLoadBalancerBackend(self.GetId(), backendId) - if err != nil { - return errors.Wrap(err, "ElbBackendGroup.RemoveBackendServer") - } - - return cloudprovider.WaitDeleted(ibackend, 2*time.Second, 30*time.Second) -} - -func (self *SElbBackendGroup) Delete(ctx context.Context) error { - if len(self.HealthMonitorID) > 0 { - err := self.region.DeleteLoadbalancerHealthCheck(self.HealthMonitorID) - if err != nil { - return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadbalancerHealthCheck") - } - } - - // 删除后端服务器组的同时,删除掉无效的后端服务器数据 - { - backends, err := self.region.getLoadBalancerAdminStateDownBackends(self.GetId()) - if err != nil { - return errors.Wrap(err, "SElbBackendGroup.Delete.getLoadBalancerAdminStateDownBackends") - } - - for i := range backends { - backend := backends[i] - err := self.RemoveBackendServer(backend.GetId(), backend.GetPort(), backend.GetWeight()) - if err != nil { - return errors.Wrap(err, "SElbBackendGroup.Delete.RemoveBackendServer") - } - } - } - - err := self.region.DeleteLoadBalancerBackendGroup(self.GetId()) - if err != nil { - return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadBalancerBackendGroup") - } - - return cloudprovider.WaitDeleted(self, 2*time.Second, 30*time.Second) -} - -func (self *SElbBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - if group == nil { - return nil - } - - _, err := self.region.UpdateLoadBalancerBackendGroup(self.GetId(), group) - return err -} - -func (self *SRegion) GetLoadBalancerBackendGroupId(backendGroupId string) (SElbBackendGroup, error) { - ret := SElbBackendGroup{} - err := DoGet(self.ecsClient.ElbBackendGroup.Get, backendGroupId, nil, &ret) - if err != nil { - return ret, err - } - - ret.region = self - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561550.html -func (self *SRegion) UpdateLoadBalancerBackendGroup(backendGroupID string, group *cloudprovider.SLoadbalancerBackendGroup) (SElbBackendGroup, error) { - params := jsonutils.NewDict() - poolObj := jsonutils.NewDict() - poolObj.Set("name", jsonutils.NewString(group.Name)) - var scheduler string - if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { - return SElbBackendGroup{}, fmt.Errorf("UpdateLoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) - } else { - scheduler = s - } - poolObj.Set("lb_algorithm", jsonutils.NewString(scheduler)) - - if group.StickySession == nil || group.StickySession.StickySession == api.LB_BOOL_OFF { - poolObj.Set("session_persistence", jsonutils.JSONNull) - } else { - s := jsonutils.NewDict() - timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) - if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { - s.Set("type", jsonutils.NewString("SOURCE_IP")) - if timeout > 0 { - s.Set("persistence_timeout", jsonutils.NewInt(timeout)) - } - } else { - s.Set("type", jsonutils.NewString(LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType])) - if len(group.StickySession.StickySessionCookie) > 0 { - s.Set("cookie_name", jsonutils.NewString(group.StickySession.StickySessionCookie)) - } else { - if timeout > 0 { - s.Set("persistence_timeout", jsonutils.NewInt(timeout)) - } - } - } - - poolObj.Set("session_persistence", s) - } - params.Set("pool", poolObj) - - ret := SElbBackendGroup{} - err := DoUpdate(self.ecsClient.ElbBackendGroup.Update, backendGroupID, params, &ret) - if err != nil { - return ret, errors.Wrap(err, "ElbBackendGroup.Update") - } - - if group.HealthCheck == nil && len(ret.HealthMonitorID) > 0 { - err := self.DeleteLoadbalancerHealthCheck(ret.HealthMonitorID) - if err != nil { - return ret, errors.Wrap(err, "DeleteLoadbalancerHealthCheck") - } - } - - if group.HealthCheck != nil { - if len(ret.HealthMonitorID) == 0 { - _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) - if err != nil { - return ret, errors.Wrap(err, "CreateLoadBalancerHealthCheck") - } - } else { - _, err := self.UpdateLoadBalancerHealthCheck(ret.HealthMonitorID, group.HealthCheck) - if err != nil { - return ret, errors.Wrap(err, "UpdateLoadBalancerHealthCheck") - } - } - } - - ret.region = self - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561551.html -func (self *SRegion) DeleteLoadBalancerBackendGroup(backendGroupID string) error { - return DoDelete(self.ecsClient.ElbBackendGroup.Delete, backendGroupID, nil, nil) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561556.html -func (self *SRegion) AddLoadBalancerBackend(backendGroupId, subnetId, ipaddr string, port, weight int) (SElbBackend, error) { - backend := SElbBackend{} - params := jsonutils.NewDict() - memberObj := jsonutils.NewDict() - memberObj.Set("address", jsonutils.NewString(ipaddr)) - memberObj.Set("protocol_port", jsonutils.NewInt(int64(port))) - memberObj.Set("subnet_id", jsonutils.NewString(subnetId)) - memberObj.Set("weight", jsonutils.NewInt(int64(weight))) - params.Set("member", memberObj) - - m := self.ecsClient.ElbBackend - err := m.SetBackendGroupId(backendGroupId) - if err != nil { - return backend, err - } - - err = DoCreate(m.Create, params, &backend) - if err != nil { - return backend, err - } - - return backend, nil -} - -func (self *SRegion) RemoveLoadBalancerBackend(lbbgId string, backendId string) error { - m := self.ecsClient.ElbBackend - err := m.SetBackendGroupId(lbbgId) - if err != nil { - return err - } - - return DoDelete(m.Delete, backendId, nil, nil) -} - -func (self *SRegion) getLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { - m := self.ecsClient.ElbBackend - err := m.SetBackendGroupId(backendGroupId) - if err != nil { - return nil, err - } - - ret := []SElbBackend{} - err = doListAll(m.List, nil, &ret) - if err != nil { - return nil, err - } - - for i := range ret { - backend := ret[i] - backend.region = self - } - - return ret, nil -} - -func (self *SRegion) GetLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { - ret, err := self.getLoadBalancerBackends(backendGroupId) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetLoadBalancerBackends.getLoadBalancerBackends") - } - - // 过滤掉服务器已经被删除的backend。原因是运管平台查询不到已删除的服务器记录,导致同步出错。产生肮数据。 - filtedRet := []SElbBackend{} - for i := range ret { - if ret[i].AdminStateUp { - backend := ret[i] - filtedRet = append(filtedRet, backend) - } - } - - return filtedRet, nil -} - -func (self *SRegion) getLoadBalancerAdminStateDownBackends(backendGroupId string) ([]SElbBackend, error) { - ret, err := self.getLoadBalancerBackends(backendGroupId) - if err != nil { - return nil, errors.Wrap(err, "SRegion.getLoadBalancerAdminStateDownBackends.getLoadBalancerBackends") - } - - filtedRet := []SElbBackend{} - for i := range ret { - if !ret[i].AdminStateUp { - backend := ret[i] - filtedRet = append(filtedRet, backend) - } - } - - return filtedRet, nil -} - -func (self *SRegion) GetLoadBalancerHealthCheck(healthCheckId string) (SElbHealthCheck, error) { - ret := SElbHealthCheck{} - err := DoGet(self.ecsClient.ElbHealthCheck.Get, healthCheckId, nil, &ret) - if err != nil { - return ret, err - } - - ret.region = self - return ret, nil -} diff --git a/pkg/multicloud/hcso/loadbalancer_cert.go b/pkg/multicloud/hcso/loadbalancer_cert.go deleted file mode 100644 index 25f94b651b..0000000000 --- a/pkg/multicloud/hcso/loadbalancer_cert.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "crypto/sha1" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbCert struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - - Certificate string `json:"certificate"` - CreateTime time.Time `json:"create_time"` - ExpireTime time.Time `json:"expire_time"` - Description string `json:"description"` - Domain string `json:"domain"` - ID string `json:"id"` - AdminStateUp bool `json:"admin_state_up"` - TenantID string `json:"tenant_id"` - Name string `json:"name"` - PrivateKey string `json:"private_key"` - Type string `json:"type"` - UpdateTime time.Time `json:"update_time"` -} - -func (self *SElbCert) GetPublickKey() string { - return self.Certificate -} - -func (self *SElbCert) GetPrivateKey() string { - return self.PrivateKey -} - -func (self *SElbCert) GetId() string { - return self.ID -} - -func (self *SElbCert) GetName() string { - return self.Name -} - -func (self *SElbCert) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbCert) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbCert) Refresh() error { - cert, err := self.region.GetLoadBalancerCertificateById(self.GetId()) - if err != nil { - return err - } - - cert.region = self.region - err = jsonutils.Update(self, cert) - if err != nil { - return err - } - - return nil -} - -func (self *SElbCert) IsEmulated() bool { - return false -} - -func (self *SElbCert) GetProjectId() string { - return "" -} - -func (self *SElbCert) Sync(name, privateKey, publickKey string) error { - params := jsonutils.NewDict() - params.Set("name", jsonutils.NewString(name)) - params.Set("private_key", jsonutils.NewString(privateKey)) - params.Set("certificate", jsonutils.NewString(publickKey)) - return DoUpdate(self.region.ecsClient.ElbCertificates.Update, self.GetId(), params, nil) -} - -func (self *SElbCert) Delete() error { - return DoDelete(self.region.ecsClient.ElbCertificates.Delete, self.GetId(), nil, nil) -} - -func (self *SElbCert) GetCommonName() string { - return self.Domain -} - -func (self *SElbCert) GetSubjectAlternativeNames() string { - return self.Domain -} - -func (self *SElbCert) GetFingerprint() string { - _fp := sha1.Sum([]byte(self.Certificate)) - fp := fmt.Sprintf("sha1:% x", _fp) - return strings.Replace(fp, " ", ":", -1) -} - -func (self *SElbCert) GetExpireTime() time.Time { - return self.ExpireTime -} diff --git a/pkg/multicloud/hcso/loadbalancer_listener.go b/pkg/multicloud/hcso/loadbalancer_listener.go deleted file mode 100644 index 17a7c816c3..0000000000 --- a/pkg/multicloud/hcso/loadbalancer_listener.go +++ /dev/null @@ -1,694 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type InsertHeaders struct { - XForwardedELBIP bool `json:"X-Forwarded-ELB-IP"` -} - -type Loadbalancer struct { - ID string `json:"id"` -} - -type SElbListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.HuaweiTags - lb *SLoadbalancer - acl *SElbACL - backendgroup *SElbBackendGroup - - ProtocolPort int `json:"protocol_port"` - Protocol string `json:"protocol"` - Description string `json:"description"` - AdminStateUp bool `json:"admin_state_up"` - Http2Enable bool `json:"http2_enable"` - Loadbalancers []Loadbalancer `json:"loadbalancers"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - ConnectionLimit int `json:"connection_limit"` - DefaultPoolID string `json:"default_pool_id"` - ID string `json:"id"` - Name string `json:"name"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - InsertHeaders InsertHeaders `json:"insert_headers"` - DefaultTlsContainerRef string `json:"default_tls_container_ref"` -} - -func (self *SElbListener) GetId() string { - return self.ID -} - -func (self *SElbListener) GetName() string { - return self.Name -} - -func (self *SElbListener) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbListener) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbListener) Refresh() error { - ilistener, err := self.lb.GetILoadBalancerListenerById(self.GetId()) - if err != nil { - return err - } - - listener := ilistener.(*SElbListener) - listener.lb = self.lb - err = jsonutils.Update(self, listener) - if err != nil { - return err - } - - return nil -} - -func (self *SElbListener) IsEmulated() bool { - return false -} - -func (self *SElbListener) GetProjectId() string { - return self.ProjectID -} - -func (self *SElbListener) GetListenerType() string { - switch self.Protocol { - case "TCP": - return api.LB_LISTENER_TYPE_TCP - case "UDP": - return api.LB_LISTENER_TYPE_UDP - case "HTTP": - return api.LB_LISTENER_TYPE_HTTP - case "TERMINATED_HTTPS": - return api.LB_LISTENER_TYPE_HTTPS - case "HTTPS": - return api.LB_LISTENER_TYPE_HTTPS - default: - return "" - } -} - -func (self *SElbListener) GetListenerPort() int { - return self.ProtocolPort -} - -func (self *SElbListener) GetBackendGroup() (*SElbBackendGroup, error) { - if self.backendgroup == nil { - lbbgId := self.GetBackendGroupId() - if len(lbbgId) > 0 { - lbbg, err := self.lb.GetILoadBalancerBackendGroupById(lbbgId) - if err != nil { - return nil, err - } - - self.backendgroup = lbbg.(*SElbBackendGroup) - } - } - - return self.backendgroup, nil -} - -func (self *SElbListener) GetScheduler() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetScheduler %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - return lbbg.GetScheduler() -} - -func (self *SElbListener) GetAcl() (*SElbACL, error) { - if self.acl != nil { - return self.acl, nil - } - - acls, err := self.lb.region.GetLoadBalancerAcls(self.GetId()) - if err != nil { - return nil, err - } - - if len(acls) == 0 { - return nil, nil - } else { - self.acl = &acls[0] - return &acls[0], nil - } -} - -func (self *SElbListener) GetAclStatus() string { - acl, err := self.GetAcl() - if err != nil { - log.Debugf("GetAclStatus %s", err) - return "" - } - - if acl != nil && acl.EnableWhitelist { - return api.LB_BOOL_ON - } - - return api.LB_BOOL_OFF -} - -func (self *SElbListener) GetAclType() string { - return api.LB_ACL_TYPE_WHITE -} - -func (self *SElbListener) GetAclId() string { - acl, err := self.GetAcl() - if err != nil { - log.Debugf("GetAclStatus %s", err) - return "" - } - - if acl == nil { - return "" - } - - return acl.GetId() -} - -func (self *SElbListener) GetEgressMbps() int { - return 0 -} - -func (self *SElbListener) GetHealthCheck() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheck %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheck %s", err.Error()) - } - - if health != nil { - return api.LB_BOOL_ON - } else { - return api.LB_BOOL_OFF - } -} - -func (self *SElbListener) GetHealthCheckType() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) - } - - if health != nil { - return health.HealthCheckType - } - - return "" -} - -func (self *SElbListener) GetHealthCheckTimeout() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) - } - - if health != nil { - return health.HealthCheckTimeout - } - - return 0 -} - -func (self *SElbListener) GetHealthCheckInterval() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) - } - - if health != nil { - return health.HealthCheckInterval - } - - return 0 -} - -func (self *SElbListener) GetHealthCheckRise() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) - } - - if health != nil { - return health.HealthCheckRise - } else { - return 0 - } -} - -func (self *SElbListener) GetHealthCheckFail() int { - return 0 -} - -func (self *SElbListener) GetHealthCheckReq() string { - return "" -} - -func (self *SElbListener) GetHealthCheckExp() string { - return "" -} - -func (self *SElbListener) GetBackendGroupId() string { - return self.DefaultPoolID -} - -func (self *SElbListener) GetBackendServerPort() int { - return 0 -} - -func (self *SElbListener) GetHealthCheckDomain() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) - } - - if health != nil { - return health.HealthCheckDomain - } - - return "" -} - -func (self *SElbListener) GetHealthCheckURI() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) - } - - if health != nil { - return health.HealthCheckURI - } - - return "" -} - -func (self *SElbListener) GetHealthCheckCode() string { - return "" -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html -func (self *SElbListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - l7policy, err := self.lb.region.CreateLoadBalancerPolicy(self.GetId(), rule) - if err != nil { - return nil, err - } - - l7policy.region = self.lb.region - l7policy.lb = self.lb - l7policy.listener = self - return &l7policy, nil -} - -func (self *SElbListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - ret := &SElbListenerPolicy{} - err := DoGet(self.lb.region.ecsClient.ElbL7policies.Get, ruleId, nil, ret) - if err != nil { - return nil, err - } - - ret.region = self.lb.region - ret.lb = self.lb - ret.listener = self - return ret, nil -} - -func (self *SElbListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - ret, err := self.lb.region.GetLoadBalancerPolicies(self.GetId()) - if err != nil { - return nil, err - } - - iret := []cloudprovider.ICloudLoadbalancerListenerRule{} - for i := range ret { - rule := ret[i] - rule.listener = self - rule.lb = self.lb - iret = append(iret, &rule) - } - - return iret, nil -} - -func (self *SElbListener) GetStickySession() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySession %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySession %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySession - } - - return "" -} - -func (self *SElbListener) GetStickySessionType() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySessionType %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySessionType %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySessionType - } - - return "" -} - -func (self *SElbListener) GetStickySessionCookie() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySessionCookie - } - - return "" -} - -func (self *SElbListener) GetStickySessionCookieTimeout() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySessionCookieTimeout - } - - return 0 -} - -func (self *SElbListener) XForwardedForEnabled() bool { - return self.InsertHeaders.XForwardedELBIP -} - -func (self *SElbListener) GzipEnabled() bool { - return false -} - -func (self *SElbListener) GetCertificateId() string { - return self.DefaultTlsContainerRef -} - -func (self *SElbListener) GetTLSCipherPolicy() string { - return "" -} - -func (self *SElbListener) HTTP2Enabled() bool { - return self.Http2Enable -} - -func (self *SElbListener) Start() error { - return nil -} - -func (self *SElbListener) Stop() error { - return cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561544.html -/* -default_pool_id有如下限制: -不能更新为其他监听器的default_pool。 -不能更新为其他监听器的关联的转发策略所使用的pool。 -default_pool_id对应的后端云服务器组的protocol和监听器的protocol有如下关系: -监听器的protocol为TCP时,后端云服务器组的protocol必须为TCP。 -监听器的protocol为UDP时,后端云服务器组的protocol必须为UDP。 -监听器的protocol为HTTP或TERMINATED_HTTPS时,后端云服务器组的protocol必须为HTTP。 -*/ -func (self *SElbListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { - return self.lb.region.UpdateLoadBalancerListener(self.GetId(), listener) -} - -func (self *SElbListener) Delete(ctx context.Context) error { - err := DoDelete(self.lb.region.ecsClient.ElbListeners.Delete, self.GetId(), nil, nil) - if err != nil { - return err - } - - return nil -} - -func (self *SRegion) UpdateLoadBalancerListener(listenerId string, listener *cloudprovider.SLoadbalancerListener) error { - params := jsonutils.NewDict() - listenerObj := jsonutils.NewDict() - listenerObj.Set("name", jsonutils.NewString(listener.Name)) - listenerObj.Set("description", jsonutils.NewString(listener.Description)) - listenerObj.Set("http2_enable", jsonutils.NewBool(listener.EnableHTTP2)) - if len(listener.BackendGroupID) > 0 { - listenerObj.Set("default_pool_id", jsonutils.NewString(listener.BackendGroupID)) - } else { - listenerObj.Set("default_pool_id", jsonutils.JSONNull) - } - - if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { - listenerObj.Set("default_tls_container_ref", jsonutils.NewString(listener.CertificateID)) - } - - if listener.XForwardedFor { - insertObj := jsonutils.NewDict() - insertObj.Set("X-Forwarded-ELB-IP", jsonutils.NewBool(listener.XForwardedFor)) - listenerObj.Set("insert_headers", insertObj) - } - - params.Set("listener", listenerObj) - err := DoUpdate(self.ecsClient.ElbListeners.Update, listenerId, params, nil) - if err != nil { - return err - } - return nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295315.html -func (self *SRegion) GetLoadBalancerPolicies(listenerId string) ([]SElbListenerPolicy, error) { - params := map[string]string{} - if len(listenerId) > 0 { - params["listener_id"] = listenerId - } - - ret := []SElbListenerPolicy{} - err := doListAll(self.ecsClient.ElbL7policies.List, params, &ret) - if err != nil { - return nil, err - } - - for i := range ret { - ret[i].region = self - } - - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0116649234.html -func (self *SRegion) GetLoadBalancerPolicyRules(policyId string) ([]SElbListenerPolicyRule, error) { - m := self.ecsClient.ElbPolicies - err := m.SetL7policyId(policyId) - if err != nil { - return nil, err - } - - ret := []SElbListenerPolicyRule{} - err = doListAll(m.List, nil, &ret) - if err != nil { - return nil, err - } - - for i := range ret { - ret[i].region = self - } - - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html -func (self *SRegion) CreateLoadBalancerPolicy(listenerID string, rule *cloudprovider.SLoadbalancerListenerRule) ( - SElbListenerPolicy, error) { - l7policy := SElbListenerPolicy{} - params := jsonutils.NewDict() - policyObj := jsonutils.NewDict() - policyObj.Set("name", jsonutils.NewString(rule.Name)) - policyObj.Set("listener_id", jsonutils.NewString(listenerID)) - // todo: REDIRECT_TO_LISTENER? - policyObj.Set("action", jsonutils.NewString("REDIRECT_TO_POOL")) - policyObj.Set("redirect_pool_id", jsonutils.NewString(rule.BackendGroupID)) - params.Set("l7policy", policyObj) - - err := DoCreate(self.ecsClient.ElbL7policies.Create, params, &l7policy) - if err != nil { - return l7policy, err - } - - m := self.ecsClient.ElbPolicies - m.SetL7policyId(l7policy.GetId()) - if len(rule.Domain) > 0 { - p := jsonutils.NewDict() - p.Set("type", jsonutils.NewString("HOST_NAME")) - p.Set("value", jsonutils.NewString(rule.Domain)) - // todo: support more compare_type - p.Set("compare_type", jsonutils.NewString("EQUAL_TO")) - rule := jsonutils.NewDict() - rule.Set("rule", p) - err := DoCreate(m.Create, rule, nil) - if err != nil { - return l7policy, err - } - } - - if len(rule.Path) > 0 { - p := jsonutils.NewDict() - p.Set("type", jsonutils.NewString("PATH")) - p.Set("value", jsonutils.NewString(rule.Path)) - p.Set("compare_type", jsonutils.NewString("EQUAL_TO")) - rule := jsonutils.NewDict() - rule.Set("rule", p) - err := DoCreate(m.Create, rule, nil) - if err != nil { - return l7policy, err - } - } - - return l7policy, nil -} - -func (self *SElbListener) GetClientIdleTimeout() int { - return 0 -} - -func (self *SElbListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/hcso/loadbalancer_listener_rule.go b/pkg/multicloud/hcso/loadbalancer_listener_rule.go deleted file mode 100644 index ccc7ffdfcd..0000000000 --- a/pkg/multicloud/hcso/loadbalancer_listener_rule.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbListenerPolicy struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.HuaweiTags - region *SRegion - lb *SLoadbalancer - listener *SElbListener - - RedirectPoolID string `json:"redirect_pool_id"` - RedirectListenerID *string `json:"redirect_listener_id"` - Description string `json:"description"` - AdminStateUp bool `json:"admin_state_up"` - Rules []Rule `json:"rules"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - ListenerID string `json:"listener_id"` - RedirectURL *string `json:"redirect_url"` - ProvisioningStatus string `json:"provisioning_status"` - Action string `json:"action"` - Position int64 `json:"position"` - ID string `json:"id"` - Name string `json:"name"` -} - -type Rule struct { - ID string `json:"id"` -} - -type SElbListenerPolicyRule struct { - region *SRegion - policy *SElbListenerPolicy - - CompareType string `json:"compare_type"` - ProvisioningStatus string `json:"provisioning_status"` - AdminStateUp bool `json:"admin_state_up"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - Invert bool `json:"invert"` - Value string `json:"value"` - Key interface{} `json:"key"` - Type string `json:"type"` - ID string `json:"id"` -} - -func (self *SElbListenerPolicy) GetId() string { - return self.ID -} - -func (self *SElbListenerPolicy) GetName() string { - return self.Name -} - -func (self *SElbListenerPolicy) GetGlobalId() string { - return self.GetId() -} - -// 负载均衡没有启用禁用操作 -func (self *SElbListenerPolicy) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbListenerPolicy) Refresh() error { - ret := &SElbListenerPolicy{} - err := DoGet(self.lb.region.ecsClient.ElbL7policies.Get, self.GetId(), nil, ret) - if err != nil { - return err - } - - err = jsonutils.Update(self, ret) - if err != nil { - return err - } - - return nil -} - -func (self *SElbListenerPolicy) IsDefault() bool { - return false -} - -func (self *SElbListenerPolicy) IsEmulated() bool { - return false -} - -func (self *SElbListenerPolicy) GetProjectId() string { - return "" -} - -func (self *SElbListenerPolicy) GetRules() ([]SElbListenerPolicyRule, error) { - ret, err := self.region.GetLoadBalancerPolicyRules(self.GetId()) - if err != nil { - return nil, err - } - - for i := range ret { - ret[i].policy = self - } - - return ret, nil -} - -func (self *SElbListenerPolicy) GetDomain() string { - rules, err := self.GetRules() - if err != nil { - log.Errorf("loadbalancer rule GetDomain %s", err) - } - - for i := range rules { - if rules[i].Type == "HOST_NAME" { - return rules[i].Value - } - } - - return "" -} - -func (self *SElbListenerPolicy) GetCondition() string { - return "" -} - -func (self *SElbListenerPolicy) GetPath() string { - rules, err := self.GetRules() - if err != nil { - log.Errorf("loadbalancer rule GetPath %s", err) - } - - for i := range rules { - if rules[i].Type == "PATH" { - return rules[i].Value - } - } - - return "" -} - -func (self *SElbListenerPolicy) GetBackendGroupId() string { - return self.RedirectPoolID -} - -func (self *SElbListenerPolicy) Delete(ctx context.Context) error { - return self.region.DeleteLoadBalancerPolicy(self.GetId()) -} - -func (self *SRegion) DeleteLoadBalancerPolicy(policyId string) error { - return DoDelete(self.ecsClient.ElbL7policies.Delete, policyId, nil, nil) -} diff --git a/pkg/multicloud/hcso/modelarts.go b/pkg/multicloud/hcso/modelarts.go deleted file mode 100644 index 0361ee4f5b..0000000000 --- a/pkg/multicloud/hcso/modelarts.go +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SModelartsPool struct { - region *SRegion - multicloud.SResourceBase - - Metadata SModelartsPoolMetadata `json:"metadata"` - Spec SModelartsPoolSpec `json:"spec"` - Status SModelartsPoolStatus `json:"status"` - InstanceType string - WorkType string -} - -type SModelartsPoolMetadata struct { - Name string `json:"name"` - CreationTimestamp string `json:"creationTimestamp"` - Labels SModelartsPoolMeatadataLabel - Annotations SModelartsPoolMetadataAnnotations `json:"annotations"` -} - -type SModelartsPoolMeatadataLabel struct { - WorkspaceId string `json:"os.modelarts/workspace.id"` - Name string `json:"os.modelarts/name"` - ResourceId string `json:"os.modelarts/resource.id"` -} - -type SModelartsPoolMetadataAnnotations struct { - Describe string `json:"os.modelarts/description"` - BillingType string `json:"os.modelarts/billing.mode"` - BillingCycle string `json:"os.modelarts/period.num"` - BillingPeriodType string `json:"os.modelarts/period.type"` - BillingMod string `json:"os.modelarts/charging.mode"` - BillingRenew string `json:"os.modelarts/auto.renew"` - OrderId string `json:"os.modelarts/order.id"` -} - -type SModelartsPoolSpec struct { - Type string `json:"type"` - Scope []string `json:"scope"` - Resource []SModelartsPoolResource `json:"resources"` -} - -type SModelartsPoolResource struct { - Flavor string `json:"flavor"` - Count int `json:"count"` - cloudprovider.Azs -} - -type SNodeStatus struct { - Creating []SNodeFlavor `json:"creating"` - Available []SNodeFlavor `json:"available"` - Abnormal []SNodeFlavor `json:"abnormal"` - Deleting []SNodeFlavor `json:"deleting"` -} - -type SNodeFlavor struct { - Flavor string `json:"flavor"` - Count int `json:"count"` -} - -type SModelartsPoolStatus struct { - Phase string `json:"phase"` - Message string `json:"message"` - Resource SNodeStatus `json:"resources"` -} - -type SModelartsPoolNetwork struct { - Metadata SModelartsPoolNetworkMetadata `json:"metadata"` -} - -type SModelartsPoolNetworkMetadata struct { - Name string `json:"name"` - CreationTimestamp string `json:"creationTimestamp"` -} - -func (self *SRegion) GetIModelartsPools() ([]cloudprovider.ICloudModelartsPool, error) { - pools := make([]SModelartsPool, 0) - resObj, err := self.client.modelartsPoolList(nil) - if err != nil { - return nil, errors.Wrap(err, "region.GetPools") - } - err = resObj.Unmarshal(&pools, "items") - if err != nil { - return nil, errors.Wrap(err, "resObj unmarshal") - } - res := make([]cloudprovider.ICloudModelartsPool, len(pools)) - for i := 0; i < len(pools); i++ { - pools[i].region = self - res[i] = &pools[i] - } - - return res, nil -} - -func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreateOption) (cloudprovider.ICloudModelartsPool, error) { - netObj, err := self.client.modelartsPoolNetworkList(nil) - if err != nil { - return nil, errors.Wrap(err, "SHuaweiClient.GetPools") - } - netRes := make([]SModelartsPoolNetwork, 0) - netObj.Unmarshal(&netRes, "items") - netId := "" - if len(netRes) != 0 { - netId = netRes[0].Metadata.Name - } else { - createNetObj, err := self.client.CreatePoolNetworks() - if err != nil { - return nil, errors.Wrap(err, "SHuaweiClient.CreatePoolNetworks") - } - netId, _ = createNetObj.GetString("metadata", "name") - } - - scopeArr := strings.Split(args.WorkType, ",") - params := map[string]interface{}{ - "apiVersion": "v2", - "kind": "Pool", - "metadata": map[string]interface{}{ - "labels": map[string]interface{}{ - "os.modelarts/name": args.Name, - "os.modelarts/workspace.id": "0", - }, - }, - "spec": map[string]interface{}{ - "type": "Dedicate", - "scope": scopeArr, - "network": map[string]interface{}{ - "name": netId, - }, - - "resources": []map[string]interface{}{ - { - "flavor": args.InstanceType, - "count": args.NodeCount, - }, - }, - }, - } - obj, err := self.client.modelartsPoolCreate(params) - if err != nil { - return nil, errors.Wrap(err, "SHuaweiClient.CreatePools") - } - pool := &SModelartsPool{} - obj.Unmarshal(&pool) - res := []cloudprovider.ICloudModelartsPool{} - for i := 0; i < 1; i++ { - pool.region = self - res = append(res, pool) - } - - return res[0], nil -} - -func (self *SRegion) DeletePool(poolName string) (jsonutils.JSONObject, error) { - return self.client.modelartsPoolDelete(poolName, nil) -} - -func (self *SRegion) GetIModelartsPoolById(poolId string) (cloudprovider.ICloudModelartsPool, error) { - obj, err := self.client.modelartsPoolById(poolId) - if err != nil { - if strings.Contains(err.Error(), "not found") { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "") - } - return nil, errors.Wrap(err, "region.modelartsPoolByName") - } - pool := &SModelartsPool{} - obj.Unmarshal(&pool) - res := []cloudprovider.ICloudModelartsPool{} - for i := 0; i < 1; i++ { - pool.region = self - res = append(res, pool) - } - return res[0], nil -} - -func (self *SRegion) MonitorPool(poolId string) (*SModelartsMetrics, error) { - resObj, err := self.client.modelartsPoolMonitor(poolId, nil) - if err != nil { - return nil, errors.Wrapf(err, "send request error") - } - metrics := SModelartsMetrics{} - err = resObj.Unmarshal(&metrics) - if err != nil { - return nil, errors.Wrapf(err, "unmarsh error") - } - return &metrics, nil -} - -type SModelartsMetrics struct { - Metrics []SModelartsMetric `json:"metrics"` -} - -type SModelartsMetric struct { - Metric SModelartsMetricInfo `json:"metric"` - Datapoints []SModelartsDataPoints `json:"dataPoints"` -} - -type SModelartsMetricInfo struct { - Dimensions []SModelartsDimensions `json:"dimensions"` - MetricName string - Namespace string -} - -type SModelartsDimensions struct { - Name string - Value string -} - -type SModelartsDataPoints struct { - Timestamp int64 - Unit string - Statistics []ModelartsStatistics -} - -type ModelartsStatistics struct { - Statistic string - Value float64 -} - -func (self *SHuaweiClient) GetPoolNetworks(poolName string) (jsonutils.JSONObject, error) { - return self.modelartsPoolNetworkList(nil) -} - -func (self *SHuaweiClient) CreatePoolNetworks() (jsonutils.JSONObject, error) { - params := map[string]interface{}{ - "apiVersion": "v1", - "kind": "Network", - "metadata": map[string]interface{}{ - "labels": map[string]interface{}{ - "os.modelarts/name": "test", - "os.modelarts/workspace.id": "0", - }, - }, - "spec": map[string]interface{}{ - "cidr": "192.168.20.0/24", - }, - } - return self.modelartsPoolNetworkCreate(params) -} - -func (self *SModelartsPool) GetCreatedAt() time.Time { - ret, _ := time.Parse("2006-01-02T15:04:05CST", self.Metadata.CreationTimestamp) - if !ret.IsZero() { - ret = ret.Add(time.Hour * 8) - } - return ret -} - -func (self *SModelartsPool) GetGlobalId() string { - return self.Metadata.Name -} - -func (self *SModelartsPool) GetId() string { - return self.Metadata.Name -} - -func (self *SModelartsPool) GetName() string { - return self.Metadata.Labels.Name -} - -func (self *SModelartsPool) GetStatus() string { - res := strings.ToLower(self.Status.Phase) - switch { - case res == compute.MODELARTS_POOL_STATUS_RUNNING && len(self.Status.Resource.Creating) != 0: - res = compute.MODELARTS_POOL_STATUS_CREATING - } - return res -} - -func (self *SModelartsPool) GetSysTags() map[string]string { - return nil -} - -func (self *SModelartsPool) GetTags() (map[string]string, error) { - return nil, nil -} - -func (self *SModelartsPool) IsEmulated() bool { - return false -} - -func (self *SModelartsPool) GetBillingType() string { - if self.Metadata.Annotations.BillingType == "1" { - return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID - } -} - -// 获取资源归属项目Id -func (self *SModelartsPool) GetProjectId() string { - return self.Metadata.Name -} - -func (self *SModelartsPool) GetExpiredAt() time.Time { - ret, _ := time.Parse("2006-01-02T15:04:05CST", self.Metadata.CreationTimestamp) - if !ret.IsZero() { - ret = ret.Add(time.Hour * 8) - } - return ret -} - -func (self *SModelartsPool) IsAutoRenew() bool { - return false -} - -func (self *SModelartsPool) Renew(bc billing.SBillingCycle) error { - return nil -} - -func (self *SModelartsPool) SetAutoRenew(bc billing.SBillingCycle) error { - return nil -} - -func (self *SModelartsPool) Refresh() error { - pool, err := self.region.client.modelartsPoolById(self.GetId()) - if err != nil { - return errors.Wrapf(err, "GetModelartsPool(%s)", self.GetId()) - } - return jsonutils.Update(self, pool) -} - -func (self *SModelartsPool) SetTags(tags map[string]string, replace bool) error { - return nil -} - -func (self *SModelartsPool) Delete() error { - _, err := self.region.DeletePool(self.GetId()) - if err != nil { - return err - } - return nil -} - -func (self *SModelartsPool) GetInstanceType() string { - return self.Spec.Resource[0].Flavor - -} - -func (self *SModelartsPool) GetWorkType() string { - return strings.Join(self.Spec.Scope, ",") -} - -func (self *SModelartsPool) GetNodeCount() int { - if len(self.Spec.Resource) < 1 { - return 0 - } - return self.Spec.Resource[0].Count -} - -func (self *SModelartsPool) ChangeConfig(opts *cloudprovider.ModelartsPoolChangeConfigOptions) error { - //{"spec":{"resources":[{"flavor":"modelarts.kat1.8xlarge","count":2}]}} - res := []map[string]interface{}{} - for _, re := range self.Spec.Resource { - res = append(res, map[string]interface{}{ - "flavor": re.Flavor, - "count": opts.NodeCount, - }) - } - params := map[string]interface{}{ - "spec": map[string]interface{}{ - "resources": res, - }, - } - _, err := self.region.client.modelartsPoolUpdate(self.Metadata.Name, params) - return err -} diff --git a/pkg/multicloud/hcso/modelarts_sku.go b/pkg/multicloud/hcso/modelarts_sku.go deleted file mode 100644 index dbb05b07f0..0000000000 --- a/pkg/multicloud/hcso/modelarts_sku.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "strconv" - "time" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SModelartsPoolSku struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - - Kind string `json:"kind"` - Spec SModelartsResourceflavorsSpec `json:"spec"` - Status SModelartsResourceflavorsStatus `json:"status"` -} - -type SModelartsResourceflavorsSpec struct { - BillingCode string `json:"billingCode"` - BillingModes []int `json:"billingMods"` - Cpu int `json:"cpu"` - CpuArch string `json:"cpuArch"` - Gpu SModelartsResourceflavorsGpuSpec `json:"gpu"` - Npu SModelartsResourceflavorsGpuSpec `json:"npu"` - Memory string `json:"memory"` - Type string `json:"type"` -} - -type SModelartsResourceflavorsGpuSpec struct { - Size int `json:"size"` - Type string `json:"type"` -} - -type SModelartsResourceflavorsStatus struct { - Phase map[string]interface{} `json:"phase"` -} - -func (self *SRegion) GetIModelartsPoolSku() ([]cloudprovider.ICloudModelartsPoolSku, error) { - params := make(map[string]interface{}) - resourceflavors := make([]SModelartsPoolSku, 0) - obj, err := self.client.modelartsResourceflavors(params) - if err != nil { - return nil, errors.Wrap(err, "region.modelartsResourceflavors") - } - obj.Unmarshal(&resourceflavors, "items") - res := make([]cloudprovider.ICloudModelartsPoolSku, len(resourceflavors)) - for i := 0; i < len(resourceflavors); i++ { - res[i] = &resourceflavors[i] - } - return res, nil -} - -func (self *SModelartsPoolSku) GetCreatedAt() time.Time { - createdAt, _ := time.Parse("2006-01-02T15:04:05CST", time.Now().Format("2006-01-02T15:04:05CST")) - return createdAt -} - -func (self *SModelartsPoolSku) GetGlobalId() string { - return self.Spec.BillingCode -} - -func (self *SModelartsPoolSku) GetId() string { - return self.Spec.BillingCode -} - -func (self *SModelartsPoolSku) GetName() string { - return self.Spec.BillingCode -} - -func (self *SModelartsPoolSku) GetCpuArch() string { - return self.Spec.CpuArch -} - -func (self *SModelartsPoolSku) GetCpuCoreCount() int { - return self.Spec.Cpu -} - -func (self *SModelartsPoolSku) GetMemorySizeMB() int { - size, _ := strconv.Atoi(self.Spec.Memory[:len(self.Spec.Memory)-2]) - return size * 1024 -} - -func (self *SModelartsPoolSku) GetStatus() string { - for _, v := range self.Status.Phase { - if v == "normal" { - return compute.MODELARTS_POOL_SKU_AVAILABLE - } - } - return compute.MODELARTS_POOL_SKU_SOLDOUT -} - -func (self *SModelartsPoolSku) GetGpuSize() int { - return self.Spec.Gpu.Size -} - -func (self *SModelartsPoolSku) GetGpuType() string { - return self.Spec.Gpu.Type -} - -func (self *SModelartsPoolSku) GetNpuSize() int { - return self.Spec.Npu.Size -} - -func (self *SModelartsPoolSku) GetNpuType() string { - return self.Spec.Npu.Type -} - -func (self *SModelartsPoolSku) GetPoolType() string { - return self.Spec.Type -} diff --git a/pkg/multicloud/hcso/monitor.go b/pkg/multicloud/hcso/monitor.go deleted file mode 100644 index 1d881b2615..0000000000 --- a/pkg/multicloud/hcso/monitor.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules" -) - -func (r *SRegion) GetMetrics() ([]modules.SMetricMeta, error) { - return r.ecsClient.CloudEye.ListMetrics() -} - -func (r *SRegion) GetMetricsData(metrics []modules.SMetricMeta, since time.Time, until time.Time) ([]modules.SMetricData, error) { - return r.ecsClient.CloudEye.GetMetricsData(metrics, since, until) -} - -func (self *SHuaweiClient) getModelartsPoolMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - resp, err := self.modelartsPoolMonitor(opts.ResourceId, nil) - if err != nil { - return nil, err - } - metricData := []SModelartsMetric{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - isMB := false - if metricData[i].Datapoints[0].Unit == "Megabytes" { - isMB = true - metricData[i].Datapoints[0].Unit = "Bytes" - } - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Datapoints[0].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].Metric.MetricName { - case "cpuUsage": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_CPU_USAGE - case "memUsedRate": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_MEM_USAGE - case "gpuUtil": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_GPU_UTIL - case "gpuMemUsage": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_GPU_MEM_USAGE - case "npuUtil": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_NPU_UTIL - case "npuMemUsage": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_NPU_MEM_USAGE - case "diskAvailableCapacity": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_AVAILABLE_CAPACITY - case "diskCapacity": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_CAPACITY - case "diskUsedRate": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_USAGE - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].Metric.MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - if isMB { - value.Statistics[0].Value *= 1024 - } - if value.Statistics[0].Value == -1 { - value.Statistics[0].Value = 0 - } - metricValue := cloudprovider.MetricValue{ - Value: value.Statistics[0].Value, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHuaweiClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_MODELARTS_POOL: - return self.getModelartsPoolMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) - } -} diff --git a/pkg/multicloud/hcso/nat_skus.go b/pkg/multicloud/hcso/nat_skus.go deleted file mode 100644 index 93bf85c7d5..0000000000 --- a/pkg/multicloud/hcso/nat_skus.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - HUAWEI_NAT_SKU_SMALL = "Small" - HUAWEI_NAT_SKU_MIDDLE = "Middle" - HUAWEI_NAT_SKU_LARGE = "Large" - HUAWEI_NAT_SKU_XLARGE = "XLarge" -) - -type SNatSku struct { - spec string -} - -func (self *SNatSku) GetName() string { - return self.spec -} - -func (self *SNatSku) GetPps() int { - return 1000000 -} - -func (self *SNatSku) GetConns() int { - switch self.spec { - case HUAWEI_NAT_SKU_SMALL: - return 10000 - case HUAWEI_NAT_SKU_MIDDLE: - return 50000 - case HUAWEI_NAT_SKU_LARGE: - return 200000 - case HUAWEI_NAT_SKU_XLARGE: - return 1000000 - } - return 0 -} - -func (self *SNatSku) GetThroughput() int { - return 10 -} - -func (self *SNatSku) GetDesc() string { - switch self.spec { - case HUAWEI_NAT_SKU_SMALL: - return "小型" - case HUAWEI_NAT_SKU_MIDDLE: - return "中型" - case HUAWEI_NAT_SKU_LARGE: - return "大型" - case HUAWEI_NAT_SKU_XLARGE: - return "超大型" - } - return "" -} - -func (self *SNatSku) GetPostpaidStatus() string { - return api.NAT_SKU_AVAILABLE -} - -func (self *SNatSku) GetPrepaidStatus() string { - return api.NAT_SKU_SOLDOUT -} - -func (self *SNatSku) GetGlobalId() string { - return self.spec -} - -func (self *SRegion) GetICloudNatSkus() ([]cloudprovider.ICloudNatSku, error) { - ret := []cloudprovider.ICloudNatSku{} - for _, spec := range []string{ - HUAWEI_NAT_SKU_SMALL, - HUAWEI_NAT_SKU_MIDDLE, - HUAWEI_NAT_SKU_LARGE, - HUAWEI_NAT_SKU_XLARGE, - } { - sku := &SNatSku{spec: spec} - ret = append(ret, sku) - } - return ret, nil -} diff --git a/pkg/multicloud/hcso/natdtable.go b/pkg/multicloud/hcso/natdtable.go deleted file mode 100644 index 28aa2aa47e..0000000000 --- a/pkg/multicloud/hcso/natdtable.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNatDEntry struct { - multicloud.SResourceBase - multicloud.HuaweiTags - gateway *SNatGateway - - ID string `json:"id"` - NatGatewayID string `json:"nat_gateway_id"` - Protocol string `json:"protocol"` - Status string `json:"status"` - ExternalIP string `json:"floating_ip_address"` - ExternalPort int `json:"external_service_port"` - InternalIP string `json:"private_ip"` - InternalPort int `json:"internal_service_port"` - PortID string `json:"port_id"` - AdminStateUp bool `json:"admin_state_up"` -} - -func (nat *SNatDEntry) GetId() string { - return nat.ID -} - -func (nat *SNatDEntry) GetName() string { - // No name so return id - return nat.GetId() -} - -func (nat *SNatDEntry) GetGlobalId() string { - return nat.GetId() -} - -func (nat *SNatDEntry) GetStatus() string { - return NatResouceStatusTransfer(nat.Status) -} - -func (nat *SNatDEntry) GetIpProtocol() string { - return nat.Protocol -} - -func (nat *SNatDEntry) GetExternalIp() string { - return nat.ExternalIP -} - -func (nat *SNatDEntry) GetExternalPort() int { - return nat.ExternalPort -} - -func (nat *SNatDEntry) GetInternalIp() string { - return nat.InternalIP -} - -func (nat *SNatDEntry) GetInternalPort() int { - return nat.InternalPort -} - -func (nat *SNatDEntry) Delete() error { - return nat.gateway.region.DeleteNatDEntry(nat.GetId()) -} - -// getNatSTable return all snat rules of gateway -func (gateway *SNatGateway) getNatDTable() ([]SNatDEntry, error) { - ret, err := gateway.region.GetNatDTable(gateway.GetId()) - if err != nil { - return nil, err - } - for i := range ret { - ret[i].gateway = gateway - } - return ret, nil -} - -func (region *SRegion) GetNatDTable(natGatewayID string) ([]SNatDEntry, error) { - queuies := map[string]string{ - "nat_gateway_id": natGatewayID, - } - dNatSTableEntries := make([]SNatDEntry, 0, 2) - // can't make true that restapi support marker para in Huawei Cloud - err := doListAllWithMarker(region.ecsClient.DNatRules.List, queuies, &dNatSTableEntries) - if err != nil { - return nil, errors.Wrapf(err, `get dnat rule of gateway %q`, natGatewayID) - } - for i := range dNatSTableEntries { - nat := &dNatSTableEntries[i] - if len(nat.InternalIP) == 0 { - port, err := region.GetPort(nat.PortID) - if err != nil { - return nil, errors.Wrapf(err, `get port info for transfer to ip of port_id %q error`, nat.PortID) - } - nat.InternalIP = port.FixedIps[0].IpAddress - } - } - return dNatSTableEntries, nil -} - -func (region *SRegion) DeleteNatDEntry(entryID string) error { - _, err := region.ecsClient.DNatRules.Delete(entryID, nil) - if err != nil { - return errors.Wrapf(err, `delete dnat rule %q failed`, entryID) - } - return nil -} - -func (nat *SNatDEntry) Refresh() error { - new, err := nat.gateway.region.GetNatDEntryByID(nat.ID) - if err != nil { - return err - } - return jsonutils.Update(nat, new) -} diff --git a/pkg/multicloud/hcso/natgateway.go b/pkg/multicloud/hcso/natgateway.go deleted file mode 100644 index 4a292e5517..0000000000 --- a/pkg/multicloud/hcso/natgateway.go +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNatGateway struct { - multicloud.SNatGatewayBase - multicloud.HuaweiTags - region *SRegion - - ID string - Name string - Description string - Spec string - Status string - InternalNetworkId string - CreatedTime string `json:"created_at"` -} - -func (gateway *SNatGateway) GetId() string { - return gateway.ID -} - -func (gateway *SNatGateway) GetName() string { - return gateway.Name -} - -func (gateway *SNatGateway) GetGlobalId() string { - return gateway.GetId() -} - -func (gateway *SNatGateway) GetStatus() string { - return NatResouceStatusTransfer(gateway.Status) -} - -func (self *SNatGateway) Delete() error { - return self.region.DeleteNatGateway(self.ID) -} - -func (self *SNatGateway) Refresh() error { - nat, err := self.region.GetNatGateway(self.ID) - if err != nil { - return errors.Wrapf(err, "GetNatGateway(%s)", self.ID) - } - return jsonutils.Update(self, nat) -} - -func (self *SNatGateway) GetINetworkId() string { - return self.InternalNetworkId -} - -func (gateway *SNatGateway) GetNatSpec() string { - switch gateway.Spec { - case "1": - return api.NAT_SPEC_SMALL - case "2": - return api.NAT_SPEC_MIDDLE - case "3": - return api.NAT_SPEC_LARGE - case "4": - return api.NAT_SPEC_XLARGE - } - return gateway.Spec -} - -func (gateway *SNatGateway) GetDescription() string { - return gateway.Description -} - -func (gateway *SNatGateway) GetBillingType() string { - // Up to 2019.07.17, only support post pay - return billing_api.BILLING_TYPE_POSTPAID -} - -func (gateway *SNatGateway) GetCreatedAt() time.Time { - t, _ := time.Parse("2006-01-02 15:04:05.000000", gateway.CreatedTime) - return t -} - -func (gateway *SNatGateway) GetExpiredAt() time.Time { - // no support for expired time - return time.Time{} -} - -func (gateway *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { - IEips, err := gateway.region.GetIEips() - if err != nil { - return nil, errors.Wrapf(err, `get all Eips of region %q error`, gateway.region.GetId()) - } - dNatTables, err := gateway.GetINatDTable() - if err != nil { - return nil, errors.Wrapf(err, `get all DNatTable of gateway %q error`, gateway.GetId()) - } - sNatTables, err := gateway.GetINatSTable() - if err != nil { - return nil, errors.Wrapf(err, `get all SNatTable of gateway %q error`, gateway.GetId()) - } - - // Get natIPSet of nat rules - natIPSet := make(map[string]struct{}) - for _, snat := range sNatTables { - natIPSet[snat.GetIP()] = struct{}{} - } - for _, dnat := range dNatTables { - natIPSet[dnat.GetExternalIp()] = struct{}{} - } - - // Add Eip whose GetIpAddr() in natIPSet to ret - ret := make([]cloudprovider.ICloudEIP, 0, 2) - for i := range IEips { - if _, ok := natIPSet[IEips[i].GetIpAddr()]; ok { - ret = append(ret, IEips[i]) - } - } - return ret, nil -} - -func (gateway *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { - dNatTable, err := gateway.getNatDTable() - if err != nil { - return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) - } - ret := make([]cloudprovider.ICloudNatDEntry, len(dNatTable)) - for i := range dNatTable { - ret[i] = &dNatTable[i] - } - return ret, nil -} - -func (gateway *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { - sNatTable, err := gateway.getNatSTable() - if err != nil { - return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) - } - ret := make([]cloudprovider.ICloudNatSEntry, len(sNatTable)) - for i := range sNatTable { - ret[i] = &sNatTable[i] - } - return ret, nil -} - -func (gateway *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { - dnat, err := gateway.region.CreateNatDEntry(rule, gateway.GetId()) - if err != nil { - return nil, err - } - dnat.gateway = gateway - return &dnat, nil -} - -func (gateway *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { - snat, err := gateway.region.CreateNatSEntry(rule, gateway.GetId()) - if err != nil { - return nil, err - } - snat.gateway = gateway - return &snat, nil -} - -func (gateway *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { - dnat, err := gateway.region.GetNatDEntryByID(id) - if err != nil { - return nil, err - } - dnat.gateway = gateway - return &dnat, nil -} - -func (gateway *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { - snat, err := gateway.region.GetNatSEntryByID(id) - if err != nil { - return nil, err - } - snat.gateway = gateway - return &snat, nil -} - -func (region *SRegion) GetNatGateways(vpcID, natGatewayID string) ([]SNatGateway, error) { - queues := make(map[string]string) - if len(natGatewayID) != 0 { - queues["id"] = natGatewayID - } - if len(vpcID) != 0 { - queues["router_id"] = vpcID - } - natGateways := make([]SNatGateway, 0, 2) - err := doListAllWithMarker(region.ecsClient.NatGateways.List, queues, &natGateways) - if err != nil { - return nil, errors.Wrapf(err, "get nat gateways error by natgatewayid") - } - for i := range natGateways { - natGateways[i].region = region - } - return natGateways, nil -} - -func (region *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayID string) (SNatDEntry, error) { - params := make(map[string]interface{}) - params["nat_gateway_id"] = gatewayID - params["private_ip"] = rule.InternalIP - params["internal_service_port"] = rule.InternalPort - params["floating_ip_id"] = rule.ExternalIPID - params["external_service_port"] = rule.ExternalPort - params["protocol"] = rule.Protocol - - packParams := map[string]map[string]interface{}{ - "dnat_rule": params, - } - - ret := SNatDEntry{} - err := DoCreate(region.ecsClient.DNatRules.Create, jsonutils.Marshal(packParams), &ret) - if err != nil { - return SNatDEntry{}, errors.Wrapf(err, `create dnat rule of nat gateway %q failed`, gatewayID) - } - return ret, nil -} - -func (region *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayID string) (SNatSEntry, error) { - params := make(map[string]interface{}) - params["nat_gateway_id"] = gatewayID - if len(rule.NetworkID) != 0 { - params["network_id"] = rule.NetworkID - } - if len(rule.SourceCIDR) != 0 { - params["cidr"] = rule.SourceCIDR - } - params["floating_ip_id"] = rule.ExternalIPID - - packParams := map[string]map[string]interface{}{ - "snat_rule": params, - } - - ret := SNatSEntry{} - err := DoCreate(region.ecsClient.SNatRules.Create, jsonutils.Marshal(packParams), &ret) - if err != nil { - return SNatSEntry{}, errors.Wrapf(err, `create snat rule of nat gateway %q failed`, gatewayID) - } - return ret, nil -} - -func (region *SRegion) GetNatDEntryByID(id string) (SNatDEntry, error) { - dnat := SNatDEntry{} - err := DoGet(region.ecsClient.DNatRules.Get, id, map[string]string{}, &dnat) - - if err != nil { - return SNatDEntry{}, err - } - return dnat, nil -} - -func (region *SRegion) GetNatSEntryByID(id string) (SNatSEntry, error) { - snat := SNatSEntry{} - err := DoGet(region.ecsClient.SNatRules.Get, id, map[string]string{}, &snat) - if err != nil { - return SNatSEntry{}, cloudprovider.ErrNotFound - } - return snat, nil -} - -func NatResouceStatusTransfer(status string) string { - // In Huawei Cloud, there are isx resource status of Nat, "ACTIVE", "PENDING_CREATE", - // "PENDING_UPDATE", "PENDING_DELETE", "EIP_FREEZED", "INACTIVE". - switch status { - case "ACTIVE": - return api.NAT_STAUTS_AVAILABLE - case "PENDING_CREATE": - return api.NAT_STATUS_ALLOCATE - case "PENDING_UPDATE", "PENDING_DELETE": - return api.NAT_STATUS_DEPLOYING - default: - return api.NAT_STATUS_UNKNOWN - } -} - -func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) { - resp, err := self.ecsClient.NatGateways.Get(id, nil) - if err != nil { - return nil, errors.Wrapf(err, "NatGateways.Get(%s)", id) - } - nat := &SNatGateway{region: self} - err = resp.Unmarshal(nat) - return nat, errors.Wrap(err, "resp.Unmarshal") -} - -func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { - nat, err := self.region.CreateNatGateway(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateNatGateway") - } - return nat, nil -} - -func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGateway, error) { - spec := "" - switch strings.ToLower(opts.NatSpec) { - case api.NAT_SPEC_SMALL: - spec = "1" - case api.NAT_SPEC_MIDDLE: - spec = "2" - case api.NAT_SPEC_LARGE: - spec = "3" - case api.NAT_SPEC_XLARGE: - spec = "4" - } - params := jsonutils.Marshal(map[string]map[string]interface{}{ - "nat_gateway": map[string]interface{}{ - "name": opts.Name, - "description": opts.Desc, - "router_id": opts.VpcId, - "internal_network_id": opts.NetworkId, - "spec": spec, - }, - }) - resp, err := self.ecsClient.NatGateways.Create(params) - if err != nil { - return nil, errors.Wrap(err, "AsyncCreate") - } - nat := &SNatGateway{region: self} - err = resp.Unmarshal(nat) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return nat, nil -} - -func (self *SRegion) DeleteNatGateway(id string) error { - _, err := self.ecsClient.NatGateways.Delete(id, nil) - return errors.Wrapf(err, "NatGateways.Delete(%s)", id) -} diff --git a/pkg/multicloud/hcso/natstable.go b/pkg/multicloud/hcso/natstable.go deleted file mode 100644 index da6f98a337..0000000000 --- a/pkg/multicloud/hcso/natstable.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNatSEntry struct { - multicloud.SResourceBase - multicloud.HuaweiTags - gateway *SNatGateway - - ID string `json:"id"` - NatGatewayID string `json:"nat_gateway_id"` - NetworkID string `json:"network_id"` - SourceCIDR string `json:"cidr"` - Status string `json:"status"` - SNatIP string `json:"floating_ip_address"` - AdminStateUp bool `json:"admin_state_up"` -} - -func (nat *SNatSEntry) GetId() string { - return nat.ID -} - -func (nat *SNatSEntry) GetName() string { - // Snat rule has no name in Huawei Cloud, so return ID - return nat.GetId() -} - -func (nat *SNatSEntry) GetGlobalId() string { - return nat.GetId() -} - -func (nat *SNatSEntry) GetStatus() string { - return NatResouceStatusTransfer(nat.Status) -} - -func (nat *SNatSEntry) GetIP() string { - return nat.SNatIP -} - -func (nat *SNatSEntry) GetSourceCIDR() string { - return nat.SourceCIDR -} - -func (nat *SNatSEntry) GetNetworkId() string { - return nat.NetworkID -} - -func (nat *SNatSEntry) Delete() error { - return nat.gateway.region.DeleteNatSEntry(nat.GetId()) -} - -// getNatSTable return all snat rules of gateway -func (gateway *SNatGateway) getNatSTable() ([]SNatSEntry, error) { - ret, err := gateway.region.GetNatSTable(gateway.GetId()) - if err != nil { - return nil, err - } - for i := range ret { - ret[i].gateway = gateway - } - return ret, nil -} - -func (region *SRegion) GetNatSTable(natGatewayID string) ([]SNatSEntry, error) { - queuies := map[string]string{ - "nat_gateway_id": natGatewayID, - } - sNatSTableEntris := make([]SNatSEntry, 0, 2) - err := doListAllWithMarker(region.ecsClient.SNatRules.List, queuies, &sNatSTableEntris) - if err != nil { - return nil, errors.Wrapf(err, `get snat rule of gateway %q`, natGatewayID) - } - for i := range sNatSTableEntris { - nat := &sNatSTableEntris[i] - if len(nat.SourceCIDR) != 0 { - continue - } - subnet := SNetwork{} - err := DoGet(region.ecsClient.Subnets.Get, nat.NetworkID, map[string]string{}, &subnet) - if err != nil { - return nil, errors.Wrapf(err, `get cidr of subnet %q`, nat.NetworkID) - } - nat.SourceCIDR = subnet.CIDR - } - return sNatSTableEntris, nil -} - -func (region *SRegion) DeleteNatSEntry(entryID string) error { - _, err := region.ecsClient.SNatRules.Delete(entryID, nil) - if err != nil { - return errors.Wrapf(err, `delete snat rule %q failed`, entryID) - } - return nil -} - -func (nat *SNatSEntry) Refresh() error { - new, err := nat.gateway.region.GetNatSEntryByID(nat.ID) - if err != nil { - return err - } - return jsonutils.Update(nat, new) -} diff --git a/pkg/multicloud/hcso/network.go b/pkg/multicloud/hcso/network.go deleted file mode 100644 index e7a4289472..0000000000 --- a/pkg/multicloud/hcso/network.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/modules" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -/* -Subnets -*/ - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html -type SNetwork struct { - multicloud.SResourceBase - multicloud.HuaweiTags - wire *SWire - - AvailabilityZone string `json:"availability_zone"` - CIDR string `json:"cidr"` - DHCPEnable bool `json:"dhcp_enable"` - DNSList []string `json:"dnsList"` - GatewayIP string `json:"gateway_ip"` - ID string `json:"id"` - Ipv6Enable bool `json:"ipv6_enable"` - Name string `json:"name"` - NeutronNetworkID string `json:"neutron_network_id"` - NeutronSubnetID string `json:"neutron_subnet_id"` - PrimaryDNS string `json:"primary_dns"` - SecondaryDNS string `json:"secondary_dns"` - Status string `json:"status"` - VpcID string `json:"vpc_id"` -} - -func (self *SNetwork) GetId() string { - return self.ID -} - -func (self *SNetwork) GetName() string { - if len(self.Name) == 0 { - return self.ID - } - - return self.Name -} - -func (self *SNetwork) GetGlobalId() string { - return self.ID -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090591.html -func (self *SNetwork) GetStatus() string { - switch self.Status { - case "ACTIVE", "UNKNOWN": - return api.NETWORK_STATUS_AVAILABLE // ? todo: // UNKNOWN - case "ERROR": - return api.NETWORK_STATUS_UNKNOWN - default: - return api.NETWORK_STATUS_UNKNOWN - } -} - -func (self *SNetwork) Refresh() error { - log.Debugf("network refresh %s", self.GetId()) - new, err := self.wire.region.getNetwork(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SNetwork) IsEmulated() bool { - return false -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - startIp = startIp.StepUp() // 2 - return startIp.String() -} - -func (self *SNetwork) GetIpEnd() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - 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.CIDR) - return pref.MaskLen -} - -func (self *SNetwork) GetGateway() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - return startIp.String() -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetIsPublic() bool { - return true -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) Delete() error { - return self.wire.region.deleteNetwork(self.VpcID, self.GetId()) -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) { - network := SNetwork{} - err := DoGet(self.ecsClient.Subnets.Get, networkId, nil, &network) - return &network, err -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090592.html -func (self *SRegion) GetNetwroks(vpcId string) ([]SNetwork, error) { - querys := map[string]string{} - if len(vpcId) > 0 { - querys["vpc_id"] = vpcId - } - - networks := make([]SNetwork, 0) - err := doListAllWithMarker(self.ecsClient.Subnets.List, querys, &networks) - return networks, err -} - -func (self *SRegion) deleteNetwork(vpcId string, networkId string) error { - ctx := &modules.SManagerContext{InstanceId: vpcId, InstanceManager: self.ecsClient.Vpcs} - return DoDeleteWithSpec(self.ecsClient.Subnets.DeleteInContextWithSpec, ctx, networkId, "", nil, nil) -} - -func (self *SNetwork) GetProjectId() string { - return self.wire.vpc.EnterpriseProjectID -} diff --git a/pkg/multicloud/hcso/object.go b/pkg/multicloud/hcso/object.go deleted file mode 100644 index b94abecceb..0000000000 --- a/pkg/multicloud/hcso/object.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - "net/http" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei/obs" -) - -type SObject struct { - bucket *SBucket - - cloudprovider.SBaseCloudObject -} - -func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { - return o.bucket -} - -func (o *SObject) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - obscli, err := o.bucket.region.getOBSClient() - if err != nil { - log.Errorf("o.bucket.region.GetOssClient error %s", err) - return acl - } - input := &obs.GetObjectAclInput{} - input.Bucket = o.bucket.Name - input.Key = o.Key - output, err := obscli.GetObjectAcl(input) - if err != nil { - log.Errorf("GetObjectAcl error: %v", err) - return acl - } - acl = obsAcl2CannedAcl(output.Grants) - return acl -} - -func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { - obscli, err := o.bucket.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "o.bucket.region.getOBSClient") - } - input := &obs.SetObjectAclInput{} - input.Bucket = o.bucket.Name - input.Key = o.Key - input.ACL = obs.AclType(string(aclStr)) - _, err = obscli.SetObjectAcl(input) - if err != nil { - return errors.Wrap(err, "obscli.SetObjectAcl") - } - return nil -} - -func (o *SObject) GetMeta() http.Header { - if o.Meta != nil { - return o.Meta - } - obscli, err := o.bucket.region.getOBSClient() - if err != nil { - log.Errorf("getOBSClient fail %s", err) - return nil - } - input := &obs.GetObjectMetadataInput{} - input.Bucket = o.bucket.Name - input.Key = o.Key - output, err := obscli.GetObjectMetadata(input) - if err != nil { - log.Errorf("obscli.GetObjectMetadata fail %s", err) - return nil - } - meta := http.Header{} - for k, v := range output.Metadata { - meta.Add(k, v) - } - if len(output.ContentType) > 0 { - meta.Add(cloudprovider.META_HEADER_CONTENT_TYPE, output.ContentType) - } - o.Meta = meta - return meta -} - -func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { - return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) -} diff --git a/pkg/multicloud/hcso/port.go b/pkg/multicloud/hcso/port.go deleted file mode 100644 index 56739286a4..0000000000 --- a/pkg/multicloud/hcso/port.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "strings" - - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SFixedIP struct { - IpAddress string - SubnetID string - NetworkId string -} - -func (fixip *SFixedIP) GetGlobalId() string { - return fixip.IpAddress -} - -func (fixip *SFixedIP) GetIP() string { - return fixip.IpAddress -} - -func (fixip *SFixedIP) GetINetworkId() string { - return fixip.NetworkId -} - -func (fixip *SFixedIP) IsPrimary() bool { - return true -} - -type Port struct { - multicloud.SNetworkInterfaceBase - multicloud.HuaweiTags - region *SRegion - ID string `json:"id"` - Name string `json:"name"` - Status string `json:"status"` - AdminStateUp string `json:"admin_state_up"` - DNSName string `json:"dns_name"` - MACAddress string `json:"mac_address"` - NetworkID string `json:"network_id"` - TenantID string `json:"tenant_id"` - DeviceID string `json:"device_id"` - DeviceOwner string `json:"device_owner"` - BindingVnicType string `json:"binding:vnic_type"` - FixedIps []SFixedIP -} - -func (port *Port) GetName() string { - if len(port.Name) > 0 { - return port.Name - } - return port.ID -} - -func (port *Port) GetId() string { - return port.ID -} - -func (port *Port) GetGlobalId() string { - return port.ID -} - -func (port *Port) GetMacAddress() string { - return port.MACAddress -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html -func (port *Port) GetAssociateType() string { - switch port.DeviceOwner { - case "compute:nova": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER - case "network:router_gateway", "network:router_interface", "network:router_interface_distributed": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_RESERVED - case "network:dhcp": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_DHCP - case "neutron:LOADBALANCERV2": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_LOADBALANCER - case "neutron:VIP_PORT": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_VIP - default: - if strings.HasPrefix(port.DeviceOwner, "compute:") { - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER - } - } - return port.DeviceOwner -} - -func (port *Port) GetAssociateId() string { - return port.DeviceID -} - -func (port *Port) GetStatus() string { - switch port.Status { - case "ACTIVE", "DOWN": - return api.NETWORK_INTERFACE_STATUS_AVAILABLE - case "BUILD": - return api.NETWORK_INTERFACE_STATUS_CREATING - } - return port.Status -} - -func (port *Port) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { - address := []cloudprovider.ICloudInterfaceAddress{} - for i := 0; i < len(port.FixedIps); i++ { - port.FixedIps[i].NetworkId = port.NetworkID - address = append(address, &port.FixedIps[i]) - } - return address, nil -} - -func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { - ports, err := region.GetPorts("") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNetworkInterface{} - for i := 0; i < len(ports); i++ { - if len(ports[i].DeviceID) == 0 || !utils.IsInStringArray(ports[i].DeviceOwner, []string{"compute:CCI", "compute:nova", "neutron:LOADBALANCERV2"}) { - ports[i].region = region - ret = append(ret, &ports[i]) - } - } - return ret, nil -} - -func (self *SRegion) GetPort(portId string) (Port, error) { - port := Port{} - err := DoGet(self.ecsClient.Port.Get, portId, nil, &port) - return port, err -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html -func (self *SRegion) GetPorts(instanceId string) ([]Port, error) { - ports := make([]Port, 0) - querys := map[string]string{} - if len(instanceId) > 0 { - querys["device_id"] = instanceId - } - - err := doListAllWithMarker(self.ecsClient.Port.List, querys, &ports) - return ports, err -} diff --git a/pkg/multicloud/hcso/project.go b/pkg/multicloud/hcso/project.go deleted file mode 100644 index 87e94e05a4..0000000000 --- a/pkg/multicloud/hcso/project.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" -) - -// https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845625.html -type SProject struct { - client *SHuaweiClient - - IsDomain bool `json:"is_domain"` - Description string `json:"description"` - Enabled bool `json:"enabled"` - ID string `json:"id"` - ParentID string `json:"parent_id"` - DomainID string `json:"domain_id"` - Name string `json:"name"` -} - -func (self *SProject) GetRegionID() string { - return strings.Split(self.Name, "_")[0] -} - -func (self *SProject) GetHealthStatus() string { - if self.Enabled { - return api.CLOUD_PROVIDER_HEALTH_NORMAL - } - - return api.CLOUD_PROVIDER_HEALTH_SUSPENDED -} - -func (self *SHuaweiClient) fetchProjects() ([]SProject, error) { - if self.projects != nil { - return self.projects, nil - } - - huawei, _ := self.newGeneralAPIClient() - projects := make([]SProject, 0) - err := doListAll(huawei.Projects.List, nil, &projects) - if err == nil { - self.projects = projects - } - - return projects, err -} - -// obs 权限必须赋予到mos project之上 -func (self *SHuaweiClient) GetMosProjectId() string { - projects, err := self.GetProjects() - if err != nil { - return "" - } - for i := range projects { - if strings.ToLower(projects[i].Name) == "mos" { - return projects[i].ID - } - } - return "" -} - -func (self *SHuaweiClient) GetMosRoles(groupId string) ([]SRole, error) { - client, _ := self.newGeneralAPIClient() - resp, err := client.Projects.ListRoles(self.GetMosProjectId(), groupId) - if err != nil { - return nil, err - } - ret := []SRole{} - return ret, jsonutils.Update(&ret, resp.Data) -} - -func (self *SHuaweiClient) GetProjectById(projectId string) (SProject, error) { - projects, err := self.fetchProjects() - if err != nil { - return SProject{}, err - } - - for _, project := range projects { - if project.ID == projectId { - return project, nil - } - } - return SProject{}, fmt.Errorf("project %s not found", projectId) -} - -func (self *SHuaweiClient) GetProjects() ([]SProject, error) { - return self.fetchProjects() -} diff --git a/pkg/multicloud/hcso/provider/doc.go b/pkg/multicloud/hcso/provider/doc.go deleted file mode 100644 index 04fcb650c2..0000000000 --- a/pkg/multicloud/hcso/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/hcso/provider" diff --git a/pkg/multicloud/hcso/provider/provider.go b/pkg/multicloud/hcso/provider/provider.go deleted file mode 100644 index efbb615641..0000000000 --- a/pkg/multicloud/hcso/provider/provider.go +++ /dev/null @@ -1,336 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" -) - -type SHCSOProviderFactory struct { - cloudprovider.SPrivateCloudBaseProviderFactory -} - -func (self *SHCSOProviderFactory) GetId() string { - return huawei.CLOUD_PROVIDER_HUAWEI -} - -func (self *SHCSOProviderFactory) GetName() string { - return huawei.CLOUD_PROVIDER_HUAWEI_CN -} - -func (self *SHCSOProviderFactory) IsCloudeventRegional() bool { - return true -} - -func (self *SHCSOProviderFactory) GetMaxCloudEventSyncDays() int { - return 7 -} - -func (self *SHCSOProviderFactory) GetMaxCloudEventKeepDays() int { - return 7 -} - -func (self *SHCSOProviderFactory) IsSupportCloudIdService() bool { - return true -} - -func (self *SHCSOProviderFactory) IsSupportClouduserPolicy() bool { - return false -} - -func (self *SHCSOProviderFactory) IsSupportCreateCloudgroup() bool { - return true -} - -func (factory *SHCSOProviderFactory) IsSupportCrossCloudEnvVpcPeering() bool { - return false -} - -func (factory *SHCSOProviderFactory) IsSupportCrossRegionVpcPeering() bool { - return false -} - -func (factory *SHCSOProviderFactory) IsSupportVpcPeeringVpcCidrOverlap() bool { - return true -} - -func (factory *SHCSOProviderFactory) IsSupportModifyRouteTable() bool { - return true -} - -func (factory *SHCSOProviderFactory) IsSupportSAMLAuth() bool { - return true -} - -func (self *SHCSOProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - - if input.SHCSOEndpoints == nil { - return output, errors.Wrap(httperrors.ErrMissingParameter, "cloud_stack_endpoints") - } - - if len(input.DefaultRegion) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "default_region") - } - - if len(input.SHCSOEndpoints.EndpointDomain) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "endpoint_domain") - } - - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - return output, nil -} - -func (self *SHCSOProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - - if input.SHCSOEndpoints != nil { - if len(input.DefaultRegion) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "default_region") - } - - if len(input.SHCSOEndpoints.EndpointDomain) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "endpoint_domain") - } - } - - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func parseAccount(account string) (accessKey string, projectId string) { - segs := strings.Split(account, "/") - if len(segs) == 2 { - accessKey = segs[0] - projectId = segs[1] - } else { - accessKey = account - projectId = "" - } - - return -} - -func (self *SHCSOProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - hscsoEndpoints := cloudprovider.SHCSOEndpoints{} - if cfg.Options != nil { - cfg.Options.Unmarshal(&hscsoEndpoints) - } - accessKey, project_id := parseAccount(cfg.Account) - client, err := huawei.NewHuaweiClient( - huawei.NewHuaweiClientConfig( - accessKey, cfg.Secret, project_id, &hscsoEndpoints, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SHCSOProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SHCSOProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - accessKey, projectId := parseAccount(info.Account) - region := "" - data := strings.Split(info.Name, "-") - if len(data) >= 3 { - region = strings.Join(data[2:], "-") - } - return map[string]string{ - "HUAWEI_CLOUD_ENV": info.Url, - "HUAWEI_ACCESS_KEY": accessKey, - "HUAWEI_SECRET": info.Secret, - "HUAWEI_REGION": region, - "HUAWEI_PROJECT": projectId, - }, nil -} - -func (self *SHCSOProviderFactory) IsMultiTenant() bool { - return true -} - -func init() { - factory := SHCSOProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SHCSOProvider struct { - cloudprovider.SBaseProvider - client *huawei.SHuaweiClient -} - -func (self *SHCSOProvider) GetVersion() string { - return self.client.GetVersion() -} - -func (self *SHCSOProvider) GetSysInfo() (jsonutils.JSONObject, error) { - regions := self.client.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") - info.Add(jsonutils.NewString(huawei.HUAWEI_API_VERSION), "api_version") - return info, nil -} - -func (self *SHCSOProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SHCSOProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(extId) -} - -func (self *SHCSOProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, nil -} - -func (self *SHCSOProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SHCSOProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SHCSOProvider) GetIamLoginUrl() string { - return self.client.GetIamLoginUrl() -} - -func (self *SHCSOProvider) GetCloudRegionExternalIdPrefix() string { - return self.client.GetCloudRegionExternalIdPrefix() -} - -func (self *SHCSOProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SHCSOProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return self.client.CreateIProject(name) -} - -func (self *SHCSOProvider) GetStorageClasses(regionId string) []string { - return []string{ - "STANDARD", "WARM", "COLD", - } -} - -func (self *SHCSOProvider) GetBucketCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLAuthRead), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SHCSOProvider) GetObjectCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLAuthRead), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SHCSOProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SHCSOProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - return self.client.CreateIClouduser(conf) -} - -func (self *SHCSOProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { - return self.client.GetICloudusers() -} - -func (self *SHCSOProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroups() -} - -func (self *SHCSOProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroupByName(name) -} - -func (self *SHCSOProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - return self.client.CreateICloudgroup(name, desc) -} - -func (self *SHCSOProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetISystemCloudpolicies() -} - -func (self *SHCSOProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetICustomCloudpolicies() -} - -func (self *SHCSOProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { - return self.client.CreateICloudpolicy(opts) -} - -func (self *SHCSOProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.client.GetIClouduserByName(name) -} - -func (self *SHCSOProvider) GetSamlEntityId() string { - return self.client.GetSamlEntityId() -} - -func (self *SHCSOProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { - return self.client.GetICloudSAMLProviders() -} - -func (self *SHCSOProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { - sp, err := self.client.CreateSAMLProvider(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateSAMLProvider") - } - return sp, nil -} - -func (self *SHCSOProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metrics, err := self.client.GetMetrics(opts) - if err != nil { - return nil, errors.Wrapf(err, "GetMetrics") - } - return metrics, nil -} diff --git a/pkg/multicloud/hcso/quota.go b/pkg/multicloud/hcso/quota.go deleted file mode 100644 index 1cc739441e..0000000000 --- a/pkg/multicloud/hcso/quota.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SQuota struct { - Min int - Quota int - Type string - Used int -} - -func (q *SQuota) GetGlobalId() string { - return q.Type -} - -func (q *SQuota) GetQuotaType() string { - return q.Type -} - -func (q *SQuota) GetName() string { - return q.Type -} - -func (q *SQuota) GetDesc() string { - return "" -} - -func (q *SQuota) GetMaxQuotaCount() int { - return q.Quota -} - -func (q *SQuota) GetCurrentQuotaUsedCount() int { - return q.Used -} - -func (self *SRegion) GetQuotas() ([]SQuota, error) { - quotas := []SQuota{} - params := map[string]string{} - result, err := self.ecsClient.Quotas.Get("", params) - if err != nil { - return nil, errors.Wrap(err, "Quotas.List") - } - - err = result.Unmarshal("as, "resources") - if err != nil { - return nil, errors.Wrap(err, "result.Unmarshal") - } - - return quotas, nil -} - -func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { - quotas, err := region.GetQuotas() - if err != nil { - return nil, errors.Wrap(err, "GetQuotas") - } - ret := []cloudprovider.ICloudQuota{} - for i := range quotas { - ret = append(ret, "as[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/hcso/region.go b/pkg/multicloud/hcso/region.go deleted file mode 100644 index 4266fc917e..0000000000 --- a/pkg/multicloud/hcso/region.go +++ /dev/null @@ -1,1114 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "net/http" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client" - "yunion.io/x/onecloud/pkg/multicloud/huawei/obs" -) - -type Locales struct { - EnUs string `json:"en-us"` - ZhCN string `json:"zh-cn"` -} - -// https://support.huaweicloud.com/api-iam/zh-cn_topic_0067148043.html -type SRegion struct { - multicloud.SRegion - - client *SHuaweiClient - ecsClient *client.Client - obsClient *obs.ObsClient // 对象存储client.请勿直接引用。 - - Description string `json:"description"` - ID string `json:"id"` - Locales Locales `json:"locales"` - ParentRegionID string `json:"parent_region_id"` - Type string `json:"type"` - - izones []cloudprovider.ICloudZone - ivpcs []cloudprovider.ICloudVpc - iskus []cloudprovider.ICloudSku - - storageCache *SStoragecache -} - -func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetClient() *SHuaweiClient { - return self.client -} - -func (self *SRegion) getECSClient() (*client.Client, error) { - var err error - - if len(self.client.projectId) > 0 { - project, err := self.client.GetProjectById(self.client.projectId) - if err != nil { - return nil, err - } - - regionId := strings.Split(project.Name, "_")[0] - if regionId != self.ID { - // log.Debugf("project %s not in region %s", self.client.ProjectId, self.ID) - return nil, errors.Error("region and project mismatch") - } - } - - if self.ecsClient == nil { - self.ecsClient, err = self.client.newRegionAPIClient(self.ID) - if err != nil { - return nil, err - } - } - - return self.ecsClient, err -} - -func (self *SRegion) getOBSEndpoint() string { - return getOBSEndpoint(self.GetId()) -} - -func (self *SRegion) getOBSClient() (*obs.ObsClient, error) { - if self.obsClient == nil { - obsClient, err := self.client.getOBSClient(self.GetId()) - if err != nil { - return nil, err - } - - client := obsClient.GetClient() - ts, _ := client.Transport.(*http.Transport) - client.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { - if self.client.cpcfg.ReadOnly { - if req.Method == "GET" || req.Method == "HEAD" { - return nil, nil - } - return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) - } - return nil, nil - }) - - self.obsClient = obsClient - } - - return self.obsClient, nil -} - -func (self *SRegion) fetchZones() error { - zones := make([]SZone, 0) - err := doListAll(self.ecsClient.Zones.List, nil, &zones) - if err != nil { - return err - } - - self.izones = make([]cloudprovider.ICloudZone, 0) - for i := range zones { - zone := zones[i] - zone.region = self - self.izones = append(self.izones, &zone) - } - return nil -} - -func (self *SRegion) fetchIVpcs() error { - // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html - vpcs := make([]SVpc, 0) - querys := map[string]string{ - "limit": "2048", - } - err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs) - if err != nil { - return err - } - - self.ivpcs = make([]cloudprovider.ICloudVpc, 0) - for i := range vpcs { - vpc := vpcs[i] - vpc.region = self - self.ivpcs = append(self.ivpcs, &vpc) - } - return nil -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - if len(id) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetIVMById") - } - - instance, err := self.GetInstanceByID(id) - if err != nil { - return nil, err - } - - zone, err := self.getZoneById(instance.OSEXTAZAvailabilityZone) - if err != nil { - return nil, errors.Wrap(err, "getZoneById") - } - instance.host = &SHost{ - zone: zone, - vms: nil, - projectId: self.client.projectId, - Id: instance.HostID, - Name: instance.OSEXTSRVATTRHost, - } - return &instance, err -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return self.GetDisk(id) -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - if info, ok := LatitudeAndLongitude[self.ID]; ok { - return info - } - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - elbs, err := self.GetLoadBalancers() - if err != nil { - return nil, err - } - - ielbs := make([]cloudprovider.ICloudLoadbalancer, len(elbs)) - for i := range elbs { - ielbs[i] = &elbs[i] - } - - return ielbs, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561531.html -func (self *SRegion) GetLoadBalancers() ([]SLoadbalancer, error) { - params := map[string]string{} - if len(self.client.projectId) > 0 { - params["project_id"] = self.client.projectId - } - - ret := []SLoadbalancer{} - err := doListAll(self.ecsClient.Elb.List, params, &ret) - if err != nil { - return nil, err - } - - for i := range ret { - ret[i].region = self - } - - return ret, nil -} - -func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { - elb, err := self.GetLoadBalancerById(loadbalancerId) - if err != nil { - return nil, err - } - - return &elb, nil -} - -func (self *SRegion) GetLoadBalancerById(loadbalancerId string) (SLoadbalancer, error) { - elb := SLoadbalancer{} - err := DoGet(self.ecsClient.Elb.Get, loadbalancerId, nil, &elb) - if err != nil { - return elb, err - } - - elb.region = self - return elb, nil -} - -func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { - acl, err := self.GetLoadBalancerAclById(aclId) - if err != nil { - return nil, err - } - - return &acl, nil -} - -func (self *SRegion) GetLoadBalancerAclById(aclId string) (SElbACL, error) { - acl := SElbACL{} - err := DoGet(self.ecsClient.ElbWhitelist.Get, aclId, nil, &acl) - if err != nil { - return acl, err - } - - acl.region = self - return acl, nil -} - -func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - cert, err := self.GetLoadBalancerCertificateById(certId) - if err != nil { - return nil, err - } - - return &cert, nil -} - -func (self *SRegion) GetLoadBalancerCertificateById(certId string) (SElbCert, error) { - ret := SElbCert{} - err := DoGet(self.ecsClient.ElbCertificates.Get, certId, nil, &ret) - if err != nil { - return ret, err - } - - ret.region = self - return ret, nil -} - -func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - ret, err := self.CreateLoadBalancerCertificate(cert) - if err != nil { - return nil, err - } - - return &ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561584.html -func (self *SRegion) CreateLoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (SElbCert, error) { - params := jsonutils.NewDict() - params.Set("name", jsonutils.NewString(cert.Name)) - params.Set("private_key", jsonutils.NewString(cert.PrivateKey)) - params.Set("certificate", jsonutils.NewString(cert.Certificate)) - - ret := SElbCert{} - err := DoCreate(self.ecsClient.ElbCertificates.Create, params, &ret) - if err != nil { - return ret, err - } - - ret.region = self - return ret, nil -} - -func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { - ret, err := self.GetLoadBalancerAcls("") - if err != nil { - return nil, err - } - - iret := make([]cloudprovider.ICloudLoadbalancerAcl, len(ret)) - for i := range ret { - iret[i] = &ret[i] - } - return iret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561582.html -func (self *SRegion) GetLoadBalancerAcls(listenerId string) ([]SElbACL, error) { - params := map[string]string{} - if len(listenerId) > 0 { - params["listener_id"] = listenerId - } - - ret := []SElbACL{} - err := doListAll(self.ecsClient.ElbWhitelist.List, params, &ret) - if err != nil { - return nil, err - } - - for i := range ret { - ret[i].region = self - } - - return ret, nil -} - -func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - ret, err := self.GetLoadBalancerCertificates() - if err != nil { - return nil, err - } - - iret := make([]cloudprovider.ICloudLoadbalancerCertificate, len(ret)) - for i := range ret { - iret[i] = &ret[i] - } - return iret, nil -} - -func (self *SRegion) GetLoadBalancerCertificates() ([]SElbCert, error) { - ret := []SElbCert{} - err := doListAll(self.ecsClient.ElbCertificates.List, nil, &ret) - if err != nil { - return nil, err - } - - for i := range ret { - ret[i].region = self - } - - return ret, nil -} - -// https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845622.html -func (self *SRegion) GetId() string { - return self.ID -} - -func (self *SRegion) GetName() string { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.Locales.ZhCN) -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.Locales.EnUs) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", api.CLOUD_PROVIDER_HCSO, self.ID) -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) Refresh() error { - return nil -} - -func (self *SRegion) IsEmulated() bool { - return false -} - -func (self *SRegion) GetLatitude() float32 { - if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok { - return locationInfo.Latitude - } - return 0.0 -} - -func (self *SRegion) GetLongitude() float32 { - if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok { - return locationInfo.Longitude - } - return 0.0 -} - -func (self *SRegion) fetchInfrastructure() error { - _, err := self.getECSClient() - if 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 { - vpc := self.ivpcs[i].(*SVpc) - wire := SWire{region: self, vpc: vpc} - vpc.addWire(&wire) - - for j := 0; j < len(self.izones); j += 1 { - zone := self.izones[j].(*SZone) - zone.addWire(&wire) - } - } - return nil -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if self.izones == nil { - var err error - err = self.fetchInfrastructure() - if 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) GetEipById(eipId string) (SEipAddress, error) { - var eip SEipAddress - err := DoGet(self.ecsClient.Eips.Get, eipId, nil, &eip) - eip.region = self - return eip, err -} - -// 返回参数分别为eip 列表、列表长度、error。 -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html -func (self *SRegion) GetEips() ([]SEipAddress, error) { - querys := make(map[string]string) - - eips := make([]SEipAddress, 0) - err := doListAllWithMarker(self.ecsClient.Eips.List, querys, &eips) - for i := range eips { - eips[i].region = self - } - return eips, err -} - -func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - _, err := self.getECSClient() - if err != nil { - return nil, err - } - - eips, err := self.GetEips() - if err != nil { - return nil, err - } - - ret := make([]cloudprovider.ICloudEIP, len(eips)) - for i := 0; i < len(eips); i += 1 { - eips[i].region = self - ret[i] = &eips[i] - } - return ret, nil -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - ivpcs, err := self.GetIVpcs() - if err != nil { - return nil, err - } - for i := 0; i < len(ivpcs); i += 1 { - if ivpcs[i].GetGlobalId() == id { - return ivpcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { - eip, err := self.GetEipById(eipId) - return &eip, err -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0060595555.html -func (self *SRegion) DeleteSecurityGroup(secgroupId string) error { - return DoDelete(self.ecsClient.SecurityGroups.Delete, secgroupId, nil, nil) -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - return self.GetSecurityGroupDetails(secgroupId) -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := self.GetSecurityGroups(opts.VpcId, opts.Name) - if err != nil { - return nil, err - } - if len(secgroups) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(secgroups) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - secgroups[0].region = self - return &secgroups[0], nil -} - -func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - return self.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090608.html -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - return self.CreateVpc(opts.NAME, opts.CIDR, opts.Desc) -} - -func (self *SRegion) CreateVpc(name, cidr, desc string) (*SVpc, error) { - params := map[string]interface{}{ - "vpc": map[string]string{ - "name": name, - "cidr": cidr, - "description": desc, - }, - } - vpc := &SVpc{region: self} - return vpc, DoCreate(self.ecsClient.Vpcs.Create, jsonutils.Marshal(params), vpc) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html -// size: 1Mbit/s~2000Mbit/s -// bgpType: 5_telcom,5_union,5_bgp,5_sbgp. -// 东北-大连:5_telcom、5_union -// 华南-广州:5_sbgp -// 华东-上海二:5_sbgp -// 华北-北京一:5_bgp、5_sbgp -// 亚太-香港:5_bgp -func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - var ctype TInternetChargeType - switch eip.ChargeType { - case api.EIP_CHARGE_TYPE_BY_TRAFFIC: - ctype = InternetChargeByTraffic - case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: - ctype = InternetChargeByBandwidth - } - - if len(eip.BGPType) == 0 { - eip.BGPType = "5_bgp" - } - - // 华为云EIP名字最大长度64 - if len(eip.Name) > 64 { - eip.Name = eip.Name[:64] - } - - ieip, err := self.AllocateEIP(eip.Name, eip.BandwidthMbps, ctype, eip.BGPType, eip.ProjectId) - ieip.region = self - if err != nil { - return nil, err - } - - err = cloudprovider.WaitStatus(ieip, api.EIP_STATUS_READY, 5*time.Second, 60*time.Second) - return ieip, err -} - -func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := self.GetSnapshots("", "") - if err != nil { - log.Errorf("self.GetSnapshots fail %s", err) - return nil, err - } - - ret := make([]cloudprovider.ICloudSnapshot, len(snapshots)) - for i := 0; i < len(snapshots); i += 1 { - snapshots[i].region = self - ret[i] = &snapshots[i] - } - return ret, nil -} - -func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := self.GetSnapshotById(snapshotId) - return &snapshot, err -} - -func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - iHosts := make([]cloudprovider.ICloudHost, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneHost, err := izones[i].GetIHosts() - if err != nil { - return nil, err - } - iHosts = append(iHosts, iZoneHost...) - } - return iHosts, nil -} - -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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetProvider() string { - return CLOUD_PROVIDER_HUAWEI -} - -func (self *SRegion) GetCloudEnv() string { - return "" -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html -// 目前desc字段并没有用到 -func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (*SSecurityGroup, error) { - // 华为不允许创建名称为default的安全组 - if strings.ToLower(name) == "default" { - name = fmt.Sprintf("%s-%s", vpcId, name) - } - - params := jsonutils.NewDict() - secgroupObj := jsonutils.NewDict() - secgroupObj.Add(jsonutils.NewString(name), "name") - if len(vpcId) > 0 && vpcId != api.NORMAL_VPC_ID { - secgroupObj.Add(jsonutils.NewString(vpcId), "vpc_id") - } - params.Add(secgroupObj, "security_group") - - secgroup := SSecurityGroup{region: self} - err := DoCreate(self.ecsClient.SecurityGroups.Create, params, &secgroup) - return &secgroup, err -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087467071.html -func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error { - _, err := self.ecsClient.SecurityGroupRules.DeleteInContextWithSpec(nil, secGrpRuleId, "", nil, nil, "") - return err -} - -func (self *SRegion) DeleteSecurityGroupRule(ruleId string) error { - return self.delSecurityGroupRule(ruleId) -} - -func (self *SRegion) CreateSecurityGroupRule(secgroupId string, rule cloudprovider.SecurityRule) error { - return self.addSecurityGroupRules(secgroupId, rule) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087451723.html -// icmp port对应关系:https://support.huaweicloud.com/api-vpc/zh-cn_topic_0024109590.html -func (self *SRegion) addSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error { - direction := "" - if rule.Direction == secrules.SecurityRuleIngress { - direction = "ingress" - } else { - direction = "egress" - } - - protocal := rule.Protocol - if rule.Protocol == secrules.PROTO_ANY { - protocal = "" - } - - // imcp协议默认为any - if rule.Protocol == secrules.PROTO_ICMP { - return self.addSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String()) - } - - if len(rule.Ports) > 0 { - for _, port := range rule.Ports { - portStr := fmt.Sprintf("%d", port) - err := self.addSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String()) - if err != nil { - return err - } - } - } else { - portStart := fmt.Sprintf("%d", rule.PortStart) - portEnd := fmt.Sprintf("%d", rule.PortEnd) - err := self.addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String()) - if err != nil { - return err - } - } - - return nil -} - -func (self *SRegion) addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error { - params := jsonutils.NewDict() - secgroupObj := jsonutils.NewDict() - secgroupObj.Add(jsonutils.NewString(secGrpId), "security_group_id") - secgroupObj.Add(jsonutils.NewString(direction), "direction") - secgroupObj.Add(jsonutils.NewString(ipNet), "remote_ip_prefix") - secgroupObj.Add(jsonutils.NewString("IPV4"), "ethertype") - // 端口为空或者1-65535 - if len(portStart) > 0 && portStart != "0" && portStart != "-1" { - secgroupObj.Add(jsonutils.NewString(portStart), "port_range_min") - } - if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" { - secgroupObj.Add(jsonutils.NewString(portEnd), "port_range_max") - } - if len(protocol) > 0 { - secgroupObj.Add(jsonutils.NewString(protocol), "protocol") - } - params.Add(secgroupObj, "security_group_rule") - - rule := SecurityGroupRule{} - return DoCreate(self.ecsClient.SecurityGroupRules.Create, params, &rule) -} - -func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - ret, err := self.CreateLoadBalancer(loadbalancer) - if err != nil { - return nil, err - } - - return &ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561535.html -func (self *SRegion) CreateLoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (SLoadbalancer, error) { - ret := SLoadbalancer{} - subnet, err := self.getNetwork(loadbalancer.NetworkIDs[0]) - if err != nil { - return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.getNetwork") - } - - params := jsonutils.NewDict() - elbObj := jsonutils.NewDict() - elbObj.Set("name", jsonutils.NewString(loadbalancer.Name)) - elbObj.Set("vip_subnet_id", jsonutils.NewString(subnet.NeutronSubnetID)) - if len(loadbalancer.Address) > 0 { - elbObj.Set("vip_address", jsonutils.NewString(loadbalancer.Address)) - } - elbObj.Set("tenant_id", jsonutils.NewString(self.client.projectId)) - params.Set("loadbalancer", elbObj) - - err = DoCreate(self.ecsClient.Elb.Create, params, &ret) - if err != nil { - return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.DoCreate") - } - - ret.region = self - - // 创建公网类型ELB - if len(loadbalancer.EipID) > 0 { - err := self.AssociateEipWithPortId(loadbalancer.EipID, ret.VipPortID) - if err != nil { - return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.AssociateEipWithPortId") - } - } - return ret, nil -} - -func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - ret, err := self.CreateLoadBalancerAcl(acl) - if err != nil { - return nil, err - } - - return &ret, nil -} - -func (self *SRegion) CreateLoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (SElbACL, error) { - params := jsonutils.NewDict() - aclObj := jsonutils.NewDict() - aclObj.Set("listener_id", jsonutils.NewString(acl.ListenerId)) - if len(acl.Entrys) > 0 { - whitelist := []string{} - for i := range acl.Entrys { - whitelist = append(whitelist, acl.Entrys[i].CIDR) - } - - aclObj.Set("enable_whitelist", jsonutils.NewBool(acl.AccessControlEnable)) - aclObj.Set("whitelist", jsonutils.NewString(strings.Join(whitelist, ","))) - } else { - aclObj.Set("enable_whitelist", jsonutils.NewBool(false)) - } - params.Set("whitelist", aclObj) - - ret := SElbACL{} - err := DoCreate(self.ecsClient.ElbWhitelist.Create, params, &ret) - if err != nil { - return ret, err - } - - ret.region = self - return ret, nil -} - -func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - iBuckets, err := region.client.getIBuckets() - if err != nil { - return nil, errors.Wrap(err, "getIBuckets") - } - ret := make([]cloudprovider.ICloudBucket, 0) - for i := range iBuckets { - // huawei OBS is shared across projects - if iBuckets[i].GetLocation() == region.GetId() { - ret = append(ret, iBuckets[i]) - } - } - return ret, nil -} - -func str2StorageClass(storageClassStr string) (obs.StorageClassType, error) { - if strings.EqualFold(storageClassStr, string(obs.StorageClassStandard)) { - return obs.StorageClassStandard, nil - } else if strings.EqualFold(storageClassStr, string(obs.StorageClassWarm)) { - return obs.StorageClassWarm, nil - } else if strings.EqualFold(storageClassStr, string(obs.StorageClassCold)) { - return obs.StorageClassCold, nil - } else { - return obs.StorageClassStandard, errors.Error("unsupported storageClass") - } -} - -func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { - obsClient, err := region.getOBSClient() - if err != nil { - return errors.Wrap(err, "region.getOBSClient") - } - input := &obs.CreateBucketInput{} - input.Bucket = name - input.Location = region.GetId() - if len(aclStr) > 0 { - if strings.EqualFold(aclStr, string(obs.AclPrivate)) { - input.ACL = obs.AclPrivate - } else if strings.EqualFold(aclStr, string(obs.AclPublicRead)) { - input.ACL = obs.AclPublicRead - } else if strings.EqualFold(aclStr, string(obs.AclPublicReadWrite)) { - input.ACL = obs.AclPublicReadWrite - } else { - return errors.Error("unsupported acl") - } - } - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return err - } - } - _, err = obsClient.CreateBucket(input) - if err != nil { - return errors.Wrap(err, "obsClient.CreateBucket") - } - region.client.invalidateIBuckets() - return nil -} - -func obsHttpCode(err error) int { - switch httpErr := err.(type) { - case obs.ObsError: - return httpErr.StatusCode - case *obs.ObsError: - return httpErr.StatusCode - } - return -1 -} - -func (region *SRegion) DeleteIBucket(name string) error { - obsClient, err := region.getOBSClient() - if err != nil { - return errors.Wrap(err, "region.getOBSClient") - } - _, err = obsClient.DeleteBucket(name) - if err != nil { - if obsHttpCode(err) == 404 { - return nil - } - log.Debugf("%#v %s", err, err) - return errors.Wrap(err, "DeleteBucket") - } - region.client.invalidateIBuckets() - return nil -} - -func (region *SRegion) HeadBucket(name string) (*obs.BaseModel, error) { - obsClient, err := region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "region.getOBSClient") - } - return obsClient.HeadBucket(name) -} - -func (region *SRegion) IBucketExist(name string) (bool, error) { - _, err := region.HeadBucket(name) - if err != nil { - if obsHttpCode(err) == 404 { - return false, nil - } else { - return false, errors.Wrap(err, "HeadBucket") - } - } - return true, nil -} - -func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { - return cloudprovider.GetIBucketById(region, name) -} - -func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { - return region.GetIBucketById(name) -} - -func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) { - if self.iskus != nil { - return self.iskus, nil - } - - ret := make([]cloudprovider.ICloudSku, 0) - flavors, err := self.fetchInstanceTypes(zoneId) - if err != nil { - return nil, errors.Wrap(err, "fetchInstanceTypes") - } - - for i := range flavors { - ret = append(ret, &flavors[i]) - } - - self.iskus = ret - return ret, nil -} - -func (self *SRegion) GetICloudSku(skuId string) (cloudprovider.ICloudSku, error) { - skus, err := self.GetSkus("") - if err != nil { - return nil, err - } - - for i := range skus { - if skus[i].GetId() == skuId { - return skus[i], nil - } - } - - return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetICloudSku") -} - -func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { - caches, err := self.GetElasticCaches() - if err != nil { - return nil, err - } - - icaches := make([]cloudprovider.ICloudElasticcache, len(caches)) - for i := range caches { - caches[i].region = self - icaches[i] = &caches[i] - } - - return icaches, nil -} - -func (region *SRegion) GetCapabilities() []string { - return region.client.GetCapabilities() -} - -func (self *SRegion) GetDiskTypes() ([]SDiskType, error) { - ret, err := self.ecsClient.Disks.GetDiskTypes() - if err != nil { - return nil, errors.Wrap(err, "GetDiskTypes") - } - - dts := []SDiskType{} - _ret := jsonutils.NewArray(ret.Data...) - err = _ret.Unmarshal(&dts) - if err != nil { - return nil, errors.Wrap(err, "Unmarshal") - } - - return dts, nil -} - -func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) { - dts, err := self.GetDiskTypes() - if err != nil { - return nil, errors.Wrap(err, "GetDiskTypes") - } - - ret := []string{} - for i := range dts { - if dts[i].IsAvaliableInZone(zoneId) { - ret = append(ret, dts[i].Name) - } - } - - return ret, nil -} - -func (self *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { - return self.GetSkus("") -} - -func (self *SRegion) GetEndpoints() ([]jsonutils.JSONObject, error) { - endpoints := make([]jsonutils.JSONObject, 0) - err := doListAll(self.ecsClient.Endpoints.List, nil, &endpoints) - if err != nil { - return nil, err - } - - return endpoints, nil -} - -func (self *SRegion) GetServices() ([]jsonutils.JSONObject, error) { - services := make([]jsonutils.JSONObject, 0) - err := doListAll(self.ecsClient.Services.List, nil, &services) - if err != nil { - return nil, err - } - - return services, nil -} diff --git a/pkg/multicloud/hcso/roles.go b/pkg/multicloud/hcso/roles.go deleted file mode 100644 index fe63dca88e..0000000000 --- a/pkg/multicloud/hcso/roles.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/cloudid" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SRole struct { - DomainId string - Flag string - DescriptionCn string - Catelog string - Description string - Id string - DisplayName string - Type string - UpdatedTime string - CreatedTime string - Links SLink - Policy jsonutils.JSONDict - roleType string -} - -func (role *SRole) GetName() string { - return role.DisplayName -} - -func (role *SRole) GetDescription() string { - return role.DescriptionCn -} - -func (role *SRole) GetPolicyType() string { - return role.roleType -} - -func (role *SRole) GetGlobalId() string { - return role.DisplayName -} - -func (role *SRole) UpdateDocument(document *jsonutils.JSONDict) error { - return cloudprovider.ErrNotImplemented -} - -func (role *SRole) GetDocument() (*jsonutils.JSONDict, error) { - return &role.Policy, nil -} - -func (role *SRole) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (self *SHuaweiClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - roles, err := self.GetRoles("", "") - if err != nil { - return nil, errors.Wrap(err, "GetRoles") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range roles { - roles[i].roleType = api.CLOUD_POLICY_TYPE_SYSTEM - ret = append(ret, &roles[i]) - } - return ret, nil -} - -func (self *SHuaweiClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - roles, err := self.GetCustomRoles() - if err != nil { - return nil, errors.Wrap(err, "GetCustomRoles") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range roles { - roles[i].roleType = api.CLOUD_POLICY_TYPE_CUSTOM - ret = append(ret, &roles[i]) - } - return ret, nil -} - -func (self *SHuaweiClient) GetCustomRoles() ([]SRole, error) { - params := map[string]string{} - - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - client.Roles.SetVersion("v3.0/OS-ROLE") - defer client.Roles.SetVersion("v3.0") - - roles := []SRole{} - err = doListAllWithNextLink(client.Roles.List, params, &roles) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return roles, nil -} - -func (self *SHuaweiClient) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - client.Roles.SetVersion("v3.0/OS-ROLE") - defer client.Roles.SetVersion("v3.0") - - params := map[string]interface{}{ - "role": map[string]interface{}{ - "display_name": opts.Name, - "type": "XA", - "description": opts.Desc, - "policy": opts.Document, - }, - } - - resp, err := client.Roles.Create(jsonutils.Marshal(params)) - if err != nil { - return nil, err - } - role := &SRole{roleType: api.CLOUD_POLICY_TYPE_CUSTOM} - err = resp.Unmarshal(role) - if err != nil { - return nil, err - } - return role, nil -} - -func (self *SHuaweiClient) GetRoles(domainId, name string) ([]SRole, error) { - params := map[string]string{} - if len(domainId) > 0 { - params["domain_id"] = self.ownerId - } - if len(name) > 0 { - params["display_name"] = name - } - - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - roles := []SRole{} - err = doListAllWithNextLink(client.Roles.List, params, &roles) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return roles, nil -} diff --git a/pkg/multicloud/hcso/routetable.go b/pkg/multicloud/hcso/routetable.go deleted file mode 100644 index 95881b23a7..0000000000 --- a/pkg/multicloud/hcso/routetable.go +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// date: 2019.07.15 -// In Huawei cloud, there are only two routing tables in a vpc, which are -// self-defined routing tables and peer-to-peer routing tables. -// The routing in these two tables is different, one's NextHop is a IP address and -// the other one's NextHop address is a instance ID of peer-to-peer connection. -// The former has no id and it's Type is ROUTE_TYPR_IP, and the latter's Type is ROUTE_TYPE_PEER. - -const ( - ROUTE_TYPR_IP = "IP" - ROUTE_TYPE_PEER = "peering" -) - -type SRouteEntry struct { - multicloud.SResourceBase - multicloud.HuaweiTags - routeTable *SRouteTable - - ID string // route ID - Type string // route type - Destination string // route destination - NextHop string // route next hop (ip or id) -} - -func (route *SRouteEntry) GetId() string { - if len(route.ID) == 0 { - return route.Destination + ":" + route.NextHop - } - return route.ID -} - -func (route *SRouteEntry) GetName() string { - return "" -} - -func (route *SRouteEntry) GetGlobalId() string { - return route.GetId() -} - -func (route *SRouteEntry) GetStatus() string { - return api.ROUTE_ENTRY_STATUS_AVAILIABLE -} - -func (route *SRouteEntry) Refresh() error { - return nil -} - -func (route *SRouteEntry) IsEmulated() bool { - return false -} - -func (route *SRouteEntry) GetType() string { - if route.Type == ROUTE_TYPE_PEER { - return api.ROUTE_ENTRY_TYPE_CUSTOM - } - return api.ROUTE_ENTRY_TYPE_SYSTEM -} - -func (route *SRouteEntry) GetCidr() string { - return route.Destination -} - -func (route *SRouteEntry) GetNextHopType() string { - // In Huawei Cloud, NextHopType is same with itself - switch route.Type { - case ROUTE_TYPE_PEER: - return api.NEXT_HOP_TYPE_VPCPEERING - default: - return "" - } -} - -func (route *SRouteEntry) GetNextHop() string { - return route.NextHop -} - -// SRouteTable has no ID and Name because there is no id or name of route table in huawei cloud. -// And some method such as GetId and GetName of ICloudRouteTable has no practical meaning -type SRouteTable struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - vpc *SVpc - - VpcId string - Description string - Type string - Routes []*SRouteEntry -} - -func NewSRouteTable(vpc *SVpc, Type string) SRouteTable { - return SRouteTable{ - region: vpc.region, - vpc: vpc, - Type: Type, - VpcId: vpc.GetId(), - } - -} - -func (self *SRouteTable) GetId() string { - return self.GetGlobalId() -} - -func (self *SRouteTable) GetName() string { - return "" -} - -func (self *SRouteTable) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.GetVpcId(), self.GetType()) -} - -func (self *SRouteTable) GetStatus() string { - return api.ROUTE_TABLE_AVAILABLE -} - -func (self *SRouteTable) Refresh() error { - return nil -} - -func (self *SRouteTable) IsEmulated() bool { - return false -} - -func (self *SRouteTable) GetDescription() string { - return self.Description -} - -func (self *SRouteTable) GetRegionId() string { - return self.region.GetId() -} - -func (self *SRouteTable) GetVpcId() string { - return self.VpcId -} - -func (self *SRouteTable) GetType() cloudprovider.RouteTableType { - return cloudprovider.RouteTableTypeSystem -} - -func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { - if self.Routes == nil { - err := self.fetchRoutes() - if err != nil { - return nil, err - } - } - ret := []cloudprovider.ICloudRoute{} - for i := range self.Routes { - ret = append(ret, self.Routes[i]) - } - return ret, nil -} - -// fetchRoutes fetch Routes -func (self *SRouteTable) fetchRoutes() error { - if self.Type == ROUTE_TYPR_IP { - return self.fetchRoutesForIP() - } - return self.fetchRoutesForPeer() -} - -// fetchRoutesForIP fetch the Routes which Type is ROUTE_TYPR_IP through vpc's get api -func (self *SRouteTable) fetchRoutesForIP() error { - ret, err := self.region.ecsClient.Vpcs.Get(self.GetVpcId(), map[string]string{}) - if err != nil { - return errors.Wrap(err, "get vpc info error") - } - routeArray, err := ret.GetArray("routes") - routes := make([]*SRouteEntry, 0, len(routeArray)) - for i := range routeArray { - destination, err := routeArray[i].GetString("destination") - if err != nil { - return errors.Wrap(err, "get destination of route error") - } - nextHop, err := routeArray[i].GetString("nexthop") - if err != nil { - return errors.Wrap(err, "get nexthop of route error") - } - routes = append(routes, &SRouteEntry{ - routeTable: self, - ID: "", - Type: ROUTE_TYPR_IP, - Destination: destination, - NextHop: nextHop, - }) - } - self.Routes = routes - return nil -} - -// fetchRoutesForPeer fetch the routes which Type is ROUTE_TYPE_PEER through vpcRoute's list api -func (self *SRouteTable) fetchRoutesForPeer() error { - retPeer, err := self.region.ecsClient.VpcRoutes.List(map[string]string{"vpc_id": self.GetVpcId()}) - if err != nil { - return errors.Wrap(err, "get peer route error") - } - routesPeer := make([]*SRouteEntry, 0, retPeer.Total) - for i := range retPeer.Data { - route := retPeer.Data[i] - id, err := route.GetString("id") - if err != nil { - return errors.Wrap(err, "get id of peer route error") - } - destination, err := route.GetString("destination") - if err != nil { - return errors.Wrap(err, "get destination of peer route error") - } - nextHop, err := route.GetString("nexthop") - if err != nil { - return errors.Wrap(err, "get nexthop of peer route error") - } - routesPeer = append(routesPeer, &SRouteEntry{ - routeTable: self, - ID: id, - Type: ROUTE_TYPE_PEER, - Destination: destination, - NextHop: nextHop, - }) - } - self.Routes = routesPeer - return nil -} - -func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { - result := []cloudprovider.RouteTableAssociation{} - return result -} - -func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { - if route.NextHopType != api.NEXT_HOP_TYPE_VPCPEERING { - return cloudprovider.ErrNotSupported - } - err := self.region.CreatePeeringRoute(self.vpc.GetId(), route.Destination, route.NextHop) - if err != nil { - return errors.Wrapf(err, " self.region.CreatePeeringRoute(%s,%s,%s)", self.vpc.GetId(), route.Destination, route.NextHop) - } - return nil -} - -func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { - err := self.RemoveRoute(route) - if err != nil { - return errors.Wrap(err, "self.RemoveRoute(route)") - } - err = self.CreateRoute(route) - if err != nil { - return errors.Wrap(err, "self.CreateRoute(route)") - } - return nil -} - -func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { - err := self.region.DeletePeeringRoute(route.RouteId) - if err != nil { - return errors.Wrapf(err, "self.region.DeletePeeringRoute(%s)", route.RouteId) - } - return nil -} - -// GetRouteTables return []SRouteTable of self -func (self *SVpc) getRouteTables() ([]SRouteTable, error) { - // every Vpc has two route table in Huawei Cloud - routeTableIp := NewSRouteTable(self, ROUTE_TYPR_IP) - routeTablePeer := NewSRouteTable(self, ROUTE_TYPE_PEER) - if err := routeTableIp.fetchRoutesForIP(); err != nil { - return nil, errors.Wrap(err, `get route table whilc type is "ip" error`) - } - if err := routeTablePeer.fetchRoutesForPeer(); err != nil { - return nil, errors.Wrap(err, `get route table whilc type is "peering" error`) - } - ret := make([]SRouteTable, 0, 2) - if len(routeTableIp.Routes) != 0 { - ret = append(ret, routeTableIp) - } - if len(routeTablePeer.Routes) != 0 { - ret = append(ret, routeTablePeer) - } - return ret, nil -} - -// GetRouteTables return []SRouteTable of vpc which id is vpcId if vpcId is no-nil, -// otherwise return []SRouteTable of all vpc in this SRegion -func (self *SRegion) GetRouteTables(vpcId string) ([]SRouteTable, error) { - vpcs, err := self.GetVpcs() - if err != nil { - return nil, errors.Wrap(err, "Get Vpcs error") - } - if vpcId != "" { - for i := range vpcs { - if vpcs[i].GetId() == vpcId { - vpcs = vpcs[i : i+1] - break - } - } - } - ret := make([]SRouteTable, 0, 2*len(vpcs)) - for _, vpc := range vpcs { - routetables, err := vpc.getRouteTables() - if err != nil { - return nil, errors.Wrapf(err, "get vpc's route tables whilch id is %s error", vpc.GetId()) - } - ret = append(ret, routetables...) - - } - return ret, nil -} - -func (self *SRegion) CreatePeeringRoute(vpcId, destinationCidr, target string) error { - params := jsonutils.NewDict() - routeObj := jsonutils.NewDict() - routeObj.Set("type", jsonutils.NewString("peering")) - routeObj.Set("nexthop", jsonutils.NewString(target)) - routeObj.Set("destination", jsonutils.NewString(destinationCidr)) - routeObj.Set("vpc_id", jsonutils.NewString(vpcId)) - params.Set("route", routeObj) - err := DoCreate(self.ecsClient.VpcRoutes.Create, params, nil) - if err != nil { - return errors.Wrapf(err, "DoCreate(self.ecsClient.VpcRoutes.Create, %s, &ret)", jsonutils.Marshal(params).String()) - } - return nil -} - -func (self *SRegion) DeletePeeringRoute(routeId string) error { - err := DoDelete(self.ecsClient.VpcRoutes.Delete, routeId, nil, nil) - if err != nil { - return errors.Wrapf(err, "DoDelete(self.ecsClient.VpcRoutes.Delete,%s,nil)", routeId) - } - return nil -} diff --git a/pkg/multicloud/hcso/saml_provider.go b/pkg/multicloud/hcso/saml_provider.go deleted file mode 100644 index 639b51cdc4..0000000000 --- a/pkg/multicloud/hcso/saml_provider.go +++ /dev/null @@ -1,349 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "time" - "unicode" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/stringutils" - - api "yunion.io/x/onecloud/pkg/apis/cloudid" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/modules" - "yunion.io/x/onecloud/pkg/util/samlutils" -) - -type SAMLProviderLinks struct { - Self string - Protocols string -} - -type SAMLProvider struct { - multicloud.SResourceBase - multicloud.HuaweiTags - client *SHuaweiClient - - Id string - Links SAMLProviderLinks - Description string -} - -func (self *SAMLProvider) GetId() string { - return self.Id -} - -func (self *SAMLProvider) GetGlobalId() string { - return self.Id -} - -func (self *SAMLProvider) GetName() string { - return self.Id -} - -func (self *SAMLProvider) GetStatus() string { - mapping, _ := self.client.findMapping() - if mapping != nil { - return api.SAML_PROVIDER_STATUS_AVAILABLE - } - return api.SAML_PROVIDER_STATUS_UNVALIABLE -} - -func (self *SAMLProvider) GetAuthUrl() string { - return fmt.Sprintf("https://auth.%s/authui/federation/websso?domain_id=%s&idp=%s&protocol=saml", self.client.endpoints.EndpointDomain, self.client.ownerId, self.Id) -} - -func (self *SAMLProvider) Delete() error { - return self.client.DeleteSAMLProvider(self.Id) -} - -func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { - info, err := self.client.GetSAMLProviderMetadata(self.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetSAMLProviderMetadata(%s)", self.Id) - } - metadata, err := samlutils.ParseMetadata([]byte(info.Data)) - if err != nil { - return nil, errors.Wrapf(err, "ParseMetadata") - } - return &metadata, nil -} - -func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { - return self.client.UpdateSAMLProviderMetadata(self.Id, metadata.String()) -} - -func (self *SHuaweiClient) ListSAMLProviders() ([]SAMLProvider, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrapf(err, "newGeneralAPIClient") - } - samls := []SAMLProvider{} - err = doListAllWithNextLink(client.SAMLProviders.List, nil, &samls) - if err != nil { - return nil, errors.Wrapf(err, "doListAll") - } - return samls, nil -} - -type SAMLProviderProtocol struct { - MappingId string - Id string -} - -func (self *SHuaweiClient) GetSAMLProviderProtocols(id string) ([]SAMLProviderProtocol, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - resp, err := client.SAMLProviders.ListInContextWithSpec(nil, fmt.Sprintf("%s/protocols", id), nil, "protocols") - if err != nil { - return nil, errors.Wrapf(err, "ListInContextWithSpec") - } - protocols := []SAMLProviderProtocol{} - return protocols, jsonutils.Update(&protocols, resp.Data) -} - -func (self *SHuaweiClient) DeleteSAMLProviderProtocol(spId, id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.SAMLProviders.DeleteInContextWithSpec(nil, spId, fmt.Sprintf("protocols/%s", id), nil, nil, "") - return err -} - -type SAMLProviderMetadata struct { - DomainId string - UpdateTime time.Time - Data string - IdpId string - ProtocolId string - Id string - EntityId string - XaccountType string -} - -func (self *SHuaweiClient) GetSAMLProviderMetadata(id string) (*SAMLProviderMetadata, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION") - resp, err := client.SAMLProviders.GetInContextWithSpec(nil, id, fmt.Sprintf("protocols/saml/metadata"), nil, "") - if err != nil { - return nil, err - } - - metadata := &SAMLProviderMetadata{} - err = resp.Unmarshal(metadata) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return metadata, nil -} - -func (self *SHuaweiClient) UpdateSAMLProviderMetadata(id, metadata string) error { - params := map[string]string{ - "domain_id": self.ownerId, - "xaccount_type": "", - "metadata": metadata, - } - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION") - _, err = client.SAMLProviders.PerformAction2("protocols/saml/metadata", id, jsonutils.Marshal(params), "") - if err != nil { - return errors.Wrapf(err, "SAMLProvider.PerformAction") - } - return nil -} - -func (self *SHuaweiClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { - samls, err := self.ListSAMLProviders() - if err != nil { - return nil, errors.Wrapf(err, "ListSAMLProviders") - } - ret := []cloudprovider.ICloudSAMLProvider{} - for i := range samls { - samls[i].client = self - ret = append(ret, &samls[i]) - } - return ret, nil -} - -func (self *SHuaweiClient) DeleteSAMLProvider(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.SAMLProviders.Delete(id, nil) - return err -} - -func (self *SHuaweiClient) CreateSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (*SAMLProvider, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - params := jsonutils.Marshal(map[string]interface{}{ - "identity_provider": map[string]interface{}{ - "description": opts.Name, - "enabled": true, - }, - }) - opts.Name = fmt.Sprintf("%s-%s", self.ownerName, opts.Name) - name := []byte{} - for _, c := range opts.Name { - if unicode.IsLetter(c) || unicode.IsNumber(c) || c == '-' || c == '_' { - name = append(name, byte(c)) - } else { - name = append(name, '-') - } - } - opts.Name = string(name) - _, err = client.SAMLProviders.Update(opts.Name, params) - if err != nil { - if he, ok := err.(*modules.HuaweiClientError); ok && he.Code != 409 { - return nil, errors.Wrapf(err, "SAMLProviders.Update") - } - } - ret := SAMLProvider{client: self, Id: opts.Name} - err = self.UpdateSAMLProviderMetadata(opts.Name, opts.Metadata.String()) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - err = self.InitSAMLProviderMapping(opts.Name) - if err != nil { - return nil, errors.Wrapf(err, "InitSAMLProviderMapping") - } - return &ret, nil -} - -type SAMLProviderMapping struct { - Id string - Rules jsonutils.JSONObject -} - -var ( - onecloudMappingRules = jsonutils.Marshal(map[string]interface{}{ - "rules": []map[string]interface{}{ - { - "remote": []map[string]interface{}{ - { - "type": "User", - }, - { - "type": "Groups", - }, - }, - "local": []map[string]interface{}{ - { - "groups": "{1}", - "user": map[string]string{"name": "{0}"}, - }, - }, - }, - }, - }) -) - -func (self *SHuaweiClient) ListSAMLProviderMappings() ([]SAMLProviderMapping, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - mappings := []SAMLProviderMapping{} - err = doListAllWithNextLink(client.SAMLProviderMappings.List, nil, &mappings) - if err != nil { - return nil, err - } - return mappings, nil -} - -func (self *SHuaweiClient) findMapping() (*SAMLProviderMapping, error) { - mappings, err := self.ListSAMLProviderMappings() - if err != nil { - return nil, errors.Wrapf(err, "ListSAMLProviderMappings") - } - for i := range mappings { - if jsonutils.Marshal(map[string]interface{}{"rules": mappings[i].Rules}).Equals(jsonutils.Marshal(onecloudMappingRules)) { - return &mappings[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHuaweiClient) InitSAMLProviderMapping(spId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - - mapping, err := self.findMapping() - if err != nil { - if errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrapf(err, "findMapping") - } - mappingId := stringutils.UUID4() - params := map[string]interface{}{ - "mapping": onecloudMappingRules, - } - _, err = client.SAMLProviderMappings.Update(mappingId, jsonutils.Marshal(params)) - if err != nil { - return errors.Wrapf(err, "create mapping") - } - mapping = &SAMLProviderMapping{ - Id: mappingId, - Rules: onecloudMappingRules, - } - } - protocols, err := self.GetSAMLProviderProtocols(spId) - if err != nil { - return errors.Wrapf(err, "GetSAMLProviderProtocols") - } - params := map[string]interface{}{ - "protocol": map[string]string{ - "mapping_id": mapping.Id, - }, - } - for i := range protocols { - if protocols[i].Id == "saml" { - if protocols[i].MappingId == mapping.Id { - return nil - } - _, err = client.SAMLProviders.PatchInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "") - return err - } - } - _, err = client.SAMLProviders.UpdateInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "") - return err -} - -func (self *SHuaweiClient) DeleteSAMLProviderMapping(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - - _, err = client.SAMLProviderMappings.Delete(id, nil) - return err -} diff --git a/pkg/multicloud/hcso/securitygroup.go b/pkg/multicloud/hcso/securitygroup.go deleted file mode 100644 index 48f6bc3668..0000000000 --- a/pkg/multicloud/hcso/securitygroup.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -/* -https://support.huaweicloud.com/usermanual-vpc/zh-cn_topic_0073379079.html -安全组的限制 -默认情况下,一个用户可以创建100个安全组。 -默认情况下,一个安全组最多只允许拥有50条安全组规则。 -默认情况下,一个弹性云服务器或辅助网卡最多只能被添加到5个安全组中。 -在创建私网弹性负载均衡时,需要选择弹性负载均衡所在的安全组。请勿删除默认规则或者确保满足以下规则: -出方向:允许发往同一个安全组的报文可以通过,或者允许对端负载均衡器报文通过。 -入方向:允许来自同一个安全组的报文可以通过,或者允许对端负载均衡器报文通过。 -*/ - -import ( - "net" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SecurityGroupRule struct { - Direction string `json:"direction"` - Ethertype string `json:"ethertype"` - ID string `json:"id"` - Description string `json:"description"` - SecurityGroupID string `json:"security_group_id"` - RemoteGroupID string `json:"remote_group_id"` -} - -type SecurityGroupRuleDetail struct { - Direction string `json:"direction"` - Ethertype string `json:"ethertype"` - ID string `json:"id"` - Description string `json:"description"` - PortRangeMax int64 `json:"port_range_max"` - PortRangeMin int64 `json:"port_range_min"` - Protocol string `json:"protocol"` - RemoteGroupID string `json:"remote_group_id"` - RemoteIPPrefix string `json:"remote_ip_prefix"` - SecurityGroupID string `json:"security_group_id"` - TenantID string `json:"tenant_id"` -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.HuaweiTags - region *SRegion - - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - VpcID string `json:"vpc_id"` - EnterpriseProjectID string `json:"enterprise_project_id "` - SecurityGroupRules []SecurityGroupRule `json:"security_group_rules"` -} - -// 判断是否兼容云端安全组规则 -func compatibleSecurityGroupRule(r SecurityGroupRule) bool { - // 忽略了源地址是安全组的规则 - if len(r.RemoteGroupID) > 0 { - return false - } - - // 忽略IPV6 - if r.Ethertype == "IPv6" { - return false - } - - return true -} - -func (self *SSecurityGroup) GetId() string { - return self.ID -} - -func (self *SSecurityGroup) GetVpcId() string { - return api.NORMAL_VPC_ID -} - -func (self *SSecurityGroup) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.ID -} - -func (self *SSecurityGroup) GetGlobalId() string { - return self.ID -} - -func (self *SSecurityGroup) GetStatus() string { - return "" -} - -func (self *SSecurityGroup) Refresh() error { - if new, err := self.region.GetSecurityGroupDetails(self.GetId()); err != nil { - return err - } else { - return jsonutils.Update(self, new) - } -} - -func (self *SSecurityGroup) IsEmulated() bool { - return false -} - -func (self *SSecurityGroup) GetDescription() string { - if self.Description == self.VpcID { - return "" - } - return self.Description -} - -// todo: 这里需要优化查询太多了 -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - rules := make([]cloudprovider.SecurityRule, 0) - for _, r := range self.SecurityGroupRules { - if !compatibleSecurityGroupRule(r) { - continue - } - - rule, err := self.GetSecurityRule(r.ID) - if err != nil { - return rules, err - } - - rules = append(rules, rule) - } - - return rules, nil -} - -func (self *SSecurityGroup) GetSecurityRule(ruleId string) (cloudprovider.SecurityRule, error) { - remoteRule := SecurityGroupRuleDetail{} - err := DoGet(self.region.ecsClient.SecurityGroupRules.Get, ruleId, nil, &remoteRule) - if err != nil { - return cloudprovider.SecurityRule{}, err - } - - var direction secrules.TSecurityRuleDirection - if remoteRule.Direction == "ingress" { - direction = secrules.SecurityRuleIngress - } else { - direction = secrules.SecurityRuleEgress - } - - protocol := secrules.PROTO_ANY - if remoteRule.Protocol != "" { - protocol = remoteRule.Protocol - } - - var portStart int - var portEnd int - if protocol == secrules.PROTO_ICMP { - portStart = -1 - portEnd = -1 - } else { - portStart = int(remoteRule.PortRangeMin) - portEnd = int(remoteRule.PortRangeMax) - } - - ipNet := &net.IPNet{} - if len(remoteRule.RemoteIPPrefix) > 0 { - _, ipNet, err = net.ParseCIDR(remoteRule.RemoteIPPrefix) - } else { - _, ipNet, err = net.ParseCIDR("0.0.0.0/0") - } - - if err != nil { - return cloudprovider.SecurityRule{}, err - } - - rule := cloudprovider.SecurityRule{ - ExternalId: ruleId, - SecurityRule: secrules.SecurityRule{ - Priority: 1, - Action: secrules.SecurityRuleAllow, - IPNet: ipNet, - Protocol: protocol, - Direction: direction, - PortStart: portStart, - PortEnd: portEnd, - Ports: nil, - Description: remoteRule.Description, - }, - } - - err = rule.ValidateRule() - return rule, err -} - -func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) { - securitygroup := SSecurityGroup{} - err := DoGet(self.ecsClient.SecurityGroups.Get, secGroupId, nil, &securitygroup) - if err != nil { - return nil, err - } - - securitygroup.region = self - return &securitygroup, err -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090617.html -func (self *SRegion) GetSecurityGroups(vpcId string, name string) ([]SSecurityGroup, error) { - querys := map[string]string{} - if len(vpcId) > 0 && !utils.IsInStringArray(vpcId, []string{"default", api.NORMAL_VPC_ID}) { // vpc_id = default or normal 时报错 '{"code":"VPC.0601","message":"Query security groups error vpcId is invalid."}' - querys["vpc_id"] = vpcId - } - - securitygroups := make([]SSecurityGroup, 0) - err := doListAllWithMarker(self.ecsClient.SecurityGroups.List, querys, &securitygroups) - if err != nil { - return nil, err - } - - // security 中的vpc字段只是一个标识,实际可以跨vpc使用 - for i := range securitygroups { - securitygroup := &securitygroups[i] - securitygroup.region = self - } - - result := []SSecurityGroup{} - for _, secgroup := range securitygroups { - if len(name) == 0 || secgroup.Name == name { - result = append(result, secgroup) - } - } - - return result, nil -} - -func (self *SSecurityGroup) GetProjectId() string { - return "" -} - -func (self *SSecurityGroup) Delete() error { - return self.region.DeleteSecurityGroup(self.ID) -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - for _, r := range append(inDels, outDels...) { - err := self.region.delSecurityGroupRule(r.ExternalId) - if err != nil { - return errors.Wrapf(err, "delSecurityGroupRule(%s %s)", r.ExternalId, r.String()) - } - } - for _, r := range append(inAdds, outAdds...) { - err := self.region.addSecurityGroupRules(self.ID, r) - if err != nil { - return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String()) - } - } - return nil -} diff --git a/pkg/multicloud/hcso/sfs-turbo.go b/pkg/multicloud/hcso/sfs-turbo.go deleted file mode 100644 index 0aca694c00..0000000000 --- a/pkg/multicloud/hcso/sfs-turbo.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SfsTurbo struct { - multicloud.SNasBase - multicloud.HuaweiTags - region *SRegion - - EnterpriseProjectId string - Actions []string - AvailCapacity float64 - AvailabilityZone string - AzName string - CreatedAt time.Time - CryptKeyId string - ExpandType string - ExportLocation string - Id string - Name string - PayModel string - Region string - SecurityGroupId string - ShareProto string - ShareType string - Size float64 - Status string - SubStatus string - SubnetId string - VpcId string - Description string -} - -func (self *SfsTurbo) GetName() string { - return self.Name -} - -func (self *SfsTurbo) GetId() string { - return self.Id -} - -func (self *SfsTurbo) GetGlobalId() string { - return self.Id -} - -func (self *SfsTurbo) GetFileSystemType() string { - return "SFS Turbo" -} - -func (self *SfsTurbo) Refresh() error { - sf, err := self.region.GetSfsTurbo(self.Id) - if err != nil { - return errors.Wrapf(err, "GetSfsTurbo") - } - return jsonutils.Update(self, sf) -} - -func (self *SfsTurbo) GetBillingType() string { - if self.PayModel == "0" { - return billing_api.BILLING_TYPE_POSTPAID - } - return billing_api.BILLING_TYPE_PREPAID -} - -func (self *SfsTurbo) GetStorageType() string { - if len(self.ExpandType) == 0 { - return strings.ToLower(self.ShareType) - } - return strings.ToLower(self.ShareType) + ".enhanced" -} - -func (self *SfsTurbo) GetProtocol() string { - return self.ShareProto -} - -func (self *SfsTurbo) GetStatus() string { - switch self.Status { - case "100": - return api.NAS_STATUS_CREATING - case "200": - return api.NAS_STATUS_AVAILABLE - case "300": - return api.NAS_STATUS_UNKNOWN - case "303": - return api.NAS_STATUS_CREATE_FAILED - case "400": - return api.NAS_STATUS_DELETING - case "800": - return api.NAS_STATUS_UNAVAILABLE - default: - return self.Status - } -} - -func (self *SfsTurbo) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SfsTurbo) GetCapacityGb() int64 { - return int64(self.Size) -} - -func (self *SfsTurbo) GetUsedCapacityGb() int64 { - return int64(self.Size - self.AvailCapacity) -} - -func (self *SfsTurbo) GetMountTargetCountLimit() int { - return 1 -} - -func (self *SfsTurbo) GetZoneId() string { - return self.AvailabilityZone -} - -func (self *SfsTurbo) GetMountTargets() ([]cloudprovider.ICloudMountTarget, error) { - mt := &sMoutTarget{sfs: self} - return []cloudprovider.ICloudMountTarget{mt}, nil -} - -func (self *SfsTurbo) CreateMountTarget(opts *cloudprovider.SMountTargetCreateOptions) (cloudprovider.ICloudMountTarget, error) { - return nil, errors.Wrap(cloudprovider.ErrNotSupported, "CreateMountTarget") -} - -func (self *SfsTurbo) Delete() error { - return self.region.DeleteSfsTurbo(self.Id) -} - -func (self *SRegion) GetICloudFileSystems() ([]cloudprovider.ICloudFileSystem, error) { - sfs, err := self.GetSfsTurbos() - if err != nil { - return nil, errors.Wrapf(err, "self.GetSfsTurbos") - } - ret := []cloudprovider.ICloudFileSystem{} - for i := range sfs { - sfs[i].region = self - ret = append(ret, &sfs[i]) - } - return ret, nil -} - -func (self *SRegion) GetICloudFileSystemById(id string) (cloudprovider.ICloudFileSystem, error) { - sf, err := self.GetSfsTurbo(id) - if err != nil { - return nil, errors.Wrapf(err, "GetSfsTurbo(%s)", id) - } - return sf, nil -} - -func (self *SRegion) GetSfsTurbos() ([]SfsTurbo, error) { - queues := make(map[string]string) - sfs := make([]SfsTurbo, 0, 2) - err := doListAllWithOffset(self.ecsClient.SfsTurbos.List, queues, &sfs) - if err != nil { - return nil, errors.Wrapf(err, "doListAllWithOffset") - } - return sfs, nil -} - -func (self *SRegion) GetSfsTurbo(id string) (*SfsTurbo, error) { - sf := &SfsTurbo{region: self} - err := DoGet(self.ecsClient.SfsTurbos.Get, id, nil, &sf) - return sf, errors.Wrapf(err, "self.ecsClient.SfsTurbos.Get") -} - -func (self *SRegion) DeleteSfsTurbo(id string) error { - return DoDelete(self.ecsClient.SfsTurbos.Delete, id, nil, nil) -} - -func (self *SRegion) GetSysDefaultSecgroupId() (string, error) { - secs, err := self.GetSecurityGroups("default", "") - if err != nil { - return "", errors.Wrapf(err, "GetSecurityGroups") - } - if len(secs) > 0 { - return secs[0].ID, nil - } - return "", fmt.Errorf("not found default security group") -} - -func (self *SRegion) CreateICloudFileSystem(opts *cloudprovider.FileSystemCraeteOptions) (cloudprovider.ICloudFileSystem, error) { - fs, err := self.CreateSfsTurbo(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateSfsTurbo") - } - return fs, nil -} - -func (self *SRegion) CreateSfsTurbo(opts *cloudprovider.FileSystemCraeteOptions) (*SfsTurbo, error) { - secId, err := self.GetSysDefaultSecgroupId() - if err != nil { - return nil, errors.Wrapf(err, "GetSysDefaultSecgroupId") - } - metadata := map[string]string{} - if strings.HasSuffix(opts.StorageType, ".enhanced") { - metadata["expand_type"] = "bandwidth" - } - params := map[string]interface{}{ - "share": map[string]interface{}{ - "name": opts.Name, - "share_proto": strings.ToUpper(opts.Protocol), - "share_type": strings.ToUpper(strings.TrimSuffix(opts.StorageType, ".enhanced")), - "size": opts.Capacity, - "availability_zone": opts.ZoneId, - "vpc_id": opts.VpcId, - "subnet_id": opts.NetworkId, - "security_group_id": secId, - "description": opts.Desc, - "metadata": metadata, - }, - } - resp, err := self.ecsClient.SfsTurbos.Create(jsonutils.Marshal(params)) - if err != nil { - return nil, errors.Wrapf(err, "Create") - } - id, err := resp.GetString("id") - if err != nil { - return nil, errors.Wrapf(err, "resp.GetString(id)") - } - return self.GetSfsTurbo(id) -} - -func (self *SRegion) GetICloudAccessGroups() ([]cloudprovider.ICloudAccessGroup, error) { - return []cloudprovider.ICloudAccessGroup{}, nil -} - -func (self *SRegion) CreateICloudAccessGroup(opts *cloudprovider.SAccessGroup) (cloudprovider.ICloudAccessGroup, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "CreateICloudAccessGroup") -} - -func (self *SRegion) GetICloudAccessGroupById(id string) (cloudprovider.ICloudAccessGroup, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetICloudAccessGroupById(%s)", id) -} - -type sMoutTarget struct { - sfs *SfsTurbo -} - -func (self *sMoutTarget) GetName() string { - return self.sfs.Name -} - -func (self *sMoutTarget) GetGlobalId() string { - return self.sfs.GetGlobalId() -} - -func (self *sMoutTarget) GetAccessGroupId() string { - return "" -} - -func (self *sMoutTarget) GetDomainName() string { - return self.sfs.ExportLocation -} - -func (self *sMoutTarget) GetNetworkType() string { - return api.NETWORK_TYPE_VPC -} - -func (self *sMoutTarget) GetNetworkId() string { - return self.sfs.SubnetId -} - -func (self *sMoutTarget) GetVpcId() string { - return self.sfs.VpcId -} - -func (self *sMoutTarget) GetStatus() string { - return api.MOUNT_TARGET_STATUS_AVAILABLE -} - -func (self *sMoutTarget) Delete() error { - return nil -} diff --git a/pkg/multicloud/hcso/shell/bucket.go b/pkg/multicloud/hcso/shell/bucket.go deleted file mode 100644 index b9787ea454..0000000000 --- a/pkg/multicloud/hcso/shell/bucket.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - objectstore.S3Shell() - - type BucketNameOptions struct { - NAME string - } - shellutils.R(&BucketNameOptions{}, "bucket-head", "Head bucket", func(cli *huawei.SRegion, args *BucketNameOptions) error { - result, err := cli.HeadBucket(args.NAME) - if err != nil { - return err - } - printObject(result) - return nil - }) - - shellutils.R(&BucketNameOptions{}, "bucket-project", "Show bucket project", func(cli *huawei.SRegion, args *BucketNameOptions) error { - bucket, err := cli.GetIBucketByName(args.NAME) - if err != nil { - return err - } - fmt.Println("project: ", bucket.GetProjectId()) - return nil - }) - -} diff --git a/pkg/multicloud/hcso/shell/cloudgroup.go b/pkg/multicloud/hcso/shell/cloudgroup.go deleted file mode 100644 index 1c92979be0..0000000000 --- a/pkg/multicloud/hcso/shell/cloudgroup.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CloudgroupListOptions struct { - DomainId string - Name string - } - shellutils.R(&CloudgroupListOptions{}, "cloud-group-list", "List cloudgroups", func(cli *huawei.SRegion, args *CloudgroupListOptions) error { - groups, err := cli.GetClient().GetGroups(args.DomainId, args.Name) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - type CloudgroupIdOptions struct { - ID string - } - - shellutils.R(&CloudgroupIdOptions{}, "cloud-group-delete", "Delete cloudgroup", func(cli *huawei.SRegion, args *CloudgroupIdOptions) error { - return cli.GetClient().DeleteGroup(args.ID) - }) - - type CloudgroupCreateOptions struct { - NAME string - Desc string - } - - shellutils.R(&CloudgroupCreateOptions{}, "cloud-group-create", "Create cloudgroup", func(cli *huawei.SRegion, args *CloudgroupCreateOptions) error { - group, err := cli.GetClient().CreateGroup(args.NAME, args.Desc) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type GroupRoleListOptions struct { - GROUP_ID string - } - - shellutils.R(&GroupRoleListOptions{}, "cloud-group-policy-list", "List role", func(cli *huawei.SRegion, args *GroupRoleListOptions) error { - roles, err := cli.GetClient().GetGroupRoles(args.GROUP_ID) - if err != nil { - return err - } - printList(roles, 0, 0, 0, nil) - return nil - }) - - type GroupRoleOptions struct { - GROUP_ID string - ROLE_ID string - } - - shellutils.R(&GroupRoleOptions{}, "cloud-group-detach-policy", "Detach group role", func(cli *huawei.SRegion, args *GroupRoleOptions) error { - return cli.GetClient().DetachGroupRole(args.GROUP_ID, args.ROLE_ID) - }) - - shellutils.R(&GroupRoleOptions{}, "cloud-group-attach-policy", "Detach group role", func(cli *huawei.SRegion, args *GroupRoleOptions) error { - return cli.GetClient().AttachGroupRole(args.GROUP_ID, args.ROLE_ID) - }) - - type GroupUserListOptions struct { - GROUP_ID string - } - - shellutils.R(&GroupUserListOptions{}, "cloud-group-user-list", "List user", func(cli *huawei.SRegion, args *GroupUserListOptions) error { - users, err := cli.GetClient().GetGroupUsers(args.GROUP_ID) - if err != nil { - return err - } - printList(users, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/hcso/shell/clouduser.go b/pkg/multicloud/hcso/shell/clouduser.go deleted file mode 100644 index bd56a330e6..0000000000 --- a/pkg/multicloud/hcso/shell/clouduser.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClouduserListOptions struct { - Name string - } - shellutils.R(&ClouduserListOptions{}, "cloud-user-list", "List cloudusers", func(cli *huawei.SRegion, args *ClouduserListOptions) error { - users, err := cli.GetClient().GetCloudusers(args.Name) - if err != nil { - return err - } - printList(users, 0, 0, 0, nil) - return nil - }) - - type ClouduserIdOptions struct { - ID string - } - - shellutils.R(&ClouduserIdOptions{}, "cloud-user-delete", "Delete clouduser", func(cli *huawei.SRegion, args *ClouduserIdOptions) error { - return cli.GetClient().DeleteClouduser(args.ID) - }) - - shellutils.R(&ClouduserIdOptions{}, "cloud-user-group-list", "List clouduser groups", func(cli *huawei.SRegion, args *ClouduserIdOptions) error { - groups, err := cli.GetClient().ListUserGroups(args.ID) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - type ClouduserCreateOptions struct { - NAME string - Password string - Desc string - } - - shellutils.R(&ClouduserCreateOptions{}, "cloud-user-create", "Create clouduser", func(cli *huawei.SRegion, args *ClouduserCreateOptions) error { - user, err := cli.GetClient().CreateClouduser(args.NAME, args.Password, args.Desc) - if err != nil { - return err - } - printObject(user) - return nil - }) - - type RoleListOptions struct { - DomainId string - Name string - } - - shellutils.R(&RoleListOptions{}, "cloud-policy-list", "List role", func(cli *huawei.SRegion, args *RoleListOptions) error { - roles, err := cli.GetClient().GetRoles(args.DomainId, args.Name) - if err != nil { - return err - } - printList(roles, 0, 0, 0, nil) - return nil - }) - - type ClouduserResetPassword struct { - ID string - PASSWORD string - } - - shellutils.R(&ClouduserResetPassword{}, "cloud-user-reset-password", "Reset clouduser password", func(cli *huawei.SRegion, args *ClouduserResetPassword) error { - return cli.GetClient().ResetClouduserPassword(args.ID, args.PASSWORD) - }) - - type ClouduserAKSKOptions struct { - Id string - } - shellutils.R(&ClouduserAKSKOptions{}, "aksk-list", "List AKSK", func(cli *huawei.SRegion, args *ClouduserAKSKOptions) error { - res, err := cli.GetClient().GetAKSK(args.Id) - if err != nil { - return err - } - printList(res, len(res), 0, 0, []string{}) - return nil - }) - type ClouduserAKSKDeleteOptions struct { - AccessKey string - } - shellutils.R(&ClouduserAKSKDeleteOptions{}, "aksk-delete", "Delete AKSK", func(cli *huawei.SRegion, args *ClouduserAKSKDeleteOptions) error { - err := cli.GetClient().DeleteAKSK(args.AccessKey) - return err - }) - - type AKSKCreateOption struct { - UserId string `help:"user id"` - Description string `help:"description"` - } - - shellutils.R(&AKSKCreateOption{}, "aksk-create", "Create aksk", func(cli *huawei.SRegion, args *AKSKCreateOption) error { - res, err := cli.GetClient().CreateAKSK(args.UserId, args.Description) - if err != nil { - return err - } - printObject(res) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/dbinstance.go b/pkg/multicloud/hcso/shell/dbinstance.go deleted file mode 100644 index ee648744e1..0000000000 --- a/pkg/multicloud/hcso/shell/dbinstance.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceListOptions struct { - } - shellutils.R(&DBInstanceListOptions{}, "dbinstance-list", "List dbinstances", func(cli *huawei.SRegion, args *DBInstanceListOptions) error { - dbinstances, err := cli.GetDBInstances() - if err != nil { - return err - } - printList(dbinstances, 0, 0, 0, nil) - return nil - }) - - type DBInstanceIdOptions struct { - ID string `help:"DBInstance ID"` - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-open-public-connection", "Open dbinstance public connection", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - return cli.PublicConnectionAction(args.ID, "openRC") - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-close-public-connection", "Close dbinstance public connection", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - return cli.PublicConnectionAction(args.ID, "closeRC") - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-show", "Show dbinstance", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - dbinstance, err := cli.GetDBInstance(args.ID) - if err != nil { - return err - } - printObject(dbinstance) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-parameter-list", "Show dbinstance parameters", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - parameters, err := cli.GetDBInstanceParameters(args.ID) - if err != nil { - return err - } - printList(parameters, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-backup-list", "Show dbinstance backups", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - backups, err := cli.GetDBInstanceBackups(args.ID, "") - if err != nil { - return err - } - printList(backups, 0, 0, 0, nil) - return nil - }) - - type DBInstanceFlavorListOption struct { - ENGINE string `help:"DBInstance engine" choices:"MySQL|SQLServer|PostgreSQL"` - VERSION string `help:"DBInstance engine version" choices:"5.6|5.7|9.5|9.6|10.0|2014 SE|2014 EE|2016 SE|2016 EE|2008 R2 EE|2008 R2 WEB|2014 WEB|2016 WEB"` - } - - shellutils.R(&DBInstanceFlavorListOption{}, "dbinstance-flavor-list", "Show dbinstance backups", func(cli *huawei.SRegion, args *DBInstanceFlavorListOption) error { - flavors, err := cli.GetDBInstanceFlavors(args.ENGINE, args.VERSION) - if err != nil { - return err - } - printList(flavors, 0, 0, 0, nil) - return nil - }) - - type DBInstanceChangeConfigOptions struct { - INSTANCE string - InstanceType string - DiskSizeGB int - } - - shellutils.R(&DBInstanceChangeConfigOptions{}, "dbinstance-change-config", "Change dbinstance config", func(cli *huawei.SRegion, args *DBInstanceChangeConfigOptions) error { - return cli.ChangeDBInstanceConfig(args.INSTANCE, args.InstanceType, args.DiskSizeGB) - }) - -} diff --git a/pkg/multicloud/hcso/shell/dbinstance_account.go b/pkg/multicloud/hcso/shell/dbinstance_account.go deleted file mode 100644 index 60375c0793..0000000000 --- a/pkg/multicloud/hcso/shell/dbinstance_account.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceIdOptions struct { - ID string `help:"DBInstance ID"` - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-account-list", "Show dbinstance accounts", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - accounts, err := cli.GetDBInstanceAccounts(args.ID) - if err != nil { - return err - } - printList(accounts, 0, 0, 0, nil) - return nil - }) - - type DBInstanceAccountDeleteOptions struct { - INSTANCE string - ACCOUNT string - } - - shellutils.R(&DBInstanceAccountDeleteOptions{}, "dbinstance-account-delete", "Delete dbinstance account", func(cli *huawei.SRegion, args *DBInstanceAccountDeleteOptions) error { - return cli.DeleteDBInstanceAccount(args.INSTANCE, args.ACCOUNT) - }) - - type DBInstanceAccountCreateOptions struct { - INSTANCE string - ACCOUNT string - PASSWORD string - } - - shellutils.R(&DBInstanceAccountCreateOptions{}, "dbinstance-account-create", "Create dbinstance account", func(cli *huawei.SRegion, args *DBInstanceAccountCreateOptions) error { - return cli.CreateDBInstanceAccount(args.INSTANCE, args.ACCOUNT, args.PASSWORD) - }) - - type DBInstanceAccountRevokePrivilegeOptions struct { - INSTANCE string - ACCOUNT string - DATABASE string - } - - shellutils.R(&DBInstanceAccountRevokePrivilegeOptions{}, "dbinstance-account-revoke-provilege", "Revoke dbinstance account privilege", func(cli *huawei.SRegion, args *DBInstanceAccountRevokePrivilegeOptions) error { - return cli.RevokeDBInstancePrivilege(args.INSTANCE, args.ACCOUNT, args.DATABASE) - }) - - type DBInstanceAccountGrantPrivilegeOptions struct { - INSTANCE string - ACCOUNT string - DATABASE string - PRIVILEGE string `help:"database privilege" choices:"r|rw"` - } - - shellutils.R(&DBInstanceAccountGrantPrivilegeOptions{}, "dbinstance-account-grant-provilege", "Grant dbinstance account privilege", func(cli *huawei.SRegion, args *DBInstanceAccountGrantPrivilegeOptions) error { - return cli.GrantDBInstancePrivilege(args.INSTANCE, args.ACCOUNT, args.DATABASE, args.PRIVILEGE) - }) - -} diff --git a/pkg/multicloud/hcso/shell/dbinstance_database.go b/pkg/multicloud/hcso/shell/dbinstance_database.go deleted file mode 100644 index afea978b93..0000000000 --- a/pkg/multicloud/hcso/shell/dbinstance_database.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceIdOptions struct { - INSTANCE string `help:"DBInstance ID"` - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-database-list", "Show dbinstance databases", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - databases, err := cli.GetDBInstanceDatabases(args.INSTANCE) - if err != nil { - return err - } - printList(databases, 0, 0, 0, nil) - return nil - }) - - type DBInstanceDatabaseDeleteOptions struct { - INSTANCE string - DATABASE string - } - - shellutils.R(&DBInstanceDatabaseDeleteOptions{}, "dbinstance-database-delete", "Delete dbinstance database", func(cli *huawei.SRegion, args *DBInstanceDatabaseDeleteOptions) error { - return cli.DeleteDBInstanceDatabase(args.INSTANCE, args.DATABASE) - }) - - type DBInstanceDatabaseCreateOptions struct { - INSTANCE string - DATABASE string - CHARACTER_SET string - } - - shellutils.R(&DBInstanceDatabaseCreateOptions{}, "dbinstance-database-create", "Create dbinstance database", func(cli *huawei.SRegion, args *DBInstanceDatabaseCreateOptions) error { - return cli.CreateDBInstanceDatabase(args.INSTANCE, args.DATABASE, args.CHARACTER_SET) - }) - -} diff --git a/pkg/multicloud/hcso/shell/dbinstance_skus.go b/pkg/multicloud/hcso/shell/dbinstance_skus.go deleted file mode 100644 index b95310dca4..0000000000 --- a/pkg/multicloud/hcso/shell/dbinstance_skus.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceDatastoreOptions struct { - ENGINE string `help:"DBInstance Engine" choices:"MySQL|PostgreSQL|SQLServer"` - } - - shellutils.R(&DBInstanceDatastoreOptions{}, "dbinstance-datastore-list", "List dbinstance datastores", func(cli *huawei.SRegion, args *DBInstanceDatastoreOptions) error { - stores, err := cli.GetDBInstanceDatastores(args.ENGINE) - if err != nil { - return err - } - printList(stores, 0, 0, 0, nil) - return nil - }) - - type DBInstanceSkuListOptions struct { - } - - shellutils.R(&DBInstanceSkuListOptions{}, "dbinstance-sku-list", "List dbinstance datastores", func(cli *huawei.SRegion, args *DBInstanceSkuListOptions) error { - skus, err := cli.GetDBInstanceSkus() - if err != nil { - return err - } - printList(skus, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/hcso/shell/disk.go b/pkg/multicloud/hcso/shell/disk.go deleted file mode 100644 index b0e1eb095e..0000000000 --- a/pkg/multicloud/hcso/shell/disk.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - Zone string `help:"Zone ID"` - } - shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *huawei.SRegion, args *DiskListOptions) error { - disks, e := cli.GetDisks(args.Zone) - if e != nil { - return e - } - printList(disks, 0, 0, 0, nil) - return nil - }) - - type DiskDeleteOptions struct { - ID string `help:"Disk ID"` - } - shellutils.R(&DiskDeleteOptions{}, "disk-delete", "List disks", func(cli *huawei.SRegion, args *DiskDeleteOptions) error { - e := cli.DeleteDisk(args.ID) - if e != nil { - return e - } - return nil - }) - - shellutils.R(&DiskListOptions{}, "disk-types", "List disk types", func(cli *huawei.SRegion, args *DiskListOptions) error { - ret, e := cli.GetDiskTypes() - if e != nil { - return e - } - printList(ret, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/doc.go b/pkg/multicloud/hcso/shell/doc.go deleted file mode 100644 index ea1098fa7e..0000000000 --- a/pkg/multicloud/hcso/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/hcso/shell" diff --git a/pkg/multicloud/hcso/shell/eip.go b/pkg/multicloud/hcso/shell/eip.go deleted file mode 100644 index 06e5e58b4c..0000000000 --- a/pkg/multicloud/hcso/shell/eip.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *huawei.SRegion, args *EipListOptions) error { - eips, e := cli.GetEips() - if e != nil { - return e - } - printList(eips, 0, 0, 0, nil) - return nil - }) - - type EipAllocateOptions struct { - NAME string `help:"eip name"` - BW int `help:"Bandwidth limit in Mbps"` - BGP string `help:"bgp type" choices:"5_telcom|5_union|5_bgp|5_sbgp"` - ProjectId string - } - shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *huawei.SRegion, args *EipAllocateOptions) error { - eip, err := cli.AllocateEIP(args.NAME, args.BW, huawei.InternetChargeByTraffic, args.BGP, args.ProjectId) - 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 *huawei.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 *huawei.SRegion, args *EipAssociateOptions) error { - err := cli.AssociateEip(args.ID, args.INSTANCE) - return err - }) - shellutils.R(&EipAssociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *huawei.SRegion, args *EipAssociateOptions) error { - err := cli.DissociateEip(args.ID, args.INSTANCE) - return err - }) -} diff --git a/pkg/multicloud/hcso/shell/elasticcache.go b/pkg/multicloud/hcso/shell/elasticcache.go deleted file mode 100644 index 2e96a36677..0000000000 --- a/pkg/multicloud/hcso/shell/elasticcache.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElasticcacheListOptions struct { - } - shellutils.R(&ElasticcacheListOptions{}, "dcs-list", "List elasticcaches", func(cli *huawei.SRegion, args *ElasticcacheListOptions) error { - instances, e := cli.GetElasticCaches() - if e != nil { - return e - } - printList(instances, len(instances), 0, 0, []string{}) - return nil - }) - - type ElasticcacheIdOptions struct { - ID string `help:"ID of instances to show"` - } - shellutils.R(&ElasticcacheIdOptions{}, "dcs-show", "Show elasticcache", func(cli *huawei.SRegion, args *ElasticcacheIdOptions) error { - instance, err := cli.GetElasticCache(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - type ElasticcacheBackupsListOptions struct { - ID string `help:"ID of instances to show"` - StartTime string `help:"backup start time. format: 20060102150405"` - EndTime string `help:"backup end time. format: 20060102150405 "` - } - - shellutils.R(&ElasticcacheBackupsListOptions{}, "dcs-backup-list", "List elasticcache backups", func(cli *huawei.SRegion, args *ElasticcacheBackupsListOptions) error { - backups, err := cli.GetElasticCacheBackups(args.ID, args.StartTime, args.EndTime) - if err != nil { - return err - } - printList(backups, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElasticcacheIdOptions{}, "dcs-parameter-list", "List elasticcache parameters", func(cli *huawei.SRegion, args *ElasticcacheIdOptions) error { - parameters, err := cli.GetElasticCacheParameters(args.ID) - if err != nil { - return err - } - printList(parameters, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/endpoints.go b/pkg/multicloud/hcso/shell/endpoints.go deleted file mode 100644 index e44ba47e54..0000000000 --- a/pkg/multicloud/hcso/shell/endpoints.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EndpointsListOptions struct { - } - shellutils.R(&EndpointsListOptions{}, "endpoint-list", "List endpoints", func(cli *huawei.SRegion, args *EndpointsListOptions) error { - regions, _ := cli.GetEndpoints() - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/enterpriseprojects.go b/pkg/multicloud/hcso/shell/enterpriseprojects.go deleted file mode 100644 index 1ad54442b2..0000000000 --- a/pkg/multicloud/hcso/shell/enterpriseprojects.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EnterpriseProjectListOptions struct { - } - shellutils.R(&EnterpriseProjectListOptions{}, "enterprise-project-list", "List enterprise projects", func(cli *huawei.SRegion, args *EnterpriseProjectListOptions) error { - projects, err := cli.GetClient().GetEnterpriseProjects() - if err != nil { - return err - } - printList(projects, 0, 0, 0, nil) - return nil - }) - - type EnterpriseProjectCreateOptions struct { - NAME string - Desc string - } - - shellutils.R(&EnterpriseProjectCreateOptions{}, "enterprise-project-create", "Create enterprise project", func(cli *huawei.SRegion, args *EnterpriseProjectCreateOptions) error { - project, err := cli.GetClient().CreateExterpriseProject(args.NAME, args.Desc) - if err != nil { - return err - } - printObject(project) - return nil - }) - -} diff --git a/pkg/multicloud/hcso/shell/events.go b/pkg/multicloud/hcso/shell/events.go deleted file mode 100644 index 2fe94a7b0e..0000000000 --- a/pkg/multicloud/hcso/shell/events.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "time" - - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EventListOptions struct { - Start time.Time - End time.Time - } - shellutils.R(&EventListOptions{}, "event-list", "List events", func(cli *huawei.SRegion, args *EventListOptions) error { - events, err := cli.GetEvents(args.Start, args.End) - if err != nil { - return err - } - printList(events, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/filesystem.go b/pkg/multicloud/hcso/shell/filesystem.go deleted file mode 100644 index 9992c7e678..0000000000 --- a/pkg/multicloud/hcso/shell/filesystem.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type FileSystemListOptions struct { - } - shellutils.R(&FileSystemListOptions{}, "file-system-list", "List FileSystem", func(cli *huawei.SRegion, args *FileSystemListOptions) error { - sfs, err := cli.GetSfsTurbos() - if err != nil { - return err - } - printList(sfs, 0, 0, 0, []string{}) - return nil - }) - - type FileSystemIdOptions struct { - ID string `help:"File System ID"` - } - shellutils.R(&FileSystemIdOptions{}, "file-system-delete", "Delete filesystem", func(cli *huawei.SRegion, args *FileSystemIdOptions) error { - return cli.DeleteSfsTurbo(args.ID) - }) - - shellutils.R(&FileSystemIdOptions{}, "file-system-show", "Show filesystem", func(cli *huawei.SRegion, args *FileSystemIdOptions) error { - fs, err := cli.GetSfsTurbo(args.ID) - if err != nil { - return err - } - printObject(fs) - return nil - }) - - shellutils.R(&cloudprovider.FileSystemCraeteOptions{}, "file-system-create", "Create filesystem", func(cli *huawei.SRegion, args *cloudprovider.FileSystemCraeteOptions) error { - fs, err := cli.CreateSfsTurbo(args) - if err != nil { - return err - } - printObject(fs) - return nil - }) - -} diff --git a/pkg/multicloud/hcso/shell/hosts.go b/pkg/multicloud/hcso/shell/hosts.go deleted file mode 100644 index 762cd705fe..0000000000 --- a/pkg/multicloud/hcso/shell/hosts.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type HostListOptions struct { - } - shellutils.R(&HostListOptions{}, "host-list", "List hosts", func(cli *huawei.SRegion, args *HostListOptions) error { - hosts, e := cli.GetIHosts() - if e != nil { - return e - } - - printList(hosts, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/iam.go b/pkg/multicloud/hcso/shell/iam.go deleted file mode 100644 index eb2d3f29a5..0000000000 --- a/pkg/multicloud/hcso/shell/iam.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type OwnerShowOptions struct { - } - shellutils.R(&OwnerShowOptions{}, "owner-show", "Get aksk owner id", func(cli *huawei.SRegion, args *OwnerShowOptions) error { - result, err := cli.GetClient().GetOwnerId() - if err != nil { - return err - } - fmt.Println(result) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/image.go b/pkg/multicloud/hcso/shell/image.go deleted file mode 100644 index cbc566a51f..0000000000 --- a/pkg/multicloud/hcso/shell/image.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - Status string `help:"image status type" choices:"queued|saving|deleted|killed|active"` - Owner string `help:"Owner type" choices:"gold|private|shared"` - // Id []string `help:"Image ID"` - Name string `help:"image name"` - // Marker string `help:"marker"` - // Limit int `help:"page Limit"` - Env string `help:"virtualization env, e.g. FusionCompute, Ironic" choices:"FusionCompute|Ironic"` - } - shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *huawei.SRegion, args *ImageListOptions) error { - images, e := cli.GetImages(args.Status, huawei.TImageOwnerType(args.Owner), args.Name, args.Env) - if e != nil { - return e - } - printList(images, 0, 0, 0, []string{}) - return nil - }) - - type ImageDeleteOptions struct { - ID string `help:"ID or Name to delete"` - } - shellutils.R(&ImageDeleteOptions{}, "image-delete", "Delete image", func(cli *huawei.SRegion, args *ImageDeleteOptions) error { - return cli.DeleteImage(args.ID) - }) - - shellutils.R(&ImageDeleteOptions{}, "image-show", "Show image", func(cli *huawei.SRegion, args *ImageDeleteOptions) error { - img, err := cli.GetImage(args.ID) - if err != nil { - return err - } - printObject(img) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/instance.go b/pkg/multicloud/hcso/shell/instance.go deleted file mode 100644 index f50dc02f99..0000000000 --- a/pkg/multicloud/hcso/shell/instance.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "context" - "fmt" - "strings" - - "yunion.io/x/onecloud/pkg/cloudprovider" - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List intances", func(cli *huawei.SRegion, args *InstanceListOptions) error { - instances, e := cli.GetInstances() - if e != nil { - return e - } - printList(instances, 0, 0, 0, nil) - 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 *huawei.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 *huawei.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 *huawei.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 *huawei.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 *huawei.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 *huawei.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"` - UserId string `help:"instance user ID"` - Image string `help:"Image ID"` - Password string `help:"admin password"` - PublicKeyName string `help:"public key name"` - UserData string `help:"cloud-init user data"` - } - - shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *huawei.SRegion, args *InstanceRebuildRootOptions) error { - ctx := context.Background() - jobId, err := cli.ChangeRoot(ctx, args.UserId, args.ID, args.Image, args.Password, args.PublicKeyName, args.UserData) - if err != nil { - return err - } - fmt.Printf("ChangeRoot jobID is %s", jobId) - return nil - }) - - type InstanceChangeConfigOptions struct { - ID string `help:"instance ID"` - InstanceType string `help:"instance type"` - } - - shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Deploy keypair/password to a stopped virtual server", func(cli *huawei.SRegion, args *InstanceChangeConfigOptions) error { - err := cli.ChangeVMConfig(args.ID, args.InstanceType) - if err != nil { - return err - } - return nil - }) - - type InstanceOrderUnsubscribeOptions struct { - ID string `help:"instance ID"` - DOMAIN string `help:"domain ID"` - } - - type InstanceSaveImageOptions struct { - ID string `help:"Instance ID"` - IMAGE_NAME string `help:"Image name"` - Notes string `hlep:"Image desc"` - } - shellutils.R(&InstanceSaveImageOptions{}, "instance-save-image", "Save instance to image", func(cli *huawei.SRegion, args *InstanceSaveImageOptions) error { - opts := cloudprovider.SaveImageOptions{ - Name: args.IMAGE_NAME, - Notes: args.Notes, - } - image, err := cli.SaveImage(args.ID, &opts) - if err != nil { - return err - } - printObject(image) - return nil - }) - - type InstanceSetTagsOptions struct { - ID string `help:"Instance ID"` - Tags []string - } - shellutils.R(&InstanceSetTagsOptions{}, "instance-set-tags", "get intance metadata", func(cli *huawei.SRegion, args *InstanceSetTagsOptions) error { - tags := map[string]string{} - for i := range args.Tags { - splited := strings.Split(args.Tags[i], "=") - if len(splited) == 2 { - tags[splited[0]] = splited[1] - } - } - err := cli.CreateServerTags(args.ID, tags) - if err != nil { - return err - } - return nil - }) - - type InstanceDelTagsOptions struct { - ID string `help:"Instance ID"` - Tags []string - } - shellutils.R(&InstanceDelTagsOptions{}, "instance-del-tags", "del intance metadata", func(cli *huawei.SRegion, args *InstanceDelTagsOptions) error { - - err := cli.DeleteServerTags(args.ID, args.Tags) - if err != nil { - return err - } - return nil - }) - - type InstanceUpdateNameOptions struct { - ID string `help:"Instance ID"` - Name string - } - shellutils.R(&InstanceUpdateNameOptions{}, "instance-set-name", "set intance name", func(cli *huawei.SRegion, args *InstanceUpdateNameOptions) error { - - err := cli.UpdateVM(args.ID, args.Name) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/instancetype.go b/pkg/multicloud/hcso/shell/instancetype.go deleted file mode 100644 index ed246896a3..0000000000 --- a/pkg/multicloud/hcso/shell/instancetype.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceMatchOptions struct { - CPU int `help:"CPU count"` - MEM int `help:"Memory in MB"` - Zone string `help:"Test in zone"` - } - shellutils.R(&InstanceMatchOptions{}, "instance-type-select", "Select matching instance types", func(cli *huawei.SRegion, args *InstanceMatchOptions) error { - instanceTypes, e := cli.GetMatchInstanceTypes(args.CPU, args.MEM, args.Zone) - if e != nil { - return e - } - printList(instanceTypes, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/keypair.go b/pkg/multicloud/hcso/shell/keypair.go deleted file mode 100644 index b28b47eec6..0000000000 --- a/pkg/multicloud/hcso/shell/keypair.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - // todo: 需要进一步确认 - type KeyPairListOptions struct { - } - shellutils.R(&KeyPairListOptions{}, "keypair-list", "List keypairs", func(cli *huawei.SRegion, args *KeyPairListOptions) error { - keypairs, total, e := cli.GetKeypairs() - if e != nil { - return e - } - printList(keypairs, total, 0, 0, []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 *huawei.SRegion, args *KeyPairImportOptions) error { - keypair, err := cli.ImportKeypair(args.NAME, args.PUBKEY) - if err != nil { - return err - } - printObject(keypair) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/loadbalancer.go b/pkg/multicloud/hcso/shell/loadbalancer.go deleted file mode 100644 index bf5ebeaed3..0000000000 --- a/pkg/multicloud/hcso/shell/loadbalancer.go +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElbListOptions struct { - } - shellutils.R(&ElbListOptions{}, "elb-list", "List loadbalancers", func(cli *huawei.SRegion, args *ElbListOptions) error { - elbs, err := cli.GetILoadBalancers() - if err != nil { - return err - } - - printList(elbs, len(elbs), 0, 0, []string{}) - return nil - }) - - type ElbCreateOptions struct { - Name string `help:"loadblancer name"` - SUBNET string `help:"subnet id"` - PrivateIP string `help:"loadbalancer private ip address"` - EipID string `help:"loadbalancer public ip id"` - } - shellutils.R(&ElbCreateOptions{}, "elb-create", "create loadbalancer", func(cli *huawei.SRegion, args *ElbCreateOptions) error { - loadbalancer := &cloudprovider.SLoadbalancer{ - Name: args.Name, - NetworkIDs: []string{args.SUBNET}, - EipID: args.EipID, - Address: args.PrivateIP, - } - - elb, err := cli.CreateLoadBalancer(loadbalancer) - if err != nil { - return err - } - - printObject(elb) - return nil - }) - - type ElbDeleteOptions struct { - ID string `help:"loadblancer id"` - } - shellutils.R(&ElbDeleteOptions{}, "elb-delete", "delete loadbalancer", func(cli *huawei.SRegion, args *ElbDeleteOptions) error { - err := cli.DeleteLoadBalancer(args.ID) - if err != nil { - return err - } - - return nil - }) - - type ElbListenerListOptions struct { - ElbID string `help:"loadblancer id"` - } - shellutils.R(&ElbListenerListOptions{}, "elb-listener-list", "list loadbalancer listener", func(cli *huawei.SRegion, args *ElbListenerListOptions) error { - listeners, err := cli.GetLoadBalancerListeners(args.ElbID) - if err != nil { - return err - } - - printList(listeners, len(listeners), 0, 0, []string{}) - return nil - }) - - type ElbListenerCreateOptions struct { - Name string `help:"listener name"` - Desc string `help:"listener Description"` - Http2 bool `help:"http2 enable status"` - PoolID string `help:"default backend group id"` - CertId string `help:"default certification id"` - XForwardedFor bool `help:"XForwardedFor enable status"` - LISTENER_TYPE string `help:"listener type" choices:"tcp|udp|http|https"` - LISTENER_PORT int `help:"listener port"` - ELB_ID string `help:"loadbalancer id"` - } - shellutils.R(&ElbListenerCreateOptions{}, "elb-listener-create", "create loadbalancer listener", func(cli *huawei.SRegion, args *ElbListenerCreateOptions) error { - input := &cloudprovider.SLoadbalancerListener{ - Name: args.Name, - LoadbalancerID: args.ELB_ID, - ListenerType: args.LISTENER_TYPE, - ListenerPort: args.LISTENER_PORT, - BackendGroupID: args.PoolID, - EnableHTTP2: args.Http2, - CertificateID: args.CertId, - Description: args.Desc, - XForwardedFor: args.XForwardedFor, - } - listener, err := cli.CreateLoadBalancerListener(input) - if err != nil { - return err - } - - printObject(listener) - return nil - }) - - type ElbListenerUpdateOptions struct { - Name string `help:"listener name"` - Desc string `help:"listener Description"` - Http2 bool `help:"http2 enable status"` - PoolID string `help:"default backend group id"` - CertId string `help:"default certification id"` - XForwardedFor bool `help:"XForwardedFor enable status"` - LISTENER_ID string `help:"listener id"` - } - shellutils.R(&ElbListenerUpdateOptions{}, "elb-listener-update", "update loadbalancer listener", func(cli *huawei.SRegion, args *ElbListenerUpdateOptions) error { - input := &cloudprovider.SLoadbalancerListener{ - Name: args.Name, - BackendGroupID: args.PoolID, - EnableHTTP2: args.Http2, - CertificateID: args.CertId, - Description: args.Desc, - XForwardedFor: args.XForwardedFor, - } - - err := cli.UpdateLoadBalancerListener(args.LISTENER_ID, input) - if err != nil { - return err - } - - return nil - }) - - type ElbBackendGroupListOptions struct { - ElbID string `help:"loadbalancer id"` - } - shellutils.R(&ElbBackendGroupListOptions{}, "elb-backend-group-list", "List backend groups", func(cli *huawei.SRegion, args *ElbBackendGroupListOptions) error { - elbbg, err := cli.GetLoadBalancerBackendGroups(args.ElbID) - if err != nil { - return err - } - - printList(elbbg, len(elbbg), 0, 0, []string{}) - return nil - }) - - type ElbBackendGroupCreateOptions struct { - Name string `help:"backend group name"` - Desc string `help:"backend group description"` - PROTOCOL string `help:"backend group protocol" choices:"tcp|udp|http"` - ALGORITHM string `help:"backend group algorithm" choices:"rr|wlc|sch"` - ListenerID string `help:"listener id to binding"` - ElbID string `help:"loadbalancer id belong to"` - StickySessionType string `help:"sticky session type" choices:"insert|server"` - StickySessionCookieName string `help:"sticky session cookie name"` - StickySessionTimeout int `help:"sticky session timeout. udp/tcp 1~60. http 1~1440"` - HealthCheck bool `help:"enable health check"` - HealthCheckType string `help:"health check type protocol" choices:"tcp|udp|http"` - HealthCheckTimeout int `help:"health check timeout"` - HealthCheckDomain string `help:"health check domain"` - HealthCheckURI string `help:"health check uri path"` - HealthCheckInterval int `help:"health check interval"` - HealthCheckRise int `help:"health check max retries"` - } - shellutils.R(&ElbBackendGroupCreateOptions{}, "elb-backend-group-create", "Create backend groups", func(cli *huawei.SRegion, args *ElbBackendGroupCreateOptions) error { - var health *cloudprovider.SLoadbalancerHealthCheck - if args.HealthCheck { - health = &cloudprovider.SLoadbalancerHealthCheck{ - HealthCheckType: args.HealthCheckType, - HealthCheckTimeout: args.HealthCheckTimeout, - HealthCheckDomain: args.HealthCheckDomain, - HealthCheckURI: args.HealthCheckURI, - HealthCheckInterval: args.HealthCheckInterval, - HealthCheckRise: args.HealthCheckRise, - } - } - - var sticky *cloudprovider.SLoadbalancerStickySession - if len(args.StickySessionType) > 0 { - sticky = &cloudprovider.SLoadbalancerStickySession{ - StickySessionCookie: args.StickySessionCookieName, - StickySessionType: args.StickySessionType, - StickySessionCookieTimeout: args.StickySessionTimeout, - } - } - - group := &cloudprovider.SLoadbalancerBackendGroup{ - Name: args.Name, - LoadbalancerID: args.ElbID, - ListenerID: args.ListenerID, - ListenType: args.PROTOCOL, - Scheduler: args.ALGORITHM, - StickySession: sticky, - HealthCheck: health, - } - - elbbg, err := cli.CreateLoadBalancerBackendGroup(group) - if err != nil { - return err - } - - printObject(elbbg) - return nil - }) - - type ElbBackendGroupUpdateOptions struct { - POOL_ID string `help:"backend group id"` - Name string `help:"backend group name"` - } - shellutils.R(&ElbBackendGroupUpdateOptions{}, "elb-backend-group-update", "Update backend groups", func(cli *huawei.SRegion, args *ElbBackendGroupUpdateOptions) error { - group := &cloudprovider.SLoadbalancerBackendGroup{ - Name: args.Name, - } - - elbbg, err := cli.UpdateLoadBalancerBackendGroup(args.POOL_ID, group) - if err != nil { - return err - } - - printObject(elbbg) - return nil - }) - - type ElbBackendGroupDeleteOptions struct { - POOL_ID string `help:"backend group id"` - } - shellutils.R(&ElbBackendGroupDeleteOptions{}, "elb-backend-group-delete", "Delete backend group", func(cli *huawei.SRegion, args *ElbBackendGroupDeleteOptions) error { - err := cli.DeleteLoadBalancerBackendGroup(args.POOL_ID) - if err != nil { - return err - } - - return nil - }) - - type ElbBackendAddOptions struct { - Name string `help:"backend name"` - POOL_ID string `help:"backend group id"` - SUBNET_ID string `help:"instance subnet id"` - ADDRESS string `help:"instance ip address"` - PORT int `help:"backend protocol port [1,65535]"` - Weight int `help:"backend weight [0,100]" default:"1"` - } - shellutils.R(&ElbBackendAddOptions{}, "elb-backend-add", "Add backend to backendgroup", func(cli *huawei.SRegion, args *ElbBackendAddOptions) error { - elbb, err := cli.AddLoadBalancerBackend(args.POOL_ID, args.SUBNET_ID, args.ADDRESS, args.PORT, args.Weight) - if err != nil { - return err - } - - printObject(elbb) - return nil - }) - - type ElbBackendListOptions struct { - POOL_ID string `help:"backend group id"` - } - shellutils.R(&ElbBackendListOptions{}, "elb-backend-list", "list backend", func(cli *huawei.SRegion, args *ElbBackendListOptions) error { - elbb, err := cli.GetLoadBalancerBackends(args.POOL_ID) - if err != nil { - return err - } - - printList(elbb, len(elbb), 0, 0, []string{}) - return nil - }) - - type ElbListenerPolicyListOptions struct { - ListenerID string `help:"listener id"` - } - shellutils.R(&ElbListenerPolicyListOptions{}, "elb-listener-policy-list", "List listener policies", func(cli *huawei.SRegion, args *ElbListenerPolicyListOptions) error { - elblp, err := cli.GetLoadBalancerPolicies(args.ListenerID) - if err != nil { - return err - } - - printList(elblp, len(elblp), 0, 0, []string{}) - return nil - }) - - type ElbListenerPolicyCreateOptions struct { - LISTENER_ID string `help:"listener id"` - Name string `help:"policy name"` - Domain string `help:"policy domain"` - Path string `help:"policy path"` - PoolID string `help:"backend group name"` - } - shellutils.R(&ElbListenerPolicyCreateOptions{}, "elb-listener-policy-create", "Create listener policy", func(cli *huawei.SRegion, args *ElbListenerPolicyCreateOptions) error { - rule := &cloudprovider.SLoadbalancerListenerRule{ - Name: args.Name, - Domain: args.Domain, - Path: args.Path, - BackendGroupID: args.PoolID, - } - - elblp, err := cli.CreateLoadBalancerPolicy(args.LISTENER_ID, rule) - if err != nil { - return err - } - - printObject(elblp) - return nil - }) - - type ElbListenerPolicyDeleteOptions struct { - POLICY_ID string `help:"policy id"` - } - shellutils.R(&ElbListenerPolicyDeleteOptions{}, "elb-listener-policy-delete", "Delete listener policy", func(cli *huawei.SRegion, args *ElbListenerPolicyDeleteOptions) error { - err := cli.DeleteLoadBalancerPolicy(args.POLICY_ID) - if err != nil { - return err - } - - return nil - }) - - type ElbListenerPolicyRuleListOptions struct { - POLICY_ID string `help:"policy id"` - } - shellutils.R(&ElbListenerPolicyRuleListOptions{}, "elb-listener-policyrule-list", "List listener policy rules", func(cli *huawei.SRegion, args *ElbListenerPolicyRuleListOptions) error { - elblpr, err := cli.GetLoadBalancerPolicyRules(args.POLICY_ID) - if err != nil { - return err - } - - printList(elblpr, len(elblpr), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/modelarts.go b/pkg/multicloud/hcso/shell/modelarts.go deleted file mode 100644 index 2e0316f725..0000000000 --- a/pkg/multicloud/hcso/shell/modelarts.go +++ /dev/null @@ -1,82 +0,0 @@ -// @@ -0,0 +1,46 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ModelartsPoolListOption struct { - PoolId string `help:"Pool Id"` - } - - shellutils.R(&ModelartsPoolListOption{}, "modelarts-pool-list", "List Modelarts Pool", func(cli *huawei.SRegion, args *ModelartsPoolListOption) error { - pools, err := cli.GetIModelartsPools() - if err != nil { - return err - } - printList(pools, len(pools), 0, 0, nil) - return nil - }) - - shellutils.R(&ModelartsPoolListOption{}, "modelarts-pool-detail", "List pool", func(cli *huawei.SRegion, args *ModelartsPoolListOption) error { - pool, err := cli.GetIModelartsPoolById(args.PoolId) - if err != nil { - return err - } - printObject(pool) - return nil - }) - - shellutils.R(&cloudprovider.ModelartsPoolCreateOption{}, "modelarts-pool-create", "Create Modelarts Pool", func(cli *huawei.SRegion, args *cloudprovider.ModelartsPoolCreateOption) error { - res, err := cli.CreateIModelartsPool(args) - if err != nil { - return err - } - printObject(res) - return nil - }) - - shellutils.R(&ModelartsPoolListOption{}, "modelarts-pool-delete", "Delete Modelarts Pool", func(cli *huawei.SRegion, args *ModelartsPoolListOption) error { - res, err := cli.DeletePool(args.PoolId) - if err != nil { - return err - } - printObject(res) - return nil - }) - - shellutils.R(&ModelartsPoolListOption{}, "modelarts-pool-monitor", "Modelarts Pool Monitor", func(cli *huawei.SRegion, args *ModelartsPoolListOption) error { - res, err := cli.MonitorPool(args.PoolId) - if err != nil { - return err - } - printList(res.Metrics, len(res.Metrics), 0, 0, nil) - return nil - }) - - shellutils.R(&ModelartsPoolListOption{}, "modelarts-pool-by-id", "Modelarts Pool By Id", func(cli *huawei.SRegion, args *ModelartsPoolListOption) error { - res, err := cli.GetIModelartsPoolById(args.PoolId) - if err != nil { - return err - } - printObject(res) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/modelarts_sku.go b/pkg/multicloud/hcso/shell/modelarts_sku.go deleted file mode 100644 index adddc35a46..0000000000 --- a/pkg/multicloud/hcso/shell/modelarts_sku.go +++ /dev/null @@ -1,35 +0,0 @@ -// @@ -0,0 +1,46 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ModelartsResourceflavorsListOption struct { - PoolName string `help:"Pool Name"` - } - shellutils.R(&ModelartsResourceflavorsListOption{}, "modelarts-sku-list", "List Modelarts Pool", func(cli *huawei.SRegion, args *ModelartsResourceflavorsListOption) error { - resourceflavors, err := cli.GetIModelartsPoolSku() - if err != nil { - return err - } - printList(resourceflavors, len(resourceflavors), 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/monitor.go b/pkg/multicloud/hcso/shell/monitor.go deleted file mode 100644 index c74162870c..0000000000 --- a/pkg/multicloud/hcso/shell/monitor.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/pkg/util/timeutils" - - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type MetricListOptions struct { - } - shellutils.R(&MetricListOptions{}, "metrics-list", "List metrics", func(cli *huawei.SRegion, args *MetricListOptions) error { - metrics, err := cli.GetMetrics() - if err != nil { - return err - } - printList(metrics, 0, 0, 0, nil) - return nil - }) - - type MetricDataOptions struct { - START int `help:"Start metrics"` - Count int `help:"Metric count" default:"1"` - SINCE string `help:"since"` - UNTIL string `help:"until"` - } - shellutils.R(&MetricDataOptions{}, "metrics-data-list", "List metrics", func(cli *huawei.SRegion, args *MetricDataOptions) error { - metrics, err := cli.GetMetrics() - if err != nil { - return err - } - since, err := timeutils.ParseTimeStr(args.SINCE) - if err != nil { - return err - } - until, err := timeutils.ParseTimeStr(args.UNTIL) - if err != nil { - return err - } - data, err := cli.GetMetricsData(metrics[args.START:args.START+args.Count], since, until) - if err != nil { - return err - } - printList(data, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/natdtable.go b/pkg/multicloud/hcso/shell/natdtable.go deleted file mode 100644 index ee071d60a8..0000000000 --- a/pkg/multicloud/hcso/shell/natdtable.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SNatDTableOptions struct { - NatGatewayID string `help:"Nat Gateway ID" positional:"true"` - } - shellutils.R(&SNatDTableOptions{}, "dnat-table-list", "List dnat table", func(region *huawei.SRegion, args *SNatDTableOptions) error { - DNatTable, err := region.GetNatDTable(args.NatGatewayID) - if err != nil { - return err - } - printList(DNatTable, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/natgateway.go b/pkg/multicloud/hcso/shell/natgateway.go deleted file mode 100644 index 4644f38c72..0000000000 --- a/pkg/multicloud/hcso/shell/natgateway.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NatGatewayOptions struct { - NatGatewayID string `help:"Nat Gateway ID"` - VpcID string `help:"Vpc ID"` - } - shellutils.R(&NatGatewayOptions{}, "nat-list", "List nat gateway", func(region *huawei.SRegion, args *NatGatewayOptions) error { - natGateways, err := region.GetNatGateways(args.VpcID, args.NatGatewayID) - if err != nil { - return err - } - printList(natGateways, 0, 0, 0, nil) - return nil - }) - - type NatGatewayIdOptions struct { - ID string `help:"Nat Id"` - } - - shellutils.R(&NatGatewayIdOptions{}, "nat-delete", "Delete nat gateways", func(cli *huawei.SRegion, args *NatGatewayIdOptions) error { - return cli.DeleteNatGateway(args.ID) - }) - - shellutils.R(&NatGatewayIdOptions{}, "nat-show", "Show nat gateways", func(cli *huawei.SRegion, args *NatGatewayIdOptions) error { - nat, err := cli.GetNatGateway(args.ID) - if err != nil { - return err - } - printObject(nat) - return nil - }) - - type SCreateDNatOptions struct { - GatewayID string `help:"Nat Gateway ID" positional:"true"` - Protocol string `help:"Protocol(tcp/udp)" positional:"true"` - ExternalIPID string `help:"External IP ID" positional:"true"` - ExternalPort int `help:"External Port" positional:"true"` - InternalIP string `help:"Internal IP" positional:"true"` - InternalPort int `help:"Nat Gateway ID" positional:"true"` - } - shellutils.R(&SCreateDNatOptions{}, "dnat-create", "Create dnat", func(region *huawei.SRegion, args *SCreateDNatOptions) error { - rule := cloudprovider.SNatDRule{ - Protocol: args.Protocol, - ExternalIPID: args.ExternalIPID, - ExternalPort: args.ExternalPort, - InternalIP: args.InternalIP, - InternalPort: args.InternalPort, - } - dnat, err := region.CreateNatDEntry(rule, args.GatewayID) - if err != nil { - return err - } - printObject(dnat) - return nil - }) - - type SCreateSNatOptions struct { - GatewayID string `help:"Nat Gateway ID" positional:"true"` - SourceCIDR string `help:"Source cidr" positional:"true"` - ExternalIPID string `help:"External IP ID" positional:"true"` - } - shellutils.R(&SCreateSNatOptions{}, "snat-create", "Create snat", func(region *huawei.SRegion, args *SCreateSNatOptions) error { - rule := cloudprovider.SNatSRule{ - SourceCIDR: args.SourceCIDR, - ExternalIPID: args.ExternalIPID, - } - snat, err := region.CreateNatSEntry(rule, args.GatewayID) - if err != nil { - return err - } - printObject(snat) - return nil - }) - - type SShowSNatOptions struct { - NatID string `help:"SNat ID" positional:"true"` - } - shellutils.R(&SShowSNatOptions{}, "snat-show", "Show snat", func(region *huawei.SRegion, args *SShowSNatOptions) error { - snat, err := region.GetNatSEntryByID(args.NatID) - if err != nil { - return err - } - printObject(snat) - return nil - }) - - type SShowDNatOptions struct { - NatID string `help:"DNat ID" positional:"true"` - } - shellutils.R(&SShowDNatOptions{}, "dnat-show", "Show dnat", func(region *huawei.SRegion, args *SShowDNatOptions) error { - dnat, err := region.GetNatDEntryByID(args.NatID) - if err != nil { - return err - } - printObject(dnat) - return nil - }) - - type SDeleteSNatOptions struct { - NatID string `help:"SNat ID" positional:"true"` - } - shellutils.R(&SDeleteSNatOptions{}, "snat-delete", "Delete snat", func(region *huawei.SRegion, args *SDeleteSNatOptions) error { - err := region.DeleteNatSEntry(args.NatID) - if err != nil { - return err - } - return nil - }) - - type SDeleteDNatOptions struct { - NatID string `help:"DNat ID" positional:"true"` - } - shellutils.R(&SDeleteDNatOptions{}, "dnat-delete", "Delete dnat", func(region *huawei.SRegion, args *SDeleteDNatOptions) error { - err := region.DeleteNatDEntry(args.NatID) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/natstable.go b/pkg/multicloud/hcso/shell/natstable.go deleted file mode 100644 index bfe2195722..0000000000 --- a/pkg/multicloud/hcso/shell/natstable.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SNatSTableOptions struct { - NatGatewayID string `help:"Nat Gateway ID" positional:"true"` - } - shellutils.R(&SNatSTableOptions{}, "snat-table-list", "List snat table", func(region *huawei.SRegion, args *SNatSTableOptions) error { - sNatTable, err := region.GetNatSTable(args.NatGatewayID) - if err != nil { - return err - } - printList(sNatTable, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/network.go b/pkg/multicloud/hcso/shell/network.go deleted file mode 100644 index 8dbab7d219..0000000000 --- a/pkg/multicloud/hcso/shell/network.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VSwitchListOptions struct { - Vpc string `help:"Vpc ID"` - } - shellutils.R(&VSwitchListOptions{}, "subnet-list", "List subnets", func(cli *huawei.SRegion, args *VSwitchListOptions) error { - vswitches, e := cli.GetNetwroks(args.Vpc) - if e != nil { - return e - } - printList(vswitches, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/obs.go b/pkg/multicloud/hcso/shell/obs.go deleted file mode 100644 index 7d36154926..0000000000 --- a/pkg/multicloud/hcso/shell/obs.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/printutils" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ObsBucketListOptions struct { - } - shellutils.R(&ObsBucketListOptions{}, "obs-list", "List all buckets", func(cli *huawei.SRegion, args *ObsBucketListOptions) error { - buckets, err := cli.GetIBuckets() - if err != nil { - return err - } - printList(buckets, 0, 0, 0, nil) - return nil - }) - shellutils.R(&ObsBucketListOptions{}, "bucket-list", "List all buckets", func(cli *huawei.SRegion, args *ObsBucketListOptions) error { - buckets, err := cli.GetIBuckets() - if err != nil { - return err - } - printutils.PrintGetterList(buckets, nil) - return nil - }) - - type ObsBucketShowOptions struct { - BUCKET string `help:"bucket name to show"` - } - shellutils.R(&ObsBucketShowOptions{}, "obs-show", "Show bucket detail", func(cli *huawei.SRegion, args *ObsBucketShowOptions) error { - bucket, err := cli.GetIBucketById(args.BUCKET) - if err != nil { - return err - } - printObject(bucket) - return nil - }) - - type ObsBucketCreateOptions struct { - BUCKET string `help:"bucket name to show"` - StorageClass string `help:"storage class"` - Acl string `help:"acl"` - } - shellutils.R(&ObsBucketCreateOptions{}, "obs-create", "Create new OBS bucket", func(cli *huawei.SRegion, args *ObsBucketCreateOptions) error { - err := cli.CreateIBucket(args.BUCKET, args.StorageClass, args.Acl) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&ObsBucketShowOptions{}, "obs-delete", "Delete OBS bucket", func(cli *huawei.SRegion, args *ObsBucketShowOptions) error { - err := cli.DeleteIBucket(args.BUCKET) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/port.go b/pkg/multicloud/hcso/shell/port.go deleted file mode 100644 index b0a35c1416..0000000000 --- a/pkg/multicloud/hcso/shell/port.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type PortListOptions struct { - InstanceId string - } - shellutils.R(&PortListOptions{}, "port-list", "List ports", func(cli *huawei.SRegion, args *PortListOptions) error { - ports, err := cli.GetPorts(args.InstanceId) - if err != nil { - return err - } - printList(ports, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/printutils.go b/pkg/multicloud/hcso/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/hcso/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/hcso/shell/quota.go b/pkg/multicloud/hcso/shell/quota.go deleted file mode 100644 index 13a7cbbdf3..0000000000 --- a/pkg/multicloud/hcso/shell/quota.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type QuotaListOptions struct { - } - shellutils.R(&QuotaListOptions{}, "quota-list", "List Quotas", func(cli *huawei.SRegion, args *QuotaListOptions) error { - quotas, err := cli.GetQuotas() - if err != nil { - return err - } - printList(quotas, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/hcso/shell/region.go b/pkg/multicloud/hcso/shell/region.go deleted file mode 100644 index 3c4bf386c9..0000000000 --- a/pkg/multicloud/hcso/shell/region.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *huawei.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&RegionListOptions{}, "project-list", "List projects", func(cli *huawei.SRegion, args *RegionListOptions) error { - projects, err := cli.GetClient().GetProjects() - if err != nil { - return err - } - printList(projects, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&RegionListOptions{}, "domain-list", "List domains", func(cli *huawei.SRegion, args *RegionListOptions) error { - domains, err := cli.GetClient().GetDomains() - if err != nil { - return err - } - printList(domains, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&RegionListOptions{}, "capabilities", "Get capabilities", func(cli *huawei.SRegion, args *RegionListOptions) error { - capabilities := cli.GetClient().GetCapabilities() - fmt.Println(capabilities) - return nil - }) - - shellutils.R(&RegionListOptions{}, "subaccount-list", "List account", func(cli *huawei.SRegion, args *RegionListOptions) error { - accounts, err := cli.GetClient().GetSubAccounts() - if err != nil { - return err - } - printList(accounts, 0, 0, 0, nil) - return nil - }) - - type SProjectRoleListOptions struct { - GROUPID string - } - - shellutils.R(&SProjectRoleListOptions{}, "mos-role-list", "List account", func(cli *huawei.SRegion, args *SProjectRoleListOptions) error { - ret, err := cli.GetClient().GetMosRoles(args.GROUPID) - if err != nil { - return err - } - printList(ret, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/hcso/shell/role.go b/pkg/multicloud/hcso/shell/role.go deleted file mode 100644 index a8d95f5456..0000000000 --- a/pkg/multicloud/hcso/shell/role.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "io/ioutil" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - cloudid_api "yunion.io/x/onecloud/pkg/apis/cloudid" - api "yunion.io/x/onecloud/pkg/apis/compute" - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RoleListOptions struct { - DomainId string - Name string - } - shellutils.R(&RoleListOptions{}, "cloud-policy-list", "List cloudpolicy", func(cli *huawei.SRegion, args *RoleListOptions) error { - roles, err := cli.GetClient().GetRoles(args.DomainId, args.Name) - if err != nil { - return err - } - printList(roles, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&RoleListOptions{}, "cloud-custom-policy-list", "List cloudpolicy", func(cli *huawei.SRegion, args *RoleListOptions) error { - roles, err := cli.GetClient().GetCustomRoles() - if err != nil { - return err - } - printList(roles, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&RoleListOptions{}, "cloud-policy-export", "Export cloudpolicy", func(cli *huawei.SRegion, args *RoleListOptions) error { - roles, err := cli.GetClient().GetRoles(args.DomainId, args.Name) - if err != nil { - return err - } - type sRule struct { - Name string - Id string - ExternalId string - CloudEnv string - Provider string - Description string - Document jsonutils.JSONDict - PolicyType string - Status string - } - idMap := map[string]bool{} - ret := []sRule{} - for i := range roles { - if _, ok := idMap[roles[i].DisplayName]; ok { - log.Errorf("duplicate id: %s", roles[i].DisplayName) - continue - } - idMap[roles[i].DisplayName] = true - ret = append(ret, sRule{ - Name: roles[i].DisplayName, - Id: roles[i].Id, - ExternalId: roles[i].DisplayName, - CloudEnv: api.CLOUD_PROVIDER_HCSO, - Provider: api.CLOUD_PROVIDER_HCSO, - Description: roles[i].DescriptionCn, - Document: roles[i].Policy, - PolicyType: cloudid_api.CLOUD_POLICY_TYPE_SYSTEM, - Status: cloudid_api.CLOUD_POLICY_STATUS_AVAILABLE, - }) - } - return ioutil.WriteFile(fmt.Sprintf("%s.json", api.CLOUD_PROVIDER_HCSO), []byte(jsonutils.Marshal(ret).PrettyString()), 0644) - }) -} diff --git a/pkg/multicloud/hcso/shell/routetable.go b/pkg/multicloud/hcso/shell/routetable.go deleted file mode 100644 index 66116b96b0..0000000000 --- a/pkg/multicloud/hcso/shell/routetable.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RouteTableListOption struct { - VpcId string `help:"Vpc ID"` - } - shellutils.R(&RouteTableListOption{}, "routetable-list", "List vpc route tables", func(cli *huawei.SRegion, args *RouteTableListOption) error { - routetables, err := cli.GetRouteTables(args.VpcId) - if err != nil { - return err - } - printList(routetables, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/saml_provider.go b/pkg/multicloud/hcso/shell/saml_provider.go deleted file mode 100644 index ca59870c2c..0000000000 --- a/pkg/multicloud/hcso/shell/saml_provider.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SAMLProviderListOptions struct { - } - shellutils.R(&SAMLProviderListOptions{}, "saml-provider-list", "List saml provider", func(cli *huawei.SRegion, args *SAMLProviderListOptions) error { - result, err := cli.GetClient().ListSAMLProviders() - if err != nil { - return err - } - printList(result, 0, 0, 0, nil) - return nil - }) - - type SAMLProviderIdOptions struct { - ID string - } - - shellutils.R(&SAMLProviderIdOptions{}, "saml-provider-delete", "Delete saml provider", func(cli *huawei.SRegion, args *SAMLProviderIdOptions) error { - return cli.GetClient().DeleteSAMLProvider(args.ID) - }) - - shellutils.R(&SAMLProviderIdOptions{}, "saml-provider-protocol-list", "List saml provider protocol", func(cli *huawei.SRegion, args *SAMLProviderIdOptions) error { - result, err := cli.GetClient().GetSAMLProviderProtocols(args.ID) - if err != nil { - return err - } - printList(result, 0, 0, 0, nil) - return nil - }) - - type SAMLProviderProtocolDeleteOptions struct { - SAML_PROVIDER string - PROTOCOL string - } - - shellutils.R(&SAMLProviderProtocolDeleteOptions{}, "saml-provider-protocol-delete", "Delete saml provider protocol", func(cli *huawei.SRegion, args *SAMLProviderProtocolDeleteOptions) error { - return cli.GetClient().DeleteSAMLProviderProtocol(args.SAML_PROVIDER, args.PROTOCOL) - }) - - shellutils.R(&SAMLProviderIdOptions{}, "saml-provider-metadata-show", "Show saml provider metadata", func(cli *huawei.SRegion, args *SAMLProviderIdOptions) error { - result, err := cli.GetClient().GetSAMLProviderMetadata(args.ID) - if err != nil { - return err - } - printObject(result) - return nil - }) - - type SAMLProviderMetadataOptions struct { - ID string - METADATA string - } - - shellutils.R(&SAMLProviderMetadataOptions{}, "saml-provider-metadata-update", "Update saml provider metadata", func(cli *huawei.SRegion, args *SAMLProviderMetadataOptions) error { - return cli.GetClient().UpdateSAMLProviderMetadata(args.ID, args.METADATA) - }) - - type MappingListOptions struct { - } - - shellutils.R(&MappingListOptions{}, "saml-provider-mapping-list", "List saml provider mapping", func(cli *huawei.SRegion, args *MappingListOptions) error { - mappings, err := cli.GetClient().ListSAMLProviderMappings() - if err != nil { - return err - } - printList(mappings, 0, 0, 0, nil) - return nil - }) - - type MappingInitOptions struct { - SAML_PROVIDER string - } - - shellutils.R(&MappingInitOptions{}, "saml-provider-mapping-init", "Init saml provider mapping", func(cli *huawei.SRegion, args *MappingInitOptions) error { - return cli.GetClient().InitSAMLProviderMapping(args.SAML_PROVIDER) - }) - - type MappingDeleteOptions struct { - ID string - } - - shellutils.R(&MappingDeleteOptions{}, "saml-provider-mapping-delete", "Delete saml provider mapping", func(cli *huawei.SRegion, args *MappingDeleteOptions) error { - return cli.GetClient().DeleteSAMLProviderMapping(args.ID) - }) - -} diff --git a/pkg/multicloud/hcso/shell/secgroup.go b/pkg/multicloud/hcso/shell/secgroup.go deleted file mode 100644 index c5ab793eac..0000000000 --- a/pkg/multicloud/hcso/shell/secgroup.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - "yunion.io/x/onecloud/pkg/cloudprovider" - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - VpcId string `help:"VPC ID"` - Name string `help:"Secgroup name"` - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security group", func(cli *huawei.SRegion, args *SecurityGroupListOptions) error { - secgrps, e := cli.GetSecurityGroups(args.VpcId, args.Name) - if e != nil { - return e - } - printList(secgrps, 0, 0, 0, nil) - 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 *huawei.SRegion, args *SecurityGroupShowOptions) error { - secgrp, err := cli.GetSecurityGroupDetails(args.ID) - if err != nil { - return err - } - printObject(secgrp) - return nil - }) - - type SecurityGroupCreateOptions struct { - NAME string `help:"secgroup name"` - VPC string `help:"ID of VPC"` - Desc string `help:"description"` - } - shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create security group", func(cli *huawei.SRegion, args *SecurityGroupCreateOptions) error { - result, err := cli.CreateSecurityGroup(args.VPC, args.NAME, args.Desc) - if err != nil { - return err - } - printObject(result) - return nil - }) - - type SecurityGroupRuleIdOptions struct { - ID string - } - - shellutils.R(&SecurityGroupRuleIdOptions{}, "security-group-rule-delete", "Delete security group rule", func(cli *huawei.SRegion, args *SecurityGroupRuleIdOptions) error { - return cli.DeleteSecurityGroupRule(args.ID) - }) - - type SecurityGroupRuleCreateOptions struct { - SECGROUP_ID string - RULE string - } - - shellutils.R(&SecurityGroupRuleCreateOptions{}, "security-group-rule-create", "Create security group rule", func(cli *huawei.SRegion, args *SecurityGroupRuleCreateOptions) error { - _rule, err := secrules.ParseSecurityRule(args.RULE) - if err != nil { - return errors.Wrapf(err, "invalid rule %s", args.RULE) - } - rule := cloudprovider.SecurityRule{ - SecurityRule: *_rule, - } - return cli.CreateSecurityGroupRule(args.SECGROUP_ID, rule) - }) - -} diff --git a/pkg/multicloud/hcso/shell/service.go b/pkg/multicloud/hcso/shell/service.go deleted file mode 100644 index 0f2a7d59aa..0000000000 --- a/pkg/multicloud/hcso/shell/service.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ServicesListOptions struct { - } - shellutils.R(&ServicesListOptions{}, "service-list", "List services", func(cli *huawei.SRegion, args *ServicesListOptions) error { - services, _ := cli.GetServices() - printList(services, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/skus.go b/pkg/multicloud/hcso/shell/skus.go deleted file mode 100644 index 1330586703..0000000000 --- a/pkg/multicloud/hcso/shell/skus.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SkuListOptions struct { - } - shellutils.R(&SkuListOptions{}, "sku-list", "List skus", func(cli *huawei.SRegion, args *SkuListOptions) error { - skus, e := cli.GetISkus() - if e != nil { - return e - } - - printList(skus, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/snapshot.go b/pkg/multicloud/hcso/shell/snapshot.go deleted file mode 100644 index 0d756ae952..0000000000 --- a/pkg/multicloud/hcso/shell/snapshot.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SnapshotListOptions struct { - DiskId string `help:"Disk ID"` - Name string `help:"Snapshot Name"` - } - shellutils.R(&SnapshotListOptions{}, "snapshot-list", "List snapshot", func(cli *huawei.SRegion, args *SnapshotListOptions) error { - snapshots, err := cli.GetSnapshots(args.DiskId, args.Name) - if err != nil { - return err - } - printList(snapshots, 0, 0, 0, nil) - return nil - }) - - type SnapshotDeleteOptions struct { - ID string `help:"Snapshot ID"` - } - - shellutils.R(&SnapshotDeleteOptions{}, "snapshot-delete", "Delete snapshot", func(cli *huawei.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 *huawei.SRegion, args *SnapshotCreateOptions) error { - _, err := cli.CreateSnapshot(args.DiskId, args.Name, args.Desc) - return err - }) - -} diff --git a/pkg/multicloud/hcso/shell/vpc.go b/pkg/multicloud/hcso/shell/vpc.go deleted file mode 100644 index 6e0256e268..0000000000 --- a/pkg/multicloud/hcso/shell/vpc.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - } - shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *huawei.SRegion, args *VpcListOptions) error { - vpcs, e := cli.GetVpcs() - if e != nil { - return e - } - printList(vpcs, 0, 0, 0, nil) - return nil - }) - - type VpcCreateOptions struct { - NAME string - CIDR string - Desc string - } - - shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *huawei.SRegion, args *VpcCreateOptions) error { - vpc, err := cli.CreateVpc(args.NAME, args.CIDR, args.Desc) - if err != nil { - return err - } - printObject(vpc) - return nil - }) - - type VpcIdOption struct { - ID string - } - - shellutils.R(&VpcIdOption{}, "vpc-delete", "Delete vpc", func(cli *huawei.SRegion, args *VpcIdOption) error { - return cli.DeleteVpc(args.ID) - }) - - type VpcPeeringListOPtion struct { - VPCID string - } - shellutils.R(&VpcPeeringListOPtion{}, "vpcPeering-list", "List vpcPeering", func(cli *huawei.SRegion, args *VpcPeeringListOPtion) error { - vpcPeerings, err := cli.GetVpcPeerings(args.VPCID) - if err != nil { - return err - } - printList(vpcPeerings, 0, 0, 0, nil) - return nil - }) - - type VpcPeeringShowOPtion struct { - VPCPEERINGID string - } - shellutils.R(&VpcPeeringShowOPtion{}, "vpcPeering-show", "show vpcPeering", func(cli *huawei.SRegion, args *VpcPeeringShowOPtion) error { - vpcPeering, err := cli.GetVpcPeering(args.VPCPEERINGID) - if err != nil { - return err - } - printObject(vpcPeering) - return nil - }) - - type VpcPeeringCreateOPtion struct { - NAME string - VPCID string - PEERVPCID string - PEEROWNERID string - } - shellutils.R(&VpcPeeringCreateOPtion{}, "vpcPeering-create", "create vpcPeering", func(cli *huawei.SRegion, args *VpcPeeringCreateOPtion) error { - opts := cloudprovider.VpcPeeringConnectionCreateOptions{} - opts.Name = args.NAME - opts.PeerVpcId = args.PEERVPCID - opts.PeerAccountId = args.PEEROWNERID - vpcPeering, err := cli.CreateVpcPeering(args.VPCID, &opts) - if err != nil { - return err - } - printObject(vpcPeering) - return nil - }) - - type VpcPeeringAcceptOPtion struct { - VPCPEERINGID string - } - shellutils.R(&VpcPeeringAcceptOPtion{}, "vpcPeering-accept", "Accept vpcPeering", func(cli *huawei.SRegion, args *VpcPeeringAcceptOPtion) error { - err := cli.AcceptVpcPeering(args.VPCPEERINGID) - if err != nil { - return err - } - return nil - }) - - type VpcPeeringDeleteOPtion struct { - VPCPEERINGID string - } - shellutils.R(&VpcPeeringDeleteOPtion{}, "vpcPeering-delete", "Delete vpcPeering", func(cli *huawei.SRegion, args *VpcPeeringDeleteOPtion) error { - err := cli.DeleteVpcPeering(args.VPCPEERINGID) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/hcso/shell/zone.go b/pkg/multicloud/hcso/shell/zone.go deleted file mode 100644 index dd3d172aee..0000000000 --- a/pkg/multicloud/hcso/shell/zone.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - huawei "yunion.io/x/onecloud/pkg/multicloud/hcso" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - } - shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *huawei.SRegion, args *ZoneListOptions) error { - zones, e := cli.GetIZones() - if e != nil { - return e - } - - printList(zones, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/hcso/snapshot.go b/pkg/multicloud/hcso/snapshot.go deleted file mode 100644 index dd661809cb..0000000000 --- a/pkg/multicloud/hcso/snapshot.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -/* -限制: -https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html -1. 从快照创建云硬盘时,volume_type字段必须和快照源云硬盘保持一致。 -2. 当指定的云硬盘类型在avaliability_zone内不存在时,则创建云硬盘失败。 -*/ - -type SnapshotStatusType string - -const ( - SnapshotStatusCreating SnapshotStatusType = "creating" - SnapshotStatusAvailable SnapshotStatusType = "available" // 云硬盘快照创建成功,可以使用。 - SnapshotStatusError SnapshotStatusType = "error" // 云硬盘快照在创建过程中出现错误。 - SnapshotStatusDeleting SnapshotStatusType = "deleting" // 云硬盘快照处于正在删除的过程中。 - SnapshotStatusErrorDeleting SnapshotStatusType = "error_deleting" // 云硬盘快照在删除过程中出现错误 - SnapshotStatusRollbacking SnapshotStatusType = "rollbacking" // 云硬盘快照处于正在回滚数据的过程中。 - SnapshotStatusBackingUp SnapshotStatusType = "backing-up" // 通过快照创建备份,快照状态就会变为backing-up -) - -type Metadata struct { - SystemEnableActive string `json:"__system__enableActive"` // 如果为true。则表明是系统盘快照 -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html -type SSnapshot struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - - Metadata Metadata `json:"metadata"` - CreatedAt string `json:"created_at"` - Description string `json:"description"` - ID string `json:"id"` - Name string `json:"name"` - OSExtendedSnapshotAttributesProgress string `json:"os-extended-snapshot-attributes:progress"` - OSExtendedSnapshotAttributesProjectID string `json:"os-extended-snapshot-attributes:project_id"` - Size int32 `json:"size"` // GB - Status string `json:"status"` - UpdatedAt string `json:"updated_at"` - VolumeID string `json:"volume_id"` -} - -func (self *SSnapshot) GetId() string { - return self.ID -} - -func (self *SSnapshot) GetName() string { - return self.Name -} - -func (self *SSnapshot) GetGlobalId() string { - return self.ID -} - -func (self *SSnapshot) GetStatus() string { - switch SnapshotStatusType(self.Status) { - case SnapshotStatusAvailable: - return api.SNAPSHOT_READY - case SnapshotStatusCreating: - return api.SNAPSHOT_CREATING - case SnapshotStatusDeleting: - return api.SNAPSHOT_DELETING - case SnapshotStatusErrorDeleting, SnapshotStatusError: - return api.SNAPSHOT_FAILED - case SnapshotStatusRollbacking: - return api.SNAPSHOT_ROLLBACKING - default: - return api.SNAPSHOT_UNKNOWN - } -} - -func (self *SSnapshot) Refresh() error { - snapshot, err := self.region.GetSnapshotById(self.GetId()) - if err != nil { - return err - } - - if err := jsonutils.Update(self, snapshot); err != nil { - return err - } - - return nil -} - -func (self *SSnapshot) IsEmulated() bool { - return false -} - -func (self *SSnapshot) GetSizeMb() int32 { - return self.Size * 1024 -} - -func (self *SSnapshot) GetDiskId() string { - return self.VolumeID -} - -func (self *SSnapshot) GetDiskType() string { - if self.Metadata.SystemEnableActive == "true" { - return api.DISK_TYPE_SYS - } else { - return api.DISK_TYPE_DATA - } -} - -func (self *SSnapshot) Delete() error { - if self.region == nil { - return fmt.Errorf("not init region for snapshot %s", self.GetId()) - } - return self.region.DeleteSnapshot(self.GetId()) -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408627.html -func (self *SRegion) GetSnapshots(diskId string, snapshotName string) ([]SSnapshot, error) { - params := make(map[string]string) - - if len(diskId) > 0 { - params["volume_id"] = diskId - } - - if len(snapshotName) > 0 { - params["name"] = snapshotName - } - - snapshots := make([]SSnapshot, 0) - err := doListAllWithOffset(self.ecsClient.Snapshots.List, params, &snapshots) - for i := range snapshots { - snapshots[i].region = self - } - - return snapshots, err -} - -func (self *SRegion) GetSnapshotById(snapshotId string) (SSnapshot, error) { - var snapshot SSnapshot - err := DoGet(self.ecsClient.Snapshots.Get, snapshotId, nil, &snapshot) - snapshot.region = self - return snapshot, err -} - -// 不能删除以autobk_snapshot_为前缀的快照。 -// 当快照状态为available、error状态时,才可以删除。 -func (self *SRegion) DeleteSnapshot(snapshotId string) error { - return DoDelete(self.ecsClient.Snapshots.Delete, snapshotId, nil, nil) -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html -// 目前已设置force字段。云硬盘处于挂载状态时,能强制创建快照。 -func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { - params := jsonutils.NewDict() - snapshotObj := jsonutils.NewDict() - snapshotObj.Add(jsonutils.NewString(name), "name") - snapshotObj.Add(jsonutils.NewString(desc), "description") - snapshotObj.Add(jsonutils.NewString(diskId), "volume_id") - snapshotObj.Add(jsonutils.JSONTrue, "force") - params.Add(snapshotObj, "snapshot") - - snapshot := SSnapshot{} - err := DoCreate(self.ecsClient.Snapshots.Create, params, &snapshot) - return snapshot.ID, err -} - -func (self *SSnapshot) GetProjectId() string { - return "" -} diff --git a/pkg/multicloud/hcso/storage.go b/pkg/multicloud/hcso/storage.go deleted file mode 100644 index 7db6037b46..0000000000 --- a/pkg/multicloud/hcso/storage.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - zone *SZone - multicloud.SStorageBase - multicloud.HuaweiTags - storageType string // volume_type 目前支持“SSD”,“SAS”和“SATA”三种 -} - -func (self *SStorage) GetId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetName() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetGlobalId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) Refresh() error { - return nil -} - -func (self *SStorage) IsEmulated() bool { - return true -} - -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, err := self.zone.region.GetDisks(self.zone.GetId()) - if err != nil { - return nil, err - } - - // 按storage type 过滤出disk - filtedDisks := make([]SDisk, 0) - for i := range disks { - disk := disks[i] - if disk.VolumeType == self.storageType { - filtedDisks = append(filtedDisks, disk) - } - } - - idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) - for i := 0; i < len(filtedDisks); i += 1 { - filtedDisks[i].storage = self - idisks[i] = &filtedDisks[i] - } - return idisks, nil -} - -func (self *SStorage) GetStorageType() string { - return self.storageType -} - -func (self *SStorage) GetMediumType() string { - if self.storageType == api.STORAGE_HUAWEI_SSD { - return api.DISK_TYPE_SSD - } else { - return api.DISK_TYPE_ROTATE - } -} - -func (self *SStorage) GetCapacityMB() int64 { - return 0 // unlimited -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - conf := jsonutils.NewDict() - return conf -} - -func (self *SStorage) GetEnabled() bool { - return true -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - diskId, err := self.zone.region.CreateDisk(self.zone.GetId(), self.storageType, conf.Name, conf.SizeGb, "", conf.Desc, conf.ProjectId) - 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 - - err = cloudprovider.WaitStatus(disk, api.DISK_READY, 5*time.Second, 120*time.Second) - if err != nil { - return nil, err - } - - return disk, nil -} - -func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - if len(idStr) == 0 { - log.Debugf("GetIDiskById disk id should not be empty") - return nil, cloudprovider.ErrNotFound - } - - if disk, err := self.zone.region.GetDisk(idStr); err != nil { - return nil, err - } else { - disk.storage = self - return disk, nil - } -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} diff --git a/pkg/multicloud/hcso/storagecache.go b/pkg/multicloud/hcso/storagecache.go deleted file mode 100644 index 4ca54add34..0000000000 --- a/pkg/multicloud/hcso/storagecache.go +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "context" - "fmt" - "math" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "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" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - iimages []cloudprovider.ICloudImage -} - -func GetBucketName(regionId string, imageId string) string { - return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), imageId) -} - -func (self *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) -} - -func (self *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) -} - -func (self *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, 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) fetchImages() error { - imagesGold, err := self.region.GetImages("", ImageOwnerPublic, "", EnvFusionCompute) - if err != nil { - return err - } - - imagesSelf, err := self.region.GetImages("", ImageOwnerSelf, "", EnvFusionCompute) - if err != nil { - return err - } - - self.iimages = make([]cloudprovider.ICloudImage, len(imagesGold)+len(imagesSelf)) - for i := range imagesGold { - imagesGold[i].storageCache = self - self.iimages[i] = &imagesGold[i] - } - - l := len(imagesGold) - for i := range imagesSelf { - imagesSelf[i].storageCache = self - self.iimages[i+l] = &imagesSelf[i] - } - return nil -} - -func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - if self.iimages == nil { - err := self.fetchImages() - if err != nil { - return nil, err - } - } - return self.iimages, nil -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - image, err := self.region.GetImage(extId) - if err != nil { - return nil, errors.Wrap(err, "self.region.GetImage") - } - image.storageCache = self - return image, nil -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -// 目前支持使用vhd、zvhd、vmdk、qcow2、raw、zvhd2、vhdx、qcow、vdi或qed格式镜像文件创建私有镜像。 -// 快速通道功能可快速完成镜像制作,但镜像文件需转换为raw或zvhd2格式并完成镜像优化。 -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0083905788.html -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 - 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) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return self.uploadImage(ctx, userCred, image, callback) -} - -func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - bucketName := GetBucketName(self.region.GetId(), image.ImageId) - - exist, _ := self.region.IBucketExist(bucketName) - if !exist { - err := self.region.CreateIBucket(bucketName, "", "") - if err != nil { - return "", errors.Wrap(err, "CreateIBucket") - } - } - defer self.region.DeleteIBucket(bucketName) - - // upload to huawei cloud - s := auth.GetAdminSession(ctx, options.Options.Region) - meta, reader, sizeByte, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) - if err != nil { - return "", errors.Wrap(err, "Images.Download") - } - log.Debugf("Images meta data %s", meta) - - minDiskMB, _ := meta.Int("min_disk") - minDiskGB := int64(math.Ceil(float64(minDiskMB) / 1024)) - // 在使用OBS桶的外部镜像文件制作镜像时生效且为必选字段。取值为40~1024GB。 - if minDiskGB < 40 { - minDiskGB = 40 - } else if minDiskGB > 1024 { - minDiskGB = 1024 - } - - bucket, err := self.region.GetIBucketByName(bucketName) - if err != nil { - return "", errors.Wrapf(err, "GetIBucketByName %s", bucketName) - } - - body := multicloud.NewProgress(sizeByte, 80, reader, callback) - err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeByte, "", "", nil, false) - if err != nil { - return "", errors.Wrap(err, "cloudprovider.UploadObject") - } - - defer bucket.DeleteObject(context.Background(), image.ImageId) - - // check image name, avoid name conflict - imageBaseName := image.ImageId - if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { - imageBaseName = fmt.Sprintf("img%s", image.ImageId) - } - imageName := imageBaseName - nameIdx := 1 - - for { - _, err = self.region.GetImageByName(imageName) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - break - } else { - return "", err - } - } - - imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) - nameIdx += 1 - log.Debugf("uploadImage Match remote name %s", imageName) - } - - jobId, err := self.region.ImportImageJob(imageName, image.OsDistribution, image.OsVersion, image.OsArch, bucketName, image.ImageId, int64(minDiskGB)) - - if err != nil { - log.Errorf("ImportImage error %s %s %s %s", jobId, image.ImageId, bucketName, err) - return "", err - } - - // timeout: 1hour = 3600 seconds - serviceType := self.region.ecsClient.Images.ServiceType() - err = self.region.waitTaskStatus(serviceType, jobId, TASK_SUCCESS, 15*time.Second, 3600*time.Second) - if err != nil { - log.Errorf("waitTaskStatus %s", err) - return "", err - } - - if callback != nil { - callback(100) - } - - // https://support.huaweicloud.com/api-ims/zh-cn_topic_0022473688.html - return self.region.GetTaskEntityID(serviceType, jobId, "image_id") -} - -func (self *SRegion) getStoragecache() *SStoragecache { - if self.storageCache == nil { - self.storageCache = &SStoragecache{region: self} - } - return self.storageCache -} - -type SJob struct { - Status string `json:"status"` - Entities map[string]string `json:"entities"` - JobID string `json:"job_id"` - JobType string `json:"job_type"` - BeginTime string `json:"begin_time"` - EndTime string `json:"end_time"` - ErrorCode string `json:"error_code"` - FailReason string `json:"fail_reason"` -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html -func (self *SRegion) createIImage(snapshotId, imageName, imageDesc string) (string, error) { - snapshot, err := self.GetSnapshotById(snapshotId) - if err != nil { - return "", err - } - - disk, err := self.GetDisk(snapshot.VolumeID) - if err != nil { - return "", err - } - - if disk.GetDiskType() != api.DISK_TYPE_SYS { - return "", fmt.Errorf("disk type err, expected disk type %s", api.DISK_TYPE_SYS) - } - - if len(disk.Attachments) == 0 { - return "", fmt.Errorf("disk is not attached.") - } - - imageObj := jsonutils.NewDict() - imageObj.Add(jsonutils.NewString(disk.Attachments[0].ServerID), "instance_id") - imageObj.Add(jsonutils.NewString(imageName), "name") - imageObj.Add(jsonutils.NewString(imageDesc), "description") - - ret, err := self.ecsClient.Images.PerformAction2("action", "", imageObj, "") - if err != nil { - return "", err - } - - job := SJob{} - jobId, err := ret.GetString("job_id") - querys := map[string]string{"service_type": self.ecsClient.Images.ServiceType()} - err = DoGet(self.ecsClient.Jobs.Get, jobId, querys, &job) - if err != nil { - return "", err - } - - if job.Status == "SUCCESS" { - imageId, exists := job.Entities["image_id"] - if exists { - return imageId, nil - } else { - return "", fmt.Errorf("image id not found in create image job %s", job.JobID) - } - } else { - return "", fmt.Errorf("create image failed, %s", job.FailReason) - } - -} - -func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - return []cloudprovider.ICloudStoragecache{storageCache}, nil -} - -func (self *SRegion) GetIStoragecacheById(idstr string) (cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - if storageCache.GetGlobalId() == idstr { - return storageCache, nil - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/hcso/traces.go b/pkg/multicloud/hcso/traces.go deleted file mode 100644 index 73a0f7e6cd..0000000000 --- a/pkg/multicloud/hcso/traces.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "strconv" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SUser struct { - Domain map[string]string - Name string - Id string -} - -type SEvent struct { - TraceId string - Code string - TraceName string - ResourceType string - ApiVersion string - SourceIp string - TraceType string - ServiceType string - EventType string - ProjectId string - Request string - Response string - TrackerName string - TraceStatus string - Time int64 - ResourceId string - ResourceName string - User SUser - RecordTime int64 -} - -func (event *SEvent) GetName() string { - if len(event.ResourceName) > 0 { - return event.ResourceName - } - if len(event.ResourceId) > 0 { - return event.ResourceId - } - return event.TraceName -} - -func (event *SEvent) GetService() string { - return event.ServiceType -} - -func (event *SEvent) GetAction() string { - return event.TraceName -} - -func (event *SEvent) GetResourceType() string { - return event.ResourceType -} - -func (event *SEvent) GetRequestId() string { - return event.TraceId -} - -func (event *SEvent) GetRequest() jsonutils.JSONObject { - return jsonutils.Marshal(event) -} - -func (event *SEvent) GetAccount() string { - return event.User.Name -} - -func (event *SEvent) IsSuccess() bool { - code, _ := strconv.Atoi(event.Code) - return code < 400 -} - -func (event *SEvent) GetCreatedAt() time.Time { - return time.Unix(event.Time/1000, event.Time%1000) -} - -func (self *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { - if !self.client.isMainProject { - return nil, cloudprovider.ErrNotSupported - } - events, err := self.GetEvents(start, end) - if err != nil { - return nil, err - } - iEvents := []cloudprovider.ICloudEvent{} - for i := range events { - iEvents = append(iEvents, &events[i]) - } - return iEvents, nil -} - -func (self *SRegion) GetEvents(start time.Time, end time.Time) ([]SEvent, error) { - events := []SEvent{} - params := map[string]string{} - if start.IsZero() { - start = time.Now().AddDate(0, 0, -7) - } - if end.IsZero() { - end = time.Now() - } - params["from"] = fmt.Sprintf("%d000", start.Unix()) - params["to"] = fmt.Sprintf("%d000", end.Unix()) - - err := doListAllWithMarker(self.ecsClient.Traces.List, params, &events) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithMarker") - } - return events, nil -} diff --git a/pkg/multicloud/hcso/utils.go b/pkg/multicloud/hcso/utils.go deleted file mode 100644 index 79c04a4054..0000000000 --- a/pkg/multicloud/hcso/utils.go +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "reflect" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/responses" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -// 常用的方法 -type listFunc func(querys map[string]string) (*responses.ListResult, error) -type getFunc func(id string, querys map[string]string) (jsonutils.JSONObject, error) -type createFunc func(params jsonutils.JSONObject) (jsonutils.JSONObject, error) -type updateFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) -type updateFunc2 func(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) -type deleteFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) -type deleteFunc2 func(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) -type listInCtxFunc func(ctx manager.IManagerContext, querys map[string]string) (*responses.ListResult, error) -type listInCtxWithSpecFunc func(ctx manager.IManagerContext, spec string, querys map[string]string, responseKey string) (*responses.ListResult, error) - -func unmarshalResult(resp jsonutils.JSONObject, respErr error, result interface{}, method string) error { - if respErr != nil { - switch e := respErr.(type) { - case *httputils.JSONClientError: - if (e.Code == 404 || utils.IsInStringArray(e.Class, NOT_FOUND_CODES)) && method != "POST" { - return cloudprovider.ErrNotFound - } - return e - default: - return e - } - } - - if result == nil { - return nil - } - - err := resp.Unmarshal(result) - if err != nil { - log.Errorf("unmarshal json error %s", err) - } - - return err -} - -var pageLimit = 100 - -// offset 表示的是页码 -func doListAllWithPagerOffset(doList listFunc, queries map[string]string, result interface{}) error { - startIndex := 0 - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - queries["offset"] = fmt.Sprintf("%d", startIndex) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - - startIndex++ - queries["offset"] = fmt.Sprintf("%d", startIndex) - } - return nil -} - -func doListAllWithNextLink(doList listFunc, querys map[string]string, result interface{}) error { - values := []jsonutils.JSONObject{} - for { - ret, err := doList(querys) - if err != nil { - return errors.Wrap(err, "doList") - } - values = append(values, ret.Data...) - if len(ret.NextLink) == 0 || ret.NextLink == "null" { - break - } - } - if result != nil { - return jsonutils.Update(result, values) - } - return nil -} - -func doListAllWithOffset(doList listFunc, queries map[string]string, result interface{}) error { - startIndex := 0 - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - queries["offset"] = fmt.Sprintf("%d", startIndex) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - queries["offset"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) - } - return nil -} - -func doListAllWithPage(doList listFunc, queries map[string]string, result interface{}) error { - startIndex := 1 - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - queries["page"] = fmt.Sprintf("%d", startIndex) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - queries["page"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) - } - return nil -} - -func doListAllWithMarker(doList listFunc, queries map[string]string, result interface{}) error { - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - lastValue := resultValue.Index(resultValue.Len() - 1) - markerValue := lastValue.FieldByNameFunc(func(key string) bool { - if strings.ToLower(key) == "id" { - return true - } - return false - }) - queries["marker"] = markerValue.String() - } - return nil -} - -func doListAll(doList listFunc, queries map[string]string, result interface{}) error { - total, _, err := doListPart(doList, queries, result) - if err != nil { - return err - } - resultValue := reflect.Indirect(reflect.ValueOf(result)) - if total > 0 && resultValue.Len() < total { - log.Warningf("INCOMPLETE QUERY, total %d queried %d", total, resultValue.Len()) - } - return nil -} - -func doListPart(doList listFunc, queries map[string]string, result interface{}) (int, int, error) { - ret, err := doList(queries) - if err != nil { - return 0, 0, err - } - resultValue := reflect.Indirect(reflect.ValueOf(result)) - elemType := resultValue.Type().Elem() - for i := range ret.Data { - elemPtr := reflect.New(elemType) - err = ret.Data[i].Unmarshal(elemPtr.Interface()) - if err != nil { - return 0, 0, err - } - resultValue.Set(reflect.Append(resultValue, elemPtr.Elem())) - } - return ret.Total, len(ret.Data), nil -} - -func DoGet(doGet getFunc, id string, queries map[string]string, result interface{}) error { - if len(id) == 0 { - resultType := reflect.Indirect(reflect.ValueOf(result)).Type() - return errors.Wrap(cloudprovider.ErrNotFound, fmt.Sprintf(" Get %s id should not be empty", resultType.Name())) - } - - ret, err := doGet(id, queries) - return unmarshalResult(ret, err, result, "GET") -} - -func DoListInContext(listFunc listInCtxFunc, ctx manager.IManagerContext, querys map[string]string, result interface{}) error { - ret, err := listFunc(ctx, querys) - if err != nil { - return err - } - - obj := responses.ListResult2JSON(ret) - err = obj.Unmarshal(result, "data") - if err != nil { - log.Errorf("unmarshal json error %s", err) - return err - } - - return nil -} - -func DoCreate(createFunc createFunc, params jsonutils.JSONObject, result interface{}) error { - ret, err := createFunc(params) - return unmarshalResult(ret, err, result, "POST") -} - -func DoUpdate(updateFunc updateFunc, id string, params jsonutils.JSONObject, result interface{}) error { - ret, err := updateFunc(id, params) - return unmarshalResult(ret, err, result, "PUT") -} - -func DoUpdateWithSpec(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject) error { - _, err := updateFunc(nil, id, spec, params, "") - return err -} - -func DoUpdateWithSpec2(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject, result interface{}) error { - ret, err := updateFunc(nil, id, spec, params, "") - return unmarshalResult(ret, err, result, "PUT") -} - -func DoDelete(deleteFunc deleteFunc, id string, params jsonutils.JSONObject, result interface{}) error { - if len(id) == 0 { - return fmt.Errorf(" id should not be empty") - } - - ret, err := deleteFunc(id, params) - return unmarshalResult(ret, err, result, "DELETE") -} - -func DoDeleteWithSpec(deleteFunc deleteFunc2, ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject) error { - if len(id) == 0 { - return fmt.Errorf(" id should not be empty") - } - - _, err := deleteFunc(ctx, id, spec, queries, params, "") - return err -} - -func ErrMessage(err error) string { - switch v := err.(type) { - case *httputils.JSONClientError: - return fmt.Sprintf("%d(%s):%s", v.Code, v.Class, v.Details) - default: - return err.Error() - } -} diff --git a/pkg/multicloud/hcso/vpc.go b/pkg/multicloud/hcso/vpc.go deleted file mode 100644 index a1619377f0..0000000000 --- a/pkg/multicloud/hcso/vpc.go +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html -type SVpc struct { - multicloud.SVpc - multicloud.HuaweiTags - - region *SRegion - - iwires []cloudprovider.ICloudWire - secgroups []cloudprovider.ICloudSecurityGroup - routeTables []cloudprovider.ICloudRouteTable - - ID string `json:"id"` - Name string `json:"name"` - CIDR string `json:"cidr"` - Status string `json:"status"` - EnterpriseProjectID string `json:"enterprise_project_id"` -} - -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) getWireByRegionId(regionId string) *SWire { - if len(regionId) == 0 { - return nil - } - - for i := 0; i < len(self.iwires); i++ { - wire := self.iwires[i].(*SWire) - - if wire.region.GetId() == regionId { - return wire - } - } - - return nil -} - -func (self *SVpc) fetchNetworks() error { - networks, err := self.region.GetNetwroks(self.ID) - if err != nil { - return err - } - - // ??????? - if len(networks) == 0 { - self.iwires = append(self.iwires, &SWire{region: self.region, vpc: self}) - return nil - } - - for i := 0; i < len(networks); i += 1 { - wire := self.getWireByRegionId(self.region.GetId()) - networks[i].wire = wire - wire.addNetwork(&networks[i]) - } - return nil -} - -// 华为云安全组可以被同region的VPC使用 -func (self *SVpc) fetchSecurityGroups() error { - secgroups, err := self.region.GetSecurityGroups("", "") - if err != nil { - return err - } - - self.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) - for i := 0; i < len(secgroups); i++ { - self.secgroups[i] = &secgroups[i] - } - return nil -} - -func (self *SVpc) GetId() string { - return self.ID -} - -func (self *SVpc) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.ID -} - -func (self *SVpc) GetGlobalId() string { - return self.ID -} - -func (self *SVpc) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} - -func (self *SVpc) Refresh() error { - new, err := self.region.getVpc(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SVpc) IsEmulated() bool { - return false -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetIsDefault() bool { - // 华为云没有default vpc. - return false -} - -func (self *SVpc) GetCidrBlock() string { - return self.CIDR -} - -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) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - if self.routeTables == nil { - routeTables, err := self.getRouteTables() - if err != nil { - return nil, errors.Wrap(err, "get route table error") - } - defaultRouteTable := NewSRouteTable(self, string(cloudprovider.RouteTableTypeSystem)) - for i := range routeTables { - defaultRouteTable.Routes = append(defaultRouteTable.Routes, routeTables[i].Routes...) - } - self.routeTables = []cloudprovider.ICloudRouteTable{&defaultRouteTable} - } - return self.routeTables, nil -} - -// 华为云 路由表资源方法 api 暂未支持,只能直接对vpc对象增加,删除 路由 -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - routeTables, err := self.getRouteTables() - if err != nil { - return nil, errors.Wrap(err, "get route table error") - } - defaultRouteTable := NewSRouteTable(self, string(cloudprovider.RouteTableTypeSystem)) - for i := range routeTables { - defaultRouteTable.Routes = append(defaultRouteTable.Routes, routeTables[i].Routes...) - } - return &defaultRouteTable, nil -} - -func (self *SVpc) Delete() error { - // todo: 确定删除VPC的逻辑 - return self.region.DeleteVpc(self.GetId()) -} - -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) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { - nats, err := self.region.GetNatGateways(self.GetId(), "") - if err != nil { - return nil, err - } - ret := make([]cloudprovider.ICloudNatGateway, len(nats)) - for i := 0; i < len(nats); i++ { - ret[i] = &nats[i] - } - return ret, nil -} - -func (self *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPCs, err := self.getVpcPeeringConnections() - if err != nil { - return nil, errors.Wrap(err, "self.getVpcPeeringConnections()") - } - ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} - for i := range svpcPCs { - ivpcPCs = append(ivpcPCs, &svpcPCs[i]) - } - return ivpcPCs, nil -} - -func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPCs, err := self.getAccepterVpcPeeringConnections() - if err != nil { - return nil, errors.Wrap(err, "self.getAccepterVpcPeeringConnections()") - } - ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} - for i := range svpcPCs { - ivpcPCs = append(ivpcPCs, &svpcPCs[i]) - } - return ivpcPCs, nil -} - -func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPC, err := self.getVpcPeeringConnectionById(id) - if err != nil { - return nil, errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) - } - return svpcPC, nil -} - -func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPC, err := self.region.CreateVpcPeering(self.GetId(), opts) - if err != nil { - return nil, errors.Wrapf(err, "self.region.CreateVpcPeering(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) - } - svpcPC.vpc = self - return svpcPC, nil -} -func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { - vpcPC, err := self.getVpcPeeringConnectionById(id) - if err != nil { - return errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) - } - if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_ACTIVE { - return nil - } - if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN { - return errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcPC: %s", jsonutils.Marshal(vpcPC).String()) - } - err = self.region.AcceptVpcPeering(id) - if err != nil { - return errors.Wrapf(err, "self.region.AcceptVpcPeering(%s)", id) - } - return nil -} - -func (self *SVpc) GetAuthorityOwnerId() string { - return self.region.client.projectId -} - -func (self *SVpc) getVpcPeeringConnections() ([]SVpcPeering, error) { - svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) - } - vpcPCs := []SVpcPeering{} - for i := range svpcPeerings { - if svpcPeerings[i].GetVpcId() == self.GetId() { - svpcPeerings[i].vpc = self - vpcPCs = append(vpcPCs, svpcPeerings[i]) - } - } - return vpcPCs, nil -} - -func (self *SVpc) getAccepterVpcPeeringConnections() ([]SVpcPeering, error) { - svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) - } - vpcPCs := []SVpcPeering{} - for i := range svpcPeerings { - if svpcPeerings[i].GetPeerVpcId() == self.GetId() { - svpcPeerings[i].vpc = self - vpcPCs = append(vpcPCs, svpcPeerings[i]) - } - } - return vpcPCs, nil -} - -func (self *SVpc) getVpcPeeringConnectionById(id string) (*SVpcPeering, error) { - svpcPC, err := self.region.GetVpcPeering(id) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetVpcPeering(%s)", id) - } - svpcPC.vpc = self - return svpcPC, nil -} - -func (self *SRegion) getVpc(vpcId string) (*SVpc, error) { - vpc := SVpc{} - err := DoGet(self.ecsClient.Vpcs.Get, vpcId, nil, &vpc) - if err != nil && strings.Contains(err.Error(), "RouterNotFound") { - return nil, cloudprovider.ErrNotFound - } - vpc.region = self - return &vpc, err -} - -func (self *SRegion) DeleteVpc(vpcId string) error { - if vpcId != "default" { - secgroups, err := self.GetSecurityGroups(vpcId, "") - if err != nil { - return errors.Wrap(err, "GetSecurityGroups") - } - for _, secgroup := range secgroups { - err = self.DeleteSecurityGroup(secgroup.ID) - if err != nil { - return errors.Wrapf(err, "DeleteSecurityGroup(%s)", secgroup.ID) - } - } - } - return DoDelete(self.ecsClient.Vpcs.Delete, vpcId, nil, nil) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html -func (self *SRegion) GetVpcs() ([]SVpc, error) { - querys := make(map[string]string) - - vpcs := make([]SVpc, 0) - err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs) - if err != nil { - return nil, err - } - - for i := range vpcs { - vpcs[i].region = self - } - return vpcs, err -} diff --git a/pkg/multicloud/hcso/vpc_peering.go b/pkg/multicloud/hcso/vpc_peering.go deleted file mode 100644 index da1dbd9d7a..0000000000 --- a/pkg/multicloud/hcso/vpc_peering.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type RequestVpcInfo struct { - VpcID string `json:"vpc_id"` - TenantID string `json:"tenant_id"` -} -type AcceptVpcInfo struct { - VpcID string `json:"vpc_id"` - TenantID string `json:"tenant_id"` -} -type SVpcPeering struct { - multicloud.SResourceBase - multicloud.HuaweiTags - vpc *SVpc - - RequestVpcInfo RequestVpcInfo `json:"request_vpc_info"` - AcceptVpcInfo AcceptVpcInfo `json:"accept_vpc_info"` - Name string `json:"name"` - ID string `json:"id"` - Status string `json:"status"` -} - -func (self *SRegion) GetVpcPeerings(vpcId string) ([]SVpcPeering, error) { - querys := make(map[string]string) - querys["vpc_id"] = vpcId - vpcPeerings := make([]SVpcPeering, 0) - err := doListAllWithMarker(self.ecsClient.VpcPeerings.List, querys, &vpcPeerings) - if err != nil { - return nil, errors.Wrapf(err, "oListAllWithMarker(self.ecsClient.VpcPeerings.List, %s, &vpcPeerings)", jsonutils.Marshal(querys).String()) - } - return vpcPeerings, nil -} - -func (self *SRegion) GetVpcPeering(vpcPeeringId string) (*SVpcPeering, error) { - if len(vpcPeeringId) == 0 { - return nil, cloudprovider.ErrNotFound - } - vpcPeering := SVpcPeering{} - err := DoGet(self.ecsClient.VpcPeerings.Get, vpcPeeringId, nil, &vpcPeering) - if err != nil { - return nil, errors.Wrapf(err, "DoGet(self.ecsClient.VpcPeerings.Get, %s, nil, &vpcPeering)", vpcPeeringId) - } - return &vpcPeering, nil -} - -func (self *SRegion) CreateVpcPeering(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPeering, error) { - params := jsonutils.NewDict() - vpcPeeringObj := jsonutils.NewDict() - requestVpcObj := jsonutils.NewDict() - acceptVpcObj := jsonutils.NewDict() - vpcPeeringObj.Set("name", jsonutils.NewString(opts.Name)) - requestVpcObj.Set("vpc_id", jsonutils.NewString(vpcId)) - requestVpcObj.Set("tenant_id", jsonutils.NewString(self.client.projectId)) - vpcPeeringObj.Set("request_vpc_info", requestVpcObj) - acceptVpcObj.Set("vpc_id", jsonutils.NewString(opts.PeerVpcId)) - acceptVpcObj.Set("tenant_id", jsonutils.NewString(opts.PeerAccountId)) - vpcPeeringObj.Set("accept_vpc_info", acceptVpcObj) - params.Set("peering", vpcPeeringObj) - ret := SVpcPeering{} - err := DoCreate(self.ecsClient.VpcPeerings.Create, params, &ret) - if err != nil { - return nil, errors.Wrapf(err, "DoCreate(self.ecsClient.VpcPeerings.Create, %s, &ret)", jsonutils.Marshal(params).String()) - } - return &ret, nil -} - -func (self *SRegion) AcceptVpcPeering(vpcPeeringId string) error { - err := DoUpdateWithSpec(self.ecsClient.VpcPeerings.UpdateInContextWithSpec, vpcPeeringId, "accept", nil) - if err != nil { - return errors.Wrapf(err, "DoUpdateWithSpec(self.ecsClient.VpcPeerings.UpdateInContextWithSpec, %s, accept, nil)", vpcPeeringId) - } - return nil -} - -func (self *SRegion) DeleteVpcPeering(vpcPeeringId string) error { - err := DoDelete(self.ecsClient.VpcPeerings.Delete, vpcPeeringId, nil, nil) - if err != nil { - return errors.Wrapf(err, "DoDelete(self.ecsClient.VpcPeerings.Delete,%s,nil)", vpcPeeringId) - } - return nil -} - -func (self *SVpcPeering) GetId() string { - return self.ID -} - -func (self *SVpcPeering) GetName() string { - return self.Name -} - -func (self *SVpcPeering) GetGlobalId() string { - return self.GetId() -} - -func (self *SVpcPeering) GetStatus() string { - switch self.Status { - case "PENDING_ACCEPTANCE": - return api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT - case "ACTIVE": - return api.VPC_PEERING_CONNECTION_STATUS_ACTIVE - default: - return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN - } -} - -func (self *SVpcPeering) Refresh() error { - peer, err := self.vpc.region.GetVpcPeering(self.ID) - if err != nil { - return errors.Wrapf(err, "self.region.GetVpcPeering(%s)", self.ID) - } - return jsonutils.Update(self, peer) -} - -func (self *SVpcPeering) GetVpcId() string { - return self.RequestVpcInfo.VpcID -} - -func (self *SVpcPeering) GetPeerVpcId() string { - return self.AcceptVpcInfo.VpcID -} - -func (self *SVpcPeering) GetPeerAccountId() string { - return self.AcceptVpcInfo.TenantID -} - -func (self *SVpcPeering) GetEnabled() bool { - return true -} - -func (self *SVpcPeering) Delete() error { - err := self.vpc.region.DeleteVpcPeering(self.ID) - if err != nil { - return errors.Wrapf(err, "self.region.DeleteVpcPeering(%s)", self.ID) - } - return nil -} diff --git a/pkg/multicloud/hcso/wire.go b/pkg/multicloud/hcso/wire.go deleted file mode 100644 index 27c494cdf2..0000000000 --- a/pkg/multicloud/hcso/wire.go +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// 华为云的子网有点特殊。子网在整个region可用。 -type SWire struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - vpc *SVpc - - inetworks []cloudprovider.ICloudNetwork -} - -func (self *SWire) GetId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) -} - -func (self *SWire) GetName() string { - return self.GetId() -} - -func (self *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SWire) Refresh() error { - return nil -} - -func (self *SWire) IsEmulated() bool { - return true -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - return nil -} - -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 -} - -/* -华为云子网可用区,类似一个zone标签。即使指定了zone子网在整个region依然是可用。 -通过华为web控制台创建子网需要指定可用区。这里是不指定的。 -*/ -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - networkId, err := self.region.createNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc) - if err != nil { - log.Errorf("createNetwork error %s", err) - return nil, err - } - - var network *SNetwork - err = cloudprovider.WaitCreated(5*time.Second, 60*time.Second, func() bool { - self.inetworks = nil - network = self.getNetworkById(networkId) - if network == nil { - return false - } else { - return true - } - }) - - if err != nil { - log.Errorf("cannot find network after create????") - return nil, err - } - - network.wire = self - return network, 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.ID { - find = true - break - } - } - if !find { - self.inetworks = append(self.inetworks, network) - } -} - -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 getDefaultGateWay(cidr string) (string, error) { - pref, err := netutils.NewIPV4Prefix(cidr) - if err != nil { - return "", errors.Wrap(err, "getDefaultGateWay.NewIPV4Prefix") - } - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - return startIp.String(), nil -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html -// cidr 掩码长度不能大于28 -func (self *SRegion) createNetwork(vpcId string, name string, cidr string, desc string) (string, error) { - gateway, err := getDefaultGateWay(cidr) - if err != nil { - return "", err - } - - params := jsonutils.NewDict() - subnetObj := jsonutils.NewDict() - subnetObj.Add(jsonutils.NewString(name), "name") - subnetObj.Add(jsonutils.NewString(vpcId), "vpc_id") - subnetObj.Add(jsonutils.NewString(cidr), "cidr") - subnetObj.Add(jsonutils.NewString(gateway), "gateway_ip") - // hard code for hcso - // https://support.huaweicloud.com/dns_faq/dns_faq_002.html - // https://support.huaweicloud.com/api-dns/dns_api_69001.html - if self.client != nil && len(self.client.endpoints.DefaultSubnetDns) > 0 { - dns := strings.Split(self.client.endpoints.DefaultSubnetDns, ",") - if len(dns) > 0 && len(dns[0]) > 0 { - subnetObj.Add(jsonutils.NewString(dns[0]), "primary_dns") - } - - if len(dns) > 1 && len(dns[1]) > 0 { - subnetObj.Add(jsonutils.NewString(dns[1]), "secondary_dns") - } - } - params.Add(subnetObj, "subnet") - - subnet := SNetwork{} - err = DoCreate(self.ecsClient.Subnets.Create, params, &subnet) - return subnet.ID, err -} diff --git a/pkg/multicloud/hcso/zone.go b/pkg/multicloud/hcso/zone.go deleted file mode 100644 index 3a973f5c33..0000000000 --- a/pkg/multicloud/hcso/zone.go +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 hcso - -import ( - "fmt" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var StorageTypes = []string{ - api.STORAGE_HUAWEI_SAS, - api.STORAGE_HUAWEI_SATA, - api.STORAGE_HUAWEI_SSD, -} - -type ZoneState struct { - Available bool `json:"available"` -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817728.html -type SZone struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - ihosts []cloudprovider.ICloudHost - - iwires []cloudprovider.ICloudWire - istorages []cloudprovider.ICloudStorage - - ZoneState ZoneState `json:"zoneState"` - ZoneName string `json:"zoneName"` - - /* 支持的磁盘种类集合 */ - 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) getStorageType() { - if len(self.storageTypes) == 0 { - if sts, err := self.region.GetZoneSupportedDiskTypes(self.GetId()); err == nil { - self.storageTypes = sts - } else { - log.Errorf("GetZoneSupportedDiskTypes %s %s", self.GetId(), err) - 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 -} - -// 华为私有云没有直接列出host的接口,所有账号下的host都是通过VM反向解析出来的 -// 当账号下没有虚拟机时,如果没有host,会导致调度找不到可用的HOST。 -// 因此,为了避免上述情况始终会在每个zone下返回一台虚拟的host -func (self *SZone) getEmulatedHost() SHost { - return SHost{ - zone: self, - vms: nil, - IsFake: true, - projectId: self.region.client.projectId, - Id: fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.GetId()), - Name: fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.GetId()), - } -} - -func (self *SZone) getHosts() ([]cloudprovider.ICloudHost, error) { - if self.ihosts != nil { - return self.ihosts, nil - } - - vms, err := self.region.GetInstances() - if err != nil { - return nil, errors.Wrap(err, "GetInstances") - } - - hosts := map[string]string{} - hostVms := map[string][]SInstance{} - for i := range vms { - vm := vms[i] - if vm.OSEXTAZAvailabilityZone == self.GetId() { - hosts[vm.HostID] = vm.OSEXTSRVATTRHost - if _, ok := hostVms[vm.HostID]; ok { - hostVms[vm.HostID] = append(hostVms[vm.HostID], vm) - } else { - hostVms[vm.HostID] = []SInstance{vm} - } - } - } - - fakeHost := self.getEmulatedHost() - ihosts := []cloudprovider.ICloudHost{&fakeHost} - for k, _ := range hosts { - h := SHost{ - zone: self, - projectId: self.region.client.projectId, - Id: k, - Name: hosts[k], - } - for i := range hostVms[k] { - hostVms[k][i].host = &h - } - - h.vms = hostVms[k] - ihosts = append(ihosts, &h) - } - - return ihosts, nil -} - -func (self *SZone) GetId() string { - return self.ZoneName -} - -func (self *SZone) GetName() string { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.ZoneName) -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.ZoneName) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SZone) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneName) -} - -func (self *SZone) GetStatus() string { - return "enable" -} - -func (self *SZone) Refresh() error { - return nil -} - -func (self *SZone) IsEmulated() bool { - return false -} - -func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - return self.getHosts() -} - -func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - ihosts, err := self.getHosts() - if err != nil { - return nil, errors.Wrap(err, "getHosts") - } - - for i := range ihosts { - if ihosts[i].GetGlobalId() == id { - return ihosts[i], nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - if self.istorages == nil { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "fetchStorages") - } - } - return self.istorages, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - if self.istorages == nil { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "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) GetIWires() ([]cloudprovider.ICloudWire, error) { - return self.iwires, nil -} - -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.GetId() == id { - return zone, nil - } - } - return nil, fmt.Errorf("no such zone %s", id) -} - -func (self *SZone) getNetworkById(networkId string) *SNetwork { - for i := 0; i < len(self.iwires); i += 1 { - wire := self.iwires[i].(*SWire) - net := wire.getNetworkById(networkId) - if net != nil { - return net - } - } - return nil -} diff --git a/pkg/multicloud/huawei/bucket.go b/pkg/multicloud/huawei/bucket.go deleted file mode 100644 index 7815359b7d..0000000000 --- a/pkg/multicloud/huawei/bucket.go +++ /dev/null @@ -1,766 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "fmt" - "io" - "net/http" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - "yunion.io/x/s3cli" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/huawei/obs" -) - -type SBucket struct { - multicloud.SBaseBucket - multicloud.HuaweiTags - - region *SRegion - - Name string - Location string - CreationDate time.Time -} - -func (b *SBucket) GetProjectId() string { - resp, err := b.region.HeadBucket(b.Name) - if err != nil { - return "" - } - epid, _ := resp.ResponseHeaders["epid"] - if len(epid) > 0 { - return epid[0] - } - return "" -} - -func (b *SBucket) GetGlobalId() string { - return b.Name -} - -func (b *SBucket) GetName() string { - return b.Name -} - -func (b *SBucket) GetLocation() string { - return b.Location -} - -func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { - return b.region -} - -func (b *SBucket) GetCreatedAt() time.Time { - return b.CreationDate -} - -func (b *SBucket) GetStorageClass() string { - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("b.region.getOBSClient error %s", err) - return "" - } - output, err := obscli.GetBucketStoragePolicy(b.Name) - if err != nil { - log.Errorf("obscli.GetBucketStoragePolicy error %s", err) - return "" - } - return output.StorageClass -} - -func obsAcl2CannedAcl(acls []obs.Grant) cloudprovider.TBucketACLType { - switch { - case len(acls) == 1: - if acls[0].Grantee.URI == "" && acls[0].Permission == s3cli.PERMISSION_FULL_CONTROL { - return cloudprovider.ACLPrivate - } - case len(acls) == 2: - for _, g := range acls { - if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_AUTH_USERS && g.Permission == s3cli.PERMISSION_READ { - return cloudprovider.ACLAuthRead - } - if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_READ { - return cloudprovider.ACLPublicRead - } - } - case len(acls) == 3: - for _, g := range acls { - if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_WRITE { - return cloudprovider.ACLPublicReadWrite - } - } - } - return cloudprovider.ACLUnknown -} - -func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("b.region.getOBSClient error %s", err) - return acl - } - output, err := obscli.GetBucketAcl(b.Name) - if err != nil { - log.Errorf("obscli.GetBucketAcl error %s", err) - return acl - } - acl = obsAcl2CannedAcl(output.Grants) - return acl -} - -func (b *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "b.region.getOBSClient") - } - input := &obs.SetBucketAclInput{} - input.Bucket = b.Name - input.ACL = obs.AclType(string(acl)) - _, err = obscli.SetBucketAcl(input) - if err != nil { - return errors.Wrap(err, "obscli.SetBucketAcl") - } - return nil -} - -func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { - return []cloudprovider.SBucketAccessUrl{ - { - Url: fmt.Sprintf("https://%s.%s", b.Name, b.region.getOBSEndpoint()), - Description: "bucket url", - Primary: true, - }, - { - Url: fmt.Sprintf("https://%s/%s", b.region.getOBSEndpoint(), b.Name), - Description: "obs url", - }, - } -} - -func (b *SBucket) GetStats() cloudprovider.SBucketStats { - stats := cloudprovider.SBucketStats{} - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("b.region.getOBSClient error %s", err) - stats.SizeBytes = -1 - stats.ObjectCount = -1 - return stats - } - output, err := obscli.GetBucketStorageInfo(b.Name) - if err != nil { - log.Errorf("obscli.GetBucketStorageInfo error %s", err) - stats.SizeBytes = -1 - stats.ObjectCount = -1 - return stats - } - stats.SizeBytes = output.Size - stats.ObjectCount = output.ObjectNumber - return stats -} - -func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { - result := cloudprovider.SListObjectResult{} - obscli, err := b.region.getOBSClient() - if err != nil { - return result, errors.Wrap(err, "GetOBSClient") - } - input := &obs.ListObjectsInput{} - input.Bucket = b.Name - if len(prefix) > 0 { - input.Prefix = prefix - } - if len(marker) > 0 { - input.Marker = marker - } - if len(delimiter) > 0 { - input.Delimiter = delimiter - } - if maxCount > 0 { - input.MaxKeys = maxCount - } - oResult, err := obscli.ListObjects(input) - if err != nil { - return result, errors.Wrap(err, "ListObjects") - } - result.Objects = make([]cloudprovider.ICloudObject, 0) - for _, object := range oResult.Contents { - obj := &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - StorageClass: string(object.StorageClass), - Key: object.Key, - SizeBytes: object.Size, - ETag: object.ETag, - LastModified: object.LastModified, - }, - } - result.Objects = append(result.Objects, obj) - } - if oResult.CommonPrefixes != nil { - result.CommonPrefixes = make([]cloudprovider.ICloudObject, 0) - for _, commonPrefix := range oResult.CommonPrefixes { - obj := &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - Key: commonPrefix, - }, - } - result.CommonPrefixes = append(result.CommonPrefixes, obj) - } - } - result.IsTruncated = oResult.IsTruncated - result.NextMarker = oResult.NextMarker - return result, nil -} - -func (b *SBucket) PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.PutObjectInput{} - input.Bucket = b.Name - input.Key = key - input.Body = reader - - if sizeBytes > 0 { - input.ContentLength = sizeBytes - } - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return err - } - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.ACL = obs.AclType(string(cannedAcl)) - if meta != nil { - val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) - if len(val) > 0 { - input.ContentType = val - } - val = meta.Get(cloudprovider.META_HEADER_CONTENT_MD5) - if len(val) > 0 { - input.ContentMD5 = val - } - extraMeta := make(map[string]string) - for k, v := range meta { - if utils.IsInStringArray(k, []string{ - cloudprovider.META_HEADER_CONTENT_TYPE, - cloudprovider.META_HEADER_CONTENT_MD5, - }) { - continue - } - if len(v[0]) > 0 { - extraMeta[k] = v[0] - } - } - input.Metadata = extraMeta - } - _, err = obscli.PutObject(input) - if err != nil { - return errors.Wrap(err, "PutObject") - } - return nil -} - -func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - - input := &obs.InitiateMultipartUploadInput{} - input.Bucket = b.Name - input.Key = key - if meta != nil { - val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) - if len(val) > 0 { - input.ContentType = val - } - extraMeta := make(map[string]string) - for k, v := range meta { - if utils.IsInStringArray(k, []string{ - cloudprovider.META_HEADER_CONTENT_TYPE, - }) { - continue - } - if len(v[0]) > 0 { - extraMeta[k] = v[0] - } - } - input.Metadata = extraMeta - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.ACL = obs.AclType(string(cannedAcl)) - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return "", errors.Wrap(err, "str2StorageClass") - } - } - output, err := obscli.InitiateMultipartUpload(input) - if err != nil { - return "", errors.Wrap(err, "InitiateMultipartUpload") - } - - return output.UploadId, nil -} - -func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, part io.Reader, partSize int64, offset, totalSize int64) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - - input := &obs.UploadPartInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - input.PartNumber = partIndex - input.PartSize = partSize - input.Body = part - output, err := obscli.UploadPart(input) - if err != nil { - return "", errors.Wrap(err, "UploadPart") - } - - return output.ETag, nil -} - -func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.CompleteMultipartUploadInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - parts := make([]obs.Part, len(partEtags)) - for i := range partEtags { - parts[i] = obs.Part{ - PartNumber: i + 1, - ETag: partEtags[i], - } - } - input.Parts = parts - _, err = obscli.CompleteMultipartUpload(input) - if err != nil { - return errors.Wrap(err, "CompleteMultipartUpload") - } - - return nil -} - -func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - input := &obs.AbortMultipartUploadInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - - _, err = obscli.AbortMultipartUpload(input) - if err != nil { - return errors.Wrap(err, "AbortMultipartUpload") - } - - return nil -} - -func (b *SBucket) DeleteObject(ctx context.Context, key string) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.DeleteObjectInput{} - input.Bucket = b.Name - input.Key = key - _, err = obscli.DeleteObject(input) - if err != nil { - return errors.Wrap(err, "DeleteObject") - } - return nil -} - -func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - input := obs.CreateSignedUrlInput{} - input.Bucket = b.Name - input.Key = key - input.Expires = int(expire / time.Second) - switch method { - case "GET": - input.Method = obs.HttpMethodGet - case "PUT": - input.Method = obs.HttpMethodPut - case "DELETE": - input.Method = obs.HttpMethodDelete - default: - return "", errors.Error("unsupported method") - } - output, err := obscli.CreateSignedUrl(&input) - return output.SignedUrl, nil -} - -func (b *SBucket) LimitSupport() cloudprovider.SBucketStats { - return cloudprovider.SBucketStats{ - SizeBytes: 1, - ObjectCount: -1, - } -} - -func (b *SBucket) GetLimit() cloudprovider.SBucketStats { - stats := cloudprovider.SBucketStats{} - obscli, err := b.region.getOBSClient() - if err != nil { - log.Errorf("getOBSClient error %s", err) - return stats - } - output, err := obscli.GetBucketQuota(b.Name) - if err != nil { - return stats - } - stats.SizeBytes = output.Quota - return stats -} - -func (b *SBucket) SetLimit(limit cloudprovider.SBucketStats) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "getOBSClient") - } - input := &obs.SetBucketQuotaInput{} - input.Bucket = b.Name - input.Quota = limit.SizeBytes - _, err = obscli.SetBucketQuota(input) - if err != nil { - return errors.Wrap(err, "SetBucketQuota") - } - return nil -} - -func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - input := &obs.CopyObjectInput{} - input.Bucket = b.Name - input.Key = destKey - input.CopySourceBucket = srcBucket - input.CopySourceKey = srcKey - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return err - } - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - input.ACL = obs.AclType(string(cannedAcl)) - if meta != nil { - val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) - if len(val) > 0 { - input.ContentType = val - } - extraMeta := make(map[string]string) - for k, v := range meta { - if utils.IsInStringArray(k, []string{ - cloudprovider.META_HEADER_CONTENT_TYPE, - }) { - continue - } - if len(v[0]) > 0 { - extraMeta[k] = v[0] - } - } - input.Metadata = extraMeta - input.MetadataDirective = obs.ReplaceMetadata - } else { - input.MetadataDirective = obs.CopyMetadata - } - _, err = obscli.CopyObject(input) - if err != nil { - return errors.Wrap(err, "obscli.CopyObject") - } - return nil -} - -func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - input := &obs.GetObjectInput{} - input.Bucket = b.Name - input.Key = key - if rangeOpt != nil { - input.RangeStart = rangeOpt.Start - input.RangeEnd = rangeOpt.End - } - output, err := obscli.GetObject(input) - if err != nil { - return nil, errors.Wrap(err, "obscli.GetObject") - } - return output.Body, nil -} - -func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return "", errors.Wrap(err, "GetOBSClient") - } - input := &obs.CopyPartInput{} - input.Bucket = b.Name - input.Key = key - input.UploadId = uploadId - input.PartNumber = partIndex - input.CopySourceBucket = srcBucket - input.CopySourceKey = srcKey - input.CopySourceRangeStart = srcOffset - input.CopySourceRangeEnd = srcOffset + srcLength - 1 - output, err := obscli.CopyPart(input) - if err != nil { - return "", errors.Wrap(err, "CopyPart") - } - return output.ETag, nil -} - -func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - obsWebConf := obs.SetBucketWebsiteConfigurationInput{} - obsWebConf.Bucket = b.Name - obsWebConf.BucketWebsiteConfiguration = obs.BucketWebsiteConfiguration{ - IndexDocument: obs.IndexDocument{Suffix: websitConf.Index}, - ErrorDocument: obs.ErrorDocument{Key: websitConf.ErrorDocument}, - } - _, err = obscli.SetBucketWebsiteConfiguration(&obsWebConf) - if err != nil { - return errors.Wrap(err, "obscli.SetBucketWebsiteConfiguration(&obsWebConf)") - } - return nil -} - -func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { - result := cloudprovider.SBucketWebsiteConf{} - obscli, err := b.region.getOBSClient() - if err != nil { - return result, errors.Wrap(err, "GetOBSClient") - } - out, err := obscli.GetBucketWebsiteConfiguration(b.Name) - if out == nil { - return result, nil - } - result.Index = out.IndexDocument.Suffix - result.ErrorDocument = out.ErrorDocument.Key - result.Url = fmt.Sprintf("https://%s.obs-website.%s.myhuaweicloud.com", b.Name, b.region.GetId()) - return result, nil -} - -func (b *SBucket) DeleteWebSiteConf() error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - _, err = obscli.DeleteBucketWebsiteConfiguration(b.Name) - if err != nil { - return errors.Wrapf(err, "obscli.DeleteBucketWebsiteConfiguration(%s)", b.Name) - } - return nil -} - -func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - opts := []obs.CorsRule{} - for i := range rules { - opts = append(opts, obs.CorsRule{ - AllowedOrigin: rules[i].AllowedOrigins, - AllowedMethod: rules[i].AllowedMethods, - AllowedHeader: rules[i].AllowedHeaders, - MaxAgeSeconds: rules[i].MaxAgeSeconds, - ExposeHeader: rules[i].ExposeHeaders, - }) - } - - input := obs.SetBucketCorsInput{} - input.Bucket = b.Name - input.BucketCors.CorsRules = opts - _, err = obscli.SetBucketCors(&input) - if err != nil { - return errors.Wrapf(err, "obscli.SetBucketCors(%s)", jsonutils.Marshal(input).String()) - } - return nil -} - -func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - conf, err := obscli.GetBucketCors(b.Name) - if err != nil { - if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") { - return nil, errors.Wrapf(err, "obscli.GetBucketCors(%s)", b.Name) - } - } - if conf == nil { - return nil, nil - } - result := []cloudprovider.SBucketCORSRule{} - for i := range conf.CorsRules { - result = append(result, cloudprovider.SBucketCORSRule{ - AllowedOrigins: conf.CorsRules[i].AllowedOrigin, - AllowedMethods: conf.CorsRules[i].AllowedMethod, - AllowedHeaders: conf.CorsRules[i].AllowedHeader, - MaxAgeSeconds: conf.CorsRules[i].MaxAgeSeconds, - ExposeHeaders: conf.CorsRules[i].ExposeHeader, - Id: strconv.Itoa(i), - }) - } - return result, nil -} - -func (b *SBucket) DeleteCORS() error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - _, err = obscli.DeleteBucketCors(b.Name) - if err != nil { - return errors.Wrapf(err, "obscli.DeleteBucketCors(%s)", b.Name) - } - return nil -} - -func (b *SBucket) GetTags() (map[string]string, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - tagresult, err := obscli.GetBucketTagging(b.Name) - if err != nil { - if strings.Contains(err.Error(), "404") { - return nil, nil - } - return nil, errors.Wrapf(err, "osscli.GetBucketTagging(%s)", b.Name) - } - result := map[string]string{} - for i := range tagresult.Tags { - result[tagresult.Tags[i].Key] = tagresult.Tags[i].Value - } - return result, nil -} - -func (b *SBucket) SetTags(tags map[string]string, replace bool) error { - obscli, err := b.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "GetOBSClient") - } - - _, err = obscli.DeleteBucketTagging(b.Name) - if err != nil { - return errors.Wrapf(err, "DeleteBucketTagging") - } - - if len(tags) == 0 { - return nil - } - - input := obs.SetBucketTaggingInput{BucketTagging: obs.BucketTagging{}} - input.Bucket = b.Name - for k, v := range tags { - input.BucketTagging.Tags = append(input.BucketTagging.Tags, obs.Tag{Key: k, Value: v}) - } - - _, err = obscli.SetBucketTagging(&input) - if err != nil { - return errors.Wrapf(err, "obscli.SetBucketTagging(%s)", jsonutils.Marshal(input).String()) - } - return nil -} - -func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { - obscli, err := b.region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "GetOBSClient") - } - result := []cloudprovider.SBucketMultipartUploads{} - - input := obs.ListMultipartUploadsInput{Bucket: b.Name} - keyMarker := "" - uploadIDMarker := "" - for { - if len(keyMarker) > 0 { - input.KeyMarker = keyMarker - } - if len(uploadIDMarker) > 0 { - input.UploadIdMarker = uploadIDMarker - } - - output, err := obscli.ListMultipartUploads(&input) - if err != nil { - return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") - } - for i := range output.Uploads { - temp := cloudprovider.SBucketMultipartUploads{ - ObjectName: output.Uploads[i].Key, - UploadID: output.Uploads[i].UploadId, - Initiator: output.Uploads[i].Initiator.DisplayName, - Initiated: output.Uploads[i].Initiated, - } - result = append(result, temp) - } - keyMarker = output.NextKeyMarker - uploadIDMarker = output.NextUploadIdMarker - if !output.IsTruncated { - break - } - } - - return result, nil -} diff --git a/pkg/multicloud/huawei/client/auth/credentials/doc.go b/pkg/multicloud/huawei/client/auth/credentials/doc.go deleted file mode 100644 index 24b145bef0..0000000000 --- a/pkg/multicloud/huawei/client/auth/credentials/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 credentials // import "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth/credentials" diff --git a/pkg/multicloud/huawei/client/auth/doc.go b/pkg/multicloud/huawei/client/auth/doc.go deleted file mode 100644 index 615bf86e8a..0000000000 --- a/pkg/multicloud/huawei/client/auth/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 auth // import "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth" diff --git a/pkg/multicloud/huawei/client/auth/signer.go b/pkg/multicloud/huawei/client/auth/signer.go deleted file mode 100644 index c7a76803ee..0000000000 --- a/pkg/multicloud/huawei/client/auth/signer.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 auth - -import ( - "crypto/md5" - "crypto/sha256" - "encoding/hex" - "fmt" - "io/ioutil" - "sort" - "strings" - "sync" - "time" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth/credentials" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth/signers" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/requests" -) - -type Signer interface { - GetName() string // 签名算法名称 - GetAccessKeyId() (accessKeyId string, err error) // 签名access key - GetSecretKey() (secretKey string, err error) // access secret - Sign(stringToSign, secretSuffix string) string // 生成签名结果 -} - -func NewSignerWithCredential(credential Credential) (signer Signer, err error) { - switch instance := credential.(type) { - case *credentials.AccessKeyCredential: - return signers.NewAccessKeySigner(instance), nil - default: - return nil, fmt.Errorf("unsupported credential error") - } -} - -// 对request进行签名 -func Sign(request requests.IRequest, signer Signer) (err error) { - return signRequest(request, signer) -} - -func signRequest(request requests.IRequest, signer Signer) error { - // https://support.huaweicloud.com/api-dis/dis_02_0508.html - // requestTime - reqTime := time.Now() - // 添加 必须的Headers - fillRequiredHeaders(request, reqTime) - // 计算CanonicalRequest - canonicalRequest := canonicalRequest(request) - // stringToSign - credentialScope := strings.Join([]string{ - formattedSignTime(reqTime, "Date"), - request.GetRegionId(), - request.GetProduct(), - "sdk_request", - }, "/") - stringToSign := strings.Join([]string{"SDK-HMAC-SHA256", - formattedSignTime(reqTime, "DateTime"), - credentialScope, - hashSha256([]byte(canonicalRequest)), - }, "\n") - // 计算SigningKey - secret, _ := signer.GetSecretKey() - signKey := getSigningKey(secret, formattedSignTime(reqTime, "Date"), - request.GetRegionId(), request.GetProduct()) - // 计算Signature - signature := signer.Sign(stringToSign, signKey) - accesskey, _ := signer.GetAccessKeyId() - addAuthorizationHeader(request, accesskey, credentialScope, signature) - return nil -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0132456728.html -// X-Project-Id 如果是专属云场景采用AK/SK 认证方式的接口请求或者多project场景采用AK/SK认证的接口请求则该字段必选。 -func fillRequiredHeaders(request requests.IRequest, t time.Time) { - request.AddHeaderParam("HOST", request.GetHost()) - request.AddHeaderParam("X-Sdk-Date", formattedSignTime(t, "DateTime")) - if len(request.GetProjectId()) > 0 { - request.AddHeaderParam("X-Project-Id", request.GetProjectId()) - } - return -} - -func buildRequestStringToSign(request requests.IRequest) string { - return "" -} - -func formattedSignTime(t time.Time, format string) string { - switch format { - case "Date": - return t.UTC().Format("20060102") - case "DateTime": - return t.UTC().Format("20060102T150405Z") - default: - return t.UTC().Format("20060102T150405Z") - } -} - -func contentSha256(request requests.IRequest) string { - method := strings.ToUpper(request.GetMethod()) - content := []byte{} - body := request.GetBodyReader() - content, _ = ioutil.ReadAll(body) - if method == "POST" { - if len(content) == 0 { - // other http method use query as content - content = []byte(request.BuildQueries()) - } - } - - return hashSha256(content) -} - -func hashSha256(msg []byte) string { - sh256 := sha256.New() - sh256.Write(msg) - - return hex.EncodeToString(sh256.Sum(nil)) -} - -func canonicalRequest(request requests.IRequest) string { - sha256 := contentSha256(request) - uri := request.GetURI() - if !strings.HasSuffix(uri, "/") { - uri = uri + "/" - } - - return strings.Join([]string{ - request.GetMethod(), - uri, - canonicalQueryString(request), - canonicalHeaders(request), - canonicalHeaderNames(request), - sha256, - }, "\n") -} - -func sortedHeaderNames(request requests.IRequest) []string { - headers := request.GetHeaders() - keys := make([]string, 0) - for k := range headers { - keys = append(keys, k) - } - - sort.Slice(keys, func(i, j int) bool { - return strings.ToLower(keys[i]) < strings.ToLower(keys[j]) - }) - - return keys -} - -func canonicalQueryString(request requests.IRequest) string { - if strings.ToUpper(request.GetMethod()) != "POST" { - return request.BuildQueries() - } - - return "" -} - -func canonicalHeaders(request requests.IRequest) string { - keys := sortedHeaderNames(request) - headers := request.GetHeaders() - ret := []string{} - for _, k := range keys { - ret = append(ret, strings.ToLower(k)+":"+strings.TrimSpace(headers[k])) - } - - return strings.Join(ret, "\n") + "\n" -} - -func canonicalHeaderNames(request requests.IRequest) string { - keys := sortedHeaderNames(request) - ret := strings.Join(keys, ";") - return strings.ToLower(ret) -} - -var SigningKeyCache sync.Map // map[string][]byte{} - -func getSigningKey(secretKey, date, regionId, service string) string { - joinedKey := strings.Join([]string{secretKey, date, regionId, service}, "") - cacheKey := fmt.Sprintf("%x", md5.Sum([]byte(joinedKey))) - if v, ok := SigningKeyCache.Load(cacheKey); ok { - return v.(string) - } - - ret := []byte("SDK" + secretKey) - for _, k := range []string{date, regionId, service, "sdk_request"} { - ret = signers.HmacSha256(k, ret) - } - - SigningKeyCache.Store(cacheKey, string(ret)) - return string(ret) -} - -func addAuthorizationHeader(request requests.IRequest, accessKey, credentialScope, signature string) { - auth := "SDK-HMAC-SHA256" + " " + strings.Join([]string{ - "Credential=" + accessKey + "/" + credentialScope, - "SignedHeaders=" + canonicalHeaderNames(request), - "Signature=" + signature, - }, ", ") - - request.AddHeaderParam("Authorization", auth) -} diff --git a/pkg/multicloud/huawei/client/auth/signers/doc.go b/pkg/multicloud/huawei/client/auth/signers/doc.go deleted file mode 100644 index 81e08568e6..0000000000 --- a/pkg/multicloud/huawei/client/auth/signers/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 signers // import "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth/signers" diff --git a/pkg/multicloud/huawei/client/auth/signers/signer_access_key.go b/pkg/multicloud/huawei/client/auth/signers/signer_access_key.go deleted file mode 100644 index 4f802a74bd..0000000000 --- a/pkg/multicloud/huawei/client/auth/signers/signer_access_key.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 signers - -import ( - "crypto/hmac" - "crypto/sha256" - "encoding/hex" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth/credentials" -) - -type AccessKeySigner struct { - credential *credentials.AccessKeyCredential -} - -func (signer *AccessKeySigner) GetName() string { - return "HmacSha256" -} - -func (signer *AccessKeySigner) GetAccessKeyId() (accessKeyId string, err error) { - return signer.credential.AccessKeyId, nil -} - -func (signer *AccessKeySigner) GetSecretKey() (secretKey string, err error) { - return signer.credential.AccessKeySecret, nil -} - -func (signer *AccessKeySigner) Sign(stringToSign, secretSuffix string) string { - return hex.EncodeToString(HmacSha256(stringToSign, []byte(secretSuffix))) -} - -func HmacSha256(data string, key []byte) []byte { - mac := hmac.New(sha256.New, key) - mac.Write([]byte(data)) - return mac.Sum(nil) -} - -func NewAccessKeySigner(credential *credentials.AccessKeyCredential) *AccessKeySigner { - return &AccessKeySigner{ - credential: credential, - } -} diff --git a/pkg/multicloud/huawei/client/client.go b/pkg/multicloud/huawei/client/client.go deleted file mode 100644 index e311a3b376..0000000000 --- a/pkg/multicloud/huawei/client/client.go +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 client - -import ( - "net/http" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth/credentials" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules" -) - -type Client struct { - cfg *SClientConfig - // 标记初始化状态 - init bool - - Balances *modules.SBalanceManager - Credentials *modules.SCredentialManager - Disks *modules.SDiskManager - Domains *modules.SDomainManager - Elasticcache *modules.SElasticcacheManager - DcsAvailableZone *modules.SDcsAvailableZoneManager - Flavors *modules.SFlavorManager - Images *modules.SImageManager - OpenStackImages *modules.SImageManager - Interface *modules.SInterfaceManager - Jobs *modules.SJobManager - Keypairs *modules.SKeypairManager - Orders *modules.SOrderManager - Port *modules.SPortManager - Projects *modules.SProjectManager - Regions *modules.SRegionManager - SecurityGroupRules *modules.SSecgroupRuleManager - SecurityGroups *modules.SSecurityGroupManager - NovaSecurityGroups *modules.SSecurityGroupManager - Servers *modules.SServerManager - ServersV2 *modules.SServerManager - NovaServers *modules.SServerManager - Snapshots *modules.SSnapshotManager - OsSnapshots *modules.SSnapshotManager - Subnets *modules.SSubnetManager - Users *modules.SUserManager - Vpcs *modules.SVpcManager - Zones *modules.SZoneManager - VpcRoutes *modules.SVpcRouteManager - SNatRules *modules.SNatSRuleManager - DNatRules *modules.SNatDRuleManager - NatGateways *modules.SNatGatewayManager - VpcPeerings *modules.SVpcPeeringManager - DBInstance *modules.SDBInstanceManager - DBInstanceBackup *modules.SDBInstanceBackupManager - DBInstanceFlavor *modules.SDBInstanceFlavorManager - DBInstanceJob *modules.SDBInstanceJobManager - Traces *modules.STraceManager - CloudEye *modules.SCloudEyeManager - Quotas *modules.SQuotaManager - EnterpriseProjects *modules.SEnterpriseProjectManager - Roles *modules.SRoleManager - Groups *modules.SGroupManager - SAMLProviders *modules.SAMLProviderManager - SAMLProviderMappings *modules.SAMLProviderMappingManager - SfsTurbos *modules.SfsTurboManager - RouteTables *modules.SRouteTableManager -} - -type SClientConfig struct { - signer auth.Signer - endpoint string // myhuaweicloud.com - regionId string - domainId string - projectId string - - debug bool -} - -func (self *SClientConfig) GetSigner() auth.Signer { - return self.signer -} - -func (self *SClientConfig) GetEndpoint() string { - return self.endpoint -} - -func (self *SClientConfig) GetRegionId() string { - return self.regionId -} - -func (self *SClientConfig) GetDomainId() string { - return self.domainId -} - -func (self *SClientConfig) GetProjectId() string { - return self.projectId -} - -func (self *SClientConfig) GetDebug() bool { - return self.debug -} - -func (self *Client) SetHttpClient(httpClient *http.Client) { - self.Credentials.SetHttpClient(httpClient) - self.Servers.SetHttpClient(httpClient) - self.ServersV2.SetHttpClient(httpClient) - self.NovaServers.SetHttpClient(httpClient) - self.Snapshots.SetHttpClient(httpClient) - self.OsSnapshots.SetHttpClient(httpClient) - self.Images.SetHttpClient(httpClient) - self.OpenStackImages.SetHttpClient(httpClient) - self.Projects.SetHttpClient(httpClient) - self.Regions.SetHttpClient(httpClient) - self.Zones.SetHttpClient(httpClient) - self.Vpcs.SetHttpClient(httpClient) - self.Elasticcache.SetHttpClient(httpClient) - self.DcsAvailableZone.SetHttpClient(httpClient) - self.Disks.SetHttpClient(httpClient) - self.Domains.SetHttpClient(httpClient) - self.Keypairs.SetHttpClient(httpClient) - self.Orders.SetHttpClient(httpClient) - self.SecurityGroupRules.SetHttpClient(httpClient) - self.SecurityGroups.SetHttpClient(httpClient) - self.NovaSecurityGroups.SetHttpClient(httpClient) - self.Subnets.SetHttpClient(httpClient) - self.Users.SetHttpClient(httpClient) - self.Interface.SetHttpClient(httpClient) - self.Jobs.SetHttpClient(httpClient) - self.Balances.SetHttpClient(httpClient) - self.Port.SetHttpClient(httpClient) - self.Flavors.SetHttpClient(httpClient) - self.VpcRoutes.SetHttpClient(httpClient) - self.SNatRules.SetHttpClient(httpClient) - self.DNatRules.SetHttpClient(httpClient) - self.NatGateways.SetHttpClient(httpClient) - self.DBInstance.SetHttpClient(httpClient) - self.DBInstanceBackup.SetHttpClient(httpClient) - self.DBInstanceFlavor.SetHttpClient(httpClient) - self.DBInstanceJob.SetHttpClient(httpClient) - self.Traces.SetHttpClient(httpClient) - self.CloudEye.SetHttpClient(httpClient) - self.EnterpriseProjects.SetHttpClient(httpClient) - self.Roles.SetHttpClient(httpClient) - self.Groups.SetHttpClient(httpClient) - self.SAMLProviders.SetHttpClient(httpClient) - self.SAMLProviderMappings.SetHttpClient(httpClient) - self.SfsTurbos.SetHttpClient(httpClient) - self.RouteTables.SetHttpClient(httpClient) -} - -func (self *Client) InitWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey string, debug bool) error { - // accessKey signer - credential := &credentials.AccessKeyCredential{ - AccessKeyId: accessKey, - AccessKeySecret: secretKey, - } - - // 从signer中初始化 - signer, err := auth.NewSignerWithCredential(credential) - if err != nil { - return err - } - self.cfg = &SClientConfig{ - signer: signer, - endpoint: endpoint, - regionId: regionId, - domainId: domainId, - projectId: projectId, - debug: debug, - } - - // 初始化 resource manager - self.initManagers() - return err -} - -func (self *Client) initManagers() { - if !self.init { - self.Servers = modules.NewServerManager(self.cfg) - self.ServersV2 = modules.NewServerV2Manager(self.cfg) - self.NovaServers = modules.NewNovaServerManager(self.cfg) - self.Snapshots = modules.NewSnapshotManager(self.cfg) - self.OsSnapshots = modules.NewOsSnapshotManager(self.cfg) - self.Images = modules.NewImageManager(self.cfg) - self.OpenStackImages = modules.NewOpenstackImageManager(self.cfg) - self.Projects = modules.NewProjectManager(self.cfg) - self.Regions = modules.NewRegionManager(self.cfg) - self.Zones = modules.NewZoneManager(self.cfg) - self.Vpcs = modules.NewVpcManager(self.cfg) - self.Elasticcache = modules.NewElasticcacheManager(self.cfg) - self.DcsAvailableZone = modules.NewDcsAvailableZoneManager(self.cfg) - self.Disks = modules.NewDiskManager(self.cfg) - self.Domains = modules.NewDomainManager(self.cfg) - self.Keypairs = modules.NewKeypairManager(self.cfg) - self.Orders = modules.NewOrderManager(self.cfg) - self.SecurityGroupRules = modules.NewSecgroupRuleManager(self.cfg) - self.SecurityGroups = modules.NewSecurityGroupManager(self.cfg) - self.NovaSecurityGroups = modules.NewNovaSecurityGroupManager(self.cfg) - self.Subnets = modules.NewSubnetManager(self.cfg) - self.Users = modules.NewUserManager(self.cfg) - self.Interface = modules.NewInterfaceManager(self.cfg) - self.Jobs = modules.NewJobManager(self.cfg) - self.Balances = modules.NewBalanceManager(self.cfg) - self.Credentials = modules.NewCredentialManager(self.cfg) - self.Port = modules.NewPortManager(self.cfg) - self.Flavors = modules.NewFlavorManager(self.cfg) - self.VpcRoutes = modules.NewVpcRouteManager(self.cfg) - self.SNatRules = modules.NewNatSManager(self.cfg) - self.DNatRules = modules.NewNatDManager(self.cfg) - self.NatGateways = modules.NewNatGatewayManager(self.cfg) - self.VpcPeerings = modules.NewVpcPeeringManager(self.cfg) - self.DBInstance = modules.NewDBInstanceManager(self.cfg) - self.DBInstanceBackup = modules.NewDBInstanceBackupManager(self.cfg) - self.DBInstanceFlavor = modules.NewDBInstanceFlavorManager(self.cfg) - self.DBInstanceJob = modules.NewDBInstanceJobManager(self.cfg) - self.Traces = modules.NewTraceManager(self.cfg) - self.CloudEye = modules.NewCloudEyeManager(self.cfg) - self.Quotas = modules.NewQuotaManager(self.cfg) - self.EnterpriseProjects = modules.NewEnterpriseProjectManager(self.cfg) - self.Roles = modules.NewRoleManager(self.cfg) - self.Groups = modules.NewGroupManager(self.cfg) - self.SAMLProviders = modules.NewSAMLProviderManager(self.cfg) - self.SAMLProviderMappings = modules.NewSAMLProviderMappingManager(self.cfg) - self.SfsTurbos = modules.NewSfsTurboManager(self.cfg) - self.RouteTables = modules.NewRouteTableManager(self.cfg) - } - - self.init = true -} - -func NewClientWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey string, debug bool) (*Client, error) { - c := &Client{} - err := c.InitWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey, debug) - return c, err -} - -func NewPublicCloudClientWithAccessKey(regionId, domainId, projectId, accessKey, secretKey string, debug bool) (*Client, error) { - return NewClientWithAccessKey("myhuaweicloud.com", regionId, domainId, projectId, accessKey, secretKey, debug) -} diff --git a/pkg/multicloud/huawei/client/doc.go b/pkg/multicloud/huawei/client/doc.go deleted file mode 100644 index 0629cbe84f..0000000000 --- a/pkg/multicloud/huawei/client/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 client // import "yunion.io/x/onecloud/pkg/multicloud/huawei/client" diff --git a/pkg/multicloud/huawei/client/manager/doc.go b/pkg/multicloud/huawei/client/manager/doc.go deleted file mode 100644 index 0059595a15..0000000000 --- a/pkg/multicloud/huawei/client/manager/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 manager // import "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" diff --git a/pkg/multicloud/huawei/client/manager/manager.go b/pkg/multicloud/huawei/client/manager/manager.go deleted file mode 100644 index 01f1fbddca..0000000000 --- a/pkg/multicloud/huawei/client/manager/manager.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 manager - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type IManagerContext interface { - GetPath() string -} - -type IBaseManager interface { - Version() string - KeyString() string - ServiceType() string - GetColumns() []string -} - -type IManager interface { - IBaseManager - // 获取资源列表 GET /cloudservers/? - List(queries map[string]string) (*responses.ListResult, error) - // 根据上文获取资源列表 GET /cloudservers//nics? - ListInContext(ctx IManagerContext, queries map[string]string) (*responses.ListResult, error) - ListInContextWithSpec(ctx IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error) - - // 查询单个资源 GET /cloudservers/? - Get(id string, queries map[string]string) (jsonutils.JSONObject, error) - // 根据上文获取资源查询单个资源 GET /cloudservers//nics/? - GetInContext(ctx IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error) - - // 创建单个资源 POST /cloudservers - Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文创建单个资源 POST /cloudservers//nics/ - CreateInContext(ctx IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 异步任务创建 POST /cloudservers. 返回异步任务 job_id。 todo:// 后续考虑返回一个task对象 - AsyncCreate(params jsonutils.JSONObject) (string, error) - - // 更新单个资源 PUT /cloudservers/ - Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文更新单个资源 PUT /cloudservers//nics/ - UpdateInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文和spec更新单个资源 PUT /v2.1/{project_id}/servers/{server_id}/os-reset-password - UpdateInContextWithSpec(ctx IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) - - // 删除单个资源 DELETE /cloudservers/ - Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文删除单个资源 DELETE /cloudservers//nics/ - DeleteInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 根据上文和spec删除单个资源 - DeleteInContextWithSpec(ctx IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) - // 批量执行操作 POST /cloudservers/ - // BatchPerformAction(action string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) - // 执行操作 POST /cloudservers// - PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) -} - -type IManagerConfig interface { - GetSigner() auth.Signer - GetEndpoint() string - GetRegionId() string - GetDomainId() string - GetProjectId() string - GetDebug() bool -} diff --git a/pkg/multicloud/huawei/client/modules/doc.go b/pkg/multicloud/huawei/client/modules/doc.go deleted file mode 100644 index 55cbb88542..0000000000 --- a/pkg/multicloud/huawei/client/modules/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules // import "yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules" diff --git a/pkg/multicloud/huawei/client/modules/manager_base.go b/pkg/multicloud/huawei/client/modules/manager_base.go deleted file mode 100644 index 1acd2d497c..0000000000 --- a/pkg/multicloud/huawei/client/modules/manager_base.go +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "context" - "fmt" - "net/http" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/requests" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -type IRequestHook interface { - Process(r requests.IRequest) -} - -type SBaseManager struct { - cfg manager.IManagerConfig - httpClient *http.Client - requestHook IRequestHook // 用于对request做特殊处理。非必要请不要使用!!!。目前只有port接口用到。 - - columns []string - debug bool -} - -type sThrottlingThreshold struct { - locked bool - lockTime time.Time -} - -func (t *sThrottlingThreshold) CheckingLock() { - if !t.locked { - return - } - - for { - if t.lockTime.Sub(time.Now()).Seconds() < 0 { - return - } - log.Debugf("throttling threshold has been reached. release at %s", t.lockTime) - time.Sleep(5 * time.Second) - } -} - -func (t *sThrottlingThreshold) Lock() { - // 锁定至少15秒 - t.locked = true - t.lockTime = time.Now().Add(15 * time.Second) -} - -var ThrottlingLock = sThrottlingThreshold{locked: false, lockTime: time.Time{}} - -func NewBaseManager2(cfg manager.IManagerConfig, requesthk IRequestHook) SBaseManager { - return SBaseManager{ - cfg: cfg, - httpClient: httputils.GetDefaultClient(), - debug: cfg.GetDebug(), - requestHook: requesthk, - } -} - -func NewBaseManager(cfg manager.IManagerConfig) SBaseManager { - return NewBaseManager2(cfg, nil) -} - -func (self *SBaseManager) GetEndpoint() string { - return self.cfg.GetEndpoint() -} - -func (self *SBaseManager) GetColumns() []string { - return self.columns -} - -func (self *SBaseManager) SetHttpClient(httpClient *http.Client) { - self.httpClient = httpClient -} - -func (self *SBaseManager) _list(request requests.IRequest, responseKey string) (*responses.ListResult, error) { - _, body, err := self.jsonRequest(request) - if err != nil { - return nil, err - } - if body == nil { - log.Warningf("empty response") - return &responses.ListResult{}, nil - } - - rets, err := body.GetArray(responseKey) - if err != nil { - return nil, errors.Wrapf(err, "body.GetArray %s", responseKey) - } - total, _ := body.Int("count") - // if err != nil { - // total = int64(len(rets)) - //} - - //if total == 0 { - // total = int64(len(rets)) - //} - - limit := 0 - if v, exists := request.GetQueryParams()["limit"]; exists { - limit, _ = strconv.Atoi(v) - } - - offset := 0 - if v, exists := request.GetQueryParams()["offset"]; exists { - offset, _ = strconv.Atoi(v) - } - - return &responses.ListResult{ - Data: rets, - Total: int(total), - Limit: limit, - Offset: offset, - }, nil -} - -func (self *SBaseManager) _do(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) { - _, resp, e := self.jsonRequest(request) - if e != nil { - return nil, e - } - - if resp == nil { // no reslt - return jsonutils.NewDict(), nil - } - - if len(responseKey) == 0 { - return resp, nil - } - - ret, e := resp.Get(responseKey) - if e != nil { - return nil, e - } - - return ret, nil -} - -func (self *SBaseManager) _get(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) { - return self._do(request, responseKey) -} - -type HuaweiClientError struct { - Code int - Errorcode []string - err error - Details string - ErrorCode string -} - -func (ce *HuaweiClientError) Error() string { - return jsonutils.Marshal(ce).String() -} - -func (ce *HuaweiClientError) ParseErrorFromJsonResponse(statusCode int, body jsonutils.JSONObject) error { - if body != nil { - body.Unmarshal(ce) - } - if ce.Code == 0 { - ce.Code = statusCode - } - if len(ce.Details) == 0 && body != nil { - ce.Details = body.String() - } - return ce -} - -func (self *SBaseManager) jsonRequest(request requests.IRequest) (http.Header, jsonutils.JSONObject, error) { - ThrottlingLock.CheckingLock() - ctx := context.Background() - // hook request - if self.requestHook != nil { - self.requestHook.Process(request) - } - // 拼接、编译、签名 requests here。 - err := self.buildRequestWithSigner(request, self.cfg.GetSigner()) - if err != nil { - return nil, nil, err - } - header := http.Header{} - for k, v := range request.GetHeaders() { - header.Set(k, v) - } - - var jsonBody jsonutils.JSONObject - content := request.GetContent() - if len(content) > 0 { - jsonBody, err = jsonutils.Parse(content) - if err != nil { - return nil, nil, fmt.Errorf("not a json body") - } - } - - client := httputils.NewJsonClient(self.httpClient) - req := httputils.NewJsonRequest(httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), jsonBody) - req.SetHeader(header) - resp := &HuaweiClientError{} - const MAX_RETRY = 3 - retry := MAX_RETRY - for { - h, b, e := client.Send(ctx, req, resp, self.debug) - if e == nil { - return h, b, nil - } - - log.Errorf("[%s] %s body: %v error: %v", req.GetHttpMethod(), req.GetUrl(), jsonBody, e) - - switch err := e.(type) { - case *HuaweiClientError: - if err.ErrorCode == "APIGW.0301" { - return h, b, errors.Wrapf(httperrors.ErrInvalidAccessKey, e.Error()) - } else if err.Code == 499 && retry > 0 && request.GetMethod() == "GET" { - retry -= 1 - time.Sleep(3 * time.Second * time.Duration(MAX_RETRY-retry)) - } else if (err.Code == 404 || strings.Contains(err.Details, "could not be found") || - strings.Contains(err.Error(), "Not Found") || - strings.Contains(err.Details, "does not exist")) && request.GetMethod() != "POST" { - return h, b, errors.Wrap(cloudprovider.ErrNotFound, err.Error()) - } else if err.Code == 429 && retry > 0 { - // 当前请求过多。 - ThrottlingLock.Lock() - retry -= 1 - time.Sleep(15 * time.Second) - } else { - return h, b, e - } - default: - return h, b, e - } - } -} - -func (self *SBaseManager) rawRequest(request requests.IRequest) (*http.Response, error) { - ctx := context.Background() - // 拼接、编译requests here。 - header := http.Header{} - for k, v := range request.GetHeaders() { - header.Set(k, v) - } - return httputils.Request(self.httpClient, ctx, httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), header, request.GetBodyReader(), self.debug) -} - -func (self *SBaseManager) buildRequestWithSigner(request requests.IRequest, signer auth.Signer) error { - return auth.Sign(request, signer) -} diff --git a/pkg/multicloud/huawei/client/modules/manager_resource.go b/pkg/multicloud/huawei/client/modules/manager_resource.go deleted file mode 100644 index 927a514bbb..0000000000 --- a/pkg/multicloud/huawei/client/modules/manager_resource.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/requests" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type ServiceNameType string - -const HuaWeiDefaultDomain = "myhuaweicloud.com" - -const ( - ServiceNameECS ServiceNameType = "ecs" // 弹性云服务 - ServiceNameCCE ServiceNameType = "cce" // 云容器服务 - ServiceNameAS ServiceNameType = "as" // 弹性伸缩服务 - ServiceNameIAM ServiceNameType = "iam" // 统一身份认证服务 - ServiceNameIMS ServiceNameType = "ims" // 镜像服务 - ServiceNameCSBS ServiceNameType = "csbs" // 云服务器备份服务 - ServiceNameCCI ServiceNameType = "cci" // 云容器实例 CCI - ServiceNameBMS ServiceNameType = "bms" // 裸金属服务器 - ServiceNameEVS ServiceNameType = "evs" // 云硬盘 EVS - ServiceNameVBS ServiceNameType = "vbs" // 云硬盘备份 VBS - ServiceNameOBS ServiceNameType = "obs" // 对象存储服务 OBS - ServiceNameVPC ServiceNameType = "vpc" // 虚拟私有云 VPC - ServiceNameELB ServiceNameType = "elb" // 弹性负载均衡 ELB - ServiceNameBSS ServiceNameType = "bss" // 合作伙伴运营能力 - ServiceNameNAT ServiceNameType = "nat" // Nat网关 NAT - ServiceNameDCS ServiceNameType = "dcs" // 分布式缓存服务 - ServiceNameRDS ServiceNameType = "rds" // 关系型数据库 RDS - ServiceNameCTS ServiceNameType = "cts" // 云审计服务 - ServiceNameCES ServiceNameType = "ces" // 监控服务 CloudEye - ServiceNameEPS ServiceNameType = "eps" // 企业项目 - - ServiceNameModelarts ServiceNameType = "modelarts" // AI ModelArts - - ServiceNameSFSTurbo ServiceNameType = "sfs-turbo" // 文件系统 -) - -type SManagerContext struct { - InstanceManager manager.IManager - InstanceId string -} - -func (self *SManagerContext) GetPath() string { - path := self.InstanceManager.KeyString() - if len(self.InstanceId) > 0 { - path += fmt.Sprintf("/%s", url.PathEscape(self.InstanceId)) - } - - return path -} - -type SResourceManager struct { - SBaseManager - ctx manager.IManagerContext - ServiceName ServiceNameType // 服务名称: ecs - Region string // 区域: cn-north-1 - DomainId string - ProjectId string // 项目ID: uuid - version string // api 版本号 - Keyword string // 资源名称单数。构建URL时使用 - KeywordPlural string // 资源名称复数形式。构建URL时使用 - - ResourceKeyword string // 资源名称。url中使用 -} - -func getContent(params jsonutils.JSONObject) string { - if params == nil { - return "" - } - - return params.String() -} - -func (self *SResourceManager) Version() string { - return self.version -} - -func (self *SResourceManager) KeyString() string { - return self.ResourceKeyword -} - -func (self *SResourceManager) ServiceType() string { - return string(self.ServiceName) -} - -func (self *SResourceManager) GetColumns() []string { - return []string{} -} - -func (self *SResourceManager) SetDomainId(domainId string) { - self.DomainId = domainId -} - -func (self *SResourceManager) getReourcePath(ctx manager.IManagerContext, rid string, spec string) string { - segs := []string{} - if ctx != nil { - segs = append(segs, ctx.GetPath()) - } - - segs = append(segs, self.KeyString()) - - if len(rid) > 0 { - segs = append(segs, url.PathEscape(rid)) - } - - if len(spec) > 0 { - specSegs := strings.Split(spec, "/") - for _, specSeg := range specSegs { - segs = append(segs, url.PathEscape(specSeg)) - } - } - - return strings.Join(segs, "/") -} - -func (self *SResourceManager) newRequest(method, rid, spec string, ctx manager.IManagerContext) *requests.SRequest { - resourcePath := self.getReourcePath(ctx, rid, spec) - return requests.NewResourceRequest(self.GetEndpoint(), method, string(self.ServiceName), self.version, self.Region, self.ProjectId, resourcePath) -} - -func (self *SResourceManager) List(queries map[string]string) (*responses.ListResult, error) { - return self.ListInContext(self.ctx, queries) -} - -func (self *SResourceManager) ListInContext(ctx manager.IManagerContext, queries map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(ctx, "", queries, self.KeywordPlural) -} - -func (self *SResourceManager) ListInContextWithSpec(ctx manager.IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error) { - request := self.newRequest("GET", "", spec, ctx) - for k, v := range queries { - request.AddQueryParam(k, v) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._list(request, responseKey) -} - -func (self *SResourceManager) Get(id string, queries map[string]string) (jsonutils.JSONObject, error) { - return self.GetInContext(self.ctx, id, queries) -} - -func (self *SResourceManager) GetInContext(ctx manager.IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error) { - return self.GetInContextWithSpec(ctx, id, "", queries, self.Keyword) -} - -func (self *SResourceManager) GetInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("GET", id, spec, ctx) - for k, v := range queries { - request.AddQueryParam(k, v) - } - - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._get(request, responseKey) -} - -func (self *SResourceManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.CreateInContext(self.ctx, params) -} - -func (self *SResourceManager) CreateInContext(ctx manager.IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.CreateInContextWithSpec(ctx, "", params, self.Keyword) -} - -func (self *SResourceManager) CreateInContextWithSpec(ctx manager.IManagerContext, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("POST", "", spec, ctx) - request.SetContent([]byte(params.String())) - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { - return "", fmt.Errorf("not supported") -} - -func (self *SResourceManager) Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.UpdateInContext(self.ctx, id, params) -} - -func (self *SResourceManager) UpdateInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.UpdateInContextWithSpec(ctx, id, "", params, self.Keyword) -} - -func (self *SResourceManager) UpdateInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("PUT", id, spec, ctx) - content := getContent(params) - if len(content) > 0 { - request.SetContent([]byte(content)) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) Patch(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.PatchInContext(self.ctx, id, params) -} - -func (self *SResourceManager) PatchInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.PatchInContextWithSpec(ctx, id, "", params, self.Keyword) -} - -func (self *SResourceManager) PatchInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("PATCH", id, spec, ctx) - content := getContent(params) - if len(content) > 0 { - request.SetContent([]byte(content)) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.DeleteInContext(self.ctx, id, params) -} - -func (self *SResourceManager) DeleteInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.DeleteInContextWithSpec(ctx, id, "", nil, params, "") -} - -func (self *SResourceManager) DeleteInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("DELETE", id, spec, ctx) - for k, v := range queries { - request.AddQueryParam(k, v) - } - - content := getContent(params) - if len(content) > 0 { - request.SetContent([]byte(content)) - } - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.PerformAction2(action, id, params, self.Keyword) -} - -func (self *SResourceManager) PerformAction2(action string, id string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { - request := self.newRequest("POST", id, action, nil) - request.SetContent([]byte(getContent(params))) - if len(self.DomainId) > 0 { - request.AddHeaderParam("X-Domain-Id", self.DomainId) - } - - return self._do(request, responseKey) -} - -func (self *SResourceManager) SetVersion(v string) { - self.version = v -} - -func (self *SResourceManager) versionedURL(path string) string { - return "" -} - -// todo: Init a manager with environment variables -func (self *SResourceManager) Init() error { - return nil -} diff --git a/pkg/multicloud/huawei/client/modules/mod_ces.go b/pkg/multicloud/huawei/client/modules/mod_ces.go deleted file mode 100644 index 56cc8a1021..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_ces.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/requests" -) - -type SCloudEyeManager struct { - SResourceManager -} - -func NewCloudEyeManager(cfg manager.IManagerConfig) *SCloudEyeManager { - return &SCloudEyeManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameCES, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "V1.0", - Keyword: "", - KeywordPlural: "metrics", - ResourceKeyword: "metrics", - }} -} - -type SMetricDimension struct { - Name string `json:"name"` - Value string `json:"value"` -} - -type SDatapoint struct { - Timestamp int64 `json:"timestamp"` - Max float64 `json:"max,omitzero"` - Min float64 `json:"min,omitzero"` - Average float64 `json:"average,omitzero"` - Sum float64 `json:"sum,omitzero"` - Variance float64 `json:"variance,omitzero"` -} - -type SMetricData struct { - SMetricMeta - - Datapoints []SDatapoint -} - -type SMetricMeta struct { - SMetric - - Unit string `json:"unit"` -} - -type SMetric struct { - MetricName string `json:"metric_name"` - Namespace string `json:"namespace"` - - Dimensions []SMetricDimension `json:"dimensions"` -} - -func (ces *SCloudEyeManager) ListMetrics() ([]SMetricMeta, error) { - metrics := make([]SMetricMeta, 0) - next := "" - for { - marker, data, err := ces.listMetricsInternal(next) - if err != nil { - return nil, errors.Wrap(err, "ces.listMetricsInternal") - } - if len(data) == 0 { - break - } - metrics = append(metrics, data...) - next = marker - } - return metrics, nil -} - -func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []SMetricMeta, error) { - request := requests.NewResourceRequest(ces.GetEndpoint(), "GET", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, ces.ResourceKeyword) - request.AddQueryParam("limit", "1000") - if len(start) > 0 { - request.AddQueryParam("start", start) - } - _, resp, err := ces.jsonRequest(request) - if err != nil { - return "", nil, errors.Wrap(err, "ces.jsonRequest") - } - marker, _ := resp.GetString("meta_data", "marker") - metrics := make([]SMetricMeta, 0) - err = resp.Unmarshal(&metrics, "metrics") - if err != nil { - return "", nil, errors.Wrap(err, "resp.Unmarshal metrics") - } - return marker, metrics, nil -} - -type SBatchQueryMetricDataInput struct { - Metrics []SMetric `json:"metrics"` - - From int64 `json:"from"` - To int64 `json:"to"` - Period string `json:"period"` - Filter string `json:"filter"` -} - -func (ces *SCloudEyeManager) GetMetricsData(metrics []SMetricMeta, since time.Time, until time.Time) ([]SMetricData, error) { - if len(metrics) > 10 { - return nil, errors.Wrap(httperrors.ErrTooLarge, "request more than 10 metrics") - } - metricReq := make([]SMetric, len(metrics)) - for i := range metrics { - metricReq[i] = metrics[i].SMetric - } - request := requests.NewResourceRequest(ces.GetEndpoint(), "POST", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, "batch-query-metric-data") - input := SBatchQueryMetricDataInput{ - Metrics: metricReq, - From: since.Unix() * 1000, - To: until.Unix() * 1000, - Period: "1", - Filter: "average", - } - body := jsonutils.Marshal(&input).String() - request.SetContent([]byte(body)) - _, resp, err := ces.jsonRequest(request) - if err != nil { - return nil, errors.Wrap(err, "ces.jsonRequest") - } - //log.Debugf("%s", resp) - result := make([]SMetricData, 0) - err = resp.Unmarshal(&result, "metrics") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return result, nil -} diff --git a/pkg/multicloud/huawei/client/modules/mod_credential.go b/pkg/multicloud/huawei/client/modules/mod_credential.go deleted file mode 100644 index 183818c91c..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_credential.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SCredentialManager struct { - SResourceManager -} - -func NewCredentialManager(cfg manager.IManagerConfig) *SCredentialManager { - return &SCredentialManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3.0", - Keyword: "credential", - KeywordPlural: "credentials", - - ResourceKeyword: "OS-CREDENTIAL/credentials", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_dbinstance.go b/pkg/multicloud/huawei/client/modules/mod_dbinstance.go deleted file mode 100644 index 0645007166..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_dbinstance.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type SDBInstanceManager struct { - SResourceManager -} - -func NewDBInstanceManager(cfg manager.IManagerConfig) *SDBInstanceManager { - return &SDBInstanceManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "", - KeywordPlural: "instances", - - ResourceKeyword: "instances", - }} -} - -func (self *SDBInstanceManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - if len(id) == 0 { - return nil, cloudprovider.ErrNotFound - } - resp, err := self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "") - if err != nil { - return nil, err - } - instances, err := resp.GetArray("instances") - if err != nil { - return nil, err - } - if len(instances) == 0 { - return nil, cloudprovider.ErrNotFound - } else if len(instances) == 1 { - return instances[0], nil - } - return nil, cloudprovider.ErrDuplicateId -} - -func (self *SDBInstanceManager) ListParameters(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListParameters missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/configurations", id), queries, "configuration_parameters") -} - -func (self *SDBInstanceManager) ListDatabases(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListDatabases missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/database/detail", id), queries, "databases") -} - -func (self *SDBInstanceManager) ListAccounts(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListAccounts missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/detail", id), queries, "users") -} - -func (self *SDBInstanceManager) ListPrivileges(queries map[string]string) (*responses.ListResult, error) { - id, _ := queries["instance_id"] - if len(id) == 0 { - return nil, fmt.Errorf("SDBInstanceManager.ListPrivileges missing parameter instance_id") - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/database", id), queries, "databases") -} diff --git a/pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go b/pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go deleted file mode 100644 index 21efbe8218..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SDBInstanceBackupManager struct { - SResourceManager -} - -func NewDBInstanceBackupManager(cfg manager.IManagerConfig) *SDBInstanceBackupManager { - return &SDBInstanceBackupManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "backup", - KeywordPlural: "backups", - - ResourceKeyword: "backups", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go b/pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go deleted file mode 100644 index db0621980d..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SDBInstanceFlavorManager struct { - SResourceManager -} - -func NewDBInstanceFlavorManager(cfg manager.IManagerConfig) *SDBInstanceFlavorManager { - return &SDBInstanceFlavorManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "flavor", - KeywordPlural: "flavor", - - ResourceKeyword: "flavors", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go b/pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go deleted file mode 100644 index 080508f448..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SDBInstanceJobManager struct { - SResourceManager -} - -func NewDBInstanceJobManager(cfg manager.IManagerConfig) *SDBInstanceJobManager { - return &SDBInstanceJobManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameRDS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v3", - Keyword: "", - KeywordPlural: "", - - ResourceKeyword: "jobs", - }} -} - -func (self *SDBInstanceJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - return self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "job") -} diff --git a/pkg/multicloud/huawei/client/modules/mod_disks.go b/pkg/multicloud/huawei/client/modules/mod_disks.go deleted file mode 100644 index ffd67ab01c..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_disks.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type SDiskManager struct { - SResourceManager -} - -func NewDiskManager(cfg manager.IManagerConfig) *SDiskManager { - return &SDiskManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEVS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "volume", - KeywordPlural: "volumes", - - ResourceKeyword: "cloudvolumes", - }} -} - -func (self *SDiskManager) List(querys map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -// https://support.huaweicloud.com/api-evs/evs_04_2003.html -func (self *SDiskManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { - origin_version := self.version - self.version = "v2.1" - defer func() { self.version = origin_version }() - - ret, err := self.CreateInContextWithSpec(nil, "", params, "") - if err != nil { - log.Debugf("AsyncCreate %s", err) - return "", err - } - - log.Debugf("AsyncCreate result %s", ret.String()) - // 按需机器 - jobId, err := ret.GetString("job_id") - if err == nil { - return jobId, nil - } - - // 包年包月机器 - return ret.GetString("order_id") -} - -// https://support.huaweicloud.com/api-evs/evs_04_2003.html -func (self *SDiskManager) GetDiskTypes() (*responses.ListResult, error) { - originKeyword := self.ResourceKeyword - self.ResourceKeyword = "" - defer func() { self.ResourceKeyword = originKeyword }() - return self.ListInContextWithSpec(self.ctx, "types", nil, "volume_types") -} diff --git a/pkg/multicloud/huawei/client/modules/mod_dnat_rules.go b/pkg/multicloud/huawei/client/modules/mod_dnat_rules.go deleted file mode 100644 index 8f7d807813..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_dnat_rules.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SNatDRuleManager struct { - SResourceManager -} - -func NewNatDManager(cfg manager.IManagerConfig) *SNatDRuleManager { - man := &SNatDRuleManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameNAT, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "dnat_rule", - KeywordPlural: "dnat_rules", - - ResourceKeyword: "dnat_rules", - }} - if len(cfg.GetProjectId()) > 0 { - man.requestHook = &sProjectHook{cfg.GetProjectId()} - } - return man -} diff --git a/pkg/multicloud/huawei/client/modules/mod_domains.go b/pkg/multicloud/huawei/client/modules/mod_domains.go deleted file mode 100644 index cbfedb04cb..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_domains.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type SDomainManager struct { - SResourceManager -} - -func NewDomainManager(cfg manager.IManagerConfig) *SDomainManager { - m := &SDomainManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3/auth", - Keyword: "domain", - KeywordPlural: "domains", - - ResourceKeyword: "domains", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} - -func (manager *SDomainManager) DeleteRole(domainId string, groupId, roleId string) error { - if len(domainId) == 0 { - return fmt.Errorf("missing domainId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - manager.SetVersion("v3") - defer manager.SetVersion("v3/auth") - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.DeleteInContextWithSpec(nil, domainId, res, nil, nil, "") - if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return err -} - -func (manager *SDomainManager) ListRoles(domainId string, groupId string) (*responses.ListResult, error) { - if len(domainId) == 0 { - return nil, fmt.Errorf("missing domainId") - } - if len(groupId) == 0 { - return nil, fmt.Errorf("missing groupId") - } - manager.SetVersion("v3") - defer manager.SetVersion("v3/auth") - res := fmt.Sprintf("%s/groups/%s/roles", domainId, groupId) - return manager.ListInContextWithSpec(nil, res, nil, "roles") -} - -func (manager *SDomainManager) AddRole(domainId string, groupId, roleId string) error { - if len(domainId) == 0 { - return fmt.Errorf("missing domainId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - manager.SetVersion("v3") - defer manager.SetVersion("v3/auth") - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.UpdateInContextWithSpec(nil, domainId, res, nil, "") - return err -} diff --git a/pkg/multicloud/huawei/client/modules/mod_elasticcache.go b/pkg/multicloud/huawei/client/modules/mod_elasticcache.go deleted file mode 100644 index 39ea576497..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_elasticcache.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type SElasticcacheManager struct { - SResourceManager -} - -type SDcsAvailableZoneManager struct { - SResourceManager -} - -func NewElasticcacheManager(cfg manager.IManagerConfig) *SElasticcacheManager { - return &SElasticcacheManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameDCS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1.0", - Keyword: "", - KeywordPlural: "instances", - - ResourceKeyword: "instances", - }} -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html -func (self *SElasticcacheManager) ListBackups(queries map[string]string) (*responses.ListResult, error) { - var spec string - if id, _ := queries["instance_id"]; len(id) == 0 { - return nil, fmt.Errorf("SElasticcacheManager.ListBackups missing parameter instance_id") - } else { - spec = fmt.Sprintf("%s/backups", id) - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, spec, queries, "backup_record_response") -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html -func (self *SElasticcacheManager) ListParameters(queries map[string]string) (*responses.ListResult, error) { - var spec string - if id, _ := queries["instance_id"]; len(id) == 0 { - return nil, fmt.Errorf("SElasticcacheManager.ListParameters missing parameter instance_id") - } else { - spec = fmt.Sprintf("%s/configs", id) - } - - delete(queries, "instance_id") - return self.ListInContextWithSpec(nil, spec, queries, "redis_config") -} - -func (self *SElasticcacheManager) Restart(instanceId string) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") - params.Add(jsonutils.NewString("restart"), "action") - return self.UpdateInContextWithSpec(nil, "", "status", params, "") -} - -// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 -func (self *SElasticcacheManager) Flush(instanceId string) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") - params.Add(jsonutils.NewString("flush"), "action") - return self.UpdateInContextWithSpec(nil, "", "status", params, "") -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html -func (self *SElasticcacheManager) RestoreInstance(instanceId string, backupId string) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewArray(jsonutils.NewString(backupId)), "backup_id") - - return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/restores", instanceId), params, "") -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html -func (self *SElasticcacheManager) ChangeInstanceSpec(instanceId string, specCode string, newCapacity int64) (jsonutils.JSONObject, error) { - params := jsonutils.NewDict() - params.Set("new_capacity", jsonutils.NewInt(newCapacity)) - params.Set("spec_code", jsonutils.NewString(specCode)) - - return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/extend", instanceId), params, "") -} - -func NewDcsAvailableZoneManager(cfg manager.IManagerConfig) *SDcsAvailableZoneManager { - return &SDcsAvailableZoneManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameDCS, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v1.0", - Keyword: "available_zone", - KeywordPlural: "available_zones", - - ResourceKeyword: "availableZones", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go b/pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go deleted file mode 100644 index c8a95e2372..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SEnterpriseProjectManager struct { - SResourceManager -} - -func NewEnterpriseProjectManager(cfg manager.IManagerConfig) *SEnterpriseProjectManager { - m := &SEnterpriseProjectManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEPS, - Region: "", - ProjectId: "", - version: "v1.0", - Keyword: "enterprise_project", - KeywordPlural: "enterprise_projects", - - ResourceKeyword: "enterprise-projects", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/pkg/multicloud/huawei/client/modules/mod_flavors.go b/pkg/multicloud/huawei/client/modules/mod_flavors.go deleted file mode 100644 index 16ab9d0fb6..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_flavors.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SFlavorManager struct { - SResourceManager -} - -func NewFlavorManager(cfg manager.IManagerConfig) *SFlavorManager { - return &SFlavorManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "flavor", - KeywordPlural: "flavors", - - ResourceKeyword: "cloudservers/flavors", // 这个接口有点特殊,实际只用到了list一个方法。为了简便直接把cloudservers附上。 - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_groups.go b/pkg/multicloud/huawei/client/modules/mod_groups.go deleted file mode 100644 index 75693bef5a..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_groups.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SGroupManager struct { - SResourceManager -} - -func NewGroupManager(cfg manager.IManagerConfig) *SGroupManager { - m := &SGroupManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3", - Keyword: "group", - KeywordPlural: "groups", - - ResourceKeyword: "groups", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/pkg/multicloud/huawei/client/modules/mod_images.go b/pkg/multicloud/huawei/client/modules/mod_images.go deleted file mode 100644 index 6b432a5e0d..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_images.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/requests" -) - -type SImageManager struct { - SResourceManager -} - -type imageProject struct { - projectId string -} - -// image创建接口若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊) -// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID -func (self *imageProject) Process(request requests.IRequest) { - request.AddHeaderParam("X-Project-Id", self.projectId) -} - -func NewImageManager(cfg manager.IManagerConfig) *SImageManager { - var requestHook imageProject - if len(cfg.GetProjectId()) > 0 { - requestHook = imageProject{projectId: cfg.GetProjectId()} - } - - return &SImageManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager2(cfg, &requestHook), - ServiceName: ServiceNameIMS, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2", - Keyword: "image", - KeywordPlural: "images", - - ResourceKeyword: "cloudimages", - }} -} - -//https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091566.html -func (self *SImageManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - if querys == nil { - querys = make(map[string]string, 0) - } - - querys["id"] = id - // 这里默认使用private - // if t, exists := querys["__imagetype"]; !exists || len(t) == 0 { - // querys["__imagetype"] = "private" - // } - - ret, err := self.ListInContext(nil, querys) - if err != nil { - return nil, err - } - - if ret.Data == nil || len(ret.Data) == 0 { - return nil, httperrors.NewNotFoundError("image %s not found", id) - } - - return ret.Data[0], nil -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092108.html -// 删除image只能用这个manager -func NewOpenstackImageManager(cfg manager.IManagerConfig) *SImageManager { - var requestHook imageProject - if len(cfg.GetProjectId()) > 0 { - requestHook = imageProject{projectId: cfg.GetProjectId()} - } - - return &SImageManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager2(cfg, &requestHook), - ServiceName: ServiceNameIMS, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2", - Keyword: "image", - KeywordPlural: "images", - - ResourceKeyword: "images", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_interface.go b/pkg/multicloud/huawei/client/modules/mod_interface.go deleted file mode 100644 index f1f953e407..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_interface.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SInterfaceManager struct { - SResourceManager -} - -// 不建议使用 -func NewInterfaceManager(cfg manager.IManagerConfig) *SInterfaceManager { - return &SInterfaceManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "interfaceAttachment", - KeywordPlural: "interfaceAttachments", - - ResourceKeyword: "os-interface", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_jobs.go b/pkg/multicloud/huawei/client/modules/mod_jobs.go deleted file mode 100644 index 610c48685f..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_jobs.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type SJobManager struct { - SResourceManager -} - -func NewJobManager(cfg manager.IManagerConfig) *SJobManager { - return &SJobManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: "", - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "", - KeywordPlural: "", - - ResourceKeyword: "jobs", - }} -} - -func (self *SJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { - processedQuery, err := self.processQueryParam(querys) - if err != nil { - return nil, err - } - - return self.GetInContext(nil, id, processedQuery) -} - -func (self *SJobManager) List(querys map[string]string) (*responses.ListResult, error) { - processedQuery, err := self.processQueryParam(querys) - if err != nil { - return nil, err - } - return self.ListInContext(nil, processedQuery) -} - -// 兼容查询不同ServiceName服务的Job做的特殊处理。 -func (self *SJobManager) processQueryParam(querys map[string]string) (map[string]string, error) { - service_type, exists := querys["service_type"] - if !exists { - return querys, fmt.Errorf("must specific query parameter `service_type`. e.g. ecs|ims|iam") - } - - self.ServiceName = ServiceNameType(service_type) - delete(querys, "service_type") - return querys, nil -} diff --git a/pkg/multicloud/huawei/client/modules/mod_keypairs.go b/pkg/multicloud/huawei/client/modules/mod_keypairs.go deleted file mode 100644 index 278f1c684e..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_keypairs.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SKeypairManager struct { - SResourceManager -} - -func NewKeypairManager(cfg manager.IManagerConfig) *SKeypairManager { - return &SKeypairManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "keypair", - KeywordPlural: "keypairs", - - ResourceKeyword: "os-keypairs", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_mapping.go b/pkg/multicloud/huawei/client/modules/mod_mapping.go deleted file mode 100644 index b668674272..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_mapping.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SAMLProviderMappingManager struct { - SResourceManager -} - -func NewSAMLProviderMappingManager(cfg manager.IManagerConfig) *SAMLProviderMappingManager { - m := &SAMLProviderMappingManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3/OS-FEDERATION", - Keyword: "mapping", - KeywordPlural: "mappings", - - ResourceKeyword: "mappings", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/pkg/multicloud/huawei/client/modules/mod_natgateway.go b/pkg/multicloud/huawei/client/modules/mod_natgateway.go deleted file mode 100644 index b73e0652fb..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_natgateway.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/requests" -) - -type SNatGatewayManager struct { - SResourceManager -} - -type sProjectHook struct { - projectId string -} - -func (self *sProjectHook) Process(request requests.IRequest) { - request.AddHeaderParam("X-Project-Id", self.projectId) -} - -func NewNatGatewayManager(cfg manager.IManagerConfig) *SNatGatewayManager { - man := &SNatGatewayManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameNAT, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "nat_gateway", - KeywordPlural: "nat_gateways", - - ResourceKeyword: "nat_gateways", - }} - if len(cfg.GetProjectId()) > 0 { - man.requestHook = &sProjectHook{cfg.GetProjectId()} - } - return man -} diff --git a/pkg/multicloud/huawei/client/modules/mod_port.go b/pkg/multicloud/huawei/client/modules/mod_port.go deleted file mode 100644 index 5a736bcc71..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_port.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/requests" -) - -type SPortManager struct { - SResourceManager -} - -type portProject struct { - projectId string -} - -// port接口查询时若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊) -// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID -func (self *portProject) Process(request requests.IRequest) { - request.AddHeaderParam("X-Project-Id", self.projectId) -} - -func NewPortManager(cfg manager.IManagerConfig) *SPortManager { - var requestHook portProject - if len(cfg.GetProjectId()) > 0 { - requestHook = portProject{projectId: cfg.GetProjectId()} - } - - return &SPortManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager2(cfg, &requestHook), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "port", - KeywordPlural: "ports", - - ResourceKeyword: "ports", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_projects.go b/pkg/multicloud/huawei/client/modules/mod_projects.go deleted file mode 100644 index 8982d04ce3..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_projects.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type SProjectManager struct { - SResourceManager -} - -func NewProjectManager(cfg manager.IManagerConfig) *SProjectManager { - m := &SProjectManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3", - Keyword: "project", - KeywordPlural: "projects", - - ResourceKeyword: "projects", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} - -func (manager *SProjectManager) ListRoles(projectId, groupId string) (*responses.ListResult, error) { - if len(projectId) == 0 { - return nil, fmt.Errorf("missing projectId") - } - if len(groupId) == 0 { - return nil, fmt.Errorf("missing groupId") - } - res := fmt.Sprintf("%s/groups/%s/roles", projectId, groupId) - return manager.ListInContextWithSpec(nil, res, nil, "roles") -} - -func (manager *SProjectManager) DeleteProjectRole(projectId, groupId, roleId string) error { - if len(projectId) == 0 { - return fmt.Errorf("missing projectId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.DeleteInContextWithSpec(nil, projectId, res, nil, nil, "") - if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return err -} - -func (manager *SProjectManager) AddProjectRole(projectId string, groupId, roleId string) error { - if len(projectId) == 0 { - return fmt.Errorf("missing projectId") - } - if len(groupId) == 0 { - return fmt.Errorf("missing groupId") - } - if len(roleId) == 0 { - return fmt.Errorf("missing roleId") - } - res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) - _, err := manager.UpdateInContextWithSpec(nil, projectId, res, nil, "") - return err -} diff --git a/pkg/multicloud/huawei/client/modules/mod_quotas.go b/pkg/multicloud/huawei/client/modules/mod_quotas.go deleted file mode 100644 index f8c3506048..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_quotas.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SQuotaManager struct { - SResourceManager -} - -func NewQuotaManager(cfg manager.IManagerConfig) *SQuotaManager { - return &SQuotaManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEVS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "quotas", - KeywordPlural: "quotas", - - ResourceKeyword: "quotas", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_regions.go b/pkg/multicloud/huawei/client/modules/mod_regions.go deleted file mode 100644 index 76ebce1ce9..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_regions.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SRegionManager struct { - SResourceManager -} - -func NewRegionManager(cfg manager.IManagerConfig) *SRegionManager { - return &SRegionManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3", - Keyword: "region", - KeywordPlural: "regions", - - ResourceKeyword: "regions", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_roles.go b/pkg/multicloud/huawei/client/modules/mod_roles.go deleted file mode 100644 index 1f4751541b..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_roles.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SRoleManager struct { - SResourceManager -} - -func NewRoleManager(cfg manager.IManagerConfig) *SRoleManager { - m := &SRoleManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3", - Keyword: "role", - KeywordPlural: "roles", - - ResourceKeyword: "roles", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/pkg/multicloud/huawei/client/modules/mod_saml_provider.go b/pkg/multicloud/huawei/client/modules/mod_saml_provider.go deleted file mode 100644 index 3542010ec8..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_saml_provider.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SAMLProviderManager struct { - SResourceManager -} - -func NewSAMLProviderManager(cfg manager.IManagerConfig) *SAMLProviderManager { - m := &SAMLProviderManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3/OS-FEDERATION", - Keyword: "identity_provider", - KeywordPlural: "identity_providers", - - ResourceKeyword: "identity_providers", - }} - m.SetDomainId(cfg.GetDomainId()) - return m -} diff --git a/pkg/multicloud/huawei/client/modules/mod_secgroup_rules.go b/pkg/multicloud/huawei/client/modules/mod_secgroup_rules.go deleted file mode 100644 index 200d46f186..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_secgroup_rules.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SSecgroupRuleManager struct { - SResourceManager -} - -func NewSecgroupRuleManager(cfg manager.IManagerConfig) *SSecgroupRuleManager { - return &SSecgroupRuleManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "security_group_rule", - KeywordPlural: "security_group_rules", - - ResourceKeyword: "security-group-rules", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_secgroups.go b/pkg/multicloud/huawei/client/modules/mod_secgroups.go deleted file mode 100644 index fe1bfe97b8..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_secgroups.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SSecurityGroupManager struct { - SResourceManager -} - -func NewSecurityGroupManager(cfg manager.IManagerConfig) *SSecurityGroupManager { - return &SSecurityGroupManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "security_group", - KeywordPlural: "security_groups", - - ResourceKeyword: "security-groups", - }} -} - -func NewNovaSecurityGroupManager(cfg manager.IManagerConfig) *SSecurityGroupManager { - return &SSecurityGroupManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2.1", - Keyword: "security_group", - KeywordPlural: "security_groups", - - ResourceKeyword: "os-security-groups", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_servers.go b/pkg/multicloud/huawei/client/modules/mod_servers.go deleted file mode 100644 index 301db7aa60..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_servers.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - "strconv" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type SServerManager struct { - SResourceManager -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212668.html -// v.1.1 新增支持创建包年/包月的弹性云服务器。!!但是不支持查询等调用 https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html -func NewServerManager(cfg manager.IManagerConfig) *SServerManager { - return &SServerManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "server", - KeywordPlural: "servers", - - ResourceKeyword: "cloudservers", - }} -} - -func (self *SServerManager) List(querys map[string]string) (*responses.ListResult, error) { - if offset, exists := querys["offset"]; !exists { - // 华为云分页参数各式各样。cloudserver offset从1开始。部分其他接口从0开始。 - // 另外部分接口使用pager分页 或者 maker分页 - querys["offset"] = "1" - } else { - n, err := strconv.Atoi(offset) - if err != nil { - return nil, fmt.Errorf("offset is invalid: %s", offset) - } - querys["offset"] = strconv.Itoa(n + 1) - } - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -/* -返回job id 或者 order id - -https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html -创建按需的弹性云服务 ——> job_id 任务ID (返回数据uuid举例:"70a599e0-31e7-49b7-b260-868f441e862b") -包年包月机器 --> order_id (返回数据举例: "CS1711152257C60TL") -*/ -func (self *SServerManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { - origin_version := self.version - self.version = "v1.1" - defer func() { self.version = origin_version }() - - ret, err := self.CreateInContextWithSpec(nil, "", params, "") - if err != nil { - log.Debugf("AsyncCreate %s", err) - return "", err - } - - log.Debugf("AsyncCreate result %s", ret.String()) - // 按需机器 - jobId, err := ret.GetString("job_id") - if err == nil { - return jobId, nil - } - - // 包年包月机器 - return ret.GetString("order_id") -} - -func (self *SServerManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return nil, fmt.Errorf("not supported.please use AsyncCreate") -} - -// 不推荐使用这个manager -func NewNovaServerManager(cfg manager.IManagerConfig) *SServerManager { - return &SServerManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2.1", - Keyword: "server", - KeywordPlural: "servers", - - ResourceKeyword: "servers", - }} -} - -// 重装弹性云服务器操作系统(安装Cloud-init),请用这个manager -func NewServerV2Manager(cfg manager.IManagerConfig) *SServerManager { - return &SServerManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "server", - KeywordPlural: "servers", - - ResourceKeyword: "cloudservers", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_sfs.go b/pkg/multicloud/huawei/client/modules/mod_sfs.go deleted file mode 100644 index b11353e914..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_sfs.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type SfsTurboManager struct { - SResourceManager -} - -func NewSfsTurboManager(cfg manager.IManagerConfig) *SfsTurboManager { - return &SfsTurboManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameSFSTurbo, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "", - KeywordPlural: "shares", - - ResourceKeyword: "sfs-turbo/shares", - }} -} - -func (self *SfsTurboManager) List(querys map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -func (self *SfsTurboManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { - return self.CreateInContextWithSpec(self.ctx, "", params, "") -} diff --git a/pkg/multicloud/huawei/client/modules/mod_snapshots.go b/pkg/multicloud/huawei/client/modules/mod_snapshots.go deleted file mode 100644 index cd5ee350a1..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_snapshots.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type SSnapshotManager struct { - SResourceManager -} - -func NewSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager { - return &SSnapshotManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEVS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "snapshot", - KeywordPlural: "snapshots", - - ResourceKeyword: "snapshots", - }} -} - -func (self *SSnapshotManager) List(querys map[string]string) (*responses.ListResult, error) { - return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html -// 回滚快照只能用这个manger。其他情况请不要使用 -// 另外,香港-亚太还支持另外一个接口。https://support.huaweicloud.com/api-evs/zh-cn_topic_0142374138.html -func NewOsSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager { - return &SSnapshotManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameEVS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "snapshot", - KeywordPlural: "snapshots", - - ResourceKeyword: "os-vendor-snapshots", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_snat_rules.go b/pkg/multicloud/huawei/client/modules/mod_snat_rules.go deleted file mode 100644 index 57f9eaf5aa..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_snat_rules.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SNatSRuleManager struct { - SResourceManager -} - -func NewNatSManager(cfg manager.IManagerConfig) *SNatSRuleManager { - man := &SNatSRuleManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameNAT, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "snat_rule", - KeywordPlural: "snat_rules", - - ResourceKeyword: "snat_rules", - }} - if len(cfg.GetProjectId()) > 0 { - man.requestHook = &sProjectHook{cfg.GetProjectId()} - } - return man -} diff --git a/pkg/multicloud/huawei/client/modules/mod_subnets.go b/pkg/multicloud/huawei/client/modules/mod_subnets.go deleted file mode 100644 index a69c6e309a..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_subnets.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SSubnetManager struct { - SResourceManager -} - -func NewSubnetManager(cfg manager.IManagerConfig) *SSubnetManager { - return &SSubnetManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "subnet", - KeywordPlural: "subnets", - - ResourceKeyword: "subnets", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_traces.go b/pkg/multicloud/huawei/client/modules/mod_traces.go deleted file mode 100644 index b2a9cb288b..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_traces.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type STraceManager struct { - SResourceManager -} - -func NewTraceManager(cfg manager.IManagerConfig) *STraceManager { - return &STraceManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameCTS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2.0", - Keyword: "trace", - KeywordPlural: "traces", - - ResourceKeyword: "system/trace", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_users.go b/pkg/multicloud/huawei/client/modules/mod_users.go deleted file mode 100644 index c1ff4467d5..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_users.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" -) - -type SUserManager struct { - SResourceManager -} - -func NewUserManager(cfg manager.IManagerConfig) *SUserManager { - user := &SUserManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameIAM, - Region: "", - ProjectId: "", - version: "v3.0/OS-USER", - Keyword: "user", - KeywordPlural: "users", - - ResourceKeyword: "users", - }} - user.SetDomainId(cfg.GetDomainId()) - return user -} - -func (self *SUserManager) List(querys map[string]string) (*responses.ListResult, error) { - self.SetVersion("v3") - return self.SResourceManager.List(querys) -} - -func (self *SUserManager) Delete(id string) (jsonutils.JSONObject, error) { - self.SetVersion("v3") - return self.SResourceManager.Delete(id, nil) -} - -func (self *SUserManager) ResetPassword(id, password string) error { - params := map[string]interface{}{ - "user": map[string]string{ - "password": password, - }, - } - _, err := self.SResourceManager.Update(id, jsonutils.Marshal(params)) - return err -} - -func (self *SUserManager) ListGroups(userId string) (*responses.ListResult, error) { - self.SetVersion("v3") - return self.SResourceManager.ListInContextWithSpec(nil, fmt.Sprintf("%s/groups", userId), nil, "groups") -} diff --git a/pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go b/pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go deleted file mode 100644 index 0e1d83bd38..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SVpcPeeringManager struct { - SResourceManager -} - -func NewVpcPeeringManager(cfg manager.IManagerConfig) *SVpcPeeringManager { - return &SVpcPeeringManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: "", - version: "v2.0", - Keyword: "peering", - KeywordPlural: "peerings", - - ResourceKeyword: "vpc/peerings", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_vpc_routes.go b/pkg/multicloud/huawei/client/modules/mod_vpc_routes.go deleted file mode 100644 index 1650a8e512..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_vpc_routes.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SVpcRouteManager struct { - SResourceManager -} - -func NewVpcRouteManager(cfg manager.IManagerConfig) *SVpcRouteManager { - return &SVpcRouteManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - // the url should not include the field "projectid" in huawei cloud api v2.0 - ProjectId: "", - version: "v2.0", - Keyword: "route", - KeywordPlural: "routes", - - ResourceKeyword: "vpc/routes", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_vpcs.go b/pkg/multicloud/huawei/client/modules/mod_vpcs.go deleted file mode 100644 index 4f2dde4ee0..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_vpcs.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SVpcManager struct { - SResourceManager -} - -func NewVpcManager(cfg manager.IManagerConfig) *SVpcManager { - return &SVpcManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameVPC, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v1", - Keyword: "vpc", - KeywordPlural: "vpcs", - - ResourceKeyword: "vpcs", - }} -} diff --git a/pkg/multicloud/huawei/client/modules/mod_zones.go b/pkg/multicloud/huawei/client/modules/mod_zones.go deleted file mode 100644 index 656ccbd545..0000000000 --- a/pkg/multicloud/huawei/client/modules/mod_zones.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 modules - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" -) - -type SZoneManager struct { - SResourceManager -} - -func NewZoneManager(cfg manager.IManagerConfig) *SZoneManager { - return &SZoneManager{SResourceManager: SResourceManager{ - SBaseManager: NewBaseManager(cfg), - ServiceName: ServiceNameECS, - Region: cfg.GetRegionId(), - ProjectId: cfg.GetProjectId(), - version: "v2", - Keyword: "availabilityZoneInfo", - KeywordPlural: "availabilityZoneInfo", - - ResourceKeyword: "os-availability-zone", - }} -} diff --git a/pkg/multicloud/huawei/client/requests/doc.go b/pkg/multicloud/huawei/client/requests/doc.go deleted file mode 100644 index 8f381028e2..0000000000 --- a/pkg/multicloud/huawei/client/requests/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 requests // import "yunion.io/x/onecloud/pkg/multicloud/huawei/client/requests" diff --git a/pkg/multicloud/huawei/client/responses/doc.go b/pkg/multicloud/huawei/client/responses/doc.go deleted file mode 100644 index 5ac8749b09..0000000000 --- a/pkg/multicloud/huawei/client/responses/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 responses // import "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" diff --git a/pkg/multicloud/huawei/client/responses/responses_test.go b/pkg/multicloud/huawei/client/responses/responses_test.go deleted file mode 100644 index 8cd532ddba..0000000000 --- a/pkg/multicloud/huawei/client/responses/responses_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 responses - -import ( - "testing" - - "yunion.io/x/jsonutils" -) - -func TestTransColonToDot(t *testing.T) { - raw := `{"A:b::C": "1:2:3", "A": true, "B": ["1:2", ":", "c"], "D:E": true}` - obj, err := jsonutils.ParseString(raw) - if err != nil { - t.Fatalf("json parse: %v", err) - } - gotj, err := TransColonToDot(obj) - if err != nil { - t.Fatalf("trans: %v", err) - } - wantj, _ := jsonutils.ParseString(`{"A":true,"A.b..C":"1:2:3","B":["1:2",":","c"],"D.E":true}`) - if !wantj.Equals(gotj) { - t.Errorf("trans failed, want:\n%s\ngot:\n%s", wantj, gotj) - } -} diff --git a/pkg/multicloud/huawei/cloudgroup.go b/pkg/multicloud/huawei/cloudgroup.go deleted file mode 100644 index 24b7a1112b..0000000000 --- a/pkg/multicloud/huawei/cloudgroup.go +++ /dev/null @@ -1,465 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SCloudgroup struct { - client *SHuaweiClient - Name string - Description string - Id string - CreateTime string -} - -func (group *SCloudgroup) GetName() string { - return group.Name -} - -func (group *SCloudgroup) GetDescription() string { - return group.Description -} - -func (group *SCloudgroup) GetGlobalId() string { - return group.Id -} - -func (group *SCloudgroup) Delete() error { - return group.client.DeleteGroup(group.Id) -} - -func (group *SCloudgroup) AddUser(name string) error { - user, err := group.client.GetIClouduserByName(name) - if err != nil { - return errors.Wrap(err, "GetIClouduserByName") - } - return group.client.AddUserToGroup(group.Id, user.GetGlobalId()) -} - -func (group *SCloudgroup) RemoveUser(name string) error { - user, err := group.client.GetIClouduserByName(name) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return errors.Wrapf(err, "GetIClouduserByName(%s)", name) - } - return group.client.RemoveUserFromGroup(group.Id, user.GetGlobalId()) -} - -func (group *SCloudgroup) DetachSystemPolicy(roleId string) error { - return group.client.DetachGroupRole(group.Id, roleId) -} - -func (group *SCloudgroup) DetachCustomPolicy(roleId string) error { - return group.client.DetachGroupCustomRole(group.Id, roleId) -} - -func (group *SCloudgroup) AttachSystemPolicy(roleId string) error { - return group.client.AttachGroupRole(group.Id, roleId) -} - -func (group *SCloudgroup) AttachCustomPolicy(roleId string) error { - return group.client.AttachGroupCustomRole(group.Id, roleId) -} - -func (group *SCloudgroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - roles, err := group.client.GetGroupRoles(group.Id) - if err != nil { - return nil, errors.Wrap(err, "GetGroupRoles") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range roles { - _, err := group.client.GetRole(roles[i].GetName()) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - continue - } - return nil, errors.Wrapf(err, "GetRole(%s)", roles[i].GetName()) - } - ret = append(ret, &roles[i]) - } - return ret, nil -} - -func (group *SCloudgroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - roles, err := group.client.GetGroupRoles(group.Id) - if err != nil { - return nil, errors.Wrap(err, "GetGroupRoles") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range roles { - _, err := group.client.GetCustomRole(roles[i].GetName()) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - continue - } - return nil, errors.Wrapf(err, "GetRole(%s)", roles[i].GetName()) - } - ret = append(ret, &roles[i]) - } - return ret, nil -} - -func (group *SCloudgroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { - users, err := group.client.GetGroupUsers(group.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.IClouduser{} - for i := range users { - users[i].client = group.client - ret = append(ret, &users[i]) - } - return ret, nil -} - -func (self *SHuaweiClient) GetGroups(domainId, name string) ([]SCloudgroup, error) { - params := map[string]string{} - if len(domainId) > 0 { - params["domain_id"] = self.ownerId - } - if len(name) > 0 { - params["name"] = name - } - - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - groups := []SCloudgroup{} - err = doListAllWithNextLink(client.Groups.List, params, &groups) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return groups, nil -} - -func (self *SHuaweiClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - groups, err := self.GetGroups("", "") - if err != nil { - return nil, errors.Wrap(err, "GetGroup") - } - ret := []cloudprovider.ICloudgroup{} - for i := range groups { - if groups[i].Name != "admin" { - groups[i].client = self - ret = append(ret, &groups[i]) - } - } - return ret, nil -} - -func (self *SHuaweiClient) GetGroupUsers(groupId string) ([]SClouduser, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - resp, err := client.Groups.ListInContextWithSpec(nil, fmt.Sprintf("%s/users", groupId), nil, "users") - if err != nil { - return nil, errors.Wrap(err, "") - } - users := []SClouduser{} - err = jsonutils.Update(&users, resp.Data) - if err != nil { - return nil, errors.Wrap(err, "jsonutils.Update") - } - return users, nil -} - -func (self *SHuaweiClient) GetGroupRoles(groupId string) ([]SRole, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - resp, err := client.Domains.ListRoles(self.ownerId, groupId) - if err != nil { - return nil, errors.Wrap(err, "ListRoles") - } - roles := []SRole{} - err = jsonutils.Update(&roles, resp.Data) - if err != nil { - return nil, errors.Wrap(err, "jsonutils.Update") - } - return roles, nil -} - -func (self *SHuaweiClient) CreateGroup(name, desc string) (*SCloudgroup, error) { - params := map[string]string{ - "name": name, - } - if len(desc) > 0 { - params["description"] = desc - } - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - group := SCloudgroup{client: self} - err = DoCreate(client.Groups.Create, jsonutils.Marshal(map[string]interface{}{"group": params}), &group) - if err != nil { - return nil, errors.Wrap(err, "DoCreate") - } - return &group, nil -} - -func (self *SHuaweiClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - group, err := self.CreateGroup(name, desc) - if err != nil { - return nil, errors.Wrap(err, "CreateGroup") - } - return group, nil -} - -func (self *SHuaweiClient) DeleteGroup(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - return DoDeleteWithSpec(client.Groups.DeleteInContextWithSpec, nil, id, "", nil, nil) -} - -func (self *SHuaweiClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - groups, err := self.GetGroups(self.ownerId, name) - if err != nil { - return nil, errors.Wrap(err, "GetGroups") - } - if len(groups) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(groups) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - groups[0].client = self - return &groups[0], nil -} - -func (self *SHuaweiClient) AddUserToGroup(groupId, userId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.Groups.UpdateInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, "") - return err -} - -func (self *SHuaweiClient) RemoveUserFromGroup(groupId, userId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.Groups.DeleteInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, nil, "") - return err -} - -func (self *SHuaweiClient) GetCustomRoles() ([]SRole, error) { - params := map[string]string{} - - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - client.Roles.SetVersion("v3.0/OS-ROLE") - defer client.Roles.SetVersion("v3.0") - - roles := []SRole{} - err = doListAllWithNextLink(client.Roles.List, params, &roles) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return roles, nil -} - -func (self *SHuaweiClient) GetCustomRole(name string) (*SRole, error) { - roles, err := self.GetCustomRoles() - if err != nil { - return nil, errors.Wrapf(err, "GetCustomRoles(%s)", name) - } - for i := range roles { - if roles[i].DisplayName == name { - return &roles[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) -} - -func (self *SHuaweiClient) GetRole(name string) (*SRole, error) { - roles, err := self.GetRoles("", "") - if err != nil { - return nil, errors.Wrapf(err, "GetRoles(%s)", name) - } - for i := range roles { - if roles[i].DisplayName == name { - return &roles[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) -} - -func (self *SHuaweiClient) DetachGroupRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - role, err := self.GetRole(roleId) - if err != nil { - return errors.Wrapf(err, "GetRole(%s)", roleId) - } - if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.AddRole(self.ownerId, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddRole") - } - if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddProjectRole") - } - } - } - if role.Type == "XA" || role.Type == "AA" { - projects, err := self.GetProjects() - if err != nil { - return errors.Wrapf(err, "GetProjects") - } - for _, project := range projects { - err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddProjectRole") - } - } - } - return nil -} - -func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - role, err := self.GetRole(roleId) - if err != nil { - return errors.Wrapf(err, "GetRole(%s)", roleId) - } - if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.AddRole(self.ownerId, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddRole") - } - if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddProjectRole") - } - } - } - if role.Type == "XA" || role.Type == "AA" { - projects, err := self.GetProjects() - if err != nil { - return errors.Wrapf(err, "GetProjects") - } - for _, project := range projects { - err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddProjectRole") - } - } - } - return nil -} - -func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - role, err := self.GetCustomRole(roleId) - if err != nil { - return errors.Wrapf(err, "GetRole(%s)", roleId) - } - if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.AddRole(self.ownerId, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddRole") - } - if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddProjectRole") - } - } - } - if role.Type == "XA" || role.Type == "AA" { - projects, err := self.GetProjects() - if err != nil { - return errors.Wrapf(err, "GetProjects") - } - for _, project := range projects { - err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "AddProjectRole") - } - } - } - return nil -} - -func (self *SHuaweiClient) DetachGroupCustomRole(groupId, roleId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - role, err := self.GetCustomRole(roleId) - if err != nil { - return errors.Wrapf(err, "GetCustomRole(%s)", roleId) - } - if role.Type == "AX" || role.Type == "AA" { - err = client.Domains.DeleteRole(self.ownerId, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "DeleteRole") - } - if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { - err = client.Projects.DeleteProjectRole(self.GetMosProjectId(), groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "DeleteProjectRole") - } - } - } - if role.Type == "XA" || role.Type == "AA" { - projects, err := self.GetProjects() - if err != nil { - return errors.Wrapf(err, "GetProjects") - } - for _, project := range projects { - err = client.Projects.DeleteProjectRole(project.ID, groupId, role.Id) - if err != nil { - return errors.Wrapf(err, "DeleteProjectRole") - } - } - } - return nil -} diff --git a/pkg/multicloud/huawei/clouduser.go b/pkg/multicloud/huawei/clouduser.go deleted file mode 100644 index e319cb1399..0000000000 --- a/pkg/multicloud/huawei/clouduser.go +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules" -) - -type SLink struct { - Next string - Previous string - Self string -} - -type SClouduser struct { - client *SHuaweiClient - - Description string - DomainId string - Enabled bool - ForceResetPwd bool - Id string - LastProjectId string - Links SLink - Name string - PasswordExpiresAt string - PwdStatus bool -} - -func (user *SClouduser) GetGlobalId() string { - return user.Id -} - -func (user *SClouduser) GetName() string { - return user.Name -} - -func (user *SClouduser) GetEmailAddr() string { - return "" -} - -func (user *SClouduser) GetInviteUrl() string { - return "" -} - -func (user *SClouduser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return []cloudprovider.ICloudpolicy{}, nil -} - -func (user *SClouduser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return []cloudprovider.ICloudpolicy{}, nil -} - -func (user *SClouduser) AttachSystemPolicy(policyType string) error { - return cloudprovider.ErrNotSupported -} - -func (user *SClouduser) AttachCustomPolicy(policyType string) error { - return cloudprovider.ErrNotSupported -} - -func (user *SClouduser) DetachSystemPolicy(policyId string) error { - return cloudprovider.ErrNotSupported -} - -func (user *SClouduser) DetachCustomPolicy(policyId string) error { - return cloudprovider.ErrNotSupported -} - -func (user *SClouduser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - groups, err := user.client.ListUserGroups(user.Id) - if err != nil { - return nil, errors.Wrap(err, "Users.ListGroups") - } - ret := []cloudprovider.ICloudgroup{} - for i := range groups { - groups[i].client = user.client - ret = append(ret, &groups[i]) - } - return ret, nil -} - -func (user *SClouduser) Delete() error { - return user.client.DeleteClouduser(user.Id) -} - -func (user *SClouduser) IsConsoleLogin() bool { - return user.Enabled == true -} - -func (user *SClouduser) ResetPassword(password string) error { - return user.client.ResetClouduserPassword(user.Id, password) -} - -func (self *SHuaweiClient) DeleteClouduser(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.Users.Delete(id) - return err -} - -func (self *SHuaweiClient) ListUserGroups(userId string) ([]SCloudgroup, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - result, err := client.Users.ListGroups(userId) - if err != nil { - return nil, errors.Wrap(err, "Users.ListGroups") - } - groups := []SCloudgroup{} - err = jsonutils.Update(&groups, result.Data) - if err != nil { - return nil, errors.Wrap(err, "jsonutils.Update") - } - return groups, nil -} - -func (self *SHuaweiClient) GetCloudusers(name string) ([]SClouduser, error) { - params := map[string]string{} - if len(name) > 0 { - params["name"] = name - } - users := []SClouduser{} - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - err = doListAllWithOffset(client.Users.List, params, &users) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return users, nil -} - -func (self *SHuaweiClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { - users, err := self.GetCloudusers("") - if err != nil { - return nil, errors.Wrap(err, "GetCloudusers") - } - iUsers := []cloudprovider.IClouduser{} - for i := range users { - if users[i].Name != self.ownerName { - users[i].client = self - iUsers = append(iUsers, &users[i]) - } - } - return iUsers, nil -} - -func (self *SHuaweiClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - users, err := self.GetCloudusers(name) - if err != nil { - return nil, errors.Wrapf(err, "GetCloudusers(%s)", name) - } - if len(users) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(users) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - users[0].client = self - return &users[0], nil -} - -func (self *SHuaweiClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - return self.CreateClouduser(conf.Name, conf.Password, conf.Desc) -} - -func (self *SHuaweiClient) CreateClouduser(name, password, desc string) (*SClouduser, error) { - params := map[string]string{ - "name": name, - "domain_id": self.ownerId, - } - if len(password) > 0 { - params["password"] = password - } - if len(desc) > 0 { - params["description"] = desc - } - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - user := SClouduser{client: self} - err = DoCreate(client.Users.Create, jsonutils.Marshal(map[string]interface{}{"user": params}), &user) - if err != nil { - ce, ok := err.(*modules.HuaweiClientError) - if ok && len(ce.Errorcode) > 0 && ce.Errorcode[0] == "1101" { - return nil, errors.Wrap(err, `IAM user name. The length is between 5 and 32. The first digit is not a number. Special characters can only contain the '_' '-' or ' '`) //https://support.huaweicloud.com/api-iam/iam_08_0015.html - } - return nil, errors.Wrap(err, "DoCreate") - } - return &user, nil -} - -func (self *SHuaweiClient) ResetClouduserPassword(id, password string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - return client.Users.ResetPassword(id, password) -} - -type SAccessKey struct { - client *SHuaweiClient - - AccessKey string `json:"access"` - Secret string `json:"secret"` - Description string `json:"description"` - Status string `json:"status"` - CreatedAt time.Time `json:"create_time"` -} - -func (self *SHuaweiClient) GetAKSK(id string) ([]cloudprovider.SAccessKey, error) { - obj, err := self.getAKSKList(id) - if err != nil { - return nil, errors.Wrap(err, "SHuaweiClient.getAKSKList") - } - aks := make([]SAccessKey, 0) - obj.Unmarshal(&aks, "credentials") - res := make([]cloudprovider.SAccessKey, len(aks)) - for i := 0; i < len(aks); i++ { - res[i].Name = aks[i].Description - res[i].AccessKey = aks[i].AccessKey - res[i].Secret = aks[i].Secret - res[i].Status = aks[i].Status - res[i].CreatedAt = aks[i].CreatedAt - } - return res, nil -} - -func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKey, error) { - params := map[string]interface{}{ - "credential": map[string]interface{}{ - "user_id": id, - "description": name, - }, - } - obj, err := self.createAKSK(params) - if err != nil { - return nil, errors.Wrap(err, "SHuaweiClient.createAKSK") - } - ak := SAccessKey{} - obj.Unmarshal(&ak, "credential") - res := cloudprovider.SAccessKey{ - Name: ak.Description, - AccessKey: ak.AccessKey, - Secret: ak.Secret, - } - return &res, nil -} - -func (self *SHuaweiClient) DeleteAKSK(accessKey string) error { - _, err := self.deleteAKSK(accessKey) - return err -} - -func (user *SClouduser) DeleteAccessKey(accessKey string) error { - return user.client.DeleteAKSK(accessKey) -} - -func (user *SClouduser) CreateAccessKey(name string) (*cloudprovider.SAccessKey, error) { - return user.client.CreateAKSK(user.Id, name) -} - -func (user *SClouduser) GetAccessKeys() ([]cloudprovider.SAccessKey, error) { - return user.client.GetAKSK(user.Id) -} diff --git a/pkg/multicloud/huawei/dbinstance.go b/pkg/multicloud/huawei/dbinstance.go deleted file mode 100644 index c1d9179370..0000000000 --- a/pkg/multicloud/huawei/dbinstance.go +++ /dev/null @@ -1,780 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "fmt" - "time" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SBackupStrategy struct { - KeepDays int - StartTime string -} - -type SDatastore struct { - Type string - Version string -} - -type SHa struct { - ReplicationMode string -} - -type SNonde struct { - AvailabilityZone string - Id string - Name string - Role string - Staus string -} - -type SVolume struct { - Size int - Type string -} - -type SRelatedInstance struct { - Id string - Type string -} - -type SDBInstance struct { - multicloud.SDBInstanceBase - multicloud.HuaweiTags - region *SRegion - - flavorCache []SDBInstanceFlavor - BackupStrategy SBackupStrategy - Created string //time.Time - Datastore SDatastore - DbUserName string - DIskEncryptionId string - FlavorRef string - Ha SHa - Id string - MaintenanceWindow string - MaxIops int - Name string - Nodes []SNonde - Port int - PrivateIps []string - PublicIps []string - Region string - RelatedInstance []SRelatedInstance - SecurityGroupId string - Status string - SubnetId string - SwitchStrategy string - TimeZone string - Type string - Updated string //time.Time - Volume SVolume - VpcId string - EnterpriseProjectId string -} - -func (region *SRegion) GetDBInstances() ([]SDBInstance, error) { - params := map[string]string{} - dbinstances := []SDBInstance{} - err := doListAllWithOffset(region.ecsClient.DBInstance.List, params, &dbinstances) - return dbinstances, err -} - -func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { - if len(instanceId) == 0 { - return nil, cloudprovider.ErrNotFound - } - instance := SDBInstance{region: region} - err := DoGet(region.ecsClient.DBInstance.Get, instanceId, nil, &instance) - return &instance, err -} - -func (rds *SDBInstance) GetName() string { - return rds.Name -} - -func (rds *SDBInstance) GetId() string { - return rds.Id -} - -func (rds *SDBInstance) GetGlobalId() string { - return rds.GetId() -} - -// 值为“BUILD”,表示实例正在创建。 -// 值为“ACTIVE”,表示实例正常。 -// 值为“FAILED”,表示实例异常。 -// 值为“FROZEN”,表示实例冻结。 -// 值为“MODIFYING”,表示实例正在扩容。 -// 值为“REBOOTING”,表示实例正在重启。 -// 值为“RESTORING”,表示实例正在恢复。 -// 值为“MODIFYING INSTANCE TYPE”,表示实例正在转主备。 -// 值为“SWITCHOVER”,表示实例正在主备切换。 -// 值为“MIGRATING”,表示实例正在迁移。 -// 值为“BACKING UP”,表示实例正在进行备份。 -// 值为“MODIFYING DATABASE PORT”,表示实例正在修改数据库端口。 -// 值为“STORAGE FULL”,表示实例磁盘空间满。 - -func (rds *SDBInstance) GetStatus() string { - switch rds.Status { - case "BUILD", "MODIFYING", "MODIFYING INSTANCE TYPE", "SWITCHOVER", "MODIFYING DATABASE PORT": - return api.DBINSTANCE_DEPLOYING - case "ACTIVE": - return api.DBINSTANCE_RUNNING - case "FAILED", "FROZEN", "STORAGE FULL": - return api.DBINSTANCE_UNKNOWN - case "REBOOTING": - return api.DBINSTANCE_REBOOTING - case "RESTORING": - return api.DBINSTANCE_RESTORING - case "MIGRATING": - return api.DBINSTANCE_MIGRATING - case "BACKING UP": - return api.DBINSTANCE_BACKING_UP - } - return rds.Status -} - -func (rds *SDBInstance) GetBillingType() string { - _, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id)) - if err != nil { - return billing_api.BILLING_TYPE_POSTPAID - } - return billing_api.BILLING_TYPE_PREPAID -} - -func (rds *SDBInstance) GetSecurityGroupIds() ([]string, error) { - return []string{rds.SecurityGroupId}, nil -} - -func (rds *SDBInstance) fetchFlavor() error { - if len(rds.flavorCache) > 0 { - return nil - } - flavors, err := rds.region.GetDBInstanceFlavors(rds.Datastore.Type, rds.Datastore.Version) - if err != nil { - return err - } - rds.flavorCache = flavors - return nil -} - -func (rds *SDBInstance) GetExpiredAt() time.Time { - order, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id)) - if err != nil { - return time.Time{} - } - return order.ExpireTime -} - -func (rds *SDBInstance) GetStorageType() string { - return rds.Volume.Type -} - -func (rds *SDBInstance) GetCreatedAt() time.Time { - t, err := time.Parse("2006-01-02T15:04:05Z0700", rds.Created) - if err != nil { - return time.Time{} - } - return t -} - -func (rds *SDBInstance) GetEngine() string { - return rds.Datastore.Type -} - -func (rds *SDBInstance) GetEngineVersion() string { - return rds.Datastore.Version -} - -func (rds *SDBInstance) GetInstanceType() string { - return rds.FlavorRef -} - -func (rds *SDBInstance) GetCategory() string { - switch rds.Type { - case "Single": - return api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE - case "Ha": - return api.HUAWEI_DBINSTANCE_CATEGORY_HA - case "Replica": - return api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA - } - return rds.Type -} - -func (rds *SDBInstance) GetVcpuCount() int { - err := rds.fetchFlavor() - if err != nil { - log.Errorf("failed to fetch flavors: %v", err) - return 0 - } - for _, flavor := range rds.flavorCache { - if flavor.SpecCode == rds.FlavorRef { - return flavor.Vcpus - } - } - return 0 -} - -func (rds *SDBInstance) GetVmemSizeMB() int { - err := rds.fetchFlavor() - if err != nil { - log.Errorf("failed to fetch flavors: %v", err) - return 0 - } - for _, flavor := range rds.flavorCache { - if flavor.SpecCode == rds.FlavorRef { - return flavor.Ram * 1024 - } - } - return 0 -} - -func (rds *SDBInstance) GetDiskSizeGB() int { - return rds.Volume.Size -} - -func (rds *SDBInstance) GetPort() int { - return rds.Port -} - -func (rds *SDBInstance) GetMaintainTime() string { - return rds.MaintenanceWindow -} - -func (rds *SDBInstance) GetIVpcId() string { - return rds.VpcId -} - -func (rds *SDBInstance) GetProjectId() string { - return rds.EnterpriseProjectId -} - -func (rds *SDBInstance) Refresh() error { - instance, err := rds.region.GetDBInstance(rds.Id) - if err != nil { - return err - } - return jsonutils.Update(rds, instance) -} - -func (rds *SDBInstance) GetZone1Id() string { - return rds.GetZoneIdByRole("master") -} - -func (rds *SDBInstance) GetZoneIdByRole(role string) string { - for _, node := range rds.Nodes { - if node.Role == role { - zone, err := rds.region.getZoneById(node.AvailabilityZone) - if err != nil { - log.Errorf("failed to found zone %s for rds %s error: %v", node.AvailabilityZone, rds.Name, err) - return "" - } - return zone.GetGlobalId() - } - } - return "" -} - -func (rds *SDBInstance) GetZone2Id() string { - return rds.GetZoneIdByRole("slave") -} - -func (rds *SDBInstance) GetZone3Id() string { - return "" -} - -func (rds *SDBInstance) GetIops() int { - return rds.MaxIops -} - -type SRdsNetwork struct { - SubnetId string - IP string -} - -func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { - ret := []cloudprovider.SDBInstanceNetwork{} - for _, ip := range rds.PrivateIps { - network := cloudprovider.SDBInstanceNetwork{ - IP: ip, - NetworkId: rds.SubnetId, - } - ret = append(ret, network) - } - return ret, nil -} - -func (rds *SDBInstance) GetInternalConnectionStr() string { - for _, ip := range rds.PrivateIps { - return ip - } - return "" -} - -func (rds *SDBInstance) GetConnectionStr() string { - for _, ip := range rds.PublicIps { - return ip - } - return "" -} - -func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { - dbinstance, err := region.GetDBInstance(instanceId) - if err != nil { - log.Errorf("failed to get dbinstance by id %s error: %v", instanceId, err) - } - return dbinstance, err -} - -func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - instances, err := region.GetDBInstances() - if err != nil { - return nil, errors.Wrapf(err, "region.GetDBInstances()") - } - idbinstances := []cloudprovider.ICloudDBInstance{} - for i := 0; i < len(instances); i++ { - instances[i].region = region - idbinstances = append(idbinstances, &instances[i]) - } - return idbinstances, nil -} - -func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { - parameters, err := rds.region.GetDBInstanceParameters(rds.Id) - if err != nil { - return nil, err - } - iparameters := []cloudprovider.ICloudDBInstanceParameter{} - for i := 0; i < len(parameters); i++ { - iparameters = append(iparameters, ¶meters[i]) - } - return iparameters, nil -} - -func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { - databases, err := rds.region.GetDBInstanceDatabases(rds.Id) - if err != nil { - return nil, errors.Wrap(err, "rds.region.GetDBInstanceDatabases(rds.Id)") - } - - idatabase := []cloudprovider.ICloudDBInstanceDatabase{} - for i := 0; i < len(databases); i++ { - databases[i].instance = rds - idatabase = append(idatabase, &databases[i]) - } - return idatabase, nil -} - -func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { - accounts, err := rds.region.GetDBInstanceAccounts(rds.Id) - if err != nil { - return nil, errors.Wrap(err, "rds.region.GetDBInstanceAccounts(rds.Id)") - } - - user := "root" - if rds.GetEngine() == api.DBINSTANCE_TYPE_SQLSERVER { - user = "rduser" - } - - accounts = append(accounts, SDBInstanceAccount{ - Name: user, - instance: rds, - }) - - iaccounts := []cloudprovider.ICloudDBInstanceAccount{} - for i := 0; i < len(accounts); i++ { - accounts[i].instance = rds - iaccounts = append(iaccounts, &accounts[i]) - } - return iaccounts, nil -} - -func (rds *SDBInstance) Delete() error { - return rds.region.DeleteDBInstance(rds.Id) -} - -func (region *SRegion) DeleteDBInstance(instanceId string) error { - _, err := region.ecsClient.DBInstance.Delete(instanceId, nil) - return err -} - -func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - zoneIds := []string{} - zones, err := region.GetIZones() - if err != nil { - return nil, err - } - for _, zone := range zones { - zoneIds = append(zoneIds, zone.GetId()) - } - - if len(desc.SecgroupIds) == 0 { - return nil, fmt.Errorf("Missing secgroupId") - } - - params := map[string]interface{}{ - "region": region.ID, - "name": desc.Name, - "datastore": map[string]string{ - "type": desc.Engine, - "version": desc.EngineVersion, - }, - "password": desc.Password, - "volume": map[string]interface{}{ - "type": desc.StorageType, - "size": desc.DiskSizeGB, - }, - "vpc_id": desc.VpcId, - "subnet_id": desc.NetworkId, - "security_group_id": desc.SecgroupIds[0], - } - - if len(desc.ProjectId) > 0 { - params["enterprise_project_id"] = desc.ProjectId - } - - if len(desc.MasterInstanceId) > 0 { - params["replica_of_id"] = desc.MasterInstanceId - delete(params, "security_group_id") - } - - if len(desc.RdsId) > 0 && len(desc.BackupId) > 0 { - params["restore_point"] = map[string]interface{}{ - "backup_id": desc.BackupId, - "instance_id": desc.RdsId, - "type": "backup", - } - } - - switch desc.Category { - case api.HUAWEI_DBINSTANCE_CATEGORY_HA: - switch desc.Engine { - case api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL: - params["ha"] = map[string]string{ - "mode": "Ha", - "replication_mode": "async", - } - case api.DBINSTANCE_TYPE_SQLSERVER: - params["ha"] = map[string]string{ - "mode": "Ha", - "replication_mode": "sync", - } - } - case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE: - case api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA: - } - - if desc.BillingCycle != nil { - periodType := "month" - periodNum := desc.BillingCycle.GetMonths() - if desc.BillingCycle.GetYears() > 0 { - periodType = "year" - periodNum = desc.BillingCycle.GetYears() - } - params["charge_info"] = map[string]interface{}{ - "charge_mode": "prePaid", - "period_type": periodType, - "period_num": periodNum, - "is_auto_renew": false, - } - } - params["flavor_ref"] = desc.InstanceType - params["availability_zone"] = desc.ZoneId - resp, err := region.ecsClient.DBInstance.Create(jsonutils.Marshal(params)) - if err != nil { - return nil, errors.Wrapf(err, "Create") - } - - instance := &SDBInstance{region: region} - err = resp.Unmarshal(instance, "instance") - if err != nil { - return nil, errors.Wrap(err, `resp.Unmarshal(&instance, "instance")`) - } - if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { - err = cloudprovider.Wait(10*time.Second, 20*time.Minute, func() (bool, error) { - job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) - if err != nil { - return false, nil - } - status, _ := job.GetString("status") - process, _ := job.GetString("process") - log.Debugf("create dbinstance job %s status: %s process: %s", jobId, status, process) - if status == "Completed" { - return true, nil - } - if status == "Failed" { - return false, fmt.Errorf("create failed") - } - return false, nil - }) - } - return instance, err -} - -func (rds *SDBInstance) Reboot() error { - return rds.region.RebootDBInstance(rds.Id) -} - -func (rds *SDBInstance) OpenPublicConnection() error { - return fmt.Errorf("Huawei current not support this operation") - //return rds.region.PublicConnectionAction(rds.Id, "openRC") -} - -func (rds *SDBInstance) ClosePublicConnection() error { - return fmt.Errorf("Huawei current not support this operation") - //return rds.region.PublicConnectionAction(rds.Id, "closeRC") -} - -func (region *SRegion) PublicConnectionAction(instanceId string, action string) error { - resp, err := region.ecsClient.DBInstance.PerformAction2(action, instanceId, nil, "") - if err != nil { - return errors.Wrapf(err, "rds.%s", action) - } - - if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { - err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { - job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) - if err != nil { - log.Errorf("failed to get job %s info error: %v", jobId, err) - return false - } - status, _ := job.GetString("status") - process, _ := job.GetString("process") - if status == "Completed" { - return true - } - log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, status, process) - return false - }) - } - - return nil - -} - -func (region *SRegion) RebootDBInstance(instanceId string) error { - params := jsonutils.Marshal(map[string]interface{}{ - "restart": map[string]string{}, - }) - resp, err := region.ecsClient.DBInstance.PerformAction2("action", instanceId, params, "") - if err != nil { - return err - } - if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { - err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { - job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) - if err != nil { - log.Errorf("failed to get job %s info error: %v", jobId, err) - return false - } - status, _ := job.GetString("status") - process, _ := job.GetString("process") - if status == "Completed" { - return true - } - log.Debugf("reboot dbinstance job %s status: %s process: %s", jobId, status, process) - return false - }) - } - return err -} - -type SDBInstanceFlavor struct { - Vcpus int - Ram int //单位GB - SpecCode string - InstanceMode string //实例模型 -} - -func (region *SRegion) GetDBInstanceFlavors(engine string, version string) ([]SDBInstanceFlavor, error) { - flavors := []SDBInstanceFlavor{} - resp, err := region.ecsClient.DBInstanceFlavor.ListInContextWithSpec(nil, engine, map[string]string{"version_name": version}, "flavors") - if err != nil { - return nil, err - } - return flavors, jsonutils.Update(&flavors, resp.Data) -} - -func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { - return rds.region.CreateDBInstanceAccount(rds.Id, conf.Name, conf.Password) -} - -func (region *SRegion) CreateDBInstanceAccount(instanceId, account, password string) error { - params := map[string]string{ - "name": account, - "password": password, - } - _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/db_user", instanceId), jsonutils.Marshal(params), "") - return err -} - -func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { - return rds.region.CreateDBInstanceDatabase(rds.Id, conf.Name, conf.CharacterSet) -} - -func (region *SRegion) CreateDBInstanceDatabase(instanceId, database, characterSet string) error { - params := map[string]string{ - "name": database, - "character_set": characterSet, - } - _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/database", instanceId), jsonutils.Marshal(params), "") - return err -} - -func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { - return rds.region.ChangeDBInstanceConfig(rds.Id, desc.InstanceType, desc.DiskSizeGB) -} - -func (region *SRegion) ChangeDBInstanceConfig(instanceId string, instanceType string, diskSizeGb int) error { - instance, err := region.GetIDBInstanceById(instanceId) - if err != nil { - return errors.Wrapf(err, "region.GetIDBInstanceById(%s)", instanceId) - } - - if len(instanceType) > 0 { - params := map[string]map[string]string{ - "resize_flavor": map[string]string{ - "spec_code": instanceType, - }, - } - _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) - if err != nil { - return errors.Wrap(err, "resize_flavor") - } - cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) - } - if diskSizeGb > 0 { - params := map[string]map[string]int{ - "enlarge_volume": map[string]int{ - "size": diskSizeGb, - }, - } - _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) - if err != nil { - return errors.Wrap(err, "enlarge_volume") - } - cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) - } - return nil -} - -func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error { - existedTags, err := self.GetTags() - if err != nil { - return errors.Wrap(err, "self.GetTags()") - } - deleteTagsKey := []string{} - for k := range existedTags { - if replace { - deleteTagsKey = append(deleteTagsKey, k) - } else { - if _, ok := tags[k]; ok { - deleteTagsKey = append(deleteTagsKey, k) - } - } - } - if len(deleteTagsKey) > 0 { - err := self.region.DeleteRdsTags(self.GetId(), deleteTagsKey) - if err != nil { - return errors.Wrapf(err, "DeleteRdsTags") - } - } - if len(tags) > 0 { - err := self.region.CreateRdsTags(self.GetId(), tags) - if err != nil { - return errors.Wrapf(err, "CreateRdsTags") - } - } - return nil -} - -func (self *SRegion) DeleteRdsTags(instanceId string, tagsKey []string) error { - params := map[string]interface{}{ - "action": "delete", - } - tagsObj := []map[string]string{} - for _, k := range tagsKey { - tagsObj = append(tagsObj, map[string]string{"key": k}) - } - params["tags"] = tagsObj - - _, err := self.ecsClient.DBInstance.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") - return err -} - -func (self *SRegion) CreateRdsTags(instanceId string, tags map[string]string) error { - params := map[string]interface{}{ - "action": "create", - } - - tagsObj := []map[string]string{} - for k, v := range tags { - tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) - } - params["tags"] = tagsObj - - _, err := self.ecsClient.DBInstance.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") - return err -} - -func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { - if len(conf.OriginDBInstanceExternalId) == 0 { - conf.OriginDBInstanceExternalId = rds.Id - } - return rds.region.RecoveryDBInstanceFromBackup(rds.Id, conf.OriginDBInstanceExternalId, conf.BackupId, conf.Databases) -} - -func (region *SRegion) RecoveryDBInstanceFromBackup(target, origin string, backupId string, databases map[string]string) error { - source := map[string]interface{}{ - "type": "backup", - "backup_id": backupId, - } - if len(origin) > 0 { - source["instance_id"] = origin - } - if len(databases) > 0 { - source["database_name"] = databases - } - params := map[string]interface{}{ - "source": source, - "target": map[string]string{ - "instance_id": target, - }, - } - _, err := region.ecsClient.DBInstance.PerformAction("", "recovery", jsonutils.Marshal(params)) - if err != nil { - return errors.Wrap(err, "dbinstance.recovery") - } - return nil -} - -func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { - return rds.region.RenewInstance(rds.Id, bc) -} diff --git a/pkg/multicloud/huawei/dbinstance_account.go b/pkg/multicloud/huawei/dbinstance_account.go deleted file mode 100644 index 15a1dedcbe..0000000000 --- a/pkg/multicloud/huawei/dbinstance_account.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceAccount struct { - multicloud.SDBInstanceAccountBase - multicloud.HuaweiTags - instance *SDBInstance - Name string -} - -func (account *SDBInstanceAccount) GetName() string { - return account.Name -} - -func (account *SDBInstanceAccount) Delete() error { - return account.instance.region.DeleteDBInstanceAccount(account.instance.Id, account.Name) -} - -func (region *SRegion) DeleteDBInstanceAccount(instanceId string, account string) error { - return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, fmt.Sprintf("db_user/%s", account), nil, nil) -} - -func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { - privileges, err := account.instance.region.GetDBInstancePrivvileges(account.instance.Id, account.Name) - if err != nil { - return nil, err - } - iprivileves := []cloudprovider.ICloudDBInstanceAccountPrivilege{} - for i := 0; i < len(privileges); i++ { - privileges[i].account = account - iprivileves = append(iprivileves, &privileges[i]) - } - return iprivileves, nil -} - -func (region *SRegion) GetDBInstanceAccounts(instanceId string) ([]SDBInstanceAccount, error) { - params := map[string]string{ - "instance_id": instanceId, - } - accounts := []SDBInstanceAccount{} - err := doListAllWithPage(region.ecsClient.DBInstance.ListAccounts, params, &accounts) - if err != nil { - return nil, err - } - return accounts, nil -} - -func (region *SRegion) GetDBInstancePrivvileges(instanceId string, username string) ([]SDatabasePrivilege, error) { - params := map[string]string{ - "instance_id": instanceId, - "user-name": username, - } - privileges := []SDatabasePrivilege{} - err := doListAllWithPage(region.ecsClient.DBInstance.ListPrivileges, params, &privileges) - if err != nil { - return nil, err - } - return privileges, nil -} - -func (account *SDBInstanceAccount) RevokePrivilege(database string) error { - return account.instance.region.RevokeDBInstancePrivilege(account.instance.Id, account.Name, database) -} - -func (region *SRegion) RevokeDBInstancePrivilege(instanceId string, account, database string) error { - params := map[string]interface{}{ - "db_name": database, - "users": []map[string]interface{}{ - map[string]interface{}{ - "name": account, - }, - }, - } - return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, "db_privilege", nil, jsonutils.Marshal(params)) -} - -func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { - return account.instance.region.GrantDBInstancePrivilege(account.instance.Id, account.Name, database, privilege) -} - -func (region *SRegion) GrantDBInstancePrivilege(instanceId string, account, database string, privilege string) error { - readonly := false - switch privilege { - case api.DATABASE_PRIVILEGE_R: - readonly = true - case api.DATABASE_PRIVILEGE_RW: - default: - return fmt.Errorf("Unknown privilege %s", privilege) - } - params := map[string]interface{}{ - "db_name": database, - "users": []map[string]interface{}{ - map[string]interface{}{ - "name": account, - "readonly": readonly, - }, - }, - } - _, err := region.ecsClient.DBInstance.PerformAction("db_privilege", instanceId, jsonutils.Marshal(params)) - return err -} - -func (account *SDBInstanceAccount) ResetPassword(password string) error { - return account.instance.region.ResetDBInstanceAccountPassword(account.instance.Id, account.Name, password) -} - -func (region *SRegion) ResetDBInstanceAccountPassword(instanceId, account, password string) error { - return fmt.Errorf("The API does not exist or has not been published in the environment") -} diff --git a/pkg/multicloud/huawei/dbinstance_backup.go b/pkg/multicloud/huawei/dbinstance_backup.go deleted file mode 100644 index 77ad059518..0000000000 --- a/pkg/multicloud/huawei/dbinstance_backup.go +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceBackup struct { - multicloud.SDBInstanceBackupBase - multicloud.HuaweiTags - region *SRegion - - BeginTime string - Datastore SDatastore - EndTime string - Id string - InstanceId string - Name string - Size int - Status string - Type string -} - -func (backup *SDBInstanceBackup) GetId() string { - return backup.Id -} - -func (backup *SDBInstanceBackup) GetGlobalId() string { - return backup.Id -} - -func (backup *SDBInstanceBackup) GetName() string { - return backup.Name -} - -func (backup *SDBInstanceBackup) GetEngine() string { - return backup.Datastore.Type -} - -func (backup *SDBInstanceBackup) GetEngineVersion() string { - return backup.Datastore.Version -} - -func (backup *SDBInstanceBackup) GetStartTime() time.Time { - //2019-08-05T08:00:02+0000 - t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.BeginTime) - if err != nil { - return time.Time{} - } - return t -} - -func (backup *SDBInstanceBackup) GetEndTime() time.Time { - t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.EndTime) - if err != nil { - return time.Time{} - } - return t -} - -func (backup *SDBInstanceBackup) GetBackupMode() string { - switch backup.Type { - case "manual": - return api.BACKUP_MODE_MANUAL - default: - return api.BACKUP_MODE_AUTOMATED - } -} - -func (backup *SDBInstanceBackup) GetStatus() string { - switch backup.Status { - case "COMPLETED": - return api.DBINSTANCE_BACKUP_READY - case "FAILED": - return api.DBINSTANCE_BACKUP_FAILED - case "BUILDING": - return api.DBINSTANCE_BACKUP_CREATING - case "DELETING": - return api.DBINSTANCE_BACKUP_DELETING - default: - return api.DBINSTANCE_BACKUP_UNKNOWN - } -} - -func (backup *SDBInstanceBackup) GetBackupSizeMb() int { - return backup.Size / 1024 -} - -func (backup *SDBInstanceBackup) GetDBNames() string { - return "" -} - -func (backup *SDBInstanceBackup) Delete() error { - return backup.region.DeleteDBInstanceBackup(backup.Id) -} - -func (region *SRegion) DeleteDBInstanceBackup(backupId string) error { - _, err := region.ecsClient.DBInstanceBackup.Delete(backupId, nil) - return err -} - -func (backup *SDBInstanceBackup) GetDBInstanceId() string { - return backup.InstanceId -} - -func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string) ([]SDBInstanceBackup, error) { - params := map[string]string{ - "instance_id": instanceId, - } - if len(backupId) > 0 { - params["backup_id"] = backupId - } - backups := []SDBInstanceBackup{} - err := doListAllWithOffset(region.ecsClient.DBInstanceBackup.List, params, &backups) - if err != nil { - return nil, err - } - return backups, nil -} - -func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - dbinstnaces, err := region.GetIDBInstances() - if err != nil { - return nil, err - } - ibackups := []cloudprovider.ICloudDBInstanceBackup{} - for i := 0; i < len(dbinstnaces); i++ { - _dbinstance := dbinstnaces[i].(*SDBInstance) - _ibackup, err := _dbinstance.GetIDBInstanceBackups() - if err != nil { - return nil, errors.Wrapf(err, "_dbinstance(%v).GetIDBInstanceBackups", _dbinstance) - } - ibackups = append(ibackups, _ibackup...) - } - return ibackups, nil -} - -func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { - backups, err := region.GetIDBInstanceBackups() - if err != nil { - return nil, errors.Wrap(err, "region.GetIDBInstanceBackups") - } - for _, backup := range backups { - if backup.GetGlobalId() == backupId { - return backup, nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - backups, err := rds.region.GetDBInstanceBackups(rds.Id, "") - if err != nil { - return nil, err - } - - ibackups := []cloudprovider.ICloudDBInstanceBackup{} - for i := 0; i < len(backups); i++ { - backups[i].region = rds.region - ibackups = append(ibackups, &backups[i]) - } - return ibackups, nil -} - -func (backup *SDBInstanceBackup) Refresh() error { - backups, err := backup.region.GetDBInstanceBackups(backup.InstanceId, backup.Id) - if err != nil { - return err - } - if len(backups) == 0 { - return cloudprovider.ErrNotFound - } - return jsonutils.Update(backup, backups[0]) -} - -func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { - backupId, err := rds.region.CreateDBInstanceBackup(rds.Id, conf.Name, conf.Description, conf.Databases) - if err != nil { - return "", err - } - backup, err := rds.region.GetIDBInstanceBackupById(backupId) - if err != nil { - return "", errors.Wrap(err, "region.GetIDBInstanceBackupById") - } - cloudprovider.WaitStatus(backup, api.DBINSTANCE_BACKUP_READY, time.Second*3, time.Minute*30) - return backupId, nil -} - -func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, descrition string, databases []string) (string, error) { - params := map[string]interface{}{ - "instance_id": instanceId, - "name": name, - "description": descrition, - } - if len(databases) > 0 { - dbs := []map[string]string{} - for _, database := range databases { - dbs = append(dbs, map[string]string{"name": database}) - } - params["databases"] = dbs - } - resp, err := region.ecsClient.DBInstanceBackup.Create(jsonutils.Marshal(params)) - if err != nil { - return "", errors.Wrap(err, "DBInstanceBackup.Create") - } - backupId, err := resp.GetString("id") - if err != nil { - return "", errors.Wrap(err, "resp.GetBackupId") - } - return backupId, nil -} - -func (self *SDBInstanceBackup) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - opts.BackupId = self.Id - return self.region.CreateIDBInstance(opts) -} diff --git a/pkg/multicloud/huawei/dbinstance_database.go b/pkg/multicloud/huawei/dbinstance_database.go deleted file mode 100644 index 4313ab32f9..0000000000 --- a/pkg/multicloud/huawei/dbinstance_database.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstanceDatabase struct { - instance *SDBInstance - multicloud.SDBInstanceDatabaseBase - multicloud.HuaweiTags - - Name string - CharacterSet string -} - -func (database *SDBInstanceDatabase) GetId() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetGlobalId() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetName() string { - return database.Name -} - -func (database *SDBInstanceDatabase) GetStatus() string { - return api.DBINSTANCE_DATABASE_RUNNING -} - -func (database *SDBInstanceDatabase) GetCharacterSet() string { - return database.CharacterSet -} - -func (database *SDBInstanceDatabase) Delete() error { - return database.instance.region.DeleteDBInstanceDatabase(database.instance.Id, database.Name) -} - -func (region *SRegion) DeleteDBInstanceDatabase(instanceId, database string) error { - _, err := region.ecsClient.DBInstance.DeleteInContextWithSpec(nil, instanceId, fmt.Sprintf("database/%s", database), nil, nil, "") - return err -} - -func (region *SRegion) GetDBInstanceDatabases(instanceId string) ([]SDBInstanceDatabase, error) { - params := map[string]string{ - "instance_id": instanceId, - } - databases := []SDBInstanceDatabase{} - err := doListAllWithPage(region.ecsClient.DBInstance.ListDatabases, params, &databases) - if err != nil { - return nil, err - } - return databases, nil -} diff --git a/pkg/multicloud/huawei/dbinstance_privilege.go b/pkg/multicloud/huawei/dbinstance_privilege.go deleted file mode 100644 index fcab4995c9..0000000000 --- a/pkg/multicloud/huawei/dbinstance_privilege.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" -) - -type SDatabasePrivilege struct { - account *SDBInstanceAccount - - Name string - Readonly bool -} - -func (privilege *SDatabasePrivilege) GetGlobalId() string { - return fmt.Sprintf("%s/%s", privilege.account.Name, privilege.Name) -} - -func (privilege *SDatabasePrivilege) GetPrivilege() string { - if privilege.Readonly { - return api.DATABASE_PRIVILEGE_R - } - return api.DATABASE_PRIVILEGE_RW -} - -func (privilege *SDatabasePrivilege) GetDBName() string { - return privilege.Name -} diff --git a/pkg/multicloud/huawei/disk.go b/pkg/multicloud/huawei/disk.go deleted file mode 100644 index 7e9f2f65ca..0000000000 --- a/pkg/multicloud/huawei/disk.go +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -/* -华为云云硬盘 -======创建========== -1.磁盘只能挂载到同一可用区的云服务器内,创建后不支持更换可用区 -2.计费模式 包年包月/按需计费 -3.*支持自动备份 - - -共享盘 和 普通盘:https://support.huaweicloud.com/productdesc-evs/zh-cn_topic_0032860759.html -根据是否支持挂载至多台云服务器可以将云硬盘分为非共享云硬盘和共享云硬盘。 -一个非共享云硬盘只能挂载至一台云服务器,而一个共享云硬盘可以同时挂载至多台云服务器。 -单个共享云硬盘最多可同时挂载给16个云服务器。目前,共享云硬盘只适用于数据盘,不支持系统盘。 -*/ - -type Attachment struct { - ServerID string `json:"server_id"` - AttachmentID string `json:"attachment_id"` - AttachedAt string `json:"attached_at"` - HostName string `json:"host_name"` - VolumeID string `json:"volume_id"` - Device string `json:"device"` - ID string `json:"id"` -} - -type DiskMeta struct { - ResourceSpecCode string `json:"resourceSpecCode"` - Billing string `json:"billing"` - ResourceType string `json:"resourceType"` - AttachedMode string `json:"attached_mode"` - Readonly string `json:"readonly"` -} - -type VolumeImageMetadata struct { - QuickStart string `json:"__quick_start"` - ContainerFormat string `json:"container_format"` - MinRAM string `json:"min_ram"` - ImageName string `json:"image_name"` - ImageID string `json:"image_id"` - OSType string `json:"__os_type"` - OSFeatureList string `json:"__os_feature_list"` - MinDisk string `json:"min_disk"` - SupportKVM string `json:"__support_kvm"` - VirtualEnvType string `json:"virtual_env_type"` - SizeGB string `json:"size"` - OSVersion string `json:"__os_version"` - OSBit string `json:"__os_bit"` - SupportKVMHi1822Hiovs string `json:"__support_kvm_hi1822_hiovs"` - SupportXen string `json:"__support_xen"` - Description string `json:"__description"` - Imagetype string `json:"__imagetype"` - DiskFormat string `json:"disk_format"` - ImageSourceType string `json:"__image_source_type"` - Checksum string `json:"checksum"` - Isregistered string `json:"__isregistered"` - HwVifMultiqueueEnabled string `json:"hw_vif_multiqueue_enabled"` - Platform string `json:"__platform"` -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0124881427.html -type SDisk struct { - storage *SStorage - multicloud.SDisk - multicloud.HuaweiDiskTags - details *SResourceDetail - - ID string `json:"id"` - Name string `json:"name"` - Status string `json:"status"` - Attachments []Attachment `json:"attachments"` - Description string `json:"description"` - SizeGB int `json:"size"` - Metadata DiskMeta `json:"metadata"` - Encrypted bool `json:"encrypted"` - Bootable string `json:"bootable"` - Multiattach bool `json:"multiattach"` - AvailabilityZone string `json:"availability_zone"` - SourceVolid string `json:"source_volid"` - SnapshotID string `json:"snapshot_id"` - CreatedAt time.Time `json:"created_at"` - VolumeType string `json:"volume_type"` - VolumeImageMetadata VolumeImageMetadata `json:"volume_image_metadata"` - ReplicationStatus string `json:"replication_status"` - UserID string `json:"user_id"` - ConsistencygroupID string `json:"consistencygroup_id"` - UpdatedAt string `json:"updated_at"` - EnterpriseProjectId string - - ExpiredTime time.Time -} - -func (self *SDisk) GetId() string { - return self.ID -} - -func (self *SDisk) GetName() string { - if len(self.Name) == 0 { - return self.ID - } - - return self.Name -} - -func (self *SDisk) GetGlobalId() string { - return self.ID -} - -func (self *SDisk) GetStatus() string { - // https://support.huaweicloud.com/api-evs/zh-cn_topic_0051803385.html - switch self.Status { - case "creating", "downloading": - return api.DISK_ALLOCATING - case "available", "in-use": - return api.DISK_READY - case "error": - return api.DISK_ALLOC_FAILED - case "attaching": - return api.DISK_ATTACHING - case "detaching": - return api.DISK_DETACHING - case "restoring-backup": - return api.DISK_REBUILD - case "backing-up": - return api.DISK_BACKUP_STARTALLOC // ? - case "error_restoring": - return api.DISK_BACKUP_ALLOC_FAILED - case "uploading": - return api.DISK_SAVING //? - case "extending": - return api.DISK_RESIZING - case "error_extending": - return api.DISK_ALLOC_FAILED // ? - case "deleting": - return api.DISK_DEALLOC //? - case "error_deleting": - return api.DISK_DEALLOC_FAILED // ? - case "rollbacking": - return api.DISK_REBUILD - case "error_rollbacking": - return api.DISK_UNKNOWN - default: - return api.DISK_UNKNOWN - } -} - -func (self *SDisk) Refresh() error { - new, err := self.storage.zone.region.GetDisk(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SDisk) IsEmulated() bool { - return false -} - -func (self *SDisk) getResourceDetails() *SResourceDetail { - if self.details != nil { - return self.details - } - - res, err := self.storage.zone.region.GetOrderResourceDetail(self.GetId()) - if err != nil { - log.Debugln(err) - return nil - } - - self.details = &res - return self.details -} - -func (self *SDisk) GetBillingType() string { - details := self.getResourceDetails() - if details == nil { - return billing_api.BILLING_TYPE_POSTPAID - } else { - return billing_api.BILLING_TYPE_PREPAID - } -} - -func (self *SDisk) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SDisk) GetExpiredAt() time.Time { - var expiredTime time.Time - details := self.getResourceDetails() - if details != nil { - expiredTime = details.ExpireTime - } - - return expiredTime -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.storage, nil -} - -func (self *SDisk) GetDiskFormat() string { - // self.volume_type ? - return "vhd" -} - -func (self *SDisk) GetDiskSizeMB() int { - return int(self.SizeGB * 1024) -} - -func (self *SDisk) checkAutoDelete(attachments []Attachment) bool { - autodelete := false - for _, attach := range attachments { - if len(attach.ServerID) > 0 { - // todo : 忽略错误?? - vm, err := self.storage.zone.region.GetInstanceByID(attach.ServerID) - if err != nil { - volumes := vm.OSExtendedVolumesVolumesAttached - for _, vol := range volumes { - if vol.ID == self.ID && strings.ToLower(vol.DeleteOnTermination) == "true" { - autodelete = true - } - } - } - - break - } - } - - return autodelete -} - -func (self *SDisk) GetIsAutoDelete() bool { - if len(self.Attachments) > 0 { - return self.checkAutoDelete(self.Attachments) - } - - return false -} - -func (self *SDisk) GetTemplateId() string { - return self.VolumeImageMetadata.ImageID -} - -// Bootable 表示硬盘是否为启动盘。 -// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) -func (self *SDisk) GetDiskType() string { - if self.Bootable == "true" { - return api.DISK_TYPE_SYS - } else { - return api.DISK_TYPE_DATA - } -} - -func (self *SDisk) GetFsFormat() string { - return "" -} - -func (self *SDisk) GetIsNonPersistent() bool { - return false -} - -func (self *SDisk) GetDriver() string { - // https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762431.html - // scsi or vbd? - // todo: implement me - return "scsi" -} - -func (self *SDisk) GetCacheMode() string { - return "none" -} - -func (self *SDisk) GetMountpoint() string { - if len(self.Attachments) > 0 { - return self.Attachments[0].Device - } - - return "" -} - -func (self *SDisk) GetMountServerId() string { - if len(self.Attachments) > 0 { - return self.Attachments[0].ServerID - } - - return "" -} - -func (self *SDisk) GetAccessPath() string { - return "" -} - -func (self *SDisk) Delete(ctx context.Context) error { - disk, err := self.storage.zone.region.GetDisk(self.GetId()) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return err - } - if disk.Status != "deleting" { - // 等待硬盘ready - cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 60*time.Second) - err := self.storage.zone.region.DeleteDisk(self.GetId()) - if err != nil { - return err - } - } - - return cloudprovider.WaitDeleted(self, 10*time.Second, 120*time.Second) -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - if snapshotId, err := self.storage.zone.region.CreateSnapshot(self.GetId(), 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, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil { - return nil, err - } - return snapshot, nil - } -} - -func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) { - snapshot, err := self.storage.zone.region.GetSnapshotById(snapshotId) - return &snapshot, err -} - -func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := self.getSnapshot(snapshotId) - return snapshot, err -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := self.storage.zone.region.GetSnapshots(self.ID, "") - if err != nil { - return nil, err - } - - isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) - for i := 0; i < len(snapshots); i++ { - isnapshots[i] = &snapshots[i] - } - return isnapshots, nil -} - -func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { - err := cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 60*time.Second) - if err != nil { - return err - } - - sizeGb := newSizeMB / 1024 - err = self.storage.zone.region.resizeDisk(self.GetId(), sizeGb) - if err != nil { - return err - } - - return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 15*time.Second, 5*time.Second, 60*time.Second) -} - -func (self *SDisk) Detach() error { - err := self.storage.zone.region.DetachDisk(self.GetMountServerId(), self.GetId()) - if err != nil { - log.Debugf("detach server %s disk %s failed: %s", self.GetMountServerId(), self.GetId(), err) - return err - } - - return cloudprovider.WaitCreated(5*time.Second, 60*time.Second, func() bool { - err := self.Refresh() - if err != nil { - log.Debugln(err) - return false - } - - if self.Status == "available" { - return true - } - - return false - }) -} - -func (self *SDisk) Attach(device string) error { - err := self.storage.zone.region.AttachDisk(self.GetMountServerId(), self.GetId(), device) - if err != nil { - log.Debugf("attach server %s disk %s failed: %s", self.GetMountServerId(), self.GetId(), err) - return err - } - - return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 10*time.Second, 5*time.Second, 60*time.Second) -} - -// 在线卸载磁盘 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0036046828.html -// 对于挂载在系统盘盘位(也就是“/dev/sda”或“/dev/vda”挂载点)上的磁盘,当前仅支持离线卸载 -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - mountpoint := self.GetMountpoint() - if len(mountpoint) > 0 { - err := self.Detach() - if err != nil { - return "", err - } - } - - diskId, err := self.storage.zone.region.resetDisk(self.GetId(), snapshotId) - if err != nil { - return diskId, err - } - - err = cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 300*time.Second) - if err != nil { - return "", err - } - - if len(mountpoint) > 0 { - err := self.Attach(mountpoint) - if err != nil { - return "", err - } - } - - return diskId, nil -} - -// 华为云不支持重置 -func (self *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { - if len(diskId) == 0 { - return nil, cloudprovider.ErrNotFound - } - var disk SDisk - err := DoGet(self.ecsClient.Disks.Get, diskId, nil, &disk) - return &disk, err -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762430.html -func (self *SRegion) GetDisks(zoneId string) ([]SDisk, error) { - queries := map[string]string{} - if len(zoneId) > 0 { - queries["availability_zone"] = zoneId - } - - disks := make([]SDisk, 0) - err := doListAllWithOffset(self.ecsClient.Disks.List, queries, &disks) - return disks, err -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html -func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, snapshotId string, desc string, projectId string) (string, error) { - params := jsonutils.NewDict() - volumeObj := jsonutils.NewDict() - volumeObj.Add(jsonutils.NewString(name), "name") - volumeObj.Add(jsonutils.NewString(zoneId), "availability_zone") - volumeObj.Add(jsonutils.NewString(desc), "description") - volumeObj.Add(jsonutils.NewString(category), "volume_type") - volumeObj.Add(jsonutils.NewInt(int64(sizeGb)), "size") - if len(snapshotId) > 0 { - volumeObj.Add(jsonutils.NewString(snapshotId), "snapshot_id") - } - if len(projectId) > 0 { - volumeObj.Add(jsonutils.NewString(projectId), "enterprise_project_id") - } - - params.Add(volumeObj, "volume") - // 目前只支持创建按需资源,返回job id。 如果创建包年包月资源则返回order id - _id, err := self.ecsClient.Disks.AsyncCreate(params) - if err != nil { - log.Debugf("AsyncCreate with params: %s", params) - return "", errors.Wrap(err, "AsyncCreate") - } - - // 按需计费 - volumeId, err := self.GetTaskEntityID(self.ecsClient.Disks.ServiceType(), _id, "volume_id") - if err != nil { - return "", errors.Wrap(err, "GetAllSubTaskEntityIDs") - } - - if len(volumeId) == 0 { - return "", errors.Errorf("CreateInstance job %s result is emtpy", _id) - } else { - return volumeId, nil - } -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762428.html -// 默认删除云硬盘关联的所有快照 -func (self *SRegion) DeleteDisk(diskId string) error { - return DoDeleteWithSpec(self.ecsClient.Disks.DeleteInContextWithSpec, nil, diskId, "", nil, nil) -} - -/* -扩容状态为available的云硬盘时,没有约束限制。 -扩容状态为in-use的云硬盘时,有以下约束: -不支持共享云硬盘,即multiattach参数值必须为false。 -云硬盘所挂载的云服务器状态必须为ACTIVE、PAUSED、SUSPENDED、SHUTOFF才支持扩容 -*/ -func (self *SRegion) resizeDisk(diskId string, sizeGB int64) error { - params := jsonutils.NewDict() - osExtendObj := jsonutils.NewDict() - osExtendObj.Add(jsonutils.NewInt(sizeGB), "new_size") // GB - params.Add(osExtendObj, "os-extend") - _, err := self.ecsClient.Disks.PerformAction2("action", diskId, params, "") - return err -} - -/* -https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html -只支持快照回滚到源云硬盘,不支持快照回滚到其它指定云硬盘。 -只有云硬盘状态处于“available”或“error_rollbacking”状态才允许快照回滚到源云硬盘。 -*/ -func (self *SRegion) resetDisk(diskId, snapshotId string) (string, error) { - params := jsonutils.NewDict() - rollbackObj := jsonutils.NewDict() - rollbackObj.Add(jsonutils.NewString(diskId), "volume_id") - params.Add(rollbackObj, "rollback") - _, err := self.ecsClient.OsSnapshots.PerformAction2("rollback", snapshotId, params, "") - return diskId, err -} - -func (self *SDisk) GetProjectId() string { - return self.EnterpriseProjectId -} diff --git a/pkg/multicloud/huawei/doc.go b/pkg/multicloud/huawei/doc.go deleted file mode 100644 index fad6a2ea8e..0000000000 --- a/pkg/multicloud/huawei/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei // import "yunion.io/x/onecloud/pkg/multicloud/huawei" diff --git a/pkg/multicloud/huawei/eip.go b/pkg/multicloud/huawei/eip.go deleted file mode 100644 index fdf0b65822..0000000000 --- a/pkg/multicloud/huawei/eip.go +++ /dev/null @@ -1,396 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type TInternetChargeType string - -const ( - InternetChargeByTraffic = TInternetChargeType("traffic") - InternetChargeByBandwidth = TInternetChargeType("bandwidth") -) - -type Bandwidth struct { - ID string `json:"id"` - Name string `json:"name"` - Size int64 `json:"size"` - ShareType string `json:"share_type"` - PublicipInfo []PublicipInfo `json:"publicip_info"` - TenantID string `json:"tenant_id"` - BandwidthType string `json:"bandwidth_type"` - ChargeMode string `json:"charge_mode"` - BillingInfo string `json:"billing_info"` - EnterpriseProjectID string `json:"enterprise_project_id"` -} - -type PublicipInfo struct { - PublicipID string `json:"publicip_id"` - PublicipAddress string `json:"publicip_address"` - PublicipType string `json:"publicip_type"` - IPVersion int64 `json:"ip_version"` -} - -type SProfile struct { - UserID string `json:"user_id"` - ProductID string `json:"product_id"` - RegionID string `json:"region_id"` - OrderID string `json:"order_id"` -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html -type SEipAddress struct { - region *SRegion - port *Port - multicloud.SEipBase - multicloud.HuaweiTags - - Alias string - ID string `json:"id"` - Status string `json:"status"` - Profile *SProfile `json:"profile,omitempty"` - Type string `json:"type"` - PublicIPAddress string `json:"public_ip_address"` - PrivateIPAddress string `json:"private_ip_address"` - TenantID string `json:"tenant_id"` - CreateTime time.Time `json:"create_time"` - BandwidthID string `json:"bandwidth_id"` - BandwidthShareType string `json:"bandwidth_share_type"` - BandwidthSize int64 `json:"bandwidth_size"` - BandwidthName string `json:"bandwidth_name"` - EnterpriseProjectID string `json:"enterprise_project_id"` - IPVersion int64 `json:"ip_version"` - PortId string `json:"port_id"` - EnterpriseProjectId string -} - -func (self *SEipAddress) GetId() string { - return self.ID -} - -func (self *SEipAddress) GetName() string { - if len(self.Alias) > 0 { - return self.Alias - } - return self.PublicIPAddress -} - -func (self *SEipAddress) GetGlobalId() string { - return self.ID -} - -func (self *SEipAddress) GetStatus() string { - // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html - switch self.Status { - case "ACTIVE", "DOWN", "ELB": - return api.EIP_STATUS_READY - case "PENDING_CREATE", "NOTIFYING": - return api.EIP_STATUS_ALLOCATE - case "BINDING": - return api.EIP_STATUS_ALLOCATE - case "BIND_ERROR": - return api.EIP_STATUS_ALLOCATE_FAIL - case "PENDING_DELETE", "NOTIFY_DELETE": - return api.EIP_STATUS_DEALLOCATE - default: - return api.EIP_STATUS_UNKNOWN - } -} - -func (self *SEipAddress) Refresh() error { - if self.IsEmulated() { - return nil - } - new, err := self.region.GetEip(self.ID) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SEipAddress) IsEmulated() bool { - return false -} - -func (self *SEipAddress) GetIpAddr() string { - return self.PublicIPAddress -} - -func (self *SEipAddress) GetMode() string { - return api.EIP_MODE_STANDALONE_EIP -} - -func (self *SEipAddress) GetPort() *Port { - if len(self.PortId) == 0 { - return nil - } - - if self.port != nil { - return self.port - } - - port, err := self.region.GetPort(self.PortId) - if err != nil { - return nil - } else { - self.port = &port - } - - return self.port -} - -func (self *SEipAddress) GetAssociationType() string { - if len(self.PortId) == 0 { - return "" - } - port, err := self.region.GetPort(self.PortId) - if err != nil { - log.Errorf("Get eip %s port %s error: %v", self.ID, self.PortId, err) - return "" - } - - if strings.HasPrefix(port.DeviceOwner, "compute") { - return api.EIP_ASSOCIATE_TYPE_SERVER - } - - switch port.DeviceOwner { - case "neutron:LOADBALANCER", "neutron:LOADBALANCERV2": - return api.EIP_ASSOCIATE_TYPE_LOADBALANCER - case "network:nat_gateway": - return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY - default: - return port.DeviceOwner - } -} - -func (self *SEipAddress) GetAssociationExternalId() string { - // network/0273a359d61847fc83405926c958c746/ext-floatingips?tenantId=0273a359d61847fc83405926c958c746&limit=2000 - // 只能通过 port id 反查device id. - if len(self.PortId) > 0 { - port, _ := self.region.GetPort(self.PortId) - return port.DeviceID - } - return "" -} - -func (self *SEipAddress) GetBandwidth() int { - return int(self.BandwidthSize) // Mb -} - -func (self *SEipAddress) GetINetworkId() string { - return "" -} - -func (self *SEipAddress) GetInternetChargeType() string { - // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090603.html - bandwidth, err := self.region.GetEipBandwidth(self.BandwidthID) - if err != nil { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - } - if bandwidth.ChargeMode == "traffic" { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - } - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH -} - -func (self *SEipAddress) GetBillingType() string { - if self.Profile == nil { - return billing_api.BILLING_TYPE_POSTPAID - } - return billing_api.BILLING_TYPE_PREPAID -} - -func (self *SEipAddress) GetCreatedAt() time.Time { - return self.CreateTime -} - -func (self *SEipAddress) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SEipAddress) Delete() error { - return self.region.DeallocateEIP(self.ID) -} - -func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { - portId, err := self.region.GetInstancePortId(conf.InstanceId) - if err != nil { - return err - } - - if len(self.PortId) > 0 { - if self.PortId == portId { - return nil - } - - return fmt.Errorf("eip %s aready associate with port %s", self.GetId(), self.PortId) - } - - err = self.region.AssociateEipWithPortId(self.ID, portId) - if err != nil { - return err - } - - err = cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 10*time.Second, 10*time.Second, 180*time.Second) - return err -} - -func (self *SEipAddress) Dissociate() error { - err := self.region.DissociateEip(self.ID) - if err != nil { - return err - } - return cloudprovider.WaitStatus(self, api.EIP_STATUS_READY, 10*time.Second, 180*time.Second) -} - -func (self *SEipAddress) ChangeBandwidth(bw int) error { - return self.region.UpdateEipBandwidth(self.BandwidthID, bw) -} - -func (self *SRegion) GetInstancePortId(instanceId string) (string, error) { - // 目前只绑定一个网卡 - // todo: 还需要按照ports状态进行过滤 - ports, err := self.GetPorts(instanceId) - if err != nil { - return "", err - } - - if len(ports) == 0 { - return "", fmt.Errorf("AssociateEip instance %s port is empty", instanceId) - } - - return ports[0].ID, nil -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html -func (self *SRegion) AllocateEIP(name string, bwMbps int, chargeType TInternetChargeType, bgpType string, projectId string) (*SEipAddress, error) { - params := map[string]interface{}{ - "bandwidth": map[string]interface{}{ - "name": name, - "size": bwMbps, - "share_type": "PER", - "charge_mode": chargeType, - }, - "publicip": map[string]interface{}{ - "type": bgpType, - "ip_version": 4, - "alias": name, - }, - } - if len(projectId) > 0 { - params["enterprise_project_id"] = projectId - } - resp, err := self.vpcCreate("publicips", params) - if err != nil { - return nil, err - } - eip := &SEipAddress{region: self} - return eip, resp.Unmarshal(eip, "publicip") -} - -func (self *SRegion) GetEip(eipId string) (*SEipAddress, error) { - resp, err := self.vpcGet("publicips/" + eipId) - if err != nil { - return nil, err - } - eip := &SEipAddress{region: self} - return eip, resp.Unmarshal(eip, "publicip") -} - -func (self *SRegion) DeallocateEIP(eipId string) error { - _, err := self.vpcDelete("publicips/" + eipId) - return err -} - -func (self *SRegion) AssociateEip(eipId string, instanceId string) error { - portId, err := self.GetInstancePortId(instanceId) - if err != nil { - return err - } - return self.AssociateEipWithPortId(eipId, portId) -} - -func (self *SRegion) AssociateEipWithPortId(eipId string, portId string) error { - params := map[string]interface{}{ - "publicip": map[string]interface{}{ - "port_id": portId, - }, - } - _, err := self.vpcUpdate("publicips/"+eipId, params) - return err -} - -func (self *SRegion) DissociateEip(eipId string) error { - return self.AssociateEipWithPortId(eipId, "") -} - -func (self *SRegion) UpdateEipBandwidth(bandwidthId string, bw int) error { - params := map[string]interface{}{ - "bandwidth": map[string]interface{}{ - "size": bw, - }, - } - _, err := self.vpcUpdate("bandwidths/"+bandwidthId, params) - return err -} - -func (self *SRegion) GetEipBandwidth(id string) (*Bandwidth, error) { - resp, err := self.vpcGet("bandwidths/" + id) - if err != nil { - return nil, err - } - ret := &Bandwidth{} - return ret, resp.Unmarshal(ret, "bandwidth") -} - -func (self *SEipAddress) GetProjectId() string { - return self.EnterpriseProjectId -} - -func (self *SRegion) GetEips(portId string, addrs []string) ([]SEipAddress, error) { - query := url.Values{} - for _, addr := range addrs { - query.Add("public_ip_address", addr) - } - if len(portId) > 0 { - query.Set("port_id", portId) - } - resp, err := self.vpcList("publicips", query) - if err != nil { - return nil, err - } - eips := []SEipAddress{} - err = resp.Unmarshal(&eips, "publicips") - if err != nil { - return nil, err - } - for i := range eips { - eips[i].region = self - } - return eips, nil -} diff --git a/pkg/multicloud/huawei/elasticcache_account.go b/pkg/multicloud/huawei/elasticcache_account.go deleted file mode 100644 index e246cffe5c..0000000000 --- a/pkg/multicloud/huawei/elasticcache_account.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElasticcacheAccount struct { - multicloud.SElasticcacheAccountBase - multicloud.HuaweiTags - - cacheDB *SElasticcache -} - -func (self *SElasticcacheAccount) GetId() string { - return fmt.Sprintf("%s/root", self.cacheDB.InstanceID) -} - -func (self *SElasticcacheAccount) GetName() string { - if len(self.cacheDB.AccessUser) > 0 { - return self.cacheDB.AccessUser - } - - return "root" -} - -func (self *SElasticcacheAccount) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheAccount) GetStatus() string { - return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE -} - -func (self *SElasticcacheAccount) GetAccountType() string { - return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN -} - -func (self *SElasticcacheAccount) GetAccountPrivilege() string { - return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html -// 未找到关闭密码的开放api, 不支持开启/关闭密码访问 -// https://console.huaweicloud.com/dcs/rest/v2/41f6bfe48d7f4455b7754f7c1b11ae34/instances/26db46e2-c7d8-4b5e-bd36-b5278d2fe17c/password/reset -// new_password: "26db46e2!" -// no_password_access: false -func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { - if input.OldPassword == nil { - return fmt.Errorf("elasticcacheAccount.ResetPassword.input OldPassword should not be empty") - } - - type ResetPasswordResult struct { - Result string `json:"result"` - Message string `json:"message"` - } - - result := ResetPasswordResult{} - params := jsonutils.NewDict() - params.Set("old_password", jsonutils.NewString(*input.OldPassword)) - params.Set("new_password", jsonutils.NewString(input.NewPassword)) - err := DoUpdateWithSpec2(self.cacheDB.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.cacheDB.GetId(), "password", params, &result) - if err != nil { - return errors.Wrap(err, "elasticcacheAccount.ResetPassword") - } - - if result.Result != "success" { - return errors.Wrap(fmt.Errorf(result.Message), "elasticcacheAccount.ResetPassword") - } - - return nil -} - -func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { - if input.Password != nil { - inputPassword := cloudprovider.SCloudElasticCacheAccountResetPasswordInput{} - inputPassword.NewPassword = *input.Password - inputPassword.OldPassword = input.OldPassword - inputPassword.NoPasswordAccess = input.NoPasswordAccess - return self.ResetPassword(inputPassword) - } - - return nil -} - -func (self *SElasticcacheAccount) Delete() error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/huawei/elasticcache_backup.go b/pkg/multicloud/huawei/elasticcache_backup.go deleted file mode 100644 index 6af0c6a593..0000000000 --- a/pkg/multicloud/huawei/elasticcache_backup.go +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html -type SElasticcacheBackup struct { - multicloud.SElasticcacheBackupBase - multicloud.HuaweiTags - - cacheDB *SElasticcache - - Status string `json:"status"` - Remark string `json:"remark"` - Period string `json:"period"` - Progress string `json:"progress"` - SizeByte int64 `json:"size"` - InstanceID string `json:"instance_id"` - BackupID string `json:"backup_id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - ExecutionAt time.Time `json:"execution_at"` - BackupType string `json:"backup_type"` - BackupName string `json:"backup_name"` - ErrorCode string `json:"error_code"` - IsSupportRestore string `json:"is_support_restore"` -} - -func (self *SElasticcacheBackup) GetId() string { - return self.BackupID -} - -func (self *SElasticcacheBackup) GetName() string { - return self.BackupName -} - -func (self *SElasticcacheBackup) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheBackup) Refresh() error { - cache, err := self.cacheDB.GetICloudElasticcacheBackup(self.GetId()) - if err != nil { - return errors.Wrap(err, "ElasticcacheBackup.Refresh.GetICloudElasticcacheBackup") - } - - err = jsonutils.Update(self, cache) - if err != nil { - return errors.Wrap(err, "ElasticcacheBackup.Refresh.Update") - } - - return nil -} - -func (self *SElasticcacheBackup) GetStatus() string { - switch self.Status { - case "waiting", "backuping": - return api.ELASTIC_CACHE_BACKUP_STATUS_CREATING - case "succeed": - return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS - case "failed": - return api.ELASTIC_CACHE_BACKUP_STATUS_FAILED - case "expired": - return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_EXPIRED - case "deleted": - return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_DELETED - default: - return self.Status - } -} - -func (self *SElasticcacheBackup) GetBackupSizeMb() int { - return int(self.SizeByte / 1024 / 1024) -} - -func (self *SElasticcacheBackup) GetBackupType() string { - switch self.BackupType { - case "manual": - return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL - case "auto": - return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED - default: - return self.BackupType - } - -} - -func (self *SElasticcacheBackup) GetBackupMode() string { - return "" -} - -func (self *SElasticcacheBackup) GetDownloadURL() string { - return "" -} - -func (self *SElasticcacheBackup) GetStartTime() time.Time { - return self.CreatedAt -} - -func (self *SElasticcacheBackup) GetEndTime() time.Time { - return self.UpdatedAt -} - -func (self *SElasticcacheBackup) Delete() error { - return cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html -func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { - _, err := self.cacheDB.region.ecsClient.Elasticcache.RestoreInstance(instanceId, self.GetId()) - if err != nil { - return nil - } - - return nil -} diff --git a/pkg/multicloud/huawei/elasticcache_instance.go b/pkg/multicloud/huawei/elasticcache_instance.go deleted file mode 100644 index 36bf3835cc..0000000000 --- a/pkg/multicloud/huawei/elasticcache_instance.go +++ /dev/null @@ -1,760 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html -type SElasticcache struct { - multicloud.SElasticcacheBase - multicloud.HuaweiTags - - region *SRegion - - Name string `json:"name"` - Engine string `json:"engine"` - CapacityGB int `json:"capacity"` - IP string `json:"ip"` - DomainName string `json:"domainName"` - Port int `json:"port"` - Status string `json:"status"` - Libos bool `json:"libos"` - Description string `json:"description"` - Task string `json:"task"` - MaxMemoryMB int `json:"max_memory"` - UsedMemoryMB int `json:"used_memory"` - InstanceID string `json:"instance_id"` - ResourceSpecCode string `json:"resource_spec_code"` - EngineVersion string `json:"engine_version"` - InternalVersion string `json:"internal_version"` - ChargingMode int `json:"charging_mode"` - CapacityMinor string `json:"capacity_minor"` - VpcID string `json:"vpc_id"` - VpcName string `json:"vpc_name"` - TaskStatus string `json:"task_status"` - CreatedAt string `json:"created_at"` - ErrorCode string `json:"error_code"` - UserID string `json:"user_id"` - UserName string `json:"user_name"` - MaintainBegin string `json:"maintain_begin"` - MaintainEnd string `json:"maintain_end"` - NoPasswordAccess string `json:"no_password_access"` - AccessUser string `json:"access_user"` - EnablePublicip bool `json:"enable_publicip"` - PublicipID string `json:"publicip_id"` - PublicipAddress string `json:"publicip_address"` - EnableSSL bool `json:"enable_ssl"` - ServiceUpgrade bool `json:"service_upgrade"` - ServiceTaskID string `json:"service_task_id"` - IsFree string `json:"is_free"` - EnterpriseProjectID string `json:"enterprise_project_id"` - AvailableZones []string `json:"available_zones"` - SubnetID string `json:"subnet_id"` - SecurityGroupID string `json:"security_group_id"` - BackendAddrs []string `json:"backend_addrs"` - ProductID string `json:"product_id"` - SecurityGroupName string `json:"security_group_name"` - SubnetName string `json:"subnet_name"` - OrderID string `json:"order_id"` - SubnetCIDR string `json:"subnet_cidr"` - InstanceBackupPolicy string `json:"instance_backup_policy"` - EnterpriseProjectName string `json:"enterprise_project_name"` -} - -func (self *SElasticcache) GetId() string { - return self.InstanceID -} - -func (self *SElasticcache) GetName() string { - return self.Name -} - -func (self *SElasticcache) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcache) GetProjectId() string { - return self.EnterpriseProjectID -} - -func (self *SElasticcache) Refresh() error { - cache, err := self.region.GetElasticCache(self.GetId()) - if err != nil { - return errors.Wrap(err, "Elasticcache.Refresh.GetElasticCache") - } - - err = jsonutils.Update(self, cache) - if err != nil { - return errors.Wrap(err, "Elasticcache.Refresh.Update") - } - - return nil -} - -func (self *SElasticcache) GetStatus() string { - switch self.Status { - case "RUNNING": - return api.ELASTIC_CACHE_STATUS_RUNNING - case "CREATING": - return api.ELASTIC_CACHE_STATUS_DEPLOYING - case "CREATEFAILED": - return api.ELASTIC_CACHE_STATUS_CREATE_FAILED - case "ERROR": - return api.ELASTIC_CACHE_STATUS_ERROR - case "RESTARTING": - return api.ELASTIC_CACHE_STATUS_RESTARTING - case "FROZEN": - return api.ELASTIC_CACHE_STATUS_UNAVAILABLE - case "EXTENDING": - return api.ELASTIC_CACHE_STATUS_CHANGING - case "RESTORING": - return api.ELASTIC_CACHE_STATUS_TRANSFORMING // ? - case "FLUSHING": - return api.ELASTIC_CACHE_STATUS_FLUSHING - } - - return "" -} - -func (self *SElasticcache) GetBillingType() string { - // charging_mode “0”:按需计费 “1”:按包年包月计费 - if self.ChargingMode == 1 { - return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SElasticcache) GetCreatedAt() time.Time { - var createtime time.Time - if len(self.CreatedAt) > 0 { - createtime, _ = time.Parse("2006-01-02T15:04:05.000Z", self.CreatedAt) - } - - return createtime -} - -func (self *SElasticcache) GetExpiredAt() time.Time { - var expiredTime time.Time - if self.ChargingMode == 1 { - res, err := self.region.GetOrderResourceDetail(self.GetId()) - if err != nil { - log.Debugln(err) - } - - expiredTime = res.ExpireTime - } - - return expiredTime -} - -func (self *SElasticcache) GetInstanceType() string { - // todo: ?? - return self.ResourceSpecCode -} - -func (self *SElasticcache) GetCapacityMB() int { - return self.CapacityGB * 1024 -} - -func (self *SElasticcache) GetArchType() string { - /* - 资源规格标识。 - - dcs.single_node:表示实例类型为单机 - dcs.master_standby:表示实例类型为主备 - dcs.cluster:表示实例类型为集群 - */ - if strings.Contains(self.ResourceSpecCode, "single") { - return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE - } else if strings.Contains(self.ResourceSpecCode, "ha") { - return api.ELASTIC_CACHE_ARCH_TYPE_MASTER - } else if strings.Contains(self.ResourceSpecCode, "cluster") { - return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER - } else if strings.Contains(self.ResourceSpecCode, "proxy") { - return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER - } - - return "" -} - -func (self *SElasticcache) GetNodeType() string { - // single(单副本) | double(双副本) - if strings.Contains(self.ResourceSpecCode, "single") { - return "single" - } else { - return "double" - } -} - -func (self *SElasticcache) GetEngine() string { - return self.Engine -} - -func (self *SElasticcache) GetEngineVersion() string { - return self.EngineVersion -} - -func (self *SElasticcache) GetVpcId() string { - return self.VpcID -} - -func (self *SElasticcache) GetZoneId() string { - if len(self.AvailableZones) > 0 { - zone, err := self.region.getZoneById(self.AvailableZones[0]) - if err != nil { - log.Errorf("elasticcache.GetZoneId %s", err) - return "" - } - - return zone.GetGlobalId() - } - - return "" -} - -func (self *SElasticcache) GetNetworkType() string { - return api.LB_NETWORK_TYPE_VPC -} - -func (self *SElasticcache) GetNetworkId() string { - return self.SubnetID -} - -func (self *SElasticcache) GetPrivateDNS() string { - return self.DomainName -} - -func (self *SElasticcache) GetPrivateIpAddr() string { - return self.IP -} - -func (self *SElasticcache) GetPrivateConnectPort() int { - return self.Port -} - -func (self *SElasticcache) GetPublicDNS() string { - return self.PublicipAddress -} - -func (self *SElasticcache) GetPublicIpAddr() string { - return self.PublicipAddress -} - -func (self *SElasticcache) GetPublicConnectPort() int { - return self.Port -} - -func (self *SElasticcache) GetMaintainStartTime() string { - return self.MaintainBegin -} - -func (self *SElasticcache) GetMaintainEndTime() string { - return self.MaintainEnd -} - -func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { - iaccounts := []cloudprovider.ICloudElasticcacheAccount{} - iaccount := &SElasticcacheAccount{cacheDB: self} - iaccounts = append(iaccounts, iaccount) - return iaccounts, nil -} - -func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { - // 华为云使用安全组做访问控制。目前未支持 - return []cloudprovider.ICloudElasticcacheAcl{}, nil -} - -func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { - start := self.GetCreatedAt().Format("20060102150405") - end := time.Now().Format("20060102150405") - backups, err := self.region.GetElasticCacheBackups(self.GetId(), start, end) - if err != nil { - return nil, err - } - - ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) - for i := range backups { - backups[i].cacheDB = self - ibackups[i] = &backups[i] - } - - return ibackups, nil -} - -func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { - parameters, err := self.region.GetElasticCacheParameters(self.GetId()) - if err != nil { - return nil, err - } - - iparameters := make([]cloudprovider.ICloudElasticcacheParameter, len(parameters)) - for i := range parameters { - parameters[i].cacheDB = self - iparameters[i] = ¶meters[i] - } - - return iparameters, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html -func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) { - params := make(map[string]string) - params["instance_id"] = instanceId - params["beginTime"] = startTime - params["endTime"] = endTime - - backups := make([]SElasticcacheBackup, 0) - err := doListAll(self.ecsClient.Elasticcache.ListBackups, params, &backups) - if err != nil { - return nil, err - } - - return backups, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html -func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { - params := make(map[string]string) - params["instance_id"] = instanceId - - parameters := make([]SElasticcacheParameter, 0) - err := doListAll(self.ecsClient.Elasticcache.ListParameters, params, ¶meters) - if err != nil { - return nil, err - } - - return parameters, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423044.html -func (self *SRegion) GetElasticCaches() ([]SElasticcache, error) { - params := make(map[string]string) - caches := make([]SElasticcache, 0) - err := doListAll(self.ecsClient.Elasticcache.List, params, &caches) - if err != nil { - return nil, errors.Wrap(err, "region.GetElasticCaches") - } - - for i := range caches { - cache, err := self.GetElasticCache(caches[i].GetId()) - if err != nil { - return nil, err - } else { - caches[i] = *cache - } - - caches[i].region = self - } - - return caches, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html -func (self *SRegion) GetElasticCache(instanceId string) (*SElasticcache, error) { - cache := SElasticcache{} - err := DoGet(self.ecsClient.Elasticcache.Get, instanceId, nil, &cache) - if err != nil { - return nil, errors.Wrapf(err, "region.GetElasticCache %s", instanceId) - } - - cache.region = self - return &cache, nil -} - -func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { - ec, err := self.GetElasticCache(id) - if err != nil { - return nil, errors.Wrap(err, "region.GetIElasticCacheById.GetElasticCache") - } - - return ec, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423047.html -func (self *SRegion) zoneNameToDcsZoneIds(zoneIds []string) ([]string, error) { - type Z struct { - ID string `json:"id"` - Code string `json:"code"` - Name string `json:"name"` - Port string `json:"port"` - ResourceAvailability string `json:"resource_availability"` - } - - rs := []Z{} - err := doListAll(self.ecsClient.DcsAvailableZone.List, nil, &rs) - if err != nil { - return nil, errors.Wrap(err, "region.zoneNameToDcsZoneIds") - } - - zoneMap := map[string]string{} - for i := range rs { - if rs[i].ResourceAvailability == "true" { - zoneMap[rs[i].Code] = rs[i].ID - } - } - - ret := []string{} - for _, zone := range zoneIds { - if id, ok := zoneMap[zone]; ok { - ret = append(ret, id) - } else { - return nil, errors.Wrap(fmt.Errorf("zone %s not found or not available", zone), "region.zoneNameToDcsZoneIds") - } - } - - return ret, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423019.html -func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { - params := jsonutils.NewDict() - params.Set("name", jsonutils.NewString(ec.InstanceName)) - params.Set("engine", jsonutils.NewString(ec.Engine)) - params.Set("engine_version", jsonutils.NewString(ec.EngineVersion)) - params.Set("capacity", jsonutils.NewInt(ec.CapacityGB)) - params.Set("vpc_id", jsonutils.NewString(ec.VpcId)) - if len(ec.SecurityGroupIds) > 0 { - params.Set("security_group_id", jsonutils.NewString(ec.SecurityGroupIds[0])) - } - params.Set("subnet_id", jsonutils.NewString(ec.NetworkId)) - params.Set("product_id", jsonutils.NewString(ec.InstanceType)) - zones, err := self.zoneNameToDcsZoneIds(ec.ZoneIds) - if err != nil { - return nil, err - } - params.Set("available_zones", jsonutils.NewStringArray(zones)) - - if len(ec.ProjectId) > 0 { - params.Set("enterprise_project_id", jsonutils.NewString(ec.ProjectId)) - } - - if len(ec.Password) > 0 { - params.Set("no_password_access", jsonutils.NewString("false")) - params.Set("password", jsonutils.NewString(ec.Password)) - - // todo: 这里换成常量 - if ec.Engine == "Memcache" { - params.Set("access_user", jsonutils.NewString(ec.UserName)) - } - } else { - params.Set("no_password_access", jsonutils.NewString("true")) - } - - if len(ec.EipId) > 0 { - params.Set("enable_publicip", jsonutils.NewString("true")) - params.Set("publicip_id", jsonutils.NewString(ec.EipId)) - // enable_ssl - } else { - params.Set("enable_publicip", jsonutils.NewString("false")) - } - - if len(ec.PrivateIpAddress) > 0 { - params.Set("private_ip", jsonutils.NewString(ec.PrivateIpAddress)) - } - - if len(ec.MaintainBegin) > 0 { - params.Set("maintain_begin", jsonutils.NewString(ec.MaintainBegin)) - params.Set("maintain_end", jsonutils.NewString(ec.MaintainEnd)) - } - - if ec.BillingCycle != nil { - bssParam := jsonutils.NewDict() - bssParam.Set("charging_mode", jsonutils.NewString("prePaid")) - bssParam.Set("is_auto_pay", jsonutils.NewString("true")) - bssParam.Set("is_auto_renew", jsonutils.NewString(fmt.Sprintf("%v", ec.BillingCycle.AutoRenew))) - if ec.BillingCycle.GetMonths() >= 1 && ec.BillingCycle.GetMonths() >= 9 { - bssParam.Set("period_type", jsonutils.NewString("month")) - bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetMonths()))) - } else if ec.BillingCycle.GetYears() >= 1 && ec.BillingCycle.GetYears() <= 3 { - bssParam.Set("period_type", jsonutils.NewString("year")) - bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetYears()))) - } else { - return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") - } - - params.Set("bss_param", bssParam) - } - - ret := &SElasticcache{} - err = DoCreate(self.ecsClient.Elasticcache.Create, params, ret) - if err != nil { - return nil, errors.Wrap(err, "region.CreateIElasticcaches") - } - - ret.region = self - return ret, nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html -func (self *SElasticcache) Restart() error { - resp, err := self.region.ecsClient.Elasticcache.Restart(self.GetId()) - if err != nil { - return errors.Wrap(err, "elasticcache.Restart") - } - - rets, err := resp.GetArray("results") - if err != nil { - return errors.Wrap(err, "elasticcache.results") - } - - for _, r := range rets { - if ret, _ := r.GetString("result"); ret != "success" { - return fmt.Errorf("elasticcache.Restart failed") - } - } - - return nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423022.html -func (self *SElasticcache) Delete() error { - err := DoDelete(self.region.ecsClient.Elasticcache.Delete, self.GetId(), nil, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.Delete") - } - - return nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html -func (self *SElasticcache) ChangeInstanceSpec(spec string) error { - segs := strings.Split(spec, ":") - if len(segs) < 2 { - return fmt.Errorf("elasticcache.ChangeInstanceSpec invalid sku %s", spec) - } - - if !strings.HasPrefix(segs[1], "m") || !strings.HasSuffix(segs[1], "g") { - return fmt.Errorf("elasticcache.ChangeInstanceSpec sku %s memeory size is invalid.", spec) - } - - newCapacity := segs[1][1 : len(segs[1])-1] - capacity, err := strconv.Atoi(newCapacity) - if err != nil { - return errors.Wrap(fmt.Errorf("invalid sku capacity %s", spec), "Elasticcache.ChangeInstanceSpec") - } - - _, err = self.region.ecsClient.Elasticcache.ChangeInstanceSpec(self.GetId(), segs[0], int64(capacity)) - if err != nil { - return errors.Wrap(err, "elasticcache.ChangeInstanceSpec") - } - - return nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html -func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { - params := jsonutils.NewDict() - params.Set("maintain_begin", jsonutils.NewString(maintainStartTime)) - params.Set("maintain_end", jsonutils.NewString(maintainEndTime)) - err := DoUpdate(self.region.ecsClient.Elasticcache.Update, self.GetId(), params, nil) - if err != nil { - return errors.Wrap(err, "elasticcache.SetMaintainTime") - } - - return nil -} - -// https://support.huaweicloud.com/usermanual-dcs/dcs-zh-ug-180314001.html -// 目前只有Redis3.0版本密码模式的实例支持通过公网访问Redis实例,其他版本暂不支持公网访问。 -// todo: 目前没找到api -func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -// todo: 目前没找到api -func (self *SElasticcache) ReleasePublicConnection() error { - return cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { - return nil, cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html - -func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423029.html -func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { - params := jsonutils.NewDict() - params.Set("redis_config", config) - err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) - if err != nil { - return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") - } - - return nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423033.html -func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func backupPeriodTrans(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) *jsonutils.JSONArray { - segs := strings.Split(config.PreferredBackupPeriod, ",") - ret := jsonutils.NewArray() - for _, seg := range segs { - switch seg { - case "Monday": - ret.Add(jsonutils.NewString("1")) - case "Tuesday": - ret.Add(jsonutils.NewString("2")) - case "Wednesday": - ret.Add(jsonutils.NewString("3")) - case "Thursday": - ret.Add(jsonutils.NewString("4")) - case "Friday": - ret.Add(jsonutils.NewString("5")) - case "Saturday": - ret.Add(jsonutils.NewString("6")) - case "Sunday": - ret.Add(jsonutils.NewString("7")) - } - } - - return ret -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html -func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { - params := jsonutils.NewDict() - policy := jsonutils.NewDict() - policy.Set("save_days", jsonutils.NewInt(int64(config.BackupReservedDays))) - policy.Set("backup_type", jsonutils.NewString(config.BackupType)) - plan := jsonutils.NewDict() - backTime := strings.ReplaceAll(config.PreferredBackupTime, "Z", "") - backupPeriod := backupPeriodTrans(config) - plan.Set("begin_at", jsonutils.NewString(backTime)) - plan.Set("period_type", jsonutils.NewString("weekly")) - plan.Set("backup_at", backupPeriod) - policy.Set("periodical_backup_plan", plan) - params.Set("instance_backup_policy", policy) - err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) - if err != nil { - return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") - } - - return nil -} - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html -// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 -func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { - resp, err := self.region.ecsClient.Elasticcache.Flush(self.GetId()) - if err != nil { - return errors.Wrap(err, "elasticcache.FlushInstance") - } - - rets, err := resp.GetArray("results") - if err != nil { - return errors.Wrap(err, "elasticcache.FlushInstance") - } - - for _, r := range rets { - if ret, _ := r.GetString("result"); ret != "success" { - return fmt.Errorf("elasticcache.FlushInstance failed") - } - } - - return nil -} - -// SElasticcacheAccount => ResetPassword -func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool, password string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetAuthMode() string { - switch self.NoPasswordAccess { - case "true": - return "off" - default: - return "on" - } -} - -func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { - accounts, err := self.GetICloudElasticcacheAccounts() - if err != nil { - return nil, errors.Wrap(err, "Elasticcache.GetICloudElasticcacheAccount.Accounts") - } - - for i := range accounts { - account := accounts[i] - if account.GetGlobalId() == accountId { - return account, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { - backups, err := self.GetICloudElasticcacheBackups() - if err != nil { - return nil, err - } - - for _, backup := range backups { - if backup.GetId() == backupId { - return backup, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (instance *SElasticcache) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { - return errors.Wrap(cloudprovider.ErrNotSupported, "UpdateSecurityGroups") -} - -func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) SetAutoRenew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/huawei/elasticcache_parameter.go b/pkg/multicloud/huawei/elasticcache_parameter.go deleted file mode 100644 index 3b4202e63a..0000000000 --- a/pkg/multicloud/huawei/elasticcache_parameter.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html -type SElasticcacheParameter struct { - multicloud.SElasticcacheParameterBase - multicloud.HuaweiTags - - cacheDB *SElasticcache - - Description string `json:"description"` - ParamID int64 `json:"param_id"` - ParamName string `json:"param_name"` - ParamValue string `json:"param_value"` - DefaultValue string `json:"default_value"` - ValueType string `json:"value_type"` - ValueRange string `json:"value_range"` -} - -func (self *SElasticcacheParameter) GetId() string { - return fmt.Sprintf("%d", self.ParamID) -} - -func (self *SElasticcacheParameter) GetName() string { - return self.ParamName -} - -func (self *SElasticcacheParameter) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.cacheDB.InstanceID, self.GetId()) -} - -func (self *SElasticcacheParameter) GetStatus() string { - return api.ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE -} - -func (self *SElasticcacheParameter) GetParameterKey() string { - return self.ParamName -} - -func (self *SElasticcacheParameter) GetParameterValue() string { - return self.ParamValue -} - -func (self *SElasticcacheParameter) GetParameterValueRange() string { - return self.Description -} - -func (self *SElasticcacheParameter) GetDescription() string { - return self.ValueRange -} - -func (self *SElasticcacheParameter) GetModifiable() bool { - return true -} - -func (self *SElasticcacheParameter) GetForceRestart() bool { - return false -} diff --git a/pkg/multicloud/huawei/enterpriceprojects.go b/pkg/multicloud/huawei/enterpriceprojects.go deleted file mode 100644 index 1b846ea92e..0000000000 --- a/pkg/multicloud/huawei/enterpriceprojects.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://support.huaweicloud.com/api-em/zh-cn_topic_0121230880.html -type SEnterpriseProject struct { - multicloud.SProjectBase - multicloud.HuaweiTags - - Id string - Name string - Description string - Status int - CreatedAt time.Time - UpdatedAt time.Time -} - -func (self *SHuaweiClient) GetEnterpriseProjects() ([]SEnterpriseProject, error) { - projects := []SEnterpriseProject{} - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - err = doListAllWithOffset(client.EnterpriseProjects.List, map[string]string{}, &projects) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return projects, nil -} - -func (ep *SEnterpriseProject) GetId() string { - return ep.Id -} - -func (ep *SEnterpriseProject) GetGlobalId() string { - return ep.Id -} - -func (ep *SEnterpriseProject) GetStatus() string { - if ep.Status == 1 { - return api.EXTERNAL_PROJECT_STATUS_AVAILABLE - } - return api.EXTERNAL_PROJECT_STATUS_UNAVAILABLE -} - -func (ep *SEnterpriseProject) GetName() string { - return ep.Name -} - -func (self *SHuaweiClient) CreateExterpriseProject(name, desc string) (*SEnterpriseProject, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - params := map[string]string{ - "name": name, - } - if len(desc) > 0 { - params["description"] = desc - } - resp, err := client.EnterpriseProjects.Create(jsonutils.Marshal(params)) - if err != nil { - if strings.Contains(err.Error(), "EPS.0004") { - return nil, cloudprovider.ErrNotSupported - } - return nil, errors.Wrap(err, "EnterpriseProjects.Create") - } - project := &SEnterpriseProject{} - err = resp.Unmarshal(&project) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return project, nil -} - -func (self *SHuaweiClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return self.CreateExterpriseProject(name, "") -} - -func (self *SHuaweiClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { - projects, err := self.GetEnterpriseProjects() - if err != nil { - return nil, errors.Wrap(err, "GetProjects") - } - ret := []cloudprovider.ICloudProject{} - for i := range projects { - ret = append(ret, &projects[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/huawei/host.go b/pkg/multicloud/huawei/host.go deleted file mode 100644 index 6cf4e8cde7..0000000000 --- a/pkg/multicloud/huawei/host.go +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone - - projectId string -} - -func (self *SHost) GetId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) GetName() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) -} - -func (self *SHost) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) Refresh() error { - return nil -} - -func (self *SHost) IsEmulated() bool { - return true -} - -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms, err := self.zone.region.GetInstances() - if err != nil { - return nil, err - } - - filtedVms := make([]SInstance, 0) - for i := range vms { - if vms[i].OSEXTAZAvailabilityZone == self.zone.GetId() { - filtedVms = append(filtedVms, vms[i]) - } - } - - ivms := make([]cloudprovider.ICloudVM, len(filtedVms)) - for i := 0; i < len(filtedVms); i += 1 { - filtedVms[i].host = self - ivms[i] = &filtedVms[i] - } - return ivms, nil -} - -func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.zone.region.GetInstanceByID(id) - vm.host = self - return &vm, err -} - -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 api.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_HUAWEI), "manufacture") - return info -} - -func (self *SHost) GetSN() string { - return "" -} - -func (self *SHost) GetCpuCount() int { - 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 api.DISK_TYPE_HYBRID -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_HUAWEI -} - -func (self *SHost) GetIsMaintenance() bool { - return false -} - -func (self *SHost) GetVersion() string { - return HUAWEI_API_VERSION -} - -func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) { - instance, err := self.zone.region.GetInstanceByID(instanceId) - if err != nil { - return nil, err - } - - instance.host = self - return &instance, nil -} - -func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - vmId, err := self._createVM( - desc.Name, desc.ExternalImageId, desc.SysDisk, - desc.Cpu, desc.MemoryMB, desc.InstanceType, - desc.ExternalNetworkId, desc.IpAddr, - desc.Description, desc.Account, - desc.Password, desc.DataDisks, - desc.PublicKey, desc.ExternalSecgroupId, - desc.UserData, desc.BillingCycle, desc.ProjectId, desc.Tags) - if err != nil { - return nil, err - } - - vm, err := self.GetInstanceById(vmId) - if err != nil { - return nil, err - } - - return vm, err -} - -func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, - networkId string, ipAddr string, desc string, account string, passwd string, - diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string, - userData string, bc *billing.SBillingCycle, projectId string, tags map[string]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") - } - - // 同步keypair - var err error - keypair := "" - if len(publicKey) > 0 { - 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 %s fail %s", imgId, err) - return "", err - } - if img.Status != ImageStatusActive { - log.Errorf("image %s status %s", imgId, img.Status) - return "", fmt.Errorf("image not ready") - } - // passwd, windows机型直接使用密码比较方便 - if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(passwd) > 0 { - keypair = "" - } - - if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) { - if u, err := updateWindowsUserData(userData, img.OSVersion, account, passwd); err == nil { - userData = u - } else { - return "", errors.Wrap(err, "SHost.CreateVM.updateWindowsUserData") - } - } - - disks := make([]SDisk, len(diskSizes)+1) - disks[0].SizeGB = img.SizeGB - if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.SizeGB { - disks[0].SizeGB = sysDisk.SizeGB - } - disks[0].VolumeType = sysDisk.StorageType - - for i, dataDisk := range diskSizes { - disks[i+1].SizeGB = dataDisk.SizeGB - disks[i+1].VolumeType = dataDisk.StorageType - } - - _, err = self.zone.region.GetSecurityGroupDetails(secgroupId) - if err != nil { - return "", errors.Wrap(err, "SHost.CreateVM.GetSecurityGroupDetails") - } - - // 创建实例 - if len(instanceType) > 0 { - log.Debugf("Try instancetype : %s", instanceType) - vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) - if err != nil { - log.Errorf("Failed for %s: %s", instanceType, err) - return "", fmt.Errorf("create %s failed:%s", instanceType, ErrMessage(err)) - } else { - return vmId, nil - } - } - - // 匹配实例类型 - instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, self.zone.GetId()) - if err != nil { - return "", err - } - if len(instanceTypes) == 0 { - return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB) - } - - var vmId string - for _, instType := range instanceTypes { - instanceTypeId := instType.Name - log.Debugf("Try instancetype : %s", instanceTypeId) - vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) - if err != nil { - log.Errorf("Failed for %s: %s", instanceTypeId, err) - } else { - return vmId, nil - } - } - - return "", fmt.Errorf("create failed: %s", ErrMessage(err)) -} diff --git a/pkg/multicloud/huawei/huawei.go b/pkg/multicloud/huawei/huawei.go deleted file mode 100644 index 474bb493bc..0000000000 --- a/pkg/multicloud/huawei/huawei.go +++ /dev/null @@ -1,862 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "fmt" - "net/http" - "net/url" - "strconv" - "strings" - "sync" - "time" - - "github.com/huaweicloud/huaweicloud-sdk-go/auth/aksk" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/gotypes" - "yunion.io/x/pkg/util/timeutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth/credentials" - "yunion.io/x/onecloud/pkg/multicloud/huawei/obs" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -/* -待解决问题: -1.同步的子账户中有一条空记录.需要查原因 -2.安全组同步需要进一步确认 -3.实例接口需要进一步确认 -4.BGP type 目前是hard code在代码中。需要考虑从cloudmeta服务中查询 -*/ - -const ( - CLOUD_PROVIDER_HUAWEI = api.CLOUD_PROVIDER_HUAWEI - CLOUD_PROVIDER_HUAWEI_CN = "华为云" - CLOUD_PROVIDER_HUAWEI_EN = "Huawei" - - HUAWEI_INTERNATIONAL_CLOUDENV = "InternationalCloud" - HUAWEI_CHINA_CLOUDENV = "ChinaCloud" - - HUAWEI_DEFAULT_REGION = "cn-north-1" - HUAWEI_API_VERSION = "2018-12-25" -) - -var HUAWEI_REGION_CACHES sync.Map - -type userRegionsCache struct { - UserId string - ExpireAt time.Time - Regions []SRegion -} - -type HuaweiClientConfig struct { - cpcfg cloudprovider.ProviderConfig - - projectId string // 华为云项目ID. - cloudEnv string // 服务区域 ChinaCloud | InternationalCloud - accessKey string - accessSecret string - - debug bool -} - -func NewHuaweiClientConfig(cloudEnv, accessKey, accessSecret, projectId string) *HuaweiClientConfig { - cfg := &HuaweiClientConfig{ - projectId: projectId, - cloudEnv: cloudEnv, - accessKey: accessKey, - accessSecret: accessSecret, - } - return cfg -} - -func (cfg *HuaweiClientConfig) CloudproviderConfig(cpcfg cloudprovider.ProviderConfig) *HuaweiClientConfig { - cfg.cpcfg = cpcfg - return cfg -} - -func (cfg *HuaweiClientConfig) Debug(debug bool) *HuaweiClientConfig { - cfg.debug = debug - return cfg -} - -type SHuaweiClient struct { - *HuaweiClientConfig - - signer auth.Signer - - isMainProject bool // whether the project is the main project in the region - clientRegion string - - ownerId string - ownerName string - ownerCreateTime time.Time - - iregions []cloudprovider.ICloudRegion - iBuckets []cloudprovider.ICloudBucket - - projects []SProject - regions []SRegion - - httpClient *http.Client -} - -// 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成,通过"/"分割。 -// 初次导入Subaccount时,参数account对应cloudaccounts表中的account字段,即accesskey。此时projectID为空, -// 只能进行同步子账号、查询region列表等projectId无关的操作。 -// todo: 通过accessurl支持国际站。目前暂时未支持国际站 -func NewHuaweiClient(cfg *HuaweiClientConfig) (*SHuaweiClient, error) { - client := SHuaweiClient{ - HuaweiClientConfig: cfg, - } - err := client.init() - if err != nil { - return nil, err - } - return &client, nil -} - -func (self *SHuaweiClient) init() error { - err := self.fetchRegions() - if err != nil { - return err - } - err = self.initSigner() - if err != nil { - return errors.Wrap(err, "initSigner") - } - err = self.initOwner() - if err != nil { - return errors.Wrap(err, "fetchOwner") - } - if self.debug { - log.Debugf("OwnerId: %s name: %s", self.ownerId, self.ownerName) - } - return nil -} - -func (self *SHuaweiClient) initSigner() error { - var err error - cred := credentials.NewAccessKeyCredential(self.accessKey, self.accessKey) - self.signer, err = auth.NewSignerWithCredential(cred) - if err != nil { - return err - } - return nil -} - -func (self *SHuaweiClient) getDefaultClient() *http.Client { - if self.httpClient != nil { - return self.httpClient - } - self.httpClient = self.cpcfg.AdaptiveTimeoutHttpClient() - ts, _ := self.httpClient.Transport.(*http.Transport) - self.httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { - service, method, path := strings.Split(req.URL.Host, ".")[0], req.Method, req.URL.Path - respCheck := func(resp *http.Response) { - if resp.StatusCode == 403 { - if self.cpcfg.UpdatePermission != nil { - self.cpcfg.UpdatePermission(service, fmt.Sprintf("%s %s", method, path)) - } - } - } - if self.cpcfg.ReadOnly { - if req.Method == "GET" { - return respCheck, nil - } - return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) - } - return respCheck, nil - }) - return self.httpClient -} - -func (self *SHuaweiClient) newRegionAPIClient(regionId string) (*client.Client, error) { - projectId := self.projectId - if len(regionId) == 0 { - projectId = "" - } - cli, err := client.NewPublicCloudClientWithAccessKey(regionId, self.ownerId, projectId, self.accessKey, self.accessSecret, self.debug) - if err != nil { - return nil, err - } - - httpClient := self.getDefaultClient() - cli.SetHttpClient(httpClient) - - return cli, nil -} - -type sPageInfo struct { - NextMarker string -} - -func (self *SHuaweiClient) newGeneralAPIClient() (*client.Client, error) { - return self.newRegionAPIClient("") -} - -func (self *SHuaweiClient) lbList(regionId, resource string, query url.Values) (jsonutils.JSONObject, error) { - url := fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) - return self.request(httputils.GET, url, query, nil) -} - -func (self *SHuaweiClient) monitorList(resource string, query url.Values) (jsonutils.JSONObject, error) { - url := fmt.Sprintf("https://ces.%s.myhuaweicloud.com/v1.0/%s/%s", self.clientRegion, self.projectId, resource) - return self.request(httputils.GET, url, query, nil) -} - -func (self *SHuaweiClient) monitorPost(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - url := fmt.Sprintf("https://ces.%s.myhuaweicloud.com/V1.0/%s/%s", self.clientRegion, self.projectId, resource) - return self.request(httputils.POST, url, nil, params) -} - -func (self *SHuaweiClient) modelartsPoolNetworkList(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/networks", self.clientRegion, self.projectId) - return self.request(httputils.GET, uri, url.Values{}, params) -} - -func (self *SHuaweiClient) modelartsPoolNetworkCreate(params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/networks", self.clientRegion, self.projectId) - return self.request(httputils.POST, uri, url.Values{}, params) -} - -func (self *SHuaweiClient) modelartsPoolById(poolName string) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/pools/%s", self.clientRegion, self.projectId, poolName) - return self.request(httputils.GET, uri, url.Values{}, nil) -} - -func (self *SHuaweiClient) modelartsPoolList(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/%s", self.clientRegion, self.projectId, resource) - return self.request(httputils.GET, uri, url.Values{}, params) -} - -func (self *SHuaweiClient) modelartsPoolCreate(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/%s", self.clientRegion, self.projectId, resource) - return self.request(httputils.POST, uri, url.Values{}, params) -} - -func (self *SHuaweiClient) modelartsPoolDelete(resource, poolName string, params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/pools/%s", self.clientRegion, self.projectId, poolName) - return self.request(httputils.DELETE, uri, url.Values{}, params) -} - -func (self *SHuaweiClient) modelartsPoolUpdate(poolName string, params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/pools/%s", self.clientRegion, self.projectId, poolName) - urlValue := url.Values{} - urlValue.Add("time_range", "") - urlValue.Add("statistics", "") - urlValue.Add("period", "") - return self.patchRequest(httputils.PATCH, uri, urlValue, params) -} - -func (self *SHuaweiClient) modelartsPoolMonitor(poolName string, params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/pools/%s/monitor", self.clientRegion, self.projectId, poolName) - return self.request(httputils.GET, uri, url.Values{}, params) -} - -func (self *SHuaweiClient) modelartsResourceflavors(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/%s", self.clientRegion, self.projectId, resource) - return self.request(httputils.GET, uri, url.Values{}, params) -} - -func (self *SHuaweiClient) getAKSKList(userId string) (jsonutils.JSONObject, error) { - params := url.Values{} - params.Set("user_id", userId) - uri := fmt.Sprintf("https://iam.cn-north-4.myhuaweicloud.com/v3.0/OS-CREDENTIAL/credentials") - return self.request(httputils.GET, uri, params, nil) -} - -func (self *SHuaweiClient) deleteAKSK(accesskey string) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://iam.cn-north-4.myhuaweicloud.com/v3.0/OS-CREDENTIAL/credentials/%s", accesskey) - return self.request(httputils.DELETE, uri, url.Values{}, nil) -} - -func (self *SHuaweiClient) createAKSK(params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://iam.cn-north-4.myhuaweicloud.com/v3.0/OS-CREDENTIAL/credentials") - return self.request(httputils.POST, uri, url.Values{}, params) -} - -func (self *SHuaweiClient) lbGet(regionId, resource string) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) - return self.request(httputils.GET, uri, url.Values{}, nil) -} - -func (self *SHuaweiClient) lbCreate(regionId, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) - return self.request(httputils.POST, uri, url.Values{}, params) -} - -func (self *SHuaweiClient) lbUpdate(regionId, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) - return self.request(httputils.PUT, uri, url.Values{}, params) -} - -func (self *SHuaweiClient) lbDelete(regionId, resource string) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) - return self.request(httputils.DELETE, uri, url.Values{}, nil) -} - -func (self *SHuaweiClient) vpcList(regionId, resource string, query url.Values) (jsonutils.JSONObject, error) { - url := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) - return self.request(httputils.GET, url, query, nil) -} - -func (self *SHuaweiClient) vpcCreate(regionId, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) - return self.request(httputils.POST, uri, url.Values{}, params) -} - -func (self *SHuaweiClient) vpcGet(regionId, resource string) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) - return self.request(httputils.GET, uri, url.Values{}, nil) -} - -func (self *SHuaweiClient) vpcDelete(regionId, resource string) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) - return self.request(httputils.DELETE, uri, url.Values{}, nil) -} - -func (self *SHuaweiClient) vpcUpdate(regionId, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - uri := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) - return self.request(httputils.PUT, uri, url.Values{}, params) -} - -type akClient struct { - client *http.Client - aksk aksk.SignOptions -} - -func (self *akClient) Do(req *http.Request) (*http.Response, error) { - req.Header.Del("Accept") - if req.Method == string(httputils.GET) || req.Method == string(httputils.DELETE) || req.Method == string(httputils.PATCH) { - req.Header.Del("Content-Length") - } - aksk.Sign(req, self.aksk) - return self.client.Do(req) -} - -func (self *SHuaweiClient) getAkClient() *akClient { - return &akClient{ - client: self.getDefaultClient(), - aksk: aksk.SignOptions{ - AccessKey: self.accessKey, - SecretKey: self.accessSecret, - }, - } -} - -func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, query url.Values, params map[string]interface{}) (jsonutils.JSONObject, error) { - client := self.getAkClient() - if len(query) > 0 { - url = fmt.Sprintf("%s?%s", url, query.Encode()) - } - var body jsonutils.JSONObject = nil - if len(params) > 0 { - body = jsonutils.Marshal(params) - } - header := http.Header{} - if len(self.projectId) > 0 { - header.Set("X-Project-Id", self.projectId) - } - if strings.Contains(url, "/OS-CREDENTIAL/credentials") && len(self.ownerId) > 0 { - header.Set("X-Domain-Id", self.ownerId) - } - _, resp, err := httputils.JSONRequest(client, context.Background(), method, url, header, body, self.debug) - if err != nil { - if e, ok := err.(*httputils.JSONClientError); ok && e.Code == 404 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, err.Error()) - } - return nil, err - } - return resp, err -} - -func (self *SHuaweiClient) fetchRegions() error { - huawei, _ := self.newGeneralAPIClient() - if self.regions == nil { - userId, err := self.GetUserId() - if err != nil { - return errors.Wrap(err, "GetUserId") - } - - if regionsCache, ok := HUAWEI_REGION_CACHES.Load(userId); !ok || regionsCache.(*userRegionsCache).ExpireAt.Sub(time.Now()).Seconds() > 0 { - regions := make([]SRegion, 0) - err := doListAll(huawei.Regions.List, nil, ®ions) - if err != nil { - return errors.Wrap(err, "Regions.List") - } - - HUAWEI_REGION_CACHES.Store(userId, &userRegionsCache{ExpireAt: time.Now().Add(24 * time.Hour), UserId: userId, Regions: regions}) - } - - if regionsCache, ok := HUAWEI_REGION_CACHES.Load(userId); ok { - self.regions = regionsCache.(*userRegionsCache).Regions - } - } - - filtedRegions := make([]SRegion, 0) - if len(self.projectId) > 0 { - project, err := self.GetProjectById(self.projectId) - if err != nil { - return err - } - - for _, region := range self.regions { - if strings.Count(project.Name, region.ID) >= 1 { - self.clientRegion = region.ID - filtedRegions = append(filtedRegions, region) - } - if project.Name == region.ID { - self.isMainProject = true - } - } - } else { - filtedRegions = self.regions - } - - if len(filtedRegions) == 0 { - return errors.Wrapf(cloudprovider.ErrNotFound, "empty regions") - } - - self.iregions = make([]cloudprovider.ICloudRegion, len(filtedRegions)) - for i := 0; i < len(filtedRegions); i += 1 { - filtedRegions[i].client = self - _, err := filtedRegions[i].getECSClient() - if err != nil { - return err - } - self.iregions[i] = &filtedRegions[i] - } - return nil -} - -func (self *SHuaweiClient) invalidateIBuckets() { - self.iBuckets = nil -} - -func (self *SHuaweiClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) { - if self.iBuckets == nil { - err := self.fetchBuckets() - if err != nil { - return nil, errors.Wrap(err, "fetchBuckets") - } - } - return self.iBuckets, nil -} - -func getOBSEndpoint(regionId string) string { - return fmt.Sprintf("obs.%s.myhuaweicloud.com", regionId) -} - -func (self *SHuaweiClient) getOBSClient(regionId string) (*obs.ObsClient, error) { - endpoint := getOBSEndpoint(regionId) - cli, err := obs.New(self.accessKey, self.accessSecret, endpoint) - if err != nil { - return nil, err - } - client := cli.GetClient() - ts, _ := client.Transport.(*http.Transport) - client.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { - method, path := req.Method, req.URL.Path - respCheck := func(resp *http.Response) { - if resp.StatusCode == 403 { - if self.cpcfg.UpdatePermission != nil { - self.cpcfg.UpdatePermission("obs", fmt.Sprintf("%s %s", method, path)) - } - } - } - if self.cpcfg.ReadOnly { - if req.Method == "GET" || req.Method == "HEAD" { - return respCheck, nil - } - return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) - } - return respCheck, nil - }) - - return cli, nil -} - -func (self *SHuaweiClient) fetchBuckets() error { - obscli, err := self.getOBSClient(HUAWEI_DEFAULT_REGION) - if err != nil { - return errors.Wrap(err, "getOBSClient") - } - input := &obs.ListBucketsInput{QueryLocation: true} - output, err := obscli.ListBuckets(input) - if err != nil { - return errors.Wrap(err, "obscli.ListBuckets") - } - self.ownerId = output.Owner.ID - - ret := make([]cloudprovider.ICloudBucket, 0) - for i := range output.Buckets { - bInfo := output.Buckets[i] - region, err := self.getIRegionByRegionId(bInfo.Location) - if err != nil { - log.Errorf("fail to find region %s", bInfo.Location) - continue - } - b := SBucket{ - region: region.(*SRegion), - - Name: bInfo.Name, - Location: bInfo.Location, - CreationDate: bInfo.CreationDate, - } - ret = append(ret, &b) - } - self.iBuckets = ret - return nil -} - -func (self *SHuaweiClient) GetCloudRegionExternalIdPrefix() string { - if len(self.projectId) > 0 { - return self.iregions[0].GetGlobalId() - } else { - return CLOUD_PROVIDER_HUAWEI - } -} - -func (self *SHuaweiClient) UpdateAccount(accessKey, secret string) error { - if self.accessKey != accessKey || self.accessSecret != secret { - self.accessKey = accessKey - self.accessSecret = secret - return self.fetchRegions() - } else { - return nil - } -} - -func (self *SHuaweiClient) 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 *SHuaweiClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - projects, err := self.fetchProjects() - if err != nil { - return nil, err - } - - // https://support.huaweicloud.com/api-iam/zh-cn_topic_0074171149.html - subAccounts := make([]cloudprovider.SSubAccount, 0) - for i := range projects { - project := projects[i] - // name 为MOS的project是华为云内部的一个特殊project。不需要同步到本地 - if strings.ToLower(project.Name) == "mos" { - continue - } - // https://www.huaweicloud.com/notice/2018/20190618171312411.html - // expiredAt, _ := timeutils.ParseTimeStr("2020-09-16 00:00:00") - // if !self.ownerCreateTime.IsZero() && self.ownerCreateTime.After(expiredAt) && strings.ToLower(project.Name) == "cn-north-1" { - // continue - // } - s := cloudprovider.SSubAccount{ - Name: fmt.Sprintf("%s-%s", self.cpcfg.Name, project.Name), - Account: fmt.Sprintf("%s/%s", self.accessKey, project.ID), - HealthStatus: project.GetHealthStatus(), - DefaultProjectId: "0", - } - for j := range self.iregions { - region := self.iregions[j].(*SRegion) - if strings.Contains(project.Name, region.ID) { - s.Desc = region.Locales.ZhCN - break - } - } - - subAccounts = append(subAccounts, s) - } - - return subAccounts, nil -} - -func (client *SHuaweiClient) GetAccountId() string { - return client.ownerId -} - -func (client *SHuaweiClient) GetIamLoginUrl() string { - return fmt.Sprintf("https://auth.huaweicloud.com/authui/login.html?account=%s#/login", client.ownerName) -} - -func (self *SHuaweiClient) GetIRegions() []cloudprovider.ICloudRegion { - return self.iregions -} - -func (self *SHuaweiClient) getIRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) { - for i := 0; i < len(self.iregions); i += 1 { - log.Debugf("%d ID: %s", i, self.iregions[i].GetId()) - if self.iregions[i].GetId() == id { - return self.iregions[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHuaweiClient) 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 *SHuaweiClient) GetRegion(regionId string) *SRegion { - if len(regionId) == 0 { - regionId = HUAWEI_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 *SHuaweiClient) 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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHuaweiClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - for i := 0; i < len(self.iregions); i += 1 { - ivpc, err := self.iregions[i].GetIVpcById(id) - if err == nil { - return ivpc, nil - } else if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHuaweiClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - for i := 0; i < len(self.iregions); i += 1 { - istorage, err := self.iregions[i].GetIStorageById(id) - if err == nil { - return istorage, nil - } else if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -// 总账户余额 -type SAccountBalance struct { - AvailableAmount float64 - CreditAmount float64 - DesignatedAmount float64 -} - -// 账户余额 -// https://support.huaweicloud.com/api-oce/zh-cn_topic_0109685133.html -type SBalance struct { - Amount float64 `json:"amount"` - Currency string `json:"currency"` - AccountID string `json:"account_id"` - AccountType int64 `json:"account_type"` - DesignatedAmount float64 `json:"designated_amount,omitempty"` - CreditAmount float64 `json:"credit_amount,omitempty"` - MeasureUnit int64 `json:"measure_unit"` -} - -// 这里的余额指的是所有租户的总余额 -func (self *SHuaweiClient) QueryAccountBalance() (*SAccountBalance, error) { - domains, err := self.getEnabledDomains() - if err != nil { - return nil, err - } - - result := &SAccountBalance{} - for _, domain := range domains { - balances, err := self.queryDomainBalances(domain.ID) - if err != nil { - return nil, err - } - for _, balance := range balances { - result.AvailableAmount += balance.Amount - result.CreditAmount += balance.CreditAmount - result.DesignatedAmount += balance.DesignatedAmount - } - } - - return result, nil -} - -// https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0075213309.html -func (self *SHuaweiClient) queryDomainBalances(domainId string) ([]SBalance, error) { - huawei, _ := self.newGeneralAPIClient() - huawei.Balances.SetDomainId(domainId) - balances := make([]SBalance, 0) - err := doListAll(huawei.Balances.List, nil, &balances) - if err != nil { - return nil, err - } - - return balances, nil -} - -func (self *SHuaweiClient) GetVersion() string { - return HUAWEI_API_VERSION -} - -func (self *SHuaweiClient) GetAccessEnv() string { - switch self.cloudEnv { - case HUAWEI_INTERNATIONAL_CLOUDENV: - return api.CLOUD_ACCESS_ENV_HUAWEI_GLOBAL - case HUAWEI_CHINA_CLOUDENV: - return api.CLOUD_ACCESS_ENV_HUAWEI_CHINA - default: - return api.CLOUD_ACCESS_ENV_HUAWEI_GLOBAL - } -} - -func (self *SHuaweiClient) GetCapabilities() []string { - caps := []string{ - cloudprovider.CLOUD_CAPABILITY_PROJECT, - cloudprovider.CLOUD_CAPABILITY_COMPUTE, - cloudprovider.CLOUD_CAPABILITY_NETWORK, - cloudprovider.CLOUD_CAPABILITY_EIP, - cloudprovider.CLOUD_CAPABILITY_LOADBALANCER, - // cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE, - cloudprovider.CLOUD_CAPABILITY_RDS, - cloudprovider.CLOUD_CAPABILITY_CACHE, - cloudprovider.CLOUD_CAPABILITY_EVENT, - cloudprovider.CLOUD_CAPABILITY_CLOUDID, - cloudprovider.CLOUD_CAPABILITY_SAML_AUTH, - cloudprovider.CLOUD_CAPABILITY_NAT, - cloudprovider.CLOUD_CAPABILITY_NAS, - cloudprovider.CLOUD_CAPABILITY_QUOTA + cloudprovider.READ_ONLY_SUFFIX, - cloudprovider.CLOUD_CAPABILITY_MODELARTES, - } - // huawei objectstore is shared across projects(subscriptions) - // to avoid multiple project access the same bucket - // only main project is allow to access objectstore bucket - if self.isMainProject { - caps = append(caps, cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE) - } - return caps -} - -func (self *SHuaweiClient) GetUserId() (string, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetUserId.newGeneralAPIClient") - } - - type cred struct { - UserId string `json:"user_id"` - } - - ret := &cred{} - err = DoGet(client.Credentials.Get, self.accessKey, nil, ret) - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetUserId.DoGet") - } - - return ret.UserId, nil -} - -// owner id == domain_id == account id -func (self *SHuaweiClient) GetOwnerId() (string, error) { - userId, err := self.GetUserId() - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.GetUserId") - } - - client, err := self.newGeneralAPIClient() - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.newGeneralAPIClient") - } - - type user struct { - DomainId string `json:"domain_id"` - Name string `json:"name"` - CreateTime string - } - - ret := &user{} - err = DoGet(client.Users.Get, userId, nil, ret) - if err != nil { - return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.DoGet") - } - self.ownerName = ret.Name - // 2021-02-02 02:43:28.0 - self.ownerCreateTime, _ = timeutils.ParseTimeStr(strings.TrimSuffix(ret.CreateTime, ".0")) - return ret.DomainId, nil -} - -func (self *SHuaweiClient) initOwner() error { - ownerId, err := self.GetOwnerId() - if err != nil { - return errors.Wrap(err, "SHuaweiClient.initOwner") - } - - self.ownerId = ownerId - return nil -} - -func (self *SHuaweiClient) patchRequest(method httputils.THttpMethod, url string, query url.Values, params map[string]interface{}) (jsonutils.JSONObject, error) { - client := self.getAkClient() - if len(query) > 0 { - url = fmt.Sprintf("%s?%s", url, query.Encode()) - } - var body jsonutils.JSONObject = nil - if len(params) > 0 { - body = jsonutils.Marshal(params) - } - header := http.Header{} - if len(self.projectId) > 0 { - header.Set("X-Project-Id", self.projectId) - } - var bodystr string - if !gotypes.IsNil(body) { - bodystr = body.String() - } - jbody := strings.NewReader(bodystr) - header.Set("Content-Length", strconv.FormatInt(int64(len(bodystr)), 10)) - header.Set("Content-Type", "application/merge-patch+json") - resp, err := httputils.Request(client, context.Background(), method, url, header, jbody, self.debug) - _, respValue, err := httputils.ParseJSONResponse(bodystr, resp, err, self.debug) - if err != nil { - if e, ok := err.(*httputils.JSONClientError); ok && e.Code == 404 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, err.Error()) - } - return nil, err - } - return respValue, err -} diff --git a/pkg/multicloud/huawei/image.go b/pkg/multicloud/huawei/image.go deleted file mode 100644 index 1424723abf..0000000000 --- a/pkg/multicloud/huawei/image.go +++ /dev/null @@ -1,474 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type TImageOwnerType string - -const ( - ImageOwnerPublic TImageOwnerType = "gold" // 公共镜像:gold - ImageOwnerSelf TImageOwnerType = "private" // 私有镜像:private - ImageOwnerShared TImageOwnerType = "shared" // 共享镜像:shared - - EnvFusionCompute = "FusionCompute" - EnvIronic = "Ironic" -) - -const ( - ImageStatusQueued = "queued" // queued:表示镜像元数据已经创建成功,等待上传镜像文件。 - ImageStatusSaving = "saving" // saving:表示镜像正在上传文件到后端存储。 - ImageStatusDeleted = "deleted" // deleted:表示镜像已经删除。 - ImageStatusKilled = "killed" // killed:表示镜像上传错误。 - ImageStatusActive = "active" // active:表示镜像可以正常使用 -) - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091565.html -type SImage struct { - multicloud.SImageBase - multicloud.HuaweiTags - storageCache *SStoragecache - - // normalized image info - imgInfo *imagetools.ImageInfo - - Schema string `json:"schema"` - MinDiskGB int64 `json:"min_disk"` - CreatedAt time.Time `json:"created_at"` - ImageSourceType string `json:"__image_source_type"` - ContainerFormat string `json:"container_format"` - File string `json:"file"` - UpdatedAt time.Time `json:"updated_at"` - Protected bool `json:"protected"` - Checksum string `json:"checksum"` - ID string `json:"id"` - Isregistered string `json:"__isregistered"` - MinRamMB int `json:"min_ram"` - Lazyloading string `json:"__lazyloading"` - Owner string `json:"owner"` - OSType string `json:"__os_type"` - Imagetype string `json:"__imagetype"` - Visibility string `json:"visibility"` - VirtualEnvType string `json:"virtual_env_type"` - Platform string `json:"__platform"` - SizeGB int `json:"size"` - ImageSize int64 `json:"__image_size"` - OSBit string `json:"__os_bit"` - OSVersion string `json:"__os_version"` - Name string `json:"name"` - Self string `json:"self"` - DiskFormat string `json:"disk_format"` - Status string `json:"status"` - SupportKVMFPGAType string `json:"__support_kvm_fpga_type"` - SupportKVMNVMEHIGHIO string `json:"__support_nvme_highio"` - SupportLargeMemory string `json:"__support_largememory"` - SupportDiskIntensive string `json:"__support_diskintensive"` - SupportHighPerformance string `json:"__support_highperformance"` - SupportXENGPUType string `json:"__support_xen_gpu_type"` - SupportKVMGPUType string `json:"__support_kvm_gpu_type"` - SupportGPUT4 string `json:"__support_gpu_t4"` - SupportKVMAscend310 string `json:"__support_kvm_ascend_310"` - SupportArm string `json:"__support_arm"` -} - -func (self *SImage) GetMinRamSizeMb() int { - return self.MinRamMB -} - -func (self *SImage) GetId() string { - return self.ID -} - -func (self *SImage) GetName() string { - return self.Name -} - -func (self *SImage) GetGlobalId() string { - return self.ID -} - -func (self *SImage) GetStatus() string { - switch self.Status { - case ImageStatusQueued: - return api.CACHED_IMAGE_STATUS_CACHING - case ImageStatusActive: - return api.CACHED_IMAGE_STATUS_ACTIVE - case ImageStatusKilled: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - default: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (self *SImage) GetImageStatus() string { - switch self.Status { - case ImageStatusQueued: - return cloudprovider.IMAGE_STATUS_QUEUED - case ImageStatusActive: - return cloudprovider.IMAGE_STATUS_ACTIVE - case ImageStatusKilled: - return cloudprovider.IMAGE_STATUS_KILLED - default: - return cloudprovider.IMAGE_STATUS_KILLED - } -} - -func (self *SImage) Refresh() error { - new, err := self.storageCache.region.GetImage(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - switch self.Imagetype { - case "gold": - return cloudprovider.ImageTypeSystem - case "private": - return cloudprovider.ImageTypeCustomized - case "shared": - return cloudprovider.ImageTypeShared - default: - return cloudprovider.ImageTypeCustomized - } -} - -func (self *SImage) GetSizeByte() int64 { - return int64(self.MinDiskGB) * 1024 * 1024 * 1024 -} - -func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if self.imgInfo == nil { - arch := "x86" - if strings.ToLower(self.SupportArm) == "true" { - arch = "arm" - } - imgInfo := imagetools.NormalizeImageInfo(self.ImageSourceType, arch, self.OSType, self.Platform, "") - self.imgInfo = &imgInfo - } - - return self.imgInfo -} - -func (self *SImage) GetFullOsName() string { - return self.ImageSourceType -} - -func (self *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) -} - -func (self *SImage) GetOsDist() string { - return self.getNormalizedImageInfo().OsDistro -} - -func (self *SImage) GetOsVersion() string { - return self.getNormalizedImageInfo().OsVersion -} - -func (self *SImage) GetOsLang() string { - return self.getNormalizedImageInfo().OsLang -} - -func (self *SImage) GetOsArch() string { - return self.getNormalizedImageInfo().OsArch -} - -func (self *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return int(self.MinDiskGB) -} - -func (self *SImage) GetImageFormat() string { - return self.DiskFormat -} - -func (self *SImage) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SImage) IsEmulated() bool { - return false -} - -func (self *SImage) Delete(ctx context.Context) error { - return self.storageCache.region.DeleteImage(self.GetId()) -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.storageCache -} - -func (self *SRegion) GetImage(imageId string) (*SImage, error) { - image := &SImage{} - err := DoGet(self.ecsClient.Images.Get, imageId, nil, image) - if err != nil { - return nil, errors.Wrap(err, "DoGet") - } - return image, nil -} - -func excludeImage(image SImage) bool { - if image.VirtualEnvType == "Ironic" { - return true - } - - if len(image.SupportDiskIntensive) > 0 { - return true - } - - if len(image.SupportKVMFPGAType) > 0 || len(image.SupportKVMAscend310) > 0 { - return true - } - - if len(image.SupportKVMGPUType) > 0 { - return true - } - - if len(image.SupportKVMNVMEHIGHIO) > 0 { - return true - } - - if len(image.SupportGPUT4) > 0 { - return true - } - - if len(image.SupportXENGPUType) > 0 { - return true - } - - if len(image.SupportHighPerformance) > 0 { - return true - } - - if len(image.SupportArm) > 0 { - return true - } - - return false -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0060804959.html -func (self *SRegion) GetImages(status string, imagetype TImageOwnerType, name string, envType string) ([]SImage, error) { - queries := map[string]string{} - if len(status) > 0 { - queries["status"] = status - } - - if len(imagetype) > 0 { - queries["__imagetype"] = string(imagetype) - if imagetype == ImageOwnerPublic { - queries["protected"] = "True" - } - } - if len(envType) > 0 { - queries["virtual_env_type"] = envType - } - - if len(name) > 0 { - queries["name"] = name - } - - images := make([]SImage, 0) - err := doListAllWithMarker(self.ecsClient.Images.List, queries, &images) - - // 排除掉需要特定镜像才能创建的实例类型 - // https://support.huaweicloud.com/eu-west-0-api-ims/zh-cn_topic_0031617666.html#ZH-CN_TOPIC_0031617666__table48545918250 - // https://support.huaweicloud.com/productdesc-ecs/zh-cn_topic_0088142947.html - filtedImages := make([]SImage, 0) - for i := range images { - if !excludeImage(images[i]) { - filtedImages = append(filtedImages, images[i]) - } - } - - return filtedImages, err -} - -func (self *SRegion) DeleteImage(imageId string) error { - return DoDelete(self.ecsClient.OpenStackImages.Delete, imageId, nil, nil) -} - -func (self *SRegion) GetImageByName(name string) (*SImage, error) { - if len(name) == 0 { - return nil, fmt.Errorf("image name should not be empty") - } - - images, err := self.GetImages("", TImageOwnerType(""), name, "") - if err != nil { - return nil, err - } - if len(images) == 0 { - return nil, cloudprovider.ErrNotFound - } - - log.Debugf("%d image found match name %s", len(images), name) - return &images[0], nil -} - -/* https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html - os version 取值范围: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html - 用于创建私有镜像的源云服务器系统盘大小大于等于40GB且不超过1024GB。 - 目前支持vhd,zvhd、raw,qcow2 - todo: 考虑使用镜像快速导入。 https://support.huaweicloud.com/api-ims/zh-cn_topic_0133188204.html - 使用OBS文件创建镜像 - - * openstack原生接口支持的格式:https://support.huaweicloud.com/api-ims/zh-cn_topic_0031615566.html -*/ -func (self *SRegion) ImportImageJob(name string, osDist string, osVersion string, osArch string, bucket string, key string, minDiskGB int64) (string, error) { - os_version, err := stdVersion(osDist, osVersion, osArch) - log.Debugf("%s %s %s: %s.min_disk %d GB", osDist, osVersion, osArch, os_version, minDiskGB) - if err != nil { - log.Debugln(err) - } - - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(name), "name") - image_url := fmt.Sprintf("%s:%s", bucket, key) - params.Add(jsonutils.NewString(image_url), "image_url") - if len(os_version) > 0 { - params.Add(jsonutils.NewString(os_version), "os_version") - } - params.Add(jsonutils.NewBool(true), "is_config_init") - params.Add(jsonutils.NewBool(true), "is_config") - params.Add(jsonutils.NewInt(minDiskGB), "min_disk") - - ret, err := self.ecsClient.Images.PerformAction2("action", "", params, "") - if err != nil { - return "", err - } - - return ret.GetString("job_id") -} - -func formatVersion(osDist string, osVersion string) (string, error) { - err := fmt.Errorf("unsupport version %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osVersion) - dist := strings.ToLower(osDist) - if dist == "ubuntu" || dist == "redhat" || dist == "centos" || dist == "oracle" || dist == "euleros" { - parts := strings.Split(osVersion, ".") - if len(parts) < 2 { - return "", err - } - - return parts[0] + "." + parts[1], nil - } - - if dist == "debian" { - parts := strings.Split(osVersion, ".") - if len(parts) < 3 { - return "", err - } - - return parts[0] + "." + parts[1] + "." + parts[2], nil - } - - if dist == "fedora" || dist == "windows" || dist == "suse" { - parts := strings.Split(osVersion, ".") - if len(parts) < 1 { - return "", err - } - - return parts[0], nil - } - - if dist == "opensuse" { - parts := strings.Split(osVersion, ".") - if len(parts) == 0 { - return "", err - } - - if len(parts) == 1 { - return parts[0], nil - } - - if len(parts) >= 2 { - return parts[0] + "." + parts[1], nil - } - } - - return "", err -} - -// todo: 如何保持同步更新 -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html -func stdVersion(osDist string, osVersion string, osArch string) (string, error) { - // 架构 - arch := "" - switch osArch { - case "64", apis.OS_ARCH_X86_64: - arch = "64bit" - case "32", apis.OS_ARCH_X86_32: - arch = "32bit" - default: - return "", fmt.Errorf("unsupported arch %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osArch) - } - - _dist := strings.Split(strings.TrimSpace(osDist), " ")[0] - _dist = strings.ToLower(_dist) - // 版本 - ver, err := formatVersion(_dist, osVersion) - if err != nil { - return "", err - } - - // 操作系统 - dist := "" - - switch _dist { - case "ubuntu": - return fmt.Sprintf("Ubuntu %s server %s", ver, arch), nil - case "redhat": - dist = "Redhat Linux Enterprise" - case "centos": - dist = "CentOS" - case "fedora": - dist = "Fedora" - case "debian": - dist = "Debian GNU/Linux" - case "windows": - dist = "Windows Server" - case "oracle": - dist = "Oracle Linux Server release" - case "suse": - dist = "SUSE Linux Enterprise Server" - case "opensuse": - dist = "OpenSUSE" - case "euleros": - dist = "EulerOS" - default: - return "", fmt.Errorf("unsupported os %s. reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", dist) - } - - return fmt.Sprintf("%s %s %s", dist, ver, arch), nil -} diff --git a/pkg/multicloud/huawei/instance.go b/pkg/multicloud/huawei/instance.go deleted file mode 100644 index 0537792a17..0000000000 --- a/pkg/multicloud/huawei/instance.go +++ /dev/null @@ -1,1538 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "encoding/base64" - "fmt" - "sort" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/apis" - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/cloudinit" -) - -const ( - InstanceStatusRunning = "ACTIVE" - InstanceStatusTerminated = "DELETED" - InstanceStatusStopped = "SHUTOFF" -) - -type IpAddress struct { - Version string `json:"version"` - Addr string `json:"addr"` - OSEXTIPSMACMACAddr string `json:"OS-EXT-IPS-MAC:mac_addr"` - OSEXTIPSPortID string `json:"OS-EXT-IPS:port_id"` - OSEXTIPSType string `json:"OS-EXT-IPS:type"` -} - -type Flavor struct { - Disk string `json:"disk"` - Vcpus string `json:"vcpus"` - RAM string `json:"ram"` - ID string `json:"id"` - Name string `json:"name"` -} - -type Image struct { - ID string `json:"id"` -} - -type VMMetadata struct { - MeteringImageID string `json:"metering.image_id"` - MeteringImagetype string `json:"metering.imagetype"` - MeteringOrderId string `json:"metering.order_id"` - MeteringResourcespeccode string `json:"metering.resourcespeccode"` - ImageName string `json:"image_name"` - OSBit string `json:"os_bit"` - VpcID string `json:"vpc_id"` - MeteringResourcetype string `json:"metering.resourcetype"` - CascadedInstanceExtrainfo string `json:"cascaded.instance_extrainfo"` - OSType string `json:"os_type"` - ChargingMode string `json:"charging_mode"` -} - -type OSExtendedVolumesVolumesAttached struct { - Device string `json:"device"` - BootIndex string `json:"bootIndex"` - ID string `json:"id"` - DeleteOnTermination string `json:"delete_on_termination"` -} - -type OSSchedulerHints struct { -} - -type SecurityGroup struct { - Name string `json:"name"` -} - -type SysTag struct { - Key string `json:"key"` - Value string `json:"value"` -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html -// https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0100166287.html v1.1 支持创建包年/包月的弹性云服务器 -type SInstance struct { - multicloud.SInstanceBase - multicloud.HuaweiTags - - host *SHost - - image *SImage - - ID string `json:"id"` - Name string `json:"name"` - Addresses map[string][]IpAddress `json:"addresses"` - Flavor Flavor `json:"flavor"` - AccessIPv4 string `json:"accessIPv4"` - AccessIPv6 string `json:"accessIPv6"` - Status string `json:"status"` - Progress string `json:"progress"` - HostID string `json:"hostId"` - Image Image `json:"image"` - Updated string `json:"updated"` - Created time.Time `json:"created"` - Metadata VMMetadata `json:"metadata"` - Description string `json:"description"` - Locked bool `json:"locked"` - ConfigDrive string `json:"config_drive"` - TenantID string `json:"tenant_id"` - UserID string `json:"user_id"` - KeyName string `json:"key_name"` - - OSExtendedVolumesVolumesAttached []OSExtendedVolumesVolumesAttached `json:"os-extended-volumes:volumes_attached"` - OSEXTSTSTaskState string `json:"OS-EXT-STS:task_state"` - OSEXTSTSPowerState int64 `json:"OS-EXT-STS:power_state"` - OSEXTSTSVMState string `json:"OS-EXT-STS:vm_state"` - OSEXTSRVATTRHost string `json:"OS-EXT-SRV-ATTR:host"` - OSEXTSRVATTRInstanceName string `json:"OS-EXT-SRV-ATTR:instance_name"` - OSEXTSRVATTRHypervisorHostname string `json:"OS-EXT-SRV-ATTR:hypervisor_hostname"` - OSDCFDiskConfig string `json:"OS-DCF:diskConfig"` - OSEXTAZAvailabilityZone string `json:"OS-EXT-AZ:availability_zone"` - OSSchedulerHints OSSchedulerHints `json:"os:scheduler_hints"` - OSEXTSRVATTRRootDeviceName string `json:"OS-EXT-SRV-ATTR:root_device_name"` - OSEXTSRVATTRRamdiskID string `json:"OS-EXT-SRV-ATTR:ramdisk_id"` - EnterpriseProjectID string `json:"enterprise_project_id"` - OSEXTSRVATTRUserData string `json:"OS-EXT-SRV-ATTR:user_data"` - OSSRVUSGLaunchedAt time.Time `json:"OS-SRV-USG:launched_at"` - OSEXTSRVATTRKernelID string `json:"OS-EXT-SRV-ATTR:kernel_id"` - OSEXTSRVATTRLaunchIndex int64 `json:"OS-EXT-SRV-ATTR:launch_index"` - HostStatus string `json:"host_status"` - OSEXTSRVATTRReservationID string `json:"OS-EXT-SRV-ATTR:reservation_id"` - OSEXTSRVATTRHostname string `json:"OS-EXT-SRV-ATTR:hostname"` - OSSRVUSGTerminatedAt time.Time `json:"OS-SRV-USG:terminated_at"` - SysTags []SysTag `json:"sys_tags"` - SecurityGroups []SecurityGroup `json:"security_groups"` - EnterpriseProjectId string -} - -func compareSet(currentSet []string, newSet []string) (add []string, remove []string, keep []string) { - sort.Strings(currentSet) - sort.Strings(newSet) - - i, j := 0, 0 - for i < len(currentSet) || j < len(newSet) { - if i < len(currentSet) && j < len(newSet) { - if currentSet[i] == newSet[j] { - keep = append(keep, currentSet[i]) - i += 1 - j += 1 - } else if currentSet[i] < newSet[j] { - remove = append(remove, currentSet[i]) - i += 1 - } else { - add = append(add, newSet[j]) - j += 1 - } - } else if i >= len(currentSet) { - add = append(add, newSet[j]) - j += 1 - } else if j >= len(newSet) { - remove = append(remove, currentSet[i]) - i += 1 - } - } - - return add, remove, keep -} - -// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) -func isBootDisk(server *SInstance, disk *SDisk) bool { - if disk.GetDiskType() != api.DISK_TYPE_SYS { - return false - } - - for _, attachment := range disk.Attachments { - if attachment.ServerID == server.GetId() && attachment.Device == server.OSEXTSRVATTRRootDeviceName { - return true - } - } - - return false -} - -func (self *SInstance) GetId() string { - return self.ID -} - -func (self *SInstance) GetHostname() string { - return self.OSEXTSRVATTRHostname -} - -func (self *SInstance) GetName() string { - return self.Name -} - -func (self *SInstance) GetGlobalId() string { - return self.ID -} - -func (self *SInstance) GetStatus() string { - switch self.Status { - case "ACTIVE": - return api.VM_RUNNING - case "MIGRATING", "REBUILD", "BUILD", "RESIZE", "VERIFY_RESIZE": // todo: pending ? - return api.VM_STARTING - case "REBOOT", "HARD_REBOOT": - return api.VM_STOPPING - case "SHUTOFF": - return api.VM_READY - default: - return api.VM_UNKNOWN - } -} - -func (self *SInstance) Refresh() error { - new, err := self.host.zone.region.GetInstanceByID(self.GetId()) - new.host = self.host - if err != nil { - return err - } - - if new.Status == InstanceStatusTerminated { - log.Debugf("Instance already terminated.") - return cloudprovider.ErrNotFound - } - - err = jsonutils.Update(self, new) - if err != nil { - return err - } - return nil -} - -func (self *SInstance) IsEmulated() bool { - return false -} - -func (self *SInstance) GetInstanceType() string { - return self.Flavor.ID -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - return self.host.zone.region.GetInstanceSecrityGroupIds(self.GetId()) -} - -// https://support.huaweicloud.com/api-ecs/ecs_02_1002.html -// key 相同时value不会替换 -func (self *SRegion) CreateServerTags(instanceId string, tags map[string]string) error { - params := map[string]interface{}{ - "action": "create", - } - - tagsObj := []map[string]string{} - for k, v := range tags { - tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) - } - params["tags"] = tagsObj - - _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") - return err -} - -// https://support.huaweicloud.com/api-ecs/ecs_02_1003.html -func (self *SRegion) DeleteServerTags(instanceId string, tagsKey []string) error { - params := map[string]interface{}{ - "action": "delete", - } - tagsObj := []map[string]string{} - for _, k := range tagsKey { - tagsObj = append(tagsObj, map[string]string{"key": k}) - } - params["tags"] = tagsObj - - _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") - return err -} - -func (self *SInstance) SetTags(tags map[string]string, replace bool) error { - existedTags, err := self.GetTags() - if err != nil { - return errors.Wrap(err, "self.GetTags()") - } - deleteTagsKey := []string{} - for k := range existedTags { - if replace { - deleteTagsKey = append(deleteTagsKey, k) - } else { - if _, ok := tags[k]; ok { - deleteTagsKey = append(deleteTagsKey, k) - } - } - } - if len(deleteTagsKey) > 0 { - err := self.host.zone.region.DeleteServerTags(self.GetId(), deleteTagsKey) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.DeleteServerTags(%s,%s)", self.GetId(), deleteTagsKey) - } - } - if len(tags) > 0 { - err := self.host.zone.region.CreateServerTags(self.GetId(), tags) - if err != nil { - return errors.Wrapf(err, "self.host.zone.region.CreateServerTags(%s,%s)", self.GetId(), jsonutils.Marshal(tags).String()) - } - } - return nil -} - -func (self *SInstance) GetBillingType() string { - // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html - // charging_mode “0”:按需计费 “1”:按包年包月计费 - if self.Metadata.ChargingMode == "1" { - return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SInstance) GetCreatedAt() time.Time { - return self.Created -} - -// charging_mode “0”:按需计费 “1”:按包年包月计费 -func (self *SInstance) GetExpiredAt() time.Time { - if len(self.Metadata.MeteringOrderId) > 0 { - res, _ := self.host.zone.region.GetOrderResources(self.Metadata.MeteringOrderId, []string{self.ID}, true) - for i := range res { - return res[i].ExpireTime - } - } - var expiredTime time.Time - if self.Metadata.ChargingMode == "1" { - res, err := self.host.zone.region.GetOrderResourceDetail(self.GetId()) - if err != nil { - log.Debugln(err) - } - - expiredTime = res.ExpireTime - } - - return expiredTime -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - err := self.Refresh() - if err != nil { - return nil, err - } - - attached := self.OSExtendedVolumesVolumesAttached - disks := make([]SDisk, 0) - for _, vol := range attached { - disk, err := self.host.zone.region.GetDisk(vol.ID) - if err != nil { - return nil, err - } - - disks = append(disks, *disk) - } - - idisks := make([]cloudprovider.ICloudDisk, len(disks)) - for i := 0; i < len(disks); i += 1 { - storage, err := self.host.zone.getStorageByCategory(disks[i].VolumeType) - if err != nil { - return nil, err - } - disks[i].storage = storage - idisks[i] = &disks[i] - // 将系统盘放到第0个位置 - if isBootDisk(self, &disks[i]) { - _temp := idisks[0] - idisks[0] = &disks[i] - idisks[i] = _temp - } - } - return idisks, nil -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nics := make([]cloudprovider.ICloudNic, 0) - - // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html - // OS-EXT-IPS.type - // todo: 这里没有区分是IPv4 还是 IPv6。统一当IPv4处理了.可能会引发错误 - for _, ipAddresses := range self.Addresses { - for _, ipAddress := range ipAddresses { - if ipAddress.OSEXTIPSType == "fixed" { - nic := SInstanceNic{ - instance: self, - ipAddr: ipAddress.Addr, - macAddr: ipAddress.OSEXTIPSMACMACAddr, - } - nics = append(nics, &nic) - } - } - } - return nics, nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - ips := make([]string, 0) - for _, addresses := range self.Addresses { - for _, address := range addresses { - if address.OSEXTIPSType != "fixed" && !strings.HasPrefix(address.Addr, "100.") { - ips = append(ips, address.Addr) - } - } - } - - if len(ips) == 0 { - return nil, nil - } - - eips, err := self.host.zone.region.GetEips("", ips) - if err != nil { - return nil, err - } - if len(eips) > 0 { - return &eips[0], nil - } - return nil, nil -} - -func (self *SInstance) GetVcpuCount() int { - cpu, _ := strconv.Atoi(self.Flavor.Vcpus) - return cpu -} - -func (self *SInstance) GetVmemSizeMB() int { - mem, _ := strconv.Atoi(self.Flavor.RAM) - return int(mem) -} - -func (self *SInstance) GetBootOrder() string { - return "dcn" -} - -func (self *SInstance) GetVga() string { - return "std" -} - -func (self *SInstance) GetVdi() string { - return "vnc" -} - -func (i *SInstance) getImage() *SImage { - if i.image == nil && len(i.Image.ID) > 0 { - image, err := i.host.zone.region.GetImage(i.Image.ID) - if err == nil { - i.image = image - } else { - log.Debugf("GetOSArch.GetImage %s: %s", i.Image.ID, err) - } - } - return i.image -} - -func (self *SInstance) GetOsArch() string { - img := self.getImage() - if img != nil { - return img.GetOsArch() - } - - t := self.GetInstanceType() - if len(t) > 0 { - if strings.HasPrefix(t, "k") { - return apis.OS_ARCH_AARCH64 - } - } - - return apis.OS_ARCH_X86 -} - -func (self *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(osprofile.NormalizeOSType(self.Metadata.OSType)) -} - -func (self *SInstance) GetFullOsName() string { - return self.Metadata.ImageName -} - -func (self *SInstance) GetBios() cloudprovider.TBiosType { - img := self.getImage() - if img != nil { - return img.GetBios() - } - return cloudprovider.BIOS -} - -func (self *SInstance) GetOsDist() string { - img := self.getImage() - if img != nil { - return img.GetOsDist() - } - return "" -} - -func (self *SInstance) GetOsVersion() string { - img := self.getImage() - if img != nil { - return img.GetOsVersion() - } - return "" -} - -func (self *SInstance) GetOsLang() string { - img := self.getImage() - if img != nil { - return img.GetOsLang() - } - return "" -} - -func (self *SInstance) GetMachine() string { - return "pc" -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - return self.SetSecurityGroups([]string{secgroupId}) -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - currentSecgroups, err := self.host.zone.region.GetInstanceSecrityGroupIds(self.GetId()) - if err != nil { - return err - } - - add, remove, _ := compareSet(currentSecgroups, secgroupIds) - err = self.host.zone.region.assignSecurityGroups(add, self.GetId()) - if err != nil { - return err - } - - return self.host.zone.region.unassignSecurityGroups(remove, self.GetId()) -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_HUAWEI -} - -func (self *SInstance) StartVM(ctx context.Context) error { - if self.Status == InstanceStatusRunning { - return nil - } - - 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 - } - - if self.GetStatus() == api.VM_RUNNING { - return nil - } else if self.GetStatus() == api.VM_READY { - err := self.host.zone.region.StartVM(self.GetId()) - if err != nil { - return err - } - } - time.Sleep(interval) - } - return cloudprovider.ErrTimeout -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - if self.Status == InstanceStatusStopped { - return nil - } - - if self.Status == InstanceStatusTerminated { - log.Debugf("Instance already terminated.") - return nil - } - - err := self.host.zone.region.StopVM(self.GetId(), opts.IsForce) - if err != nil { - return err - } - return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - if self.Status == InstanceStatusTerminated { - return nil - } - - for { - err := self.host.zone.region.DeleteVM(self.GetId()) - if err != nil && self.Status != InstanceStatusTerminated { - log.Errorf("DeleteVM fail: %s", err) - return err - } else { - break - } - } - - return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return self.host.zone.region.UpdateVM(self.GetId(), name) -} - -// https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0032380449.html -// 创建云服务器过程中注入用户数据。支持注入文本、文本文件或gzip文件。 -// 注入内容,需要进行base64格式编码。注入内容(编码之前的内容)最大长度32KB。 -// 对于Linux弹性云服务器,adminPass参数传入时,user_data参数不生效。 -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html 使用原镜像重装 -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html 更换系统盘操作系统 -// 不支持调整系统盘大小 -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - var err error - var jobId string - - publicKeyName := "" - if len(desc.PublicKey) > 0 { - publicKeyName, err = self.host.zone.region.syncKeypair(desc.PublicKey) - if err != nil { - return "", err - } - } - - image, err := self.host.zone.region.GetImage(desc.ImageId) - if err != nil { - return "", errors.Wrap(err, "SInstance.RebuildRoot.GetImage") - } - - // Password存在的情况下,windows 系统直接使用密码 - if strings.ToLower(image.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(desc.Password) > 0 { - publicKeyName = "" - } - - userData, err := updateUserData(self.OSEXTSRVATTRUserData, image.OSVersion, desc.Account, desc.Password, desc.PublicKey) - if err != nil { - return "", errors.Wrap(err, "SInstance.RebuildRoot.updateUserData") - } - - if self.Metadata.MeteringImageID == desc.ImageId { - jobId, err = self.host.zone.region.RebuildRoot(ctx, self.UserID, self.GetId(), desc.Password, publicKeyName, userData) - if err != nil { - return "", err - } - } else { - jobId, err = self.host.zone.region.ChangeRoot(ctx, self.UserID, self.GetId(), desc.ImageId, desc.Password, publicKeyName, userData) - if err != nil { - return "", err - } - } - - err = self.host.zone.region.waitTaskStatus(self.host.zone.region.ecsClient.Servers.ServiceType(), jobId, TASK_SUCCESS, 15*time.Second, 900*time.Second) - if err != nil { - log.Errorf("RebuildRoot task error %s", err) - return "", err - } - - err = self.Refresh() - if err != nil { - return "", err - } - - idisks, err := self.GetIDisks() - if err != nil { - return "", err - } - - if len(idisks) == 0 { - return "", fmt.Errorf("server %s has no volume attached.", self.GetId()) - } - - return idisks[0].GetId(), nil -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return self.host.zone.region.DeployVM(self.GetId(), name, password, publicKey, deleteKeypair, description) -} - -func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - instanceTypes := []string{} - if len(config.InstanceType) > 0 { - instanceTypes = []string{config.InstanceType} - } else { - flavors, err := self.host.zone.region.GetMatchInstanceTypes(config.Cpu, config.MemoryMB, self.OSEXTAZAvailabilityZone) - if err != nil { - return errors.Wrapf(err, "GetMatchInstanceTypes") - } - for _, flavor := range flavors { - instanceTypes = append(instanceTypes, flavor.ID) - } - } - var err error - for _, instanceType := range instanceTypes { - err = self.host.zone.region.ChangeVMConfig(self.GetId(), instanceType) - if err != nil { - log.Warningf("ChangeVMConfig %s for %s error: %v", self.GetId(), instanceType, err) - } else { - return cloudprovider.WaitStatusWithDelay(self, api.VM_READY, 15*time.Second, 15*time.Second, 180*time.Second) - } - } - if err != nil { - return errors.Wrapf(err, "ChangeVMConfig") - } - return fmt.Errorf("Failed to change vm config, specification not supported") -} - -// todo:// 返回jsonobject感觉很诡异。不能直接知道内部细节 -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - return self.host.zone.region.GetInstanceVNCUrl(self.GetId()) -} - -func (self *SInstance) NextDeviceName() (string, error) { - prefix := "s" - if strings.Contains(self.OSEXTSRVATTRRootDeviceName, "/vd") { - prefix = "v" - } - - currents := []string{} - for _, item := range self.OSExtendedVolumesVolumesAttached { - currents = append(currents, strings.ToLower(item.Device)) - } - - for i := 0; i < 25; i++ { - device := fmt.Sprintf("/dev/%sd%s", prefix, string([]byte{byte(98 + i)})) - if ok, _ := utils.InStringArray(device, currents); !ok { - return device, nil - } - } - - return "", fmt.Errorf("disk devicename out of index, current deivces: %s", currents) -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - device, err := self.NextDeviceName() - if err != nil { - return errors.Wrap(err, "Instance.AttachDisk.NextDeviceName") - } - - err = self.host.zone.region.AttachDisk(self.GetId(), diskId, device) - if err != nil { - return errors.Wrap(err, "Instance.AttachDisk.AttachDisk") - } - - return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { - disk, err := self.host.zone.region.GetDisk(diskId) - if err != nil { - log.Debugf("Instance.AttachDisk.GetDisk %s", err) - return false, nil - } - - if disk.Status == "in-use" { - return true, nil - } - - return false, nil - }) -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - err := self.host.zone.region.DetachDisk(self.GetId(), diskId) - if err != nil { - return errors.Wrap(err, "Instance.DetachDisk") - } - - return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { - disk, err := self.host.zone.region.GetDisk(diskId) - if err != nil { - log.Debugf("Instance.DetachDisk.GetDisk %s", err) - return false, nil - } - - if disk.Status == "available" { - return true, nil - } - - return false, nil - }) -} - -func (self *SInstance) Renew(bc billing.SBillingCycle) error { - return self.host.zone.region.RenewInstance(self.GetId(), bc) -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148850.html -func (self *SRegion) GetInstances() ([]SInstance, error) { - queries := make(map[string]string) - - if len(self.client.projectId) > 0 { - queries["project_id"] = self.client.projectId - } - - instances := make([]SInstance, 0) - err := doListAllWithPagerOffset(self.ecsClient.Servers.List, queries, &instances) - return instances, err -} - -func (self *SRegion) GetInstanceByID(instanceId string) (SInstance, error) { - instance := SInstance{} - err := DoGet(self.ecsClient.Servers.Get, instanceId, nil, &instance) - return instance, err -} - -func (self *SRegion) GetInstanceByIds(ids []string) ([]SInstance, int, error) { - instances := make([]SInstance, 0) - for _, instanceId := range ids { - instance, err := self.GetInstanceByID(instanceId) - if err != nil { - return nil, 0, err - } - instances = append(instances, instance) - } - - return instances, len(instances), nil -} - -/* -系统盘大小取值范围:1-1024 GB,且必须不小于镜像min_disk. -*/ -type SServerCreate struct { - AvailabilityZone string `json:"availability_zone"` - Name string `json:"name"` - ImageRef string `json:"imageRef"` - RootVolume RootVolume `json:"root_volume"` - DataVolumes []DataVolume `json:"data_volumes"` - FlavorRef string `json:"flavorRef"` - UserData string `json:"user_data"` - Vpcid string `json:"vpcid"` - SecurityGroups []SecGroup `json:"security_groups"` - Nics []NIC `json:"nics"` - KeyName string `json:"key_name"` - AdminPass string `json:"adminPass"` - Count int64 `json:"count"` - Extendparam ServerExtendparam `json:"extendparam"` - ServerTags []ServerTag `json:"server_tags"` - Description string `json:"description"` - Metadata map[string]string `json:"metadata"` -} - -type DataVolume struct { - Volumetype string `json:"volumetype"` - SizeGB int `json:"size"` - Extendparam *DataVolumeExtendparam `json:"extendparam,omitempty"` - Multiattach *bool `json:"multiattach,omitempty"` - HwPassthrough *string `json:"hw:passthrough,omitempty"` -} - -type DataVolumeExtendparam struct { - SnapshotID string `json:"snapshotId"` -} - -type ServerExtendparam struct { - ChargingMode string `json:"chargingMode"` // 计费模式 prePaid|postPaid - PeriodType string `json:"periodType"` // 周期类型:month|year - PeriodNum string `json:"periodNum"` // 订购周期数:periodType=month(周期类型为月)时,取值为[1,9]。periodType=year(周期类型为年)时,取值为1。 - IsAutoRenew string `json:"isAutoRenew"` // 是否自动续订 true|false - IsAutoPay string `json:"isAutoPay"` // 是否自动从客户的账户中支付 true|false - RegionID string `json:"regionID"` - EnterpriseProjectId string `json:"enterprise_project_id,omitempty"` -} - -type NIC struct { - SubnetID string `json:"subnet_id"` // 网络ID. 与 SNetwork里的ID对应。统一使用这个ID - IpAddress string `json:"ip_address"` -} - -type RootVolume struct { - Volumetype string `json:"volumetype"` - SizeGB int `json:"size"` -} - -type SecGroup struct { - ID string `json:"id"` -} - -type ServerTag struct { - Key string `json:"key"` - Value string `json:"value"` -} - -/* -包月机器退订规则: https://support.huaweicloud.com/usermanual-billing/zh-cn_topic_0083138805.html -5天无理由全额退订:新购资源(不包含续费资源)在开通的五天内且退订次数不超过10次(每账号每年10次)的符合5天无理由全额退订。 -非5天无理由退订:不符合5天无理由全额退订条件的退订,都属于非5天无理由退订。非5天无理由退订,不限制退订次数,但需要收取退订手续费。 - -退订资源的方法: https://support.huaweicloud.com/usermanual-billing/zh-cn_topic_0072297197.html -*/ -func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, SubnetId string, - securityGroupId string, vpcId string, zoneId string, desc string, disks []SDisk, ipAddr string, - keypair string, publicKey string, passwd string, userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (string, error) { - params := SServerCreate{} - params.AvailabilityZone = zoneId - params.Name = name - params.FlavorRef = instanceType - params.ImageRef = imageId - params.Description = desc - params.Count = 1 - params.Nics = []NIC{{SubnetID: SubnetId, IpAddress: ipAddr}} - params.SecurityGroups = []SecGroup{{ID: securityGroupId}} - params.Vpcid = vpcId - params.Metadata = map[string]string{} - - for i, disk := range disks { - if i == 0 { - params.RootVolume.Volumetype = disk.VolumeType - params.RootVolume.SizeGB = disk.SizeGB - } else { - dataVolume := DataVolume{} - dataVolume.Volumetype = disk.VolumeType - dataVolume.SizeGB = disk.SizeGB - params.DataVolumes = append(params.DataVolumes, dataVolume) - } - } - - if len(projectId) > 0 { - params.Extendparam.EnterpriseProjectId = projectId - } - - // billing type - if bc != nil { - params.Extendparam.ChargingMode = PRE_PAID - if bc.GetMonths() <= 9 { - params.Extendparam.PeriodNum = strconv.Itoa(bc.GetMonths()) - params.Extendparam.PeriodType = "month" - } else { - params.Extendparam.PeriodNum = strconv.Itoa(bc.GetYears()) - params.Extendparam.PeriodType = "year" - } - - params.Extendparam.RegionID = self.GetId() - if bc.AutoRenew { - params.Extendparam.IsAutoRenew = "true" - } else { - params.Extendparam.IsAutoRenew = "false" - } - params.Extendparam.IsAutoPay = "true" - params.Metadata["op_svc_userid"] = self.client.ownerId - } else { - params.Extendparam.ChargingMode = POST_PAID - } - - // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212668.html#ZH-CN_TOPIC_0020212668__table761103195216 - if len(keypair) > 0 { - params.KeyName = keypair - } else { - params.AdminPass = passwd - } - - if len(userData) > 0 { - params.UserData = userData - } - - if len(tags) > 0 { - serverTags := []ServerTag{} - for k, v := range tags { - serverTags = append(serverTags, ServerTag{Key: k, Value: v}) - } - params.ServerTags = serverTags - } - - serverObj := jsonutils.Marshal(params) - createParams := jsonutils.NewDict() - createParams.Add(serverObj, "server") - _id, err := self.ecsClient.Servers.AsyncCreate(createParams) - if err != nil { - return "", err - } - - ids, err := self.GetAllSubTaskEntityIDs(self.ecsClient.Servers.ServiceType(), _id, "server_id") - if err != nil { - return "", errors.Wrapf(err, "GetAllSubTaskEntityIDs(%s)", _id) - } - - if len(ids) == 0 { - return "", fmt.Errorf("CreateInstance job %s result is emtpy", _id) - } - if len(ids) == 1 { - return ids[0], nil - } - return "", fmt.Errorf("CreateInstance job %s mutliple instance id returned. %s", _id, ids) -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067161469.html -// 添加多个安全组时,建议最多为弹性云服务器添加5个安全组。 -// todo: 确认是否需要先删除,再进行添加操作 -func (self *SRegion) assignSecurityGroups(secgroupIds []string, instanceId string) error { - _, err := self.GetInstanceByID(instanceId) - if err != nil { - return err - } - - for i := range secgroupIds { - secId := secgroupIds[i] - params := jsonutils.NewDict() - secgroupObj := jsonutils.NewDict() - secgroupObj.Add(jsonutils.NewString(secId), "name") - params.Add(secgroupObj, "addSecurityGroup") - - _, err := self.ecsClient.NovaServers.PerformAction("action", instanceId, params) - if err != nil { - return err - } - } - return nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067161717.html -func (self *SRegion) unassignSecurityGroups(secgroupIds []string, instanceId string) error { - for i := range secgroupIds { - secId := secgroupIds[i] - params := jsonutils.NewDict() - secgroupObj := jsonutils.NewDict() - secgroupObj.Add(jsonutils.NewString(secId), "name") - params.Add(secgroupObj, "removeSecurityGroup") - - _, err := self.ecsClient.NovaServers.PerformAction("action", instanceId, params) - if err != nil { - return err - } - } - return nil -} - -func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) { - instance, err := self.GetInstanceByID(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: %s", err) - return err - } - if status != remoteStatus { - log.Errorf("instanceStatusChecking: vm status is %s expect %s", remoteStatus, status) - return cloudprovider.ErrInvalidStatus - } - - return nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212207.html -func (self *SRegion) StartVM(instanceId string) error { - rstatus, err := self.GetInstanceStatus(instanceId) - if err != nil { - return err - } - - if rstatus == InstanceStatusRunning { - return nil - } - - if rstatus != InstanceStatusStopped { - log.Errorf("instanceStatusChecking: vm status is %s expect %s", rstatus, InstanceStatusStopped) - return cloudprovider.ErrInvalidStatus - } - - params := jsonutils.NewDict() - startObj := jsonutils.NewDict() - serversObj := jsonutils.NewArray() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(instanceId), "id") - serversObj.Add(serverObj) - startObj.Add(serversObj, "servers") - params.Add(startObj, "os-start") - _, err = self.ecsClient.Servers.PerformAction2("action", "", params, "") - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212651.html -func (self *SRegion) StopVM(instanceId string, isForce bool) error { - rstatus, err := self.GetInstanceStatus(instanceId) - if err != nil { - return err - } - - if rstatus == InstanceStatusStopped { - return nil - } - - if rstatus != InstanceStatusRunning { - log.Errorf("instanceStatusChecking: vm status is %s expect %s", rstatus, InstanceStatusRunning) - return cloudprovider.ErrInvalidStatus - } - - params := jsonutils.NewDict() - stopObj := jsonutils.NewDict() - serversObj := jsonutils.NewArray() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(instanceId), "id") - serversObj.Add(serverObj) - stopObj.Add(serversObj, "servers") - if isForce { - stopObj.Add(jsonutils.NewString("HARD"), "type") - } else { - stopObj.Add(jsonutils.NewString("SOFT"), "type") - } - params.Add(stopObj, "os-stop") - _, err = self.ecsClient.Servers.PerformAction2("action", "", params, "") - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212679.html -// 只删除主机。弹性IP和数据盘需要单独删除 -func (self *SRegion) DeleteVM(instanceId string) error { - remoteStatus, err := self.GetInstanceStatus(instanceId) - if err != nil { - return err - } - - if remoteStatus != InstanceStatusStopped { - log.Errorf("DeleteVM vm status is %s expect %s", remoteStatus, InstanceStatusStopped) - return cloudprovider.ErrInvalidStatus - } - - params := jsonutils.NewDict() - serversObj := jsonutils.NewArray() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(instanceId), "id") - serversObj.Add(serverObj) - params.Add(serversObj, "servers") - params.Add(jsonutils.NewBool(false), "delete_publicip") - params.Add(jsonutils.NewBool(false), "delete_volume") - - _, err = self.ecsClient.Servers.PerformAction2("delete", "", params, "") - return err -} - -func (self *SRegion) UpdateVM(instanceId, name string) error { - params := jsonutils.NewDict() - serverObj := jsonutils.NewDict() - serverObj.Add(jsonutils.NewString(name), "name") - params.Add(serverObj, "server") - - _, err := self.ecsClient.Servers.Update(instanceId, params) - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html -// 返回job id -func (self *SRegion) RebuildRoot(ctx context.Context, userId, instanceId, passwd, publicKeyName, userData string) (string, error) { - params := jsonutils.NewDict() - reinstallObj := jsonutils.NewDict() - - if len(publicKeyName) > 0 { - reinstallObj.Add(jsonutils.NewString(publicKeyName), "keyname") - } else if len(passwd) > 0 { - reinstallObj.Add(jsonutils.NewString(passwd), "adminpass") - } else { - return "", fmt.Errorf("both password and publicKey are empty.") - } - - if len(userData) > 0 { - meta := jsonutils.NewDict() - meta.Add(jsonutils.NewString(userData), "user_data") - reinstallObj.Add(meta, "metadata") - } - - if len(userId) > 0 { - reinstallObj.Add(jsonutils.NewString(userId), "userid") - } - - params.Add(reinstallObj, "os-reinstall") - ret, err := self.ecsClient.ServersV2.PerformAction2("reinstallos", instanceId, params, "") - if err != nil { - return "", err - } - - return ret.GetString("job_id") -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html -// 返回job id -func (self *SRegion) ChangeRoot(ctx context.Context, userId, instanceId, imageId, passwd, publicKeyName, userData string) (string, error) { - params := jsonutils.NewDict() - changeOsObj := jsonutils.NewDict() - - if len(publicKeyName) > 0 { - changeOsObj.Add(jsonutils.NewString(publicKeyName), "keyname") - } else if len(passwd) > 0 { - changeOsObj.Add(jsonutils.NewString(passwd), "adminpass") - } else { - return "", fmt.Errorf("both password and publicKey are empty.") - } - - if len(userData) > 0 { - meta := jsonutils.NewDict() - meta.Add(jsonutils.NewString(userData), "user_data") - changeOsObj.Add(meta, "metadata") - } - - if len(userId) > 0 { - changeOsObj.Add(jsonutils.NewString(userId), "userid") - } - - changeOsObj.Add(jsonutils.NewString(imageId), "imageid") - params.Add(changeOsObj, "os-change") - - ret, err := self.ecsClient.ServersV2.PerformAction2("changeos", instanceId, params, "") - if err != nil { - return "", err - } - - return ret.GetString("job_id") -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212692.html -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0110109377.html -// 一键式重置密码 需要安装安装一键式重置密码插件 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0068095385.html -// 目前不支持直接重置密钥 -func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { - serverObj := jsonutils.NewDict() - if len(name) > 0 { - serverObj.Add(jsonutils.NewString(name), "name") - } - - // if len(description) > 0 { - // serverObj.Add(jsonutils.NewString(description), "description") - // } - - if serverObj.Size() > 0 { - params := jsonutils.NewDict() - params.Add(serverObj, "server") - // 这里华为返回的image字段是字符串。和SInstance的定义的image是字典结构不一致。 - err := DoUpdate(self.ecsClient.NovaServers.Update, instanceId, params, nil) - if err != nil { - return err - } - } - - if len(password) > 0 { - params := jsonutils.NewDict() - passwdObj := jsonutils.NewDict() - passwdObj.Add(jsonutils.NewString(password), "new_password") - params.Add(passwdObj, "reset-password") - - err := DoUpdateWithSpec(self.ecsClient.NovaServers.UpdateInContextWithSpec, instanceId, "os-reset-password", params) - if err != nil { - return err - } - } - - return nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212653.html -func (self *SRegion) ChangeVMConfig(instanceId string, instanceType string) error { - self.ecsClient.Servers.SetVersion("v1.1") - defer self.ecsClient.Servers.SetVersion("v1") - - params := jsonutils.NewDict() - resizeObj := jsonutils.NewDict() - resizeObj.Add(jsonutils.NewString(instanceType), "flavorRef") - params.Add(resizeObj, "resize") - _, err := self.ecsClient.Servers.PerformAction2("resize", instanceId, params, "") - return errors.Wrapf(err, "PerformAction2(resize)") -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0142763126.html 微版本2.6及以上? -// https://support.huaweicloud.com/api-ecs/ecs_02_0208.html -func (self *SRegion) GetInstanceVNCUrl(instanceId string) (*cloudprovider.ServerVncOutput, error) { - params := jsonutils.NewDict() - vncObj := jsonutils.NewDict() - vncObj.Add(jsonutils.NewString("novnc"), "type") - vncObj.Add(jsonutils.NewString("vnc"), "protocol") - params.Add(vncObj, "remote_console") - - ret, err := self.ecsClient.Servers.PerformAction2("remote_console", instanceId, params, "remote_console") - if err != nil { - return nil, err - } - - result := &cloudprovider.ServerVncOutput{ - Hypervisor: api.HYPERVISOR_HUAWEI, - } - ret.Unmarshal(result) - result.Protocol = "huawei" - return result, nil -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022472987.html -// XEN平台虚拟机device为必选参数。 -func (self *SRegion) AttachDisk(instanceId string, diskId string, device string) error { - params := jsonutils.NewDict() - volumeObj := jsonutils.NewDict() - volumeObj.Add(jsonutils.NewString(diskId), "volumeId") - if len(device) > 0 { - volumeObj.Add(jsonutils.NewString(device), "device") - } - - params.Add(volumeObj, "volumeAttachment") - - _, err := self.ecsClient.Servers.PerformAction2("attachvolume", instanceId, params, "") - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022472988.html -// 默认非强制卸载。delete_flag=0 -func (self *SRegion) DetachDisk(instanceId string, diskId string) error { - path := fmt.Sprintf("detachvolume/%s", diskId) - err := DoDeleteWithSpec(self.ecsClient.Servers.DeleteInContextWithSpec, nil, instanceId, path, nil, nil) - //volume a2091934-2669-4fca-8eb4-a950c1836b3c is not in server 49b053d2-f798-432f-af55-76eb6ef2c769 attach volume list => 磁盘已经被卸载了 - if err != nil && strings.Contains(err.Error(), fmt.Sprintf("is not in server")) && strings.Contains(err.Error(), fmt.Sprintf("attach volume list")) { - return nil - } - return err -} - -// // https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0082522029.html -// 只支持传入主资源ID, 根据“查询客户包周期资源列表”接口响应参数中的“is_main_resource”来标识。 -// expire_mode 0:进入宽限期 1:转按需 2:自动退订 3:自动续订(当前只支持ECS、EVS和VPC) -func (self *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle) error { - params := jsonutils.NewDict() - res := jsonutils.NewArray() - res.Add(jsonutils.NewString(instanceId)) - params.Add(res, "resource_ids") - params.Add(jsonutils.NewInt(EXPIRE_MODE_AUTO_UNSUBSCRIBE), "expire_mode") // 自动退订 - params.Add(jsonutils.NewInt(AUTO_PAY_TRUE), "isAutoPay") // 自动支付 - month := int64(bc.GetMonths()) - year := int64(bc.GetYears()) - - if month >= 1 && month <= 11 { - params.Add(jsonutils.NewInt(PERIOD_TYPE_MONTH), "period_type") - params.Add(jsonutils.NewInt(month), "period_num") - } else if year >= 1 && year <= 3 { - params.Add(jsonutils.NewInt(PERIOD_TYPE_YEAR), "period_type") - params.Add(jsonutils.NewInt(year), "period_num") - } else { - return fmt.Errorf("invalid renew period %d month,must be 1~11 month or 1~3 year", month) - } - - domainId, err := self.getDomianId() - if err != nil { - return err - } - - err = self.ecsClient.Orders.SetDomainId(domainId) - if err != nil { - return err - } - - _, err = self.ecsClient.Orders.RenewPeriodResource(params) - return err -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817702.html -func (self *SRegion) GetInstanceSecrityGroupIds(instanceId string) ([]string, error) { - if len(instanceId) == 0 { - return nil, fmt.Errorf("GetInstanceSecrityGroups instanceId is empty") - } - - securitygroups := make([]SSecurityGroup, 0) - ctx := &modules.SManagerContext{InstanceManager: self.ecsClient.NovaServers, InstanceId: instanceId} - err := DoListInContext(self.ecsClient.NovaSecurityGroups.ListInContext, ctx, nil, &securitygroups) - if err != nil { - return nil, err - } - - securitygroupIds := []string{} - for _, secgroup := range securitygroups { - securitygroupIds = append(securitygroupIds, secgroup.GetId()) - } - - return securitygroupIds, nil -} - -// https://support.huaweicloud.com/api-oce/zh-cn_topic_0082522030.html -func (self *SRegion) UnsubscribeInstance(instanceId string, domianId string) (jsonutils.JSONObject, error) { - unsubObj := jsonutils.NewDict() - unsubObj.Add(jsonutils.NewInt(1), "unSubType") - unsubObj.Add(jsonutils.NewInt(5), "unsubscribeReasonType") - unsubObj.Add(jsonutils.NewString("no reason"), "unsubscribeReason") - resList := jsonutils.NewArray() - resList.Add(jsonutils.NewString(instanceId)) - unsubObj.Add(resList, "resourceIds") - - self.ecsClient.Orders.SetDomainId(domianId) - return self.ecsClient.Orders.PerformAction("resources/delete", "", unsubObj) -} - -func (self *SInstance) GetProjectId() string { - return self.EnterpriseProjectId -} - -func (self *SInstance) GetError() error { - return nil -} - -func updateUserData(userData, osVersion, username, password, publicKey string) (string, error) { - winOS := strings.ToLower(osprofile.OS_TYPE_WINDOWS) - osVersion = strings.ToLower(osVersion) - config := &cloudinit.SCloudConfig{} - if strings.Contains(osVersion, winOS) { - if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { - config = _config - } else { - log.Debugf("updateWindowsUserData invalid userdata %s", userData) - } - } else { - if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { - config = _config - } else { - return "", fmt.Errorf("updateLinuxUserData invalid userdata %s", userData) - } - } - - user := cloudinit.NewUser(username) - config.RemoveUser(user) - config.DisableRoot = 0 - if len(password) > 0 { - config.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON - user.Password(password) - config.MergeUser(user) - } - - if len(publicKey) > 0 { - user.SshKey(publicKey) - config.MergeUser(user) - } - - if strings.Contains(osVersion, winOS) { - userData, err := updateWindowsUserData(config.UserDataPowerShell(), osVersion, username, password) - if err != nil { - return "", errors.Wrap(err, "updateUserData.updateWindowsUserData") - } - return userData, nil - } else { - return config.UserDataBase64(), nil - } -} - -func updateWindowsUserData(userData string, osVersion string, username, password string) (string, error) { - // Windows Server 2003, Windows Vista, Windows Server 2008, Windows Server 2003 R2, Windows Server 2000, Windows Server 2012, Windows Server 2003 with SP1, Windows 8 - oldVersions := []string{"2000", "2003", "2008", "2012", "Vista"} - isOldVersion := false - for i := range oldVersions { - if strings.Contains(osVersion, oldVersions[i]) { - isOldVersion = true - } - } - - shells := "" - if isOldVersion { - shells += fmt.Sprintf("rem cmd\n") - if username == "Administrator" { - shells += fmt.Sprintf("net user %s %s\n", username, password) - } else { - shells += fmt.Sprintf("net user %s %s /add\n", username, password) - shells += fmt.Sprintf("net localgroup administrators %s /add\n", username) - } - - shells += fmt.Sprintf("net user %s /active:yes", username) - } else { - if !strings.HasPrefix(userData, "#ps1") { - shells = fmt.Sprintf("#ps1\n%s", userData) - } - } - - return base64.StdEncoding.EncodeToString([]byte(shells)), nil -} - -func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { - params := map[string]string{ - "name": opts.Name, - "instance_id": instanceId, - } - if len(opts.Notes) > 0 { - params["description"] = func() string { - opts.Notes = strings.ReplaceAll(opts.Notes, "<", "") - opts.Notes = strings.ReplaceAll(opts.Notes, ">", "") - opts.Notes = strings.ReplaceAll(opts.Notes, "\n", "") - if len(opts.Notes) > 1024 { - opts.Notes = opts.Notes[:1024] - } - return opts.Notes - }() - } - resp, err := self.ecsClient.Images.CreateInContextWithSpec(nil, "action", jsonutils.Marshal(params), "") - if err != nil { - return nil, errors.Wrapf(err, "Images.Create") - } - jobId, err := resp.GetString("job_id") - if err != nil { - return nil, errors.Wrapf(err, "resp.GetString(job_id)") - } - err = self.waitTaskStatus(self.ecsClient.Images.ServiceType(), jobId, TASK_SUCCESS, 15*time.Second, 10*time.Minute) - if err != nil { - return nil, errors.Wrapf(err, "waitTaskStatus") - } - imageId, err := self.GetTaskEntityID(self.ecsClient.Images.ServiceType(), jobId, "image_id") - if err != nil { - return nil, errors.Wrapf(err, "GetTaskEntityID") - } - image, err := self.GetImage(imageId) - if err != nil { - return nil, errors.Wrapf(err, "GetImage(%s)", imageId) - } - image.storageCache = self.getStoragecache() - return image, nil -} - -func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { - image, err := self.host.zone.region.SaveImage(self.ID, opts) - if err != nil { - return nil, errors.Wrapf(err, "SaveImage") - } - return image, nil -} diff --git a/pkg/multicloud/huawei/instancenic.go b/pkg/multicloud/huawei/instancenic.go deleted file mode 100644 index d1041ac6f7..0000000000 --- a/pkg/multicloud/huawei/instancenic.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules" -) - -// =========================================== -type Interface struct { - PortState string `json:"port_state"` - FixedIPS []FixedIP `json:"fixed_ips"` - NetID string `json:"net_id"` // 网络ID. 与 SNetwork里的ID对应。统一使用这个ID - PortID string `json:"port_id"` - MACAddr string `json:"mac_addr"` -} - -/* -subnet: {id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233", name: "subnet-149c", cidr: "192.168.0.0/24",…} -availability_zone: "cn-north-1b" -cidr: "192.168.0.0/24" -dhcp_enable: true -dnsList: ["100.125.1.250", "100.125.21.250"] -gateway_ip: "192.168.0.1" -id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233" -ipv6_enable: false -name: "subnet-149c" -neutron_network_id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233" -neutron_subnet_id: "81fcfaa0-8e73-4472-9eba-3b2b7736d3a7" -primary_dns: "100.125.1.250" -secondary_dns: "100.125.21.250" -status: "ACTIVE" -tags: [] -vpc_id: "877f1feb-3dc8-4c2d-92e9-0d94fd7d79dd"} -*/ -type FixedIP struct { - SubnetID string `json:"subnet_id"` // 子网ID, 与SNetwork中的 neutron_subnet_id对应. 注意!!! 并不是SNetwork ID。 - IPAddress string `json:"ip_address"` -} - -// =========================================== - -type SInstanceNic struct { - instance *SInstance - ipAddr string - macAddr string - - cloudprovider.DummyICloudNic -} - -func (self *SInstanceNic) GetId() string { - return "" -} - -func (self *SInstanceNic) GetIP() string { - return self.ipAddr -} - -func (self *SInstanceNic) GetMAC() string { - return self.macAddr -} - -func (self *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (self *SInstanceNic) GetINetworkId() string { - instanceId := self.instance.GetId() - subnets, err := self.instance.host.zone.region.getSubnetIdsByInstanceId(instanceId) - if err != nil || len(subnets) == 0 { - log.Errorf("getSubnetIdsByInstanceId error: %s", err.Error()) - return "" - } - - return subnets[0] -} - -func (self *SRegion) getSubnetIdsByInstanceId(instanceId string) ([]string, error) { - ctx := &modules.SManagerContext{InstanceManager: self.ecsClient.NovaServers, InstanceId: instanceId} - interfaces := make([]Interface, 0) - err := DoListInContext(self.ecsClient.Interface.ListInContext, ctx, nil, &interfaces) - if err != nil { - return nil, err - } - - subnets := make([]string, 0) - for _, i := range interfaces { - subnets = append(subnets, i.NetID) - } - - return subnets, nil -} diff --git a/pkg/multicloud/huawei/latitud_and_longitude.go b/pkg/multicloud/huawei/latitud_and_longitude.go deleted file mode 100644 index d6ec366c55..0000000000 --- a/pkg/multicloud/huawei/latitud_and_longitude.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -// China: https://developer.huaweicloud.com/endpoint -// International: https://developer-intl.huaweicloud.com/endpoint -// ref: https://countrycode.org -var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ - "cn-east-2": api.RegionShanghai, - "cn-east-3": api.RegionShanghai, - "cn-north-1": api.RegionBeijing, - "cn-north-4": api.RegionBeijing, - "cn-south-1": api.RegionGuangzhou, - "cn-south-2": api.RegionGuangzhou, - "ap-southeast-1": api.RegionHongkong, - "ap-southeast-2": api.RegionBangkok, - "ap-southeast-3": api.RegionSingapore, - "eu-west-0": api.RegionParis, - "cn-northeast-1": api.RegionDalian, - "cn-southwest-2": api.RegionGuiyang, - "af-south-1": api.RegionJohannesburg, - "sa-brazil-1": api.RegionSaoPaulo, - "na-mexico-1": api.RegionMexico, - "la-south-2": api.RegionSantiago, - "cn-north-9": api.RegionNeimenggu, - "cn-north-219": api.RegionBeijing, -} diff --git a/pkg/multicloud/huawei/loadbalancer.go b/pkg/multicloud/huawei/loadbalancer.go deleted file mode 100644 index 1e382af968..0000000000 --- a/pkg/multicloud/huawei/loadbalancer.go +++ /dev/null @@ -1,625 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "fmt" - "net/url" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var LB_ALGORITHM_MAP = map[string]string{ - api.LB_SCHEDULER_WRR: "ROUND_ROBIN", - api.LB_SCHEDULER_WLC: "LEAST_CONNECTIONS", - api.LB_SCHEDULER_SCH: "SOURCE_IP", -} - -var LB_PROTOCOL_MAP = map[string]string{ - api.LB_LISTENER_TYPE_HTTP: "HTTP", - api.LB_LISTENER_TYPE_HTTPS: "TERMINATED_HTTPS", - api.LB_LISTENER_TYPE_UDP: "UDP", - api.LB_LISTENER_TYPE_TCP: "TCP", -} - -var LBBG_PROTOCOL_MAP = map[string]string{ - api.LB_LISTENER_TYPE_HTTP: "HTTP", - api.LB_LISTENER_TYPE_HTTPS: "HTTP", - api.LB_LISTENER_TYPE_UDP: "UDP", - api.LB_LISTENER_TYPE_TCP: "TCP", -} - -var LB_STICKY_SESSION_MAP = map[string]string{ - api.LB_STICKY_SESSION_TYPE_INSERT: "HTTP_COOKIE", - api.LB_STICKY_SESSION_TYPE_SERVER: "APP_COOKIE", -} - -var LB_HEALTHCHECK_TYPE_MAP = map[string]string{ - api.LB_HEALTH_CHECK_HTTP: "HTTP", - api.LB_HEALTH_CHECK_TCP: "TCP", - api.LB_HEALTH_CHECK_UDP: "UDP_CONNECT", -} - -type SLoadbalancer struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - subnet *SNetwork - eip *SEipAddress - - Description string `json:"description"` - ProvisioningStatus string `json:"provisioning_status"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - AdminStateUp bool `json:"admin_state_up"` - Provider string `json:"provider"` - Pools []Pool `json:"pools"` - Listeners []Listener `json:"listeners"` - VipPortID string `json:"vip_port_id"` - OperatingStatus string `json:"operating_status"` - VipAddress string `json:"vip_address"` - VipSubnetID string `json:"vip_subnet_id"` - ID string `json:"id"` - Name string `json:"name"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` -} - -type Listener struct { - ID string `json:"id"` -} - -type Pool struct { - ID string `json:"id"` -} - -func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { - if self.GetEip() == nil { - return nil, nil - } - - return self.eip, nil -} - -func (self *SLoadbalancer) GetId() string { - return self.ID -} - -func (self *SLoadbalancer) GetName() string { - return self.Name -} - -func (self *SLoadbalancer) GetGlobalId() string { - return self.ID -} - -func (self *SLoadbalancer) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLoadbalancer) Refresh() error { - lb, err := self.region.GetLoadbalancer(self.GetId()) - if err != nil { - return err - } - - return jsonutils.Update(self, lb) -} - -func (self *SLoadbalancer) IsEmulated() bool { - return false -} - -func (self *SLoadbalancer) GetProjectId() string { - return self.ProjectID -} - -func (self *SLoadbalancer) GetAddress() string { - return self.VipAddress -} - -// todo: api.LB_ADDR_TYPE_INTERNET? -func (self *SLoadbalancer) GetAddressType() string { - return api.LB_ADDR_TYPE_INTRANET -} - -func (self *SLoadbalancer) GetNetworkType() string { - return api.LB_NETWORK_TYPE_VPC -} - -func (self *SLoadbalancer) GetNetworkIds() []string { - net := self.GetNetwork() - if net != nil { - return []string{net.GetId()} - } - - return []string{} -} - -func (self *SLoadbalancer) GetNetwork() *SNetwork { - if self.subnet == nil { - port, err := self.region.GetPort(self.VipPortID) - if err == nil { - net, err := self.region.getNetwork(port.NetworkID) - if err == nil { - self.subnet = net - } else { - log.Debugf("huawei.SLoadbalancer.getNetwork %s", err) - } - } else { - log.Debugf("huawei.SLoadbalancer.GetPort %s", err) - } - } - - return self.subnet -} - -func (self *SLoadbalancer) GetEip() *SEipAddress { - if self.eip == nil { - eips, _ := self.region.GetEips(self.VipPortID, nil) - for i := range eips { - self.eip = &eips[i] - } - } - return self.eip -} - -func (self *SLoadbalancer) GetVpcId() string { - net := self.GetNetwork() - if net != nil { - return net.VpcID - } - - return "" -} - -func (self *SLoadbalancer) GetZoneId() string { - net := self.GetNetwork() - if net != nil { - z, err := self.region.getZoneById(net.AvailabilityZone) - if err != nil { - log.Infof("getZoneById %s %s", net.AvailabilityZone, err) - return "" - } - - return z.GetGlobalId() - } - - return "" -} - -func (self *SLoadbalancer) GetZone1Id() string { - return "" -} - -func (self *SLoadbalancer) GetLoadbalancerSpec() string { - return "" -} - -func (self *SLoadbalancer) GetChargeType() string { - eip := self.GetEip() - if eip != nil { - return eip.GetInternetChargeType() - } - - return api.EIP_CHARGE_TYPE_BY_TRAFFIC -} - -func (self *SLoadbalancer) GetEgressMbps() int { - eip := self.GetEip() - if eip != nil { - return eip.GetBandwidth() - } - - return 0 -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0141008275.html -func (self *SLoadbalancer) Delete(ctx context.Context) error { - return self.region.DeleteLoadBalancer(self.GetId()) -} - -func (self *SLoadbalancer) Start() error { - return nil -} - -func (self *SLoadbalancer) Stop() error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - ret, err := self.region.GetLoadBalancerListeners(self.GetId()) - if err != nil { - return nil, err - } - - iret := make([]cloudprovider.ICloudLoadbalancerListener, 0) - for i := range ret { - listener := ret[i] - listener.lb = self - iret = append(iret, &listener) - } - - return iret, nil -} - -func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - ret, err := self.region.GetLoadBalancerBackendGroups(self.GetId()) - if err != nil { - return nil, err - } - - iret := make([]cloudprovider.ICloudLoadbalancerBackendGroup, 0) - for i := range ret { - bg := ret[i] - bg.lb = self - bg.region = self.region - iret = append(iret, &bg) - } - - return iret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561549.html -func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - ret, err := self.region.CreateLoadBalancerBackendGroup(group) - ret.lb = self - return &ret, err -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561563.html -func (self *SLoadbalancer) CreateHealthCheck(backendGroupId string, healthcheck *cloudprovider.SLoadbalancerHealthCheck) error { - _, err := self.region.CreateLoadBalancerHealthCheck(backendGroupId, healthcheck) - return err -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561548.html -func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - ret := &SElbBackendGroup{lb: self, region: self.region} - resp, err := self.region.lbGet("elb/pools/" + groupId) - if err != nil { - return nil, err - } - return ret, resp.Unmarshal(ret, "pool") -} - -func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - ret, err := self.region.CreateLoadBalancerListener(listener) - if err != nil { - return nil, err - } - - ret.lb = self - return &ret, nil -} - -func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { - ret := &SElbListener{lb: self} - resp, err := self.region.lbGet("elb/listeners/" + listenerId) - if err != nil { - return nil, err - } - return ret, resp.Unmarshal(ret, "listener") -} - -func (self *SRegion) GetLoadbalancer(id string) (*SLoadbalancer, error) { - resp, err := self.lbGet("elb/loadbalancers/" + id) - if err != nil { - return nil, err - } - ret := &SLoadbalancer{region: self} - return ret, resp.Unmarshal(ret, "loadbalancer") -} - -func (self *SRegion) DeleteLoadBalancer(elbId string) error { - resource := fmt.Sprintf("elb/loadbalancers/%s", elbId) - _, err := self.lbDelete(resource) - return err -} - -func (self *SRegion) GetLoadBalancerListeners(lbId string) ([]SElbListener, error) { - ret := []SElbListener{} - params := url.Values{} - if len(lbId) > 0 { - params.Set("loadbalancer_id", lbId) - } - return ret, self.lbListAll("elb/listeners", params, "listeners", &ret) -} - -func (self *SRegion) CreateLoadBalancerListener(listener *cloudprovider.SLoadbalancerListener) (SElbListener, error) { - params := map[string]interface{}{ - "name": listener.Name, - "description": listener.Description, - "protocol": LB_PROTOCOL_MAP[listener.ListenerType], - "protocol_port": listener.ListenerPort, - "loadbalancer_id": listener.LoadbalancerID, - "http2_enable": listener.EnableHTTP2, - } - if len(listener.BackendGroupID) > 0 { - params["default_pool_id"] = listener.BackendGroupID - } - - if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { - params["default_tls_container_ref"] = listener.CertificateID - } - - if listener.XForwardedFor { - params["insert_headers"] = map[string]interface{}{ - "X-Forwarded-ELB-IP": listener.XForwardedFor, - } - } - - ret := SElbListener{} - resp, err := self.lbCreate("lb/listeners", map[string]interface{}{"listener": params}) - if err != nil { - return ret, err - } - return ret, resp.Unmarshal(&ret, "listener") -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html -func (self *SRegion) GetLoadBalancerBackendGroups(elbId string) ([]SElbBackendGroup, error) { - query := url.Values{} - if len(elbId) > 0 { - query.Set("loadbalancer_id", elbId) - } - - ret := []SElbBackendGroup{} - return ret, self.lbListAll("elb/pools", query, "pools", &ret) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html -func (self *SRegion) CreateLoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (SElbBackendGroup, error) { - ret := SElbBackendGroup{region: self} - var protocol, scheduler string - if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { - return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) - } else { - scheduler = s - } - - if t, ok := LBBG_PROTOCOL_MAP[group.ListenType]; !ok { - return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported listener type %s", group.ListenType) - } else { - protocol = t - } - - params := map[string]interface{}{ - "project_id": self.client.projectId, - "name": group.Name, - "protocol": protocol, - "lb_algorithm": scheduler, - } - - if len(group.ListenerID) > 0 { - params["listener_id"] = group.ListenerID - } else if len(group.LoadbalancerID) > 0 { - params["loadbalancer_id"] = group.LoadbalancerID - } else { - return ret, fmt.Errorf("CreateLoadBalancerBackendGroup one of listener id / loadbalancer id must be specified") - } - - if group.StickySession != nil { - s := map[string]interface{}{} - timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) - if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { - s["type"] = "SOURCE_IP" - if timeout > 0 { - s["persistence_timeout"] = timeout - } - } else { - s["type"] = LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType] - if len(group.StickySession.StickySessionCookie) > 0 { - s["cookie_name"] = group.StickySession.StickySessionCookie - } else { - if timeout > 0 { - s["persistence_timeout"] = timeout - } - } - } - params["session_persistence"] = s - } - resp, err := self.lbCreate("elb/pools", map[string]interface{}{"pool": params}) - if err != nil { - return ret, err - } - err = resp.Unmarshal(&ret, "pool") - if err != nil { - return ret, err - } - - if group.HealthCheck != nil { - _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) - if err != nil { - return ret, err - } - } - - return ret, nil -} - -func (self *SRegion) CreateLoadBalancerHealthCheck(backendGroupID string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { - params := map[string]interface{}{ - "delay": healthCheck.HealthCheckInterval, - "max_retries": healthCheck.HealthCheckRise, - "pool_id": backendGroupID, - "timeout": healthCheck.HealthCheckTimeout, - "type": LB_HEALTHCHECK_TYPE_MAP[healthCheck.HealthCheckType], - } - if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { - if len(healthCheck.HealthCheckDomain) > 0 { - params["domain_name"] = healthCheck.HealthCheckDomain - } - - if len(healthCheck.HealthCheckURI) > 0 { - params["url_path"] = healthCheck.HealthCheckURI - } - - if len(healthCheck.HealthCheckHttpCode) > 0 { - params["expected_codes"] = ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode) - } - } - - ret := SElbHealthCheck{region: self} - resp, err := self.lbCreate("elb/healthmonitors", map[string]interface{}{"healthmonitor": params}) - if err != nil { - return ret, err - } - - return ret, resp.Unmarshal(&ret, "healthmonitor") -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561564.html -func (self *SRegion) UpdateLoadBalancerHealthCheck(healthCheckID string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { - params := map[string]interface{}{ - "delay": healthCheck.HealthCheckInterval, - "max_retries": healthCheck.HealthCheckRise, - "timeout": healthCheck.HealthCheckTimeout, - } - if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { - if len(healthCheck.HealthCheckDomain) > 0 { - params["domain_name"] = healthCheck.HealthCheckDomain - } - - if len(healthCheck.HealthCheckURI) > 0 { - params["url_path"] = healthCheck.HealthCheckURI - } - - if len(healthCheck.HealthCheckHttpCode) > 0 { - params["expected_codes"] = ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode) - } - } - - ret := SElbHealthCheck{region: self} - resp, err := self.lbUpdate("elb/healthmonitors/"+healthCheckID, map[string]interface{}{"healthmonitor": params}) - if err != nil { - return ret, err - } - return ret, resp.Unmarshal(&ret, "healthmonitor") -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561565.html -func (self *SRegion) DeleteLoadbalancerHealthCheck(healthCheckID string) error { - _, err := self.lbDelete("elb/healthmonitors/" + healthCheckID) - return err -} - -func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) lbList(resource string, query url.Values) (jsonutils.JSONObject, error) { - return self.client.lbList(self.ID, resource, query) -} - -func (self *SRegion) vpcList(resource string, query url.Values) (jsonutils.JSONObject, error) { - return self.client.vpcList(self.ID, resource, query) -} - -func (self *SRegion) vpcCreate(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - return self.client.vpcCreate(self.ID, resource, params) -} - -func (self *SRegion) vpcGet(resource string) (jsonutils.JSONObject, error) { - return self.client.vpcGet(self.ID, resource) -} - -func (self *SRegion) vpcDelete(resource string) (jsonutils.JSONObject, error) { - return self.client.vpcDelete(self.ID, resource) -} - -func (self *SRegion) vpcUpdate(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - return self.client.vpcUpdate(self.ID, resource, params) -} - -func (self *SRegion) lbListAll(resource string, query url.Values, respKey string, retVal interface{}) error { - ret := jsonutils.NewArray() - for { - resp, err := self.lbList(resource, query) - if err != nil { - return err - } - arr, err := resp.GetArray(respKey) - if err != nil { - return errors.Wrapf(err, "get %s", respKey) - } - ret.Add(arr...) - marker, _ := resp.GetString("page_info", "next_marker") - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return ret.Unmarshal(retVal) -} - -func (self *SRegion) lbGet(resource string) (jsonutils.JSONObject, error) { - return self.client.lbGet(self.ID, resource) -} - -func (self *SRegion) lbDelete(resource string) (jsonutils.JSONObject, error) { - return self.client.lbDelete(self.ID, resource) -} - -func (self *SRegion) lbCreate(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - return self.client.lbCreate(self.ID, resource, params) -} - -func (self *SRegion) lbUpdate(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { - return self.client.lbUpdate(self.ID, resource, params) -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561535.html -func (self *SRegion) CreateLoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (*SLoadbalancer, error) { - subnet, err := self.getNetwork(loadbalancer.NetworkIDs[0]) - if err != nil { - return nil, errors.Wrap(err, "SRegion.CreateLoadBalancer.getNetwork") - } - - params := map[string]interface{}{ - "name": loadbalancer.Name, - "vip_subnet_id": subnet.NeutronSubnetID, - "tenant_id": self.client.projectId, - } - if len(loadbalancer.Address) > 0 { - params["vip_address"] = loadbalancer.Address - } - resp, err := self.lbCreate("elb/loadbalancers", map[string]interface{}{"loadbalancer": params}) - if err != nil { - return nil, err - } - ret := &SLoadbalancer{region: self} - err = resp.Unmarshal(ret, "loadbalancer") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - - // 创建公网类型ELB - if len(loadbalancer.EipID) > 0 { - err := self.AssociateEipWithPortId(loadbalancer.EipID, ret.VipPortID) - if err != nil { - return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.AssociateEipWithPortId") - } - } - return ret, nil -} diff --git a/pkg/multicloud/huawei/loadbalancer_acl.go b/pkg/multicloud/huawei/loadbalancer_acl.go deleted file mode 100644 index 5170e2f1f9..0000000000 --- a/pkg/multicloud/huawei/loadbalancer_acl.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "net/url" - "strings" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbACL struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - - ID string `json:"id"` - ListenerID string `json:"listener_id"` - TenantID string `json:"tenant_id"` - EnableWhitelist bool `json:"enable_whitelist"` - Whitelist string `json:"whitelist"` -} - -func (self *SElbACL) GetAclListenerID() string { - return self.ListenerID -} - -func (self *SElbACL) GetId() string { - return self.ID -} - -func (self *SElbACL) GetName() string { - return self.ID -} - -func (self *SElbACL) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbACL) GetStatus() string { - if self.EnableWhitelist { - return api.LB_BOOL_ON - } - - return api.LB_BOOL_OFF -} - -func (self *SElbACL) Refresh() error { - acl, err := self.region.GetLoadBalancerAcl(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, acl) -} - -func (self *SElbACL) IsEmulated() bool { - return false -} - -func (self *SElbACL) GetProjectId() string { - return "" -} - -func (self *SElbACL) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { - ret := []cloudprovider.SLoadbalancerAccessControlListEntry{} - for _, cidr := range strings.Split(self.Whitelist, ",") { - ret = append(ret, cloudprovider.SLoadbalancerAccessControlListEntry{CIDR: cidr}) - } - - return ret -} - -func (self *SElbACL) Sync(acl *cloudprovider.SLoadbalancerAccessControlList) error { - whiteList := "" - cidrs := []string{} - for _, entry := range acl.Entrys { - cidrs = append(cidrs, entry.CIDR) - } - whiteList = strings.Join(cidrs, ",") - params := map[string]interface{}{ - "whitelist": whiteList, - "enable_whitelist": acl.AccessControlEnable, - } - _, err := self.region.lbUpdate("elb/whitelists/"+self.GetId(), map[string]interface{}{"whitelist": params}) - return err -} - -func (self *SElbACL) Delete() error { - _, err := self.region.lbDelete("elb/whitelists/" + self.GetId()) - return err -} - -func (self *SRegion) GetLoadBalancerAcl(aclId string) (*SElbACL, error) { - resp, err := self.lbGet("elb/whitelists/" + aclId) - if err != nil { - return nil, err - } - ret := &SElbACL{region: self} - return ret, resp.Unmarshal(ret, "whitelist") -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561582.html -func (self *SRegion) GetLoadBalancerAcls(listenerId string) ([]SElbACL, error) { - query := url.Values{} - if len(listenerId) > 0 { - query.Set("listener_id", listenerId) - } - resp, err := self.lbList("elb/whitelists", query) - if err != nil { - return nil, err - } - ret := []SElbACL{} - return ret, resp.Unmarshal(&ret, "whitelists") -} - -func (self *SRegion) CreateLoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (*SElbACL, error) { - params := map[string]interface{}{ - "listener_id": acl.ListenerId, - } - if len(acl.Entrys) > 0 { - whitelist := []string{} - for i := range acl.Entrys { - whitelist = append(whitelist, acl.Entrys[i].CIDR) - } - params["enable_whitelist"] = acl.AccessControlEnable - params["whitelist"] = strings.Join(whitelist, ",") - } else { - params["enable_whitelist"] = false - } - resp, err := self.lbCreate("elb/whitelists", map[string]interface{}{"whitelist": params}) - if err != nil { - return nil, err - } - ret := &SElbACL{region: self} - return ret, resp.Unmarshal(ret, "whitelist") -} diff --git a/pkg/multicloud/huawei/loadbalancer_backend.go b/pkg/multicloud/huawei/loadbalancer_backend.go deleted file mode 100644 index 09f7f4a5d3..0000000000 --- a/pkg/multicloud/huawei/loadbalancer_backend.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbBackend struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - lb *SLoadbalancer - backendGroup *SElbBackendGroup - - Name string `json:"name"` - Weight int `json:"weight"` - AdminStateUp bool `json:"admin_state_up"` - SubnetID string `json:"subnet_id"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - Address string `json:"address"` - ProtocolPort int `json:"protocol_port"` - OperatingStatus string `json:"operating_status"` - ID string `json:"id"` -} - -func (self *SElbBackend) GetId() string { - return self.ID -} - -func (self *SElbBackend) GetName() string { - return self.Name -} - -func (self *SElbBackend) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbBackend) Refresh() error { - backend, err := self.region.GetElbBackend(self.backendGroup.GetId(), self.ID) - if err != nil { - return err - } - return jsonutils.Update(self, backend) -} - -func (self *SElbBackend) IsEmulated() bool { - return false -} - -func (self *SElbBackend) GetProjectId() string { - return "" -} - -func (self *SElbBackend) GetWeight() int { - return self.Weight -} - -func (self *SElbBackend) GetPort() int { - return self.ProtocolPort -} - -func (self *SElbBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (self *SElbBackend) GetBackendRole() string { - return api.LB_BACKEND_ROLE_DEFAULT -} - -func (self *SElbBackend) GetBackendId() string { - i, err := self.lb.region.getInstanceByIP(self.Address) - if err != nil { - log.Errorf("ElbBackend GetBackendId %s", err) - } - - if i != nil { - return i.GetId() - } - - return "" -} - -func (self *SElbBackend) GetIpAddress() string { - return "" -} - -func (self *SElbBackend) SyncConf(ctx context.Context, port, weight int) error { - if port > 0 { - log.Warningf("Elb backend SyncConf unsupport modify port") - } - - params := map[string]interface{}{ - "weight": weight, - } - res := fmt.Sprintf("elb/pools/%s/members/%s", self.backendGroup.GetId(), self.ID) - _, err := self.region.lbUpdate(res, map[string]interface{}{"member": params}) - return err -} - -func (self *SRegion) getInstanceByIP(privateIP string) (*SInstance, error) { - queries := make(map[string]string) - - if len(self.client.projectId) > 0 { - queries["project_id"] = self.client.projectId - } - - if len(privateIP) > 0 { - queries["ip"] = privateIP - } - - instances := make([]SInstance, 0) - err := doListAllWithOffset(self.ecsClient.Servers.List, queries, &instances) - if err != nil { - return nil, err - } - - if len(instances) == 1 { - return &instances[0], nil - } else if len(instances) > 1 { - log.Warningf("SRegion.getInstanceByIP %s result: multiple server find", privateIP) - return &instances[0], nil - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetElbBackend(pool, id string) (*SElbBackend, error) { - res := fmt.Sprintf("elb/pools/%s/members/%s", pool, id) - resp, err := self.lbGet(res) - if err != nil { - return nil, err - } - ret := &SElbBackend{region: self} - return ret, resp.Unmarshal(ret, "member") -} diff --git a/pkg/multicloud/huawei/loadbalancer_backendgroup.go b/pkg/multicloud/huawei/loadbalancer_backendgroup.go deleted file mode 100644 index a7bcfc2b49..0000000000 --- a/pkg/multicloud/huawei/loadbalancer_backendgroup.go +++ /dev/null @@ -1,509 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbBackendGroup struct { - multicloud.SResourceBase - multicloud.HuaweiTags - lb *SLoadbalancer - region *SRegion - - LBAlgorithm string `json:"lb_algorithm"` - Protocol string `json:"protocol"` - Description string `json:"description"` - AdminStateUp bool `json:"admin_state_up"` - Loadbalancers []Listener `json:"loadbalancers"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - Listeners []Listener `json:"listeners"` - ID string `json:"id"` - Name string `json:"name"` - HealthMonitorID string `json:"healthmonitor_id"` - SessionPersistence StickySession `json:"session_persistence"` -} - -func (self *SElbBackendGroup) GetLoadbalancerId() string { - return self.lb.GetId() -} - -func (self *SElbBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { - return self.lb -} - -type StickySession struct { - Type string `json:"type"` - CookieName string `json:"cookie_name"` - PersistenceTimeout int `json:"persistence_timeout"` -} - -func (self *SElbBackendGroup) GetProtocolType() string { - switch self.Protocol { - case "TCP": - return api.LB_LISTENER_TYPE_TCP - case "UDP": - return api.LB_LISTENER_TYPE_UDP - case "HTTP": - return api.LB_LISTENER_TYPE_HTTP - default: - return "" - } -} - -func (self *SElbBackendGroup) GetScheduler() string { - switch self.LBAlgorithm { - case "ROUND_ROBIN": - return api.LB_SCHEDULER_WRR - case "LEAST_CONNECTIONS": - return api.LB_SCHEDULER_WLC - case "SOURCE_IP": - return api.LB_SCHEDULER_SCH - default: - return "" - } -} - -func ToHuaweiHealthCheckHttpCode(c string) string { - c = strings.TrimSpace(c) - segs := strings.Split(c, ",") - ret := []string{} - for _, seg := range segs { - seg = strings.TrimLeft(seg, "http_") - seg = strings.TrimSpace(seg) - seg = strings.Replace(seg, "xx", "00", -1) - ret = append(ret, seg) - } - - return strings.Join(ret, ",") -} - -func ToOnecloudHealthCheckHttpCode(c string) string { - c = strings.TrimSpace(c) - segs := strings.Split(c, ",") - ret := []string{} - for _, seg := range segs { - seg = strings.TrimSpace(seg) - seg = strings.Replace(seg, "00", "xx", -1) - seg = "http_" + seg - ret = append(ret, seg) - } - - return strings.Join(ret, ",") -} - -func (self *SElbBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - if len(self.HealthMonitorID) == 0 { - return nil, nil - } - - health, err := self.region.GetLoadBalancerHealthCheck(self.HealthMonitorID) - if err != nil { - return nil, err - } - - var healthCheckType string - switch health.Type { - case "TCP": - healthCheckType = api.LB_HEALTH_CHECK_TCP - case "UDP_CONNECT": - healthCheckType = api.LB_HEALTH_CHECK_UDP - case "HTTP": - healthCheckType = api.LB_HEALTH_CHECK_HTTP - default: - healthCheckType = "" - } - - ret := cloudprovider.SLoadbalancerHealthCheck{ - HealthCheckType: healthCheckType, - HealthCheckTimeout: health.Timeout, - HealthCheckDomain: health.DomainName, - HealthCheckURI: health.URLPath, - HealthCheckInterval: health.Delay, - HealthCheckRise: health.MaxRetries, - HealthCheckHttpCode: ToOnecloudHealthCheckHttpCode(health.ExpectedCodes), - } - - return &ret, nil -} - -func (self *SElbBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - if len(self.SessionPersistence.Type) == 0 { - return nil, nil - } - - var stickySessionType string - switch self.SessionPersistence.Type { - case "SOURCE_IP": - stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT - case "HTTP_COOKIE": - stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT - case "APP_COOKIE": - stickySessionType = api.LB_STICKY_SESSION_TYPE_SERVER - } - - ret := cloudprovider.SLoadbalancerStickySession{ - StickySession: api.LB_BOOL_ON, - StickySessionCookie: self.SessionPersistence.CookieName, - StickySessionType: stickySessionType, - StickySessionCookieTimeout: self.SessionPersistence.PersistenceTimeout * 60, - } - - return &ret, nil -} - -func (self *SElbBackendGroup) GetId() string { - return self.ID -} - -func (self *SElbBackendGroup) GetName() string { - return self.Name -} - -func (self *SElbBackendGroup) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbBackendGroup) Refresh() error { - ret, err := self.lb.region.GetLoadBalancerBackendGroupId(self.GetId()) - if err != nil { - return err - } - ret.lb = self.lb - - err = jsonutils.Update(self, ret) - if err != nil { - return err - } - - return nil -} - -func (self *SElbBackendGroup) IsEmulated() bool { - return false -} - -func (self *SElbBackendGroup) GetProjectId() string { - return self.ProjectID -} - -func (self *SElbBackendGroup) IsDefault() bool { - return false -} - -func (self *SElbBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_NORMAL -} - -func (self *SElbBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - ret, err := self.region.GetLoadBalancerBackends(self.GetId()) - if err != nil { - return nil, err - } - - iret := []cloudprovider.ICloudLoadbalancerBackend{} - for i := range ret { - backend := ret[i] - backend.lb = self.lb - backend.backendGroup = self - - iret = append(iret, &backend) - } - - return iret, nil -} - -func (self *SElbBackendGroup) GetILoadbalancerBackendById(serverId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - backend, err := self.region.GetElbBackend(self.GetId(), serverId) - if err != nil { - return nil, err - } - backend.lb = self.lb - backend.backendGroup = self - return backend, nil -} - -func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - instance, err := self.lb.region.GetInstanceByID(serverId) - if err != nil { - return nil, err - } - - nics, err := instance.GetINics() - if err != nil { - return nil, err - } else if len(nics) == 0 { - return nil, fmt.Errorf("AddBackendServer %s no network interface found", serverId) - } - - subnets, err := self.lb.region.getSubnetIdsByInstanceId(instance.GetId()) - if err != nil { - return nil, err - } else if len(subnets) == 0 { - return nil, fmt.Errorf("AddBackendServer %s no subnet found", serverId) - } - - net, err := self.lb.region.getNetwork(subnets[0]) - if err != nil { - return nil, err - } - - backend, err := self.region.AddLoadBalancerBackend(self.GetId(), net.NeutronSubnetID, nics[0].GetIP(), port, weight) - if err != nil { - return nil, err - } - - backend.lb = self.lb - backend.backendGroup = self - return backend, nil -} - -func (self *SElbBackendGroup) RemoveBackendServer(backendId string, weight int, port int) error { - ibackend, err := self.GetILoadbalancerBackendById(backendId) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - - return errors.Wrap(err, "ElbBackendGroup.GetILoadbalancerBackendById") - } - - err = self.region.RemoveLoadBalancerBackend(self.GetId(), backendId) - if err != nil { - return errors.Wrap(err, "ElbBackendGroup.RemoveBackendServer") - } - - return cloudprovider.WaitDeleted(ibackend, 2*time.Second, 30*time.Second) -} - -func (self *SElbBackendGroup) Delete(ctx context.Context) error { - if len(self.HealthMonitorID) > 0 { - err := self.region.DeleteLoadbalancerHealthCheck(self.HealthMonitorID) - if err != nil { - return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadbalancerHealthCheck") - } - } - - // 删除后端服务器组的同时,删除掉无效的后端服务器数据 - { - backends, err := self.region.getLoadBalancerAdminStateDownBackends(self.GetId()) - if err != nil { - return errors.Wrap(err, "SElbBackendGroup.Delete.getLoadBalancerAdminStateDownBackends") - } - - for i := range backends { - backend := backends[i] - err := self.RemoveBackendServer(backend.GetId(), backend.GetPort(), backend.GetWeight()) - if err != nil { - return errors.Wrap(err, "SElbBackendGroup.Delete.RemoveBackendServer") - } - } - } - - err := self.region.DeleteLoadBalancerBackendGroup(self.GetId()) - if err != nil { - return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadBalancerBackendGroup") - } - - return cloudprovider.WaitDeleted(self, 2*time.Second, 30*time.Second) -} - -func (self *SElbBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - if group == nil { - return nil - } - - _, err := self.region.UpdateLoadBalancerBackendGroup(self.GetId(), group) - return err -} - -func (self *SRegion) GetLoadBalancerBackendGroupId(backendGroupId string) (*SElbBackendGroup, error) { - ret := &SElbBackendGroup{region: self} - res := fmt.Sprintf("elb/pools/" + backendGroupId) - resp, err := self.lbGet(res) - if err != nil { - return nil, err - } - return ret, resp.Unmarshal(ret, "pool") -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561550.html -func (self *SRegion) UpdateLoadBalancerBackendGroup(backendGroupID string, group *cloudprovider.SLoadbalancerBackendGroup) (*SElbBackendGroup, error) { - params := map[string]interface{}{ - "name": group.Name, - } - var scheduler string - if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { - return nil, fmt.Errorf("UpdateLoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) - } else { - scheduler = s - } - params["lb_algorithm"] = scheduler - - if group.StickySession == nil || group.StickySession.StickySession == api.LB_BOOL_OFF { - params["session_persistence"] = jsonutils.JSONNull - } else { - s := map[string]interface{}{} - timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) - if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { - s["type"] = "SOURCE_IP" - if timeout > 0 { - s["persistence_timeout"] = timeout - } - } else { - s["type"] = LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType] - if len(group.StickySession.StickySessionCookie) > 0 { - s["cookie_name"] = group.StickySession.StickySessionCookie - } else { - if timeout > 0 { - s["persistence_timeout"] = timeout - } - } - } - params["session_persistence"] = s - } - resp, err := self.lbUpdate("elb/pools/"+backendGroupID, map[string]interface{}{"pool": params}) - if err != nil { - return nil, err - } - - ret := &SElbBackendGroup{} - err = resp.Unmarshal(ret, "pool") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - - if group.HealthCheck == nil && len(ret.HealthMonitorID) > 0 { - err := self.DeleteLoadbalancerHealthCheck(ret.HealthMonitorID) - if err != nil { - return ret, errors.Wrap(err, "DeleteLoadbalancerHealthCheck") - } - } - - if group.HealthCheck != nil { - if len(ret.HealthMonitorID) == 0 { - _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) - if err != nil { - return ret, errors.Wrap(err, "CreateLoadBalancerHealthCheck") - } - } else { - _, err := self.UpdateLoadBalancerHealthCheck(ret.HealthMonitorID, group.HealthCheck) - if err != nil { - return ret, errors.Wrap(err, "UpdateLoadBalancerHealthCheck") - } - } - } - - ret.region = self - return ret, nil -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561551.html -func (self *SRegion) DeleteLoadBalancerBackendGroup(id string) error { - _, err := self.lbDelete("elb/pools/" + id) - return err -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561556.html -func (self *SRegion) AddLoadBalancerBackend(backendGroupId, subnetId, ipaddr string, port, weight int) (*SElbBackend, error) { - params := map[string]interface{}{ - "address": ipaddr, - "protocol_port": port, - "subnet_id": subnetId, - "weight": weight, - } - ret := &SElbBackend{} - resp, err := self.lbCreate(fmt.Sprintf("elb/pools/%s/members", backendGroupId), map[string]interface{}{"member": params}) - if err != nil { - return nil, err - } - return ret, resp.Unmarshal(ret, "member") -} - -func (self *SRegion) RemoveLoadBalancerBackend(lbbgId string, backendId string) error { - _, err := self.lbDelete(fmt.Sprintf("elb/pools/%s/members/%s", lbbgId, backendId)) - return err -} - -func (self *SRegion) getLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { - res := fmt.Sprintf("elb/pools/%s/members", backendGroupId) - resp, err := self.lbList(res, url.Values{}) - if err != nil { - return nil, err - } - ret := []SElbBackend{} - return ret, resp.Unmarshal(&ret, "members") -} - -func (self *SRegion) GetLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { - ret, err := self.getLoadBalancerBackends(backendGroupId) - if err != nil { - return nil, errors.Wrap(err, "SRegion.GetLoadBalancerBackends.getLoadBalancerBackends") - } - - // 过滤掉服务器已经被删除的backend。原因是运管平台查询不到已删除的服务器记录,导致同步出错。产生肮数据。 - filtedRet := []SElbBackend{} - for i := range ret { - if ret[i].AdminStateUp { - backend := ret[i] - filtedRet = append(filtedRet, backend) - } - } - - return filtedRet, nil -} - -func (self *SRegion) getLoadBalancerAdminStateDownBackends(backendGroupId string) ([]SElbBackend, error) { - ret, err := self.getLoadBalancerBackends(backendGroupId) - if err != nil { - return nil, errors.Wrap(err, "SRegion.getLoadBalancerAdminStateDownBackends.getLoadBalancerBackends") - } - - filtedRet := []SElbBackend{} - for i := range ret { - if !ret[i].AdminStateUp { - backend := ret[i] - filtedRet = append(filtedRet, backend) - } - } - - return filtedRet, nil -} - -func (self *SRegion) GetLoadBalancerHealthCheck(healthCheckId string) (*SElbHealthCheck, error) { - resp, err := self.lbGet("elb/healthmonitors/" + healthCheckId) - if err != nil { - return nil, err - } - ret := &SElbHealthCheck{region: self} - return ret, resp.Unmarshal(ret, "healthmonitor") -} diff --git a/pkg/multicloud/huawei/loadbalancer_cert.go b/pkg/multicloud/huawei/loadbalancer_cert.go deleted file mode 100644 index b750477e4b..0000000000 --- a/pkg/multicloud/huawei/loadbalancer_cert.go +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "crypto/sha1" - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbCert struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - - Certificate string `json:"certificate"` - CreateTime time.Time `json:"create_time"` - ExpireTime time.Time `json:"expire_time"` - Description string `json:"description"` - Domain string `json:"domain"` - ID string `json:"id"` - AdminStateUp bool `json:"admin_state_up"` - TenantID string `json:"tenant_id"` - Name string `json:"name"` - PrivateKey string `json:"private_key"` - Type string `json:"type"` - UpdateTime time.Time `json:"update_time"` -} - -func (self *SElbCert) GetPublickKey() string { - return self.Certificate -} - -func (self *SElbCert) GetPrivateKey() string { - return self.PrivateKey -} - -func (self *SElbCert) GetId() string { - return self.ID -} - -func (self *SElbCert) GetName() string { - return self.Name -} - -func (self *SElbCert) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbCert) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbCert) Refresh() error { - cert, err := self.region.GetLoadBalancerCertificate(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, cert) -} - -func (self *SElbCert) IsEmulated() bool { - return false -} - -func (self *SElbCert) GetProjectId() string { - return "" -} - -func (self *SElbCert) Sync(name, privateKey, publickKey string) error { - params := map[string]interface{}{ - "name": name, - "private_key": privateKey, - "certificate": publickKey, - } - _, err := self.region.lbUpdate("elb/certificates/"+self.GetId(), params) - return err -} - -func (self *SElbCert) Delete() error { - _, err := self.region.lbDelete("elb/certificates/" + self.GetId()) - return err -} - -func (self *SElbCert) GetCommonName() string { - return self.Domain -} - -func (self *SElbCert) GetSubjectAlternativeNames() string { - return self.Domain -} - -func (self *SElbCert) GetFingerprint() string { - _fp := sha1.Sum([]byte(self.Certificate)) - fp := fmt.Sprintf("sha1:% x", _fp) - return strings.Replace(fp, " ", ":", -1) -} - -func (self *SElbCert) GetExpireTime() time.Time { - return self.ExpireTime -} - -func (self *SRegion) GetLoadBalancerCertificate(id string) (*SElbCert, error) { - resp, err := self.lbGet("elb/certificates/" + id) - if err != nil { - return nil, err - } - ret := &SElbCert{region: self} - return ret, resp.Unmarshal(ret) -} - -// https://support.huaweicloud.com/api-elb/elb_qy_zs_0001.html -func (self *SRegion) CreateLoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (*SElbCert, error) { - params := map[string]interface{}{ - "name": cert.Name, - "private_key": cert.PrivateKey, - "certificate": cert.Certificate, - } - resp, err := self.lbCreate("elb/certificates", params) - if err != nil { - return nil, err - } - ret := &SElbCert{region: self} - return ret, resp.Unmarshal(ret) -} - -func (self *SRegion) GetLoadBalancerCertificates() ([]SElbCert, error) { - resp, err := self.lbList("elb/certificates", url.Values{}) - if err != nil { - return nil, err - } - ret := []SElbCert{} - return ret, resp.Unmarshal(&ret, "certificates") -} diff --git a/pkg/multicloud/huawei/loadbalancer_listener.go b/pkg/multicloud/huawei/loadbalancer_listener.go deleted file mode 100644 index b230f7adf4..0000000000 --- a/pkg/multicloud/huawei/loadbalancer_listener.go +++ /dev/null @@ -1,663 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "fmt" - "net/url" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type InsertHeaders struct { - XForwardedELBIP bool `json:"X-Forwarded-ELB-IP"` -} - -type Loadbalancer struct { - ID string `json:"id"` -} - -type SElbListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.HuaweiTags - lb *SLoadbalancer - acl *SElbACL - backendgroup *SElbBackendGroup - - ProtocolPort int `json:"protocol_port"` - Protocol string `json:"protocol"` - Description string `json:"description"` - AdminStateUp bool `json:"admin_state_up"` - Http2Enable bool `json:"http2_enable"` - Loadbalancers []Loadbalancer `json:"loadbalancers"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - ConnectionLimit int `json:"connection_limit"` - DefaultPoolID string `json:"default_pool_id"` - ID string `json:"id"` - Name string `json:"name"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - InsertHeaders InsertHeaders `json:"insert_headers"` - DefaultTlsContainerRef string `json:"default_tls_container_ref"` -} - -func (self *SElbListener) GetId() string { - return self.ID -} - -func (self *SElbListener) GetName() string { - return self.Name -} - -func (self *SElbListener) GetGlobalId() string { - return self.GetId() -} - -func (self *SElbListener) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbListener) Refresh() error { - ilistener, err := self.lb.GetILoadBalancerListenerById(self.GetId()) - if err != nil { - return err - } - - listener := ilistener.(*SElbListener) - listener.lb = self.lb - err = jsonutils.Update(self, listener) - if err != nil { - return err - } - - return nil -} - -func (self *SElbListener) IsEmulated() bool { - return false -} - -func (self *SElbListener) GetProjectId() string { - return self.ProjectID -} - -func (self *SElbListener) GetListenerType() string { - switch self.Protocol { - case "TCP": - return api.LB_LISTENER_TYPE_TCP - case "UDP": - return api.LB_LISTENER_TYPE_UDP - case "HTTP": - return api.LB_LISTENER_TYPE_HTTP - case "TERMINATED_HTTPS": - return api.LB_LISTENER_TYPE_HTTPS - case "HTTPS": - return api.LB_LISTENER_TYPE_HTTPS - default: - return "" - } -} - -func (self *SElbListener) GetListenerPort() int { - return self.ProtocolPort -} - -func (self *SElbListener) GetBackendGroup() (*SElbBackendGroup, error) { - if self.backendgroup == nil { - lbbgId := self.GetBackendGroupId() - if len(lbbgId) > 0 { - lbbg, err := self.lb.GetILoadBalancerBackendGroupById(lbbgId) - if err != nil { - return nil, err - } - - self.backendgroup = lbbg.(*SElbBackendGroup) - } - } - - return self.backendgroup, nil -} - -func (self *SElbListener) GetScheduler() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetScheduler %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - return lbbg.GetScheduler() -} - -func (self *SElbListener) GetAcl() (*SElbACL, error) { - if self.acl != nil { - return self.acl, nil - } - - acls, err := self.lb.region.GetLoadBalancerAcls(self.GetId()) - if err != nil { - return nil, err - } - - if len(acls) == 0 { - return nil, nil - } else { - self.acl = &acls[0] - return &acls[0], nil - } -} - -func (self *SElbListener) GetAclStatus() string { - acl, err := self.GetAcl() - if err != nil { - log.Debugf("GetAclStatus %s", err) - return "" - } - - if acl != nil && acl.EnableWhitelist { - return api.LB_BOOL_ON - } - - return api.LB_BOOL_OFF -} - -func (self *SElbListener) GetAclType() string { - return api.LB_ACL_TYPE_WHITE -} - -func (self *SElbListener) GetAclId() string { - acl, err := self.GetAcl() - if err != nil { - log.Debugf("GetAclStatus %s", err) - return "" - } - - if acl == nil { - return "" - } - - return acl.GetId() -} - -func (self *SElbListener) GetEgressMbps() int { - return 0 -} - -func (self *SElbListener) GetHealthCheck() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheck %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheck %s", err.Error()) - } - - if health != nil { - return api.LB_BOOL_ON - } else { - return api.LB_BOOL_OFF - } -} - -func (self *SElbListener) GetHealthCheckType() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) - } - - if health != nil { - return health.HealthCheckType - } - - return "" -} - -func (self *SElbListener) GetHealthCheckTimeout() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) - } - - if health != nil { - return health.HealthCheckTimeout - } - - return 0 -} - -func (self *SElbListener) GetHealthCheckInterval() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) - } - - if health != nil { - return health.HealthCheckInterval - } - - return 0 -} - -func (self *SElbListener) GetHealthCheckRise() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) - } - - if health != nil { - return health.HealthCheckRise - } else { - return 0 - } -} - -func (self *SElbListener) GetHealthCheckFail() int { - return 0 -} - -func (self *SElbListener) GetHealthCheckReq() string { - return "" -} - -func (self *SElbListener) GetHealthCheckExp() string { - return "" -} - -func (self *SElbListener) GetBackendGroupId() string { - return self.DefaultPoolID -} - -func (self *SElbListener) GetBackendServerPort() int { - return 0 -} - -func (self *SElbListener) GetHealthCheckDomain() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) - } - - if health != nil { - return health.HealthCheckDomain - } - - return "" -} - -func (self *SElbListener) GetHealthCheckURI() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - health, err := lbbg.GetHealthCheck() - if err != nil { - log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) - } - - if health != nil { - return health.HealthCheckURI - } - - return "" -} - -func (self *SElbListener) GetHealthCheckCode() string { - return "" -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html -func (self *SElbListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - l7policy, err := self.lb.region.CreateLoadBalancerPolicy(self.GetId(), rule) - if err != nil { - return nil, err - } - - l7policy.region = self.lb.region - l7policy.lb = self.lb - l7policy.listener = self - return l7policy, nil -} - -func (self *SElbListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - ret := &SElbListenerPolicy{region: self.lb.region, lb: self.lb, listener: self} - resp, err := self.lb.region.lbGet("elb/l7policies/" + ruleId) - if err != nil { - return nil, err - } - return ret, resp.Unmarshal(ret, "l7policy") -} - -func (self *SElbListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - ret, err := self.lb.region.GetLoadBalancerPolicies(self.GetId()) - if err != nil { - return nil, err - } - - iret := []cloudprovider.ICloudLoadbalancerListenerRule{} - for i := range ret { - rule := ret[i] - rule.listener = self - rule.lb = self.lb - rule.region = self.lb.region - iret = append(iret, &rule) - } - - return iret, nil -} - -func (self *SElbListener) GetStickySession() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySession %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySession %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySession - } - - return "" -} - -func (self *SElbListener) GetStickySessionType() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySessionType %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySessionType %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySessionType - } - - return "" -} - -func (self *SElbListener) GetStickySessionCookie() string { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) - } - - if lbbg == nil { - return "" - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySessionCookie - } - - return "" -} - -func (self *SElbListener) GetStickySessionCookieTimeout() int { - lbbg, err := self.GetBackendGroup() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) - } - - if lbbg == nil { - return 0 - } - - stickySession, err := lbbg.GetStickySession() - if err != nil { - log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) - } - - if stickySession != nil { - return stickySession.StickySessionCookieTimeout - } - - return 0 -} - -func (self *SElbListener) XForwardedForEnabled() bool { - return self.InsertHeaders.XForwardedELBIP -} - -func (self *SElbListener) GzipEnabled() bool { - return false -} - -func (self *SElbListener) GetCertificateId() string { - return self.DefaultTlsContainerRef -} - -func (self *SElbListener) GetTLSCipherPolicy() string { - return "" -} - -func (self *SElbListener) HTTP2Enabled() bool { - return self.Http2Enable -} - -func (self *SElbListener) Start() error { - return nil -} - -func (self *SElbListener) Stop() error { - return cloudprovider.ErrNotSupported -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561544.html -/* -default_pool_id有如下限制: -不能更新为其他监听器的default_pool。 -不能更新为其他监听器的关联的转发策略所使用的pool。 -default_pool_id对应的后端云服务器组的protocol和监听器的protocol有如下关系: -监听器的protocol为TCP时,后端云服务器组的protocol必须为TCP。 -监听器的protocol为UDP时,后端云服务器组的protocol必须为UDP。 -监听器的protocol为HTTP或TERMINATED_HTTPS时,后端云服务器组的protocol必须为HTTP。 -*/ -func (self *SElbListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { - return self.lb.region.UpdateLoadBalancerListener(self.GetId(), listener) -} - -func (self *SElbListener) Delete(ctx context.Context) error { - _, err := self.lb.region.lbDelete("elb/listeners/" + self.GetId()) - return err -} - -func (self *SRegion) UpdateLoadBalancerListener(listenerId string, listener *cloudprovider.SLoadbalancerListener) error { - params := map[string]interface{}{ - "name": listener.Name, - "description": listener.Description, - "http2_enable": listener.EnableHTTP2, - "default_pool_id": jsonutils.JSONNull, - } - if len(listener.BackendGroupID) > 0 { - params["default_pool_id"] = listener.BackendGroupID - } - - if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { - params["default_tls_container_ref"] = listener.CertificateID - } - - if listener.XForwardedFor { - params["insert_headers"] = map[string]interface{}{ - "X-Forwarded-ELB-IP": listener.XForwardedFor, - } - } - _, err := self.lbUpdate("elb/listeners/"+listenerId, map[string]interface{}{"listener": params}) - return err -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295315.html -func (self *SRegion) GetLoadBalancerPolicies(listenerId string) ([]SElbListenerPolicy, error) { - query := url.Values{} - if len(listenerId) > 0 { - query.Set("listener_id", listenerId) - } - - resp, err := self.lbList("elb/l7policies", query) - if err != nil { - return nil, err - } - - ret := []SElbListenerPolicy{} - return ret, resp.Unmarshal(&ret, "l7policies") -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0116649234.html -func (self *SRegion) GetLoadBalancerPolicyRules(policyId string) ([]SElbListenerPolicyRule, error) { - resp, err := self.lbList(fmt.Sprintf("elb/l7policies/%s/rules", policyId), url.Values{}) - if err != nil { - return nil, err - } - - ret := []SElbListenerPolicyRule{} - return ret, resp.Unmarshal(&ret, "rules") -} - -// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html -func (self *SRegion) CreateLoadBalancerPolicy(listenerID string, rule *cloudprovider.SLoadbalancerListenerRule) (*SElbListenerPolicy, error) { - ret := &SElbListenerPolicy{} - params := map[string]interface{}{ - "name": rule.Name, - "listener_id": listenerID, - "action": "REDIRECT_TO_POOL", - "redirect_pool_id": rule.BackendGroupID, - } - resp, err := self.lbCreate("elb/l7policies", map[string]interface{}{"l7policy": params}) - if err != nil { - return nil, err - } - err = resp.Unmarshal(ret, "l7policy") - if err != nil { - return nil, err - } - if len(rule.Domain) > 0 { - params := map[string]interface{}{ - "type": "HOST_NAME", - "value": rule.Domain, - "compare_type": "EQUAL_TO", - } - _, err := self.lbCreate(fmt.Sprintf("elb/l7policies/%s/rules", ret.GetId()), map[string]interface{}{"rule": params}) - if err != nil { - return ret, err - } - } - - if len(rule.Path) > 0 { - params := map[string]interface{}{ - "type": "PATH", - "value": rule.Path, - "compare_type": "EQUAL_TO", - } - _, err := self.lbCreate(fmt.Sprintf("elb/l7policies/%s/rules", ret.GetId()), map[string]interface{}{"rule": params}) - if err != nil { - return ret, err - } - } - - return ret, nil -} - -func (self *SElbListener) GetClientIdleTimeout() int { - return 0 -} - -func (self *SElbListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/huawei/loadbalancer_listener_rule.go b/pkg/multicloud/huawei/loadbalancer_listener_rule.go deleted file mode 100644 index 061db632f4..0000000000 --- a/pkg/multicloud/huawei/loadbalancer_listener_rule.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElbListenerPolicy struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.HuaweiTags - region *SRegion - lb *SLoadbalancer - listener *SElbListener - - RedirectPoolID string `json:"redirect_pool_id"` - RedirectListenerID *string `json:"redirect_listener_id"` - Description string `json:"description"` - AdminStateUp bool `json:"admin_state_up"` - Rules []Rule `json:"rules"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - ListenerID string `json:"listener_id"` - RedirectURL *string `json:"redirect_url"` - ProvisioningStatus string `json:"provisioning_status"` - Action string `json:"action"` - Position int64 `json:"position"` - ID string `json:"id"` - Name string `json:"name"` -} - -type Rule struct { - ID string `json:"id"` -} - -type SElbListenerPolicyRule struct { - region *SRegion - policy *SElbListenerPolicy - - CompareType string `json:"compare_type"` - ProvisioningStatus string `json:"provisioning_status"` - AdminStateUp bool `json:"admin_state_up"` - TenantID string `json:"tenant_id"` - ProjectID string `json:"project_id"` - Invert bool `json:"invert"` - Value string `json:"value"` - Key interface{} `json:"key"` - Type string `json:"type"` - ID string `json:"id"` -} - -func (self *SElbListenerPolicy) GetId() string { - return self.ID -} - -func (self *SElbListenerPolicy) GetName() string { - return self.Name -} - -func (self *SElbListenerPolicy) GetGlobalId() string { - return self.GetId() -} - -// 负载均衡没有启用禁用操作 -func (self *SElbListenerPolicy) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SElbListenerPolicy) Refresh() error { - resp, err := self.lb.region.lbGet("") - if err != nil { - return err - } - return resp.Unmarshal(self, "l7policy") -} - -func (self *SElbListenerPolicy) IsDefault() bool { - return false -} - -func (self *SElbListenerPolicy) IsEmulated() bool { - return false -} - -func (self *SElbListenerPolicy) GetProjectId() string { - return "" -} - -func (self *SElbListenerPolicy) GetRules() ([]SElbListenerPolicyRule, error) { - ret, err := self.region.GetLoadBalancerPolicyRules(self.GetId()) - if err != nil { - return nil, err - } - - for i := range ret { - ret[i].region = self.lb.region - ret[i].policy = self - } - - return ret, nil -} - -func (self *SElbListenerPolicy) GetDomain() string { - rules, err := self.GetRules() - if err != nil { - log.Errorf("loadbalancer rule GetDomain %s", err) - } - - for i := range rules { - if rules[i].Type == "HOST_NAME" { - return rules[i].Value - } - } - - return "" -} - -func (self *SElbListenerPolicy) GetCondition() string { - return "" -} - -func (self *SElbListenerPolicy) GetPath() string { - rules, err := self.GetRules() - if err != nil { - log.Errorf("loadbalancer rule GetPath %s", err) - } - - for i := range rules { - if rules[i].Type == "PATH" { - return rules[i].Value - } - } - - return "" -} - -func (self *SElbListenerPolicy) GetBackendGroupId() string { - return self.RedirectPoolID -} - -func (self *SElbListenerPolicy) Delete(ctx context.Context) error { - return self.region.DeleteLoadBalancerPolicy(self.GetId()) -} - -func (self *SRegion) DeleteLoadBalancerPolicy(policyId string) error { - _, err := self.lbDelete("elb/l7policies/" + policyId) - return err -} diff --git a/pkg/multicloud/huawei/modelarts_pool.go b/pkg/multicloud/huawei/modelarts_pool.go deleted file mode 100644 index 61e6065a84..0000000000 --- a/pkg/multicloud/huawei/modelarts_pool.go +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SModelartsPool struct { - region *SRegion - multicloud.SResourceBase - - Metadata SModelartsPoolMetadata `json:"metadata"` - Spec SModelartsPoolSpec `json:"spec"` - Status SModelartsPoolStatus `json:"status"` - InstanceType string - WorkType string -} - -type SModelartsPoolMetadata struct { - Name string `json:"name"` - CreationTimestamp string `json:"creationTimestamp"` - Labels SModelartsPoolMeatadataLabel - Annotations SModelartsPoolMetadataAnnotations `json:"annotations"` -} - -type SModelartsPoolMeatadataLabel struct { - WorkspaceId string `json:"os.modelarts/workspace.id"` - Name string `json:"os.modelarts/name"` - ResourceId string `json:"os.modelarts/resource.id"` -} - -type SModelartsPoolMetadataAnnotations struct { - Describe string `json:"os.modelarts/description"` - BillingType string `json:"os.modelarts/billing.mode"` - BillingCycle string `json:"os.modelarts/period.num"` - BillingPeriodType string `json:"os.modelarts/period.type"` - BillingMod string `json:"os.modelarts/charging.mode"` - BillingRenew string `json:"os.modelarts/auto.renew"` - OrderId string `json:"os.modelarts/order.id"` -} - -type SModelartsPoolSpec struct { - Type string `json:"type"` - Scope []string `json:"scope"` - Resource []SModelartsPoolResource `json:"resources"` -} - -type SModelartsPoolResource struct { - Flavor string `json:"flavor"` - Count int `json:"count"` - cloudprovider.Azs -} - -type SNodeStatus struct { - Creating []SNodeFlavor `json:"creating"` - Available []SNodeFlavor `json:"available"` - Abnormal []SNodeFlavor `json:"abnormal"` - Deleting []SNodeFlavor `json:"deleting"` -} -type SNodeFlavor struct { - Flavor string `json:"flavor"` - Count int `json:"count"` -} - -type SModelartsPoolStatus struct { - Phase string `json:"phase"` - Message string `json:"message"` - Resource SNodeStatus `json:"resources"` -} - -type SModelartsPoolNetwork struct { - Metadata SModelartsPoolNetworkMetadata `json:"metadata"` -} - -type SModelartsPoolNetworkMetadata struct { - Name string `json:"name"` - CreationTimestamp string `json:"creationTimestamp"` -} - -func (self *SRegion) GetIModelartsPools() ([]cloudprovider.ICloudModelartsPool, error) { - pools := make([]SModelartsPool, 0) - resObj, err := self.client.modelartsPoolList("pools", nil) - if err != nil { - return nil, errors.Wrap(err, "region.GetPools") - } - err = resObj.Unmarshal(&pools, "items") - if err != nil { - return nil, errors.Wrap(err, "resObj unmarshal") - } - res := make([]cloudprovider.ICloudModelartsPool, len(pools)) - for i := 0; i < len(pools); i++ { - pools[i].region = self - res[i] = &pools[i] - } - - return res, nil -} - -func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreateOption) (cloudprovider.ICloudModelartsPool, error) { - netObj, err := self.client.modelartsPoolNetworkList("network", nil) - if err != nil { - return nil, errors.Wrap(err, "SHuaweiClient.GetPools") - } - netRes := make([]SModelartsPoolNetwork, 0) - netObj.Unmarshal(&netRes, "items") - netId := "" - if len(netRes) != 0 { - netId = netRes[0].Metadata.Name - } else { - createNetObj, err := self.client.CreatePoolNetworks() - if err != nil { - return nil, errors.Wrap(err, "SHuaweiClient.CreatePoolNetworks") - } - netId, _ = createNetObj.GetString("metadata", "name") - } - - scopeArr := strings.Split(args.WorkType, ",") - params := map[string]interface{}{ - "apiVersion": "v2", - "kind": "Pool", - "metadata": map[string]interface{}{ - "labels": map[string]interface{}{ - "os.modelarts/name": args.Name, - "os.modelarts/workspace.id": "0", - }, - }, - "spec": map[string]interface{}{ - "type": "Dedicate", - "scope": scopeArr, - "network": map[string]interface{}{ - "name": netId, - }, - - "resources": []map[string]interface{}{ - { - "flavor": args.InstanceType, - "count": args.NodeCount, - }, - }, - }, - } - obj, err := self.client.modelartsPoolCreate("pools", params) - if err != nil { - return nil, errors.Wrap(err, "SHuaweiClient.CreatePools") - } - pool := &SModelartsPool{} - obj.Unmarshal(&pool) - res := []cloudprovider.ICloudModelartsPool{} - for i := 0; i < 1; i++ { - pool.region = self - res = append(res, pool) - } - - return res[0], nil -} - -func (self *SRegion) DeletePool(poolName string) (jsonutils.JSONObject, error) { - return self.client.modelartsPoolDelete("pools", poolName, nil) -} - -func (self *SRegion) GetIModelartsPoolById(poolId string) (cloudprovider.ICloudModelartsPool, error) { - obj, err := self.client.modelartsPoolById(poolId) - if err != nil { - if strings.Contains(err.Error(), "not found") { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "") - } - return nil, errors.Wrap(err, "region.modelartsPoolByName") - } - pool := &SModelartsPool{} - obj.Unmarshal(&pool) - res := []cloudprovider.ICloudModelartsPool{} - for i := 0; i < 1; i++ { - pool.region = self - res = append(res, pool) - } - return res[0], nil -} - -func (self *SRegion) MonitorPool(poolId string) (*SModelartsMetrics, error) { - resObj, err := self.client.modelartsPoolMonitor(poolId, nil) - if err != nil { - return nil, errors.Wrapf(err, "send request error") - } - metrics := SModelartsMetrics{} - err = resObj.Unmarshal(&metrics) - if err != nil { - return nil, errors.Wrapf(err, "unmarsh error") - } - return &metrics, nil -} - -type SModelartsMetrics struct { - Metrics []SModelartsMetric `json:"metrics"` -} - -type SModelartsMetric struct { - Metric SModelartsMetricInfo `json:"metric"` - Datapoints []SModelartsDataPoints `json:"dataPoints"` -} - -type SModelartsMetricInfo struct { - Dimensions []SModelartsDimensions `json:"dimensions"` - MetricName string - Namespace string -} - -type SModelartsDimensions struct { - Name string - Value string -} - -type SModelartsDataPoints struct { - Timestamp int64 - Unit string - Statistics []ModelartsStatistics -} - -type ModelartsStatistics struct { - Statistic string - Value float64 -} - -func (self *SHuaweiClient) GetPoolNetworks(poolName string) (jsonutils.JSONObject, error) { - return self.modelartsPoolNetworkList(poolName, nil) -} - -func (self *SHuaweiClient) CreatePoolNetworks() (jsonutils.JSONObject, error) { - params := map[string]interface{}{ - "apiVersion": "v1", - "kind": "Network", - "metadata": map[string]interface{}{ - "labels": map[string]interface{}{ - "os.modelarts/name": "test", - "os.modelarts/workspace.id": "0", - }, - }, - "spec": map[string]interface{}{ - "cidr": "192.168.20.0/24", - }, - } - return self.modelartsPoolNetworkCreate(params) -} - -func (self *SModelartsPool) GetCreatedAt() time.Time { - ret, _ := time.Parse("2006-01-02T15:04:05CST", self.Metadata.CreationTimestamp) - if !ret.IsZero() { - ret = ret.Add(time.Hour * 8) - } - return ret -} - -func (self *SModelartsPool) GetGlobalId() string { - return self.Metadata.Name -} - -func (self *SModelartsPool) GetId() string { - return self.Metadata.Name -} - -func (self *SModelartsPool) GetName() string { - return self.Metadata.Labels.Name -} - -func (self *SModelartsPool) GetStatus() string { - res := strings.ToLower(self.Status.Phase) - switch { - case res == compute.MODELARTS_POOL_STATUS_RUNNING && len(self.Status.Resource.Creating) != 0: - res = compute.MODELARTS_POOL_STATUS_CREATING - } - return res -} - -func (self *SModelartsPool) GetSysTags() map[string]string { - return nil -} - -func (self *SModelartsPool) GetTags() (map[string]string, error) { - return nil, nil -} - -func (self *SModelartsPool) IsEmulated() bool { - return false -} - -func (self *SModelartsPool) GetBillingType() string { - if self.Metadata.Annotations.BillingType == "1" { - return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID - } -} - -// 获取资源归属项目Id -func (self *SModelartsPool) GetProjectId() string { - return self.Metadata.Name -} - -func (self *SModelartsPool) GetExpiredAt() time.Time { - ret, _ := time.Parse("2006-01-02T15:04:05CST", self.Metadata.CreationTimestamp) - if !ret.IsZero() { - ret = ret.Add(time.Hour * 8) - } - return ret -} - -func (self *SModelartsPool) IsAutoRenew() bool { - return false -} - -func (self *SModelartsPool) Renew(bc billing.SBillingCycle) error { - return nil -} - -func (self *SModelartsPool) SetAutoRenew(bc billing.SBillingCycle) error { - return nil -} - -func (self *SModelartsPool) Refresh() error { - pool, err := self.region.client.modelartsPoolById(self.GetId()) - if err != nil { - return errors.Wrapf(err, "GetModelartsPool(%s)", self.GetId()) - } - return jsonutils.Update(self, pool) -} - -func (self *SModelartsPool) SetTags(tags map[string]string, replace bool) error { - return nil -} - -func (self *SModelartsPool) Delete() error { - _, err := self.region.DeletePool(self.GetId()) - if err != nil { - return err - } - return nil -} - -func (self *SModelartsPool) GetInstanceType() string { - return self.Spec.Resource[0].Flavor - -} - -func (self *SModelartsPool) GetWorkType() string { - return strings.Join(self.Spec.Scope, ",") -} - -func (self *SModelartsPool) GetNodeCount() int { - if len(self.Spec.Resource) < 1 { - return 0 - } - return self.Spec.Resource[0].Count -} - -func (self *SModelartsPool) ChangeConfig(opts *cloudprovider.ModelartsPoolChangeConfigOptions) error { - //{"spec":{"resources":[{"flavor":"modelarts.kat1.8xlarge","count":2}]}} - res := []map[string]interface{}{} - for _, re := range self.Spec.Resource { - res = append(res, map[string]interface{}{ - "flavor": re.Flavor, - "count": opts.NodeCount, - }) - } - params := map[string]interface{}{ - "spec": map[string]interface{}{ - "resources": res, - }, - } - _, err := self.region.client.modelartsPoolUpdate(self.Metadata.Name, params) - return err -} diff --git a/pkg/multicloud/huawei/modelarts_pool_sku.go b/pkg/multicloud/huawei/modelarts_pool_sku.go deleted file mode 100644 index 0eaf8a4a9c..0000000000 --- a/pkg/multicloud/huawei/modelarts_pool_sku.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "strconv" - "time" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SModelartsPoolSku struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - - Kind string `json:"kind"` - Spec SModelartsResourceflavorsSpec `json:"spec"` - Status SModelartsResourceflavorsStatus `json:"status"` -} - -type SModelartsResourceflavorsSpec struct { - BillingCode string `json:"billingCode"` - BillingModes []int `json:"billingMods"` - Cpu int `json:"cpu"` - CpuArch string `json:"cpuArch"` - Gpu SModelartsResourceflavorsGpuSpec `json:"gpu"` - Npu SModelartsResourceflavorsGpuSpec `json:"npu"` - Memory string `json:"memory"` - Type string `json:"type"` -} - -type SModelartsResourceflavorsGpuSpec struct { - Size int `json:"size"` - Type string `json:"type"` -} - -type SModelartsResourceflavorsStatus struct { - Phase map[string]interface{} `json:"phase"` -} - -func (self *SRegion) GetIModelartsPoolSku() ([]cloudprovider.ICloudModelartsPoolSku, error) { - params := make(map[string]interface{}) - resourceflavors := make([]SModelartsPoolSku, 0) - obj, err := self.client.modelartsResourceflavors("resourceflavors", params) - if err != nil { - return nil, errors.Wrap(err, "region.modelartsResourceflavors") - } - obj.Unmarshal(&resourceflavors, "items") - res := make([]cloudprovider.ICloudModelartsPoolSku, len(resourceflavors)) - for i := 0; i < len(resourceflavors); i++ { - res[i] = &resourceflavors[i] - } - return res, nil -} - -func (self *SModelartsPoolSku) GetCreatedAt() time.Time { - createdAt, _ := time.Parse("2006-01-02T15:04:05CST", time.Now().Format("2006-01-02T15:04:05CST")) - return createdAt -} - -func (self *SModelartsPoolSku) GetGlobalId() string { - return self.Spec.BillingCode -} - -func (self *SModelartsPoolSku) GetId() string { - return self.Spec.BillingCode -} - -func (self *SModelartsPoolSku) GetName() string { - return self.Spec.BillingCode -} - -func (self *SModelartsPoolSku) GetCpuArch() string { - return self.Spec.CpuArch -} - -func (self *SModelartsPoolSku) GetCpuCoreCount() int { - return self.Spec.Cpu -} - -func (self *SModelartsPoolSku) GetMemorySizeMB() int { - size, _ := strconv.Atoi(self.Spec.Memory[:len(self.Spec.Memory)-2]) - return size * 1024 -} - -func (self *SModelartsPoolSku) GetStatus() string { - for _, v := range self.Status.Phase { - if v == "normal" { - return compute.MODELARTS_POOL_SKU_AVAILABLE - } - } - return compute.MODELARTS_POOL_SKU_SOLDOUT -} - -func (self *SModelartsPoolSku) GetGpuSize() int { - return self.Spec.Gpu.Size -} - -func (self *SModelartsPoolSku) GetGpuType() string { - return self.Spec.Gpu.Type -} - -func (self *SModelartsPoolSku) GetNpuSize() int { - return self.Spec.Npu.Size -} - -func (self *SModelartsPoolSku) GetNpuType() string { - return self.Spec.Npu.Type -} - -func (self *SModelartsPoolSku) GetPoolType() string { - return self.Spec.Type -} diff --git a/pkg/multicloud/huawei/monitor.go b/pkg/multicloud/huawei/monitor.go deleted file mode 100644 index 864951076d..0000000000 --- a/pkg/multicloud/huawei/monitor.go +++ /dev/null @@ -1,563 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules" -) - -func (r *SRegion) GetMetrics() ([]modules.SMetricMeta, error) { - return r.ecsClient.CloudEye.ListMetrics() -} - -func (r *SRegion) GetMetricsData(metrics []modules.SMetricMeta, since time.Time, until time.Time) ([]modules.SMetricData, error) { - return r.ecsClient.CloudEye.GetMetricsData(metrics, since, until) -} - -type MetricData struct { - Namespace string - MetricName string - Dimensions []struct { - Name string - Value string - } - Datapoints []struct { - Average float64 - Timestamp int64 - } - Unit string -} - -func (self *SHuaweiClient) getServerMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - params := map[string]interface{}{ - "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), - "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), - "period": "1", - "filter": "average", - } - metrics := []interface{}{} - namespace, dimesionName, metricNames := "SYS.ECS", "instance_id", []string{ - "cpu_util", - "network_incoming_bytes_aggregate_rate", - "network_outgoing_bytes_aggregate_rate", - "disk_read_bytes_rate", - "disk_write_bytes_rate", - "disk_read_requests_rate", - "disk_write_requests_rate", - } - for _, metricName := range metricNames { - metrics = append(metrics, map[string]interface{}{ - "namespace": namespace, - "metric_name": metricName, - "dimensions": []map[string]string{ - { - "name": dimesionName, - "value": opts.ResourceId, - }, - }, - }) - } - params["metrics"] = metrics - resp, err := self.monitorPost("batch-query-metric-data", params) - if err != nil { - return nil, err - } - metricData := []MetricData{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].MetricName { - case "cpu_util": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_CPU_USAGE - case "network_incoming_bytes_aggregate_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_RX - tags = map[string]string{"net_type": "internet"} - case "network_outgoing_bytes_aggregate_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_TX - tags = map[string]string{"net_type": "internet"} - case "disk_read_bytes_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS - case "disk_write_bytes_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS - case "disk_read_requests_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS - case "disk_write_requests_rate": - ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - metricValue := cloudprovider.MetricValue{ - Value: value.Average, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHuaweiClient) getRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - params := map[string]interface{}{ - "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), - "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), - "period": "1", - "filter": "average", - } - metrics := []interface{}{} - namespace, dimesionName, metricNames := "SYS.DCS", "dcs_instance_id", []string{ - "cpu_usage", - "memory_usage", - "instantaneous_input_kbps", - "instantaneous_output_kbps", - "connected_clients", - "instantaneous_ops", - "keys", - "expires", - "used_memory_dataset", - } - for _, metricName := range metricNames { - metrics = append(metrics, map[string]interface{}{ - "namespace": namespace, - "metric_name": metricName, - "dimensions": []map[string]string{ - { - "name": dimesionName, - "value": opts.ResourceId, - }, - }, - }) - } - params["metrics"] = metrics - resp, err := self.monitorPost("batch-query-metric-data", params) - if err != nil { - return nil, err - } - metricData := []MetricData{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].MetricName { - case "cpu_usage": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE - case "memory_usage": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE - case "instantaneous_input_kbps": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX - case "instantaneous_output_kbps": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX - case "connected_clients": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_USED_CONN - case "instantaneous_ops": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_OPT_SES - case "keys": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS - case "expires": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS - case "used_memory_dataset": - ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - metricValue := cloudprovider.MetricValue{ - Value: value.Average, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHuaweiClient) getRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - params := map[string]interface{}{ - "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), - "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), - "period": "1", - "filter": "average", - } - metrics := []interface{}{} - namespace, dimesionName, metricNames := "SYS.RDS", "rds_cluster_id", []string{ - "rds001_cpu_util", - "rds002_mem_util", - "rds004_bytes_in", - "rds004_bytes_in", - "rds005_bytes_out", - "rds039_disk_util", - "rds049_disk_read_throughput", - "rds050_disk_write_throughput", - "rds006_conn_count", - "rds008_qps", - "rds009_tps", - "rds013_innodb_reads", - "rds014_innodb_writes", - } - switch opts.Engine { - case api.DBINSTANCE_TYPE_POSTGRESQL: - dimesionName = "postgresql_cluster_id" - case api.DBINSTANCE_TYPE_SQLSERVER: - dimesionName = "rds_cluster_sqlserver_id" - } - - for _, metricName := range metricNames { - metrics = append(metrics, map[string]interface{}{ - "namespace": namespace, - "metric_name": metricName, - "dimensions": []map[string]string{ - { - "name": dimesionName, - "value": opts.ResourceId, - }, - }, - }) - } - params["metrics"] = metrics - resp, err := self.monitorPost("batch-query-metric-data", params) - if err != nil { - return nil, err - } - metricData := []MetricData{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].MetricName { - case "rds001_cpu_util": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_CPU_USAGE - case "rds002_mem_util": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_MEM_USAGE - case "rds004_bytes_in": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX - case "rds005_bytes_out": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX - case "rds039_disk_util": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_USAGE - case "rds049_disk_read_throughput": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_READ_BPS - case "rds050_disk_write_throughput": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_WRITE_BPS - case "rds006_conn_count": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_CONN_COUNT - case "rds008_qps": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_QPS - case "rds009_tps": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_TPS - case "rds013_innodb_reads": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_INNODB_READ_BPS - case "rds014_innodb_writes": - ret.MetricType = cloudprovider.RDS_METRIC_TYPE_INNODB_WRITE_BPS - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - metricValue := cloudprovider.MetricValue{ - Value: value.Average, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHuaweiClient) getBucketMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - params := map[string]interface{}{ - "from": opts.StartTime.UnixMilli(), - "to": opts.EndTime.UnixMilli(), - "period": "1", - "filter": "average", - } - metrics := []interface{}{} - namespace, dimesionName, metricNames := "SYS.OBS", "bucket_name", []string{ - "download_bytes", - "upload_bytes", - "first_byte_latency", - "get_request_count", - "request_count_4xx", - "request_count_5xx", - } - - for _, metricName := range metricNames { - metrics = append(metrics, map[string]interface{}{ - "namespace": namespace, - "metric_name": metricName, - "dimensions": []map[string]string{ - { - "name": dimesionName, - "value": opts.ResourceId, - }, - }, - }) - } - params["metrics"] = metrics - resp, err := self.monitorPost("batch-query-metric-data", params) - if err != nil { - return nil, err - } - metricData := []MetricData{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].MetricName { - case "download_bytes": - ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_TX - case "upload_bytes": - ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_RX - case "first_byte_latency": - ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_LATECY - tags = map[string]string{"request": "get"} - case "get_request_count": - ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT - tags = map[string]string{"request": "get"} - case "request_count_4xx": - ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT - tags = map[string]string{"request": "4xx"} - case "request_count_5xx": - ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT - tags = map[string]string{"request": "5xx"} - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - metricValue := cloudprovider.MetricValue{ - Value: value.Average, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHuaweiClient) getLoadbalancerMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - params := map[string]interface{}{ - "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), - "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), - "period": "1", - "filter": "average", - } - metrics := []interface{}{} - namespace, dimesionName, metricNames := "SYS.ELB", "lb_instance_id", []string{ - "m7_in_Bps", - "m8_out_Bps", - "mc_l7_http_2xx", - "md_l7_http_3xx", - "me_l7_http_4xx", - "mf_l7_http_5xx", - } - - for _, metricName := range metricNames { - metrics = append(metrics, map[string]interface{}{ - "namespace": namespace, - "metric_name": metricName, - "dimensions": []map[string]string{ - { - "name": dimesionName, - "value": opts.ResourceId, - }, - }, - }) - } - params["metrics"] = metrics - resp, err := self.monitorPost("batch-query-metric-data", params) - if err != nil { - return nil, err - } - metricData := []MetricData{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].MetricName { - case "m7_in_Bps": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_NET_BPS_RX - case "m8_out_Bps": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_NET_BPS_TX - case "mc_l7_http_2xx": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT - tags = map[string]string{"request": "2xx"} - case "md_l7_http_3xx": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT - tags = map[string]string{"request": "3xx"} - case "md_l7_http_4xx": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT - tags = map[string]string{"request": "4xx"} - case "md_l7_http_5xx": - ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT - tags = map[string]string{"request": "5xx"} - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - metricValue := cloudprovider.MetricValue{ - Value: value.Average, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHuaweiClient) getModelartsPoolMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - resp, err := self.modelartsPoolMonitor(opts.ResourceId, nil) - if err != nil { - return nil, err - } - metricData := []SModelartsMetric{} - err = resp.Unmarshal(&metricData, "metrics") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - result := []cloudprovider.MetricValues{} - for i := range metricData { - isMB := false - if metricData[i].Datapoints[0].Unit == "Megabytes" { - isMB = true - metricData[i].Datapoints[0].Unit = "Bytes" - } - ret := cloudprovider.MetricValues{ - Id: opts.ResourceId, - Unit: metricData[i].Datapoints[0].Unit, - Values: []cloudprovider.MetricValue{}, - } - tags := map[string]string{} - switch metricData[i].Metric.MetricName { - case "cpuUsage": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_CPU_USAGE - case "memUsedRate": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_MEM_USAGE - case "gpuUtil": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_GPU_UTIL - case "gpuMemUsage": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_GPU_MEM_USAGE - case "npuUtil": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_NPU_UTIL - case "npuMemUsage": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_NPU_MEM_USAGE - case "diskAvailableCapacity": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_AVAILABLE_CAPACITY - case "diskCapacity": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_CAPACITY - case "diskUsedRate": - ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_USAGE - default: - log.Warningf("invalid metricName %s for %s %s", metricData[i].Metric.MetricName, opts.ResourceType, opts.ResourceId) - continue - } - for _, value := range metricData[i].Datapoints { - if isMB { - value.Statistics[0].Value *= 1024 - } - if value.Statistics[0].Value == -1 { - value.Statistics[0].Value = 0 - } - metricValue := cloudprovider.MetricValue{ - Value: value.Statistics[0].Value, - Timestamp: time.UnixMilli(value.Timestamp), - Tags: tags, - } - ret.Values = append(ret.Values, metricValue) - } - result = append(result, ret) - } - return result, nil -} - -func (self *SHuaweiClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.getServerMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: - return self.getRedisMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_RDS: - return self.getRdsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_BUCKET: - return self.getBucketMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_LB: - return self.getLoadbalancerMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_MODELARTS_POOL: - return self.getModelartsPoolMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) - } -} diff --git a/pkg/multicloud/huawei/natdtable.go b/pkg/multicloud/huawei/natdtable.go deleted file mode 100644 index 2ac6914bf8..0000000000 --- a/pkg/multicloud/huawei/natdtable.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNatDEntry struct { - multicloud.SResourceBase - multicloud.HuaweiTags - gateway *SNatGateway - - ID string `json:"id"` - NatGatewayID string `json:"nat_gateway_id"` - Protocol string `json:"protocol"` - Status string `json:"status"` - ExternalIP string `json:"floating_ip_address"` - ExternalPort int `json:"external_service_port"` - InternalIP string `json:"private_ip"` - InternalPort int `json:"internal_service_port"` - PortID string `json:"port_id"` - AdminStateUp bool `json:"admin_state_up"` -} - -func (nat *SNatDEntry) GetId() string { - return nat.ID -} - -func (nat *SNatDEntry) GetName() string { - // No name so return id - return nat.GetId() -} - -func (nat *SNatDEntry) GetGlobalId() string { - return nat.GetId() -} - -func (nat *SNatDEntry) GetStatus() string { - return NatResouceStatusTransfer(nat.Status) -} - -func (nat *SNatDEntry) GetIpProtocol() string { - return nat.Protocol -} - -func (nat *SNatDEntry) GetExternalIp() string { - return nat.ExternalIP -} - -func (nat *SNatDEntry) GetExternalPort() int { - return nat.ExternalPort -} - -func (nat *SNatDEntry) GetInternalIp() string { - return nat.InternalIP -} - -func (nat *SNatDEntry) GetInternalPort() int { - return nat.InternalPort -} - -func (nat *SNatDEntry) Delete() error { - return nat.gateway.region.DeleteNatDEntry(nat.GetId()) -} - -// getNatSTable return all snat rules of gateway -func (gateway *SNatGateway) getNatDTable() ([]SNatDEntry, error) { - ret, err := gateway.region.GetNatDTable(gateway.GetId()) - if err != nil { - return nil, err - } - for i := range ret { - ret[i].gateway = gateway - } - return ret, nil -} - -func (region *SRegion) GetNatDTable(natGatewayID string) ([]SNatDEntry, error) { - queuies := map[string]string{ - "nat_gateway_id": natGatewayID, - } - dNatSTableEntries := make([]SNatDEntry, 0, 2) - // can't make true that restapi support marker para in Huawei Cloud - err := doListAllWithMarker(region.ecsClient.DNatRules.List, queuies, &dNatSTableEntries) - if err != nil { - return nil, errors.Wrapf(err, `get dnat rule of gateway %q`, natGatewayID) - } - for i := range dNatSTableEntries { - nat := &dNatSTableEntries[i] - if len(nat.InternalIP) == 0 { - port, err := region.GetPort(nat.PortID) - if err != nil { - return nil, errors.Wrapf(err, `get port info for transfer to ip of port_id %q error`, nat.PortID) - } - nat.InternalIP = port.FixedIps[0].IpAddress - } - } - return dNatSTableEntries, nil -} - -func (region *SRegion) DeleteNatDEntry(entryID string) error { - _, err := region.ecsClient.DNatRules.Delete(entryID, nil) - if err != nil { - return errors.Wrapf(err, `delete dnat rule %q failed`, entryID) - } - return nil -} - -func (nat *SNatDEntry) Refresh() error { - new, err := nat.gateway.region.GetNatDEntryByID(nat.ID) - if err != nil { - return err - } - return jsonutils.Update(nat, new) -} diff --git a/pkg/multicloud/huawei/natgateway.go b/pkg/multicloud/huawei/natgateway.go deleted file mode 100644 index 13aa9a7b0b..0000000000 --- a/pkg/multicloud/huawei/natgateway.go +++ /dev/null @@ -1,353 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNatGateway struct { - multicloud.SNatGatewayBase - multicloud.HuaweiTags - region *SRegion - - ID string - Name string - Description string - Spec string - Status string - InternalNetworkId string - CreatedTime string `json:"created_at"` -} - -func (gateway *SNatGateway) GetId() string { - return gateway.ID -} - -func (gateway *SNatGateway) GetName() string { - return gateway.Name -} - -func (gateway *SNatGateway) GetGlobalId() string { - return gateway.GetId() -} - -func (gateway *SNatGateway) GetStatus() string { - return NatResouceStatusTransfer(gateway.Status) -} - -func (self *SNatGateway) Delete() error { - return self.region.DeleteNatGateway(self.ID) -} - -func (self *SNatGateway) Refresh() error { - nat, err := self.region.GetNatGateway(self.ID) - if err != nil { - return errors.Wrapf(err, "GetNatGateway(%s)", self.ID) - } - return jsonutils.Update(self, nat) -} - -func (self *SNatGateway) GetINetworkId() string { - return self.InternalNetworkId -} - -func (gateway *SNatGateway) GetNatSpec() string { - switch gateway.Spec { - case "1": - return api.NAT_SPEC_SMALL - case "2": - return api.NAT_SPEC_MIDDLE - case "3": - return api.NAT_SPEC_LARGE - case "4": - return api.NAT_SPEC_XLARGE - } - return gateway.Spec -} - -func (gateway *SNatGateway) GetDescription() string { - return gateway.Description -} - -func (gateway *SNatGateway) GetBillingType() string { - // Up to 2019.07.17, only support post pay - return billing_api.BILLING_TYPE_POSTPAID -} - -func (gateway *SNatGateway) GetCreatedAt() time.Time { - t, _ := time.Parse("2006-01-02 15:04:05.000000", gateway.CreatedTime) - return t -} - -func (gateway *SNatGateway) GetExpiredAt() time.Time { - // no support for expired time - return time.Time{} -} - -func (gateway *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { - IEips, err := gateway.region.GetIEips() - if err != nil { - return nil, errors.Wrapf(err, `get all Eips of region %q error`, gateway.region.GetId()) - } - dNatTables, err := gateway.GetINatDTable() - if err != nil { - return nil, errors.Wrapf(err, `get all DNatTable of gateway %q error`, gateway.GetId()) - } - sNatTables, err := gateway.GetINatSTable() - if err != nil { - return nil, errors.Wrapf(err, `get all SNatTable of gateway %q error`, gateway.GetId()) - } - - // Get natIPSet of nat rules - natIPSet := make(map[string]struct{}) - for _, snat := range sNatTables { - natIPSet[snat.GetIP()] = struct{}{} - } - for _, dnat := range dNatTables { - natIPSet[dnat.GetExternalIp()] = struct{}{} - } - - // Add Eip whose GetIpAddr() in natIPSet to ret - ret := make([]cloudprovider.ICloudEIP, 0, 2) - for i := range IEips { - if _, ok := natIPSet[IEips[i].GetIpAddr()]; ok { - ret = append(ret, IEips[i]) - } - } - return ret, nil -} - -func (gateway *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { - dNatTable, err := gateway.getNatDTable() - if err != nil { - return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) - } - ret := make([]cloudprovider.ICloudNatDEntry, len(dNatTable)) - for i := range dNatTable { - ret[i] = &dNatTable[i] - } - return ret, nil -} - -func (gateway *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { - sNatTable, err := gateway.getNatSTable() - if err != nil { - return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) - } - ret := make([]cloudprovider.ICloudNatSEntry, len(sNatTable)) - for i := range sNatTable { - ret[i] = &sNatTable[i] - } - return ret, nil -} - -func (gateway *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { - dnat, err := gateway.region.CreateNatDEntry(rule, gateway.GetId()) - if err != nil { - return nil, err - } - dnat.gateway = gateway - return &dnat, nil -} - -func (gateway *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { - snat, err := gateway.region.CreateNatSEntry(rule, gateway.GetId()) - if err != nil { - return nil, err - } - snat.gateway = gateway - return &snat, nil -} - -func (gateway *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { - dnat, err := gateway.region.GetNatDEntryByID(id) - if err != nil { - return nil, err - } - dnat.gateway = gateway - return &dnat, nil -} - -func (gateway *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { - snat, err := gateway.region.GetNatSEntryByID(id) - if err != nil { - return nil, err - } - snat.gateway = gateway - return &snat, nil -} - -func (region *SRegion) GetNatGateways(vpcID, natGatewayID string) ([]SNatGateway, error) { - queues := make(map[string]string) - if len(natGatewayID) != 0 { - queues["id"] = natGatewayID - } - if len(vpcID) != 0 { - queues["router_id"] = vpcID - } - natGateways := make([]SNatGateway, 0, 2) - err := doListAllWithMarker(region.ecsClient.NatGateways.List, queues, &natGateways) - if err != nil { - return nil, errors.Wrapf(err, "get nat gateways error by natgatewayid") - } - for i := range natGateways { - natGateways[i].region = region - } - return natGateways, nil -} - -func (region *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayID string) (SNatDEntry, error) { - params := make(map[string]interface{}) - params["nat_gateway_id"] = gatewayID - params["private_ip"] = rule.InternalIP - params["internal_service_port"] = rule.InternalPort - params["floating_ip_id"] = rule.ExternalIPID - params["external_service_port"] = rule.ExternalPort - params["protocol"] = rule.Protocol - - packParams := map[string]map[string]interface{}{ - "dnat_rule": params, - } - - ret := SNatDEntry{} - err := DoCreate(region.ecsClient.DNatRules.Create, jsonutils.Marshal(packParams), &ret) - if err != nil { - return SNatDEntry{}, errors.Wrapf(err, `create dnat rule of nat gateway %q failed`, gatewayID) - } - return ret, nil -} - -func (region *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayID string) (SNatSEntry, error) { - params := make(map[string]interface{}) - params["nat_gateway_id"] = gatewayID - if len(rule.NetworkID) != 0 { - params["network_id"] = rule.NetworkID - } - if len(rule.SourceCIDR) != 0 { - params["cidr"] = rule.SourceCIDR - } - params["floating_ip_id"] = rule.ExternalIPID - - packParams := map[string]map[string]interface{}{ - "snat_rule": params, - } - - ret := SNatSEntry{} - err := DoCreate(region.ecsClient.SNatRules.Create, jsonutils.Marshal(packParams), &ret) - if err != nil { - return SNatSEntry{}, errors.Wrapf(err, `create snat rule of nat gateway %q failed`, gatewayID) - } - return ret, nil -} - -func (region *SRegion) GetNatDEntryByID(id string) (SNatDEntry, error) { - dnat := SNatDEntry{} - err := DoGet(region.ecsClient.DNatRules.Get, id, map[string]string{}, &dnat) - - if err != nil { - return SNatDEntry{}, err - } - return dnat, nil -} - -func (region *SRegion) GetNatSEntryByID(id string) (SNatSEntry, error) { - snat := SNatSEntry{} - err := DoGet(region.ecsClient.SNatRules.Get, id, map[string]string{}, &snat) - if err != nil { - return SNatSEntry{}, cloudprovider.ErrNotFound - } - return snat, nil -} - -func NatResouceStatusTransfer(status string) string { - // In Huawei Cloud, there are isx resource status of Nat, "ACTIVE", "PENDING_CREATE", - // "PENDING_UPDATE", "PENDING_DELETE", "EIP_FREEZED", "INACTIVE". - switch status { - case "ACTIVE": - return api.NAT_STAUTS_AVAILABLE - case "PENDING_CREATE": - return api.NAT_STATUS_ALLOCATE - case "PENDING_UPDATE", "PENDING_DELETE": - return api.NAT_STATUS_DEPLOYING - default: - return api.NAT_STATUS_UNKNOWN - } -} - -func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) { - resp, err := self.ecsClient.NatGateways.Get(id, nil) - if err != nil { - return nil, errors.Wrapf(err, "NatGateways.Get(%s)", id) - } - nat := &SNatGateway{region: self} - err = resp.Unmarshal(nat) - return nat, errors.Wrap(err, "resp.Unmarshal") -} - -func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { - nat, err := self.region.CreateNatGateway(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateNatGateway") - } - return nat, nil -} - -func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGateway, error) { - spec := "" - switch strings.ToLower(opts.NatSpec) { - case api.NAT_SPEC_SMALL: - spec = "1" - case api.NAT_SPEC_MIDDLE: - spec = "2" - case api.NAT_SPEC_LARGE: - spec = "3" - case api.NAT_SPEC_XLARGE: - spec = "4" - } - params := jsonutils.Marshal(map[string]map[string]interface{}{ - "nat_gateway": map[string]interface{}{ - "name": opts.Name, - "description": opts.Desc, - "router_id": opts.VpcId, - "internal_network_id": opts.NetworkId, - "spec": spec, - }, - }) - resp, err := self.ecsClient.NatGateways.Create(params) - if err != nil { - return nil, errors.Wrap(err, "AsyncCreate") - } - nat := &SNatGateway{region: self} - err = resp.Unmarshal(nat) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return nat, nil -} - -func (self *SRegion) DeleteNatGateway(id string) error { - _, err := self.ecsClient.NatGateways.Delete(id, nil) - return errors.Wrapf(err, "NatGateways.Delete(%s)", id) -} diff --git a/pkg/multicloud/huawei/natstable.go b/pkg/multicloud/huawei/natstable.go deleted file mode 100644 index 5ce4d8cd6f..0000000000 --- a/pkg/multicloud/huawei/natstable.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNatSEntry struct { - multicloud.SResourceBase - multicloud.HuaweiTags - gateway *SNatGateway - - ID string `json:"id"` - NatGatewayID string `json:"nat_gateway_id"` - NetworkID string `json:"network_id"` - SourceCIDR string `json:"cidr"` - Status string `json:"status"` - SNatIP string `json:"floating_ip_address"` - AdminStateUp bool `json:"admin_state_up"` -} - -func (nat *SNatSEntry) GetId() string { - return nat.ID -} - -func (nat *SNatSEntry) GetName() string { - // Snat rule has no name in Huawei Cloud, so return ID - return nat.GetId() -} - -func (nat *SNatSEntry) GetGlobalId() string { - return nat.GetId() -} - -func (nat *SNatSEntry) GetStatus() string { - return NatResouceStatusTransfer(nat.Status) -} - -func (nat *SNatSEntry) GetIP() string { - return nat.SNatIP -} - -func (nat *SNatSEntry) GetSourceCIDR() string { - return nat.SourceCIDR -} - -func (nat *SNatSEntry) GetNetworkId() string { - return nat.NetworkID -} - -func (nat *SNatSEntry) Delete() error { - return nat.gateway.region.DeleteNatSEntry(nat.GetId()) -} - -// getNatSTable return all snat rules of gateway -func (gateway *SNatGateway) getNatSTable() ([]SNatSEntry, error) { - ret, err := gateway.region.GetNatSTable(gateway.GetId()) - if err != nil { - return nil, err - } - for i := range ret { - ret[i].gateway = gateway - } - return ret, nil -} - -func (region *SRegion) GetNatSTable(natGatewayID string) ([]SNatSEntry, error) { - queuies := map[string]string{ - "nat_gateway_id": natGatewayID, - } - sNatSTableEntris := make([]SNatSEntry, 0, 2) - err := doListAllWithMarker(region.ecsClient.SNatRules.List, queuies, &sNatSTableEntris) - if err != nil { - return nil, errors.Wrapf(err, `get snat rule of gateway %q`, natGatewayID) - } - for i := range sNatSTableEntris { - nat := &sNatSTableEntris[i] - if len(nat.SourceCIDR) != 0 { - continue - } - subnet := SNetwork{} - err := DoGet(region.ecsClient.Subnets.Get, nat.NetworkID, map[string]string{}, &subnet) - if err != nil { - return nil, errors.Wrapf(err, `get cidr of subnet %q`, nat.NetworkID) - } - nat.SourceCIDR = subnet.CIDR - } - return sNatSTableEntris, nil -} - -func (region *SRegion) DeleteNatSEntry(entryID string) error { - _, err := region.ecsClient.SNatRules.Delete(entryID, nil) - if err != nil { - return errors.Wrapf(err, `delete snat rule %q failed`, entryID) - } - return nil -} - -func (nat *SNatSEntry) Refresh() error { - new, err := nat.gateway.region.GetNatSEntryByID(nat.ID) - if err != nil { - return err - } - return jsonutils.Update(nat, new) -} diff --git a/pkg/multicloud/huawei/network.go b/pkg/multicloud/huawei/network.go deleted file mode 100644 index 2c8923591e..0000000000 --- a/pkg/multicloud/huawei/network.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -/* -Subnets -*/ - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html -type SNetwork struct { - multicloud.SResourceBase - multicloud.HuaweiTags - wire *SWire - - AvailabilityZone string `json:"availability_zone"` - CIDR string `json:"cidr"` - DHCPEnable bool `json:"dhcp_enable"` - DNSList []string `json:"dnsList"` - GatewayIP string `json:"gateway_ip"` - ID string `json:"id"` - Ipv6Enable bool `json:"ipv6_enable"` - Name string `json:"name"` - NeutronNetworkID string `json:"neutron_network_id"` - NeutronSubnetID string `json:"neutron_subnet_id"` - PrimaryDNS string `json:"primary_dns"` - SecondaryDNS string `json:"secondary_dns"` - Status string `json:"status"` - VpcID string `json:"vpc_id"` -} - -func (self *SNetwork) GetId() string { - return self.ID -} - -func (self *SNetwork) GetName() string { - if len(self.Name) == 0 { - return self.ID - } - - return self.Name -} - -func (self *SNetwork) GetGlobalId() string { - return self.ID -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090591.html -func (self *SNetwork) GetStatus() string { - switch self.Status { - case "ACTIVE", "UNKNOWN": - return api.NETWORK_STATUS_AVAILABLE // ? todo: // UNKNOWN - case "ERROR": - return api.NETWORK_STATUS_UNKNOWN - default: - return api.NETWORK_STATUS_UNKNOWN - } -} - -func (self *SNetwork) Refresh() error { - log.Debugf("network refresh %s", self.GetId()) - new, err := self.wire.region.getNetwork(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SNetwork) IsEmulated() bool { - return false -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - startIp = startIp.StepUp() // 2 - return startIp.String() -} - -func (self *SNetwork) GetIpEnd() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - 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.CIDR) - return pref.MaskLen -} - -func (self *SNetwork) GetGateway() string { - pref, _ := netutils.NewIPV4Prefix(self.CIDR) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - return startIp.String() -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetIsPublic() bool { - return true -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) Delete() error { - return self.wire.region.deleteNetwork(self.VpcID, self.GetId()) -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) { - network := SNetwork{} - err := DoGet(self.ecsClient.Subnets.Get, networkId, nil, &network) - return &network, err -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090592.html -func (self *SRegion) GetNetwroks(vpcId string) ([]SNetwork, error) { - querys := map[string]string{} - if len(vpcId) > 0 { - querys["vpc_id"] = vpcId - } - - networks := make([]SNetwork, 0) - err := doListAllWithMarker(self.ecsClient.Subnets.List, querys, &networks) - return networks, err -} - -func (self *SRegion) deleteNetwork(vpcId string, networkId string) error { - ctx := &modules.SManagerContext{InstanceId: vpcId, InstanceManager: self.ecsClient.Vpcs} - return DoDeleteWithSpec(self.ecsClient.Subnets.DeleteInContextWithSpec, ctx, networkId, "", nil, nil) -} - -func (self *SNetwork) GetProjectId() string { - return self.wire.vpc.EnterpriseProjectID -} diff --git a/pkg/multicloud/huawei/object.go b/pkg/multicloud/huawei/object.go deleted file mode 100644 index 6a8fe7d9b3..0000000000 --- a/pkg/multicloud/huawei/object.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "net/http" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei/obs" -) - -type SObject struct { - bucket *SBucket - - cloudprovider.SBaseCloudObject -} - -func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { - return o.bucket -} - -func (o *SObject) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - obscli, err := o.bucket.region.getOBSClient() - if err != nil { - log.Errorf("o.bucket.region.GetOssClient error %s", err) - return acl - } - input := &obs.GetObjectAclInput{} - input.Bucket = o.bucket.Name - input.Key = o.Key - output, err := obscli.GetObjectAcl(input) - if err != nil { - log.Errorf("GetObjectAcl error: %v", err) - return acl - } - acl = obsAcl2CannedAcl(output.Grants) - return acl -} - -func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { - obscli, err := o.bucket.region.getOBSClient() - if err != nil { - return errors.Wrap(err, "o.bucket.region.getOBSClient") - } - input := &obs.SetObjectAclInput{} - input.Bucket = o.bucket.Name - input.Key = o.Key - input.ACL = obs.AclType(string(aclStr)) - _, err = obscli.SetObjectAcl(input) - if err != nil { - return errors.Wrap(err, "obscli.SetObjectAcl") - } - return nil -} - -func (o *SObject) GetMeta() http.Header { - if o.Meta != nil { - return o.Meta - } - obscli, err := o.bucket.region.getOBSClient() - if err != nil { - log.Errorf("getOBSClient fail %s", err) - return nil - } - input := &obs.GetObjectMetadataInput{} - input.Bucket = o.bucket.Name - input.Key = o.Key - output, err := obscli.GetObjectMetadata(input) - if err != nil { - log.Errorf("obscli.GetObjectMetadata fail %s", err) - return nil - } - meta := http.Header{} - for k, v := range output.Metadata { - meta.Add(k, v) - } - if len(output.ContentType) > 0 { - meta.Add(cloudprovider.META_HEADER_CONTENT_TYPE, output.ContentType) - } - o.Meta = meta - return meta -} - -func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { - return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) -} diff --git a/pkg/multicloud/huawei/obs/doc.go b/pkg/multicloud/huawei/obs/doc.go deleted file mode 100644 index 77b0336052..0000000000 --- a/pkg/multicloud/huawei/obs/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 obs // import "yunion.io/x/onecloud/pkg/multicloud/huawei/obs" diff --git a/pkg/multicloud/huawei/order.go b/pkg/multicloud/huawei/order.go deleted file mode 100644 index 5c30937063..0000000000 --- a/pkg/multicloud/huawei/order.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SOrder struct { - ErrorCode *string `json:"error_code"` // 只有失败时才返回此参数 - ErrorMsg *string `json:"error_msg"` //只有失败时才返回此参数 - TotalSize int `json:"totalSize"` // 只有成功时才返回此参数 - Resources []SResource `json:"resources"` -} - -type SResource struct { - ResourceID string `json:"resourceId"` - CloudServiceType string `json:"cloudServiceType"` - RegionCode string `json:"regionCode"` - ResourceType string `json:"resourceType"` - ResourceSpecCode string `json:"resourceSpecCode"` - Status int64 `json:"status"` -} - -type SResourceDetail struct { - ID string `json:"id"` - Status int64 `json:"status"` - ResourceID string `json:"resource_id"` - ResourceName string `json:"resource_name"` - RegionCode string `json:"region_code"` - CloudServiceTypeCode string `json:"cloud_service_type_code"` - ResourceTypeCode string `json:"resource_type_code"` - ResourceSpecCode string `json:"resource_spec_code"` - ProjectCode string `json:"project_code"` - ProductID string `json:"product_id"` - MainResourceID string `json:"main_resource_id"` - IsMainResource int64 `json:"is_main_resource"` - ValidTime time.Time `json:"valid_time"` - ExpireTime time.Time `json:"expire_time"` - NextOperationPolicy string `json:"next_operation_policy"` -} - -func (self *SRegion) getDomianId() (string, error) { - domains, err := self.client.getEnabledDomains() - if err != nil { - return "", err - } - - if domains == nil || len(domains) == 0 { - return "", fmt.Errorf("GetAllResByOrderId domain is empty") - } else if len(domains) > 1 { - // not supported?? - return "", fmt.Errorf("GetAllResByOrderId mutliple domain(%d) found", len(domains)) - } - - return domains[0].ID, nil -} - -/* -获取订单信息 https://support.huaweicloud.com/api-oce/api_order_00001.html -*/ -func (self *SRegion) GetOrder(orderId string) (SOrder, error) { - var order SOrder - domain, err := self.getDomianId() - if err != nil { - return order, err - } - - err = self.ecsClient.Orders.SetDomainId(domain) - if err != nil { - return order, err - } - - err = DoGet(self.ecsClient.Orders.Get, orderId, nil, &order) - return order, err -} - -/* -获取订单资源详情列表 https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html -*/ -func (self *SRegion) GetOrderResources(orderId string, resource_ids []string, only_main_resource bool) ([]SResourceDetail, error) { - domain, err := self.getDomianId() - if err != nil { - return nil, err - } - - err = self.ecsClient.Orders.SetDomainId(domain) - if err != nil { - return nil, err - } - - resources := make([]SResourceDetail, 0) - queries := map[string]string{"customer_id": domain} - if len(orderId) > 0 { - queries["order_id"] = orderId - } - - if len(resource_ids) > 0 { - queries["resource_ids"] = strings.Join(resource_ids, ",") - } - - if only_main_resource { - queries["only_main_resource"] = "1" - } - - err = doListAll(self.ecsClient.Orders.GetPeriodResourceList, queries, &resources) - return resources, err -} - -/* -获取资源详情 https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html -*/ -func (self *SRegion) GetOrderResourceDetail(resourceId string) (SResourceDetail, error) { - var res SResourceDetail - if len(resourceId) == 0 { - return res, fmt.Errorf("GetOrderResourceDetail resource id should not be empty") - } - - resources, err := self.GetOrderResources("", []string{resourceId}, false) - if err != nil { - return res, err - } - - switch len(resources) { - case 0: - return res, cloudprovider.ErrNotFound - case 1: - return resources[0], nil - default: - return res, fmt.Errorf("%d resources with id %s found, Expect 1", len(resources), resourceId) - } -} - -func (self *SRegion) GetAllResByOrderId(orderId string) ([]SResource, error) { - order, err := self.GetOrder(orderId) - if err != nil { - return nil, err - } - - log.Debugf("GetAllResByOrderId %#v", order.Resources) - return order.Resources, nil -} - -func (self *SRegion) getAllResByType(orderId string, resourceType string) ([]SResource, error) { - res, err := self.GetAllResByOrderId(orderId) - if err != nil { - return nil, err - } - - ret := make([]SResource, 0) - for i := range res { - r := res[i] - if r.ResourceType == resourceType { - ret = append(ret, r) - } - } - - return ret, nil -} - -func (self *SRegion) getAllResIdsByType(orderId string, resourceType string) ([]string, error) { - res, err := self.getAllResByType(orderId, resourceType) - if err != nil { - return nil, err - } - - ids := make([]string, 0) - for _, r := range res { - if len(r.ResourceID) > 0 { - ids = append(ids, r.ResourceID) - } - } - - return ids, nil -} diff --git a/pkg/multicloud/huawei/port.go b/pkg/multicloud/huawei/port.go deleted file mode 100644 index 2258e85f48..0000000000 --- a/pkg/multicloud/huawei/port.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "strings" - - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SFixedIP struct { - IpAddress string - SubnetID string - NetworkId string -} - -func (fixip *SFixedIP) GetGlobalId() string { - return fixip.IpAddress -} - -func (fixip *SFixedIP) GetIP() string { - return fixip.IpAddress -} - -func (fixip *SFixedIP) GetINetworkId() string { - return fixip.NetworkId -} - -func (fixip *SFixedIP) IsPrimary() bool { - return true -} - -type Port struct { - multicloud.SNetworkInterfaceBase - multicloud.HuaweiTags - region *SRegion - ID string `json:"id"` - Name string `json:"name"` - Status string `json:"status"` - AdminStateUp string `json:"admin_state_up"` - DNSName string `json:"dns_name"` - MACAddress string `json:"mac_address"` - NetworkID string `json:"network_id"` - TenantID string `json:"tenant_id"` - DeviceID string `json:"device_id"` - DeviceOwner string `json:"device_owner"` - BindingVnicType string `json:"binding:vnic_type"` - FixedIps []SFixedIP -} - -func (port *Port) GetName() string { - if len(port.Name) > 0 { - return port.Name - } - return port.ID -} - -func (port *Port) GetId() string { - return port.ID -} - -func (port *Port) GetGlobalId() string { - return port.ID -} - -func (port *Port) GetMacAddress() string { - return port.MACAddress -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html -func (port *Port) GetAssociateType() string { - switch port.DeviceOwner { - case "compute:nova": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER - case "network:router_gateway", "network:router_interface", "network:router_interface_distributed": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_RESERVED - case "network:dhcp": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_DHCP - case "neutron:LOADBALANCERV2": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_LOADBALANCER - case "neutron:VIP_PORT": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_VIP - default: - if strings.HasPrefix(port.DeviceOwner, "compute:") { - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER - } - } - return port.DeviceOwner -} - -func (port *Port) GetAssociateId() string { - return port.DeviceID -} - -func (port *Port) GetStatus() string { - switch port.Status { - case "ACTIVE", "DOWN": - return api.NETWORK_INTERFACE_STATUS_AVAILABLE - case "BUILD": - return api.NETWORK_INTERFACE_STATUS_CREATING - } - return port.Status -} - -func (port *Port) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { - address := []cloudprovider.ICloudInterfaceAddress{} - for i := 0; i < len(port.FixedIps); i++ { - port.FixedIps[i].NetworkId = port.NetworkID - address = append(address, &port.FixedIps[i]) - } - return address, nil -} - -func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { - ports, err := region.GetPorts("") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNetworkInterface{} - for i := 0; i < len(ports); i++ { - if len(ports[i].DeviceID) == 0 || !utils.IsInStringArray(ports[i].DeviceOwner, []string{"compute:CCI", "compute:nova", "neutron:LOADBALANCERV2"}) { - ports[i].region = region - ret = append(ret, &ports[i]) - } - } - return ret, nil -} - -func (self *SRegion) GetPort(portId string) (Port, error) { - port := Port{} - err := DoGet(self.ecsClient.Port.Get, portId, nil, &port) - return port, err -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html -func (self *SRegion) GetPorts(instanceId string) ([]Port, error) { - ports := make([]Port, 0) - querys := map[string]string{} - if len(instanceId) > 0 { - querys["device_id"] = instanceId - } - - err := doListAllWithMarker(self.ecsClient.Port.List, querys, &ports) - return ports, err -} diff --git a/pkg/multicloud/huawei/project.go b/pkg/multicloud/huawei/project.go deleted file mode 100644 index 0dce0f8297..0000000000 --- a/pkg/multicloud/huawei/project.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "strings" - - api "yunion.io/x/onecloud/pkg/apis/compute" -) - -// https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845625.html -type SProject struct { - client *SHuaweiClient - - IsDomain bool `json:"is_domain"` - Description string `json:"description"` - Enabled bool `json:"enabled"` - ID string `json:"id"` - ParentID string `json:"parent_id"` - DomainID string `json:"domain_id"` - Name string `json:"name"` -} - -func (self *SProject) GetRegionID() string { - return strings.Split(self.Name, "_")[0] -} - -func (self *SProject) GetHealthStatus() string { - if self.Enabled { - return api.CLOUD_PROVIDER_HEALTH_NORMAL - } - - return api.CLOUD_PROVIDER_HEALTH_SUSPENDED -} - -func (self *SHuaweiClient) fetchProjects() ([]SProject, error) { - if self.projects != nil { - return self.projects, nil - } - - huawei, _ := self.newGeneralAPIClient() - projects := make([]SProject, 0) - err := doListAll(huawei.Projects.List, nil, &projects) - if err == nil { - self.projects = projects - } - - return projects, err -} - -// obs 权限必须赋予到mos project之上 -func (self *SHuaweiClient) GetMosProjectId() string { - projects, err := self.GetProjects() - if err != nil { - return "" - } - for i := range projects { - if strings.ToLower(projects[i].Name) == "mos" { - return projects[i].ID - } - } - return "" -} - -func (self *SHuaweiClient) GetProjectById(projectId string) (SProject, error) { - projects, err := self.fetchProjects() - if err != nil { - return SProject{}, err - } - - for _, project := range projects { - if project.ID == projectId { - return project, nil - } - } - return SProject{}, fmt.Errorf("project %s not found", projectId) -} - -func (self *SHuaweiClient) GetProjects() ([]SProject, error) { - return self.fetchProjects() -} diff --git a/pkg/multicloud/huawei/provider/doc.go b/pkg/multicloud/huawei/provider/doc.go deleted file mode 100644 index 19893de9aa..0000000000 --- a/pkg/multicloud/huawei/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/huawei/provider" diff --git a/pkg/multicloud/huawei/provider/provider.go b/pkg/multicloud/huawei/provider/provider.go deleted file mode 100644 index 0a2e40c2bd..0000000000 --- a/pkg/multicloud/huawei/provider/provider.go +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/huawei" -) - -type SHuaweiProviderFactory struct { - cloudprovider.SPublicCloudBaseProviderFactory -} - -func (self *SHuaweiProviderFactory) GetId() string { - return huawei.CLOUD_PROVIDER_HUAWEI -} - -func (self *SHuaweiProviderFactory) GetName() string { - return huawei.CLOUD_PROVIDER_HUAWEI_CN -} - -func (self *SHuaweiProviderFactory) IsCloudeventRegional() bool { - return true -} - -func (self *SHuaweiProviderFactory) GetMaxCloudEventSyncDays() int { - return 7 -} - -func (self *SHuaweiProviderFactory) GetMaxCloudEventKeepDays() int { - return 7 -} - -func (self *SHuaweiProviderFactory) IsSupportCloudIdService() bool { - return true -} - -func (self *SHuaweiProviderFactory) IsSupportClouduserPolicy() bool { - return false -} - -func (self *SHuaweiProviderFactory) IsSupportCreateCloudgroup() bool { - return true -} - -func (factory *SHuaweiProviderFactory) IsSupportCrossCloudEnvVpcPeering() bool { - return false -} - -func (factory *SHuaweiProviderFactory) IsSupportCrossRegionVpcPeering() bool { - return false -} - -func (factory *SHuaweiProviderFactory) IsSupportVpcPeeringVpcCidrOverlap() bool { - return true -} - -func (factory *SHuaweiProviderFactory) IsSupportModifyRouteTable() bool { - return true -} - -func (factory *SHuaweiProviderFactory) IsSupportSAMLAuth() bool { - return true -} - -func (self *SHuaweiProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - if len(input.Environment) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "environment") - } - - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - output.AccessUrl = input.Environment - - return output, nil -} - -func (self *SHuaweiProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func parseAccount(account string) (accessKey string, projectId string) { - segs := strings.Split(account, "/") - if len(segs) == 2 { - accessKey = segs[0] - projectId = segs[1] - } else { - accessKey = account - projectId = "" - } - - return -} - -func (self *SHuaweiProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - accessKey, projectId := parseAccount(cfg.Account) - client, err := huawei.NewHuaweiClient( - huawei.NewHuaweiClientConfig( - cfg.URL, accessKey, cfg.Secret, projectId, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SHuaweiProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SHuaweiProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - accessKey, projectId := parseAccount(info.Account) - region := huawei.HUAWEI_DEFAULT_REGION - data := strings.Split(info.Name, "-") - if len(data) >= 3 { - region = strings.Join(data[len(data)-3:], "-") - } - return map[string]string{ - "HUAWEI_CLOUD_ENV": info.Url, - "HUAWEI_ACCESS_KEY": accessKey, - "HUAWEI_SECRET": info.Secret, - "HUAWEI_REGION": region, - "HUAWEI_PROJECT": projectId, - }, nil -} - -func init() { - factory := SHuaweiProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SHuaweiProvider struct { - cloudprovider.SBaseProvider - client *huawei.SHuaweiClient -} - -func (self *SHuaweiProvider) GetVersion() string { - return self.client.GetVersion() -} - -func (self *SHuaweiProvider) GetSysInfo() (jsonutils.JSONObject, error) { - regions := self.client.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") - info.Add(jsonutils.NewString(huawei.HUAWEI_API_VERSION), "api_version") - return info, nil -} - -func (self *SHuaweiProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SHuaweiProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(extId) -} - -func (self *SHuaweiProvider) GetBalance() (float64, string, error) { - balance, err := self.client.QueryAccountBalance() - if err != nil { - return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, err - } - status := api.CLOUD_PROVIDER_HEALTH_NORMAL - if balance.AvailableAmount < 0.0 && balance.CreditAmount < 0.0 { - status = api.CLOUD_PROVIDER_HEALTH_ARREARS - } - return balance.AvailableAmount, status, nil -} - -func (self *SHuaweiProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SHuaweiProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SHuaweiProvider) GetIamLoginUrl() string { - return self.client.GetIamLoginUrl() -} - -func (self *SHuaweiProvider) GetCloudRegionExternalIdPrefix() string { - return self.client.GetCloudRegionExternalIdPrefix() -} - -func (self *SHuaweiProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SHuaweiProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return self.client.CreateIProject(name) -} - -func (self *SHuaweiProvider) GetStorageClasses(regionId string) []string { - return []string{ - "STANDARD", "WARM", "COLD", - } -} - -func (self *SHuaweiProvider) GetBucketCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLAuthRead), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SHuaweiProvider) GetObjectCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLAuthRead), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - } -} - -func (self *SHuaweiProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SHuaweiProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - return self.client.CreateIClouduser(conf) -} - -func (self *SHuaweiProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { - return self.client.GetICloudusers() -} - -func (self *SHuaweiProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroups() -} - -func (self *SHuaweiProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroupByName(name) -} - -func (self *SHuaweiProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - return self.client.CreateICloudgroup(name, desc) -} - -func (self *SHuaweiProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetISystemCloudpolicies() -} - -func (self *SHuaweiProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return []cloudprovider.ICloudpolicy{}, nil -} - -func (self *SHuaweiProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.client.GetIClouduserByName(name) -} - -func (self *SHuaweiProvider) GetSamlEntityId() string { - return cloudprovider.SAML_ENTITY_ID_HUAWEI_CLOUD -} - -func (self *SHuaweiProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { - return self.client.GetICloudSAMLProviders() -} - -func (self *SHuaweiProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { - sp, err := self.client.CreateSAMLProvider(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateSAMLProvider") - } - return sp, nil -} - -func (self *SHuaweiProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metrics, err := self.client.GetMetrics(opts) - if err != nil { - return nil, errors.Wrapf(err, "GetMetrics") - } - return metrics, nil -} diff --git a/pkg/multicloud/huawei/quota.go b/pkg/multicloud/huawei/quota.go deleted file mode 100644 index 047ec3dfee..0000000000 --- a/pkg/multicloud/huawei/quota.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SQuota struct { - Min int - Quota int - Type string - Used int -} - -func (q *SQuota) GetGlobalId() string { - return q.Type -} - -func (q *SQuota) GetQuotaType() string { - return q.Type -} - -func (q *SQuota) GetName() string { - return q.Type -} - -func (q *SQuota) GetDesc() string { - return "" -} - -func (q *SQuota) GetMaxQuotaCount() int { - return q.Quota -} - -func (q *SQuota) GetCurrentQuotaUsedCount() int { - return q.Used -} - -func (self *SRegion) GetQuotas() ([]SQuota, error) { - quotas := []SQuota{} - params := map[string]string{} - result, err := self.ecsClient.Quotas.Get("", params) - if err != nil { - return nil, errors.Wrap(err, "Quotas.List") - } - - err = result.Unmarshal("as, "resources") - if err != nil { - return nil, errors.Wrap(err, "result.Unmarshal") - } - - return quotas, nil -} - -func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { - quotas, err := region.GetQuotas() - if err != nil { - return nil, errors.Wrap(err, "GetQuotas") - } - ret := []cloudprovider.ICloudQuota{} - for i := range quotas { - ret = append(ret, "as[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/huawei/region.go b/pkg/multicloud/huawei/region.go deleted file mode 100644 index baffc8c785..0000000000 --- a/pkg/multicloud/huawei/region.go +++ /dev/null @@ -1,862 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client" - "yunion.io/x/onecloud/pkg/multicloud/huawei/obs" -) - -type Locales struct { - EnUs string `json:"en-us"` - ZhCN string `json:"zh-cn"` -} - -// https://support.huaweicloud.com/api-iam/zh-cn_topic_0067148043.html -type SRegion struct { - multicloud.SRegion - - client *SHuaweiClient - ecsClient *client.Client - obsClient *obs.ObsClient // 对象存储client.请勿直接引用。 - - Description string `json:"description"` - ID string `json:"id"` - Locales Locales `json:"locales"` - ParentRegionID string `json:"parent_region_id"` - Type string `json:"type"` - - izones []cloudprovider.ICloudZone - ivpcs []cloudprovider.ICloudVpc - - storageCache *SStoragecache -} - -func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetClient() *SHuaweiClient { - return self.client -} - -func (self *SRegion) getECSClient() (*client.Client, error) { - var err error - - if len(self.client.projectId) > 0 { - project, err := self.client.GetProjectById(self.client.projectId) - if err != nil { - return nil, err - } - - if !strings.Contains(project.Name, self.ID) { - return nil, errors.Errorf("region %s and project %s mismatch", self.ID, project.Name) - } - } - - if self.ecsClient == nil { - self.ecsClient, err = self.client.newRegionAPIClient(self.ID) - if err != nil { - return nil, err - } - } - - return self.ecsClient, err -} - -func (self *SRegion) getOBSEndpoint() string { - return getOBSEndpoint(self.GetId()) -} - -func (self *SRegion) getOBSClient() (*obs.ObsClient, error) { - if self.obsClient == nil { - obsClient, err := self.client.getOBSClient(self.GetId()) - if err != nil { - return nil, err - } - - self.obsClient = obsClient - } - - return self.obsClient, nil -} - -func (self *SRegion) fetchZones() error { - zones := make([]SZone, 0) - err := doListAll(self.ecsClient.Zones.List, nil, &zones) - if err != nil { - return err - } - - self.izones = make([]cloudprovider.ICloudZone, 0) - for i := range zones { - zone := zones[i] - zone.region = self - self.izones = append(self.izones, &zone) - } - return nil -} - -func (self *SRegion) fetchIVpcs() error { - // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html - vpcs := make([]SVpc, 0) - querys := map[string]string{ - "limit": "2048", - } - err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs) - if err != nil { - return err - } - - self.ivpcs = make([]cloudprovider.ICloudVpc, 0) - for i := range vpcs { - vpc := vpcs[i] - vpc.region = self - self.ivpcs = append(self.ivpcs, &vpc) - } - return nil -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - if len(id) == 0 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetIVMById") - } - - instance, err := self.GetInstanceByID(id) - if err != nil { - return nil, err - } - return &instance, err -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return self.GetDisk(id) -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - if info, ok := LatitudeAndLongitude[self.ID]; ok { - return info - } - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - elbs, err := self.GetLoadBalancers() - if err != nil { - return nil, err - } - - ielbs := make([]cloudprovider.ICloudLoadbalancer, len(elbs)) - for i := range elbs { - elbs[i].region = self - ielbs[i] = &elbs[i] - } - - return ielbs, nil -} - -func (self *SRegion) GetLoadBalancers() ([]SLoadbalancer, error) { - lbs := []SLoadbalancer{} - params := url.Values{} - return lbs, self.lbListAll("elb/loadbalancers", params, "loadbalancers", &lbs) -} - -func (self *SRegion) GetILoadBalancerById(id string) (cloudprovider.ICloudLoadbalancer, error) { - elb, err := self.GetLoadbalancer(id) - if err != nil { - return nil, err - } - return elb, nil -} - -func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { - acl, err := self.GetLoadBalancerAcl(aclId) - if err != nil { - return nil, err - } - return acl, nil -} - -func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - cert, err := self.GetLoadBalancerCertificate(certId) - if err != nil { - return nil, err - } - return cert, nil -} - -func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - ret, err := self.CreateLoadBalancerCertificate(cert) - if err != nil { - return nil, err - } - return ret, nil -} - -func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { - ret, err := self.GetLoadBalancerAcls("") - if err != nil { - return nil, err - } - - iret := make([]cloudprovider.ICloudLoadbalancerAcl, len(ret)) - for i := range ret { - ret[i].region = self - iret[i] = &ret[i] - } - return iret, nil -} - -func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - ret, err := self.GetLoadBalancerCertificates() - if err != nil { - return nil, err - } - - iret := make([]cloudprovider.ICloudLoadbalancerCertificate, len(ret)) - for i := range ret { - ret[i].region = self - iret[i] = &ret[i] - } - return iret, nil -} - -// https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845622.html -func (self *SRegion) GetId() string { - return self.ID -} - -func (self *SRegion) GetName() string { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.Locales.ZhCN) -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.Locales.EnUs) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.ID) -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) Refresh() error { - return nil -} - -func (self *SRegion) IsEmulated() bool { - return false -} - -func (self *SRegion) GetLatitude() float32 { - if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok { - return locationInfo.Latitude - } - return 0.0 -} - -func (self *SRegion) GetLongitude() float32 { - if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok { - return locationInfo.Longitude - } - return 0.0 -} - -func (self *SRegion) fetchInfrastructure() error { - _, err := self.getECSClient() - if 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 { - vpc := self.ivpcs[i].(*SVpc) - wire := SWire{region: self, vpc: vpc} - vpc.addWire(&wire) - - for j := 0; j < len(self.izones); j += 1 { - zone := self.izones[j].(*SZone) - zone.addWire(&wire) - } - } - return nil -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if self.izones == nil { - var err error - err = self.fetchInfrastructure() - if 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) { - eips, err := self.GetEips("", nil) - if err != nil { - return nil, err - } - - ret := []cloudprovider.ICloudEIP{} - for i := 0; i < len(eips); i += 1 { - eips[i].region = self - ret = append(ret, &eips[i]) - } - return ret, nil -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - ivpcs, err := self.GetIVpcs() - if err != nil { - return nil, err - } - for i := 0; i < len(ivpcs); i += 1 { - if ivpcs[i].GetGlobalId() == id { - return ivpcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { - eip, err := self.GetEip(eipId) - if err != nil { - return nil, err - } - return eip, nil -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0060595555.html -func (self *SRegion) DeleteSecurityGroup(secgroupId string) error { - return DoDelete(self.ecsClient.SecurityGroups.Delete, secgroupId, nil, nil) -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - return self.GetSecurityGroupDetails(secgroupId) -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := self.GetSecurityGroups(opts.VpcId, opts.Name) - if err != nil { - return nil, err - } - if len(secgroups) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(secgroups) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - secgroups[0].region = self - return &secgroups[0], nil -} - -func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - return self.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090608.html -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - return self.CreateVpc(opts.NAME, opts.CIDR, opts.Desc) -} - -func (self *SRegion) CreateVpc(name, cidr, desc string) (*SVpc, error) { - params := map[string]interface{}{ - "vpc": map[string]string{ - "name": name, - "cidr": cidr, - "description": desc, - }, - } - vpc := &SVpc{region: self} - return vpc, DoCreate(self.ecsClient.Vpcs.Create, jsonutils.Marshal(params), vpc) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html -// size: 1Mbit/s~2000Mbit/s -// bgpType: 5_telcom,5_union,5_bgp,5_sbgp. -// 东北-大连:5_telcom、5_union -// 华南-广州:5_sbgp -// 华东-上海二:5_sbgp -// 华北-北京一:5_bgp、5_sbgp -// 亚太-香港:5_bgp -func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - var ctype TInternetChargeType - switch eip.ChargeType { - case api.EIP_CHARGE_TYPE_BY_TRAFFIC: - ctype = InternetChargeByTraffic - case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: - ctype = InternetChargeByBandwidth - } - - // todo: 如何避免hardcode。集成到cloudmeta服务中? - if len(eip.BGPType) == 0 { - switch self.GetId() { - case "cn-north-1", "cn-east-2", "cn-south-1": - eip.BGPType = "5_sbgp" - case "cn-northeast-1": - eip.BGPType = "5_telcom" - case "cn-north-4", "ap-southeast-1", "ap-southeast-2", "eu-west-0": - eip.BGPType = "5_bgp" - case "cn-southwest-2": - eip.BGPType = "5_sbgp" - default: - eip.BGPType = "5_bgp" - } - } - - // 华为云EIP名字最大长度64 - if len(eip.Name) > 64 { - eip.Name = eip.Name[:64] - } - - ieip, err := self.AllocateEIP(eip.Name, eip.BandwidthMbps, ctype, eip.BGPType, eip.ProjectId) - ieip.region = self - if err != nil { - return nil, err - } - - err = cloudprovider.WaitStatus(ieip, api.EIP_STATUS_READY, 5*time.Second, 60*time.Second) - return ieip, err -} - -func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := self.GetSnapshots("", "") - if err != nil { - log.Errorf("self.GetSnapshots fail %s", err) - return nil, err - } - - ret := make([]cloudprovider.ICloudSnapshot, len(snapshots)) - for i := 0; i < len(snapshots); i += 1 { - snapshots[i].region = self - ret[i] = &snapshots[i] - } - return ret, nil -} - -func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := self.GetSnapshotById(snapshotId) - return &snapshot, err -} - -func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - iHosts := make([]cloudprovider.ICloudHost, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneHost, err := izones[i].GetIHosts() - if err != nil { - return nil, err - } - iHosts = append(iHosts, iZoneHost...) - } - return iHosts, nil -} - -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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetProvider() string { - return CLOUD_PROVIDER_HUAWEI -} - -func (self *SRegion) GetCloudEnv() string { - return self.client.cloudEnv -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html -// 目前desc字段并没有用到 -func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (*SSecurityGroup, error) { - // 华为不允许创建名称为default的安全组 - if strings.ToLower(name) == "default" { - name = fmt.Sprintf("%s-%s", vpcId, name) - } - - params := jsonutils.NewDict() - secgroupObj := jsonutils.NewDict() - secgroupObj.Add(jsonutils.NewString(name), "name") - if len(vpcId) > 0 && vpcId != api.NORMAL_VPC_ID { - secgroupObj.Add(jsonutils.NewString(vpcId), "vpc_id") - } - params.Add(secgroupObj, "security_group") - - secgroup := SSecurityGroup{region: self} - err := DoCreate(self.ecsClient.SecurityGroups.Create, params, &secgroup) - return &secgroup, err -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087467071.html -func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error { - _, err := self.ecsClient.SecurityGroupRules.DeleteInContextWithSpec(nil, secGrpRuleId, "", nil, nil, "") - return err -} - -func (self *SRegion) DeleteSecurityGroupRule(ruleId string) error { - return self.delSecurityGroupRule(ruleId) -} - -func (self *SRegion) CreateSecurityGroupRule(secgroupId string, rule cloudprovider.SecurityRule) error { - return self.addSecurityGroupRules(secgroupId, rule) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087451723.html -// icmp port对应关系:https://support.huaweicloud.com/api-vpc/zh-cn_topic_0024109590.html -func (self *SRegion) addSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error { - direction := "" - if rule.Direction == secrules.SecurityRuleIngress { - direction = "ingress" - } else { - direction = "egress" - } - - protocal := rule.Protocol - if rule.Protocol == secrules.PROTO_ANY { - protocal = "" - } - - // imcp协议默认为any - if rule.Protocol == secrules.PROTO_ICMP { - return self.addSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String()) - } - - if len(rule.Ports) > 0 { - for _, port := range rule.Ports { - portStr := fmt.Sprintf("%d", port) - err := self.addSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String()) - if err != nil { - return err - } - } - } else { - portStart := fmt.Sprintf("%d", rule.PortStart) - portEnd := fmt.Sprintf("%d", rule.PortEnd) - err := self.addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String()) - if err != nil { - return err - } - } - - return nil -} - -func (self *SRegion) addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error { - params := jsonutils.NewDict() - secgroupObj := jsonutils.NewDict() - secgroupObj.Add(jsonutils.NewString(secGrpId), "security_group_id") - secgroupObj.Add(jsonutils.NewString(direction), "direction") - secgroupObj.Add(jsonutils.NewString(ipNet), "remote_ip_prefix") - secgroupObj.Add(jsonutils.NewString("IPV4"), "ethertype") - // 端口为空或者1-65535 - if len(portStart) > 0 && portStart != "0" && portStart != "-1" { - secgroupObj.Add(jsonutils.NewString(portStart), "port_range_min") - } - if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" { - secgroupObj.Add(jsonutils.NewString(portEnd), "port_range_max") - } - if len(protocol) > 0 { - secgroupObj.Add(jsonutils.NewString(protocol), "protocol") - } - params.Add(secgroupObj, "security_group_rule") - - rule := SecurityGroupRule{} - return DoCreate(self.ecsClient.SecurityGroupRules.Create, params, &rule) -} - -func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - ret, err := self.CreateLoadBalancer(loadbalancer) - if err != nil { - return nil, err - } - - return ret, nil -} - -func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - ret, err := self.CreateLoadBalancerAcl(acl) - if err != nil { - return nil, err - } - - return ret, nil -} - -func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - iBuckets, err := region.client.getIBuckets() - if err != nil { - return nil, errors.Wrap(err, "getIBuckets") - } - ret := make([]cloudprovider.ICloudBucket, 0) - for i := range iBuckets { - // huawei OBS is shared across projects - if iBuckets[i].GetLocation() == region.GetId() { - ret = append(ret, iBuckets[i]) - } - } - return ret, nil -} - -func str2StorageClass(storageClassStr string) (obs.StorageClassType, error) { - if strings.EqualFold(storageClassStr, string(obs.StorageClassStandard)) { - return obs.StorageClassStandard, nil - } else if strings.EqualFold(storageClassStr, string(obs.StorageClassWarm)) { - return obs.StorageClassWarm, nil - } else if strings.EqualFold(storageClassStr, string(obs.StorageClassCold)) { - return obs.StorageClassCold, nil - } else { - return obs.StorageClassStandard, errors.Error("unsupported storageClass") - } -} - -func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { - obsClient, err := region.getOBSClient() - if err != nil { - return errors.Wrap(err, "region.getOBSClient") - } - input := &obs.CreateBucketInput{} - input.Bucket = name - input.Location = region.GetId() - if len(aclStr) > 0 { - if strings.EqualFold(aclStr, string(obs.AclPrivate)) { - input.ACL = obs.AclPrivate - } else if strings.EqualFold(aclStr, string(obs.AclPublicRead)) { - input.ACL = obs.AclPublicRead - } else if strings.EqualFold(aclStr, string(obs.AclPublicReadWrite)) { - input.ACL = obs.AclPublicReadWrite - } else { - return errors.Error("unsupported acl") - } - } - if len(storageClassStr) > 0 { - input.StorageClass, err = str2StorageClass(storageClassStr) - if err != nil { - return err - } - } - _, err = obsClient.CreateBucket(input) - if err != nil { - return errors.Wrap(err, "obsClient.CreateBucket") - } - region.client.invalidateIBuckets() - return nil -} - -func obsHttpCode(err error) int { - switch httpErr := err.(type) { - case obs.ObsError: - return httpErr.StatusCode - case *obs.ObsError: - return httpErr.StatusCode - } - return -1 -} - -func (region *SRegion) DeleteIBucket(name string) error { - obsClient, err := region.getOBSClient() - if err != nil { - return errors.Wrap(err, "region.getOBSClient") - } - _, err = obsClient.DeleteBucket(name) - if err != nil { - if obsHttpCode(err) == 404 { - return nil - } - log.Debugf("%#v %s", err, err) - return errors.Wrap(err, "DeleteBucket") - } - region.client.invalidateIBuckets() - return nil -} - -func (region *SRegion) HeadBucket(name string) (*obs.BaseModel, error) { - obsClient, err := region.getOBSClient() - if err != nil { - return nil, errors.Wrap(err, "region.getOBSClient") - } - return obsClient.HeadBucket(name) -} - -func (region *SRegion) IBucketExist(name string) (bool, error) { - _, err := region.HeadBucket(name) - if err != nil { - if obsHttpCode(err) == 404 { - return false, nil - } else { - return false, errors.Wrap(err, "HeadBucket") - } - } - return true, nil -} - -func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { - return cloudprovider.GetIBucketById(region, name) -} - -func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { - return region.GetIBucketById(name) -} - -func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { - caches, err := self.GetElasticCaches() - if err != nil { - return nil, err - } - - icaches := make([]cloudprovider.ICloudElasticcache, len(caches)) - for i := range caches { - caches[i].region = self - icaches[i] = &caches[i] - } - - return icaches, nil -} - -func (region *SRegion) GetCapabilities() []string { - return region.client.GetCapabilities() -} - -func (self *SRegion) GetDiskTypes() ([]SDiskType, error) { - ret, err := self.ecsClient.Disks.GetDiskTypes() - if err != nil { - return nil, errors.Wrap(err, "GetDiskTypes") - } - - dts := []SDiskType{} - _ret := jsonutils.NewArray(ret.Data...) - err = _ret.Unmarshal(&dts) - if err != nil { - return nil, errors.Wrap(err, "Unmarshal") - } - - return dts, nil -} - -func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) { - dts, err := self.GetDiskTypes() - if err != nil { - return nil, errors.Wrap(err, "GetDiskTypes") - } - - ret := []string{} - for i := range dts { - if dts[i].IsAvaliableInZone(zoneId) { - ret = append(ret, dts[i].Name) - } - } - - return ret, nil -} diff --git a/pkg/multicloud/huawei/roles.go b/pkg/multicloud/huawei/roles.go deleted file mode 100644 index 64d2c791f8..0000000000 --- a/pkg/multicloud/huawei/roles.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SRole struct { - DomainId string - Flag string - DescriptionCn string - Catelog string - Description string - Id string - DisplayName string - Type string - UpdatedTime string - CreatedTime string - Links SLink - Policy jsonutils.JSONDict -} - -func (role *SRole) GetName() string { - return role.DisplayName -} - -func (role *SRole) GetDescription() string { - return role.DescriptionCn -} - -func (role *SRole) GetPolicyType() string { - return "System" -} - -func (role *SRole) GetGlobalId() string { - return role.Id -} - -func (role *SRole) UpdateDocument(document *jsonutils.JSONDict) error { - return cloudprovider.ErrNotImplemented -} - -func (role *SRole) GetDocument() (*jsonutils.JSONDict, error) { - return &role.Policy, nil -} - -func (role *SRole) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (self *SHuaweiClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - roles, err := self.GetRoles("", "") - if err != nil { - return nil, errors.Wrap(err, "GetRoles") - } - ret := []cloudprovider.ICloudpolicy{} - for i := range roles { - ret = append(ret, &roles[i]) - } - return ret, nil -} - -func (self *SHuaweiClient) GetRoles(domainId, name string) ([]SRole, error) { - params := map[string]string{} - if len(domainId) > 0 { - params["domain_id"] = self.ownerId - } - if len(name) > 0 { - params["name"] = name - } - - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - - roles := []SRole{} - err = doListAllWithNextLink(client.Roles.List, params, &roles) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithOffset") - } - return roles, nil -} diff --git a/pkg/multicloud/huawei/routetables.go b/pkg/multicloud/huawei/routetables.go deleted file mode 100644 index 8c922996c7..0000000000 --- a/pkg/multicloud/huawei/routetables.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var hoptypes = map[string]string{ - api.NEXT_HOP_TYPE_VPCPEERING: "peering", - api.NEXT_HOP_TYPE_INSTANCE: "ecs", - api.NEXT_HOP_TYPE_NAT: "nat", - api.NEXT_HOP_TYPE_HAVIP: "vip", - api.NEXT_HOP_TYPE_NETWORK: "eni", - api.NEXT_HOP_TYPE_INTERVPCNETWORK: "cc", -} - -type SRoute struct { - multicloud.SResourceBase - multicloud.HuaweiTags - - Type string `json:"type"` - Destination string `json:"destination"` - Nexthop string `json:"nexthop"` - Description string `json:"description,omitempty"` -} - -func (self *SRoute) GetCidr() string { - return self.Destination -} - -func (self *SRoute) GetGlobalId() string { - return self.GetId() -} - -func (self *SRoute) GetId() string { - return fmt.Sprintf("%s:%s:%s", self.Type, self.Nexthop, self.Destination) -} - -func (self *SRoute) GetName() string { - return "" -} - -func (route *SRoute) GetStatus() string { - return api.ROUTE_ENTRY_STATUS_AVAILIABLE -} - -func (route *SRoute) GetType() string { - if route.Type != "local" { - return api.ROUTE_ENTRY_TYPE_CUSTOM - } - return api.ROUTE_ENTRY_TYPE_SYSTEM -} - -func (self *SRoute) GetNextHopType() string { - for k, v := range hoptypes { - if v == self.Type { - return k - } - } - return self.Type -} - -type Subnet struct { - Id string `json:"id"` -} - -type SRouteTable struct { - multicloud.SResourceBase - multicloud.HuaweiTags - vpc *SVpc - - Id string `json:"id"` - Name string `json:"name"` - Routes []SRoute `json:"routes"` - Subnets []Subnet `json:"subnets"` - VpcId string `json:"vpc_id"` - Default bool `json:"default"` - TenantId string `json:"tenant_id"` -} - -func (self *SRouteTable) GetDescription() string { - return "" -} - -func (self *SRouteTable) GetGlobalId() string { - return self.Id -} - -func (self *SRouteTable) GetId() string { - return self.Id -} - -func (self *SRouteTable) GetName() string { - return self.Name -} - -func (self *SRouteTable) GetRegionId() string { - return self.vpc.region.GetId() -} - -func (self *SRouteTable) GetVpcId() string { - return self.VpcId -} - -func (self *SRouteTable) GetType() cloudprovider.RouteTableType { - return cloudprovider.RouteTableTypeSystem -} - -func (self *SRouteTable) GetStatus() string { - return api.ROUTE_TABLE_AVAILABLE -} - -func (self *SRouteTable) Refresh() error { - rtb, err := self.vpc.region.GetRouteTable(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, rtb) -} - -func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { - if len(self.Routes) == 0 { - err := self.Refresh() - if err != nil { - return nil, err - } - } - ret := []cloudprovider.ICloudRoute{} - for i := range self.Routes { - ret = append(ret, &self.Routes[i]) - } - return ret, nil -} - -func (self *SRoute) GetNextHop() string { - return self.Nexthop -} - -func (self *SRegion) GetRouteTables(vpcId string) ([]SRouteTable, error) { - params := map[string]string{} - if len(vpcId) > 0 { - params["vpc_id"] = vpcId - } - rtbs := make([]SRouteTable, 0) - err := doListAllWithMarker(self.ecsClient.RouteTables.List, params, &rtbs) - return rtbs, err -} - -func (self *SRegion) GetRouteTable(id string) (*SRouteTable, error) { - resp, err := self.ecsClient.RouteTables.Get(id, nil) - if err != nil { - return nil, err - } - tb := &SRouteTable{} - return tb, resp.Unmarshal(tb) -} - -func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { - routeType, ok := hoptypes[route.NextHopType] - if !ok { - return errors.Wrapf(cloudprovider.ErrNotSupported, route.NextHopType) - } - params := map[string]interface{}{ - "routes": map[string]interface{}{ - "add": []map[string]interface{}{ - { - "type": routeType, - "destination": route.Destination, - "nexthop": route.NextHop, - }, - }, - }, - } - _, err := self.vpc.region.ecsClient.VpcRoutes.Update(self.Id, jsonutils.Marshal(params)) - return err -} - -func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { - routeType, ok := hoptypes[route.NextHopType] - if !ok { - return errors.Wrapf(cloudprovider.ErrNotSupported, route.NextHopType) - } - params := map[string]interface{}{ - "routes": map[string]interface{}{ - "mod": []map[string]interface{}{ - { - "type": routeType, - "destination": route.Destination, - "nexthop": route.NextHop, - }, - }, - }, - } - _, err := self.vpc.region.ecsClient.VpcRoutes.Update(self.Id, jsonutils.Marshal(params)) - return err -} - -func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { - err := self.RemoveRoute(route) - if err != nil { - return errors.Wrap(err, "self.RemoveRoute(route)") - } - err = self.CreateRoute(route) - if err != nil { - return errors.Wrap(err, "self.CreateRoute(route)") - } - return nil -} - -func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { - return []cloudprovider.RouteTableAssociation{} -} diff --git a/pkg/multicloud/huawei/saml_provider.go b/pkg/multicloud/huawei/saml_provider.go deleted file mode 100644 index 69211fa1e4..0000000000 --- a/pkg/multicloud/huawei/saml_provider.go +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "time" - "unicode" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/stringutils" - - api "yunion.io/x/onecloud/pkg/apis/cloudid" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules" - "yunion.io/x/onecloud/pkg/util/samlutils" -) - -type SAMLProviderLinks struct { - Self string - Protocols string -} - -type SAMLProvider struct { - multicloud.SResourceBase - multicloud.HuaweiTags - client *SHuaweiClient - - Id string - Links SAMLProviderLinks - Description string -} - -func (self *SAMLProvider) GetId() string { - return self.Id -} - -func (self *SAMLProvider) GetGlobalId() string { - return self.Id -} - -func (self *SAMLProvider) GetName() string { - return self.Id -} - -func (self *SAMLProvider) GetStatus() string { - mapping, _ := self.client.findMapping() - if mapping != nil { - return api.SAML_PROVIDER_STATUS_AVAILABLE - } - return api.SAML_PROVIDER_STATUS_UNVALIABLE -} - -func (self *SAMLProvider) GetAuthUrl() string { - return fmt.Sprintf("https://auth.huaweicloud.com/authui/federation/websso?domain_id=%s&idp=%s&protocol=saml", self.client.ownerId, self.Id) -} - -func (self *SAMLProvider) Delete() error { - return self.client.DeleteSAMLProvider(self.Id) -} - -func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { - info, err := self.client.GetSAMLProviderMetadata(self.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetSAMLProviderMetadata(%s)", self.Id) - } - metadata, err := samlutils.ParseMetadata([]byte(info.Data)) - if err != nil { - return nil, errors.Wrapf(err, "ParseMetadata") - } - return &metadata, nil -} - -func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { - return self.client.UpdateSAMLProviderMetadata(self.Id, metadata.String()) -} - -func (self *SHuaweiClient) ListSAMLProviders() ([]SAMLProvider, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrapf(err, "newGeneralAPIClient") - } - samls := []SAMLProvider{} - err = doListAllWithNextLink(client.SAMLProviders.List, nil, &samls) - if err != nil { - return nil, errors.Wrapf(err, "doListAll") - } - return samls, nil -} - -type SAMLProviderProtocol struct { - MappingId string - Id string -} - -func (self *SHuaweiClient) GetSAMLProviderProtocols(id string) ([]SAMLProviderProtocol, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - resp, err := client.SAMLProviders.ListInContextWithSpec(nil, fmt.Sprintf("%s/protocols", id), nil, "protocols") - if err != nil { - return nil, errors.Wrapf(err, "ListInContextWithSpec") - } - protocols := []SAMLProviderProtocol{} - return protocols, jsonutils.Update(&protocols, resp.Data) -} - -func (self *SHuaweiClient) DeleteSAMLProviderProtocol(spId, id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.SAMLProviders.DeleteInContextWithSpec(nil, spId, fmt.Sprintf("protocols/%s", id), nil, nil, "") - return err -} - -type SAMLProviderMetadata struct { - DomainId string - UpdateTime time.Time - Data string - IdpId string - ProtocolId string - Id string - EntityId string - XaccountType string -} - -func (self *SHuaweiClient) GetSAMLProviderMetadata(id string) (*SAMLProviderMetadata, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION") - resp, err := client.SAMLProviders.GetInContextWithSpec(nil, id, fmt.Sprintf("protocols/saml/metadata"), nil, "") - if err != nil { - return nil, err - } - - metadata := &SAMLProviderMetadata{} - err = resp.Unmarshal(metadata) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return metadata, nil -} - -func (self *SHuaweiClient) UpdateSAMLProviderMetadata(id, metadata string) error { - params := map[string]string{ - "domain_id": self.ownerId, - "xaccount_type": "", - "metadata": metadata, - } - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION") - _, err = client.SAMLProviders.PerformAction2("protocols/saml/metadata", id, jsonutils.Marshal(params), "") - if err != nil { - return errors.Wrapf(err, "SAMLProvider.PerformAction") - } - return nil -} - -func (self *SHuaweiClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { - samls, err := self.ListSAMLProviders() - if err != nil { - return nil, errors.Wrapf(err, "ListSAMLProviders") - } - ret := []cloudprovider.ICloudSAMLProvider{} - for i := range samls { - samls[i].client = self - ret = append(ret, &samls[i]) - } - return ret, nil -} - -func (self *SHuaweiClient) DeleteSAMLProvider(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - _, err = client.SAMLProviders.Delete(id, nil) - return err -} - -func (self *SHuaweiClient) CreateSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (*SAMLProvider, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - params := jsonutils.Marshal(map[string]interface{}{ - "identity_provider": map[string]interface{}{ - "description": opts.Name, - "enabled": true, - }, - }) - name := []byte{} - for _, c := range opts.Name { - if unicode.IsLetter(c) || unicode.IsNumber(c) || c == '-' || c == '_' { - name = append(name, byte(c)) - } else { - name = append(name, '-') - } - } - samlName := string(name) - err = func() error { - idx := 1 - for { - _, err = client.SAMLProviders.Update(samlName, params) - if err == nil { - return nil - } - he, ok := err.(*modules.HuaweiClientError) - if !ok { - return errors.Wrapf(err, "SAMLProviders.Update") - } - if he.Code != 409 { - return errors.Wrapf(err, "SAMLProviders.Update") - } - samlName = fmt.Sprintf("%s-%d", string(name), idx) - idx++ - if idx >= 40 { - break - } - } - return err - }() - if err != nil { - return nil, errors.Wrapf(err, "saml provider create") - } - ret := SAMLProvider{client: self, Id: samlName} - err = self.UpdateSAMLProviderMetadata(samlName, opts.Metadata.String()) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - err = self.InitSAMLProviderMapping(samlName) - if err != nil { - return nil, errors.Wrapf(err, "InitSAMLProviderMapping") - } - return &ret, nil -} - -type SAMLProviderMapping struct { - Id string - Rules jsonutils.JSONObject -} - -var ( - onecloudMappingRules = jsonutils.Marshal(map[string]interface{}{ - "rules": []map[string]interface{}{ - { - "remote": []map[string]interface{}{ - { - "type": "User", - }, - { - "type": "Groups", - }, - }, - "local": []map[string]interface{}{ - { - "groups": "{1}", - "user": map[string]string{"name": "{0}"}, - }, - }, - }, - }, - }) -) - -func (self *SHuaweiClient) ListSAMLProviderMappings() ([]SAMLProviderMapping, error) { - client, err := self.newGeneralAPIClient() - if err != nil { - return nil, errors.Wrap(err, "newGeneralAPIClient") - } - mappings := []SAMLProviderMapping{} - err = doListAllWithNextLink(client.SAMLProviderMappings.List, nil, &mappings) - if err != nil { - return nil, err - } - return mappings, nil -} - -func (self *SHuaweiClient) findMapping() (*SAMLProviderMapping, error) { - mappings, err := self.ListSAMLProviderMappings() - if err != nil { - return nil, errors.Wrapf(err, "ListSAMLProviderMappings") - } - for i := range mappings { - if jsonutils.Marshal(map[string]interface{}{"rules": mappings[i].Rules}).Equals(jsonutils.Marshal(onecloudMappingRules)) { - return &mappings[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHuaweiClient) InitSAMLProviderMapping(spId string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - - mapping, err := self.findMapping() - if err != nil { - if errors.Cause(err) != cloudprovider.ErrNotFound { - return errors.Wrapf(err, "findMapping") - } - mappingId := stringutils.UUID4() - params := map[string]interface{}{ - "mapping": onecloudMappingRules, - } - _, err = client.SAMLProviderMappings.Update(mappingId, jsonutils.Marshal(params)) - if err != nil { - return errors.Wrapf(err, "create mapping") - } - mapping = &SAMLProviderMapping{ - Id: mappingId, - Rules: onecloudMappingRules, - } - } - protocols, err := self.GetSAMLProviderProtocols(spId) - if err != nil { - return errors.Wrapf(err, "GetSAMLProviderProtocols") - } - params := map[string]interface{}{ - "protocol": map[string]string{ - "mapping_id": mapping.Id, - }, - } - for i := range protocols { - if protocols[i].Id == "saml" { - if protocols[i].MappingId == mapping.Id { - return nil - } - _, err = client.SAMLProviders.PatchInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "") - return err - } - } - _, err = client.SAMLProviders.UpdateInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "") - return err -} - -func (self *SHuaweiClient) DeleteSAMLProviderMapping(id string) error { - client, err := self.newGeneralAPIClient() - if err != nil { - return errors.Wrap(err, "newGeneralAPIClient") - } - - _, err = client.SAMLProviderMappings.Delete(id, nil) - return err -} diff --git a/pkg/multicloud/huawei/securitygroup.go b/pkg/multicloud/huawei/securitygroup.go deleted file mode 100644 index de2a3c6c9a..0000000000 --- a/pkg/multicloud/huawei/securitygroup.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -/* -https://support.huaweicloud.com/usermanual-vpc/zh-cn_topic_0073379079.html -安全组的限制 -默认情况下,一个用户可以创建100个安全组。 -默认情况下,一个安全组最多只允许拥有50条安全组规则。 -默认情况下,一个弹性云服务器或辅助网卡最多只能被添加到5个安全组中。 -在创建私网弹性负载均衡时,需要选择弹性负载均衡所在的安全组。请勿删除默认规则或者确保满足以下规则: -出方向:允许发往同一个安全组的报文可以通过,或者允许对端负载均衡器报文通过。 -入方向:允许来自同一个安全组的报文可以通过,或者允许对端负载均衡器报文通过。 -*/ - -import ( - "net" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SecurityGroupRule struct { - Direction string `json:"direction"` - Ethertype string `json:"ethertype"` - ID string `json:"id"` - Description string `json:"description"` - SecurityGroupID string `json:"security_group_id"` - RemoteGroupID string `json:"remote_group_id"` -} - -type SecurityGroupRuleDetail struct { - Direction string `json:"direction"` - Ethertype string `json:"ethertype"` - ID string `json:"id"` - Description string `json:"description"` - PortRangeMax int64 `json:"port_range_max"` - PortRangeMin int64 `json:"port_range_min"` - Protocol string `json:"protocol"` - RemoteGroupID string `json:"remote_group_id"` - RemoteIPPrefix string `json:"remote_ip_prefix"` - SecurityGroupID string `json:"security_group_id"` - TenantID string `json:"tenant_id"` -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.HuaweiTags - region *SRegion - - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - VpcID string `json:"vpc_id"` - EnterpriseProjectID string `json:"enterprise_project_id "` - SecurityGroupRules []SecurityGroupRule `json:"security_group_rules"` -} - -// 判断是否兼容云端安全组规则 -func compatibleSecurityGroupRule(r SecurityGroupRule) bool { - // 忽略了源地址是安全组的规则 - if len(r.RemoteGroupID) > 0 { - return false - } - - // 忽略IPV6 - if r.Ethertype == "IPv6" { - return false - } - - return true -} - -func (self *SSecurityGroup) GetId() string { - return self.ID -} - -func (self *SSecurityGroup) GetVpcId() string { - return api.NORMAL_VPC_ID -} - -func (self *SSecurityGroup) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.ID -} - -func (self *SSecurityGroup) GetGlobalId() string { - return self.ID -} - -func (self *SSecurityGroup) GetStatus() string { - return "" -} - -func (self *SSecurityGroup) Refresh() error { - if new, err := self.region.GetSecurityGroupDetails(self.GetId()); err != nil { - return err - } else { - return jsonutils.Update(self, new) - } -} - -func (self *SSecurityGroup) IsEmulated() bool { - return false -} - -func (self *SSecurityGroup) GetDescription() string { - if self.Description == self.VpcID { - return "" - } - return self.Description -} - -// todo: 这里需要优化查询太多了 -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - rules := make([]cloudprovider.SecurityRule, 0) - for _, r := range self.SecurityGroupRules { - if !compatibleSecurityGroupRule(r) { - continue - } - - rule, err := self.GetSecurityRule(r.ID) - if err != nil { - return rules, err - } - - rules = append(rules, rule) - } - - return rules, nil -} - -func (self *SSecurityGroup) GetSecurityRule(ruleId string) (cloudprovider.SecurityRule, error) { - remoteRule := SecurityGroupRuleDetail{} - err := DoGet(self.region.ecsClient.SecurityGroupRules.Get, ruleId, nil, &remoteRule) - if err != nil { - return cloudprovider.SecurityRule{}, err - } - - var direction secrules.TSecurityRuleDirection - if remoteRule.Direction == "ingress" { - direction = secrules.SecurityRuleIngress - } else { - direction = secrules.SecurityRuleEgress - } - - protocol := secrules.PROTO_ANY - if remoteRule.Protocol != "" { - protocol = remoteRule.Protocol - } - - var portStart int - var portEnd int - if protocol == secrules.PROTO_ICMP { - portStart = -1 - portEnd = -1 - } else { - portStart = int(remoteRule.PortRangeMin) - portEnd = int(remoteRule.PortRangeMax) - } - - ipNet := &net.IPNet{} - if len(remoteRule.RemoteIPPrefix) > 0 { - _, ipNet, err = net.ParseCIDR(remoteRule.RemoteIPPrefix) - } else { - _, ipNet, err = net.ParseCIDR("0.0.0.0/0") - } - - if err != nil { - return cloudprovider.SecurityRule{}, err - } - - rule := cloudprovider.SecurityRule{ - ExternalId: ruleId, - SecurityRule: secrules.SecurityRule{ - Priority: 1, - Action: secrules.SecurityRuleAllow, - IPNet: ipNet, - Protocol: protocol, - Direction: direction, - PortStart: portStart, - PortEnd: portEnd, - Ports: nil, - Description: remoteRule.Description, - }, - } - - err = rule.ValidateRule() - return rule, err -} - -func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) { - securitygroup := SSecurityGroup{} - err := DoGet(self.ecsClient.SecurityGroups.Get, secGroupId, nil, &securitygroup) - if err != nil { - return nil, err - } - - securitygroup.region = self - return &securitygroup, err -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090617.html -func (self *SRegion) GetSecurityGroups(vpcId string, name string) ([]SSecurityGroup, error) { - querys := map[string]string{} - if len(vpcId) > 0 && !utils.IsInStringArray(vpcId, []string{"default", api.NORMAL_VPC_ID}) { // vpc_id = default or normal 时报错 '{"code":"VPC.0601","message":"Query security groups error vpcId is invalid."}' - querys["vpc_id"] = vpcId - } - - securitygroups := make([]SSecurityGroup, 0) - err := doListAllWithMarker(self.ecsClient.SecurityGroups.List, querys, &securitygroups) - if err != nil { - return nil, err - } - - // security 中的vpc字段只是一个标识,实际可以跨vpc使用 - for i := range securitygroups { - securitygroup := &securitygroups[i] - securitygroup.region = self - } - - result := []SSecurityGroup{} - for _, secgroup := range securitygroups { - if len(name) == 0 || secgroup.Name == name { - result = append(result, secgroup) - } - } - - return result, nil -} - -func (self *SSecurityGroup) GetProjectId() string { - return "" -} - -func (self *SSecurityGroup) Delete() error { - return self.region.DeleteSecurityGroup(self.ID) -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - for _, r := range append(inDels, outDels...) { - err := self.region.delSecurityGroupRule(r.ExternalId) - if err != nil { - return errors.Wrapf(err, "delSecurityGroupRule(%s %s)", r.ExternalId, r.String()) - } - } - for _, r := range append(inAdds, outAdds...) { - err := self.region.addSecurityGroupRules(self.ID, r) - if err != nil { - return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String()) - } - } - return nil -} diff --git a/pkg/multicloud/huawei/sfs-turbo.go b/pkg/multicloud/huawei/sfs-turbo.go deleted file mode 100644 index 8257ebbb96..0000000000 --- a/pkg/multicloud/huawei/sfs-turbo.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SfsTurbo struct { - multicloud.SNasBase - multicloud.HuaweiTags - region *SRegion - - EnterpriseProjectId string - Actions []string - AvailCapacity float64 - AvailabilityZone string - AzName string - CreatedAt time.Time - CryptKeyId string - ExpandType string - ExportLocation string - Id string - Name string - PayModel string - Region string - SecurityGroupId string - ShareProto string - ShareType string - Size float64 - Status string - SubStatus string - SubnetId string - VpcId string - Description string -} - -func (self *SfsTurbo) GetName() string { - return self.Name -} - -func (self *SfsTurbo) GetId() string { - return self.Id -} - -func (self *SfsTurbo) GetGlobalId() string { - return self.Id -} - -func (self *SfsTurbo) GetFileSystemType() string { - return "SFS Turbo" -} - -func (self *SfsTurbo) Refresh() error { - sf, err := self.region.GetSfsTurbo(self.Id) - if err != nil { - return errors.Wrapf(err, "GetSfsTurbo") - } - return jsonutils.Update(self, sf) -} - -func (self *SfsTurbo) GetBillingType() string { - if self.PayModel == "0" { - return billing_api.BILLING_TYPE_POSTPAID - } - return billing_api.BILLING_TYPE_PREPAID -} - -func (self *SfsTurbo) GetStorageType() string { - if len(self.ExpandType) == 0 { - return strings.ToLower(self.ShareType) - } - return strings.ToLower(self.ShareType) + ".enhanced" -} - -func (self *SfsTurbo) GetProtocol() string { - return self.ShareProto -} - -func (self *SfsTurbo) GetStatus() string { - switch self.Status { - case "100": - return api.NAS_STATUS_CREATING - case "200": - return api.NAS_STATUS_AVAILABLE - case "300": - return api.NAS_STATUS_UNKNOWN - case "303": - return api.NAS_STATUS_CREATE_FAILED - case "400": - return api.NAS_STATUS_DELETING - case "800": - return api.NAS_STATUS_UNAVAILABLE - default: - return self.Status - } -} - -func (self *SfsTurbo) GetCreatedAt() time.Time { - return self.CreatedAt -} - -func (self *SfsTurbo) GetCapacityGb() int64 { - return int64(self.Size) -} - -func (self *SfsTurbo) GetUsedCapacityGb() int64 { - return int64(self.Size - self.AvailCapacity) -} - -func (self *SfsTurbo) GetMountTargetCountLimit() int { - return 1 -} - -func (self *SfsTurbo) GetZoneId() string { - return self.AvailabilityZone -} - -func (self *SfsTurbo) GetMountTargets() ([]cloudprovider.ICloudMountTarget, error) { - mt := &sMoutTarget{sfs: self} - return []cloudprovider.ICloudMountTarget{mt}, nil -} - -func (self *SfsTurbo) CreateMountTarget(opts *cloudprovider.SMountTargetCreateOptions) (cloudprovider.ICloudMountTarget, error) { - return nil, errors.Wrap(cloudprovider.ErrNotSupported, "CreateMountTarget") -} - -func (self *SfsTurbo) Delete() error { - return self.region.DeleteSfsTurbo(self.Id) -} - -func (self *SRegion) GetICloudFileSystems() ([]cloudprovider.ICloudFileSystem, error) { - sfs, err := self.GetSfsTurbos() - if err != nil { - return nil, errors.Wrapf(err, "self.GetSfsTurbos") - } - ret := []cloudprovider.ICloudFileSystem{} - for i := range sfs { - sfs[i].region = self - ret = append(ret, &sfs[i]) - } - return ret, nil -} - -func (self *SRegion) GetICloudFileSystemById(id string) (cloudprovider.ICloudFileSystem, error) { - sf, err := self.GetSfsTurbo(id) - if err != nil { - return nil, errors.Wrapf(err, "GetSfsTurbo(%s)", id) - } - return sf, nil -} - -func (self *SRegion) GetSfsTurbos() ([]SfsTurbo, error) { - queues := make(map[string]string) - sfs := make([]SfsTurbo, 0, 2) - err := doListAllWithOffset(self.ecsClient.SfsTurbos.List, queues, &sfs) - if err != nil { - return nil, errors.Wrapf(err, "doListAllWithOffset") - } - return sfs, nil -} - -func (self *SRegion) GetSfsTurbo(id string) (*SfsTurbo, error) { - sf := &SfsTurbo{region: self} - err := DoGet(self.ecsClient.SfsTurbos.Get, id, nil, &sf) - return sf, errors.Wrapf(err, "self.ecsClient.SfsTurbos.Get") -} - -func (self *SRegion) DeleteSfsTurbo(id string) error { - return DoDelete(self.ecsClient.SfsTurbos.Delete, id, nil, nil) -} - -func (self *SRegion) GetSysDefaultSecgroupId() (string, error) { - secs, err := self.GetSecurityGroups("default", "") - if err != nil { - return "", errors.Wrapf(err, "GetSecurityGroups") - } - if len(secs) > 0 { - return secs[0].ID, nil - } - return "", fmt.Errorf("not found default security group") -} - -func (self *SRegion) CreateICloudFileSystem(opts *cloudprovider.FileSystemCraeteOptions) (cloudprovider.ICloudFileSystem, error) { - fs, err := self.CreateSfsTurbo(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateSfsTurbo") - } - return fs, nil -} - -func (self *SRegion) CreateSfsTurbo(opts *cloudprovider.FileSystemCraeteOptions) (*SfsTurbo, error) { - secId, err := self.GetSysDefaultSecgroupId() - if err != nil { - return nil, errors.Wrapf(err, "GetSysDefaultSecgroupId") - } - metadata := map[string]string{} - if strings.HasSuffix(opts.StorageType, ".enhanced") { - metadata["expand_type"] = "bandwidth" - } - params := map[string]interface{}{ - "share": map[string]interface{}{ - "name": opts.Name, - "share_proto": strings.ToUpper(opts.Protocol), - "share_type": strings.ToUpper(strings.TrimSuffix(opts.StorageType, ".enhanced")), - "size": opts.Capacity, - "availability_zone": opts.ZoneId, - "vpc_id": opts.VpcId, - "subnet_id": opts.NetworkId, - "security_group_id": secId, - "description": opts.Desc, - "metadata": metadata, - }, - } - resp, err := self.ecsClient.SfsTurbos.Create(jsonutils.Marshal(params)) - if err != nil { - return nil, errors.Wrapf(err, "Create") - } - id, err := resp.GetString("id") - if err != nil { - return nil, errors.Wrapf(err, "resp.GetString(id)") - } - return self.GetSfsTurbo(id) -} - -func (self *SRegion) GetICloudAccessGroups() ([]cloudprovider.ICloudAccessGroup, error) { - return []cloudprovider.ICloudAccessGroup{}, nil -} - -func (self *SRegion) CreateICloudAccessGroup(opts *cloudprovider.SAccessGroup) (cloudprovider.ICloudAccessGroup, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "CreateICloudAccessGroup") -} - -func (self *SRegion) GetICloudAccessGroupById(id string) (cloudprovider.ICloudAccessGroup, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetICloudAccessGroupById(%s)", id) -} - -type sMoutTarget struct { - sfs *SfsTurbo -} - -func (self *sMoutTarget) GetName() string { - return self.sfs.Name -} - -func (self *sMoutTarget) GetGlobalId() string { - return self.sfs.GetGlobalId() -} - -func (self *sMoutTarget) GetAccessGroupId() string { - return "" -} - -func (self *sMoutTarget) GetDomainName() string { - return self.sfs.ExportLocation -} - -func (self *sMoutTarget) GetNetworkType() string { - return api.NETWORK_TYPE_VPC -} - -func (self *sMoutTarget) GetNetworkId() string { - return self.sfs.SubnetId -} - -func (self *sMoutTarget) GetVpcId() string { - return self.sfs.VpcId -} - -func (self *sMoutTarget) GetStatus() string { - return api.MOUNT_TARGET_STATUS_AVAILABLE -} - -func (self *sMoutTarget) Delete() error { - return nil -} diff --git a/pkg/multicloud/huawei/shell/bucket.go b/pkg/multicloud/huawei/shell/bucket.go deleted file mode 100644 index 3f7238d110..0000000000 --- a/pkg/multicloud/huawei/shell/bucket.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - objectstore.S3Shell() - - type BucketNameOptions struct { - NAME string - } - shellutils.R(&BucketNameOptions{}, "bucket-head", "Head bucket", func(cli *huawei.SRegion, args *BucketNameOptions) error { - result, err := cli.HeadBucket(args.NAME) - if err != nil { - return err - } - printObject(result) - return nil - }) - - shellutils.R(&BucketNameOptions{}, "bucket-project", "Show bucket project", func(cli *huawei.SRegion, args *BucketNameOptions) error { - bucket, err := cli.GetIBucketByName(args.NAME) - if err != nil { - return err - } - fmt.Println("project: ", bucket.GetProjectId()) - return nil - }) - -} diff --git a/pkg/multicloud/huawei/shell/business.go b/pkg/multicloud/huawei/shell/business.go deleted file mode 100644 index 3e4f36d4d8..0000000000 --- a/pkg/multicloud/huawei/shell/business.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type AccountBalanceOptions struct { - } - shellutils.R(&AccountBalanceOptions{}, "balance", "Get account balance", func(cli *huawei.SRegion, args *AccountBalanceOptions) error { - result, err := cli.GetClient().QueryAccountBalance() - if err != nil { - return err - } - printObject(result) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/cloudgroup.go b/pkg/multicloud/huawei/shell/cloudgroup.go deleted file mode 100644 index ebc3a43588..0000000000 --- a/pkg/multicloud/huawei/shell/cloudgroup.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CloudgroupListOptions struct { - DomainId string - Name string - } - shellutils.R(&CloudgroupListOptions{}, "cloud-group-list", "List cloudgroups", func(cli *huawei.SRegion, args *CloudgroupListOptions) error { - groups, err := cli.GetClient().GetGroups(args.DomainId, args.Name) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - type CloudgroupIdOptions struct { - ID string - } - - shellutils.R(&CloudgroupIdOptions{}, "cloud-group-delete", "Delete cloudgroup", func(cli *huawei.SRegion, args *CloudgroupIdOptions) error { - return cli.GetClient().DeleteGroup(args.ID) - }) - - type CloudgroupCreateOptions struct { - NAME string - Desc string - } - - shellutils.R(&CloudgroupCreateOptions{}, "cloud-group-create", "Create cloudgroup", func(cli *huawei.SRegion, args *CloudgroupCreateOptions) error { - group, err := cli.GetClient().CreateGroup(args.NAME, args.Desc) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type GroupRoleListOptions struct { - GROUP_ID string - } - - shellutils.R(&GroupRoleListOptions{}, "cloud-group-policy-list", "List role", func(cli *huawei.SRegion, args *GroupRoleListOptions) error { - roles, err := cli.GetClient().GetGroupRoles(args.GROUP_ID) - if err != nil { - return err - } - printList(roles, 0, 0, 0, nil) - return nil - }) - - type GroupRoleOptions struct { - GROUP_ID string - ROLE_ID string - } - - shellutils.R(&GroupRoleOptions{}, "cloud-group-detach-policy", "Detach group role", func(cli *huawei.SRegion, args *GroupRoleOptions) error { - return cli.GetClient().DetachGroupRole(args.GROUP_ID, args.ROLE_ID) - }) - - shellutils.R(&GroupRoleOptions{}, "cloud-group-attach-policy", "Detach group role", func(cli *huawei.SRegion, args *GroupRoleOptions) error { - return cli.GetClient().AttachGroupRole(args.GROUP_ID, args.ROLE_ID) - }) - - type GroupUserListOptions struct { - GROUP_ID string - } - - shellutils.R(&GroupUserListOptions{}, "cloud-group-user-list", "List user", func(cli *huawei.SRegion, args *GroupUserListOptions) error { - users, err := cli.GetClient().GetGroupUsers(args.GROUP_ID) - if err != nil { - return err - } - printList(users, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/huawei/shell/clouduser.go b/pkg/multicloud/huawei/shell/clouduser.go deleted file mode 100644 index b6cc65a6b7..0000000000 --- a/pkg/multicloud/huawei/shell/clouduser.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClouduserListOptions struct { - Name string - } - shellutils.R(&ClouduserListOptions{}, "cloud-user-list", "List cloudusers", func(cli *huawei.SRegion, args *ClouduserListOptions) error { - users, err := cli.GetClient().GetCloudusers(args.Name) - if err != nil { - return err - } - printList(users, 0, 0, 0, nil) - return nil - }) - - type ClouduserIdOptions struct { - ID string - } - - shellutils.R(&ClouduserIdOptions{}, "cloud-user-delete", "Delete clouduser", func(cli *huawei.SRegion, args *ClouduserIdOptions) error { - return cli.GetClient().DeleteClouduser(args.ID) - }) - - shellutils.R(&ClouduserIdOptions{}, "cloud-user-group-list", "List clouduser groups", func(cli *huawei.SRegion, args *ClouduserIdOptions) error { - groups, err := cli.GetClient().ListUserGroups(args.ID) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - type ClouduserCreateOptions struct { - NAME string - Password string - Desc string - } - - shellutils.R(&ClouduserCreateOptions{}, "cloud-user-create", "Create clouduser", func(cli *huawei.SRegion, args *ClouduserCreateOptions) error { - user, err := cli.GetClient().CreateClouduser(args.NAME, args.Password, args.Desc) - if err != nil { - return err - } - printObject(user) - return nil - }) - - type RoleListOptions struct { - DomainId string - Name string - } - - shellutils.R(&RoleListOptions{}, "cloud-policy-list", "List role", func(cli *huawei.SRegion, args *RoleListOptions) error { - roles, err := cli.GetClient().GetRoles(args.DomainId, args.Name) - if err != nil { - return err - } - printList(roles, 0, 0, 0, nil) - return nil - }) - - type ClouduserResetPassword struct { - ID string - PASSWORD string - } - - shellutils.R(&ClouduserResetPassword{}, "cloud-user-reset-password", "Reset clouduser password", func(cli *huawei.SRegion, args *ClouduserResetPassword) error { - return cli.GetClient().ResetClouduserPassword(args.ID, args.PASSWORD) - }) - - type ClouduserAKSKOptions struct { - Id string - } - shellutils.R(&ClouduserAKSKOptions{}, "aksk-list", "List AKSK", func(cli *huawei.SRegion, args *ClouduserAKSKOptions) error { - res, err := cli.GetClient().GetAKSK(args.Id) - if err != nil { - return err - } - printList(res, len(res), 0, 0, []string{}) - return nil - }) - type ClouduserAKSKDeleteOptions struct { - AccessKey string - } - shellutils.R(&ClouduserAKSKDeleteOptions{}, "aksk-delete", "Delete AKSK", func(cli *huawei.SRegion, args *ClouduserAKSKDeleteOptions) error { - err := cli.GetClient().DeleteAKSK(args.AccessKey) - return err - }) - - type AKSKCreateOption struct { - UserId string `help:"user id"` - Description string `help:"description"` - } - - shellutils.R(&AKSKCreateOption{}, "aksk-create", "Create aksk", func(cli *huawei.SRegion, args *AKSKCreateOption) error { - res, err := cli.GetClient().CreateAKSK(args.UserId, args.Description) - if err != nil { - return err - } - printObject(res) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/dbinstance.go b/pkg/multicloud/huawei/shell/dbinstance.go deleted file mode 100644 index 82a3656daf..0000000000 --- a/pkg/multicloud/huawei/shell/dbinstance.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceListOptions struct { - } - shellutils.R(&DBInstanceListOptions{}, "dbinstance-list", "List dbinstances", func(cli *huawei.SRegion, args *DBInstanceListOptions) error { - dbinstances, err := cli.GetDBInstances() - if err != nil { - return err - } - printList(dbinstances, 0, 0, 0, nil) - return nil - }) - - type DBInstanceIdOptions struct { - ID string `help:"DBInstance ID"` - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-open-public-connection", "Open dbinstance public connection", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - return cli.PublicConnectionAction(args.ID, "openRC") - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-close-public-connection", "Close dbinstance public connection", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - return cli.PublicConnectionAction(args.ID, "closeRC") - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-show", "Show dbinstance", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - dbinstance, err := cli.GetDBInstance(args.ID) - if err != nil { - return err - } - printObject(dbinstance) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-parameter-list", "Show dbinstance parameters", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - parameters, err := cli.GetDBInstanceParameters(args.ID) - if err != nil { - return err - } - printList(parameters, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-backup-list", "Show dbinstance backups", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - backups, err := cli.GetDBInstanceBackups(args.ID, "") - if err != nil { - return err - } - printList(backups, 0, 0, 0, nil) - return nil - }) - - type DBInstanceFlavorListOption struct { - ENGINE string `help:"DBInstance engine" choices:"MySQL|SQLServer|PostgreSQL"` - VERSION string `help:"DBInstance engine version" choices:"5.6|5.7|9.5|9.6|10.0|2014 SE|2014 EE|2016 SE|2016 EE|2008 R2 EE|2008 R2 WEB|2014 WEB|2016 WEB"` - } - - shellutils.R(&DBInstanceFlavorListOption{}, "dbinstance-flavor-list", "Show dbinstance backups", func(cli *huawei.SRegion, args *DBInstanceFlavorListOption) error { - flavors, err := cli.GetDBInstanceFlavors(args.ENGINE, args.VERSION) - if err != nil { - return err - } - printList(flavors, 0, 0, 0, nil) - return nil - }) - - type DBInstanceChangeConfigOptions struct { - INSTANCE string - InstanceType string - DiskSizeGB int - } - - shellutils.R(&DBInstanceChangeConfigOptions{}, "dbinstance-change-config", "Change dbinstance config", func(cli *huawei.SRegion, args *DBInstanceChangeConfigOptions) error { - return cli.ChangeDBInstanceConfig(args.INSTANCE, args.InstanceType, args.DiskSizeGB) - }) - -} diff --git a/pkg/multicloud/huawei/shell/dbinstance_account.go b/pkg/multicloud/huawei/shell/dbinstance_account.go deleted file mode 100644 index 283b8baef7..0000000000 --- a/pkg/multicloud/huawei/shell/dbinstance_account.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceIdOptions struct { - ID string `help:"DBInstance ID"` - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-account-list", "Show dbinstance accounts", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - accounts, err := cli.GetDBInstanceAccounts(args.ID) - if err != nil { - return err - } - printList(accounts, 0, 0, 0, nil) - return nil - }) - - type DBInstanceAccountDeleteOptions struct { - INSTANCE string - ACCOUNT string - } - - shellutils.R(&DBInstanceAccountDeleteOptions{}, "dbinstance-account-delete", "Delete dbinstance account", func(cli *huawei.SRegion, args *DBInstanceAccountDeleteOptions) error { - return cli.DeleteDBInstanceAccount(args.INSTANCE, args.ACCOUNT) - }) - - type DBInstanceAccountCreateOptions struct { - INSTANCE string - ACCOUNT string - PASSWORD string - } - - shellutils.R(&DBInstanceAccountCreateOptions{}, "dbinstance-account-create", "Create dbinstance account", func(cli *huawei.SRegion, args *DBInstanceAccountCreateOptions) error { - return cli.CreateDBInstanceAccount(args.INSTANCE, args.ACCOUNT, args.PASSWORD) - }) - - type DBInstanceAccountRevokePrivilegeOptions struct { - INSTANCE string - ACCOUNT string - DATABASE string - } - - shellutils.R(&DBInstanceAccountRevokePrivilegeOptions{}, "dbinstance-account-revoke-provilege", "Revoke dbinstance account privilege", func(cli *huawei.SRegion, args *DBInstanceAccountRevokePrivilegeOptions) error { - return cli.RevokeDBInstancePrivilege(args.INSTANCE, args.ACCOUNT, args.DATABASE) - }) - - type DBInstanceAccountGrantPrivilegeOptions struct { - INSTANCE string - ACCOUNT string - DATABASE string - PRIVILEGE string `help:"database privilege" choices:"r|rw"` - } - - shellutils.R(&DBInstanceAccountGrantPrivilegeOptions{}, "dbinstance-account-grant-provilege", "Grant dbinstance account privilege", func(cli *huawei.SRegion, args *DBInstanceAccountGrantPrivilegeOptions) error { - return cli.GrantDBInstancePrivilege(args.INSTANCE, args.ACCOUNT, args.DATABASE, args.PRIVILEGE) - }) - -} diff --git a/pkg/multicloud/huawei/shell/dbinstance_database.go b/pkg/multicloud/huawei/shell/dbinstance_database.go deleted file mode 100644 index 51b8a7230b..0000000000 --- a/pkg/multicloud/huawei/shell/dbinstance_database.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceIdOptions struct { - INSTANCE string `help:"DBInstance ID"` - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-database-list", "Show dbinstance databases", func(cli *huawei.SRegion, args *DBInstanceIdOptions) error { - databases, err := cli.GetDBInstanceDatabases(args.INSTANCE) - if err != nil { - return err - } - printList(databases, 0, 0, 0, nil) - return nil - }) - - type DBInstanceDatabaseDeleteOptions struct { - INSTANCE string - DATABASE string - } - - shellutils.R(&DBInstanceDatabaseDeleteOptions{}, "dbinstance-database-delete", "Delete dbinstance database", func(cli *huawei.SRegion, args *DBInstanceDatabaseDeleteOptions) error { - return cli.DeleteDBInstanceDatabase(args.INSTANCE, args.DATABASE) - }) - - type DBInstanceDatabaseCreateOptions struct { - INSTANCE string - DATABASE string - CHARACTER_SET string - } - - shellutils.R(&DBInstanceDatabaseCreateOptions{}, "dbinstance-database-create", "Create dbinstance database", func(cli *huawei.SRegion, args *DBInstanceDatabaseCreateOptions) error { - return cli.CreateDBInstanceDatabase(args.INSTANCE, args.DATABASE, args.CHARACTER_SET) - }) - -} diff --git a/pkg/multicloud/huawei/shell/disk.go b/pkg/multicloud/huawei/shell/disk.go deleted file mode 100644 index f6ead5656d..0000000000 --- a/pkg/multicloud/huawei/shell/disk.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - Zone string `help:"Zone ID"` - } - shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *huawei.SRegion, args *DiskListOptions) error { - disks, e := cli.GetDisks(args.Zone) - if e != nil { - return e - } - printList(disks, 0, 0, 0, nil) - return nil - }) - - type DiskDeleteOptions struct { - ID string `help:"Disk ID"` - } - shellutils.R(&DiskDeleteOptions{}, "disk-delete", "List disks", func(cli *huawei.SRegion, args *DiskDeleteOptions) error { - e := cli.DeleteDisk(args.ID) - if e != nil { - return e - } - return nil - }) - - shellutils.R(&DiskListOptions{}, "disk-types", "List disk types", func(cli *huawei.SRegion, args *DiskListOptions) error { - ret, e := cli.GetDiskTypes() - if e != nil { - return e - } - printList(ret, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/doc.go b/pkg/multicloud/huawei/shell/doc.go deleted file mode 100644 index 2ef405b734..0000000000 --- a/pkg/multicloud/huawei/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/huawei/shell" diff --git a/pkg/multicloud/huawei/shell/eip.go b/pkg/multicloud/huawei/shell/eip.go deleted file mode 100644 index b9fb7bdabb..0000000000 --- a/pkg/multicloud/huawei/shell/eip.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - PortId string - Addrs []string - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *huawei.SRegion, args *EipListOptions) error { - eips, e := cli.GetEips(args.PortId, args.Addrs) - if e != nil { - return e - } - printList(eips, 0, 0, 0, nil) - return nil - }) - - type EipAllocateOptions struct { - NAME string `help:"eip name"` - BW int `help:"Bandwidth limit in Mbps"` - BGP string `help:"bgp type" choices:"5_telcom|5_union|5_bgp|5_sbgp"` - ChargeType string `help:"eip charge type" default:"traffic" choices:"traffic|bandwidth"` - ProjectId string - } - shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *huawei.SRegion, args *EipAllocateOptions) error { - eip, err := cli.AllocateEIP(args.NAME, args.BW, huawei.TInternetChargeType(args.ChargeType), args.BGP, args.ProjectId) - 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 *huawei.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 *huawei.SRegion, args *EipAssociateOptions) error { - return cli.AssociateEip(args.ID, args.INSTANCE) - }) - - type EipDissociateOptions struct { - ID string `help:"EIP allocation ID"` - } - - shellutils.R(&EipDissociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *huawei.SRegion, args *EipDissociateOptions) error { - return cli.DissociateEip(args.ID) - }) -} diff --git a/pkg/multicloud/huawei/shell/elasticcache.go b/pkg/multicloud/huawei/shell/elasticcache.go deleted file mode 100644 index 32805b8f57..0000000000 --- a/pkg/multicloud/huawei/shell/elasticcache.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElasticcacheListOptions struct { - } - shellutils.R(&ElasticcacheListOptions{}, "dcs-list", "List elasticcaches", func(cli *huawei.SRegion, args *ElasticcacheListOptions) error { - instances, e := cli.GetElasticCaches() - if e != nil { - return e - } - printList(instances, len(instances), 0, 0, []string{}) - return nil - }) - - type ElasticcacheIdOptions struct { - ID string `help:"ID of instances to show"` - } - shellutils.R(&ElasticcacheIdOptions{}, "dcs-show", "Show elasticcache", func(cli *huawei.SRegion, args *ElasticcacheIdOptions) error { - instance, err := cli.GetElasticCache(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - type ElasticcacheBackupsListOptions struct { - ID string `help:"ID of instances to show"` - StartTime string `help:"backup start time. format: 20060102150405"` - EndTime string `help:"backup end time. format: 20060102150405 "` - } - - shellutils.R(&ElasticcacheBackupsListOptions{}, "dcs-backup-list", "List elasticcache backups", func(cli *huawei.SRegion, args *ElasticcacheBackupsListOptions) error { - backups, err := cli.GetElasticCacheBackups(args.ID, args.StartTime, args.EndTime) - if err != nil { - return err - } - printList(backups, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&ElasticcacheIdOptions{}, "dcs-parameter-list", "List elasticcache parameters", func(cli *huawei.SRegion, args *ElasticcacheIdOptions) error { - parameters, err := cli.GetElasticCacheParameters(args.ID) - if err != nil { - return err - } - printList(parameters, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/enterpriseprojects.go b/pkg/multicloud/huawei/shell/enterpriseprojects.go deleted file mode 100644 index ea6ffeb458..0000000000 --- a/pkg/multicloud/huawei/shell/enterpriseprojects.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EnterpriseProjectListOptions struct { - } - shellutils.R(&EnterpriseProjectListOptions{}, "enterprise-project-list", "List enterprise projects", func(cli *huawei.SRegion, args *EnterpriseProjectListOptions) error { - projects, err := cli.GetClient().GetEnterpriseProjects() - if err != nil { - return err - } - printList(projects, 0, 0, 0, nil) - return nil - }) - - type EnterpriseProjectCreateOptions struct { - NAME string - Desc string - } - - shellutils.R(&EnterpriseProjectCreateOptions{}, "enterprise-project-create", "Create enterprise project", func(cli *huawei.SRegion, args *EnterpriseProjectCreateOptions) error { - project, err := cli.GetClient().CreateExterpriseProject(args.NAME, args.Desc) - if err != nil { - return err - } - printObject(project) - return nil - }) - -} diff --git a/pkg/multicloud/huawei/shell/events.go b/pkg/multicloud/huawei/shell/events.go deleted file mode 100644 index 87b0004ad6..0000000000 --- a/pkg/multicloud/huawei/shell/events.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "time" - - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EventListOptions struct { - Start time.Time - End time.Time - } - shellutils.R(&EventListOptions{}, "event-list", "List events", func(cli *huawei.SRegion, args *EventListOptions) error { - events, err := cli.GetEvents(args.Start, args.End) - if err != nil { - return err - } - printList(events, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/filesystem.go b/pkg/multicloud/huawei/shell/filesystem.go deleted file mode 100644 index fb97501ef2..0000000000 --- a/pkg/multicloud/huawei/shell/filesystem.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type FileSystemListOptions struct { - } - shellutils.R(&FileSystemListOptions{}, "file-system-list", "List FileSystem", func(cli *huawei.SRegion, args *FileSystemListOptions) error { - sfs, err := cli.GetSfsTurbos() - if err != nil { - return err - } - printList(sfs, 0, 0, 0, []string{}) - return nil - }) - - type FileSystemIdOptions struct { - ID string `help:"File System ID"` - } - shellutils.R(&FileSystemIdOptions{}, "file-system-delete", "Delete filesystem", func(cli *huawei.SRegion, args *FileSystemIdOptions) error { - return cli.DeleteSfsTurbo(args.ID) - }) - - shellutils.R(&FileSystemIdOptions{}, "file-system-show", "Show filesystem", func(cli *huawei.SRegion, args *FileSystemIdOptions) error { - fs, err := cli.GetSfsTurbo(args.ID) - if err != nil { - return err - } - printObject(fs) - return nil - }) - - shellutils.R(&cloudprovider.FileSystemCraeteOptions{}, "file-system-create", "Create filesystem", func(cli *huawei.SRegion, args *cloudprovider.FileSystemCraeteOptions) error { - fs, err := cli.CreateSfsTurbo(args) - if err != nil { - return err - } - printObject(fs) - return nil - }) - -} diff --git a/pkg/multicloud/huawei/shell/iam.go b/pkg/multicloud/huawei/shell/iam.go deleted file mode 100644 index e98e1ba72a..0000000000 --- a/pkg/multicloud/huawei/shell/iam.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type OwnerShowOptions struct { - } - shellutils.R(&OwnerShowOptions{}, "owner-show", "Get aksk owner id", func(cli *huawei.SRegion, args *OwnerShowOptions) error { - result, err := cli.GetClient().GetOwnerId() - if err != nil { - return err - } - fmt.Println(result) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/image.go b/pkg/multicloud/huawei/shell/image.go deleted file mode 100644 index aa9d64ae70..0000000000 --- a/pkg/multicloud/huawei/shell/image.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - Status string `help:"image status type" choices:"queued|saving|deleted|killed|active"` - Owner string `help:"Owner type" choices:"gold|private|shared"` - // Id []string `help:"Image ID"` - Name string `help:"image name"` - // Marker string `help:"marker"` - // Limit int `help:"page Limit"` - Env string `help:"virtualization env, e.g. FusionCompute, Ironic" choices:"FusionCompute|Ironic"` - } - shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *huawei.SRegion, args *ImageListOptions) error { - images, e := cli.GetImages(args.Status, huawei.TImageOwnerType(args.Owner), args.Name, args.Env) - if e != nil { - return e - } - printList(images, 0, 0, 0, []string{}) - return nil - }) - - type ImageDeleteOptions struct { - ID string `help:"ID or Name to delete"` - } - shellutils.R(&ImageDeleteOptions{}, "image-delete", "Delete image", func(cli *huawei.SRegion, args *ImageDeleteOptions) error { - return cli.DeleteImage(args.ID) - }) - - shellutils.R(&ImageDeleteOptions{}, "image-show", "Show image", func(cli *huawei.SRegion, args *ImageDeleteOptions) error { - img, err := cli.GetImage(args.ID) - if err != nil { - return err - } - printObject(img) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/instance.go b/pkg/multicloud/huawei/shell/instance.go deleted file mode 100644 index d46f364462..0000000000 --- a/pkg/multicloud/huawei/shell/instance.go +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "context" - "fmt" - "strings" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List intances", func(cli *huawei.SRegion, args *InstanceListOptions) error { - instances, e := cli.GetInstances() - if e != nil { - return e - } - printList(instances, 0, 0, 0, nil) - 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 *huawei.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 *huawei.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 *huawei.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 *huawei.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 *huawei.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 *huawei.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"` - UserId string `help:"instance user ID"` - Image string `help:"Image ID"` - Password string `help:"admin password"` - PublicKeyName string `help:"public key name"` - UserData string `help:"cloud-init user data"` - } - - shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *huawei.SRegion, args *InstanceRebuildRootOptions) error { - ctx := context.Background() - jobId, err := cli.ChangeRoot(ctx, args.UserId, args.ID, args.Image, args.Password, args.PublicKeyName, args.UserData) - if err != nil { - return err - } - fmt.Printf("ChangeRoot jobID is %s", jobId) - return nil - }) - - type InstanceChangeConfigOptions struct { - ID string `help:"instance ID"` - InstanceType string `help:"instance type"` - } - - shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Deploy keypair/password to a stopped virtual server", func(cli *huawei.SRegion, args *InstanceChangeConfigOptions) error { - err := cli.ChangeVMConfig(args.ID, args.InstanceType) - if err != nil { - return err - } - return nil - }) - - type InstanceOrderUnsubscribeOptions struct { - ID string `help:"instance ID"` - DOMAIN string `help:"domain ID"` - } - - shellutils.R(&InstanceOrderUnsubscribeOptions{}, "instance-order-unsubscribe", "Unsubscribe a prepaid server", func(cli *huawei.SRegion, args *InstanceOrderUnsubscribeOptions) error { - instance, e := cli.GetInstanceByID(args.ID) - if e != nil { - return e - } - - _, err := cli.UnsubscribeInstance(instance.GetId(), args.DOMAIN) - if err != nil { - return err - } - return nil - }) - - type InstanceSaveImageOptions struct { - ID string `help:"Instance ID"` - IMAGE_NAME string `help:"Image name"` - Notes string `hlep:"Image desc"` - } - shellutils.R(&InstanceSaveImageOptions{}, "instance-save-image", "Save instance to image", func(cli *huawei.SRegion, args *InstanceSaveImageOptions) error { - opts := cloudprovider.SaveImageOptions{ - Name: args.IMAGE_NAME, - Notes: args.Notes, - } - image, err := cli.SaveImage(args.ID, &opts) - if err != nil { - return err - } - printObject(image) - return nil - }) - - type InstanceSetTagsOptions struct { - ID string `help:"Instance ID"` - Tags []string - } - shellutils.R(&InstanceSetTagsOptions{}, "instance-set-tags", "get intance metadata", func(cli *huawei.SRegion, args *InstanceSetTagsOptions) error { - tags := map[string]string{} - for i := range args.Tags { - splited := strings.Split(args.Tags[i], "=") - if len(splited) == 2 { - tags[splited[0]] = splited[1] - } - } - err := cli.CreateServerTags(args.ID, tags) - if err != nil { - return err - } - return nil - }) - - type InstanceDelTagsOptions struct { - ID string `help:"Instance ID"` - Tags []string - } - shellutils.R(&InstanceDelTagsOptions{}, "instance-del-tags", "del intance metadata", func(cli *huawei.SRegion, args *InstanceDelTagsOptions) error { - - err := cli.DeleteServerTags(args.ID, args.Tags) - if err != nil { - return err - } - return nil - }) - - type InstanceUpdateNameOptions struct { - ID string `help:"Instance ID"` - Name string - } - shellutils.R(&InstanceUpdateNameOptions{}, "instance-set-name", "set intance name", func(cli *huawei.SRegion, args *InstanceUpdateNameOptions) error { - - err := cli.UpdateVM(args.ID, args.Name) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/instancetype.go b/pkg/multicloud/huawei/shell/instancetype.go deleted file mode 100644 index de8985aae1..0000000000 --- a/pkg/multicloud/huawei/shell/instancetype.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceMatchOptions struct { - CPU int `help:"CPU count"` - MEM int `help:"Memory in MB"` - Zone string `help:"Test in zone"` - } - shellutils.R(&InstanceMatchOptions{}, "instance-type-select", "Select matching instance types", func(cli *huawei.SRegion, args *InstanceMatchOptions) error { - instanceTypes, e := cli.GetMatchInstanceTypes(args.CPU, args.MEM, args.Zone) - if e != nil { - return e - } - printList(instanceTypes, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/keypair.go b/pkg/multicloud/huawei/shell/keypair.go deleted file mode 100644 index dc5fec1a69..0000000000 --- a/pkg/multicloud/huawei/shell/keypair.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - // todo: 需要进一步确认 - type KeyPairListOptions struct { - } - shellutils.R(&KeyPairListOptions{}, "keypair-list", "List keypairs", func(cli *huawei.SRegion, args *KeyPairListOptions) error { - keypairs, total, e := cli.GetKeypairs() - if e != nil { - return e - } - printList(keypairs, total, 0, 0, []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 *huawei.SRegion, args *KeyPairImportOptions) error { - keypair, err := cli.ImportKeypair(args.NAME, args.PUBKEY) - if err != nil { - return err - } - printObject(keypair) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/loadbalancer.go b/pkg/multicloud/huawei/shell/loadbalancer.go deleted file mode 100644 index 6a4a4d4ecc..0000000000 --- a/pkg/multicloud/huawei/shell/loadbalancer.go +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElbListOptions struct { - } - shellutils.R(&ElbListOptions{}, "elb-list", "List loadbalancers", func(cli *huawei.SRegion, args *ElbListOptions) error { - elbs, err := cli.GetILoadBalancers() - if err != nil { - return err - } - printList(elbs, len(elbs), 0, 0, []string{}) - return nil - }) - - type ElbCreateOptions struct { - Name string `help:"loadblancer name"` - SUBNET string `help:"subnet id"` - PrivateIP string `help:"loadbalancer private ip address"` - EipID string `help:"loadbalancer public ip id"` - } - shellutils.R(&ElbCreateOptions{}, "elb-create", "create loadbalancer", func(cli *huawei.SRegion, args *ElbCreateOptions) error { - loadbalancer := &cloudprovider.SLoadbalancer{ - Name: args.Name, - NetworkIDs: []string{args.SUBNET}, - EipID: args.EipID, - Address: args.PrivateIP, - } - - elb, err := cli.CreateLoadBalancer(loadbalancer) - if err != nil { - return err - } - - printObject(elb) - return nil - }) - - type ElbIdOptions struct { - ID string `help:"loadblancer id"` - } - shellutils.R(&ElbIdOptions{}, "elb-delete", "delete loadbalancer", func(cli *huawei.SRegion, args *ElbIdOptions) error { - err := cli.DeleteLoadBalancer(args.ID) - if err != nil { - return err - } - - return nil - }) - - shellutils.R(&ElbIdOptions{}, "elb-show", "show loadbalancer", func(cli *huawei.SRegion, args *ElbIdOptions) error { - lb, err := cli.GetLoadbalancer(args.ID) - if err != nil { - return err - } - printObject(lb) - return nil - }) - - type ElbListenerListOptions struct { - ElbID string `help:"loadblancer id"` - } - shellutils.R(&ElbListenerListOptions{}, "elb-listener-list", "list loadbalancer listener", func(cli *huawei.SRegion, args *ElbListenerListOptions) error { - listeners, err := cli.GetLoadBalancerListeners(args.ElbID) - if err != nil { - return err - } - - printList(listeners, len(listeners), 0, 0, []string{}) - return nil - }) - - type ElbListenerCreateOptions struct { - Name string `help:"listener name"` - Desc string `help:"listener Description"` - Http2 bool `help:"http2 enable status"` - PoolID string `help:"default backend group id"` - CertId string `help:"default certification id"` - XForwardedFor bool `help:"XForwardedFor enable status"` - LISTENER_TYPE string `help:"listener type" choices:"tcp|udp|http|https"` - LISTENER_PORT int `help:"listener port"` - ELB_ID string `help:"loadbalancer id"` - } - shellutils.R(&ElbListenerCreateOptions{}, "elb-listener-create", "create loadbalancer listener", func(cli *huawei.SRegion, args *ElbListenerCreateOptions) error { - input := &cloudprovider.SLoadbalancerListener{ - Name: args.Name, - LoadbalancerID: args.ELB_ID, - ListenerType: args.LISTENER_TYPE, - ListenerPort: args.LISTENER_PORT, - BackendGroupID: args.PoolID, - EnableHTTP2: args.Http2, - CertificateID: args.CertId, - Description: args.Desc, - XForwardedFor: args.XForwardedFor, - } - listener, err := cli.CreateLoadBalancerListener(input) - if err != nil { - return err - } - - printObject(listener) - return nil - }) - - type ElbListenerUpdateOptions struct { - Name string `help:"listener name"` - Desc string `help:"listener Description"` - Http2 bool `help:"http2 enable status"` - PoolID string `help:"default backend group id"` - CertId string `help:"default certification id"` - XForwardedFor bool `help:"XForwardedFor enable status"` - LISTENER_ID string `help:"listener id"` - } - shellutils.R(&ElbListenerUpdateOptions{}, "elb-listener-update", "update loadbalancer listener", func(cli *huawei.SRegion, args *ElbListenerUpdateOptions) error { - input := &cloudprovider.SLoadbalancerListener{ - Name: args.Name, - BackendGroupID: args.PoolID, - EnableHTTP2: args.Http2, - CertificateID: args.CertId, - Description: args.Desc, - XForwardedFor: args.XForwardedFor, - } - - err := cli.UpdateLoadBalancerListener(args.LISTENER_ID, input) - if err != nil { - return err - } - - return nil - }) - - type ElbBackendGroupListOptions struct { - ElbID string `help:"loadbalancer id"` - } - shellutils.R(&ElbBackendGroupListOptions{}, "elb-backend-group-list", "List backend groups", func(cli *huawei.SRegion, args *ElbBackendGroupListOptions) error { - elbbg, err := cli.GetLoadBalancerBackendGroups(args.ElbID) - if err != nil { - return err - } - - printList(elbbg, len(elbbg), 0, 0, []string{}) - return nil - }) - - type ElbBackendGroupCreateOptions struct { - Name string `help:"backend group name"` - Desc string `help:"backend group description"` - PROTOCOL string `help:"backend group protocol" choices:"tcp|udp|http"` - ALGORITHM string `help:"backend group algorithm" choices:"rr|wlc|sch"` - ListenerID string `help:"listener id to binding"` - ElbID string `help:"loadbalancer id belong to"` - StickySessionType string `help:"sticky session type" choices:"insert|server"` - StickySessionCookieName string `help:"sticky session cookie name"` - StickySessionTimeout int `help:"sticky session timeout. udp/tcp 1~60. http 1~1440"` - HealthCheck bool `help:"enable health check"` - HealthCheckType string `help:"health check type protocol" choices:"tcp|udp|http"` - HealthCheckTimeout int `help:"health check timeout"` - HealthCheckDomain string `help:"health check domain"` - HealthCheckURI string `help:"health check uri path"` - HealthCheckInterval int `help:"health check interval"` - HealthCheckRise int `help:"health check max retries"` - } - shellutils.R(&ElbBackendGroupCreateOptions{}, "elb-backend-group-create", "Create backend groups", func(cli *huawei.SRegion, args *ElbBackendGroupCreateOptions) error { - var health *cloudprovider.SLoadbalancerHealthCheck - if args.HealthCheck { - health = &cloudprovider.SLoadbalancerHealthCheck{ - HealthCheckType: args.HealthCheckType, - HealthCheckTimeout: args.HealthCheckTimeout, - HealthCheckDomain: args.HealthCheckDomain, - HealthCheckURI: args.HealthCheckURI, - HealthCheckInterval: args.HealthCheckInterval, - HealthCheckRise: args.HealthCheckRise, - } - } - - var sticky *cloudprovider.SLoadbalancerStickySession - if len(args.StickySessionType) > 0 { - sticky = &cloudprovider.SLoadbalancerStickySession{ - StickySessionCookie: args.StickySessionCookieName, - StickySessionType: args.StickySessionType, - StickySessionCookieTimeout: args.StickySessionTimeout, - } - } - - group := &cloudprovider.SLoadbalancerBackendGroup{ - Name: args.Name, - LoadbalancerID: args.ElbID, - ListenerID: args.ListenerID, - ListenType: args.PROTOCOL, - Scheduler: args.ALGORITHM, - StickySession: sticky, - HealthCheck: health, - } - - elbbg, err := cli.CreateLoadBalancerBackendGroup(group) - if err != nil { - return err - } - - printObject(elbbg) - return nil - }) - - type ElbBackendGroupUpdateOptions struct { - POOL_ID string `help:"backend group id"` - Name string `help:"backend group name"` - } - shellutils.R(&ElbBackendGroupUpdateOptions{}, "elb-backend-group-update", "Update backend groups", func(cli *huawei.SRegion, args *ElbBackendGroupUpdateOptions) error { - group := &cloudprovider.SLoadbalancerBackendGroup{ - Name: args.Name, - } - - elbbg, err := cli.UpdateLoadBalancerBackendGroup(args.POOL_ID, group) - if err != nil { - return err - } - - printObject(elbbg) - return nil - }) - - type ElbBackendGroupDeleteOptions struct { - POOL_ID string `help:"backend group id"` - } - shellutils.R(&ElbBackendGroupDeleteOptions{}, "elb-backend-group-delete", "Delete backend group", func(cli *huawei.SRegion, args *ElbBackendGroupDeleteOptions) error { - err := cli.DeleteLoadBalancerBackendGroup(args.POOL_ID) - if err != nil { - return err - } - - return nil - }) - - type ElbBackendAddOptions struct { - Name string `help:"backend name"` - POOL_ID string `help:"backend group id"` - SUBNET_ID string `help:"instance subnet id"` - ADDRESS string `help:"instance ip address"` - PORT int `help:"backend protocol port [1,65535]"` - Weight int `help:"backend weight [0,100]" default:"1"` - } - shellutils.R(&ElbBackendAddOptions{}, "elb-backend-add", "Add backend to backendgroup", func(cli *huawei.SRegion, args *ElbBackendAddOptions) error { - elbb, err := cli.AddLoadBalancerBackend(args.POOL_ID, args.SUBNET_ID, args.ADDRESS, args.PORT, args.Weight) - if err != nil { - return err - } - - printObject(elbb) - return nil - }) - - type ElbBackendListOptions struct { - POOL_ID string `help:"backend group id"` - } - shellutils.R(&ElbBackendListOptions{}, "elb-backend-list", "list backend", func(cli *huawei.SRegion, args *ElbBackendListOptions) error { - elbb, err := cli.GetLoadBalancerBackends(args.POOL_ID) - if err != nil { - return err - } - - printList(elbb, len(elbb), 0, 0, []string{}) - return nil - }) - - type ElbListenerPolicyListOptions struct { - ListenerID string `help:"listener id"` - } - shellutils.R(&ElbListenerPolicyListOptions{}, "elb-listener-policy-list", "List listener policies", func(cli *huawei.SRegion, args *ElbListenerPolicyListOptions) error { - elblp, err := cli.GetLoadBalancerPolicies(args.ListenerID) - if err != nil { - return err - } - - printList(elblp, len(elblp), 0, 0, []string{}) - return nil - }) - - type ElbListenerPolicyCreateOptions struct { - LISTENER_ID string `help:"listener id"` - Name string `help:"policy name"` - Domain string `help:"policy domain"` - Path string `help:"policy path"` - PoolID string `help:"backend group name"` - } - shellutils.R(&ElbListenerPolicyCreateOptions{}, "elb-listener-policy-create", "Create listener policy", func(cli *huawei.SRegion, args *ElbListenerPolicyCreateOptions) error { - rule := &cloudprovider.SLoadbalancerListenerRule{ - Name: args.Name, - Domain: args.Domain, - Path: args.Path, - BackendGroupID: args.PoolID, - } - - elblp, err := cli.CreateLoadBalancerPolicy(args.LISTENER_ID, rule) - if err != nil { - return err - } - - printObject(elblp) - return nil - }) - - type ElbListenerPolicyDeleteOptions struct { - POLICY_ID string `help:"policy id"` - } - shellutils.R(&ElbListenerPolicyDeleteOptions{}, "elb-listener-policy-delete", "Delete listener policy", func(cli *huawei.SRegion, args *ElbListenerPolicyDeleteOptions) error { - err := cli.DeleteLoadBalancerPolicy(args.POLICY_ID) - if err != nil { - return err - } - - return nil - }) - - type ElbListenerPolicyRuleListOptions struct { - POLICY_ID string `help:"policy id"` - } - shellutils.R(&ElbListenerPolicyRuleListOptions{}, "elb-listener-policyrule-list", "List listener policy rules", func(cli *huawei.SRegion, args *ElbListenerPolicyRuleListOptions) error { - elblpr, err := cli.GetLoadBalancerPolicyRules(args.POLICY_ID) - if err != nil { - return err - } - - printList(elblpr, len(elblpr), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/modelarts_pool.go b/pkg/multicloud/huawei/shell/modelarts_pool.go deleted file mode 100644 index 8dcbad583c..0000000000 --- a/pkg/multicloud/huawei/shell/modelarts_pool.go +++ /dev/null @@ -1,78 +0,0 @@ -// @@ -0,0 +1,46 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ModelartsPoolListOption struct { - PoolId string `help:"Pool Id"` - } - - shellutils.R(&ModelartsPoolListOption{}, "modelarts-pool-list", "List Modelarts Pool", func(cli *huawei.SRegion, args *ModelartsPoolListOption) error { - pools, err := cli.GetIModelartsPools() - if err != nil { - return err - } - printList(pools, len(pools), 0, 0, nil) - return nil - }) - - shellutils.R(&ModelartsPoolListOption{}, "modelarts-pool-detail", "List pool", func(cli *huawei.SRegion, args *ModelartsPoolListOption) error { - pools, err := cli.GetIModelartsPoolById(args.PoolId) - if err != nil { - return err - } - log.Infoln(pools) - return nil - }) - - shellutils.R(&cloudprovider.ModelartsPoolCreateOption{}, "modelarts-pool-create", "Create Modelarts Pool", func(cli *huawei.SRegion, args *cloudprovider.ModelartsPoolCreateOption) error { - res, err := cli.CreateIModelartsPool(args) - if err != nil { - return err - } - // printList(pools, len(pools), 0, 0, nil) - log.Infoln("this is res:", res) - return nil - }) - - shellutils.R(&ModelartsPoolListOption{}, "modelarts-pool-delete", "Delete Modelarts Pool", func(cli *huawei.SRegion, args *ModelartsPoolListOption) error { - res, err := cli.DeletePool(args.PoolId) - if err != nil { - return err - } - // printList(pools, len(pools), 0, 0, nil) - log.Infoln("this is res:", res) - return nil - }) - - shellutils.R(&ModelartsPoolListOption{}, "modelarts-pool-monitor", "Delete Modelarts Pool", func(cli *huawei.SRegion, args *ModelartsPoolListOption) error { - res, err := cli.MonitorPool(args.PoolId) - if err != nil { - return err - } - // log.Println("this is res:", res) - printList(res.Metrics, len(res.Metrics), 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/modelarts_pool_sku.go b/pkg/multicloud/huawei/shell/modelarts_pool_sku.go deleted file mode 100644 index fdf6c62a32..0000000000 --- a/pkg/multicloud/huawei/shell/modelarts_pool_sku.go +++ /dev/null @@ -1,35 +0,0 @@ -// @@ -0,0 +1,46 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ModelartsResourceflavorsListOption struct { - PoolName string `help:"Pool Name"` - } - shellutils.R(&ModelartsResourceflavorsListOption{}, "modelarts-sku-list", "List Modelarts Pool", func(cli *huawei.SRegion, args *ModelartsResourceflavorsListOption) error { - resourceflavors, err := cli.GetIModelartsPoolSku() - if err != nil { - return err - } - printList(resourceflavors, len(resourceflavors), 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/monitor.go b/pkg/multicloud/huawei/shell/monitor.go deleted file mode 100644 index ef8578823d..0000000000 --- a/pkg/multicloud/huawei/shell/monitor.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - "yunion.io/x/pkg/util/timeutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics", func(cli *huawei.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric: %s %s %s", metrics[i].Id, metrics[i].MetricType, metrics[i].Unit) - printList(metrics[i].Values, len(metrics[i].Values), 0, 0, []string{}) - } - return nil - }) - - type MetricDataOptions struct { - START int `help:"Start metrics"` - Count int `help:"Metric count" default:"1"` - SINCE string `help:"since"` - UNTIL string `help:"until"` - } - shellutils.R(&MetricDataOptions{}, "metrics-data-list", "List metrics", func(cli *huawei.SRegion, args *MetricDataOptions) error { - metrics, err := cli.GetMetrics() - if err != nil { - return err - } - since, err := timeutils.ParseTimeStr(args.SINCE) - if err != nil { - return err - } - until, err := timeutils.ParseTimeStr(args.UNTIL) - if err != nil { - return err - } - data, err := cli.GetMetricsData(metrics[args.START:args.START+args.Count], since, until) - if err != nil { - return err - } - printList(data, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/natdtable.go b/pkg/multicloud/huawei/shell/natdtable.go deleted file mode 100644 index 27922658f3..0000000000 --- a/pkg/multicloud/huawei/shell/natdtable.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SNatDTableOptions struct { - NatGatewayID string `help:"Nat Gateway ID" positional:"true"` - } - shellutils.R(&SNatDTableOptions{}, "dnat-table-list", "List dnat table", func(region *huawei.SRegion, args *SNatDTableOptions) error { - DNatTable, err := region.GetNatDTable(args.NatGatewayID) - if err != nil { - return err - } - printList(DNatTable, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/natgateway.go b/pkg/multicloud/huawei/shell/natgateway.go deleted file mode 100644 index 89b980c29f..0000000000 --- a/pkg/multicloud/huawei/shell/natgateway.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NatGatewayOptions struct { - NatGatewayID string `help:"Nat Gateway ID"` - VpcID string `help:"Vpc ID"` - } - shellutils.R(&NatGatewayOptions{}, "nat-list", "List nat gateway", func(region *huawei.SRegion, args *NatGatewayOptions) error { - natGateways, err := region.GetNatGateways(args.VpcID, args.NatGatewayID) - if err != nil { - return err - } - printList(natGateways, 0, 0, 0, nil) - return nil - }) - - type NatGatewayIdOptions struct { - ID string `help:"Nat Id"` - } - - shellutils.R(&NatGatewayIdOptions{}, "nat-delete", "Delete nat gateways", func(cli *huawei.SRegion, args *NatGatewayIdOptions) error { - return cli.DeleteNatGateway(args.ID) - }) - - shellutils.R(&NatGatewayIdOptions{}, "nat-show", "Show nat gateways", func(cli *huawei.SRegion, args *NatGatewayIdOptions) error { - nat, err := cli.GetNatGateway(args.ID) - if err != nil { - return err - } - printObject(nat) - return nil - }) - - type SCreateDNatOptions struct { - GatewayID string `help:"Nat Gateway ID" positional:"true"` - Protocol string `help:"Protocol(tcp/udp)" positional:"true"` - ExternalIPID string `help:"External IP ID" positional:"true"` - ExternalPort int `help:"External Port" positional:"true"` - InternalIP string `help:"Internal IP" positional:"true"` - InternalPort int `help:"Nat Gateway ID" positional:"true"` - } - shellutils.R(&SCreateDNatOptions{}, "dnat-create", "Create dnat", func(region *huawei.SRegion, args *SCreateDNatOptions) error { - rule := cloudprovider.SNatDRule{ - Protocol: args.Protocol, - ExternalIPID: args.ExternalIPID, - ExternalPort: args.ExternalPort, - InternalIP: args.InternalIP, - InternalPort: args.InternalPort, - } - dnat, err := region.CreateNatDEntry(rule, args.GatewayID) - if err != nil { - return err - } - printObject(dnat) - return nil - }) - - type SCreateSNatOptions struct { - GatewayID string `help:"Nat Gateway ID" positional:"true"` - SourceCIDR string `help:"Source cidr" positional:"true"` - ExternalIPID string `help:"External IP ID" positional:"true"` - } - shellutils.R(&SCreateSNatOptions{}, "snat-create", "Create snat", func(region *huawei.SRegion, args *SCreateSNatOptions) error { - rule := cloudprovider.SNatSRule{ - SourceCIDR: args.SourceCIDR, - ExternalIPID: args.ExternalIPID, - } - snat, err := region.CreateNatSEntry(rule, args.GatewayID) - if err != nil { - return err - } - printObject(snat) - return nil - }) - - type SShowSNatOptions struct { - NatID string `help:"SNat ID" positional:"true"` - } - shellutils.R(&SShowSNatOptions{}, "snat-show", "Show snat", func(region *huawei.SRegion, args *SShowSNatOptions) error { - snat, err := region.GetNatSEntryByID(args.NatID) - if err != nil { - return err - } - printObject(snat) - return nil - }) - - type SShowDNatOptions struct { - NatID string `help:"DNat ID" positional:"true"` - } - shellutils.R(&SShowDNatOptions{}, "dnat-show", "Show dnat", func(region *huawei.SRegion, args *SShowDNatOptions) error { - dnat, err := region.GetNatDEntryByID(args.NatID) - if err != nil { - return err - } - printObject(dnat) - return nil - }) - - type SDeleteSNatOptions struct { - NatID string `help:"SNat ID" positional:"true"` - } - shellutils.R(&SDeleteSNatOptions{}, "snat-delete", "Delete snat", func(region *huawei.SRegion, args *SDeleteSNatOptions) error { - err := region.DeleteNatSEntry(args.NatID) - if err != nil { - return err - } - return nil - }) - - type SDeleteDNatOptions struct { - NatID string `help:"DNat ID" positional:"true"` - } - shellutils.R(&SDeleteDNatOptions{}, "dnat-delete", "Delete dnat", func(region *huawei.SRegion, args *SDeleteDNatOptions) error { - err := region.DeleteNatDEntry(args.NatID) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/natstable.go b/pkg/multicloud/huawei/shell/natstable.go deleted file mode 100644 index de0417e8ee..0000000000 --- a/pkg/multicloud/huawei/shell/natstable.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SNatSTableOptions struct { - NatGatewayID string `help:"Nat Gateway ID" positional:"true"` - } - shellutils.R(&SNatSTableOptions{}, "snat-table-list", "List snat table", func(region *huawei.SRegion, args *SNatSTableOptions) error { - sNatTable, err := region.GetNatSTable(args.NatGatewayID) - if err != nil { - return err - } - printList(sNatTable, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/network.go b/pkg/multicloud/huawei/shell/network.go deleted file mode 100644 index 967fac5e99..0000000000 --- a/pkg/multicloud/huawei/shell/network.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VSwitchListOptions struct { - Vpc string `help:"Vpc ID"` - } - shellutils.R(&VSwitchListOptions{}, "subnet-list", "List subnets", func(cli *huawei.SRegion, args *VSwitchListOptions) error { - vswitches, e := cli.GetNetwroks(args.Vpc) - if e != nil { - return e - } - printList(vswitches, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/obs.go b/pkg/multicloud/huawei/shell/obs.go deleted file mode 100644 index 0cb3b7727d..0000000000 --- a/pkg/multicloud/huawei/shell/obs.go +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/printutils" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ObsBucketListOptions struct { - } - shellutils.R(&ObsBucketListOptions{}, "obs-list", "List all buckets", func(cli *huawei.SRegion, args *ObsBucketListOptions) error { - buckets, err := cli.GetIBuckets() - if err != nil { - return err - } - printList(buckets, 0, 0, 0, nil) - return nil - }) - shellutils.R(&ObsBucketListOptions{}, "bucket-list", "List all buckets", func(cli *huawei.SRegion, args *ObsBucketListOptions) error { - buckets, err := cli.GetIBuckets() - if err != nil { - return err - } - printutils.PrintGetterList(buckets, nil) - return nil - }) - - type ObsBucketShowOptions struct { - BUCKET string `help:"bucket name to show"` - } - shellutils.R(&ObsBucketShowOptions{}, "obs-show", "Show bucket detail", func(cli *huawei.SRegion, args *ObsBucketShowOptions) error { - bucket, err := cli.GetIBucketById(args.BUCKET) - if err != nil { - return err - } - printObject(bucket) - return nil - }) - - type ObsBucketCreateOptions struct { - BUCKET string `help:"bucket name to show"` - StorageClass string `help:"storage class"` - Acl string `help:"acl"` - } - shellutils.R(&ObsBucketCreateOptions{}, "obs-create", "Create new OBS bucket", func(cli *huawei.SRegion, args *ObsBucketCreateOptions) error { - err := cli.CreateIBucket(args.BUCKET, args.StorageClass, args.Acl) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&ObsBucketShowOptions{}, "obs-delete", "Delete OBS bucket", func(cli *huawei.SRegion, args *ObsBucketShowOptions) error { - err := cli.DeleteIBucket(args.BUCKET) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/order.go b/pkg/multicloud/huawei/shell/order.go deleted file mode 100644 index 810502ab78..0000000000 --- a/pkg/multicloud/huawei/shell/order.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type OrderListOptions struct { - OrderId string `help:"Order Id"` - ResourceIds []string `help:"ResourceIds"` - MainResource bool `help:"Main resource"` - } - shellutils.R(&OrderListOptions{}, "order-list", "List order", func(cli *huawei.SRegion, args *OrderListOptions) error { - orders, err := cli.GetOrderResources(args.OrderId, args.ResourceIds, args.MainResource) - if err != nil { - return err - } - printList(orders, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/port.go b/pkg/multicloud/huawei/shell/port.go deleted file mode 100644 index 4004a7a4f3..0000000000 --- a/pkg/multicloud/huawei/shell/port.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type PortListOptions struct { - InstanceId string - } - shellutils.R(&PortListOptions{}, "port-list", "List ports", func(cli *huawei.SRegion, args *PortListOptions) error { - ports, err := cli.GetPorts(args.InstanceId) - if err != nil { - return err - } - printList(ports, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/printutils.go b/pkg/multicloud/huawei/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/huawei/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/huawei/shell/quota.go b/pkg/multicloud/huawei/shell/quota.go deleted file mode 100644 index d1695785e0..0000000000 --- a/pkg/multicloud/huawei/shell/quota.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type QuotaListOptions struct { - } - shellutils.R(&QuotaListOptions{}, "quota-list", "List Quotas", func(cli *huawei.SRegion, args *QuotaListOptions) error { - quotas, err := cli.GetQuotas() - if err != nil { - return err - } - printList(quotas, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/huawei/shell/region.go b/pkg/multicloud/huawei/shell/region.go deleted file mode 100644 index 38e02402ee..0000000000 --- a/pkg/multicloud/huawei/shell/region.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *huawei.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&RegionListOptions{}, "project-list", "List projects", func(cli *huawei.SRegion, args *RegionListOptions) error { - projects, err := cli.GetClient().GetProjects() - if err != nil { - return err - } - printList(projects, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&RegionListOptions{}, "domain-list", "List domains", func(cli *huawei.SRegion, args *RegionListOptions) error { - domains, err := cli.GetClient().GetDomains() - if err != nil { - return err - } - printList(domains, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&RegionListOptions{}, "capabilities", "Get capabilities", func(cli *huawei.SRegion, args *RegionListOptions) error { - capabilities := cli.GetClient().GetCapabilities() - fmt.Println(capabilities) - return nil - }) - - shellutils.R(&RegionListOptions{}, "subaccount-list", "List account", func(cli *huawei.SRegion, args *RegionListOptions) error { - accounts, err := cli.GetClient().GetSubAccounts() - if err != nil { - return err - } - printList(accounts, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/huawei/shell/role.go b/pkg/multicloud/huawei/shell/role.go deleted file mode 100644 index fbcd2acf65..0000000000 --- a/pkg/multicloud/huawei/shell/role.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RoleListOptions struct { - DomainId string - Name string - } - shellutils.R(&RoleListOptions{}, "cloud-policy-list", "List cloudpolicy", func(cli *huawei.SRegion, args *RoleListOptions) error { - roles, err := cli.GetClient().GetRoles(args.DomainId, args.Name) - if err != nil { - return err - } - printList(roles, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/routetable.go b/pkg/multicloud/huawei/shell/routetable.go deleted file mode 100644 index 0f0280762b..0000000000 --- a/pkg/multicloud/huawei/shell/routetable.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RouteTableListOption struct { - VpcId string `help:"Vpc ID"` - } - shellutils.R(&RouteTableListOption{}, "routetable-list", "List vpc route tables", func(cli *huawei.SRegion, args *RouteTableListOption) error { - routetables, err := cli.GetRouteTables(args.VpcId) - if err != nil { - return err - } - printList(routetables, 0, 0, 0, nil) - return nil - }) - - type RouteTableIdOptions struct { - ID string `help:"RouteTable ID"` - } - shellutils.R(&RouteTableIdOptions{}, "routetable-show", "Show vpc route table", func(cli *huawei.SRegion, args *RouteTableIdOptions) error { - routetable, err := cli.GetRouteTable(args.ID) - if err != nil { - return err - } - printObject(routetable) - return nil - }) - -} diff --git a/pkg/multicloud/huawei/shell/saml_provider.go b/pkg/multicloud/huawei/shell/saml_provider.go deleted file mode 100644 index f8cac29493..0000000000 --- a/pkg/multicloud/huawei/shell/saml_provider.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/samlutils" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SAMLProviderListOptions struct { - } - shellutils.R(&SAMLProviderListOptions{}, "saml-provider-list", "List saml provider", func(cli *huawei.SRegion, args *SAMLProviderListOptions) error { - result, err := cli.GetClient().ListSAMLProviders() - if err != nil { - return err - } - printList(result, 0, 0, 0, nil) - return nil - }) - - type SAMLProviderCreateOptions struct { - NAME string - Metadata string - } - shellutils.R(&SAMLProviderCreateOptions{}, "saml-provider-create", "Create saml provider", func(cli *huawei.SRegion, args *SAMLProviderCreateOptions) error { - opts := cloudprovider.SAMLProviderCreateOptions{ - Name: args.NAME, - } - if len(args.Metadata) > 0 { - var err error - opts.Metadata, err = samlutils.ParseMetadata([]byte(args.Metadata)) - if err != nil { - return err - } - } - result, err := cli.GetClient().CreateSAMLProvider(&opts) - if err != nil { - return err - } - printObject(result) - return nil - }) - - type SAMLProviderIdOptions struct { - ID string - } - - shellutils.R(&SAMLProviderIdOptions{}, "saml-provider-delete", "Delete saml provider", func(cli *huawei.SRegion, args *SAMLProviderIdOptions) error { - return cli.GetClient().DeleteSAMLProvider(args.ID) - }) - - shellutils.R(&SAMLProviderIdOptions{}, "saml-provider-protocol-list", "List saml provider protocol", func(cli *huawei.SRegion, args *SAMLProviderIdOptions) error { - result, err := cli.GetClient().GetSAMLProviderProtocols(args.ID) - if err != nil { - return err - } - printList(result, 0, 0, 0, nil) - return nil - }) - - type SAMLProviderProtocolDeleteOptions struct { - SAML_PROVIDER string - PROTOCOL string - } - - shellutils.R(&SAMLProviderProtocolDeleteOptions{}, "saml-provider-protocol-delete", "Delete saml provider protocol", func(cli *huawei.SRegion, args *SAMLProviderProtocolDeleteOptions) error { - return cli.GetClient().DeleteSAMLProviderProtocol(args.SAML_PROVIDER, args.PROTOCOL) - }) - - shellutils.R(&SAMLProviderIdOptions{}, "saml-provider-metadata-show", "Show saml provider metadata", func(cli *huawei.SRegion, args *SAMLProviderIdOptions) error { - result, err := cli.GetClient().GetSAMLProviderMetadata(args.ID) - if err != nil { - return err - } - printObject(result) - return nil - }) - - type SAMLProviderMetadataOptions struct { - ID string - METADATA string - } - - shellutils.R(&SAMLProviderMetadataOptions{}, "saml-provider-metadata-update", "Update saml provider metadata", func(cli *huawei.SRegion, args *SAMLProviderMetadataOptions) error { - return cli.GetClient().UpdateSAMLProviderMetadata(args.ID, args.METADATA) - }) - - type MappingListOptions struct { - } - - shellutils.R(&MappingListOptions{}, "saml-provider-mapping-list", "List saml provider mapping", func(cli *huawei.SRegion, args *MappingListOptions) error { - mappings, err := cli.GetClient().ListSAMLProviderMappings() - if err != nil { - return err - } - printList(mappings, 0, 0, 0, nil) - return nil - }) - - type MappingInitOptions struct { - SAML_PROVIDER string - } - - shellutils.R(&MappingInitOptions{}, "saml-provider-mapping-init", "Init saml provider mapping", func(cli *huawei.SRegion, args *MappingInitOptions) error { - return cli.GetClient().InitSAMLProviderMapping(args.SAML_PROVIDER) - }) - - type MappingDeleteOptions struct { - ID string - } - - shellutils.R(&MappingDeleteOptions{}, "saml-provider-mapping-delete", "Delete saml provider mapping", func(cli *huawei.SRegion, args *MappingDeleteOptions) error { - return cli.GetClient().DeleteSAMLProviderMapping(args.ID) - }) - -} diff --git a/pkg/multicloud/huawei/shell/secgroup.go b/pkg/multicloud/huawei/shell/secgroup.go deleted file mode 100644 index bf04d220e3..0000000000 --- a/pkg/multicloud/huawei/shell/secgroup.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - VpcId string `help:"VPC ID"` - Name string `help:"Secgroup name"` - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security group", func(cli *huawei.SRegion, args *SecurityGroupListOptions) error { - secgrps, e := cli.GetSecurityGroups(args.VpcId, args.Name) - if e != nil { - return e - } - printList(secgrps, 0, 0, 0, nil) - 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 *huawei.SRegion, args *SecurityGroupShowOptions) error { - secgrp, err := cli.GetSecurityGroupDetails(args.ID) - if err != nil { - return err - } - printObject(secgrp) - return nil - }) - - type SecurityGroupCreateOptions struct { - NAME string `help:"secgroup name"` - VPC string `help:"ID of VPC"` - Desc string `help:"description"` - } - shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create security group", func(cli *huawei.SRegion, args *SecurityGroupCreateOptions) error { - result, err := cli.CreateSecurityGroup(args.VPC, args.NAME, args.Desc) - if err != nil { - return err - } - printObject(result) - return nil - }) - - type SecurityGroupRuleIdOptions struct { - ID string - } - - shellutils.R(&SecurityGroupRuleIdOptions{}, "security-group-rule-delete", "Delete security group rule", func(cli *huawei.SRegion, args *SecurityGroupRuleIdOptions) error { - return cli.DeleteSecurityGroupRule(args.ID) - }) - - type SecurityGroupRuleCreateOptions struct { - SECGROUP_ID string - RULE string - } - - shellutils.R(&SecurityGroupRuleCreateOptions{}, "security-group-rule-create", "Create security group rule", func(cli *huawei.SRegion, args *SecurityGroupRuleCreateOptions) error { - _rule, err := secrules.ParseSecurityRule(args.RULE) - if err != nil { - return errors.Wrapf(err, "invalid rule %s", args.RULE) - } - rule := cloudprovider.SecurityRule{ - SecurityRule: *_rule, - } - return cli.CreateSecurityGroupRule(args.SECGROUP_ID, rule) - }) - -} diff --git a/pkg/multicloud/huawei/shell/snapshot.go b/pkg/multicloud/huawei/shell/snapshot.go deleted file mode 100644 index a46a3bbbf1..0000000000 --- a/pkg/multicloud/huawei/shell/snapshot.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SnapshotListOptions struct { - DiskId string `help:"Disk ID"` - Name string `help:"Snapshot Name"` - } - shellutils.R(&SnapshotListOptions{}, "snapshot-list", "List snapshot", func(cli *huawei.SRegion, args *SnapshotListOptions) error { - snapshots, err := cli.GetSnapshots(args.DiskId, args.Name) - if err != nil { - return err - } - printList(snapshots, 0, 0, 0, nil) - return nil - }) - - type SnapshotDeleteOptions struct { - ID string `help:"Snapshot ID"` - } - - shellutils.R(&SnapshotDeleteOptions{}, "snapshot-delete", "Delete snapshot", func(cli *huawei.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 *huawei.SRegion, args *SnapshotCreateOptions) error { - _, err := cli.CreateSnapshot(args.DiskId, args.Name, args.Desc) - return err - }) - -} diff --git a/pkg/multicloud/huawei/shell/vpc.go b/pkg/multicloud/huawei/shell/vpc.go deleted file mode 100644 index b19165bd4e..0000000000 --- a/pkg/multicloud/huawei/shell/vpc.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - } - shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *huawei.SRegion, args *VpcListOptions) error { - vpcs, e := cli.GetVpcs() - if e != nil { - return e - } - printList(vpcs, 0, 0, 0, nil) - return nil - }) - - type VpcCreateOptions struct { - NAME string - CIDR string - Desc string - } - - shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *huawei.SRegion, args *VpcCreateOptions) error { - vpc, err := cli.CreateVpc(args.NAME, args.CIDR, args.Desc) - if err != nil { - return err - } - printObject(vpc) - return nil - }) - - type VpcIdOption struct { - ID string - } - - shellutils.R(&VpcIdOption{}, "vpc-delete", "Delete vpc", func(cli *huawei.SRegion, args *VpcIdOption) error { - return cli.DeleteVpc(args.ID) - }) - - type VpcPeeringListOPtion struct { - VPCID string - } - shellutils.R(&VpcPeeringListOPtion{}, "vpcPeering-list", "List vpcPeering", func(cli *huawei.SRegion, args *VpcPeeringListOPtion) error { - vpcPeerings, err := cli.GetVpcPeerings(args.VPCID) - if err != nil { - return err - } - printList(vpcPeerings, 0, 0, 0, nil) - return nil - }) - - type VpcPeeringShowOPtion struct { - VPCPEERINGID string - } - shellutils.R(&VpcPeeringShowOPtion{}, "vpcPeering-show", "show vpcPeering", func(cli *huawei.SRegion, args *VpcPeeringShowOPtion) error { - vpcPeering, err := cli.GetVpcPeering(args.VPCPEERINGID) - if err != nil { - return err - } - printObject(vpcPeering) - return nil - }) - - type VpcPeeringCreateOPtion struct { - NAME string - VPCID string - PEERVPCID string - PEEROWNERID string - } - shellutils.R(&VpcPeeringCreateOPtion{}, "vpcPeering-create", "create vpcPeering", func(cli *huawei.SRegion, args *VpcPeeringCreateOPtion) error { - opts := cloudprovider.VpcPeeringConnectionCreateOptions{} - opts.Name = args.NAME - opts.PeerVpcId = args.PEERVPCID - opts.PeerAccountId = args.PEEROWNERID - vpcPeering, err := cli.CreateVpcPeering(args.VPCID, &opts) - if err != nil { - return err - } - printObject(vpcPeering) - return nil - }) - - type VpcPeeringAcceptOPtion struct { - VPCPEERINGID string - } - shellutils.R(&VpcPeeringAcceptOPtion{}, "vpcPeering-accept", "Accept vpcPeering", func(cli *huawei.SRegion, args *VpcPeeringAcceptOPtion) error { - err := cli.AcceptVpcPeering(args.VPCPEERINGID) - if err != nil { - return err - } - return nil - }) - - type VpcPeeringDeleteOPtion struct { - VPCPEERINGID string - } - shellutils.R(&VpcPeeringDeleteOPtion{}, "vpcPeering-delete", "Delete vpcPeering", func(cli *huawei.SRegion, args *VpcPeeringDeleteOPtion) error { - err := cli.DeleteVpcPeering(args.VPCPEERINGID) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/huawei/shell/zone.go b/pkg/multicloud/huawei/shell/zone.go deleted file mode 100644 index 32b90ee182..0000000000 --- a/pkg/multicloud/huawei/shell/zone.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - } - shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *huawei.SRegion, args *ZoneListOptions) error { - zones, e := cli.GetIZones() - if e != nil { - return e - } - - printList(zones, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/huawei/snapshot.go b/pkg/multicloud/huawei/snapshot.go deleted file mode 100644 index ebec09ab7f..0000000000 --- a/pkg/multicloud/huawei/snapshot.go +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -/* -限制: -https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html -1. 从快照创建云硬盘时,volume_type字段必须和快照源云硬盘保持一致。 -2. 当指定的云硬盘类型在avaliability_zone内不存在时,则创建云硬盘失败。 -*/ - -type SnapshotStatusType string - -const ( - SnapshotStatusCreating SnapshotStatusType = "creating" - SnapshotStatusAvailable SnapshotStatusType = "available" // 云硬盘快照创建成功,可以使用。 - SnapshotStatusError SnapshotStatusType = "error" // 云硬盘快照在创建过程中出现错误。 - SnapshotStatusDeleting SnapshotStatusType = "deleting" // 云硬盘快照处于正在删除的过程中。 - SnapshotStatusErrorDeleting SnapshotStatusType = "error_deleting" // 云硬盘快照在删除过程中出现错误 - SnapshotStatusRollbacking SnapshotStatusType = "rollbacking" // 云硬盘快照处于正在回滚数据的过程中。 - SnapshotStatusBackingUp SnapshotStatusType = "backing-up" // 通过快照创建备份,快照状态就会变为backing-up -) - -type Metadata struct { - SystemEnableActive string `json:"__system__enableActive"` // 如果为true。则表明是系统盘快照 -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html -type SSnapshot struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - - Metadata Metadata `json:"metadata"` - CreatedAt string `json:"created_at"` - Description string `json:"description"` - ID string `json:"id"` - Name string `json:"name"` - OSExtendedSnapshotAttributesProgress string `json:"os-extended-snapshot-attributes:progress"` - OSExtendedSnapshotAttributesProjectID string `json:"os-extended-snapshot-attributes:project_id"` - Size int32 `json:"size"` // GB - Status string `json:"status"` - UpdatedAt string `json:"updated_at"` - VolumeID string `json:"volume_id"` -} - -func (self *SSnapshot) GetId() string { - return self.ID -} - -func (self *SSnapshot) GetName() string { - return self.Name -} - -func (self *SSnapshot) GetGlobalId() string { - return self.ID -} - -func (self *SSnapshot) GetStatus() string { - switch SnapshotStatusType(self.Status) { - case SnapshotStatusAvailable: - return api.SNAPSHOT_READY - case SnapshotStatusCreating: - return api.SNAPSHOT_CREATING - case SnapshotStatusDeleting: - return api.SNAPSHOT_DELETING - case SnapshotStatusErrorDeleting, SnapshotStatusError: - return api.SNAPSHOT_FAILED - case SnapshotStatusRollbacking: - return api.SNAPSHOT_ROLLBACKING - default: - return api.SNAPSHOT_UNKNOWN - } -} - -func (self *SSnapshot) Refresh() error { - snapshot, err := self.region.GetSnapshotById(self.GetId()) - if err != nil { - return err - } - - if err := jsonutils.Update(self, snapshot); err != nil { - return err - } - - return nil -} - -func (self *SSnapshot) IsEmulated() bool { - return false -} - -func (self *SSnapshot) GetSizeMb() int32 { - return self.Size * 1024 -} - -func (self *SSnapshot) GetDiskId() string { - return self.VolumeID -} - -func (self *SSnapshot) GetDiskType() string { - if self.Metadata.SystemEnableActive == "true" { - return api.DISK_TYPE_SYS - } else { - return api.DISK_TYPE_DATA - } -} - -func (self *SSnapshot) Delete() error { - if self.region == nil { - return fmt.Errorf("not init region for snapshot %s", self.GetId()) - } - return self.region.DeleteSnapshot(self.GetId()) -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408627.html -func (self *SRegion) GetSnapshots(diskId string, snapshotName string) ([]SSnapshot, error) { - params := make(map[string]string) - - if len(diskId) > 0 { - params["volume_id"] = diskId - } - - if len(snapshotName) > 0 { - params["name"] = snapshotName - } - - snapshots := make([]SSnapshot, 0) - err := doListAllWithOffset(self.ecsClient.Snapshots.List, params, &snapshots) - for i := range snapshots { - snapshots[i].region = self - } - - return snapshots, err -} - -func (self *SRegion) GetSnapshotById(snapshotId string) (SSnapshot, error) { - var snapshot SSnapshot - err := DoGet(self.ecsClient.Snapshots.Get, snapshotId, nil, &snapshot) - snapshot.region = self - return snapshot, err -} - -// 不能删除以autobk_snapshot_为前缀的快照。 -// 当快照状态为available、error状态时,才可以删除。 -func (self *SRegion) DeleteSnapshot(snapshotId string) error { - return DoDelete(self.ecsClient.Snapshots.Delete, snapshotId, nil, nil) -} - -// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html -// 目前已设置force字段。云硬盘处于挂载状态时,能强制创建快照。 -func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { - params := jsonutils.NewDict() - snapshotObj := jsonutils.NewDict() - snapshotObj.Add(jsonutils.NewString(name), "name") - snapshotObj.Add(jsonutils.NewString(desc), "description") - snapshotObj.Add(jsonutils.NewString(diskId), "volume_id") - snapshotObj.Add(jsonutils.JSONTrue, "force") - params.Add(snapshotObj, "snapshot") - - snapshot := SSnapshot{} - err := DoCreate(self.ecsClient.Snapshots.Create, params, &snapshot) - return snapshot.ID, err -} - -func (self *SSnapshot) GetProjectId() string { - return "" -} diff --git a/pkg/multicloud/huawei/storage.go b/pkg/multicloud/huawei/storage.go deleted file mode 100644 index 7036f2d704..0000000000 --- a/pkg/multicloud/huawei/storage.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - zone *SZone - multicloud.SStorageBase - multicloud.HuaweiTags - storageType string // volume_type 目前支持“SSD”,“SAS”和“SATA”三种 -} - -func (self *SStorage) GetId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetName() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetGlobalId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) Refresh() error { - return nil -} - -func (self *SStorage) IsEmulated() bool { - return true -} - -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, err := self.zone.region.GetDisks(self.zone.GetId()) - if err != nil { - return nil, err - } - - // 按storage type 过滤出disk - filtedDisks := make([]SDisk, 0) - for i := range disks { - disk := disks[i] - if disk.VolumeType == self.storageType { - filtedDisks = append(filtedDisks, disk) - } - } - - idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) - for i := 0; i < len(filtedDisks); i += 1 { - filtedDisks[i].storage = self - idisks[i] = &filtedDisks[i] - } - return idisks, nil -} - -func (self *SStorage) GetStorageType() string { - return self.storageType -} - -func (self *SStorage) GetMediumType() string { - if self.storageType == api.STORAGE_HUAWEI_SSD { - return api.DISK_TYPE_SSD - } else { - return api.DISK_TYPE_ROTATE - } -} - -func (self *SStorage) GetCapacityMB() int64 { - return 0 // unlimited -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - conf := jsonutils.NewDict() - return conf -} - -func (self *SStorage) GetEnabled() bool { - return true -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - diskId, err := self.zone.region.CreateDisk(self.zone.GetId(), self.storageType, conf.Name, conf.SizeGb, "", conf.Desc, conf.ProjectId) - 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 - - err = cloudprovider.WaitStatus(disk, api.DISK_READY, 5*time.Second, 120*time.Second) - if err != nil { - return nil, err - } - - return disk, nil -} - -func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - if len(idStr) == 0 { - log.Debugf("GetIDiskById disk id should not be empty") - return nil, cloudprovider.ErrNotFound - } - - if disk, err := self.zone.region.GetDisk(idStr); err != nil { - return nil, err - } else { - disk.storage = self - return disk, nil - } -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} diff --git a/pkg/multicloud/huawei/storagecache.go b/pkg/multicloud/huawei/storagecache.go deleted file mode 100644 index d5058f4188..0000000000 --- a/pkg/multicloud/huawei/storagecache.go +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "context" - "fmt" - "math" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "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" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion -} - -func GetBucketName(regionId string, imageId string) string { - return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), imageId) -} - -func (self *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) -} - -func (self *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) -} - -func (self *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, 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) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - imagesSelf, err := self.region.GetImages("", ImageOwnerSelf, "", EnvFusionCompute) - if err != nil { - return nil, errors.Wrapf(err, "GetImages") - } - - ret := []cloudprovider.ICloudImage{} - for i := range imagesSelf { - imagesSelf[i].storageCache = self - ret = append(ret, &imagesSelf[i]) - } - return ret, nil -} - -func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - image, err := self.region.GetImage(extId) - if err != nil { - return nil, errors.Wrap(err, "self.region.GetImage") - } - image.storageCache = self - return image, nil -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -// 目前支持使用vhd、zvhd、vmdk、qcow2、raw、zvhd2、vhdx、qcow、vdi或qed格式镜像文件创建私有镜像。 -// 快速通道功能可快速完成镜像制作,但镜像文件需转换为raw或zvhd2格式并完成镜像优化。 -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0083905788.html -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 - 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) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return self.uploadImage(ctx, userCred, image, callback) -} - -func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - bucketName := GetBucketName(self.region.GetId(), image.ImageId) - - exist, _ := self.region.IBucketExist(bucketName) - if !exist { - err := self.region.CreateIBucket(bucketName, "", "") - if err != nil { - return "", errors.Wrap(err, "CreateIBucket") - } - } - defer self.region.DeleteIBucket(bucketName) - - // upload to huawei cloud - s := auth.GetAdminSession(ctx, options.Options.Region) - meta, reader, sizeByte, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) - if err != nil { - return "", errors.Wrap(err, "Images.Download") - } - log.Debugf("Images meta data %s", meta) - - minDiskMB, _ := meta.Int("min_disk") - minDiskGB := int64(math.Ceil(float64(minDiskMB) / 1024)) - // 在使用OBS桶的外部镜像文件制作镜像时生效且为必选字段。取值为40~1024GB。 - if minDiskGB < 40 { - minDiskGB = 40 - } else if minDiskGB > 1024 { - minDiskGB = 1024 - } - - bucket, err := self.region.GetIBucketByName(bucketName) - if err != nil { - return "", errors.Wrapf(err, "GetIBucketByName %s", bucketName) - } - - body := multicloud.NewProgress(sizeByte, 95, reader, callback) - err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeByte, "", "", nil, false) - if err != nil { - return "", errors.Wrap(err, "cloudprovider.UploadObject") - } - - defer bucket.DeleteObject(context.Background(), image.ImageId) - - // check image name, avoid name conflict - imageBaseName := image.ImageId - if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { - imageBaseName = fmt.Sprintf("img%s", image.ImageId) - } - imageName := imageBaseName - nameIdx := 1 - - for { - _, err = self.region.GetImageByName(imageName) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - break - } else { - return "", err - } - } - - imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) - nameIdx += 1 - log.Debugf("uploadImage Match remote name %s", imageName) - } - - jobId, err := self.region.ImportImageJob(imageName, image.OsDistribution, image.OsVersion, image.OsArch, bucketName, image.ImageId, int64(minDiskGB)) - - if err != nil { - log.Errorf("ImportImage error %s %s %s %s", jobId, image.ImageId, bucketName, err) - return "", err - } - - // timeout: 1hour = 3600 seconds - serviceType := self.region.ecsClient.Images.ServiceType() - err = self.region.waitTaskStatus(serviceType, jobId, TASK_SUCCESS, 15*time.Second, 3600*time.Second) - if err != nil { - log.Errorf("waitTaskStatus %s", err) - return "", err - } - - if callback != nil { - callback(100) - } - - // https://support.huaweicloud.com/api-ims/zh-cn_topic_0022473688.html - return self.region.GetTaskEntityID(serviceType, jobId, "image_id") -} - -func (self *SRegion) getStoragecache() *SStoragecache { - if self.storageCache == nil { - self.storageCache = &SStoragecache{region: self} - } - return self.storageCache -} - -type SJob struct { - Status string `json:"status"` - Entities map[string]string `json:"entities"` - JobID string `json:"job_id"` - JobType string `json:"job_type"` - BeginTime string `json:"begin_time"` - EndTime string `json:"end_time"` - ErrorCode string `json:"error_code"` - FailReason string `json:"fail_reason"` -} - -// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html -func (self *SRegion) createIImage(snapshotId, imageName, imageDesc string) (string, error) { - snapshot, err := self.GetSnapshotById(snapshotId) - if err != nil { - return "", err - } - - disk, err := self.GetDisk(snapshot.VolumeID) - if err != nil { - return "", err - } - - if disk.GetDiskType() != api.DISK_TYPE_SYS { - return "", fmt.Errorf("disk type err, expected disk type %s", api.DISK_TYPE_SYS) - } - - if len(disk.Attachments) == 0 { - return "", fmt.Errorf("disk is not attached.") - } - - imageObj := jsonutils.NewDict() - imageObj.Add(jsonutils.NewString(disk.Attachments[0].ServerID), "instance_id") - imageObj.Add(jsonutils.NewString(imageName), "name") - imageObj.Add(jsonutils.NewString(imageDesc), "description") - - ret, err := self.ecsClient.Images.PerformAction2("action", "", imageObj, "") - if err != nil { - return "", err - } - - job := SJob{} - jobId, err := ret.GetString("job_id") - querys := map[string]string{"service_type": self.ecsClient.Images.ServiceType()} - err = DoGet(self.ecsClient.Jobs.Get, jobId, querys, &job) - if err != nil { - return "", err - } - - if job.Status == "SUCCESS" { - imageId, exists := job.Entities["image_id"] - if exists { - return imageId, nil - } else { - return "", fmt.Errorf("image id not found in create image job %s", job.JobID) - } - } else { - return "", fmt.Errorf("create image failed, %s", job.FailReason) - } - -} - -func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - return []cloudprovider.ICloudStoragecache{storageCache}, nil -} - -func (self *SRegion) GetIStoragecacheById(idstr string) (cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - if storageCache.GetGlobalId() == idstr { - return storageCache, nil - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/huawei/traces.go b/pkg/multicloud/huawei/traces.go deleted file mode 100644 index 3d6daa3d96..0000000000 --- a/pkg/multicloud/huawei/traces.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "strconv" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SUser struct { - Domain map[string]string - Name string - Id string -} - -type SEvent struct { - TraceId string - Code string - TraceName string - ResourceType string - ApiVersion string - SourceIp string - TraceType string - ServiceType string - EventType string - ProjectId string - Request string - Response string - TrackerName string - TraceStatus string - Time int64 - ResourceId string - ResourceName string - User SUser - RecordTime int64 -} - -func (event *SEvent) GetName() string { - if len(event.ResourceName) > 0 { - return event.ResourceName - } - if len(event.ResourceId) > 0 { - return event.ResourceId - } - return event.TraceName -} - -func (event *SEvent) GetService() string { - return event.ServiceType -} - -func (event *SEvent) GetAction() string { - return event.TraceName -} - -func (event *SEvent) GetResourceType() string { - return event.ResourceType -} - -func (event *SEvent) GetRequestId() string { - return event.TraceId -} - -func (event *SEvent) GetRequest() jsonutils.JSONObject { - return jsonutils.Marshal(event) -} - -func (event *SEvent) GetAccount() string { - return event.User.Name -} - -func (event *SEvent) IsSuccess() bool { - code, _ := strconv.Atoi(event.Code) - return code < 400 -} - -func (event *SEvent) GetCreatedAt() time.Time { - return time.Unix(event.Time/1000, event.Time%1000) -} - -func (self *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { - if !self.client.isMainProject { - return nil, cloudprovider.ErrNotSupported - } - events, err := self.GetEvents(start, end) - if err != nil { - return nil, err - } - iEvents := []cloudprovider.ICloudEvent{} - for i := range events { - iEvents = append(iEvents, &events[i]) - } - return iEvents, nil -} - -func (self *SRegion) GetEvents(start time.Time, end time.Time) ([]SEvent, error) { - events := []SEvent{} - params := map[string]string{} - if start.IsZero() { - start = time.Now().AddDate(0, 0, -7) - } - if end.IsZero() { - end = time.Now() - } - params["from"] = fmt.Sprintf("%d000", start.Unix()) - params["to"] = fmt.Sprintf("%d000", end.Unix()) - - err := doListAllWithMarker(self.ecsClient.Traces.List, params, &events) - if err != nil { - return nil, errors.Wrap(err, "doListAllWithMarker") - } - return events, nil -} diff --git a/pkg/multicloud/huawei/utils.go b/pkg/multicloud/huawei/utils.go deleted file mode 100644 index f05a2b47a3..0000000000 --- a/pkg/multicloud/huawei/utils.go +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "reflect" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -// 常用的方法 -type listFunc func(querys map[string]string) (*responses.ListResult, error) -type getFunc func(id string, querys map[string]string) (jsonutils.JSONObject, error) -type createFunc func(params jsonutils.JSONObject) (jsonutils.JSONObject, error) -type updateFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) -type updateFunc2 func(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) -type deleteFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) -type deleteFunc2 func(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) -type listInCtxFunc func(ctx manager.IManagerContext, querys map[string]string) (*responses.ListResult, error) -type listInCtxWithSpecFunc func(ctx manager.IManagerContext, spec string, querys map[string]string, responseKey string) (*responses.ListResult, error) - -func unmarshalResult(resp jsonutils.JSONObject, respErr error, result interface{}, method string) error { - if respErr != nil { - switch e := respErr.(type) { - case *httputils.JSONClientError: - if (e.Code == 404 || utils.IsInStringArray(e.Class, NOT_FOUND_CODES)) && method != "POST" { - return cloudprovider.ErrNotFound - } - return e - default: - return e - } - } - - if result == nil { - return nil - } - - err := resp.Unmarshal(result) - if err != nil { - log.Errorf("unmarshal json error %s", err) - } - - return err -} - -var pageLimit = 100 - -// offset 表示的是页码 -func doListAllWithPagerOffset(doList listFunc, queries map[string]string, result interface{}) error { - startIndex := 0 - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - queries["offset"] = fmt.Sprintf("%d", startIndex) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - - startIndex++ - queries["offset"] = fmt.Sprintf("%d", startIndex) - } - return nil -} - -func doListAllWithNextLink(doList listFunc, querys map[string]string, result interface{}) error { - values := []jsonutils.JSONObject{} - for { - ret, err := doList(querys) - if err != nil { - return errors.Wrap(err, "doList") - } - values = append(values, ret.Data...) - if len(ret.NextLink) == 0 || ret.NextLink == "null" { - break - } - } - if result != nil { - return jsonutils.Update(result, values) - } - return nil -} - -func doListAllWithOffset(doList listFunc, queries map[string]string, result interface{}) error { - startIndex := 0 - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - queries["offset"] = fmt.Sprintf("%d", startIndex) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - queries["offset"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) - } - return nil -} - -func doListAllWithPage(doList listFunc, queries map[string]string, result interface{}) error { - startIndex := 1 - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - queries["page"] = fmt.Sprintf("%d", startIndex) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - queries["page"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) - } - return nil -} - -func doListAllWithMarker(doList listFunc, queries map[string]string, result interface{}) error { - resultValue := reflect.Indirect(reflect.ValueOf(result)) - queries["limit"] = fmt.Sprintf("%d", pageLimit) - for { - total, part, err := doListPart(doList, queries, result) - if err != nil { - return err - } - if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { - break - } - lastValue := resultValue.Index(resultValue.Len() - 1) - markerValue := lastValue.FieldByNameFunc(func(key string) bool { - if strings.ToLower(key) == "id" { - return true - } - return false - }) - queries["marker"] = markerValue.String() - } - return nil -} - -func doListAll(doList listFunc, queries map[string]string, result interface{}) error { - total, _, err := doListPart(doList, queries, result) - if err != nil { - return err - } - resultValue := reflect.Indirect(reflect.ValueOf(result)) - if total > 0 && resultValue.Len() < total { - log.Warningf("INCOMPLETE QUERY, total %d queried %d", total, resultValue.Len()) - } - return nil -} - -func doListPart(doList listFunc, queries map[string]string, result interface{}) (int, int, error) { - ret, err := doList(queries) - if err != nil { - return 0, 0, err - } - resultValue := reflect.Indirect(reflect.ValueOf(result)) - elemType := resultValue.Type().Elem() - for i := range ret.Data { - elemPtr := reflect.New(elemType) - err = ret.Data[i].Unmarshal(elemPtr.Interface()) - if err != nil { - return 0, 0, err - } - resultValue.Set(reflect.Append(resultValue, elemPtr.Elem())) - } - return ret.Total, len(ret.Data), nil -} - -func DoGet(doGet getFunc, id string, queries map[string]string, result interface{}) error { - if len(id) == 0 { - resultType := reflect.Indirect(reflect.ValueOf(result)).Type() - return errors.Wrap(cloudprovider.ErrNotFound, fmt.Sprintf(" Get %s id should not be empty", resultType.Name())) - } - - ret, err := doGet(id, queries) - return unmarshalResult(ret, err, result, "GET") -} - -func DoListInContext(listFunc listInCtxFunc, ctx manager.IManagerContext, querys map[string]string, result interface{}) error { - ret, err := listFunc(ctx, querys) - if err != nil { - return err - } - - obj := responses.ListResult2JSON(ret) - err = obj.Unmarshal(result, "data") - if err != nil { - log.Errorf("unmarshal json error %s", err) - return err - } - - return nil -} - -func DoCreate(createFunc createFunc, params jsonutils.JSONObject, result interface{}) error { - ret, err := createFunc(params) - return unmarshalResult(ret, err, result, "POST") -} - -func DoUpdate(updateFunc updateFunc, id string, params jsonutils.JSONObject, result interface{}) error { - ret, err := updateFunc(id, params) - return unmarshalResult(ret, err, result, "PUT") -} - -func DoUpdateWithSpec(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject) error { - _, err := updateFunc(nil, id, spec, params, "") - return err -} - -func DoUpdateWithSpec2(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject, result interface{}) error { - ret, err := updateFunc(nil, id, spec, params, "") - return unmarshalResult(ret, err, result, "PUT") -} - -func DoDelete(deleteFunc deleteFunc, id string, params jsonutils.JSONObject, result interface{}) error { - if len(id) == 0 { - return fmt.Errorf(" id should not be empty") - } - - ret, err := deleteFunc(id, params) - return unmarshalResult(ret, err, result, "DELETE") -} - -func DoDeleteWithSpec(deleteFunc deleteFunc2, ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject) error { - if len(id) == 0 { - return fmt.Errorf(" id should not be empty") - } - - _, err := deleteFunc(ctx, id, spec, queries, params, "") - return err -} - -func ErrMessage(err error) string { - switch v := err.(type) { - case *httputils.JSONClientError: - return fmt.Sprintf("%d(%s):%s", v.Code, v.Class, v.Details) - default: - return err.Error() - } -} diff --git a/pkg/multicloud/huawei/vpc.go b/pkg/multicloud/huawei/vpc.go deleted file mode 100644 index e2440019ae..0000000000 --- a/pkg/multicloud/huawei/vpc.go +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html -type SVpc struct { - multicloud.SVpc - multicloud.HuaweiTags - - region *SRegion - - iwires []cloudprovider.ICloudWire - secgroups []cloudprovider.ICloudSecurityGroup - - ID string `json:"id"` - Name string `json:"name"` - CIDR string `json:"cidr"` - Status string `json:"status"` - EnterpriseProjectID string `json:"enterprise_project_id"` -} - -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) getWireByRegionId(regionId string) *SWire { - if len(regionId) == 0 { - return nil - } - - for i := 0; i < len(self.iwires); i++ { - wire := self.iwires[i].(*SWire) - - if wire.region.GetId() == regionId { - return wire - } - } - - return nil -} - -func (self *SVpc) fetchNetworks() error { - networks, err := self.region.GetNetwroks(self.ID) - if err != nil { - return err - } - - // ??????? - if len(networks) == 0 { - self.iwires = append(self.iwires, &SWire{region: self.region, vpc: self}) - return nil - } - - for i := 0; i < len(networks); i += 1 { - wire := self.getWireByRegionId(self.region.GetId()) - networks[i].wire = wire - wire.addNetwork(&networks[i]) - } - return nil -} - -// 华为云安全组可以被同region的VPC使用 -func (self *SVpc) fetchSecurityGroups() error { - secgroups, err := self.region.GetSecurityGroups("", "") - if err != nil { - return err - } - - self.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) - for i := 0; i < len(secgroups); i++ { - self.secgroups[i] = &secgroups[i] - } - return nil -} - -func (self *SVpc) GetId() string { - return self.ID -} - -func (self *SVpc) GetName() string { - if len(self.Name) > 0 { - return self.Name - } - return self.ID -} - -func (self *SVpc) GetGlobalId() string { - return self.ID -} - -func (self *SVpc) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} - -func (self *SVpc) Refresh() error { - new, err := self.region.getVpc(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SVpc) IsEmulated() bool { - return false -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetIsDefault() bool { - // 华为云没有default vpc. - return false -} - -func (self *SVpc) GetCidrBlock() string { - return self.CIDR -} - -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) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - rtbs, err := self.region.GetRouteTables(self.ID) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudRouteTable{} - for i := range rtbs { - rtbs[i].vpc = self - ret = append(ret, &rtbs[i]) - } - return ret, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - rtb, err := self.region.GetRouteTable(routeTableId) - if err != nil { - return nil, err - } - rtb.vpc = self - return rtb, nil -} - -func (self *SVpc) Delete() error { - // todo: 确定删除VPC的逻辑 - return self.region.DeleteVpc(self.GetId()) -} - -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) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { - nats, err := self.region.GetNatGateways(self.GetId(), "") - if err != nil { - return nil, err - } - ret := make([]cloudprovider.ICloudNatGateway, len(nats)) - for i := 0; i < len(nats); i++ { - ret[i] = &nats[i] - } - return ret, nil -} - -func (self *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPCs, err := self.getVpcPeeringConnections() - if err != nil { - return nil, errors.Wrap(err, "self.getVpcPeeringConnections()") - } - ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} - for i := range svpcPCs { - ivpcPCs = append(ivpcPCs, &svpcPCs[i]) - } - return ivpcPCs, nil -} - -func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPCs, err := self.getAccepterVpcPeeringConnections() - if err != nil { - return nil, errors.Wrap(err, "self.getAccepterVpcPeeringConnections()") - } - ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} - for i := range svpcPCs { - ivpcPCs = append(ivpcPCs, &svpcPCs[i]) - } - return ivpcPCs, nil -} - -func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPC, err := self.getVpcPeeringConnectionById(id) - if err != nil { - return nil, errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) - } - return svpcPC, nil -} - -func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPC, err := self.region.CreateVpcPeering(self.GetId(), opts) - if err != nil { - return nil, errors.Wrapf(err, "self.region.CreateVpcPeering(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) - } - svpcPC.vpc = self - return svpcPC, nil -} -func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { - vpcPC, err := self.getVpcPeeringConnectionById(id) - if err != nil { - return errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) - } - if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_ACTIVE { - return nil - } - if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN { - return errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcPC: %s", jsonutils.Marshal(vpcPC).String()) - } - err = self.region.AcceptVpcPeering(id) - if err != nil { - return errors.Wrapf(err, "self.region.AcceptVpcPeering(%s)", id) - } - return nil -} - -func (self *SVpc) GetAuthorityOwnerId() string { - return self.region.client.projectId -} - -func (self *SVpc) getVpcPeeringConnections() ([]SVpcPeering, error) { - svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) - } - vpcPCs := []SVpcPeering{} - for i := range svpcPeerings { - if svpcPeerings[i].GetVpcId() == self.GetId() { - svpcPeerings[i].vpc = self - vpcPCs = append(vpcPCs, svpcPeerings[i]) - } - } - return vpcPCs, nil -} - -func (self *SVpc) getAccepterVpcPeeringConnections() ([]SVpcPeering, error) { - svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) - } - vpcPCs := []SVpcPeering{} - for i := range svpcPeerings { - if svpcPeerings[i].GetPeerVpcId() == self.GetId() { - svpcPeerings[i].vpc = self - vpcPCs = append(vpcPCs, svpcPeerings[i]) - } - } - return vpcPCs, nil -} - -func (self *SVpc) getVpcPeeringConnectionById(id string) (*SVpcPeering, error) { - svpcPC, err := self.region.GetVpcPeering(id) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetVpcPeering(%s)", id) - } - svpcPC.vpc = self - return svpcPC, nil -} - -func (self *SRegion) getVpc(vpcId string) (*SVpc, error) { - vpc := SVpc{} - err := DoGet(self.ecsClient.Vpcs.Get, vpcId, nil, &vpc) - if err != nil && strings.Contains(err.Error(), "RouterNotFound") { - return nil, cloudprovider.ErrNotFound - } - vpc.region = self - return &vpc, err -} - -func (self *SRegion) DeleteVpc(vpcId string) error { - if vpcId != "default" { - secgroups, err := self.GetSecurityGroups(vpcId, "") - if err != nil { - return errors.Wrap(err, "GetSecurityGroups") - } - for _, secgroup := range secgroups { - err = self.DeleteSecurityGroup(secgroup.ID) - if err != nil { - return errors.Wrapf(err, "DeleteSecurityGroup(%s)", secgroup.ID) - } - } - } - return DoDelete(self.ecsClient.Vpcs.Delete, vpcId, nil, nil) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html -func (self *SRegion) GetVpcs() ([]SVpc, error) { - querys := make(map[string]string) - - vpcs := make([]SVpc, 0) - err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs) - if err != nil { - return nil, err - } - - for i := range vpcs { - vpcs[i].region = self - } - return vpcs, err -} diff --git a/pkg/multicloud/huawei/vpc_peering.go b/pkg/multicloud/huawei/vpc_peering.go deleted file mode 100644 index 4c36b346eb..0000000000 --- a/pkg/multicloud/huawei/vpc_peering.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type RequestVpcInfo struct { - VpcID string `json:"vpc_id"` - TenantID string `json:"tenant_id"` -} -type AcceptVpcInfo struct { - VpcID string `json:"vpc_id"` - TenantID string `json:"tenant_id"` -} -type SVpcPeering struct { - multicloud.SResourceBase - multicloud.HuaweiTags - vpc *SVpc - - RequestVpcInfo RequestVpcInfo `json:"request_vpc_info"` - AcceptVpcInfo AcceptVpcInfo `json:"accept_vpc_info"` - Name string `json:"name"` - ID string `json:"id"` - Status string `json:"status"` -} - -func (self *SRegion) GetVpcPeerings(vpcId string) ([]SVpcPeering, error) { - querys := make(map[string]string) - querys["vpc_id"] = vpcId - vpcPeerings := make([]SVpcPeering, 0) - err := doListAllWithMarker(self.ecsClient.VpcPeerings.List, querys, &vpcPeerings) - if err != nil { - return nil, errors.Wrapf(err, "oListAllWithMarker(self.ecsClient.VpcPeerings.List, %s, &vpcPeerings)", jsonutils.Marshal(querys).String()) - } - return vpcPeerings, nil -} - -func (self *SRegion) GetVpcPeering(vpcPeeringId string) (*SVpcPeering, error) { - if len(vpcPeeringId) == 0 { - return nil, cloudprovider.ErrNotFound - } - vpcPeering := SVpcPeering{} - err := DoGet(self.ecsClient.VpcPeerings.Get, vpcPeeringId, nil, &vpcPeering) - if err != nil { - return nil, errors.Wrapf(err, "DoGet(self.ecsClient.VpcPeerings.Get, %s, nil, &vpcPeering)", vpcPeeringId) - } - return &vpcPeering, nil -} - -func (self *SRegion) CreateVpcPeering(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPeering, error) { - params := jsonutils.NewDict() - vpcPeeringObj := jsonutils.NewDict() - requestVpcObj := jsonutils.NewDict() - acceptVpcObj := jsonutils.NewDict() - vpcPeeringObj.Set("name", jsonutils.NewString(opts.Name)) - requestVpcObj.Set("vpc_id", jsonutils.NewString(vpcId)) - requestVpcObj.Set("tenant_id", jsonutils.NewString(self.client.projectId)) - vpcPeeringObj.Set("request_vpc_info", requestVpcObj) - acceptVpcObj.Set("vpc_id", jsonutils.NewString(opts.PeerVpcId)) - acceptVpcObj.Set("tenant_id", jsonutils.NewString(opts.PeerAccountId)) - vpcPeeringObj.Set("accept_vpc_info", acceptVpcObj) - params.Set("peering", vpcPeeringObj) - ret := SVpcPeering{} - err := DoCreate(self.ecsClient.VpcPeerings.Create, params, &ret) - if err != nil { - return nil, errors.Wrapf(err, "DoCreate(self.ecsClient.VpcPeerings.Create, %s, &ret)", jsonutils.Marshal(params).String()) - } - return &ret, nil -} - -func (self *SRegion) AcceptVpcPeering(vpcPeeringId string) error { - err := DoUpdateWithSpec(self.ecsClient.VpcPeerings.UpdateInContextWithSpec, vpcPeeringId, "accept", nil) - if err != nil { - return errors.Wrapf(err, "DoUpdateWithSpec(self.ecsClient.VpcPeerings.UpdateInContextWithSpec, %s, accept, nil)", vpcPeeringId) - } - return nil -} - -func (self *SRegion) DeleteVpcPeering(vpcPeeringId string) error { - err := DoDelete(self.ecsClient.VpcPeerings.Delete, vpcPeeringId, nil, nil) - if err != nil { - return errors.Wrapf(err, "DoDelete(self.ecsClient.VpcPeerings.Delete,%s,nil)", vpcPeeringId) - } - return nil -} - -func (self *SVpcPeering) GetId() string { - return self.ID -} - -func (self *SVpcPeering) GetName() string { - return self.Name -} - -func (self *SVpcPeering) GetGlobalId() string { - return self.GetId() -} - -func (self *SVpcPeering) GetStatus() string { - switch self.Status { - case "PENDING_ACCEPTANCE": - return api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT - case "ACTIVE": - return api.VPC_PEERING_CONNECTION_STATUS_ACTIVE - default: - return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN - } -} - -func (self *SVpcPeering) Refresh() error { - peer, err := self.vpc.region.GetVpcPeering(self.ID) - if err != nil { - return errors.Wrapf(err, "self.region.GetVpcPeering(%s)", self.ID) - } - return jsonutils.Update(self, peer) -} - -func (self *SVpcPeering) GetVpcId() string { - return self.RequestVpcInfo.VpcID -} - -func (self *SVpcPeering) GetPeerVpcId() string { - return self.AcceptVpcInfo.VpcID -} - -func (self *SVpcPeering) GetPeerAccountId() string { - return self.AcceptVpcInfo.TenantID -} - -func (self *SVpcPeering) GetEnabled() bool { - return true -} - -func (self *SVpcPeering) Delete() error { - err := self.vpc.region.DeleteVpcPeering(self.ID) - if err != nil { - return errors.Wrapf(err, "self.region.DeleteVpcPeering(%s)", self.ID) - } - return nil -} diff --git a/pkg/multicloud/huawei/wire.go b/pkg/multicloud/huawei/wire.go deleted file mode 100644 index 526050d1ab..0000000000 --- a/pkg/multicloud/huawei/wire.go +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// 华为云的子网有点特殊。子网在整个region可用。 -type SWire struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - vpc *SVpc - - inetworks []cloudprovider.ICloudNetwork -} - -func (self *SWire) GetId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) -} - -func (self *SWire) GetName() string { - return self.GetId() -} - -func (self *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SWire) Refresh() error { - return nil -} - -func (self *SWire) IsEmulated() bool { - return true -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - return nil -} - -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 -} - -/* -华为云子网可用区,类似一个zone标签。即使指定了zone子网在整个region依然是可用。 -通过华为web控制台创建子网需要指定可用区。这里是不指定的。 -*/ -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - networkId, err := self.region.createNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc) - if err != nil { - log.Errorf("createNetwork error %s", err) - return nil, err - } - - var network *SNetwork - err = cloudprovider.WaitCreated(5*time.Second, 60*time.Second, func() bool { - self.inetworks = nil - network = self.getNetworkById(networkId) - if network == nil { - return false - } else { - return true - } - }) - - if err != nil { - log.Errorf("cannot find network after create????") - return nil, err - } - - network.wire = self - return network, 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.ID { - find = true - break - } - } - if !find { - self.inetworks = append(self.inetworks, network) - } -} - -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 getDefaultGateWay(cidr string) (string, error) { - pref, err := netutils.NewIPV4Prefix(cidr) - if err != nil { - return "", errors.Wrap(err, "getDefaultGateWay.NewIPV4Prefix") - } - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - return startIp.String(), nil -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html -// cidr 掩码长度不能大于28 -func (self *SRegion) createNetwork(vpcId string, name string, cidr string, desc string) (string, error) { - gateway, err := getDefaultGateWay(cidr) - if err != nil { - return "", err - } - - params := jsonutils.NewDict() - subnetObj := jsonutils.NewDict() - subnetObj.Add(jsonutils.NewString(name), "name") - subnetObj.Add(jsonutils.NewString(vpcId), "vpc_id") - subnetObj.Add(jsonutils.NewString(cidr), "cidr") - subnetObj.Add(jsonutils.NewString(gateway), "gateway_ip") - params.Add(subnetObj, "subnet") - - subnet := SNetwork{} - err = DoCreate(self.ecsClient.Subnets.Create, params, &subnet) - return subnet.ID, err -} diff --git a/pkg/multicloud/huawei/zone.go b/pkg/multicloud/huawei/zone.go deleted file mode 100644 index 91d953956f..0000000000 --- a/pkg/multicloud/huawei/zone.go +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 huawei - -import ( - "fmt" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var StorageTypes = []string{ - api.STORAGE_HUAWEI_SAS, - api.STORAGE_HUAWEI_SATA, - api.STORAGE_HUAWEI_SSD, -} - -type ZoneState struct { - Available bool `json:"available"` -} - -// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817728.html -type SZone struct { - multicloud.SResourceBase - multicloud.HuaweiTags - region *SRegion - host *SHost - - iwires []cloudprovider.ICloudWire - istorages []cloudprovider.ICloudStorage - - ZoneState ZoneState `json:"zoneState"` - ZoneName string `json:"zoneName"` - - /* 支持的磁盘种类集合 */ - 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) getStorageType() { - if len(self.storageTypes) == 0 { - if sts, err := self.region.GetZoneSupportedDiskTypes(self.GetId()); err == nil { - self.storageTypes = sts - } else { - log.Errorf("GetZoneSupportedDiskTypes %s %s", self.GetId(), err) - 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) getHost() *SHost { - if self.host == nil { - self.host = &SHost{zone: self, projectId: self.region.client.projectId} - } - return self.host -} - -func (self *SZone) GetId() string { - return self.ZoneName -} - -func (self *SZone) GetName() string { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.ZoneName) -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.ZoneName) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SZone) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneName) -} - -func (self *SZone) GetStatus() string { - return "enable" -} - -func (self *SZone) Refresh() error { - return nil -} - -func (self *SZone) IsEmulated() bool { - return false -} - -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 { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "fetchStorages") - } - } - return self.istorages, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - if self.istorages == nil { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "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) GetIWires() ([]cloudprovider.ICloudWire, error) { - return self.iwires, nil -} - -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.GetId() == id { - return zone, nil - } - } - return nil, fmt.Errorf("no such zone %s", id) -} - -func (self *SZone) getNetworkById(networkId string) *SNetwork { - for i := 0; i < len(self.iwires); i += 1 { - wire := self.iwires[i].(*SWire) - net := wire.getNetworkById(networkId) - if net != nil { - return net - } - } - return nil -} diff --git a/pkg/multicloud/incloudsphere/disk.go b/pkg/multicloud/incloudsphere/disk.go deleted file mode 100644 index b69739a1a4..0000000000 --- a/pkg/multicloud/incloudsphere/disk.go +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "context" - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type RelatedVms struct { - Id string `json:"id"` - Text string `json:"text"` - IconCls string `json:"iconCls"` - State string `json:"state"` - Children string `json:"children"` - Object string `json:"object"` - Name string `json:"name"` - ViewId string `json:"viewId"` - TargetType string `json:"targetType"` - InnerName string `json:"innerName"` - ServiceType string `json:"serviceType"` - StorageType string `json:"storageType"` - HciType string `json:"hciType"` - VMType string `json:"vmType"` - HostId string `json:"hostId"` - ParentId string `json:"parentId"` - DatastoreRole string `json:"datastoreRole"` - Vlan string `json:"vlan"` - DhcpEnabled bool `json:"dhcpEnabled"` - ConnectMode string `json:"connectMode"` - DataStoreType string `json:"dataStoreType"` - Hypervisor string `json:"hypervisor"` -} - -type SDisk struct { - multicloud.SDisk - multicloud.InCloudSphereTags - - region *SRegion - - Id string `json:"id"` - UUID string `json:"uuid"` - Size float64 `json:"size"` - RealSize float64 `json:"realSize"` - Name string `json:"name"` - FileName string `json:"fileName"` - Offset int `json:"offset"` - Shared bool `json:"shared"` - DeleteModel string `json:"deleteModel"` - VolumePolicy string `json:"volumePolicy"` - Format string `json:"format"` - BlockDeviceId string `json:"blockDeviceId"` - DiskType string `json:"diskType"` - DataStoreId string `json:"dataStoreId"` - DataStoreName string `json:"dataStoreName"` - DataStoreSize float64 `json:"dataStoreSize"` - FreeStorage float64 `json:"freeStorage"` - DataStoreType string `json:"dataStoreType"` - DataStoreReplicate int `json:"dataStoreReplicate"` - VMName string `json:"vmName"` - VMStatus string `json:"vmStatus"` - Type string `json:"type"` - Description string `json:"description"` - Bootable bool `json:"bootable"` - VolumeStatus string `json:"volumeStatus"` - MountedHostIds string `json:"mountedHostIds"` - Md5 string `json:"md5"` - DataSize int `json:"dataSize"` - OpenStackId string `json:"openStackId"` - VvSourceDto string `json:"vvSourceDto"` - FormatDisk bool `json:"formatDisk"` - ToBeConverted bool `json:"toBeConverted"` - RelatedVms []RelatedVms `json:"relatedVms"` - XactiveDataStoreId string `json:"xactiveDataStoreId"` - ClusterSize int `json:"clusterSize"` - ScsiId string `json:"scsiId"` - SecondaryUUId string `json:"secondaryUuid"` - SecondaryVolumes string `json:"secondaryVolumes"` -} - -func (self *SDisk) GetName() string { - return self.Name -} - -func (self *SDisk) GetId() string { - return self.Id -} - -func (self *SDisk) GetGlobalId() string { - return self.GetId() -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SDisk) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SDisk) GetCacheMode() string { - return "none" -} - -func (self *SDisk) GetFsFormat() string { - return "" -} - -func (self *SDisk) GetIsNonPersistent() bool { - return false -} - -func (self *SDisk) GetDriver() string { - return "scsi" -} - -func (self *SDisk) GetDiskType() string { - if strings.HasSuffix(self.Name, "1") || strings.HasSuffix(self.Name, "0") { - return api.DISK_TYPE_SYS - } - return api.DISK_TYPE_DATA -} - -func (self *SDisk) GetDiskFormat() string { - return strings.ToLower(self.Format) -} - -func (self *SDisk) GetDiskSizeMB() int { - return int(self.Size * 1024) -} - -func (self *SDisk) GetIsAutoDelete() bool { - return true -} - -func (self *SDisk) GetMountpoint() string { - return "" -} - -func (self *SDisk) GetStatus() string { - return api.DISK_READY -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { - return self.region.ResizeDisk(self.Id, int(sizeMb/1024)) -} - -func (self *SDisk) GetTemplateId() string { - return "" -} - -func (self *SDisk) GetAccessPath() string { - return self.FileName -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.region.GetStorage(self.DataStoreId) -} - -func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - return []cloudprovider.ICloudSnapshot{}, nil -} - -func (self *SRegion) GetDisks(storageId string) ([]SDisk, error) { - ret := []SDisk{} - res := fmt.Sprintf("/storages/%s/volumes", storageId) - return ret, self.list(res, url.Values{}, &ret) -} - -func (self *SRegion) GetDisk(id string) (*SDisk, error) { - ret := &SDisk{region: self} - res := fmt.Sprintf("/volumes/%s", id) - return ret, self.get(res, nil, ret) -} - -func (self *SRegion) ResizeDisk(id string, sizeGb int) error { - disk, err := self.GetDisk(id) - if err != nil { - return errors.Wrapf(err, "GetDisk(%s)", id) - } - body := map[string]interface{}{ - "size": sizeGb, - "name": disk.Name, - "bootable": disk.Bootable, - "volumePolicy": disk.VolumePolicy, - "dataStoreType": disk.DataStoreType, - } - return self.put("/volumes/"+disk.Id, nil, jsonutils.Marshal(body), nil) -} - -func (self *SRegion) CreateDisk(name, storageId string, sizeGb int) (*SDisk, error) { - body := map[string]interface{}{ - "dataStoreId": storageId, - "format": "RAW", - "name": name, - "replicate": 1, - "size": sizeGb, - "volumePolicy": "THIN", - } - resp, err := self.client.post("/volumes", jsonutils.Marshal(body)) - if err != nil { - return nil, err - } - taskId, err := resp.GetString("taskId") - if err != nil { - return nil, err - } - diskId, err := self.client.waitTask(taskId) - if err != nil { - return nil, errors.Wrapf(err, "waitTask(%s)", taskId) - } - return self.GetDisk(diskId) -} diff --git a/pkg/multicloud/incloudsphere/doc.go b/pkg/multicloud/incloudsphere/doc.go deleted file mode 100644 index 4da76cc844..0000000000 --- a/pkg/multicloud/incloudsphere/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere // import "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" diff --git a/pkg/multicloud/incloudsphere/host.go b/pkg/multicloud/incloudsphere/host.go deleted file mode 100644 index 446328516a..0000000000 --- a/pkg/multicloud/incloudsphere/host.go +++ /dev/null @@ -1,452 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "fmt" - "net" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SHost struct { - multicloud.SHostBase - multicloud.InCloudSphereTags - zone *SZone - - Id string `json:"id"` - IP string `json:"ip"` - SwitchUplinkPortDto string `json:"switchUplinkPortDto"` - UplinkTopoDto string `json:"uplinkTopoDto"` - Pnics string `json:"pnics"` - Disks string `json:"disks"` - Name string `json:"name"` - HostName string `json:"hostName"` - NodeVersion string `json:"nodeVersion"` - Password string `json:"password"` - DataCenterId string `json:"dataCenterId"` - DataCenterName string `json:"dataCenterName"` - ClusterName string `json:"clusterName"` - ClusterId string `json:"clusterId"` - Status string `json:"status"` - CPUSocket int64 `json:"cpuSocket"` - CPUCorePerSocket int64 `json:"cpuCorePerSocket"` - CPUThreadPerCore int64 `json:"cpuThreadPerCore"` - LogicCPUNum int64 `json:"logicCpuNum"` - LogicalProcessor int64 `json:"logicalProcessor"` - CPUFrequency float64 `json:"cpuFrequency"` - CPUUsage float64 `json:"cpuUsage"` - CPUTotalHz int64 `json:"cpuTotalHz"` - FreeCPU int64 `json:"freeCpu"` - UsedCPU int64 `json:"usedCpu"` - TotalMem float64 `json:"totalMem"` - LogicTotalMem int64 `json:"logicTotalMem"` - MemoryUsage float64 `json:"memoryUsage"` - FreeMemory int64 `json:"freeMemory"` - UsedMemory int64 `json:"usedMemory"` - LogicUsedMemory int64 `json:"logicUsedMemory"` - LogicFreeMemory int64 `json:"logicFreeMemory"` - PnicNum int64 `json:"pnicNum"` - NormalRunTime int64 `json:"normalRunTime"` - Model string `json:"model"` - CPUType string `json:"cpuType"` - VTDegree int64 `json:"vtDegree"` - Powerstate string `json:"powerstate"` - HostBmcDto string `json:"hostBmcDto"` - MountPath string `json:"mountPath"` - MonMountState string `json:"monMountState"` - CPUModel string `json:"cpuModel"` - NetworkDtos string `json:"networkDtos"` - PortIP string `json:"portIp"` - Monstatus bool `json:"monstatus"` - HostIqn string `json:"hostIqn"` - VxlanPortDto string `json:"vxlanPortDto"` - SDNUpLinks string `json:"sdnUpLinks"` - AllPNicsCount int64 `json:"allPNicsCount"` - AvailablePNicsCount int64 `json:"availablePNicsCount"` - CfsDomainStatus string `json:"cfsDomainStatus"` - SerialNumber string `json:"serialNumber"` - Manufacturer string `json:"manufacturer"` - IndicatorStatus string `json:"indicatorStatus"` - EntryTemperature string `json:"entryTemperature"` - MulticastEnabled bool `json:"multicastEnabled"` - BroadcastLimitEnabled bool `json:"broadcastLimitEnabled"` - Pcies string `json:"pcies"` - VgpuEnable bool `json:"vgpuEnable"` - SSHEnable bool `json:"sshEnable"` - SpecialFailover bool `json:"specialFailover"` - VswitchDtos string `json:"vswitchDtos"` - HotfixVersion string `json:"hotfixVersion"` - VMMigBandWidth string `json:"vmMigBandWidth"` - VMMigBandWidthFlag bool `json:"vmMigBandWidthFlag"` - DpdkEnabled bool `json:"dpdkEnabled"` - HugePageTotal int64 `json:"hugePageTotal"` - HugePageUsed int64 `json:"hugePageUsed"` - HugePageFree int64 `json:"hugePageFree"` - StorageUsage int64 `json:"storageUsage"` - NodeForm string `json:"nodeForm"` - CPUArchType string `json:"cpuArchType"` - LogPartitionSize int64 `json:"logPartitionSize"` - RootPartitionSize int64 `json:"rootPartitionSize"` - Cpuflags string `json:"cpuflags"` -} - -func (self *SHost) GetId() string { - return self.Id -} - -func (self *SHost) GetGlobalId() string { - return self.Id -} - -func (self *SHost) GetName() string { - return self.HostName -} - -func (self *SHost) GetEnabled() bool { - return true -} - -func (self *SHost) GetHostStatus() string { - return api.HOST_ONLINE -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) GetAccessIp() string { - return self.Name -} - -func (self *SHost) GetAccessMac() string { - return "" -} - -func (self *SHost) GetSysInfo() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (self *SHost) GetSN() string { - return self.SerialNumber -} - -func (self *SHost) GetCpuCount() int { - return int(self.CPUCorePerSocket) -} - -func (self *SHost) GetNodeCount() int8 { - return int8(self.CPUSocket) -} - -func (self *SHost) GetCpuDesc() string { - return self.CPUType -} - -func (self *SHost) GetCpuMhz() int { - return int(self.CPUFrequency * 1024) -} - -func (self *SHost) GetCpuCmtbound() float32 { - return 1 -} - -func (self *SHost) GetMemSizeMB() int { - return int(self.TotalMem) -} - -func (self *SHost) GetMemCmtbound() float32 { - return 1 -} - -func (self *SHost) GetReservedMemoryMb() int { - return 0 -} - -func (self *SHost) GetStorageSizeMB() int { - return 0 -} - -func (self *SHost) GetStorageType() string { - return api.STORAGE_LOCAL -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_INCLOUD_SPHERE -} - -func (self *SHost) GetIsMaintenance() bool { - return false -} - -func (self *SHost) GetVersion() string { - return self.NodeVersion -} - -func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - storages, err := self.zone.region.GetImageStorages(self.zone.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetImageStorages") - } - var image *SImage = nil - storageCache := &SStoragecache{zone: self.zone} - for i := range storages { - images, err := self.zone.region.GetImageList(storages[i].Id) - if err != nil { - return nil, err - } - for j := range images { - images[j].cache = storageCache - if images[j].GetGlobalId() == opts.ExternalImageId { - image = &images[j] - break - } - } - } - if image == nil { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, opts.ExternalImageId) - } - format := "RAW" - if strings.HasSuffix(opts.ExternalImageId, "qcow2") { - format = "QCOW2" - } - sizeGb := float64((image.GetSizeByte() + 1024/2) / 1024 / 1024 / 1024) - disks := []Disks{} - disks = append(disks, Disks{ - BusModel: "IDE", - ReadWriteModel: "NONE", - QueueNum: 1, - Volume: Volume{ - Bootable: true, - DataStoreId: opts.SysDisk.StorageExternalId, - Format: format, - Size: sizeGb, - VolumePolicy: "THIN", - VvSourceDto: VvSourceDto{ - FilePath: fmt.Sprintf("%s/%s", image.Path, image.Name), - SourceType: "IMAGE_STORAGE", - FtpServerHost: FtpServerHost{ - Id: image.ServerID, - Ip: image.FTPServer, - }, - }, - }, - }) - for i := range opts.DataDisks { - disks = append(disks, Disks{ - BusModel: "IDE", - ReadWriteModel: "NONE", - QueueNum: 1, - Volume: Volume{ - Bootable: false, - DataStoreId: opts.DataDisks[i].StorageExternalId, - Format: "RAW", - Size: float64(opts.DataDisks[i].SizeGB), - VolumePolicy: "THIN", - }, - }) - } - imageTree, err := self.zone.region.GetImageTrees() - if err != nil { - return nil, errors.Wrapf(err, "GetImageTrees") - } - guestLabel, guestosType := "CentOS 7.9(2009) 64bit", "CentOS" - for i := range imageTree { - images := imageTree[i].ToList() - for j := range images { - if images[j].IsEquals(image.Name) { - guestLabel = images[j].Model - guestosType = images[j].OsDist - break - } - } - } - nic := SInstanceNic{ - AutoGenerated: true, - DeviceId: opts.ExternalNetworkId, - DeviceType: "NETWORK", - Model: "E1000", - Queues: 1, - } - network, err := self.zone.region.GetNetwork(opts.ExternalNetworkId) - if err != nil { - return nil, errors.Wrapf(err, "GetNetwork") - } - if network.DhcpEnabled { - nic.Dhcp = true - nic.DhcpEnabled = true - nic.DhcpIP = opts.IpAddr - } else if len(opts.IpAddr) > 0 { - nic.IP = opts.IpAddr - mask := net.CIDRMask(int(network.GetIpMask()), 32) - nic.Netmask = fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]) - nic.Gateway = network.GetGateway() - if len(nic.Gateway) == 0 { - info := strings.Split(opts.IpAddr, ".") - if len(info) == 4 { - info[3] = "1" - nic.Gateway = strings.Join(info, ".") - } - } - } - body := map[string]interface{}{ - "boot": "HD", - "bootMode": "BIOS", - "clockModel": "LOCALTIME", - "cpuBindType": "NOBIND", - "cpuCore": opts.Cpu, - "cpuHotplugEnabled": false, - "cpuLimit": -1, - "cpuModelType": "SELF_ADAPTING", - "cpuNum": opts.Cpu, - "cpuReservation": 0, - "cpuShares": 1024, - "cpuSocket": 1, - "dataCenterId": self.zone.Id, - "dataStoreId": opts.SysDisk.StorageExternalId, - "deacription": opts.Description, - "disks": disks, - "enableHugeMemPage": false, - "enableReplicate": false, - "graphicsCardMemory": 16384, - "graphicsCardModel": "VGA", - "guestosLabel": guestLabel, - "guestosType": guestosType, - "hostBinded": false, - "hostId": self.Id, - "maxCpuNum": 128, - "maxMemory": 4194304, - "memory": opts.MemoryMB, - "memoryShow": 4, - "memoryUnit": "GB", - "name": opts.Name, - "nics": []SInstanceNic{ - nic, - }, - "panickPolicy": "NO_ACTION", - "replicate": 1, - "socketLimit": 24, - "startPriority": "DEFAULT", - "supportCpuHotPlug": true, - "supportMemHotPlug": true, - "supportUefiBootMode": true, - "vcpuPin": "all", - "version": "V2", - } - resp, err := self.zone.region.post("/vms", jsonutils.Marshal(body)) - if err != nil { - return nil, err - } - taskId, err := resp.GetString("taskId") - if err != nil { - return nil, errors.Wrapf(err, "taskId") - } - vmId, err := self.zone.region.client.waitTask(taskId) - if err != nil { - return nil, err - } - vm, err := self.zone.region.GetInstance(vmId) - if err != nil { - return nil, err - } - vm.host = self - return vm, nil -} - -func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms, err := self.zone.region.GetInstances(self.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetInstances") - } - ret := []cloudprovider.ICloudVM{} - for i := range vms { - vms[i].host = self - ret = append(ret, &vms[i]) - } - return ret, nil -} - -func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.zone.region.GetInstance(id) - if err != nil { - return nil, err - } - if vm.HostId != self.Id { - return nil, cloudprovider.ErrNotFound - } - vm.host = self - return vm, nil -} - -func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - wires, err := self.zone.region.GetWiresByDs(self.DataCenterId) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudWire{} - for i := range wires { - wires[i].region = self.zone.region - ret = append(ret, &wires[i]) - } - return ret, nil -} - -func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := self.zone.region.GetStoragesByHost(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStorage{} - for i := range storages { - storages[i].zone = self.zone - ret = append(ret, &storages[i]) - } - return ret, nil -} - -func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storage, err := self.zone.region.GetStorage(id) - if err != nil { - return nil, err - } - storage.zone = self.zone - if storage.HostId != self.Id { - return nil, cloudprovider.ErrNotFound - } - return storage, nil -} - -func (self *SRegion) GetHosts(dcId string) ([]SHost, error) { - hosts := []SHost{} - res := fmt.Sprintf("/datacenters/%s/hosts", dcId) - return hosts, self.list(res, url.Values{}, &hosts) -} - -func (self *SRegion) GetHost(id string) (*SHost, error) { - ret := &SHost{} - res := fmt.Sprintf("/hosts/%s", id) - return ret, self.get(res, url.Values{}, ret) -} diff --git a/pkg/multicloud/incloudsphere/image.go b/pkg/multicloud/incloudsphere/image.go deleted file mode 100644 index 1edc007a47..0000000000 --- a/pkg/multicloud/incloudsphere/image.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "context" - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type SImage struct { - multicloud.SImageBase - multicloud.InCloudSphereTags - cache *SStoragecache - - imageInfo *imagetools.ImageInfo - - Name string `json:"name"` - FileSize int64 `json:"fileSize"` - RealSize int64 `json:"realSize"` - SourceType string `json:"sourceType"` - Format string `json:"format"` - FileType string `json:"fileType"` - Size int64 `json:"size"` - Date string `json:"date"` - Path string `json:"path"` - FTPServer string `json:"ftpServer"` - DataStoreID string `json:"dataStoreId"` - DataStoreName string `json:"dataStoreName"` - ServerID string `json:"serverId"` - Md5 string `json:"md5"` -} - -func (self *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (self *SImage) GetId() string { - return fmt.Sprintf("%s/%s/%s", self.cache.zone.Id, self.Path, self.Name) -} - -func (self *SImage) GetName() string { - return self.Name -} - -func (self *SImage) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SImage) GetGlobalId() string { - return self.GetId() -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.cache -} - -func (self *SImage) GetStatus() string { - return api.CACHED_IMAGE_STATUS_ACTIVE -} - -func (self *SImage) GetImageStatus() string { - return cloudprovider.IMAGE_STATUS_ACTIVE -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - return cloudprovider.ImageTypeSystem -} - -func (self *SImage) GetSizeByte() int64 { - return self.FileSize -} - -func (i *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(i.getNormalizedImageInfo().OsType) -} - -func (i *SImage) GetOsDist() string { - return i.getNormalizedImageInfo().OsDistro -} - -func (i *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if i.imageInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(i.Name, "", "", "", "") - i.imageInfo = &imgInfo - } - return i.imageInfo -} - -func (i *SImage) GetFullOsName() string { - return i.Name -} - -func (i *SImage) GetOsVersion() string { - return i.getNormalizedImageInfo().OsVersion -} - -func (i *SImage) GetOsArch() string { - return i.getNormalizedImageInfo().OsArch -} - -func (i *SImage) GetOsLang() string { - return i.getNormalizedImageInfo().OsLang -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - if self.GetOsType() == "windows" { - return 40 - } - return 30 -} - -func (self *SImage) GetImageFormat() string { - return self.Format -} - -func (i *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(i.getNormalizedImageInfo().OsBios) -} - -type SImageInfo struct { - OsType string - OsDist string - Model string - SocketLimit int - SupportCpuHotPlug bool - SupportMemHotPlug bool - SupportDiskHotPlug bool - SupportUefiBootMode bool -} - -func (self *SImageInfo) IsEquals(name string) bool { - model := imagetools.NormalizeImageInfo(self.Model, "", "", "", "") - image := imagetools.NormalizeImageInfo(name, "", "", "", "") - return model.OsDistro == image.OsDistro && model.OsVersion == image.OsVersion -} - -type SImageTree struct { - Id string - Name string - Children []struct { - Id string - Name string - Children []struct { - Id string - Name string - Object SImageInfo - } - } -} - -func (self *SImageTree) ToList() []SImageInfo { - ret := []SImageInfo{} - for i := range self.Children { - for j := range self.Children[i].Children { - self.Children[i].Children[j].Object.OsType = self.Name - self.Children[i].Children[j].Object.OsDist = self.Children[i].Name - ret = append(ret, self.Children[i].Children[j].Object) - } - } - return ret -} - -func (self *SRegion) GetImageTrees() ([]SImageTree, error) { - ret := []SImageTree{} - return ret, self.get("/vms/ostrees", nil, &ret) -} diff --git a/pkg/multicloud/incloudsphere/instance.go b/pkg/multicloud/incloudsphere/instance.go deleted file mode 100644 index 5526df8987..0000000000 --- a/pkg/multicloud/incloudsphere/instance.go +++ /dev/null @@ -1,613 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "context" - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type Cdrom struct { - Path string `json:"path"` - Type string `json:"type"` - Connected bool `json:"connected"` - StartConnected bool `json:"startConnected"` - CifsDto string `json:"cifsDto"` - DataStore struct { - Id string `json:"id"` - Name string `json:"name"` - } `json:"dataStore"` -} - -type Floppy struct { - Path string `json:"path"` - DataStore string `json:"dataStore"` - VfdType string `json:"vfdType"` -} - -type FtpServerHost struct { - Id string `json:"id"` - Ip string `json:"ip"` -} - -type VvSourceDto struct { - SourceType string `json:"sourceType"` - FilePath string `json:"filePath"` - Name string `json:"name"` - FtpServerHost FtpServerHost `json:"ftpServerHost"` -} - -type Volume struct { - Id string `json:"id"` - UUID string `json:"uuid"` - Size float64 `json:"size"` - RealSize float64 `json:"realSize"` - Name string `json:"name"` - FileName string `json:"fileName"` - Offset int `json:"offset"` - Shared bool `json:"shared"` - DeleteModel string `json:"deleteModel"` - VolumePolicy string `json:"volumePolicy"` - Format string `json:"format"` - BlockDeviceId string `json:"blockDeviceId"` - DiskType string `json:"diskType"` - DataStoreId string `json:"dataStoreId"` - DataStoreName string `json:"dataStoreName"` - DataStoreSize float64 `json:"dataStoreSize"` - FreeStorage float64 `json:"freeStorage"` - DataStoreType string `json:"dataStoreType"` - DataStoreReplicate int `json:"dataStoreReplicate"` - VMName string `json:"vmName"` - VMStatus string `json:"vmStatus"` - Type string `json:"type"` - Description string `json:"description"` - Bootable bool `json:"bootable"` - VolumeStatus string `json:"volumeStatus"` - MountedHostIds string `json:"mountedHostIds"` - Md5 string `json:"md5"` - DataSize int `json:"dataSize"` - OpenStackId string `json:"openStackId"` - VvSourceDto VvSourceDto `json:"vvSourceDto"` - FormatDisk bool `json:"formatDisk"` - ToBeConverted bool `json:"toBeConverted"` - RelatedVms string `json:"relatedVms"` - XactiveDataStoreId string `json:"xactiveDataStoreId"` - ClusterSize int `json:"clusterSize"` - ScsiId string `json:"scsiId"` - SecondaryUUID string `json:"secondaryUuid"` - SecondaryVolumes []struct{} `json:"secondaryVolumes"` -} - -type Disks struct { - Id string `json:"id"` - Label string `json:"label"` - ScsiId string `json:"scsiId"` - Enabled bool `json:"enabled"` - WriteBps int `json:"writeBps"` - ReadBps int `json:"readBps"` - TotalBps int `json:"totalBps"` - TotalIops int `json:"totalIops"` - WriteIops int `json:"writeIops"` - ReadIops int `json:"readIops"` - Volume Volume `json:"volume"` - BusModel string `json:"busModel"` - Usage float64 `json:"usage"` - MonReadIops float64 `json:"monReadIops"` - MonWriteIops float64 `json:"monWriteIops"` - ReadThroughput float64 `json:"readThroughput"` - WriteThroughput float64 `json:"writeThroughput"` - ReadWriteModel string `json:"readWriteModel"` - EnableNativeIO bool `json:"enableNativeIO"` - EnableKernelIO bool `json:"enableKernelIO"` - L2CacheSize int `json:"l2CacheSize"` - QueueNum int `json:"queueNum"` -} - -type CdpInfo struct { - CdpBackupDatastoreId string `json:"cdpBackupDatastoreId"` - BackupDataStoreName string `json:"backupDataStoreName"` - StartTime string `json:"startTime"` - EndTime string `json:"endTime"` - EnableCDP bool `json:"enableCDP"` - CdpAvgWriteMBps int `json:"cdpAvgWriteMBps"` - CdpRemainTimes int `json:"cdpRemainTimes"` - CdpLogSpaceSize int `json:"cdpLogSpaceSize"` - IntervalTime int `json:"intervalTime"` -} - -type GuestOSAuthInfo struct { - UserName string `json:"userName"` - UserPwd string `json:"userPwd"` -} - -type SInstance struct { - multicloud.SInstanceBase - multicloud.InCloudSphereTags - - host *SHost - - osInfo *imagetools.ImageInfo - - Id string `json:"id"` - CustomVMId string `json:"customVmId"` - Name string `json:"name"` - State string `json:"state"` - Status string `json:"status"` - HostId string `json:"hostId"` - HostName string `json:"hostName"` - HostIP string `json:"hostIp"` - HostStatus string `json:"hostStatus"` - HostMemory int64 `json:"hostMemory"` - DataCenterId string `json:"dataCenterId"` - HaEnabled bool `json:"haEnabled"` - RouterFlag bool `json:"routerFlag"` - Migratable bool `json:"migratable"` - HostBinded bool `json:"hostBinded"` - ToolsInstalled bool `json:"toolsInstalled"` - ToolsVersion string `json:"toolsVersion"` - ToolsType string `json:"toolsType"` - ToolsVersionStatus string `json:"toolsVersionStatus"` - ToolsRunningStatus string `json:"toolsRunningStatus"` - ToolsNeedUpdate bool `json:"toolsNeedUpdate"` - Description string `json:"description"` - HaMaxLimit int64 `json:"haMaxLimit"` - Template bool `json:"template"` - Initialized bool `json:"initialized"` - GuestosLabel string `json:"guestosLabel"` - GuestosType string `json:"guestosType"` - GuestOSInfo struct { - Model string `json:"model"` - SocketLimit int `json:"socketLimit"` - SupportCpuHotPlug bool `json:"supportCpuHotPlug"` - SupportDiskHotPlug bool `json:"supportDiskHotPlug"` - SupportMemHotPlug bool `json:"supportMemHotPlug"` - SupportUefiBootMode bool `json:"supportUefiBootMode"` - } `json:"guestOsInfo"` - InnerName string `json:"innerName"` - UUId string `json:"uuid"` - MaxMemory int64 `json:"maxMemory"` - Memory int `json:"memory"` - MemoryUsage int64 `json:"memoryUsage"` - MemHotplugEnabled bool `json:"memHotplugEnabled"` - EnableHugeMemPage bool `json:"enableHugeMemPage"` - CPUNum int `json:"cpuNum"` - CPUSocket int `json:"cpuSocket"` - CPUCore int64 `json:"cpuCore"` - CPUUsage int64 `json:"cpuUsage"` - MaxCPUNum int64 `json:"maxCpuNum"` - CPUHotplugEnabled bool `json:"cpuHotplugEnabled"` - CPUModelType string `json:"cpuModelType"` - CPUModelEnabled bool `json:"cpuModelEnabled"` - RunningTime int64 `json:"runningTime"` - Boot string `json:"boot"` - BootMode string `json:"bootMode"` - SplashTime int64 `json:"splashTime"` - StoragePriority int64 `json:"storagePriority"` - USB string `json:"usb"` - - //Usbs []interface{} `json:"usbs"` - Cdrom Cdrom `json:"cdrom"` - Floppy Floppy `json:"floppy"` - Disks []Disks `json:"disks"` - Nics []SInstanceNic `json:"nics"` - - //Gpus []interface{} `json:"gpus"` - //VMPcis []interface{} `json:"vmPcis"` - ConfigLocation string `json:"configLocation"` - HotplugEnabled bool `json:"hotplugEnabled"` - VNCPort int64 `json:"vncPort"` - VNCPasswd string `json:"vncPasswd"` - VNCSharePolicy string `json:"vncSharePolicy"` - CPUBindType string `json:"cpuBindType"` - VcpuPin string `json:"vcpuPin"` - VcpuPins []string `json:"vcpuPins"` - CPUShares int64 `json:"cpuShares"` - PanickPolicy string `json:"panickPolicy"` - DataStoreId string `json:"dataStoreId"` - SdsdomainId string `json:"sdsdomainId"` - ClockModel string `json:"clockModel"` - CPULimit int64 `json:"cpuLimit"` - MemShares int64 `json:"memShares"` - CPUReservation int64 `json:"cpuReservation"` - MemReservation int64 `json:"memReservation"` - LastBackup string `json:"lastBackup"` - VMType string `json:"vmType"` - SystemVMType string `json:"systemVmType"` - MemBalloonEnabled bool `json:"memBalloonEnabled"` - Completed bool `json:"completed"` - GraphicsCardModel string `json:"graphicsCardModel"` - GraphicsCardMemory int64 `json:"graphicsCardMemory"` - GraphicsCards string `json:"graphicsCards"` - VMHostName string `json:"vmHostName"` - DiskTotalSize int64 `json:"diskTotalSize"` - DiskUsedSize float64 `json:"diskUsedSize"` - DiskUsage float64 `json:"diskUsage"` - StartPriority string `json:"startPriority"` - OwnerName string `json:"ownerName"` - Version string `json:"version"` - EnableReplicate bool `json:"enableReplicate"` - ReplicationDatastoreId string `json:"replicationDatastoreId"` - ReplicationDatastoreName string `json:"replicationDatastoreName"` - RecoveryFlag bool `json:"recoveryFlag"` - SpiceUSBNum int64 `json:"spiceUsbNum"` - CDPInfo CdpInfo `json:"cdpInfo"` - GuestOSAuthInfo GuestOSAuthInfo `json:"guestOSAuthInfo"` - AwareNUMAEnabled bool `json:"awareNumaEnabled"` - DrxEnabled bool `json:"drxEnabled"` - SecretLevel string `json:"secretLevel"` - //VmfpgaDevs []interface{} `json:"vmfpgaDevs"` -} - -func (self *SInstance) GetName() string { - return self.Name -} - -func (self *SInstance) GetId() string { - return self.Id -} - -func (self *SInstance) GetGlobalId() string { - return self.GetId() -} - -func (self *SInstance) Refresh() error { - ins, err := self.host.zone.region.GetInstance(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, ins) -} - -func (self *SInstance) AssignSecurityGroup(id string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return self.host.zone.region.AttachDisk(self.Id, diskId) -} - -func (self *SInstance) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error { - return self.host.zone.region.ChangeConfig(self.Id, opts.Cpu, opts.MemoryMB) -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - return self.host.zone.region.DeleteVM(self.Id) -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return self.host.zone.region.ResetVmPassword(self.Id, username, password) -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return self.host.zone.region.DetachDisk(self.Id, diskId) -} - -func (self *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(self.BootMode) -} - -func (self *SInstance) GetBootOrder() string { - return strings.ToLower(self.Boot) -} - -func (self *SInstance) GetError() error { - return nil -} - -func (self *SInstance) GetHostname() string { - return self.HostName -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_INCLOUD_SPHERE -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - ret := []cloudprovider.ICloudDisk{} - for i := range self.Disks { - disk, err := self.host.zone.region.GetDisk(self.Disks[i].Volume.Id) - if err != nil { - return nil, err - } - ret = append(ret, disk) - } - return ret, nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - ret := []cloudprovider.ICloudNic{} - for i := range self.Nics { - self.Nics[i].ins = self - ret = append(ret, &self.Nics[i]) - } - return ret, nil -} - -func (self *SInstance) GetInstanceType() string { - return fmt.Sprintf("ecs.g1.c%dm%d", self.GetVcpuCount(), self.GetVmemSizeMB()/1024) -} - -func (self *SInstance) GetMachine() string { - return "" -} - -/* -PENDING 开启准备中 -STARTING 开启或恢复中 -STARTED 开启的 -PAUSING 暂停中 -PAUSED 暂停的 -RESTARTING 重启中 -STOPPING 关机中 -STOPPED 关闭的 -HOT_SAVING 开机快照中 -COLD_SAVING 关机快照中 -PRE_MIGRATE 迁移准备中 -HOT_MIGRATING 热迁移中 -COLD_MIGRATING 冷迁移中 -REVERTING 恢复快照中 -EXPORTING 导出中 -IMPORTING 导入中 -COLD_BACKUPING 关机备份中 -HOT_BACKUPING 开机备份中 -COLD_MODIFYING 冷配置中 -HOT_MODIFYING 热配置中 -COLD_COPING 关机复制中 -*/ - -func (self *SInstance) GetStatus() string { - switch strings.ToUpper(self.Status) { - case "COLD_COPING", "COLD_BACKUPING", "COLD_SAVING", "STOPPED": - return api.VM_READY - case "PENDING", "STARTING": - return api.VM_START_START - case "STARTED", "HOT_SAVING", "HOT_BACKUPING": - return api.VM_RUNNING - case "PAUSING", "RESTARTING", "STOPPING": - return api.VM_START_STOP - case "REVERTING", "EXPORTING", "IMPORTING", "COLD_MODIFYING", "HOT_MODIFYING": - return api.VM_RESUMING - case "PRE_MIGRATE", "HOT_MIGRATING", "COLD_MIGRATING": - return api.VM_MIGRATING - } - return strings.ToLower(self.Status) -} - -func (i *SInstance) GetFullOsName() string { - return i.GuestOSInfo.Model -} - -func (i *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(i.GuestosType) -} - -func (i *SInstance) GetOsArch() string { - return i.GetIHost().GetCpuArchitecture() -} - -func (i *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { - if i.osInfo == nil { - osInfo := imagetools.NormalizeImageInfo(i.GuestOSInfo.Model, "", "", "", "") - i.osInfo = &osInfo - } - return i.osInfo -} - -func (i *SInstance) GetOsDist() string { - return i.getNormalizedOsInfo().OsDistro -} - -func (i *SInstance) GetOsVersion() string { - return i.getNormalizedOsInfo().OsVersion -} - -func (i *SInstance) GetOsLang() string { - return i.getNormalizedOsInfo().OsLang -} - -func (self *SInstance) GetProjectId() string { - return "" -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - ret := &cloudprovider.ServerVncOutput{ - Protocol: "vnc", - Host: self.host.Name, - Port: self.VNCPort, - Id: self.Id, - Password: "1q@W3e$R", - } - return ret, nil -} - -func (self *SInstance) GetVcpuCount() int { - return int(self.CPUNum) -} - -func (self *SInstance) GetVmemSizeMB() int { - return int(self.Memory) -} - -func (self *SInstance) GetVga() string { - return "std" -} - -func (self *SInstance) GetVdi() string { - return "vnc" -} - -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - return []string{}, nil -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) StartVM(ctx context.Context) error { - return self.host.zone.region.StartVm(self.Id, "", "") -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - if self.GetStatus() == api.VM_READY { - return nil - } - return self.host.zone.region.StopVm(self.Id) -} - -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetInstances(hostId string) ([]SInstance, error) { - ret := []SInstance{} - res := fmt.Sprintf("/hosts/%s/vms", hostId) - return ret, self.list(res, url.Values{}, &ret) -} - -func (self *SRegion) GetInstance(id string) (*SInstance, error) { - ret := &SInstance{} - res := fmt.Sprintf("/vms/%s", id) - return ret, self.get(res, nil, ret) -} - -func (self *SRegion) StartVm(id string, password, publicKey string) error { - res := fmt.Sprintf("/vms/%s", id) - params := url.Values{} - params.Set("action", "poweron") - if len(password) > 0 { - params.Set("os-passwd", password) - } - if len(publicKey) > 0 { - params.Set("publicKey", publicKey) - } - return self.put(res, params, nil, nil) -} - -func (self *SRegion) StopVm(id string) error { - res := fmt.Sprintf("/vms/%s", id) - params := url.Values{} - params.Set("action", "poweroff") - return self.put(res, params, nil, nil) -} - -func (self *SRegion) AttachDisk(vmId, diskId string) error { - disk, err := self.GetDisk(diskId) - if err != nil { - return errors.Wrapf(err, "GetDisk(%s)", diskId) - } - vm, err := self.GetInstance(vmId) - if err != nil { - return errors.Wrapf(err, "GetInstance(%s)", vmId) - } - vm.VNCPasswd = "" - diskInfo := Disks{ - BusModel: "VIRTIO", - ReadWriteModel: "NONE", - QueueNum: 1, - Volume: Volume{ - Id: disk.Id, - Size: disk.Size, - }, - } - vm.Disks = append(vm.Disks, diskInfo) - return self.put("/vms/"+vm.Id, nil, jsonutils.Marshal(vm), nil) -} - -func (self *SRegion) DetachDisk(vmId, diskId string) error { - vm, err := self.GetInstance(vmId) - if err != nil { - return errors.Wrapf(err, "GetInstance(%s)", vmId) - } - vm.VNCPasswd = "" - disks := []Disks{} - for i := 0; i < len(vm.Disks); i++ { - if vm.Disks[i].Volume.Id == diskId { - continue - } - disks = append(disks, vm.Disks[i]) - } - vm.Disks = disks - return self.put("/vms/"+vm.Id, nil, jsonutils.Marshal(vm), nil) -} - -func (self *SRegion) ChangeConfig(vmId string, cpu int, memMb int) error { - vm, err := self.GetInstance(vmId) - if err != nil { - return errors.Wrapf(err, "GetInstance(%s)", vmId) - } - vm.VNCPasswd = "" - changed := false - if cpu > 0 { - vm.CPUCore = 1 - vm.CPUNum = cpu - vm.CPUSocket = cpu - changed = true - } - if memMb > 0 { - vm.Memory = memMb - changed = true - } - if !changed { - return nil - } - return self.put("/vms/"+vm.Id, nil, jsonutils.Marshal(vm), nil) -} - -func (self *SRegion) ResetVmPassword(vmId string, username, password string) error { - params := url.Values{} - params.Set("action", "updateOsAuth") - body := map[string]interface{}{ - "userName": username, - "userPwd": password, - } - return self.put("/vms/"+vmId, params, jsonutils.Marshal(body), nil) -} - -func (self *SRegion) DeleteVM(vmId string) error { - params := url.Values{} - params.Set("type", "force") - return self.del("/vms/"+vmId, params, nil) -} diff --git a/pkg/multicloud/incloudsphere/network.go b/pkg/multicloud/incloudsphere/network.go deleted file mode 100644 index 376789336e..0000000000 --- a/pkg/multicloud/incloudsphere/network.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.InCloudSphereTags - - wire *SWire - - Id string `json:"id"` - Name string `json:"name"` - ResourceId string `json:"resourceId"` - Vlan int `json:"vlan"` - VlanFlag bool `json:"vlanFlag"` - Mtu string `json:"mtu"` - Type string `json:"type"` - VswitchDto SWire `json:"vswitchDto"` - //PortDtos []string `json:"portDtos"` - VMDtos string `json:"vmDtos"` - VnicDtos string `json:"vnicDtos"` - Vmcount int `json:"vmcount"` - Vniccount int `json:"vniccount"` - ConnectMode string `json:"connectMode"` - // 约定未开启dhcp时,描述信息里面放置/ - Description string `json:"description"` - UplinkRate int `json:"uplinkRate"` - UplinkBurst int `json:"uplinkBurst"` - DownlinkRate int `json:"downlinkRate"` - DownlinkBurst int `json:"downlinkBurst"` - QosEnabled bool `json:"qosEnabled"` - DataServiceType string `json:"dataServiceType"` - UserVlan string `json:"userVlan"` - TpidType string `json:"tpidType"` - PermitDel bool `json:"permitDel"` - Cidr string `json:"cidr"` - Gateway string `json:"gateway"` - DhcpEnabled bool `json:"dhcpEnabled"` - DNS string `json:"dns"` - DataCenterDto SZone `json:"dataCenterDto"` - NetworkTopoly bool `json:"networkTopoly"` -} - -func (self *SNetwork) GetCidr() string { - if len(self.Cidr) > 0 { - return self.Cidr - } - _, err := netutils.NewIPV4Prefix(self.Description) - if err == nil { - return self.Description - } - return "0.0.0.0/0" -} - -func (self *SNetwork) GetName() string { - return self.Name -} - -func (self *SNetwork) GetId() string { - return self.Id -} - -func (self *SNetwork) GetGlobalId() string { - return self.GetId() -} - -func (self *SNetwork) Refresh() error { - ret, err := self.wire.region.GetNetwork(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, ret) -} - -func (self *SNetwork) Delete() error { - return cloudprovider.ErrNotFound -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (self *SNetwork) GetGateway() string { - if len(self.Gateway) > 0 { - return self.Gateway - } - if len(self.Description) > 0 && strings.Contains(self.Description, "/") { - info := strings.Split(self.Description, "/") - ip, err := netutils.NewIPV4Addr(info[0]) - if err == nil { - return ip.String() - } - } - return self.Gateway -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetIpStart() string { - _range, err := netutils.NewIPV4Prefix(self.GetCidr()) - if err != nil { - return "" - } - return _range.ToIPRange().StartIp().StepUp().String() -} - -func (self *SNetwork) GetIpEnd() string { - _range, err := netutils.NewIPV4Prefix(self.GetCidr()) - if err != nil { - return "" - } - return _range.ToIPRange().EndIp().StepDown().String() -} - -func (self *SNetwork) Contains(_ip string) bool { - start, _ := netutils.NewIPV4Addr(self.GetIpStart()) - end, _ := netutils.NewIPV4Addr(self.GetIpEnd()) - ip, _ := netutils.NewIPV4Addr(_ip) - return netutils.NewIPV4AddrRange(start, end).Contains(ip) -} - -func (self *SNetwork) GetIpMask() int8 { - pref, err := netutils.NewIPV4Prefix(self.GetCidr()) - if err != nil { - return 0 - } - return pref.MaskLen -} - -func (self *SNetwork) GetProjectId() string { - return "" -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetStatus() string { - return api.NETWORK_STATUS_AVAILABLE -} - -func (self *SRegion) GetNetworks(vsId string) ([]SNetwork, error) { - ret := []SNetwork{} - res := fmt.Sprintf("/vswitchs/%s/networks", vsId) - return ret, self.list(res, url.Values{}, &ret) -} - -func (self *SRegion) GetNetwork(id string) (*SNetwork, error) { - ret := &SNetwork{} - res := fmt.Sprintf("/networks/%s", id) - return ret, self.get(res, url.Values{}, ret) -} diff --git a/pkg/multicloud/incloudsphere/nic.go b/pkg/multicloud/incloudsphere/nic.go deleted file mode 100644 index bba4b95bee..0000000000 --- a/pkg/multicloud/incloudsphere/nic.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "strings" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - cloudprovider.DummyICloudNic - ins *SInstance - - Id string `json:"id"` - AutoGenerated bool `json:"autoGenerated"` - Name string `json:"name"` - NolocalName string `json:"nolocalName"` - InnerName string `json:"innerName"` - DevName string `json:"devName"` - IP string `json:"ip"` - Netmask string `json:"netmask"` - Gateway string `json:"gateway"` - Mac string `json:"mac"` - Model string `json:"model"` - DeviceId string `json:"deviceId"` - DeviceName string `json:"deviceName"` - DeviceType string `json:"deviceType"` - SwitchType string `json:"switchType"` - VswitchId string `json:"vswitchId"` - UplinkRate int `json:"uplinkRate"` - UplinkBurst int `json:"uplinkBurst"` - DownlinkRate int `json:"downlinkRate"` - DownlinkBurst int `json:"downlinkBurst"` - DownlinkQueue string `json:"downlinkQueue"` - Enable bool `json:"enable"` - Status string `json:"status"` - InboundRate float64 `json:"inboundRate"` - OutboundRate float64 `json:"outboundRate"` - ConnectStatus bool `json:"connectStatus"` - VMName string `json:"vmName"` - VMId string `json:"vmId"` - VMStatus string `json:"vmStatus"` - VMTemplate bool `json:"vmTemplate"` - NetworkName string `json:"networkName"` - NetworkVlan string `json:"networkVlan"` - VlanRange string `json:"vlanRange"` - NetworkId string `json:"networkId"` - NetworkType string `json:"networkType"` - HostIP string `json:"hostIp"` - HostStatus string `json:"hostStatus"` - HostId string `json:"hostId"` - DirectObjName string `json:"directObjName"` - TotalOctets float64 `json:"totalOctets"` - TotalDropped float64 `json:"totalDropped"` - TotalPackets float64 `json:"totalPackets"` - TotalBytes float64 `json:"totalBytes"` - TotalErrors float64 `json:"totalErrors"` - WriteOctets float64 `json:"writeOctets"` - WriteDropped float64 `json:"writeDropped"` - WritePackets float64 `json:"writePackets"` - WriteBytes float64 `json:"writeBytes"` - WriteErrors float64 `json:"writeErrors"` - ReadOctets float64 `json:"readOctets"` - ReadDropped float64 `json:"readDropped"` - ReadPackets float64 `json:"readPackets"` - ReadBytes float64 `json:"readBytes"` - ReadErrors float64 `json:"readErrors"` - SecurityGroups string `json:"securityGroups"` - AdvancedNetIP string `json:"advancedNetIp"` - PortId string `json:"portId"` - SdnVFId string `json:"sdnVFId"` - OpenstackId string `json:"openstackId"` - BindIPEnable bool `json:"bindIpEnable"` - BindIP string `json:"bindIp"` - PriorityEnabled bool `json:"priorityEnabled"` - NetPriority string `json:"netPriority"` - VMType string `json:"vmType"` - SystemVMType string `json:"systemVmType"` - Dhcp bool `json:"dhcp"` - DhcpIP string `json:"dhcpIp"` - DhcpEnabled bool `json:"dhcpEnabled"` - UsedDpdk bool `json:"usedDpdk"` - Queues int `json:"queues"` -} - -func (self *SInstanceNic) GetId() string { - return self.Id -} - -func (self *SInstanceNic) GetIP() string { - return self.IP -} - -func (self *SInstanceNic) GetMAC() string { - return self.Mac -} - -func (self *SInstanceNic) GetDriver() string { - return strings.ToLower(self.Model) -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return true -} - -func (self *SInstanceNic) GetSubAddress() ([]string, error) { - return []string{}, nil -} - -func (self *SInstanceNic) GetINetworkId() string { - return self.NetworkId -} - -func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/incloudsphere/provider/doc.go b/pkg/multicloud/incloudsphere/provider/doc.go deleted file mode 100644 index eabfd222dd..0000000000 --- a/pkg/multicloud/incloudsphere/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/incloudsphere/provider" diff --git a/pkg/multicloud/incloudsphere/provider/provider.go b/pkg/multicloud/incloudsphere/provider/provider.go deleted file mode 100644 index ffdf2deade..0000000000 --- a/pkg/multicloud/incloudsphere/provider/provider.go +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/regutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" -) - -type SInCloudSphereProviderFactory struct { - cloudprovider.SPrivateCloudBaseProviderFactory -} - -func (self *SInCloudSphereProviderFactory) GetId() string { - return incloudsphere.CLOUD_PROVIDER_INCLOUD_SPHERE -} - -func (self *SInCloudSphereProviderFactory) GetName() string { - return incloudsphere.CLOUD_PROVIDER_INCLOUD_SPHERE -} - -func (self *SInCloudSphereProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { - return fmt.Errorf("Changing %s bandwidth is not supported", incloudsphere.CLOUD_PROVIDER_INCLOUD_SPHERE) -} - -func (self *SInCloudSphereProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - if len(input.Host) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "host") - } - input.Host = strings.TrimPrefix(input.Host, "https://") - input.Host = strings.TrimPrefix(input.Host, "http://") - if !regutils.MatchIPAddr(input.Host) && !regutils.MatchDomainName(input.Host) { - return output, errors.Wrap(httperrors.ErrInputParameter, "host should be ip or domain name") - } - output.AccessUrl = input.Host - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - return output, nil -} - -func (self *SInCloudSphereProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func (self *SInCloudSphereProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - client, err := incloudsphere.NewSphereClient( - incloudsphere.NewSphereClientConfig( - cfg.URL, cfg.Account, cfg.Secret, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SInCloudSphereProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SInCloudSphereProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - return map[string]string{ - "INCLOUD_SPHERE_HOST": info.Url, - "INCLOUD_SPHERE_ACCESS_KEY_ID": info.Account, - "INCLOUD_SPHERE_ACCESS_KEY_SECRET": info.Secret, - }, nil -} - -func init() { - factory := SInCloudSphereProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SInCloudSphereProvider struct { - cloudprovider.SBaseProvider - client *incloudsphere.SphereClient -} - -func (self *SInCloudSphereProvider) GetSysInfo() (jsonutils.JSONObject, error) { - return jsonutils.NewDict(), nil -} - -func (self *SInCloudSphereProvider) GetVersion() string { - return "5.8" -} - -func (self *SInCloudSphereProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SInCloudSphereProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SInCloudSphereProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SInCloudSphereProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - regions := self.GetIRegions() - for i := range regions { - if regions[i].GetGlobalId() == id { - return regions[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SInCloudSphereProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SInCloudSphereProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return []cloudprovider.ICloudProject{}, nil -} - -func (self *SInCloudSphereProvider) GetStorageClasses(regionId string) []string { - return nil -} - -func (self *SInCloudSphereProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (self *SInCloudSphereProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (self *SInCloudSphereProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} diff --git a/pkg/multicloud/incloudsphere/region.go b/pkg/multicloud/incloudsphere/region.go deleted file mode 100644 index 044673dc45..0000000000 --- a/pkg/multicloud/incloudsphere/region.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "fmt" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - multicloud.SRegion - multicloud.SRegionEipBase - multicloud.SNoObjectStorageRegion - multicloud.SRegionLbBase - - client *SphereClient -} - -func (self *SRegion) GetClient() *SphereClient { - return self.client -} - -func (self *SRegion) GetName() string { - return self.client.cpcfg.Name -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) - return table -} - -func (self *SRegion) GetId() string { - return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_INCLOUD_SPHERE, self.client.cpcfg.Id) -} - -func (self *SRegion) GetGlobalId() string { - return self.GetId() -} - -func (self *SRegion) GetProvider() string { - return CLOUD_PROVIDER_INCLOUD_SPHERE -} - -func (self *SRegion) GetCloudEnv() string { - return "" -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) Refresh() error { - return nil -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) CreateIVpc(conf *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SRegion) getVpc() *SVpc { - return &SVpc{region: self} -} - -func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - vpc := self.getVpc() - return []cloudprovider.ICloudVpc{vpc}, nil -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - vpcs, err := self.GetIVpcs() - if err != nil { - return nil, err - } - for i := range vpcs { - if vpcs[i].GetGlobalId() == id { - return vpcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - zone, err := self.GetZone(id) - if err != nil { - return nil, errors.Wrapf(err, "GetZone(%s)", id) - } - return zone, nil -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - zones, err := self.GetZones() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudZone{} - for i := range zones { - zones[i].region = self - ret = append(ret, &zones[i]) - } - return ret, nil -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.GetInstance(id) - if err != nil { - return nil, err - } - return vm, nil -} - -func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - host, err := self.GetHost(id) - if err != nil { - return nil, err - } - zone, err := self.GetZone(host.DataCenterId) - if err != nil { - return nil, err - } - host.zone = zone - return host, nil -} - -func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - zones, err := self.GetZones() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStoragecache{} - for i := range zones { - cache := &SStoragecache{zone: &zones[i]} - ret = append(ret, cache) - } - return ret, nil -} - -func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - caches, err := self.GetIStoragecaches() - if err != nil { - return nil, err - } - for i := range caches { - if caches[i].GetGlobalId() == id { - return caches[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) _list(res string, params url.Values) (jsonutils.JSONObject, error) { - return self.client._list(res, params) -} - -func (self *SRegion) list(res string, params url.Values, retVal interface{}) error { - return self.client.list(res, params, retVal) -} - -func (self *SRegion) get(res string, params url.Values, retVal interface{}) error { - return self.client.get(res, params, retVal) -} - -func (self *SRegion) post(res string, params interface{}) (jsonutils.JSONObject, error) { - return self.client.post(res, params) -} - -func (self *SRegion) put(res string, params url.Values, body jsonutils.JSONObject, retVal interface{}) error { - return self.client.put(res, params, body, retVal) -} - -func (self *SRegion) del(res string, params url.Values, retVal interface{}) error { - return self.client.del(res, params, retVal) -} diff --git a/pkg/multicloud/incloudsphere/shell/disk.go b/pkg/multicloud/incloudsphere/shell/disk.go deleted file mode 100644 index bededafe1a..0000000000 --- a/pkg/multicloud/incloudsphere/shell/disk.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - STORAGE_ID string - } - shellutils.R(&DiskListOptions{}, "disk-list", "list disks", func(cli *incloudsphere.SRegion, args *DiskListOptions) error { - disks, err := cli.GetDisks(args.STORAGE_ID) - if err != nil { - return err - } - printList(disks, 0, 0, 0, []string{}) - return nil - }) - - type DiskIdOptions struct { - ID string - } - - shellutils.R(&DiskIdOptions{}, "disk-show", "show disk", func(cli *incloudsphere.SRegion, args *DiskIdOptions) error { - ret, err := cli.GetDisk(args.ID) - if err != nil { - return err - } - printObject(ret) - return nil - }) - - type DiskResizeOptions struct { - ID string - SIZE_GB int - } - - shellutils.R(&DiskResizeOptions{}, "disk-resize", "resize disk", func(cli *incloudsphere.SRegion, args *DiskResizeOptions) error { - return cli.ResizeDisk(args.ID, args.SIZE_GB) - }) - - type DiskCreateOptions struct { - NAME string - STORAGE_ID string - SIZE_GB int - } - - shellutils.R(&DiskCreateOptions{}, "disk-create", "create disk", func(cli *incloudsphere.SRegion, args *DiskCreateOptions) error { - disk, err := cli.CreateDisk(args.NAME, args.STORAGE_ID, args.SIZE_GB) - if err != nil { - return err - } - printObject(disk) - return nil - }) - -} diff --git a/pkg/multicloud/incloudsphere/shell/doc.go b/pkg/multicloud/incloudsphere/shell/doc.go deleted file mode 100644 index ec4cbe2b58..0000000000 --- a/pkg/multicloud/incloudsphere/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/incloudsphere/shell" diff --git a/pkg/multicloud/incloudsphere/shell/host.go b/pkg/multicloud/incloudsphere/shell/host.go deleted file mode 100644 index 87666588e2..0000000000 --- a/pkg/multicloud/incloudsphere/shell/host.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type HostListOptions struct { - DATACENTERID string - } - shellutils.R(&HostListOptions{}, "host-list", "list hosts", func(cli *incloudsphere.SRegion, args *HostListOptions) error { - hosts, err := cli.GetHosts(args.DATACENTERID) - if err != nil { - return err - } - printList(hosts, 0, 0, 0, []string{}) - return nil - }) - - type HostIdOptions struct { - ID string - } - - shellutils.R(&HostIdOptions{}, "host-show", "show host", func(cli *incloudsphere.SRegion, args *HostIdOptions) error { - ret, err := cli.GetHost(args.ID) - if err != nil { - return err - } - printObject(ret) - return nil - }) - -} diff --git a/pkg/multicloud/incloudsphere/shell/image.go b/pkg/multicloud/incloudsphere/shell/image.go deleted file mode 100644 index df86debca9..0000000000 --- a/pkg/multicloud/incloudsphere/shell/image.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageTreeOptions struct { - } - shellutils.R(&ImageTreeOptions{}, "image-tree", "list images", func(cli *incloudsphere.SRegion, args *ImageTreeOptions) error { - trees, err := cli.GetImageTrees() - if err != nil { - return err - } - for i := range trees { - printList(trees[i].ToList(), 0, 0, 0, []string{}) - } - return nil - }) - - type ImageStorageListOptions struct { - DS_ID string - } - - shellutils.R(&ImageStorageListOptions{}, "image-storage-list", "list image storages", func(cli *incloudsphere.SRegion, args *ImageStorageListOptions) error { - storages, err := cli.GetImageStorages(args.DS_ID) - if err != nil { - return err - } - printList(storages, 0, 0, 0, []string{}) - return nil - }) - - type ImageListOptions struct { - STORAGE_ID string - } - - shellutils.R(&ImageListOptions{}, "image-list", "list images", func(cli *incloudsphere.SRegion, args *ImageListOptions) error { - images, err := cli.GetImageList(args.STORAGE_ID) - if err != nil { - return err - } - printList(images, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/incloudsphere/shell/instance.go b/pkg/multicloud/incloudsphere/shell/instance.go deleted file mode 100644 index 6d29b4f156..0000000000 --- a/pkg/multicloud/incloudsphere/shell/instance.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - HOST_ID string - } - shellutils.R(&InstanceListOptions{}, "instance-list", "list instances", func(cli *incloudsphere.SRegion, args *InstanceListOptions) error { - instances, err := cli.GetInstances(args.HOST_ID) - if err != nil { - return err - } - printList(instances, 0, 0, 0, []string{}) - return nil - }) - - type InstanceIdOptions struct { - ID string - } - - shellutils.R(&InstanceIdOptions{}, "instance-show", "show instance", func(cli *incloudsphere.SRegion, args *InstanceIdOptions) error { - ret, err := cli.GetInstance(args.ID) - if err != nil { - return err - } - printObject(ret) - return nil - }) - - shellutils.R(&InstanceIdOptions{}, "instance-stop", "stop instance", func(cli *incloudsphere.SRegion, args *InstanceIdOptions) error { - return cli.StopVm(args.ID) - }) - - type InstanceStartOptions struct { - ID string - Password string - PublicKey string - } - - shellutils.R(&InstanceStartOptions{}, "instance-start", "Start instance", func(cli *incloudsphere.SRegion, args *InstanceStartOptions) error { - return cli.StartVm(args.ID, args.Password, args.PublicKey) - }) - - type InstanceAttachDiskOptions struct { - ID string - DISK_ID string - } - - shellutils.R(&InstanceAttachDiskOptions{}, "instance-attach-disk", "Attach instance disk", func(cli *incloudsphere.SRegion, args *InstanceAttachDiskOptions) error { - return cli.AttachDisk(args.ID, args.DISK_ID) - }) - - shellutils.R(&InstanceAttachDiskOptions{}, "instance-detach-disk", "Attach instance disk", func(cli *incloudsphere.SRegion, args *InstanceAttachDiskOptions) error { - return cli.DetachDisk(args.ID, args.DISK_ID) - }) - - type InstanceChangeConfigOptions struct { - ID string - Cpu int - MemMb int - } - - shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Change instance config", func(cli *incloudsphere.SRegion, args *InstanceChangeConfigOptions) error { - return cli.ChangeConfig(args.ID, args.Cpu, args.MemMb) - }) - -} diff --git a/pkg/multicloud/incloudsphere/shell/network.go b/pkg/multicloud/incloudsphere/shell/network.go deleted file mode 100644 index ea9be0a3fc..0000000000 --- a/pkg/multicloud/incloudsphere/shell/network.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkListOptions struct { - VSWITCH_ID string - } - shellutils.R(&NetworkListOptions{}, "network-list", "list networks", func(cli *incloudsphere.SRegion, args *NetworkListOptions) error { - networks, err := cli.GetNetworks(args.VSWITCH_ID) - if err != nil { - return err - } - printList(networks, 0, 0, 0, []string{}) - return nil - }) - - type NetworkIdOptions struct { - ID string - } - - shellutils.R(&NetworkIdOptions{}, "network-show", "show network", func(cli *incloudsphere.SRegion, args *NetworkIdOptions) error { - ret, err := cli.GetNetwork(args.ID) - if err != nil { - return err - } - printObject(ret) - return nil - }) - -} diff --git a/pkg/multicloud/incloudsphere/shell/printutils.go b/pkg/multicloud/incloudsphere/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/incloudsphere/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/incloudsphere/shell/region.go b/pkg/multicloud/incloudsphere/shell/region.go deleted file mode 100644 index 5632504d93..0000000000 --- a/pkg/multicloud/incloudsphere/shell/region.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "list regions", func(cli *incloudsphere.SRegion, args *RegionListOptions) error { - regions, err := cli.GetClient().GetRegions() - if err != nil { - return err - } - printList(regions, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/incloudsphere/shell/storage.go b/pkg/multicloud/incloudsphere/shell/storage.go deleted file mode 100644 index 8fbae7dd99..0000000000 --- a/pkg/multicloud/incloudsphere/shell/storage.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type StorageListOptions struct { - DATACENTERID string - } - shellutils.R(&StorageListOptions{}, "storage-list", "list storages", func(cli *incloudsphere.SRegion, args *StorageListOptions) error { - storages, err := cli.GetStoragesByDc(args.DATACENTERID) - if err != nil { - return err - } - printList(storages, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/incloudsphere/shell/version.go b/pkg/multicloud/incloudsphere/shell/version.go deleted file mode 100644 index 796bda1742..0000000000 --- a/pkg/multicloud/incloudsphere/shell/version.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VersionShowOptions struct { - } - shellutils.R(&VersionShowOptions{}, "version-show", "show version", func(cli *incloudsphere.SRegion, args *VersionShowOptions) error { - version, err := cli.GetClient().GetVersion() - if err != nil { - return err - } - printObject(version) - return nil - }) -} diff --git a/pkg/multicloud/incloudsphere/shell/wire.go b/pkg/multicloud/incloudsphere/shell/wire.go deleted file mode 100644 index 6920405d1f..0000000000 --- a/pkg/multicloud/incloudsphere/shell/wire.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type WireListOptions struct { - } - shellutils.R(&WireListOptions{}, "wire-list", "list wires", func(cli *incloudsphere.SRegion, args *WireListOptions) error { - wires, err := cli.GetWires() - if err != nil { - return err - } - printList(wires, 0, 0, 0, []string{}) - return nil - }) - - type WireIdOptions struct { - ID string - } - - shellutils.R(&WireIdOptions{}, "wire-show", "show wire", func(cli *incloudsphere.SRegion, args *WireIdOptions) error { - ret, err := cli.GetWire(args.ID) - if err != nil { - return err - } - printObject(ret) - return nil - }) -} diff --git a/pkg/multicloud/incloudsphere/shell/zone.go b/pkg/multicloud/incloudsphere/shell/zone.go deleted file mode 100644 index f2359f271f..0000000000 --- a/pkg/multicloud/incloudsphere/shell/zone.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/incloudsphere" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - } - shellutils.R(&ZoneListOptions{}, "zone-list", "list zones", func(cli *incloudsphere.SRegion, args *ZoneListOptions) error { - zones, err := cli.GetZones() - if err != nil { - return err - } - printList(zones, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/incloudsphere/storage.go b/pkg/multicloud/incloudsphere/storage.go deleted file mode 100644 index 276081b565..0000000000 --- a/pkg/multicloud/incloudsphere/storage.go +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type DataCenterOrHostDto struct { - DataCenterOrHost string `json:"dataCenterOrHost"` - DataCenterName string `json:"dataCenterName"` - HostName string `json:"hostName"` - Status string `json:"status"` -} - -type BlockDeviceDto struct { - ID string `json:"id"` - Name string `json:"name"` - PartitionFlag bool `json:"partitionFlag"` - PartitionNumber string `json:"partitionNumber"` - Capacity int `json:"capacity"` - DisplayCapacity string `json:"displayCapacity"` - DiskType string `json:"diskType"` - AbsolutePath string `json:"absolutePath"` - Transport string `json:"transport"` - Used string `json:"used"` - IsUsed bool `json:"isUsed"` -} - -type SStorage struct { - multicloud.SStorageBase - multicloud.InCloudSphereTags - - zone *SZone - - Id string `json:"id"` - Name string `json:"name"` - MountPath string `json:"mountPath"` - DataStoreType string `json:"dataStoreType"` - Capacity float64 `json:"capacity"` - UsedCapacity float64 `json:"usedCapacity"` - AvailCapacity float64 `json:"availCapacity"` - DataCenterId string `json:"dataCenterId"` - HostId string `json:"hostId"` - MountStatus string `json:"mountStatus"` - HostIP string `json:"hostIp"` - UUID string `json:"uuid"` - AbsolutePath string `json:"absolutePath"` - DataCenterName string `json:"dataCenterName"` - DataCenterOrHostDto DataCenterOrHostDto `json:"dataCenterOrHostDto"` - BlockDeviceDto BlockDeviceDto `json:"blockDeviceDto"` - XactiveStoreName string `json:"xactiveStoreName"` - XactiveStoreId string `json:"xactiveStoreId"` - DataCenterDto string `json:"dataCenterDto"` - HostNumbers int `json:"hostNumbers"` - VMNumbers int `json:"vmNumbers"` - VolumesNumbers int `json:"volumesNumbers"` - VMTemplateNumbers int `json:"vmTemplateNumbers"` - Tags string `json:"tags"` - MaxSlots int `json:"maxSlots"` - Creating bool `json:"creating"` - StorageBackUp bool `json:"storageBackUp"` - ExtensionType string `json:"extensionType"` - CanBeImageStorage bool `json:"canBeImageStorage"` - MultiplexRatio float64 `json:"multiplexRatio"` - Oplimit bool `json:"oplimit"` - Maxop int `json:"maxop"` - MountStateCount string `json:"mountStateCount"` - DatastoreRole string `json:"datastoreRole"` - CanCreateXactive bool `json:"canCreateXactive"` - BlockDeviceUUId string `json:"blockDeviceUuid"` - OpHostIP string `json:"opHostIp"` - IsMount string `json:"isMount"` - HostDto string `json:"hostDto"` - ScvmOn bool `json:"scvmOn"` -} - -func (self *SStorage) GetName() string { - return self.Name -} - -func (self *SStorage) GetId() string { - return self.Id -} - -func (self *SStorage) GetGlobalId() string { - return self.GetId() -} - -func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := self.zone.region.GetDisks(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudDisk{} - for i := range disks { - disks[i].region = self.zone.region - ret = append(ret, &disks[i]) - } - return ret, nil -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - disk, err := self.zone.region.CreateDisk(conf.Name, self.Id, conf.SizeGb) - if err != nil { - return nil, err - } - return disk, nil -} - -func (self *SStorage) GetCapacityMB() int64 { - return int64(self.Capacity) * 1024 -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return int64(self.UsedCapacity) * 1024 -} - -func (self *SStorage) GetEnabled() bool { - return true -} - -func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - disk, err := self.zone.region.GetDisk(id) - if err != nil { - return nil, err - } - if disk.DataStoreId != self.Id { - return nil, cloudprovider.ErrNotFound - } - return disk, nil -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - cache := &SStoragecache{zone: self.zone} - return cache -} - -func (self *SStorage) GetMediumType() string { - return api.DISK_TYPE_SSD -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) Refresh() error { - ret, err := self.zone.region.GetStorage(self.GetGlobalId()) - if err != nil { - return err - } - return jsonutils.Update(self, ret) -} - -func (self *SStorage) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (self *SStorage) GetStorageType() string { - return strings.ToLower(self.DataStoreType) -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} - -func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storage, err := self.GetStorage(id) - if err != nil { - return nil, err - } - zone, err := self.GetZone(storage.DataCenterId) - if err != nil { - return nil, err - } - storage.zone = zone - return storage, nil -} - -func (self *SRegion) GetStoragesByDc(dcId string) ([]SStorage, error) { - storages := []SStorage{} - res := fmt.Sprintf("/datacenters/%s/storages", dcId) - return storages, self.list(res, url.Values{}, &storages) -} - -func (self *SRegion) GetStoragesByHost(hostId string) ([]SStorage, error) { - storages := []SStorage{} - res := fmt.Sprintf("/hosts/%s/storages", hostId) - return storages, self.list(res, url.Values{}, &storages) -} - -func (self *SRegion) GetStorage(id string) (*SStorage, error) { - ret := &SStorage{} - res := fmt.Sprintf("/storages/%s", id) - return ret, self.get(res, url.Values{}, ret) -} diff --git a/pkg/multicloud/incloudsphere/storagecache.go b/pkg/multicloud/incloudsphere/storagecache.go deleted file mode 100644 index 712544817f..0000000000 --- a/pkg/multicloud/incloudsphere/storagecache.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "context" - "fmt" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.InCloudSphereTags - - zone *SZone -} - -func (self *SStoragecache) GetGlobalId() string { - return self.zone.GetGlobalId() -} - -func (self *SStoragecache) GetId() string { - return self.zone.GetId() -} - -func (self *SStoragecache) GetName() string { - return self.zone.GetName() -} - -func (self *SStoragecache) GetStatus() string { - return "available" -} - -func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - ret := []cloudprovider.ICloudImage{} - iss, err := self.zone.region.GetImageStorages(self.zone.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetImageStorages") - } - for i := range iss { - images, err := self.zone.region.GetImageList(iss[i].Id) - if err != nil { - return nil, err - } - for j := range images { - if utils.IsInStringArray(images[j].GetImageFormat(), []string{"iso", "ova"}) { - continue - } - images[j].cache = self - ret = append(ret, &images[j]) - } - } - return ret, nil -} - -func (seflf *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SStoragecache) GetIImageById(id string) (cloudprovider.ICloudImage, error) { - images, err := self.GetICloudImages() - if err != nil { - return nil, err - } - for i := range images { - if images[i].GetGlobalId() == id { - return images[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -func (self *SStoragecache) CreateIImage(snpId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -type SImageStorage struct { - Id string - Name string -} - -func (self *SRegion) GetImageStorages(dsId string) ([]SImageStorage, error) { - params := url.Values{} - params.Set("type", "imagestorage") - res := fmt.Sprintf("/datacenters/%s/storages", dsId) - ret := []SImageStorage{} - return ret, self.get(res, params, &ret) -} - -func (self *SRegion) GetImageList(storageId string) ([]SImage, error) { - res := fmt.Sprintf("/storages/%s/files", storageId) - ret := []SImage{} - return ret, self.list(res, url.Values{}, &ret) -} diff --git a/pkg/multicloud/incloudsphere/task.go b/pkg/multicloud/incloudsphere/task.go deleted file mode 100644 index e900b56062..0000000000 --- a/pkg/multicloud/incloudsphere/task.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "fmt" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type STask struct { - Id string - Name string - Detail string - Error string - State string - CreatedResourceId string -} - -func (self *SphereClient) waitTask(id string) (string, error) { - resId := "" - return resId, cloudprovider.Wait(time.Second*10, time.Minute*10, func() (bool, error) { - task := &STask{} - err := self.get("/tasks/"+id, nil, task) - if err != nil { - return false, errors.Wrapf(err, "get task %s", id) - } - switch task.State { - case "WAITING", "READY", "RUNNING": - log.Debugf("task %s with %s state: %s", task.Id, task.Detail, task.State) - return false, nil - case "FINISHED": - resId = task.CreatedResourceId - return true, nil - case "ERROR": - return false, fmt.Errorf("%s: %s", task.Detail, task.Error) - default: - log.Debugf("task %s with %s state: %s", task.Id, task.Detail, task.State) - return false, fmt.Errorf("%s: %s invalid state: %v", task.Detail, task.Error, task.State) - } - }) -} diff --git a/pkg/multicloud/incloudsphere/vpc.go b/pkg/multicloud/incloudsphere/vpc.go deleted file mode 100644 index f47151e3ba..0000000000 --- a/pkg/multicloud/incloudsphere/vpc.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - multicloud.InCloudSphereTags - - region *SRegion -} - -func (self *SVpc) GetName() string { - return "Default" -} - -func (self *SVpc) GetId() string { - return self.region.GetId() -} - -func (self *SVpc) GetGlobalId() string { - return self.GetId() -} - -func (self *SVpc) Delete() error { - return cloudprovider.ErrNotSupported -} - -func (self *SVpc) IsEmulated() bool { - return true -} - -func (self *SVpc) GetCidrBlock() string { - return "0.0.0.0/0" -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - return []cloudprovider.ICloudRouteTable{}, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - return []cloudprovider.ICloudSecurityGroup{}, nil -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - wires, err := self.region.GetWires() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudWire{} - for i := range wires { - wires[i].region = self.region - ret = append(ret, &wires[i]) - } - return ret, nil -} - -func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { - wire, err := self.region.GetWire(id) - if err != nil { - return nil, err - } - wire.region = self.region - return wire, nil -} - -func (self *SVpc) GetIsDefault() bool { - return true -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} diff --git a/pkg/multicloud/incloudsphere/wire.go b/pkg/multicloud/incloudsphere/wire.go deleted file mode 100644 index d6da3dc8aa..0000000000 --- a/pkg/multicloud/incloudsphere/wire.go +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "fmt" - "net/url" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.InCloudSphereTags - - region *SRegion - - Id string `json:"id"` - Name string `json:"name"` - ResourceId string `json:"resourceId"` - ControllerIP string `json:"controllerIP"` - DataCenterDto SZone `json:"dataCenterDto"` - HostDtos []SHost `json:"hostDtos"` - SwitchType string `json:"switchType"` - AppType string `json:"appType"` - Description string `json:"description"` - NetworkDtos string `json:"networkDtos"` - SdnNetworkDtos string `json:"sdnNetworkDtos"` - VMDtos string `json:"vmDtos"` - HostNum int `json:"hostNum"` - PnicNum int `json:"pnicNum"` - NetworkNum int `json:"networkNum"` - VMNum int `json:"vmNum"` - Maxvfs int `json:"maxvfs"` - ThirdPartySDN bool `json:"thirdPartySDN"` - Hierarchy bool `json:"hierarchy"` - ConnectStorage bool `json:"connectStorage"` - ConnectManage bool `json:"connectManage"` - ConnectSwitches string `json:"connectSwitches"` - DhcpProtection bool `json:"dhcpProtection"` - NeutronName string `json:"neutronName"` - NeutronPassword string `json:"neutronPassword"` - ConnectScvm bool `json:"connectScvm"` - SwitchUplinkType string `json:"switchUplinkType"` - ComputerNetNum int `json:"computerNetNum"` - DataNetNum int `json:"dataNetNum"` - MigrateNetNum int `json:"migrateNetNum"` - VMMigBandWidth string `json:"vmMigBandWidth"` - EnableDpdk bool `json:"enableDpdk"` - SflowStatus bool `json:"sflowStatus"` - NetflowStatus bool `json:"netflowStatus"` - MulticastStatus bool `json:"multicastStatus"` - MirrorStatus bool `json:"mirrorStatus"` - BrLimitStatus bool `json:"brLimitStatus"` - Hidden bool `json:"hidden"` - NetworkTopoly bool `json:"networkTopoly"` -} - -func (self *SWire) GetName() string { - return self.Name -} - -func (self *SWire) GetId() string { - return self.Id -} - -func (self *SWire) GetGlobalId() string { - return self.GetId() -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SWire) GetBandwidth() int { - return 10000 -} - -func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - nets, err := self.region.GetNetworks(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNetwork{} - for i := range nets { - nets[i].wire = self - ret = append(ret, &nets[i]) - } - return ret, nil -} - -func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { - net, err := self.region.GetNetwork(id) - if err != nil { - return nil, err - } - net.wire = self - if net.VswitchDto.Id != self.Id { - return nil, cloudprovider.ErrNotFound - } - return net, nil -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.region.getVpc() -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - zone, _ := self.region.GetZone(self.DataCenterDto.Id) - return zone -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SRegion) GetWires() ([]SWire, error) { - ret := []SWire{} - return ret, self.list("/vswitchs", url.Values{}, &ret) -} - -func (self *SRegion) GetWiresByDs(dsId string) ([]SWire, error) { - ret := []SWire{} - res := fmt.Sprintf("/datacenters/%s/vswitchs", dsId) - return ret, self.list(res, url.Values{}, &ret) -} - -func (self *SRegion) GetWire(id string) (*SWire, error) { - ret := &SWire{region: self} - res := fmt.Sprintf("/vswitchs/%s", id) - return ret, self.get(res, url.Values{}, ret) -} diff --git a/pkg/multicloud/incloudsphere/zone.go b/pkg/multicloud/incloudsphere/zone.go deleted file mode 100644 index 05f6d0a448..0000000000 --- a/pkg/multicloud/incloudsphere/zone.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 incloudsphere - -import ( - "fmt" - "net/url" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SZone struct { - multicloud.SResourceBase - multicloud.InCloudSphereTags - - region *SRegion - - Id string `json:"id"` - Name string `json:"name"` - NFSPath string `json:"nfsPath"` - Type string `json:"type"` - Description string `json:"description"` - HostNum int64 `json:"hostNum"` - VMNum int64 `json:"vmNum"` - ClusterNum int64 `json:"clusterNum"` - CfsDomainNum int64 `json:"cfsDomainNum"` - StorageNum int64 `json:"storageNum"` - ImageISONum int64 `json:"imageIsoNum"` - NetNum int64 `json:"netNum"` - NeutronNetNum int64 `json:"neutronNetNum"` - CPUCapacity string `json:"cpuCapacity"` - CPUAvailable string `json:"cpuAvailable"` - CPUUsed string `json:"cpuUsed"` - CPUUtilization string `json:"cpuUtilization"` - MemoryCapacity string `json:"memoryCapacity"` - MemoryAvailable string `json:"memoryAvailable"` - MemoryUsed string `json:"memoryUsed"` - MemoryUtilization string `json:"memoryUtilization"` - StorageCapacity string `json:"storageCapacity"` - StorageAvailable string `json:"storageAvailable"` - StorageUsed string `json:"storageUsed"` - StorageUtilization string `json:"storageUtilization"` - DatastoreNum int64 `json:"datastoreNum"` - LocalstoreNum int64 `json:"localstoreNum"` - CfsstoreNum int64 `json:"cfsstoreNum"` - RawstoreNum int64 `json:"rawstoreNum"` - NfsstoreNum int64 `json:"nfsstoreNum"` - XactivestoreNum int64 `json:"xactivestoreNum"` - NetworkType string `json:"networkType"` - VswitchDtos string `json:"vswitchDtos"` - //SDNNetworkDtos []interface{} `json:"sdnNetworkDtos"` - SDNInit bool `json:"sdnInit"` - SDNSpeedUp bool `json:"sdnSpeedUp"` - SDNConfigDto string `json:"sdnConfigDto"` -} - -func (self *SZone) GetId() string { - return self.Id -} - -func (self *SZone) GetGlobalId() string { - return self.Id -} - -func (self *SZone) GetName() string { - return self.Name -} - -func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SZone) GetStatus() string { - return api.ZONE_ENABLE -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) - return table -} - -func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - host, err := self.region.GetHost(id) - if err != nil { - return nil, err - } - host.zone = self - if host.DataCenterId != self.Id { - return nil, cloudprovider.ErrNotFound - } - return host, nil -} - -func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - hosts, err := self.region.GetHosts(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudHost{} - for i := range hosts { - hosts[i].zone = self - ret = append(ret, &hosts[i]) - } - return ret, nil -} - -func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := self.region.GetStoragesByDc(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStorage{} - for i := range storages { - storages[i].zone = self - ret = append(ret, &storages[i]) - } - return ret, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storage, err := self.region.GetStorage(id) - if err != nil { - return nil, err - } - if storage.DataCenterId != self.Id { - return nil, cloudprovider.ErrNotFound - } - storage.zone = self - return storage, nil -} - -func (self *SRegion) GetZones() ([]SZone, error) { - ret := []SZone{} - return ret, self.list("/datacenters", url.Values{}, &ret) -} - -func (self *SRegion) GetZone(id string) (*SZone, error) { - ret := &SZone{region: self} - res := fmt.Sprintf("/datacenters/%s", id) - return ret, self.get(res, url.Values{}, ret) -} diff --git a/pkg/multicloud/jdcloud/disk.go b/pkg/multicloud/jdcloud/disk.go deleted file mode 100644 index 39f8654a22..0000000000 --- a/pkg/multicloud/jdcloud/disk.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "context" - "fmt" - "time" - - commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" - "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/apis" - "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/client" - "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/models" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDisk struct { - storage *SStorage - - multicloud.SDisk - multicloud.JdcloudTags - multicloud.SBillingBase - - models.Disk - - ImageId string - IsSystemDisk bool -} - -func (d *SDisk) GetBillingType() string { - return billingType(&d.Charge) -} - -func (d *SDisk) GetExpiredAt() time.Time { - return expireAt(&d.Charge) -} - -func (d *SDisk) GetId() string { - return d.DiskId -} - -func (d *SDisk) GetName() string { - return d.Name -} - -func (d *SDisk) GetGlobalId() string { - return d.GetId() -} - -func (d *SDisk) GetIops() int { - return d.Iops -} - -func (d *SDisk) GetStatus() string { - switch d.Status { - case "available", "in-use": - return api.DISK_READY - case "creating": - return api.DISK_ALLOCATING - case "extending": - return api.DISK_RESIZING - case "restoring": - return api.DISK_RESET - case "deleting": - return api.DISK_DEALLOC - case "error_create": - return api.DISK_ALLOC_FAILED - case "error_delete": - return api.DISK_DEALLOC_FAILED - case "error_restore": - return api.DISK_RESET_FAILED - case "error_extend": - return api.DISK_RESIZE_FAILED - default: - return api.DISK_UNKNOWN - } -} - -func (d *SDisk) Refresh() error { - return nil -} - -func (d *SDisk) IsEmulated() bool { - return false -} - -func (d *SDisk) GetSysTags() map[string]string { - return map[string]string{ - "hypervisor": api.HYPERVISOR_JDCLOUD, - } -} - -func (d *SDisk) GetProjectId() string { - return "" -} - -func (d *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return d.storage, nil -} - -func (d *SDisk) GetDiskFormat() string { - return "vhd" -} - -func (d *SDisk) GetDiskSizeMB() int { - return d.DiskSizeGB * 1024 -} - -func (d *SDisk) GetIsAutoDelete() bool { - if len(d.Attachments) == 0 { - return false - } - return true -} - -func (d *SDisk) GetTemplateId() string { - // TODO 通过快照创建的盘应该如何 - return d.ImageId -} - -func (d *SDisk) GetDiskType() string { - if d.IsSystemDisk { - return api.DISK_TYPE_SYS - } - return api.DISK_TYPE_DATA -} - -func (d *SDisk) GetFsFormat() string { - return "" -} - -func (d *SDisk) GetIsNonPersistent() bool { - return false -} - -func (d *SDisk) GetDriver() string { - return "scsi" -} - -func (d *SDisk) GetCacheMode() string { - return "none" -} - -func (d *SDisk) GetMountpoint() string { - return "" -} - -func (d *SDisk) GetAccessPath() string { - return "" -} - -func (d *SDisk) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (d *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (d *SDisk) GetISnapshot(id string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := d.storage.zone.region.GetSnapshotById(id) - if err != nil { - return nil, err - } - snapshot.disk = d - return snapshot, nil -} - -func (s *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots := make([]SSnapshot, 0) - n := 1 - for { - parts, total, err := s.storage.zone.region.GetSnapshots(s.DiskId, n, 100) - if err != nil { - return nil, err - } - snapshots = append(snapshots, parts...) - if len(snapshots) >= total { - break - } - n++ - } - isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) - for i := range snapshots { - snapshots[i].disk = s - isnapshots[i] = &snapshots[i] - } - return isnapshots, nil -} - -func (s *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { - return []string{}, nil -} - -func (s *SDisk) Resize(ctx context.Context, newSizeMB int64) error { - return cloudprovider.ErrNotImplemented -} - -func (s *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", cloudprovider.ErrNotImplemented -} - -func (s *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (r *SRegion) GetDisks(instanceId, zoneId, diskType string, diskIds []string, pageNumber, pageSize int) ([]SDisk, int, error) { - filters := []commodels.Filter{} - if instanceId != "" { - filters = append(filters, commodels.Filter{ - Name: "instanceId", - Values: []string{instanceId}, - }, commodels.Filter{ - Name: "instanceType", - Values: []string{"vm"}, - }) - } - if zoneId != "" { - filters = append(filters, commodels.Filter{ - Name: "az", - Values: []string{zoneId}, - }) - } - if len(diskIds) > 0 { - filters = append(filters, commodels.Filter{ - Name: "diskId", - Values: diskIds, - }) - } - if diskType != "" { - filters = append(filters, commodels.Filter{ - Name: "diskType", - Values: []string{diskType}, - }) - } - req := apis.NewDescribeDisksRequestWithAllParams(r.ID, &pageNumber, &pageSize, nil, filters) - client := client.NewDiskClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeDisks(req) - if err != nil { - return nil, 0, err - } - if resp.Error.Code >= 400 { - return nil, 0, fmt.Errorf(resp.Error.Message) - } - total := resp.Result.TotalCount - disks := make([]SDisk, 0, len(resp.Result.Disks)) - for i := range resp.Result.Disks { - disks = append(disks, SDisk{ - Disk: resp.Result.Disks[i], - }) - } - return disks, total, nil -} - -func (r *SRegion) GetDiskById(id string) (*SDisk, error) { - req := apis.NewDescribeDiskRequest(r.ID, id) - client := client.NewDiskClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeDisk(req) - if err != nil { - return nil, err - } - if resp.Error.Code >= 400 { - return nil, fmt.Errorf(resp.Error.Message) - } - return &SDisk{ - Disk: resp.Result.Disk, - }, nil -} diff --git a/pkg/multicloud/jdcloud/doc.go b/pkg/multicloud/jdcloud/doc.go deleted file mode 100644 index c8fa4164ed..0000000000 --- a/pkg/multicloud/jdcloud/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud // import "yunion.io/x/onecloud/pkg/multicloud/jdcloud" diff --git a/pkg/multicloud/jdcloud/eip.go b/pkg/multicloud/jdcloud/eip.go deleted file mode 100644 index b182ee57d2..0000000000 --- a/pkg/multicloud/jdcloud/eip.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - "time" - - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/apis" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/client" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/models" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SEip struct { - region *SRegion - multicloud.SEipBase - multicloud.JdcloudTags - - models.ElasticIp -} - -func (e *SEip) GetId() string { - return e.ElasticIpId -} - -func (e *SEip) GetName() string { - return e.ElasticIpAddress -} - -func (e *SEip) GetGlobalId() string { - return e.GetId() -} - -func (e *SEip) GetStatus() string { - return api.EIP_STATUS_READY -} - -func (e *SEip) Refresh() error { - return nil -} - -func (e *SEip) IsEmulated() bool { - return false -} - -func (e *SEip) GetIpAddr() string { - return e.ElasticIpAddress -} - -func (e *SEip) GetMode() string { - return api.EIP_MODE_STANDALONE_EIP -} - -func (e *SEip) GetAssociationType() string { - switch e.InstanceType { - case "compute": - return api.EIP_ASSOCIATE_TYPE_SERVER - case "lb": - return api.EIP_ASSOCIATE_TYPE_LOADBALANCER - default: - return e.InstanceType - } -} - -func (e *SEip) GetAssociationExternalId() string { - return e.InstanceId -} - -func (e *SEip) GetBillingType() string { - return billingType(&e.Charge) -} - -func (e *SEip) GetCreatedAt() time.Time { - return parseTime(e.CreatedTime) -} - -func (e *SEip) GetExpiredAt() time.Time { - return expireAt(&e.Charge) -} - -func (e *SEip) Delete() error { - return nil -} - -func (e *SEip) GetBandwidth() int { - return e.BandwidthMbps -} - -func (e *SEip) GetINetworkId() string { - return "" -} - -func (e *SEip) GetInternetChargeType() string { - switch e.Charge.ChargeMode { - case "postpaid_by_usage": - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - case "postpaid_by_duration": - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH - default: - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - } -} - -func (e *SEip) Associate(conf *cloudprovider.AssociateConfig) error { - return nil -} - -func (e *SEip) Dissociate() error { - return nil -} - -func (e *SEip) ChangeBandwidth(bw int) error { - return nil -} - -func (e *SEip) GetProjectId() string { - return "" -} - -func (r *SRegion) GetEIPById(id string) (*SEip, error) { - req := apis.NewDescribeElasticIpRequest(r.ID, id) - client := client.NewVpcClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeElasticIp(req) - if err != nil { - return nil, err - } - if resp.Error.Code >= 400 { - return nil, fmt.Errorf(resp.Error.Message) - } - return &SEip{ - region: r, - ElasticIp: resp.Result.ElasticIp, - }, nil -} diff --git a/pkg/multicloud/jdcloud/host.go b/pkg/multicloud/jdcloud/host.go deleted file mode 100644 index 6e511165b5..0000000000 --- a/pkg/multicloud/jdcloud/host.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/sets" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone -} - -func (h *SHost) GetId() string { - return fmt.Sprintf("%s-%s", h.zone.region.cpcfg.Id, h.zone.GetGlobalId()) -} - -func (h *SHost) GetName() string { - return fmt.Sprintf("%s-%s", h.zone.region.cpcfg.Name, h.zone.GetName()) -} - -func (h *SHost) GetGlobalId() string { - return h.GetId() -} - -func (h *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (h *SHost) Refresh() error { - return nil -} - -func (h *SHost) IsEmulated() bool { - return true -} - -func (h *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms := make([]SInstance, 0) - n := 1 - for { - parts, total, err := h.zone.region.GetInstances(h.zone.ID, nil, n, 100) - if err != nil { - return nil, err - } - vms = append(vms, parts...) - if len(vms) >= total { - break - } - n++ - } - // fill instanceType - instanceTypes := sets.NewString() - for i := range vms { - instanceTypes.Insert(vms[i].InstanceType) - } - its, err := h.zone.region.InstanceTypes(instanceTypes.UnsortedList()...) - if err != nil { - return nil, errors.Wrap(err, "unable to fetch instanceTypes") - } - itMap := make(map[string]*SInstanceType, len(its)) - for i := range its { - itMap[its[i].InstanceType.InstanceType] = &its[i] - } - ivms := make([]cloudprovider.ICloudVM, len(vms)) - for i := range vms { - vms[i].host = h - vms[i].instanceType = itMap[vms[i].InstanceType] - ivms[i] = &vms[i] - } - return ivms, nil -} - -func (h *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - in, err := h.zone.region.GetInstanceById(id) - if err != nil { - return nil, err - } - in.host = h - return in, nil -} - -func (h *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - return nil, nil -} - -func (h *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - return h.zone.GetIStorages() -} - -func (h *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return h.zone.GetIStorageById(id) -} - -func (h *SHost) GetEnabled() bool { - return true -} - -func (h *SHost) GetHostStatus() string { - return api.HOST_ONLINE -} - -func (h *SHost) GetAccessIp() string { - return "" -} - -func (h *SHost) GetAccessMac() string { - return "" -} - -func (h *SHost) GetSysInfo() jsonutils.JSONObject { - info := jsonutils.NewDict() - info.Add(jsonutils.NewString(api.CLOUD_PROVIDER_JDCLOUD), "manufacture") - return info -} - -func (h *SHost) GetSN() string { - return "" -} - -func (h *SHost) GetCpuCount() int { - return 0 -} - -func (h *SHost) GetNodeCount() int8 { - return 0 -} - -func (h *SHost) GetCpuDesc() string { - return "" -} - -func (h *SHost) GetCpuMhz() int { - return 0 -} - -func (h *SHost) GetMemSizeMB() int { - return 0 -} - -func (h *SHost) GetStorageSizeMB() int { - return 0 -} - -func (h *SHost) GetStorageType() string { - return api.DISK_TYPE_HYBRID -} - -func (h *SHost) GetHostType() string { - return api.HOST_TYPE_JDCLOUD -} - -func (h *SHost) GetIsMaintenance() bool { - return false -} - -func (h *SHost) GetVersion() string { - return "" -} - -func (h *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (h *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/jdcloud/image.go b/pkg/multicloud/jdcloud/image.go deleted file mode 100644 index b7c57f45dc..0000000000 --- a/pkg/multicloud/jdcloud/image.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/apis" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/client" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/models" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type SImage struct { - multicloud.SImageBase - multicloud.JdcloudTags - - storageCache *SStoragecache - - imageInfo *imagetools.ImageInfo - - models.Image -} - -func (i *SImage) GetCreatedAt() time.Time { - return parseTime(i.CreateTime) -} - -func (i *SImage) GetId() string { - return i.ImageId -} - -func (i *SImage) GetName() string { - return i.Name -} - -func (i *SImage) GetDescription() string { - return i.Desc -} - -func (i *SImage) GetGlobalId() string { - return i.GetId() -} - -func (i *SImage) GetStatus() string { - switch i.Status { - case "pending": - return api.CACHED_IMAGE_STATUS_SAVING - case "ready": - return api.CACHED_IMAGE_STATUS_ACTIVE - case "deleting": - return api.CACHED_IMAGE_STATUS_DELETING - case "error": - return api.CACHED_IMAGE_STATUS_UNKNOWN - default: - return api.CACHED_IMAGE_STATUS_UNKNOWN - } -} - -func (i *SImage) Refresh() error { - return nil -} - -func (i *SImage) IsEmulated() bool { - return false -} - -func (i *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if i.imageInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(i.Name, i.Architecture, i.OsType, i.Platform, i.OsVersion) - i.imageInfo = &imgInfo - } - return i.imageInfo -} - -func (i *SImage) GetFullOsName() string { - return i.Name -} - -func (i *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(i.getNormalizedImageInfo().OsType) -} - -func (i *SImage) GetOsDist() string { - return i.getNormalizedImageInfo().OsDistro -} - -func (i *SImage) GetOsVersion() string { - return i.getNormalizedImageInfo().OsVersion -} - -func (i *SImage) GetOsLang() string { - return i.getNormalizedImageInfo().OsLang -} - -func (i *SImage) GetOsArch() string { - return i.getNormalizedImageInfo().OsArch -} - -func (i *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(i.getNormalizedImageInfo().OsBios) -} - -func (i *SImage) GetMinOsDiskSizeGb() int { - return i.SystemDiskSizeGB -} - -func (i *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (i *SImage) GetImageFormat() string { - return "" -} - -func (i *SImage) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (i *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return nil -} - -func (i *SImage) GetSizeByte() int64 { - return int64(i.SizeMB) * 1024 * 1024 -} - -func (i *SImage) GetImageType() cloudprovider.TImageType { - switch i.ImageSource { - case "jcloud": - return cloudprovider.ImageTypeSystem - case "marketplace": - return cloudprovider.ImageTypeMarket - case "self": - return cloudprovider.ImageTypeCustomized - case "shared": - return cloudprovider.ImageTypeShared - default: - return cloudprovider.TImageType("") - } -} - -func (i *SImage) GetImageStatus() string { - switch i.Status { - case "pending": - return cloudprovider.IMAGE_STATUS_QUEUED - default: - return cloudprovider.IMAGE_STATUS_ACTIVE - } -} - -func (r *SRegion) GetImage(imageId string) (*SImage, error) { - req := apis.NewDescribeImageRequest(r.ID, imageId) - client := client.NewVmClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeImage(req) - if err != nil { - return nil, err - } - if resp.Error.Code >= 400 { - err = fmt.Errorf(resp.Error.Message) - return nil, err - } - return &SImage{ - Image: resp.Result.Image, - }, nil -} - -func (r *SRegion) GetImages(imageIds []string, imageSource string, pageNumber, pageSize int) ([]SImage, int, error) { - req := apis.NewDescribeImagesRequestWithAllParams(r.ID, &imageSource, nil, nil, nil, imageIds, nil, nil, nil, nil, &pageNumber, &pageSize) - client := client.NewVmClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeImages(req) - if err != nil { - log.Errorf("err: %v", err) - return nil, 0, err - } - if resp.Error.Code >= 400 { - if strings.Contains(resp.Error.Message, "secret key is nul") || strings.Contains(resp.Error.Message, "sign result is not same") { - return nil, 0, errors.Wrapf(httperrors.ErrInvalidAccessKey, resp.Error.Message) - } - err = fmt.Errorf(resp.Error.Message) - return nil, 0, err - } - images := make([]SImage, len(resp.Result.Images)) - for i := range resp.Result.Images { - images[i] = SImage{ - Image: resp.Result.Images[i], - } - } - return images, resp.Result.TotalCount, nil -} diff --git a/pkg/multicloud/jdcloud/instance.go b/pkg/multicloud/jdcloud/instance.go deleted file mode 100644 index 82af48fd53..0000000000 --- a/pkg/multicloud/jdcloud/instance.go +++ /dev/null @@ -1,443 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "context" - "fmt" - "time" - - commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/apis" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/client" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/models" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/sets" - - napis "yunion.io/x/onecloud/pkg/apis" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SInstance struct { - multicloud.SInstanceBase - multicloud.SBillingBase - multicloud.JdcloudTags - - host *SHost - image *SImage - - models.Instance - - instanceType *SInstanceType -} - -func (i *SInstance) GetBillingType() string { - return billingType(&i.Charge) -} - -func (i *SInstance) GetExpiredAt() time.Time { - return expireAt(&i.Charge) -} - -func (i *SInstance) GetId() string { - return i.InstanceId -} - -func (i *SInstance) GetName() string { - return i.InstanceName -} - -func (i *SInstance) GetHostname() string { - return i.Hostname -} - -func (i *SInstance) GetGlobalId() string { - return i.GetId() -} - -func (i *SInstance) GetStatus() string { - switch i.Status { - case "pending": - return api.VM_DEPLOYING - case "starting": - return api.VM_STARTING - case "running": - return api.VM_RUNNING - case "stopping": - return api.VM_STOPPING - case "stopped": - return api.VM_READY - case "reboot": - return api.VM_STARTING - case "rebuilding": - return api.VM_REBUILD_ROOT - case "resizing": - return api.VM_CHANGE_FLAVOR - case "deleting": - return api.VM_DELETING - default: - return api.VM_UNKNOWN - } -} - -func (i *SInstance) Refresh() error { - return nil -} - -func (i *SInstance) IsEmulated() bool { - return false -} - -func (i *SInstance) GetBootOrder() string { - return "dcn" -} - -func (i *SInstance) GetVga() string { - return "std" -} - -func (i *SInstance) GetVdi() string { - return "vnc" -} - -func (i *SInstance) GetImage() (*SImage, error) { - if i.image != nil { - return i.image, nil - } - image, err := i.host.zone.region.GetImage(i.ImageId) - if err != nil { - return nil, err - } - i.image = image - return i.image, nil -} - -func (i *SInstance) GetOsType() cloudprovider.TOsType { - image, err := i.GetImage() - if err != nil { - return cloudprovider.OsTypeLinux - } - return image.GetOsType() -} - -func (i *SInstance) GetFullOsName() string { - image, err := i.GetImage() - if err != nil { - return "" - } - return image.GetFullOsName() -} - -func (i *SInstance) GetBios() cloudprovider.TBiosType { - image, err := i.GetImage() - if err != nil { - return cloudprovider.BIOS - } - return image.GetBios() -} - -func (i *SInstance) GetOsArch() string { - image, err := i.GetImage() - if err != nil { - return napis.OS_ARCH_X86_64 - } - return image.GetOsArch() -} - -func (i *SInstance) GetOsDist() string { - image, err := i.GetImage() - if err != nil { - return "" - } - return image.GetOsDist() -} - -func (i *SInstance) GetOsVersion() string { - image, err := i.GetImage() - if err != nil { - return "" - } - return image.GetOsVersion() -} - -func (i *SInstance) GetOsLang() string { - image, err := i.GetImage() - if err != nil { - return "" - } - return image.GetOsLang() -} - -func (i *SInstance) GetMachine() string { - return "pc" -} - -func (i *SInstance) GetInstanceType() string { - return i.InstanceType -} - -func (in *SInstance) GetProjectId() string { - return "" -} - -func (in *SInstance) GetIHost() cloudprovider.ICloudHost { - return in.host -} - -func (in *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks := make([]cloudprovider.ICloudDisk, 0, len(in.DataDisks)+1) - if in.SystemDisk.DiskCategory != "local" { - disk := &SDisk{ - Disk: in.SystemDisk.CloudDisk, - ImageId: in.ImageId, - IsSystemDisk: true, - } - stroage, err := in.host.zone.getStorageByType(disk.DiskType) - if err != nil { - return nil, errors.Wrapf(err, "unable to find storage with type %s", disk.DiskType) - } - disk.storage = stroage - disks = append(disks, disk) - } - for i := range in.DataDisks { - disk := &SDisk{ - Disk: in.DataDisks[i].CloudDisk, - } - stroage, err := in.host.zone.getStorageByType(disk.DiskType) - if err != nil { - return nil, errors.Wrapf(err, "unable to find storage with type %s", disk.DiskType) - } - disk.storage = stroage - disks = append(disks, disk) - } - return disks, nil -} - -func (in *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nis := make([]cloudprovider.ICloudNic, 0, len(in.SecondaryNetworkInterfaces)+1) - nis = append(nis, &SInstanceNic{ - instance: in, - InstanceNetworkInterface: in.PrimaryNetworkInterface.NetworkInterface, - }) - for i := range in.SecondaryNetworkInterfaces { - nis = append(nis, &SInstanceNic{ - instance: in, - InstanceNetworkInterface: in.SecondaryNetworkInterfaces[i].NetworkInterface, - }) - } - return nis, nil -} - -func (in *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - eip, err := in.host.zone.region.GetEIPById(in.ElasticIpId) - if err != nil { - return nil, err - } - return eip, nil -} - -func (in *SInstance) GetSecurityGroupIds() ([]string, error) { - ids := sets.NewString() - for _, sg := range in.PrimaryNetworkInterface.NetworkInterface.SecurityGroups { - ids.Insert(sg.GroupId) - } - for i := range in.SecondaryNetworkInterfaces { - for _, sg := range in.SecondaryNetworkInterfaces[i].NetworkInterface.SecurityGroups { - ids.Insert(sg.GroupId) - } - } - return ids.UnsortedList(), nil -} - -func (in *SInstance) fetchInstanceType() error { - its, err := in.host.zone.region.InstanceTypes(in.InstanceType) - if err != nil { - return err - } - if len(its) == 0 { - return cloudprovider.ErrNotFound - } - for i := range its { - if its[i].InstanceType.InstanceType == in.InstanceType { - in.instanceType = &its[i] - return nil - } - } - return cloudprovider.ErrNotFound -} - -func (in *SInstance) GetVcpuCount() int { - if in.instanceType == nil { - err := in.fetchInstanceType() - if err != nil { - log.Errorf("unable to get instance type %s: %v", in.InstanceType, err) - return 0 - } - } - return in.instanceType.GetCpu() -} - -func (in *SInstance) GetVmemSizeMB() int { - if in.instanceType == nil { - err := in.fetchInstanceType() - if err != nil { - log.Errorf("unable to get instance type %s", in.InstanceType) - return 0 - } - } - return in.instanceType.GetMemoryMB() -} - -func (in *SInstance) AssignSecurityGroup(id string) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) SetSecurityGroups(ids []string) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) GetHypervisor() string { - return api.HYPERVISOR_JDCLOUD -} - -func (in *SInstance) StartVM(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) DeleteVM(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) UpdateVM(ctx context.Context, name string) error { - return cloudprovider.ErrNotSupported -} - -func (in *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - return "", cloudprovider.ErrNotImplemented -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - region := in.host.zone.region - req := apis.NewDescribeInstanceVncUrlRequest(region.ID, in.InstanceId) - client := client.NewVmClient(region.getCredential()) - client.Logger = Logger{debug: region.client.debug} - resp, err := client.DescribeInstanceVncUrl(req) - if err != nil { - return nil, err - } - - ret := &cloudprovider.ServerVncOutput{ - Url: resp.Result.VncUrl, - Protocol: "jdcloud", - InstanceId: in.GetId(), - Hypervisor: api.HYPERVISOR_JDCLOUD, - } - return ret, nil -} - -func (in *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return cloudprovider.ErrNotImplemented -} - -func (in *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) GetError() error { - return nil -} - -func (r *SRegion) GetInstances(zoneId string, ids []string, pangeNumber, pageSize int) ([]SInstance, int, error) { - filters := []commodels.Filter{} - if zoneId != "" { - filters = append(filters, commodels.Filter{ - Name: "az", - Values: []string{zoneId}, - }) - } - if len(ids) > 0 { - filters = append(filters, commodels.Filter{ - Name: "instanceId", - Values: ids, - }) - } - req := apis.NewDescribeInstancesRequestWithAllParams(r.ID, &pangeNumber, &pageSize, filters) - client := client.NewVmClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeInstances(req) - if err != nil { - return nil, 0, err - } - if resp.Error.Code >= 400 { - return nil, 0, fmt.Errorf(resp.Error.Message) - } - ins := make([]SInstance, len(resp.Result.Instances)) - for i := range ins { - ins[i] = SInstance{ - Instance: resp.Result.Instances[i], - } - } - return ins, resp.Result.TotalCount, nil -} - -func (r *SRegion) GetInstanceById(id string) (*SInstance, error) { - req := apis.NewDescribeInstanceRequest(r.ID, id) - client := client.NewVmClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeInstance(req) - if err != nil { - return nil, err - } - return &SInstance{ - Instance: resp.Result.Instance, - }, nil -} - -func (r *SRegion) FillHost(instance *SInstance) { - izone, err := r.getIZoneByRealId(instance.Az) - if err != nil { - log.Errorf("unable to find zone %s: %v", instance.Az, err) - return - } - zone := izone.(*SZone) - instance.host = &SHost{ - zone: zone, - } -} diff --git a/pkg/multicloud/jdcloud/instancenic.go b/pkg/multicloud/jdcloud/instancenic.go deleted file mode 100644 index b4811a5b34..0000000000 --- a/pkg/multicloud/jdcloud/instancenic.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/models" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - instance *SInstance - cloudprovider.DummyICloudNic - - models.InstanceNetworkInterface -} - -func (in *SInstanceNic) GetIP() string { - return in.PrimaryIp.PrivateIpAddress -} - -func (in *SInstanceNic) GetMAC() string { - return in.MacAddress -} - -func (in *SInstanceNic) GetId() string { - return in.NetworkInterfaceId -} - -func (in *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (in *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (in *SInstanceNic) GetINetworkId() string { - return in.SubnetId -} diff --git a/pkg/multicloud/jdcloud/latitud_and_longitude.go b/pkg/multicloud/jdcloud/latitud_and_longitude.go deleted file mode 100644 index 9e08b4134a..0000000000 --- a/pkg/multicloud/jdcloud/latitud_and_longitude.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ - "cn-south-1": {Latitude: 23.129110, Longitude: 113.264381, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "cn-north-1": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-east-2": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-east-1": {Latitude: 33.939763, Longitude: 118.267582, City: api.CITY_SU_QIAN, CountryCode: api.COUNTRY_CODE_CN}, -} diff --git a/pkg/multicloud/jdcloud/monitor.go b/pkg/multicloud/jdcloud/monitor.go deleted file mode 100644 index 5b17c516e9..0000000000 --- a/pkg/multicloud/jdcloud/monitor.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - "strconv" - "time" - - jc_apis "github.com/jdcloud-api/jdcloud-sdk-go/services/monitor/apis" - client "github.com/jdcloud-api/jdcloud-sdk-go/services/monitor/client" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/timeutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -func (self *SJDCloudClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_RDS: - return self.GetRdsMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) - } -} - -func (self *SJDCloudClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - for metricType, metricName := range map[cloudprovider.TMetricType]string{ - cloudprovider.VM_METRIC_TYPE_CPU_USAGE: "cpu_util", - cloudprovider.VM_METRIC_TYPE_MEM_USAGE: "memory.usage", - cloudprovider.VM_METRIC_TYPE_DISK_USAGE: "vm.disk.dev.used", - cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: "vm.network.dev.bytes.in", - cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: "vm.network.dev.bytes.out", - cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: "vm.disk.dev.bytes.read", - cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: "vm.disk.dev.bytes.write", - cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: "vm.disk.dev.io.read", - cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: "vm.disk.dev.io.write", - } { - - aggrType, downSampleType, serviceCode := "avg", "avg", "vm" - startTime, endTime := opts.StartTime.Format(timeutils.FullIsoTimeFormat), opts.EndTime.Format(timeutils.FullIsoTimeFormat) - request := jc_apis.NewDescribeMetricDataRequestWithAllParams(opts.RegionExtId, metricName, &aggrType, &downSampleType, &startTime, &endTime, nil, nil, nil, nil, &serviceCode, nil, opts.ResourceId) - monitorClient := client.NewMonitorClient(self.getCredential()) - monitorClient.Logger = Logger{debug: self.debug} - response, err := monitorClient.DescribeMetricData(request) - if err != nil { - return nil, err - } - metric := cloudprovider.MetricValues{} - metric.Id = opts.ResourceId - metric.MetricType = metricType - for _, data := range response.Result.MetricDatas { - for _, value := range data.Data { - metricValue := cloudprovider.MetricValue{} - metricValue.Timestamp = time.Unix(value.Timestamp/1000, 0) - if value.Value == nil { - continue - } - metricValue.Value, err = strconv.ParseFloat(fmt.Sprintf("%s", value.Value), 64) - if err != nil { - log.Errorf("parse value %v error: %v", value.Value, nil) - continue - } - metric.Values = append(metric.Values, metricValue) - } - } - ret = append(ret, metric) - } - return ret, nil -} - -func (self *SJDCloudClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - metrics := map[cloudprovider.TMetricType]string{} - switch opts.Engine { - case api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_SQLSERVER, api.DBINSTANCE_TYPE_PERCONA, api.DBINSTANCE_TYPE_MARIADB: - metrics = map[cloudprovider.TMetricType]string{ - cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: "database.docker.cpu.util", - cloudprovider.RDS_METRIC_TYPE_MEM_USAGE: "database.docker.memory.pused", - cloudprovider.RDS_METRIC_TYPE_DISK_USAGE: "database.docker.disk1.used", - cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: "database.docker.network.incoming", - cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: "database.docker.network.outgoing", - } - case api.DBINSTANCE_TYPE_POSTGRESQL: - metrics = map[cloudprovider.TMetricType]string{ - cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: "database.docker.cpu.util", - cloudprovider.RDS_METRIC_TYPE_MEM_USAGE: "database.docker.memory.pused", - cloudprovider.RDS_METRIC_TYPE_DISK_USAGE: "database.docker.disk1.used", - cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: "database.docker.network.incoming", - cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: "database.docker.network.outgoing", - } - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.Engine) - } - ret := []cloudprovider.MetricValues{} - aggrType, downSampleType := "avg", "avg" - startTime, endTime := opts.StartTime.Format(timeutils.FullIsoTimeFormat), opts.EndTime.Format(timeutils.FullIsoTimeFormat) - serviceCode := map[string]string{ - api.DBINSTANCE_TYPE_SQLSERVER: "sqlserver", - api.DBINSTANCE_TYPE_MYSQL: "database", - api.DBINSTANCE_TYPE_PERCONA: "percona", - api.DBINSTANCE_TYPE_MARIADB: "mariadb", - api.DBINSTANCE_TYPE_POSTGRESQL: "pag", - }[opts.Engine] - for metricType, metricName := range metrics { - request := jc_apis.NewDescribeMetricDataRequestWithAllParams(opts.RegionExtId, metricName, &aggrType, &downSampleType, &startTime, &endTime, nil, nil, nil, nil, &serviceCode, nil, opts.ResourceId) - monitorClient := client.NewMonitorClient(self.getCredential()) - monitorClient.Logger = Logger{} - response, err := monitorClient.DescribeMetricData(request) - if err != nil { - return nil, err - } - metric := cloudprovider.MetricValues{} - metric.Id = opts.ResourceId - metric.MetricType = metricType - for _, data := range response.Result.MetricDatas { - for _, value := range data.Data { - metricValue := cloudprovider.MetricValue{} - metricValue.Timestamp = time.Unix(value.Timestamp/1000, 0) - if value.Value == nil { - continue - } - metricValue.Value, err = strconv.ParseFloat(fmt.Sprintf("%s", value.Value), 64) - if err != nil { - log.Errorf("parse value %v error: %v", value.Value, nil) - continue - } - // kbps -> byte - if opts.Engine != api.DBINSTANCE_TYPE_POSTGRESQL && (metricType == cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX || metricType == cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX) { - metricValue.Value = metricValue.Value / 1024.0 - } - metric.Values = append(metric.Values, metricValue) - } - } - ret = append(ret, metric) - } - return ret, nil -} diff --git a/pkg/multicloud/jdcloud/network.go b/pkg/multicloud/jdcloud/network.go deleted file mode 100644 index 188c2a921e..0000000000 --- a/pkg/multicloud/jdcloud/network.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - - commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/apis" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/client" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/models" - - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.JdcloudTags - - wire *SWire - - models.Subnet -} - -func (n *SNetwork) GetId() string { - return n.SubnetId -} - -func (n *SNetwork) GetName() string { - return n.SubnetName -} - -func (n *SNetwork) GetGlobalId() string { - return n.GetId() -} - -func (n *SNetwork) GetStatus() string { - return api.NETWORK_STATUS_AVAILABLE -} - -func (n *SNetwork) Refresh() error { - return nil -} - -func (n *SNetwork) IsEmulated() bool { - return false -} - -func (n *SNetwork) GetProjectId() string { - return "" -} - -func (n *SNetwork) GetIWire() cloudprovider.ICloudWire { - return n.wire -} - -func (n *SNetwork) GetIpStart() string { - return n.StartIp -} - -func (n *SNetwork) GetIpEnd() string { - return n.EndIp -} - -func (n *SNetwork) Cidr() string { - return n.AddressPrefix -} - -func (n *SNetwork) GetIpMask() int8 { - pref, _ := netutils.NewIPV4Prefix(n.Cidr()) - return pref.MaskLen -} - -func (n *SNetwork) GetGateway() string { - return "" -} - -func (n *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (n *SNetwork) GetIsPublic() bool { - return true -} - -func (n *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (n *SNetwork) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (n *SNetwork) GetAllocTimeoutSeconds() int { - return 120 -} - -func (r *SRegion) GetNetworks(vpcId string, pageNumber int, pageSize int) ([]SNetwork, int, error) { - filters := []commodels.Filter{} - if vpcId != "" { - filters = append(filters, commodels.Filter{ - Name: "vpcId", - Values: []string{vpcId}, - }) - } - req := apis.NewDescribeSubnetsRequestWithAllParams(r.ID, &pageNumber, &pageSize, filters) - client := client.NewVpcClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeSubnets(req) - if err != nil { - return nil, 0, err - } - if resp.Error.Code >= 400 { - return nil, 0, fmt.Errorf(resp.Error.Message) - } - nets := make([]SNetwork, len(resp.Result.Subnets)) - for i := range nets { - nets[i] = SNetwork{ - Subnet: resp.Result.Subnets[i], - } - } - return nets, resp.Result.TotalCount, nil -} - -func (r *SRegion) GetNetworkById(id string) (*SNetwork, error) { - req := apis.NewDescribeSubnetRequest(r.ID, id) - client := client.NewVpcClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeSubnet(req) - if err != nil { - return nil, err - } - if resp.Error.Code >= 400 { - return nil, fmt.Errorf(resp.Error.Message) - } - return &SNetwork{ - Subnet: resp.Result.Subnet, - }, nil -} diff --git a/pkg/multicloud/jdcloud/networkinterface.go b/pkg/multicloud/jdcloud/networkinterface.go deleted file mode 100644 index a479883784..0000000000 --- a/pkg/multicloud/jdcloud/networkinterface.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/models" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNetworkInterface struct { - multicloud.SNetworkInterfaceBase - multicloud.JdcloudTags - region *SRegion - - models.NetworkInterface -} - -func (nic *SNetworkInterface) GetId() string { - return nic.NetworkInterfaceId -} - -func (nic *SNetworkInterface) GetName() string { - return nic.NetworkInterfaceName -} - -func (nic *SNetworkInterface) GetGlobalId() string { - return nic.GetId() -} - -func (nic *SNetworkInterface) GetAssociateId() string { - return nic.InstanceId -} - -func (nic *SNetworkInterface) GetAssociateType() string { - if nic.InstanceType == "vm" { - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER - } - return "" -} - -func (nic *SNetworkInterface) GetMacAddress() string { - return nic.MacAddress -} - -func (nic *SNetworkInterface) GetStatus() string { - switch nic.NetworkInterfaceStatus { - case "enabled": - return api.NETWORK_INTERFACE_STATUS_AVAILABLE - case "disabled": - return api.NETWORK_INTERFACE_STATUS_DISABLED - } - return api.NETWORK_INTERFACE_STATUS_UNKNOWN -} - -type SNetworkInterfacePrivateIp struct { - subnetId string - isPrimary bool - models.NetworkInterfacePrivateIp -} - -func (ip *SNetworkInterfacePrivateIp) GetGlobalId() string { - return ip.PrivateIpAddress -} - -func (ip *SNetworkInterfacePrivateIp) GetINetworkId() string { - return ip.subnetId -} - -func (ip *SNetworkInterfacePrivateIp) GetIP() string { - return ip.PrivateIpAddress -} - -func (ip *SNetworkInterfacePrivateIp) IsPrimary() bool { - return ip.isPrimary -} - -func (nic *SNetworkInterface) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { - address := make([]cloudprovider.ICloudInterfaceAddress, 0, len(nic.SecondaryIps)+1) - address = append(address, &SNetworkInterfacePrivateIp{ - subnetId: nic.SubnetId, - isPrimary: true, - NetworkInterfacePrivateIp: nic.PrimaryIp, - }) - for i := range nic.SecondaryIps { - address = append(address, &SNetworkInterfacePrivateIp{ - subnetId: nic.SubnetId, - isPrimary: false, - NetworkInterfacePrivateIp: nic.SecondaryIps[i], - }) - } - return address, nil -} diff --git a/pkg/multicloud/jdcloud/provider/doc.go b/pkg/multicloud/jdcloud/provider/doc.go deleted file mode 100644 index 60f657a42d..0000000000 --- a/pkg/multicloud/jdcloud/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/jdcloud/provider" diff --git a/pkg/multicloud/jdcloud/provider/provider.go b/pkg/multicloud/jdcloud/provider/provider.go deleted file mode 100644 index 7816a68c1f..0000000000 --- a/pkg/multicloud/jdcloud/provider/provider.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/jdcloud" -) - -type SJdcloudProviderFactory struct { - cloudprovider.SPublicCloudBaseProviderFactory -} - -func (f *SJdcloudProviderFactory) GetId() string { - return jdcloud.CLOUD_PROVIDER_JDCLOUD -} - -func (f *SJdcloudProviderFactory) GetName() string { - return jdcloud.CLOUD_PROVIDER_JDCLOUD_CN -} - -func (f *SJdcloudProviderFactory) IsSupportPrepaidResources() bool { - return true -} - -func (f *SJdcloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - return output, nil -} - -func (f *SJdcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func (f *SJdcloudProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - segs := strings.Split(cfg.Account, "/") - account := cfg.Account - if len(segs) == 2 { - account = segs[0] - } - client, err := jdcloud.NewJDCloudClient( - jdcloud.NewJDCloudClientConfig( - account, - cfg.Secret, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - - return &SJdcloudProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(f), - client: client, - }, nil -} - -func (f *SJdcloudProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - return map[string]string{ - "JDCLOUD_ACCESS_KEY": info.Account, - "JDCLOUD_SECRET": info.Secret, - "JDCLOUD_REGION": jdcloud.JDCLOUD_DEFAULT_REGION, - }, nil -} - -func init() { - factory := SJdcloudProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SJdcloudProvider struct { - cloudprovider.SBaseProvider - - client *jdcloud.SJDCloudClient -} - -func (p *SJdcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return p.client.GetSubAccounts() -} - -func (p *SJdcloudProvider) GetAccountId() string { - return p.client.GetAccountId() -} - -func (p *SJdcloudProvider) GetIRegions() []cloudprovider.ICloudRegion { - return p.client.GetIRegions() -} - -func (p *SJdcloudProvider) GetSysInfo() (jsonutils.JSONObject, error) { - iregions := p.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(iregions))), "region_count") - return info, nil -} - -func (p *SJdcloudProvider) GetVersion() string { - return "" -} - -func (p *SJdcloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - iregions := p.GetIRegions() - for i := range iregions { - if iregions[i].GetGlobalId() == id { - return iregions[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (p *SJdcloudProvider) GetBalance() (float64, string, error) { - balance, err := p.client.DescribeAccountAmount() - if err != nil { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NO_PERMISSION, errors.Wrap(err, "DescribeAccountAmount") - } - amount, _ := jsonutils.Marshal(balance).Float("totalAmount") - if amount < 0 { - return amount, api.CLOUD_PROVIDER_HEALTH_ARREARS, nil - } else if amount < 50 { - return amount, api.CLOUD_PROVIDER_HEALTH_INSUFFICIENT, nil - } - return amount, api.CLOUD_PROVIDER_HEALTH_NORMAL, nil -} - -func (p *SJdcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (p *SJdcloudProvider) GetStorageClasses(regionId string) []string { - // TODO - return nil -} - -func (p *SJdcloudProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (p *SJdcloudProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (p *SJdcloudProvider) GetCloudRegionExternalIdPrefix() string { - return api.CLOUD_PROVIDER_JDCLOUD -} - -func (p *SJdcloudProvider) GetCapabilities() []string { - iRegions := p.GetIRegions() - if len(iRegions) > 0 { - return iRegions[0].GetCapabilities() - } - caps := []string{ - cloudprovider.CLOUD_CAPABILITY_COMPUTE + cloudprovider.READ_ONLY_SUFFIX, - cloudprovider.CLOUD_CAPABILITY_NETWORK + cloudprovider.READ_ONLY_SUFFIX, - cloudprovider.CLOUD_CAPABILITY_EIP + cloudprovider.READ_ONLY_SUFFIX, - cloudprovider.CLOUD_CAPABILITY_RDS + cloudprovider.READ_ONLY_SUFFIX, - } - return caps -} - -func (self *SJdcloudProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/jdcloud/rds.go b/pkg/multicloud/jdcloud/rds.go deleted file mode 100644 index 1c8a981fce..0000000000 --- a/pkg/multicloud/jdcloud/rds.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - "strconv" - "strings" - "time" - - commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" - "github.com/jdcloud-api/jdcloud-sdk-go/services/rds/apis" - "github.com/jdcloud-api/jdcloud-sdk-go/services/rds/client" - "github.com/jdcloud-api/jdcloud-sdk-go/services/rds/models" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDBInstance struct { - multicloud.SDBInstanceBase - multicloud.JdcloudTags - region *SRegion - - models.DBInstance -} - -func (self *SDBInstance) GetName() string { - return self.InstanceName -} - -func (self *SDBInstance) GetInstanceType() string { - return self.InstanceClass -} - -func (self *SDBInstance) GetCategory() string { - return self.InstanceType -} - -func (self *SDBInstance) GetDiskSizeGB() int { - return self.InstanceStorageGB -} - -func (self *SDBInstance) GetEngine() string { - return self.Engine -} - -func (self *SDBInstance) GetEngineVersion() string { - return self.EngineVersion -} - -func (self *SDBInstance) GetGlobalId() string { - return self.InstanceId -} - -func (self *SDBInstance) GetId() string { - return self.InstanceId -} - -func (self *SDBInstance) GetIVpcId() string { - return self.VpcId -} - -func (self *SDBInstance) Refresh() error { - rds, err := self.region.GetDBInstance(self.InstanceId) - if err != nil { - return err - } - return jsonutils.Update(self, rds) -} - -func (self *SDBInstance) GetMaintainTime() string { - return "" -} - -func (self *SDBInstance) GetMasterInstanceId() string { - return self.SourceInstanceId -} - -func (self *SDBInstance) GetPort() int { - if len(self.InstancePort) == 0 { - self.Refresh() - } - port, _ := strconv.Atoi(self.InstancePort) - return int(port) -} - -func (self *SDBInstance) GetCreatedAt() time.Time { - return parseTime(self.CreateTime) -} - -func (self *SDBInstance) GetExpiredAt() time.Time { - return expireAt(&self.Charge) -} - -func (self *SDBInstance) GetStatus() string { - switch self.InstanceStatus { - case "BUILDING", "DDLING", "PARAMETERGROUP_MODIFYING", "AUDIT_OPENING", "AUDIT_CLOSING", "SECURITY_OPENING", "SECURITY_CLOSING", "SSL_OPENING", "SSL_CLOSING": - return api.DBINSTANCE_DEPLOYING - case "RUNNING": - return api.DBINSTANCE_RUNNING - case "DELETING": - return api.DBINSTANCE_DELETING - case "FAILOVER", "AZ_MIGRATING": - return api.DBINSTANCE_MIGRATING - case "RESTORING", "DB_RESTORING": - return api.DBINSTANCE_RESTORING - case "MODIFYING": - return api.DBINSTANCE_CHANGE_CONFIG - case "BUILD_READONLY": - return api.DBINSTANCE_DEPLOYING - case "REBOOTING": - return api.DBINSTANCE_REBOOTING - case "MAINTENANCE": - return api.DBINSTANCE_MAINTENANCE - default: - return self.InstanceStatus - } -} - -func (self *SDBInstance) GetStorageType() string { - return self.InstanceStorageType -} - -func (self *SDBInstance) GetVcpuCount() int { - return self.InstanceCPU -} - -func (self *SDBInstance) GetVmemSizeMB() int { - return self.InstanceMemoryMB -} - -func (self *SDBInstance) GetZone1Id() string { - if len(self.AzId) > 0 { - return self.AzId[0] - } - return "" -} - -func (self *SDBInstance) GetZone2Id() string { - if len(self.AzId) > 1 { - return self.AzId[1] - } - return "" -} - -func (self *SDBInstance) GetZone3Id() string { - if len(self.AzId) > 2 { - return self.AzId[2] - } - return "" -} - -func (self *SDBInstance) GetConnectionStr() string { - return self.PublicDomainName -} - -func (self *SDBInstance) GetInternalConnectionStr() string { - return self.InternalDomainName -} - -func (self *SDBInstance) Delete() error { - return self.region.DeleteDBInstance(self.InstanceId) -} - -func (self *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - rds := []SDBInstance{} - n := 1 - for { - part, total, err := self.GetDBInstances(n, 100) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstances") - } - rds = append(rds, part...) - if len(rds) >= total { - break - } - n++ - } - ret := []cloudprovider.ICloudDBInstance{} - for i := range rds { - ret = append(ret, &rds[i]) - } - return ret, nil -} - -func (self *SRegion) GetIDBInstanceById(id string) (cloudprovider.ICloudDBInstance, error) { - rds, err := self.GetDBInstance(id) - if err != nil { - return nil, errors.Wrapf(err, "GetDBInstance(%s)", id) - } - return rds, nil -} - -func (self *SRegion) GetDBInstance(id string) (*SDBInstance, error) { - req := apis.NewDescribeInstanceAttributesRequest(self.ID, id) - client := client.NewRdsClient(self.getCredential()) - client.Logger = Logger{debug: self.client.debug} - resp, err := client.DescribeInstanceAttributes(req) - if err != nil { - return nil, errors.Wrapf(err, "DescribeInstanceAttributes") - } - if resp.Error.Code == 404 || strings.Contains(resp.Error.Status, "NotFound") { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, jsonutils.Marshal(resp.Error).String()) - } else if resp.Error.Code != 0 { - return nil, errors.Error(jsonutils.Marshal(resp.Error).String()) - } - ret := SDBInstance{ - region: self, - } - jsonutils.Update(&ret.DBInstance, resp.Result.DbInstanceAttributes) - return &ret, nil -} - -func (self *SRegion) DeleteDBInstance(id string) error { - req := apis.NewDeleteInstanceRequest(self.ID, id) - client := client.NewRdsClient(self.getCredential()) - client.Logger = Logger{} - resp, err := client.DeleteInstance(req) - if err != nil { - return err - } - if resp.Error.Code == 404 { - return nil - } - return nil -} - -func (self *SRegion) GetDBInstances(pageNumber int, pageSize int) ([]SDBInstance, int, error) { - req := apis.NewDescribeInstancesRequestWithAllParams(self.ID, &pageNumber, &pageSize, []commodels.Filter{}, []commodels.TagFilter{}) - client := client.NewRdsClient(self.getCredential()) - client.Logger = Logger{debug: self.client.debug} - resp, err := client.DescribeInstances(req) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeInstances") - } - if resp.Error.Code >= 400 { - err = fmt.Errorf(resp.Error.Message) - return nil, 0, err - } - total := resp.Result.TotalCount - ret := []SDBInstance{} - for i := range resp.Result.DbInstances { - ret = append(ret, SDBInstance{ - region: self, - DBInstance: resp.Result.DbInstances[i], - }) - } - return ret, total, nil -} diff --git a/pkg/multicloud/jdcloud/region.go b/pkg/multicloud/jdcloud/region.go deleted file mode 100644 index d33727e683..0000000000 --- a/pkg/multicloud/jdcloud/region.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - - "github.com/jdcloud-api/jdcloud-sdk-go/core" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - CLOUD_PROVIDER_JDCLOUD = api.CLOUD_PROVIDER_JDCLOUD - CLOUD_PROVIDER_JDCLOUD_CN = "京东云" - CLOUD_PROVIDER_JDCLOUD_EN = "JDcloud" - - JDCLOUD_DEFAULT_REGION = "cn-north-1" -) - -var regionList = map[string]string{ - "cn-north-1": "华北-北京", - "cn-east-1": "华东-宿迁", - "cn-east-2": "华东-上海", - "cn-south-1": "华南-广州", -} - -type SRegion struct { - cloudprovider.SFakeOnPremiseRegion - multicloud.SRegion - multicloud.SNoObjectStorageRegion - - client *SJDCloudClient - - cpcfg cloudprovider.ProviderConfig - storageCache *SStoragecache - - ID string `json:"id"` - Name string `json:"Name"` - - izones []cloudprovider.ICloudZone - ivpcs []cloudprovider.ICloudVpc -} - -func (self *SRegion) GetClient() *SJDCloudClient { - return self.client -} - -func (self *SRegion) getCredential() *core.Credential { - return self.client.getCredential() -} - -func (r *SRegion) GetId() string { - return r.ID -} - -func (r *SRegion) GetName() string { - return r.Name -} - -func (r *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", api.CLOUD_ACCESS_ENV_JDCLOUD_CHINA, r.GetId()) -} - -func (r *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (r *SRegion) Refresh() error { - return nil -} - -func (r *SRegion) IsEmulated() bool { - return false -} - -func (r *SRegion) GetI18n() cloudprovider.SModelI18nTable { - en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_JDCLOUD_EN, r.Name) - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(r.GetName()).CN(r.GetName()).EN(en) - return table -} - -func (r *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - if info, ok := LatitudeAndLongitude[r.ID]; ok { - return info - } - return cloudprovider.SGeographicInfo{} -} - -func (r *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if r.izones == nil { - err := r.fetchZones() - if err != nil { - return nil, err - } - } - return r.izones, nil -} - -func (r *SRegion) fetchZones() error { - zoneIdens := ZonesInRegion[r.ID] - r.izones = make([]cloudprovider.ICloudZone, 0, len(zoneIdens)) - for _, iden := range zoneIdens { - zone := SZone{ - region: r, - ID: iden.Id, - Name: iden.Name, - } - r.izones = append(r.izones, &zone) - } - return nil -} - -func (r *SRegion) fetchVpcs() error { - vpcs := make([]SVpc, 0) - n := 1 - for { - part, total, err := r.GetVpcs(n, 100) - if err != nil { - return err - } - vpcs = append(vpcs, part...) - if len(vpcs) >= total { - break - } - n++ - } - r.ivpcs = make([]cloudprovider.ICloudVpc, len(vpcs)) - for i := 0; i < len(vpcs); i++ { - r.ivpcs[i] = &vpcs[i] - } - return nil -} - -func (r *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - if r.ivpcs == nil { - err := r.fetchVpcs() - if err != nil { - return nil, err - } - } - return r.ivpcs, nil -} - -func (r *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - return nil, nil -} - -func (r *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - vpc, err := r.GetVpcById(id) - if err != nil { - return nil, err - } - return vpc, nil -} - -func (r *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := r.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (r *SRegion) getIZoneByRealId(id string) (cloudprovider.ICloudZone, error) { - izones, err := r.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - if izones[i].GetId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (r *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (r *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := r.GetInstanceById(id) - if err != nil { - return nil, err - } - izone, err := r.getIZoneByRealId(vm.Az) - if err != nil { - return nil, err - } - zone := izone.(*SZone) - vm.host = &SHost{ - zone: zone, - } - return vm, nil -} - -func (r *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return r.GetDiskById(id) -} - -func (r *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - izones, err := r.GetIZones() - if err != nil { - return nil, err - } - iHosts := make([]cloudprovider.ICloudHost, 0, len(izones)) - for i := range izones { - hosts, err := izones[i].GetIHosts() - if err != nil { - return nil, err - } - iHosts = append(iHosts, hosts...) - } - return iHosts, nil -} - -func (r *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - hosts, err := r.GetIHosts() - if err != nil { - return nil, err - } - for i := range hosts { - if hosts[i].GetGlobalId() == id { - return hosts[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (r *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := r.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -func (r *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - istores, err := r.GetIStorages() - if err != nil { - return nil, err - } - for i := range istores { - if istores[i].GetGlobalId() == id { - return istores[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (r *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - sc := r.getStoragecache() - return []cloudprovider.ICloudStoragecache{sc}, nil -} - -func (s *SRegion) getStoragecache() *SStoragecache { - if s.storageCache == nil { - s.storageCache = &SStoragecache{region: s} - } - return s.storageCache -} - -func (r *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - storageCache := r.getStoragecache() - if storageCache.GetGlobalId() == id { - return storageCache, nil - } - return nil, cloudprovider.ErrNotFound -} - -func (r *SRegion) GetProvider() string { - return api.CLOUD_PROVIDER_JDCLOUD -} - -func (r *SRegion) GetCapabilities() []string { - return []string{ - cloudprovider.CLOUD_CAPABILITY_COMPUTE + cloudprovider.READ_ONLY_SUFFIX, - cloudprovider.CLOUD_CAPABILITY_NETWORK + cloudprovider.READ_ONLY_SUFFIX, - cloudprovider.CLOUD_CAPABILITY_EIP + cloudprovider.READ_ONLY_SUFFIX, - cloudprovider.CLOUD_CAPABILITY_RDS + cloudprovider.READ_ONLY_SUFFIX, - } -} diff --git a/pkg/multicloud/jdcloud/securitygroup.go b/pkg/multicloud/jdcloud/securitygroup.go deleted file mode 100644 index 6d8635f4b2..0000000000 --- a/pkg/multicloud/jdcloud/securitygroup.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - "net" - - commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/apis" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/client" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/models" - - "yunion.io/x/pkg/util/secrules" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.JdcloudTags - - vpc *SVpc - models.NetworkSecurityGroup -} - -func (sg *SSecurityGroup) GetVpcId() string { - return sg.VpcId -} - -func (sg *SSecurityGroup) GetId() string { - return sg.NetworkSecurityGroupId -} - -func (sg *SSecurityGroup) GetGlobalId() string { - return sg.GetId() -} - -func (sg *SSecurityGroup) GetName() string { - return sg.NetworkSecurityGroupName -} - -func (sg *SSecurityGroup) GetDescription() string { - return sg.Description -} - -func (sg *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - rules := sg.SecurityGroupRules - srs := make([]cloudprovider.SecurityRule, 0, len(rules)) - for i := range rules { - rule := secrules.SecurityRule{ - Priority: 1, - } - - if rules[i].Direction == 0 { - rule.Direction = secrules.SecurityRuleIngress - } else { - rule.Direction = secrules.SecurityRuleEgress - } - - switch rules[i].Protocol { - case 6: - rule.Protocol = secrules.PROTO_TCP - case 17: - rule.Protocol = secrules.PROTO_UDP - case 1: - rule.Protocol = secrules.PROTO_ICMP - case 300: - rule.Protocol = secrules.PROTO_ANY - } - - _, rule.IPNet, _ = net.ParseCIDR(rules[i].AddressPrefix) - rule.Description = rules[i].Description - rule.PortStart = rules[i].FromPort - rule.PortEnd = rules[i].ToPort - rule.Action = secrules.SecurityRuleAllow - - if rules[i].RuleType == "default" && rules[i].FromPort == 0 && rules[i].ToPort == 0 { - rule.Action = secrules.SecurityRuleDeny - } - - sr := cloudprovider.SecurityRule{ - Id: rules[i].RuleId, - ExternalId: rules[i].RuleId, - SecurityRule: rule, - } - srs = append(srs, sr) - } - return srs, nil -} - -func (sg *SSecurityGroup) GetStatus() string { - return "" -} - -func (sg *SSecurityGroup) IsEmulated() bool { - return false -} - -func (sg *SSecurityGroup) Refresh() error { - return nil -} - -func (sg *SSecurityGroup) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (sg *SSecurityGroup) GetProjectId() string { - return "" -} - -func (sg *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - return nil -} - -func (r *SRegion) GetSecurityGroups(vpcId string, securityGroupIds []string, pageNumber int, pageSize int) ([]SSecurityGroup, int, error) { - filters := []commodels.Filter{} - if vpcId != "" { - filters = append(filters, commodels.Filter{ - Name: "vpcId", - Values: []string{vpcId}, - }) - } - if len(securityGroupIds) > 0 { - filters = append(filters, commodels.Filter{ - Name: "networkSecurityGroupIds", - Values: securityGroupIds, - }) - } - req := apis.NewDescribeNetworkSecurityGroupsRequestWithAllParams(r.ID, &pageNumber, &pageSize, filters) - client := client.NewVpcClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeNetworkSecurityGroups(req) - if err != nil { - return nil, 0, err - } - if resp.Error.Code >= 400 { - err = fmt.Errorf(resp.Error.Message) - return nil, 0, err - } - total := resp.Result.TotalCount - sgs := make([]SSecurityGroup, 0, len(resp.Result.NetworkSecurityGroups)) - for i := range resp.Result.NetworkSecurityGroups { - sgs = append(sgs, SSecurityGroup{ - NetworkSecurityGroup: resp.Result.NetworkSecurityGroups[i], - }) - } - return sgs, total, nil -} diff --git a/pkg/multicloud/jdcloud/shell/balance.go b/pkg/multicloud/jdcloud/shell/balance.go deleted file mode 100644 index 09faa6c571..0000000000 --- a/pkg/multicloud/jdcloud/shell/balance.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/jdcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type BalanceShowOptions struct { - } - shellutils.R(&BalanceShowOptions{}, "balance-show", "Show balance", func(cli *jdcloud.SRegion, args *BalanceShowOptions) error { - balance, err := cli.GetClient().DescribeAccountAmount() - if err != nil { - return err - } - printObject(balance) - return nil - }) -} diff --git a/pkg/multicloud/jdcloud/shell/doc.go b/pkg/multicloud/jdcloud/shell/doc.go deleted file mode 100644 index 563f26ba3e..0000000000 --- a/pkg/multicloud/jdcloud/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/jdcloud/shell" diff --git a/pkg/multicloud/jdcloud/shell/image.go b/pkg/multicloud/jdcloud/shell/image.go deleted file mode 100644 index e64cd6c753..0000000000 --- a/pkg/multicloud/jdcloud/shell/image.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/jdcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VImageListOptions struct { - ListOptions - SOURCE string `help:"image source" choices:"public|private|shared|thirdparty|community"` - } - shellutils.R(&VImageListOptions{}, "image-list", "List images", func(cli *jdcloud.SRegion, args *VImageListOptions) error { - images, total, e := cli.GetImages(nil, args.SOURCE, args.Offset+1, args.Limit) - if e != nil { - return e - } - printList(images, total, args.Offset, args.Limit, nil) - return nil - }) -} diff --git a/pkg/multicloud/jdcloud/shell/instance.go b/pkg/multicloud/jdcloud/shell/instance.go deleted file mode 100644 index 15a04e99c2..0000000000 --- a/pkg/multicloud/jdcloud/shell/instance.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/jdcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - ListOptions - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List intances", func(cli *jdcloud.SRegion, args *InstanceListOptions) error { - instances, total, e := cli.GetInstances("", nil, args.Offset+1, args.Limit) - if e != nil { - return e - } - printList(instances, total, args.Offset, args.Limit, []string{}) - return nil - }) - type InstanceShowOptions struct { - ID string - } - shellutils.R(&InstanceShowOptions{}, "instance-show", "Show intances", func(cli *jdcloud.SRegion, args *InstanceShowOptions) error { - instance, e := cli.GetInstanceById(args.ID) - if e != nil { - return e - } - printObject(instance) - return nil - }) - shellutils.R(&InstanceShowOptions{}, "instance-nic-list", "List intance nics", func(cli *jdcloud.SRegion, args *InstanceShowOptions) error { - instance, e := cli.GetInstanceById(args.ID) - if e != nil { - return e - } - cli.FillHost(instance) - nics, err := instance.GetINics() - if err != nil { - return err - } - printList(nics, 0, 0, 0, []string{}) - return nil - }) - shellutils.R(&InstanceShowOptions{}, "instance-disk-list", "List intance disks", func(cli *jdcloud.SRegion, args *InstanceShowOptions) error { - instance, e := cli.GetInstanceById(args.ID) - if e != nil { - return e - } - cli.FillHost(instance) - disks, err := instance.GetIDisks() - if err != nil { - return err - } - printList(disks, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/jdcloud/shell/monitor.go b/pkg/multicloud/jdcloud/shell/monitor.go deleted file mode 100644 index 7ae4f56f05..0000000000 --- a/pkg/multicloud/jdcloud/shell/monitor.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/jdcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics", func(cli *jdcloud.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric: %s %s %s", metrics[i].Id, metrics[i].MetricType, metrics[i].Unit) - printList(metrics[i].Values, len(metrics[i].Values), 0, 0, []string{}) - } - return nil - }) -} diff --git a/pkg/multicloud/jdcloud/shell/network.go b/pkg/multicloud/jdcloud/shell/network.go deleted file mode 100644 index 23c474c57e..0000000000 --- a/pkg/multicloud/jdcloud/shell/network.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/jdcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VNetworkListOptions struct { - VPCID string `help:"Vpc ID"` - } - shellutils.R(&VNetworkListOptions{}, "subnet-list", "List subnets", func(cli *jdcloud.SRegion, args *VNetworkListOptions) error { - ivpc, err := cli.GetIVpcById(args.VPCID) - if err != nil { - return err - } - vpc := ivpc.(*jdcloud.SVpc) - wire := vpc.GetWire() - networks, err := wire.GetINetworks() - if err != nil { - return err - } - printList(networks, 0, 0, 0, nil) - return nil - }) - shellutils.R(&VNetworkListOptions{}, "secgroup-list", "List secgroup", func(cli *jdcloud.SRegion, args *VNetworkListOptions) error { - ivpc, err := cli.GetIVpcById(args.VPCID) - if err != nil { - return err - } - segs, err := ivpc.GetISecurityGroups() - if err != nil { - return err - } - printList(segs, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/jdcloud/shell/rds.go b/pkg/multicloud/jdcloud/shell/rds.go deleted file mode 100644 index e838786015..0000000000 --- a/pkg/multicloud/jdcloud/shell/rds.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/jdcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DBInstanceListOptions struct { - PageNumber int `default:"1"` - PageSize int `default:"100"` - } - - shellutils.R(&DBInstanceListOptions{}, "dbinstance-list", "List rds", func(cli *jdcloud.SRegion, args *DBInstanceListOptions) error { - dbs, _, err := cli.GetDBInstances(args.PageNumber, args.PageSize) - if err != nil { - return err - } - printList(dbs, 0, 0, 0, nil) - return nil - }) - - type DBInstanceIdOptions struct { - ID string - } - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-show", "Show rds", func(cli *jdcloud.SRegion, args *DBInstanceIdOptions) error { - rds, err := cli.GetDBInstance(args.ID) - if err != nil { - return err - } - printObject(rds) - return nil - }) - - shellutils.R(&DBInstanceIdOptions{}, "dbinstance-delete", "Delete rds", func(cli *jdcloud.SRegion, args *DBInstanceIdOptions) error { - return cli.DeleteDBInstance(args.ID) - }) - - type DBInstanceAccountListOptions struct { - PageNumber int `default:"1"` - PageSize int `default:"100"` - ID string - } - - shellutils.R(&DBInstanceAccountListOptions{}, "dbinstance-account-list", "List rds account", func(cli *jdcloud.SRegion, args *DBInstanceAccountListOptions) error { - accounts, _, err := cli.GetDBInstanceAccounts(args.ID, args.PageNumber, args.PageSize) - if err != nil { - return err - } - printList(accounts, 0, 0, 0, nil) - return nil - }) - - type DBInstanceDatabaseListOptions struct { - PageNumber int `default:"1"` - PageSize int `default:"100"` - ID string - } - - shellutils.R(&DBInstanceDatabaseListOptions{}, "dbinstance-database-list", "List rds database", func(cli *jdcloud.SRegion, args *DBInstanceDatabaseListOptions) error { - databases, _, err := cli.GetDBInstanceDatabases(args.ID, args.PageNumber, args.PageSize) - if err != nil { - return err - } - printList(databases, 0, 0, 0, nil) - return nil - }) - - type DBInstanceBackupListOptions struct { - PageNumber int `default:"1"` - PageSize int `default:"100"` - ID string - } - - shellutils.R(&DBInstanceBackupListOptions{}, "dbinstance-backup-list", "List rds backup", func(cli *jdcloud.SRegion, args *DBInstanceBackupListOptions) error { - backups, _, err := cli.GetDBInstanceBackups(args.ID, args.PageNumber, args.PageSize) - if err != nil { - return err - } - printList(backups, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/jdcloud/shell/utils.go b/pkg/multicloud/jdcloud/shell/utils.go deleted file mode 100644 index 7458561857..0000000000 --- a/pkg/multicloud/jdcloud/shell/utils.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} - -type ListOptions struct { - Offset int `help:"page offset" default:"0"` - Limit int `help:"page size" default:"20"` -} diff --git a/pkg/multicloud/jdcloud/shell/vpc.go b/pkg/multicloud/jdcloud/shell/vpc.go deleted file mode 100644 index bedda45cf5..0000000000 --- a/pkg/multicloud/jdcloud/shell/vpc.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/jdcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - } - shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *jdcloud.SRegion, args *VpcListOptions) error { - vpcs, err := cli.GetIVpcs() - if err != nil { - return err - } - printList(vpcs, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/jdcloud/shell/zone.go b/pkg/multicloud/jdcloud/shell/zone.go deleted file mode 100644 index 94802d54db..0000000000 --- a/pkg/multicloud/jdcloud/shell/zone.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/jdcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - } - shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *jdcloud.SRegion, args *ZoneListOptions) error { - zones, err := cli.GetIZones() - if err != nil { - return err - } - printList(zones, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/jdcloud/snapshot.go b/pkg/multicloud/jdcloud/snapshot.go deleted file mode 100644 index c56aff9e46..0000000000 --- a/pkg/multicloud/jdcloud/snapshot.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - - commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" - "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/apis" - "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/client" - "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/models" - - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSnapshot struct { - multicloud.SResourceBase - multicloud.JdcloudTags - region *SRegion - - models.Snapshot - disk *SDisk -} - -func (s *SSnapshot) GetId() string { - return s.SnapshotId -} - -func (s *SSnapshot) GetName() string { - return s.Name -} - -func (s *SSnapshot) GetStatus() string { - switch s.Status { - case "creating": - return api.SNAPSHOT_CREATING - case "available", "in-use": - return api.SNAPSHOT_READY - case "deleting": - return api.SNAPSHOT_DELETING - case "error_create": - return api.SNAPSHOT_FAILED - case "error_delete": - return api.SNAPSHOT_DELETE_FAILED - default: - return api.SNAPSHOT_UNKNOWN - } -} - -func (s *SSnapshot) GetSizeMb() int32 { - return int32(s.SnapshotSizeGB) * 1024 -} - -func (s *SSnapshot) GetDiskId() string { - return s.DiskId -} - -func (s *SSnapshot) getDisk() (*SDisk, error) { - if s.disk != nil { - return s.disk, nil - } - disk, err := s.region.GetDiskById(s.DiskId) - if err != nil { - return disk, err - } - s.disk = disk - return s.disk, nil -} - -func (s *SSnapshot) GetDiskType() string { - disk, err := s.getDisk() - if err != nil { - log.Errorf("unable to get disk %s", s.DiskId) - return "" - } - return disk.GetDiskType() -} - -func (s *SSnapshot) Refresh() error { - return nil -} - -func (s *SSnapshot) GetGlobalId() string { - return s.GetId() -} - -func (s *SSnapshot) IsEmulated() bool { - return false -} - -func (s *SSnapshot) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (s *SSnapshot) GetProjectId() string { - return "" -} - -func (r *SRegion) GetSnapshots(diskId string, pageNumber, pageSize int) ([]SSnapshot, int, error) { - filters := []commodels.Filter{} - if diskId != "" { - filters = append(filters, commodels.Filter{ - Name: "diskId", - Values: []string{diskId}, - }) - } - req := apis.NewDescribeSnapshotsRequestWithAllParams(r.ID, &pageNumber, &pageSize, nil, filters) - client := client.NewDiskClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeSnapshots(req) - if err != nil { - return nil, 0, err - } - if resp.Error.Code >= 400 { - return nil, 0, fmt.Errorf(resp.Error.Message) - } - snapshots := make([]SSnapshot, len(resp.Result.Snapshots)) - for i := range resp.Result.Snapshots { - snapshots = append(snapshots, SSnapshot{ - region: r, - Snapshot: resp.Result.Snapshots[i], - }) - } - return snapshots, resp.Result.TotalCount, nil -} - -func (r *SRegion) GetSnapshotById(id string) (*SSnapshot, error) { - req := apis.NewDescribeSnapshotRequest(r.ID, id) - client := client.NewDiskClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeSnapshot(req) - if err != nil { - return nil, err - } - if resp.Error.Code >= 400 { - return nil, fmt.Errorf(resp.Error.Message) - } - snapshot := SSnapshot{ - region: r, - Snapshot: resp.Result.Snapshot, - } - return &snapshot, nil -} diff --git a/pkg/multicloud/jdcloud/storage.go b/pkg/multicloud/jdcloud/storage.go deleted file mode 100644 index 595b528fe9..0000000000 --- a/pkg/multicloud/jdcloud/storage.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var storageTypes = []string{ - api.STORAGE_JDCLOUD_STD, - api.STORAGE_JDCLOUD_GP1, - api.STORAGE_JDCLOUD_IO1, - api.STORAGE_JDCLOUD_SSD, - api.STORAGE_JDCLOUD_PHD, -} - -type SStorage struct { - multicloud.SStorageBase - multicloud.JdcloudTags - zone *SZone - storageType string -} - -func (s *SStorage) GetId() string { - return fmt.Sprintf("%s-%s-%s", s.zone.region.cpcfg.Id, s.zone.GetGlobalId(), s.storageType) -} - -func (s *SStorage) GetName() string { - return fmt.Sprintf("%s-%s-%s", s.zone.region.cpcfg.Name, s.zone.GetName(), s.storageType) -} - -func (s *SStorage) GetGlobalId() string { - return s.GetId() -} - -func (s *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (s *SStorage) Refresh() error { - return nil -} - -func (s *SStorage) IsEmulated() bool { - return true -} - -func (s *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return s.zone.region.getStoragecache() -} - -var ss cloudprovider.ICloudStorage = &SStorage{} - -func (s *SStorage) GetIZone() cloudprovider.ICloudZone { - return s.zone -} - -func (s *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks := make([]SDisk, 0) - n := 1 - for { - parts, total, err := s.zone.region.GetDisks("", s.zone.GetId(), s.storageType, []string{}, n, 100) - if err != nil { - return nil, err - } - disks = append(disks, parts...) - if len(disks) >= total { - break - } - n++ - } - idisk := make([]cloudprovider.ICloudDisk, len(disks)) - for i := range disks { - disks[i].storage = s - idisk[i] = &disks[i] - } - return idisk, nil -} - -func (s *SStorage) GetStorageType() string { - return s.storageType -} - -func (s *SStorage) GetMediumType() string { - if s.storageType == api.STORAGE_JDCLOUD_STD { - return api.DISK_TYPE_ROTATE - } else { - return api.DISK_TYPE_SSD - } -} - -func (s *SStorage) GetCapacityMB() int64 { - return 0 -} - -func (s *SStorage) GetStorageConf() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (s *SStorage) GetEnabled() bool { - return true -} - -func (s *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (s *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - disk, err := s.zone.region.GetDiskById(idStr) - if err != nil { - return nil, err - } - disk.storage = s - return disk, nil -} - -func (s *SStorage) GetMountPoint() string { - return "" -} - -func (s *SStorage) IsSysDiskStore() bool { - return true -} -func (s *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (s *SStorage) DisableSync() bool { - return false -} diff --git a/pkg/multicloud/jdcloud/storagecache.go b/pkg/multicloud/jdcloud/storagecache.go deleted file mode 100644 index 9e47d79e0a..0000000000 --- a/pkg/multicloud/jdcloud/storagecache.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.JdcloudTags - region *SRegion -} - -func (sc *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", sc.region.cpcfg.Id, sc.region.GetId()) -} - -func (sc *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", sc.region.cpcfg.Name, sc.region.GetName()) -} - -func (sc *SStoragecache) GetStatus() string { - return "available" -} - -func (sc *SStoragecache) Refresh() error { - return nil -} - -func (sc *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", sc.region.cpcfg.Id, sc.region.GetGlobalId()) -} - -func (sc *SStoragecache) IsEmulated() bool { - return false -} - -func (sc *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (sc *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - images := make([]SImage, 0) - n := 1 - for { - parts, total, err := sc.region.GetImages([]string{}, "private", n, 100) - if err != nil { - return nil, err - } - images = append(images, parts...) - if len(images) >= total { - break - } - n++ - } - ret := make([]cloudprovider.ICloudImage, len(images)) - for i := range ret { - images[i].storageCache = sc - ret[i] = &images[i] - } - return ret, nil -} - -func (sc *SStoragecache) GetIImageById(exId string) (cloudprovider.ICloudImage, error) { - img, err := sc.region.GetImage(exId) - if err != nil { - return nil, err - } - img.storageCache = sc - return img, nil -} - -func (sc *SStoragecache) GetPath() string { - return "" -} - -func (sc *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (sc *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (sc *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return "", cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/jdcloud/utils.go b/pkg/multicloud/jdcloud/utils.go deleted file mode 100644 index 385d8b2398..0000000000 --- a/pkg/multicloud/jdcloud/utils.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "time" - - "github.com/jdcloud-api/jdcloud-sdk-go/services/charge/models" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" -) - -func parseTime(ts string) time.Time { - t, _ := time.Parse("2006-01-02T15:04:05Z", ts) - return t -} - -func billingType(charge *models.Charge) string { - switch charge.ChargeMode { - case "prepaid_by_duration": - return billing_api.BILLING_TYPE_PREPAID - case "postpaid_by_usage", "postpaid_by_duration": - return billing_api.BILLING_TYPE_POSTPAID - default: - return "" - } -} - -func expireAt(charge *models.Charge) time.Time { - if billingType(charge) == billing_api.BILLING_TYPE_POSTPAID { - return time.Time{} - } - return parseTime(charge.ChargeExpiredTime) -} diff --git a/pkg/multicloud/jdcloud/vpc.go b/pkg/multicloud/jdcloud/vpc.go deleted file mode 100644 index a0e3be5f21..0000000000 --- a/pkg/multicloud/jdcloud/vpc.go +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/apis" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/client" - "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/models" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - multicloud.JdcloudTags - models.Vpc - - secgroups []cloudprovider.ICloudSecurityGroup - iwires []cloudprovider.ICloudWire - - region *SRegion -} - -func (v *SVpc) GetId() string { - return v.VpcId -} - -func (v *SVpc) GetName() string { - return v.VpcName -} - -func (v *SVpc) GetGlobalId() string { - return v.GetId() -} - -func (v *SVpc) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} - -func (v *SVpc) Refresh() error { - return nil -} - -func (v *SVpc) IsEmulated() bool { - return false -} - -func (v *SVpc) GetRegion() cloudprovider.ICloudRegion { - return v.region -} - -func (v *SVpc) GetIsDefault() bool { - return false -} - -func (v *SVpc) GetCidrBlock() string { - return "" -} - -func (v *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - if v.iwires != nil { - return v.iwires, nil - } - wire := SWire{ - vpc: v, - } - v.iwires = []cloudprovider.ICloudWire{&wire} - return v.iwires, nil -} - -func (v *SVpc) GetWire() *SWire { - return &SWire{ - vpc: v, - } -} - -func (v *SVpc) fetchSecurityGroups() error { - secgroups := make([]SSecurityGroup, 0) - n := 1 - for { - parts, total, err := v.region.GetSecurityGroups(v.GetId(), []string{}, n, 100) - if err != nil { - return err - } - secgroups = append(secgroups, parts...) - if len(secgroups) >= total { - break - } - n++ - } - v.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) - for i := 0; i < len(secgroups); i++ { - secgroups[i].vpc = v - v.secgroups[i] = &secgroups[i] - } - return nil -} - -func (v *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - if v.secgroups == nil { - err := v.fetchSecurityGroups() - if err != nil { - return nil, err - } - } - return v.secgroups, nil -} - -func (v *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (v *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, nil -} - -func (v *SVpc) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (v *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { - iwires, err := v.GetIWires() - if err != nil { - return nil, err - } - for i := range iwires { - if iwires[i].GetGlobalId() == wireId { - return iwires[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (r *SRegion) GetVpcs(pageNumber, pageSize int) (vpcs []SVpc, total int, err error) { - req := apis.NewDescribeVpcsRequestWithAllParams(r.ID, &pageNumber, &pageSize, nil) - client := client.NewVpcClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeVpcs(req) - if err != nil { - return - } - if resp.Error.Code >= 400 { - err = errors.Error(resp.Error.Message) - return - } - total = resp.Result.TotalCount - vpcs = make([]SVpc, 0, len(resp.Result.Vpcs)) - for i := range resp.Result.Vpcs { - vpcs = append(vpcs, SVpc{ - Vpc: resp.Result.Vpcs[i], - region: r, - }) - } - return -} - -func (r *SRegion) GetVpcById(id string) (*SVpc, error) { - req := apis.NewDescribeVpcRequest(r.ID, id) - client := client.NewVpcClient(r.getCredential()) - client.Logger = Logger{debug: r.client.debug} - resp, err := client.DescribeVpc(req) - if err != nil { - return nil, err - } - if resp.Error.Code >= 400 { - return nil, fmt.Errorf(resp.Error.Message) - } - return &SVpc{ - region: r, - Vpc: resp.Result.Vpc, - }, nil -} diff --git a/pkg/multicloud/jdcloud/wire.go b/pkg/multicloud/jdcloud/wire.go deleted file mode 100644 index f0f72dbc74..0000000000 --- a/pkg/multicloud/jdcloud/wire.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.JdcloudTags - - vpc *SVpc - inetworks []cloudprovider.ICloudNetwork -} - -func (w *SWire) GetId() string { - return fmt.Sprintf("%s-%s", w.vpc.GetId(), w.vpc.region.GetId()) -} - -func (w *SWire) GetName() string { - return w.GetId() -} - -func (w *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", w.vpc.GetGlobalId(), w.vpc.region.GetGlobalId()) -} - -func (w *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (w *SWire) Refresh() error { - return nil -} - -func (w *SWire) IsEmulated() bool { - return true -} - -func (w *SWire) GetIVpc() cloudprovider.ICloudVpc { - return w.vpc -} - -func (w *SWire) GetIZone() cloudprovider.ICloudZone { - return nil -} - -func (w *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - if w.inetworks == nil { - nets, err := w.networks() - if err != nil { - return nil, err - } - w.inetworks = make([]cloudprovider.ICloudNetwork, 0, len(nets)) - for i := range nets { - nets[i].wire = w - w.inetworks = append(w.inetworks, &nets[i]) - } - } - return w.inetworks, nil -} - -func (w *SWire) networks() ([]SNetwork, error) { - nets := make([]SNetwork, 0) - n := 1 - for { - parts, total, err := w.vpc.region.GetNetworks(w.vpc.VpcId, n, 100) - if err != nil { - return nil, err - } - nets = append(nets, parts...) - if len(nets) >= total { - break - } - n++ - } - return nets, nil -} - -func (w *SWire) GetBandwidth() int { - return 10000 -} - -func (w *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { - networks, err := w.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 (w *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (w *SWire) CreateNetworks() (*SNetwork, error) { - return nil, cloudprovider.ErrNotImplemented -} diff --git a/pkg/multicloud/jdcloud/zone.go b/pkg/multicloud/jdcloud/zone.go deleted file mode 100644 index a69f0f94a3..0000000000 --- a/pkg/multicloud/jdcloud/zone.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 jdcloud - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type sZoneIden struct { - Id string - Name string -} - -var ZonesInRegion = map[string][]sZoneIden{ - "cn-north-1": { - { - Id: "cn-north-1a", - Name: "可用区A", - }, - { - Id: "cn-north-1b", - Name: "可用区B", - }, - { - Id: "cn-north-1c", - Name: "可用区C", - }, - }, - "cn-east-1": { - { - Id: "cn-east-1a", - Name: "可用区A", - }, - }, - "cn-east-2": { - { - Id: "cn-east-2a", - Name: "可用区A", - }, - { - Id: "cn-east-2b", - Name: "可用区B", - }, - { - Id: "cn-east-2c", - Name: "可用区C", - }, - }, - "cn-south-1": { - { - Id: "cn-south-1a", - Name: "可用区A", - }, - { - Id: "cn-south-1b", - Name: "可用区B", - }, - { - Id: "cn-south-1c", - Name: "可用区C", - }, - }, -} - -type SZone struct { - multicloud.SResourceBase - multicloud.JdcloudTags - region *SRegion - - ihost cloudprovider.ICloudHost - istorages []cloudprovider.ICloudStorage - - ID string - Name string -} - -func (z *SZone) GetId() string { - return z.ID -} - -func (z *SZone) GetName() string { - return z.Name -} - -func (z *SZone) GetGlobalId() string { - return fmt.Sprintf("%s/%s", z.region.GetGlobalId(), z.ID) -} - -func (z *SZone) GetStatus() string { - return "enable" -} - -func (z *SZone) Refresh() error { - return nil -} - -func (z *SZone) IsEmulated() bool { - return false -} - -func (z *SZone) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(z.GetName()).CN(z.GetName()).EN(fmt.Sprintf("%s %s", CLOUD_PROVIDER_JDCLOUD_EN, z.Name)) - return table -} - -func (z *SZone) GetIRegion() cloudprovider.ICloudRegion { - return z.region -} - -func (z *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - if z.ihost != nil { - return []cloudprovider.ICloudHost{z.ihost}, nil - } - z.ihost = &SHost{ - zone: z, - } - return []cloudprovider.ICloudHost{z.ihost}, nil -} - -func (z *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - ihosts, err := z.GetIHosts() - if err != nil { - return nil, err - } - for i := range ihosts { - if ihosts[i].GetGlobalId() == id { - return ihosts[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (z *SZone) fetchStorages() error { - istorages := make([]cloudprovider.ICloudStorage, len(storageTypes)) - for i := range istorages { - istorages[i] = &SStorage{ - zone: z, - storageType: storageTypes[i], - } - } - z.istorages = istorages - return nil -} - -func (z *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - if z.istorages == nil { - err := z.fetchStorages() - if err != nil { - return nil, err - } - } - return z.istorages, nil -} - -func (z *SZone) getStorageByType(t string) (*SStorage, error) { - istorages, err := z.GetIStorages() - if err != nil { - return nil, err - } - for i := range istorages { - if istorages[i].GetStorageType() == t { - return istorages[i].(*SStorage), nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (z *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - istorages, err := z.GetIStorages() - if err != nil { - return nil, err - } - for i := range istorages { - if istorages[i].GetGlobalId() == id { - return istorages[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/loader/doc.go b/pkg/multicloud/loader/doc.go deleted file mode 100644 index 05b678d2df..0000000000 --- a/pkg/multicloud/loader/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 loader // import "yunion.io/x/onecloud/pkg/multicloud/loader" diff --git a/pkg/multicloud/loader/loader.go b/pkg/multicloud/loader/loader.go deleted file mode 100644 index fbcdbcb11c..0000000000 --- a/pkg/multicloud/loader/loader.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 loader - -import ( - "yunion.io/x/log" // on-premise virtualization technologies - - _ "yunion.io/x/onecloud/pkg/multicloud/aliyun/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/apsara/provider" // aliyun apsara stack - _ "yunion.io/x/onecloud/pkg/multicloud/aws/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/azure/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/bingocloud/provider" // private clouds - _ "yunion.io/x/onecloud/pkg/multicloud/cloudpods/provider" // private clouds - _ "yunion.io/x/onecloud/pkg/multicloud/ctyun/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/ecloud/provider" // public clouds - _ "yunion.io/x/onecloud/pkg/multicloud/esxi/provider" // private clouds - _ "yunion.io/x/onecloud/pkg/multicloud/google/provider" // public clouds - _ "yunion.io/x/onecloud/pkg/multicloud/hcs/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/hcso/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/huawei/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/incloudsphere/provider" // private clouds - _ "yunion.io/x/onecloud/pkg/multicloud/jdcloud/provider" // public clouds - _ "yunion.io/x/onecloud/pkg/multicloud/nutanix/provider" // private clouds - _ "yunion.io/x/onecloud/pkg/multicloud/objectstore/ceph/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/objectstore/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/objectstore/xsky/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/openstack/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/proxmox/provider" // private clouds - _ "yunion.io/x/onecloud/pkg/multicloud/qcloud/provider" - _ "yunion.io/x/onecloud/pkg/multicloud/remotefile/provider" // private clouds - _ "yunion.io/x/onecloud/pkg/multicloud/ucloud/provider" // object storages - _ "yunion.io/x/onecloud/pkg/multicloud/zstack/provider" // private clouds -) - -func init() { - log.Infof("Loading cloud providers ...") -} diff --git a/pkg/multicloud/loader/proxyfunc_test.go b/pkg/multicloud/loader/proxyfunc_test.go deleted file mode 100644 index 4249991cee..0000000000 --- a/pkg/multicloud/loader/proxyfunc_test.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 loader - -import ( - "net/http" - "net/url" - "testing" - - "yunion.io/x/s3cli" - - "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -func TestProxyFunc(t *testing.T) { - runT := func(t *testing.T, cpcfg *cloudprovider.ProviderConfig) { - vendor := cpcfg.Vendor - proxied := false - proxyFunc := func(req *http.Request) (*url.URL, error) { - proxied = true - return url.Parse("http://TestProxyFunc" + "." + vendor + "/") - } - cpcfg.ProxyFunc = proxyFunc - _, err := cloudprovider.GetProvider(*cpcfg) - if !proxied { - if err != nil { - t.Logf("vendor %s: err: %v", vendor, err) - } - t.Errorf("vendor %s: proxyFunc not working", vendor) - } - t.Run("default client no proxy", func(t *testing.T) { - proxied = false - client := httputils.GetDefaultClient() - client.Get("http://default-client-no-proxy.TestProxyFunc." + vendor + "/") - if proxied { - t.Errorf("%s: default client proxy changed", vendor) - } - }) - } - - t.Parallel() - t.Run("cloud", func(t *testing.T) { - cpcfgs := map[string]*cloudprovider.ProviderConfig{ - compute.CLOUD_PROVIDER_VMWARE: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_QCLOUD: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_AZURE: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_HUAWEI: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_OPENSTACK: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_ZSTACK: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_UCLOUD: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_ALIYUN: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_AWS: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_CTYUN: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_GOOGLE: &cloudprovider.ProviderConfig{}, - } - for vendor := range cpcfgs { - cpcfgs[vendor].Vendor = vendor - cpcfgs[vendor].Id = vendor + "-Id" - cpcfgs[vendor].Name = vendor + "-Name" - cpcfgs[vendor].URL = "http://" + vendor + ".AccessUrl/TestProxyFunc" - cpcfgs[vendor].Account = vendor + "-Account" - cpcfgs[vendor].Secret = vendor + "-Secret" - } - - if true { - cpcfgs[compute.CLOUD_PROVIDER_OPENSTACK].Account = "projectId/username/domainName" - } - if true { - cpcfgs[compute.CLOUD_PROVIDER_AZURE].URL = "AzureChinaCloud" - cpcfgs[compute.CLOUD_PROVIDER_AZURE].Account = "tenantId/subscriptionId" - cpcfgs[compute.CLOUD_PROVIDER_AZURE].Secret = "appId/appKey" - } - if true { - cpcfgs[compute.CLOUD_PROVIDER_UCLOUD].Account = "accessKey::projectId" - } - if true { - const pkey = `-----BEGIN RSA PRIVATE KEY-----` + "\n" + - `MIICXgIBAAKBgQDIUZ819CKNzPf3dL1aTC9tx6Y+Z/wQ74hWgyxM4DM5kxMZDoWd` + "\n" + - `2zzj7B8vUU64tYaeCaPFahxcMNs705wNACkFnmqop08zUSWTfbPg/uNdhGvuF0vT` + "\n" + - `3o5oNbUfVLrusvVJwP6mAnfJsECZJsPMqVIyM5z6uMBpAkjsaqEP7cOISwIDAQAB` + "\n" + - `AoGBAIzBXZ/ptcXxumM0skCau9DlspizNFkqFqDDdwNlnljcUVUP8S9kd7qnlZoI` + "\n" + - `BcqgMsElgOAcmWTmJ4Y4QLSZ4jgDthDUqt+dv384G4tUHv5LDU4SMnKiPFzqzsOn` + "\n" + - `PR72ZcoZZZW9PvNMmJDWSIwuEXgWovXhK5pO3wuuHUDjPHlxAkEA8DdcBRAV9yuq` + "\n" + - `AbVFSWxBIpNkXkIoOCQiBOP8LBTvua5Dkuxe5qZkDXuTupYmLRmIoDJuZVKo0jWw` + "\n" + - `6xBg1Io4BQJBANV7J3u5HV7IxlG35g8iCsU/AnLYQYWIWqF9+DKM8fqkDHGx6KGl` + "\n" + - `THG0gKGjhkWe/qzTsQbe4gHWZp6z1apVQA8CQQC9aDkzeMKJGTG8lQzj3urg82zx` + "\n" + - `caK62arFRmrA62U2eHSptZ0CqvI7O1R5jAjgCMEU547qb6nTzigIwOpIzA9tAkB6` + "\n" + - `EyaM1Vo6LU1axXJFDQ5jpJhd29P76/EHj+Ux4u8siEqlaTrB1KhWDQXRaJULktPH` + "\n" + - `OHZum11Z96RO9D8mXAF5AkEAq1xtCrJp8rWTGH5PGShyCOk2ZNbV0AL+may4FAgc` + "\n" + - `hbZ+WzxylVxMKJmWqEBAYF3/7oouyteF8Vq3TVOv442NSg==` + "\n" + - `-----END RSA PRIVATE KEY-----` - cpcfgs[compute.CLOUD_PROVIDER_GOOGLE].Account = "projectId/email" - cpcfgs[compute.CLOUD_PROVIDER_GOOGLE].Secret = "keyid/" + pkey - } - for _, cpcfg := range cpcfgs { - cpcfg := cpcfg - t.Run(cpcfg.Vendor, func(t *testing.T) { - //t.Parallel() - runT(t, cpcfg) - }) - } - }) - t.Run("objectstore", func(t *testing.T) { - s3cli.MaxRetry = 1 - cpcfgs := map[string]*cloudprovider.ProviderConfig{ - compute.CLOUD_PROVIDER_CEPH: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_XSKY: &cloudprovider.ProviderConfig{}, - compute.CLOUD_PROVIDER_GENERICS3: &cloudprovider.ProviderConfig{}, - } - for vendor := range cpcfgs { - cpcfgs[vendor].Vendor = vendor - cpcfgs[vendor].Id = vendor + "-Id" - cpcfgs[vendor].Name = vendor + "-Name" - cpcfgs[vendor].URL = "http://" + vendor + ".AccessUrl/TestProxyFunc" - cpcfgs[vendor].Account = vendor + "-Account" - cpcfgs[vendor].Secret = vendor + "-Secret" - } - for _, cpcfg := range cpcfgs { - cpcfg := cpcfg - t.Run(cpcfg.Vendor, func(t *testing.T) { - //t.Parallel() - runT(t, cpcfg) - }) - } - }) -} diff --git a/pkg/multicloud/nutanix/disk.go b/pkg/multicloud/nutanix/disk.go deleted file mode 100644 index 1733faf987..0000000000 --- a/pkg/multicloud/nutanix/disk.go +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "context" - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type DiskStats struct { - HypervisorAvgIoLatencyUsecs string `json:"hypervisor_avg_io_latency_usecs"` - HypervisorWriteIoBandwidthKBps string `json:"hypervisor_write_io_bandwidth_kBps"` - ControllerRandomOpsPpm string `json:"controller.random_ops_ppm"` - ControllerStorageTierSsdUsageBytes string `json:"controller.storage_tier.ssd.usage_bytes"` - ReadIoPpm string `json:"read_io_ppm"` - ControllerFrontendReadLatencyHistogram1000Us string `json:"controller.frontend_read_latency_histogram_1000us"` - ControllerNumIops string `json:"controller_num_iops"` - ControllerFrontendWriteOps string `json:"controller.frontend_write_ops"` - ControllerFrontendWriteLatencyHistogram10000Us string `json:"controller.frontend_write_latency_histogram_10000us"` - ControllerReadSizeHistogram1024KB string `json:"controller.read_size_histogram_1024kB"` - TotalReadIoTimeUsecs string `json:"total_read_io_time_usecs"` - ControllerTotalReadIoTimeUsecs string `json:"controller_total_read_io_time_usecs"` - ControllerWss3600SWriteMB string `json:"controller.wss_3600s_write_MB"` - ControllerFrontendReadLatencyHistogram50000Us string `json:"controller.frontend_read_latency_histogram_50000us"` - ControllerFrontendReadLatencyHistogram2000Us string `json:"controller.frontend_read_latency_histogram_2000us"` - ControllerNumWriteIo string `json:"controller_num_write_io"` - ControllerReadSourceCacheSsdBytes string `json:"controller.read_source_cache_ssd_bytes"` - ControllerReadSourceOplogBytes string `json:"controller.read_source_oplog_bytes"` - ControllerReadSourceCacheDramBytes string `json:"controller.read_source_cache_dram_bytes"` - ControllerRandomReadOps string `json:"controller.random_read_ops"` - ControllerTotalIoTimeUsecs string `json:"controller_total_io_time_usecs"` - ControllerNumSeqIo string `json:"controller_num_seq_io"` - ControllerTotalIoSizeKbytes string `json:"controller_total_io_size_kbytes"` - ControllerWss120SWriteMB string `json:"controller.wss_120s_write_MB"` - ControllerReadSourceBlockStoreBytes string `json:"controller.read_source_block_store_bytes"` - ControllerNumIo string `json:"controller_num_io"` - ControllerReadSourceEstoreZeroBytes string `json:"controller.read_source_estore_zero_bytes"` - ControllerNumRandomIo string `json:"controller_num_random_io"` - HypervisorNumReadIo string `json:"hypervisor_num_read_io"` - HypervisorTotalReadIoTimeUsecs string `json:"hypervisor_total_read_io_time_usecs"` - NumIo string `json:"num_io"` - HypervisorNumWriteIo string `json:"hypervisor_num_write_io"` - ControllerWriteSizeHistogram32KB string `json:"controller.write_size_histogram_32kB"` - ControllerFrontendReadLatencyHistogram20000Us string `json:"controller.frontend_read_latency_histogram_20000us"` - ControllerReadSizeHistogram32KB string `json:"controller.read_size_histogram_32kB"` - HypervisorNumWriteIops string `json:"hypervisor_num_write_iops"` - AvgIoLatencyUsecs string `json:"avg_io_latency_usecs"` - ControllerWriteIoPpm string `json:"controller_write_io_ppm"` - ControllerReadSourceEstoreSsdBytes string `json:"controller.read_source_estore_ssd_bytes"` - HypervisorTotalReadIoSizeKbytes string `json:"hypervisor_total_read_io_size_kbytes"` - ControllerNumWriteIops string `json:"controller_num_write_iops"` - TotalIoTimeUsecs string `json:"total_io_time_usecs"` - ControllerWss3600SReadMB string `json:"controller.wss_3600s_read_MB"` - ControllerSummaryReadSourceSsdBytesPerSec string `json:"controller.summary_read_source_ssd_bytes_per_sec"` - ControllerWriteSizeHistogram16KB string `json:"controller.write_size_histogram_16kB"` - TotalTransformedUsageBytes string `json:"total_transformed_usage_bytes"` - AvgWriteIoLatencyUsecs string `json:"avg_write_io_latency_usecs"` - ControllerCseTarget90PercentWriteMB string `json:"controller.cse_target_90_percent_write_MB"` - NumReadIo string `json:"num_read_io"` - HypervisorReadIoBandwidthKBps string `json:"hypervisor_read_io_bandwidth_kBps"` - HypervisorTotalIoTimeUsecs string `json:"hypervisor_total_io_time_usecs"` - NumRandomIo string `json:"num_random_io"` - ControllerWriteDestEstoreBytes string `json:"controller.write_dest_estore_bytes"` - ControllerFrontendWriteLatencyHistogram5000Us string `json:"controller.frontend_write_latency_histogram_5000us"` - ControllerStorageTierDasSataPinnedUsageBytes string `json:"controller.storage_tier.das-sata.pinned_usage_bytes"` - NumWriteIo string `json:"num_write_io"` - ControllerFrontendWriteLatencyHistogram2000Us string `json:"controller.frontend_write_latency_histogram_2000us"` - ControllerRandomWriteOpsPerSec string `json:"controller.random_write_ops_per_sec"` - ControllerFrontendWriteLatencyHistogram20000Us string `json:"controller.frontend_write_latency_histogram_20000us"` - IoBandwidthKBps string `json:"io_bandwidth_kBps"` - ControllerWriteSizeHistogram512KB string `json:"controller.write_size_histogram_512kB"` - ControllerReadSizeHistogram16KB string `json:"controller.read_size_histogram_16kB"` - WriteIoPpm string `json:"write_io_ppm"` - ControllerAvgWriteIoLatencyUsecs string `json:"controller_avg_write_io_latency_usecs"` - ControllerFrontendReadLatencyHistogram100000Us string `json:"controller.frontend_read_latency_histogram_100000us"` - NumReadIops string `json:"num_read_iops"` - ControllerSummaryReadSourceHddBytesPerSec string `json:"controller.summary_read_source_hdd_bytes_per_sec"` - ControllerReadSourceExtentCacheBytes string `json:"controller.read_source_extent_cache_bytes"` - TimespanUsecs string `json:"timespan_usecs"` - ControllerNumReadIops string `json:"controller_num_read_iops"` - ControllerFrontendReadLatencyHistogram10000Us string `json:"controller.frontend_read_latency_histogram_10000us"` - ControllerWriteSizeHistogram64KB string `json:"controller.write_size_histogram_64kB"` - ControllerFrontendWriteLatencyHistogram0Us string `json:"controller.frontend_write_latency_histogram_0us"` - ControllerFrontendWriteLatencyHistogram100000Us string `json:"controller.frontend_write_latency_histogram_100000us"` - HypervisorNumIo string `json:"hypervisor_num_io"` - ControllerTotalTransformedUsageBytes string `json:"controller_total_transformed_usage_bytes"` - AvgReadIoLatencyUsecs string `json:"avg_read_io_latency_usecs"` - ControllerTotalReadIoSizeKbytes string `json:"controller_total_read_io_size_kbytes"` - ControllerReadIoPpm string `json:"controller_read_io_ppm"` - ControllerFrontendOps string `json:"controller.frontend_ops"` - ControllerWss120SReadMB string `json:"controller.wss_120s_read_MB"` - ControllerReadSizeHistogram512KB string `json:"controller.read_size_histogram_512kB"` - HypervisorAvgReadIoLatencyUsecs string `json:"hypervisor_avg_read_io_latency_usecs"` - ControllerWriteSizeHistogram1024KB string `json:"controller.write_size_histogram_1024kB"` - ControllerWriteDestBlockStoreBytes string `json:"controller.write_dest_block_store_bytes"` - ControllerReadSizeHistogram4KB string `json:"controller.read_size_histogram_4kB"` - NumWriteIops string `json:"num_write_iops"` - ControllerRandomOpsPerSec string `json:"controller.random_ops_per_sec"` - NumIops string `json:"num_iops"` - ControllerStorageTierCloudPinnedUsageBytes string `json:"controller.storage_tier.cloud.pinned_usage_bytes"` - ControllerAvgIoLatencyUsecs string `json:"controller_avg_io_latency_usecs"` - ControllerReadSizeHistogram8KB string `json:"controller.read_size_histogram_8kB"` - ControllerNumReadIo string `json:"controller_num_read_io"` - ControllerSeqIoPpm string `json:"controller_seq_io_ppm"` - ControllerReadIoBandwidthKBps string `json:"controller_read_io_bandwidth_kBps"` - ControllerIoBandwidthKBps string `json:"controller_io_bandwidth_kBps"` - ControllerReadSizeHistogram0KB string `json:"controller.read_size_histogram_0kB"` - ControllerRandomOps string `json:"controller.random_ops"` - HypervisorTimespanUsecs string `json:"hypervisor_timespan_usecs"` - TotalReadIoSizeKbytes string `json:"total_read_io_size_kbytes"` - HypervisorTotalIoSizeKbytes string `json:"hypervisor_total_io_size_kbytes"` - ControllerFrontendOpsPerSec string `json:"controller.frontend_ops_per_sec"` - ControllerWriteDestOplogBytes string `json:"controller.write_dest_oplog_bytes"` - ControllerFrontendWriteLatencyHistogram1000Us string `json:"controller.frontend_write_latency_histogram_1000us"` - HypervisorNumReadIops string `json:"hypervisor_num_read_iops"` - ControllerSummaryReadSourceCacheBytesPerSec string `json:"controller.summary_read_source_cache_bytes_per_sec"` - ControllerWriteIoBandwidthKBps string `json:"controller_write_io_bandwidth_kBps"` - ControllerUserBytes string `json:"controller_user_bytes"` - HypervisorAvgWriteIoLatencyUsecs string `json:"hypervisor_avg_write_io_latency_usecs"` - ControllerStorageTierSsdPinnedUsageBytes string `json:"controller.storage_tier.ssd.pinned_usage_bytes"` - ReadIoBandwidthKBps string `json:"read_io_bandwidth_kBps"` - ControllerFrontendReadOps string `json:"controller.frontend_read_ops"` - HypervisorNumIops string `json:"hypervisor_num_iops"` - HypervisorIoBandwidthKBps string `json:"hypervisor_io_bandwidth_kBps"` - ControllerWss120SUnionMB string `json:"controller.wss_120s_union_MB"` - ControllerReadSourceEstoreHddBytes string `json:"controller.read_source_estore_hdd_bytes"` - ControllerRandomIoPpm string `json:"controller_random_io_ppm"` - ControllerCseTarget90PercentReadMB string `json:"controller.cse_target_90_percent_read_MB"` - ControllerStorageTierDasSataUsageBytes string `json:"controller.storage_tier.das-sata.usage_bytes"` - ControllerFrontendReadLatencyHistogram5000Us string `json:"controller.frontend_read_latency_histogram_5000us"` - ControllerAvgReadIoSizeKbytes string `json:"controller_avg_read_io_size_kbytes"` - WriteIoBandwidthKBps string `json:"write_io_bandwidth_kBps"` - ControllerRandomReadOpsPerSec string `json:"controller.random_read_ops_per_sec"` - ControllerReadSizeHistogram64KB string `json:"controller.read_size_histogram_64kB"` - ControllerWss3600SUnionMB string `json:"controller.wss_3600s_union_MB"` - RandomIoPpm string `json:"random_io_ppm"` - TotalUntransformedUsageBytes string `json:"total_untransformed_usage_bytes"` - ControllerFrontendReadLatencyHistogram0Us string `json:"controller.frontend_read_latency_histogram_0us"` - ControllerRandomWriteOps string `json:"controller.random_write_ops"` - ControllerAvgWriteIoSizeKbytes string `json:"controller_avg_write_io_size_kbytes"` - ControllerAvgReadIoLatencyUsecs string `json:"controller_avg_read_io_latency_usecs"` - TotalIoSizeKbytes string `json:"total_io_size_kbytes"` - ControllerStorageTierCloudUsageBytes string `json:"controller.storage_tier.cloud.usage_bytes"` - ControllerFrontendWriteLatencyHistogram50000Us string `json:"controller.frontend_write_latency_histogram_50000us"` - ControllerWriteSizeHistogram8KB string `json:"controller.write_size_histogram_8kB"` - ControllerTimespanUsecs string `json:"controller_timespan_usecs"` - NumSeqIo string `json:"num_seq_io"` - ControllerWriteSizeHistogram4KB string `json:"controller.write_size_histogram_4kB"` - SeqIoPpm string `json:"seq_io_ppm"` - ControllerWriteSizeHistogram0KB string `json:"controller.write_size_histogram_0kB"` -} - -type SDisk struct { - multicloud.STagBase - multicloud.SDisk - - storage *SStorage - - VirtualDiskID string `json:"virtual_disk_id"` - UUID string `json:"uuid"` - DeviceUUID string `json:"device_uuid"` - NutanixNfsfilePath string `json:"nutanix_nfsfile_path"` - DiskAddress string `json:"disk_address"` - AttachedVMID string `json:"attached_vm_id"` - AttachedVMUUID string `json:"attached_vm_uuid"` - AttachedVmname string `json:"attached_vmname"` - AttachedVolumeGroupID string `json:"attached_volume_group_id"` - DiskCapacityInBytes int64 `json:"disk_capacity_in_bytes"` - ClusterUUID string `json:"cluster_uuid"` - StorageContainerID string `json:"storage_container_id"` - StorageContainerUUID string `json:"storage_container_uuid"` - FlashModeEnabled string `json:"flash_mode_enabled"` - DataSourceURL string `json:"data_source_url"` - Stats DiskStats `json:"stats"` - - isSys bool -} - -func (self *SDisk) GetName() string { - return self.DiskAddress -} - -func (self *SDisk) GetId() string { - return self.UUID -} - -func (self *SDisk) GetGlobalId() string { - return self.UUID -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SDisk) Delete(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDisk) GetAccessPath() string { - return self.NutanixNfsfilePath -} - -func (self *SDisk) GetCacheMode() string { - return "none" -} - -func (self *SDisk) GetFsFormat() string { - return "" -} - -func (self *SDisk) GetIsNonPersistent() bool { - return false -} - -func (self *SDisk) GetDriver() string { - if info := strings.Split(self.DiskAddress, "."); len(info) > 0 { - return info[0] - } - return "scsi" -} - -func (self *SDisk) GetDiskType() string { - if self.isSys { - return api.DISK_TYPE_SYS - } - ins, err := self.storage.zone.region.GetInstance(self.AttachedVMUUID) - if err != nil { - return api.DISK_TYPE_DATA - } - for _, disk := range ins.VMDiskInfo { - if disk.IsCdrom { - continue - } - if disk.DiskAddress.VmdiskUUID == self.UUID { - return api.DISK_TYPE_SYS - } else { - return api.DISK_TYPE_DATA - } - } - return api.DISK_TYPE_DATA -} - -func (self *SDisk) GetDiskFormat() string { - return "raw" -} - -func (self *SDisk) GetDiskSizeMB() int { - return int(self.DiskCapacityInBytes / 1024 / 1024) -} - -func (self *SDisk) GetIsAutoDelete() bool { - return true -} - -func (self *SDisk) GetMountpoint() string { - return "" -} - -func (self *SDisk) GetStatus() string { - return api.DISK_READY -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { - ins, err := self.storage.zone.region.GetInstance(self.AttachedVMUUID) - if err != nil { - return errors.Wrapf(err, "GetInstance(%s)", self.AttachedVMUUID) - } - for _, disk := range ins.VMDiskInfo { - if disk.DiskAddress.VmdiskUUID == self.UUID { - params := map[string]interface{}{ - "vm_disks": []map[string]interface{}{ - { - "disk_address": disk.DiskAddress, - "flash_mode_enabled": disk.FlashModeEnabled, - "is_cdrom": disk.IsCdrom, - "is_empty": disk.IsEmpty, - "vm_disk_create": map[string]interface{}{ - "storage_container_uuid": disk.StorageContainerUUID, - "size": sizeMb * 1024 * 1024, - }, - }, - }, - } - return self.storage.zone.region.update("vms", fmt.Sprintf("%s/disks/update", self.AttachedVMUUID), jsonutils.Marshal(params), nil) - } - } - return cloudprovider.ErrNotSupported -} - -func (self *SDisk) GetTemplateId() string { - return "" -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.storage, nil -} - -func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetDisks(storageId, vmId string) ([]SDisk, error) { - disks := []SDisk{} - params := url.Values{} - filter := []string{} - if len(storageId) > 0 { - filter = append(filter, "container_uuid=="+storageId) - } - if len(vmId) > 0 { - filter = append(filter, "vm_uuid=="+vmId) - filter = append(filter, "attach_vm_id=="+vmId) - } - if len(filter) > 0 { - params.Set("filter_criteria", strings.Join(filter, ",")) - } - return disks, self.listAll("virtual_disks", params, &disks) -} - -func (self *SRegion) GetDisk(id string) (*SDisk, error) { - disk := &SDisk{} - return disk, self.get("virtual_disks", id, url.Values{}, disk) -} diff --git a/pkg/multicloud/nutanix/doc.go b/pkg/multicloud/nutanix/doc.go deleted file mode 100644 index 22af4751fd..0000000000 --- a/pkg/multicloud/nutanix/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix // import "yunion.io/x/onecloud/pkg/multicloud/nutanix" diff --git a/pkg/multicloud/nutanix/host.go b/pkg/multicloud/nutanix/host.go deleted file mode 100644 index 67378397fb..0000000000 --- a/pkg/multicloud/nutanix/host.go +++ /dev/null @@ -1,512 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "strconv" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SHost struct { - multicloud.STagBase - multicloud.SHostBase - firstHost bool - - zone *SZone - - ServiceVmid string `json:"service_vmid"` - UUID string `json:"uuid"` - DiskHardwareConfigs DiskHardwareConfigs `json:"disk_hardware_configs"` - Name string `json:"name"` - ServiceVmexternalIP string `json:"service_vmexternal_ip"` - ServiceVmnatIP string `json:"service_vmnat_ip"` - ServiceVmnatPort string `json:"service_vmnat_port"` - OplogDiskPct float64 `json:"oplog_disk_pct"` - OplogDiskSize int64 `json:"oplog_disk_size"` - HypervisorKey string `json:"hypervisor_key"` - HypervisorAddress string `json:"hypervisor_address"` - HypervisorUsername string `json:"hypervisor_username"` - HypervisorPassword string `json:"hypervisor_password"` - BackplaneIP string `json:"backplane_ip"` - ControllerVMBackplaneIP string `json:"controller_vm_backplane_ip"` - RdmaBackplaneIps string `json:"rdma_backplane_ips"` - ManagementServerName string `json:"management_server_name"` - IpmiAddress string `json:"ipmi_address"` - IpmiUsername string `json:"ipmi_username"` - IpmiPassword string `json:"ipmi_password"` - Monitored bool `json:"monitored"` - Position Position `json:"position"` - Serial string `json:"serial"` - BlockSerial string `json:"block_serial"` - BlockModel string `json:"block_model"` - BlockModelName string `json:"block_model_name"` - BlockLocation string `json:"block_location"` - HostMaintenanceModeReason string `json:"host_maintenance_mode_reason"` - HypervisorState string `json:"hypervisor_state"` - AcropolisConnectionState string `json:"acropolis_connection_state"` - MetadataStoreStatus string `json:"metadata_store_status"` - MetadataStoreStatusMessage string `json:"metadata_store_status_message"` - State string `json:"state"` - DynamicRingChangingNode string `json:"dynamic_ring_changing_node"` - RemovalStatus []string `json:"removal_status"` - VzoneName string `json:"vzone_name"` - CPUModel string `json:"cpu_model"` - NumCPUCores int `json:"num_cpu_cores"` - NumCPUThreads int `json:"num_cpu_threads"` - NumCPUSockets int `json:"num_cpu_sockets"` - CPUFrequencyInHz int64 `json:"cpu_frequency_in_hz"` - CPUCapacityInHz int64 `json:"cpu_capacity_in_hz"` - MemoryCapacityInBytes int64 `json:"memory_capacity_in_bytes"` - HypervisorFullName string `json:"hypervisor_full_name"` - HypervisorType string `json:"hypervisor_type"` - NumVms int `json:"num_vms"` - BootTimeInUsecs int64 `json:"boot_time_in_usecs"` - IsDegraded bool `json:"is_degraded"` - IsSecureBooted bool `json:"is_secure_booted"` - IsHardwareVirtualized bool `json:"is_hardware_virtualized"` - FailoverClusterFqdn string `json:"failover_cluster_fqdn"` - FailoverClusterNodeState string `json:"failover_cluster_node_state"` - RebootPending bool `json:"reboot_pending"` - DefaultVMLocation string `json:"default_vm_location"` - DefaultVMStorageContainerID string `json:"default_vm_storage_container_id"` - DefaultVMStorageContainerUUID string `json:"default_vm_storage_container_uuid"` - DefaultVhdLocation string `json:"default_vhd_location"` - DefaultVhdStorageContainerID string `json:"default_vhd_storage_container_id"` - DefaultVhdStorageContainerUUID string `json:"default_vhd_storage_container_uuid"` - BiosVersion string `json:"bios_version"` - BiosModel string `json:"bios_model"` - BmcVersion string `json:"bmc_version"` - BmcModel string `json:"bmc_model"` - HbaFirmwaresList string `json:"hba_firmwares_list"` - ClusterUUID string `json:"cluster_uuid"` - Stats Stats `json:"stats"` - UsageStats UsageStats `json:"usage_stats"` - HasCsr bool `json:"has_csr"` - HostNicIds []string `json:"host_nic_ids"` - HostGpus string `json:"host_gpus"` - GpuDriverVersion string `json:"gpu_driver_version"` - HostType string `json:"host_type"` - KeyManagementDeviceToCertificateStatus KeyManagementDeviceToCertificateStatus `json:"key_management_device_to_certificate_status"` - HostInMaintenanceMode string `json:"host_in_maintenance_mode"` -} - -type Num1 struct { - SerialNumber string `json:"serial_number"` - DiskID string `json:"disk_id"` - DiskUUID string `json:"disk_uuid"` - Location int `json:"location"` - Bad bool `json:"bad"` - Mounted bool `json:"mounted"` - MountPath string `json:"mount_path"` - Model string `json:"model"` - Vendor string `json:"vendor"` - BootDisk bool `json:"boot_disk"` - OnlyBootDisk bool `json:"only_boot_disk"` - UnderDiagnosis bool `json:"under_diagnosis"` - BackgroundOperation string `json:"background_operation"` - CurrentFirmwareVersion string `json:"current_firmware_version"` - TargetFirmwareVersion string `json:"target_firmware_version"` - CanAddAsNewDisk bool `json:"can_add_as_new_disk"` - CanAddAsOldDisk bool `json:"can_add_as_old_disk"` -} -type Num2 struct { - SerialNumber string `json:"serial_number"` - DiskID string `json:"disk_id"` - DiskUUID string `json:"disk_uuid"` - Location int `json:"location"` - Bad bool `json:"bad"` - Mounted bool `json:"mounted"` - MountPath string `json:"mount_path"` - Model string `json:"model"` - Vendor string `json:"vendor"` - BootDisk bool `json:"boot_disk"` - OnlyBootDisk bool `json:"only_boot_disk"` - UnderDiagnosis bool `json:"under_diagnosis"` - BackgroundOperation string `json:"background_operation"` - CurrentFirmwareVersion string `json:"current_firmware_version"` - TargetFirmwareVersion string `json:"target_firmware_version"` - CanAddAsNewDisk bool `json:"can_add_as_new_disk"` - CanAddAsOldDisk bool `json:"can_add_as_old_disk"` -} -type DiskHardwareConfigs struct { - Num1 Num1 `json:"1"` - Num2 Num2 `json:"2"` -} -type Position struct { - Ordinal int `json:"ordinal"` - Name string `json:"name"` - PhysicalPosition string `json:"physical_position"` -} -type Stats struct { - HypervisorAvgIoLatencyUsecs string `json:"hypervisor_avg_io_latency_usecs"` - NumReadIops string `json:"num_read_iops"` - HypervisorWriteIoBandwidthKBps string `json:"hypervisor_write_io_bandwidth_kBps"` - TimespanUsecs string `json:"timespan_usecs"` - ControllerNumReadIops string `json:"controller_num_read_iops"` - ReadIoPpm string `json:"read_io_ppm"` - ControllerNumIops string `json:"controller_num_iops"` - TotalReadIoTimeUsecs string `json:"total_read_io_time_usecs"` - ControllerTotalReadIoTimeUsecs string `json:"controller_total_read_io_time_usecs"` - HypervisorNumIo string `json:"hypervisor_num_io"` - ControllerTotalTransformedUsageBytes string `json:"controller_total_transformed_usage_bytes"` - HypervisorCPUUsagePpm string `json:"hypervisor_cpu_usage_ppm"` - ControllerNumWriteIo string `json:"controller_num_write_io"` - AvgReadIoLatencyUsecs string `json:"avg_read_io_latency_usecs"` - ContentCacheLogicalSsdUsageBytes string `json:"content_cache_logical_ssd_usage_bytes"` - ControllerTotalIoTimeUsecs string `json:"controller_total_io_time_usecs"` - ControllerTotalReadIoSizeKbytes string `json:"controller_total_read_io_size_kbytes"` - ControllerNumSeqIo string `json:"controller_num_seq_io"` - ControllerReadIoPpm string `json:"controller_read_io_ppm"` - ContentCacheNumLookups string `json:"content_cache_num_lookups"` - ControllerTotalIoSizeKbytes string `json:"controller_total_io_size_kbytes"` - ContentCacheHitPpm string `json:"content_cache_hit_ppm"` - ControllerNumIo string `json:"controller_num_io"` - HypervisorAvgReadIoLatencyUsecs string `json:"hypervisor_avg_read_io_latency_usecs"` - ContentCacheNumDedupRefCountPph string `json:"content_cache_num_dedup_ref_count_pph"` - NumWriteIops string `json:"num_write_iops"` - ControllerNumRandomIo string `json:"controller_num_random_io"` - NumIops string `json:"num_iops"` - HypervisorNumReadIo string `json:"hypervisor_num_read_io"` - HypervisorTotalReadIoTimeUsecs string `json:"hypervisor_total_read_io_time_usecs"` - ControllerAvgIoLatencyUsecs string `json:"controller_avg_io_latency_usecs"` - NumIo string `json:"num_io"` - ControllerNumReadIo string `json:"controller_num_read_io"` - HypervisorNumWriteIo string `json:"hypervisor_num_write_io"` - ControllerSeqIoPpm string `json:"controller_seq_io_ppm"` - ControllerReadIoBandwidthKBps string `json:"controller_read_io_bandwidth_kBps"` - ControllerIoBandwidthKBps string `json:"controller_io_bandwidth_kBps"` - HypervisorNumReceivedBytes string `json:"hypervisor_num_received_bytes"` - HypervisorTimespanUsecs string `json:"hypervisor_timespan_usecs"` - HypervisorNumWriteIops string `json:"hypervisor_num_write_iops"` - TotalReadIoSizeKbytes string `json:"total_read_io_size_kbytes"` - HypervisorTotalIoSizeKbytes string `json:"hypervisor_total_io_size_kbytes"` - AvgIoLatencyUsecs string `json:"avg_io_latency_usecs"` - HypervisorNumReadIops string `json:"hypervisor_num_read_iops"` - ContentCacheSavedSsdUsageBytes string `json:"content_cache_saved_ssd_usage_bytes"` - ControllerWriteIoBandwidthKBps string `json:"controller_write_io_bandwidth_kBps"` - ControllerWriteIoPpm string `json:"controller_write_io_ppm"` - HypervisorAvgWriteIoLatencyUsecs string `json:"hypervisor_avg_write_io_latency_usecs"` - HypervisorNumTransmittedBytes string `json:"hypervisor_num_transmitted_bytes"` - HypervisorTotalReadIoSizeKbytes string `json:"hypervisor_total_read_io_size_kbytes"` - ReadIoBandwidthKBps string `json:"read_io_bandwidth_kBps"` - HypervisorMemoryUsagePpm string `json:"hypervisor_memory_usage_ppm"` - HypervisorNumIops string `json:"hypervisor_num_iops"` - HypervisorIoBandwidthKBps string `json:"hypervisor_io_bandwidth_kBps"` - ControllerNumWriteIops string `json:"controller_num_write_iops"` - TotalIoTimeUsecs string `json:"total_io_time_usecs"` - ContentCachePhysicalSsdUsageBytes string `json:"content_cache_physical_ssd_usage_bytes"` - ControllerRandomIoPpm string `json:"controller_random_io_ppm"` - ControllerAvgReadIoSizeKbytes string `json:"controller_avg_read_io_size_kbytes"` - TotalTransformedUsageBytes string `json:"total_transformed_usage_bytes"` - AvgWriteIoLatencyUsecs string `json:"avg_write_io_latency_usecs"` - NumReadIo string `json:"num_read_io"` - WriteIoBandwidthKBps string `json:"write_io_bandwidth_kBps"` - HypervisorReadIoBandwidthKBps string `json:"hypervisor_read_io_bandwidth_kBps"` - RandomIoPpm string `json:"random_io_ppm"` - TotalUntransformedUsageBytes string `json:"total_untransformed_usage_bytes"` - HypervisorTotalIoTimeUsecs string `json:"hypervisor_total_io_time_usecs"` - NumRandomIo string `json:"num_random_io"` - ControllerAvgWriteIoSizeKbytes string `json:"controller_avg_write_io_size_kbytes"` - ControllerAvgReadIoLatencyUsecs string `json:"controller_avg_read_io_latency_usecs"` - NumWriteIo string `json:"num_write_io"` - TotalIoSizeKbytes string `json:"total_io_size_kbytes"` - IoBandwidthKBps string `json:"io_bandwidth_kBps"` - ContentCachePhysicalMemoryUsageBytes string `json:"content_cache_physical_memory_usage_bytes"` - ControllerTimespanUsecs string `json:"controller_timespan_usecs"` - NumSeqIo string `json:"num_seq_io"` - ContentCacheSavedMemoryUsageBytes string `json:"content_cache_saved_memory_usage_bytes"` - SeqIoPpm string `json:"seq_io_ppm"` - WriteIoPpm string `json:"write_io_ppm"` - ControllerAvgWriteIoLatencyUsecs string `json:"controller_avg_write_io_latency_usecs"` - ContentCacheLogicalMemoryUsageBytes string `json:"content_cache_logical_memory_usage_bytes"` -} -type UsageStats struct { - StorageTierDasSataUsageBytes string `json:"storage_tier.das-sata.usage_bytes"` - StorageCapacityBytes string `json:"storage.capacity_bytes"` - StorageLogicalUsageBytes string `json:"storage.logical_usage_bytes"` - StorageTierDasSataCapacityBytes string `json:"storage_tier.das-sata.capacity_bytes"` - StorageFreeBytes string `json:"storage.free_bytes"` - StorageTierSsdUsageBytes string `json:"storage_tier.ssd.usage_bytes"` - StorageTierSsdCapacityBytes string `json:"storage_tier.ssd.capacity_bytes"` - StorageTierDasSataFreeBytes string `json:"storage_tier.das-sata.free_bytes"` - StorageUsageBytes string `json:"storage.usage_bytes"` - StorageTierSsdFreeBytes string `json:"storage_tier.ssd.free_bytes"` -} -type KeyManagementDeviceToCertificateStatus struct { -} - -func (self *SRegion) GetHosts() ([]SHost, error) { - hosts := []SHost{} - return hosts, self.listAll("hosts", nil, &hosts) -} - -func (self *SRegion) GetHost(id string) (*SHost, error) { - host := &SHost{} - return host, self.cli.get("hosts", id, nil, host) -} - -func (self *SHost) GetName() string { - return self.Name -} - -func (self *SHost) GetId() string { - return self.UUID -} - -func (self *SHost) GetGlobalId() string { - return self.UUID -} - -func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - image, err := self.zone.region.GetImage(opts.ExternalImageId) - if err != nil { - return nil, errors.Wrapf(err, "GetImage") - } - disks := []map[string]interface{}{ - { - "disk_address": map[string]interface{}{ - "device_bus": "ide", - "device_index": 0, - }, - "is_cdrom": true, - "is_empty": true, - }, - { - "disk_address": map[string]interface{}{ - "device_bus": "scsi", - "device_index": 0, - }, - "is_cdrom": false, - "vm_disk_clone": map[string]interface{}{ - "disk_address": map[string]string{ - "vmdisk_uuid": image.VMDiskID, - }, - "minimum_size": opts.SysDisk.SizeGB * 1024 * 1024 * 1024, - }, - }, - } - for i, disk := range opts.DataDisks { - disks = append(disks, map[string]interface{}{ - "disk_address": map[string]interface{}{ - "device_bus": "scsi", - "device_index": i + 1, - }, - "is_cdrom": false, - "vm_disk_create": map[string]interface{}{ - "size": disk.SizeGB * 1024 * 1024 * 1024, - "storage_container_uuid": disk.StorageExternalId, - }, - }) - } - nic := map[string]interface{}{ - "network_uuid": opts.ExternalVpcId, - } - if len(opts.IpAddr) > 0 { - nic["requested_ip_address"] = opts.IpAddr - } - params := map[string]interface{}{ - "boot": map[string]interface{}{ - "boot_device_order": []string{"CDROM", "DISK", "NIC"}, - "uefi_boot": false, - }, - "description": opts.Description, - "hypervisor_type": "ACROPOLIS", - "memory_mb": opts.MemoryMB, - "name": opts.Name, - "num_cores_per_vcpu": 1, - "num_vcpus": opts.Cpu, - "timezone": "UTC", - "vm_customization_config": map[string]interface{}{ - "files_to_inject_list": []string{}, - "userdata": opts.UserData, - }, - "vm_disks": disks, - "vm_features": map[string]interface{}{ - "AGENT_VM": false, - }, - "vm_nics": []map[string]interface{}{ - nic, - }, - } - ret := struct { - TaskUUID string - }{} - err = self.zone.region.post("vms", jsonutils.Marshal(params), &ret) - if err != nil { - return nil, err - } - resId, err := self.zone.region.cli.wait(ret.TaskUUID) - if err != nil { - return nil, err - } - vm, err := self.zone.region.GetInstance(resId) - if err != nil { - return nil, err - } - vm.host = self - return vm, nil -} - -func (self *SHost) GetAccessIp() string { - return self.HypervisorAddress -} - -func (self *SHost) GetAccessMac() string { - return "" -} - -func (self *SHost) GetCpuCmtbound() float32 { - return 16.0 -} - -func (self *SHost) GetMemCmtbound() float32 { - return 1.5 -} - -func (self *SHost) GetCpuCount() int { - return self.NumCPUCores * self.NumCPUSockets -} - -func (self *SHost) GetNodeCount() int8 { - return int8(self.NumCPUSockets) -} - -func (self *SHost) GetEnabled() bool { - return true -} - -func (self *SHost) GetCpuDesc() string { - return self.CPUModel -} - -func (self *SHost) GetCpuMhz() int { - return int(self.CPUCapacityInHz / 1000 / 1000) -} - -func (self *SHost) GetMemSizeMB() int { - return int(self.MemoryCapacityInBytes / 1024 / 1024) -} - -func (self *SHost) GetStorageSizeMB() int { - sizeBytes, _ := strconv.Atoi(self.UsageStats.StorageCapacityBytes) - return sizeBytes / 1024 / 1024 -} - -func (self *SHost) GetStorageType() string { - return api.DISK_TYPE_HYBRID -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_NUTANIX -} - -func (self *SHost) GetHostStatus() string { - return api.HOST_ONLINE -} - -func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return []cloudprovider.ICloudHostNetInterface{}, nil -} - -func (self *SHost) GetIsMaintenance() bool { - return false -} - -func (self *SHost) GetVersion() string { - return "" -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) GetSN() string { - return "" -} - -func (self *SHost) GetSysInfo() jsonutils.JSONObject { - info := jsonutils.NewDict() - info.Add(jsonutils.NewString(CLOUD_PROVIDER_NUTANIX), "manufacture") - return info -} - -func (self *SHost) IsEmulated() bool { - return false -} - -func (self *SHost) Refresh() error { - host, err := self.zone.region.GetHost(self.UUID) - if err != nil { - return err - } - return jsonutils.Update(self, host) -} - -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) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms, err := self.zone.region.GetInstances() - if err != nil { - return nil, errors.Wrapf(err, "GetInstances") - } - ret := []cloudprovider.ICloudVM{} - for i := range vms { - if vms[i].HostUUID == self.UUID || (self.firstHost && len(vms[i].HostUUID) == 0) { - vms[i].host = self - ret = append(ret, &vms[i]) - } - } - return ret, nil -} - -func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.zone.region.GetInstance(id) - if err != nil { - return nil, errors.Wrapf(err, "GetInstance") - } - if len(vm.HostUUID) > 0 && vm.HostUUID != self.UUID { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "vm not locate host %s, it locate host %s", self.Name, vm.HostUUID) - } - vm.host = self - return vm, nil -} - -func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - vpcs, err := self.zone.region.GetIVpcs() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudWire{} - for i := range vpcs { - wires, err := vpcs[i].GetIWires() - if err != nil { - return nil, errors.Wrapf(err, "GetIWires") - } - ret = append(ret, wires...) - } - return ret, nil -} diff --git a/pkg/multicloud/nutanix/image.go b/pkg/multicloud/nutanix/image.go deleted file mode 100644 index 20d9c65fcf..0000000000 --- a/pkg/multicloud/nutanix/image.go +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "context" - "fmt" - "io" - "net/http" - "net/url" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type SImage struct { - multicloud.STagBase - multicloud.SImageBase - - cache *SStoragecache - - imageInfo *imagetools.ImageInfo - - UUID string `json:"uuid"` - Name string `json:"name"` - Deleted bool `json:"deleted"` - StorageContainerID int `json:"storage_container_id"` - StorageContainerUUID string `json:"storage_container_uuid"` - LogicalTimestamp int `json:"logical_timestamp"` - ImageType string `json:"image_type"` - VMDiskID string `json:"vm_disk_id"` - ImageState string `json:"image_state"` - CreatedTimeInUsecs int64 `json:"created_time_in_usecs"` - UpdatedTimeInUsecs int64 `json:"updated_time_in_usecs"` - VMDiskSize int64 `json:"vm_disk_size"` -} - -func (self *SImage) GetName() string { - return self.Name -} - -func (self *SImage) GetId() string { - return self.UUID -} - -func (self *SImage) GetGlobalId() string { - return self.UUID -} - -func (self *SImage) Refresh() error { - image, err := self.cache.region.GetImage(self.GetGlobalId()) - if err != nil { - return err - } - return jsonutils.Update(self, image) -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.cache -} - -func (self *SImage) GetImageFormat() string { - if self.ImageType == "ISO_IMAGE" { - return "iso" - } - return "raw" -} - -func (self *SImage) GetStatus() string { - switch self.ImageState { - case "ACTIVE": - return api.CACHED_IMAGE_STATUS_ACTIVE - case "INACTIVE": - return api.CACHED_IMAGE_STATUS_SAVING - } - return self.ImageState -} - -func (self *SImage) GetImageStatus() string { - switch self.ImageState { - case "ACTIVE": - return cloudprovider.IMAGE_STATUS_ACTIVE - case "INACTIVE": - return cloudprovider.IMAGE_STATUS_QUEUED - } - return cloudprovider.IMAGE_STATUS_KILLED -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - return cloudprovider.ImageTypeSystem -} - -func (self *SImage) GetCreatedAt() time.Time { - return time.Unix(self.CreatedTimeInUsecs/1000, self.CreatedTimeInUsecs%1000) -} - -func (self *SImage) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return int(self.VMDiskSize / 1024 / 1024 / 1024) -} - -func (self *SImage) GetSizeByte() int64 { - return self.VMDiskSize -} - -func (img *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if img.imageInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(img.Name, "", "", "", "") - img.imageInfo = &imgInfo - } - return img.imageInfo -} - -func (img *SImage) GetFullOsName() string { - return img.Name -} - -func (ins *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(ins.getNormalizedImageInfo().OsType) -} - -func (ins *SImage) GetOsDist() string { - return ins.getNormalizedImageInfo().OsDistro -} - -func (ins *SImage) GetOsVersion() string { - return ins.getNormalizedImageInfo().OsVersion -} - -func (ins *SImage) GetOsLang() string { - return ins.getNormalizedImageInfo().OsLang -} - -func (ins *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(ins.getNormalizedImageInfo().OsBios) -} - -func (ins *SImage) GetOsArch() string { - return ins.getNormalizedImageInfo().OsArch -} - -func (self *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (self *SRegion) GetImages() ([]SImage, error) { - images := []SImage{} - params := url.Values{} - params.Set("include_vm_disk_sizes", "true") - params.Set("include_vm_disk_paths", "true") - return images, self.listAll("images", nil, &images) -} - -func (self *SRegion) GetImage(id string) (*SImage, error) { - image := &SImage{} - params := url.Values{} - params.Set("include_vm_disk_sizes", "true") - params.Set("include_vm_disk_paths", "true") - return image, self.get("images", id, params, image) -} - -func (self *SRegion) CreateImage(storageId string, opts *cloudprovider.SImageCreateOption, sizeBytes int64, body io.Reader, callback func(float32)) (*SImage, error) { - params := map[string]interface{}{ - "image_type": "DISK_IMAGE", - "name": opts.ImageName, - "annotation": opts.OsDistribution, - } - ret := struct { - TaskUUID string - }{} - err := self.post("images", jsonutils.Marshal(params), &ret) - if err != nil { - return nil, errors.Wrapf(err, "create image") - } - imageId := "" - err = cloudprovider.Wait(time.Second*5, time.Minute*3, func() (bool, error) { - task, err := self.GetTask(ret.TaskUUID) - if err != nil { - return false, err - } - for _, entity := range task.EntityList { - imageId = entity.EntityID - } - log.Debugf("task %s %s status: %s", task.OperationType, task.UUID, task.ProgressStatus) - if task.ProgressStatus == "Succeeded" { - for _, entity := range task.EntityList { - imageId = entity.EntityID - } - return true, nil - } - return false, nil - }) - if err != nil { - return nil, err - } - header := http.Header{} - header.Set("X-Nutanix-Destination-Container", storageId) - header.Set("Content-Type", "application/octet-stream") - header.Set("Content-Length", fmt.Sprintf("%d", sizeBytes)) - reader := multicloud.NewProgress(sizeBytes, 90, body, callback) - resp, err := self.upload("images", fmt.Sprintf("%s/upload", imageId), header, reader) - if err != nil { - return nil, errors.Wrapf(err, "upload") - } - resp.Unmarshal(&ret) - err = cloudprovider.Wait(time.Second*10, time.Hour*2, func() (bool, error) { - task, err := self.GetTask(ret.TaskUUID) - if err != nil { - return false, err - } - if callback != nil { - callback(90 + float32(task.PercentageComplete)*0.1) - } - log.Debugf("task %s %s status: %s", task.OperationType, task.UUID, task.ProgressStatus) - if task.ProgressStatus == "Succeeded" { - for _, entity := range task.EntityList { - imageId = entity.EntityID - } - return true, nil - } - return false, nil - }) - if err != nil { - return nil, errors.Wrapf(err, "wait image ready") - } - return self.GetImage(imageId) -} diff --git a/pkg/multicloud/nutanix/instance.go b/pkg/multicloud/nutanix/instance.go deleted file mode 100644 index 4f02170c0c..0000000000 --- a/pkg/multicloud/nutanix/instance.go +++ /dev/null @@ -1,422 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "context" - "fmt" - "net/url" - "sort" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/apis" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type Boot struct { - UefiBoot bool `json:"uefi_boot"` -} - -type VMFeatures struct { - VGACONSOLE bool `json:"VGA_CONSOLE"` - AGENTVM bool `json:"AGENT_VM"` -} - -type DiskAddress struct { - DeviceBus string `json:"device_bus"` - DeviceIndex int `json:"device_index"` - DiskLabel string `json:"disk_label"` - NdfsFilepath string `json:"ndfs_filepath"` - VmdiskUUID string `json:"vmdisk_uuid"` - DeviceUUID string `json:"device_uuid"` -} - -type VMDiskInfo struct { - IsCdrom bool `json:"is_cdrom"` - IsEmpty bool `json:"is_empty"` - FlashModeEnabled bool `json:"flash_mode_enabled"` - IsScsiPassthrough bool `json:"is_scsi_passthrough"` - IsHotRemoveEnabled bool `json:"is_hot_remove_enabled"` - IsThinProvisioned bool `json:"is_thin_provisioned"` - Shared bool `json:"shared"` - SourceDiskAddress SourceDiskAddress `json:"source_disk_address,omitempty"` - StorageContainerUUID string `json:"storage_container_uuid,omitempty"` - Size int64 `json:"size,omitempty"` - DataSourceURL string `json:"data_source_url"` - DiskAddress DiskAddress `json:"disk_address,omitempty"` -} - -type SourceDiskAddress struct { - VmdiskUUID string `json:"vmdisk_uuid"` -} - -type VMNics struct { - MacAddress string `json:"mac_address"` - NetworkUUID string `json:"network_uuid"` - NicUUID string `json:"nic_uuid"` - Model string `json:"model"` - VlanMode string `json:"vlan_mode"` - IsConnected bool `json:"is_connected"` -} - -type SInstance struct { - multicloud.STagBase - multicloud.SInstanceBase - - host *SHost - - AllowLiveMigrate bool `json:"allow_live_migrate"` - GpusAssigned bool `json:"gpus_assigned"` - Boot Boot `json:"boot"` - HaPriority int `json:"ha_priority"` - HostUUID string `json:"host_uuid"` - MemoryMb int `json:"memory_mb"` - Name string `json:"name"` - NumCoresPerVcpu int `json:"num_cores_per_vcpu"` - NumVcpus int `json:"num_vcpus"` - PowerState string `json:"power_state"` - Timezone string `json:"timezone"` - UUID string `json:"uuid"` - VMFeatures VMFeatures `json:"vm_features"` - VMLogicalTimestamp int `json:"vm_logical_timestamp"` - MachineType string `json:"machine_type"` - - VMDiskInfo []VMDiskInfo `json:"vm_disk_info"` - VMNics []VMNics `json:"vm_nics"` -} - -func (self *SRegion) GetInstances() ([]SInstance, error) { - vms := []SInstance{} - params := url.Values{} - params.Set("include_vm_disk_config", "true") - params.Set("include_vm_nic_config", "true") - return vms, self.listAll("vms", params, &vms) -} - -func (self *SRegion) GetInstance(id string) (*SInstance, error) { - vm := &SInstance{} - params := url.Values{} - params.Set("include_vm_disk_config", "true") - params.Set("include_vm_nic_config", "true") - return vm, self.get("vms", id, params, vm) -} - -func (self *SInstance) GetName() string { - return self.Name -} - -func (self *SInstance) GetId() string { - return self.UUID -} - -func (self *SInstance) GetGlobalId() string { - return self.UUID -} - -func (self *SInstance) Refresh() error { - ins, err := self.host.zone.region.GetInstance(self.UUID) - if err != nil { - return err - } - return jsonutils.Update(self, ins) -} - -func (self *SInstance) AssignSecurityGroup(id string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) { - driver := opts.Driver - if !utils.IsInStringArray(driver, []string{"ide", "scsi", "pci", "sata"}) { - driver = "scsi" - } - idx, ids := -1, []int{} - for _, disk := range self.VMDiskInfo { - if disk.DiskAddress.DeviceBus == driver { - ids = append(ids, disk.DiskAddress.DeviceIndex) - } - } - sort.Ints(ids) - for _, id := range ids { - if id == idx+1 { - idx = id - } - } - params := map[string]interface{}{ - "vm_disks": []map[string]interface{}{ - { - "is_cdrom": false, - "disk_address": map[string]interface{}{ - "device_bus": driver, - "device_index": idx + 1, - }, - "vm_disk_create": map[string]interface{}{ - "storage_container_uuid": opts.StorageId, - "size": opts.SizeMb * 1024 * 1024, - }, - }, - }, - } - ret := struct { - TaskUUID string - }{} - res := fmt.Sprintf("vms/%s/disks/attach", self.UUID) - err := self.host.zone.region.post(res, jsonutils.Marshal(params), &ret) - if err != nil { - return "", err - } - return self.host.zone.region.cli.wait(ret.TaskUUID) -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error { - params := map[string]interface{}{ - "memory_mb": opts.MemoryMB, - "num_cores_per_vcpu": self.NumCoresPerVcpu, - "num_vcpus": opts.Cpu / self.NumCoresPerVcpu, - } - return self.host.zone.region.update("vms", self.UUID, jsonutils.Marshal(params), nil) -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - return self.host.zone.region.DeleteVM(self.UUID) -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) GetBios() cloudprovider.TBiosType { - if self.Boot.UefiBoot { - return cloudprovider.UEFI - } - return cloudprovider.BIOS -} - -func (self *SInstance) GetBootOrder() string { - return "dcn" -} - -func (self *SInstance) GetError() error { - return nil -} - -func (self *SInstance) GetHostname() string { - return self.Name -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_NUTANIX -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := self.host.zone.region.GetDisks("", self.GetGlobalId()) - if err != nil { - return nil, errors.Wrapf(err, "GetInstanceDisks") - } - cdroms := []string{} - for _, disk := range self.VMDiskInfo { - if disk.IsCdrom && len(disk.DiskAddress.VmdiskUUID) > 0 { - cdroms = append(cdroms, disk.DiskAddress.VmdiskUUID) - } - } - isSys := true - ret := []cloudprovider.ICloudDisk{} - for i := range disks { - if utils.IsInStringArray(disks[i].UUID, cdroms) { // skip cdrom disk - continue - } - storage, err := self.host.zone.GetIStorageById(disks[i].StorageContainerUUID) - if err != nil { - log.Errorf("can not found disk %s storage %s", disks[i].DiskAddress, disks[i].StorageContainerUUID) - continue - } - disks[i].isSys = isSys - disks[i].storage = storage.(*SStorage) - isSys = false - ret = append(ret, &disks[i]) - } - return ret, nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nics, err := self.host.zone.region.GetInstanceNics(self.GetGlobalId()) - if err != nil { - return nil, errors.Wrapf(err, "GetInstanceNics") - } - ret := []cloudprovider.ICloudNic{} - for i := range nics { - nics[i].ins = self - ret = append(ret, &nics[i]) - } - return ret, nil -} - -func (self *SInstance) GetInstanceType() string { - return fmt.Sprintf("ecs.g1.c%dm%d", self.GetVcpuCount(), self.GetVmemSizeMB()/1024) -} - -func (self *SInstance) GetMachine() string { - return self.MachineType -} - -// "UNKNOWN", "OFF", "POWERING_ON", "ON", "SHUTTING_DOWN", "POWERING_OFF", "PAUSING", "PAUSED", "SUSPENDING", "SUSPENDED", "RESUMING", "RESETTING", "MIGRATING" -func (self *SInstance) GetStatus() string { - switch strings.ToUpper(self.PowerState) { - case "OFF": - return api.VM_READY - case "POWERING_ON": - return api.VM_START_START - case "ON": - return api.VM_RUNNING - case "SHUTTING_DOWN": - return api.VM_START_STOP - case "POWERING_OFF": - return api.VM_START_STOP - case "PAUSING", "PAUSED": - return api.VM_READY - case "SUSPENDING", "SUSPENDED": - return api.VM_SUSPEND - case "RESUMING": - return api.VM_RESUMING - case "RESETTING": - return api.VM_RUNNING - case "MIGRATING": - return api.VM_MIGRATING - } - return api.VM_UNKNOWN -} - -func (self *SInstance) GetFullOsName() string { - return "" -} - -func (self *SInstance) GetOsType() cloudprovider.TOsType { - if strings.Contains(strings.ToLower(self.Name), "win") { - return cloudprovider.OsTypeWindows - } - return cloudprovider.OsTypeLinux -} - -func (ins *SInstance) GetOsDist() string { - return "" -} - -func (ins *SInstance) GetOsVersion() string { - return "" -} - -func (ins *SInstance) GetOsLang() string { - return "" -} - -func (ins *SInstance) GetOsArch() string { - return apis.OS_ARCH_X86_64 -} - -func (self *SInstance) GetProjectId() string { - return "" -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - return []string{}, nil -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SInstance) GetVcpuCount() int { - return self.NumCoresPerVcpu * self.NumVcpus -} - -func (self *SInstance) GetVmemSizeMB() int { - return self.MemoryMb -} - -func (self *SInstance) GetVga() string { - return "std" -} - -func (self *SInstance) GetVdi() string { - return "vnc" -} - -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) StartVM(ctx context.Context) error { - return self.host.zone.region.SetInstancePowerState(self.UUID, "on") -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - act := "acpi_shutdown" - if opts.IsForce { - act = "off" - } - return self.host.zone.region.SetInstancePowerState(self.UUID, act) -} - -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) SetInstancePowerState(id string, state string) error { - res := fmt.Sprintf("vms/%s/set_power_state", id) - ret := struct { - TaskUUID string - }{} - err := self.post(res, jsonutils.Marshal(map[string]string{"transition": state}), &ret) - if err != nil { - return err - } - _, err = self.cli.wait(ret.TaskUUID) - return err -} - -func (self *SRegion) DeleteVM(id string) error { - return self.delete("vms", id) -} diff --git a/pkg/multicloud/nutanix/instancenic.go b/pkg/multicloud/nutanix/instancenic.go deleted file mode 100644 index 8a5e0cf331..0000000000 --- a/pkg/multicloud/nutanix/instancenic.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "fmt" - "net/url" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - cloudprovider.DummyICloudNic - ins *SInstance - - MacAddress string `json:"mac_address"` - NetworkUUID string `json:"network_uuid"` - NicUUID string `json:"nic_uuid"` - Model string `json:"model"` - IPAddress string `json:"ip_address"` - IPAddresses []string `json:"ip_addresses"` - VlanMode string `json:"vlan_mode"` - IsConnected bool `json:"is_connected"` -} - -func (self *SInstanceNic) GetId() string { - return self.NicUUID -} - -func (self *SInstanceNic) GetIP() string { - return self.IPAddress -} - -func (self *SInstanceNic) GetMAC() string { - return self.MacAddress -} - -func (self *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (self *SInstanceNic) GetSubAddress() ([]string, error) { - ret := []string{} - for _, addr := range self.IPAddresses { - if addr != self.IPAddress { - ret = append(ret, addr) - } - } - return ret, nil -} - -func (self *SInstanceNic) GetINetworkId() string { - if len(self.IPAddress) == 0 { - return self.NetworkUUID - } - vpc, err := self.ins.host.zone.region.GetVpc(self.NetworkUUID) - if err != nil { - return self.NetworkUUID - } - wires, err := vpc.GetIWires() - if err != nil { - return self.NetworkUUID - } - for i := range wires { - networks, err := wires[i].GetINetworks() - if err != nil { - continue - } - for j := range networks { - network := networks[j].(*SNetwork) - if network.Contains(self.IPAddress) { - return network.GetGlobalId() - } - } - } - return self.NetworkUUID -} - -func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetInstanceNics(id string) ([]SInstanceNic, error) { - nics := []SInstanceNic{} - res := fmt.Sprintf("vms/%s/nics", id) - params := url.Values{} - params.Set("include_address_assignments", "true") - _, err := self.list(res, params, &nics) - return nics, err -} diff --git a/pkg/multicloud/nutanix/network.go b/pkg/multicloud/nutanix/network.go deleted file mode 100644 index 3f08adaf41..0000000000 --- a/pkg/multicloud/nutanix/network.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.STagBase - wire *SWire - - Range string -} - -func (self *SNetwork) GetName() string { - if len(self.Range) > 0 { - return self.Range - } - return self.wire.GetName() -} - -func (self *SNetwork) GetId() string { - if len(self.Range) > 0 { - return self.Range - } - return self.wire.GetId() -} - -func (self *SNetwork) GetGlobalId() string { - if len(self.Range) > 0 { - return self.Range - } - return self.wire.GetGlobalId() -} - -func (self *SNetwork) IsEmulated() bool { - return len(self.Range) == 0 -} - -func (self *SNetwork) Refresh() error { - vpc, err := self.wire.vpc.region.GetVpc(self.wire.vpc.GetGlobalId()) - if err != nil { - return err - } - for _, pool := range vpc.IPConfig.Pool { - if pool.Range == self.Range { - return nil - } - } - return cloudprovider.ErrNotFound -} - -func (self *SNetwork) Delete() error { - if len(self.Range) == 0 { - return nil - } - return self.wire.vpc.region.DeleteNetwork(self.wire.vpc.UUID, self.Range) -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (self *SNetwork) GetGateway() string { - return self.wire.vpc.IPConfig.DefaultGateway -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetIpStart() string { - if info := strings.Split(self.Range, " "); len(info) == 2 { - return info[0] - } - cidr := self.wire.vpc.GetCidrBlock() - if len(cidr) == 0 { - cidr = "0.0.0.0/0" - } - _range, _ := netutils.NewIPV4Prefix(cidr) - return _range.ToIPRange().StartIp().StepUp().String() -} - -func (self *SNetwork) GetIpEnd() string { - if info := strings.Split(self.Range, " "); len(info) == 2 { - return info[1] - } - cidr := self.wire.vpc.GetCidrBlock() - if len(cidr) == 0 { - cidr = "0.0.0.0/0" - } - _range, _ := netutils.NewIPV4Prefix(cidr) - return _range.ToIPRange().EndIp().StepDown().String() -} - -func (self *SNetwork) Contains(_ip string) bool { - start, _ := netutils.NewIPV4Addr(self.GetIpStart()) - end, _ := netutils.NewIPV4Addr(self.GetIpEnd()) - ip, _ := netutils.NewIPV4Addr(_ip) - return netutils.NewIPV4AddrRange(start, end).Contains(ip) -} - -func (self *SNetwork) GetIpMask() int8 { - pref, _ := netutils.NewIPV4Prefix(self.wire.vpc.GetCidrBlock()) - return pref.MaskLen -} - -func (self *SNetwork) GetProjectId() string { - return "" -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetStatus() string { - return api.NETWORK_STATUS_AVAILABLE -} - -func (self *SRegion) CreateNetwork(vpcId string, opts *cloudprovider.SNetworkCreateOptions) (*SNetwork, error) { - vpc, err := self.GetVpc(vpcId) - if err != nil { - return nil, errors.Wrapf(err, "GetVpc") - } - cidr, _ := netutils.NewIPV4Prefix(opts.Cidr) - _range := fmt.Sprintf("%s %s", cidr.ToIPRange().StartIp().StepUp(), cidr.ToIPRange().EndIp().StepDown()) - pool := SPool{Range: _range} - vpc.IPConfig.Pool = append(vpc.IPConfig.Pool, pool) - err = self.update("networks", vpcId, jsonutils.Marshal(vpc), nil) - if err != nil { - return nil, err - } - wire := vpc.getWire() - return &SNetwork{wire: wire, Range: _range}, nil -} - -func (self *SRegion) DeleteNetwork(vpcId string, _range string) error { - vpc, err := self.GetVpc(vpcId) - if err != nil { - return err - } - pools, find := []SPool{}, false - for i := range vpc.IPConfig.Pool { - if vpc.IPConfig.Pool[i].Range == _range { - find = true - continue - } - pools = append(pools, vpc.IPConfig.Pool[i]) - } - if !find { - return nil - } - vpc.IPConfig.Pool = pools - return self.update("networks", vpcId, jsonutils.Marshal(vpc), nil) -} diff --git a/pkg/multicloud/nutanix/provider/doc.go b/pkg/multicloud/nutanix/provider/doc.go deleted file mode 100644 index 42ef0c5026..0000000000 --- a/pkg/multicloud/nutanix/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/nutanix/provider" diff --git a/pkg/multicloud/nutanix/provider/provider.go b/pkg/multicloud/nutanix/provider/provider.go deleted file mode 100644 index 3a8e815112..0000000000 --- a/pkg/multicloud/nutanix/provider/provider.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "fmt" - "net/url" - "strconv" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/regutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/nutanix" -) - -type SNutanixProviderFactory struct { - cloudprovider.SPrivateCloudBaseProviderFactory -} - -func (self *SNutanixProviderFactory) GetId() string { - return nutanix.CLOUD_PROVIDER_NUTANIX -} - -func (self *SNutanixProviderFactory) GetName() string { - return nutanix.CLOUD_PROVIDER_NUTANIX -} - -func (self *SNutanixProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { - return fmt.Errorf("Changing %s bandwidth is not supported", nutanix.CLOUD_PROVIDER_NUTANIX) -} - -func (self *SNutanixProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.Username) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "username") - } - if len(input.Password) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "password") - } - if len(input.Host) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "host") - } - if !regutils.MatchIPAddr(input.Host) && !regutils.MatchDomainName(input.Host) { - return output, errors.Wrap(httperrors.ErrInputParameter, "host should be ip or domain name") - } - if input.Port == 0 { - input.Port = 9440 - } - output.AccessUrl = fmt.Sprintf("https://%s:%d", input.Host, input.Port) - output.Account = input.Username - output.Secret = input.Password - return output, nil -} - -func (self *SNutanixProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.Username) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "username") - } - if len(input.Password) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "password") - } - output = cloudprovider.SCloudaccount{ - Account: input.Username, - Secret: input.Password, - } - return output, nil -} - -func parseHostPort(_url string) (string, int, error) { - urlParse, err := url.Parse(_url) - if err != nil { - return "", 0, errors.Wrapf(err, "parse %s", _url) - } - port := func() int { - if len(urlParse.Port()) > 0 { - _port, _ := strconv.Atoi(urlParse.Port()) - return _port - } - return 9440 - }() - return strings.TrimSuffix(urlParse.Host, fmt.Sprintf(":%d", port)), port, nil -} - -func (self *SNutanixProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - host, port, err := parseHostPort(cfg.URL) - if err != nil { - return nil, errors.Wrapf(err, "parseHostPort") - } - - client, err := nutanix.NewNutanixClient( - nutanix.NewNutanixClientConfig( - host, cfg.Account, cfg.Secret, port, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SNutanixProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SNutanixProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - host, port, err := parseHostPort(info.Url) - if err != nil { - return nil, err - } - - return map[string]string{ - "NUTANIX_HOST": host, - "NUTANIX_PORT": fmt.Sprintf("%d", port), - "NUTANIX_USERNAME": info.Account, - "NUTANIX_PASSWORD": info.Secret, - }, nil -} - -func init() { - factory := SNutanixProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SNutanixProvider struct { - cloudprovider.SBaseProvider - client *nutanix.SNutanixClient -} - -func (self *SNutanixProvider) GetSysInfo() (jsonutils.JSONObject, error) { - return jsonutils.NewDict(), nil -} - -func (self *SNutanixProvider) GetVersion() string { - return nutanix.NUTANIX_VERSION_V2 -} - -func (self *SNutanixProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SNutanixProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SNutanixProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SNutanixProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - regions := self.GetIRegions() - for i := range regions { - if regions[i].GetGlobalId() == id { - return regions[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SNutanixProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SNutanixProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return []cloudprovider.ICloudProject{}, nil - //return self.client.GetIProjects() -} - -func (self *SNutanixProvider) GetStorageClasses(regionId string) []string { - return nil -} - -func (self *SNutanixProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (self *SNutanixProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (self *SNutanixProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} diff --git a/pkg/multicloud/nutanix/region.go b/pkg/multicloud/nutanix/region.go deleted file mode 100644 index 828707bc37..0000000000 --- a/pkg/multicloud/nutanix/region.go +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "fmt" - "io" - "net/http" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - multicloud.SRegion - multicloud.SNoObjectStorageRegion - multicloud.SNoLbRegion - - cli *SNutanixClient -} - -func (self *SRegion) GetId() string { - return self.cli.cpcfg.Id -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", api.CLOUD_PROVIDER_NUTANIX, self.cli.cpcfg.Id) -} - -func (self *SRegion) GetName() string { - return self.cli.cpcfg.Name -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) - return table -} - -func (self *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - return self.CreateVpc(opts) -} - -func (self *SRegion) GetCapabilities() []string { - return self.cli.GetCapabilities() -} - -func (self *SRegion) GetCloudEnv() string { - return "" -} - -func (self *SRegion) GetProvider() string { - return api.CLOUD_PROVIDER_NUTANIX -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - return []cloudprovider.ICloudEIP{}, nil -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - vpc, err := self.GetVpc(id) - if err != nil { - return nil, errors.Wrapf(err, "GetVpc(%s)", id) - } - return vpc, nil -} - -func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - vpcs, err := self.GetVpcs() - if err != nil { - return nil, errors.Wrapf(err, "GetVpcs") - } - ret := []cloudprovider.ICloudVpc{} - for i := range vpcs { - vpcs[i].region = self - ret = append(ret, &vpcs[i]) - } - return ret, nil -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - clusters, err := self.GetClusters() - if err != nil { - return nil, errors.Wrapf(err, "GetClusters") - } - ret := []cloudprovider.ICloudZone{} - for i := range clusters { - ret = append(ret, &SZone{ - SCluster: clusters[i], - region: self, - }) - } - return ret, nil -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - zones, err := self.GetIZones() - if err != nil { - return nil, errors.Wrapf(err, "GetIZones") - } - for i := range zones { - if zones[i].GetGlobalId() == id { - return zones[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - zones, err := self.GetIZones() - if err != nil { - return nil, errors.Wrapf(err, "GetIZones") - } - ret := []cloudprovider.ICloudHost{} - for i := range zones { - part, err := zones[i].GetIHosts() - if err != nil { - return nil, errors.Wrapf(err, "GetIHost") - } - ret = append(ret, part...) - } - return ret, nil -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.GetInstance(id) - if err != nil { - return nil, err - } - return vm, nil -} - -func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - hosts, err := self.GetIHosts() - if err != nil { - return nil, errors.Wrapf(err, "GetIHosts") - } - for i := range hosts { - if hosts[i].GetGlobalId() == id { - return hosts[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) list(res string, params url.Values, retVal interface{}) (int, error) { - return self.cli.list(res, params, retVal) -} - -func (self *SRegion) get(res, id string, params url.Values, retVal interface{}) error { - return self.cli.get(res, id, params, retVal) -} - -func (self *SRegion) listAll(res string, params url.Values, retVal interface{}) error { - return self.cli.listAll(res, params, retVal) -} - -func (self *SRegion) post(res string, body jsonutils.JSONObject, retVal interface{}) error { - return self.cli.post(res, body, retVal) -} - -func (self *SRegion) delete(res string, id string) error { - return self.cli.delete(res, id) -} - -func (self *SRegion) update(res string, id string, body jsonutils.JSONObject, retVal interface{}) error { - return self.cli.update(res, id, body, retVal) -} - -func (self *SRegion) upload(res string, id string, header http.Header, body io.Reader) (jsonutils.JSONObject, error) { - return self.cli.upload(res, id, header, body) -} - -func (self *SRegion) getTask(id string) (*STask, error) { - task := &STask{} - return task, self.get("tasks", id, nil, task) -} diff --git a/pkg/multicloud/nutanix/shell/cluster.go b/pkg/multicloud/nutanix/shell/cluster.go deleted file mode 100644 index 7ce8673204..0000000000 --- a/pkg/multicloud/nutanix/shell/cluster.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/nutanix" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClusterListOptions struct { - } - shellutils.R(&ClusterListOptions{}, "cluster-list", "list clusters", func(cli *nutanix.SRegion, args *ClusterListOptions) error { - clusters, err := cli.GetClusters() - if err != nil { - return err - } - printList(clusters, 0, 0, 0, []string{}) - return nil - }) - - type ClusterIdOptions struct { - ID string - } - - shellutils.R(&ClusterIdOptions{}, "cluster-show", "show clusters", func(cli *nutanix.SRegion, args *ClusterIdOptions) error { - cluster, err := cli.GetCluster(args.ID) - if err != nil { - return err - } - printObject(cluster) - return nil - }) - -} diff --git a/pkg/multicloud/nutanix/shell/disk.go b/pkg/multicloud/nutanix/shell/disk.go deleted file mode 100644 index c0828eda0c..0000000000 --- a/pkg/multicloud/nutanix/shell/disk.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/nutanix" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - StorageId string - InstanceId string - } - shellutils.R(&DiskListOptions{}, "disk-list", "list disks", func(cli *nutanix.SRegion, args *DiskListOptions) error { - disks, err := cli.GetDisks(args.StorageId, args.InstanceId) - if err != nil { - return err - } - printList(disks, 0, 0, 0, []string{}) - return nil - }) - - type DiskIdOptions struct { - ID string - } - - shellutils.R(&DiskIdOptions{}, "disk-show", "show disk", func(cli *nutanix.SRegion, args *DiskIdOptions) error { - disk, err := cli.GetDisk(args.ID) - if err != nil { - return err - } - printObject(disk) - return nil - }) - -} diff --git a/pkg/multicloud/nutanix/shell/doc.go b/pkg/multicloud/nutanix/shell/doc.go deleted file mode 100644 index b3b5b93b1e..0000000000 --- a/pkg/multicloud/nutanix/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/nutanix/shell" diff --git a/pkg/multicloud/nutanix/shell/host.go b/pkg/multicloud/nutanix/shell/host.go deleted file mode 100644 index 4bab663fb3..0000000000 --- a/pkg/multicloud/nutanix/shell/host.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/nutanix" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type HostListOptions struct { - } - shellutils.R(&HostListOptions{}, "host-list", "list hosts", func(cli *nutanix.SRegion, args *HostListOptions) error { - hosts, err := cli.GetHosts() - if err != nil { - return err - } - printList(hosts, 0, 0, 0, []string{}) - return nil - }) - - type HostIdOptions struct { - ID string - } - - shellutils.R(&HostIdOptions{}, "host-show", "show host", func(cli *nutanix.SRegion, args *HostIdOptions) error { - host, err := cli.GetHost(args.ID) - if err != nil { - return err - } - printObject(host) - return nil - }) - -} diff --git a/pkg/multicloud/nutanix/shell/image.go b/pkg/multicloud/nutanix/shell/image.go deleted file mode 100644 index 5284003833..0000000000 --- a/pkg/multicloud/nutanix/shell/image.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "os" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/nutanix" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - } - shellutils.R(&ImageListOptions{}, "image-list", "list hosts", func(cli *nutanix.SRegion, args *ImageListOptions) error { - images, err := cli.GetImages() - if err != nil { - return err - } - printList(images, 0, 0, 0, []string{}) - return nil - }) - - type ImageIdOptions struct { - ID string - } - - shellutils.R(&ImageIdOptions{}, "image-show", "show host", func(cli *nutanix.SRegion, args *ImageIdOptions) error { - image, err := cli.GetImage(args.ID) - if err != nil { - return err - } - printObject(image) - return nil - }) - - type ImageUploadOptions struct { - STOREG_ID string - NAME string - FILE string - } - - shellutils.R(&ImageUploadOptions{}, "image-upload", "upload host", func(cli *nutanix.SRegion, args *ImageUploadOptions) error { - fi, err := os.Open(args.FILE) - if err != nil { - return err - } - defer fi.Close() - - stat, _ := fi.Stat() - image, err := cli.CreateImage( - args.STOREG_ID, - &cloudprovider.SImageCreateOption{ - ImageName: args.NAME, - }, - stat.Size(), - fi, - nil, - ) - if err != nil { - return err - } - printObject(image) - return nil - }) - -} diff --git a/pkg/multicloud/nutanix/shell/instance.go b/pkg/multicloud/nutanix/shell/instance.go deleted file mode 100644 index 9a3bd12112..0000000000 --- a/pkg/multicloud/nutanix/shell/instance.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/nutanix" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - } - shellutils.R(&InstanceListOptions{}, "instance-list", "list instances", func(cli *nutanix.SRegion, args *InstanceListOptions) error { - vms, err := cli.GetInstances() - if err != nil { - return err - } - printList(vms, 0, 0, 0, []string{}) - return nil - }) - - type InstanceIdOptions struct { - ID string - } - - shellutils.R(&InstanceIdOptions{}, "instance-show", "show instance", func(cli *nutanix.SRegion, args *InstanceIdOptions) error { - vm, err := cli.GetInstance(args.ID) - if err != nil { - return err - } - printObject(vm) - return nil - }) - -} diff --git a/pkg/multicloud/nutanix/shell/printutils.go b/pkg/multicloud/nutanix/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/nutanix/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/nutanix/shell/storage.go b/pkg/multicloud/nutanix/shell/storage.go deleted file mode 100644 index 3b7b5bd919..0000000000 --- a/pkg/multicloud/nutanix/shell/storage.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/nutanix" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type StorageListOptions struct { - } - shellutils.R(&StorageListOptions{}, "storage-list", "list storage", func(cli *nutanix.SRegion, args *StorageListOptions) error { - storages, err := cli.GetStorages() - if err != nil { - return err - } - printList(storages, 0, 0, 0, []string{}) - return nil - }) - - type StorageIdOptions struct { - ID string - } - - shellutils.R(&StorageIdOptions{}, "storage-show", "show storage", func(cli *nutanix.SRegion, args *StorageIdOptions) error { - storage, err := cli.GetStorage(args.ID) - if err != nil { - return err - } - printObject(storage) - return nil - }) - -} diff --git a/pkg/multicloud/nutanix/shell/task.go b/pkg/multicloud/nutanix/shell/task.go deleted file mode 100644 index 70227f9d1c..0000000000 --- a/pkg/multicloud/nutanix/shell/task.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/nutanix" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type TaskListOptions struct { - } - shellutils.R(&TaskListOptions{}, "task-list", "list task", func(cli *nutanix.SRegion, args *TaskListOptions) error { - tasks, err := cli.GetTasks() - if err != nil { - return err - } - printList(tasks, 0, 0, 0, []string{}) - return nil - }) - - type TaskIdOptions struct { - ID string - } - - shellutils.R(&TaskIdOptions{}, "task-show", "show task", func(cli *nutanix.SRegion, args *TaskIdOptions) error { - task, err := cli.GetTask(args.ID) - if err != nil { - return err - } - printObject(task) - return nil - }) - -} diff --git a/pkg/multicloud/nutanix/shell/vpc.go b/pkg/multicloud/nutanix/shell/vpc.go deleted file mode 100644 index a144276f6c..0000000000 --- a/pkg/multicloud/nutanix/shell/vpc.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/nutanix" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - } - shellutils.R(&VpcListOptions{}, "vpc-list", "list vpc", func(cli *nutanix.SRegion, args *VpcListOptions) error { - vpcs, err := cli.GetVpcs() - if err != nil { - return err - } - printList(vpcs, 0, 0, 0, []string{}) - return nil - }) - - type VpcIdOptions struct { - ID string - } - - shellutils.R(&VpcIdOptions{}, "vpc-show", "show vpc", func(cli *nutanix.SRegion, args *VpcIdOptions) error { - vpc, err := cli.GetVpc(args.ID) - if err != nil { - return err - } - printObject(vpc) - return nil - }) - - shellutils.R(&VpcIdOptions{}, "vpc-delete", "delete vpc", func(cli *nutanix.SRegion, args *VpcIdOptions) error { - return cli.DeleteVpc(args.ID) - }) - - type VpcCreateOptions struct { - Name string - Desc string - CIDR string - } - - shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *nutanix.SRegion, args *VpcCreateOptions) error { - opts := cloudprovider.VpcCreateOptions{ - NAME: args.Name, - CIDR: args.CIDR, - Desc: args.Desc, - } - vpc, err := cli.CreateVpc(&opts) - if err != nil { - return err - } - printObject(vpc) - return nil - }) - -} diff --git a/pkg/multicloud/nutanix/storage.go b/pkg/multicloud/nutanix/storage.go deleted file mode 100644 index 8a984bf6de..0000000000 --- a/pkg/multicloud/nutanix/storage.go +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type DownMigrateTimesInSecs struct { - SSDSATA int `json:"SSD-SATA"` - SSDPCIe int `json:"SSD-PCIe"` - DASSATA int `json:"DAS-SATA"` -} - -type MappedRemoteContainers struct { -} - -type StorageStats struct { - HypervisorAvgIoLatencyUsecs string `json:"hypervisor_avg_io_latency_usecs"` - NumReadIops string `json:"num_read_iops"` - HypervisorWriteIoBandwidthKBps string `json:"hypervisor_write_io_bandwidth_kBps"` - TimespanUsecs string `json:"timespan_usecs"` - ControllerNumReadIops string `json:"controller_num_read_iops"` - ReadIoPpm string `json:"read_io_ppm"` - ControllerNumIops string `json:"controller_num_iops"` - TotalReadIoTimeUsecs string `json:"total_read_io_time_usecs"` - ControllerTotalReadIoTimeUsecs string `json:"controller_total_read_io_time_usecs"` - HypervisorNumIo string `json:"hypervisor_num_io"` - ControllerTotalTransformedUsageBytes string `json:"controller_total_transformed_usage_bytes"` - ControllerNumWriteIo string `json:"controller_num_write_io"` - AvgReadIoLatencyUsecs string `json:"avg_read_io_latency_usecs"` - ControllerTotalIoTimeUsecs string `json:"controller_total_io_time_usecs"` - ControllerTotalReadIoSizeKbytes string `json:"controller_total_read_io_size_kbytes"` - ControllerNumSeqIo string `json:"controller_num_seq_io"` - ControllerReadIoPpm string `json:"controller_read_io_ppm"` - ControllerTotalIoSizeKbytes string `json:"controller_total_io_size_kbytes"` - ControllerNumIo string `json:"controller_num_io"` - HypervisorAvgReadIoLatencyUsecs string `json:"hypervisor_avg_read_io_latency_usecs"` - NumWriteIops string `json:"num_write_iops"` - ControllerNumRandomIo string `json:"controller_num_random_io"` - NumIops string `json:"num_iops"` - HypervisorNumReadIo string `json:"hypervisor_num_read_io"` - HypervisorTotalReadIoTimeUsecs string `json:"hypervisor_total_read_io_time_usecs"` - ControllerAvgIoLatencyUsecs string `json:"controller_avg_io_latency_usecs"` - NumIo string `json:"num_io"` - ControllerNumReadIo string `json:"controller_num_read_io"` - HypervisorNumWriteIo string `json:"hypervisor_num_write_io"` - ControllerSeqIoPpm string `json:"controller_seq_io_ppm"` - ControllerReadIoBandwidthKBps string `json:"controller_read_io_bandwidth_kBps"` - ControllerIoBandwidthKBps string `json:"controller_io_bandwidth_kBps"` - HypervisorTimespanUsecs string `json:"hypervisor_timespan_usecs"` - HypervisorNumWriteIops string `json:"hypervisor_num_write_iops"` - TotalReadIoSizeKbytes string `json:"total_read_io_size_kbytes"` - HypervisorTotalIoSizeKbytes string `json:"hypervisor_total_io_size_kbytes"` - AvgIoLatencyUsecs string `json:"avg_io_latency_usecs"` - HypervisorNumReadIops string `json:"hypervisor_num_read_iops"` - ControllerWriteIoBandwidthKBps string `json:"controller_write_io_bandwidth_kBps"` - ControllerWriteIoPpm string `json:"controller_write_io_ppm"` - HypervisorAvgWriteIoLatencyUsecs string `json:"hypervisor_avg_write_io_latency_usecs"` - HypervisorTotalReadIoSizeKbytes string `json:"hypervisor_total_read_io_size_kbytes"` - ReadIoBandwidthKBps string `json:"read_io_bandwidth_kBps"` - HypervisorNumIops string `json:"hypervisor_num_iops"` - HypervisorIoBandwidthKBps string `json:"hypervisor_io_bandwidth_kBps"` - ControllerNumWriteIops string `json:"controller_num_write_iops"` - TotalIoTimeUsecs string `json:"total_io_time_usecs"` - ControllerRandomIoPpm string `json:"controller_random_io_ppm"` - ControllerAvgReadIoSizeKbytes string `json:"controller_avg_read_io_size_kbytes"` - TotalTransformedUsageBytes string `json:"total_transformed_usage_bytes"` - AvgWriteIoLatencyUsecs string `json:"avg_write_io_latency_usecs"` - NumReadIo string `json:"num_read_io"` - WriteIoBandwidthKBps string `json:"write_io_bandwidth_kBps"` - HypervisorReadIoBandwidthKBps string `json:"hypervisor_read_io_bandwidth_kBps"` - RandomIoPpm string `json:"random_io_ppm"` - TotalUntransformedUsageBytes string `json:"total_untransformed_usage_bytes"` - HypervisorTotalIoTimeUsecs string `json:"hypervisor_total_io_time_usecs"` - NumRandomIo string `json:"num_random_io"` - ControllerAvgWriteIoSizeKbytes string `json:"controller_avg_write_io_size_kbytes"` - ControllerAvgReadIoLatencyUsecs string `json:"controller_avg_read_io_latency_usecs"` - NumWriteIo string `json:"num_write_io"` - TotalIoSizeKbytes string `json:"total_io_size_kbytes"` - IoBandwidthKBps string `json:"io_bandwidth_kBps"` - ControllerTimespanUsecs string `json:"controller_timespan_usecs"` - NumSeqIo string `json:"num_seq_io"` - SeqIoPpm string `json:"seq_io_ppm"` - WriteIoPpm string `json:"write_io_ppm"` - ControllerAvgWriteIoLatencyUsecs string `json:"controller_avg_write_io_latency_usecs"` -} -type StorageUsageStats struct { - StorageUserUnreservedOwnUsageBytes string `json:"storage.user_unreserved_own_usage_bytes"` - StorageReservedFreeBytes string `json:"storage.reserved_free_bytes"` - DataReductionOverallSavingRatioPpm string `json:"data_reduction.overall.saving_ratio_ppm"` - DataReductionUserSavedBytes string `json:"data_reduction.user_saved_bytes"` - StorageTierDasSataUsageBytes string `json:"storage_tier.das-sata.usage_bytes"` - DataReductionErasureCodingPostReductionBytes string `json:"data_reduction.erasure_coding.post_reduction_bytes"` - StorageReservedUsageBytes string `json:"storage.reserved_usage_bytes"` - StorageUserUnreservedSharedUsageBytes string `json:"storage.user_unreserved_shared_usage_bytes"` - StorageUserUnreservedUsageBytes int64 `json:"storage.user_unreserved_usage_bytes"` - StorageUsageBytes string `json:"storage.usage_bytes"` - DataReductionCompressionUserSavedBytes string `json:"data_reduction.compression.user_saved_bytes"` - DataReductionErasureCodingUserPreReductionBytes string `json:"data_reduction.erasure_coding.user_pre_reduction_bytes"` - StorageUserUnreservedCapacityBytes string `json:"storage.user_unreserved_capacity_bytes"` - StorageUserCapacityBytes int64 `json:"storage.user_capacity_bytes"` - StorageUserStoragePoolCapacityBytes string `json:"storage.user_storage_pool_capacity_bytes"` - DataReductionPreReductionBytes string `json:"data_reduction.pre_reduction_bytes"` - DataReductionUserPreReductionBytes string `json:"data_reduction.user_pre_reduction_bytes"` - StorageUserOtherContainersReservedCapacityBytes string `json:"storage.user_other_containers_reserved_capacity_bytes"` - DataReductionErasureCodingPreReductionBytes string `json:"data_reduction.erasure_coding.pre_reduction_bytes"` - StorageCapacityBytes int64 `json:"storage.capacity_bytes"` - StorageUserUnreservedFreeBytes string `json:"storage.user_unreserved_free_bytes"` - DataReductionCloneUserSavedBytes string `json:"data_reduction.clone.user_saved_bytes"` - DataReductionDedupPostReductionBytes string `json:"data_reduction.dedup.post_reduction_bytes"` - DataReductionCloneSavingRatioPpm string `json:"data_reduction.clone.saving_ratio_ppm"` - StorageLogicalUsageBytes string `json:"storage.logical_usage_bytes"` - DataReductionSavedBytes string `json:"data_reduction.saved_bytes"` - StorageUserDiskPhysicalUsageBytes string `json:"storage.user_disk_physical_usage_bytes"` - StorageFreeBytes string `json:"storage.free_bytes"` - DataReductionCompressionPostReductionBytes string `json:"data_reduction.compression.post_reduction_bytes"` - DataReductionCompressionUserPostReductionBytes string `json:"data_reduction.compression.user_post_reduction_bytes"` - StorageUserFreeBytes string `json:"storage.user_free_bytes"` - StorageUnreservedFreeBytes string `json:"storage.unreserved_free_bytes"` - StorageUserContainerOwnUsageBytes string `json:"storage.user_container_own_usage_bytes"` - DataReductionCompressionSavingRatioPpm string `json:"data_reduction.compression.saving_ratio_ppm"` - StorageUserUsageBytes int64 `json:"storage.user_usage_bytes"` - DataReductionErasureCodingUserSavedBytes string `json:"data_reduction.erasure_coding.user_saved_bytes"` - DataReductionDedupSavingRatioPpm string `json:"data_reduction.dedup.saving_ratio_ppm"` - StorageUnreservedCapacityBytes string `json:"storage.unreserved_capacity_bytes"` - StorageUserReservedUsageBytes string `json:"storage.user_reserved_usage_bytes"` - DataReductionCompressionUserPreReductionBytes string `json:"data_reduction.compression.user_pre_reduction_bytes"` - DataReductionUserPostReductionBytes string `json:"data_reduction.user_post_reduction_bytes"` - DataReductionOverallUserSavedBytes string `json:"data_reduction.overall.user_saved_bytes"` - DataReductionErasureCodingParityBytes string `json:"data_reduction.erasure_coding.parity_bytes"` - DataReductionSavingRatioPpm string `json:"data_reduction.saving_ratio_ppm"` - StorageUnreservedOwnUsageBytes string `json:"storage.unreserved_own_usage_bytes"` - DataReductionErasureCodingSavingRatioPpm string `json:"data_reduction.erasure_coding.saving_ratio_ppm"` - StorageUserReservedCapacityBytes string `json:"storage.user_reserved_capacity_bytes"` - DataReductionThinProvisionUserSavedBytes string `json:"data_reduction.thin_provision.user_saved_bytes"` - StorageDiskPhysicalUsageBytes string `json:"storage.disk_physical_usage_bytes"` - DataReductionErasureCodingUserPostReductionBytes string `json:"data_reduction.erasure_coding.user_post_reduction_bytes"` - DataReductionCompressionPreReductionBytes string `json:"data_reduction.compression.pre_reduction_bytes"` - DataReductionDedupPreReductionBytes string `json:"data_reduction.dedup.pre_reduction_bytes"` - DataReductionDedupUserSavedBytes string `json:"data_reduction.dedup.user_saved_bytes"` - StorageUnreservedUsageBytes string `json:"storage.unreserved_usage_bytes"` - StorageTierSsdUsageBytes string `json:"storage_tier.ssd.usage_bytes"` - DataReductionPostReductionBytes string `json:"data_reduction.post_reduction_bytes"` - DataReductionThinProvisionSavingRatioPpm string `json:"data_reduction.thin_provision.saving_ratio_ppm"` - StorageReservedCapacityBytes string `json:"storage.reserved_capacity_bytes"` - StorageUserReservedFreeBytes string `json:"storage.user_reserved_free_bytes"` -} - -type SStorage struct { - multicloud.SStorageBase - multicloud.STagBase - - zone *SZone - - StorageContainerUUID string `json:"storage_container_uuid"` - Name string `json:"name"` - ClusterUUID string `json:"cluster_uuid"` - MarkedForRemoval bool `json:"marked_for_removal"` - MaxCapacity int64 `json:"max_capacity"` - TotalExplicitReservedCapacity int `json:"total_explicit_reserved_capacity"` - TotalImplicitReservedCapacity int `json:"total_implicit_reserved_capacity"` - AdvertisedCapacity interface{} `json:"advertised_capacity"` - ReplicationFactor int `json:"replication_factor"` - OplogReplicationFactor int `json:"oplog_replication_factor"` - NfsWhitelist []interface{} `json:"nfs_whitelist"` - NfsWhitelistInherited bool `json:"nfs_whitelist_inherited"` - RandomIoPreference []string `json:"random_io_preference"` - SeqIoPreference []string `json:"seq_io_preference"` - IlmPolicy interface{} `json:"ilm_policy"` - DownMigrateTimesInSecs DownMigrateTimesInSecs `json:"down_migrate_times_in_secs"` - ErasureCode string `json:"erasure_code"` - InlineEcEnabled interface{} `json:"inline_ec_enabled"` - PreferHigherEcfaultDomain interface{} `json:"prefer_higher_ecfault_domain"` - ErasureCodeDelaySecs interface{} `json:"erasure_code_delay_secs"` - FingerPrintOnWrite string `json:"finger_print_on_write"` - OnDiskDedup string `json:"on_disk_dedup"` - CompressionEnabled bool `json:"compression_enabled"` - CompressionDelayInSecs int `json:"compression_delay_in_secs"` - IsNutanixManaged interface{} `json:"is_nutanix_managed"` - EnableSoftwareEncryption bool `json:"enable_software_encryption"` - VstoreNameList []string `json:"vstore_name_list"` - MappedRemoteContainers MappedRemoteContainers `json:"mapped_remote_containers"` - Stats StorageStats `json:"stats"` - UsageStats StorageUsageStats `json:"usage_stats"` - Encrypted interface{} `json:"encrypted"` -} - -func (self *SStorage) GetName() string { - return self.Name -} - -func (self *SStorage) GetId() string { - return self.StorageContainerUUID -} - -func (self *SStorage) GetGlobalId() string { - return self.StorageContainerUUID -} - -func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := self.zone.region.GetDisks(self.GetGlobalId(), "") - if err != nil { - return nil, errors.Wrapf(err, "GetDisks") - } - ret := []cloudprovider.ICloudDisk{} - for i := range disks { - disks[i].storage = self - ret = append(ret, &disks[i]) - } - return ret, nil -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStorage) GetCapacityMB() int64 { - return self.UsageStats.StorageUserCapacityBytes / 1024 / 1024 -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return self.UsageStats.StorageUserUsageBytes / 1024 / 1024 -} - -func (self *SStorage) GetEnabled() bool { - return true -} - -func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - disk, err := self.zone.region.GetDisk(id) - if err != nil { - return nil, err - } - if disk.StorageContainerUUID != self.GetGlobalId() { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) - } - disk.storage = self - return disk, nil -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return &SStoragecache{storage: self, region: self.zone.region} -} - -func (self *SRegion) GetStorages() ([]SStorage, error) { - storages := []SStorage{} - err := self.listAll("storage_containers", nil, &storages) - if err != nil { - return nil, err - } - ret := []SStorage{} - for i := range storages { - if storages[i].Name == "NutanixManagementShare" { // https://portal.nutanix.com/page/documents/details?targetId=Web-Console-Guide-Prism-v5_15-ZH:wc-container-create-wc-t.html - continue - } - ret = append(ret, storages[i]) - } - return ret, nil -} - -func (self *SRegion) GetStorage(id string) (*SStorage, error) { - storage := &SStorage{} - return storage, self.get("storage_containers", id, nil, storage) -} - -func (self *SStorage) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -func (self *SStorage) GetMediumType() string { - return api.DISK_TYPE_SSD -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) Refresh() error { - storage, err := self.zone.region.GetStorage(self.GetGlobalId()) - if err != nil { - return err - } - return jsonutils.Update(self, storage) -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (self *SStorage) GetStorageType() string { - return api.STORAGE_LOCAL -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} - -func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - zones, err := self.GetIZones() - if err != nil { - return nil, errors.Wrapf(err, "GetIZones") - } - for i := range zones { - storage, err := zones[i].GetIStorageById(id) - if err == nil && storage != nil { - return storage, nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} diff --git a/pkg/multicloud/nutanix/storagecache.go b/pkg/multicloud/nutanix/storagecache.go deleted file mode 100644 index f9168f0ada..0000000000 --- a/pkg/multicloud/nutanix/storagecache.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "context" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/esxi/options" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/mcclient/auth" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.STagBase - - storage *SStorage - region *SRegion -} - -func (self *SStoragecache) GetName() string { - return self.storage.GetName() -} - -func (self *SStoragecache) GetId() string { - return self.storage.GetId() -} - -func (self *SStoragecache) GetGlobalId() string { - return self.storage.GetGlobalId() -} - -func (self *SStoragecache) GetStatus() string { - return "available" -} - -func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - images, err := self.region.GetImages() - if err != nil { - return nil, errors.Wrapf(err, "GetImages") - } - ret := []cloudprovider.ICloudImage{} - for i := range images { - if images[i].StorageContainerUUID != self.storage.GetGlobalId() { - continue - } - images[i].cache = self - ret = append(ret, &images[i]) - } - return ret, nil -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SStoragecache) GetIImageById(id string) (cloudprovider.ICloudImage, error) { - image, err := self.region.GetImage(id) - if err != nil { - return nil, err - } - image.cache = self - return image, nil -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, opts *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { - s := auth.GetAdminSession(ctx, options.Options.Region) - - meta, reader, size, err := modules.Images.Download(s, opts.ImageId, string(qemuimg.QCOW2), false) - if err != nil { - return "", err - } - log.Infof("meta data %s", meta) - image, err := self.region.CreateImage(self.storage.StorageContainerUUID, opts, size, reader, callback) - if err != nil { - return "", err - } - if callback != nil { - callback(100.0) - } - image.cache = self - return image.GetGlobalId(), nil -} - -func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storages, err := self.GetStorages() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStoragecache{} - for i := range storages { - cache := &SStoragecache{storage: &storages[i], region: self} - ret = append(ret, cache) - } - return ret, nil -} - -func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - storage, err := self.GetStorage(id) - if err != nil { - return nil, errors.Wrapf(err, "GetStorage") - } - return &SStoragecache{region: self, storage: storage}, nil -} diff --git a/pkg/multicloud/nutanix/vpc.go b/pkg/multicloud/nutanix/vpc.go deleted file mode 100644 index c962d5256a..0000000000 --- a/pkg/multicloud/nutanix/vpc.go +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "fmt" - "net/url" - "sort" - "strconv" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type DhcpOptions struct { -} - -type SPool struct { - Range string `json:"range"` -} - -type IPConfig struct { - NetworkAddress string `json:"network_address"` - PrefixLength int `json:"prefix_length"` - DefaultGateway string `json:"default_gateway"` - DhcpOptions DhcpOptions `json:"dhcp_options"` - Pool []SPool `json:"pool"` - DhcpServerAddress string `json:"dhcp_server_address"` -} - -type SVpc struct { - multicloud.SVpc - multicloud.STagBase - - region *SRegion - - LogicalTimestamp int `json:"logical_timestamp"` - VlanID int `json:"vlan_id"` - UUID string `json:"uuid"` - Name string `json:"name"` - IPConfig IPConfig `json:"ip_config,omitempty"` -} - -func (self *SVpc) GetName() string { - return self.Name -} - -func (self *SVpc) GetId() string { - return self.UUID -} - -func (self *SVpc) GetGlobalId() string { - return self.UUID -} - -func (self *SVpc) Delete() error { - return self.region.DeleteVpc(self.UUID) -} - -func (self *SVpc) GetCidrBlock() string { - if len(self.IPConfig.NetworkAddress) > 0 { - return fmt.Sprintf("%s/%d", self.IPConfig.NetworkAddress, self.IPConfig.PrefixLength) - } - return "" -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - return []cloudprovider.ICloudRouteTable{}, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - return []cloudprovider.ICloudSecurityGroup{}, nil -} - -func (self *SRegion) GetVpcs() ([]SVpc, error) { - vpcs := []SVpc{} - _, err := self.list("networks", url.Values{}, &vpcs) - return vpcs, err -} - -func (self *SVpc) getWire() *SWire { - return &SWire{vpc: self} -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - wire := self.getWire() - return []cloudprovider.ICloudWire{wire}, nil -} - -func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { - wires, err := self.GetIWires() - if err != nil { - return nil, err - } - for i := range wires { - if wires[i].GetGlobalId() == wireId { - return wires[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SVpc) GetIsDefault() bool { - return len(self.GetCidrBlock()) > 0 -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} - -func (self *SRegion) GetVpc(id string) (*SVpc, error) { - vpc := &SVpc{region: self} - return vpc, self.get("networks", id, url.Values{}, vpc) -} - -func (self *SRegion) CreateVpc(opts *cloudprovider.VpcCreateOptions) (*SVpc, error) { - ipConfig := map[string]interface{}{} - if len(opts.CIDR) > 0 { - if addrs := strings.Split(opts.CIDR, "/"); len(addrs) == 2 { - ipConfig["network_address"] = addrs[0] - ipConfig["prefix_length"], _ = strconv.Atoi(addrs[1]) - } - - } - vpcs, err := self.GetVpcs() - if err != nil { - return nil, errors.Wrapf(err, "GetVpcs") - } - vlanId, vlanIds := -1, []int{} - for i := range vpcs { - vlanIds = append(vlanIds, vpcs[i].VlanID) - } - sort.Ints(vlanIds) - for _, vlan := range vlanIds { - if vlan == vlanId+1 { - vlanId = vlan - } - } - params := map[string]interface{}{ - "name": opts.NAME, - "annotation": opts.Desc, - "ip_config": ipConfig, - "vlan_id": vlanId + 1, - } - ret := struct { - NetworkUUID string - }{} - err = self.post("networks", jsonutils.Marshal(params), &ret) - if err != nil { - return nil, err - } - return self.GetVpc(ret.NetworkUUID) -} - -func (self *SRegion) DeleteVpc(id string) error { - return self.delete("networks", id) -} diff --git a/pkg/multicloud/nutanix/wire.go b/pkg/multicloud/nutanix/wire.go deleted file mode 100644 index 75a6f79ef7..0000000000 --- a/pkg/multicloud/nutanix/wire.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.STagBase - - vpc *SVpc -} - -func (self *SWire) GetName() string { - return self.vpc.GetName() -} - -func (self *SWire) GetId() string { - return self.vpc.GetId() -} - -func (self *SWire) GetGlobalId() string { - return self.vpc.GetGlobalId() -} - -func (self *SWire) IsEmulated() bool { - return true -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - network, err := self.vpc.region.CreateNetwork(self.vpc.UUID, opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateNetwork") - } - return network, nil -} - -func (self *SWire) GetBandwidth() int { - return 10000 -} - -func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - ret := []cloudprovider.ICloudNetwork{} - if len(self.vpc.IPConfig.Pool) == 0 { - network := &SNetwork{wire: self} - ret = append(ret, network) - } - for _, pool := range self.vpc.IPConfig.Pool { - network := &SNetwork{wire: self} - network.Range = pool.Range - ret = append(ret, network) - } - return ret, nil -} - -func (self *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { - networks, err := self.GetINetworks() - if err != nil { - return nil, err - } - - for i := range networks { - if networks[i].GetGlobalId() == netid { - return networks[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - cluster := SCluster{} - err := self.vpc.region.get("cluster", "", nil, &cluster) - if err != nil { - return nil - } - return &SZone{SCluster: cluster, region: self.vpc.region} -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} diff --git a/pkg/multicloud/nutanix/zone.go b/pkg/multicloud/nutanix/zone.go deleted file mode 100644 index ddcdb0591a..0000000000 --- a/pkg/multicloud/nutanix/zone.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 nutanix - -import ( - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SZone struct { - multicloud.STagBase - multicloud.SResourceBase - - SCluster - region *SRegion -} - -func (self *SZone) GetName() string { - return self.Name -} - -func (self *SZone) GetId() string { - return self.UUID -} - -func (self *SZone) GetGlobalId() string { - return self.UUID -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) - return table -} - -func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - hosts, err := self.region.GetHosts() - if err != nil { - return nil, errors.Wrapf(err, "GetIHosts") - } - firstHost := true - ret := []cloudprovider.ICloudHost{} - for i := range hosts { - if hosts[i].ClusterUUID != self.UUID { - continue - } - hosts[i].zone = self - hosts[i].firstHost = firstHost - ret = append(ret, &hosts[i]) - if firstHost { - firstHost = false - } - } - return ret, nil -} - -func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - host, err := self.region.GetHost(id) - if err != nil { - return nil, errors.Wrapf(err, "GetIHostById(%s)", id) - } - if host.ClusterUUID != self.UUID { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) - } - host.zone = self - return host, nil -} - -func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SZone) GetStatus() string { - return api.ZONE_ENABLE -} - -func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := self.region.GetStorages() - if err != nil { - return nil, errors.Wrapf(err, "GetStorages") - } - ret := []cloudprovider.ICloudStorage{} - for i := range storages { - if storages[i].ClusterUUID != self.UUID { - continue - } - storages[i].zone = self - ret = append(ret, &storages[i]) - } - return ret, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storage, err := self.region.GetStorage(id) - if err != nil { - return nil, errors.Wrapf(err, "GetStorage %s", id) - } - if storage.ClusterUUID != self.UUID { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) - } - storage.zone = self - return storage, nil -} diff --git a/pkg/multicloud/objectstore/ceph/bucket.go b/pkg/multicloud/objectstore/ceph/bucket.go deleted file mode 100644 index 9c9d75347b..0000000000 --- a/pkg/multicloud/objectstore/ceph/bucket.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ceph - -import ( - "context" - "strconv" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" -) - -type SCephRadosBucket struct { - *objectstore.SBucket -} - -func (b *SCephRadosBucket) GetStats() cloudprovider.SBucketStats { - _, hdr, _ := b.GetIBucketProvider().S3Client().BucketExists(b.Name) - if hdr != nil { - sizeBytesStr := hdr.Get("X-Rgw-Bytes-Used") - sizeBytes, _ := strconv.ParseInt(sizeBytesStr, 10, 64) - objCntStr := hdr.Get("X-Rgw-Object-Count") - objCnt, _ := strconv.ParseInt(objCntStr, 10, 64) - return cloudprovider.SBucketStats{ - SizeBytes: sizeBytes, - ObjectCount: int(objCnt), - } - } - return b.SBucket.GetStats() -} - -func (b *SCephRadosBucket) GetLimit() cloudprovider.SBucketStats { - if cephCli, ok := b.GetIBucketProvider().(*SCephRadosClient); ok { - quota, err := cephCli.adminApi.GetBucketQuota(context.Background(), cephCli.GetAccountId(), b.Name) - if err == nil { - limit := cloudprovider.SBucketStats{} - if quota.Enabled.IsTrue() { - limit.SizeBytes = quota.MaxSize - limit.ObjectCount = quota.MaxObjects - } - return limit - } - } - return b.SBucket.GetLimit() -} - -func (b *SCephRadosBucket) SetLimit(limit cloudprovider.SBucketStats) error { - /*if cephCli, ok := b.GetIBucketProvider().(*SCephRadosClient); ok { - err := cephCli.adminApi.SetBucketQuota(context.Background(), cephCli.GetAccountId(), b.Name, limit.SizeBytes, limit.ObjectCount) - return errors.Wrap(err, "cephCli.adminApi.SetBucketQuota") - } - return b.SBucket.SetLimit(limit)*/ - return httperrors.ErrNotSupported -} diff --git a/pkg/multicloud/objectstore/ceph/doc.go b/pkg/multicloud/objectstore/ceph/doc.go deleted file mode 100644 index 330f4c76e0..0000000000 --- a/pkg/multicloud/objectstore/ceph/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ceph // import "yunion.io/x/onecloud/pkg/multicloud/objectstore/ceph" diff --git a/pkg/multicloud/objectstore/ceph/provider/doc.go b/pkg/multicloud/objectstore/ceph/provider/doc.go deleted file mode 100644 index fbb350f37d..0000000000 --- a/pkg/multicloud/objectstore/ceph/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/objectstore/ceph/provider" diff --git a/pkg/multicloud/objectstore/ceph/provider/provider.go b/pkg/multicloud/objectstore/ceph/provider/provider.go deleted file mode 100644 index 16f4d2b3f9..0000000000 --- a/pkg/multicloud/objectstore/ceph/provider/provider.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" - "yunion.io/x/onecloud/pkg/multicloud/objectstore/ceph" - s3provider "yunion.io/x/onecloud/pkg/multicloud/objectstore/provider" -) - -type SCephRadosProviderFactory struct { - s3provider.SObjectStoreProviderFactory -} - -func (self *SCephRadosProviderFactory) GetId() string { - return api.CLOUD_PROVIDER_CEPH -} - -func (self *SCephRadosProviderFactory) GetName() string { - return api.CLOUD_PROVIDER_CEPH -} - -func (self *SCephRadosProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - client, err := ceph.NewCephRados( - objectstore.NewObjectStoreClientConfig( - cfg.URL, cfg.Account, cfg.Secret, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return s3provider.NewObjectStoreProvider(self, client, []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - }), nil -} - -func (self *SCephRadosProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - return map[string]string{ - "S3_ACCESS_KEY": info.Account, - "S3_SECRET": info.Secret, - "S3_ACCESS_URL": info.Url, - "S3_BACKEND": api.CLOUD_PROVIDER_CEPH, - }, nil -} - -func init() { - factory := SCephRadosProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} diff --git a/pkg/multicloud/objectstore/doc.go b/pkg/multicloud/objectstore/doc.go deleted file mode 100644 index 1f75c24a3a..0000000000 --- a/pkg/multicloud/objectstore/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 objectstore // import "yunion.io/x/onecloud/pkg/multicloud/objectstore" diff --git a/pkg/multicloud/objectstore/object.go b/pkg/multicloud/objectstore/object.go deleted file mode 100644 index e69344bce0..0000000000 --- a/pkg/multicloud/objectstore/object.go +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 objectstore - -import ( - "context" - "net/http" - "strings" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/s3cli" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - META_HEADER = "X-Amz-Meta-" -) - -type SObject struct { - bucket *SBucket - - cloudprovider.SBaseCloudObject -} - -func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { - return o.bucket -} - -func (o *SObject) GetAcl() cloudprovider.TBucketACLType { - acl, err := o.bucket.client.GetObjectAcl(o.bucket.Name, o.Key) - if err != nil { - if e, ok := errors.Cause(err).(s3cli.ErrorResponse); ok { - if e.Code == "NoSuchKey" || e.Message == "The specified key does not exist." { - objects, _ := o.bucket.ListObjects(o.Key, "", "", 1) - if len(objects.Objects) > 0 { - return cloudprovider.ACLPrivate - } - } - } - log.Errorf("o.bucket.client.GetObjectAcl error %s", err) - return cloudprovider.ACLPrivate - } - return acl -} - -func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { - err := o.bucket.client.SetObjectAcl(o.bucket.Name, o.Key, aclStr) - if err != nil { - if strings.Contains(err.Error(), "not implemented") || strings.Contains(err.Error(), "Please use AWS4-HMAC-SHA256") { - // ignore not implemented error - return nil // cloudprovider.ErrNotImplemented - } else { - return errors.Wrap(err, "o.bucket.client.SetObjectAcl") - } - } - return nil -} - -func (o *SObject) GetMeta() http.Header { - if o.Meta != nil { - return o.Meta - } - cli := o.bucket.client.S3Client() - objInfo, err := cli.StatObject(o.bucket.Name, o.Key, s3cli.StatObjectOptions{}) - if err != nil { - log.Errorf("cli.statObject fail %s", err) - return nil - } - if len(objInfo.ContentType) > 0 { - objInfo.Metadata.Set(cloudprovider.META_HEADER_CONTENT_TYPE, objInfo.ContentType) - } - o.Meta = cloudprovider.FetchMetaFromHttpHeader(META_HEADER, objInfo.Metadata) - return o.Meta -} - -func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { - return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) -} diff --git a/pkg/multicloud/objectstore/provider/doc.go b/pkg/multicloud/objectstore/provider/doc.go deleted file mode 100644 index 2ce176816e..0000000000 --- a/pkg/multicloud/objectstore/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/objectstore/provider" diff --git a/pkg/multicloud/objectstore/provider/provider.go b/pkg/multicloud/objectstore/provider/provider.go deleted file mode 100644 index dc335e99be..0000000000 --- a/pkg/multicloud/objectstore/provider/provider.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" -) - -type SObjectStoreProviderFactory struct { - cloudprovider.SPremiseBaseProviderFactory -} - -func (self *SObjectStoreProviderFactory) GetId() string { - return api.CLOUD_PROVIDER_GENERICS3 -} - -func (self *SObjectStoreProviderFactory) GetName() string { - return api.CLOUD_PROVIDER_GENERICS3 -} - -func (self *SObjectStoreProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - if len(input.Endpoint) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "endpoint") - } - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - output.AccessUrl = input.Endpoint - return output, nil -} - -func (self *SObjectStoreProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func (self *SObjectStoreProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - client, err := objectstore.NewObjectStoreClient( - objectstore.NewObjectStoreClientConfig( - cfg.URL, cfg.Account, cfg.Secret, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return NewObjectStoreProvider(self, client, []string{ - string(cloudprovider.ACLPrivate), - }), nil -} - -func (self *SObjectStoreProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - return map[string]string{ - "S3_ACCESS_KEY": info.Account, - "S3_SECRET": info.Secret, - "S3_ACCESS_URL": info.Url, - "S3_BACKEND": api.CLOUD_PROVIDER_GENERICS3, - }, nil -} - -func init() { - factory := SObjectStoreProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SObjectStoreProvider struct { - cloudprovider.SBaseProvider - client objectstore.IBucketProvider - supportedAcls []string -} - -func NewObjectStoreProvider(factory cloudprovider.ICloudProviderFactory, client objectstore.IBucketProvider, acls []string) *SObjectStoreProvider { - return &SObjectStoreProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(factory), - client: client, - supportedAcls: acls, - } -} - -func (self *SObjectStoreProvider) GetIRegions() []cloudprovider.ICloudRegion { - return nil -} - -func (self *SObjectStoreProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SObjectStoreProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SObjectStoreProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { - return self.client, nil -} - -func (self *SObjectStoreProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SObjectStoreProvider) GetSysInfo() (jsonutils.JSONObject, error) { - return self.client.About(), nil -} - -func (self *SObjectStoreProvider) GetVersion() string { - return self.client.GetVersion() -} - -func (self *SObjectStoreProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SObjectStoreProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SObjectStoreProvider) GetStorageClasses(regionId string) []string { - return []string{} -} - -func (self *SObjectStoreProvider) GetBucketCannedAcls(regionId string) []string { - return self.supportedAcls -} - -func (self *SObjectStoreProvider) GetObjectCannedAcls(regionId string) []string { - return self.supportedAcls -} - -func (self *SObjectStoreProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} diff --git a/pkg/multicloud/objectstore/shell/bucket.go b/pkg/multicloud/objectstore/shell/bucket.go deleted file mode 100644 index f44f1c4081..0000000000 --- a/pkg/multicloud/objectstore/shell/bucket.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import "yunion.io/x/onecloud/pkg/multicloud/objectstore" - -func init() { - objectstore.S3Shell() -} diff --git a/pkg/multicloud/objectstore/shell/doc.go b/pkg/multicloud/objectstore/shell/doc.go deleted file mode 100644 index 48acf30c38..0000000000 --- a/pkg/multicloud/objectstore/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/objectstore/shell" diff --git a/pkg/multicloud/objectstore/shell/minio.go b/pkg/multicloud/objectstore/shell/minio.go deleted file mode 100644 index a39ae2f4fb..0000000000 --- a/pkg/multicloud/objectstore/shell/minio.go +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type MinioBucketOption struct { - BUCKET string `help:"name of bucket"` - } - shellutils.R(&MinioBucketOption{}, "bucket-head", "HEAD bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error { - cli.IBucketExist(args.BUCKET) - return nil - }) - - shellutils.R(&MinioBucketOption{}, "bucket-acl", "Get ACL of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error { - acl, err := cli.GetIBucketAcl(args.BUCKET) - if err != nil { - return err - } - fmt.Println("ACL:", acl) - return nil - }) - - type MinioBucketCannedAclConfigOption struct { - BUCKET string `help:"name of bucket"` - ACL string `help:"canned ACL" choices:"private|public-read|public-read-write|auth-read"` - } - shellutils.R(&MinioBucketCannedAclConfigOption{}, "bucket-canned-acl-config", "Set canned ACL of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketCannedAclConfigOption) error { - err := cli.SetIBucketAcl(args.BUCKET, cloudprovider.TBucketACLType(args.ACL)) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&MinioBucketOption{}, "bucket-policy", "Get Policy of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error { - policy, err := cli.GetIBucketPolicy(args.BUCKET) - if err != nil { - return err - } - fmt.Println("Policy:", policy) - return nil - }) - - shellutils.R(&MinioBucketOption{}, "bucket-lifecycle", "Get lifecycle of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error { - lifecycle, err := cli.GetIBucketLiftcycle(args.BUCKET) - if err != nil { - return err - } - fmt.Println("Lifecycle:", lifecycle) - return nil - }) - - shellutils.R(&MinioBucketOption{}, "bucket-info", "Get info of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error { - info, err := cli.GetIBucketInfo(args.BUCKET) - if err != nil { - return err - } - fmt.Println("Info:", info) - return nil - }) - - shellutils.R(&MinioBucketOption{}, "bucket-location", "Get location of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error { - info, err := cli.GetIBucketLocation(args.BUCKET) - if err != nil { - return err - } - fmt.Println("Info:", info) - return nil - }) - - shellutils.R(&MinioBucketOption{}, "bucket-website", "Get website info of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error { - info, err := cli.GetIBucketWebsite(args.BUCKET) - if err != nil { - return err - } - fmt.Println("Info:", info) - return nil - }) - - shellutils.R(&MinioBucketOption{}, "bucket-logging", "Get logging configuration of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error { - info, err := cli.GetIBucketLogging(args.BUCKET) - if err != nil { - return err - } - fmt.Println("Logging:", info) - return nil - }) - - type MinioSetLoggingOption struct { - BUCKET string `help:"id or name of bucket"` - Target string `help:"target bucket"` - Prefix string `help:"target prefix"` - Email string `help:"email"` - } - shellutils.R(&MinioSetLoggingOption{}, "bucket-logging-config", "Set logging configuration of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioSetLoggingOption) error { - err := cli.SetIBucketLogging(args.BUCKET, args.Target, args.Prefix, args.Email) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&MinioBucketOption{}, "bucket-referer", "Get info of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error { - info, err := cli.GetIBucketReferer(args.BUCKET) - if err != nil { - return err - } - fmt.Println("Info:", info) - return nil - }) - - shellutils.R(&MinioBucketOption{}, "bucket-cors", "Get info of bucket", func(cli *objectstore.SObjectStoreClient, args *MinioBucketOption) error { - info, err := cli.GetIBucketCors(args.BUCKET) - if err != nil { - return err - } - fmt.Println("Info:", info) - return nil - }) -} diff --git a/pkg/multicloud/objectstore/shell/printutils.go b/pkg/multicloud/objectstore/shell/printutils.go deleted file mode 100644 index 94b9f1fc45..0000000000 --- a/pkg/multicloud/objectstore/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import "yunion.io/x/onecloud/pkg/util/printutils" - -func printList(data interface{}, columns []string) { - printutils.PrintGetterList(data, columns) -} - -func printObject(obj interface{}) { - printutils.PrintInterfaceObject(obj) -} diff --git a/pkg/multicloud/objectstore/xsky/bucket.go b/pkg/multicloud/objectstore/xsky/bucket.go deleted file mode 100644 index 5af598c601..0000000000 --- a/pkg/multicloud/objectstore/xsky/bucket.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 xsky - -import ( - "context" - "strconv" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" -) - -type SXskyBucket struct { - *objectstore.SBucket - - client *SXskyClient -} - -func (b *SXskyBucket) GetStats() cloudprovider.SBucketStats { - _, hdr, _ := b.GetIBucketProvider().S3Client().BucketExists(b.Name) - if hdr != nil { - sizeBytesStr := hdr.Get("X-Rgw-Bytes-Used") - sizeBytes, _ := strconv.ParseInt(sizeBytesStr, 10, 64) - objCntStr := hdr.Get("X-Rgw-Object-Count") - objCnt, _ := strconv.ParseInt(objCntStr, 10, 64) - return cloudprovider.SBucketStats{ - SizeBytes: sizeBytes, - ObjectCount: int(objCnt), - } - } - return b.SBucket.GetStats() -} - -func (b *SXskyBucket) LimitSupport() cloudprovider.SBucketStats { - return cloudprovider.SBucketStats{ - SizeBytes: 1, - ObjectCount: 1, - } -} - -func (b *SXskyBucket) GetLimit() cloudprovider.SBucketStats { - limit := cloudprovider.SBucketStats{} - bucket, err := b.client.adminApi.getBucketByName(context.Background(), b.Name) - if err != nil { - log.Errorf("b.client.adminApi.getBucketByName error %s", err) - } else { - limit.SizeBytes = bucket.QuotaMaxSize - limit.ObjectCount = bucket.QuotaMaxObjects - } - return limit -} - -func (b *SXskyBucket) SetLimit(limit cloudprovider.SBucketStats) error { - bucket, err := b.client.adminApi.getBucketByName(context.Background(), b.Name) - if err != nil { - return errors.Wrap(err, "b.client.adminApi.getBucketByName") - } - input := sBucketQuotaInput{} - input.OsBucket.QuotaMaxObjects = limit.ObjectCount - input.OsBucket.QuotaMaxSize = limit.SizeBytes - err = b.client.adminApi.setBucketQuota(context.Background(), bucket.Id, input) - if err != nil { - return errors.Wrap(err, "b.client.adminApi.setBucketQuota") - } - cloudprovider.Wait(time.Second, 30*time.Second, func() (bool, error) { - target := b.GetLimit() - if target.SizeBytes == limit.SizeBytes && target.ObjectCount == limit.ObjectCount { - return true, nil - } - return false, nil - }) - return nil -} diff --git a/pkg/multicloud/objectstore/xsky/doc.go b/pkg/multicloud/objectstore/xsky/doc.go deleted file mode 100644 index 71b68d83c7..0000000000 --- a/pkg/multicloud/objectstore/xsky/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 xsky // import "yunion.io/x/onecloud/pkg/multicloud/objectstore/xsky" diff --git a/pkg/multicloud/objectstore/xsky/provider/doc.go b/pkg/multicloud/objectstore/xsky/provider/doc.go deleted file mode 100644 index 4daf26a1dd..0000000000 --- a/pkg/multicloud/objectstore/xsky/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/objectstore/xsky/provider" diff --git a/pkg/multicloud/objectstore/xsky/provider/provider.go b/pkg/multicloud/objectstore/xsky/provider/provider.go deleted file mode 100644 index 486b09e45a..0000000000 --- a/pkg/multicloud/objectstore/xsky/provider/provider.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" - s3provider "yunion.io/x/onecloud/pkg/multicloud/objectstore/provider" - "yunion.io/x/onecloud/pkg/multicloud/objectstore/xsky" -) - -type SXskyProviderFactory struct { - s3provider.SObjectStoreProviderFactory -} - -func (self *SXskyProviderFactory) GetId() string { - return api.CLOUD_PROVIDER_XSKY -} - -func (self *SXskyProviderFactory) GetName() string { - return api.CLOUD_PROVIDER_XSKY -} - -func (self *SXskyProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - client, err := xsky.NewXskyClient( - objectstore.NewObjectStoreClientConfig( - cfg.URL, cfg.Account, cfg.Secret, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return s3provider.NewObjectStoreProvider(self, client, []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLPublicRead), - string(cloudprovider.ACLPublicReadWrite), - }), nil -} - -func (self *SXskyProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - client, err := xsky.NewXskyClient( - objectstore.NewObjectStoreClientConfig( - info.Url, info.Account, info.Secret, - ), - ) - if err != nil { - return nil, err - } - return client.GetClientRC(), nil -} - -func init() { - factory := SXskyProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} diff --git a/pkg/multicloud/openstack/disk.go b/pkg/multicloud/openstack/disk.go deleted file mode 100644 index f93a87d6e5..0000000000 --- a/pkg/multicloud/openstack/disk.go +++ /dev/null @@ -1,448 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "context" - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/version" -) - -const ( - DISK_STATUS_CREATING = "creating" // The volume is being created. - - DISK_STATUS_ATTACHING = "attaching" // The volume is attaching to an instance. - DISK_STATUS_DETACHING = "detaching" // The volume is detaching from an instance. - DISK_STATUS_EXTENDING = "extending" // The volume is being extended. - DISK_STATUS_DELETING = "deleting" // The volume is being deleted. - - DISK_STATUS_RETYPING = "retyping" // The volume is changing type to another volume type. - DISK_STATUS_AVAILABLE = "available" // The volume is ready to attach to an instance. - DISK_STATUS_RESERVED = "reserved" // The volume is reserved for attaching or shelved. - DISK_STATUS_IN_USE = "in-use" // The volume is attached to an instance. - DISK_STATUS_MAINTENANCE = "maintenance" // The volume is locked and being migrated. - DISK_STATUS_AWAITING_TRANSFER = "awaiting-transfer" // The volume is awaiting for transfer. - DISK_STATUS_BACKING_UP = "backing-up" // The volume is being backed up. - DISK_STATUS_RESTORING_BACKUP = "restoring-backup" // A backup is being restored to the volume. - DISK_STATUS_DOWNLOADING = "downloading" // The volume is downloading an image. - DISK_STATUS_UPLOADING = "uploading" // The volume is being uploaded to an image. - - DISK_STATUS_ERROR = "error" // A volume creation error occurred. - DISK_STATUS_ERROR_DELETING = "error_deleting" // A volume deletion error occurred. - DISK_STATUS_ERROR_BACKING_UP = "error_backing-up" // A backup error occurred. - DISK_STATUS_ERROR_RESTORING = "error_restoring" // A backup restoration error occurred. - DISK_STATUS_ERROR_EXTENDING = "error_extending" // An error occurred while attempting to extend a volume. - -) - -type Attachment struct { - ServerId string - AttachmentId string - HostName string - VolumeId string - Device string - Id string -} - -type Link struct { - Href string - Rel string -} - -type VolumeImageMetadata struct { - Checksum string - MinRAM int - DiskFormat string - ImageName string - ImageId string - ContainerFormat string - MinDisk int - Size int -} - -type SDisk struct { - storage *SStorage - multicloud.SDisk - multicloud.OpenStackTags - - Id string - Name string - - MigrationStatus string - Attachments []Attachment - Links []Link - - AvailabilityZone string - Host string `json:"os-vol-host-attr:host"` - Encrypted bool - ReplicationStatus string - SnapshotId string - Size int - UserId string - TenantId string `json:"os-vol-tenant-attr:tenant_id"` - Migstat string `json:"os-vol-mig-status-attr:migstat"` - - Status string - Description string - Multiattach string - SourceVolid string - ConsistencygroupId string - VolumeImageMetadata VolumeImageMetadata - NameId string `json:"os-vol-mig-status-attr:name_id"` - Bootable bool - CreatedAt time.Time - VolumeType string -} - -func (region *SRegion) GetDisks() ([]SDisk, error) { - disks := []SDisk{} - resource := "/volumes/detail" - query := url.Values{} - query.Set("all_tenants", "true") - for { - resp, err := region.bsList(resource, query) - if err != nil { - return nil, errors.Wrap(err, "bsList") - } - part := struct { - Volumes []SDisk - VolumesLinks SNextLinks - }{} - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - disks = append(disks, part.Volumes...) - marker := part.VolumesLinks.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return disks, nil -} - -func (disk *SDisk) GetId() string { - return disk.Id -} - -func (disk *SDisk) Delete(ctx context.Context) error { - err := disk.storage.zone.region.DeleteDisk(disk.Id) - if err != nil { - return err - } - return cloudprovider.WaitDeleted(disk, 10*time.Second, 8*time.Minute) -} - -func (disk *SDisk) attachInstances(attachments []Attachment) error { - for _, attachment := range attachments { - startTime := time.Now() - for time.Now().Sub(startTime) < 5*time.Minute { - if err := disk.storage.zone.region.AttachDisk(attachment.ServerId, disk.Id); err != nil { - if strings.Contains(err.Error(), "status must be available or downloading") { - time.Sleep(time.Second * 10) - continue - } - log.Errorf("recover attach disk %s => instance %s error: %v", disk.Id, attachment.ServerId, err) - return err - } else { - return nil - } - } - } - return nil -} - -func (disk *SDisk) Resize(ctx context.Context, sizeMb int64) error { - maxVersion := "" - for _, service := range []string{OPENSTACK_SERVICE_VOLUMEV3, OPENSTACK_SERVICE_VOLUMEV2, OPENSTACK_SERVICE_VOLUME} { - maxVersion, _ = disk.storage.zone.region.GetMaxVersion(service) - if len(maxVersion) > 0 { - break - } - } - if version.GE(maxVersion, "3.42") { - return disk.storage.zone.region.ResizeDisk(disk.Id, sizeMb) - } - instanceIds := []string{} - for _, attachement := range disk.Attachments { - if err := disk.storage.zone.region.DetachDisk(attachement.ServerId, disk.Id); err != nil { - return err - } - instanceIds = append(instanceIds, attachement.ServerId) - } - err := disk.storage.zone.region.ResizeDisk(disk.Id, sizeMb) - if err != nil { - disk.attachInstances(disk.Attachments) - return err - } - return disk.attachInstances(disk.Attachments) -} - -func (disk *SDisk) GetName() string { - if len(disk.Name) > 0 { - return disk.Name - } - return disk.Id -} - -func (disk *SDisk) GetGlobalId() string { - return disk.Id -} - -func (disk *SDisk) IsEmulated() bool { - return false -} - -func (disk *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return disk.storage, nil -} - -func (disk *SDisk) GetStatus() string { - switch disk.Status { - case DISK_STATUS_CREATING, DISK_STATUS_DOWNLOADING: - return api.DISK_ALLOCATING - case DISK_STATUS_ATTACHING: - return api.DISK_ATTACHING - case DISK_STATUS_DETACHING: - return api.DISK_DETACHING - case DISK_STATUS_EXTENDING: - return api.DISK_RESIZING - case DISK_STATUS_RETYPING, DISK_STATUS_AVAILABLE, DISK_STATUS_RESERVED, DISK_STATUS_IN_USE, DISK_STATUS_MAINTENANCE, DISK_STATUS_AWAITING_TRANSFER, DISK_STATUS_BACKING_UP, DISK_STATUS_RESTORING_BACKUP, DISK_STATUS_UPLOADING: - return api.DISK_READY - case DISK_STATUS_DELETING: - return api.DISK_DEALLOC - case DISK_STATUS_ERROR: - return api.DISK_ALLOC_FAILED - default: - return api.DISK_UNKNOWN - } -} - -func (disk *SDisk) Refresh() error { - _disk, err := disk.storage.zone.region.GetDisk(disk.Id) - if err != nil { - return err - } - return jsonutils.Update(disk, _disk) -} - -func (disk *SDisk) ResizeDisk(sizeMb int64) error { - return disk.storage.zone.region.ResizeDisk(disk.Id, sizeMb) -} - -func (disk *SDisk) GetDiskFormat() string { - return "lvm" -} - -func (disk *SDisk) GetDiskSizeMB() int { - return disk.Size * 1024 -} - -func (disk *SDisk) GetIsAutoDelete() bool { - return false -} - -func (disk *SDisk) GetTemplateId() string { - return disk.VolumeImageMetadata.ImageId -} - -func (disk *SDisk) GetDiskType() string { - if disk.Bootable { - return api.DISK_TYPE_SYS - } - return api.DISK_TYPE_DATA -} - -func (disk *SDisk) GetFsFormat() string { - return "" -} - -func (disk *SDisk) GetIsNonPersistent() bool { - return false -} - -func (disk *SDisk) GetDriver() string { - return "scsi" -} - -func (disk *SDisk) GetCacheMode() string { - return "none" -} - -func (disk *SDisk) GetMountpoint() string { - return "" -} - -func (region *SRegion) CreateDisk(imageRef string, volumeType string, name string, sizeGb int, desc string, projectId string) (*SDisk, error) { - params := map[string]map[string]interface{}{ - "volume": { - "size": sizeGb, - "volume_type": volumeType, - "name": name, - "description": desc, - }, - } - if len(imageRef) > 0 { - params["volume"]["imageRef"] = imageRef - } - resp, err := region.bsCreate(projectId, "/volumes", params) - if err != nil { - return nil, errors.Wrap(err, "bsCreate") - } - - disk := &SDisk{} - err = resp.Unmarshal(disk, "volume") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - //这里由于不好初始化disk的storage就手动循环了,如果是通过镜像创建,有个下载过程,比较慢,等待时间较长 - startTime := time.Now() - timeout := time.Minute * 10 - //若是通过镜像创建,需要先下载镜像,需要的时间更长 - if len(imageRef) > 0 { - timeout = time.Minute * 30 - } - for time.Now().Sub(startTime) < timeout { - disk, err = region.GetDisk(disk.GetGlobalId()) - if err != nil { - return nil, errors.Wrapf(err, "GetDisk(%s)", disk.GetGlobalId()) - } - log.Debugf("disk status %s expect %s", disk.GetStatus(), api.DISK_READY) - status := disk.GetStatus() - if status == api.DISK_READY { - break - } - if status == api.DISK_ALLOC_FAILED { - messages, _ := region.GetMessages(disk.Id) - if len(messages) > 0 { - return nil, fmt.Errorf("allocate disk %s failed, status is %s message: %s", disk.Name, disk.Status, messages[0].UserMessage) - } - return nil, fmt.Errorf("allocate disk %s failed, status is %s", disk.Name, disk.Status) - } - time.Sleep(time.Second * 10) - } - if disk.GetStatus() != api.DISK_READY { - return nil, fmt.Errorf("timeout for waitting disk ready, current status: %s", disk.Status) - } - return disk, nil -} - -func (region *SRegion) GetDisk(diskId string) (*SDisk, error) { - resource := fmt.Sprintf("/volumes/%s", diskId) - resp, err := region.bsGet(resource) - if err != nil { - return nil, errors.Wrap(err, "bsGet") - } - disk := &SDisk{} - err = resp.Unmarshal(disk, "volume") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return disk, nil -} - -func (region *SRegion) DeleteDisk(diskId string) error { - resource := fmt.Sprintf("/volumes/%s", diskId) - _, err := region.bsDelete(resource) - return err -} - -func (region *SRegion) ResizeDisk(diskId string, sizeMb int64) error { - params := map[string]map[string]interface{}{ - "os-extend": { - "new_size": sizeMb / 1024, - }, - } - resource := fmt.Sprintf("/volumes/%s/action", diskId) - _, err := region.bsPost(resource, params) - return err -} - -func (region *SRegion) ResetDisk(diskId, snapshotId string) error { - params := map[string]map[string]interface{}{ - "revert": { - "snapshot_id": snapshotId, - }, - } - resource := fmt.Sprintf("/volumes/%s/action", diskId) - _, err := region.bsPost(resource, params) - return err -} - -func (disk *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := disk.storage.zone.region.CreateSnapshot(disk.Id, name, desc) - if err != nil { - return nil, err - } - return snapshot, cloudprovider.WaitStatus(snapshot, api.SNAPSHOT_READY, time.Second*5, time.Minute*5) -} - -func (disk *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - return disk.storage.zone.region.GetISnapshotById(snapshotId) -} - -func (disk *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := disk.storage.zone.region.GetSnapshots(disk.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetSnapshots(%s)", disk.Id) - } - isnapshots := []cloudprovider.ICloudSnapshot{} - for i := range snapshots { - snapshots[i].region = disk.storage.zone.region - isnapshots = append(isnapshots, &snapshots[i]) - } - return isnapshots, nil -} - -func (disk *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return disk.Id, disk.storage.zone.region.ResetDisk(disk.Id, snapshotId) -} - -func (disk *SDisk) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (disk *SDisk) GetCreatedAt() time.Time { - return disk.CreatedAt -} - -func (disk *SDisk) GetExpiredAt() time.Time { - return time.Time{} -} - -func (disk *SDisk) GetAccessPath() string { - return "" -} - -func (disk *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (disk *SDisk) GetProjectId() string { - return disk.TenantId -} diff --git a/pkg/multicloud/openstack/doc.go b/pkg/multicloud/openstack/doc.go deleted file mode 100644 index 3764063105..0000000000 --- a/pkg/multicloud/openstack/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack // import "yunion.io/x/onecloud/pkg/multicloud/openstack" diff --git a/pkg/multicloud/openstack/eip.go b/pkg/multicloud/openstack/eip.go deleted file mode 100644 index a5ea69c37d..0000000000 --- a/pkg/multicloud/openstack/eip.go +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - "net/url" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SPortDetail struct { - Status string `json:"status"` - Name string `json:"name"` - AdminStateUp bool `json:"admin_state_up"` - NetworkId string `json:"network_id"` - DeviceOwner string `json:"device_owner"` - MacAddress string `json:"mac_address"` - DeviceId string `json:"device_id"` -} - -type SEipAddress struct { - region *SRegion - multicloud.SEipBase - multicloud.OpenStackTags - - RouterId string `json:"router_id"` - Status string `json:"status"` - Description string `json:"description"` - Tags []string `json:"tags"` - TenantId string `json:"tenant_id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - FloatingNetworkId string `json:"floating_network_id"` - PortDetails SPortDetail `json:"port_details"` - FixedIPAddress string `json:"fixed_ip_address"` - FloatingIPAddress string `json:"floating_ip_address"` - RevisionNumber int `json:"revision_number"` - ProjectId string `json:"project_id"` - PortId string `json:"port_id"` - Id string `json:"id"` - QosPolicyId string `json:"qos_policy_id"` -} - -func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { - resource := fmt.Sprintf("/v2.0/floatingips/%s", eipId) - resp, err := region.vpcGet(resource) - if err != nil { - return nil, err - } - eip := &SEipAddress{region: region} - err = resp.Unmarshal(eip, "floatingip") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return eip, nil -} - -func (region *SRegion) GetEipByIp(ip string) (*SEipAddress, error) { - eips, err := region.GetEips(ip) - if err != nil { - return nil, errors.Wrap(err, "GetEips") - } - if len(eips) == 1 { - eips[0].region = region - return &eips[0], nil - } - if len(eips) == 0 { - return nil, cloudprovider.ErrNotFound - } - return nil, cloudprovider.ErrDuplicateId -} - -func (region *SRegion) GetEips(ip string) ([]SEipAddress, error) { - resource := "/v2.0/floatingips" - eips := []SEipAddress{} - query := url.Values{} - if len(ip) > 0 { - query.Set("floating_ip_address", ip) - } - for { - part := struct { - Floatingips []SEipAddress - FloatingipsLinks SNextLinks - }{} - resp, err := region.vpcList(resource, query) - if err != nil { - return nil, errors.Wrap(err, "vpcList") - } - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - eips = append(eips, part.Floatingips...) - marker := part.FloatingipsLinks.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return eips, nil -} - -func (eip *SEipAddress) GetId() string { - return eip.Id -} - -func (eip *SEipAddress) GetName() string { - return eip.FloatingIPAddress -} - -func (eip *SEipAddress) GetGlobalId() string { - return eip.Id -} - -func (eip *SEipAddress) GetStatus() string { - switch eip.Status { - case "ACTIVE": - return api.EIP_STATUS_READY - case "DOWN": //实际是未绑定在机器上 - return api.EIP_STATUS_READY - case "ERROR": - return api.EIP_STATUS_UNKNOWN - default: - log.Errorf("Unknown eip %s status %s", eip.Id, eip.Status) - return api.EIP_STATUS_UNKNOWN - } -} - -func (eip *SEipAddress) Refresh() error { - _eip, err := eip.region.GetEip(eip.Id) - if err != nil { - return err - } - return jsonutils.Update(eip, _eip) -} - -func (eip *SEipAddress) IsEmulated() bool { - return false -} - -func (eip *SEipAddress) GetIpAddr() string { - return eip.FloatingIPAddress -} - -func (eip *SEipAddress) GetMode() string { - return api.EIP_MODE_STANDALONE_EIP -} - -func (eip *SEipAddress) GetAssociationType() string { - if len(eip.GetAssociationExternalId()) > 0 { - return api.EIP_ASSOCIATE_TYPE_SERVER - } - return "" -} - -func (eip *SEipAddress) GetAssociationExternalId() string { - if len(eip.PortDetails.DeviceId) > 0 { - return eip.PortDetails.DeviceId - } - if len(eip.PortId) > 0 { - port, err := eip.region.GetPort(eip.PortId) - if err != nil { - log.Errorf("failed to get eip port %s info", eip.PortId) - return "" - } - return port.DeviceID - } - return "" -} - -func (eip *SEipAddress) GetBillingType() string { - return "" -} - -func (eip *SEipAddress) GetCreatedAt() time.Time { - return eip.CreatedAt -} - -func (eip *SEipAddress) GetExpiredAt() time.Time { - return time.Time{} -} - -func (eip *SEipAddress) Delete() error { - return eip.region.DeleteEip(eip.Id) -} - -func (eip *SEipAddress) GetBandwidth() int { - return 0 -} - -func (eip *SEipAddress) GetINetworkId() string { - networks, err := eip.region.GetNetworks(eip.FloatingNetworkId) - if err != nil { - log.Errorf("failed to find vpc id for eip %s(%s), error: %v", eip.FloatingIPAddress, eip.FloatingNetworkId, err) - return "" - } - for _, network := range networks { - for _, pool := range network.AllocationPools { - if pool.Contains(eip.FloatingIPAddress) { - network.AllocationPools = []AllocationPool{pool} - return network.GetGlobalId() - } - } - } - log.Errorf("failed to find eip %s(%s) networkId", eip.FloatingIPAddress, eip.FloatingNetworkId) - return "" -} - -func (eip *SEipAddress) GetInternetChargeType() string { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC -} - -func (eip *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { - return eip.region.AssociateEip(conf.InstanceId, eip.Id) -} - -func (eip *SEipAddress) Dissociate() error { - return eip.region.DisassociateEip(eip.Id) -} - -func (eip *SEipAddress) ChangeBandwidth(bw int) error { - return cloudprovider.ErrNotSupported -} - -func (eip *SEipAddress) GetProjectId() string { - return eip.ProjectId -} - -func (region *SRegion) CreateEip(vpcId, networkId, ip string, projectId string) (*SEipAddress, error) { - _, networkId = getNetworkId(networkId) - params := map[string]map[string]string{ - "floatingip": map[string]string{ - "floating_network_id": vpcId, - "subnet_id": networkId, - }, - } - if len(projectId) > 0 { - params["floatingip"]["tenant_id"] = projectId - } - if len(ip) > 0 { - params["floatingip"]["floating_ip_address"] = ip - } - resource := "/v2.0/floatingips" - resp, err := region.vpcPost(resource, params) - if err != nil { - return nil, errors.Wrap(err, "vpcPost") - } - eip := &SEipAddress{region: region} - err = resp.Unmarshal(eip, "floatingip") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return eip, nil -} - -func (region *SRegion) AssociateEip(instanceId, eipId string) error { - instance, err := region.GetInstance(instanceId) - if err != nil { - return err - } - for networkName, address := range instance.Addresses { - for i := 0; i < len(address); i++ { - if instance.Addresses[networkName][i].Type == "fixed" { - ports, err := region.GetPorts(instance.Addresses[networkName][i].MacAddr, "") - if err != nil { - return err - } - - if len(ports) == 1 { - params := map[string]map[string]string{ - "floatingip": { - "port_id": ports[0].ID, - }, - } - resource := "/v2.0/floatingips/" + eipId - _, err = region.vpcUpdate(resource, params) - return err - } - - if len(ports) == 0 { - log.Errorf("failed to found port for instance nic %s(%s)", instance.Addresses[networkName][i].Addr, instance.Addresses[networkName][i].MacAddr) - return cloudprovider.ErrNotFound - } - return cloudprovider.ErrDuplicateId - } - } - } - return fmt.Errorf("failed to found instnace %s nics for binding eip", instanceId) -} - -func (region *SRegion) AssociateEipWithPortId(portid, eipId string) error { - params := map[string]map[string]string{ - "floatingip": { - "port_id": portid, - }, - } - _, err := region.vpcUpdate("/v2.0/floatingips/"+eipId, jsonutils.Marshal(params)) - return err -} - -func (region *SRegion) DisassociateEip(eipId string) error { - params, _ := jsonutils.Parse([]byte(`{ - "floatingip": { - "port_id": null, - }, - }`)) - _, err := region.vpcUpdate("/v2.0/floatingips/"+eipId, params) - return err -} - -func (region *SRegion) DeleteEip(eipId string) error { - resource := "/v2.0/floatingips/" + eipId - _, err := region.vpcDelete(resource) - return err -} diff --git a/pkg/multicloud/openstack/flavor.go b/pkg/multicloud/openstack/flavor.go deleted file mode 100644 index abc19322a4..0000000000 --- a/pkg/multicloud/openstack/flavor.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - "net/url" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SFlavor struct { - multicloud.SServerSku - multicloud.OpenStackTags - region *SRegion - - Id string - Disk int - Ephemeral int - ExtraSpecs ExtraSpecs - OriginalName string - Name string - RAM int - Swap string - Vcpus int -} - -func (region *SRegion) GetFlavors() ([]SFlavor, error) { - resource := "/flavors/detail" - flavors := []SFlavor{} - query := url.Values{} - for { - resp, err := region.ecsList(resource, query) - if err != nil { - return nil, errors.Wrap(err, "ecsList") - } - part := struct { - Flavors []SFlavor - FlavorsLinks SNextLinks - }{} - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - flavors = append(flavors, part.Flavors...) - - marker := part.FlavorsLinks.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return flavors, nil -} - -func (region *SRegion) GetFlavor(flavorId string) (*SFlavor, error) { - resource := fmt.Sprintf("/flavors/%s", flavorId) - resp, err := region.ecsGet(resource) - if err != nil { - return nil, errors.Wrap(err, "ecsGet") - } - flavor := &SFlavor{region: region} - err = resp.Unmarshal(flavor, "flavor") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return flavor, nil -} - -func (region *SRegion) SyncFlavor(name string, cpu, memoryMb, diskGB int) (string, error) { - flavor, err := region.syncFlavor(name, cpu, memoryMb, diskGB) - if err != nil { - return "", errors.Wrapf(err, "syncFlavor") - } - return flavor.Id, nil -} - -func (region *SRegion) syncFlavor(name string, cpu, memoryMb, diskGB int) (*SFlavor, error) { - flavors, err := region.GetFlavors() - if err != nil { - return nil, errors.Wrapf(err, "GetFlavors") - } - - if cpu == 0 && memoryMb == 0 { - return nil, fmt.Errorf("failed to find instance type %s", name) - } - - for i := range flavors { - flavor := flavors[i] - flavorName := flavor.GetName() - if (len(name) == 0 || flavorName == name || flavorName == fmt.Sprintf("%s-%d", name, diskGB)) && - flavor.GetCpuCoreCount() == cpu && - flavor.GetMemorySizeMB() == memoryMb && - diskGB <= flavor.GetSysDiskMaxSizeGB() { - return &flavor, nil - } - } - if len(name) == 0 { - name = fmt.Sprintf("ecs.g1.c%dm%d", cpu, memoryMb/1024) - } - name = fmt.Sprintf("%s-%d", name, diskGB) - flavor, err := region.CreateFlavor(name, cpu, memoryMb, diskGB) - if err != nil { - return nil, errors.Wrap(err, "CreateFlavor") - } - return flavor, nil -} - -func (region *SRegion) CreateISku(opts *cloudprovider.SServerSkuCreateOption) (cloudprovider.ICloudSku, error) { - flavor, err := region.CreateFlavor(opts.Name, opts.CpuCount, opts.VmemSizeMb, opts.SysDiskMaxSizeGb) - if err != nil { - return nil, errors.Wrapf(err, "CreateFlavor") - } - return flavor, nil -} - -func (region *SRegion) CreateFlavor(name string, cpu int, memoryMb int, diskGB int) (*SFlavor, error) { - if diskGB <= 0 { - diskGB = 30 - } - params := map[string]map[string]interface{}{ - "flavor": { - "name": name, - "ram": memoryMb, - "vcpus": cpu, - "disk": diskGB, - }, - } - resp, err := region.ecsPost("/flavors", params) - if err != nil { - return nil, errors.Wrap(err, "ecsPost") - } - flavor := &SFlavor{region: region} - err = resp.Unmarshal(flavor, "flavor") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return flavor, nil -} - -func (region *SRegion) DeleteFlavor(flavorId string) error { - _, err := region.ecsDelete("/flavors/" + flavorId) - return err -} - -func (flavor *SFlavor) Delete() error { - return flavor.region.DeleteFlavor(flavor.Id) -} - -func (flavor *SFlavor) IsEmulated() bool { - return false -} - -func (flavor *SFlavor) Refresh() error { - _flavor, err := flavor.region.GetFlavor(flavor.Id) - if err != nil { - return err - } - return jsonutils.Update(flavor, _flavor) -} - -func (flavor *SFlavor) GetName() string { - if len(flavor.OriginalName) > 0 { - return flavor.OriginalName - } - return flavor.Name -} - -func (flavor *SFlavor) GetId() string { - return flavor.Id -} - -func (flavor *SFlavor) GetGlobalId() string { - return flavor.Id -} - -func (flavor *SFlavor) GetInstanceTypeFamily() string { - return api.InstanceFamilies[api.SkuCategoryGeneralPurpose] -} - -func (flavor *SFlavor) GetInstanceTypeCategory() string { - return api.SkuCategoryGeneralPurpose -} - -func (flavor *SFlavor) GetPrepaidStatus() string { - return api.SkuStatusSoldout -} - -func (flavor *SFlavor) GetPostpaidStatus() string { - return api.SkuStatusAvailable -} - -func (flavor *SFlavor) GetCpuArch() string { - return "" -} - -func (flavor *SFlavor) GetCpuCoreCount() int { - return int(flavor.Vcpus) -} - -func (flavor *SFlavor) GetMemorySizeMB() int { - return flavor.RAM -} - -func (flavor *SFlavor) GetOsName() string { - return "Any" -} - -func (flavor *SFlavor) GetSysDiskResizable() bool { - return true -} - -func (flavor *SFlavor) GetSysDiskType() string { - return "" -} - -func (flavor *SFlavor) GetSysDiskMinSizeGB() int { - return 0 -} - -func (flavor *SFlavor) GetSysDiskMaxSizeGB() int { - return flavor.Disk -} - -func (flavor *SFlavor) GetAttachedDiskType() string { - return "iscsi" -} - -func (flavor *SFlavor) GetAttachedDiskSizeGB() int { - return 0 -} - -func (flavor *SFlavor) GetAttachedDiskCount() int { - return 0 -} - -func (flavor *SFlavor) GetDataDiskTypes() string { - return "" -} - -func (flavor *SFlavor) GetDataDiskMaxCount() int { - return 6 -} - -func (flavor *SFlavor) GetNicType() string { - return "vpc" -} - -func (flavor *SFlavor) GetNicMaxCount() int { - return 1 -} - -func (flavor *SFlavor) GetGpuAttachable() bool { - return false -} - -func (flavor *SFlavor) GetGpuSpec() string { - return "" -} - -func (flavor *SFlavor) GetGpuCount() int { - return 0 -} - -func (flavor *SFlavor) GetGpuMaxCount() int { - return 0 -} diff --git a/pkg/multicloud/openstack/image.go b/pkg/multicloud/openstack/image.go deleted file mode 100644 index 64d806908f..0000000000 --- a/pkg/multicloud/openstack/image.go +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "context" - "fmt" - "io" - "net/url" - "strings" - "time" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" - "yunion.io/x/onecloud/pkg/util/qemuimg" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -const ( - QUEUED = "queued" // The Image service reserved an image ID for the image in the catalog but did not yet upload any image data. - SAVING = "saving" // The Image service is in the process of saving the raw data for the image into the backing store. - ACTIVE = "active" // The image is active and ready for consumption in the Image service. - KILLED = "killed" // An image data upload error occurred. - DELETED = "deleted" // The Image service retains information about the image but the image is no longer available for use. - PENDING_DELETE = "pending_delete" // Similar to the deleted status. An image in this state is not recoverable. - DEACTIVATED = "deactivated" // The image data is not available for use. - UPLOADING = "uploading" // Data has been staged as part of the interoperable image import process. It is not yet available for use. (Since Image API 2.6) - IMPORTING = "importing" // The image data is being processed as part of the interoperable image import process, but is not yet available for use. (Since Image API 2.6) -) - -type SImage struct { - multicloud.SImageBase - storageCache *SStoragecache - multicloud.OpenStackTags - - // normalized image info - imgInfo *imagetools.ImageInfo - - Status string - Name string - Tags []string - ContainerFormat string - CreatedAt time.Time - DiskFormat string - UpdatedAt time.Time - Visibility string - Self string - MinDisk int - Protected bool - Id string - File string - Checksum string - OsHashAlgo string - OsHashValue string - OsHidden bool - OsDistro string - OsType string - Owner string - Size int - MinRAM int - Schema string - VirtualSize int - visibility string -} - -func (image *SImage) GetMinRamSizeMb() int { - return image.MinRAM -} - -func (region *SRegion) GetImages(name string, status string, imageId string) ([]SImage, error) { - query := url.Values{} - if len(status) > 0 { - query.Set("status", status) - } - if len(name) > 0 { - query.Set("name", name) - } - if len(imageId) > 0 { - query.Set("id", imageId) - } - images := []SImage{} - resource := "/v2/images" - marker := "" - for { - if len(marker) > 0 { - query.Set("marker", marker) - } - resp, err := region.imageList(resource, query) - if err != nil { - return nil, errors.Wrap(err, "imageList") - } - part := struct { - Images []SImage - Next string - }{} - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - images = append(images, part.Images...) - if len(part.Next) == 0 { - break - } - if len(part.Next) > 0 { - href, err := url.Parse(part.Next) - if err != nil { - marker = "" - } else { - marker = href.Query().Get("marker") - } - } - if len(marker) == 0 { - break - } - } - return images, nil -} - -func (image *SImage) GetId() string { - return image.Id -} - -func (image *SImage) GetName() string { - return image.Name -} - -func (image *SImage) IsEmulated() bool { - return false -} - -func (image *SImage) GetGlobalId() string { - return image.Id -} - -func (image *SImage) Delete(ctx context.Context) error { - return image.storageCache.region.DeleteImage(image.Id) -} - -func (image *SImage) GetStatus() string { - switch image.Status { - case QUEUED, SAVING, UPLOADING, IMPORTING: - return api.CACHED_IMAGE_STATUS_CACHING - case ACTIVE: - return api.CACHED_IMAGE_STATUS_ACTIVE - case DELETED, DEACTIVATED, PENDING_DELETE, KILLED: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - default: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (image *SImage) GetImageStatus() string { - switch image.Status { - case QUEUED, SAVING, UPLOADING, IMPORTING: - return cloudprovider.IMAGE_STATUS_SAVING - case ACTIVE: - return cloudprovider.IMAGE_STATUS_ACTIVE - case DELETED, DEACTIVATED, PENDING_DELETE: - return cloudprovider.IMAGE_STATUS_DELETED - case KILLED: - return cloudprovider.IMAGE_STATUS_KILLED - default: - return cloudprovider.IMAGE_STATUS_DELETED - } -} - -func (image *SImage) Refresh() error { - _image, err := image.storageCache.region.GetImage(image.Id) - if err != nil { - return errors.Wrap(err, "GetImage") - } - return jsonutils.Update(image, _image) -} - -func (image *SImage) GetImageType() cloudprovider.TImageType { - return cloudprovider.ImageTypeSystem -} - -func (image *SImage) GetPublicScope() rbacutils.TRbacScope { - switch image.Visibility { - case "private": - return rbacutils.ScopeNone - default: - return rbacutils.ScopeSystem - } -} - -func (image *SImage) GetProjectId() string { - return image.Owner -} - -func (image *SImage) GetSizeByte() int64 { - return int64(image.Size) -} - -func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if self.imgInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(self.Name, "", self.OsType, "", "") - self.imgInfo = &imgInfo - } - - return self.imgInfo -} - -func (image *SImage) GetFullOsName() string { - return image.Name -} - -func (image *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(image.getNormalizedImageInfo().OsType) -} - -func (image *SImage) GetOsDist() string { - return image.getNormalizedImageInfo().OsDistro -} - -func (image *SImage) GetOsVersion() string { - return image.getNormalizedImageInfo().OsVersion -} - -func (image *SImage) GetOsArch() string { - return image.getNormalizedImageInfo().OsArch -} - -func (image *SImage) GetOsLang() string { - return image.getNormalizedImageInfo().OsLang -} - -func (image *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(image.getNormalizedImageInfo().OsBios) -} - -func (image *SImage) GetMinOsDiskSizeGb() int { - if image.MinDisk > 0 { - return image.MinDisk - } - return 30 -} - -func (image *SImage) GetImageFormat() string { - return image.DiskFormat -} - -func (image *SImage) GetCreatedAt() time.Time { - return image.CreatedAt -} - -func (region *SRegion) GetImage(imageId string) (*SImage, error) { - resource := "/v2/images/" + imageId - resp, err := region.imageGet(resource) - if err != nil { - return nil, errors.Wrapf(err, "imageGet(%s)", resource) - } - image := &SImage{} - err = resp.Unmarshal(image) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return image, nil -} - -func (image *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return image.storageCache -} - -func (region *SRegion) DeleteImage(imageId string) error { - _, err := region.imageDelete("/v2/images/" + imageId) - return err -} - -func (region *SRegion) GetImageStatus(imageId string) (string, error) { - image, err := region.GetImage(imageId) - if err != nil { - return "", err - } - return image.Status, nil -} - -func (region *SRegion) GetImageByName(name string) (*SImage, error) { - images, err := region.GetImages(name, "", "") - if err != nil { - return nil, err - } - if len(images) == 0 { - return nil, cloudprovider.ErrNotFound - } - return &images[0], nil -} - -func (region *SRegion) CreateImage(imageName string, osType string, osDist string, minDiskGb int, minRam int, size int64, body io.Reader, callback func(progress float32)) (*SImage, error) { - params := map[string]interface{}{ - "container_format": "bare", - "disk_format": string(qemuimg.QCOW2), - "name": imageName, - "min_disk": minDiskGb, - "min_ram": minRam, - "os_type": strings.ToLower(osType), - "os_distro": osDist, - "hw_qemu_guest_agent": "yes", - } - - resp, err := region.imagePost("/v2/images", params) - if err != nil { - return nil, errors.Wrap(err, "imagePost") - } - image := &SImage{} - err = resp.Unmarshal(image) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - url := fmt.Sprintf("/v2/images/%s/file", image.Id) - err = region.imageUpload(url, size, body, callback) - if err != nil { - return nil, errors.Wrap(err, "imageUpload") - } - return image, nil -} diff --git a/pkg/multicloud/openstack/instance.go b/pkg/multicloud/openstack/instance.go deleted file mode 100644 index 6531bab35c..0000000000 --- a/pkg/multicloud/openstack/instance.go +++ /dev/null @@ -1,1167 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "context" - "fmt" - "net/url" - "time" - - "gopkg.in/fatih/set.v0" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -const ( - INSTANCE_STATUS_ACTIVE = "ACTIVE" //The server is active. - INSTANCE_STATUS_BUILD = "BUILD" //The server has not finished the original build process. - INSTANCE_STATUS_DELETED = "DELETED" //The server is permanently deleted. - INSTANCE_STATUS_ERROR = "ERROR" //The server is in error. - INSTANCE_STATUS_HARD_REBOOT = "HARD_REBOOT" //The server is hard rebooting. This is equivalent to pulling the power plug on a physical server, plugging it back in, and rebooting it. - INSTANCE_STATUS_MIGRATING = "MIGRATING" //The server is being migrated to a new host. - INSTANCE_STATUS_PASSWORD = "PASSWORD" //The password is being reset on the server. - INSTANCE_STATUS_PAUSED = "PAUSED" //In a paused state, the state of the server is stored in RAM.A paused server continues to run in frozen state. - INSTANCE_STATUS_REBOOT = "REBOOT" //The server is in a soft reboot state. A reboot command was passed to the operating system. - INSTANCE_STATUS_REBUILD = "REBUILD" //The server is currently being rebuilt from an image. - INSTANCE_STATUS_RESCUE = "RESCUE" //The server is in rescue mode. A rescue image is running with the original server image attached. - INSTANCE_STATUS_RESIZE = "RESIZE" //Server is performing the differential copy of data that changed during its initial copy. Server is down for this stage. - INSTANCE_STATUS_REVERT_RESIZE = "REVERT_RESIZE" //The resize or migration of a server failed for some reason. The destination server is being cleaned up and the original source server is restarting. - INSTANCE_STATUS_SHELVED = "SHELVED" // The server is in shelved state. Depending on the shelve offload time, the server will be automatically shelved offloaded. - INSTANCE_STATUS_SHELVED_OFFLOADED = "SHELVED_OFFLOADED" // The shelved server is offloaded (removed from the compute host) and it needs unshelved action to be used again. - INSTANCE_STATUS_SHUTOFF = "SHUTOFF" //The server is powered off and the disk image still persists. - INSTANCE_STATUS_SOFT_DELETED = "SOFT_DELETED" //The server is marked as deleted but the disk images are still available to restore. - INSTANCE_STATUS_SUSPENDED = "SUSPENDED" //The server is suspended, either by request or necessity. This status appears for only the XenServer/XCP, KVM, and ESXi hypervisors. Administrative users can suspend an instance if it is infrequently used or to perform system maintenance. When you suspend an instance, its VM state is stored on disk, all memory is written to disk, and the virtual machine is stopped. Suspending an instance is similar to placing a device in hibernation; memory and vCPUs become available to create other instances. - INSTANCE_STATUS_UNKNOWN = "UNKNOWN" //The state of the server is unknown. Contact your cloud provider. - INSTANCE_STATUS_VERIFY_RESIZE = "VERIFY_RESIZE" //System is awaiting confirmation that the server is operational after a move or resize. -) - -type SPrivate struct { - MacAddr string `json:"OS-EXT-IPS-MAC:mac_addr,omitempty"` - Addr string `json:"OS-EXT-IPS:type,omitempty"` - Version int -} - -type SecurityGroup struct { - Id string - Name string - Description string -} - -type ExtraSpecs struct { - CpuPolicy string `json:"hw:cpu_policy,omitempty"` - MemPageSize string `json:"hw:mem_page_size,omitempty"` -} - -type Resource struct { - Id string - Links []Link -} - -type VolumesAttached struct { - Id string - DeleteOnTermination bool -} - -type SFault struct { - Message string - Code int - Details string -} - -type SInstance struct { - multicloud.SInstanceBase - multicloud.OpenStackTags - host *SHypervisor - - imageObj *SImage - - DiskConfig string `json:"OS-DCF:diskConfig,omitempty"` - AvailabilityZone string `json:"OS-EXT-AZ:availability_zone,omitempty"` - Host string `json:"OS-EXT-SRV-ATTR:host,omitempty"` - Hostname string `json:"OS-EXT-SRV-ATTR:hostname,omitempty"` - HypervisorHostname string `json:"OS-EXT-SRV-ATTR:hypervisor_hostname,omitempty"` - InstanceName string `json:"OS-EXT-SRV-ATTR:instance_name,omitempty"` - KernelId string `json:"OS-EXT-SRV-ATTR:kernel_id,omitempty"` - LaunchIndex int `json:"OS-EXT-SRV-ATTR:launch_index,omitempty"` - RamdiskId string `json:"OS-EXT-SRV-ATTR:ramdisk_id,omitempty"` - ReservationId string `json:"OS-EXT-SRV-ATTR:reservation_id,omitempty"` - RootDeviceName string `json:"OS-EXT-SRV-ATTR:root_device_name,omitempty"` - UserData string `json:"OS-EXT-SRV-ATTR:user_data,omitempty"` - PowerState int `json:"OS-EXT-STS:power_state,omitempty"` - TaskState string `json:"OS-EXT-STS:task_state,omitempty"` - VmState string `json:"OS-EXT-STS:vm_state,omitempty"` - LaunchedAt time.Time `json:"OS-SRV-USG:launched_at,omitempty"` - TerminatedAt string `json:"OS-SRV-USG:terminated_at,omitempty"` - - AccessIPv4 string - AccessIPv6 string - Addresses map[string][]SInstanceNic - ConfigDrive string - Created time.Time - Description string - Flavor SFlavor - HostId string - HostStatus string - Id string - Image jsonutils.JSONObject `json:"image"` //有可能是字符串 - KeyName string - Links []Link - Locked bool - Name string - VolumesAttached []VolumesAttached `json:"os-extended-volumes:volumes_attached,omitempty"` - Progress int - SecurityGroups []SecurityGroup - Status string - Tags []string - TenantId string - TrustedImageCertificates []string - Updated time.Time - UserId string - Fault SFault -} - -func (region *SRegion) GetSecurityGroupsByInstance(instanceId string) ([]SecurityGroup, error) { - resource := fmt.Sprintf("/servers/%s/os-security-groups", instanceId) - resp, err := region.ecsGet(resource) - if err != nil { - return nil, errors.Wrap(err, "ecsGet") - } - secgroups := []SecurityGroup{} - err = resp.Unmarshal(&secgroups, "security_groups") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return secgroups, nil -} - -func (region *SRegion) GetInstances(host string) ([]SInstance, error) { - instances := []SInstance{} - resource := "/servers/detail" - query := url.Values{} - query.Set("all_tenants", "True") - for { - resp, err := region.ecsList(resource, query) - if err != nil { - return nil, errors.Wrap(err, "ecsList") - } - part := struct { - Servers []SInstance - ServersLinks SNextLinks - }{} - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - for i := range part.Servers { - if len(host) == 0 || part.Servers[i].Host == host || part.Servers[i].HypervisorHostname == host { - instances = append(instances, part.Servers[i]) - } - } - marker := part.ServersLinks.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return instances, nil -} - -func (region *SRegion) GetInstance(instanceId string) (*SInstance, error) { - resource := "/servers/" + instanceId - resp, err := region.ecsGet(resource) - if err != nil { - return nil, errors.Wrap(err, "ecsGet") - } - instance := &SInstance{} - err = resp.Unmarshal(instance, "server") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarsha") - } - return instance, nil -} - -func (instance *SInstance) GetSecurityGroupIds() ([]string, error) { - secgroupIds := []string{} - secgroups, err := instance.host.zone.region.GetSecurityGroupsByInstance(instance.Id) - if err != nil { - return nil, err - } - for _, secgroup := range secgroups { - secgroupIds = append(secgroupIds, secgroup.Id) - } - return secgroupIds, nil -} - -func (instance *SInstance) GetIHost() cloudprovider.ICloudHost { - return instance.host -} - -func (instance *SInstance) GetId() string { - return instance.Id -} - -func (instance *SInstance) GetName() string { - return instance.Name -} - -func (instance *SInstance) GetHostname() string { - return instance.Hostname -} - -func (instance *SInstance) GetGlobalId() string { - return instance.Id -} - -func (instance *SInstance) IsEmulated() bool { - return false -} - -func (instance *SInstance) fetchFlavor() error { - if len(instance.Flavor.Id) > 0 && instance.Flavor.Vcpus == 0 { - flavor, err := instance.host.zone.region.GetFlavor(instance.Flavor.Id) - if err != nil { - return err - } - instance.Flavor = *flavor - } - return nil -} - -func (instance *SInstance) GetInstanceType() string { - err := instance.fetchFlavor() - if err != nil { - return "" - } - return instance.Flavor.GetName() -} - -func (instance *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks := []SDisk{} - hasSysDisk := false - for i := 0; i < len(instance.VolumesAttached); i++ { - disk, err := instance.host.zone.region.GetDisk(instance.VolumesAttached[i].Id) - if err != nil { - return nil, errors.Wrapf(err, "GetDisk(%s)", instance.VolumesAttached[i].Id) - } - disks = append(disks, *disk) - if disk.GetDiskType() == api.DISK_TYPE_SYS { - hasSysDisk = true - } - } - idisks := []cloudprovider.ICloudDisk{} - for i := 0; i < len(disks); i++ { - store, err := instance.host.zone.getStorageByCategory(disks[i].VolumeType, disks[i].Host) - if err != nil { - return nil, errors.Wrapf(err, "getStorageByCategory(%s.%s)", disks[i].Id, disks[i].VolumeType) - } - disks[i].storage = store - idisks = append(idisks, &disks[i]) - } - - if !hasSysDisk { - store := &SNovaStorage{zone: instance.host.zone, host: instance.host} - disk := &SNovaDisk{storage: store, instanceId: instance.Id, region: instance.host.zone.region} - idisks = append([]cloudprovider.ICloudDisk{disk}, idisks...) - } - - return idisks, nil -} - -func (instance *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nics, err := instance.host.zone.region.GetInstancePorts(instance.Id) - if err != nil { - return nil, errors.Wrap(err, "GetInstancePorts") - } - inics := []cloudprovider.ICloudNic{} - for i := range nics { - nics[i].region = instance.host.zone.region - inics = append(inics, &nics[i]) - } - return inics, nil -} - -func (instance *SInstance) GetVcpuCount() int { - err := instance.fetchFlavor() - if err != nil { - return 0 - } - return instance.Flavor.Vcpus -} - -func (instance *SInstance) GetVmemSizeMB() int { - err := instance.fetchFlavor() - if err != nil { - return 0 - } - return instance.Flavor.RAM -} - -func (instance *SInstance) GetBootOrder() string { - return "dcn" -} - -func (instance *SInstance) GetVga() string { - return "std" -} - -func (instance *SInstance) GetVdi() string { - return "vnc" -} - -func (instance *SInstance) getImage() *SImage { - if instance.imageObj == nil && instance.Image != nil { - imageId, _ := instance.Image.GetString("id") - if len(imageId) == 0 { - imageId, _ = instance.Image.GetString() - } - if len(imageId) > 0 { - image, _ := instance.host.zone.region.GetImage(imageId) - if image != nil { - instance.imageObj = image - } - } - } - return instance.imageObj -} - -func (instance *SInstance) GetOsType() cloudprovider.TOsType { - img := instance.getImage() - if img != nil { - return img.GetOsType() - } - return cloudprovider.OsTypeLinux -} - -func (instance *SInstance) GetFullOsName() string { - img := instance.getImage() - if img != nil { - return img.GetFullOsName() - } - return "" -} - -func (instance *SInstance) GetBios() cloudprovider.TBiosType { - img := instance.getImage() - if img != nil { - return img.GetBios() - } - return "BIOS" -} - -func (instance *SInstance) GetOsDist() string { - img := instance.getImage() - if img != nil { - return img.GetOsDist() - } - return "" -} - -func (instance *SInstance) GetOsVersion() string { - img := instance.getImage() - if img != nil { - return img.GetOsVersion() - } - return "" -} - -func (instance *SInstance) GetOsLang() string { - img := instance.getImage() - if img != nil { - return img.GetOsLang() - } - return "" -} - -func (instance *SInstance) GetOsArch() string { - img := instance.getImage() - if img != nil { - return img.GetOsArch() - } - return "" -} - -func (instance *SInstance) GetMachine() string { - return "pc" -} - -func (instance *SInstance) GetStatus() string { - switch instance.Status { - case INSTANCE_STATUS_ACTIVE, INSTANCE_STATUS_RESCUE: - return api.VM_RUNNING - case INSTANCE_STATUS_BUILD, INSTANCE_STATUS_PASSWORD: - return api.VM_DEPLOYING - case INSTANCE_STATUS_DELETED: - return api.VM_DELETING - case INSTANCE_STATUS_HARD_REBOOT, INSTANCE_STATUS_REBOOT: - return api.VM_STARTING - case INSTANCE_STATUS_MIGRATING: - return api.VM_MIGRATING - case INSTANCE_STATUS_PAUSED, INSTANCE_STATUS_SUSPENDED: - return api.VM_SUSPEND - case INSTANCE_STATUS_RESIZE: - return api.VM_CHANGE_FLAVOR - case INSTANCE_STATUS_VERIFY_RESIZE: - // API请求更改配置后,状态先回变更到 INSTANCE_STATUS_RESIZE 等待一会变成此状态 - // 到达此状态后需要再次发送确认请求,变更才会生效 - // 此状态不能和INSTANCE_STATUS_RESIZE返回一样,避免在INSTANCE_STATUS_RESIZE状态下发送确认请求,导致更改配置失败 - return api.VM_SYNC_CONFIG - case INSTANCE_STATUS_SHELVED, INSTANCE_STATUS_SHELVED_OFFLOADED, INSTANCE_STATUS_SHUTOFF, INSTANCE_STATUS_SOFT_DELETED: - return api.VM_READY - default: - return api.VM_UNKNOWN - } -} - -func (instance *SInstance) Refresh() error { - _instance, err := instance.host.zone.region.GetInstance(instance.Id) - if err != nil { - return err - } - return jsonutils.Update(instance, _instance) -} - -func (instance *SInstance) UpdateVM(ctx context.Context, name string) error { - if instance.Name != name { - params := map[string]map[string]string{ - "server": { - "name": name, - }, - } - resource := "/servers/" + instance.Id - _, err := instance.host.zone.region.ecsUpdate(resource, params) - return err - } - return nil -} - -func (instance *SInstance) GetHypervisor() string { - return api.HYPERVISOR_OPENSTACK -} - -func (instance *SInstance) StartVM(ctx context.Context) error { - err := instance.host.zone.region.StartVM(instance.Id) - if err != nil { - return errors.Wrapf(err, "StartVM(%s)", instance.Id) - } - return cloudprovider.WaitStatus(instance, api.VM_RUNNING, 10*time.Second, 8*time.Minute) -} - -func (instance *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - err := instance.host.zone.region.StopVM(instance.Id, opts.IsForce) - if err != nil { - return errors.Wrapf(err, "StopVM(%s)", instance.Id) - } - return cloudprovider.WaitStatus(instance, api.VM_READY, 10*time.Second, 8*time.Minute) -} - -func (region *SRegion) GetInstanceVNCUrl(instanceId string, origin bool) (*cloudprovider.ServerVncOutput, error) { - params := map[string]map[string]string{ - "remote_console": { - "protocol": "vnc", - "type": "novnc", - }, - } - resource := fmt.Sprintf("/servers/%s/remote-consoles", instanceId) - resp, err := region.ecsPost(resource, params) - if err != nil { - return nil, errors.Wrap(err, "ecsPost") - } - ret := &cloudprovider.ServerVncOutput{ - Protocol: "openstack", - InstanceId: instanceId, - Hypervisor: api.HYPERVISOR_OPENSTACK, - } - - ret.Url, err = resp.GetString("remote_console", "url") - if err != nil { - return nil, errors.Wrapf(err, "remote_console") - } - - if origin { - return ret, nil - } - - token := string([]byte(ret.Url)[len(ret.Url)-36:]) - vncUrl, _ := url.Parse(ret.Url) - ret.Url = fmt.Sprintf("ws://%s?token=%s", vncUrl.Host, token) - ret.Protocol = "vnc" - return ret, nil -} - -func (region *SRegion) GetInstanceVNC(instanceId string, origin bool) (*cloudprovider.ServerVncOutput, error) { - params := map[string]map[string]string{ - "os-getVNCConsole": { - "type": "novnc", - }, - } - resource := fmt.Sprintf("/servers/%s/action", instanceId) - resp, err := region.ecsPost(resource, params) - if err != nil { - return nil, errors.Wrap(err, "ecsPost") - } - ret := &cloudprovider.ServerVncOutput{ - Protocol: "openstack", - InstanceId: instanceId, - Hypervisor: api.HYPERVISOR_OPENSTACK, - } - - ret.Url, err = resp.GetString("console", "url") - if err != nil { - return nil, errors.Wrapf(err, "remote_console") - } - - if origin { - return ret, nil - } - - token := string([]byte(ret.Url)[len(ret.Url)-36:]) - vncUrl, _ := url.Parse(ret.Url) - ret.Url = fmt.Sprintf("ws://%s?token=%s", vncUrl.Host, token) - ret.Protocol = "vnc" - return ret, nil -} - -func (instance *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - origin := false - if input != nil { - origin = input.Origin - } - ret, err := instance.host.zone.region.GetInstanceVNCUrl(instance.Id, origin) - if err == nil { - return ret, nil - } - return instance.host.zone.region.GetInstanceVNC(instance.Id, origin) -} - -func (instance *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return instance.host.zone.region.DeployVM(instance.Id, name, password, publicKey, deleteKeypair, description) -} - -func (instance *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - return instance.Id, instance.host.zone.region.ReplaceSystemDisk(instance.Id, desc.ImageId, desc.Password, desc.PublicKey, desc.SysSizeGB) -} - -func (instance *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - if (len(config.InstanceType) > 0 && instance.GetInstanceType() != config.InstanceType) || instance.GetVcpuCount() != config.Cpu || instance.GetVmemSizeMB() != config.MemoryMB { - flavor, err := instance.host.zone.region.syncFlavor(config.InstanceType, config.Cpu, config.MemoryMB, 40) - if err != nil { - return errors.Wrapf(err, "syncFlavor(%s)", config.InstanceType) - } - // When resizing, instances must change flavor! - if flavor.Name == instance.Flavor.OriginalName { - return nil - } - return instance.host.zone.region.ChangeConfig(instance, flavor.Id) - } - return nil -} - -func (region *SRegion) ChangeConfig(instance *SInstance, flavorId string) error { - params := map[string]map[string]string{ - "resize": { - "flavorRef": flavorId, - }, - } - resource := fmt.Sprintf("/servers/%s/action", instance.Id) - _, err := region.ecsPost(resource, params) - if err != nil { - return errors.Wrap(err, "ecsPost") - } - err = cloudprovider.WaitStatus(instance, api.VM_SYNC_CONFIG, time.Second*3, time.Minute*4) - if err != nil { - return errors.Wrap(err, "WaitStatsAfterChangeConfig") - } - return region.instanceOperation(instance.Id, "confirmResize") -} - -func (instance *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return instance.host.zone.region.AttachDisk(instance.Id, diskId) -} - -func (instance *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return instance.host.zone.region.DetachDisk(instance.Id, diskId) -} - -func (region *SRegion) instanceOperation(instanceId, operate string) error { - params := map[string]string{operate: ""} - resource := fmt.Sprintf("/servers/%s/action", instanceId) - _, err := region.ecsPost(resource, params) - return err -} - -func (region *SRegion) doStopVM(instanceId string, isForce bool) error { - return region.instanceOperation(instanceId, "os-stop") -} - -func (region *SRegion) doDeleteVM(instanceId string) error { - return region.instanceOperation(instanceId, "forceDelete") -} - -func (region *SRegion) StartVM(instanceId string) error { - return region.instanceOperation(instanceId, "os-start") -} - -func (region *SRegion) StopVM(instanceId string, isForce bool) error { - return region.doStopVM(instanceId, isForce) -} - -func (region *SRegion) DeleteVM(instanceId string) error { - instance, err := region.GetInstance(instanceId) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return errors.Wrapf(err, "GetInstance(%s)", instanceId) - } - status := instance.GetStatus() - log.Debugf("Instance status on delete is %s", status) - if status != api.VM_READY { - log.Warningf("DeleteVM: vm status is %s expect %s", status, api.VM_READY) - } - return region.doDeleteVM(instanceId) -} - -func (region *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { - if len(password) > 0 { - params := map[string]map[string]string{ - "changePassword": { - "adminPass": password, - }, - } - resource := fmt.Sprintf("/servers/%s/action", instanceId) - _, err := region.ecsPost(resource, params) - return err - } - return nil -} - -func (instance *SInstance) DeleteVM(ctx context.Context) error { - err := instance.host.zone.region.DeleteVM(instance.Id) - if err != nil { - return errors.Wrapf(err, "instance.host.zone.region.DeleteVM(%s)", instance.Id) - } - return cloudprovider.WaitDeleted(instance, time.Second*5, time.Minute*10) -} - -func (region *SRegion) ReplaceSystemDisk(instanceId string, imageId string, passwd string, publicKey string, sysDiskSizeGB int) error { - params := map[string]map[string]string{ - "rebuild": { - "imageRef": imageId, - }, - } - - if len(publicKey) > 0 { - keypairName, err := region.syncKeypair(instanceId, publicKey) - if err != nil { - return err - } - params["rebuild"]["key_name"] = keypairName - } - - if len(passwd) > 0 { - params["rebuild"]["adminPass"] = passwd - } - resource := fmt.Sprintf("/servers/%s/action", instanceId) - _, err := region.ecsPost(resource, params) - return err -} - -func (region *SRegion) DetachDisk(instanceId string, diskId string) error { - resource := fmt.Sprintf("/servers/%s/os-volume_attachments/%s", instanceId, diskId) - _, err := region.ecsDelete(resource) - if err != nil { - return errors.Wrap(err, "ecsDelete") - } - status := "" - startTime := time.Now() - for time.Now().Sub(startTime) < time.Minute*10 { - disk, err := region.GetDisk(diskId) - if err != nil { - return errors.Wrapf(err, "GetDisk(%s)", diskId) - } - status = disk.Status - log.Debugf("status %s expect %s", status, DISK_STATUS_AVAILABLE) - if status == DISK_STATUS_AVAILABLE { - return nil - } - time.Sleep(time.Second * 15) - } - return fmt.Errorf("timeout for waitting detach disk, current status: %s", status) -} - -func (region *SRegion) AttachDisk(instanceId string, diskId string) error { - params := map[string]map[string]string{ - "volumeAttachment": { - "volumeId": diskId, - }, - } - resource := fmt.Sprintf("/servers/%s/os-volume_attachments", instanceId) - _, err := region.ecsPost(resource, params) - if err != nil { - return errors.Wrap(err, "ecsPost") - } - status := "" - startTime := time.Now() - for time.Now().Sub(startTime) < time.Minute*10 { - disk, err := region.GetDisk(diskId) - if err != nil { - return errors.Wrapf(err, "GetDisk(%s)", diskId) - } - status = disk.Status - log.Debugf("status %s expect %s", status, DISK_STATUS_IN_USE) - if status == DISK_STATUS_IN_USE { - return nil - } - time.Sleep(time.Second * 15) - } - return fmt.Errorf("timeout for waitting attach disk, current status: %s", status) -} - -func (region *SRegion) MigrateVM(instanceId string, hostName string) error { - params := jsonutils.NewDict() - migrate := jsonutils.NewDict() - migrate.Add(jsonutils.JSONNull, "host") - if hostName != "" { - migrate.Add(jsonutils.NewString(hostName), "host") - } - params.Add(migrate, "migrate") - resource := fmt.Sprintf("/servers/%s/action", instanceId) - _, err := region.ecsPost(resource, params) - if err != nil { - return errors.Wrapf(err, "On Requst Migrate instance:%s", instanceId) - } - return nil -} - -func (region *SRegion) LiveMigrateVM(instanceId string, hostName string) error { - params := jsonutils.NewDict() - osMigrateLive := jsonutils.NewDict() - osMigrateLive.Add(jsonutils.NewString("auto"), "block_migration") - osMigrateLive.Add(jsonutils.JSONNull, "host") - if hostName != "" { - osMigrateLive.Add(jsonutils.NewString(hostName), "host") - } - params.Add(osMigrateLive, "os-migrateLive") - resource := fmt.Sprintf("/servers/%s/action", instanceId) - _, err := region.ecsPost(resource, params) - if err != nil { - return errors.Wrapf(err, "On Requst LiveMigrate instance:%s", instanceId) - } - return nil -} - -//仅live-migration -func (region *SRegion) ListServerMigration(instanceId string) error { - resource := fmt.Sprintf("/servers/%s/migrations", instanceId) - _, err := region.ecsGet(resource) - if err != nil { - return errors.Wrapf(err, "ListServerMigration") - } - return nil -} - -//仅live-migration -func (region *SRegion) DeleteMigration(instanceId string, migrationId string) error { - resource := fmt.Sprintf("/servers/%s/migrations/%s", instanceId, migrationId) - _, err := region.ecsDelete(resource) - if err != nil { - return errors.Wrapf(err, "On Requst delete LiveMigrate:%s", migrationId) - } - return nil -} - -//仅live-migration -func (region *SRegion) ForceCompleteMigration(instanceId string, migrationId string) error { - params := jsonutils.NewDict() - params.Add(jsonutils.JSONNull, "force_complete") - resource := fmt.Sprintf("/servers/%s/migrations/%s/action", instanceId, migrationId) - _, err := region.ecsPost(resource, params) - if err != nil { - return errors.Wrapf(err, "On Requst delete LiveMigrate:%s", migrationId) - } - return nil -} - -func (region *SRegion) GetMigrations(instanceId string, migrationType string) (jsonutils.JSONObject, error) { - query := url.Values{} - query.Set("instance_uuid", instanceId) - query.Set("migration_type", migrationType) - resource := "/os-migrations" - migrations, err := region.ecsList(resource, query) - if err != nil { - return nil, errors.Wrapf(err, "On Get instance :%s Migration,migration_type:%s", instanceId, migrationType) - } - return migrations, nil -} - -func (instance *SInstance) AssignSecurityGroup(secgroupId string) error { - if secgroupId == SECGROUP_NOT_SUPPORT { - return fmt.Errorf("Security groups are not supported. Security group components are not installed") - } - secgroup, err := instance.host.zone.region.GetSecurityGroup(secgroupId) - if err != nil { - return errors.Wrapf(err, "GetSecurityGroup(%s)", secgroupId) - } - params := map[string]map[string]string{ - "addSecurityGroup": { - "name": secgroup.Name, - }, - } - resource := fmt.Sprintf("/servers/%s/action", instance.Id) - _, err = instance.host.zone.region.ecsDo(instance.GetProjectId(), resource, params) - return err -} - -func (instance *SInstance) RevokeSecurityGroup(secgroupId string) error { - // 若OpenStack不支持安全组,则忽略解绑安全组 - if secgroupId == SECGROUP_NOT_SUPPORT { - return nil - } - secgroup, err := instance.host.zone.region.GetSecurityGroup(secgroupId) - if err != nil { - return errors.Wrapf(err, "GetSecurityGroup(%s)", secgroupId) - } - params := map[string]map[string]string{ - "removeSecurityGroup": { - "name": secgroup.Name, - }, - } - resource := fmt.Sprintf("/servers/%s/action", instance.Id) - _, err = instance.host.zone.region.ecsDo(instance.GetProjectId(), resource, params) - return err -} - -func (instance *SInstance) SetSecurityGroups(secgroupIds []string) error { - secgroups, err := instance.host.zone.region.GetSecurityGroupsByInstance(instance.Id) - if err != nil { - return errors.Wrapf(err, "GetSecurityGroupsByInstance(%s)", instance.Id) - } - local := set.New(set.ThreadSafe) - for _, secgroup := range secgroups { - local.Add(secgroup.Id) - } - newG := set.New(set.ThreadSafe) - for _, secgroupId := range secgroupIds { - newG.Add(secgroupId) - } - for _, del := range set.Difference(local, newG).List() { - secgroupId := del.(string) - err := instance.RevokeSecurityGroup(secgroupId) - if err != nil { - return errors.Wrapf(err, "RevokeSecurityGroup(%s)", secgroupId) - } - } - for _, add := range set.Difference(newG, local).List() { - secgroupId := add.(string) - err := instance.AssignSecurityGroup(secgroupId) - if err != nil { - return errors.Wrapf(err, "AssignSecurityGroup(%s)", secgroupId) - } - } - return nil -} - -func (instance *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - for networkName, address := range instance.Addresses { - for i := 0; i < len(address); i++ { - if instance.Addresses[networkName][i].Type == "floating" { - return instance.host.zone.region.GetEipByIp(instance.Addresses[networkName][i].Addr) - } - } - } - return nil, nil -} - -func (instance *SInstance) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (instance *SInstance) GetCreatedAt() time.Time { - return instance.Created -} - -func (instance *SInstance) GetExpiredAt() time.Time { - return time.Time{} -} - -func (instance *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -func (instance *SInstance) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (region *SRegion) RenewInstances(instanceId []string, bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (instance *SInstance) GetProjectId() string { - return instance.TenantId -} - -func (self *SInstance) GetError() error { - if self.Status == INSTANCE_STATUS_ERROR && len(self.Fault.Message) > 0 { - return errors.Error(self.Fault.Message) - } - return nil -} - -func (instance *SInstance) MigrateVM(hostId string) error { - hostName := "" - if hostId != "" { - iHost, err := instance.host.zone.region.GetIHostById(hostId) - if err != nil { - return errors.Wrapf(err, "GetIHostById(%s)", hostId) - } - hostName = iHost.GetName() - } - - previousHostName := instance.Host - err := instance.host.zone.region.MigrateVM(instance.Id, hostName) - if err != nil { - return errors.Wrap(err, "MigrateVm") - } - err = cloudprovider.WaitMultiStatus(instance, []string{api.VM_SYNC_CONFIG, api.VM_READY, api.VM_UNKNOWN}, time.Second*10, time.Hour*3) - if err != nil { - return errors.Wrap(err, "WaitMultiStatus") - } - if instance.GetStatus() == api.VM_UNKNOWN { - return errors.Wrap(errors.ErrInvalidStatus, "GetStatus") - } - if instance.GetStatus() == api.VM_READY { - if instance.Host == previousHostName { - return errors.Wrap(fmt.Errorf("instance not migrated"), "Check host after migration") - } - return nil - } - return instance.host.zone.region.instanceOperation(instance.Id, "confirmResize") -} - -func (instance *SInstance) LiveMigrateVM(hostId string) error { - hostName := "" - if hostId != "" { - iHost, err := instance.host.zone.region.GetIHostById(hostId) - if err != nil { - return errors.Wrapf(err, "GetIHostById(%s)", hostId) - } - hostName = iHost.GetName() - } - previousHostName := instance.Host - err := instance.host.zone.region.LiveMigrateVM(instance.Id, hostName) - if err != nil { - return errors.Wrap(err, "LiveMIgrateVm") - } - err = cloudprovider.WaitMultiStatus(instance, []string{api.VM_SYNC_CONFIG, api.VM_RUNNING, api.VM_UNKNOWN}, time.Second*10, time.Hour*3) - if err != nil { - return errors.Wrap(err, "WaitMultiStatus") - } - if instance.GetStatus() == api.VM_UNKNOWN { - return errors.Wrap(errors.ErrInvalidStatus, "GetStatus") - } - if instance.GetStatus() == api.VM_RUNNING { - if instance.Host == previousHostName { - return errors.Wrap(fmt.Errorf("instance not migrated"), "Check host after migration") - } - return nil - } - return instance.host.zone.region.instanceOperation(instance.Id, "confirmResize") -} -func (instance *SInstance) GetIHostId() string { - err := instance.host.zone.fetchHosts() - if err != nil { - return "" - } - for _, host := range instance.host.zone.hosts { - if instance.HypervisorHostname == host.HypervisorHostname { - return host.GetGlobalId() - } - } - return "" -} - -func (region *SRegion) GetInstanceMetadata(instanceId string) (map[string]string, error) { - resource := fmt.Sprintf("/servers/%s/metadata", instanceId) - resp, err := region.ecsList(resource, nil) - if err != nil { - return nil, errors.Wrap(err, "ecsList") - } - result := struct { - Metadata map[string]string - }{} - err = resp.Unmarshal(&result) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return result.Metadata, nil -} - -func (zone *SZone) CreateVM(hypervisor string, opts *cloudprovider.SManagedVMCreateConfig) (*SInstance, error) { - region := zone.region - network, err := region.GetNetwork(opts.ExternalNetworkId) - if err != nil { - return nil, err - } - - secgroups := []map[string]string{} - for _, secgroupId := range opts.ExternalSecgroupIds { - if secgroupId != SECGROUP_NOT_SUPPORT { - secgroups = append(secgroups, map[string]string{"name": secgroupId}) - } - } - - image, err := region.GetImage(opts.ExternalImageId) - if err != nil { - return nil, errors.Wrapf(err, "GetImage(%s)", opts.ExternalImageId) - } - - sysDiskSizeGB := image.Size / 1024 / 1024 / 1024 - if opts.SysDisk.SizeGB < sysDiskSizeGB { - opts.SysDisk.SizeGB = sysDiskSizeGB - } - - if opts.SysDisk.SizeGB < image.GetMinOsDiskSizeGb() { - opts.SysDisk.SizeGB = image.GetMinOsDiskSizeGb() - } - - BlockDeviceMappingV2 := []map[string]interface{}{} - - diskIds := []string{} - - defer func() { - for _, diskId := range diskIds { - err = region.DeleteDisk(diskId) - if err != nil { - log.Errorf("clean disk %s error: %v", diskId, err) - } - } - }() - - if opts.SysDisk.StorageType != api.STORAGE_OPENSTACK_NOVA { //新建volume - istorage, err := zone.GetIStorageById(opts.SysDisk.StorageExternalId) - if err != nil { - return nil, errors.Wrapf(err, "GetIStorageById(%s)", opts.SysDisk.StorageExternalId) - } - - _sysDisk, err := region.CreateDisk(opts.ExternalImageId, istorage.GetName(), "", opts.SysDisk.SizeGB, opts.SysDisk.Name, opts.ProjectId) - if err != nil { - return nil, errors.Wrapf(err, "CreateDisk %s", opts.SysDisk.Name) - } - - diskIds = append(diskIds, _sysDisk.GetGlobalId()) - - BlockDeviceMappingV2 = append(BlockDeviceMappingV2, map[string]interface{}{ - "boot_index": 0, - "uuid": _sysDisk.GetGlobalId(), - "source_type": "volume", - "destination_type": "volume", - "delete_on_termination": true, - }) - } else { - BlockDeviceMappingV2 = append(BlockDeviceMappingV2, map[string]interface{}{ - "boot_index": 0, - "uuid": image.Id, - "source_type": "image", - "destination_type": "local", - "delete_on_termination": true, - }) - } - - var _disk *SDisk - for index, disk := range opts.DataDisks { - istorage, err := zone.GetIStorageById(disk.StorageExternalId) - if err != nil { - return nil, errors.Wrapf(err, "GetIStorageById(%s)", disk.StorageExternalId) - } - _disk, err = region.CreateDisk("", istorage.GetName(), "", disk.SizeGB, disk.Name, opts.ProjectId) - if err != nil { - return nil, errors.Wrapf(err, "CreateDisk %s", disk.Name) - } - diskIds = append(diskIds, _disk.Id) - - mapping := map[string]interface{}{ - "source_type": "volume", - "destination_type": "volume", - "delete_on_termination": true, - "boot_index": index + 1, - "uuid": _disk.Id, - } - - BlockDeviceMappingV2 = append(BlockDeviceMappingV2, mapping) - } - - az := zone.ZoneName - if len(hypervisor) > 0 { - az = fmt.Sprintf("%s:%s", zone.ZoneName, hypervisor) - } - - net := map[string]string{ - "uuid": network.NetworkId, - } - if len(opts.IpAddr) > 0 { - net["fixed_ip"] = opts.IpAddr - } - - params := map[string]map[string]interface{}{ - "server": { - "name": opts.Name, - "adminPass": opts.Password, - "availability_zone": az, - "networks": []map[string]string{net}, - "security_groups": secgroups, - "user_data": opts.UserData, - "imageRef": opts.ExternalImageId, - "block_device_mapping_v2": BlockDeviceMappingV2, - }, - } - if len(opts.IpAddr) > 0 { - params["server"]["accessIPv4"] = opts.IpAddr - } - - flavor, err := region.syncFlavor(opts.InstanceType, opts.Cpu, opts.MemoryMB, opts.SysDisk.SizeGB) - if err != nil { - return nil, err - } - params["server"]["flavorRef"] = flavor.Id - - if len(opts.PublicKey) > 0 { - keypairName, err := region.syncKeypair(opts.Name, opts.PublicKey) - if err != nil { - return nil, err - } - params["server"]["key_name"] = keypairName - } - - resp, err := region.ecsCreate(opts.ProjectId, "/servers", params) - if err != nil { - return nil, errors.Wrap(err, "ecsCreate") - } - diskIds = []string{} - instance := &SInstance{} - err = resp.Unmarshal(instance, "server") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return instance, nil -} diff --git a/pkg/multicloud/openstack/instancenic.go b/pkg/multicloud/openstack/instancenic.go deleted file mode 100644 index a8288ac6b7..0000000000 --- a/pkg/multicloud/openstack/instancenic.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/regutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - MacAddr string `json:"OS-EXT-IPS-MAC:mac_addr"` - Version int `json:"version"` - Addr string `json:"addr"` - Type string `json:"OS-EXT-IPS:type"` -} - -type SFixedIp struct { - IpAddress string - SubnetId string -} - -type SInstancePort struct { - region *SRegion - FixedIps []SFixedIp - MacAddr string - NetId string - PortId string - PortState string - - cloudprovider.DummyICloudNic -} - -func (region *SRegion) GetInstancePorts(instanceId string) ([]SInstancePort, error) { - resource := fmt.Sprintf("/servers/%s/os-interface", instanceId) - resp, err := region.ecsList(resource, nil) - if err != nil { - return nil, errors.Wrap(err, "ecsList") - } - ports := []SInstancePort{} - err = resp.Unmarshal(&ports, "interfaceAttachments") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return ports, nil -} - -func (nic *SInstancePort) GetId() string { - return "" -} - -func (nic *SInstancePort) GetIP() string { - for i := range nic.FixedIps { - if regutils.MatchIPAddr(nic.FixedIps[i].IpAddress) { - return nic.FixedIps[i].IpAddress - } - } - return "" -} - -func (nic *SInstancePort) GetMAC() string { - return nic.MacAddr -} - -func (nic *SInstancePort) GetDriver() string { - return "virtio" -} - -func (nic *SInstancePort) InClassicNetwork() bool { - return false -} - -func (nic *SInstancePort) GetINetworkId() string { - for i := range nic.FixedIps { - if regutils.MatchIPAddr(nic.FixedIps[i].IpAddress) { - network, err := nic.region.GetNetwork(nic.FixedIps[i].SubnetId) - if err != nil { - return nic.FixedIps[i].SubnetId - } - return network.GetGlobalId() - } - } - return "" -} diff --git a/pkg/multicloud/openstack/loadbalanceracl.go b/pkg/multicloud/openstack/loadbalanceracl.go deleted file mode 100644 index 802b5146c1..0000000000 --- a/pkg/multicloud/openstack/loadbalanceracl.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - "time" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type AclEntrys struct { - AclEntry []AclEntry -} - -type AclEntry struct { - AclEntryComment string - AclEntryIP string -} - -type SLoadbalancerAcl struct { - multicloud.SResourceBase - multicloud.OpenStackTags - listener *SLoadbalancerListener -} - -func (acl *SLoadbalancerAcl) GetAclListenerID() string { - return acl.listener.ID -} - -func (acl *SLoadbalancerAcl) GetName() string { - return acl.listener.Name + "AllowedCidrs" -} - -func (acl *SLoadbalancerAcl) GetId() string { - return acl.listener.ID -} - -func (acl *SLoadbalancerAcl) GetGlobalId() string { - return acl.listener.ID -} - -func (acl *SLoadbalancerAcl) GetStatus() string { - return "" -} - -func (acl *SLoadbalancerAcl) IsEmulated() bool { - return false -} - -func (acl *SLoadbalancerAcl) Refresh() error { - return acl.listener.Refresh() -} - -func (acl *SLoadbalancerAcl) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { - aclEntrys := []cloudprovider.SLoadbalancerAccessControlListEntry{} - for i := 0; i < len(acl.listener.AllowedCidrs); i++ { - aclEntry := cloudprovider.SLoadbalancerAccessControlListEntry{} - aclEntry.CIDR = acl.listener.AllowedCidrs[i] - aclEntry.Comment = "AllowedCidr" - aclEntrys = append(aclEntrys, aclEntry) - } - return aclEntrys -} - -func (region *SRegion) UpdateLoadbalancerListenerAllowedCidrs(listenerId string, cidrs []string) error { - params := jsonutils.NewDict() - listenerParam := jsonutils.NewDict() - listenerParam.Add(jsonutils.NewStringArray(cidrs), "allowed_cidrs") - params.Add(listenerParam, "listener") - _, err := region.lbUpdate(fmt.Sprintf("/v2/lbaas/listeners/%s", listenerId), params) - if err != nil { - return errors.Wrapf(err, `region.lbUpdate(/v2/lbaas/listeners/%s, params)`, listenerId) - } - return nil -} - -func (acl *SLoadbalancerAcl) Delete() error { - // ensure listener status - err := waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute) - if err != nil { - return errors.Wrap(err, `waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute)`) - } - err = acl.listener.region.UpdateLoadbalancerListenerAllowedCidrs(acl.listener.ID, []string{}) - if err != nil { - return errors.Wrap(err, `acl.listener.region.UpdateLoadbalancerListenerAllowedCidrs(acl.listener.ID, []string{})`) - } - err = waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute) - if err != nil { - return errors.Wrap(err, `waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute)`) - } - return nil -} - -func (region *SRegion) GetLoadbalancerAclDetail(aclId string) (*SLoadbalancerAcl, error) { - listener, err := region.GetLoadbalancerListenerbyId(aclId) - if err != nil { - return nil, errors.Wrapf(err, "region.GetLoadbalancerListenerbyId(%s)", aclId) - } - acl := SLoadbalancerAcl{} - acl.listener = listener - return &acl, nil -} - -func (region *SRegion) GetLoadBalancerAcls() ([]SLoadbalancerAcl, error) { - listeners, err := region.GetLoadbalancerListeners() - if err != nil { - return nil, errors.Wrap(err, "region.GetLoadbalancerListeners()") - } - acls := []SLoadbalancerAcl{} - for i := 0; i < len(listeners); i++ { - if len(listeners[i].AllowedCidrs) < 1 { - continue - } - acl := new(SLoadbalancerAcl) - acl.listener = &listeners[i] - acls = append(acls, *acl) - - } - return acls, nil -} - -func (region *SRegion) CreateLoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (*SLoadbalancerAcl, error) { - if !acl.AccessControlEnable { - return nil, errors.Wrap(fmt.Errorf("only support allowed cidrs"), "CreateLoadBalancerAcl") - } - if len(acl.ListenerId) < 1 { - return nil, errors.Wrap(fmt.Errorf("loadbalanceracl must band to a loadbalancerlistener"), "CreateLoadBalancerAcl") - } - cidrs := []string{} - for i := 0; i < len(acl.Entrys); i++ { - cidrs = append(cidrs, acl.Entrys[i].CIDR) - } - sacl, err := region.GetLoadbalancerAclDetail(acl.ListenerId) - if err != nil { - return nil, errors.Wrapf(err, "region.GetLoadbalancerAclDetail(%s)", acl.ListenerId) - } - // ensure listener status - err = waitLbResStatus(sacl.listener, 10*time.Second, 8*time.Minute) - if err != nil { - return nil, errors.Wrap(err, `waitLbResStatus(sacl.listener, 10*time.Second, 8*time.Minute)`) - } - return sacl, region.UpdateLoadbalancerListenerAllowedCidrs(acl.ListenerId, cidrs) -} - -func (acl *SLoadbalancerAcl) Sync(_acl *cloudprovider.SLoadbalancerAccessControlList) error { - // ensure listener status - err := waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute) - if err != nil { - return errors.Wrap(err, "waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute)") - } - - cidrs := []string{} - for i := 0; i < len(_acl.Entrys); i++ { - cidrs = append(cidrs, _acl.Entrys[i].CIDR) - } - err = acl.listener.region.UpdateLoadbalancerListenerAllowedCidrs(acl.listener.ID, cidrs) - if err != nil { - return errors.Wrapf(err, "UpdateLoadbalancerListenerAllowedCidrs(%s, cidrs)", acl.listener.ID) - } - err = waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute) - if err != nil { - return errors.Wrap(err, "waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute)") - } - return nil -} - -func (acl *SLoadbalancerAcl) GetProjectId() string { - return acl.listener.ProjectID -} diff --git a/pkg/multicloud/openstack/loadbalancerlistener.go b/pkg/multicloud/openstack/loadbalancerlistener.go deleted file mode 100644 index 0d70d649f1..0000000000 --- a/pkg/multicloud/openstack/loadbalancerlistener.go +++ /dev/null @@ -1,774 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "context" - "fmt" - "net/url" - "strconv" - "time" - - "github.com/coredns/coredns/plugin/pkg/log" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLoadbalancerListenerCreateParams struct { - Protocol string `json:"protocol,omitempty"` - Description string `json:"description,omitempty"` - AdminStateUp bool `json:"admin_state_up,omitempty"` - ConnectionLimit *int `json:"connection_limit,omitempty"` - ProtocolPort string `json:"protocol_port,omitempty"` - LoadbalancerID string `json:"loadbalancer_id,omitempty"` - DefaultPoolId string `json:"default_pool_id,omitempty"` - Name string `json:"name,omitempty"` - InsertHeaders SInsertHeaders `json:"insert_headers,omitempty"` - DefaultTLSContainerRef string `json:"default_tls_container_ref,omitempty"` - SniContainerRefs []string `json:"sni_container_refs,omitempty"` - TimeoutClientData *int `json:"timeout_client_data,omitempty"` - TimeoutMemberConnect *int `json:"timeout_member_connect,omitempty"` - TimeoutMemberData *int `json:"timeout_member_data,omitempty"` - TimeoutTCPInspect *int `json:"timeout_tcp_inspect,omitempty"` - Tags []string `json:"tags,omitempty"` - ClientCaTLSContainerRef string `json:"client_ca_tls_container_ref,omitempty"` - ClientAuthentication string `json:"client_authentication,omitempty"` - ClientCrlContainerRef string `json:"client_crl_container_ref,omitempty"` - AllowedCidrs []string `json:"allowed_cidrs,omitempty"` - TLSCiphers string `json:"tls_ciphers,omitempty"` - TLSVersions []string `json:"tls_versions,omitempty"` -} - -type SLoadbalancerListenerUpdateParams struct { - Description string `json:"description,omitempty"` - AdminStateUp bool `json:"admin_state_up,omitempty"` - ConnectionLimit *int `json:"connection_limit,omitempty"` - DefaultPoolId string `json:"default_pool_id,omitempty"` - Name string `json:"name,omitempty"` - InsertHeaders SInsertHeaders `json:"insert_headers,omitempty"` - DefaultTLSContainerRef string `json:"default_tls_container_ref,omitempty"` - SniContainerRefs []string `json:"sni_container_refs,omitempty"` - TimeoutClientData *int `json:"timeout_client_data,omitempty"` - TimeoutMemberConnect *int `json:"timeout_member_connect,omitempty"` - TimeoutMemberData *int `json:"timeout_member_data,omitempty"` - TimeoutTCPInspect *int `json:"timeout_tcp_inspect,omitempty"` - Tags []string `json:"tags,omitempty"` - ClientCaTLSContainerRef string `json:"client_ca_tls_container_ref,omitempty"` - ClientAuthentication string `json:"client_authentication,omitempty"` - ClientCrlContainerRef string `json:"client_crl_container_ref,omitempty"` - AllowedCidrs []string `json:"allowed_cidrs,omitempty"` - TLSCiphers string `json:"tls_ciphers,omitempty"` - TLSVersions []string `json:"tls_versions,omitempty"` -} - -type SInsertHeaders struct { - XForwardedPort string `json:"X-Forwarded-Port"` - XForwardedFor string `json:"X-Forwarded-For"` -} - -type SLoadbalancerListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.OpenStackTags - region *SRegion - l7policies []SLoadbalancerL7Policy - pools []SLoadbalancerPool - Description string `json:"description"` - AdminStateUp bool `json:"admin_state_up"` - ProjectID string `json:"project_id"` - Protocol string `json:"protocol"` - ProtocolPort int `json:"protocol_port"` - ProvisioningStatus string `json:"provisioning_status"` - DefaultTLSContainerRef string `json:"default_tls_container_ref"` - LoadbalancerIds []SLoadbalancerID `json:"loadbalancers"` - InsertHeaders SInsertHeaders `json:"insert_headers"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` - ID string `json:"id"` - OperatingStatus string `json:"operating_status"` - DefaultPoolID string `json:"default_pool_id"` - SniContainerRefs []string `json:"sni_container_refs"` - L7PolicieIds []SL7PolicieID `json:"l7policies"` - Name string `json:"name"` - TimeoutClientData int `json:"timeout_client_data"` - TimeoutMemberConnect int `json:"timeout_member_connect"` - TimeoutMemberData int `json:"timeout_member_data"` - TimeoutTCPInspect int `json:"timeout_tcp_inspect"` - Tags []string `json:"tags"` - ClientCaTLSContainerRef string `json:"client_ca_tls_container_ref"` - ClientAuthentication string `json:"client_authentication"` - ClientCrlContainerRef string `json:"client_crl_container_ref"` - AllowedCidrs []string `json:"allowed_cidrs"` - TLSCiphers string `json:"tls_ciphers"` - TLSVersions []string `json:"tls_versions"` -} - -func (listener *SLoadbalancerListener) GetName() string { - if len(listener.Name) == 0 { - listener.Refresh() - } - if len(listener.Name) > 0 { - return listener.Name - } - return fmt.Sprintf("HTTP:%d", listener.ProtocolPort) -} - -func (listener *SLoadbalancerListener) GetId() string { - return listener.ID -} - -func (listener *SLoadbalancerListener) GetGlobalId() string { - return listener.GetId() -} - -func (listener *SLoadbalancerListener) GetStatus() string { - switch listener.ProvisioningStatus { - case "ACTIVE": - return api.LB_STATUS_ENABLED - case "PENDING_CREATE": - return api.LB_CREATING - case "PENDING_UPDATE": - return api.LB_SYNC_CONF - case "PENDING_DELETE": - return api.LB_STATUS_DELETING - case "DELETED": - return api.LB_STATUS_DELETED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (listener *SLoadbalancerListener) IsEmulated() bool { - return false -} - -func (listener *SLoadbalancerListener) GetEgressMbps() int { - - return 0 -} - -func (region *SRegion) GetLoadbalancerListeners() ([]SLoadbalancerListener, error) { - listeners := []SLoadbalancerListener{} - resource := "/v2/lbaas/listeners" - query := url.Values{} - for { - resp, err := region.lbList(resource, query) - if err != nil { - return nil, errors.Wrap(err, "lbList") - } - part := struct { - Listeners []SLoadbalancerListener - ListenersLinks SNextLinks - }{} - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - listeners = append(listeners, part.Listeners...) - marker := part.ListenersLinks.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - - for i := 0; i < len(listeners); i++ { - listeners[i].region = region - } - for i := 0; i < len(listeners); i++ { - err := listeners[i].fetchLoadbalancerListenerL7Policies() - if err != nil { - return nil, errors.Wrap(err, "listener.fetchLoadbalancerListenerL7Policies()") - } - } - - for i := 0; i < len(listeners); i++ { - err := listeners[i].fetchLoadbalancerPools() - if err != nil { - return nil, errors.Wrap(err, "listeners[i].fetchLoadbalancerPools()") - } - } - - return listeners, nil -} - -func (region *SRegion) GetLoadbalancerListenerbyId(listenerId string) (*SLoadbalancerListener, error) { - resp, err := region.lbGet(fmt.Sprintf("/v2/lbaas/listeners/%s", listenerId)) - if err != nil { - return nil, errors.Wrapf(err, "region.Get(/v2/lbaas/listeners/%s)", listenerId) - } - listener := SLoadbalancerListener{} - err = resp.Unmarshal(&listener, "listener") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal(&listener, listener)") - } - listener.region = region - err = listener.fetchLoadbalancerListenerL7Policies() - if err != nil { - return nil, errors.Wrap(err, "listener.fetchLoadbalancerListenerL7Policies()") - } - - err = listener.fetchLoadbalancerPools() - if err != nil { - return nil, errors.Wrap(err, "listeners[i].fetchLoadbalancerPools()") - - } - return &listener, nil -} - -func (region *SRegion) CreateLoadbalancerListener(loadbalancerId string, listenerParams *cloudprovider.SLoadbalancerListener) (*SLoadbalancerListener, error) { - type CreateParams struct { - Listener SLoadbalancerListenerCreateParams `json:"listener"` - } - params := CreateParams{} - params.Listener.AdminStateUp = true - params.Listener.LoadbalancerID = loadbalancerId - params.Listener.DefaultPoolId = listenerParams.BackendGroupID - params.Listener.Protocol = LB_PROTOCOL_MAP[listenerParams.ListenerType] - params.Listener.ProtocolPort = strconv.Itoa(listenerParams.ListenerPort) - if listenerParams.ClientIdleTimeout != 0 { - // 毫秒单位 - msClientIdleTimeout := listenerParams.ClientIdleTimeout * 1000 - params.Listener.TimeoutClientData = &msClientIdleTimeout - } - if listenerParams.BackendConnectTimeout != 0 { - msBackendConnectTimeout := listenerParams.BackendConnectTimeout * 1000 - params.Listener.TimeoutMemberConnect = &msBackendConnectTimeout - } - if listenerParams.BackendIdleTimeout != 0 { - msBackendIdleTimeout := listenerParams.BackendIdleTimeout * 1000 - params.Listener.TimeoutMemberData = &msBackendIdleTimeout - } - - params.Listener.Name = listenerParams.Name - if listenerParams.XForwardedFor { - params.Listener.InsertHeaders.XForwardedFor = "true" - } - body, err := region.lbPost("/v2/lbaas/listeners", jsonutils.Marshal(params)) - if err != nil { - return nil, errors.Wrap(err, "region.Post(/v2/lbaas/listeners)") - } - slistener := SLoadbalancerListener{} - slistener.region = region - return &slistener, body.Unmarshal(&slistener, "listener") -} - -func (listener *SLoadbalancerListener) Refresh() error { - newlistener, err := listener.region.GetLoadbalancerListenerbyId(listener.ID) - if err != nil { - return errors.Wrapf(err, "listener.region.GetLoadbalancerListenerbyId(%s)", listener.ID) - } - return jsonutils.Update(listener, newlistener) -} - -func (listener *SLoadbalancerListener) GetListenerType() string { - switch listener.Protocol { - case "HTTP": - return api.LB_LISTENER_TYPE_HTTP - case "HTTPS": - return api.LB_LISTENER_TYPE_HTTPS - case "TERMINATED_HTTPS": - return api.LB_LISTENER_TYPE_TERMINATED_HTTPS - case "TCP": - return api.LB_LISTENER_TYPE_TCP - case "UDP": - return api.LB_LISTENER_TYPE_UDP - default: - return "" - } -} - -func (listener *SLoadbalancerListener) GetListenerPort() int { - return listener.ProtocolPort -} - -func (listener *SLoadbalancerListener) GetBackendGroupId() string { - return listener.DefaultPoolID -} - -func (listener *SLoadbalancerListener) GetBackendServerPort() int { - return listener.ProtocolPort -} - -func (listener *SLoadbalancerListener) GetScheduler() string { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetScheduler():listener.fetchFeaturePool():%s", err) - return "" - } - switch pool.LbAlgorithm { - case "ROUND_ROBIN": - return api.LB_SCHEDULER_WRR - case "LEAST_CONNECTIONS": - return api.LB_SCHEDULER_WLC - case "SOURCE_IP": - return api.LB_SCHEDULER_SCH - case "SOURCE_IP_PORT": - return api.LB_SCHEDULER_TCH - default: - return "" - } -} - -func (listener *SLoadbalancerListener) GetAclStatus() string { - if len(listener.AllowedCidrs) > 0 { - return api.LB_BOOL_ON - } - return api.LB_BOOL_OFF -} - -func (listener *SLoadbalancerListener) GetAclType() string { - return api.LB_ACL_TYPE_WHITE -} - -func (listener *SLoadbalancerListener) GetAclId() string { - return "" -} - -func (listener *SLoadbalancerListener) GetHealthCheck() string { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetHealthCheck():listener.fetchFeaturePool():%s", err) - return "" - } - if pool.healthmonitor != nil { - return api.LB_BOOL_ON - } - return api.LB_BOOL_OFF - -} - -func (listener *SLoadbalancerListener) GetHealthCheckType() string { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetHealthCheckType():listener.fetchFeaturePool():%s", err) - return "" - } - if pool.healthmonitor == nil { - return "" - } - switch pool.healthmonitor.Type { - case "HTTP": - return api.LB_HEALTH_CHECK_HTTP - case "HTTPS": - return api.LB_HEALTH_CHECK_HTTPS - case "TCP": - return api.LB_HEALTH_CHECK_TCP - case "UDP-CONNECT": - return api.LB_HEALTH_CHECK_UDP - default: - return "" - } -} - -func (listener *SLoadbalancerListener) GetHealthCheckDomain() string { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetHealthCheckDomain():listener.fetchFeaturePool():%s", err) - return "" - } - if pool.healthmonitor == nil { - return "" - } - return pool.healthmonitor.DomainName -} - -func (listener *SLoadbalancerListener) GetHealthCheckURI() string { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetHealthCheckURI():listener.fetchFeaturePool():%s", err) - return "" - } - if pool.healthmonitor == nil { - return "" - } - return pool.healthmonitor.URLPath -} - -func (listener *SLoadbalancerListener) GetHealthCheckCode() string { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetHealthCheckCode():listener.fetchFeaturePool():%s", err) - return "" - } - if pool.healthmonitor == nil { - return "" - } - return pool.healthmonitor.ExpectedCodes -} - -func (listener *SLoadbalancerListener) GetHealthCheckRise() int { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetHealthCheckRise():listener.fetchFeaturePool():%s", err) - return 0 - } - if pool.healthmonitor == nil { - return 0 - } - return pool.healthmonitor.MaxRetries -} - -func (listener *SLoadbalancerListener) GetHealthCheckFail() int { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetHealthCheckFail():listener.fetchFeaturePool():%s", err) - return 0 - } - if pool.healthmonitor == nil { - return 0 - } - return pool.healthmonitor.MaxRetriesDown -} - -func (listener *SLoadbalancerListener) GetHealthCheckTimeout() int { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetHealthCheckTimeout():listener.fetchFeaturePool():%s", err) - return 0 - } - if pool.healthmonitor == nil { - return 0 - } - return pool.healthmonitor.Timeout -} - -func (listener *SLoadbalancerListener) GetHealthCheckInterval() int { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetHealthCheckInterval():listener.fetchFeaturePool():%s", err) - return 0 - } - if pool.healthmonitor == nil { - return 0 - } - return pool.healthmonitor.Delay -} - -func (listener *SLoadbalancerListener) GetHealthCheckReq() string { - return "" -} - -func (listener *SLoadbalancerListener) GetHealthCheckExp() string { - return "" -} - -func (listener *SLoadbalancerListener) GetStickySession() string { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) - return api.LB_BOOL_OFF - } - stickySession, err := pool.GetStickySession() - if err != nil { - log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) - return api.LB_BOOL_OFF - } - if stickySession == nil { - return "" - } - return stickySession.StickySession -} - -func (listener *SLoadbalancerListener) GetStickySessionType() string { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) - return "" - } - stickySession, err := pool.GetStickySession() - if err != nil { - log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) - return "" - } - if stickySession == nil { - return "" - } - return stickySession.StickySessionType -} - -func (listener *SLoadbalancerListener) GetStickySessionCookie() string { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) - return "" - } - stickySession, err := pool.GetStickySession() - if err != nil { - log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) - return "" - } - if stickySession == nil { - return "" - } - return stickySession.StickySessionCookie -} - -func (listener *SLoadbalancerListener) GetStickySessionCookieTimeout() int { - pool, err := listener.fetchFeaturePool() - if err != nil { - log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) - return 0 - } - stickySession, err := pool.GetStickySession() - if err != nil { - log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) - return 0 - } - if stickySession == nil { - return 0 - } - return stickySession.StickySessionCookieTimeout -} - -func (listener *SLoadbalancerListener) XForwardedForEnabled() bool { - if listener.InsertHeaders.XForwardedFor == "true" { - return true - } - return false -} - -func (listener *SLoadbalancerListener) GzipEnabled() bool { - return false -} - -func (listener *SLoadbalancerListener) GetCertificateId() string { - return "" -} - -func (listener *SLoadbalancerListener) GetTLSCipherPolicy() string { - return listener.TLSCiphers -} - -func (listener *SLoadbalancerListener) HTTP2Enabled() bool { - return false -} - -func (listener *SLoadbalancerListener) fetchLoadbalancerListenerL7Policies() error { - l7policies := []SLoadbalancerL7Policy{} - for i := 0; i < len(listener.L7PolicieIds); i++ { - l7policy, err := listener.region.GetLoadbalancerL7PolicybyId(listener.L7PolicieIds[i].ID) - if err != nil { - return errors.Wrapf(err, "listener.region.GetLoadbalancerL7PolicybyId(%s)", listener.L7PolicieIds[i].ID) - } - l7policies = append(l7policies, *l7policy) - } - listener.l7policies = l7policies - return nil -} - -func (listener *SLoadbalancerListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} - for i := 0; i < len(listener.l7policies); i++ { - for j := 0; j < len(listener.l7policies[i].l7rules); j++ { - iRules = append(iRules, &listener.l7policies[i].l7rules[j]) - } - } - return iRules, nil -} - -func (region *SRegion) DeleteLoadbalancerListener(listenerId string) error { - _, err := region.lbDelete(fmt.Sprintf("/v2/lbaas/listeners/%s", listenerId)) - if err != nil { - return errors.Wrapf(err, `region.lbDelete("/v2/lbaas/listeners/%s")`, listenerId) - } - return nil -} - -func (listener *SLoadbalancerListener) Delete(ctx context.Context) error { - waitLbResStatus(listener, 10*time.Second, 1*time.Minute) - return listener.region.DeleteLoadbalancerListener(listener.ID) -} - -func (listener *SLoadbalancerListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - l7policy, err := listener.region.CreateLoadbalancerL7Policy(listener.ID, rule) - if err != nil { - return nil, errors.Wrapf(err, `listener.region.CreateLoadbalancerL7Policy(%s, rule)`, listener.ID) - } - // async wait - err = waitLbResStatus(l7policy, 10*time.Second, 8*time.Minute) - if err != nil { - return nil, errors.Wrap(err, `waitLbResStatus(l7policy, 10*time.Second, 8*time.Minute)`) - } - - l7rule, err := listener.region.CreateLoadbalancerL7Rule(l7policy.ID, rule) - if err != nil { - return nil, errors.Wrapf(err, `listener.region.CreateLoadbalancerL7Rule(%s, rule)`, l7policy.ID) - } - l7rule.policy = l7policy - // async wait - err = waitLbResStatus(l7rule, 10*time.Second, 8*time.Minute) - if err != nil { - return nil, errors.Wrap(err, `waitLbResStatus(l7rule, 10*time.Second, 8*time.Minute)`) - } - return l7rule, nil -} - -func (listener *SLoadbalancerListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - for i := 0; i < len(listener.l7policies); i++ { - for j := 0; j < len(listener.l7policies[i].l7rules); j++ { - if listener.l7policies[i].l7rules[j].GetId() == ruleId { - return &listener.l7policies[i].l7rules[j], nil - } - } - } - return nil, nil -} - -func (listener *SLoadbalancerListener) fetchLoadbalancerPools() error { - pools := []SLoadbalancerPool{} - if len(listener.DefaultPoolID) > 0 { - defaultPool, err := listener.region.GetLoadbalancerPoolById(listener.DefaultPoolID) - if err != nil { - return errors.Wrapf(err, "listener.region.GetLoadbalancerPoolById(%s)", listener.DefaultPoolID) - } - pools = append(pools, *defaultPool) - } - for i := 0; i < len(listener.l7policies); i++ { - if len(listener.l7policies[i].RedirectPoolID) > 0 { - policyPool, err := listener.region.GetLoadbalancerPoolById(listener.l7policies[i].RedirectPoolID) - if err != nil { - return errors.Wrapf(err, "listener.region.GetLoadbalancerPoolById(%s)", listener.l7policies[i].RedirectPoolID) - } - pools = append(pools, *policyPool) - } - } - listener.pools = pools - return nil -} - -func (listener *SLoadbalancerListener) fetchFeaturePool() (*SLoadbalancerPool, error) { - if len(listener.pools) < 1 { - return nil, fmt.Errorf("can't find pool with healthmonitor") - } - for i := 0; i < len(listener.pools); i++ { - if listener.pools[i].healthmonitor != nil { - return &listener.pools[i], nil - } - } - return &listener.pools[0], nil -} - -func (region *SRegion) UpdateLoadBalancerListenerAdminStateUp(AdminStateUp bool, loadbalancerListenerId string) error { - params := jsonutils.NewDict() - poolParam := jsonutils.NewDict() - poolParam.Add(jsonutils.NewBool(AdminStateUp), "admin_state_up") - params.Add(poolParam, "listener") - _, err := region.lbUpdate(fmt.Sprintf("/v2/lbaas/listeners/%s", loadbalancerListenerId), params) - if err != nil { - return errors.Wrapf(err, `region.lbUpdate(/v2/lbaas/listeners/%s, params)`, loadbalancerListenerId) - } - return nil -} - -func (region *SRegion) UpdateLoadBalancerListener(loadbalancerListenerId string, lblis *cloudprovider.SLoadbalancerListener) error { - type UpdateParams struct { - Listener SLoadbalancerListenerUpdateParams `json:"listener"` - } - params := UpdateParams{} - params.Listener.AdminStateUp = true - params.Listener.DefaultPoolId = lblis.BackendGroupID - - if lblis.ClientIdleTimeout != 0 { - // 毫秒单位 - msClientIdleTimeout := lblis.ClientIdleTimeout * 1000 - params.Listener.TimeoutClientData = &msClientIdleTimeout - } - if lblis.BackendConnectTimeout != 0 { - msBackendConnectTimeout := lblis.BackendConnectTimeout * 1000 - params.Listener.TimeoutMemberConnect = &msBackendConnectTimeout - } - if lblis.BackendIdleTimeout != 0 { - msBackendIdleTimeout := lblis.BackendIdleTimeout * 1000 - params.Listener.TimeoutMemberData = &msBackendIdleTimeout - } - params.Listener.Name = lblis.Name - if lblis.XForwardedFor { - params.Listener.InsertHeaders.XForwardedFor = "true" - } - _, err := region.lbUpdate(fmt.Sprintf("/v2/lbaas/listeners/%s", loadbalancerListenerId), jsonutils.Marshal(params)) - if err != nil { - return errors.Wrapf(err, `region.lbUpdate(/v2/lbaas/listeners/%s, jsonutils.Marshal(params))`, loadbalancerListenerId) - } - return nil -} - -func (listener *SLoadbalancerListener) Start() error { - // ensure listener status - err := waitLbResStatus(listener, 10*time.Second, 8*time.Minute) - if err != nil { - return errors.Wrap(err, ` waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) - } - err = listener.region.UpdateLoadBalancerListenerAdminStateUp(true, listener.ID) - if err != nil { - return errors.Wrapf(err, `listener.region.UpdateLoadBalancerListenerAdminStateUp(true, %s)`, listener.ID) - } - err = waitLbResStatus(listener, 10*time.Second, 8*time.Minute) - if err != nil { - return errors.Wrap(err, `waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) - } - return nil -} - -func (listener *SLoadbalancerListener) Stop() error { - // ensure listener status - err := waitLbResStatus(listener, 10*time.Second, 8*time.Minute) - if err != nil { - return errors.Wrap(err, ` waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) - } - err = listener.region.UpdateLoadBalancerListenerAdminStateUp(false, listener.ID) - if err != nil { - return errors.Wrapf(err, `listener.region.UpdateLoadBalancerListenerAdminStateUp(false,%s)`, listener.ID) - } - err = waitLbResStatus(listener, 10*time.Second, 8*time.Minute) - if err != nil { - return errors.Wrap(err, `waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) - } - return nil -} - -func (listener *SLoadbalancerListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { - // ensure listener status - err := waitLbResStatus(listener, 10*time.Second, 8*time.Minute) - if err != nil { - return errors.Wrap(err, ` waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) - } - err = listener.region.UpdateLoadBalancerListener(listener.ID, lblis) - if err != nil { - return errors.Wrapf(err, `listener.region.UpdateLoadBalancerListener(%s, lblis)`, listener.ID) - } - err = waitLbResStatus(listener, 10*time.Second, 8*time.Minute) - if err != nil { - return errors.Wrap(err, `waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) - } - return nil -} - -func (listener *SLoadbalancerListener) GetProjectId() string { - return listener.ProjectID -} - -func (listener *SLoadbalancerListener) GetClientIdleTimeout() int { - return 0 -} - -func (listener *SLoadbalancerListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/openstack/network.go b/pkg/multicloud/openstack/network.go deleted file mode 100644 index f48ca2ba73..0000000000 --- a/pkg/multicloud/openstack/network.go +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - "net/url" - "strings" - "time" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type AllocationPool struct { - Start string `json:"start"` - End string `json:"end"` -} - -func (p AllocationPool) IsValid() bool { - for _, ip := range []string{p.Start, p.End} { - _, err := netutils.NewIPV4Addr(ip) - if err != nil { - return false - } - } - return true -} - -func (p AllocationPool) Equals(s AllocationPool) bool { - return p.Start == s.Start && p.End == s.End -} - -func (p AllocationPool) Contains(ip string) bool { - start, err := netutils.NewIPV4Addr(p.Start) - if err != nil { - return false - } - end, err := netutils.NewIPV4Addr(p.End) - if err != nil { - return false - } - addr, err := netutils.NewIPV4Addr(ip) - if err != nil { - return false - } - return netutils.NewIPV4AddrRange(start, end).Contains(addr) -} - -type SNextLinks []SNextLink - -func (links SNextLinks) GetNextMark() string { - for _, link := range links { - if link.Rel == "next" && len(link.Href) > 0 { - href, err := url.Parse(link.Href) - if err != nil { - log.Errorf("failed parse next link %s error: %v", link.Href, err) - continue - } - marker := href.Query().Get("marker") - if len(marker) > 0 { - return marker - } - } - } - return "" -} - -type SNextLink struct { - Href string - Rel string -} - -type SNetwork struct { - multicloud.SResourceBase - multicloud.OpenStackTags - wire *SWire - - Name string - EnableDhcp bool - NetworkId string - SegmentId string - ProjectId string - TenantId string - DnsNameservers []string - AllocationPools []AllocationPool - HostRoutes []string - IpVersion int - GatewayIP string - CIDR string - Id string - CreatedAt time.Time - Description string - Ipv6AddressMode string - Ipv6RaMode string - RevisionNumber int - ServiceTypes []string - SubnetpoolId string - Tags []string - UpdatedAt time.Time -} - -func (network *SNetwork) GetId() string { - return network.Id -} - -func (network *SNetwork) GetName() string { - if len(network.Name) > 0 { - return network.Name - } - return network.Id -} - -func (network *SNetwork) GetGlobalId() string { - if len(network.AllocationPools) > 0 { - return fmt.Sprintf("%s|%s-%s", network.Id, network.AllocationPools[0].Start, network.AllocationPools[0].End) - } - return network.Id -} - -func (network *SNetwork) IsEmulated() bool { - return false -} - -func (network *SNetwork) GetStatus() string { - return api.NETWORK_STATUS_AVAILABLE -} - -func (network *SNetwork) Delete() error { - nw, err := network.wire.vpc.region.GetNetwork(network.Id) - if err != nil { - return errors.Wrapf(err, "GetNetwork(%s)", network.Id) - } - if len(nw.AllocationPools) <= 1 || len(network.AllocationPools) == 0 { - return network.wire.vpc.region.DeleteNetwork(network.Id) - } - pools := []AllocationPool{} - for i := range nw.AllocationPools { - if nw.AllocationPools[i].Equals(network.AllocationPools[0]) { - continue - } - pools = append(pools, nw.AllocationPools[i]) - } - - params := map[string]interface{}{ - "subnet": map[string]interface{}{ - "allocation_pools": pools, - }, - } - resource := fmt.Sprintf("/v2.0/subnets/%s", network.Id) - _, err = network.wire.vpc.region.vpcUpdate(resource, jsonutils.Marshal(params)) - return err -} - -func (region *SRegion) DeleteNetwork(networkId string) error { - resource := fmt.Sprintf("/v2.0/subnets/%s", networkId) - _, err := region.vpcDelete(resource) - return err -} - -func (network *SNetwork) GetIWire() cloudprovider.ICloudWire { - return network.wire -} - -func (network *SNetwork) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (network *SNetwork) GetGateway() string { - return network.GatewayIP -} - -func (network *SNetwork) GetIpStart() string { - if len(network.AllocationPools) >= 1 { - return network.AllocationPools[0].Start - } - return "" -} - -func (network *SNetwork) GetIpEnd() string { - if len(network.AllocationPools) >= 1 { - return network.AllocationPools[0].End - } - return "" -} - -func (network *SNetwork) GetIPRange() netutils.IPV4AddrRange { - start, _ := netutils.NewIPV4Addr(network.GetIpStart()) - end, _ := netutils.NewIPV4Addr(network.GetIpEnd()) - return netutils.NewIPV4AddrRange(start, end) -} - -func (network *SNetwork) Contains(ipAddr string) bool { - for _, pool := range network.AllocationPools { - if pool.Contains(ipAddr) { - return true - } - } - return false -} - -func (network *SNetwork) GetIpMask() int8 { - pref, _ := netutils.NewIPV4Prefix(network.CIDR) - return pref.MaskLen -} - -func (network *SNetwork) GetIsPublic() bool { - return network.wire.vpc.Shared -} - -func (network *SNetwork) GetPublicScope() rbacutils.TRbacScope { - if network.wire.vpc.Shared { - return rbacutils.ScopeSystem - } - return rbacutils.ScopeNone -} - -func (network *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func getNetworkId(networkId string) (AllocationPool, string) { - pool := AllocationPool{} - if !strings.Contains(networkId, "|") { - return pool, networkId - } - info := strings.Split(networkId, "|") - networkId = info[0] - ipInfo := strings.Split(info[1], "-") - pool.Start, pool.End = ipInfo[0], ipInfo[1] - return pool, networkId -} - -func (region *SRegion) GetNetwork(networkId string) (*SNetwork, error) { - var pool AllocationPool - pool, networkId = getNetworkId(networkId) - resource := fmt.Sprintf("/v2.0/subnets/%s", networkId) - resp, err := region.vpcGet(resource) - if err != nil { - return nil, err - } - network := &SNetwork{} - err = resp.Unmarshal(network, "subnet") - if err != nil { - return nil, err - } - if len(pool.Start) == 0 && len(pool.End) == 0 { - return network, nil - } - for _, _pool := range network.AllocationPools { - if _pool.Equals(pool) { - network.AllocationPools = []AllocationPool{pool} - return network, nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", networkId) -} - -func (region *SRegion) GetNetworks(vpcId string) ([]SNetwork, error) { - resource := "/v2.0/subnets" - networks := []SNetwork{} - query := url.Values{} - if len(vpcId) > 0 { - query.Set("network_id", vpcId) - } - for { - resp, err := region.vpcList(resource, query) - if err != nil { - return nil, errors.Wrap(err, "vpcList") - } - - part := struct { - Subnets []SNetwork - SubnetsLinks SNextLinks - }{} - - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - - networks = append(networks, part.Subnets...) - marker := part.SubnetsLinks.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return networks, nil -} - -func (network *SNetwork) Refresh() error { - _network, err := network.wire.vpc.region.GetNetwork(network.Id) - if err != nil { - return err - } - return jsonutils.Update(network, _network) -} - -func (region *SRegion) CreateNetwork(vpcId string, projectId, name string, cidr string, desc string) (*SNetwork, error) { - params := map[string]map[string]interface{}{ - "subnet": { - "name": name, - "network_id": vpcId, - "cidr": cidr, - "description": desc, - "ip_version": 4, - }, - } - if len(projectId) > 0 { - params["subnet"]["project_id"] = projectId - } - resp, err := region.vpcPost("/v2.0/subnets", params) - if err != nil { - return nil, errors.Wrap(err, "vpcPost") - } - network := &SNetwork{} - err = resp.Unmarshal(network, "subnet") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return network, nil -} - -func (network *SNetwork) GetProjectId() string { - return network.TenantId -} diff --git a/pkg/multicloud/openstack/port.go b/pkg/multicloud/openstack/port.go deleted file mode 100644 index 85820c59cb..0000000000 --- a/pkg/multicloud/openstack/port.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "net/url" - "strings" - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type DnsAssignment struct { - Hostname string - IpAddress string - Fqdn string -} - -type ExtraDhcpOpt struct { - OptValue string - IpVersion int - OptName string -} - -type SFixedIP struct { - port *SPort - - IpAddress string - SubnetID string -} - -func (fixip *SFixedIP) GetGlobalId() string { - return fixip.IpAddress -} - -func (fixip *SFixedIP) GetIP() string { - return fixip.IpAddress -} - -func (fixip *SFixedIP) GetINetworkId() string { - network, err := fixip.port.region.GetNetwork(fixip.SubnetID) - if err != nil { - return "" - } - for _, pool := range network.AllocationPools { - if pool.Contains(fixip.IpAddress) { - network.AllocationPools = []AllocationPool{pool} - return network.GetGlobalId() - } - } - return "" -} - -func (fixip *SFixedIP) IsPrimary() bool { - return true -} - -type SPort struct { - multicloud.SNetworkInterfaceBase - multicloud.OpenStackTags - region *SRegion - AdminStateUp bool - AllowedAddressPairs []string - CreatedAt time.Time - DataPlaneStatus string - Description string - DeviceID string - DeviceOwner string - DnsAssignment []DnsAssignment - DnsDomain string - DnsName string - ExtraDhcpOpts []ExtraDhcpOpt - FixedIps []SFixedIP - ID string - IpAllocation string - MacAddress string - Name string - NetworkID string - ProjectID string - RevisionNumber int - SecurityGroups []string - Status string - Tags []string - TenantID string - UpdatedAt time.Time - QosPolicyID string - PortSecurityEnabled bool - UplinkStatusPropagation bool -} - -func (port *SPort) GetName() string { - if len(port.Name) > 0 { - return port.Name - } - return port.ID -} - -func (port *SPort) GetId() string { - return port.ID -} - -func (port *SPort) GetGlobalId() string { - return port.ID -} - -func (port *SPort) GetMacAddress() string { - return port.MacAddress -} - -func (port *SPort) GetAssociateType() string { - switch port.DeviceOwner { - case "compute:nova": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER - case "network:router_gateway", "network:dhcp", "network:router_interface": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_RESERVED - } - return port.DeviceOwner -} - -func (port *SPort) GetAssociateId() string { - return port.DeviceID -} - -func (port *SPort) GetStatus() string { - switch port.Status { - case "ACTIVE", "DOWN": - return api.NETWORK_INTERFACE_STATUS_AVAILABLE - case "BUILD": - return api.NETWORK_INTERFACE_STATUS_CREATING - } - return port.Status -} - -func (port *SPort) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { - address := []cloudprovider.ICloudInterfaceAddress{} - for i := 0; i < len(port.FixedIps); i++ { - port.FixedIps[i].port = port - address = append(address, &port.FixedIps[i]) - } - return address, nil -} - -func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { - ports, err := region.GetPorts("", "") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNetworkInterface{} - for i := 0; i < len(ports); i++ { - if strings.HasPrefix(ports[i].DeviceOwner, "compute:") || ports[i].DeviceOwner == "network:floatingip" { - continue - } - ports[i].region = region - ret = append(ret, &ports[i]) - } - return ret, nil -} - -func (region *SRegion) GetPort(portId string) (*SPort, error) { - resource := "/v2.0/ports/" + portId - resp, err := region.vpcGet(resource) - if err != nil { - return nil, err - } - port := &SPort{} - err = resp.Unmarshal(port, "port") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return port, nil -} - -func (region *SRegion) GetPorts(macAddress, deviceId string) ([]SPort, error) { - resource, ports := "/v2.0/ports", []SPort{} - query := url.Values{} - if len(macAddress) > 0 { - query.Set("mac_address", macAddress) - } - if len(deviceId) > 0 { - query.Set("device_id", deviceId) - } - for { - resp, err := region.vpcList(resource, query) - if err != nil { - return nil, errors.Wrap(err, "vpcList") - } - part := struct { - Ports []SPort - PortsLinks SNextLinks - }{} - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - ports = append(ports, part.Ports...) - marker := part.PortsLinks.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return ports, nil -} diff --git a/pkg/multicloud/openstack/project.go b/pkg/multicloud/openstack/project.go deleted file mode 100644 index a4eff5eb5a..0000000000 --- a/pkg/multicloud/openstack/project.go +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - "net/url" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -type SProject struct { - multicloud.SProjectBase - multicloud.OpenStackTags - client *SOpenStackClient - Description string - Enabled bool - Id string - Name string -} - -func (p *SProject) GetId() string { - return p.Id -} - -func (p *SProject) GetGlobalId() string { - return p.GetId() -} - -func (p *SProject) GetName() string { - return p.Name -} - -func (p *SProject) GetStatus() string { - if !p.Enabled { - return api.EXTERNAL_PROJECT_STATUS_UNKNOWN - } - _, err := p.getToken() - if err != nil { - log.Errorf("get project %s token error: %v %T", p.Name, err, err) - return api.EXTERNAL_PROJECT_STATUS_UNKNOWN - } - return api.EXTERNAL_PROJECT_STATUS_AVAILABLE -} - -func (p *SProject) getToken() (mcclient.TokenCredential, error) { - return p.client.getProjectToken(p.Id, p.Name) -} - -func (p *SProject) IsEmulated() bool { - return false -} - -func (p *SProject) Refresh() error { - return nil -} - -type SProjectLinks struct { - Next string - Previous string - Self string -} - -func (link SProjectLinks) GetNextMark() string { - if len(link.Next) == 0 || link.Next == "null" { - return "" - } - next, err := url.Parse(link.Next) - if err != nil { - log.Errorf("parse next link %s error: %v", link.Next, err) - return "" - } - return next.Query().Get("marker") -} - -func (cli *SOpenStackClient) GetProjects() ([]SProject, error) { - resource := "/v3/projects" - projects := []SProject{} - query := url.Values{} - for { - resp, err := cli.iamRequest("", httputils.GET, resource, query, nil) - if err != nil { - return nil, errors.Wrap(err, "iamRequest") - } - part := struct { - Projects []SProject - Links SProjectLinks - }{} - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "iamRequest") - } - projects = append(projects, part.Projects...) - marker := part.Links.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return projects, nil -} - -func (cli *SOpenStackClient) DeleteProject(projectId string) error { - resource := fmt.Sprintf("/v3/projects/%s", projectId) - _, err := cli.iamRequest(cli.getDefaultRegionName(), httputils.DELETE, resource, nil, nil) - return err -} diff --git a/pkg/multicloud/openstack/provider/doc.go b/pkg/multicloud/openstack/provider/doc.go deleted file mode 100644 index 256bee2b15..0000000000 --- a/pkg/multicloud/openstack/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/openstack/provider" diff --git a/pkg/multicloud/openstack/provider/provider.go b/pkg/multicloud/openstack/provider/provider.go deleted file mode 100644 index 406d91d809..0000000000 --- a/pkg/multicloud/openstack/provider/provider.go +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/openstack" -) - -type SOpenStackProviderFactory struct { - cloudprovider.SPrivateCloudBaseProviderFactory -} - -var EndpointTypes = []string{"admin", "internal", "public"} - -func (self *SOpenStackProviderFactory) GetId() string { - return openstack.CLOUD_PROVIDER_OPENSTACK -} - -func (self *SOpenStackProviderFactory) GetName() string { - return openstack.CLOUD_PROVIDER_OPENSTACK -} - -func (self *SOpenStackProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.ProjectName) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "project_name") - } - if len(input.Username) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "username") - } - if len(input.Password) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "password") - } - if len(input.AuthUrl) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "auth_url") - } - - output.Account = fmt.Sprintf("%s/%s", input.ProjectName, input.Username) - if len(input.DomainName) > 0 { - output.Account = fmt.Sprintf("%s/%s", output.Account, input.DomainName) - } - - output.Secret = input.Password - output.AccessUrl = input.AuthUrl - return output, nil -} - -func (self *SOpenStackProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.ProjectName) == 0 { - accountInfo := strings.Split(cloudaccount, "/") - if len(accountInfo) < 2 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "project_name") - } - input.ProjectName = accountInfo[0] - } - if len(input.Username) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "username") - } - if len(input.Password) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "password") - } - - _account := fmt.Sprintf("%s/%s", input.ProjectName, input.Username) - if len(input.DomainName) == 0 { - if accountInfo := strings.Split(cloudaccount, "/"); len(accountInfo) == 3 { - input.DomainName = accountInfo[2] - } - } - - if len(input.DomainName) > 0 { - _account = fmt.Sprintf("%s/%s", _account, input.DomainName) - } - - output = cloudprovider.SCloudaccount{ - Account: _account, - Secret: input.Password, - } - return output, nil -} - -func (self *SOpenStackProviderFactory) IsNeedForceAutoCreateProject() bool { - return true -} - -func (self *SOpenStackProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - accountInfo := strings.Split(cfg.Account, "/") - if len(accountInfo) < 2 { - return nil, fmt.Errorf("Missing username or project name %s", cfg.Account) - } - project, username, endpointType, domainName, projectDomainName := accountInfo[0], accountInfo[1], "internal", "Default", "Default" - if len(accountInfo) == 3 { - domainName, projectDomainName = accountInfo[2], accountInfo[2] - } - client, err := openstack.NewOpenStackClient( - openstack.NewOpenstackClientConfig( - cfg.URL, - username, - cfg.Secret, - project, - projectDomainName, - ). - DomainName(domainName). - EndpointType(endpointType). - CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SOpenStackProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SOpenStackProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - accountInfo := strings.Split(info.Account, "/") - if len(accountInfo) < 2 { - return nil, fmt.Errorf("Missing username or project name %s", info.Account) - } - project, username, endpointType, domainName, projectDomainName := accountInfo[0], accountInfo[1], "internal", "Default", "Default" - if len(accountInfo) == 3 { - domainName, projectDomainName = accountInfo[2], accountInfo[2] - } - - return map[string]string{ - "OPENSTACK_AUTH_URL": info.Url, - "OPENSTACK_USERNAME": username, - "OPENSTACK_PASSWORD": info.Secret, - "OPENSTACK_PROJECT": project, - "OPENSTACK_ENDPOINT_TYPE": endpointType, - "OPENSTACK_DOMAIN_NAME": domainName, - "OPENSTACK_PROJECT_DOMAIN": projectDomainName, - "OPENSTACK_REGION_ID": openstack.OPENSTACK_DEFAULT_REGION, - }, nil -} - -func init() { - factory := SOpenStackProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SOpenStackProvider struct { - cloudprovider.SBaseProvider - client *openstack.SOpenStackClient -} - -func (self *SOpenStackProvider) GetVersion() string { - return "" -} - -func (self *SOpenStackProvider) GetSysInfo() (jsonutils.JSONObject, error) { - return jsonutils.NewDict(), nil -} - -func (self *SOpenStackProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SOpenStackProvider) GetAccountId() string { - return "" -} - -func (self *SOpenStackProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SOpenStackProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(extId) -} - -func (self *SOpenStackProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, cloudprovider.ErrNotSupported -} - -func (self *SOpenStackProvider) GetCloudRegionExternalIdPrefix() string { - return self.client.GetCloudRegionExternalIdPrefix() -} - -func (self *SOpenStackProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SOpenStackProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return self.client.CreateIProject(name) -} - -func (self *SOpenStackProvider) GetStorageClasses(regionId string) []string { - return nil -} - -func (self *SOpenStackProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (self *SOpenStackProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (self *SOpenStackProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} diff --git a/pkg/multicloud/openstack/quota.go b/pkg/multicloud/openstack/quota.go deleted file mode 100644 index 60791bf60a..0000000000 --- a/pkg/multicloud/openstack/quota.go +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type QuotaDetail struct { - Reserved int - Limit int - InUse int -} - -type QuotaSet struct { - InjectedFileContentBytes QuotaDetail - MetadataItems QuotaDetail - ServerGroupMembers QuotaDetail - ServerGroups QuotaDetail - Ram QuotaDetail - FloatingIps QuotaDetail - KeyPairs QuotaDetail - Id string - Instances QuotaDetail - SecurityGroupRules QuotaDetail - InjectedFiles QuotaDetail - Cores QuotaDetail - FixedIps QuotaDetail - InjectedFilePathBytes QuotaDetail - SecurityGroups QuotaDetail -} - -type SQuota struct { - Cores int - Instances int - KeyPairs int - FixedIps int - MetadataItems int - Ram int - ServerGroups int - ServerGroupMembers int - InjectedFileContentBytes int - InjectedFilePathBytes int - InjectedFiles int - Floatingips int - Networks int - Port int - RbacPolicy int - Router int - SecurityGroups int - SecurityGroupRules int -} - -func (region *SRegion) GetQuota() (*QuotaSet, error) { - resource := fmt.Sprintf("/os-quota-sets/%s/detail", region.client.tokenCredential.GetTenantId()) - resp, err := region.ecsGet(resource) - if err != nil { - return nil, errors.Wrap(err, "ecsGet") - } - quota := &QuotaSet{} - return quota, resp.Unmarshal(quota, "quota_set") -} - -func (region *SRegion) SetQuota(quota *SQuota) error { - params := map[string]map[string]interface{}{ - "quota_set": { - "force": "True", - }, - } - - if quota.Floatingips > 0 { - params["quota_set"]["floating_ips"] = quota.Floatingips - } - - if quota.SecurityGroups > 0 { - params["quota_set"]["security_group"] = quota.SecurityGroups - } - - if quota.SecurityGroupRules > 0 { - params["quota_set"]["security_group_rules"] = quota.SecurityGroupRules - } - - if quota.FixedIps > 0 { - params["quota_set"]["fixed_ips"] = quota.FixedIps - } - - if quota.Networks > 0 { - params["quota_set"]["networks"] = quota.Networks - } - - resource := "/os-quota-sets/" + region.client.tokenCredential.GetTenantId() - _, err := region.ecsUpdate(resource, params) - return err -} - -type IQuota struct { - Name string - Limit int - InUse int -} - -func (iq *IQuota) GetGlobalId() string { - return iq.Name -} - -func (iq *IQuota) GetName() string { - return iq.Name -} - -func (iq *IQuota) GetDesc() string { - return "" -} - -func (iq *IQuota) GetQuotaType() string { - return iq.Name -} - -func (iq *IQuota) GetMaxQuotaCount() int { - return iq.Limit -} - -func (iq *IQuota) GetCurrentQuotaUsedCount() int { - return iq.InUse -} - -func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { - quota, err := region.GetQuota() - if err != nil { - return nil, errors.Wrap(err, "GetQuota") - } - - ret := []cloudprovider.ICloudQuota{} - - ret = append(ret, &IQuota{Name: "injected_file_content_bytes", Limit: quota.InjectedFileContentBytes.Limit, InUse: quota.InjectedFileContentBytes.InUse}) - ret = append(ret, &IQuota{Name: "metadata_items", Limit: quota.MetadataItems.Limit, InUse: quota.MetadataItems.InUse}) - ret = append(ret, &IQuota{Name: "server_group_members", Limit: quota.ServerGroupMembers.Limit, InUse: quota.ServerGroupMembers.InUse}) - ret = append(ret, &IQuota{Name: "server_groups", Limit: quota.ServerGroups.Limit, InUse: quota.ServerGroups.InUse}) - ret = append(ret, &IQuota{Name: "ram", Limit: quota.Ram.Limit, InUse: quota.Ram.InUse}) - ret = append(ret, &IQuota{Name: "floating_ips", Limit: quota.FloatingIps.Limit, InUse: quota.FloatingIps.InUse}) - ret = append(ret, &IQuota{Name: "key_pairs", Limit: quota.KeyPairs.Limit, InUse: quota.KeyPairs.InUse}) - ret = append(ret, &IQuota{Name: "instances", Limit: quota.Instances.Limit, InUse: quota.Instances.InUse}) - ret = append(ret, &IQuota{Name: "security_group_rules", Limit: quota.SecurityGroupRules.Limit, InUse: quota.SecurityGroupRules.InUse}) - ret = append(ret, &IQuota{Name: "injected_files", Limit: quota.InjectedFiles.Limit, InUse: quota.InjectedFiles.InUse}) - ret = append(ret, &IQuota{Name: "cores", Limit: quota.Cores.Limit, InUse: quota.Cores.InUse}) - ret = append(ret, &IQuota{Name: "fixed_ips", Limit: quota.FixedIps.Limit, InUse: quota.FixedIps.InUse}) - ret = append(ret, &IQuota{Name: "injected_file_path_bytes", Limit: quota.InjectedFilePathBytes.Limit, InUse: quota.InjectedFilePathBytes.InUse}) - ret = append(ret, &IQuota{Name: "security_groups", Limit: quota.SecurityGroups.Limit, InUse: quota.SecurityGroups.InUse}) - return ret, nil -} diff --git a/pkg/multicloud/openstack/region.go b/pkg/multicloud/openstack/region.go deleted file mode 100644 index 630de15212..0000000000 --- a/pkg/multicloud/openstack/region.go +++ /dev/null @@ -1,620 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - "io" - "net/url" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -type SRegion struct { - multicloud.SRegion - - client *SOpenStackClient - - Name string - - vpcs []SVpc - - storageCache *SStoragecache - routers []SRouter -} - -func (region *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - backendGroups := []cloudprovider.ICloudLoadbalancerBackendGroup{} - pools, err := region.GetLoadbalancerPools() - if err != nil { - return backendGroups, errors.Wrap(err, "region.GetLoadbalancerPools()") - } - for i := 0; i < len(pools); i++ { - backendGroups = append(backendGroups, &pools[i]) - } - return backendGroups, nil -} - -func (region *SRegion) GetClient() *SOpenStackClient { - return region.client -} - -func (region *SRegion) GetId() string { - return region.Name -} - -func (region *SRegion) GetName() string { - return fmt.Sprintf("%s-%s", region.client.cpcfg.Name, region.Name) -} - -func (region *SRegion) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(region.GetName()).CN(region.GetName()) - return table -} - -func (region *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s/%s", CLOUD_PROVIDER_OPENSTACK, region.client.cpcfg.Id, region.Name) -} - -func (region *SRegion) IsEmulated() bool { - return false -} - -func (region *SRegion) GetProvider() string { - return CLOUD_PROVIDER_OPENSTACK -} - -func (region *SRegion) GetCloudEnv() string { - return "" -} - -func (region *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - return cloudprovider.SGeographicInfo{} -} - -func (region *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (region *SRegion) Refresh() error { - // do nothing - return nil -} - -func (region *SRegion) GetMaxVersion(service string) (string, error) { - return region.client.GetMaxVersion(region.Name, service) -} - -func (region *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - vpc, err := region.CreateVpc(opts.NAME, opts.Desc) - if err != nil { - return nil, errors.Wrap(err, "CreateVp") - } - return vpc, nil -} - -func (region *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - izones, err := region.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i++ { - ihost, err := izones[i].GetIHostById(id) - if err == nil { - return ihost, nil - } else if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - izones, err := region.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i++ { - istore, err := izones[i].GetIStorageById(id) - if err == nil { - return istore, nil - } else if errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - iHosts := []cloudprovider.ICloudHost{} - izones, err := region.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i++ { - iZoneHost, err := izones[i].GetIHosts() - if err != nil { - return nil, err - } - iHosts = append(iHosts, iZoneHost...) - } - return iHosts, nil -} - -func (region *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - izones, err := region.GetIZones() - if err != nil { - return nil, err - } - iStorages := []cloudprovider.ICloudStorage{} - for i := 0; i < len(izones); i++ { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStorages = append(iStorages, iZoneStores...) - } - return iStorages, nil -} - -func (region *SRegion) getStoragecache() *SStoragecache { - if region.storageCache == nil { - region.storageCache = &SStoragecache{region: region} - } - return region.storageCache -} - -func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - storageCache := region.getStoragecache() - if storageCache.GetGlobalId() == id { - return region.storageCache, nil - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storageCache := region.getStoragecache() - return []cloudprovider.ICloudStoragecache{storageCache}, nil -} - -func (region *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - instance, err := region.GetInstance(id) - if err != nil { - return nil, errors.Wrapf(err, "GetInstance(%s)", id) - } - hosts, err := region.GetIHosts() - if err != nil { - return nil, err - } - for i := range hosts { - host := hosts[i].(*SHypervisor) - if instance.HypervisorHostname == host.HypervisorHostname { - instance.host = host - } - } - return instance, nil -} - -func (region *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - disk, err := region.GetDisk(id) - if err != nil { - _, err := region.GetInstance(id) - if err == nil { - return &SNovaDisk{region: region, instanceId: id}, nil - } - return nil, errors.Wrapf(err, "GetDisk(%s)", id) - } - return disk, nil -} - -func (region *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - vpc, err := region.GetVpc(id) - if err != nil { - return nil, errors.Wrapf(err, "GetVpc(%s)", id) - } - return vpc, nil -} - -func (region *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := region.GetIZones() - if err != nil { - return nil, errors.Wrap(err, "GetIZones") - } - for i := 0; i < len(izones); i++ { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetZones() ([]SZone, error) { - zones, err := region.getZones() - if err != nil { - return nil, errors.Wrap(err, "getZones") - } - ret := []SZone{} - for i := 0; i < len(zones); i++ { - if zones[i].ZoneName == "internal" { - continue - } - zones[i].region = region - ret = append(ret, zones[i]) - } - return ret, nil -} - -func (region *SRegion) fetchVpcs() error { - if len(region.vpcs) > 0 { - return nil - } - var err error - region.vpcs, err = region.GetVpcs("") - if err != nil { - return errors.Wrap(err, "GetVpcs") - } - return nil -} - -func (region *SRegion) ecsList(resource string, query url.Values) (jsonutils.JSONObject, error) { - return region.client.ecsRequest(region.Name, httputils.GET, resource, query, nil) -} - -func (region *SRegion) ecsGet(resource string) (jsonutils.JSONObject, error) { - return region.client.ecsRequest(region.Name, httputils.GET, resource, nil, nil) -} - -func (region *SRegion) ecsUpdate(resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.ecsRequest(region.Name, httputils.PUT, resource, nil, params) -} - -func (region *SRegion) ecsPost(resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.ecsRequest(region.Name, httputils.POST, resource, nil, params) -} - -func (region *SRegion) ecsDo(projectId, resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.ecsDo(projectId, region.Name, resource, params) -} - -func (region *SRegion) ecsDelete(resource string) (jsonutils.JSONObject, error) { - return region.client.ecsRequest(region.Name, httputils.DELETE, resource, nil, nil) -} - -func (region *SRegion) ecsCreate(projectId, resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.ecsCreate(projectId, region.Name, resource, params) -} - -func (region *SRegion) vpcList(resource string, query url.Values) (jsonutils.JSONObject, error) { - return region.client.vpcRequest(region.Name, httputils.GET, resource, query, nil) -} - -func (region *SRegion) vpcGet(resource string) (jsonutils.JSONObject, error) { - return region.client.vpcRequest(region.Name, httputils.GET, resource, nil, nil) -} - -func (region *SRegion) vpcUpdate(resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.vpcRequest(region.Name, httputils.PUT, resource, nil, params) -} - -func (region *SRegion) vpcPost(resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.vpcRequest(region.Name, httputils.POST, resource, nil, params) -} - -func (region *SRegion) vpcDelete(resource string) (jsonutils.JSONObject, error) { - return region.client.vpcRequest(region.Name, httputils.DELETE, resource, nil, nil) -} - -func (region *SRegion) imageList(resource string, query url.Values) (jsonutils.JSONObject, error) { - return region.client.imageRequest(region.Name, httputils.GET, resource, query, nil) -} - -func (region *SRegion) imageGet(resource string) (jsonutils.JSONObject, error) { - return region.client.imageRequest(region.Name, httputils.GET, resource, nil, nil) -} - -func (region *SRegion) imagePost(resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.imageRequest(region.Name, httputils.POST, resource, nil, params) -} - -func (region *SRegion) imageDelete(resource string) (jsonutils.JSONObject, error) { - return region.client.imageRequest(region.Name, httputils.DELETE, resource, nil, nil) -} - -func (region *SRegion) imageUpload(url string, size int64, body io.Reader, callback func(progress float32)) error { - resp, err := region.client.imageUpload(region.Name, url, size, body, callback) - _, _, err = httputils.ParseResponse("", resp, err, region.client.debug) - return err -} - -// Block Storage -func (region *SRegion) bsList(resource string, query url.Values) (jsonutils.JSONObject, error) { - return region.client.bsRequest(region.Name, httputils.GET, resource, query, nil) -} - -func (region *SRegion) bsGet(resource string) (jsonutils.JSONObject, error) { - return region.client.bsRequest(region.Name, httputils.GET, resource, nil, nil) -} - -func (region *SRegion) bsUpdate(resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.bsRequest(region.Name, httputils.PUT, resource, nil, params) -} - -func (region *SRegion) bsPost(resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.bsRequest(region.Name, httputils.POST, resource, nil, params) -} - -func (region *SRegion) bsDelete(resource string) (jsonutils.JSONObject, error) { - return region.client.bsRequest(region.Name, httputils.DELETE, resource, nil, nil) -} - -func (region *SRegion) bsCreate(projectId, resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.bsCreate(projectId, region.Name, resource, params) -} - -//loadbalancer - -func (region *SRegion) lbList(resource string, query url.Values) (jsonutils.JSONObject, error) { - return region.client.lbRequest(region.Name, httputils.GET, resource, query, nil) -} - -func (region *SRegion) lbGet(resource string) (jsonutils.JSONObject, error) { - return region.client.lbRequest(region.Name, httputils.GET, resource, nil, nil) -} - -func (region *SRegion) lbUpdate(resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.lbRequest(region.Name, httputils.PUT, resource, nil, params) -} - -func (region *SRegion) lbPost(resource string, params interface{}) (jsonutils.JSONObject, error) { - return region.client.lbRequest(region.Name, httputils.POST, resource, nil, params) -} - -func (region *SRegion) lbDelete(resource string) (jsonutils.JSONObject, error) { - return region.client.lbRequest(region.Name, httputils.DELETE, resource, nil, nil) -} - -func (region *SRegion) ProjectId() string { - return region.client.tokenCredential.GetProjectId() -} - -func (region *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - zones, err := region.GetZones() - if err != nil { - return nil, errors.Wrapf(err, "GetZones") - } - ret := []cloudprovider.ICloudZone{} - for i := range zones { - ret = append(ret, &zones[i]) - } - return ret, nil -} - -func (region *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - err := region.fetchVpcs() - if err != nil { - return nil, errors.Wrap(err, "fetchVpcs") - } - ivpcs := []cloudprovider.ICloudVpc{} - for i := range region.vpcs { - region.vpcs[i].region = region - ivpcs = append(ivpcs, ®ion.vpcs[i]) - } - return ivpcs, nil -} - -func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, err := region.GetEips("") - if err != nil { - return nil, err - } - ieips := []cloudprovider.ICloudEIP{} - for i := 0; i < len(eips); i++ { - eips[i].region = region - ieips = append(ieips, &eips[i]) - } - return ieips, nil -} - -func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - network, err := region.GetNetwork(eip.NetworkExternalId) - if err != nil { - return nil, errors.Wrapf(err, "GetNetwork(%s)", eip.NetworkExternalId) - } - ieip, err := region.CreateEip(network.NetworkId, eip.NetworkExternalId, eip.IP, eip.ProjectId) - if err != nil { - return nil, errors.Wrap(err, "CreateEip") - } - return ieip, nil -} - -func (region *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { - return region.GetEip(eipId) -} - -func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - loadbalancers := []cloudprovider.ICloudLoadbalancer{} - sloadbalancers, err := region.GetLoadbalancers() - if err != nil { - return nil, errors.Wrap(err, "region.GetLoadbalancers()") - } - for i := 0; i < len(sloadbalancers); i++ { - loadbalancers = append(loadbalancers, &sloadbalancers[i]) - } - return loadbalancers, nil -} - -func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { - sloadbalancer, err := region.GetLoadbalancerbyId(loadbalancerId) - if err != nil { - return nil, errors.Wrapf(err, "region.GetLoadbalancerbyId(%s)", loadbalancerId) - } - return sloadbalancer, nil -} - -func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { - return region.GetLoadbalancerAclDetail(aclId) -} - -func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { - iloadbalancerAcls := []cloudprovider.ICloudLoadbalancerAcl{} - acls, err := region.GetLoadBalancerAcls() - if err != nil { - return nil, errors.Wrap(err, "region.GetLoadBalancerAcls") - } - for i := 0; i < len(acls); i++ { - iloadbalancerAcls = append(iloadbalancerAcls, &acls[i]) - } - return iloadbalancerAcls, nil -} - -func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - sloadbalancer, err := region.CreateLoadBalancer(loadbalancer) - if err != nil { - return nil, errors.Wrap(err, "region.CreateLoadBalancer") - } - return sloadbalancer, nil -} - -func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - sacl, err := region.CreateLoadBalancerAcl(acl) - if err != nil { - return nil, errors.Wrap(err, "region.CreateLoadBalancerAcl(acl)") - } - err = cloudprovider.WaitMultiStatus(sacl.listener, []string{api.LB_STATUS_ENABLED, api.LB_STATUS_UNKNOWN}, 10*time.Second, 8*time.Minute) - if err != nil { - return nil, errors.Wrap(err, "cloudprovider.WaitMultiStatus") - } - if sacl.listener.GetStatus() == api.LB_STATUS_UNKNOWN { - return nil, errors.Wrap(fmt.Errorf("status error"), "check status") - } - return sacl, nil -} - -func (region *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { - flavors, err := region.GetFlavors() - if err != nil { - return nil, err - } - iskus := make([]cloudprovider.ICloudSku, len(flavors)) - for i := 0; i < len(flavors); i++ { - flavors[i].region = region - iskus[i] = &flavors[i] - } - return iskus, nil -} - -func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) CreateIBucket(name string, storageClassStr string, acl string) error { - return cloudprovider.ErrNotImplemented -} - -func (region *SRegion) DeleteIBucket(name string) error { - return cloudprovider.ErrNotImplemented -} - -func (region *SRegion) IBucketExist(name string) (bool, error) { - return false, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - return region.GetSecurityGroup(secgroupId) -} - -func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := region.GetSecurityGroups(opts.ProjectId, opts.Name) - if err != nil { - return nil, err - } - if len(secgroups) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(secgroups) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - secgroups[0].region = region - return &secgroups[0], nil -} - -func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - return region.CreateSecurityGroup(conf.ProjectId, conf.Name, conf.Desc) -} - -func (region *SRegion) GetCapabilities() []string { - return region.client.GetCapabilities() -} - -func (region *SRegion) GetRouters() ([]SRouter, error) { - resource := "/v2.0/routers" - resp, err := region.vpcList(resource, nil) - if err != nil { - return nil, errors.Wrap(err, "vpcList.routes") - } - routers := []SRouter{} - err = resp.Unmarshal(&routers, "routers") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - for i := 0; i < len(routers); i++ { - ports, err := region.GetPorts("", routers[i].Id) - if err != nil { - return nil, errors.Wrap(err, "vpc.region.GetPortsByDeviceId") - } - routers[i].ports = ports - } - return routers, nil -} - -func (region *SRegion) fetchrouters() error { - if len(region.routers) > 0 { - return nil - } - routers, err := region.GetRouters() - if err != nil { - return errors.Wrap(err, "region.GetRouters()") - } - region.routers = routers - return nil -} diff --git a/pkg/multicloud/openstack/roles.go b/pkg/multicloud/openstack/roles.go deleted file mode 100644 index c3afda57d9..0000000000 --- a/pkg/multicloud/openstack/roles.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - "net/url" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -type SRole struct { - Id string - Name string -} - -func (cli *SOpenStackClient) GetRoles(name string) ([]SRole, error) { - resource := "/v3/roles" - query := url.Values{} - if len(name) > 0 { - query.Set("name", name) - } - resp, err := cli.iamRequest(cli.getDefaultRegionName(), httputils.GET, resource, query, nil) - if err != nil { - return nil, errors.Wrap(err, "iamRequest") - } - roles := []SRole{} - err = resp.Unmarshal(&roles, "roles") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return roles, nil -} - -func (cli *SOpenStackClient) AssignRoleToUserOnProject(userId, projectId, roleName string) error { - if len(roleName) == 0 { - return errors.Error("empty role name") - } - roles, err := cli.GetRoles(roleName) - if err != nil { - return errors.Wrapf(err, "GetRoles(%s)", roleName) - } - if len(roles) == 0 { - return errors.Wrapf(cloudprovider.ErrNotFound, "role %s", roleName) - } - if len(roles) > 1 { - return errors.Wrapf(cloudprovider.ErrDuplicateId, "roles %d for %s", len(roles), roleName) - } - resource := fmt.Sprintf("/v3/projects/%s/users/%s/roles/%s", projectId, userId, roles[0].Id) - _, err = cli.iamRequest(cli.getDefaultRegionName(), httputils.PUT, resource, nil, map[string]string{}) - return err -} diff --git a/pkg/multicloud/openstack/routetable.go b/pkg/multicloud/openstack/routetable.go deleted file mode 100644 index ba73d61ce6..0000000000 --- a/pkg/multicloud/openstack/routetable.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRouteEntry struct { - multicloud.SResourceBase - multicloud.OpenStackTags - Destination string `json:"destination"` - Nexthop string `json:"nexthop"` -} - -func (route *SRouteEntry) GetId() string { - return route.Destination + ":" + route.Nexthop -} -func (route *SRouteEntry) GetName() string { - return "" -} -func (route *SRouteEntry) GetGlobalId() string { - return route.GetId() -} - -func (route *SRouteEntry) GetStatus() string { - return "" -} - -func (route *SRouteEntry) Refresh() error { - return nil -} - -func (route *SRouteEntry) IsEmulated() bool { - return false -} - -func (route *SRouteEntry) GetType() string { - return api.ROUTE_ENTRY_TYPE_CUSTOM -} - -func (route *SRouteEntry) GetCidr() string { - return route.Destination -} - -func (route *SRouteEntry) GetNextHopType() string { - return route.Nexthop -} - -func (route *SRouteEntry) GetNextHop() string { - return route.Nexthop -} - -type SRouteTable struct { - multicloud.SResourceBase - multicloud.OpenStackTags - vpc *SVpc - entries []SRouteEntry - router *SRouter -} - -func (self *SRouteTable) GetDescription() string { - return "" -} - -func (self *SRouteTable) GetId() string { - return self.GetGlobalId() -} - -func (self *SRouteTable) GetGlobalId() string { - return self.router.Id -} - -func (self *SRouteTable) GetName() string { - return self.router.Name -} - -func (self *SRouteTable) GetRegionId() string { - return self.vpc.region.GetId() -} - -func (self *SRouteTable) GetType() cloudprovider.RouteTableType { - return cloudprovider.RouteTableTypeSystem -} - -func (self *SRouteTable) GetVpcId() string { - return self.vpc.GetId() -} - -func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { - ret := []cloudprovider.ICloudRoute{} - for index := range self.entries { - ret = append(ret, &self.entries[index]) - } - return ret, nil -} - -func (self *SRouteTable) GetStatus() string { - return self.router.Status -} - -func (self *SRouteTable) IsEmulated() bool { - return false -} - -func (self *SRouteTable) Refresh() error { - return nil -} - -func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { - result := []cloudprovider.RouteTableAssociation{} - return result -} - -func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/openstack/securitygroup.go b/pkg/multicloud/openstack/securitygroup.go deleted file mode 100644 index 430019989c..0000000000 --- a/pkg/multicloud/openstack/securitygroup.go +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - "net/url" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -const ( - SECGROUP_NOT_SUPPORT = "openstack_skip_security_group" -) - -type SSecurityGroupRule struct { - Direction string - Ethertype string - Id string - PortRangeMax int - PortRangeMin int - Protocol string - RemoteGroupId string - RemoteIpPrefix string - SecurityGroupId string - ProjectId string - RevisionNumber int - Tags []string - TenantId string - CreatedAt time.Time - UpdatedAt time.Time - Description string -} - -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.OpenStackTags - region *SRegion - - Description string - Id string - Name string - SecurityGroupRules []SSecurityGroupRule - ProjectId string - RevisionNumber int - CreatedAt time.Time - UpdatedAt time.Time - Tags []string - TenantId string -} - -func (region *SRegion) GetSecurityGroup(secgroupId string) (*SSecurityGroup, error) { - resource := "/v2.0/security-groups/" + secgroupId - resp, err := region.vpcGet(resource) - if err != nil { - return nil, errors.Wrap(err, "vpcGet") - } - secgroup := &SSecurityGroup{region: region} - err = resp.Unmarshal(secgroup, "security_group") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return secgroup, nil -} - -func (region *SRegion) GetSecurityGroups(projectId, name string) ([]SSecurityGroup, error) { - secgroups := []SSecurityGroup{} - resource := "/v2.0/security-groups" - query := url.Values{} - if len(name) > 0 { - query.Set("name", name) - } - if len(projectId) > 0 { - query.Set("project_id", projectId) - } - for { - resp, err := region.vpcList(resource, query) - if err != nil { - return nil, errors.Wrap(err, "vpcList") - } - part := struct { - SecurityGroups []SSecurityGroup - SecurityGroupsLinks SNextLinks - }{} - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - secgroups = append(secgroups, part.SecurityGroups...) - marker := part.SecurityGroupsLinks.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return secgroups, nil -} - -func (secgroup *SSecurityGroup) GetVpcId() string { - return "normal" -} - -func (secgroup *SSecurityGroup) GetId() string { - return secgroup.Id -} - -func (secgroup *SSecurityGroup) GetGlobalId() string { - return secgroup.Id -} - -func (secgroup *SSecurityGroup) GetDescription() string { - return secgroup.Description -} - -func (secgroup *SSecurityGroup) GetName() string { - if len(secgroup.Name) > 0 { - return secgroup.Name - } - return secgroup.Id -} - -func (secgrouprule *SSecurityGroupRule) toRules() ([]cloudprovider.SecurityRule, error) { - rules := []cloudprovider.SecurityRule{} - // 暂时忽略IPv6安全组规则,忽略远端也是安全组的规则 - if secgrouprule.Ethertype != "IPv4" || len(secgrouprule.RemoteGroupId) > 0 { - return rules, fmt.Errorf("ethertype: %s remoteGroupId: %s", secgrouprule.Ethertype, secgrouprule.RemoteGroupId) - } - rule := cloudprovider.SecurityRule{ - ExternalId: secgrouprule.Id, - SecurityRule: secrules.SecurityRule{ - Direction: secrules.DIR_IN, - Action: secrules.SecurityRuleAllow, - Description: secgrouprule.Description, - }, - } - if utils.IsInStringArray(secgrouprule.Protocol, []string{"any", "-1", ""}) { - rule.Protocol = secrules.PROTO_ANY - } else if utils.IsInStringArray(secgrouprule.Protocol, []string{"6", "tcp"}) { - rule.Protocol = secrules.PROTO_TCP - } else if utils.IsInStringArray(secgrouprule.Protocol, []string{"17", "udp"}) { - rule.Protocol = secrules.PROTO_UDP - } else if utils.IsInStringArray(secgrouprule.Protocol, []string{"1", "icmp"}) { - rule.Protocol = secrules.PROTO_ICMP - } else { - return rules, errors.Wrap(httperrors.ErrUnsupportedProtocol, secgrouprule.Protocol) - } - if secgrouprule.Direction == "egress" { - rule.Direction = secrules.DIR_OUT - } - if len(secgrouprule.RemoteIpPrefix) == 0 { - secgrouprule.RemoteIpPrefix = "0.0.0.0/0" - } - - rule.ParseCIDR(secgrouprule.RemoteIpPrefix) - if secgrouprule.PortRangeMax > 0 && secgrouprule.PortRangeMin > 0 { - if secgrouprule.PortRangeMax == secgrouprule.PortRangeMin { - rule.Ports = []int{secgrouprule.PortRangeMax} - } else { - rule.PortStart = secgrouprule.PortRangeMin - rule.PortEnd = secgrouprule.PortRangeMax - } - } - err := rule.ValidateRule() - if err != nil && err != secrules.ErrInvalidPriority { - return rules, errors.Wrap(err, "rule.ValidateRule") - } - return []cloudprovider.SecurityRule{rule}, nil -} - -func (secgroup *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - rules := []cloudprovider.SecurityRule{} - for _, rule := range secgroup.SecurityGroupRules { - subRules, err := rule.toRules() - if err != nil { - log.Errorf("failed to convert rule %s for secgroup %s(%s) error: %v", rule.Id, secgroup.Name, secgroup.Id, err) - continue - } - rules = append(rules, subRules...) - } - return rules, nil -} - -func (secgroup *SSecurityGroup) GetStatus() string { - return "" -} - -func (secgroup *SSecurityGroup) IsEmulated() bool { - return false -} - -func (secgroup *SSecurityGroup) Refresh() error { - new, err := secgroup.region.GetSecurityGroup(secgroup.Id) - if err != nil { - return err - } - return jsonutils.Update(secgroup, new) -} - -func (region *SRegion) delSecurityGroupRule(ruleId string) error { - resource := "/v2.0/security-group-rules/" + ruleId - _, err := region.vpcDelete(resource) - return err -} - -func (region *SRegion) addSecurityGroupRules(secgroupId string, rule cloudprovider.SecurityRule) error { - direction := "ingress" - if rule.Direction == secrules.SecurityRuleEgress { - direction = "egress" - } - - if rule.Protocol == secrules.PROTO_ANY { - rule.Protocol = "" - } - - ruleInfo := map[string]interface{}{ - "direction": direction, - "security_group_id": secgroupId, - "remote_ip_prefix": rule.IPNet.String(), - } - if len(rule.Protocol) > 0 { - ruleInfo["protocol"] = rule.Protocol - } - - params := map[string]map[string]interface{}{ - "security_group_rule": ruleInfo, - } - if len(rule.Ports) > 0 { - for _, port := range rule.Ports { - params["security_group_rule"]["port_range_max"] = port - params["security_group_rule"]["port_range_min"] = port - resource := "/v2.0/security-group-rules" - _, err := region.vpcPost(resource, params) - if err != nil { - return errors.Wrap(err, "vpcPost") - } - } - return nil - } - if rule.PortEnd > 0 && rule.PortStart > 0 { - params["security_group_rule"]["port_range_min"] = rule.PortStart - params["security_group_rule"]["port_range_max"] = rule.PortEnd - } - _, err := region.vpcPost("/v2.0/security-group-rules", params) - return err -} - -func (region *SRegion) DeleteSecurityGroup(secGroupId string) error { - resource := "/v2.0/security-groups/" + secGroupId - _, err := region.vpcDelete(resource) - return err -} - -func (secgroup *SSecurityGroup) Delete() error { - return secgroup.region.DeleteSecurityGroup(secgroup.Id) -} - -func (region *SRegion) CreateSecurityGroup(projectId, name, description string) (*SSecurityGroup, error) { - params := map[string]map[string]interface{}{ - "security_group": { - "name": name, - "description": description, - }, - } - if len(projectId) > 0 { - params["security_group"]["project_id"] = projectId - } - resp, err := region.vpcPost("/v2.0/security-groups", params) - if err != nil { - return nil, errors.Wrap(err, "vpcPost") - } - secgroup := &SSecurityGroup{region: region} - err = resp.Unmarshal(secgroup, "security_group") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return secgroup, nil -} - -func (secgroup *SSecurityGroup) GetProjectId() string { - return secgroup.TenantId -} - -func (secgroup *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - for _, r := range append(inDels, outDels...) { - err := secgroup.region.delSecurityGroupRule(r.ExternalId) - if err != nil { - return errors.Wrapf(err, "delSecurityGroupRule(%s)", r.ExternalId) - } - } - for _, r := range append(inAdds, outAdds...) { - err := secgroup.region.addSecurityGroupRules(secgroup.Id, r) - if err != nil { - if jsonError, ok := err.(*httputils.JSONClientError); ok { - if jsonError.Class == "SecurityGroupRuleExists" { - continue - } - } - return errors.Wrapf(err, "addSecgroupRules(%s)", r.String()) - } - } - return nil -} diff --git a/pkg/multicloud/openstack/shell/disk.go b/pkg/multicloud/openstack/shell/disk.go deleted file mode 100644 index 7127ec620e..0000000000 --- a/pkg/multicloud/openstack/shell/disk.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - } - shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *openstack.SRegion, args *DiskListOptions) error { - disks, err := cli.GetDisks() - if err != nil { - return err - } - printList(disks, 0, 0, 0, []string{}) - return nil - }) - - type DiskOptions struct { - ID string `help:"ID of disk"` - } - - shellutils.R(&DiskOptions{}, "disk-show", "Show disk", func(cli *openstack.SRegion, args *DiskOptions) error { - disk, err := cli.GetDisk(args.ID) - if err != nil { - return err - } - printObject(disk) - return nil - }) - - shellutils.R(&DiskOptions{}, "disk-delete", "Delete disk", func(cli *openstack.SRegion, args *DiskOptions) error { - return cli.DeleteDisk(args.ID) - }) - - type DiskCreateOptions struct { - ImageRef string `help:"ImageRef"` - CATEGORY string `help:"Disk category"` - NAME string `help:"Disk Name"` - SIZE int `help:"Disk Size GB"` - Desc string `help:"Description of disk"` - ProjectId string `help:"ProjectId"` - } - shellutils.R(&DiskCreateOptions{}, "disk-create", "Create disk", func(cli *openstack.SRegion, args *DiskCreateOptions) error { - disk, err := cli.CreateDisk(args.ImageRef, args.CATEGORY, args.NAME, args.SIZE, args.Desc, args.ProjectId) - if err != nil { - return err - } - printObject(disk) - return nil - }) - - type DiskResetOptions struct { - DISK string `help:"ID of disk"` - SNAPSHOT string `help:"ID of snapshot"` - } - - shellutils.R(&DiskResetOptions{}, "disk-reset", "Reset disk", func(cli *openstack.SRegion, args *DiskResetOptions) error { - return cli.ResetDisk(args.DISK, args.SNAPSHOT) - }) - - type DiskResizeOptions struct { - DISK string `help:"ID of disk"` - SIZE int64 `help:"Disk size GB"` - } - - shellutils.R(&DiskResizeOptions{}, "disk-resize", "Resize disk", func(cli *openstack.SRegion, args *DiskResizeOptions) error { - return cli.ResizeDisk(args.DISK, args.SIZE*1024) - }) - -} diff --git a/pkg/multicloud/openstack/shell/doc.go b/pkg/multicloud/openstack/shell/doc.go deleted file mode 100644 index a8989ca260..0000000000 --- a/pkg/multicloud/openstack/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/openstack/shell" diff --git a/pkg/multicloud/openstack/shell/eip.go b/pkg/multicloud/openstack/shell/eip.go deleted file mode 100644 index 1e07e18f81..0000000000 --- a/pkg/multicloud/openstack/shell/eip.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - Ip string - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *openstack.SRegion, args *EipListOptions) error { - eips, err := cli.GetEips(args.Ip) - if err != nil { - return err - } - printList(eips, 0, 0, 0, []string{}) - return nil - }) - - type EipDeleteOptions struct { - ID string - } - shellutils.R(&EipDeleteOptions{}, "eip-delete", "Delete eip", func(cli *openstack.SRegion, args *EipDeleteOptions) error { - return cli.DeleteEip(args.ID) - }) - - type EipCreateOptions struct { - NETWORK string - SUBNET string - Ip string - TenantId string - } - - shellutils.R(&EipCreateOptions{}, "eip-create", "Create eip", func(cli *openstack.SRegion, args *EipCreateOptions) error { - eip, err := cli.CreateEip(args.NETWORK, args.SUBNET, args.Ip, args.TenantId) - if err != nil { - return err - } - printObject(eip) - return nil - }) - -} diff --git a/pkg/multicloud/openstack/shell/flavor.go b/pkg/multicloud/openstack/shell/flavor.go deleted file mode 100644 index 8dee5baebd..0000000000 --- a/pkg/multicloud/openstack/shell/flavor.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type FlavorkListOptions struct { - } - shellutils.R(&FlavorkListOptions{}, "flavor-list", "List flavors", func(cli *openstack.SRegion, args *FlavorkListOptions) error { - flavors, err := cli.GetFlavors() - if err != nil { - return err - } - printList(flavors, 0, 0, 0, []string{}) - return nil - }) - - type FlavorOptions struct { - ID string `help:"ID of flavor"` - } - - shellutils.R(&FlavorOptions{}, "flavor-show", "Show flavor", func(cli *openstack.SRegion, args *FlavorOptions) error { - flavor, err := cli.GetFlavor(args.ID) - if err != nil { - return err - } - printObject(flavor) - return nil - }) - - shellutils.R(&FlavorOptions{}, "flavor-delete", "Delete flavor", func(cli *openstack.SRegion, args *FlavorOptions) error { - return cli.DeleteFlavor(args.ID) - }) - - type FlavorCreateOptions struct { - NAME string `help:"Name of flavor"` - CPU int `help:"Core num of cpu"` - MEMORY_MB int `help:"Memory of flavor"` - DISK int `help:"Disk size of flavor"` - } - - shellutils.R(&FlavorCreateOptions{}, "flavor-create", "Create flavor", func(cli *openstack.SRegion, args *FlavorCreateOptions) error { - flavor, err := cli.CreateFlavor(args.NAME, args.CPU, args.MEMORY_MB, args.DISK) - if err != nil { - return err - } - printObject(flavor) - return nil - }) - - shellutils.R(&FlavorCreateOptions{}, "flavor-sync", "Sync flavor", func(cli *openstack.SRegion, args *FlavorCreateOptions) error { - flavorId, err := cli.SyncFlavor(args.NAME, args.CPU, args.MEMORY_MB, args.DISK) - if err != nil { - return err - } - fmt.Println(flavorId) - return nil - }) - -} diff --git a/pkg/multicloud/openstack/shell/host.go b/pkg/multicloud/openstack/shell/host.go deleted file mode 100644 index 7c5f095c99..0000000000 --- a/pkg/multicloud/openstack/shell/host.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type HostListOptions struct { - } - shellutils.R(&HostListOptions{}, "host-list", "List hosts", func(cli *openstack.SRegion, args *HostListOptions) error { - hosts, err := cli.GetHosts() - if err != nil { - return err - } - printList(hosts, 0, 0, 0, []string{}) - return nil - }) - - type AggregateListOption struct { - } - - shellutils.R(&AggregateListOption{}, "aggregate-list", "List os-aggregates", func(cli *openstack.SRegion, args *AggregateListOption) error { - aggregates, err := cli.GetAggregates() - if err != nil { - return err - } - printList(aggregates, 0, 0, 0, []string{}) - return nil - }) - - type HypervisorListOption struct { - } - - shellutils.R(&HypervisorListOption{}, "hypervisor-list", "List os-hypervisor", func(cli *openstack.SRegion, args *HypervisorListOption) error { - hypervisors, err := cli.GetHypervisors() - if err != nil { - return err - } - printList(hypervisors, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/openstack/shell/image.go b/pkg/multicloud/openstack/shell/image.go deleted file mode 100644 index 910e20e73c..0000000000 --- a/pkg/multicloud/openstack/shell/image.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "os" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - Name string - Id string - Status string - } - shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *openstack.SRegion, args *ImageListOptions) error { - images, err := cli.GetImages(args.Name, args.Status, args.Id) - if err != nil { - return err - } - printList(images, 0, 0, 0, []string{}) - return nil - }) - - type ImageOptions struct { - ID string - } - - shellutils.R(&ImageOptions{}, "image-show", "Show image", func(cli *openstack.SRegion, args *ImageOptions) error { - image, err := cli.GetImage(args.ID) - if err != nil { - return err - } - printObject(image) - return nil - }) - - shellutils.R(&ImageOptions{}, "image-delete", "Delete image", func(cli *openstack.SRegion, args *ImageOptions) error { - return cli.DeleteImage(args.ID) - }) - - type ImageCreateOptions struct { - NAME string - OsType string `help:"os type" default:"linux" choices:"linux|windows"` - OsDistro string - MinDiskSizeGB int - MinRamMb int - FILE string - } - - shellutils.R(&ImageCreateOptions{}, "image-create", "Create image", func(cli *openstack.SRegion, args *ImageCreateOptions) error { - file, err := os.Open(args.FILE) - if err != nil { - return errors.Wrap(err, "os.Open") - } - defer file.Close() - image, err := cli.CreateImage(args.NAME, args.OsType, args.OsDistro, args.MinDiskSizeGB, args.MinRamMb, 0, file, nil) - if err != nil { - return err - } - printObject(image) - return nil - }) - -} diff --git a/pkg/multicloud/openstack/shell/instance.go b/pkg/multicloud/openstack/shell/instance.go deleted file mode 100644 index 3e3ad6595f..0000000000 --- a/pkg/multicloud/openstack/shell/instance.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - Host string `help:"Host name for filter instance list"` - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List instances", func(cli *openstack.SRegion, args *InstanceListOptions) error { - instances, err := cli.GetInstances(args.Host) - if err != nil { - return err - } - printList(instances, 0, 0, 0, nil) - return nil - }) - - type InstanceOptions struct { - ID string `help:"Instance ID"` - } - - shellutils.R(&InstanceOptions{}, "instance-network-list", "List instance network", func(cli *openstack.SRegion, args *InstanceOptions) error { - ports, err := cli.GetInstancePorts(args.ID) - if err != nil { - return err - } - printObject(ports) - return nil - }) - - shellutils.R(&InstanceOptions{}, "instance-show", "Show instance", func(cli *openstack.SRegion, args *InstanceOptions) error { - instance, err := cli.GetInstance(args.ID) - if err != nil { - return err - } - printObject(instance) - return nil - }) - - shellutils.R(&InstanceOptions{}, "instance-metadata", "Show instance metadata", func(cli *openstack.SRegion, args *InstanceOptions) error { - metadata, err := cli.GetInstanceMetadata(args.ID) - if err != nil { - return err - } - printObject(metadata) - return nil - }) - - shellutils.R(&InstanceOptions{}, "instance-vnc", "Show instance vnc url", func(cli *openstack.SRegion, args *InstanceOptions) error { - ret, err := cli.GetInstanceVNCUrl(args.ID, true) - if err != nil { - ret, err = cli.GetInstanceVNC(args.ID, true) - } - if err != nil { - return err - } - printObject(ret) - return nil - }) - - type InstanceDeployOptions struct { - ID string `help:"Instance ID"` - Password string `help:"Instance password"` - Name string `help:"Instance name"` - } - - shellutils.R(&InstanceDeployOptions{}, "instance-deploy", "Deploy instance", func(cli *openstack.SRegion, args *InstanceDeployOptions) error { - return cli.DeployVM(args.ID, args.Name, args.Password, "", false, "") - }) - - type InstanceChangeConfigOptions struct { - ID string `help:"Instance ID"` - FLAVOR_ID string `help:"Flavor ID"` - } - - shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Change instance config", func(cli *openstack.SRegion, args *InstanceChangeConfigOptions) error { - instance, err := cli.GetInstance(args.ID) - if err != nil { - return err - } - return cli.ChangeConfig(instance, args.FLAVOR_ID) - }) - - type InstanceDiskOptions struct { - ID string `help:"Instance ID"` - DISK string `help:"DiskId"` - } - - shellutils.R(&InstanceDiskOptions{}, "instance-detach-disk", "Detach instance disk", func(cli *openstack.SRegion, args *InstanceDiskOptions) error { - return cli.DetachDisk(args.ID, args.DISK) - }) - - type InstanceMigrateOptions struct { - ID string `help:"Instance ID"` - Host string `help:"host id"` - } - type MigrationOptions struct { - ID string `help:"Instance ID"` - Type string `help:"migration choices:evacuation|live-migration|migration|resize"` - Migrationid string `help:"migration ID"` - } - shellutils.R(&InstanceMigrateOptions{}, "instance-migrate", "migrate instance", func(cli *openstack.SRegion, args *InstanceMigrateOptions) error { - return cli.MigrateVM(args.ID, args.Host) - }) - - shellutils.R(&InstanceMigrateOptions{}, "instance-live-migrate", "migrate instance", func(cli *openstack.SRegion, args *InstanceMigrateOptions) error { - return cli.LiveMigrateVM(args.ID, args.Host) - }) - - shellutils.R(&MigrationOptions{}, "instance-migration-list", "list live migration", func(cli *openstack.SRegion, args *MigrationOptions) error { - return cli.ListServerMigration(args.ID) - }) - shellutils.R(&MigrationOptions{}, "instance-migration-delete", "delet migration", func(cli *openstack.SRegion, args *MigrationOptions) error { - return cli.DeleteMigration(args.ID, args.Migrationid) - }) - shellutils.R(&MigrationOptions{}, "instance-migration-forceComplete", "deletmigration", func(cli *openstack.SRegion, args *MigrationOptions) error { - return cli.ForceCompleteMigration(args.ID, args.Migrationid) - }) - - shellutils.R(&MigrationOptions{}, "migrations-show", "show migrations", func(cli *openstack.SRegion, args *MigrationOptions) error { - _, err := cli.GetMigrations(args.ID, args.Type) - return err - }) -} diff --git a/pkg/multicloud/openstack/shell/keypair.go b/pkg/multicloud/openstack/shell/keypair.go deleted file mode 100644 index d7b6f1c59d..0000000000 --- a/pkg/multicloud/openstack/shell/keypair.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KeypairListOptions struct { - } - shellutils.R(&KeypairListOptions{}, "keypair-list", "List keypairs", func(cli *openstack.SRegion, args *KeypairListOptions) error { - keypairs, err := cli.GetKeypairs() - if err != nil { - return err - } - printList(keypairs, 0, 0, 0, []string{}) - return nil - }) - - type KeypairCreateOptions struct { - NAME string - PublicKey string - Type string `help:"keypair type" choices:"ssh|x509"` - } - - shellutils.R(&KeypairCreateOptions{}, "keypair-create", "Create keypair", func(cli *openstack.SRegion, args *KeypairCreateOptions) error { - keypair, err := cli.CreateKeypair(args.NAME, args.PublicKey, args.Type) - if err != nil { - return err - } - printObject(keypair) - return nil - }) - - type KeypairOptions struct { - NAME string `help:"Keypair name"` - } - - shellutils.R(&KeypairOptions{}, "keypair-show", "Show keypair", func(cli *openstack.SRegion, args *KeypairOptions) error { - keypair, err := cli.GetKeypair(args.NAME) - if err != nil { - return err - } - printObject(keypair) - return nil - }) - - shellutils.R(&KeypairOptions{}, "keypair-delete", "Delete keypair", func(cli *openstack.SRegion, args *KeypairOptions) error { - return cli.DeleteKeypair(args.NAME) - }) - -} diff --git a/pkg/multicloud/openstack/shell/loadbalancer.go b/pkg/multicloud/openstack/shell/loadbalancer.go deleted file mode 100644 index 8a30e3477a..0000000000 --- a/pkg/multicloud/openstack/shell/loadbalancer.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LoadbalancerListOptions struct { - } - type LoadbalancerPoolListOptions struct { - } - type LoadbalancerListenerListOptions struct { - } - type LoadbalancerOptions struct { - ID string `help:"LoadbalancerId"` - } - type LoadbalancerListenerOptions struct { - ID string `help:"LoadbalancerListenerId"` - } - - shellutils.R(&LoadbalancerListOptions{}, "lb-list", "List loadbalancers", func(cli *openstack.SRegion, args *LoadbalancerListOptions) error { - loadbalancers, err := cli.GetLoadbalancers() - if err != nil { - return err - } - printObject(loadbalancers) - return nil - }) - shellutils.R(&LoadbalancerOptions{}, "lb-show", "Show loadbalancer", func(cli *openstack.SRegion, args *LoadbalancerOptions) error { - loadbalancer, err := cli.GetLoadbalancerbyId(args.ID) - if err != nil { - return err - } - printObject(loadbalancer) - return nil - }) - shellutils.R(&LoadbalancerOptions{}, "lb-delete", "delete loadbalancer", func(cli *openstack.SRegion, args *LoadbalancerOptions) error { - err := cli.DeleteLoadbalancer(args.ID) - if err != nil { - return err - } - return nil - }) - shellutils.R(&LoadbalancerPoolListOptions{}, "lbpool-list", "List loadbalancers pool", func(cli *openstack.SRegion, args *LoadbalancerPoolListOptions) error { - loadbalancers, err := cli.GetLoadbalancerPools() - if err != nil { - return err - } - printObject(loadbalancers) - return nil - }) - - shellutils.R(&LoadbalancerListenerListOptions{}, "lblistener-list", "List loadbalancers listener", func(cli *openstack.SRegion, args *LoadbalancerListenerListOptions) error { - loadbalancers, err := cli.GetLoadbalancerListeners() - if err != nil { - return err - } - printObject(loadbalancers) - return nil - }) - shellutils.R(&LoadbalancerOptions{}, "lblistener-delete", "Delete loadbalancer listener", func(cli *openstack.SRegion, args *LoadbalancerOptions) error { - err := cli.DeleteLoadbalancerListener(args.ID) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/openstack/shell/messages.go b/pkg/multicloud/openstack/shell/messages.go deleted file mode 100644 index 31c61fb2f3..0000000000 --- a/pkg/multicloud/openstack/shell/messages.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type MessageListOptions struct { - ResourceId string - } - shellutils.R(&MessageListOptions{}, "message-list", "List messages", func(cli *openstack.SRegion, args *MessageListOptions) error { - messages, err := cli.GetMessages(args.ResourceId) - if err != nil { - return err - } - printList(messages, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/openstack/shell/network.go b/pkg/multicloud/openstack/shell/network.go deleted file mode 100644 index 7024c248ab..0000000000 --- a/pkg/multicloud/openstack/shell/network.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkListOptions struct { - VpcId string `help:"Vpc ID for filter network list"` - } - shellutils.R(&NetworkListOptions{}, "network-list", "List networks", func(cli *openstack.SRegion, args *NetworkListOptions) error { - networks, err := cli.GetNetworks(args.VpcId) - if err != nil { - return err - } - printList(networks, 0, 0, 0, nil) - return nil - }) - - type NetworkOptions struct { - ID string `help:"Network ID"` - } - shellutils.R(&NetworkOptions{}, "network-show", "Show network", func(cli *openstack.SRegion, args *NetworkOptions) error { - network, err := cli.GetNetwork(args.ID) - if err != nil { - return err - } - printObject(network) - return nil - }) - - type NetworkCreateOptions struct { - VPCID string - NAME string - CIDR string - Desc string - ProjectId string - } - - shellutils.R(&NetworkCreateOptions{}, "network-create", "Create network", func(cli *openstack.SRegion, args *NetworkCreateOptions) error { - network, err := cli.CreateNetwork(args.VPCID, args.ProjectId, args.NAME, args.CIDR, args.Desc) - if err != nil { - return err - } - printObject(network) - return nil - }) -} diff --git a/pkg/multicloud/openstack/shell/port.go b/pkg/multicloud/openstack/shell/port.go deleted file mode 100644 index 1fa39c0b48..0000000000 --- a/pkg/multicloud/openstack/shell/port.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type PortListOptions struct { - MacAddr string - DeviceId string - } - shellutils.R(&PortListOptions{}, "port-list", "List ports", func(cli *openstack.SRegion, args *PortListOptions) error { - ports, err := cli.GetPorts(args.MacAddr, args.DeviceId) - if err != nil { - return err - } - printList(ports, 0, 0, 0, nil) - return nil - }) - - type PortIdOptions struct { - ID string - } - - shellutils.R(&PortIdOptions{}, "port-show", "Show port", func(cli *openstack.SRegion, args *PortIdOptions) error { - port, err := cli.GetPort(args.ID) - if err != nil { - return err - } - printObject(port) - return nil - }) - -} diff --git a/pkg/multicloud/openstack/shell/printutils.go b/pkg/multicloud/openstack/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/openstack/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/openstack/shell/project.go b/pkg/multicloud/openstack/shell/project.go deleted file mode 100644 index 253b80c111..0000000000 --- a/pkg/multicloud/openstack/shell/project.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ProjectListOptions struct { - } - shellutils.R(&ProjectListOptions{}, "project-list", "List project", func(cli *openstack.SRegion, args *ProjectListOptions) error { - project, err := cli.GetClient().GetProjects() - if err != nil { - return err - } - printList(project, 0, 0, 0, nil) - return nil - }) - - type ProjectCreateOptions struct { - NAME string - Desc string - } - - shellutils.R(&ProjectCreateOptions{}, "project-create", "Create project", func(cli *openstack.SRegion, args *ProjectCreateOptions) error { - project, err := cli.GetClient().CreateProject(args.NAME, args.Desc) - if err != nil { - return err - } - printObject(project) - return nil - }) - - type ProjectIdOption struct { - ID string - } - - shellutils.R(&ProjectIdOption{}, "project-delete", "Delete project", func(cli *openstack.SRegion, args *ProjectIdOption) error { - return cli.GetClient().DeleteProject(args.ID) - }) - -} diff --git a/pkg/multicloud/openstack/shell/quota.go b/pkg/multicloud/openstack/shell/quota.go deleted file mode 100644 index 9dec68a2da..0000000000 --- a/pkg/multicloud/openstack/shell/quota.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type QuotaOptions struct { - } - shellutils.R(&QuotaOptions{}, "quota-show", "Show quota", func(cli *openstack.SRegion, args *QuotaOptions) error { - quota, err := cli.GetQuota() - if err != nil { - return err - } - printObject(quota) - return nil - }) - - shellutils.R(&openstack.SQuota{}, "quota-set", "Set quota", func(cli *openstack.SRegion, args *openstack.SQuota) error { - return cli.SetQuota(args) - }) - -} diff --git a/pkg/multicloud/openstack/shell/region.go b/pkg/multicloud/openstack/shell/region.go deleted file mode 100644 index 382898d754..0000000000 --- a/pkg/multicloud/openstack/shell/region.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *openstack.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/openstack/shell/role.go b/pkg/multicloud/openstack/shell/role.go deleted file mode 100644 index b002e5eaea..0000000000 --- a/pkg/multicloud/openstack/shell/role.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RoleListOptions struct { - Name string - } - shellutils.R(&RoleListOptions{}, "role-list", "List roles", func(cli *openstack.SRegion, args *RoleListOptions) error { - roles, err := cli.GetClient().GetRoles(args.Name) - if err != nil { - return err - } - printList(roles, 0, 0, 0, []string{}) - return nil - }) - - type RoleAssignOptions struct { - PROJECT_ID string - USERID string - ROLE string - } - - shellutils.R(&RoleAssignOptions{}, "role-assign", "Assign role to user on project", func(cli *openstack.SRegion, args *RoleAssignOptions) error { - return cli.GetClient().AssignRoleToUserOnProject(args.USERID, args.PROJECT_ID, args.ROLE) - }) - -} diff --git a/pkg/multicloud/openstack/shell/router.go b/pkg/multicloud/openstack/shell/router.go deleted file mode 100644 index 14e5af604a..0000000000 --- a/pkg/multicloud/openstack/shell/router.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RouterListOptions struct { - } - shellutils.R(&RouterListOptions{}, "router-list", "List routers", func(cli *openstack.SRegion, args *RouterListOptions) error { - routers, err := cli.GetRouters() - if err != nil { - return nil - } - printList(routers, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/openstack/shell/securitygroup.go b/pkg/multicloud/openstack/shell/securitygroup.go deleted file mode 100644 index 9c75d06d30..0000000000 --- a/pkg/multicloud/openstack/shell/securitygroup.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - ProjectId string - Name string - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security groups", func(cli *openstack.SRegion, args *SecurityGroupListOptions) error { - secgroup, err := cli.GetSecurityGroups(args.ProjectId, args.Name) - if err != nil { - return err - } - printList(secgroup, 0, 0, 0, nil) - return nil - }) - - type SecurityGroupShowOptions struct { - ID string `help:"ID of security group"` - ShowRules bool `help:"Show rules"` - } - shellutils.R(&SecurityGroupShowOptions{}, "security-group-show", "Show security group", func(cli *openstack.SRegion, args *SecurityGroupShowOptions) error { - secgroup, err := cli.GetSecurityGroup(args.ID) - if err != nil { - return err - } - printObject(secgroup) - if args.ShowRules { - rules, err := secgroup.GetRules() - if err != nil { - return err - } - for _, r := range rules { - printObject(r) - } - } - return nil - }) - - type SecurityGroupCreateOptions struct { - ProjectId string - NAME string `help:"Name of security group"` - Desc string `help:"Description of security group"` - } - - shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create security group", func(cli *openstack.SRegion, args *SecurityGroupCreateOptions) error { - secgroup, err := cli.CreateSecurityGroup(args.ProjectId, args.NAME, args.Desc) - if err != nil { - return err - } - printObject(secgroup) - return nil - }) - -} diff --git a/pkg/multicloud/openstack/shell/snapshot.go b/pkg/multicloud/openstack/shell/snapshot.go deleted file mode 100644 index f981b1f451..0000000000 --- a/pkg/multicloud/openstack/shell/snapshot.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SnapshotListOptions struct { - DiskId string `help:"Disk ID for filter snapshot"` - } - shellutils.R(&SnapshotListOptions{}, "snapshot-list", "List snapshots", func(cli *openstack.SRegion, args *SnapshotListOptions) error { - snapshots, err := cli.GetSnapshots(args.DiskId) - if err != nil { - return err - } - printList(snapshots, 0, 0, 0, []string{}) - return nil - }) - - type SnapshotOptions struct { - ID string `help:"ID of snapshot"` - } - - shellutils.R(&SnapshotOptions{}, "snapshot-show", "Show snapshot", func(cli *openstack.SRegion, args *SnapshotOptions) error { - snapshot, err := cli.GetISnapshotById(args.ID) - if err != nil { - return err - } - printObject(snapshot) - return nil - }) - - shellutils.R(&SnapshotOptions{}, "snapshot-delete", "Delete snapshot", func(cli *openstack.SRegion, args *SnapshotOptions) error { - return cli.DeleteSnapshot(args.ID) - }) - - type SnapshotCreateOptions struct { - DISKID string `help:"Disk ID"` - Name string `help:"Disk Name"` - Desc string `help:"Disk description"` - } - - shellutils.R(&SnapshotCreateOptions{}, "snapshot-create", "Create snapshot", func(cli *openstack.SRegion, args *SnapshotCreateOptions) error { - snapshot, err := cli.CreateSnapshot(args.DISKID, args.Name, args.Desc) - if err != nil { - return err - } - printObject(snapshot) - return nil - }) - -} diff --git a/pkg/multicloud/openstack/shell/storage.go b/pkg/multicloud/openstack/shell/storage.go deleted file mode 100644 index 17f2d4584e..0000000000 --- a/pkg/multicloud/openstack/shell/storage.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type StorageListOptions struct { - } - shellutils.R(&StorageListOptions{}, "storage-list", "List storages", func(cli *openstack.SRegion, args *StorageListOptions) error { - storages, err := cli.GetStorageTypes() - if err != nil { - return err - } - printList(storages, 0, 0, 0, []string{}) - return nil - }) - - type CinderServiceListOptions struct { - } - - shellutils.R(&CinderServiceListOptions{}, "cinder-service-list", "List cinder services", func(cli *openstack.SRegion, args *CinderServiceListOptions) error { - services, err := cli.GetCinderServices() - if err != nil { - return err - } - printList(services, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/openstack/shell/vpc.go b/pkg/multicloud/openstack/shell/vpc.go deleted file mode 100644 index 0da4516405..0000000000 --- a/pkg/multicloud/openstack/shell/vpc.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - TenantId string - } - shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *openstack.SRegion, args *VpcListOptions) error { - vpcs, err := cli.GetVpcs(args.TenantId) - if err != nil { - return err - } - printList(vpcs, 0, 0, 0, nil) - return nil - }) - - type VpcIdOptions struct { - ID string `help:"ID of vpc"` - } - shellutils.R(&VpcIdOptions{}, "vpc-show", "Show vpc", func(cli *openstack.SRegion, args *VpcIdOptions) error { - vpc, err := cli.GetVpc(args.ID) - if err != nil { - return err - } - printObject(vpc) - return nil - }) - - shellutils.R(&VpcIdOptions{}, "vpc-delete", "Delete vpc", func(cli *openstack.SRegion, args *VpcIdOptions) error { - return cli.DeleteVpc(args.ID) - }) - - type VpcCreateOptions struct { - NAME string - Desc string - } - - shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *openstack.SRegion, args *VpcCreateOptions) error { - vpc, err := cli.CreateVpc(args.NAME, args.Desc) - if err != nil { - return err - } - printObject(vpc) - return nil - }) -} diff --git a/pkg/multicloud/openstack/shell/zone.go b/pkg/multicloud/openstack/shell/zone.go deleted file mode 100644 index 92802ea9ba..0000000000 --- a/pkg/multicloud/openstack/shell/zone.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/openstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - } - shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *openstack.SRegion, args *ZoneListOptions) error { - zones, err := cli.GetZones() - if err != nil { - return err - } - printList(zones, 0, 0, 0, nil) - return nil - }) - - type SchedulerPoolListOptions struct { - } - shellutils.R(&SchedulerPoolListOptions{}, "scheduler-pool-list", "List scheduler pool", func(cli *openstack.SRegion, args *SchedulerPoolListOptions) error { - pools, err := cli.GetSchedulerStatsPool() - if err != nil { - return err - } - printList(pools, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/openstack/snapshot.go b/pkg/multicloud/openstack/snapshot.go deleted file mode 100644 index 6162a7b389..0000000000 --- a/pkg/multicloud/openstack/snapshot.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - SNAPSHOT_STATUS_CREATING = "creating" //The snapshot is being created. - SNAPSHOT_STATUS_AVAILABLE = "available" //The snapshot is ready to use. - SNAPSHOT_STATUS_BACKING_UP = "backing-up" //The snapshot is being backed up. - SNAPSHOT_STATUS_DELETING = "deleting" //The snapshot is being deleted. - SNAPSHOT_STATUS_ERROR = "error" //A snapshot creation error occurred. - SNAPSHOT_STATUS_DELETED = "deleted" //The snapshot has been deleted. - SNAPSHOT_STATUS_UNMANAGING = "unmanaging" //The snapshot is being unmanaged. - SNAPSHOT_STATUS_RESTORING = "restoring" //The snapshot is being restored to a volume. - SNAPSHOT_STATUS_ERROR_DELETING = "error_deleting" //A snapshot deletion error occurred. -) - -type SSnapshot struct { - multicloud.SResourceBase - multicloud.OpenStackTags - region *SRegion - - Id string - VolumeId string - - Status string - - Progress string `json:"os-extended-snapshot-attributes:progress"` - Name string - UserId string - ProjectId string `json:"os-extended-snapshot-attributes:project_id"` - //CreatedAt time.Time - Size int32 - - Description string - //UpdatedAt time.Time -} - -func (region *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - resource := "/snapshots/" + snapshotId - resp, err := region.bsGet(resource) - if err != nil { - return nil, errors.Wrap(err, "bsGet") - } - snapshot := SSnapshot{region: region} - err = resp.Unmarshal(&snapshot, "snapshot") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return &snapshot, nil -} - -func (snapshot *SSnapshot) GetStatus() string { - switch snapshot.Status { - case SNAPSHOT_STATUS_CREATING: - return api.SNAPSHOT_CREATING - case SNAPSHOT_STATUS_AVAILABLE: - return api.SNAPSHOT_READY - case SNAPSHOT_STATUS_BACKING_UP: - return api.SNAPSHOT_ROLLBACKING - case SNAPSHOT_STATUS_DELETED, SNAPSHOT_STATUS_DELETING: - return api.SNAPSHOT_DELETING - default: - return api.SNAPSHOT_UNKNOWN - } -} - -func (snapshot *SSnapshot) IsEmulated() bool { - return false -} - -func (snapshot *SSnapshot) Refresh() error { - _snapshot, err := snapshot.region.GetISnapshotById(snapshot.Id) - if err != nil { - return err - } - return jsonutils.Update(snapshot, _snapshot) -} - -func (region *SRegion) GetSnapshots(diskId string) ([]SSnapshot, error) { - resource := "/snapshots/detail" - query := url.Values{} - query.Set("all_tenants", "true") - if len(diskId) > 0 { - query.Set("volume_id", diskId) - } - snapshots := []SSnapshot{} - for { - resp, err := region.bsList(resource, query) - if err != nil { - return nil, errors.Wrap(err, "bsList") - } - part := struct { - Snapshots []SSnapshot - SnapshotsLinks SNextLinks - }{} - - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - snapshots = append(snapshots, part.Snapshots...) - marker := part.SnapshotsLinks.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return snapshots, nil -} - -func (region *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := region.GetSnapshots("") - if err != nil { - return nil, err - } - isnapshots := []cloudprovider.ICloudSnapshot{} - for i := range snapshots { - snapshots[i].region = region - isnapshots = append(isnapshots, &snapshots[i]) - } - return isnapshots, nil -} - -func (snapshot *SSnapshot) GetSizeMb() int32 { - return snapshot.Size * 1024 -} - -func (snapshot *SSnapshot) GetDiskId() string { - return snapshot.VolumeId -} - -func (snapshot *SSnapshot) GetId() string { - return snapshot.Id -} - -func (snapshot *SSnapshot) GetGlobalId() string { - return snapshot.Id -} - -func (snapshot *SSnapshot) GetName() string { - if len(snapshot.Name) == 0 { - return snapshot.Id - } - return snapshot.Name -} - -func (snapshot *SSnapshot) Delete() error { - return snapshot.region.DeleteSnapshot(snapshot.Id) -} - -func (snapshot *SSnapshot) GetDiskType() string { - if len(snapshot.VolumeId) > 0 { - disk, err := snapshot.region.GetDisk(snapshot.VolumeId) - if err != nil { - log.Errorf("failed to get snapshot %s disk %s error: %v", snapshot.Name, snapshot.VolumeId, err) - return api.DISK_TYPE_DATA - } - return disk.GetDiskType() - } - return api.DISK_TYPE_DATA -} - -func (region *SRegion) DeleteSnapshot(snapshotId string) error { - resource := "/snapshots/" + snapshotId - _, err := region.bsDelete(resource) - return err -} - -func (region *SRegion) CreateSnapshot(diskId, name, desc string) (*SSnapshot, error) { - params := map[string]map[string]interface{}{ - "snapshot": { - "volume_id": diskId, - "name": name, - "description": desc, - "force": true, - }, - } - resp, err := region.bsPost("/snapshots", params) - if err != nil { - return nil, errors.Wrap(err, "bsPost") - } - snapshot := &SSnapshot{region: region} - err = resp.Unmarshal(snapshot, "snapshot") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return snapshot, nil -} - -func (self *SSnapshot) GetProjectId() string { - return self.ProjectId -} diff --git a/pkg/multicloud/openstack/storage.go b/pkg/multicloud/openstack/storage.go deleted file mode 100644 index 582ce67aa7..0000000000 --- a/pkg/multicloud/openstack/storage.go +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - DEFAULT_STORAGE_TYPE = "scheduler" -) - -type SExtraSpecs struct { - VolumeBackendName string -} - -type SStorage struct { - multicloud.SStorageBase - zone *SZone - Name string - ExtraSpecs SExtraSpecs - ID string -} - -func (storage *SStorage) GetId() string { - return storage.ID -} - -func (storage *SStorage) GetName() string { - return storage.Name -} - -func (storage *SStorage) GetGlobalId() string { - return fmt.Sprintf("%s-%s", storage.zone.GetGlobalId(), storage.ID) -} - -func (storage *SStorage) IsEmulated() bool { - return false -} - -func (storage *SStorage) GetIZone() cloudprovider.ICloudZone { - return storage.zone -} - -func (storage *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := storage.zone.region.GetDisks() - if err != nil { - return nil, err - } - idisks := []cloudprovider.ICloudDisk{} - for i := 0; i < len(disks); i++ { - if disks[i].AvailabilityZone == storage.zone.ZoneName && (disks[i].VolumeType == storage.Name || strings.HasSuffix(disks[i].Host, "#"+storage.ExtraSpecs.VolumeBackendName)) { - disks[i].storage = storage - idisks = append(idisks, &disks[i]) - } - } - return idisks, nil -} - -func (storage *SStorage) GetStorageType() string { - if len(storage.ExtraSpecs.VolumeBackendName) == 0 { - return DEFAULT_STORAGE_TYPE - } - return storage.ExtraSpecs.VolumeBackendName -} - -func (storage *SStorage) GetMediumType() string { - if strings.Contains(storage.Name, "SSD") { - return api.DISK_TYPE_SSD - } - return api.DISK_TYPE_ROTATE -} - -func (storage *SStorage) GetCapacityMB() int64 { - return 0 // unlimited -} - -func (storage *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (storage *SStorage) GetStorageConf() jsonutils.JSONObject { - conf := jsonutils.NewDict() - return conf -} - -func (storage *SStorage) GetStatus() string { - ok, err := storage.zone.region.IsStorageAvailable(storage.GetStorageType()) - if err != nil || !ok { - return api.STORAGE_OFFLINE - } - return api.STORAGE_ONLINE -} - -func (storage *SStorage) Refresh() error { - // do nothing - return nil -} - -func (storage *SStorage) GetEnabled() bool { - return true -} - -func (storage *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return storage.zone.region.getStoragecache() -} - -func (storage *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - disk, err := storage.zone.region.CreateDisk("", storage.Name, conf.Name, conf.SizeGb, conf.Desc, conf.ProjectId) - if err != nil { - log.Errorf("createDisk fail %v", err) - return nil, err - } - disk.storage = storage - return disk, cloudprovider.WaitStatus(disk, api.DISK_READY, time.Second*5, time.Minute*5) -} - -func (storage *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - disk, err := storage.zone.region.GetDisk(idStr) - if err != nil { - return nil, err - } - if disk.AvailabilityZone != storage.zone.ZoneName { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "disk %s not in zone %s", disk.Name, storage.zone.ZoneName) - } - disk.storage = storage - return disk, nil -} - -func (storage *SStorage) GetMountPoint() string { - return "" -} - -func (storage *SStorage) IsSysDiskStore() bool { - return true -} - -func (region *SRegion) GetStorageTypes() ([]SStorage, error) { - resource := "/types" - storages := []SStorage{} - query := url.Values{} - for { - resp, err := region.bsList(resource, query) - if err != nil { - return nil, errors.Wrap(err, "bsReqest") - } - part := struct { - VolumeTypes []SStorage - VolumeTypeLinks SNextLinks - }{} - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - storages = append(storages, part.VolumeTypes...) - marker := part.VolumeTypeLinks.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return storages, nil -} - -type SCinderService struct { - ActiveBackendId string - // cinder-volume - Binary string - DisabledReason string - Frozen string - Host string - ReplicationStatus string - State string - Status string - UpdatedAt time.Time - Zone string -} - -func (region *SRegion) GetCinderServices() ([]SCinderService, error) { - resp, err := region.bsList("/os-services", nil) - if err != nil { - return nil, errors.Wrap(err, "bsList") - } - services := []SCinderService{} - err = resp.Unmarshal(&services, "services") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return services, nil -} - -func (region *SRegion) IsStorageAvailable(storageType string) (bool, error) { - if utils.IsInStringArray(storageType, []string{DEFAULT_STORAGE_TYPE, api.STORAGE_OPENSTACK_NOVA}) { - return true, nil - } - services, err := region.GetCinderServices() - if err != nil { - return false, errors.Wrap(err, "GetCinderServices") - } - for _, service := range services { - if service.Binary == "cinder-volume" && strings.Contains(service.Host, "@") { - hostInfo := strings.Split(service.Host, "@") - if hostInfo[len(hostInfo)-1] == storageType { - if service.State == "up" && service.Status == "enabled" { - return true, nil - } - } - } - } - log.Errorf("storage %s offline", storageType) - return false, nil -} - -type SCapabilities struct { -} - -type SPool struct { - Name string - Capabilities SCapabilities -} - -func (region *SRegion) GetSchedulerStatsPool() ([]SPool, error) { - resp, err := region.bsList("/scheduler-stats/get_pools", nil) - if err != nil { - return nil, errors.Wrap(err, "bsList") - } - pools := []SPool{} - err = resp.Unmarshal(&pools, "pools") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return pools, nil -} diff --git a/pkg/multicloud/openstack/storagecache.go b/pkg/multicloud/openstack/storagecache.go deleted file mode 100644 index a17d65ffa1..0000000000 --- a/pkg/multicloud/openstack/storagecache.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "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" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.OpenStackTags - region *SRegion -} - -func (cache *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", cache.region.client.cpcfg.Id, cache.region.GetId()) -} - -func (cache *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", cache.region.client.cpcfg.Name, cache.region.GetId()) -} - -func (cache *SStoragecache) GetStatus() string { - return "available" -} - -func (cache *SStoragecache) Refresh() error { - return nil -} - -func (cache *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", cache.region.client.cpcfg.Id, cache.region.GetGlobalId()) -} - -func (cache *SStoragecache) IsEmulated() bool { - return false -} - -func (cache *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - images, err := cache.region.GetImages("", ACTIVE, "") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudImage{} - for i := 0; i < len(images); i++ { - images[i].storageCache = cache - ret = append(ret, &images[i]) - } - return ret, nil -} - -func (cache *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (cache *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - image, err := cache.region.GetImage(extId) - if err != nil { - return nil, err - } - image.storageCache = cache - return image, nil -} - -func (cache *SStoragecache) GetPath() string { - return "" -} - -func (cache *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return cache.uploadImage(ctx, userCred, image, callback) -} - -func (cache *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - s := auth.GetAdminSession(ctx, options.Options.Region) - - meta, reader, size, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false) - if err != nil { - return "", err - } - log.Infof("meta data %s", meta) - - imageBaseName := image.ImageName - imageName := imageBaseName - nameIdx := 1 - - for { - _, err = cache.region.GetImageByName(imageName) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - break - } else { - return "", err - } - } - imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) - nameIdx++ - } - - minDiskSizeMb, _ := meta.Int("min_disk") - minRamMb, _ := meta.Int("min_ram") - osType, _ := meta.GetString("properties", "os_type") - osDist, _ := meta.GetString("properties", "os_distribution") - minDiskSizeGB := minDiskSizeMb / 1024 - if minDiskSizeMb%1024 > 0 { - minDiskSizeGB += 1 - } - - img, err := cache.region.CreateImage(imageName, osType, osDist, int(minDiskSizeGB), int(minRamMb), size, reader, callback) - if err != nil { - return "", err - } - - img.storageCache = cache - - err = cloudprovider.WaitStatus(img, api.CACHED_IMAGE_STATUS_ACTIVE, 15*time.Second, 3600*time.Second) - if err != nil { - return "", errors.Wrapf(err, "WaitStatus") - } - - if callback != nil { - callback(100) - } - - return img.Id, nil -} - -func (cache *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (cache *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} diff --git a/pkg/multicloud/openstack/vpc.go b/pkg/multicloud/openstack/vpc.go deleted file mode 100644 index d867a3f9bc..0000000000 --- a/pkg/multicloud/openstack/vpc.go +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - "net/url" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - VPC_STATUS_ACTIVE = "ACTIVE" - VPC_STATUS_DOWN = "DOWN" - VPC_STATUS_BUILD = "BUILD" - VPC_STATUS_ERROR = "ERROR" -) - -type SVpc struct { - multicloud.SVpc - multicloud.OpenStackTags - region *SRegion - - AdminStateUp bool - AvailabilityZoneHints []string - AvailabilityZones []string - CreatedAt time.Time - DnsDomain string - Id string - Ipv4AddressScope string - Ipv6AddressScope string - L2Adjacency bool - Mtu int - Name string - PortSecurityEnabled bool - ProjectID string - QosPolicyID string - RevisionNumber int - External bool `json:"router:external"` - Shared bool - Status string - Subnets []string - TenantID string - UpdatedAt time.Time - VlanTransparent bool - Fescription string - IsDefault bool - NetworkType string `json:"provider:network_type"` // flat, vlan, vxlan, or gre ... - PhysicalNetwork string `json:"provider:physical_network"` - SegmentationId string `json:"provider:segmentation_id"` -} - -func (vpc *SVpc) GetId() string { - return vpc.Id -} - -func (vpc *SVpc) GetName() string { - if len(vpc.Name) > 0 { - return vpc.Name - } - return vpc.Id -} - -func (vpc *SVpc) GetGlobalId() string { - return vpc.Id -} - -func (vpc *SVpc) IsEmulated() bool { - return false -} - -func (vpc *SVpc) GetIsDefault() bool { - return vpc.IsDefault -} - -func (vpc *SVpc) GetCidrBlock() string { - return "" -} - -func (vpc *SVpc) GetStatus() string { - switch vpc.Status { - case VPC_STATUS_ACTIVE: - return api.VPC_STATUS_AVAILABLE - case VPC_STATUS_BUILD, VPC_STATUS_DOWN: - return api.VPC_STATUS_PENDING - case VPC_STATUS_ERROR: - return api.VPC_STATUS_FAILED - default: - return api.VPC_STATUS_UNKNOWN - } -} - -func (vpc *SVpc) Delete() error { - return vpc.region.DeleteVpc(vpc.Id) -} - -func (region *SRegion) DeleteVpc(vpcId string) error { - resource := fmt.Sprintf("/v2.0/networks/%s", vpcId) - _, err := region.vpcDelete(resource) - return err -} - -func (vpc *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - err := vpc.region.client.fetchProjects() - if err != nil { - return nil, errors.Wrap(err, "fetchProjects") - } - iSecgroups := []cloudprovider.ICloudSecurityGroup{} - for _, project := range vpc.region.client.projects { - secgroups, err := vpc.region.GetSecurityGroups(project.Id, "") - if err != nil { - return nil, errors.Wrapf(err, "GetSecurityGroups(%s)", project.Id) - } - for i := 0; i < len(secgroups); i++ { - secgroups[i].region = vpc.region - iSecgroups = append(iSecgroups, &secgroups[i]) - } - } - return iSecgroups, nil -} - -func (vpc *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - if vpc.PhysicalNetwork == "public" { - return []cloudprovider.ICloudRouteTable{}, nil - } - err := vpc.region.fetchrouters() - if err != nil { - return nil, errors.Wrap(err, "vpc.region.fetchrouters()") - } - routeTables := []SRouteTable{} - for index, router := range vpc.region.routers { - if len(router.Routes) < 1 { - continue - } - for _, port := range router.ports { - if port.NetworkID == vpc.GetId() { - routeTable := SRouteTable{} - routeTable.entries = router.Routes - routeTable.router = &vpc.region.routers[index] - routeTable.vpc = vpc - routeTables = append(routeTables, routeTable) - break - } - } - } - ret := []cloudprovider.ICloudRouteTable{} - for i := range routeTables { - ret = append(ret, &routeTables[i]) - } - return ret, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (vpc *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { - iwires, err := vpc.GetIWires() - if err != nil { - return nil, errors.Wrap(err, "GetIWires") - } - for i := range iwires { - if iwires[i].GetGlobalId() == wireId { - return iwires[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (vpc *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - return []cloudprovider.ICloudWire{&SWire{vpc: vpc}}, nil -} - -func (vpc *SVpc) GetRegion() cloudprovider.ICloudRegion { - return vpc.region -} - -func (region *SRegion) GetVpc(vpcId string) (*SVpc, error) { - vpc := &SVpc{region: region} - resource := fmt.Sprintf("/v2.0/networks/%s", vpcId) - resp, err := region.vpcGet(resource) - if err != nil { - return nil, errors.Wrapf(err, "vpcGet(%s)", resource) - } - err = resp.Unmarshal(vpc, "network") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return vpc, nil -} - -func (region *SRegion) GetVpcs(projectId string) ([]SVpc, error) { - vpcs := []SVpc{} - resource := "/v2.0/networks" - query := url.Values{} - if len(projectId) > 0 { - query.Set("tenant_id", projectId) - } - for { - resp, err := region.vpcList(resource, query) - if err != nil { - return nil, errors.Wrapf(err, "vpcList.%s", resource) - } - - part := struct { - Networks []SVpc - NetworksLinks SNextLinks - }{} - - err = resp.Unmarshal(&part) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - vpcs = append(vpcs, part.Networks...) - marker := part.NetworksLinks.GetNextMark() - if len(marker) == 0 { - break - } - query.Set("marker", marker) - } - return vpcs, nil -} - -func (vpc *SVpc) Refresh() error { - _vpc, err := vpc.region.GetVpc(vpc.Id) - if err != nil { - return errors.Wrapf(err, "GetVpc(%s)", vpc.Id) - } - return jsonutils.Update(vpc, _vpc) -} - -func (region *SRegion) CreateVpc(name, desc string) (*SVpc, error) { - params := map[string]map[string]string{ - "network": { - "name": name, - "description": desc, - }, - } - resource := "/v2.0/networks" - resp, err := region.vpcPost(resource, params) - if err != nil { - return nil, errors.Wrap(err, "vpcPost") - } - vpc := &SVpc{region: region} - err = resp.Unmarshal(vpc, "network") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return vpc, nil -} diff --git a/pkg/multicloud/openstack/wire.go b/pkg/multicloud/openstack/wire.go deleted file mode 100644 index 5ce202e802..0000000000 --- a/pkg/multicloud/openstack/wire.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.OpenStackTags - - vpc *SVpc -} - -func (wire *SWire) GetId() string { - return wire.vpc.GetId() -} - -func (wire *SWire) GetName() string { - return wire.GetId() -} - -func (wire *SWire) IsEmulated() bool { - return true -} - -func (wire *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (wire *SWire) Refresh() error { - return nil -} - -func (wire *SWire) GetGlobalId() string { - return wire.vpc.GetGlobalId() -} - -func (wire *SWire) GetIVpc() cloudprovider.ICloudVpc { - return wire.vpc -} - -func (wire *SWire) GetIZone() cloudprovider.ICloudZone { - return nil -} - -func (wire *SWire) GetBandwidth() int { - return 10000 -} - -func (wire *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - network, err := wire.vpc.region.CreateNetwork(wire.vpc.Id, opts.ProjectId, opts.Name, opts.Cidr, opts.Desc) - if err != nil { - return nil, errors.Wrap(err, "CreateNetwork") - } - network.wire = wire - return network, nil -} - -func (wire *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { - networks, err := wire.GetINetworks() - if err != nil { - return nil, err - } - for i := 0; i < len(networks); i++ { - if networks[i].GetGlobalId() == netid { - return networks[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, netid) -} - -func (wire *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - _networks, err := wire.vpc.region.GetNetworks(wire.vpc.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetNetworks(%s)", wire.vpc.Id) - } - networks := []SNetwork{} - for i := range _networks { - pools := _networks[i].AllocationPools - for j := range pools { - if !pools[j].IsValid() { - continue - } - _networks[i].AllocationPools = []AllocationPool{pools[j]} - networks = append(networks, _networks[i]) - } - } - inetworks := []cloudprovider.ICloudNetwork{} - for i := range networks { - networks[i].wire = wire - inetworks = append(inetworks, &networks[i]) - } - return inetworks, nil -} diff --git a/pkg/multicloud/openstack/zone.go b/pkg/multicloud/openstack/zone.go deleted file mode 100644 index 2e9fcb2919..0000000000 --- a/pkg/multicloud/openstack/zone.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 openstack - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type ZoneState struct { - Available bool -} - -type HostState struct { - Available bool - Active bool - UpdatedAt time.Time -} - -type SZone struct { - multicloud.SResourceBase - multicloud.OpenStackTags - region *SRegion - - ZoneName string - ZoneState ZoneState - - Hosts map[string]jsonutils.JSONObject - - hosts []SHypervisor -} - -func (zone *SZone) GetId() string { - return zone.ZoneName -} - -func (zone *SZone) GetName() string { - return zone.ZoneName -} - -func (zone *SZone) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(zone.GetName()).CN(zone.GetName()) - return table -} - -func (zone *SZone) GetGlobalId() string { - return fmt.Sprintf("%s/%s/%s", CLOUD_PROVIDER_OPENSTACK, zone.region.Name, zone.ZoneName) -} - -func (zone *SZone) IsEmulated() bool { - return false -} - -func (zone *SZone) GetStatus() string { - if zone.ZoneState.Available { - return api.ZONE_ENABLE - } - return api.ZONE_DISABLE -} - -func (zone *SZone) Refresh() error { - // do nothing - return nil -} - -func (zone *SZone) GetIRegion() cloudprovider.ICloudRegion { - return zone.region -} - -func (zone *SZone) getStorageByCategory(category, host string) (*SStorage, error) { - storages, err := zone.region.GetStorageTypes() - if err != nil { - return nil, errors.Wrap(err, "GetStorageTypes") - } - for i := range storages { - if storages[i].Name == category || storages[i].ExtraSpecs.VolumeBackendName == category { - storages[i].zone = zone - return &storages[i], nil - } - } - for i := range storages { - if strings.HasSuffix(host, "#"+storages[i].Name) || strings.HasSuffix(host, "#"+storages[i].ExtraSpecs.VolumeBackendName) { - storages[i].zone = zone - return &storages[i], nil - } - } - return nil, fmt.Errorf("No such storage [%s]", category) -} - -func (zone *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := zone.region.GetStorageTypes() - if err != nil && errors.Cause(err) != ErrNoEndpoint { - return nil, errors.Wrap(err, "GetStorageTypes") - } - istorages := []cloudprovider.ICloudStorage{} - for i := range storages { - storages[i].zone = zone - istorages = append(istorages, &storages[i]) - } - err = zone.fetchHosts() - if err != nil { - return nil, errors.Wrap(err, "fetchHosts") - } - for i := range zone.hosts { - nova := &SNovaStorage{host: &zone.hosts[i], zone: zone} - istorages = append(istorages, nova) - } - return istorages, nil -} - -func (zone *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - istorages, err := zone.GetIStorages() - if err != nil { - return nil, errors.Wrap(err, "GetIStorages") - } - for i := 0; i < len(istorages); i++ { - if istorages[i].GetGlobalId() == id { - return istorages[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (zone *SZone) fetchHosts() error { - if len(zone.hosts) > 0 { - return nil - } - - zone.hosts = []SHypervisor{} - hypervisors, err := zone.region.GetHypervisors() - if err != nil { - return errors.Wrap(err, "GetHypervisors") - } - for i := range hypervisors { - hypervisor := strings.ToLower(hypervisors[i].HypervisorType) - // 过滤vmware的机器 - if strings.Index(hypervisor, "vmware") != -1 { - continue - } - - _, ok1 := zone.Hosts[hypervisors[i].HypervisorHostname] - _, ok2 := zone.Hosts[hypervisors[i].Service.Host] - if !ok1 && !ok2 { - continue - } - zone.hosts = append(zone.hosts, hypervisors[i]) - } - return nil - -} - -func (zone *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - err := zone.fetchHosts() - if err != nil { - return nil, errors.Wrap(err, "fetchHosts") - } - ihosts := []cloudprovider.ICloudHost{} - for i := range zone.hosts { - zone.hosts[i].zone = zone - ihosts = append(ihosts, &zone.hosts[i]) - } - return ihosts, nil -} - -func (zone *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - ihosts, err := zone.GetIHosts() - if err != nil { - return nil, errors.Wrap(err, "GetIHosts") - } - for i := range ihosts { - if ihosts[i].GetGlobalId() == id { - return ihosts[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) getZones() ([]SZone, error) { - zones := []SZone{} - resp, err := region.ecsList("os-availability-zone/detail", nil) - if err != nil { - return nil, errors.Wrap(err, "ecsList.os-availability-zone") - } - err = resp.Unmarshal(&zones, "availabilityZoneInfo") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return zones, nil -} diff --git a/pkg/multicloud/proxmox/disk.go b/pkg/multicloud/proxmox/disk.go deleted file mode 100644 index 97df7566fc..0000000000 --- a/pkg/multicloud/proxmox/disk.go +++ /dev/null @@ -1,236 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - "context" - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDisk struct { - multicloud.SDisk - multicloud.ProxmoxTags - - region *SRegion - - Storage string - Node string - DiskDriver string - DriverIdx int - VmId int - CacheMode string - - Format string `json:"format"` - Size int64 `json:"size"` - VolId string `json:"volid"` - Name string `json:"name"` - Parent string `json:"parent"` - Content string `json:"content"` -} - -func (self *SDisk) GetName() string { - return self.Name -} - -func (self *SDisk) GetId() string { - return self.VolId -} - -func (self *SDisk) GetGlobalId() string { - return self.GetId() -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SDisk) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SDisk) GetCacheMode() string { - return self.CacheMode -} - -func (self *SDisk) GetFsFormat() string { - return "" -} - -func (self *SDisk) GetIsNonPersistent() bool { - return false -} - -func (self *SDisk) GetDriver() string { - return self.DiskDriver -} - -func (self *SDisk) GetDiskType() string { - return api.DISK_TYPE_DATA -} - -func (self *SDisk) GetDiskFormat() string { - return strings.ToLower(self.Format) -} - -func (self *SDisk) GetDiskSizeMB() int { - return int(self.Size / 1024 / 1024) -} - -func (self *SDisk) GetIsAutoDelete() bool { - return true -} - -func (self *SDisk) GetMountpoint() string { - return "" -} - -func (self *SDisk) GetStatus() string { - return api.DISK_READY -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { - return self.region.ResizeDisk(self.VolId, int(sizeMb/1024)) -} - -func (self *SDisk) GetTemplateId() string { - return "" -} - -func (self *SDisk) GetAccessPath() string { - return "" -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - DataStoreId := fmt.Sprintf("storage/%s/%s", self.Node, self.Storage) - return self.region.GetStorage(DataStoreId) -} - -func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - return []cloudprovider.ICloudSnapshot{}, nil -} - -func (self *SRegion) GetDisks(storageId string) ([]SDisk, error) { - vols := []SDisk{} - disks := []SDisk{} - - splited := strings.Split(storageId, "/") - nodeName := "" - storageName := "" - - if len(splited) == 3 { - nodeName, storageName = splited[1], splited[2] - } - - res := fmt.Sprintf("/nodes/%s/storage/%s/content", nodeName, storageName) - err := self.get(res, url.Values{}, &vols) - if err != nil { - return nil, err - } - for i := range vols { - _, diskName := ParseSubConf(vols[i].VolId, ":") - if err != nil { - continue - } - vols[i].Storage = storageName - vols[i].Node = nodeName - vols[i].Name = diskName.(string) - - disks = append(disks, vols[i]) - } - - return disks, nil -} - -func (self *SRegion) GetDisk(Id string) (*SDisk, error) { - - vols := []SDisk{} - nodeName := "" - storageName, diskName := ParseSubConf(Id, ":") - resources, err := self.GetClusterStoragesResources() - if err != nil { - return nil, err - } - - if res, ok := resources[storageName]; !ok { - return nil, errors.Errorf("self.GetDisk") - } else { - nodeName = res.Node - } - - res := fmt.Sprintf("/nodes/%s/storage/%s/content", nodeName, storageName) - err = self.get(res, url.Values{}, &vols) - if err != nil { - return nil, errors.Wrapf(err, "self.GetDisk") - } - - for _, vol := range vols { - if vol.VolId == Id { - ret := &SDisk{ - region: self, - Storage: storageName, - Node: nodeName, - Format: vol.Format, - Size: vol.Size, - VolId: vol.VolId, - Name: diskName.(string), - Parent: vol.Parent, - VmId: vol.VmId, - Content: vol.Content, - } - return ret, nil - } - } - - return nil, errors.Errorf("self.GetDisk failed to get disk by %s", Id) -} - -func (self *SRegion) ResizeDisk(id string, sizeGb int) error { - disk, err := self.GetDisk(id) - if err != nil { - return errors.Wrapf(err, "GetDisk(%s)", id) - } - // not support unmount disk - if disk.VmId < 1 { - return nil - } - body := map[string]interface{}{ - "disk": fmt.Sprintf("%s%d", disk.DiskDriver, disk.DriverIdx), - "size": sizeGb, - } - - res := fmt.Sprintf("/nodes/%s/qemu/%d/resize", disk.Node, disk.VmId) - return self.put(res, nil, jsonutils.Marshal(body), nil) -} diff --git a/pkg/multicloud/proxmox/doc.go b/pkg/multicloud/proxmox/doc.go deleted file mode 100644 index 001c77cb57..0000000000 --- a/pkg/multicloud/proxmox/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox // import "yunion.io/x/onecloud/pkg/multicloud/proxmox" diff --git a/pkg/multicloud/proxmox/host.go b/pkg/multicloud/proxmox/host.go deleted file mode 100644 index 932442d8c4..0000000000 --- a/pkg/multicloud/proxmox/host.go +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - "fmt" - "net/url" - "strconv" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SHost struct { - multicloud.SHostBase - multicloud.ProxmoxTags - zone *SZone - - Id string - Node string - - Uptime int `json:"uptime"` - Wait int `json:"wait"` - Idle int `json:"idle"` - Kversion string `json:"kversion"` - Pveversion string `json:"pveversion"` - CPU int `json:"cpu"` - Loadavg []string `json:"loadavg"` - Rootfs Rootfs `json:"rootfs"` - Swap Swap `json:"swap"` - Memory Memory `json:"memory"` - Cpuinfo Cpuinfo `json:"cpuinfo"` - Ksm Ksm `json:"ksm"` -} - -type Rootfs struct { - Used int64 `json:"used"` - Total int64 `json:"total"` - Avail int64 `json:"avail"` - Free int64 `json:"free"` -} - -type Swap struct { - Free int64 `json:"free"` - Used int64 `json:"used"` - Total int64 `json:"total"` -} - -type Memory struct { - Free int64 `json:"free"` - Used int64 `json:"used"` - Total int64 `json:"total"` -} - -type Cpuinfo struct { - Flags string `json:"flags"` - Hvm string `json:"hvm"` - Cores int `json:"cores"` - Model string `json:"model"` - Mhz float64 `json:"mhz"` - Cpus int `json:"cpus"` - UserHz int `json:"user_hz"` - Sockets int `json:"sockets"` -} - -type Ksm struct { - Shared int `json:"shared"` -} - -func (self *SHost) GetId() string { - return self.Id -} - -func (self *SHost) GetGlobalId() string { - return self.Id -} - -func (self *SHost) GetName() string { - return self.Node -} - -func (self *SHost) GetEnabled() bool { - return true -} - -func (self *SHost) GetHostStatus() string { - return api.HOST_ONLINE -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) GetAccessIp() string { - return "" -} - -func (self *SHost) GetAccessMac() string { - return "" -} - -func (self *SHost) GetSysInfo() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (self *SHost) GetSN() string { - return "" -} - -func (self *SHost) GetCpuCount() int { - return int(self.Cpuinfo.Cores) -} - -func (self *SHost) GetNodeCount() int8 { - return int8(self.Cpuinfo.Sockets) -} - -func (self *SHost) GetCpuDesc() string { - return self.Cpuinfo.Model -} - -func (self *SHost) GetCpuMhz() int { - return int(self.Cpuinfo.Mhz) -} - -func (self *SHost) GetCpuCmtbound() float32 { - return 1 -} - -func (self *SHost) GetMemSizeMB() int { - return int(self.Memory.Total / 1024 / 1024) -} - -func (self *SHost) GetMemCmtbound() float32 { - return 1 -} - -func (self *SHost) GetReservedMemoryMb() int { - return 0 -} - -func (self *SHost) GetStorageSizeMB() int { - return int(self.Rootfs.Total / 1024 / 1024) -} - -func (self *SHost) GetStorageType() string { - return api.STORAGE_LOCAL -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_PROXMOX -} - -func (self *SHost) GetIsMaintenance() bool { - return false -} - -func (self *SHost) GetVersion() string { - return self.Pveversion -} - -func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - - vmId := self.zone.region.GetClusterVmMaxId() - if vmId == -1 { - return nil, errors.Errorf("failed to get vm number by %d", vmId) - } else { - vmId++ - } - - splited := strings.Split(opts.SysDisk.StorageExternalId, "/") - storage := splited[2] - - body := map[string]interface{}{ - "vmid": vmId, - "name": opts.Name, - "ostype": "other", - "sockets": 1, - "cores": opts.Cpu, - "cpu": "host", - "kvm": 1, - "hotplug": "network,disk,usb", - "memory": opts.MemoryMB, - "description": opts.OsDistribution, - "scsihw": "virtio-scsi-pci", - "scsi0": fmt.Sprintf("%s:%d", storage, opts.SysDisk.SizeGB), - } - - res := fmt.Sprintf("/nodes/%s/qemu", self.Node) - _, err := self.zone.region.post(res, jsonutils.Marshal(body)) - if err != nil { - return nil, err - } - - vmIdRet := strconv.Itoa(vmId) - vm, err := self.zone.region.GetInstance(vmIdRet) - if err != nil { - return nil, err - } - - for k, _ := range vm.QemuDisks { - _, diskName := ParseSubConf(k, ":") - opts.SysDisk.Name = diskName.(string) - break - } - - vm.host = self - return vm, nil -} - -func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms, err := self.zone.region.GetInstances(self.Id) - if err != nil { - return nil, errors.Wrapf(err, "GetInstances") - } - ret := []cloudprovider.ICloudVM{} - for i := range vms { - vms[i].host = self - ret = append(ret, &vms[i]) - } - return ret, nil -} - -func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.zone.region.GetInstance(id) - if err != nil { - return nil, err - } - hostId := fmt.Sprintf("node/%s", vm.Node) - if hostId != self.Id { - return nil, cloudprovider.ErrNotFound - } - vm.host = self - return vm, nil -} - -func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - wires, err := self.zone.region.GetWires() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudWire{} - for i := range wires { - wires[i].region = self.zone.region - ret = append(ret, &wires[i]) - } - return ret, nil -} - -func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := self.zone.region.GetStoragesByHost(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStorage{} - for i := range storages { - storages[i].zone = self.zone - ret = append(ret, &storages[i]) - } - return ret, nil -} - -func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storage, err := self.zone.region.GetStorage(id) - if err != nil { - return nil, err - } - storage.zone = self.zone - - return storage, nil -} - -func (self *SRegion) GetHosts() ([]SHost, error) { - hosts := []SHost{} - resources, err := self.GetClusterNodeResources() - if err != nil { - return nil, err - } - - for _, res := range resources { - host := &SHost{} - status := fmt.Sprintf("nodes/%s/status", res.Node) - err := self.get(status, url.Values{}, host) - if err != nil { - return nil, err - } - host.Id = res.Id - host.Node = res.Node - hosts = append(hosts, *host) - } - - return hosts, nil -} - -func (self *SRegion) GetHost(id string) (*SHost, error) { - ret := &SHost{} - nodeName := "" - - //"id": "node/nodeNAME", - splited := strings.Split(id, "/") - if len(splited) == 2 { - nodeName = splited[1] - } - - res := fmt.Sprintf("nodes/%s/status", nodeName) - err := self.get(res, url.Values{}, ret) - if err != nil { - return nil, err - } - ret.Id = id - ret.Node = nodeName - - return ret, nil -} diff --git a/pkg/multicloud/proxmox/image.go b/pkg/multicloud/proxmox/image.go deleted file mode 100644 index b12d745744..0000000000 --- a/pkg/multicloud/proxmox/image.go +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - "context" - "fmt" - "net/url" - "regexp" - "strconv" - "strings" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type SImage struct { - multicloud.SImageBase - multicloud.ProxmoxTags - cache *SStoragecache - - imageInfo *imagetools.ImageInfo - - VmId int - Node string - Name string - Format string - SizeGB float64 -} - -func (self *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (self *SImage) GetId() string { - return fmt.Sprintf("%d", self.VmId) -} - -func (self *SImage) GetName() string { - return self.Name -} - -func (self *SImage) Delete(ctx context.Context) error { - return cloudprovider.ErrNotImplemented -} - -func (self *SImage) GetGlobalId() string { - return self.GetId() -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.cache -} - -func (self *SImage) GetStatus() string { - return api.CACHED_IMAGE_STATUS_ACTIVE -} - -func (self *SImage) GetImageStatus() string { - return cloudprovider.IMAGE_STATUS_ACTIVE -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - return cloudprovider.ImageTypeSystem -} - -func (self *SImage) GetSizeByte() int64 { - return int64(self.SizeGB * 1024 * 1024) -} - -func (img *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if img.imageInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(img.Name, "", "", "", "") - img.imageInfo = &imgInfo - } - return img.imageInfo -} - -func (img *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(img.getNormalizedImageInfo().OsType) -} - -func (img *SImage) GetOsDist() string { - return img.getNormalizedImageInfo().OsDistro -} - -func (img *SImage) GetOsVersion() string { - return img.getNormalizedImageInfo().OsVersion -} - -func (img *SImage) GetOsArch() string { - return img.getNormalizedImageInfo().OsArch -} - -func (img *SImage) GetOsLang() string { - return img.getNormalizedImageInfo().OsLang -} - -func (img *SImage) GetFullOsName() string { - return img.Name -} - -func (img *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.BIOS -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - if self.GetOsType() == "windows" { - return 40 - } - return 30 -} - -func (self *SImage) GetImageFormat() string { - return "raw" -} - -func (self *SRegion) GetImageList() ([]SImage, error) { - ret := []SImage{} - resources, err := self.GetClusterVmResources() - if err != nil { - return nil, err - } - for _, vm := range resources { - if vm.Template == true { - image := SImage{ - VmId: vm.VmId, - Name: vm.Name, - Node: vm.Node, - } - - res := fmt.Sprintf("/nodes/%s/qemu/%d/config", image.Node, image.VmId) - vmConfig := map[string]interface{}{} - err := self.get(res, url.Values{}, &vmConfig) - if err != nil { - return nil, err - } - - diskNames := []string{} - for k := range vmConfig { - if diskName := regexp.MustCompile(`(virtio|scsi|sata)\d+`).FindStringSubmatch(k); len(diskName) > 0 { - diskNames = append(diskNames, diskName[0]) - } - } - - for _, diskName := range diskNames { - diskConfStr := vmConfig[diskName].(string) - diskConfMap := ParsePMConf(diskConfStr, "volume") - - if diskConfMap["volume"].(string) == "none" { - continue - } - if diskConfMap["media"] != nil { - continue - } - - storageName, fileName := ParseSubConf(diskConfMap["volume"].(string), ":") - diskConfMap["storage"] = storageName - diskConfMap["file"] = fileName - - // cloud-init disks not always have the size sent by the API, which results in a crash - if diskConfMap["size"] == nil && strings.Contains(fileName.(string), "cloudinit") { - diskConfMap["size"] = "4M" // default cloud-init disk size - } - - image.SizeGB += DiskSizeGB(diskConfMap["size"]) - - } - ret = append(ret, image) - } - } - - return ret, nil -} - -func (self *SRegion) GetImage(id string) (*SImage, error) { - image := &SImage{} - vmId, err := strconv.Atoi(id) - if err != nil { - return nil, err - } - resources, err := self.GetClusterVmResources() - if err != nil { - return nil, err - } - if resources[vmId].Template == false { - return nil, errors.Errorf("self.GetDisk") - } - image.VmId = resources[vmId].VmId - image.Name = resources[vmId].Name - image.Node = resources[vmId].Node - res := fmt.Sprintf("/nodes/%s/qemu/%d/config", image.Node, image.VmId) - vmConfig := map[string]interface{}{} - err = self.get(res, url.Values{}, &vmConfig) - if err != nil { - return nil, err - } - - diskNames := []string{} - for k := range vmConfig { - if diskName := regexp.MustCompile(`(virtio|scsi|sata)\d+`).FindStringSubmatch(k); len(diskName) > 0 { - diskNames = append(diskNames, diskName[0]) - } - } - - for _, diskName := range diskNames { - diskConfStr := vmConfig[diskName].(string) - diskConfMap := ParsePMConf(diskConfStr, "volume") - - if diskConfMap["volume"].(string) == "none" || diskConfMap["media"].(string) == "cdrom" { - continue - } - - storageName, fileName := ParseSubConf(diskConfMap["volume"].(string), ":") - diskConfMap["storage"] = storageName - diskConfMap["file"] = fileName - - // cloud-init disks not always have the size sent by the API, which results in a crash - if diskConfMap["size"] == nil && strings.Contains(fileName.(string), "cloudinit") { - diskConfMap["size"] = "4M" // default cloud-init disk size - } - - var sizeInTerabytes = regexp.MustCompile(`[0-9]+T`) - // Convert to gigabytes if disk size was received in terabytes - matched := sizeInTerabytes.MatchString(diskConfMap["size"].(string)) - if matched { - image.SizeGB += DiskSizeGB(diskConfMap["size"]) - } - - } - - return image, nil -} diff --git a/pkg/multicloud/proxmox/instance.go b/pkg/multicloud/proxmox/instance.go deleted file mode 100644 index 44724b25f9..0000000000 --- a/pkg/multicloud/proxmox/instance.go +++ /dev/null @@ -1,1019 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - "context" - "encoding/json" - "fmt" - "net/url" - "regexp" - "sort" - "strconv" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/osprofile" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var ( - rxIso = regexp.MustCompile(`(.*?),media`) - rxDeviceID = regexp.MustCompile(`\d+`) - rxDiskName = regexp.MustCompile(`(virtio|scsi|sata|ide)\d+`) - rxDiskType = regexp.MustCompile(`\D+`) - rxUnusedDiskName = regexp.MustCompile(`^(unused)\d+`) - rxNicName = regexp.MustCompile(`net\d+`) - rxSerialName = regexp.MustCompile(`serial\d+`) - rxUsbName = regexp.MustCompile(`usb\d+`) -) - -type ( - QemuDevices map[string]map[string]interface{} - QemuDevice map[string]interface{} - QemuDeviceParam []string -) - -type Intermediate struct { - HardwareAddress string `json:"hardware-address"` - IPAddresses []struct { - IPAddress string `json:"ip-address"` - IPAddressType string `json:"ip-address-type"` - Prefix int `json:"prefix"` - } `json:"ip-addresses"` - Name string `json:"name"` - Statistics map[string]int64 `json:"statistics"` -} - -type VmBase struct { - Name string `json:"name"` - Description string `json:"Description"` - Tags string `json:"tags"` - Args string `json:"args"` - Bios string `json:"bios"` - OnBoot int `json:"onboot"` - Startup string `json:"startup"` - Tablet int `json:"tablet"` - Ostype string `json:"ostype"` - Memory int64 `json:"memory"` - Balloon int64 `json:"balloon"` - Cores int64 `json:"cores"` - Vcpus int64 `json:"vcpus"` - Sockets int64 `json:"sockets"` - Cpu string `json:"cpu"` - Numa int `json:"numa"` - Hotplug string `json:"hotplug"` - Boot string `json:"boot"` - Bootdisk string `json:"bootdisk"` - Kvm int `json:"kvm"` - Scsihw string `json:"scsihw"` - Hookscript string `json:"hookscript"` - Machine string `json:"machine"` - Ide2 string `json:"ide2,omitempty"` - Ciuser string `json:"ciuser"` - Cipassword string `json:"cipassword"` - Cicustom string `json:"cicustom"` - Searchdomain string `json:"searchdomain"` - Nameserver string `json:"nameserver"` - Sshkeys string `json:"sshkeys"` -} - -type SInstance struct { - multicloud.SInstanceBase - multicloud.ProxmoxTags - - host *SHost - - QemuNetworks []SInstanceNic - PowerState string - Node string - - VmID int `json:"vmid"` - Name string `json:"name"` - Description string `json:"desc"` - Pool string `json:"pool,omitempty"` - Bios string `json:"bios"` - EFIDisk QemuDevice `json:"efidisk,omitempty"` - Machine string `json:"machine,omitempty"` - Onboot bool `json:"onboot"` - Startup string `json:"startup,omitempty"` - Tablet bool `json:"tablet"` - Agent int `json:"agent"` - Memory int `json:"memory"` - Balloon int `json:"balloon"` - QemuOs string `json:"ostype"` - QemuCores int `json:"cores"` - QemuSockets int `json:"sockets"` - QemuVcpus int `json:"vcpus"` - QemuCpu string `json:"cpu"` - QemuNuma bool `json:"numa"` - QemuKVM bool `json:"kvm"` - Hotplug string `json:"hotplug"` - QemuIso string `json:"iso"` - QemuPxe bool `json:"pxe"` - FullClone *int `json:"fullclone"` - Boot string `json:"boot"` - BootDisk string `json:"bootdisk,omitempty"` - Scsihw string `json:"scsihw,omitempty"` - QemuDisks QemuDevices `json:"disk"` - QemuUnusedDisks QemuDevices `json:"unused_disk"` - QemuVga QemuDevice `json:"vga,omitempty"` - QemuSerials QemuDevices `json:"serial,omitempty"` - QemuUsbs QemuDevices `json:"usb,omitempty"` - Hookscript string `json:"hookscript,omitempty"` - Tags string `json:"tags"` - Args string `json:"args"` - - // Deprecated single disk. - DiskSize float64 `json:"diskGB"` - Storage string `json:"storage"` - StorageType string `json:"storageType"` // virtio|scsi (cloud-init defaults to scsi) - - // Deprecated single nic. - QemuNicModel string `json:"nic"` - QemuBridge string `json:"bridge"` - QemuVlanTag int `json:"vlan"` - QemuMacAddr string `json:"mac"` - - // cloud-init options - CIuser string `json:"ciuser"` - CIpassword string `json:"cipassword"` - CIcustom string `json:"cicustom"` - - Searchdomain string `json:"searchdomain"` - Nameserver string `json:"nameserver"` - Sshkeys string `json:"sshkeys"` -} - -func (self *SInstance) GetName() string { - return self.Name -} - -func (self *SInstance) GetId() string { - return strconv.Itoa(self.VmID) -} - -func (self *SInstance) GetGlobalId() string { - return self.GetId() -} - -func (self *SInstance) Refresh() error { - id := strconv.Itoa(int(self.VmID)) - ins, err := self.host.zone.region.GetInstance(id) - if err != nil { - return err - } - return jsonutils.Update(self, ins) -} - -func (self *SInstance) AssignSecurityGroup(id string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return self.host.zone.region.AttachDisk(self.VmID, diskId) -} - -func (self *SInstance) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error { - return self.host.zone.region.ChangeConfig(self.VmID, opts.Cpu, opts.MemoryMB) -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - return self.host.zone.region.DeleteVM(self.VmID) -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return self.host.zone.region.ResetVmPassword(self.VmID, username, password) -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return self.host.zone.region.DetachDisk(self.VmID, diskId) -} - -func (self *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(self.Bios) -} - -func (self *SInstance) GetBootOrder() string { - return strings.ToLower(self.Boot) -} - -func (self *SInstance) GetError() error { - return nil -} - -func (self *SInstance) GetHostname() string { - return self.GetName() -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_PROXMOX -} - -func (self *SInstance) VMIdExists(vmId int) (bool, error) { - resources, err := self.host.zone.region.GetClusterVmResources() - if err != nil { - return false, err - } - - _, res := resources[vmId] - return res, nil -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - ret := []cloudprovider.ICloudDisk{} - id := self.VmID - - exist, err := self.VMIdExists(self.VmID) - if err != nil { - return nil, err - } - - if exist == false { - return nil, nil - } - - for k, v := range self.QemuDisks { - disk, err := self.host.zone.region.GetDisk(k) - if err != nil { - continue - } - disk.VmId = id - disk.DiskDriver = v["type"].(string) - disk.DriverIdx = v["slot"].(int) - if cache, ok := v["cache"].(string); ok { - disk.CacheMode = cache - } - ret = append(ret, disk) - } - - // for k, v := range self.QemuUnusedDisks { - // disk, err := self.host.zone.region.GetDisk(k) - // if err != nil { - // continue - // } - // disk.VmId = self.VmID - // disk.DriverIdx = v["slot"].(int) - // ret = append(ret, disk) - // } - - return ret, nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - ret := []cloudprovider.ICloudNic{} - for i := range self.QemuNetworks { - self.QemuNetworks[i].ins = self - ret = append(ret, &self.QemuNetworks[i]) - } - return ret, nil -} - -func (self *SInstance) GetInstanceType() string { - return fmt.Sprintf("ecs.g1.c%dm%d", self.GetVcpuCount(), self.GetVmemSizeMB()/1024) -} - -func (self *SInstance) GetMachine() string { - return self.Machine -} - -func (self *SInstance) GetStatus() string { - switch strings.ToLower(self.PowerState) { - case "running": - return api.VM_RUNNING - case "stopped": - return api.VM_READY - case "paused": - return api.VM_SUSPEND - } - return api.VM_UNKNOWN -} - -func (self *SInstance) GetFullOsName() string { - return "" -} - -func (self *SInstance) GetOsType() cloudprovider.TOsType { - isWin, _ := regexp.MatchString("(wxp|w2k|w2k3|w2k8|wvista|win7|win8|win10|win11)", self.QemuOs) - if isWin == true { - return cloudprovider.TOsType(osprofile.OS_TYPE_WINDOWS) - } else { - return cloudprovider.TOsType(osprofile.OS_TYPE_LINUX) - } -} - -func (ins *SInstance) GetOsArch() string { - return "x86_64" -} - -func (ins *SInstance) GetOsDist() string { - return "" -} - -func (ins *SInstance) GetOsVersion() string { - return "" -} - -func (ins *SInstance) GetOsLang() string { - return "" -} - -func (self *SInstance) GetProjectId() string { - return "" -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetVcpuCount() int { - return int(self.QemuCores * self.QemuSockets) -} - -func (self *SInstance) GetVmemSizeMB() int { - return int(self.Memory) -} - -func (self *SInstance) GetVga() string { - return "std" -} - -func (self *SInstance) GetVdi() string { - return "vnc" -} - -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - return []string{}, nil -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) StartVM(ctx context.Context) error { - return self.host.zone.region.StartVm(self.VmID) -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - if self.GetStatus() == api.VM_READY { - return nil - } - return self.host.zone.region.StopVm(self.VmID) -} - -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return cloudprovider.ErrNotSupported -} - -// readDeviceConfig - get standard sub-conf strings where `key=value` and update conf map. -func (confMap QemuDevice) readDeviceConfig(confList []string) error { - // Add device config. - for _, conf := range confList { - key, value := ParseSubConf(conf, "=") - confMap[key] = value - } - return nil -} - -func (self *SRegion) GetVmAgentNetworkInterfaces(node string, VmId int) (map[string]string, error) { - intermediates := []Intermediate{} - ipMap := map[string]string{} - res := fmt.Sprintf("/nodes/%s/qemu/%d/agent/network-get-interfaces", node, VmId) - err := self.getAgent(res, url.Values{}, &intermediates) - if err != nil { - return nil, errors.Wrap(err, "GetVmAgentNetworkInterfaces") - } - - for _, intermediate := range intermediates { - ipMap[intermediate.HardwareAddress] = intermediate.IPAddresses[0].IPAddress - } - - return ipMap, nil -} - -func (self *SRegion) GetVmPowerStatus(node string, VmId int) string { - current := map[string]string{} - res := fmt.Sprintf("/nodes/%s/qemu/%d/status/current", node, VmId) - err := self.get(res, url.Values{}, ¤t) - if err != nil { - return "unkown" - } - - power := "unkown" - if _, ok := current["qmpstatus"]; ok { - power = current["qmpstatus"] - } - - return power -} - -func (self *SRegion) GetQemuConfig(node string, VmId int) (*SInstance, error) { - //ret := &SInstance{} - res := fmt.Sprintf("/nodes/%s/qemu/%d/config", node, VmId) - vmConfig := map[string]interface{}{} - vmBase := &VmBase{ - Bios: "seabios", - OnBoot: 1, - Tablet: 1, - Ostype: "other", - Memory: 0, - Balloon: 0, - Cores: 0, - Vcpus: 0, - Sockets: 0, - Cpu: "host", - Numa: 0, - Hotplug: "network,disk,usb", - Boot: "cdn", - Kvm: 1, - Scsihw: "lsi", - Machine: "i440fx", - } - err := self.get(res, url.Values{}, &vmConfig) - if err != nil { - return nil, err - } - byteArr, err := json.Marshal(&vmConfig) - if err != nil { - return nil, err - } - err = json.Unmarshal(byteArr, &vmBase) - if err != nil { - return nil, err - } - - config := SInstance{ - VmID: int(VmId), - Name: vmBase.Name, - Description: strings.TrimSpace(vmBase.Description), - Tags: strings.TrimSpace(vmBase.Tags), - Args: strings.TrimSpace(vmBase.Args), - Bios: vmBase.Bios, - EFIDisk: QemuDevice{}, - Machine: vmBase.Machine, - Onboot: Itob(vmBase.OnBoot), - Startup: vmBase.Startup, - Tablet: Itob(vmBase.Tablet), - QemuOs: vmBase.Ostype, - Memory: int(vmBase.Memory), - QemuCores: int(vmBase.Cores), - QemuSockets: int(vmBase.Sockets), - QemuCpu: vmBase.Cpu, - QemuNuma: Itob(vmBase.Numa), - QemuKVM: Itob(vmBase.Kvm), - Hotplug: vmBase.Hotplug, - QemuVlanTag: -1, - Boot: vmBase.Boot, - BootDisk: vmBase.Bootdisk, - Scsihw: vmBase.Scsihw, - Hookscript: vmBase.Hookscript, - QemuDisks: QemuDevices{}, - QemuUnusedDisks: QemuDevices{}, - QemuVga: QemuDevice{}, - QemuNetworks: []SInstanceNic{}, - QemuSerials: QemuDevices{}, - QemuUsbs: QemuDevices{}, - Node: node, - CIuser: vmBase.Ciuser, - CIpassword: vmBase.Cipassword, - Searchdomain: vmBase.Searchdomain, - Nameserver: vmBase.Nameserver, - } - - // vmConfig Sample: map[ cpu:host - // net0:virtio=62:DF:XX:XX:XX:XX,bridge=vmbr0 - // ide2:local:iso/xxx-xx.iso,media=cdrom memory:2048 - // smbios1:uuid=8b3bf833-aad8-4545-xxx-xxxxxxx digest:aa6ce5xxxxx1b9ce33e4aaeff564d4 sockets:1 - // name:terraform-ubuntu1404-template bootdisk:virtio0 - // virtio0:ProxmoxxxxISCSI:vm-1014-disk-2,size=4G - // description:Base image - // cores:2 ostype:l26 - if vmConfig["ide2"] != nil { - isoMatch := rxIso.FindStringSubmatch(vmConfig["ide2"].(string)) - config.QemuIso = isoMatch[1] - } - - if _, ok := vmConfig["sshkeys"]; ok { - config.Sshkeys, _ = url.PathUnescape(vmConfig["sshkeys"].(string)) - } - - agent := 0 - if _, ok := vmConfig["agent"]; ok { - switch vmConfig["agent"].(type) { - case int64: - agent = int(vmConfig["agent"].(int64)) - case string: - agentConfList := strings.Split(vmConfig["agent"].(string), ",") - agent, _ = strconv.Atoi(agentConfList[0]) - } - - } - config.Agent = agent - - config.PowerState = self.GetVmPowerStatus(node, VmId) - - // Add disks. - diskNames := []string{} - for k := range vmConfig { - if diskName := rxDiskName.FindStringSubmatch(k); len(diskName) > 0 { - diskNames = append(diskNames, diskName[0]) - } - } - - for _, diskName := range diskNames { - diskConfStr := vmConfig[diskName].(string) - - id := rxDeviceID.FindStringSubmatch(diskName) - diskID, _ := strconv.Atoi(id[0]) - diskType := rxDiskType.FindStringSubmatch(diskName)[0] - - diskConfMap := ParsePMConf(diskConfStr, "volume") - - if diskConfMap["volume"].(string) == "none" { - continue - } - - diskConfMap["slot"] = diskID - diskConfMap["type"] = diskType - - storageName, fileName := ParseSubConf(diskConfMap["volume"].(string), ":") - diskConfMap["storage"] = storageName - diskConfMap["file"] = fileName - - volId := diskConfMap["volume"].(string) - - // cloud-init disks not always have the size sent by the API, which results in a crash - if diskConfMap["size"] == nil && strings.Contains(fileName.(string), "cloudinit") { - diskConfMap["size"] = "4M" // default cloud-init disk size - } - - var sizeInTerabytes = regexp.MustCompile(`[0-9]+T`) - // Convert to gigabytes if disk size was received in terabytes - matched := sizeInTerabytes.MatchString(diskConfMap["size"].(string)) - if matched { - diskConfMap["size"] = fmt.Sprintf("%.0fG", DiskSizeGB(diskConfMap["size"])) - } - - // And device config to disks map. - if len(diskConfMap) > 0 { - config.QemuDisks[volId] = diskConfMap - } - } - - // Add unused disks - // unused0:local:100/vm-100-disk-1.qcow2 - unusedDiskNames := []string{} - for k := range vmConfig { - // look for entries from the config in the format "unusedX:" where X is an integer - if unusedDiskName := rxUnusedDiskName.FindStringSubmatch(k); len(unusedDiskName) > 0 { - unusedDiskNames = append(unusedDiskNames, unusedDiskName[0]) - } - } - if len(unusedDiskNames) > 0 { - log.Debugf("[DEBUG] unusedDiskNames: %v", unusedDiskNames) - } - - for _, unusedDiskName := range unusedDiskNames { - unusedDiskConfStr := vmConfig[unusedDiskName].(string) - finalDiskConfMap := QemuDevice{} - - // parse "unused0" to get the id '0' as an int - id := rxDeviceID.FindStringSubmatch(unusedDiskName) - slotID, err := strconv.Atoi(id[0]) - if err != nil { - return nil, errors.Errorf("Unable to parse unused disk id from input string '%s' .", unusedDiskName) - } - finalDiskConfMap["slot"] = slotID - - // parse the attributes from the unused disk - // extract the storage and file path from the unused disk entry - parsedUnusedDiskMap := ParsePMConf(unusedDiskConfStr, "storage+file") - storageName, fileName := ParseSubConf(parsedUnusedDiskMap["storage+file"].(string), ":") - finalDiskConfMap["storage"] = storageName - finalDiskConfMap["file"] = fileName - volId := parsedUnusedDiskMap["storage+file"].(string) - - config.QemuUnusedDisks[volId] = finalDiskConfMap - } - - //Display - if vga, ok := vmConfig["vga"]; ok { - vgaList := strings.Split(vga.(string), ",") - vgaMap := QemuDevice{} - - // TODO: keep going if error? - err = vgaMap.readDeviceConfig(vgaList) - if err != nil { - log.Debugf("[ERROR] %q", err) - } - if len(vgaMap) > 0 { - config.QemuVga = vgaMap - } - } - - // Add networks. - nicNames := []string{} - ipMap := make(map[string]string) - if config.PowerState == "running" && config.Agent == 1 { - ipMap, _ = self.GetVmAgentNetworkInterfaces(node, VmId) - } - - for k := range vmConfig { - if nicName := rxNicName.FindStringSubmatch(k); len(nicName) > 0 { - nicNames = append(nicNames, nicName[0]) - } - } - - for _, nicName := range nicNames { - nicConfStr := vmConfig[nicName] - nicConfList := strings.Split(nicConfStr.(string), ",") - - //id := rxDeviceID.FindStringSubmatch(nicName) - model, macaddr := ParseSubConf(nicConfList[0], "=") - _, network := ParseSubConf(nicConfList[1], "=") - //nicID := fmt.Sprintf("%d:%s", VmId, nicName) - - // Add model and MAC address. - nicConf := SInstanceNic{ - NicId: network.(string), - Model: model, - MacAddr: strings.ToLower(macaddr.(string)), - NetworkId: fmt.Sprintf("network/%s/%s", node, network), - } - - if ip, ok := ipMap[nicConf.MacAddr]; ok { - nicConf.IpAddr = ip - } - - // And device config to networks. - config.QemuNetworks = append(config.QemuNetworks, nicConf) - } - - // Add serials - serialNames := []string{} - - for k := range vmConfig { - if serialName := rxSerialName.FindStringSubmatch(k); len(serialName) > 0 { - serialNames = append(serialNames, serialName[0]) - } - } - - for _, serialName := range serialNames { - id := rxDeviceID.FindStringSubmatch(serialName) - serialID, _ := strconv.Atoi(id[0]) - - serialConfMap := QemuDevice{ - "id": serialID, - "type": vmConfig[serialName], - } - - // And device config to serials map. - if len(serialConfMap) > 0 { - config.QemuSerials[serialName] = serialConfMap - } - } - - // Add usbs - usbNames := []string{} - - for k := range vmConfig { - if usbName := rxUsbName.FindStringSubmatch(k); len(usbName) > 0 { - usbNames = append(usbNames, usbName[0]) - } - } - - for _, usbName := range usbNames { - usbConfStr := vmConfig[usbName] - usbConfList := strings.Split(usbConfStr.(string), ",") - id := rxDeviceID.FindStringSubmatch(usbName) - usbID, _ := strconv.Atoi(id[0]) - _, host := ParseSubConf(usbConfList[0], "=") - - usbConfMap := QemuDevice{ - "id": usbID, - "host": host, - } - - err = usbConfMap.readDeviceConfig(usbConfList[1:]) - if err != nil { - log.Debugf("[ERROR] %q", err) - } - if usbConfMap["usb3"] == 1 { - usbConfMap["usb3"] = true - } - - // And device config to usbs map. - if len(usbConfMap) > 0 { - config.QemuUsbs[usbName] = usbConfMap - } - } - - return &config, nil - -} - -func (self *SRegion) GetInstances(hostId string) ([]SInstance, error) { - ret := []SInstance{} - resources, err := self.GetClusterVmResources() - if err != nil { - return nil, err - } - - for _, res := range resources { - if res.NodeId == hostId { - instance, err := self.GetQemuConfig(res.Node, res.VmId) - if err == nil { - ret = append(ret, *instance) - } - - } - } - - return ret, nil -} - -func (self *SRegion) GetInstance(id string) (*SInstance, error) { - resources, err := self.GetClusterVmResources() - if err != nil { - return nil, err - } - - nodeName := "" - vmId, _ := strconv.Atoi(id) - if resource, ok := resources[vmId]; !ok { - return nil, errors.Errorf("failed get Instance id %s", id) - } else { - nodeName = resource.Node - } - - return self.GetQemuConfig(nodeName, vmId) -} - -func (self *SRegion) StartVm(vmId int) error { - resources, err := self.GetClusterVmResources() - if err != nil { - return err - } - - nodeName := "" - if resource, ok := resources[vmId]; !ok { - return errors.Errorf("start VM id %d", vmId) - } else { - nodeName = resource.Node - } - - res := fmt.Sprintf("/nodes/%s/qemu/%d/status/start", nodeName, vmId) - params := url.Values{} - - _, err = self.post(res, params) - return err - -} - -func (self *SRegion) StopVm(vmId int) error { - resources, err := self.GetClusterVmResources() - if err != nil { - return err - } - - nodeName := "" - if resource, ok := resources[vmId]; !ok { - return errors.Errorf("start VM id %d", vmId) - } else { - nodeName = resource.Node - } - - res := fmt.Sprintf("/nodes/%s/qemu/%d/status/stop", nodeName, vmId) - params := url.Values{} - - _, err = self.post(res, params) - return err -} - -func (self *SRegion) AttachDisk(vmId int, diskId string) error { - id := strconv.Itoa(int(vmId)) - vm1, err := self.GetInstance(id) - if err != nil { - return errors.Wrapf(err, "GetInstance(%d)", vmId) - } - if _, ok := vm1.QemuUnusedDisks[diskId]; !ok { - return nil - } - - slotsArr := []int{} - for _, v := range vm1.QemuDisks { - if v["type"] == "scsi" { - slotIdx := v["slot"].(int) - slotsArr = append(slotsArr, slotIdx) - } - } - sort.Ints(slotsArr) - minSlot := slotsArr[0] - for idx, _ := range slotsArr { - if slotsArr[idx] == minSlot { - minSlot++ - } else { - break - } - - } - - body := map[string]string{} - params := url.Values{} - diskName := fmt.Sprintf("scsi%d", minSlot) - body[diskName] = diskId - res := fmt.Sprintf("/nodes/%s/qemu/%d/config", vm1.Node, vm1.VmID) - err = self.put(res, params, jsonutils.Marshal(body), nil) - if err != nil { - return errors.Wrapf(err, "GetInstance(%d) self.put", vmId) - } - //clear - vm1.QemuDisks = make(map[string]map[string]interface{}) - vm1.QemuUnusedDisks = make(map[string]map[string]interface{}) - - vm2, err := self.GetInstance(id) - if err != nil { - return errors.Wrapf(err, "GetInstance(%d) vm2", vmId) - } - vm1.QemuDisks = vm2.QemuDisks - vm1.QemuUnusedDisks = vm2.QemuUnusedDisks - - return nil - -} - -func (self *SRegion) DetachDisk(vmId int, diskId string) error { - id := strconv.Itoa(int(vmId)) - vm1, err := self.GetInstance(id) - if err != nil { - return errors.Wrapf(err, "GetInstance(%d)", vmId) - } - if v, ok := vm1.QemuDisks[diskId]; !ok { - return nil - } else { - diskName := fmt.Sprintf("%s%d", v["type"].(string), v["slot"].(int)) - body := map[string]string{} - params := url.Values{} - body["delete"] = diskName - res := fmt.Sprintf("/nodes/%s/qemu/%d/config", vm1.Node, vm1.VmID) - err := self.put(res, params, jsonutils.Marshal(body), nil) - if err != nil { - return errors.Wrapf(err, "GetInstance(%d) self.put", vmId) - } - //clear - vm1.QemuDisks = make(map[string]map[string]interface{}) - vm1.QemuUnusedDisks = make(map[string]map[string]interface{}) - - vm2, err := self.GetInstance(id) - if err != nil { - return errors.Wrapf(err, "GetInstance(%d) vm2", vmId) - } - vm1.QemuDisks = vm2.QemuDisks - vm1.QemuUnusedDisks = vm2.QemuUnusedDisks - - return nil - } - -} - -func (self *SRegion) ChangeConfig(vmId int, cpu int, memMb int) error { - vm, err := self.GetInstance(strconv.Itoa(int(vmId))) - body := map[string]interface{}{} - if err != nil { - return errors.Wrapf(err, "ChangeConfig(%d)", vmId) - } - - changed := false - if cpu > 0 { - vm.QemuCores = 1 - vm.QemuSockets = cpu - vm.QemuVcpus = cpu - changed = true - body["cores"] = 1 - body["sockets"] = cpu - body["vcpus"] = cpu - } - if memMb > 0 { - vm.Memory = memMb - body["memory"] = memMb - changed = true - } - if !changed { - return nil - } - - params := url.Values{} - res := fmt.Sprintf("/nodes/%s/qemu/%d/config", vm.Node, vmId) - return self.put(res, params, jsonutils.Marshal(body), nil) -} - -func (self *SRegion) ResetVmPassword(vmId int, username, password string) error { - resources, err := self.GetClusterVmResources() - if err != nil { - return err - } - - nodeName := "" - if resource, ok := resources[vmId]; !ok { - return errors.Errorf("failed to ResetVmPassword VM id %d", vmId) - } else { - nodeName = resource.Node - } - - params := url.Values{} - body := map[string]interface{}{ - "username": username, - "password": password, - } - - res := fmt.Sprintf("/nodes/%s/qemu/%d/agent/set-user-password", nodeName, vmId) - return self.put(res, params, jsonutils.Marshal(body), nil) - -} - -func (self *SRegion) DeleteVM(vmId int) error { - id := strconv.Itoa(int(vmId)) - vm1, err := self.GetInstance(id) - if err != nil { - return errors.Wrapf(err, "GetInstance(%d)", vmId) - } - params := url.Values{} - params.Set("purge", "1") - - res := fmt.Sprintf("/nodes/%s/qemu/%d", vm1.Node, vmId) - return self.del(res, params, nil) -} -func (self *SRegion) GenVM(name, node string, cores, memMB int) (*SInstance, error) { - - vmId := self.GetClusterVmMaxId() - if vmId == -1 { - return nil, errors.Errorf("failed to get vm number by %d", vmId) - } else { - vmId++ - } - - body := map[string]interface{}{ - "vmid": vmId, - "name": name, - "ostype": "other", - "sockets": 1, - "cores": cores, - "cpu": "host", - "kvm": 1, - "hotplug": "network,disk,usb", - "memory": memMB, - "description": "", - "scsihw": "virtio-scsi-pci", - } - - res := fmt.Sprintf("/nodes/%s/qemu", node) - _, err := self.post(res, jsonutils.Marshal(body)) - if err != nil { - return nil, err - } - - vmIdRet := strconv.Itoa(vmId) - vm, err := self.GetInstance(vmIdRet) - if err != nil { - return nil, err - } - - return vm, nil -} diff --git a/pkg/multicloud/proxmox/network.go b/pkg/multicloud/proxmox/network.go deleted file mode 100644 index d04216bac1..0000000000 --- a/pkg/multicloud/proxmox/network.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.ProxmoxTags - - wire *SWire - - Id string - - Priority int `json:"priority"` - Families []string `json:"families"` - Method string `json:"method"` - Autostart int `json:"autostart,omitempty"` - Iface string `json:"iface"` - BridgeFd string `json:"bridge_fd,omitempty"` - Method6 string `json:"method6"` - BridgePorts string `json:"bridge_ports,omitempty"` - Type string `json:"type"` - Active int `json:"active"` - BridgeStp string `json:"bridge_stp,omitempty"` - BridgeVids string `json:"bridge_vids,omitempty"` - Netmask string `json:"netmask,omitempty"` - Address string `json:"address,omitempty"` - BridgeVlanAware int `json:"bridge_vlan_aware,omitempty"` - Gateway string `json:"gateway,omitempty"` - Cidr string `json:"cidr,omitempty"` - Exists int `json:"exists,omitempty"` - Options []string `json:"options,omitempty"` -} - -func (self *SNetwork) GetName() string { - return self.Iface -} - -func (self *SNetwork) GetId() string { - return self.Id -} - -func (self *SNetwork) GetGlobalId() string { - return self.GetId() -} - -func (self *SNetwork) Refresh() error { - ret, err := self.wire.region.GetNetwork(self.Id) - if err != nil { - return err - } - return jsonutils.Update(self, ret) -} - -func (self *SNetwork) Delete() error { - return cloudprovider.ErrNotFound -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (self *SNetwork) GetGateway() string { - return self.Gateway -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.Cidr) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - startIp = startIp.StepUp() // 2 - return startIp.String() -} - -func (self *SNetwork) GetIpEnd() string { - pref, _ := netutils.NewIPV4Prefix(self.Cidr) - 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) Contains(_ip string) bool { - start, _ := netutils.NewIPV4Addr(self.GetIpStart()) - end, _ := netutils.NewIPV4Addr(self.GetIpEnd()) - ip, _ := netutils.NewIPV4Addr(_ip) - return netutils.NewIPV4AddrRange(start, end).Contains(ip) -} - -func (self *SNetwork) GetIpMask() int8 { - pref, _ := netutils.NewIPV4Prefix(self.Cidr) - return pref.MaskLen -} - -func (self *SNetwork) GetProjectId() string { - return "" -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetStatus() string { - return api.NETWORK_STATUS_AVAILABLE -} - -func (self *SRegion) GetNetworks() ([]SNetwork, error) { - ret := []SNetwork{} - - resources, err := self.GetClusterNodeResources() - if err != nil { - return nil, err - } - - for _, res := range resources { - networks := []SNetwork{} - urlNetwork := fmt.Sprintf("/nodes/%s/network", res.Node) - self.get(urlNetwork, url.Values{}, &networks) - - for _, iface := range networks { - id := fmt.Sprintf("network/%s/%s", res.Node, iface.Iface) - iface.Id = id - - ret = append(ret, iface) - } - - } - - return ret, nil -} - -func (self *SRegion) GetNetwork(id string) (*SNetwork, error) { - ret := &SNetwork{} - - //"id": "network/nodeNAME/iface", - splited := strings.Split(id, "/") - nodeName := "" - networkName := "" - - if len(splited) == 3 { - nodeName = splited[1] - networkName = splited[2] - } else { - return nil, errors.Errorf("failed to get network by %s", id) - } - - res := fmt.Sprintf("/nodes/%s/network/%s", nodeName, networkName) - err := self.get(res, url.Values{}, ret) - ret.Id = id - - return ret, err -} diff --git a/pkg/multicloud/proxmox/nic.go b/pkg/multicloud/proxmox/nic.go deleted file mode 100644 index 35af9d4e7b..0000000000 --- a/pkg/multicloud/proxmox/nic.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - "fmt" - "strings" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - cloudprovider.DummyICloudNic - ins *SInstance - - MacAddr string - IpAddr string - NicId string - Model string - NetworkId string -} - -func (self *SInstanceNic) GetId() string { - return fmt.Sprintf("%d/%s", self.ins.VmID, self.NicId) -} - -func (self *SInstanceNic) GetIP() string { - return self.IpAddr -} - -func (self *SInstanceNic) GetMAC() string { - return self.MacAddr -} - -func (self *SInstanceNic) GetDriver() string { - return strings.ToLower(self.Model) -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return true -} - -func (self *SInstanceNic) GetSubAddress() ([]string, error) { - return []string{}, nil -} - -func (self *SInstanceNic) GetINetworkId() string { - return self.NetworkId -} - -func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/proxmox/provider/doc.go b/pkg/multicloud/proxmox/provider/doc.go deleted file mode 100644 index 35d941c28b..0000000000 --- a/pkg/multicloud/proxmox/provider/doc.go +++ /dev/null @@ -1 +0,0 @@ -package provider // import "yunion.io/x/onecloud/pkg/multicloud/proxmox/provider" diff --git a/pkg/multicloud/proxmox/provider/provider.go b/pkg/multicloud/proxmox/provider/provider.go deleted file mode 100644 index 16ce5f8bfc..0000000000 --- a/pkg/multicloud/proxmox/provider/provider.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "fmt" - "net/url" - "strconv" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/regutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/proxmox" -) - -type SProxmoxProviderFactory struct { - cloudprovider.SPrivateCloudBaseProviderFactory -} - -func (self *SProxmoxProviderFactory) GetId() string { - return proxmox.CLOUD_PROVIDER_PROXMOX -} - -func (self *SProxmoxProviderFactory) GetName() string { - return proxmox.CLOUD_PROVIDER_PROXMOX -} - -func (self *SProxmoxProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { - return fmt.Errorf("Changing %s bandwidth is not supported", proxmox.CLOUD_PROVIDER_PROXMOX) -} - -func (self *SProxmoxProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.Username) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "username") - } - if len(input.Password) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "password") - } - if len(input.Host) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "host") - } - if !regutils.MatchIPAddr(input.Host) && !regutils.MatchDomainName(input.Host) { - return output, errors.Wrap(httperrors.ErrInputParameter, "host should be ip or domain name") - } - if input.Port == 0 { - input.Port = 8006 - } - output.AccessUrl = fmt.Sprintf("https://%s:%d", input.Host, input.Port) - output.Account = input.Username - output.Secret = input.Password - return output, nil -} - -func (self *SProxmoxProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.Username) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "username") - } - if len(input.Password) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "password") - } - output = cloudprovider.SCloudaccount{ - Account: input.Username, - Secret: input.Password, - } - return output, nil -} - -func parseHostPort(_url string) (string, int, error) { - urlParse, err := url.Parse(_url) - if err != nil { - return "", 0, errors.Wrapf(err, "parse %s", _url) - } - port := func() int { - if len(urlParse.Port()) > 0 { - _port, _ := strconv.Atoi(urlParse.Port()) - return _port - } - return 8006 - }() - return strings.TrimSuffix(urlParse.Host, fmt.Sprintf(":%d", port)), port, nil -} - -func (self *SProxmoxProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - host, port, err := parseHostPort(cfg.URL) - if err != nil { - return nil, errors.Wrapf(err, "parseHostPort") - } - - client, err := proxmox.NewProxmoxClient( - proxmox.NewProxmoxClientConfig( - cfg.Account, cfg.Secret, host, port, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SProxmoxProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SProxmoxProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - host, port, err := parseHostPort(info.Url) - if err != nil { - return nil, err - } - - return map[string]string{ - "PROXMOX_HOST": host, - "PROXMOX_PORT": fmt.Sprintf("%d", port), - "PROXMOX_USERNAME": info.Account, - "PROXMOX_PASSWORD": info.Secret, - }, nil -} - -func init() { - factory := SProxmoxProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SProxmoxProvider struct { - cloudprovider.SBaseProvider - client *proxmox.SProxmoxClient -} - -func (self *SProxmoxProvider) GetSysInfo() (jsonutils.JSONObject, error) { - return jsonutils.NewDict(), nil -} - -func (self *SProxmoxProvider) GetVersion() string { - return "1.0" -} - -func (self *SProxmoxProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SProxmoxProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SProxmoxProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SProxmoxProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - regions := self.GetIRegions() - for i := range regions { - if regions[i].GetGlobalId() == id { - return regions[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SProxmoxProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SProxmoxProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return []cloudprovider.ICloudProject{}, nil -} - -func (self *SProxmoxProvider) GetStorageClasses(regionId string) []string { - return nil -} - -func (self *SProxmoxProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (self *SProxmoxProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (self *SProxmoxProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} diff --git a/pkg/multicloud/proxmox/region.go b/pkg/multicloud/proxmox/region.go deleted file mode 100644 index f1bb1b277e..0000000000 --- a/pkg/multicloud/proxmox/region.go +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - "fmt" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - multicloud.SRegion - multicloud.SRegionEipBase - multicloud.SNoObjectStorageRegion - multicloud.SRegionLbBase - - client *SProxmoxClient -} - -func (self *SRegion) GetClient() *SProxmoxClient { - return self.client -} - -func (self *SRegion) GetName() string { - return self.client.cpcfg.Name -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) - return table -} - -func (self *SRegion) GetId() string { - return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_PROXMOX, self.client.cpcfg.Id) -} - -func (self *SRegion) GetGlobalId() string { - return self.GetId() -} - -func (self *SRegion) GetProvider() string { - return CLOUD_PROVIDER_PROXMOX -} - -func (self *SRegion) GetCloudEnv() string { - return "" -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) Refresh() error { - return nil -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) CreateIVpc(conf *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SRegion) getVpc() *SVpc { - return &SVpc{region: self} -} - -func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - vpc := self.getVpc() - return []cloudprovider.ICloudVpc{vpc}, nil -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - vpcs, err := self.GetIVpcs() - if err != nil { - return nil, err - } - for i := range vpcs { - if vpcs[i].GetGlobalId() == id { - return vpcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - zone, err := self.GetZone() - if err != nil { - return nil, errors.Wrapf(err, "GetZone()") - } - return zone, nil -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - zone, err := self.GetZone() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudZone{} - zone.region = self - ret = append(ret, zone) - return ret, nil -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.GetInstance(id) - if err != nil { - return nil, err - } - return vm, nil -} - -func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - host, err := self.GetHost(id) - if err != nil { - return nil, err - } - zone, err := self.GetZone() - if err != nil { - return nil, err - } - host.zone = zone - return host, nil -} - -func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - zone, err := self.GetZone() - if err != nil { - return nil, cloudprovider.ErrNotSupported - } - ret := []cloudprovider.ICloudStoragecache{} - cache := &SStoragecache{zone: zone} - ret = append(ret, cache) - return ret, nil -} - -func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - caches, err := self.GetIStoragecaches() - if err != nil { - return nil, cloudprovider.ErrNotSupported - } - for i := range caches { - if caches[i].GetGlobalId() == id { - return caches[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) get(res string, params url.Values, retVal interface{}) error { - return self.client.get(res, params, retVal) -} - -func (self *SRegion) getAgent(res string, params url.Values, retVal interface{}) error { - return self.client.getAgent(res, params, retVal) -} - -func (self *SRegion) post(res string, params interface{}) (jsonutils.JSONObject, error) { - return self.client.post(res, params) -} - -func (self *SRegion) put(res string, params url.Values, body jsonutils.JSONObject, retVal interface{}) error { - return self.client.put(res, params, body, retVal) -} - -func (self *SRegion) del(res string, params url.Values, retVal interface{}) error { - return self.client.del(res, params, retVal) -} diff --git a/pkg/multicloud/proxmox/shell/cluster.go b/pkg/multicloud/proxmox/shell/cluster.go deleted file mode 100644 index ba4b444f15..0000000000 --- a/pkg/multicloud/proxmox/shell/cluster.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/proxmox" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClusterListOptions struct { - } - shellutils.R(&ClusterListOptions{}, "cluster-list", "list clusters", func(cli *proxmox.SRegion, args *ClusterListOptions) error { - clusters, err := cli.GetClusterAllResources() - if err != nil { - return err - } - printList(clusters, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&ClusterListOptions{}, "cluster-node-list", "list nodes", func(cli *proxmox.SRegion, args *ClusterListOptions) error { - clusters, err := cli.GetClusterNodeResources() - if err != nil { - return err - } - printList(clusters, 0, 0, 0, []string{}) - return nil - }) - - shellutils.R(&ClusterListOptions{}, "cluster-storge-list", "list storges", func(cli *proxmox.SRegion, args *ClusterListOptions) error { - clusters, err := cli.GetClusterStoragesResources() - if err != nil { - return err - } - printList(clusters, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/proxmox/shell/disk.go b/pkg/multicloud/proxmox/shell/disk.go deleted file mode 100644 index 35172afbe7..0000000000 --- a/pkg/multicloud/proxmox/shell/disk.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/proxmox" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - STORAGE_ID string - } - shellutils.R(&DiskListOptions{}, "disk-list", "list disks", func(cli *proxmox.SRegion, args *DiskListOptions) error { - disks, err := cli.GetDisks(args.STORAGE_ID) - if err != nil { - return err - } - printList(disks, 0, 0, 0, []string{}) - return nil - }) - - type DiskIdOptions struct { - ID string - } - - shellutils.R(&DiskIdOptions{}, "disk-show", "show disk", func(cli *proxmox.SRegion, args *DiskIdOptions) error { - ret, err := cli.GetDisk(args.ID) - if err != nil { - return err - } - printObject(ret) - return nil - }) - -} diff --git a/pkg/multicloud/proxmox/shell/doc.go b/pkg/multicloud/proxmox/shell/doc.go deleted file mode 100644 index 6862f8ad4e..0000000000 --- a/pkg/multicloud/proxmox/shell/doc.go +++ /dev/null @@ -1 +0,0 @@ -package shell // import "yunion.io/x/onecloud/pkg/multicloud/proxmox/shell" diff --git a/pkg/multicloud/proxmox/shell/hosts.go b/pkg/multicloud/proxmox/shell/hosts.go deleted file mode 100644 index 2479ff2fa3..0000000000 --- a/pkg/multicloud/proxmox/shell/hosts.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/proxmox" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type HostListOptions struct { - } - shellutils.R(&HostListOptions{}, "host-list", "list hosts", func(cli *proxmox.SRegion, args *HostListOptions) error { - hosts, err := cli.GetHosts() - if err != nil { - return err - } - printList(hosts, 0, 0, 0, []string{}) - return nil - }) - - type HostIdOptions struct { - ID string - } - - shellutils.R(&HostIdOptions{}, "host-show", "show host", func(cli *proxmox.SRegion, args *HostIdOptions) error { - host, err := cli.GetHost(args.ID) - if err != nil { - return err - } - printObject(host) - printObject(host.Cpuinfo) - return nil - }) - -} diff --git a/pkg/multicloud/proxmox/shell/image.go b/pkg/multicloud/proxmox/shell/image.go deleted file mode 100644 index 10f0217094..0000000000 --- a/pkg/multicloud/proxmox/shell/image.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/proxmox" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - } - - shellutils.R(&ImageListOptions{}, "image-list", "list images", func(cli *proxmox.SRegion, args *ImageListOptions) error { - images, err := cli.GetImageList() - if err != nil { - return err - } - printList(images, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/proxmox/shell/instance.go b/pkg/multicloud/proxmox/shell/instance.go deleted file mode 100644 index 6508700afb..0000000000 --- a/pkg/multicloud/proxmox/shell/instance.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "strconv" - - "yunion.io/x/onecloud/pkg/multicloud/proxmox" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - HOST_ID string - } - shellutils.R(&InstanceListOptions{}, "instance-list", "list instances", func(cli *proxmox.SRegion, args *InstanceListOptions) error { - instances, err := cli.GetInstances(args.HOST_ID) - if err != nil { - return err - } - printList(instances, 0, 0, 0, []string{}) - return nil - }) - - type InstanceIdOptions struct { - ID string - } - - shellutils.R(&InstanceIdOptions{}, "instance-show", "show instance", func(cli *proxmox.SRegion, args *InstanceIdOptions) error { - ret, err := cli.GetInstance(args.ID) - if err != nil { - return err - } - printObject(ret) - return nil - }) - - shellutils.R(&InstanceIdOptions{}, "instance-stop", "stop instance", func(cli *proxmox.SRegion, args *InstanceIdOptions) error { - id, _ := strconv.Atoi(args.ID) - return cli.StopVm(id) - }) - - shellutils.R(&InstanceIdOptions{}, "instance-delete", "delete instance", func(cli *proxmox.SRegion, args *InstanceIdOptions) error { - id, _ := strconv.Atoi(args.ID) - return cli.DeleteVM(id) - }) - - type InstanceStartOptions struct { - ID string - Password string - PublicKey string - } - - shellutils.R(&InstanceStartOptions{}, "instance-start", "Start instance", func(cli *proxmox.SRegion, args *InstanceStartOptions) error { - id, _ := strconv.Atoi(args.ID) - return cli.StartVm(id) - }) - - type InstanceAttachDiskOptions struct { - ID string - DISK_ID string - } - - shellutils.R(&InstanceAttachDiskOptions{}, "instance-attach-disk", "Attach instance disk", func(cli *proxmox.SRegion, args *InstanceAttachDiskOptions) error { - id, _ := strconv.Atoi(args.ID) - return cli.AttachDisk(id, args.DISK_ID) - }) - - shellutils.R(&InstanceAttachDiskOptions{}, "instance-detach-disk", "Attach instance disk", func(cli *proxmox.SRegion, args *InstanceAttachDiskOptions) error { - id, _ := strconv.Atoi(args.ID) - return cli.DetachDisk(id, args.DISK_ID) - }) - - type InstanceChangeConfigOptions struct { - ID string - Cpu int - MemMb int - } - - shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Change instance config", func(cli *proxmox.SRegion, args *InstanceChangeConfigOptions) error { - id, _ := strconv.Atoi(args.ID) - return cli.ChangeConfig(id, args.Cpu, args.MemMb) - }) - - type InstanceCreateOptions struct { - Name string - Node string - Cpu int - MemMb int - } - - shellutils.R(&InstanceCreateOptions{}, "instance-create", "create instance ", func(cli *proxmox.SRegion, args *InstanceCreateOptions) error { - ret, err := cli.GenVM(args.Name, args.Node, args.Cpu, args.MemMb) - printObject(ret) - return err - }) - -} diff --git a/pkg/multicloud/proxmox/shell/network.go b/pkg/multicloud/proxmox/shell/network.go deleted file mode 100644 index cbcf4d2335..0000000000 --- a/pkg/multicloud/proxmox/shell/network.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/proxmox" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkListOptions struct { - } - shellutils.R(&NetworkListOptions{}, "network-list", "list networks", func(cli *proxmox.SRegion, args *NetworkListOptions) error { - networks, err := cli.GetNetworks() - if err != nil { - return err - } - printList(networks, 0, 0, 0, []string{}) - return nil - }) - - type NetworkIdOptions struct { - ID string - } - - shellutils.R(&NetworkIdOptions{}, "network-show", "show network", func(cli *proxmox.SRegion, args *NetworkIdOptions) error { - ret, err := cli.GetNetwork(args.ID) - if err != nil { - return err - } - printObject(ret) - return nil - }) - -} diff --git a/pkg/multicloud/proxmox/shell/printutils.go b/pkg/multicloud/proxmox/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/proxmox/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/proxmox/shell/region.go b/pkg/multicloud/proxmox/shell/region.go deleted file mode 100644 index 601344c961..0000000000 --- a/pkg/multicloud/proxmox/shell/region.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/proxmox" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "list regions", func(cli *proxmox.SRegion, args *RegionListOptions) error { - regions, err := cli.GetClient().GetRegions() - if err != nil { - return err - } - printList(regions, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/proxmox/shell/storage.go b/pkg/multicloud/proxmox/shell/storage.go deleted file mode 100644 index 1fc946d635..0000000000 --- a/pkg/multicloud/proxmox/shell/storage.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/proxmox" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type StorageListOptions struct { - } - shellutils.R(&StorageListOptions{}, "storage-list", "list storage", func(cli *proxmox.SRegion, args *StorageListOptions) error { - storages, err := cli.GetStorages() - if err != nil { - return err - } - printList(storages, 0, 0, 0, []string{}) - return nil - }) - - type StorageIdOptions struct { - ID string - } - - shellutils.R(&StorageIdOptions{}, "storage-show", "show storage", func(cli *proxmox.SRegion, args *StorageIdOptions) error { - storage, err := cli.GetStorage(args.ID) - if err != nil { - return err - } - printObject(storage) - return nil - }) - -} diff --git a/pkg/multicloud/proxmox/shell/zone.go b/pkg/multicloud/proxmox/shell/zone.go deleted file mode 100644 index e8be99cc38..0000000000 --- a/pkg/multicloud/proxmox/shell/zone.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/proxmox" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - } - shellutils.R(&ZoneListOptions{}, "zone-list", "list zones", func(cli *proxmox.SRegion, args *ZoneListOptions) error { - zone, err := cli.GetZone() - if err != nil { - return err - } - printObject(zone) - return nil - }) - -} diff --git a/pkg/multicloud/proxmox/storage.go b/pkg/multicloud/proxmox/storage.go deleted file mode 100644 index 026f5aea58..0000000000 --- a/pkg/multicloud/proxmox/storage.go +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - multicloud.SStorageBase - multicloud.ProxmoxTags - - zone *SZone - - Id string - Node string - - Total int64 `json:"total"` - Storage string `json:"storage"` - Shared int `json:"shared"` - Used int64 `json:"used"` - Content string `json:"content"` - Active int `json:"active"` - UsedFraction float64 `json:"used_fraction"` - Avail int64 `json:"avail"` - Enabled int `json:"enabled"` - Type string `json:"type"` -} - -func (self *SStorage) GetName() string { - return self.Storage -} - -func (self *SStorage) GetId() string { - return self.Id -} - -func (self *SStorage) GetGlobalId() string { - return self.GetId() -} - -func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := self.zone.region.GetDisks(self.Id) - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudDisk{} - for i := range disks { - disks[i].region = self.zone.region - ret = append(ret, &disks[i]) - } - return ret, nil -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SStorage) GetCapacityMB() int64 { - return int64(self.Total / 1024 / 1024) -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return int64(self.Used / 1024 / 1024) -} - -func (self *SStorage) GetEnabled() bool { - return true -} - -func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - disk, err := self.zone.region.GetDisk(id) - if err != nil { - return nil, cloudprovider.ErrNotFound - } - - return disk, nil -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - cache := &SStoragecache{zone: self.zone} - return cache -} - -func (self *SStorage) GetMediumType() string { - return api.DISK_TYPE_SSD -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) Refresh() error { - ret, err := self.zone.region.GetStorage(self.GetGlobalId()) - if err != nil { - return err - } - return jsonutils.Update(self, ret) -} - -func (self *SStorage) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (self *SStorage) GetStorageType() string { - return strings.ToLower(self.Type) -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} - -func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storage, err := self.GetStorage(id) - if err != nil { - return nil, err - } - zone, err := self.GetZone() - if err != nil { - return nil, err - } - storage.zone = zone - return storage, nil -} - -func (self *SRegion) GetStorages() ([]SStorage, error) { - storages := []SStorage{} - resources, err := self.GetClusterStoragesResources() - if err != nil { - return nil, err - } - - for _, res := range resources { - storage := &SStorage{} - status := fmt.Sprintf("%s/status", res.Path) - err := self.get(status, url.Values{}, storage) - if err != nil { - return nil, err - } - - storage.Id = res.Id - storage.Node = res.Node - // not support storageCache, so chanege the type name. - if storage.Type == "rbd" { - storage.Type = "cephrbd" - } - if storage.Storage == "" { - storage.Storage = res.Name - } - - storages = append(storages, *storage) - } - - return storages, nil -} - -func (self *SRegion) GetStoragesByHost(hostId string) ([]SStorage, error) { - storages := []SStorage{} - nodeName := "" - splited := strings.Split(hostId, "/") - nodeName = splited[1] - - res := fmt.Sprintf("/nodes/%s/storage", nodeName) - err := self.get(res, url.Values{}, &storages) - if err != nil { - return nil, err - } - - for i := range storages { - id := fmt.Sprintf("storage/%s/%s", nodeName, storages[i].Storage) - storages[i].Node = nodeName - storages[i].Id = id - if storages[i].Type == "rbd" { - storages[i].Type = "cephrbd" - } - } - - return storages, nil -} - -func (self *SRegion) GetStorage(id string) (*SStorage, error) { - ret := &SStorage{} - - //"id": "storage/nodeNAME/strogeNAME", - splited := strings.Split(id, "/") - nodeName := "" - storageName := "" - - if len(splited) == 3 { - nodeName, storageName = splited[1], splited[2] - } - - status := fmt.Sprintf("/nodes/%s/storage/%s/status", nodeName, storageName) - err := self.get(status, url.Values{}, ret) - ret.Id = id - ret.Node = nodeName - if ret.Type == "rbd" { - ret.Type = "cephrbd" - } - - return ret, err -} diff --git a/pkg/multicloud/proxmox/storagecache.go b/pkg/multicloud/proxmox/storagecache.go deleted file mode 100644 index e85f07e9e5..0000000000 --- a/pkg/multicloud/proxmox/storagecache.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - "context" - - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.ProxmoxTags - - zone *SZone -} - -func (self *SStoragecache) GetGlobalId() string { - return self.zone.GetGlobalId() -} - -func (self *SStoragecache) GetId() string { - return self.zone.GetId() -} - -func (self *SStoragecache) GetName() string { - return self.zone.GetName() -} - -func (self *SStoragecache) GetStatus() string { - return "available" -} - -func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - ret := []cloudprovider.ICloudImage{} - images, err := self.zone.region.GetImageList() - if err != nil { - return nil, err - } - for i := range images { - images[i].cache = self - ret = append(ret, &images[i]) - } - - return ret, nil -} - -func (seflf *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SStoragecache) GetIImageById(id string) (cloudprovider.ICloudImage, error) { - images, err := self.GetICloudImages() - if err != nil { - return nil, err - } - for i := range images { - if images[i].GetGlobalId() == id { - return images[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -func (self *SStoragecache) CreateIImage(snpId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { - return "", cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/proxmox/task.go b/pkg/multicloud/proxmox/task.go deleted file mode 100644 index b567a8b171..0000000000 --- a/pkg/multicloud/proxmox/task.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - "encoding/json" - "fmt" - "strings" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type STask struct { - User string `json:"user"` - Type string `json:"type"` - Saved string `json:"saved"` - Status string `json:"status"` - Starttime int `json:"starttime"` - Node string `json:"node"` - ID string `json:"id"` - Endtime int `json:"endtime"` - Upid string `json:"upid"` -} - -func (c *SProxmoxClient) getTaskId(taskResponse map[string]interface{}) string { - if taskResponse["errors"] != nil { - errJSON, _ := json.MarshalIndent(taskResponse["errors"], "", " ") - return string(errJSON) - } - if taskResponse["data"] == nil { - return "" - } - - taskUpid := taskResponse["data"].(string) - return taskUpid -} - -func (self *SProxmoxClient) waitTask(id string) (string, error) { - resId := "" - return resId, cloudprovider.Wait(time.Second*10, time.Minute*10, func() (bool, error) { - tasks := []STask{} - err := self.get("/cluster/tasks", nil, &tasks) - if err != nil { - return false, errors.Wrapf(err, "get task %s", id) - } - - for _, task := range tasks { - if task.Upid == id { - switch strings.ToLower(task.Status) { - case "running": - log.Debugf("task %s state: %s", task.Upid, task.Status) - return false, nil - case "ok": - log.Debugf("task %s state: %s", task.Upid, task.Status) - resId = task.Upid - return true, nil - case "": - log.Debugf("task %s not finish", task.Upid) - return false, nil - default: - log.Debugf("task %s state: %s", task.Upid, task.Status) - return false, fmt.Errorf("task %s state: %s", task.Upid, task.Status) - } - - } - } - - return false, fmt.Errorf("not find task %s ", id) - }) -} diff --git a/pkg/multicloud/proxmox/vpc.go b/pkg/multicloud/proxmox/vpc.go deleted file mode 100644 index 9637ccd149..0000000000 --- a/pkg/multicloud/proxmox/vpc.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - multicloud.ProxmoxTags - - region *SRegion -} - -func (self *SVpc) GetName() string { - return "Default" -} - -func (self *SVpc) GetId() string { - return self.region.GetId() -} - -func (self *SVpc) GetGlobalId() string { - return self.GetId() -} - -func (self *SVpc) Delete() error { - return cloudprovider.ErrNotSupported -} - -func (self *SVpc) IsEmulated() bool { - return true -} - -func (self *SVpc) GetCidrBlock() string { - return "0.0.0.0/0" -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - return []cloudprovider.ICloudRouteTable{}, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - return []cloudprovider.ICloudSecurityGroup{}, nil -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - wires, err := self.region.GetWires() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudWire{} - for i := range wires { - wires[i].region = self.region - ret = append(ret, &wires[i]) - } - return ret, nil -} - -func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { - wire, err := self.region.GetWire() - if err != nil { - return nil, err - } - wire.region = self.region - return wire, nil -} - -func (self *SVpc) GetIsDefault() bool { - return true -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVpc) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} diff --git a/pkg/multicloud/proxmox/wire.go b/pkg/multicloud/proxmox/wire.go deleted file mode 100644 index c46a315215..0000000000 --- a/pkg/multicloud/proxmox/wire.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.ProxmoxTags - - region *SRegion -} - -func (self *SWire) GetId() string { - return self.region.GetId() -} - -func (self *SWire) GetName() string { - return "Default" -} - -func (self *SWire) GetGlobalId() string { - return self.GetId() -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SWire) GetBandwidth() int { - return 10000 -} - -func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - nets, err := self.region.GetNetworks() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNetwork{} - for i := range nets { - nets[i].wire = self - ret = append(ret, &nets[i]) - } - return ret, nil -} - -func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { - net, err := self.region.GetNetwork(id) - if err != nil { - return nil, err - } - net.wire = self - return net, nil -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.region.getVpc() -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - zone, _ := self.region.GetZone() - return zone -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SRegion) GetWires() ([]SWire, error) { - ret := []SWire{} - wire := &SWire{region: self} - ret = append(ret, *wire) - return ret, nil -} - -func (self *SRegion) GetWire() (*SWire, error) { - ret := &SWire{region: self} - return ret, nil -} diff --git a/pkg/multicloud/proxmox/zone.go b/pkg/multicloud/proxmox/zone.go deleted file mode 100644 index 8868631f8c..0000000000 --- a/pkg/multicloud/proxmox/zone.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 proxmox - -import ( - "net/url" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SZone struct { - multicloud.SResourceBase - multicloud.ProxmoxTags - - region *SRegion - - Name string - Nodes int - Quorate int - Version int -} - -type ClusterStatus struct { - Nodes int `json:"nodes,omitempty"` - Quorate int `json:"quorate,omitempty"` - Version int `json:"version,omitempty"` - Type string `json:"type"` - ID string `json:"id"` - Name string `json:"name"` - Online int `json:"online,omitempty"` - Level string `json:"level,omitempty"` - Nodeid int `json:"nodeid,omitempty"` - Local int `json:"local,omitempty"` - IP string `json:"ip,omitempty"` -} - -func (self *SZone) GetId() string { - return self.Name -} - -func (self *SZone) GetGlobalId() string { - return self.Name -} - -func (self *SZone) GetName() string { - return self.Name -} - -func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SZone) GetStatus() string { - return api.ZONE_ENABLE -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) - return table -} - -func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - host, err := self.region.GetHost(id) - if err != nil { - return nil, err - } - host.zone = self - - return host, nil -} - -func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - hosts, err := self.region.GetHosts() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudHost{} - for i := range hosts { - hosts[i].zone = self - ret = append(ret, &hosts[i]) - } - return ret, nil -} - -func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := self.region.GetStorages() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStorage{} - for i := range storages { - storages[i].zone = self - ret = append(ret, &storages[i]) - } - return ret, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storage, err := self.region.GetStorage(id) - if err != nil { - return nil, errors.Wrapf(err, "GetStorage %s", id) - } - - storage.zone = self - return storage, nil -} - -func (self *SRegion) GetZone() (*SZone, error) { - ret := &SZone{region: self} - css := []ClusterStatus{} - - noneClusterMsg := true - nodeNum := 0 - - err := self.get("/cluster/status", url.Values{}, &css) - if err != nil { - return nil, err - } - - for _, cs := range css { - if cs.Type == "cluster" { - ret.Name = cs.Name - ret.Nodes = cs.Nodes - ret.Quorate = cs.Quorate - ret.Version = cs.Version - noneClusterMsg = false - break - } else { - nodeNum++ - } - - } - - if noneClusterMsg == true { - ret.Name = "cluster" - ret.Nodes = nodeNum - } - - return ret, nil -} diff --git a/pkg/multicloud/qcloud/bucket.go b/pkg/multicloud/qcloud/bucket.go deleted file mode 100644 index cec26b5c61..0000000000 --- a/pkg/multicloud/qcloud/bucket.go +++ /dev/null @@ -1,1169 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - "io" - "net/http" - "strconv" - "strings" - "time" - - "github.com/tencentyun/cos-go-sdk-v5" - "gopkg.in/fatih/set.v0" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/timeutils" - "yunion.io/x/s3cli" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - COS_META_HEADER = "X-Cos-Meta-" -) - -type SBucket struct { - multicloud.SBaseBucket - multicloud.QcloudTags - - appId string - - region *SRegion - zone *SZone - - Name string - Location string - CreateDate time.Time -} - -func (b *SBucket) GetProjectId() string { - return "" -} - -func (b *SBucket) GetGlobalId() string { - if b.getAppId() == b.region.client.appId { - return b.Name - } else { - return b.getFullName() - } -} - -func (b *SBucket) GetName() string { - return b.GetGlobalId() -} - -func (b *SBucket) GetLocation() string { - return b.Location -} - -func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { - return b.region -} - -func (b *SBucket) GetCreatedAt() time.Time { - return b.CreateDate -} - -func (b *SBucket) GetStorageClass() string { - return "" -} - -const ( - ACL_GROUP_URI_ALL_USERS = "http://cam.qcloud.com/groups/global/AllUsers" - ACL_GROUP_URI_AUTH_USERS = "http://cam.qcloud.com/groups/global/AuthenticatedUsers" -) - -func cosAcl2CannedAcl(acls []cos.ACLGrant) cloudprovider.TBucketACLType { - switch { - case len(acls) == 1: - if acls[0].Grantee.URI == "" && acls[0].Permission == s3cli.PERMISSION_FULL_CONTROL { - return cloudprovider.ACLPrivate - } - case len(acls) == 2: - for _, g := range acls { - if g.Grantee.URI == ACL_GROUP_URI_AUTH_USERS && g.Permission == s3cli.PERMISSION_READ { - return cloudprovider.ACLAuthRead - } - if g.Grantee.URI == ACL_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_READ { - return cloudprovider.ACLPublicRead - } - } - case len(acls) == 3: - for _, g := range acls { - if g.Grantee.URI == ACL_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_WRITE { - return cloudprovider.ACLPublicReadWrite - } - } - } - return cloudprovider.ACLUnknown -} - -func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - coscli, err := b.region.GetCosClient(b) - if err != nil { - log.Errorf("GetCosClient fail %s", err) - return acl - } - result, _, err := coscli.Bucket.GetACL(context.Background()) - if err != nil { - log.Errorf("coscli.Bucket.GetACL fail %s", err) - return acl - } - return cosAcl2CannedAcl(result.AccessControlList) -} - -func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrap(err, "b.region.GetCosClient") - } - opts := &cos.BucketPutACLOptions{} - opts.Header = &cos.ACLHeaderOptions{} - opts.Header.XCosACL = string(aclStr) - _, err = coscli.Bucket.PutACL(context.Background(), opts) - if err != nil { - return errors.Wrap(err, "PutACL") - } - return nil -} - -func (b *SBucket) getAppId() string { - if len(b.appId) > 0 { - return b.appId - } - if b.zone != nil { - return b.zone.region.client.appId - } - return b.region.client.appId -} - -func (b *SBucket) getFullName() string { - return fmt.Sprintf("%s-%s", b.Name, b.getAppId()) -} - -func (b *SBucket) getBucketUrlHost() string { - if b.zone != nil { - return fmt.Sprintf("%s.%s", b.getFullName(), b.zone.getCosEndpoint()) - } else { - return fmt.Sprintf("%s.%s", b.getFullName(), b.region.getCosEndpoint()) - } -} - -func (b *SBucket) getBucketUrl() string { - return fmt.Sprintf("https://%s", b.getBucketUrlHost()) -} - -func (b *SBucket) getBucketWebsiteUrlHost() string { - if b.zone != nil { - return fmt.Sprintf("%s.%s", b.getFullName(), b.zone.getCosWebsiteEndpoint()) - } else { - return fmt.Sprintf("%s.%s", b.getFullName(), b.region.getCosWebsiteEndpoint()) - } -} - -func (b *SBucket) getWebsiteUrl() string { - return fmt.Sprintf("https://%s", b.getBucketWebsiteUrlHost()) -} - -func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { - return []cloudprovider.SBucketAccessUrl{ - { - Url: b.getBucketUrl(), - Description: "bucket domain", - Primary: true, - }, - { - Url: fmt.Sprintf("https://%s/%s", b.region.getCosEndpoint(), b.getFullName()), - Description: "cos domain", - }, - } -} - -func (b *SBucket) GetStats() cloudprovider.SBucketStats { - stats, _ := cloudprovider.GetIBucketStats(b) - return stats -} - -func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { - result := cloudprovider.SListObjectResult{} - coscli, err := b.region.GetCosClient(b) - if err != nil { - return result, errors.Wrap(err, "GetCosClient") - } - opts := &cos.BucketGetOptions{} - if len(prefix) > 0 { - opts.Prefix = prefix - } - if len(marker) > 0 { - opts.Marker = marker - } - if len(delimiter) > 0 { - opts.Delimiter = delimiter - } - if maxCount > 0 { - opts.MaxKeys = maxCount - } - oResult, _, err := coscli.Bucket.Get(context.Background(), opts) - if err != nil { - return result, errors.Wrap(err, "coscli.Bucket.Get") - } - result.Objects = make([]cloudprovider.ICloudObject, 0) - for _, object := range oResult.Contents { - lastModified, _ := timeutils.ParseTimeStr(object.LastModified) - obj := &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - StorageClass: string(object.StorageClass), - Key: object.Key, - SizeBytes: int64(object.Size), - ETag: object.ETag, - LastModified: lastModified, - }, - } - result.Objects = append(result.Objects, obj) - } - if oResult.CommonPrefixes != nil { - result.CommonPrefixes = make([]cloudprovider.ICloudObject, 0) - for _, commPrefix := range oResult.CommonPrefixes { - obj := &SObject{ - bucket: b, - SBaseCloudObject: cloudprovider.SBaseCloudObject{ - Key: commPrefix, - }, - } - result.CommonPrefixes = append(result.CommonPrefixes, obj) - } - } - result.IsTruncated = oResult.IsTruncated - result.NextMarker = oResult.NextMarker - return result, nil -} - -func (b *SBucket) PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrap(err, "GetCosClient") - } - opts := &cos.ObjectPutOptions{ - ACLHeaderOptions: &cos.ACLHeaderOptions{}, - ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{}, - } - if sizeBytes > 0 { - opts.ContentLength = sizeBytes - } - if meta != nil { - extraHdr := http.Header{} - for k, v := range meta { - if len(v) == 0 || len(v[0]) == 0 { - continue - } - switch http.CanonicalHeaderKey(k) { - case cloudprovider.META_HEADER_CACHE_CONTROL: - opts.CacheControl = v[0] - case cloudprovider.META_HEADER_CONTENT_TYPE: - opts.ContentType = v[0] - case cloudprovider.META_HEADER_CONTENT_MD5: - opts.ContentMD5 = v[0] - case cloudprovider.META_HEADER_CONTENT_ENCODING: - opts.ContentEncoding = v[0] - case cloudprovider.META_HEADER_CONTENT_DISPOSITION: - opts.ContentDisposition = v[0] - default: - extraHdr.Add(fmt.Sprintf("%s%s", COS_META_HEADER, k), v[0]) - } - } - if len(extraHdr) > 0 { - opts.XCosMetaXXX = &extraHdr - } - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - opts.XCosACL = string(cannedAcl) - if len(storageClassStr) > 0 { - opts.XCosStorageClass = storageClassStr - } - _, err = coscli.Object.Put(ctx, key, reader, opts) - if err != nil { - return errors.Wrap(err, "coscli.Object.Put") - } - return nil -} - -func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return "", errors.Wrap(err, "GetCosClient") - } - opts := &cos.InitiateMultipartUploadOptions{ - ACLHeaderOptions: &cos.ACLHeaderOptions{}, - ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{}, - } - if meta != nil { - extraHdr := http.Header{} - for k, v := range meta { - if len(v) == 0 || len(v[0]) == 0 { - continue - } - switch http.CanonicalHeaderKey(k) { - case cloudprovider.META_HEADER_CACHE_CONTROL: - opts.CacheControl = v[0] - case cloudprovider.META_HEADER_CONTENT_TYPE: - opts.ContentType = v[0] - case cloudprovider.META_HEADER_CONTENT_MD5: - opts.ContentMD5 = v[0] - case cloudprovider.META_HEADER_CONTENT_ENCODING: - opts.ContentEncoding = v[0] - case cloudprovider.META_HEADER_CONTENT_DISPOSITION: - opts.ContentDisposition = v[0] - default: - extraHdr.Add(fmt.Sprintf("%s%s", COS_META_HEADER, k), v[0]) - } - } - if len(extraHdr) > 0 { - opts.XCosMetaXXX = &extraHdr - } - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - opts.XCosACL = string(cannedAcl) - if len(storageClassStr) > 0 { - opts.XCosStorageClass = storageClassStr - } - result, _, err := coscli.Object.InitiateMultipartUpload(ctx, key, opts) - if err != nil { - return "", errors.Wrap(err, "InitiateMultipartUpload") - } - - return result.UploadID, nil -} - -func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return "", errors.Wrap(err, "GetCosClient") - } - opts := &cos.ObjectUploadPartOptions{} - opts.ContentLength = partSize - resp, err := coscli.Object.UploadPart(ctx, key, uploadId, partIndex, input, opts) - if err != nil { - return "", errors.Wrap(err, "UploadPart") - } - - return resp.Header.Get("Etag"), nil -} - -func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrap(err, "GetCosClient") - } - opts := &cos.CompleteMultipartUploadOptions{} - parts := make([]cos.Object, len(partEtags)) - for i := range partEtags { - parts[i] = cos.Object{ - PartNumber: i + 1, - ETag: partEtags[i], - } - } - opts.Parts = parts - _, _, err = coscli.Object.CompleteMultipartUpload(ctx, key, uploadId, opts) - - if err != nil { - return errors.Wrap(err, "CompleteMultipartUpload") - } - - return nil -} - -func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrap(err, "GetCosClient") - } - - _, err = coscli.Object.AbortMultipartUpload(ctx, key, uploadId) - if err != nil { - return errors.Wrap(err, "AbortMultipartUpload") - } - - return nil -} - -func (b *SBucket) DeleteObject(ctx context.Context, key string) error { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrap(err, "GetCosClient") - } - _, err = coscli.Object.Delete(ctx, key) - if err != nil { - return errors.Wrap(err, "coscli.Object.Delete") - } - return nil -} - -func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { - if method != "GET" && method != "PUT" && method != "DELETE" { - return "", errors.Error("unsupported method") - } - coscli, err := b.region.GetCosClient(b) - if err != nil { - return "", errors.Wrap(err, "GetCosClient") - } - url, err := coscli.Object.GetPresignedURL(context.Background(), method, key, - b.region.client.secretId, - b.region.client.secretKey, - expire, nil) - if err != nil { - return "", errors.Wrap(err, "coscli.Object.GetPresignedURL") - } - return url.String(), nil -} - -func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucketName, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrap(err, "GetCosClient") - } - opts := &cos.ObjectCopyOptions{ - ObjectCopyHeaderOptions: &cos.ObjectCopyHeaderOptions{}, - ACLHeaderOptions: &cos.ACLHeaderOptions{}, - } - if len(cannedAcl) == 0 { - cannedAcl = b.GetAcl() - } - opts.XCosACL = string(cannedAcl) - if len(storageClassStr) > 0 { - opts.XCosStorageClass = storageClassStr - } - if meta != nil { - opts.XCosMetadataDirective = "Replaced" - extraHdr := http.Header{} - for k, v := range meta { - if len(v) == 0 || len(v[0]) == 0 { - continue - } - switch http.CanonicalHeaderKey(k) { - case cloudprovider.META_HEADER_CACHE_CONTROL: - opts.CacheControl = v[0] - case cloudprovider.META_HEADER_CONTENT_TYPE: - opts.ContentType = v[0] - case cloudprovider.META_HEADER_CONTENT_ENCODING: - opts.ContentEncoding = v[0] - case cloudprovider.META_HEADER_CONTENT_DISPOSITION: - opts.ContentDisposition = v[0] - default: - extraHdr.Add(fmt.Sprintf("%s%s", COS_META_HEADER, k), v[0]) - } - } - if len(extraHdr) > 0 { - opts.XCosMetaXXX = &extraHdr - } - } else { - opts.XCosMetadataDirective = "Copy" - } - srcBucket := SBucket{ - region: b.region, - Name: srcBucketName, - } - srcUrl := fmt.Sprintf("%s/%s", srcBucket.getBucketUrlHost(), srcKey) - _, _, err = coscli.Object.Copy(ctx, destKey, srcUrl, opts) - if err != nil { - return errors.Wrap(err, "coscli.Object.Copy") - } - return nil -} - -func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return nil, errors.Wrap(err, "GetCosClient") - } - opts := &cos.ObjectGetOptions{} - if rangeOpt != nil { - opts.Range = rangeOpt.String() - } - resp, err := coscli.Object.Get(ctx, key, opts) - if err != nil { - return nil, errors.Wrap(err, "coscli.Object.Get") - } - return resp.Body, nil -} - -func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucketName string, srcKey string, srcOffset int64, srcLength int64) (string, error) { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return "", errors.Wrap(err, "GetCosClient") - } - srcBucket := SBucket{ - region: b.region, - Name: srcBucketName, - } - opts := cos.ObjectCopyPartOptions{} - srcUrl := fmt.Sprintf("%s/%s", srcBucket.getBucketUrlHost(), srcKey) - opts.XCosCopySourceRange = fmt.Sprintf("bytes=%d-%d", srcOffset, srcOffset+srcLength-1) - result, _, err := coscli.Object.CopyPart(ctx, key, uploadId, partIndex, srcUrl, &opts) - if err != nil { - return "", errors.Wrap(err, "coscli.Object.CopyPart") - } - return result.ETag, nil -} - -func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { - if len(websitConf.Index) == 0 { - return errors.Wrap(cloudprovider.ErrNotSupported, "missing Index") - } - if len(websitConf.ErrorDocument) == 0 { - return errors.Wrap(cloudprovider.ErrNotSupported, "missing ErrorDocument") - } - if websitConf.Protocol != "http" && websitConf.Protocol != "https" { - return errors.Wrap(cloudprovider.ErrNotSupported, "missing Protocol") - } - - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrap(err, "b.region.GetCosClient") - } - - rulesOpts := []cos.WebsiteRoutingRule{} - for i := range websitConf.Rules { - rulesOpts = append(rulesOpts, cos.WebsiteRoutingRule{ - ConditionErrorCode: websitConf.Rules[i].ConditionErrorCode, - ConditionPrefix: websitConf.Rules[i].ConditionPrefix, - - RedirectProtocol: websitConf.Rules[i].RedirectProtocol, - RedirectReplaceKey: websitConf.Rules[i].RedirectReplaceKey, - RedirectReplaceKeyPrefix: websitConf.Rules[i].ConditionPrefix, - }) - } - opts := &cos.BucketPutWebsiteOptions{ - Index: websitConf.Index, - Error: &cos.ErrorDocument{Key: websitConf.ErrorDocument}, - RedirectProtocol: &cos.RedirectRequestsProtocol{Protocol: websitConf.Protocol}, - } - if len(rulesOpts) > 0 { - opts.RoutingRules = &cos.WebsiteRoutingRules{Rules: rulesOpts} - } - - _, err = coscli.Bucket.PutWebsite(context.Background(), opts) - if err != nil { - return errors.Wrap(err, "PutWebsite") - } - return nil -} - -func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return cloudprovider.SBucketWebsiteConf{}, errors.Wrap(err, "b.region.GetCosClient") - } - websiteResult, _, err := coscli.Bucket.GetWebsite(context.Background()) - if err != nil { - if strings.Contains(err.Error(), "NoSuchWebsiteConfiguration") { - return cloudprovider.SBucketWebsiteConf{}, nil - } - return cloudprovider.SBucketWebsiteConf{}, errors.Wrap(err, "coscli.Bucket.GetWebsite") - } - - result := cloudprovider.SBucketWebsiteConf{ - Index: websiteResult.Index, - } - if websiteResult.Error != nil { - result.ErrorDocument = websiteResult.Error.Key - } - if websiteResult.RedirectProtocol != nil { - result.Protocol = websiteResult.RedirectProtocol.Protocol - } - routingRules := []cloudprovider.SBucketWebsiteRoutingRule{} - if websiteResult.RoutingRules != nil { - for i := range websiteResult.RoutingRules.Rules { - routingRules = append(routingRules, cloudprovider.SBucketWebsiteRoutingRule{ - ConditionErrorCode: websiteResult.RoutingRules.Rules[i].ConditionErrorCode, - ConditionPrefix: websiteResult.RoutingRules.Rules[i].ConditionPrefix, - - RedirectProtocol: websiteResult.RoutingRules.Rules[i].RedirectProtocol, - RedirectReplaceKey: websiteResult.RoutingRules.Rules[i].RedirectReplaceKey, - RedirectReplaceKeyPrefix: websiteResult.RoutingRules.Rules[i].RedirectReplaceKeyPrefix, - }) - } - } - result.Rules = routingRules - result.Url = b.getWebsiteUrl() - return result, nil -} - -func (b *SBucket) DeleteWebSiteConf() error { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrap(err, "b.region.GetCosClient") - } - _, err = coscli.Bucket.DeleteWebsite(context.Background()) - if err != nil { - return errors.Wrap(err, "coscli.Bucket.DeleteWebsite") - } - return nil -} - -func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { - if len(rules) == 0 { - return nil - } - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrap(err, "b.region.GetCosClient") - } - input := cos.BucketPutCORSOptions{} - for i := range rules { - input.Rules = append(input.Rules, cos.BucketCORSRule{ - AllowedOrigins: rules[i].AllowedOrigins, - AllowedMethods: rules[i].AllowedMethods, - AllowedHeaders: rules[i].AllowedHeaders, - MaxAgeSeconds: rules[i].MaxAgeSeconds, - ExposeHeaders: rules[i].ExposeHeaders, - ID: rules[i].Id, - }) - } - - _, err = coscli.Bucket.PutCORS(context.Background(), &input) - if err != nil { - return errors.Wrap(err, "coscli.Bucket.PutCORS") - } - return nil -} - -func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return nil, errors.Wrap(err, "b.region.GetCosClient") - } - conf, _, err := coscli.Bucket.GetCORS(context.Background()) - if err != nil { - if strings.Contains(err.Error(), "NoSuchCORSConfiguration") { - return nil, nil - } - return nil, errors.Wrap(err, "b.region.GetCORS") - } - result := []cloudprovider.SBucketCORSRule{} - for i := range conf.Rules { - result = append(result, cloudprovider.SBucketCORSRule{ - AllowedOrigins: conf.Rules[i].AllowedOrigins, - AllowedMethods: conf.Rules[i].AllowedMethods, - AllowedHeaders: conf.Rules[i].AllowedHeaders, - MaxAgeSeconds: conf.Rules[i].MaxAgeSeconds, - ExposeHeaders: conf.Rules[i].ExposeHeaders, - Id: strconv.Itoa(i), - }) - } - return result, nil -} - -func (b *SBucket) DeleteCORS() error { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrap(err, "b.region.GetCosClient") - } - _, err = coscli.Bucket.DeleteCORS(context.Background()) - if err != nil { - return errors.Wrap(err, "coscli.Bucket.DeleteCORS") - } - return nil -} - -func (b *SBucket) SetReferer(conf cloudprovider.SBucketRefererConf) error { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrap(err, "b.region.GetCosClient") - } - - if !conf.Enabled { - _, err = coscli.Bucket.PutReferer(context.Background(), nil) - return errors.Wrap(err, "Disable Refer") - } - - opts := cos.BucketPutRefererOptions{ - Status: "Enabled", - EmptyReferConfiguration: "Deny", - RefererType: conf.RefererType, - DomainList: conf.DomainList, - } - - if conf.AllowEmptyRefer { - opts.EmptyReferConfiguration = "Allow" - } - - _, err = coscli.Bucket.PutReferer(context.Background(), &opts) - if err != nil { - return errors.Wrap(err, "coscli.Bucket.PutReferer") - } - return nil -} -func (b *SBucket) GetReferer() (cloudprovider.SBucketRefererConf, error) { - result := cloudprovider.SBucketRefererConf{} - coscli, err := b.region.GetCosClient(b) - if err != nil { - return result, errors.Wrap(err, "b.region.GetCosClient") - } - - referResult, _, err := coscli.Bucket.GetReferer(context.Background()) - if err != nil { - return result, errors.Wrap(err, " coscli.Bucket.GetReferer") - } - - result.AllowEmptyRefer = (referResult.EmptyReferConfiguration == "Allow") - result.Enabled = (referResult.Status == "Enabled") - result.RefererType = referResult.RefererType - result.DomainList = referResult.DomainList - - return result, nil -} - -func toAPICdnArea(area string) string { - switch area { - case "mainland": - return api.CDN_DOMAIN_AREA_MAINLAND - case "overseas": - return api.CDN_DOMAIN_AREA_OVERSEAS - case "global": - return api.CDN_DOMAIN_AREA_GLOBAL - default: - return "" - } -} -func toAPICdnStatus(status string) string { - switch status { - case "online": - return api.CDN_DOMAIN_STATUS_ONLINE - case "offline": - return api.CDN_DOMAIN_STATUS_OFFLINE - case "processing": - return api.CDN_DOMAIN_STATUS_PROCESSING - case "rejected": - return api.CDN_DOMAIN_STATUS_REJECTED - default: - return "" - } -} - -func (b *SBucket) GetCdnDomains() ([]cloudprovider.SCdnDomain, error) { - result := []cloudprovider.SCdnDomain{} - bucketHost := b.getBucketUrlHost() - bucketWebsiteHost := b.getBucketWebsiteUrlHost() - - bucketCdnDomains, err := b.region.client.DescribeAllCdnDomains(nil, []string{bucketHost}, "cos") - if err != nil { - return nil, errors.Wrapf(err, `b.region.client.DescribeAllCdnDomains(nil, []string{%s}, "cos")`, bucketHost) - } - - for i := range bucketCdnDomains { - result = append(result, cloudprovider.SCdnDomain{ - Domain: bucketCdnDomains[i].Domain, - Status: toAPICdnStatus(bucketCdnDomains[i].Status), - Cname: bucketCdnDomains[i].Cname, - Area: toAPICdnArea(bucketCdnDomains[i].Area), - Origin: bucketHost, - OriginType: api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET, - }) - } - - bucketWebsiteCdnDomains, err := b.region.client.DescribeAllCdnDomains(nil, []string{bucketWebsiteHost}, "cos") - if err != nil { - return nil, errors.Wrapf(err, `b.region.client.DescribeAllCdnDomains(nil, []string{%s}, "cos")`, bucketWebsiteHost) - } - - for i := range bucketWebsiteCdnDomains { - result = append(result, cloudprovider.SCdnDomain{ - Domain: bucketWebsiteCdnDomains[i].Domain, - Status: toAPICdnStatus(bucketWebsiteCdnDomains[i].Status), - Cname: bucketWebsiteCdnDomains[i].Cname, - Area: toAPICdnArea(bucketWebsiteCdnDomains[i].Area), - Origin: bucketWebsiteHost, - OriginType: api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET, - }) - } - return result, nil -} - -func getQcsResourcePath(resource []string) []string { - path := []string{} - for i := range resource { - strs := strings.Split(resource[i], ":") - path = append(path, strs[len(strs)-1]) - } - return path -} - -func getQcsUserId(principal []string) []string { - ids := []string{} - for i := range principal { - // qcs::cam::uin/100008182714:uin/100008182714 - // qcs::cam::uin/100008182714:service/cdn - // qcs::cam::anyone:anyone - - strs := strings.Split(principal[i], "::") - ids = append(ids, strings.Replace(strs[len(strs)-1], "uin/", "", 2)) - } - - return ids -} - -var cannedReadActions = [...]string{ - "name/cos:GetBucket", - "name/cos:GetBucketObjectVersions", - "name/cos:HeadBucket", - "name/cos:ListMultipartUploads", - "name/cos:ListParts", - "name/cos:GetObject", - "name/cos:HeadObject", - "name/cos:OptionsObject", -} - -var cannedReadWriteActions = [...]string{ - "name/cos:GetBucket", - "name/cos:GetBucketObjectVersions", - "name/cos:HeadBucket", - "name/cos:ListMultipartUploads", - "name/cos:ListParts", - "name/cos:GetObject", - "name/cos:HeadObject", - "name/cos:OptionsObject", - - "name/cos:PutObject", - "name/cos:PostObject", - "name/cos:DeleteObject", - "name/cos:InitiateMultipartUpload", - "name/cos:UploadPart", - "name/cos:CompleteMultipartUpload", - "name/cos:AbortMultipartUpload", -} - -func getCannedAction(action []string) string { - cannedAction := "" - - actionSet := set.New(set.NonThreadSafe) - for i := range action { - actionSet.Add(action[i]) - } - if actionSet.Has("name/cos:*") { - return "FullControl" - } - - readSet := set.New(set.NonThreadSafe) - for i := range cannedReadActions { - readSet.Add(cannedReadActions[i]) - } - if set.Difference(readSet, actionSet).Size() == 0 { - cannedAction = "Read" - } - - readWriteSet := set.New(set.NonThreadSafe) - for i := range cannedReadWriteActions { - readWriteSet.Add(cannedReadWriteActions[i]) - } - if set.Difference(readWriteSet, actionSet).Size() == 0 { - cannedAction = "ReadWrite" - } - return cannedAction -} - -func (b *SBucket) GetPolicy() ([]cloudprovider.SBucketPolicyStatement, error) { - policyOptions := []cloudprovider.SBucketPolicyStatement{} - coscli, err := b.region.GetCosClient(b) - if err != nil { - return nil, errors.Wrap(err, "GetCosClient") - } - result, _, err := coscli.Bucket.GetPolicy(context.Background()) - if err != nil { - if strings.Contains(err.Error(), "404") { - return nil, nil - } - return nil, errors.Wrap(err, "GetPolicy") - } - - users, err := b.region.client.GetICloudusers() - if err != nil { - return nil, errors.Wrapf(err, "GetICloudusers") - } - - userMaps := map[string]string{} - for i := range users { - userMaps[fmt.Sprintf("%s:%s", b.region.client.ownerName, users[i].GetGlobalId())] = users[i].GetName() - } - - for i := range result.Statement { - policyOption := cloudprovider.SBucketPolicyStatement{ - Principal: result.Statement[i].Principal, - Action: result.Statement[i].Action, - Effect: result.Statement[i].Effect, - Resource: result.Statement[i].Resource, - Condition: result.Statement[i].Condition, - - PrincipalId: getQcsUserId(result.Statement[i].Principal["qcs"]), - CannedAction: getCannedAction(result.Statement[i].Action), - ResourcePath: getQcsResourcePath(result.Statement[i].Resource), - Id: strconv.Itoa(i), - } - policyOption.PrincipalNames = func() map[string]string { - ret := map[string]string{} - for _, id := range policyOption.PrincipalId { - ret[id], _ = userMaps[id] - } - return ret - }() - policyOptions = append(policyOptions, policyOption) - } - return policyOptions, nil -} - -func (b *SBucket) SetPolicy(policy cloudprovider.SBucketPolicyStatementInput) error { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrapf(err, "GetCosClient") - } - opts := cos.BucketPutPolicyOptions{} - opts.Version = "2.0" - oldOpts, _, err := coscli.Bucket.GetPolicy(context.Background()) - if err != nil { - if !strings.Contains(err.Error(), "404") { - return errors.Wrap(err, "GetPolicy") - } - } - if len(oldOpts.Statement) > 0 { - opts.Statement = oldOpts.Statement - } - newStatement := cos.BucketStatement{} - ids := []string{} - for i := range policy.PrincipalId { - id := strings.Split(policy.PrincipalId[i], ":") - if len(id) == 1 { - ids = append(ids, fmt.Sprintf("qcs::cam::uin/%s:uin/%s", id[0], id[0])) - } - if len(id) == 2 { - // 没有主账号id,设为owner id - if len(id[0]) == 0 { - s, _, err := coscli.Service.Get(context.Background()) - if err != nil { - return errors.Wrap(err, "coscli.Service.Get") - } - id[0] = s.Owner.DisplayName - } - // 没有子账号,默认和主账号相同 - if len(id[1]) == 0 { - id[1] = id[0] - } - ids = append(ids, fmt.Sprintf("qcs::cam::uin/%s:uin/%s", id[0], id[1])) - } - if len(id) > 2 { - return errors.Wrap(cloudprovider.ErrNotSupported, "Invalida PrincipalId Input") - } - } - principal := map[string][]string{} - principal["qcs"] = ids - newStatement.Principal = principal - newStatement.Effect = policy.Effect - resources := []string{} - for i := range policy.ResourcePath { - resources = append(resources, fmt.Sprintf("qcs::cos:%s:uid/%s:%s%s", b.GetIRegion().GetId(), b.appId, b.getFullName(), policy.ResourcePath[i])) - } - newStatement.Resource = resources - ipEqual := []string{} - ipNotEqual := []string{} - for i := range policy.IpEquals { - ipEqual = append(ipEqual, policy.IpEquals[i]) - } - for i := range policy.IpNotEquals { - ipNotEqual = append(ipNotEqual, policy.IpNotEquals[i]) - } - condition := map[string]map[string]interface{}{} - newStatement.Condition = condition - if len(ipEqual) > 0 { - newStatement.Condition["ip_equal"] = map[string]interface{}{"qcs:ip": ipEqual} - } - if len(ipNotEqual) > 0 { - newStatement.Condition["ip_not_equal"] = map[string]interface{}{"qcs:ip": ipNotEqual} - } - - if policy.CannedAction == "FullControl" { - newStatement.Action = []string{"name/cos:*"} - } - if policy.CannedAction == "Read" { - newStatement.Action = cannedReadActions[:] - } - if policy.CannedAction == "ReadWrite" { - newStatement.Action = cannedReadWriteActions[:] - } - opts.Statement = append([]cos.BucketStatement{newStatement}, opts.Statement...) - - _, err = coscli.Bucket.PutPolicy(context.Background(), &opts) - if err != nil { - log.Errorf("coscli.Bucket.GetACL fail %s", err) - return errors.Wrapf(err, " coscli.Bucket.PutPolicy(context.Background(), %s)", jsonutils.Marshal(opts).String()) - } - return nil -} - -func (b *SBucket) DeletePolicy(id []string) ([]cloudprovider.SBucketPolicyStatement, error) { - deletedPolicy := []cloudprovider.SBucketPolicyStatement{} - coscli, err := b.region.GetCosClient(b) - if err != nil { - log.Errorf("GetCosClient fail %s", err) - return nil, errors.Wrap(err, "b.region.GetCosClient(b)") - } - result, _, err := coscli.Bucket.GetPolicy(context.Background()) - if err != nil { - if strings.Contains(err.Error(), "404") { - return nil, nil - } - log.Errorf("coscli.Bucket.GetACL fail %s", err) - return nil, errors.Wrap(err, "coscli.Bucket.GetPolicy(context.Background())") - } - newOpts := cos.BucketPutPolicyOptions{} - newOpts.Version = result.Version - newOpts.Principal = result.Principal - excludeMap := map[int]bool{} - for i := range id { - index, err := strconv.Atoi(id[i]) - if err == nil { - excludeMap[index] = true - } - } - for i := range result.Statement { - if _, ok := excludeMap[i]; !ok { - newOpts.Statement = append(newOpts.Statement, result.Statement[i]) - } else { - deletedPolicy = append(deletedPolicy, cloudprovider.SBucketPolicyStatement{ - Principal: result.Statement[i].Principal, - Action: result.Statement[i].Action, - Effect: result.Statement[i].Effect, - Resource: result.Statement[i].Resource, - Condition: result.Statement[i].Condition, - - PrincipalId: getQcsUserId(result.Statement[i].Principal["qcs"]), - CannedAction: getCannedAction(result.Statement[i].Action), - ResourcePath: getQcsResourcePath(result.Statement[i].Resource), - }) - } - } - - if len(newOpts.Statement) == 0 { - _, err := coscli.Bucket.DeletePolicy(context.Background()) - if err != nil { - log.Errorf("coscli.Bucket.DeletePolicy fail %s", err) - return nil, errors.Wrap(err, "coscli.Bucket.DeletePolicy(context.Background())") - } - return deletedPolicy, nil - } - - _, err = coscli.Bucket.PutPolicy(context.Background(), &newOpts) - if err != nil { - log.Errorf("coscli.Bucket.GetACL fail %s", err) - return nil, errors.Wrapf(err, "coscli.Bucket.PutPolicy(context.Background(), %s)", jsonutils.Marshal(newOpts).String()) - } - return deletedPolicy, nil -} - -func (b *SBucket) GetTags() (map[string]string, error) { - coscli, err := b.region.GetCosClient(b) - if err != nil { - return nil, errors.Wrap(err, "GetCosClient") - } - - tagresult, _, err := coscli.Bucket.GetTagging(context.Background()) - if err != nil { - if strings.Contains(err.Error(), "404") { - return nil, nil - } - return nil, errors.Wrap(err, "GetTagging") - } - result := map[string]string{} - for i := range tagresult.TagSet { - result[tagresult.TagSet[i].Key] = tagresult.TagSet[i].Value - } - return result, nil -} - -func (b *SBucket) SetTags(tags map[string]string, replace bool) error { - if !replace { - return cloudprovider.ErrNotSupported - } - coscli, err := b.region.GetCosClient(b) - if err != nil { - return errors.Wrapf(err, "b.region.GetCosClient(%s)", b.Name) - } - - _, err = coscli.Bucket.DeleteTagging(context.Background()) - if err != nil { - return errors.Wrapf(err, "DeleteTagging") - } - - if len(tags) == 0 { - return nil - } - - input := cos.BucketPutTaggingOptions{} - for k, v := range tags { - input.TagSet = append(input.TagSet, cos.BucketTaggingTag{Key: k, Value: v}) - } - - _, err = coscli.Bucket.PutTagging(context.Background(), &input) - if err != nil { - return errors.Wrapf(err, "coscli.Bucket.PutTagging(%s)", jsonutils.Marshal(input)) - } - return nil -} - -func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { - coscli, err := b.region.GetCosClient(b) - if err != nil { - log.Errorf("GetCosClient fail %s", err) - return nil, errors.Wrap(err, "b.region.GetCosClient(b)") - } - result := []cloudprovider.SBucketMultipartUploads{} - input := cos.ListMultipartUploadsOptions{} - keyMarker := "" - uploadIDMarker := "" - for { - input.KeyMarker = keyMarker - input.UploadIDMarker = uploadIDMarker - output, _, err := coscli.Bucket.ListMultipartUploads(context.Background(), &input) - if err != nil { - return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") - } - for i := range output.Uploads { - temp := cloudprovider.SBucketMultipartUploads{ - ObjectName: output.Uploads[i].Key, - UploadID: output.Uploads[i].UploadID, - Initiator: output.Uploads[i].Initiator.DisplayName, - } - temp.Initiated, _ = timeutils.ParseTimeStr(output.Uploads[i].Initiated) - result = append(result, temp) - } - keyMarker = output.NextKeyMarker - uploadIDMarker = output.NextUploadIDMarker - if !output.IsTruncated { - break - } - } - - return result, nil -} diff --git a/pkg/multicloud/qcloud/cam_group.go b/pkg/multicloud/qcloud/cam_group.go deleted file mode 100644 index 1f2e581b23..0000000000 --- a/pkg/multicloud/qcloud/cam_group.go +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "time" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SGroup struct { - client *SQcloudClient - - GroupId int - GroupName string - CreateTime time.Time -} - -func (self *SGroup) GetName() string { - return self.GroupName -} - -func (self *SGroup) GetGlobalId() string { - return self.GroupName -} - -func (self *SGroup) GetDescription() string { - return "" -} - -func (self *SGroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { - users := []SUser{} - offset := 1 - for { - part, total, err := self.client.ListGroupUsers(self.GroupId, offset, 100) - if err != nil { - return nil, errors.Wrapf(err, "ListGroupUsers") - } - users = append(users, part...) - if len(users) >= total { - break - } - offset += 1 - } - ret := []cloudprovider.IClouduser{} - for i := range users { - users[i].client = self.client - ret = append(ret, &users[i]) - } - return ret, nil -} - -func (self *SGroup) AddUser(name string) error { - user, err := self.client.GetUser(name) - if err != nil { - return errors.Wrapf(err, "GetUser(%s)", name) - } - return self.client.AddUserToGroup(self.GroupId, int(user.Uid)) -} - -func (self *SGroup) RemoveUser(name string) error { - user, err := self.client.GetUser(name) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return errors.Wrapf(err, "GetUser(%s)", name) - } - return self.client.RemoveUserFromGroup(self.GroupId, int(user.Uid)) -} - -func (self *SGroup) AttachSystemPolicy(policyId string) error { - return self.client.AttachGroupPolicy(self.GroupId, policyId) -} - -func (self *SGroup) AttachCustomPolicy(policyId string) error { - return self.client.AttachGroupPolicy(self.GroupId, policyId) -} - -func (self *SGroup) DetachSystemPolicy(policyId string) error { - return self.client.DetachGroupPolicy(self.GroupId, policyId) -} - -func (self *SGroup) DetachCustomPolicy(policyId string) error { - return self.client.DetachGroupPolicy(self.GroupId, policyId) -} - -func (self *SGroup) ListGroupPolicies() ([]SPolicy, error) { - policies := []SPolicy{} - offset := 1 - for { - part, total, err := self.client.ListAttachedGroupPolicies(self.GroupId, offset, 200) - if err != nil { - return nil, errors.Wrapf(err, "ListAttachedGroupPolicies") - } - policies = append(policies, part...) - if len(policies) >= total { - break - } - offset += 1 - } - return policies, nil -} - -func (self *SGroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := self.ListGroupPolicies() - if err != nil { - return nil, errors.Wrapf(err, "ListGroupPolicies") - } - ret := []cloudprovider.ICloudpolicy{} - customPolicyMaps, err := self.client.GetCustomPolicyMaps() - if err != nil { - return nil, errors.Wrap(err, "GetCustomPolicyIds") - } - for i := range policies { - _, ok := customPolicyMaps[policies[i].PolicyName] - if ok { - policies[i].client = self.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (self *SQcloudClient) GetCustomPolicyMaps() (map[string]int64, error) { - policyMaps := map[string]int64{} - offset := 1 - for { - part, total, err := self.ListPolicies("", "Local", offset, 50) - if err != nil { - return nil, errors.Wrap(err, "ListPolicies") - } - for _, policy := range part { - policyMaps[policy.PolicyName] = policy.PolicyId - } - if len(policyMaps) >= total { - break - } - offset += 1 - } - return policyMaps, nil -} - -func (self *SGroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies, err := self.ListGroupPolicies() - if err != nil { - return nil, errors.Wrapf(err, "ListGroupPolicies") - } - ret := []cloudprovider.ICloudpolicy{} - customPolicyMaps, err := self.client.GetCustomPolicyMaps() - if err != nil { - return nil, errors.Wrap(err, "GetCustomPolicyIds") - } - for i := range policies { - _, ok := customPolicyMaps[policies[i].PolicyName] - if !ok { - policies[i].client = self.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (self *SGroup) Delete() error { - return self.client.DeleteGroup(self.GroupId) -} - -func (self *SQcloudClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - ret := []cloudprovider.ICloudgroup{} - offset := 1 - for { - part, total, err := self.ListGroups("", offset, 50) - if err != nil { - return nil, errors.Wrapf(err, "DescribeRoleList") - } - for i := range part { - part[i].client = self - ret = append(ret, &part[i]) - } - if total >= len(ret) { - break - } - offset += 1 - } - return ret, nil -} - -func (self *SQcloudClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - group, err := self.CreateGroup(name, desc) - if err != nil { - return nil, errors.Wrapf(err, "CreateGroup") - } - return group, nil -} - -func (self *SQcloudClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - groups := []SGroup{} - offset := 1 - for { - part, total, err := self.ListGroups(name, offset, 50) - if err != nil { - return nil, errors.Wrapf(err, "ListGroups") - } - groups = append(groups, part...) - if len(groups) >= total { - break - } - offset += 1 - } - for i := range groups { - if groups[i].GroupName == name { - groups[i].client = self - return &groups[i], nil - } - } - return nil, errors.Wrap(cloudprovider.ErrNotFound, name) -} - -func (self *SQcloudClient) ListGroups(keyword string, offset int, limit int) ([]SGroup, int, error) { - if offset < 1 { - offset = 1 - } - if limit <= 0 || limit > 50 { - limit = 50 - } - params := map[string]string{ - "Page": fmt.Sprintf("%d", offset), - "Rp": fmt.Sprintf("%d", limit), - } - if len(keyword) > 0 { - params["Keyword"] = keyword - } - - resp, err := self.camRequest("ListGroups", params) - if err != nil { - return nil, 0, errors.Wrap(err, "camRequest.ListGroups") - } - groups := []SGroup{} - err = resp.Unmarshal(&groups, "GroupInfo") - if err != nil { - return nil, 0, errors.Wrap(err, "resp.Unmarshal") - } - total, _ := resp.Float("TotalNum") - return groups, int(total), nil -} - -func (self *SQcloudClient) CreateGroup(name string, remark string) (*SGroup, error) { - params := map[string]string{ - "GroupName": name, - } - if len(remark) > 0 { - params["Remark"] = remark - } - resp, err := self.camRequest("CreateGroup", params) - if err != nil { - return nil, errors.Wrap(err, "camRequest.CreateGroup") - } - groupId, _ := resp.Float("GroupId") - return self.GetGroup(int(groupId)) -} - -func (self *SQcloudClient) GetGroup(groupId int) (*SGroup, error) { - params := map[string]string{ - "GroupId": fmt.Sprintf("%d", groupId), - } - resp, err := self.camRequest("GetGroup", params) - if err != nil { - return nil, errors.Wrap(err, "camRequest.GetGroup") - } - group := &SGroup{client: self} - err = resp.Unmarshal(group) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return group, nil -} - -func (self *SQcloudClient) DeleteGroup(id int) error { - params := map[string]string{ - "GroupId": fmt.Sprintf("%d", id), - } - _, err := self.camRequest("DeleteGroup", params) - return err -} - -func (self *SQcloudClient) ListAttachedGroupPolicies(groupId int, offset int, limit int) ([]SPolicy, int, error) { - if offset < 1 { - offset = 1 - } - if limit <= 0 || limit > 50 { - limit = 50 - } - params := map[string]string{ - "TargetGroupId": fmt.Sprintf("%d", groupId), - "Page": fmt.Sprintf("%d", offset), - "Rp": fmt.Sprintf("%d", limit), - } - resp, err := self.camRequest("ListAttachedGroupPolicies", params) - if err != nil { - return nil, 0, errors.Wrap(err, "iamRequest.ListAttachedGroupPolicies") - } - policies := []SPolicy{} - err = resp.Unmarshal(&policies, "List") - if err != nil { - return nil, 0, errors.Wrap(err, "resp.Unmarshal") - } - total, _ := resp.Float("TotalNum") - return policies, int(total), nil -} - -func (self *SQcloudClient) ListGroupUsers(groupId int, offset int, limit int) ([]SUser, int, error) { - if offset < 1 { - offset = 1 - } - if limit <= 0 || limit > 50 { - limit = 50 - } - params := map[string]string{ - "GroupId": fmt.Sprintf("%d", groupId), - "Page": fmt.Sprintf("%d", offset), - "Rp": fmt.Sprintf("%d", limit), - } - resp, err := self.camRequest("ListUsersForGroup", params) - if err != nil { - return nil, 0, errors.Wrap(err, "iamRequest.ListUserForGroup") - } - users := []SUser{} - err = resp.Unmarshal(&users, "UserInfo") - if err != nil { - return nil, 0, errors.Wrap(err, "resp.Unmarshal") - } - total, _ := resp.Float("TotalNum") - return users, int(total), nil -} - -func (self *SQcloudClient) RemoveUserFromGroup(groupId, userId int) error { - params := map[string]string{ - "Info.0.Uid": fmt.Sprintf("%d", userId), - "Info.0.GroupId": fmt.Sprintf("%d", groupId), - } - _, err := self.camRequest("RemoveUserFromGroup", params) - return err -} - -func (self *SQcloudClient) AddUserToGroup(groupId, userId int) error { - params := map[string]string{ - "Info.0.Uid": fmt.Sprintf("%d", userId), - "Info.0.GroupId": fmt.Sprintf("%d", groupId), - } - _, err := self.camRequest("AddUserToGroup", params) - return err -} - -func (self *SQcloudClient) AttachGroupPolicy(groupId int, policyId string) error { - params := map[string]string{ - "PolicyId": policyId, - "AttachGroupId": fmt.Sprintf("%d", groupId), - } - _, err := self.camRequest("AttachGroupPolicy", params) - return err -} - -func (self *SQcloudClient) DetachGroupPolicy(groupId int, policyId string) error { - params := map[string]string{ - "PolicyId": policyId, - "DetachGroupId": fmt.Sprintf("%d", groupId), - } - _, err := self.camRequest("DetachGroupPolicy", params) - return err -} diff --git a/pkg/multicloud/qcloud/cam_policy.go b/pkg/multicloud/qcloud/cam_policy.go deleted file mode 100644 index f3864743f3..0000000000 --- a/pkg/multicloud/qcloud/cam_policy.go +++ /dev/null @@ -1,285 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SPolicy struct { - client *SQcloudClient - - PolicyId int64 - PolicyName string - AddTime time.Time - CreateMode string - PolicyType string - Description string - PolicyDocument string -} - -func (self *SPolicy) GetGlobalId() string { - return fmt.Sprintf("%d", self.PolicyId) -} - -func (self *SPolicy) GetName() string { - return self.PolicyName -} - -func (self *SPolicy) UpdateDocument(document *jsonutils.JSONDict) error { - return self.client.UpdatePolicy(int(self.PolicyId), document.String(), "") -} - -func (self *SPolicy) GetDocument() (*jsonutils.JSONDict, error) { - if len(self.PolicyDocument) == 0 { - err := self.Refresh() - if err != nil { - return nil, errors.Wrapf(err, "Refesh") - } - } - jsonObj, err := jsonutils.Parse([]byte(self.PolicyDocument)) - if err != nil { - return nil, errors.Wrapf(err, "jsonutils.Parse") - } - return jsonObj.(*jsonutils.JSONDict), nil -} - -func (self *SPolicy) Delete() error { - return self.client.DeletePolicy([]int{int(self.PolicyId)}) -} - -func (self *SPolicy) Refresh() error { - p, err := self.client.GetPolicy(self.GetGlobalId()) - if err != nil { - return errors.Wrapf(err, "GetPolicy(%s)", self.GetGlobalId()) - } - // p.PolicyId一般为0,若jsonutils.Update会有问题 - self.Description = p.Description - self.PolicyDocument = p.PolicyDocument - return nil -} - -func (self *SPolicy) GetDescription() string { - if len(self.Description) == 0 { - err := self.Refresh() - if err != nil { - return "" - } - } - return self.Description -} - -func (self *SQcloudClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - ret := []cloudprovider.ICloudpolicy{} - offset := 1 - for { - part, total, err := self.ListPolicies("", "QCS", offset, 50) - if err != nil { - return nil, errors.Wrap(err, "ListPolicies") - } - for i := range part { - part[i].client = self - ret = append(ret, &part[i]) - } - if len(ret) >= total { - break - } - offset += 1 - } - return ret, nil -} - -func (self *SQcloudClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - ret := []cloudprovider.ICloudpolicy{} - offset := 1 - for { - part, total, err := self.ListPolicies("", "Local", offset, 50) - if err != nil { - return nil, errors.Wrap(err, "ListPolicies") - } - for i := range part { - part[i].client = self - ret = append(ret, &part[i]) - } - if len(ret) >= total { - break - } - offset += 1 - } - return ret, nil -} - -func (self *SQcloudClient) ListAttachedUserPolicies(uin string, offset int, limit int) ([]SPolicy, int, error) { - if offset < 1 { - offset = 1 - } - if limit <= 0 || limit > 50 { - limit = 50 - } - params := map[string]string{ - "TargetUin": uin, - "Page": fmt.Sprintf("%d", offset), - "Rp": fmt.Sprintf("%d", limit), - } - resp, err := self.camRequest("ListAttachedUserPolicies", params) - if err != nil { - return nil, 0, errors.Wrap(err, "camRequest.ListAttachedUserPolicies") - } - policies := []SPolicy{} - err = resp.Unmarshal(&policies, "List") - if err != nil { - return nil, 0, errors.Wrap(err, "resp.Unmarshal") - } - total, _ := resp.Float("TotalNum") - return policies, int(total), nil -} - -func (self *SQcloudClient) AttachUserPolicy(uin, policyId string) error { - params := map[string]string{ - "AttachUin": uin, - "PolicyId": policyId, - } - _, err := self.camRequest("AttachUserPolicy", params) - return err -} - -func (self *SQcloudClient) DetachUserPolicy(uin, policyId string) error { - params := map[string]string{ - "DetachUin": uin, - "PolicyId": policyId, - } - _, err := self.camRequest("DetachUserPolicy", params) - return err -} - -// https://cloud.tencent.com/document/api/598/34570 -func (self *SQcloudClient) ListPolicies(keyword, scope string, offset int, limit int) ([]SPolicy, int, error) { - if offset < 1 { - offset = 1 - } - if limit <= 0 || limit > 50 { - limit = 50 - } - params := map[string]string{ - "Page": fmt.Sprintf("%d", offset), - "Rp": fmt.Sprintf("%d", limit), - } - if len(scope) > 0 { - params["Scope"] = scope - } - if len(keyword) > 0 { - params["Keyword"] = keyword - } - resp, err := self.camRequest("ListPolicies", params) - if err != nil { - return nil, 0, errors.Wrap(err, "camRequest.ListPolicies") - } - policies := []SPolicy{} - err = resp.Unmarshal(&policies, "List") - if err != nil { - return nil, 0, errors.Wrap(err, "resp.Unmarshal") - } - total, _ := resp.Float("TotalNum") - return policies, int(total), nil -} - -func (self *SQcloudClient) GetPolicy(policyId string) (*SPolicy, error) { - params := map[string]string{ - "PolicyId": policyId, - } - resp, err := self.camRequest("GetPolicy", params) - if err != nil { - return nil, errors.Wrap(err, "GetPolicy") - } - policy := SPolicy{} - err = resp.Unmarshal(&policy) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return &policy, nil -} - -func (self *SQcloudClient) DeletePolicy(policyIds []int) error { - params := map[string]string{} - for i, policyId := range policyIds { - params[fmt.Sprintf("PolicyId.%d", i)] = fmt.Sprintf("%d", policyId) - } - _, err := self.camRequest("DeletePolicy", params) - return err -} - -func (self *SQcloudClient) GetPolicyByName(name string) (*SPolicy, error) { - policies := []SPolicy{} - offset := 1 - for { - part, total, err := self.ListPolicies(name, "", offset, 50) - if err != nil { - return nil, errors.Wrapf(err, "ListPolicies") - } - policies = append(policies, part...) - if len(policies) >= total { - break - } - offset += 1 - } - for i := range policies { - if policies[i].PolicyName == name { - policies[i].client = self - return &policies[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetPolicyByName(%s)", name) -} - -func (self *SQcloudClient) CreatePolicy(name, document, desc string) (*SPolicy, error) { - params := map[string]string{ - "PolicyName": name, - "PolicyDocument": document, - "Description": desc, - } - _, err := self.camRequest("CreatePolicy", params) - if err != nil { - return nil, errors.Wrapf(err, "CreatePolicy") - } - return self.GetPolicyByName(name) -} - -func (self *SQcloudClient) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { - policy, err := self.CreatePolicy(opts.Name, opts.Document.String(), opts.Desc) - if err != nil { - return nil, errors.Wrapf(err, "CreatePolicy") - } - return policy, nil -} - -func (self *SQcloudClient) UpdatePolicy(policyId int, document, desc string) error { - params := map[string]string{ - "PolicyId": fmt.Sprintf("%d", policyId), - } - if len(document) > 0 { - params["PolicyDocument"] = document - } - if len(desc) > 0 { - params["Description"] = desc - } - _, err := self.camRequest("UpdatePolicy", params) - return err -} diff --git a/pkg/multicloud/qcloud/cam_role.go b/pkg/multicloud/qcloud/cam_role.go deleted file mode 100644 index 9fa911ab12..0000000000 --- a/pkg/multicloud/qcloud/cam_role.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - DEFAULT_ROLE_DOCUMENT = `{"version":"2.0","statement":[{"action":"name/sts:AssumeRole","effect":"allow","principal":{"service":["cvm.qcloud.com"]}}]}` -) - -/* -"AddTime": "2020-08-11 17:03:30", -"ConsoleLogin": 0.000000, -"Description": "hello", -"PolicyDocument": "{\"version\":\"2.0\",\"statement\":[{\"action\":\"name/sts:AssumeRole\",\"effect\":\"allow\",\"principal\":{\"service\":[\"cdb.qcloud.com\",\"blueking.cloud.tencent.com\"]}}]}", -"RoleId": "4611686018428392276", -"RoleName": "test-role", -"RoleType": "user", -"SessionDuration": 0.000000, -"UpdateTime": "2020-08-11 17:03:30" -*/ - -type SPrincipal struct { - Federated []string -} - -type Statement struct { - Action string - Effect string - Principal SPrincipal -} - -type SRole struct { - multicloud.SResourceBase - client *SQcloudClient - - AddTime time.Time - ConsoleLogin float32 - Description string - PolicyDocument string - RoleId string - RoleName string - RoleType string - SessionDuration float32 - UpdateTime time.Time -} - -func (self *SRole) GetGlobalId() string { - return self.RoleName -} - -func (self *SRole) GetName() string { - return self.RoleName -} - -func (self *SRole) GetDocument() *jsonutils.JSONDict { - if len(self.PolicyDocument) > 0 { - document, err := jsonutils.Parse([]byte(self.PolicyDocument)) - if err != nil { - return nil - } - return document.(*jsonutils.JSONDict) - } - return nil -} - -func (self *SRole) GetSAMLProvider() string { - document := self.GetDocument() - if document != nil { - statements := []Statement{} - document.Unmarshal(&statements, "statement") - for i := range statements { - if statements[i].Action == "name/sts:AssumeRoleWithSAML" { - for _, federated := range statements[i].Principal.Federated { - if strings.Contains(federated, ":saml-provider/") { - info := strings.Split(federated, "/") - return info[len(info)-1] - } - } - } - } - } - return "" -} - -func (self *SRole) Delete() error { - return self.client.DeleteRole(self.RoleName) -} - -func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - ret := []cloudprovider.ICloudpolicy{} - for { - part, total, err := self.client.ListAttachedRolePolicies(self.RoleName, "", len(ret), 50) - if err != nil { - return nil, errors.Wrapf(err, "ListAttachedRolePolicies") - } - for i := range part { - part[i].client = self.client - ret = append(ret, &part[i]) - } - if len(ret) >= total { - break - } - } - return ret, nil -} - -func (self *SRole) AttachPolicy(id string) error { - return self.client.AttachRolePolicy(self.RoleName, id) -} - -func (self *SRole) DetachPolicy(id string) error { - return self.client.DetachRolePolicy(self.RoleName, id) -} - -func (self *SQcloudClient) GetICloudroles() ([]cloudprovider.ICloudrole, error) { - ret := []cloudprovider.ICloudrole{} - for { - part, total, err := self.DescribeRoleList(len(ret), 200) - if err != nil { - return nil, errors.Wrapf(err, "DescribeRoleList") - } - for i := range part { - part[i].client = self - ret = append(ret, &part[i]) - } - if len(ret) >= total { - break - } - } - return ret, nil -} - -func (self *SQcloudClient) DescribeRoleList(offset int, limit int) ([]SRole, int, error) { - if limit < 1 || limit > 200 { - limit = 200 - } - if offset < 1 { - offset = 1 - } - params := map[string]string{ - "Page": fmt.Sprintf("%d", offset), - "Rp": fmt.Sprintf("%d", limit), - } - roles := []SRole{} - resp, err := self.camRequest("DescribeRoleList", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeRoleList") - } - err = resp.Unmarshal(&roles, "List") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - total, _ := resp.Float("TotalNum") - return roles, int(total), nil -} - -func (self *SQcloudClient) CreateRole(name, document, desc string) (*SRole, error) { - if len(document) == 0 { - document = DEFAULT_ROLE_DOCUMENT - } - params := map[string]string{ - "RoleName": name, - "PolicyDocument": document, - "ConsoleLogin": "1", - "SessionDuration": "43200", - "Description": desc, - } - _, err := self.camRequest("CreateRole", params) - if err != nil { - return nil, errors.Wrap(err, "CreateRole") - } - return self.GetRole(name) -} - -func (self *SQcloudClient) GetRole(name string) (*SRole, error) { - params := map[string]string{ - "RoleName": name, - } - resp, err := self.camRequest("GetRole", params) - if err != nil { - return nil, errors.Wrapf(err, "GetRole(%s)", name) - } - role := &SRole{client: self} - err = resp.Unmarshal(role, "RoleInfo") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return role, nil -} - -func (self *SQcloudClient) ListAttachedRolePolicies(roleName, policyType string, offset, limit int) ([]SPolicy, int, error) { - if limit < 1 || limit > 200 { - limit = 200 - } - if offset < 1 { - offset = 1 - } - params := map[string]string{ - "Page": fmt.Sprintf("%d", offset), - "Rp": fmt.Sprintf("%d", limit), - "RoleName": roleName, - } - if len(policyType) > 0 { - params["PolicyType"] = policyType - } - resp, err := self.camRequest("ListAttachedRolePolicies", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "ListAttachedRolePolicies") - } - policies := []SPolicy{} - err = resp.Unmarshal(&policies, "List") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - total, _ := resp.Float("TotalNum") - return policies, int(total), nil -} - -func (self *SQcloudClient) DeleteRole(name string) error { - params := map[string]string{ - "RoleName": name, - } - _, err := self.camRequest("DeleteRole", params) - return err -} - -func (self *SQcloudClient) AttachRolePolicy(roleName string, policyId string) error { - params := map[string]string{ - "AttachRoleName": roleName, - } - if _id, _ := strconv.Atoi(policyId); _id > 0 { - params["PolicyId"] = policyId - } else { - params["PolicyName"] = policyId - } - _, err := self.camRequest("AttachRolePolicy", params) - return err -} - -func (self *SQcloudClient) DetachRolePolicy(roleName string, policyId string) error { - params := map[string]string{ - "DetachRoleName": roleName, - } - if _id, _ := strconv.Atoi(policyId); _id > 0 { - params["PolicyId"] = policyId - } else { - params["PolicyName"] = policyId - } - _, err := self.camRequest("DetachRolePolicy", params) - return err -} diff --git a/pkg/multicloud/qcloud/cam_user.go b/pkg/multicloud/qcloud/cam_user.go deleted file mode 100644 index 3896411a75..0000000000 --- a/pkg/multicloud/qcloud/cam_user.go +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SUser struct { - multicloud.SBaseClouduser - client *SQcloudClient - - Uin int64 - Name string - Uid int64 - Remark string - ConsoleLogin int - CountryCode string - Email string -} - -func (user *SUser) GetGlobalId() string { - return fmt.Sprintf("%d", user.Uin) -} - -func (self *SUser) GetEmailAddr() string { - return self.Email -} - -func (self *SUser) GetInviteUrl() string { - return "" -} - -func (user *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies := []SPolicy{} - offset := 1 - for { - part, total, err := user.client.ListAttachedUserPolicies(user.GetGlobalId(), offset, 50) - if err != nil { - return nil, errors.Wrap(err, "GetClouduserPolicy") - } - policies = append(policies, part...) - if len(policies) >= total { - break - } - offset += 1 - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].PolicyType == "QCS" || policies[i].PolicyType == "" { - policies[i].client = user.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (user *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - policies := []SPolicy{} - offset := 1 - for { - part, total, err := user.client.ListAttachedUserPolicies(user.GetGlobalId(), offset, 50) - if err != nil { - return nil, errors.Wrap(err, "GetClouduserPolicy") - } - policies = append(policies, part...) - if len(policies) >= total { - break - } - offset += 1 - } - ret := []cloudprovider.ICloudpolicy{} - for i := range policies { - if policies[i].PolicyType == "User" { - policies[i].client = user.client - ret = append(ret, &policies[i]) - } - } - return ret, nil -} - -func (user *SUser) AttachSystemPolicy(policyId string) error { - return user.client.AttachUserPolicy(user.GetGlobalId(), policyId) -} - -func (user *SUser) AttachCustomPolicy(policyId string) error { - return user.client.AttachUserPolicy(user.GetGlobalId(), policyId) -} - -func (user *SUser) DetachSystemPolicy(policyId string) error { - return user.client.DetachUserPolicy(user.GetGlobalId(), policyId) -} - -func (user *SUser) DetachCustomPolicy(policyId string) error { - return user.client.DetachUserPolicy(user.GetGlobalId(), policyId) -} - -func (user *SUser) IsConsoleLogin() bool { - return user.ConsoleLogin == 1 -} - -func (user *SUser) Delete() error { - return user.client.DeleteUser(user.Name) -} - -func (user *SUser) ResetPassword(password string) error { - return user.client.UpdateUser(user.Name, password) -} - -func (user *SUser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - ret := []cloudprovider.ICloudgroup{} - offset := 1 - for { - part, total, err := user.client.ListGroupsForUser(int(user.Uin), offset, 100) - if err != nil { - return nil, errors.Wrapf(err, "ListGroupsForUser") - } - for i := range part { - part[i].client = user.client - ret = append(ret, &part[i]) - } - if len(ret) >= total { - break - } - offset += 1 - } - return ret, nil -} - -func (user *SUser) GetName() string { - return user.Name -} - -func (self *SQcloudClient) DeleteUser(name string) error { - params := map[string]string{ - "Name": name, - "Force": "1", - } - _, err := self.camRequest("DeleteUser", params) - return err -} - -func (self *SQcloudClient) ListUsers() ([]SUser, error) { - resp, err := self.camRequest("ListUsers", nil) - if err != nil { - return nil, errors.Wrap(err, "camRequest.ListUsers") - } - users := []SUser{} - err = resp.Unmarshal(&users, "Data") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return users, nil -} - -func (self *SQcloudClient) ListGroupsForUser(uin int, offset, limit int) ([]SGroup, int, error) { - if offset < 1 { - offset = 1 - } - if limit <= 0 || limit > 50 { - limit = 50 - } - params := map[string]string{ - "SubUin": fmt.Sprintf("%d", uin), - "Page": fmt.Sprintf("%d", offset), - "Rp": fmt.Sprintf("%d", limit), - } - resp, err := self.camRequest("ListGroupsForUser", params) - if err != nil { - return nil, 0, errors.Wrap(err, "camRequest.ListGroupsForUser") - } - groups := []SGroup{} - err = resp.Unmarshal(&groups, "GroupInfo") - if err != nil { - return nil, 0, errors.Wrap(err, "resp.Unmarshal") - } - total, _ := resp.Float("TotalNum") - return groups, int(total), nil -} - -func (self *SQcloudClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { - users, err := self.ListUsers() - if err != nil { - return nil, errors.Wrap(err, "ListUsers") - } - - ret := []cloudprovider.IClouduser{} - for i := range users { - users[i].client = self - ret = append(ret, &users[i]) - } - collaborators := []SUser{} - for { - part, total, err := self.ListCollaborators(len(collaborators), 50) - if err != nil { - return nil, errors.Wrapf(err, "ListCollaborators") - } - collaborators = append(collaborators, part...) - if len(collaborators) >= total { - break - } - } - for i := range collaborators { - collaborators[i].client = self - ret = append(ret, &collaborators[i]) - } - return ret, nil -} - -func (self *SQcloudClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.GetUser(name) -} - -func (self *SQcloudClient) GetUser(name string) (*SUser, error) { - params := map[string]string{ - "Name": name, - } - resp, err := self.camRequest("GetUser", params) - if err != nil { - return nil, errors.Wrap(err, "camRequest.GetUser") - } - user := &SUser{client: self} - err = resp.Unmarshal(user) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return user, nil -} - -func (self *SQcloudClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - user, err := self.AddUser(conf.Name, conf.Password, conf.Desc, conf.IsConsoleLogin) - if err != nil { - return nil, errors.Wrap(err, "CreateClouduser") - } - for _, policyId := range conf.ExternalPolicyIds { - err = user.client.AttachUserPolicy(fmt.Sprintf("%d", user.Uin), policyId) - if err != nil { - log.Errorf("attach policy %s for user %s error: %v", policyId, conf.Name, err) - } - } - return user, nil -} - -func (self *SQcloudClient) AddUser(name, password, desc string, consoleLogin bool) (*SUser, error) { - params := map[string]string{ - "Name": name, - "Remark": desc, - "ConsoleLogin": "0", - } - if len(password) > 0 { - params["Password"] = password - } - if consoleLogin { - params["ConsoleLogin"] = "1" - } - resp, err := self.camRequest("AddUser", params) - if err != nil { - return nil, errors.Wrap(err, "camRequest.AddUser") - } - user := &SUser{client: self} - err = resp.Unmarshal(user) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return user, nil -} - -func (self *SQcloudClient) UpdateUser(name, password string) error { - params := map[string]string{ - "Name": name, - "ConsoleLogin": "1", - "Password": password, - } - _, err := self.camRequest("UpdateUser", params) - if err != nil { - return errors.Wrap(err, "UpdateUser") - } - return nil -} diff --git a/pkg/multicloud/qcloud/cdn.go b/pkg/multicloud/qcloud/cdn.go deleted file mode 100644 index 1cef888137..0000000000 --- a/pkg/multicloud/qcloud/cdn.go +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strconv" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SCdnOrigin struct { - Origins []string `json:"Origins"` - OriginType string `json:"OriginType"` - ServerName string `json:"ServerName"` - CosPrivateAccess string `json:"CosPrivateAccess"` - OriginPullProtocol string `json:"OriginPullProtocol"` - BackupOrigins []string `json:"BackupOrigins"` - BackupOriginType string `json:"BackupOriginType"` - BackupServerName string `json:"BackupServerName"` -} - -type SCdnDomain struct { - multicloud.SResourceBase - multicloud.QcloudTags - - client *SQcloudClient - - Area string `json:"Area"` - Cname string `json:"Cname"` - CreateTime string `json:"CreateTime"` - Disable string `json:"Disable"` - Domain string `json:"Domain"` - Origin SCdnOrigin `json:"Origin"` - ProjectID int `json:"ProjectId"` - Readonly string `json:"Readonly"` - ResourceID string `json:"ResourceId"` - ServiceType string `json:"ServiceType"` - Status string `json:"Status"` - UpdateTime string `json:"UpdateTime"` -} - -func (self *SCdnDomain) GetName() string { - return self.Domain -} - -func (self *SCdnDomain) GetGlobalId() string { - return self.Domain -} - -func (self *SCdnDomain) GetId() string { - return self.Domain -} - -func (self *SCdnDomain) GetStatus() string { - return self.Status -} - -func (self *SCdnDomain) GetEnabled() bool { - return self.Disable == "normal" -} - -func (self *SCdnDomain) GetCname() string { - return self.Cname -} - -func (self *SCdnDomain) GetOrigins() *cloudprovider.SCdnOrigins { - ret := cloudprovider.SCdnOrigins{} - if self.Origin.OriginType == "cos" { - self.Origin.OriginType = api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET - } - for _, org := range self.Origin.Origins { - ret = append(ret, cloudprovider.SCdnOrigin{ - Type: self.Origin.OriginType, - ServerName: self.Origin.ServerName, - Protocol: self.Origin.OriginPullProtocol, - Origin: org, - }) - } - for _, org := range self.Origin.BackupOrigins { - ret = append(ret, cloudprovider.SCdnOrigin{ - Type: self.Origin.BackupOriginType, - ServerName: self.Origin.BackupServerName, - Origin: org, - }) - } - return &ret -} - -func (self *SCdnDomain) GetArea() string { - return self.Area -} - -func (self *SCdnDomain) GetServiceType() string { - return self.ServiceType -} - -func (self *SQcloudClient) GetCdnDomain(domain string) (*SCdnDomain, error) { - domains, _, err := self.DescribeCdnDomains([]string{domain}, nil, "", 0, 100) - if err != nil { - return nil, errors.Wrapf(err, "DescribeCdnDomains") - } - for i := range domains { - if domains[i].Domain == domain { - domains[i].client = self - return &domains[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, domain) -} - -func (self *SCdnDomain) Refresh() error { - domain, err := self.client.GetCdnDomain(self.Domain) - if err != nil { - return err - } - return jsonutils.Update(self, domain) -} - -func (self *SCdnDomain) Delete() error { - err := self.client.StopCdnDomain(self.Domain) - if err != nil { - return errors.Wrapf(err, "StopCdnDomain") - } - return self.client.DeleteCdnDomain(self.Domain) -} - -func (self *SCdnDomain) SetTags(tags map[string]string, replace bool) error { - region, err := self.client.getDefaultRegion() - if err != nil { - return errors.Wrapf(err, "getDefaultRegion") - } - return region.SetResourceTags("cdn", "domain", []string{self.Domain}, tags, replace) -} - -func (self *SQcloudClient) StopCdnDomain(domain string) error { - params := map[string]string{ - "Domain": domain, - } - _, err := self.cdnRequest("StopCdnDomain", params) - return errors.Wrapf(err, "StopCdnDomain") -} - -func (self *SQcloudClient) StartCdnDomain(domain string) error { - params := map[string]string{ - "Domain": domain, - } - _, err := self.cdnRequest("StartCdnDomain", params) - return errors.Wrapf(err, "StartCdnDomain") -} - -func (self *SQcloudClient) DeleteCdnDomain(domain string) error { - params := map[string]string{ - "Domain": domain, - } - _, err := self.cdnRequest("DeleteCdnDomain", params) - return errors.Wrapf(err, "DeleteCdnDomain") -} - -type SDomains struct { - RequestID string `json:"RequestId"` - Domains []SCdnDomain `json:"Domains"` - TotalNumber int `json:"TotalNumber"` -} - -func (self *SQcloudClient) GetICloudCDNDomains() ([]cloudprovider.ICloudCDNDomain, error) { - cdns, err := self.DescribeAllCdnDomains(nil, nil, "") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudCDNDomain{} - for i := range cdns { - cdns[i].client = self - ret = append(ret, &cdns[i]) - } - return ret, nil -} - -func (self *SQcloudClient) GetICloudCDNDomainByName(name string) (cloudprovider.ICloudCDNDomain, error) { - domains, _, err := self.DescribeCdnDomains([]string{name}, nil, "", 0, 1) - if err != nil { - return nil, errors.Wrapf(err, "DescribeCdnDomains") - } - for i := range domains { - if domains[i].Domain == name { - domains[i].client = self - return &domains[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) -} - -func (client *SQcloudClient) AddCdnDomain(domain string, originType string, origins []string, cosPrivateAccess string) error { - params := map[string]string{} - params["Domain"] = domain - params["ServiceType"] = "web" - for i := range origins { - params[fmt.Sprintf("Origin.Origins.%d", i)] = origins[i] - } - params["Origin.OriginType"] = originType - params["Origin.CosPrivateAccess"] = cosPrivateAccess - _, err := client.cdnRequest("AddCdnDomain", params) - if err != nil { - return errors.Wrapf(err, `AddCdnDomain %s`, params) - } - return nil -} - -func (client *SQcloudClient) DescribeCdnDomains(domains, origins []string, domainType string, offset int, limit int) ([]SCdnDomain, int, error) { - params := map[string]string{} - params["Offset"] = strconv.Itoa(offset) - params["Limit"] = strconv.Itoa(limit) - filterIndex := 0 - if len(domains) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filterIndex)] = "domain" - for i := range domains { - params[fmt.Sprintf("Filters.%d.Value.%d", filterIndex, i)] = domains[i] - } - filterIndex++ - } - if len(origins) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filterIndex)] = "origin" - for i := range origins { - params[fmt.Sprintf("Filters.%d.Value.%d", filterIndex, i)] = origins[i] - } - filterIndex++ - } - - if len(domainType) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filterIndex)] = "domainType" - params[fmt.Sprintf("Filters.%d.Value.0", filterIndex)] = domainType - filterIndex++ - } - - resp, err := client.cdnRequest("DescribeDomainsConfig", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeDomainsConfig %s", params) - } - cdnDomains := []SCdnDomain{} - err = resp.Unmarshal(&cdnDomains, "Domains") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - totalcount, _ := resp.Float("TotalNumber") - return cdnDomains, int(totalcount), nil -} - -func (client *SQcloudClient) DescribeAllCdnDomains(domains, origins []string, domainType string) ([]SCdnDomain, error) { - cdnDomains := make([]SCdnDomain, 0) - for { - part, total, err := client.DescribeCdnDomains(domains, origins, domainType, len(cdnDomains), 50) - if err != nil { - return nil, errors.Wrap(err, "DescribeCdnDomains") - } - cdnDomains = append(cdnDomains, part...) - if len(cdnDomains) >= total { - break - } - } - return cdnDomains, nil -} - -func (self *SQcloudClient) CreateCDNDomain(opts *cloudprovider.CdnCreateOptions) (*SCdnDomain, error) { - params := map[string]string{ - "Domain": opts.Domain, - "ServiceType": opts.ServiceType, - } - if len(opts.Area) > 0 { - params["Area"] = opts.Area - } - originTypes := map[string][]string{} - for _, origin := range opts.Origins { - _, ok := originTypes[origin.Type] - if !ok { - originTypes[origin.Type] = []string{} - } - originTypes[origin.Type] = append(originTypes[origin.Type], origin.Origin) - } - for _, origin := range opts.Origins { - params["Origin.OriginType"] = origin.Type - if origin.Type == api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET { - params["Origin.OriginType"] = "cos" - } - if len(origin.ServerName) > 0 { - params["Origin.ServerName"] = origin.ServerName - } else { - params["Origin.ServerName"] = origin.Origin - } - if len(origin.Protocol) > 0 { - params["Origin.OriginPullProtocol"] = origin.Protocol - } - origins, ok := originTypes[origin.Type] - if ok { - for i, origin := range origins { - params[fmt.Sprintf("Origin.Origins.%d", i)] = origin - } - } - } - _, err := self.cdnRequest("AddCdnDomain", params) - if err != nil { - return nil, errors.Wrapf(err, "AddCdnDomain") - } - return self.GetCdnDomain(opts.Domain) -} diff --git a/pkg/multicloud/qcloud/cloud_connect_network.go b/pkg/multicloud/qcloud/cloud_connect_network.go deleted file mode 100644 index e699781da4..0000000000 --- a/pkg/multicloud/qcloud/cloud_connect_network.go +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strconv" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SCcn struct { - multicloud.SResourceBase - multicloud.QcloudTags - region *SRegion - - CcnID string `json:"CcnId"` - CcnName string `json:"CcnName"` - CcnDescription string `json:"CcnDescription"` - InstanceCount int `json:"InstanceCount"` - CreateTime string `json:"CreateTime"` - State string `json:"State"` - AttachedInstances []SCcnInstance -} - -type SCcnInstance struct { - CcnID string `json:"CcnId"` - InstanceType string `json:"InstanceType"` - InstanceID string `json:"InstanceId"` - InstanceName string `json:"InstanceName"` - InstanceRegion string `json:"InstanceRegion"` - InstanceUin string `json:"InstanceUin"` - CidrBlock []string `json:"CidrBlock"` - State string `json:"State"` -} - -type SCcnAttachInstanceInput struct { - InstanceType string - InstanceId string - InstanceRegion string -} - -func (self *SRegion) DescribeCcns(ccnIds []string, offset int, limit int) ([]SCcn, int, error) { - params := map[string]string{} - params["Offset"] = strconv.Itoa(offset) - params["Limit"] = strconv.Itoa(limit) - if ccnIds != nil && len(ccnIds) > 0 { - for index, ccnId := range ccnIds { - params[fmt.Sprintf("CcnIds.%d", index)] = ccnId - } - } - resp, err := self.vpcRequest("DescribeCcns", params) - if err != nil { - return nil, 0, errors.Wrapf(err, `self.vpcRequest("DescribeCcns", %s)`, jsonutils.Marshal(params).String()) - } - ccns := []SCcn{} - err = resp.Unmarshal(&ccns, "CcnSet") - if err != nil { - return nil, 0, errors.Wrapf(err, `(%s).Unmarshal(&ccns,"CcnSet")`, jsonutils.Marshal(resp).String()) - } - total, _ := resp.Float("TotalCount") - return ccns, int(total), nil -} - -func (self *SRegion) GetAllCcns() ([]SCcn, error) { - ccns := []SCcn{} - for { - part, total, err := self.DescribeCcns(nil, len(ccns), 50) - if err != nil { - return nil, errors.Wrapf(err, "self.DescribeCcns(nil, %d, 50)", len(ccns)) - } - ccns = append(ccns, part...) - if len(ccns) >= total { - break - } - } - for i := range ccns { - ccns[i].region = self - } - return ccns, nil -} - -func (self *SRegion) GetCcnById(ccnId string) (*SCcn, error) { - ccns, _, err := self.DescribeCcns([]string{ccnId}, 0, 50) - if err != nil { - return nil, errors.Wrapf(err, "self.DescribeCcns(%s, 0, 50)", ccnId) - } - if len(ccns) < 1 { - return nil, errors.Wrap(cloudprovider.ErrNotFound, "DescribeCcns") - } - if len(ccns) > 1 { - return nil, errors.Wrap(cloudprovider.ErrDuplicateId, "DescribeCcns") - } - ccns[0].region = self - return &ccns[0], nil -} - -func (self *SRegion) DescribeCcnAttachedInstances(ccnId string, offset int, limit int) ([]SCcnInstance, int, error) { - params := map[string]string{} - params["Offset"] = strconv.Itoa(offset) - params["Limit"] = strconv.Itoa(limit) - params["Filters.0.Name"] = "ccn-id" - params["Filters.0.Values.0"] = ccnId - resp, err := self.vpcRequest("DescribeCcnAttachedInstances", params) - if err != nil { - return nil, 0, errors.Wrapf(err, `self.vpcRequest("DescribeCcnAttachedInstances", %s)`, jsonutils.Marshal(params).String()) - } - instances := []SCcnInstance{} - err = resp.Unmarshal(&instances, "InstanceSet") - if err != nil { - return nil, 0, errors.Wrapf(err, `(%s).Unmarshal(&instances, "InstanceSet")`, jsonutils.Marshal(resp).String()) - } - total, _ := resp.Float("TotalCount") - return instances, int(total), nil -} - -func (self *SRegion) GetAllCcnAttachedInstances(ccnId string) ([]SCcnInstance, error) { - ccnInstances := []SCcnInstance{} - for { - part, total, err := self.DescribeCcnAttachedInstances(ccnId, len(ccnInstances), 50) - if err != nil { - return nil, errors.Wrapf(err, "self.DescribeCcns(nil, %d, 50)", len(ccnInstances)) - } - ccnInstances = append(ccnInstances, part...) - if len(ccnInstances) >= total { - break - } - } - return ccnInstances, nil -} - -func (self *SRegion) CreateCcn(opts *cloudprovider.SInterVpcNetworkCreateOptions) (string, error) { - params := make(map[string]string) - params["CcnName"] = opts.Name - params["CcnDescription"] = opts.Desc - // 默认的后付费不能被支持 - params["InstanceChargeType"] = "PREPAID" - // 预付费仅支持地域间限速 - params["BandwidthLimitType"] = "INTER_REGION_LIMIT" - resp, err := self.vpcRequest("CreateCcn", params) - if err != nil { - return "", errors.Wrapf(err, `self.vpcRequest("CreateCcn", %s)`, jsonutils.Marshal(params).String()) - } - ccn := &SCcn{} - err = resp.Unmarshal(ccn, "Ccn") - if err != nil { - return "", errors.Wrapf(err, `(%s).Unmarshal(ccn, "Ccn")`, jsonutils.Marshal(resp).String()) - } - return ccn.CcnID, nil -} - -func (self *SRegion) AcceptAttachCcnInstances(ccnId string, instances []SCcnAttachInstanceInput) error { - params := make(map[string]string) - params["CcnId"] = ccnId - for i := range instances { - params[fmt.Sprintf("Instances.%d.InstanceType", i)] = instances[i].InstanceType - params[fmt.Sprintf("Instances.%d.InstanceId", i)] = instances[i].InstanceId - params[fmt.Sprintf("Instances.%d.InstanceRegion", i)] = instances[i].InstanceRegion - } - _, err := self.vpcRequest("AcceptAttachCcnInstances", params) - if err != nil { - return errors.Wrapf(err, `self.vpcRequest("AcceptAttachCcnInstances", %s)`, jsonutils.Marshal(params).String()) - } - return nil -} - -func (self *SRegion) DeleteCcn(ccnId string) error { - params := make(map[string]string) - params["CcnId"] = ccnId - _, err := self.vpcRequest("DeleteCcn", params) - if err != nil { - return errors.Wrapf(err, ` self.vpcRequest("DeleteCcn", %s)`, jsonutils.Marshal(params).String()) - } - return nil -} - -func (self *SRegion) AttachCcnInstances(ccnId string, ccnUin string, instances []SCcnAttachInstanceInput) error { - params := make(map[string]string) - params["CcnId"] = ccnId - if len(ccnUin) > 0 { - params["CcnUin"] = ccnUin - } - for i := range instances { - params[fmt.Sprintf("Instances.%d.InstanceType", i)] = instances[i].InstanceType - params[fmt.Sprintf("Instances.%d.InstanceId", i)] = instances[i].InstanceId - params[fmt.Sprintf("Instances.%d.InstanceRegion", i)] = instances[i].InstanceRegion - } - - _, err := self.vpcRequest("AttachCcnInstances", params) - if err != nil { - return errors.Wrapf(err, ` self.vpcRequest("AttachCcnInstances", %s)`, jsonutils.Marshal(params).String()) - } - return nil -} - -func (self *SRegion) DetachCcnInstances(ccnId string, instances []SCcnAttachInstanceInput) error { - params := make(map[string]string) - params["CcnId"] = ccnId - - for i := range instances { - params[fmt.Sprintf("Instances.%d.InstanceType", i)] = instances[i].InstanceType - params[fmt.Sprintf("Instances.%d.InstanceId", i)] = instances[i].InstanceId - params[fmt.Sprintf("Instances.%d.InstanceRegion", i)] = instances[i].InstanceRegion - } - - _, err := self.vpcRequest("DetachCcnInstances", params) - if err != nil { - return errors.Wrapf(err, ` self.vpcRequest("DetachCcnInstances", %s)`, jsonutils.Marshal(params).String()) - } - return nil -} - -func (self *SCcn) GetId() string { - return self.CcnID -} - -func (self *SCcn) GetName() string { - return self.CcnName -} - -func (self *SCcn) GetGlobalId() string { - return self.GetId() -} - -func (self *SCcn) GetStatus() string { - switch self.State { - case "AVAILABLE": - return api.INTER_VPC_NETWORK_STATUS_AVAILABLE - case "ISOLATED": - return api.INTER_VPC_NETWORK_STATUS_UNKNOWN - default: - return api.INTER_VPC_NETWORK_STATUS_UNKNOWN - } -} - -func (self *SCcn) Refresh() error { - ccn, err := self.region.GetCcnById(self.GetId()) - if err != nil { - return errors.Wrapf(err, "self.region.GetCcnById(%s)", self.GetId()) - } - return jsonutils.Update(self, ccn) -} - -func (self *SCcn) GetAuthorityOwnerId() string { - return self.region.client.ownerName -} - -func (self *SCcn) fetchAttachedInstances() error { - if self.AttachedInstances != nil { - return nil - } - - instances, err := self.region.GetAllCcnAttachedInstances(self.GetId()) - if err != nil { - return errors.Wrapf(err, "self.region.GetAllCcnAttachedInstances(%s)", self.GetId()) - } - self.AttachedInstances = instances - return nil -} - -func (self *SCcn) GetICloudVpcIds() ([]string, error) { - err := self.fetchAttachedInstances() - if err != nil { - return nil, errors.Wrap(err, "self.fetchAttachedInstances()") - } - result := []string{} - for i := range self.AttachedInstances { - if self.AttachedInstances[i].InstanceType == "VPC" { - result = append(result, self.AttachedInstances[i].InstanceID) - } - } - return result, nil -} - -func (self *SCcn) AttachVpc(opts *cloudprovider.SInterVpcNetworkAttachVpcOption) error { - if self.GetAuthorityOwnerId() == opts.VpcAuthorityOwnerId { - return nil - } - instance := SCcnAttachInstanceInput{ - InstanceType: "VPC", - InstanceId: opts.VpcId, - InstanceRegion: opts.VpcRegionId, - } - err := self.region.AcceptAttachCcnInstances(self.GetId(), []SCcnAttachInstanceInput{instance}) - if err != nil { - return errors.Wrapf(err, "self.region.AcceptAttachCcnInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) - } - return nil -} - -func (self *SCcn) DetachVpc(opts *cloudprovider.SInterVpcNetworkDetachVpcOption) error { - instance := SCcnAttachInstanceInput{ - InstanceType: "VPC", - InstanceId: opts.VpcId, - InstanceRegion: opts.VpcRegionId, - } - err := self.region.DetachCcnInstances(self.GetId(), []SCcnAttachInstanceInput{instance}) - if err != nil { - return errors.Wrapf(err, "self.client.DetachCcnInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) - } - return nil -} - -func (self *SCcn) Delete() error { - err := self.region.DeleteCcn(self.GetId()) - if err != nil { - return errors.Wrapf(err, "self.region.DeleteCcn(%s)", self.GetId()) - } - return nil -} - -func (self *SCcn) GetIRoutes() ([]cloudprovider.ICloudInterVpcNetworkRoute, error) { - routes, err := self.region.GetAllCcnRouteSets(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, " self.region.GetAllCcnRouteSets(self.GetId())") - } - result := []cloudprovider.ICloudInterVpcNetworkRoute{} - for i := range routes { - result = append(result, &routes[i]) - } - return result, nil -} - -func (self *SCcn) EnableRouteEntry(routeId string) error { - err := self.region.EnableCcnRoutes(self.GetId(), []string{routeId}) - if err != nil { - return errors.Wrap(err, "self.region.EnableCcnRoutes") - } - return nil -} - -func (self *SCcn) DisableRouteEntry(routeId string) error { - err := self.region.DisableCcnRoutes(self.GetId(), []string{routeId}) - if err != nil { - return errors.Wrap(err, "self.region.DisableCcnRoutes") - } - return nil -} - -func (client *SQcloudClient) GetICloudInterVpcNetworks() ([]cloudprovider.ICloudInterVpcNetwork, error) { - region, err := client.getDefaultRegion() - if err != nil { - return nil, errors.Wrap(err, "getDefaultRegion") - } - sccns, err := region.GetAllCcns() - if err != nil { - return nil, errors.Wrap(err, " region.GetAllCcns()") - } - result := []cloudprovider.ICloudInterVpcNetwork{} - for i := range sccns { - result = append(result, &sccns[i]) - } - return result, nil -} - -func (client *SQcloudClient) GetICloudInterVpcNetworkById(id string) (cloudprovider.ICloudInterVpcNetwork, error) { - region, err := client.getDefaultRegion() - if err != nil { - return nil, errors.Wrap(err, "getDefaultRegion") - } - ccn, err := region.GetCcnById(id) - if err != nil { - return nil, errors.Wrapf(err, "region.GetCcnById(%s)", id) - } - return ccn, nil -} - -func (client *SQcloudClient) CreateICloudInterVpcNetwork(opts *cloudprovider.SInterVpcNetworkCreateOptions) (cloudprovider.ICloudInterVpcNetwork, error) { - region, err := client.getDefaultRegion() - if err != nil { - return nil, errors.Wrap(err, "getDefaultRegion") - } - - ccnId, err := region.CreateCcn(opts) - if err != nil { - return nil, errors.Wrapf(err, "region.CreateCcn(%s)", jsonutils.Marshal(opts).String()) - } - iNetwork, err := client.GetICloudInterVpcNetworkById(ccnId) - if err != nil { - return nil, errors.Wrapf(err, "client.GetICloudInterVpcNetworkById(%s)", ccnId) - } - return iNetwork, nil -} diff --git a/pkg/multicloud/qcloud/dbinstance.go b/pkg/multicloud/qcloud/dbinstance.go deleted file mode 100644 index 296dd54cfc..0000000000 --- a/pkg/multicloud/qcloud/dbinstance.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "strings" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -func (self *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - ret := []cloudprovider.ICloudDBInstance{} - mysqls, err := self.GetIMySQLs() - if err != nil { - return nil, errors.Wrapf(err, "GetIMySQLs") - } - ret = append(ret, mysqls...) - tdsqls, err := self.GetITDSQLs() - if err != nil { - return nil, errors.Wrapf(err, "GetITDSQLs") - } - ret = append(ret, tdsqls...) - return ret, nil -} - -func (self *SRegion) GetIDBInstanceById(id string) (cloudprovider.ICloudDBInstance, error) { - if strings.HasPrefix(id, "cdb") { - return self.GetMySQLInstanceById(id) - } else if strings.HasPrefix(id, "tdsqlshard") { - return self.GetTDSQL(id) - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) CreateIDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { - if opts.Category == api.QCLOUD_DBINSTANCE_CATEGORY_TDSQL { - return nil, cloudprovider.ErrNotImplemented - } - switch opts.Engine { - case api.DBINSTANCE_TYPE_MYSQL: - rds, err := self.CreateMySQLDBInstance(opts) - if err != nil { - return nil, errors.Wrapf(err, "CreateMySQLDBInstance") - } - return rds, nil - } - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "For %s", opts.Engine) -} diff --git a/pkg/multicloud/qcloud/disk.go b/pkg/multicloud/qcloud/disk.go deleted file mode 100644 index 4efdac26d1..0000000000 --- a/pkg/multicloud/qcloud/disk.go +++ /dev/null @@ -1,415 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - "sort" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type Placement struct { - ProjectId int - Zone string -} - -type SDisk struct { - storage *SStorage - multicloud.SDisk - multicloud.QcloudTags - - Attached bool - AutoRenewFlagError bool - CreateTime time.Time - DeadlineError bool - DeadlineTime time.Time - DifferDaysOfDeadline int - DiskChargeType string - DiskId string - DiskName string - DiskSize int - DiskState string - DiskType string - DiskUsage string - Encrypt bool - InstanceId string - IsReturnable bool - Placement Placement - Portable bool - RenewFlag string - ReturnFailCode int - RollbackPercent int - Rollbacking bool - SnapshotAbility bool - DeleteWithInstance bool -} - -type SDiskSet []SDisk - -func (v SDiskSet) Len() int { - return len(v) -} - -func (v SDiskSet) Swap(i, j int) { - v[i], v[j] = v[j], v[i] -} - -func (v SDiskSet) Less(i, j int) bool { - if v[i].DiskUsage == "SYSTEM_DISK" || v[j].DiskUsage == "DATA_DISK" { - return true - } - return false -} - -func (self *SRegion) GetDisks(instanceId string, zoneId string, category string, diskIds []string, offset int, limit int) ([]SDisk, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - filter := 0 - - if len(zoneId) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "zone" - params[fmt.Sprintf("Filters.%d.Values.0", filter)] = zoneId - filter++ - } - - if len(instanceId) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "instance-id" - params[fmt.Sprintf("Filters.%d.Values.0", filter)] = instanceId - filter++ - } - - if len(category) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "disk-type" - params[fmt.Sprintf("Filters.%d.Values.0", filter)] = category - filter++ - } - if diskIds != nil && len(diskIds) > 0 { - for index, diskId := range diskIds { - params[fmt.Sprintf("DiskIds.%d", index)] = diskId - } - } - - body, err := self.cbsRequest("DescribeDisks", params) - if err != nil { - log.Errorf("GetDisks fail %s", err) - return nil, 0, err - } - - disks := make([]SDisk, 0) - err = body.Unmarshal(&disks, "DiskSet") - if err != nil { - log.Errorf("Unmarshal disk details fail %s", err) - return nil, 0, err - } - total, _ := body.Float("TotalCount") - sort.Sort(SDiskSet(disks)) - return disks, int(total), 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 *SDisk) GetId() string { - return self.DiskId -} - -func (self *SRegion) DeleteDisk(diskId string) error { - params := make(map[string]string) - params["Region"] = self.Region - params["DiskIds.0"] = diskId - - _, err := self.cbsRequest("TerminateDisks", params) - return err -} - -func (self *SDisk) Delete(ctx context.Context) error { - return self.storage.zone.region.DeleteDisk(self.DiskId) -} - -func (self *SRegion) ResizeDisk(ctx context.Context, diskId string, sizeGb int64) error { - params := make(map[string]string) - params["DiskId"] = diskId - params["DiskSize"] = fmt.Sprintf("%d", sizeGb) - startTime := time.Now() - for { - _, err := self.cbsRequest("ResizeDisk", params) - if err != nil { - if strings.Index(err.Error(), "Code=InvalidDisk.Busy") > 0 { - log.Infof("The disk is busy, try later ...") - time.Sleep(10 * time.Second) - if time.Now().Sub(startTime) > time.Minute*20 { - return cloudprovider.ErrTimeout - } - continue - } - } - return err - } -} - -func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { - return self.storage.zone.region.ResizeDisk(ctx, self.DiskId, sizeMb/1024) -} - -func (self *SDisk) GetName() string { - if len(self.DiskName) > 0 && self.DiskName != "未命名" { - return self.DiskName - } - return self.DiskId -} - -func (self *SDisk) GetGlobalId() string { - return self.DiskId -} - -func (self *SDisk) IsEmulated() bool { - return false -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.storage, nil -} - -func (self *SDisk) GetStatus() string { - switch self.DiskState { - case "ATTACHING", "DETACHING", "EXPANDING", "ROLLBACKING": - return api.DISK_ALLOCATING - default: - return api.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) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { - snapshotId, err := self.storage.zone.region.CreateSnapshot(self.DiskId, name, desc) - if err != nil { - log.Errorf("createSnapshot fail %s", err) - return nil, err - } - snapshots, total, err := self.storage.zone.region.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) - if err != nil { - return nil, err - } - if total == 1 { - snapshot := &snapshots[0] - err := cloudprovider.WaitStatus(snapshot, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second) - if err != nil { - return nil, err - } - return snapshot, nil - } - return nil, nil -} - -func (self *SDisk) GetDiskType() string { - switch self.DiskUsage { - case "SYSTEM_DISK": - return api.DISK_TYPE_SYS - case "DATA_DISK": - return api.DISK_TYPE_DATA - default: - return api.DISK_TYPE_DATA - } -} - -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) GetBillingType() string { - switch self.DiskChargeType { - case "PREPAID": - return billing_api.BILLING_TYPE_PREPAID - case "POSTPAID_BY_HOUR": - return billing_api.BILLING_TYPE_POSTPAID - default: - return billing_api.BILLING_TYPE_PREPAID - } -} - -func (self *SDisk) GetDiskFormat() string { - return "vhd" -} - -func (self *SDisk) GetDiskSizeMB() int { - return self.DiskSize * 1024 -} - -func (self *SDisk) GetIsAutoDelete() bool { - return self.DeleteWithInstance -} - -func (self *SDisk) GetCreatedAt() time.Time { - // 2019-12-25 09:00:43 #非UTC时间 - return self.CreateTime.Add(time.Hour * -8) -} - -func (self *SDisk) GetExpiredAt() time.Time { - if self.DeadlineTime.IsZero() { - return time.Time{} - } - return self.DeadlineTime.Add(time.Hour * -8) -} - -func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - snapshots, total, err := self.storage.zone.region.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) - if err != nil { - return nil, err - } - if total == 1 { - return &snapshots[0], nil - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots := make([]SSnapshot, 0) - for { - parts, total, err := self.storage.zone.region.GetSnapshots("", self.DiskId, "", []string{}, 0, 20) - if err != nil { - log.Errorf("GetDisks fail %s", err) - return nil, err - } - 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) GetExtSnapshotPolicyIds() ([]string, error) { - return self.storage.zone.region.GetSnapshotIdByDiskId(self.GetId()) -} - -func (self *SDisk) GetTemplateId() string { - //return self.ImageId - return "" -} - -func (self *SRegion) ResetDisk(diskId, snapshotId string) error { - params := make(map[string]string) - params["Region"] = self.Region - params["DiskId"] = diskId - params["SnapshotId"] = snapshotId - _, err := self.cbsRequest("ApplySnapshot", params) - if err != nil { - log.Errorf("ResetDisk %s to snapshot %s fail %s", diskId, snapshotId, err) - return err - } - return nil -} - -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", self.storage.zone.region.ResetDisk(self.DiskId, snapshotId) -} - -func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, desc string, projectId string) (string, error) { - params := make(map[string]string) - params["Region"] = self.Region - params["DiskType"] = category - params["DiskChargeType"] = "POSTPAID_BY_HOUR" - // [TencentCloudSDKError] Code=InvalidParameter, Message=DiskName: vdisk_stress-testvm-qcloud-1_1560117118026502729, length is 48, out of range [0,20] (e11d6c4007e4), RequestId=a8409994-0357-42e9-b028-e11d6c4007e4 - if len(name) > 20 { - name = name[:20] - } - params["DiskName"] = name - params["Placement.Zone"] = zoneId - if len(projectId) > 0 { - params["Placement.ProjectId"] = projectId - } - //params["Encrypted"] = "false" - params["DiskSize"] = fmt.Sprintf("%d", sizeGb) - params["ClientToken"] = utils.GenRequestId(20) - - body, err := self.cbsRequest("CreateDisks", params) - if err != nil { - return "", err - } - diskIDSet := []string{} - err = body.Unmarshal(&diskIDSet, "DiskIdSet") - if err != nil { - return "", err - } - if len(diskIDSet) < 1 { - return "", fmt.Errorf("Create Disk error") - } - return diskIDSet[0], nil -} - -func (disk *SDisk) GetAccessPath() string { - return "" -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - // TODO - return cloudprovider.ErrNotSupported -} - -func (self *SDisk) GetProjectId() string { - return strconv.Itoa(self.Placement.ProjectId) -} diff --git a/pkg/multicloud/qcloud/doc.go b/pkg/multicloud/qcloud/doc.go deleted file mode 100644 index d6ac5e19e7..0000000000 --- a/pkg/multicloud/qcloud/doc.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud // import "yunion.io/x/onecloud/pkg/multicloud/qcloud" - -/* -Network Pre Conditions - -若是不开放公网,则需要开放以下域名的443和80端口, 避免部分资源同步异常或创建资源失败 - -cvm.tencentcloudapi.com -cvm.ap-shanghai-fsi.tencentcloudapi.com -cvm.ap-shenzhen-fsi.tencentcloudapi.com - -vpc.tencentcloudapi.com -vpc.ap-shanghai-fsi.tencentcloudapi.com -vpc.ap-shenzhen-fsi.tencentcloudapi.com - -cloudaudit.tencentcloudapi.com -cloudaudit.ap-shanghai-fsi.tencentcloudapi.com -cloudaudit.ap-shenzhen-fsi.tencentcloudapi.com - -cbs.tencentcloudapi.com -cbs.ap-shanghai-fsi.tencentcloudapi.com -cbs.ap-shenzhen-fsi.tencentcloudapi.com - -account.api.qcloud.com - -clb.tencentcloudapi.com -clb.ap-shanghai-fsi.tencentcloudapi.com -clb.ap-shenzhen-fsi.tencentcloudapi.com - -cdb.tencentcloudapi.com -cdb.ap-shanghai-fsi.tencentcloudapi.com -cdb.ap-shenzhen-fsi.tencentcloudapi.com - -mariadb.tencentcloudapi.com -mariadb.ap-shanghai-fsi.tencentcloudapi.com -mariadb.ap-shenzhen-fsi.tencentcloudapi.com - -postgres.tencentcloudapi.com -postgres.ap-shanghai-fsi.tencentcloudapi.com -postgres.ap-shenzhen-fsi.tencentcloudapi.com - -sqlserver.tencentcloudapi.com -sqlserver.ap-shanghai-fsi.tencentcloudapi.com -sqlserver.ap-shenzhen-fsi.tencentcloudapi.com - -lb.api.qcloud.com -wss.api.qcloud.com -cns.api.qcloud.com -vpc.api.qcloud.com -billing.tencentcloudapi.com -cam.tencentcloudapi.com -monitor.tencentcloudapi.com - -cos.ap-beijing.myqcloud.com -service.cos.myqcloud.com -cos.ap-bangkok.myqcloud.com. -bj.file.myqcloud.com. -tj.file.myqcloud.com. -cd.file.myqcloud.com. -cq.file.myqcloud.com. -gz.file.myqcloud.com. -hk.file.myqcloud.com. -cos.ap-mumbai.myqcloud.com. -cos.ap-nanjing.myqcloud.com. -cos.ap-seoul.myqcloud.com. -sh.file.myqcloud.com. -cos.ap-shanghai-fsi.myqcloud.com. -cos.ap-shenzhen-fsi.myqcloud.com. -sgp.file.myqcloud.com. -cos.ap-tokyo.myqcloud.com. -ger.file.myqcloud.com. -cos.eu-moscow.myqcloud.com. -cos.na-ashburn.myqcloud.com. -cos.na-siliconvalley.myqcloud.com. -ca.file.myqcloud.com. -3jytr9q1.dayugslb.com. -60icvusw.dayugslb.com. -5ekm872f.dayugslb.com. -r5mfqoyl.dayugslb.com. - -Permission Pre Conditions -若仅需要同步资源, 则需要赋予账号以下权限 -QCloudFinanceFullAccess -QcloudCVMReadOnlyAccess -QcloudCamReadOnlyAccess -QcloudCOSReadOnlyAccess -QcloudAuditReadOnlyAccess -QcloudMonitorReadOnlyAccess - -若需要资源读写,需要赋予账号以下权限 -QCloudFinanceFullAccess -QcloudCVMFullAccess -QcloudCamFullAccess -QcloudCBSFullAccess -QcloudEIPFullAccess -QcloudCOSFullAccess -QcloudAuditFullAccess -QcloudMonitorFullAccess -*/ diff --git a/pkg/multicloud/qcloud/eip.go b/pkg/multicloud/qcloud/eip.go deleted file mode 100644 index 5a863abbe0..0000000000 --- a/pkg/multicloud/qcloud/eip.go +++ /dev/null @@ -1,424 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - EIP_STATUS_CREATING = "CREATING" - EIP_STATUS_BINDING = "BINDING" - EIP_STATUS_BIND = "BIND" - EIP_STATUS_UNBINDING = "UNBINDING" - EIP_STATUS_UNBIND = "UNBIND" - EIP_STATUS_OFFLINING = "OFFLINING" - EIP_STATUS_BIND_ENI = "BIND_ENI" - EIP_STATUS_CREATE_FAILED = "CREATE_FAILED" - - EIP_TYPE_CALCIP = "CalcIP" //表示设备ip - EIP_TYPE_WANIP = "WanIP" //普通公网ip - EIP_TYPE_EIP = "EIP" //弹性公网ip - EIP_TYPE_ANYCASTEIP = "AnycastEIP" //加速EIP -) - -type SEipAddress struct { - region *SRegion - multicloud.SEipBase - multicloud.QcloudTags - - AddressId string // EIP的ID,是EIP的唯一标识。 - AddressName string // EIP名称。 - AddressStatus string // EIP状态。 - AddressIp string // 外网IP地址 - InstanceId string // 绑定的资源实例ID。可能是一个CVM,NAT。 - CreatedTime time.Time // 创建时间。按照ISO8601标准表示,并且使用UTC时间。格式为:YYYY-MM-DDThh:mm:ssZ。 - NetworkInterfaceId string // 绑定的弹性网卡ID - PrivateAddressIp string // 绑定的资源内网ip - IsArrears bool // 资源隔离状态。true表示eip处于隔离状态,false表示资源处于未隔离装填 - IsBlocked bool // 资源封堵状态。true表示eip处于封堵状态,false表示eip处于未封堵状态 - IsEipDirectConnection bool // eip是否支持直通模式。true表示eip支持直通模式,false表示资源不支持直通模式 - AddressType string // eip资源类型,包括"CalcIP","WanIP","EIP","AnycastEIP"。其中"CalcIP"表示设备ip,“WanIP”表示普通公网ip,“EIP”表示弹性公网ip,“AnycastEip”表示加速EIP - CascadeRelease bool // eip是否在解绑后自动释放。true表示eip将会在解绑后自动释放,false表示eip在解绑后不会自动释放 - Bandwidth int - InternetChargeType string -} - -func (self *SEipAddress) GetId() string { - return self.AddressId -} - -func (self *SEipAddress) GetName() string { - if len(self.AddressName) > 0 && self.AddressName != "未命名" { - return self.AddressName - } - return self.AddressId -} - -func (self *SEipAddress) GetGlobalId() string { - return self.AddressId -} - -func (self *SEipAddress) GetStatus() string { - switch self.AddressStatus { - case EIP_STATUS_CREATING: - return api.EIP_STATUS_ALLOCATE - case EIP_STATUS_BINDING: - return api.EIP_STATUS_ASSOCIATE - case EIP_STATUS_UNBINDING: - return api.EIP_STATUS_DISSOCIATE - case EIP_STATUS_UNBIND, EIP_STATUS_BIND, EIP_STATUS_OFFLINING, EIP_STATUS_BIND_ENI: - return api.EIP_STATUS_READY - case EIP_STATUS_CREATE_FAILED: - return api.EIP_STATUS_ALLOCATE_FAIL - default: - return api.EIP_STATUS_UNKNOWN - } -} - -func (self *SEipAddress) Refresh() error { - if self.IsEmulated() { - return nil - } - new, err := self.region.GetEip(self.AddressId) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SEipAddress) IsEmulated() bool { - if self.AddressId == self.InstanceId { - // fixed Public IP - return true - } else { - return false - } -} - -func (self *SEipAddress) GetIpAddr() string { - return self.AddressIp -} - -func (self *SEipAddress) GetMode() string { - if self.InstanceId == self.AddressId { - return api.EIP_MODE_INSTANCE_PUBLICIP - } - return api.EIP_MODE_STANDALONE_EIP -} - -func (self *SEipAddress) GetAssociationType() string { - if len(self.InstanceId) > 0 { - for prefix, instanceType := range map[string]string{ - "nat-": api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY, - "ins-": api.EIP_ASSOCIATE_TYPE_SERVER, - "lb-": api.EIP_ASSOCIATE_TYPE_LOADBALANCER, - "lbl-": api.EIP_ASSOCIATE_TYPE_LOADBALANCER, - } { - if strings.HasPrefix(self.InstanceId, prefix) { - return instanceType - } - } - if info := strings.Split(self.InstanceId, "-"); len(info) > 0 { - return info[0] - } - return self.InstanceId - } - return "" -} - -func (self *SEipAddress) GetAssociationExternalId() string { - return self.InstanceId -} - -func (self *SEipAddress) Delete() error { - return self.region.DeallocateEIP(self.AddressId) -} - -func (self *SEipAddress) GetBandwidth() int { - if self.Bandwidth > 0 { - return self.Bandwidth - } - if len(self.InstanceId) > 0 { - if strings.HasPrefix(self.InstanceId, "ins-") { - if instance, err := self.region.GetInstance(self.InstanceId); err == nil { - return instance.InternetAccessible.InternetMaxBandwidthOut - } - } - } - return 0 -} - -func (self *SEipAddress) GetINetworkId() string { - return "" -} - -func (self *SEipAddress) GetBillingType() string { - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SEipAddress) GetCreatedAt() time.Time { - return self.CreatedTime -} - -func (self *SEipAddress) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SEipAddress) GetInternetChargeType() string { - switch self.InternetChargeType { - case "TRAFFIC_POSTPAID_BY_HOUR": - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - case "BANDWIDTH_PACKAGE", "BANDWIDTH_POSTPAID_BY_HOUR", "BANDWIDTH_PREPAID_BY_MONTH": - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH - } - if len(self.InstanceId) > 0 { - if strings.HasPrefix(self.InstanceId, "ins-") { - if instance, err := self.region.GetInstance(self.InstanceId); err == nil { - switch instance.InternetAccessible.InternetChargeType { - case InternetChargeTypeTrafficPostpaidByHour: - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - default: - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH - } - } - } - } - return "" -} - -func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { - err := self.region.AssociateEip(self.AddressId, conf.InstanceId) - if err != nil { - return err - } - if conf.Bandwidth > 0 && self.Bandwidth == 0 { - err = self.region.UpdateInstanceBandwidth(conf.InstanceId, conf.Bandwidth, conf.ChargeType) - if err != nil { - log.Warningf("failed to change instance %s bandwidth -> %d error: %v", conf.InstanceId, conf.Bandwidth, err) - } - } - return cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 5*time.Second, 10*time.Second, 180*time.Second) -} - -func (self *SEipAddress) Dissociate() error { - err := self.region.DissociateEip(self.AddressId) - if err != nil { - return err - } - return cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 5*time.Second, 10*time.Second, 180*time.Second) -} - -func (self *SEipAddress) ChangeBandwidth(bw int) error { - if len(self.InstanceId) > 0 && self.Bandwidth == 0 && self.GetAssociationType() == api.EIP_ASSOCIATE_TYPE_SERVER { - return self.region.UpdateInstanceBandwidth(self.InstanceId, bw, "") - } - if len(self.InternetChargeType) > 0 { - return self.region.ChangeEipBindWidth(self.AddressId, bw, self.InternetChargeType) - } - return nil -} - -func (region *SRegion) GetEips(eipId string, instanceId string, offset int, limit int) ([]SEipAddress, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - - params := make(map[string]string) - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - - if len(eipId) > 0 { - params["AddressIds.0"] = eipId - } - - if len(instanceId) > 0 { - params["Filters.0.Name"] = "instance-id" - params["Filters.0.Values.0"] = instanceId - } - - body, err := region.vpcRequest("DescribeAddresses", params) - if err != nil { - log.Errorf("DescribeEipAddresses fail %s", err) - return nil, 0, err - } - - eips := make([]SEipAddress, 0) - err = body.Unmarshal(&eips, "AddressSet") - if err != nil { - log.Errorf("Unmarshal EipAddress details fail %s", err) - return nil, 0, err - } - total, _ := body.Float("TotalCount") - for i := 0; i < len(eips); i++ { - eips[i].region = region - } - return eips, int(total), nil -} - -func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { - eips, total, err := region.GetEips(eipId, "", 0, 1) - if err != nil { - return nil, err - } - if total != 1 { - return nil, cloudprovider.ErrNotFound - } - return &eips[0], nil -} - -func (region *SRegion) AllocateEIP(name string, bwMbps int, chargeType string) (*SEipAddress, error) { - params := make(map[string]string) - params["AddressName"] = name - if len(name) > 20 { - params["AddressName"] = name[:20] - } - if bwMbps > 0 { - params["InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bwMbps) - } - - _, totalCount, err := region.GetBandwidthPackages([]string{}, 0, 50) - if err != nil { - return nil, errors.Wrapf(err, "GetBandwidthPackages") - } - if totalCount == 0 { - switch chargeType { - case api.EIP_CHARGE_TYPE_BY_TRAFFIC: - params["InternetChargeType"] = "TRAFFIC_POSTPAID_BY_HOUR" - case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: - params["InternetChargeType"] = "BANDWIDTH_POSTPAID_BY_HOUR" - } - } - - addRessSet := []string{} - body, err := region.vpcRequest("AllocateAddresses", params) - if err != nil { - return nil, errors.Wrapf(err, "AllocateAddresses") - } - err = body.Unmarshal(&addRessSet, "AddressSet") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return region.GetEip(addRessSet[0]) -} - -// https://cloud.tencent.com/document/api/215/16699 -// 腾讯云eip不支持指定项目 -func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - return region.AllocateEIP(eip.Name, eip.BandwidthMbps, eip.ChargeType) -} - -func (region *SRegion) DeallocateEIP(eipId string) error { - params := make(map[string]string) - params["Region"] = region.Region - params["AddressIds.0"] = eipId - - _, err := region.vpcRequest("ReleaseAddresses", params) - return errors.Wrapf(err, "ReleaseAddresses") -} - -func (region *SRegion) AssociateEip(eipId string, instanceId string) error { - params := make(map[string]string) - params["AddressId"] = eipId - params["InstanceId"] = instanceId - - _, err := region.vpcRequest("AssociateAddress", params) - return errors.Wrapf(err, "AssociateAddress") -} - -func (region *SRegion) DissociateEip(eipId string) error { - params := make(map[string]string) - params["Region"] = region.Region - params["AddressId"] = eipId - - _, err := region.vpcRequest("DisassociateAddress", params) - return errors.Wrapf(err, "DisassociateAddress") -} - -func (self *SRegion) UpdateInstanceBandwidth(instanceId string, bw int, chargeType string) error { - params := make(map[string]string) - params["Region"] = self.Region - params["InternetAccessible.InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bw) - - _, totalCount, err := self.GetBandwidthPackages([]string{}, 0, 50) - if err != nil { - return errors.Wrapf(err, "GetBandwidthPackages") - } - if totalCount > 0 { - params["InstanceIds.0"] = instanceId - _, err = self.cvmRequest("ResetInstancesInternetMaxBandwidth", params, true) - return errors.Wrapf(err, "ResetInstancesInternetMaxBandwidth") - } - internetChargeType := "TRAFFIC_POSTPAID_BY_HOUR" - if chargeType == api.EIP_CHARGE_TYPE_BY_BANDWIDTH { - internetChargeType = "BANDWIDTH_POSTPAID_BY_HOUR" - } - params["InternetAccessible.InternetChargeType"] = internetChargeType - action := "ResetInstancesInternetMaxBandwidth" - - instance, err := self.GetInstance(instanceId) - if err != nil { - return errors.Wrapf(err, "GetInstance(%s)", instanceId) - } - if instance.InternetAccessible.InternetChargeType != internetChargeType { //避免 Code=InvalidParameterValue, Message=参数`InternetChargeType`中`TRAFFIC_POSTPAID_BY_HOUR`没有更改, RequestId=6be2f9bc-a967-41db-9f0d-aff789c703ca - params["InstanceId"] = instanceId - action = "ModifyInstanceInternetChargeType" - } else { - params["InstanceIds.0"] = instanceId - } - err = cloudprovider.Wait(time.Second*5, time.Minute*3, func() (bool, error) { - instance, err := self.GetInstance(instanceId) - if err != nil { - return false, errors.Wrapf(err, "GetInstance(%s)", instanceId) - } - _bw := instance.InternetAccessible.InternetMaxBandwidthOut - log.Infof("%s bandwidth from %d -> %d expect %d", action, _bw, bw, bw) - if _bw == bw { - return true, nil - } - if _, err := self.cvmRequest(action, params, true); err != nil { - log.Errorf("%s %v", action, err) - return false, nil - } - return false, nil - }) - return errors.Wrapf(err, "cloudprovider.Wait bandwidth changed") -} - -func (self *SRegion) ChangeEipBindWidth(eipId string, bw int, chargeType string) error { - params := map[string]string{ - "Region": self.Region, - "InternetMaxBandwidthOut": fmt.Sprintf("%d", bw), - "InternetChargeType": chargeType, - "AddressId": eipId, - } - _, err := self.vpcRequest("ModifyAddressInternetChargeType", params) - return errors.Wrapf(err, "ModifyAddressInternetChargeType") -} - -func (self *SEipAddress) GetProjectId() string { - return "" -} diff --git a/pkg/multicloud/qcloud/elastic_search.go b/pkg/multicloud/qcloud/elastic_search.go deleted file mode 100644 index 0db7dc09cb..0000000000 --- a/pkg/multicloud/qcloud/elastic_search.go +++ /dev/null @@ -1,351 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElasticSearch struct { - multicloud.SVirtualResourceBase - multicloud.SBillingBase - multicloud.QcloudTags - region *SRegion - - InstanceId string - InstanceName string - Region string - Zone string - AppId int - Uin string - VpcUid string - SubnetUid string - Status int - ChargeType string - ChargePeriod int - RenewFlag string - NodeType string - NodeNum int - CpuNum int - MemSize int - DiskType string - DiskSize int - EsDomain string - EsVip string - EsPort int - KibanaUrl string - EsVersion string - EsConfig string - EsAcl struct { - BlackIpList []string - WhiteIpList []string - } - CreateTime time.Time - UpdateTime time.Time - Deadline string - InstanceType int - IkConfig struct { - MainDict []struct { - Key string - Name string - Size int - } - Stopwords []struct { - Key string - Name string - Size int - } - QQDict []struct { - Key string - Name string - Size int - } - Synonym []struct { - Key string - Name string - Size int - } - UpdateType string - } - MasterNodeInfo struct { - EnableDedicatedMaster bool - MasterNodeType string - MasterNodeNum int - MasterNodeCpuNum int - MasterNodeMemSize int - MasterNodeDiskSize int - MasterNodeDiskType string - } - CosBackup struct { - IsAutoBackup bool - BackupTime string - } - AllowCosBackup bool - LicenseType string - EnableHotWarmMode bool - WarmNodeType string - WarmNodeNum int - WarmCpuNum int - WarmMemSize int - WarmDiskType string - WarmDiskSize int - NodeInfoList []struct { - NodeNum int - NodeType string - Type string - DiskType string - DiskSize int - LocalDiskInfo struct { - LocalDiskType string - LocalDiskSize int - LocalDiskCount int - } - DiskCount int - DiskEncrypt int - } - EsPublicUrl string - MultiZoneInfo []struct { - Zone string - SubnetId string - } - DeployMode int - PublicAccess string - EsPublicAcl struct { - BlackIpList []string - WhiteIpList []string - } - KibanaPrivateUrl string - KibanaPublicAccess string - KibanaPrivateAccess string - SecurityType int - SceneType int - KibanaConfig string - KibanaNodeInfo struct { - KibanaNodeType string - KibanaNodeNum int - KibanaNodeCpuNum int - KibanaNodeMemSize int - KibanaNodeDiskType string - KibanaNodeDiskSize int - } -} - -func (self *SElasticSearch) GetId() string { - return self.InstanceId -} - -func (self *SElasticSearch) GetGlobalId() string { - return self.InstanceId -} - -func (self *SElasticSearch) GetName() string { - if len(self.InstanceName) > 0 { - return self.InstanceName - } - return self.InstanceId -} - -func (self *SElasticSearch) GetVersion() string { - return self.EsVersion -} - -func (self *SElasticSearch) Refresh() error { - es, err := self.region.GetElasticSearch(self.InstanceId) - if err != nil { - return err - } - return jsonutils.Update(self, es) -} - -func (self *SElasticSearch) GetDiskSizeGb() int { - return self.DiskSize -} - -func (self *SElasticSearch) GetStorageType() string { - return self.DiskType -} - -func (self *SElasticSearch) GetCategory() string { - return self.LicenseType -} - -func (self *SElasticSearch) GetCreatedAt() time.Time { - return self.CreateTime -} - -func (self *SElasticSearch) GetVpcId() string { - return self.VpcUid -} - -func (self *SElasticSearch) GetNetworkId() string { - for _, zone := range self.MultiZoneInfo { - if len(zone.SubnetId) > 0 { - return zone.SubnetId - } - } - return self.SubnetUid -} - -func (self *SElasticSearch) GetInstanceType() string { - return self.NodeType -} - -func (self *SElasticSearch) GetVcpuCount() int { - return self.CpuNum -} - -func (self *SElasticSearch) GetVmemSizeGb() int { - return self.MemSize -} - -func (self *SElasticSearch) GetZoneId() string { - for _, zone := range self.MultiZoneInfo { - if len(zone.Zone) > 0 { - return zone.Zone - } - } - return self.Zone -} - -func (self *SElasticSearch) IsMultiAz() bool { - return len(self.MultiZoneInfo) > 1 -} - -func (self *SElasticSearch) GetBillingType() string { - switch self.ChargeType { - case "PREPAID", "CDHPAID": - return billing_api.BILLING_TYPE_PREPAID - case "POSTPAID_BY_HOUR": - return billing_api.BILLING_TYPE_POSTPAID - } - return billing_api.BILLING_TYPE_POSTPAID -} - -func (self *SElasticSearch) GetStatus() string { - switch self.Status { - case 0: - return api.ELASITC_SEARCH_STATUS_CREATING - case 1: - return api.ELASTIC_SEARCH_STATUS_AVAILABLE - case -1: - return api.ELASTIC_SEARCH_STATUS_UNAVAILABLE - case -2, -3: - return api.ELASTIC_SEARCH_STATUS_DELETING - } - return fmt.Sprintf("%d", self.Status) -} - -func (self *SElasticSearch) IsAutoRenew() bool { - return self.RenewFlag == "NOTIFY_AND_AUTO_RENEW" -} - -func (self *SElasticSearch) Delete() error { - return self.region.DeleteElasticSearch(self.InstanceId) -} - -func (self *SElasticSearch) GetAccessInfo() (*cloudprovider.ElasticSearchAccessInfo, error) { - return &cloudprovider.ElasticSearchAccessInfo{ - Port: self.EsPort, - Vip: self.EsVip, - Domain: self.EsPublicUrl, - PrivateDomain: self.EsDomain, - KibanaUrl: self.KibanaUrl, - KibanaPrivateUrl: self.KibanaPrivateUrl, - }, nil -} - -func (self *SRegion) GetIElasticSearchs() ([]cloudprovider.ICloudElasticSearch, error) { - ess := []SElasticSearch{} - for { - part, total, err := self.GetElasticSearchs(nil, 100, len(ess)) - if err != nil { - return nil, errors.Wrapf(err, "GetElasticSearchs") - } - ess = append(ess, part...) - if len(ess) >= total { - break - } - } - ret := []cloudprovider.ICloudElasticSearch{} - for i := range ess { - ess[i].region = self - ret = append(ret, &ess[i]) - } - return ret, nil -} - -func (self *SRegion) GetIElasticSearchById(id string) (cloudprovider.ICloudElasticSearch, error) { - es, err := self.GetElasticSearch(id) - if err != nil { - return nil, errors.Wrapf(err, "GetElasitcSearch") - } - return es, nil -} - -func (self *SRegion) GetElasticSearch(id string) (*SElasticSearch, error) { - if len(id) == 0 { - return nil, cloudprovider.ErrNotFound - } - ret, _, err := self.GetElasticSearchs([]string{id}, 1, 0) - if err != nil { - return nil, errors.Wrapf(err, "GetElasticSearchs") - } - for i := range ret { - ret[i].region = self - return &ret[i], nil - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SRegion) GetElasticSearchs(ids []string, limit, offset int) ([]SElasticSearch, int, error) { - if limit < 1 || limit > 100 { - limit = 100 - } - params := map[string]string{ - "Limit": fmt.Sprintf("%d", limit), - "Offset": fmt.Sprintf("%d", offset), - } - for i, id := range ids { - params[fmt.Sprintf("InstanceIds.%d", i)] = id - } - resp, err := self.esRequest("DescribeInstances", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeInstances") - } - ret := []SElasticSearch{} - err = resp.Unmarshal(&ret, "InstanceList") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - totalCount, _ := resp.Float("TotalCount") - return ret, int(totalCount), nil -} - -func (self *SRegion) DeleteElasticSearch(id string) error { - params := map[string]string{ - "InstanceId": id, - } - _, err := self.esRequest("DeleteInstance", params) - return errors.Wrapf(err, "DeleteDBInstance") -} diff --git a/pkg/multicloud/qcloud/elasticcache_account.go b/pkg/multicloud/qcloud/elasticcache_account.go deleted file mode 100644 index e9331ca2e7..0000000000 --- a/pkg/multicloud/qcloud/elasticcache_account.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElasticcacheAccount struct { - multicloud.SElasticcacheAccountBase - multicloud.QcloudTags - - cacheDB *SElasticcache - - InstanceID string `json:"InstanceId"` - AccountName string `json:"AccountName"` - Remark string `json:"Remark"` - Privilege string `json:"Privilege"` - ReadonlyPolicy []string `json:"ReadonlyPolicy"` - Status int `json:"Status"` - IsEmulate bool `json:"is_emulate"` -} - -func (self *SElasticcacheAccount) GetId() string { - return fmt.Sprintf("%s/%s", self.InstanceID, self.AccountName) -} - -func (self *SElasticcacheAccount) GetName() string { - return self.AccountName -} - -func (self *SElasticcacheAccount) IsEmulated() bool { - return self.IsEmulate -} - -func (self *SElasticcacheAccount) GetGlobalId() string { - return self.GetId() -} - -func (self *SElasticcacheAccount) GetStatus() string { - switch self.Status { - case 1: - return api.ELASTIC_CACHE_ACCOUNT_STATUS_CREATING - case 2: - return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE - case 4: - return api.ELASTIC_CACHE_ACCOUNT_STATUS_DELETED - default: - return api.ELASTIC_CACHE_ACCOUNT_STATUS_UNAVAILABLE - } -} - -func (self *SElasticcacheAccount) GetAccountType() string { - if strings.ToLower(self.AccountName) == "root" { - return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN - } else { - return api.ELASTIC_CACHE_ACCOUNT_TYPE_NORMAL - } -} - -func (self *SElasticcacheAccount) GetAccountPrivilege() string { - switch self.Privilege { - case "r": - return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_READ - case "w": - return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE - case "rw": - return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE - default: - return self.Privilege - } -} - -func (self *SElasticcacheAccount) Refresh() error { - account, err := self.cacheDB.GetICloudElasticcacheAccount(self.GetGlobalId()) - if err != nil { - return errors.Wrap(err, "GetICloudElasticcacheAccount") - } - - err = jsonutils.Update(self, account) - if err != nil { - return errors.Wrap(err, "Update") - } - - return nil -} - -// https://cloud.tencent.com/document/product/239/38925 -func (self *SElasticcacheAccount) Delete() error { - params := map[string]string{} - params["InstanceId"] = self.cacheDB.GetId() - params["AccountName"] = self.AccountName - _, err := self.cacheDB.region.redisRequest("DeleteInstanceAccount", params) - if err != nil { - return errors.Wrap(err, "DeleteInstanceAccount") - } - - return nil -} - -// https://cloud.tencent.com/document/product/239/20014 -func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { - params := map[string]string{} - params["InstanceId"] = self.cacheDB.GetId() - if input.NoPasswordAccess != nil && *input.NoPasswordAccess { - params["NoAuth"] = "true" - } else { - if len(input.NewPassword) > 0 { - params["Password"] = input.NewPassword - } else { - return nil - } - } - - _, err := self.cacheDB.region.redisRequest("ResetPassword", params) - if err != nil { - return errors.Wrap(err, "ResetPassword") - } - - return nil -} - -// https://cloud.tencent.com/document/product/239/38923 -func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { - params := map[string]string{} - params["InstanceId"] = self.cacheDB.GetId() - params["AccountName"] = self.AccountName - if input.NoPasswordAccess != nil && *input.NoPasswordAccess { - params["NoAuth"] = "true" - } else { - if input.Password != nil && len(*input.Password) > 0 { - params["AccountPassword"] = *input.Password - } - } - - if input.Description != nil && len(*input.Description) > 0 { - params["Remark"] = *input.Description - } - - if input.AccountPrivilege != nil && len(*input.AccountPrivilege) > 0 { - params["Privilege"] = *input.AccountPrivilege - params["ReadonlyPolicy.0"] = "master" - } - - _, err := self.cacheDB.region.redisRequest("ModifyInstanceAccount", params) - if err != nil { - return errors.Wrap(err, "ModifyInstanceAccount") - } - - return nil -} diff --git a/pkg/multicloud/qcloud/elasticcache_backup.go b/pkg/multicloud/qcloud/elasticcache_backup.go deleted file mode 100644 index 0a6dc71a55..0000000000 --- a/pkg/multicloud/qcloud/elasticcache_backup.go +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "strconv" - "strings" - "time" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SElasticcacheBackup struct { - multicloud.SElasticcacheBackupBase - multicloud.QcloudTags - - cacheDB *SElasticcache - - StartTime time.Time `json:"StartTime"` - BackupID string `json:"BackupId"` - BackupType string `json:"BackupType"` - Status int `json:"Status"` - Remark string `json:"Remark"` - Locked int64 `json:"Locked"` -} - -func (self *SElasticcacheBackup) GetId() string { - return self.BackupID -} - -func (self *SElasticcacheBackup) GetName() string { - if len(self.Remark) > 0 { - segs := strings.Split(self.Remark, "@") - return segs[0] - } - - return self.GetId() -} - -func (self *SElasticcacheBackup) GetGlobalId() string { - return self.GetId() -} - -/* - ELASTIC_CACHE_BACKUP_STATUS_CREATING = "creating" // 备份中 - ELASTIC_CACHE_BACKUP_STATUS_CREATE_EXPIRED = "expired" //(备份文件已过期) - ELASTIC_CACHE_BACKUP_STATUS_CREATE_DELETED = "deleted" //(备份文件已删除) - ELASTIC_CACHE_BACKUP_STATUS_DELETING = "deleting" // 删除中 - ELASTIC_CACHE_BACKUP_STATUS_SUCCESS = "success" // 备份成功 - ELASTIC_CACHE_BACKUP_STATUS_FAILED = "failed" // 备份失败 -*/ -func (self *SElasticcacheBackup) GetStatus() string { - switch self.Status { - case 1: - return api.ELASTIC_CACHE_BACKUP_STATUS_CREATING - case 2: - return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS - case -1: - return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_EXPIRED - case -2: - return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_DELETED - case 3: - return api.ELASTIC_CACHE_BACKUP_STATUS_CREATING - case 4: - return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS - default: - return strconv.Itoa(self.Status) - } -} - -func (self *SElasticcacheBackup) Refresh() error { - backup, err := self.cacheDB.GetICloudElasticcacheBackup(self.GetGlobalId()) - if err != nil { - return errors.Wrap(err, "GetICloudElasticcacheBackup") - } - - err = jsonutils.Update(self, backup) - if err != nil { - return errors.Wrap(err, "Update") - } - - return nil -} - -func (self *SElasticcacheBackup) GetBackupSizeMb() int { - return 0 -} - -func (self *SElasticcacheBackup) GetBackupType() string { - return api.ELASTIC_CACHE_BACKUP_TYPE_INCREMENTAL -} - -func (self *SElasticcacheBackup) GetBackupMode() string { - switch self.BackupType { - case "1", "systemBackupInstance": - return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED - case "0", "manualBackupInstance": - return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL - default: - return self.BackupType - } -} - -// https://cloud.tencent.com/document/api/239/34443 -func (self *SElasticcacheBackup) GetDownloadURL() string { - url, err := self.GetBackupDownloadURL() - if err != nil { - log.Debugf("GetBackupDownloadURL %s", err) - return "" - } - - return url -} - -func (self *SElasticcacheBackup) GetStartTime() time.Time { - return self.StartTime -} - -func (self *SElasticcacheBackup) GetEndTime() time.Time { - return time.Time{} -} - -func (self *SElasticcacheBackup) Delete() error { - return errors.Wrap(cloudprovider.ErrNotSupported, "Delete") -} - -// https://cloud.tencent.com/document/product/239/34435 -// todo: password -func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { - params := map[string]string{} - params["InstanceId"] = instanceId - params["BackupId"] = self.GetId() - //if len(Password) > 0 { - // params["Password"] = Password - //} - - _, err := self.cacheDB.region.redisRequest("RestoreInstance", params) - if err != nil { - return errors.Wrap(err, "RestoreInstance") - } - - return nil -} - -func (self *SElasticcacheBackup) GetBackupDownloadURL() (string, error) { - params := map[string]string{} - params["InstanceId"] = self.cacheDB.GetId() - params["BackupId"] = self.GetId() - client := self.cacheDB.region.client - resp, err := client.redisRequest("DescribeBackupUrl", params) - if err != nil { - return "", errors.Wrap(err, "DescribeBackupUrl") - } - - urls := []string{} - err = resp.Unmarshal(&urls, "DownloadUrl") - if err != nil { - return "", errors.Wrap(err, "Unmarshal.DownloadUrl") - } - - if len(urls) > 0 { - return urls[0], nil - } - - return "", nil -} diff --git a/pkg/multicloud/qcloud/elasticcache_instance.go b/pkg/multicloud/qcloud/elasticcache_instance.go deleted file mode 100644 index 3c4fb49116..0000000000 --- a/pkg/multicloud/qcloud/elasticcache_instance.go +++ /dev/null @@ -1,1229 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strconv" - "strings" - "time" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SElasticcache struct { - multicloud.SElasticcacheBase - multicloud.QcloudTags - region *SRegion - - ClientLimit int - ClientLimitMax int - ClientLimitMin int - MaintenanceTime *MaintenanceTime `json:"maintenance_time"` - NoAuth *bool `json:"no_auth"` - NodeSet []NodeSet `json:"NodeSet"` - Appid int64 `json:"Appid"` - AutoRenewFlag int64 `json:"AutoRenewFlag"` - BillingMode int64 `json:"BillingMode"` - CloseTime string `json:"CloseTime"` - Createtime time.Time `json:"Createtime"` - DeadlineTime string `json:"DeadlineTime"` - Engine string `json:"Engine"` - InstanceID string `json:"InstanceId"` - InstanceName string `json:"InstanceName"` - InstanceNode []interface{} `json:"InstanceNode"` - InstanceTitle string `json:"InstanceTitle"` - OfflineTime string `json:"OfflineTime"` - Port int `json:"Port"` - PriceID int64 `json:"PriceId"` - ProductType string `json:"ProductType"` - ProjectID int `json:"ProjectId"` - RedisReplicasNum int `json:"RedisReplicasNum"` - RedisShardNum int64 `json:"RedisShardNum"` - RedisShardSize int64 `json:"RedisShardSize"` // MB - DiskSize int64 `json:"disk_size"` - RegionID int64 `json:"RegionId"` - Size int `json:"Size"` - SizeUsed int64 `json:"SizeUsed"` - SlaveReadWeight int64 `json:"SlaveReadWeight"` - Status int `json:"Status"` - SubStatus int64 `json:"SubStatus"` - SubnetID int64 `json:"SubnetId"` - Type int `json:"Type"` - UniqSubnetID string `json:"UniqSubnetId"` - UniqVpcID string `json:"UniqVpcId"` - VpcID int64 `json:"VpcId"` - WANIP string `json:"WanIp"` - ZoneID int `json:"ZoneId"` -} - -func (self *SElasticcache) SetTags(tags map[string]string, replace bool) error { - return self.region.SetResourceTags("redis", "instance", []string{self.InstanceID}, tags, replace) -} - -type MaintenanceTime struct { - StartTime string `json:"start_time"` - EndTime string `json:"end_time"` -} - -type NodeSet struct { - NodeID int64 `json:"NodeId"` - NodeType int64 `json:"NodeType"` - ZoneID int64 `json:"ZoneId"` -} - -var zoneMaps = map[int]string{ - 100001: "ap-guangzhou-1", - 100002: "ap-guangzhou-2", - 100003: "ap-guangzhou-3", - 100004: "ap-guangzhou-4", - 100006: "ap-guangzhou-6", - 110001: "ap-shenzhen-fsi-1", - 110002: "ap-shenzhen-fsi-2", - 110003: "ap-shenzhen-fsi-3", - 200001: "ap-shanghai-1", - 200002: "ap-shanghai-2", - 200003: "ap-shanghai-3", - 200004: "ap-shanghai-4", - 200005: "ap-shanghai-5", - 200006: "ap-shanghai-6", - 200007: "ap-shanghai-7", - 700001: "ap-shanghai-fsi-1", - 700002: "ap-shanghai-fsi-2", - 700003: "ap-shanghai-fsi-3", - 330001: "ap-nanjing-1", - 330002: "ap-nanjing-2", - 330003: "ap-nanjing-3", - 800001: "ap-beijing-1", - 800002: "ap-beijing-2", - 800003: "ap-beijing-3", - 800004: "ap-beijing-4", - 800005: "ap-beijing-5", - 800006: "ap-beijing-6", - 800007: "ap-beijing-7", - 460001: "ap-beijing-fsi-1", - 360001: "ap-tianjin-1", - 360002: "ap-tianjin-2", - 160001: "ap-chengdu-1", - 160002: "ap-chengdu-2", - 190001: "ap-chongqing-1", - 300001: "ap-hongkong-1", - 300002: "ap-hongkong-2", - 300003: "ap-hongkong-3", - 390001: "ap-taipei-1", - 900001: "ap-singapore-1", - 230001: "ap-bangkok-1", - 210001: "ap-mumbai-1", - 210002: "ap-mumbai-2", - 180001: "ap-seoul-1", - 180002: "ap-seoul-2", - 250001: "ap-tokyo-1", - 150001: "na-siliconvalley-1", - 150002: "na-siliconvalley-2", - 220001: "na-ashburn-1", - 220002: "na-ashburn-2", - 400001: "na-toronto-1", - 170001: "eu-frankfurt-1", - 240001: "eu-moscow-1", -} - -var zoneIdMaps = map[string]int{ - "ap-guangzhou-1": 100001, - "ap-guangzhou-2": 100002, - "ap-guangzhou-3": 100003, - "ap-guangzhou-4": 100004, - "ap-guangzhou-6": 100006, - "ap-shenzhen-fsi-1": 110001, - "ap-shenzhen-fsi-2": 110002, - "ap-shenzhen-fsi-3": 110003, - "ap-shanghai-1": 200001, - "ap-shanghai-2": 200002, - "ap-shanghai-3": 200003, - "ap-shanghai-4": 200004, - "ap-shanghai-5": 200005, - "ap-shanghai-6": 200006, - "ap-shanghai-7": 200007, - "ap-shanghai-fsi-1": 700001, - "ap-shanghai-fsi-2": 700002, - "ap-shanghai-fsi-3": 700003, - "ap-nanjing-1": 330001, - "ap-nanjing-2": 330002, - "ap-nanjing-3": 330003, - "ap-beijing-1": 800001, - "ap-beijing-2": 800002, - "ap-beijing-3": 800003, - "ap-beijing-4": 800004, - "ap-beijing-5": 800005, - "ap-beijing-6": 800006, - "ap-beijing-7": 800007, - "ap-beijing-fsi-1": 460001, - "ap-tianjin-1": 360001, - "ap-tianjin-2": 360002, - "ap-chengdu-1": 160001, - "ap-chengdu-2": 160002, - "ap-chongqing-1": 190001, - "ap-hongkong-1": 300001, - "ap-hongkong-2": 300002, - "ap-hongkong-3": 300003, - "ap-taipei-1": 390001, - "ap-singapore-1": 900001, - "ap-bangkok-1": 230001, - "ap-mumbai-1": 210001, - "ap-mumbai-2": 210002, - "ap-seoul-1": 180001, - "ap-seoul-2": 180002, - "ap-tokyo-1": 250001, - "na-siliconvalley-1": 150001, - "na-siliconvalley-2": 150002, - "na-ashburn-1": 220001, - "na-ashburn-2": 220002, - "na-toronto-1": 400001, - "eu-frankfurt-1": 170001, - "eu-moscow-1": 240001, -} - -func (self *SElasticcache) GetId() string { - return self.InstanceID -} - -func (self *SElasticcache) GetName() string { - return self.InstanceName -} - -func (self *SElasticcache) GetGlobalId() string { - return self.GetId() -} - -// https://cloud.tencent.com/document/api/239/20022#InstanceSet -// 实例当前状态,0:待初始化;1:实例在流程中;2:实例运行中;-2:实例已隔离;-3:实例待删除 -func (self *SElasticcache) GetStatus() string { - switch self.Status { - case 2: - return api.ELASTIC_CACHE_STATUS_RUNNING - case 0: - return api.ELASTIC_CACHE_STATUS_DEPLOYING - case -3: - return api.ELASTIC_CACHE_STATUS_RELEASING - case -2: - return api.ELASTIC_CACHE_STATUS_UNAVAILABLE - case 1: - return api.ELASTIC_CACHE_STATUS_CHANGING - } - - return "" -} - -func (self *SElasticcache) GetConnections() int { - return self.ClientLimit -} - -func (self *SElasticcache) Refresh() error { - cache, err := self.region.GetIElasticcacheById(self.GetId()) - if err != nil { - return errors.Wrap(err, "Elasticcache.Refresh.GetElasticCache") - } - - err = jsonutils.Update(self, cache) - if err != nil { - return errors.Wrap(err, "Elasticcache.Refresh.Update") - } - - return nil -} - -func (self *SElasticcache) IsEmulated() bool { - return false -} - -func (self *SElasticcache) GetProjectId() string { - return strconv.Itoa(self.ProjectID) -} - -func (self *SElasticcache) GetBillingType() string { - // 计费模式:0-按量计费,1-包年包月 - if self.BillingMode == 1 { - return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SElasticcache) GetCreatedAt() time.Time { - return self.Createtime -} - -func (self *SElasticcache) GetExpiredAt() time.Time { - if self.DeadlineTime == "0000-00-00 00:00:00" || len(self.DeadlineTime) == 0 { - return time.Time{} - } - - t, err := time.Parse("2006-01-02 15:04:05", self.DeadlineTime) - if err != nil { - log.Debugf("GetExpiredAt.Parse %s", err) - return time.Time{} - } - - return t -} - -// https://cloud.tencent.com/document/product/239/31785 -func (self *SElasticcache) SetAutoRenew(bc billing.SBillingCycle) error { - params := map[string]string{} - params["Operation"] = "modifyAutoRenew" - params["InstanceIds.0"] = self.GetId() - if bc.AutoRenew { - params["AutoRenews.0"] = "1" - } else { - params["AutoRenews.0"] = "0" - } - - _, err := self.region.redisRequest("ModifyInstance", params) - if err != nil { - return errors.Wrap(err, "ModifyInstance") - } - - return nil -} - -func (self *SElasticcache) IsAutoRenew() bool { - // 实例是否设置自动续费标识,1:设置自动续费;0:未设置自动续费 - return self.AutoRenewFlag == 1 -} - -// redis:master:s1:r5:m1g:v4.0 -// 实例类型:2 – Redis2.8内存版(标准架构),3 – CKV 3.2内存版(标准架构),4 – CKV 3.2内存版(集群架构) -// ,6 – Redis4.0内存版(标准架构),7 – Redis4.0内存版(集群架构), -// 8 – Redis5.0内存版(标准架构),9 – Redis5.0内存版(集群架构) -func (self *SElasticcache) GetInstanceType() string { - segs := make([]string, 6) - segs[0] = "redis" - switch self.Type { - case 2, 3, 6, 8: - segs[1] = "master" - case 4, 7, 9, 10: - segs[1] = "cluster" - case 5: - segs[1] = "single" - default: - segs[1] = strconv.Itoa(self.Type) - } - - segs[2] = fmt.Sprintf("s%d", self.RedisShardNum) - segs[3] = fmt.Sprintf("r%d", self.RedisReplicasNum) - if self.DiskSize > 0 { - segs[4] = fmt.Sprintf("m%dg-d%dg", self.Size/1024, self.DiskSize) - } else { - segs[4] = fmt.Sprintf("m%dg", self.Size/1024) - } - segs[5] = fmt.Sprintf("v%s", self.GetEngineVersion()) - - return strings.Join(segs, ":") -} - -func (self *SElasticcache) GetCapacityMB() int { - return self.Size -} - -func (self *SElasticcache) GetArchType() string { - // 产品类型:standalone – 标准版,cluster – 集群版 - switch self.ProductType { - case "standalone": - return api.ELASTIC_CACHE_ARCH_TYPE_MASTER - case "cluster": - return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER - } - - return "" -} - -func (self *SElasticcache) GetNodeType() string { - // single(单副本) | double(双副本) - switch self.RedisReplicasNum { - case 1: - return "single" - case 2: - return "double" - case 3: - return "three" - case 4: - return "four" - case 5: - return "five" - case 6: - return "six" - } - - return strconv.Itoa(self.RedisReplicasNum) -} - -func (self *SElasticcache) GetEngine() string { - return api.ELASTIC_CACHE_ENGINE_REDIS -} - -func (self *SElasticcache) GetEngineVersion() string { - switch self.Type { - case 1, 2, 5: - return "2.8" - case 3, 4: - return "3.2" - case 6, 7, 10: - return "4.0" - case 8, 9: - return "5.0" - } - - return "unknown" -} - -func (self *SElasticcache) GetVpcId() string { - return self.UniqVpcID -} - -// https://cloud.tencent.com/document/product/239/4106 -func (self *SElasticcache) GetZoneId() string { - zone := zoneMaps[self.ZoneID] - if len(zone) == 0 { - net, err := self.region.GetNetwork(self.UniqSubnetID) - if err != nil { - log.Warningf("zone %d not found. zone map needed update.", self.ZoneID) - log.Debugf("GetNetwork %s %s", self.UniqSubnetID, err) - return "" - } - - zone = net.Zone - } - - z, err := self.region.getZoneById(zone) - if err != nil { - log.Debugf("getZoneById %s", err) - return "" - } - - return z.GetGlobalId() -} - -func (self *SElasticcache) GetNetworkType() string { - if len(self.UniqVpcID) > 0 { - return api.LB_NETWORK_TYPE_VPC - } else { - return api.LB_NETWORK_TYPE_CLASSIC - } -} - -func (self *SElasticcache) GetNetworkId() string { - return self.UniqSubnetID -} - -func (self *SElasticcache) GetPrivateDNS() string { - return self.WANIP -} - -func (self *SElasticcache) GetPrivateIpAddr() string { - return self.WANIP -} - -func (self *SElasticcache) GetPrivateConnectPort() int { - return self.Port -} - -func (self *SElasticcache) GetPublicDNS() string { - return "" -} - -func (self *SElasticcache) GetPublicIpAddr() string { - return "" -} - -func (self *SElasticcache) GetPublicConnectPort() int { - return self.Port -} - -// https://cloud.tencent.com/document/api/239/46336 -func (self *SElasticcache) getMaintenanceTime() error { - params := map[string]string{} - params["InstanceId"] = self.GetId() - params["Region"] = self.region.GetId() - resp, err := self.region.client.redisRequest("DescribeMaintenanceWindow", params) - if err != nil { - return errors.Wrap(err, "DescribeMaintenanceWindow") - } - - self.MaintenanceTime = &MaintenanceTime{} - err = resp.Unmarshal(self.MaintenanceTime) - if err != nil { - return errors.Wrap(err, "err.MaintenanceTime") - } - - return nil -} - -func (self *SElasticcache) GetMaintainStartTime() string { - if self.MaintenanceTime == nil { - if err := self.getMaintenanceTime(); err != nil { - log.Debugf("getMaintenanceTime %s", err) - return "" - } - } - - return self.MaintenanceTime.StartTime -} - -func (self *SElasticcache) GetMaintainEndTime() string { - if self.MaintenanceTime == nil { - if err := self.getMaintenanceTime(); err != nil { - log.Debugf("getMaintenanceTime %s", err) - return "" - } - } - - return self.MaintenanceTime.EndTime -} - -func (self *SElasticcache) GetAuthMode() string { - if self.NoAuth != nil && *self.NoAuth == false { - return "on" - } - - return "off" -} - -func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { - ss, err := self.region.GetCloudElasticcacheSecurityGroups(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "GetCloudElasticcacheSecurityGroups") - } - - ret := make([]string, len(ss)) - for i := range ss { - ret[i] = ss[i].SecurityGroupID - } - - return ret, nil -} - -func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { - accounts, err := self.getCloudElasticcacheAccounts() - if err != nil { - return nil, errors.Wrap(err, "GetCloudElasticcacheAccounts") - } - - iaccounts := make([]cloudprovider.ICloudElasticcacheAccount, len(accounts)) - for i := range accounts { - account := accounts[i] - account.cacheDB = self - iaccounts[i] = &account - } - - return iaccounts, nil -} - -func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { - backups, err := self.region.GetCloudElasticcacheBackups(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "GetCloudElasticcacheBackups") - } - - ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) - for i := range backups { - backup := backups[i] - backup.cacheDB = self - ibackups[i] = &backup - } - - return ibackups, nil -} - -func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { - parameters, err := self.region.GetCloudElasticcacheParameters(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "GetCloudElasticcacheParameters") - } - - ret := []cloudprovider.ICloudElasticcacheParameter{} - for i := range parameters { - parameter := parameters[i] - parameter.cacheDB = self - ret = append(ret, ¶meter) - } - - return ret, nil -} - -func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { - accounts, err := self.getCloudElasticcacheAccounts() - if err != nil { - return nil, errors.Wrap(err, "GetCloudElasticcacheAccounts") - } - - for i := range accounts { - account := accounts[i] - if account.GetGlobalId() == accountId { - account.cacheDB = self - return &account, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { - backups, err := self.region.GetCloudElasticcacheBackups(self.InstanceID) - if err != nil { - return nil, errors.Wrap(err, "GetCloudElasticcacheBackups") - } - - for i := range backups { - backup := backups[i] - if backup.GetGlobalId() == backupId { - backup.cacheDB = self - return &backup, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SElasticcache) GetICloudElasticcacheBackupByReadmark(readmark string) (cloudprovider.ICloudElasticcacheBackup, error) { - backups, err := self.region.GetCloudElasticcacheBackups(self.InstanceID) - if err != nil { - return nil, errors.Wrap(err, "GetCloudElasticcacheBackups") - } - - for i := range backups { - backup := backups[i] - if backup.Remark == readmark { - backup.cacheDB = self - return &backup, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SElasticcache) Restart() error { - return errors.Wrap(cloudprovider.ErrNotSupported, "Restart") -} - -// https://cloud.tencent.com/document/product/239/34440 -func (self *SElasticcache) Delete() error { - requiredStatus := "" - if self.GetBillingType() == billing_api.BILLING_TYPE_POSTPAID { - if err := self.DestroyPostpaidInstance(); err != nil { - return errors.Wrap(err, "DestroyPostpaidInstance") - } - - requiredStatus = api.ELASTIC_CACHE_STATUS_RELEASING - } else { - if err := self.DestroyPrepaidInstance(); err != nil { - return errors.Wrap(err, "DestroyPrepaidInstance") - } - - requiredStatus = api.ELASTIC_CACHE_STATUS_UNAVAILABLE - } - - err := cloudprovider.WaitStatus(self, requiredStatus, 5*time.Second, 300*time.Second) - if err != nil { - return errors.Wrap(err, fmt.Sprintf("WaitStatus.%s", requiredStatus)) - } - - err = self.CleanupInstance() - if err != nil { - return errors.Wrap(err, "CleanupInstance") - } - - return nil -} - -// https://cloud.tencent.com/document/product/239/34439 -func (self *SElasticcache) DestroyPrepaidInstance() error { - if self.GetStatus() == api.ELASTIC_CACHE_STATUS_UNAVAILABLE { - return nil - } - - params := map[string]string{} - params["InstanceId"] = self.GetId() - _, err := self.region.redisRequest("DestroyPrepaidInstance", params) - if err != nil { - return errors.Wrap(err, "DestroyPrepaidInstance") - } - - return nil -} - -// https://cloud.tencent.com/document/product/239/34439 -func (self *SElasticcache) DestroyPostpaidInstance() error { - if self.GetStatus() == api.ELASTIC_CACHE_STATUS_RELEASING { - return nil - } - - params := map[string]string{} - params["InstanceId"] = self.GetId() - _, err := self.region.redisRequest("DestroyPostpaidInstance", params) - if err != nil { - return errors.Wrap(err, "DestroyPostpaidInstance") - } - - return nil -} - -// https://cloud.tencent.com/document/product/239/34442 -func (self *SElasticcache) CleanupInstance() error { - params := map[string]string{} - params["InstanceId"] = self.GetId() - _, err := self.region.redisRequest("CleanUpInstance", params) - if err != nil { - return errors.Wrap(err, "CleanUpInstance") - } - - return nil -} - -// https://cloud.tencent.com/document/product/239/20013 -func (self *SElasticcache) ChangeInstanceSpec(spec string) error { - s, err := parseLocalInstanceSpec(spec) - if err != nil { - return errors.Wrap(err, "parseLocalInstanceSpec") - } - - params := map[string]string{} - params["InstanceId"] = self.GetId() - params["MemSize"] = fmt.Sprintf("%d", s.MemSizeMB) - params["RedisShardNum"] = s.RedisShardNum - params["RedisReplicasNum"] = s.RedisReplicasNum - _, err = self.region.redisRequest("UpgradeInstance", params) - if err != nil { - return errors.Wrap(err, "UpgradeInstance") - } - - return nil -} - -// https://cloud.tencent.com/document/product/239/46335 -func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { - params := map[string]string{} - params["InstanceId"] = self.GetId() - params["StartTime"] = maintainStartTime - params["EndTime"] = maintainEndTime - _, err := self.region.redisRequest("ModifyMaintenanceWindow", params) - if err != nil { - return errors.Wrap(err, "ModifyMaintenanceWindow") - } - - return nil -} - -func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { - return "", errors.Wrap(cloudprovider.ErrNotSupported, "AllocatePublicConnection") -} - -func (self *SElasticcache) ReleasePublicConnection() error { - return errors.Wrap(cloudprovider.ErrNotSupported, "ReleasePublicConnection") -} - -// https://cloud.tencent.com/document/product/239/38926 -func (self *SElasticcache) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { - params := map[string]string{} - params["InstanceId"] = self.GetId() - params["AccountName"] = account.AccountName - params["AccountPassword"] = account.AccountPassword - params["Privilege"] = account.AccountPrivilege - params["ReadonlyPolicy.0"] = "master" - if len(account.Description) > 0 { - params["Remark"] = account.Description - } - - _, err := self.region.redisRequest("CreateInstanceAccount", params) - if err != nil { - return nil, errors.Wrap(err, "CreateInstanceAccount") - } - - accountId := "" - cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { - accounts, err := self.GetICloudElasticcacheAccounts() - if err != nil { - log.Debugf("GetICloudElasticcacheAccounts %s", err) - return false, nil - } - - for i := range accounts { - if accounts[i].GetName() == account.AccountName { - accountId = accounts[i].GetGlobalId() - return true, nil - } - } - - return false, nil - }) - - return self.GetICloudElasticcacheAccount(accountId) -} - -func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { - return nil, errors.Wrap(cloudprovider.ErrNotSupported, "CreateAcl") -} - -// https://cloud.tencent.com/document/product/239/20010 -func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { - readmark := strings.Join([]string{desc, fmt.Sprintf("%d", time.Now().Unix())}, "@") - params := map[string]string{} - params["InstanceId"] = self.GetId() - params["Remark"] = readmark - resp, err := self.region.redisRequest("ManualBackupInstance", params) - if err != nil { - return nil, errors.Wrap(err, "ManualBackupInstance") - } - - taskId := 0 - err = resp.Unmarshal(&taskId, "TaskId") - if err != nil { - return nil, errors.Wrap(err, "Unmarshal") - } - - var task *SElasticcacheTask - err = cloudprovider.Wait(5*time.Second, 900*time.Second, func() (bool, error) { - task, err = self.region.DescribeTaskInfo(fmt.Sprintf("%d", taskId)) - if err != nil { - return false, nil - } - - if task != nil { - if task.Status == "failed" || task.Status == "error" { - return false, fmt.Errorf("CreateBackup failed %#v", task) - } - - if task.Status == "succeed" { - return true, nil - } - } - - return false, nil - }) - if err != nil { - return nil, errors.Wrap(err, "Wait.DescribeTaskInfo") - } - - if task == nil { - return nil, fmt.Errorf("CreateBackup failed task is empty") - } - - return self.GetICloudElasticcacheBackupByReadmark(readmark) -} - -// https://cloud.tencent.com/document/product/239/20021 -func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { - params := map[string]string{} - params["InstanceId"] = self.GetId() - if self.NoAuth != nil && *self.NoAuth == false { - if len(input.Password) > 0 { - params["Password"] = input.Password - } else { - return fmt.Errorf("password required on auth mode while flush elastich cache instance") - } - } - _, err := self.region.redisRequest("ClearInstance", params) - if err != nil { - return errors.Wrap(err, "ClearInstance") - } - - return nil -} - -// https://cloud.tencent.com/document/product/239/38923 -// https://cloud.tencent.com/document/product/239/20014 -// true表示将主账号切换为免密账号,这里只适用于主账号,子账号不可免密 -func (self *SElasticcache) UpdateAuthMode(noPasswordAccess bool, password string) error { - params := map[string]string{} - params["InstanceId"] = self.GetId() - if noPasswordAccess { - params["NoAuth"] = "true" - } else { - params["NoAuth"] = "false" - params["Password"] = password - } - - _, err := self.region.redisRequest("ResetPassword", params) - if err != nil { - return errors.Wrap(err, "ResetPassword") - } - - return nil -} - -// https://cloud.tencent.com/document/product/239/34445 -// todo: finish me -func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { - params := map[string]string{} - params["InstanceId"] = self.GetId() - params["InstanceParams.0"] = config.String() - _, err := self.region.redisRequest("ModifyInstanceParams", params) - if err != nil { - return errors.Wrap(err, "ModifyInstanceParams") - } - - return nil -} - -func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { - panic("implement me") -} - -func (self *SElasticcache) getCloudElasticcacheAccounts() ([]SElasticcacheAccount, error) { - if self.GetEngineVersion() == "2.8" || (self.NodeSet != nil && len(self.NodeSet) > 0) { - account := SElasticcacheAccount{} - account.cacheDB = self - account.AccountName = "root" - account.InstanceID = self.GetId() - account.Privilege = "rw" - account.Status = 2 - account.IsEmulate = true - - return []SElasticcacheAccount{account}, nil - } - - accounts, err := self.region.GetCloudElasticcacheAccounts(self.GetId()) - if err != nil { - return nil, errors.Wrap(err, "GetCloudElasticcacheAccounts") - } - - for i := range accounts { - accounts[i].cacheDB = self - } - - return accounts, nil -} - -// https://cloud.tencent.com/document/api/239/38924 -func (self *SElasticcache) getCloudElasticcacheAccount(accountName string) (*SElasticcacheAccount, error) { - accounts, err := self.getCloudElasticcacheAccounts() - if err != nil { - return nil, errors.Wrap(err, "GetCloudElasticcacheAccounts") - } - - for i := range accounts { - if accounts[i].AccountName == accountName { - accounts[i].cacheDB = self - return &accounts[i], nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -// https://cloud.tencent.com/document/api/239/41256 -func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { - params := map[string]string{} - params["InstanceId"] = self.GetId() - params["Product"] = "redis" - for i := range secgroupIds { - params[fmt.Sprintf("SecurityGroupIds.%d", i)] = secgroupIds[i] - } - - _, err := self.region.redisRequest("ModifyDBInstanceSecurityGroups", params) - if err != nil { - return errors.Wrap(err, "ModifyDBInstanceSecurityGroups") - } - - return nil -} - -func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { - month := bc.GetMonths() - if month <= 0 { - return errors.Wrap(fmt.Errorf("month should great than 0"), "GetMonths") - } - - params := map[string]string{} - params["InstanceId"] = self.GetId() - params["Period"] = fmt.Sprintf("%d", month) - _, err := self.region.redisRequest("RenewInstance", params) - if err != nil { - return errors.Wrap(err, "RenewInstance") - } - - return nil -} - -// https://cloud.tencent.com/document/api/239/38924 -func (self *SRegion) GetCloudElasticcacheAccounts(instanceId string) ([]SElasticcacheAccount, error) { - params := map[string]string{} - params["Region"] = self.GetId() - params["InstanceId"] = instanceId - params["Limit"] = "20" - params["Offset"] = "0" - - ret := []SElasticcacheAccount{} - offset := 0 - for { - resp, err := self.client.redisRequest("DescribeInstanceAccount", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeInstanceAccount") - } - - _ret := []SElasticcacheAccount{} - err = resp.Unmarshal(&_ret, "Accounts") - if err != nil { - return nil, errors.Wrap(err, "Unmarshal") - } else { - ret = append(ret, _ret...) - } - - if len(_ret) < 20 { - break - } else { - offset += 20 - params["Offset"] = strconv.Itoa(offset) - } - } - - return ret, nil -} - -// https://cloud.tencent.com/document/api/239/20011 -func (self *SRegion) GetCloudElasticcacheBackups(instanceId string) ([]SElasticcacheBackup, error) { - params := map[string]string{} - params["Region"] = self.GetId() - params["InstanceId"] = instanceId - params["Limit"] = "20" - params["Offset"] = "0" - - ret := []SElasticcacheBackup{} - offset := 0 - for { - resp, err := self.client.redisRequest("DescribeInstanceBackups", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeInstanceBackups") - } - - _ret := []SElasticcacheBackup{} - err = resp.Unmarshal(&_ret, "BackupSet") - if err != nil { - return nil, errors.Wrap(err, "Unmarshal") - } else { - ret = append(ret, _ret...) - } - - if len(_ret) < 20 { - break - } else { - offset += 20 - params["Offset"] = strconv.Itoa(offset) - } - } - - return ret, nil -} - -// https://cloud.tencent.com/document/api/239/41259 -func (self *SRegion) GetCloudElasticcacheSecurityGroups(instanceId string) ([]SElasticcacheSecgroup, error) { - params := map[string]string{} - params["Region"] = self.GetId() - params["InstanceId"] = instanceId - params["Product"] = "redis" - resp, err := self.client.redisRequest("DescribeDBSecurityGroups", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeDBSecurityGroups") - } - - ret := []SElasticcacheSecgroup{} - err = resp.Unmarshal(&ret, "Groups") - if err != nil { - return nil, errors.Wrap(err, "Unmarshal") - } - - return ret, nil -} - -// https://cloud.tencent.com/document/api/239/34448 -func (self *SRegion) GetCloudElasticcacheParameters(instanceId string) ([]SElasticcacheParameter, error) { - params := map[string]string{} - params["Region"] = self.GetId() - params["InstanceId"] = instanceId - resp, err := self.client.redisRequest("DescribeInstanceParams", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeInstanceParams") - } - - ret1 := []SElasticcacheParameter{} - err = resp.Unmarshal(&ret1, "InstanceEnumParam") - if err != nil { - return nil, errors.Wrap(err, "InstanceEnumParam") - } - - ret2 := []SElasticcacheParameter{} - err = resp.Unmarshal(&ret2, "InstanceIntegerParam") - if err != nil { - return nil, errors.Wrap(err, "InstanceIntegerParam") - } - - ret3 := []SElasticcacheParameter{} - err = resp.Unmarshal(&ret3, "InstanceMultiParam") - if err != nil { - return nil, errors.Wrap(err, "InstanceMultiParam") - } - - ret4 := []SElasticcacheParameter{} - err = resp.Unmarshal(&ret4, "InstanceTextParam") - if err != nil { - return nil, errors.Wrap(err, "InstanceTextParam") - } - - ret := []SElasticcacheParameter{} - ret = append(ret, ret1...) - ret = append(ret, ret2...) - ret = append(ret, ret3...) - ret = append(ret, ret4...) - return ret, nil -} - -// https://cloud.tencent.com/document/api/239/20018 -func (self *SRegion) GetCloudElasticcaches(instanceId string) ([]SElasticcache, error) { - params := map[string]string{} - params["Region"] = self.GetId() - params["Limit"] = "20" - params["Offset"] = "0" - - if len(instanceId) > 0 { - params["InstanceId"] = instanceId - } - - ret := []SElasticcache{} - offset := 0 - for { - resp, err := self.client.redisRequest("DescribeInstances", params) - if err != nil { - return nil, errors.Wrap(err, "DescribeInstances") - } - - _ret := []SElasticcache{} - err = resp.Unmarshal(&_ret, "InstanceSet") - if err != nil { - return nil, errors.Wrap(err, "Unmarshal") - } else { - ret = append(ret, _ret...) - } - - if len(_ret) < 20 { - break - } else { - offset += 20 - params["Offset"] = strconv.Itoa(offset) - } - } - - return ret, nil -} - -type elasticcachInstanceSpec struct { - TypeId string `json:"type_id"` - MemSizeMB int `json:"mem_size_mb"` - DiskSizeGB int `json:"disk_size_gb"` - RedisShardNum string `json:"redis_shard_num"` - RedisReplicasNum string `json:"redis_replicas_num"` -} - -// redis:master:s1:r5:m1g:v4.0 -func parseLocalInstanceSpec(s string) (elasticcachInstanceSpec, error) { - ret := elasticcachInstanceSpec{} - segs := strings.Split(s, ":") - if len(segs) != 6 { - return ret, fmt.Errorf("invalid instance spec %s", s) - } - if segs[1] == "master" { - switch segs[5] { - case "v2.8": - ret.TypeId = "2" - case "v3.2": - ret.TypeId = "3" - case "v4.0": - ret.TypeId = "6" - case "v5.0": - ret.TypeId = "8" - default: - return ret, fmt.Errorf("unknown master elastic cache version %s", segs[1]) - } - } else if segs[1] == "cluster" { - switch segs[5] { - case "v3.0": - ret.TypeId = "4" - case "v4.0": - ret.TypeId = "7" - case "v5.0": - if strings.Contains(segs[4], "-d") { - ret.TypeId = "10" - } else { - ret.TypeId = "9" - } - - default: - return ret, fmt.Errorf("unknown cluster elastic cache version %s", segs[1]) - } - } else if segs[1] == "single" { - switch segs[5] { - case "v2.8": - ret.TypeId = "5" - default: - return ret, fmt.Errorf("unknown single elastic cache version %s", segs[1]) - } - } else { - return ret, fmt.Errorf("unknown elastic cache type %s", segs[1]) - } - - // - sizes := strings.Split(segs[4], "-") - if len(sizes) == 2 { - ms, err := strconv.Atoi(strings.Trim(sizes[1], "dg")) - if err != nil { - return ret, errors.Wrap(err, "Atoi") - } - - ret.DiskSizeGB = ms - } - - sn, err := strconv.Atoi(strings.Trim(segs[2], "s")) - if err != nil { - return ret, errors.Wrap(err, "RedisShardNum") - } - - ms, err := strconv.Atoi(strings.Trim(sizes[0], "mdg")) - if err != nil { - return ret, errors.Wrap(err, "Atoi") - } - if strings.HasSuffix(sizes[0], "g") { - ret.MemSizeMB = ms * 1024 / sn - } else if strings.HasSuffix(sizes[0], "m") { - ret.MemSizeMB = ms / sn - } - - ret.RedisShardNum = strings.Trim(segs[2], "s") - ret.RedisReplicasNum = strings.Trim(segs[3], "r") - return ret, nil -} diff --git a/pkg/multicloud/qcloud/events.go b/pkg/multicloud/qcloud/events.go deleted file mode 100644 index 339255aded..0000000000 --- a/pkg/multicloud/qcloud/events.go +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SEvent struct { - region *SRegion - AccountID int64 - CloudAuditEvent string - ErrorCode int - EventId string - EventName string - EventNameCn string - EventRegion string - EventSource string - EventTime int64 - RequestID string - ResourceRegion string - ResourceTypeCn string - Resources map[string]string - SecretId string - SourceIPAddress string - Username string -} - -func (event *SEvent) GetName() string { - if resourceName, ok := event.Resources["ResourceName"]; ok && len(resourceName) > 0 { - return resourceName - } - return event.EventName -} - -func (event *SEvent) GetService() string { - return event.ResourceTypeCn -} - -func (event *SEvent) GetAction() string { - return event.EventName -} - -func (event *SEvent) GetResourceType() string { - if resourceType, ok := event.Resources["ResourceType"]; ok { - return resourceType - } - return "" -} - -func (event *SEvent) GetRequest() jsonutils.JSONObject { - return jsonutils.Marshal(event) -} - -func (event *SEvent) GetRequestId() string { - return event.RequestID -} - -func (event *SEvent) GetAccount() string { - if len(event.SecretId) > 0 { - return event.SecretId - } - return event.Username -} - -func (event *SEvent) IsSuccess() bool { - return event.ErrorCode == 0 -} - -func (event *SEvent) GetCreatedAt() time.Time { - return time.Unix(event.EventTime, 0) -} - -func (region *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { - events, err := region.GetEvents(start, end) - if err != nil { - return nil, err - } - iEvents := []cloudprovider.ICloudEvent{} - for i := range events { - if withReadEvent || !strings.Contains(events[i].CloudAuditEvent, `"Read"`) { - iEvents = append(iEvents, &events[i]) - } - } - return iEvents, nil -} - -func (region *SRegion) GetEvents(start time.Time, end time.Time) ([]SEvent, error) { - var ( - events []SEvent - nextToken string - err error - _events []SEvent - ) - for { - _events, nextToken, err = region.getEvents(start, end, nextToken) - if err != nil { - return nil, err - } - if len(nextToken) == 0 { - break - } - events = append(events, _events...) - } - return events, nil -} - -func (region *SRegion) getEvents(start time.Time, end time.Time, nextToken string) ([]SEvent, string, error) { - params := map[string]string{} - if start.IsZero() { - start = time.Now().AddDate(0, 0, -7) - } - if end.IsZero() { - end = time.Now() - } - params["StartTime"] = fmt.Sprintf("%d", start.Unix()) - params["EndTime"] = fmt.Sprintf("%d", end.Unix()) - params["MaxResults"] = "50" - if len(nextToken) > 0 { - params["NextToken"] = nextToken - } - - body, err := region.auditRequest("LookUpEvents", params) - if err != nil { - return nil, "", err - } - - events := []SEvent{} - - err = body.Unmarshal(&events, "Events") - if err != nil { - return nil, "", errors.Wrap(err, "body.Unmarshal") - } - nextToken, _ = body.GetString("NextToken") - if over, _ := body.Bool("ListOver"); over { - nextToken = "" - } - return events, nextToken, nil -} diff --git a/pkg/multicloud/qcloud/host.go b/pkg/multicloud/qcloud/host.go deleted file mode 100644 index d406840cbd..0000000000 --- a/pkg/multicloud/qcloud/host.go +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone -} - -func (self *SHost) GetId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) GetName() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) -} - -func (self *SHost) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -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(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - vmId, err := self._createVM(desc.Name, desc.Hostname, desc.ExternalImageId, - desc.SysDisk, desc.Cpu, desc.MemoryMB, - desc.InstanceType, desc.ExternalNetworkId, - desc.IpAddr, desc.Description, desc.Password, - desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, - desc.UserData, desc.BillingCycle, desc.ProjectId, desc.PublicIpBw, desc.PublicIpChargeType, desc.Tags, desc.OsType) - 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, hostname string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, - networkId string, ipAddr string, desc string, passwd string, - diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string, userData string, bc *billing.SBillingCycle, projectId string, - publicIpBw int, publicIpChargeType cloudprovider.TElasticipChargeType, - tags map[string]string, osType string, -) (string, error) { - net := self.zone.getNetworkById(networkId) - if net == nil { - return "", fmt.Errorf("invalid network ID %s", networkId) - } - - var err error - - keypair := "" - if len(publicKey) > 0 { - keypair, err = self.zone.region.syncKeypair(publicKey) - if err != nil { - return "", err - } - } - - img, err := self.zone.region.GetImage(imgId) - if err != nil { - return "", errors.Wrapf(err, "GetImage(%s)", imgId) - } - if img.ImageState != ImageStatusNormal && img.ImageState != ImageStatusUsing { - return "", fmt.Errorf("image %s not ready status is %s", imgId, img.ImageState) - } - - err = self.zone.validateStorageType(sysDisk.StorageType) - if err != nil { - return "", fmt.Errorf("Storage %s not avaiable: %s", sysDisk.StorageType, err) - } - - disks := make([]SDisk, len(diskSizes)+1) - disks[0].DiskSize = img.ImageSize - if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.ImageSize { - disks[0].DiskSize = sysDisk.SizeGB - } - if disks[0].DiskSize < 50 { - disks[0].DiskSize = 50 - } - disks[0].DiskType = strings.ToUpper(sysDisk.StorageType) - - for i, dataDisk := range diskSizes { - disks[i+1].DiskSize = dataDisk.SizeGB - err = self.zone.validateStorageType(dataDisk.StorageType) - if err != nil { - return "", fmt.Errorf("Storage %s not avaiable: %s", dataDisk.StorageType, err) - } - disks[i+1].DiskType = strings.ToUpper(dataDisk.StorageType) - } - - if len(instanceType) > 0 { - log.Debugf("Try instancetype : %s", instanceType) - vmId, err := self.zone.region.CreateInstance(name, hostname, imgId, instanceType, secgroupId, self.zone.Zone, desc, passwd, disks, networkId, ipAddr, keypair, userData, bc, projectId, publicIpBw, publicIpChargeType, tags, osType) - if err != nil { - return "", errors.Wrapf(err, "Failed to create specification %s", instanceType) - } - return vmId, nil - } - - instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, 0, self.zone.Zone) - if err != nil { - return "", err - } - if len(instanceTypes) == 0 { - return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB) - } - - var vmId string - for _, instType := range instanceTypes { - instanceTypeId := instType.InstanceType - log.Debugf("Try instancetype : %s", instanceTypeId) - vmId, err = self.zone.region.CreateInstance(name, hostname, imgId, instanceTypeId, secgroupId, self.zone.Zone, desc, passwd, disks, networkId, ipAddr, keypair, userData, bc, projectId, publicIpBw, publicIpChargeType, tags, osType) - if err != nil { - log.Errorf("Failed for %s: %s", instanceTypeId, err) - } else { - return vmId, nil - } - } - - return "", fmt.Errorf("Failed to create, %s", err.Error()) -} - -func (self *SHost) Refresh() error { - return nil -} - -func (self *SHost) GetAccessIp() string { - return "" -} - -func (self *SHost) GetAccessMac() string { - return "" -} - -func (self *SHost) GetSN() string { - return "" -} - -func (self *SHost) GetCpuCount() int { - 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) GetEnabled() bool { - return true -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) GetHostStatus() string { - return api.HOST_ONLINE -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_QCLOUD -} - -func (self *SHost) GetStorageType() string { - return api.DISK_TYPE_HYBRID -} - -func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return self.zone.GetIStorageById(id) -} - -func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - return self.zone.GetIStorages() -} - -func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) { - if len(gid) == 0 { - return nil, cloudprovider.ErrNotFound - } - parts, _, err := self.zone.region.GetInstances(self.zone.Zone, []string{gid}, 0, 1) - if err != nil { - return nil, err - } - if len(parts) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(parts) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - parts[0].host = self - return &parts[0], nil -} - -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms := make([]SInstance, 0) - for { - parts, total, err := self.zone.region.GetInstances(self.zone.Zone, nil, len(vms), 50) - if err != nil { - return nil, err - } - vms = append(vms, parts...) - if len(vms) >= total { - break - } - } - ivms := make([]cloudprovider.ICloudVM, len(vms)) - for i := 0; i < len(vms); i++ { - vms[i].host = self - ivms[i] = &vms[i] - } - return ivms, nil -} - -func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - return self.zone.GetIWires() -} - -func (self *SHost) GetSysInfo() jsonutils.JSONObject { - info := jsonutils.NewDict() - info.Add(jsonutils.NewString(CLOUD_PROVIDER_QCLOUD), "manufacture") - return info -} - -func (self *SHost) IsEmulated() bool { - return true -} - -func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (host *SHost) GetIsMaintenance() bool { - return false -} - -func (host *SHost) GetVersion() string { - return QCLOUD_API_VERSION -} diff --git a/pkg/multicloud/qcloud/image.go b/pkg/multicloud/qcloud/image.go deleted file mode 100644 index f378983407..0000000000 --- a/pkg/multicloud/qcloud/image.go +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/apis" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type ImageStatusType string - -const ( - ImageStatusCreating ImageStatusType = "CREATING" - ImageStatusNormal ImageStatusType = "NORMAL" - ImageStatusSycing ImageStatusType = "SYNCING" - ImageStatusImporting ImageStatusType = "IMPORTING" - ImageStatusUsing ImageStatusType = "USING" - ImageStatusDeleting ImageStatusType = "DELETING" -) - -type SImage struct { - multicloud.SImageBase - multicloud.QcloudTags - storageCache *SStoragecache - - // normalized image info - imgInfo *imagetools.ImageInfo - - ImageId string // 镜像ID - OsName string // 镜像操作系统 - ImageType string // 镜像类型 - CreatedTime time.Time // 镜像创建时间 - ImageName string // 镜像名称 - ImageDescription string // 镜像描述 - ImageSize int // 镜像大小 - Architecture string // 镜像架构 - ImageState ImageStatusType // 镜像状态 - Platform string // 镜像来源平台 - ImageCreator string // 镜像创建者 - ImageSource string // 镜像来源 - SyncPercent int // 同步百分比 - IsSupportCloudinit bool // 镜像是否支持cloud-init -} - -func (self *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (self *SRegion) GetImages(status string, owner string, imageIds []string, name string, offset int, limit int) ([]SImage, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - - for index, imageId := range imageIds { - params[fmt.Sprintf("ImageIds.%d", index)] = imageId - } - - if len(imageIds) == 0 { // imageIds 不能和Filter同时查询 - filter := 0 - if len(status) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "image-state" - params[fmt.Sprintf("Filters.%d.Values.0", filter)] = status - filter++ - } - - if len(owner) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "image-type" - params[fmt.Sprintf("Filters.%d.Values.0", filter)] = owner - filter++ - } - - if len(name) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "image-name" - params[fmt.Sprintf("Filters.%d.Values.0", filter)] = name - filter++ - } - } - - images := make([]SImage, 0) - body, err := self.cvmRequest("DescribeImages", params, true) - if err != nil { - return nil, 0, err - } - err = body.Unmarshal(&images, "ImageSet") - if err != nil { - return nil, 0, err - } - for i := 0; i < len(images); i++ { - images[i].storageCache = self.getStoragecache() - } - total, _ := body.Float("TotalCount") - return images, int(total), nil -} - -func (self *SImage) GetId() string { - return self.ImageId -} - -func (self *SImage) GetName() string { - return self.ImageName -} - -func (self *SImage) IsEmulated() bool { - return false -} - -func (self *SImage) GetGlobalId() string { - return self.ImageId -} - -func (self *SImage) Delete(ctx context.Context) error { - return self.storageCache.region.DeleteImage(self.ImageId) -} - -func (self *SImage) GetStatus() string { - switch self.ImageState { - case ImageStatusCreating, ImageStatusSycing, ImageStatusImporting: - return api.CACHED_IMAGE_STATUS_CACHING - case ImageStatusNormal, ImageStatusUsing: - return api.CACHED_IMAGE_STATUS_ACTIVE - default: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (self *SImage) GetImageStatus() string { - switch self.ImageState { - case ImageStatusCreating, ImageStatusSycing, ImageStatusImporting: - return cloudprovider.IMAGE_STATUS_SAVING - case ImageStatusNormal, ImageStatusUsing: - return cloudprovider.IMAGE_STATUS_ACTIVE - case ImageStatusDeleting: - return cloudprovider.IMAGE_STATUS_DELETED - default: - return cloudprovider.IMAGE_STATUS_DELETED - } -} - -func (self *SImage) Refresh() error { - new, err := self.storageCache.region.GetImage(self.ImageId) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SImage) GetImageType() cloudprovider.TImageType { - switch self.ImageType { - case "PUBLIC_IMAGE": - return cloudprovider.ImageTypeSystem - case "PRIVATE_IMAGE": - return cloudprovider.ImageTypeCustomized - default: - return cloudprovider.ImageTypeCustomized - } -} - -func (self *SImage) GetSizeByte() int64 { - return int64(self.ImageSize) * 1024 * 1024 * 1024 -} - -func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if self.imgInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(self.OsName, self.Architecture, self.Platform, self.Platform, "") - self.imgInfo = &imgInfo - } - - return self.imgInfo -} - -func (self *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) -} - -func (self *SImage) GetOsDist() string { - return self.getNormalizedImageInfo().OsDistro -} - -func (self *SImage) GetOsVersion() string { - return self.getNormalizedImageInfo().OsVersion -} - -func (self *SImage) GetOsArch() string { - return self.getNormalizedImageInfo().OsArch -} - -func (img *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(img.getNormalizedImageInfo().OsBios) -} - -func (img *SImage) GetFullOsName() string { - return img.OsName -} - -func (img *SImage) GetOsLang() string { - return img.getNormalizedImageInfo().OsLang -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return 50 -} - -func (self *SImage) GetImageFormat() string { - return "qcow2" -} - -func (self *SImage) GetCreatedAt() time.Time { - return self.CreatedTime -} - -func (self *SRegion) GetImage(imageId string) (*SImage, error) { - images, _, err := self.GetImages("", "", []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 *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.storageCache -} - -func (self *SRegion) DeleteImage(imageId string) error { - params := make(map[string]string) - params["ImageIds.0"] = imageId - - _, err := self.cvmRequest("DeleteImages", params, true) - return err -} - -func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) { - image, err := self.GetImage(imageId) - if err != nil { - return "", err - } - return image.ImageState, nil -} - -func (self *SRegion) GetImageByName(name string) (*SImage, error) { - images, _, err := self.GetImages("", "", nil, name, 0, 1) - if err != nil { - return nil, err - } - if len(images) == 0 { - return nil, cloudprovider.ErrNotFound - } - return &images[0], nil -} - -type ImportImageOsListSupported struct { - Linux []string //"CentOS|Ubuntu|Debian|OpenSUSE|SUSE|CoreOS|FreeBSD|Other Linux" - Windows []string //"Windows Server 2008|Windows Server 2012|Windows Server 2016" -} - -type ImportImageOsVersionSet struct { - Architecture []string - OsName string //"CentOS|Ubuntu|Debian|OpenSUSE|SUSE|CoreOS|FreeBSD|Other Linux|Windows Server 2008|Windows Server 2012|Windows Server 2016" - OsVersions []string -} - -type SupportImageSet struct { - ImportImageOsListSupported ImportImageOsListSupported - ImportImageOsVersionSet []ImportImageOsVersionSet -} - -func (self *SRegion) GetSupportImageSet() (*SupportImageSet, error) { - body, err := self.cvmRequest("DescribeImportImageOs", map[string]string{}, true) - if err != nil { - return nil, err - } - imageSet := SupportImageSet{} - return &imageSet, body.Unmarshal(&imageSet) -} - -func (self *SRegion) GetImportImageParams(name string, osArch, osDist, osVersion string, imageUrl string) (map[string]string, error) { - params := map[string]string{} - imageSet, err := self.GetSupportImageSet() - if err != nil { - return nil, err - } - osType := "" - for _, _imageSet := range imageSet.ImportImageOsVersionSet { - if strings.ToLower(osDist) == strings.ToLower(_imageSet.OsName) { //Linux一般可正常匹配 - osType = _imageSet.OsName - } else if strings.Contains(strings.ToLower(_imageSet.OsName), "windows") && strings.Contains(strings.ToLower(osDist), "windows") { - info := strings.Split(_imageSet.OsName, " ") - _osVersion := "2008" - for _, version := range info { - if _, err := strconv.Atoi(version); err == nil { - _osVersion = version - break - } - } - if strings.Contains(osDist+osVersion, _osVersion) { - osType = _imageSet.OsName - } - } - if len(osType) == 0 { - continue - } - if !utils.IsInStringArray(osArch, _imageSet.Architecture) { - osArch = apis.OS_ARCH_X86_64 - } - for _, _osVersion := range _imageSet.OsVersions { - if strings.HasPrefix(osVersion, _osVersion) { - osVersion = _osVersion - break - } - } - if !utils.IsInStringArray(osVersion, _imageSet.OsVersions) { - osVersion = "-" - if len(_imageSet.OsVersions) > 0 { - osVersion = _imageSet.OsVersions[0] - } - } - break - } - if len(osType) == 0 { - osType = "Other Linux" - osArch = apis.OS_ARCH_X86_64 - osVersion = "-" - } - - params["ImageName"] = name - params["OsType"] = osType - params["OsVersion"] = osVersion - params["Architecture"] = osArch // "x86_64|i386" - params["ImageUrl"] = imageUrl - params["Force"] = "true" - return params, nil -} - -func (self *SRegion) ImportImage(name string, osArch, osDist, osVersion string, imageUrl string) (*SImage, error) { - params, err := self.GetImportImageParams(name, osArch, osDist, osVersion, imageUrl) - if err != nil { - return nil, err - } - - log.Debugf("Upload image with params %#v", params) - - if _, err := self.cvmRequest("ImportImage", params, true); err != nil { - return nil, err - } - for i := 0; i < 8; i++ { - image, err := self.GetImageByName(name) - if err == nil { - return image, nil - } - time.Sleep(time.Minute * time.Duration(i)) - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/qcloud/instance.go b/pkg/multicloud/qcloud/instance.go deleted file mode 100644 index eb472c8504..0000000000 --- a/pkg/multicloud/qcloud/instance.go +++ /dev/null @@ -1,1072 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - sdkerrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -const ( - // PENDING:表示创建中 - // LAUNCH_FAILED:表示创建失败 - // RUNNING:表示运行中 - // STOPPED:表示关机 - // STARTING:表示开机中 - // STOPPING:表示关机中 - // REBOOTING:表示重启中 - // SHUTDOWN:表示停止待销毁 - // TERMINATING:表示销毁中。 - - InstanceStatusStopped = "STOPPED" - InstanceStatusRunning = "RUNNING" - InstanceStatusStopping = "STOPPING" - InstanceStatusStarting = "STARTING" -) - -const ( - InternetChargeTypeBandwidthPrepaid = "BANDWIDTH_PREPAID" - InternetChargeTypeTrafficPostpaidByHour = "TRAFFIC_POSTPAID_BY_HOUR" - InternetChargeTypeBandwidthPostpaidByHour = "BANDWIDTH_POSTPAID_BY_HOUR" - InternetChargeTypeBandwidthPackage = "BANDWIDTH_PACKAGE" -) - -type SystemDisk struct { - DiskType string //系统盘类型。系统盘类型限制详见CVM实例配置。取值范围:LOCAL_BASIC:本地硬盘 LOCAL_SSD:本地SSD硬盘 CLOUD_BASIC:普通云硬盘 CLOUD_SSD:SSD云硬盘 CLOUD_PREMIUM:高性能云硬盘 默认取值:CLOUD_BASIC。 - DiskId string // 系统盘ID。LOCAL_BASIC 和 LOCAL_SSD 类型没有ID。暂时不支持该参数。 - DiskSize float32 //系统盘大小,单位:GB。默认值为 50 -} - -type DataDisk struct { - DiskSize float32 // 数据盘大小,单位:GB。最小调整步长为10G,不同数据盘类型取值范围不同,具体限制详见:CVM实例配置。默认值为0,表示不购买数据盘。更多限制详见产品文档。 - DiskType string // 数据盘类型。数据盘类型限制详见CVM实例配置。取值范围:LOCAL_BASIC:本地硬盘 LOCAL_SSD:本地SSD硬盘 CLOUD_BASIC:普通云硬盘 CLOUD_PREMIUM:高性能云硬盘 CLOUD_SSD:SSD云硬盘 默认取值:LOCAL_BASIC。 该参数对ResizeInstanceDisk接口无效。 - DiskId string // 数据盘ID。LOCAL_BASIC 和 LOCAL_SSD 类型没有ID。暂时不支持该参数。 - DeleteWithInstance bool // 数据盘是否随子机销毁。取值范围:TRUE:子机销毁时,销毁数据盘 FALSE:子机销毁时,保留数据盘 默认取值:TRUE 该参数目前仅用于 RunInstances 接口。 -} - -type InternetAccessible struct { - InternetChargeType string //网络计费类型。取值范围:BANDWIDTH_PREPAID:预付费按带宽结算 TRAFFIC_POSTPAID_BY_HOUR:流量按小时后付费 BANDWIDTH_POSTPAID_BY_HOUR:带宽按小时后付费 BANDWIDTH_PACKAGE:带宽包用户 默认取值:非带宽包用户默认与子机付费类型保持一致。 - InternetMaxBandwidthOut int // 公网出带宽上限,单位:Mbps。默认值:0Mbps。不同机型带宽上限范围不一致,具体限制详见购买网络带宽。 - PublicIpAssigned bool // 是否分配公网IP。取值范围: TRUE:表示分配公网IP FALSE:表示不分配公网IP 当公网带宽大于0Mbps时,可自由选择开通与否,默认开通公网IP;当公网带宽为0,则不允许分配公网IP。 -} - -type VirtualPrivateCloud struct { - VpcId string // 私有网络ID,形如vpc-xxx。有效的VpcId可通过登录控制台查询;也可以调用接口 DescribeVpcEx ,从接口返回中的unVpcId字段获取。 - SubnetId string // 私有网络子网ID,形如subnet-xxx。有效的私有网络子网ID可通过登录控制台查询;也可以调用接口 DescribeSubnets ,从接口返回中的unSubnetId字段获取。 - AsVpcGateway bool // 是否用作公网网关。公网网关只有在实例拥有公网IP以及处于私有网络下时才能正常使用。取值范围:TRUE:表示用作公网网关 FALSE:表示不用作公网网关 默认取值:FALSE。 - PrivateIpAddresses []string // 私有网络子网 IP 数组,在创建实例、修改实例vpc属性操作中可使用此参数。当前仅批量创建多台实例时支持传入相同子网的多个 IP。 -} - -type LoginSettings struct { - Password string //实例登录密码。不同操作系统类型密码复杂度限制不一样,具体如下:Linux实例密码必须8到16位,至少包括两项[a-z,A-Z]、[0-9] 和 [( ) ~ ! @ # $ % ^ & * - + = | { } [ ] : ; ' , . ? / ]中的特殊符号。
  • Windows实例密码必须12到16位,至少包括三项[a-z],[A-Z],[0-9] 和 [( ) ~ ! @ # $ % ^ & * - + = { } [ ] : ; ' , . ? /]中的特殊符号。 若不指定该参数,则由系统随机生成密码,并通过站内信方式通知到用户。 - KeyIds []string // 密钥ID列表。关联密钥后,就可以通过对应的私钥来访问实例;KeyId可通过接口DescribeKeyPairs获取,密钥与密码不能同时指定,同时Windows操作系统不支持指定密钥。当前仅支持购买的时候指定一个密钥。 - KeepImageLogin string // 保持镜像的原始设置。该参数与Password或KeyIds.N不能同时指定。只有使用自定义镜像、共享镜像或外部导入镜像创建实例时才能指定该参数为TRUE。取值范围: TRUE:表示保持镜像的登录设置 FALSE:表示不保持镜像的登录设置 默认取值:FALSE。 -} - -type Tag struct { - Key string - Value string -} - -type SInstance struct { - multicloud.SInstanceBase - multicloud.QcloudTags - - host *SHost - - // normalized image info - osInfo *imagetools.ImageInfo - - image *SImage - idisks []cloudprovider.ICloudDisk - - Placement Placement - InstanceId string - InstanceType string - CPU int - Memory int - RestrictState string //NORMAL EXPIRED PROTECTIVELY_ISOLATED - InstanceName string - InstanceChargeType InstanceChargeType //PREPAID:表示预付费,即包年包月 POSTPAID_BY_HOUR:表示后付费,即按量计费 CDHPAID:CDH付费,即只对CDH计费,不对CDH上的实例计费。 - SystemDisk SystemDisk //实例系统盘信息。 - DataDisks []DataDisk //实例数据盘信息。只包含随实例购买的数据盘。 - PrivateIpAddresses []string //实例主网卡的内网IP列表。 - PublicIpAddresses []string //实例主网卡的公网IP列表。 - InternetAccessible InternetAccessible //实例带宽信息。 - VirtualPrivateCloud VirtualPrivateCloud //实例所属虚拟私有网络信息。 - ImageId string // 生产实例所使用的镜像ID。 - RenewFlag string // 自动续费标识。取值范围:NOTIFY_AND_MANUAL_RENEW:表示通知即将过期,但不自动续费 NOTIFY_AND_AUTO_RENEW:表示通知即将过期,而且自动续费 DISABLE_NOTIFY_AND_MANUAL_RENEW:表示不通知即将过期,也不自动续费。 - CreatedTime time.Time // 创建时间。按照ISO8601标准表示,并且使用UTC时间。格式为:YYYY-MM-DDThh:mm:ssZ。 - ExpiredTime time.Time // 到期时间。按照ISO8601标准表示,并且使用UTC时间。格式为:YYYY-MM-DDThh:mm:ssZ。 - OsName string // 操作系统名称。 - SecurityGroupIds []string // 实例所属安全组。该参数可以通过调用 DescribeSecurityGroups 的返回值中的sgId字段来获取。 - LoginSettings LoginSettings //实例登录设置。目前只返回实例所关联的密钥。 - InstanceState string // 实例状态。取值范围:PENDING:表示创建中 LAUNCH_FAILED:表示创建失败 RUNNING:表示运行中 STOPPED:表示关机 STARTING:表示开机中 STOPPING:表示关机中 REBOOTING:表示重启中 SHUTDOWN:表示停止待销毁 TERMINATING:表示销毁中。 - Tags []Tag -} - -func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit int) ([]SInstance, int, error) { - params := make(map[string]string) - if limit < 1 || limit > 50 { - limit = 50 - } - - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - instances := make([]SInstance, 0) - if ids != nil && len(ids) > 0 { - for index, id := range ids { - params[fmt.Sprintf("InstanceIds.%d", index)] = id - } - } else { - if len(zoneId) > 0 { - params["Filters.0.Name"] = "zone" - params["Filters.0.Values.0"] = zoneId - } - } - body, err := self.cvmRequest("DescribeInstances", params, true) - if err != nil { - return nil, 0, err - } - err = body.Unmarshal(&instances, "InstanceSet") - if err != nil { - return nil, 0, err - } - total, _ := body.Float("TotalCount") - return instances, int(total), nil -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - return self.SecurityGroupIds, nil -} - -func (self *SInstance) getCloudMetadata() (map[string]string, error) { - mtags, err := self.host.zone.region.FetchResourceTags("cvm", "instance", []string{self.InstanceId}) - if err != nil { - return nil, errors.Wrap(err, "FetchResourceTags") - } - if tags, ok := mtags[self.InstanceId]; ok { - return *tags, nil - } else { - return nil, nil - } -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetId() string { - return self.InstanceId -} - -func (self *SInstance) GetName() string { - if len(self.InstanceName) > 0 && self.InstanceName != "未命名" { - return self.InstanceName - } - return self.InstanceId -} - -func (self *SInstance) GetHostname() string { - return self.GetName() -} - -func (self *SInstance) GetGlobalId() string { - return self.InstanceId -} - -func (self *SInstance) IsEmulated() bool { - return false -} - -func (self *SInstance) GetInstanceType() string { - return self.InstanceType -} - -func (self *SInstance) getVpc() (*SVpc, error) { - return self.host.zone.region.getVpc(self.VirtualPrivateCloud.VpcId) -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - idisks := make([]cloudprovider.ICloudDisk, 0) - - if utils.IsInStringArray(strings.ToUpper(self.SystemDisk.DiskType), QCLOUD_LOCAL_STORAGE_TYPES) { - storage := SLocalStorage{zone: self.host.zone, storageType: self.SystemDisk.DiskType} - disk := SLocalDisk{ - storage: &storage, - DiskId: self.SystemDisk.DiskId, - DiskSize: self.SystemDisk.DiskSize, - DisktType: self.SystemDisk.DiskType, - DiskUsage: "SYSTEM_DISK", - imageId: self.ImageId, - } - idisks = append(idisks, &disk) - } - - for i := 0; i < len(self.DataDisks); i++ { - if utils.IsInStringArray(strings.ToUpper(self.DataDisks[i].DiskType), QCLOUD_LOCAL_STORAGE_TYPES) { - storage := SLocalStorage{zone: self.host.zone, storageType: self.DataDisks[i].DiskType} - disk := SLocalDisk{ - storage: &storage, - DiskId: self.DataDisks[i].DiskId, - DiskSize: self.DataDisks[i].DiskSize, - DisktType: self.DataDisks[i].DiskType, - DiskUsage: "DATA_DISK", - } - idisks = append(idisks, &disk) - } - } - - disks := make([]SDisk, 0) - totalDisk := -1 - for totalDisk < 0 || len(disks) < totalDisk { - parts, total, err := self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, len(disks), 50) - if err != nil { - log.Errorf("fetchDisks fail %s", err) - return nil, err - } - if len(parts) > 0 { - disks = append(disks, parts...) - } - totalDisk = total - } - - for i := 0; i < len(disks); i += 1 { - store, err := self.host.zone.getStorageByCategory(disks[i].DiskType) - if err != nil { - return nil, err - } - disks[i].storage = store - idisks = append(idisks, &disks[i]) - } - - return idisks, nil -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - classic := self.VirtualPrivateCloud.VpcId == "" - region := self.host.zone.region - ret := []cloudprovider.ICloudNic{} - if classic { - for _, ipAddr := range self.PrivateIpAddresses { - nic := SInstanceNic{ - instance: self, - ipAddr: ipAddr, - classic: true, - } - ret = append(ret, &nic) - } - } - nics, _, err := region.GetNetworkInterfaces(nil, self.InstanceId, "", 0, 10) - if err != nil { - return nil, errors.Wrapf(err, "GetNetworkInterfaces") - } - for _, networkInterface := range nics { - nic := &SInstanceNic{ - instance: self, - id: String(&networkInterface.NetworkInterfaceId), - macAddr: strings.ToLower(networkInterface.MacAddress), - classic: classic, - } - for _, addr := range networkInterface.PrivateIpAddressSet { - if addr.Primary { - nic.ipAddr = addr.PrivateIpAddress - } - } - ret = append(ret, nic) - } - return ret, nil -} - -func (self *SInstance) GetVcpuCount() int { - return self.CPU -} - -func (self *SInstance) GetVmemSizeMB() int { - return self.Memory * 1024 -} - -func (self *SInstance) GetBootOrder() string { - return "dcn" -} - -func (self *SInstance) GetVga() string { - return "std" -} - -func (self *SInstance) GetVdi() string { - return "vnc" -} - -func (ins *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { - if ins.osInfo == nil { - osInfo := imagetools.NormalizeImageInfo(ins.OsName, "", "", "", "") - ins.osInfo = &osInfo - } - return ins.osInfo -} - -func (ins *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(ins.getNormalizedOsInfo().OsType) -} - -func (ins *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(ins.getNormalizedOsInfo().OsBios) -} - -func (ins *SInstance) GetFullOsName() string { - return ins.OsName -} - -func (ins *SInstance) GetOsLang() string { - return ins.getNormalizedOsInfo().OsLang -} - -func (ins *SInstance) GetOsArch() string { - return ins.getNormalizedOsInfo().OsArch -} - -func (ins *SInstance) GetOsDist() string { - return ins.getNormalizedOsInfo().OsDistro -} - -func (ins *SInstance) GetOsVersion() string { - return ins.getNormalizedOsInfo().OsVersion -} - -func (self *SInstance) GetMachine() string { - return "pc" -} - -func (self *SInstance) GetStatus() string { - switch self.InstanceState { - case "PENDING": - return api.VM_DEPLOYING - case "LAUNCH_FAILED": - return api.VM_DEPLOY_FAILED - case "RUNNING": - return api.VM_RUNNING - case "STOPPED": - return api.VM_READY - case "STARTING", "REBOOTING": - return api.VM_STARTING - case "STOPPING": - return api.VM_STOPPING - case "SHUTDOWN": - return api.VM_DEALLOCATED - case "TERMINATING": - return api.VM_DELETING - default: - return api.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) GetHypervisor() string { - return api.HYPERVISOR_QCLOUD -} - -func (self *SInstance) StartVM(ctx context.Context) error { - err := cloudprovider.Wait(time.Second*15, time.Minute*5, func() (bool, error) { - err := self.Refresh() - if err != nil { - return true, errors.Wrapf(err, "Refresh") - } - log.Debugf("status %s expect %s", self.GetStatus(), api.VM_RUNNING) - if self.GetStatus() == api.VM_RUNNING { - return true, nil - } - if self.GetStatus() == api.VM_STARTING { - return false, nil - } - if self.GetStatus() == api.VM_READY { - err := self.host.zone.region.StartVM(self.InstanceId) - if err != nil { - if e, ok := errors.Cause(err).(*sdkerrors.TencentCloudSDKError); ok { - if e.Code == "UnsupportedOperation.InstanceStateRunning" { - return true, nil - } - } - return true, err - } - } - return false, nil - }) - return errors.Wrapf(err, "Wait") -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - err := self.host.zone.region.StopVM(self.InstanceId, opts) - if err != nil { - return err - } - return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 8*time.Minute) // 8 mintues, 腾讯云有时关机比较慢 -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - url, err := self.host.zone.region.GetInstanceVNCUrl(self.InstanceId) - if err != nil { - return nil, err - } - ret := &cloudprovider.ServerVncOutput{ - Url: url, - Protocol: "qcloud", - InstanceId: self.InstanceId, - Hypervisor: api.HYPERVISOR_QCLOUD, - } - return ret, nil -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return self.host.zone.region.UpdateVM(self.InstanceId, name) -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - var keypairName string - if len(publicKey) > 0 { - var err error - keypairName, err = self.host.zone.region.syncKeypair(publicKey) - if err != nil { - return err - } - } - - return self.host.zone.region.DeployVM(self.InstanceId, name, password, keypairName, deleteKeypair, description) -} - -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - keypair := "" - if len(desc.PublicKey) > 0 { - var err error - keypair, err = self.host.zone.region.syncKeypair(desc.PublicKey) - if err != nil { - return "", err - } - } - err := self.host.zone.region.ReplaceSystemDisk(self.InstanceId, desc.ImageId, desc.Password, keypair, desc.SysSizeGB) - if err != nil { - return "", err - } - opts := &cloudprovider.ServerStopOptions{ - IsForce: true, - } - self.StopVM(ctx, opts) - instance, err := self.host.zone.region.GetInstance(self.InstanceId) - if err != nil { - return "", err - } - return instance.SystemDisk.DiskId, nil -} - -func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - instanceTypes := []string{} - if len(config.InstanceType) > 0 { - instanceTypes = []string{config.InstanceType} - } else { - specs, err := self.host.zone.region.GetMatchInstanceTypes(config.Cpu, config.MemoryMB, 0, self.Placement.Zone) - if err != nil { - return errors.Wrapf(err, "GetMatchInstanceTypes") - } - for _, spec := range specs { - instanceTypes = append(instanceTypes, spec.InstanceType) - } - } - - var err error - for _, instanceType := range instanceTypes { - err = self.host.zone.region.ChangeVMConfig(self.InstanceId, instanceType) - if err != nil { - log.Errorf("ChangeConfig for %s with %s error: %v", self.InstanceId, instanceType, err) - continue - } - return nil - } - if err != nil { - return err - } - - return fmt.Errorf("Failed to change vm config, specification not supported") -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return self.host.zone.region.AttachDisk(self.InstanceId, diskId) -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return self.host.zone.region.DetachDisk(self.InstanceId, diskId) -} - -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 - } - if len(instances) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - if instances[0].InstanceState == "LAUNCH_FAILED" { - return nil, cloudprovider.ErrNotFound - } - return &instances[0], nil -} - -func (self *SRegion) CreateInstance(name, hostname string, imageId string, instanceType string, securityGroupId string, - zoneId string, desc string, passwd string, disks []SDisk, networkId string, ipAddr string, - keypair string, userData string, bc *billing.SBillingCycle, projectId string, - publicIpBw int, publicIpChargeType cloudprovider.TElasticipChargeType, - tags map[string]string, osType string, -) (string, error) { - params := make(map[string]string) - params["Region"] = self.Region - params["ImageId"] = imageId - params["InstanceType"] = instanceType - params["SecurityGroupIds.0"] = securityGroupId - params["Placement.Zone"] = zoneId - if len(projectId) > 0 { - params["Placement.ProjectId"] = projectId - } - params["InstanceName"] = name - if len(hostname) > 0 { - params["HostName"] = hostname - } - - bandwidth := publicIpBw - if publicIpBw == 0 { - bandwidth = 100 - if bc != nil { - bandwidth = 200 - } - } - - internetChargeType := "TRAFFIC_POSTPAID_BY_HOUR" - if publicIpChargeType == cloudprovider.ElasticipChargeTypeByBandwidth { - internetChargeType = "BANDWIDTH_POSTPAID_BY_HOUR" - } - pkgs, _, err := self.GetBandwidthPackages([]string{}, 0, 50) - if err != nil { - return "", errors.Wrapf(err, "GetBandwidthPackages") - } - if len(pkgs) > 0 { - bandwidth = 65535 // unlimited bandwidth - if publicIpBw > 0 { // 若用户指定带宽则限制带宽大小 - bandwidth = publicIpBw - } - internetChargeType = "BANDWIDTH_PACKAGE" - pkgId := pkgs[0].BandwidthPackageId - for _, pkg := range pkgs { - if len(pkg.ResourceSet) < 100 { - pkgId = pkg.BandwidthPackageId - break - } - } - params["InternetAccessible.BandwidthPackageId"] = pkgId - } - - params["InternetAccessible.InternetChargeType"] = internetChargeType - params["InternetAccessible.InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bandwidth) - params["InternetAccessible.PublicIpAssigned"] = "TRUE" - if publicIpBw == 0 { - params["InternetAccessible.PublicIpAssigned"] = "FALSE" - } - if len(keypair) > 0 { - params["LoginSettings.KeyIds.0"] = keypair - } else if len(passwd) > 0 { - params["LoginSettings.Password"] = passwd - } else { - params["LoginSettings.KeepImageLogin"] = "TRUE" - } - if len(userData) > 0 { - params["UserData"] = userData - } - - if bc != nil { - params["InstanceChargeType"] = "PREPAID" - params["InstanceChargePrepaid.Period"] = fmt.Sprintf("%d", bc.GetMonths()) - if bc.AutoRenew { - params["InstanceChargePrepaid.RenewFlag"] = "NOTIFY_AND_AUTO_RENEW" - } else { - params["InstanceChargePrepaid.RenewFlag"] = "NOTIFY_AND_MANUAL_RENEW" - } - } else { - params["InstanceChargeType"] = "POSTPAID_BY_HOUR" - } - - // tags - if len(tags) > 0 { - params["TagSpecification.0.ResourceType"] = "instance" - tagIdx := 0 - for k, v := range tags { - params[fmt.Sprintf("TagSpecification.0.Tags.%d.Key", tagIdx)] = k - params[fmt.Sprintf("TagSpecification.0.Tags.%d.Value", tagIdx)] = v - tagIdx += 1 - } - } - - //params["IoOptimized"] = "optimized" - for i, d := range disks { - if i == 0 { - params["SystemDisk.DiskType"] = d.DiskType - params["SystemDisk.DiskSize"] = fmt.Sprintf("%d", d.DiskSize) - } else { - params[fmt.Sprintf("DataDisks.%d.DiskSize", i-1)] = fmt.Sprintf("%d", d.DiskSize) - params[fmt.Sprintf("DataDisks.%d.DiskType", i-1)] = d.DiskType - } - } - network, err := self.GetNetwork(networkId) - if err != nil { - return "", errors.Wrapf(err, "GetNetwork(%s)", networkId) - } - params["VirtualPrivateCloud.SubnetId"] = networkId - params["VirtualPrivateCloud.VpcId"] = network.VpcId - if len(ipAddr) > 0 { - params["VirtualPrivateCloud.PrivateIpAddresses.0"] = ipAddr - } - - var body jsonutils.JSONObject - instanceIdSet := []string{} - err = cloudprovider.Wait(time.Second*10, time.Minute, func() (bool, error) { - params["ClientToken"] = utils.GenRequestId(20) - body, err = self.cvmRequest("RunInstances", params, true) - if err != nil { - if strings.Contains(err.Error(), "Code=InvalidPermission") { // 带宽上移用户未指定公网ip时不能设置带宽 - delete(params, "InternetAccessible.InternetChargeType") - delete(params, "InternetAccessible.InternetMaxBandwidthOut") - return false, nil - } - if strings.Contains(err.Error(), "UnsupportedOperation.BandwidthPackageIdNotSupported") || - (strings.Contains(err.Error(), "Code=InvalidParameterCombination") && strings.Contains(err.Error(), "InternetAccessible.BandwidthPackageId")) { - delete(params, "InternetAccessible.BandwidthPackageId") - return false, nil - } - return false, errors.Wrapf(err, "RunInstances") - } - return true, nil - }) - if err != nil { - return "", errors.Wrap(err, "RunInstances") - } - err = body.Unmarshal(&instanceIdSet, "InstanceIdSet") - if err == nil && len(instanceIdSet) > 0 { - return instanceIdSet[0], nil - } - return "", fmt.Errorf("Failed to create instance") -} - -func (self *SRegion) doStartVM(instanceId string) error { - return self.instanceOperation(instanceId, "StartInstances", nil, true) -} - -func (self *SRegion) doStopVM(instanceId string, opts *cloudprovider.ServerStopOptions) error { - params := make(map[string]string) - if opts.IsForce { - // params["ForceStop"] = "FALSE" - params["StopType"] = "HARD" - } else { - // params["ForceStop"] = "FALSE" - params["StopType"] = "SOFT" - } - if opts.StopCharging { - params["StoppedMode"] = "STOP_CHARGING" - } - return self.instanceOperation(instanceId, "StopInstances", params, true) -} - -func (self *SRegion) doDeleteVM(instanceId string) error { - params := make(map[string]string) - err := self.instanceOperation(instanceId, "TerminateInstances", params, true) - if err != nil && cloudprovider.IsError(err, []string{"InvalidInstanceId.NotFound"}) { - return nil - } - return err -} - -func (self *SRegion) StartVM(instanceId string) error { - status, err := self.GetInstanceStatus(instanceId) - if err != nil { - log.Errorf("Fail to get instance status on StartVM: %s", err) - return err - } - if status != InstanceStatusStopped { - log.Errorf("StartVM: vm status is %s expect %s", status, InstanceStatusStopped) - return cloudprovider.ErrInvalidStatus - } - return self.doStartVM(instanceId) -} - -func (self *SRegion) StopVM(instanceId string, opts *cloudprovider.ServerStopOptions) error { - status, err := self.GetInstanceStatus(instanceId) - if err != nil { - log.Errorf("Fail to get instance status on StopVM: %s", err) - return err - } - if status == InstanceStatusStopped { - return nil - } - return self.doStopVM(instanceId, opts) -} - -func (self *SRegion) DeleteVM(instanceId string) error { - status, err := self.GetInstanceStatus(instanceId) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - return errors.Wrapf(err, "self.GetInstanceStatus") - } - log.Debugf("Instance status on delete is %s", status) - if status != InstanceStatusStopped { - log.Warningf("DeleteVM: vm status is %s expect %s", status, InstanceStatusStopped) - } - return self.doDeleteVM(instanceId) -} - -func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { - instance, err := self.GetInstance(instanceId) - if err != nil { - return err - } - - // 修改密钥时直接返回 - if deleteKeypair { - for i := 0; i < len(instance.LoginSettings.KeyIds); i++ { - err = self.DetachKeyPair(instanceId, instance.LoginSettings.KeyIds[i]) - if err != nil { - return err - } - } - } - - if len(keypairName) > 0 { - err = self.AttachKeypair(instanceId, keypairName) - if err != nil { - return err - } - } - - params := make(map[string]string) - - if len(name) > 0 && instance.InstanceName != name { - params["InstanceName"] = name - } - - if len(params) > 0 { - err := self.modifyInstanceAttribute(instanceId, params) - if err != nil { - return err - } - } - if len(password) > 0 { - return self.instanceOperation(instanceId, "ResetInstancesPassword", map[string]string{"Password": password}, true) - } - return nil -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - err := self.host.zone.region.DeleteVM(self.InstanceId) - if err != nil { - return errors.Wrapf(err, "region.DeleteVM(%s)", self.InstanceId) - } - if self.GetBillingType() == billing_api.BILLING_TYPE_PREPAID { // 预付费的需要删除两次 - cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) { - err = self.Refresh() - if err != nil { - log.Warningf("refresh instance %s(%s) error: %v", self.InstanceName, self.InstanceId, err) - return false, nil - } - // 需要等待第一次删除后,状态变为SHUTDOWN,才可以进行第二次删除,否则会报: - // Code=OperationDenied.InstanceOperationInProgress, Message=该实例`['ins-mxqturgj']` - if self.InstanceState == "SHUTDOWN" { - return true, nil - } - log.Debugf("wait %s(%s) status be SHUTDOWN, current is %s", self.InstanceName, self.InstanceId, self.InstanceState) - return false, nil - }) - err := self.host.zone.region.DeleteVM(self.InstanceId) - if err != nil { - return errors.Wrapf(err, "region.DeleteVM(%s)", self.InstanceId) - } - } - return cloudprovider.WaitDeleted(self, 10*time.Second, 5*time.Minute) // 5minutes -} - -func (self *SRegion) UpdateVM(instanceId string, name string) error { - params := make(map[string]string) - params["InstanceName"] = name - return self.modifyInstanceAttribute(instanceId, params) -} - -func (self *SRegion) modifyInstanceAttribute(instanceId string, params map[string]string) error { - return self.instanceOperation(instanceId, "ModifyInstancesAttribute", params, true) -} - -func (self *SRegion) ReplaceSystemDisk(instanceId string, imageId string, passwd string, keypairName string, sysDiskSizeGB int) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["ImageId"] = imageId - params["EnhancedService.SecurityService.Enabled"] = "TRUE" - params["EnhancedService.MonitorService.Enabled"] = "TRUE" - - // 秘钥和密码及保留镜像设置只能选其一 - if len(keypairName) > 0 { - params["LoginSettings.KeyIds.0"] = keypairName - } else if len(passwd) > 0 { - params["LoginSettings.Password"] = passwd - } else { - params["LoginSettings.KeepImageLogin"] = "TRUE" - } - - if sysDiskSizeGB > 0 { - params["SystemDisk.DiskSize"] = fmt.Sprintf("%d", sysDiskSizeGB) - } - _, err := self.cvmRequest("ResetInstance", params, true) - return err -} - -func (self *SRegion) ChangeVMConfig(instanceId string, instanceType string) error { - params := make(map[string]string) - params["InstanceType"] = instanceType - - err := self.instanceOperation(instanceId, "ResetInstancesType", params, true) - return errors.Wrapf(err, "ResetInstancesType %s", instanceType) -} - -func (self *SRegion) DetachDisk(instanceId string, diskId string) error { - params := make(map[string]string) - params["DiskIds.0"] = diskId - log.Infof("Detach instance %s disk %s", instanceId, diskId) - _, err := self.cbsRequest("DetachDisks", params) - if err != nil { - // 可重复卸载,无报错,若磁盘被删除会有以下错误 - //[TencentCloudSDKError] Code=InvalidDisk.NotSupported, Message=disk(disk-4g5s7zhl) deleted (39a711ce2d17), RequestId=508d7fe3-e64e-4bb8-8ad7-39a711ce2d17 - if strings.Contains(err.Error(), fmt.Sprintf("disk(%s) deleted", diskId)) { - return nil - } - return errors.Wrap(err, "DetachDisks") - } - - return nil -} - -func (self *SRegion) AttachDisk(instanceId string, diskId string) error { - params := make(map[string]string) - params["InstanceId"] = instanceId - params["DiskIds.0"] = diskId - _, err := self.cbsRequest("AttachDisks", params) - if err != nil { - log.Errorf("AttachDisks %s to %s fail %s", diskId, instanceId, err) - return err - } - return nil -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - params := map[string]string{"SecurityGroups.0": secgroupId} - return self.host.zone.region.instanceOperation(self.InstanceId, "ModifyInstancesAttribute", params, true) -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - params := map[string]string{} - for i := 0; i < len(secgroupIds); i++ { - params[fmt.Sprintf("SecurityGroups.%d", i)] = secgroupIds[i] - } - return self.host.zone.region.instanceOperation(self.InstanceId, "ModifyInstancesAttribute", params, true) -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - eip, total, err := self.host.zone.region.GetEips("", self.InstanceId, 0, 1) - if err != nil { - return nil, err - } - if total == 1 { - return &eip[0], nil - } - self.Refresh() - for _, address := range self.PublicIpAddresses { - eip := SEipAddress{region: self.host.zone.region} - eip.AddressIp = address - eip.InstanceId = self.InstanceId - eip.AddressId = self.InstanceId - eip.AddressName = address - eip.AddressType = EIP_TYPE_WANIP - eip.AddressStatus = EIP_STATUS_BIND - eip.Bandwidth = self.InternetAccessible.InternetMaxBandwidthOut - return &eip, nil - } - return nil, nil -} - -func (self *SInstance) GetBillingType() string { - switch self.InstanceChargeType { - case PrePaidInstanceChargeType: - return billing_api.BILLING_TYPE_PREPAID - case PostPaidInstanceChargeType: - return billing_api.BILLING_TYPE_POSTPAID - default: - return billing_api.BILLING_TYPE_PREPAID - } -} - -func (self *SInstance) GetCreatedAt() time.Time { - return self.CreatedTime -} - -func (self *SInstance) GetExpiredAt() time.Time { - return self.ExpiredTime -} - -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) Renew(bc billing.SBillingCycle) error { - return self.host.zone.region.RenewInstances([]string{self.InstanceId}, bc) -} - -func (region *SRegion) RenewInstances(instanceId []string, bc billing.SBillingCycle) error { - params := make(map[string]string) - for i := 0; i < len(instanceId); i += 1 { - params[fmt.Sprintf("InstanceIds.%d", i)] = instanceId[i] - } - params["InstanceChargePrepaid.Period"] = fmt.Sprintf("%d", bc.GetMonths()) - params["InstanceChargePrepaid.RenewFlag"] = "NOTIFY_AND_MANUAL_RENEW" - params["RenewPortableDataDisk"] = "TRUE" - _, err := region.cvmRequest("RenewInstances", params, true) - if err != nil { - log.Errorf("RenewInstance fail %s", err) - return err - } - return nil -} - -func (self *SInstance) GetProjectId() string { - return strconv.Itoa(self.Placement.ProjectId) -} - -func (self *SInstance) GetError() error { - return nil -} - -func (region *SRegion) ConvertPublicIpToEip(instanceId string) error { - params := map[string]string{ - "InstanceId": instanceId, - "Region": region.Region, - } - _, err := region.vpcRequest("TransformAddress", params) - if err != nil { - log.Errorf("TransformAddress fail %s", err) - return err - } - return nil -} - -func (self *SInstance) ConvertPublicIpToEip() error { - return self.host.zone.region.ConvertPublicIpToEip(self.InstanceId) -} - -func (self *SInstance) IsAutoRenew() bool { - return self.RenewFlag == "NOTIFY_AND_AUTO_RENEW" -} - -// https://cloud.tencent.com/document/api/213/15752 -func (region *SRegion) SetInstanceAutoRenew(instanceId string, autoRenew bool) error { - params := map[string]string{ - "InstanceIds.0": instanceId, - "Region": region.Region, - "RenewFlag": "NOTIFY_AND_MANUAL_RENEW", - } - if autoRenew { - params["RenewFlag"] = "NOTIFY_AND_AUTO_RENEW" - } - _, err := region.cvmRequest("ModifyInstancesRenewFlag", params, true) - return err -} - -func (self *SInstance) SetAutoRenew(bc billing.SBillingCycle) error { - return self.host.zone.region.SetInstanceAutoRenew(self.InstanceId, bc.AutoRenew) -} - -func (self *SInstance) SetTags(tags map[string]string, replace bool) error { - return self.host.zone.region.SetResourceTags("cvm", "instance", []string{self.InstanceId}, tags, replace) -} - -func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { - params := map[string]string{ - "ImageName": opts.Name, - "InstanceId": instanceId, - } - if len(opts.Notes) > 0 { - params["ImageDescription"] = opts.Notes - } - resp, err := self.cvmRequest("CreateImage", params, true) - if err != nil { - return nil, errors.Wrapf(err, "CreateImage") - } - ret := struct{ ImageId string }{} - err = resp.Unmarshal(&ret) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - imageIds := []string{} - if len(ret.ImageId) > 0 { - imageIds = append(imageIds, ret.ImageId) - } - - images, _, err := self.GetImages("", "PRIVATE_IMAGE", imageIds, opts.Name, 0, 1) - if err != nil { - return nil, errors.Wrapf(err, "GetImage(%s,%s)", opts.Name, ret.ImageId) - } - for i := range images { - if images[i].ImageId == ret.ImageId || images[i].ImageName == opts.Name { - images[i].storageCache = self.getStoragecache() - return &images[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "after save image %s", opts.Name) -} - -func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { - image, err := self.host.zone.region.SaveImage(self.InstanceId, opts) - if err != nil { - return nil, errors.Wrapf(err, "SaveImage") - } - return image, nil -} diff --git a/pkg/multicloud/qcloud/instancenic.go b/pkg/multicloud/qcloud/instancenic.go deleted file mode 100644 index b02ce23274..0000000000 --- a/pkg/multicloud/qcloud/instancenic.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - instance *SInstance - - id string - ipAddr string - macAddr string - classic bool - - cloudprovider.DummyICloudNic -} - -func (self *SInstanceNic) GetId() string { - return self.id -} - -func (self *SInstanceNic) GetIP() string { - return self.ipAddr -} - -func (self *SInstanceNic) GetMAC() string { - return self.macAddr -} - -func (self *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return self.classic -} - -func (self *SInstanceNic) GetINetworkId() string { - return self.instance.VirtualPrivateCloud.SubnetId -} diff --git a/pkg/multicloud/qcloud/kafka.go b/pkg/multicloud/qcloud/kafka.go deleted file mode 100644 index fe7f2e7951..0000000000 --- a/pkg/multicloud/qcloud/kafka.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SKafka struct { - multicloud.SVirtualResourceBase - multicloud.SBillingBase - multicloud.QcloudTags - region *SRegion - - InstanceId string - InstanceName string - Vip string - Vport string - VipList []struct { - Vip string - Vport string - } - Status int - Bandwidth int - DiskSize int - ZoneId int - VpcId string - SubnetId string - RenewFlag int - Healthy int - HealthyMessage string - CreateTime int - ExpireTime int - IsInternal int - TopicNum int - Version string - ZoneIds []int - Cvm int - InstanceType string - DiskType string - MaxTopicNumber int - MaxPartitionNubmer int - RebalanceTime string - MsgRetentionTime int -} - -func (self *SKafka) GetName() string { - if len(self.InstanceName) > 0 { - return self.InstanceName - } - return self.InstanceId -} - -func (self *SKafka) GetId() string { - return self.InstanceId -} - -func (self *SKafka) GetGlobalId() string { - return self.InstanceId -} - -func (self *SKafka) GetVpcId() string { - return self.VpcId -} - -func (self *SKafka) GetNetworkId() string { - return self.SubnetId -} - -func (self *SKafka) IsAutoRenew() bool { - return self.RenewFlag == 1 -} - -func (self *SKafka) GetBillingType() string { - return billing_api.BILLING_TYPE_PREPAID -} - -func (self *SKafka) GetCreatedAt() time.Time { - return time.Unix(int64(self.CreateTime), 0) -} - -func (self *SKafka) GetExpiredAt() time.Time { - return time.Unix(int64(self.ExpireTime), 0) -} - -func (self *SKafka) GetInstanceType() string { - return self.InstanceType -} - -func (self *SKafka) GetDiskSizeGb() int { - return self.DiskSize -} - -func (self *SKafka) GetVersion() string { - return self.Version -} - -func (self *SKafka) IsMultiAz() bool { - return len(self.ZoneIds) > 1 -} - -func (self *SKafka) GetBandwidthMb() int { - return self.Bandwidth / 8 -} - -func (self *SKafka) GetStorageType() string { - return self.DiskType -} - -func (self *SKafka) GetEndpoint() string { - endpoints := []string{} - var add = func(vip, vport string) { - endpoint := fmt.Sprintf("%s:%s", vip, vport) - if len(vip) > 0 && len(vport) > 0 && !utils.IsInStringArray(endpoint, endpoints) { - endpoints = append(endpoints, endpoint) - } - } - for _, ed := range self.VipList { - add(ed.Vip, ed.Vport) - } - add(self.Vip, self.Vport) - return strings.Join(endpoints, ",") -} - -func (self *SKafka) GetStatus() string { - switch self.Status { - case 0: - return api.KAFKA_STATUS_CREATING - case 1: - return api.KAFKA_STATUS_AVAILABLE - case 2: - return api.KAFKA_STATUS_DELETING - default: - return fmt.Sprintf("%d", self.Status) - } -} - -func (self *SKafka) GetMsgRetentionMinute() int { - if self.MsgRetentionTime == 0 { - self.Refresh() - } - return self.MsgRetentionTime -} - -func (self *SKafka) GetZoneId() string { - return fmt.Sprintf("%s-%d", self.region.Region, self.ZoneId) -} - -func (self *SKafka) Refresh() error { - kafka, err := self.region.GetKafka(self.InstanceId) - if err != nil { - return err - } - return jsonutils.Update(self, kafka) -} - -func (self *SKafka) Delete() error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetICloudKafkaById(id string) (cloudprovider.ICloudKafka, error) { - kafka, err := self.GetKafka(id) - if err != nil { - return nil, errors.Wrapf(err, "GetKafka(%s)", id) - } - return kafka, nil -} - -func (self *SRegion) GetICloudKafkas() ([]cloudprovider.ICloudKafka, error) { - kafkas := []SKafka{} - for { - part, total, err := self.GetKafkas("", 20, len(kafkas)) - if err != nil { - return nil, errors.Wrapf(err, "GetKafkas") - } - kafkas = append(kafkas, part...) - if len(kafkas) >= total { - break - } - } - ret := []cloudprovider.ICloudKafka{} - for i := range kafkas { - kafkas[i].region = self - ret = append(ret, &kafkas[i]) - } - return ret, nil -} - -func (self *SRegion) GetKafka(id string) (*SKafka, error) { - params := map[string]string{ - "InstanceId": id, - } - resp, err := self.kafkaRequest("DescribeInstanceAttributes", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeInstanceAttributes") - } - ret := SKafka{region: self} - err = resp.Unmarshal(&ret, "Result") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return &ret, nil -} - -func (self *SRegion) GetKafkas(id string, limit, offset int) ([]SKafka, int, error) { - if limit < 1 || limit > 20 { - limit = 20 - } - params := map[string]string{ - "Limit": fmt.Sprintf("%d", limit), - "Offset": fmt.Sprintf("%d", offset), - } - if len(id) > 0 { - params["InstanceId"] = id - } - resp, err := self.kafkaRequest("DescribeInstancesDetail", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeInstancesDetail") - } - ret := []SKafka{} - err = resp.Unmarshal(&ret, "Result", "InstanceList") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - totalCount, _ := resp.Int("Result", "TotalCount") - return ret, int(totalCount), nil -} diff --git a/pkg/multicloud/qcloud/keypair.go b/pkg/multicloud/qcloud/keypair.go deleted file mode 100644 index fa81811591..0000000000 --- a/pkg/multicloud/qcloud/keypair.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strconv" - "time" - - "github.com/aokoli/goutils" - "golang.org/x/crypto/ssh" - - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SKeypair struct { - AssociatedInstanceIds []string - CreateTime time.Time - Description string - KeyId string - KeyName string - PublicKey string -} - -func (self *SRegion) GetKeypairs(name string, keyIds []string, offset int, limit int) ([]SKeypair, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := map[string]string{} - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - - if len(keyIds) > 0 { - for i := 0; i < len(keyIds); i++ { - params[fmt.Sprintf("KeyIds.%d", i)] = keyIds[i] - } - } else { - if len(name) > 0 { - params["Filters.0.Name"] = "key-name" - params["Filters.0.Values.0"] = name - } - } - - body, err := self.cvmRequest("DescribeKeyPairs", params, true) - if err != nil { - log.Errorf("GetKeypairs fail %s", err) - return nil, 0, err - } - - keypairs := []SKeypair{} - err = body.Unmarshal(&keypairs, "KeyPairSet") - if err != nil { - log.Errorf("Unmarshal keypair fail %s", err) - return nil, 0, err - } - total, _ := body.Float("TotalCount") - return keypairs, int(total), nil -} - -func (self *SRegion) ImportKeypair(name string, pubKey string) (*SKeypair, error) { - params := map[string]string{} - params["PublicKey"] = pubKey - params["ProjectId"] = "0" - params["KeyName"] = name - - body, err := self.cvmRequest("ImportKeyPair", params, true) - if err != nil { - log.Errorf("ImportKeypair fail %s", err) - return nil, err - } - - keypairID, err := body.GetString("KeyId") - if err != nil { - return nil, err - } - keypairs, total, err := self.GetKeypairs("", []string{keypairID}, 0, 1) - if err != nil { - return nil, err - } - if total != 1 { - return nil, cloudprovider.ErrNotFound - } - return &keypairs[0], nil -} - -func (self *SRegion) AttachKeypair(instanceId string, keypairId string) error { - params := map[string]string{} - params["InstanceIds.0"] = instanceId - params["KeyIds.0"] = keypairId - _, err := self.cvmRequest("AssociateInstancesKeyPairs", params, true) - return err -} - -func (self *SRegion) DetachKeyPair(instanceId string, keypairId string) error { - params := make(map[string]string) - params["InstanceIds.0"] = instanceId - params["KeyIds.0"] = keypairId - _, err := self.cvmRequest("DisassociateInstancesKeyPairs", params, true) - return err -} - -func (self *SRegion) CreateKeyPair(name string) (*SKeypair, error) { - params := make(map[string]string) - params["KeyName"] = name - params["ProjectId"] = "0" - body, err := self.cvmRequest("CreateKeyPair", params, true) - keypair := SKeypair{} - err = body.Unmarshal(&keypair, "KeyPair") - if err != nil { - return nil, err - } - return &keypair, err -} - -func (self *SRegion) getKeypairs() ([]SKeypair, error) { - keypairs := []SKeypair{} - for { - parts, total, err := self.GetKeypairs("", []string{}, 0, 50) - if err != nil { - log.Errorf("Get keypairs fail %v", err) - return nil, err - } - keypairs = append(keypairs, parts...) - if len(keypairs) >= total { - break - } - } - return keypairs, nil -} - -func (self *SRegion) getFingerprint(publicKey string) (string, error) { - pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKey)) - if err != nil { - return "", fmt.Errorf("publicKey error %s", err) - } - return ssh.FingerprintLegacyMD5(pk), nil -} - -func (self *SRegion) lookUpQcloudKeypair(publicKey string) (string, error) { - keypairs, err := self.getKeypairs() - if err != nil { - return "", err - } - - localFiger, err := self.getFingerprint(publicKey) - if err != nil { - return "", err - } - - for i := 0; i < len(keypairs); i++ { - finger, err := self.getFingerprint(keypairs[i].PublicKey) - if err != nil { - continue - } - if finger == localFiger { - return keypairs[i].KeyId, nil - } - } - return "", cloudprovider.ErrNotFound -} - -func (self *SRegion) syncKeypair(publicKey string) (string, error) { - keypairId, err := self.lookUpQcloudKeypair(publicKey) - if err == nil { - return keypairId, nil - } - - prefix, e := goutils.RandomAlphabetic(6) - if e != nil { - return "", fmt.Errorf("publicKey error %s", e) - } - - name := prefix + strconv.FormatInt(time.Now().Unix(), 10) - keypair, err := self.ImportKeypair(name, publicKey) - if err != nil { - return "", err - } - return keypair.KeyId, nil -} diff --git a/pkg/multicloud/qcloud/kube_node_pools.go b/pkg/multicloud/qcloud/kube_node_pools.go deleted file mode 100644 index e8c36f1028..0000000000 --- a/pkg/multicloud/qcloud/kube_node_pools.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SKubeNodePool struct { - multicloud.SResourceBase - multicloud.QcloudTags - - cluster *SKubeCluster - - NodePoolId string - Name string - ClusterInstanceId string - LifeState string - LaunchConfigurationId string - AutoscalingGroupId string - Labels []struct { - Name string - Value string - } - Taints []struct { - Kye string - Value string - Effect string - } - NodeCountSummary struct { - ManuallyAdded struct { - Joining int - Initializing int - Normal int - Total int - } - AutoscalingAdded struct { - Joining int - Initializing int - Normal int - Total int - } - } - AutoscalingGroupStatus string - MaxNodesNum int - MinNodesNum int - DesiredNodesNum int - NodePoolOs string - OsCustomizeType string - ImageId string - DesiredPodNum int - UserScript string -} - -func (self *SKubeNodePool) GetId() string { - return self.NodePoolId -} - -func (self *SKubeNodePool) GetGlobalId() string { - return self.NodePoolId -} - -func (self *SKubeNodePool) GetName() string { - return self.Name -} - -func (self *SKubeNodePool) GetStatus() string { - return self.LifeState -} - -func (self *SKubeCluster) GetIKubeNodePools() ([]cloudprovider.ICloudKubeNodePool, error) { - pools, err := self.region.GetKubeNodePools(self.ClusterId) - if err != nil { - return nil, errors.Wrapf(err, "GetKubeNodePools") - } - ret := []cloudprovider.ICloudKubeNodePool{} - for i := range pools { - pools[i].cluster = self - ret = append(ret, &pools[i]) - } - return ret, nil -} - -func (self *SRegion) GetKubeNodePools(clusterId string) ([]SKubeNodePool, error) { - params := map[string]string{ - "ClusterId": clusterId, - } - resp, err := self.tkeRequest("DescribeClusterNodePools", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeClusterNodePools") - } - pools := []SKubeNodePool{} - err = resp.Unmarshal(&pools, "NodePoolSet") - if err != nil { - return nil, errors.Wrapf(err, "NodePoolSet") - } - return pools, nil -} diff --git a/pkg/multicloud/qcloud/kube_nodes.go b/pkg/multicloud/qcloud/kube_nodes.go deleted file mode 100644 index 0eb2a0f684..0000000000 --- a/pkg/multicloud/qcloud/kube_nodes.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SKubeNode struct { - multicloud.SResourceBase - multicloud.QcloudTags - - cluster *SKubeCluster - - InstanceId string - InstanceRole string - FailedReason string - InstanceState string - DrainStatus string - InstanceAdvancedSettings struct { - MountTarget string - DockerGraphPath string - UserScript string - Unschedulable int - DesiredPodNumber int - PreStartUserScript string - Labels []struct { - Name string - Value string - } - DataDisks []struct { - DiskType string - FileSystem string - DiskSize int - AutoFormatAndMount bool - MountTarget string - DiskPartition string - } - ExtraArgs struct { - Kubelet []string - } - } - CreatedTime string - LanIP string - NodePoolId string - AutoscalingGroupId string -} - -func (self *SKubeNode) GetId() string { - return self.InstanceId -} - -func (self *SKubeNode) GetGlobalId() string { - return self.InstanceId -} - -func (self *SKubeNode) GetName() string { - return self.InstanceId -} - -func (self *SKubeNode) GetStatus() string { - return self.DrainStatus -} - -func (self *SKubeNode) GetINodePoolId() string { - return self.NodePoolId -} - -func (self *SKubeCluster) GetIKubeNodes() ([]cloudprovider.ICloudKubeNode, error) { - nodes := []SKubeNode{} - for { - part, total, err := self.region.GetKubeNodes(self.ClusterId, 100, len(nodes)/100) - if err != nil { - return nil, errors.Wrapf(err, "GetIKubeNodes") - } - nodes = append(nodes, part...) - if len(nodes) >= total || len(part) == 0 { - break - } - } - ret := []cloudprovider.ICloudKubeNode{} - for i := range nodes { - nodes[i].cluster = self - ret = append(ret, &nodes[i]) - } - return ret, nil -} - -func (self *SRegion) GetKubeNodes(clusterId string, limit, offset int) ([]SKubeNode, int, error) { - if limit < 1 || limit > 100 { - limit = 100 - } - params := map[string]string{ - "Limit": fmt.Sprintf("%d", limit), - "Offset": fmt.Sprintf("%d", offset), - "ClusterId": clusterId, - } - resp, err := self.tkeRequest("DescribeClusterInstances", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeClusterInstances") - } - nodes := []SKubeNode{} - err = resp.Unmarshal(&nodes, "InstanceSet") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - totalCount, _ := resp.Float("TotalCount") - return nodes, int(totalCount), nil -} diff --git a/pkg/multicloud/qcloud/latitud_and_longitude.go b/pkg/multicloud/qcloud/latitud_and_longitude.go deleted file mode 100644 index 8d87548c7b..0000000000 --- a/pkg/multicloud/qcloud/latitud_and_longitude.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ - "ap-bangkok": api.RegionBangkok, // 腾讯云 亚太地区(曼谷) - "ap-beijing": api.RegionBeijing, // 腾讯云 华北地区(北京) - "ap-chengdu": api.RegionChengdu, // 腾讯云 西南地区(成都) - "ap-chongqing": api.RegionChongqing, // 腾讯云 西南地区(重庆) - "ap-guangzhou": api.RegionGuangzhou, // 腾讯云 华南地区(广州) - "ap-guangzhou-open": api.RegionGuangzhou, // 腾讯云 华南地区(广州Open) - "ap-hongkong": api.RegionHongkong, // 腾讯云 东南亚地区(香港) - "ap-mumbai": api.RegionMumbai, // 腾讯云 亚太地区(孟买) - "ap-seoul": api.RegionSeoul, // 腾讯云 东南亚地区(首尔) - "ap-shanghai": api.RegionShanghai, // 腾讯云 华东地区(上海) - "ap-shanghai-fsi": api.RegionShanghai, // 腾讯云 华东地区(上海金融) - "ap-shenzhen-fsi": api.RegionShenzhen, // 腾讯云 华南地区(深圳金融) - "ap-singapore": api.RegionSingapore, // 腾讯云 东南亚地区(新加坡) - "ap-tokyo": api.RegionTokyo, // 腾讯云 亚太地区(东京) - "eu-frankfurt": api.RegionFrankfurt, // 腾讯云 欧洲地区(德国) - "eu-moscow": api.RegionMoscow, // 腾讯云 欧洲地区(莫斯科) - "na-ashburn": api.RegionVirginia, // 腾讯云 美国东部(弗吉尼亚) - "na-siliconvalley": api.RegionSiliconValley, // 腾讯云 美国西部(硅谷) - "na-toronto": api.RegionToronto, // 腾讯云 北美地区(多伦多) - "ap-nanjing": api.RegionNanjing, -} diff --git a/pkg/multicloud/qcloud/loadbalancer.go b/pkg/multicloud/qcloud/loadbalancer.go deleted file mode 100644 index 6ea93a9faa..0000000000 --- a/pkg/multicloud/qcloud/loadbalancer.go +++ /dev/null @@ -1,715 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - LB_ADDR_TYPE_INTERNAL = "INTERNAL" - LB_ADDR_TYPE_OPEN = "OPEN" -) - -type LB_TYPE int64 - -const ( - LB_TYPE_CLASSIC = LB_TYPE(0) - LB_TYPE_APPLICATION = LB_TYPE(1) -) - -/* -todo: -1.统一LB 证书fingerprint算法.另外缺少一个回写指纹算法到数据库的方法。 -2.需要同步腾讯云LB 所在的project -*/ - -// https://cloud.tencent.com/document/api/214/30694#LoadBalancer -type SLoadbalancer struct { - multicloud.SLoadbalancerBase - multicloud.QcloudTags - region *SRegion - - Status int64 `json:"Status"` // 0:创建中,1:正常运行 - Domain string `json:"Domain"` - VpcID string `json:"VpcId"` - Log string `json:"Log"` - ProjectID int64 `json:"ProjectId"` - Snat bool `json:"Snat"` - LoadBalancerID string `json:"LoadBalancerId"` - LoadBalancerVips []string `json:"LoadBalancerVips"` - LoadBalancerType string `json:"LoadBalancerType"` // 负载均衡实例的网络类型: OPEN:公网属性, INTERNAL:内网属性。 - LoadBalancerName string `json:"LoadBalancerName"` - Forward LB_TYPE `json:"Forward"` // 应用型负载均衡标识,1:应用型负载均衡,0:传统型的负载均衡。 - StatusTime time.Time `json:"StatusTime"` - OpenBGP int64 `json:"OpenBgp"` // 高防 LB 的标识,1:高防负载均衡 0:非高防负载均衡。 - CreateTime time.Time `json:"CreateTime"` - Isolation int64 `json:"Isolation"` // 0:表示未被隔离,1:表示被隔离。 - SubnetId string `json:"SubnetId"` - BackupZoneSet []ZoneSet `json:"BackupZoneSet"` - MasterZone ZoneSet `json:"MasterZone"` - NetworkAttributes struct { - InternetChargeType string - InternetMaxBandwidthOut int - } -} - -type ZoneSet struct { - Zone string `json:"Zone"` - ZoneID int64 `json:"ZoneId"` - ZoneName string `json:"ZoneName"` -} - -func (self *SLoadbalancer) GetLoadbalancerSpec() string { - return "" -} - -func (self *SLoadbalancer) GetChargeType() string { - if len(self.NetworkAttributes.InternetChargeType) > 0 && self.NetworkAttributes.InternetChargeType != "TRAFFIC_POSTPAID_BY_HOUR" { - return api.LB_CHARGE_TYPE_BY_BANDWIDTH - } - return api.LB_CHARGE_TYPE_BY_TRAFFIC -} - -func (self *SLoadbalancer) GetEgressMbps() int { - return self.NetworkAttributes.InternetMaxBandwidthOut -} - -// https://cloud.tencent.com/document/product/214/30689 -func (self *SLoadbalancer) Delete(ctx context.Context) error { - lockman.LockRawObject(ctx, "qcloud.SLoadbalancer.Delete", self.region.client.ownerId) - defer lockman.ReleaseRawObject(ctx, "qcloud.SLoadbalancer.Delete", self.region.client.ownerId) - - if self.Forward == LB_TYPE_APPLICATION { - _, err := self.region.DeleteLoadbalancer(self.GetId()) - if err != nil { - return err - } - } else { - _, err := self.region.DeleteClassicLoadbalancer(self.GetId()) - if err != nil { - return err - } - } - - return cloudprovider.WaitDeleted(self, 5*time.Second, 60*time.Second) -} - -// 腾讯云loadbalance不支持启用/禁用 -func (self *SLoadbalancer) Start() error { - return nil -} - -func (self *SLoadbalancer) Stop() error { - return cloudprovider.ErrNotSupported -} - -// 腾讯云无后端服务器组 -// todo: 是否返回一个fake的后端服务器组 -func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - groups, err := self.GetILoadBalancerBackendGroups() - if err != nil { - return nil, err - } - - for _, group := range groups { - if group.GetId() == groupId { - return group, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func onecloudHealthCodeToQcloud(codes string) int { - qcode := 0 - for i, code := range HTTP_CODES { - if strings.Contains(codes, code) { - // 按位或然后再赋值qcode - qcode |= 1 << uint(i) - } - } - - return qcode -} - -// https://cloud.tencent.com/document/product/214/30693 -// todo: 1.限制比较多必须加参数校验 2.Onecloud 不支持双向证书可能存在兼容性问题 -// 应用型负载均衡 传统型不支持设置SNI -func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - lockman.LockRawObject(ctx, "qcloud.SLoadbalancer.CreateILoadBalancerListener", self.region.client.ownerId) - defer lockman.ReleaseRawObject(ctx, "qcloud.SLoadbalancer.CreateILoadBalancerListener", self.region.client.ownerId) - - sniSwitch := 0 - hc := getHealthCheck(listener) - cert := getCertificate(listener) - - var listenId string - var err error - if self.Forward == LB_TYPE_APPLICATION { - listenId, err = self.region.CreateLoadbalancerListener(self.GetId(), - listener.Name, - getProtocol(listener), - listener.ListenerPort, - getScheduler(listener), - &listener.StickySessionCookieTimeout, - &sniSwitch, - hc, - cert) - } else { - // 传统型内网属性负载均衡不支持指定scheduler - var scheduler *string - if self.LoadBalancerType == "OPEN" { - scheduler = getScheduler(listener) - } - - listenId, err = self.region.CreateClassicLoadbalancerListener(self.GetId(), - listener.Name, - getClassicLBProtocol(listener), - listener.ListenerPort, - listener.BackendServerPort, - scheduler, - &listener.StickySessionCookieTimeout, - &sniSwitch, - hc, - cert) - } - if err != nil { - return nil, err - } - - var lblis cloudprovider.ICloudLoadbalancerListener - err = cloudprovider.Wait(3*time.Second, 30*time.Second, func() (bool, error) { - lblis, err = self.GetILoadBalancerListenerById(listenId) - if err != nil { - if errors.Cause(err) != cloudprovider.ErrNotFound { - return false, err - } else { - return false, nil - } - } - - return true, nil - }) - if err != nil { - return nil, errors.Wrap(err, "GetILoadBalancerListenerById.Wait") - } - - return lblis, nil -} - -func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { - listeners, err := self.GetLoadbalancerListeners("") - if err != nil { - return nil, err - } - - for _, listener := range listeners { - if listener.GetId() == listenerId { - return &listener, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SLoadbalancer) GetId() string { - return self.LoadBalancerID -} - -func (self *SLoadbalancer) GetName() string { - return self.LoadBalancerName -} - -// add region? -func (self *SLoadbalancer) GetGlobalId() string { - return self.LoadBalancerID -} - -func (self *SLoadbalancer) GetStatus() string { - switch self.Status { - case 0: - return api.LB_STATUS_INIT - case 1: - return api.LB_STATUS_ENABLED - default: - return api.LB_STATUS_UNKNOWN - } -} - -func (self *SLoadbalancer) Refresh() error { - lb, err := self.region.GetLoadbalancer(self.GetId()) - if err != nil { - return err - } - - return jsonutils.Update(self, lb) -} - -func (self *SLoadbalancer) IsEmulated() bool { - return false -} - -func (self *SLoadbalancer) GetSysTags() map[string]string { - meta := map[string]string{} - meta["Forward"] = strconv.FormatInt(int64(self.Forward), 10) - meta["OpenBGP"] = strconv.FormatInt(self.OpenBGP, 10) - meta["Domain"] = self.Domain - meta["ProjectID"] = strconv.FormatInt(self.ProjectID, 10) - return meta -} - -// 腾讯云当前不支持一个LB绑定多个ip,每个LB只支持绑定一个ip -func (self *SLoadbalancer) GetAddress() string { - return self.LoadBalancerVips[0] -} - -func (self *SLoadbalancer) GetAddressType() string { - switch self.LoadBalancerType { - case LB_ADDR_TYPE_INTERNAL: - return api.LB_ADDR_TYPE_INTRANET - case LB_ADDR_TYPE_OPEN: - return api.LB_ADDR_TYPE_INTERNET - default: - return "" - } -} - -func (self *SLoadbalancer) GetNetworkType() string { - if len(self.VpcID) > 0 { - return api.LB_NETWORK_TYPE_VPC - } else { - return api.LB_NETWORK_TYPE_CLASSIC - } -} - -func (self *SLoadbalancer) GetNetworkIds() []string { - if len(self.SubnetId) == 0 { - return []string{} - } - - return []string{self.SubnetId} -} - -func (self *SLoadbalancer) GetVpcId() string { - return self.VpcID -} - -func (self *SLoadbalancer) GetZoneId() string { - zoneId := "" - if len(self.MasterZone.Zone) > 0 { - zoneId = self.MasterZone.Zone - } else if len(self.SubnetId) > 0 { - net, err := self.region.GetNetwork(self.SubnetId) - if err != nil { - log.Warningf("GetNetwork %s %s", self.SubnetId, err) - return "" - } - - zoneId = net.Zone - } - - if len(zoneId) > 0 { - z, err := self.region.getZoneById(zoneId) - if err != nil { - log.Warningf("getZoneById %s %s", zoneId, err) - return "" - } - - return z.GetGlobalId() - } - - return "" -} - -func (self *SLoadbalancer) GetZone1Id() string { - if self.BackupZoneSet == nil { - return "" - } - - if len(self.BackupZoneSet) > 0 { - z, err := self.region.getZoneById(self.BackupZoneSet[0].Zone) - if err != nil { - log.Warningf("getZoneById %s %s", self.BackupZoneSet[0].Zone, err) - return "" - } - - return z.GetGlobalId() - } - - return "" -} - -func (self *SLoadbalancer) GetLoadbalancerListeners(protocal string) ([]SLBListener, error) { - listeners, err := self.region.GetLoadbalancerListeners(self.GetId(), self.Forward, protocal) - if err != nil { - return nil, err - } - - for i := range listeners { - listeners[i].lb = self - } - - return listeners, nil -} - -func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - listeners, err := self.GetLoadbalancerListeners("") - if err != nil { - return nil, err - } - - ilisteners := make([]cloudprovider.ICloudLoadbalancerListener, len(listeners)) - for i := range listeners { - l := listeners[i] - ilisteners[i] = &l - } - - return ilisteners, nil -} - -func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - if self.Forward == LB_TYPE_CLASSIC { - bg := SLBBackendGroup{lb: self} - return []cloudprovider.ICloudLoadbalancerBackendGroup{&bg}, nil - } - - listeners, err := self.GetLoadbalancerListeners("") - if err != nil { - return nil, err - } - - bgs := []cloudprovider.ICloudLoadbalancerBackendGroup{} - for i := range listeners { - listener := listeners[i] - t := listener.GetListenerType() - if t == api.LB_LISTENER_TYPE_HTTP || t == api.LB_LISTENER_TYPE_HTTPS { - rules := listener.Rules - for i := range rules { - rule := rules[i] - rule.listener = &listener - bg := rule.GetBackendGroup() - bgs = append(bgs, bg) - } - } else { - bg := listener.GetBackendGroup() - bgs = append(bgs, bg) - } - } - - ibgs := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(bgs)) - for i := range bgs { - ibgs[i] = bgs[i] - } - - return ibgs, nil -} - -func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { - if self.LoadBalancerType == "OPEN" && len(self.LoadBalancerVips) > 0 { - return &SEipAddress{ - region: self.region, - AddressId: self.LoadBalancerID, - AddressIp: self.LoadBalancerVips[0], - AddressType: EIP_STATUS_BIND, - InstanceId: self.LoadBalancerID, - CreatedTime: self.CreateTime, - }, nil - } - return nil, nil -} - -func (self *SRegion) GetLoadbalancers(ids []string) ([]SLoadbalancer, error) { - params := map[string]string{} - for i, id := range ids { - params[fmt.Sprintf("LoadBalancerIds.%d", i)] = id - } - - offset := 0 - limit := 100 - lbs := make([]SLoadbalancer, 0) - for { - params["Limit"] = strconv.Itoa(limit) - params["Offset"] = strconv.Itoa(offset) - - resp, err := self.clbRequest("DescribeLoadBalancers", params) - if err != nil { - return nil, err - } - - parts := make([]SLoadbalancer, 0) - err = resp.Unmarshal(&parts, "LoadBalancerSet") - if err != nil { - return nil, err - } - - _total, err := resp.Float("TotalCount") - if err != nil { - return nil, err - } - - total := int(_total) - if err != nil { - return nil, err - } - - lbs = append(lbs, parts...) - offset += len(parts) - if offset >= total { - for i := range lbs { - lbs[i].region = self - } - - return lbs, err - } - } -} - -func (self *SRegion) GetLoadbalancer(id string) (*SLoadbalancer, error) { - if len(id) == 0 { - return nil, fmt.Errorf("GetILoadbalancer id should not empty") - } - - lbs, err := self.GetLoadbalancers([]string{id}) - if err != nil { - return nil, err - } - - switch len(lbs) { - case 0: - return nil, cloudprovider.ErrNotFound - case 1: - return &lbs[0], nil - default: - return nil, fmt.Errorf("GetILoadbalancer %s found %d", id, len(lbs)) - } -} - -/* -返回requstid 用于异步任务查询 -https://cloud.tencent.com/document/product/214/30689 -*/ -func (self *SRegion) DeleteLoadbalancer(lbid string) (string, error) { - if len(lbid) == 0 { - return "", fmt.Errorf("loadbalancer id should not be empty") - } - - params := map[string]string{"LoadBalancerIds.0": lbid} - resp, err := self.clbRequest("DeleteLoadBalancer", params) - if err != nil { - return "", err - } - - return resp.GetString("RequestId") -} - -/* -返回requstid 用于异步任务查询 -https://cloud.tencent.com/document/product/214/30689 -*/ -func (self *SRegion) DeleteClassicLoadbalancer(lbid string) (string, error) { - if len(lbid) == 0 { - return "", fmt.Errorf("loadbalancer id should not be empty") - } - - params := map[string]string{"loadBalancerIds.n": lbid} - resp, err := self.lbRequest("DeleteLoadBalancers", params) - if err != nil { - return "", err - } - - return resp.GetString("requestId") -} - -/* -https://cloud.tencent.com/document/product/214/30693 -SNI 特性是什么?? -*/ -func (self *SRegion) CreateLoadbalancerListener(lbid, name, protocol string, port int, scheduler *string, sessionExpireTime, sniSwitch *int, healthCheck *healthCheck, cert *certificate) (string, error) { - if len(lbid) == 0 { - return "", fmt.Errorf("loadbalancer id should not be empty") - } - - params := map[string]string{ - "LoadBalancerId": lbid, - "Ports.0": strconv.Itoa(port), - "Protocol": protocol, - } - - if len(name) > 0 { - params["ListenerNames.0"] = name - } - - if utils.IsInStringArray(protocol, []string{PROTOCOL_TCP, PROTOCOL_UDP, PROTOCOL_TCP_SSL}) { - params = healthCheckParams(LB_TYPE_APPLICATION, params, healthCheck, "HealthCheck.") - - if scheduler != nil && len(*scheduler) > 0 { - params["Scheduler"] = *scheduler - } - - if sessionExpireTime != nil { - params["SessionExpireTime"] = strconv.Itoa(*sessionExpireTime) - } - } else { - if protocol == PROTOCOL_HTTPS && sniSwitch != nil { - params["SniSwitch"] = strconv.Itoa(*sniSwitch) - } - } - - params = certificateParams(LB_TYPE_APPLICATION, params, cert, "Certificate.") - - resp, err := self.clbRequest("CreateListener", params) - if err != nil { - return "", err - } - - listeners, err := resp.GetArray("ListenerIds") - if err != nil { - return "", err - } - - if len(listeners) == 0 { - return "", fmt.Errorf("CreateLoadbalancerListener no listener id returned: %s", resp.String()) - } else if len(listeners) == 1 { - return listeners[0].GetString() - } else { - return "", fmt.Errorf("CreateLoadbalancerListener mutliple listener id returned: %s", resp.String()) - } -} - -// https://cloud.tencent.com/document/api/214/1255 -// 不支持sniSwitch -// todo: 待测试 -func (self *SRegion) CreateClassicLoadbalancerListener(lbid, name string, protocol, port, backendServerPort int, scheduler *string, sessionExpireTime, sniSwitch *int, healthCheck *healthCheck, cert *certificate) (string, error) { - if len(lbid) == 0 { - return "", fmt.Errorf("loadbalancer id should not be empty") - } - - // 负载均衡实例监听器协议类型 1:HTTP,2:TCP,3:UDP,4:HTTPS。 - // todo: 待测试 。 这里没有判断是否为公网负载均衡,可能存在问题.内网传统型负载均衡监听协议只支持TCP、UDP,并且不能指定调度算法 - params := map[string]string{ - "loadBalancerId": lbid, - "listeners.0.loadBalancerPort": strconv.Itoa(port), - "listeners.0.instancePort": strconv.Itoa(backendServerPort), - "listeners.0.protocol": strconv.Itoa(protocol), - } - - if len(name) > 0 { - params["listeners.0.listenerName"] = name - } - - if sessionExpireTime != nil { - params["listeners.0.sessionExpire"] = strconv.Itoa(*sessionExpireTime) - } - - if scheduler != nil && len(*scheduler) > 0 && (protocol == 2 || protocol == 3) { - params["listeners.0.scheduler"] = strings.ToLower(*scheduler) - } - - if scheduler != nil && len(*scheduler) > 0 && (protocol == 1 || protocol == 4) { - params["listeners.0.httpHash"] = strings.ToLower(*scheduler) - } - - params = healthCheckParams(LB_TYPE_CLASSIC, params, healthCheck, "listeners.0.") - params = certificateParams(LB_TYPE_CLASSIC, params, cert, "listeners.0.") - - resp, err := self.lbRequest("CreateLoadBalancerListeners", params) - if err != nil { - return "", err - } - - listeners, err := resp.GetArray("listenerIds") - if err != nil { - return "", err - } - - if len(listeners) == 0 { - return "", fmt.Errorf("CreateLoadbalancerListener no listener id returned: %s", resp.String()) - } else if len(listeners) == 1 { - return listeners[0].GetString() - } else { - return "", fmt.Errorf("CreateLoadbalancerListener mutliple listener id returned: %s", resp.String()) - } -} - -// https://cloud.tencent.com/document/product/214/30683 -// 任务的当前状态。 0:成功,1:失败,2:进行中 -func (self *SRegion) GetLBTaskStatus(requestId string) (string, error) { - if len(requestId) == 0 { - return "", fmt.Errorf("WaitTaskSuccess requestId should not be emtpy") - } - - params := map[string]string{"TaskId": requestId} - resp, err := self.clbRequest("DescribeTaskStatus", params) - if err != nil { - return "", err - } - - status, err := resp.Get("Status") - if err != nil { - log.Debugf("WaitTaskSuccess failed %s: %s", err, resp.String()) - return "", err - } - - _status, err := status.Float() - return fmt.Sprintf("%1.f", _status), err -} - -func (self *SRegion) WaitLBTaskSuccess(requestId string, interval time.Duration, timeout time.Duration) error { - startTime := time.Now() - for time.Now().Sub(startTime) < timeout { - status, err := self.GetLBTaskStatus(requestId) - if err != nil { - return err - } - if status == "0" { - return nil - } - - if status == "1" { - return fmt.Errorf("Task %s failed.", requestId) - } - - time.Sleep(interval) - } - - return cloudprovider.ErrTimeout -} - -func (self *SLoadbalancer) GetProjectId() string { - return strconv.Itoa(int(self.ProjectID)) -} - -func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { - return self.region.SetResourceTags("clb", "clb", []string{self.LoadBalancerID}, tags, replace) -} diff --git a/pkg/multicloud/qcloud/loadbalancer_acl.go b/pkg/multicloud/qcloud/loadbalancer_acl.go deleted file mode 100644 index ed8737dc05..0000000000 --- a/pkg/multicloud/qcloud/loadbalancer_acl.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// 腾讯云没有LB ACL -type SLBACL struct { - multicloud.SResourceBase - multicloud.QcloudTags -} - -func (self *SLBACL) GetAclListenerID() string { - return "" -} - -func (self *SLBACL) Sync(acl *cloudprovider.SLoadbalancerAccessControlList) error { - return nil -} - -func (self *SLBACL) Delete() error { - return nil -} - -func (self *SLBACL) GetId() string { - return "" -} - -func (self *SLBACL) GetName() string { - return "" -} - -func (self *SLBACL) GetGlobalId() string { - return "" -} - -func (self *SLBACL) GetStatus() string { - return api.LB_BOOL_OFF -} - -func (self *SLBACL) Refresh() error { - return nil -} - -func (self *SLBACL) IsEmulated() bool { - return false -} - -func (self *SLBACL) GetAclEntries() *jsonutils.JSONArray { - return nil -} - -func (self *SLBACL) GetProjectId() string { - return "" -} diff --git a/pkg/multicloud/qcloud/loadbalancer_backend.go b/pkg/multicloud/qcloud/loadbalancer_backend.go deleted file mode 100644 index 71e35b66fd..0000000000 --- a/pkg/multicloud/qcloud/loadbalancer_backend.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLBBackend struct { - multicloud.SResourceBase - multicloud.QcloudTags - group *SLBBackendGroup - - PublicIPAddresses []string `json:"PublicIpAddresses"` - Weight int `json:"Weight"` - InstanceID string `json:"InstanceId"` - InstanceName string `json:"InstanceName"` - PrivateIPAddresses []string `json:"PrivateIpAddresses"` - RegisteredTime string `json:"RegisteredTime"` - Type string `json:"Type"` - Port int `json:"Port"` -} - -// ========================================================== -type SListenerBackend struct { - Rules []rule `json:"Rules"` - Targets []SLBBackend `json:"Targets"` - Protocol string `json:"Protocol"` - ListenerID string `json:"ListenerId"` - Port int64 `json:"Port"` -} - -type rule struct { - URL string `json:"Url"` - Domain string `json:"Domain"` - LocationID string `json:"LocationId"` - Targets []SLBBackend `json:"Targets"` -} - -// ========================================================== - -// backend InstanceID + protocol +Port + ip + rip全局唯一 -func (self *SLBBackend) GetId() string { - return fmt.Sprintf("%s/%s-%d", self.group.GetId(), self.InstanceID, self.Port) -} - -func (self *SLBBackend) GetName() string { - return self.GetId() -} - -func (self *SLBBackend) GetGlobalId() string { - return self.GetId() -} - -func (self *SLBBackend) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLBBackend) Refresh() error { - backends, err := self.group.GetBackends() - if err != nil { - return err - } - - for _, backend := range backends { - if backend.GetId() == self.GetId() { - return jsonutils.Update(self, backend) - } - } - - return cloudprovider.ErrNotFound -} - -func (self *SLBBackend) IsEmulated() bool { - return false -} - -func (self *SLBBackend) GetWeight() int { - return self.Weight -} - -func (self *SLBBackend) GetPort() int { - return self.Port -} - -func (self *SLBBackend) GetBackendType() string { - return api.LB_BACKEND_GUEST -} - -func (self *SLBBackend) GetBackendRole() string { - return api.LB_BACKEND_ROLE_DEFAULT -} - -func (self *SLBBackend) GetBackendId() string { - return self.InstanceID -} - -func (self *SLBBackend) GetIpAddress() string { - return "" -} - -// 传统型: https://cloud.tencent.com/document/product/214/31790 -func (self *SRegion) getClassicBackends(lbId, listenerId string) ([]SLBBackend, error) { - params := map[string]string{"LoadBalancerId": lbId} - - resp, err := self.clbRequest("DescribeClassicalLBTargets", params) - if err != nil { - return nil, err - } - - backends := []SLBBackend{} - err = resp.Unmarshal(&backends, "Targets") - if err != nil { - return nil, err - } - return backends, nil -} - -// 应用型: https://cloud.tencent.com/document/product/214/30684 -func (self *SRegion) getBackends(lbId, listenerId, ruleId string) ([]SLBBackend, error) { - params := map[string]string{"LoadBalancerId": lbId} - - if len(listenerId) > 0 { - params["ListenerIds.0"] = listenerId - } - - resp, err := self.clbRequest("DescribeTargets", params) - if err != nil { - return nil, err - } - - lbackends := []SListenerBackend{} - err = resp.Unmarshal(&lbackends, "Listeners") - if err != nil { - return nil, err - } - - for _, entry := range lbackends { - if (entry.Protocol == "HTTP" || entry.Protocol == "HTTPS") && len(ruleId) == 0 { - return nil, fmt.Errorf("GetBackends for http/https listener %s must specific rule id", listenerId) - } - - if len(ruleId) > 0 { - for _, r := range entry.Rules { - if r.LocationID == ruleId { - return r.Targets, nil - } - } - } else { - return entry.Targets, nil - } - } - - // todo: 这里是返回空列表还是404? - return []SLBBackend{}, nil -} - -// 注意http、https监听器必须指定ruleId -func (self *SRegion) GetLBBackends(t LB_TYPE, lbId, listenerId, ruleId string) ([]SLBBackend, error) { - if len(lbId) == 0 { - return nil, fmt.Errorf("GetLBBackends loadbalancer id should not be empty") - } - - if t == LB_TYPE_APPLICATION { - return self.getBackends(lbId, listenerId, ruleId) - } else if t == LB_TYPE_CLASSIC { - return self.getClassicBackends(lbId, listenerId) - } else { - return nil, fmt.Errorf("GetLBBackends unsupported loadbalancer type %d", t) - } -} - -func (self *SLBBackend) GetProjectId() string { - return self.group.GetProjectId() -} - -func (self *SLBBackend) SyncConf(ctx context.Context, port, weight int) error { - lockman.LockRawObject(ctx, "qcloud.SLBBackend.SyncConf", self.group.lb.region.client.ownerId) - defer lockman.ReleaseRawObject(ctx, "qcloud.SLBBackend.SyncConf", self.group.lb.region.client.ownerId) - - err := self.group.UpdateBackendServer(self.InstanceID, self.Weight, self.Port, weight, port) - if err != nil { - return err - } - - self.Port = port - self.Weight = weight - return nil -} diff --git a/pkg/multicloud/qcloud/loadbalancer_backendgroup.go b/pkg/multicloud/qcloud/loadbalancer_backendgroup.go deleted file mode 100644 index 6c6343de7f..0000000000 --- a/pkg/multicloud/qcloud/loadbalancer_backendgroup.go +++ /dev/null @@ -1,422 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLBBackendGroup struct { - multicloud.SResourceBase - multicloud.QcloudTags - lb *SLoadbalancer // 必须不能为nil - listener *SLBListener // 可能为nil - rule *SLBListenerRule // tcp、udp、tcp_ssl监听rule 为nil -} - -func (self *SLBBackendGroup) GetLoadbalancerId() string { - return self.lb.GetId() -} - -func (self *SLBBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { - return self.lb -} - -func (self *SLBBackendGroup) GetProtocolType() string { - return "" -} - -func (self *SLBBackendGroup) GetScheduler() string { - return "" -} - -func (self *SLBBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { - return nil, nil -} - -func (self *SLBBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { - return nil, nil -} - -func (self *SLBBackendGroup) GetListenerId() string { - if self.listener != nil { - return self.listener.GetId() - } - - return "" -} - -// 返回requestid -func (self *SLBBackendGroup) appLBBackendServer(action string, serverId string, weight int, port int) (string, error) { - if len(serverId) == 0 { - return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") - } - - params := map[string]string{ - "LoadBalancerId": self.lb.GetId(), - "ListenerId": self.GetListenerId(), - "Targets.0.InstanceId": serverId, - "Targets.0.Port": strconv.Itoa(port), - "Targets.0.Weight": strconv.Itoa(weight), - } - - if self.rule != nil { - params["LocationId"] = self.rule.GetId() - } - - resp, err := self.lb.region.clbRequest(action, params) - if err != nil { - return "", err - } - - return resp.GetString("RequestId") -} - -// deprecated -func (self *SLBBackendGroup) appLBSeventhBackendServer(action string, serverId string, weight int, port int) (string, error) { - if len(serverId) == 0 { - return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") - } - - params := map[string]string{ - "loadBalancerId": self.lb.GetId(), - "listenerId": self.GetListenerId(), - "backends.0.InstanceId": serverId, - "backends.0.Port": strconv.Itoa(port), - "backends.0.Weight": strconv.Itoa(weight), - } - - if self.rule != nil { - params["LocationId"] = self.rule.GetId() - } - - resp, err := self.lb.region.clbRequest(action, params) - if err != nil { - return "", err - } - - return resp.GetString("RequestId") -} - -// https://cloud.tencent.com/document/product/214/30677 -func (self *SLBBackendGroup) updateBackendServerWeight(action string, serverId string, weight int, port int) (string, error) { - if len(serverId) == 0 { - return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") - } - - params := map[string]string{ - "LoadBalancerId": self.lb.GetId(), - "ListenerId": self.GetListenerId(), - "Targets.0.InstanceId": serverId, - "Targets.0.Port": strconv.Itoa(port), - "Targets.0.Weight": strconv.Itoa(weight), - } - - if self.rule != nil { - params["LocationId"] = self.rule.GetId() - } - - resp, err := self.lb.region.clbRequest(action, params) - if err != nil { - return "", err - } - - return resp.GetString("RequestId") -} - -// https://cloud.tencent.com/document/product/214/30678 -func (self *SLBBackendGroup) updateBackendServerPort(action string, serverId string, oldPort int, newPort int) (string, error) { - if len(serverId) == 0 { - return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") - } - - params := map[string]string{ - "LoadBalancerId": self.lb.GetId(), - "ListenerId": self.GetListenerId(), - "Targets.0.InstanceId": serverId, - "Targets.0.Port": strconv.Itoa(oldPort), - "NewPort": strconv.Itoa(newPort), - } - - if self.rule != nil { - params["LocationId"] = self.rule.GetId() - } - - resp, err := self.lb.region.clbRequest(action, params) - if err != nil { - return "", err - } - - return resp.GetString("RequestId") -} - -// 返回requestid -// https://cloud.tencent.com/document/api/214/1264 -func (self *SLBBackendGroup) classicLBBackendServer(action string, serverId string, weight int, port int) (string, error) { - // 传统型负载均衡忽略了port参数 - params := map[string]string{ - "LoadBalancerId": self.lb.GetId(), - "Targets.0.InstanceId": serverId, - "Targets.0.Weight": strconv.Itoa(weight), - } - - resp, err := self.lb.region.clbRequest(action, params) - if err != nil { - return "", err - } - - return resp.GetString("RequestId") -} - -// https://cloud.tencent.com/document/product/214/30676 -// https://cloud.tencent.com/document/product/214/31789 -func (self *SLBBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { - var requestId string - var err error - if self.lb.Forward == LB_TYPE_APPLICATION { - requestId, err = self.appLBBackendServer("RegisterTargets", serverId, weight, port) - } else { - requestId, err = self.classicLBBackendServer("RegisterTargetsWithClassicalLB", serverId, weight, port) - } - - if err != nil { - return nil, err - } - - err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) - if err != nil { - return nil, err - } - - err = self.Refresh() - if err != nil { - return nil, err - } - - backends, err := self.GetBackends() - if err != nil { - return nil, err - } - - for _, backend := range backends { - if strings.HasSuffix(backend.GetId(), fmt.Sprintf("%s-%d", serverId, port)) { - return &backend, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -// https://cloud.tencent.com/document/product/214/30687 -// https://cloud.tencent.com/document/product/214/31794 -func (self *SLBBackendGroup) RemoveBackendServer(serverId string, weight int, port int) error { - _, err := self.lb.region.GetInstance(serverId) - if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { - return nil - } - - var requestId string - if self.lb.Forward == LB_TYPE_APPLICATION { - requestId, err = self.appLBBackendServer("DeregisterTargets", serverId, weight, port) - } else { - requestId, err = self.classicLBBackendServer("DeregisterTargetsFromClassicalLB", serverId, weight, port) - } - - if err != nil { - if strings.Contains(err.Error(), "not registered") { - return nil - } - return err - } - - return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) -} - -func (self *SLBBackendGroup) UpdateBackendServer(serverId string, oldWeight, oldPort, weight, newPort int) error { - var requestId string - var err error - // if self.lb.Forward == LB_TYPE_APPLICATION { - // // https://cloud.tencent.com/document/product/214/30678 - // // https://cloud.tencent.com/document/product/214/30677 - // if self.listener.Protocol == api.LB_LISTENER_TYPE_HTTPS || self.listener.Protocol == api.LB_LISTENER_TYPE_HTTP { - // requestId, err = self.appLBSeventhBackendServer("ModifyForwardSeventhBackends", serverId, weight, port) - // } else { - // requestId, err = self.appLBBackendServer("ModifyForwardFourthBackendsWeight", serverId, weight, port) - // } - // } else { - // requestId, err = self.classicLBBackendServer("ModifyLoadBalancerBackends", serverId, weight, port) - // } - if oldWeight != weight { - requestId, err = self.updateBackendServerWeight("ModifyTargetWeight", serverId, weight, oldPort) - if err != nil { - if strings.Contains(err.Error(), "not registered") { - return nil - } - return errors.Wrap(err, "LBBackendGroup.updateBackendServerWeight") - } - - err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) - if err != nil { - return errors.Wrap(err, "LBBackendGroup.updateBackendServerWeight.WaitLBTaskSuccess") - } - } - - if oldPort != newPort { - requestId, err = self.updateBackendServerPort("ModifyTargetPort", serverId, oldPort, newPort) - if err != nil { - if strings.Contains(err.Error(), "not registered") { - return nil - } - return errors.Wrap(err, "LBBackendGroup.updateBackendServerPort") - } - - err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) - if err != nil { - return errors.Wrap(err, "LBBackendGroup.updateBackendServerPort.WaitLBTaskSuccess") - } - } - - return nil -} - -// 腾讯云无后端服务器组。 -func (self *SLBBackendGroup) Delete(ctx context.Context) error { - return fmt.Errorf("Please remove related listener/rule frist") -} - -// 腾讯云无后端服务器组 -func (self *SLBBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { - return nil -} - -func backendGroupIdGen(lbid string, secondId string) string { - if len(secondId) > 0 { - return fmt.Sprintf("%s", secondId) - } else { - return lbid - } -} - -func (self *SLBBackendGroup) GetId() string { - t := "" - if self.listener != nil { - t = self.listener.GetListenerType() - } - - if t == api.LB_LISTENER_TYPE_HTTP || t == api.LB_LISTENER_TYPE_HTTPS { - // http https 后端服务器只与规则绑定 - return backendGroupIdGen(self.lb.GetId(), self.rule.GetId()) - } else if self.lb.Forward == LB_TYPE_APPLICATION { - return backendGroupIdGen(self.lb.GetId(), self.GetListenerId()) - } else { - // 传统型lb 所有监听共用一个后端服务器组 - return backendGroupIdGen(self.lb.GetId(), "") - } -} - -func (self *SLBBackendGroup) GetName() string { - return self.GetId() -} - -func (self *SLBBackendGroup) GetGlobalId() string { - return self.GetId() -} - -func (self *SLBBackendGroup) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLBBackendGroup) Refresh() error { - return nil -} - -// note: model没有更新这个字段? -func (self *SLBBackendGroup) IsEmulated() bool { - return true -} - -func (self *SLBBackendGroup) IsDefault() bool { - return false -} - -func (self *SLBBackendGroup) GetType() string { - return api.LB_BACKENDGROUP_TYPE_NORMAL -} - -func (self *SLBBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := self.GetBackends() - if err != nil { - return nil, err - } - - ibackends := make([]cloudprovider.ICloudLoadbalancerBackend, len(backends)) - for i := range backends { - backends[i].group = self - ibackends[i] = &backends[i] - } - - return ibackends, nil -} - -func (self *SLBBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { - backends, err := self.GetILoadbalancerBackends() - if err != nil { - return nil, err - } - for i := 0; i < len(backends); i++ { - if backends[i].GetGlobalId() == backendId { - return backends[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SLBBackendGroup) GetBackends() ([]SLBBackend, error) { - backends := []SLBBackend{} - var err error - if self.rule != nil { - // http、https监听 - backends, err = self.lb.region.GetLBBackends(self.lb.Forward, self.lb.GetId(), self.GetListenerId(), self.rule.GetId()) - if err != nil { - return nil, err - } - } else { - // tcp,udp,tcp_ssl监听 - backends, err = self.lb.region.GetLBBackends(self.lb.Forward, self.lb.GetId(), self.GetListenerId(), "") - if err != nil { - return nil, err - } - } - - for i := range backends { - backends[i].group = self - } - - return backends, nil -} - -func (self *SLBBackendGroup) GetProjectId() string { - return self.lb.GetProjectId() -} diff --git a/pkg/multicloud/qcloud/loadbalancer_listener.go b/pkg/multicloud/qcloud/loadbalancer_listener.go deleted file mode 100644 index 19e9ed3791..0000000000 --- a/pkg/multicloud/qcloud/loadbalancer_listener.go +++ /dev/null @@ -1,884 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -var HTTP_CODES = []string{ - api.LB_HEALTH_CHECK_HTTP_CODE_1xx, - api.LB_HEALTH_CHECK_HTTP_CODE_2xx, - api.LB_HEALTH_CHECK_HTTP_CODE_3xx, - api.LB_HEALTH_CHECK_HTTP_CODE_4xx, - api.LB_HEALTH_CHECK_HTTP_CODE_5xx, -} - -const ( - PROTOCOL_TCP = "TCP" - PROTOCOL_UDP = "UDP" - PROTOCOL_TCP_SSL = "TCP_SSL" - PROTOCOL_HTTP = "HTTP" - PROTOCOL_HTTPS = "HTTPS" -) - -type certificate struct { - SSLMode string `json:"SSLMode"` - CERTCAID string `json:"CertCaId"` - CERTID string `json:"CertId"` -} - -/* -健康检查状态码(仅适用于HTTP/HTTPS转发规则)。可选值:1~31,默认 31。 -1 表示探测后返回值 1xx 表示健康,2 表示返回 2xx 表示健康,4 表示返回 3xx 表示健康,8 表示返回 4xx 表示健康,16 表示返回 5xx 表示健康。 -若希望多种码都表示健康,则将相应的值相加。 -*/ -type healthCheck struct { - HTTPCheckDomain string `json:"HttpCheckDomain"` - HealthSwitch int `json:"HealthSwitch"` - HTTPCheckPath string `json:"HttpCheckPath"` - HTTPCheckMethod string `json:"HttpCheckMethod"` - UnHealthNum int `json:"UnHealthNum"` - IntervalTime int `json:"IntervalTime"` - HTTPCode int `json:"HttpCode"` // 健康检查状态码(仅适用于HTTP/HTTPS转发规则)。可选值:1~31,默认 31。 - HealthNum int `json:"HealthNum"` - TimeOut int `json:"TimeOut"` -} - -type SLBListener struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.QcloudTags - lb *SLoadbalancer - - Protocol string `json:"Protocol"` // 监听器协议类型,取值 TCP | UDP | HTTP | HTTPS | TCP_SSL - Certificate certificate `json:"Certificate"` - SniSwitch int64 `json:"SniSwitch"` // 是否开启SNI特性(本参数仅对于HTTPS监听器有意义) - HealthCheck healthCheck `json:"HealthCheck"` // 仅适用于TCP/UDP/TCP_SSL监听器 - ListenerID string `json:"ListenerId"` - ListenerName string `json:"ListenerName"` - Rules []SLBListenerRule `json:"Rules"` // 监听器下的全部转发规则(本参数仅对于HTTP/HTTPS监听器有意义) - Scheduler string `json:"Scheduler"` - SessionExpireTime int `json:"SessionExpireTime"` // 会话保持时间,单位:秒。可选值:30~3600,默认 0,表示不开启。此参数仅适用于TCP/UDP监听器。 - Port int `json:"Port"` - ClassicListener bool // 这个字段是在qcloud返回字段基础上,额外增加的字段。用于区分listener 是否是classic。 -} - -// 腾讯云后端端口不是与listener绑定的 -func (self *SLBListener) GetBackendServerPort() int { - return 0 -} - -// https://cloud.tencent.com/document/product/214/30691 -func (self *SLBListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - hc := getListenerRuleHealthCheck(rule) - requestId, err := self.lb.region.CreateLoadbalancerListenerRule(self.lb.GetId(), - self.GetId(), - rule.Domain, - rule.Path, - rule.Scheduler, - rule.StickySessionCookieTimeout, - hc) - if err != nil { - return nil, err - } - - err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) - if err != nil { - return nil, err - } - - err = self.Refresh() - if err != nil { - return nil, err - } - - for _, r := range self.Rules { - if r.GetPath() == rule.Path { - r.listener = self - return &r, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SLBListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { - rules, err := self.GetILoadbalancerListenerRules() - if err != nil { - return nil, err - } - - for _, rule := range rules { - if rule.GetId() == ruleId { - return rule, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SLBListener) Start() error { - return nil -} - -func (self *SLBListener) Stop() error { - return cloudprovider.ErrNotSupported -} - -// https://cloud.tencent.com/document/product/214/30677 -func (self *SLBListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { - lockman.LockRawObject(ctx, "qcloud.SLBListener.Sync", self.lb.region.client.ownerId) - defer lockman.ReleaseRawObject(ctx, "qcloud.SLBListener.Sync", self.lb.region.client.ownerId) - - hc := getHealthCheck(listener) - cert := getCertificate(listener) - requestId, err := self.lb.region.UpdateLoadbalancerListener( - self.lb.Forward, - self.lb.GetId(), - self.GetId(), - &listener.Name, - getScheduler(listener), - &listener.StickySessionCookieTimeout, - hc, - cert) - if err != nil { - return err - } - - return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) -} - -func (self *SLBListener) Delete(ctx context.Context) error { - lockman.LockRawObject(ctx, "qcloud.SLBListener.Delete", self.lb.region.client.ownerId) - defer lockman.ReleaseRawObject(ctx, "qcloud.SLBListener.Delete", self.lb.region.client.ownerId) - - requestId, err := self.lb.region.DeleteLoadbalancerListener(self.lb.Forward, self.lb.GetId(), self.GetId()) - if err != nil { - return err - } - - return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) -} - -// https://cloud.tencent.com/document/api/214/30694#ClassicalListener -type SLBClassicListener struct { - InstancePort int64 `json:"InstancePort"` - CERTCAID string `json:"CertCaId"` - Status int64 `json:"Status"` - CERTID string `json:"CertId"` - Protocol string `json:"Protocol"` - TimeOut int `json:"TimeOut"` - HTTPHash string `json:"HttpHash"` // 公网固定IP型的 HTTP、HTTPS 协议监听器的轮询方法。wrr 表示按权重轮询,ip_hash 表示根据访问的源 IP 进行一致性哈希方式来分发 - UnhealthNum int `json:"UnhealthNum"` - IntervalTime int `json:"IntervalTime"` - ListenerID string `json:"ListenerId"` - ListenerPort int `json:"ListenerPort"` - HTTPCheckPath string `json:"HttpCheckPath"` - HealthNum int `json:"HealthNum"` - ListenerName string `json:"ListenerName"` - HealthSwitch int `json:"HealthSwitch"` - SSLMode string `json:"SSLMode"` - SessionExpire int `json:"SessionExpire"` - HTTPCode int `json:"HttpCode"` -} - -func (self *SLBClassicListener) ToLBListener() SLBListener { - // 转换之后丢弃了 InstancePort、Status、HttpHash - return SLBListener{ - Protocol: self.Protocol, - Certificate: certificate{ - SSLMode: self.SSLMode, - CERTCAID: self.CERTCAID, - CERTID: self.CERTID, - }, - HealthCheck: healthCheck{ - HTTPCheckDomain: "", - HealthSwitch: self.HealthSwitch, - HTTPCheckPath: self.HTTPCheckPath, - HTTPCheckMethod: "", - UnHealthNum: self.UnhealthNum, - IntervalTime: self.IntervalTime, - HTTPCode: self.HTTPCode, - HealthNum: self.HealthNum, - TimeOut: self.TimeOut, - }, - ListenerID: self.ListenerID, - ListenerName: self.ListenerName, - Rules: nil, - Scheduler: self.HTTPHash, - SessionExpireTime: self.SessionExpire, - Port: self.ListenerPort, - ClassicListener: true, - } -} - -func (self *SLBListener) GetId() string { - return self.ListenerID -} - -func (self *SLBListener) GetName() string { - return self.ListenerName -} - -func (self *SLBListener) GetGlobalId() string { - return self.ListenerID -} - -// 腾讯云负载均衡没有启用禁用操作 -func (self *SLBListener) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLBListener) Refresh() error { - listeners, err := self.lb.region.GetLoadbalancerListeners(self.lb.GetId(), self.lb.Forward, "") - if err != nil { - return err - } - - for _, listener := range listeners { - if listener.GetId() == self.GetId() { - listener.lb = self.lb - err := jsonutils.Update(self, listener) - if err != nil { - return err - } - - return nil - } - } - - return cloudprovider.ErrNotFound -} - -func (self *SLBListener) IsEmulated() bool { - return false -} - -func (self *SLBListener) GetEgressMbps() int { - return 0 -} - -func (self *SLBListener) GetListenerType() string { - switch self.Protocol { - case PROTOCOL_TCP: - return api.LB_LISTENER_TYPE_TCP - case PROTOCOL_UDP: - return api.LB_LISTENER_TYPE_UDP - case PROTOCOL_HTTP: - return api.LB_LISTENER_TYPE_HTTP - case PROTOCOL_HTTPS: - return api.LB_LISTENER_TYPE_HTTPS - case PROTOCOL_TCP_SSL: - return api.LB_LISTENER_TYPE_TCP - default: - return "" - } -} - -func (self *SLBListener) GetListenerPort() int { - return self.Port -} - -func (self *SLBListener) GetScheduler() string { - switch strings.ToLower(self.Scheduler) { - case "wrr": - return api.LB_SCHEDULER_WRR - case "ip_hash": - return api.LB_SCHEDULER_SCH - case "least_conn": - return api.LB_SCHEDULER_WLC - default: - return "" - } -} - -func (self *SLBListener) GetAclStatus() string { - return api.LB_BOOL_OFF -} - -func (self *SLBListener) GetAclType() string { - return "" -} - -func (self *SLBListener) GetAclId() string { - return "" -} - -func (self *SLBListener) GetHealthCheck() string { - if self.HealthCheck.HealthSwitch == 0 { - return api.LB_BOOL_OFF - } else { - return api.LB_BOOL_ON - } -} - -func (self *SLBListener) GetHealthCheckType() string { - if len(self.HealthCheck.HTTPCheckMethod) > 0 { - return api.LB_HEALTH_CHECK_HTTP - } else { - return api.LB_HEALTH_CHECK_TCP - } -} - -func (self *SLBListener) GetHealthCheckTimeout() int { - return self.HealthCheck.TimeOut -} - -func (self *SLBListener) GetHealthCheckInterval() int { - return self.HealthCheck.IntervalTime -} - -func (self *SLBListener) GetHealthCheckRise() int { - return self.HealthCheck.HealthNum -} - -func (self *SLBListener) GetHealthCheckFail() int { - return self.HealthCheck.UnHealthNum -} - -func (self *SLBListener) GetHealthCheckReq() string { - return "" -} - -func (self *SLBListener) GetHealthCheckExp() string { - return "" -} - -func (self *SLBListener) GetBackendGroup() *SLBBackendGroup { - t := self.GetListenerType() - // http、https类型的监听不能直接绑定服务器 - if t == api.LB_LISTENER_TYPE_HTTP || t == api.LB_LISTENER_TYPE_HTTPS { - return nil - } else { - return &SLBBackendGroup{lb: self.lb, listener: self} - } -} - -func (self *SLBListener) GetBackendGroupId() string { - bg := self.GetBackendGroup() - if bg == nil { - return "" - } - - return bg.GetId() -} - -func (self *SLBListener) GetHealthCheckDomain() string { - return self.HealthCheck.HTTPCheckDomain -} - -func (self *SLBListener) GetHealthCheckURI() string { - return self.HealthCheck.HTTPCheckPath -} - -func (self *SLBListener) GetHealthCheckCode() string { - codes := []string{} - for i := uint8(0); i < 5; i++ { - n := 1 << i - if (self.HealthCheck.HTTPCode & n) == n { - codes = append(codes, HTTP_CODES[i]) - } - } - - return strings.Join(codes, ",") -} - -// 仅http、https类型监听包含rules -func (self *SLBListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { - rules := self.Rules - iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} - for i := 0; i < len(rules); i++ { - rules[i].listener = self - iRules = append(iRules, &rules[i]) - } - return iRules, nil -} - -func (self *SLBListener) GetStickySession() string { - if self.SessionExpireTime == 0 { - return api.LB_BOOL_OFF - } else { - return api.LB_BOOL_ON - } -} - -// 支持基于 cookie 插入的会话保持能力 https://cloud.tencent.com/document/product/214/6154 -func (self *SLBListener) GetStickySessionType() string { - return api.LB_STICKY_SESSION_TYPE_INSERT -} - -// https://cloud.tencent.com/document/product/214/2736 -// 经测试应用型负载均衡返回都是 tgw_l7_route。 -func (self *SLBListener) GetStickySessionCookie() string { - if self.GetListenerType() == api.LB_LISTENER_TYPE_HTTPS { - return "tgw_l7_route" - } - - return "" -} - -func (self *SLBListener) GetStickySessionCookieTimeout() int { - return self.SessionExpireTime -} - -/* -7层负载均衡系统提供 X-Forwarded-For 的方式获取访问者真实 IP,LB 侧默认开启 - -https://cloud.tencent.com/document/product/214/6151 -七层转发获取来访真实IP的方法 https://cloud.tencent.com/document/product/214/3728 -*/ -func (self *SLBListener) XForwardedForEnabled() bool { - switch self.GetListenerType() { - case api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS: - return true - default: - return false - } -} - -// HTTP/HTTPS协议默认支持用户开启gzip压缩功能 -// 负载均衡开启Gzip配置及检测方法说明 https://cloud.tencent.com/document/product/214/5404 -func (self *SLBListener) GzipEnabled() bool { - switch self.GetListenerType() { - case api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS: - return true - default: - return false - } -} - -func (self *SLBListener) GetCertificateId() string { - return self.Certificate.CERTID -} - -// https://cloud.tencent.com/document/product/214/5412#2.-https.E6.94.AF.E6.8C.81.E5.93.AA.E4.BA.9B.E7.89.88.E6.9C.AC.E7.9A.84ssl.2Ftls.E5.AE.89.E5.85.A8.E5.8D.8F.E8.AE.AE.EF.BC.9F -func (self *SLBListener) GetTLSCipherPolicy() string { - return "" -} - -// 负载均衡能力说明 https://cloud.tencent.com/document/product/214/6534 -func (self *SLBListener) HTTP2Enabled() bool { - return true -} - -func (self *SRegion) GetLoadbalancerListeners(lbid string, t LB_TYPE, protocol string) ([]SLBListener, error) { - params := map[string]string{"LoadBalancerId": lbid} - if len(protocol) > 0 { - params["Protocol"] = protocol - } - - listeners := []SLBListener{} - if t == LB_TYPE_CLASSIC { - resp, err := self.clbRequest("DescribeClassicalLBListeners", params) - if err != nil { - return nil, err - } - - clisteners := []SLBClassicListener{} - err = resp.Unmarshal(&clisteners, "Listeners") - if err != nil { - return nil, err - } - - for _, l := range clisteners { - listeners = append(listeners, l.ToLBListener()) - } - - return listeners, nil - } - - resp, err := self.clbRequest("DescribeListeners", params) - if err != nil { - return nil, err - } - - err = resp.Unmarshal(&listeners, "Listeners") - if err != nil { - return nil, err - } - - return listeners, nil -} - -// 返回requestID -func (self *SRegion) CreateLoadbalancerListenerRule(lbid string, listenerId string, domain string, url string, scheduler string, sessionExpireTime int, hc *healthCheck) (string, error) { - if len(lbid) == 0 { - return "", fmt.Errorf("loadbalancer id should not be empty") - } - - params := map[string]string{ - "LoadBalancerId": lbid, - "ListenerId": listenerId, - "Rules.0.Domain": domain, - "Rules.0.Url": url, - } - - params["Rules.0.Scheduler"] = scheduler - params["Rules.0.SessionExpireTime"] = strconv.Itoa(sessionExpireTime) - - // health check - params["Rules.0.HealthCheck.HealthSwitch"] = strconv.Itoa(hc.HealthSwitch) - params["Rules.0.HealthCheck.IntervalTime"] = strconv.Itoa(hc.IntervalTime) - params["Rules.0.HealthCheck.HealthNum"] = strconv.Itoa(hc.HealthNum) - params["Rules.0.HealthCheck.UnHealthNum"] = strconv.Itoa(hc.UnHealthNum) - if hc.HTTPCode > 0 { - params["Rules.0.HealthCheck.HttpCode"] = strconv.Itoa(hc.HTTPCode) - params["Rules.0.HealthCheck.HttpCheckPath"] = hc.HTTPCheckPath - params["Rules.0.HealthCheck.HttpCheckDomain"] = hc.HTTPCheckDomain - params["Rules.0.HealthCheck.HttpCheckMethod"] = hc.HTTPCheckMethod - } - - resp, err := self.clbRequest("CreateRule", params) - if err != nil { - return "", err - } - - return resp.GetString("RequestId") -} - -// 返回requestID -func (self *SRegion) deleteLoadbalancerListener(lbid string, listenerId string) (string, error) { - if len(lbid) == 0 { - return "", fmt.Errorf("loadbalancer id should not be empty") - } - - params := map[string]string{ - "LoadBalancerId": lbid, - "ListenerId": listenerId, - } - - resp, err := self.clbRequest("DeleteListener", params) - if err != nil { - return "", err - } - - return resp.GetString("RequestId") -} - -// 返回requestID -func (self *SRegion) deleteClassicLoadbalancerListener(lbid string, listenerId string) (string, error) { - if len(lbid) == 0 { - return "", fmt.Errorf("classic loadbalancer id should not be empty") - } - - params := map[string]string{ - "loadBalancerId": lbid, - "listenerIds.0": listenerId, - } - - resp, err := self.lbRequest("DeleteLoadBalancerListeners", params) - if err != nil { - return "", err - } - - _requestId, err := resp.Float("requestId") - if err != nil { - return "", err - } - - return fmt.Sprintf("%.f", _requestId), nil -} - -// 返回requestID -func (self *SRegion) DeleteLoadbalancerListener(t LB_TYPE, lbid string, listenerId string) (string, error) { - ctx := context.Background() - lockman.LockRawObject(ctx, "qcloud.SRegion.DeleteLoadbalancerListener", self.client.ownerId) - defer lockman.ReleaseRawObject(ctx, "qcloud.SRegion.DeleteLoadbalancerListener", self.client.ownerId) - - if len(lbid) == 0 { - return "", fmt.Errorf("loadbalancer id should not be empty") - } - - if t == LB_TYPE_APPLICATION { - return self.deleteLoadbalancerListener(lbid, listenerId) - } else { - return self.deleteClassicLoadbalancerListener(lbid, listenerId) - } -} - -// https://cloud.tencent.com/document/product/214/30681 -func (self *SRegion) updateLoadbalancerListener(lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) { - params := map[string]string{ - "LoadBalancerId": lbid, - "ListenerId": listenerId, - } - - if listenerName != nil && len(*listenerName) > 0 { - params["ListenerName"] = *listenerName - } - - if scheduler != nil && len(*scheduler) > 0 { - params["Scheduler"] = *scheduler - } - - if sessionExpireTime != nil { - params["SessionExpireTime"] = strconv.Itoa(*sessionExpireTime) - } - - params = healthCheckParams(LB_TYPE_APPLICATION, params, healthCheck, "HealthCheck.") - params = certificateParams(LB_TYPE_APPLICATION, params, cert, "Certificate.") - - resp, err := self.clbRequest("ModifyListener", params) - if err != nil { - return "", err - } - - return resp.GetString("RequestId") -} - -// https://cloud.tencent.com/document/api/214/3601 -func (self *SRegion) updateClassicLoadbalancerListener(lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) { - params := map[string]string{ - "loadBalancerId": lbid, - "listenerId": listenerId, - } - - if listenerName != nil && len(*listenerName) > 0 { - params["listenerName"] = *listenerName - } - - if scheduler != nil && len(*scheduler) > 0 { - params["scheduler"] = strings.ToLower(*scheduler) - } - - if sessionExpireTime != nil { - params["sessionExpire"] = strconv.Itoa(*sessionExpireTime) - } - - params = healthCheckParams(LB_TYPE_APPLICATION, params, healthCheck, "listeners.0.") - params = certificateParams(LB_TYPE_APPLICATION, params, cert, "listeners.0.") - - resp, err := self.lbRequest("ModifyLoadBalancerListener", params) - if err != nil { - return "", err - } - - return resp.GetString("RequestId") -} - -func (self *SRegion) UpdateLoadbalancerListener(t LB_TYPE, lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) { - if len(lbid) == 0 { - return "", fmt.Errorf("loadbalancer id should not be empty") - } - - if len(listenerId) == 0 { - return "", fmt.Errorf("loadbalancer listener id should not be empty") - } - - if t == LB_TYPE_APPLICATION { - return self.updateLoadbalancerListener(lbid, listenerId, listenerName, scheduler, sessionExpireTime, healthCheck, cert) - } else { - return self.updateClassicLoadbalancerListener(lbid, listenerId, listenerName, scheduler, sessionExpireTime, healthCheck, cert) - } -} - -func getHealthCheck(listener *cloudprovider.SLoadbalancerListener) *healthCheck { - var hc *healthCheck - if listener.HealthCheck == api.LB_BOOL_ON { - hc = &healthCheck{ - HealthSwitch: 1, - UnHealthNum: listener.HealthCheckFail, - IntervalTime: listener.HealthCheckInterval, - HealthNum: listener.HealthCheckRise, - TimeOut: listener.HealthCheckTimeout, - } - - httpCode := onecloudHealthCodeToQcloud(listener.HealthCheckHttpCode) - if httpCode > 0 { - hc.HTTPCode = httpCode - hc.HTTPCheckMethod = "HEAD" // todo: add column HttpCheckMethod in model - hc.HTTPCheckDomain = listener.HealthCheckDomain - hc.HTTPCheckPath = listener.HealthCheckURI - } - } else { - hc = &healthCheck{ - HealthSwitch: 0, - UnHealthNum: 3, - IntervalTime: 5, - HealthNum: 3, - TimeOut: 2, - } - } - - return hc -} - -func getListenerRuleHealthCheck(rule *cloudprovider.SLoadbalancerListenerRule) *healthCheck { - var hc *healthCheck - if rule.HealthCheck == api.LB_BOOL_ON { - hc = &healthCheck{ - HealthSwitch: 1, - UnHealthNum: rule.HealthCheckFail, - IntervalTime: rule.HealthCheckInterval, - HealthNum: rule.HealthCheckRise, - TimeOut: rule.HealthCheckTimeout, - } - - httpCode := onecloudHealthCodeToQcloud(rule.HealthCheckHttpCode) - if httpCode > 0 { - hc.HTTPCode = httpCode - hc.HTTPCheckMethod = "HEAD" // todo: add column HttpCheckMethod in model - hc.HTTPCheckDomain = rule.HealthCheckDomain - hc.HTTPCheckPath = rule.HealthCheckURI - } - } else { - hc = &healthCheck{ - HealthSwitch: 0, - UnHealthNum: 3, - IntervalTime: 5, - HealthNum: 3, - TimeOut: 2, - } - } - - return hc -} - -func getCertificate(listener *cloudprovider.SLoadbalancerListener) *certificate { - var cert *certificate - if len(listener.CertificateID) > 0 { - cert = &certificate{ - SSLMode: "UNIDIRECTIONAL", - CERTCAID: "", - CERTID: listener.CertificateID, - } - } - - return cert -} - -func getProtocol(listener *cloudprovider.SLoadbalancerListener) string { - switch listener.ListenerType { - case api.LB_LISTENER_TYPE_HTTPS: - return PROTOCOL_HTTPS - case api.LB_LISTENER_TYPE_HTTP: - return PROTOCOL_HTTP - case api.LB_LISTENER_TYPE_TCP: - return PROTOCOL_TCP - case api.LB_LISTENER_TYPE_UDP: - return PROTOCOL_UDP - case "tcp_ssl": - return PROTOCOL_TCP_SSL - default: - return "" - } -} - -func getClassicLBProtocol(listener *cloudprovider.SLoadbalancerListener) int { - switch listener.ListenerType { - case api.LB_LISTENER_TYPE_HTTP: - return 1 - case api.LB_LISTENER_TYPE_HTTPS: - return 4 - case api.LB_LISTENER_TYPE_TCP: - return 2 - case api.LB_LISTENER_TYPE_UDP: - return 3 - default: - return 0 // 非法值 - } -} - -func getScheduler(listener *cloudprovider.SLoadbalancerListener) *string { - var sch string - switch listener.Scheduler { - case api.LB_SCHEDULER_WRR: - sch = "WRR" - case api.LB_SCHEDULER_WLC: - sch = "LEAST_CONN" - case api.LB_SCHEDULER_SCH: - sch = "IP_HASH" - default: - return nil - } - - return &sch -} - -func healthCheckParams(t LB_TYPE, params map[string]string, hc *healthCheck, paramPrefix string) map[string]string { - if hc == nil { - return params - } - - if t == LB_TYPE_APPLICATION { - params[paramPrefix+"HealthSwitch"] = strconv.Itoa(hc.HealthSwitch) - params[paramPrefix+"TimeOut"] = strconv.Itoa(hc.TimeOut) - params[paramPrefix+"IntervalTime"] = strconv.Itoa(hc.IntervalTime) - params[paramPrefix+"HealthNum"] = strconv.Itoa(hc.HealthNum) - params[paramPrefix+"UnHealthNum"] = strconv.Itoa(hc.UnHealthNum) - if hc.HTTPCode > 0 { - params[paramPrefix+"HttpCode"] = strconv.Itoa(hc.HTTPCode) - params[paramPrefix+"HttpCheckPath"] = hc.HTTPCheckPath - params[paramPrefix+"HttpCheckDomain"] = hc.HTTPCheckDomain - params[paramPrefix+"HttpCheckMethod"] = hc.HTTPCheckMethod - } - } else { - params[paramPrefix+"healthSwitch"] = strconv.Itoa(hc.HealthSwitch) - params[paramPrefix+"timeOut"] = strconv.Itoa(hc.TimeOut) - params[paramPrefix+"intervalTime"] = strconv.Itoa(hc.IntervalTime) - params[paramPrefix+"healthNum"] = strconv.Itoa(hc.HealthNum) - params[paramPrefix+"unHealthNum"] = strconv.Itoa(hc.UnHealthNum) - if hc.HTTPCode > 0 { - params[paramPrefix+"httpCode"] = strconv.Itoa(hc.HTTPCode) - params[paramPrefix+"httpCheckPath"] = hc.HTTPCheckPath - } - } - return params -} - -func certificateParams(t LB_TYPE, params map[string]string, cert *certificate, paramPrefix string) map[string]string { - if cert == nil { - return params - } - - if t == LB_TYPE_APPLICATION { - params[paramPrefix+"SSLMode"] = cert.SSLMode - params[paramPrefix+"CertId"] = cert.CERTID - if len(cert.CERTCAID) > 0 { - params[paramPrefix+"CertCaId"] = cert.CERTCAID - } - } else { - params[paramPrefix+"SSLMode"] = strings.ToLower(cert.SSLMode) - params[paramPrefix+"certId"] = cert.CERTID - if len(cert.CERTCAID) > 0 { - params[paramPrefix+"certCaId"] = cert.CERTCAID - } - } - return params -} - -func (self *SLBListener) GetProjectId() string { - return self.lb.GetProjectId() -} - -func (self *SLBListener) GetClientIdleTimeout() int { - return 0 -} - -func (self *SLBListener) GetBackendConnectTimeout() int { - return 0 -} diff --git a/pkg/multicloud/qcloud/loadbalancer_listenerrule.go b/pkg/multicloud/qcloud/loadbalancer_listenerrule.go deleted file mode 100644 index 2e828622a3..0000000000 --- a/pkg/multicloud/qcloud/loadbalancer_listenerrule.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SLBListenerRule struct { - multicloud.SResourceBase - multicloud.SLoadbalancerRedirectBase - multicloud.QcloudTags - listener *SLBListener - - Domain string `json:"Domain"` - Certificate certificate `json:"Certificate"` - URL string `json:"Url"` - HealthCheck healthCheck `json:"HealthCheck"` - LocationID string `json:"LocationId"` - Scheduler string `json:"Scheduler"` - SessionExpireTime int64 `json:"SessionExpireTime"` -} - -// https://cloud.tencent.com/document/api/214/30688 -func (self *SLBListenerRule) Delete(ctx context.Context) error { - lockman.LockRawObject(ctx, "qcloud.SLBListenerRule.Delete", self.listener.lb.region.client.ownerId) - defer lockman.ReleaseRawObject(ctx, "qcloud.SLBListenerRule.Delete", self.listener.lb.region.client.ownerId) - - _, err := self.listener.lb.region.DeleteLBListenerRule(self.listener.lb.GetId(), self.listener.GetId(), self.GetId()) - if err != nil { - return err - } - - return cloudprovider.WaitDeleted(self, 5*time.Second, 60*time.Second) -} - -func (self *SLBListenerRule) GetId() string { - return self.LocationID -} - -func (self *SLBListenerRule) GetName() string { - return self.LocationID -} - -func (self *SLBListenerRule) GetGlobalId() string { - return self.LocationID -} - -func (self *SLBListenerRule) GetStatus() string { - return api.LB_STATUS_ENABLED -} - -func (self *SLBListenerRule) Refresh() error { - err := self.listener.Refresh() - if err != nil { - return err - } - - for _, rule := range self.listener.Rules { - if rule.GetId() == self.GetId() { - rule.listener = self.listener - return jsonutils.Update(self, rule) - } - } - - return cloudprovider.ErrNotFound -} - -func (self *SLBListenerRule) IsDefault() bool { - return false -} - -func (self *SLBListenerRule) IsEmulated() bool { - return false -} - -func (self *SLBListenerRule) GetDomain() string { - return self.Domain -} - -func (self *SLBListenerRule) GetCondition() string { - return "" -} - -func (self *SLBListenerRule) GetPath() string { - return self.URL -} - -func (self *SLBListenerRule) GetProjectId() string { - return self.listener.GetProjectId() -} - -func (self *SLBListenerRule) GetBackendGroup() *SLBBackendGroup { - t := self.listener.GetListenerType() - if t == api.LB_LISTENER_TYPE_HTTP || t == api.LB_LISTENER_TYPE_HTTPS { - return &SLBBackendGroup{ - lb: self.listener.lb, - listener: self.listener, - rule: self, - } - } - - return nil -} - -// 只有http、https协议监听规则有backendgroupid -func (self *SLBListenerRule) GetBackendGroupId() string { - bg := self.GetBackendGroup() - if bg == nil { - return "" - } - - return bg.GetId() -} - -// https://cloud.tencent.com/document/api/214/30688 -// 返回requestId及error -func (self *SRegion) DeleteLBListenerRule(lbid, listenerId, ruleId string) (string, error) { - if len(ruleId) == 0 { - return "", fmt.Errorf("DeleteLBListenerRule rule id should not be empty") - } - return self.DeleteLBListenerRules(lbid, listenerId, []string{ruleId}) -} - -func (self *SRegion) DeleteLBListenerRules(lbid, listenerId string, ruleIds []string) (string, error) { - if len(lbid) == 0 { - return "", fmt.Errorf("DeleteLBListenerRules loadbalancer id should not be empty") - } - - if len(listenerId) == 0 { - return "", fmt.Errorf("DeleteLBListenerRules listener id should not be empty") - } - - if len(ruleIds) == 0 { - return "", fmt.Errorf("DeleteLBListenerRules rule id should not be empty") - } - - params := map[string]string{"LoadBalancerId": lbid, "ListenerId": listenerId} - for i, ruleId := range ruleIds { - params[fmt.Sprintf("LocationIds.%d", i)] = ruleId - } - - resp, err := self.clbRequest("DeleteRule", params) - if err != nil { - return "", err - } - - return resp.GetString("RequestId") -} diff --git a/pkg/multicloud/qcloud/memcached.go b/pkg/multicloud/qcloud/memcached.go deleted file mode 100644 index f93ae13b23..0000000000 --- a/pkg/multicloud/qcloud/memcached.go +++ /dev/null @@ -1,314 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strconv" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SMemcached struct { - multicloud.SElasticcacheBase - multicloud.QcloudTags - region *SRegion - - InstanceId string `json:"InstanceId"` - InstanceName string `json:"InstanceName"` - AppId int `json:"AppId"` - ProjectId int `json:"ProjectId"` - InstanceDesc string `json:"InstanceDesc"` - Vip string `json:"Vip"` - Vport int `json:"Vport"` - Status int `json:"Status"` - AutoRenewFlag int `json:"AutoRenewFlag"` - VpcId int `json:"VpcId"` - SubnetId int `json:"SubnetId"` - PayMode int `json:"PayMode"` - ZoneId int `json:"ZoneId"` - Expire int `json:"Expire"` - RegionId int `json:"RegionId"` - AddTimeStamp time.Time `json:"AddTimeStamp"` - ModtimeStamp time.Time `json:"ModTimeStamp"` - IsolateTimesSamp time.Time `json:"IsolateTimeStamp"` - UniqVpcId string `json:"UniqVpcId"` - UniqSubnetId string `json:"UniqSubnetId"` - DeadlineTimeStamp string `json:"DeadlineTimeStamp"` - SetId int `json:"SetId"` - CmemId int `json:"CmemId"` -} - -func (self *SMemcached) GetId() string { - return self.InstanceId -} - -func (self *SMemcached) GetName() string { - return self.InstanceName -} - -func (self *SMemcached) GetGlobalId() string { - return self.GetId() -} - -func (self *SMemcached) GetStatus() string { - switch self.Status { - case 0: - return api.ELASTIC_CACHE_STATUS_DEPLOYING - case 1: - return api.ELASTIC_CACHE_STATUS_RUNNING - case 2: - return api.ELASTIC_CACHE_STATUS_CREATE_FAILED - case 4, 5, 6, 7: - return api.ELASTIC_CACHE_STATUS_RELEASING - default: - return fmt.Sprintf("%d", self.Status) - } -} - -func (self *SMemcached) GetProjectId() string { - return strconv.Itoa(self.ProjectId) -} - -func (self *SMemcached) GetBillingType() string { - // 计费模式:0-按量计费,1-包年包月 - if self.PayMode == 1 { - return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SMemcached) GetCreatedAt() time.Time { - return self.AddTimeStamp -} - -func (self *SMemcached) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SMemcached) SetAutoRenew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (self *SMemcached) IsAutoRenew() bool { - return self.AutoRenewFlag == 1 -} - -func (self *SMemcached) GetInstanceType() string { - return "" -} - -func (self *SMemcached) GetCapacityMB() int { - return 0 -} - -func (self *SMemcached) GetArchType() string { - return api.ELASTIC_CACHE_NODE_TYPE_SINGLE -} - -func (self *SMemcached) GetNodeType() string { - return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE -} - -func (self *SMemcached) GetEngine() string { - return api.ELASTIC_CACHE_ENGINE_MEMCACHED -} - -func (self *SMemcached) GetEngineVersion() string { - return "latest" -} - -func (self *SMemcached) GetVpcId() string { - return self.UniqVpcId -} - -func (self *SMemcached) GetZoneId() string { - return fmt.Sprintf("%s/%s-%d", self.region.GetGlobalId(), self.region.Region, self.ZoneId%10) -} - -func (self *SMemcached) GetNetworkType() string { - if len(self.UniqSubnetId) > 0 { - return api.LB_NETWORK_TYPE_VPC - } - return api.LB_NETWORK_TYPE_CLASSIC -} - -func (self *SMemcached) GetNetworkId() string { - return self.UniqSubnetId -} - -func (self *SMemcached) GetPrivateDNS() string { - return "" -} - -func (self *SMemcached) GetPrivateIpAddr() string { - return self.Vip -} - -func (self *SMemcached) GetPrivateConnectPort() int { - return self.Vport -} - -func (self *SMemcached) GetPublicDNS() string { - return "" -} - -func (self *SMemcached) GetPublicIpAddr() string { - return "" -} - -func (self *SMemcached) GetPublicConnectPort() int { - return 0 -} - -func (self *SMemcached) GetMaintainStartTime() string { - return "" -} - -func (self *SMemcached) GetMaintainEndTime() string { - return "" -} - -func (self *SMemcached) GetAuthMode() string { - return "off" -} - -func (self *SMemcached) GetSecurityGroupIds() ([]string, error) { - return []string{}, nil -} - -func (self *SMemcached) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { - return []cloudprovider.ICloudElasticcacheAccount{}, nil -} - -func (self *SMemcached) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { - return []cloudprovider.ICloudElasticcacheAcl{}, nil -} - -func (self *SMemcached) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { - return []cloudprovider.ICloudElasticcacheBackup{}, nil -} - -func (self *SMemcached) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { - return []cloudprovider.ICloudElasticcacheParameter{}, nil -} - -func (self *SMemcached) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SMemcached) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SMemcached) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { - return nil, cloudprovider.ErrNotFound -} - -func (self *SMemcached) Restart() error { - return errors.Wrap(cloudprovider.ErrNotSupported, "Restart") -} - -func (self *SMemcached) Delete() error { - return cloudprovider.ErrNotSupported -} - -func (self *SMemcached) CleanupInstance() error { - return cloudprovider.ErrNotSupported -} - -func (self *SMemcached) ChangeInstanceSpec(spec string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SMemcached) SetMaintainTime(maintainStartTime, maintainEndTime string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SMemcached) AllocatePublicConnection(port int) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SMemcached) ReleasePublicConnection() error { - return errors.Wrap(cloudprovider.ErrNotSupported, "ReleasePublicConnection") -} - -func (self *SMemcached) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SMemcached) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { - return nil, errors.Wrap(cloudprovider.ErrNotSupported, "CreateAcl") -} - -func (self *SMemcached) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SMemcached) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { - return cloudprovider.ErrNotSupported -} - -func (self *SMemcached) UpdateAuthMode(noPasswordAccess bool, password string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SMemcached) UpdateInstanceParameters(config jsonutils.JSONObject) error { - return cloudprovider.ErrNotSupported -} - -func (self *SMemcached) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { - return cloudprovider.ErrNotSupported -} - -func (self *SMemcached) UpdateSecurityGroups(secgroupIds []string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SMemcached) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetMemcaches(ids []string, limit, offset int) ([]SMemcached, int, error) { - params := map[string]string{} - if limit <= 0 { - limit = 100 - } - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - for i, id := range ids { - params[fmt.Sprintf("InstanceIds.%d", i)] = id - } - resp, err := self.memcachedRequest("DescribeInstances", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeInstances") - } - ret := []SMemcached{} - err = resp.Unmarshal(&ret, "InstanceList") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal InstanceList") - } - total, _ := resp.Float("TotalCount") - return ret, int(total), nil -} diff --git a/pkg/multicloud/qcloud/mongodb.go b/pkg/multicloud/qcloud/mongodb.go deleted file mode 100644 index e7bd91133e..0000000000 --- a/pkg/multicloud/qcloud/mongodb.go +++ /dev/null @@ -1,406 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - "time" - - sdkerrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SMongoDB struct { - multicloud.QcloudTags - multicloud.SVirtualResourceBase - multicloud.SBillingBase - multicloud.SMongodbBase - - region *SRegion - - IOPS int - NetworkAddress string - AutoRenewFlag int `json:"AutoRenewFlag"` - CloneInstances []interface{} `json:"CloneInstances"` - ClusterType int `json:"ClusterType"` - ClusterVer int `json:"ClusterVer"` - ConfigServerCpuNum int `json:"ConfigServerCpuNum"` - ConfigServerMemory int `json:"ConfigServerMemory"` - ConfigServerNodeNum int `json:"ConfigServerNodeNum"` - ConfigServerVolume int `json:"ConfigServerVolume"` - CpuNum int `json:"CpuNum"` - CreateTime time.Time `json:"CreateTime"` - DeadLine string `json:"DeadLine"` - InstanceId string `json:"InstanceId"` - InstanceName string `json:"InstanceName"` - InstanceStatusDesc string `json:"InstanceStatusDesc"` - InstanceTaskDesc string `json:"InstanceTaskDesc"` - InstanceTaskId int `json:"InstanceTaskId"` - InstanceType int `json:"InstanceType"` - InstanceVer int `json:"InstanceVer"` - MachineType string `json:"MachineType"` - MaintenanceEnd string `json:"MaintenanceEnd"` - MaintenanceStart string `json:"MaintenanceStart"` - Memory int `json:"Memory"` - MongoVersion string `json:"MongoVersion"` - MongosCpuNum int `json:"MongosCpuNum"` - MongosMemory int `json:"MongosMemory"` - MongosNodeNum int `json:"MongosNodeNum"` - NetType int `json:"NetType"` - PayMode int `json:"PayMode"` - ProjectId int `json:"ProjectId"` - Protocol int `json:"Protocol"` - Readonlyinstances []interface{} `json:"ReadonlyInstances"` - RealInstanceId string `json:"RealInstanceId"` - Region string `json:"Region"` - Relatedinstance struct { - InstanceId string `json:"InstanceId"` - Region string `json:"Region"` - } `json:"RelatedInstance"` - Replicasets []struct { - Memory int `json:"Memory"` - OplogSize int `json:"OplogSize"` - RealReplicasetId string `json:"RealReplicaSetId"` - ReplicaSetId string `json:"ReplicaSetId"` - ReplicaSetName string `json:"ReplicaSetName"` - SecondaryNum int `json:"SecondaryNum"` - UsedVolume int `json:"UsedVolume"` - Volume int `json:"Volume"` - } `json:"ReplicaSets"` - ReplicationSetNum int `json:"ReplicationSetNum"` - SecondaryNum int `json:"SecondaryNum"` - StandbyInstances []interface{} `json:"StandbyInstances"` - Status int `json:"Status"` - SubnetId string `json:"SubnetId"` - UsedVolume int `json:"UsedVolume"` - Vip string `json:"Vip"` - Volume int `json:"Volume"` - VpcId string `json:"VpcId"` - Vport int `json:"Vport"` - Zone string `json:"Zone"` -} - -func (self *SMongoDB) GetGlobalId() string { - return self.InstanceId -} - -func (self *SMongoDB) GetId() string { - return self.InstanceId -} - -func (self *SMongoDB) GetName() string { - return self.InstanceName -} - -func (self *SMongoDB) GetStatus() string { - switch self.Status { - case 0, 1: - return api.MONGO_DB_STATUS_CREATING - case 2: - return api.MONGO_DB_STATUS_RUNNING - case -2, -3: - return api.MONGO_DB_STATUS_DELETING - } - return fmt.Sprintf("%d", self.Status) -} - -func (self *SMongoDB) Refresh() error { - ins, err := self.region.GetMongoDB(self.InstanceId) - if err != nil { - return errors.Wrapf(err, "GetMongoDB") - } - return jsonutils.Update(self, ins) -} - -func (self *SMongoDB) GetProjectId() string { - return fmt.Sprintf("%d", self.ProjectId) -} - -func (self *SMongoDB) GetVpcId() string { - return self.VpcId -} - -func (self *SMongoDB) GetNetworkId() string { - return self.SubnetId -} - -func (self *SMongoDB) GetCreatedAt() time.Time { - return self.CreateTime.Add(time.Hour * -8) -} - -func (self *SMongoDB) GetExpiredAt() time.Time { - return time.Time{} -} - -func (self *SMongoDB) GetIpAddr() string { - return self.Vip -} - -func (self *SMongoDB) GetVcpuCount() int { - return self.CpuNum -} - -func (self *SMongoDB) GetVmemSizeMb() int { - return self.Memory -} - -func (self *SMongoDB) GetReplicationNum() int { - switch self.GetCategory() { - case api.MONGO_DB_CATEGORY_SHARDING: - return self.ReplicationSetNum - case api.MONGO_DB_CATEGORY_REPLICATE: - return 3 - } - return self.ReplicationSetNum -} - -func (self *SMongoDB) GetDiskSizeMb() int { - return self.Volume -} - -func (self *SMongoDB) GetZoneId() string { - return self.Zone -} - -func (self *SMongoDB) GetBillingType() string { - // 计费模式:0-按量计费,1-包年包月 - if self.PayMode == 1 { - return billing_api.BILLING_TYPE_PREPAID - } else { - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SMongoDB) IsAutoRenew() bool { - return self.AutoRenewFlag == 1 -} - -func (self *SMongoDB) GetCategory() string { - switch self.ClusterType { - case 0: - return api.MONGO_DB_CATEGORY_REPLICATE - case 1: - return api.MONGO_DB_CATEGORY_SHARDING - default: - return fmt.Sprintf("%d", self.ClusterType) - } -} - -func (self *SMongoDB) GetEngine() string { - if utils.IsInStringArray("WT", strings.Split(self.MongoVersion, "_")) { - return api.MONGO_DB_ENGINE_WIRED_TIGER - } - return api.MONGO_DB_ENGINE_ROCKS -} - -func (self *SMongoDB) GetEngineVersion() string { - vers := strings.Split(self.MongoVersion, "_") - if len(vers) > 1 { - return strings.Join(strings.Split(vers[1], ""), ".") - } - return "" -} - -func (self *SMongoDB) GetInstanceType() string { - return self.MachineType -} - -func (self *SMongoDB) GetMaintainTime() string { - return fmt.Sprintf("%s-%s", self.MaintenanceStart, self.MaintenanceEnd) -} - -func (self *SMongoDB) GetPort() int { - return self.Vport -} - -func (self *SMongoDB) Delete() error { - return self.region.DeleteMongoDB(self.InstanceId) -} - -func (self *SRegion) DeleteMongoDB(id string) error { - err := self.IsolateMongoDB(id) - if err != nil { - return errors.Wrapf(err, "IsolateDBInstance") - } - return cloudprovider.Wait(time.Second*10, time.Minute*3, func() (bool, error) { - err = self.OfflineIsolatedMongoDB(id) - if err == nil { - return true, nil - } - if e, ok := errors.Cause(err).(*sdkerrors.TencentCloudSDKError); ok && e.Code == "InvalidParameterValue.LockFailed" { - return false, nil - } - return true, err - }) -} - -func (self *SMongoDB) SetTags(tags map[string]string, replace bool) error { - return self.region.SetResourceTags("mongodb", "instance", []string{self.InstanceId}, tags, replace) -} - -func (self *SMongoDB) GetIBackups() ([]cloudprovider.SMongoDBBackup, error) { - return self.region.GetMongoDBBackups(self.InstanceId) -} - -func (self *SRegion) IsolateMongoDB(id string) error { - params := map[string]string{ - "InstanceId": id, - } - _, err := self.mongodbRequest("IsolateDBInstance", params) - return errors.Wrapf(err, "IsolateDBInstance") -} - -func (self *SRegion) OfflineIsolatedMongoDB(id string) error { - params := map[string]string{ - "InstanceId": id, - } - _, err := self.mongodbRequest("OfflineIsolatedDBInstance", params) - return errors.Wrapf(err, "OfflineIsolatedDBInstance") -} - -func (self *SRegion) GetMongoDBs(ids []string, limit, offset int) ([]SMongoDB, int, error) { - if limit < 1 || limit > 100 { - limit = 100 - } - params := map[string]string{ - "Limit": fmt.Sprintf("%d", limit), - "Offset": fmt.Sprintf("%d", offset), - } - for i, id := range ids { - params[fmt.Sprintf("InstanceIds.%d", i)] = id - } - resp, err := self.mongodbRequest("DescribeDBInstances", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeDBInstances") - } - dbs := []SMongoDB{} - err = resp.Unmarshal(&dbs, "InstanceDetails") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - totalCount, _ := resp.Float("TotalCount") - return dbs, int(totalCount), nil -} - -func (self *SMongoDB) GetIops() int { - return self.IOPS -} - -func (self *SMongoDB) GetNetworkAddress() string { - return self.NetworkAddress -} - -func (self *SRegion) GetICloudMongoDBs() ([]cloudprovider.ICloudMongoDB, error) { - dbs := []SMongoDB{} - for { - part, total, err := self.GetMongoDBs(nil, 100, len(dbs)) - if err != nil { - return nil, errors.Wrapf(err, "GetMongoDBs") - } - dbs = append(dbs, part...) - if len(dbs) >= total { - break - } - } - ret := []cloudprovider.ICloudMongoDB{} - for i := range dbs { - dbs[i].region = self - ret = append(ret, &dbs[i]) - } - return ret, nil -} - -func (self *SRegion) GetMongoDBBackups(id string) ([]cloudprovider.SMongoDBBackup, error) { - params := map[string]string{ - "BackupMethod": "2", - "InstanceId": id, - } - resp, err := self.mongodbRequest("DescribeDBBackups", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeDBBackups") - } - backups := []struct { - InstanceId string - BackupType int - BackupName string - BackupDesc string - BackupSize int - StartTime time.Time - EndTime time.Time - Status int - BackupMethod int - }{} - err = resp.Unmarshal(&backups, "BackupList") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - ret := []cloudprovider.SMongoDBBackup{} - for _, backup := range backups { - b := cloudprovider.SMongoDBBackup{ - Name: backup.BackupName, - Description: backup.BackupDesc, - BackupSizeKb: backup.BackupSize, - } - b.StartTime = backup.StartTime.Add(time.Hour * -8) - b.EndTime = backup.EndTime.Add(time.Hour * -8) - switch backup.Status { - case 1: - b.Status = cloudprovider.MongoDBBackupStatusCreating - case 2: - b.Status = cloudprovider.MongoDBBackupStatusAvailable - default: - b.Status = cloudprovider.MongoDBBackupStatusUnknown - } - b.BackupMethod = cloudprovider.MongoDBBackupMethodLogical - if backup.BackupMethod == 0 { - b.BackupMethod = cloudprovider.MongoDBBackupMethodPhysical - } - b.BackupType = cloudprovider.MongoDBBackupTypeAuto - if backup.BackupType == 1 { - b.BackupType = cloudprovider.MongoDBBackupTypeManual - } - ret = append(ret, b) - } - return ret, nil -} - -func (self *SRegion) GetMongoDB(id string) (*SMongoDB, error) { - dbs, _, err := self.GetMongoDBs([]string{id}, 1, 0) - if err != nil { - return nil, errors.Wrapf(err, "GetMongoDB(%s)", id) - } - for i := range dbs { - dbs[i].region = self - return &dbs[i], nil - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SRegion) GetICloudMongoDBById(id string) (cloudprovider.ICloudMongoDB, error) { - db, err := self.GetMongoDB(id) - if err != nil { - return nil, errors.Wrapf(err, "GetMongoDB") - } - return db, nil -} diff --git a/pkg/multicloud/qcloud/monitor.go b/pkg/multicloud/qcloud/monitor.go deleted file mode 100644 index 1052e7ef7d..0000000000 --- a/pkg/multicloud/qcloud/monitor.go +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/timeutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -const ( - QCLOUD_API_VERSION_METRICS = "2018-07-24" -) - -type SQcMetricDimension struct { - Name string `json:"Name"` - Value string `json:"Value"` -} - -type SQcMetricConditionDimension struct { - Key string `json:"Key"` - Value string `json:"Value"` - Operator string `json:"Operator"` -} - -type SQcInstanceMetricDimension struct { - Dimensions []SQcMetricDimension -} - -type SDataPoint struct { - Dimensions []SQcMetricDimension `json:"Dimensions"` - Timestamps []float64 `json:"Timestamps"` - Values []float64 `json:"Values"` -} - -type SK8SDataPoint struct { - MetricName string `json:"MetricName"` - Points []SK8sPoint `json:"Points"` -} - -type SK8sPoint struct { - Dimensions []SQcMetricDimension `json:"Dimensions"` - Values []SK8sPointValue `json:"Values"` -} - -type SK8sPointValue struct { - Timestamp float64 `json:"Timestamp"` - Value float64 `json:"Value"` -} - -type SBatchQueryMetricDataInput struct { - MetricName string `json:"MetricName"` - Namespace string `json:"Namespace"` - Metrics []SQcMetricDimension `json:"Metrics"` - StartTime int64 `json:"StartTime"` - EndTime int64 `json:"EndTime"` - Period string `json:"Period"` -} - -func (self *SQcloudClient) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { - cli, err := self.getDefaultClient(params) - if err != nil { - return nil, err - } - return monitorRequest(cli, action, params, self.cpcfg.UpdatePermission, self.debug) -} - -func (self *SQcloudClient) GetMonitorData(ns string, name string, since time.Time, until time.Time, regionId string, dimensionName string, resIds []string) ([]SDataPoint, error) { - params := make(map[string]string) - params["Region"] = regionId - params["MetricName"] = name - params["Namespace"] = ns - params["StartTime"] = since.Format(timeutils.IsoTimeFormat) - params["EndTime"] = until.Format(timeutils.IsoTimeFormat) - for idx, resId := range resIds { - params[fmt.Sprintf("Instances.%d.Dimensions.0.Name", idx)] = dimensionName - params[fmt.Sprintf("Instances.%d.Dimensions.0.Value", idx)] = resId - } - body, err := self.metricsRequest("GetMonitorData", params) - if err != nil { - return nil, errors.Wrapf(err, "MetricRequest for %s", resIds) - } - ret := []SDataPoint{} - err = body.Unmarshal(&ret, "DataPoints") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return ret, nil -} - -func (self *SQcloudClient) GetK8sMonitorData(ns, name, resourceId string, since time.Time, until time.Time, regionId string) ([]SK8SDataPoint, error) { - params := make(map[string]string) - params["Module"] = "monitor" - params["Region"] = regionId - params["MetricNames.0"] = name - params["Namespace"] = ns - params["Period"] = "60" - params["StartTime"] = since.Format(timeutils.IsoTimeFormat) - params["EndTime"] = until.Format(timeutils.IsoTimeFormat) - params["Conditions.0.Key"] = "tke_cluster_instance_id" - params["Conditions.0.Operator"] = "in" - params["Conditions.0.Value.0"] = resourceId - body, err := self.metricsRequest("DescribeStatisticData", params) - if err != nil { - return nil, errors.Wrap(err, "region.MetricRequest") - } - ret := []SK8SDataPoint{} - return ret, body.Unmarshal(&ret, "Data") -} - -func (self *SQcloudClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: - return self.GetRedisMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_RDS: - return self.GetRdsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_K8S: - return self.GetK8sMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) - } -} - -func (self *SQcloudClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ - cloudprovider.VM_METRIC_TYPE_CPU_USAGE: { - "CPUUsage": "", - }, - cloudprovider.VM_METRIC_TYPE_MEM_USAGE: { - "MemUsage": "", - }, - cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: { - "lanOuttraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - "WanOuttraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, - }, - cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: { - "lanIntraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - "WanIntraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, - }, - } { - for metricName, tag := range metricNames { - metrics, err := self.GetMonitorData("QCE/CVM", metricName, opts.StartTime, opts.EndTime, opts.RegionExtId, "InstanceId", opts.ResourceIds) - if err != nil { - log.Errorf("GetMonitorData error: %v", err) - continue - } - for i := range metrics { - metric := cloudprovider.MetricValues{} - if len(metrics[i].Dimensions) < 1 || metrics[i].Dimensions[0].Name != "InstanceId" { - continue - } - metric.Id = metrics[i].Dimensions[0].Value - metric.MetricType = metricType - metricValue := cloudprovider.MetricValue{} - metricValue.Tags = map[string]string{} - idx := strings.Index(tag, ":") - if idx > 0 { - metricValue.Tags[tag[:idx]] = tag[idx+1:] - } - if len(metrics[i].Timestamps) == 0 { - continue - } - for j := range metrics[i].Timestamps { - metricValue.Value = metrics[i].Values[j] - if strings.Contains(metricName, "traffic") { //Mbps - metricValue.Value *= 1024 * 1024 - } - metricValue.Timestamp = time.Unix(int64(metrics[i].Timestamps[j]), 0) - metric.Values = append(metric.Values, metricValue) - } - ret = append(ret, metric) - } - } - } - return ret, nil -} - -func (self *SQcloudClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ - cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE: { - "CpuUsMin": "", - }, - cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE: { - "StorageUsMin": "", - }, - cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX: { - "InFlowMin": "", - }, - cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX: { - "OutFlowMin": "", - }, - cloudprovider.REDIS_METRIC_TYPE_USED_CONN: { - "ConnectionsMin": "", - }, - cloudprovider.REDIS_METRIC_TYPE_OPT_SES: { - "QpsMin": "", - }, - cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS: { - "KeysMin": "", - }, - cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS: { - "ExpiredKeysMin": "", - }, - cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE: { - "StorageMin": "", - }, - } { - for metricName, tag := range metricNames { - metrics, err := self.GetMonitorData("QCE/REDIS", metricName, opts.StartTime, opts.EndTime, opts.RegionExtId, "instanceid", opts.ResourceIds) - if err != nil { - log.Errorf("GetMonitorData error: %v", err) - continue - } - for i := range metrics { - metric := cloudprovider.MetricValues{} - if len(metrics[i].Dimensions) < 1 || metrics[i].Dimensions[0].Name != "instanceid" { - continue - } - metric.Id = metrics[i].Dimensions[0].Value - metric.MetricType = metricType - metricValue := cloudprovider.MetricValue{} - metricValue.Tags = map[string]string{} - idx := strings.Index(tag, ":") - if idx > 0 { - metricValue.Tags[tag[:idx]] = tag[idx+1:] - } - if len(metrics[i].Timestamps) == 0 { - continue - } - for j := range metrics[i].Timestamps { - metricValue.Value = metrics[i].Values[j] - metricValue.Timestamp = time.Unix(int64(metrics[i].Timestamps[j]), 0) - metric.Values = append(metric.Values, metricValue) - } - ret = append(ret, metric) - } - } - } - return ret, nil -} - -func (self *SQcloudClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ - cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: { - "CPUUseRate": "", - }, - cloudprovider.RDS_METRIC_TYPE_MEM_USAGE: { - "MemoryUseRate": "", - }, - cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: { - "BytesSent": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - }, - cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: { - "BytesReceived": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, - }, - cloudprovider.RDS_METRIC_TYPE_DISK_USAGE: { - "VolumeRate": "", - }, - cloudprovider.RDS_METRIC_TYPE_CONN_COUNT: { - "ThreadsConnected": "", - }, - cloudprovider.RDS_METRIC_TYPE_CONN_USAGE: { - "ConnectionUseRate": "", - }, - cloudprovider.RDS_METRIC_TYPE_QPS: { - "QPS": "", - }, - cloudprovider.RDS_METRIC_TYPE_TPS: { - "TPS": "", - }, - cloudprovider.RDS_METRIC_TYPE_INNODB_READ_BPS: { - "InnodbDataRead": "", - }, - cloudprovider.RDS_METRIC_TYPE_INNODB_WRITE_BPS: { - "InnodbDataWritten": "", - }, - } { - for metricName, tag := range metricNames { - metrics, err := self.GetMonitorData("QCE/CDB", metricName, opts.StartTime, opts.EndTime, opts.RegionExtId, "InstanceId", opts.ResourceIds) - if err != nil { - log.Errorf("GetMonitorData error: %v", err) - continue - } - for i := range metrics { - metric := cloudprovider.MetricValues{} - if len(metrics[i].Dimensions) < 1 || metrics[i].Dimensions[0].Name != "InstanceId" { - continue - } - metric.Id = metrics[i].Dimensions[0].Value - metric.MetricType = metricType - metricValue := cloudprovider.MetricValue{} - metricValue.Tags = map[string]string{} - idx := strings.Index(tag, ":") - if idx > 0 { - metricValue.Tags[tag[:idx]] = tag[idx+1:] - } - if len(metrics[i].Timestamps) == 0 { - continue - } - for j := range metrics[i].Timestamps { - metricValue.Value = metrics[i].Values[j] - metricValue.Timestamp = time.Unix(int64(metrics[i].Timestamps[j]), 0) - metric.Values = append(metric.Values, metricValue) - } - ret = append(ret, metric) - } - } - } - return ret, nil -} - -func (self *SQcloudClient) GetK8sMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ret := []cloudprovider.MetricValues{} - for metricType, metricName := range map[cloudprovider.TMetricType]string{ - cloudprovider.K8S_NODE_METRIC_TYPE_CPU_USAGE: "K8sNodeCpuUsage", - cloudprovider.K8S_NODE_METRIC_TYPE_MEM_USAGE: "K8sNodeMemUsage", - } { - metrics, err := self.GetK8sMonitorData("QCE/TKE2", metricName, opts.ResourceId, opts.StartTime, opts.EndTime, opts.RegionExtId) - if err != nil { - log.Errorf("GetMonitorData error: %v", err) - continue - } - for i := range metrics { - for _, point := range metrics[i].Points { - tags := map[string]string{} - for _, dim := range point.Dimensions { - if dim.Name == "node" { - tags[cloudprovider.METRIC_TAG_NODE] = dim.Value - } - } - metric := cloudprovider.MetricValues{} - metric.Id = opts.ResourceId - metric.MetricType = metricType - for _, value := range point.Values { - metric.Values = append(metric.Values, cloudprovider.MetricValue{ - Value: value.Value, - Timestamp: time.Unix(int64(value.Timestamp), 0), - Tags: tags, - }) - } - if len(metric.Values) > 0 { - ret = append(ret, metric) - } - } - } - } - return ret, nil -} diff --git a/pkg/multicloud/qcloud/natdtable.go b/pkg/multicloud/qcloud/natdtable.go deleted file mode 100644 index 6bf6d88ee8..0000000000 --- a/pkg/multicloud/qcloud/natdtable.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "time" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDTable struct { - multicloud.SResourceBase - multicloud.QcloudTags - nat *SNatGateway - - Eip string - NatId string - Description string - UniqVpcId string - Proto string - Pport int - Eport int - Owner string - VpcId int - PipType int - Pip string - UniqNatId string - CreateTime time.Time -} - -func (table *SDTable) GetName() string { - if len(table.Description) > 0 { - return table.Description - } - return fmt.Sprintf("%s/%s/%d", table.Eip, table.Proto, table.Eport) -} - -func (table *SDTable) GetId() string { - return fmt.Sprintf("%s/%s/%d", table.NatId, table.Eip, table.Eport) -} - -func (table *SDTable) GetGlobalId() string { - return table.GetId() -} - -func (table *SDTable) GetStatus() string { - return api.NAT_STAUTS_AVAILABLE -} - -func (table *SDTable) GetExternalIp() string { - return table.Eip -} - -func (table *SDTable) GetExternalPort() int { - return table.Eport -} - -func (table *SDTable) GetInternalIp() string { - return table.Pip -} - -func (table *SDTable) GetInternalPort() int { - return table.Pport -} - -func (table *SDTable) GetIpProtocol() string { - return table.Proto -} - -func (table *SDTable) Delete() error { - return cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetDTables(natId, vpcId string) ([]SDTable, error) { - param := map[string]string{} - param["vpcId"] = vpcId - param["natId"] = natId - - body, err := region.vpc2017Request("GetDnaptRule", param) - if err != nil { - return nil, err - } - tables := []SDTable{} - err = body.Unmarshal(&tables, "data", "detail") - if err != nil { - return nil, err - } - return tables, nil -} diff --git a/pkg/multicloud/qcloud/natgateway.go b/pkg/multicloud/qcloud/natgateway.go deleted file mode 100644 index 20c7932a80..0000000000 --- a/pkg/multicloud/qcloud/natgateway.go +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "time" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SNatGateway struct { - multicloud.SNatGatewayBase - multicloud.QcloudTags - vpc *SVpc - - NatId string `json:"natId"` - NatName string `json:"natName"` - ProductionStatus float32 `json:"productionStatus"` - State float32 `json:"state"` - UnVpcId string `json:"unVpcId"` - VpcId float32 `json:"vpcId"` - VpcName string `json:"vpcName"` - Zone string `json:"zone"` - - Bandwidth float32 `json:"bandwidth"` - CreateTime time.Time `json:"createTime"` - EipCount float32 `json:"eipCount"` - MaxConcurrent float32 `json:"maxConcurrent"` -} - -func (nat *SNatGateway) GetName() string { - if len(nat.NatName) > 0 { - return nat.NatName - } - return nat.NatId -} - -func (nat *SNatGateway) GetId() string { - return nat.NatId -} - -func (nat *SNatGateway) GetGlobalId() string { - return nat.NatId -} - -func (self *SNatGateway) GetINetworkId() string { - return "" -} - -func (nat *SNatGateway) GetStatus() string { - // NAT网关状态,0:运行中, 1:不可用, 2:欠费停服 - switch int(nat.State) { - case 0: - return api.NAT_STAUTS_AVAILABLE - case 1, 2: - return api.NAT_STATUS_UNKNOWN - default: - return api.NAT_STATUS_UNKNOWN - } -} - -func (nat *SNatGateway) GetNatSpec() string { - switch int(nat.MaxConcurrent) { - case 100 * 10000: - return api.QCLOUD_NAT_SPEC_SMALL - case 300 * 10000: - return api.QCLOUD_NAT_SPEC_MIDDLE - case 1000 * 10000: - return api.QCLOUD_NAT_SPEC_LARGE - } - return "" -} - -func (nat *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips := []SEipAddress{} - for { - part, total, err := nat.vpc.region.GetEips("", nat.NatId, len(eips), 50) - if err != nil { - return nil, err - } - eips = append(eips, part...) - if len(eips) >= total { - break - } - } - ieips := []cloudprovider.ICloudEIP{} - for i := 0; i < len(eips); i++ { - eips[i].region = nat.vpc.region - ieips = append(ieips, &eips[i]) - } - return ieips, nil -} - -func (nat *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { - return []cloudprovider.ICloudNatSEntry{}, nil -} - -func (nat *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { - tables, err := nat.vpc.region.GetDTables(nat.NatId, nat.vpc.VpcId) - if err != nil { - return nil, err - } - itables := []cloudprovider.ICloudNatDEntry{} - for i := 0; i < len(tables); i++ { - tables[i].nat = nat - itables = append(itables, &tables[i]) - } - return itables, nil -} - -func (nat *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (nat *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (nat *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (nat *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetNatGateways(vpcId string, offset int, limit int) ([]SNatGateway, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - - params := make(map[string]string) - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - if len(vpcId) > 0 { - params["vpcId"] = vpcId - } - body, err := region.vpc2017Request("DescribeNatGateway", params) - if err != nil { - return nil, 0, err - } - nats := []SNatGateway{} - err = body.Unmarshal(&nats, "data") - if err != nil { - return nil, 0, err - } - total, _ := body.Float("totalCount") - return nats, int(total), nil -} diff --git a/pkg/multicloud/qcloud/network.go b/pkg/multicloud/qcloud/network.go deleted file mode 100644 index a28296cdaf..0000000000 --- a/pkg/multicloud/qcloud/network.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "time" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.QcloudTags - wire *SWire - - CidrBlock string - Zone string - SubnetId string - VpcId string - SubnetName string - AvailableIpAddressCount int - CreatedTime time.Time - EnableBroadcast bool - IsDefault bool - RouteTableId string -} - -func (self *SNetwork) GetId() string { - return self.SubnetId -} - -func (self *SNetwork) GetName() string { - if len(self.SubnetName) > 0 { - return self.SubnetName - } - return self.SubnetId -} - -func (self *SNetwork) GetGlobalId() string { - return self.SubnetId -} - -func (self *SNetwork) IsEmulated() bool { - return false -} - -func (self *SNetwork) GetStatus() string { - return api.NETWORK_STATUS_AVAILABLE -} - -func (self *SNetwork) Delete() error { - return self.wire.zone.region.DeleteNetwork(self.SubnetId) -} - -func (self *SRegion) DeleteNetwork(networkId string) error { - params := make(map[string]string) - params["SubnetId"] = networkId - - interfaces := []SNetworkInterface{} - for { - _interfaces, total, err := self.GetNetworkInterfaces([]string{}, "", networkId, len(interfaces), 50) - if err != nil { - return errors.Wrapf(err, "DeleteNetwork.GetNetworkInterfaces") - } - interfaces = append(interfaces, _interfaces...) - if len(interfaces) >= total { - break - } - } - - for _, nic := range interfaces { - err := self.DeleteNetworkInterface(nic.NetworkInterfaceId) - if err != nil { - return errors.Wrapf(err, "DeleteNetwork.DeleteNetworkInterface") - } - } - - _, err := self.vpcRequest("DeleteSubnet", params) - if err != nil { - return errors.Wrapf(err, "vpcRequest.DeleteSubnet") - } - return nil -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (self *SNetwork) SetTags(tags map[string]string, replace bool) error { - return self.wire.vpc.region.SetResourceTags("vpc", "subnet", []string{self.SubnetId}, tags, replace) -} - -func (self *SNetwork) GetGateway() string { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 - endIp = endIp.StepDown() // 254 - return endIp.String() -} - -//https://cloud.tencent.com/document/product/215/20046 -func (self *SNetwork) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 - startIp = startIp.StepUp() // 2 - return startIp.String() -} - -func (self *SNetwork) GetIpEnd() string { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 - endIp = endIp.StepDown() // 254 - return endIp.String() -} - -func (self *SNetwork) GetIpMask() int8 { - pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) - return pref.MaskLen -} - -func (self *SNetwork) GetIsPublic() bool { - // return self.IsDefault - return true -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) Refresh() error { - log.Debugf("network refresh %s", self.SubnetId) - new, err := self.wire.zone.region.GetNetwork(self.SubnetId) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SRegion) CreateNetwork(zoneId string, vpcId string, name string, cidr string, desc string) (string, error) { - params := make(map[string]string) - params["Zone"] = zoneId - params["VpcId"] = vpcId - params["CidrBlock"] = cidr - params["SubnetName"] = name - body, err := self.vpcRequest("CreateSubnet", params) - if err != nil { - return "", err - } - return body.GetString("Subnet", "SubnetId") -} - -func (self *SNetwork) GetProjectId() string { - return "" -} diff --git a/pkg/multicloud/qcloud/networkinterface.go b/pkg/multicloud/qcloud/networkinterface.go deleted file mode 100644 index 50db0a3740..0000000000 --- a/pkg/multicloud/qcloud/networkinterface.go +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - "time" - - "github.com/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SPrivateIpAddress struct { - nic *SNetworkInterface - Description string - Primary bool - PrivateIpAddress string - PublicIpAddress string - IsWanIpBlocked bool - State string -} - -func (ip *SPrivateIpAddress) GetGlobalId() string { - return ip.PrivateIpAddress -} - -func (ip *SPrivateIpAddress) GetIP() string { - return ip.PrivateIpAddress -} - -func (ip *SPrivateIpAddress) GetINetworkId() string { - return ip.nic.SubnetId -} - -func (ip *SPrivateIpAddress) IsPrimary() bool { - return ip.Primary -} - -type SNetworkInterfaceAttachment struct { - InstanceId string - DeviceIndex int - InstanceAccountId string - AttachTime string -} - -type SNetworkInterface struct { - multicloud.SNetworkInterfaceBase - multicloud.QcloudTags - region *SRegion - VpcId string - SubnetId string - NetworkInterfaceId string - NetworkInterfaceName string - NetworkInterfaceDescription string - GroupSet []string - Primary bool - MacAddress string - State string - CreatedTime time.Time - Attachment SNetworkInterfaceAttachment - Zone string - PrivateIpAddressSet []SPrivateIpAddress -} - -func (nic *SNetworkInterface) GetName() string { - return nic.NetworkInterfaceName -} - -func (nic *SNetworkInterface) GetId() string { - return nic.NetworkInterfaceId -} - -func (nic *SNetworkInterface) GetGlobalId() string { - return nic.NetworkInterfaceId -} - -func (nic *SNetworkInterface) GetMacAddress() string { - return nic.MacAddress -} - -func (nic *SNetworkInterface) GetAssociateType() string { - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER -} - -func (nic *SNetworkInterface) GetAssociateId() string { - return nic.Attachment.InstanceId -} - -func (nic *SNetworkInterface) GetStatus() string { - switch nic.State { - case "PENDING": - return api.NETWORK_INTERFACE_STATUS_CREATING - case "AVAILABLE": - return api.NETWORK_INTERFACE_STATUS_AVAILABLE - case "ATTACHING": - return api.NETWORK_INTERFACE_STATUS_ATTACHING - case "DETACHING": - return api.NETWORK_INTERFACE_STATUS_DETACHING - case "DELETING": - return api.NETWORK_INTERFACE_STATUS_DELETING - } - return nic.State -} - -func (nic *SNetworkInterface) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { - address := []cloudprovider.ICloudInterfaceAddress{} - for i := 0; i < len(nic.PrivateIpAddressSet); i++ { - nic.PrivateIpAddressSet[i].nic = nic - address = append(address, &nic.PrivateIpAddressSet[i]) - } - return address, nil -} - -func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { - interfaces := []SNetworkInterface{} - for { - parts, total, err := region.GetNetworkInterfaces([]string{}, "", "", len(interfaces), 50) - if err != nil { - return nil, err - } - interfaces = append(interfaces, parts...) - if len(interfaces) >= total { - break - } - } - ret := []cloudprovider.ICloudNetworkInterface{} - for i := 0; i < len(interfaces); i++ { - if !strings.HasPrefix(interfaces[i].Attachment.InstanceId, "ins-") { //弹性网卡有可能已绑定资源,若绑定资源则由资源进行同步 - interfaces[i].region = region - ret = append(ret, &interfaces[i]) - } - } - return ret, nil -} - -func (region *SRegion) GetNetworkInterfaces(nicIds []string, instanceId, subnetId string, offset int, limit int) ([]SNetworkInterface, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := map[string]string{} - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - - for idx, interfaceId := range nicIds { - params[fmt.Sprintf("NetworkInterfaceIds.%d", idx)] = interfaceId - } - - idx := 0 - if len(subnetId) > 0 { - params[fmt.Sprintf("Filters.%d.Name", idx)] = "subnet-id" - params[fmt.Sprintf("Filters.%d.Values.0", idx)] = subnetId - idx++ - } - if len(instanceId) > 0 { - params[fmt.Sprintf("Filters.%d.Name", idx)] = "attachment.instance-id" - params[fmt.Sprintf("Filters.%d.Values.0", idx)] = instanceId - idx++ - } - body, err := region.vpcRequest("DescribeNetworkInterfaces", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeNetworkInterfaces") - } - - interfaces := []SNetworkInterface{} - err = body.Unmarshal(&interfaces, "NetworkInterfaceSet") - if err != nil { - return nil, 0, errors.Wrapf(err, "Unmarshal.NetworkInterfaceSet") - } - total, _ := body.Float("TotalCount") - return interfaces, int(total), nil -} - -func (region *SRegion) DeleteNetworkInterface(interfaceId string) error { - params := map[string]string{} - params["Region"] = region.Region - params["NetworkInterfaceId"] = interfaceId - - _, err := region.vpcRequest("DeleteNetworkInterface", params) - if err != nil { - return errors.Wrapf(err, "vpcRequest.DeleteNetworkInterface") - } - return nil -} diff --git a/pkg/multicloud/qcloud/object.go b/pkg/multicloud/qcloud/object.go deleted file mode 100644 index bbfd856d56..0000000000 --- a/pkg/multicloud/qcloud/object.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "net/http" - - "github.com/tencentyun/cos-go-sdk-v5" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SObject struct { - bucket *SBucket - - cloudprovider.SBaseCloudObject -} - -func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { - return o.bucket -} - -func (o *SObject) GetAcl() cloudprovider.TBucketACLType { - acl := cloudprovider.ACLPrivate - coscli, err := o.bucket.region.GetCosClient(o.bucket) - if err != nil { - log.Errorf("o.bucket.region.GetOssClient error %s", err) - return acl - } - result, _, err := coscli.Object.GetACL(context.Background(), o.Key) - if err != nil { - log.Errorf("coscli.Object.GetACL error %s", err) - return acl - } - return cosAcl2CannedAcl(result.AccessControlList) -} - -func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { - coscli, err := o.bucket.region.GetCosClient(o.bucket) - if err != nil { - return errors.Wrap(err, "o.bucket.region.GetCosClient") - } - opts := &cos.ObjectPutACLOptions{ - Header: &cos.ACLHeaderOptions{}, - } - opts.Header.XCosACL = string(aclStr) - _, err = coscli.Object.PutACL(context.Background(), o.Key, opts) - if err != nil { - return errors.Wrap(err, "coscli.Object.PutACL") - } - return nil -} - -func (o *SObject) GetMeta() http.Header { - if o.Meta != nil { - return o.Meta - } - coscli, err := o.bucket.region.GetCosClient(o.bucket) - if err != nil { - log.Errorf("o.bucket.region.GetCosClient fail %s", err) - return nil - } - resp, err := coscli.Object.Head(context.Background(), o.Key, nil) - if err != nil { - log.Errorf("coscli.Object.Head fail %s", err) - return nil - } - o.Meta = cloudprovider.FetchMetaFromHttpHeader(COS_META_HEADER, resp.Header) - return o.Meta -} - -func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { - return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) -} diff --git a/pkg/multicloud/qcloud/project.go b/pkg/multicloud/qcloud/project.go deleted file mode 100644 index 81a2ef1bb8..0000000000 --- a/pkg/multicloud/qcloud/project.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SProject struct { - multicloud.SProjectBase - multicloud.QcloudTags - client *SQcloudClient - - ProjectName string `json:"projectName"` - ProjectId string `json:"projectId"` - CreateTime time.Time `json:"createTime"` - CreateorUin int `json:"creatorUin"` - ProjectInfo string `json:"projectInfo"` -} - -func (p *SProject) GetId() string { - var pId string - pos := strings.Index(p.ProjectId, ".") - if pos >= 0 { - pId = p.ProjectId[:pos] - } else { - pId = p.ProjectId - } - return pId -} - -func (p *SProject) GetGlobalId() string { - return p.GetId() -} - -func (p *SProject) GetName() string { - return p.ProjectName -} - -func (p *SProject) GetStatus() string { - return api.EXTERNAL_PROJECT_STATUS_AVAILABLE -} - -func (p *SProject) IsEmulated() bool { - return false -} - -func (p *SProject) Refresh() error { - return nil -} - -func (client *SQcloudClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return client.CreateProject(name, "") -} - -func (client *SQcloudClient) GetProjects() ([]SProject, error) { - projects := []SProject{} - params := map[string]string{"allList": "1"} - resp, err := client.accountRequestRequest("DescribeProject", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeProject") - } - err = resp.Unmarshal(&projects) - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return projects, nil -} - -func (client *SQcloudClient) CreateProject(name, desc string) (*SProject, error) { - params := map[string]string{ - "projectName": name, - } - if len(desc) > 0 { - params["projectDesc"] = desc - } - body, err := client.accountRequestRequest("AddProject", params) - if err != nil { - return nil, errors.Wrap(err, "AddProject") - } - projectId, _ := body.GetString("projectId") - if len(projectId) == 0 { - return nil, fmt.Errorf("empty project reture") - } - projects, err := client.GetProjects() - if err != nil { - return nil, errors.Wrap(err, "GetProjects") - } - for i := range projects { - if projects[i].GetId() == projectId { - return &projects[i], nil - } - } - return nil, fmt.Errorf("failedd to found created project") -} diff --git a/pkg/multicloud/qcloud/provider/doc.go b/pkg/multicloud/qcloud/provider/doc.go deleted file mode 100644 index 2b50333baa..0000000000 --- a/pkg/multicloud/qcloud/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/qcloud/provider" diff --git a/pkg/multicloud/qcloud/provider/provider.go b/pkg/multicloud/qcloud/provider/provider.go deleted file mode 100644 index b0bf309fda..0000000000 --- a/pkg/multicloud/qcloud/provider/provider.go +++ /dev/null @@ -1,463 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "fmt" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/qcloud" -) - -type SQcloudProviderFactory struct { - cloudprovider.SPublicCloudBaseProviderFactory -} - -func (self *SQcloudProviderFactory) GetId() string { - return qcloud.CLOUD_PROVIDER_QCLOUD -} - -func (self *SQcloudProviderFactory) GetName() string { - return qcloud.CLOUD_PROVIDER_QCLOUD_CN -} - -func (self *SQcloudProviderFactory) IsCloudeventRegional() bool { - return true -} - -func (self *SQcloudProviderFactory) GetMaxCloudEventSyncDays() int { - return 7 -} - -func (self *SQcloudProviderFactory) GetMaxCloudEventKeepDays() int { - return 30 -} - -func (self *SQcloudProviderFactory) IsSupportCloudIdService() bool { - return true -} - -func (self *SQcloudProviderFactory) IsSupportCreateCloudgroup() bool { - return true -} - -func (self *SQcloudProviderFactory) IsSupportSAMLAuth() bool { - return true -} - -func (self *SQcloudProviderFactory) IsSupportCrossCloudEnvVpcPeering() bool { - return false -} - -func (self *SQcloudProviderFactory) IsSupportCrossRegionVpcPeering() bool { - return true -} - -func (self *SQcloudProviderFactory) IsSupportVpcPeeringVpcCidrOverlap() bool { - return false -} - -func (self *SQcloudProviderFactory) ValidateCrossRegionVpcPeeringBandWidth(bandwidth int) error { - validatedBandwidths := []int{10, 20, 50, 100, 200, 500, 1000} - ok, _ := utils.InArray(bandwidth, validatedBandwidths) - if ok { - return nil - } - return httperrors.NewInputParameterError("require validated qcloud cross region vpcPeering bandwidth values:[10, 20, 50, 100, 200, 500, 1000],unit Mbps") -} - -func (self *SQcloudProviderFactory) GetSupportedDnsZoneTypes() []cloudprovider.TDnsZoneType { - return []cloudprovider.TDnsZoneType{ - cloudprovider.PublicZone, - } -} - -func (self *SQcloudProviderFactory) GetSupportedDnsTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType { - return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType{ - cloudprovider.PublicZone: []cloudprovider.TDnsType{ - cloudprovider.DnsTypeA, - cloudprovider.DnsTypeAAAA, - cloudprovider.DnsTypeCNAME, - cloudprovider.DnsTypeMX, - cloudprovider.DnsTypeNS, - cloudprovider.DnsTypeSRV, - cloudprovider.DnsTypeTXT, - cloudprovider.DnsTypePTR, - }, - } -} - -func (self *SQcloudProviderFactory) GetSupportedDnsPolicyTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType { - return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType{ - cloudprovider.PublicZone: []cloudprovider.TDnsPolicyType{ - cloudprovider.DnsPolicyTypeSimple, - cloudprovider.DnsPolicyTypeByCarrier, - cloudprovider.DnsPolicyTypeByGeoLocation, - cloudprovider.DnsPolicyTypeBySearchEngine, - cloudprovider.DnsPolicyTypeWeighted, - }, - } -} - -func (self *SQcloudProviderFactory) GetSupportedDnsPolicyValues() map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue { - return map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue{ - cloudprovider.DnsPolicyTypeByCarrier: []cloudprovider.TDnsPolicyValue{ - cloudprovider.DnsPolicyValueUnicom, - cloudprovider.DnsPolicyValueTelecom, - cloudprovider.DnsPolicyValueChinaMobile, - cloudprovider.DnsPolicyValueCernet, - }, - cloudprovider.DnsPolicyTypeByGeoLocation: []cloudprovider.TDnsPolicyValue{ - cloudprovider.DnsPolicyValueOversea, - cloudprovider.DnsPolicyValueMainland, - }, - cloudprovider.DnsPolicyTypeBySearchEngine: []cloudprovider.TDnsPolicyValue{ - cloudprovider.DnsPolicyValueBaidu, - cloudprovider.DnsPolicyValueBing, - cloudprovider.DnsPolicyValueGoogle, - cloudprovider.DnsPolicyValueYoudao, - cloudprovider.DnsPolicyValueSousou, - cloudprovider.DnsPolicyValueSougou, - cloudprovider.DnsPolicyValueQihu360, - }, - } -} - -// https://buy.cloud.tencent.com/cns?from=gobuy&domain=example4.com -func (self *SQcloudProviderFactory) GetTTLRange(zoneType cloudprovider.TDnsZoneType, productType cloudprovider.TDnsProductType) cloudprovider.TTlRange { - if len(productType) > 0 { - switch productType { - case cloudprovider.DnsProductEnterpriseUltimate: - return cloudprovider.TtlRangeQcloudEnterpriseUltimate - case cloudprovider.DnsProductEnterpriseStandard: - return cloudprovider.TtlRangeQcloudEnterpriseStandard - case cloudprovider.DnsProductEnterpriseBasic: - return cloudprovider.TtlRangeQcloudEnterpriseBasic - case cloudprovider.DnsProductPersonalProfessional: - return cloudprovider.TtlRangeQcloudPersonalProfessional - case cloudprovider.DnsProductFree: - return cloudprovider.TtlRangeQcloudFree - default: - return cloudprovider.TtlRangeQcloudFree - } - } - return cloudprovider.TtlRangeQcloudFree -} - -func (self *SQcloudProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { - if len(instanceId) == 0 { - return fmt.Errorf("Only changes to the binding machine's EIP bandwidth are supported") - } - return nil -} - -func (self *SQcloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AppId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "app_id") - } - if len(input.SecretId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_id") - } - if len(input.SecretKey) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_key") - } - output.Account = fmt.Sprintf("%s/%s", input.SecretId, input.AppId) - output.Secret = input.SecretKey - return output, nil -} - -func (self *SQcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AppId) == 0 { - accountInfo := strings.Split(cloudaccount, "/") - if len(accountInfo) < 2 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "app_id") - } - input.AppId = accountInfo[1] - } - if len(input.SecretId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_id") - } - if len(input.SecretKey) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_key") - } - output = cloudprovider.SCloudaccount{ - Account: fmt.Sprintf("%s/%s", input.SecretId, input.AppId), - Secret: input.SecretKey, - } - return output, nil -} - -func (self *SQcloudProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - secretId := cfg.Account - appId := "" - if tmp := strings.Split(cfg.Account, "/"); len(tmp) == 2 { - secretId = tmp[0] - appId = tmp[1] - } - client, err := qcloud.NewQcloudClient( - qcloud.NewQcloudClientConfig( - secretId, cfg.Secret, - ).AppId(appId).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SQcloudProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SQcloudProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - secretId := info.Account - appId := "" - if tmp := strings.Split(info.Account, "/"); len(tmp) == 2 { - secretId = tmp[0] - appId = tmp[1] - } - return map[string]string{ - "QCLOUD_APPID": appId, - "QCLOUD_SECRET_ID": secretId, - "QCLOUD_SECRET_KEY": info.Secret, - "QCLOUD_REGION": qcloud.QCLOUD_DEFAULT_REGION, - }, nil -} - -func init() { - factory := SQcloudProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SQcloudProvider struct { - cloudprovider.SBaseProvider - client *qcloud.SQcloudClient -} - -func (self *SQcloudProvider) GetSysInfo() (jsonutils.JSONObject, error) { - regions := self.client.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") - info.Add(jsonutils.NewString(qcloud.QCLOUD_API_VERSION), "api_version") - return info, nil -} - -func (self *SQcloudProvider) GetVersion() string { - return qcloud.QCLOUD_API_VERSION -} - -func (self *SQcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SQcloudProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SQcloudProvider) GetIamLoginUrl() string { - return self.client.GetIamLoginUrl() -} - -func (self *SQcloudProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SQcloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(id) -} - -func (self *SQcloudProvider) GetBalance() (float64, string, error) { - balance, err := self.client.QueryAccountBalance() - if err != nil { - return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, err - } - status := api.CLOUD_PROVIDER_HEALTH_NORMAL - if balance.AvailableAmount < 0.0 { - status = api.CLOUD_PROVIDER_HEALTH_ARREARS - } - return balance.AvailableAmount, status, nil -} - -func (self *SQcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SQcloudProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return self.client.CreateIProject(name) -} - -func (self *SQcloudProvider) GetStorageClasses(regionId string) []string { - return []string{ - "STANDARD", "STANDARD_IA", "ARCHIVE", - } -} - -func (self *SQcloudProvider) GetBucketCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLAuthRead), - string(cloudprovider.ACLPublicRead), - } -} - -func (self *SQcloudProvider) GetObjectCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLAuthRead), - string(cloudprovider.ACLPublicRead), - } -} - -func (self *SQcloudProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SQcloudProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { - return self.client.CreateIClouduser(conf) -} - -func (self *SQcloudProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { - return self.client.GetICloudusers() -} - -func (self *SQcloudProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroups() -} - -func (self *SQcloudProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { - return self.client.GetICloudgroupByName(name) -} - -func (self *SQcloudProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { - return self.client.CreateICloudgroup(name, desc) -} - -func (self *SQcloudProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetISystemCloudpolicies() -} - -func (self *SQcloudProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { - return self.client.GetICustomCloudpolicies() -} - -func (self *SQcloudProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { - return self.client.GetIClouduserByName(name) -} - -func (self *SQcloudProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { - return self.client.CreateICloudpolicy(opts) -} - -func (self *SQcloudProvider) GetSamlEntityId() string { - return cloudprovider.SAML_ENTITY_ID_QCLOUD -} - -func (self *SQcloudProvider) GetICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { - return self.client.GetICloudDnsZones() -} - -func (self *SQcloudProvider) GetICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { - domain, err := self.client.GetDomain(id) - if err != nil { - return nil, err - } - return domain, nil -} - -func (self *SQcloudProvider) CreateICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { - return self.client.CreateICloudDnsZone(opts) -} - -func (self *SQcloudProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { - saml, err := self.client.CreateSAMLProvider(opts.Name, opts.Metadata.String(), "") - if err != nil { - return nil, errors.Wrap(err, "CreateSAMLProvider") - } - return saml, nil -} - -func (self *SQcloudProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { - return self.client.GetICloudSAMLProviders() -} - -func (self *SQcloudProvider) CreateICloudrole(opts *cloudprovider.SRoleCreateOptions) (cloudprovider.ICloudrole, error) { - if len(opts.SAMLProvider) > 0 { - document := fmt.Sprintf(`{"version":"2.0","statement":[{"action":"name/sts:AssumeRoleWithSAML","effect":"allow","principal":{"federated":["qcs::cam::uin/%s:saml-provider/%s"]},"condition":{}}]}`, self.client.GetAccountId(), opts.SAMLProvider) - role, err := self.client.CreateRole(opts.Name, document, opts.Desc) - if err != nil { - return nil, errors.Wrapf(err, "CreateRole") - } - return role, nil - } - role, err := self.client.CreateRole(opts.Name, "", opts.Desc) - if err != nil { - return nil, errors.Wrapf(err, "") - } - return role, nil -} - -func (self *SQcloudProvider) GetICloudroles() ([]cloudprovider.ICloudrole, error) { - return self.client.GetICloudroles() -} - -func (self *SQcloudProvider) GetICloudroleByName(name string) (cloudprovider.ICloudrole, error) { - role, err := self.client.GetRole(name) - if err != nil { - return nil, errors.Wrapf(err, "GetRole(%s)", name) - } - return role, nil -} - -func (self *SQcloudProvider) GetICloudroleById(id string) (cloudprovider.ICloudrole, error) { - return self.GetICloudroleByName(id) -} - -func (self *SQcloudProvider) GetICloudInterVpcNetworks() ([]cloudprovider.ICloudInterVpcNetwork, error) { - return self.client.GetICloudInterVpcNetworks() -} - -func (self *SQcloudProvider) GetICloudInterVpcNetworkById(id string) (cloudprovider.ICloudInterVpcNetwork, error) { - return self.client.GetICloudInterVpcNetworkById(id) -} - -func (self *SQcloudProvider) CreateICloudInterVpcNetwork(opts *cloudprovider.SInterVpcNetworkCreateOptions) (cloudprovider.ICloudInterVpcNetwork, error) { - return self.client.CreateICloudInterVpcNetwork(opts) -} - -func (self *SQcloudProvider) GetICloudCDNDomains() ([]cloudprovider.ICloudCDNDomain, error) { - return self.client.GetICloudCDNDomains() -} - -func (self *SQcloudProvider) GetICloudCDNDomainByName(name string) (cloudprovider.ICloudCDNDomain, error) { - return self.client.GetICloudCDNDomainByName(name) -} - -func (self *SQcloudProvider) CreateICloudCDNDomain(opts *cloudprovider.CdnCreateOptions) (cloudprovider.ICloudCDNDomain, error) { - return self.client.CreateCDNDomain(opts) -} - -func (self *SQcloudProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/qcloud/quota.go b/pkg/multicloud/qcloud/quota.go deleted file mode 100644 index 38f961e7a3..0000000000 --- a/pkg/multicloud/qcloud/quota.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "strings" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type ImageQuota struct { - region *SRegion - ImageNumQuota int -} - -func (iq *ImageQuota) GetGlobalId() string { - return "ImageNumQuota" -} - -func (iq *ImageQuota) GetName() string { - return "ImageNumQuota" -} - -func (iq *ImageQuota) GetDesc() string { - return "" -} - -func (iq *ImageQuota) GetQuotaType() string { - return "ImageNumQuota" -} - -func (iq *ImageQuota) GetMaxQuotaCount() int { - return iq.ImageNumQuota -} - -func (iq *ImageQuota) GetCurrentQuotaUsedCount() int { - _, count, err := iq.region.GetImages("", "PRIVATE_IMAGE", nil, "", 0, iq.ImageNumQuota) - if err != nil { - log.Errorf("get private image error: %v", err) - return -1 - } - return count -} - -func (region *SRegion) GetImageQuota() (*ImageQuota, error) { - params := map[string]string{} - resp, err := region.cvmRequest("DescribeImageQuota", params, true) - if err != nil { - return nil, errors.Wrap(err, "DescribeImageQuota") - } - imageQuota := &ImageQuota{region: region} - return imageQuota, resp.Unmarshal(imageQuota) -} - -type QuotaSet struct { - QuotaId string - QuotaCurrent int - QuotaLimit int -} - -func (qs *QuotaSet) GetGlobalId() string { - return strings.ToLower(qs.QuotaId) -} - -func (qs *QuotaSet) GetName() string { - return qs.QuotaId -} - -func (qs *QuotaSet) GetDesc() string { - return "" -} - -func (qs *QuotaSet) GetQuotaType() string { - return qs.QuotaId -} - -func (qs *QuotaSet) GetMaxQuotaCount() int { - return qs.QuotaLimit -} - -func (qs *QuotaSet) GetCurrentQuotaUsedCount() int { - return qs.QuotaCurrent -} - -func (region *SRegion) GetQuota(action string) ([]QuotaSet, error) { - params := map[string]string{} - resp, err := region.vpcRequest(action, params) - if err != nil { - return nil, errors.Wrap(err, action) - } - quotas := []QuotaSet{} - err = resp.Unmarshal("as, "QuotaSet") - if err != nil { - return nil, errors.Wrap(err, "resp.Unmarshal") - } - return quotas, nil -} - -func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { - ret := []cloudprovider.ICloudQuota{} - imageQ, err := region.GetImageQuota() - if err != nil { - return nil, errors.Wrap(err, "GetImageQuota") - } - ret = append(ret, imageQ) - for _, action := range []string{"DescribeAddressQuota", "DescribeBandwidthPackageQuota"} { - quotas, err := region.GetQuota(action) - if err != nil { - return nil, errors.Wrapf(err, "GetQuota(%s)", action) - } - for i := range quotas { - ret = append(ret, "as[i]) - } - } - return ret, nil -} diff --git a/pkg/multicloud/qcloud/rds_mysql.go b/pkg/multicloud/qcloud/rds_mysql.go deleted file mode 100644 index 9a98e46b4a..0000000000 --- a/pkg/multicloud/qcloud/rds_mysql.go +++ /dev/null @@ -1,923 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - "regexp" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/timeutils" - "yunion.io/x/pkg/utils" - - billingapi "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SlaveInstanceInfo struct { - Region string - Vip string - VpcId int - Vport int - Zone string -} - -type SlaveInfo struct { - First SlaveInstanceInfo - Second SlaveInstanceInfo -} - -type SDrInfo struct { - Status int - Zone string - InstanceId string - Region string - SyncStatus string - InstanceName string - InstanceType string -} - -type SMasterInfo struct { - Region string - RegionId int - ZoneId int - Zone string - InstanceId string - ResourceId string - Status int - InstanceName string - InstanceType int - TaskStatus int - Memory int - Volume int - DeviceType string - Qps int - VpcId int - SubnetId int - ExClusterId string - ExClusterName string -} - -type SRoGroup struct { - RoGroupMode string - RoGroupId string - RoGroupName string - RoOfflineDelay int - RoMaxDelayTime int - MinRoInGroup int - WeightMode string - Weight int - // RoInstances - Vip string - Vport int - UniqVpcId string - UniqSubnetId string - RoGroupRegion string - RoGroupZone string -} - -type SRoVipInfo struct { - RoVipStatus int - RoSubnetId int - RoVpcId int - RoVport int - RoVip string -} - -type SMySQLInstance struct { - region *SRegion - multicloud.SDBInstanceBase - multicloud.QcloudTags - - AutoRenew int - CdbError int - Cpu int - CreateTime time.Time - DeadlineTime string - DeployGroupId string - DeployMode int - DeviceClass string - DeviceType string - DrInfo []SDrInfo - EngineVersion string - ExClusterId string - HourFeeStatus int - InitFlag int - InstanceId string - InstanceName string - InstanceType int - IsolateTime string - MasterInfo SMasterInfo - Memory int - OfflineTime string - PayType int - PhysicalId string - ProjectId int - ProtectMode string - Qps int - Region string - RegionId string - ResourceId string - RoGroups []SRoGroup - RoVipInfo SRoVipInfo - SecurityGroupIds []string - SlaveInfo SlaveInfo - Status int - SubnetId int - //TagList": null, - TaskStatus int - UniqSubnetId string - UniqVpcId string - Vip string - Volume int - VpcId int - Vport int - WanDomain string - WanPort int - WanStatus int - Zone string - ZoneId int - ZoneName string -} - -func (self *SMySQLInstance) GetId() string { - return self.InstanceId -} - -func (self *SMySQLInstance) GetGlobalId() string { - return self.InstanceId -} - -func (self *SMySQLInstance) GetName() string { - if len(self.InstanceName) > 0 { - return self.InstanceName - } - return self.InstanceId -} - -func (self *SMySQLInstance) GetDiskSizeGB() int { - return self.Volume -} - -func (self *SMySQLInstance) GetEngine() string { - return api.DBINSTANCE_TYPE_MYSQL -} - -func (self *SMySQLInstance) GetEngineVersion() string { - return self.EngineVersion -} - -func (self *SMySQLInstance) GetIVpcId() string { - return self.UniqVpcId -} - -func (self *SMySQLInstance) Refresh() error { - rds, err := self.region.GetMySQLInstanceById(self.InstanceId) - if err != nil { - return errors.Wrapf(err, "GetMySQLInstanceById(%s)", self.InstanceId) - } - return jsonutils.Update(self, rds) -} - -func (self *SMySQLInstance) GetInstanceType() string { - return fmt.Sprintf("%d核%dMB", self.Cpu, self.Memory) -} - -func (self *SMySQLInstance) GetMaintainTime() string { - timeWindow, err := self.region.DescribeMySQLTimeWindow(self.InstanceId) - if err != nil { - log.Errorf("DescribeMySQLTimeWindow %s error: %v", self.InstanceId, err) - return "" - } - return timeWindow.String() -} - -func (self *SMySQLInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { - return []cloudprovider.SDBInstanceNetwork{ - cloudprovider.SDBInstanceNetwork{NetworkId: self.UniqSubnetId, IP: self.Vip}, - }, nil -} - -func (self *SMySQLInstance) GetConnectionStr() string { - if self.WanStatus == 1 { - return fmt.Sprintf("%s:%d", self.WanDomain, self.WanPort) - } - return "" -} - -func (self *SMySQLInstance) GetInternalConnectionStr() string { - return fmt.Sprintf("%s:%d", self.Vip, self.Vport) -} - -func (self *SMySQLInstance) Reboot() error { - return self.region.RebootMySQLInstance(self.InstanceId) -} - -func (self *SMySQLInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedDBInstanceChangeConfig) error { - mb := self.GetVmemSizeMB() - if len(opts.InstanceType) > 0 { - re := regexp.MustCompile(`(\d{1,4})核(\d{1,20})MB$`) - params := re.FindStringSubmatch(opts.InstanceType) - if len(params) != 3 { - return fmt.Errorf("invalid rds instance type %s", opts.InstanceType) - } - _mb, _ := strconv.Atoi(params[2]) - mb = int(_mb) - } - if opts.DiskSizeGB == 0 { - opts.DiskSizeGB = self.GetDiskSizeGB() - } - return self.region.UpgradeMySQLDBInstance(self.InstanceId, mb, opts.DiskSizeGB) -} - -func (self *SMySQLInstance) GetMasterInstanceId() string { - return self.MasterInfo.InstanceId -} - -func (self *SMySQLInstance) GetSecurityGroupIds() ([]string, error) { - if len(self.SecurityGroupIds) > 0 { - return self.SecurityGroupIds, nil - } - if self.DeviceType == "BASIC" { - return []string{}, nil - } - secgroups, err := self.region.DescribeMySQLDBSecurityGroups(self.InstanceId) - if err != nil { - return []string{}, errors.Wrapf(err, "DescribeMySQLDBSecurityGroups") - } - ids := []string{} - for i := range secgroups { - ids = append(ids, secgroups[i].SecurityGroupId) - } - return ids, nil -} - -func (self *SMySQLInstance) SetSecurityGroups(ids []string) error { - return self.region.ModifyMySQLInstanceSecurityGroups(self.InstanceId, ids) -} - -func (self *SRegion) ModifyMySQLInstanceSecurityGroups(rdsId string, secIds []string) error { - params := map[string]string{ - "InstanceId": rdsId, - } - for idx, id := range secIds { - params[fmt.Sprintf("SecurityGroupIds.%d", idx)] = id - } - _, err := self.cdbRequest("ModifyDBInstanceSecurityGroups", params) - return err -} - -func (self *SMySQLInstance) Renew(bc billing.SBillingCycle) error { - month := bc.GetMonths() - return self.region.RenewMySQLDBInstance(self.InstanceId, month) -} - -func (self *SMySQLInstance) OpenPublicConnection() error { - if self.WanStatus == 0 { - return self.region.OpenMySQLWanService(self.InstanceId) - } - return nil -} - -func (self *SMySQLInstance) ClosePublicConnection() error { - if self.WanStatus == 1 { - return self.region.CloseMySQLWanService(self.InstanceId) - } - return nil -} - -func (self *SMySQLInstance) GetPort() int { - return self.Vport -} - -func (self *SMySQLInstance) GetStatus() string { - if self.InitFlag == 0 { - return api.DBINSTANCE_INIT - } - switch self.Status { - case 4: - return api.DBINSTANCE_ISOLATING - case 5: - return api.DBINSTANCE_ISOLATE - } - switch self.TaskStatus { - case 0: - switch self.Status { - case 0: - return api.DBINSTANCE_DEPLOYING - case 1: - return api.DBINSTANCE_RUNNING - } - case 1: - return api.DBINSTANCE_UPGRADING - case 2: //数据导入中 - return api.DBINSTANCE_IMPORTING - case 3, 4: //开放关闭外网地址 - return api.DBINSTANCE_DEPLOYING - case 10: - return api.DBINSTANCE_REBOOTING - case 12: - return api.DBINSTANCE_MIGRATING - default: - return api.DBINSTANCE_DEPLOYING - } - return api.DBINSTANCE_UNKNOWN -} - -func (self *SMySQLInstance) GetCategory() string { - category := strings.ToLower(self.DeviceType) - if category == "universal" { - category = "ha" - } - return category -} - -func (self *SMySQLInstance) GetStorageType() string { - switch self.DeviceType { - case "BASIC": - return api.QCLOUD_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD - default: - return api.QCLOUD_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD - } -} - -func (self *SMySQLInstance) GetCreatedAt() time.Time { - // 2019-12-25 09:00:43 #非UTC时间 - return self.CreateTime.Add(time.Hour * -8) -} - -func (self *SMySQLInstance) GetBillingType() string { - if self.PayType == 0 { - return billingapi.BILLING_TYPE_PREPAID - } - return billingapi.BILLING_TYPE_POSTPAID -} - -func (self *SMySQLInstance) SetAutoRenew(bc billing.SBillingCycle) error { - return self.region.ModifyMySQLAutoRenewFlag([]string{self.InstanceId}, bc.AutoRenew) -} - -func (self *SMySQLInstance) IsAutoRenew() bool { - return self.AutoRenew == 1 -} - -func (self *SMySQLInstance) GetExpiredAt() time.Time { - offline, _ := timeutils.ParseTimeStr(self.OfflineTime) - if !offline.IsZero() { - return offline.Add(time.Hour * -8) - } - deadline, _ := timeutils.ParseTimeStr(self.DeadlineTime) - if !deadline.IsZero() { - return deadline.Add(time.Hour * -8) - } - return time.Time{} -} - -func (self *SMySQLInstance) GetVcpuCount() int { - return self.Cpu -} - -func (self *SMySQLInstance) GetVmemSizeMB() int { - return self.Memory -} - -func (self *SMySQLInstance) GetZone1Id() string { - return self.Zone -} - -func (self *SMySQLInstance) GetZone2Id() string { - return self.SlaveInfo.First.Zone -} - -func (self *SMySQLInstance) GetZone3Id() string { - return self.SlaveInfo.Second.Zone -} - -func (self *SMySQLInstance) GetProjectId() string { - return fmt.Sprintf("%d", self.ProjectId) -} - -func (self *SMySQLInstance) Delete() error { - err := self.region.IsolateMySQLDBInstance(self.InstanceId) - if err != nil { - return errors.Wrapf(err, "IsolateMySQLDBInstance") - } - return self.region.OfflineIsolatedMySQLInstances([]string{self.InstanceId}) -} - -func (self *SRegion) ListMySQLInstances(ids []string, offset, limit int) ([]SMySQLInstance, int, error) { - if limit < 1 || limit > 50 { - limit = 50 - } - params := map[string]string{ - "Offset": fmt.Sprintf("%d", offset), - "Limit": fmt.Sprintf("%d", limit), - } - for idx, id := range ids { - params[fmt.Sprintf("InstanceIds.%d", idx)] = id - } - resp, err := self.cdbRequest("DescribeDBInstances", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeDBInstances") - } - items := []SMySQLInstance{} - err = resp.Unmarshal(&items, "Items") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - total, _ := resp.Float("TotalCount") - return items, int(total), nil -} - -type SAsyncRequestResult struct { - Info string - Status string -} - -func (self *SRegion) DescribeMySQLAsyncRequestInfo(id string) (*SAsyncRequestResult, error) { - resp, err := self.cdbRequest("DescribeAsyncRequestInfo", map[string]string{"AsyncRequestId": id}) - if err != nil { - return nil, errors.Wrapf(err, "DescribeAsyncRequestInfo") - } - result := SAsyncRequestResult{} - err = resp.Unmarshal(&result) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return &result, nil -} - -func (self *SRegion) waitAsyncAction(action string, resId, asyncRequestId string) error { - if len(asyncRequestId) == 0 { - return errors.Error("Missing AsyncRequestId") - } - return cloudprovider.Wait(time.Second*10, time.Minute*20, func() (bool, error) { - result, err := self.DescribeMySQLAsyncRequestInfo(asyncRequestId) - if err != nil { - return false, errors.Wrapf(err, action) - } - log.Debugf("task %s(%s) for mysql instance %s status: %s", action, asyncRequestId, resId, result.Status) - switch result.Status { - case "FAILED", "KILLED", "REMOVED", "PAUSED": - return true, errors.Errorf(result.Info) - case "SUCCESS": - return true, nil - default: - return false, nil - } - }) -} - -func (self *SRegion) RebootMySQLInstance(id string) error { - resp, err := self.cdbRequest("RestartDBInstances", map[string]string{"InstanceIds.0": id}) - if err != nil { - return errors.Wrapf(err, "RestartDBInstances") - } - asyncRequestId, _ := resp.GetString("AsyncRequestId") - return self.waitAsyncAction("RestartDBInstances", id, asyncRequestId) -} - -func (self *SRegion) DescribeMySQLDBInstanceInfo(id string) (*SMySQLInstance, error) { - resp, err := self.cdbRequest("DescribeDBInstanceInfo", map[string]string{"InstanceId": id}) - if err != nil { - return nil, errors.Wrapf(err, "DescribeDBInstanceInfo") - } - result := SMySQLInstance{region: self} - err = resp.Unmarshal(&result) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return &result, nil -} - -func (self *SRegion) RenewMySQLDBInstance(id string, month int) error { - params := map[string]string{ - "InstanceId": id, - "TimeSpan": fmt.Sprintf("%d", month), - } - _, err := self.cdbRequest("RenewDBInstance", params) - if err != nil { - return errors.Wrapf(err, "RenewDBInstance") - } - return nil -} - -func (self *SRegion) OfflineIsolatedMySQLInstances(ids []string) error { - params := map[string]string{} - for idx, id := range ids { - params[fmt.Sprintf("InstanceIds.%d", idx)] = id - } - _, err := self.cdbRequest("OfflineIsolatedInstances", params) - if err != nil { - return errors.Wrapf(err, "OfflineIsolatedInstances") - } - return nil -} - -func (self *SRegion) ReleaseIsolatedMySQLDBInstances(ids []string) error { - params := map[string]string{} - for idx, id := range ids { - params[fmt.Sprintf("InstanceIds.%d", idx)] = id - } - resp, err := self.cdbRequest("ReleaseIsolatedDBInstances", params) - if err != nil { - return errors.Wrapf(err, "ReleaseIsolatedDBInstances") - } - result := []struct { - InstanceId string - Code int - Message string - }{} - err = resp.Unmarshal(&result, "Items") - if err != nil { - return errors.Wrapf(err, "resp.Unmarshal") - } - msg := []string{} - for i := range result { - if result[i].Code != 0 { - msg = append(msg, fmt.Sprintf("instance %s release isolate error: %s", result[i].InstanceId, result[i].Message)) - } - } - if len(msg) > 0 { - return errors.Error(strings.Join(msg, " ")) - } - return cloudprovider.Wait(time.Second, time.Minute*10, func() (bool, error) { - instances, _, err := self.ListMySQLInstances(ids, 0, len(ids)) - if err != nil { - return false, errors.Wrapf(err, "ListMySQLInstances") - } - for i := range instances { - if instances[i].Status == 4 || instances[i].Status == 5 { - log.Debugf("mysql instance %s(%s) current be isolate", instances[i].InstanceName, instances[i].InstanceId) - return false, nil - } - } - return true, nil - }) -} - -func (self *SRegion) IsolateMySQLDBInstance(id string) error { - params := map[string]string{"InstanceId": id} - resp, err := self.cdbRequest("IsolateDBInstance", params) - if err != nil { - return errors.Wrapf(err, "IsolateDBInstance") - } - asyncRequestId, _ := resp.GetString("AsyncRequestId") - if len(asyncRequestId) > 0 { - return self.waitAsyncAction("IsolateDBInstance", id, asyncRequestId) - } - return cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) { - instances, _, err := self.ListMySQLInstances([]string{id}, 0, 1) - if err != nil { - return false, errors.Wrapf(err, "ListMySQLInstances(%s)", id) - } - statusMap := map[int]string{0: "创建中", 1: "运行中", 4: "隔离中", 5: "已隔离"} - for _, rds := range instances { - status, _ := statusMap[rds.Status] - log.Debugf("instance %s(%s) status %d(%s)", rds.InstanceName, rds.InstanceId, rds.Status, status) - if rds.Status != 5 { - return false, nil - } - } - return true, nil - }) -} - -func (self *SRegion) CloseMySQLWanService(id string) error { - params := map[string]string{"InstanceId": id} - resp, err := self.cdbRequest("CloseWanService", params) - if err != nil { - return errors.Wrapf(err, "CloseWanService") - } - asyncRequestId, _ := resp.GetString("AsyncRequestId") - return self.waitAsyncAction("CloseWanService", id, asyncRequestId) -} - -func (self *SRegion) OpenMySQLWanService(id string) error { - params := map[string]string{"InstanceId": id} - resp, err := self.cdbRequest("OpenWanService", params) - if err != nil { - return errors.Wrapf(err, "OpenWanService") - } - asyncRequestId, _ := resp.GetString("AsyncRequestId") - return self.waitAsyncAction("OpenWanService", id, asyncRequestId) -} - -func (self *SRegion) InitMySQLDBInstances(ids []string, password string, parameters map[string]string, vport int) error { - params := map[string]string{"NewPassword": password} - for idx, id := range ids { - params[fmt.Sprintf("InstanceIds.%d", idx)] = id - } - i := 0 - for k, v := range parameters { - params[fmt.Sprintf("Parameters.%d.name", i)] = k - params[fmt.Sprintf("Parameters.%d.value", i)] = v - i++ - } - if vport >= 1024 && vport <= 65535 { - params["Vport"] = fmt.Sprintf("%d", vport) - } - resp, err := self.cdbRequest("InitDBInstances", params) - if err != nil { - return errors.Wrapf(err, "InitDBInstances") - } - asyncRequestIds := []string{} - err = resp.Unmarshal(&asyncRequestIds, "AsyncRequestIds") - if err != nil { - return errors.Wrapf(err, "resp.Unmarshal") - } - for idx, requestId := range asyncRequestIds { - err = self.waitAsyncAction("InitDBInstances", fmt.Sprintf("%d", idx), requestId) - if err != nil { - return err - } - } - return nil -} - -func (self *SRegion) UpgradeMySQLDBInstance(id string, memoryMb int, volumeGb int) error { - params := map[string]string{ - "InstanceId": id, - "Memory": fmt.Sprintf("%d", memoryMb), - "Volume": fmt.Sprintf("%d", volumeGb), - } - resp, err := self.cdbRequest("UpgradeDBInstance", params) - if err != nil { - return errors.Wrapf(err, "UpgradeDBInstance") - } - asyncRequestId, _ := resp.GetString("AsyncRequestId") - return self.waitAsyncAction("UpgradeDBInstance", id, asyncRequestId) -} - -func (self *SRegion) ModifyMySQLAutoRenewFlag(ids []string, autoRenew bool) error { - params := map[string]string{} - for idx, id := range ids { - params[fmt.Sprintf("InstanceIds.%d", idx)] = id - } - params["AutoRenew"] = "0" - if autoRenew { - params["AutoRenew"] = "1" - } - _, err := self.cdbRequest("ModifyAutoRenewFlag", params) - return err -} - -type SMaintenanceTime struct { - Monday []string - Tuesday []string - Wednesday []string - Thursday []string - Friday []string - Saturday []string - Sunday []string -} - -func (w SMaintenanceTime) String() string { - windows := []string{} - for k, v := range map[string][]string{ - "Monday": w.Monday, - "Tuesday": w.Tuesday, - "Wednesday": w.Wednesday, - "Thursday": w.Thursday, - "Friday": w.Friday, - "Saturday": w.Saturday, - "Sunday": w.Sunday, - } { - if len(v) > 0 { - windows = append(windows, fmt.Sprintf("%s: %s", k, strings.Join(v, " "))) - } - } - return strings.Join(windows, "\n") -} - -func (self *SRegion) DescribeMySQLTimeWindow(id string) (*SMaintenanceTime, error) { - params := map[string]string{"InstanceId": id} - resp, err := self.cdbRequest("DescribeTimeWindow", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeTimeWindow") - } - timeWindow := &SMaintenanceTime{} - err = resp.Unmarshal(timeWindow) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return timeWindow, nil -} - -type SDBSecgroup struct { - ProjectId int - CreateTime time.Time - SecurityGroupId string - SecurityGroupName string - SecurityGroupRemark string -} - -func (self *SRegion) DescribeMySQLDBSecurityGroups(instanceId string) ([]SDBSecgroup, error) { - params := map[string]string{ - "InstanceId": instanceId, - } - resp, err := self.cdbRequest("DescribeDBSecurityGroups", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeDBSecurityGroups") - } - result := []SDBSecgroup{} - err = resp.Unmarshal(&result, "Groups") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return result, nil -} - -func (self *SRegion) CreateMySQLDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (*SMySQLInstance, error) { - params := map[string]string{ - "InstanceName": opts.Name, - "GoodsNum": "1", - "Memory": fmt.Sprintf("%d", opts.VmemSizeMb), - "Volume": fmt.Sprintf("%d", opts.DiskSizeGB), - "EngineVersion": opts.EngineVersion, - } - if len(opts.VpcId) > 0 { - params["UniqVpcId"] = opts.VpcId - } - if len(opts.NetworkId) > 0 { - params["UniqSubnetId"] = opts.NetworkId - } - if len(opts.ProjectId) > 0 { - params["ProjectId"] = opts.ProjectId - } - if opts.Port > 1024 && opts.Port < 65535 { - params["Port"] = fmt.Sprintf("%d", opts.Port) - } - if len(opts.Password) > 0 { - params["Password"] = opts.Password - } - for i, secId := range opts.SecgroupIds { - params[fmt.Sprintf("SecurityGroup.%d", i)] = secId - } - action := "CreateDBInstanceHour" - if opts.BillingCycle != nil { - params["Period"] = fmt.Sprintf("%d", opts.BillingCycle.GetMonths()) - params["AutoRenewFlag"] = "0" - if opts.BillingCycle.AutoRenew { - params["AutoRenewFlag"] = "1" - } - action = "CreateDBInstance" - } - if len(opts.Zone1) > 0 { - params["Zone"] = opts.Zone1 - } - params["DeployMode"] = "0" - switch opts.Category { - case api.QCLOUD_DBINSTANCE_CATEGORY_BASIC: - params["DeviceType"] = strings.ToUpper(opts.Category) - case api.QCLOUD_DBINSTANCE_CATEGORY_HA: - params["DeviceType"] = strings.ToUpper(opts.Category) - if len(opts.Zone2) > 0 { - params["SlaveZone"] = opts.Zone2 - } - case api.QCLOUD_DBINSTANCE_CATEGORY_FINANCE: - params["DeviceType"] = "HA" - params["ProtectMode"] = "2" - if len(opts.Zone2) > 0 { - params["SlaveZone"] = opts.Zone2 - } - if len(opts.Zone3) > 0 { - params["BackupZone"] = opts.Zone3 - } - } - if len(opts.Zone1) > 0 && len(opts.Zone2) > 0 && opts.Zone1 != opts.Zone2 { - params["DeployMode"] = "1" - } - params["ClientToken"] = utils.GenRequestId(20) - - i := 0 - for k, v := range opts.Tags { - params[fmt.Sprintf("ResourceTags.%d.TagKey", i)] = k - params[fmt.Sprintf("ResourceTags.%d.TagValue", i)] = v - i++ - } - - var create = func(action string, params map[string]string) (jsonutils.JSONObject, error) { - startTime := time.Now() - var resp jsonutils.JSONObject - var err error - for time.Now().Sub(startTime) < time.Minute*10 { - resp, err = self.cdbRequest(action, params) - if err != nil { - if strings.Contains(err.Error(), "OperationDenied.OtherOderInProcess") || strings.Contains(err.Error(), "Message=请求已经在处理中") { - time.Sleep(time.Second * 20) - continue - } - return nil, errors.Wrapf(err, "cdbRequest") - } - return resp, nil - } - return resp, err - } - - resp, err := create(action, params) - if err != nil { - return nil, errors.Wrapf(err, "cdbRequest") - } - instanceIds := []string{} - err = resp.Unmarshal(&instanceIds, "InstanceIds") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - if len(instanceIds) == 0 { - return nil, fmt.Errorf("%s not return InstanceIds", action) - } - err = cloudprovider.Wait(time.Second*10, time.Minute*20, func() (bool, error) { - instances, _, err := self.ListMySQLInstances(instanceIds, 0, 1) - if err != nil { - return false, errors.Wrapf(err, "ListMySQLInstances(%s)", instanceIds) - } - for _, rds := range instances { - log.Debugf("instance %s(%s) task status: %d", rds.InstanceName, rds.InstanceId, rds.TaskStatus) - if rds.TaskStatus == 1 { - return false, nil - } - } - return true, nil - }) - if err != nil { - return nil, errors.Wrapf(err, "cloudprovider.Wait After create") - } - return self.GetMySQLInstanceById(instanceIds[0]) -} - -func (self *SRegion) GetMySQLInstanceById(id string) (*SMySQLInstance, error) { - part, total, err := self.ListMySQLInstances([]string{id}, 0, 20) - if err != nil { - return nil, errors.Wrapf(err, "ListMySQLInstances") - } - if total > 1 { - return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "id: [%s]", id) - } - if total < 1 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) - } - part[0].region = self - return &part[0], nil -} - -func (self *SMySQLInstance) CreateDatabase(opts *cloudprovider.SDBInstanceDatabaseCreateConfig) error { - return cloudprovider.ErrNotSupported -} - -func (self *SMySQLInstance) CreateAccount(opts *cloudprovider.SDBInstanceAccountCreateConfig) error { - return self.region.CreateMySQLAccount(self.InstanceId, opts) -} - -func (self *SMySQLInstance) CreateIBackup(opts *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { - tables := map[string]string{} - for _, d := range opts.Databases { - tables[d] = "" - } - return self.region.CreateMySQLBackup(self.InstanceId, tables) -} - -func (self *SMySQLInstance) SetTags(tags map[string]string, replace bool) error { - return self.region.SetResourceTags("cdb", "instanceId", []string{self.InstanceId}, tags, replace) -} - -func (self *SRegion) GetIMySQLs() ([]cloudprovider.ICloudDBInstance, error) { - ret := []cloudprovider.ICloudDBInstance{} - mysql := []SMySQLInstance{} - for { - part, total, err := self.ListMySQLInstances([]string{}, len(mysql), 50) - if err != nil { - return nil, errors.Wrapf(err, "ListMySQLInstances") - } - mysql = append(mysql, part...) - if len(mysql) >= total { - break - } - } - for i := range mysql { - mysql[i].region = self - ret = append(ret, &mysql[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/qcloud/region.go b/pkg/multicloud/qcloud/region.go deleted file mode 100644 index e611692cb3..0000000000 --- a/pkg/multicloud/qcloud/region.go +++ /dev/null @@ -1,1244 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - "strconv" - "strings" - "time" - - sdkerrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" - "github.com/tencentyun/cos-go-sdk-v5" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - multicloud.SRegion - - client *SQcloudClient - - izones []cloudprovider.ICloudZone - ivpcs []cloudprovider.ICloudVpc - - storageCache *SStoragecache - - instanceTypes []SInstanceType - - Region string - RegionName string - RegionState string - - Latitude float64 - Longitude float64 - fetchLocation bool -} - -func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - lbs, err := self.GetLoadbalancers(nil) - if err != nil { - return nil, err - } - - ilbs := make([]cloudprovider.ICloudLoadbalancer, len(lbs)) - for i := range lbs { - lbs[i].region = self - ilbs[i] = &lbs[i] - } - - return ilbs, nil -} - -// 腾讯云不支持acl -func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { - return []cloudprovider.ICloudLoadbalancerAcl{}, nil -} - -func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - certs, err := self.GetCertificates("", "", "") - if err != nil { - return nil, errors.Wrap(err, "GetCertificates") - } - - icerts := make([]cloudprovider.ICloudLoadbalancerCertificate, len(certs)) - for i := range certs { - icerts[i] = &certs[i] - } - - return icerts, nil -} - -func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - cert, err := self.GetCertificate(certId) - if err != nil { - return nil, errors.Wrap(err, "GetCertificate") - } - - return cert, nil -} - -func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { - lbs, err := self.GetLoadbalancers([]string{loadbalancerId}) - if err != nil { - return nil, err - } - - if len(lbs) == 1 { - lbs[0].region = self - return &lbs[0], nil - } else if len(lbs) == 0 { - return nil, cloudprovider.ErrNotFound - } else { - log.Debugf("GetILoadBalancerById %s %d loadbalancer found", loadbalancerId, len(lbs)) - return nil, cloudprovider.ErrNotFound - } -} - -func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, nil -} - -// https://cloud.tencent.com/document/api/214/30692 -// todo: 1. 支持跨地域绑定负载均衡 及 https://cloud.tencent.com/document/product/214/12014 -// todo: 2. 支持指定Project。 ProjectId可以通过 DescribeProject 接口获取。不填则属于默认项目。 -func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - params := map[string]string{ - "LoadBalancerName": loadbalancer.Name, - "VpcId": loadbalancer.VpcID, - } - - LoadBalancerType := "INTERNAL" - if loadbalancer.AddressType == api.LB_ADDR_TYPE_INTERNET { - LoadBalancerType = "OPEN" - switch loadbalancer.ChargeType { - case api.LB_CHARGE_TYPE_BY_BANDWIDTH: - pkgs, _, err := self.GetBandwidthPackages([]string{}, 0, 50) - if err != nil { - return nil, errors.Wrapf(err, "GetBandwidthPackages") - } - bps := loadbalancer.EgressMbps - if bps == 0 { - bps = 200 - } - if len(pkgs) > 0 { - pkgId := pkgs[0].BandwidthPackageId - for _, pkg := range pkgs { - if len(pkg.ResourceSet) < 100 { - pkgId = pkg.BandwidthPackageId - break - } - } - params["BandwidthPackageId"] = pkgId - params["InternetAccessible.InternetChargeType"] = "BANDWIDTH_PACKAGE" - params["InternetAccessible.InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bps) - } else { - params["InternetAccessible.InternetChargeType"] = "BANDWIDTH_POSTPAID_BY_HOUR" - params["InternetAccessible.InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bps) - } - default: - bps := loadbalancer.EgressMbps - if bps == 0 { - bps = 200 - } - params["InternetAccessible.InternetChargeType"] = "TRAFFIC_POSTPAID_BY_HOUR" - params["InternetAccessible.InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bps) - - } - } - - params["LoadBalancerType"] = LoadBalancerType - - if len(loadbalancer.ProjectId) > 0 { - params["ProjectId"] = loadbalancer.ProjectId - } - - if loadbalancer.AddressType != api.LB_ADDR_TYPE_INTERNET { - params["SubnetId"] = loadbalancer.NetworkIDs[0] - } else { - // 公网类型ELB可支持多可用区 - if len(loadbalancer.ZoneID) > 0 { - if len(loadbalancer.SlaveZoneID) > 0 { - params["MasterZoneId"] = loadbalancer.ZoneID - } else { - params["ZoneId"] = loadbalancer.ZoneID - } - } - } - i := 0 - for k, v := range loadbalancer.Tags { - params[fmt.Sprintf("Tags.%d.TagKey", i)] = k - params[fmt.Sprintf("Tags.%d.TagValue", i)] = v - i++ - } - - resp, err := func() (jsonutils.JSONObject, error) { - _resp, err := self.clbRequest("CreateLoadBalancer", params) - if err != nil { - // 兼容不支持指定zone的账号 - if e, ok := err.(*sdkerrors.TencentCloudSDKError); ok && e.Code == "InvalidParameterValue" { - delete(params, "ZoneId") - delete(params, "MasterZoneId") - return self.clbRequest("CreateLoadBalancer", params) - } - } - return _resp, err - }() - if err != nil { - return nil, err - } - - requestId, err := resp.GetString("RequestId") - if err != nil { - return nil, err - } - - lbs, err := resp.GetArray("LoadBalancerIds") - if err != nil || len(lbs) != 1 { - log.Debugf("CreateILoadBalancer %s", resp.String()) - return nil, err - } - - err = self.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) - if err != nil { - return nil, err - } - - lbId, err := lbs[0].GetString() - if err != nil { - return nil, err - } - - return self.GetLoadbalancer(lbId) -} - -func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -// todo:目前onecloud端只能指定服务器端证书。需要兼容客户端证书? -// todo:支持指定Project。 -// todo: 已过期的证书不能上传也不能关联资源 -func (self *SRegion) CreateILoadBalancerCertificate(input *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - certId, err := self.CreateCertificate("", input.Certificate, input.PrivateKey, "SVR", input.Name) - if err != nil { - return nil, err - } - - cert, err := self.GetCertificate(certId) - if err != nil { - log.Debugf("GetCertificate %s failed", certId) - return nil, err - } - - return cert, nil -} - -func (self *SRegion) GetId() string { - return self.Region -} - -func (self *SRegion) GetName() string { - return self.RegionName -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - en := self.RegionName - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_QCLOUD, self.Region) -} - -func (self *SRegion) IsEmulated() bool { - return false -} - -func (self *SRegion) GetProvider() string { - return CLOUD_PROVIDER_QCLOUD -} - -func (self *SRegion) GetCloudEnv() string { - return "" -} - -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - params := make(map[string]string) - if len(opts.CIDR) > 0 { - params["CidrBlock"] = opts.CIDR - } - if len(opts.NAME) > 0 { - params["VpcName"] = opts.NAME - } - body, err := self.vpcRequest("CreateVpc", params) - if err != nil { - return nil, err - } - vpcId, err := body.GetString("Vpc", "VpcId") - if err != nil { - return nil, err - } - err = self.fetchInfrastructure() - if err != nil { - return nil, err - } - return self.GetIVpcById(vpcId) -} - -func (self *SRegion) GetCosClient(bucket *SBucket) (*cos.Client, error) { - return self.client.getCosClient(bucket) -} - -func (self *SRegion) GetClient() *SQcloudClient { - return self.client -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - return self.GetInstance(id) -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return self.GetDisk(id) -} - -func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { - if len(eipId) == 0 { - return nil, cloudprovider.ErrNotFound - } - eips, total, err := self.GetEips(eipId, "", 0, 1) - 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) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, total, err := self.GetEips("", "", 0, 50) - if err != nil { - return nil, err - } - for len(eips) < total { - var parts []SEipAddress - parts, total, err = self.GetEips("", "", len(eips), 50) - if err != nil { - return nil, err - } - eips = append(eips, parts...) - } - ret := make([]cloudprovider.ICloudEIP, len(eips)) - for i := 0; i < len(eips); i++ { - ret[i] = &eips[i] - } - return ret, nil -} - -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 errors.Cause(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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - iHosts := make([]cloudprovider.ICloudHost, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneHost, err := izones[i].GetIHosts() - if err != nil { - return nil, err - } - iHosts = append(iHosts, iZoneHost...) - } - return iHosts, nil -} - -func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - if storageCache.GetGlobalId() == id { - return self.storageCache, nil - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - return []cloudprovider.ICloudStoragecache{storageCache}, nil -} - -func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname string) error { - params := make(map[string]string) - params["InstanceId"] = instId - if len(name) > 0 { - params["InstanceName"] = name - } - if len(desc) > 0 { - params["Description"] = desc - } - if len(passwd) > 0 { - params["Password"] = passwd - } - if len(hostname) > 0 { - params["HostName"] = hostname - } - _, err := self.cvmRequest("ModifyInstanceAttribute", params, true) - return err -} - -func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error { - return self.updateInstance(instId, "", "", passwd, "") -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - ivpcs, err := self.GetIVpcs() - if err != nil { - return nil, err - } - for i := 0; i < len(ivpcs); i++ { - if ivpcs[i].GetGlobalId() == id { - return ivpcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -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.Zone == id { - return zone, nil - } - } - return nil, fmt.Errorf("no such zone %s", id) -} - -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) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if self.izones == nil { - var err error - err = self.fetchInfrastructure() - if err != nil { - return nil, err - } - } - return self.izones, nil -} - -func (self *SRegion) _fetchZones() error { - params := make(map[string]string) - zones := make([]SZone, 0) - body, err := self.cvmRequest("DescribeZones", params, true) - if err != nil { - return err - } - err = body.Unmarshal(&zones, "ZoneSet") - if err != nil { - return err - } - self.izones = make([]cloudprovider.ICloudZone, len(zones)) - for i := 0; i < len(zones); i++ { - zones[i].region = self - self.izones[i] = &zones[i] - } - return nil -} - -func (self *SRegion) fetchInfrastructure() error { - err := self._fetchZones() - if err != nil { - return err - } - err = self.fetchIVpcs() - if 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) DeleteVpc(vpcId string) error { - params := make(map[string]string) - params["VpcId"] = vpcId - - _, err := self.vpcRequest("DeleteVpc", params) - return err -} - -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.ErrDuplicateId - } - if total == 0 { - return nil, cloudprovider.ErrNotFound - } - vpcs[0].region = self - return &vpcs[0], nil -} - -func (self *SRegion) fetchIVpcs() error { - vpcs := make([]SVpc, 0) - for { - part, total, err := self.GetVpcs(nil, len(vpcs), 50) - if err != nil { - return err - } - vpcs = append(vpcs, part...) - if len(vpcs) >= total { - break - } - } - self.ivpcs = make([]cloudprovider.ICloudVpc, len(vpcs)) - for i := 0; i < len(vpcs); i += 1 { - vpcs[i].region = self - self.ivpcs[i] = &vpcs[i] - } - return nil -} - -func (self *SRegion) GetVpcs(vpcIds []string, offset int, limit int) ([]SVpc, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - if vpcIds != nil && len(vpcIds) > 0 { - for index, vpcId := range vpcIds { - params[fmt.Sprintf("VpcIds.%d", index)] = vpcId - } - } - body, err := self.vpcRequest("DescribeVpcs", params) - if err != nil { - return nil, 0, err - } - vpcs := make([]SVpc, 0) - err = body.Unmarshal(&vpcs, "VpcSet") - if err != nil { - log.Errorf("Unmarshal vpc fail %s", err) - return nil, 0, err - } - total, _ := body.Float("TotalCount") - return vpcs, int(total), nil -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - if info, ok := LatitudeAndLongitude[self.Region]; ok { - return info - } - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetStatus() string { - if self.RegionState == "AVAILABLE" { - return api.CLOUD_REGION_STATUS_INSERVER - } - return api.CLOUD_REGION_STATUS_OUTOFSERVICE -} - -func (self *SRegion) Refresh() error { - // do nothing - return nil -} - -// 容器 -func (self *SRegion) tkeRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.tkeRequest(apiName, params) -} - -func (self *SRegion) vpcRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.vpcRequest(apiName, params) -} - -func (self *SRegion) auditRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.auditRequest(apiName, params) -} - -func (self *SRegion) vpc2017Request(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.vpc2017Request(apiName, params) -} - -func (self *SRegion) cvmRequest(apiName string, params map[string]string, retry bool) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.jsonRequest(apiName, params, retry) -} - -func (self *SRegion) accountRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - return self.client.accountRequestRequest(apiName, params) -} - -func (self *SRegion) cbsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.cbsRequest(apiName, params) -} - -func (self *SRegion) clbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.clbRequest(apiName, params) -} - -func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.lbRequest(apiName, params) -} - -func (self *SRegion) cdbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.cdbRequest(apiName, params) -} - -func (self *SRegion) mariadbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.mariadbRequest(apiName, params) -} - -func (self *SRegion) postgresRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.postgresRequest(apiName, params) -} - -func (self *SRegion) sqlserverRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.sqlserverRequest(apiName, params) -} - -// deprecated -func (self *SRegion) wssRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - return self.client.wssRequest(apiName, params) -} - -func (self *SRegion) sslRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - return self.client.sslRequest(apiName, params) -} - -func (self *SRegion) kafkaRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.kafkaRequest(apiName, params) -} - -func (self *SRegion) redisRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.redisRequest(apiName, params) -} - -func (self *SRegion) dcdbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.dcdbRequest(apiName, params) -} - -func (self *SRegion) mongodbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.mongodbRequest(apiName, params) -} - -// Elasticsearch -func (self *SRegion) esRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.esRequest(apiName, params) -} - -func (self *SRegion) memcachedRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { - params["Region"] = self.Region - return self.client.memcachedRequest(apiName, params) -} - -func (self *SRegion) GetNetworks(ids []string, vpcId string, offset int, limit int) ([]SNetwork, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - base := 0 - if ids != nil && len(ids) > 0 { - for index, networkId := range ids { - params[fmt.Sprintf("SubnetIds.%d", index)] = networkId - } - base += len(ids) - } - if len(vpcId) > 0 { - params["Filters.0.Name"] = "vpc-id" - params["Filters.0.Values.0"] = vpcId - } - - body, err := self.vpcRequest("DescribeSubnets", params) - if err != nil { - log.Errorf("DescribeSubnets fail %s", err) - return nil, 0, err - } - - networks := make([]SNetwork, 0) - err = body.Unmarshal(&networks, "SubnetSet") - if err != nil { - log.Errorf("Unmarshal network fail %s", err) - return nil, 0, err - } - total, _ := body.Float("TotalCount") - return networks, int(total), nil -} - -func (self *SRegion) GetNetwork(networkId string) (*SNetwork, error) { - networks, total, err := self.GetNetworks([]string{networkId}, "", 0, 1) - if err != nil { - return nil, err - } - if total > 1 { - return nil, cloudprovider.ErrDuplicateId - } - if total == 0 { - return nil, cloudprovider.ErrNotFound - } - return &networks[0], nil -} - -func (self *SRegion) getStoragecache() *SStoragecache { - if self.storageCache == nil { - self.storageCache = &SStoragecache{region: self} - } - return self.storageCache -} - -func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, gpu int, zoneId string) ([]SInstanceType, error) { - if self.instanceTypes == nil { - types, err := self.GetInstanceTypes() - if err != nil { - log.Errorf("GetInstanceTypes %s", err) - return nil, err - } - self.instanceTypes = types - } - - var available []string - if len(zoneId) > 0 { - zone, err := self.getZoneById(zoneId) - if err != nil { - return nil, err - } - available = zone.getAvaliableInstanceTypes() - } - ret := make([]SInstanceType, 0) - for _, t := range self.instanceTypes { - if t.CPU == cpu && memMB == t.memoryMB() && gpu == t.GPU { - if available == nil || utils.IsInStringArray(t.InstanceType, available) { - ret = append(ret, t) - } - } - } - return ret, nil -} - -func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, memGB int, storageType string, dataDiskSizesGB []int, networkId string, passwd string, publicKey string, secgroup string, tags map[string]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.Zone) - net := z.getNetworkById(networkId) - if net != nil { - desc := &cloudprovider.SManagedVMCreateConfig{ - Name: name, - ExternalImageId: imgId, - SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType}, - Cpu: cpu, - MemoryMB: memGB * 1024, - ExternalNetworkId: networkId, - Password: passwd, - DataDisks: []cloudprovider.SDiskInfo{}, - PublicKey: publicKey, - - Tags: tags, - - ExternalSecgroupId: secgroup, - } - for _, sizeGB := range dataDiskSizesGB { - desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType}) - } - inst, err := z.getHost().CreateVM(desc) - if err != nil { - return nil, err - } - return inst.(*SInstance), nil - } - } - return nil, fmt.Errorf("cannot find network %s", networkId) -} - -func (self *SRegion) instanceOperation(instanceId string, opname string, extra map[string]string, retry bool) error { - params := make(map[string]string) - params["InstanceIds.0"] = instanceId - if extra != nil && len(extra) > 0 { - for k, v := range extra { - params[k] = v - } - } - _, err := self.cvmRequest(opname, params, retry) - return err -} - -func (self *SRegion) GetInstanceVNCUrl(instanceId string) (string, error) { - params := make(map[string]string) - params["InstanceId"] = instanceId - body, err := self.cvmRequest("DescribeInstanceVncUrl", params, true) - if err != nil { - return "", err - } - return body.GetString("InstanceVncUrl") -} - -func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) { - instance, err := self.GetInstance(instanceId) - if err != nil { - return "", err - } - return instance.InstanceState, nil -} - -func (self *SRegion) QueryAccountBalance() (*SAccountBalance, error) { - return self.client.QueryAccountBalance() -} - -func (self *SRegion) getCosEndpoint() string { - return fmt.Sprintf("cos.%s.myqcloud.com", self.GetId()) -} - -func (self *SRegion) getCosWebsiteEndpoint() string { - return fmt.Sprintf("cos-website.%s.myqcloud.com", self.GetId()) -} - -func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - iBuckets, err := region.client.getIBuckets() - if err != nil { - return nil, err - } - ret := make([]cloudprovider.ICloudBucket, 0) - for i := range iBuckets { - bucket := iBuckets[i].(*SBucket) - if bucket.region.GetId() != region.GetId() { - continue - } - ret = append(ret, iBuckets[i]) - } - return ret, nil -} - -func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { - bucket := &SBucket{ - region: region, - Name: name, - } - coscli, err := region.GetCosClient(bucket) - if err != nil { - return errors.Wrap(err, "GetCosClient") - } - opts := &cos.BucketPutOptions{} - if len(aclStr) > 0 { - if utils.IsInStringArray(aclStr, []string{ - "private", "public-read", "public-read-write", "authenticated-read", - }) { - opts.XCosACL = aclStr - } else { - return errors.Error("invalid acl") - } - } - _, err = coscli.Bucket.Put(context.Background(), opts) - if err != nil { - return errors.Wrap(err, "coscli.Bucket.Put") - } - region.client.invalidateIBuckets() - return nil -} - -func cosHttpCode(err error) int { - if httpErr, ok := err.(*cos.ErrorResponse); ok { - return httpErr.Response.StatusCode - } - return -1 -} - -func (region *SRegion) DeleteIBucket(name string) error { - bucket := &SBucket{ - region: region, - Name: name, - } - coscli, err := region.GetCosClient(bucket) - if err != nil { - return errors.Wrap(err, "GetCosClient") - } - _, err = coscli.Bucket.Delete(context.Background()) - if err != nil { - if cosHttpCode(err) == 404 { - return nil - } - return errors.Wrap(err, "DeleteBucket") - } - return nil -} - -func (region *SRegion) IBucketExist(name string) (bool, error) { - bucket := &SBucket{ - region: region, - Name: name, - } - coscli, err := region.GetCosClient(bucket) - if err != nil { - return false, errors.Wrap(err, "GetCosClient") - } - _, err = coscli.Bucket.Head(context.Background()) - if err != nil { - if cosHttpCode(err) == 404 { - return false, nil - } - return false, errors.Wrap(err, "BucketExists") - } - return true, nil -} - -func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { - return cloudprovider.GetIBucketById(region, name) -} - -func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { - return region.GetIBucketById(name) -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, total, err := self.GetSecurityGroups([]string{secgroupId}, "", "", 0, 1) - if err != nil { - return nil, errors.Wrapf(err, "GetSecurityGroups(%s)", secgroupId) - } - if total < 1 { - return nil, cloudprovider.ErrNotFound - } - secgroups[0].region = self - return &secgroups[0], nil -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, total, err := self.GetSecurityGroups([]string{}, opts.VpcId, opts.Name, 0, 0) - if err != nil { - return nil, err - } - if total == 0 { - return nil, cloudprovider.ErrNotFound - } - if total > 1 { - return nil, cloudprovider.ErrDuplicateId - } - return &secgroups[0], nil -} - -func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - return self.CreateSecurityGroup(conf.Name, conf.ProjectId, conf.Desc) -} - -func (region *SRegion) GetCapabilities() []string { - return region.client.GetCapabilities() -} - -func (region *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { - caches, err := region.GetCloudElasticcaches("") - if err != nil { - return nil, errors.Wrap(err, "GetCloudElasticcaches") - } - - ret := []cloudprovider.ICloudElasticcache{} - for i := range caches { - cache := caches[i] - cache.region = region - ret = append(ret, &cache) - } - - mems := []SMemcached{} - offset := 0 - for { - part, total, err := region.GetMemcaches(nil, 100, offset) - if err != nil { - return nil, errors.Wrapf(err, "GetMemcaches") - } - mems = append(mems, part...) - if len(mems) >= total { - break - } - offset += len(part) - } - for i := range mems { - mems[i].region = region - ret = append(ret, &mems[i]) - } - - return ret, nil -} - -func (region *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { - if strings.HasPrefix(id, "cmem-") { - memcacheds, _, err := region.GetMemcaches([]string{id}, 1, 0) - if err != nil { - return nil, errors.Wrapf(err, "GetMemcaches") - } - for i := range memcacheds { - if memcacheds[i].GetGlobalId() == id { - memcacheds[i].region = region - return &memcacheds[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) - } - caches, err := region.GetCloudElasticcaches(id) - if err != nil { - return nil, errors.Wrap(err, "GetCloudElasticcaches") - } - - for i := range caches { - if caches[i].GetGlobalId() == id { - caches[i].region = region - return &caches[i], nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -// DescribeProductInfo 可以查询在售可用区信息 -// https://cloud.tencent.com/document/product/239/20026 -func (r *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { - params := map[string]string{} - if len(ec.ZoneIds) == 0 { - return nil, fmt.Errorf("CreateIElasticcaches zone id should not be empty.") - } - - zoneId, ok := zoneIdMaps[ec.ZoneIds[0]] - if !ok { - return nil, fmt.Errorf("can't convert zone %s to integer id", ec.ZoneIds[0]) - } - - if len(ec.ZoneIds) > 1 { - for i := range ec.ZoneIds { - if i == 0 { - params[fmt.Sprintf("NodeSet.%d.NodeType", i)] = "0" - params[fmt.Sprintf("NodeSet.%d.ZoneId", i)] = fmt.Sprintf("%d", zoneId) - } else { - _z, ok := zoneIdMaps[ec.ZoneIds[i]] - if !ok { - return nil, fmt.Errorf("can't convert zone %s to integer id", ec.ZoneIds[i]) - } - params[fmt.Sprintf("NodeSet.%d.NodeType", i)] = "1" - params[fmt.Sprintf("NodeSet.%d.ZoneId", i)] = fmt.Sprintf("%d", _z) - } - } - } - - spec, err := parseLocalInstanceSpec(ec.InstanceType) - if err != nil { - return nil, errors.Wrap(err, "parseLocalInstanceSpec") - } - - params["InstanceName"] = ec.InstanceName - if len(ec.ProjectId) > 0 { - params["ProjectId"] = ec.ProjectId - } - params["ZoneId"] = fmt.Sprintf("%d", zoneId) - params["TypeId"] = spec.TypeId - params["MemSize"] = strconv.Itoa(spec.MemSizeMB) - params["RedisShardNum"] = spec.RedisShardNum - params["RedisReplicasNum"] = spec.RedisReplicasNum - params["GoodsNum"] = "1" - if ec.NetworkType == api.LB_NETWORK_TYPE_VPC { - params["VpcId"] = ec.VpcId - params["SubnetId"] = ec.NetworkId - - for i := range ec.SecurityGroupIds { - params[fmt.Sprintf("SecurityGroupIdList.%d", i)] = ec.SecurityGroupIds[i] - } - } - params["Period"] = "1" - params["BillingMode"] = "0" - if ec.BillingCycle != nil && ec.BillingCycle.GetMonths() >= 1 { - params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths()) - params["BillingMode"] = "1" - // 自动续费 - if ec.BillingCycle.AutoRenew { - params["AutoRenew"] = "1" - } - } - - if len(ec.Password) > 0 { - params["NoAuth"] = "false" - params["Password"] = ec.Password - } else { - params["NoAuth"] = "true" - } - - resp, err := r.redisRequest("CreateInstances", params) - if err != nil { - return nil, errors.Wrap(err, "CreateInstances") - } - - instanceId := "" - if resp.Contains("InstanceIds") { - ids := []string{} - if err := resp.Unmarshal(&ids, "InstanceIds"); err != nil { - log.Debugf("Unmarshal.InstanceIds %s", resp) - } else { - if len(ids) > 0 { - instanceId = ids[0] - } - } - } - - // try to fetch instance id from deal id - if len(instanceId) == 0 { - dealId, err := resp.GetString("DealId") - if err != nil { - return nil, errors.Wrap(err, "dealId") - } - - // maybe is a dealId not a instance ID. - if strings.HasPrefix(dealId, "crs-") { - instanceId = dealId - } else { - err = cloudprovider.Wait(5*time.Second, 900*time.Second, func() (bool, error) { - _realInstanceId, err := r.GetElasticcacheIdByDeal(dealId) - if err != nil { - return false, nil - } - - instanceId = _realInstanceId - return true, nil - }) - if err != nil { - return nil, errors.Wrap(err, "Wait.GetElasticcacheIdByDeal") - } - } - } - - err = r.SetResourceTags("redis", "instance", []string{instanceId}, ec.Tags, false) - if err != nil { - log.Errorf("SetResourceTags(redis:%s,error:%s)", instanceId, err) - } - return r.GetIElasticcacheById(instanceId) -} diff --git a/pkg/multicloud/qcloud/route_table.go b/pkg/multicloud/qcloud/route_table.go deleted file mode 100644 index d9120ff624..0000000000 --- a/pkg/multicloud/qcloud/route_table.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRouteSet struct { - multicloud.SResourceBase - multicloud.QcloudTags - RouteID int `json:"RouteId"` - RouteItemID string `json:"RouteItemId"` - DestinationIpv6CidrBlock string `json:"DestinationIpv6CidrBlock,omitempty"` - GatewayType string `json:"GatewayType"` - GatewayID string `json:"GatewayId"` - RouteDescription string `json:"RouteDescription"` - DestinationCidrBlock string `json:"DestinationCidrBlock,omitempty"` - RouteType string `json:"RouteType"` -} -type SRouteTableSet struct { - multicloud.SResourceBase - multicloud.QcloudTags - vpc *SVpc - VpcID string `json:"VpcId"` - RouteTableID string `json:"RouteTableId"` - RouteTableName string `json:"RouteTableName"` - AssociationSet []RouteTableAssociationSet `json:"AssociationSet"` - RouteSet []SRouteSet `json:"RouteSet"` - Main bool `json:"Main"` - CreatedTime string `json:"CreatedTime"` -} - -type RouteTableAssociationSet struct { - SubnetId string - RouteTableId string -} - -func (self *SRegion) DescribeRouteTables(vpcId string, routetables []string, offset int, limit int) ([]SRouteTableSet, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - - for i := range routetables { - params[fmt.Sprintf("RouteTableIds.%d", i)] = routetables[i] - } - - if len(vpcId) > 0 { - params["Filters.0.Name"] = "vpc-id" - params["Filters.0.Values.0"] = vpcId - } - body, err := self.vpcRequest("DescribeRouteTables", params) - if err != nil { - return nil, 0, errors.Wrapf(err, ` self.vpcRequest("DescribeRouteTables", %s)`, jsonutils.Marshal(params)) - } - routeTables := make([]SRouteTableSet, 0) - err = body.Unmarshal(&routeTables, "RouteTableSet") - if err != nil { - return nil, 0, errors.Wrapf(err, "body.Unmarshal(RouteTableSet)[%s]", body.String()) - } - total, _ := body.Float("TotalCount") - return routeTables, int(total), nil -} - -func (self *SRegion) GetAllRouteTables(vpcId string, routetables []string) ([]SRouteTableSet, error) { - routeTables := make([]SRouteTableSet, 0) - for { - part, total, err := self.DescribeRouteTables(vpcId, routetables, len(routeTables), 50) - if err != nil { - return nil, errors.Wrap(err, "self.DescribeRouteTables(vpcId, routetables, offset, limit)") - } - routeTables = append(routeTables, part...) - if len(routeTables) >= total { - break - } - } - return routeTables, nil -} - -func (self *SRouteTableSet) GetId() string { - return self.RouteTableID -} - -func (self *SRouteTableSet) GetName() string { - return self.RouteTableName -} - -func (self *SRouteTableSet) GetGlobalId() string { - return self.RouteTableID -} - -func (self *SRouteTableSet) GetStatus() string { - return api.ROUTE_TABLE_AVAILABLE -} - -func (self *SRouteTableSet) Refresh() error { - return nil -} - -func (self *SRouteTableSet) IsEmulated() bool { - return false -} - -func (self *SRouteTableSet) GetAssociations() []cloudprovider.RouteTableAssociation { - result := []cloudprovider.RouteTableAssociation{} - for i := range self.AssociationSet { - association := cloudprovider.RouteTableAssociation{ - AssociationType: cloudprovider.RouteTableAssociaToSubnet, - AssociatedResourceId: self.AssociationSet[i].SubnetId, - } - result = append(result, association) - } - return result -} - -func (self *SRouteTableSet) GetDescription() string { - return "" -} - -func (self *SRouteTableSet) GetRegionId() string { - return self.vpc.GetRegion().GetId() -} - -func (self *SRouteTableSet) GetVpcId() string { - return self.vpc.GetId() -} - -func (self *SRouteTableSet) GetType() cloudprovider.RouteTableType { - if self.Main { - return cloudprovider.RouteTableTypeSystem - } - return cloudprovider.RouteTableTypeCustom -} - -func (self *SRouteTableSet) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { - result := []cloudprovider.ICloudRoute{} - for i := range self.RouteSet { - result = append(result, &self.RouteSet[i]) - } - return result, nil -} - -func (self *SRouteTableSet) CreateRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRouteTableSet) UpdateRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRouteTableSet) RemoveRoute(route cloudprovider.RouteSet) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRouteSet) GetId() string { - return self.RouteItemID -} - -func (self *SRouteSet) GetName() string { - return "" -} - -func (self *SRouteSet) GetGlobalId() string { - return self.RouteItemID -} - -func (self *SRouteSet) GetStatus() string { - return api.ROUTE_ENTRY_STATUS_AVAILIABLE -} - -func (self *SRouteSet) Refresh() error { - return nil -} - -func (self *SRouteSet) IsEmulated() bool { - return false -} - -func (self *SRouteSet) GetType() string { - switch self.RouteType { - case "USER": - return api.ROUTE_ENTRY_TYPE_CUSTOM - case "NETD": - return api.ROUTE_ENTRY_TYPE_SYSTEM - case "CCN": - return api.ROUTE_ENTRY_TYPE_PROPAGATE - default: - return api.ROUTE_ENTRY_TYPE_SYSTEM - } -} - -func (self *SRouteSet) GetCidr() string { - return self.DestinationCidrBlock -} - -func (self *SRouteSet) GetNextHopType() string { - switch self.GatewayType { - case "CVM": - return api.NEXT_HOP_TYPE_INSTANCE - case "VPN": - return api.NEXT_HOP_TYPE_VPN - case "DIRECTCONNECT": - return api.NEXT_HOP_TYPE_DIRECTCONNECTION - case "PEERCONNECTION": - return api.NEXT_HOP_TYPE_VPCPEERING - case "SSLVPN": - return api.NEXT_HOP_TYPE_VPN - case "NAT": - return api.NEXT_HOP_TYPE_NAT - case "NORMAL_CVM": - return api.NEXT_HOP_TYPE_INSTANCE - case "EIP": - return api.NEXT_HOP_TYPE_EIP - case "CCN": - return api.NEXT_HOP_TYPE_INTERVPCNETWORK - default: - return "" - } -} - -func (self *SRouteSet) GetNextHop() string { - return self.GatewayID -} diff --git a/pkg/multicloud/qcloud/saml_provider.go b/pkg/multicloud/qcloud/saml_provider.go deleted file mode 100644 index cba34417ad..0000000000 --- a/pkg/multicloud/qcloud/saml_provider.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "encoding/base64" - "fmt" - "time" - "unicode" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/cloudid" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/samlutils" -) - -type SAMLProvider struct { - multicloud.SResourceBase - multicloud.QcloudTags - client *SQcloudClient - - Name string - Description string - CreateTime time.Time - ModifyTime time.Time - SAMLMetadata string -} - -func (self *SAMLProvider) GetId() string { - return self.Name -} - -func (self *SAMLProvider) GetGlobalId() string { - return self.Name -} - -func (self *SAMLProvider) GetName() string { - return self.Name -} - -func (self *SAMLProvider) GetStatus() string { - return api.SAML_PROVIDER_STATUS_AVAILABLE -} - -func (self *SAMLProvider) Delete() error { - return self.client.DeleteSAMLProvider(self.Name) -} - -func (self *SAMLProvider) GetAuthUrl() string { - return fmt.Sprintf("https://cloud.tencent.com/login/forwardIdp/%s/%s", self.client.ownerName, self.Name) -} - -func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { - provider, err := self.client.GetSAMLProvider(self.Name) - if err != nil { - return nil, errors.Wrapf(err, "GetSAMLProvider(%s)", self.Name) - } - metadata, err := base64.StdEncoding.DecodeString(provider.SAMLMetadata) - if err != nil { - return nil, errors.Wrapf(err, "decode metadata") - } - ret, err := samlutils.ParseMetadata(metadata) - if err != nil { - return nil, errors.Wrapf(err, "ParseMetadata") - } - return &ret, nil -} - -func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { - return self.client.UpdateSAMLProvider(self.Name, metadata.String(), "") -} - -func (self *SQcloudClient) ListSAMLProviders() ([]SAMLProvider, error) { - resp, err := self.camRequest("ListSAMLProviders", nil) - if err != nil { - return nil, errors.Wrapf(err, "ListSAMLProviders") - } - result := []SAMLProvider{} - err = resp.Unmarshal(&result, "SAMLProviderSet") - if err != nil { - return nil, errors.Wrapf(err, "Unmarshal") - } - return result, nil -} - -func (self *SQcloudClient) CreateSAMLProvider(name, metadata, desc string) (*SAMLProvider, error) { - if len(desc) == 0 { - desc = "For CloudId Service" - } - //支持3-128个数字、大小写字母、和+=,.@_- - name = func() string { - ret := "" - for _, c := range name { - if unicode.IsLetter(c) || unicode.IsNumber(c) || - c == '+' || c == '=' || c == ',' || c == '.' || c == '@' || c == '_' || c == '-' { - ret += string(c) - } else { - ret += "-" - } - } - return ret - }() - if len(name) > 128 { - name = name[:128] - } - params := map[string]string{ - "Name": name, - "Description": desc, - "SAMLMetadataDocument": base64.StdEncoding.EncodeToString([]byte(metadata)), - } - _, err := self.camRequest("CreateSAMLProvider", params) - if err != nil { - return nil, errors.Wrapf(err, "CreateSAMLProvider") - } - return self.GetSAMLProvider(name) -} - -func (self *SQcloudClient) GetSAMLProvider(name string) (*SAMLProvider, error) { - params := map[string]string{ - "Name": name, - } - resp, err := self.camRequest("GetSAMLProvider", params) - if err != nil { - return nil, errors.Wrapf(err, "GetSAMLProvider") - } - result := &SAMLProvider{client: self} - err = resp.Unmarshal(result) - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return result, nil -} - -func (self *SQcloudClient) DeleteSAMLProvider(name string) error { - params := map[string]string{ - "Name": name, - } - _, err := self.camRequest("DeleteSAMLProvider", params) - return err -} - -func (self *SQcloudClient) UpdateSAMLProvider(name, metadata, desc string) error { - params := map[string]string{ - "Name": name, - } - if len(desc) > 0 { - params["Description"] = desc - } - if len(metadata) > 0 { - params["SAMLMetadataDocument"] = base64.StdEncoding.EncodeToString([]byte(metadata)) - } - _, err := self.camRequest("UpdateSAMLProvider", params) - if err != nil { - return errors.Wrap(err, "UpdateSAMLProvider") - } - return nil -} - -func (self *SQcloudClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { - providers, err := self.ListSAMLProviders() - if err != nil { - return nil, errors.Wrapf(err, "ListSAMLProviders") - } - ret := []cloudprovider.ICloudSAMLProvider{} - for i := range providers { - providers[i].client = self - ret = append(ret, &providers[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/qcloud/securitygroup.go b/pkg/multicloud/qcloud/securitygroup.go deleted file mode 100644 index cc43418db4..0000000000 --- a/pkg/multicloud/qcloud/securitygroup.go +++ /dev/null @@ -1,570 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "sort" - "strconv" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SecurityGroupPolicy struct { - region *SRegion - PolicyIndex int // 安全组规则索引号。 - Protocol string // 协议, 取值: TCP,UDP, ICMP。 - Port string // 端口(all, 离散port, range)。 - ServiceTemplate ServiceTemplateSpecification // 协议端口ID或者协议端口组ID。ServiceTemplate和Protocol+Port互斥。 - CidrBlock string // 网段或IP(互斥)。 - SecurityGroupId string // 已绑定安全组的网段或IP。 - AddressTemplate AddressTemplateSpecification // IP地址ID或者ID地址组ID。 - Action string // ACCEPT 或 DROP。 - PolicyDescription string // 安全组规则描述。 - direction string -} - -type ServiceTemplateSpecification struct { - ServiceId string // 协议端口ID,例如:ppm-f5n1f8da。 - ServiceGroupId string // 协议端口组ID,例如:ppmg-f5n1f8da。 -} - -type AddressTemplateSpecification struct { - AddressId string // IP地址ID,例如:ipm-2uw6ujo6。 - AddressGroupId string // IP地址组ID,例如:ipmg-2uw6ujo6。 -} - -type SecurityGroupPolicySet struct { - Version string - Egress []SecurityGroupPolicy // 出站规则。 - Ingress []SecurityGroupPolicy // 入站规则。 -} - -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.QcloudTags - region *SRegion - SecurityGroupId string // 安全组实例ID,例如:sg-ohuuioma。 - SecurityGroupName string // 安全组名称,可任意命名,但不得超过60个字符。 - SecurityGroupDesc string // 安全组备注,最多100个字符。 - ProjectId string // 项目id,默认0。可在qcloud控制台项目管理页面查询到。 - IsDefault bool // 是否是默认安全组,默认安全组不支持删除。 - CreatedTime time.Time // 安全组创建时间。 - SecurityGroupPolicySet SecurityGroupPolicySet -} - -func (self *SRegion) GetSecurityGroups(ids []string, vpcId string, name string, offset int, limit int) ([]SSecurityGroup, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - - if len(name) > 0 { - params["Filters.0.Name"] = "security-group-name" - params["Filters.0.Values.0"] = name - } - - for idx, id := range ids { - params[fmt.Sprintf("SecurityGroupIds.%d", idx)] = id - } - - resp, err := self.vpcRequest("DescribeSecurityGroups", params) - if err != nil { - return nil, 0, errors.Wrapf(err, "DescribeSecurityGroups") - } - - secgrps := make([]SSecurityGroup, 0) - err = resp.Unmarshal(&secgrps, "SecurityGroupSet") - if err != nil { - return nil, 0, errors.Wrapf(err, "resp.Unmarshal") - } - total, _ := resp.Float("TotalCount") - return secgrps, int(total), nil -} - -func (self *SSecurityGroup) GetVpcId() string { - //腾讯云安全组未与vpc关联,统一使用normal - return "normal" -} - -func (self *SSecurityGroup) GetId() string { - return self.SecurityGroupId -} - -func (self *SSecurityGroup) GetGlobalId() string { - return self.SecurityGroupId -} - -func (self *SSecurityGroup) GetDescription() string { - return self.SecurityGroupDesc -} - -func (self *SSecurityGroup) GetName() string { - if len(self.SecurityGroupName) > 0 { - return self.SecurityGroupName - } - return self.SecurityGroupId -} - -func (self *SecurityGroupPolicy) String() string { - rules := self.toRules() - result := []string{} - for _, rule := range rules { - result = append(result, rule.String()) - } - return strings.Join(result, ";") -} - -type ReferredSecurityGroup struct { - SecurityGroupId string - ReferredSecurityGroupIds []string -} - -func (self *SSecurityGroup) GetReferences() ([]cloudprovider.SecurityGroupReference, error) { - references, err := self.region.DescribeSecurityGroupReferences(self.SecurityGroupId) - if err != nil { - return nil, errors.Wrapf(err, "DescribeSecurityGroupReferences") - } - ret := []cloudprovider.SecurityGroupReference{} - for _, refer := range references { - if refer.SecurityGroupId == self.SecurityGroupId { - for _, id := range refer.ReferredSecurityGroupIds { - ret = append(ret, cloudprovider.SecurityGroupReference{ - Id: id, - }) - } - } - } - return ret, nil -} - -func (self *SRegion) DescribeSecurityGroupReferences(id string) ([]ReferredSecurityGroup, error) { - params := map[string]string{ - "Region": self.Region, - "SecurityGroupIds.0": id, - } - resp, err := self.vpcRequest("DescribeSecurityGroupReferences", params) - if err != nil { - return nil, errors.Wrapf(err, "DescribeSecurityGroupReferences") - } - ret := []ReferredSecurityGroup{} - err = resp.Unmarshal(&ret, "ReferredSecurityGroupSet") - if err != nil { - return nil, errors.Wrapf(err, "resp.Unmarshal") - } - return ret, nil -} - -func (self *SecurityGroupPolicy) toRules() []cloudprovider.SecurityRule { - result := []cloudprovider.SecurityRule{} - rule := cloudprovider.SecurityRule{ - ExternalId: fmt.Sprintf("%d", self.PolicyIndex), - SecurityRule: secrules.SecurityRule{ - Action: secrules.SecurityRuleAllow, - Protocol: secrules.PROTO_ANY, - Direction: secrules.TSecurityRuleDirection(self.direction), - Priority: self.PolicyIndex, - Ports: []int{}, - PortStart: -1, - PortEnd: -1, - }, - } - if len(self.SecurityGroupId) != 0 { - rule.ParseCIDR("0.0.0.0/0") - rule.PeerSecgroupId = self.SecurityGroupId - } - if strings.ToLower(self.Action) == "drop" { - rule.Action = secrules.SecurityRuleDeny - } - if utils.IsInStringArray(strings.ToLower(self.Protocol), []string{"tcp", "udp", "icmp"}) { - rule.Protocol = strings.ToLower(self.Protocol) - } - if strings.Index(self.Port, ",") > 0 { - for _, _port := range strings.Split(self.Port, ",") { - port, err := strconv.Atoi(_port) - if err != nil { - log.Errorf("parse secgroup port %s %s error %v", self.Port, _port, err) - continue - } - rule.Ports = append(rule.Ports, port) - } - } else if strings.Index(self.Port, "-") > 0 { - ports := strings.Split(self.Port, "-") - if len(ports) == 2 { - portStart, err := strconv.Atoi(ports[0]) - if err != nil { - return nil - } - portEnd, err := strconv.Atoi(ports[1]) - if err != nil { - return nil - } - rule.PortStart, rule.PortEnd = portStart, portEnd - } - } else if strings.ToLower(self.Port) != "all" { - port, err := strconv.Atoi(self.Port) - if err != nil { - return nil - } - rule.PortStart, rule.PortEnd = port, port - } - - if len(self.AddressTemplate.AddressGroupId) > 0 { - addressGroup, total, err := self.region.AddressGroupList(self.AddressTemplate.AddressGroupId, "", 0, 1) - if err != nil { - log.Errorf("Get AddressList %s failed %v", self.AddressTemplate.AddressId, err) - return nil - } - if total != 1 { - return nil - } - for i := 0; i < len(addressGroup[0].AddressTemplateIdSet); i++ { - rules, err := self.getAddressRules(rule, addressGroup[0].AddressTemplateIdSet[i]) - if err != nil { - return nil - } - result = append(result, rules...) - } - } else if len(self.AddressTemplate.AddressId) > 0 { - rules, err := self.getAddressRules(rule, self.AddressTemplate.AddressId) - if err != nil { - return nil - } - result = append(result, rules...) - } else if len(self.SecurityGroupId) > 0 { - rule.PeerSecgroupId = self.SecurityGroupId - result = append(result, rule) - } else if len(self.CidrBlock) > 0 { - rule.ParseCIDR(self.CidrBlock) - result = append(result, rule) - } - return result -} - -func (self *SecurityGroupPolicy) getAddressRules(rule cloudprovider.SecurityRule, addressId string) ([]cloudprovider.SecurityRule, error) { - result := []cloudprovider.SecurityRule{} - address, total, err := self.region.AddressList(addressId, "", 0, 1) - if err != nil { - log.Errorf("Get AddressList %s failed %v", self.AddressTemplate.AddressId, err) - return nil, err - } - if total != 1 { - return nil, fmt.Errorf("failed to find address %s", addressId) - } - for _, ip := range address[0].AddressSet { - rule.ParseCIDR(ip) - result = append(result, rule) - } - return result, nil -} - -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - policySet, err := self.region.DescribeSecurityGroupPolicies(self.SecurityGroupId) - if err != nil { - return nil, err - } - for i := 0; i < len(policySet.Egress); i++ { - policySet.Egress[i].direction = "out" - } - for i := 0; i < len(policySet.Ingress); i++ { - policySet.Ingress[i].direction = "in" - } - originRules := []SecurityGroupPolicy{} - originRules = append(originRules, policySet.Egress...) - originRules = append(originRules, policySet.Ingress...) - for i := 0; i < len(originRules); i++ { - originRules[i].region = self.region - } - rules := []cloudprovider.SecurityRule{} - for _, rule := range originRules { - subRules := rule.toRules() - rules = append(rules, subRules...) - } - return rules, nil -} - -func (self *SSecurityGroup) GetStatus() string { - return "" -} - -func (self *SSecurityGroup) IsEmulated() bool { - return false -} - -func (self *SSecurityGroup) Refresh() error { - groups, total, err := self.region.GetSecurityGroups([]string{self.SecurityGroupId}, "", "", 0, 0) - if err != nil { - return err - } - if total < 1 { - return cloudprovider.ErrNotFound - } - return jsonutils.Update(self, groups[0]) -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - rules := append(common, append(inAdds, outAdds...)...) - sort.Sort(cloudprovider.SecurityRuleSet(rules)) - return self.region.syncSecgroupRules(self.SecurityGroupId, rules) -} - -func (self *SRegion) syncSecgroupRules(secgroupId string, rules []cloudprovider.SecurityRule) error { - params := map[string]string{ - "SecurityGroupId": secgroupId, - "SortPolicys": "True", - } - egressIndex, ingressIndex := 0, 0 - for _, rule := range rules { - switch rule.Direction { - case secrules.DIR_IN: - params = convertSecgroupRule(ingressIndex, rule, params) - ingressIndex++ - case secrules.DIR_OUT: - params = convertSecgroupRule(egressIndex, rule, params) - egressIndex++ - } - } - _, err := self.vpcRequest("ModifySecurityGroupPolicies", params) - if err != nil { - return errors.Wrapf(err, "ModifySecurityGroupPolicies") - } - if egressIndex == 0 || ingressIndex == 0 { - ruleSet, err := self.DescribeSecurityGroupPolicies(secgroupId) - if err != nil { - return errors.Wrapf(err, "DescribeSecurityGroupPolicies") - } - params = map[string]string{ - "SecurityGroupId": secgroupId, - } - if egressIndex == 0 && len(ruleSet.Egress) > 0 { - for idx, rule := range ruleSet.Egress { - params[fmt.Sprintf("SecurityGroupPolicySet.Egress.%d.PolicyIndex", idx)] = fmt.Sprintf("%d", rule.PolicyIndex) - } - } - if ingressIndex == 0 && len(ruleSet.Ingress) > 0 { - for idx, rule := range ruleSet.Ingress { - params[fmt.Sprintf("SecurityGroupPolicySet.Ingress.%d.PolicyIndex", idx)] = fmt.Sprintf("%d", rule.PolicyIndex) - } - } - if len(params) > 1 { - _, err = self.vpcRequest("DeleteSecurityGroupPolicies", params) - if err != nil { - return errors.Wrapf(err, "DeleteSecurityGroupPolicies") - } - } - } - return nil -} - -func convertSecgroupRule(policyIndex int, rule cloudprovider.SecurityRule, params map[string]string) map[string]string { - direction := "Egress" - action := "accept" - if rule.Action == secrules.SecurityRuleDeny { - action = "drop" - } - protocol := "ALL" - if rule.Protocol != secrules.PROTO_ANY { - protocol = rule.Protocol - } - if rule.Direction == secrules.DIR_IN { - direction = "Ingress" - } - params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.Action", direction, policyIndex)] = action - params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.PolicyDescription", direction, policyIndex)] = rule.Description - params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.Protocol", direction, policyIndex)] = protocol - if len(rule.PeerSecgroupId) > 0 { - params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.SecurityGroupId", direction, policyIndex)] = rule.PeerSecgroupId - } else { - params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.CidrBlock", direction, policyIndex)] = rule.IPNet.String() - } - if rule.Protocol == secrules.PROTO_TCP || rule.Protocol == secrules.PROTO_UDP { - port := "ALL" - if rule.PortEnd > 0 && rule.PortStart > 0 { - if rule.PortStart == rule.PortEnd { - port = fmt.Sprintf("%d", rule.PortStart) - } else { - port = fmt.Sprintf("%d-%d", rule.PortStart, rule.PortEnd) - } - } else if len(rule.Ports) > 0 { - ports := []string{} - for _, _port := range rule.Ports { - ports = append(ports, fmt.Sprintf("%d", _port)) - } - port = strings.Join(ports, ",") - } - params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.Port", direction, policyIndex)] = port - } - return params -} - -func (self *SRegion) DescribeSecurityGroupPolicies(secGroupId string) (*SecurityGroupPolicySet, error) { - params := make(map[string]string) - params["Region"] = self.Region - params["SecurityGroupId"] = secGroupId - - body, err := self.vpcRequest("DescribeSecurityGroupPolicies", params) - if err != nil { - log.Errorf("DescribeSecurityGroupAttribute fail %s", err) - return nil, err - } - - policies := SecurityGroupPolicySet{} - err = body.Unmarshal(&policies, "SecurityGroupPolicySet") - if err != nil { - return nil, errors.Wrapf(err, "body.Unmarshal") - } - return &policies, nil -} - -func (self *SRegion) DeleteSecurityGroup(secGroupId string) error { - params := make(map[string]string) - params["Region"] = self.Region - params["SecurityGroupId"] = secGroupId - _, err := self.vpcRequest("DeleteSecurityGroup", params) - return err -} - -type AddressTemplate struct { - AddressSet []string - AddressTemplateId string - AddressTemplateName string - CreatedTime time.Time -} - -func (self *SRegion) AddressList(addressId, addressName string, offset, limit int) ([]AddressTemplate, int, error) { - params := map[string]string{} - filter := 0 - if len(addressId) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "address-template-id" - params[fmt.Sprintf("Filters.%d.Values.0", filter)] = addressId - filter++ - } - if len(addressName) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "address-template-name" - params[fmt.Sprintf("Filters.%d.Values.0", filter)] = addressName - filter++ - } - params["Offset"] = fmt.Sprintf("%d", offset) - if limit == 0 { - limit = 20 - } - params["Limit"] = fmt.Sprintf("%d", limit) - body, err := self.vpcRequest("DescribeAddressTemplates", params) - if err != nil { - return nil, 0, err - } - addressTemplates := []AddressTemplate{} - err = body.Unmarshal(&addressTemplates, "AddressTemplateSet") - if err != nil { - return nil, 0, err - } - total, _ := body.Float("TotalCount") - return addressTemplates, int(total), nil -} - -type AddressTemplateGroup struct { - AddressTemplateIdSet []string - AddressTemplateGroupName string - AddressTemplateGroupId string - CreatedTime time.Time -} - -func (self *SRegion) AddressGroupList(groupId, groupName string, offset, limit int) ([]AddressTemplateGroup, int, error) { - params := map[string]string{} - filter := 0 - if len(groupId) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "address-template-group-id" - params[fmt.Sprintf("Filters.%d.Values.0", filter)] = groupId - filter++ - } - if len(groupName) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "address-template-group-name" - params[fmt.Sprintf("Filters.%d.Values.0", filter)] = groupName - filter++ - } - params["Offset"] = fmt.Sprintf("%d", offset) - if limit == 0 { - limit = 20 - } - params["Limit"] = fmt.Sprintf("%d", limit) - body, err := self.vpcRequest("DescribeAddressTemplateGroups", params) - if err != nil { - return nil, 0, err - } - addressTemplateGroups := []AddressTemplateGroup{} - err = body.Unmarshal(&addressTemplateGroups, "AddressTemplateGroupSet") - if err != nil { - return nil, 0, err - } - total, _ := body.Float("TotalCount") - return addressTemplateGroups, int(total), nil -} - -func (self *SRegion) DeleteSecgroupRule(secId string, direction string, index int) error { - params := map[string]string{ - "SecurityGroupId": secId, - } - switch direction { - case secrules.DIR_IN: - params["SecurityGroupPolicySet.Ingress.0.PolicyIndex"] = fmt.Sprintf("%d", index) - case secrules.DIR_OUT: - params["SecurityGroupPolicySet.Egress.0.PolicyIndex"] = fmt.Sprintf("%d", index) - } - _, err := self.vpcRequest("DeleteSecurityGroupPolicies", params) - return errors.Wrapf(err, "DeleteSecurityGroupPolicies") -} - -func (self *SRegion) CreateSecurityGroup(name, projectId, description string) (*SSecurityGroup, error) { - params := make(map[string]string) - params["Region"] = self.Region - params["GroupName"] = name - params["GroupDescription"] = description - if len(projectId) > 0 { - params["ProjectId"] = projectId - } - - if len(description) == 0 { - params["GroupDescription"] = "Customize Create" - } - secgroup := SSecurityGroup{region: self} - body, err := self.vpcRequest("CreateSecurityGroup", params) - if err != nil { - return nil, errors.Wrap(err, "CreateSecurityGroup") - } - err = body.Unmarshal(&secgroup, "SecurityGroup") - if err != nil { - return nil, errors.Wrap(err, "body.Unmarshal") - } - return &secgroup, nil -} - -func (self *SSecurityGroup) GetProjectId() string { - return self.ProjectId -} - -func (self *SSecurityGroup) Delete() error { - return self.region.DeleteSecurityGroup(self.SecurityGroupId) -} diff --git a/pkg/multicloud/qcloud/shell/balance.go b/pkg/multicloud/qcloud/shell/balance.go deleted file mode 100644 index 54e9040abe..0000000000 --- a/pkg/multicloud/qcloud/shell/balance.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type BalanceOptions struct { - } - shellutils.R(&BalanceOptions{}, "balance-show", "Show balance", func(cli *qcloud.SRegion, args *BalanceOptions) error { - balance, err := cli.QueryAccountBalance() - if err != nil { - return err - } - printObject(balance) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/bandwidthpackage.go b/pkg/multicloud/qcloud/shell/bandwidthpackage.go deleted file mode 100644 index 09683854fc..0000000000 --- a/pkg/multicloud/qcloud/shell/bandwidthpackage.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type BandwidthPackageListOptions struct { - Ids []string `help:"Bandwidth package ids"` - Offset int `help:"List offset"` - Limit int `help:"List limit"` - } - shellutils.R(&BandwidthPackageListOptions{}, "bandwidth-package-list", "List bandwidth packages", func(cli *qcloud.SRegion, args *BandwidthPackageListOptions) error { - packages, total, err := cli.GetBandwidthPackages(args.Ids, args.Offset, args.Limit) - if err != nil { - return err - } - printList(packages, total, args.Offset, args.Limit, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/cam_group.go b/pkg/multicloud/qcloud/shell/cam_group.go deleted file mode 100644 index 693795127e..0000000000 --- a/pkg/multicloud/qcloud/shell/cam_group.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CloudgroupListOptions struct { - Keyword string - Offset int - Limit int - } - shellutils.R(&CloudgroupListOptions{}, "cloud-group-list", "List cloudgroups", func(cli *qcloud.SRegion, args *CloudgroupListOptions) error { - groups, _, err := cli.GetClient().ListGroups(args.Keyword, args.Offset, args.Limit) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - type CloudgroupIdOptions struct { - ID int - } - - shellutils.R(&CloudgroupIdOptions{}, "cloud-group-delete", "Delete cloudgroup", func(cli *qcloud.SRegion, args *CloudgroupIdOptions) error { - return cli.GetClient().DeleteGroup(args.ID) - }) - - shellutils.R(&CloudgroupIdOptions{}, "cloud-group-show", "Show cloudgroup", func(cli *qcloud.SRegion, args *CloudgroupIdOptions) error { - group, err := cli.GetClient().GetGroup(args.ID) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type CloudgroupCreateOptions struct { - NAME string - Remark string - } - - shellutils.R(&CloudgroupCreateOptions{}, "cloud-group-create", "Create cloudgroup", func(cli *qcloud.SRegion, args *CloudgroupCreateOptions) error { - group, err := cli.GetClient().CreateGroup(args.NAME, args.Remark) - if err != nil { - return err - } - printObject(group) - return nil - }) - - type CloudgroupUserListOptions struct { - GROUPID int - Offset int - Limit int - } - shellutils.R(&CloudgroupUserListOptions{}, "cloud-group-user-list", "List cloudgroup users", func(cli *qcloud.SRegion, args *CloudgroupUserListOptions) error { - users, _, err := cli.GetClient().ListGroupUsers(args.GROUPID, args.Offset, args.Limit) - if err != nil { - return err - } - printList(users, 0, 0, 0, nil) - return nil - }) - - type GroupUserOptions struct { - GROUP int - USER int - } - - shellutils.R(&GroupUserOptions{}, "cloud-group-add-user", "Add user to cloudgroup", func(cli *qcloud.SRegion, args *GroupUserOptions) error { - return cli.GetClient().AddUserToGroup(args.GROUP, args.USER) - }) - - shellutils.R(&GroupUserOptions{}, "cloud-group-remove-user", "Remove user from cloudgroup", func(cli *qcloud.SRegion, args *GroupUserOptions) error { - return cli.GetClient().RemoveUserFromGroup(args.GROUP, args.USER) - }) - - type GroupPolicyOptions struct { - GROUP int - POLICY string - } - - shellutils.R(&GroupPolicyOptions{}, "cloud-group-attach-policy", "Attach policy to cloudgroup", func(cli *qcloud.SRegion, args *GroupPolicyOptions) error { - return cli.GetClient().AttachGroupPolicy(args.GROUP, args.POLICY) - }) - - shellutils.R(&GroupPolicyOptions{}, "cloud-group-detach-policy", "Detach policy from cloudgroup", func(cli *qcloud.SRegion, args *GroupPolicyOptions) error { - return cli.GetClient().DetachGroupPolicy(args.GROUP, args.POLICY) - }) - -} diff --git a/pkg/multicloud/qcloud/shell/cam_policy.go b/pkg/multicloud/qcloud/shell/cam_policy.go deleted file mode 100644 index 3cdeff70b2..0000000000 --- a/pkg/multicloud/qcloud/shell/cam_policy.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CloudpolicyListOption struct { - Keyword string - Scope string `choices:"QCS|Local"` - Offset int - Limit int - } - - shellutils.R(&CloudpolicyListOption{}, "cloud-policy-list", "List cloudpolicy", func(cli *qcloud.SRegion, args *CloudpolicyListOption) error { - policies, _, err := cli.GetClient().ListPolicies(args.Keyword, args.Scope, args.Offset, args.Limit) - if err != nil { - return err - } - printList(policies, 0, 0, 0, nil) - return nil - }) - - type CloudpolicyShowOption struct { - POLICY_ID string - } - - shellutils.R(&CloudpolicyShowOption{}, "cloud-policy-show", "Show cloudpolicy", func(cli *qcloud.SRegion, args *CloudpolicyShowOption) error { - policy, err := cli.GetClient().GetPolicy(args.POLICY_ID) - if err != nil { - return err - } - printObject(policy) - return nil - }) - - type CloudpolicyIdsOptions struct { - IDS []int - } - - shellutils.R(&CloudpolicyIdsOptions{}, "cloud-policy-delete", "Delete cloudpolicies", func(cli *qcloud.SRegion, args *CloudpolicyIdsOptions) error { - return cli.GetClient().DeletePolicy(args.IDS) - }) - - type CloudpolicyCreateOptions struct { - NAME string - DOCUMENT string - Desc string - } - - shellutils.R(&CloudpolicyCreateOptions{}, "cloud-policy-create", "Create cloudpolicy", func(cli *qcloud.SRegion, args *CloudpolicyCreateOptions) error { - policy, err := cli.GetClient().CreatePolicy(args.NAME, args.DOCUMENT, args.Desc) - if err != nil { - return err - } - printObject(policy) - return nil - }) - - type CloudpolicyUpdateOptions struct { - ID int - Document string - Desc string - } - - shellutils.R(&CloudpolicyUpdateOptions{}, "cloud-policy-update", "Update cloudpolicy", func(cli *qcloud.SRegion, args *CloudpolicyUpdateOptions) error { - return cli.GetClient().UpdatePolicy(args.ID, args.Document, args.Desc) - }) - -} diff --git a/pkg/multicloud/qcloud/shell/cam_role.go b/pkg/multicloud/qcloud/shell/cam_role.go deleted file mode 100644 index a4ccfedd9b..0000000000 --- a/pkg/multicloud/qcloud/shell/cam_role.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "strconv" - - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RoleListOptions struct { - Offset int - Limit int - } - shellutils.R(&RoleListOptions{}, "cloud-role-list", "List roles", func(cli *qcloud.SRegion, args *RoleListOptions) error { - roles, _, err := cli.GetClient().DescribeRoleList(args.Offset, args.Limit) - if err != nil { - return err - } - printList(roles, 0, 0, 0, nil) - return nil - }) - - type RoleNameOptions struct { - ROLE string - } - - shellutils.R(&RoleNameOptions{}, "cloud-role-show", "Show role details", func(cli *qcloud.SRegion, args *RoleNameOptions) error { - role, err := cli.GetClient().GetRole(args.ROLE) - if err != nil { - return err - } - printObject(role) - return nil - }) - - shellutils.R(&RoleNameOptions{}, "cloud-role-delete", "Delete role", func(cli *qcloud.SRegion, args *RoleNameOptions) error { - return cli.GetClient().DeleteRole(args.ROLE) - }) - - type RolePolicyOptions struct { - ROLE string - PolicyType string `choices:"User|QCS"` - Offset int - Limit int - } - - shellutils.R(&RolePolicyOptions{}, "cloud-role-policy-list", "List role policies", func(cli *qcloud.SRegion, args *RolePolicyOptions) error { - policies, _, err := cli.GetClient().ListAttachedRolePolicies(args.ROLE, args.PolicyType, args.Offset, args.Limit) - if err != nil { - return err - } - printList(policies, 0, 0, 0, nil) - return nil - }) - - type RolePolicyActionOptions struct { - ROLE string - POLICY_ID int - } - - shellutils.R(&RolePolicyActionOptions{}, "cloud-role-attach-policy", "Attach role policy", func(cli *qcloud.SRegion, args *RolePolicyActionOptions) error { - return cli.GetClient().AttachRolePolicy(args.ROLE, strconv.Itoa(args.POLICY_ID)) - }) - - shellutils.R(&RolePolicyActionOptions{}, "cloud-role-detach-policy", "Detach role policy", func(cli *qcloud.SRegion, args *RolePolicyActionOptions) error { - return cli.GetClient().AttachRolePolicy(args.ROLE, strconv.Itoa(args.POLICY_ID)) - }) - - type RoleCreateOption struct { - NAME string - DOCUMENT string - Desc string - } - - shellutils.R(&RoleCreateOption{}, "cloud-role-create", "Create role", func(cli *qcloud.SRegion, args *RoleCreateOption) error { - role, err := cli.GetClient().CreateRole(args.NAME, args.DOCUMENT, args.Desc) - if err != nil { - return err - } - printObject(role) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/cam_user.go b/pkg/multicloud/qcloud/shell/cam_user.go deleted file mode 100644 index e62af9d531..0000000000 --- a/pkg/multicloud/qcloud/shell/cam_user.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClouduserListOptions struct { - } - shellutils.R(&ClouduserListOptions{}, "cloud-user-list", "List cloudusers", func(cli *qcloud.SRegion, args *ClouduserListOptions) error { - users, err := cli.GetClient().ListUsers() - if err != nil { - return err - } - printList(users, 0, 0, 0, nil) - return nil - }) - - type ClouduserOptions struct { - USER string - } - shellutils.R(&ClouduserOptions{}, "cloud-user-delete", "Delete clouduser", func(cli *qcloud.SRegion, args *ClouduserOptions) error { - return cli.GetClient().DeleteUser(args.USER) - }) - - shellutils.R(&ClouduserOptions{}, "cloud-user-show", "Show clouduser", func(cli *qcloud.SRegion, args *ClouduserOptions) error { - user, err := cli.GetClient().GetUser(args.USER) - if err != nil { - return err - } - printObject(user) - return nil - }) - - type ClouduserCreateOptions struct { - NAME string - Password string - Desc string - ConsoleLogin bool - } - - shellutils.R(&ClouduserCreateOptions{}, "cloud-user-create", "Create clouduser", func(cli *qcloud.SRegion, args *ClouduserCreateOptions) error { - user, err := cli.GetClient().AddUser(args.NAME, args.Password, args.Desc, args.ConsoleLogin) - if err != nil { - return err - } - printObject(user) - return nil - }) - - type ClouduserPolicyOptions struct { - UIN string - POLICY_ID string - } - - shellutils.R(&ClouduserPolicyOptions{}, "cloud-user-attach-policy", "Attach policy for clouduser", func(cli *qcloud.SRegion, args *ClouduserPolicyOptions) error { - return cli.GetClient().AttachUserPolicy(args.UIN, args.POLICY_ID) - }) - - shellutils.R(&ClouduserPolicyOptions{}, "cloud-user-detach-policy", "Detach policy from clouduser", func(cli *qcloud.SRegion, args *ClouduserPolicyOptions) error { - return cli.GetClient().DetachUserPolicy(args.UIN, args.POLICY_ID) - }) - - type ClouduserPolicyListOptions struct { - UIN string - Offset int - Limit int - } - - shellutils.R(&ClouduserPolicyListOptions{}, "cloud-user-policy-list", "List policy from clouduser", func(cli *qcloud.SRegion, args *ClouduserPolicyListOptions) error { - policies, _, err := cli.GetClient().ListAttachedUserPolicies(args.UIN, args.Offset, args.Limit) - if err != nil { - return err - } - printList(policies, 0, 0, 0, nil) - return nil - }) - - type ClouduserGroupListOptions struct { - UIN int - Offset int - Limit int - } - - shellutils.R(&ClouduserGroupListOptions{}, "cloud-user-group-list", "List clouduser groups", func(cli *qcloud.SRegion, args *ClouduserGroupListOptions) error { - groups, _, err := cli.GetClient().ListGroupsForUser(args.UIN, args.Offset, args.Limit) - if err != nil { - return err - } - printList(groups, 0, 0, 0, nil) - return nil - }) - - type CollaboratorList struct { - Offset int - Limit int - } - - shellutils.R(&CollaboratorList{}, "collaborator-list", "List collaborator", func(cli *qcloud.SRegion, args *CollaboratorList) error { - collaborators, _, err := cli.GetClient().ListCollaborators(args.Offset, args.Limit) - if err != nil { - return err - } - printList(collaborators, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/ccn_route.go b/pkg/multicloud/qcloud/shell/ccn_route.go deleted file mode 100644 index cfcd30db17..0000000000 --- a/pkg/multicloud/qcloud/shell/ccn_route.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CcnRouteListOption struct { - CCNID string - } - shellutils.R(&CcnRouteListOption{}, "ccn-route-list", "List cloud connect network route", func(cli *qcloud.SRegion, args *CcnRouteListOption) error { - routes, err := cli.GetAllCcnRouteSets(args.CCNID) - if err != nil { - return err - } - printList(routes, len(routes), 0, len(routes), []string{}) - return nil - }) - - type CcnRouteEnableOption struct { - CCNID string - ROUTEID string - } - shellutils.R(&CcnRouteEnableOption{}, "ccn-route-enable", "enable cloud connect network route", func(cli *qcloud.SRegion, args *CcnRouteEnableOption) error { - err := cli.EnableCcnRoutes(args.CCNID, []string{args.ROUTEID}) - if err != nil { - return err - } - return nil - }) - - type CcnRouteDisableOption struct { - CCNID string - ROUTEID string - } - shellutils.R(&CcnRouteDisableOption{}, "ccn-route-disable", "disable cloud connect network route", func(cli *qcloud.SRegion, args *CcnRouteDisableOption) error { - err := cli.DisableCcnRoutes(args.CCNID, []string{args.ROUTEID}) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/cdn.go b/pkg/multicloud/qcloud/shell/cdn.go deleted file mode 100644 index 99c9c0999c..0000000000 --- a/pkg/multicloud/qcloud/shell/cdn.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CdnDomainCreateOption struct { - Domain string - OriginType string - Origins []string - CosPrivateAccess string - } - - shellutils.R(&CdnDomainCreateOption{}, "cdn-domain-create", "create cdn domain", func(cli *qcloud.SRegion, args *CdnDomainCreateOption) error { - err := cli.GetClient().AddCdnDomain(args.Domain, args.OriginType, args.Origins, args.CosPrivateAccess) - if err != nil { - return err - } - return nil - }) - - type CdnDomainListOption struct { - Domains []string - Origins []string - DomainType string `help:"origin domain type" choices:"cos|cname"` - } - shellutils.R(&CdnDomainListOption{}, "cdn-domain-list", "list cdn domain", func(cli *qcloud.SRegion, args *CdnDomainListOption) error { - domains, err := cli.GetClient().DescribeAllCdnDomains(args.Domains, args.Origins, args.DomainType) - if err != nil { - return err - } - printList(domains, len(domains), 0, len(domains), nil) - return nil - }) - - type DomainOptions struct { - DOMAIN string - } - - shellutils.R(&DomainOptions{}, "cdn-domain-stop", "Stop cdn domain", func(cli *qcloud.SRegion, args *DomainOptions) error { - return cli.GetClient().StopCdnDomain(args.DOMAIN) - }) - - shellutils.R(&DomainOptions{}, "cdn-domain-start", "Start cdn domain", func(cli *qcloud.SRegion, args *DomainOptions) error { - return cli.GetClient().StartCdnDomain(args.DOMAIN) - }) - - shellutils.R(&DomainOptions{}, "cdn-domain-delete", "Stop cdn domain", func(cli *qcloud.SRegion, args *DomainOptions) error { - return cli.GetClient().DeleteCdnDomain(args.DOMAIN) - }) - -} diff --git a/pkg/multicloud/qcloud/shell/cloud_connect_network.go b/pkg/multicloud/qcloud/shell/cloud_connect_network.go deleted file mode 100644 index 3a35db76df..0000000000 --- a/pkg/multicloud/qcloud/shell/cloud_connect_network.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CcnListOption struct { - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&CcnListOption{}, "ccn-list", "List cloud connect network", func(cli *qcloud.SRegion, args *CcnListOption) error { - vpcs, total, err := cli.DescribeCcns(nil, args.Offset, args.Limit) - if err != nil { - return err - } - printList(vpcs, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type CcnShowOption struct { - CCNID string - } - shellutils.R(&CcnShowOption{}, "ccn-show", "show cloud connect network", func(cli *qcloud.SRegion, args *CcnShowOption) error { - ccn, err := cli.GetCcnById(args.CCNID) - if err != nil { - return err - } - printObject(ccn) - return nil - }) - - type CcnChildListOption struct { - CCNID string - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&CcnChildListOption{}, "ccn-child-list", "List cloud connect network attatched instance", func(cli *qcloud.SRegion, args *CcnChildListOption) error { - vpcs, total, err := cli.DescribeCcnAttachedInstances(args.CCNID, args.Offset, args.Limit) - if err != nil { - return err - } - printList(vpcs, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type CenCreateOptions struct { - Name string - Description string - } - shellutils.R(&CenCreateOptions{}, "ccn-create", "create cloud connect network", func(cli *qcloud.SRegion, args *CenCreateOptions) error { - opts := cloudprovider.SInterVpcNetworkCreateOptions{} - opts.Name = args.Name - opts.Desc = args.Description - ccnId, err := cli.CreateCcn(&opts) - if err != nil { - return err - } - print(ccnId) - return nil - }) - - type CenDeleteOptions struct { - ID string - } - shellutils.R(&CenDeleteOptions{}, "ccn-delete", "delete cloud connect network", func(cli *qcloud.SRegion, args *CenDeleteOptions) error { - err := cli.DeleteCcn(args.ID) - if err != nil { - return err - } - return nil - }) - - type CenAddVpcOptions struct { - ID string - OwnerId string - VpcId string - VpcRegionId string - } - shellutils.R(&CenAddVpcOptions{}, "ccn-add-vpc", "add vpc to cloud connect network attatched instance", func(cli *qcloud.SRegion, args *CenAddVpcOptions) error { - - instance := qcloud.SCcnAttachInstanceInput{ - InstanceType: "VPC", - InstanceId: args.VpcId, - InstanceRegion: args.VpcRegionId, - } - err := cli.AttachCcnInstances(args.ID, args.OwnerId, []qcloud.SCcnAttachInstanceInput{instance}) - if err != nil { - return err - } - return nil - }) - - type CenRemoveVpcOptions struct { - ID string - VpcId string - VpcRegionId string - } - shellutils.R(&CenAddVpcOptions{}, "ccn-remove-vpc", "remove vpc to cloud connect network attatched instance", func(cli *qcloud.SRegion, args *CenAddVpcOptions) error { - instance := qcloud.SCcnAttachInstanceInput{ - InstanceType: "VPC", - InstanceId: args.VpcId, - InstanceRegion: args.VpcRegionId, - } - err := cli.DetachCcnInstances(args.ID, []qcloud.SCcnAttachInstanceInput{instance}) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/cos.go b/pkg/multicloud/qcloud/shell/cos.go deleted file mode 100644 index 9482e9f16d..0000000000 --- a/pkg/multicloud/qcloud/shell/cos.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/objectstore" -) - -func init() { - objectstore.S3Shell() -} diff --git a/pkg/multicloud/qcloud/shell/disk.go b/pkg/multicloud/qcloud/shell/disk.go deleted file mode 100644 index a1303a1ed5..0000000000 --- a/pkg/multicloud/qcloud/shell/disk.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "context" - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "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 *qcloud.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 DiskOptions struct { - ID string `help:"Disk ID"` - } - shellutils.R(&DiskOptions{}, "disk-delete", "Delete disks", func(cli *qcloud.SRegion, args *DiskOptions) error { - e := cli.DeleteDisk(args.ID) - if e != nil { - return e - } - return nil - }) - - shellutils.R(&DiskOptions{}, "disk-show", "Show disk", func(cli *qcloud.SRegion, args *DiskOptions) error { - disk, err := cli.GetDisk(args.ID) - if err != nil { - return err - } - printObject(disk) - return nil - }) - - type DiskCreateOptions struct { - ZONE string `help:"Zone ID"` - CATEGORY string `help:"Disk category" choices:"CLOUD_BASIC|CLOUD_PREMIUM|CLOUD_SSD"` - NAME string `help:"Disk Name"` - SIZE int `help:"Disk Size GB"` - Desc string `help:"Description"` - ProjectId string `help:"Project Id"` - } - shellutils.R(&DiskCreateOptions{}, "disk-create", "Create disk", func(cli *qcloud.SRegion, args *DiskCreateOptions) error { - diskId, err := cli.CreateDisk(args.ZONE, args.CATEGORY, args.NAME, args.SIZE, args.Desc, args.ProjectId) - if err != nil { - return err - } - fmt.Println(diskId) - return nil - }) - - type DiskResizeOptions struct { - ID string `help:"Disk ID"` - SIZE int64 `help:"Disk Size GB"` - } - shellutils.R(&DiskResizeOptions{}, "disk-resize", "Resize disk", func(cli *qcloud.SRegion, args *DiskResizeOptions) error { - ctx := context.Background() - return cli.ResizeDisk(ctx, args.ID, args.SIZE) - }) - - type DiskResetOptions struct { - ID string `help:"Disk ID"` - SNAPSHOT string `help:"Snapshot ID"` - } - shellutils.R(&DiskResetOptions{}, "disk-reset", "Reset disk", func(cli *qcloud.SRegion, args *DiskResetOptions) error { - return cli.ResetDisk(args.ID, args.SNAPSHOT) - }) -} diff --git a/pkg/multicloud/qcloud/shell/dnspod.go b/pkg/multicloud/qcloud/shell/dnspod.go deleted file mode 100644 index 7a65a37e32..0000000000 --- a/pkg/multicloud/qcloud/shell/dnspod.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "strconv" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DomianListOptions struct { - Offset int - Limit int - Keyword string - } - shellutils.R(&DomianListOptions{}, "domain-list", "List domains", func(cli *qcloud.SRegion, args *DomianListOptions) error { - domains, total, e := cli.GetClient().GetDomains(args.Keyword, args.Offset, args.Limit) - if e != nil { - return e - } - printList(domains, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type DomianCreateOptions struct { - DOMAIN string - } - shellutils.R(&DomianCreateOptions{}, "domain-create", "create domain", func(cli *qcloud.SRegion, args *DomianCreateOptions) error { - domain, e := cli.GetClient().CreateDomian(args.DOMAIN) - if e != nil { - return e - } - printObject(domain) - return nil - }) - - type DomianDeleteOptions struct { - DOMAIN string - } - shellutils.R(&DomianDeleteOptions{}, "domain-delete", "delete domains", func(cli *qcloud.SRegion, args *DomianDeleteOptions) error { - e := cli.GetClient().DeleteDomian(args.DOMAIN) - if e != nil { - return e - } - return nil - }) - - type DomianShowOptions struct { - DOMAIN string - } - shellutils.R(&DomianShowOptions{}, "domain-show", "show domains", func(cli *qcloud.SRegion, args *DomianShowOptions) error { - domain, err := cli.GetClient().GetDomain(args.DOMAIN) - if err != nil { - return err - } - printObject(domain) - return nil - }) - - type DnsRecordListOptions struct { - DOMAIN string - Offset int - Limit int - } - shellutils.R(&DnsRecordListOptions{}, "dnsrecord-list", "List dndrecord", func(cli *qcloud.SRegion, args *DnsRecordListOptions) error { - records, total, e := cli.GetClient().GetDnsRecords(args.DOMAIN, args.Offset, args.Limit) - if e != nil { - return e - } - printList(records, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type DnsRecordCreateOptions struct { - DOMAIN string - NAME string - VALUE string //joined by '*' - TTL int64 - TYPE string - } - shellutils.R(&DnsRecordCreateOptions{}, "dnsrecord-create", "create dndrecord", func(cli *qcloud.SRegion, args *DnsRecordCreateOptions) error { - change := cloudprovider.DnsRecordSet{} - change.DnsName = args.NAME - change.DnsValue = args.VALUE - change.Ttl = args.TTL - change.DnsType = cloudprovider.TDnsType(args.TYPE) - _, e := cli.GetClient().CreateDnsRecord(&change, args.DOMAIN) - if e != nil { - return e - } - return nil - }) - - type DnsRecordUpdateOptions struct { - DOMAIN string - RECORDID int - NAME string - VALUE string //joined by '*' - TTL int64 - TYPE string - } - shellutils.R(&DnsRecordUpdateOptions{}, "dnsrecord-update", "update dndrecord", func(cli *qcloud.SRegion, args *DnsRecordUpdateOptions) error { - change := cloudprovider.DnsRecordSet{} - change.DnsName = args.NAME - change.ExternalId = strconv.Itoa(args.RECORDID) - change.DnsValue = args.VALUE - change.Ttl = args.TTL - change.DnsType = cloudprovider.TDnsType(args.TYPE) - e := cli.GetClient().ModifyDnsRecord(&change, args.DOMAIN) - if e != nil { - return e - } - return nil - }) - - type DnsRecordUpdateStatusOptions struct { - DOMAIN string - RECORDID int - STATUS string `choices:"DISABLE|ENABLE"` - } - shellutils.R(&DnsRecordUpdateStatusOptions{}, "dnsrecord-updatestatus", "update dndrecord", func(cli *qcloud.SRegion, args *DnsRecordUpdateStatusOptions) error { - e := cli.GetClient().ModifyRecordStatus(args.STATUS, strconv.Itoa(args.RECORDID), args.DOMAIN) - if e != nil { - return e - } - return nil - }) - - type DnsRecordRemoveOptions struct { - DOMAIN string - RECORDID string - } - shellutils.R(&DnsRecordRemoveOptions{}, "dnsrecord-delete", "delete dndrecord", func(cli *qcloud.SRegion, args *DnsRecordRemoveOptions) error { - e := cli.GetClient().DeleteDnsRecord(args.RECORDID, args.DOMAIN) - if e != nil { - return e - } - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/doc.go b/pkg/multicloud/qcloud/shell/doc.go deleted file mode 100644 index 5a528c8b98..0000000000 --- a/pkg/multicloud/qcloud/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/qcloud/shell" diff --git a/pkg/multicloud/qcloud/shell/eip.go b/pkg/multicloud/qcloud/shell/eip.go deleted file mode 100644 index b88ae596b0..0000000000 --- a/pkg/multicloud/qcloud/shell/eip.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - Eip string `help:"EIP ID"` - InstanceId string `help:"Instance Id"` - Offset int `help:"List offset"` - Limit int `help:"List limit"` - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *qcloud.SRegion, args *EipListOptions) error { - eips, total, err := cli.GetEips(args.Eip, args.InstanceId, args.Offset, args.Limit) - if err != nil { - return err - } - printList(eips, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type EipAllocateOptions struct { - BANDWIDTH int `help:"EIP bandwoidth"` - NAME string `help:"EIP Name"` - ChargeType string `help:"EIP ChargeType" choices:"traffic|bandwidth"` - } - shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *qcloud.SRegion, args *EipAllocateOptions) error { - eip, err := cli.AllocateEIP(args.NAME, args.BANDWIDTH, args.ChargeType) - 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 *qcloud.SRegion, args *EipReleaseOptions) error { - return cli.DeallocateEIP(args.ID) - }) - - type EipShowOptions struct { - ID string `help:"EIP ID"` - } - shellutils.R(&EipShowOptions{}, "eip-show", "Show an EIP", func(cli *qcloud.SRegion, args *EipShowOptions) error { - eip, err := cli.GetEip(args.ID) - if err != nil { - return err - } - printObject(eip) - return nil - }) - - type EipAssociateOptions struct { - ID string `help:"EIP allocation ID"` - INSTANCE string `help:"Instance ID"` - } - shellutils.R(&EipAssociateOptions{}, "eip-associate", "Associate an EIP", func(cli *qcloud.SRegion, args *EipAssociateOptions) error { - return cli.AssociateEip(args.ID, args.INSTANCE) - }) - - type EipDissociateOptions struct { - ID string `help:"EIP allocation ID"` - } - - shellutils.R(&EipDissociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *qcloud.SRegion, args *EipDissociateOptions) error { - return cli.DissociateEip(args.ID) - }) -} diff --git a/pkg/multicloud/qcloud/shell/elasticcache.go b/pkg/multicloud/qcloud/shell/elasticcache.go deleted file mode 100644 index 5e76aece69..0000000000 --- a/pkg/multicloud/qcloud/shell/elasticcache.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RedisListOptions struct { - } - shellutils.R(&RedisListOptions{}, "redis-list", "List redis", func(cli *qcloud.SRegion, args *RedisListOptions) error { - redis, err := cli.GetCloudElasticcaches("") - if err != nil { - return err - } - printList(redis, 0, 0, 0, []string{}) - return nil - }) - - type RedisParameterListOptions struct { - INSTANCEID string `json:"instanceid"` - } - - shellutils.R(&RedisParameterListOptions{}, "redis-parameter-list", "List redis parameters", func(cli *qcloud.SRegion, args *RedisParameterListOptions) error { - parameters, err := cli.GetCloudElasticcacheParameters(args.INSTANCEID) - if err != nil { - return err - } - printList(parameters, 0, 0, 0, []string{}) - return nil - }) - - type RedisBackupListOptions struct { - INSTANCEID string `json:"instanceid"` - } - - shellutils.R(&RedisBackupListOptions{}, "redis-backup-list", "List redis backups", func(cli *qcloud.SRegion, args *RedisBackupListOptions) error { - backups, err := cli.GetCloudElasticcacheBackups(args.INSTANCEID) - if err != nil { - return err - } - printList(backups, 0, 0, 0, []string{}) - return nil - }) - - type RedisSecGroupListOptions struct { - INSTANCEID string `json:"instanceid"` - } - - shellutils.R(&RedisSecGroupListOptions{}, "redis-secgroup-list", "List redis secgroups", func(cli *qcloud.SRegion, args *RedisSecGroupListOptions) error { - secgroups, err := cli.GetCloudElasticcacheSecurityGroups(args.INSTANCEID) - if err != nil { - return err - } - printList(secgroups, 0, 0, 0, []string{}) - return nil - }) - - type RedisAccountListOptions struct { - INSTANCEID string `json:"instanceid"` - } - - shellutils.R(&RedisAccountListOptions{}, "redis-account-list", "List redis accounts", func(cli *qcloud.SRegion, args *RedisAccountListOptions) error { - accounts, err := cli.GetCloudElasticcacheAccounts(args.INSTANCEID) - if err != nil { - return err - } - printList(accounts, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/elasticsearch.go b/pkg/multicloud/qcloud/shell/elasticsearch.go deleted file mode 100644 index b9e0d3cad1..0000000000 --- a/pkg/multicloud/qcloud/shell/elasticsearch.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ElasticSearchListOptions struct { - Ids []string - Offset int - Limit int - } - shellutils.R(&ElasticSearchListOptions{}, "elastic-search-list", "List Elasticsearch", func(cli *qcloud.SRegion, args *ElasticSearchListOptions) error { - es, _, err := cli.GetElasticSearchs(args.Ids, args.Limit, args.Offset) - if err != nil { - return err - } - printList(es, 0, 0, 0, []string{}) - return nil - }) - - type ElasticSearchIdOptions struct { - ID string - } - - shellutils.R(&ElasticSearchIdOptions{}, "elastic-search-delete", "Delete Elasticsearch", func(cli *qcloud.SRegion, args *ElasticSearchIdOptions) error { - return cli.DeleteElasticSearch(args.ID) - }) - -} diff --git a/pkg/multicloud/qcloud/shell/events.go b/pkg/multicloud/qcloud/shell/events.go deleted file mode 100644 index 8e19fad15e..0000000000 --- a/pkg/multicloud/qcloud/shell/events.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "time" - - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EventListOptions struct { - Start time.Time - End time.Time - Offset int `help:"List offset"` - Limit int `help:"List limit"` - } - shellutils.R(&EventListOptions{}, "event-list", "List events", func(cli *qcloud.SRegion, args *EventListOptions) error { - events, err := cli.GetEvents(args.Start, args.End) - if err != nil { - return err - } - printList(events, 0, args.Offset, args.Limit, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/image.go b/pkg/multicloud/qcloud/shell/image.go deleted file mode 100644 index 446f7e28f8..0000000000 --- a/pkg/multicloud/qcloud/shell/image.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - Status string `help:"Image status"` - Owner string `help:"Image owner" choices:"PRIVATE_IMAGE|PUBLIC_IMAGE|MARKET_IMAGE|SHARED_IMAGE"` - Image 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 *qcloud.SRegion, args *ImageListOptions) error { - imageIds := []string{} - if len(args.Image) > 0 { - imageIds = append(imageIds, args.Image) - } - images, total, err := cli.GetImages(args.Status, args.Owner, imageIds, args.Name, args.Offset, args.Limit) - if err != nil { - return err - } - printList(images, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type ImageCreateOptions struct { - NAME string `helo:"Image name"` - OSTYPE string `helo:"Operation system" choices:"CentOS|Ubuntu|Debian|OpenSUSE|SUSE|CoreOS|FreeBSD|Other Linux|Windows Server 2008|Windows Server 2012|Windows Server 2016"` - OSARCH string `help:"OS Architecture" choices:"x86_64|i386"` - osVersion string `help:"OS Version"` - URL string `helo:"Cos URL"` - } - - shellutils.R(&ImageCreateOptions{}, "image-create", "Create image", func(cli *qcloud.SRegion, args *ImageCreateOptions) error { - image, err := cli.ImportImage(args.NAME, args.OSARCH, args.OSTYPE, args.osVersion, args.URL) - if err != nil { - return err - } - printObject(image) - return nil - }) - - type ImageDeleteOptions struct { - ID string `helo:"Image ID"` - } - - shellutils.R(&ImageDeleteOptions{}, "image-delete", "Delete image", func(cli *qcloud.SRegion, args *ImageDeleteOptions) error { - return cli.DeleteImage(args.ID) - }) - - type ImageSupportSetOptions struct { - } - - shellutils.R(&ImageSupportSetOptions{}, "image-support-set", "Show image support set", func(cli *qcloud.SRegion, args *ImageSupportSetOptions) error { - imageSet, err := cli.GetSupportImageSet() - if err != nil { - return err - } - printObject(imageSet) - return nil - }) - - type ImageParam struct { - osArch string - osDist string - osVersion string - OutputArch string - OutputDist string - OutputOsVersion string - } - - shellutils.R(&ImageSupportSetOptions{}, "image-import-test", "Test image import params", func(cli *qcloud.SRegion, args *ImageSupportSetOptions) error { - imageParams := []ImageParam{ - { - osArch: "test", - osDist: "Centos", - osVersion: "3.4", - OutputArch: apis.OS_ARCH_X86_64, - OutputDist: "CentOS", - OutputOsVersion: "-", - }, - { - osArch: "i386", - osDist: "Centos", - osVersion: "6.9", - OutputArch: "i386", - OutputDist: "CentOS", - OutputOsVersion: "6", - }, - { - osArch: "i386", - osDist: "Centos", - osVersion: "7.1.1503", - OutputArch: "i386", - OutputDist: "CentOS", - OutputOsVersion: "7", - }, - { - osArch: "", - osDist: "", - osVersion: "7.1", - OutputArch: apis.OS_ARCH_X86_64, - OutputDist: "Other Linux", - OutputOsVersion: "-", - }, - { - osArch: apis.OS_ARCH_X86_64, - osDist: "Windows Server", - osVersion: "2008 R2 Datacenter Evaluation", - OutputArch: apis.OS_ARCH_X86_64, - OutputDist: "Windows Server 2008", - OutputOsVersion: "-", - }, - { - osArch: apis.OS_ARCH_X86_64, - osDist: "Ubuntu", - osVersion: "16.04.5", - OutputArch: apis.OS_ARCH_X86_64, - OutputDist: "Ubuntu", - OutputOsVersion: "16", - }, - { - osArch: apis.OS_ARCH_X86_64, - osDist: "Windows%20Server%202008%20R2%20Datacenter", - osVersion: "6.1", - OutputArch: apis.OS_ARCH_X86_64, - OutputDist: "Windows Server 2008", - OutputOsVersion: "-", - }, - { - osArch: apis.OS_ARCH_X86_64, - osDist: "Windows Server 2012 R2 Datacenter Evaluation", - osVersion: "6.2", - OutputArch: apis.OS_ARCH_X86_64, - OutputDist: "Windows Server 2012", - OutputOsVersion: "-", - }, - } - for _, imageParam := range imageParams { - log.Debugf("process %s", imageParam.osDist) - params, err := cli.GetImportImageParams("", imageParam.osArch, imageParam.osDist, imageParam.osVersion, "") - if err != nil { - return err - } - if params["OsType"] != imageParam.OutputDist { - return fmt.Errorf("params: %s osType should be %s not %s", imageParam, imageParam.OutputDist, params["OsType"]) - } - if params["OsVersion"] != imageParam.OutputOsVersion { - return fmt.Errorf("params: %s OsVersion should be %s not %s", imageParam, imageParam.OutputOsVersion, params["OsVersion"]) - } - if params["Architecture"] != imageParam.OutputArch { - return fmt.Errorf("params: %s Architecture should be %s not %s", imageParam, imageParam.OutputArch, params["Architecture"]) - } - } - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/instance.go b/pkg/multicloud/qcloud/shell/instance.go deleted file mode 100644 index aad5a42318..0000000000 --- a/pkg/multicloud/qcloud/shell/instance.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "strings" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "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 *qcloud.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 InstanceCreateOptions 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:"LOCAL_BASIC|LOCAL_SSD|CLOUD_BASIC|CLOUD_PREMIUM|CLOUD_SSD"` - NETWORK string `help:"Network ID"` - PASSWD string `help:"password"` - SECGROUP string `help:"Security group"` - PublicKey string `help:"PublicKey"` - Tag []string `help:"tags"` - } - - shellutils.R(&InstanceCreateOptions{}, "instance-create", "Create a instance", func(cli *qcloud.SRegion, args *InstanceCreateOptions) error { - tags := make(map[string]string) - if len(args.Tag) > 0 { - for _, t := range args.Tag { - ts := strings.Split(t, ":") - if len(ts) >= 2 { - tags[ts[0]] = ts[1] - } else { - tags[ts[0]] = "" - } - } - } - instance, e := cli.CreateInstanceSimple(args.NAME, args.IMAGE, args.CPU, args.MEMORYGB, args.STORAGE, args.Disk, args.NETWORK, args.PASSWD, args.PublicKey, args.SECGROUP, tags) - if e != nil { - return e - } - printObject(instance) - return nil - }) - - type InstanceDiskOperationOptions struct { - ID string `help:"instance ID"` - DISK string `help:"disk ID"` - } - - shellutils.R(&InstanceDiskOperationOptions{}, "instance-attach-disk", "Attach a disk to instance", func(cli *qcloud.SRegion, args *InstanceDiskOperationOptions) error { - err := cli.AttachDisk(args.ID, args.DISK) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&InstanceDiskOperationOptions{}, "instance-detach-disk", "Detach a disk to instance", func(cli *qcloud.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 *qcloud.SRegion, args *InstanceOperationOptions) error { - err := cli.StartVM(args.ID) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&InstanceOperationOptions{}, "instance-convert-eip", "Convert public ip to eip for instance", func(cli *qcloud.SRegion, args *InstanceOperationOptions) error { - err := cli.ConvertPublicIpToEip(args.ID) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&InstanceOperationOptions{}, "instance-vnc", "Get a instance VNC url", func(cli *qcloud.SRegion, args *InstanceOperationOptions) error { - url, err := cli.GetInstanceVNCUrl(args.ID) - if err != nil { - return err - } - fmt.Println(url) - return nil - }) - - type InstanceStopOptions struct { - ID string `help:"instance ID"` - Force bool `help:"Force stop instance"` - StopCharging bool `help:"Stop charging"` - } - shellutils.R(&InstanceStopOptions{}, "instance-stop", "Stop a instance", func(cli *qcloud.SRegion, args *InstanceStopOptions) error { - opts := &cloudprovider.ServerStopOptions{ - IsForce: args.Force, - StopCharging: args.StopCharging, - } - err := cli.StopVM(args.ID, opts) - if err != nil { - return err - } - return nil - }) - shellutils.R(&InstanceOperationOptions{}, "instance-delete", "Delete a instance", func(cli *qcloud.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 *qcloud.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"` - Password string `help:"pasword"` - Keypair string `help:"keypair name"` - Size int `help:"system disk size in GB"` - } - - shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *qcloud.SRegion, args *InstanceRebuildRootOptions) error { - err := cli.ReplaceSystemDisk(args.ID, args.Image, args.Password, args.Keypair, args.Size) - if err != nil { - return err - } - return nil - }) - - type InstanceChangeConfigOptions struct { - ID string `help:"instance ID"` - InstanceType string `help:"instance type"` - } - - shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Deploy keypair/password to a stopped virtual server", func(cli *qcloud.SRegion, args *InstanceChangeConfigOptions) error { - err := cli.ChangeVMConfig(args.ID, args.InstanceType) - if err != nil { - return err - } - return nil - }) - - type InstanceUpdatePasswordOptions struct { - ID string `help:"Instance ID"` - PASSWD string `help:"new password"` - } - shellutils.R(&InstanceUpdatePasswordOptions{}, "instance-update-password", "Update instance password", func(cli *qcloud.SRegion, args *InstanceUpdatePasswordOptions) error { - err := cli.UpdateInstancePassword(args.ID, args.PASSWD) - return err - }) - - type InstanceSetAutoRenewOptions struct { - ID string `help:"Instance ID"` - AutoRenew bool `help:"Set auto renew"` - } - shellutils.R(&InstanceSetAutoRenewOptions{}, "instance-set-auto-renew", "Set instance auto renew flag", func(cli *qcloud.SRegion, args *InstanceSetAutoRenewOptions) error { - return cli.SetInstanceAutoRenew(args.ID, args.AutoRenew) - }) - - type InstanceSaveImageOptions struct { - ID string `help:"Instance ID"` - IMAGE_NAME string `help:"Image name"` - Notes string `hlep:"Image desc"` - } - shellutils.R(&InstanceSaveImageOptions{}, "instance-save-image", "Save instance to image", func(cli *qcloud.SRegion, args *InstanceSaveImageOptions) error { - opts := cloudprovider.SaveImageOptions{ - Name: args.IMAGE_NAME, - Notes: args.Notes, - } - image, err := cli.SaveImage(args.ID, &opts) - if err != nil { - return err - } - printObject(image) - return nil - }) - - type InstanceBandWidthOptions struct { - ID string `help:"Instance ID"` - BANDWIDTH int `help:"Bandwidth"` - InternetChargeType string `help:"InternetChargeType" default:"traffic" choices:"traffic|bandwidth"` - } - shellutils.R(&InstanceBandWidthOptions{}, "instance-change-bandwidth", "Change instance bandwidth", func(cli *qcloud.SRegion, args *InstanceBandWidthOptions) error { - return cli.UpdateInstanceBandwidth(args.ID, args.BANDWIDTH, args.InternetChargeType) - }) - -} diff --git a/pkg/multicloud/qcloud/shell/kafka.go b/pkg/multicloud/qcloud/shell/kafka.go deleted file mode 100644 index 4e8da88eb5..0000000000 --- a/pkg/multicloud/qcloud/shell/kafka.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KafkaListOptions struct { - Id string - Offset int - Limit int - } - shellutils.R(&KafkaListOptions{}, "kafka-list", "List kafka", func(cli *qcloud.SRegion, args *KafkaListOptions) error { - kafkas, _, err := cli.GetKafkas(args.Id, args.Limit, args.Offset) - if err != nil { - return err - } - printList(kafkas, 0, 0, 0, []string{}) - return nil - }) - - type KafkaIdOptions struct { - ID string - } - - type KafkaTopicListOptions struct { - KafkaIdOptions - Offset int - Limit int - } - - shellutils.R(&KafkaTopicListOptions{}, "kafka-topic-list", "List kafka topic", func(cli *qcloud.SRegion, args *KafkaTopicListOptions) error { - topics, _, err := cli.GetKafkaTopics(args.ID, args.Limit, args.Offset) - if err != nil { - return err - } - printList(topics, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/keypair.go b/pkg/multicloud/qcloud/shell/keypair.go deleted file mode 100644 index 3c26582789..0000000000 --- a/pkg/multicloud/qcloud/shell/keypair.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KeyPairListOptions struct { - Name string `help:"Keypair Name"` - IDs []string `help:"Keypari ids"` - Offset int `help:"List offset"` - Limit int `help:"List limit"` - } - shellutils.R(&KeyPairListOptions{}, "keypair-list", "List keypair", func(cli *qcloud.SRegion, args *KeyPairListOptions) error { - keypairs, total, err := cli.GetKeypairs(args.Name, args.IDs, args.Offset, args.Limit) - if err != nil { - return err - } - printList(keypairs, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type KeyPairCreateOptions struct { - NAME string `help:"Keypair Name"` - } - shellutils.R(&KeyPairCreateOptions{}, "keypair-create", "Create keypair", func(cli *qcloud.SRegion, args *KeyPairCreateOptions) error { - keypair, err := cli.CreateKeyPair(args.NAME) - if err != nil { - return err - } - printObject(keypair) - return nil - }) - - type KeyPairAssociateOptions struct { - KEYPAIRID string `help:"Keypair ID"` - INSTANCEID string `help:"Instance ID"` - } - - shellutils.R(&KeyPairAssociateOptions{}, "keypair-associate-instance", "Attach Keypair to a instance", func(cli *qcloud.SRegion, args *KeyPairAssociateOptions) error { - return cli.AttachKeypair(args.INSTANCEID, args.KEYPAIRID) - }) - -} diff --git a/pkg/multicloud/qcloud/shell/kube_cluster.go b/pkg/multicloud/qcloud/shell/kube_cluster.go deleted file mode 100644 index 17d60093bc..0000000000 --- a/pkg/multicloud/qcloud/shell/kube_cluster.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KubeClusterListOptions struct { - IDs []string `help:"Kube Cluster ids"` - Offset int `help:"List offset"` - Limit int `help:"List limit"` - } - shellutils.R(&KubeClusterListOptions{}, "kube-cluster-list", "List kube cluster", func(cli *qcloud.SRegion, args *KubeClusterListOptions) error { - clusters, total, err := cli.GetKubeClusters(args.IDs, args.Offset, args.Limit) - if err != nil { - return err - } - printList(clusters, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type KubeClusterIdOptions struct { - ID string - } - - shellutils.R(&KubeClusterIdOptions{}, "kube-cluster-delete", "Delete kube cluster", func(cli *qcloud.SRegion, args *KubeClusterIdOptions) error { - return cli.DeleteKubeCluster(args.ID, false) - }) - - type KubeClusterKubeconfigOptions struct { - ID string - Private bool - } - - shellutils.R(&KubeClusterKubeconfigOptions{}, "kube-cluster-kubeconfig", "Get kube cluster kubeconfig", func(cli *qcloud.SRegion, args *KubeClusterKubeconfigOptions) error { - config, err := cli.GetKubeConfig(args.ID, args.Private) - if err != nil { - return err - } - printObject(config) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/kube_node_pools.go b/pkg/multicloud/qcloud/shell/kube_node_pools.go deleted file mode 100644 index e48ec14a4b..0000000000 --- a/pkg/multicloud/qcloud/shell/kube_node_pools.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KubeNodePoolListOptions struct { - CLUSTER string `help:"Kube Cluster id"` - } - shellutils.R(&KubeNodePoolListOptions{}, "kube-node-list", "List kube nodes", func(cli *qcloud.SRegion, args *KubeNodePoolListOptions) error { - pools, err := cli.GetKubeNodePools(args.CLUSTER) - if err != nil { - return err - } - printList(pools, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/kube_nodes.go b/pkg/multicloud/qcloud/shell/kube_nodes.go deleted file mode 100644 index 785a93057c..0000000000 --- a/pkg/multicloud/qcloud/shell/kube_nodes.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type KubeNodeListOptions struct { - CLUSTER string `help:"Kube Cluster id"` - Offset int `help:"List offset"` - Limit int `help:"List limit"` - } - shellutils.R(&KubeNodeListOptions{}, "kube-node-list", "List kube nodes", func(cli *qcloud.SRegion, args *KubeNodeListOptions) error { - nodes, total, err := cli.GetKubeNodes(args.CLUSTER, args.Offset, args.Limit) - if err != nil { - return err - } - printList(nodes, total, args.Offset, args.Limit, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/loadbalancer.go b/pkg/multicloud/qcloud/shell/loadbalancer.go deleted file mode 100644 index 6aff12d88f..0000000000 --- a/pkg/multicloud/qcloud/shell/loadbalancer.go +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "io/ioutil" - - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type LbListOptions struct { - } - shellutils.R(&LbListOptions{}, "lb-list", "List loadbalancers", func(cli *qcloud.SRegion, args *LbListOptions) error { - lbs, err := cli.GetILoadBalancers() - if err != nil { - return err - } - - printList(lbs, 0, 0, 0, []string{}) - return nil - }) - - type LbCertListOptions struct { - } - shellutils.R(&LbCertListOptions{}, "lbcert-list", "List certs", func(cli *qcloud.SRegion, args *LbCertListOptions) error { - certs, err := cli.GetCertificates("", "", "") - if err != nil { - return err - } - - printList(certs, 0, 0, 0, []string{}) - return nil - }) - - type LbCertIdOptions struct { - ID string `json:"id" help:"certificate id"` - } - shellutils.R(&LbCertIdOptions{}, "lbcert-show", "Show cert", func(cli *qcloud.SRegion, args *LbCertIdOptions) error { - cert, err := cli.GetCertificate(args.ID) - if err != nil { - return err - } - - printObject(cert) - return nil - }) - - shellutils.R(&LbCertIdOptions{}, "lbcert-delete", "delete cert", func(cli *qcloud.SRegion, args *LbCertIdOptions) error { - err := cli.DeleteCertificate(args.ID) - if err != nil { - return err - } - - return nil - }) - - type LbCertUploadOptions struct { - PublicKeyPath string `json:"public_key_path"` - PrivateKeyPath string `json:"private_key_path"` - CertType string `json:"cert_type"` - Desc string `json:"desc"` - } - - shellutils.R(&LbCertUploadOptions{}, "lbcert-upload", "Upload cert", func(cli *qcloud.SRegion, args *LbCertUploadOptions) error { - public := "" - if len(args.PublicKeyPath) > 0 { - _public, err := ioutil.ReadFile(args.PublicKeyPath) - if err != nil { - return err - } - - public = string(_public) - } - - private := "" - if len(args.PrivateKeyPath) > 0 { - _private, err := ioutil.ReadFile(args.PrivateKeyPath) - if err != nil { - return err - } - - private = string(_private) - } - certId, err := cli.CreateCertificate("", public, private, args.CertType, args.Desc) - if err != nil { - return err - } - - print(certId) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/memcached.go b/pkg/multicloud/qcloud/shell/memcached.go deleted file mode 100644 index cbcdd9e1aa..0000000000 --- a/pkg/multicloud/qcloud/shell/memcached.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type MemcachedListOptions struct { - Ids []string - Offset int - Limit int - } - shellutils.R(&MemcachedListOptions{}, "memcached-list", "List memcached", func(cli *qcloud.SRegion, args *MemcachedListOptions) error { - memcacheds, _, err := cli.GetMemcaches(args.Ids, args.Limit, args.Offset) - if err != nil { - return err - } - printList(memcacheds, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/mongodb.go b/pkg/multicloud/qcloud/shell/mongodb.go deleted file mode 100644 index 5f68bdbadd..0000000000 --- a/pkg/multicloud/qcloud/shell/mongodb.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type MongoDBListOptions struct { - Ids []string - Offset int - Limit int - } - shellutils.R(&MongoDBListOptions{}, "mongodb-list", "List mongodb", func(cli *qcloud.SRegion, args *MongoDBListOptions) error { - dbs, _, err := cli.GetMongoDBs(args.Ids, args.Limit, args.Offset) - if err != nil { - return err - } - printList(dbs, 0, 0, 0, []string{}) - return nil - }) - - type MongoDBIdOptions struct { - ID string - } - - shellutils.R(&MongoDBIdOptions{}, "mongodb-isoloate", "Isolate mongodb", func(cli *qcloud.SRegion, args *MongoDBIdOptions) error { - return cli.IsolateMongoDB(args.ID) - }) - - shellutils.R(&MongoDBIdOptions{}, "mongodb-offline", "Offlie mongodb", func(cli *qcloud.SRegion, args *MongoDBIdOptions) error { - return cli.OfflineIsolatedMongoDB(args.ID) - }) - - shellutils.R(&MongoDBIdOptions{}, "mongodb-delete", "Delete mongodb", func(cli *qcloud.SRegion, args *MongoDBIdOptions) error { - return cli.DeleteMongoDB(args.ID) - }) - - shellutils.R(&MongoDBIdOptions{}, "mongodb-backup-list", "List mongodb backups", func(cli *qcloud.SRegion, args *MongoDBIdOptions) error { - backups, err := cli.GetMongoDBBackups(args.ID) - if err != nil { - return err - } - printList(backups, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/monitor.go b/pkg/multicloud/qcloud/shell/monitor.go deleted file mode 100644 index 4d69e51005..0000000000 --- a/pkg/multicloud/qcloud/shell/monitor.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics", func(cli *qcloud.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - for i := range metrics { - log.Infof("metric: %s %s %s", metrics[i].Id, metrics[i].MetricType, metrics[i].Unit) - printList(metrics[i].Values, len(metrics[i].Values), 0, 0, []string{}) - } - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/natdtable.go b/pkg/multicloud/qcloud/shell/natdtable.go deleted file mode 100644 index 8642d46c7d..0000000000 --- a/pkg/multicloud/qcloud/shell/natdtable.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NatDTableListOptions struct { - VPCID string `help:"Vpc ID"` - NATID string `help:"Nat ID"` - } - shellutils.R(&NatDTableListOptions{}, "dtable-list", "List nat dtables", func(cli *qcloud.SRegion, args *NatDTableListOptions) error { - tables, err := cli.GetDTables(args.NATID, args.VPCID) - if err != nil { - return err - } - printList(tables, len(tables), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/natgateway.go b/pkg/multicloud/qcloud/shell/natgateway.go deleted file mode 100644 index bd06c46005..0000000000 --- a/pkg/multicloud/qcloud/shell/natgateway.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NatGatewayListOptions struct { - VpcId string `help:"Vpc ID"` - Offset int `help:"List offset"` - Limit int `help:"List limit"` - } - shellutils.R(&NatGatewayListOptions{}, "natgateway-list", "List nat gateway", func(cli *qcloud.SRegion, args *NatGatewayListOptions) error { - nats, total, e := cli.GetNatGateways(args.VpcId, args.Offset, args.Limit) - if e != nil { - return e - } - printList(nats, total, args.Offset, args.Limit, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/network.go b/pkg/multicloud/qcloud/shell/network.go deleted file mode 100644 index 9007e70449..0000000000 --- a/pkg/multicloud/qcloud/shell/network.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkListOptions struct { - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&NetworkListOptions{}, "network-list", "List networks", func(cli *qcloud.SRegion, args *NetworkListOptions) error { - networks, total, e := cli.GetNetworks(nil, "", args.Offset, args.Limit) - if e != nil { - return e - } - printList(networks, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type NetworkOptions struct { - ID string `help:"Network ID"` - } - shellutils.R(&NetworkOptions{}, "network-delete", "Delete network", func(cli *qcloud.SRegion, args *NetworkOptions) error { - return cli.DeleteNetwork(args.ID) - }) - - shellutils.R(&NetworkOptions{}, "network-show", "Show network", func(cli *qcloud.SRegion, args *NetworkOptions) error { - network, err := cli.GetNetwork(args.ID) - if err != nil { - return err - } - printObject(network) - return nil - }) - - type NetworkCreateOptions struct { - ZONE string `help:"Zone ID"` - VPC string `help:"VPC ID"` - CIDR string `help:"Network CIDR"` - NAME string `help:"Network Name"` - } - shellutils.R(&NetworkCreateOptions{}, "network-create", "Create network", func(cli *qcloud.SRegion, args *NetworkCreateOptions) error { - networkId, err := cli.CreateNetwork(args.ZONE, args.VPC, args.NAME, args.CIDR, "") - if err != nil { - return err - } - fmt.Println(networkId) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/networkinterface.go b/pkg/multicloud/qcloud/shell/networkinterface.go deleted file mode 100644 index 6d5bbbbeee..0000000000 --- a/pkg/multicloud/qcloud/shell/networkinterface.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkInterfaceListOptions struct { - Subnet string - Ids []string - InstanceId string - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&NetworkInterfaceListOptions{}, "network-interface-list", "List network interfaces", func(cli *qcloud.SRegion, args *NetworkInterfaceListOptions) error { - interfaces, total, err := cli.GetNetworkInterfaces(args.Ids, args.InstanceId, args.Subnet, args.Offset, args.Limit) - if err != nil { - return err - } - printList(interfaces, total, args.Offset, args.Limit, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/printutils.go b/pkg/multicloud/qcloud/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/qcloud/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/qcloud/shell/project.go b/pkg/multicloud/qcloud/shell/project.go deleted file mode 100644 index 574ba3f15d..0000000000 --- a/pkg/multicloud/qcloud/shell/project.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ProjectListOptions struct { - } - shellutils.R(&ProjectListOptions{}, "project-list", "List project", func(cli *qcloud.SRegion, args *ProjectListOptions) error { - projects, err := cli.GetClient().GetProjects() - if err != nil { - return err - } - printList(projects, 0, 0, 0, nil) - return nil - }) - - type ProjectCreateOptions struct { - NAME string - Desc string - } - - shellutils.R(&ProjectCreateOptions{}, "project-create", "Create project", func(cli *qcloud.SRegion, args *ProjectCreateOptions) error { - project, err := cli.GetClient().CreateProject(args.NAME, args.Desc) - if err != nil { - return err - } - printObject(project) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/quota.go b/pkg/multicloud/qcloud/shell/quota.go deleted file mode 100644 index 1125e3215c..0000000000 --- a/pkg/multicloud/qcloud/shell/quota.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageQuotaShowOptions struct { - } - shellutils.R(&ImageQuotaShowOptions{}, "image-quota", "Show image quota", func(cli *qcloud.SRegion, args *ImageQuotaShowOptions) error { - quota, err := cli.GetImageQuota() - if err != nil { - return err - } - printObject(quota) - return nil - }) - - type QuotaListOptions struct { - ACTION string `choices:"DescribeAddressQuota|DescribeBandwidthPackageQuota"` - } - - shellutils.R(&QuotaListOptions{}, "quota-list", "List quotas", func(cli *qcloud.SRegion, args *QuotaListOptions) error { - quotas, err := cli.GetQuota(args.ACTION) - if err != nil { - return err - } - printList(quotas, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/rds_mariadb.go b/pkg/multicloud/qcloud/shell/rds_mariadb.go deleted file mode 100644 index 4738a670f2..0000000000 --- a/pkg/multicloud/qcloud/shell/rds_mariadb.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "github.com/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type MariadbRegionListOptions struct { - } - shellutils.R(&MariadbRegionListOptions{}, "mariadb-region-list", "List mariadb region list", func(cli *qcloud.SRegion, args *MariadbRegionListOptions) error { - regions, err := cli.DescribeSaleInfo() - if err != nil { - return errors.Wrapf(err, "DescribeSaleInfo") - } - printList(regions, 0, 0, 0, nil) - return nil - }) - - type MariadbSpecListOptions struct { - } - - shellutils.R(&MariadbSpecListOptions{}, "mariadb-spec-list", "List mariadb specs", func(cli *qcloud.SRegion, args *MariadbSpecListOptions) error { - specs, err := cli.DescribeDBInstanceSpecs() - if err != nil { - return errors.Wrapf(err, "DescribeDBInstanceSpecs") - } - printList(specs, 0, 0, 0, nil) - return nil - }) - - type MariadbSkuListOptions struct { - } - - shellutils.R(&MariadbSkuListOptions{}, "mariadb-sku-list", "List mariadb skus", func(cli *qcloud.SRegion, args *MariadbSkuListOptions) error { - skus, err := cli.ListMariadbSkus() - if err != nil { - return errors.Wrapf(err, "ListMariadbSkus") - } - printList(skus, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/rds_mysql.go b/pkg/multicloud/qcloud/shell/rds_mysql.go deleted file mode 100644 index 3de8c3678d..0000000000 --- a/pkg/multicloud/qcloud/shell/rds_mysql.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type MysqlSkuListOptions struct { - } - shellutils.R(&MysqlSkuListOptions{}, "mysql-sku-list", "List mysql instance types", func(cli *qcloud.SRegion, args *MysqlSkuListOptions) error { - skus, err := cli.ListMysqlSkus() - if err != nil { - return errors.Wrapf(err, "ListMysqlSkus") - } - printList(skus, 0, 0, 0, nil) - return nil - }) - - type MysqlInstanceListOptions struct { - Ids []string - Offset int - Limit int - } - - shellutils.R(&MysqlInstanceListOptions{}, "mysql-instance-list", "List mysql instance", func(cli *qcloud.SRegion, args *MysqlInstanceListOptions) error { - result, _, err := cli.ListMySQLInstances(args.Ids, args.Offset, args.Limit) - if err != nil { - return errors.Wrapf(err, "ListMySQLInstances") - } - printList(result, 0, 0, 0, nil) - return nil - }) - - type MySQLInstanceIdOptions struct { - ID string - } - - shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-reboot", "Reboot mysql instance", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error { - return cli.RebootMySQLInstance(args.ID) - }) - - shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-isolate", "Isolate mysql instance", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error { - return cli.IsolateMySQLDBInstance(args.ID) - }) - - shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-offline-isolate", "Offline Isolate mysql instance", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error { - return cli.OfflineIsolatedMySQLInstances([]string{args.ID}) - }) - - shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-release-isolate", "Release Isolate mysql instance", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error { - return cli.ReleaseIsolatedMySQLDBInstances([]string{args.ID}) - }) - - shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-secgroup-list", "List mysql instance secgroups", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error { - secgroups, err := cli.DescribeMySQLDBSecurityGroups(args.ID) - if err != nil { - return err - } - printList(secgroups, 0, 0, 0, nil) - return nil - }) - - type MySQLInstanceDBListOptions struct { - MySQLInstanceIdOptions - Offset int - Limit int - } - - shellutils.R(&MySQLInstanceDBListOptions{}, "mysql-instance-database-list", "List mysql instance database", func(cli *qcloud.SRegion, args *MySQLInstanceDBListOptions) error { - databases, totalCount, err := cli.DescribeMySQLDatabases(args.ID, args.Offset, args.Limit) - if err != nil { - return err - } - printList(databases, 0, 0, 0, nil) - fmt.Println("TotalCount: ", totalCount) - return nil - }) - - shellutils.R(&MySQLInstanceDBListOptions{}, "mysql-instance-account-list", "List mysql instance accounts", func(cli *qcloud.SRegion, args *MySQLInstanceDBListOptions) error { - accounts, totalCount, err := cli.DescribeMySQLAccounts(args.ID, args.Offset, args.Limit) - if err != nil { - return err - } - printList(accounts, 0, 0, 0, nil) - fmt.Println("TotalCount: ", totalCount) - return nil - }) - - shellutils.R(&MySQLInstanceDBListOptions{}, "mysql-instance-backup-list", "List mysql instance backups", func(cli *qcloud.SRegion, args *MySQLInstanceDBListOptions) error { - backups, totalCount, err := cli.DescribeMySQLBackups(args.ID, args.Offset, args.Limit) - if err != nil { - return err - } - printList(backups, 0, 0, 0, nil) - fmt.Println("TotalCount: ", totalCount) - return nil - }) - - shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-show", "Show mysql instance", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error { - result, err := cli.DescribeMySQLDBInstanceInfo(args.ID) - if err != nil { - return err - } - printObject(result) - return nil - }) - - type MySQLRenewOptions struct { - MySQLInstanceIdOptions - MONTH int `choices:"1|2|3|4|5|6|7|8|9|10|11|12|24|36"` - } - - type MySQLAutoRenewOptions struct { - MySQLInstanceIdOptions - AutoRenew bool - } - - shellutils.R(&MySQLAutoRenewOptions{}, "mysql-instance-set-auto-renew", "Set Auto Renew for mysql instance", func(cli *qcloud.SRegion, args *MySQLAutoRenewOptions) error { - return cli.ModifyMySQLAutoRenewFlag([]string{args.ID}, args.AutoRenew) - }) - - shellutils.R(&MySQLRenewOptions{}, "mysql-instance-renew", "Renew mysql instance", func(cli *qcloud.SRegion, args *MySQLRenewOptions) error { - return cli.RenewMySQLDBInstance(args.ID, args.MONTH) - }) - - shellutils.R(&MySQLInstanceIdOptions{}, "mysql-instance-backup-create", "Create mysql instance backup", func(cli *qcloud.SRegion, args *MySQLInstanceIdOptions) error { - backup, err := cli.CreateMySQLBackup(args.ID, nil) - if err != nil { - return err - } - printObject(backup) - return nil - }) - - type RestAccountPasswordOptions struct { - INSTANCE_ID string - PASSWORD string - USER string - Host string `default:"%"` - } - - shellutils.R(&RestAccountPasswordOptions{}, "mysql-account-reset-password", "Reset mysql account password", func(cli *qcloud.SRegion, args *RestAccountPasswordOptions) error { - return cli.ModifyMySQLAccountPassword(args.INSTANCE_ID, args.PASSWORD, map[string]string{args.USER: args.Host}) - }) - - type MySQLAccountPrivilegeShowOptions struct { - INSTANCE_ID string - USER string - Host string `default:"%"` - } - - shellutils.R(&MySQLAccountPrivilegeShowOptions{}, "mysql-account-privilege-show", "Show account privileges", func(cli *qcloud.SRegion, args *MySQLAccountPrivilegeShowOptions) error { - result, err := cli.DescribeAccountPrivileges(args.INSTANCE_ID, args.USER, args.Host) - if err != nil { - return err - } - printObject(result) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/rds_postgre.go b/pkg/multicloud/qcloud/shell/rds_postgre.go deleted file mode 100644 index 66e2c58cf7..0000000000 --- a/pkg/multicloud/qcloud/shell/rds_postgre.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type PostgreSQLProductListOptions struct { - } - shellutils.R(&PostgreSQLProductListOptions{}, "postgre-product-list", "List postgre sql products", func(cli *qcloud.SRegion, args *PostgreSQLProductListOptions) error { - products, err := cli.DescribeProductConfig() - if err != nil { - return errors.Wrapf(err, "DescribeProductConfig") - } - printList(products, 0, 0, 0, nil) - return nil - }) - - type SPostgreSQLSkuListOptions struct { - } - - shellutils.R(&SPostgreSQLSkuListOptions{}, "postgre-sku-list", "List postgre sql skus", func(cli *qcloud.SRegion, args *SPostgreSQLSkuListOptions) error { - skus, err := cli.ListPostgreSQLSkus() - if err != nil { - return errors.Wrapf(err, "ListPostgreSQLSkus") - } - printList(skus, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/rds_sqlserver.go b/pkg/multicloud/qcloud/shell/rds_sqlserver.go deleted file mode 100644 index e9d854c331..0000000000 --- a/pkg/multicloud/qcloud/shell/rds_sqlserver.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SQLServerSQLProductListOptions struct { - ZONE string - } - shellutils.R(&SQLServerSQLProductListOptions{}, "sqlserver-product-list", "List sql server products", func(cli *qcloud.SRegion, args *SQLServerSQLProductListOptions) error { - products, err := cli.DescribeSqlServerProductConfig(args.ZONE) - if err != nil { - return errors.Wrapf(err, "DescribeProductConfig") - } - printList(products, 0, 0, 0, nil) - return nil - }) - - type SSQLServerSQLSkuListOptions struct { - } - - shellutils.R(&SSQLServerSQLSkuListOptions{}, "sqlserver-sku-list", "List sqlserver skus", func(cli *qcloud.SRegion, args *SSQLServerSQLSkuListOptions) error { - skus, err := cli.ListSQLServerSkus() - if err != nil { - return errors.Wrapf(err, "ListSQLServerSkus") - } - printList(skus, 0, 0, 0, nil) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/region.go b/pkg/multicloud/qcloud/shell/region.go deleted file mode 100644 index 67aea5beaf..0000000000 --- a/pkg/multicloud/qcloud/shell/region.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *qcloud.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/route_table.go b/pkg/multicloud/qcloud/shell/route_table.go deleted file mode 100644 index 9f3966d115..0000000000 --- a/pkg/multicloud/qcloud/shell/route_table.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "github.com/pkg/errors" - - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RouteTableListOption struct { - VpcId string - } - shellutils.R(&RouteTableListOption{}, "routetable-list", "list routetable", func(cli *qcloud.SRegion, args *RouteTableListOption) error { - routetables, err := cli.GetAllRouteTables(args.VpcId, []string{}) - if err != nil { - return errors.Wrapf(err, "GetAllRouteTables") - } - printList(routetables, 0, 0, 0, nil) - return nil - }) - - type RouteTableShowOption struct { - ROUTETABLEID string - } - shellutils.R(&RouteTableShowOption{}, "routetable-show", "show routetable", func(cli *qcloud.SRegion, args *RouteTableShowOption) error { - routetables, err := cli.GetAllRouteTables("", []string{args.ROUTETABLEID}) - if err != nil { - return errors.Wrapf(err, "GetAllRouteTables") - } - printList(routetables, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/saml_provider.go b/pkg/multicloud/qcloud/shell/saml_provider.go deleted file mode 100644 index 370b561743..0000000000 --- a/pkg/multicloud/qcloud/shell/saml_provider.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SAMLProviderListOptions struct { - } - shellutils.R(&SAMLProviderListOptions{}, "saml-provider-list", "List saml provider", func(cli *qcloud.SRegion, args *SAMLProviderListOptions) error { - result, err := cli.GetClient().ListSAMLProviders() - if err != nil { - return err - } - printList(result, 0, 0, 0, nil) - return nil - }) - - type SAMLProviderCreateOptions struct { - NAME string - Desc string - METADATA string - } - - shellutils.R(&SAMLProviderCreateOptions{}, "saml-provider-create", "Create saml provider", func(cli *qcloud.SRegion, args *SAMLProviderCreateOptions) error { - result, err := cli.GetClient().CreateSAMLProvider(args.NAME, args.METADATA, args.Desc) - if err != nil { - return err - } - printObject(result) - return nil - }) - - type SAMLProviderNameOptions struct { - NAME string - } - - shellutils.R(&SAMLProviderNameOptions{}, "saml-provider-show", "Show saml provider", func(cli *qcloud.SRegion, args *SAMLProviderNameOptions) error { - result, err := cli.GetClient().GetSAMLProvider(args.NAME) - if err != nil { - return err - } - printObject(result) - return nil - }) - - shellutils.R(&SAMLProviderNameOptions{}, "saml-provider-delete", "Delete saml provider", func(cli *qcloud.SRegion, args *SAMLProviderNameOptions) error { - return cli.GetClient().DeleteSAMLProvider(args.NAME) - }) - - type SAMLProviderUpdateOptions struct { - NAME string - Desc string - Metadata string - } - - shellutils.R(&SAMLProviderUpdateOptions{}, "saml-provider-update", "Update saml provider", func(cli *qcloud.SRegion, args *SAMLProviderUpdateOptions) error { - return cli.GetClient().UpdateSAMLProvider(args.NAME, args.Metadata, args.Desc) - }) - -} diff --git a/pkg/multicloud/qcloud/shell/securitygroup.go b/pkg/multicloud/qcloud/shell/securitygroup.go deleted file mode 100644 index 4329466446..0000000000 --- a/pkg/multicloud/qcloud/shell/securitygroup.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - Ids []string `help:"Secgroup Ids"` - VpcId string `help:"Vpc Id"` - Name string `help:"Secgroup Name"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List SecurityGroup", func(cli *qcloud.SRegion, args *SecurityGroupListOptions) error { - secgrps, total, err := cli.GetSecurityGroups(args.Ids, args.VpcId, args.Name, args.Limit, args.Offset) - if err != nil { - return err - } - printList(secgrps, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type SecurityGroupOptions struct { - ID string `help:"SecurityGroup ID"` - } - shellutils.R(&SecurityGroupOptions{}, "security-group-show", "Show SecurityGroup", func(cli *qcloud.SRegion, args *SecurityGroupOptions) error { - secgroups, _, err := cli.GetSecurityGroups([]string{args.ID}, "", "", 0, 1) - if err != nil { - return err - } - if len(secgroups) == 1 { - printObject(secgroups[0]) - return nil - } - return cloudprovider.ErrNotFound - }) - - shellutils.R(&SecurityGroupOptions{}, "security-group-references", "Show references of a security group", func(cli *qcloud.SRegion, args *SecurityGroupOptions) error { - references, err := cli.DescribeSecurityGroupReferences(args.ID) - if err != nil { - return err - } - printList(references, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&SecurityGroupOptions{}, "security-group-delete", "Delete SecurityGroup", func(cli *qcloud.SRegion, args *SecurityGroupOptions) error { - return cli.DeleteSecurityGroup(args.ID) - }) - - type SecurityGroupCreateOptions struct { - NAME string `help:"SecurityGroup Name"` - ProjectId string `help:"Project SecurityGroup belong to"` - Desc string `help:"SecurityGroup Description"` - } - - shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create SecurityGroup", func(cli *qcloud.SRegion, args *SecurityGroupCreateOptions) error { - secgrp, err := cli.CreateSecurityGroup(args.NAME, args.ProjectId, args.Desc) - if err != nil { - return err - } - printObject(secgrp) - return nil - }) - - type AddressShowOptions struct { - Id string `help:"IP address ID"` - Name string `help:"IP address name"` - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&AddressShowOptions{}, "address-list", "Show address", func(cli *qcloud.SRegion, args *AddressShowOptions) error { - address, total, err := cli.AddressList(args.Id, args.Name, args.Offset, args.Limit) - if err != nil { - return err - } - printList(address, total, args.Offset, args.Limit, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/snapshot.go b/pkg/multicloud/qcloud/shell/snapshot.go deleted file mode 100644 index 89769b20a8..0000000000 --- a/pkg/multicloud/qcloud/shell/snapshot.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "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 *qcloud.SRegion, args *SnapshotListOptions) error { - snapshots, total, err := cli.GetSnapshots(args.InstanceId, args.DiskId, args.Name, args.SnapshotIds, args.Offset, args.Limit) - if err != nil { - return err - } - 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 *qcloud.SRegion, args *SnapshotDeleteOptions) error { - return cli.DeleteSnapshot(args.ID) - }) - - type SnapshotCreateOptions struct { - DISK string `help:"Disk ID"` - Name string `help:"Snapeshot Name"` - Desc string `help:"Snapshot Desc"` - } - - shellutils.R(&SnapshotCreateOptions{}, "snapshot-create", "Create snapshot", func(cli *qcloud.SRegion, args *SnapshotCreateOptions) error { - _, err := cli.CreateSnapshot(args.DISK, args.Name, args.Desc) - return err - }) - -} diff --git a/pkg/multicloud/qcloud/shell/snapshot_policy.go b/pkg/multicloud/qcloud/shell/snapshot_policy.go deleted file mode 100644 index 7a1e120004..0000000000 --- a/pkg/multicloud/qcloud/shell/snapshot_policy.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SSnapshotPolicyListOptions struct { - PolicyId string `help:"snapshot policy id"` - Offset int `help:"offset"` - Limit int `help:"limit"` - } - - shellutils.R(&SSnapshotPolicyListOptions{}, "snapshot-policy-list", "list snapshot policy", - func(cli *qcloud.SRegion, args *SSnapshotPolicyListOptions) error { - snapshotPolicis, num, err := cli.GetSnapshotPolicies(args.PolicyId, args.Offset, args.Limit) - if err != nil { - return err - } - - printList(snapshotPolicis, num, args.Offset, args.Limit, []string{}) - return nil - }, - ) - - type SSnapshotPolicyDeleteOptions struct { - ID string `help:"snapshot id"` - } - shellutils.R(&SSnapshotPolicyDeleteOptions{}, "snapshot-policy-delete", "delete snapshot policy", - func(cli *qcloud.SRegion, args *SSnapshotPolicyDeleteOptions) error { - err := cli.DeleteSnapshotPolicy(args.ID) - return err - }, - ) - - type SSnapshotPolicyCreateOptions struct { - Name string `help:"snapshot name"` - - RetentionDays int `help:"retention days"` - RepeatWeekdays []int `help:"auto snapshot which days of the week"` - TimePoints []int `help:"auto snapshot which hours of the day"` - } - shellutils.R(&SSnapshotPolicyCreateOptions{}, "snapshot-policy-create", "create snapshot policy", - func(cli *qcloud.SRegion, args *SSnapshotPolicyCreateOptions) error { - input := cloudprovider.SnapshotPolicyInput{ - RetentionDays: args.RetentionDays, - RepeatWeekdays: args.RepeatWeekdays, - TimePoints: args.TimePoints, - PolicyName: args.Name, - } - _, err := cli.CreateSnapshotPolicy(&input) - if err != nil { - return err - } - return nil - }, - ) - - type SSnapshotPolicyApplyOptions struct { - SNAPSHOTPOLICYID string `help:"snapshot policy id"` - DISKID string `help:"disk id"` - } - shellutils.R(&SSnapshotPolicyApplyOptions{}, "snapshot-policy-apply", "apply snapshot policy", - func(cli *qcloud.SRegion, args *SSnapshotPolicyApplyOptions) error { - err := cli.ApplySnapshotPolicyToDisks(args.SNAPSHOTPOLICYID, args.DISKID) - return err - }, - ) - - type SSnapshotPolicyCancelOptions struct { - SNAPSHOTPOLICYID string `help:"snapshot policy id"` - DISKID string `help:"disk id"` - } - shellutils.R(&SSnapshotPolicyCancelOptions{}, "snapshot-policy-cancel", "cancel snapshot policy", - func(cli *qcloud.SRegion, args *SSnapshotPolicyCancelOptions) error { - err := cli.CancelSnapshotPolicyToDisks(args.SNAPSHOTPOLICYID, args.DISKID) - return err - }, - ) -} diff --git a/pkg/multicloud/qcloud/shell/storage.go b/pkg/multicloud/qcloud/shell/storage.go deleted file mode 100644 index 469f57b0a8..0000000000 --- a/pkg/multicloud/qcloud/shell/storage.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type StorageListOptions struct { - ZONE string `help:"ID or Name of zone"` - } - shellutils.R(&StorageListOptions{}, "storage-list", "List storages", func(cli *qcloud.SRegion, args *StorageListOptions) error { - storages, err := cli.GetDiskConfigSet(args.ZONE) - if err != nil { - return err - } - printList(storages, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/sts.go b/pkg/multicloud/qcloud/shell/sts.go deleted file mode 100644 index 6f2c2d2151..0000000000 --- a/pkg/multicloud/qcloud/shell/sts.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type CallerShowOptions struct { - } - shellutils.R(&CallerShowOptions{}, "caller-show", "Show caller", func(cli *qcloud.SRegion, args *CallerShowOptions) error { - caller, err := cli.GetClient().GetCallerIdentity() - if err != nil { - return err - } - printObject(caller) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/tags.go b/pkg/multicloud/qcloud/shell/tags.go deleted file mode 100644 index daf1ae83f6..0000000000 --- a/pkg/multicloud/qcloud/shell/tags.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - "strings" - - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type TagGetOptions struct { - SERVICE string `help:"service, eg. cvm"` - RESTYPE string `help:"resource type, eg. instance"` - ID []string `help:"resource Id, eg. ins-123xxx"` - } - shellutils.R(&TagGetOptions{}, "tag-show", "show tag of a specific resource", func(cli *qcloud.SRegion, args *TagGetOptions) error { - tags, err := cli.FetchResourceTags(args.SERVICE, args.RESTYPE, args.ID) - if err != nil { - return err - } - for id, tag := range tags { - fmt.Println(id, *tag) - } - return nil - }) - - type TagSetOptions struct { - TagGetOptions - Tag []string `help:"tag to set, key:value"` - Replace bool `help:"replace all tags"` - } - shellutils.R(&TagSetOptions{}, "tag-set", "set tags of a specific resource", func(cli *qcloud.SRegion, args *TagSetOptions) error { - tags := make(map[string]string) - for _, t := range args.Tag { - parts := strings.Split(t, ":") - tags[parts[0]] = parts[1] - } - err := cli.SetResourceTags(args.SERVICE, args.RESTYPE, args.ID, tags, args.Replace) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/tdsql.go b/pkg/multicloud/qcloud/shell/tdsql.go deleted file mode 100644 index e88bd12a21..0000000000 --- a/pkg/multicloud/qcloud/shell/tdsql.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type TDSQLListOptions struct { - Ids []string - Limit int - Offset int - } - shellutils.R(&TDSQLListOptions{}, "tdsql-list", "List tdsql", func(cli *qcloud.SRegion, args *TDSQLListOptions) error { - tdsqls, _, err := cli.GetTDSQLs(args.Ids, args.Limit, args.Offset) - if err != nil { - return err - } - printList(tdsqls, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/qcloud/shell/vpc.go b/pkg/multicloud/qcloud/shell/vpc.go deleted file mode 100644 index de977ab17b..0000000000 --- a/pkg/multicloud/qcloud/shell/vpc.go +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "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 *qcloud.SRegion, args *VpcListOptions) error { - vpcs, total, err := cli.GetVpcs(nil, args.Offset, args.Limit) - if err != nil { - return err - } - printList(vpcs, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type VpcCreateOptions struct { - NAME string `help:"Name for vpc"` - CIDR string `help:"Cidr for vpc" choices:"10.0.0.0/16|172.16.0.0/12|192.168.0.0/16"` - } - shellutils.R(&VpcCreateOptions{}, "vpc-create", "Create vpc", func(cli *qcloud.SRegion, args *VpcCreateOptions) error { - opts := &cloudprovider.VpcCreateOptions{ - NAME: args.NAME, - CIDR: args.CIDR, - } - vpc, err := cli.CreateIVpc(opts) - if err != nil { - return err - } - printObject(vpc) - return nil - }) - - type VpcDeleteOptions struct { - ID string `help:"VPC ID or Name"` - } - shellutils.R(&VpcDeleteOptions{}, "vpc-delete", "Delete vpc", func(cli *qcloud.SRegion, args *VpcDeleteOptions) error { - return cli.DeleteVpc(args.ID) - }) - - type VpcPCListOption struct { - VPCID string - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&VpcPCListOption{}, "vpcPC-list", "List vpc peering connections", func(cli *qcloud.SRegion, args *VpcPCListOption) error { - vpcs, total, err := cli.DescribeVpcPeeringConnections(args.VPCID, "", args.Offset, args.Limit) - if err != nil { - return err - } - printList(vpcs, total, args.Offset, args.Limit, []string{}) - return nil - }) - - type VpcPCShowOption struct { - VPCPCID string - } - shellutils.R(&VpcPCShowOption{}, "vpcPC-show", "show vpc peering connection", func(cli *qcloud.SRegion, args *VpcPCShowOption) error { - vpcPC, err := cli.GetVpcPeeringConnectionbyId(args.VPCPCID) - if err != nil { - return err - } - printObject(vpcPC) - return nil - }) - - type VpcPCCreateOPtion struct { - NAME string - VPCID string - PEERVPCID string - PEERREGIONID string - PEEROWNERID string - Bandwidth int - } - shellutils.R(&VpcPCCreateOPtion{}, "vpcPC-create", "create vpc peering connection", func(cli *qcloud.SRegion, args *VpcPCCreateOPtion) error { - opts := cloudprovider.VpcPeeringConnectionCreateOptions{} - opts.Name = args.NAME - opts.PeerVpcId = args.PEERVPCID - opts.PeerAccountId = args.PEEROWNERID - opts.PeerRegionId = args.PEERREGIONID - vpcPCId, err := cli.CreateVpcPeeringConnection(args.VPCID, &opts) - if err != nil { - return err - } - printObject(vpcPCId) - return nil - }) - - shellutils.R(&VpcPCCreateOPtion{}, "vpcPC-createEx", "create Ex vpc peering connection", func(cli *qcloud.SRegion, args *VpcPCCreateOPtion) error { - opts := cloudprovider.VpcPeeringConnectionCreateOptions{} - opts.Name = args.NAME - opts.PeerVpcId = args.PEERVPCID - opts.PeerAccountId = args.PEEROWNERID - opts.PeerRegionId = args.PEERREGIONID - opts.Bandwidth = args.Bandwidth - taskId, err := cli.CreateVpcPeeringConnectionEx(args.VPCID, &opts) - if err != nil { - return err - } - printObject(taskId) - return nil - }) - - type VpcPeeringAcceptOPtion struct { - VPCPEERINGID string - } - shellutils.R(&VpcPeeringAcceptOPtion{}, "vpcPC-accept", "Accept vpcPeering", func(cli *qcloud.SRegion, args *VpcPeeringAcceptOPtion) error { - err := cli.AcceptVpcPeeringConnection(args.VPCPEERINGID) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&VpcPeeringAcceptOPtion{}, "vpcPC-acceptEx", "Accept Ex vpcPeering", func(cli *qcloud.SRegion, args *VpcPeeringAcceptOPtion) error { - _, err := cli.AcceptVpcPeeringConnectionEx(args.VPCPEERINGID) - if err != nil { - return err - } - return nil - }) - - type VpcPeeringDeleteOPtion struct { - VPCPEERINGID string - } - shellutils.R(&VpcPeeringAcceptOPtion{}, "vpcPC-delete", "Delete vpcPeering", func(cli *qcloud.SRegion, args *VpcPeeringAcceptOPtion) error { - err := cli.DeleteVpcPeeringConnection(args.VPCPEERINGID) - if err != nil { - return err - } - return nil - }) - - shellutils.R(&VpcPeeringAcceptOPtion{}, "vpcPC-deleteEx", "Delete Ex vpcPeering", func(cli *qcloud.SRegion, args *VpcPeeringAcceptOPtion) error { - status, err := cli.DeleteVpcPeeringConnectionEx(args.VPCPEERINGID) - if err != nil { - return err - } - println(status) - return nil - }) - - type VpcTaskShowOption struct { - TASKID string - } - shellutils.R(&VpcTaskShowOption{}, "vpcTask-show", "show vpc task", func(cli *qcloud.SRegion, args *VpcTaskShowOption) error { - status, err := cli.DescribeVpcTaskResult(args.TASKID) - if err != nil { - return err - } - println(status) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/shell/zone.go b/pkg/multicloud/qcloud/shell/zone.go deleted file mode 100644 index 553ed6f011..0000000000 --- a/pkg/multicloud/qcloud/shell/zone.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/qcloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - Limit int `help:"page size"` - Offset int `help:"page offset"` - } - shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *qcloud.SRegion, args *ZoneListOptions) error { - zones, err := cli.GetIZones() - if err != nil { - return err - } - printList(zones, len(zones), args.Offset, args.Limit, []string{}) - return nil - }) - - type ZoneInstanceTypeListOptions struct { - ZONE string - } - - shellutils.R(&ZoneInstanceTypeListOptions{}, "zone-instance-type-list", "List zone instance type", func(cli *qcloud.SRegion, args *ZoneInstanceTypeListOptions) error { - instanceTypes, err := cli.GetZoneInstanceTypes(args.ZONE) - if err != nil { - return err - } - printList(instanceTypes, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/qcloud/snapshot.go b/pkg/multicloud/qcloud/snapshot.go deleted file mode 100644 index 7789b21d32..0000000000 --- a/pkg/multicloud/qcloud/snapshot.go +++ /dev/null @@ -1,233 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strconv" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SnapshotStatusType string - -const ( - SnapshotStatusAccomplished SnapshotStatusType = "NORMAL" - SnapshotStatusProgress SnapshotStatusType = "CREATING" - SnapshotStatusFailed SnapshotStatusType = "failed" -) - -type SSnapshot struct { - multicloud.SResourceBase - multicloud.QcloudTags - region *SRegion - - SnapshotId string // 快照ID。 - Placement Placement // 快照所在的位置。 - DiskUsage string // 创建此快照的云硬盘类型。取值范围:SYSTEM_DISK:系统盘 DATA_DISK:数据盘。 - DiskId string // 创建此快照的云硬盘ID。 - DiskSize int32 // 创建此快照的云硬盘大小,单位GB。 - SnapshotState SnapshotStatusType // 快照的状态。取值范围: NORMAL:正常 CREATING:创建中 ROLLBACKING:回滚中 COPYING_FROM_REMOTE:跨地域复制快照拷贝中。 - SnapshotName string // 快照名称,用户自定义的快照别名。调用ModifySnapshotAttribute可修改此字段。 - Percent int // 快照创建进度百分比,快照创建成功后此字段恒为100。 - CreateTime time.Time // 快照的创建时间。 - DeadlineTime time.Time // 快照到期时间。如果快照为永久保留,此字段为空。 - Encrypt bool // 是否为加密盘创建的快照。取值范围:true:该快照为加密盘创建的 false:非加密盘创建的快照。 - IsPermanent bool // 是否为永久快照。取值范围: true:永久快照 false:非永久快照。 - CopyingToRegions []string // 快照正在跨地域复制的目的地域,默认取值为[]。 - CopyFromRemote bool // 是否为跨地域复制的快照。取值范围:true:表示为跨地域复制的快照。 false:本地域的快照。 -} - -func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) - if err != nil { - return nil, err - } - if total > 1 { - return nil, cloudprovider.ErrDuplicateId - } - if total == 0 { - return nil, cloudprovider.ErrNotFound - } - return &snapshots[0], nil -} - -func (self *SSnapshot) GetStatus() string { - // NORMAL:正常 - // CREATING:创建中 - // ROLLBACKING:回滚中 - // COPYING_FROM_REMOTE:跨地域复制快照拷贝中。 - switch self.SnapshotState { - case "NORMAL", "COPYING_FROM_REMOTE": - return api.SNAPSHOT_READY - case "CREATING": - return api.SNAPSHOT_CREATING - case "ROLLBACKING": - return api.SNAPSHOT_ROLLBACKING - } - return api.SNAPSHOT_UNKNOWN -} - -func (self *SSnapshot) IsEmulated() bool { - return false -} - -func (self *SSnapshot) Refresh() error { - snapshots, total, err := self.region.GetSnapshots("", "", "", []string{self.SnapshotId}, 0, 1) - if err != nil { - return err - } - if total > 1 { - return cloudprovider.ErrDuplicateId - } - - if total == 0 { - return cloudprovider.ErrNotFound - } - return jsonutils.Update(self, snapshots[0]) -} - -func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["Limit"] = fmt.Sprintf("%d", limit) - params["Offset"] = fmt.Sprintf("%d", offset) - - filter := 0 - if len(instanceId) > 0 { - } - if len(diskId) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "disk-id" - params[fmt.Sprintf("Filters.%d.Values.0", filter)] = diskId - filter++ - } - if len(snapshotName) > 0 { - params[fmt.Sprintf("Filters.%d.Name", filter)] = "snapshot-name" - params[fmt.Sprintf("Filters.%d.Values", filter)] = snapshotName - filter++ - } - if snapshotIds != nil && len(snapshotIds) > 0 { - for index, snapshotId := range snapshotIds { - params[fmt.Sprintf("SnapshotIds.%d", index)] = snapshotId - } - } - snapshots := []SSnapshot{} - body, err := self.cbsRequest("DescribeSnapshots", params) - if err != nil { - log.Errorf("GetSnapshots fail %s", err) - return nil, 0, err - } - body.Unmarshal(&snapshots, "SnapshotSet") - if err != nil { - return nil, 0, err - } - total, _ := body.Float("TotalCount") - for i := 0; i < len(snapshots); i++ { - snapshots[i].region = self - } - return snapshots, int(total), nil -} - -func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, total, err := self.GetSnapshots("", "", "", []string{}, 0, 50) - if err != nil { - return nil, err - } - for len(snapshots) < total { - var parts []SSnapshot - parts, total, err = self.GetSnapshots("", "", "", []string{}, len(snapshots), 50) - if err != nil { - return nil, err - } - snapshots = append(snapshots, parts...) - } - ret := make([]cloudprovider.ICloudSnapshot, len(snapshots)) - for i := 0; i < len(snapshots); i++ { - ret[i] = &snapshots[i] - } - return ret, nil -} - -func (self *SSnapshot) GetRegionId() string { - return self.region.GetId() -} - -func (self *SSnapshot) GetSizeMb() int32 { - return self.DiskSize * 1024 -} - -func (self *SSnapshot) GetDiskId() string { - return self.DiskId -} - -func (self *SSnapshot) GetId() string { - return self.SnapshotId -} - -func (self *SSnapshot) GetGlobalId() string { - return fmt.Sprintf("%s", self.SnapshotId) -} - -func (self *SSnapshot) GetName() string { - return self.SnapshotName -} - -func (self *SSnapshot) Delete() error { - if self.region == nil { - return fmt.Errorf("not init region for snapshot %s", self.SnapshotId) - } - return self.region.DeleteSnapshot(self.SnapshotId) -} - -func (self *SSnapshot) GetDiskType() string { - switch self.DiskUsage { - case "SYSTEM_DISK": - return api.DISK_TYPE_SYS - case "DATA_DISK": - return api.DISK_TYPE_DATA - } - return api.DISK_TYPE_DATA -} - -func (self *SRegion) DeleteSnapshot(snapshotId string) error { - params := map[string]string{"SnapshotIds.0": snapshotId} - _, err := self.cbsRequest("DeleteSnapshots", params) - return err -} - -func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { - params := make(map[string]string) - params["DiskId"] = diskId - params["SnapshotName"] = name - - body, err := self.cbsRequest("CreateSnapshot", params) - if err != nil { - log.Errorf("CreateSnapshot fail %s", err) - return "", err - } - return body.GetString("SnapshotId") -} - -func (self *SSnapshot) GetProjectId() string { - return strconv.Itoa(self.Placement.ProjectId) -} diff --git a/pkg/multicloud/qcloud/snapshot_policy.go b/pkg/multicloud/qcloud/snapshot_policy.go deleted file mode 100644 index 900182d18d..0000000000 --- a/pkg/multicloud/qcloud/snapshot_policy.go +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strconv" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - NORMAL = "NORMAL" - UNKOWN = "ISOLATED" -) - -type SSnapshotDatePolicy struct { - DayOfWeek []int - Hour []int -} - -type SSnapshotPolicy struct { - multicloud.SResourceBase - multicloud.QcloudTags - region *SRegion - - AutoSnapshotPolicyName string - AutoSnapshotPolicyId string - AutoSnapshotPolicyState string - RetentionDays int - Policy []SSnapshotDatePolicy - Activated bool `json:"IsActivated"` - IsPermanent bool -} - -func (self *SSnapshotPolicy) GetId() string { - return self.AutoSnapshotPolicyId -} - -func (self *SSnapshotPolicy) GetName() string { - return self.AutoSnapshotPolicyName -} - -func (self *SSnapshotPolicy) GetGlobalId() string { - return self.GetId() -} - -func (self *SSnapshotPolicy) GetStatus() string { - if self.AutoSnapshotPolicyState == NORMAL { - return api.SNAPSHOT_POLICY_READY - } - return api.SNAPSHOT_POLICY_UNKNOWN -} - -func (self *SSnapshotPolicy) Refresh() error { - if snapshotPolicies, total, err := self.region.GetSnapshotPolicies(self.AutoSnapshotPolicyId, 0, 1); err != nil { - return err - } else if total != 1 { - return cloudprovider.ErrNotFound - } else if err := jsonutils.Update(self, snapshotPolicies[0]); err != nil { - return err - } - return nil -} - -func (self *SSnapshotPolicy) IsEmulated() bool { - return false -} - -func (self *SSnapshotPolicy) GetProjectId() string { - return "" -} - -func (self *SSnapshotPolicy) GetRetentionDays() int { - if self.IsPermanent { - return -1 - } - return self.RetentionDays -} - -func (self *SSnapshotPolicy) GetRepeatWeekdays() ([]int, error) { - if len(self.Policy) == 0 { - return nil, errors.Error("Policy Set Empty") - } - repeatWeekdays := self.Policy[0].DayOfWeek - if len(repeatWeekdays) > 0 { - if repeatWeekdays[0] == 0 { - repeatWeekdays = append(repeatWeekdays, 7)[1:] - } - } - return repeatWeekdays, nil -} - -func (self *SSnapshotPolicy) GetTimePoints() ([]int, error) { - if len(self.Policy) == 0 { - return nil, errors.Error("Policy Set Empty") - } - return self.Policy[0].Hour, nil -} - -func (self *SSnapshotPolicy) IsActivated() bool { - return self.Activated -} - -func (self *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { - snapshotPolicies, total, err := self.GetSnapshotPolicies("", 0, 50) - if err != nil { - return nil, err - } - for len(snapshotPolicies) < total { - var parts []SSnapshotPolicy - parts, total, err = self.GetSnapshotPolicies("", len(snapshotPolicies), 50) - if err != nil { - return nil, err - } - snapshotPolicies = append(snapshotPolicies, parts...) - } - ret := make([]cloudprovider.ICloudSnapshotPolicy, len(snapshotPolicies)) - for i := 0; i < len(snapshotPolicies); i += 1 { - ret[i] = &snapshotPolicies[i] - } - return ret, nil -} - -func (self *SRegion) GetSnapshotPolicies(policyId string, offset int, limit int) ([]SSnapshotPolicy, int, error) { - params := make(map[string]string) - if len(policyId) > 0 { - params["AutoSnapshotPolicyIds.0"] = policyId - } - if limit != 0 { - params["Limit"] = strconv.Itoa(limit) - params["Offset"] = strconv.Itoa(offset) - } - body, err := self.cbsRequest("DescribeAutoSnapshotPolicies", params) - if err != nil { - return nil, 0, errors.Wrap(err, "Get Snapshot Policies failed") - } - snapshotPolicies := make([]SSnapshotPolicy, 0, 1) - if err := body.Unmarshal(&snapshotPolicies, "AutoSnapshotPolicySet"); err != nil { - return nil, 0, errors.Wrap(err, "Unmarshal snapshot policies detail failed") - } - for i := range snapshotPolicies { - snapshotPolicies[i].region = self - } - return snapshotPolicies, len(snapshotPolicies), nil -} - -func (self *SSnapshotPolicy) Delete() error { - if self.region == nil { - return fmt.Errorf("Not init region for snapshotPolicy %s", self.GetId()) - } - return self.region.DeleteSnapshotPolicy(self.GetId()) -} - -func (self *SRegion) DeleteSnapshotPolicy(snapshotPolicyId string) error { - params := make(map[string]string) - params["AutoSnapshotPolicyIds.0"] = snapshotPolicyId - _, err := self.cbsRequest("DeleteAutoSnapshotPolicies", params) - if err != nil { - return errors.Wrapf(err, "delete auto snapshot policy %s failed", snapshotPolicyId) - } - return nil -} - -func (self *SRegion) GetISnapshotPolicyById(snapshotPolicyId string) (cloudprovider.ICloudSnapshotPolicy, error) { - policies, _, err := self.GetSnapshotPolicies(snapshotPolicyId, 0, 1) - if err != nil { - return nil, err - } - if len(policies) == 0 { - return nil, cloudprovider.ErrNotFound - } - return &policies[0], nil -} - -func (self *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput) (string, error) { - if input.RepeatWeekdays == nil { - return "", fmt.Errorf("Can't create snapshot policy with nil repeatWeekdays") - } - if input.TimePoints == nil { - return "", fmt.Errorf("Can't create snapshot policy with nil timePoints") - } - params := make(map[string]string) - - // In Qcloud, that IsPermanent is true means that keep snapshot forever, - // In OneCloud, that RetentionDays is -1 means that keep snapshot forever. - if input.RetentionDays == -1 { - params["IsPermanent"] = strconv.FormatBool(true) - } else { - params["RetentionDays"] = strconv.Itoa(input.RetentionDays) - } - dayOfWeekPrefix, hourPrefix := "Policy.0.DayOfWeek.", "Policy.0.Hour." - for index, day := range input.RepeatWeekdays { - if day == 7 { - day = 0 - } - params[dayOfWeekPrefix+strconv.Itoa(index)] = strconv.Itoa(day) - } - if len(input.PolicyName) > 0 { - params["AutoSnapshotPolicyName"] = input.PolicyName - } - for index, hour := range input.TimePoints { - params[hourPrefix+strconv.Itoa(index)] = strconv.Itoa(hour) - } - body, err := self.cbsRequest("CreateAutoSnapshotPolicy", params) - if err != nil { - return "", errors.Wrap(err, "create auto snapshot policy failed") - } - id, _ := body.GetString("AutoSnapshotPolicyId") - return id, nil -} - -func (self *SRegion) UpdateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput, snapshotPolicyId string) error { - // not implement - return nil -} - -func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { - params := make(map[string]string) - params["AutoSnapshotPolicyId"] = snapshotPolicyId - params["DiskIds.0"] = diskId - _, err := self.cbsRequest("BindAutoSnapshotPolicy", params) - if err != nil { - return errors.Wrapf(err, "Bind AutoSnapshotPolicy %s to Disk failed", snapshotPolicyId) - } - return nil -} - -func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { - params := make(map[string]string) - params["AutoSnapshotPolicyId"] = snapshotPolicyId - params["DiskIds.0"] = diskId - _, err := self.cbsRequest("UnbindAutoSnapshotPolicy", params) - if err != nil { - return errors.Wrapf(err, "Unbind AutoSnapshotPolicy %s of Disk failed", snapshotPolicyId) - } - return nil -} - -func (self *SRegion) GetSnapshotIdByDiskId(diskID string) ([]string, error) { - params := make(map[string]string) - params["DiskId"] = diskID - - rps, err := self.cbsRequest("DescribeDiskAssociatedAutoSnapshotPolicy", params) - if err != nil { - return nil, errors.Wrapf(err, "Get All SnapshotpolicyIDs of Disk %s failed", diskID) - } - - snapshotpolicies := make([]SSnapshotPolicy, 0) - if err := rps.Unmarshal(&snapshotpolicies, "AutoSnapshotPolicySet"); err != nil { - return nil, errors.Wrapf(err, "Unmarshal snapshot policies details failed") - } - ret := make([]string, len(snapshotpolicies)) - for i := range snapshotpolicies { - ret[i] = snapshotpolicies[i].GetId() - } - return ret, nil -} diff --git a/pkg/multicloud/qcloud/storage.go b/pkg/multicloud/qcloud/storage.go deleted file mode 100644 index 2f57344dcc..0000000000 --- a/pkg/multicloud/qcloud/storage.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - multicloud.SStorageBase - zone *SZone - storageType string - available bool -} - -func (self *SStorage) GetId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), strings.ToLower(self.storageType)) -} - -func (self *SStorage) GetName() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), strings.ToLower(self.storageType)) -} - -func (self *SStorage) GetGlobalId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), strings.ToLower(self.storageType)) -} - -func (self *SStorage) IsEmulated() bool { - return true -} - -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++ { - disks[i].storage = self - idisks[i] = &disks[i] - } - return idisks, nil -} - -func (self *SStorage) GetStorageType() string { - return strings.ToLower(self.storageType) -} - -func (self *SStorage) GetMediumType() string { - if strings.HasSuffix(self.storageType, "_BASIC") { - return api.DISK_TYPE_ROTATE - } - return api.DISK_TYPE_SSD -} - -func (self *SStorage) GetCapacityMB() int64 { - return 0 // unlimited -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - conf := jsonutils.NewDict() - return conf -} - -func (self *SStorage) GetStatus() string { - if !self.available { - return api.STORAGE_OFFLINE - } - return api.STORAGE_ONLINE -} - -func (self *SStorage) Refresh() error { - // do nothing - return nil -} - -func (self *SStorage) GetEnabled() bool { - return self.available == true -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.zone.region.getStoragecache() -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - diskId, err := self.zone.region.CreateDisk(self.zone.Zone, self.storageType, conf.Name, conf.SizeGb, conf.Desc, conf.ProjectId) - if err != nil { - log.Errorf("createDisk fail %s", err) - return nil, err - } - //腾讯刚创建完成的磁盘,需要稍微等待才能查询 - for i := 0; i < 3; i++ { - disk, err := self.zone.region.GetDisk(diskId) - if err == nil { - disk.storage = self - return disk, nil - } - time.Sleep(time.Second * 3) - } - log.Errorf("getDisk fail %s id %s", err, diskId) - return nil, cloudprovider.ErrNotFound -} - -func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { - disk, err := self.zone.region.GetDisk(idStr) - if err != nil { - return nil, err - } - disk.storage = self - return disk, nil -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - return strings.ToLower(self.storageType) != api.STORAGE_CLOUD_HSSD -} diff --git a/pkg/multicloud/qcloud/storagecache.go b/pkg/multicloud/qcloud/storagecache.go deleted file mode 100644 index 2578da59e3..0000000000 --- a/pkg/multicloud/qcloud/storagecache.go +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "context" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "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" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.QcloudTags - region *SRegion -} - -func (self *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) -} - -func (self *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) -} - -func (self *SStoragecache) GetStatus() string { - return "available" -} - -func (self *SStoragecache) Refresh() error { - return nil -} - -func (self *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetGlobalId()) -} - -func (self *SStoragecache) IsEmulated() bool { - return false -} - -func (self *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - // if imageId, err := self.region.createIImage(snapshoutId, 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 - // if err := cloudprovider.WaitStatus(iimage[0], compute.IMAGE_STATUS_ACTIVE, 15*time.Second, 3600*time.Second); err != nil { - // return nil, err - // } - // return iimage[0], nil - // } - return nil, nil -} - -func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - //return self.downloadImage(userCred, imageId, extId, path) - return nil, nil -} - -func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - images := make([]SImage, 0) - for { - parts, total, err := self.region.GetImages("", "PRIVATE_IMAGE", nil, "", len(images), 50) - if err != nil { - return nil, errors.Wrapf(err, "GetImages") - } - images = append(images, parts...) - if len(images) >= total { - break - } - } - ret := []cloudprovider.ICloudImage{} - for i := 0; i < len(images); i += 1 { - images[i].storageCache = self - ret = append(ret, &images[i]) - } - return ret, nil -} - -func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - parts, _, err := self.region.GetImages("", "", []string{extId}, "", 0, 1) - if err != nil { - return nil, err - } - if len(parts) == 0 { - return nil, cloudprovider.ErrNotFound - } - parts[0].storageCache = self - return &parts[0], nil -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return self.uploadImage(ctx, userCred, image, callback) -} - -func (self *SRegion) getCosUrl(bucket, object string) string { - //signature := cosauth.NewSignature(self.client.AppID, bucket, self.client.secretId, time.Now().Add(time.Minute*30).String(), time.Now().String(), "yunion", object).SignOnce(self.client.secretKey) - return fmt.Sprintf("http://%s-%s.cos.%s.myqcloud.com/%s", bucket, self.client.appId, self.Region, object) -} - -func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - // first upload image to oss - s := auth.GetAdminSession(ctx, options.Options.Region) - - _, reader, sizeBytes, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) - if err != nil { - return "", err - } - - bucketName := strings.Replace(strings.ToLower(self.region.GetId()+image.ImageId), "-", "", -1) - if len(bucketName) > 40 { - bucketName = bucketName[:40] - } - exists, _ := self.region.IBucketExist(bucketName) - if !exists { - log.Debugf("Bucket %s not exists, to create ...", bucketName) - err := self.region.CreateIBucket(bucketName, "", "public-read") - if err != nil { - log.Errorf("Create bucket error %s", err) - return "", err - } - } else { - log.Debugf("Bucket %s exists", bucketName) - } - defer self.region.DeleteIBucket(bucketName) - log.Debugf("To upload image to bucket %s ...", bucketName) - bucket, err := self.region.GetIBucketById(bucketName) - if err != nil { - return "", errors.Wrap(err, "GetIBucketByName") - } - body := multicloud.NewProgress(sizeBytes, 80, reader, callback) - err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeBytes, "", "", nil, false) - // err = bucket.PutObject(context.Background(), image.ImageId, reader, sizeBytes, "", "", "") - if err != nil { - log.Errorf("UploadObject error %s %s", image.ImageId, err) - return "", errors.Wrap(err, "bucket.PutObject") - } - - defer bucket.DeleteObject(context.Background(), image.ImageId) - - // 腾讯云镜像名称需要小于20个字符 - imageBaseName := image.ImageId[:10] - if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { - imageBaseName = fmt.Sprintf("img%s", image.ImageId[:10]) - } - imageName := imageBaseName - nameIdx := 1 - - // check image name, avoid name conflict - for { - _, err = self.region.GetImageByName(imageName) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - break - } else { - return "", err - } - } - imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) - nameIdx++ - } - - log.Debugf("Import image %s", imageName) - img, err := self.region.ImportImage(imageName, image.OsArch, image.OsDistribution, image.OsVersion, self.region.getCosUrl(bucketName, image.ImageId)) - if err != nil { - return "", err - } - err = cloudprovider.WaitStatus(img, api.CACHED_IMAGE_STATUS_ACTIVE, 15*time.Second, 3600*time.Second) - if err != nil { - return "", err - } - if callback != nil { - callback(100) - } - return img.ImageId, nil -} diff --git a/pkg/multicloud/qcloud/vpc.go b/pkg/multicloud/qcloud/vpc.go deleted file mode 100644 index ff136b4d34..0000000000 --- a/pkg/multicloud/qcloud/vpc.go +++ /dev/null @@ -1,428 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - multicloud.QcloudTags - - region *SRegion - - iwires []cloudprovider.ICloudWire - - secgroups []cloudprovider.ICloudSecurityGroup - - CidrBlock string - CreatedTime time.Time - DhcpOptionsId string - DnsServerSet []string - DomainName string - EnableMulticast bool - IsDefault bool - VpcId string - VpcName string -} - -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) IsEmulated() bool { - return false -} - -func (self *SVpc) GetIsDefault() bool { - return self.IsDefault -} - -func (self *SVpc) GetCidrBlock() string { - return self.CidrBlock -} - -func (self *SVpc) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} - -func (self *SVpc) Delete() error { - return self.region.DeleteVpc(self.VpcId) -} - -func (self *SVpc) SetTags(tags map[string]string, replace bool) error { - return self.region.SetResourceTags("vpc", "vpc", []string{self.VpcId}, tags, replace) -} - -func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - secgroups := make([]SSecurityGroup, 0) - for { - parts, total, err := self.region.GetSecurityGroups([]string{}, self.VpcId, "", len(secgroups), 50) - if err != nil { - return nil, err - } - secgroups = append(secgroups, parts...) - if len(secgroups) >= total { - break - } - } - isecgroups := make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) - for i := 0; i < len(secgroups); i++ { - secgroups[i].region = self.region - isecgroups[i] = &secgroups[i] - } - return isecgroups, nil -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - rts := []cloudprovider.ICloudRouteTable{} - routetables, err := self.region.GetAllRouteTables(self.GetId(), []string{}) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetAllRouteTables(%s, []string{})", self.GetId()) - } - for i := range routetables { - routetables[i].vpc = self - rts = append(rts, &routetables[i]) - } - return rts, nil -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - routetables, err := self.region.GetAllRouteTables(self.GetId(), []string{routeTableId}) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetAllRouteTables(%s, []string{})", self.GetId()) - } - if len(routetables) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(routetables) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - routetables[0].vpc = self - return &routetables[0], nil -} - -func (self *SVpc) getWireByZoneId(zoneId string) *SWire { - for i := 0; i <= len(self.iwires); i++ { - wire := self.iwires[i].(*SWire) - if wire.zone.Zone == zoneId { - return wire - } - } - return nil -} - -func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { - nats := []SNatGateway{} - for { - part, total, err := self.region.GetNatGateways(self.VpcId, len(nats), 50) - if err != nil { - return nil, err - } - nats = append(nats, part...) - if len(nats) >= total { - break - } - } - inats := []cloudprovider.ICloudNatGateway{} - for i := 0; i < len(nats); i++ { - nats[i].vpc = self - inats = append(inats, &nats[i]) - } - return inats, nil -} - -func (self *SVpc) fetchNetworks() error { - networks, total, err := self.region.GetNetworks(nil, self.VpcId, 0, 50) - if err != nil { - return err - } - if total > len(networks) { - networks, _, err = self.region.GetNetworks(nil, self.VpcId, 0, total) - if err != nil { - return err - } - } - for i := 0; i < len(networks); i += 1 { - wire := self.getWireByZoneId(networks[i].Zone) - networks[i].wire = wire - wire.addNetwork(&networks[i]) - } - return nil -} - -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) GetIWires() ([]cloudprovider.ICloudWire, error) { - if self.iwires == nil { - err := self.fetchNetworks() - if err != nil { - return nil, err - } - } - return self.iwires, nil -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -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) addWire(wire *SWire) { - if self.iwires == nil { - self.iwires = make([]cloudprovider.ICloudWire, 0) - } - self.iwires = append(self.iwires, wire) -} - -func (self *SVpc) GetSVpcPeeringConnections() ([]SVpcPC, error) { - svpcPCs, err := self.region.GetAllVpcPeeringConnections(self.GetId()) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetAllVpcPeeringConnections(%s)", self.GetId()) - } - ret := []SVpcPC{} - for i := range svpcPCs { - if svpcPCs[i].UnVpcID == self.VpcId { - svpcPCs[i].vpc = self - ret = append(ret, svpcPCs[i]) - } - } - return ret, nil -} - -func (self *SVpc) GetAccepterSVpcPeeringConnections() ([]SVpcPC, error) { - result := []SVpcPC{} - svpcPCs, err := self.region.GetAllVpcPeeringConnections("") - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetAllVpcPeeringConnections(%s)", self.GetId()) - } - - for i := range svpcPCs { - if svpcPCs[i].PeerVpcID == self.GetId() { - svpcPCs[i].vpc = self - result = append(result, svpcPCs[i]) - } - - } - return result, nil -} - -func (self *SVpc) GetSVpcPeeringConnectionById(id string) (*SVpcPC, error) { - svpcPC, err := self.region.GetVpcPeeringConnectionbyId(id) - if err != nil { - return nil, errors.Wrapf(err, "self.region.GetVpcPeeringConnectionbyId(%s)", id) - } - svpcPC.vpc = self - return svpcPC, nil -} - -func (self *SVpc) CreateSVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPC, error) { - vpcPCId, err := self.region.CreateVpcPeeringConnection(self.GetId(), opts) - if err != nil { - return nil, errors.Wrapf(err, "self.region.CreateVpcPeeringConnection(%s, %s)", self.GetId(), jsonutils.Marshal(opts).String()) - } - SvpcPC, err := self.GetSVpcPeeringConnectionById(vpcPCId) - if err != nil { - return nil, errors.Wrapf(err, "self.GetSVpcPeeringConnectionById(%s)", vpcPCId) - } - return SvpcPC, nil -} - -func (self *SVpc) CreateCrossRegionSVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPC, error) { - taskId, err := self.region.CreateVpcPeeringConnectionEx(self.GetId(), opts) - if err != nil { - return nil, errors.Wrapf(err, "self.region.CreateVpcPeeringConnectionEx(%s, %s)", self.GetId(), jsonutils.Marshal(opts).String()) - } - err = cloudprovider.Wait(time.Second*5, time.Minute*6, func() (bool, error) { - status, err := self.region.DescribeVpcTaskResult(fmt.Sprintf("%d", taskId)) - if err != nil { - return false, errors.Wrap(err, "self.vpc.region.DescribeVpcTaskResult") - } - //任务的当前状态。0:成功,1:失败,2:进行中。 - if status == 1 { - return false, errors.Wrapf(fmt.Errorf("taskfailed,taskId=%d", taskId), "client.DescribeVpcTaskResult(taskId)") - } - if status == 0 { - return true, nil - } - return false, nil - }) - if err != nil { - return nil, errors.Wrapf(err, "cloudprovider.Wait %d", taskId) - } - svpcPCs, err := self.GetSVpcPeeringConnections() - if err != nil { - return nil, errors.Wrap(err, "self.GetSVpcPeeringConnections()") - } - for i := range svpcPCs { - if svpcPCs[i].GetPeerVpcId() == opts.PeerVpcId { - return &svpcPCs[i], nil - } - } - return nil, errors.Wrap(cloudprovider.ErrNotFound, "vpcPeeringConnection not found after createEx") -} - -func (self *SVpc) AcceptSVpcPeeringConnection(id string) error { - err := self.region.AcceptVpcPeeringConnection(id) - if err != nil { - return errors.Wrapf(err, "self.region.AcceptVpcPeeringConnection(%s)", id) - } - return nil -} - -func (self *SVpc) AcceptCrossRegionSVpcPeeringConnection(id string) error { - taskId, err := self.region.AcceptVpcPeeringConnectionEx(id) - if err != nil { - return errors.Wrapf(err, "self.region.AcceptVpcPeeringConnectionEx(%s)", id) - } - err = cloudprovider.Wait(time.Second*5, time.Minute*6, func() (bool, error) { - status, err := self.region.DescribeVpcTaskResult(fmt.Sprintf("%d", taskId)) - if err != nil { - return false, errors.Wrap(err, "self.vpc.region.DescribeVpcTaskResult") - } - //任务的当前状态。0:成功,1:失败,2:进行中。 - if status == 1 { - return false, errors.Wrap(fmt.Errorf("taskfailed,taskId=%d", taskId), "client.DescribeVpcTaskResult(taskId)") - } - if status == 0 { - return true, nil - } - return false, nil - }) - if err != nil { - return errors.Wrapf(err, " cloudprovider.Wait %d", taskId) - } - svpcPC, err := self.GetSVpcPeeringConnectionById(id) - if err != nil { - return errors.Wrapf(err, "self.GetSVpcPeeringConnectionById(%s)", id) - } - if svpcPC.GetStatus() != api.VPC_PEERING_CONNECTION_STATUS_ACTIVE { - return errors.Wrap(cloudprovider.ErrInvalidStatus, "invalid status after AcceptCrossRegionSVpcPeeringConnection") - } - return nil -} - -func (self *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - result := []cloudprovider.ICloudVpcPeeringConnection{} - SVpcPCs, err := self.GetSVpcPeeringConnections() - if err != nil { - return nil, errors.Wrap(err, "self.GetSVpcPeeringConnections()") - } - for i := range SVpcPCs { - result = append(result, &SVpcPCs[i]) - } - return result, nil -} - -func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - result := []cloudprovider.ICloudVpcPeeringConnection{} - SVpcPCs, err := self.GetAccepterSVpcPeeringConnections() - if err != nil { - return nil, errors.Wrap(err, "self.GetSVpcPeeringConnections()") - } - for i := range SVpcPCs { - result = append(result, &SVpcPCs[i]) - } - return result, nil -} - -func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { - svpcPC, err := self.GetSVpcPeeringConnectionById(id) - if err != nil { - return nil, errors.Wrapf(err, "self.GetSVpcPeeringConnectionById(%s)", id) - } - return svpcPC, nil -} - -func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { - if self.GetRegion().GetId() == opts.PeerRegionId { - return self.CreateSVpcPeeringConnection(opts) - } else { - return self.CreateCrossRegionSVpcPeeringConnection(opts) - } -} - -func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { - svpcPC, err := self.GetSVpcPeeringConnectionById(id) - if err != nil { - return errors.Wrapf(err, "self.GetSVpcPeeringConnectionById(%s)", id) - } - if svpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_ACTIVE { - return nil - } - - if !svpcPC.IsCrossRegion() { - return self.AcceptSVpcPeeringConnection(id) - } else { - return self.AcceptCrossRegionSVpcPeeringConnection(id) - } -} - -func (self *SVpc) GetAuthorityOwnerId() string { - return self.region.client.ownerName -} - -func (self *SVpc) ProposeJoinICloudInterVpcNetwork(opts *cloudprovider.SVpcJointInterVpcNetworkOption) error { - instance := SCcnAttachInstanceInput{ - InstanceType: "VPC", - InstanceId: self.GetId(), - InstanceRegion: self.region.GetId(), - } - err := self.region.AttachCcnInstances(opts.InterVpcNetworkId, opts.NetworkAuthorityOwnerId, []SCcnAttachInstanceInput{instance}) - if err != nil { - return errors.Wrapf(err, "self.region.AttachCcnInstance(%s,%s,%s)", jsonutils.Marshal(opts).String(), self.GetId(), self.region.GetId()) - } - return nil -} diff --git a/pkg/multicloud/qcloud/vpc_peering_connection.go b/pkg/multicloud/qcloud/vpc_peering_connection.go deleted file mode 100644 index ee6bc8799f..0000000000 --- a/pkg/multicloud/qcloud/vpc_peering_connection.go +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpcPC struct { - multicloud.SResourceBase - multicloud.QcloudTags - vpc *SVpc - VpcID string `json:"vpcId"` - UnVpcID string `json:"unVpcId"` - PeerVpcID string `json:"peerVpcId"` - UnPeerVpcID string `json:"unPeerVpcId"` - AppID string `json:"appId"` - PeeringConnectionID string `json:"peeringConnectionId"` - PeeringConnectionName string `json:"peeringConnectionName"` - State int `json:"state"` - CreateTime string `json:"createTime"` - Uin string `json:"uin"` - PeerUin string `json:"peerUin"` - Region string `json:"region"` - PeerRegion string `json:"peerRegion"` -} - -func (region *SRegion) DescribeVpcPeeringConnections(vpcId string, peeringConnectionId string, offset int, limit int) ([]SVpcPC, int, error) { - if limit > 50 || limit <= 0 { - limit = 50 - } - params := make(map[string]string) - params["offset"] = fmt.Sprintf("%d", offset) - params["limit"] = fmt.Sprintf("%d", limit) - if len(vpcId) > 0 { - params["vpcId"] = vpcId - } - if len(peeringConnectionId) > 0 { - params["peeringConnectionId"] = peeringConnectionId - } - body, err := region.vpc2017Request("DescribeVpcPeeringConnections", params) - if err != nil { - return nil, 0, errors.Wrapf(err, `region.vpcRequest("DescribeVpcPeeringConnections", %s)`, jsonutils.Marshal(params).String()) - } - - total, _ := body.Float("totalCount") - if total <= 0 { - return nil, int(total), nil - } - - vpcPCs := make([]SVpcPC, 0) - err = body.Unmarshal(&vpcPCs, "data") - if err != nil { - return nil, 0, errors.Wrapf(err, "body.Unmarshal(&vpcPCs,%s)", body.String()) - } - return vpcPCs, int(total), nil -} - -func (region *SRegion) GetAllVpcPeeringConnections(vpcId string) ([]SVpcPC, error) { - result := []SVpcPC{} - for { - vpcPCS, total, err := region.DescribeVpcPeeringConnections(vpcId, "", len(result), 50) - if err != nil { - return nil, errors.Wrapf(err, `client.DescribeVpcPeeringConnections(%s,"",%d,50)`, vpcId, len(result)) - } - result = append(result, vpcPCS...) - if total <= len(result) { - break - } - } - return result, nil -} - -func (region *SRegion) GetVpcPeeringConnectionbyId(vpcPCId string) (*SVpcPC, error) { - vpcPCs, _, err := region.DescribeVpcPeeringConnections("", vpcPCId, 0, 50) - if err != nil { - return nil, errors.Wrapf(err, `client.DescribeVpcPeeringConnections("", %s, 0, 50)`, vpcPCId) - } - if len(vpcPCs) < 1 { - return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetVpcPeeringConnectionbyId(%s)", vpcPCId) - } - if len(vpcPCs) > 1 { - return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "GetVpcPeeringConnectionbyId(%s)", vpcPCId) - } - return &vpcPCs[0], nil -} - -func (region *SRegion) CreateVpcPeeringConnection(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (string, error) { - params := make(map[string]string) - params["vpcId"] = vpcId - params["peerVpcId"] = opts.PeerVpcId - params["peerUin"] = opts.PeerAccountId - params["peeringConnectionName"] = opts.Name - body, err := region.vpc2017Request("CreateVpcPeeringConnection", params) - if err != nil { - return "", errors.Wrapf(err, `client.vpc2017Request("CreateVpcPeeringConnection", %s)`, jsonutils.Marshal(params).String()) - } - peeringId, err := body.GetString("peeringConnectionId") - if err != nil { - return "", errors.Wrapf(err, `%s body.GetString("peeringConnectionId")`, body.String()) - } - return peeringId, nil -} - -func (region *SRegion) AcceptVpcPeeringConnection(peeringId string) error { - params := make(map[string]string) - params["peeringConnectionId"] = peeringId - _, err := region.vpc2017Request("AcceptVpcPeeringConnection", params) - if err != nil { - return errors.Wrapf(err, `client.vpc2017Request("AcceptVpcPeeringConnection",%s)`, jsonutils.Marshal(params).String()) - } - return nil -} - -func (region *SRegion) DeleteVpcPeeringConnection(peeringId string) error { - params := make(map[string]string) - params["peeringConnectionId"] = peeringId - _, err := region.vpc2017Request("DeleteVpcPeeringConnection", params) - if err != nil { - return errors.Wrapf(err, `client.vpc2017Request("DeleteVpcPeeringConnection",%s)`, jsonutils.Marshal(params).String()) - } - return nil -} - -func (region *SRegion) CreateVpcPeeringConnectionEx(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (int64, error) { - params := make(map[string]string) - params["vpcId"] = vpcId - params["peerVpcId"] = opts.PeerVpcId - params["peerUin"] = opts.PeerAccountId - params["peeringConnectionName"] = opts.Name - params["peerRegion"] = opts.PeerRegionId - params["bandwidth"] = fmt.Sprintf("%d", opts.Bandwidth) - body, err := region.vpc2017Request("CreateVpcPeeringConnectionEx", params) - if err != nil { - return 0, errors.Wrapf(err, `client.vpc2017Request("CreateVpcPeeringConnectionEx", %s)`, jsonutils.Marshal(params).String()) - } - taskId, err := body.Int("taskId") - if err != nil { - return 0, errors.Wrapf(err, `%s body.Int("taskId")`, body.String()) - } - return taskId, nil -} - -func (region *SRegion) DescribeVpcTaskResult(taskId string) (int, error) { - params := make(map[string]string) - params["taskId"] = taskId - body, err := region.vpc2017Request("DescribeVpcTaskResult", params) - if err != nil { - return 0, errors.Wrapf(err, `client.vpc2017Request("DescribeVpcTaskResult",%s)`, taskId) - } - status, err := body.Float("data", "status") - if err != nil { - return 0, errors.Wrapf(err, `%s body.Int("data.status")`, body.String()) - } - return int(status), nil -} - -func (region *SRegion) AcceptVpcPeeringConnectionEx(peeringId string) (int64, error) { - params := make(map[string]string) - params["peeringConnectionId"] = peeringId - body, err := region.vpc2017Request("AcceptVpcPeeringConnectionEx", params) - if err != nil { - return 0, errors.Wrapf(err, `client.vpc2017Request("AcceptVpcPeeringConnectionEx", %s)`, jsonutils.Marshal(params).String()) - } - taskId, err := body.Int("taskId") - if err != nil { - return 0, errors.Wrapf(err, `%s body.Int("taskId")`, body.String()) - } - return taskId, nil -} - -func (region *SRegion) DeleteVpcPeeringConnectionEx(peeringId string) (int64, error) { - params := make(map[string]string) - params["peeringConnectionId"] = peeringId - body, err := region.vpc2017Request("DeleteVpcPeeringConnectionEx", params) - if err != nil { - return 0, errors.Wrapf(err, `client.vpc2017Request("DeleteVpcPeeringConnectionEx",%s)`, jsonutils.Marshal(params).String()) - } - taskId, err := body.Int("taskId") - if err != nil { - return 0, errors.Wrapf(err, `%s body.Int("taskId")`, body.String()) - } - return taskId, nil -} - -func (self *SVpcPC) GetId() string { - return self.PeeringConnectionID -} - -func (self *SVpcPC) GetName() string { - return self.PeeringConnectionName -} - -func (self *SVpcPC) GetGlobalId() string { - return self.GetId() -} - -func (self *SVpcPC) GetStatus() string { - switch self.State { - case 1: - return api.VPC_PEERING_CONNECTION_STATUS_ACTIVE - case 0: - return api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT - default: - return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN - } -} - -func (self *SVpcPC) Refresh() error { - svpcPC, err := self.vpc.region.GetVpcPeeringConnectionbyId(self.GetId()) - if err != nil { - return errors.Wrapf(err, "self.vpc.region.GetVpcPeeringConnectionbyId(%s)", self.GetId()) - } - return jsonutils.Update(self, svpcPC) -} - -func (self *SVpcPC) GetPeerVpcId() string { - return self.UnPeerVpcID -} - -func (self *SVpcPC) GetPeerAccountId() string { - if strings.Contains(self.PeerUin, ".") { - return strings.Split(self.PeerUin, ".")[0] - } - return self.PeerUin -} - -func (self *SVpcPC) GetEnabled() bool { - return true -} - -func (self *SVpcPC) Delete() error { - if !self.IsCrossRegion() { - return self.vpc.region.DeleteVpcPeeringConnection(self.GetId()) - } - taskId, err := self.vpc.region.DeleteVpcPeeringConnectionEx(self.GetId()) - if err != nil { - return errors.Wrapf(err, "self.vpc.region.DeleteVpcPeeringConnection(%s)", self.GetId()) - } - //err = self.vpc.region.WaitVpcTask(fmt.Sprintf("%d", taskId), time.Second*5, time.Minute*10) - err = cloudprovider.Wait(time.Second*5, time.Minute*6, func() (bool, error) { - status, err := self.vpc.region.DescribeVpcTaskResult(fmt.Sprintf("%d", taskId)) - if err != nil { - return false, errors.Wrap(err, "self.vpc.region.DescribeVpcTaskResult") - } - //任务的当前状态。0:成功,1:失败,2:进行中。 - if status == 1 { - return false, errors.Wrap(fmt.Errorf("taskfailed,taskId=%d", taskId), "client.DescribeVpcTaskResult(taskId)") - } - if status == 0 { - return true, nil - } - return false, nil - }) - if err != nil { - return errors.Wrapf(err, "self.region.WaitTask(%d)", taskId) - } - return nil -} - -func (self *SVpcPC) IsCrossRegion() bool { - if len(self.Region) == 0 { - return false - } - return self.Region != self.PeerRegion -} diff --git a/pkg/multicloud/qcloud/wire.go b/pkg/multicloud/qcloud/wire.go deleted file mode 100644 index 6df8bfaa84..0000000000 --- a/pkg/multicloud/qcloud/wire.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.QcloudTags - 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) IsEmulated() bool { - return true -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SWire) Refresh() error { - return nil -} - -func (self *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.zone.GetGlobalId()) -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -func (self *SWire) GetBandwidth() int { - return 10000 -} - -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].(*SNetwork) - if network.SubnetId == networkId { - return network - } - } - return nil -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - networkId, err := self.zone.region.CreateNetwork(self.zone.Zone, self.vpc.VpcId, opts.Name, opts.Cidr, opts.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 vswitch after create????") - return nil, cloudprovider.ErrNotFound - } - return network, nil -} - -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) 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].(*SNetwork) - if network.SubnetId == networkId { - return network - } - } - return nil -} - -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) 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.SubnetId { - find = true - break - } - } - if !find { - self.inetworks = append(self.inetworks, network) - } -} diff --git a/pkg/multicloud/qcloud/zone.go b/pkg/multicloud/qcloud/zone.go deleted file mode 100644 index 54652d2eba..0000000000 --- a/pkg/multicloud/qcloud/zone.go +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 qcloud - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type InstanceChargeType string - -const ( - PrePaidInstanceChargeType InstanceChargeType = "PREPAID" - PostPaidInstanceChargeType InstanceChargeType = "POSTPAID_BY_HOUR" - CdhPaidInstanceChargeType InstanceChargeType = "CDHPAID" - DefaultInstanceChargeType = PostPaidInstanceChargeType -) - -type SZone struct { - multicloud.SResourceBase - multicloud.QcloudTags - region *SRegion - - iwires []cloudprovider.ICloudWire - - host *SHost - - istorages []cloudprovider.ICloudStorage - - instanceTypes []string - refreshTime time.Time - localstorages []string - cloudstorages []string - - Zone string - ZoneName string - ZoneState string -} - -func (self *SZone) GetId() string { - return self.Zone -} - -func (self *SZone) GetName() string { - return self.ZoneName -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - en := self.ZoneName - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SZone) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.Zone) -} - -func (self *SZone) IsEmulated() bool { - return false -} - -func (self *SZone) Refresh() error { - // do nothing - return nil -} - -func (self *SZone) GetStatus() string { - if self.ZoneState == "AVAILABLE" { - return api.ZONE_ENABLE - } - return api.ZONE_SOLDOUT -} - -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) GetIHosts() ([]cloudprovider.ICloudHost, error) { - return []cloudprovider.ICloudHost{self.getHost()}, nil -} - -func (self *SZone) getHost() *SHost { - if self.host == nil { - self.host = &SHost{zone: self} - } - return self.host -} - -func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -type SDiskConfigSet struct { - Available bool - DeviceClass string - DiskChargeType string - DiskType string - DiskUsage string - InstanceFamily string - MaxDiskSize int - MinDiskSize int - Zone string -} - -func (self *SRegion) GetDiskConfigSet(zoneName string) ([]SDiskConfigSet, error) { - params := map[string]string{} - params["Region"] = self.Region - params["Zones.0"] = zoneName - params["InquiryType"] = "INQUIRY_CBS_CONFIG" - body, err := self.cbsRequest("DescribeDiskConfigQuota", params) - if err != nil { - return nil, err - } - diskConfigSet := []SDiskConfigSet{} - return diskConfigSet, body.Unmarshal(&diskConfigSet, "DiskConfigSet") -} - -func (self *SZone) fetchStorages() error { - self.istorages = []cloudprovider.ICloudStorage{} - diskConfigSet, err := self.region.GetDiskConfigSet(self.Zone) - if err != nil { - return err - } - self.cloudstorages = []string{} - for _, diskConfig := range diskConfigSet { - if !utils.IsInStringArray(strings.ToUpper(diskConfig.DiskType), self.cloudstorages) { - self.cloudstorages = append(self.cloudstorages, strings.ToUpper(diskConfig.DiskType)) - storage := SStorage{zone: self, storageType: diskConfig.DiskType, available: diskConfig.Available} - self.istorages = append(self.istorages, &storage) - } - } - for _, storageType := range []string{"CLOUD_PREMIUM", "CLOUD_SSD", "CLOUD_BASIC"} { - if !utils.IsInStringArray(storageType, self.cloudstorages) { - self.cloudstorages = append(self.cloudstorages, storageType) - storage := SStorage{zone: self, storageType: storageType, available: false} - self.istorages = append(self.istorages, &storage) - } - } - self.localstorages, err = self.region.GetZoneLocalStorages(self.Zone) - if err != nil { - log.Errorf("falied to fetch local storage for zone %s", self.Zone) - } - for _, localstorageType := range self.localstorages { - storage := SLocalStorage{zone: self, storageType: localstorageType, available: true} - self.istorages = append(self.istorages, &storage) - } - for _, storageType := range QCLOUD_LOCAL_STORAGE_TYPES { - if !utils.IsInStringArray(storageType, self.localstorages) { - storage := SLocalStorage{zone: self, storageType: storageType, available: false} - self.istorages = append(self.istorages, &storage) - } - } - return nil -} - -func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - if self.istorages == nil { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "fetchStorages") - } - } - return self.istorages, nil -} - -func (self *SZone) getLocalStorageByCategory(category string) (*SLocalStorage, error) { - if len(self.localstorages) == 0 { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrap(err, "fetchStorages") - } - } - if utils.IsInStringArray(strings.ToUpper(category), self.localstorages) { - return &SLocalStorage{zone: self, storageType: strings.ToUpper(category)}, nil - } - return nil, fmt.Errorf("No such storage %s", category) -} - -func (self *SZone) validateStorageType(category string) error { - if len(self.localstorages) == 0 || len(self.cloudstorages) == 0 { - err := self.fetchStorages() - if err != nil { - return errors.Wrap(err, "fetchStorages") - } - } - if utils.IsInStringArray(strings.ToUpper(category), self.localstorages) || utils.IsInStringArray(strings.ToUpper(category), self.cloudstorages) { - return nil - } - return fmt.Errorf("No such storage %s", category) -} - -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++ { - if utils.IsInStringArray(storages[i].GetStorageType(), self.localstorages) { - continue - //return &SStorage{zone: self, storageType: strings.ToUpper(storages[i].GetStorageType())}, nil - } - storage := storages[i].(*SStorage) - if strings.ToLower(storage.storageType) == strings.ToLower(category) { - return storage, nil - } - } - return nil, fmt.Errorf("No such storage %s", category) -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - if self.istorages == nil { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "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) addWire(wire *SWire) { - if self.iwires == nil { - self.iwires = make([]cloudprovider.ICloudWire, 0) - } - self.iwires = append(self.iwires, wire) -} - -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) fetchInstanceTypes() { - self.instanceTypes = []string{} - params := map[string]string{} - params["Region"] = self.region.Region - params["Filters.0.Name"] = "zone" - params["Filters.0.Values.0"] = self.Zone - if body, err := self.region.cvmRequest("DescribeInstanceTypeConfigs", params, true); err != nil { - log.Errorf("DescribeInstanceTypeConfigs error: %v", err) - } else if configSet, err := body.GetArray("InstanceTypeConfigSet"); err != nil { - log.Errorf("Get InstanceTypeConfigSet error: %v", err) - } else { - for _, config := range configSet { - if instanceType, err := config.GetString("InstanceType"); err == nil && !utils.IsInStringArray(instanceType, self.instanceTypes) { - self.instanceTypes = append(self.instanceTypes, instanceType) - } - } - self.refreshTime = time.Now() - } -} - -func (self *SZone) getAvaliableInstanceTypes() []string { - if self.instanceTypes == nil || len(self.instanceTypes) == 0 || time.Now().Sub(self.refreshTime).Hours() > refreshHours() { - self.fetchInstanceTypes() - } - return self.instanceTypes -} - -func refreshHours() float64 { - return 5 -} - -func (self *SZone) getCosEndpoint() string { - return fmt.Sprintf("cos.%s.myqcloud.com", self.GetId()) -} - -func (self *SZone) getCosWebsiteEndpoint() string { - return fmt.Sprintf("cos-website.%s.myqcloud.com", self.GetId()) -} diff --git a/pkg/multicloud/remotefile/bucket.go b/pkg/multicloud/remotefile/bucket.go deleted file mode 100644 index 94f769771b..0000000000 --- a/pkg/multicloud/remotefile/bucket.go +++ /dev/null @@ -1,185 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - "context" - "io" - "net/http" - "time" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SBucket struct { - SResourceBase - - region *SRegion - - RegionId string - MaxPart int - MaxPartBytes int64 - Acl string - Location string - StorageClass string - AccessUrls []cloudprovider.SBucketAccessUrl - - Stats cloudprovider.SBucketStats - Limit cloudprovider.SBucketStats -} - -func (self *SBucket) MaxPartCount() int { - return self.MaxPart -} - -func (self *SBucket) MaxPartSizeBytes() int64 { - return self.MaxPartBytes -} - -func (self *SBucket) GetAcl() cloudprovider.TBucketACLType { - return cloudprovider.TBucketACLType(self.Acl) -} - -func (self *SBucket) GetLocation() string { - return self.Location -} - -func (self *SBucket) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SBucket) GetStorageClass() string { - return self.StorageClass -} - -func (self *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { - return self.AccessUrls -} - -func (self *SBucket) GetStats() cloudprovider.SBucketStats { - return self.Stats -} - -func (self *SBucket) GetLimit() cloudprovider.SBucketStats { - return self.Limit -} - -func (self *SBucket) SetLimit(limit cloudprovider.SBucketStats) error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) LimitSupport() cloudprovider.SBucketStats { - return self.Limit -} - -func (self *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { - return cloudprovider.SListObjectResult{}, cloudprovider.ErrNotSupported -} - -func (self *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SBucket) DeleteObject(ctx context.Context, keys string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SBucket) PutObject(ctx context.Context, key string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucketName string, srcKey string, srcOffset int64, srcLength int64) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) SetWebsite(conf cloudprovider.SBucketWebsiteConf) error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { - return cloudprovider.SBucketWebsiteConf{}, cloudprovider.ErrNotSupported -} - -func (self *SBucket) DeleteWebSiteConf() error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SBucket) DeleteCORS() error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) SetReferer(conf cloudprovider.SBucketRefererConf) error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) GetReferer() (cloudprovider.SBucketRefererConf, error) { - return cloudprovider.SBucketRefererConf{}, cloudprovider.ErrNotSupported -} - -func (self *SBucket) GetCdnDomains() ([]cloudprovider.SCdnDomain, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SBucket) GetPolicy() ([]cloudprovider.SBucketPolicyStatement, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SBucket) SetPolicy(policy cloudprovider.SBucketPolicyStatementInput) error { - return cloudprovider.ErrNotSupported -} - -func (self *SBucket) DeletePolicy(id []string) ([]cloudprovider.SBucketPolicyStatement, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { - return nil, cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/remotefile/dbinstance.go b/pkg/multicloud/remotefile/dbinstance.go deleted file mode 100644 index 6fdcf7dc81..0000000000 --- a/pkg/multicloud/remotefile/dbinstance.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - "context" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SDBInstance struct { - SResourceBase - - region *SRegion - RegionId string - SecurityGroupIds []string - Port int - Engine string - EngineVersion string - InstanceType string - VcpuCount int - VmemSizeMb int - DiskSizeGb int - DiskSizeUsedGb int - Category string - StorageType string - MaintainTime string - ConnectionStr string - InternalConnectionStr string - Zone1Id string - Zone2Id string - Zone3Id string - VpcId string - Iops int -} - -func (self *SDBInstance) Reboot() error { - return cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) GetMasterInstanceId() string { - return "" -} - -func (self *SDBInstance) GetSecurityGroupIds() ([]string, error) { - return self.SecurityGroupIds, nil -} - -func (self *SDBInstance) SetSecurityGroups(ids []string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) GetPort() int { - return self.Port -} - -func (self *SDBInstance) GetEngine() string { - return self.Engine -} - -func (self *SDBInstance) GetEngineVersion() string { - return self.EngineVersion -} - -func (self *SDBInstance) GetInstanceType() string { - return self.InstanceType -} - -func (self *SDBInstance) GetVcpuCount() int { - return self.VcpuCount -} - -func (self *SDBInstance) GetVmemSizeMB() int { - return self.VmemSizeMb -} - -func (self *SDBInstance) GetDiskSizeGB() int { - return self.DiskSizeGb -} - -func (self *SDBInstance) GetDiskSizeUsedMB() int { - return self.DiskSizeUsedGb -} - -func (self *SDBInstance) GetCategory() string { - return self.Category -} - -func (self *SDBInstance) GetStorageType() string { - return self.StorageType -} - -func (self *SDBInstance) GetMaintainTime() string { - return self.MaintainTime -} - -func (self *SDBInstance) GetConnectionStr() string { - return self.ConnectionStr -} - -func (self *SDBInstance) GetInternalConnectionStr() string { - return self.InternalConnectionStr -} - -func (self *SDBInstance) GetZone1Id() string { - return self.Zone1Id -} - -func (self *SDBInstance) GetZone2Id() string { - return self.Zone2Id -} - -func (self *SDBInstance) GetZone3Id() string { - return self.Zone3Id -} - -func (self *SDBInstance) GetIVpcId() string { - return self.VpcId -} - -func (self *SDBInstance) GetIops() int { - return self.Iops -} - -func (self *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedDBInstanceChangeConfig) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) OpenPublicConnection() error { - return cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) ClosePublicConnection() error { - return cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDBInstance) Delete() error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { - res, err := self.client.GetDBInstances() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudDBInstance{} - for i := range res { - if res[i].RegionId != self.GetId() { - continue - } - res[i].region = self - ret = append(ret, &res[i]) - } - return ret, nil -} - -func (self *SRegion) GetIDBInstanceById(id string) (cloudprovider.ICloudDBInstance, error) { - res, err := self.GetIDBInstances() - if err != nil { - return nil, err - } - for i := range res { - if res[i].GetGlobalId() == id { - return res[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/remotefile/disk.go b/pkg/multicloud/remotefile/disk.go deleted file mode 100644 index af42af3126..0000000000 --- a/pkg/multicloud/remotefile/disk.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - "context" - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SDisk struct { - SResourceBase - - storage *SStorage - ZoneId string - StorageId string - DiskFormat string - DiskSizeMb int - IsAutoDelete bool - DiskType string - FsFormat string - Iops int - Driver string - CacheMode string - Mountpoint string - AccessPath string -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - if self.storage == nil { - return nil, fmt.Errorf("disk %s(%s) missing storage", self.Name, self.Id) - } - return self.storage, nil -} - -func (self *SDisk) GetIStorageId() string { - return self.StorageId -} - -func (self *SDisk) GetDiskFormat() string { - return self.DiskFormat -} - -func (self *SDisk) GetDiskSizeMB() int { - return self.DiskSizeMb -} - -func (self *SDisk) GetIsAutoDelete() bool { - return self.IsAutoDelete -} - -func (self *SDisk) GetTemplateId() string { - return "" -} - -func (self *SDisk) GetDiskType() string { - if len(self.DiskType) == 0 { - return api.DISK_TYPE_DATA - } - return self.DiskType -} - -func (self *SDisk) GetFsFormat() string { - return self.FsFormat -} - -func (self *SDisk) GetIsNonPersistent() bool { - return false -} - -func (self *SDisk) GetIops() int { - return self.Iops -} - -func (self *SDisk) GetDriver() string { - return self.Driver -} - -func (self *SDisk) GetCacheMode() string { - return self.CacheMode -} - -func (self *SDisk) GetMountpoint() string { - return self.Mountpoint -} - -func (self *SDisk) GetAccessPath() string { - return self.AccessPath -} - -func (self *SDisk) Delete(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { - return cloudprovider.ErrNotSupported -} - -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/remotefile/doc.go b/pkg/multicloud/remotefile/doc.go deleted file mode 100644 index ed6889b700..0000000000 --- a/pkg/multicloud/remotefile/doc.go +++ /dev/null @@ -1 +0,0 @@ -package remotefile // import "yunion.io/x/onecloud/pkg/multicloud/remotefile" diff --git a/pkg/multicloud/remotefile/eip.go b/pkg/multicloud/remotefile/eip.go deleted file mode 100644 index c07e739830..0000000000 --- a/pkg/multicloud/remotefile/eip.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SEip struct { - SResourceBase - - IpAddr string - RegionId string - AssociateId string - Bandwidth int -} - -func (self *SEip) GetIpAddr() string { - return self.IpAddr -} - -func (self *SEip) GetMode() string { - return api.EIP_MODE_STANDALONE_EIP -} - -func (self *SEip) GetINetworkId() string { - return "" -} - -func (self *SEip) GetAssociationType() string { - return api.EIP_ASSOCIATE_TYPE_SERVER -} - -func (self *SEip) GetAssociationExternalId() string { - return self.AssociateId -} - -func (self *SEip) GetBandwidth() int { - return self.Bandwidth -} - -func (self *SEip) GetInternetChargeType() string { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC -} - -func (self *SEip) Delete() error { - return cloudprovider.ErrNotSupported -} - -func (self *SEip) Associate(conf *cloudprovider.AssociateConfig) error { - return cloudprovider.ErrNotSupported -} - -func (self *SEip) Dissociate() error { - return cloudprovider.ErrNotSupported -} - -func (self *SEip) ChangeBandwidth(bw int) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/remotefile/host.go b/pkg/multicloud/remotefile/host.go deleted file mode 100644 index 37110d8185..0000000000 --- a/pkg/multicloud/remotefile/host.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SHost struct { - SResourceBase - multicloud.SHostBase - zone *SZone - - AccessIp string - AccessMac string - ZoneId string - Enabled bool - HostStatus string - SN string - CpuCount int - NodeCount int8 - CpuDesc string - CpuMbz int - MemSizeMb int - StorageSizeMb int - StorageType string - - AttachStorageTypes []string -} - -func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SHost) GetEnabled() bool { - return self.Enabled -} - -func (self *SHost) GetHostStatus() string { - if len(self.HostStatus) == 0 { - return api.HOST_ONLINE - } - return self.HostStatus -} - -func (self *SHost) GetAccessIp() string { - return self.AccessIp -} - -func (self *SHost) GetAccessMac() string { - return self.AccessMac -} - -func (self *SHost) GetSysInfo() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (self *SHost) GetSN() string { - return self.SN -} - -func (self *SHost) GetCpuCount() int { - return self.CpuCount -} - -func (self *SHost) GetNodeCount() int8 { - return self.NodeCount -} - -func (self *SHost) GetCpuDesc() string { - return self.CpuDesc -} - -func (self *SHost) GetCpuMhz() int { - return self.CpuMbz -} - -func (self *SHost) GetCpuCmtbound() float32 { - return 1 -} - -func (self *SHost) GetMemSizeMB() int { - return self.MemSizeMb -} - -func (self *SHost) GetMemCmtbound() float32 { - return 1 -} - -func (self *SHost) GetReservedMemoryMb() int { - return 0 -} - -func (self *SHost) GetStorageSizeMB() int { - return self.StorageSizeMb -} - -func (self *SHost) GetStorageType() string { - return self.StorageType -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_REMOTEFILE -} - -func (self *SHost) GetIsMaintenance() bool { - return false -} - -func (self *SHost) GetVersion() string { - return "" -} - -func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := self.zone.GetIStorages() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStorage{} - for i := range storages { - if utils.IsInStringArray(storages[i].GetStorageType(), self.AttachStorageTypes) { - ret = append(ret, storages[i]) - } - } - return ret, nil -} - -func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storages, err := self.GetIStorages() - if err != nil { - return nil, err - } - for i := range storages { - if storages[i].GetGlobalId() == id { - return storages[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms, err := self.zone.region.client.GetInstances() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudVM{} - for i := range vms { - if vms[i].HostId != self.GetId() { - continue - } - vms[i].host = self - ret = append(ret, &vms[i]) - } - return ret, nil -} - -func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vms, err := self.GetIVMs() - if err != nil { - return nil, err - } - for i := range vms { - if vms[i].GetGlobalId() == id { - return vms[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - return nil, cloudprovider.ErrNotImplemented -} diff --git a/pkg/multicloud/remotefile/instance.go b/pkg/multicloud/remotefile/instance.go deleted file mode 100644 index 47bc2ab660..0000000000 --- a/pkg/multicloud/remotefile/instance.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - "context" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type SInstance struct { - SResourceBase - - host *SHost - - osInfo *imagetools.ImageInfo - - HostId string - Hostname string - SecurityGroupIds []string - VcpuCount int - VmemSizeMb int - BootOrder string - Vga string - Vdi string - OsArch string - OsType string - OsName string - Bios string - Machine string - InstanceType string - Bandwidth int - Throughput int - EipId string - Disks []SDisk - - Nics []SInstanceNic -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - return self.SecurityGroupIds, nil -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) StartVM(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetIHostId() string { - return self.HostId -} - -func (self *SInstance) GetInternetMaxBandwidthOut() int { - return self.Bandwidth -} - -func (self *SInstance) GetThroughput() int { - return self.Throughput -} - -func (self *SInstance) GetSerialOutput(port int) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SInstance) ConvertPublicIpToEip() error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SInstance) MigrateVM(hostid string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) LiveMigrateVM(hostid string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetError() error { - return nil -} - -func (self *SInstance) CreateInstanceSnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudInstanceSnapshot, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetInstanceSnapshot(idStr string) (cloudprovider.ICloudInstanceSnapshot, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetInstanceSnapshots() ([]cloudprovider.ICloudInstanceSnapshot, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SInstance) ResetToInstanceSnapshot(ctx context.Context, idStr string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SInstance) AllocatePublicIpAddress() (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (self *SInstance) GetVcpuCount() int { - return self.VcpuCount -} - -func (self *SInstance) GetVmemSizeMB() int { - return self.VmemSizeMb -} - -func (self *SInstance) GetBootOrder() string { - return self.BootOrder -} - -func (self *SInstance) GetVga() string { - return self.Vga -} - -func (self *SInstance) GetVdi() string { - return self.Vdi -} - -func (ins *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { - if ins.osInfo == nil { - osInfo := imagetools.NormalizeImageInfo(ins.OsName, ins.OsArch, ins.OsType, "", "") - ins.osInfo = &osInfo - } - return ins.osInfo -} - -func (ins *SInstance) GetOsArch() string { - return ins.getNormalizedOsInfo().OsArch -} - -func (ins *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(ins.getNormalizedOsInfo().OsType) -} - -func (ins *SInstance) GetFullOsName() string { - return ins.OsName -} - -func (ins *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(ins.Bios) -} - -func (ins *SInstance) GetOsLang() string { - return ins.getNormalizedOsInfo().OsLang -} - -func (ins *SInstance) GetOsDist() string { - return ins.getNormalizedOsInfo().OsDistro -} - -func (ins *SInstance) GetOsVersion() string { - return ins.getNormalizedOsInfo().OsVersion -} - -func (self *SInstance) GetMachine() string { - return self.Machine -} - -func (self *SInstance) GetInstanceType() string { - return self.InstanceType -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_REMOTEFILE -} - -func (self *SInstance) GetHostname() string { - return self.Hostname -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - ret := []cloudprovider.ICloudDisk{} - for i := range self.Disks { - ret = append(ret, &self.Disks[i]) - } - return ret, nil -} - -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - return self.host.zone.region.GetIEipById(self.EipId) -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - ret := []cloudprovider.ICloudNic{} - for i := range self.Nics { - ret = append(ret, &self.Nics[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/remotefile/instancenic.go b/pkg/multicloud/remotefile/instancenic.go deleted file mode 100644 index 512e983ef2..0000000000 --- a/pkg/multicloud/remotefile/instancenic.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import "yunion.io/x/onecloud/pkg/cloudprovider" - -type SInstanceNic struct { - SResourceBase - - Ip string - Mac string - Classic bool - Driver string - NetworkId string - SubAddr []string -} - -func (self *SInstanceNic) GetIP() string { - return self.Ip -} - -func (self *SInstanceNic) GetMAC() string { - return self.Mac -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return self.Classic -} - -func (self *SInstanceNic) GetDriver() string { - return self.Driver -} - -func (self *SInstanceNic) GetINetworkId() string { - return self.NetworkId -} - -func (self *SInstanceNic) GetSubAddress() ([]string, error) { - return self.SubAddr, nil -} - -func (self *SInstanceNic) AssignNAddress(count int) ([]string, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SInstanceNic) UnassignAddress(ipAddrs []string) error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/remotefile/loadbalancer.go b/pkg/multicloud/remotefile/loadbalancer.go deleted file mode 100644 index e4a99cb4b7..0000000000 --- a/pkg/multicloud/remotefile/loadbalancer.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - "context" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SLoadbalancer struct { - SResourceBase - - region *SRegion - RegionId string - Address string - AddressType string - NetworkType string - VpcId string - ZoneId string - Zone1Id string - InstanceType string - ChargeType string - Bandwidth int - NetworkIds []string -} - -func (self *SLoadbalancer) GetAddress() string { - return self.Address -} - -func (self *SLoadbalancer) GetAddressType() string { - return self.AddressType -} - -func (self *SLoadbalancer) GetNetworkType() string { - return self.NetworkType -} - -func (self *SLoadbalancer) GetNetworkIds() []string { - return self.NetworkIds -} - -func (self *SLoadbalancer) GetVpcId() string { - return self.VpcId -} - -func (self *SLoadbalancer) GetZoneId() string { - return self.ZoneId -} - -func (self *SLoadbalancer) GetZone1Id() string { - return self.Zone1Id -} - -func (self *SLoadbalancer) GetLoadbalancerSpec() string { - return self.InstanceType -} - -func (self *SLoadbalancer) GetChargeType() string { - return self.ChargeType -} - -func (self *SLoadbalancer) GetEgressMbps() int { - return self.Bandwidth -} - -func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SLoadbalancer) Delete(ctx context.Context) error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) Start() error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) Stop() error { - return cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { - return nil, cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/remotefile/monitor.go b/pkg/multicloud/remotefile/monitor.go deleted file mode 100644 index 956e92336e..0000000000 --- a/pkg/multicloud/remotefile/monitor.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -func (self *SRemoteFileClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) - } -} - -func (self *SRemoteFileClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.getMetrics(opts.ResourceType, opts.MetricType) -} diff --git a/pkg/multicloud/remotefile/network.go b/pkg/multicloud/remotefile/network.go deleted file mode 100644 index 532e742d5b..0000000000 --- a/pkg/multicloud/remotefile/network.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - SResourceBase - - wire *SWire - WireId string - IpStart string - IpEnd string - IpMask int8 - Gatway string -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetIpStart() string { - return self.IpStart -} - -func (self *SNetwork) GetIpEnd() string { - return self.IpEnd -} - -func (self *SNetwork) GetIpMask() int8 { - return self.IpMask -} - -func (self *SNetwork) GetGateway() string { - return self.Gatway -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) Delete() error { - return cloudprovider.ErrNotSupported -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 6 -} diff --git a/pkg/multicloud/remotefile/provider/doc.go b/pkg/multicloud/remotefile/provider/doc.go deleted file mode 100644 index 9dafb32bb8..0000000000 --- a/pkg/multicloud/remotefile/provider/doc.go +++ /dev/null @@ -1 +0,0 @@ -package provider // import "yunion.io/x/onecloud/pkg/multicloud/remotefile/provider" diff --git a/pkg/multicloud/remotefile/provider/provider.go b/pkg/multicloud/remotefile/provider/provider.go deleted file mode 100644 index aa15534a60..0000000000 --- a/pkg/multicloud/remotefile/provider/provider.go +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/remotefile" -) - -type SRemoteFileProviderFactory struct { - cloudprovider.SPrivateCloudBaseProviderFactory -} - -func (self *SRemoteFileProviderFactory) GetId() string { - return remotefile.CLOUD_PROVIDER_REMOTEFILE -} - -func (self *SRemoteFileProviderFactory) GetName() string { - return remotefile.CLOUD_PROVIDER_REMOTEFILE -} - -func (self *SRemoteFileProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AuthUrl) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "auth_url") - } - if len(input.Username) == 0 { - input.Username = "root" - } - if len(input.Password) == 0 { - input.Password = "password" - } - output.Account = input.Username - output.Secret = input.Password - output.AccessUrl = input.AuthUrl - return output, nil -} - -func (self *SRemoteFileProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - return output, cloudprovider.ErrNotSupported -} - -func (self *SRemoteFileProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - client, err := remotefile.NewRemoteFileClient( - remotefile.NewRemoteFileClientConfig( - cfg.URL, - cfg.Account, - cfg.Secret, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SRemoteFileProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SRemoteFileProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - return map[string]string{ - "REMOTEFILE_AUTH_URL": info.Url, - }, nil -} - -func init() { - factory := SRemoteFileProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SRemoteFileProvider struct { - cloudprovider.SBaseProvider - client *remotefile.SRemoteFileClient -} - -func (self *SRemoteFileProvider) GetVersion() string { - return "" -} - -func (self *SRemoteFileProvider) GetSysInfo() (jsonutils.JSONObject, error) { - return jsonutils.NewDict(), nil -} - -func (self *SRemoteFileProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SRemoteFileProvider) GetAccountId() string { - return "" -} - -func (self *SRemoteFileProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SRemoteFileProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(id) -} - -func (self *SRemoteFileProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, cloudprovider.ErrNotSupported -} - -func (self *SRemoteFileProvider) GetCloudRegionExternalIdPrefix() string { - return self.client.GetCloudRegionExternalIdPrefix() -} - -func (self *SRemoteFileProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SRemoteFileProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRemoteFileProvider) GetStorageClasses(regionId string) []string { - return nil -} - -func (self *SRemoteFileProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (self *SRemoteFileProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (self *SRemoteFileProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SRemoteFileProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetMetrics(opts) -} diff --git a/pkg/multicloud/remotefile/region.go b/pkg/multicloud/remotefile/region.go deleted file mode 100644 index 9b8a26730c..0000000000 --- a/pkg/multicloud/remotefile/region.go +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - SResourceBase - multicloud.SRegion - multicloud.SRegionSecurityGroupBase - multicloud.SRegionOssBase - multicloud.SRegionLbBase - - client *SRemoteFileClient -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s%s", self.client.GetCloudRegionExternalIdPrefix(), self.Id) -} - -func (self *SRegion) GetProvider() string { - return self.client.cpcfg.Vendor -} - -func (self *SRegion) GetCloudEnv() string { - return "" -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - zones, err := self.client.GetZones() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudZone{} - for i := range zones { - if zones[i].RegionId != self.GetId() { - continue - } - zones[i].region = self - ret = append(ret, &zones[i]) - } - return ret, nil -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - zones, err := self.client.GetZones() - if err != nil { - return nil, err - } - for i := 0; i < len(zones); i += 1 { - if zones[i].RegionId != self.GetId() { - continue - } - if zones[i].GetGlobalId() == id { - zones[i].region = self - return &zones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - instances, err := region.client.GetInstances() - if err != nil { - return nil, err - } - instance := SInstance{} - for _, v := range instances { - if v.Id == id { - return &instance, nil - } - } - return nil, errors.Wrapf(errors.ErrNotFound, "GetIVMById:%s", id) -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - vpcs, err := self.client.GetVpcs() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudVpc{} - for i := range vpcs { - if vpcs[i].RegionId != self.GetId() { - continue - } - vpcs[i].region = self - ret = append(ret, &vpcs[i]) - } - return ret, nil -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - ivpcs, err := self.GetIVpcs() - if err != nil { - return nil, err - } - for i := 0; i < len(ivpcs); i += 1 { - if ivpcs[i].GetGlobalId() == id { - return ivpcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, err := self.client.GetEips() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudEIP{} - for i := range eips { - if eips[i].RegionId != self.GetId() { - continue - } - ret = append(ret, &eips[i]) - } - return ret, nil -} - -func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { - eips, err := self.GetIEips() - if err != nil { - return nil, err - } - for i := range eips { - if eips[i].GetGlobalId() == id { - return eips[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := self.client.GetSecgroups() - if err != nil { - return nil, err - } - for i := range secgroups { - if secgroups[i].GetGlobalId() == secgroupId { - return &secgroups[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := self.client.GetSecgroups() - if err != nil { - return nil, err - } - for i := range secgroups { - if secgroups[i].GetName() == opts.Name { - return &secgroups[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - lbs, err := self.client.GetLoadbalancers() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudLoadbalancer{} - for i := range lbs { - if lbs[i].RegionId != self.GetId() { - continue - } - lbs[i].region = self - ret = append(ret, &lbs[i]) - } - return ret, nil -} - -func (self *SRegion) GetILoadBalancerById(id string) (cloudprovider.ICloudLoadbalancer, error) { - lbs, err := self.GetILoadBalancers() - if err != nil { - return nil, err - } - for i := range lbs { - if lbs[i].GetGlobalId() == id { - return lbs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - buckets, err := self.client.GetBuckets() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudBucket{} - for i := range buckets { - if buckets[i].RegionId != self.GetId() { - continue - } - buckets[i].region = self - ret = append(ret, &buckets[i]) - } - return ret, nil -} - -func (self *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { - buckets, err := self.GetIBuckets() - if err != nil { - return nil, err - } - for i := range buckets { - if buckets[i].GetName() == name { - return buckets[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { - buckets, err := self.GetIBuckets() - if err != nil { - return nil, err - } - for i := range buckets { - if buckets[i].GetGlobalId() == name { - return buckets[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) CreateIBucket(name string, storageClassStr string, acl string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetIMiscResources() ([]cloudprovider.ICloudMiscResource, error) { - misc, err := self.client.GetMisc() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudMiscResource{} - for i := range misc { - ret = append(ret, &misc[i]) - } - return ret, nil -} - -func (self *SRegion) GetCapabilities() []string { - return self.client.GetCapabilities() -} diff --git a/pkg/multicloud/remotefile/securitygroup.go b/pkg/multicloud/remotefile/securitygroup.go deleted file mode 100644 index 1f797ac0c7..0000000000 --- a/pkg/multicloud/remotefile/securitygroup.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import "yunion.io/x/onecloud/pkg/cloudprovider" - -type SSecurityGroup struct { - SResourceBase - - VpcId string - Desc string -} - -func (self *SSecurityGroup) GetDescription() string { - return self.Desc -} - -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - return []cloudprovider.SecurityRule{}, nil -} - -func (self *SSecurityGroup) GetVpcId() string { - return self.VpcId -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - return cloudprovider.ErrNotSupported -} - -func (self *SSecurityGroup) GetReferences() ([]cloudprovider.SecurityGroupReference, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SSecurityGroup) Delete() error { - return cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/remotefile/storage.go b/pkg/multicloud/remotefile/storage.go deleted file mode 100644 index ffa5f0b18a..0000000000 --- a/pkg/multicloud/remotefile/storage.go +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - "yunion.io/x/jsonutils" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SStorage struct { - SResourceBase - - zone *SZone - ZoneId string - StorageType string - MediumType string - CapacityMb int64 - CapacityUsedMb int64 - Enabled bool - SkipSync bool -} - -func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return nil -} - -func (self *SStorage) GetIZone() cloudprovider.ICloudZone { - return self.zone -} - -func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := self.zone.region.client.GetDisks() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudDisk{} - for i := range disks { - if disks[i].StorageId != self.GetId() { - continue - } - disks[i].storage = self - ret = append(ret, &disks[i]) - } - return ret, nil -} - -func (self *SStorage) GetStorageType() string { - return self.StorageType -} - -func (self *SStorage) GetMediumType() string { - return self.MediumType -} - -func (self *SStorage) GetCapacityMB() int64 { - return self.CapacityMb -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return self.CapacityUsedMb -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (self *SStorage) GetEnabled() bool { - return self.Enabled -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - disks, err := self.GetIDisks() - if err != nil { - return nil, err - } - for i := range disks { - if disks[i].GetGlobalId() == id { - return disks[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} - -func (self *SStorage) DisableSync() bool { - return self.SkipSync -} diff --git a/pkg/multicloud/remotefile/vpc.go b/pkg/multicloud/remotefile/vpc.go deleted file mode 100644 index a3e3655b99..0000000000 --- a/pkg/multicloud/remotefile/vpc.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - "yunion.io/x/pkg/utils" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - SResourceBase - - region *SRegion - - RegionId string - CidrBlock string - IsDefault bool -} - -func (self *SVpc) Delete() error { - return cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetCidrBlock() string { - return self.CidrBlock -} - -func (self *SVpc) GetIRouteTableById(id string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - wires, err := self.region.client.GetWires() - if err != nil { - return nil, err - } - zones, err := self.region.client.GetZones() - if err != nil { - return nil, err - } - zoneIds := []string{} - for i := range zones { - zoneIds = append(zoneIds, zones[i].Id) - } - ret := []cloudprovider.ICloudWire{} - for i := range wires { - if wires[i].VpcId != self.GetId() || !utils.IsInStringArray(wires[i].ZoneId, zoneIds) { - continue - } - wires[i].region = self.region - ret = append(ret, &wires[i]) - } - return ret, nil -} - -func (self *SVpc) CreateIWire(opts *cloudprovider.SWireCreateOptions) (cloudprovider.ICloudWire, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := self.region.client.GetSecgroups() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudSecurityGroup{} - for i := range secgroups { - if secgroups[i].VpcId != self.GetId() { - continue - } - ret = append(ret, &secgroups[i]) - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { - wires, err := self.GetIWires() - if err != nil { - return nil, err - } - for i := range wires { - if wires[i].GetGlobalId() == id { - return wires[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { - return cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetAuthorityOwnerId() string { - return "" -} - -func (self *SVpc) ProposeJoinICloudInterVpcNetwork(opts *cloudprovider.SVpcJointInterVpcNetworkOption) error { - return cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetICloudIPv6Gateways() ([]cloudprovider.ICloudIPv6Gateway, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetIsDefault() bool { - return self.IsDefault -} - -func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { - return self.region -} diff --git a/pkg/multicloud/remotefile/wire.go b/pkg/multicloud/remotefile/wire.go deleted file mode 100644 index 367d5533a3..0000000000 --- a/pkg/multicloud/remotefile/wire.go +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import "yunion.io/x/onecloud/pkg/cloudprovider" - -type SWire struct { - SResourceBase - - region *SRegion - - WireId string - VpcId string - ZoneId string - Bandwidth int -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - vpcs, err := self.region.client.GetVpcs() - if err != nil { - return nil - } - for i := range vpcs { - if vpcs[i].GetId() == self.VpcId { - vpcs[i].region = self.region - return &vpcs[i] - } - } - return nil -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - zones, err := self.region.client.GetZones() - if err != nil { - return nil - } - for i := range zones { - if zones[i].GetId() == self.ZoneId { - zones[i].region = self.region - return &zones[i] - } - } - return nil -} - -func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - networks, err := self.region.client.GetNetworks() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudNetwork{} - for i := range networks { - if networks[i].WireId != self.GetId() { - continue - } - networks[i].wire = self - ret = append(ret, &networks[i]) - } - return ret, nil -} - -func (self *SWire) GetBandwidth() int { - return self.Bandwidth -} - -func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { - networks, err := self.GetINetworks() - if err != nil { - return nil, err - } - for i := range networks { - if networks[i].GetGlobalId() == id { - return networks[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - return nil, cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/remotefile/zone.go b/pkg/multicloud/remotefile/zone.go deleted file mode 100644 index d093db5945..0000000000 --- a/pkg/multicloud/remotefile/zone.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 remotefile - -import ( - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SZone struct { - SResourceBase - region *SRegion - - RegionId string -} - -func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - hosts, err := self.region.client.GetHosts() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudHost{} - for i := range hosts { - if hosts[i].ZoneId != self.GetId() { - continue - } - hosts[i].zone = self - ret = append(ret, &hosts[i]) - } - return ret, nil -} - -func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - hosts, err := self.GetIHosts() - if err != nil { - return nil, err - } - for i := range hosts { - if hosts[i].GetGlobalId() == id { - return hosts[i], nil - } - } - return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) -} - -func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := self.region.client.GetStorages() - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudStorage{} - for i := range storages { - if storages[i].ZoneId != self.GetId() { - continue - } - storages[i].zone = self - ret = append(ret, &storages[i]) - } - return ret, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storages, err := self.GetIStorages() - if err != nil { - return nil, err - } - for i := range storages { - if storages[i].GetGlobalId() == id { - return storages[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} diff --git a/pkg/multicloud/tag_base.go b/pkg/multicloud/tag_base.go deleted file mode 100644 index c46dc43e98..0000000000 --- a/pkg/multicloud/tag_base.go +++ /dev/null @@ -1,559 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 multicloud - -import ( - "strings" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/util/encode" -) - -type STagBase struct { -} - -func (self STagBase) GetSysTags() map[string]string { - return nil -} - -func (self STagBase) GetTags() (map[string]string, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") -} - -func (self STagBase) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type QcloudTags struct { - TagSet []STag - - // Redis - InstanceTags []STag - // Elasticsearch - TagList []STag - // Kafka - Tags []STag - // Cdn - Tag []STag - // TDSQL - ResourceTags []STag -} - -func (self *QcloudTags) getTags() (map[string]string, error) { - ret := map[string]string{} - for _, tag := range self.TagSet { - if tag.Value == "null" { - tag.Value = "" - } - ret[tag.Key] = tag.Value - } - for _, tag := range self.InstanceTags { - if tag.TagValue == "null" { - tag.TagValue = "" - } - ret[tag.TagKey] = tag.TagValue - } - for _, tag := range self.TagList { - if tag.TagValue == "null" { - tag.TagValue = "" - } - ret[tag.TagKey] = tag.TagValue - } - for _, tag := range self.Tags { - if tag.TagValue == "null" { - tag.TagValue = "" - } - ret[tag.TagKey] = tag.TagValue - } - for _, tag := range self.Tag { - if tag.TagValue == "null" { - tag.TagValue = "" - } - ret[tag.TagKey] = tag.TagValue - } - for _, tag := range self.ResourceTags { - if tag.TagValue == "null" { - tag.TagValue = "" - } - ret[tag.TagKey] = tag.TagValue - } - return ret, nil -} - -func (self *QcloudTags) GetTags() (map[string]string, error) { - tags, _ := self.getTags() - for k := range tags { - if strings.HasPrefix(k, "tencentcloud:") { - delete(tags, k) - } - } - return tags, nil -} - -func (self *QcloudTags) GetSysTags() map[string]string { - tags, _ := self.getTags() - ret := map[string]string{} - for k, v := range tags { - if strings.HasPrefix(k, "tencentcloud:") { - ret[k] = v - } - } - return ret -} - -func (self *QcloudTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type STag struct { - TagKey string - TagValue string - - Key string - Value string -} - -type AliyunTags struct { - Tags struct { - Tag []STag - - // Kafka - TagVO []STag `json:"TagVO" yunion-deprecated-by:"Tag"` - } -} - -func (self *AliyunTags) GetTags() (map[string]string, error) { - ret := map[string]string{} - for _, tag := range self.Tags.Tag { - if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") || - strings.HasPrefix(tag.Key, "aliyun") || strings.HasPrefix(tag.Key, "acs:") || - strings.HasPrefix(tag.Key, "ack.") || strings.HasPrefix(tag.TagKey, "ack.") { // k8s - continue - } - if len(tag.TagKey) > 0 { - ret[tag.TagKey] = tag.TagValue - } else if len(tag.Key) > 0 { - ret[tag.Key] = tag.Value - } - } - - return ret, nil -} - -func (self *AliyunTags) GetSysTags() map[string]string { - ret := map[string]string{} - for _, tag := range self.Tags.Tag { - if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") || - strings.HasPrefix(tag.Key, "aliyun") || strings.HasPrefix(tag.Key, "acs:") || - strings.HasPrefix(tag.Key, "ack.") || strings.HasPrefix(tag.TagKey, "ack.") { // k8s - if len(tag.TagKey) > 0 { - ret[tag.TagKey] = tag.TagValue - } else if len(tag.Key) > 0 { - ret[tag.Key] = tag.Value - } - } - } - return ret -} - -func (self *AliyunTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type ApsaraTags struct { - Tags struct { - Tag []STag - } -} - -func (self *ApsaraTags) GetTags() (map[string]string, error) { - ret := map[string]string{} - for _, tag := range self.Tags.Tag { - if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") || - strings.HasSuffix(tag.Key, "aliyun") || strings.HasPrefix(tag.Key, "acs:") { - continue - } - if len(tag.TagKey) > 0 { - ret[tag.TagKey] = tag.TagValue - } else if len(tag.Key) > 0 { - ret[tag.Key] = tag.Value - } - } - return ret, nil -} - -func (self *ApsaraTags) GetSysTags() map[string]string { - ret := map[string]string{} - for _, tag := range self.Tags.Tag { - if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") || - strings.HasPrefix(tag.Key, "aliyun") || strings.HasPrefix(tag.Key, "acs:") { - if len(tag.TagKey) > 0 { - ret[tag.TagKey] = tag.TagValue - } else if len(tag.Key) > 0 { - ret[tag.Key] = tag.Value - } - } - } - return ret -} - -func (self *ApsaraTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type GoogleTags struct { - Labels map[string]string -} - -func (self *GoogleTags) GetTags() (map[string]string, error) { - ret := map[string]string{} - for k, v := range self.Labels { - if strings.HasPrefix(k, "goog-") { - continue - } - ret[encode.DecodeGoogleLable(k)] = encode.DecodeGoogleLable(v) - } - return ret, nil -} - -func (self *GoogleTags) GetSysTags() map[string]string { - ret := map[string]string{} - for k, v := range self.Labels { - if strings.HasPrefix(k, "goog-") { - ret[k] = v - } - } - return ret -} - -func (self *GoogleTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type AzureTags struct { - Tags map[string]string -} - -func (self *AzureTags) GetTags() (map[string]string, error) { - return self.Tags, nil -} - -func (self *AzureTags) GetSysTags() map[string]string { - return nil -} - -func (self *AzureTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type SAwsTag struct { - Key string `xml:"key"` - Value string `xml:"value"` -} - -type SAwsRdsTag struct { - Key string `xml:"Key"` - Value string `xml:"Value"` -} - -type AwsTags struct { - TagSet []SAwsTag `xml:"tagSet>item"` - // rds - TagList []SAwsRdsTag `xml:"TagList>Tag"` -} - -func (self AwsTags) GetName() string { - for _, tag := range self.TagSet { - if strings.ToLower(tag.Key) == "name" { - return tag.Value - } - } - return "" -} - -func (self *AwsTags) GetTags() (map[string]string, error) { - ret := map[string]string{} - for _, tag := range self.TagSet { - if tag.Key == "Name" || tag.Key == "Description" { - continue - } - ret[tag.Key] = tag.Value - } - for _, tag := range self.TagList { - if strings.ToLower(tag.Key) == "name" || strings.ToLower(tag.Key) == "description" { - continue - } - ret[tag.Key] = tag.Value - } - return ret, nil -} - -func (self *AwsTags) GetSysTags() map[string]string { - return nil -} - -func (self *AwsTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type CtyunTags struct { -} - -func (self *CtyunTags) GetTags() (map[string]string, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") -} - -func (self *CtyunTags) GetSysTags() map[string]string { - return nil -} - -func (self *CtyunTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type EcloudTags struct { -} - -func (self *EcloudTags) GetTags() (map[string]string, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") -} - -func (self *EcloudTags) GetSysTags() map[string]string { - return nil -} - -func (self *EcloudTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type JdcloudTags struct { -} - -func (jt *JdcloudTags) GetTags() (map[string]string, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") -} - -func (self *JdcloudTags) GetSysTags() map[string]string { - return nil -} - -func (self *JdcloudTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type HuaweiTags struct { - Tags []string -} - -func (self *HuaweiTags) GetTags() (map[string]string, error) { - tags := map[string]string{} - for _, kv := range self.Tags { - splited := strings.Split(kv, "=") - if len(splited) == 2 { - tags[splited[0]] = splited[1] - } - } - return tags, nil -} - -func (self *HuaweiTags) GetSysTags() map[string]string { - return nil -} - -func (self *HuaweiTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type HuaweiDiskTags struct { - Tags map[string]string -} - -func (self *HuaweiDiskTags) GetTags() (map[string]string, error) { - return self.Tags, nil -} - -func (self *HuaweiDiskTags) GetSysTags() map[string]string { - return nil -} - -func (self *HuaweiDiskTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type OpenStackTags struct { - Metadata map[string]string -} - -func (self *OpenStackTags) GetTags() (map[string]string, error) { - return self.Metadata, nil -} - -func (self *OpenStackTags) GetSysTags() map[string]string { - return nil -} - -func (self *OpenStackTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type UcloudTags struct { -} - -func (self *UcloudTags) GetTags() (map[string]string, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") -} - -func (self *UcloudTags) GetSysTags() map[string]string { - return nil -} - -func (self *UcloudTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type ZStackTags struct { -} - -func (self *ZStackTags) GetTags() (map[string]string, error) { - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") -} - -func (self *ZStackTags) GetSysTags() map[string]string { - return nil -} - -func (self *ZStackTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type CloudpodsTags struct { - Metadata map[string]string -} - -func (self *CloudpodsTags) GetTags() (map[string]string, error) { - metadatas := map[string]string{} - for k, v := range self.Metadata { - if strings.HasPrefix(k, apis.USER_TAG_PREFIX) { - metadatas[strings.TrimPrefix(k, apis.USER_TAG_PREFIX)] = v - } - } - return metadatas, nil -} - -func (self *CloudpodsTags) GetSysTags() map[string]string { - return nil -} - -func (self *CloudpodsTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type BingoTags struct { - TagSet []struct { - Key string - Value string - } -} - -func (self *BingoTags) GetTags() (map[string]string, error) { - tags := map[string]string{} - for _, tag := range self.TagSet { - tags[tag.Key] = tag.Value - } - return tags, nil -} - -func (self *BingoTags) GetSysTags() map[string]string { - return nil -} - -func (self *BingoTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type InCloudSphereTags struct { -} - -func (self *InCloudSphereTags) GetTags() (map[string]string, error) { - tags := map[string]string{} - return tags, nil -} - -func (self *InCloudSphereTags) GetSysTags() map[string]string { - return nil -} - -func (self *InCloudSphereTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type ProxmoxTags struct { -} - -func (self *ProxmoxTags) GetTags() (map[string]string, error) { - tags := map[string]string{} - return tags, nil -} - -func (self *ProxmoxTags) GetSysTags() map[string]string { - return nil -} - -func (self *ProxmoxTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type RemoteFileTags struct { - Tags map[string]string - SysTags map[string]string -} - -func (self *RemoteFileTags) GetTags() (map[string]string, error) { - return self.Tags, nil -} - -func (self *RemoteFileTags) GetSysTags() map[string]string { - return self.SysTags -} - -func (self *RemoteFileTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} - -type HcsTags struct { - Tags []string -} - -func (self *HcsTags) GetTags() (map[string]string, error) { - tags := map[string]string{} - for _, kv := range self.Tags { - splited := strings.Split(kv, "=") - if len(splited) == 2 { - tags[splited[0]] = splited[1] - } - } - return tags, nil -} - -func (self *HcsTags) GetSysTags() map[string]string { - return nil -} - -func (self *HcsTags) SetTags(tags map[string]string, replace bool) error { - return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") -} diff --git a/pkg/multicloud/test/doc.go b/pkg/multicloud/test/doc.go deleted file mode 100644 index 236ecfb904..0000000000 --- a/pkg/multicloud/test/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 test // import "yunion.io/x/onecloud/pkg/multicloud/test" diff --git a/pkg/multicloud/test/readonly.go b/pkg/multicloud/test/readonly.go deleted file mode 100644 index f65ab84b80..0000000000 --- a/pkg/multicloud/test/readonly.go +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 test - -import ( - "os" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/util/printutils" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func TestShell() { - - type RegionResourceCount struct { - ZoneCount int - VpcCount int - NetworkCount int - EipCount int - VmCount int - LbCount int - LbCertCount int - DiskCount int - SnapshotCount int - SnapshotPolicyCount int - ImageCount int - NetworkInterfaceCount int - BucketCount int - RdsCount int - } - - type ReadonlyTestOptions struct { - TestVpc bool `default:"true"` - TestLb bool `default:"true"` - } - - var list = func(parent cloudprovider.ICloudResource, resource string, callback func() (interface{}, error)) interface{} { - result, err := callback() - if err != nil { - if errors.Cause(err) != cloudprovider.ErrNotImplemented && errors.Cause(err) != cloudprovider.ErrNotSupported { - return result - } - log.Errorf("list %s error: %v", resource, err) - os.Exit(-1) - } - log.Debugf("%s(%s) %s:", parent.GetName(), parent.GetGlobalId(), resource) - printutils.PrintGetterList(result, nil) - return result - } - - var show = func(parent cloudprovider.ICloudResource, resource string, callback func() (interface{}, error)) interface{} { - result, err := callback() - if err != nil { - if errors.Cause(err) != cloudprovider.ErrNotImplemented && errors.Cause(err) != cloudprovider.ErrNotSupported { - return result - } - log.Errorf("show %s(%s) %s error: %v", parent.GetName(), parent.GetGlobalId(), resource, err) - os.Exit(-1) - } - log.Debugf("%s(%s) %s:", parent.GetName(), parent.GetGlobalId(), resource) - printutils.PrintGetterObject(result) - return result - } - - shellutils.R(&ReadonlyTestOptions{}, "test-readonly", "Test read", func(cli cloudprovider.ICloudRegion, args *ReadonlyTestOptions) error { - result := RegionResourceCount{ - ZoneCount: 0, - VpcCount: 0, - NetworkCount: 0, - EipCount: 0, - VmCount: 0, - LbCount: 0, - LbCertCount: 0, - DiskCount: 0, - SnapshotCount: 0, - SnapshotPolicyCount: 0, - ImageCount: 0, - NetworkInterfaceCount: 0, - BucketCount: 0, - } - if args.TestVpc { - _vpcs := list(cli, "vpcs", func() (interface{}, error) { - return cli.GetIVpcs() - }) - vpcs := _vpcs.([]cloudprovider.ICloudVpc) - result.VpcCount += len(vpcs) - for i := range vpcs { - _wire := list(vpcs[i], "wire", func() (interface{}, error) { - return vpcs[i].GetIWires() - }) - wires := _wire.([]cloudprovider.ICloudWire) - for j := range wires { - _networks := list(wires[j], "networks", func() (interface{}, error) { - return wires[j].GetINetworks() - }) - networks := _networks.([]cloudprovider.ICloudNetwork) - result.NetworkCount += len(networks) - } - } - } - _eips := list(cli, "eips", func() (interface{}, error) { - return cli.GetIEips() - }) - eips := _eips.([]cloudprovider.ICloudEIP) - result.EipCount = len(eips) - _snapshots := list(cli, "snapshots", func() (interface{}, error) { - return cli.GetISnapshots() - }) - snapshots := _snapshots.([]cloudprovider.ICloudSnapshot) - result.SnapshotCount = len(snapshots) - _snapshotPolicies := list(cli, "snapshot policies", func() (interface{}, error) { - return cli.GetISnapshotPolicies() - }) - snapshotPolicies := _snapshotPolicies.([]cloudprovider.ICloudSnapshotPolicy) - result.SnapshotPolicyCount = len(snapshotPolicies) - _nics := list(cli, "network interfaces", func() (interface{}, error) { - return cli.GetINetworkInterfaces() - }) - nics := _nics.([]cloudprovider.ICloudNetworkInterface) - result.NetworkInterfaceCount = len(nics) - - _buckets := list(cli, "buckets", func() (interface{}, error) { - return cli.GetIBuckets() - }) - buckets := _buckets.([]cloudprovider.ICloudBucket) - result.BucketCount = len(buckets) - for i := range buckets { - list(buckets[i], "bucket objects", func() (interface{}, error) { - return buckets[i].ListObjects("", "", "", 10) - }) - } - - list(cli, "storages", func() (interface{}, error) { - return cli.GetIStorages() - }) - _caches := list(cli, "storagecaches", func() (interface{}, error) { - return cli.GetIStoragecaches() - }) - caches := _caches.([]cloudprovider.ICloudStoragecache) - for i := range caches { - _images := list(caches[i], "images", func() (interface{}, error) { - return caches[i].GetICloudImages() - }) - images := _images.([]cloudprovider.ICloudImage) - result.ImageCount = len(images) - } - - _zones := list(cli, "zones", func() (interface{}, error) { - return cli.GetIZones() - }) - zones := _zones.([]cloudprovider.ICloudZone) - result.ZoneCount = len(zones) - for i := range zones { - _hosts := list(zones[i], "host", func() (interface{}, error) { - return zones[i].GetIHosts() - }) - hosts := _hosts.([]cloudprovider.ICloudHost) - for j := range hosts { - _vms := list(hosts[j], "vms", func() (interface{}, error) { - return hosts[j].GetIVMs() - }) - vms := _vms.([]cloudprovider.ICloudVM) - result.VmCount += len(vms) - for k := range vms { - list(vms[k], "vm disks", func() (interface{}, error) { - return vms[k].GetIDisks() - }) - list(vms[k], "vm nics", func() (interface{}, error) { - return vms[k].GetINics() - }) - show(vms[k], "vm eip", func() (interface{}, error) { - return vms[k].GetIEIP() - }) - } - } - _storages := list(zones[i], "storages", func() (interface{}, error) { - return zones[i].GetIStorages() - }) - storages := _storages.([]cloudprovider.ICloudStorage) - for j := range storages { - _disks := list(storages[j], "disks", func() (interface{}, error) { - return storages[j].GetIDisks() - }) - disks := _disks.([]cloudprovider.ICloudDisk) - result.DiskCount += len(disks) - } - } - if args.TestLb { - /* - list(cli, "lb acls", func() (interface{}, error) { - return cli.GetILoadBalancerAcls() - }) - */ - _certs := list(cli, "lb certificates", func() (interface{}, error) { - return cli.GetILoadBalancerCertificates() - }) - certs := _certs.([]cloudprovider.ICloudLoadbalancerCertificate) - result.LbCertCount = len(certs) - /* - list(cli, "lb backend groups", func() (interface{}, error) { - return cli.GetILoadBalancerBackendGroups() - }) - */ - _lbs := list(cli, "lbs", func() (interface{}, error) { - return cli.GetILoadBalancers() - }) - lbs := _lbs.([]cloudprovider.ICloudLoadbalancer) - result.LbCount += len(lbs) - for i := range lbs { - _listeners := list(lbs[i], "lb listeners", func() (interface{}, error) { - return lbs[i].GetILoadBalancerListeners() - }) - listeners := _listeners.([]cloudprovider.ICloudLoadbalancerListener) - for j := range listeners { - list(listeners[j], "listener rules", func() (interface{}, error) { - return listeners[j].GetILoadbalancerListenerRules() - }) - } - _groups := list(lbs[i], "lb backend groups", func() (interface{}, error) { - return lbs[i].GetILoadBalancerBackendGroups() - }) - groups := _groups.([]cloudprovider.ICloudLoadbalancerBackendGroup) - for j := range groups { - list(groups[j], "lb backend", func() (interface{}, error) { - return groups[j].GetILoadbalancerBackends() - }) - } - } - } - - _rds := list(cli, "rds", func() (interface{}, error) { - return cli.GetIDBInstances() - }) - rds := _rds.([]cloudprovider.ICloudDBInstance) - result.RdsCount = len(rds) - log.Println("resource sum for ", cli.GetName(), jsonutils.Marshal(result).PrettyString()) - return nil - }) -} diff --git a/pkg/multicloud/ucloud/client.go b/pkg/multicloud/ucloud/client.go deleted file mode 100644 index c03682576d..0000000000 --- a/pkg/multicloud/ucloud/client.go +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "context" - "crypto/sha1" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -const UCLOUD_API_HOST = "https://api.ucloud.cn" - -// API返回结果对应的字段名 -var UCLOUD_API_RESULT_KEYS = map[string]string{ - "AllocateEIP": "EIPSet", - "GetProjectList": "ProjectSet", - "GetRegion": "Regions", - "DescribeVPC": "DataSet", - "DescribeImage": "ImageSet", - "DescribeIsolationGroup": "IsolationGroupSet", - "DescribeUHostInstance": "UHostSet", - "DescribeUHostTags": "TagSet", - "DescribeUDSet": "UDSet", - "DescribeUDisk": "DataSet", - "DescribeUDiskSnapshot": "DataSet", - "DescribeEIP": "EIPSet", - "DescribeFirewall": "DataSet", - "DescribeSubnet": "DataSet", - "DescribeBucket": "DataSet", - "CreateUDisk": "UDiskId", - "CreateVPC": "VPCId", - "CreateUDiskSnapshot": "SnapshotId", - "DescribeVIP": "VIPSet", -} - -type SParams struct { - data jsonutils.JSONDict -} - -type SUcloudError struct { - Action string `json:"Action"` - Message string `json:"Message"` - RetCode int64 `json:"RetCode"` -} - -func (self *SUcloudError) Error() string { - return fmt.Sprintf("Do %s failed, code: %d, %s", self.Action, self.RetCode, self.Message) -} - -func NewUcloudParams() SParams { - data := jsonutils.NewDict() - return SParams{data: *data} -} - -func (self *SParams) Set(key string, value interface{}) { - switch v := value.(type) { - case string: - self.data.Set(key, jsonutils.NewString(v)) - case int64: - self.data.Set(key, jsonutils.NewInt(v)) - case int: - self.data.Set(key, jsonutils.NewInt(int64(v))) - case bool: - self.data.Set(key, jsonutils.NewBool(v)) - case float64: - self.data.Set(key, jsonutils.NewFloat64(v)) - case float32: - self.data.Set(key, jsonutils.NewFloat32(v)) - case []string: - self.data.Set(key, jsonutils.NewStringArray(v)) - default: - log.Debugf("unsuported params type %T", value) - } -} - -func (self *SParams) SetAction(action string) { - self.data.Set("Action", jsonutils.NewString(action)) -} - -func (self *SParams) SetPagination(limit, offset int) { - if limit == 0 { - limit = 20 - } - - self.data.Set("Limit", jsonutils.NewInt(int64(limit))) - self.data.Set("Offset", jsonutils.NewInt(int64(offset))) -} - -func (self *SParams) String() string { - return self.data.String() -} - -func (self *SParams) PrettyString() string { - return self.data.PrettyString() -} - -func (self *SParams) GetParams() jsonutils.JSONDict { - return self.data -} - -// https://docs.ucloud.cn/api/summary/signature -func BuildParams(params SParams, privateKey string) jsonutils.JSONObject { - data := params.GetParams() - // remove old Signature - data.Remove("Signature") - - // 排序并计算signture - keys := data.SortedKeys() - lst := []string{} - for _, k := range keys { - lst = append(lst, k) - v, _ := data.GetString(k) - lst = append(lst, v) - } - - raw := strings.Join(lst, "") + privateKey - signture := fmt.Sprintf("%x", sha1.Sum([]byte(raw))) - - data.Set("Signature", jsonutils.NewString(signture)) - return &data -} - -func GetSignature(params SParams, privateKey string) string { - sign, _ := BuildParams(params, privateKey).GetString("Signature") - return sign -} - -func parseUcloudResponse(params SParams, resp jsonutils.JSONObject) (jsonutils.JSONObject, error) { - err := &SUcloudError{} - e := resp.Unmarshal(err) - if e != nil { - return nil, e - } - - err.Action, _ = params.data.GetString("Action") - - if err.RetCode > 0 { - if err.RetCode == 171 { - return nil, errors.Wrapf(httperrors.ErrInvalidAccessKey, err.Error()) - } - return nil, err - } - - return resp, nil -} - -func jsonRequest(client *SUcloudClient, params SParams) (jsonutils.JSONObject, error) { - ctx := context.Background() - MAX_RETRY := 3 - retry := 0 - var err error - var resp jsonutils.JSONObject - for retry < MAX_RETRY { - _, resp, err = httputils.JSONRequest( - client.httpClient, - ctx, - httputils.POST, - UCLOUD_API_HOST, - nil, - BuildParams(params, client.accessKeySecret), - client.debug) - - if err == nil { - return parseUcloudResponse(params, resp) - } - - switch e := err.(type) { - case *httputils.JSONClientError: - if e.Code >= 499 && !strings.Contains(err.Error(), cloudprovider.ErrAccountReadOnly.Error()) { - time.Sleep(3 * time.Second) - retry += 1 - continue - } else { - return nil, err - } - default: - return nil, err - } - } - - return resp, err -} diff --git a/pkg/multicloud/ucloud/client_test.go b/pkg/multicloud/ucloud/client_test.go deleted file mode 100644 index 2b41a99f70..0000000000 --- a/pkg/multicloud/ucloud/client_test.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "testing" - - "yunion.io/x/jsonutils" -) - -func TestGetSignature(t *testing.T) { - type args struct { - params SParams - privateKey string - } - - _obj, _ := jsonutils.ParseString(`{ - "Password" : "VUNsb3VkLmNu", - "Region" : "cn-bj2", - "Zone" : "cn-bj2-04", - "ImageId" : "f43736e1-65a5-4bea-ad2e-8a46e18883c2", - "CPU" : 2, - "Memory" : 2048, - "DiskSpace" : 10, - "LoginMode" : "Password", - "Action" : "CreateUHostInstance", - "Name" : "Host01", - "ChargeType" : "Month", - "Quantity" : 1, - "PublicKey" : "ucloudsomeone@example.com1296235120854146120" -}`) - - obj := _obj.(*jsonutils.JSONDict) - - tests := []struct { - name string - args args - want string - }{ - { - name: "Ucloud api signature validate", - args: args{ - params: SParams{data: *obj}, - privateKey: "46f09bb9fab4f12dfc160dae12273d5332b5debe", - }, - want: "4f9ef5df2abab2c6fccd1e9515cb7e2df8c6bb65", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := GetSignature(tt.args.params, tt.args.privateKey); got != tt.want { - t.Errorf("GetSignature() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/multicloud/ucloud/disk.go b/pkg/multicloud/ucloud/disk.go deleted file mode 100644 index 2bf33bfa12..0000000000 --- a/pkg/multicloud/ucloud/disk.go +++ /dev/null @@ -1,456 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "context" - "fmt" - "strings" - "time" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://docs.ucloud.cn/api/udisk-api/describe_udisk -type SDisk struct { - storage *SStorage - multicloud.SDisk - multicloud.UcloudTags - - Status string `json:"Status"` - DeviceName string `json:"DeviceName"` - UHostID string `json:"UHostId"` - Tag string `json:"Tag"` - Version string `json:"Version"` - Name string `json:"Name"` - Zone string `json:"Zone"` - UHostIP string `json:"UHostIP"` - DiskType string `json:"DiskType"` - UDataArkMode string `json:"UDataArkMode"` - SnapshotLimit int `json:"SnapshotLimit"` - ExpiredTime int64 `json:"ExpiredTime"` - SnapshotCount int `json:"SnapshotCount"` - IsExpire string `json:"IsExpire"` - UDiskID string `json:"UDiskId"` - ChargeType string `json:"ChargeType"` - UHostName string `json:"UHostName"` - CreateTime int64 `json:"CreateTime"` - SizeGB int `json:"Size"` -} - -func (self *SDisk) GetProjectId() string { - return self.storage.zone.region.client.projectId -} - -func (self *SDisk) GetId() string { - return self.UDiskID -} - -func (self *SDisk) GetName() string { - if len(self.Name) == 0 { - return self.GetId() - } - - return self.Name -} - -func (self *SDisk) GetGlobalId() string { - return self.GetId() -} - -func (self *SDisk) GetStatus() string { - switch self.Status { - case "Available": - return api.DISK_READY - case "Attaching": - return api.DISK_ATTACHING - case "InUse": - return api.DISK_READY - case "Detaching": - return api.DISK_DETACHING - case "Initializating": - return api.DISK_ALLOCATING - case "Failed": - return api.DISK_ALLOC_FAILED - case "Cloning": - return api.DISK_CLONING - case "Restoring": - return api.DISK_RESET - case "RestoreFailed": - return api.DISK_RESET_FAILED - default: - return api.DISK_UNKNOWN - } -} - -func (self *SDisk) Refresh() error { - new, err := self.storage.zone.region.GetDisk(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SDisk) IsEmulated() bool { - return false -} - -func (self *SDisk) GetSysTags() map[string]string { - data := map[string]string{} - data["hypervisor"] = api.HYPERVISOR_UCLOUD - - return data -} - -// Year,Month,Dynamic,Trial -func (self *SDisk) GetBillingType() string { - switch self.ChargeType { - case "Year", "Month": - return billing_api.BILLING_TYPE_PREPAID - default: - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SDisk) GetCreatedAt() time.Time { - return time.Unix(self.CreateTime, 0) -} - -func (self *SDisk) GetExpiredAt() time.Time { - return time.Unix(self.ExpiredTime, 0) -} - -func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - return self.storage, nil -} - -func (self *SDisk) GetDiskFormat() string { - return "vhd" -} - -func (self *SDisk) GetDiskSizeMB() int { - return self.SizeGB * 1024 -} - -func (self *SDisk) GetIsAutoDelete() bool { - if self.DiskType == "SystemDisk" { - return true - } - - return false -} - -func (self *SDisk) GetTemplateId() string { - if strings.Contains(self.DiskType, "SystemDisk") && len(self.UHostID) > 0 { - ins, err := self.storage.zone.region.GetInstanceByID(self.UHostID) - if err != nil { - log.Errorln(err) - } - - return ins.ImageID - } - - return "" -} - -func (self *SDisk) GetDiskType() string { - if strings.Contains(self.DiskType, "SystemDisk") { - return api.DISK_TYPE_SYS - } - - return api.DISK_TYPE_DATA -} - -func (self *SDisk) GetStorageType() string { - if self.storage == nil { - if strings.Contains(self.DiskType, "SSD") { - return api.STORAGE_UCLOUD_CLOUD_SSD - } else { - return api.STORAGE_UCLOUD_CLOUD_NORMAL - } - } - - return self.storage.storageType -} - -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) GetAccessPath() string { - return "" -} - -func (self *SDisk) Delete(ctx context.Context) error { - return self.storage.zone.region.DeleteDisk(self.Zone, self.GetId()) -} - -func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := self.storage.zone.region.CreateSnapshot(self.Zone, self.GetId(), name, desc) - if err != nil { - return nil, err - } - - isnapshot, err := self.GetISnapshot(snapshot) - if err != nil { - return nil, err - } - - err = cloudprovider.WaitStatus(isnapshot, api.SNAPSHOT_READY, time.Second*10, time.Second*300) - if err != nil { - return nil, errors.Wrap(err, "CreateISnapshot") - } - - return isnapshot, nil -} - -func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) { - snapshot, err := self.storage.zone.region.GetSnapshotById(self.Zone, snapshotId) - return &snapshot, err -} - -func (self *SDisk) GetISnapshot(idStr string) (cloudprovider.ICloudSnapshot, error) { - snapshot, err := self.getSnapshot(idStr) - return snapshot, err -} - -func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := self.storage.zone.region.GetSnapshots("", self.GetId(), "") - if err != nil { - return nil, err - } - - isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) - for i := 0; i < len(snapshots); i++ { - isnapshots[i] = &snapshots[i] - } - return isnapshots, nil -} - -func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { - var sizeGB int64 - // 向上取整 - if (newSizeMB % 1024) > 0 { - sizeGB = newSizeMB/1024 + 1 - } else { - sizeGB = newSizeMB / 1024 - } - - if self.Status == "InUse" { - err := self.storage.zone.region.DetachDisk(self.Zone, self.UHostID, self.UDiskID) - if err != nil { - return err - } - - defer self.storage.zone.region.AttachDisk(self.Zone, self.UHostID, self.UDiskID) - err = cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 10*time.Second, 5*time.Second, 60*time.Second) - if err != nil { - return errors.Wrap(err, "DiskResize") - } - - } - return self.storage.zone.region.resizeDisk(self.Zone, self.GetId(), sizeGB) -} - -func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - err := self.storage.zone.region.resetDisk(self.Zone, self.GetId(), snapshotId) - if err != nil { - return "", err - } - - return self.GetId(), nil -} - -func (self *SDisk) Rebuild(ctx context.Context) error { - return self.storage.zone.region.resetDisk(self.Zone, self.GetId(), "") -} - -func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { - if len(diskId) == 0 { - return nil, fmt.Errorf("GetDisk id should not empty") - } - - disks, err := self.GetDisks("", "", []string{diskId}) - if err != nil { - return nil, err - } - - if len(disks) == 1 { - return &disks[0], nil - } else if len(disks) == 0 { - return nil, cloudprovider.ErrNotFound - } else { - return nil, fmt.Errorf("GetDisk %s %d found", diskId, len(disks)) - } -} - -// https://docs.ucloud.cn/api/udisk-api/describe_udisk -// diskType DataDisk|SystemDisk (DataDisk表示数据盘,SystemDisk表示系统盘) -func (self *SRegion) GetDisks(zoneId string, diskType string, diskIds []string) ([]SDisk, error) { - disks := make([]SDisk, 0) - params := NewUcloudParams() - if len(zoneId) > 0 { - params.Set("Zone", zoneId) - } - - if len(diskType) > 0 { - params.Set("DiskType", diskType) - } - - err := self.DoListAll("DescribeUDisk", params, &disks) - if err != nil { - return nil, err - } - - if len(diskIds) > 0 { - filtedDisks := make([]SDisk, 0) - for i := range disks { - if utils.IsInStringArray(disks[i].UDiskID, diskIds) { - filtedDisks = append(filtedDisks, disks[i]) - } - } - - return filtedDisks, nil - } - - return disks, nil -} - -// https://docs.ucloud.cn/api/udisk-api/delete_udisk -func (self *SRegion) DeleteDisk(zoneId string, diskId string) error { - params := NewUcloudParams() - params.Set("Zone", zoneId) - params.Set("UDiskId", diskId) - - return self.DoAction("DeleteUDisk", params, nil) -} - -// https://docs.ucloud.cn/api/udisk-api/create_udisk -func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int) (string, error) { - params := NewUcloudParams() - params.Set("Zone", zoneId) - params.Set("Size", sizeGb) - params.Set("Name", name) - params.Set("DiskType", category) - - diskIds := make([]string, 0) - err := self.DoAction("CreateUDisk", params, &diskIds) - if err != nil { - return "", err - } - - if len(diskIds) == 0 { - return "", fmt.Errorf("CreateDisk with empty response") - } - - return diskIds[0], nil -} - -// https://docs.ucloud.cn/api/udisk-api/create_udisk_snapshot -func (self *SRegion) CreateSnapshot(zoneId, diskId, name, desc string) (string, error) { - params := NewUcloudParams() - params.Set("Zone", zoneId) - params.Set("UDiskId", diskId) - params.Set("Name", name) - params.Set("Comment", desc) - - snapshotIds := make([]string, 0) - err := self.DoAction("CreateUDiskSnapshot", params, &snapshotIds) - if err != nil { - return "", err - } - - if len(snapshotIds) == 0 { - return "", fmt.Errorf("CreateSnapshot with empty response") - } - - return snapshotIds[0], nil -} - -// https://docs.ucloud.cn/api/udisk-api/resize_udisk -func (self *SRegion) resizeDisk(zoneId string, diskId string, sizeGB int64) error { - params := NewUcloudParams() - params.Set("Zone", zoneId) - params.Set("Size", sizeGB) - params.Set("UDiskId", diskId) - - return self.DoAction("ResizeUDisk", params, nil) -} - -// https://docs.ucloud.cn/api/udisk-api/restore_u_disk -func (self *SRegion) resetDisk(zoneId, diskId, snapshotId string) error { - params := NewUcloudParams() - params.Set("Zone", zoneId) - params.Set("UDiskId", diskId) - if len(snapshotId) > 0 { - params.Set("SnapshotId", snapshotId) - } - - return self.DoAction("RestoreUDisk", params, nil) -} - -// https://docs.ucloud.cn/api/udisk-api/attach_udisk -func (self *SRegion) AttachDisk(zoneId string, instanceId string, diskId string) error { - params := NewUcloudParams() - params.Set("Zone", zoneId) - params.Set("UHostId", instanceId) - params.Set("UDiskId", diskId) - - return self.DoAction("AttachUDisk", params, nil) -} - -// https://docs.ucloud.cn/api/udisk-api/detach_udisk -func (self *SRegion) DetachDisk(zoneId string, instanceId string, diskId string) error { - idisks, err := self.GetDisk(diskId) - if err != nil { - return err - } - - if idisks.Status == "Available" { - return nil - } - - params := NewUcloudParams() - params.Set("Zone", zoneId) - params.Set("UHostId", instanceId) - params.Set("UDiskId", diskId) - - return self.DoAction("DetachUDisk", params, nil) -} diff --git a/pkg/multicloud/ucloud/doc.go b/pkg/multicloud/ucloud/doc.go deleted file mode 100644 index d085c2dc6e..0000000000 --- a/pkg/multicloud/ucloud/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud // import "yunion.io/x/onecloud/pkg/multicloud/ucloud" diff --git a/pkg/multicloud/ucloud/eip.go b/pkg/multicloud/ucloud/eip.go deleted file mode 100644 index ba7cc80ce5..0000000000 --- a/pkg/multicloud/ucloud/eip.go +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -const ( - EIP_CHARGE_TYPE_BY_TRAFFIC = "traffic" - EIP_CHARGE_TYPE_BY_BANDWIDTH = "bandwidth" -) - -// https://docs.ucloud.cn/api/unet-api/describe_eip -type SEip struct { - region *SRegion - multicloud.SEipBase - multicloud.UcloudTags - - BandwidthMb int `json:"Bandwidth"` - BandwidthType int `json:"BandwidthType"` - ChargeType string `json:"ChargeType"` - CreateTime int64 `json:"CreateTime"` - EIPAddr []EIPAddr `json:"EIPAddr"` - EIPID string `json:"EIPId"` - Expire bool `json:"Expire"` - ExpireTime int64 `json:"ExpireTime"` - Name string `json:"Name"` - PayMode string `json:"PayMode"` - Remark string `json:"Remark"` - Resource Resource `json:"Resource"` - ShareBandwidthSet ShareBandwidthSet `json:"ShareBandwidthSet"` - Status string `json:"Status"` - Tag string `json:"Tag"` - Weight int `json:"Weight"` -} - -func (self *SEip) GetProjectId() string { - return self.region.client.projectId -} - -type EIPAddr struct { - IP string `json:"IP"` - OperatorName string `json:"OperatorName"` -} - -type Resource struct { - ResourceID string `json:"ResourceID"` - ResourceName string `json:"ResourceName"` - ResourceType string `json:"ResourceType"` - Zone string `json:"Zone"` -} - -type ShareBandwidthSet struct { - ShareBandwidth int `json:"ShareBandwidth"` - ShareBandwidthID string `json:"ShareBandwidthId"` - ShareBandwidthName string `json:"ShareBandwidthName"` -} - -func (self *SEip) GetId() string { - return self.EIPID -} - -func (self *SEip) GetName() string { - if len(self.Name) == 0 { - return self.GetId() - } - - return self.Name -} - -func (self *SEip) GetGlobalId() string { - return self.GetId() -} - -// 弹性IP的资源绑定状态, 枚举值为: used: 已绑定, free: 未绑定, freeze: 已冻结 -func (self *SEip) GetStatus() string { - switch self.Status { - case "used": - return api.EIP_STATUS_ASSOCIATE // ? - case "free": - return api.EIP_STATUS_READY - case "freeze": - return api.EIP_STATUS_UNKNOWN - default: - return api.EIP_STATUS_UNKNOWN - } -} - -func (self *SEip) Refresh() error { - if self.IsEmulated() { - return nil - } - new, err := self.region.GetEipById(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SEip) IsEmulated() bool { - return false -} - -// 付费方式, 枚举值为: Year, 按年付费; Month, 按月付费; Dynamic, 按小时付费; Trial, 试用. 按小时付费和试用这两种付费模式需要开通权限. -func (self *SEip) GetBillingType() string { - switch self.ChargeType { - case "Year", "Month": - return billing_api.BILLING_TYPE_PREPAID - default: - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SEip) GetCreatedAt() time.Time { - return time.Unix(self.CreateTime, 0) -} - -func (self *SEip) GetExpiredAt() time.Time { - return time.Unix(self.ExpireTime, 0) -} - -func (self *SEip) GetIpAddr() string { - if len(self.EIPAddr) > 1 { - log.Warningf("GetIpAddr %d eip addr found", len(self.EIPAddr)) - } else if len(self.EIPAddr) == 0 { - return "" - } - - return self.EIPAddr[0].IP -} - -func (self *SEip) GetMode() string { - return api.EIP_MODE_STANDALONE_EIP -} - -func (self *SEip) GetAssociationType() string { - switch self.Resource.ResourceType { - case "uhost": - return api.EIP_ASSOCIATE_TYPE_SERVER - case "natgw": - return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY - case "ulb": - return api.EIP_ASSOCIATE_TYPE_LOADBALANCER - default: - return self.Resource.ResourceType - } -} - -// 已绑定的资源类型, 枚举值为: uhost, 云主机;natgw:NAT网关;ulb:负载均衡器;upm: 物理机; hadoophost: 大数据集群;fortresshost:堡垒机;udockhost:容器;udhost:私有专区主机;vpngw:IPSec VPN;ucdr:云灾备;dbaudit:数据库审计。 -func (self *SEip) GetAssociationExternalId() string { - return self.Resource.ResourceID -} - -func (self *SEip) GetBandwidth() int { - return self.BandwidthMb -} - -func (self *SEip) GetINetworkId() string { - return "" -} - -// 弹性IP的计费模式, 枚举值为: "Bandwidth", 带宽计费; "Traffic", 流量计费; "ShareBandwidth",共享带宽模式. 默认为 "Bandwidth". -func (self *SEip) GetInternetChargeType() string { - switch self.PayMode { - case "Bandwidth": - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH - case "Traffic": - return api.EIP_CHARGE_TYPE_BY_TRAFFIC - default: - return api.EIP_CHARGE_TYPE_BY_BANDWIDTH - } -} - -func (self *SEip) Delete() error { - return self.region.DeallocateEIP(self.GetId()) -} - -func (self *SEip) Associate(conf *cloudprovider.AssociateConfig) error { - return self.region.AssociateEip(self.GetId(), conf.InstanceId) -} - -func (self *SEip) Dissociate() error { - return self.region.DissociateEip(self.GetId(), self.Resource.ResourceID) -} - -func (self *SEip) ChangeBandwidth(bw int) error { - return self.region.UpdateEipBandwidth(self.GetId(), bw) -} - -// https://docs.ucloud.cn/api/unet-api/allocate_eip -// 增加共享带宽模式ShareBandwidth -func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - if len(eip.BGPType) == 0 { - if strings.HasPrefix(self.GetId(), "cn-") { - eip.BGPType = "Bgp" - } else { - eip.BGPType = "International" - } - } - - params := NewUcloudParams() - params.Set("OperatorName", eip.BGPType) - params.Set("Bandwidth", eip.BandwidthMbps) - params.Set("Name", eip.Name) - var payMode string - switch eip.ChargeType { - case api.EIP_CHARGE_TYPE_BY_TRAFFIC: - payMode = "Traffic" - case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: - payMode = "Bandwidth" - } - params.Set("PayMode", payMode) - params.Set("ChargeType", "Dynamic") // 按需付费 - - eips := make([]SEip, 0) - err := self.DoAction("AllocateEIP", params, &eips) - if err != nil { - return nil, err - } - - if len(eips) == 1 { - eip := eips[0] - eip.region = self - eip.Refresh() - return &eip, nil - } else { - return nil, fmt.Errorf("CreateEIP %d eip created", len(eips)) - } -} - -// https://docs.ucloud.cn/api/unet-api/release_eip -func (self *SRegion) DeallocateEIP(eipId string) error { - params := NewUcloudParams() - params.Set("EIPId", eipId) - - return self.DoAction("ReleaseEIP", params, nil) -} - -// https://docs.ucloud.cn/api/unet-api/bind_eip -func (self *SRegion) AssociateEip(eipId string, instanceId string) error { - params := NewUcloudParams() - params.Set("EIPId", eipId) - params.Set("ResourceType", "uhost") - params.Set("ResourceId", instanceId) - - return self.DoAction("BindEIP", params, nil) -} - -// https://docs.ucloud.cn/api/unet-api/unbind_eip -func (self *SRegion) DissociateEip(eipId string, instanceId string) error { - params := NewUcloudParams() - params.Set("EIPId", eipId) - params.Set("ResourceType", "uhost") - params.Set("ResourceId", instanceId) - - return self.DoAction("UnBindEIP", params, nil) -} - -// https://docs.ucloud.cn/api/unet-api/modify_eip_bandwidth -func (self *SRegion) UpdateEipBandwidth(eipId string, bw int) error { - params := NewUcloudParams() - params.Set("EIPId", eipId) - params.Set("Bandwidth", bw) - - return self.DoAction("ModifyEIPBandwidth", params, nil) -} diff --git a/pkg/multicloud/ucloud/host.go b/pkg/multicloud/ucloud/host.go deleted file mode 100644 index 02981c72ee..0000000000 --- a/pkg/multicloud/ucloud/host.go +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "encoding/base64" - "fmt" - "strconv" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone - - projectId string -} - -func (self *SHost) GetId() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) -} - -func (self *SHost) GetName() string { - return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) -} - -func (self *SHost) GetGlobalId() string { - return self.GetId() -} - -func (self *SHost) GetStatus() string { - return api.HOST_STATUS_RUNNING -} - -func (self *SHost) Refresh() error { - return nil -} - -func (self *SHost) IsEmulated() bool { - return true -} - -func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - vms, err := self.zone.GetInstances() - 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(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.zone.region.GetInstanceByID(id) - if err != nil { - return nil, err - } - - vm.host = self - return &vm, 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 api.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_UCLOUD), "manufacture") - return info -} - -func (self *SHost) GetSN() string { - return "" -} - -func (self *SHost) GetCpuCount() int { - 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 api.DISK_TYPE_HYBRID -} - -func (self *SHost) GetHostType() string { - return api.HOST_TYPE_UCLOUD -} - -func (self *SHost) GetIsMaintenance() bool { - return false -} - -func (self *SHost) GetVersion() string { - return UCLOUD_API_VERSION -} - -// 不支持user data -// 不支持指定keypair -func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, desc.ExternalSecgroupId, desc.BillingCycle) - if err != nil { - return nil, err - } - - vm, err := self.zone.region.GetInstanceByID(vmId) - if err != nil { - return nil, err - } - - vm.host = self - return &vm, err -} - -func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -type SInstanceType struct { - UHostType string - CPU int - MemoryMB int - GPU int -} - -func ParseInstanceType(instanceType string) (SInstanceType, error) { - i := SInstanceType{} - segs := strings.Split(instanceType, ".") - if len(segs) < 3 { - return i, fmt.Errorf("invalid instance type %s", instanceType) - } else if len(segs) >= 4 { - gpu, err := strconv.Atoi(strings.TrimLeft(segs[3], "g")) - if err != nil { - return i, err - } - - i.GPU = gpu - } - - cpu, err := strconv.Atoi(strings.TrimLeft(segs[1], "c")) - if err != nil { - return i, err - } - - mem, err := strconv.Atoi(strings.TrimLeft(segs[2], "m")) - if err != nil { - return i, err - } - - i.UHostType = segs[0] - i.CPU = cpu - i.MemoryMB = mem * 1024 - return i, nil -} - -func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo, cpu, memMB int, instanceType string, - networkId, ipAddr, desc, passwd string, - dataDisks []cloudprovider.SDiskInfo, secgroupId string, bc *billing.SBillingCycle) (string, error) { - // 网络配置及安全组绑定 - net, _ := self.zone.region.getNetwork(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 { - return "", fmt.Errorf("CreateVM no secgroupId specified") - } - - if len(passwd) == 0 { - return "", fmt.Errorf("CreateVM password should not be emtpty") - } - - // 镜像及硬盘配置 - img, err := self.zone.region.GetImage(imgId) - if err != nil { - log.Errorf("GetImage %s fail %s", imgId, err) - return "", err - } - if img.GetStatus() != api.CACHED_IMAGE_STATUS_ACTIVE { - log.Errorf("image %s status %s, expect %s", imgId, img.GetStatus(), api.CACHED_IMAGE_STATUS_ACTIVE) - return "", fmt.Errorf("image not ready") - } - - disks := make([]SDisk, len(dataDisks)+1) - disks[0].SizeGB = int(img.ImageSizeGB) - if sysDisk.SizeGB > 0 && sysDisk.SizeGB > int(img.ImageSizeGB) { - disks[0].SizeGB = sysDisk.SizeGB - } - disks[0].DiskType = sysDisk.StorageType - - for i, dataDisk := range dataDisks { - disks[i+1].SizeGB = dataDisk.SizeGB - disks[i+1].DiskType = dataDisk.StorageType - } - - // 创建实例 - // https://docs.ucloud.cn/api/uhost-api/uhost_type - // https://docs.ucloud.cn/compute/uhost/introduction/uhost/type - var vmId string - i, err := ParseInstanceType(instanceType) - if err != nil { - if cpu <= 0 || memMB <= 0 { - return "", err - } else { - i.UHostType = "N2" - i.CPU = cpu - i.MemoryMB = memMB - } - } - - vmId, err = self.zone.region.CreateInstance(name, imgId, i.UHostType, passwd, net.wire.vpc.GetId(), networkId, secgroupId, self.zone.ZoneId, desc, ipAddr, i.CPU, i.MemoryMB, i.GPU, disks, bc) - if err != nil { - return "", fmt.Errorf("Failed to create: %v", err) - } - - return vmId, nil -} - -// https://docs.ucloud.cn/api/uhost-api/create_uhost_instance -// https://docs.ucloud.cn/api/uhost-api/specification -// 支持8-30位字符, 不能包含[A-Z],[a-z],[0-9]和[()`~!@#$%^&*-+=_|{}[]:;'<>,.?/]之外的非法字符 -func (self *SRegion) CreateInstance(name, imageId, hostType, password, vpcId, SubnetId, securityGroupId, - zoneId, desc, ipAddr string, cpu, memMB, gpu int, disks []SDisk, bc *billing.SBillingCycle) (string, error) { - params := NewUcloudParams() - params.Set("Zone", zoneId) - params.Set("ImageId", imageId) - params.Set("Password", base64.StdEncoding.EncodeToString([]byte(password))) - params.Set("LoginMode", "Password") - params.Set("Name", name) - params.Set("UHostType", hostType) - params.Set("CPU", cpu) - params.Set("Memory", memMB) - params.Set("VPCId", vpcId) - params.Set("SubnetId", SubnetId) - params.Set("SecurityGroupId", securityGroupId) - if gpu > 0 { - params.Set("GPU", gpu) - } - - if bc != nil && bc.GetMonths() >= 1 && bc.GetMonths() < 10 { - params.Set("ChargeType", "Month") - params.Set("Quantity", bc.GetMonths()) - } else if bc != nil && bc.GetMonths() >= 10 && bc.GetMonths() < 12 { - params.Set("ChargeType", "Year") - params.Set("Quantity", 1) - } else if bc != nil && bc.GetYears() >= 1 { - params.Set("ChargeType", "Year") - params.Set("Quantity", bc.GetYears()) - } else { - params.Set("ChargeType", "Dynamic") - } - - // boot disk - params.Set("Disks.0.IsBoot", "True") - params.Set("Disks.0.Type", disks[0].DiskType) - params.Set("Disks.0.Size", disks[0].SizeGB) - - // data disk - for i, disk := range disks[1:] { - N := i + 1 - params.Set(fmt.Sprintf("Disks.%d.IsBoot", N), "False") - params.Set(fmt.Sprintf("Disks.%d.Type", N), disk.DiskType) - params.Set(fmt.Sprintf("Disks.%d.Size", N), disk.SizeGB) - } - - type Ret struct { - UHostIds []string - } - - ret := Ret{} - err := self.DoAction("CreateUHostInstance", params, &ret) - if err != nil { - return "", err - } - - if len(ret.UHostIds) == 1 { - return ret.UHostIds[0], nil - } - - return "", fmt.Errorf("CreateInstance %d instance created. %s", len(ret.UHostIds), ret.UHostIds) -} diff --git a/pkg/multicloud/ucloud/image.go b/pkg/multicloud/ucloud/image.go deleted file mode 100644 index e32f1adb01..0000000000 --- a/pkg/multicloud/ucloud/image.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type SImage struct { - multicloud.SImageBase - multicloud.UcloudTags - storageCache *SStoragecache - - // normalized image info - imgInfo *imagetools.ImageInfo - - Zone string `json:"Zone"` - ImageDescription string `json:"ImageDescription"` - OSName string `json:"OsName"` - ImageID string `json:"ImageId"` - State string `json:"State"` - ImageName string `json:"ImageName"` - OSType string `json:"OsType"` - CreateTime int64 `json:"CreateTime"` - ImageType string `json:"ImageType"` - ImageSizeGB int64 `json:"ImageSize"` -} - -func (self *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (self *SImage) GetId() string { - return self.ImageID -} - -func (self *SImage) GetName() string { - if len(self.ImageName) == 0 { - return self.GetId() - } - - return self.ImageName -} - -func (self *SImage) GetGlobalId() string { - return self.GetId() -} - -// 镜像状态, 可用:Available,制作中:Making, 不可用:Unavailable -func (self *SImage) GetStatus() string { - switch self.State { - case "Available": - return api.CACHED_IMAGE_STATUS_ACTIVE - case "Making": - return api.CACHED_IMAGE_STATUS_CACHING - case "Unavailable": - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - default: - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (self *SImage) Refresh() error { - new, err := self.storageCache.region.GetImage(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SImage) IsEmulated() bool { - return false -} - -func (self *SImage) Delete(ctx context.Context) error { - return self.storageCache.region.DeleteImage(self.GetId()) -} - -func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return self.storageCache -} - -func (self *SImage) GetSizeByte() int64 { - return self.ImageSizeGB * 1024 * 1024 * 1024 -} - -// 镜像类型。标准镜像:Base,镜像市场:Business, 自定义镜像:Custom,默认返回所有类型 -func (self *SImage) GetImageType() cloudprovider.TImageType { - switch self.ImageType { - case "Base": - return cloudprovider.ImageTypeSystem - case "Custom": - return cloudprovider.ImageTypeCustomized - case "Business": - return cloudprovider.ImageTypeShared - default: - return cloudprovider.ImageTypeCustomized - } -} - -func (self *SImage) GetImageStatus() string { - switch self.State { - case "Available": - return cloudprovider.IMAGE_STATUS_ACTIVE - case "Making": - return cloudprovider.IMAGE_STATUS_QUEUED - case "Unavailable": - return cloudprovider.IMAGE_STATUS_KILLED - default: - return cloudprovider.IMAGE_STATUS_KILLED - } -} - -func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if self.imgInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(self.ImageName, "", "", "", "") - self.imgInfo = &imgInfo - } - - return self.imgInfo -} - -func (self *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) -} - -func (self *SImage) GetOsDist() string { - return self.getNormalizedImageInfo().OsDistro -} - -func (self *SImage) GetOsVersion() string { - return self.getNormalizedImageInfo().OsVersion -} - -func (self *SImage) GetOsArch() string { - return self.getNormalizedImageInfo().OsArch -} - -func (img *SImage) GetOsLang() string { - return img.getNormalizedImageInfo().OsLang -} - -func (img *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(img.getNormalizedImageInfo().OsBios) -} - -func (img *SImage) GetFullOsName() string { - return img.ImageName -} - -func (self *SImage) GetMinOsDiskSizeGb() int { - return int(self.ImageSizeGB) -} - -func (self *SImage) GetImageFormat() string { - return "" -} - -func (self *SImage) GetCreatedAt() time.Time { - return time.Unix(self.CreateTime, 0) -} - -// https://docs.ucloud.cn/api/uhost-api/describe_image -func (self *SRegion) GetImage(imageId string) (SImage, error) { - params := NewUcloudParams() - params.Set("ImageId", imageId) - - images := make([]SImage, 0) - err := self.DoListAll("DescribeImage", params, &images) - if err != nil { - return SImage{}, err - } - - if len(images) == 1 { - return images[0], nil - } else if len(images) == 0 { - return SImage{}, cloudprovider.ErrNotFound - } else { - return SImage{}, fmt.Errorf("GetImage %s %d found.", imageId, len(images)) - } -} - -// https://docs.ucloud.cn/api/uhost-api/describe_image -// ImageType 标准镜像:Base,镜像市场:Business, 自定义镜像:Custom,默认返回所有类型 -func (self *SRegion) GetImages(imageType string, imageId string) ([]SImage, error) { - params := NewUcloudParams() - - if len(imageId) > 0 { - params.Set("ImageId", imageId) - } - - if len(imageType) > 0 { - params.Set("ImageType", imageType) - } - - images := make([]SImage, 0) - err := self.DoListAll("DescribeImage", params, &images) - return images, err -} - -// https://docs.ucloud.cn/api/uhost-api/terminate_custom_image -func (self *SRegion) DeleteImage(imageId string) error { - params := NewUcloudParams() - params.Set("ImageId", imageId) - - return self.DoAction("TerminateCustomImage", params, nil) -} diff --git a/pkg/multicloud/ucloud/instance.go b/pkg/multicloud/ucloud/instance.go deleted file mode 100644 index 30ebdf5e38..0000000000 --- a/pkg/multicloud/ucloud/instance.go +++ /dev/null @@ -1,705 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "context" - "encoding/base64" - "fmt" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/imagetools" -) - -type SInstance struct { - multicloud.SInstanceBase - multicloud.UcloudTags - - host *SHost - - osInfo *imagetools.ImageInfo - - UHostID string `json:"UHostId"` - Zone string `json:"Zone"` - LifeCycle string `json:"LifeCycle"` - OSName string `json:"OsName"` - ImageID string `json:"ImageId"` - BasicImageID string `json:"BasicImageId"` - BasicImageName string `json:"BasicImageName"` - Tag string `json:"Tag"` - Name string `json:"Name"` - Remark string `json:"Remark"` - State string `json:"State"` - NetworkState string `json:"NetworkState"` - HostType string `json:"HostType"` - StorageType string `json:"StorageType"` - TotalDiskSpace int `json:"TotalDiskSpace"` - DiskSet []DiskSet `json:"DiskSet"` - NetCapability string `json:"NetCapability"` - IPSet []IPSet `json:"IPSet"` - SubnetType string `json:"SubnetType"` - ChargeType string `json:"ChargeType"` - ExpireTime int64 `json:"ExpireTime"` - AutoRenew string `json:"AutoRenew"` - IsExpire string `json:"IsExpire"` - UHostType string `json:"UHostType"` - OSType string `json:"OsType"` - CreateTime int64 `json:"CreateTime"` - CPU int `json:"CPU"` - GPU int `json:"GPU"` - MemoryMB int `json:"Memory"` - TimemachineFeature string `json:"TimemachineFeature"` - HotplugFeature bool `json:"HotplugFeature"` - NetCapFeature bool `json:"NetCapFeature"` - BootDiskState string `json:"BootDiskState"` -} - -func (self *SInstance) GetSecurityGroupIds() ([]string, error) { - secgroups, err := self.GetSecurityGroups() - if err != nil { - log.Errorln(err) - } - - secgroupIds := make([]string, 0) - for _, secgroup := range secgroups { - secgroupIds = append(secgroupIds, secgroup.GetId()) - } - - return secgroupIds, nil -} - -func (self *SInstance) GetProjectId() string { - return self.host.zone.region.client.projectId -} - -func (self *SInstance) GetError() error { - return nil -} - -type DiskSet struct { - DiskID string `json:"DiskId"` - DiskType string `json:"DiskType"` - Drive string `json:"Drive"` - IsBoot bool `json:"IsBoot"` - Size int `json:"Size"` - Encrypted string `json:"Encrypted"` - Type string `json:"Type"` -} - -type IPSet struct { - Type string `json:"Type"` - IP string `json:"IP"` - IPId string `json:"IPId"` // IP资源ID (内网IP无对应的资源ID) - MAC string `json:"Mac"` - VPCID string `json:"VPCId"` - SubnetID string `json:"SubnetId"` -} - -type SVncInfo struct { - VNCIP string `json:"VncIP"` - VNCPassword string `json:"VncPassword"` - UHostID string `json:"UHostId"` - Action string `json:"Action"` - VNCPort int64 `json:"VncPort"` -} - -func (self *SInstance) GetId() string { - return self.UHostID -} - -func (self *SInstance) GetName() string { - if len(self.Name) == 0 { - return self.GetId() - } - return self.Name -} - -func (self *SInstance) GetHostname() string { - return self.GetName() -} - -func (self *SInstance) GetGlobalId() string { - return self.GetId() -} - -// 实例状态,枚举值: -// >初始化: Initializing; -// >启动中: Starting; -// > 运行中: Running; -// > 关机中: Stopping; -// >关机: Stopped -// >安装失败: Install Fail; -// >重启中: Rebooting -func (self *SInstance) GetStatus() string { - switch self.State { - case "Running": - return api.VM_RUNNING - case "Stopped": - return api.VM_READY - case "Rebooting": - return api.VM_STOPPING - case "Initializing": - return api.VM_INIT - case "Starting": - return api.VM_STARTING - case "Stopping": - return api.VM_STOPPING - case "Install Fail": - return api.VM_CREATE_FAILED - default: - return api.VM_UNKNOWN - } -} - -func (self *SInstance) Refresh() error { - new, err := self.host.zone.region.GetInstanceByID(self.GetId()) - if err != nil { - return err - } - - new.host = self.host - return jsonutils.Update(self, new) -} - -func (self *SInstance) IsEmulated() bool { - return false -} - -func (self *SInstance) GetSysTags() map[string]string { - data := map[string]string{} - // todo: add price key here - data["zone_ext_id"] = self.host.zone.GetGlobalId() - if len(self.BasicImageID) > 0 { - if image, err := self.host.zone.region.GetImage(self.BasicImageID); err != nil { - log.Errorf("Failed to find image %s for instance %s", self.BasicImageID, self.GetName()) - } else { - meta := image.GetSysTags() - for k, v := range meta { - data[k] = v - } - } - } - - return data -} - -// 计费模式,枚举值为: Year,按年付费; Month,按月付费; Dynamic,按需付费(需开启权限); -func (self *SInstance) GetBillingType() string { - switch self.ChargeType { - case "Year", "Month": - return billing_api.BILLING_TYPE_PREPAID - default: - return billing_api.BILLING_TYPE_POSTPAID - } -} - -func (self *SInstance) GetCreatedAt() time.Time { - return time.Unix(self.CreateTime, 0) -} - -func (self *SInstance) GetExpiredAt() time.Time { - if self.AutoRenew != "Yes" { - return time.Unix(self.ExpireTime, 0) - } - - return time.Time{} -} - -func (self *SInstance) GetIHost() cloudprovider.ICloudHost { - return self.host -} - -func (self *SInstance) GetLocalDisk(diskId, storageType string, sizeGB int, isBoot bool) SDisk { - diskType := "" - if isBoot { - diskType = "SystemDisk" - } - - disk := SDisk{ - SDisk: multicloud.SDisk{}, - Status: "Available", - UHostID: self.GetId(), - Name: diskId, - Zone: self.host.zone.GetId(), - DiskType: diskType, - UDiskID: diskId, - UHostName: self.GetName(), - CreateTime: self.CreateTime, - SizeGB: sizeGB, - } - - disk.storage = &SStorage{zone: self.host.zone, storageType: storageType} - return disk -} - -func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - localDisks := make([]SDisk, 0) - diskIds := make([]string, 0) - for _, disk := range self.DiskSet { - if utils.IsInStringArray(disk.DiskType, []string{api.STORAGE_UCLOUD_LOCAL_NORMAL, api.STORAGE_UCLOUD_LOCAL_SSD}) { - localDisks = append(localDisks, self.GetLocalDisk(disk.DiskID, disk.DiskType, disk.Size, disk.IsBoot)) - } else { - diskIds = append(diskIds, disk.DiskID) - } - } - - disks := []SDisk{} - var err error - if len(diskIds) > 0 { - disks, err = self.host.zone.region.GetDisks("", "", diskIds) - if err != nil { - return nil, err - } - } - - disks = append(disks, localDisks...) - idisks := make([]cloudprovider.ICloudDisk, len(disks)) - for i := 0; i < len(disks); i += 1 { - if disks[i].storage == nil { - var category string - if strings.Contains(disks[i].DiskType, "SSD") { - category = api.STORAGE_UCLOUD_CLOUD_SSD - } else { - category = api.STORAGE_UCLOUD_CLOUD_NORMAL - } - storage, err := self.host.zone.getStorageByCategory(category) - if err != nil { - return nil, err - } - disks[i].storage = storage - } - idisks[i] = &disks[i] - // 将系统盘放到第0个位置 - if disks[i].GetDiskType() == api.DISK_TYPE_SYS { - idisks[0], idisks[i] = idisks[i], idisks[0] - } - } - - return idisks, nil -} - -func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - nics := make([]cloudprovider.ICloudNic, 0) - - for _, ip := range self.IPSet { - if len(ip.SubnetID) == 0 { - continue - } - - nic := SInstanceNic{ - instance: self, - ipAddr: ip.IP, - macAddr: ip.MAC, - } - nics = append(nics, &nic) - } - - return nics, nil -} - -// 国际: Internation,BGP: BGP,内网: Private -func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - for _, ip := range self.IPSet { - if len(ip.IPId) > 0 { - eip, err := self.host.zone.region.GetEipById(ip.IPId) - if err != nil { - return nil, err - } - - return &eip, nil - } - } - - return nil, nil -} - -func (self *SInstance) GetVcpuCount() int { - return self.CPU -} - -func (self *SInstance) GetVmemSizeMB() int { - return self.MemoryMB -} - -func (self *SInstance) GetBootOrder() string { - return "dcn" -} - -func (self *SInstance) GetVga() string { - return "std" -} - -func (self *SInstance) GetVdi() string { - return "vnc" -} - -func (ins *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { - if ins.osInfo == nil { - osInfo := imagetools.NormalizeImageInfo(ins.OSName, "", ins.OSType, "", "") - ins.osInfo = &osInfo - } - return ins.osInfo -} - -func (ins *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(ins.getNormalizedOsInfo().OsType) -} - -func (ins *SInstance) GetFullOsName() string { - return ins.OSName -} - -func (ins *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(ins.getNormalizedOsInfo().OsBios) -} - -func (ins *SInstance) GetOsArch() string { - return ins.getNormalizedOsInfo().OsArch -} - -func (ins *SInstance) GetOsDist() string { - return ins.getNormalizedOsInfo().OsDistro -} - -func (ins *SInstance) GetOsVersion() string { - return ins.getNormalizedOsInfo().OsVersion -} - -func (ins *SInstance) GetOsLang() string { - return ins.getNormalizedOsInfo().OsLang -} - -func (self *SInstance) GetMachine() string { - return "pc" -} - -func (self *SInstance) GetInstanceType() string { - // C1.c8.m24 - if strings.HasPrefix(self.HostType, "G") { - return fmt.Sprintf("%s.c%d.m%d.g%d", self.HostType, self.CPU, self.MemoryMB/1014, self.GPU) - } else { - return fmt.Sprintf("%s.c%d.m%d", self.HostType, self.CPU, self.MemoryMB/1014) - } -} - -func (self *SInstance) AssignSecurityGroup(secgroupId string) error { - return self.host.zone.region.assignSecurityGroups(self.GetId(), secgroupId) -} - -// https://docs.ucloud.cn/api/unet-api/grant_firewall -func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { - if len(secgroupIds) == 0 { - return fmt.Errorf("SetSecurityGroups secgroup id should not be empty") - } else if len(secgroupIds) > 1 { - return fmt.Errorf("SetSecurityGroups only allowed to assign one secgroup id. %d given", len(secgroupIds)) - } - - return self.host.zone.region.assignSecurityGroups(self.GetId(), secgroupIds[0]) -} - -func (self *SInstance) GetHypervisor() string { - return api.HYPERVISOR_UCLOUD -} - -func (self *SInstance) StartVM(ctx context.Context) error { - err := self.host.zone.region.StartVM(self.GetId()) - if err != nil { - return err - } - err = cloudprovider.WaitStatusWithDelay(self, api.VM_RUNNING, 10*time.Second, 10*time.Second, 600*time.Second) - if err != nil { - return errors.Wrap(err, "StartVM") - } - - return nil -} - -func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - err := self.host.zone.region.StopVM(self.GetId()) - if err != nil { - return err - } - err = cloudprovider.WaitStatusWithDelay(self, api.VM_READY, 10*time.Second, 10*time.Second, 600*time.Second) - if err != nil { - return errors.Wrap(err, "StopVM") - } - - return nil -} - -func (self *SInstance) DeleteVM(ctx context.Context) error { - return self.host.zone.region.DeleteVM(self.GetId()) -} - -func (self *SInstance) UpdateVM(ctx context.Context, name string) error { - return self.host.zone.region.UpdateVM(self.GetId(), name) -} - -func (self *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -// https://docs.ucloud.cn/api/uhost-api/reinstall_uhost_instance -// 1.请确认在重新安装之前,该实例已被关闭; -// 2.请确认该实例未挂载UDisk; -// todo:// 3.将原系统重装为不同类型的系统时(Linux->Windows),不可选择保留数据盘; -// 4.重装不同版本的系统时(CentOS6->CentOS7),若选择保留数据盘,请注意数据盘的文件系统格式; -// 5.若主机CPU低于2核,不可重装为Windows系统。 -func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - if len(desc.PublicKey) > 0 { - return "", fmt.Errorf("DeployVM not support assign ssh keypair") - } - - if self.GetStatus() != api.VM_READY { - return "", fmt.Errorf("DeployVM instance status %s , expected %s.", self.GetStatus(), api.VM_READY) - } - - if len(self.DiskSet) > 1 { - for _, disk := range self.DiskSet { - if disk.Type == "Data" { - err := self.host.zone.region.DetachDisk(self.host.zone.GetId(), self.GetId(), disk.DiskID) - if err != nil { - return "", fmt.Errorf("RebuildRoot detach disk %s", err) - } - - defer self.host.zone.region.AttachDisk(self.host.zone.GetId(), self.GetId(), disk.DiskID) - } - - } - } - - err := self.host.zone.region.RebuildRoot(self.GetId(), desc.ImageId, desc.Password) - if err != nil { - return "", err - } - - err = cloudprovider.WaitStatusWithDelay(self, api.VM_RUNNING, 10*time.Second, 15*time.Second, 300*time.Second) - if err != nil { - return "", errors.Wrap(err, "RebuildRoot") - } - - disks, err := self.GetIDisks() - if len(disks) > 0 { - return disks[0].GetId(), nil - } else { - return "", fmt.Errorf("RebuildRoot %s", err) - } -} - -func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - if len(publicKey) > 0 { - return fmt.Errorf("DeployVM not support assign ssh keypair") - } - - if deleteKeypair { - return fmt.Errorf("DeployVM not support delete ssh keypair") - } - - if self.GetStatus() != api.VM_READY { - return fmt.Errorf("DeployVM instance status %s , expected %s.", self.GetStatus(), api.VM_READY) - } - - if len(password) > 0 { - err := self.host.zone.region.ResetVMPasswd(self.GetId(), password) - if err != nil { - return err - } - } - - err := cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) - if err != nil { - return errors.Wrap(err, "DeployVM") - } - - return nil -} - -func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - if len(config.InstanceType) > 0 { - return self.ChangeConfig2(ctx, config.InstanceType) - } - return self.host.zone.region.ResizeVM(self.GetId(), config.Cpu, config.MemoryMB) -} - -func (self *SInstance) ChangeConfig2(ctx context.Context, instanceType string) error { - i, err := ParseInstanceType(instanceType) - if err != nil { - return err - } - - return self.host.zone.region.ResizeVM(self.GetId(), i.CPU, i.MemoryMB) -} - -func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - return self.host.zone.region.GetInstanceVNCUrl(self.GetId()) -} - -func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return self.host.zone.region.AttachDisk(self.host.zone.GetId(), self.GetId(), diskId) -} - -func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { - err := self.host.zone.region.DetachDisk(self.host.zone.GetId(), self.GetId(), diskId) - if err != nil { - return err - } - - disk, err := self.host.zone.region.GetDisk(diskId) - if err != nil { - return err - } - - disk.storage = &SStorage{zone: self.host.zone, storageType: disk.GetStorageType()} - err = cloudprovider.WaitStatusWithDelay(disk, api.DISK_READY, 10*time.Second, 10*time.Second, 60*time.Second) - if err != nil { - return errors.Wrap(err, "DetachDisk") - } - - return nil -} - -func (self *SInstance) Renew(bc billing.SBillingCycle) error { - // return self.host.zone.region - return self.host.zone.region.RenewInstance(self.GetId(), bc) -} - -func (self *SInstance) GetSecurityGroups() ([]SSecurityGroup, error) { - return self.host.zone.region.GetSecurityGroups("", self.GetId(), "") -} - -// https://docs.ucloud.cn/api/uhost-api/get_uhost_instance_vnc_info -func (self *SRegion) GetInstanceVNCUrl(instanceId string) (*cloudprovider.ServerVncOutput, error) { - params := NewUcloudParams() - params.Set("UHostId", instanceId) - vnc := SVncInfo{} - err := self.DoAction("GetUHostInstanceVncInfo", params, &vnc) - if err != nil { - return nil, err - } - - ret := &cloudprovider.ServerVncOutput{ - Host: vnc.VNCIP, - Port: vnc.VNCPort, - Password: vnc.VNCPassword, - Hypervisor: api.HYPERVISOR_UCLOUD, - } - return ret, nil -} - -// https://docs.ucloud.cn/api/unet-api/grant_firewall -func (self *SRegion) assignSecurityGroups(instanceId string, secgroupId string) error { - params := NewUcloudParams() - params.Set("FWId", secgroupId) - params.Set("ResourceType", "uhost") - params.Set("ResourceId", instanceId) - - return self.DoAction("GrantFirewall", params, nil) -} - -// https://docs.ucloud.cn/api/uhost-api/start_uhost_instance -func (self *SRegion) StartVM(instanceId string) error { - params := NewUcloudParams() - params.Set("UHostId", instanceId) - - return self.DoAction("StartUHostInstance", params, nil) -} - -// https://docs.ucloud.cn/api/uhost-api/stop_uhost_instance -func (self *SRegion) StopVM(instanceId string) error { - params := NewUcloudParams() - params.Set("UHostId", instanceId) - - return self.DoAction("StopUHostInstance", params, nil) -} - -// https://docs.ucloud.cn/api/uhost-api/terminate_uhost_instance -func (self *SRegion) DeleteVM(instanceId string) error { - params := NewUcloudParams() - params.Set("UHostId", instanceId) - params.Set("Destroy", 1) // 跳过回收站,直接删除 - - return self.DoAction("TerminateUHostInstance", params, nil) -} - -// https://docs.ucloud.cn/api/uhost-api/modify_uhost_instance_name -func (self *SRegion) UpdateVM(instanceId, name string) error { - params := NewUcloudParams() - params.Set("UHostId", instanceId) - params.Set("Name", name) - - return self.DoAction("ModifyUHostInstanceName", params, nil) -} - -// ChargeType : Dynamic(按需)/Month(按月)/Year(按年) -func (self *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle) error { - params := NewUcloudParams() - params.Set("ResourceId", instanceId) - params.Set("ResourceType", "Host") - - if bc.GetMonths() >= 10 && bc.GetMonths() < 12 { - params.Set("ChargeType", "Year") - params.Set("Quantity", 1) - } else if bc.GetYears() >= 1 { - params.Set("ChargeType", "Year") - params.Set("Quantity", bc.GetYears()) - } else { - params.Set("ChargeType", "Month") - params.Set("Quantity", bc.GetMonths()) - } - - return self.DoAction("CreateRenew", params, nil) -} - -// https://docs.ucloud.cn/api/uhost-api/reset_uhost_instance_password -// 该操作需要UHost实例处于关闭状态。 -func (self *SRegion) ResetVMPasswd(instanceId, password string) error { - params := NewUcloudParams() - params.Set("UHostId", instanceId) - params.Set("Password", base64.StdEncoding.EncodeToString([]byte(password))) - - return self.DoAction("ResetUHostInstancePassword", params, nil) -} - -// https://docs.ucloud.cn/api/uhost-api/reinstall_uhost_instance -// (密码格式使用BASE64编码;LoginMode不可变更) -func (self *SRegion) RebuildRoot(instanceId, imageId, password string) error { - params := NewUcloudParams() - params.Set("UHostId", instanceId) - params.Set("Password", base64.StdEncoding.EncodeToString([]byte(password))) - params.Set("ImageId", imageId) - - return self.DoAction("ReinstallUHostInstance", params, nil) -} - -// https://docs.ucloud.cn/api/uhost-api/resize_uhost_instance -func (self *SRegion) ResizeVM(instanceId string, cpu, memoryMB int) error { - params := NewUcloudParams() - params.Set("UHostId", instanceId) - params.Set("CPU", cpu) - params.Set("Memory", memoryMB) - - return self.DoAction("ResizeUHostInstance", params, nil) -} diff --git a/pkg/multicloud/ucloud/instancenic.go b/pkg/multicloud/ucloud/instancenic.go deleted file mode 100644 index 7a9515974b..0000000000 --- a/pkg/multicloud/ucloud/instancenic.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - instance *SInstance - ipAddr string - macAddr string - - cloudprovider.DummyICloudNic -} - -func (self *SInstanceNic) GetId() string { - return "" -} - -func (self *SInstanceNic) GetIP() string { - return self.ipAddr -} - -func (self *SInstanceNic) GetMAC() string { - return self.macAddr -} - -func (self *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (self *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (self *SInstanceNic) GetINetworkId() string { - for _, ip := range self.instance.IPSet { - if ip.IP == self.ipAddr { - return ip.SubnetID - } - } - return "" -} diff --git a/pkg/multicloud/ucloud/latitud_and_longitude.go b/pkg/multicloud/ucloud/latitud_and_longitude.go deleted file mode 100644 index c06fbf5541..0000000000 --- a/pkg/multicloud/ucloud/latitud_and_longitude.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -// https://docs.ucloud.cn/api/summary/regionlist -var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ - "cn-bj1": {Latitude: 39.9041999, Longitude: 116.4073963, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-bj2": {Latitude: 39.9041999, Longitude: 116.4073963, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, - "cn-sh": {Latitude: 31.2303904, Longitude: 121.4737021, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-sh2": {Latitude: 31.2303904, Longitude: 121.4737021, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, - "cn-gd": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, - "hk": {Latitude: 22.396428, Longitude: 114.109497, City: api.CITY_HONG_KONG, CountryCode: api.COUNTRY_CODE_CN}, - "us-ca": {Latitude: 34.0522342, Longitude: -118.2436849, City: api.CITY_LOS_ANGELES, CountryCode: api.COUNTRY_CODE_US}, - "us-ws": {Latitude: 38.9071923, Longitude: -77.0368707, City: api.CITY_WASHINGTON, CountryCode: api.COUNTRY_CODE_US}, - "ge-fra": {Latitude: 50.1109221, Longitude: 8.6821267, City: api.CITY_FRANKFURT, CountryCode: api.COUNTRY_CODE_DE}, - "th-bkk": {Latitude: 13.7563309, Longitude: 100.5017651, City: api.CITY_BANGKOK, CountryCode: api.COUNTRY_CODE_TH}, - "kr-seoul": {Latitude: 37.566535, Longitude: 126.9779692, City: api.CITY_SEOUL, CountryCode: api.COUNTRY_CODE_KR}, - "sg": {Latitude: 1.352083, Longitude: 103.819836, City: api.CITY_SINGAPORE, CountryCode: api.COUNTRY_CODE_SG}, - "tw-tp": {Latitude: 25.0329694, Longitude: 121.5654177, City: api.CITY_TAIPEI, CountryCode: api.COUNTRY_CODE_CN}, - "tw-kh": {Latitude: 22.6272784, Longitude: 120.3014353, City: api.CITY_KAOHSIUNG, CountryCode: api.COUNTRY_CODE_CN}, - "jpn-tky": {Latitude: 35.7090259, Longitude: 139.7319925, City: api.CITY_TOKYO, CountryCode: api.COUNTRY_CODE_JP}, - "rus-mosc": {Latitude: 55.755826, Longitude: 37.6172999, City: api.CITY_MOSCOW, CountryCode: api.COUNTRY_CODE_RU}, - "uae-dubai": {Latitude: 25.2048493, Longitude: 55.2707828, City: api.CITY_DUBAI, CountryCode: api.COUNTRY_CODE_AE}, - "idn-jakarta": {Latitude: -6.2087634, Longitude: 106.845599, City: api.CITY_JAKARTA, CountryCode: api.COUNTRY_CODE_ID}, - "ind-mumbai": {Latitude: 19.0759837, Longitude: 72.8776559, City: api.CITY_MUMBAI, CountryCode: api.COUNTRY_CODE_IN}, - "bra-saopaulo": {Latitude: -23.5505199, Longitude: -46.6333094, City: api.CITY_SAO_PAULO, CountryCode: api.COUNTRY_CODE_BR}, - "uk-london": {Latitude: 51.5073509, Longitude: -0.1277583, City: api.CITY_LONDON, CountryCode: api.COUNTRY_CODE_GB}, - "afr-nigeria": {Latitude: 6.5243793, Longitude: 3.3792057, City: api.CITY_LAGOS, CountryCode: api.COUNTRY_CODE_NG}, - "vn-sng": {Latitude: 10.8230989, Longitude: 106.6296638, City: api.CITY_HO_CHI_MINH, CountryCode: api.COUNTRY_CODE_VN}, - "cn-qz": {Latitude: 24.9037185, Longitude: 118.5134676, City: api.CITY_QUAN_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, -} diff --git a/pkg/multicloud/ucloud/network.go b/pkg/multicloud/ucloud/network.go deleted file mode 100644 index 723e19b696..0000000000 --- a/pkg/multicloud/ucloud/network.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -// https://docs.ucloud.cn/api/vpc2.0-api/describe_subnet -type SNetwork struct { - multicloud.SResourceBase - multicloud.UcloudTags - wire *SWire - - CreateTime int64 `json:"CreateTime"` - Gateway string `json:"Gateway"` - HasNATGW bool `json:"HasNATGW"` - Name string `json:"Name"` - Netmask string `json:"Netmask"` - Remark string `json:"Remark"` - RouteTableID string `json:"RouteTableId"` - Subnet string `json:"Subnet"` - SubnetID string `json:"SubnetId"` - SubnetName string `json:"SubnetName"` - SubnetType int `json:"SubnetType"` - Tag string `json:"Tag"` - VPCID string `json:"VPCId"` - VPCName string `json:"VPCName"` - VRouterID string `json:"VRouterId"` - Zone string `json:"Zone"` -} - -func (self *SNetwork) GetProjectId() string { - return self.wire.region.client.projectId -} - -func (self *SNetwork) GetId() string { - return self.SubnetID -} - -func (self *SNetwork) GetName() string { - if len(self.SubnetName) > 0 { - return self.SubnetName - } - - return self.GetId() -} - -func (self *SNetwork) GetGlobalId() string { - return self.GetId() -} - -func (self *SNetwork) GetStatus() string { - return api.NETWORK_STATUS_AVAILABLE -} - -func (self *SNetwork) Refresh() error { - log.Debugf("network refresh %s", self.GetId()) - new, err := self.wire.region.getNetwork(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SNetwork) IsEmulated() bool { - return false -} - -func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { - return self.wire -} - -func (self *SNetwork) GetIpStart() string { - pref, _ := netutils.NewIPV4Prefix(self.Subnet + "/" + self.Netmask) - startIp := pref.Address.NetAddr(pref.MaskLen) // 0 - startIp = startIp.StepUp() // 1 gateway - startIp = startIp.StepUp() // 2 - return startIp.String() -} - -func (self *SNetwork) GetIpEnd() string { - pref, _ := netutils.NewIPV4Prefix(self.Subnet + "/" + self.Netmask) - endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 - endIp = endIp.StepDown() // 254 - return endIp.String() -} - -func (self *SNetwork) GetIpMask() int8 { - pref, _ := netutils.NewIPV4Prefix(self.Subnet + "/" + self.Netmask) - return pref.MaskLen -} - -func (self *SNetwork) GetGateway() string { - return self.Gateway -} - -func (self *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (self *SNetwork) GetIsPublic() bool { - return true -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeDomain -} - -func (self *SNetwork) Delete() error { - return self.wire.region.DeleteNetwork(self.GetId()) -} - -func (self *SNetwork) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -// https://docs.ucloud.cn/api/vpc2.0-api/describe_subnet -func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) { - if len(networkId) == 0 { - return nil, fmt.Errorf("getNetwork network id should not be empty") - } - networks := make([]SNetwork, 0) - - params := NewUcloudParams() - params.Set("SubnetId", networkId) - err := self.DoListAll("DescribeSubnet", params, &networks) - if err != nil { - return nil, err - } - - if len(networks) == 1 { - network := networks[0] - vpc, err := self.getVpc(network.VPCID) - if err != nil { - return nil, err - } - network.wire = &SWire{region: self, vpc: vpc, inetworks: []cloudprovider.ICloudNetwork{&network}} - return &network, nil - } else if len(networks) == 0 { - return nil, cloudprovider.ErrNotFound - } else { - return nil, fmt.Errorf("getNetwork %s %d found", networkId, len(networks)) - } -} - -// https://docs.ucloud.cn/api/vpc2.0-api/delete_subnet -func (self *SRegion) DeleteNetwork(networkId string) error { - params := NewUcloudParams() - params.Set("SubnetId", networkId) - - return self.DoAction("DeleteSubnet", params, nil) -} - -// https://docs.ucloud.cn/api/vpc2.0-api/create_subnet -func (self *SRegion) CreateNetwork(vpcId string, name string, cidr string, desc string) (*SNetwork, error) { - ip, mask, err := netutils.ParsePrefix(cidr) - if err != nil { - return nil, fmt.Errorf("CreateINetwork invalid cidr %s", cidr) - } - - params := NewUcloudParams() - params.Set("VPCId", vpcId) - params.Set("Subnet", ip.String()) - params.Set("Netmask", int(mask)) - params.Set("SubnetName", name) - params.Set("Remark", desc) - - type SNet struct { - SubnetId string - } - - net := SNet{} - err = self.DoAction("CreateSubnet", params, &net) - if err != nil { - return nil, err - } - - return self.getNetwork(net.SubnetId) -} diff --git a/pkg/multicloud/ucloud/project.go b/pkg/multicloud/ucloud/project.go deleted file mode 100644 index 4dab5fe695..0000000000 --- a/pkg/multicloud/ucloud/project.go +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://docs.ucloud.cn/api/summary/get_project_list -type SProject struct { - multicloud.SProjectBase - multicloud.UcloudTags - ProjectID string `json:"ProjectId"` - ProjectName string `json:"ProjectName"` - ParentID string `json:"ParentId"` - ParentName string `json:"ParentName"` - CreateTime int64 `json:"CreateTime"` - IsDefault bool `json:"IsDefault"` - MemberCount int64 `json:"MemberCount"` - ResourceCount int64 `json:"ResourceCount"` -} - -func (self *SProject) GetId() string { - return self.ProjectID -} - -func (self *SProject) GetName() string { - return self.ProjectName -} - -func (self *SProject) GetGlobalId() string { - return self.GetId() -} - -func (self *SProject) GetStatus() string { - return "" -} - -func (self *SProject) Refresh() error { - return nil -} - -func (self *SProject) IsEmulated() bool { - return false -} - -func (self *SUcloudClient) FetchProjects() ([]SProject, error) { - params := NewUcloudParams() - projects := make([]SProject, 0) - err := self.DoListAll("GetProjectList", params, &projects) - return projects, err -} diff --git a/pkg/multicloud/ucloud/provider/doc.go b/pkg/multicloud/ucloud/provider/doc.go deleted file mode 100644 index 4127749d37..0000000000 --- a/pkg/multicloud/ucloud/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/ucloud/provider" diff --git a/pkg/multicloud/ucloud/provider/provider.go b/pkg/multicloud/ucloud/provider/provider.go deleted file mode 100644 index 38c2df0c52..0000000000 --- a/pkg/multicloud/ucloud/provider/provider.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/ucloud" -) - -// tag:finished -type SUcloudProviderFactory struct { - cloudprovider.SPublicCloudBaseProviderFactory -} - -func (self *SUcloudProviderFactory) GetId() string { - return ucloud.CLOUD_PROVIDER_UCLOUD -} - -func (self *SUcloudProviderFactory) GetName() string { - return ucloud.CLOUD_PROVIDER_UCLOUD_CN -} - -func (self *SUcloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - return output, nil -} - -func (self *SUcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") - } - if len(input.AccessKeySecret) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") - } - output = cloudprovider.SCloudaccount{ - Account: input.AccessKeyId, - Secret: input.AccessKeySecret, - } - return output, nil -} - -func parseAccount(account string) (accessKey string, projectId string) { - segs := strings.Split(account, "::") - if len(segs) == 2 { - accessKey = segs[0] - projectId = segs[1] - } else { - accessKey = account - projectId = "" - } - - return -} - -func (self *SUcloudProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - accessKey, projectId := parseAccount(cfg.Account) - client, err := ucloud.NewUcloudClient( - ucloud.NewUcloudClientConfig( - accessKey, cfg.Secret, - ).ProjectId(projectId).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SUcloudProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SUcloudProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - accessKey, projectId := parseAccount(info.Account) - return map[string]string{ - "UCLOUD_ACCESS_KEY": accessKey, - "UCLOUD_SECRET": info.Secret, - "UCLOUD_REGION": ucloud.UCLOUD_DEFAULT_REGION, - "UCLOUD_PROJECT": projectId, - }, nil -} - -func init() { - factory := SUcloudProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SUcloudProvider struct { - cloudprovider.SBaseProvider - client *ucloud.SUcloudClient -} - -func (self *SUcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - projects, err := self.client.FetchProjects() - if err != nil { - return nil, err - } - - iprojects := make([]cloudprovider.ICloudProject, len(projects)) - for i := range projects { - iprojects[i] = &projects[i] - } - - return iprojects, nil -} - -func (self *SUcloudProvider) GetSysInfo() (jsonutils.JSONObject, error) { - regions := self.client.GetIRegions() - info := jsonutils.NewDict() - info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") - info.Add(jsonutils.NewString(ucloud.UCLOUD_API_VERSION), "api_version") - return info, nil -} - -func (self *SUcloudProvider) GetVersion() string { - return ucloud.UCLOUD_API_VERSION -} - -func (self *SUcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SUcloudProvider) GetAccountId() string { - return self.client.GetAccountId() -} - -func (self *SUcloudProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SUcloudProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(extId) -} - -func (self *SUcloudProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported -} - -func (self *SUcloudProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SUcloudProvider) GetStorageClasses(regionId string) []string { - return []string{ - "STANDARD", "IA", "ARCHIVE", - } -} - -func (self *SUcloudProvider) GetBucketCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLPublicRead), - } -} - -func (self *SUcloudProvider) GetObjectCannedAcls(regionId string) []string { - return []string{ - string(cloudprovider.ACLPrivate), - string(cloudprovider.ACLPublicRead), - } -} - -func (self *SUcloudProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} diff --git a/pkg/multicloud/ucloud/region.go b/pkg/multicloud/ucloud/region.go deleted file mode 100644 index 9128a5986b..0000000000 --- a/pkg/multicloud/ucloud/region.go +++ /dev/null @@ -1,697 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "fmt" - "strings" - - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - multicloud.SRegion - client *SUcloudClient - - RegionID string - - izones []cloudprovider.ICloudZone - ivpcs []cloudprovider.ICloudVpc - - storageCache *SStoragecache - - latitude float64 - longitude float64 - fetchLocation bool -} - -func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetId() string { - return self.RegionID -} - -func (self *SRegion) GetName() string { - if name, exist := UCLOUD_REGION_NAMES[self.GetId()]; exist { - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_UCLOUD_CN, name) - } - - return fmt.Sprintf("%s %s", CLOUD_PROVIDER_UCLOUD_CN, self.GetId()) -} - -func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { - var en string - if name, exist := UCLOUD_REGION_NAMES_EN[self.GetId()]; exist { - en = fmt.Sprintf("%s %s", CLOUD_PROVIDER_UCLOUD, name) - } else { - en = fmt.Sprintf("%s %s", CLOUD_PROVIDER_UCLOUD, self.GetId()) - } - - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_UCLOUD, self.GetId()) -} - -func (self *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (self *SRegion) Refresh() error { - return nil -} - -func (self *SRegion) IsEmulated() bool { - return false -} - -func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - if info, ok := LatitudeAndLongitude[self.GetId()]; ok { - return info - } - return cloudprovider.SGeographicInfo{} -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - instance, err := self.GetInstanceByID(id) - if err != nil { - return nil, err - } - return &instance, nil -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - return self.GetDisk(id) -} - -func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if self.izones == nil { - var err error - err = self.fetchInfrastructure() - if 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 -} - -// https://docs.ucloud.cn/api/unet-api/describe_eip -func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - params := NewUcloudParams() - eips := make([]SEip, 0) - err := self.DoListAll("DescribeEIP", params, &eips) - if err != nil { - return nil, err - } - - ieips := []cloudprovider.ICloudEIP{} - for i := range eips { - eip := eips[i] - eip.region = self - ieips = append(ieips, &eip) - } - - return ieips, nil -} - -func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { - ivpcs, err := self.GetIVpcs() - if err != nil { - return nil, err - } - for i := 0; i < len(ivpcs); i += 1 { - if ivpcs[i].GetGlobalId() == id { - return ivpcs[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetEipById(eipId string) (SEip, error) { - params := NewUcloudParams() - params.Set("EIPIds.0", eipId) - eips := make([]SEip, 0) - err := self.DoListAll("DescribeEIP", params, &eips) - if err != nil { - return SEip{}, err - } - - if len(eips) == 1 { - eip := eips[0] - eip.region = self - return eip, nil - } else if len(eips) == 0 { - return SEip{}, cloudprovider.ErrNotFound - } else { - return SEip{}, fmt.Errorf("GetEipById %d eip found", len(eips)) - } -} - -func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { - eip, err := self.GetEipById(id) - return &eip, err -} - -// https://docs.ucloud.cn/api/unet-api/delete_firewall -func (self *SRegion) DeleteSecurityGroup(secgroupId string) error { - params := NewUcloudParams() - params.Set("FWId", secgroupId) - return self.DoAction("DeleteFirewall", params, nil) -} - -func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - return self.GetSecurityGroupById(secgroupId) -} - -func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := self.GetSecurityGroups("", "", opts.Name) - if err != nil { - return nil, err - } - if len(secgroups) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(secgroups) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - return &secgroups[0], nil -} - -func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - externalId, err := self.CreateDefaultSecurityGroup(conf.Name, conf.Desc) - if err != nil { - return nil, err - } - return self.GetISecurityGroupById(externalId) -} - -// https://docs.ucloud.cn/api/unet-api/describe_firewall -// 绑定防火墙组的资源类型,默认为全部资源类型。枚举值为:"unatgw",NAT网关; "uhost",云主机; "upm",物理云主机; "hadoophost",hadoop节点; "fortresshost",堡垒机; "udhost",私有专区主机;"udockhost",容器;"dbaudit",数据库审计. -// todo: 是否需要过滤出仅绑定云主机的安全组? - -func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - params := NewUcloudParams() - params.Set("Name", opts.NAME) - params.Set("Remark", opts.Desc) - for i, cidr := range strings.Split(opts.CIDR, ",") { - params.Set(fmt.Sprintf("Network.%d", i), cidr) - } - - vpcId := "" - err := self.DoAction("CreateVPC", params, &vpcId) - if err != nil { - return nil, err - } - - return self.GetIVpcById(vpcId) -} - -// https://docs.ucloud.cn/api/udisk-api/describe_udisk_snapshot -func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - params := NewUcloudParams() - snapshots := make([]SSnapshot, 0) - err := self.DoListAll("DescribeUDiskSnapshot", params, &snapshots) - if err != nil { - return nil, err - } - - isnapshots := make([]cloudprovider.ICloudSnapshot, 0) - for i := range snapshots { - snapshots[i].region = self - isnapshots = append(isnapshots, &snapshots[i]) - } - - return isnapshots, nil -} - -func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - if len(snapshotId) == 0 { - return nil, cloudprovider.ErrNotFound - } - - params := NewUcloudParams() - snapshots := make([]SSnapshot, 0) - err := self.DoListAll("DescribeUDiskSnapshot", params, &snapshots) - if err != nil { - return nil, err - } - - for i := range snapshots { - if snapshots[i].SnapshotID == snapshotId { - snapshot := snapshots[i] - snapshot.region = self - return &snapshot, nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - iHosts := make([]cloudprovider.ICloudHost, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneHost, err := izones[i].GetIHosts() - if err != nil { - return nil, err - } - iHosts = append(iHosts, iZoneHost...) - } - return iHosts, nil -} - -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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - iStores := make([]cloudprovider.ICloudStorage, 0) - - izones, err := self.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i += 1 { - iZoneStores, err := izones[i].GetIStorages() - if err != nil { - return nil, err - } - iStores = append(iStores, iZoneStores...) - } - return iStores, nil -} - -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 errors.Cause(err) != cloudprovider.ErrNotFound { - return nil, err - } - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) getStoragecache() *SStoragecache { - if self.storageCache == nil { - self.storageCache = &SStoragecache{region: self} - } - return self.storageCache -} - -func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - return []cloudprovider.ICloudStoragecache{storageCache}, nil -} - -func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - storageCache := self.getStoragecache() - if storageCache.GetGlobalId() == id { - return storageCache, nil - } - return nil, cloudprovider.ErrNotFound -} - -func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SRegion) GetProvider() string { - return CLOUD_PROVIDER_UCLOUD -} - -func (self *SRegion) GetCloudEnv() string { - return "" -} - -func (self *SRegion) DoListAll(action string, params SParams, result interface{}) error { - params.Set("Region", self.GetId()) - return self.client.DoListAll(action, params, result) -} - -// return total,lenght,error -func (self *SRegion) DoListPart(action string, limit int, offset int, params SParams, result interface{}) (int, int, error) { - params.Set("Region", self.GetId()) - return self.client.DoListPart(action, limit, offset, params, result) -} - -func (self *SRegion) DoAction(action string, params SParams, result interface{}) error { - params.Set("Region", self.GetId()) - return self.client.DoAction(action, params, result) -} - -func (self *SRegion) fetchInfrastructure() error { - 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 { - vpc := self.ivpcs[i].(*SVPC) - wire := SWire{region: self, vpc: vpc} - vpc.addWire(&wire) - - for j := 0; j < len(self.izones); j += 1 { - zone := self.izones[j].(*SZone) - zone.addWire(&wire) - } - } - return nil -} - -func (self *SRegion) fetchZones() error { - type Region struct { - RegionID int64 `json:"RegionId"` - RegionName string `json:"RegionName"` - IsDefault bool `json:"IsDefault"` - BitMaps string `json:"BitMaps"` - Region string `json:"Region"` - Zone string `json:"Zone"` - } - - params := NewUcloudParams() - regions := make([]Region, 0) - err := self.client.DoListAll("GetRegion", params, ®ions) - if err != nil { - return err - } - - for _, r := range regions { - if r.Region != self.GetId() { - continue - } - - szone := SZone{} - szone.ZoneId = r.Zone - szone.RegionId = r.Region - szone.region = self - self.izones = append(self.izones, &szone) - } - - return nil -} - -func (self *SRegion) fetchIVpcs() error { - vpcs := make([]SVPC, 0) - params := NewUcloudParams() - err := self.DoListAll("DescribeVPC", params, &vpcs) - if err != nil { - return err - } - - for i := range vpcs { - vpc := vpcs[i] - vpc.region = self - self.ivpcs = append(self.ivpcs, &vpc) - } - - return nil -} - -// https://docs.ucloud.cn/api/uhost-api/describe_uhost_instance -func (self *SRegion) GetInstanceByID(instanceId string) (SInstance, error) { - params := NewUcloudParams() - params.Set("UHostIds.0", instanceId) - instances := make([]SInstance, 0) - err := self.DoAction("DescribeUHostInstance", params, &instances) - if err != nil { - return SInstance{}, err - } - - if len(instances) == 1 { - return instances[0], nil - } else if len(instances) == 0 { - return SInstance{}, cloudprovider.ErrNotFound - } else { - return SInstance{}, fmt.Errorf("GetInstanceByID %s %d found.", instanceId, len(instances)) - } -} - -// GRE协议被忽略了 -func toUcloudSecRule(rule cloudprovider.SecurityRule) []string { - net := rule.IPNet.String() - action := "DROP" - if rule.Action == secrules.SecurityRuleAllow { - action = "ACCEPT" - } - - rules := make([]string, 0) - if len(rule.Ports) > 0 { - for _, port := range rule.Ports { - _rules := generatorRule(rule.Protocol, net, action, port, port, rule.Priority) - rules = append(rules, _rules...) - } - } else { - _rules := generatorRule(rule.Protocol, net, action, rule.PortStart, rule.PortEnd, rule.Priority) - rules = append(rules, _rules...) - } - - return rules -} - -func generatorRule(protocol, net, action string, startPort, endPort, priority int) []string { - rules := make([]string, 0) - - var ports string - if startPort <= 0 || endPort <= 0 { - ports = "1-65535" - } else if startPort == endPort { - ports = fmt.Sprintf("%d", startPort) - } else { - ports = fmt.Sprintf("%d-%d", startPort, endPort) - } - prio := "LOW" - switch priority { - case 1: - prio = "LOW" - case 2: - prio = "MEDIUM" - case 3: - prio = "HIGH" - } - - template := fmt.Sprintf("%s|%s|%s|%s|%s|", "%s", "%s", net, action, prio) - switch protocol { - case secrules.PROTO_ANY: - rules = append(rules, fmt.Sprintf(template, "TCP", ports)) - rules = append(rules, fmt.Sprintf(template, "UDP", ports)) - rules = append(rules, fmt.Sprintf(template, "ICMP", "")) - case secrules.PROTO_TCP: - rules = append(rules, fmt.Sprintf(template, "TCP", ports)) - case secrules.PROTO_UDP: - rules = append(rules, fmt.Sprintf(template, "UDP", ports)) - case secrules.PROTO_ICMP: - rules = append(rules, fmt.Sprintf(template, "ICMP", "")) - } - - return rules -} - -// https://docs.ucloud.cn/api/unet-api/update_firewall -func (self *SRegion) syncSecgroupRules(secgroupId string, rules []cloudprovider.SecurityRule) error { - _rules := []string{} - for _, r := range rules { - _rules = append(_rules, toUcloudSecRule(r)...) - } - - params := NewUcloudParams() - params.Set("FWId", secgroupId) - for i, r := range _rules { - N := i + 1 - params.Set(fmt.Sprintf("Rule.%d", N), r) - } - - return self.DoAction("UpdateFirewall", params, nil) -} - -func (self *SRegion) GetClient() *SUcloudClient { - return self.client -} - -// https://docs.ucloud.cn/api/ufile-api/describe_bucket -func (client *SUcloudClient) listBuckets(name string, offset int, limit int) ([]SBucket, error) { - params := NewUcloudParams() - if len(name) > 0 { - params.Set("BucketName", name) - } else { - params.Set("Limit", limit) - params.Set("Offset", offset) - } - buckets := make([]SBucket, 0) - // request without RegionId - err := client.DoAction("DescribeBucket", params, &buckets) - if err != nil { - return nil, errors.Wrap(err, "DoAction DescribeBucket") - } - return buckets, nil -} - -// https://docs.ucloud.cn/api/ufile-api/update_bucket -func (region *SRegion) updateBucket(name string, aclType string) error { - params := NewUcloudParams() - params.Set("BucketName", name) - params.Set("ProjectId", region.client.projectId) - params.Set("Type", aclType) - return region.client.DoAction("UpdateBucket", params, nil) -} - -func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { - iBuckets, err := region.client.getIBuckets() - if err != nil { - return nil, errors.Wrap(err, "getIBuckets") - } - ret := make([]cloudprovider.ICloudBucket, 0) - for i := range iBuckets { - if iBuckets[i].GetLocation() != region.GetId() { - continue - } - ret = append(ret, iBuckets[i]) - } - return ret, nil -} - -func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { - if aclStr != "private" && aclStr != "public" { - return errors.Error("invalid acl") - } - return region.CreateBucket(name, aclStr) -} - -func (region *SRegion) DeleteIBucket(name string) error { - err := region.DeleteBucket(name) - if err != nil { - if strings.Index(err.Error(), "bucket not found") >= 0 { - return nil - } - return errors.Wrap(err, "region.DeleteBucket") - } - return nil -} - -func (region *SRegion) IBucketExist(name string) (bool, error) { - parts, err := region.client.listBuckets(name, 0, 1) - if err != nil { - return false, errors.Wrap(err, "region.listBuckets") - } - if len(parts) == 0 { - return false, cloudprovider.ErrNotFound - } - return true, nil -} - -func (region *SRegion) GetIBucketById(bucketId string) (cloudprovider.ICloudBucket, error) { - return cloudprovider.GetIBucketById(region, bucketId) -} - -func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { - return region.GetIBucketByName(name) -} - -func (region *SRegion) GetCapabilities() []string { - return region.client.GetCapabilities() -} diff --git a/pkg/multicloud/ucloud/securitygroup.go b/pkg/multicloud/ucloud/securitygroup.go deleted file mode 100644 index e7c34b3bdd..0000000000 --- a/pkg/multicloud/ucloud/securitygroup.go +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "fmt" - "math/rand" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://docs.ucloud.cn/api/unet-api/describe_firewall -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.UcloudTags - region *SRegion - vpc *SVPC // 安全组在UCLOUD实际上与VPC是没有直接关联的。这里的vpc字段只是为了统一,仅仅是标记是哪个VPC在操作该安全组。 - - CreateTime int64 `json:"CreateTime"` - FWID string `json:"FWId"` - GroupID string `json:"GroupId"` - Name string `json:"Name"` - Remark string `json:"Remark"` - ResourceCount int `json:"ResourceCount"` - Rule []Rule `json:"Rule"` - Tag string `json:"Tag"` - Type string `json:"Type"` -} - -func (self *SSecurityGroup) GetProjectId() string { - return self.region.client.projectId -} - -type Rule struct { - DstPort string `json:"DstPort"` - Priority string `json:"Priority"` - ProtocolType string `json:"ProtocolType"` - RuleAction string `json:"RuleAction"` - SrcIP string `json:"SrcIP"` -} - -func (self *SSecurityGroup) GetId() string { - return self.FWID -} - -func (self *SSecurityGroup) GetName() string { - if len(self.Name) == 0 { - return self.GetId() - } - - return self.Name -} - -func (self *SSecurityGroup) GetGlobalId() string { - return self.GetId() -} - -func (self *SSecurityGroup) GetStatus() string { - return "" -} - -func (self *SSecurityGroup) Refresh() error { - if new, err := self.region.GetSecurityGroupById(self.GetId()); err != nil { - return err - } else { - return jsonutils.Update(self, new) - } -} - -func (self *SSecurityGroup) IsEmulated() bool { - return false -} - -func (self *SSecurityGroup) GetDescription() string { - return self.Remark -} - -func (self *SSecurityGroup) UcloudSecRuleToOnecloud(rule Rule) (cloudprovider.SecurityRule, error) { - secrule := cloudprovider.SecurityRule{} - switch rule.Priority { - case "HIGH": - secrule.Priority = 3 - case "MEDIUM": - secrule.Priority = 2 - case "LOW": - secrule.Priority = 1 - default: - secrule.Priority = 1 - } - - switch rule.RuleAction { - case "ACCEPT": - secrule.Action = secrules.SecurityRuleAllow - case "DROP": - secrule.Action = secrules.SecurityRuleDeny - default: - secrule.Action = secrules.SecurityRuleDeny - } - - secrule.ParseCIDR(rule.SrcIP) - secrule.Protocol = strings.ToLower(rule.ProtocolType) - secrule.Direction = secrules.SecurityRuleIngress - err := secrule.ParsePorts(rule.DstPort) - if err != nil { - return secrule, errors.Wrapf(err, "ParsePorts(%s)", rule.DstPort) - } - - return secrule, nil -} - -// https://docs.ucloud.cn/network/firewall/firewall -// 只有入方向规则 -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - rules := make([]cloudprovider.SecurityRule, 0) - for _, r := range self.Rule { - rule, err := self.UcloudSecRuleToOnecloud(r) - if err != nil { - log.Errorf("failed to convert rule for group %s(%s) error: %v", self.Name, self.GroupID, err) - continue - } - rules = append(rules, rule) - } - - return rules, nil -} - -func (self *SSecurityGroup) GetVpcId() string { - // 无vpc关联的安全组统一返回normal - return api.NORMAL_VPC_ID -} - -func (self *SRegion) GetSecurityGroupById(secGroupId string) (*SSecurityGroup, error) { - secgroups, err := self.GetSecurityGroups(secGroupId, "", "") - if err != nil { - return nil, err - } - - if len(secgroups) == 1 { - return &secgroups[0], nil - } else if len(secgroups) == 0 { - return nil, cloudprovider.ErrNotFound - } else { - return nil, fmt.Errorf("GetSecurityGroupById %s %d found", secGroupId, len(secgroups)) - } -} - -func randomString(prefix string, length int) string { - bytes := []byte("0123456789abcdefghijklmnopqrstuvwxyz") - result := []byte{} - r := rand.New(rand.NewSource(time.Now().UnixNano())) - for i := 0; i < length; i++ { - result = append(result, bytes[r.Intn(len(bytes))]) - } - return prefix + string(result) -} - -func (self *SRegion) CreateDefaultSecurityGroup(name, description string) (string, error) { - // 减少安全组名称冲突 - name = randomString(name, 4) - return self.CreateSecurityGroup(name, description, []string{"TCP|1-65535|0.0.0.0/0|ACCEPT|LOW", "UDP|1-65535|0.0.0.0/0|ACCEPT|LOW", "ICMP||0.0.0.0/0|ACCEPT|LOW"}) -} - -// https://docs.ucloud.cn/api/unet-api/create_firewall -func (self *SRegion) CreateSecurityGroup(name, description string, rules []string) (string, error) { - params := NewUcloudParams() - params.Set("Name", name) - params.Set("Remark", description) - if len(rules) == 0 { - return "", fmt.Errorf("CreateSecurityGroup required at least one rule") - } - - for i, rule := range rules { - params.Set(fmt.Sprintf("Rule.%d", i), rule) - } - - type Firewall struct { - FWId string - } - - firewall := Firewall{} - err := self.DoAction("CreateFirewall", params, &firewall) - if err != nil { - return "", err - } - - return firewall.FWId, nil -} - -// https://docs.ucloud.cn/api/unet-api/describe_firewall -func (self *SRegion) GetSecurityGroups(secGroupId string, resourceId string, name string) ([]SSecurityGroup, error) { - secgroups := make([]SSecurityGroup, 0) - - params := NewUcloudParams() - if len(secGroupId) > 0 { - params.Set("FWId", secGroupId) - } - - if len(resourceId) > 0 { - params.Set("ResourceId", resourceId) - params.Set("ResourceType", "uhost") // 默认只支持"uhost",云主机 - } - err := self.DoListAll("DescribeFirewall", params, &secgroups) - if err != nil { - if strings.Contains(err.Error(), "not exist") { - return nil, cloudprovider.ErrNotFound - } - return nil, err - } - - result := []SSecurityGroup{} - - for i := range secgroups { - if len(name) == 0 || secgroups[i].Name == name { - secgroups[i].region = self - result = append(result, secgroups[i]) - } - } - - return result, nil -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - if len(inAdds) == 0 && len(inDels) == 0 { - return nil - } - rules := append(common, inAdds...) - return self.region.syncSecgroupRules(self.FWID, rules) -} - -func (self *SSecurityGroup) Delete() error { - return self.region.DeleteSecurityGroup(self.FWID) -} diff --git a/pkg/multicloud/ucloud/shell/disk.go b/pkg/multicloud/ucloud/shell/disk.go deleted file mode 100644 index 4323363360..0000000000 --- a/pkg/multicloud/ucloud/shell/disk.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - Zone string `help:"Zone ID"` - } - shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *ucloud.SRegion, args *DiskListOptions) error { - disks, e := cli.GetDisks(args.Zone, "", nil) - if e != nil { - return e - } - printList(disks, 0, 0, 0, nil) - return nil - }) - - type DiskDeleteOptions struct { - ZONE string `help:"Zone ID"` - ID string `help:"Disk ID"` - } - shellutils.R(&DiskDeleteOptions{}, "disk-delete", "List disks", func(cli *ucloud.SRegion, args *DiskDeleteOptions) error { - e := cli.DeleteDisk(args.ZONE, args.ID) - if e != nil { - return e - } - return nil - }) -} diff --git a/pkg/multicloud/ucloud/shell/doc.go b/pkg/multicloud/ucloud/shell/doc.go deleted file mode 100644 index 0f0853035e..0000000000 --- a/pkg/multicloud/ucloud/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/ucloud/shell" diff --git a/pkg/multicloud/ucloud/shell/eip.go b/pkg/multicloud/ucloud/shell/eip.go deleted file mode 100644 index 1f488772bb..0000000000 --- a/pkg/multicloud/ucloud/shell/eip.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *ucloud.SRegion, args *EipListOptions) error { - eips, e := cli.GetIEips() - if e != nil { - return e - } - printList(eips, 0, 0, 0, nil) - return nil - }) - - type EipAllocateOptions struct { - NAME string `help:"eip name"` - BW int `help:"Bandwidth limit in Mbps"` - BGP string `help:"bgp type" choices:"Bgp|International"` - } - shellutils.R(&EipAllocateOptions{}, "eip-create", "Allocate an EIP", func(cli *ucloud.SRegion, args *EipAllocateOptions) error { - option := cloudprovider.SEip{ - Name: args.NAME, - BandwidthMbps: args.BW, - BGPType: args.BGP, - } - eip, err := cli.CreateEIP(&option) - 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 *ucloud.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 *ucloud.SRegion, args *EipAssociateOptions) error { - err := cli.AssociateEip(args.ID, args.INSTANCE) - return err - }) - shellutils.R(&EipAssociateOptions{}, "eip-dissociate", "Dissociate an EIP", func(cli *ucloud.SRegion, args *EipAssociateOptions) error { - err := cli.DissociateEip(args.ID, args.INSTANCE) - return err - }) -} diff --git a/pkg/multicloud/ucloud/shell/image.go b/pkg/multicloud/ucloud/shell/image.go deleted file mode 100644 index bbf6affc95..0000000000 --- a/pkg/multicloud/ucloud/shell/image.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - Owner string `help:"Owner type" choices:"Base|Business|Custom"` - Id string `help:"Image ID"` - } - shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *ucloud.SRegion, args *ImageListOptions) error { - images, e := cli.GetImages(args.Owner, args.Id) - if e != nil { - return e - } - printList(images, 0, 0, 0, []string{}) - return nil - }) - - type ImageDeleteOptions struct { - ID string `help:"ID or Name to delete"` - } - shellutils.R(&ImageDeleteOptions{}, "image-delete", "Delete image", func(cli *ucloud.SRegion, args *ImageDeleteOptions) error { - return cli.DeleteImage(args.ID) - }) - - shellutils.R(&ImageDeleteOptions{}, "image-show", "Show image", func(cli *ucloud.SRegion, args *ImageDeleteOptions) error { - img, err := cli.GetImage(args.ID) - if err != nil { - return err - } - printObject(img) - return nil - }) -} diff --git a/pkg/multicloud/ucloud/shell/instance.go b/pkg/multicloud/ucloud/shell/instance.go deleted file mode 100644 index 6ce8bfa6f3..0000000000 --- a/pkg/multicloud/ucloud/shell/instance.go +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List intances", func(cli *ucloud.SRegion, args *InstanceListOptions) error { - instances, e := cli.GetInstances("", "") - if e != nil { - return e - } - printList(instances, 0, 0, 0, nil) - return nil - }) - - type InstanceDiskOperationOptions struct { - ZONE string `help:"zone ID"` - 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 *ucloud.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 *ucloud.SRegion, args *InstanceDiskOperationOptions) error { - err := cli.DetachDisk(args.ZONE, args.ID, args.DISK) - if err != nil { - return err - } - return nil - }) - - type InstanceCrateOptions struct { - NAME string `help:"name of instance"` - IMAGE string `help:"image ID"` - INSTANCETYPE string `help:"intance type.eg. N2.c1.m1"` - PASSWORD string `help:"password"` - VPC string `help:"VPC ID"` - NETWORK string `help:"Network ID"` - SECGROUP string `help:"secgroup ID"` - ZONE string `help:"zone ID"` - STORAGE string `help:"Storage type" choices:"CLOUD_NORMAL|CLOUD_SSD|LOCAL_NORMAL|LOCAL_SSD"` - DISKSIZE int `help:"root disk size GB"` - } - shellutils.R(&InstanceCrateOptions{}, "instance-create", "Create a instance", func(cli *ucloud.SRegion, args *InstanceCrateOptions) error { - disk := ucloud.SDisk{DiskType: args.STORAGE, SizeGB: args.DISKSIZE} - i, err := ucloud.ParseInstanceType(args.INSTANCETYPE) - if err != nil { - return err - } - instance, e := cli.CreateInstance(args.NAME, args.IMAGE, i.UHostType, args.PASSWORD, args.VPC, args.NETWORK, args.SECGROUP, args.ZONE, "", "", i.CPU, i.MemoryMB, i.GPU, []ucloud.SDisk{disk}, nil) - if e != nil { - return e - } - printObject(instance) - return nil - }) - - type InstanceOperationOptions struct { - ID string `help:"instance ID"` - } - shellutils.R(&InstanceOperationOptions{}, "instance-start", "Start a instance", func(cli *ucloud.SRegion, args *InstanceOperationOptions) error { - err := cli.StartVM(args.ID) - if err != nil { - return err - } - return nil - }) - - type InstanceStopOptions struct { - ID string `help:"instance ID"` - } - shellutils.R(&InstanceStopOptions{}, "instance-stop", "Stop a instance", func(cli *ucloud.SRegion, args *InstanceStopOptions) error { - err := cli.StopVM(args.ID) - if err != nil { - return err - } - return nil - }) - shellutils.R(&InstanceOperationOptions{}, "instance-delete", "Delete a instance", func(cli *ucloud.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"` - Password string `help:"new password"` - } - - shellutils.R(&InstanceDeployOptions{}, "instance-deploy", "Deploy keypair/password to a stopped virtual server", func(cli *ucloud.SRegion, args *InstanceDeployOptions) error { - err := cli.ResetVMPasswd(args.ID, args.Password) - if err != nil { - return err - } - return nil - }) - - type InstanceRebuildRootOptions struct { - ID string `help:"instance ID"` - Image string `help:"Image ID"` - Password string `help:"admin password"` - } - - shellutils.R(&InstanceRebuildRootOptions{}, "instance-rebuild-root", "Reinstall virtual server system image", func(cli *ucloud.SRegion, args *InstanceRebuildRootOptions) error { - err := cli.RebuildRoot(args.ID, args.Image, args.Password) - if err != nil { - return err - } - - return nil - }) - - type InstanceChangeConfigOptions struct { - ID string `help:"instance ID"` - NCPU int `help:"cpu"` - MEM int `help:"memory MB"` - } - - shellutils.R(&InstanceChangeConfigOptions{}, "instance-change-config", "Deploy keypair/password to a stopped virtual server", func(cli *ucloud.SRegion, args *InstanceChangeConfigOptions) error { - err := cli.ResizeVM(args.ID, args.NCPU, args.MEM) - if err != nil { - return err - } - return nil - }) -} diff --git a/pkg/multicloud/ucloud/shell/network.go b/pkg/multicloud/ucloud/shell/network.go deleted file mode 100644 index 0a69af1283..0000000000 --- a/pkg/multicloud/ucloud/shell/network.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VSwitchListOptions struct { - Vpc string `help:"Vpc ID"` - } - shellutils.R(&VSwitchListOptions{}, "subnet-list", "List subnets", func(cli *ucloud.SRegion, args *VSwitchListOptions) error { - vswitches, e := cli.GetNetworks(args.Vpc) - if e != nil { - return e - } - printList(vswitches, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ucloud/shell/printutils.go b/pkg/multicloud/ucloud/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/ucloud/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/ucloud/shell/region.go b/pkg/multicloud/ucloud/shell/region.go deleted file mode 100644 index c63b9ca58b..0000000000 --- a/pkg/multicloud/ucloud/shell/region.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *ucloud.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) - - shellutils.R(&RegionListOptions{}, "project-list", "List projects", func(cli *ucloud.SRegion, args *RegionListOptions) error { - projects, err := cli.GetClient().FetchProjects() - if err != nil { - return err - } - printList(projects, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ucloud/shell/secgroup.go b/pkg/multicloud/ucloud/shell/secgroup.go deleted file mode 100644 index 95ed1a11a5..0000000000 --- a/pkg/multicloud/ucloud/shell/secgroup.go +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - Name string - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List security group", func(cli *ucloud.SRegion, args *SecurityGroupListOptions) error { - secgrps, e := cli.GetSecurityGroups("", "", args.Name) - if e != nil { - return e - } - printList(secgrps, 0, 0, 0, nil) - return nil - }) - - type SecurityGroupIdOptions struct { - ID string `help:"ID or name of security group"` - } - shellutils.R(&SecurityGroupIdOptions{}, "security-group-show", "Show details of a security group", func(cli *ucloud.SRegion, args *SecurityGroupIdOptions) error { - secgrp, err := cli.GetSecurityGroupById(args.ID) - if err != nil { - return err - } - printObject(secgrp) - return nil - }) - - shellutils.R(&SecurityGroupIdOptions{}, "security-group-delete", "Show details of a security group", func(cli *ucloud.SRegion, args *SecurityGroupIdOptions) error { - return cli.DeleteSecurityGroup(args.ID) - }) - - type SecurityGroupCreateOptions struct { - NAME string `help:"Name of security group"` - Desc string `help:"Description of secgroup"` - } - - shellutils.R(&SecurityGroupCreateOptions{}, "security-group-create", "Create security group", func(cli *ucloud.SRegion, args *SecurityGroupCreateOptions) error { - secgrpId, err := cli.CreateDefaultSecurityGroup(args.NAME, args.Desc) - if err != nil { - return err - } - fmt.Println(secgrpId) - return nil - }) - -} diff --git a/pkg/multicloud/ucloud/shell/snapshot.go b/pkg/multicloud/ucloud/shell/snapshot.go deleted file mode 100644 index 696d566585..0000000000 --- a/pkg/multicloud/ucloud/shell/snapshot.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SnapshotListOptions struct { - DiskId string `help:"Disk ID"` - Name string `help:"Snapshot Name"` - } - shellutils.R(&SnapshotListOptions{}, "snapshot-list", "List snapshot", func(cli *ucloud.SRegion, args *SnapshotListOptions) error { - snapshots, err := cli.GetSnapshots("", args.DiskId, args.Name) - if err != nil { - return err - } - printList(snapshots, 0, 0, 0, nil) - return nil - }) - - type SnapshotDeleteOptions struct { - ID string `help:"Snapshot ID"` - Zone string `help:"Snapshot zone id"` - } - - shellutils.R(&SnapshotDeleteOptions{}, "snapshot-delete", "Delete snapshot", func(cli *ucloud.SRegion, args *SnapshotDeleteOptions) error { - return cli.DeleteSnapshot(args.ID, args.Zone) - }) - - type SnapshotCreateOptions struct { - ZoneId string `help:"Zone ID"` - DiskId string `help:"Disk ID"` - Name string `help:"Snapeshot Name"` - Desc string `help:"Snapshot Desc"` - } - - shellutils.R(&SnapshotCreateOptions{}, "snapshot-create", "Create snapshot", func(cli *ucloud.SRegion, args *SnapshotCreateOptions) error { - _, err := cli.CreateSnapshot(args.ZoneId, args.DiskId, args.Name, args.Desc) - return err - }) - -} diff --git a/pkg/multicloud/ucloud/shell/ufile.go b/pkg/multicloud/ucloud/shell/ufile.go deleted file mode 100644 index 9482e9f16d..0000000000 --- a/pkg/multicloud/ucloud/shell/ufile.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/objectstore" -) - -func init() { - objectstore.S3Shell() -} diff --git a/pkg/multicloud/ucloud/shell/vip.go b/pkg/multicloud/ucloud/shell/vip.go deleted file mode 100644 index e053b26b36..0000000000 --- a/pkg/multicloud/ucloud/shell/vip.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VipListOptions struct { - } - shellutils.R(&VipListOptions{}, "vip-list", "List vips", func(cli *ucloud.SRegion, args *VipListOptions) error { - vips, err := cli.GetVips() - if err != nil { - return err - } - printList(vips, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ucloud/shell/vpc.go b/pkg/multicloud/ucloud/shell/vpc.go deleted file mode 100644 index 19ce9d3579..0000000000 --- a/pkg/multicloud/ucloud/shell/vpc.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VpcListOptions struct { - } - shellutils.R(&VpcListOptions{}, "vpc-list", "List vpcs", func(cli *ucloud.SRegion, args *VpcListOptions) error { - vpcs, e := cli.GetVpcs("") - if e != nil { - return e - } - printList(vpcs, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/ucloud/shell/zone.go b/pkg/multicloud/ucloud/shell/zone.go deleted file mode 100644 index 40b8198411..0000000000 --- a/pkg/multicloud/ucloud/shell/zone.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/ucloud" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - } - shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *ucloud.SRegion, args *ZoneListOptions) error { - zones, e := cli.GetIZones() - if e != nil { - return e - } - - printList(zones, 0, 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/ucloud/snapshot.go b/pkg/multicloud/ucloud/snapshot.go deleted file mode 100644 index 20331271b2..0000000000 --- a/pkg/multicloud/ucloud/snapshot.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "fmt" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://docs.ucloud.cn/api/udisk-api/describe_udisk_snapshot -type SSnapshot struct { - multicloud.SResourceBase - multicloud.UcloudTags - region *SRegion - - Comment string `json:"Comment"` - ChargeType string `json:"ChargeType"` - Name string `json:"Name"` - UDiskName string `json:"UDiskName"` - ExpiredTime int64 `json:"ExpiredTime"` - UDiskID string `json:"UDiskId"` - SnapshotID string `json:"SnapshotId"` - CreateTime int64 `json:"CreateTime"` - SizeGB int32 `json:"Size"` - Status string `json:"Status"` - IsUDiskAvailable bool `json:"IsUDiskAvailable"` - Version string `json:"Version"` - DiskType int `json:"DiskType"` - UHostID string `json:"UHostId"` -} - -func (self *SSnapshot) GetProjectId() string { - return self.region.client.projectId -} - -func (self *SSnapshot) GetId() string { - return self.SnapshotID -} - -func (self *SSnapshot) GetName() string { - if len(self.Name) == 0 { - return self.GetId() - } - - return self.Name -} - -func (self *SSnapshot) GetGlobalId() string { - return self.GetId() -} - -// 快照状态,Normal:正常,Failed:失败,Creating:制作中 -func (self *SSnapshot) GetStatus() string { - switch self.Status { - case "Normal": - return api.SNAPSHOT_READY - case "Failed": - return api.SNAPSHOT_FAILED - case "Creating": - return api.SNAPSHOT_CREATING - default: - return api.SNAPSHOT_UNKNOWN - } -} - -func (self *SSnapshot) Refresh() error { - disk, err := self.region.GetDisk(self.UDiskID) - if err != nil { - return err - } - - snapshot, err := self.region.GetSnapshotById(disk.Zone, self.GetId()) - if err != nil { - return err - } - - if err := jsonutils.Update(self, snapshot); err != nil { - return err - } - - return nil -} - -func (self *SSnapshot) IsEmulated() bool { - return false -} - -func (self *SSnapshot) GetSizeMb() int32 { - return self.SizeGB * 1024 -} - -func (self *SSnapshot) GetDiskId() string { - return self.UDiskID -} - -// 磁盘类型,0:数据盘,1:系统盘 -func (self *SSnapshot) GetDiskType() string { - if self.DiskType == 1 { - return api.DISK_TYPE_SYS - } else { - return api.DISK_TYPE_DATA - } -} - -// https://docs.ucloud.cn/api/udisk-api/delete_udisk_snapshot -func (self *SSnapshot) Delete() error { - zoneId := "" - idisk, err := self.region.GetDisk(self.UDiskID) - if err == nil { - zoneId = idisk.Zone - } else if errors.Cause(err) == cloudprovider.ErrNotFound { - zones, err := self.region.GetIZones() - if err != nil { - return errors.Wrap(err, "snapshot.Delete GetIZones") - } - - for _, zone := range zones { - if _, err := self.region.GetSnapshotById(zone.GetId(), self.GetId()); err == nil { - zoneId = zone.GetId() - break - } - } - } else { - return errors.Wrap(err, "snapshot.Delete") - } - - if len(zoneId) == 0 { - return fmt.Errorf("snapshot.Delete can not found snapshot %s zone id", self.GetId()) - } - - return self.region.DeleteSnapshot(self.GetId(), zoneId) -} - -func (self *SRegion) GetSnapshotById(zoneId string, snapshotId string) (SSnapshot, error) { - snapshots, err := self.GetSnapshots(zoneId, "", snapshotId) - if err != nil { - return SSnapshot{}, err - } - - if len(snapshots) == 1 { - return snapshots[0], nil - } else if len(snapshots) == 0 { - return SSnapshot{}, cloudprovider.ErrNotFound - } else { - return SSnapshot{}, fmt.Errorf("GetSnapshotById %s %d found", snapshotId, len(snapshots)) - } -} - -func (self *SRegion) GetSnapshots(zoneId string, diskId string, snapshotId string) ([]SSnapshot, error) { - params := NewUcloudParams() - if len(diskId) > 0 { - disk, err := self.GetDisk(diskId) - if err != nil { - return nil, err - } - - params.Set("UDiskId", diskId) - params.Set("Zone", disk.Zone) - } - - if len(zoneId) > 0 { - params.Set("Zone", zoneId) - } - - if len(snapshotId) > 0 { - params.Set("SnapshotId", snapshotId) - } - - snapshots := make([]SSnapshot, 0) - err := self.DoAction("DescribeUDiskSnapshot", params, &snapshots) - if err != nil { - return nil, err - } - - for i := range snapshots { - snapshots[i].region = self - } - - return snapshots, nil -} - -// https://docs.ucloud.cn/api/udisk-api/delete_udisk_snapshot -func (self *SRegion) DeleteSnapshot(snapshotId string, zoneId string) error { - params := NewUcloudParams() - params.Set("SnapshotId", snapshotId) - params.Set("Zone", zoneId) - - return self.DoAction("DeleteUDiskSnapshot", params, nil) -} diff --git a/pkg/multicloud/ucloud/storage.go b/pkg/multicloud/ucloud/storage.go deleted file mode 100644 index 125dffa008..0000000000 --- a/pkg/multicloud/ucloud/storage.go +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SStorage struct { - multicloud.SStorageBase - multicloud.UcloudTags - zone *SZone - storageType string -} - -func (self *SStorage) GetId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetName() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) -} - -func (self *SStorage) GetGlobalId() string { - return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) -} - -func (self *SStorage) GetStatus() string { - return api.STORAGE_ONLINE -} - -func (self *SStorage) Refresh() error { - return nil -} - -func (self *SStorage) IsEmulated() bool { - return true -} - -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, err := self.zone.region.GetDisks(self.zone.GetId(), "", nil) - if err != nil { - return nil, err - } - - filtedDisks := make([]SDisk, 0) - for _, disk := range disks { - // ssd 盘 - if self.storageType == api.STORAGE_UCLOUD_CLOUD_SSD && strings.Contains(disk.DiskType, "SSD") { - filtedDisks = append(filtedDisks, disk) - } - - // 普通盘 - if self.storageType == api.STORAGE_UCLOUD_CLOUD_NORMAL && !strings.Contains(disk.DiskType, "SSD") { - filtedDisks = append(filtedDisks, disk) - } - } - - idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) - for i := 0; i < len(filtedDisks); i += 1 { - filtedDisks[i].storage = self - idisks[i] = &filtedDisks[i] - } - return idisks, nil -} - -func (self *SStorage) GetStorageType() string { - return self.storageType -} - -func (self *SStorage) GetMediumType() string { - if self.storageType == api.STORAGE_UCLOUD_CLOUD_SSD { - return api.DISK_TYPE_SSD - } else { - return api.DISK_TYPE_ROTATE - } -} - -func (self *SStorage) GetCapacityMB() int64 { - return 0 // unlimited -} - -func (self *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (self *SStorage) GetStorageConf() jsonutils.JSONObject { - return jsonutils.NewDict() -} - -func (self *SStorage) GetEnabled() bool { - return true -} - -func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - diskType := "DataDisk" - switch self.storageType { - case api.STORAGE_UCLOUD_CLOUD_SSD: - diskType = "SSDDataDisk" - } - diskId, err := self.zone.region.CreateDisk(self.zone.GetId(), diskType, conf.Name, conf.SizeGb) - if err != nil { - return nil, err - } - - disk, err := self.zone.region.GetDisk(diskId) - if err != nil { - return nil, err - } - - disk.storage = self - return disk, nil -} - -func (self *SStorage) GetIDiskById(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 - } -} - -func (self *SStorage) GetMountPoint() string { - return "" -} - -func (self *SStorage) IsSysDiskStore() bool { - return true -} diff --git a/pkg/multicloud/ucloud/storagecache.go b/pkg/multicloud/ucloud/storagecache.go deleted file mode 100644 index 8c737ba2a3..0000000000 --- a/pkg/multicloud/ucloud/storagecache.go +++ /dev/null @@ -1,393 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "context" - "fmt" - "math" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - "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" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.UcloudTags - region *SRegion -} - -func GetBucketName(regionId string, imageId string) string { - return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), strings.ToLower(imageId)) -} - -func (self *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) -} - -func (self *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) -} - -func (self *SStoragecache) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, 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) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - images, err := self.region.GetImages("", "Custom") - if err != nil { - return nil, errors.Wrapf(err, "GetImages") - } - ret := []cloudprovider.ICloudImage{} - for i := range images { - images[i].storageCache = self - ret = append(ret, &images[i]) - } - return ret, nil -} - -func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - image, err := self.region.GetImage(extId) - image.storageCache = self - return &image, err -} - -func (self *SStoragecache) GetPath() string { - return "" -} - -func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} - -// https://docs.ucloud.cn/api/uhost-api/import_custom_image -func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return self.uploadImage(ctx, userCred, image, callback) -} - -func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - if len(image.OsVersion) == 0 { - return "", fmt.Errorf("uploadImage os version is empty") - } - - bucketName := GetBucketName(self.region.GetId(), image.ImageId) - - // create bucket - exist, err := self.region.IBucketExist(bucketName) - if err != nil { - return "", errors.Wrap(err, "self.region.IBucketExist") - } - if !exist { - err = self.region.CreateBucket(bucketName, "private") - if err != nil { - return "", errors.Wrap(err, "CreateBucket") - } - } - defer func() { - e := self.region.DeleteBucket(bucketName) - if e != nil { - log.Errorf("uploadImage delete bucket %s", e.Error()) - } - }() - - // upload to ucloud - s := auth.GetAdminSession(ctx, options.Options.Region) - meta, reader, size, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) - if err != nil { - return "", err - } - log.Debugf("Images meta data %s", meta) - minDiskMB, _ := meta.Int("min_disk") - minDiskGB := int64(math.Ceil(float64(minDiskMB) / 1024)) - - if minDiskGB < 40 { - minDiskGB = 40 - } else if minDiskGB > 1024 { - minDiskGB = 1024 - } - // size, _ := meta.Int("size") - md5, _ := meta.GetString("checksum") - diskFormat, _ := meta.GetString("disk_format") - // upload to ucloud - bucket, err := self.region.GetIBucketById(bucketName) - if err != nil { - return "", errors.Wrap(err, "GetIBucketByName") - } - file := SFile{ - bucket: bucket.(*SBucket), - file: multicloud.NewProgress(size, 98, reader, callback), - - Size: size, - FileName: image.ImageId, - Hash: md5, - } - - err = file.Upload() - if err != nil { - return "", err - } - defer func() { - e := file.Delete() - if e != nil { - log.Errorf("uploadImage delete object %s", e.Error()) - } - }() // remove object - - // check image name, avoid name conflict - imageBaseName := image.ImageId - if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { - imageBaseName = fmt.Sprintf("img%s", image.ImageId) - } - imageName := imageBaseName - nameIdx := 1 - - for { - _, err = self.region.GetImageByName(imageName) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - break - } else { - return "", err - } - } - - imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) - nameIdx += 1 - log.Debugf("uploadImage Match remote name %s", imageName) - } - - imgId, err := self.region.ImportImage(imageName, file.FetchFileUrl(), image.OsDistribution, image.OsVersion, diskFormat) - - if err != nil { - log.Errorf("ImportImage error %s %s", file.FetchFileUrl(), err) - return "", err - } - - // timeout: 1hour = 3600 seconds - err = cloudprovider.WaitCreated(60*time.Second, 3600*time.Second, func() bool { - image, err := self.region.GetImage(imgId) - if err == nil && image.State == "Available" { - return true - } - - return false - }) - if err != nil { - return "", errors.Wrap(err, "UploadImage") - } - if callback != nil { - callback(100) - } - return imgId, err -} - -// https://docs.ucloud.cn/api/uhost-api/create_custom_image -func (self *SRegion) createIImage(snapshotId, imageName, imageDesc string) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -/*func (self *SRegion) GetBucketDomain(name string) (string, error) { - params := NewUcloudParams() - params.Set("BucketName", name) - - res := make([]SBucket, 0) - err := self.client.DoListAll("DescribeBucket", params, &res) - if err != nil { - return "", err - } - - if len(res) == 1 && len(res[0].Domain.Src) >= 1 { - return res[0].Domain.Src[0], nil - } else { - return "", fmt.Errorf("GetBucketDomain failed. %v", res) - } -}*/ - -// https://docs.ucloud.cn/api/ufile-api/create_bucket -func (self *SRegion) CreateBucket(name, bucketType string) error { - params := NewUcloudParams() - params.Set("BucketName", name) - params.Set("Type", bucketType) - err := self.DoAction("CreateBucket", params, nil) - if err != nil { - return err - } - self.client.invalidateIBuckets() - return nil -} - -// https://docs.ucloud.cn/api/ufile-api/delete_bucket -func (self *SRegion) DeleteBucket(name string) error { - params := NewUcloudParams() - params.Set("BucketName", name) - err := self.DoAction("DeleteBucket", params, nil) - if err != nil { - return err - } - self.client.invalidateIBuckets() - return nil -} - -// https://docs.ucloud.cn/api/ufile-api/put_file -func (self *SRegion) uploadObj(name string) error { - params := NewUcloudParams() - params.Set("BucketName", name) - return self.DoAction("PutFile", params, nil) -} - -func (self *SRegion) GetImageByName(name string) (*SImage, error) { - images, err := self.GetImages("Custom", "") - if err != nil { - return nil, err - } - - for i := range images { - if images[i].GetName() == name { - return &images[i], nil - } - } - - return nil, cloudprovider.ErrNotFound -} - -func normalizeOsType(osType string) string { - switch strings.ToLower(osType) { - case "centos": - return "CentOS" - case "ubuntu": - return "Ubuntu" - case "windows": - return "Windows" - case "redHat": - return "RedHat" - case "debian": - return "Debian" - default: - return "Other" - } -} - -func normalizeOsName(normalizeOsType string, fullVersion string) string { - if utils.IsInStringArray(normalizeOsType, []string{"CentOS", "RedHat", "Debian"}) { - if len(fullVersion) >= 3 { - return fmt.Sprintf("%s %s 64位", normalizeOsType, fullVersion[0:3]) - } else { - return fmt.Sprintf("%s %s.0 64位", normalizeOsType, fullVersion[0:1]) - } - } - - if normalizeOsType == "Ubuntu" { - if len(fullVersion) >= 5 { - return fmt.Sprintf("Ubuntu %s 64位", fullVersion[0:5]) - } else if len(fullVersion) >= 2 { - return fmt.Sprintf("Ubuntu %s.04 64位", fullVersion[0:2]) - } else { - // 默认猜一个? - return "Ubuntu 14.04 64位" - } - } - - if normalizeOsType == "Windows" { - if len(fullVersion) >= 4 { - return fmt.Sprintf("Windows %s 64位", fullVersion[0:4]) - } else { - // 默认猜一个? - return "Windows 2016 64位" - } - } - - return "Other" -} - -func normalizeDiskFormat(diskFormat string) (string, error) { - switch strings.ToLower(diskFormat) { - case "raw": - return "RAW", nil - case "vhd": - return "VHD", nil - case "vmdk": - return "VMDK", nil - case "qcow2": - return "qcow2", nil - default: - return "", fmt.Errorf("unsupported image format %s", diskFormat) - } -} - -// https://docs.ucloud.cn/api/uhost-api/import_custom_image -func (self *SRegion) ImportImage(name string, ufileUrl string, osType string, osVersion string, diskFormat string) (string, error) { - format, err := normalizeDiskFormat(diskFormat) - if err != nil { - return "", err - } - - nOsType := normalizeOsType(osType) - - params := NewUcloudParams() - params.Set("ImageName", name) - params.Set("UFileUrl", ufileUrl) - // 操作系统平台,比如CentOS、Ubuntu、Windows、RedHat等,请参考控制台的镜像版本;若导入控制台上没有的操作系统,参数为Other - params.Set("OsType", nOsType) - // 操作系统详细版本,请参考控制台的镜像版本;OsType为Other时,输入参数为Other - params.Set("OsName", normalizeOsName(nOsType, osVersion)) - params.Set("Format", format) - params.Set("Auth", "True") - params.Set("ImageDescription", osVersion) - - type SImageId struct { - ImageId string - } - - ret := SImageId{} - log.Debugf("ImportImage with params %s", params.String()) - err = self.DoAction("ImportCustomImage", params, &ret) - if err != nil { - return "", err - } - - return ret.ImageId, nil -} diff --git a/pkg/multicloud/ucloud/ufile.go b/pkg/multicloud/ucloud/ufile.go deleted file mode 100644 index eed81b1a70..0000000000 --- a/pkg/multicloud/ucloud/ufile.go +++ /dev/null @@ -1,394 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "context" - "crypto/hmac" - "crypto/sha1" - "encoding/base64" - "fmt" - "io" - "net/http" - "net/url" - "strconv" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/httputils" -) - -type SBucket struct { - multicloud.SBaseBucket - multicloud.UcloudTags - - region *SRegion - - // projectId string - - Domain Domain `json:"Domain"` - BucketID string `json:"BucketId"` - Region string `json:"Region"` - CreateTime int64 `json:"CreateTime"` - Biz string `json:"Biz"` - BucketName string `json:"BucketName"` - ModifyTime int64 `json:"ModifyTime"` - Type string `json:"Type"` - Tag string `json:"Tag"` - HasUserDomain int64 `json:"HasUserDomain"` - CDNDomainID []string `json:"CdnDomainId"` -} - -type Domain struct { - Src []string `json:"Src"` - CDN []string `json:"Cdn"` - CustomCDN []interface{} `json:"CustomCdn"` - CustomSrc []interface{} `json:"CustomSrc"` -} - -type SFile struct { - bucket *SBucket - - BucketName string `json:"BucketName"` - FileName string `json:"FileName"` - Size int64 `json:"Size"` - Hash string `json:"Hash"` - MimeType string `json:"MimeType"` - CreateTime int64 `json:"CreateTime"` - ModifyTime int64 `json:"ModifyTime"` - StorageClass string `json:"StorageClass"` - - file io.Reader -} - -func (client *SUcloudClient) signHeader(httpMethod string, path string, md5 string) string { - contentType := "" - if httpMethod == http.MethodPut { - contentType = "application/octet-stream" - } - - data := httpMethod + "\n" - data += md5 + "\n" - data += contentType + "\n" - data += "\n" - data += path - - log.Debugf("sign %s", data) - h := hmac.New(sha1.New, []byte(client.accessKeySecret)) - h.Write([]byte(data)) - return base64.StdEncoding.EncodeToString(h.Sum(nil)) -} - -func (self *SFile) signHeader(httpMethod string) string { - return self.bucket.region.client.signHeader(httpMethod, "/"+self.bucket.BucketName+"/"+self.FileName, self.Hash) -} - -func (self *SFile) auth(httpMethod string) string { - return "UCloud" + " " + self.bucket.region.client.accessKeyId + ":" + self.signHeader(httpMethod) -} - -func (self *SFile) GetHost() string { - return self.bucket.Domain.Src[0] -} - -func (self *SFile) GetUrl() string { - return fmt.Sprintf("http://%s/%s", self.GetHost(), self.FileName) -} - -// https://github.com/ufilesdk-dev/ufile-gosdk/blob/master/auth.go -func (self *SFile) FetchFileUrl() string { - expired := strconv.FormatInt(time.Now().Add(6*time.Hour).Unix(), 10) - // sign - data := "GET\n\n\n" + expired + "\n" - data += "/" + self.bucket.BucketName + "/" + self.FileName - h := hmac.New(sha1.New, []byte(self.bucket.region.client.accessKeySecret)) - h.Write([]byte(data)) - sign := base64.StdEncoding.EncodeToString(h.Sum(nil)) - - urlEncoder := url.Values{} - urlEncoder.Add("UCloudPublicKey", self.bucket.region.client.accessKeyId) - urlEncoder.Add("Signature", sign) - urlEncoder.Add("Expires", expired) - querys := urlEncoder.Encode() - return fmt.Sprintf("%s?%s", self.GetUrl(), querys) -} - -func (self *SFile) Upload() error { - req, _ := http.NewRequest(http.MethodPut, self.GetUrl(), self.file) - req.Header.Add("Authorization", self.auth(http.MethodPut)) - req.Header.Add("Content-MD5", self.Hash) - req.Header.Add("Content-Type", "application/octet-stream") - req.Header.Add("Content-Length", strconv.FormatInt(self.Size, 10)) - _, err := doRequest(req) - return err -} - -func (self *SFile) Delete() error { - req, _ := http.NewRequest(http.MethodDelete, self.GetUrl(), nil) - req.Header.Add("Authorization", self.auth(http.MethodDelete)) - _, err := doRequest(req) - return err -} - -func (self *SFile) GetIBucket() cloudprovider.ICloudBucket { - return self.bucket -} - -func (self *SFile) GetKey() string { - return self.FileName -} - -func (self *SFile) GetSizeBytes() int64 { - return self.Size -} - -func (self *SFile) GetLastModified() time.Time { - return time.Unix(self.ModifyTime, 0) -} - -func (self *SFile) GetStorageClass() string { - return self.StorageClass -} - -func (self *SFile) GetETag() string { - return self.Hash -} - -func (self *SFile) GetContentType() string { - return self.MimeType -} - -func (self *SFile) GetAcl() cloudprovider.TBucketACLType { - return self.bucket.GetAcl() -} - -func (self *SFile) SetAcl(cloudprovider.TBucketACLType) error { - return nil -} - -func (self *SFile) GetMeta() http.Header { - return nil -} - -func (self *SFile) SetMeta(ctx context.Context, meta http.Header) error { - return cloudprovider.ErrNotSupported -} - -func doRequest(req *http.Request) (jsonutils.JSONObject, error) { - // ufile request use no timeout client so as to download/upload large files - res, err := httputils.GetAdaptiveTimeoutClient().Do(req) - if err != nil { - return nil, errors.Wrap(err, "httpclient Do") - } - _, body, err := httputils.ParseJSONResponse("", res, err, false) - if err != nil { - return nil, errors.Wrap(err, "ParseJSONResponse") - } - return body, nil -} - -type sPrefixFileListOutput struct { - BucketName string - BucketId string - NextMarker string - DataSet []SFile -} - -func (b *SBucket) doPrefixFileList(prefix string, marker string, limit int) (*sPrefixFileListOutput, error) { - params := jsonutils.NewDict() - params.Add(jsonutils.NewString(""), "list") - if len(prefix) > 0 { - params.Add(jsonutils.NewString(prefix), "prefix") - } - if len(marker) > 0 { - params.Add(jsonutils.NewString(marker), "marker") - } - if limit > 0 { - params.Add(jsonutils.NewInt(int64(limit)), "limit") - } - host := fmt.Sprintf("https://%s.ufile.ucloud.cn", b.BucketName) - path := fmt.Sprintf("/?%s", params.QueryString()) - - log.Debugf("Request %s%s", host, path) - - req, _ := http.NewRequest(http.MethodGet, host+path, nil) - - sign := b.region.client.signHeader(http.MethodGet, path, "") - auth := "UCloud" + " " + b.region.client.accessKeyId + ":" + sign - - req.Header.Add("Authorization", auth) - - output := sPrefixFileListOutput{} - - body, err := doRequest(req) - if err != nil { - return nil, errors.Wrap(err, "doRequest") - } - err = body.Unmarshal(&output) - if err != nil { - return nil, errors.Wrap(err, "body.Unmarshal") - } - - return &output, nil -} - -func (b *SBucket) GetProjectId() string { - return b.region.client.projectId -} - -func (b *SBucket) GetGlobalId() string { - return b.BucketID -} - -func (b *SBucket) GetName() string { - return b.BucketName -} - -func (b *SBucket) GetLocation() string { - return b.region.GetId() -} - -func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { - return b.region -} - -func (b *SBucket) GetCreatedAt() time.Time { - return time.Unix(b.CreateTime, 0) -} - -func (b *SBucket) GetStorageClass() string { - return "" -} - -func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { - switch b.Type { - case "public": - return cloudprovider.ACLPublicRead - default: - return cloudprovider.ACLPrivate - } -} - -func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error { - aclType := "private" - if aclStr == cloudprovider.ACLPublicRead || aclStr == cloudprovider.ACLPublicReadWrite { - aclType = "public" - } - return b.region.updateBucket(b.BucketName, aclType) -} - -func (b *SBucket) getSrcUrl() string { - if len(b.Domain.Src) > 0 { - return b.Domain.Src[0] - } - return "" -} - -func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { - ret := make([]cloudprovider.SBucketAccessUrl, 0) - for i, u := range b.Domain.Src { - primary := false - if i == 0 { - primary = true - } - ret = append(ret, cloudprovider.SBucketAccessUrl{ - Url: u, - Description: fmt.Sprintf("src%d", i), - Primary: primary, - }) - } - for i, u := range b.Domain.CDN { - ret = append(ret, cloudprovider.SBucketAccessUrl{ - Url: u, - Description: fmt.Sprintf("cdn%d", i), - }) - } - return ret -} - -func (b *SBucket) GetStats() cloudprovider.SBucketStats { - stats, _ := cloudprovider.GetIBucketStats(b) - return stats -} - -func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { - result := cloudprovider.SListObjectResult{} - - output, err := b.doPrefixFileList(prefix, marker, maxCount) - if err != nil { - return result, errors.Wrap(err, "b.doPrefixFileList") - } - - if len(output.NextMarker) > 0 { - result.NextMarker = output.NextMarker - result.IsTruncated = true - } - - result.Objects = make([]cloudprovider.ICloudObject, len(output.DataSet)) - for i := range output.DataSet { - result.Objects[i] = &output.DataSet[i] - } - - return result, nil -} - -func (b *SBucket) PutObject(ctx context.Context, key string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - return cloudprovider.ErrNotSupported -} - -func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { - return cloudprovider.ErrNotSupported -} - -func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { - return cloudprovider.ErrNotSupported -} - -func (b *SBucket) DeleteObject(ctx context.Context, key string) error { - file := SFile{ - bucket: b, - FileName: key, - } - return file.Delete() -} - -func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { - return "", cloudprovider.ErrNotSupported -} - -func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { - return cloudprovider.ErrNotSupported -} - -func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucketName string, srcKey string, srcOffset int64, srcLength int64) (string, error) { - return "", cloudprovider.ErrNotSupported -} diff --git a/pkg/multicloud/ucloud/vip.go b/pkg/multicloud/ucloud/vip.go deleted file mode 100644 index 56baaaa0ed..0000000000 --- a/pkg/multicloud/ucloud/vip.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVipAddr struct { - VIP string - SubnetId string -} - -func (ip *SVipAddr) GetIP() string { - return ip.VIP -} - -func (ip *SVipAddr) GetINetworkId() string { - return ip.SubnetId -} - -func (ip *SVipAddr) IsPrimary() bool { - return true -} - -func (ip *SVipAddr) GetGlobalId() string { - return ip.VIP -} - -type SVip struct { - multicloud.SNetworkInterfaceBase - multicloud.UcloudTags - region *SRegion - CreateTime int64 - Name string - RealIp string - Remark string - SubnetId string - Tag string - VIP string - VIPId string - VPCId string - Zone string -} - -func (vip *SVip) GetName() string { - if len(vip.Name) > 0 { - return vip.Name - } - return vip.VIPId -} - -func (vip *SVip) GetId() string { - return vip.VIPId -} - -func (vip *SVip) GetGlobalId() string { - return vip.VIPId -} - -func (vip *SVip) GetMacAddress() string { - ip, _ := netutils.NewIPV4Addr(vip.VIP) - return ip.ToMac("00:16:") -} - -func (vip *SVip) GetAssociateType() string { - return "" -} - -func (vip *SVip) GetAssociateId() string { - return "" -} - -func (vip *SVip) GetStatus() string { - return api.NETWORK_INTERFACE_STATUS_AVAILABLE -} - -func (vip *SVip) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { - ip := &SVipAddr{VIP: vip.VIP, SubnetId: vip.SubnetId} - return []cloudprovider.ICloudInterfaceAddress{ip}, nil -} - -func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { - vips, err := region.GetVips() - if err != nil { - return nil, errors.Wrap(err, "region.GetVips") - } - ret := []cloudprovider.ICloudNetworkInterface{} - for i := 0; i < len(vips); i++ { - vips[i].region = region - ret = append(ret, &vips[i]) - } - return ret, nil -} - -func (self *SRegion) GetVips() ([]SVip, error) { - vips := []SVip{} - params := NewUcloudParams() - - err := self.DoListAll("DescribeVIP", params, &vips) - return vips, err -} diff --git a/pkg/multicloud/ucloud/vpc.go b/pkg/multicloud/ucloud/vpc.go deleted file mode 100644 index b3e930543b..0000000000 --- a/pkg/multicloud/ucloud/vpc.go +++ /dev/null @@ -1,242 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "fmt" - "strings" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVPC struct { - multicloud.SVpc - multicloud.UcloudTags - - region *SRegion - - iwires []cloudprovider.ICloudWire - secgroups []cloudprovider.ICloudSecurityGroup - - CreateTime int64 `json:"CreateTime"` - Name string `json:"Name"` - Network []string `json:"Network"` - NetworkInfo []NetworkInfo `json:"NetworkInfo"` - SubnetCount int `json:"SubnetCount"` - Tag string `json:"Tag"` - UpdateTime int64 `json:"UpdateTime"` - VPCID string `json:"VPCId"` -} - -type NetworkInfo struct { - Network string `json:"Network"` - SubnetCount int `json:"SubnetCount"` -} - -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.Name) > 0 { - return self.Name - } - return self.VPCID -} - -func (self *SVPC) GetGlobalId() string { - return self.GetId() -} - -func (self *SVPC) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} - -func (self *SVPC) Refresh() error { - new, err := self.region.getVpc(self.GetId()) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SVPC) IsEmulated() bool { - return false -} - -func (self *SVPC) GetRegion() cloudprovider.ICloudRegion { - return self.region -} - -func (self *SVPC) GetIsDefault() bool { - return false -} - -func (self *SVPC) GetCidrBlock() string { - return strings.Join(self.Network, ",") -} - -func (self *SVPC) GetIWires() ([]cloudprovider.ICloudWire, error) { - if self.iwires == nil { - err := self.fetchNetworks() - if err != nil { - return nil, err - } - } - return self.iwires, nil -} - -// 由于Ucloud 安全组和vpc没有直接关联,这里是返回同一个项目下的防火墙列表,会导致重复同步的问题。 -// https://docs.ucloud.cn/api/unet-api/grant_firewall -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) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - rts := []cloudprovider.ICloudRouteTable{} - return rts, nil -} - -func (self *SVPC) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVPC) Delete() error { - return self.region.DeleteVpc(self.GetId()) -} - -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) fetchNetworks() error { - networks, err := self.region.GetNetworks(self.GetId()) - if err != nil { - return err - } - - for i := 0; i < len(networks); i += 1 { - wire := self.getWireByRegionId(self.region.GetId()) - networks[i].wire = wire - wire.addNetwork(&networks[i]) - } - - return nil -} - -func (self *SVPC) getWireByRegionId(regionId string) *SWire { - if len(regionId) == 0 { - return nil - } - - for i := 0; i < len(self.iwires); i++ { - wire := self.iwires[i].(*SWire) - - if wire.region.GetId() == regionId { - return wire - } - } - - return nil -} - -func (self *SRegion) getVpc(vpcId string) (*SVPC, error) { - vpcs, err := self.GetVpcs(vpcId) - if err != nil { - return nil, err - } - - if len(vpcs) == 1 { - return &vpcs[0], nil - } else if len(vpcs) == 0 { - return nil, cloudprovider.ErrNotFound - } else { - return nil, fmt.Errorf("getVpc %s %d found", vpcId, len(vpcs)) - } -} - -// https://docs.ucloud.cn/api/vpc2.0-api/delete_vpc -func (self *SRegion) DeleteVpc(vpcId string) error { - params := NewUcloudParams() - params.Set("VPCId", vpcId) - return self.DoAction("DeleteVPC", params, nil) -} - -// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html -func (self *SRegion) GetVpcs(vpcId string) ([]SVPC, error) { - vpcs := make([]SVPC, 0) - params := NewUcloudParams() - if len(vpcId) > 0 { - params.Set("VPCIds.0", vpcId) - } - - err := self.DoListAll("DescribeVPC", params, &vpcs) - return vpcs, err -} - -func (self *SRegion) GetNetworks(vpcId string) ([]SNetwork, error) { - params := NewUcloudParams() - if len(vpcId) > 0 { - params.Set("VPCId", vpcId) - } - - networks := make([]SNetwork, 0) - err := self.DoAction("DescribeSubnet", params, &networks) - return networks, err -} - -// UCLOUD 同一个项目共用安全组(防火墙) -func (self *SVPC) fetchSecurityGroups() error { - secgroups, err := self.region.GetSecurityGroups("", "", "") - if err != nil { - return err - } - - self.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) - for i := 0; i < len(secgroups); i++ { - secgroups[i].vpc = self - secgroups[i].region = self.region - self.secgroups[i] = &secgroups[i] - } - return nil -} diff --git a/pkg/multicloud/ucloud/wire.go b/pkg/multicloud/ucloud/wire.go deleted file mode 100644 index aa00a3c4c2..0000000000 --- a/pkg/multicloud/ucloud/wire.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// 子网在整个region可用 -type SWire struct { - multicloud.SResourceBase - multicloud.UcloudTags - region *SRegion - vpc *SVPC - - inetworks []cloudprovider.ICloudNetwork -} - -func (self *SWire) GetId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) -} - -func (self *SWire) GetName() string { - return self.GetId() -} - -func (self *SWire) GetGlobalId() string { - return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) -} - -func (self *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (self *SWire) Refresh() error { - return nil -} - -func (self *SWire) IsEmulated() bool { - return true -} - -func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { - return self.vpc -} - -func (self *SWire) GetIZone() cloudprovider.ICloudZone { - return nil -} - -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 -} - -// https://docs.ucloud.cn/api/vpc2.0-api/create_subnet -func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - return self.region.CreateNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc) -} - -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.GetId() { - find = true - break - } - } - if !find { - self.inetworks = append(self.inetworks, network) - } -} diff --git a/pkg/multicloud/ucloud/zone.go b/pkg/multicloud/ucloud/zone.go deleted file mode 100644 index 634a4eddcb..0000000000 --- a/pkg/multicloud/ucloud/zone.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 ucloud - -import ( - "fmt" - - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -// https://docs.ucloud.cn/api/udisk-api/create_udisk -// UDisk 类型: DataDisk(普通数据盘),SSDDataDisk(SSD数据盘),默认值(DataDisk) -var StorageTypes = []string{ - api.STORAGE_UCLOUD_CLOUD_NORMAL, - api.STORAGE_UCLOUD_CLOUD_SSD, - api.STORAGE_UCLOUD_LOCAL_NORMAL, // 本地盘 - api.STORAGE_UCLOUD_LOCAL_SSD, // 本地SSD盘 -} - -type SZone struct { - multicloud.SResourceBase - multicloud.UcloudTags - region *SRegion - host *SHost - - iwires []cloudprovider.ICloudWire - istorages []cloudprovider.ICloudStorage - - RegionId string - ZoneId 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, projectId: self.region.client.projectId} - } - 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) GetId() string { - return self.ZoneId -} - -func (self *SZone) GetName() string { - if name, exists := UCLOUD_ZONE_NAMES[self.GetId()]; exists { - return name - } - - return self.GetId() -} - -func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { - var en string - if name, exists := UCLOUD_ZONE_NAMES_EN[self.GetId()]; exists { - en = name - } else { - en = self.GetId() - } - - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) - return table -} - -func (self *SZone) GetGlobalId() string { - return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.GetId()) -} - -func (self *SZone) GetStatus() string { - return api.ZONE_ENABLE -} - -func (self *SZone) Refresh() error { - return nil -} - -func (self *SZone) IsEmulated() bool { - return false -} - -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 { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "fetchStorages") - } - } - return self.istorages, nil -} - -func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - if self.istorages == nil { - err := self.fetchStorages() - if err != nil { - return nil, errors.Wrapf(err, "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 -} - -// https://docs.ucloud.cn/api/uhost-api/describe_uhost_instance -func (self *SZone) GetInstances() ([]SInstance, error) { - return self.region.GetInstances(self.GetId(), "") -} - -func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { - return self.iwires, nil -} - -// https://docs.ucloud.cn/api/uhost-api/describe_uhost_instance -func (self *SRegion) GetInstances(zoneId string, instanceId string) ([]SInstance, error) { - instances := make([]SInstance, 0) - - params := NewUcloudParams() - if len(zoneId) > 0 { - params.Set("Zone", zoneId) - } - - if len(instanceId) > 0 { - params.Set("UHostIds.0", instanceId) - } - - err := self.DoListAll("DescribeUHostInstance", params, &instances) - return instances, err -} - -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) -} diff --git a/pkg/multicloud/zstack/disk.go b/pkg/multicloud/zstack/disk.go deleted file mode 100644 index 7cf316e608..0000000000 --- a/pkg/multicloud/zstack/disk.go +++ /dev/null @@ -1,419 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "context" - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SDisk struct { - multicloud.SDisk - multicloud.ZStackTags - - localStorage *SLocalStorage - storage *SStorage - region *SRegion - - ZStackBasic - PrimaryStorageUUID string `json:"primaryStorageUuid"` - VMInstanceUUID string `json:"vmInstanceUuid"` - DiskOfferingUUID string `json:"diskOfferingUuid"` - RootImageUUID string `json:"rootImageUuid"` - InstallPath string `json:"installPath"` - Type string `json:"type"` - Format string `json:"format"` - Size int `json:"size"` - ActualSize int `json:"actualSize"` - DeviceID float32 `json:"deviceId"` - State string `json:"state"` - Status string `json:"status"` - - ZStackTime -} - -func (region *SRegion) GetDisk(diskId string) (*SDisk, error) { - disk := &SDisk{region: region} - err := region.client.getResource("volumes", diskId, disk) - if err != nil { - return nil, err - } - if disk.Status == "NotInstantiated" || disk.Status == "Deleted" { - return nil, cloudprovider.ErrNotFound - } - return disk, nil -} - -func (region *SRegion) GetDiskWithStorage(diskId string) (*SDisk, error) { - disk, err := region.GetDisk(diskId) - if err != nil { - log.Errorf("Get Disk %s error: %v", diskId, err) - return nil, err - } - storage, err := region.GetStorage(disk.PrimaryStorageUUID) - if err != nil { - log.Errorf("Get primary storage %s error: %v", disk.PrimaryStorageUUID, err) - return nil, err - } - switch storage.Type { - case StorageTypeLocal: - if len(disk.VMInstanceUUID) > 0 { - instance, err := region.GetInstance(disk.VMInstanceUUID) - if err != nil { - return nil, err - } - hostId := instance.LastHostUUID - if len(hostId) == 0 { - hostId = instance.HostUUID - } - disk.localStorage = &SLocalStorage{region: region, primaryStorageID: storage.UUID, HostUUID: hostId} - return disk, nil - } - tags, err := region.GetResourceSysTags("", "VolumeVO", disk.UUID, "") - if err != nil { - log.Errorf("get disk tag error: %v", err) - return nil, err - } - for i := 0; i < len(tags); i++ { - if strings.HasPrefix(tags[i].Tag, "localStorage::hostUuid::") { - hostInfo := strings.Split(tags[i].Tag, "localStorage::hostUuid::") - if len(hostInfo) == 2 { - localStorage, err := region.GetLocalStorage(storage.UUID, hostInfo[1]) - if err != nil { - return nil, err - } - disk.localStorage = localStorage - return disk, nil - } - return nil, fmt.Errorf("invalid host info %s from disk %s", tags[i].Tag, disk.Name) - } - } - return nil, cloudprovider.ErrNotFound - case StorageTypeCeph: - disk.storage = storage - return disk, nil - default: - return nil, fmt.Errorf("Unsupport StorageType %s", storage.Type) - } -} - -func (region *SRegion) GetDisks(storageId string, diskIds []string, diskType string) ([]SDisk, error) { - disks := []SDisk{} - params := url.Values{} - params.Add("q", "status!=Deleted") - params.Add("q", "status!=NotInstantiated") - if len(storageId) > 0 { - params.Add("q", "primaryStorageUuid="+storageId) - } - if len(diskIds) > 0 { - params.Add("q", "uuid?="+strings.Join(diskIds, ",")) - } - if len(diskType) > 0 { - params.Add("q", "type="+diskType) - } - return disks, region.client.listAll("volumes", params, &disks) -} - -func (disk *SDisk) GetSysTags() map[string]string { - data := map[string]string{} - data["hypervisor"] = api.HYPERVISOR_ZSTACK - return data -} - -func (disk *SDisk) GetId() string { - return disk.UUID -} - -func (disk *SDisk) Delete(ctx context.Context) error { - if disk.Status == "Deleted" { - return disk.region.ExpungeDisk(disk.UUID) - } - return disk.region.DeleteDisk(disk.UUID) -} - -func (disk *SDisk) Resize(ctx context.Context, sizeMb int64) error { - return disk.region.ResizeDisk(disk.UUID, sizeMb) -} - -func (disk *SDisk) GetName() string { - return disk.Name -} - -func (disk *SDisk) GetGlobalId() string { - return disk.UUID -} - -func (disk *SDisk) IsEmulated() bool { - return false -} - -func (disk *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { - if disk.localStorage != nil { - return disk.localStorage, nil - } - if disk.storage != nil { - return disk.storage, nil - } - return nil, cloudprovider.ErrNotFound -} - -func (disk *SDisk) GetIStorageId() string { - storage, err := disk.region.GetStorage(disk.PrimaryStorageUUID) - if err != nil { - return disk.PrimaryStorageUUID - } else if storage.Type == StorageTypeLocal && len(disk.VMInstanceUUID) > 0 { - instnace, err := disk.region.GetInstance(disk.VMInstanceUUID) - if err != nil { - log.Warningf("failed to get instance %s for disk %s(%s) error: %v", disk.VMInstanceUUID, disk.Name, disk.UUID, err) - return "" - } - return fmt.Sprintf("%s/%s", disk.PrimaryStorageUUID, instnace.LastHostUUID) - } - return disk.PrimaryStorageUUID -} - -func (disk *SDisk) GetStatus() string { - switch disk.Status { - case "Ready": - return api.DISK_READY - case "NotInstantiated": - //数据云盘特有的状态。在这个连接状态中,数据云盘只存在于数据库的表记录中。NotInstantiated状态的数据云盘可以挂载到任何类型虚拟机管理程序管理的云主机上;当挂载到云主机上后,数据云盘的hypervisorType域会存储云主机对应的虚拟机管理程序类型,在主存储上被实例化为虚拟机管理程序类型的实际二进制文件,同时连接状态会改为就绪(Ready);在这之后,这些数据云盘就只能被重新挂载到相同类型虚拟机管理程序管理的云主机上了。 - return api.DISK_INIT - case "Creating": - return api.DISK_ALLOCATING - case "Deleted": - return api.DISK_DEALLOC - default: - log.Errorf("Unknown disk %s(%s) status %s", disk.Name, disk.UUID, disk.Status) - return api.DISK_UNKNOWN - } -} - -func (disk *SDisk) Refresh() error { - new, err := disk.region.GetDisk(disk.UUID) - if err != nil { - return err - } - return jsonutils.Update(disk, new) -} - -func (disk *SDisk) GetDiskFormat() string { - return disk.Format -} - -func (disk *SDisk) GetDiskSizeMB() int { - return disk.Size / 1024 / 1024 -} - -func (disk *SDisk) GetIsAutoDelete() bool { - return disk.GetDiskType() == api.DISK_TYPE_SYS || disk.localStorage != nil -} - -func (disk *SDisk) GetTemplateId() string { - return disk.RootImageUUID -} - -func (disk *SDisk) GetDiskType() string { - switch disk.Type { - case "Root": - return api.DISK_TYPE_SYS - default: - return api.DISK_TYPE_DATA - } -} - -func (disk *SDisk) GetFsFormat() string { - return "" -} - -func (disk *SDisk) GetIsNonPersistent() bool { - return false -} - -func (disk *SDisk) GetDriver() string { - return "scsi" -} - -func (disk *SDisk) GetCacheMode() string { - return "none" -} - -func (disk *SDisk) GetMountpoint() string { - return "" -} - -func (region *SRegion) CreateDisk(name string, storageId string, hostId string, poolName string, sizeGb int, desc string) (*SDisk, error) { - offerings, err := region.GetDiskOfferings(sizeGb) - if err != nil { - return nil, err - } - diskOfferingUuid := "" - if len(offerings) > 0 { - diskOfferingUuid = offerings[0].UUID - } else { - offering, err := region.CreateDiskOffering(sizeGb) - if err != nil { - return nil, err - } - diskOfferingUuid = offering.UUID - defer region.DeleteDiskOffering(diskOfferingUuid) - } - params := map[string]interface{}{ - "params": map[string]string{ - "name": name, - "description": desc, - "diskOfferingUuid": diskOfferingUuid, - "primaryStorageUuid": storageId, - }, - } - if len(hostId) > 0 { - params["systemTags"] = []string{"localStorage::hostUuid::" + hostId} - } - if len(poolName) > 0 { - params["systemTags"] = []string{"ceph::pool::" + poolName} - } - resp, err := region.client.post("volumes/data", jsonutils.Marshal(params)) - if err != nil { - return nil, err - } - disk := &SDisk{region: region} - return disk, resp.Unmarshal(disk, "inventory") -} - -func (region *SRegion) ExpungeDisk(diskId string) error { - params := map[string]interface{}{ - "expungeDataVolume": jsonutils.NewDict(), - } - _, err := region.client.put("volumes", diskId, jsonutils.Marshal(params)) - return err -} - -func (region *SRegion) DeleteDisk(diskId string) error { - err := region.client.delete("volumes", diskId, "Enforcing") - if err != nil { - return err - } - return region.ExpungeDisk(diskId) -} - -func (region *SRegion) ResizeDisk(diskId string, sizeMb int64) error { - disk, err := region.GetDisk(diskId) - if err != nil { - return err - } - - if disk.GetDiskSizeMB() == int(sizeMb) { - return nil - } - - params := jsonutils.Marshal(map[string]interface{}{ - fmt.Sprintf("resize%sVolume", disk.Type): map[string]int64{ - "size": sizeMb * 1024 * 1024, - }, - }) - resource := "volumes/resize" - if disk.Type == "Data" { - resource = "volumes/data/resize" - } - _, err = region.client.put(resource, diskId, params) - return err -} - -func (disk *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { - return disk.region.CreateSnapshot(name, disk.UUID, desc) -} - -func (disk *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - snapshots, err := disk.region.GetSnapshots(snapshotId, disk.UUID) - if err != nil { - return nil, err - } - if len(snapshots) == 1 { - if snapshots[0].UUID == snapshotId { - return &snapshots[0], nil - } - return nil, cloudprovider.ErrNotFound - } - if len(snapshots) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - return nil, cloudprovider.ErrNotFound -} - -func (disk *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := disk.region.GetSnapshots("", disk.UUID) - if err != nil { - return nil, err - } - isnapshots := []cloudprovider.ICloudSnapshot{} - for i := 0; i < len(snapshots); i++ { - isnapshots = append(isnapshots, &snapshots[i]) - } - return isnapshots, nil -} - -func (disk *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { - _, err := disk.region.ResetDisks(snapshotId) - return disk.UUID, err -} - -func (region *SRegion) ResetDisks(snapshotId string) (jsonutils.JSONObject, error) { - params := map[string]interface{}{ - "revertVolumeFromSnapshot": jsonutils.NewDict(), - } - return region.client.put("volume-snapshots", snapshotId, jsonutils.Marshal(params)) -} - -func (disk *SDisk) GetBillingType() string { - return "" -} - -func (disk *SDisk) GetExpiredAt() time.Time { - return time.Time{} -} - -func (disk *SDisk) GetCreatedAt() time.Time { - return disk.CreateDate -} - -func (disk *SDisk) GetAccessPath() string { - return disk.InstallPath -} - -func (disk *SDisk) Rebuild(ctx context.Context) error { - return disk.region.RebuildDisk(disk.UUID) -} - -func (region *SRegion) RebuildDisk(diskId string) error { - params := map[string]interface{}{ - "recoverDataVolume": jsonutils.NewDict(), - } - _, err := region.client.put("volumes", diskId, jsonutils.Marshal(params)) - return err -} - -func (disk *SDisk) GetProjectId() string { - return "" -} diff --git a/pkg/multicloud/zstack/doc.go b/pkg/multicloud/zstack/doc.go deleted file mode 100644 index ec6fff109e..0000000000 --- a/pkg/multicloud/zstack/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack // import "yunion.io/x/onecloud/pkg/multicloud/zstack" diff --git a/pkg/multicloud/zstack/eip.go b/pkg/multicloud/zstack/eip.go deleted file mode 100644 index 2732fb0569..0000000000 --- a/pkg/multicloud/zstack/eip.go +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "fmt" - "net/url" - "time" - - "yunion.io/x/jsonutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SEipAddress struct { - region *SRegion - multicloud.SEipBase - multicloud.ZStackTags - - ZStackBasic - VMNicUUID string `json:"vmNicUuid"` - VipUUID string `json:"vipUuid"` - State string `json:"state"` - VipIP string `json:"vipIp"` - GuestIP string `json:"guestIp"` - ZStackTime -} - -func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { - eip := &SEipAddress{region: region} - return eip, region.client.getResource("eips", eipId, eip) -} - -func (region *SRegion) GetEips(eipId, instanceId string) ([]SEipAddress, error) { - eips := []SEipAddress{} - params := url.Values{} - if len(eipId) > 0 { - params.Add("q", "uuid="+eipId) - } - if len(instanceId) > 0 { - params.Add("q", "vmNic.vmInstanceUuid="+instanceId) - } - err := region.client.listAll("eips", params, &eips) - if err != nil { - return nil, err - } - for i := 0; i < len(eips); i++ { - eips[i].region = region - } - return eips, nil -} - -func (eip *SEipAddress) GetId() string { - return eip.UUID -} - -func (eip *SEipAddress) GetName() string { - return eip.Name -} - -func (eip *SEipAddress) GetGlobalId() string { - return eip.UUID -} - -func (eip *SEipAddress) GetStatus() string { - return api.EIP_STATUS_READY -} - -func (eip *SEipAddress) Refresh() error { - new, err := eip.region.GetEip(eip.UUID) - if err != nil { - return err - } - return jsonutils.Update(eip, new) -} - -func (eip *SEipAddress) IsEmulated() bool { - return false -} - -func (eip *SEipAddress) GetIpAddr() string { - return eip.VipIP -} - -func (eip *SEipAddress) GetMode() string { - return api.EIP_MODE_STANDALONE_EIP -} - -func (eip *SEipAddress) GetAssociationType() string { - if len(eip.GetAssociationExternalId()) > 0 { - return api.EIP_ASSOCIATE_TYPE_SERVER - } - return "" -} - -func (eip *SEipAddress) GetAssociationExternalId() string { - if len(eip.VMNicUUID) > 0 { - instances, err := eip.region.GetInstances("", "", eip.VMNicUUID) - if err == nil && len(instances) == 1 { - return instances[0].UUID - } - } - return "" -} - -func (eip *SEipAddress) GetBillingType() string { - return "" -} - -func (eip *SEipAddress) GetCreatedAt() time.Time { - return eip.CreateDate -} - -func (eip *SEipAddress) GetExpiredAt() time.Time { - return time.Time{} -} - -func (eip *SEipAddress) Delete() error { - return eip.region.DeleteVirtualIP(eip.VipUUID) -} - -func (eip *SEipAddress) GetBandwidth() int { - return 0 -} - -func (eip *SEipAddress) GetINetworkId() string { - vip, err := eip.region.GetVirtualIP(eip.VipUUID) - if err == nil { - return eip.region.GetNetworkId(vip) - } - return "" -} - -func (eip *SEipAddress) GetInternetChargeType() string { - return api.EIP_CHARGE_TYPE_BY_TRAFFIC -} - -func (eip *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { - return eip.region.AssociateEip(conf.InstanceId, eip.UUID) -} - -func (eip *SEipAddress) Dissociate() error { - return eip.region.DisassociateEip(eip.UUID) -} - -func (eip *SEipAddress) ChangeBandwidth(bw int) error { - return cloudprovider.ErrNotSupported -} - -func (eip *SEipAddress) GetProjectId() string { - return "" -} - -func (region *SRegion) CreateEip(name string, vipId string, desc string) (*SEipAddress, error) { - params := map[string]map[string]string{ - "params": { - "name": name, - "description": desc, - "vipUuid": vipId, - }, - } - eip := &SEipAddress{region: region} - resp, err := region.client.post("eips", jsonutils.Marshal(params)) - if err != nil { - return nil, err - } - return eip, resp.Unmarshal(eip, "inventory") -} - -func (region *SRegion) AssociateEip(instanceId, eipId string) error { - instance, err := region.GetInstance(instanceId) - if err != nil { - return err - } - if len(instance.VMNics) == 0 { - return fmt.Errorf("instance %s does not have any nic", instance.Name) - } - resource := fmt.Sprintf("eips/%s/vm-instances/nics/%s", eipId, instance.VMNics[0].UUID) - params := map[string]interface{}{ - "params": jsonutils.NewDict(), - } - _, err = region.client.post(resource, jsonutils.Marshal(params)) - return err -} - -func (region *SRegion) DisassociateEip(eipId string) error { - resource := fmt.Sprintf("eips/%s/vm-instances/nics", eipId) - return region.client.delete(resource, "", "") -} diff --git a/pkg/multicloud/zstack/host.go b/pkg/multicloud/zstack/host.go deleted file mode 100644 index d57cacf1a7..0000000000 --- a/pkg/multicloud/zstack/host.go +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "fmt" - "net/url" - "strings" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SHost struct { - multicloud.SHostBase - zone *SZone - - ZStackBasic - Username string `json:"username"` - SSHPort int `json:"sshPort"` - ZoneUUID string `json:"zoneUuid"` - ClusterUUID string `json:"clusterUuid"` - ManagementIP string `json:"managementIp"` - HypervisorType string `json:"hypervisorType"` - State string `json:"state"` - Status string `json:"status"` - TotalCPUCapacity int `json:"totalCpuCapacity"` - AvailableCPUCapacity int `json:"availableCpuCapacity"` - CPUSockets int `json:"cpuSockets"` - TotalMemoryCapacity int `json:"totalMemoryCapacity"` - AvailableMemoryCapacity int `json:"availableMemoryCapacity"` - CPUNum int `json:"cpuNum"` - ZStackTime -} - -func (region *SRegion) GetHosts(zoneId string, hostId string) ([]SHost, error) { - hosts := []SHost{} - params := url.Values{} - if len(zoneId) > 0 { - params.Add("q", "zone.uuid="+zoneId) - } - if len(hostId) > 0 { - params.Add("q", "uuid="+hostId) - } - if SkipEsxi { - params.Add("q", "hypervisorType!=ESX") - } - return hosts, region.client.listAll("hosts", params, &hosts) -} - -func (region *SRegion) GetHost(hostId string) (*SHost, error) { - host := &SHost{} - err := region.client.getResource("hosts", hostId, host) - if err != nil { - return nil, err - } - zone, err := region.GetZone(host.ZoneUUID) - if err != nil { - return nil, err - } - host.zone = zone - return host, nil -} - -func (host *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { - wires, err := host.zone.region.GetWires(host.ZoneUUID, "", host.ClusterUUID) - if err != nil { - return nil, err - } - iwires := []cloudprovider.ICloudWire{} - for i := 0; i < len(wires); i++ { - iwires = append(iwires, &wires[i]) - } - return iwires, nil -} - -func (host *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - storages, err := host.zone.region.GetStorages(host.zone.UUID, host.ClusterUUID, "") - if err != nil { - return nil, err - } - istorages := []cloudprovider.ICloudStorage{} - for i := 0; i < len(storages); i++ { - storages[i].region = host.zone.region - switch storages[i].Type { - case StorageTypeLocal: - localStorages, err := host.zone.region.getILocalStorages(storages[i].UUID, host.UUID) - if err != nil { - return nil, err - } - istorages = append(istorages, localStorages...) - case StorageTypeCeph: - istorages = append(istorages, &storages[i]) - case StorageTypeVCenter: - } - } - return istorages, nil -} - -func (host *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - return host.zone.GetIStorageById(id) -} - -func (host *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { - instances, err := host.zone.region.GetInstances(host.UUID, "", "") - if err != nil { - return nil, err - } - iInstnace := []cloudprovider.ICloudVM{} - for i := 0; i < len(instances); i++ { - instances[i].host = host - iInstnace = append(iInstnace, &instances[i]) - } - return iInstnace, nil -} - -func (host *SHost) GetIVMById(instanceId string) (cloudprovider.ICloudVM, error) { - instance, err := host.zone.region.GetInstance(instanceId) - if err != nil { - return nil, err - } - instance.host = host - return instance, nil -} - -func (host *SHost) GetId() string { - return host.UUID -} - -func (host *SHost) GetName() string { - return host.Name -} - -func (host *SHost) GetGlobalId() string { - return host.GetId() -} - -func (host *SHost) IsEmulated() bool { - return false -} - -func (host *SHost) GetStatus() string { - if host.Status == "Connected" { - return api.HOST_STATUS_RUNNING - } - return api.HOST_STATUS_UNKNOWN -} - -func (host *SHost) Refresh() error { - return nil -} - -func (host *SHost) GetHostStatus() string { - if host.Status == "Connected" { - return api.HOST_ONLINE - } - return api.HOST_OFFLINE -} - -func (host *SHost) GetEnabled() bool { - return host.State == "Enabled" -} - -func (host *SHost) GetAccessIp() string { - return host.ManagementIP -} - -func (host *SHost) GetAccessMac() string { - return "" -} - -func (host *SHost) GetSysInfo() jsonutils.JSONObject { - info := jsonutils.NewDict() - info.Add(jsonutils.NewString(CLOUD_PROVIDER_ZSTACK), "manufacture") - return info -} - -func (host *SHost) GetSN() string { - return "" -} - -func (host *SHost) GetReservedMemoryMb() int { - host.zone.fetchHostCmtbound() - return host.zone.reservedMemeoryMb -} - -func (host *SHost) GetCpuCmtbound() float32 { - host.zone.fetchHostCmtbound() - return host.zone.cpuCmtbound -} - -func (host *SHost) GetMemCmtbound() float32 { - host.zone.fetchHostCmtbound() - return host.zone.memCmtbound -} - -func (host *SHost) GetCpuCount() int { - cpuCmtBound := host.GetCpuCmtbound() - if cpuCmtBound > 0 { - return int(float32(host.TotalCPUCapacity) / cpuCmtBound) - } - return host.TotalCPUCapacity -} - -func (host *SHost) GetNodeCount() int8 { - return int8(host.CPUSockets) -} - -func (host *SHost) GetCpuDesc() string { - return "" -} - -func (host *SHost) GetCpuMhz() int { - return 0 -} - -func (host *SHost) GetMemSizeMB() int { - return host.TotalMemoryCapacity / 1024 / 1024 -} - -func (host *SHost) GetStorageSizeMB() int { - storages, err := host.zone.region.GetStorages(host.zone.UUID, host.ClusterUUID, "") - if err != nil { - return 0 - } - totalStorage := 0 - for _, storage := range storages { - if storage.Type == StorageTypeLocal { - localStorages, err := host.zone.region.GetLocalStorages(storage.UUID, host.UUID) - if err != nil { - return 0 - } - for i := 0; i < len(localStorages); i++ { - totalStorage += int(localStorages[i].TotalCapacity) - } - } - } - return totalStorage / 1024 / 1024 -} - -func (host *SHost) GetStorageType() string { - return api.DISK_TYPE_HYBRID -} - -func (host *SHost) GetHostType() string { - return api.HOST_TYPE_ZSTACK -} - -func (region *SRegion) cleanDisks(diskIds []string) { - for i := 0; i < len(diskIds); i++ { - err := region.DeleteDisk(diskIds[i]) - if err != nil { - log.Errorf("clean disk %s error: %v", diskIds[i], err) - } - } -} - -func (region *SRegion) createDataDisks(disks []cloudprovider.SDiskInfo, hostId string) ([]string, error) { - diskIds := []string{} - - storages, err := region.GetStorages("", "", "") - if err != nil { - return nil, errors.Wrapf(err, "createDataDisks.GetStorages") - } - - localstorages := []SLocalStorage{} - - for _, storage := range storages { - if storage.Type == StorageTypeLocal { - localstorage, _ := region.GetLocalStorage(storage.UUID, hostId) - if localstorage != nil { - localstorages = append(localstorages, *localstorage) - } - } - } - - for i := 0; i < len(disks); i++ { - storageInfo := strings.Split(disks[i].StorageExternalId, "/") - if len(storageInfo) == 0 { - return diskIds, fmt.Errorf("invalidate storage externalId: %s", disks[i].StorageExternalId) - } - storage, err := region.GetStorage(storageInfo[0]) - if err != nil { - return diskIds, errors.Wrapf(err, "createDataDisks") - } - - switch storage.Type { - case StorageTypeCeph: - poolName := "" - for _, pool := range storage.Pools { - if pool.Type == CephPoolTypeData { - poolName = pool.PoolName - } - } - if len(poolName) == 0 { - return diskIds, fmt.Errorf("failed to found ceph data pool for storage %s to createDataDisk", storage.Name) - } - disk, err := region.CreateDisk(disks[i].Name, storage.UUID, "", poolName, disks[i].SizeGB, "") - if err != nil { - return diskIds, err - } - diskIds = append(diskIds, disk.UUID) - case StorageTypeLocal: - if len(localstorages) == 0 { - return nil, fmt.Errorf("No validate localstorage") - } - var disk *SDisk - var err error - for _, localstorage := range localstorages { - disk, err = region.CreateDisk(disks[i].Name, localstorage.primaryStorageID, hostId, "", disks[i].SizeGB, "") - if err != nil { - log.Warningf("createDataDisks error: %v", err) - } else { - diskIds = append(diskIds, disk.UUID) - break - } - } - if err != nil { - return diskIds, err - } - default: - return diskIds, fmt.Errorf("not support storageType %s", disks[i].StorageType) - } - } - return diskIds, nil -} - -func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { - instance, err := host.zone.region._createVM(desc, host.ZoneUUID) - if err != nil { - return nil, errors.Wrapf(err, "host.zone.region._createVM") - } - - diskIds, err := host.zone.region.createDataDisks(desc.DataDisks, instance.HostUUID) - if err != nil { - defer host.zone.region.cleanDisks(diskIds) - defer host.zone.region.DeleteVM(instance.UUID) - return nil, errors.Wrapf(err, "host.zone.region.createDataDisks") - } - - err = host.zone.region.ResizeDisk(instance.RootVolumeUUID, int64(desc.SysDisk.SizeGB)*1024) - if err != nil { - log.Warningf("failed to resize system disk %s error: %v", instance.RootVolumeUUID, err) - } - - for i := 0; i < len(diskIds); i++ { - err = host.zone.region.AttachDisk(instance.UUID, diskIds[i]) - if err != nil { - log.Errorf("failed to attach disk %s into instance %s error: %v", diskIds[i], instance.Name, err) - } - } - err = host.zone.region.AssignSecurityGroup(instance.UUID, desc.ExternalSecgroupId) - if err != nil { - return nil, err - } - return host.GetIVMById(instance.UUID) -} - -func (region *SRegion) _createVM(desc *cloudprovider.SManagedVMCreateConfig, zoneId string) (*SInstance, error) { - l3Id := strings.Split(desc.ExternalNetworkId, "/")[0] - if len(l3Id) == 0 { - return nil, fmt.Errorf("invalid networkid: %s", desc.ExternalNetworkId) - } - _, err := region.GetL3Network(l3Id) - if err != nil { - log.Errorf("failed to found l3network %s error: %v", l3Id, err) - return nil, err - } - offerings := map[string]string{} - if len(desc.InstanceType) > 0 { - offering, err := region.GetInstanceOfferingByType(desc.InstanceType) - if err != nil { - if errors.Cause(err) == cloudprovider.ErrNotFound { - offering, err = region.CreateInstanceOffering(desc.InstanceType, desc.Cpu, desc.MemoryMB, "UserVm") - if err != nil { - return nil, err - } - } else { - return nil, err - } - } - offerings[offering.Name] = offering.UUID - } else { - _offerings, err := region.GetInstanceOfferings("", "", desc.Cpu, desc.MemoryMB) - if err != nil { - return nil, err - } - for _, offering := range _offerings { - offerings[offering.Name] = offering.UUID - } - if len(offerings) == 0 { - return nil, fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB) - } - } - return region.CreateInstance(desc, l3Id, zoneId, offerings) -} - -func (region *SRegion) CreateInstance(desc *cloudprovider.SManagedVMCreateConfig, l3Id, zoneId string, offerings map[string]string) (*SInstance, error) { - instance := &SInstance{} - systemTags := []string{ - "createWithoutCdRom::true", - "usbRedirect::false", - "vmConsoleMode::vnc", - "cleanTraffic::false", - } - if len(desc.IpAddr) > 0 { - systemTags = append(systemTags, fmt.Sprintf("staticIp::%s::%s", l3Id, desc.IpAddr)) - } - if len(desc.UserData) > 0 { - systemTags = append(systemTags, "userdata::"+desc.UserData) - } - if len(desc.PublicKey) > 0 { - systemTags = append(systemTags, "sshkey::"+desc.PublicKey) - } - var err error - for offerName, offerId := range offerings { - params := map[string]interface{}{ - "params": map[string]interface{}{ - "name": desc.NameEn, - "description": desc.Description, - "instanceOfferingUuid": offerId, - "imageUuid": desc.ExternalImageId, - "l3NetworkUuids": []string{ - l3Id, - }, - "zoneUuid": zoneId, - "dataVolumeSystemTags": []string{}, - "rootVolumeSystemTags": []string{}, - "vmMachineType": "", - "tagUuids": []string{}, - "defaultL3NetworkUuid": l3Id, - "dataDiskOfferingUuids": []string{}, - "systemTags": systemTags, - "vmNicConfig": []string{}, - }, - } - - log.Debugf("Try instanceOffering : %s", offerName) - err = region.client.create("vm-instances", jsonutils.Marshal(params), instance) - if err == nil { - return instance, nil - } - log.Errorf("create %s instance failed error: %v", offerName, err) - } - if err != nil { - return nil, err - } - return nil, fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB) -} - -func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (host *SHost) GetIsMaintenance() bool { - return false -} - -func (host *SHost) GetVersion() string { - return "" -} diff --git a/pkg/multicloud/zstack/image.go b/pkg/multicloud/zstack/image.go deleted file mode 100644 index 3a0173151b..0000000000 --- a/pkg/multicloud/zstack/image.go +++ /dev/null @@ -1,303 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "context" - "fmt" - "io" - "net/http" - "net/url" - "sort" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/httputils" - "yunion.io/x/onecloud/pkg/util/imagetools" - "yunion.io/x/onecloud/pkg/util/multipart" -) - -type SBackupStorageRef struct { - BackupStorageUUID string `json:"backupStorageUuid"` - CreateDate time.Time `json:"createDate"` - ImageUUID string `json:"ImageUuid"` - InstallPath string `json:"installPath"` - LastOpDate time.Time `json:"lastOpDate"` - Status string `json:"status"` -} - -type SImage struct { - multicloud.SImageBase - multicloud.ZStackTags - storageCache *SStoragecache - - // normalized image info - imgInfo *imagetools.ImageInfo - - BackupStorageRefs []SBackupStorageRef `json:"backupStorageRefs"` - ActualSize int `json:"actualSize"` - CreateDate time.Time `json:"createDate"` - Description string `json:"description"` - Format string `json:"format"` - LastOpDate time.Time `json:"lastOpDate"` - MD5Sum string `json:"md5sum"` - MediaType string `json:"mediaType"` - Name string `json:"name"` - Platform string `json:"platform"` - Size int `json:"size"` - State string `json:"state"` - Status string `json:"Ready"` - System bool `json:"system"` - Type string `json:"type"` - URL string `json:"url"` - UUID string `json:"uuid"` -} - -func (image *SImage) GetMinRamSizeMb() int { - return 0 -} - -func (image *SImage) GetId() string { - return image.UUID -} - -func (image *SImage) GetName() string { - return image.Name -} - -func (image *SImage) IsEmulated() bool { - return false -} - -func (image *SImage) Delete(ctx context.Context) error { - return image.storageCache.region.DeleteImage(image.UUID) -} - -func (image *SImage) GetGlobalId() string { - return image.UUID -} - -func (region *SRegion) DeleteImage(imageId string) error { - err := region.client.delete("images", imageId, "") - if err != nil { - return err - } - params := map[string]interface{}{ - "expungeImage": jsonutils.NewDict(), - } - _, err = region.client.put("images", imageId, jsonutils.Marshal(params)) - return err -} - -func (image *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return image.storageCache -} - -func (image *SImage) GetStatus() string { - if image.State != "Enabled" { - return api.CACHED_IMAGE_STATUS_CACHING - } - switch image.Status { - case "Ready": - return api.CACHED_IMAGE_STATUS_ACTIVE - case "Downloading": - return api.CACHED_IMAGE_STATUS_CACHING - case "Deleted": - return api.CACHED_IMAGE_STATUS_DELETING - default: - log.Errorf("Unknown image status: %s", image.Status) - return api.CACHED_IMAGE_STATUS_CACHE_FAILED - } -} - -func (image *SImage) GetImageStatus() string { - switch image.Status { - case "Ready": - return cloudprovider.IMAGE_STATUS_ACTIVE - case "Deleted": - return cloudprovider.IMAGE_STATUS_DELETED - default: - return cloudprovider.IMAGE_STATUS_KILLED - } -} - -func (image *SImage) Refresh() error { - new, err := image.storageCache.region.GetImage(image.UUID) - if err != nil { - return err - } - return jsonutils.Update(image, new) -} - -func (image *SImage) GetImageType() cloudprovider.TImageType { - return cloudprovider.ImageTypeSystem -} - -func (image *SImage) GetSizeByte() int64 { - return int64(image.Size) -} - -func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { - if self.imgInfo == nil { - imgInfo := imagetools.NormalizeImageInfo(self.URL, "", self.Platform, self.Platform, "") - self.imgInfo = &imgInfo - } - - return self.imgInfo -} - -func (image *SImage) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(image.getNormalizedImageInfo().OsType) -} - -func (image *SImage) GetOsDist() string { - return image.getNormalizedImageInfo().OsDistro -} - -func (image *SImage) GetOsVersion() string { - return image.getNormalizedImageInfo().OsVersion -} - -func (image *SImage) GetOsArch() string { - return image.getNormalizedImageInfo().OsArch -} - -func (image *SImage) GetBios() cloudprovider.TBiosType { - return cloudprovider.TBiosType(image.getNormalizedImageInfo().OsBios) -} - -func (image *SImage) GetOsLang() string { - return image.getNormalizedImageInfo().OsLang -} - -func (image *SImage) GetFullOsName() string { - return image.URL -} - -func (image *SImage) GetMinOsDiskSizeGb() int { - return image.Size / 1024 / 1024 / 1024 -} - -func (image *SImage) GetImageFormat() string { - return image.Format -} - -func (image *SImage) GetCreatedAt() time.Time { - return image.CreateDate -} - -func (region *SRegion) GetImage(imageId string) (*SImage, error) { - image := &SImage{} - err := region.client.getResource("images", imageId, image) - if err != nil { - return nil, errors.Wrapf(err, "region.GetImage") - } - return image, nil -} - -func (region *SRegion) GetImages(zoneId string, imageId string) ([]SImage, error) { - images := []SImage{} - params := url.Values{} - params.Add("q", "system=false") - if len(zoneId) > 0 { - params.Add("q", "backupStorage.zone.uuid="+zoneId) - } - if len(imageId) > 0 { - params.Add("q", "uuid="+imageId) - } - if SkipEsxi { - params.Add("q", "type!=vmware") - } - return images, region.client.listAll("images", params, &images) -} - -func (region *SRegion) GetBackupStorageUUID(zondId string) ([]string, error) { - imageServers, err := region.GetImageServers(zondId, "") - if err != nil { - return nil, err - } - if len(imageServers) == 0 { - return nil, fmt.Errorf("failed to found any image servers") - } - servers := ImageServers(imageServers) - sort.Sort(servers) - return []string{servers[0].UUID}, nil -} - -func (region *SRegion) CreateImage(zoneId string, imageName, format, osType, desc string, reader io.Reader, size int64, callback func(progress float32)) (*SImage, error) { - backupStorageUUIDs, err := region.GetBackupStorageUUID(zoneId) - if err != nil { - return nil, err - } - platform := "" - switch osType { - case "linux": - platform = "Linux" - case "windows": - platform = "Windows" - default: - platform = "Other" - } - parmas := map[string]interface{}{ - "params": map[string]interface{}{ - "name": imageName, - "url": fmt.Sprintf("upload://%s", imageName), - "description": desc, - "mediaType": "RootVolumeTemplate", - "system": false, - "format": format, - "platform": platform, - "backupStorageUuids": backupStorageUUIDs, - "systemTags": []string{"qemuga", "bootMode::Legacy"}, - }, - } - - if reader == nil { - return nil, fmt.Errorf("invalid reader") - } - - if size == 0 { - return nil, fmt.Errorf("invalid image size") - } - - body := multipart.NewReader(reader, "", imageName) - - image := &SImage{} - err = region.client.create("images", jsonutils.Marshal(parmas), image) - if err != nil { - return nil, err - } - - if len(image.BackupStorageRefs) < 0 { - return nil, fmt.Errorf("no InstallPath reture") - } - header := http.Header{} - header.Add("X-IMAGE-UUID", image.UUID) - header.Add("X-IMAGE-SIZE", fmt.Sprintf("%d", size)) - header.Add("Content-Type", body.FormDataContentType()) - r := multicloud.NewProgress(size, 99, body, callback) - resp, err := httputils.Request(httputils.GetTimeoutClient(0), context.Background(), "POST", image.BackupStorageRefs[0].InstallPath, header, r, false) - if err != nil { - return nil, err - } - defer resp.Body.Close() - return image, nil -} diff --git a/pkg/multicloud/zstack/instance.go b/pkg/multicloud/zstack/instance.go deleted file mode 100644 index f09ef90ee1..0000000000 --- a/pkg/multicloud/zstack/instance.go +++ /dev/null @@ -1,689 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "context" - "fmt" - "net/url" - "strings" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/utils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/billing" - "yunion.io/x/onecloud/pkg/util/imagetools" - "yunion.io/x/onecloud/pkg/util/version" -) - -type SInstanceCdrome struct { -} - -type SInstance struct { - multicloud.SInstanceBase - multicloud.ZStackTags - host *SHost - - osInfo *imagetools.ImageInfo - - ZStackBasic - ZoneUUID string `json:"zoneUuid"` - ClusterUUID string `json:"clusterUuid"` - HostUUID string `json:"hostUuid"` - LastHostUUID string `json:"lastHostUuid"` - RootVolumeUUID string `json:"rootVolumeUuid"` - Platform string `json:"platform"` - InstanceOfferingUUID string `json:"instanceOfferingUuid"` - - DefaultL3NetworkUUID string `json:"defaultL3NetworkUuid"` - Type string `json:"type"` - HypervisorType string `json:"hypervisorType"` - MemorySize int `json:"memorySize"` - CPUNum int `json:"cpuNum"` - CPUSpeed int `json:"cpuSpeed"` - State string `json:"state"` - InternalID string `json:"internalId"` - VMNics []SInstanceNic `json:"vmNics"` - AllVolumes []SDisk `json:"allVolumes"` - VMCdRoms []SInstanceCdrome `json:"vmCdRoms"` - ZStackTime -} - -func (region *SRegion) GetInstance(instanceId string) (*SInstance, error) { - instance := &SInstance{} - err := region.client.getResource("vm-instances", instanceId, instance) - if err != nil { - return nil, err - } - if instance.State == "Destroyed" { - return nil, cloudprovider.ErrNotFound - } - return instance, nil -} - -func (region *SRegion) GetInstances(hostId string, instanceId string, nicId string) ([]SInstance, error) { - instance := []SInstance{} - params := url.Values{} - params.Add("q", "type=UserVm") - params.Add("q", "state!=Destroyed") - if len(hostId) > 0 { - params.Add("q", "lastHostUuid="+hostId) - } - if len(instanceId) > 0 { - params.Add("q", "uuid="+instanceId) - } - if len(nicId) > 0 { - params.Add("q", "vmNics.uuid="+nicId) - } - if SkipEsxi { - params.Add("q", "hypervisorType!=ESX") - } - return instance, region.client.listAll("vm-instances", params, &instance) -} - -func (instance *SInstance) GetSecurityGroupIds() ([]string, error) { - ids := []string{} - secgroups, err := instance.host.zone.region.GetSecurityGroups("", instance.UUID, "") - if err != nil { - return nil, err - } - for _, secgroup := range secgroups { - ids = append(ids, secgroup.UUID) - } - return ids, nil -} - -func (instance *SInstance) GetIHost() cloudprovider.ICloudHost { - return instance.host -} - -func (instance *SInstance) GetIHostId() string { - if len(instance.LastHostUUID) > 0 { - return instance.LastHostUUID - } - return instance.HostUUID -} - -func (instance *SInstance) GetId() string { - return instance.UUID -} - -func (instance *SInstance) GetName() string { - return instance.Name -} - -func (instance *SInstance) GetHostname() string { - return instance.Name -} - -func (instance *SInstance) GetGlobalId() string { - return instance.GetId() -} - -func (instance *SInstance) IsEmulated() bool { - return false -} - -func (instance *SInstance) GetInstanceType() string { - if len(instance.InstanceOfferingUUID) > 0 { - offer, err := instance.host.zone.region.GetInstanceOffering(instance.InstanceOfferingUUID) - if err == nil { - return offer.Name - } - } - return instance.Type -} - -func (instance *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - idisks := []cloudprovider.ICloudDisk{} - rootDisk, err := instance.host.zone.region.GetDiskWithStorage(instance.RootVolumeUUID) - if err != nil { - return nil, err - } - idisks = append(idisks, rootDisk) - for i := 0; i < len(instance.AllVolumes); i++ { - if instance.AllVolumes[i].UUID != instance.RootVolumeUUID { - dataDisk, err := instance.host.zone.region.GetDiskWithStorage(instance.AllVolumes[i].UUID) - if err != nil { - return nil, err - } - idisks = append(idisks, dataDisk) - } - } - return idisks, nil -} - -func (instance *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { - iNics := []cloudprovider.ICloudNic{} - for i := 0; i < len(instance.VMNics); i++ { - instance.VMNics[i].instance = instance - iNics = append(iNics, &instance.VMNics[i]) - } - return iNics, nil -} - -func (instance *SInstance) GetVcpuCount() int { - return instance.CPUNum -} - -func (instance *SInstance) GetVmemSizeMB() int { - return instance.MemorySize / 1024 / 1024 -} - -func (instance *SInstance) GetBootOrder() string { - return instance.host.zone.region.GetBootOrder(instance.UUID) -} - -func (region *SRegion) GetBootOrder(instanceId string) string { - resp, err := region.client.get("vm-instances", instanceId, "boot-orders") - if err != nil { - return "dcn" - } - orders := []string{} - err = resp.Unmarshal(&orders, "orders") - if err != nil { - return "dcn" - } - order := "" - for _, _order := range orders { - switch _order { - case "CdRom": - order += "c" - case "HardDisk": - order += "d" - default: - log.Errorf("Unknown BootOrder %s for instance %s", _order, instanceId) - } - } - return order -} - -func (instance *SInstance) GetVga() string { - return "std" -} - -func (instance *SInstance) GetVdi() string { - return "vnc" -} - -func (instance *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { - if instance.osInfo == nil { - osInfo := imagetools.NormalizeImageInfo(instance.Platform, "", "", "", "") - instance.osInfo = &osInfo - } - return instance.osInfo -} - -func (instance *SInstance) GetOsType() cloudprovider.TOsType { - return cloudprovider.TOsType(instance.getNormalizedOsInfo().OsType) -} - -func (instance *SInstance) GetFullOsName() string { - return instance.Platform -} - -func (instance *SInstance) GetBios() cloudprovider.TBiosType { - return cloudprovider.ToBiosType(instance.getNormalizedOsInfo().OsBios) -} - -func (instance *SInstance) GetOsDist() string { - return instance.getNormalizedOsInfo().OsDistro -} - -func (instance *SInstance) GetOsVersion() string { - return instance.getNormalizedOsInfo().OsVersion -} - -func (instance *SInstance) GetOsLang() string { - return instance.getNormalizedOsInfo().OsLang -} - -func (instance *SInstance) GetOsArch() string { - return instance.getNormalizedOsInfo().OsArch -} - -func (instance *SInstance) GetMachine() string { - return "pc" -} - -func (instance *SInstance) GetStatus() string { - switch instance.State { - case "Stopped": - return api.VM_READY - case "Running": - return api.VM_RUNNING - case "Destroyed": - return api.VM_DEALLOCATED - default: - log.Errorf("Unknown instance %s status %s", instance.Name, instance.State) - return api.VM_UNKNOWN - } -} - -func (instance *SInstance) Refresh() error { - new, err := instance.host.zone.region.GetInstance(instance.UUID) - if err != nil { - return err - } - return jsonutils.Update(instance, new) -} - -func (instance *SInstance) GetHypervisor() string { - return api.HYPERVISOR_ZSTACK -} - -func (instance *SInstance) StartVM(ctx context.Context) error { - err := instance.host.zone.region.StartVM(instance.UUID) - if err != nil { - return err - } - return cloudprovider.WaitStatus(instance, api.VM_RUNNING, 5*time.Second, 5*time.Minute) -} - -func (region *SRegion) StartVM(instanceId string) error { - params := map[string]interface{}{ - "startVmInstance": jsonutils.NewDict(), - } - _, err := region.client.put("vm-instances", instanceId, jsonutils.Marshal(params)) - return err -} - -func (instance *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { - err := instance.host.zone.region.StopVM(instance.UUID, opts.IsForce) - if err != nil { - return err - } - return cloudprovider.WaitStatus(instance, api.VM_READY, 5*time.Second, 5*time.Minute) -} - -func (region *SRegion) StopVM(instanceId string, isForce bool) error { - option := "grace" - if isForce { - option = "cold" - } - params := map[string]interface{}{ - "stopVmInstance": map[string]string{ - "type": option, - "stopHA": "true", - }, - } - _, err := region.client.put("vm-instances", instanceId, jsonutils.Marshal(params)) - return err -} - -func (instance *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { - info, err := instance.host.zone.region.GetInstanceConsoleInfo(instance.UUID) - if err != nil { - return nil, err - } - authURL, _ := url.Parse(instance.host.zone.region.client.authURL) - url := fmt.Sprintf("%s://%s:5000/thirdparty/vnc_auto.html?host=%s&port=%d&token=%s&title=%s", info.Scheme, authURL.Hostname(), info.Hostname, info.Port, info.Token, instance.Name) - if ver, _ := instance.host.zone.region.client.GetVersion(); ver != nil { - if version.GE(ver.Version, "4.0.0") { - url = fmt.Sprintf("%s://%s:5000/novnc/index.html?host=%s&port=%d&token=%s&title=%s&language=zh-CN&lowVersion=false", info.Scheme, authURL.Hostname(), info.Hostname, info.Port, info.Token, instance.Name) - } - } - password, _ := instance.host.zone.region.GetInstanceConsolePassword(instance.UUID) - if len(password) > 0 { - url = url + fmt.Sprintf("&password=%s", password) - } - ret := &cloudprovider.ServerVncOutput{ - Url: url, - Protocol: "zstack", - InstanceId: instance.UUID, - Hypervisor: api.HYPERVISOR_ZSTACK, - } - return ret, nil -} - -func (instance *SInstance) UpdateVM(ctx context.Context, name string) error { - params := map[string]interface{}{ - "updateVmInstance": map[string]string{ - "name": name, - }, - } - return instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params)) -} - -func (region *SRegion) UpdateVM(instanceId string, params jsonutils.JSONObject) error { - _, err := region.client.put("vm-instances", instanceId, params) - return err -} - -func (instance *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { - if instance.Name != name || instance.Description != description { - params := map[string]interface{}{ - "updateVmInstance": map[string]string{ - "name": name, - "description": description, - }, - } - err := instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params)) - if err != nil { - return err - } - } - if len(password) > 0 { - params := map[string]interface{}{ - "changeVmPassword": map[string]string{ - "account": username, - "password": password, - }, - } - err := instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params)) - if err != nil { - return err - } - } - if len(publicKey) > 0 { - params := map[string]interface{}{ - "setVmSshKey": map[string]string{ - "SshKey": publicKey, - }, - } - err := instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params)) - if err != nil { - return err - } - } - if deleteKeypair { - err := instance.host.zone.region.client.delete("vm-instances", fmt.Sprintf("%s/ssh-keys", instance.UUID), "") - if err != nil { - return err - } - } - - return nil -} - -func (instance *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { - return instance.host.zone.region.RebuildRoot(instance.UUID, desc.ImageId, desc.SysSizeGB) -} - -func (region *SRegion) RebuildRoot(instanceId, imageId string, sysSizeGB int) (string, error) { - params := map[string]interface{}{ - "changeVmImage": map[string]string{ - "imageUuid": imageId, - }, - } - instance := &SInstance{} - resp, err := region.client.put("vm-instances", instanceId, jsonutils.Marshal(params)) - if err != nil { - return "", err - } - err = resp.Unmarshal(instance, "inventory") - if err != nil { - return "", err - } - disk, err := region.GetDisk(instance.RootVolumeUUID) - if err != nil { - return "", err - } - if sysSizeGB > disk.GetDiskSizeMB()*1024 { - return instance.RootVolumeUUID, region.ResizeDisk(disk.UUID, int64(sysSizeGB)*1024) - } - return instance.RootVolumeUUID, nil -} - -func (instance *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { - offerings, err := instance.host.zone.region.GetInstanceOfferings("", "", config.Cpu, config.MemoryMB) - if err != nil { - return err - } - if len(config.InstanceType) > 0 { - for _, offering := range offerings { - if offering.Name == config.InstanceType { - return instance.host.zone.region.ChangeConfig(instance.UUID, offering.UUID) - } - } - offering, err := instance.host.zone.region.CreateInstanceOffering(config.InstanceType, config.Cpu, config.MemoryMB, "UserVm") - if err != nil { - return err - } - return instance.host.zone.region.ChangeConfig(instance.UUID, offering.UUID) - } - for _, offering := range offerings { - log.Debugf("try instance offering %s(%s) ...", offering.Name, offering.UUID) - err := instance.host.zone.region.ChangeConfig(instance.UUID, offering.UUID) - if err != nil { - log.Errorf("failed to change config for instance %s(%s) error: %v", instance.Name, instance.UUID, err) - } else { - return nil - } - } - return fmt.Errorf("Failed to change vm config, specification not supported") -} - -func (region *SRegion) ChangeConfig(instanceId, offeringId string) error { - params := map[string]interface{}{ - "changeInstanceOffering": map[string]string{ - "instanceOfferingUuid": offeringId, - }, - } - return region.UpdateVM(instanceId, jsonutils.Marshal(params)) -} - -func (instance *SInstance) AttachDisk(ctx context.Context, diskId string) error { - return instance.host.zone.region.AttachDisk(instance.UUID, diskId) -} - -func (region *SRegion) AttachDisk(instanceId string, diskId string) error { - _, err := region.client.post(fmt.Sprintf("volumes/%s/vm-instances/%s", diskId, instanceId), jsonutils.NewDict()) - return err -} - -func (instance *SInstance) DetachDisk(ctx context.Context, diskId string) error { - return instance.host.zone.region.DetachDisk(instance.UUID, diskId) -} - -func (region *SRegion) DetachDisk(instanceId, diskId string) error { - url := fmt.Sprintf("volumes/%s/vm-instances?vmUuid=%s", diskId, instanceId) - err := region.client.delete(url, "", "") - if err != nil && strings.Contains(err.Error(), "is not attached to any vm") { - return nil - } - return err -} - -func (instance *SInstance) DeleteVM(ctx context.Context) error { - disks, err := instance.GetIDisks() - if err != nil { - return errors.Wrapf(err, "GetIDisks") - } - err = instance.host.zone.region.DeleteVM(instance.UUID) - if err != nil { - return errors.Wrapf(err, "DeleteVM") - } - for i := range disks { - if disks[i].GetDiskType() != api.DISK_TYPE_SYS && disks[i].GetIsAutoDelete() { - err = disks[i].Delete(ctx) - if err != nil { - log.Warningf("delete disk %s failed %s", disks[i].GetId(), err) - } - } - } - return nil -} - -func (region *SRegion) DeleteVM(instanceId string) error { - err := region.client.delete("vm-instances", instanceId, "Enforcing") - if err != nil { - return err - } - params := map[string]interface{}{ - "expungeVmInstance": jsonutils.NewDict(), - } - _, err = region.client.put("vm-instances", instanceId, jsonutils.Marshal(params)) - if err != nil { - return errors.Wrapf(err, "expungeVmInstance") - } - return nil -} - -func (instance *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { - eips, err := instance.host.zone.region.GetEips("", instance.UUID) - if err != nil { - return nil, err - } - if len(eips) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(eips) == 1 { - return &eips[0], nil - } - return nil, cloudprovider.ErrDuplicateId -} - -func (instance *SInstance) AssignSecurityGroup(secgroupId string) error { - return instance.host.zone.region.AssignSecurityGroup(instance.UUID, secgroupId) -} - -func (instance *SInstance) SetSecurityGroups(secgroupIds []string) error { - currentIds, err := instance.GetSecurityGroupIds() - if err != nil { - return err - } - for _, id := range currentIds { - if !utils.IsInStringArray(id, secgroupIds) { - err := instance.host.zone.region.RevokeSecurityGroup(instance.UUID, id) - if err != nil { - return err - } - } - } - for _, id := range secgroupIds { - if !utils.IsInStringArray(id, currentIds) { - err := instance.host.zone.region.AssignSecurityGroup(instance.UUID, id) - if err != nil { - return err - } - } - } - return nil -} - -func (region *SRegion) AssignSecurityGroup(instanceId, secgroupId string) error { - instance, err := region.GetInstance(instanceId) - if err != nil { - return err - } - secgroup, err := region.GetSecurityGroup(secgroupId) - if err != nil { - return err - } - if len(instance.VMNics) > 0 { - if !utils.IsInStringArray(instance.VMNics[0].L3NetworkUUID, secgroup.AttachedL3NetworkUUIDs) { - resource := fmt.Sprintf("security-groups/%s/l3-networks/%s", secgroupId, instance.VMNics[0].L3NetworkUUID) - _, err := region.client.post(resource, jsonutils.NewDict()) - if err != nil { - return err - } - } - params := map[string]interface{}{ - "params": map[string]interface{}{ - "vmNicUuids": []string{instance.VMNics[0].UUID}, - }, - } - resource := fmt.Sprintf("security-groups/%s/vm-instances/nics", secgroupId) - _, err = region.client.post(resource, jsonutils.Marshal(params)) - return err - } - return nil -} - -func (region *SRegion) RevokeSecurityGroup(instanceId, secgroupId string) error { - instance, err := region.GetInstance(instanceId) - if err != nil { - return err - } - for _, nic := range instance.VMNics { - resource := fmt.Sprintf("security-groups/%s/vm-instances/nics?vmNicUuids=%s", secgroupId, nic.UUID) - err := region.client.delete(resource, "", "") - if err != nil { - return err - } - } - return nil -} - -func (instance *SInstance) GetBillingType() string { - return "" -} - -func (instance *SInstance) GetCreatedAt() time.Time { - return instance.CreateDate -} - -func (instance *SInstance) GetExpiredAt() time.Time { - return time.Time{} -} - -func (instance *SInstance) UpdateUserData(userData string) error { - return cloudprovider.ErrNotSupported -} - -func (instance *SInstance) Renew(bc billing.SBillingCycle) error { - return cloudprovider.ErrNotSupported -} - -func (instance *SInstance) GetProjectId() string { - return "" -} - -func (instance *SInstance) GetError() error { - return nil -} - -type SConsoleInfo struct { - Scheme string `json:"scheme"` - Hostname string `json:"hostname"` - Port int `json:"port"` - Token string `json:"token"` -} - -func (region *SRegion) GetInstanceConsoleInfo(instnaceId string) (*SConsoleInfo, error) { - params := map[string]interface{}{ - "params": map[string]string{ - "vmInstanceUuid": instnaceId, - }, - } - resp, err := region.client.post("consoles", jsonutils.Marshal(params)) - if err != nil { - return nil, err - } - info := &SConsoleInfo{} - err = resp.Unmarshal(info, "inventory") - if err != nil { - return nil, err - } - return info, nil -} - -func (region *SRegion) GetInstanceConsolePassword(instnaceId string) (string, error) { - resp, err := region.client.get("vm-instances", instnaceId, "console-passwords") - if err != nil { - return "", err - } - if resp.Contains("consolePassword") { - return resp.GetString("consolePassword") - } - return "", nil -} diff --git a/pkg/multicloud/zstack/instancenic.go b/pkg/multicloud/zstack/instancenic.go deleted file mode 100644 index 9ca8c9782f..0000000000 --- a/pkg/multicloud/zstack/instancenic.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SInstanceNic struct { - instance *SInstance - - UUID string `json:"uuid"` - VMInstanceUUID string `json:"vmInstanceUuid"` - L3NetworkUUID string `json:"l3NetworkUuid"` - IP string `json:"ip"` - Mac string `json:"mac"` - HypervisorType string `json:"hypervisorType"` - IPVersion int `json:"ipVersion"` - UsedIps []string `json:"usedIps"` - InternalName string `json:"internalName"` - DeviceID int `json:"deviceId"` - ZStackTime - - cloudprovider.DummyICloudNic -} - -func (nic *SInstanceNic) GetId() string { - return "" -} - -func (nic *SInstanceNic) GetIP() string { - return nic.IP -} - -func (nic *SInstanceNic) GetMAC() string { - return nic.Mac -} - -func (nic *SInstanceNic) GetDriver() string { - return "virtio" -} - -func (nic *SInstanceNic) InClassicNetwork() bool { - return false -} - -func (nic *SInstanceNic) GetINetworkId() string { - networks, err := nic.instance.host.zone.region.GetNetworks(nic.instance.host.zone.UUID, "", nic.L3NetworkUUID, "") - if err != nil { - log.Errorf("failed to found networks for nic %v error: %v", jsonutils.Marshal(nic).String(), err) - return "" - } - for i := 0; i < len(networks); i++ { - if networks[i].Contains(nic.IP) { - return networks[i].L3NetworkUUID - } - } - return "" -} diff --git a/pkg/multicloud/zstack/monitor.go b/pkg/multicloud/zstack/monitor.go deleted file mode 100644 index e1efa3d926..0000000000 --- a/pkg/multicloud/zstack/monitor.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -type SDataPoint struct { - DataPoints []DataPoint `json:"data"` -} - -type DataPoint struct { - Value float64 `json:"value"` - Time int64 `json:"time"` - Labels Label `json:"labels"` -} - -type Label struct { - VMUuid string `json:"VMUuid"` - HostUuid string `json:"HostUuid"` -} - -func (self *SZStackClient) GetMonitorData(name string, namespace string, since time.Time, until time.Time) ([]DataPoint, error) { - datas := SDataPoint{} - param := jsonutils.NewDict() - param.Add(jsonutils.NewString(namespace), "namespace") - param.Add(jsonutils.NewString(name), "metricName") - param.Add(jsonutils.NewString("60"), "period") - param.Add(jsonutils.NewInt(since.Unix()), "startTime") - param.Add(jsonutils.NewInt(until.Unix()), "endTime") - rep, err := self.getMonitor("zwatch/metrics", param) - if err != nil { - return nil, err - } - return datas.DataPoints, rep.Unmarshal(&datas) -} - -func (self *SZStackClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - switch opts.ResourceType { - case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: - return self.GetEcsMetrics(opts) - case cloudprovider.METRIC_RESOURCE_TYPE_HOST: - return self.GetHostMetrics(opts) - default: - return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) - } -} - -func (self *SZStackClient) GetHostMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ns, metricName := "ZStack/Host", "" - switch opts.MetricType { - case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: - metricName = "CPUAverageUsedUtilization" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: - metricName = "DiskReadBytes" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: - metricName = "DiskWriteBytes" - case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: - metricName = "NetworkInBytes" - case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: - metricName = "NetworkOutBytes" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: - metricName = "DiskReadOps" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: - metricName = "DiskWriteOps" - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) - } - data, err := self.GetMonitorData(metricName, ns, opts.StartTime, opts.EndTime) - if err != nil { - return nil, errors.Wrapf(err, "GetMonitorData") - } - ret := []cloudprovider.MetricValues{} - for i := range data { - metric := cloudprovider.MetricValues{} - metric.MetricType = opts.MetricType - metric.Id = data[i].Labels.HostUuid - metric.Values = append(metric.Values, cloudprovider.MetricValue{ - Timestamp: time.Unix(data[i].Time, 0), - Value: data[i].Value, - }) - ret = append(ret, metric) - } - return ret, nil -} - -func (self *SZStackClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - ns, metricName := "ZStack/VM", "" - switch opts.MetricType { - case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: - metricName = "CPUAverageUsedUtilization" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: - metricName = "DiskReadBytes" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: - metricName = "DiskWriteBytes" - case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: - metricName = "NetworkInBytes" - case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: - metricName = "NetworkOutBytes" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: - metricName = "DiskReadOps" - case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: - metricName = "DiskWriteOps" - default: - return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) - } - data, err := self.GetMonitorData(metricName, ns, opts.StartTime, opts.EndTime) - if err != nil { - return nil, errors.Wrapf(err, "GetMonitorData") - } - ret := []cloudprovider.MetricValues{} - for i := range data { - metric := cloudprovider.MetricValues{} - metric.MetricType = opts.MetricType - metric.Id = data[i].Labels.VMUuid - metric.Values = append(metric.Values, cloudprovider.MetricValue{ - Timestamp: time.Unix(data[i].Time, 0), - Value: data[i].Value, - }) - ret = append(ret, metric) - } - return ret, nil -} diff --git a/pkg/multicloud/zstack/network.go b/pkg/multicloud/zstack/network.go deleted file mode 100644 index cef89c0488..0000000000 --- a/pkg/multicloud/zstack/network.go +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "fmt" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/rbacutils" -) - -type SNetwork struct { - multicloud.SResourceBase - multicloud.ZStackTags - wire *SWire - - ZStackBasic - L3NetworkUUID string `json:"l3NetworkUuid"` - StartIP string `json:"startIp"` - EndIP string `json:"endIp"` - Netmask string `json:"netmask"` - Gateway string `json:"gateway"` - NetworkCIDR string `json:"networkCidr"` - IPVersion int `json:"ipVersion"` - PrefixLen int `json:"prefixLen"` - ZStackTime -} - -type SHostRoute struct { - ID int - L3NetworkUuid string `json:"l3NetworkUuid"` - Prefix string - Nexthop string - ZStackTime -} - -type SL3Network struct { - ZStackBasic - Type string `json:"type"` - ZoneUUID string `json:"zoneUuid"` - L2NetworkUUID string `json:"l2NetworkUuid"` - State string `json:"state"` - System bool `json:"system"` - Category bool `json:"category"` - IPVersion int `json:"ipVersion"` - DNS []string `json:"dns"` - Networks []SNetwork `json:"ipRanges"` - HostRoute []SHostRoute `json:"hostRoute"` - ZStackTime -} - -func (region *SRegion) GetNetwork(zoneId, wireId, l3Id, networkId string) (*SNetwork, error) { - networks, err := region.GetNetworks(zoneId, wireId, l3Id, networkId) - if err != nil { - return nil, err - } - if len(networks) == 1 { - if networks[0].UUID == networkId { - return &networks[0], nil - } - return nil, cloudprovider.ErrNotFound - } - if len(networks) == 0 || len(networkId) == 0 { - return nil, cloudprovider.ErrNotFound - } - return nil, cloudprovider.ErrDuplicateId -} - -func (region *SRegion) GetL3Network(l3Id string) (*SL3Network, error) { - l3network := &SL3Network{} - return l3network, region.client.getResource("l3-networks", l3Id, l3network) -} - -func (region *SRegion) GetL3Networks(zoneId string, wireId string, l3Id string) ([]SL3Network, error) { - l3Networks := []SL3Network{} - params := url.Values{} - if len(zoneId) > 0 { - params.Add("q", "zone.uuid="+zoneId) - } - if len(wireId) > 0 { - params.Add("q", "l2NetworkUuid="+wireId) - } - if len(l3Id) > 0 { - params.Add("q", "uuid="+l3Id) - } - return l3Networks, region.client.listAll("l3-networks", params, &l3Networks) -} - -func (region *SRegion) GetNetworks(zoneId string, wireId string, l3Id string, networkId string) ([]SNetwork, error) { - l3Networks, err := region.GetL3Networks(zoneId, wireId, l3Id) - if err != nil { - return nil, err - } - networks := []SNetwork{} - for i := 0; i < len(l3Networks); i++ { - for j := 0; j < len(l3Networks[i].Networks); j++ { - if len(networkId) == 0 || l3Networks[i].Networks[j].UUID == networkId { - networks = append(networks, l3Networks[i].Networks[j]) - } - } - } - return networks, nil -} - -func (network *SNetwork) GetId() string { - return network.UUID -} - -func (network *SNetwork) GetName() string { - return network.Name -} - -func (network *SNetwork) GetGlobalId() string { - return fmt.Sprintf("%s/%s", network.L3NetworkUUID, network.UUID) -} - -func (network *SNetwork) IsEmulated() bool { - return false -} - -func (network *SNetwork) GetStatus() string { - return api.NETWORK_STATUS_AVAILABLE -} - -func (network *SNetwork) Delete() error { - return network.wire.vpc.region.DeleteNetwork(network.UUID) -} - -func (region *SRegion) DeleteNetwork(networkId string) error { - network, err := region.GetNetwork("", "", "", networkId) - if err != nil { - return err - } - l3, err := region.GetL3Network(network.L3NetworkUUID) - if err != nil { - return err - } - if len(l3.Networks) == 1 { - return region.client.delete("l3-networks", l3.UUID, "") - } - return region.client.delete("l3-networks/ip-ranges", networkId, "") -} - -func (network *SNetwork) GetIWire() cloudprovider.ICloudWire { - return network.wire -} - -func (network *SNetwork) GetAllocTimeoutSeconds() int { - return 120 // 2 minutes -} - -func (network *SNetwork) GetGateway() string { - return network.Gateway -} - -func (network *SNetwork) GetIpStart() string { - return network.StartIP -} - -func (network *SNetwork) GetIpEnd() string { - return network.EndIP -} - -func (network *SNetwork) GetIPRange() netutils.IPV4AddrRange { - start, _ := netutils.NewIPV4Addr(network.GetIpStart()) - end, _ := netutils.NewIPV4Addr(network.GetIpEnd()) - return netutils.NewIPV4AddrRange(start, end) -} - -func (network *SNetwork) Contains(ipAddr string) bool { - ip, err := netutils.NewIPV4Addr(ipAddr) - if err != nil { - return false - } - return network.GetIPRange().Contains(ip) -} - -func (network *SNetwork) GetIpMask() int8 { - return int8(network.PrefixLen) -} - -func (network *SNetwork) GetIsPublic() bool { - return true -} - -func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { - return rbacutils.ScopeSystem -} - -func (network *SNetwork) GetServerType() string { - return api.NETWORK_TYPE_GUEST -} - -func (network *SNetwork) Refresh() error { - new, err := network.wire.vpc.region.GetNetwork("", network.wire.UUID, network.L3NetworkUUID, network.UUID) - if err != nil { - return err - } - return jsonutils.Update(network, new) -} - -func (network *SNetwork) GetProjectId() string { - return "" -} - -func (region *SRegion) CreateNetwork(name string, cidr string, wireId string, desc string) (*SNetwork, error) { - params := map[string]interface{}{ - "params": map[string]interface{}{ - "name": name, - "type": "L3BasicNetwork", - "l2NetworkUuid": wireId, - "category": "Private", - "system": false, - }, - } - l3 := &SL3Network{} - resp, err := region.client.post("l3-networks", jsonutils.Marshal(params)) - if err != nil { - return nil, err - } - err = resp.Unmarshal(l3, "inventory") - if err != nil { - return nil, err - } - region.AttachServiceForl3Network(l3.UUID, []string{"Flat", "SecurityGroup"}) - params = map[string]interface{}{ - "params": map[string]interface{}{ - "name": name, - "networkCidr": cidr, - }, - } - resource := fmt.Sprintf("l3-networks/%s/ip-ranges/by-cidr", l3.UUID) - resp, err = region.client.post(resource, jsonutils.Marshal(params)) - if err != nil { - region.client.delete("l3-networks", l3.UUID, "") - return nil, err - } - network := &SNetwork{} - return network, resp.Unmarshal(network, "inventory") -} diff --git a/pkg/multicloud/zstack/provider/doc.go b/pkg/multicloud/zstack/provider/doc.go deleted file mode 100644 index aa2169706a..0000000000 --- a/pkg/multicloud/zstack/provider/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider // import "yunion.io/x/onecloud/pkg/multicloud/zstack/provider" diff --git a/pkg/multicloud/zstack/provider/provider.go b/pkg/multicloud/zstack/provider/provider.go deleted file mode 100644 index 770a881365..0000000000 --- a/pkg/multicloud/zstack/provider/provider.go +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 provider - -import ( - "context" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud/zstack" -) - -type SZStackProviderFactory struct { - cloudprovider.SPrivateCloudBaseProviderFactory -} - -func (self *SZStackProviderFactory) GetId() string { - return zstack.CLOUD_PROVIDER_ZSTACK -} - -func (self *SZStackProviderFactory) GetName() string { - return zstack.CLOUD_PROVIDER_ZSTACK -} - -func (self *SZStackProviderFactory) GetSupportedBrands() []string { - return []string{api.ZSTACK_BRAND_DSTACK} -} - -func (self *SZStackProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AuthUrl) == 0 { - return output, errors.Wrap(httperrors.ErrMissingParameter, "auth_url") - } - output.AccessUrl = input.AuthUrl - //为了兼容以前用username的参数,2.12之后尽可能的使用access_key_id参数 - if len(input.AccessKeyId) > 0 && len(input.AccessKeySecret) > 0 { - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - } else if len(input.Username) > 0 && len(input.Password) > 0 { - output.Account = input.Username - output.Secret = input.Password - } else { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id or access_key_secret") - } - return output, nil -} - -func (self *SZStackProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { - output := cloudprovider.SCloudaccount{} - if len(input.AccessKeyId) > 0 && len(input.AccessKeySecret) > 0 { - output.Account = input.AccessKeyId - output.Secret = input.AccessKeySecret - } else if len(input.Username) > 0 && len(input.Password) > 0 { - output.Account = input.Username - output.Secret = input.Password - } else { - return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id or access_key_secret") - } - return output, nil -} - -func (self *SZStackProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { - client, err := zstack.NewZStackClient( - zstack.NewZstackClientConfig( - cfg.URL, cfg.Account, cfg.Secret, - ).CloudproviderConfig(cfg), - ) - if err != nil { - return nil, err - } - return &SZStackProvider{ - SBaseProvider: cloudprovider.NewBaseProvider(self), - client: client, - }, nil -} - -func (self *SZStackProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { - return map[string]string{ - "ZSTACK_AUTH_URL": info.Url, - "ZSTACK_USERNAME": info.Account, - "ZSTACK_PASSWORD": info.Secret, - "ZSTACK_REGION_ID": zstack.ZSTACK_DEFAULT_REGION, - }, nil -} - -func init() { - factory := SZStackProviderFactory{} - cloudprovider.RegisterFactory(&factory) -} - -type SZStackProvider struct { - cloudprovider.SBaseProvider - client *zstack.SZStackClient -} - -func (self *SZStackProvider) GetVersion() string { - return "" -} - -func (self *SZStackProvider) GetSysInfo() (jsonutils.JSONObject, error) { - return jsonutils.NewDict(), nil -} - -func (self *SZStackProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { - return self.client.GetSubAccounts() -} - -func (self *SZStackProvider) GetAccountId() string { - return "" -} - -func (self *SZStackProvider) GetIRegions() []cloudprovider.ICloudRegion { - return self.client.GetIRegions() -} - -func (self *SZStackProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { - return self.client.GetIRegionById(extId) -} - -func (self *SZStackProvider) GetBalance() (float64, string, error) { - return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, cloudprovider.ErrNotSupported -} - -func (self *SZStackProvider) GetCloudRegionExternalIdPrefix() string { - return self.client.GetCloudRegionExternalIdPrefix() -} - -func (self *SZStackProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { - return self.client.GetIProjects() -} - -func (self *SZStackProvider) GetStorageClasses(regionId string) []string { - return nil -} - -func (self *SZStackProvider) GetBucketCannedAcls(regionId string) []string { - return nil -} - -func (self *SZStackProvider) GetObjectCannedAcls(regionId string) []string { - return nil -} - -func (self *SZStackProvider) GetCapabilities() []string { - return self.client.GetCapabilities() -} - -func (self *SZStackProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { - return self.client.GetEcsMetrics(opts) -} diff --git a/pkg/multicloud/zstack/quota.go b/pkg/multicloud/zstack/quota.go deleted file mode 100644 index 0930b2f08e..0000000000 --- a/pkg/multicloud/zstack/quota.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "net/url" - - "yunion.io/x/pkg/errors" - - "yunion.io/x/onecloud/pkg/cloudprovider" -) - -/* - "uuid":"132e0ad32b2242c4a648440be917ec4a", - "name":"pci.num", - "identityUuid":"2dce5dc485554d21a3796500c1db007a", - "identityType":"AccountVO", - "value":0, - "lastOpDate":"Dec 28, 2019 2:26:03 PM", - "createDate":"Dec 28, 2019 2:26:03 PM" -*/ - -type SQuota struct { - Uuid string - Name string - IdentityUuid string - IdentityType string - Value int -} - -func (q *SQuota) GetGlobalId() string { - return q.Uuid -} - -func (q *SQuota) GetName() string { - return q.Name -} - -func (q *SQuota) GetDesc() string { - return "" -} - -func (q *SQuota) GetQuotaType() string { - return q.Name -} - -func (q *SQuota) GetMaxQuotaCount() int { - return q.Value -} - -func (q *SQuota) GetCurrentQuotaUsedCount() int { - return -1 -} - -func (region *SRegion) GetQuotas() ([]SQuota, error) { - quotas := []SQuota{} - params := url.Values{} - err := region.client.listAll("accounts/quotas", params, "as) - if err != nil { - return nil, err - } - return quotas, nil -} - -type SUserAccount struct { - Uuid string -} - -func (region *SRegion) GetUserAccount(name string) ([]SUserAccount, error) { - users := []SUserAccount{} - params := url.Values{} - if len(name) > 0 { - params.Add("q", "name="+name) - } - err := region.client.listAll("accounts/users", params, &users) - if err != nil { - return nil, errors.Wrap(err, "users.list") - } - return users, nil -} - -func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { - quotas, err := region.GetQuotas() - if err != nil { - return nil, errors.Wrap(err, "GetQuotas") - } - ret := []cloudprovider.ICloudQuota{} - for i := range quotas { - ret = append(ret, "as[i]) - } - return ret, nil -} diff --git a/pkg/multicloud/zstack/region.go b/pkg/multicloud/zstack/region.go deleted file mode 100644 index be04244b78..0000000000 --- a/pkg/multicloud/zstack/region.go +++ /dev/null @@ -1,386 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/log" - "yunion.io/x/pkg/errors" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SRegion struct { - multicloud.SRegion - multicloud.SNoObjectStorageRegion - - client *SZStackClient - - Name string - - izones []cloudprovider.ICloudZone - ivpcs []cloudprovider.ICloudVpc -} - -func (region *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetClient() *SZStackClient { - return region.client -} - -func (region *SRegion) GetId() string { - return region.Name -} - -func (region *SRegion) GetName() string { - return region.client.cpcfg.Name -} - -func (region *SRegion) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(region.GetName()).CN(region.GetName()) - return table -} - -func (region *SRegion) GetGlobalId() string { - return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_ZSTACK, region.client.cpcfg.Id) -} - -func (region *SRegion) IsEmulated() bool { - return false -} - -func (region *SRegion) GetProvider() string { - return CLOUD_PROVIDER_ZSTACK -} - -func (region *SRegion) GetCloudEnv() string { - return "" -} - -func (region *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { - return cloudprovider.SGeographicInfo{} -} - -func (region *SRegion) GetStatus() string { - return api.CLOUD_REGION_STATUS_INSERVER -} - -func (region *SRegion) Refresh() error { - // do nothing - return nil -} - -func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { - vm, err := self.GetInstance(id) - if err != nil { - return nil, err - } - return vm, nil -} - -func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { - disk, err := self.GetDisk(id) - if err != nil { - return nil, err - } - return disk, nil -} - -func (region *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { - return region.GetHost(id) -} - -func (region *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { - storages, err := region.getIStorages("") - if err != nil { - return nil, err - } - for i := 0; i < len(storages); i++ { - if storages[i].GetGlobalId() == id { - return storages[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { - hosts, err := region.GetHosts("", "") - if err != nil { - return nil, err - } - ihosts := []cloudprovider.ICloudHost{} - for i := 0; i < len(hosts); i++ { - ihosts = append(ihosts, &hosts[i]) - } - return ihosts, nil -} - -func (region *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - return region.getIStorages("") -} - -func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { - caches, err := region.GetIStoragecaches() - if err != nil { - return nil, err - } - for i := 0; i < len(caches); i++ { - if caches[i].GetGlobalId() == id { - return caches[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { - zones, err := region.GetZones("") - if err != nil { - return nil, err - } - icaches := []cloudprovider.ICloudStoragecache{} - for i := 0; i < len(zones); i++ { - icaches = append(icaches, &SStoragecache{ZoneId: zones[i].UUID, region: region}) - } - return icaches, nil -} - -func (region *SRegion) GetIVpcById(vpcId string) (cloudprovider.ICloudVpc, error) { - return &SVpc{region: region}, nil -} - -func (region *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { - izones, err := region.GetIZones() - if err != nil { - return nil, err - } - for i := 0; i < len(izones); i++ { - if izones[i].GetGlobalId() == id { - return izones[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (region *SRegion) GetZone(zoneId string) (*SZone, error) { - zone := &SZone{region: region} - return zone, region.client.getResource("zones", zoneId, zone) -} - -func (region *SRegion) GetZones(zoneId string) ([]SZone, error) { - zones := []SZone{} - params := url.Values{} - if len(zoneId) > 0 { - params.Add("q", "uuid="+zoneId) - } - err := region.client.listAll("zones", params, &zones) - if err != nil { - return nil, err - } - for i := 0; i < len(zones); i++ { - zones[i].region = region - } - return zones, nil -} - -func (region *SRegion) fetchZones() { - if region.izones == nil || len(region.izones) == 0 { - zones, err := region.GetZones("") - if err != nil { - log.Errorf("failed to get zones error: %v", err) - return - } - region.izones = []cloudprovider.ICloudZone{} - for i := 0; i < len(zones); i++ { - region.izones = append(region.izones, &zones[i]) - } - } -} - -func (region *SRegion) fetchInfrastructure() error { - region.fetchZones() - region.GetIVpcs() - return nil -} - -func (region *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { - if region.izones == nil { - if err := region.fetchInfrastructure(); err != nil { - return nil, err - } - } - return region.izones, nil -} - -func (region *SRegion) GetVpc() *SVpc { - return &SVpc{region: region} -} - -func (region *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { - region.ivpcs = []cloudprovider.ICloudVpc{region.GetVpc()} - return region.ivpcs, nil -} - -func (region *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { - if len(eip.NetworkExternalId) == 0 { - return nil, fmt.Errorf("networkId cannot be empty") - } - networkInfo := strings.Split(eip.NetworkExternalId, "/") - if len(networkInfo) != 2 { - return nil, fmt.Errorf("invalid network externalId, it should be `l3networId/networkId` format") - } - _, err := region.GetL3Network(networkInfo[0]) - if err != nil { - return nil, err - } - vip, err := region.CreateVirtualIP(eip.Name, "", eip.IP, networkInfo[0]) - if err != nil { - return nil, err - } - return region.CreateEip(eip.Name, vip.UUID, "") -} - -func (region *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { - return region.GetEip(eipId) -} - -func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { - eips, err := region.GetEips("", "") - if err != nil { - return nil, err - } - ieips := []cloudprovider.ICloudEIP{} - for i := 0; i < len(eips); i++ { - ieips = append(ieips, &eips[i]) - } - return ieips, nil -} - -func (region *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { - snapshots, err := region.GetSnapshots("", "") - if err != nil { - return nil, err - } - isnapshots := []cloudprovider.ICloudSnapshot{} - for i := 0; i < len(snapshots); i++ { - snapshots[i].region = region - isnapshots = append(isnapshots, &snapshots[i]) - } - return isnapshots, nil -} - -func (region *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { - return region.GetSnapshot(snapshotId) -} - -func (region *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { - offerings, err := region.GetInstanceOfferings("", "", 0, 0) - if err != nil { - return nil, err - } - iskus := []cloudprovider.ICloudSku{} - for i := 0; i < len(offerings); i++ { - offerings[i].region = region - iskus = append(iskus, &offerings[i]) - } - return iskus, nil -} - -func (region *SRegion) DeleteISkuByName(name string) error { - offerings, err := region.GetInstanceOfferings("", name, 0, 0) - if err != nil { - return errors.Wrap(err, "region.GetInstanceOfferings") - } - for _, offering := range offerings { - err = offering.Delete() - if err != nil { - return err - } - } - return nil -} - -func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { - return region.GetSecurityGroup(secgroupId) -} - -func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := region.GetSecurityGroups("", "", opts.Name) - if err != nil { - return nil, err - } - if len(secgroups) == 0 { - return nil, cloudprovider.ErrNotFound - } - if len(secgroups) > 1 { - return nil, cloudprovider.ErrDuplicateId - } - return &secgroups[0], nil -} - -func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { - return region.CreateSecurityGroup(conf.Name, conf.Desc) -} - -func (region *SRegion) GetCapabilities() []string { - return region.client.GetCapabilities() -} diff --git a/pkg/multicloud/zstack/securitygroup.go b/pkg/multicloud/zstack/securitygroup.go deleted file mode 100644 index a0a5161189..0000000000 --- a/pkg/multicloud/zstack/securitygroup.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/errors" - "yunion.io/x/pkg/util/secrules" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSecurityGroupRule struct { - ZStackBasic - SecurityGroupUUID string `json:"securityGroupUuid"` - Type string `json:"type"` - IPVersion int `json:"ipVersion"` - StartPort int `json:"startPort"` - EndPort int `json:"endPort"` - Protocol string `json:"protocol"` - State string `json:"state"` - AllowedCIDR string `json:"allowedCidr"` - RemoteSecurityGroupUUID string `json:"remoteSecurityGroupUuid"` - ZStackTime -} - -type SSecurityGroup struct { - multicloud.SSecurityGroup - multicloud.ZStackTags - region *SRegion - - ZStackBasic - State string `json:"state"` - IPVersion int `json:"ipVersion"` - ZStackTime - InternalID int `json:"internalId"` - Rules []SSecurityGroupRule `json:"rules"` - AttachedL3NetworkUUIDs []string `json:"attachedL3NetworkUuids"` -} - -func (region *SRegion) GetSecurityGroup(secgroupId string) (*SSecurityGroup, error) { - secgroup := &SSecurityGroup{region: region} - return secgroup, region.client.getResource("security-groups", secgroupId, secgroup) -} - -func (region *SRegion) GetSecurityGroups(secgroupId string, instanceId string, name string) ([]SSecurityGroup, error) { - secgroups := []SSecurityGroup{} - params := url.Values{} - if len(secgroupId) > 0 { - params.Add("q", "uuid="+secgroupId) - } - if len(instanceId) > 0 { - params.Add("q", "vmNic.vmInstanceUuid="+instanceId) - } - if len(name) > 0 { - params.Add("q", "name="+name) - } - err := region.client.listAll("security-groups", params, &secgroups) - if err != nil { - return nil, err - } - for i := 0; i < len(secgroups); i++ { - secgroups[i].region = region - } - return secgroups, nil -} - -func (self *SSecurityGroup) GetVpcId() string { - return api.NORMAL_VPC_ID -} - -func (self *SSecurityGroup) GetId() string { - return self.UUID -} - -func (self *SSecurityGroup) GetGlobalId() string { - return self.UUID -} - -func (self *SSecurityGroup) GetDescription() string { - return self.Description -} - -func (rule *SSecurityGroupRule) toRule() (cloudprovider.SecurityRule, error) { - r := cloudprovider.SecurityRule{ - ExternalId: rule.UUID, - SecurityRule: secrules.SecurityRule{ - Direction: secrules.DIR_IN, - Action: secrules.SecurityRuleAllow, - Priority: 1, - Protocol: secrules.PROTO_ANY, - PortStart: rule.StartPort, - PortEnd: rule.EndPort, - }, - } - r.ParseCIDR(rule.AllowedCIDR) - if rule.Type == "Egress" { - r.Direction = secrules.DIR_OUT - } - if rule.Protocol != "ALL" { - r.Protocol = strings.ToLower(rule.Protocol) - } - err := r.ValidateRule() - if err != nil { - return r, errors.Wrap(err, "invalid rule") - } - return r, nil -} - -func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { - rules := []cloudprovider.SecurityRule{} - for i := 0; i < len(self.Rules); i++ { - if self.Rules[i].IPVersion == 4 { - rule, err := self.Rules[i].toRule() - if err != nil { - return nil, err - } - rules = append(rules, rule) - } - } - return rules, nil -} - -func (self *SSecurityGroup) GetName() string { - return self.Name -} - -func (self *SSecurityGroup) GetStatus() string { - return "" -} - -func (self *SSecurityGroup) IsEmulated() bool { - return false -} - -func (self *SSecurityGroup) Refresh() error { - new, err := self.region.GetSecurityGroup(self.UUID) - if err != nil { - return err - } - return jsonutils.Update(self, new) -} - -func (self *SSecurityGroup) GetProjectId() string { - return "" -} - -func (region *SRegion) AddSecurityGroupRule(secgroupId string, rules []cloudprovider.SecurityRule) error { - ruleParam := []map[string]interface{}{} - for _, rule := range rules { - Type := "Ingress" - if rule.Direction == secrules.DIR_OUT { - Type = "Egress" - } - protocol := "ALL" - if rule.Protocol != secrules.PROTO_ANY { - protocol = strings.ToUpper(rule.Protocol) - } - if rule.Protocol == secrules.PROTO_ICMP || rule.Protocol == secrules.PROTO_ANY { - rule.PortStart = -1 - rule.PortEnd = -1 - rule.Ports = []int{} - } - if len(rule.Ports) > 0 { - for _, port := range rule.Ports { - ruleParam = append(ruleParam, map[string]interface{}{ - "type": Type, - "startPort": port, - "endPort": port, - "protocol": protocol, - "allowedCidr": rule.IPNet.String(), - }) - } - } else { - if protocol != "ALL" { - // TCP UDP端口不能为-1 - if (rule.Protocol == secrules.PROTO_TCP || rule.Protocol == secrules.PROTO_UDP) && - (rule.PortStart <= 0 && rule.PortEnd <= 0) { - rule.PortStart = 0 - rule.PortEnd = 65535 - } - ruleParam = append(ruleParam, map[string]interface{}{ - "type": Type, - "startPort": rule.PortStart, - "endPort": rule.PortEnd, - "protocol": protocol, - "allowedCidr": rule.IPNet.String(), - }) - } else { - ruleParam = append(ruleParam, map[string]interface{}{ - "type": Type, - "protocol": protocol, - "allowedCidr": rule.IPNet.String(), - }) - } - } - } - if len(ruleParam) > 0 { - params := map[string]interface{}{ - "params": map[string]interface{}{ - "rules": ruleParam, - }, - } - return region.client.create(fmt.Sprintf("security-groups/%s/rules", secgroupId), jsonutils.Marshal(params), nil) - } - return nil -} - -func (region *SRegion) DeleteSecurityGroupRules(ruleIds []string) error { - if len(ruleIds) > 0 { - ids := []string{} - for _, ruleId := range ruleIds { - ids = append(ids, fmt.Sprintf("ruleUuids=%s", ruleId)) - } - resource := fmt.Sprintf("security-groups/rules?%s", strings.Join(ids, "&")) - return region.client.delete(resource, "", "") - } - return nil -} - -func (region *SRegion) CreateSecurityGroup(name, desc string) (*SSecurityGroup, error) { - secgroup := &SSecurityGroup{region: region} - params := map[string]map[string]string{ - "params": { - "name": name, - "description": desc, - }, - } - return secgroup, region.client.create("security-groups", jsonutils.Marshal(params), secgroup) -} - -func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { - deleteIds := []string{} - for _, r := range append(inDels, outDels...) { - deleteIds = append(deleteIds, r.ExternalId) - } - err := self.region.DeleteSecurityGroupRules(deleteIds) - if err != nil { - return errors.Wrapf(err, "DeleteSecurityGroupRules(%s)", deleteIds) - } - return self.region.AddSecurityGroupRule(self.UUID, append(inAdds, outAdds...)) -} - -func (self *SSecurityGroup) Delete() error { - return self.region.client.delete("security-groups", self.UUID, "Permissive") -} diff --git a/pkg/multicloud/zstack/shell/cluster.go b/pkg/multicloud/zstack/shell/cluster.go deleted file mode 100644 index 2e3344bcb7..0000000000 --- a/pkg/multicloud/zstack/shell/cluster.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ClusterListOptions struct { - StorageId string - DiskId string - } - shellutils.R(&ClusterListOptions{}, "cluster-list", "List clusters", func(cli *zstack.SRegion, args *ClusterListOptions) error { - clusters, err := cli.GetClusters() - if err != nil { - return err - } - printList(clusters, len(clusters), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/zstack/shell/configration.go b/pkg/multicloud/zstack/shell/configration.go deleted file mode 100644 index b84f1e1752..0000000000 --- a/pkg/multicloud/zstack/shell/configration.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ConfigrationListOptions struct { - } - shellutils.R(&ConfigrationListOptions{}, "configration-list", "List configration", func(cli *zstack.SRegion, args *ConfigrationListOptions) error { - configrations, err := cli.GetConfigrations() - if err != nil { - return err - } - printList(configrations, len(configrations), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/zstack/shell/disk.go b/pkg/multicloud/zstack/shell/disk.go deleted file mode 100644 index 82032543db..0000000000 --- a/pkg/multicloud/zstack/shell/disk.go +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskListOptions struct { - StorageId string - DiskIds []string - DiskType string - } - shellutils.R(&DiskListOptions{}, "disk-list", "List disks", func(cli *zstack.SRegion, args *DiskListOptions) error { - disks, err := cli.GetDisks(args.StorageId, args.DiskIds, args.DiskType) - if err != nil { - return err - } - printList(disks, len(disks), 0, 0, []string{}) - return nil - }) - - type DiskIdOptions struct { - ID string - } - - shellutils.R(&DiskIdOptions{}, "disk-show", "Show disk", func(cli *zstack.SRegion, args *DiskIdOptions) error { - disk, err := cli.GetDisk(args.ID) - if err != nil { - return err - } - printObject(disk) - return nil - }) - - shellutils.R(&DiskIdOptions{}, "disk-delete", "Delete disk", func(cli *zstack.SRegion, args *DiskIdOptions) error { - return cli.DeleteDisk(args.ID) - }) - - type DiskCreateOptions struct { - NAME string - Description string - SizeGB int - HostId string - PoolId string - STORAGE_ID string - } - - shellutils.R(&DiskCreateOptions{}, "disk-create", "Create disk", func(cli *zstack.SRegion, args *DiskCreateOptions) error { - disk, err := cli.CreateDisk(args.NAME, args.STORAGE_ID, args.HostId, args.PoolId, args.SizeGB, args.Description) - if err != nil { - return err - } - printObject(disk) - return nil - }) - - type DiskResize struct { - ID string - SIZEGB int64 - } - - shellutils.R(&DiskResize{}, "disk-resize", "Resize disk", func(cli *zstack.SRegion, args *DiskResize) error { - return cli.ResizeDisk(args.ID, args.SIZEGB*1024) - }) - -} diff --git a/pkg/multicloud/zstack/shell/disk_offering.go b/pkg/multicloud/zstack/shell/disk_offering.go deleted file mode 100644 index b0eb753cc0..0000000000 --- a/pkg/multicloud/zstack/shell/disk_offering.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type DiskOfferingOptions struct { - SizeGb int - } - shellutils.R(&DiskOfferingOptions{}, "disk-offering-list", "List disk offerings", func(cli *zstack.SRegion, args *DiskOfferingOptions) error { - offerings, err := cli.GetDiskOfferings(args.SizeGb) - if err != nil { - return err - } - printList(offerings, len(offerings), 0, 0, []string{}) - return nil - }) - - type DiskOfferingCreateOptions struct { - SIZE_GB int - } - - shellutils.R(&DiskOfferingCreateOptions{}, "disk-offering-create", "Create disk offering", func(cli *zstack.SRegion, args *DiskOfferingCreateOptions) error { - offering, err := cli.CreateDiskOffering(args.SIZE_GB) - if err != nil { - return err - } - printObject(offering) - return nil - }) - - type DiskOfferingDeleteOptions struct { - ID string - } - - shellutils.R(&DiskOfferingDeleteOptions{}, "disk-offering-delete", "Delete disk offering", func(cli *zstack.SRegion, args *DiskOfferingDeleteOptions) error { - return cli.DeleteDiskOffering(args.ID) - }) - -} diff --git a/pkg/multicloud/zstack/shell/doc.go b/pkg/multicloud/zstack/shell/doc.go deleted file mode 100644 index 90c1242ac3..0000000000 --- a/pkg/multicloud/zstack/shell/doc.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell // import "yunion.io/x/onecloud/pkg/multicloud/zstack/shell" diff --git a/pkg/multicloud/zstack/shell/eip.go b/pkg/multicloud/zstack/shell/eip.go deleted file mode 100644 index 2a8b7dbf59..0000000000 --- a/pkg/multicloud/zstack/shell/eip.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type EipListOptions struct { - EipId string - InstanceId string - } - shellutils.R(&EipListOptions{}, "eip-list", "List eips", func(cli *zstack.SRegion, args *EipListOptions) error { - eips, err := cli.GetEips(args.EipId, args.InstanceId) - if err != nil { - return err - } - printList(eips, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/zstack/shell/host.go b/pkg/multicloud/zstack/shell/host.go deleted file mode 100644 index 6d27fa23c2..0000000000 --- a/pkg/multicloud/zstack/shell/host.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type HostListOptions struct { - ZoneId string - HostId string - } - shellutils.R(&HostListOptions{}, "host-list", "List hosts", func(cli *zstack.SRegion, args *HostListOptions) error { - hosts, err := cli.GetHosts(args.ZoneId, args.HostId) - if err != nil { - return err - } - printList(hosts, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/zstack/shell/image.go b/pkg/multicloud/zstack/shell/image.go deleted file mode 100644 index 1043df2ad0..0000000000 --- a/pkg/multicloud/zstack/shell/image.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "os" - - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageListOptions struct { - ZoneId string - ImageId string - } - shellutils.R(&ImageListOptions{}, "image-list", "List images", func(cli *zstack.SRegion, args *ImageListOptions) error { - images, err := cli.GetImages(args.ZoneId, args.ImageId) - if err != nil { - return err - } - printList(images, 0, 0, 0, []string{}) - return nil - }) - - type ImageCreateOptions struct { - ZONE string - FILE string - FORMAT string `choices:"qcow2|raw|iso"` - PLATFORM string `choices:"Linux|Windows|Other"` - Desc string - } - - shellutils.R(&ImageCreateOptions{}, "image-create", "Create image", func(cli *zstack.SRegion, args *ImageCreateOptions) error { - f, err := os.Open(args.FILE) - if err != nil { - return err - } - defer f.Close() - finfo, err := f.Stat() - if err != nil { - return err - } - image, err := cli.CreateImage(args.ZONE, args.FILE, args.FORMAT, args.PLATFORM, args.Desc, f, finfo.Size(), nil) - if err != nil { - return err - } - printObject(image) - return nil - }) - - type ImageIdOptions struct { - ID string - } - - shellutils.R(&ImageIdOptions{}, "image-delete", "Delete image", func(cli *zstack.SRegion, args *ImageIdOptions) error { - return cli.DeleteImage(args.ID) - }) - -} diff --git a/pkg/multicloud/zstack/shell/image_server.go b/pkg/multicloud/zstack/shell/image_server.go deleted file mode 100644 index fb7ba49f03..0000000000 --- a/pkg/multicloud/zstack/shell/image_server.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ImageServerListOptions struct { - ZoneId string - ServerId string - } - shellutils.R(&ImageServerListOptions{}, "image-server-list", "List image servers", func(cli *zstack.SRegion, args *ImageServerListOptions) error { - servers, err := cli.GetImageServers(args.ZoneId, args.ServerId) - if err != nil { - return err - } - printList(servers, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/zstack/shell/instance.go b/pkg/multicloud/zstack/shell/instance.go deleted file mode 100644 index 57a30a1f8e..0000000000 --- a/pkg/multicloud/zstack/shell/instance.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "fmt" - - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceListOptions struct { - HostId string - InstanceId string - NicId string - } - shellutils.R(&InstanceListOptions{}, "instance-list", "List instances", func(cli *zstack.SRegion, args *InstanceListOptions) error { - instances, err := cli.GetInstances(args.HostId, args.InstanceId, args.NicId) - if err != nil { - return err - } - printList(instances, len(instances), 0, 0, []string{}) - return nil - }) - - type InstanceOperation struct { - ID string - } - - shellutils.R(&InstanceOperation{}, "instance-delete", "Delete instance", func(cli *zstack.SRegion, args *InstanceOperation) error { - return cli.DeleteVM(args.ID) - }) - - shellutils.R(&InstanceOperation{}, "instance-console-password", "Show instance console password", func(cli *zstack.SRegion, args *InstanceOperation) error { - password, err := cli.GetInstanceConsolePassword(args.ID) - if err != nil { - return err - } - fmt.Println(password) - return nil - }) - - shellutils.R(&InstanceOperation{}, "instance-console-info", "Show instance console info", func(cli *zstack.SRegion, args *InstanceOperation) error { - info, err := cli.GetInstanceConsoleInfo(args.ID) - if err != nil { - return err - } - printObject(info) - return nil - }) - - shellutils.R(&InstanceOperation{}, "instance-start", "Start instance", func(cli *zstack.SRegion, args *InstanceOperation) error { - return cli.StartVM(args.ID) - }) - - shellutils.R(&InstanceOperation{}, "instance-boot-order", "Show instance boot order", func(cli *zstack.SRegion, args *InstanceOperation) error { - fmt.Println(cli.GetBootOrder(args.ID)) - return nil - }) - - type InstanceStopOption struct { - ID string - IsForce bool - } - - shellutils.R(&InstanceStopOption{}, "instance-stop", "Start instance", func(cli *zstack.SRegion, args *InstanceStopOption) error { - return cli.StopVM(args.ID, args.IsForce) - }) - - type InstanceSecgroupOption struct { - ID string - SECGRPID string - } - - shellutils.R(&InstanceSecgroupOption{}, "instance-assign-secgroup", "Assign secgroup for a instance", func(cli *zstack.SRegion, args *InstanceSecgroupOption) error { - return cli.AssignSecurityGroup(args.ID, args.SECGRPID) - }) - - shellutils.R(&InstanceSecgroupOption{}, "instance-revoke-secgroup", "Assign secgroup for a instance", func(cli *zstack.SRegion, args *InstanceSecgroupOption) error { - return cli.RevokeSecurityGroup(args.ID, args.SECGRPID) - }) - -} diff --git a/pkg/multicloud/zstack/shell/instance_offering.go b/pkg/multicloud/zstack/shell/instance_offering.go deleted file mode 100644 index 94a6c733a5..0000000000 --- a/pkg/multicloud/zstack/shell/instance_offering.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type InstanceOfferingListOptions struct { - OfferId string - Name string - Cpu int - MemoryMb int - } - shellutils.R(&InstanceOfferingListOptions{}, "instance-offering-list", "List instance offerings", func(cli *zstack.SRegion, args *InstanceOfferingListOptions) error { - offerings, err := cli.GetInstanceOfferings(args.OfferId, args.Name, args.Cpu, args.MemoryMb) - if err != nil { - return err - } - printList(offerings, len(offerings), 0, 0, []string{}) - return nil - }) - - type InstanceOfferingCreateOptions struct { - NAME string - CPU int - MEMORY_MB int - TYPE string `choices:"UserVm"` - } - - shellutils.R(&InstanceOfferingCreateOptions{}, "instance-offering-create", "Create instance offerings", func(cli *zstack.SRegion, args *InstanceOfferingCreateOptions) error { - offer, err := cli.CreateInstanceOffering(args.NAME, args.CPU, args.MEMORY_MB, args.TYPE) - if err != nil { - return err - } - printObject(offer) - return nil - }) - - type InstanceOfferingIdOptions struct { - ID string - } - - shellutils.R(&InstanceOfferingIdOptions{}, "instance-offering-delete", "Delete instance offerings", func(cli *zstack.SRegion, args *InstanceOfferingIdOptions) error { - return cli.DeleteOffering(args.ID) - }) - -} diff --git a/pkg/multicloud/zstack/shell/monitor.go b/pkg/multicloud/zstack/shell/monitor.go deleted file mode 100644 index 2702460d58..0000000000 --- a/pkg/multicloud/zstack/shell/monitor.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/aliyun" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - shellutils.R(&cloudprovider.MetricListOptions{}, "metric-list", "List metrics in a namespace", func(cli *aliyun.SRegion, args *cloudprovider.MetricListOptions) error { - metrics, err := cli.GetClient().GetMetrics(args) - if err != nil { - return err - } - printList(metrics, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/zstack/shell/network.go b/pkg/multicloud/zstack/shell/network.go deleted file mode 100644 index e20e71c183..0000000000 --- a/pkg/multicloud/zstack/shell/network.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type NetworkListOptions struct { - ZoneId string - WireId string - VpcId string - NetworkId string - } - shellutils.R(&NetworkListOptions{}, "network-list", "List networks", func(cli *zstack.SRegion, args *NetworkListOptions) error { - networks, err := cli.GetNetworks(args.ZoneId, args.WireId, args.VpcId, args.NetworkId) - if err != nil { - return err - } - printList(networks, len(networks), 0, 0, []string{}) - return nil - }) - - type NetworkDeleteOptions struct { - ID string - } - - shellutils.R(&NetworkDeleteOptions{}, "network-delete", "Delete network", func(cli *zstack.SRegion, args *NetworkDeleteOptions) error { - return cli.DeleteNetwork(args.ID) - }) - - type NetworkCreateOptions struct { - NAME string - Desc string - WIRE string - CIDR string - } - - shellutils.R(&NetworkCreateOptions{}, "network-create", "Create network", func(cli *zstack.SRegion, args *NetworkCreateOptions) error { - network, err := cli.CreateNetwork(args.NAME, args.CIDR, args.WIRE, args.Desc) - if err != nil { - return err - } - printObject(network) - return nil - }) - - type L3NetworkListOptions struct { - ZoneId string - WireId string - Id string - } - - shellutils.R(&L3NetworkListOptions{}, "l3network-list", "List networks", func(cli *zstack.SRegion, args *L3NetworkListOptions) error { - l3networks, err := cli.GetL3Networks(args.ZoneId, args.WireId, args.Id) - if err != nil { - return err - } - printList(l3networks, len(l3networks), 0, 0, []string{}) - return nil - }) - - type NetworkServicesOptions struct { - } - - shellutils.R(&NetworkServicesOptions{}, "network-service-list", "List network services", func(cli *zstack.SRegion, args *NetworkServicesOptions) error { - service, err := cli.GetNetworkServices() - if err != nil { - return err - } - printObject(service) - return nil - }) - - type NetworkServiceProviderOptions struct { - Type string - } - - shellutils.R(&NetworkServiceProviderOptions{}, "network-service-provider-list", "List network service providers", func(cli *zstack.SRegion, args *NetworkServiceProviderOptions) error { - providers, err := cli.GetNetworkServiceProviders(args.Type) - if err != nil { - return err - } - printList(providers, len(providers), 0, 0, []string{}) - return nil - }) - - type NetworkServiceAttachOptions struct { - Services []string - ID string - } - - shellutils.R(&NetworkServiceAttachOptions{}, "network-service-attach", "Attach network service to l3network", func(cli *zstack.SRegion, args *NetworkServiceAttachOptions) error { - cli.AttachServiceForl3Network(args.ID, args.Services) - return nil - }) - - type NetworkServiceRefOptions struct { - L3Id string - Type string - } - - shellutils.R(&NetworkServiceRefOptions{}, "network-service-ref", "List network service ref", func(cli *zstack.SRegion, args *NetworkServiceRefOptions) error { - refs, err := cli.GetNetworkServiceRef(args.L3Id, args.Type) - if err != nil { - return err - } - printList(refs, len(refs), 0, 0, []string{}) - return nil - }) - - type NetworkServiceRemoveOptions struct { - L3ID string - SERVICE string `choices:"Userdata|DHCP|VipQos|HostRoute|Eip|SecurityGroup|DNS|SNAT"` - } - - shellutils.R(&NetworkServiceRemoveOptions{}, "remove-network-service", "Remove l3network service", func(cli *zstack.SRegion, args *NetworkServiceRemoveOptions) error { - return cli.RemoveNetworkService(args.L3ID, args.SERVICE) - }) - -} diff --git a/pkg/multicloud/zstack/shell/printutils.go b/pkg/multicloud/zstack/shell/printutils.go deleted file mode 100644 index 1b46ec704a..0000000000 --- a/pkg/multicloud/zstack/shell/printutils.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 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) -} diff --git a/pkg/multicloud/zstack/shell/quota.go b/pkg/multicloud/zstack/shell/quota.go deleted file mode 100644 index 671a5b1ba4..0000000000 --- a/pkg/multicloud/zstack/shell/quota.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type QuotaListOptions struct { - } - shellutils.R(&QuotaListOptions{}, "quota-list", "List quotas", func(cli *zstack.SRegion, args *QuotaListOptions) error { - quotas, err := cli.GetQuotas() - if err != nil { - return err - } - printList(quotas, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/zstack/shell/region.go b/pkg/multicloud/zstack/shell/region.go deleted file mode 100644 index 80d89a5bb0..0000000000 --- a/pkg/multicloud/zstack/shell/region.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type RegionListOptions struct { - } - shellutils.R(&RegionListOptions{}, "region-list", "List regions", func(cli *zstack.SRegion, args *RegionListOptions) error { - regions := cli.GetClient().GetRegions() - printList(regions, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/zstack/shell/securitygroup.go b/pkg/multicloud/zstack/shell/securitygroup.go deleted file mode 100644 index f109170102..0000000000 --- a/pkg/multicloud/zstack/shell/securitygroup.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SecurityGroupListOptions struct { - Name string - SecgroupId string - InstanceId string - } - shellutils.R(&SecurityGroupListOptions{}, "security-group-list", "List secgroups", func(cli *zstack.SRegion, args *SecurityGroupListOptions) error { - secgroups, err := cli.GetSecurityGroups(args.SecgroupId, args.InstanceId, args.Name) - if err != nil { - return err - } - printList(secgroups, len(secgroups), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/zstack/shell/snapshot.go b/pkg/multicloud/zstack/shell/snapshot.go deleted file mode 100644 index 47384530b8..0000000000 --- a/pkg/multicloud/zstack/shell/snapshot.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type SnapshotListOptions struct { - SnapshotId string - DiskId string - } - shellutils.R(&SnapshotListOptions{}, "snapshot-list", "List snapshots", func(cli *zstack.SRegion, args *SnapshotListOptions) error { - snapshots, err := cli.GetSnapshots(args.SnapshotId, args.DiskId) - if err != nil { - return err - } - printList(snapshots, len(snapshots), 0, 0, []string{}) - return nil - }) - - type SnapshoDeleteOptions struct { - ID string - } - - shellutils.R(&SnapshoDeleteOptions{}, "snapshot-delete", "Delete snapshot", func(cli *zstack.SRegion, args *SnapshoDeleteOptions) error { - return cli.DeleteSnapshot(args.ID) - }) - - type SnapshoCreateOptions struct { - DISKID string - NAME string - Desc string - } - - shellutils.R(&SnapshoCreateOptions{}, "snapshot-create", "Create snapshot", func(cli *zstack.SRegion, args *SnapshoCreateOptions) error { - snapshot, err := cli.CreateSnapshot(args.NAME, args.DISKID, args.Desc) - if err != nil { - return err - } - printObject(snapshot) - return nil - }) -} diff --git a/pkg/multicloud/zstack/shell/storage.go b/pkg/multicloud/zstack/shell/storage.go deleted file mode 100644 index 52f2fa01b1..0000000000 --- a/pkg/multicloud/zstack/shell/storage.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type StorageListOptions struct { - ZoneId string - ClusterId string - Id string - } - shellutils.R(&StorageListOptions{}, "storage-list", "List storages", func(cli *zstack.SRegion, args *StorageListOptions) error { - storages, err := cli.GetStorages(args.ZoneId, args.ClusterId, args.Id) - if err != nil { - return err - } - printList(storages, 0, 0, 0, []string{}) - return nil - }) - - type LocalStorageOptions struct { - STORAGE_ID string - HostId string - } - - shellutils.R(&LocalStorageOptions{}, "local-storage-list", "Show local storages", func(cli *zstack.SRegion, args *LocalStorageOptions) error { - storages, err := cli.GetLocalStorages(args.STORAGE_ID, args.HostId) - if err != nil { - return err - } - printList(storages, 0, 0, 0, []string{}) - return nil - }) - -} diff --git a/pkg/multicloud/zstack/shell/tag.go b/pkg/multicloud/zstack/shell/tag.go deleted file mode 100644 index 00a0d6d6c6..0000000000 --- a/pkg/multicloud/zstack/shell/tag.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type TagListOptions struct { - TagId string - ResourceType string - ResourceId string - Tag string - } - shellutils.R(&TagListOptions{}, "system-tag-list", "List system tags", func(cli *zstack.SRegion, args *TagListOptions) error { - tags, err := cli.GetResourceSysTags(args.TagId, args.ResourceType, args.ResourceId, args.Tag) - if err != nil { - return err - } - printList(tags, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/zstack/shell/user.go b/pkg/multicloud/zstack/shell/user.go deleted file mode 100644 index 4ab858233a..0000000000 --- a/pkg/multicloud/zstack/shell/user.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type UserListOptions struct { - Name string - } - shellutils.R(&UserListOptions{}, "user-list", "List users", func(cli *zstack.SRegion, args *UserListOptions) error { - users, err := cli.GetUserAccount(args.Name) - if err != nil { - return err - } - printList(users, 0, 0, 0, nil) - return nil - }) -} diff --git a/pkg/multicloud/zstack/shell/version.go b/pkg/multicloud/zstack/shell/version.go deleted file mode 100644 index 1bde64f04c..0000000000 --- a/pkg/multicloud/zstack/shell/version.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VersionShowOptions struct { - } - shellutils.R(&VersionShowOptions{}, "version-show", "Show version", func(cli *zstack.SRegion, args *VersionShowOptions) error { - ver, err := cli.GetClient().GetVersion() - if err != nil { - return err - } - printObject(ver) - return nil - }) -} diff --git a/pkg/multicloud/zstack/shell/vip.go b/pkg/multicloud/zstack/shell/vip.go deleted file mode 100644 index 7692d7ad40..0000000000 --- a/pkg/multicloud/zstack/shell/vip.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type VipListOptions struct { - VipId string - } - shellutils.R(&VipListOptions{}, "vip-list", "List vips", func(cli *zstack.SRegion, args *VipListOptions) error { - vips, err := cli.GetVirtualIPs(args.VipId) - if err != nil { - return err - } - printList(vips, 0, 0, 0, []string{}) - return nil - }) - - type VipCreateOptions struct { - NAME string - Desc string - Ip string - L3ID string - } - - shellutils.R(&VipCreateOptions{}, "vip-create", "Create vip", func(cli *zstack.SRegion, args *VipCreateOptions) error { - vip, err := cli.CreateVirtualIP(args.NAME, args.Desc, args.Ip, args.L3ID) - if err != nil { - return err - } - printObject(vip) - return nil - }) - -} diff --git a/pkg/multicloud/zstack/shell/wire.go b/pkg/multicloud/zstack/shell/wire.go deleted file mode 100644 index 814be1facf..0000000000 --- a/pkg/multicloud/zstack/shell/wire.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type WireListOptions struct { - ZoneId string - WireId string - ClusterId string - } - shellutils.R(&WireListOptions{}, "wire-list", "List wires", func(cli *zstack.SRegion, args *WireListOptions) error { - wires, err := cli.GetWires(args.ZoneId, args.WireId, args.ClusterId) - if err != nil { - return err - } - printList(wires, len(wires), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/zstack/shell/zone.go b/pkg/multicloud/zstack/shell/zone.go deleted file mode 100644 index 6015b8eaa8..0000000000 --- a/pkg/multicloud/zstack/shell/zone.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 shell - -import ( - "yunion.io/x/onecloud/pkg/multicloud/zstack" - "yunion.io/x/onecloud/pkg/util/shellutils" -) - -func init() { - type ZoneListOptions struct { - } - shellutils.R(&ZoneListOptions{}, "zone-list", "List zones", func(cli *zstack.SRegion, args *ZoneListOptions) error { - zones, err := cli.GetIZones() - if err != nil { - return err - } - printList(zones, len(zones), 0, 0, []string{}) - return nil - }) -} diff --git a/pkg/multicloud/zstack/snapshot.go b/pkg/multicloud/zstack/snapshot.go deleted file mode 100644 index bdf603f05e..0000000000 --- a/pkg/multicloud/zstack/snapshot.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "fmt" - "net/url" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SSnapshot struct { - multicloud.SResourceBase - multicloud.ZStackTags - region *SRegion - - ZStackBasic - PrimaryStorageUUID string `json:"primaryStorageUuid"` - VolumeUUID string `json:"volumeUuid"` - VolumeType string `json:"volumeType"` - Format string `json:"format"` - Latest bool `json:"latest"` - Size int `json:"size"` - State string `json:"state"` - Status string `json:"status"` -} - -func (snapshot *SSnapshot) GetId() string { - return snapshot.UUID -} - -func (snapshot *SSnapshot) GetName() string { - return snapshot.Name -} - -func (snapshot *SSnapshot) GetStatus() string { - switch snapshot.Status { - case "Ready": - return api.SNAPSHOT_READY - default: - log.Errorf("unknown snapshot %s(%s) status %s", snapshot.Name, snapshot.UUID, snapshot.Status) - return api.SNAPSHOT_UNKNOWN - } -} - -func (snapshot *SSnapshot) GetSizeMb() int32 { - return int32(snapshot.Size / 1024 / 1024) -} - -func (snapshot *SSnapshot) GetDiskId() string { - return snapshot.VolumeUUID -} - -func (snapshot *SSnapshot) GetDiskType() string { - switch snapshot.VolumeType { - case "Root": - return api.DISK_TYPE_SYS - default: - return api.DISK_TYPE_DATA - } -} - -func (snapshot *SSnapshot) Refresh() error { - new, err := snapshot.region.GetSnapshot(snapshot.UUID) - if err != nil { - return err - } - return jsonutils.Update(snapshot, new) -} - -func (snapshot *SSnapshot) GetGlobalId() string { - return snapshot.UUID -} - -func (snapshot *SSnapshot) IsEmulated() bool { - return false -} - -func (region *SRegion) GetSnapshot(snapshotId string) (*SSnapshot, error) { - snapshot := &SSnapshot{region: region} - return snapshot, region.client.getResource("volume-snapshots", snapshotId, snapshot) -} - -func (region *SRegion) GetSnapshots(snapshotId string, diskId string) ([]SSnapshot, error) { - snapshots := []SSnapshot{} - params := url.Values{} - if len(snapshotId) > 0 { - params.Add("q", "uuid="+snapshotId) - } - if len(diskId) > 0 { - params.Add("q", "volumeUuid="+diskId) - } - if err := region.client.listAll("volume-snapshots", params, &snapshots); err != nil { - return nil, err - } - for i := 0; i < len(snapshots); i++ { - snapshots[i].region = region - } - return snapshots, nil -} - -func (snapshot *SSnapshot) Delete() error { - return snapshot.region.DeleteSnapshot(snapshot.UUID) -} - -func (region *SRegion) DeleteSnapshot(snapshotId string) error { - return region.client.delete("volume-snapshots", snapshotId, "Enforcing") -} - -func (snapshot *SSnapshot) GetProjectId() string { - return "" -} - -func (region *SRegion) CreateSnapshot(name, diskId, desc string) (*SSnapshot, error) { - params := map[string]interface{}{ - "params": map[string]string{ - "name": name, - "description": desc, - }, - } - resource := fmt.Sprintf("volumes/%s/volume-snapshots", diskId) - resp, err := region.client.post(resource, jsonutils.Marshal(params)) - if err != nil { - return nil, err - } - snapshot := &SSnapshot{region: region} - return snapshot, resp.Unmarshal(snapshot, "inventory") -} diff --git a/pkg/multicloud/zstack/storage.go b/pkg/multicloud/zstack/storage.go deleted file mode 100644 index 57860f8b93..0000000000 --- a/pkg/multicloud/zstack/storage.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "fmt" - "net/url" - "strings" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type TStorageType string - -type TCephPoolType string - -const ( - StorageTypeCeph = TStorageType("Ceph") - StorageTypeLocal = TStorageType("LocalStorage") - StorageTypeVCenter = TStorageType("VCenter") - - CephPoolTypeData = TCephPoolType("Data") - CephPoolTypeRoot = TCephPoolType("Root") - CephPoolTypeImageCache = TCephPoolType("ImageCache") -) - -type SPool struct { - UUID string `json:"uuid"` - PrimaryStorageUUID string `json:"primaryStorageUuid"` - PoolName string `json:"poolName"` - Type TCephPoolType `json:"type"` - AvailableCapacity int64 `json:"availableCapacity"` - UsedCapacity int64 `json:"usedCapacity"` - ReplicatedSize int64 `json:"replicatedSize"` - TotalCapacity int64 `json:"totalCapacity"` - ZStackTime -} - -type SStorage struct { - multicloud.SStorageBase - multicloud.ZStackTags - region *SRegion - - ZStackBasic - VCenterUUID string `json:"VCenterUuid"` - Datastore string `json:"datastore"` - ZoneUUID string `json:"zoneUuid"` - URL string `json:"url"` - TotalCapacity int64 `json:"totalCapacity"` - AvailableCapacity int `json:"availableCapacity"` - TotalPhysicalCapacity int `json:"totalPhysicalCapacity"` - AvailablePhysicalCapacity int `json:"availablePhysicalCapacity"` - Type TStorageType `json:"type"` - State string `json:"state"` - Status string `json:"status"` - MountPath string `json:"mountPath"` - AttachedClusterUUIDs []string `json:"attachedClusterUuids"` - - Pools []SPool `json:"pools"` - - ZStackTime -} - -func (region *SRegion) getIStorages(zondId string) ([]cloudprovider.ICloudStorage, error) { - primaryStorages, err := region.GetStorages(zondId, "", "") - if err != nil { - return nil, err - } - istorage := []cloudprovider.ICloudStorage{} - for i := 0; i < len(primaryStorages); i++ { - primaryStorage := primaryStorages[i] - switch primaryStorage.Type { - case StorageTypeLocal: - ilocalStorages, err := region.getILocalStorages(primaryStorage.UUID, "") - if err != nil { - return nil, err - } - istorage = append(istorage, ilocalStorages...) - case StorageTypeCeph: - primaryStorage.region = region - istorage = append(istorage, &primaryStorage) - case StorageTypeVCenter: - } - } - return istorage, nil -} - -func (region *SRegion) GetStorage(storageId string) (*SStorage, error) { - if len(storageId) == 0 { - return nil, cloudprovider.ErrNotFound - } - storages, err := region.GetStorages("", "", storageId) - if err != nil { - return nil, err - } - if len(storages) == 1 && storages[0].UUID == storageId { - storages[0].region = region - return &storages[0], nil - } - if len(storages) == 0 { - return nil, cloudprovider.ErrNotFound - } - return nil, cloudprovider.ErrDuplicateId -} - -func (region *SRegion) GetStorages(zoneId, clusterId, storageId string) ([]SStorage, error) { - storages := []SStorage{} - params := url.Values{} - if len(zoneId) > 0 { - params.Add("q", "zone.uuid="+zoneId) - } - if len(clusterId) > 0 { - params.Add("q", "cluster.uuid="+clusterId) - } - if SkipEsxi { - params.Add("q", "type!=VCenter") - } - if len(storageId) > 0 { - params.Add("q", "uuid="+storageId) - } - return storages, region.client.listAll("primary-storage", params, &storages) -} - -func (storage *SStorage) GetStatus() string { - if storage.Status == "Connected" { - return api.STORAGE_ONLINE - } - return api.STORAGE_OFFLINE -} - -func (storage *SStorage) GetId() string { - return storage.UUID -} - -func (storage *SStorage) GetName() string { - return storage.Name -} - -func (storage *SStorage) GetGlobalId() string { - return storage.GetId() -} - -func (storage *SStorage) IsEmulated() bool { - return false -} - -func (storage *SStorage) GetIZone() cloudprovider.ICloudZone { - zone, err := storage.region.GetZone(storage.ZoneUUID) - if err != nil { - log.Errorf("failed to find zone for storage %s(%s)", storage.Name, storage.UUID) - return nil - } - return zone -} - -func (storage *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { - disks, err := storage.region.GetDisks(storage.UUID, []string{}, "") - if err != nil { - return nil, err - } - idisks := []cloudprovider.ICloudDisk{} - for i := 0; i < len(disks); i++ { - disks[i].storage = storage - disks[i].region = storage.region - idisks = append(idisks, &disks[i]) - } - return idisks, nil -} - -func (storage *SStorage) GetStorageType() string { - return strings.ToLower(string(storage.Type)) -} - -func (storage *SStorage) GetMediumType() string { - return api.DISK_TYPE_ROTATE -} - -func (storage *SStorage) GetCapacityMB() int64 { - return storage.TotalCapacity / 1024 / 1024 -} - -func (storage *SStorage) GetCapacityUsedMB() int64 { - return 0 -} - -func (storage *SStorage) GetStorageConf() jsonutils.JSONObject { - conf := jsonutils.NewDict() - return conf -} - -func (storage *SStorage) Refresh() error { - // do nothing - return nil -} - -func (storage *SStorage) GetEnabled() bool { - return true -} - -func (storage *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { - return &SStoragecache{ZoneId: storage.ZoneUUID, region: storage.region} -} - -func (storage *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { - poolName, err := storage.GetDataPoolName() - if err != nil { - return nil, err - } - disk, err := storage.region.CreateDisk(conf.Name, storage.UUID, "", poolName, conf.SizeGb, conf.Desc) - if err != nil { - return nil, err - } - disk.storage = storage - return disk, nil -} - -func (storage *SStorage) GetIDiskById(diskId string) (cloudprovider.ICloudDisk, error) { - disk, err := storage.region.GetDisk(diskId) - if err != nil { - return nil, err - } - if disk.PrimaryStorageUUID != storage.UUID { - return nil, cloudprovider.ErrNotFound - } - disk.region = storage.region - disk.storage = storage - return disk, nil -} - -func (storage *SStorage) GetMountPoint() string { - poolName, _ := storage.GetDataPoolName() - if len(poolName) > 0 { - return fmt.Sprintf("ceph://%s", poolName) - } - return "" -} - -func (storage *SStorage) IsSysDiskStore() bool { - return true -} - -func (storage *SStorage) GetDataPoolName() (string, error) { - for _, pool := range storage.Pools { - if pool.Type == CephPoolTypeData { - return pool.PoolName, nil - } - } - return "", fmt.Errorf("failed to found storage %s(%s) data pool name", storage.Name, storage.UUID) -} diff --git a/pkg/multicloud/zstack/storagecache.go b/pkg/multicloud/zstack/storagecache.go deleted file mode 100644 index 64dd5b1a7b..0000000000 --- a/pkg/multicloud/zstack/storagecache.go +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "context" - "fmt" - "time" - - "yunion.io/x/jsonutils" - "yunion.io/x/log" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "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" - modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/util/qemuimg" -) - -type SStoragecache struct { - multicloud.SResourceBase - multicloud.ZStackTags - ZoneId string - region *SRegion -} - -func (scache *SStoragecache) GetId() string { - return fmt.Sprintf("%s-%s/%s", scache.region.client.cpcfg.Id, scache.region.GetId(), scache.ZoneId) -} - -func (scache *SStoragecache) GetName() string { - return fmt.Sprintf("%s-%s/%s", scache.region.client.cpcfg.Name, scache.region.GetId(), scache.ZoneId) -} - -func (scache *SStoragecache) GetStatus() string { - return "available" -} - -func (scache *SStoragecache) Refresh() error { - return nil -} - -func (scache *SStoragecache) GetGlobalId() string { - return scache.GetId() -} - -func (scache *SStoragecache) IsEmulated() bool { - return false -} - -func (scache *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (scache *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { - images, err := scache.region.GetImages(scache.ZoneId, "") - if err != nil { - return nil, err - } - ret := []cloudprovider.ICloudImage{} - for i := 0; i < len(images); i++ { - images[i].storageCache = scache - ret = append(ret, &images[i]) - } - return ret, nil -} - -func (scache *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { - images, err := scache.region.GetImages(scache.ZoneId, extId) - if err != nil { - return nil, err - } - if len(images) == 1 { - images[0].storageCache = scache - return &images[0], nil - } - if len(images) == 0 { - return nil, cloudprovider.ErrNotFound - } - return nil, cloudprovider.ErrDuplicateId -} - -func (scache *SStoragecache) GetPath() string { - return "" -} - -func (scache *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - return scache.uploadImage(ctx, userCred, image, callback) -} - -func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { - s := auth.GetAdminSession(ctx, options.Options.Region) - - meta, reader, size, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false) - if err != nil { - return "", err - } - log.Infof("meta data %s", meta) - - // size, _ := meta.Int("size") - img, err := self.region.CreateImage(self.ZoneId, image.ImageName, string(qemuimg.QCOW2), image.OsType, "", reader, size, callback) - if err != nil { - return "", err - } - img.storageCache = self - err = cloudprovider.WaitStatus(img, api.CACHED_IMAGE_STATUS_ACTIVE, time.Second*5, time.Minute*20) //windows镜像转换比较慢,等待时间稍微设长一些 - if err != nil { - log.Errorf("waitting for image %s(%s) status ready timeout", img.Name, img.UUID) - } - if callback != nil { - callback(100) - } - return img.UUID, err -} - -func (scache *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { - return nil, cloudprovider.ErrNotImplemented -} - -func (scache *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { - return nil, cloudprovider.ErrNotImplemented -} diff --git a/pkg/multicloud/zstack/vip.go b/pkg/multicloud/zstack/vip.go deleted file mode 100644 index 5a063c26c7..0000000000 --- a/pkg/multicloud/zstack/vip.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "fmt" - "net/url" - - "github.com/pkg/errors" - - "yunion.io/x/jsonutils" - "yunion.io/x/pkg/util/netutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVirtualIP struct { - multicloud.SNetworkInterfaceBase - multicloud.ZStackTags - region *SRegion - ZStackBasic - IPRangeUUID string `json:"ipRangeUuid"` - L3NetworkUUID string `json:"l3NetworkUuid"` - IP string `json:"ip"` - State string `json:"state"` - Gateway string `json:"gateway"` - Netmask string `json:"netmask"` - PrefixLen int `json:"prefixLen"` - ServiceProvider string `json:"serviceProvider"` - PeerL3NetworkUuids []string `json:"peerL3NetworkUuids"` - UseFor string `json:"useFor"` - UsedIPUUID string `json:"usedIpUuid"` - ZStackTime -} - -type SInterfaceIP struct { - IP string - L3NetworkUUID string - IPRangeUUID string -} - -func (ip *SInterfaceIP) GetIP() string { - return ip.IP -} - -func (ip *SInterfaceIP) GetINetworkId() string { - return fmt.Sprintf("%s/%s", ip.L3NetworkUUID, ip.IPRangeUUID) -} - -func (ip *SInterfaceIP) IsPrimary() bool { - return true -} - -func (ip *SInterfaceIP) GetGlobalId() string { - return ip.IP -} - -func (vip *SVirtualIP) GetName() string { - if len(vip.Name) > 0 { - return vip.Name - } - return vip.UUID -} - -func (vip *SVirtualIP) GetId() string { - return vip.UUID -} - -func (vip *SVirtualIP) GetGlobalId() string { - return vip.UUID -} - -func (vip *SVirtualIP) GetMacAddress() string { - ip, _ := netutils.NewIPV4Addr(vip.IP) - return ip.ToMac("00:16:") -} - -func (vip *SVirtualIP) GetAssociateType() string { - switch vip.UseFor { - case "LoadBalancer": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_LOADBALANCER - case "Eip": - return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_RESERVED - } - return vip.UseFor -} - -func (vip *SVirtualIP) GetAssociateId() string { - return vip.UsedIPUUID -} - -func (vip *SVirtualIP) GetStatus() string { - if vip.State == "Enabled" { - return api.NETWORK_INTERFACE_STATUS_AVAILABLE - } - return api.NETWORK_INTERFACE_STATUS_UNKNOWN -} - -func (vip *SVirtualIP) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { - ip := &SInterfaceIP{IP: vip.IP, IPRangeUUID: vip.IPRangeUUID, L3NetworkUUID: vip.L3NetworkUUID} - return []cloudprovider.ICloudInterfaceAddress{ip}, nil -} - -func (region *SRegion) GetVirtualIP(vipId string) (*SVirtualIP, error) { - vip := &SVirtualIP{} - return vip, region.client.getResource("vips", vipId, vip) -} - -func (region *SRegion) GetNetworkId(vip *SVirtualIP) string { - networks, err := region.GetNetworks("", "", vip.L3NetworkUUID, "") - if err == nil { - for _, network := range networks { - if network.Contains(vip.IP) { - return fmt.Sprintf("%s/%s", vip.L3NetworkUUID, network.UUID) - } - } - } - return "" -} - -func (region *SRegion) GetVirtualIPs(vipId string) ([]SVirtualIP, error) { - vips := []SVirtualIP{} - params := url.Values{} - if len(vipId) > 0 { - params.Add("q", "uuid="+vipId) - } - return vips, region.client.listAll("vips", params, &vips) -} - -func (region *SRegion) CreateVirtualIP(name, desc, ip string, l3Id string) (*SVirtualIP, error) { - vip := SVirtualIP{} - params := map[string]map[string]string{ - "params": { - "name": name, - "description": desc, - "l3NetworkUuid": l3Id, - }, - } - if len(ip) > 0 { - params["params"]["requiredIp"] = ip - } - resp, err := region.client.post("vips", jsonutils.Marshal(params)) - if err != nil { - return nil, err - } - return &vip, resp.Unmarshal(&vip, "inventory") -} - -func (region *SRegion) DeleteVirtualIP(vipId string) error { - return region.client.delete("vips", vipId, "") -} - -func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { - vips, err := region.GetVirtualIPs("") - if err != nil { - return nil, errors.Wrap(err, "region.GetVirtualIPs") - } - ret := []cloudprovider.ICloudNetworkInterface{} - for i := 0; i < len(vips); i++ { - if vips[i].UseFor != "Eip" { - vips[i].region = region - ret = append(ret, &vips[i]) - } - } - return ret, nil -} diff --git a/pkg/multicloud/zstack/vpc.go b/pkg/multicloud/zstack/vpc.go deleted file mode 100644 index 56f1a2a8f5..0000000000 --- a/pkg/multicloud/zstack/vpc.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "fmt" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SVpc struct { - multicloud.SVpc - multicloud.ZStackTags - - region *SRegion - - iwires []cloudprovider.ICloudWire -} - -func (vpc *SVpc) GetId() string { - return fmt.Sprintf("%s/vpc", vpc.region.GetGlobalId()) -} - -func (vpc *SVpc) GetName() string { - return fmt.Sprintf("%s-VPC", vpc.region.client.cpcfg.Name) -} - -func (vpc *SVpc) GetGlobalId() string { - return vpc.GetId() -} - -func (vpc *SVpc) IsEmulated() bool { - return true -} - -func (vpc *SVpc) GetIsDefault() bool { - return true -} - -func (vpc *SVpc) GetCidrBlock() string { - return "" -} - -func (vpc *SVpc) GetStatus() string { - return api.VPC_STATUS_AVAILABLE -} - -func (vpc *SVpc) Refresh() error { - return nil -} - -func (vpc *SVpc) GetRegion() cloudprovider.ICloudRegion { - return vpc.region -} - -func (vpc *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { - if vpc.iwires == nil || len(vpc.iwires) == 0 { - vpc.iwires = []cloudprovider.ICloudWire{} - wires, err := vpc.region.GetWires("", "", "") - if err != nil { - return nil, err - } - for i := 0; i < len(wires); i++ { - wires[i].vpc = vpc - vpc.iwires = append(vpc.iwires, &wires[i]) - } - } - return vpc.iwires, nil -} - -func (vpc *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { - wire, err := vpc.region.GetWire(wireId) - if err != nil { - return nil, err - } - wire.vpc = vpc - return wire, nil -} - -func (vpc *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { - secgroups, err := vpc.region.GetSecurityGroups("", "", "") - if err != nil { - return nil, err - } - isecgroups := []cloudprovider.ICloudSecurityGroup{} - for i := 0; i < len(secgroups); i++ { - isecgroups = append(isecgroups, &secgroups[i]) - } - return isecgroups, nil -} - -func (vpc *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { - return nil, cloudprovider.ErrNotSupported -} - -func (vpc *SVpc) Delete() error { - return nil -} diff --git a/pkg/multicloud/zstack/wire.go b/pkg/multicloud/zstack/wire.go deleted file mode 100644 index e66e11d9ee..0000000000 --- a/pkg/multicloud/zstack/wire.go +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "fmt" - "net/url" - "strings" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SWire struct { - multicloud.SResourceBase - multicloud.ZStackTags - vpc *SVpc - - inetworks []cloudprovider.ICloudNetwork - - ZStackBasic - Vlan int `json:"vlan"` - ZoneUUID string `json:"zoneUuid"` - PhysicalInterface string `json:"physicalInterface"` - Type string `json:"type"` - ZStackTime - AttachedClusterUUIDs []string `json:"attachedClusterUuids"` -} - -func (region *SRegion) GetWire(wireId string) (*SWire, error) { - wire := &SWire{vpc: region.GetVpc()} - return wire, region.client.getResource("l2-networks", wireId, wire) -} - -func (region *SRegion) GetWires(zoneId string, wireId string, clusterId string) ([]SWire, error) { - wires := []SWire{} - clusterIds, err := region.GetClusterIds() - if err != nil { - return nil, err - } - params := url.Values{} - params.Add("q", "attachedClusterUuids?="+strings.Join(clusterIds, ",")) - if len(clusterId) > 0 { - params.Set("q", "attachedClusterUuids?="+clusterId) - } - if len(zoneId) > 0 { - params.Add("q", "zone.uuid="+zoneId) - } - if len(wireId) > 0 { - params.Add("q", "uuid="+wireId) - } - err = region.client.listAll("l2-networks", params, &wires) - if err != nil { - return nil, err - } - for i := 0; i < len(wires); i++ { - wires[i].vpc = region.GetVpc() - } - return wires, nil -} - -func (wire *SWire) GetId() string { - return wire.UUID -} - -func (wire *SWire) GetName() string { - return wire.Name -} - -func (wire *SWire) IsEmulated() bool { - return false -} - -func (wire *SWire) GetStatus() string { - return api.WIRE_STATUS_AVAILABLE -} - -func (wire *SWire) Refresh() error { - return nil -} - -func (wire *SWire) GetGlobalId() string { - return wire.UUID -} - -func (wire *SWire) GetIVpc() cloudprovider.ICloudVpc { - return nil -} - -func (wire *SWire) GetIZone() cloudprovider.ICloudZone { - zone, _ := wire.vpc.region.GetZone(wire.ZoneUUID) - return zone -} - -func (wire *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { - if wire.inetworks == nil || len(wire.inetworks) == 0 { - networks, err := wire.vpc.region.GetNetworks(wire.ZoneUUID, wire.UUID, "", "") - if err != nil { - return nil, err - } - wire.inetworks = []cloudprovider.ICloudNetwork{} - for i := 0; i < len(networks); i++ { - networks[i].wire = wire - wire.inetworks = append(wire.inetworks, &networks[i]) - } - } - return wire.inetworks, nil -} - -func (wire *SWire) GetBandwidth() int { - return 10000 -} - -func (wire *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { - network, err := wire.vpc.region.CreateNetwork(opts.Name, opts.Cidr, wire.UUID, opts.Desc) - if err != nil { - return nil, err - } - network.wire = wire - return network, nil -} - -func (wire *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { - idInfo := strings.Split(netid, "/") - if len(idInfo) == 2 { - network, err := wire.vpc.region.GetNetwork(wire.ZoneUUID, wire.UUID, idInfo[0], idInfo[1]) - if err != nil { - return nil, err - } - network.wire = wire - return network, nil - } - return nil, fmt.Errorf("invalid netid %s", netid) -} diff --git a/pkg/multicloud/zstack/zone.go b/pkg/multicloud/zstack/zone.go deleted file mode 100644 index 6a3f0cbce7..0000000000 --- a/pkg/multicloud/zstack/zone.go +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2019 Yunion -// -// 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 zstack - -import ( - "strconv" - - "yunion.io/x/log" - "yunion.io/x/pkg/util/fileutils" - - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" -) - -type SZone struct { - multicloud.SResourceBase - multicloud.ZStackTags - region *SRegion - - ZStackBasic - Type string - State string - cpuCmtbound float32 - memCmtbound float32 - reservedMemeoryMb int - - iwires []cloudprovider.ICloudWire - istorages []cloudprovider.ICloudStorage - - ihosts []cloudprovider.ICloudHost -} - -func (zone *SZone) GetId() string { - return zone.Name -} - -func (zone *SZone) GetName() string { - return zone.Name -} - -func (zone *SZone) GetI18n() cloudprovider.SModelI18nTable { - table := cloudprovider.SModelI18nTable{} - table["name"] = cloudprovider.NewSModelI18nEntry(zone.GetName()).CN(zone.GetName()) - return table -} - -func (zone *SZone) GetGlobalId() string { - return zone.GetId() -} - -func (zone *SZone) IsEmulated() bool { - return false -} - -func (zone *SZone) GetStatus() string { - if zone.State == "Enabled" { - return api.ZONE_ENABLE - } - return api.ZONE_DISABLE -} - -func (zone *SZone) Refresh() error { - // do nothing - return nil -} - -func (zone *SZone) GetIRegion() cloudprovider.ICloudRegion { - return zone.region -} - -func (zone *SZone) fetchHostCmtbound() { - if zone.cpuCmtbound > 0 || zone.memCmtbound > 0 || zone.reservedMemeoryMb > 0 { - return - } - configurations, err := zone.region.GetConfigrations() - if err != nil { - log.Errorf("failed to get global configurations error: %v", err) - return - } - for _, config := range configurations { - if config.Name == "cpu.overProvisioning.ratio" && config.Category == "host" { - if cpuCmtbound, err := strconv.ParseFloat(config.Value, 32); err == nil { - zone.cpuCmtbound = float32(cpuCmtbound) - } - } - if config.Name == "reservedMemory" && config.Category == "kvm" { - zone.reservedMemeoryMb, _ = fileutils.GetSizeMb(config.Value, 'M', 1024) - } - if config.Name == "overProvisioning.memory" && config.Category == "mevoco" { - if memCmtbound, err := strconv.ParseFloat(config.Value, 32); err == nil { - zone.memCmtbound = float32(memCmtbound) - } - } - } -} - -func (zone *SZone) fetchStorages(clusterId string) error { - storages, err := zone.region.getIStorages(zone.UUID) - if err != nil { - return err - } - zone.istorages = storages - return nil -} - -func (zone *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { - if zone.istorages == nil || len(zone.istorages) == 0 { - return zone.istorages, zone.fetchStorages("") - } - return zone.istorages, nil -} - -func (zone *SZone) GetIStorageById(storageId string) (cloudprovider.ICloudStorage, error) { - err := zone.fetchStorages("") - if err != nil { - return nil, err - } - for i := 0; i < len(zone.istorages); i++ { - if zone.istorages[i].GetGlobalId() == storageId { - return zone.istorages[i], nil - } - } - return nil, cloudprovider.ErrNotFound -} - -func (zone *SZone) GetIHostById(hostId string) (cloudprovider.ICloudHost, error) { - host, err := zone.region.GetHost(hostId) - if err != nil { - return nil, err - } - if host.ZoneUUID != zone.UUID { - return nil, cloudprovider.ErrNotFound - } - host.zone = zone - return host, nil -} - -func (zone *SZone) fetchHosts() error { - hosts, err := zone.region.GetHosts(zone.UUID, "") - if err != nil { - return err - } - zone.ihosts = []cloudprovider.ICloudHost{} - for i := 0; i < len(hosts); i++ { - hosts[i].zone = zone - zone.ihosts = append(zone.ihosts, &hosts[i]) - } - return nil -} - -func (zone *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { - if zone.ihosts == nil || len(zone.ihosts) == 0 { - return zone.ihosts, zone.fetchHosts() - } - return zone.ihosts, nil -} - -func (zone *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { - if zone.iwires == nil || len(zone.iwires) == 0 { - wires, err := zone.region.GetWires(zone.UUID, "", "") - if err != nil { - return nil, err - } - zone.iwires = []cloudprovider.ICloudWire{} - for i := 0; i < len(wires); i++ { - zone.iwires = append(zone.iwires, &wires[i]) - } - } - return zone.iwires, nil -} diff --git a/pkg/notify/models/event_template.go b/pkg/notify/models/event_template.go index cc480879eb..47a719b93e 100644 --- a/pkg/notify/models/event_template.go +++ b/pkg/notify/models/event_template.go @@ -52,7 +52,7 @@ type sEvenWebhookMsg struct { ResourceDetails map[string]interface{} `json:"resource_details"` } -//templateDir = "/opt/yunion/share/local-templates" +// templateDir = "/opt/yunion/share/local-templates" type SLocalTemplateManager struct { templateDir string templatesTable *sync.Map diff --git a/pkg/s3gateway/handlers/handlers.go b/pkg/s3gateway/handlers/handlers.go index 0b5bbdb140..1b18214911 100644 --- a/pkg/s3gateway/handlers/handlers.go +++ b/pkg/s3gateway/handlers/handlers.go @@ -23,6 +23,7 @@ import ( "github.com/minio/minio-go/pkg/s3utils" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/regutils" @@ -30,7 +31,6 @@ import ( "yunion.io/x/s3cli" "yunion.io/x/onecloud/pkg/appsrv" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/auth" diff --git a/pkg/s3gateway/handlers/multipart.go b/pkg/s3gateway/handlers/multipart.go index 33d7a4a26c..955c47dcbc 100644 --- a/pkg/s3gateway/handlers/multipart.go +++ b/pkg/s3gateway/handlers/multipart.go @@ -19,10 +19,10 @@ import ( "net/http" "sort" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/errors" "yunion.io/x/s3cli" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/s3gateway/models" ) diff --git a/pkg/s3gateway/handlers/object.go b/pkg/s3gateway/handlers/object.go index ddebb8fa37..60a5bdf545 100644 --- a/pkg/s3gateway/handlers/object.go +++ b/pkg/s3gateway/handlers/object.go @@ -22,13 +22,13 @@ import ( "strconv" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/timeutils" "yunion.io/x/s3cli" "yunion.io/x/onecloud/pkg/appsrv" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/s3gateway/models" diff --git a/pkg/s3gateway/models/buckets.go b/pkg/s3gateway/models/buckets.go index 5dcc3c9e59..dd0d3a2166 100644 --- a/pkg/s3gateway/models/buckets.go +++ b/pkg/s3gateway/models/buckets.go @@ -20,11 +20,11 @@ import ( "github.com/pkg/errors" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/pkg/gotypes" "yunion.io/x/s3cli" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" @@ -45,46 +45,46 @@ func init() { } /* -{ - "access_urls":[{"description":"bucket domain","primary":true,"url":"https://yunion-billing-reports.s3.cn-northwest-1.amazonaws.com.cn"},{"description":"s3 domain","primary":false,"url":"https://s3.cn-northwest-1.amazonaws.com.cn/yunion-billing-reports"}], - "account":"aws-cn", - "account_id":"edc90a61-7f8a-4be7-84f1-8f3ac70ef5e6", - "acl":"private", - "brand":"Aws", - "can_delete":false, - "can_update":true, - "cloud_env":"public", - "cloudregion_id":"4cbf92a5-337b-4cc6-82c7-86e5427b69e3", - "created_at":"2019-03-11T10:31:26.000000Z", - "domain_id":"default", - "external_id":"yunion-billing-reports", - "id":"056bb8c6-527d-4554-8939-12eb6aa803bd", - "is_emulated":false, - "is_system":false, - "location":"cn-northwest-1", - "manager":"aws-cn", - "manager_domain":"Default", - "manager_domain_id":"default", - "manager_id":"d8df39fa-b212-43c1-8d44-aeef897e216d", - "manager_project":"system", - "manager_project_id":"5d65667d112e47249ae66dbd7bc07030", - "name":"yunion-billing-reports", - "object_cnt":44, - "object_cnt_limit":0, - "project_domain":"Default", - "project_src":"cloud", - "provider":"Aws", - "region":"AWS 中国(宁夏)", - "region_ext_id":"cn-northwest-1", - "region_id":"4cbf92a5-337b-4cc6-82c7-86e5427b69e3", - "size_bytes":3332448, - "size_bytes_limit":0, - "status":"ready", - "tenant":"system", - "tenant_id":"5d65667d112e47249ae66dbd7bc07030", - "update_version":1, - "updated_at":"2019-08-18T15:52:42.000000Z", -} + { + "access_urls":[{"description":"bucket domain","primary":true,"url":"https://yunion-billing-reports.s3.cn-northwest-1.amazonaws.com.cn"},{"description":"s3 domain","primary":false,"url":"https://s3.cn-northwest-1.amazonaws.com.cn/yunion-billing-reports"}], + "account":"aws-cn", + "account_id":"edc90a61-7f8a-4be7-84f1-8f3ac70ef5e6", + "acl":"private", + "brand":"Aws", + "can_delete":false, + "can_update":true, + "cloud_env":"public", + "cloudregion_id":"4cbf92a5-337b-4cc6-82c7-86e5427b69e3", + "created_at":"2019-03-11T10:31:26.000000Z", + "domain_id":"default", + "external_id":"yunion-billing-reports", + "id":"056bb8c6-527d-4554-8939-12eb6aa803bd", + "is_emulated":false, + "is_system":false, + "location":"cn-northwest-1", + "manager":"aws-cn", + "manager_domain":"Default", + "manager_domain_id":"default", + "manager_id":"d8df39fa-b212-43c1-8d44-aeef897e216d", + "manager_project":"system", + "manager_project_id":"5d65667d112e47249ae66dbd7bc07030", + "name":"yunion-billing-reports", + "object_cnt":44, + "object_cnt_limit":0, + "project_domain":"Default", + "project_src":"cloud", + "provider":"Aws", + "region":"AWS 中国(宁夏)", + "region_ext_id":"cn-northwest-1", + "region_id":"4cbf92a5-337b-4cc6-82c7-86e5427b69e3", + "size_bytes":3332448, + "size_bytes_limit":0, + "status":"ready", + "tenant":"system", + "tenant_id":"5d65667d112e47249ae66dbd7bc07030", + "update_version":1, + "updated_at":"2019-08-18T15:52:42.000000Z", + } */ type SBucketDelegate struct { SBaseModelDelegate diff --git a/pkg/s3gateway/models/cloudproviders.go b/pkg/s3gateway/models/cloudproviders.go index 457af29827..0da9c2747d 100644 --- a/pkg/s3gateway/models/cloudproviders.go +++ b/pkg/s3gateway/models/cloudproviders.go @@ -22,12 +22,12 @@ import ( "golang.org/x/net/http/httpproxy" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/gotypes" "yunion.io/x/pkg/utils" proxyapi "yunion.io/x/onecloud/pkg/apis/cloudcommon/proxy" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" "yunion.io/x/onecloud/pkg/s3gateway/session" diff --git a/pkg/s3gateway/service/service.go b/pkg/s3gateway/service/service.go index 7395b82151..f6d2e5170c 100644 --- a/pkg/s3gateway/service/service.go +++ b/pkg/s3gateway/service/service.go @@ -17,6 +17,7 @@ package service import ( "os" + _ "yunion.io/x/cloudmux/pkg/multicloud/loader" "yunion.io/x/log" _ "yunion.io/x/sqlchemy/backends" @@ -24,7 +25,6 @@ import ( "yunion.io/x/onecloud/pkg/cloudcommon" app_common "yunion.io/x/onecloud/pkg/cloudcommon/app" common_options "yunion.io/x/onecloud/pkg/cloudcommon/options" - _ "yunion.io/x/onecloud/pkg/multicloud/loader" "yunion.io/x/onecloud/pkg/s3gateway/handlers" "yunion.io/x/onecloud/pkg/s3gateway/options" ) diff --git a/pkg/scheduledtask/models/scheduled_tasks.go b/pkg/scheduledtask/models/scheduled_tasks.go index b013956fd9..41ecda789e 100644 --- a/pkg/scheduledtask/models/scheduled_tasks.go +++ b/pkg/scheduledtask/models/scheduled_tasks.go @@ -681,7 +681,8 @@ var ( // Action itself is meaningless, a meaningful Action is generated by // calling Resource, Operation, Session and DefaultParams. // A example: -// Action.ResourceOperation(ServerStart).Session(...).Apply(...) +// +// Action.ResourceOperation(ServerStart).Session(...).Apply(...) var Action = SAction{timeout: 5 * time.Minute} // SAction encapsulates action to for onecloud resources diff --git a/pkg/scheduler/algorithm/predicates/guest/image_predicate.go b/pkg/scheduler/algorithm/predicates/guest/image_predicate.go index 4a738b4a6a..33d30e075e 100644 --- a/pkg/scheduler/algorithm/predicates/guest/image_predicate.go +++ b/pkg/scheduler/algorithm/predicates/guest/image_predicate.go @@ -19,10 +19,10 @@ import ( "database/sql" "fmt" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/scheduler/algorithm/predicates" "yunion.io/x/onecloud/pkg/scheduler/core" diff --git a/pkg/util/alipayclient/alipay.go b/pkg/util/alipayclient/alipay.go index 3d3dab8d33..1330164b8b 100644 --- a/pkg/util/alipayclient/alipay.go +++ b/pkg/util/alipayclient/alipay.go @@ -158,8 +158,9 @@ type SAlipaySystemOAuthTokenResponse struct { } // {"alipay_system_oauth_token_response":{"access_token":"authusrB9ee9ecc8105e4fc4869b41e8a470dX90","alipay_user_id":"20881023391875409149385062614990","expires_in":1296000, -// "re_expires_in":2592000,"refresh_token":"authusrBe1a9c0bdf8d344e786ee57f2df9d6E90","user_id":"2088002723447908"}, -// "sign":"rXGE/YX12UrmkEae9jw9WD7B2dS13Hs0r+EnqWwKdERGsUiFmP..."} +// +// "re_expires_in":2592000,"refresh_token":"authusrBe1a9c0bdf8d344e786ee57f2df9d6E90","user_id":"2088002723447908"}, +// "sign":"rXGE/YX12UrmkEae9jw9WD7B2dS13Hs0r+EnqWwKdERGsUiFmP..."} func (c *SAlipayClient) GetOAuthToken(ctx context.Context, code string) (*SAlipaySystemOAuthTokenResponse, error) { resp, err := c.execute(ctx, "alipay.system.oauth.token", map[string]string{ "code": code, @@ -177,7 +178,8 @@ func (c *SAlipayClient) GetOAuthToken(ctx context.Context, code string) (*SAlipa } // {"alipay_user_info_share_response":{"code":"10000","msg":"Success","city":"北京市","gender":"m","nick_name":"剑","province":"北京","user_id":"2088002723447908"}, -// "sign":"WZ+uBloiHvQYOOxq02aS/Y4MEoZf5+ANBnt1OKQ9Z8hOPmQsw=="} +// +// "sign":"WZ+uBloiHvQYOOxq02aS/Y4MEoZf5+ANBnt1OKQ9Z8hOPmQsw=="} func (c *SAlipayClient) GetUserInfo(ctx context.Context, authToken string) (map[string]string, error) { resp, err := c.execute(ctx, "alipay.user.info.share", map[string]string{ "auth_token": authToken, diff --git a/pkg/util/atexit/atexit.go b/pkg/util/atexit/atexit.go index 20d20a065c..43ef6fbbba 100644 --- a/pkg/util/atexit/atexit.go +++ b/pkg/util/atexit/atexit.go @@ -26,7 +26,7 @@ type ExitHandlerFunc func(ExitHandler) // ExitHandler defines the spec of handler // -// Reason and Func are mandatory and must not be empty or nil +// # Reason and Func are mandatory and must not be empty or nil // // Handlers with smaller Prio will be executed earlier than those with bigger // Prio at exit time. Handler func will receive a copy of the ExitHandler diff --git a/pkg/util/cephutils/ceph.go b/pkg/util/cephutils/ceph.go index 0bfa1fbcc8..846e07e379 100644 --- a/pkg/util/cephutils/ceph.go +++ b/pkg/util/cephutils/ceph.go @@ -21,13 +21,13 @@ import ( "os" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/fileutils2" "yunion.io/x/onecloud/pkg/util/procutils" ) diff --git a/pkg/util/gin/middleware/log.go b/pkg/util/gin/middleware/log.go index 3a576c5907..7d9ab80d85 100644 --- a/pkg/util/gin/middleware/log.go +++ b/pkg/util/gin/middleware/log.go @@ -58,8 +58,9 @@ func ErrorLoggerT(typ gin.ErrorType) gin.HandlerFunc { // http://godoc.org/github.com/gin-gonic/gin#Logger does. // // Example: -// router := gin.New() -// router.Use(ginglog.Logger()) +// +// router := gin.New() +// router.Use(ginglog.Logger()) func Logger() gin.HandlerFunc { return func(c *gin.Context) { t := time.Now() diff --git a/pkg/util/qemuimg/qemuimg.go b/pkg/util/qemuimg/qemuimg.go index 97bba092bf..7e94c49de9 100644 --- a/pkg/util/qemuimg/qemuimg.go +++ b/pkg/util/qemuimg/qemuimg.go @@ -20,13 +20,13 @@ import ( "strconv" "strings" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" "yunion.io/x/log" "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/fileutils2" "yunion.io/x/onecloud/pkg/util/procutils" "yunion.io/x/onecloud/pkg/util/qemutils" diff --git a/pkg/util/rbacutils/policycore.go b/pkg/util/rbacutils/policycore.go index 1b872868c9..6689ecbab4 100644 --- a/pkg/util/rbacutils/policycore.go +++ b/pkg/util/rbacutils/policycore.go @@ -93,8 +93,9 @@ func (policy TPolicy) Explain(request [][]string) [][]string { } // Contains of TPolicy -// TPolicy p1 contains p2 means any action allowed by p2 is also allowed by p1 -// and any action denied by p1 is also denied by p2 +// +// TPolicy p1 contains p2 means any action allowed by p2 is also allowed by p1 +// and any action denied by p1 is also denied by p2 func (policy1 TPolicy) Contains(policy2 TPolicy) bool { for _, rule := range policy2 { if rule.Result == Allow { diff --git a/pkg/util/rbacutils/policyset.go b/pkg/util/rbacutils/policyset.go index 636314384e..c4c66e8ed9 100644 --- a/pkg/util/rbacutils/policyset.go +++ b/pkg/util/rbacutils/policyset.go @@ -59,7 +59,8 @@ func (policies TPolicySet) Encode() jsonutils.JSONObject { } // Contains of TPolicySet -// TPolicySet ps1 contains ps2 means any member of ps2 is contained by one of the members of ps1 +// +// TPolicySet ps1 contains ps2 means any member of ps2 is contained by one of the members of ps1 func (policies1 TPolicySet) Contains(policies2 TPolicySet) bool { for _, ps2 := range policies2 { contained := false diff --git a/pkg/util/rbacutils/policytags.go b/pkg/util/rbacutils/policytags.go index 43216eaba5..3d140debe4 100644 --- a/pkg/util/rbacutils/policytags.go +++ b/pkg/util/rbacutils/policytags.go @@ -108,8 +108,8 @@ func (policy SPolicy) Encode() jsonutils.JSONObject { } // policy1 contains policy2 means -// 1. any action allow in policy2 is allowed in policy1 -// 2. policy tags of policy1 contains of policy tags of policy2 +// 1. any action allow in policy2 is allowed in policy1 +// 2. policy tags of policy1 contains of policy tags of policy2 func (policy1 SPolicy) Contains(policy2 SPolicy) bool { if !policy1.Rules.Contains(policy2.Rules) { return false diff --git a/pkg/util/s3auth/v2.go b/pkg/util/s3auth/v2.go index e2f78603b6..039c8949a9 100644 --- a/pkg/util/s3auth/v2.go +++ b/pkg/util/s3auth/v2.go @@ -36,11 +36,12 @@ const ( // From the Amazon docs: // // StringToSign = HTTP-Verb + "\n" + -// Content-Md5 + "\n" + -// Content-Type + "\n" + -// Date + "\n" + -// CanonicalizedProtocolHeaders + -// CanonicalizedResource; +// +// Content-Md5 + "\n" + +// Content-Type + "\n" + +// Date + "\n" + +// CanonicalizedProtocolHeaders + +// CanonicalizedResource; func stringToSignV2(req http.Request, virtualHost bool) string { buf := new(bytes.Buffer) // Write standard headers. @@ -128,8 +129,9 @@ var resourceList = []string{ // From the Amazon docs: // // CanonicalizedResource = [ "/" + Bucket ] + -// + -// [ sub-resource, if present. For example "?acl", "?location", "?logging", or "?torrent"]; +// +// + +// [ sub-resource, if present. For example "?acl", "?location", "?logging", or "?torrent"]; func writeCanonicalizedResource(buf *bytes.Buffer, req http.Request, virtualHost bool) { // Save request URL. requestURL := req.URL diff --git a/pkg/util/s3auth/v4.go b/pkg/util/s3auth/v4.go index 535afa3dcf..5b0bd8662e 100644 --- a/pkg/util/s3auth/v4.go +++ b/pkg/util/s3auth/v4.go @@ -68,41 +68,41 @@ func getStringToSignV4(t time.Time, location, canonicalRequest string) string { return stringToSign } -/// -/// Excerpts from @lsegal - -/// https://github.com/aws/aws-sdk-js/issues/659#issuecomment-120477258. -/// -/// User-Agent: -/// -/// This is ignored from signing because signing this causes -/// problems with generating pre-signed URLs (that are executed -/// by other agents) or when customers pass requests through -/// proxies, which may modify the user-agent. -/// -/// Content-Length: -/// -/// This is ignored from signing because generating a pre-signed -/// URL should not provide a content-length constraint, -/// specifically when vending a S3 pre-signed PUT URL. The -/// corollary to this is that when sending regular requests -/// (non-pre-signed), the signature contains a checksum of the -/// body, which implicitly validates the payload length (since -/// changing the number of bytes would change the checksum) -/// and therefore this header is not valuable in the signature. -/// -/// Content-Type: -/// -/// Signing this header causes quite a number of problems in -/// browser environments, where browsers like to modify and -/// normalize the content-type header in different ways. There is -/// more information on this in https://goo.gl/2E9gyy. Avoiding -/// this field simplifies logic and reduces the possibility of -/// future bugs. -/// -/// Authorization: -/// -/// Is skipped for obvious reasons -/// +// / +// / Excerpts from @lsegal - +// / https://github.com/aws/aws-sdk-js/issues/659#issuecomment-120477258. +// / +// / User-Agent: +// / +// / This is ignored from signing because signing this causes +// / problems with generating pre-signed URLs (that are executed +// / by other agents) or when customers pass requests through +// / proxies, which may modify the user-agent. +// / +// / Content-Length: +// / +// / This is ignored from signing because generating a pre-signed +// / URL should not provide a content-length constraint, +// / specifically when vending a S3 pre-signed PUT URL. The +// / corollary to this is that when sending regular requests +// / (non-pre-signed), the signature contains a checksum of the +// / body, which implicitly validates the payload length (since +// / changing the number of bytes would change the checksum) +// / and therefore this header is not valuable in the signature. +// / +// / Content-Type: +// / +// / Signing this header causes quite a number of problems in +// / browser environments, where browsers like to modify and +// / normalize the content-type header in different ways. There is +// / more information on this in https://goo.gl/2E9gyy. Avoiding +// / this field simplifies logic and reduces the possibility of +// / future bugs. +// / +// / Authorization: +// / +// / Is skipped for obvious reasons +// / var v4IgnoredHeaders = map[string]bool{ "Authorization": true, "Content-Type": true, @@ -134,12 +134,13 @@ func getSignature(signingKey []byte, stringToSign string) string { // getCanonicalRequest generate a canonical request of style. // // canonicalRequest = -// \n -// \n -// \n -// \n -// \n -// +// +// \n +// \n +// \n +// \n +// \n +// func getCanonicalRequest(req http.Request, signedHeaders []string) string { req.URL.RawQuery = strings.Replace(req.URL.Query().Encode(), "+", "%20", -1) canonicalRequest := strings.Join([]string{ diff --git a/pkg/util/sysutils/sysutils.go b/pkg/util/sysutils/sysutils.go index 1e8f53cdab..134719b857 100644 --- a/pkg/util/sysutils/sysutils.go +++ b/pkg/util/sysutils/sysutils.go @@ -290,10 +290,9 @@ func GetSerialPorts(lines []string) []string { // ParseSGMap parse command 'sg_map -x' outputs: // -// /dev/sg1 0 2 0 0 0 /dev/sda -// /dev/sg2 0 2 1 0 0 /dev/sdb -// /dev/sg3 0 2 2 0 0 /dev/sdc -// +// /dev/sg1 0 2 0 0 0 /dev/sda +// /dev/sg2 0 2 1 0 0 /dev/sdb +// /dev/sg3 0 2 2 0 0 /dev/sdc func ParseSGMap(lines []string) []compute.SGMapItem { ret := make([]compute.SGMapItem, 0) for _, l := range lines { diff --git a/pkg/util/tagutils/tagsetlist.go b/pkg/util/tagutils/tagsetlist.go index 3bf4508e6e..56ee086d1d 100644 --- a/pkg/util/tagutils/tagsetlist.go +++ b/pkg/util/tagutils/tagsetlist.go @@ -46,8 +46,9 @@ func (t1 TTagSetList) Contains(t2 TTagSet) bool { } // Contains of TTagSetList -// tagsetlist t1 contains tagsetlist t2 means any tag set of t2 is -// contained by one of the tag set of t1 +// +// tagsetlist t1 contains tagsetlist t2 means any tag set of t2 is +// contained by one of the tag set of t1 func (t1 TTagSetList) ContainsAll(t2 TTagSetList) bool { if len(t2) == 0 { return true diff --git a/pkg/webconsole/session/remote_console.go b/pkg/webconsole/session/remote_console.go index 6324a22d63..ca3bbcc3d8 100644 --- a/pkg/webconsole/session/remote_console.go +++ b/pkg/webconsole/session/remote_console.go @@ -19,10 +19,10 @@ import ( "net/url" "os/exec" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/jsonutils" api "yunion.io/x/onecloud/pkg/apis/webconsole" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/mcclient" modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" "yunion.io/x/onecloud/pkg/webconsole/options" diff --git a/vendor/github.com/fatih/color/README.md b/vendor/github.com/fatih/color/README.md index d62e4024aa..5152bf59bf 100644 --- a/vendor/github.com/fatih/color/README.md +++ b/vendor/github.com/fatih/color/README.md @@ -78,7 +78,7 @@ notice("Don't forget this...") ### Custom fprint functions (FprintFunc) ```go -blue := color.New(FgBlue).FprintfFunc() +blue := color.New(color.FgBlue).FprintfFunc() blue(myWriter, "important notice: %s", stars) // Mix up with multiple attributes @@ -127,14 +127,16 @@ fmt.Println("All text will now be bold magenta.") There might be a case where you want to explicitly disable/enable color output. the `go-isatty` package will automatically disable color output for non-tty output streams -(for example if the output were piped directly to `less`) +(for example if the output were piped directly to `less`). -`Color` has support to disable/enable colors both globally and for single color -definitions. For example suppose you have a CLI app and a `--no-color` bool flag. You -can easily disable the color output with: +The `color` package also disables color output if the [`NO_COLOR`](https://no-color.org) environment +variable is set (regardless of its value). + +`Color` has support to disable/enable colors programatically both globally and +for single color definitions. For example suppose you have a CLI app and a +`--no-color` bool flag. You can easily disable the color output with: ```go - var flagNoColor = flag.Bool("no-color", false, "Disable color output") if *flagNoColor { @@ -156,6 +158,10 @@ c.EnableColor() c.Println("This prints again cyan...") ``` +## GitHub Actions + +To output color in GitHub Actions (or other CI systems that support ANSI colors), make sure to set `color.NoColor = false` so that it bypasses the check for non-tty output streams. + ## Todo * Save/Return previous values @@ -170,4 +176,3 @@ c.Println("This prints again cyan...") ## License The MIT License (MIT) - see [`LICENSE.md`](https://github.com/fatih/color/blob/master/LICENSE.md) for more details - diff --git a/vendor/github.com/fatih/color/color.go b/vendor/github.com/fatih/color/color.go index 91c8e9f062..98a60f3c88 100644 --- a/vendor/github.com/fatih/color/color.go +++ b/vendor/github.com/fatih/color/color.go @@ -15,9 +15,11 @@ import ( var ( // NoColor defines if the output is colorized or not. It's dynamically set to // false or true based on the stdout's file descriptor referring to a terminal - // or not. This is a global option and affects all colors. For more control - // over each color block use the methods DisableColor() individually. - NoColor = os.Getenv("TERM") == "dumb" || + // or not. It's also set to true if the NO_COLOR environment variable is + // set (regardless of its value). This is a global option and affects all + // colors. For more control over each color block use the methods + // DisableColor() individually. + NoColor = noColorExists() || os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd())) // Output defines the standard output of the print functions. By default @@ -33,6 +35,12 @@ var ( colorsCacheMu sync.Mutex // protects colorsCache ) +// noColorExists returns true if the environment variable NO_COLOR exists. +func noColorExists() bool { + _, exists := os.LookupEnv("NO_COLOR") + return exists +} + // Color defines a custom color object which is defined by SGR parameters. type Color struct { params []Attribute @@ -108,7 +116,14 @@ const ( // New returns a newly created color object. func New(value ...Attribute) *Color { - c := &Color{params: make([]Attribute, 0)} + c := &Color{ + params: make([]Attribute, 0), + } + + if noColorExists() { + c.noColor = boolPtr(true) + } + c.Add(value...) return c } @@ -387,7 +402,7 @@ func (c *Color) EnableColor() { } func (c *Color) isNoColorSet() bool { - // check first if we have user setted action + // check first if we have user set action if c.noColor != nil { return *c.noColor } diff --git a/vendor/github.com/fatih/color/doc.go b/vendor/github.com/fatih/color/doc.go index cf1e96500f..04541de786 100644 --- a/vendor/github.com/fatih/color/doc.go +++ b/vendor/github.com/fatih/color/doc.go @@ -118,6 +118,8 @@ the color output with: color.NoColor = true // disables colorized output } +You can also disable the color by setting the NO_COLOR environment variable to any value. + It also has support for single color definitions (local). You can disable/enable color output on the fly: diff --git a/vendor/github.com/ma314smith/signedxml/exclusivecanonicalization.go b/vendor/github.com/ma314smith/signedxml/exclusivecanonicalization.go index a048261c8e..78c1f7dba2 100644 --- a/vendor/github.com/ma314smith/signedxml/exclusivecanonicalization.go +++ b/vendor/github.com/ma314smith/signedxml/exclusivecanonicalization.go @@ -149,6 +149,9 @@ func (e ExclusiveCanonicalization) processRecursive(node *etree.Element, e.renderAttributes(node, prefixesInScope, defaultNS) for _, child := range node.Child { + oldNamespaces := e.namespaces + e.namespaces = copyNamespace(oldNamespaces) + switch child := child.(type) { case *etree.Comment: if !e.WithComments { @@ -157,6 +160,8 @@ func (e ExclusiveCanonicalization) processRecursive(node *etree.Element, case *etree.Element: e.processRecursive(child, newPrefixesInScope, newDefaultNS) } + + e.namespaces = oldNamespaces } } @@ -204,7 +209,10 @@ func (e ExclusiveCanonicalization) renderAttributes(node *etree.Element, attr.Space != "xmlns" && !contains(prefixesInScope, attr.Space) { - nsListToRender["xmlns:"+attr.Space] = e.namespaces[attr.Space] + if attr.Space != "xml"{ + nsListToRender["xmlns:"+attr.Space] = e.namespaces[attr.Space] + } + prefixesInScope = append(prefixesInScope, attr.Space) } @@ -300,3 +308,12 @@ func isWhitespace(s string) bool { } return true } + +func copyNamespace(namespaces map[string]string) map[string]string { + newVersion := map[string]string{} + for index, element := range namespaces { + newVersion[index] = element + } + return newVersion +} + diff --git a/vendor/github.com/mattn/go-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go index 95f2c6be25..2dcb09aab8 100644 --- a/vendor/github.com/mattn/go-colorable/noncolorable.go +++ b/vendor/github.com/mattn/go-colorable/noncolorable.go @@ -27,7 +27,10 @@ loop: } if c1 != 0x1b { bw[0] = c1 - w.out.Write(bw[:]) + _, err = w.out.Write(bw[:]) + if err != nil { + break loop + } continue } c2, err := er.ReadByte() diff --git a/vendor/github.com/tredoe/osutil/AUTHORS.md b/vendor/github.com/tredoe/osutil/AUTHORS.md index 1a575d3f3b..518f194222 100644 --- a/vendor/github.com/tredoe/osutil/AUTHORS.md +++ b/vendor/github.com/tredoe/osutil/AUTHORS.md @@ -13,4 +13,4 @@ Please keep the list sorted. ## Code -* Jonas mg (https://github.com/tredoe) \ No newline at end of file +* Jonas mg (https://github.com/tredoe) diff --git a/vendor/github.com/tredoe/osutil/CONTRIBUTORS.md b/vendor/github.com/tredoe/osutil/CONTRIBUTORS.md index 879ecc2386..b630fff1c1 100644 --- a/vendor/github.com/tredoe/osutil/CONTRIBUTORS.md +++ b/vendor/github.com/tredoe/osutil/CONTRIBUTORS.md @@ -15,4 +15,8 @@ Please keep the list sorted. ## Code -* Jonas mg (https://github.com/tredoe) \ No newline at end of file +* Jonas mg (https://github.com/tredoe) + +* DJ Gregor +* Jeramey Crawford +* Misha Seltzer (https://github.com/mishas) diff --git a/vendor/github.com/tredoe/osutil/user/crypt/common/salt.go b/vendor/github.com/tredoe/osutil/user/crypt/common/salt.go index 22f51cc677..ee38851bcf 100644 --- a/vendor/github.com/tredoe/osutil/user/crypt/common/salt.go +++ b/vendor/github.com/tredoe/osutil/user/crypt/common/salt.go @@ -46,7 +46,7 @@ func (s *Salt) Generate(length int) []byte { saltLen := (length * 6 / 8) if (length*6)%8 != 0 { - saltLen += 1 + saltLen++ } salt := make([]byte, saltLen) rand.Read(salt) @@ -87,14 +87,14 @@ func (s *Salt) GenerateWRounds(length, rounds int) []byte { saltLen := (length * 6 / 8) if (length*6)%8 != 0 { - saltLen += 1 + saltLen++ } salt := make([]byte, saltLen) rand.Read(salt) roundsText := "" if rounds != s.RoundsDefault { - roundsText = "rounds=" + strconv.Itoa(rounds) + roundsText = "rounds=" + strconv.Itoa(rounds) + "$" } out := make([]byte, len(s.MagicPrefix)+len(roundsText)+length) diff --git a/vendor/github.com/vishvananda/netlink/.gitignore b/vendor/github.com/vishvananda/netlink/.gitignore new file mode 100644 index 0000000000..9f11b755a1 --- /dev/null +++ b/vendor/github.com/vishvananda/netlink/.gitignore @@ -0,0 +1 @@ +.idea/ diff --git a/vendor/github.com/vishvananda/netlink/.travis.yml b/vendor/github.com/vishvananda/netlink/.travis.yml index f5c0b3eb5f..7d14af4d6d 100644 --- a/vendor/github.com/vishvananda/netlink/.travis.yml +++ b/vendor/github.com/vishvananda/netlink/.travis.yml @@ -1,4 +1,8 @@ language: go +go: + - "1.10.x" + - "1.11.x" + - "1.12.x" before_script: # make sure we keep path in tact when we sudo - sudo sed -i -e 's/^Defaults\tsecure_path.*$//' /etc/sudoers @@ -9,5 +13,7 @@ before_script: - sudo modprobe nf_conntrack_netlink - sudo modprobe nf_conntrack_ipv4 - sudo modprobe nf_conntrack_ipv6 + - sudo modprobe sch_hfsc install: - go get github.com/vishvananda/netns +go_import_path: github.com/vishvananda/netlink diff --git a/vendor/github.com/vishvananda/netlink/addr_linux.go b/vendor/github.com/vishvananda/netlink/addr_linux.go index d59c3281ec..28746d5afe 100644 --- a/vendor/github.com/vishvananda/netlink/addr_linux.go +++ b/vendor/github.com/vishvananda/netlink/addr_linux.go @@ -15,39 +15,62 @@ import ( const IFA_FLAGS = 0x8 // AddrAdd will add an IP address to a link device. +// // Equivalent to: `ip addr add $addr dev $link` +// +// If `addr` is an IPv4 address and the broadcast address is not given, it +// will be automatically computed based on the IP mask if /30 or larger. func AddrAdd(link Link, addr *Addr) error { return pkgHandle.AddrAdd(link, addr) } // AddrAdd will add an IP address to a link device. +// // Equivalent to: `ip addr add $addr dev $link` +// +// If `addr` is an IPv4 address and the broadcast address is not given, it +// will be automatically computed based on the IP mask if /30 or larger. func (h *Handle) AddrAdd(link Link, addr *Addr) error { req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK) return h.addrHandle(link, addr, req) } // AddrReplace will replace (or, if not present, add) an IP address on a link device. +// // Equivalent to: `ip addr replace $addr dev $link` +// +// If `addr` is an IPv4 address and the broadcast address is not given, it +// will be automatically computed based on the IP mask if /30 or larger. func AddrReplace(link Link, addr *Addr) error { return pkgHandle.AddrReplace(link, addr) } // AddrReplace will replace (or, if not present, add) an IP address on a link device. +// // Equivalent to: `ip addr replace $addr dev $link` +// +// If `addr` is an IPv4 address and the broadcast address is not given, it +// will be automatically computed based on the IP mask if /30 or larger. func (h *Handle) AddrReplace(link Link, addr *Addr) error { req := h.newNetlinkRequest(unix.RTM_NEWADDR, unix.NLM_F_CREATE|unix.NLM_F_REPLACE|unix.NLM_F_ACK) return h.addrHandle(link, addr, req) } // AddrDel will delete an IP address from a link device. +// // Equivalent to: `ip addr del $addr dev $link` +// +// If `addr` is an IPv4 address and the broadcast address is not given, it +// will be automatically computed based on the IP mask if /30 or larger. func AddrDel(link Link, addr *Addr) error { return pkgHandle.AddrDel(link, addr) } // AddrDel will delete an IP address from a link device. // Equivalent to: `ip addr del $addr dev $link` +// +// If `addr` is an IPv4 address and the broadcast address is not given, it +// will be automatically computed based on the IP mask if /30 or larger. func (h *Handle) AddrDel(link Link, addr *Addr) error { req := h.newNetlinkRequest(unix.RTM_DELADDR, unix.NLM_F_ACK) return h.addrHandle(link, addr, req) @@ -65,7 +88,11 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error msg := nl.NewIfAddrmsg(family) msg.Index = uint32(base.Index) msg.Scope = uint8(addr.Scope) - prefixlen, masklen := addr.Mask.Size() + mask := addr.Mask + if addr.Peer != nil { + mask = addr.Peer.Mask + } + prefixlen, masklen := mask.Size() msg.Prefixlen = uint8(prefixlen) req.AddData(msg) @@ -104,14 +131,20 @@ func (h *Handle) addrHandle(link Link, addr *Addr, req *nl.NetlinkRequest) error } if family == FAMILY_V4 { - if addr.Broadcast == nil { + // Automatically set the broadcast address if it is unset and the + // subnet is large enough to sensibly have one (/30 or larger). + // See: RFC 3021 + if addr.Broadcast == nil && prefixlen < 31 { calcBroadcast := make(net.IP, masklen/8) for i := range localAddrData { - calcBroadcast[i] = localAddrData[i] | ^addr.Mask[i] + calcBroadcast[i] = localAddrData[i] | ^mask[i] } addr.Broadcast = calcBroadcast } - req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast)) + + if addr.Broadcast != nil { + req.AddData(nl.NewRtAttr(unix.IFA_BROADCAST, addr.Broadcast)) + } if addr.Label != "" { labelData := nl.NewRtAttr(unix.IFA_LABEL, nl.ZeroTerminated(addr.Label)) @@ -206,13 +239,17 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) { IP: attr.Value, Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), } - addr.Peer = dst case unix.IFA_LOCAL: + // iproute2 manual: + // If a peer address is specified, the local address + // cannot have a prefix length. The network prefix is + // associated with the peer rather than with the local + // address. + n := 8 * len(attr.Value) local = &net.IPNet{ IP: attr.Value, - Mask: net.CIDRMask(int(msg.Prefixlen), 8*len(attr.Value)), + Mask: net.CIDRMask(n, n), } - addr.IPNet = local case unix.IFA_BROADCAST: addr.Broadcast = attr.Value case unix.IFA_LABEL: @@ -226,12 +263,24 @@ func parseAddr(m []byte) (addr Addr, family, index int, err error) { } } - // IFA_LOCAL should be there but if not, fall back to IFA_ADDRESS + // libnl addr.c comment: + // IPv6 sends the local address as IFA_ADDRESS with no + // IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS + // with IFA_ADDRESS being the peer address if they differ + // + // But obviously, as there are IPv6 PtP addresses, too, + // IFA_LOCAL should also be handled for IPv6. if local != nil { - addr.IPNet = local + if family == FAMILY_V4 && local.IP.Equal(dst.IP) { + addr.IPNet = dst + } else { + addr.IPNet = local + addr.Peer = dst + } } else { addr.IPNet = dst } + addr.Scope = int(msg.Scope) return @@ -250,21 +299,22 @@ type AddrUpdate struct { // AddrSubscribe takes a chan down which notifications will be sent // when addresses change. Close the 'done' chan to stop subscription. func AddrSubscribe(ch chan<- AddrUpdate, done <-chan struct{}) error { - return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false) + return addrSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0) } // AddrSubscribeAt works like AddrSubscribe plus it allows the caller // to choose the network namespace in which to subscribe (ns). func AddrSubscribeAt(ns netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}) error { - return addrSubscribeAt(ns, netns.None(), ch, done, nil, false) + return addrSubscribeAt(ns, netns.None(), ch, done, nil, false, 0) } // AddrSubscribeOptions contains a set of options to use with // AddrSubscribeWithOptions. type AddrSubscribeOptions struct { - Namespace *netns.NsHandle - ErrorCallback func(error) - ListExisting bool + Namespace *netns.NsHandle + ErrorCallback func(error) + ListExisting bool + ReceiveBufferSize int } // AddrSubscribeWithOptions work like AddrSubscribe but enable to @@ -275,10 +325,10 @@ func AddrSubscribeWithOptions(ch chan<- AddrUpdate, done <-chan struct{}, option none := netns.None() options.Namespace = &none } - return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting) + return addrSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting, options.ReceiveBufferSize) } -func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error { +func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-chan struct{}, cberr func(error), listExisting bool, rcvbuf int) error { s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_IFADDR, unix.RTNLGRP_IPV6_IFADDR) if err != nil { return err @@ -289,6 +339,12 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c s.Close() }() } + if rcvbuf != 0 { + err = pkgHandle.SetSocketReceiveBufferSize(rcvbuf, false) + if err != nil { + return err + } + } if listExisting { req := pkgHandle.newNetlinkRequest(unix.RTM_GETADDR, unix.NLM_F_DUMP) @@ -301,13 +357,19 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c go func() { defer close(ch) for { - msgs, err := s.Receive() + msgs, from, err := s.Receive() if err != nil { if cberr != nil { cberr(err) } return } + if from.Pid != nl.PidKernel { + if cberr != nil { + cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)) + } + continue + } for _, m := range msgs { if m.Header.Type == unix.NLMSG_DONE { continue @@ -319,16 +381,17 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c continue } if cberr != nil { - cberr(syscall.Errno(-error)) + cberr(fmt.Errorf("error message: %v", + syscall.Errno(-error))) } - return + continue } msgType := m.Header.Type if msgType != unix.RTM_NEWADDR && msgType != unix.RTM_DELADDR { if cberr != nil { cberr(fmt.Errorf("bad message type: %d", msgType)) } - return + continue } addr, _, ifindex, err := parseAddr(m.Data) @@ -336,7 +399,7 @@ func addrSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- AddrUpdate, done <-c if cberr != nil { cberr(fmt.Errorf("could not parse address: %v", err)) } - return + continue } ch <- AddrUpdate{LinkAddress: *addr.IPNet, diff --git a/vendor/github.com/vishvananda/netlink/bridge_linux.go b/vendor/github.com/vishvananda/netlink/bridge_linux.go index 350ab0db4b..6e1224c47b 100644 --- a/vendor/github.com/vishvananda/netlink/bridge_linux.go +++ b/vendor/github.com/vishvananda/netlink/bridge_linux.go @@ -96,7 +96,7 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged flags |= nl.BRIDGE_FLAGS_MASTER } if flags > 0 { - nl.NewRtAttrChild(br, nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags)) + br.AddRtAttr(nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags)) } vlanInfo := &nl.BridgeVlanInfo{Vid: vid} if pvid { @@ -105,11 +105,8 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged if untagged { vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED } - nl.NewRtAttrChild(br, nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize()) + br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize()) req.AddData(br) _, err := req.Execute(unix.NETLINK_ROUTE, 0) - if err != nil { - return err - } - return nil + return err } diff --git a/vendor/github.com/vishvananda/netlink/class.go b/vendor/github.com/vishvananda/netlink/class.go index 8ee13af48e..dcc22d9e97 100644 --- a/vendor/github.com/vishvananda/netlink/class.go +++ b/vendor/github.com/vishvananda/netlink/class.go @@ -4,25 +4,76 @@ import ( "fmt" ) +// Class interfaces for all classes type Class interface { Attrs() *ClassAttrs Type() string } +// Generic networking statistics for netlink users. +// This file contains "gnet_" prefixed structs and relevant functions. +// See Documentation/networking/getn_stats.txt in Linux source code for more details. + +// GnetStatsBasic Ref: struct gnet_stats_basic { ... } +type GnetStatsBasic struct { + Bytes uint64 // number of seen bytes + Packets uint32 // number of seen packets +} + +// GnetStatsRateEst Ref: struct gnet_stats_rate_est { ... } +type GnetStatsRateEst struct { + Bps uint32 // current byte rate + Pps uint32 // current packet rate +} + +// GnetStatsRateEst64 Ref: struct gnet_stats_rate_est64 { ... } +type GnetStatsRateEst64 struct { + Bps uint64 // current byte rate + Pps uint64 // current packet rate +} + +// GnetStatsQueue Ref: struct gnet_stats_queue { ... } +type GnetStatsQueue struct { + Qlen uint32 // queue length + Backlog uint32 // backlog size of queue + Drops uint32 // number of dropped packets + Requeues uint32 // number of requues + Overlimits uint32 // number of enqueues over the limit +} + +// ClassStatistics representation based on generic networking statistics for netlink. +// See Documentation/networking/gen_stats.txt in Linux source code for more details. +type ClassStatistics struct { + Basic *GnetStatsBasic + Queue *GnetStatsQueue + RateEst *GnetStatsRateEst +} + +// NewClassStatistics Construct a ClassStatistics struct which fields are all initialized by 0. +func NewClassStatistics() *ClassStatistics { + return &ClassStatistics{ + Basic: &GnetStatsBasic{}, + Queue: &GnetStatsQueue{}, + RateEst: &GnetStatsRateEst{}, + } +} + // ClassAttrs represents a netlink class. A filter is associated with a link, // has a handle and a parent. The root filter of a device should have a // parent == HANDLE_ROOT. type ClassAttrs struct { - LinkIndex int - Handle uint32 - Parent uint32 - Leaf uint32 + LinkIndex int + Handle uint32 + Parent uint32 + Leaf uint32 + Statistics *ClassStatistics } func (q ClassAttrs) String() string { return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Leaf: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Leaf) } +// HtbClassAttrs stores the attributes of HTB class type HtbClassAttrs struct { // TODO handle all attributes Rate uint64 @@ -54,10 +105,12 @@ func (q HtbClass) String() string { return fmt.Sprintf("{Rate: %d, Ceil: %d, Buffer: %d, Cbuffer: %d}", q.Rate, q.Ceil, q.Buffer, q.Cbuffer) } +// Attrs returns the class attributes func (q *HtbClass) Attrs() *ClassAttrs { return &q.ClassAttrs } +// Type return the class type func (q *HtbClass) Type() string { return "htb" } @@ -69,10 +122,90 @@ type GenericClass struct { ClassType string } +// Attrs return the class attributes func (class *GenericClass) Attrs() *ClassAttrs { return &class.ClassAttrs } +// Type return the class type func (class *GenericClass) Type() string { return class.ClassType } + +// ServiceCurve is the way the HFSC curve are represented +type ServiceCurve struct { + m1 uint32 + d uint32 + m2 uint32 +} + +// Attrs return the parameters of the service curve +func (c *ServiceCurve) Attrs() (uint32, uint32, uint32) { + return c.m1, c.d, c.m2 +} + +// HfscClass is a representation of the HFSC class +type HfscClass struct { + ClassAttrs + Rsc ServiceCurve + Fsc ServiceCurve + Usc ServiceCurve +} + +// SetUsc sets the Usc curve +func (hfsc *HfscClass) SetUsc(m1 uint32, d uint32, m2 uint32) { + hfsc.Usc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8} +} + +// SetFsc sets the Fsc curve +func (hfsc *HfscClass) SetFsc(m1 uint32, d uint32, m2 uint32) { + hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8} +} + +// SetRsc sets the Rsc curve +func (hfsc *HfscClass) SetRsc(m1 uint32, d uint32, m2 uint32) { + hfsc.Rsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8} +} + +// SetSC implements the SC from the tc CLI +func (hfsc *HfscClass) SetSC(m1 uint32, d uint32, m2 uint32) { + hfsc.Rsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8} + hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8} +} + +// SetUL implements the UL from the tc CLI +func (hfsc *HfscClass) SetUL(m1 uint32, d uint32, m2 uint32) { + hfsc.Usc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8} +} + +// SetLS implements the LS from the tc CLI +func (hfsc *HfscClass) SetLS(m1 uint32, d uint32, m2 uint32) { + hfsc.Fsc = ServiceCurve{m1: m1 / 8, d: d, m2: m2 / 8} +} + +// NewHfscClass returns a new HFSC struct with the set parameters +func NewHfscClass(attrs ClassAttrs) *HfscClass { + return &HfscClass{ + ClassAttrs: attrs, + Rsc: ServiceCurve{}, + Fsc: ServiceCurve{}, + Usc: ServiceCurve{}, + } +} + +func (hfsc *HfscClass) String() string { + return fmt.Sprintf( + "{%s -- {RSC: {m1=%d d=%d m2=%d}} {FSC: {m1=%d d=%d m2=%d}} {USC: {m1=%d d=%d m2=%d}}}", + hfsc.Attrs(), hfsc.Rsc.m1*8, hfsc.Rsc.d, hfsc.Rsc.m2*8, hfsc.Fsc.m1*8, hfsc.Fsc.d, hfsc.Fsc.m2*8, hfsc.Usc.m1*8, hfsc.Usc.d, hfsc.Usc.m2*8, + ) +} + +// Attrs return the Hfsc parameters +func (hfsc *HfscClass) Attrs() *ClassAttrs { + return &hfsc.ClassAttrs +} + +// Type return the type of the class +func (hfsc *HfscClass) Type() string { + return "hfsc" +} diff --git a/vendor/github.com/vishvananda/netlink/class_linux.go b/vendor/github.com/vishvananda/netlink/class_linux.go index a4997740e2..31091e5010 100644 --- a/vendor/github.com/vishvananda/netlink/class_linux.go +++ b/vendor/github.com/vishvananda/netlink/class_linux.go @@ -1,14 +1,34 @@ package netlink import ( + "bytes" + "encoding/binary" + "encoding/hex" "errors" + "fmt" "syscall" "github.com/vishvananda/netlink/nl" "golang.org/x/sys/unix" ) -// NOTE: function is in here because it uses other linux functions +// Internal tc_stats representation in Go struct. +// This is for internal uses only to deserialize the payload of rtattr. +// After the deserialization, this should be converted into the canonical stats +// struct, ClassStatistics, in case of statistics of a class. +// Ref: struct tc_stats { ... } +type tcStats struct { + Bytes uint64 // Number of enqueued bytes + Packets uint32 // Number of enqueued packets + Drops uint32 // Packets dropped because of lack of resources + Overlimits uint32 // Number of throttle events when this flow goes out of allocated bandwidth + Bps uint32 // Current flow byte rate + Pps uint32 // Current flow packet rate + Qlen uint32 + Backlog uint32 +} + +// NewHtbClass NOTE: function is in here because it uses other linux functions func NewHtbClass(attrs ClassAttrs, cattrs HtbClassAttrs) *HtbClass { mtu := 1600 rate := cattrs.Rate / 8 @@ -126,7 +146,9 @@ func classPayload(req *nl.NetlinkRequest, class Class) error { req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(class.Type()))) options := nl.NewRtAttr(nl.TCA_OPTIONS, nil) - if htb, ok := class.(*HtbClass); ok { + switch class.Type() { + case "htb": + htb := class.(*HtbClass) opt := nl.TcHtbCopt{} opt.Buffer = htb.Buffer opt.Cbuffer = htb.Cbuffer @@ -151,9 +173,18 @@ func classPayload(req *nl.NetlinkRequest, class Class) error { return errors.New("HTB: failed to calculate ceil rate table") } opt.Ceil = tcceil - nl.NewRtAttrChild(options, nl.TCA_HTB_PARMS, opt.Serialize()) - nl.NewRtAttrChild(options, nl.TCA_HTB_RTAB, SerializeRtab(rtab)) - nl.NewRtAttrChild(options, nl.TCA_HTB_CTAB, SerializeRtab(ctab)) + options.AddRtAttr(nl.TCA_HTB_PARMS, opt.Serialize()) + options.AddRtAttr(nl.TCA_HTB_RTAB, SerializeRtab(rtab)) + options.AddRtAttr(nl.TCA_HTB_CTAB, SerializeRtab(ctab)) + case "hfsc": + hfsc := class.(*HfscClass) + opt := nl.HfscCopt{} + opt.Rsc.Set(hfsc.Rsc.Attrs()) + opt.Fsc.Set(hfsc.Fsc.Attrs()) + opt.Usc.Set(hfsc.Usc.Attrs()) + options.AddRtAttr(nl.TCA_HFSC_RSC, nl.SerializeHfscCurve(&opt.Rsc)) + options.AddRtAttr(nl.TCA_HFSC_FSC, nl.SerializeHfscCurve(&opt.Fsc)) + options.AddRtAttr(nl.TCA_HFSC_USC, nl.SerializeHfscCurve(&opt.Usc)) } req.AddData(options) return nil @@ -197,9 +228,10 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) { } base := ClassAttrs{ - LinkIndex: int(msg.Ifindex), - Handle: msg.Handle, - Parent: msg.Parent, + LinkIndex: int(msg.Ifindex), + Handle: msg.Handle, + Parent: msg.Parent, + Statistics: nil, } var class Class @@ -211,6 +243,8 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) { switch classType { case "htb": class = &HtbClass{} + case "hfsc": + class = &HfscClass{} default: class = &GenericClass{ClassType: classType} } @@ -225,6 +259,26 @@ func (h *Handle) ClassList(link Link, parent uint32) ([]Class, error) { if err != nil { return nil, err } + case "hfsc": + data, err := nl.ParseRouteAttr(attr.Value) + if err != nil { + return nil, err + } + _, err = parseHfscClassData(class, data) + if err != nil { + return nil, err + } + } + // For backward compatibility. + case nl.TCA_STATS: + base.Statistics, err = parseTcStats(attr.Value) + if err != nil { + return nil, err + } + case nl.TCA_STATS2: + base.Statistics, err = parseTcStats2(attr.Value) + if err != nil { + return nil, err } } } @@ -253,3 +307,78 @@ func parseHtbClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, erro } return detailed, nil } + +func parseHfscClassData(class Class, data []syscall.NetlinkRouteAttr) (bool, error) { + hfsc := class.(*HfscClass) + detailed := false + for _, datum := range data { + m1, d, m2 := nl.DeserializeHfscCurve(datum.Value).Attrs() + switch datum.Attr.Type { + case nl.TCA_HFSC_RSC: + hfsc.Rsc = ServiceCurve{m1: m1, d: d, m2: m2} + case nl.TCA_HFSC_FSC: + hfsc.Fsc = ServiceCurve{m1: m1, d: d, m2: m2} + case nl.TCA_HFSC_USC: + hfsc.Usc = ServiceCurve{m1: m1, d: d, m2: m2} + } + } + return detailed, nil +} + +func parseTcStats(data []byte) (*ClassStatistics, error) { + buf := &bytes.Buffer{} + buf.Write(data) + native := nl.NativeEndian() + tcStats := &tcStats{} + if err := binary.Read(buf, native, tcStats); err != nil { + return nil, err + } + + stats := NewClassStatistics() + stats.Basic.Bytes = tcStats.Bytes + stats.Basic.Packets = tcStats.Packets + stats.Queue.Qlen = tcStats.Qlen + stats.Queue.Backlog = tcStats.Backlog + stats.Queue.Drops = tcStats.Drops + stats.Queue.Overlimits = tcStats.Overlimits + stats.RateEst.Bps = tcStats.Bps + stats.RateEst.Pps = tcStats.Pps + + return stats, nil +} + +func parseGnetStats(data []byte, gnetStats interface{}) error { + buf := &bytes.Buffer{} + buf.Write(data) + native := nl.NativeEndian() + return binary.Read(buf, native, gnetStats) +} + +func parseTcStats2(data []byte) (*ClassStatistics, error) { + rtAttrs, err := nl.ParseRouteAttr(data) + if err != nil { + return nil, err + } + stats := NewClassStatistics() + for _, datum := range rtAttrs { + switch datum.Attr.Type { + case nl.TCA_STATS_BASIC: + if err := parseGnetStats(datum.Value, stats.Basic); err != nil { + return nil, fmt.Errorf("Failed to parse ClassStatistics.Basic with: %v\n%s", + err, hex.Dump(datum.Value)) + } + case nl.TCA_STATS_QUEUE: + if err := parseGnetStats(datum.Value, stats.Queue); err != nil { + return nil, fmt.Errorf("Failed to parse ClassStatistics.Queue with: %v\n%s", + err, hex.Dump(datum.Value)) + } + case nl.TCA_STATS_RATE_EST: + if err := parseGnetStats(datum.Value, stats.RateEst); err != nil { + return nil, fmt.Errorf("Failed to parse ClassStatistics.RateEst with: %v\n%s", + err, hex.Dump(datum.Value)) + } + } + } + + return stats, nil +} diff --git a/vendor/github.com/vishvananda/netlink/conntrack_linux.go b/vendor/github.com/vishvananda/netlink/conntrack_linux.go index a0fc74a372..4bff0dcbab 100644 --- a/vendor/github.com/vishvananda/netlink/conntrack_linux.go +++ b/vendor/github.com/vishvananda/netlink/conntrack_linux.go @@ -22,11 +22,7 @@ const ( // https://github.com/torvalds/linux/blob/master/include/uapi/linux/netfilter/nfnetlink.h -> #define NFNL_SUBSYS_CTNETLINK_EXP 2 ConntrackExpectTable = 2 ) -const ( - // For Parsing Mark - TCP_PROTO = 6 - UDP_PROTO = 17 -) + const ( // backward compatibility with golang 1.6 which does not have io.SeekCurrent seekCurrent = 1 @@ -135,11 +131,13 @@ func (h *Handle) dumpConntrackTable(table ConntrackTableType, family InetFamily) // http://git.netfilter.org/libnetfilter_conntrack/tree/include/internal/object.h // For the time being, the structure below allows to parse and extract the base information of a flow type ipTuple struct { - SrcIP net.IP + Bytes uint64 DstIP net.IP - Protocol uint8 - SrcPort uint16 DstPort uint16 + Packets uint64 + Protocol uint8 + SrcIP net.IP + SrcPort uint16 } type ConntrackFlow struct { @@ -151,11 +149,12 @@ type ConntrackFlow struct { func (s *ConntrackFlow) String() string { // conntrack cmd output: - // udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 mark=0 - return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d\tsrc=%s dst=%s sport=%d dport=%d mark=%d", + // udp 17 src=127.0.0.1 dst=127.0.0.1 sport=4001 dport=1234 packets=5 bytes=532 [UNREPLIED] src=127.0.0.1 dst=127.0.0.1 sport=1234 dport=4001 packets=10 bytes=1078 mark=0 + return fmt.Sprintf("%s\t%d src=%s dst=%s sport=%d dport=%d packets=%d bytes=%d\tsrc=%s dst=%s sport=%d dport=%d packets=%d bytes=%d mark=%d", nl.L4ProtoMap[s.Forward.Protocol], s.Forward.Protocol, - s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort, - s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Mark) + s.Forward.SrcIP.String(), s.Forward.DstIP.String(), s.Forward.SrcPort, s.Forward.DstPort, s.Forward.Packets, s.Forward.Bytes, + s.Reverse.SrcIP.String(), s.Reverse.DstIP.String(), s.Reverse.SrcPort, s.Reverse.DstPort, s.Reverse.Packets, s.Reverse.Bytes, + s.Mark) } // This method parse the ip tuple structure @@ -220,9 +219,35 @@ func parseBERaw16(r *bytes.Reader, v *uint16) { binary.Read(r, binary.BigEndian, v) } +func parseBERaw32(r *bytes.Reader, v *uint32) { + binary.Read(r, binary.BigEndian, v) +} + +func parseBERaw64(r *bytes.Reader, v *uint64) { + binary.Read(r, binary.BigEndian, v) +} + +func parseByteAndPacketCounters(r *bytes.Reader) (bytes, packets uint64) { + for i := 0; i < 2; i++ { + switch _, t, _ := parseNfAttrTL(r); t { + case nl.CTA_COUNTERS_BYTES: + parseBERaw64(r, &bytes) + case nl.CTA_COUNTERS_PACKETS: + parseBERaw64(r, &packets) + default: + return + } + } + return +} + +func parseConnectionMark(r *bytes.Reader) (mark uint32) { + parseBERaw32(r, &mark) + return +} + func parseRawData(data []byte) *ConntrackFlow { s := &ConntrackFlow{} - var proto uint8 // First there is the Nfgenmsg header // consume only the family field reader := bytes.NewReader(data) @@ -238,36 +263,31 @@ func parseRawData(data []byte) *ConntrackFlow { // 4 bytes // flow information of the reverse flow for reader.Len() > 0 { - nested, t, l := parseNfAttrTL(reader) - if nested && t == nl.CTA_TUPLE_ORIG { - if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP { - proto = parseIpTuple(reader, &s.Forward) + if nested, t, l := parseNfAttrTL(reader); nested { + switch t { + case nl.CTA_TUPLE_ORIG: + if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP { + parseIpTuple(reader, &s.Forward) + } + case nl.CTA_TUPLE_REPLY: + if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP { + parseIpTuple(reader, &s.Reverse) + } else { + // Header not recognized skip it + reader.Seek(int64(l), seekCurrent) + } + case nl.CTA_COUNTERS_ORIG: + s.Forward.Bytes, s.Forward.Packets = parseByteAndPacketCounters(reader) + case nl.CTA_COUNTERS_REPLY: + s.Reverse.Bytes, s.Reverse.Packets = parseByteAndPacketCounters(reader) } - } else if nested && t == nl.CTA_TUPLE_REPLY { - if nested, t, _ = parseNfAttrTL(reader); nested && t == nl.CTA_TUPLE_IP { - parseIpTuple(reader, &s.Reverse) - - // Got all the useful information stop parsing - break - } else { - // Header not recognized skip it - reader.Seek(int64(l), seekCurrent) + } else { + switch t { + case nl.CTA_MARK: + s.Mark = parseConnectionMark(reader) } } } - if proto == TCP_PROTO { - reader.Seek(64, seekCurrent) - _, t, _, v := parseNfAttrTLV(reader) - if t == nl.CTA_MARK { - s.Mark = uint32(v[3]) - } - } else if proto == UDP_PROTO { - reader.Seek(16, seekCurrent) - _, t, _, v := parseNfAttrTLV(reader) - if t == nl.CTA_MARK { - s.Mark = uint32(v[3]) - } - } return s } @@ -285,7 +305,7 @@ func parseRawData(data []byte) *ConntrackFlow { // Common parameters and options: // -s, --src, --orig-src ip Source address from original direction // -d, --dst, --orig-dst ip Destination address from original direction -// -r, --reply-src ip Source addres from reply direction +// -r, --reply-src ip Source address from reply direction // -q, --reply-dst ip Destination address from reply direction // -p, --protonum proto Layer 4 Protocol, eg. 'tcp' // -f, --family proto Layer 3 Protocol, eg. 'ipv6' @@ -302,11 +322,14 @@ func parseRawData(data []byte) *ConntrackFlow { type ConntrackFilterType uint8 const ( - ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction - ConntrackOrigDstIP // -orig-dst ip Destination address from original direction - ConntrackNatSrcIP // -src-nat ip Source NAT ip - ConntrackNatDstIP // -dst-nat ip Destination NAT ip - ConntrackNatAnyIP // -any-nat ip Source or destination NAT ip + ConntrackOrigSrcIP = iota // -orig-src ip Source address from original direction + ConntrackOrigDstIP // -orig-dst ip Destination address from original direction + ConntrackReplySrcIP // --reply-src ip Reply Source IP + ConntrackReplyDstIP // --reply-dst ip Reply Destination IP + ConntrackReplyAnyIP // Match source or destination reply IP + ConntrackNatSrcIP = ConntrackReplySrcIP // deprecated use instead ConntrackReplySrcIP + ConntrackNatDstIP = ConntrackReplyDstIP // deprecated use instead ConntrackReplyDstIP + ConntrackNatAnyIP = ConntrackReplyAnyIP // deprecated use instaed ConntrackReplyAnyIP ) type CustomConntrackFilter interface { @@ -351,17 +374,17 @@ func (f *ConntrackFilter) MatchConntrackFlow(flow *ConntrackFlow) bool { } // -src-nat ip Source NAT ip - if elem, found := f.ipFilter[ConntrackNatSrcIP]; match && found { + if elem, found := f.ipFilter[ConntrackReplySrcIP]; match && found { match = match && elem.Equal(flow.Reverse.SrcIP) } // -dst-nat ip Destination NAT ip - if elem, found := f.ipFilter[ConntrackNatDstIP]; match && found { + if elem, found := f.ipFilter[ConntrackReplyDstIP]; match && found { match = match && elem.Equal(flow.Reverse.DstIP) } - // -any-nat ip Source or destination NAT ip - if elem, found := f.ipFilter[ConntrackNatAnyIP]; match && found { + // Match source or destination reply IP + if elem, found := f.ipFilter[ConntrackReplyAnyIP]; match && found { match = match && (elem.Equal(flow.Reverse.SrcIP) || elem.Equal(flow.Reverse.DstIP)) } diff --git a/vendor/github.com/vishvananda/netlink/devlink_linux.go b/vendor/github.com/vishvananda/netlink/devlink_linux.go new file mode 100644 index 0000000000..29b3f8ec1d --- /dev/null +++ b/vendor/github.com/vishvananda/netlink/devlink_linux.go @@ -0,0 +1,272 @@ +package netlink + +import ( + "syscall" + + "fmt" + "github.com/vishvananda/netlink/nl" + "golang.org/x/sys/unix" +) + +// DevlinkDevEswitchAttr represents device's eswitch attributes +type DevlinkDevEswitchAttr struct { + Mode string + InlineMode string + EncapMode string +} + +// DevlinkDevAttrs represents device attributes +type DevlinkDevAttrs struct { + Eswitch DevlinkDevEswitchAttr +} + +// DevlinkDevice represents device and its attributes +type DevlinkDevice struct { + BusName string + DeviceName string + Attrs DevlinkDevAttrs +} + +func parseDevLinkDeviceList(msgs [][]byte) ([]*DevlinkDevice, error) { + devices := make([]*DevlinkDevice, 0, len(msgs)) + for _, m := range msgs { + attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:]) + if err != nil { + return nil, err + } + dev := &DevlinkDevice{} + if err = dev.parseAttributes(attrs); err != nil { + return nil, err + } + devices = append(devices, dev) + } + return devices, nil +} + +func eswitchStringToMode(modeName string) (uint16, error) { + if modeName == "legacy" { + return nl.DEVLINK_ESWITCH_MODE_LEGACY, nil + } else if modeName == "switchdev" { + return nl.DEVLINK_ESWITCH_MODE_SWITCHDEV, nil + } else { + return 0xffff, fmt.Errorf("invalid switchdev mode") + } +} + +func parseEswitchMode(mode uint16) string { + var eswitchMode = map[uint16]string{ + nl.DEVLINK_ESWITCH_MODE_LEGACY: "legacy", + nl.DEVLINK_ESWITCH_MODE_SWITCHDEV: "switchdev", + } + if eswitchMode[mode] == "" { + return "unknown" + } else { + return eswitchMode[mode] + } +} + +func parseEswitchInlineMode(inlinemode uint8) string { + var eswitchInlineMode = map[uint8]string{ + nl.DEVLINK_ESWITCH_INLINE_MODE_NONE: "none", + nl.DEVLINK_ESWITCH_INLINE_MODE_LINK: "link", + nl.DEVLINK_ESWITCH_INLINE_MODE_NETWORK: "network", + nl.DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT: "transport", + } + if eswitchInlineMode[inlinemode] == "" { + return "unknown" + } else { + return eswitchInlineMode[inlinemode] + } +} + +func parseEswitchEncapMode(encapmode uint8) string { + var eswitchEncapMode = map[uint8]string{ + nl.DEVLINK_ESWITCH_ENCAP_MODE_NONE: "disable", + nl.DEVLINK_ESWITCH_ENCAP_MODE_BASIC: "enable", + } + if eswitchEncapMode[encapmode] == "" { + return "unknown" + } else { + return eswitchEncapMode[encapmode] + } +} + +func (d *DevlinkDevice) parseAttributes(attrs []syscall.NetlinkRouteAttr) error { + for _, a := range attrs { + switch a.Attr.Type { + case nl.DEVLINK_ATTR_BUS_NAME: + d.BusName = string(a.Value) + case nl.DEVLINK_ATTR_DEV_NAME: + d.DeviceName = string(a.Value) + case nl.DEVLINK_ATTR_ESWITCH_MODE: + d.Attrs.Eswitch.Mode = parseEswitchMode(native.Uint16(a.Value)) + case nl.DEVLINK_ATTR_ESWITCH_INLINE_MODE: + d.Attrs.Eswitch.InlineMode = parseEswitchInlineMode(uint8(a.Value[0])) + case nl.DEVLINK_ATTR_ESWITCH_ENCAP_MODE: + d.Attrs.Eswitch.EncapMode = parseEswitchEncapMode(uint8(a.Value[0])) + } + } + return nil +} + +func (dev *DevlinkDevice) parseEswitchAttrs(msgs [][]byte) { + m := msgs[0] + attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:]) + if err != nil { + return + } + dev.parseAttributes(attrs) +} + +func (h *Handle) getEswitchAttrs(family *GenlFamily, dev *DevlinkDevice) { + msg := &nl.Genlmsg{ + Command: nl.DEVLINK_CMD_ESWITCH_GET, + Version: nl.GENL_DEVLINK_VERSION, + } + req := h.newNetlinkRequest(int(family.ID), unix.NLM_F_REQUEST|unix.NLM_F_ACK) + req.AddData(msg) + + b := make([]byte, len(dev.BusName)) + copy(b, dev.BusName) + data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b) + req.AddData(data) + + b = make([]byte, len(dev.DeviceName)) + copy(b, dev.DeviceName) + data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b) + req.AddData(data) + + msgs, err := req.Execute(unix.NETLINK_GENERIC, 0) + if err != nil { + return + } + dev.parseEswitchAttrs(msgs) +} + +// DevLinkGetDeviceList provides a pointer to devlink devices and nil error, +// otherwise returns an error code. +func (h *Handle) DevLinkGetDeviceList() ([]*DevlinkDevice, error) { + f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME) + if err != nil { + return nil, err + } + msg := &nl.Genlmsg{ + Command: nl.DEVLINK_CMD_GET, + Version: nl.GENL_DEVLINK_VERSION, + } + req := h.newNetlinkRequest(int(f.ID), + unix.NLM_F_REQUEST|unix.NLM_F_ACK|unix.NLM_F_DUMP) + req.AddData(msg) + msgs, err := req.Execute(unix.NETLINK_GENERIC, 0) + if err != nil { + return nil, err + } + devices, err := parseDevLinkDeviceList(msgs) + if err != nil { + return nil, err + } + for _, d := range devices { + h.getEswitchAttrs(f, d) + } + return devices, nil +} + +// DevLinkGetDeviceList provides a pointer to devlink devices and nil error, +// otherwise returns an error code. +func DevLinkGetDeviceList() ([]*DevlinkDevice, error) { + return pkgHandle.DevLinkGetDeviceList() +} + +func parseDevlinkDevice(msgs [][]byte) (*DevlinkDevice, error) { + m := msgs[0] + attrs, err := nl.ParseRouteAttr(m[nl.SizeofGenlmsg:]) + if err != nil { + return nil, err + } + dev := &DevlinkDevice{} + if err = dev.parseAttributes(attrs); err != nil { + return nil, err + } + return dev, nil +} + +func (h *Handle) createCmdReq(cmd uint8, bus string, device string) (*GenlFamily, *nl.NetlinkRequest, error) { + f, err := h.GenlFamilyGet(nl.GENL_DEVLINK_NAME) + if err != nil { + return nil, nil, err + } + + msg := &nl.Genlmsg{ + Command: cmd, + Version: nl.GENL_DEVLINK_VERSION, + } + req := h.newNetlinkRequest(int(f.ID), + unix.NLM_F_REQUEST|unix.NLM_F_ACK) + req.AddData(msg) + + b := make([]byte, len(bus)+1) + copy(b, bus) + data := nl.NewRtAttr(nl.DEVLINK_ATTR_BUS_NAME, b) + req.AddData(data) + + b = make([]byte, len(device)+1) + copy(b, device) + data = nl.NewRtAttr(nl.DEVLINK_ATTR_DEV_NAME, b) + req.AddData(data) + + return f, req, nil +} + +// DevlinkGetDeviceByName provides a pointer to devlink device and nil error, +// otherwise returns an error code. +func (h *Handle) DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) { + f, req, err := h.createCmdReq(nl.DEVLINK_CMD_GET, Bus, Device) + if err != nil { + return nil, err + } + + respmsg, err := req.Execute(unix.NETLINK_GENERIC, 0) + if err != nil { + return nil, err + } + dev, err := parseDevlinkDevice(respmsg) + if err == nil { + h.getEswitchAttrs(f, dev) + } + return dev, err +} + +// DevlinkGetDeviceByName provides a pointer to devlink device and nil error, +// otherwise returns an error code. +func DevLinkGetDeviceByName(Bus string, Device string) (*DevlinkDevice, error) { + return pkgHandle.DevLinkGetDeviceByName(Bus, Device) +} + +// DevLinkSetEswitchMode sets eswitch mode if able to set successfully or +// returns an error code. +// Equivalent to: `devlink dev eswitch set $dev mode switchdev` +// Equivalent to: `devlink dev eswitch set $dev mode legacy` +func (h *Handle) DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error { + mode, err := eswitchStringToMode(NewMode) + if err != nil { + return err + } + + _, req, err := h.createCmdReq(nl.DEVLINK_CMD_ESWITCH_SET, Dev.BusName, Dev.DeviceName) + if err != nil { + return err + } + + req.AddData(nl.NewRtAttr(nl.DEVLINK_ATTR_ESWITCH_MODE, nl.Uint16Attr(mode))) + + _, err = req.Execute(unix.NETLINK_GENERIC, 0) + return err +} + +// DevLinkSetEswitchMode sets eswitch mode if able to set successfully or +// returns an error code. +// Equivalent to: `devlink dev eswitch set $dev mode switchdev` +// Equivalent to: `devlink dev eswitch set $dev mode legacy` +func DevLinkSetEswitchMode(Dev *DevlinkDevice, NewMode string) error { + return pkgHandle.DevLinkSetEswitchMode(Dev, NewMode) +} diff --git a/vendor/github.com/vishvananda/netlink/filter.go b/vendor/github.com/vishvananda/netlink/filter.go index c2cf8e4dcf..88792eab0e 100644 --- a/vendor/github.com/vishvananda/netlink/filter.go +++ b/vendor/github.com/vishvananda/netlink/filter.go @@ -2,6 +2,7 @@ package netlink import ( "fmt" + "net" ) type Filter interface { @@ -135,6 +136,27 @@ func (action *BpfAction) Attrs() *ActionAttrs { return &action.ActionAttrs } +type ConnmarkAction struct { + ActionAttrs + Zone uint16 +} + +func (action *ConnmarkAction) Type() string { + return "connmark" +} + +func (action *ConnmarkAction) Attrs() *ActionAttrs { + return &action.ActionAttrs +} + +func NewConnmarkAction() *ConnmarkAction { + return &ConnmarkAction{ + ActionAttrs: ActionAttrs{ + Action: TC_ACT_PIPE, + }, + } +} + type MirredAct uint8 func (a MirredAct) String() string { @@ -182,47 +204,59 @@ func NewMirredAction(redirIndex int) *MirredAction { } } -// Sel of the U32 filters that contains multiple TcU32Key. This is the copy -// and the frontend representation of nl.TcU32Sel. It is serialized into canonical -// nl.TcU32Sel with the appropriate endianness. -type TcU32Sel struct { - Flags uint8 - Offshift uint8 - Nkeys uint8 - Pad uint8 - Offmask uint16 - Off uint16 - Offoff int16 - Hoff int16 - Hmask uint32 - Keys []TcU32Key +type TunnelKeyAct int8 + +const ( + TCA_TUNNEL_KEY_SET TunnelKeyAct = 1 // set tunnel key + TCA_TUNNEL_KEY_UNSET TunnelKeyAct = 2 // unset tunnel key +) + +type TunnelKeyAction struct { + ActionAttrs + Action TunnelKeyAct + SrcAddr net.IP + DstAddr net.IP + KeyID uint32 } -// TcU32Key contained of Sel in the U32 filters. This is the copy and the frontend -// representation of nl.TcU32Key. It is serialized into chanonical nl.TcU32Sel -// with the appropriate endianness. -type TcU32Key struct { - Mask uint32 - Val uint32 - Off int32 - OffMask int32 +func (action *TunnelKeyAction) Type() string { + return "tunnel_key" } -// U32 filters on many packet related properties -type U32 struct { - FilterAttrs - ClassId uint32 - RedirIndex int - Sel *TcU32Sel - Actions []Action +func (action *TunnelKeyAction) Attrs() *ActionAttrs { + return &action.ActionAttrs } -func (filter *U32) Attrs() *FilterAttrs { - return &filter.FilterAttrs +func NewTunnelKeyAction() *TunnelKeyAction { + return &TunnelKeyAction{ + ActionAttrs: ActionAttrs{ + Action: TC_ACT_PIPE, + }, + } } -func (filter *U32) Type() string { - return "u32" +type SkbEditAction struct { + ActionAttrs + QueueMapping *uint16 + PType *uint16 + Priority *uint32 + Mark *uint32 +} + +func (action *SkbEditAction) Type() string { + return "skbedit" +} + +func (action *SkbEditAction) Attrs() *ActionAttrs { + return &action.ActionAttrs +} + +func NewSkbEditAction() *SkbEditAction { + return &SkbEditAction{ + ActionAttrs: ActionAttrs{ + Action: TC_ACT_PIPE, + }, + } } // MatchAll filters match all packets @@ -262,6 +296,8 @@ type BpfFilter struct { Fd int Name string DirectAction bool + Id int + Tag string } func (filter *BpfFilter) Type() string { diff --git a/vendor/github.com/vishvananda/netlink/filter_linux.go b/vendor/github.com/vishvananda/netlink/filter_linux.go index f0eac6b78c..c56f314cd3 100644 --- a/vendor/github.com/vishvananda/netlink/filter_linux.go +++ b/vendor/github.com/vishvananda/netlink/filter_linux.go @@ -3,10 +3,11 @@ package netlink import ( "bytes" "encoding/binary" + "encoding/hex" "errors" "fmt" + "net" "syscall" - "unsafe" "github.com/vishvananda/netlink/nl" "golang.org/x/sys/unix" @@ -20,6 +21,35 @@ const ( TC_U32_EAT = nl.TC_U32_EAT ) +// Sel of the U32 filters that contains multiple TcU32Key. This is the type +// alias and the frontend representation of nl.TcU32Sel. It is serialized into +// canonical nl.TcU32Sel with the appropriate endianness. +type TcU32Sel = nl.TcU32Sel + +// TcU32Key contained of Sel in the U32 filters. This is the type alias and the +// frontend representation of nl.TcU32Key. It is serialized into chanonical +// nl.TcU32Sel with the appropriate endianness. +type TcU32Key = nl.TcU32Key + +// U32 filters on many packet related properties +type U32 struct { + FilterAttrs + ClassId uint32 + Divisor uint32 // Divisor MUST be power of 2. + Hash uint32 + RedirIndex int + Sel *TcU32Sel + Actions []Action +} + +func (filter *U32) Attrs() *FilterAttrs { + return &filter.FilterAttrs +} + +func (filter *U32) Type() string { + return "u32" +} + // Fw filter filters on firewall marks // NOTE: this is in filter_linux because it refers to nl.TcPolice which // is defined in nl/tc_linux.go @@ -123,8 +153,24 @@ func FilterAdd(filter Filter) error { // FilterAdd will add a filter to the system. // Equivalent to: `tc filter add $filter` func (h *Handle) FilterAdd(filter Filter) error { + return h.filterModify(filter, unix.NLM_F_CREATE|unix.NLM_F_EXCL) +} + +// FilterReplace will replace a filter. +// Equivalent to: `tc filter replace $filter` +func FilterReplace(filter Filter) error { + return pkgHandle.FilterReplace(filter) +} + +// FilterReplace will replace a filter. +// Equivalent to: `tc filter replace $filter` +func (h *Handle) FilterReplace(filter Filter) error { + return h.filterModify(filter, unix.NLM_F_CREATE) +} + +func (h *Handle) filterModify(filter Filter, flags int) error { native = nl.NativeEndian() - req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK) + req := h.newNetlinkRequest(unix.RTM_NEWTFILTER, flags|unix.NLM_F_ACK) base := filter.Attrs() msg := &nl.TcMsg{ Family: nl.FAMILY_ALL, @@ -140,8 +186,7 @@ func (h *Handle) FilterAdd(filter Filter) error { switch filter := filter.(type) { case *U32: - // Convert TcU32Sel into nl.TcU32Sel as it is without copy. - sel := (*nl.TcU32Sel)(unsafe.Pointer(filter.Sel)) + sel := filter.Sel if sel == nil { // match all sel = &nl.TcU32Sel{ @@ -168,11 +213,20 @@ func (h *Handle) FilterAdd(filter Filter) error { } } sel.Nkeys = uint8(len(sel.Keys)) - nl.NewRtAttrChild(options, nl.TCA_U32_SEL, sel.Serialize()) + options.AddRtAttr(nl.TCA_U32_SEL, sel.Serialize()) if filter.ClassId != 0 { - nl.NewRtAttrChild(options, nl.TCA_U32_CLASSID, nl.Uint32Attr(filter.ClassId)) + options.AddRtAttr(nl.TCA_U32_CLASSID, nl.Uint32Attr(filter.ClassId)) } - actionsAttr := nl.NewRtAttrChild(options, nl.TCA_U32_ACT, nil) + if filter.Divisor != 0 { + if (filter.Divisor-1)&filter.Divisor != 0 { + return fmt.Errorf("illegal divisor %d. Must be a power of 2", filter.Divisor) + } + options.AddRtAttr(nl.TCA_U32_DIVISOR, nl.Uint32Attr(filter.Divisor)) + } + if filter.Hash != 0 { + options.AddRtAttr(nl.TCA_U32_HASH, nl.Uint32Attr(filter.Hash)) + } + actionsAttr := options.AddRtAttr(nl.TCA_U32_ACT, nil) // backwards compatibility if filter.RedirIndex != 0 { filter.Actions = append([]Action{NewMirredAction(filter.RedirIndex)}, filter.Actions...) @@ -184,51 +238,51 @@ func (h *Handle) FilterAdd(filter Filter) error { if filter.Mask != 0 { b := make([]byte, 4) native.PutUint32(b, filter.Mask) - nl.NewRtAttrChild(options, nl.TCA_FW_MASK, b) + options.AddRtAttr(nl.TCA_FW_MASK, b) } if filter.InDev != "" { - nl.NewRtAttrChild(options, nl.TCA_FW_INDEV, nl.ZeroTerminated(filter.InDev)) + options.AddRtAttr(nl.TCA_FW_INDEV, nl.ZeroTerminated(filter.InDev)) } if (filter.Police != nl.TcPolice{}) { - police := nl.NewRtAttrChild(options, nl.TCA_FW_POLICE, nil) - nl.NewRtAttrChild(police, nl.TCA_POLICE_TBF, filter.Police.Serialize()) + police := options.AddRtAttr(nl.TCA_FW_POLICE, nil) + police.AddRtAttr(nl.TCA_POLICE_TBF, filter.Police.Serialize()) if (filter.Police.Rate != nl.TcRateSpec{}) { payload := SerializeRtab(filter.Rtab) - nl.NewRtAttrChild(police, nl.TCA_POLICE_RATE, payload) + police.AddRtAttr(nl.TCA_POLICE_RATE, payload) } if (filter.Police.PeakRate != nl.TcRateSpec{}) { payload := SerializeRtab(filter.Ptab) - nl.NewRtAttrChild(police, nl.TCA_POLICE_PEAKRATE, payload) + police.AddRtAttr(nl.TCA_POLICE_PEAKRATE, payload) } } if filter.ClassId != 0 { b := make([]byte, 4) native.PutUint32(b, filter.ClassId) - nl.NewRtAttrChild(options, nl.TCA_FW_CLASSID, b) + options.AddRtAttr(nl.TCA_FW_CLASSID, b) } case *BpfFilter: var bpfFlags uint32 if filter.ClassId != 0 { - nl.NewRtAttrChild(options, nl.TCA_BPF_CLASSID, nl.Uint32Attr(filter.ClassId)) + options.AddRtAttr(nl.TCA_BPF_CLASSID, nl.Uint32Attr(filter.ClassId)) } if filter.Fd >= 0 { - nl.NewRtAttrChild(options, nl.TCA_BPF_FD, nl.Uint32Attr((uint32(filter.Fd)))) + options.AddRtAttr(nl.TCA_BPF_FD, nl.Uint32Attr((uint32(filter.Fd)))) } if filter.Name != "" { - nl.NewRtAttrChild(options, nl.TCA_BPF_NAME, nl.ZeroTerminated(filter.Name)) + options.AddRtAttr(nl.TCA_BPF_NAME, nl.ZeroTerminated(filter.Name)) } if filter.DirectAction { bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT } - nl.NewRtAttrChild(options, nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags)) + options.AddRtAttr(nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags)) case *MatchAll: - actionsAttr := nl.NewRtAttrChild(options, nl.TCA_MATCHALL_ACT, nil) + actionsAttr := options.AddRtAttr(nl.TCA_MATCHALL_ACT, nil) if err := EncodeActions(actionsAttr, filter.Actions); err != nil { return err } if filter.ClassId != 0 { - nl.NewRtAttrChild(options, nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId)) + options.AddRtAttr(nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId)) } } @@ -366,34 +420,91 @@ func EncodeActions(attr *nl.RtAttr, actions []Action) error { default: return fmt.Errorf("unknown action type %s", action.Type()) case *MirredAction: - table := nl.NewRtAttrChild(attr, tabIndex, nil) + table := attr.AddRtAttr(tabIndex, nil) tabIndex++ - nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred")) - aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil) + table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred")) + aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) mirred := nl.TcMirred{ Eaction: int32(action.MirredAction), Ifindex: uint32(action.Ifindex), } toTcGen(action.Attrs(), &mirred.TcGen) - nl.NewRtAttrChild(aopts, nl.TCA_MIRRED_PARMS, mirred.Serialize()) + aopts.AddRtAttr(nl.TCA_MIRRED_PARMS, mirred.Serialize()) + case *TunnelKeyAction: + table := attr.AddRtAttr(tabIndex, nil) + tabIndex++ + table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("tunnel_key")) + aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) + tun := nl.TcTunnelKey{ + Action: int32(action.Action), + } + toTcGen(action.Attrs(), &tun.TcGen) + aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_PARMS, tun.Serialize()) + if action.Action == TCA_TUNNEL_KEY_SET { + aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_KEY_ID, htonl(action.KeyID)) + if v4 := action.SrcAddr.To4(); v4 != nil { + aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC, v4[:]) + } else if v6 := action.SrcAddr.To16(); v6 != nil { + aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC, v6[:]) + } else { + return fmt.Errorf("invalid src addr %s for tunnel_key action", action.SrcAddr) + } + if v4 := action.DstAddr.To4(); v4 != nil { + aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV4_DST, v4[:]) + } else if v6 := action.DstAddr.To16(); v6 != nil { + aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV6_DST, v6[:]) + } else { + return fmt.Errorf("invalid dst addr %s for tunnel_key action", action.DstAddr) + } + } + case *SkbEditAction: + table := attr.AddRtAttr(tabIndex, nil) + tabIndex++ + table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("skbedit")) + aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) + skbedit := nl.TcSkbEdit{} + toTcGen(action.Attrs(), &skbedit.TcGen) + aopts.AddRtAttr(nl.TCA_SKBEDIT_PARMS, skbedit.Serialize()) + if action.QueueMapping != nil { + aopts.AddRtAttr(nl.TCA_SKBEDIT_QUEUE_MAPPING, nl.Uint16Attr(*action.QueueMapping)) + } + if action.Priority != nil { + aopts.AddRtAttr(nl.TCA_SKBEDIT_PRIORITY, nl.Uint32Attr(*action.Priority)) + } + if action.PType != nil { + aopts.AddRtAttr(nl.TCA_SKBEDIT_PTYPE, nl.Uint16Attr(*action.PType)) + } + if action.Mark != nil { + aopts.AddRtAttr(nl.TCA_SKBEDIT_MARK, nl.Uint32Attr(*action.Mark)) + } + case *ConnmarkAction: + table := attr.AddRtAttr(tabIndex, nil) + tabIndex++ + table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("connmark")) + aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) + connmark := nl.TcConnmark{ + Zone: action.Zone, + } + toTcGen(action.Attrs(), &connmark.TcGen) + aopts.AddRtAttr(nl.TCA_CONNMARK_PARMS, connmark.Serialize()) case *BpfAction: - table := nl.NewRtAttrChild(attr, tabIndex, nil) + table := attr.AddRtAttr(tabIndex, nil) tabIndex++ - nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf")) - aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil) + table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf")) + aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) gen := nl.TcGen{} toTcGen(action.Attrs(), &gen) - nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_PARMS, gen.Serialize()) - nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd))) - nl.NewRtAttrChild(aopts, nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name)) + aopts.AddRtAttr(nl.TCA_ACT_BPF_PARMS, gen.Serialize()) + aopts.AddRtAttr(nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd))) + aopts.AddRtAttr(nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name)) case *GenericAction: - table := nl.NewRtAttrChild(attr, tabIndex, nil) + table := attr.AddRtAttr(tabIndex, nil) tabIndex++ - nl.NewRtAttrChild(table, nl.TCA_ACT_KIND, nl.ZeroTerminated("gact")) - aopts := nl.NewRtAttrChild(table, nl.TCA_ACT_OPTIONS, nil) + table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("gact")) + aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil) gen := nl.TcGen{} toTcGen(action.Attrs(), &gen) - nl.NewRtAttrChild(aopts, nl.TCA_GACT_PARMS, gen.Serialize()) + aopts.AddRtAttr(nl.TCA_GACT_PARMS, gen.Serialize()) } } return nil @@ -419,8 +530,14 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) { action = &MirredAction{} case "bpf": action = &BpfAction{} + case "connmark": + action = &ConnmarkAction{} case "gact": action = &GenericAction{} + case "tunnel_key": + action = &TunnelKeyAction{} + case "skbedit": + action = &SkbEditAction{} default: break nextattr } @@ -435,11 +552,46 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) { switch adatum.Attr.Type { case nl.TCA_MIRRED_PARMS: mirred := *nl.DeserializeTcMirred(adatum.Value) - toAttrs(&mirred.TcGen, action.Attrs()) action.(*MirredAction).ActionAttrs = ActionAttrs{} + toAttrs(&mirred.TcGen, action.Attrs()) action.(*MirredAction).Ifindex = int(mirred.Ifindex) action.(*MirredAction).MirredAction = MirredAct(mirred.Eaction) } + case "tunnel_key": + switch adatum.Attr.Type { + case nl.TCA_TUNNEL_KEY_PARMS: + tun := *nl.DeserializeTunnelKey(adatum.Value) + action.(*TunnelKeyAction).ActionAttrs = ActionAttrs{} + toAttrs(&tun.TcGen, action.Attrs()) + action.(*TunnelKeyAction).Action = TunnelKeyAct(tun.Action) + case nl.TCA_TUNNEL_KEY_ENC_KEY_ID: + action.(*TunnelKeyAction).KeyID = networkOrder.Uint32(adatum.Value[0:4]) + case nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC: + case nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC: + action.(*TunnelKeyAction).SrcAddr = net.IP(adatum.Value[:]) + case nl.TCA_TUNNEL_KEY_ENC_IPV6_DST: + case nl.TCA_TUNNEL_KEY_ENC_IPV4_DST: + action.(*TunnelKeyAction).DstAddr = net.IP(adatum.Value[:]) + } + case "skbedit": + switch adatum.Attr.Type { + case nl.TCA_SKBEDIT_PARMS: + skbedit := *nl.DeserializeSkbEdit(adatum.Value) + action.(*SkbEditAction).ActionAttrs = ActionAttrs{} + toAttrs(&skbedit.TcGen, action.Attrs()) + case nl.TCA_SKBEDIT_MARK: + mark := native.Uint32(adatum.Value[0:4]) + action.(*SkbEditAction).Mark = &mark + case nl.TCA_SKBEDIT_PRIORITY: + priority := native.Uint32(adatum.Value[0:4]) + action.(*SkbEditAction).Priority = &priority + case nl.TCA_SKBEDIT_PTYPE: + ptype := native.Uint16(adatum.Value[0:2]) + action.(*SkbEditAction).PType = &ptype + case nl.TCA_SKBEDIT_QUEUE_MAPPING: + mapping := native.Uint16(adatum.Value[0:2]) + action.(*SkbEditAction).QueueMapping = &mapping + } case "bpf": switch adatum.Attr.Type { case nl.TCA_ACT_BPF_PARMS: @@ -450,6 +602,14 @@ func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) { case nl.TCA_ACT_BPF_NAME: action.(*BpfAction).Name = string(adatum.Value[:len(adatum.Value)-1]) } + case "connmark": + switch adatum.Attr.Type { + case nl.TCA_CONNMARK_PARMS: + connmark := *nl.DeserializeTcConnmark(adatum.Value) + action.(*ConnmarkAction).ActionAttrs = ActionAttrs{} + toAttrs(&connmark.TcGen, action.Attrs()) + action.(*ConnmarkAction).Zone = connmark.Zone + } case "gact": switch adatum.Attr.Type { case nl.TCA_GACT_PARMS: @@ -474,7 +634,7 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) case nl.TCA_U32_SEL: detailed = true sel := nl.DeserializeTcU32Sel(datum.Value) - u32.Sel = (*TcU32Sel)(unsafe.Pointer(sel)) + u32.Sel = sel if native != networkOrder { // Handle the endianness of attributes u32.Sel.Offmask = native.Uint16(htons(sel.Offmask)) @@ -500,6 +660,10 @@ func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) } case nl.TCA_U32_CLASSID: u32.ClassId = native.Uint32(datum.Value) + case nl.TCA_U32_DIVISOR: + u32.Divisor = native.Uint32(datum.Value) + case nl.TCA_U32_HASH: + u32.Hash = native.Uint32(datum.Value) } } return detailed, nil @@ -551,6 +715,10 @@ func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) if (flags & nl.TCA_BPF_FLAG_ACT_DIRECT) != 0 { bpf.DirectAction = true } + case nl.TCA_BPF_ID: + bpf.Id = int(native.Uint32(datum.Value[0:4])) + case nl.TCA_BPF_TAG: + bpf.Tag = hex.EncodeToString(datum.Value[:len(datum.Value)-1]) } } return detailed, nil diff --git a/vendor/github.com/vishvananda/netlink/fou_linux.go b/vendor/github.com/vishvananda/netlink/fou_linux.go index 62d59bd2d0..ed55b2b790 100644 --- a/vendor/github.com/vishvananda/netlink/fou_linux.go +++ b/vendor/github.com/vishvananda/netlink/fou_linux.go @@ -90,11 +90,7 @@ func (h *Handle) FouAdd(f Fou) error { req.AddRawData(raw) _, err = req.Execute(unix.NETLINK_GENERIC, 0) - if err != nil { - return err - } - - return nil + return err } func FouDel(f Fou) error { diff --git a/vendor/github.com/vishvananda/netlink/genetlink_linux.go b/vendor/github.com/vishvananda/netlink/genetlink_linux.go index ce7969907d..772e5834a2 100644 --- a/vendor/github.com/vishvananda/netlink/genetlink_linux.go +++ b/vendor/github.com/vishvananda/netlink/genetlink_linux.go @@ -157,6 +157,9 @@ func (h *Handle) GenlFamilyGet(name string) (*GenlFamily, error) { return nil, err } families, err := parseFamilies(msgs) + if err != nil { + return nil, err + } if len(families) != 1 { return nil, fmt.Errorf("invalid response for GENL_CTRL_CMD_GETFAMILY") } diff --git a/vendor/github.com/vishvananda/netlink/handle_linux.go b/vendor/github.com/vishvananda/netlink/handle_linux.go index 9f6d7fe0fb..26887b7596 100644 --- a/vendor/github.com/vishvananda/netlink/handle_linux.go +++ b/vendor/github.com/vishvananda/netlink/handle_linux.go @@ -91,7 +91,7 @@ func (h *Handle) GetSocketReceiveBufferSize() ([]int, error) { return results, nil } -// NewHandle returns a netlink handle on the network namespace +// NewHandleAt returns a netlink handle on the network namespace // specified by ns. If ns=netns.None(), current network namespace // will be assumed func NewHandleAt(ns netns.NsHandle, nlFamilies ...int) (*Handle, error) { diff --git a/vendor/github.com/vishvananda/netlink/handle_unspecified.go b/vendor/github.com/vishvananda/netlink/handle_unspecified.go index 915b765ded..ef914dcb8c 100644 --- a/vendor/github.com/vishvananda/netlink/handle_unspecified.go +++ b/vendor/github.com/vishvananda/netlink/handle_unspecified.go @@ -73,10 +73,18 @@ func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error { return ErrNotImplemented } +func (h *Handle) LinkSetVfVlanQos(link Link, vf, vlan, qos int) error { + return ErrNotImplemented +} + func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error { return ErrNotImplemented } +func (h *Handle) LinkSetVfRate(link Link, vf, minRate, maxRate int) error { + return ErrNotImplemented +} + func (h *Handle) LinkSetMaster(link Link, master *Bridge) error { return ErrNotImplemented } @@ -149,6 +157,10 @@ func (h *Handle) LinkSetTxQLen(link Link, qlen int) error { return ErrNotImplemented } +func (h *Handle) LinkSetGroup(link Link, group int) error { + return ErrNotImplemented +} + func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error { return ErrNotImplemented } diff --git a/vendor/github.com/vishvananda/netlink/ioctl_linux.go b/vendor/github.com/vishvananda/netlink/ioctl_linux.go index a8503126d5..4d33db5da5 100644 --- a/vendor/github.com/vishvananda/netlink/ioctl_linux.go +++ b/vendor/github.com/vishvananda/netlink/ioctl_linux.go @@ -56,18 +56,10 @@ type ethtoolSset struct { data [1]uint32 } -// ethtoolGstrings is string set for data tagging -type ethtoolGstrings struct { - cmd uint32 - stringSet uint32 - length uint32 - data [32]byte -} - type ethtoolStats struct { cmd uint32 nStats uint32 - data [1]uint64 + // Followed by nStats * []uint64. } // newIocltSlaveReq returns filled IfreqSlave with proper interface names diff --git a/vendor/github.com/vishvananda/netlink/link.go b/vendor/github.com/vishvananda/netlink/link.go index fe74ffab96..886d88d1b2 100644 --- a/vendor/github.com/vishvananda/netlink/link.go +++ b/vendor/github.com/vishvananda/netlink/link.go @@ -4,6 +4,7 @@ import ( "fmt" "net" "os" + "strconv" ) // Link represents a link device from netlink. Shared link attributes @@ -41,6 +42,29 @@ type LinkAttrs struct { NetNsID int NumTxQueues int NumRxQueues int + GSOMaxSize uint32 + GSOMaxSegs uint32 + Vfs []VfInfo // virtual functions available on link + Group uint32 + Slave LinkSlave +} + +// LinkSlave represents a slave device. +type LinkSlave interface { + SlaveType() string +} + +// VfInfo represents configuration of virtual function +type VfInfo struct { + ID int + Mac net.HardwareAddr + Vlan int + Qos int + TxRate int // IFLA_VF_TX_RATE Max TxRate + Spoofchk bool + LinkState uint32 + MaxTxRate uint32 // IFLA_VF_RATE Max TxRate + MinTxRate uint32 // IFLA_VF_RATE Min TxRate } // LinkOperState represents the values of the IFLA_OPERSTATE link @@ -223,6 +247,7 @@ type Bridge struct { LinkAttrs MulticastSnooping *bool HelloTime *uint32 + VlanFiltering *bool } func (bridge *Bridge) Attrs() *LinkAttrs { @@ -236,7 +261,8 @@ func (bridge *Bridge) Type() string { // Vlan links have ParentIndex set in their Attrs() type Vlan struct { LinkAttrs - VlanId int + VlanId int + VlanProtocol VlanProtocol } func (vlan *Vlan) Attrs() *LinkAttrs { @@ -290,10 +316,13 @@ type TuntapFlag uint16 // Tuntap links created via /dev/tun/tap, but can be destroyed via netlink type Tuntap struct { LinkAttrs - Mode TuntapMode - Flags TuntapFlag - Queues int - Fds []*os.File + Mode TuntapMode + Flags TuntapFlag + NonPersist bool + Queues int + Fds []*os.File + Owner uint32 + Group uint32 } func (tuntap *Tuntap) Attrs() *LinkAttrs { @@ -307,7 +336,8 @@ func (tuntap *Tuntap) Type() string { // Veth devices must specify PeerName on create type Veth struct { LinkAttrs - PeerName string // veth on create only + PeerName string // veth on create only + PeerHardwareAddr net.HardwareAddr } func (veth *Veth) Attrs() *LinkAttrs { @@ -376,9 +406,18 @@ const ( IPVLAN_MODE_MAX ) +type IPVlanFlag uint16 + +const ( + IPVLAN_FLAG_BRIDGE IPVlanFlag = iota + IPVLAN_FLAG_PRIVATE + IPVLAN_FLAG_VEPA +) + type IPVlan struct { LinkAttrs Mode IPVlanMode + Flag IPVlanFlag } func (ipvlan *IPVlan) Attrs() *LinkAttrs { @@ -389,6 +428,43 @@ func (ipvlan *IPVlan) Type() string { return "ipvlan" } +// VlanProtocol type +type VlanProtocol int + +func (p VlanProtocol) String() string { + s, ok := VlanProtocolToString[p] + if !ok { + return fmt.Sprintf("VlanProtocol(%d)", p) + } + return s +} + +// StringToVlanProtocol returns vlan protocol, or unknown is the s is invalid. +func StringToVlanProtocol(s string) VlanProtocol { + mode, ok := StringToVlanProtocolMap[s] + if !ok { + return VLAN_PROTOCOL_UNKNOWN + } + return mode +} + +// VlanProtocol possible values +const ( + VLAN_PROTOCOL_UNKNOWN VlanProtocol = 0 + VLAN_PROTOCOL_8021Q VlanProtocol = 0x8100 + VLAN_PROTOCOL_8021AD VlanProtocol = 0x88A8 +) + +var VlanProtocolToString = map[VlanProtocol]string{ + VLAN_PROTOCOL_8021Q: "802.1q", + VLAN_PROTOCOL_8021AD: "802.1ad", +} + +var StringToVlanProtocolMap = map[string]VlanProtocol{ + "802.1q": VLAN_PROTOCOL_8021Q, + "802.1ad": VLAN_PROTOCOL_8021AD, +} + // BondMode type type BondMode int @@ -400,7 +476,7 @@ func (b BondMode) String() string { return s } -// StringToBondMode returns bond mode, or uknonw is the s is invalid. +// StringToBondMode returns bond mode, or unknown is the s is invalid. func StringToBondMode(s string) BondMode { mode, ok := StringToBondModeMap[s] if !ok { @@ -491,7 +567,7 @@ func (b BondXmitHashPolicy) String() string { return s } -// StringToBondXmitHashPolicy returns bond lacp arte, or uknonw is the s is invalid. +// StringToBondXmitHashPolicy returns bond lacp arte, or unknown is the s is invalid. func StringToBondXmitHashPolicy(s string) BondXmitHashPolicy { lacp, ok := StringToBondXmitHashPolicyMap[s] if !ok { @@ -536,7 +612,7 @@ func (b BondLacpRate) String() string { return s } -// StringToBondLacpRate returns bond lacp arte, or uknonw is the s is invalid. +// StringToBondLacpRate returns bond lacp arte, or unknown is the s is invalid. func StringToBondLacpRate(s string) BondLacpRate { lacp, ok := StringToBondLacpRateMap[s] if !ok { @@ -680,6 +756,67 @@ func (bond *Bond) Type() string { return "bond" } +// BondSlaveState represents the values of the IFLA_BOND_SLAVE_STATE bond slave +// attribute, which contains the state of the bond slave. +type BondSlaveState uint8 + +const ( + BondStateActive = iota // Link is active. + BondStateBackup // Link is backup. +) + +func (s BondSlaveState) String() string { + switch s { + case BondStateActive: + return "ACTIVE" + case BondStateBackup: + return "BACKUP" + default: + return strconv.Itoa(int(s)) + } +} + +// BondSlaveState represents the values of the IFLA_BOND_SLAVE_MII_STATUS bond slave +// attribute, which contains the status of MII link monitoring +type BondSlaveMiiStatus uint8 + +const ( + BondLinkUp = iota // link is up and running. + BondLinkFail // link has just gone down. + BondLinkDown // link has been down for too long time. + BondLinkBack // link is going back. +) + +func (s BondSlaveMiiStatus) String() string { + switch s { + case BondLinkUp: + return "UP" + case BondLinkFail: + return "GOING_DOWN" + case BondLinkDown: + return "DOWN" + case BondLinkBack: + return "GOING_BACK" + default: + return strconv.Itoa(int(s)) + } +} + +type BondSlave struct { + State BondSlaveState + MiiStatus BondSlaveMiiStatus + LinkFailureCount uint32 + PermHardwareAddr net.HardwareAddr + QueueId uint16 + AggregatorId uint16 + AdActorOperPortState uint8 + AdPartnerOperPortState uint16 +} + +func (b *BondSlave) SlaveType() string { + return "bond" +} + // Gretap devices must specify LocalIP and RemoteIP on create type Gretap struct { LinkAttrs @@ -734,6 +871,27 @@ func (iptun *Iptun) Type() string { return "ipip" } +type Ip6tnl struct { + LinkAttrs + Link uint32 + Local net.IP + Remote net.IP + Ttl uint8 + Tos uint8 + EncapLimit uint8 + Flags uint32 + Proto uint8 + FlowInfo uint32 +} + +func (ip6tnl *Ip6tnl) Attrs() *LinkAttrs { + return &ip6tnl.LinkAttrs +} + +func (ip6tnl *Ip6tnl) Type() string { + return "ip6tnl" +} + type Sittun struct { LinkAttrs Link uint32 @@ -769,7 +927,10 @@ func (vti *Vti) Attrs() *LinkAttrs { return &vti.LinkAttrs } -func (iptun *Vti) Type() string { +func (vti *Vti) Type() string { + if vti.Local.To4() == nil { + return "vti6" + } return "vti" } @@ -831,11 +992,68 @@ func (gtp *GTP) Type() string { return "gtp" } +// Virtual XFRM Interfaces +// Named "xfrmi" to prevent confusion with XFRM objects +type Xfrmi struct { + LinkAttrs + Ifid uint32 +} + +func (xfrm *Xfrmi) Attrs() *LinkAttrs { + return &xfrm.LinkAttrs +} + +func (xfrm *Xfrmi) Type() string { + return "xfrm" +} + +// IPoIB interface + +type IPoIBMode uint16 + +func (m *IPoIBMode) String() string { + str, ok := iPoIBModeToString[*m] + if !ok { + return fmt.Sprintf("mode(%d)", *m) + } + return str +} + +const ( + IPOIB_MODE_DATAGRAM = iota + IPOIB_MODE_CONNECTED +) + +var iPoIBModeToString = map[IPoIBMode]string{ + IPOIB_MODE_DATAGRAM: "datagram", + IPOIB_MODE_CONNECTED: "connected", +} + +var StringToIPoIBMode = map[string]IPoIBMode{ + "datagram": IPOIB_MODE_DATAGRAM, + "connected": IPOIB_MODE_CONNECTED, +} + +type IPoIB struct { + LinkAttrs + Pkey uint16 + Mode IPoIBMode + Umcast uint16 +} + +func (ipoib *IPoIB) Attrs() *LinkAttrs { + return &ipoib.LinkAttrs +} + +func (ipoib *IPoIB) Type() string { + return "ipoib" +} + // iproute2 supported devices; // vlan | veth | vcan | dummy | ifb | macvlan | macvtap | // bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | -// gre | gretap | ip6gre | ip6gretap | vti | nlmon | -// bond_slave | ipvlan +// gre | gretap | ip6gre | ip6gretap | vti | vti6 | nlmon | +// bond_slave | ipvlan | xfrm // LinkNotFoundError wraps the various not found errors when // getting/reading links. This is intended for better error diff --git a/vendor/github.com/vishvananda/netlink/link_linux.go b/vendor/github.com/vishvananda/netlink/link_linux.go index 540191ed84..ec915a0b97 100644 --- a/vendor/github.com/vishvananda/netlink/link_linux.go +++ b/vendor/github.com/vishvananda/netlink/link_linux.go @@ -4,8 +4,11 @@ import ( "bytes" "encoding/binary" "fmt" + "io/ioutil" "net" "os" + "strconv" + "strings" "syscall" "unsafe" @@ -16,7 +19,7 @@ import ( const ( SizeofLinkStats32 = 0x5c - SizeofLinkStats64 = 0xd8 + SizeofLinkStats64 = 0xb8 ) const ( @@ -31,6 +34,12 @@ const ( TUNTAP_MULTI_QUEUE_DEFAULTS TuntapFlag = TUNTAP_MULTI_QUEUE | TUNTAP_NO_PI ) +const ( + VF_LINK_STATE_AUTO uint32 = 0 + VF_LINK_STATE_ENABLE uint32 = 1 + VF_LINK_STATE_DISABLE uint32 = 2 +) + var lookupByDump = false var macvlanModes = [...]uint32{ @@ -113,6 +122,52 @@ func (h *Handle) SetPromiscOn(link Link) error { return err } +// LinkSetAllmulticastOn enables the reception of all hardware multicast packets for the link device. +// Equivalent to: `ip link set $link allmulticast on` +func LinkSetAllmulticastOn(link Link) error { + return pkgHandle.LinkSetAllmulticastOn(link) +} + +// LinkSetAllmulticastOn enables the reception of all hardware multicast packets for the link device. +// Equivalent to: `ip link set $link allmulticast on` +func (h *Handle) LinkSetAllmulticastOn(link Link) error { + base := link.Attrs() + h.ensureIndex(base) + req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK) + + msg := nl.NewIfInfomsg(unix.AF_UNSPEC) + msg.Change = unix.IFF_ALLMULTI + msg.Flags = unix.IFF_ALLMULTI + + msg.Index = int32(base.Index) + req.AddData(msg) + + _, err := req.Execute(unix.NETLINK_ROUTE, 0) + return err +} + +// LinkSetAllmulticastOff disables the reception of all hardware multicast packets for the link device. +// Equivalent to: `ip link set $link allmulticast off` +func LinkSetAllmulticastOff(link Link) error { + return pkgHandle.LinkSetAllmulticastOff(link) +} + +// LinkSetAllmulticastOff disables the reception of all hardware multicast packets for the link device. +// Equivalent to: `ip link set $link allmulticast off` +func (h *Handle) LinkSetAllmulticastOff(link Link) error { + base := link.Attrs() + h.ensureIndex(base) + req := h.newNetlinkRequest(unix.RTM_NEWLINK, unix.NLM_F_ACK) + + msg := nl.NewIfInfomsg(unix.AF_UNSPEC) + msg.Change = unix.IFF_ALLMULTI + msg.Index = int32(base.Index) + req.AddData(msg) + + _, err := req.Execute(unix.NETLINK_ROUTE, 0) + return err +} + func MacvlanMACAddrAdd(link Link, addr net.HardwareAddr) error { return pkgHandle.MacvlanMACAddrAdd(link, addr) } @@ -155,24 +210,24 @@ func (h *Handle) macvlanMACAddrChange(link Link, addrs []net.HardwareAddr, mode req.AddData(msg) linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil) - nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type())) - inner := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + linkInfo.AddRtAttr(nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type())) + inner := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) // IFLA_MACVLAN_MACADDR_MODE = mode b := make([]byte, 4) native.PutUint32(b, mode) - nl.NewRtAttrChild(inner, nl.IFLA_MACVLAN_MACADDR_MODE, b) + inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR_MODE, b) // populate message with MAC addrs, if necessary switch mode { case nl.MACVLAN_MACADDR_ADD, nl.MACVLAN_MACADDR_DEL: if len(addrs) == 1 { - nl.NewRtAttrChild(inner, nl.IFLA_MACVLAN_MACADDR, []byte(addrs[0])) + inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR, []byte(addrs[0])) } case nl.MACVLAN_MACADDR_SET: - mad := nl.NewRtAttrChild(inner, nl.IFLA_MACVLAN_MACADDR_DATA, nil) + mad := inner.AddRtAttr(nl.IFLA_MACVLAN_MACADDR_DATA, nil) for _, addr := range addrs { - nl.NewRtAttrChild(mad, nl.IFLA_MACVLAN_MACADDR, []byte(addr)) + mad.AddRtAttr(nl.IFLA_MACVLAN_MACADDR, []byte(addr)) } } @@ -203,7 +258,6 @@ func (h *Handle) SetPromiscOff(link Link) error { msg := nl.NewIfInfomsg(unix.AF_UNSPEC) msg.Change = unix.IFF_PROMISC - msg.Flags = 0 & ^unix.IFF_PROMISC msg.Index = int32(base.Index) req.AddData(msg) @@ -253,7 +307,6 @@ func (h *Handle) LinkSetDown(link Link) error { msg := nl.NewIfInfomsg(unix.AF_UNSPEC) msg.Change = unix.IFF_UP - msg.Flags = 0 & ^unix.IFF_UP msg.Index = int32(base.Index) req.AddData(msg) @@ -378,12 +431,12 @@ func (h *Handle) LinkSetVfHardwareAddr(link Link, vf int, hwaddr net.HardwareAdd req.AddData(msg) data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) - info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil) + info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) vfmsg := nl.VfMac{ Vf: uint32(vf), } copy(vfmsg.Mac[:], []byte(hwaddr)) - nl.NewRtAttrChild(info, nl.IFLA_VF_MAC, vfmsg.Serialize()) + info.AddRtAttr(nl.IFLA_VF_MAC, vfmsg.Serialize()) req.AddData(data) _, err := req.Execute(unix.NETLINK_ROUTE, 0) @@ -407,11 +460,42 @@ func (h *Handle) LinkSetVfVlan(link Link, vf, vlan int) error { msg.Index = int32(base.Index) req.AddData(msg) + data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) + info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) + vfmsg := nl.VfVlan{ + Vf: uint32(vf), + Vlan: uint32(vlan), + } + info.AddRtAttr(nl.IFLA_VF_VLAN, vfmsg.Serialize()) + req.AddData(data) + + _, err := req.Execute(unix.NETLINK_ROUTE, 0) + return err +} + +// LinkSetVfVlanQos sets the vlan and qos priority of a vf for the link. +// Equivalent to: `ip link set $link vf $vf vlan $vlan qos $qos` +func LinkSetVfVlanQos(link Link, vf, vlan, qos int) error { + return pkgHandle.LinkSetVfVlanQos(link, vf, vlan, qos) +} + +// LinkSetVfVlanQos sets the vlan and qos priority of a vf for the link. +// Equivalent to: `ip link set $link vf $vf vlan $vlan qos $qos` +func (h *Handle) LinkSetVfVlanQos(link Link, vf, vlan, qos int) error { + base := link.Attrs() + h.ensureIndex(base) + req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) + + msg := nl.NewIfInfomsg(unix.AF_UNSPEC) + msg.Index = int32(base.Index) + req.AddData(msg) + data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil) vfmsg := nl.VfVlan{ Vf: uint32(vf), Vlan: uint32(vlan), + Qos: uint32(qos), } nl.NewRtAttrChild(info, nl.IFLA_VF_VLAN, vfmsg.Serialize()) req.AddData(data) @@ -438,12 +522,73 @@ func (h *Handle) LinkSetVfTxRate(link Link, vf, rate int) error { req.AddData(msg) data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) - info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil) + info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) vfmsg := nl.VfTxRate{ Vf: uint32(vf), Rate: uint32(rate), } - nl.NewRtAttrChild(info, nl.IFLA_VF_TX_RATE, vfmsg.Serialize()) + info.AddRtAttr(nl.IFLA_VF_TX_RATE, vfmsg.Serialize()) + req.AddData(data) + + _, err := req.Execute(unix.NETLINK_ROUTE, 0) + return err +} + +// LinkSetVfRate sets the min and max tx rate of a vf for the link. +// Equivalent to: `ip link set $link vf $vf min_tx_rate $min_rate max_tx_rate $max_rate` +func LinkSetVfRate(link Link, vf, minRate, maxRate int) error { + return pkgHandle.LinkSetVfRate(link, vf, minRate, maxRate) +} + +// LinkSetVfRate sets the min and max tx rate of a vf for the link. +// Equivalent to: `ip link set $link vf $vf min_tx_rate $min_rate max_tx_rate $max_rate` +func (h *Handle) LinkSetVfRate(link Link, vf, minRate, maxRate int) error { + base := link.Attrs() + h.ensureIndex(base) + req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) + + msg := nl.NewIfInfomsg(unix.AF_UNSPEC) + msg.Index = int32(base.Index) + req.AddData(msg) + + data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) + info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) + vfmsg := nl.VfRate{ + Vf: uint32(vf), + MinTxRate: uint32(minRate), + MaxTxRate: uint32(maxRate), + } + info.AddRtAttr(nl.IFLA_VF_RATE, vfmsg.Serialize()) + req.AddData(data) + + _, err := req.Execute(unix.NETLINK_ROUTE, 0) + return err +} + +// LinkSetVfState enables/disables virtual link state on a vf. +// Equivalent to: `ip link set $link vf $vf state $state` +func LinkSetVfState(link Link, vf int, state uint32) error { + return pkgHandle.LinkSetVfState(link, vf, state) +} + +// LinkSetVfState enables/disables virtual link state on a vf. +// Equivalent to: `ip link set $link vf $vf state $state` +func (h *Handle) LinkSetVfState(link Link, vf int, state uint32) error { + base := link.Attrs() + h.ensureIndex(base) + req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) + + msg := nl.NewIfInfomsg(unix.AF_UNSPEC) + msg.Index = int32(base.Index) + req.AddData(msg) + + data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) + info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) + vfmsg := nl.VfLinkState{ + Vf: uint32(vf), + LinkState: state, + } + info.AddRtAttr(nl.IFLA_VF_LINK_STATE, vfmsg.Serialize()) req.AddData(data) _, err := req.Execute(unix.NETLINK_ROUTE, 0) @@ -456,7 +601,7 @@ func LinkSetVfSpoofchk(link Link, vf int, check bool) error { return pkgHandle.LinkSetVfSpoofchk(link, vf, check) } -// LinkSetVfSpookfchk enables/disables spoof check on a vf for the link. +// LinkSetVfSpoofchk enables/disables spoof check on a vf for the link. // Equivalent to: `ip link set $link vf $vf spoofchk $check` func (h *Handle) LinkSetVfSpoofchk(link Link, vf int, check bool) error { var setting uint32 @@ -469,7 +614,7 @@ func (h *Handle) LinkSetVfSpoofchk(link Link, vf int, check bool) error { req.AddData(msg) data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) - info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil) + info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) if check { setting = 1 } @@ -477,7 +622,7 @@ func (h *Handle) LinkSetVfSpoofchk(link Link, vf int, check bool) error { Vf: uint32(vf), Setting: setting, } - nl.NewRtAttrChild(info, nl.IFLA_VF_SPOOFCHK, vfmsg.Serialize()) + info.AddRtAttr(nl.IFLA_VF_SPOOFCHK, vfmsg.Serialize()) req.AddData(data) _, err := req.Execute(unix.NETLINK_ROUTE, 0) @@ -503,7 +648,7 @@ func (h *Handle) LinkSetVfTrust(link Link, vf int, state bool) error { req.AddData(msg) data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) - info := nl.NewRtAttrChild(data, nl.IFLA_VF_INFO, nil) + info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) if state { setting = 1 } @@ -511,22 +656,66 @@ func (h *Handle) LinkSetVfTrust(link Link, vf int, state bool) error { Vf: uint32(vf), Setting: setting, } - nl.NewRtAttrChild(info, nl.IFLA_VF_TRUST, vfmsg.Serialize()) + info.AddRtAttr(nl.IFLA_VF_TRUST, vfmsg.Serialize()) req.AddData(data) _, err := req.Execute(unix.NETLINK_ROUTE, 0) return err } +// LinkSetVfNodeGUID sets the node GUID of a vf for the link. +// Equivalent to: `ip link set dev $link vf $vf node_guid $nodeguid` +func LinkSetVfNodeGUID(link Link, vf int, nodeguid net.HardwareAddr) error { + return pkgHandle.LinkSetVfGUID(link, vf, nodeguid, nl.IFLA_VF_IB_NODE_GUID) +} + +// LinkSetVfPortGUID sets the port GUID of a vf for the link. +// Equivalent to: `ip link set dev $link vf $vf port_guid $portguid` +func LinkSetVfPortGUID(link Link, vf int, portguid net.HardwareAddr) error { + return pkgHandle.LinkSetVfGUID(link, vf, portguid, nl.IFLA_VF_IB_PORT_GUID) +} + +// LinkSetVfGUID sets the node or port GUID of a vf for the link. +func (h *Handle) LinkSetVfGUID(link Link, vf int, vfGuid net.HardwareAddr, guidType int) error { + var err error + var guid uint64 + + buf := bytes.NewBuffer(vfGuid) + err = binary.Read(buf, binary.BigEndian, &guid) + if err != nil { + return err + } + + base := link.Attrs() + h.ensureIndex(base) + req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) + + msg := nl.NewIfInfomsg(unix.AF_UNSPEC) + msg.Index = int32(base.Index) + req.AddData(msg) + + data := nl.NewRtAttr(unix.IFLA_VFINFO_LIST, nil) + info := data.AddRtAttr(nl.IFLA_VF_INFO, nil) + vfmsg := nl.VfGUID{ + Vf: uint32(vf), + GUID: guid, + } + info.AddRtAttr(guidType, vfmsg.Serialize()) + req.AddData(data) + + _, err = req.Execute(unix.NETLINK_ROUTE, 0) + return err +} + // LinkSetMaster sets the master of the link device. // Equivalent to: `ip link set $link master $master` -func LinkSetMaster(link Link, master *Bridge) error { +func LinkSetMaster(link Link, master Link) error { return pkgHandle.LinkSetMaster(link, master) } // LinkSetMaster sets the master of the link device. // Equivalent to: `ip link set $link master $master` -func (h *Handle) LinkSetMaster(link Link, master *Bridge) error { +func (h *Handle) LinkSetMaster(link Link, master Link) error { index := 0 if master != nil { masterBase := master.Attrs() @@ -672,69 +861,69 @@ type vxlanPortRange struct { } func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) if vxlan.FlowBased { vxlan.VxlanId = 0 } - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_ID, nl.Uint32Attr(uint32(vxlan.VxlanId))) + data.AddRtAttr(nl.IFLA_VXLAN_ID, nl.Uint32Attr(uint32(vxlan.VxlanId))) if vxlan.VtepDevIndex != 0 { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LINK, nl.Uint32Attr(uint32(vxlan.VtepDevIndex))) + data.AddRtAttr(nl.IFLA_VXLAN_LINK, nl.Uint32Attr(uint32(vxlan.VtepDevIndex))) } if vxlan.SrcAddr != nil { ip := vxlan.SrcAddr.To4() if ip != nil { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LOCAL, []byte(ip)) + data.AddRtAttr(nl.IFLA_VXLAN_LOCAL, []byte(ip)) } else { ip = vxlan.SrcAddr.To16() if ip != nil { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LOCAL6, []byte(ip)) + data.AddRtAttr(nl.IFLA_VXLAN_LOCAL6, []byte(ip)) } } } if vxlan.Group != nil { group := vxlan.Group.To4() if group != nil { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GROUP, []byte(group)) + data.AddRtAttr(nl.IFLA_VXLAN_GROUP, []byte(group)) } else { group = vxlan.Group.To16() if group != nil { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GROUP6, []byte(group)) + data.AddRtAttr(nl.IFLA_VXLAN_GROUP6, []byte(group)) } } } - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_TTL, nl.Uint8Attr(uint8(vxlan.TTL))) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_TOS, nl.Uint8Attr(uint8(vxlan.TOS))) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LEARNING, boolAttr(vxlan.Learning)) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PROXY, boolAttr(vxlan.Proxy)) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_RSC, boolAttr(vxlan.RSC)) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss)) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss)) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_ZERO_CSUM6_TX, boolAttr(vxlan.UDP6ZeroCSumTx)) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_ZERO_CSUM6_RX, boolAttr(vxlan.UDP6ZeroCSumRx)) + data.AddRtAttr(nl.IFLA_VXLAN_TTL, nl.Uint8Attr(uint8(vxlan.TTL))) + data.AddRtAttr(nl.IFLA_VXLAN_TOS, nl.Uint8Attr(uint8(vxlan.TOS))) + data.AddRtAttr(nl.IFLA_VXLAN_LEARNING, boolAttr(vxlan.Learning)) + data.AddRtAttr(nl.IFLA_VXLAN_PROXY, boolAttr(vxlan.Proxy)) + data.AddRtAttr(nl.IFLA_VXLAN_RSC, boolAttr(vxlan.RSC)) + data.AddRtAttr(nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss)) + data.AddRtAttr(nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss)) + data.AddRtAttr(nl.IFLA_VXLAN_UDP_ZERO_CSUM6_TX, boolAttr(vxlan.UDP6ZeroCSumTx)) + data.AddRtAttr(nl.IFLA_VXLAN_UDP_ZERO_CSUM6_RX, boolAttr(vxlan.UDP6ZeroCSumRx)) if vxlan.UDPCSum { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_UDP_CSUM, boolAttr(vxlan.UDPCSum)) + data.AddRtAttr(nl.IFLA_VXLAN_UDP_CSUM, boolAttr(vxlan.UDPCSum)) } if vxlan.GBP { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GBP, []byte{}) + data.AddRtAttr(nl.IFLA_VXLAN_GBP, []byte{}) } if vxlan.FlowBased { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_FLOWBASED, boolAttr(vxlan.FlowBased)) + data.AddRtAttr(nl.IFLA_VXLAN_FLOWBASED, boolAttr(vxlan.FlowBased)) } if vxlan.NoAge { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0)) + data.AddRtAttr(nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0)) } else if vxlan.Age > 0 { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(uint32(vxlan.Age))) + data.AddRtAttr(nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(uint32(vxlan.Age))) } if vxlan.Limit > 0 { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_LIMIT, nl.Uint32Attr(uint32(vxlan.Limit))) + data.AddRtAttr(nl.IFLA_VXLAN_LIMIT, nl.Uint32Attr(uint32(vxlan.Limit))) } if vxlan.Port > 0 { - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT, htons(uint16(vxlan.Port))) + data.AddRtAttr(nl.IFLA_VXLAN_PORT, htons(uint16(vxlan.Port))) } if vxlan.PortLow > 0 || vxlan.PortHigh > 0 { pr := vxlanPortRange{uint16(vxlan.PortLow), uint16(vxlan.PortHigh)} @@ -742,100 +931,100 @@ func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) { buf := new(bytes.Buffer) binary.Write(buf, binary.BigEndian, &pr) - nl.NewRtAttrChild(data, nl.IFLA_VXLAN_PORT_RANGE, buf.Bytes()) + data.AddRtAttr(nl.IFLA_VXLAN_PORT_RANGE, buf.Bytes()) } } func addBondAttrs(bond *Bond, linkInfo *nl.RtAttr) { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) if bond.Mode >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_MODE, nl.Uint8Attr(uint8(bond.Mode))) + data.AddRtAttr(nl.IFLA_BOND_MODE, nl.Uint8Attr(uint8(bond.Mode))) } if bond.ActiveSlave >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_ACTIVE_SLAVE, nl.Uint32Attr(uint32(bond.ActiveSlave))) + data.AddRtAttr(nl.IFLA_BOND_ACTIVE_SLAVE, nl.Uint32Attr(uint32(bond.ActiveSlave))) } if bond.Miimon >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_MIIMON, nl.Uint32Attr(uint32(bond.Miimon))) + data.AddRtAttr(nl.IFLA_BOND_MIIMON, nl.Uint32Attr(uint32(bond.Miimon))) } if bond.UpDelay >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_UPDELAY, nl.Uint32Attr(uint32(bond.UpDelay))) + data.AddRtAttr(nl.IFLA_BOND_UPDELAY, nl.Uint32Attr(uint32(bond.UpDelay))) } if bond.DownDelay >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_DOWNDELAY, nl.Uint32Attr(uint32(bond.DownDelay))) + data.AddRtAttr(nl.IFLA_BOND_DOWNDELAY, nl.Uint32Attr(uint32(bond.DownDelay))) } if bond.UseCarrier >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_USE_CARRIER, nl.Uint8Attr(uint8(bond.UseCarrier))) + data.AddRtAttr(nl.IFLA_BOND_USE_CARRIER, nl.Uint8Attr(uint8(bond.UseCarrier))) } if bond.ArpInterval >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_ARP_INTERVAL, nl.Uint32Attr(uint32(bond.ArpInterval))) + data.AddRtAttr(nl.IFLA_BOND_ARP_INTERVAL, nl.Uint32Attr(uint32(bond.ArpInterval))) } if bond.ArpIpTargets != nil { - msg := nl.NewRtAttrChild(data, nl.IFLA_BOND_ARP_IP_TARGET, nil) + msg := data.AddRtAttr(nl.IFLA_BOND_ARP_IP_TARGET, nil) for i := range bond.ArpIpTargets { ip := bond.ArpIpTargets[i].To4() if ip != nil { - nl.NewRtAttrChild(msg, i, []byte(ip)) + msg.AddRtAttr(i, []byte(ip)) continue } ip = bond.ArpIpTargets[i].To16() if ip != nil { - nl.NewRtAttrChild(msg, i, []byte(ip)) + msg.AddRtAttr(i, []byte(ip)) } } } if bond.ArpValidate >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_ARP_VALIDATE, nl.Uint32Attr(uint32(bond.ArpValidate))) + data.AddRtAttr(nl.IFLA_BOND_ARP_VALIDATE, nl.Uint32Attr(uint32(bond.ArpValidate))) } if bond.ArpAllTargets >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_ARP_ALL_TARGETS, nl.Uint32Attr(uint32(bond.ArpAllTargets))) + data.AddRtAttr(nl.IFLA_BOND_ARP_ALL_TARGETS, nl.Uint32Attr(uint32(bond.ArpAllTargets))) } if bond.Primary >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_PRIMARY, nl.Uint32Attr(uint32(bond.Primary))) + data.AddRtAttr(nl.IFLA_BOND_PRIMARY, nl.Uint32Attr(uint32(bond.Primary))) } if bond.PrimaryReselect >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_PRIMARY_RESELECT, nl.Uint8Attr(uint8(bond.PrimaryReselect))) + data.AddRtAttr(nl.IFLA_BOND_PRIMARY_RESELECT, nl.Uint8Attr(uint8(bond.PrimaryReselect))) } if bond.FailOverMac >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_FAIL_OVER_MAC, nl.Uint8Attr(uint8(bond.FailOverMac))) + data.AddRtAttr(nl.IFLA_BOND_FAIL_OVER_MAC, nl.Uint8Attr(uint8(bond.FailOverMac))) } if bond.XmitHashPolicy >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_XMIT_HASH_POLICY, nl.Uint8Attr(uint8(bond.XmitHashPolicy))) + data.AddRtAttr(nl.IFLA_BOND_XMIT_HASH_POLICY, nl.Uint8Attr(uint8(bond.XmitHashPolicy))) } if bond.ResendIgmp >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_RESEND_IGMP, nl.Uint32Attr(uint32(bond.ResendIgmp))) + data.AddRtAttr(nl.IFLA_BOND_RESEND_IGMP, nl.Uint32Attr(uint32(bond.ResendIgmp))) } if bond.NumPeerNotif >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_NUM_PEER_NOTIF, nl.Uint8Attr(uint8(bond.NumPeerNotif))) + data.AddRtAttr(nl.IFLA_BOND_NUM_PEER_NOTIF, nl.Uint8Attr(uint8(bond.NumPeerNotif))) } if bond.AllSlavesActive >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_ALL_SLAVES_ACTIVE, nl.Uint8Attr(uint8(bond.AllSlavesActive))) + data.AddRtAttr(nl.IFLA_BOND_ALL_SLAVES_ACTIVE, nl.Uint8Attr(uint8(bond.AllSlavesActive))) } if bond.MinLinks >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_MIN_LINKS, nl.Uint32Attr(uint32(bond.MinLinks))) + data.AddRtAttr(nl.IFLA_BOND_MIN_LINKS, nl.Uint32Attr(uint32(bond.MinLinks))) } if bond.LpInterval >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_LP_INTERVAL, nl.Uint32Attr(uint32(bond.LpInterval))) + data.AddRtAttr(nl.IFLA_BOND_LP_INTERVAL, nl.Uint32Attr(uint32(bond.LpInterval))) } if bond.PackersPerSlave >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PackersPerSlave))) + data.AddRtAttr(nl.IFLA_BOND_PACKETS_PER_SLAVE, nl.Uint32Attr(uint32(bond.PackersPerSlave))) } if bond.LacpRate >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_LACP_RATE, nl.Uint8Attr(uint8(bond.LacpRate))) + data.AddRtAttr(nl.IFLA_BOND_AD_LACP_RATE, nl.Uint8Attr(uint8(bond.LacpRate))) } if bond.AdSelect >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_SELECT, nl.Uint8Attr(uint8(bond.AdSelect))) + data.AddRtAttr(nl.IFLA_BOND_AD_SELECT, nl.Uint8Attr(uint8(bond.AdSelect))) } if bond.AdActorSysPrio >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_ACTOR_SYS_PRIO, nl.Uint16Attr(uint16(bond.AdActorSysPrio))) + data.AddRtAttr(nl.IFLA_BOND_AD_ACTOR_SYS_PRIO, nl.Uint16Attr(uint16(bond.AdActorSysPrio))) } if bond.AdUserPortKey >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_USER_PORT_KEY, nl.Uint16Attr(uint16(bond.AdUserPortKey))) + data.AddRtAttr(nl.IFLA_BOND_AD_USER_PORT_KEY, nl.Uint16Attr(uint16(bond.AdUserPortKey))) } if bond.AdActorSystem != nil { - nl.NewRtAttrChild(data, nl.IFLA_BOND_AD_ACTOR_SYSTEM, []byte(bond.AdActorSystem)) + data.AddRtAttr(nl.IFLA_BOND_AD_ACTOR_SYSTEM, []byte(bond.AdActorSystem)) } if bond.TlbDynamicLb >= 0 { - nl.NewRtAttrChild(data, nl.IFLA_BOND_TLB_DYNAMIC_LB, nl.Uint8Attr(uint8(bond.TlbDynamicLb))) + data.AddRtAttr(nl.IFLA_BOND_TLB_DYNAMIC_LB, nl.Uint8Attr(uint8(bond.TlbDynamicLb))) } } @@ -853,7 +1042,7 @@ func LinkAdd(link Link) error { } // LinkAdd adds a new link device. The type and features of the device -// are taken fromt the parameters in the link object. +// are taken from the parameters in the link object. // Equivalent to: `ip link add $link` func (h *Handle) LinkAdd(link Link) error { return h.linkModify(link, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK) @@ -863,16 +1052,18 @@ func (h *Handle) linkModify(link Link, flags int) error { // TODO: support extra data for macvlan base := link.Attrs() - if base.Name == "" { - return fmt.Errorf("LinkAttrs.Name cannot be empty!") + // if tuntap, then the name can be empty, OS will provide a name + tuntap, isTuntap := link.(*Tuntap) + + if base.Name == "" && !isTuntap { + return fmt.Errorf("LinkAttrs.Name cannot be empty") } - if tuntap, ok := link.(*Tuntap); ok { + if isTuntap { // TODO: support user // TODO: support group - // TODO: support non- persistent if tuntap.Mode < unix.IFF_TUN || tuntap.Mode > unix.IFF_TAP { - return fmt.Errorf("Tuntap.Mode %v unknown!", tuntap.Mode) + return fmt.Errorf("Tuntap.Mode %v unknown", tuntap.Mode) } queues := tuntap.Queues @@ -913,12 +1104,25 @@ func (h *Handle) linkModify(link Link, flags int) error { cleanupFds(fds) return fmt.Errorf("Tuntap IOCTL TUNSETIFF failed [%d], errno %v", i, errno) } + // 1) we only care for the name of the first tap in the multi queue set + // 2) if the original name was empty, the localReq has now the actual name + // + // In addition: + // This ensures that the link name is always identical to what the kernel returns. + // Not only in case of an empty name, but also when using name templates. + // e.g. when the provided name is "tap%d", the kernel replaces %d with the next available number. + if i == 0 { + link.Attrs().Name = strings.Trim(string(localReq.Name[:]), "\x00") + } } - _, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1) - if errno != 0 { - cleanupFds(fds) - return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno) + // only persist interface if NonPersist is NOT set + if !tuntap.NonPersist { + _, _, errno := unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 1) + if errno != 0 { + cleanupFds(fds) + return fmt.Errorf("Tuntap IOCTL TUNSETPERSIST failed, errno %v", errno) + } } h.ensureIndex(base) @@ -928,7 +1132,11 @@ func (h *Handle) linkModify(link Link, flags int) error { // TODO: verify MasterIndex is actually a bridge? err := h.LinkSetMasterByIndex(link, base.MasterIndex) if err != nil { - _, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0) + // un-persist (e.g. allow the interface to be removed) the tuntap + // should not hurt if not set prior, condition might be not needed + if !tuntap.NonPersist { + _, _, _ = unix.Syscall(unix.SYS_IOCTL, fds[0].Fd(), uintptr(unix.TUNSETPERSIST), 0) + } cleanupFds(fds) return err } @@ -978,8 +1186,8 @@ func (h *Handle) linkModify(link Link, flags int) error { native.PutUint32(b, uint32(base.ParentIndex)) data := nl.NewRtAttr(unix.IFLA_LINK, b) req.AddData(data) - } else if link.Type() == "ipvlan" { - return fmt.Errorf("Can't create ipvlan link without ParentIndex") + } else if link.Type() == "ipvlan" || link.Type() == "ipoib" { + return fmt.Errorf("Can't create %s link without ParentIndex", link.Type()) } nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(base.Name)) @@ -1010,14 +1218,29 @@ func (h *Handle) linkModify(link Link, flags int) error { req.AddData(rxqueues) } + if base.GSOMaxSegs > 0 { + gsoAttr := nl.NewRtAttr(unix.IFLA_GSO_MAX_SEGS, nl.Uint32Attr(base.GSOMaxSegs)) + req.AddData(gsoAttr) + } + + if base.GSOMaxSize > 0 { + gsoAttr := nl.NewRtAttr(unix.IFLA_GSO_MAX_SIZE, nl.Uint32Attr(base.GSOMaxSize)) + req.AddData(gsoAttr) + } + + if base.Group > 0 { + groupAttr := nl.NewRtAttr(unix.IFLA_GROUP, nl.Uint32Attr(base.Group)) + req.AddData(groupAttr) + } + if base.Namespace != nil { var attr *nl.RtAttr - switch base.Namespace.(type) { + switch ns := base.Namespace.(type) { case NsPid: - val := nl.Uint32Attr(uint32(base.Namespace.(NsPid))) + val := nl.Uint32Attr(uint32(ns)) attr = nl.NewRtAttr(unix.IFLA_NET_NS_PID, val) case NsFd: - val := nl.Uint32Attr(uint32(base.Namespace.(NsFd))) + val := nl.Uint32Attr(uint32(ns)) attr = nl.NewRtAttr(unix.IFLA_NET_NS_FD, val) } @@ -1029,47 +1252,56 @@ func (h *Handle) linkModify(link Link, flags int) error { } linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil) - nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type())) + linkInfo.AddRtAttr(nl.IFLA_INFO_KIND, nl.NonZeroTerminated(link.Type())) switch link := link.(type) { case *Vlan: b := make([]byte, 2) native.PutUint16(b, uint16(link.VlanId)) - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) - nl.NewRtAttrChild(data, nl.IFLA_VLAN_ID, b) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) + data.AddRtAttr(nl.IFLA_VLAN_ID, b) + + if link.VlanProtocol != VLAN_PROTOCOL_UNKNOWN { + data.AddRtAttr(nl.IFLA_VLAN_PROTOCOL, htons(uint16(link.VlanProtocol))) + } case *Veth: - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) - peer := nl.NewRtAttrChild(data, nl.VETH_INFO_PEER, nil) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) + peer := data.AddRtAttr(nl.VETH_INFO_PEER, nil) nl.NewIfInfomsgChild(peer, unix.AF_UNSPEC) - nl.NewRtAttrChild(peer, unix.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName)) + peer.AddRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(link.PeerName)) if base.TxQLen >= 0 { - nl.NewRtAttrChild(peer, unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen))) + peer.AddRtAttr(unix.IFLA_TXQLEN, nl.Uint32Attr(uint32(base.TxQLen))) } if base.MTU > 0 { - nl.NewRtAttrChild(peer, unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU))) + peer.AddRtAttr(unix.IFLA_MTU, nl.Uint32Attr(uint32(base.MTU))) + } + if link.PeerHardwareAddr != nil { + peer.AddRtAttr(unix.IFLA_ADDRESS, []byte(link.PeerHardwareAddr)) } - case *Vxlan: addVxlanAttrs(link, linkInfo) case *Bond: addBondAttrs(link, linkInfo) case *IPVlan: - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) - nl.NewRtAttrChild(data, nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode))) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) + data.AddRtAttr(nl.IFLA_IPVLAN_MODE, nl.Uint16Attr(uint16(link.Mode))) + data.AddRtAttr(nl.IFLA_IPVLAN_FLAG, nl.Uint16Attr(uint16(link.Flag))) case *Macvlan: if link.Mode != MACVLAN_MODE_DEFAULT { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) - nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode])) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) + data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode])) } case *Macvtap: if link.Mode != MACVLAN_MODE_DEFAULT { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) - nl.NewRtAttrChild(data, nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode])) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) + data.AddRtAttr(nl.IFLA_MACVLAN_MODE, nl.Uint32Attr(macvlanModes[link.Mode])) } case *Gretap: addGretapAttrs(link, linkInfo) case *Iptun: addIptunAttrs(link, linkInfo) + case *Ip6tnl: + addIp6tnlAttrs(link, linkInfo) case *Sittun: addSittunAttrs(link, linkInfo) case *Gretun: @@ -1082,6 +1314,10 @@ func (h *Handle) linkModify(link Link, flags int) error { addBridgeAttrs(link, linkInfo) case *GTP: addGTPAttrs(link, linkInfo) + case *Xfrmi: + addXfrmiAttrs(link, linkInfo) + case *IPoIB: + addIPoIBAttrs(link, linkInfo) } req.AddData(linkInfo) @@ -1170,6 +1406,9 @@ func (h *Handle) LinkByName(name string) (Link, error) { msg := nl.NewIfInfomsg(unix.AF_UNSPEC) req.AddData(msg) + attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF)) + req.AddData(attr) + nameData := nl.NewRtAttr(unix.IFLA_IFNAME, nl.ZeroTerminated(name)) req.AddData(nameData) @@ -1202,6 +1441,9 @@ func (h *Handle) LinkByAlias(alias string) (Link, error) { msg := nl.NewIfInfomsg(unix.AF_UNSPEC) req.AddData(msg) + attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF)) + req.AddData(attr) + nameData := nl.NewRtAttr(unix.IFLA_IFALIAS, nl.ZeroTerminated(alias)) req.AddData(nameData) @@ -1228,6 +1470,8 @@ func (h *Handle) LinkByIndex(index int) (Link, error) { msg := nl.NewIfInfomsg(unix.AF_UNSPEC) msg.Index = int32(index) req.AddData(msg) + attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF)) + req.AddData(attr) return execGetLink(req) } @@ -1270,10 +1514,12 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { base.Promisc = 1 } var ( - link Link - stats32 []byte - stats64 []byte - linkType string + link Link + stats32 *LinkStatistics32 + stats64 *LinkStatistics64 + linkType string + linkSlave LinkSlave + slaveType string ) for _, attr := range attrs { switch attr.Attr.Type { @@ -1313,18 +1559,26 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { link = &Gretap{} case "ipip": link = &Iptun{} + case "ip6tnl": + link = &Ip6tnl{} case "sit": link = &Sittun{} case "gre": link = &Gretun{} case "ip6gre": link = &Gretun{} - case "vti": + case "vti", "vti6": link = &Vti{} case "vrf": link = &Vrf{} case "gtp": link = >P{} + case "xfrm": + link = &Xfrmi{} + case "tun": + link = &Tuntap{} + case "ipoib": + link = &IPoIB{} default: link = &GenericLink{LinkType: linkType} } @@ -1352,13 +1606,15 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { parseGretapData(link, data) case "ipip": parseIptunData(link, data) + case "ip6tnl": + parseIp6tnlData(link, data) case "sit": parseSittunData(link, data) case "gre": parseGretunData(link, data) case "ip6gre": parseGretunData(link, data) - case "vti": + case "vti", "vti6": parseVtiData(link, data) case "vrf": parseVrfData(link, data) @@ -1366,6 +1622,27 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { parseBridgeData(link, data) case "gtp": parseGTPData(link, data) + case "xfrm": + parseXfrmiData(link, data) + case "tun": + parseTuntapData(link, data) + case "ipoib": + parseIPoIBData(link, data) + } + case nl.IFLA_INFO_SLAVE_KIND: + slaveType = string(info.Value[:len(info.Value)-1]) + switch slaveType { + case "bond": + linkSlave = &BondSlave{} + } + case nl.IFLA_INFO_SLAVE_DATA: + switch slaveType { + case "bond": + data, err := nl.ParseRouteAttr(info.Value) + if err != nil { + return nil, err + } + parseBondSlaveData(linkSlave, data) } } } @@ -1392,9 +1669,15 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { case unix.IFLA_IFALIAS: base.Alias = string(attr.Value[:len(attr.Value)-1]) case unix.IFLA_STATS: - stats32 = attr.Value[:] + stats32 = new(LinkStatistics32) + if err := binary.Read(bytes.NewBuffer(attr.Value[:]), nl.NativeEndian(), stats32); err != nil { + return nil, err + } case unix.IFLA_STATS64: - stats64 = attr.Value[:] + stats64 = new(LinkStatistics64) + if err := binary.Read(bytes.NewBuffer(attr.Value[:]), nl.NativeEndian(), stats64); err != nil { + return nil, err + } case unix.IFLA_XDP: xdp, err := parseLinkXdp(attr.Value[:]) if err != nil { @@ -1408,19 +1691,40 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { if err != nil { return nil, err } - base.Protinfo = parseProtinfo(attrs) + protinfo := parseProtinfo(attrs) + base.Protinfo = &protinfo } case unix.IFLA_OPERSTATE: base.OperState = LinkOperState(uint8(attr.Value[0])) case unix.IFLA_LINK_NETNSID: base.NetNsID = int(native.Uint32(attr.Value[0:4])) + case unix.IFLA_GSO_MAX_SIZE: + base.GSOMaxSize = native.Uint32(attr.Value[0:4]) + case unix.IFLA_GSO_MAX_SEGS: + base.GSOMaxSegs = native.Uint32(attr.Value[0:4]) + case unix.IFLA_VFINFO_LIST: + data, err := nl.ParseRouteAttr(attr.Value) + if err != nil { + return nil, err + } + vfs, err := parseVfInfoList(data) + if err != nil { + return nil, err + } + base.Vfs = vfs + case unix.IFLA_NUM_TX_QUEUES: + base.NumTxQueues = int(native.Uint32(attr.Value[0:4])) + case unix.IFLA_NUM_RX_QUEUES: + base.NumRxQueues = int(native.Uint32(attr.Value[0:4])) + case unix.IFLA_GROUP: + base.Group = native.Uint32(attr.Value[0:4]) } } if stats64 != nil { - base.Statistics = parseLinkStats64(stats64) + base.Statistics = (*LinkStatistics)(stats64) } else if stats32 != nil { - base.Statistics = parseLinkStats32(stats32) + base.Statistics = (*LinkStatistics)(stats32.to64()) } // Links that don't have IFLA_INFO_KIND are hardware devices @@ -1428,10 +1732,59 @@ func LinkDeserialize(hdr *unix.NlMsghdr, m []byte) (Link, error) { link = &Device{} } *link.Attrs() = base + link.Attrs().Slave = linkSlave + + // If the tuntap attributes are not updated by netlink due to + // an older driver, use sysfs + if link != nil && linkType == "tun" { + tuntap := link.(*Tuntap) + + if tuntap.Mode == 0 { + ifname := tuntap.Attrs().Name + if flags, err := readSysPropAsInt64(ifname, "tun_flags"); err == nil { + + if flags&unix.IFF_TUN != 0 { + tuntap.Mode = unix.IFF_TUN + } else if flags&unix.IFF_TAP != 0 { + tuntap.Mode = unix.IFF_TAP + } + + tuntap.NonPersist = false + if flags&unix.IFF_PERSIST == 0 { + tuntap.NonPersist = true + } + } + + // The sysfs interface for owner/group returns -1 for root user, instead of returning 0. + // So explicitly check for negative value, before assigning the owner uid/gid. + if owner, err := readSysPropAsInt64(ifname, "owner"); err == nil && owner > 0 { + tuntap.Owner = uint32(owner) + } + + if group, err := readSysPropAsInt64(ifname, "group"); err == nil && group > 0 { + tuntap.Group = uint32(group) + } + } + } return link, nil } +func readSysPropAsInt64(ifname, prop string) (int64, error) { + fname := fmt.Sprintf("/sys/class/net/%s/%s", ifname, prop) + contents, err := ioutil.ReadFile(fname) + if err != nil { + return 0, err + } + + num, err := strconv.ParseInt(strings.TrimSpace(string(contents)), 0, 64) + if err == nil { + return num, nil + } + + return 0, err +} + // LinkList gets a list of link devices. // Equivalent to: `ip link show` func LinkList() ([]Link, error) { @@ -1447,6 +1800,8 @@ func (h *Handle) LinkList() ([]Link, error) { msg := nl.NewIfInfomsg(unix.AF_UNSPEC) req.AddData(msg) + attr := nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(nl.RTEXT_FILTER_VF)) + req.AddData(attr) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK) if err != nil { @@ -1526,13 +1881,19 @@ func linkSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- LinkUpdate, done <-c go func() { defer close(ch) for { - msgs, err := s.Receive() + msgs, from, err := s.Receive() if err != nil { if cberr != nil { cberr(err) } return } + if from.Pid != nl.PidKernel { + if cberr != nil { + cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)) + } + continue + } for _, m := range msgs { if m.Header.Type == unix.NLMSG_DONE { continue @@ -1639,7 +2000,7 @@ func (h *Handle) setProtinfoAttr(link Link, mode bool, attr int) error { req.AddData(msg) br := nl.NewRtAttr(unix.IFLA_PROTINFO|unix.NLA_F_NESTED, nil) - nl.NewRtAttrChild(br, attr, boolToByte(mode)) + br.AddRtAttr(attr, boolToByte(mode)) req.AddData(br) _, err := req.Execute(unix.NETLINK_ROUTE, 0) if err != nil { @@ -1675,12 +2036,43 @@ func (h *Handle) LinkSetTxQLen(link Link, qlen int) error { return err } +// LinkSetGroup sets the link group id which can be used to perform mass actions +// with iproute2 as well use it as a reference in nft filters. +// Equivalent to: `ip link set $link group $id` +func LinkSetGroup(link Link, group int) error { + return pkgHandle.LinkSetGroup(link, group) +} + +// LinkSetGroup sets the link group id which can be used to perform mass actions +// with iproute2 as well use it as a reference in nft filters. +// Equivalent to: `ip link set $link group $id` +func (h *Handle) LinkSetGroup(link Link, group int) error { + base := link.Attrs() + h.ensureIndex(base) + req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) + + msg := nl.NewIfInfomsg(unix.AF_UNSPEC) + msg.Index = int32(base.Index) + req.AddData(msg) + + b := make([]byte, 4) + native.PutUint32(b, uint32(group)) + + data := nl.NewRtAttr(unix.IFLA_GROUP, b) + req.AddData(data) + + _, err := req.Execute(unix.NETLINK_ROUTE, 0) + return err +} + func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) { vlan := link.(*Vlan) for _, datum := range data { switch datum.Attr.Type { case nl.IFLA_VLAN_ID: vlan.VlanId = int(native.Uint16(datum.Value[0:2])) + case nl.IFLA_VLAN_PROTOCOL: + vlan.VlanProtocol = VlanProtocol(int(ntohs(datum.Value[0:2]))) } } } @@ -1762,7 +2154,7 @@ func parseBondData(link Link, data []syscall.NetlinkRouteAttr) { case nl.IFLA_BOND_ARP_INTERVAL: bond.ArpInterval = int(native.Uint32(data[i].Value[0:4])) case nl.IFLA_BOND_ARP_IP_TARGET: - // TODO: implement + bond.ArpIpTargets = parseBondArpIpTargets(data[i].Value) case nl.IFLA_BOND_ARP_VALIDATE: bond.ArpValidate = BondArpValidate(native.Uint32(data[i].Value[0:4])) case nl.IFLA_BOND_ARP_ALL_TARGETS: @@ -1805,12 +2197,75 @@ func parseBondData(link Link, data []syscall.NetlinkRouteAttr) { } } +func parseBondArpIpTargets(value []byte) []net.IP { + data, err := nl.ParseRouteAttr(value) + if err != nil { + return nil + } + + targets := []net.IP{} + for i := range data { + target := net.IP(data[i].Value) + if ip := target.To4(); ip != nil { + targets = append(targets, ip) + continue + } + if ip := target.To16(); ip != nil { + targets = append(targets, ip) + } + } + + return targets +} + +func addBondSlaveAttrs(bondSlave *BondSlave, linkInfo *nl.RtAttr) { + data := linkInfo.AddRtAttr(nl.IFLA_INFO_SLAVE_DATA, nil) + + data.AddRtAttr(nl.IFLA_BOND_SLAVE_STATE, nl.Uint8Attr(uint8(bondSlave.State))) + data.AddRtAttr(nl.IFLA_BOND_SLAVE_MII_STATUS, nl.Uint8Attr(uint8(bondSlave.MiiStatus))) + data.AddRtAttr(nl.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, nl.Uint32Attr(bondSlave.LinkFailureCount)) + data.AddRtAttr(nl.IFLA_BOND_SLAVE_QUEUE_ID, nl.Uint16Attr(bondSlave.QueueId)) + data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, nl.Uint16Attr(bondSlave.AggregatorId)) + data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, nl.Uint8Attr(bondSlave.AdActorOperPortState)) + data.AddRtAttr(nl.IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, nl.Uint16Attr(bondSlave.AdPartnerOperPortState)) + + if mac := bondSlave.PermHardwareAddr; mac != nil { + data.AddRtAttr(nl.IFLA_BOND_SLAVE_PERM_HWADDR, []byte(mac)) + } +} + +func parseBondSlaveData(slave LinkSlave, data []syscall.NetlinkRouteAttr) { + bondSlave := slave.(*BondSlave) + for i := range data { + switch data[i].Attr.Type { + case nl.IFLA_BOND_SLAVE_STATE: + bondSlave.State = BondSlaveState(data[i].Value[0]) + case nl.IFLA_BOND_SLAVE_MII_STATUS: + bondSlave.MiiStatus = BondSlaveMiiStatus(data[i].Value[0]) + case nl.IFLA_BOND_SLAVE_LINK_FAILURE_COUNT: + bondSlave.LinkFailureCount = native.Uint32(data[i].Value[0:4]) + case nl.IFLA_BOND_SLAVE_PERM_HWADDR: + bondSlave.PermHardwareAddr = net.HardwareAddr(data[i].Value[0:6]) + case nl.IFLA_BOND_SLAVE_QUEUE_ID: + bondSlave.QueueId = native.Uint16(data[i].Value[0:2]) + case nl.IFLA_BOND_SLAVE_AD_AGGREGATOR_ID: + bondSlave.AggregatorId = native.Uint16(data[i].Value[0:2]) + case nl.IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE: + bondSlave.AdActorOperPortState = uint8(data[i].Value[0]) + case nl.IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE: + bondSlave.AdPartnerOperPortState = native.Uint16(data[i].Value[0:2]) + } + } +} + func parseIPVlanData(link Link, data []syscall.NetlinkRouteAttr) { ipv := link.(*IPVlan) for _, datum := range data { - if datum.Attr.Type == nl.IFLA_IPVLAN_MODE { + switch datum.Attr.Type { + case nl.IFLA_IPVLAN_MODE: ipv.Mode = IPVlanMode(native.Uint32(datum.Value[0:4])) - return + case nl.IFLA_IPVLAN_FLAG: + ipv.Flag = IPVlanFlag(native.Uint32(datum.Value[0:4])) } } } @@ -1873,11 +2328,11 @@ func linkFlags(rawFlags uint32) net.Flags { } func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) if gretap.FlowBased { // In flow based mode, no other attributes need to be configured - nl.NewRtAttrChild(data, nl.IFLA_GRE_COLLECT_METADATA, boolAttr(gretap.FlowBased)) + data.AddRtAttr(nl.IFLA_GRE_COLLECT_METADATA, boolAttr(gretap.FlowBased)) return } @@ -1885,40 +2340,40 @@ func addGretapAttrs(gretap *Gretap, linkInfo *nl.RtAttr) { if ip.To4() != nil { ip = ip.To4() } - nl.NewRtAttrChild(data, nl.IFLA_GRE_LOCAL, []byte(ip)) + data.AddRtAttr(nl.IFLA_GRE_LOCAL, []byte(ip)) } if ip := gretap.Remote; ip != nil { if ip.To4() != nil { ip = ip.To4() } - nl.NewRtAttrChild(data, nl.IFLA_GRE_REMOTE, []byte(ip)) + data.AddRtAttr(nl.IFLA_GRE_REMOTE, []byte(ip)) } if gretap.IKey != 0 { - nl.NewRtAttrChild(data, nl.IFLA_GRE_IKEY, htonl(gretap.IKey)) + data.AddRtAttr(nl.IFLA_GRE_IKEY, htonl(gretap.IKey)) gretap.IFlags |= uint16(nl.GRE_KEY) } if gretap.OKey != 0 { - nl.NewRtAttrChild(data, nl.IFLA_GRE_OKEY, htonl(gretap.OKey)) + data.AddRtAttr(nl.IFLA_GRE_OKEY, htonl(gretap.OKey)) gretap.OFlags |= uint16(nl.GRE_KEY) } - nl.NewRtAttrChild(data, nl.IFLA_GRE_IFLAGS, htons(gretap.IFlags)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_OFLAGS, htons(gretap.OFlags)) + data.AddRtAttr(nl.IFLA_GRE_IFLAGS, htons(gretap.IFlags)) + data.AddRtAttr(nl.IFLA_GRE_OFLAGS, htons(gretap.OFlags)) if gretap.Link != 0 { - nl.NewRtAttrChild(data, nl.IFLA_GRE_LINK, nl.Uint32Attr(gretap.Link)) + data.AddRtAttr(nl.IFLA_GRE_LINK, nl.Uint32Attr(gretap.Link)) } - nl.NewRtAttrChild(data, nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gretap.PMtuDisc)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_TTL, nl.Uint8Attr(gretap.Ttl)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_TOS, nl.Uint8Attr(gretap.Tos)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gretap.EncapType)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gretap.EncapFlags)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_SPORT, htons(gretap.EncapSport)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_DPORT, htons(gretap.EncapDport)) + data.AddRtAttr(nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gretap.PMtuDisc)) + data.AddRtAttr(nl.IFLA_GRE_TTL, nl.Uint8Attr(gretap.Ttl)) + data.AddRtAttr(nl.IFLA_GRE_TOS, nl.Uint8Attr(gretap.Tos)) + data.AddRtAttr(nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gretap.EncapType)) + data.AddRtAttr(nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gretap.EncapFlags)) + data.AddRtAttr(nl.IFLA_GRE_ENCAP_SPORT, htons(gretap.EncapSport)) + data.AddRtAttr(nl.IFLA_GRE_ENCAP_DPORT, htons(gretap.EncapDport)) } func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) { @@ -1930,9 +2385,9 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) { case nl.IFLA_GRE_IKEY: gre.OKey = ntohl(datum.Value[0:4]) case nl.IFLA_GRE_LOCAL: - gre.Local = net.IP(datum.Value[0:16]) + gre.Local = net.IP(datum.Value) case nl.IFLA_GRE_REMOTE: - gre.Remote = net.IP(datum.Value[0:16]) + gre.Remote = net.IP(datum.Value) case nl.IFLA_GRE_ENCAP_SPORT: gre.EncapSport = ntohs(datum.Value[0:2]) case nl.IFLA_GRE_ENCAP_DPORT: @@ -1941,7 +2396,6 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) { gre.IFlags = ntohs(datum.Value[0:2]) case nl.IFLA_GRE_OFLAGS: gre.OFlags = ntohs(datum.Value[0:2]) - case nl.IFLA_GRE_TTL: gre.Ttl = uint8(datum.Value[0]) case nl.IFLA_GRE_TOS: @@ -1953,73 +2407,70 @@ func parseGretapData(link Link, data []syscall.NetlinkRouteAttr) { case nl.IFLA_GRE_ENCAP_FLAGS: gre.EncapFlags = native.Uint16(datum.Value[0:2]) case nl.IFLA_GRE_COLLECT_METADATA: - if len(datum.Value) > 0 { - gre.FlowBased = int8(datum.Value[0]) != 0 - } + gre.FlowBased = true } } } func addGretunAttrs(gre *Gretun, linkInfo *nl.RtAttr) { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) if ip := gre.Local; ip != nil { if ip.To4() != nil { ip = ip.To4() } - nl.NewRtAttrChild(data, nl.IFLA_GRE_LOCAL, []byte(ip)) + data.AddRtAttr(nl.IFLA_GRE_LOCAL, []byte(ip)) } if ip := gre.Remote; ip != nil { if ip.To4() != nil { ip = ip.To4() } - nl.NewRtAttrChild(data, nl.IFLA_GRE_REMOTE, []byte(ip)) + data.AddRtAttr(nl.IFLA_GRE_REMOTE, []byte(ip)) } if gre.IKey != 0 { - nl.NewRtAttrChild(data, nl.IFLA_GRE_IKEY, htonl(gre.IKey)) + data.AddRtAttr(nl.IFLA_GRE_IKEY, htonl(gre.IKey)) gre.IFlags |= uint16(nl.GRE_KEY) } if gre.OKey != 0 { - nl.NewRtAttrChild(data, nl.IFLA_GRE_OKEY, htonl(gre.OKey)) + data.AddRtAttr(nl.IFLA_GRE_OKEY, htonl(gre.OKey)) gre.OFlags |= uint16(nl.GRE_KEY) } - nl.NewRtAttrChild(data, nl.IFLA_GRE_IFLAGS, htons(gre.IFlags)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_OFLAGS, htons(gre.OFlags)) + data.AddRtAttr(nl.IFLA_GRE_IFLAGS, htons(gre.IFlags)) + data.AddRtAttr(nl.IFLA_GRE_OFLAGS, htons(gre.OFlags)) if gre.Link != 0 { - nl.NewRtAttrChild(data, nl.IFLA_GRE_LINK, nl.Uint32Attr(gre.Link)) + data.AddRtAttr(nl.IFLA_GRE_LINK, nl.Uint32Attr(gre.Link)) } - nl.NewRtAttrChild(data, nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gre.PMtuDisc)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_TTL, nl.Uint8Attr(gre.Ttl)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_TOS, nl.Uint8Attr(gre.Tos)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gre.EncapType)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gre.EncapFlags)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_SPORT, htons(gre.EncapSport)) - nl.NewRtAttrChild(data, nl.IFLA_GRE_ENCAP_DPORT, htons(gre.EncapDport)) + data.AddRtAttr(nl.IFLA_GRE_PMTUDISC, nl.Uint8Attr(gre.PMtuDisc)) + data.AddRtAttr(nl.IFLA_GRE_TTL, nl.Uint8Attr(gre.Ttl)) + data.AddRtAttr(nl.IFLA_GRE_TOS, nl.Uint8Attr(gre.Tos)) + data.AddRtAttr(nl.IFLA_GRE_ENCAP_TYPE, nl.Uint16Attr(gre.EncapType)) + data.AddRtAttr(nl.IFLA_GRE_ENCAP_FLAGS, nl.Uint16Attr(gre.EncapFlags)) + data.AddRtAttr(nl.IFLA_GRE_ENCAP_SPORT, htons(gre.EncapSport)) + data.AddRtAttr(nl.IFLA_GRE_ENCAP_DPORT, htons(gre.EncapDport)) } func parseGretunData(link Link, data []syscall.NetlinkRouteAttr) { gre := link.(*Gretun) for _, datum := range data { switch datum.Attr.Type { - case nl.IFLA_GRE_OKEY: - gre.IKey = ntohl(datum.Value[0:4]) case nl.IFLA_GRE_IKEY: + gre.IKey = ntohl(datum.Value[0:4]) + case nl.IFLA_GRE_OKEY: gre.OKey = ntohl(datum.Value[0:4]) case nl.IFLA_GRE_LOCAL: - gre.Local = net.IP(datum.Value[0:16]) + gre.Local = net.IP(datum.Value) case nl.IFLA_GRE_REMOTE: - gre.Remote = net.IP(datum.Value[0:16]) + gre.Remote = net.IP(datum.Value) case nl.IFLA_GRE_IFLAGS: gre.IFlags = ntohs(datum.Value[0:2]) case nl.IFLA_GRE_OFLAGS: gre.OFlags = ntohs(datum.Value[0:2]) - case nl.IFLA_GRE_TTL: gre.Ttl = uint8(datum.Value[0]) case nl.IFLA_GRE_TOS: @@ -2038,23 +2489,15 @@ func parseGretunData(link Link, data []syscall.NetlinkRouteAttr) { } } -func parseLinkStats32(data []byte) *LinkStatistics { - return (*LinkStatistics)((*LinkStatistics32)(unsafe.Pointer(&data[0:SizeofLinkStats32][0])).to64()) -} - -func parseLinkStats64(data []byte) *LinkStatistics { - return (*LinkStatistics)((*LinkStatistics64)(unsafe.Pointer(&data[0:SizeofLinkStats64][0]))) -} - func addXdpAttrs(xdp *LinkXdp, req *nl.NetlinkRequest) { attrs := nl.NewRtAttr(unix.IFLA_XDP|unix.NLA_F_NESTED, nil) b := make([]byte, 4) native.PutUint32(b, uint32(xdp.Fd)) - nl.NewRtAttrChild(attrs, nl.IFLA_XDP_FD, b) + attrs.AddRtAttr(nl.IFLA_XDP_FD, b) if xdp.Flags != 0 { b := make([]byte, 4) native.PutUint32(b, xdp.Flags) - nl.NewRtAttrChild(attrs, nl.IFLA_XDP_FLAGS, b) + attrs.AddRtAttr(nl.IFLA_XDP_FLAGS, b) } req.AddData(attrs) } @@ -2083,32 +2526,32 @@ func parseLinkXdp(data []byte) (*LinkXdp, error) { func addIptunAttrs(iptun *Iptun, linkInfo *nl.RtAttr) { if iptun.FlowBased { // In flow based mode, no other attributes need to be configured - nl.NewRtAttrChild(linkInfo, nl.IFLA_IPTUN_COLLECT_METADATA, boolAttr(iptun.FlowBased)) + linkInfo.AddRtAttr(nl.IFLA_IPTUN_COLLECT_METADATA, boolAttr(iptun.FlowBased)) return } - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) ip := iptun.Local.To4() if ip != nil { - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LOCAL, []byte(ip)) + data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip)) } ip = iptun.Remote.To4() if ip != nil { - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_REMOTE, []byte(ip)) + data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip)) } if iptun.Link != 0 { - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LINK, nl.Uint32Attr(iptun.Link)) + data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(iptun.Link)) } - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(iptun.PMtuDisc)) - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TTL, nl.Uint8Attr(iptun.Ttl)) - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TOS, nl.Uint8Attr(iptun.Tos)) - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(iptun.EncapType)) - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(iptun.EncapFlags)) - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_SPORT, htons(iptun.EncapSport)) - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_DPORT, htons(iptun.EncapDport)) + data.AddRtAttr(nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(iptun.PMtuDisc)) + data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(iptun.Ttl)) + data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(iptun.Tos)) + data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(iptun.EncapType)) + data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(iptun.EncapFlags)) + data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(iptun.EncapSport)) + data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_DPORT, htons(iptun.EncapDport)) } func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) { @@ -2139,34 +2582,83 @@ func parseIptunData(link Link, data []syscall.NetlinkRouteAttr) { } } +func addIp6tnlAttrs(ip6tnl *Ip6tnl, linkInfo *nl.RtAttr) { + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) + + if ip6tnl.Link != 0 { + data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(ip6tnl.Link)) + } + + ip := ip6tnl.Local.To16() + if ip != nil { + data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip)) + } + + ip = ip6tnl.Remote.To16() + if ip != nil { + data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip)) + } + + data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(ip6tnl.Ttl)) + data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(ip6tnl.Tos)) + data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_LIMIT, nl.Uint8Attr(ip6tnl.EncapLimit)) + data.AddRtAttr(nl.IFLA_IPTUN_FLAGS, nl.Uint32Attr(ip6tnl.Flags)) + data.AddRtAttr(nl.IFLA_IPTUN_PROTO, nl.Uint8Attr(ip6tnl.Proto)) + data.AddRtAttr(nl.IFLA_IPTUN_FLOWINFO, nl.Uint32Attr(ip6tnl.FlowInfo)) +} + +func parseIp6tnlData(link Link, data []syscall.NetlinkRouteAttr) { + ip6tnl := link.(*Ip6tnl) + for _, datum := range data { + switch datum.Attr.Type { + case nl.IFLA_IPTUN_LOCAL: + ip6tnl.Local = net.IP(datum.Value[:16]) + case nl.IFLA_IPTUN_REMOTE: + ip6tnl.Remote = net.IP(datum.Value[:16]) + case nl.IFLA_IPTUN_TTL: + ip6tnl.Ttl = uint8(datum.Value[0]) + case nl.IFLA_IPTUN_TOS: + ip6tnl.Tos = uint8(datum.Value[0]) + case nl.IFLA_IPTUN_ENCAP_LIMIT: + ip6tnl.EncapLimit = uint8(datum.Value[0]) + case nl.IFLA_IPTUN_FLAGS: + ip6tnl.Flags = native.Uint32(datum.Value[:4]) + case nl.IFLA_IPTUN_PROTO: + ip6tnl.Proto = uint8(datum.Value[0]) + case nl.IFLA_IPTUN_FLOWINFO: + ip6tnl.FlowInfo = native.Uint32(datum.Value[:4]) + } + } +} + func addSittunAttrs(sittun *Sittun, linkInfo *nl.RtAttr) { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) if sittun.Link != 0 { - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LINK, nl.Uint32Attr(sittun.Link)) + data.AddRtAttr(nl.IFLA_IPTUN_LINK, nl.Uint32Attr(sittun.Link)) } ip := sittun.Local.To4() if ip != nil { - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_LOCAL, []byte(ip)) + data.AddRtAttr(nl.IFLA_IPTUN_LOCAL, []byte(ip)) } ip = sittun.Remote.To4() if ip != nil { - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_REMOTE, []byte(ip)) + data.AddRtAttr(nl.IFLA_IPTUN_REMOTE, []byte(ip)) } if sittun.Ttl > 0 { // Would otherwise fail on 3.10 kernel - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TTL, nl.Uint8Attr(sittun.Ttl)) + data.AddRtAttr(nl.IFLA_IPTUN_TTL, nl.Uint8Attr(sittun.Ttl)) } - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_TOS, nl.Uint8Attr(sittun.Tos)) - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(sittun.PMtuDisc)) - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(sittun.EncapType)) - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(sittun.EncapFlags)) - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_SPORT, htons(sittun.EncapSport)) - nl.NewRtAttrChild(data, nl.IFLA_IPTUN_ENCAP_DPORT, htons(sittun.EncapDport)) + data.AddRtAttr(nl.IFLA_IPTUN_TOS, nl.Uint8Attr(sittun.Tos)) + data.AddRtAttr(nl.IFLA_IPTUN_PMTUDISC, nl.Uint8Attr(sittun.PMtuDisc)) + data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_TYPE, nl.Uint16Attr(sittun.EncapType)) + data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_FLAGS, nl.Uint16Attr(sittun.EncapFlags)) + data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_SPORT, htons(sittun.EncapSport)) + data.AddRtAttr(nl.IFLA_IPTUN_ENCAP_DPORT, htons(sittun.EncapDport)) } func parseSittunData(link Link, data []syscall.NetlinkRouteAttr) { @@ -2196,24 +2688,39 @@ func parseSittunData(link Link, data []syscall.NetlinkRouteAttr) { } func addVtiAttrs(vti *Vti, linkInfo *nl.RtAttr) { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) - ip := vti.Local.To4() - if ip != nil { - nl.NewRtAttrChild(data, nl.IFLA_VTI_LOCAL, []byte(ip)) + family := FAMILY_V4 + if vti.Local.To4() == nil { + family = FAMILY_V6 } - ip = vti.Remote.To4() + var ip net.IP + + if family == FAMILY_V4 { + ip = vti.Local.To4() + } else { + ip = vti.Local + } if ip != nil { - nl.NewRtAttrChild(data, nl.IFLA_VTI_REMOTE, []byte(ip)) + data.AddRtAttr(nl.IFLA_VTI_LOCAL, []byte(ip)) + } + + if family == FAMILY_V4 { + ip = vti.Remote.To4() + } else { + ip = vti.Remote + } + if ip != nil { + data.AddRtAttr(nl.IFLA_VTI_REMOTE, []byte(ip)) } if vti.Link != 0 { - nl.NewRtAttrChild(data, nl.IFLA_VTI_LINK, nl.Uint32Attr(vti.Link)) + data.AddRtAttr(nl.IFLA_VTI_LINK, nl.Uint32Attr(vti.Link)) } - nl.NewRtAttrChild(data, nl.IFLA_VTI_IKEY, htonl(vti.IKey)) - nl.NewRtAttrChild(data, nl.IFLA_VTI_OKEY, htonl(vti.OKey)) + data.AddRtAttr(nl.IFLA_VTI_IKEY, htonl(vti.IKey)) + data.AddRtAttr(nl.IFLA_VTI_OKEY, htonl(vti.OKey)) } func parseVtiData(link Link, data []syscall.NetlinkRouteAttr) { @@ -2221,9 +2728,9 @@ func parseVtiData(link Link, data []syscall.NetlinkRouteAttr) { for _, datum := range data { switch datum.Attr.Type { case nl.IFLA_VTI_LOCAL: - vti.Local = net.IP(datum.Value[0:4]) + vti.Local = net.IP(datum.Value) case nl.IFLA_VTI_REMOTE: - vti.Remote = net.IP(datum.Value[0:4]) + vti.Remote = net.IP(datum.Value) case nl.IFLA_VTI_IKEY: vti.IKey = ntohl(datum.Value[0:4]) case nl.IFLA_VTI_OKEY: @@ -2233,10 +2740,10 @@ func parseVtiData(link Link, data []syscall.NetlinkRouteAttr) { } func addVrfAttrs(vrf *Vrf, linkInfo *nl.RtAttr) { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) b := make([]byte, 4) native.PutUint32(b, uint32(vrf.Table)) - nl.NewRtAttrChild(data, nl.IFLA_VRF_TABLE, b) + data.AddRtAttr(nl.IFLA_VRF_TABLE, b) } func parseVrfData(link Link, data []syscall.NetlinkRouteAttr) { @@ -2250,12 +2757,15 @@ func parseVrfData(link Link, data []syscall.NetlinkRouteAttr) { } func addBridgeAttrs(bridge *Bridge, linkInfo *nl.RtAttr) { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) if bridge.MulticastSnooping != nil { - nl.NewRtAttrChild(data, nl.IFLA_BR_MCAST_SNOOPING, boolToByte(*bridge.MulticastSnooping)) + data.AddRtAttr(nl.IFLA_BR_MCAST_SNOOPING, boolToByte(*bridge.MulticastSnooping)) } if bridge.HelloTime != nil { - nl.NewRtAttrChild(data, nl.IFLA_BR_HELLO_TIME, nl.Uint32Attr(*bridge.HelloTime)) + data.AddRtAttr(nl.IFLA_BR_HELLO_TIME, nl.Uint32Attr(*bridge.HelloTime)) + } + if bridge.VlanFiltering != nil { + data.AddRtAttr(nl.IFLA_BR_VLAN_FILTERING, boolToByte(*bridge.VlanFiltering)) } } @@ -2269,17 +2779,20 @@ func parseBridgeData(bridge Link, data []syscall.NetlinkRouteAttr) { case nl.IFLA_BR_MCAST_SNOOPING: mcastSnooping := datum.Value[0] == 1 br.MulticastSnooping = &mcastSnooping + case nl.IFLA_BR_VLAN_FILTERING: + vlanFiltering := datum.Value[0] == 1 + br.VlanFiltering = &vlanFiltering } } } func addGTPAttrs(gtp *GTP, linkInfo *nl.RtAttr) { - data := nl.NewRtAttrChild(linkInfo, nl.IFLA_INFO_DATA, nil) - nl.NewRtAttrChild(data, nl.IFLA_GTP_FD0, nl.Uint32Attr(uint32(gtp.FD0))) - nl.NewRtAttrChild(data, nl.IFLA_GTP_FD1, nl.Uint32Attr(uint32(gtp.FD1))) - nl.NewRtAttrChild(data, nl.IFLA_GTP_PDP_HASHSIZE, nl.Uint32Attr(131072)) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) + data.AddRtAttr(nl.IFLA_GTP_FD0, nl.Uint32Attr(uint32(gtp.FD0))) + data.AddRtAttr(nl.IFLA_GTP_FD1, nl.Uint32Attr(uint32(gtp.FD1))) + data.AddRtAttr(nl.IFLA_GTP_PDP_HASHSIZE, nl.Uint32Attr(131072)) if gtp.Role != nl.GTP_ROLE_GGSN { - nl.NewRtAttrChild(data, nl.IFLA_GTP_ROLE, nl.Uint32Attr(uint32(gtp.Role))) + data.AddRtAttr(nl.IFLA_GTP_ROLE, nl.Uint32Attr(uint32(gtp.Role))) } } @@ -2299,6 +2812,70 @@ func parseGTPData(link Link, data []syscall.NetlinkRouteAttr) { } } +func parseVfInfoList(data []syscall.NetlinkRouteAttr) ([]VfInfo, error) { + var vfs []VfInfo + + for i, element := range data { + if element.Attr.Type != nl.IFLA_VF_INFO { + return nil, fmt.Errorf("Incorrect element type in vf info list: %d", element.Attr.Type) + } + vfAttrs, err := nl.ParseRouteAttr(element.Value) + if err != nil { + return nil, err + } + vfs = append(vfs, parseVfInfo(vfAttrs, i)) + } + return vfs, nil +} + +func parseVfInfo(data []syscall.NetlinkRouteAttr, id int) VfInfo { + vf := VfInfo{ID: id} + for _, element := range data { + switch element.Attr.Type { + case nl.IFLA_VF_MAC: + mac := nl.DeserializeVfMac(element.Value[:]) + vf.Mac = mac.Mac[:6] + case nl.IFLA_VF_VLAN: + vl := nl.DeserializeVfVlan(element.Value[:]) + vf.Vlan = int(vl.Vlan) + vf.Qos = int(vl.Qos) + case nl.IFLA_VF_TX_RATE: + txr := nl.DeserializeVfTxRate(element.Value[:]) + vf.TxRate = int(txr.Rate) + case nl.IFLA_VF_SPOOFCHK: + sp := nl.DeserializeVfSpoofchk(element.Value[:]) + vf.Spoofchk = sp.Setting != 0 + case nl.IFLA_VF_LINK_STATE: + ls := nl.DeserializeVfLinkState(element.Value[:]) + vf.LinkState = ls.LinkState + case nl.IFLA_VF_RATE: + vfr := nl.DeserializeVfRate(element.Value[:]) + vf.MaxTxRate = vfr.MaxTxRate + vf.MinTxRate = vfr.MinTxRate + } + } + return vf +} + +func addXfrmiAttrs(xfrmi *Xfrmi, linkInfo *nl.RtAttr) { + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) + data.AddRtAttr(nl.IFLA_XFRM_LINK, nl.Uint32Attr(uint32(xfrmi.ParentIndex))) + data.AddRtAttr(nl.IFLA_XFRM_IF_ID, nl.Uint32Attr(xfrmi.Ifid)) + +} + +func parseXfrmiData(link Link, data []syscall.NetlinkRouteAttr) { + xfrmi := link.(*Xfrmi) + for _, datum := range data { + switch datum.Attr.Type { + case nl.IFLA_XFRM_LINK: + xfrmi.ParentIndex = int(native.Uint32(datum.Value)) + case nl.IFLA_XFRM_IF_ID: + xfrmi.Ifid = native.Uint32(datum.Value) + } + } +} + // LinkSetBondSlave add slave to bond link via ioctl interface. func LinkSetBondSlave(link Link, master *Bond) error { fd, err := getSocketUDP() @@ -2316,6 +2893,52 @@ func LinkSetBondSlave(link Link, master *Bond) error { return nil } +// LinkSetBondSlaveQueueId modify bond slave queue-id. +func (h *Handle) LinkSetBondSlaveQueueId(link Link, queueId uint16) error { + base := link.Attrs() + h.ensureIndex(base) + req := h.newNetlinkRequest(unix.RTM_SETLINK, unix.NLM_F_ACK) + + msg := nl.NewIfInfomsg(unix.AF_UNSPEC) + msg.Index = int32(base.Index) + req.AddData(msg) + + linkInfo := nl.NewRtAttr(unix.IFLA_LINKINFO, nil) + data := linkInfo.AddRtAttr(nl.IFLA_INFO_SLAVE_DATA, nil) + data.AddRtAttr(nl.IFLA_BOND_SLAVE_QUEUE_ID, nl.Uint16Attr(queueId)) + + req.AddData(linkInfo) + _, err := req.Execute(unix.NETLINK_ROUTE, 0) + return err +} + +// LinkSetBondSlaveQueueId modify bond slave queue-id. +func LinkSetBondSlaveQueueId(link Link, queueId uint16) error { + return pkgHandle.LinkSetBondSlaveQueueId(link, queueId) +} + +func vethStatsSerialize(stats ethtoolStats) ([]byte, error) { + statsSize := int(unsafe.Sizeof(stats)) + int(stats.nStats)*int(unsafe.Sizeof(uint64(0))) + b := make([]byte, 0, statsSize) + buf := bytes.NewBuffer(b) + err := binary.Write(buf, nl.NativeEndian(), stats) + return buf.Bytes()[:statsSize], err +} + +type vethEthtoolStats struct { + Cmd uint32 + NStats uint32 + Peer uint64 + // Newer kernels have XDP stats in here, but we only care + // to extract the peer ifindex here. +} + +func vethStatsDeserialize(b []byte) (vethEthtoolStats, error) { + var stats = vethEthtoolStats{} + err := binary.Read(bytes.NewReader(b), nl.NativeEndian(), &stats) + return stats, err +} + // VethPeerIndex get veth peer index. func VethPeerIndex(link *Veth) (int, error) { fd, err := getSocketUDP() @@ -2330,25 +2953,66 @@ func VethPeerIndex(link *Veth) (int, error) { return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno) } - gstrings := ðtoolGstrings{ - cmd: ETHTOOL_GSTRINGS, - stringSet: ETH_SS_STATS, - length: sSet.data[0], + stats := ethtoolStats{ + cmd: ETHTOOL_GSTATS, + nStats: sSet.data[0], } - ifreq.Data = uintptr(unsafe.Pointer(gstrings)) + + buffer, err := vethStatsSerialize(stats) + if err != nil { + return -1, err + } + + ifreq.Data = uintptr(unsafe.Pointer(&buffer[0])) _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq))) if errno != 0 { return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno) } - stats := ðtoolStats{ - cmd: ETHTOOL_GSTATS, - nStats: gstrings.length, + vstats, err := vethStatsDeserialize(buffer) + if err != nil { + return -1, err } - ifreq.Data = uintptr(unsafe.Pointer(stats)) - _, _, errno = syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), SIOCETHTOOL, uintptr(unsafe.Pointer(ifreq))) - if errno != 0 { - return -1, fmt.Errorf("SIOCETHTOOL request for %q failed, errno=%v", link.Attrs().Name, errno) + + return int(vstats.Peer), nil +} + +func parseTuntapData(link Link, data []syscall.NetlinkRouteAttr) { + tuntap := link.(*Tuntap) + for _, datum := range data { + switch datum.Attr.Type { + case nl.IFLA_TUN_OWNER: + tuntap.Owner = native.Uint32(datum.Value) + case nl.IFLA_TUN_GROUP: + tuntap.Group = native.Uint32(datum.Value) + case nl.IFLA_TUN_TYPE: + tuntap.Mode = TuntapMode(uint8(datum.Value[0])) + case nl.IFLA_TUN_PERSIST: + tuntap.NonPersist = false + if uint8(datum.Value[0]) == 0 { + tuntap.NonPersist = true + } + } } - return int(stats.data[0]), nil +} + +func parseIPoIBData(link Link, data []syscall.NetlinkRouteAttr) { + ipoib := link.(*IPoIB) + for _, datum := range data { + switch datum.Attr.Type { + case nl.IFLA_IPOIB_PKEY: + ipoib.Pkey = uint16(native.Uint16(datum.Value)) + case nl.IFLA_IPOIB_MODE: + ipoib.Mode = IPoIBMode(native.Uint16(datum.Value)) + case nl.IFLA_IPOIB_UMCAST: + ipoib.Umcast = uint16(native.Uint16(datum.Value)) + } + } +} + +func addIPoIBAttrs(ipoib *IPoIB, linkInfo *nl.RtAttr) { + data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil) + data.AddRtAttr(nl.IFLA_IPOIB_PKEY, nl.Uint16Attr(uint16(ipoib.Pkey))) + data.AddRtAttr(nl.IFLA_IPOIB_MODE, nl.Uint16Attr(uint16(ipoib.Mode))) + data.AddRtAttr(nl.IFLA_IPOIB_UMCAST, nl.Uint16Attr(uint16(ipoib.Umcast))) } diff --git a/vendor/github.com/vishvananda/netlink/neigh.go b/vendor/github.com/vishvananda/netlink/neigh.go index 3f5cd497a7..379e5655f7 100644 --- a/vendor/github.com/vishvananda/netlink/neigh.go +++ b/vendor/github.com/vishvananda/netlink/neigh.go @@ -17,9 +17,16 @@ type Neigh struct { LLIPAddr net.IP //Used in the case of NHRP Vlan int VNI int + MasterIndex int } // String returns $ip/$hwaddr $label func (neigh *Neigh) String() string { return fmt.Sprintf("%s %s", neigh.IP, neigh.HardwareAddr) } + +// NeighUpdate is sent when a neighbor changes - type is RTM_NEWNEIGH or RTM_DELNEIGH. +type NeighUpdate struct { + Type uint16 + Neigh +} diff --git a/vendor/github.com/vishvananda/netlink/neigh_linux.go b/vendor/github.com/vishvananda/netlink/neigh_linux.go index f75c22649f..cb3b55d350 100644 --- a/vendor/github.com/vishvananda/netlink/neigh_linux.go +++ b/vendor/github.com/vishvananda/netlink/neigh_linux.go @@ -1,10 +1,13 @@ package netlink import ( + "fmt" "net" + "syscall" "unsafe" "github.com/vishvananda/netlink/nl" + "github.com/vishvananda/netns" "golang.org/x/sys/unix" ) @@ -18,7 +21,10 @@ const ( NDA_PORT NDA_VNI NDA_IFINDEX - NDA_MAX = NDA_IFINDEX + NDA_MASTER + NDA_LINK_NETNSID + NDA_SRC_VNI + NDA_MAX = NDA_SRC_VNI ) // Neighbor Cache Entry States. @@ -43,6 +49,7 @@ const ( NTF_ROUTER = 0x80 ) +// Ndmsg is for adding, removing or receiving information about a neighbor table entry type Ndmsg struct { Family uint8 Index uint32 @@ -170,45 +177,58 @@ func neighHandle(neigh *Neigh, req *nl.NetlinkRequest) error { req.AddData(vniData) } + if neigh.MasterIndex != 0 { + masterData := nl.NewRtAttr(NDA_MASTER, nl.Uint32Attr(uint32(neigh.MasterIndex))) + req.AddData(masterData) + } + _, err := req.Execute(unix.NETLINK_ROUTE, 0) return err } -// NeighList gets a list of IP-MAC mappings in the system (ARP table). +// NeighList returns a list of IP-MAC mappings in the system (ARP table). // Equivalent to: `ip neighbor show`. // The list can be filtered by link and ip family. func NeighList(linkIndex, family int) ([]Neigh, error) { return pkgHandle.NeighList(linkIndex, family) } -// NeighProxyList gets a list of neighbor proxies in the system. +// NeighProxyList returns a list of neighbor proxies in the system. // Equivalent to: `ip neighbor show proxy`. // The list can be filtered by link and ip family. func NeighProxyList(linkIndex, family int) ([]Neigh, error) { return pkgHandle.NeighProxyList(linkIndex, family) } -// NeighList gets a list of IP-MAC mappings in the system (ARP table). +// NeighList returns a list of IP-MAC mappings in the system (ARP table). // Equivalent to: `ip neighbor show`. // The list can be filtered by link and ip family. func (h *Handle) NeighList(linkIndex, family int) ([]Neigh, error) { - return h.neighList(linkIndex, family, 0) + return h.NeighListExecute(Ndmsg{ + Family: uint8(family), + Index: uint32(linkIndex), + }) } -// NeighProxyList gets a list of neighbor proxies in the system. +// NeighProxyList returns a list of neighbor proxies in the system. // Equivalent to: `ip neighbor show proxy`. // The list can be filtered by link, ip family. func (h *Handle) NeighProxyList(linkIndex, family int) ([]Neigh, error) { - return h.neighList(linkIndex, family, NTF_PROXY) -} - -func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) { - req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP) - msg := Ndmsg{ + return h.NeighListExecute(Ndmsg{ Family: uint8(family), Index: uint32(linkIndex), - Flags: uint8(flags), - } + Flags: NTF_PROXY, + }) +} + +// NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state. +func NeighListExecute(msg Ndmsg) ([]Neigh, error) { + return pkgHandle.NeighListExecute(msg) +} + +// NeighListExecute returns a list of neighbour entries filtered by link, ip family, flag and state. +func (h *Handle) NeighListExecute(msg Ndmsg) ([]Neigh, error) { + req := h.newNetlinkRequest(unix.RTM_GETNEIGH, unix.NLM_F_DUMP) req.AddData(&msg) msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNEIGH) @@ -219,7 +239,7 @@ func (h *Handle) neighList(linkIndex, family, flags int) ([]Neigh, error) { var res []Neigh for _, m := range msgs { ndm := deserializeNdmsg(m) - if linkIndex != 0 && int(ndm.Index) != linkIndex { + if msg.Index != 0 && ndm.Index != msg.Index { // Ignore messages from other interfaces continue } @@ -251,14 +271,6 @@ func NeighDeserialize(m []byte) (*Neigh, error) { return nil, err } - // This should be cached for perfomance - // once per table dump - link, err := LinkByIndex(neigh.LinkIndex) - if err != nil { - return nil, err - } - encapType := link.Attrs().EncapType - for _, attr := range attrs { switch attr.Attr.Type { case NDA_DST: @@ -268,13 +280,16 @@ func NeighDeserialize(m []byte) (*Neigh, error) { // #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len)) // #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0)) attrLen := attr.Attr.Len - unix.SizeofRtAttr - if attrLen == 4 && (encapType == "ipip" || - encapType == "sit" || - encapType == "gre") { + if attrLen == 4 { neigh.LLIPAddr = net.IP(attr.Value) - } else if attrLen == 16 && - encapType == "tunnel6" { - neigh.IP = net.IP(attr.Value) + } else if attrLen == 16 { + // Can be IPv6 or FireWire HWAddr + link, err := LinkByIndex(neigh.LinkIndex) + if err == nil && link.Attrs().EncapType == "tunnel6" { + neigh.IP = net.IP(attr.Value) + } else { + neigh.HardwareAddr = net.HardwareAddr(attr.Value) + } } else { neigh.HardwareAddr = net.HardwareAddr(attr.Value) } @@ -282,8 +297,126 @@ func NeighDeserialize(m []byte) (*Neigh, error) { neigh.Vlan = int(native.Uint16(attr.Value[0:2])) case NDA_VNI: neigh.VNI = int(native.Uint32(attr.Value[0:4])) + case NDA_MASTER: + neigh.MasterIndex = int(native.Uint32(attr.Value[0:4])) } } return &neigh, nil } + +// NeighSubscribe takes a chan down which notifications will be sent +// when neighbors are added or deleted. Close the 'done' chan to stop subscription. +func NeighSubscribe(ch chan<- NeighUpdate, done <-chan struct{}) error { + return neighSubscribeAt(netns.None(), netns.None(), ch, done, nil, false) +} + +// NeighSubscribeAt works like NeighSubscribe plus it allows the caller +// to choose the network namespace in which to subscribe (ns). +func NeighSubscribeAt(ns netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}) error { + return neighSubscribeAt(ns, netns.None(), ch, done, nil, false) +} + +// NeighSubscribeOptions contains a set of options to use with +// NeighSubscribeWithOptions. +type NeighSubscribeOptions struct { + Namespace *netns.NsHandle + ErrorCallback func(error) + ListExisting bool +} + +// NeighSubscribeWithOptions work like NeighSubscribe but enable to +// provide additional options to modify the behavior. Currently, the +// namespace can be provided as well as an error callback. +func NeighSubscribeWithOptions(ch chan<- NeighUpdate, done <-chan struct{}, options NeighSubscribeOptions) error { + if options.Namespace == nil { + none := netns.None() + options.Namespace = &none + } + return neighSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting) +} + +func neighSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- NeighUpdate, done <-chan struct{}, cberr func(error), listExisting bool) error { + s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_NEIGH) + makeRequest := func(family int) error { + req := pkgHandle.newNetlinkRequest(unix.RTM_GETNEIGH, + unix.NLM_F_DUMP) + infmsg := nl.NewIfInfomsg(family) + req.AddData(infmsg) + if err := s.Send(req); err != nil { + return err + } + return nil + } + if err != nil { + return err + } + if done != nil { + go func() { + <-done + s.Close() + }() + } + if listExisting { + if err := makeRequest(unix.AF_UNSPEC); err != nil { + return err + } + // We have to wait for NLMSG_DONE before making AF_BRIDGE request + } + go func() { + defer close(ch) + for { + msgs, from, err := s.Receive() + if err != nil { + if cberr != nil { + cberr(err) + } + return + } + if from.Pid != nl.PidKernel { + if cberr != nil { + cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)) + } + continue + } + for _, m := range msgs { + if m.Header.Type == unix.NLMSG_DONE { + if listExisting { + // This will be called after handling AF_UNSPEC + // list request, we have to wait for NLMSG_DONE + // before making another request + if err := makeRequest(unix.AF_BRIDGE); err != nil { + if cberr != nil { + cberr(err) + } + return + } + listExisting = false + } + continue + } + if m.Header.Type == unix.NLMSG_ERROR { + native := nl.NativeEndian() + error := int32(native.Uint32(m.Data[0:4])) + if error == 0 { + continue + } + if cberr != nil { + cberr(syscall.Errno(-error)) + } + return + } + neigh, err := NeighDeserialize(m.Data) + if err != nil { + if cberr != nil { + cberr(err) + } + return + } + ch <- NeighUpdate{Type: m.Header.Type, Neigh: *neigh} + } + } + }() + + return nil +} diff --git a/vendor/github.com/vishvananda/netlink/netlink.go b/vendor/github.com/vishvananda/netlink/netlink.go index fb159526e3..9cb685dc81 100644 --- a/vendor/github.com/vishvananda/netlink/netlink.go +++ b/vendor/github.com/vishvananda/netlink/netlink.go @@ -27,7 +27,8 @@ func ParseIPNet(s string) (*net.IPNet, error) { if err != nil { return nil, err } - return &net.IPNet{IP: ip, Mask: ipNet.Mask}, nil + ipNet.IP = ip + return ipNet, nil } // NewIPNet generates an IPNet from an ip address using a netmask of 32 or 128. diff --git a/vendor/github.com/vishvananda/netlink/netlink_unspecified.go b/vendor/github.com/vishvananda/netlink/netlink_unspecified.go index 86111b92ce..42d3acf918 100644 --- a/vendor/github.com/vishvananda/netlink/netlink_unspecified.go +++ b/vendor/github.com/vishvananda/netlink/netlink_unspecified.go @@ -48,10 +48,18 @@ func LinkSetVfVlan(link Link, vf, vlan int) error { return ErrNotImplemented } +func LinkSetVfVlanQos(link Link, vf, vlan, qos int) error { + return ErrNotImplemented +} + func LinkSetVfTxRate(link Link, vf, rate int) error { return ErrNotImplemented } +func LinkSetVfRate(link Link, vf, minRate, maxRate int) error { + return ErrNotImplemented +} + func LinkSetNoMaster(link Link) error { return ErrNotImplemented } @@ -152,6 +160,10 @@ func AddrAdd(link Link, addr *Addr) error { return ErrNotImplemented } +func AddrReplace(link Link, addr *Addr) error { + return ErrNotImplemented +} + func AddrDel(link Link, addr *Addr) error { return ErrNotImplemented } diff --git a/vendor/github.com/vishvananda/netlink/netns_linux.go b/vendor/github.com/vishvananda/netlink/netns_linux.go new file mode 100644 index 0000000000..77cf6f4690 --- /dev/null +++ b/vendor/github.com/vishvananda/netlink/netns_linux.go @@ -0,0 +1,141 @@ +package netlink + +// Network namespace ID functions +// +// The kernel has a weird concept called the network namespace ID. +// This is different from the file reference in proc (and any bind-mounted +// namespaces, etc.) +// +// Instead, namespaces can be assigned a numeric ID at any time. Once set, +// the ID is fixed. The ID can either be set manually by the user, or +// automatically, triggered by certain kernel actions. The most common kernel +// action that triggers namespace ID creation is moving one end of a veth pair +// in to that namespace. + +import ( + "fmt" + + "github.com/vishvananda/netlink/nl" + "golang.org/x/sys/unix" +) + +// These can be replaced by the values from sys/unix when it is next released. +const ( + _ = iota + NETNSA_NSID + NETNSA_PID + NETNSA_FD +) + +// GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id). +// Returns -1 if the namespace does not have an ID set. +func (h *Handle) GetNetNsIdByPid(pid int) (int, error) { + return h.getNetNsId(NETNSA_PID, uint32(pid)) +} + +// GetNetNsIdByPid looks up the network namespace ID for a given pid (really thread id). +// Returns -1 if the namespace does not have an ID set. +func GetNetNsIdByPid(pid int) (int, error) { + return pkgHandle.GetNetNsIdByPid(pid) +} + +// SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id). +// The ID can only be set for namespaces without an ID already set. +func (h *Handle) SetNetNsIdByPid(pid, nsid int) error { + return h.setNetNsId(NETNSA_PID, uint32(pid), uint32(nsid)) +} + +// SetNetNSIdByPid sets the ID of the network namespace for a given pid (really thread id). +// The ID can only be set for namespaces without an ID already set. +func SetNetNsIdByPid(pid, nsid int) error { + return pkgHandle.SetNetNsIdByPid(pid, nsid) +} + +// GetNetNsIdByFd looks up the network namespace ID for a given fd. +// fd must be an open file descriptor to a namespace file. +// Returns -1 if the namespace does not have an ID set. +func (h *Handle) GetNetNsIdByFd(fd int) (int, error) { + return h.getNetNsId(NETNSA_FD, uint32(fd)) +} + +// GetNetNsIdByFd looks up the network namespace ID for a given fd. +// fd must be an open file descriptor to a namespace file. +// Returns -1 if the namespace does not have an ID set. +func GetNetNsIdByFd(fd int) (int, error) { + return pkgHandle.GetNetNsIdByFd(fd) +} + +// SetNetNSIdByFd sets the ID of the network namespace for a given fd. +// fd must be an open file descriptor to a namespace file. +// The ID can only be set for namespaces without an ID already set. +func (h *Handle) SetNetNsIdByFd(fd, nsid int) error { + return h.setNetNsId(NETNSA_FD, uint32(fd), uint32(nsid)) +} + +// SetNetNSIdByFd sets the ID of the network namespace for a given fd. +// fd must be an open file descriptor to a namespace file. +// The ID can only be set for namespaces without an ID already set. +func SetNetNsIdByFd(fd, nsid int) error { + return pkgHandle.SetNetNsIdByFd(fd, nsid) +} + +// getNetNsId requests the netnsid for a given type-val pair +// type should be either NETNSA_PID or NETNSA_FD +func (h *Handle) getNetNsId(attrType int, val uint32) (int, error) { + req := h.newNetlinkRequest(unix.RTM_GETNSID, unix.NLM_F_REQUEST) + + rtgen := nl.NewRtGenMsg() + req.AddData(rtgen) + + b := make([]byte, 4, 4) + native.PutUint32(b, val) + attr := nl.NewRtAttr(attrType, b) + req.AddData(attr) + + msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID) + + if err != nil { + return 0, err + } + + for _, m := range msgs { + msg := nl.DeserializeRtGenMsg(m) + + attrs, err := nl.ParseRouteAttr(m[msg.Len():]) + if err != nil { + return 0, err + } + + for _, attr := range attrs { + switch attr.Attr.Type { + case NETNSA_NSID: + return int(int32(native.Uint32(attr.Value))), nil + } + } + } + + return 0, fmt.Errorf("unexpected empty result") +} + +// setNetNsId sets the netnsid for a given type-val pair +// type should be either NETNSA_PID or NETNSA_FD +// The ID can only be set for namespaces without an ID already set +func (h *Handle) setNetNsId(attrType int, val uint32, newnsid uint32) error { + req := h.newNetlinkRequest(unix.RTM_NEWNSID, unix.NLM_F_REQUEST|unix.NLM_F_ACK) + + rtgen := nl.NewRtGenMsg() + req.AddData(rtgen) + + b := make([]byte, 4, 4) + native.PutUint32(b, val) + attr := nl.NewRtAttr(attrType, b) + req.AddData(attr) + + b1 := make([]byte, 4, 4) + native.PutUint32(b1, newnsid) + attr1 := nl.NewRtAttr(NETNSA_NSID, b1) + req.AddData(attr1) + + _, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWNSID) + return err +} diff --git a/vendor/github.com/vishvananda/netlink/netns_unspecified.go b/vendor/github.com/vishvananda/netlink/netns_unspecified.go new file mode 100644 index 0000000000..5c5899e362 --- /dev/null +++ b/vendor/github.com/vishvananda/netlink/netns_unspecified.go @@ -0,0 +1,19 @@ +// +build !linux + +package netlink + +func GetNetNsIdByPid(pid int) (int, error) { + return 0, ErrNotImplemented +} + +func SetNetNsIdByPid(pid, nsid int) error { + return ErrNotImplemented +} + +func GetNetNsIdByFd(fd int) (int, error) { + return 0, ErrNotImplemented +} + +func SetNetNsIdByFd(fd, nsid int) error { + return ErrNotImplemented +} diff --git a/vendor/github.com/vishvananda/netlink/nl/bridge_linux.go b/vendor/github.com/vishvananda/netlink/nl/bridge_linux.go index 6c0d333387..34e78ba8da 100644 --- a/vendor/github.com/vishvananda/netlink/nl/bridge_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/bridge_linux.go @@ -11,8 +11,8 @@ const ( /* Bridge Flags */ const ( - BRIDGE_FLAGS_MASTER = iota /* Bridge command to/from master */ - BRIDGE_FLAGS_SELF /* Bridge command to/from lowerdev */ + BRIDGE_FLAGS_MASTER = iota + 1 /* Bridge command to/from master */ + BRIDGE_FLAGS_SELF /* Bridge command to/from lowerdev */ ) /* Bridge management nested attributes diff --git a/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go b/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go index 380cc5967b..79d2b6b890 100644 --- a/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/conntrack_linux.go @@ -76,12 +76,17 @@ const ( // __CTA_MAX // }; const ( - CTA_TUPLE_ORIG = 1 - CTA_TUPLE_REPLY = 2 - CTA_STATUS = 3 - CTA_TIMEOUT = 7 - CTA_MARK = 8 - CTA_PROTOINFO = 4 + CTA_TUPLE_ORIG = 1 + CTA_TUPLE_REPLY = 2 + CTA_STATUS = 3 + CTA_PROTOINFO = 4 + CTA_TIMEOUT = 7 + CTA_MARK = 8 + CTA_COUNTERS_ORIG = 9 + CTA_COUNTERS_REPLY = 10 + CTA_USE = 11 + CTA_ID = 12 + CTA_TIMESTAMP = 20 ) // enum ctattr_tuple { @@ -163,6 +168,29 @@ const ( CTA_PROTOINFO_TCP_FLAGS_REPLY = 5 ) +// enum ctattr_counters { +// CTA_COUNTERS_UNSPEC, +// CTA_COUNTERS_PACKETS, /* 64bit counters */ +// CTA_COUNTERS_BYTES, /* 64bit counters */ +// CTA_COUNTERS32_PACKETS, /* old 32bit counters, unused */ +// CTA_COUNTERS32_BYTES, /* old 32bit counters, unused */ +// CTA_COUNTERS_PAD, +// __CTA_COUNTERS_M +// }; +// #define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1) +const ( + CTA_COUNTERS_PACKETS = 1 + CTA_COUNTERS_BYTES = 2 +) + +// enum CTA TIMESTAMP TLVs +// CTA_TIMESTAMP_START /* 64bit value */ +// CTA_TIMESTAMP_STOP /* 64bit value */ +const ( + CTA_TIMESTAMP_START = 1 + CTA_TIMESTAMP_STOP = 2 +) + // /* General form of address family dependent message. // */ // struct nfgenmsg { diff --git a/vendor/github.com/vishvananda/netlink/nl/devlink_linux.go b/vendor/github.com/vishvananda/netlink/nl/devlink_linux.go new file mode 100644 index 0000000000..db66faaad3 --- /dev/null +++ b/vendor/github.com/vishvananda/netlink/nl/devlink_linux.go @@ -0,0 +1,40 @@ +package nl + +// All the following constants are coming from: +// https://github.com/torvalds/linux/blob/master/include/uapi/linux/devlink.h + +const ( + GENL_DEVLINK_VERSION = 1 + GENL_DEVLINK_NAME = "devlink" +) + +const ( + DEVLINK_CMD_GET = 1 + DEVLINK_CMD_ESWITCH_GET = 29 + DEVLINK_CMD_ESWITCH_SET = 30 +) + +const ( + DEVLINK_ATTR_BUS_NAME = 1 + DEVLINK_ATTR_DEV_NAME = 2 + DEVLINK_ATTR_ESWITCH_MODE = 25 + DEVLINK_ATTR_ESWITCH_INLINE_MODE = 26 + DEVLINK_ATTR_ESWITCH_ENCAP_MODE = 62 +) + +const ( + DEVLINK_ESWITCH_MODE_LEGACY = 0 + DEVLINK_ESWITCH_MODE_SWITCHDEV = 1 +) + +const ( + DEVLINK_ESWITCH_INLINE_MODE_NONE = 0 + DEVLINK_ESWITCH_INLINE_MODE_LINK = 1 + DEVLINK_ESWITCH_INLINE_MODE_NETWORK = 2 + DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT = 3 +) + +const ( + DEVLINK_ESWITCH_ENCAP_MODE_NONE = 0 + DEVLINK_ESWITCH_ENCAP_MODE_BASIC = 1 +) diff --git a/vendor/github.com/vishvananda/netlink/nl/link_linux.go b/vendor/github.com/vishvananda/netlink/nl/link_linux.go index 84a3498dd3..afb16a9c18 100644 --- a/vendor/github.com/vishvananda/netlink/nl/link_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/link_linux.go @@ -13,7 +13,9 @@ const ( IFLA_INFO_KIND IFLA_INFO_DATA IFLA_INFO_XSTATS - IFLA_INFO_MAX = IFLA_INFO_XSTATS + IFLA_INFO_SLAVE_KIND + IFLA_INFO_SLAVE_DATA + IFLA_INFO_MAX = IFLA_INFO_SLAVE_DATA ) const ( @@ -87,7 +89,8 @@ const ( const ( IFLA_IPVLAN_UNSPEC = iota IFLA_IPVLAN_MODE - IFLA_IPVLAN_MAX = IFLA_IPVLAN_MODE + IFLA_IPVLAN_FLAG + IFLA_IPVLAN_MAX = IFLA_IPVLAN_FLAG ) const ( @@ -164,6 +167,8 @@ const ( IFLA_BOND_SLAVE_PERM_HWADDR IFLA_BOND_SLAVE_QUEUE_ID IFLA_BOND_SLAVE_AD_AGGREGATOR_ID + IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE ) const ( @@ -217,9 +222,11 @@ const ( IFLA_VF_RSS_QUERY_EN /* RSS Redirection Table and Hash Key query * on/off switch */ - IFLA_VF_STATS /* network device statistics */ - IFLA_VF_TRUST /* Trust state of VF */ - IFLA_VF_MAX = IFLA_VF_TRUST + IFLA_VF_STATS /* network device statistics */ + IFLA_VF_TRUST /* Trust state of VF */ + IFLA_VF_IB_NODE_GUID /* VF Infiniband node GUID */ + IFLA_VF_IB_PORT_GUID /* VF Infiniband port GUID */ + IFLA_VF_MAX = IFLA_VF_IB_PORT_GUID ) const ( @@ -248,6 +255,7 @@ const ( SizeofVfLinkState = 0x08 SizeofVfRssQueryEn = 0x08 SizeofVfTrust = 0x08 + SizeofVfGUID = 0x10 ) // struct ifla_vf_mac { @@ -430,6 +438,30 @@ func (msg *VfTrust) Serialize() []byte { return (*(*[SizeofVfTrust]byte)(unsafe.Pointer(msg)))[:] } +// struct ifla_vf_guid { +// __u32 vf; +// __u32 rsvd; +// __u64 guid; +// }; + +type VfGUID struct { + Vf uint32 + Rsvd uint32 + GUID uint64 +} + +func (msg *VfGUID) Len() int { + return SizeofVfGUID +} + +func DeserializeVfGUID(b []byte) *VfGUID { + return (*VfGUID)(unsafe.Pointer(&b[0:SizeofVfGUID][0])) +} + +func (msg *VfGUID) Serialize() []byte { + return (*(*[SizeofVfGUID]byte)(unsafe.Pointer(msg)))[:] +} + const ( XDP_FLAGS_UPDATE_IF_NOEXIST = 1 << iota XDP_FLAGS_SKB_MODE @@ -546,3 +578,33 @@ const ( GTP_ROLE_GGSN = iota GTP_ROLE_SGSN ) + +const ( + IFLA_XFRM_UNSPEC = iota + IFLA_XFRM_LINK + IFLA_XFRM_IF_ID + + IFLA_XFRM_MAX = iota - 1 +) + +const ( + IFLA_TUN_UNSPEC = iota + IFLA_TUN_OWNER + IFLA_TUN_GROUP + IFLA_TUN_TYPE + IFLA_TUN_PI + IFLA_TUN_VNET_HDR + IFLA_TUN_PERSIST + IFLA_TUN_MULTI_QUEUE + IFLA_TUN_NUM_QUEUES + IFLA_TUN_NUM_DISABLED_QUEUES + IFLA_TUN_MAX = IFLA_TUN_NUM_DISABLED_QUEUES +) + +const ( + IFLA_IPOIB_UNSPEC = iota + IFLA_IPOIB_PKEY + IFLA_IPOIB_MODE + IFLA_IPOIB_UMCAST + IFLA_IPOIB_MAX = IFLA_IPOIB_UMCAST +) diff --git a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go index bc8e82c2cc..aaf56c6715 100644 --- a/vendor/github.com/vishvananda/netlink/nl/nl_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/nl_linux.go @@ -21,7 +21,13 @@ const ( FAMILY_ALL = unix.AF_UNSPEC FAMILY_V4 = unix.AF_INET FAMILY_V6 = unix.AF_INET6 - FAMILY_MPLS = AF_MPLS + FAMILY_MPLS = unix.AF_MPLS + // Arbitrary set value (greater than default 4k) to allow receiving + // from kernel more verbose messages e.g. for statistics, + // tc rules or filters, or other more memory requiring data. + RECEIVE_BUFFER_SIZE = 65536 + // Kernel netlink pid + PidKernel uint32 = 0 ) // SupportedNlFamilies contains the list of netlink families this netlink package supports @@ -42,7 +48,7 @@ func GetIPFamily(ip net.IP) int { var nativeEndian binary.ByteOrder -// Get native endianness for the system +// NativeEndian gets native endianness for the system func NativeEndian() binary.ByteOrder { if nativeEndian == nil { var x uint32 = 0x01020304 @@ -271,15 +277,22 @@ func NewRtAttr(attrType int, data []byte) *RtAttr { } } -// Create a new RtAttr obj anc add it as a child of an existing object +// NewRtAttrChild adds an RtAttr as a child to the parent and returns the new attribute +// +// Deprecated: Use AddRtAttr() on the parent object func NewRtAttrChild(parent *RtAttr, attrType int, data []byte) *RtAttr { + return parent.AddRtAttr(attrType, data) +} + +// AddRtAttr adds an RtAttr as a child and returns the new attribute +func (a *RtAttr) AddRtAttr(attrType int, data []byte) *RtAttr { attr := NewRtAttr(attrType, data) - parent.children = append(parent.children, attr) + a.children = append(a.children, attr) return attr } -// AddChild adds an existing RtAttr as a child. -func (a *RtAttr) AddChild(attr *RtAttr) { +// AddChild adds an existing NetlinkRequestData as a child. +func (a *RtAttr) AddChild(attr NetlinkRequestData) { a.children = append(a.children, attr) } @@ -360,16 +373,12 @@ func (req *NetlinkRequest) Serialize() []byte { } func (req *NetlinkRequest) AddData(data NetlinkRequestData) { - if data != nil { - req.Data = append(req.Data, data) - } + req.Data = append(req.Data, data) } // AddRawData adds raw bytes to the end of the NetlinkRequest object during serialization func (req *NetlinkRequest) AddRawData(data []byte) { - if data != nil { - req.RawData = append(req.RawData, data...) - } + req.RawData = append(req.RawData, data...) } // Execute the request against a the given sockType. @@ -413,10 +422,13 @@ func (req *NetlinkRequest) Execute(sockType int, resType uint16) ([][]byte, erro done: for { - msgs, err := s.Receive() + msgs, from, err := s.Receive() if err != nil { return nil, err } + if from.Pid != PidKernel { + return nil, fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, PidKernel) + } for _, m := range msgs { if m.Header.Seq != req.Seq { if sharedSocket { @@ -425,7 +437,7 @@ done: return nil, fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, req.Seq) } if m.Header.Pid != pid { - return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid) + continue } if m.Header.Type == unix.NLMSG_DONE { break done @@ -610,21 +622,31 @@ func (s *NetlinkSocket) Send(request *NetlinkRequest) error { return nil } -func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, error) { +func (s *NetlinkSocket) Receive() ([]syscall.NetlinkMessage, *unix.SockaddrNetlink, error) { fd := int(atomic.LoadInt32(&s.fd)) if fd < 0 { - return nil, fmt.Errorf("Receive called on a closed socket") + return nil, nil, fmt.Errorf("Receive called on a closed socket") } - rb := make([]byte, unix.Getpagesize()) - nr, _, err := unix.Recvfrom(fd, rb, 0) + var fromAddr *unix.SockaddrNetlink + var rb [RECEIVE_BUFFER_SIZE]byte + nr, from, err := unix.Recvfrom(fd, rb[:], 0) if err != nil { - return nil, err + return nil, nil, err + } + fromAddr, ok := from.(*unix.SockaddrNetlink) + if !ok { + return nil, nil, fmt.Errorf("Error converting to netlink sockaddr") } if nr < unix.NLMSG_HDRLEN { - return nil, fmt.Errorf("Got short response from netlink") + return nil, nil, fmt.Errorf("Got short response from netlink") } - rb = rb[:nr] - return syscall.ParseNetlinkMessage(rb) + rb2 := make([]byte, nr) + copy(rb2, rb[:nr]) + nl, err := syscall.ParseNetlinkMessage(rb2) + if err != nil { + return nil, nil, err + } + return nl, fromAddr, nil } // SetSendTimeout allows to set a send timeout on the socket diff --git a/vendor/github.com/vishvananda/netlink/nl/rdma_link_linux.go b/vendor/github.com/vishvananda/netlink/nl/rdma_link_linux.go new file mode 100644 index 0000000000..1224b747de --- /dev/null +++ b/vendor/github.com/vishvananda/netlink/nl/rdma_link_linux.go @@ -0,0 +1,35 @@ +package nl + +const ( + RDMA_NL_GET_CLIENT_SHIFT = 10 +) + +const ( + RDMA_NL_NLDEV = 5 +) + +const ( + RDMA_NLDEV_CMD_GET = 1 + RDMA_NLDEV_CMD_SET = 2 + RDMA_NLDEV_CMD_SYS_GET = 6 + RDMA_NLDEV_CMD_SYS_SET = 7 +) + +const ( + RDMA_NLDEV_ATTR_DEV_INDEX = 1 + RDMA_NLDEV_ATTR_DEV_NAME = 2 + RDMA_NLDEV_ATTR_PORT_INDEX = 3 + RDMA_NLDEV_ATTR_CAP_FLAGS = 4 + RDMA_NLDEV_ATTR_FW_VERSION = 5 + RDMA_NLDEV_ATTR_NODE_GUID = 6 + RDMA_NLDEV_ATTR_SYS_IMAGE_GUID = 7 + RDMA_NLDEV_ATTR_SUBNET_PREFIX = 8 + RDMA_NLDEV_ATTR_LID = 9 + RDMA_NLDEV_ATTR_SM_LID = 10 + RDMA_NLDEV_ATTR_LMC = 11 + RDMA_NLDEV_ATTR_PORT_STATE = 12 + RDMA_NLDEV_ATTR_PORT_PHYS_STATE = 13 + RDMA_NLDEV_ATTR_DEV_NODE_TYPE = 14 + RDMA_NLDEV_SYS_ATTR_NETNS_MODE = 66 + RDMA_NLDEV_NET_NS_FD = 68 +) diff --git a/vendor/github.com/vishvananda/netlink/nl/route_linux.go b/vendor/github.com/vishvananda/netlink/nl/route_linux.go index f6906fcaf7..03c1900ffa 100644 --- a/vendor/github.com/vishvananda/netlink/nl/route_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/route_linux.go @@ -79,3 +79,29 @@ func (msg *RtNexthop) Serialize() []byte { } return buf } + +type RtGenMsg struct { + unix.RtGenmsg +} + +func NewRtGenMsg() *RtGenMsg { + return &RtGenMsg{ + RtGenmsg: unix.RtGenmsg{ + Family: unix.AF_UNSPEC, + }, + } +} + +func (msg *RtGenMsg) Len() int { + return rtaAlignOf(unix.SizeofRtGenmsg) +} + +func DeserializeRtGenMsg(b []byte) *RtGenMsg { + return &RtGenMsg{RtGenmsg: unix.RtGenmsg{Family: b[0]}} +} + +func (msg *RtGenMsg) Serialize() []byte { + out := make([]byte, msg.Len()) + out[0] = msg.Family + return out +} diff --git a/vendor/github.com/vishvananda/netlink/nl/seg6_linux.go b/vendor/github.com/vishvananda/netlink/nl/seg6_linux.go index b3425f6b0e..5774cbb15a 100644 --- a/vendor/github.com/vishvananda/netlink/nl/seg6_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/seg6_linux.go @@ -99,6 +99,49 @@ func DecodeSEG6Encap(buf []byte) (int, []net.IP, error) { return mode, srh.Segments, nil } +func DecodeSEG6Srh(buf []byte) ([]net.IP, error) { + native := NativeEndian() + srh := IPv6SrHdr{ + nextHdr: buf[0], + hdrLen: buf[1], + routingType: buf[2], + segmentsLeft: buf[3], + firstSegment: buf[4], + flags: buf[5], + reserved: native.Uint16(buf[6:8]), + } + buf = buf[8:] + if len(buf)%16 != 0 { + err := fmt.Errorf("DecodeSEG6Srh: error parsing Segment List (buf len: %d)", len(buf)) + return nil, err + } + for len(buf) > 0 { + srh.Segments = append(srh.Segments, net.IP(buf[:16])) + buf = buf[16:] + } + return srh.Segments, nil +} +func EncodeSEG6Srh(segments []net.IP) ([]byte, error) { + nsegs := len(segments) // nsegs: number of segments + if nsegs == 0 { + return nil, errors.New("EncodeSEG6Srh: No Segments") + } + b := make([]byte, 8, 8+len(segments)*16) + native := NativeEndian() + b[0] = 0 // srh.nextHdr (0 when calling netlink) + b[1] = uint8(16 * nsegs >> 3) // srh.hdrLen (in 8-octets unit) + b[2] = IPV6_SRCRT_TYPE_4 // srh.routingType (assigned by IANA) + b[3] = uint8(nsegs - 1) // srh.segmentsLeft + b[4] = uint8(nsegs - 1) // srh.firstSegment + b[5] = 0 // srh.flags (SR6_FLAG1_HMAC for srh_hmac) + // srh.reserved: Defined as "Tag" in draft-ietf-6man-segment-routing-header-07 + native.PutUint16(b[6:], 0) // srh.reserved + for _, netIP := range segments { + b = append(b, netIP...) // srh.Segments + } + return b, nil +} + // Helper functions func SEG6EncapModeString(mode int) string { switch mode { diff --git a/vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go b/vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go new file mode 100644 index 0000000000..1500177267 --- /dev/null +++ b/vendor/github.com/vishvananda/netlink/nl/seg6local_linux.go @@ -0,0 +1,76 @@ +package nl + +import () + +// seg6local parameters +const ( + SEG6_LOCAL_UNSPEC = iota + SEG6_LOCAL_ACTION + SEG6_LOCAL_SRH + SEG6_LOCAL_TABLE + SEG6_LOCAL_NH4 + SEG6_LOCAL_NH6 + SEG6_LOCAL_IIF + SEG6_LOCAL_OIF + __SEG6_LOCAL_MAX +) +const ( + SEG6_LOCAL_MAX = __SEG6_LOCAL_MAX +) + +// seg6local actions +const ( + SEG6_LOCAL_ACTION_END = iota + 1 // 1 + SEG6_LOCAL_ACTION_END_X // 2 + SEG6_LOCAL_ACTION_END_T // 3 + SEG6_LOCAL_ACTION_END_DX2 // 4 + SEG6_LOCAL_ACTION_END_DX6 // 5 + SEG6_LOCAL_ACTION_END_DX4 // 6 + SEG6_LOCAL_ACTION_END_DT6 // 7 + SEG6_LOCAL_ACTION_END_DT4 // 8 + SEG6_LOCAL_ACTION_END_B6 // 9 + SEG6_LOCAL_ACTION_END_B6_ENCAPS // 10 + SEG6_LOCAL_ACTION_END_BM // 11 + SEG6_LOCAL_ACTION_END_S // 12 + SEG6_LOCAL_ACTION_END_AS // 13 + SEG6_LOCAL_ACTION_END_AM // 14 + __SEG6_LOCAL_ACTION_MAX +) +const ( + SEG6_LOCAL_ACTION_MAX = __SEG6_LOCAL_ACTION_MAX - 1 +) + +// Helper functions +func SEG6LocalActionString(action int) string { + switch action { + case SEG6_LOCAL_ACTION_END: + return "End" + case SEG6_LOCAL_ACTION_END_X: + return "End.X" + case SEG6_LOCAL_ACTION_END_T: + return "End.T" + case SEG6_LOCAL_ACTION_END_DX2: + return "End.DX2" + case SEG6_LOCAL_ACTION_END_DX6: + return "End.DX6" + case SEG6_LOCAL_ACTION_END_DX4: + return "End.DX4" + case SEG6_LOCAL_ACTION_END_DT6: + return "End.DT6" + case SEG6_LOCAL_ACTION_END_DT4: + return "End.DT4" + case SEG6_LOCAL_ACTION_END_B6: + return "End.B6" + case SEG6_LOCAL_ACTION_END_B6_ENCAPS: + return "End.B6.Encaps" + case SEG6_LOCAL_ACTION_END_BM: + return "End.BM" + case SEG6_LOCAL_ACTION_END_S: + return "End.S" + case SEG6_LOCAL_ACTION_END_AS: + return "End.AS" + case SEG6_LOCAL_ACTION_END_AM: + return "End.AM" + } + return "unknown" +} diff --git a/vendor/github.com/vishvananda/netlink/nl/syscall.go b/vendor/github.com/vishvananda/netlink/nl/syscall.go index fc631e0e50..f7f7f92e6f 100644 --- a/vendor/github.com/vishvananda/netlink/nl/syscall.go +++ b/vendor/github.com/vishvananda/netlink/nl/syscall.go @@ -42,16 +42,6 @@ const ( TCPDIAG_NOCOOKIE = 0xFFFFFFFF /* TCPDIAG_NOCOOKIE in net/ipv4/tcp_diag.h*/ ) -const ( - AF_MPLS = 28 -) - -const ( - RTA_NEWDST = 0x13 - RTA_ENCAP_TYPE = 0x15 - RTA_ENCAP = 0x16 -) - // RTA_ENCAP subtype const ( MPLS_IPTUNNEL_UNSPEC = iota @@ -67,6 +57,7 @@ const ( LWTUNNEL_ENCAP_IP6 LWTUNNEL_ENCAP_SEG6 LWTUNNEL_ENCAP_BPF + LWTUNNEL_ENCAP_SEG6_LOCAL ) // routing header types diff --git a/vendor/github.com/vishvananda/netlink/nl/tc_linux.go b/vendor/github.com/vishvananda/netlink/nl/tc_linux.go index 94ebc290a9..501f554b21 100644 --- a/vendor/github.com/vishvananda/netlink/nl/tc_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/tc_linux.go @@ -1,6 +1,7 @@ package nl import ( + "encoding/binary" "unsafe" ) @@ -64,6 +65,15 @@ const ( TCA_PRIO_MAX = TCA_PRIO_MQ ) +const ( + TCA_STATS_UNSPEC = iota + TCA_STATS_BASIC + TCA_STATS_RATE_EST + TCA_STATS_QUEUE + TCA_STATS_APP + TCA_STATS_MAX = TCA_STATS_APP +) + const ( SizeofTcMsg = 0x14 SizeofTcActionMsg = 0x04 @@ -79,7 +89,10 @@ const ( SizeofTcU32Key = 0x10 SizeofTcU32Sel = 0x10 // without keys SizeofTcGen = 0x14 + SizeofTcConnmark = SizeofTcGen + 0x04 SizeofTcMirred = SizeofTcGen + 0x08 + SizeofTcTunnelKey = SizeofTcGen + 0x04 + SizeofTcSkbEdit = SizeofTcGen SizeofTcPolice = 2*SizeofTcRateSpec + 0x20 ) @@ -412,6 +425,57 @@ func (x *TcHtbGlob) Serialize() []byte { return (*(*[SizeofTcHtbGlob]byte)(unsafe.Pointer(x)))[:] } +// HFSC + +type Curve struct { + m1 uint32 + d uint32 + m2 uint32 +} + +type HfscCopt struct { + Rsc Curve + Fsc Curve + Usc Curve +} + +func (c *Curve) Attrs() (uint32, uint32, uint32) { + return c.m1, c.d, c.m2 +} + +func (c *Curve) Set(m1 uint32, d uint32, m2 uint32) { + c.m1 = m1 + c.d = d + c.m2 = m2 +} + +func DeserializeHfscCurve(b []byte) *Curve { + return &Curve{ + m1: binary.LittleEndian.Uint32(b[0:4]), + d: binary.LittleEndian.Uint32(b[4:8]), + m2: binary.LittleEndian.Uint32(b[8:12]), + } +} + +func SerializeHfscCurve(c *Curve) (b []byte) { + t := make([]byte, binary.MaxVarintLen32) + binary.LittleEndian.PutUint32(t, c.m1) + b = append(b, t[:4]...) + binary.LittleEndian.PutUint32(t, c.d) + b = append(b, t[:4]...) + binary.LittleEndian.PutUint32(t, c.m2) + b = append(b, t[:4]...) + return b +} + +type TcHfscOpt struct { + Defcls uint16 +} + +func (x *TcHfscOpt) Serialize() []byte { + return (*(*[2]byte)(unsafe.Pointer(x)))[:] +} + const ( TCA_U32_UNSPEC = iota TCA_U32_CLASSID @@ -586,11 +650,47 @@ const ( TCA_BPF_FD TCA_BPF_NAME TCA_BPF_FLAGS - TCA_BPF_MAX = TCA_BPF_FLAGS + TCA_BPF_FLAGS_GEN + TCA_BPF_TAG + TCA_BPF_ID + TCA_BPF_MAX = TCA_BPF_ID ) type TcBpf TcGen +const ( + TCA_ACT_CONNMARK = 14 +) + +const ( + TCA_CONNMARK_UNSPEC = iota + TCA_CONNMARK_PARMS + TCA_CONNMARK_TM + TCA_CONNMARK_MAX = TCA_CONNMARK_TM +) + +// struct tc_connmark { +// tc_gen; +// __u16 zone; +// }; + +type TcConnmark struct { + TcGen + Zone uint16 +} + +func (msg *TcConnmark) Len() int { + return SizeofTcConnmark +} + +func DeserializeTcConnmark(b []byte) *TcConnmark { + return (*TcConnmark)(unsafe.Pointer(&b[0:SizeofTcConnmark][0])) +} + +func (x *TcConnmark) Serialize() []byte { + return (*(*[SizeofTcConnmark]byte)(unsafe.Pointer(x)))[:] +} + const ( TCA_ACT_MIRRED = 8 ) @@ -626,6 +726,63 @@ func (x *TcMirred) Serialize() []byte { return (*(*[SizeofTcMirred]byte)(unsafe.Pointer(x)))[:] } +const ( + TCA_TUNNEL_KEY_UNSPEC = iota + TCA_TUNNEL_KEY_TM + TCA_TUNNEL_KEY_PARMS + TCA_TUNNEL_KEY_ENC_IPV4_SRC + TCA_TUNNEL_KEY_ENC_IPV4_DST + TCA_TUNNEL_KEY_ENC_IPV6_SRC + TCA_TUNNEL_KEY_ENC_IPV6_DST + TCA_TUNNEL_KEY_ENC_KEY_ID + TCA_TUNNEL_KEY_MAX = TCA_TUNNEL_KEY_ENC_KEY_ID +) + +type TcTunnelKey struct { + TcGen + Action int32 +} + +func (x *TcTunnelKey) Len() int { + return SizeofTcTunnelKey +} + +func DeserializeTunnelKey(b []byte) *TcTunnelKey { + return (*TcTunnelKey)(unsafe.Pointer(&b[0:SizeofTcTunnelKey][0])) +} + +func (x *TcTunnelKey) Serialize() []byte { + return (*(*[SizeofTcTunnelKey]byte)(unsafe.Pointer(x)))[:] +} + +const ( + TCA_SKBEDIT_UNSPEC = iota + TCA_SKBEDIT_TM + TCA_SKBEDIT_PARMS + TCA_SKBEDIT_PRIORITY + TCA_SKBEDIT_QUEUE_MAPPING + TCA_SKBEDIT_MARK + TCA_SKBEDIT_PAD + TCA_SKBEDIT_PTYPE + TCA_SKBEDIT_MAX = TCA_SKBEDIT_MARK +) + +type TcSkbEdit struct { + TcGen +} + +func (x *TcSkbEdit) Len() int { + return SizeofTcSkbEdit +} + +func DeserializeSkbEdit(b []byte) *TcSkbEdit { + return (*TcSkbEdit)(unsafe.Pointer(&b[0:SizeofTcSkbEdit][0])) +} + +func (x *TcSkbEdit) Serialize() []byte { + return (*(*[SizeofTcSkbEdit]byte)(unsafe.Pointer(x)))[:] +} + // struct tc_police { // __u32 index; // int action; @@ -708,3 +865,10 @@ const ( TCA_FQ_CODEL_DROP_BATCH_SIZE TCA_FQ_CODEL_MEMORY_LIMIT ) + +const ( + TCA_HFSC_UNSPEC = iota + TCA_HFSC_RSC + TCA_HFSC_FSC + TCA_HFSC_USC +) diff --git a/vendor/github.com/vishvananda/netlink/nl/xfrm_linux.go b/vendor/github.com/vishvananda/netlink/nl/xfrm_linux.go index 09a2ffa10e..dce9073f7b 100644 --- a/vendor/github.com/vishvananda/netlink/nl/xfrm_linux.go +++ b/vendor/github.com/vishvananda/netlink/nl/xfrm_linux.go @@ -50,34 +50,44 @@ const ( // Attribute types const ( /* Netlink message attributes. */ - XFRMA_UNSPEC = 0x00 - XFRMA_ALG_AUTH = 0x01 /* struct xfrm_algo */ - XFRMA_ALG_CRYPT = 0x02 /* struct xfrm_algo */ - XFRMA_ALG_COMP = 0x03 /* struct xfrm_algo */ - XFRMA_ENCAP = 0x04 /* struct xfrm_algo + struct xfrm_encap_tmpl */ - XFRMA_TMPL = 0x05 /* 1 or more struct xfrm_user_tmpl */ - XFRMA_SA = 0x06 /* struct xfrm_usersa_info */ - XFRMA_POLICY = 0x07 /* struct xfrm_userpolicy_info */ - XFRMA_SEC_CTX = 0x08 /* struct xfrm_sec_ctx */ - XFRMA_LTIME_VAL = 0x09 - XFRMA_REPLAY_VAL = 0x0a - XFRMA_REPLAY_THRESH = 0x0b - XFRMA_ETIMER_THRESH = 0x0c - XFRMA_SRCADDR = 0x0d /* xfrm_address_t */ - XFRMA_COADDR = 0x0e /* xfrm_address_t */ - XFRMA_LASTUSED = 0x0f /* unsigned long */ - XFRMA_POLICY_TYPE = 0x10 /* struct xfrm_userpolicy_type */ - XFRMA_MIGRATE = 0x11 - XFRMA_ALG_AEAD = 0x12 /* struct xfrm_algo_aead */ - XFRMA_KMADDRESS = 0x13 /* struct xfrm_user_kmaddress */ - XFRMA_ALG_AUTH_TRUNC = 0x14 /* struct xfrm_algo_auth */ - XFRMA_MARK = 0x15 /* struct xfrm_mark */ - XFRMA_TFCPAD = 0x16 /* __u32 */ - XFRMA_REPLAY_ESN_VAL = 0x17 /* struct xfrm_replay_esn */ - XFRMA_SA_EXTRA_FLAGS = 0x18 /* __u32 */ - XFRMA_MAX = 0x18 + XFRMA_UNSPEC = iota + XFRMA_ALG_AUTH /* struct xfrm_algo */ + XFRMA_ALG_CRYPT /* struct xfrm_algo */ + XFRMA_ALG_COMP /* struct xfrm_algo */ + XFRMA_ENCAP /* struct xfrm_algo + struct xfrm_encap_tmpl */ + XFRMA_TMPL /* 1 or more struct xfrm_user_tmpl */ + XFRMA_SA /* struct xfrm_usersa_info */ + XFRMA_POLICY /* struct xfrm_userpolicy_info */ + XFRMA_SEC_CTX /* struct xfrm_sec_ctx */ + XFRMA_LTIME_VAL + XFRMA_REPLAY_VAL + XFRMA_REPLAY_THRESH + XFRMA_ETIMER_THRESH + XFRMA_SRCADDR /* xfrm_address_t */ + XFRMA_COADDR /* xfrm_address_t */ + XFRMA_LASTUSED /* unsigned long */ + XFRMA_POLICY_TYPE /* struct xfrm_userpolicy_type */ + XFRMA_MIGRATE + XFRMA_ALG_AEAD /* struct xfrm_algo_aead */ + XFRMA_KMADDRESS /* struct xfrm_user_kmaddress */ + XFRMA_ALG_AUTH_TRUNC /* struct xfrm_algo_auth */ + XFRMA_MARK /* struct xfrm_mark */ + XFRMA_TFCPAD /* __u32 */ + XFRMA_REPLAY_ESN_VAL /* struct xfrm_replay_esn */ + XFRMA_SA_EXTRA_FLAGS /* __u32 */ + XFRMA_PROTO /* __u8 */ + XFRMA_ADDRESS_FILTER /* struct xfrm_address_filter */ + XFRMA_PAD + XFRMA_OFFLOAD_DEV /* struct xfrm_state_offload */ + XFRMA_SET_MARK /* __u32 */ + XFRMA_SET_MARK_MASK /* __u32 */ + XFRMA_IF_ID /* __u32 */ + + XFRMA_MAX = iota - 1 ) +const XFRMA_OUTPUT_MARK = XFRMA_SET_MARK + const ( SizeofXfrmAddress = 0x10 SizeofXfrmSelector = 0x38 diff --git a/vendor/github.com/vishvananda/netlink/protinfo.go b/vendor/github.com/vishvananda/netlink/protinfo.go index 0087c4438b..60b23b3742 100644 --- a/vendor/github.com/vishvananda/netlink/protinfo.go +++ b/vendor/github.com/vishvananda/netlink/protinfo.go @@ -18,6 +18,10 @@ type Protinfo struct { // String returns a list of enabled flags func (prot *Protinfo) String() string { + if prot == nil { + return "" + } + var boolStrings []string if prot.Hairpin { boolStrings = append(boolStrings, "Hairpin") diff --git a/vendor/github.com/vishvananda/netlink/protinfo_linux.go b/vendor/github.com/vishvananda/netlink/protinfo_linux.go index 43c465f057..15b65123ce 100644 --- a/vendor/github.com/vishvananda/netlink/protinfo_linux.go +++ b/vendor/github.com/vishvananda/netlink/protinfo_linux.go @@ -41,7 +41,7 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) { if err != nil { return pi, err } - pi = *parseProtinfo(infos) + pi = parseProtinfo(infos) return pi, nil } @@ -49,8 +49,7 @@ func (h *Handle) LinkGetProtinfo(link Link) (Protinfo, error) { return pi, fmt.Errorf("Device with index %d not found", base.Index) } -func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo { - var pi Protinfo +func parseProtinfo(infos []syscall.NetlinkRouteAttr) (pi Protinfo) { for _, info := range infos { switch info.Attr.Type { case nl.IFLA_BRPORT_MODE: @@ -71,5 +70,5 @@ func parseProtinfo(infos []syscall.NetlinkRouteAttr) *Protinfo { pi.ProxyArpWiFi = byteToBool(info.Value[0]) } } - return &pi + return } diff --git a/vendor/github.com/vishvananda/netlink/qdisc.go b/vendor/github.com/vishvananda/netlink/qdisc.go index 3df4b5c291..af78305ac2 100644 --- a/vendor/github.com/vishvananda/netlink/qdisc.go +++ b/vendor/github.com/vishvananda/netlink/qdisc.go @@ -176,6 +176,13 @@ type Netem struct { CorruptCorr uint32 } +func (netem *Netem) String() string { + return fmt.Sprintf( + "{Latency: %v, Limit: %v, Loss: %v, Gap: %v, Duplicate: %v, Jitter: %v}", + netem.Latency, netem.Limit, netem.Loss, netem.Gap, netem.Duplicate, netem.Jitter, + ) +} + func (qdisc *Netem) Attrs() *QdiscAttrs { return &qdisc.QdiscAttrs } @@ -231,6 +238,33 @@ func (qdisc *GenericQdisc) Type() string { return qdisc.QdiscType } +type Hfsc struct { + QdiscAttrs + Defcls uint16 +} + +func NewHfsc(attrs QdiscAttrs) *Hfsc { + return &Hfsc{ + QdiscAttrs: attrs, + Defcls: 1, + } +} + +func (hfsc *Hfsc) Attrs() *QdiscAttrs { + return &hfsc.QdiscAttrs +} + +func (hfsc *Hfsc) Type() string { + return "hfsc" +} + +func (hfsc *Hfsc) String() string { + return fmt.Sprintf( + "{%v -- default: %d}", + hfsc.Attrs(), hfsc.Defcls, + ) +} + // Fq is a classless packet scheduler meant to be mostly used for locally generated traffic. type Fq struct { QdiscAttrs @@ -249,6 +283,13 @@ type Fq struct { LowRateThreshold uint32 } +func (fq *Fq) String() string { + return fmt.Sprintf( + "{PacketLimit: %v, FlowPacketLimit: %v, Quantum: %v, InitialQuantum: %v, Pacing: %v, FlowDefaultRate: %v, FlowMaxRate: %v, Buckets: %v, FlowRefillDelay: %v, LowRateThreshold: %v}", + fq.PacketLimit, fq.FlowPacketLimit, fq.Quantum, fq.InitialQuantum, fq.Pacing, fq.FlowDefaultRate, fq.FlowMaxRate, fq.Buckets, fq.FlowRefillDelay, fq.LowRateThreshold, + ) +} + func NewFq(attrs QdiscAttrs) *Fq { return &Fq{ QdiscAttrs: attrs, @@ -276,6 +317,13 @@ type FqCodel struct { // There are some more attributes here, but support for them seems not ubiquitous } +func (fqcodel *FqCodel) String() string { + return fmt.Sprintf( + "{%v -- Target: %v, Limit: %v, Interval: %v, ECM: %v, Flows: %v, Quantum: %v}", + fqcodel.Attrs(), fqcodel.Target, fqcodel.Limit, fqcodel.Interval, fqcodel.ECN, fqcodel.Flows, fqcodel.Quantum, + ) +} + func NewFqCodel(attrs QdiscAttrs) *FqCodel { return &FqCodel{ QdiscAttrs: attrs, diff --git a/vendor/github.com/vishvananda/netlink/qdisc_linux.go b/vendor/github.com/vishvananda/netlink/qdisc_linux.go index 3794ac18a8..e9eee59084 100644 --- a/vendor/github.com/vishvananda/netlink/qdisc_linux.go +++ b/vendor/github.com/vishvananda/netlink/qdisc_linux.go @@ -175,15 +175,15 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error { opt.Peakrate.Rate = uint32(qdisc.Peakrate) opt.Limit = qdisc.Limit opt.Buffer = qdisc.Buffer - nl.NewRtAttrChild(options, nl.TCA_TBF_PARMS, opt.Serialize()) + options.AddRtAttr(nl.TCA_TBF_PARMS, opt.Serialize()) if qdisc.Rate >= uint64(1<<32) { - nl.NewRtAttrChild(options, nl.TCA_TBF_RATE64, nl.Uint64Attr(qdisc.Rate)) + options.AddRtAttr(nl.TCA_TBF_RATE64, nl.Uint64Attr(qdisc.Rate)) } if qdisc.Peakrate >= uint64(1<<32) { - nl.NewRtAttrChild(options, nl.TCA_TBF_PRATE64, nl.Uint64Attr(qdisc.Peakrate)) + options.AddRtAttr(nl.TCA_TBF_PRATE64, nl.Uint64Attr(qdisc.Peakrate)) } if qdisc.Peakrate > 0 { - nl.NewRtAttrChild(options, nl.TCA_TBF_PBURST, nl.Uint32Attr(qdisc.Minburst)) + options.AddRtAttr(nl.TCA_TBF_PBURST, nl.Uint32Attr(qdisc.Minburst)) } case *Htb: opt := nl.TcHtbGlob{} @@ -193,8 +193,12 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error { // TODO: Handle Debug properly. For now default to 0 opt.Debug = qdisc.Debug opt.DirectPkts = qdisc.DirectPkts - nl.NewRtAttrChild(options, nl.TCA_HTB_INIT, opt.Serialize()) - // nl.NewRtAttrChild(options, nl.TCA_HTB_DIRECT_QLEN, opt.Serialize()) + options.AddRtAttr(nl.TCA_HTB_INIT, opt.Serialize()) + // options.AddRtAttr(nl.TCA_HTB_DIRECT_QLEN, opt.Serialize()) + case *Hfsc: + opt := nl.TcHfscOpt{} + opt.Defcls = qdisc.Defcls + options = nl.NewRtAttr(nl.TCA_OPTIONS, opt.Serialize()) case *Netem: opt := nl.TcNetemQopt{} opt.Latency = qdisc.Latency @@ -211,21 +215,21 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error { corr.DupCorr = qdisc.DuplicateCorr if corr.DelayCorr > 0 || corr.LossCorr > 0 || corr.DupCorr > 0 { - nl.NewRtAttrChild(options, nl.TCA_NETEM_CORR, corr.Serialize()) + options.AddRtAttr(nl.TCA_NETEM_CORR, corr.Serialize()) } // Corruption corruption := nl.TcNetemCorrupt{} corruption.Probability = qdisc.CorruptProb corruption.Correlation = qdisc.CorruptCorr if corruption.Probability > 0 { - nl.NewRtAttrChild(options, nl.TCA_NETEM_CORRUPT, corruption.Serialize()) + options.AddRtAttr(nl.TCA_NETEM_CORRUPT, corruption.Serialize()) } // Reorder reorder := nl.TcNetemReorder{} reorder.Probability = qdisc.ReorderProb reorder.Correlation = qdisc.ReorderCorr if reorder.Probability > 0 { - nl.NewRtAttrChild(options, nl.TCA_NETEM_REORDER, reorder.Serialize()) + options.AddRtAttr(nl.TCA_NETEM_REORDER, reorder.Serialize()) } case *Ingress: // ingress filters must use the proper handle @@ -233,50 +237,54 @@ func qdiscPayload(req *nl.NetlinkRequest, qdisc Qdisc) error { return fmt.Errorf("Ingress filters must set Parent to HANDLE_INGRESS") } case *FqCodel: - nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_ECN, nl.Uint32Attr((uint32(qdisc.ECN)))) + options.AddRtAttr(nl.TCA_FQ_CODEL_ECN, nl.Uint32Attr((uint32(qdisc.ECN)))) if qdisc.Limit > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_LIMIT, nl.Uint32Attr((uint32(qdisc.Limit)))) + options.AddRtAttr(nl.TCA_FQ_CODEL_LIMIT, nl.Uint32Attr((uint32(qdisc.Limit)))) } if qdisc.Interval > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_INTERVAL, nl.Uint32Attr((uint32(qdisc.Interval)))) + options.AddRtAttr(nl.TCA_FQ_CODEL_INTERVAL, nl.Uint32Attr((uint32(qdisc.Interval)))) } if qdisc.Flows > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_FLOWS, nl.Uint32Attr((uint32(qdisc.Flows)))) + options.AddRtAttr(nl.TCA_FQ_CODEL_FLOWS, nl.Uint32Attr((uint32(qdisc.Flows)))) } if qdisc.Quantum > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum)))) + options.AddRtAttr(nl.TCA_FQ_CODEL_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum)))) } case *Fq: - nl.NewRtAttrChild(options, nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing)))) + options.AddRtAttr(nl.TCA_FQ_RATE_ENABLE, nl.Uint32Attr((uint32(qdisc.Pacing)))) if qdisc.Buckets > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_BUCKETS_LOG, nl.Uint32Attr((uint32(qdisc.Buckets)))) + options.AddRtAttr(nl.TCA_FQ_BUCKETS_LOG, nl.Uint32Attr((uint32(qdisc.Buckets)))) } if qdisc.LowRateThreshold > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_LOW_RATE_THRESHOLD, nl.Uint32Attr((uint32(qdisc.LowRateThreshold)))) + options.AddRtAttr(nl.TCA_FQ_LOW_RATE_THRESHOLD, nl.Uint32Attr((uint32(qdisc.LowRateThreshold)))) } if qdisc.Quantum > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum)))) + options.AddRtAttr(nl.TCA_FQ_QUANTUM, nl.Uint32Attr((uint32(qdisc.Quantum)))) } if qdisc.InitialQuantum > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_INITIAL_QUANTUM, nl.Uint32Attr((uint32(qdisc.InitialQuantum)))) + options.AddRtAttr(nl.TCA_FQ_INITIAL_QUANTUM, nl.Uint32Attr((uint32(qdisc.InitialQuantum)))) } if qdisc.FlowRefillDelay > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_REFILL_DELAY, nl.Uint32Attr((uint32(qdisc.FlowRefillDelay)))) + options.AddRtAttr(nl.TCA_FQ_FLOW_REFILL_DELAY, nl.Uint32Attr((uint32(qdisc.FlowRefillDelay)))) } if qdisc.FlowPacketLimit > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_PLIMIT, nl.Uint32Attr((uint32(qdisc.FlowPacketLimit)))) + options.AddRtAttr(nl.TCA_FQ_FLOW_PLIMIT, nl.Uint32Attr((uint32(qdisc.FlowPacketLimit)))) } if qdisc.FlowMaxRate > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_MAX_RATE, nl.Uint32Attr((uint32(qdisc.FlowMaxRate)))) + options.AddRtAttr(nl.TCA_FQ_FLOW_MAX_RATE, nl.Uint32Attr((uint32(qdisc.FlowMaxRate)))) } if qdisc.FlowDefaultRate > 0 { - nl.NewRtAttrChild(options, nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate)))) + options.AddRtAttr(nl.TCA_FQ_FLOW_DEFAULT_RATE, nl.Uint32Attr((uint32(qdisc.FlowDefaultRate)))) } + default: + options = nil } - req.AddData(options) + if options != nil { + req.AddData(options) + } return nil } @@ -348,6 +356,8 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) { qdisc = &Htb{} case "fq": qdisc = &Fq{} + case "hfsc": + qdisc = &Hfsc{} case "fq_codel": qdisc = &FqCodel{} case "netem": @@ -375,6 +385,10 @@ func (h *Handle) QdiscList(link Link) ([]Qdisc, error) { if err := parseTbfData(qdisc, data); err != nil { return nil, err } + case "hfsc": + if err := parseHfscData(qdisc, attr.Value); err != nil { + return nil, err + } case "htb": data, err := nl.ParseRouteAttr(attr.Value) if err != nil { @@ -474,6 +488,13 @@ func parseFqCodelData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error { return nil } +func parseHfscData(qdisc Qdisc, data []byte) error { + Hfsc := qdisc.(*Hfsc) + native = nl.NativeEndian() + Hfsc.Defcls = native.Uint16(data) + return nil +} + func parseFqData(qdisc Qdisc, data []syscall.NetlinkRouteAttr) error { native = nl.NativeEndian() fq := qdisc.(*Fq) diff --git a/vendor/github.com/vishvananda/netlink/rdma_link_linux.go b/vendor/github.com/vishvananda/netlink/rdma_link_linux.go new file mode 100644 index 0000000000..2d0bdc8c36 --- /dev/null +++ b/vendor/github.com/vishvananda/netlink/rdma_link_linux.go @@ -0,0 +1,264 @@ +package netlink + +import ( + "bytes" + "encoding/binary" + "fmt" + "net" + + "github.com/vishvananda/netlink/nl" + "golang.org/x/sys/unix" +) + +// LinkAttrs represents data shared by most link types +type RdmaLinkAttrs struct { + Index uint32 + Name string + FirmwareVersion string + NodeGuid string + SysImageGuid string +} + +// Link represents a rdma device from netlink. +type RdmaLink struct { + Attrs RdmaLinkAttrs +} + +func getProtoField(clientType int, op int) int { + return ((clientType << nl.RDMA_NL_GET_CLIENT_SHIFT) | op) +} + +func uint64ToGuidString(guid uint64) string { + //Convert to byte array + sysGuidBytes := new(bytes.Buffer) + binary.Write(sysGuidBytes, binary.LittleEndian, guid) + + //Convert to HardwareAddr + sysGuidNet := net.HardwareAddr(sysGuidBytes.Bytes()) + + //Get the String + return sysGuidNet.String() +} + +func executeOneGetRdmaLink(data []byte) (*RdmaLink, error) { + + link := RdmaLink{} + + reader := bytes.NewReader(data) + for reader.Len() >= 4 { + _, attrType, len, value := parseNfAttrTLV(reader) + + switch attrType { + case nl.RDMA_NLDEV_ATTR_DEV_INDEX: + var Index uint32 + r := bytes.NewReader(value) + binary.Read(r, nl.NativeEndian(), &Index) + link.Attrs.Index = Index + case nl.RDMA_NLDEV_ATTR_DEV_NAME: + link.Attrs.Name = string(value[0 : len-1]) + case nl.RDMA_NLDEV_ATTR_FW_VERSION: + link.Attrs.FirmwareVersion = string(value[0 : len-1]) + case nl.RDMA_NLDEV_ATTR_NODE_GUID: + var guid uint64 + r := bytes.NewReader(value) + binary.Read(r, nl.NativeEndian(), &guid) + link.Attrs.NodeGuid = uint64ToGuidString(guid) + case nl.RDMA_NLDEV_ATTR_SYS_IMAGE_GUID: + var sysGuid uint64 + r := bytes.NewReader(value) + binary.Read(r, nl.NativeEndian(), &sysGuid) + link.Attrs.SysImageGuid = uint64ToGuidString(sysGuid) + } + if (len % 4) != 0 { + // Skip pad bytes + reader.Seek(int64(4-(len%4)), seekCurrent) + } + } + return &link, nil +} + +func execRdmaGetLink(req *nl.NetlinkRequest, name string) (*RdmaLink, error) { + + msgs, err := req.Execute(unix.NETLINK_RDMA, 0) + if err != nil { + return nil, err + } + for _, m := range msgs { + link, err := executeOneGetRdmaLink(m) + if err != nil { + return nil, err + } + if link.Attrs.Name == name { + return link, nil + } + } + return nil, fmt.Errorf("Rdma device %v not found", name) +} + +func execRdmaSetLink(req *nl.NetlinkRequest) error { + + _, err := req.Execute(unix.NETLINK_RDMA, 0) + return err +} + +// RdmaLinkByName finds a link by name and returns a pointer to the object if +// found and nil error, otherwise returns error code. +func RdmaLinkByName(name string) (*RdmaLink, error) { + return pkgHandle.RdmaLinkByName(name) +} + +// RdmaLinkByName finds a link by name and returns a pointer to the object if +// found and nil error, otherwise returns error code. +func (h *Handle) RdmaLinkByName(name string) (*RdmaLink, error) { + + proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_GET) + req := h.newNetlinkRequest(proto, unix.NLM_F_ACK|unix.NLM_F_DUMP) + + return execRdmaGetLink(req, name) +} + +// RdmaLinkSetName sets the name of the rdma link device. Return nil on success +// or error otherwise. +// Equivalent to: `rdma dev set $old_devname name $name` +func RdmaLinkSetName(link *RdmaLink, name string) error { + return pkgHandle.RdmaLinkSetName(link, name) +} + +// RdmaLinkSetName sets the name of the rdma link device. Return nil on success +// or error otherwise. +// Equivalent to: `rdma dev set $old_devname name $name` +func (h *Handle) RdmaLinkSetName(link *RdmaLink, name string) error { + proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SET) + req := h.newNetlinkRequest(proto, unix.NLM_F_ACK) + + b := make([]byte, 4) + native.PutUint32(b, uint32(link.Attrs.Index)) + data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, b) + req.AddData(data) + + b = make([]byte, len(name)+1) + copy(b, name) + data = nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_NAME, b) + req.AddData(data) + + return execRdmaSetLink(req) +} + +func netnsModeToString(mode uint8) string { + switch mode { + case 0: + return "exclusive" + case 1: + return "shared" + default: + return "unknown" + } +} + +func executeOneGetRdmaNetnsMode(data []byte) (string, error) { + reader := bytes.NewReader(data) + for reader.Len() >= 4 { + _, attrType, len, value := parseNfAttrTLV(reader) + + switch attrType { + case nl.RDMA_NLDEV_SYS_ATTR_NETNS_MODE: + var mode uint8 + r := bytes.NewReader(value) + binary.Read(r, nl.NativeEndian(), &mode) + return netnsModeToString(mode), nil + } + if (len % 4) != 0 { + // Skip pad bytes + reader.Seek(int64(4-(len%4)), seekCurrent) + } + } + return "", fmt.Errorf("Invalid netns mode") +} + +// RdmaSystemGetNetnsMode gets the net namespace mode for RDMA subsystem +// Returns mode string and error status as nil on success or returns error +// otherwise. +// Equivalent to: `rdma system show netns' +func RdmaSystemGetNetnsMode() (string, error) { + return pkgHandle.RdmaSystemGetNetnsMode() +} + +// RdmaSystemGetNetnsMode gets the net namespace mode for RDMA subsystem +// Returns mode string and error status as nil on success or returns error +// otherwise. +// Equivalent to: `rdma system show netns' +func (h *Handle) RdmaSystemGetNetnsMode() (string, error) { + + proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SYS_GET) + req := h.newNetlinkRequest(proto, unix.NLM_F_ACK) + + msgs, err := req.Execute(unix.NETLINK_RDMA, 0) + if err != nil { + return "", err + } + if len(msgs) == 0 { + return "", fmt.Errorf("No valid response from kernel") + } + return executeOneGetRdmaNetnsMode(msgs[0]) +} + +func netnsModeStringToUint8(mode string) (uint8, error) { + switch mode { + case "exclusive": + return 0, nil + case "shared": + return 1, nil + default: + return 0, fmt.Errorf("Invalid mode; %q", mode) + } +} + +// RdmaSystemSetNetnsMode sets the net namespace mode for RDMA subsystem +// Returns nil on success or appropriate error code. +// Equivalent to: `rdma system set netns { shared | exclusive }' +func RdmaSystemSetNetnsMode(NewMode string) error { + return pkgHandle.RdmaSystemSetNetnsMode(NewMode) +} + +// RdmaSystemSetNetnsMode sets the net namespace mode for RDMA subsystem +// Returns nil on success or appropriate error code. +// Equivalent to: `rdma system set netns { shared | exclusive }' +func (h *Handle) RdmaSystemSetNetnsMode(NewMode string) error { + value, err := netnsModeStringToUint8(NewMode) + if err != nil { + return err + } + + proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SYS_SET) + req := h.newNetlinkRequest(proto, unix.NLM_F_ACK) + + data := nl.NewRtAttr(nl.RDMA_NLDEV_SYS_ATTR_NETNS_MODE, []byte{value}) + req.AddData(data) + + _, err = req.Execute(unix.NETLINK_RDMA, 0) + return err +} + +// RdmaLinkSetNsFd puts the RDMA device into a new network namespace. The +// fd must be an open file descriptor to a network namespace. +// Similar to: `rdma dev set $dev netns $ns` +func RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error { + return pkgHandle.RdmaLinkSetNsFd(link, fd) +} + +// RdmaLinkSetNsFd puts the RDMA device into a new network namespace. The +// fd must be an open file descriptor to a network namespace. +// Similar to: `rdma dev set $dev netns $ns` +func (h *Handle) RdmaLinkSetNsFd(link *RdmaLink, fd uint32) error { + proto := getProtoField(nl.RDMA_NL_NLDEV, nl.RDMA_NLDEV_CMD_SET) + req := h.newNetlinkRequest(proto, unix.NLM_F_ACK) + + data := nl.NewRtAttr(nl.RDMA_NLDEV_ATTR_DEV_INDEX, + nl.Uint32Attr(link.Attrs.Index)) + req.AddData(data) + + data = nl.NewRtAttr(nl.RDMA_NLDEV_NET_NS_FD, nl.Uint32Attr(fd)) + req.AddData(data) + + return execRdmaSetLink(req) +} diff --git a/vendor/github.com/vishvananda/netlink/route.go b/vendor/github.com/vishvananda/netlink/route.go index 2cd58ee334..58ff1af600 100644 --- a/vendor/github.com/vishvananda/netlink/route.go +++ b/vendor/github.com/vishvananda/netlink/route.go @@ -47,6 +47,7 @@ type Route struct { Encap Encap MTU int AdvMSS int + Hoplimit int } func (r Route) String() string { @@ -89,6 +90,7 @@ func (r Route) Equal(x Route) bool { r.Table == x.Table && r.Type == x.Type && r.Tos == x.Tos && + r.Hoplimit == x.Hoplimit && r.Flags == x.Flags && (r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) && (r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) && diff --git a/vendor/github.com/vishvananda/netlink/route_linux.go b/vendor/github.com/vishvananda/netlink/route_linux.go index 3f856711f3..c69c595ed3 100644 --- a/vendor/github.com/vishvananda/netlink/route_linux.go +++ b/vendor/github.com/vishvananda/netlink/route_linux.go @@ -32,6 +32,7 @@ const ( RT_FILTER_SRC RT_FILTER_GW RT_FILTER_TABLE + RT_FILTER_HOPLIMIT ) const ( @@ -207,6 +208,7 @@ func (e *SEG6Encap) Decode(buf []byte) error { } buf = buf[:l] // make sure buf size upper limit is Length typ := native.Uint16(buf[2:]) + // LWTUNNEL_ENCAP_SEG6 has only one attr type SEG6_IPTUNNEL_SRH if typ != nl.SEG6_IPTUNNEL_SRH { return fmt.Errorf("unknown SEG6 Type: %d", typ) } @@ -259,6 +261,188 @@ func (e *SEG6Encap) Equal(x Encap) bool { return true } +// SEG6LocalEncap definitions +type SEG6LocalEncap struct { + Flags [nl.SEG6_LOCAL_MAX]bool + Action int + Segments []net.IP // from SRH in seg6_local_lwt + Table int // table id for End.T and End.DT6 + InAddr net.IP + In6Addr net.IP + Iif int + Oif int +} + +func (e *SEG6LocalEncap) Type() int { + return nl.LWTUNNEL_ENCAP_SEG6_LOCAL +} +func (e *SEG6LocalEncap) Decode(buf []byte) error { + attrs, err := nl.ParseRouteAttr(buf) + if err != nil { + return err + } + native := nl.NativeEndian() + for _, attr := range attrs { + switch attr.Attr.Type { + case nl.SEG6_LOCAL_ACTION: + e.Action = int(native.Uint32(attr.Value[0:4])) + e.Flags[nl.SEG6_LOCAL_ACTION] = true + case nl.SEG6_LOCAL_SRH: + e.Segments, err = nl.DecodeSEG6Srh(attr.Value[:]) + e.Flags[nl.SEG6_LOCAL_SRH] = true + case nl.SEG6_LOCAL_TABLE: + e.Table = int(native.Uint32(attr.Value[0:4])) + e.Flags[nl.SEG6_LOCAL_TABLE] = true + case nl.SEG6_LOCAL_NH4: + e.InAddr = net.IP(attr.Value[0:4]) + e.Flags[nl.SEG6_LOCAL_NH4] = true + case nl.SEG6_LOCAL_NH6: + e.In6Addr = net.IP(attr.Value[0:16]) + e.Flags[nl.SEG6_LOCAL_NH6] = true + case nl.SEG6_LOCAL_IIF: + e.Iif = int(native.Uint32(attr.Value[0:4])) + e.Flags[nl.SEG6_LOCAL_IIF] = true + case nl.SEG6_LOCAL_OIF: + e.Oif = int(native.Uint32(attr.Value[0:4])) + e.Flags[nl.SEG6_LOCAL_OIF] = true + } + } + return err +} +func (e *SEG6LocalEncap) Encode() ([]byte, error) { + var err error + native := nl.NativeEndian() + res := make([]byte, 8) + native.PutUint16(res, 8) // length + native.PutUint16(res[2:], nl.SEG6_LOCAL_ACTION) + native.PutUint32(res[4:], uint32(e.Action)) + if e.Flags[nl.SEG6_LOCAL_SRH] { + srh, err := nl.EncodeSEG6Srh(e.Segments) + if err != nil { + return nil, err + } + attr := make([]byte, 4) + native.PutUint16(attr, uint16(len(srh)+4)) + native.PutUint16(attr[2:], nl.SEG6_LOCAL_SRH) + attr = append(attr, srh...) + res = append(res, attr...) + } + if e.Flags[nl.SEG6_LOCAL_TABLE] { + attr := make([]byte, 8) + native.PutUint16(attr, 8) + native.PutUint16(attr[2:], nl.SEG6_LOCAL_TABLE) + native.PutUint32(attr[4:], uint32(e.Table)) + res = append(res, attr...) + } + if e.Flags[nl.SEG6_LOCAL_NH4] { + attr := make([]byte, 4) + native.PutUint16(attr, 8) + native.PutUint16(attr[2:], nl.SEG6_LOCAL_NH4) + ipv4 := e.InAddr.To4() + if ipv4 == nil { + err = fmt.Errorf("SEG6_LOCAL_NH4 has invalid IPv4 address") + return nil, err + } + attr = append(attr, ipv4...) + res = append(res, attr...) + } + if e.Flags[nl.SEG6_LOCAL_NH6] { + attr := make([]byte, 4) + native.PutUint16(attr, 20) + native.PutUint16(attr[2:], nl.SEG6_LOCAL_NH6) + attr = append(attr, e.In6Addr...) + res = append(res, attr...) + } + if e.Flags[nl.SEG6_LOCAL_IIF] { + attr := make([]byte, 8) + native.PutUint16(attr, 8) + native.PutUint16(attr[2:], nl.SEG6_LOCAL_IIF) + native.PutUint32(attr[4:], uint32(e.Iif)) + res = append(res, attr...) + } + if e.Flags[nl.SEG6_LOCAL_OIF] { + attr := make([]byte, 8) + native.PutUint16(attr, 8) + native.PutUint16(attr[2:], nl.SEG6_LOCAL_OIF) + native.PutUint32(attr[4:], uint32(e.Oif)) + res = append(res, attr...) + } + return res, err +} +func (e *SEG6LocalEncap) String() string { + strs := make([]string, 0, nl.SEG6_LOCAL_MAX) + strs = append(strs, fmt.Sprintf("action %s", nl.SEG6LocalActionString(e.Action))) + + if e.Flags[nl.SEG6_LOCAL_TABLE] { + strs = append(strs, fmt.Sprintf("table %d", e.Table)) + } + if e.Flags[nl.SEG6_LOCAL_NH4] { + strs = append(strs, fmt.Sprintf("nh4 %s", e.InAddr)) + } + if e.Flags[nl.SEG6_LOCAL_NH6] { + strs = append(strs, fmt.Sprintf("nh6 %s", e.In6Addr)) + } + if e.Flags[nl.SEG6_LOCAL_IIF] { + link, err := LinkByIndex(e.Iif) + if err != nil { + strs = append(strs, fmt.Sprintf("iif %d", e.Iif)) + } else { + strs = append(strs, fmt.Sprintf("iif %s", link.Attrs().Name)) + } + } + if e.Flags[nl.SEG6_LOCAL_OIF] { + link, err := LinkByIndex(e.Oif) + if err != nil { + strs = append(strs, fmt.Sprintf("oif %d", e.Oif)) + } else { + strs = append(strs, fmt.Sprintf("oif %s", link.Attrs().Name)) + } + } + if e.Flags[nl.SEG6_LOCAL_SRH] { + segs := make([]string, 0, len(e.Segments)) + //append segment backwards (from n to 0) since seg#0 is the last segment. + for i := len(e.Segments); i > 0; i-- { + segs = append(segs, fmt.Sprintf("%s", e.Segments[i-1])) + } + strs = append(strs, fmt.Sprintf("segs %d [ %s ]", len(e.Segments), strings.Join(segs, " "))) + } + return strings.Join(strs, " ") +} +func (e *SEG6LocalEncap) Equal(x Encap) bool { + o, ok := x.(*SEG6LocalEncap) + if !ok { + return false + } + if e == o { + return true + } + if e == nil || o == nil { + return false + } + // compare all arrays first + for i := range e.Flags { + if e.Flags[i] != o.Flags[i] { + return false + } + } + if len(e.Segments) != len(o.Segments) { + return false + } + for i := range e.Segments { + if !e.Segments[i].Equal(o.Segments[i]) { + return false + } + } + // compare values + if !e.InAddr.Equal(o.InAddr) || !e.In6Addr.Equal(o.In6Addr) { + return false + } + if e.Action != o.Action || e.Table != o.Table || e.Iif != o.Iif || e.Oif != o.Oif { + return false + } + return true +} + // RouteAdd will add a route to the system. // Equivalent to: `ip route add $route` func RouteAdd(route *Route) error { @@ -335,18 +519,18 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg if err != nil { return err } - rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_NEWDST, buf)) + rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_NEWDST, buf)) } if route.Encap != nil { buf := make([]byte, 2) native.PutUint16(buf, uint16(route.Encap.Type())) - rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP_TYPE, buf)) + rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP_TYPE, buf)) buf, err := route.Encap.Encode() if err != nil { return err } - rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP, buf)) + rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP, buf)) } if route.Src != nil { @@ -410,17 +594,17 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg if err != nil { return err } - children = append(children, nl.NewRtAttr(nl.RTA_NEWDST, buf)) + children = append(children, nl.NewRtAttr(unix.RTA_NEWDST, buf)) } if nh.Encap != nil { buf := make([]byte, 2) native.PutUint16(buf, uint16(nh.Encap.Type())) - rtAttrs = append(rtAttrs, nl.NewRtAttr(nl.RTA_ENCAP_TYPE, buf)) + children = append(children, nl.NewRtAttr(unix.RTA_ENCAP_TYPE, buf)) buf, err := nh.Encap.Encode() if err != nil { return err } - children = append(children, nl.NewRtAttr(nl.RTA_ENCAP, buf)) + children = append(children, nl.NewRtAttr(unix.RTA_ENCAP, buf)) } rtnh.Children = children buf = append(buf, rtnh.Serialize()...) @@ -464,6 +648,10 @@ func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg b := nl.Uint32Attr(uint32(route.AdvMSS)) metrics = append(metrics, nl.NewRtAttr(unix.RTAX_ADVMSS, b)) } + if route.Hoplimit > 0 { + b := nl.Uint32Attr(uint32(route.Hoplimit)) + metrics = append(metrics, nl.NewRtAttr(unix.RTAX_HOPLIMIT, b)) + } if metrics != nil { attr := nl.NewRtAttr(unix.RTA_METRICS, nil) @@ -574,6 +762,8 @@ func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) continue } } + case filterMask&RT_FILTER_HOPLIMIT != 0 && route.Hoplimit != filter.Hoplimit: + continue } } res = append(res, route) @@ -649,7 +839,7 @@ func deserializeRoute(m []byte) (Route, error) { switch attr.Attr.Type { case unix.RTA_GATEWAY: info.Gw = net.IP(attr.Value) - case nl.RTA_NEWDST: + case unix.RTA_NEWDST: var d Destination switch msg.Family { case nl.FAMILY_MPLS: @@ -659,9 +849,9 @@ func deserializeRoute(m []byte) (Route, error) { return nil, nil, err } info.NewDst = d - case nl.RTA_ENCAP_TYPE: + case unix.RTA_ENCAP_TYPE: encapType = attr - case nl.RTA_ENCAP: + case unix.RTA_ENCAP: encap = attr } } @@ -690,7 +880,7 @@ func deserializeRoute(m []byte) (Route, error) { route.MultiPath = append(route.MultiPath, info) rest = buf } - case nl.RTA_NEWDST: + case unix.RTA_NEWDST: var d Destination switch msg.Family { case nl.FAMILY_MPLS: @@ -700,9 +890,9 @@ func deserializeRoute(m []byte) (Route, error) { return route, err } route.NewDst = d - case nl.RTA_ENCAP_TYPE: + case unix.RTA_ENCAP_TYPE: encapType = attr - case nl.RTA_ENCAP: + case unix.RTA_ENCAP: encap = attr case unix.RTA_METRICS: metrics, err := nl.ParseRouteAttr(attr.Value) @@ -715,6 +905,8 @@ func deserializeRoute(m []byte) (Route, error) { route.MTU = int(native.Uint32(metric.Value[0:4])) case unix.RTAX_ADVMSS: route.AdvMSS = int(native.Uint32(metric.Value[0:4])) + case unix.RTAX_HOPLIMIT: + route.Hoplimit = int(native.Uint32(metric.Value[0:4])) } } } @@ -734,6 +926,11 @@ func deserializeRoute(m []byte) (Route, error) { if err := e.Decode(encap.Value); err != nil { return route, err } + case nl.LWTUNNEL_ENCAP_SEG6_LOCAL: + e = &SEG6LocalEncap{} + if err := e.Decode(encap.Value); err != nil { + return route, err + } } route.Encap = e } @@ -840,13 +1037,19 @@ func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done < go func() { defer close(ch) for { - msgs, err := s.Receive() + msgs, from, err := s.Receive() if err != nil { if cberr != nil { cberr(err) } return } + if from.Pid != nl.PidKernel { + if cberr != nil { + cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)) + } + continue + } for _, m := range msgs { if m.Header.Type == unix.NLMSG_DONE { continue diff --git a/vendor/github.com/vishvananda/netlink/rule_linux.go b/vendor/github.com/vishvananda/netlink/rule_linux.go index 6238ae4586..e12569fe45 100644 --- a/vendor/github.com/vishvananda/netlink/rule_linux.go +++ b/vendor/github.com/vishvananda/netlink/rule_linux.go @@ -144,7 +144,7 @@ func ruleHandle(rule *Rule, req *nl.NetlinkRequest) error { req.AddData(nl.NewRtAttr(nl.FRA_OIFNAME, []byte(rule.OifName))) } if rule.Goto >= 0 { - msg.Type = nl.FR_ACT_NOP + msg.Type = nl.FR_ACT_GOTO b := make([]byte, 4) native.PutUint32(b, uint32(rule.Goto)) req.AddData(nl.NewRtAttr(nl.FRA_GOTO, b)) diff --git a/vendor/github.com/vishvananda/netlink/socket_linux.go b/vendor/github.com/vishvananda/netlink/socket_linux.go index 99e9fb4d89..c4d89c17ed 100644 --- a/vendor/github.com/vishvananda/netlink/socket_linux.go +++ b/vendor/github.com/vishvananda/netlink/socket_linux.go @@ -141,10 +141,13 @@ func SocketGet(local, remote net.Addr) (*Socket, error) { }, }) s.Send(req) - msgs, err := s.Receive() + msgs, from, err := s.Receive() if err != nil { return nil, err } + if from.Pid != nl.PidKernel { + return nil, fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel) + } if len(msgs) == 0 { return nil, errors.New("no message nor error from netlink") } diff --git a/vendor/github.com/vishvananda/netlink/xfrm_monitor_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_monitor_linux.go index efe72ddf29..985d3a915f 100644 --- a/vendor/github.com/vishvananda/netlink/xfrm_monitor_linux.go +++ b/vendor/github.com/vishvananda/netlink/xfrm_monitor_linux.go @@ -54,11 +54,15 @@ func XfrmMonitor(ch chan<- XfrmMsg, done <-chan struct{}, errorChan chan<- error go func() { defer close(ch) for { - msgs, err := s.Receive() + msgs, from, err := s.Receive() if err != nil { errorChan <- err return } + if from.Pid != nl.PidKernel { + errorChan <- fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel) + return + } for _, m := range msgs { switch m.Header.Type { case nl.XFRM_MSG_EXPIRE: diff --git a/vendor/github.com/vishvananda/netlink/xfrm_policy.go b/vendor/github.com/vishvananda/netlink/xfrm_policy.go index c97ec43a25..6219d27725 100644 --- a/vendor/github.com/vishvananda/netlink/xfrm_policy.go +++ b/vendor/github.com/vishvananda/netlink/xfrm_policy.go @@ -35,6 +35,25 @@ func (d Dir) String() string { return fmt.Sprintf("socket %d", d-XFRM_SOCKET_IN) } +// PolicyAction is an enum representing an ipsec policy action. +type PolicyAction uint8 + +const ( + XFRM_POLICY_ALLOW PolicyAction = 0 + XFRM_POLICY_BLOCK PolicyAction = 1 +) + +func (a PolicyAction) String() string { + switch a { + case XFRM_POLICY_ALLOW: + return "allow" + case XFRM_POLICY_BLOCK: + return "block" + default: + return fmt.Sprintf("action %d", a) + } +} + // XfrmPolicyTmpl encapsulates a rule for the base addresses of an ipsec // policy. These rules are matched with XfrmState to determine encryption // and authentication algorithms. @@ -64,11 +83,14 @@ type XfrmPolicy struct { Dir Dir Priority int Index int + Action PolicyAction + Ifindex int + Ifid int Mark *XfrmMark Tmpls []XfrmPolicyTmpl } func (p XfrmPolicy) String() string { - return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Mark: %s, Tmpls: %s}", - p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Mark, p.Tmpls) + return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Action: %s, Ifindex: %d, Ifid: %d, Mark: %s, Tmpls: %s}", + p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Action, p.Ifindex, p.Ifid, p.Mark, p.Tmpls) } diff --git a/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go index fde0c2ca5a..a4e132ef55 100644 --- a/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go +++ b/vendor/github.com/vishvananda/netlink/xfrm_policy_linux.go @@ -27,6 +27,7 @@ func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) { if sel.Sport != 0 { sel.SportMask = ^uint16(0) } + sel.Ifindex = int32(policy.Ifindex) } // XfrmPolicyAdd will add an xfrm policy to the system. @@ -61,6 +62,7 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error { msg.Priority = uint32(policy.Priority) msg.Index = uint32(policy.Index) msg.Dir = uint8(policy.Dir) + msg.Action = uint8(policy.Action) msg.Lft.SoftByteLimit = nl.XFRM_INF msg.Lft.HardByteLimit = nl.XFRM_INF msg.Lft.SoftPacketLimit = nl.XFRM_INF @@ -90,6 +92,9 @@ func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error { req.AddData(out) } + ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid))) + req.AddData(ifId) + _, err := req.Execute(unix.NETLINK_XFRM, 0) return err } @@ -183,6 +188,9 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo req.AddData(out) } + ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid))) + req.AddData(ifId) + resType := nl.XFRM_MSG_NEWPOLICY if nlProto == nl.XFRM_MSG_DELPOLICY { resType = 0 @@ -197,12 +205,7 @@ func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPo return nil, err } - p, err := parseXfrmPolicy(msgs[0], FAMILY_ALL) - if err != nil { - return nil, err - } - - return p, nil + return parseXfrmPolicy(msgs[0], FAMILY_ALL) } func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) { @@ -220,9 +223,11 @@ func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) { policy.Proto = Proto(msg.Sel.Proto) policy.DstPort = int(nl.Swap16(msg.Sel.Dport)) policy.SrcPort = int(nl.Swap16(msg.Sel.Sport)) + policy.Ifindex = int(msg.Sel.Ifindex) policy.Priority = int(msg.Priority) policy.Index = int(msg.Index) policy.Dir = Dir(msg.Dir) + policy.Action = PolicyAction(msg.Action) attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { @@ -249,6 +254,8 @@ func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) { policy.Mark = new(XfrmMark) policy.Mark.Value = mark.Value policy.Mark.Mask = mark.Mask + case nl.XFRMA_IF_ID: + policy.Ifid = int(native.Uint32(attr.Value)) } } diff --git a/vendor/github.com/vishvananda/netlink/xfrm_state.go b/vendor/github.com/vishvananda/netlink/xfrm_state.go index d14740dc55..483d8934a8 100644 --- a/vendor/github.com/vishvananda/netlink/xfrm_state.go +++ b/vendor/github.com/vishvananda/netlink/xfrm_state.go @@ -94,6 +94,8 @@ type XfrmState struct { Limits XfrmStateLimits Statistics XfrmStateStats Mark *XfrmMark + OutputMark int + Ifid int Auth *XfrmStateAlgo Crypt *XfrmStateAlgo Aead *XfrmStateAlgo @@ -102,8 +104,8 @@ type XfrmState struct { } func (sa XfrmState) String() string { - return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t", - sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN) + return fmt.Sprintf("Dst: %v, Src: %v, Proto: %s, Mode: %s, SPI: 0x%x, ReqID: 0x%x, ReplayWindow: %d, Mark: %v, OutputMark: %d, Ifid: %d, Auth: %v, Crypt: %v, Aead: %v, Encap: %v, ESN: %t", + sa.Dst, sa.Src, sa.Proto, sa.Mode, sa.Spi, sa.Reqid, sa.ReplayWindow, sa.Mark, sa.OutputMark, sa.Ifid, sa.Auth, sa.Crypt, sa.Aead, sa.Encap, sa.ESN) } func (sa XfrmState) Print(stats bool) string { if !stats { diff --git a/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go b/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go index 5dfdb33e44..66c99423c4 100644 --- a/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go +++ b/vendor/github.com/vishvananda/netlink/xfrm_state_linux.go @@ -158,6 +158,13 @@ func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error { out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow)) req.AddData(out) } + if state.OutputMark != 0 { + out := nl.NewRtAttr(nl.XFRMA_OUTPUT_MARK, nl.Uint32Attr(uint32(state.OutputMark))) + req.AddData(out) + } + + ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid))) + req.AddData(ifId) _, err := req.Execute(unix.NETLINK_XFRM, 0) return err @@ -184,12 +191,7 @@ func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) { return nil, err } - s, err := parseXfrmState(msgs[0], FAMILY_ALL) - if err != nil { - return nil, err - } - - return s, err + return parseXfrmState(msgs[0], FAMILY_ALL) } // XfrmStateDel will delete an xfrm state from the system. Note that @@ -275,6 +277,9 @@ func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState req.AddData(out) } + ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(state.Ifid))) + req.AddData(ifId) + resType := nl.XFRM_MSG_NEWSA if nlProto == nl.XFRM_MSG_DELSA { resType = 0 @@ -372,6 +377,10 @@ func parseXfrmState(m []byte, family int) (*XfrmState, error) { state.Mark = new(XfrmMark) state.Mark.Value = mark.Value state.Mark.Mask = mark.Mask + case nl.XFRMA_OUTPUT_MARK: + state.OutputMark = int(native.Uint32(attr.Value)) + case nl.XFRMA_IF_ID: + state.Ifid = int(native.Uint32(attr.Value)) } } @@ -394,11 +403,7 @@ func (h *Handle) XfrmStateFlush(proto Proto) error { req.AddData(&nl.XfrmUsersaFlush{Proto: uint8(proto)}) _, err := req.Execute(unix.NETLINK_XFRM, 0) - if err != nil { - return err - } - - return nil + return err } func limitsToLft(lmts XfrmStateLimits, lft *nl.XfrmLifetimeCfg) { diff --git a/vendor/golang.org/x/time/rate/rate.go b/vendor/golang.org/x/time/rate/rate.go index 563f70429a..a98fe77827 100644 --- a/vendor/golang.org/x/time/rate/rate.go +++ b/vendor/golang.org/x/time/rate/rate.go @@ -53,10 +53,9 @@ func Every(interval time.Duration) Limit { // // The methods AllowN, ReserveN, and WaitN consume n tokens. type Limiter struct { - limit Limit - burst int - mu sync.Mutex + limit Limit + burst int tokens float64 // last is the last time the limiter's tokens field was updated last time.Time @@ -76,6 +75,8 @@ func (lim *Limiter) Limit() Limit { // Burst values allow more events to happen at once. // A zero Burst allows no events, unless limit == Inf. func (lim *Limiter) Burst() int { + lim.mu.Lock() + defer lim.mu.Unlock() return lim.burst } @@ -196,7 +197,7 @@ func (lim *Limiter) Reserve() *Reservation { // ReserveN returns a Reservation that indicates how long the caller must wait before n events happen. // The Limiter takes this Reservation into account when allowing future events. -// ReserveN returns false if n exceeds the Limiter's burst size. +// The returned Reservation’s OK() method returns false if n exceeds the Limiter's burst size. // Usage example: // r := lim.ReserveN(time.Now(), 1) // if !r.OK() { @@ -229,7 +230,7 @@ func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) { lim.mu.Unlock() if n > burst && limit != Inf { - return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, lim.burst) + return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, burst) } // Check if ctx is already cancelled select { @@ -359,6 +360,7 @@ func (lim *Limiter) reserveN(now time.Time, n int, maxFutureReserve time.Duratio // advance calculates and returns an updated state for lim resulting from the passage of time. // lim is not changed. +// advance requires that lim.mu is held. func (lim *Limiter) advance(now time.Time) (newNow time.Time, newLast time.Time, newTokens float64) { last := lim.last if now.Before(last) { diff --git a/vendor/modules.txt b/vendor/modules.txt index d9604be327..3ee9e6eb81 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -386,7 +386,7 @@ github.com/elgatito/upnp # github.com/farsightsec/golang-framestream v0.0.0-20181102145529-8a0cb8ba8710 ## explicit github.com/farsightsec/golang-framestream -# github.com/fatih/color v1.10.0 +# github.com/fatih/color v1.13.0 ## explicit; go 1.13 github.com/fatih/color # github.com/fernet/fernet-go v0.0.0-20180830025343-9eac43b88a5e @@ -651,10 +651,10 @@ github.com/lestrrat/go-pdebug # github.com/libvirt/libvirt-go-xml v5.2.0+incompatible ## explicit github.com/libvirt/libvirt-go-xml -# github.com/ma314smith/signedxml v0.0.0-20200410192636-c342a2d0ae60 +# github.com/ma314smith/signedxml v0.0.0-20210628192057-abc5b481ae1c ## explicit github.com/ma314smith/signedxml -# github.com/mattn/go-colorable v0.1.8 +# github.com/mattn/go-colorable v0.1.9 ## explicit; go 1.13 github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.14 @@ -886,16 +886,16 @@ github.com/tklauser/go-sysconf # github.com/tklauser/numcpus v0.4.0 ## explicit; go 1.11 github.com/tklauser/numcpus -# github.com/tredoe/osutil v0.0.0-20161130133508-7d3ee1afa71c -## explicit +# github.com/tredoe/osutil v1.0.6 +## explicit; go 1.16 github.com/tredoe/osutil/user/crypt github.com/tredoe/osutil/user/crypt/common github.com/tredoe/osutil/user/crypt/sha512_crypt # github.com/ugorji/go/codec v1.1.7 ## explicit github.com/ugorji/go/codec -# github.com/vishvananda/netlink v1.0.0 -## explicit +# github.com/vishvananda/netlink v1.1.0 +## explicit; go 1.12 github.com/vishvananda/netlink github.com/vishvananda/netlink/nl # github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 @@ -1091,7 +1091,7 @@ golang.org/x/text/secure/bidirule golang.org/x/text/transform golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm -# golang.org/x/time v0.0.0-20191024005414-555d28b269f0 +# golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba ## explicit golang.org/x/time/rate # golang.org/x/tools v0.1.2 @@ -1428,6 +1428,85 @@ sigs.k8s.io/structured-merge-diff/v4/value # sigs.k8s.io/yaml v1.2.0 ## explicit; go 1.12 sigs.k8s.io/yaml +# yunion.io/x/cloudmux v0.3.10-0-alpha.0 +## explicit; go 1.18 +yunion.io/x/cloudmux/pkg/apis +yunion.io/x/cloudmux/pkg/apis/billing +yunion.io/x/cloudmux/pkg/apis/cloudid +yunion.io/x/cloudmux/pkg/apis/compute +yunion.io/x/cloudmux/pkg/cloudprovider +yunion.io/x/cloudmux/pkg/multicloud +yunion.io/x/cloudmux/pkg/multicloud/aliyun +yunion.io/x/cloudmux/pkg/multicloud/aliyun/provider +yunion.io/x/cloudmux/pkg/multicloud/apsara +yunion.io/x/cloudmux/pkg/multicloud/apsara/provider +yunion.io/x/cloudmux/pkg/multicloud/aws +yunion.io/x/cloudmux/pkg/multicloud/aws/provider +yunion.io/x/cloudmux/pkg/multicloud/azure +yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent +yunion.io/x/cloudmux/pkg/multicloud/azure/progress +yunion.io/x/cloudmux/pkg/multicloud/azure/provider +yunion.io/x/cloudmux/pkg/multicloud/bingocloud +yunion.io/x/cloudmux/pkg/multicloud/bingocloud/provider +yunion.io/x/cloudmux/pkg/multicloud/cloudpods +yunion.io/x/cloudmux/pkg/multicloud/cloudpods/provider +yunion.io/x/cloudmux/pkg/multicloud/ctyun +yunion.io/x/cloudmux/pkg/multicloud/ctyun/provider +yunion.io/x/cloudmux/pkg/multicloud/ecloud +yunion.io/x/cloudmux/pkg/multicloud/ecloud/provider +yunion.io/x/cloudmux/pkg/multicloud/esxi +yunion.io/x/cloudmux/pkg/multicloud/esxi/provider +yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter +yunion.io/x/cloudmux/pkg/multicloud/google +yunion.io/x/cloudmux/pkg/multicloud/google/provider +yunion.io/x/cloudmux/pkg/multicloud/hcs +yunion.io/x/cloudmux/pkg/multicloud/hcs/provider +yunion.io/x/cloudmux/pkg/multicloud/hcso +yunion.io/x/cloudmux/pkg/multicloud/hcso/client +yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth +yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials +yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signers +yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager +yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules +yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests +yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses +yunion.io/x/cloudmux/pkg/multicloud/hcso/provider +yunion.io/x/cloudmux/pkg/multicloud/huawei +yunion.io/x/cloudmux/pkg/multicloud/huawei/client +yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth +yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials +yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers +yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager +yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules +yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests +yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses +yunion.io/x/cloudmux/pkg/multicloud/huawei/obs +yunion.io/x/cloudmux/pkg/multicloud/huawei/provider +yunion.io/x/cloudmux/pkg/multicloud/incloudsphere +yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/provider +yunion.io/x/cloudmux/pkg/multicloud/jdcloud +yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider +yunion.io/x/cloudmux/pkg/multicloud/loader +yunion.io/x/cloudmux/pkg/multicloud/nutanix +yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider +yunion.io/x/cloudmux/pkg/multicloud/objectstore +yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph +yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider +yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider +yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky +yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/provider +yunion.io/x/cloudmux/pkg/multicloud/openstack +yunion.io/x/cloudmux/pkg/multicloud/openstack/provider +yunion.io/x/cloudmux/pkg/multicloud/proxmox +yunion.io/x/cloudmux/pkg/multicloud/proxmox/provider +yunion.io/x/cloudmux/pkg/multicloud/qcloud +yunion.io/x/cloudmux/pkg/multicloud/qcloud/provider +yunion.io/x/cloudmux/pkg/multicloud/remotefile +yunion.io/x/cloudmux/pkg/multicloud/remotefile/provider +yunion.io/x/cloudmux/pkg/multicloud/ucloud +yunion.io/x/cloudmux/pkg/multicloud/ucloud/provider +yunion.io/x/cloudmux/pkg/multicloud/zstack +yunion.io/x/cloudmux/pkg/multicloud/zstack/provider # yunion.io/x/executor v0.0.0-20211018100936-39a2cd966656 ## explicit; go 1.12 yunion.io/x/executor/apis diff --git a/vendor/yunion.io/x/cloudmux/LICENSE b/vendor/yunion.io/x/cloudmux/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/billing/billing_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/billing/billing_const.go new file mode 100644 index 0000000000..6d9e67e428 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/billing/billing_const.go @@ -0,0 +1,20 @@ +// Copyright 2019 Yunion +// +// 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 billing + +const ( + BILLING_TYPE_POSTPAID = "postpaid" + BILLING_TYPE_PREPAID = "prepaid" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/cloudid.go b/vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/cloudid.go new file mode 100644 index 0000000000..78a152bd3b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/cloudid.go @@ -0,0 +1,23 @@ +// Copyright 2019 Yunion +// +// 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 cloudid + +import "yunion.io/x/cloudmux/pkg/apis" + +const ( + SERVICE_TYPE = apis.SERVICE_TYPE_CLOUDID + SAML_IDP_PREFIX = "/api/saml/idp" + SERVICE_VERSION = "" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/cloudpolicy.go b/vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/cloudpolicy.go new file mode 100644 index 0000000000..b59babf6fc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/cloudpolicy.go @@ -0,0 +1,26 @@ +// Copyright 2019 Yunion +// +// 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 cloudid + +const ( + CLOUD_POLICY_STATUS_AVAILABLE = "available" + CLOUD_POLICY_STATUS_SYNCING = "syncing" + CLOUD_POLICY_STATUS_SYNC_FAILE = "sync_failed" + CLOUD_POLICY_STATUS_DELETING = "deleting" + CLOUD_POLICY_STATUS_DELETE_FAILED = "delete_failed" + + CLOUD_POLICY_TYPE_SYSTEM = "system" + CLOUD_POLICY_TYPE_CUSTOM = "custom" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/saml_provider.go b/vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/saml_provider.go new file mode 100644 index 0000000000..5ce32af350 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/cloudid/saml_provider.go @@ -0,0 +1,29 @@ +// Copyright 2019 Yunion +// +// 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 cloudid + +const ( + SAML_PROVIDER_STATUS_AVAILABLE = "available" + SAML_PROVIDER_STATUS_NOT_MATCH = "not_match" + SAML_PROVIDER_STATUS_DELETING = "deleting" + SAML_PROVIDER_STATUS_DELETE_FAILED = "delete_failed" + SAML_PROVIDER_STATUS_UNKNOWN = "unknown" + SAML_PROVIDER_STATUS_CREATING = "creating" + SAML_PROVIDER_STATUS_CREATE_FAILED = "create_failed" + SAML_PROVIDER_STATUS_UNVALIABLE = "unavailable" + SAML_PROVIDER_STATUS_UPDATE_METADATA = "update_metadata" + SAML_PROVIDER_STATUS_UPDATE_METADATA_FAILED = "update_metadata_failed" + SAML_PROVIDER_STATUS_SYNC = "sync" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/bucket.go new file mode 100644 index 0000000000..604d78974d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/bucket.go @@ -0,0 +1,33 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + BUCKET_OPS_STATS_CHANGE = "stats_change" + + BUCKET_STATUS_START_CREATE = "start_create" + BUCKET_STATUS_CREATING = "creating" + BUCKET_STATUS_READY = "ready" + BUCKET_STATUS_CREATE_FAIL = "create_fail" + BUCKET_STATUS_START_DELETE = "start_delete" + BUCKET_STATUS_DELETING = "deleting" + BUCKET_STATUS_DELETED = "deleted" + BUCKET_STATUS_DELETE_FAIL = "delete_fail" + BUCKET_STATUS_UNKNOWN = "unknown" + + BUCKET_UPLOAD_OBJECT_KEY_HEADER = "X-Yunion-Bucket-Upload-Key" + BUCKET_UPLOAD_OBJECT_ACL_HEADER = "X-Yunion-Bucket-Upload-Acl" + BUCKET_UPLOAD_OBJECT_STORAGECLASS_HEADER = "X-Yunion-Bucket-Upload-Storageclass" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cachedimages_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cachedimages_const.go new file mode 100644 index 0000000000..a80c85fe68 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cachedimages_const.go @@ -0,0 +1,32 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + CACHED_IMAGE_STATUS_INIT = "init" + CACHED_IMAGE_STATUS_SAVING = "saving" + CACHED_IMAGE_STATUS_CACHING = "caching" + CACHED_IMAGE_STATUS_ACTIVE = "active" + CACHED_IMAGE_STATUS_DELETING = "deleting" + CACHED_IMAGE_STATUS_CACHE_FAILED = "cache_fail" + CACHED_IMAGE_STATUS_UNKNOWN = "unknown" + + DOWNLOAD_SESSION_LENGTH = 3600 * 3 // 3 hour +) + +const ( + CACHED_IMAGE_REFRESH_SECONDS = 1 // 1 second + CACHED_IMAGE_REFERENCE_SESSION_EXPIRE_SECONDS = 86400 // 1 day +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cdn.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cdn.go new file mode 100644 index 0000000000..98dc694bb4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cdn.go @@ -0,0 +1,38 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + CDN_DOMAIN_STATUS_ONLINE = "online" + CDN_DOMAIN_STATUS_OFFLINE = "offline" + CDN_DOMAIN_STATUS_DELETING = "deleting" + CDN_DOMAIN_STATUS_DELETE_FAILED = "delete_failed" + CDN_DOMAIN_STATUS_PROCESSING = "processing" + CDN_DOMAIN_STATUS_REJECTED = "rejected" + CDN_DOMAIN_STATUS_UNKNOWN = "unknown" + + CDN_DOMAIN_AREA_MAINLAND = "mainland" + CDN_DOMAIN_AREA_OVERSEAS = "overseas" + CDN_DOMAIN_AREA_GLOBAL = "global" + CDN_DOMAIN_ORIGIN_TYPE_DOMAIN = "domain" + CDN_DOMAIN_ORIGIN_TYPE_IP = "ip" + CDN_DOMAIN_ORIGIN_TYPE_BUCKET = "bucket" + CDN_DOMAIN_ORIGIN_THIRED_PARTY = "third_party" + + // Qcloud + CDN_SERVICE_TYPE_WEB = "web" // 静态加速 + CND_SERVICE_TYPE_DOWNLOAD = "download" // 下载加速 + CND_SERVICE_TYPE_MEDIA = "media" // 流媒体点播加速 +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cloudaccount_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cloudaccount_const.go new file mode 100644 index 0000000000..b68057406e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cloudaccount_const.go @@ -0,0 +1,265 @@ +// Copyright 2019 Yunion +// +// 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 compute + +import ( + "yunion.io/x/onecloud/pkg/util/choices" + + "yunion.io/x/cloudmux/pkg/apis" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + CLOUD_PROVIDER_INIT = "init" + CLOUD_PROVIDER_CONNECTED = "connected" + CLOUD_PROVIDER_DISCONNECTED = "disconnected" + CLOUD_PROVIDER_START_DELETE = "start_delete" + CLOUD_PROVIDER_DELETING = "deleting" + CLOUD_PROVIDER_DELETED = "deleted" + CLOUD_PROVIDER_DELETE_FAILED = "delete_failed" + CLOUD_PROVIDER_SYNC_NETWORK = "sync_network" + + CLOUD_PROVIDER_SYNC_STATUS_QUEUING = "queuing" + CLOUD_PROVIDER_SYNC_STATUS_QUEUED = "queued" + CLOUD_PROVIDER_SYNC_STATUS_SYNCING = "syncing" + CLOUD_PROVIDER_SYNC_STATUS_IDLE = "idle" + CLOUD_PROVIDER_SYNC_STATUS_ERROR = "error" + + CLOUD_PROVIDER_ONECLOUD = "OneCloud" + CLOUD_PROVIDER_VMWARE = "VMware" + CLOUD_PROVIDER_NUTANIX = "Nutanix" + CLOUD_PROVIDER_ALIYUN = "Aliyun" + CLOUD_PROVIDER_APSARA = "Apsara" + CLOUD_PROVIDER_QCLOUD = "Qcloud" + CLOUD_PROVIDER_AZURE = "Azure" + CLOUD_PROVIDER_AWS = "Aws" + CLOUD_PROVIDER_HUAWEI = "Huawei" + CLOUD_PROVIDER_HCSO = "HCSO" + CLOUD_PROVIDER_HCS = "HCS" + CLOUD_PROVIDER_OPENSTACK = "OpenStack" + CLOUD_PROVIDER_UCLOUD = "Ucloud" + CLOUD_PROVIDER_ZSTACK = "ZStack" + CLOUD_PROVIDER_GOOGLE = "Google" + CLOUD_PROVIDER_CTYUN = "Ctyun" + CLOUD_PROVIDER_ECLOUD = "Ecloud" + CLOUD_PROVIDER_JDCLOUD = "JDcloud" + CLOUD_PROVIDER_CLOUDPODS = "Cloudpods" + CLOUD_PROVIDER_BINGO_CLOUD = "BingoCloud" + CLOUD_PROVIDER_INCLOUD_SPHERE = "InCloudSphere" + CLOUD_PROVIDER_PROXMOX = "Proxmox" + CLOUD_PROVIDER_REMOTEFILE = "RemoteFile" + + CLOUD_PROVIDER_GENERICS3 = "S3" + CLOUD_PROVIDER_CEPH = "Ceph" + CLOUD_PROVIDER_XSKY = "Xsky" + + CLOUD_PROVIDER_HEALTH_NORMAL = "normal" // 远端处于健康状态 + CLOUD_PROVIDER_HEALTH_INSUFFICIENT = "insufficient" // 不足按需资源余额 + CLOUD_PROVIDER_HEALTH_SUSPENDED = "suspended" // 远端处于冻结状态 + CLOUD_PROVIDER_HEALTH_ARREARS = "arrears" // 远端处于欠费状态 + CLOUD_PROVIDER_HEALTH_UNKNOWN = "unknown" // 未知状态,查询失败 + CLOUD_PROVIDER_HEALTH_NO_PERMISSION = "no permission" // 没有权限获取账单信息 + + ZSTACK_BRAND_DSTACK = "DStack" + ONECLOUD_BRAND_ONECLOUD = "OneCloud" + + CLOUD_ACCOUNT_WIRE_LEVEL_VCENTER = "vcenter" + CLOUD_ACCOUNT_WIRE_LEVEL_DATACENTER = "datacenter" + CLOUD_ACCOUNT_WIRE_LEVEL_CLUSTER = "cluster" +) + +var CLOUD_ACCOUNT_WIRE_LEVELS = choices.NewChoices( + CLOUD_ACCOUNT_WIRE_LEVEL_VCENTER, + CLOUD_ACCOUNT_WIRE_LEVEL_DATACENTER, + CLOUD_ACCOUNT_WIRE_LEVEL_CLUSTER, +) + +const ( + CLOUD_ACCESS_ENV_AWS_GLOBAL = CLOUD_PROVIDER_AWS + "-int" + CLOUD_ACCESS_ENV_AWS_CHINA = CLOUD_PROVIDER_AWS + CLOUD_ACCESS_ENV_AZURE_GLOBAL = CLOUD_PROVIDER_AZURE + "-int" + CLOUD_ACCESS_ENV_AZURE_GERMAN = CLOUD_PROVIDER_AZURE + "-de" + CLOUD_ACCESS_ENV_AZURE_US_GOVERNMENT = CLOUD_PROVIDER_AZURE + "-us-gov" + CLOUD_ACCESS_ENV_AZURE_CHINA = CLOUD_PROVIDER_AZURE + CLOUD_ACCESS_ENV_HUAWEI_GLOBAL = CLOUD_PROVIDER_HUAWEI + "-int" + CLOUD_ACCESS_ENV_HUAWEI_CHINA = CLOUD_PROVIDER_HUAWEI + CLOUD_ACCESS_ENV_ALIYUN_GLOBAL = CLOUD_PROVIDER_ALIYUN + CLOUD_ACCESS_ENV_ALIYUN_FINANCE = CLOUD_PROVIDER_ALIYUN + "-fin" + CLOUD_ACCESS_ENV_CTYUN_CHINA = CLOUD_PROVIDER_CTYUN + CLOUD_ACCESS_ENV_ECLOUD_CHINA = CLOUD_PROVIDER_ECLOUD + CLOUD_ACCESS_ENV_JDCLOUD_CHINA = CLOUD_PROVIDER_JDCLOUD +) + +var ( + CLOUD_PROVIDER_VALID_STATUS = []string{CLOUD_PROVIDER_CONNECTED} + CLOUD_PROVIDER_VALID_HEALTH_STATUS = []string{CLOUD_PROVIDER_HEALTH_NORMAL, CLOUD_PROVIDER_HEALTH_NO_PERMISSION} + PRIVATE_CLOUD_PROVIDERS = []string{CLOUD_PROVIDER_ZSTACK, CLOUD_PROVIDER_OPENSTACK, CLOUD_PROVIDER_APSARA, + CLOUD_PROVIDER_HCSO, CLOUD_PROVIDER_HCS, CLOUD_PROVIDER_INCLOUD_SPHERE, CLOUD_PROVIDER_PROXMOX, CLOUD_PROVIDER_REMOTEFILE} + + CLOUD_PROVIDERS = []string{ + CLOUD_PROVIDER_ONECLOUD, + CLOUD_PROVIDER_VMWARE, + CLOUD_PROVIDER_ALIYUN, + CLOUD_PROVIDER_APSARA, + CLOUD_PROVIDER_QCLOUD, + CLOUD_PROVIDER_AZURE, + CLOUD_PROVIDER_AWS, + CLOUD_PROVIDER_HUAWEI, + CLOUD_PROVIDER_HCSO, + CLOUD_PROVIDER_HCS, + CLOUD_PROVIDER_OPENSTACK, + CLOUD_PROVIDER_UCLOUD, + CLOUD_PROVIDER_ZSTACK, + CLOUD_PROVIDER_GOOGLE, + CLOUD_PROVIDER_CTYUN, + CLOUD_PROVIDER_ECLOUD, + CLOUD_PROVIDER_JDCLOUD, + CLOUD_PROVIDER_CLOUDPODS, + CLOUD_PROVIDER_NUTANIX, + CLOUD_PROVIDER_BINGO_CLOUD, + CLOUD_PROVIDER_INCLOUD_SPHERE, + CLOUD_PROVIDER_PROXMOX, + CLOUD_PROVIDER_REMOTEFILE, + } + + CLOUD_PROVIDER_HOST_TYPE_MAP = map[string][]string{ + CLOUD_PROVIDER_ONECLOUD: { + HOST_TYPE_KVM, + HOST_TYPE_BAREMETAL, + HOST_TYPE_HYPERVISOR, + }, + CLOUD_PROVIDER_VMWARE: { + HOST_TYPE_ESXI, + }, + CLOUD_PROVIDER_ALIYUN: { + HOST_TYPE_ALIYUN, + }, + CLOUD_PROVIDER_APSARA: { + HOST_TYPE_APSARA, + }, + CLOUD_PROVIDER_QCLOUD: { + HOST_TYPE_QCLOUD, + }, + CLOUD_PROVIDER_AZURE: { + HOST_TYPE_AZURE, + }, + CLOUD_PROVIDER_AWS: { + HOST_TYPE_AWS, + }, + CLOUD_PROVIDER_HUAWEI: { + HOST_TYPE_HUAWEI, + }, + CLOUD_PROVIDER_HCSO: { + HOST_TYPE_HCSO, + }, + CLOUD_PROVIDER_HCS: { + HOST_TYPE_HCS, + }, + CLOUD_PROVIDER_OPENSTACK: { + HOST_TYPE_OPENSTACK, + }, + CLOUD_PROVIDER_UCLOUD: { + HOST_TYPE_UCLOUD, + }, + CLOUD_PROVIDER_ZSTACK: { + HOST_TYPE_ZSTACK, + }, + CLOUD_PROVIDER_GOOGLE: { + HOST_TYPE_GOOGLE, + }, + CLOUD_PROVIDER_CTYUN: { + HOST_TYPE_CTYUN, + }, + CLOUD_PROVIDER_ECLOUD: { + HOST_TYPE_ECLOUD, + }, + CLOUD_PROVIDER_JDCLOUD: { + HOST_TYPE_JDCLOUD, + }, + CLOUD_PROVIDER_CLOUDPODS: { + HOST_TYPE_CLOUDPODS, + }, + CLOUD_PROVIDER_NUTANIX: { + HOST_TYPE_NUTANIX, + }, + CLOUD_PROVIDER_BINGO_CLOUD: { + HOST_TYPE_BINGO_CLOUD, + }, + CLOUD_PROVIDER_INCLOUD_SPHERE: { + HOST_TYPE_INCLOUD_SPHERE, + }, + CLOUD_PROVIDER_PROXMOX: { + HOST_TYPE_PROXMOX, + }, + CLOUD_PROVIDER_REMOTEFILE: { + HOST_TYPE_REMOTEFILE, + }, + } +) + +const ( + CLOUD_ENV_PUBLIC_CLOUD = cloudprovider.CLOUD_ENV_PUBLIC_CLOUD + CLOUD_ENV_PRIVATE_CLOUD = cloudprovider.CLOUD_ENV_PRIVATE_CLOUD + CLOUD_ENV_ON_PREMISE = cloudprovider.CLOUD_ENV_ON_PREMISE + + CLOUD_ENV_PRIVATE_ON_PREMISE = cloudprovider.CLOUD_ENV_PRIVATE_ON_PREMISE +) + +const ( + CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN = apis.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN + CLOUD_ACCOUNT_SHARE_MODE_SYSTEM = apis.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM + CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN = apis.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN +) + +var ( + CLOUD_ACCOUNT_SHARE_MODES = []string{ + CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN, + CLOUD_ACCOUNT_SHARE_MODE_SYSTEM, + CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN, + } + + CLOUD_ENV_MAP = map[string]map[string]string{ + CLOUD_PROVIDER_AZURE: { + "AzureGermanCloud": CLOUD_ACCESS_ENV_AZURE_GERMAN, + "AzureChinaCloud": CLOUD_ACCESS_ENV_AZURE_CHINA, + "AzureUSGovernmentCloud": CLOUD_ACCESS_ENV_AZURE_US_GOVERNMENT, + "AzurePublicCloud": CLOUD_ACCESS_ENV_AZURE_GLOBAL, + }, + CLOUD_PROVIDER_AWS: { + "InternationalCloud": CLOUD_ACCESS_ENV_AWS_GLOBAL, + "ChinaCloud": CLOUD_ACCESS_ENV_AWS_CHINA, + }, + CLOUD_PROVIDER_HUAWEI: { + "InternationalCloud": CLOUD_ACCESS_ENV_HUAWEI_GLOBAL, + "ChinaCloud": CLOUD_ACCESS_ENV_HUAWEI_CHINA, + }, + CLOUD_PROVIDER_ALIYUN: { + "InternationalCloud": CLOUD_PROVIDER_ALIYUN, + "FinanceCloud": CLOUD_ACCESS_ENV_ALIYUN_FINANCE, + }, + } +) + +func GetCloudEnv(provider, accessUrl string) string { + envMap, ok := CLOUD_ENV_MAP[provider] + if !ok { + return provider + } + env, ok := envMap[accessUrl] + if !ok { + return provider + } + return env +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cloudregions_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cloudregions_const.go new file mode 100644 index 0000000000..78d408eaaa --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/cloudregions_const.go @@ -0,0 +1,233 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + CLOUD_REGION_STATUS_INSERVER = "inservice" + CLOUD_REGION_STATUS_OUTOFSERVICE = "outofservice" + + DEFAULT_REGION_ID = "default" + + // 中国 + CITY_QING_DAO = "Qingdao" //青岛 + CITY_BEI_JING = "Beijing" //北京 + CITY_ZHANG_JIA_KOU = "Zhangjiakou" //张家口 + CITY_HU_HE_HAO_TE = "Huhehaote" //呼和浩特 + CITY_HANG_ZHOU = "Hangzhou" //杭州 + CITY_SHANG_HAI = "Shanghai" //上海 + CITY_SHEN_ZHEN = "Shenzhen" //深圳 + CITY_HONG_KONG = "Hongkong" //香港 + CITY_NING_XIA = "Ningxia" //宁夏 + CITY_GUANG_ZHOU = "Guangzhou" //广州 + CITY_TAI_WAN = "Taiwan" //台湾 + CITY_GUI_YANG = "Guiyang" //贵阳 + CITY_TAIPEI = "Taipei" //台北市 + CITY_KAOHSIUNG = "Kaohsiung" //高雄市 + CITY_CHENG_DU = "Chengdu" //成都 + CITY_HE_YUAN = "HeYuan" //河源 + CITY_CHONG_QING = "Chongqing" //重庆 + CITY_LAN_ZHOU = "Lanzhou" //兰州 + CITY_TAI_YUAN = "Taiyuan" //太原 + CITY_TIAN_JIN = "Tianjin" //天津 + CITY_WU_LU_MU_QI = "Wulumuqi" //乌鲁木齐 + CITY_NAN_NING = "Nanning" //南宁 + CITY_ZHENG_ZHOU = "Zhengzhou" //郑州 + CITY_KUN_MING = "Kunming" //昆明 + CITY_XI_AN = "Xian" //西安 + CITY_HAI_KOU = "Haikou" //海口 + CITY_WU_HU = "Wuhu" //芜湖 + CITY_FU_ZHOU = "Fuzhou" //福州 + CITY_WU_HAN = "Wuhan" //武汉 + CITY_CHANG_SHA = "Changsha" //长沙 + CITY_SU_ZHOU = "Suzhou" //苏州 + CITY_BAO_DING = "Baoding" //保定 + CITY_NAN_JING = "Nanjing" //南京 + CITY_FO_SHAN = "Foshan" //佛山 + CITY_QUAN_ZHOU = "Quanzhou" //泉州 + CITY_NEI_MENG_GU = "Neimenggu" //内蒙古 + CITY_WU_LAN_CHA_BU = "Wulanchabu" //乌兰察布 + CITY_JI_NAM = "JiNan" //济南 + CITY_CHANG_CHUN = "ChangChun" //长春 + CITY_XIANG_YANG = "XiangYang" //襄阳 + CITY_NAN_CHANG = "NanChang" //南昌 + CITY_SHEN_YANG = "ShenYang" //沈阳 + CITY_SHI_JIA_ZHUANG = "ShiJiaZhuang" //石家庄 + CITY_XIA_MEN = "XiaMen" //厦门 + CITY_HUAI_NAN = "HuaiNan" //淮南 + CITY_SU_QIAN = "SuQian" //宿迁 + CITY_DA_LIAN = "Dalian" //大连 + + // 日本 + CITY_TOKYO = "Tokyo" //东京 + CITY_OSAKA = "Osaka" //大阪市 + + // 新加坡 + CITY_SINGAPORE = "Singapore" //新加坡 + + // 澳大利亚 + CITY_SYDNEY = "Sydney" //悉尼 + CITY_YARRALUMLA = "Yarralumla" //亚拉伦拉 + CITY_MELBOURNE = "Melbourne" //墨尔本 + + //芬兰 + CITY_FINLAND = "Finland" + + //比利时 + CITY_BELGIUM = "Belgium" //比利时 + + //瑞士 + CITY_ZURICH = "Zurich" //苏黎世 + CITY_GENEVA = "Geneva" //日内瓦 + + // 挪威 + CITY_STAVANGER = "Stavanger" //斯塔万格 + CITY_OSLO = "Oslo" // 奥斯陆 + + // 马来西亚 + CITY_KUALA_LUMPUR = "Kuala Lumpur" //吉隆坡 + + // 印度尼西亚 + CITY_JAKARTA = "Jakarta" //雅加达 + + // 印度 + CITY_DELHI = "Delhi" // 德里 + CITY_MUMBAI = "Mumbai" //孟买 + CITY_KANCHIPURAM = "Kanchipuram" //甘吉布勒姆 + CITY_MAHARASHTRA = "Maharashtra" //马哈拉施特拉邦 + CITY_JAMNAGAR = "Jamnagar" //贾姆讷格尔 + CITY_NAGPUR = "Nagpur" //那格浦尔 + + // 美国 + CITY_VIRGINIA = "Virginia" //弗吉尼亚 + CITY_SILICONVALLEY = "Siliconvalley" //硅谷 + CITY_OHIO = "Ohio" //俄亥俄州 + CITY_N_VIRGINIA = "N. Virginia" //北弗吉尼亚 + CITY_N_CALIFORNIA = "N. California" //北加州 + CITY_OREGON = "Oregon" //俄勒冈州 + CITY_LOS_ANGELES = "Los Angeles" //洛杉矶 + CITY_SAN_FRANCISCO = "San Francisco" //旧金山 + CITY_UTAH = "Utah" //犹他州 + CITY_WASHINGTON = "Washington" //华盛顿 + CITY_TEXAS = "Texas" //德克萨斯 + CITY_CHICAGO = "Chicago" //芝加哥 + CITY_IOWA = "Iowa" //爱荷华 + CITY_US_GOV_WEST = "us-gov-west" //??? + CITY_SOUTH_CAROLINA = "South Carolina" //南卡罗来纳州 + CITY_SALT_LAKE_CITY = "Salt Lake City" //盐湖城 + CITY_LAS_VEGAS = "Las Vegas" //拉斯维加斯 + CITY_PHOENIX = "Phoenix" //菲尼克斯 + + // 英国 + CITY_LONDON = "London" //伦敦 + CITY_HALTON = "Halton" //哈尔顿 + CITY_WEST_SUSSEX = "West Sussex" //西苏塞克斯 + + // 阿拉伯联合酋长国 + CITY_DUBAI = "Dubai" //迪拜 + + // 德国 + CITY_FRANKFURT = "Frankfurt" // 法兰克福 + CITY_DELMENHORST = "Delmenhorst" // 代尔门霍斯特 + + // 韩国 + CITY_SEOUL = "Seoul" //首尔 + CITY_BUSAN = "Busan" //釜山 + + // 加拿大 + CITY_CANADA_CENTRAL = "Canada Central" //加拿大中部 + CITY_QUEBEC = "Quebec" //魁北克市 + CITY_TORONTO = "Toronto" //多伦多 + CITY_MONTREAL = "Montreal" //蒙特利尔 + + // 爱尔兰 + CITY_IRELAND = "Ireland" //爱尔兰 + CITY_DUBLIN = "Dublin" //都柏林 + + // 法国 + CITY_PARIS = "Paris" //巴黎 + CITY_ALLIER = "Allier" //阿利埃河 + CITY_TARN = "Tarn" //塔恩 + + // 瑞典 + CITY_STOCKHOLM = "Stockholm" //斯德哥尔摩 + + // 波兰 + CITY_WARSAW = "Warsaw" // 华沙 + + // 巴西 + CITY_SAO_PAULO = "Sao Paulo" //圣保罗 + CITY_RIO_DE_JANEIRO = "Rio de Janeiro" // 里约热内卢 + + // 智利 + CITY_SANTIAGO = "Santiago" // 圣地亚哥 + + // 墨西哥 + CITY_MEXICO = "Mexico" // 墨西哥 + + // 荷兰 + CITY_HOLLAND = "Holland" //荷兰 + + // 南非 + CITY_PRETORIA = "Pretoria" //比勒陀利亚 + CITY_CAPE_TOWN = "Cape Town" //开普敦 + CITY_JOHANNESBURG = "Johannesburg" //约翰内斯堡 + + // 泰国 + CITY_BANGKOK = "Bangkok" //曼谷 + + // 俄罗斯 + CITY_MOSCOW = "Moscow" //莫斯科 + + // 尼日利亚 + CITY_LAGOS = "Lagos" //拉哥斯 + + // 巴林王国 (中东国家) + CITY_BAHRAIN = "Bahrain" // 巴林 + + // 越南 + CITY_HO_CHI_MINH = "Ho Chi Minh" //??? + + COUNTRY_CODE_CN = "CN" //中国 + COUNTRY_CODE_JP = "JP" //日本 + COUNTRY_CODE_SG = "SG" //新加坡 + COUNTRY_CODE_AU = "AU" //澳大利亚 + COUNTRY_CODE_MY = "MY" //马来西亚 + COUNTRY_CODE_ID = "ID" //印度尼西亚 + COUNTRY_CODE_IN = "IN" //印度 + COUNTRY_CODE_US = "US" //美国 + COUNTRY_CODE_GB = "GB" //英国 + COUNTRY_CODE_AE = "AE" //阿拉伯联合酋长国 + COUNTRY_CODE_DE = "DE" //德国 + COUNTRY_CODE_KR = "KR" //韩国 + COUNTRY_CODE_CA = "CA" //加拿大 + COUNTRY_CODE_IE = "IE" //爱尔兰 + COUNTRY_CODE_FR = "FR" //法国 + COUNTRY_CODE_SE = "SE" //瑞典 + COUNTRY_CODE_BR = "BR" //巴西 + COUNTRY_CODE_NL = "NL" //荷兰 + COUNTRY_CODE_ZA = "ZA" //南非 + COUNTRY_CODE_TH = "TH" //泰国 + COUNTRY_CODE_RU = "RU" //俄罗斯 + COUNTRY_CODE_NG = "NG" //尼日利亚 + COUNTRY_CODE_VN = "VN" //越南 + COUNTRY_CODE_CH = "CH" //瑞士 + COUNTRY_CODE_NO = "NO" //挪威 + COUNTRY_CODE_MX = "MX" //墨西哥 + COUNTRY_CODE_CL = "CL" //智利 + COUNTRY_CODE_BH = "BH" //巴林 + COUNTRY_CODE_PL = "PL" //波兰 + COUNTRY_CODE_FI = "FI" //芬兰 + COUNTRY_CODE_BE = "BE" //比利时 +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dbinstance_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dbinstance_const.go new file mode 100644 index 0000000000..43b1c1b405 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dbinstance_const.go @@ -0,0 +1,187 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + //实例状态 + DBINSTANCE_INIT = "init" //初始化 + DBINSTANCE_DEPLOYING = "deploying" //部署中 + DBINSTANCE_RUNNING = "running" //运行中 + DBINSTANCE_REBOOTING = "rebooting" //重启中 + DBINSTANCE_MIGRATING = "migrating" //迁移中 + DBINSTANCE_BACKING_UP = "backing_up" //备份中 + DBINSTANCE_BACKING_UP_FAILED = "backing_up_failed" //备份失败 + DBINSTANCE_RESTORING = "restoring" //备份恢复中 + DBINSTANCE_RESTORE_FAILED = "restore_failed" + DBINSTANCE_IMPORTING = "importing" //数据导入中 + DBINSTANCE_CLONING = "cloning" //克隆中 + DBINSTANCE_DELETING = "deleting" //删除中 + DBINSTANCE_DELETE_FAILED = "delete_failed" //删除失败 + DBINSTANCE_MAINTENANCE = "maintenance" //维护中 + DBINSTANCE_ISOLATING = "isolating" //隔离中 + DBINSTANCE_ISOLATE = "isolate" //已隔离 + DBINSTANCE_UPGRADING = "upgrading" //升级中 + DBINSTANCE_SET_AUTO_RENEW = "set_auto_renew" //设置自动续费中 + DBINSTANCE_SET_AUTO_RENEW_FAILED = "set_auto_renew_failed" //设置自动续费失败 + DBINSTANCE_UNKNOWN = "unknown" + DBINSTANCE_SYNC_SECGROUP_FAILED = "sync_secgroup_failed" // 同步安全组失败 + + DBINSTANCE_CHANGE_CONFIG = "change_config" //调整配置 + DBINSTANCE_CHANGE_CONFIG_FAILED = "change_config_failed" //调整配置失败 + + DBINSTANCE_RENEWING = "renewing" //续费中 + DBINSTANCE_RENEW_FAILED = "renew_failed" //续费失败 + + DBINSTANCE_SYNC_CONFIG = "sync_config" //同步配置 + + DBINSTANCE_REBOOT_FAILED = "reboot_failed" //重启失败 + DBINSTANCE_CREATE_FAILED = "create_failed" //创建失败 + + DBINSTANCE_FAILE = "failed" //操作失败 + + DBINSTANCE_UPDATE_TAGS = "update_tags" + DBINSTANCE_UPDATE_TAGS_FAILED = "update_tags_fail" + + //备份状态 + DBINSTANCE_BACKUP_READY = "ready" //正常 + DBINSTANCE_BACKUP_CREATING = "creating" //创建中 + DBINSTANCE_BACKUP_CREATE_FAILED = "create_failed" //创建失败 + DBINSTANCE_BACKUP_DELETING = "deleting" //删除中 + DBINSTANCE_BACKUP_DELETE_FAILED = "delete_failed" //删除失败 + DBINSTANCE_BACKUP_FAILED = "failed" //异常 + DBINSTANCE_BACKUP_UNKNOWN = "unknown" //未知 + + //备份模式 + BACKUP_MODE_AUTOMATED = "automated" //自动 + BACKUP_MODE_MANUAL = "manual" //手动 + + //实例数据库状态 + DBINSTANCE_DATABASE_CREATING = "creating" //创建中 + DBINSTANCE_DATABASE_CREATE_FAILE = "create_failed" //创建失败 + DBINSTANCE_DATABASE_RUNNING = "running" //正常 + DBINSTANCE_DATABASE_GRANT_PRIVILEGE = "grant_privilege" //赋予权限中 + DBINSTANCE_DATABASE_DELETING = "deleting" //删除中 + DBINSTANCE_DATABASE_DELETE_FAILED = "delete_failed" //删除失败 + + //实例用户状态 + DBINSTANCE_USER_UNAVAILABLE = "unavailable" //不可用 + DBINSTANCE_USER_AVAILABLE = "available" //正常 + DBINSTANCE_USER_CREATING = "creating" //创建中 + DBINSTANCE_USER_CREATE_FAILED = "create_failed" //创建失败 + DBINSTANCE_USER_DELETING = "deleting" //删除中 + DBINSTANCE_USER_DELETE_FAILED = "delete_failed" //删除失败 + DBINSTANCE_USER_RESET_PASSWD = "reset_passwd" //重置密码中 + DBINSTANCE_USER_GRANT_PRIVILEGE = "grant_privilege" //赋予权限中 + DBINSTANCE_USER_SET_PRIVILEGE = "set_privilege" //设置权限中 + DBINSTANCE_USER_REVOKE_PRIVILEGE = "revoke_privilege" //解除权限中 + DBINSTANCE_USER_RESET_PASSWD_FAILED = "reset_passwd_failed" //重置密码失败 + + //数据库权限 + DATABASE_PRIVILEGE_RW = "rw" //读写 + DATABASE_PRIVILEGE_R = "r" //只读 + DATABASE_PRIVILEGE_DDL = "ddl" + DATABASE_PRIVILEGE_DML = "dml" + DATABASE_PRIVILEGE_OWNER = "owner" + DATABASE_PRIVILEGE_CUSTOM = "custom" //自定义 + + DBINSTANCE_TYPE_MYSQL = "MySQL" + DBINSTANCE_TYPE_SQLSERVER = "SQLServer" + DBINSTANCE_TYPE_POSTGRESQL = "PostgreSQL" + DBINSTANCE_TYPE_MARIADB = "MariaDB" + DBINSTANCE_TYPE_ORACLE = "Oracle" + DBINSTANCE_TYPE_PPAS = "PPAS" + DBINSTANCE_TYPE_PERCONA = "Percona" + DBINSTANCE_TYPE_AURORA = "Aurora" + + //阿里云实例类型 + ALIYUN_DBINSTANCE_CATEGORY_BASIC = "basic" //基础版 + ALIYUN_DBINSTANCE_CATEGORY_HA = "high_availability" //高可用 + ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON = "always_on" //集群版 + ALIYUN_DBINSTANCE_CATEGORY_FINANCE = "finance" //金融版 + + //腾讯云实例类型 + QCLOUD_DBINSTANCE_CATEGORY_BASIC = "basic" //基础版 + QCLOUD_DBINSTANCE_CATEGORY_HA = "ha" //高可用 + QCLOUD_DBINSTANCE_CATEGORY_FINANCE = "fe" //金融版 + QCLOUD_DBINSTANCE_CATEGORY_TDSQL = "tdsql" //TDSQL + + //华为云实例类型 + HUAWEI_DBINSTANCE_CATEGORY_HA = "ha" //主备 + HUAWEI_DBINSTANCE_CATEGORY_SINGLE = "single" //单机 + HUAWEI_DBINSTANCE_CATEGORY_REPLICA = "replica" //只读 + + //谷歌云实例类型 + GOOGLE_DBINSTANCE_CATEGORY_REGIONAL = "Regional" // 高可用性(区域级) + GOOGLE_DBINSTANCE_CATEGORY_ZONAL = "Zonal" // 单个地区 + + // Azure + AZURE_DBINSTANCE_CATEGORY_BASIC = "basic" + + // Aws + // SQLServer + AWS_DBINSTANCE_CATEGORY_ENTERPRISE_EDITION = "Enterprise Edition" + AWS_DBINSTANCE_CATEGORY_EXPRESS_EDITION = "Express Edition" + AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION = "Standard Edition" + AWS_DBINSTANCE_CATEGORY_WEB_EDITION = "Web Edition" + // Oracle + AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION_TWO = "Standard Edition Two" + + AWS_DBINSTANCE_CATEGORY_GENERAL_PURPOSE = "General Purpose" + AWS_DBINSTANCE_CATEGORY_MEMORY_OPTIMIZED = "Memory Optimized" + + //阿里云存储类型 + ALIYUN_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD = "local_ssd" //本地盘SSD盘 + ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_ESSD = "cloud_essd" //ESSD云盘 + ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD = "cloud_ssd" //SSD云盘 + + //华为云存储类型 + HUAWEI_DBINSTANCE_STORAGE_TYPE_ULTRAHIGH = "ULTRAHIGH" //超高IO云硬盘 + HUAWEI_DBINSTANCE_STORAGE_TYPE_ULTRAHIGHPRO = "ULTRAHIGHPRO" + HUAWEI_DBINSTANCE_STORAGE_TYPE_COMMON = "COMMON" + HUAWEI_DBINSTANCE_STORAGE_TYPE_HIGH = "HIGH" + + //腾讯云 + QCLOUD_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD = "local_ssd" //本地盘SSD盘 + QCLOUD_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD = "cloud_ssd" //SSD云盘 + + // Azure + AZURE_DBINSTANCE_STORAGE_TYPE_DEFAULT = "default" +) + +var ( + ALIYUN_MYSQL_DENY_KEYWORKD []string = []string{ + "accessible", "account", "action", "actual", "add", "after", "against", "aggregate", "all", "algorithm", "alter", "always", "analyse", "analyze", "and", "any", "as", "asc", "ascii", "asensitive", "at", "auto_increment", "autoextend_size", "avg", "avg_row_length", "backup", "before", "begin", "between", "bigint", "binary", "binlog", "bit", "blob", "block", "bool", "boolean", "both", "btree", "by", "byte", "cache", "call", "cascade", "cascaded", "case", "catalog_name", "chain", "change", "changed", "channel", "char", "character", "charset", "check", "checksum", "cipher", "class_origin", "client", "close", "coalesce", "code", "collate", "collation", "column", "column_format", "column_name", "columns", "comment", "commit", "committed", "compact", "completion", "compression", "compressed", "encryption", "concurrent", "condition", "connection", "consistent", "constraint", "constraint_catalog", "constraint_name", "constraint_schema", "contains", "context", "continue", "convert", "cpu", "create", "cross", "cube", "current", "current_date", "current_time", "current_timestamp", "current_user", "cursor", "cursor_name", "data", "database", "databases", "datafile", "date", "datetime", "day", "day_hour", "day_microsecond", "day_minute", "day_second", "deallocate", "dec", "decimal", "declare", "default", "default_auth", "definer", "delayed", "delay_key_write", "desc", "describe", "des_key_file", "deterministic", "diagnostics", "directory", "disable", "discard", "disk", "distinct", "distinctrow", "div", "do", "double", "drop", "dual", "dumpfile", "duplicate", "dynamic", "each", "else", "elseif", "enable", "enclosed", "end", "ends", "engine", "engines", "enum", "error", "errors", "escape", "escaped", "event", "events", "every", "exchange", "execute", "exists", "exit", "expansion", "export", "expire", "explain", "extended", "extent_size", "false", "fast", "faults", "fetch", "fields", "file", "file_block_size", "filter", "first", "fixed", "float", "float4", "float8", "flush", "follows", "for", "force", "foreign", "format", "found", "from", "full", "fulltext", "function", "general", "group_replication", "geometry", "geometrycollection", "get_format", "get", "generated", "global", "grant", "grants", "group", "handler", "hash", "having", "help", "high_priority", "host", "hosts", "hour", "hour_microsecond", "hour_minute", "hour_second", "identified", "if", "ignore", "ignore_server_ids", "import", "in", "index", "indexes", "infile", "initial_size", "inner", "inout", "insensitive", "insert_method", "install", "instance", "int", "int1", "int2", "int3", "int4", "int8", "integer", "interval", "into", "io", "io_after_gtids", "io_before_gtids", "io_thread", "ipc", "is", "isolation", "issuer", "iterate", "invoker", "join", "json", "key", "keys", "key_block_size", "kill", "language", "last", "leading", "leave", "leaves", "left", "less", "level", "like", "limit", "linear", "lines", "linestring", "list", "load", "local", "localtime", "localtimestamp", "lock", "locks", "logfile", "logs", "long", "longblob", "longtext", "loop", "low_priority", "master", "master_auto_position", "master_bind", "master_connect_retry", "master_delay", "master_host", "master_log_file", "master_log_pos", "master_password", "master_port", "master_retry_count", "master_server_id", "master_ssl", "master_ssl_ca", "master_ssl_capath", "master_tls_version", "master_ssl_cert", "master_ssl_cipher", "master_ssl_crl", "master_ssl_crlpath", "master_ssl_key", "master_ssl_verify_server_cert", "master_user", "master_heartbeat_period", "match", "max_connections_per_hour", "max_queries_per_hour", "max_rows", "max_size", "max_updates_per_hour", "max_user_connections", "maxvalue", "medium", "mediumblob", "mediumint", "mediumtext", "memory", "merge", "message_text", "microsecond", "middleint", "migrate", "minute", "minute_microsecond", "minute_second", "min_rows", "mod", "mode", "modifies", "modify", "month", "multilinestring", "multipoint", "multipolygon", "mutex", "mysql_errno", "name", "names", "national", "natural", "ndb", "ndbcluster", "nchar", "never", "new", "next", "no", "no_wait", "nodegroup", "none", "not", "no_write_to_binlog", "null", "number", "numeric", "nvarchar", "offset", "on", "one", "only", "open", "optimize", "optimizer_costs", "options", "option", "optionally", "or", "order", "out", "outer", "outfile", "owner", "pack_keys", "parser", "page", "parse_gcol_expr", "partial", "partition", "partitioning", "partitions", "password", "phase", "plugin", "plugins", "plugin_dir", "point", "polygon", "port", "precedes", "precision", "prepare", "preserve", "prev", "primary", "privileges", "procedure", "process", "processlist", "profile", "profiles", "proxy", "purge", "quarter", "query", "quick", "range", "rds_charsetnum", "rds_connection_id", "rds_prepare_begin_id", "rds_current_connection", "rds_db", "rds_rw_mode", "rds_host_show", "rds_resetconnection", "read", "read_only", "read_write", "reads", "real", "rebuild", "recover", "redo_buffer_size", "redofile", "redundant", "references", "regexp", "relay", "relaylog", "relay_log_file", "relay_log_pos", "relay_thread", "release", "reload", "remove", "rename", "reorganize", "repair", "repeatable", "replication", "replicate_do_db", "replicate_ignore_db", "replicate_do_table", "replicate_ignore_table", "replicate_wild_do_table", "replicate_wild_ignore_table", "replicate_rewrite_db", "repeat", "require", "reset", "resignal", "restore", "restrict", "resume", "returned_sqlstate", "return", "returns", "reverse", "revoke", "right", "rlike", "rollback", "rollup", "routine", "rotate", "row", "row_count", "rows", "row_format", "rtree", "savepoint", "schedule", "schema", "schema_name", "schemas", "second", "second_microsecond", "security", "sensitive", "separator", "serial", "serializable", "session", "server", "set", "share", "show", "shutdown", "signal", "signed", "simple", "slave", "slow", "snapshot", "smallint", "socket", "some", "soname", "sounds", "source", "spatial", "specific", "sql", "sqlexception", "sqlstate", "sqlwarning", "sql_after_gtids", "sql_after_mts_gaps", "sql_before_gtids", "sql_big_result", "sql_buffer_result", "sql_cache", "sql_calc_found_rows", "sql_filters", "sql_no_cache", "sql_small_result", "sql_thread", "sql_tsi_second", "sql_tsi_minute", "sql_tsi_hour", "sql_tsi_day", "sql_tsi_week", "sql_tsi_month", "sql_tsi_quarter", "sql_tsi_year", "ssl", "stacked", "start", "starting", "starts", "stats_auto_recalc", "stats_persistent", "stats_sample_pages", "status", "stop", "storage", "stored", "straight_join", "string", "subclass_origin", "subject", "subpartition", "subpartitions", "super", "suspend", "swaps", "switches", "table", "table_name", "tables", "tablespace", "table_checksum", "temporary", "temptable", "terminated", "text", "than", "then", "time", "timestamp", "timestampadd", "timestampdiff", "tinyblob", "tinyint", "tinytext", "to", "trailing", "transaction", "trigger", "triggers", "true", "truncate", "type", "types", "uncommitted", "undefined", "undo_buffer_size", "undofile", "undo", "unicode", "union", "unique", "unknown", "unlock", "uninstall", "unsigned", "until", "upgrade", "usage", "use", "user", "user_resources", "use_frm", "using", "utc_date", "utc_time", "utc_timestamp", "validation", "value", "values", "varbinary", "varchar", "varcharacter", "variables", "varying", "wait", "warnings", "week", "weight_string", "when", "where", "while", "view", "virtual", "with", "without", "work", "wrapper", "write", "x509", "xor", "xa", "xid", "xml", "year", "year_month", "zerofill", "lag", "rds_audit", "rds_inner_backup", "rds_change_user", "rds_user", "rds_ip", "rds_add_proxy_protocol_networks", "rds_show_proxy_protocol_ips", "sync", "delete", "insert", "replace", "select", "update", "adddate", "bit_and", "bit_or", "bit_xor", "cast", "count", "curdate", "curtime", "date_add", "date_sub", "extract", "group_concat", "json_objectagg", "json_arrayagg", "max", "mid", "min", "now", "position", "session_user", "std", "stddev", "stddev_pop", "stddev_samp", "subdate", "substr", "substring", "sum", "sysdate", "system_user", "trim", "variance", "var_pop", "var_samp", "bka", "bnl", "dupsweedout", "firstmatch", "intoexists", "loosescan", "materialization", "max_execution_time", "no_bka", "no_bnl", "no_icp", "no_mrr", "no_range_optimization", "no_semijoin", "mrr", "qb_name", "semijoin", "subquery", + } + + ALIYUN_SQL_SERVER_DENY_KEYWORD []string = []string{ + "root", " admin", " eagleye", " master", " aurora", " sa", " sysadmin", " administrator", " mssqld", " public", " securityadmin", " serveradmin", " setupadmin", " processadmin", " diskadmin", " dbcreator", " bulkadmin", " tempdb", " msdb", " model", " distribution", " mssqlsystemresource", " guest", " add", " except", " percent", " all", " exec", " plan", " alter", " execute", " precision", " and", " exists", " primary", " any", " exit", " print", " as", " fetch", " proc", " asc", " file", " procedure", " authorization", " fillfactor", " public", " backup", " for", " raiserror", " begin", " foreign", " read", " between", " freetext", " readtext", " break", " freetexttable", " reconfigure", " browse", " from", " references", " bulk", " full", " replication", " by", " function", " restore", " cascade", " goto", " restrict", " case", " grant", " return", " check", " group", " revoke", " checkpoint", " having", " right", " close", " holdlock", " rollback", " clustered", " identity", " rowcount", " coalesce", " identity_insert", " rowguidcol", " collate", " identitycol", " rule", " column", " if", " save", " commit", " in", " schema", " compute", " index", " select", " constraint", " inner", " session_user", " contains", " insert", " set", " containstable", " intersect", " setuser", " continue", " into", " shutdown", " convert", " is", " some", " create", " join", " statistics", " cross", " key", " system_user", " current", " kill", " table", " current_date", " left", " textsize", " current_time", " like", " then", " current_timestamp", " lineno", " to", " current_user", " load", " top", " cursor", " national", " tran", " database", " nocheck", " transaction", " dbcc", " nonclustered", " trigger", " deallocate", " not", " truncate", " declare", " null", " tsequal", " default", " nullif", " union", " delete", " of", " unique", " deny", " off", " update", " desc", " offsets", " updatetext", " disk", " on", " use", " distinct", " open", " user", " distributed", " opendatasource", " values", " double", " openquery", " varying", " drop", " openrowset", " view", " dummy", " openxml", " waitfor", " dump", " option", " when", " else", " or", " where", " end", " order", " while", " errlvl", " outer", " with", " escape", " over", " writetext", " galaxy", + } + + RW_PRIVILEGE_SET = []string{ + "SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", + "DROP", "REFERENCES", "INDEX", "ALTER", "CREATE TEMPORARY TABLES", + "LOCK TABLES", "EXECUTE", "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", + "ALTER ROUTINE", "EVENT", "TRIGGER", "PROCESS", "REPLICATION SLAVE", + "REPLICATION CLIENT", + } + R_PRIVILEGE_SET = []string{"SELECT", "LOCK TABLES", "SHOW VIEW", "PROCESS", "REPLICATION SLAVE", "REPLICATION CLIENT"} + QCLOUD_RW_PRIVILEGE_SET = []string{ + "SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", + "DROP", "REFERENCES", "INDEX", "ALTER", "CREATE TEMPORARY TABLES", + "LOCK TABLES", "EXECUTE", "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", + "ALTER ROUTINE", "EVENT", "TRIGGER", + } + QCLOUD_R_PRIVILEGE_SET = []string{"SELECT", "LOCK TABLES", "SHOW VIEW"} +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dbinstance_sku_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dbinstance_sku_const.go new file mode 100644 index 0000000000..979d56f473 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dbinstance_sku_const.go @@ -0,0 +1,20 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + DBINSTANCE_SKU_AVAILABLE = "available" + DBINSTANCE_SKU_SOLDOUT = "soldout" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/disk_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/disk_const.go new file mode 100644 index 0000000000..0b92c53405 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/disk_const.go @@ -0,0 +1,75 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + DISK_INIT = "init" + DISK_REBUILD = "rebuild" + DISK_ALLOC_FAILED = "alloc_failed" + DISK_STARTALLOC = "start_alloc" + DISK_BACKUP_STARTALLOC = "backup_start_alloc" + DISK_BACKUP_ALLOC_FAILED = "backup_alloc_failed" + DISK_ALLOCATING = "allocating" + DISK_READY = "ready" + DISK_RESET = "reset" + DISK_RESET_FAILED = "reset_failed" + DISK_DEALLOC = "deallocating" + DISK_DEALLOC_FAILED = "dealloc_failed" + DISK_UNKNOWN = "unknown" + DISK_DETACHING = "detaching" + DISK_ATTACHING = "attaching" + DISK_CLONING = "cloning" // 硬盘克隆 + + DISK_START_SAVE = "start_save" + DISK_SAVING = "saving" + + DISK_START_RESIZE = "start_resize" + DISK_RESIZING = "resizing" + DISK_RESIZE_FAILED = "resize_failed" + + DISK_START_MIGRATE = "start_migrate" + DISK_POST_MIGRATE = "post_migrate" + DISK_MIGRATING = "migrating" + + DISK_CLONE = "clone" + DISK_CLONE_FAIL = "clone_failed" + + DISK_START_SNAPSHOT = "start_snapshot" + DISK_SNAPSHOTING = "snapshoting" + DISK_APPLY_SNAPSHOT_FAIL = "apply_snapshot_failed" + DISK_CALCEL_SNAPSHOT_FAIL = "cancel_snapshot_failed" + + DISK_TYPE_SYS = "sys" + DISK_TYPE_SWAP = "swap" + DISK_TYPE_DATA = "data" + DISK_TYPE_VOLUME = "volume" + + DISK_BACKING_IMAGE = "image" + + DISK_SIZE_AUTOEXTEND = -1 + + DISK_NOT_EXIST = "not_exist" + DISK_EXIST = "exist" +) + +const DISK_META_EXISTING_PATH = "disk_existing_path" + +const ( + DISK_DRIVER_VIRTIO = "virtio" + DISK_DRIVER_SCSI = "scsi" + DISK_DRIVER_PVSCSI = "pvscsi" + DISK_DRIVER_IDE = "ide" + DISK_DRIVER_SATA = "sata" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dnsrecordsets.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dnsrecordsets.go new file mode 100644 index 0000000000..b37220ab21 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dnsrecordsets.go @@ -0,0 +1,19 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + DNS_RECORDSET_STATUS_AVAILABLE = "available" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dnszone.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dnszone.go new file mode 100644 index 0000000000..8257315e45 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/dnszone.go @@ -0,0 +1,84 @@ +// Copyright 2019 Yunion +// +// 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 compute + +/* + +Architecture For DnsZone + + + +-----------+ +----------------+ +-----------+ + | RecordSet | | TrafficPolicy | | RecordSet | +-------------+ + | (A) | | (Aliyun) | | (TXT) | | Vpc1 | + | | | | | | | (Aws) | + | | | | | | | | + +-----------------------+ | | | | | | +-----------------+ | | + API | DnsZone example.com | | RecordSet | | TrafficPolicy | | RecordSet | | DnsZone abc.app | | Vpc2 | + | (Public) | ------>| (AAAA) | -----------------> | (Tencent) | <-------------| (CAA) | <-------------| (Private) |-----> | (Tencent) | + +-----------------------+ | | | | | | +-----------------+ | | + ^ | | | | | | ^ | | + | | | | | | | | | Vpc3 | + | | RecordSet | | TrafficPolicy | | RecordSet | | | (Aws) | + | | (NS) | | (Aws) | | (PTR) | | +-------------+ + | +-----------+ +----------------+ +-----------+ | + | | + | | + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + | | + v | + +-----------------+ | + | | | + | | +----------+ v + | example.com <-------------> | Account1 | +----------+ +---------------+ + | | | (Aliyun) | | Account3 | <-------> | abc.app | + | | +----------+ +------------+ | (Aws) | | | + | | | Account2 | +----------+ | | + | example.com <-------------------------------------------------------> | (Tencent) | | | + Cache | | +------------+ | | + | | | | + | | +----------+ | | + | example.com <-------------> | Account4 | <--------------------------------------------------------------------------------> | abc.app | + | | | (Aliyun) | | | + | | +----------+ +---------------+ + +-----------------+ + + --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + + ************* *************** ************* + **** **** **** **** **** **** + Public Cloud ** Aliyun ** ** Tencent ** ** Aws ** + **** **** **** **** **** **** + ************* *************** ************* + + +*/ + +const ( + DNS_ZONE_STATUS_AVAILABLE = "available" // 可用 + DNS_ZONE_STATUS_CREATING = "creating" // 创建中 + DNS_ZONE_STATUS_CREATE_FAILE = "create_failed" // 创建失败 + DNS_ZONE_STATUS_UNCACHING = "uncaching" // 云上资源删除中 + DNS_ZONE_STATUS_UNCACHE_FAILED = "uncache_failed" // 云上资源删除失败 + DNS_ZONE_STATUS_CACHING = "caching" // 云上资源创建中 + DNS_ZONE_STATUS_CACHE_FAILED = "cache_failed" // 云上资源创建失败 + DNS_ZONE_STATUS_SYNC_VPCS = "sync_vpcs" // 同步VPC中 + DNS_ZONE_STATUS_SYNC_VPCS_FAILED = "sync_vpcs_failed" // 同步VPC失败 + DNS_ZONE_STATUS_SYNC_RECORD_SETS = "sync_record_sets" // 同步解析列表中 + DNS_ZONE_STATUS_SYNC_RECORD_SETS_FAILED = "sync_record_sets_failed" // 同步解析列表失败 + DNS_ZONE_STATUS_DELETING = "deleting" // 删除中 + DNS_ZONE_STATUS_DELETE_FAILED = "delete_failed" // 删除失败 + DNS_ZONE_STATUS_UNKNOWN = "unknown" // 未知 +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/elastic_search.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/elastic_search.go new file mode 100644 index 0000000000..eb8e4987c4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/elastic_search.go @@ -0,0 +1,24 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + ELASTIC_SEARCH_STATUS_AVAILABLE = "available" + ELASTIC_SEARCH_STATUS_UNAVAILABLE = "unavailable" + ELASITC_SEARCH_STATUS_CREATING = "creating" + ELASTIC_SEARCH_STATUS_DELETING = "deleting" + ELASTIC_SEARCH_STATUS_DELETE_FAILED = "delete_failed" + ELASTIC_SEARCH_STATUS_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/elasticache_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/elasticache_const.go new file mode 100644 index 0000000000..53654d851f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/elasticache_const.go @@ -0,0 +1,133 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + ELASTIC_CACHE_STATUS_RUNNING = "running" //(正常) + ELASTIC_CACHE_STATUS_RESTARTING = "restarting" //(重启中) + ELASTIC_CACHE_STATUS_RESTART_FAILED = "restart_failed" //(重启失败) + ELASTIC_CACHE_STATUS_DEPLOYING = "deploying" //(创建中) + ELASTIC_CACHE_STATUS_CREATE_FAILED = "create_failed" //(创建失败) + ELASTIC_CACHE_STATUS_CHANGING = "changing" //(修改中) + ELASTIC_CACHE_STATUS_CHANGE_FAILED = "change_failed" //(修改失败) + ELASTIC_CACHE_STATUS_INACTIVE = "inactive" //(被禁用) + ELASTIC_CACHE_STATUS_FLUSHING = "flushing" //(清除中) + ELASTIC_CACHE_STATUS_FLUSHING_FAILED = "flushing_failed" //(清除失败) + ELASTIC_CACHE_STATUS_RELEASING = "releasing" //(释放中) + ELASTIC_CACHE_STATUS_RELEASED = "released" //(已释放) + ELASTIC_CACHE_STATUS_RELEASE_FAILED = "release_failed" //(释放失败) + ELASTIC_CACHE_STATUS_TRANSFORMING = "transforming" //(转换中) + ELASTIC_CACHE_STATUS_UNAVAILABLE = "unavailable" //(服务停止) + ELASTIC_CACHE_STATUS_ERROR = "error" //(删除失败) + ELASTIC_CACHE_STATUS_MIGRATING = "migrating" //(迁移中) + ELASTIC_CACHE_STATUS_BACKUPRECOVERING = "backuprecovering" //(备份恢复中) + ELASTIC_CACHE_STATUS_MINORVERSIONUPGRADING = "minorversionupgrading" //(小版本升级中) + ELASTIC_CACHE_STATUS_NETWORKMODIFYING = "networkmodifying" //(网络变更中) + ELASTIC_CACHE_STATUS_SSLMODIFYING = "sslmodifying" //(SSL变更中) + ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING = "majorversionupgrading" //(大版本升级中,可正常访问) + ELASTIC_CACHE_STATUS_UNKNOWN = "unknown" //(未知状态) + ELASTIC_CACHE_STATUS_DELETING = "deleting" // (删除) + ELASTIC_CACHE_STATUS_SNAPSHOTTING = "snapshotting" //(快照) + ELASTIC_CACHE_STATUS_SYNCING = "syncing" //(同步中) + ELASTIC_CACHE_STATUS_SYNC_FAILED = "sync_failed" //(同步失败) + ELASTIC_CACHE_RENEWING = "renewing" //(续费中) + ELASTIC_CACHE_RENEW_FAILED = "renew_failed" //(续费失败) + ELASTIC_CACHE_SET_AUTO_RENEW = "set_auto_renew" //(设置自动续费) + ELASTIC_CACHE_SET_AUTO_RENEW_FAILED = "set_auto_renew_failed" //(设置自动续费失败) + + ELASTIC_CACHE_ENGINE_REDIS = "redis" + ELASTIC_CACHE_ENGINE_MEMCACHED = "memcached" +) + +const ( + ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE = "available" // 正常可用 + ELASTIC_CACHE_ACCOUNT_STATUS_UNAVAILABLE = "unavailable" // 不可用 + ELASTIC_CACHE_ACCOUNT_STATUS_CREATING = "creating" // 创建中 + ELASTIC_CACHE_ACCOUNT_STATUS_MODIFYING = "modifying" // 修改中 + ELASTIC_CACHE_ACCOUNT_STATUS_CREATE_FAILED = "create_failed" //(创建失败) + ELASTIC_CACHE_ACCOUNT_STATUS_DELETING = "deleting" // 删除中 + ELASTIC_CACHE_ACCOUNT_STATUS_DELETE_FAILED = "delete_failed" // 删除失败 + ELASTIC_CACHE_ACCOUNT_STATUS_DELETED = "deleted" // 已删除 +) + +const ( + ELASTIC_CACHE_UPDATE_TAGS = "update_tags" + ELASTIC_CACHE_UPDATE_TAGS_FAILED = "update_tags_fail" +) + +const ( + ELASTIC_CACHE_ACCOUNT_TYPE_NORMAL = "normal" // 普通账号 + ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN = "admin" // 管理账号 +) + +const ( + ELASTIC_CACHE_ACCOUNT_PRIVILEGE_READ = "read" // 只读 + ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE = "write" // 读写 + ELASTIC_CACHE_ACCOUNT_PRIVILEGE_REPL = "repl" // 复制,复制权限支持读写,且支持使用SYNC/PSYNC命令。 +) + +const ( + ELASTIC_CACHE_BACKUP_STATUS_CREATING = "creating" // 备份中 + ELASTIC_CACHE_BACKUP_STATUS_RESTORING = "restoring" + ELASTIC_CACHE_BACKUP_STATUS_COPYING = "copying" + ELASTIC_CACHE_BACKUP_STATUS_CREATE_EXPIRED = "expired" //(备份文件已过期) + ELASTIC_CACHE_BACKUP_STATUS_CREATE_DELETED = "deleted" //(备份文件已删除) + ELASTIC_CACHE_BACKUP_STATUS_DELETING = "deleting" // 删除中 + ELASTIC_CACHE_BACKUP_STATUS_SUCCESS = "success" // 备份成功 + ELASTIC_CACHE_BACKUP_STATUS_FAILED = "failed" // 备份失败 + ELASTIC_CACHE_BACKUP_STATUS_UNKNOWN = "unknown" // 未知 +) + +const ( + ELASTIC_CACHE_BACKUP_TYPE_FULL = "full" // 全量备份 + ELASTIC_CACHE_BACKUP_TYPE_INCREMENTAL = "incremental" // 增量备份 +) + +const ( + ELASTIC_CACHE_BACKUP_MODE_AUTOMATED = "automated" // 自动备份 + ELASTIC_CACHE_BACKUP_MODE_MANUAL = "manual" // 手动触发备份 +) + +const ( + ELASTIC_CACHE_ACL_STATUS_AVAILABLE = "available" // 正常可用 + ELASTIC_CACHE_ACL_STATUS_CREATING = "creating" // 创建中 + ELASTIC_CACHE_ACL_STATUS_CREATE_FAILED = "create_failed" //(创建失败) + ELASTIC_CACHE_ACL_STATUS_DELETING = "deleting" // 删除中 + ELASTIC_CACHE_ACL_STATUS_DELETE_FAILED = "delete_failed" // 删除失败 + ELASTIC_CACHE_ACL_STATUS_UPDATING = "updating" // 更新中 + ELASTIC_CACHE_ACL_STATUS_UPDATE_FAILED = "update_failed" // 更新失败 +) + +const ( + ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE = "available" // 正常可用 + ELASTIC_CACHE_PARAMETER_STATUS_UPDATING = "updating" // 更新中 + ELASTIC_CACHE_PARAMETER_STATUS_UPDATE_FAILED = "update_failed" // 更新失败 +) + +const ( + ELASTIC_CACHE_ARCH_TYPE_SINGLE = "single" // 单副本 + ELASTIC_CACHE_ARCH_TYPE_MASTER = "master" // 主备 + ELASTIC_CACHE_ARCH_TYPE_CLUSTER = "cluster" // 集群 + ELASTIC_CACHE_ARCH_TYPE_RWSPLIT = "rwsplit" // 读写分离 +) + +const ( + ELASTIC_CACHE_NODE_TYPE_SINGLE = "single" + ELASTIC_CACHE_NODE_TYPE_DOUBLE = "double" + ELASTIC_CACHE_NODE_TYPE_THREE = "three" + ELASTIC_CACHE_NODE_TYPE_FOUR = "four" + ELASTIC_CACHE_NODE_TYPE_FIVE = "five" + ELASTIC_CACHE_NODE_TYPE_SIX = "six" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/elasticips_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/elasticips_const.go new file mode 100644 index 0000000000..36f15324c0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/elasticips_const.go @@ -0,0 +1,57 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + EIP_MODE_INSTANCE_PUBLICIP = "public_ip" + EIP_MODE_STANDALONE_EIP = "elastic_ip" + + EIP_ASSOCIATE_TYPE_SERVER = "server" + EIP_ASSOCIATE_TYPE_NAT_GATEWAY = "natgateway" + EIP_ASSOCIATE_TYPE_LOADBALANCER = "loadbalancer" + EIP_ASSOCIATE_TYPE_UNKNOWN = "unknown" + + EIP_ASSOCIATE_TYPE_INSTANCE_GROUP = "instancegroup" + + EIP_STATUS_READY = "ready" + EIP_STATUS_UNKNOWN = "unknown" + EIP_STATUS_ALLOCATE = "allocate" + EIP_STATUS_ALLOCATE_FAIL = "allocate_fail" + EIP_STATUS_DEALLOCATE = "deallocate" + EIP_STATUS_DEALLOCATE_FAIL = "deallocate_fail" + EIP_STATUS_ASSOCIATE = "associate" + EIP_STATUS_ASSOCIATE_FAIL = "associate_fail" + EIP_STATUS_DISSOCIATE = "dissociate" + EIP_STATUS_DISSOCIATE_FAIL = "dissociate_fail" + + EIP_STATUS_CHANGE_BANDWIDTH = "change_bandwidth" + + EIP_CHARGE_TYPE_BY_TRAFFIC = "traffic" + EIP_CHARGE_TYPE_BY_BANDWIDTH = "bandwidth" + + INSTANCE_ASSOCIATE_EIP = "associate_eip" + INSTANCE_ASSOCIATE_EIP_FAILED = "associate_eip_failed" + INSTANCE_DISSOCIATE_EIP = "dissociate_eip" + INSTANCE_DISSOCIATE_EIP_FAILED = "dissociate_eip_failed" +) + +var ( + EIP_ASSOCIATE_VALID_TYPES = []string{ + EIP_ASSOCIATE_TYPE_SERVER, + EIP_ASSOCIATE_TYPE_NAT_GATEWAY, + EIP_ASSOCIATE_TYPE_INSTANCE_GROUP, + EIP_ASSOCIATE_TYPE_LOADBALANCER, + } +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/esxi_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/esxi_const.go new file mode 100644 index 0000000000..f5c2f55a32 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/esxi_const.go @@ -0,0 +1,19 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + ESXI_IMAGE_CACHE_TMP_PREFIX = "yunioncloud.imagecache" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/externalproject.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/externalproject.go new file mode 100644 index 0000000000..78f9024f6b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/externalproject.go @@ -0,0 +1,29 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + EXTERNAL_PROJECT_STATUS_AVAILABLE = "available" // 可用 + EXTERNAL_PROJECT_STATUS_UNAVAILABLE = "unavailable" // 不可用 + EXTERNAL_PROJECT_STATUS_CREATING = "creating" // 创建中 + EXTERNAL_PROJECT_STATUS_DELETING = "deleting" // 删除中 + EXTERNAL_PROJECT_STATUS_UNKNOWN = "unknown" // 未知 +) + +var ( + MANGER_EXTERNAL_PROJECT_PROVIDERS = []string{ + CLOUD_PROVIDER_AZURE, + } +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/filesystem.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/filesystem.go new file mode 100644 index 0000000000..93d47632a8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/filesystem.go @@ -0,0 +1,36 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + // 可用 + NAS_STATUS_AVAILABLE = "available" + // 不可用 + NAS_STATUS_UNAVAILABLE = "unavailable" + // 扩容中 + NAS_STATUS_EXTENDING = "extending" + // 创建中 + NAS_STATUS_CREATING = "creating" + // 创建失败 + NAS_STATUS_CREATE_FAILED = "create_failed" + // 未知 + NAS_STATUS_UNKNOWN = "unknown" + // 删除中 + NAS_STATUS_DELETING = "deleting" + NAS_STATUS_DELETE_FAILED = "delete_failed" + + NAS_UPDATE_TAGS = "update_tags" + NAS_UPDATE_TAGS_FAILED = "update_tags_fail" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/globalvpc_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/globalvpc_const.go new file mode 100644 index 0000000000..13aee5e74d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/globalvpc_const.go @@ -0,0 +1,20 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + GLOBAL_VPC_STATUS_AVAILABLE = "available" + GLOBAL_VPC_STATUS_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/guest_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/guest_const.go new file mode 100644 index 0000000000..fa62538e59 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/guest_const.go @@ -0,0 +1,384 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + VM_INIT = "init" + VM_UNKNOWN = "unknown" + VM_SCHEDULE = "schedule" + VM_SCHEDULE_FAILED = "sched_fail" + VM_CREATE_NETWORK = "network" + VM_NETWORK_FAILED = "net_fail" + VM_DEVICE_FAILED = "dev_fail" + VM_CREATE_FAILED = "create_fail" + VM_CREATE_DISK = "disk" + VM_DISK_FAILED = "disk_fail" + VM_IMAGE_CACHING = "image_caching" // 缓存镜像中 + VM_START_DEPLOY = "start_deploy" + VM_DEPLOYING = "deploying" + VM_DEPLOY_FAILED = "deploy_fail" + VM_READY = "ready" + VM_START_START = "start_start" + VM_STARTING = "starting" + VM_START_FAILED = "start_fail" // # = ready + VM_RUNNING = "running" + VM_START_STOP = "start_stop" + VM_STOPPING = "stopping" + VM_STOP_FAILED = "stop_fail" // # = running + VM_RENEWING = "renewing" + VM_RENEW_FAILED = "renew_failed" + VM_ATTACH_DISK = "attach_disk" + VM_DETACH_DISK = "detach_disk" + + VM_BACKUP_STARTING = "backup_starting" + VM_BACKUP_CREATING = "backup_creating" + VM_BACKUP_CREATE_FAILED = "backup_create_fail" + VM_DEPLOYING_BACKUP = "deploying_backup" + VM_DEPLOYING_BACKUP_FAILED = "deploging_backup_fail" + VM_DELETING_BACKUP = "deleting_backup" + VM_BACKUP_DELETE_FAILED = "backup_delete_fail" + VM_SWITCH_TO_BACKUP = "switch_to_backup" + VM_SWITCH_TO_BACKUP_FAILED = "switch_to_backup_fail" + + VM_ATTACH_DISK_FAILED = "attach_disk_fail" + VM_DETACH_DISK_FAILED = "detach_disk_fail" + + VM_START_SUSPEND = "start_suspend" + VM_SUSPENDING = "suspending" + VM_SUSPEND = "suspend" + VM_SUSPEND_FAILED = "suspend_failed" + + VM_RESUMING = "resuming" + VM_RESUME_FAILED = "resume_failed" + + VM_START_DELETE = "start_delete" + VM_DELETE_FAIL = "delete_fail" + VM_DELETING = "deleting" + + VM_DEALLOCATED = "deallocated" + + VM_START_MIGRATE = "start_migrate" + VM_MIGRATING = "migrating" + VM_LIVE_MIGRATING = "live_migrating" + VM_MIGRATE_FAILED = "migrate_failed" + + VM_CHANGE_FLAVOR = "change_flavor" + VM_CHANGE_FLAVOR_FAIL = "change_flavor_fail" + VM_REBUILD_ROOT = "rebuild_root" + VM_REBUILD_ROOT_FAIL = "rebuild_root_fail" + + VM_START_SNAPSHOT = "snapshot_start" + VM_SNAPSHOT = "snapshot" + VM_SNAPSHOT_DELETE = "snapshot_delete" + VM_BLOCK_STREAM = "block_stream" + VM_BLOCK_STREAM_FAIL = "block_stream_fail" + VM_SNAPSHOT_SUCC = "snapshot_succ" + VM_SNAPSHOT_FAILED = "snapshot_failed" + VM_DISK_RESET = "disk_reset" + VM_DISK_RESET_FAIL = "disk_reset_failed" + VM_DISK_CHANGE_STORAGE = "disk_change_storage" + VM_DISK_CHANGE_STORAGE_FAIL = "disk_change_storage_fail" + + VM_START_INSTANCE_SNAPSHOT = "start_instance_snapshot" + VM_INSTANCE_SNAPSHOT_FAILED = "instance_snapshot_failed" + VM_START_SNAPSHOT_RESET = "start_snapshot_reset" + VM_SNAPSHOT_RESET_FAILED = "snapshot_reset_failed" + VM_SNAPSHOT_AND_CLONE_FAILED = "clone_from_snapshot_failed" + + VM_START_INSTANCE_BACKUP = "start_instance_backup" + VM_INSTANCE_BACKUP_FAILED = "instance_backup_failed" + + VM_SYNC_CONFIG = "sync_config" + VM_SYNC_FAIL = "sync_fail" + + VM_START_RESIZE_DISK = "start_resize_disk" + VM_RESIZE_DISK = "resize_disk" + VM_RESIZE_DISK_FAILED = "resize_disk_fail" + + VM_START_SAVE_DISK = "start_save_disk" + VM_SAVE_DISK = "save_disk" + VM_SAVE_DISK_FAILED = "save_disk_failed" + + VM_RESTORING_SNAPSHOT = "restoring_snapshot" + VM_RESTORE_DISK = "restore_disk" + VM_RESTORE_STATE = "restore_state" + VM_RESTORE_FAILED = "restore_failed" + + VM_ASSOCIATE_EIP = INSTANCE_ASSOCIATE_EIP + VM_ASSOCIATE_EIP_FAILED = INSTANCE_ASSOCIATE_EIP_FAILED + VM_DISSOCIATE_EIP = INSTANCE_DISSOCIATE_EIP + VM_DISSOCIATE_EIP_FAILED = INSTANCE_DISSOCIATE_EIP_FAILED + + // 公网IP转换Eip中(EIP转换中) + VM_START_EIP_CONVERT = "start_eip_convert" + VM_EIP_CONVERT_FAILED = "eip_convert_failed" + + // 设置自动续费 + VM_SET_AUTO_RENEW = "set_auto_renew" + VM_SET_AUTO_RENEW_FAILED = "set_auto_renew_failed" + + VM_REMOVE_STATEFILE = "remove_state" + + VM_IO_THROTTLE = "io_throttle" + VM_IO_THROTTLE_FAIL = "io_throttle_fail" + + VM_ADMIN = "admin" + + VM_IMPORT = "import" + VM_IMPORT_FAILED = "import_fail" + + VM_CONVERT = "convert" + VM_CONVERTING = "converting" + VM_CONVERT_FAILED = "convert_failed" + VM_CONVERTED = "converted" + + VM_TEMPLATE_SAVING = "tempalte_saving" + VM_TEMPLATE_SAVE_FAILED = "template_save_failed" + + VM_UPDATE_TAGS = "update_tags" + VM_UPDATE_TAGS_FAILED = "update_tags_fail" + + VM_RESTART_NETWORK = "restart_network" + VM_RESTART_NETWORK_FAILED = "restart_network_failed" + + VM_SYNC_ISOLATED_DEVICE_FAILED = "sync_isolated_device_failed" + + VM_QGA_SET_PASSWORD = "qga_set_password" + VM_QGA_COMMAND_EXECUTING = "qga_command_executing" + + SHUTDOWN_STOP = "stop" + SHUTDOWN_TERMINATE = "terminate" + + HYPERVISOR_KVM = "kvm" + HYPERVISOR_CONTAINER = "container" + HYPERVISOR_BAREMETAL = "baremetal" + HYPERVISOR_ESXI = "esxi" + HYPERVISOR_HYPERV = "hyperv" + HYPERVISOR_XEN = "xen" + + HYPERVISOR_ALIYUN = "aliyun" + HYPERVISOR_APSARA = "apsara" + HYPERVISOR_QCLOUD = "qcloud" + HYPERVISOR_AZURE = "azure" + HYPERVISOR_AWS = "aws" + HYPERVISOR_HUAWEI = "huawei" + HYPERVISOR_HCS = "hcs" + HYPERVISOR_HCSO = "hcso" + HYPERVISOR_OPENSTACK = "openstack" + HYPERVISOR_UCLOUD = "ucloud" + HYPERVISOR_ZSTACK = "zstack" + HYPERVISOR_GOOGLE = "google" + HYPERVISOR_CTYUN = "ctyun" + HYPERVISOR_ECLOUD = "ecloud" + HYPERVISOR_JDCLOUD = "jdcloud" + HYPERVISOR_CLOUDPODS = "cloudpods" + HYPERVISOR_NUTANIX = "nutanix" + HYPERVISOR_BINGO_CLOUD = "bingocloud" + HYPERVISOR_INCLOUD_SPHERE = "incloudsphere" + HYPERVISOR_PROXMOX = "proxmox" + HYPERVISOR_REMOTEFILE = "remotefile" + + // HYPERVISOR_DEFAULT = HYPERVISOR_KVM + HYPERVISOR_DEFAULT = HYPERVISOR_KVM +) + +const ( + VM_POWER_STATES_ON = "on" + VM_POWER_STATES_OFF = "off" + VM_POWER_STATES_UNKNOWN = "unknown" +) + +const ( + QGA_STATUS_UNKNOWN = "unknown" + QGA_STATUS_EXCUTING = "executing" + QGA_STATUS_EXECUTE_FAILED = "execute_failed" + QGA_STATUS_AVAILABLE = "available" +) + +const ( + CPU_MODE_QEMU = "qemu" + CPU_MODE_HOST = "host" +) + +const ( + VM_MACHINE_TYPE_PC = "pc" + VM_MACHINE_TYPE_Q35 = "q35" + + VM_MACHINE_TYPE_ARM_VIRT = "virt" + + VM_VDI_PROTOCOL_VNC = "vnc" + VM_VDI_PROTOCOL_SPICE = "spice" + + VM_VIDEO_STANDARD = "std" + VM_VIDEO_QXL = "qxl" + VM_VIDEO_VIRTIO = "virtio" +) + +var VM_RUNNING_STATUS = []string{VM_START_START, VM_STARTING, VM_RUNNING, VM_BLOCK_STREAM, VM_BLOCK_STREAM_FAIL} +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_APSARA, + HYPERVISOR_AZURE, + HYPERVISOR_AWS, + HYPERVISOR_QCLOUD, + HYPERVISOR_HUAWEI, + HYPERVISOR_HCSO, + HYPERVISOR_HCS, + HYPERVISOR_OPENSTACK, + HYPERVISOR_UCLOUD, + HYPERVISOR_ZSTACK, + HYPERVISOR_GOOGLE, + HYPERVISOR_CTYUN, + HYPERVISOR_ECLOUD, + HYPERVISOR_JDCLOUD, + HYPERVISOR_CLOUDPODS, + HYPERVISOR_NUTANIX, + HYPERVISOR_BINGO_CLOUD, + HYPERVISOR_INCLOUD_SPHERE, + HYPERVISOR_PROXMOX, + HYPERVISOR_REMOTEFILE, +} + +var ONECLOUD_HYPERVISORS = []string{ + HYPERVISOR_BAREMETAL, + HYPERVISOR_KVM, + HYPERVISOR_CONTAINER, +} + +var PUBLIC_CLOUD_HYPERVISORS = []string{ + HYPERVISOR_ALIYUN, + HYPERVISOR_AWS, + HYPERVISOR_AZURE, + HYPERVISOR_QCLOUD, + HYPERVISOR_HUAWEI, + HYPERVISOR_UCLOUD, + HYPERVISOR_GOOGLE, + HYPERVISOR_CTYUN, + HYPERVISOR_ECLOUD, + HYPERVISOR_JDCLOUD, +} + +var PRIVATE_CLOUD_HYPERVISORS = []string{ + HYPERVISOR_ZSTACK, + HYPERVISOR_OPENSTACK, + HYPERVISOR_APSARA, + HYPERVISOR_CLOUDPODS, + HYPERVISOR_HCSO, + HYPERVISOR_HCS, + HYPERVISOR_NUTANIX, + HYPERVISOR_BINGO_CLOUD, + HYPERVISOR_INCLOUD_SPHERE, + HYPERVISOR_PROXMOX, + HYPERVISOR_REMOTEFILE, +} + +// var HYPERVISORS = []string{HYPERVISOR_ALIYUN} + +var HYPERVISOR_HOSTTYPE = map[string]string{ + HYPERVISOR_KVM: HOST_TYPE_HYPERVISOR, + HYPERVISOR_BAREMETAL: HOST_TYPE_BAREMETAL, + HYPERVISOR_ESXI: HOST_TYPE_ESXI, + HYPERVISOR_CONTAINER: HOST_TYPE_KUBELET, + HYPERVISOR_ALIYUN: HOST_TYPE_ALIYUN, + HYPERVISOR_APSARA: HOST_TYPE_APSARA, + HYPERVISOR_AZURE: HOST_TYPE_AZURE, + HYPERVISOR_AWS: HOST_TYPE_AWS, + HYPERVISOR_QCLOUD: HOST_TYPE_QCLOUD, + HYPERVISOR_HUAWEI: HOST_TYPE_HUAWEI, + HYPERVISOR_HCSO: HOST_TYPE_HCSO, + HYPERVISOR_HCS: HOST_TYPE_HCS, + HYPERVISOR_OPENSTACK: HOST_TYPE_OPENSTACK, + HYPERVISOR_UCLOUD: HOST_TYPE_UCLOUD, + HYPERVISOR_ZSTACK: HOST_TYPE_ZSTACK, + HYPERVISOR_GOOGLE: HOST_TYPE_GOOGLE, + HYPERVISOR_CTYUN: HOST_TYPE_CTYUN, + HYPERVISOR_ECLOUD: HOST_TYPE_ECLOUD, + HYPERVISOR_JDCLOUD: HOST_TYPE_JDCLOUD, + HYPERVISOR_CLOUDPODS: HOST_TYPE_CLOUDPODS, + HYPERVISOR_NUTANIX: HOST_TYPE_NUTANIX, + HYPERVISOR_BINGO_CLOUD: HOST_TYPE_BINGO_CLOUD, + HYPERVISOR_INCLOUD_SPHERE: HOST_TYPE_INCLOUD_SPHERE, + HYPERVISOR_PROXMOX: HOST_TYPE_PROXMOX, + HYPERVISOR_REMOTEFILE: HOST_TYPE_REMOTEFILE, +} + +var HOSTTYPE_HYPERVISOR = map[string]string{ + HOST_TYPE_HYPERVISOR: HYPERVISOR_KVM, + HOST_TYPE_BAREMETAL: HYPERVISOR_BAREMETAL, + HOST_TYPE_ESXI: HYPERVISOR_ESXI, + HOST_TYPE_KUBELET: HYPERVISOR_CONTAINER, + HOST_TYPE_ALIYUN: HYPERVISOR_ALIYUN, + HOST_TYPE_APSARA: HYPERVISOR_APSARA, + HOST_TYPE_AZURE: HYPERVISOR_AZURE, + HOST_TYPE_AWS: HYPERVISOR_AWS, + HOST_TYPE_QCLOUD: HYPERVISOR_QCLOUD, + HOST_TYPE_HUAWEI: HYPERVISOR_HUAWEI, + HOST_TYPE_HCSO: HYPERVISOR_HCSO, + HOST_TYPE_HCS: HYPERVISOR_HCS, + HOST_TYPE_OPENSTACK: HYPERVISOR_OPENSTACK, + HOST_TYPE_UCLOUD: HYPERVISOR_UCLOUD, + HOST_TYPE_ZSTACK: HYPERVISOR_ZSTACK, + HOST_TYPE_GOOGLE: HYPERVISOR_GOOGLE, + HOST_TYPE_CTYUN: HYPERVISOR_CTYUN, + HOST_TYPE_ECLOUD: HYPERVISOR_ECLOUD, + HOST_TYPE_JDCLOUD: HYPERVISOR_JDCLOUD, + HOST_TYPE_CLOUDPODS: HYPERVISOR_CLOUDPODS, + HOST_TYPE_NUTANIX: HYPERVISOR_NUTANIX, + HOST_TYPE_BINGO_CLOUD: HYPERVISOR_BINGO_CLOUD, + HOST_TYPE_INCLOUD_SPHERE: HYPERVISOR_INCLOUD_SPHERE, + HOST_TYPE_PROXMOX: HYPERVISOR_PROXMOX, + HOST_TYPE_REMOTEFILE: HYPERVISOR_REMOTEFILE, +} + +const ( + VM_DEFAULT_WINDOWS_LOGIN_USER = "Administrator" + VM_DEFAULT_LINUX_LOGIN_USER = "root" + VM_AWS_DEFAULT_LOGIN_USER = "ec2user" + VM_AWS_DEFAULT_WINDOWS_LOGIN_USER = "Administrator" + VM_JDCLOUD_DEFAULT_WINDOWS_LOGIN_USER = "administrator" + VM_AZURE_DEFAULT_LOGIN_USER = "azureuser" + VM_ZSTACK_DEFAULT_LOGIN_USER = "root" + + VM_METADATA_APP_TAGS = "app_tags" + VM_METADATA_CREATE_PARAMS = "create_params" + VM_METADATA_LOGIN_ACCOUNT = "login_account" + VM_METADATA_LOGIN_KEY = "login_key" + VM_METADATA_LAST_LOGIN_KEY = "last_login_key" + VM_METADATA_LOGIN_KEY_TIMESTAMP = "login_key_timestamp" + VM_METADATA_OS_ARCH = "os_arch" + VM_METADATA_OS_DISTRO = "os_distribution" + VM_METADATA_OS_NAME = "os_name" + VM_METADATA_OS_VERSION = "os_version" + VM_METADATA_CGROUP_CPUSET = "cgroup_cpuset" + VM_METADATA_ENABLE_MEMCLEAN = "enable_memclean" +) + +func Hypervisors2HostTypes(hypervisors []string) []string { + hostTypes := make([]string, len(hypervisors)) + for i := range hypervisors { + hostTypes[i] = HYPERVISOR_HOSTTYPE[hypervisors[i]] + } + return hostTypes +} + +// windows allow a maximal length of 15 +// http://support.microsoft.com/kb/909264 +const MAX_WINDOWS_COMPUTER_NAME_LENGTH = 15 diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/host_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/host_const.go new file mode 100644 index 0000000000..757efb833d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/host_const.go @@ -0,0 +1,135 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + HOST_TYPE_BAREMETAL = "baremetal" + HOST_TYPE_HYPERVISOR = "hypervisor" // KVM + HOST_TYPE_KVM = "kvm" + HOST_TYPE_ESXI = "esxi" // # VMWare vSphere ESXi + HOST_TYPE_KUBELET = "kubelet" // # Kubernetes Kubelet + HOST_TYPE_HYPERV = "hyperv" // # Microsoft Hyper-V + HOST_TYPE_XEN = "xen" // # XenServer + + HOST_TYPE_ALIYUN = "aliyun" + HOST_TYPE_APSARA = "apsara" + HOST_TYPE_AWS = "aws" + HOST_TYPE_QCLOUD = "qcloud" + HOST_TYPE_AZURE = "azure" + HOST_TYPE_HUAWEI = "huawei" + HOST_TYPE_HCSO = "hcso" + HOST_TYPE_HCS = "hcs" + HOST_TYPE_OPENSTACK = "openstack" + HOST_TYPE_UCLOUD = "ucloud" + HOST_TYPE_ZSTACK = "zstack" + HOST_TYPE_GOOGLE = "google" + HOST_TYPE_CTYUN = "ctyun" + HOST_TYPE_ECLOUD = "ecloud" + HOST_TYPE_JDCLOUD = "jdcloud" + HOST_TYPE_CLOUDPODS = "cloudpods" + HOST_TYPE_NUTANIX = "nutanix" + HOST_TYPE_BINGO_CLOUD = "bingocloud" + HOST_TYPE_INCLOUD_SPHERE = "incloudsphere" + HOST_TYPE_PROXMOX = "proxmox" + HOST_TYPE_REMOTEFILE = "remotefile" + + HOST_TYPE_DEFAULT = HOST_TYPE_HYPERVISOR + + // # possible status + HOST_ONLINE = "online" + HOST_ENABLED = "online" + HOST_OFFLINE = "offline" + HOST_DISABLED = "offline" + + NIC_TYPE_IPMI = "ipmi" + NIC_TYPE_ADMIN = "admin" + // #NIC_TYPE_NORMAL = 'normal' + + BAREMETAL_INIT = "init" + BAREMETAL_PREPARE = "prepare" + BAREMETAL_PREPARE_FAIL = "prepare_fail" + BAREMETAL_READY = "ready" + BAREMETAL_RUNNING = "running" + BAREMETAL_MAINTAINING = "maintaining" + BAREMETAL_START_MAINTAIN = "start_maintain" + BAREMETAL_MAINTAIN_FAIL = "maintain_fail" + BAREMETAL_DELETING = "deleting" + BAREMETAL_DELETE = "delete" + BAREMETAL_DELETE_FAIL = "delete_fail" + BAREMETAL_UNKNOWN = "unknown" + BAREMETAL_SYNCING_STATUS = "syncing_status" + BAREMETAL_SYNC = "sync" + BAREMETAL_SYNC_FAIL = "sync_fail" + BAREMETAL_START_CONVERT = "start_convert" + BAREMETAL_CONVERTING = "converting" + BAREMETAL_START_FAIL = "start_fail" + BAREMETAL_STOP_FAIL = "stop_fail" + + BAREMETAL_START_PROBE = "start_probe" + BAREMETAL_PROBING = "probing" + BAREMETAL_PROBE_FAIL = "probe_fail" + + BAREMETAL_START_INSERT_ISO = "start_insert" + BAREMETAL_INSERTING_ISO = "inserting_iso" + BAREMETAL_INSERT_FAIL = "insert_fail" + + BAREMETAL_START_EJECT_ISO = "start_eject" + BAREMETAL_EJECTING_ISO = "ejecting_iso" + BAREMETAL_EJECT_FAIL = "eject_fail" + + HOST_STATUS_RUNNING = BAREMETAL_RUNNING + HOST_STATUS_READY = BAREMETAL_READY + HOST_STATUS_UNKNOWN = BAREMETAL_UNKNOWN +) + +const ( + BAREMETAL_CDROM_ACTION_INSERT = "insert" + BAREMETAL_CDROM_ACTION_EJECT = "eject" +) + +const ( + HostResourceTypeShared = "shared" + HostResourceTypeDefault = HostResourceTypeShared + HostResourceTypePrepaidRecycle = "prepaid" + HostResourceTypeDedicated = "dedicated" +) + +var HOST_TYPES = []string{ + HOST_TYPE_BAREMETAL, + HOST_TYPE_HYPERVISOR, + HOST_TYPE_ESXI, + HOST_TYPE_KUBELET, + HOST_TYPE_XEN, + HOST_TYPE_ALIYUN, + HOST_TYPE_APSARA, + HOST_TYPE_AZURE, + HOST_TYPE_AWS, + HOST_TYPE_QCLOUD, + HOST_TYPE_HUAWEI, + HOST_TYPE_HCSO, + HOST_TYPE_HCS, + HOST_TYPE_OPENSTACK, + HOST_TYPE_UCLOUD, + HOST_TYPE_ZSTACK, + HOST_TYPE_CTYUN, + HOST_TYPE_GOOGLE, + HOST_TYPE_JDCLOUD, + HOST_TYPE_CLOUDPODS, + HOST_TYPE_NUTANIX, + HOST_TYPE_BINGO_CLOUD, + HOST_TYPE_INCLOUD_SPHERE, + HOST_TYPE_PROXMOX, + HOST_TYPE_REMOTEFILE, +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/inter_vpc_network.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/inter_vpc_network.go new file mode 100644 index 0000000000..b3a9e99746 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/inter_vpc_network.go @@ -0,0 +1,31 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + INTER_VPC_NETWORK_STATUS_AVAILABLE = "available" + INTER_VPC_NETWORK_STATUS_CREATING = "creating" + INTER_VPC_NETWORK_STATUS_CREATE_FAILED = "create_failed" + INTER_VPC_NETWORK_STATUS_DELETE_FAILED = "delete_failed" + INTER_VPC_NETWORK_STATUS_DELETING = "deleting" + INTER_VPC_NETWORK_STATUS_ACTIVE = "active" + INTER_VPC_NETWORK_STATUS_ADDVPC = "add_vpc" + INTER_VPC_NETWORK_STATUS_ADDVPC_FAILED = "add_vpc_failed" + INTER_VPC_NETWORK_STATUS_REMOVEVPC = "remove_vpc" + INTER_VPC_NETWORK_STATUS_REMOVEVPC_FAILED = "remove_vpc_failed" + INTER_VPC_NETWORK_STATUS_UPDATEROUTE = "update_route" + INTER_VPC_NETWORK_STATUS_UPDATEROUTE_FAILED = "update_route_failed" + INTER_VPC_NETWORK_STATUS_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/kafka.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/kafka.go new file mode 100644 index 0000000000..ab9ad68908 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/kafka.go @@ -0,0 +1,24 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + KAFKA_STATUS_AVAILABLE = "available" + KAFKA_STATUS_UNAVAILABLE = "unavailable" + KAFKA_STATUS_CREATING = "creating" + KAFKA_STATUS_DELETING = "deleting" + KAFKA_STATUS_DELETE_FAILED = "delete_failed" + KAFKA_STATUS_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/kube_cluster.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/kube_cluster.go new file mode 100644 index 0000000000..2c0dd699de --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/kube_cluster.go @@ -0,0 +1,29 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + KUBE_CLUSTER_STATUS_RUNNING = "running" + KUBE_CLUSTER_STATUS_CREATING = "creating" + KUBE_CLUSTER_STATUS_ABNORMAL = "abnormal" + // 升级中 + KUBE_CLUSTER_STATUS_UPDATING = "updating" + // 升级失败 + KUBE_CLUSTER_STATUS_UPDATING_FAILED = "updating_failed" + // 伸缩中 + KUBE_CLUSTER_STATUS_SCALING = "scaling" + // 停止 + KUBE_CLUSTER_STATUS_STOPPED = "stopped" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/loadbalancer_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/loadbalancer_const.go new file mode 100644 index 0000000000..356d96a02d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/loadbalancer_const.go @@ -0,0 +1,436 @@ +// Copyright 2019 Yunion +// +// 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 compute + +import ( + "yunion.io/x/onecloud/pkg/util/choices" +) + +// Load balancer status transition (for spec status) +// +// create start stop delete +// init running - - - +// running - - stopped stopped +// stopped - running - - +// +// Each entity will have spec and runtime version. Spec version will increment +// on entity attribute update. Runtime version will be filled by the scheduler +// to the newest spec it has seen and committed +// +// When spec and runtime version differ, scheduler will set runtime version to +// "configuring", "stopping" and will finally transition to a terminal state. +// +// In the case of instance has PendingDeleted marked, it is also the +// scheduler's duty to make the runtime status to stopped and finally the +// entity in question +// +const ( + LB_STATUS_ENABLED = "enabled" + LB_STATUS_DISABLED = "disabled" + + LB_STATUS_INIT = "init" + + LB_CREATING = "creating" + LB_CREATE_FAILED = "create_failed" + + LB_SYNC_CONF = "sync_conf" + LB_SYNC_CONF_FAILED = "sync_conf_failed" + + LB_STATUS_DELETING = "deleting" + LB_STATUS_DELETE_FAILED = "delete_failed" + LB_STATUS_DELETED = "deleted" + + LB_STATUS_START_FAILED = "start_failed" + LB_STATUS_STOP_FAILED = "stop_failed" + + LB_UPDATE_TAGS = "update_tags" + LB_UPDATE_TAGS_FAILED = "update_tags_fail" + + LB_STATUS_UNKNOWN = "unknown" +) + +var LB_STATUS_SPEC = choices.NewChoices( + LB_STATUS_ENABLED, + LB_STATUS_DISABLED, +) + +const ( + //默认后端服务器组 + LB_BACKENDGROUP_TYPE_DEFAULT = "default" + //普通后端服务器组 + LB_BACKENDGROUP_TYPE_NORMAL = "normal" + //主备后端服务器组 + LB_BACKENDGROUP_TYPE_MASTER_SLAVE = "master_slave" +) + +var LB_BACKENDGROUP_TYPE = choices.NewChoices( + LB_BACKENDGROUP_TYPE_DEFAULT, + LB_BACKENDGROUP_TYPE_NORMAL, + LB_BACKENDGROUP_TYPE_MASTER_SLAVE, +) + +const ( + LB_ALIYUN_SPEC_SHAREABLE = "" //性能共享型 + LB_ALIYUN_SPEC_S1_SMALL = "slb.s1.small" + LB_ALIYUN_SPEC_S2_SMALL = "slb.s2.small" + LB_ALIYUN_SPEC_S3_SMALL = "slb.s3.small" + LB_ALIYUN_SPEC_S2_MEDIUM = "slb.s2.medium" + LB_ALIYUN_SPEC_S3_MEDIUM = "slb.s3.medium" + LB_ALIYUN_SPEC_S3_LARGE = "slb.s3.large" + + LB_AWS_SPEC_APPLICATION = "application" + LB_AWS_SPEC_NETWORK = "network" +) + +const ( + LB_MbpsMin = 0 + LB_MbpsMax = 10000 +) + +var LB_ALIYUN_SPECS = choices.NewChoices( + LB_ALIYUN_SPEC_SHAREABLE, + LB_ALIYUN_SPEC_S1_SMALL, + LB_ALIYUN_SPEC_S2_SMALL, + LB_ALIYUN_SPEC_S3_SMALL, + LB_ALIYUN_SPEC_S2_MEDIUM, + LB_ALIYUN_SPEC_S3_MEDIUM, + LB_ALIYUN_SPEC_S3_LARGE, +) + +var LB_AWS_SPECS = choices.NewChoices( + LB_AWS_SPEC_APPLICATION, + LB_AWS_SPEC_NETWORK, +) + +// Load Balancer network type (vpc or classic) determines viable backend +// servers (they should be from the same network type as the load balancer). +// +// Load Balancer address type (intranet or internet) determins the scope the +// service provided by load balancer can be accessed. If it's intranet, then +// it will only be accessible from the specified network. If it's internet, +// then it's public and can be accessed from outside the cloud region +const ( + LB_ADDR_TYPE_INTRANET = "intranet" + LB_ADDR_TYPE_INTERNET = "internet" +) + +var LB_ADDR_TYPES = choices.NewChoices( + LB_ADDR_TYPE_INTERNET, + LB_ADDR_TYPE_INTRANET, +) + +const ( + LB_NETWORK_TYPE_CLASSIC = "classic" + LB_NETWORK_TYPE_VPC = "vpc" +) + +var LB_NETWORK_TYPES = choices.NewChoices( + LB_NETWORK_TYPE_CLASSIC, + LB_NETWORK_TYPE_VPC, +) + +// TODO https_direct sni +const ( + LB_LISTENER_TYPE_TCP = "tcp" + LB_LISTENER_TYPE_UDP = "udp" + LB_LISTENER_TYPE_TCP_UDP = "tcp_udp" + LB_LISTENER_TYPE_HTTP = "http" + LB_LISTENER_TYPE_HTTPS = "https" + LB_LISTENER_TYPE_TERMINATED_HTTPS = "terminated_https" +) + +var LB_LISTENER_TYPES = choices.NewChoices( + LB_LISTENER_TYPE_TCP, + LB_LISTENER_TYPE_UDP, + LB_LISTENER_TYPE_HTTP, + LB_LISTENER_TYPE_HTTPS, +) + +// aws_network_lb_listener +var AWS_NETWORK_LB_LISTENER_TYPES = choices.NewChoices( + LB_LISTENER_TYPE_TCP, + LB_LISTENER_TYPE_UDP, + // LB_LISTENER_TYPE_TCP_UDP +) + +// aws_application_lb_listener +var AWS_APPLICATION_LB_LISTENER_TYPES = choices.NewChoices( + LB_LISTENER_TYPE_HTTP, + LB_LISTENER_TYPE_HTTPS, +) + +// huawei backend group protocal choices +var HUAWEI_LBBG_PROTOCOL_TYPES = choices.NewChoices( + LB_LISTENER_TYPE_TCP, + LB_LISTENER_TYPE_UDP, + LB_LISTENER_TYPE_HTTP, +) + +var HUAWEI_LBBG_SCHDULERS = choices.NewChoices( + LB_SCHEDULER_WLC, + LB_SCHEDULER_RR, + LB_SCHEDULER_SCH, +) + +const ( + LB_ACL_TYPE_BLACK = "black" + LB_ACL_TYPE_WHITE = "white" +) + +var LB_ACL_TYPES = choices.NewChoices( + LB_ACL_TYPE_BLACK, + LB_ACL_TYPE_WHITE, +) + +const ( + LB_TLS_CERT_FINGERPRINT_ALGO_SHA1 = "sha1" + LB_TLS_CERT_FINGERPRINT_ALGO_SHA256 = "sha256" +) + +const ( + LB_TLS_CERT_PUBKEY_ALGO_RSA = "RSA" + LB_TLS_CERT_PUBKEY_ALGO_ECDSA = "ECDSA" +) + +var LB_TLS_CERT_PUBKEY_ALGOS = choices.NewChoices( + LB_TLS_CERT_PUBKEY_ALGO_RSA, + LB_TLS_CERT_PUBKEY_ALGO_ECDSA, +) + +// TODO may want extra for legacy apps +const ( + LB_TLS_CIPHER_POLICY_1_0 = "tls_cipher_policy_1_0" + LB_TLS_CIPHER_POLICY_1_1 = "tls_cipher_policy_1_1" + LB_TLS_CIPHER_POLICY_1_2 = "tls_cipher_policy_1_2" + LB_TLS_CIPHER_POLICY_1_2_strict = "tls_cipher_policy_1_2_strict" + LB_TLS_CIPHER_POLICY_deault = "" +) + +var LB_TLS_CIPHER_POLICIES = choices.NewChoices( + LB_TLS_CIPHER_POLICY_1_0, + LB_TLS_CIPHER_POLICY_1_1, + LB_TLS_CIPHER_POLICY_1_2, + LB_TLS_CIPHER_POLICY_1_2_strict, + LB_TLS_CIPHER_POLICY_deault, +) + +const ( + LB_STICKY_SESSION_TYPE_INSERT = "insert" + LB_STICKY_SESSION_TYPE_SERVER = "server" +) + +var LB_STICKY_SESSION_TYPES = choices.NewChoices( + LB_STICKY_SESSION_TYPE_INSERT, + LB_STICKY_SESSION_TYPE_SERVER, +) + +// TODO maybe https check when field need comes ;) +const ( + LB_HEALTH_CHECK_PING = "ping" + LB_HEALTH_CHECK_TCP = "tcp" + LB_HEALTH_CHECK_UDP = "udp" + LB_HEALTH_CHECK_HTTP = "http" + LB_HEALTH_CHECK_HTTPS = "https" +) + +var LB_HEALTH_CHECK_TYPES = choices.NewChoices( + LB_HEALTH_CHECK_TCP, + LB_HEALTH_CHECK_UDP, + LB_HEALTH_CHECK_HTTP, +) + +var LB_HEALTH_CHECK_TYPES_TCP = choices.NewChoices( + LB_HEALTH_CHECK_TCP, + LB_HEALTH_CHECK_HTTP, +) + +var LB_HEALTH_CHECK_TYPES_UDP = choices.NewChoices( + LB_HEALTH_CHECK_UDP, +) + +const ( + LB_HEALTH_CHECK_HTTP_CODE_1xx = "http_1xx" + LB_HEALTH_CHECK_HTTP_CODE_2xx = "http_2xx" + LB_HEALTH_CHECK_HTTP_CODE_3xx = "http_3xx" + LB_HEALTH_CHECK_HTTP_CODE_4xx = "http_4xx" + LB_HEALTH_CHECK_HTTP_CODE_5xx = "http_5xx" + LB_HEALTH_CHECK_HTTP_CODE_DEFAULT = "http_2xx,http_3xx" +) + +var LB_HEALTH_CHECK_HTTP_CODES = choices.NewChoices( + LB_HEALTH_CHECK_HTTP_CODE_1xx, + LB_HEALTH_CHECK_HTTP_CODE_2xx, + LB_HEALTH_CHECK_HTTP_CODE_3xx, + LB_HEALTH_CHECK_HTTP_CODE_4xx, + LB_HEALTH_CHECK_HTTP_CODE_5xx, +) + +const ( + LB_REDIRECT_OFF = "off" + LB_REDIRECT_RAW = "raw" +) + +var LB_REDIRECT_TYPES = choices.NewChoices( + LB_REDIRECT_OFF, + LB_REDIRECT_RAW, +) + +const ( + LB_REDIRECT_CODE_301 = int64(301) // Moved Permanently + LB_REDIRECT_CODE_302 = int64(302) // Found + LB_REDIRECT_CODE_307 = int64(307) // Temporary Redirect +) + +var LB_REDIRECT_CODES = []int64{ + LB_REDIRECT_CODE_301, + LB_REDIRECT_CODE_302, + LB_REDIRECT_CODE_307, +} + +const ( + LB_REDIRECT_SCHEME_IDENTITY = "" + LB_REDIRECT_SCHEME_HTTP = "http" + LB_REDIRECT_SCHEME_HTTPS = "https" +) + +var LB_REDIRECT_SCHEMES = choices.NewChoices( + LB_REDIRECT_SCHEME_IDENTITY, + LB_REDIRECT_SCHEME_HTTP, + LB_REDIRECT_SCHEME_HTTPS, +) + +const ( + LB_BOOL_ON = "on" + LB_BOOL_OFF = "off" +) + +var LB_BOOL_VALUES = choices.NewChoices( + LB_BOOL_ON, + LB_BOOL_OFF, +) + +//TODO +// +// - qch, quic connection id +// - mh, maglev consistent hash +const ( + LB_SCHEDULER_RR = "rr" // round robin + LB_SCHEDULER_WRR = "wrr" // weighted round robin + LB_SCHEDULER_WLC = "wlc" // weighted least connection + LB_SCHEDULER_SCH = "sch" // source-ip-based consistent hash + LB_SCHEDULER_TCH = "tch" // 4-tuple-based consistent hash + LB_SCHEDULER_QCH = "qch" + LB_SCHEDULER_MH = "mh" // maglev consistent hash +) + +var LB_SCHEDULER_TYPES = choices.NewChoices( + LB_SCHEDULER_RR, + LB_SCHEDULER_WRR, + LB_SCHEDULER_WLC, + LB_SCHEDULER_SCH, + LB_SCHEDULER_TCH, +) + +const ( + LB_SENDPROXY_OFF = "off" + LB_SENDPROXY_V1 = "v1" + LB_SENDPROXY_V2 = "v2" + LB_SENDPROXY_V2_SSL = "v2-ssl" + LB_SENDPROXY_V2_SSL_CN = "v2-ssl-cn" +) + +var LB_SENDPROXY_CHOICES = choices.NewChoices( + LB_SENDPROXY_OFF, + LB_SENDPROXY_V1, + LB_SENDPROXY_V2, + LB_SENDPROXY_V2_SSL, + LB_SENDPROXY_V2_SSL_CN, +) + +var LB_ALIYUN_UDP_SCHEDULER_TYPES = choices.NewChoices( + LB_SCHEDULER_RR, + LB_SCHEDULER_WRR, + LB_SCHEDULER_WLC, + LB_SCHEDULER_SCH, + LB_SCHEDULER_TCH, + LB_SCHEDULER_QCH, +) + +var LB_ALIYUN_COMMON_SCHEDULER_TYPES = choices.NewChoices( + LB_SCHEDULER_RR, + LB_SCHEDULER_WRR, + LB_SCHEDULER_WLC, +) + +// TODO raw type +const ( + LB_BACKEND_GUEST = "guest" + LB_BACKEND_HOST = "host" + LB_BACKEND_IP = "ip" +) + +var LB_BACKEND_TYPES = choices.NewChoices( + LB_BACKEND_GUEST, + LB_BACKEND_HOST, + LB_BACKEND_IP, +) + +const ( + LB_BACKEND_ROLE_DEFAULT = "default" + LB_BACKEND_ROLE_MASTER = "master" + LB_BACKEND_ROLE_SLAVE = "slave" +) + +var LB_BACKEND_ROLES = choices.NewChoices( + LB_BACKEND_ROLE_MASTER, + LB_BACKEND_ROLE_DEFAULT, + LB_BACKEND_ROLE_SLAVE, +) + +const ( + LB_CHARGE_TYPE_BY_TRAFFIC = "traffic" + LB_CHARGE_TYPE_BY_BANDWIDTH = "bandwidth" +) + +var LB_CHARGE_TYPES = choices.NewChoices( + LB_CHARGE_TYPE_BY_TRAFFIC, + LB_CHARGE_TYPE_BY_BANDWIDTH, +) + +const ( + LB_HA_STATE_MASTER = "MASTER" + LB_HA_STATE_BACKUP = "BACKUP" + LB_HA_STATE_FAULT = "FAULT" + LB_HA_STATE_STOP = "STOP" + LB_HA_STATE_UNKNOWN = "UNKNOWN" +) + +var LB_HA_STATES = choices.NewChoices( + LB_HA_STATE_MASTER, + LB_HA_STATE_BACKUP, + LB_HA_STATE_FAULT, + LB_HA_STATE_STOP, + LB_HA_STATE_UNKNOWN, +) + +const ( + LBAGENT_QUERY_ORIG_KEY = "_orig" + LBAGENT_QUERY_ORIG_VAL = "lbagent" +) + +const ( + LB_ASSOCIATE_TYPE_LISTENER = "listener" + LB_ASSOCIATE_TYPE_RULE = "rule" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/modelarts_pool.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/modelarts_pool.go new file mode 100644 index 0000000000..311afd7888 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/modelarts_pool.go @@ -0,0 +1,25 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + MODELARTS_POOL_STATUS_RUNNING = "running" + MODELARTS_POOL_STATUS_ABNORMAL = "abnormal" + MODELARTS_POOL_STATUS_CREATING = "creating" + MODELARTS_POOL_STATUS_DELETING = "deleting" + MODELARTS_POOL_STATUS_CHANGE_CONFIG = "change_config" + MODELARTS_POOL_STATUS_ERROR = "error" + MODELARTS_POOL_STATUS_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/modelarts_pool_sku.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/modelarts_pool_sku.go new file mode 100644 index 0000000000..3dec38e833 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/modelarts_pool_sku.go @@ -0,0 +1,20 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + MODELARTS_POOL_SKU_AVAILABLE = "available" + MODELARTS_POOL_SKU_SOLDOUT = "soldout" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/mongodb_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/mongodb_const.go new file mode 100644 index 0000000000..d5c2887159 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/mongodb_const.go @@ -0,0 +1,38 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + MONGO_DB_STATUS_CREATING = "creating" + MONGO_DB_STATUS_RUNNING = "running" + MONGO_DB_STATUS_DEPLOY = "deploy" + MONGO_DB_STATUS_CHANGE_CONFIG = "change_config" + MONGO_DB_STATUS_DELETING = "deleting" + MONGO_DB_STATUS_DELETE_FAILED = "delete_failed" + MONGO_DB_STATUS_REBOOTING = "rebooting" + MONGO_DB_STATUS_UNKNOWN = "unknown" + + MONGO_DB_ENGINE_WIRED_TIGER = "WiredTiger" + MONGO_DB_ENGINE_ROCKS = "Rocks" + + MONGO_DB_ENGINE_VERSION_40 = "4.0" + MONGO_DB_ENGINE_VERSION_36 = "3.6" + MONGO_DB_ENGINE_VERSION_32 = "3.2" + + // 分片 + MONGO_DB_CATEGORY_SHARDING = "sharding" + // 副本集 + MONGO_DB_CATEGORY_REPLICATE = "replicate" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/mount_targets.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/mount_targets.go new file mode 100644 index 0000000000..080f8e64fc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/mount_targets.go @@ -0,0 +1,25 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + MOUNT_TARGET_STATUS_AVAILABLE = "available" + MOUNT_TARGET_STATUS_UNAVAILABLE = "unavailable" + MOUNT_TARGET_STATUS_CREATING = "creating" + MOUNT_TARGET_STATUS_CREATE_FAILED = "create_failed" + MOUNT_TARGET_STATUS_DELETING = "deleting" + MOUNT_TARGET_STATUS_DELETE_FAILED = "delete_failed" + MOUNT_TARGET_STATUS_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/nat_skus.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/nat_skus.go new file mode 100644 index 0000000000..dd2e529ba2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/nat_skus.go @@ -0,0 +1,22 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + NAT_SKU_AVAILABLE = "available" + NAT_SKU_SOLDOUT = "soldout" + + ALIYUN_NAT_SKU_DEFAULT = "Default" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/natgateway.go new file mode 100644 index 0000000000..8dca6b8166 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/natgateway.go @@ -0,0 +1,39 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + NAT_STAUTS_AVAILABLE = "available" // 可用 + NAT_STATUS_ALLOCATE = "allocate" // 创建中 + NAT_STATUS_DEPLOYING = "deploying" // 配置中 + NAT_STATUS_UNKNOWN = "unknown" // 未知状态 + NAT_STATUS_CREATE_FAILED = "create_failed" // 创建失败 + NAT_STATUS_DELETED = "deleted" // 删除 + NAT_STATUS_DELETING = "deleting" // 删除中 + NAT_STATUS_DELETE_FAILED = "delete_failed" // 删除失败 + NAT_STATUS_SET_AUTO_RENEW = "set_auto_renew" // 设置自动续费中 + NAT_STATUS_SET_AUTO_RENEW_FAILED = "set_auto_renew_failed" // 设置自动续费失败 + NAT_STATUS_RENEWING = "renewing" // 续费中 + NAT_STATUS_RENEW_FAILED = "renew_failed" // 续费失败 + + NAT_SPEC_SMALL = "small" //小型 + NAT_SPEC_MIDDLE = "middle" //中型 + NAT_SPEC_LARGE = "large" //大型 + NAT_SPEC_XLARGE = "xlarge" //超大型 + + QCLOUD_NAT_SPEC_SMALL = "small" + QCLOUD_NAT_SPEC_MIDDLE = "middle" + QCLOUD_NAT_SPEC_LARGE = "large" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/network.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/network.go new file mode 100644 index 0000000000..6a9bf4fdc3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/network.go @@ -0,0 +1,20 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + NETWORK_TYPE_VPC = "vpc" + NETWORK_TYPE_CLASSIC = "classic" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/network_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/network_const.go new file mode 100644 index 0000000000..a1d8002384 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/network_const.go @@ -0,0 +1,66 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + // # DEFAULT_BANDWIDTH = options.default_bandwidth + MAX_BANDWIDTH = 100000 + + NETWORK_TYPE_GUEST = "guest" + NETWORK_TYPE_BAREMETAL = "baremetal" + NETWORK_TYPE_CONTAINER = "container" + NETWORK_TYPE_PXE = "pxe" + NETWORK_TYPE_IPMI = "ipmi" + NETWORK_TYPE_EIP = "eip" + + STATIC_ALLOC = "static" + + MAX_NETWORK_NAME_LEN = 11 + + EXTRA_DNS_UPDATE_TARGETS = "__extra_dns_update_targets" + + NETWORK_STATUS_INIT = "init" + NETWORK_STATUS_PENDING = "pending" + NETWORK_STATUS_AVAILABLE = "available" + NETWORK_STATUS_UNAVAILABLE = "unavailable" + NETWORK_STATUS_FAILED = "failed" + NETWORK_STATUS_UNKNOWN = "unknown" + NETWORK_STATUS_START_DELETE = "start_delete" + NETWORK_STATUS_DELETING = "deleting" + NETWORK_STATUS_DELETED = "deleted" + NETWORK_STATUS_DELETE_FAILED = "delete_failed" +) + +var ( + ALL_NETWORK_TYPES = []string{ + NETWORK_TYPE_GUEST, + NETWORK_TYPE_BAREMETAL, + NETWORK_TYPE_CONTAINER, + NETWORK_TYPE_PXE, + NETWORK_TYPE_IPMI, + NETWORK_TYPE_EIP, + } + + REGIONAL_NETWORK_PROVIDERS = []string{ + CLOUD_PROVIDER_HUAWEI, + CLOUD_PROVIDER_HCSO, + CLOUD_PROVIDER_HCS, + CLOUD_PROVIDER_CTYUN, + CLOUD_PROVIDER_UCLOUD, + CLOUD_PROVIDER_GOOGLE, + CLOUD_PROVIDER_OPENSTACK, + CLOUD_PROVIDER_JDCLOUD, + } +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/networkinterface_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/networkinterface_const.go new file mode 100644 index 0000000000..d26ce9b878 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/networkinterface_const.go @@ -0,0 +1,32 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER = "server" + NETWORK_INTERFACE_ASSOCIATE_TYPE_RESERVED = "reserved" + NETWORK_INTERFACE_ASSOCIATE_TYPE_LOADBALANCER = "loadbalancer" + NETWORK_INTERFACE_ASSOCIATE_TYPE_VIP = "vip" + NETWORK_INTERFACE_ASSOCIATE_TYPE_DHCP = "dhcp" + + NETWORK_INTERFACE_STATUS_INIT = "init" + NETWORK_INTERFACE_STATUS_CREATING = "creating" + NETWORK_INTERFACE_STATUS_AVAILABLE = "available" + NETWORK_INTERFACE_STATUS_DISABLED = "disabled" + NETWORK_INTERFACE_STATUS_ATTACHING = "attaching" + NETWORK_INTERFACE_STATUS_DETACHING = "detaching" + NETWORK_INTERFACE_STATUS_DELETING = "deleting" + NETWORK_INTERFACE_STATUS_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/regiondata.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/regiondata.go new file mode 100644 index 0000000000..91ab4c24f3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/regiondata.go @@ -0,0 +1,568 @@ +// Copyright 2019 Yunion +// +// 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 compute + +import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +var ( + // China + RegionBeijing = cloudprovider.SGeographicInfo{ + Latitude: 39.90419989999999, + Longitude: 116.4073963, + City: CITY_BEI_JING, + CountryCode: COUNTRY_CODE_CN, + } + RegionNingxia = cloudprovider.SGeographicInfo{ + Latitude: 37.198731, + Longitude: 106.1580937, + City: CITY_NING_XIA, + CountryCode: COUNTRY_CODE_CN, + } + RegionShanghai = cloudprovider.SGeographicInfo{ + Latitude: 31.17, + Longitude: 121.47, + City: CITY_SHANG_HAI, + CountryCode: COUNTRY_CODE_CN, + } + RegionGuangzhou = cloudprovider.SGeographicInfo{ + Latitude: 23.12911, + Longitude: 113.264385, + City: CITY_GUANG_ZHOU, + CountryCode: COUNTRY_CODE_CN, + } + RegionDalian = cloudprovider.SGeographicInfo{ + Latitude: 38.91400300000001, + Longitude: 121.614682, + City: CITY_DA_LIAN, + CountryCode: COUNTRY_CODE_CN, + } + RegionGuiyang = cloudprovider.SGeographicInfo{ + Latitude: 26.6470035286, + Longitude: 106.6302113880, + City: CITY_GUI_YANG, + CountryCode: COUNTRY_CODE_CN, + } + RegionNeimenggu = cloudprovider.SGeographicInfo{ + Latitude: 41.0178713, + Longitude: 113.094978, + City: CITY_NEI_MENG_GU, + CountryCode: COUNTRY_CODE_CN, + } + RegionQingdao = cloudprovider.SGeographicInfo{ + Latitude: 36.067108, + Longitude: 120.382607, + City: CITY_QING_DAO, + CountryCode: COUNTRY_CODE_CN, + } + RegionZhangjiakou = cloudprovider.SGeographicInfo{ + Latitude: 40.767544, + Longitude: 114.886337, + City: CITY_ZHANG_JIA_KOU, + CountryCode: COUNTRY_CODE_CN, + } + RegionHuhehaote = cloudprovider.SGeographicInfo{ + Latitude: 40.842358, + Longitude: 111.749992, + City: CITY_HU_HE_HAO_TE, + CountryCode: COUNTRY_CODE_CN, + } + RegionHangzhou = cloudprovider.SGeographicInfo{ + Latitude: 30.274084, + Longitude: 120.155067, + City: CITY_HANG_ZHOU, + CountryCode: COUNTRY_CODE_CN, + } + RegionShenzhen = cloudprovider.SGeographicInfo{ + Latitude: 22.543097, + Longitude: 114.057861, + City: CITY_SHEN_ZHEN, + CountryCode: COUNTRY_CODE_CN, + } + RegionChengdu = cloudprovider.SGeographicInfo{ + Latitude: 30.572815, + Longitude: 104.066803, + City: CITY_CHENG_DU, + CountryCode: COUNTRY_CODE_CN, + } + RegionHeyuan = cloudprovider.SGeographicInfo{ + Latitude: 23.7292717, + Longitude: 114.6965786, + City: CITY_HE_YUAN, + CountryCode: COUNTRY_CODE_CN, + } + RegionWulanchabu = cloudprovider.SGeographicInfo{ + Latitude: 41.0178065, + Longitude: 113.094978, + City: CITY_WU_LAN_CHA_BU, + CountryCode: COUNTRY_CODE_CN, + } + RegionChongqing = cloudprovider.SGeographicInfo{ + Latitude: 29.431585, + Longitude: 106.912254, + City: CITY_CHONG_QING, + CountryCode: COUNTRY_CODE_CN, + } + RegionNanjing = cloudprovider.SGeographicInfo{ + Latitude: 32.0584065670, + Longitude: 118.7964897811, + City: CITY_NAN_JING, + CountryCode: COUNTRY_CODE_CN, + } + + // Asia + RegionTaiwan = cloudprovider.SGeographicInfo{ + Latitude: 25.0443, + Longitude: 121.509, + City: CITY_TAI_WAN, + CountryCode: COUNTRY_CODE_CN, + } + RegionHongkong = cloudprovider.SGeographicInfo{ + Latitude: 22.396427, + Longitude: 114.109497, + City: CITY_HONG_KONG, + CountryCode: COUNTRY_CODE_CN, + } + RegionTokyo = cloudprovider.SGeographicInfo{ + Latitude: 35.709026, + Longitude: 139.731995, + City: CITY_TOKYO, + CountryCode: COUNTRY_CODE_JP, + } + RegionOsaka = cloudprovider.SGeographicInfo{ + Latitude: 34.6937378, + Longitude: 135.5021651, + City: CITY_OSAKA, + CountryCode: COUNTRY_CODE_JP, + } + RegionSeoul = cloudprovider.SGeographicInfo{ + Latitude: 34.6937378, + Longitude: 135.5021651, + City: CITY_SEOUL, + CountryCode: COUNTRY_CODE_KR, + } + RegionBusan = cloudprovider.SGeographicInfo{ + Latitude: 35.1, + Longitude: 129.0403, + City: CITY_BUSAN, + CountryCode: COUNTRY_CODE_KR, + } + + RegionMumbai = cloudprovider.SGeographicInfo{ + Latitude: 19.07599, + Longitude: 72.877393, + City: CITY_MUMBAI, + CountryCode: COUNTRY_CODE_IN, + } + RegionDelhi = cloudprovider.SGeographicInfo{ + Latitude: 28.61, + Longitude: 77.23, + City: CITY_DELHI, + CountryCode: COUNTRY_CODE_IN, + } + RegionMaharashtra = cloudprovider.SGeographicInfo{ + Latitude: 18.97, + Longitude: 72.82, + City: CITY_MAHARASHTRA, + CountryCode: COUNTRY_CODE_IN, + } + RegionKanchipuram = cloudprovider.SGeographicInfo{ + Latitude: 12.8387, + Longitude: 79.7016, + City: CITY_KANCHIPURAM, + CountryCode: COUNTRY_CODE_IN, + } + + RegionSingapore = cloudprovider.SGeographicInfo{ + Latitude: 1.352083, + Longitude: 103.819839, + City: CITY_SINGAPORE, + CountryCode: COUNTRY_CODE_SG, + } + RegionJakarta = cloudprovider.SGeographicInfo{ + Latitude: -6.175110, + Longitude: 106.865036, + City: CITY_JAKARTA, + CountryCode: COUNTRY_CODE_ID, + } + RegionKualaLumpur = cloudprovider.SGeographicInfo{ + Latitude: 3.139003, + Longitude: 101.686852, + City: CITY_KUALA_LUMPUR, + CountryCode: COUNTRY_CODE_MY, + } + RegionBangkok = cloudprovider.SGeographicInfo{ + Latitude: 13.7563309, + Longitude: 100.5017651, + City: CITY_BANGKOK, + CountryCode: COUNTRY_CODE_TH, + } + + RegionSydney = cloudprovider.SGeographicInfo{ + Latitude: -33.8688197, + Longitude: 151.2092955, + City: CITY_SYDNEY, + CountryCode: COUNTRY_CODE_AU, + } + RegionMelbourne = cloudprovider.SGeographicInfo{ + Latitude: -37.813611, + Longitude: 144.963056, + City: CITY_MELBOURNE, + CountryCode: COUNTRY_CODE_AU, + } + //亚拉伦拉 澳大利亚 + RegionYarralumla = cloudprovider.SGeographicInfo{ + Latitude: -35.3016, + Longitude: 149.078, + City: CITY_YARRALUMLA, + CountryCode: COUNTRY_CODE_AU, + } + + // Africa + RegionCapeTown = cloudprovider.SGeographicInfo{ + Latitude: -33.9152209, + Longitude: 18.3758904, + City: CITY_CAPE_TOWN, + CountryCode: COUNTRY_CODE_ZA, + } + // 比勒陀利亚 + RegionPretoria = cloudprovider.SGeographicInfo{ + Latitude: -25.716667, + Longitude: 28.283333, + City: CITY_PRETORIA, + CountryCode: COUNTRY_CODE_ZA, + } + RegionJohannesburg = cloudprovider.SGeographicInfo{ + Latitude: -26.1714537, + Longitude: 27.8999389, + City: CITY_JOHANNESBURG, + CountryCode: COUNTRY_CODE_ZA, + } + + // Middleeast + RegionBahrain = cloudprovider.SGeographicInfo{ + Latitude: 25.9408826, + Longitude: 50.4474957, + City: CITY_BAHRAIN, + CountryCode: COUNTRY_CODE_BH, + } + RegionDubai = cloudprovider.SGeographicInfo{ + Latitude: 25.263056, + Longitude: 55.297222, + City: CITY_DUBAI, + CountryCode: COUNTRY_CODE_AE, + } + + // Europe + RegionFinland = cloudprovider.SGeographicInfo{ + Latitude: 64.8255731, + Longitude: 21.5432837, + City: CITY_FINLAND, + CountryCode: COUNTRY_CODE_FI, + } + RegionBelgium = cloudprovider.SGeographicInfo{ + Latitude: 50.499734, + Longitude: 3.9057517, + City: CITY_BELGIUM, + CountryCode: COUNTRY_CODE_BE, + } + RegionLondon = cloudprovider.SGeographicInfo{ + Latitude: 51.507351, + Longitude: -0.127758, + City: CITY_LONDON, + CountryCode: COUNTRY_CODE_GB, + } + RegionHalton = cloudprovider.SGeographicInfo{ + Latitude: 53.3331, + Longitude: -2.6957, + City: CITY_HALTON, + CountryCode: COUNTRY_CODE_GB, + } + RegionSussex = cloudprovider.SGeographicInfo{ + Latitude: 51, + Longitude: 0, + City: CITY_WEST_SUSSEX, + CountryCode: COUNTRY_CODE_GB, + } + RegionFrankfurt = cloudprovider.SGeographicInfo{ + Latitude: 51.165691, + Longitude: 10.451526, + City: CITY_FRANKFURT, + CountryCode: COUNTRY_CODE_DE, + } + RegionHolland = cloudprovider.SGeographicInfo{ + Latitude: 52.2076831, + Longitude: 4.1585786, + City: CITY_HOLLAND, + CountryCode: COUNTRY_CODE_NL, + } + RegionZurich = cloudprovider.SGeographicInfo{ + Latitude: 47.3774497, + Longitude: 8.5016958, + City: CITY_ZURICH, + CountryCode: COUNTRY_CODE_CH, + } + RegionWarsaw = cloudprovider.SGeographicInfo{ + Latitude: 52.233333, + Longitude: 21.016667, + City: CITY_WARSAW, + CountryCode: COUNTRY_CODE_PL, + } + RegionIreland = cloudprovider.SGeographicInfo{ + Latitude: 53.41291, + Longitude: -8.24389, + City: CITY_IRELAND, + CountryCode: COUNTRY_CODE_IE, + } + RegionDublin = cloudprovider.SGeographicInfo{ + Latitude: 53.349722, + Longitude: -6.260278, + City: CITY_DUBLIN, + CountryCode: COUNTRY_CODE_IE, + } + RegionParis = cloudprovider.SGeographicInfo{ + Latitude: 48.856614, + Longitude: 2.3522219, + City: CITY_PARIS, + CountryCode: COUNTRY_CODE_FR, + } + RegionAllier = cloudprovider.SGeographicInfo{ + Latitude: 46.5178, + Longitude: 3.3592, + City: CITY_ALLIER, + CountryCode: COUNTRY_CODE_FR, + } + RegionTarn = cloudprovider.SGeographicInfo{ + Latitude: 43.8656, + Longitude: 1.505, + City: CITY_TARN, + CountryCode: COUNTRY_CODE_FR, + } + RegionStockholm = cloudprovider.SGeographicInfo{ + Latitude: 59.1946, + Longitude: 18.47, + City: CITY_STOCKHOLM, + CountryCode: COUNTRY_CODE_SE, + } + RegionDelmenhorst = cloudprovider.SGeographicInfo{ + Latitude: 53.050556, + Longitude: 8.631667, + City: CITY_DELMENHORST, + CountryCode: COUNTRY_CODE_DE, + } + RegionGeneva = cloudprovider.SGeographicInfo{ + Latitude: 46.201667, + Longitude: 6.146944, + City: CITY_GENEVA, + CountryCode: COUNTRY_CODE_CH, + } + RegionStavanger = cloudprovider.SGeographicInfo{ + Latitude: 58.963333, + Longitude: 5.718889, + City: CITY_STAVANGER, + CountryCode: COUNTRY_CODE_NO, + } + RegionOslo = cloudprovider.SGeographicInfo{ + Latitude: 59.905556, + Longitude: 10.768333, + City: CITY_OSLO, + CountryCode: COUNTRY_CODE_NO, + } + + RegionMoscow = cloudprovider.SGeographicInfo{ + Latitude: 55.755825, + Longitude: 37.617298, + City: CITY_MOSCOW, + CountryCode: COUNTRY_CODE_RU, + } + + // America + RegionMontreal = cloudprovider.SGeographicInfo{ + Latitude: 45.5580206, + Longitude: -73.8003414, + City: CITY_MONTREAL, + CountryCode: COUNTRY_CODE_CA, + } + RegionToronto = cloudprovider.SGeographicInfo{ + Latitude: 43.653225, + Longitude: -79.383186, + City: CITY_TORONTO, + CountryCode: COUNTRY_CODE_CA, + } + RegionCanadaCentral = cloudprovider.SGeographicInfo{ + Latitude: 56.130366, + Longitude: -106.346771, + City: CITY_CANADA_CENTRAL, + CountryCode: COUNTRY_CODE_CA, + } + RegionQuebec = cloudprovider.SGeographicInfo{ + Latitude: 52, + Longitude: -72, + City: CITY_QUEBEC, + CountryCode: COUNTRY_CODE_CA, + } + + RegionSaoPaulo = cloudprovider.SGeographicInfo{ + Latitude: -23.5505199, + Longitude: -46.6333094, + City: CITY_SAO_PAULO, + CountryCode: COUNTRY_CODE_BR, + } + // 里约热内卢 + RegionRioDeJaneiro = cloudprovider.SGeographicInfo{ + Latitude: -22.9083, + Longitude: -43.1964, + City: CITY_RIO_DE_JANEIRO, + CountryCode: COUNTRY_CODE_BR, + } + + RegionMexico = cloudprovider.SGeographicInfo{ + Latitude: 55.1182908, + Longitude: 141.0377645, + City: CITY_MEXICO, + CountryCode: COUNTRY_CODE_MX, + } + + RegionSantiago = cloudprovider.SGeographicInfo{ + Latitude: -33.45206, + Longitude: -70.676031, + City: CITY_SANTIAGO, + CountryCode: COUNTRY_CODE_CL, + } + + RegionIowa = cloudprovider.SGeographicInfo{ + Latitude: 41.9328655, + Longitude: -94.5106809, + City: CITY_IOWA, + CountryCode: COUNTRY_CODE_US, + } + RegionCarolina = cloudprovider.SGeographicInfo{ + Latitude: 33.6194409, + Longitude: -82.0475635, + City: CITY_SOUTH_CAROLINA, + CountryCode: COUNTRY_CODE_US, + } + // 西雅图,华盛顿州 + RegionWashington = cloudprovider.SGeographicInfo{ + Latitude: 47.6, + Longitude: -122.3, + City: CITY_WASHINGTON, + CountryCode: COUNTRY_CODE_US, + } + RegionVirginia = cloudprovider.SGeographicInfo{ + Latitude: 37.4315734, + Longitude: -78.6568942, + City: CITY_VIRGINIA, + CountryCode: COUNTRY_CODE_US, + } + RegionTexas = cloudprovider.SGeographicInfo{ + Latitude: 31, + Longitude: -100, + City: CITY_TEXAS, + CountryCode: COUNTRY_CODE_US, + } + RegionChicago = cloudprovider.SGeographicInfo{ + Latitude: 41.8819, + Longitude: -87.6278, + City: CITY_CHICAGO, + CountryCode: COUNTRY_CODE_US, + } + RegionPhoenix = cloudprovider.SGeographicInfo{ + Latitude: 33.4483, + Longitude: -112.0739, + City: CITY_PHOENIX, + CountryCode: COUNTRY_CODE_US, + } + RegionUtah = cloudprovider.SGeographicInfo{ + Latitude: 39.5, + Longitude: -111.5, + City: CITY_UTAH, + CountryCode: COUNTRY_CODE_US, + } + RegionSanFrancisco = cloudprovider.SGeographicInfo{ + Latitude: 37.7775, + Longitude: -122.4164, + City: CITY_SAN_FRANCISCO, + CountryCode: COUNTRY_CODE_US, + } + RegionSiliconValley = cloudprovider.SGeographicInfo{ + Latitude: 37.387474, + Longitude: -122.057541, + City: CITY_SILICONVALLEY, + CountryCode: COUNTRY_CODE_US, + } + RegionNothVirginia = cloudprovider.SGeographicInfo{ + Latitude: 37.4315734, + Longitude: -78.6568942, + City: CITY_N_VIRGINIA, + CountryCode: COUNTRY_CODE_US, + } + RegionOregon = cloudprovider.SGeographicInfo{ + Latitude: 43.8041334, + Longitude: -120.5542012, + City: CITY_OREGON, + CountryCode: COUNTRY_CODE_US, + } + RegionLosAngeles = cloudprovider.SGeographicInfo{ + Latitude: 34.0522342, + Longitude: -118.2436849, + City: CITY_LOS_ANGELES, + CountryCode: COUNTRY_CODE_US, + } + RegionSaltLakeCity = cloudprovider.SGeographicInfo{ + Latitude: 40.7767168, + Longitude: -111.9905243, + City: CITY_SALT_LAKE_CITY, + CountryCode: COUNTRY_CODE_US, + } + RegionLasVegas = cloudprovider.SGeographicInfo{ + Latitude: 36.1249185, + Longitude: -115.3150811, + City: CITY_LAS_VEGAS, + CountryCode: COUNTRY_CODE_US, + } + RegionNorthCalifornia = cloudprovider.SGeographicInfo{ + Latitude: 38.8375215, + Longitude: -120.8958242, + City: CITY_N_CALIFORNIA, + CountryCode: COUNTRY_CODE_US, + } + RegionOhio = cloudprovider.SGeographicInfo{ + Latitude: 40.4172871, + Longitude: -82.90712300000001, + City: CITY_OHIO, + CountryCode: COUNTRY_CODE_US, + } + + RegionUSGOVWest = cloudprovider.SGeographicInfo{ + Latitude: 37.09024, + Longitude: -95.712891, + City: CITY_US_GOV_WEST, + CountryCode: COUNTRY_CODE_US, + } + RegionJioIndiaWest = cloudprovider.SGeographicInfo{ + Latitude: 22.4707, + Longitude: 70.0577, + City: CITY_JAMNAGAR, + CountryCode: COUNTRY_CODE_IN, + } + RegionJioIndiaCentral = cloudprovider.SGeographicInfo{ + Latitude: 21.1466, + Longitude: 79.0889, + City: CITY_NAGPUR, + CountryCode: COUNTRY_CODE_IN, + } +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/routetable.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/routetable.go new file mode 100644 index 0000000000..7d79920506 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/routetable.go @@ -0,0 +1,22 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + ROUTE_TABLE_UPDATING = "updating" + ROUTE_TABLE_UPDATEFAILED = "update_falied" + ROUTE_TABLE_AVAILABLE = "available" + ROUTE_TABLE_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/routetable_routesets.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/routetable_routesets.go new file mode 100644 index 0000000000..13419ab4a4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/routetable_routesets.go @@ -0,0 +1,48 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + ROUTE_ENTRY_TYPE_CUSTOM = "Custom" // 自定义路由 + ROUTE_ENTRY_TYPE_SYSTEM = "System" // 系统路由 + ROUTE_ENTRY_TYPE_PROPAGATE = "Propagate" +) + +const ( + NEXT_HOP_TYPE_INSTANCE = "Instance" // ECS实例。 + NEXT_HOP_TYPE_HAVIP = "HaVip" // 高可用虚拟IP。 + NEXT_HOP_TYPE_VPN = "VpnGateway" // VPN网关。 + NEXT_HOP_TYPE_NAT = "NatGateway" // NAT网关。 + NEXT_HOP_TYPE_NETWORK = "NetworkInterface" // 辅助弹性网卡。 + NEXT_HOP_TYPE_EIP = "Eip" // 弹性IP + NEXT_HOP_TYPE_ROUTER = "RouterInterface" // 路由器接口。 + NEXT_HOP_TYPE_IPV6 = "IPv6Gateway" // IPv6网关。 + NEXT_HOP_TYPE_INTERNET = "InternetGateway" // Internet网关。 + NEXT_HOP_TYPE_EGRESS_INTERNET = "EgressInternetGateway" // egress only Internet网关。 + NEXT_HOP_TYPE_VPCPEERING = "VpcPeering" // vpc对等连接 + NEXT_HOP_TYPE_INTERVPCNETWORK = "InterVpcNetwork" //vpc 互联网络 + NEXT_HOP_TYPE_DIRECTCONNECTION = "DirectConnection" //专线 + NEXT_HOP_TYPE_VPC = "VPC" + NEXT_HOP_TYPE_VBR = "VBR" // 边界路由器 + + NEXT_HOP_TYPE_IP = "IP" +) + +const ( + ROUTE_ENTRY_STATUS_AVAILIABLE = "available" + ROUTE_ENTRY_STATUS_CONFLICT = "conflict" + ROUTE_ENTRY_STATUS_DISABLED = "disabled" + ROUTE_ENTRY_STATUS_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/secgroup_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/secgroup_const.go new file mode 100644 index 0000000000..0e6cff51db --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/secgroup_const.go @@ -0,0 +1,23 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + SECGROUP_STATUS_READY = "ready" + SECGROUP_STATUS_DELETING = "deleting" // 删除中 + SECGROUP_STATUS_SYNC_RULES = "sync_rules" // 同步规则中 + + SECGROUP_DEFAULT_ID = "default" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/sku_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/sku_const.go new file mode 100644 index 0000000000..76c468478d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/sku_const.go @@ -0,0 +1,59 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + SkuCategoryGeneralPurpose = "general_purpose" // 通用型 + SkuCategoryBurstable = "burstable" // 突发性能型 + SkuCategoryComputeOptimized = "compute_optimized" // 计算优化型 + SkuCategoryMemoryOptimized = "memory_optimized" // 内存优化型 + SkuCategoryStorageIOOptimized = "storage_optimized" // 存储IO优化型 + SkuCategoryHardwareAccelerated = "hardware_accelerated" // 硬件加速型 + SkuCategoryHighStorage = "high_storage" // 高存储型 + SkuCategoryHighMemory = "high_memory" // 高内存型 +) + +const ( + SkuStatusAvailable = "available" + SkuStatusSoldout = "soldout" + SkuStatusCreating = "creating" + SkuStatusCreatFailed = "create_failed" + SkuStatusDeleting = "deleting" + SkuStatusDeleteFailed = "delete_failed" + SkuStatusUnknown = "unknown" + SkuStatusReady = "ready" +) + +var InstanceFamilies = map[string]string{ + SkuCategoryGeneralPurpose: "g1", + SkuCategoryBurstable: "t1", + SkuCategoryComputeOptimized: "c1", + SkuCategoryMemoryOptimized: "r1", + SkuCategoryStorageIOOptimized: "i1", + SkuCategoryHardwareAccelerated: "", + SkuCategoryHighStorage: "hc1", + SkuCategoryHighMemory: "hr1", +} + +var SKU_FAMILIES = []string{ + SkuCategoryGeneralPurpose, + SkuCategoryBurstable, + SkuCategoryComputeOptimized, + SkuCategoryMemoryOptimized, + SkuCategoryStorageIOOptimized, + SkuCategoryHardwareAccelerated, + SkuCategoryHighStorage, + SkuCategoryHighMemory, +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/snapshot_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/snapshot_const.go new file mode 100644 index 0000000000..b60f1daf3c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/snapshot_const.go @@ -0,0 +1,61 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + // create by + SNAPSHOT_MANUAL = "manual" + SNAPSHOT_AUTO = "auto" + + SNAPSHOT_CREATING = "creating" + SNAPSHOT_ROLLBACKING = "rollbacking" + SNAPSHOT_FAILED = "create_failed" + SNAPSHOT_READY = "ready" + SNAPSHOT_DELETE_FAILED = "delete_failed" + SNAPSHOT_DELETING = "deleting" + SNAPSHOT_UNKNOWN = "unknown" + + SNAPSHOT_POLICY_CREATING = "creating" + + SNAPSHOT_POLICY_READY = "ready" + SNAPSHOT_POLICY_UPDATING = "updating" + SNAPSHOT_POLICY_UNKNOWN = "unknown" + SNAPSHOT_POLICY_DELETING = "deleting" + SNAPSHOT_POLICY_DELETE_FAILED = "delete_failed" + + SNAPSHOT_POLICY_APPLY = "applying" + SNAPSHOT_POLICY_APPLY_FAILED = "apply_failed" + SNAPSHOT_POLICY_CANCEL = "canceling" + SNAPSHOT_POLICY_CANCEL_FAILED = "cancel_failed" + + SNAPSHOT_POLICY_DISK_INIT = "init" + SNAPSHOT_POLICY_DISK_READY = "ready" + SNAPSHOT_POLICY_DISK_DELETING = "deleting" + SNAPSHOT_POLICY_DISK_DELETE_FAILED = "delete_failed" + + INSTANCE_SNAPSHOT_READY = "ready" + INSTANCE_SNAPSHOT_UNKNOWN = "unknown" + INSTANCE_SNAPSHOT_FAILED = "instance_snapshot_create_failed" + INSTANCE_SNAPSHOT_START_DELETE = "instance_snapshot_start_delete" + INSTANCE_SNAPSHOT_DELETE_FAILED = "instance_snapshot_delete_failed" + INSTANCE_SNAPSHOT_RESET = "instance_snapshot_reset" + + SNAPSHOT_POLICY_CACHE_STATUS_READY = "ready" + SNAPSHOT_POLICY_CACHE_STATUS_DELETING = "deleting" + SNAPSHOT_POLICY_CACHE_STATUS_DELETE_FAILED = "delete_failed" + + SNAPSHOT_EXIST = "exist" + SNAPSHOT_NOT_EXIST = "not_exist" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/storage_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/storage_const.go new file mode 100644 index 0000000000..72db90af6d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/storage_const.go @@ -0,0 +1,162 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + STORAGE_LOCAL = "local" + STORAGE_BAREMETAL = "baremetal" + STORAGE_SHEEPDOG = "sheepdog" + STORAGE_RBD = "rbd" + STORAGE_DOCKER = "docker" + STORAGE_NAS = "nas" + STORAGE_VSAN = "vsan" + STORAGE_NFS = "nfs" + STORAGE_GPFS = "gpfs" + STORAGE_CIFS = "cifs" + + STORAGE_PUBLIC_CLOUD = "cloud" + STORAGE_CLOUD_EFFICIENCY = "cloud_efficiency" + STORAGE_CLOUD_SSD = "cloud_ssd" + STORAGE_CLOUD_ESSD = "cloud_essd" // 增强型(Enhanced)SSD 云盘, 单盘最高随机读写IOPS 5万 + STORAGE_CLOUD_ESSD_PL2 = "cloud_essd_pl2" // 单盘最高随机读写IOPS 10万 + STORAGE_CLOUD_ESSD_PL3 = "cloud_essd_pl3" // 单盘最高随机读写IOPS 100万 + STORAGE_EPHEMERAL_SSD = "ephemeral_ssd" // 单块本地SSD盘, 容量最大不能超过800 GiB + STORAGE_LOCAL_HDD_PRO = "local_hdd_pro" // 实例规格族d1ne和d1搭载的SATA HDD本地盘 + STORAGE_LOCAL_SSD_PRO = "local_ssd_pro" // 实例规格族i2、i2g、i1、ga1和gn5等搭载的NVMe + + //Azure hdd and ssd storagetype + STORAGE_STANDARD_LRS = "standard_lrs" + STORAGE_STANDARDSSD_LRS = "standardssd_lrs" + STORAGE_PREMIUM_LRS = "premium_lrs" + STORAGE_AZURE_BASIC = "basic_storage" + STORAGE_AZURE_GENERAL_PURPOSE = "general_purpose_storage" + + // aws storage type + STORAGE_GP2_SSD = "gp2" // aws general purpose ssd + STORAGE_GP3_SSD = "gp3" // aws General Purpose SSD (gp3) + STORAGE_IO1_SSD = "io1" // aws Provisioned IOPS SSD + STORAGE_IO2_SSD = "io2" // aws Provisioned IOPS 2 SSD + STORAGE_ST1_HDD = "st1" // aws Throughput Optimized HDD + STORAGE_SC1_HDD = "sc1" // aws Cold HDD + STORAGE_STANDARD_HDD = "standard" // aws Magnetic volumes + + // qcloud storage type + // STORAGE_CLOUD_SSD ="cloud_ssd" + STORAGE_LOCAL_BASIC = "local_basic" + STORAGE_LOCAL_SSD = "local_ssd" + STORAGE_LOCAL_PRO = "local_pro" + STORAGE_CLOUD_BASIC = "cloud_basic" + STORAGE_CLOUD_PREMIUM = "cloud_premium" //高性能云硬盘 + STORAGE_CLOUD_HSSD = "cloud_hssd" //增强型SSD云硬盘 + + // huawei storage type + STORAGE_HUAWEI_SSD = "SSD" // 超高IO云硬盘 + STORAGE_HUAWEI_SAS = "SAS" // 高IO云硬盘 + STORAGE_HUAWEI_SATA = "SATA" // 普通IO云硬盘 + STORAGE_HUAWEI_GPSSD = "GPSSD" // 通用型SSD + STORAGE_HUAWEI_ESSD = "ESSD" // 急速型SSD + + // openstack + STORAGE_OPENSTACK_ISCSI = "iscsi" + STORAGE_OPENSTACK_NOVA = "nova" + + // Ucloud storage type + STORAGE_UCLOUD_CLOUD_NORMAL = "CLOUD_NORMAL" // 普通云盘 + STORAGE_UCLOUD_CLOUD_SSD = "CLOUD_SSD" // SSD云盘 + STORAGE_UCLOUD_LOCAL_NORMAL = "LOCAL_NORMAL" // 普通本地盘 + STORAGE_UCLOUD_LOCAL_SSD = "LOCAL_SSD" // SSD本地盘 + STORAGE_UCLOUD_EXCLUSIVE_LOCAL_DISK = "EXCLUSIVE_LOCAL_DISK" // 独享本地盘 + + // Zstack storage type + STORAGE_ZSTACK_LOCAL_STORAGE = "localstorage" + STORAGE_ZSTACK_CEPH = "ceph" + + // Google storage type + STORAGE_GOOGLE_LOCAL_SSD = "local-ssd" //本地SSD暂存盘 (最多8个) + STORAGE_GOOGLE_PD_STANDARD = "pd-standard" //标准永久性磁盘 + STORAGE_GOOGLE_PD_SSD = "pd-ssd" //SSD永久性磁盘 + STORAGE_GOOGLE_PD_BALANCED = "pd-balanced" //平衡永久性磁盘 + + // ctyun storage type + STORAGE_CTYUN_SSD = "SSD" // 超高IO云硬盘 + STORAGE_CTYUN_SAS = "SAS" // 高IO云硬盘 + STORAGE_CTYUN_SATA = "SATA" // 普通IO云硬盘 + + // jd cloud storage type + STORAGE_JDCLOUD_GP1 = "ssd.gp1" // 通用型SSD云硬盘 + STORAGE_JDCLOUD_IO1 = "ssd.io1" // 性能型SSD云硬盘 + STORAGE_JDCLOUD_STD = "hdd.std1" // 容量型HDD云硬盘 + STORAGE_JDCLOUD_SSD = "ssd" // SSD云硬盘 + STORAGE_JDCLOUD_PHD = "premium-hdd" // HDD云硬盘 + + STORAGE_ECLOUD_CAPEBS = "capebs" // 容量盘 + STORAGE_ECLOUD_EBS = "ebs" // 性能盘 + STORAGE_ECLOUD_SSD = "ssd" // 高性能盘 + STORAGE_ECLOUD_SSDEBS = "ssdebs" // 性能优化盘 + STORAGE_ECLOUD_SYSTEM = "system" // 系统盘 +) + +const ( + STORAGE_ENABLED = "enabled" + // STORAGE_DISABLED = "disabled" + STORAGE_OFFLINE = "offline" // 离线 + STORAGE_ONLINE = "online" // 在线 + STORAGE_UNMOUNT = "unmount" // 待挂载 + + DISK_TYPE_ROTATE = "rotate" + DISK_TYPE_SSD = "ssd" + DISK_TYPE_HYBRID = "hybrid" +) + +const ( + RBD_DEFAULT_MON_TIMEOUT = 5 //5 seconds 连接超时时间 + RBD_DEFAULT_OSD_TIMEOUT = 20 * 60 //20 minute 操作超时时间 + RBD_DEFAULT_MOUNT_TIMEOUT = 2 * 60 //CephFS挂载超时时间, 目前未使用 +) + +var ( + DISK_TYPES = []string{DISK_TYPE_ROTATE, DISK_TYPE_SSD, DISK_TYPE_HYBRID} + STORAGE_LOCAL_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_UCLOUD_LOCAL_NORMAL, STORAGE_UCLOUD_LOCAL_SSD, STORAGE_UCLOUD_EXCLUSIVE_LOCAL_DISK, + STORAGE_EPHEMERAL_SSD, STORAGE_LOCAL_BASIC, STORAGE_LOCAL_SSD, STORAGE_LOCAL_PRO, STORAGE_OPENSTACK_NOVA, + STORAGE_ZSTACK_LOCAL_STORAGE, STORAGE_GOOGLE_LOCAL_SSD} + STORAGE_SUPPORT_TYPES = STORAGE_LOCAL_TYPES + STORAGE_ALL_TYPES = []string{ + STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_SHEEPDOG, + STORAGE_RBD, STORAGE_DOCKER, STORAGE_NAS, STORAGE_VSAN, + STORAGE_NFS, STORAGE_GPFS, STORAGE_CIFS, + } + STORAGE_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_SHEEPDOG, + STORAGE_RBD, STORAGE_DOCKER, STORAGE_NAS, STORAGE_VSAN, STORAGE_NFS, + STORAGE_PUBLIC_CLOUD, STORAGE_CLOUD_SSD, STORAGE_CLOUD_ESSD, STORAGE_CLOUD_ESSD_PL2, STORAGE_CLOUD_ESSD_PL3, + STORAGE_EPHEMERAL_SSD, STORAGE_CLOUD_EFFICIENCY, + STORAGE_STANDARD_LRS, STORAGE_STANDARDSSD_LRS, STORAGE_PREMIUM_LRS, + STORAGE_GP2_SSD, STORAGE_GP3_SSD, STORAGE_IO1_SSD, STORAGE_ST1_HDD, STORAGE_SC1_HDD, STORAGE_STANDARD_HDD, + STORAGE_LOCAL_BASIC, STORAGE_LOCAL_SSD, STORAGE_CLOUD_BASIC, STORAGE_CLOUD_PREMIUM, + STORAGE_HUAWEI_SSD, STORAGE_HUAWEI_SAS, STORAGE_HUAWEI_SATA, + STORAGE_OPENSTACK_ISCSI, STORAGE_UCLOUD_CLOUD_NORMAL, STORAGE_UCLOUD_CLOUD_SSD, + STORAGE_UCLOUD_LOCAL_NORMAL, STORAGE_UCLOUD_LOCAL_SSD, STORAGE_UCLOUD_EXCLUSIVE_LOCAL_DISK, + STORAGE_ZSTACK_LOCAL_STORAGE, STORAGE_ZSTACK_CEPH, STORAGE_GPFS, STORAGE_CIFS, + } + + HOST_STORAGE_LOCAL_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_ZSTACK_LOCAL_STORAGE, STORAGE_OPENSTACK_NOVA} + + STORAGE_LIMITED_TYPES = []string{STORAGE_LOCAL, STORAGE_BAREMETAL, STORAGE_NAS, STORAGE_RBD, STORAGE_NFS, STORAGE_GPFS, STORAGE_VSAN, STORAGE_CIFS} + + SHARED_FILE_STORAGE = []string{STORAGE_NFS, STORAGE_GPFS} + FIEL_STORAGE = []string{STORAGE_LOCAL, STORAGE_NFS, STORAGE_GPFS} + + // 目前来说只支持这些 + SHARED_STORAGE = []string{STORAGE_NFS, STORAGE_GPFS, STORAGE_RBD} +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/tablestores.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/tablestores.go new file mode 100644 index 0000000000..deb0ca6798 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/tablestores.go @@ -0,0 +1,20 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + TABLESTORE_STATUS_RUNNING = "running" + TABLESTORE_STATUS_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpc_peering_connection.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpc_peering_connection.go new file mode 100644 index 0000000000..0d70703967 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpc_peering_connection.go @@ -0,0 +1,25 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + VPC_PEERING_CONNECTION_STATUS_CREATING = "creating" + VPC_PEERING_CONNECTION_STATUS_CREATE_FAILED = "create_failed" + VPC_PEERING_CONNECTION_STATUS_DELETE_FAILED = "delete_failed" + VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT = "pending-acceptance" + VPC_PEERING_CONNECTION_STATUS_ACTIVE = "active" + VPC_PEERING_CONNECTION_STATUS_DELETING = "deleting" + VPC_PEERING_CONNECTION_STATUS_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpcs_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpcs_const.go new file mode 100644 index 0000000000..ebe7a6e84a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpcs_const.go @@ -0,0 +1,38 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + VPC_STATUS_PENDING = "pending" + VPC_STATUS_AVAILABLE = "available" + VPC_STATUS_UNAVAILABLE = "unavailable" + VPC_STATUS_FAILED = "failed" + VPC_STATUS_START_DELETE = "start_delete" + VPC_STATUS_DELETING = "deleting" + VPC_STATUS_DELETE_FAILED = "delete_failed" + VPC_STATUS_DELETED = "deleted" + VPC_STATUS_UNKNOWN = "unknown" + + MAX_VPC_PER_REGION = 3 + + DEFAULT_VPC_ID = "default" + NORMAL_VPC_ID = "normal" // 没有关联VPC的安全组,统一使用normal + + CLASSIC_VPC_NAME = "-" +) + +const ( + VPC_PROVIDER_OVN = "ovn" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpcs_ovn.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpcs_ovn.go new file mode 100644 index 0000000000..635f88c301 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/vpcs_ovn.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 compute + +// IP: 20 +// UDP: 8 +// GENEVE HDR: 8 + 4x +// total: 36 + 4x +const VPC_OVN_ENCAP_COST = 60 + +const ( + VPC_EXTERNAL_ACCESS_MODE_DISTGW = "distgw" // distgw only + VPC_EXTERNAL_ACCESS_MODE_EIP_DISTGW = "eip-distgw" // eip when available, distgw otherwise + VPC_EXTERNAL_ACCESS_MODE_EIP = "eip" // eip only + VPC_EXTERNAL_ACCESS_MODE_NONE = "none" // no external access +) + +var ( + VPC_EXTERNAL_ACCESS_MODES = []string{ + VPC_EXTERNAL_ACCESS_MODE_DISTGW, + VPC_EXTERNAL_ACCESS_MODE_EIP_DISTGW, + VPC_EXTERNAL_ACCESS_MODE_EIP, + VPC_EXTERNAL_ACCESS_MODE_NONE, + } +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/waf_instance.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/waf_instance.go new file mode 100644 index 0000000000..16d2b60063 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/waf_instance.go @@ -0,0 +1,30 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + WAF_ACTION_ALLOW = "Allow" + WAF_ACTION_BLOCK = "Block" + WAF_ACTION_PREVENTION = "Prevention" + WAF_ACTION_DETECTION = "Detection" + + WAF_STATUS_AVAILABLE = "available" + WAF_STATUS_DELETING = "deleting" + WAF_STATUS_DELETE_FAILED = "delete_failed" + WAF_STATUS_CREATING = "creating" + WAF_STATUS_CREATE_FAILED = "create_failed" + WAF_STATUS_UPDATING = "updating" + WAF_STATUS_UNKNOWN = "unknown" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/wire_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/wire_const.go new file mode 100644 index 0000000000..828a3bfd16 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/wire_const.go @@ -0,0 +1,22 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + WIRE_STATUS_AVAILABLE = "available" + WIRE_STATUS_READY_DEPRECATED = "ready" + WIRE_STATUS_MERGE_NETWORK = "merge_network" + WIRE_STATUS_MERGE_NETWORK_FAILED = "merge_network_failed" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/compute/zones_const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/zones_const.go new file mode 100644 index 0000000000..2472aa2d29 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/compute/zones_const.go @@ -0,0 +1,23 @@ +// Copyright 2019 Yunion +// +// 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 compute + +const ( + ZONE_INIT = "init" + ZONE_ENABLE = "enable" + ZONE_DISABLE = "disable" + ZONE_SOLDOUT = "soldout" + // ZONE_LACK = "lack" +) diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/const.go b/vendor/yunion.io/x/cloudmux/pkg/apis/const.go new file mode 100644 index 0000000000..d1315dffcf --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/const.go @@ -0,0 +1,102 @@ +// Copyright 2019 Yunion +// +// 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 apis + +import "yunion.io/x/pkg/utils" + +const ( + SERVICE_TYPE_IMAGE = "image" + SERVICE_TYPE_OFFLINE_CLOUDMETA = "offlinecloudmeta" + SERVICE_TYPE_CLOUDID = "cloudid" + SERVICE_TYPE_CLOUDEVENT = "cloudevent" + SERVICE_TYPE_DEVTOOL = "devtool" + SERVICE_TYPE_ANSIBLE = "ansible" + SERVICE_TYPE_CLOUDMETA = "cloudmeta" + SERVICE_TYPE_YUNIONCONF = "yunionconf" + SERVICE_TYPE_METER = "meter" + SERVICE_TYPE_SCHEDULER = "scheduler" + SERVICE_TYPE_VNCPROXY = "vncproxy" + SERVICE_TYPE_KEYSTONE = "identity" + SERVICE_TYPE_NOTIFY = "notify" + SERVICE_TYPE_MONITOR = "monitor" + SERVICE_TYPE_LOG = "log" + SERVICE_TYPE_REGION = "compute" + SERVICE_TYPE_CLOUDMON = "cloudmon" + + SERVICE_TYPE_ETCD = "etcd" + SERVICE_TYPE_INFLUXDB = "influxdb" + + SERVICE_TYPE_SCHEDULEDTASK = "scheduledtask" + + STATUS_UPDATE_TAGS = "update_tags" + STATUS_UPDATE_TAGS_FAILED = "update_tags_fail" + + STATUS_SYNC_STATUS = "sync_status" + STATUS_DELETING = "deleting" + STATUS_DELETE_FAILED = "delete_failed" + STATUS_UNKNOWN = "unknown" + STATUS_CREATING = "creating" + STATUS_CREATE_FAILED = "create_failed" + + CLOUD_TAG_PREFIX = "ext:" + USER_TAG_PREFIX = "user:" + SYS_CLOUD_TAG_PREFIX = "sys:" + // Such tags have inherited and isolated properties + CLASS_TAT_PREFIX = "cls:" + + SKU_STATUS_AVAILABLE = "available" + SKU_STATUS_SOLDOUT = "soldout" +) + +var ( + NO_RESOURCE_SERVICES = []string{ + SERVICE_TYPE_OFFLINE_CLOUDMETA, + SERVICE_TYPE_CLOUDMETA, + SERVICE_TYPE_SCHEDULER, + SERVICE_TYPE_VNCPROXY, + SERVICE_TYPE_KEYSTONE, + SERVICE_TYPE_ETCD, + SERVICE_TYPE_INFLUXDB, + } +) + +const ( + OS_ARCH_X86 = "x86" + OS_ARCH_ARM = "arm" + + OS_ARCH_I386 = "i386" + OS_ARCH_X86_32 = "x86_32" + OS_ARCH_X86_64 = "x86_64" + OS_ARCH_AARCH32 = "aarch32" + OS_ARCH_AARCH64 = "aarch64" +) + +var ( + ARCH_X86 = []string{ + OS_ARCH_X86, + OS_ARCH_I386, + OS_ARCH_X86_32, + OS_ARCH_X86_64, + } + ARCH_ARM = []string{ + OS_ARCH_ARM, + OS_ARCH_AARCH32, + OS_ARCH_AARCH64, + } +) + +func IsARM(osArch string) bool { + return utils.IsInStringArray(osArch, ARCH_ARM) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/metadata.go b/vendor/yunion.io/x/cloudmux/pkg/apis/metadata.go new file mode 100644 index 0000000000..ede9495ceb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/metadata.go @@ -0,0 +1,20 @@ +// Copyright 2019 Yunion +// +// 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 apis + +const ( + IS_SYSTEM = "IsSystem" +) + diff --git a/vendor/yunion.io/x/cloudmux/pkg/apis/share.go b/vendor/yunion.io/x/cloudmux/pkg/apis/share.go new file mode 100644 index 0000000000..febc73228f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/apis/share.go @@ -0,0 +1,22 @@ +// Copyright 2019 Yunion +// +// 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 apis + +const ( + CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN = "account_domain" + CLOUD_ACCOUNT_SHARE_MODE_SYSTEM = "system" + CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN = "provider_domain" +) + diff --git a/pkg/cloudprovider/access_group.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/access_group.go similarity index 100% rename from pkg/cloudprovider/access_group.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/access_group.go diff --git a/pkg/cloudprovider/cdn.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/cdn.go similarity index 100% rename from pkg/cloudprovider/cdn.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/cdn.go diff --git a/pkg/cloudprovider/cloudprovider.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/cloudprovider.go similarity index 99% rename from pkg/cloudprovider/cloudprovider.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/cloudprovider.go index adc1137374..05f16c96e3 100644 --- a/pkg/cloudprovider/cloudprovider.go +++ b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/cloudprovider.go @@ -174,6 +174,7 @@ type ProviderConfig struct { DefaultRegion string ProxyFunc httputils.TransportProxyFunc + Debug bool UpdatePermission func(service, permission string) } diff --git a/pkg/cloudprovider/cloudrole.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/cloudrole.go similarity index 100% rename from pkg/cloudprovider/cloudrole.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/cloudrole.go diff --git a/pkg/cloudprovider/clouduser.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/clouduser.go similarity index 100% rename from pkg/cloudprovider/clouduser.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/clouduser.go diff --git a/pkg/cloudprovider/consts.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/consts.go similarity index 100% rename from pkg/cloudprovider/consts.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/consts.go diff --git a/pkg/cloudprovider/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/dbinstance.go similarity index 100% rename from pkg/cloudprovider/dbinstance.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/dbinstance.go diff --git a/pkg/cloudprovider/disk.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/disk.go similarity index 100% rename from pkg/cloudprovider/disk.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/disk.go diff --git a/pkg/cloudprovider/dnszone.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/dnszone.go similarity index 100% rename from pkg/cloudprovider/dnszone.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/dnszone.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/doc.go new file mode 100644 index 0000000000..9df97e2416 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 cloudprovider // import "yunion.io/x/cloudmux/pkg/cloudprovider" diff --git a/pkg/cloudprovider/eip.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/eip.go similarity index 100% rename from pkg/cloudprovider/eip.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/eip.go diff --git a/pkg/cloudprovider/elasticcache.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/elasticcache.go similarity index 100% rename from pkg/cloudprovider/elasticcache.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/elasticcache.go diff --git a/pkg/cloudprovider/elasticsearch.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/elasticsearch.go similarity index 100% rename from pkg/cloudprovider/elasticsearch.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/elasticsearch.go diff --git a/pkg/cloudprovider/endpoints.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/endpoints.go similarity index 100% rename from pkg/cloudprovider/endpoints.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/endpoints.go diff --git a/pkg/cloudprovider/extra.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/extra.go similarity index 100% rename from pkg/cloudprovider/extra.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/extra.go diff --git a/pkg/cloudprovider/fakeregion.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/fakeregion.go similarity index 100% rename from pkg/cloudprovider/fakeregion.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/fakeregion.go diff --git a/pkg/cloudprovider/geoinfo.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/geoinfo.go similarity index 100% rename from pkg/cloudprovider/geoinfo.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/geoinfo.go diff --git a/pkg/cloudprovider/globalvpc.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/globalvpc.go similarity index 100% rename from pkg/cloudprovider/globalvpc.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/globalvpc.go diff --git a/pkg/cloudprovider/i18n.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/i18n.go similarity index 100% rename from pkg/cloudprovider/i18n.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/i18n.go diff --git a/pkg/cloudprovider/images.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/images.go similarity index 100% rename from pkg/cloudprovider/images.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/images.go diff --git a/pkg/cloudprovider/instance.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/instance.go similarity index 100% rename from pkg/cloudprovider/instance.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/instance.go diff --git a/pkg/cloudprovider/inter_vpc_network.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/inter_vpc_network.go similarity index 100% rename from pkg/cloudprovider/inter_vpc_network.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/inter_vpc_network.go diff --git a/pkg/cloudprovider/kafka.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/kafka.go similarity index 100% rename from pkg/cloudprovider/kafka.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/kafka.go diff --git a/pkg/cloudprovider/kube_cluster.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/kube_cluster.go similarity index 100% rename from pkg/cloudprovider/kube_cluster.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/kube_cluster.go diff --git a/pkg/cloudprovider/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalancer.go similarity index 100% rename from pkg/cloudprovider/loadbalancer.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalancer.go diff --git a/pkg/cloudprovider/loadbalanceracl.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalanceracl.go similarity index 100% rename from pkg/cloudprovider/loadbalanceracl.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalanceracl.go diff --git a/pkg/cloudprovider/loadbalancerbackend.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalancerbackend.go similarity index 100% rename from pkg/cloudprovider/loadbalancerbackend.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalancerbackend.go diff --git a/pkg/cloudprovider/loadbalancerbackendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalancerbackendgroup.go similarity index 100% rename from pkg/cloudprovider/loadbalancerbackendgroup.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalancerbackendgroup.go diff --git a/pkg/cloudprovider/loadbalancercertificate.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalancercertificate.go similarity index 100% rename from pkg/cloudprovider/loadbalancercertificate.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalancercertificate.go diff --git a/pkg/cloudprovider/loadbalancerlistener.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalancerlistener.go similarity index 100% rename from pkg/cloudprovider/loadbalancerlistener.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/loadbalancerlistener.go diff --git a/pkg/cloudprovider/metrics.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/metrics.go similarity index 100% rename from pkg/cloudprovider/metrics.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/metrics.go diff --git a/pkg/cloudprovider/modelarts_pool.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/modelarts_pool.go similarity index 100% rename from pkg/cloudprovider/modelarts_pool.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/modelarts_pool.go diff --git a/pkg/cloudprovider/mongodb.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/mongodb.go similarity index 100% rename from pkg/cloudprovider/mongodb.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/mongodb.go diff --git a/pkg/cloudprovider/mount_target.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/mount_target.go similarity index 100% rename from pkg/cloudprovider/mount_target.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/mount_target.go diff --git a/pkg/cloudprovider/nas.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/nas.go similarity index 100% rename from pkg/cloudprovider/nas.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/nas.go diff --git a/pkg/cloudprovider/nat.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/nat.go similarity index 100% rename from pkg/cloudprovider/nat.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/nat.go diff --git a/pkg/cloudprovider/network.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/network.go similarity index 100% rename from pkg/cloudprovider/network.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/network.go diff --git a/pkg/cloudprovider/objectstore.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/objectstore.go similarity index 100% rename from pkg/cloudprovider/objectstore.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/objectstore.go diff --git a/pkg/cloudprovider/osinfo.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/osinfo.go similarity index 100% rename from pkg/cloudprovider/osinfo.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/osinfo.go diff --git a/pkg/cloudprovider/resources.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/resources.go similarity index 100% rename from pkg/cloudprovider/resources.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/resources.go diff --git a/pkg/cloudprovider/resourcetags.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/resourcetags.go similarity index 100% rename from pkg/cloudprovider/resourcetags.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/resourcetags.go diff --git a/pkg/cloudprovider/retry.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/retry.go similarity index 100% rename from pkg/cloudprovider/retry.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/retry.go diff --git a/pkg/cloudprovider/route_table.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/route_table.go similarity index 100% rename from pkg/cloudprovider/route_table.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/route_table.go diff --git a/pkg/cloudprovider/saml.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/saml.go similarity index 100% rename from pkg/cloudprovider/saml.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/saml.go diff --git a/pkg/cloudprovider/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/securitygroup.go similarity index 100% rename from pkg/cloudprovider/securitygroup.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/securitygroup.go diff --git a/pkg/cloudprovider/serversku.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/serversku.go similarity index 100% rename from pkg/cloudprovider/serversku.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/serversku.go diff --git a/pkg/cloudprovider/snapshot_policy.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/snapshot_policy.go similarity index 100% rename from pkg/cloudprovider/snapshot_policy.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/snapshot_policy.go diff --git a/pkg/cloudprovider/subaccount.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/subaccount.go similarity index 100% rename from pkg/cloudprovider/subaccount.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/subaccount.go diff --git a/pkg/cloudprovider/subscription.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/subscription.go similarity index 100% rename from pkg/cloudprovider/subscription.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/subscription.go diff --git a/pkg/cloudprovider/transport.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/transport.go similarity index 100% rename from pkg/cloudprovider/transport.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/transport.go diff --git a/pkg/cloudprovider/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/vpc.go similarity index 100% rename from pkg/cloudprovider/vpc.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/vpc.go diff --git a/pkg/cloudprovider/vpc_peering_connection.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/vpc_peering_connection.go similarity index 100% rename from pkg/cloudprovider/vpc_peering_connection.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/vpc_peering_connection.go diff --git a/pkg/cloudprovider/waf.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/waf.go similarity index 100% rename from pkg/cloudprovider/waf.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/waf.go diff --git a/pkg/cloudprovider/waitstatus.go b/vendor/yunion.io/x/cloudmux/pkg/cloudprovider/waitstatus.go similarity index 100% rename from pkg/cloudprovider/waitstatus.go rename to vendor/yunion.io/x/cloudmux/pkg/cloudprovider/waitstatus.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/access_groups.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/access_groups.go new file mode 100644 index 0000000000..d707c30104 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/access_groups.go @@ -0,0 +1,329 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + + alierr "github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SAccessGroup struct { + region *SRegion + + RuleCount int + AccessGroupType string + Description string + AccessGroupName string + MountTargetCount int + FileSystemType string +} + +func (self *SAccessGroup) GetName() string { + return self.AccessGroupName +} + +func (self *SAccessGroup) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.GetFileSystemType(), self.AccessGroupName) +} + +func (self *SAccessGroup) GetFileSystemType() string { + return self.FileSystemType +} + +func (self *SAccessGroup) IsDefault() bool { + return self.AccessGroupName == "DEFAULT_CLASSIC_GROUP_NAME" || self.AccessGroupName == "DEFAULT_VPC_GROUP_NAME" +} + +func (self *SAccessGroup) GetDesc() string { + return self.Description +} + +func (self *SAccessGroup) GetMountTargetCount() int { + return self.MountTargetCount +} + +func (self *SAccessGroup) GetNetworkType() string { + return strings.ToLower(self.AccessGroupType) +} + +func (self *SAccessGroup) GetMaxPriority() int { + return 1 +} + +func (self *SAccessGroup) GetMinPriority() int { + return 100 +} + +func (self *SAccessGroup) Delete() error { + return self.region.DeleteAccessGroup(self.FileSystemType, self.AccessGroupName) +} + +func (self *SAccessGroup) GetSupporedUserAccessTypes() []cloudprovider.TUserAccessType { + return []cloudprovider.TUserAccessType{ + cloudprovider.UserAccessTypeAllSquash, + cloudprovider.UserAccessTypeRootSquash, + cloudprovider.UserAccessTypeNoRootSquash, + } +} + +func (self *SAccessGroup) GetRules() ([]cloudprovider.AccessGroupRule, error) { + rules := []SAccessGroupRule{} + num := 1 + for { + part, total, err := self.region.GetAccessGroupRules(self.AccessGroupName, 50, num) + if err != nil { + return nil, errors.Wrapf(err, "GetAccessGroupRules") + } + rules = append(rules, part...) + if len(rules) >= total { + break + } + } + ret := []cloudprovider.AccessGroupRule{} + for i := range rules { + rule := cloudprovider.AccessGroupRule{ + ExternalId: rules[i].AccessRuleId, + Priority: rules[i].Priority, + Source: rules[i].SourceCidrIp, + } + switch rules[i].RWAccess { + case "RDWR": + rule.RWAccessType = cloudprovider.RWAccessTypeRW + case "RDONLY": + rule.RWAccessType = cloudprovider.RWAccessTypeR + } + switch rules[i].UserAccess { + case "no_squash": + rule.UserAccessType = cloudprovider.UserAccessTypeNoRootSquash + case "root_squash": + rule.UserAccessType = cloudprovider.UserAccessTypeRootSquash + case "all_squash": + rule.UserAccessType = cloudprovider.UserAccessTypeAllSquash + } + ret = append(ret, rule) + } + return ret, nil +} + +func (self *SRegion) getAccessGroups(fsType string, pageSize, pageNum int) ([]SAccessGroup, int, error) { + if pageSize < 1 || pageSize > 100 { + pageSize = 50 + } + if pageNum < 1 { + pageNum = 1 + } + params := map[string]string{ + "RegionId": self.RegionId, + "PageSize": fmt.Sprintf("%d", pageSize), + "PageNumber": fmt.Sprintf("%d", pageNum), + "FileSystemType": fsType, + } + resp, err := self.nasRequest("DescribeAccessGroups", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeAccessGroups") + } + + ret := struct { + TotalCount int + AccessGroups struct { + AccessGroup []SAccessGroup + } + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + return ret.AccessGroups.AccessGroup, ret.TotalCount, nil +} + +type SAccessGroupRule struct { + RWAccess string + UserAccess string + Priority int + SourceCidrIp string + AccessRuleId string +} + +func (self *SRegion) GetAccessGroupRules(groupName string, pageSize, pageNum int) ([]SAccessGroupRule, int, error) { + if pageSize < 1 || pageSize > 100 { + pageSize = 50 + } + if pageNum < 1 { + pageNum = 1 + } + params := map[string]string{ + "RegionId": self.RegionId, + "AccessGroupName": groupName, + "PageSize": fmt.Sprintf("%d", pageSize), + "PageNumber": fmt.Sprintf("%d", pageNum), + } + resp, err := self.nasRequest("DescribeAccessRules", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeAccessRules") + } + ret := struct { + TotalCount int + AccessRules struct { + AccessRule []SAccessGroupRule + } + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + return ret.AccessRules.AccessRule, ret.TotalCount, nil +} + +func (self *SRegion) GetAccessGroups(fsType string) ([]SAccessGroup, error) { + accessGroups := []SAccessGroup{} + num := 1 + for { + part, total, err := self.getAccessGroups(fsType, 50, num) + if err != nil { + if e, ok := errors.Cause(err).(*alierr.ServerError); ok && e.ErrorCode() == "Region.NotSupported" { + return accessGroups, nil + } + return nil, errors.Wrapf(err, "GetAccessGroups") + } + for i := range part { + part[i].FileSystemType = fsType + accessGroups = append(accessGroups, part[i]) + } + if len(accessGroups) >= total { + break + } + } + return accessGroups, nil +} + +func (self *SRegion) GetICloudAccessGroups() ([]cloudprovider.ICloudAccessGroup, error) { + standardAccessGroups, err := self.GetAccessGroups("standard") + if err != nil { + return nil, errors.Wrapf(err, "GetAccessGroups") + } + extremeAccessGroups, err := self.GetAccessGroups("extreme") + if err != nil { + return nil, errors.Wrapf(err, "GetAccessGroups") + } + ret := []cloudprovider.ICloudAccessGroup{} + for _, accessGroups := range [][]SAccessGroup{standardAccessGroups, extremeAccessGroups} { + for i := range accessGroups { + accessGroups[i].region = self + ret = append(ret, &accessGroups[i]) + } + } + return ret, nil +} + +func (self *SRegion) GetICloudAccessGroupById(id string) (cloudprovider.ICloudAccessGroup, error) { + groups, err := self.GetICloudAccessGroups() + if err != nil { + return nil, errors.Wrapf(err, "self.GetICloudAccessGroups") + } + for i := range groups { + if groups[i].GetGlobalId() == id { + return groups[i], nil + } + } + return nil, errors.Wrapf(err, "GetICloudAccessGroupById(%s)", id) +} + +func (self *SRegion) CreateICloudAccessGroup(opts *cloudprovider.SAccessGroup) (cloudprovider.ICloudAccessGroup, error) { + err := self.CreateAccessGroup(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateAccessGroup") + } + return self.GetICloudAccessGroupById(fmt.Sprintf("%s/%s", opts.FileSystemType, opts.Name)) +} + +func (self *SRegion) CreateAccessGroup(opts *cloudprovider.SAccessGroup) error { + params := map[string]string{ + "RegionId": self.RegionId, + "AccessGroupName": opts.Name, + "AccessGroupType": opts.NetworkType, + "FileSystemType": opts.FileSystemType, + } + _, err := self.nasRequest("CreateAccessGroup", params) + return errors.Wrapf(err, "CreateAccessGroup") +} + +func (self *SRegion) DeleteAccessGroup(fsType, name string) error { + params := map[string]string{ + "RegionId": self.RegionId, + "AccessGroupName": name, + "FileSystemType": fsType, + } + _, err := self.nasRequest("DeleteAccessGroup", params) + return errors.Wrapf(err, "DeleteAccessGroup") +} + +func (self *SRegion) DeleteAccessGroupRule(fsType, groupName, ruleId string) error { + params := map[string]string{ + "RegionId": self.RegionId, + "AccessRuleId": ruleId, + "AccessGroupName": groupName, + "FileSystemType": fsType, + } + _, err := self.nasRequest("DeleteAccessRule", params) + return errors.Wrapf(err, "DeleteAccessRule") +} + +func (self *SRegion) CreateAccessGroupRule(source, fsType, groupName string, rwType cloudprovider.TRWAccessType, userType cloudprovider.TUserAccessType, priority int) error { + params := map[string]string{ + "RegionId": self.RegionId, + "SourceCidrIp": source, + "AccessGroupName": groupName, + "Priority": fmt.Sprintf("%d", priority), + "FileSystemType": fsType, + } + switch rwType { + case cloudprovider.RWAccessTypeR: + params["RWAccessType"] = "RDONLY" + case cloudprovider.RWAccessTypeRW: + params["RWAccessType"] = "RDWR" + } + switch userType { + case cloudprovider.UserAccessTypeAllSquash: + params["UserAccessType"] = "all_squash" + case cloudprovider.UserAccessTypeRootSquash: + params["UserAccessType"] = "root_squash" + case cloudprovider.UserAccessTypeNoRootSquash: + params["UserAccessType"] = "no_squash" + } + _, err := self.nasRequest("CreateAccessRule", params) + return errors.Wrapf(err, "CreateAccessRule") +} + +func (self *SAccessGroup) SyncRules(common, added, removed cloudprovider.AccessGroupRuleSet) error { + for _, rule := range removed { + err := self.region.DeleteAccessGroupRule(self.FileSystemType, self.AccessGroupName, rule.ExternalId) + if err != nil { + return errors.Wrapf(err, "DeleteAccessGroupRule") + } + } + for _, rule := range added { + err := self.region.CreateAccessGroupRule(rule.Source, self.FileSystemType, self.AccessGroupName, rule.RWAccessType, rule.UserAccessType, rule.Priority) + if err != nil { + return errors.Wrapf(err, "CreateAccessGroupRule") + } + } + return nil +} diff --git a/pkg/multicloud/aliyun/aliyun.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/aliyun.go similarity index 99% rename from pkg/multicloud/aliyun/aliyun.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/aliyun.go index 4f16242b60..41570bc6b4 100644 --- a/pkg/multicloud/aliyun/aliyun.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/aliyun.go @@ -35,11 +35,12 @@ import ( v "yunion.io/x/pkg/util/version" "yunion.io/x/pkg/utils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/options" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/util/httputils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) const ( diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/bucket.go new file mode 100644 index 0000000000..4df309f4fa --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/bucket.go @@ -0,0 +1,778 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" + + "github.com/aliyun/aliyun-oss-go-sdk/oss" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SBucket struct { + multicloud.SBaseBucket + AliyunTags + + region *SRegion + + Name string + Location string + CreationDate time.Time + StorageClass string +} + +func (b *SBucket) GetProjectId() string { + return "" +} + +func (b *SBucket) GetGlobalId() string { + return b.Name +} + +func (b *SBucket) GetName() string { + return b.Name +} + +func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + osscli, err := b.getOssClient() + if err != nil { + log.Errorf("b.region.GetOssClient fail %s", err) + return acl + } + aclResp, err := osscli.GetBucketACL(b.Name) + if err != nil { + log.Errorf("osscli.GetBucketACL fail %s", err) + return acl + } + acl = cloudprovider.TBucketACLType(aclResp.ACL) + return acl +} + +func (b *SBucket) GetLocation() string { + return b.Location +} + +func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { + return b.region +} + +func (b *SBucket) GetCreatedAt() time.Time { + return b.CreationDate +} + +func (b *SBucket) GetStorageClass() string { + return b.StorageClass +} + +func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { + ret := []cloudprovider.SBucketAccessUrl{ + { + Url: fmt.Sprintf("%s.%s", b.Name, b.region.getOSSExternalDomain()), + Description: "ExtranetEndpoint", + Primary: true, + }, + { + Url: fmt.Sprintf("%s.%s", b.Name, b.region.getOSSInternalDomain()), + Description: "IntranetEndpoint", + }, + } + return ret +} + +func (b *SBucket) GetStats() cloudprovider.SBucketStats { + stats, err := cloudprovider.GetIBucketStats(b) + if err != nil { + log.Errorf("GetStats fail %s", err) + } + return stats +} + +func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error { + osscli, err := b.region.GetOssClient() + if err != nil { + log.Errorf("b.region.GetOssClient fail %s", err) + return errors.Wrap(err, "b.region.GetOssClient") + } + acl, err := str2Acl(string(aclStr)) + if err != nil { + return errors.Wrap(err, "str2Acl") + } + err = osscli.SetBucketACL(b.Name, acl) + if err != nil { + return errors.Wrap(err, "SetBucketACL") + } + return nil +} + +func (b *SBucket) getOssClient() (*oss.Client, error) { + if b.region.client.GetAccessEnv() == ALIYUN_FINANCE_CLOUDENV { + osscli, err := b.region.GetOssClient() + if err != nil { + return nil, errors.Wrapf(err, "GetOssClient") + } + info, err := osscli.GetBucketInfo(b.Name) + if err != nil { + return nil, errors.Wrapf(err, "GetBucketInfo") + } + if len(info.BucketInfo.ExtranetEndpoint) > 0 { + return b.region.client.getOssClientByEndpoint(info.BucketInfo.ExtranetEndpoint) + } + } + return b.region.GetOssClient() +} + +func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { + result := cloudprovider.SListObjectResult{} + osscli, err := b.region.GetOssClient() + if err != nil { + return result, errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return result, errors.Wrap(err, "Bucket") + } + opts := make([]oss.Option, 0) + if len(prefix) > 0 { + opts = append(opts, oss.Prefix(prefix)) + } + if len(delimiter) > 0 { + opts = append(opts, oss.Delimiter(delimiter)) + } + if len(marker) > 0 { + opts = append(opts, oss.Marker(marker)) + } + if maxCount > 0 { + opts = append(opts, oss.MaxKeys(maxCount)) + } + oResult, err := bucket.ListObjects(opts...) + if err != nil { + return result, errors.Wrap(err, "ListObjects") + } + result.Objects = make([]cloudprovider.ICloudObject, 0) + for _, object := range oResult.Objects { + obj := &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + StorageClass: object.StorageClass, + Key: object.Key, + SizeBytes: object.Size, + ETag: object.ETag, + LastModified: object.LastModified, + }, + } + result.Objects = append(result.Objects, obj) + } + if oResult.CommonPrefixes != nil { + result.CommonPrefixes = make([]cloudprovider.ICloudObject, len(oResult.CommonPrefixes)) + for i, commPrefix := range oResult.CommonPrefixes { + result.CommonPrefixes[i] = &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{Key: commPrefix}, + } + } + } + result.IsTruncated = oResult.IsTruncated + result.NextMarker = oResult.NextMarker + return result, nil +} + +func metaOpts(opts []oss.Option, meta http.Header) []oss.Option { + for k, v := range meta { + if len(v) == 0 { + continue + } + switch http.CanonicalHeaderKey(k) { + case cloudprovider.META_HEADER_CONTENT_TYPE: + opts = append(opts, oss.ContentType(v[0])) + case cloudprovider.META_HEADER_CONTENT_MD5: + opts = append(opts, oss.ContentMD5(v[0])) + case cloudprovider.META_HEADER_CONTENT_LANGUAGE: + opts = append(opts, oss.ContentLanguage(v[0])) + case cloudprovider.META_HEADER_CONTENT_ENCODING: + opts = append(opts, oss.ContentEncoding(v[0])) + case cloudprovider.META_HEADER_CONTENT_DISPOSITION: + opts = append(opts, oss.ContentDisposition(v[0])) + case cloudprovider.META_HEADER_CACHE_CONTROL: + opts = append(opts, oss.CacheControl(v[0])) + default: + opts = append(opts, oss.Meta(http.CanonicalHeaderKey(k), v[0])) + } + } + return opts +} + +func (b *SBucket) PutObject(ctx context.Context, key string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + osscli, err := b.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return errors.Wrap(err, "Bucket") + } + opts := make([]oss.Option, 0) + if sizeBytes > 0 { + opts = append(opts, oss.ContentLength(sizeBytes)) + } + if meta != nil { + opts = metaOpts(opts, meta) + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + acl, err := str2Acl(string(cannedAcl)) + if err != nil { + return errors.Wrap(err, "") + } + opts = append(opts, oss.ObjectACL(acl)) + if len(storageClassStr) > 0 { + storageClass, err := str2StorageClass(storageClassStr) + if err != nil { + return errors.Wrap(err, "str2StorageClass") + } + opts = append(opts, oss.ObjectStorageClass(storageClass)) + } + return bucket.PutObject(key, input, opts...) +} + +func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + osscli, err := b.region.GetOssClient() + if err != nil { + return "", errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return "", errors.Wrap(err, "Bucket") + } + opts := make([]oss.Option, 0) + if meta != nil { + opts = metaOpts(opts, meta) + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + acl, err := str2Acl(string(cannedAcl)) + if err != nil { + return "", errors.Wrap(err, "str2Acl") + } + opts = append(opts, oss.ObjectACL(acl)) + if len(storageClassStr) > 0 { + storageClass, err := str2StorageClass(storageClassStr) + if err != nil { + return "", errors.Wrap(err, "str2StorageClass") + } + opts = append(opts, oss.ObjectStorageClass(storageClass)) + } + result, err := bucket.InitiateMultipartUpload(key, opts...) + if err != nil { + return "", errors.Wrap(err, "bucket.InitiateMultipartUpload") + } + return result.UploadID, nil +} + +func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { + osscli, err := b.region.GetOssClient() + if err != nil { + return "", errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return "", errors.Wrap(err, "Bucket") + } + imur := oss.InitiateMultipartUploadResult{ + Bucket: b.Name, + Key: key, + UploadID: uploadId, + } + part, err := bucket.UploadPart(imur, input, partSize, partIndex) + if err != nil { + return "", errors.Wrap(err, "bucket.UploadPart") + } + if b.region.client.debug { + log.Debugf("upload part key:%s uploadId:%s partIndex:%d etag:%s", key, uploadId, partIndex, part.ETag) + } + return part.ETag, nil +} + +func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { + osscli, err := b.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return errors.Wrap(err, "Bucket") + } + imur := oss.InitiateMultipartUploadResult{ + Bucket: b.Name, + Key: key, + UploadID: uploadId, + } + parts := make([]oss.UploadPart, len(partEtags)) + for i := range partEtags { + parts[i] = oss.UploadPart{ + PartNumber: i + 1, + ETag: partEtags[i], + } + } + result, err := bucket.CompleteMultipartUpload(imur, parts) + if err != nil { + return errors.Wrap(err, "bucket.CompleteMultipartUpload") + } + if b.region.client.debug { + log.Debugf("CompleteMultipartUpload bucket:%s key:%s etag:%s location:%s", result.Bucket, result.Key, result.ETag, result.Location) + } + return nil +} + +func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { + osscli, err := b.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return errors.Wrap(err, "Bucket") + } + imur := oss.InitiateMultipartUploadResult{ + Bucket: b.Name, + Key: key, + UploadID: uploadId, + } + err = bucket.AbortMultipartUpload(imur) + if err != nil { + return errors.Wrap(err, "AbortMultipartUpload") + } + return nil +} + +func (b *SBucket) DeleteObject(ctx context.Context, key string) error { + osscli, err := b.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return errors.Wrap(err, "Bucket") + } + err = bucket.DeleteObject(key) + if err != nil { + return errors.Wrap(err, "DeleteObject") + } + return nil +} + +func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { + if method != "GET" && method != "PUT" && method != "DELETE" { + return "", errors.Error("unsupported method") + } + osscli, err := b.region.GetOssClient() + if err != nil { + return "", errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return "", errors.Wrap(err, "Bucket") + } + urlStr, err := bucket.SignURL(key, oss.HTTPMethod(method), int64(expire/time.Second)) + if err != nil { + return "", errors.Wrap(err, "SignURL") + } + return urlStr, nil +} + +func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + osscli, err := b.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return errors.Wrap(err, "Bucket") + } + opts := make([]oss.Option, 0) + if meta != nil { + opts = metaOpts(opts, meta) + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + acl, err := str2Acl(string(cannedAcl)) + if err != nil { + return errors.Wrap(err, "str2Acl") + } + opts = append(opts, oss.ObjectACL(acl)) + if len(storageClassStr) > 0 { + storageClass, err := str2StorageClass(storageClassStr) + if err != nil { + return errors.Wrap(err, "str2StorageClass") + } + opts = append(opts, oss.ObjectStorageClass(storageClass)) + } + _, err = bucket.CopyObjectFrom(srcBucket, srcKey, destKey, opts...) + if err != nil { + return errors.Wrap(err, "CopyObjectFrom") + } + return nil +} + +func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { + osscli, err := b.region.GetOssClient() + if err != nil { + return nil, errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return nil, errors.Wrap(err, "Bucket") + } + opts := make([]oss.Option, 0) + if rangeOpt != nil { + opts = append(opts, oss.NormalizedRange(rangeOpt.String())) + } + output, err := bucket.GetObject(key, opts...) + if err != nil { + return nil, errors.Wrap(err, "bucket.GetObject") + } + return output, nil +} + +func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partNumber int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { + osscli, err := b.region.GetOssClient() + if err != nil { + return "", errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return "", errors.Wrap(err, "Bucket") + } + imur := oss.InitiateMultipartUploadResult{ + Bucket: b.Name, + Key: key, + UploadID: uploadId, + } + opts := make([]oss.Option, 0) + part, err := bucket.UploadPartCopy(imur, srcBucket, srcKey, srcOffset, srcLength, partNumber, opts...) + if err != nil { + return "", errors.Wrap(err, "bucket.UploadPartCopy") + } + return part.ETag, nil +} + +func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { + if len(websitConf.Index) == 0 { + return errors.Wrap(cloudprovider.ErrNotSupported, "missing Index") + } + if len(websitConf.ErrorDocument) == 0 { + return errors.Wrap(cloudprovider.ErrNotSupported, "missing ErrorDocument") + } + osscli, err := b.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + + err = osscli.SetBucketWebsite(b.Name, websitConf.Index, websitConf.ErrorDocument) + if err != nil { + return errors.Wrapf(err, " osscli.SetBucketWebsite(%s,%s,%s)", b.Name, websitConf.Index, websitConf.ErrorDocument) + } + return nil +} + +func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { + result := cloudprovider.SBucketWebsiteConf{} + osscli, err := b.region.GetOssClient() + if err != nil { + return result, errors.Wrap(err, "GetOssClient") + } + websiteResult, err := osscli.GetBucketWebsite(b.Name) + if err != nil { + if strings.Contains(err.Error(), "NoSuchWebsiteConfiguration") { + return cloudprovider.SBucketWebsiteConf{}, nil + } + return result, errors.Wrapf(err, "osscli.GetBucketWebsite(%s)", b.Name) + } + result.Index = websiteResult.IndexDocument.Suffix + result.ErrorDocument = websiteResult.ErrorDocument.Key + return result, nil +} + +func (b *SBucket) DeleteWebSiteConf() error { + osscli, err := b.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + log.Infof("to be delete") + err = osscli.DeleteBucketWebsite(b.Name) + if err != nil { + return errors.Wrapf(err, "osscli.DeleteBucketWebsite(%s)", b.Name) + } + log.Infof("deleted") + return nil +} + +func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { + if len(rules) == 0 { + return nil + } + osscli, err := b.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + input := []oss.CORSRule{} + for i := range rules { + input = append(input, oss.CORSRule{ + AllowedOrigin: rules[i].AllowedOrigins, + AllowedMethod: rules[i].AllowedMethods, + AllowedHeader: rules[i].AllowedHeaders, + MaxAgeSeconds: rules[i].MaxAgeSeconds, + ExposeHeader: rules[i].ExposeHeaders, + }) + } + + err = osscli.SetBucketCORS(b.Name, input) + if err != nil { + return errors.Wrapf(err, "osscli.SetBucketCORS(%s,%s)", b.Name, jsonutils.Marshal(input).String()) + } + return nil +} + +func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { + osscli, err := b.region.GetOssClient() + if err != nil { + return nil, errors.Wrap(err, "GetOssClient") + } + conf, err := osscli.GetBucketCORS(b.Name) + if err != nil { + if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") { + return nil, errors.Wrapf(err, "osscli.GetBucketCORS(%s)", b.Name) + } + } + result := []cloudprovider.SBucketCORSRule{} + for i := range conf.CORSRules { + result = append(result, cloudprovider.SBucketCORSRule{ + AllowedOrigins: conf.CORSRules[i].AllowedOrigin, + AllowedMethods: conf.CORSRules[i].AllowedMethod, + AllowedHeaders: conf.CORSRules[i].AllowedHeader, + MaxAgeSeconds: conf.CORSRules[i].MaxAgeSeconds, + ExposeHeaders: conf.CORSRules[i].ExposeHeader, + Id: strconv.Itoa(i), + }) + } + return result, nil +} + +func (b *SBucket) DeleteCORS() error { + osscli, err := b.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + + err = osscli.DeleteBucketCORS(b.Name) + if err != nil { + return errors.Wrapf(err, "osscli.DeleteBucketCORS(%s)", b.Name) + } + + return nil +} + +func (b *SBucket) SetReferer(conf cloudprovider.SBucketRefererConf) error { + osscli, err := b.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + if !conf.Enabled { + return errors.Wrapf(cloudprovider.ErrNotSupported, "Disable Refer") + } + + if conf.RefererType == "Black-List" { + return errors.Wrapf(cloudprovider.ErrNotSupported, "Black List") + } + + err = osscli.SetBucketReferer(b.Name, conf.DomainList, conf.AllowEmptyRefer) + if err != nil { + return errors.Wrapf(err, "osscli.SetBucketReferer(%s,%s,%t)", b.Name, conf.DomainList, conf.AllowEmptyRefer) + } + return nil +} + +func (b *SBucket) GetReferer() (cloudprovider.SBucketRefererConf, error) { + result := cloudprovider.SBucketRefererConf{} + osscli, err := b.region.GetOssClient() + if err != nil { + return result, errors.Wrap(err, "GetOssClient") + } + refererResult, err := osscli.GetBucketReferer(b.Name) + if err != nil { + return result, errors.Wrapf(err, "osscli.GetBucketReferer(%s)", b.Name) + } + result = cloudprovider.SBucketRefererConf{ + Enabled: true, + RefererType: "White-List", + DomainList: refererResult.RefererList, + AllowEmptyRefer: refererResult.AllowEmptyReferer, + } + return result, nil +} + +func toAPICdnArea(area string) string { + switch area { + case "domestic": + return api.CDN_DOMAIN_AREA_MAINLAND + case "overseas": + return api.CDN_DOMAIN_AREA_OVERSEAS + case "global": + return api.CDN_DOMAIN_AREA_GLOBAL + default: + return "" + } +} + +func toAPICdnStatus(status string) string { + switch status { + case "online": + return api.CDN_DOMAIN_STATUS_ONLINE + case "offline": + return api.CDN_DOMAIN_STATUS_OFFLINE + case "configuring", "checking", "stopping", "deleting": + return api.CDN_DOMAIN_STATUS_PROCESSING + case "check_failed", "configure_failed": + return api.CDN_DOMAIN_STATUS_REJECTED + default: + return "" + } +} + +func (b *SBucket) GetCdnDomains() ([]cloudprovider.SCdnDomain, error) { + bucketExtUrl := fmt.Sprintf("%s.%s", b.Name, b.region.getOSSExternalDomain()) + cdnDomains, err := b.region.client.DescribeDomainsBySource(bucketExtUrl) + if err != nil { + return nil, errors.Wrapf(err, " b.region.client.DescribeDomainsBySource(%s)", bucketExtUrl) + } + result := []cloudprovider.SCdnDomain{} + for i := range cdnDomains.DomainsData { + if cdnDomains.DomainsData[i].Source == bucketExtUrl { + for j := range cdnDomains.DomainsData[i].Domains.DomainNames { + area := "" + domain, _ := b.region.client.GetCDNDomainByName(cdnDomains.DomainsData[i].Domains.DomainNames[j]) + if domain != nil { + area = domain.Coverage + } + result = append(result, cloudprovider.SCdnDomain{ + Domain: cdnDomains.DomainsData[i].Domains.DomainNames[j], + Status: toAPICdnStatus(cdnDomains.DomainsData[i].DomainInfos.DomainInfo[j].Status), + Cname: cdnDomains.DomainsData[i].DomainInfos.DomainInfo[j].DomainCname, + Area: toAPICdnArea(area), + Origin: bucketExtUrl, + OriginType: api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET, + }) + } + } + } + return result, nil +} + +func (b *SBucket) GetTags() (map[string]string, error) { + osscli, err := b.region.GetOssClient() + if err != nil { + return nil, errors.Wrap(err, "GetOssClient") + } + + tagresult, err := osscli.GetBucketTagging(b.Name) + if err != nil { + return nil, errors.Wrapf(err, "GetBucketTagging %s", b.Name) + } + result := map[string]string{} + for _, tag := range tagresult.Tags { + result[tag.Key] = tag.Value + } + return result, nil +} + +func (b *SBucket) SetTags(tags map[string]string, replace bool) error { + osscli, err := b.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + + err = osscli.DeleteBucketTagging(b.Name) + if err != nil { + return errors.Wrapf(err, "DeleteBucketTagging(%s)", b.Name) + } + + if len(tags) == 0 { + return nil + } + + input := []oss.Tag{} + for k, v := range tags { + input = append(input, oss.Tag{Key: k, Value: v}) + } + + err = osscli.SetBucketTagging(b.Name, oss.Tagging{Tags: input}) + if err != nil { + return errors.Wrapf(err, "osscli.SetBucketTagging(%s)", jsonutils.Marshal(input)) + } + return nil +} + +func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { + osscli, err := b.region.GetOssClient() + if err != nil { + return nil, errors.Wrap(err, "GetOssClient") + } + result := []cloudprovider.SBucketMultipartUploads{} + + ossBucket, err := osscli.Bucket(b.Name) + if err != nil { + return nil, errors.Wrap(err, "osscli.Bucket(b.Name)") + } + + keyMarker := oss.KeyMarker("") + uploadIDMarker := oss.UploadIDMarker("") + for { + output, err := ossBucket.ListMultipartUploads(keyMarker, uploadIDMarker) + if err != nil { + return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") + } + for i := range output.Uploads { + temp := cloudprovider.SBucketMultipartUploads{ + ObjectName: output.Uploads[i].Key, + UploadID: output.Uploads[i].UploadID, + Initiated: output.Uploads[i].Initiated, + } + result = append(result, temp) + } + keyMarker = oss.KeyMarker(output.NextKeyMarker) + uploadIDMarker = oss.UploadIDMarker(output.NextUploadIDMarker) + if !output.IsTruncated { + break + } + } + + return result, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/business.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/business.go new file mode 100644 index 0000000000..debf55df81 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/business.go @@ -0,0 +1,126 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +func (self *SAliyunClient) businessRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + cli, err := self.getDefaultClient() + if err != nil { + return nil, err + } + return jsonRequest(cli, "business.aliyuncs.com", ALIYUN_BSS_API_VERSION, apiName, params, self.debug) +} + +type SAccountBalance struct { + AvailableAmount float64 + AvailableCashAmount float64 + CreditAmount float64 + MybankCreditAmount float64 + Currency string +} + +type SCashCoupon struct { + ApplicableProducts string + ApplicableScenarios string + Balance float64 + CashCouponId string + CashCouponNo string + EffectiveTime time.Time + ExpiryTime time.Time + GrantedTime time.Time + NominalValue float64 + Status string +} + +type SPrepaidCard struct { + PrepaidCardId string + PrepaidCardNo string + GrantedTime time.Time + EffectiveTime time.Time + ExpiryTime time.Time + NominalValue float64 + Balance float64 + ApplicableProducts string + ApplicableScenarios string +} + +func (self *SAliyunClient) QueryAccountBalance() (*SAccountBalance, error) { + body, err := self.businessRequest("QueryAccountBalance", nil) + if err != nil { + // {"RequestId":"5258BDEF-8975-4EB0-9E0C-08D5E54E7981","HostId":"business.aliyuncs.com","Code":"NotAuthorized","Message":"This API is not authorized for caller."} + if isError(err, "NotApplicable") || isError(err, "NotAuthorized") { + return nil, cloudprovider.ErrNoBalancePermission + } + return nil, errors.Wrapf(err, "QueryAccountBalance") + } + balance := SAccountBalance{} + err = body.Unmarshal(&balance, "Data") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal AccountBalance") + } + return &balance, nil +} + +func (self *SAliyunClient) QueryCashCoupons() ([]SCashCoupon, error) { + params := make(map[string]string) + params["EffectiveOrNot"] = "True" + body, err := self.businessRequest("QueryCashCoupons", params) + if err != nil { + return nil, errors.Wrapf(err, "QueryCashCoupons") + } + coupons := make([]SCashCoupon, 0) + err = body.Unmarshal(&coupons, "Data", "CashCoupon") + if err != nil { + return nil, errors.Wrapf(err, "body.Unmarshal") + } + return coupons, nil +} + +func (self *SAliyunClient) QueryPrepaidCards() ([]SPrepaidCard, error) { + params := make(map[string]string) + params["EffectiveOrNot"] = "True" + body, err := self.businessRequest("QueryPrepaidCards", params) + if err != nil { + return nil, errors.Wrapf(err, "QueryPrepaidCards") + } + cards := make([]SPrepaidCard, 0) + err = body.Unmarshal(&cards, "Data", "PrepaidCard") + if err != nil { + return nil, errors.Wrapf(err, "body.Unmarshal") + } + return cards, nil +} + +func (self *SAliyunClient) SubscribeBillToOSS(bucket string) error { + params := make(map[string]string) + params["SubscribeBucket"] = bucket + params["SubscribeType.0"] = "BillingItemDetailForBillingPeriod" + params["SubscribeType.1"] = "InstanceDetailForBillingPeriod" + body, err := self.businessRequest("SubscribeBillToOSS", params) + if err != nil { + return errors.Wrap(err, "SubscribeBillToOSS") + } + log.Debugf("%s", body) + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/cdn.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/cdn.go new file mode 100644 index 0000000000..4568e03b72 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/cdn.go @@ -0,0 +1,315 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SCdnDomainNames struct { + DomainNames []string `json:"domainNames"` +} + +type SDomainInfo struct { + DomainCname string `json:"DomainCname"` + Status string `json:"Status"` + CreateTime time.Time `json:"CreateTime"` + UpdateTime time.Time `json:"UpdateTime"` + DomainName string `json:"DomainName"` +} + +type SCdnDomainInfos struct { + DomainInfo []SDomainInfo `json:"domainInfo"` +} + +type SCdnDomainsData struct { + Source string `json:"Source"` + Domains SCdnDomainNames `json:"Domains"` + DomainInfos SCdnDomainInfos `json:"DomainInfos"` +} + +type SCdnDomainsList struct { + DomainsData []SCdnDomainsData `json:"DomainsData"` +} + +type SCdnSource struct { + Port int `json:"Port"` + Weight string `json:"Weight"` + Type string `json:"Type"` + Content string `json:"Content"` + Priority string `json:"Priority"` +} + +type SCdnSources struct { + Source []SCdnSource `json:"Source"` +} + +type SCdnDomain struct { + multicloud.SResourceBase + + client *SAliyunClient + + Cname string `json:"Cname"` + Description string `json:"Description"` + CdnType string `json:"CdnType"` + ResourceGroupID string `json:"ResourceGroupId"` + DomainStatus string `json:"DomainStatus"` + SslProtocol string `json:"SslProtocol"` + DomainName string `json:"DomainName"` + Coverage string `json:"Coverage"` + Sources SCdnSource `json:"Sources"` + GmtModified string `json:"GmtModified"` + Sandbox string `json:"Sandbox"` + GmtCreated time.Time `json:"GmtCreated"` + SourceModels struct { + SourceModel []struct { + Content string + Type string + Port int + Enabled string + Priority int + Weight string + } + } +} + +func (self *SCdnDomain) GetArea() string { + switch self.Coverage { + case "domestic": + return api.CDN_DOMAIN_AREA_MAINLAND + case "global": + return api.CDN_DOMAIN_AREA_GLOBAL + case "overseas": + return api.CDN_DOMAIN_AREA_OVERSEAS + default: + return self.Coverage + } +} + +func (self *SCdnDomain) GetCname() string { + return self.Cname +} + +func (self *SCdnDomain) GetEnabled() bool { + return self.DomainStatus != "offline" +} + +func (self *SCdnDomain) GetId() string { + return self.DomainName +} + +func (self *SCdnDomain) GetGlobalId() string { + return self.DomainName +} + +func (self *SCdnDomain) GetName() string { + return self.DomainName +} + +func (self *SCdnDomain) Refresh() error { + domain, err := self.client.GetCdnDomain(self.DomainName) + if err != nil { + return errors.Wrapf(err, "GetCdnDomain") + } + self.DomainStatus = domain.DomainStatus + return nil +} + +func (self *SCdnDomain) GetTags() (map[string]string, error) { + _, tags, err := self.client.GetRegion("").ListSysAndUserTags(ALIYUN_SERVICE_CDN, "DOMAIN", self.DomainName) + if err != nil { + return nil, errors.Wrapf(err, "ListTags") + } + tagMaps := map[string]string{} + for k, v := range tags { + tagMaps[strings.ToLower(k)] = v + } + return tagMaps, nil +} + +func (self *SCdnDomain) GetSysTags() map[string]string { + tags, _, err := self.client.GetRegion("").ListSysAndUserTags(ALIYUN_SERVICE_CDN, "DOMAIN", self.DomainName) + if err != nil { + return nil + } + tagMaps := map[string]string{} + for k, v := range tags { + tagMaps[strings.ToLower(k)] = v + } + return tagMaps +} + +func (self *SCdnDomain) SetTags(tags map[string]string, replace bool) error { + return self.client.GetRegion("").SetResourceTags(ALIYUN_SERVICE_CDN, "DOMAIN", self.DomainName, tags, replace) +} + +func (self *SCdnDomain) GetOrigins() *cloudprovider.SCdnOrigins { + domain, err := self.client.GetCdnDomain(self.DomainName) + if err != nil { + return nil + } + ret := cloudprovider.SCdnOrigins{} + for _, origin := range domain.SourceModels.SourceModel { + ret = append(ret, cloudprovider.SCdnOrigin{ + Type: origin.Type, + Origin: origin.Content, + Port: origin.Port, + Enabled: origin.Enabled, + Priority: origin.Priority, + }) + } + return &ret +} + +func (self *SCdnDomain) GetServiceType() string { + return self.CdnType +} + +func (self *SCdnDomain) GetStatus() string { + switch self.DomainStatus { + case "online", "offline": + return self.DomainStatus + case "configuring", "checking": + return api.CDN_DOMAIN_STATUS_PROCESSING + case "configure_failed": + return self.DomainStatus + case "check_failed": + return api.CDN_DOMAIN_STATUS_REJECTED + } + return self.DomainStatus +} + +func (self *SCdnDomain) Delete() error { + params := map[string]string{ + "DomainName": self.DomainName, + } + _, err := self.client.cdnRequest("DeleteCdnDomain", params) + return errors.Wrapf(err, "DeleteCdnDomain") +} + +func (self *SAliyunClient) GetICloudCDNDomains() ([]cloudprovider.ICloudCDNDomain, error) { + domains, err := self.GetCdnDomains() + if err != nil { + return nil, errors.Wrapf(err, "GetCdnDomains") + } + ret := []cloudprovider.ICloudCDNDomain{} + for i := range domains { + domains[i].client = self + ret = append(ret, &domains[i]) + } + return ret, nil +} + +func (self *SAliyunClient) GetICloudCDNDomainByName(name string) (cloudprovider.ICloudCDNDomain, error) { + return self.GetCDNDomainByName(name) +} + +func (self *SAliyunClient) GetCDNDomainByName(name string) (*SCdnDomain, error) { + domains, total, err := self.DescribeUserDomains(name, 1, 1) + if err != nil { + return nil, errors.Wrapf(err, "GetCdnDomain") + } + if total == 1 { + domains[0].client = self + return &domains[0], nil + } + if total == 0 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) + } + return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, name) +} + +func (client *SAliyunClient) DescribeDomainsBySource(origin string) (SCdnDomainsList, error) { + sproducts := SCdnDomainsList{} + params := map[string]string{} + params["Action"] = "DescribeDomainsBySource" + params["Sources"] = origin + resp, err := client.cdnRequest("DescribeDomainsBySource", params) + if err != nil { + return sproducts, errors.Wrap(err, "DescribeDomainsBySource") + } + err = resp.Unmarshal(&sproducts, "DomainsList") + if err != nil { + return sproducts, errors.Wrap(err, "resp.Unmarshal") + } + return sproducts, nil +} + +func (self *SAliyunClient) GetCdnDomains() ([]SCdnDomain, error) { + domains := []SCdnDomain{} + for { + part, total, err := self.DescribeUserDomains("", 50, len(domains)/50+1) + if err != nil { + return nil, errors.Wrapf(err, "DescribeUserDomains") + } + domains = append(domains, part...) + if len(domains) >= total || len(part) == 0 { + break + } + } + return domains, nil +} + +func (client *SAliyunClient) DescribeUserDomains(domain string, pageSize, pageNumber int) ([]SCdnDomain, int, error) { + if pageSize < 1 || pageSize > 50 { + pageSize = 50 + } + if pageNumber < 1 { + pageNumber = 1 + } + params := map[string]string{ + "PageSize": fmt.Sprintf("%d", pageSize), + "PageNumber": fmt.Sprintf("%d", pageNumber), + } + if len(domain) > 0 { + params["DomainName"] = domain + params["DomainSearchType"] = "full_match" + } + resp, err := client.cdnRequest("DescribeUserDomains", params) + if err != nil { + return nil, 0, errors.Wrap(err, "DescribeUserDomains") + } + domains := []SCdnDomain{} + err = resp.Unmarshal(&domains, "Domains", "PageData") + if err != nil { + return nil, 0, errors.Wrap(err, "resp.Unmarshal") + } + totalCount, _ := resp.Int("TotalCount") + return domains, int(totalCount), nil +} + +func (self *SAliyunClient) GetCdnDomain(domainName string) (*SCdnDomain, error) { + params := map[string]string{ + "DomainName": domainName, + } + resp, err := self.cdnRequest("DescribeCdnDomainDetail", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeCdnDomainDetail") + } + domain := &SCdnDomain{client: self} + err = resp.Unmarshal(domain, "GetDomainDetailModel") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return domain, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/charge.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/charge.go new file mode 100644 index 0000000000..8fab3adedb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/charge.go @@ -0,0 +1,42 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "time" + + api "yunion.io/x/cloudmux/pkg/apis/billing" +) + +func convertChargeType(ct TChargeType) string { + switch ct { + case PrePaidInstanceChargeType, PrePaidDBInstanceChargeType: + return api.BILLING_TYPE_PREPAID + case PostPaidInstanceChargeType, PostPaidDBInstanceChargeType: + return api.BILLING_TYPE_POSTPAID + default: + return "" + } +} + +func convertExpiredAt(expired time.Time) time.Time { + if !expired.IsZero() { + now := time.Now() + if expired.Sub(now) < time.Hour*24*365*6 { + return expired + } + } + return time.Time{} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/cloud_enterprise_network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/cloud_enterprise_network.go new file mode 100644 index 0000000000..620f25a288 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/cloud_enterprise_network.go @@ -0,0 +1,394 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SCen struct { + multicloud.SResourceBase + AliyunTags + client *SAliyunClient + Status string `json:"Status"` + ProtectionLevel string `json:"ProtectionLevel"` + CenID string `json:"CenId"` + CreationTime string `json:"CreationTime"` + CenBandwidthPackageIds CenBandwidthPackageIds `json:"CenBandwidthPackageIds"` + Name string `json:"Name"` +} + +type SCens struct { + TotalCount int `json:"TotalCount"` + RequestID string `json:"RequestId"` + PageSize int `json:"PageSize"` + PageNumber int `json:"PageNumber"` + Cens sCens `json:"Cens"` +} + +type CenBandwidthPackageIds struct { + CenBandwidthPackageID []string `json:"CenBandwidthPackageId"` +} + +type sCens struct { + Cen []SCen `json:"Cen"` +} + +type SCenChildInstances struct { + PageNumber int `json:"PageNumber"` + ChildInstances sCenChildInstances `json:"ChildInstances"` + TotalCount int `json:"TotalCount"` + PageSize int `json:"PageSize"` + RequestID string `json:"RequestId"` +} + +type SCenChildInstance struct { + Status string `json:"Status"` + ChildInstanceOwnerID string `json:"ChildInstanceOwnerId"` + ChildInstanceID string `json:"ChildInstanceId"` + ChildInstanceRegionID string `json:"ChildInstanceRegionId"` + CenID string `json:"CenId"` + ChildInstanceType string `json:"ChildInstanceType"` +} + +type sCenChildInstances struct { + ChildInstance []SCenChildInstance `json:"ChildInstance"` +} + +type SCenAttachInstanceInput struct { + InstanceType string + InstanceId string + InstanceRegion string + ChildInstanceOwnerId string +} + +func (client *SAliyunClient) DescribeCens(pageNumber int, pageSize int) (SCens, error) { + scens := SCens{} + params := map[string]string{} + params["Action"] = "DescribeCens" + params["PageNumber"] = strconv.Itoa(pageNumber) + params["PageSize"] = strconv.Itoa(pageSize) + resp, err := client.cbnRequest("DescribeCens", params) + if err != nil { + return scens, errors.Wrap(err, "DescribeCens") + } + err = resp.Unmarshal(&scens) + if err != nil { + return scens, errors.Wrap(err, "resp.Unmarshal") + } + return scens, nil +} + +func (client *SAliyunClient) GetAllCens() ([]SCen, error) { + pageNumber := 0 + sCen := []SCen{} + for { + pageNumber++ + cens, err := client.DescribeCens(pageNumber, 20) + if err != nil { + return nil, errors.Wrapf(err, "client.DescribeCens(%d, 20)", pageNumber) + } + sCen = append(sCen, cens.Cens.Cen...) + if len(sCen) >= cens.TotalCount { + break + } + } + for i := 0; i < len(sCen); i++ { + sCen[i].client = client + } + return sCen, nil +} + +func (client *SAliyunClient) CreateCen(opts *cloudprovider.SInterVpcNetworkCreateOptions) (string, error) { + params := map[string]string{} + params["Name"] = opts.Name + params["Description"] = opts.Desc + resp, err := client.cbnRequest("CreateCen", params) + if err != nil { + return "", errors.Wrap(err, "CreateCen") + } + type CentId struct { + CenId string `json:"CenId"` + } + centId := CentId{} + err = resp.Unmarshal(¢Id) + if err != nil { + return "", errors.Wrap(err, "resp.Unmarshal") + } + return centId.CenId, nil +} + +func (client *SAliyunClient) DeleteCen(id string) error { + params := map[string]string{} + params["CenId"] = id + _, err := client.cbnRequest("DeleteCen", params) + if err != nil { + return errors.Wrap(err, "DeleteCen") + } + return nil +} + +func (client *SAliyunClient) DescribeCenAttachedChildInstances(cenId string, pageNumber int, pageSize int) (SCenChildInstances, error) { + scenChilds := SCenChildInstances{} + params := map[string]string{} + params["CenId"] = cenId + params["PageNumber"] = strconv.Itoa(pageNumber) + params["PageSize"] = strconv.Itoa(pageSize) + resp, err := client.cbnRequest("DescribeCenAttachedChildInstances", params) + if err != nil { + return scenChilds, errors.Wrap(err, "DescribeCenAttachedChildInstances") + } + err = resp.Unmarshal(&scenChilds) + if err != nil { + return scenChilds, errors.Wrap(err, "resp.Unmarshal") + } + return scenChilds, nil +} + +func (client *SAliyunClient) GetAllCenAttachedChildInstances(cenId string) ([]SCenChildInstance, error) { + pageNumber := 0 + scenChilds := []SCenChildInstance{} + for { + pageNumber++ + cenChilds, err := client.DescribeCenAttachedChildInstances(cenId, pageNumber, 20) + if err != nil { + return nil, errors.Wrapf(err, "client.DescribeCens(%d, 20)", pageNumber) + } + scenChilds = append(scenChilds, cenChilds.ChildInstances.ChildInstance...) + if len(scenChilds) >= cenChilds.TotalCount { + break + } + } + return scenChilds, nil +} + +func (client *SAliyunClient) AttachCenChildInstance(cenId string, instance SCenAttachInstanceInput) error { + params := map[string]string{} + params["CenId"] = cenId + params["ChildInstanceId"] = instance.InstanceId + params["ChildInstanceRegionId"] = instance.InstanceRegion + params["ChildInstanceType"] = instance.InstanceType + params["ChildInstanceOwnerId"] = instance.ChildInstanceOwnerId + _, err := client.cbnRequest("AttachCenChildInstance", params) + if err != nil { + return errors.Wrap(err, "AttachCenChildInstance") + } + return nil +} + +func (client *SAliyunClient) DetachCenChildInstance(cenId string, instance SCenAttachInstanceInput) error { + params := map[string]string{} + params["CenId"] = cenId + params["ChildInstanceId"] = instance.InstanceId + params["ChildInstanceRegionId"] = instance.InstanceRegion + params["ChildInstanceType"] = instance.InstanceType + params["ChildInstanceOwnerId"] = instance.ChildInstanceOwnerId + _, err := client.cbnRequest("DetachCenChildInstance", params) + if err != nil { + return errors.Wrap(err, "DetachCenChildInstance") + } + return nil +} + +func (self *SCen) GetId() string { + return self.CenID +} + +func (self *SCen) GetName() string { + return self.Name +} + +func (self *SCen) GetGlobalId() string { + return self.GetId() +} + +func (self *SCen) GetStatus() string { + switch self.Status { + case "Creating": + return api.INTER_VPC_NETWORK_STATUS_CREATING + case "Active": + return api.INTER_VPC_NETWORK_STATUS_AVAILABLE + case "Deleting": + return api.INTER_VPC_NETWORK_STATUS_DELETING + default: + return api.INTER_VPC_NETWORK_STATUS_UNKNOWN + } +} + +func (self *SCen) Refresh() error { + scens, err := self.client.GetAllCens() + if err != nil { + return errors.Wrap(err, "self.client.GetAllCens()") + } + for i := range scens { + if scens[i].CenID == self.CenID { + return jsonutils.Update(self, scens[i]) + } + } + return cloudprovider.ErrNotFound +} + +func (self *SCen) GetAuthorityOwnerId() string { + return self.client.ownerId +} + +func (self *SCen) GetICloudVpcIds() ([]string, error) { + childs, err := self.client.GetAllCenAttachedChildInstances(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "self.client.GetAllCenAttachedChildInstances(self.GetId())") + } + vpcIds := []string{} + for i := range childs { + if childs[i].ChildInstanceType == "VPC" { + vpcIds = append(vpcIds, childs[i].ChildInstanceID) + } + } + return vpcIds, nil +} + +func (self *SCen) AttachVpc(opts *cloudprovider.SInterVpcNetworkAttachVpcOption) error { + instance := SCenAttachInstanceInput{ + InstanceType: "VPC", + InstanceId: opts.VpcId, + InstanceRegion: opts.VpcRegionId, + ChildInstanceOwnerId: opts.VpcAuthorityOwnerId, + } + err := self.client.AttachCenChildInstance(self.GetId(), instance) + if err != nil { + return errors.Wrapf(err, "self.client.AttachCenChildInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) + } + return nil +} + +func (self *SCen) DetachVpc(opts *cloudprovider.SInterVpcNetworkDetachVpcOption) error { + instance := SCenAttachInstanceInput{ + InstanceType: "VPC", + InstanceId: opts.VpcId, + InstanceRegion: opts.VpcRegionId, + ChildInstanceOwnerId: opts.VpcAuthorityOwnerId, + } + err := self.client.DetachCenChildInstance(self.GetId(), instance) + if err != nil { + return errors.Wrapf(err, "self.client.DetachCenChildInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) + } + return nil +} + +func (self *SCen) Delete() error { + err := self.client.DeleteCen(self.GetId()) + if err != nil { + return errors.Wrapf(err, "self.client.DeleteCen(%s)", self.GetId()) + } + return nil +} + +func (self *SCen) GetInstanceRouteEntries() ([]SCenRouteEntry, error) { + childInstance, err := self.client.GetAllCenAttachedChildInstances(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "self.client.GetAllCenAttachedChildInstances(self.GetId())") + } + result := []SCenRouteEntry{} + for i := range childInstance { + routes, err := self.client.GetAllCenChildInstanceRouteEntries(self.GetId(), childInstance[i].ChildInstanceID, childInstance[i].ChildInstanceRegionID, childInstance[i].ChildInstanceType) + if err != nil { + return nil, errors.Wrap(err, "self.client.GetAllCenChildInstanceRouteEntries(self.GetId(), childInstance[i].ChildInstanceID, childInstance[i].ChildInstanceRegionID, childInstance[i].ChildInstanceType)") + } + for j := range routes { + // CEN 类型的路由是通过CEN从其他vpc/vbr的路由表中传播过来的 + // 只关注路由的发源 + if routes[j].Type != "CEN" { + routes[j].ChildInstance = &childInstance[i] + result = append(result, routes[j]) + } + } + } + return result, nil +} + +func (self *SCen) GetIRoutes() ([]cloudprovider.ICloudInterVpcNetworkRoute, error) { + result := []cloudprovider.ICloudInterVpcNetworkRoute{} + routeEntries, err := self.GetInstanceRouteEntries() + if err != nil { + return nil, errors.Wrap(err, "self.GetInstanceRouteEntries()") + } + for i := range routeEntries { + result = append(result, &routeEntries[i]) + } + return result, nil +} + +func (self *SCen) EnableRouteEntry(routeId string) error { + idContent := strings.Split(routeId, ":") + if len(idContent) != 2 { + return errors.Wrapf(cloudprovider.ErrNotSupported, "invalid aliyun generated cenRouteId %s", routeId) + } + routeTable := idContent[0] + cidr := idContent[1] + routeEntries, err := self.GetInstanceRouteEntries() + if err != nil { + return errors.Wrap(err, "self.GetInstanceRouteEntries()") + } + routeEntry := SCenRouteEntry{} + for i := range routeEntries { + if routeEntries[i].RouteTableID == routeTable && routeEntries[i].DestinationCidrBlock == cidr { + routeEntry = routeEntries[i] + break + } + } + if routeEntry.GetEnabled() { + return nil + } + err = self.client.PublishRouteEntries(self.GetId(), routeEntry.GetInstanceId(), routeTable, routeEntry.GetInstanceRegionId(), routeEntry.GetInstanceType(), cidr) + if err != nil { + return errors.Wrap(err, "self.client.PublishRouteEntries()") + } + return nil +} + +func (self *SCen) DisableRouteEntry(routeId string) error { + idContent := strings.Split(routeId, ":") + if len(idContent) != 2 { + return errors.Wrapf(cloudprovider.ErrNotSupported, "invalid aliyun generated cenRouteId %s", routeId) + } + routeTable := idContent[0] + cidr := idContent[1] + routeEntries, err := self.GetInstanceRouteEntries() + if err != nil { + return errors.Wrap(err, "self.GetInstanceRouteEntries()") + } + routeEntry := SCenRouteEntry{} + for i := range routeEntries { + if routeEntries[i].RouteTableID == routeTable && routeEntries[i].DestinationCidrBlock == cidr { + routeEntry = routeEntries[i] + break + } + } + if !routeEntry.GetEnabled() { + return nil + } + err = self.client.WithdrawPublishedRouteEntries(self.GetId(), routeEntry.GetInstanceId(), routeTable, routeEntry.GetInstanceRegionId(), routeEntry.GetInstanceType(), cidr) + if err != nil { + return errors.Wrap(err, "self.client.PublishRouteEntries()") + } + return nil +} diff --git a/pkg/multicloud/aliyun/cloud_enterprise_network_route.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/cloud_enterprise_network_route.go similarity index 98% rename from pkg/multicloud/aliyun/cloud_enterprise_network_route.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/cloud_enterprise_network_route.go index 3358c31cbd..47df3801e6 100644 --- a/pkg/multicloud/aliyun/cloud_enterprise_network_route.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/cloud_enterprise_network_route.go @@ -20,8 +20,8 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SCenRouteEntries struct { @@ -58,7 +58,7 @@ type Conflict struct { type SCenRouteEntry struct { multicloud.SResourceBase - multicloud.AliyunTags + AliyunTags ChildInstance *SCenChildInstance NextHopInstanceID string `json:"NextHopInstanceId,omitempty"` Status string `json:"Status"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance.go new file mode 100644 index 0000000000..ffb57a7c0d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance.go @@ -0,0 +1,908 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/rand" +) + +type SReadOnlyDBInstanceIds struct { + ReadOnlyDBInstanceId []string +} + +type SDBInstanceId struct { + DBInstanceId []string +} + +type SDBInstanceExtra struct { + DBInstanceId SDBInstanceId +} + +type SDBInstance struct { + multicloud.SDBInstanceBase + + netInfo []SDBInstanceNetwork + + region *SRegion + + AccountMaxQuantity int + AccountType string + CanTempUpgrade bool + Category string + AvailabilityValue string + DBInstanceDescription string + DBInstanceId string + ConnectionMode string + ConnectionString string + ConnectionDomain string + CurrentKernelVersion string + DBInstanceCPU int + CreateTime time.Time + DBInstanceClass string + DBInstanceClassType string + DBInstanceNetType string + DBInstanceStatus string + DBInstanceType string + DBInstanceDiskUsed int64 + DBInstanceStorage int + DBInstanceStorageType string + MasterInstanceId string + DBInstanceMemory int + DBMaxQuantity int + IPType string + LatestKernelVersion string + DispenseMode string + Engine string + EngineVersion string + ExpireTime time.Time + InstanceNetworkType string + LockMode string + LockReason string + MutriORsignle bool + MaintainTime string + MaxConnections int + MaxIOPS int + Port int + PayType TChargeType + ReadOnlyDBInstanceIds SReadOnlyDBInstanceIds + RegionId string + ResourceGroupId string + VSwitchId string + VpcCloudInstanceId string + VpcId string + ZoneId string + Extra SDBInstanceExtra + SecurityIPList string + SecurityIPMode string + SupportCreateSuperAccount string + SupportUpgradeAccountType string + TempUpgradeTimeEnd time.Time + TempUpgradeTimeStart time.Time +} + +func (rds *SDBInstance) GetName() string { + if len(rds.DBInstanceDescription) > 0 { + return rds.DBInstanceDescription + } + return rds.DBInstanceId +} + +func (rds *SDBInstance) GetId() string { + return rds.DBInstanceId +} + +func (rds *SDBInstance) GetGlobalId() string { + return rds.GetId() +} + +// Creating 创建中 +// Running 使用中 +// Deleting 删除中 +// Rebooting 重启中 +// DBInstanceClassChanging 升降级中 +// TRANSING 迁移中 +// EngineVersionUpgrading 迁移版本中 +// TransingToOthers 迁移数据到其他RDS中 +// GuardDBInstanceCreating 生产灾备实例中 +// Restoring 备份恢复中 +// Importing 数据导入中 +// ImportingFromOthers 从其他RDS实例导入数据中 +// DBInstanceNetTypeChanging 内外网切换中 +// GuardSwitching 容灾切换中 +// INS_CLONING 实例克隆中 +func (rds *SDBInstance) GetStatus() string { + switch rds.DBInstanceStatus { + case "Creating", "GuardDBInstanceCreating", "DBInstanceNetTypeChanging", "GuardSwitching", "NET_CREATING", "NET_DELETING": + return api.DBINSTANCE_DEPLOYING + case "DBInstanceClassChanging": + return api.DBINSTANCE_CHANGE_CONFIG + case "Running": + return api.DBINSTANCE_RUNNING + case "Deleting": + return api.DBINSTANCE_DELETING + case "Rebooting": + return api.DBINSTANCE_REBOOTING + case "TRANSING", "EngineVersionUpgrading", "TransingToOthers": + return api.DBINSTANCE_MIGRATING + case "Restoring": + return api.DBINSTANCE_RESTORING + case "Importing", "ImportingFromOthers": + return api.DBINSTANCE_IMPORTING + case "INS_CLONING": + return api.DBINSTANCE_CLONING + default: + log.Errorf("Unknown dbinstance status %s", rds.DBInstanceStatus) + return api.DBINSTANCE_UNKNOWN + } +} + +func (rds *SDBInstance) GetBillingType() string { + return convertChargeType(rds.PayType) +} + +func (rds *SDBInstance) GetExpiredAt() time.Time { + return rds.ExpireTime +} + +func (rds *SDBInstance) GetCreatedAt() time.Time { + return rds.CreateTime +} + +func (rds *SDBInstance) GetStorageType() string { + return rds.DBInstanceStorageType +} + +func (rds *SDBInstance) GetEngine() string { + switch rds.Engine { + case "MySQL": + return api.DBINSTANCE_TYPE_MYSQL + case "SQLServer": + return api.DBINSTANCE_TYPE_SQLSERVER + case "PostgreSQL": + return api.DBINSTANCE_TYPE_POSTGRESQL + case "PPAS": + return api.DBINSTANCE_TYPE_PPAS + case "MariaDB": + return api.DBINSTANCE_TYPE_MARIADB + } + return rds.Engine +} + +func (rds *SDBInstance) GetEngineVersion() string { + return rds.EngineVersion +} + +func (rds *SDBInstance) GetInstanceType() string { + return rds.DBInstanceClass +} + +func (rds *SDBInstance) GetCategory() string { + switch rds.Category { + case "Basic": + return api.ALIYUN_DBINSTANCE_CATEGORY_BASIC + case "HighAvailability": + return api.ALIYUN_DBINSTANCE_CATEGORY_HA + case "AlwaysOn": + return api.ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON + case "Finance": + return api.ALIYUN_DBINSTANCE_CATEGORY_FINANCE + } + return rds.Category +} + +func (rds *SDBInstance) GetVcpuCount() int { + if rds.DBInstanceCPU == 0 { + rds.Refresh() + } + return rds.DBInstanceCPU +} + +func (rds *SDBInstance) GetVmemSizeMB() int { + if rds.DBInstanceMemory == 0 { + rds.Refresh() + } + return rds.DBInstanceMemory +} + +func (rds *SDBInstance) GetDiskSizeGB() int { + if rds.DBInstanceStorage == 0 { + rds.Refresh() + } + return rds.DBInstanceStorage +} + +func (rds *SDBInstance) GetDiskSizeUsedMB() int { + if rds.DBInstanceDiskUsed == 0 { + rds.Refresh() + } + return int(rds.DBInstanceDiskUsed / 1024 / 1024) +} + +func (rds *SDBInstance) GetPort() int { + if rds.Port == 0 { + rds.Refresh() + } + return rds.Port +} + +func (rds *SDBInstance) GetMaintainTime() string { + return rds.MaintainTime +} + +func (rds *SDBInstance) GetIVpcId() string { + return rds.VpcId +} + +func (rds *SDBInstance) Refresh() error { + instance, err := rds.region.GetDBInstanceDetail(rds.DBInstanceId) + if err != nil { + return err + } + return jsonutils.Update(rds, instance) +} + +func (rds *SDBInstance) getZoneId(index int) string { + zoneId := rds.getZone(index) + if len(zoneId) > 0 { + zone, err := rds.region.getZoneById(zoneId) + if err != nil { + log.Errorf("failed to found zone %s for rds %s", zoneId, rds.GetName()) + return "" + } + return zone.GetGlobalId() + } + return "" +} + +func (rds *SDBInstance) GetZone1Id() string { + return rds.getZoneId(1) +} + +func (rds *SDBInstance) GetZone2Id() string { + return rds.getZoneId(2) +} + +func (rds *SDBInstance) GetZone3Id() string { + return rds.getZoneId(3) +} + +func (rds *SDBInstance) GetIOPS() int { + if rds.MaxIOPS == 0 { + rds.Refresh() + } + return rds.MaxIOPS +} + +func (rds *SDBInstance) GetNetworkAddress() string { + return rds.ConnectionDomain +} + +func (rds *SDBInstance) getZone(index int) string { + zoneStr := strings.Replace(rds.ZoneId, ")", "", -1) + zoneInfo := strings.Split(zoneStr, ",") + if len(zoneInfo) < index { + return "" + } + zone := zoneInfo[index-1] + zoneCode := zone[len(zone)-1] + if strings.HasPrefix(rds.ZoneId, fmt.Sprintf("%s-", rds.RegionId)) { + return fmt.Sprintf("%s-%s", rds.RegionId, string(zoneCode)) + } + return fmt.Sprintf("%s%s", rds.RegionId, string(zoneCode)) +} + +func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { + netInfo, err := rds.region.GetDBInstanceNetInfo(rds.DBInstanceId) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceNetInfo") + } + networks := []cloudprovider.SDBInstanceNetwork{} + for _, net := range netInfo { + if net.IPType == "Private" { + network := cloudprovider.SDBInstanceNetwork{} + network.IP = net.IPAddress + network.NetworkId = net.VSwitchId + networks = append(networks, network) + } + } + return networks, nil +} + +func (rds *SDBInstance) fetchNetInfo() error { + if len(rds.netInfo) > 0 { + return nil + } + netInfo, err := rds.region.GetDBInstanceNetInfo(rds.DBInstanceId) + if err != nil { + return errors.Wrap(err, "GetDBInstanceNetInfo") + } + rds.netInfo = netInfo + return nil +} + +func (rds *SDBInstance) GetInternalConnectionStr() string { + err := rds.fetchNetInfo() + if err != nil { + log.Errorf("failed to fetch netInfo error: %v", err) + return "" + } + + str := "" + for _, net := range rds.netInfo { + if net.IPType != "Public" { + if net.IPType == "Private" { + return net.ConnectionString + } else if net.IPType == "Inner" { + str = net.ConnectionString + } + } + } + return str +} + +func (rds *SDBInstance) GetConnectionStr() string { + err := rds.fetchNetInfo() + if err != nil { + log.Errorf("failed to fetch netInfo error: %v", err) + return "" + } + + for _, net := range rds.netInfo { + if net.IPType == "Public" { + return net.ConnectionString + } + } + return "" +} + +func (region *SRegion) GetDBInstances(ids []string, offset int, limit int) ([]SDBInstance, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + body, err := region.rdsRequest("DescribeDBInstances", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "GetDBInstances") + } + instances := []SDBInstance{} + err = body.Unmarshal(&instances, "Items", "DBInstance") + if err != nil { + return nil, 0, errors.Wrapf(err, "GetDBInstances.Unmarshal") + } + total, _ := body.Int("TotalRecordCount") + return instances, int(total), nil +} + +func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { + rds, err := region.GetDBInstanceDetail(instanceId) + if err != nil { + return nil, err + } + rds.region = region + return rds, nil +} + +func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { + instances := []SDBInstance{} + for { + part, total, err := region.GetDBInstances([]string{}, len(instances), 50) + if err != nil { + return nil, err + } + instances = append(instances, part...) + if len(instances) >= total { + break + } + } + idbinstances := []cloudprovider.ICloudDBInstance{} + for i := 0; i < len(instances); i++ { + instances[i].region = region + idbinstances = append(idbinstances, &instances[i]) + } + return idbinstances, nil +} + +func (region *SRegion) GetDBInstanceDetail(instanceId string) (*SDBInstance, error) { + if len(instanceId) == 0 { + return nil, cloudprovider.ErrNotFound + } + params := map[string]string{} + params["RegionId"] = region.RegionId + params["DBInstanceId"] = instanceId + body, err := region.rdsRequest("DescribeDBInstanceAttribute", params) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceDetail") + } + instances := []SDBInstance{} + err = body.Unmarshal(&instances, "Items", "DBInstanceAttribute") + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceDetail.Unmarshal") + } + if len(instances) == 1 { + instances[0].region = region + return &instances[0], nil + } + if len(instances) == 0 { + return nil, cloudprovider.ErrNotFound + } + return nil, cloudprovider.ErrDuplicateId +} + +func (region *SRegion) DeleteDBInstance(instanceId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["DBInstanceId"] = instanceId + _, err := region.rdsRequest("DeleteDBInstance", params) + return err +} + +type SDBInstanceWeight struct { +} + +type SDBInstanceWeights struct { + DBInstanceWeight []SDBInstanceWeight +} + +type SsecurityIPGroup struct { +} + +type SSecurityIPGroups struct { + securityIPGroup []SsecurityIPGroup +} + +type SDBInstanceNetwork struct { + ConnectionString string + ConnectionStringType string + DBInstanceWeights SDBInstanceWeights + IPAddress string + IPType string + Port int + SecurityIPGroups SSecurityIPGroups + Upgradeable string + VPCId string + VSwitchId string +} + +func (network *SDBInstanceNetwork) GetGlobalId() string { + return network.IPAddress +} + +func (network *SDBInstanceNetwork) GetINetworkId() string { + return network.VSwitchId +} + +func (network *SDBInstanceNetwork) GetIP() string { + return network.IPAddress +} + +func (region *SRegion) GetDBInstanceNetInfo(instanceId string) ([]SDBInstanceNetwork, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["DBInstanceId"] = instanceId + body, err := region.rdsRequest("DescribeDBInstanceNetInfo", params) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceNetwork") + } + networks := []SDBInstanceNetwork{} + err = body.Unmarshal(&networks, "DBInstanceNetInfos", "DBInstanceNetInfo") + if err != nil { + return nil, err + } + return networks, nil +} + +func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { + parameters, err := rds.region.GetDBInstanceParameters(rds.DBInstanceId) + if err != nil { + return nil, err + } + iparameters := []cloudprovider.ICloudDBInstanceParameter{} + for i := 0; i < len(parameters); i++ { + iparameters = append(iparameters, ¶meters[i]) + } + return iparameters, nil +} + +func (self *SDBInstance) GetSecurityGroupIds() ([]string, error) { + return self.region.GetRdsSecgroupIds(self.DBInstanceId) +} + +func (self *SDBInstance) SetSecurityGroups(ids []string) error { + return self.region.SetRdsSecgroups(self.DBInstanceId, ids) +} + +func (self *SRegion) SetRdsSecgroups(rdsId string, secIds []string) error { + params := map[string]string{ + "DBInstanceId": rdsId, + "SecurityGroupId": strings.Join(secIds, ","), + } + _, err := self.rdsRequest("ModifySecurityGroupConfiguration", params) + if err != nil { + return errors.Wrapf(err, "ModifySecurityGroupConfiguration") + } + return nil +} + +func (self *SRegion) GetRdsSecgroupIds(rdsId string) ([]string, error) { + params := map[string]string{ + "DBInstanceId": rdsId, + } + resp, err := self.rdsRequest("DescribeSecurityGroupConfiguration", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeSecurityGroupConfiguration") + } + items := []struct { + NetworkType string + SecurityGroupId string + RegionId string + }{} + err = resp.Unmarshal(&items, "Items", "EcsSecurityGroupRelation") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + ids := []string{} + for _, item := range items { + ids = append(ids, item.SecurityGroupId) + } + return ids, nil +} + +func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { + backups, err := region.GetIDBInstanceBackups() + if err != nil { + return nil, errors.Wrap(err, "region.GetIDBInstanceBackups") + } + for _, backup := range backups { + if backup.GetGlobalId() == backupId { + return backup, nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (rds *SDBInstance) Reboot() error { + return rds.region.RebootDBInstance(rds.DBInstanceId) +} + +func (rds *SDBInstance) Delete() error { + return rds.region.DeleteDBInstance(rds.DBInstanceId) +} + +func (region *SRegion) RebootDBInstance(instanceId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["DBInstanceId"] = instanceId + _, err := region.rdsRequest("RestartDBInstance", params) + return err +} + +func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { + databases := []SDBInstanceDatabase{} + for { + parts, total, err := rds.region.GetDBInstanceDatabases(rds.DBInstanceId, "", len(databases), 500) + if err != nil { + return nil, err + } + databases = append(databases, parts...) + if len(databases) >= total { + break + } + } + + idatabase := []cloudprovider.ICloudDBInstanceDatabase{} + for i := 0; i < len(databases); i++ { + databases[i].instance = rds + idatabase = append(idatabase, &databases[i]) + } + return idatabase, nil +} + +func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { + accounts := []SDBInstanceAccount{} + for { + parts, total, err := rds.region.GetDBInstanceAccounts(rds.DBInstanceId, len(accounts), 50) + if err != nil { + return nil, err + } + accounts = append(accounts, parts...) + if len(accounts) >= total { + break + } + } + + iaccounts := []cloudprovider.ICloudDBInstanceAccount{} + for i := 0; i < len(accounts); i++ { + accounts[i].instance = rds + iaccounts = append(iaccounts, &accounts[i]) + } + return iaccounts, nil +} + +func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { + return rds.region.ChangeDBInstanceConfig(rds.DBInstanceId, string(rds.PayType), desc) +} + +func (region *SRegion) ChangeDBInstanceConfig(instanceId, payType string, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { + params := map[string]string{ + "RegionId": region.RegionId, + "DBInstanceId": instanceId, + "PayType": payType, + } + if len(desc.InstanceType) > 0 { + params["DBInstanceClass"] = desc.InstanceType + } + if desc.DiskSizeGB > 0 { + params["DBInstanceStorage"] = fmt.Sprintf("%d", desc.DiskSizeGB) + } + + _, err := region.rdsRequest("ModifyDBInstanceSpec", params) + if err != nil { + return errors.Wrap(err, "region.rdsRequest.ModifyDBInstanceSpec") + } + return nil +} + +func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + params := map[string]string{ + "RegionId": region.RegionId, + "Engine": desc.Engine, + "EngineVersion": desc.EngineVersion, + "DBInstanceStorage": fmt.Sprintf("%d", desc.DiskSizeGB), + "DBInstanceNetType": "Intranet", + "PayType": "Postpaid", + "SecurityIPList": "0.0.0.0/0", + "DBInstanceDescription": desc.Name, + "InstanceNetworkType": "VPC", + "VPCId": desc.VpcId, + "VSwitchId": desc.NetworkId, + "DBInstanceStorageType": desc.StorageType, + "DBInstanceClass": desc.InstanceType, + "ZoneId": desc.ZoneId, + "ClientToken": utils.GenRequestId(20), + } + switch desc.Category { + case api.ALIYUN_DBINSTANCE_CATEGORY_HA: + params["Category"] = "HighAvailability" + case api.ALIYUN_DBINSTANCE_CATEGORY_BASIC: + params["Category"] = "Basic" + case api.ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON: + params["Category"] = "AlwaysOn" + case api.ALIYUN_DBINSTANCE_CATEGORY_FINANCE: + params["Category"] = "Finance" + } + + if len(desc.Address) > 0 { + params["PrivateIpAddress"] = desc.Address + } + if len(desc.ProjectId) > 0 { + params["ResourceGroupId"] = desc.ProjectId + } + if desc.BillingCycle != nil { + params["PayType"] = "Prepaid" + if desc.BillingCycle.GetYears() > 0 { + params["Period"] = "Year" + params["UsedTime"] = fmt.Sprintf("%d", desc.BillingCycle.GetYears()) + } else { + params["Period"] = "Month" + params["UsedTime"] = fmt.Sprintf("%d", desc.BillingCycle.GetMonths()) + } + params["AutoRenew"] = "False" + if desc.BillingCycle.AutoRenew { + params["AutoRenew"] = "True" + } + } + + action := "CreateDBInstance" + if len(desc.MasterInstanceId) > 0 { + action = "CreateReadOnlyDBInstance" + params["DBInstanceId"] = desc.MasterInstanceId + } + + resp, err := region.rdsRequest(action, params) + if err != nil { + return nil, errors.Wrapf(err, "rdsRequest") + } + instanceId, err := resp.GetString("DBInstanceId") + if err != nil { + return nil, errors.Wrap(err, `resp.GetString("DBInstanceId")`) + } + region.SetResourceTags(ALIYUN_SERVICE_RDS, "INSTANCE", instanceId, desc.Tags, false) + return region.GetIDBInstanceById(instanceId) +} + +func (rds *SDBInstance) GetMasterInstanceId() string { + if len(rds.MasterInstanceId) > 0 { + return rds.MasterInstanceId + } + rds.Refresh() + return rds.MasterInstanceId +} + +func (region *SRegion) OpenPublicConnection(instanceId string) error { + rds, err := region.GetDBInstanceDetail(instanceId) + if err != nil { + return err + } + params := map[string]string{ + "RegionId": region.RegionId, + "ConnectionStringPrefix": rds.DBInstanceId + rand.String(3), + "DBInstanceId": rds.DBInstanceId, + "Port": fmt.Sprintf("%d", rds.Port), + } + _, err = rds.region.rdsRequest("AllocateInstancePublicConnection", params) + if err != nil { + return errors.Wrap(err, "rdsRequest(AllocateInstancePublicConnection)") + } + return nil +} + +func (rds *SDBInstance) OpenPublicConnection() error { + if url := rds.GetConnectionStr(); len(url) == 0 { + err := rds.region.OpenPublicConnection(rds.DBInstanceId) + if err != nil { + return err + } + rds.netInfo = []SDBInstanceNetwork{} + } + return nil +} + +func (region *SRegion) ClosePublicConnection(instanceId string) error { + netInfo, err := region.GetDBInstanceNetInfo(instanceId) + if err != nil { + return errors.Wrap(err, "GetDBInstanceNetInfo") + } + + for _, net := range netInfo { + if net.IPType == "Public" { + params := map[string]string{ + "RegionId": region.RegionId, + "CurrentConnectionString": net.ConnectionString, + "DBInstanceId": instanceId, + } + _, err = region.rdsRequest("ReleaseInstancePublicConnection", params) + if err != nil { + return errors.Wrap(err, "rdsRequest(ReleaseInstancePublicConnection)") + } + + } + } + return nil + +} + +func (rds *SDBInstance) ClosePublicConnection() error { + return rds.region.ClosePublicConnection(rds.DBInstanceId) +} + +func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { + if len(conf.OriginDBInstanceExternalId) == 0 { + conf.OriginDBInstanceExternalId = rds.DBInstanceId + } + return rds.region.RecoveryDBInstanceFromBackup(conf.OriginDBInstanceExternalId, rds.DBInstanceId, conf.BackupId, conf.Databases) +} + +func (region *SRegion) RecoveryDBInstanceFromBackup(srcId, destId string, backupId string, databases map[string]string) error { + params := map[string]string{ + "RegionId": region.RegionId, + "DBInstanceId": srcId, + "TargetDBInstanceId": destId, + "BackupId": backupId, + "DbNames": jsonutils.Marshal(databases).String(), + } + _, err := region.rdsRequest("RecoveryDBInstance", params) + if err != nil { + return errors.Wrap(err, "rdsRequest.RecoveryDBInstance") + } + return nil +} + +func (rds *SDBInstance) GetProjectId() string { + return rds.ResourceGroupId +} + +func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { + return rds.region.CreateDBInstanceDatabae(rds.DBInstanceId, conf.CharacterSet, conf.Name, conf.Description) +} + +func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { + return rds.region.CreateDBInstanceAccount(rds.DBInstanceId, conf.Name, conf.Password, conf.Description) +} + +func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { + return rds.region.RenewInstance(rds.DBInstanceId, bc) +} + +func (rds *SDBInstance) SetAutoRenew(bc billing.SBillingCycle) error { + month := 1 + if bc.GetMonths() > 0 { + month = bc.GetMonths() + } + return rds.region.ModifyInstanceAutoRenewalAttribute(rds.DBInstanceId, month, bc.AutoRenew) +} + +func (region *SRegion) ModifyInstanceAutoRenewalAttribute(rdsId string, month int, autoRenew bool) error { + params := map[string]string{ + "RegionId": region.RegionId, + "DBInstanceId": rdsId, + "AutoRenew": "False", + "ClientToken": utils.GenRequestId(20), + } + if autoRenew { + params["AutoRenew"] = "True" + params["Duration"] = fmt.Sprintf("%d", month) + } + _, err := region.rdsRequest("ModifyInstanceAutoRenewalAttribute", params) + if err != nil { + return errors.Wrap(err, "ModifyInstanceAutoRenewalAttribute") + } + return nil +} + +func (region *SRegion) RenewDBInstance(instanceId string, bc billing.SBillingCycle) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "Period": fmt.Sprintf("%d", bc.GetMonths()), + "ClientToken": utils.GenRequestId(20), + } + _, err := region.rdsRequest("RenewInstance", params) + return err +} + +func (self *SDBInstance) GetTags() (map[string]string, error) { + _, tags, err := self.region.ListSysAndUserTags(ALIYUN_SERVICE_RDS, "INSTANCE", self.DBInstanceId) + if err != nil { + return nil, errors.Wrapf(err, "ListTags") + } + tagMaps := map[string]string{} + for k, v := range tags { + tagMaps[strings.ToLower(k)] = v + } + return tagMaps, nil +} + +func (self *SDBInstance) GetSysTags() map[string]string { + tags, _, err := self.region.ListSysAndUserTags(ALIYUN_SERVICE_RDS, "INSTANCE", self.DBInstanceId) + if err != nil { + return nil + } + tagMaps := map[string]string{} + for k, v := range tags { + tagMaps[strings.ToLower(k)] = v + } + return tagMaps +} + +func (rds *SDBInstance) SetTags(tags map[string]string, replace bool) error { + return rds.region.SetResourceTags(ALIYUN_SERVICE_RDS, "INSTANCE", rds.GetId(), tags, replace) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_account.go new file mode 100644 index 0000000000..4de9bfee9e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_account.go @@ -0,0 +1,178 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDatabasePrivileges struct { + DatabasePrivilege []SDatabasePrivilege +} + +type SDBInstanceAccount struct { + multicloud.SDBInstanceAccountBase + AliyunTags + instance *SDBInstance + + AccountDescription string + AccountName string + AccountStatus string + AccountType string + DBInstanceId string + DatabasePrivileges SDatabasePrivileges + PrivExceeded string +} + +func (account *SDBInstanceAccount) GetName() string { + return account.AccountName +} + +func (account *SDBInstanceAccount) Delete() error { + return account.instance.region.DeleteDBInstanceAccount(account.DBInstanceId, account.AccountName) +} + +func (account *SDBInstanceAccount) RevokePrivilege(database string) error { + return account.instance.region.RevokeDBInstancePrivilege(account.DBInstanceId, account.AccountName, database) +} + +func (region *SRegion) RevokeDBInstancePrivilege(instanceId, account, database string) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "AccountName": account, + "DBName": database, + } + _, err := region.rdsRequest("RevokeAccountPrivilege", params) + return err +} + +func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { + return account.instance.region.GrantDBInstancePrivilege(account.DBInstanceId, account.AccountName, database, privilege) +} + +func (region *SRegion) GrantDBInstancePrivilege(instanceId, account, database, privilege string) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "AccountName": account, + "DBName": database, + } + switch privilege { + case api.DATABASE_PRIVILEGE_R: + params["AccountPrivilege"] = "ReadOnly" + case api.DATABASE_PRIVILEGE_RW: + params["AccountPrivilege"] = "ReadWrite" + case api.DATABASE_PRIVILEGE_DDL: + params["AccountPrivilege"] = "DDLOnly" + case api.DATABASE_PRIVILEGE_DML: + params["AccountPrivilege"] = "DMLOnly" + case api.DATABASE_PRIVILEGE_OWNER: + params["AccountPrivilege"] = "DBOwner" + default: + return fmt.Errorf("Unknown privilege [%s]", privilege) + } + _, err := region.rdsRequest("GrantAccountPrivilege", params) + return err +} + +func (account *SDBInstanceAccount) ResetPassword(password string) error { + return account.instance.region.ResetDBInstanceAccountPassword(account.DBInstanceId, account.AccountName, password, account.AccountType) +} + +func (region *SRegion) ResetDBInstanceAccountPassword(instanceId, account, password, accountType string) error { + action := "ResetAccountPassword" + if accountType == "Super" { + action = "ResetAccount" + } + params := map[string]string{ + "DBInstanceId": instanceId, + "AccountName": account, + "AccountPassword": password, + } + _, err := region.rdsRequest(action, params) + return err +} + +func (account *SDBInstanceAccount) GetStatus() string { + switch account.AccountStatus { + case "Available": + return api.DBINSTANCE_USER_AVAILABLE + case "Unavailable": + return api.DBINSTANCE_USER_UNAVAILABLE + } + return account.AccountStatus +} + +func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { + privileves := []cloudprovider.ICloudDBInstanceAccountPrivilege{} + for i := 0; i < len(account.DatabasePrivileges.DatabasePrivilege); i++ { + account.DatabasePrivileges.DatabasePrivilege[i].account = account + privileves = append(privileves, &account.DatabasePrivileges.DatabasePrivilege[i]) + } + return privileves, nil +} + +func (region *SRegion) GetDBInstanceAccounts(instanceId string, offset int, limit int) ([]SDBInstanceAccount, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := map[string]string{ + "RegionId": region.RegionId, + "PageSize": fmt.Sprintf("%d", limit), + "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), + "DBInstanceId": instanceId, + } + body, err := region.rdsRequest("DescribeAccounts", params) + if err != nil { + return nil, 0, errors.Wrap(err, "DescribeAccounts") + } + accounts := []SDBInstanceAccount{} + err = body.Unmarshal(&accounts, "Accounts", "DBInstanceAccount") + if err != nil { + return nil, 0, errors.Wrap(err, "Unmarshal") + } + total, _ := body.Int("TotalRecordCount") + return accounts, int(total), nil +} + +func (region *SRegion) DeleteDBInstanceAccount(instanceId string, accountName string) error { + params := map[string]string{ + "RegionId": region.RegionId, + "DBInstanceId": instanceId, + "AccountName": accountName, + } + + _, err := region.rdsRequest("DeleteAccount", params) + return err +} + +func (region *SRegion) CreateDBInstanceAccount(instanceId string, name string, password string, desc string) error { + params := map[string]string{ + "RegionId": region.RegionId, + "DBInstanceId": instanceId, + "AccountName": name, + "AccountPassword": password, + "AccountDescription": desc, + } + + _, err := region.rdsRequest("CreateAccount", params) + return err + +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_backup.go new file mode 100644 index 0000000000..5bd7c18cf6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_backup.go @@ -0,0 +1,357 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceBackup struct { + multicloud.SDBInstanceBackupBase + AliyunTags + region *SRegion + + BackupDBNames string + BackupIntranetDownloadURL string + BackupDownloadURL string + BackupEndTime time.Time + BackupId string + BackupLocation string + BackupMethod string + BackupMode string + BackupScale string + BackupSize int + BackupStartTime time.Time + BackupStatus string + BackupType string + DBInstanceId string + HostInstanceID int + MetaStatus string + StoreStatus string +} + +func (backup *SDBInstanceBackup) GetId() string { + return backup.BackupId +} + +func (backup *SDBInstanceBackup) GetGlobalId() string { + return backup.BackupId +} + +func (backup *SDBInstanceBackup) GetName() string { + return backup.BackupId +} + +func (backup *SDBInstanceBackup) GetStartTime() time.Time { + return backup.BackupStartTime +} + +func (backup *SDBInstanceBackup) GetEndTime() time.Time { + return backup.BackupEndTime +} + +func (backup *SDBInstanceBackup) GetBackupMode() string { + switch backup.BackupMode { + case "Manual": + return api.BACKUP_MODE_MANUAL + default: + return api.BACKUP_MODE_AUTOMATED + } +} + +func (backup *SDBInstanceBackup) GetStatus() string { + switch backup.BackupStatus { + case "Success": + return api.DBINSTANCE_BACKUP_READY + case "Failed": + return api.DBINSTANCE_BACKUP_FAILED + default: + return api.DBINSTANCE_BACKUP_UNKNOWN + } +} + +func (backup *SDBInstanceBackup) GetBackupSizeMb() int { + return backup.BackupSize / 1024 / 1024 +} + +func (backup *SDBInstanceBackup) GetDBNames() string { + return backup.BackupDBNames +} + +func (backup *SDBInstanceBackup) GetEngine() string { + instance, _ := backup.region.GetDBInstanceDetail(backup.DBInstanceId) + if instance != nil { + return instance.Engine + } + return "" +} + +func (backup *SDBInstanceBackup) GetEngineVersion() string { + instance, _ := backup.region.GetDBInstanceDetail(backup.DBInstanceId) + if instance != nil { + return instance.EngineVersion + } + return "" +} + +func (backup *SDBInstanceBackup) GetDBInstanceId() string { + return backup.DBInstanceId +} + +func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string, offset int, limit int) ([]SDBInstanceBackup, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := map[string]string{ + "RegionId": region.RegionId, + "PageSize": fmt.Sprintf("%d", limit), + "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), + "DBInstanceId": instanceId, + } + if len(backupId) > 0 { + params["BackupId"] = backupId + } + body, err := region.rdsRequest("DescribeBackups", params) + if err != nil { + return nil, 0, errors.Wrap(err, "DescribeBackups") + } + backups := []SDBInstanceBackup{} + err = body.Unmarshal(&backups, "Items", "Backup") + if err != nil { + return nil, 0, errors.Wrap(err, "Unmarshal") + } + total, _ := body.Int("TotalRecordCount") + return backups, int(total), nil +} + +func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + dbinstnaces, err := region.GetIDBInstances() + if err != nil { + return nil, err + } + ibackups := []cloudprovider.ICloudDBInstanceBackup{} + for i := 0; i < len(dbinstnaces); i++ { + _dbinstance := dbinstnaces[i].(*SDBInstance) + _ibackup, err := _dbinstance.GetIDBInstanceBackups() + if err != nil { + return nil, errors.Wrapf(err, "_dbinstance(%v).GetIDBInstanceBackups", _dbinstance) + } + ibackups = append(ibackups, _ibackup...) + } + return ibackups, nil +} + +func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + backups := []SDBInstanceBackup{} + for { + parts, total, err := rds.region.GetDBInstanceBackups(rds.DBInstanceId, "", len(backups), 50) + if err != nil { + return nil, err + } + backups = append(backups, parts...) + if len(backups) >= total { + break + } + } + + ibackups := []cloudprovider.ICloudDBInstanceBackup{} + for i := 0; i < len(backups); i++ { + backups[i].region = rds.region + ibackups = append(ibackups, &backups[i]) + } + return ibackups, nil +} + +func (self *SRegion) CreateDBInstanceBackup(rdsId string, databases []string) (string, error) { + rds, err := self.GetDBInstanceDetail(rdsId) + if err != nil { + return "", errors.Wrapf(err, "GetDBInstanceDetail") + } + params := map[string]string{ + "DBInstanceId": rdsId, + } + switch rds.Engine { + case api.DBINSTANCE_TYPE_MYSQL: + if utils.IsInStringArray(rds.EngineVersion, []string{"5.7", "8.0"}) && ((utils.IsInStringArray(rds.GetStorageType(), []string{ + api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_ESSD, + api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD, + }) && rds.GetCategory() == api.ALIYUN_DBINSTANCE_CATEGORY_HA) || + (rds.GetStorageType() == api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD && + rds.GetCategory() == api.ALIYUN_DBINSTANCE_CATEGORY_BASIC)) { + params["BackupMethod"] = "Snapshot" + } else { + params["BackupMethod"] = "Physical" + if len(databases) > 0 { + params["BackupStrategy"] = "db" + params["DBName"] = strings.Join(databases, ",") + params["BackupMethod"] = "Logical" + } + } + case api.DBINSTANCE_TYPE_MARIADB: + params["BackupMethod"] = "Snapshot" + case api.DBINSTANCE_TYPE_SQLSERVER: + params["BackupMethod"] = "Physical" + case api.DBINSTANCE_TYPE_POSTGRESQL: + if rds.GetStorageType() == api.ALIYUN_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD { + params["BackupMethod"] = "Physical" + } else { + params["BackupMethod"] = "Snapshot" + } + case api.DBINSTANCE_TYPE_PPAS: + params["BackupMethod"] = "Physical" + } + body, err := self.rdsRequest("CreateBackup", params) + if err != nil { + return "", errors.Wrap(err, "CreateBackup") + } + jobId, err := body.GetString("BackupJobId") + if err != nil { + return "", errors.Wrap(err, "body.BackupJobId") + } + return self.waitBackupCreateComplete(rds.DBInstanceId, jobId) +} + +func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { + return rds.region.CreateDBInstanceBackup(rds.DBInstanceId, conf.Databases) +} + +func (backup *SDBInstanceBackup) Delete() error { + return backup.region.DeleteDBInstanceBackup(backup.DBInstanceId, backup.BackupId) +} + +func (region *SRegion) DeleteDBInstanceBackup(instanceId string, backupId string) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "BackupId": backupId, + } + _, err := region.rdsRequest("DeleteBackup", params) + return err +} + +type SDBInstanceBackupJob struct { + BackupProgressStatus string + Process string + JobMode string + TaskAction string + BackupStatus string + BackupJobId string + BackupId string +} + +type SDBInstanceBackupJobs struct { + BackupJob []SDBInstanceBackupJob +} + +func (region *SRegion) GetDBInstanceBackupJobs(instanceId, jobId string) (*SDBInstanceBackupJobs, error) { + params := map[string]string{ + "DBInstanceId": instanceId, + "ClientToken": utils.GenRequestId(20), + "BackupMode": "Manual", + } + if len(jobId) > 0 { + params["BackupJobId"] = jobId + } + body, err := region.rdsRequest("DescribeBackupTasks", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeBackupTasks") + } + + jobs := SDBInstanceBackupJobs{} + + err = body.Unmarshal(&jobs, "Items") + if err != nil { + return nil, errors.Wrapf(err, "body.Unmarshal(%s)", body) + } + + return &jobs, nil +} + +func (region *SRegion) waitBackupCreateComplete(instanceId, jobId string) (string, error) { + err := cloudprovider.Wait(time.Second*10, time.Minute*40, func() (bool, error) { + jobs, err := region.GetDBInstanceBackupJobs(instanceId, jobId) + if err != nil { + return false, errors.Wrapf(err, "region.GetDBInstanceBackupJobs(%s, %s)", instanceId, jobId) + } + if len(jobs.BackupJob) == 0 { + return true, nil + } + for _, job := range jobs.BackupJob { + log.Infof("instance %s backup job %s status: %s(%s)", instanceId, jobId, job.BackupStatus, job.Process) + if job.BackupStatus == "Finished" && job.BackupJobId == jobId { + return true, nil + } + if job.BackupStatus == "Failed" && job.BackupJobId == jobId { + return false, fmt.Errorf("instance %s backup job %s failed", instanceId, jobId) + } + } + return false, nil + }) + if err != nil { + return "", errors.Wrapf(err, "wait backup create job") + } + jobs, err := region.GetDBInstanceBackupJobs(instanceId, jobId) + if err != nil { + return "", errors.Wrapf(err, "region.GetDBInstanceBackupJobs(%s, %s)", instanceId, jobId) + } + for _, job := range jobs.BackupJob { + if job.BackupStatus == "Finished" && job.BackupJobId == jobId { + if len(job.BackupId) == 0 { + return "", fmt.Errorf("Missing backup id") + } + return job.BackupId, nil + } + } + return "", fmt.Errorf("failed to found backup job %s backupid", jobId) +} + +func (self *SDBInstanceBackup) GetBackupMethod() cloudprovider.TBackupMethod { + return cloudprovider.TBackupMethod(self.BackupMethod) +} + +func (self *SDBInstanceBackup) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + rdsId, err := self.region.CreateDBInstanceByBackup(self.BackupId, opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateDBInstanceByBackup") + } + return self.region.GetDBInstanceDetail(rdsId) +} + +func (self *SRegion) CreateDBInstanceByBackup(backupId string, opts *cloudprovider.SManagedDBInstanceCreateConfig) (string, error) { + params := map[string]string{ + "DBInstanceId": opts.RdsId, + "DBInstanceStorageType": opts.StorageType, + "PayType": "Postpaid", + "BackupId": backupId, + } + resp, err := self.rdsRequest("CloneDBInstance", params) + if err != nil { + return "", errors.Wrapf(err, "rdsRequest") + } + rdsId, err := resp.GetString("DBInstanceId") + if err != nil { + return "", fmt.Errorf("missing DBInstanceId after CloneDBInstance") + } + return rdsId, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_database.go new file mode 100644 index 0000000000..acf89e5ee1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_database.go @@ -0,0 +1,118 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceDatabase struct { + multicloud.SDBInstanceDatabaseBase + AliyunTags + instance *SDBInstance + + CharacterSetName string + DBDescription string + DBInstanceId string + DBName string + DBStatus string + Engine string +} + +func (database *SDBInstanceDatabase) GetId() string { + return database.DBName +} + +func (database *SDBInstanceDatabase) GetGlobalId() string { + return database.DBName +} + +func (database *SDBInstanceDatabase) GetName() string { + return database.DBName +} + +func (database *SDBInstanceDatabase) GetStatus() string { + switch database.DBStatus { + case "Creating": + return api.DBINSTANCE_DATABASE_CREATING + case "Running": + return api.DBINSTANCE_DATABASE_RUNNING + case "Deleting": + return api.DBINSTANCE_DATABASE_DELETING + } + return database.DBStatus +} + +func (database *SDBInstanceDatabase) GetCharacterSet() string { + return database.CharacterSetName +} + +func (database *SDBInstanceDatabase) Delete() error { + return database.instance.region.DeleteDBInstanceDatabase(database.DBInstanceId, database.DBName) +} + +func (region *SRegion) DeleteDBInstanceDatabase(instanceId string, dbName string) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "DBName": dbName, + } + + _, err := region.rdsRequest("DeleteDatabase", params) + return err +} + +func (region *SRegion) CreateDBInstanceDatabae(instanceId, characterSet, dbName, desc string) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "DBName": dbName, + "CharacterSetName": characterSet, + "DBDescription": desc, + } + + _, err := region.rdsRequest("CreateDatabase", params) + return err + +} + +func (region *SRegion) GetDBInstanceDatabases(instanceId, dbName string, offset int, limit int) ([]SDBInstanceDatabase, int, error) { + if limit > 500 || limit <= 0 { + limit = 500 + } + params := map[string]string{ + "RegionId": region.RegionId, + "PageSize": fmt.Sprintf("%d", limit), + "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), + "DBInstanceId": instanceId, + } + if len(dbName) > 0 { + params["DBName"] = dbName + } + body, err := region.rdsRequest("DescribeDatabases", params) + if err != nil { + return nil, 0, errors.Wrap(err, "DescribeDatabases") + } + databases := []SDBInstanceDatabase{} + err = body.Unmarshal(&databases, "Databases", "Database") + if err != nil { + return nil, 0, errors.Wrap(err, "Unmarshal") + } + total, _ := body.Int("TotalRecordCount") + return databases, int(total), nil +} diff --git a/pkg/multicloud/aliyun/dbinstance_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_parameter.go similarity index 100% rename from pkg/multicloud/aliyun/dbinstance_parameter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_parameter.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_privilege.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_privilege.go new file mode 100644 index 0000000000..0cbb673583 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dbinstance_privilege.go @@ -0,0 +1,55 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +type SDatabasePrivilege struct { + account *SDBInstanceAccount + + AccountPrivilege string + AccountPrivilegeDetail string + DBName string +} + +func (privilege *SDatabasePrivilege) GetGlobalId() string { + return fmt.Sprintf("%s/%s", privilege.account.GetName(), privilege.DBName) +} + +func (privilege *SDatabasePrivilege) GetPrivilege() string { + switch privilege.AccountPrivilege { + case "ReadWrite": + return api.DATABASE_PRIVILEGE_RW + case "ReadOnly": + return api.DATABASE_PRIVILEGE_R + case "DDLOnly": + return api.DATABASE_PRIVILEGE_DDL + case "DMLOnly": + return api.DATABASE_PRIVILEGE_DML + case "DBOwner": + return api.DATABASE_PRIVILEGE_OWNER + case "Custom": + return api.DBINSTANCE_DATABASE_CREATING + } + return privilege.AccountPrivilege +} + +func (privilege *SDatabasePrivilege) GetDBName() string { + return privilege.DBName +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/disk.go new file mode 100644 index 0000000000..e417e634ef --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/disk.go @@ -0,0 +1,427 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SMountInstances struct { + MountInstance []string +} + +type SDisk struct { + storage *SStorage + multicloud.SDisk + AliyunTags + + IOPS int + AttachedTime time.Time + AutoSnapshotPolicyId string + Category string + PerformanceLevel string + CreationTime time.Time + DeleteAutoSnapshot bool + DeleteWithInstance bool + Description string + DetachedTime time.Time + Device string + DiskChargeType TChargeType + DiskId string + DiskName string + EnableAutoSnapshot bool + EnableAutomatedSnapshotPolicy bool + Encrypted bool + ExpiredTime time.Time + ImageId string + InstanceId string + MountInstances SMountInstances + OperationLocks SOperationLocks + Portable bool + ProductCode string + RegionId string + ResourceGroupId string + Size int + SourceSnapshotId string + Status string + Type string + ZoneId string +} + +func (self *SDisk) GetIops() int { + return self.IOPS +} + +func (self *SRegion) GetDisks(instanceId string, zoneId string, category string, diskIds []string, offset int, limit int) ([]SDisk, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if len(instanceId) > 0 { + params["InstanceId"] = instanceId + } + if len(zoneId) > 0 { + params["ZoneId"] = zoneId + } + if len(category) > 0 { + params["Category"] = category + } + if diskIds != nil && len(diskIds) > 0 { + params["DiskIds"] = jsonutils.Marshal(diskIds).String() + } + + body, err := self.ecsRequest("DescribeDisks", params) + if err != nil { + log.Errorf("GetDisks fail %s", err) + return nil, 0, err + } + + disks := make([]SDisk, 0) + err = body.Unmarshal(&disks, "Disks", "Disk") + if err != nil { + log.Errorf("Unmarshal disk details fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return disks, int(total), nil +} + +func (self *SDisk) GetId() string { + return self.DiskId +} + +func (self *SDisk) Delete(ctx context.Context) error { + _, err := self.storage.zone.region.getDisk(self.DiskId) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + // 未找到disk, 说明disk已经被删除了. 避免回收站中disk-delete循环删除失败 + return nil + } + log.Errorf("Failed to find disk %s when delete: %s", self.DiskId, err) + return err + } + + for { + err := self.storage.zone.region.DeleteDisk(self.DiskId) + if err != nil { + if isError(err, "IncorrectDiskStatus") { + log.Infof("The disk is initializing, try later ...") + time.Sleep(10 * time.Second) + } else { + log.Errorf("DeleteDisk fail: %s", err) + return err + } + } else { + break + } + } + return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes +} + +func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { + return self.storage.zone.region.resizeDisk(self.DiskId, sizeMb) +} + +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) IsEmulated() bool { + return false +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +func (self *SDisk) GetStatus() string { + // In_use Available Attaching Detaching Creating ReIniting All + switch self.Status { + case "Creating", "ReIniting": + return api.DISK_ALLOCATING + default: + return api.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) ResizeDisk(newSize int64) error { + // newSize 单位为 GB. 范围在20 ~2000. 只能往大调。不能调小 + // https://help.aliyun.com/document_detail/25522.html?spm=a2c4g.11174283.6.897.aHwqkS + return self.storage.zone.region.resizeDisk(self.DiskId, newSize) +} + +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 { + switch self.Type { + case "system": + return api.DISK_TYPE_SYS + case "data": + return api.DISK_TYPE_DATA + default: + return api.DISK_TYPE_DATA + } +} + +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 *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, desc string, projectId string) (string, error) { + params := make(map[string]string) + params["ZoneId"] = zoneId + params["DiskName"] = name + if len(desc) > 0 { + params["Description"] = desc + } + params["Encrypted"] = "false" + params["DiskCategory"] = category + if category == api.STORAGE_CLOUD_ESSD_PL2 { + params["DiskCategory"] = api.STORAGE_CLOUD_ESSD + params["PerformanceLevel"] = "PL2" + } + if category == api.STORAGE_CLOUD_ESSD_PL3 { + params["DiskCategory"] = api.STORAGE_CLOUD_ESSD + params["PerformanceLevel"] = "PL3" + } + + if len(projectId) > 0 { + params["ResourceGroupId"] = projectId + } + params["Size"] = fmt.Sprintf("%d", sizeGb) + params["ClientToken"] = utils.GenRequestId(20) + + body, err := self.ecsRequest("CreateDisk", params) + if err != nil { + return "", err + } + return body.GetString("DiskId") +} + +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 { + params := make(map[string]string) + params["DiskId"] = diskId + + _, err := self.ecsRequest("DeleteDisk", params) + return err +} + +func (self *SRegion) resizeDisk(diskId string, sizeMb int64) error { + sizeGb := sizeMb / 1024 + params := make(map[string]string) + params["DiskId"] = diskId + params["NewSize"] = fmt.Sprintf("%d", sizeGb) + + _, err := self.ecsRequest("ResizeDisk", params) + if err != nil { + log.Errorf("resizing disk (%s) to %d GiB failed: %s", diskId, sizeGb, err) + return err + } + + return nil +} + +func (self *SRegion) resetDisk(diskId, snapshotId string) error { + params := make(map[string]string) + params["DiskId"] = diskId + params["SnapshotId"] = snapshotId + _, err := self.ecsRequest("ResetDisk", params) + if err != nil { + log.Errorf("ResetDisk %s to snapshot %s fail %s", diskId, snapshotId, err) + return err + } + + return nil +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { + snapshotId, err := self.storage.zone.region.CreateSnapshot(self.DiskId, name, desc) + if err != nil { + return nil, errors.Wrapf(err, "CreateSnapshot") + } + snapshot, err := self.storage.zone.region.GetISnapshotById(snapshotId) + if err != nil { + return nil, errors.Wrapf(err, "getSnapshot(%s)", snapshotId) + } + err = cloudprovider.WaitStatus(snapshot, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second) + if err != nil { + return nil, errors.Wrapf(err, "cloudprovider.WaitStatus") + } + return snapshot, nil +} + +func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["DiskId"] = diskId + params["SnapshotName"] = name + params["Description"] = desc + + if body, err := self.ecsRequest("CreateSnapshot", params); err != nil { + log.Errorf("CreateSnapshot fail %s", err) + return "", err + } else { + return body.GetString("SnapshotId") + } +} + +func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + return self.storage.zone.region.GetISnapshotById(snapshotId) +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots := make([]SSnapshot, 0) + for { + parts, total, err := self.storage.zone.region.GetSnapshots("", self.DiskId, "", []string{}, 0, 20) + if err != nil { + return nil, errors.Wrapf(err, "GetSnapshots(%s)", self.DiskId) + } + snapshots = append(snapshots, parts...) + if len(snapshots) >= total { + break + } + } + isnapshots := []cloudprovider.ICloudSnapshot{} + for i := 0; i < len(snapshots); i++ { + snapshots[i].region = self.storage.zone.region + isnapshots = append(isnapshots, &snapshots[i]) + } + return isnapshots, nil +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", self.storage.zone.region.resetDisk(self.DiskId, snapshotId) +} + +func (self *SDisk) GetBillingType() string { + return convertChargeType(self.DiskChargeType) +} + +func (self *SDisk) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { + if len(self.AutoSnapshotPolicyId) == 0 { + return []string{}, nil + } + return []string{self.AutoSnapshotPolicyId}, nil +} + +func (self *SDisk) GetExpiredAt() time.Time { + return convertExpiredAt(self.ExpiredTime) +} + +func (self *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + err := self.storage.zone.region.rebuildDisk(self.DiskId) + if err != nil { + if isError(err, "IncorrectInstanceStatus") { + return nil + } + log.Errorf("rebuild disk fail %s", err) + return err + } + return nil +} + +func (self *SRegion) rebuildDisk(diskId string) error { + params := make(map[string]string) + params["DiskId"] = diskId + _, err := self.ecsRequest("ReInitDisk", params) + if err != nil { + log.Errorf("ReInitDisk %s fail %s", diskId, err) + return err + } + return nil +} + +func (self *SDisk) GetProjectId() string { + return self.ResourceGroupId +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dns_domain.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dns_domain.go new file mode 100644 index 0000000000..51633b30d7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dns_domain.go @@ -0,0 +1,437 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "strconv" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDomain struct { + multicloud.SResourceBase + AliyunTags + client *SAliyunClient + ttlMinValue int64 + PunyCode string `json:"PunyCode"` + VersionCode string `json:"VersionCode"` + InstanceID string `json:"InstanceId"` + AliDomain bool `json:"AliDomain"` + DomainName string `json:"DomainName"` + DomainID string `json:"DomainId"` + DNSServers DNSServers `json:"DnsServers"` + GroupID string `json:"GroupId"` +} + +type SDomains struct { + PageNumber int `json:"PageNumber"` + TotalCount int `json:"TotalCount"` + PageSize int `json:"PageSize"` + // RequestID string `json:"RequestId"` + Domains sDomains `json:"Domains"` +} + +type DNSServers struct { + DNSServer []string `json:"DnsServer"` +} + +type sDomains struct { + Domain []SDomain `json:"Domain"` +} + +// https://help.aliyun.com/document_detail/29758.html?spm=a2c4g.11186623.6.653.2ad93b59euq4oF +type SDNSProduct struct { + client *SAliyunClient + InstanceID string `json:"InstanceId"` + VersionCode string `json:"VersionCode"` + VersionName string `json:"VersionName"` + StartTime int64 `json:"StartTime"` + EndTime int64 `json:"EndTime"` + Domain string `json:"Domain"` + BindCount int64 `json:"BindCount"` + BindUsedCount int64 `json:"BindUsedCount"` + TTLMinValue int64 `json:"TTLMinValue"` + SubDomainLevel int64 `json:"SubDomainLevel"` + DNSSLBCount int64 `json:"DnsSLBCount"` + URLForwardCount int64 `json:"URLForwardCount"` + DDosDefendFlow int64 `json:"DDosDefendFlow"` + DDosDefendQuery int64 `json:"DDosDefendQuery"` + OverseaDDosDefendFlow int64 `json:"OverseaDDosDefendFlow"` + SearchEngineLines string `json:"SearchEngineLines"` + ISPLines string `json:"ISPLines"` + ISPRegionLines string `json:"ISPRegionLines"` + OverseaLine string `json:"OverseaLine"` +} + +type sDNSProducts struct { + DNSProduct []SDNSProduct `json:"DnsProduct"` +} + +type SDNSProducts struct { + // RequestID string `json:"RequestId"` + TotalCount int `json:"TotalCount"` + PageNumber int `json:"PageNumber"` + PageSize int `json:"PageSize"` + DNSProducts sDNSProducts `json:"DnsProducts"` +} + +// https://help.aliyun.com/document_detail/29758.html?spm=a2c4g.11186623.6.653.4b6d6970WphX2t +func (client *SAliyunClient) DescribeDnsProductInstances(pageNumber int, pageSize int) (SDNSProducts, error) { + sproducts := SDNSProducts{} + params := map[string]string{} + params["Action"] = "DescribeDnsProductInstances" + params["PageNumber"] = strconv.Itoa(pageNumber) + params["PageSize"] = strconv.Itoa(pageSize) + resp, err := client.alidnsRequest("DescribeDnsProductInstances", params) + if err != nil { + return sproducts, errors.Wrap(err, "DescribeDnsProductInstances") + } + err = resp.Unmarshal(&sproducts, "DnsProducts") + if err != nil { + return sproducts, errors.Wrap(err, "resp.Unmarshal") + } + return sproducts, nil +} + +func (client *SAliyunClient) GetAllDnsProductInstances() ([]SDNSProduct, error) { + pageNumber := 0 + sproducts := []SDNSProduct{} + for { + pageNumber++ + products, err := client.DescribeDnsProductInstances(pageNumber, 20) + if err != nil { + return nil, errors.Wrapf(err, "client.DescribeDnsProductInstances(%d, 20)", pageNumber) + } + sproducts = append(sproducts, products.DNSProducts.DNSProduct...) + if len(sproducts) >= products.TotalCount { + break + } + } + for i := 0; i < len(sproducts); i++ { + sproducts[i].client = client + } + return sproducts, nil +} + +// https://help.aliyun.com/document_detail/29751.html?spm=a2c4g.11186623.6.638.55563230d00kzJ +func (client *SAliyunClient) DescribeDomains(pageNumber int, pageSize int) (SDomains, error) { + sdomains := SDomains{} + params := map[string]string{} + params["Action"] = "DescribeDomains" + params["PageNumber"] = strconv.Itoa(pageNumber) + params["PageSize"] = strconv.Itoa(pageSize) + resp, err := client.alidnsRequest("DescribeDomains", params) + if err != nil { + return sdomains, errors.Wrap(err, "DescribeDomains") + } + err = resp.Unmarshal(&sdomains) + if err != nil { + return sdomains, errors.Wrap(err, "resp.Unmarshal") + } + return sdomains, nil +} + +func (client *SAliyunClient) GetAllDomains() ([]SDomain, error) { + pageNumber := 0 + sdomains := []SDomain{} + for { + pageNumber += 1 + domains, err := client.DescribeDomains(pageNumber, 20) + if err != nil { + return nil, errors.Wrapf(err, "client.DescribeDomains(%d, 20)", pageNumber) + } + sdomains = append(sdomains, domains.Domains.Domain...) + if len(sdomains) >= domains.TotalCount { + break + } + } + for i := 0; i < len(sdomains); i++ { + sdomains[i].client = client + } + return sdomains, nil +} + +func (client *SAliyunClient) GetPublicICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { + izones := []cloudprovider.ICloudDnsZone{} + sdomains, err := client.GetAllDomains() + if err != nil { + return nil, errors.Wrap(err, "client.GetAllDomains()") + } + for i := 0; i < len(sdomains); i++ { + izones = append(izones, &sdomains[i]) + } + return izones, nil +} + +func (client *SAliyunClient) DescribeDomainInfo(domainName string) (*SDomain, error) { + sdomain := &SDomain{client: client} + params := map[string]string{} + params["Action"] = "DescribeDomainInfo" + params["DomainName"] = domainName + resp, err := client.alidnsRequest("DescribeDomainInfo", params) + if err != nil { + return sdomain, errors.Wrap(err, "DescribeDomainInfo") + } + err = resp.Unmarshal(sdomain) + if err != nil { + return sdomain, errors.Wrap(err, "resp.Unmarshal") + } + return sdomain, nil +} + +func (client *SAliyunClient) GetPublicICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { + izones, err := client.GetPublicICloudDnsZones() + if err != nil { + return nil, errors.Wrapf(err, "client.DescribeDomainInfo(%s)", id) + } + for i := 0; i < len(izones); i++ { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (client *SAliyunClient) AddDomain(domainName string) (*SDomain, error) { + sdomain := &SDomain{client: client} + params := map[string]string{} + params["Action"] = "AddDomain" + params["DomainName"] = domainName + resp, err := client.alidnsRequest("AddDomain", params) + if err != nil { + return sdomain, errors.Wrap(err, "AddDomain") + } + err = resp.Unmarshal(sdomain) + if err != nil { + return sdomain, errors.Wrapf(err, "%s:resp.Unmarshal()", resp) + } + return sdomain, nil +} + +func (client *SAliyunClient) CreatePublicICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { + sdomain, err := client.AddDomain(opts.Name) + if err != nil { + return nil, errors.Wrapf(err, "client.AddDomain(%s)", opts.Name) + } + return sdomain, nil +} + +func (client *SAliyunClient) DeleteDomain(domainName string) error { + params := map[string]string{} + params["Action"] = "DeleteDomain" + params["DomainName"] = domainName + _, err := client.alidnsRequest("DeleteDomain", params) + if err != nil { + return errors.Wrap(err, "DeleteDomain") + } + return nil +} + +func (self *SDomain) GetId() string { + return self.DomainID +} + +func (self *SDomain) GetName() string { + if len(self.PunyCode) > 0 { + return self.PunyCode + } + return self.DomainName +} + +func (self *SDomain) GetGlobalId() string { + return self.GetId() +} + +func (self *SDomain) GetStatus() string { + return api.DNS_ZONE_STATUS_AVAILABLE +} + +func (self *SDomain) Refresh() error { + sdomain, err := self.client.DescribeDomainInfo(self.DomainName) + if err != nil { + return errors.Wrapf(err, "self.client.DescribeDomainInfo(%s)", self.DomainName) + } + return jsonutils.Update(self, sdomain) +} + +func (self *SDomain) GetZoneType() cloudprovider.TDnsZoneType { + return cloudprovider.PublicZone +} +func (self *SDomain) GetOptions() *jsonutils.JSONDict { + return nil +} + +func (self *SDomain) GetICloudVpcIds() ([]string, error) { + return nil, nil +} +func (self *SDomain) AddVpc(vpc *cloudprovider.SPrivateZoneVpc) error { + return cloudprovider.ErrNotSupported +} +func (self *SDomain) RemoveVpc(vpc *cloudprovider.SPrivateZoneVpc) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDomain) GetIDnsRecordSets() ([]cloudprovider.ICloudDnsRecordSet, error) { + irecords := []cloudprovider.ICloudDnsRecordSet{} + records, err := self.client.GetAllDomainRecords(self.DomainName) + if err != nil { + return nil, errors.Wrapf(err, "self.client.GetAllDomainRecords(%s)", self.DomainName) + } + for i := 0; i < len(records); i++ { + irecords = append(irecords, &records[i]) + } + return irecords, nil +} + +func (self *SDomain) SyncDnsRecordSets(common, add, del, update []cloudprovider.DnsRecordSet) error { + for i := 0; i < len(common); i++ { + if len(common[i].Desc) > 0 { + err := self.client.UpdateDomainRecordRemark(common[i].ExternalId, common[i].Desc) + if err != nil { + return errors.Wrapf(err, "UpdateDomainRecordRemark") + } + } + } + for i := 0; i < len(del); i++ { + err := self.client.DeleteDomainRecord(del[i].ExternalId) + if err != nil { + return errors.Wrapf(err, "self.client.DeleteDomainRecord(%s)", del[i].ExternalId) + } + } + + for i := 0; i < len(add); i++ { + recordId, err := self.client.AddDomainRecord(self.DomainName, add[i]) + if err != nil { + return errors.Wrapf(err, "self.client.AddDomainRecord(%s,%s)", self.DomainName, jsonutils.Marshal(add[i]).String()) + } + if !add[i].Enabled { + // Enable: 启用解析 Disable: 暂停解析 + err = self.client.SetDomainRecordStatus(recordId, "Disable") + if err != nil { + return errors.Wrapf(err, "self.client.SetDomainRecordStatus(%s,%t)", recordId, add[i].Enabled) + } + } + if len(add[i].Desc) > 0 { + err = self.client.UpdateDomainRecordRemark(recordId, add[i].Desc) + if err != nil { + return errors.Wrapf(err, "UpdateDomainRecordRemark") + } + } + } + + for i := 0; i < len(update); i++ { + // Enable: 启用解析 Disable: 暂停解析 + status := "Enable" + if !update[i].Enabled { + status = "Disable" + } + err := self.client.SetDomainRecordStatus(update[i].ExternalId, status) + if err != nil { + return errors.Wrapf(err, "self.client.SetDomainRecordStatus(%s,%t)", update[i].ExternalId, update[i].Enabled) + } + domainRecord, err := self.client.DescribeDomainRecordInfo(update[i].ExternalId) + if err != nil { + return errors.Wrapf(err, "self.client.DescribeDomainRecordInfo(%s)", update[i].ExternalId) + } + if !domainRecord.match(update[i]) { + err = self.client.UpdateDomainRecord(update[i]) + if err != nil { + return errors.Wrapf(err, "self.client.UpdateDomainRecord(%s)", jsonutils.Marshal(update[i]).String()) + } + } + if len(update[i].Desc) > 0 { + err = self.client.UpdateDomainRecordRemark(update[i].ExternalId, update[i].Desc) + if err != nil { + return errors.Wrapf(err, "UpdateDomainRecordRemark") + } + } + } + return nil +} + +func (self *SDomain) Delete() error { + return self.client.DeleteDomain(self.DomainName) +} + +func TDnsProductType(productName string) cloudprovider.TDnsProductType { + switch productName { + case "企业旗舰版": + return cloudprovider.DnsProductEnterpriseUltimate + case "企业标准版": + return cloudprovider.DnsProductEnterpriseStandard + case "个人版": + return cloudprovider.DnsProductPersonalProfessional + default: + return cloudprovider.DnsProductFree + } +} + +func (self *SDomain) GetDnsProductType() cloudprovider.TDnsProductType { + sproducts, err := self.client.GetAllDnsProductInstances() + if err != nil { + log.Errorf("self.client.GetAllDnsProductInstances():%s", err) + return cloudprovider.DnsProductFree + } + // https://help.aliyun.com/document_detail/29806.html?spm=a2c4g.11186623.4.1.67728197c8SCN9 + // 免费版,最低600 + self.ttlMinValue = 600 + for i := 0; i < len(sproducts); i++ { + if sproducts[i].Domain == self.DomainName { + return TDnsProductType(sproducts[i].VersionName) + } + } + return cloudprovider.DnsProductFree +} + +func (self *SDomain) fetchTTLMinValue() (int64, error) { + if self.ttlMinValue != 0 { + return self.ttlMinValue, nil + } + sproducts, err := self.client.GetAllDnsProductInstances() + if err != nil { + return 0, errors.Wrap(err, "self.client.GetAllDnsProductInstances()") + } + // https://help.aliyun.com/document_detail/29806.html?spm=a2c4g.11186623.4.1.67728197c8SCN9 + // 免费版,最低600 + self.ttlMinValue = 600 + for i := 0; i < len(sproducts); i++ { + if sproducts[i].Domain == self.DomainName { + self.ttlMinValue = sproducts[i].TTLMinValue + return self.ttlMinValue, nil + } + } + return self.ttlMinValue, nil +} + +func (self *SDomain) GetProperlyTTL(ttl int64) int64 { + ttlMin, err := self.fetchTTLMinValue() + if err != nil { + log.Errorf("self.fetchTTLMinValue():%s", err) + ttlMin = 600 + } + if ttl <= ttlMin { + return ttlMin + } + if ttl > 86400 { + return 86400 + } + return ttl +} diff --git a/pkg/multicloud/aliyun/dns_domain_record.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dns_domain_record.go similarity index 99% rename from pkg/multicloud/aliyun/dns_domain_record.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dns_domain_record.go index d51e34ecac..8c979ae08c 100644 --- a/pkg/multicloud/aliyun/dns_domain_record.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/dns_domain_record.go @@ -20,8 +20,8 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SDomainRecords struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/doc.go new file mode 100644 index 0000000000..c3bac09836 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 aliyun // import "yunion.io/x/cloudmux/pkg/multicloud/aliyun" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/eip.go new file mode 100644 index 0000000000..8d5ad3ecd6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/eip.go @@ -0,0 +1,395 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type TInternetChargeType string + +const ( + InternetChargeByTraffic = TInternetChargeType("PayByTraffic") + InternetChargeByBandwidth = TInternetChargeType("PayByBandwidth") +) + +const ( + EIP_STATUS_ASSOCIATING = "Associating" + EIP_STATUS_UNASSOCIATING = "Unassociating" + EIP_STATUS_INUSE = "InUse" + EIP_STATUS_AVAILABLE = "Available" + + EIP_OPERATION_LOCK_FINANCIAL = "financial" + EIP_OPERATION_LOCK_SECURITY = "security" + + EIP_INSTANCE_TYPE_ECS = "EcsInstance" // (默认值):VPC类型的ECS实例 + EIP_INTANNCE_TYPE_SLB = "SlbInstance" // :VPC类型的SLB实例 + EIP_INSTANCE_TYPE_NAT = "Nat" // :NAT网关 + EIP_INSTANCE_TYPE_HAVIP = "HaVip" // :HAVIP +) + +/* +{ + "AllocationId":"eip-2zeddtan63ou44dtyt9s3", + "AllocationTime":"2019-02-23T06:48:36Z", + "Bandwidth":"100", + "ChargeType":"PostPaid", + "ExpiredTime":"", + "InstanceId":"", + "InstanceType":"", + "InternetChargeType":"PayByTraffic", + "IpAddress":"39.105.131.32", + "OperationLocks":{"LockReason":[]}, + "RegionId":"cn-beijing", + "Status":"Available" +} +*/ + +type SEipAddress struct { + region *SRegion + multicloud.SEipBase + AliyunTags + + Name string + AllocationId string + + InternetChargeType TInternetChargeType + + IpAddress string + Status string + + InstanceType string + InstanceId string + Bandwidth int /* Mbps */ + + BusinessStatus string + AllocationTime time.Time + DeletionProtection bool + Descritpion string + ISP string + Mode string + Netmode string + + OperationLocks string + + ChargeType TChargeType + ExpiredTime time.Time + ResourceGroupId string +} + +func (self *SEipAddress) GetId() string { + return self.AllocationId +} + +func (self *SEipAddress) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.IpAddress +} + +func (self *SEipAddress) GetGlobalId() string { + return self.AllocationId +} + +func (self *SEipAddress) GetStatus() string { + switch self.Status { + case EIP_STATUS_AVAILABLE, EIP_STATUS_INUSE: + return api.EIP_STATUS_READY + case EIP_STATUS_ASSOCIATING: + return api.EIP_STATUS_ASSOCIATE + case EIP_STATUS_UNASSOCIATING: + return api.EIP_STATUS_DISSOCIATE + default: + return api.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 { + // fixed Public IP + return true + } else { + return false + } +} + +func (self *SEipAddress) GetIpAddr() string { + return self.IpAddress +} + +func (self *SEipAddress) GetMode() string { + if self.InstanceId == self.AllocationId { + return api.EIP_MODE_INSTANCE_PUBLICIP + } else { + return api.EIP_MODE_STANDALONE_EIP + } +} + +func (self *SEipAddress) GetAssociationType() string { + switch self.InstanceType { + case EIP_INSTANCE_TYPE_ECS, "NetworkInterface": + return api.EIP_ASSOCIATE_TYPE_SERVER + case EIP_INSTANCE_TYPE_NAT: + return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY + case EIP_INTANNCE_TYPE_SLB: + return api.EIP_ASSOCIATE_TYPE_LOADBALANCER + default: + return self.InstanceType + } +} + +func (self *SEipAddress) GetAssociationExternalId() string { + return self.InstanceId +} + +func (self *SEipAddress) GetBillingType() string { + return convertChargeType(self.ChargeType) +} + +func (self *SEipAddress) GetCreatedAt() time.Time { + return self.AllocationTime +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return convertExpiredAt(self.ExpiredTime) +} + +func (self *SEipAddress) Delete() error { + return self.region.DeallocateEIP(self.AllocationId) +} + +func (self *SEipAddress) GetBandwidth() int { + return self.Bandwidth +} + +func (self *SEipAddress) GetINetworkId() string { + return "" +} + +func (self *SEipAddress) GetInternetChargeType() string { + switch self.InternetChargeType { + case InternetChargeByTraffic: + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + case InternetChargeByBandwidth: + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH + default: + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + } +} + +func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { + err := cloudprovider.Wait(20*time.Second, 60*time.Second, func() (bool, error) { + err := self.region.AssociateEip(self.AllocationId, conf.InstanceId) + if err != nil { + if isError(err, "IncorrectInstanceStatus") { + return false, nil + } + return false, errors.Wrap(err, "region.AssociateEip") + } + return true, nil + }) + err = cloudprovider.WaitStatus(self, api.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, api.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 (region *SRegion) GetEips(eipId string, associatedId, addr string, offset int, limit int) ([]SEipAddress, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + if len(addr) > 0 { + params["EipAddress"] = addr + } + + if len(eipId) > 0 { + params["AllocationId"] = eipId + } + + if len(associatedId) > 0 { + params["AssociatedInstanceId"] = associatedId + for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "ngw-": "Nat", "lb-": "SlbInstance"} { + if strings.HasPrefix(associatedId, prefix) { + params["AssociatedInstanceType"] = instanceType + } + } + } + + body, err := region.vpcRequest("DescribeEipAddresses", params) + if err != nil { + log.Errorf("DescribeEipAddresses fail %s", err) + return nil, 0, err + } + + eips := make([]SEipAddress, 0) + err = body.Unmarshal(&eips, "EipAddresses", "EipAddress") + if err != nil { + log.Errorf("Unmarshal EipAddress details fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + for i := 0; i < len(eips); i += 1 { + eips[i].region = region + } + return eips, int(total), nil +} + +func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { + eips, total, err := region.GetEips(eipId, "", "", 0, 1) + if err != nil { + return nil, err + } + if total != 1 { + return nil, cloudprovider.ErrNotFound + } + return &eips[0], nil +} + +func (region *SRegion) AllocateEIP(name string, bwMbps int, chargeType TInternetChargeType, projectId string) (*SEipAddress, error) { + params := make(map[string]string) + + if len(name) > 0 { + params["Name"] = name + } + params["Bandwidth"] = fmt.Sprintf("%d", bwMbps) + params["InternetChargeType"] = string(chargeType) + params["InstanceChargeType"] = "PostPaid" + params["ClientToken"] = utils.GenRequestId(20) + if len(projectId) > 0 { + params["ResourceGroupId"] = projectId + } + + body, err := region.vpcRequest("AllocateEipAddress", params) + if err != nil { + log.Errorf("AllocateEipAddress fail %s", err) + return nil, err + } + + eipId, err := body.GetString("AllocationId") + if err != nil { + log.Errorf("fail to get AllocationId after EIP allocation??? %s", err) + return nil, err + } + + return region.GetEip(eipId) +} + +func (region *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + var ctype TInternetChargeType + switch opts.ChargeType { + case api.EIP_CHARGE_TYPE_BY_TRAFFIC: + ctype = InternetChargeByTraffic + case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: + ctype = InternetChargeByBandwidth + } + return region.AllocateEIP(opts.Name, opts.BandwidthMbps, ctype, opts.ProjectId) +} + +func (region *SRegion) DeallocateEIP(eipId string) error { + params := make(map[string]string) + params["AllocationId"] = eipId + + _, err := region.vpcRequest("ReleaseEipAddress", params) + if err != nil { + log.Errorf("ReleaseEipAddress fail %s", err) + } + return err +} + +func (region *SRegion) AssociateEip(eipId string, instanceId string) error { + params := make(map[string]string) + params["AllocationId"] = eipId + params["InstanceId"] = instanceId + for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "lb-": "SlbInstance", "ngw-": "Nat"} { + if strings.HasPrefix(instanceId, prefix) { + params["InstanceType"] = instanceType + } + } + + _, err := region.vpcRequest("AssociateEipAddress", params) + return errors.Wrapf(err, "AssociateEipAddress") +} + +func (region *SRegion) DissociateEip(eipId string, instanceId string) error { + params := make(map[string]string) + params["AllocationId"] = eipId + params["InstanceId"] = instanceId + for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "lb-": "SlbInstance", "ngw-": "Nat"} { + if strings.HasPrefix(instanceId, prefix) { + params["InstanceType"] = instanceType + } + } + + _, err := region.vpcRequest("UnassociateEipAddress", params) + if err != nil { + log.Errorf("UnassociateEipAddress fail %s", err) + } + return err +} + +func (region *SRegion) UpdateEipBandwidth(eipId string, bw int) error { + params := make(map[string]string) + params["AllocationId"] = eipId + params["Bandwidth"] = fmt.Sprintf("%d", bw) + + _, err := region.vpcRequest("ModifyEipAddressAttribute", params) + if err != nil { + log.Errorf("ModifyEipAddressAttribute fail %s", err) + } + return err +} + +func (self *SEipAddress) GetProjectId() string { + return self.ResourceGroupId +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elastic_search.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elastic_search.go new file mode 100644 index 0000000000..8ba4f04edd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elastic_search.go @@ -0,0 +1,373 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElasticSearch struct { + multicloud.SVirtualResourceBase + multicloud.SBillingBase + region *SRegion + + Tags []struct { + TagKey string + TagValue string + } + AdvancedDedicateMaster bool + AdvancedSetting struct { + gcName string + } + AliwsDicts []struct { + FileSize int + Name string + SourceType string + Type string + } + ClientNodeConfiguration struct { + Amount int + Disk int + DiskType string + Spec string + } + InstanceCategory string + CreatedAt time.Time + DedicateMaster bool + Description string + DictList []struct { + FileSize int + Name string + SourceType string + Type string + } + Domain string + ElasticDataNodeConfiguration struct { + Amount int + Disk int + DiskType string + Spec string + } + EnableKibanaPrivateNetwork bool + EnableKibanaPublicNetwork bool + EnablePublic bool + EsConfig map[string]string + EsIPBlacklist []string + EsIPWhitelist []string + EsVersion string + ExtendConfigs []struct { + ConfigType string + Value string + MaintainEndTime string + AliVersion string + } + HaveClientNode bool + HaveKibana bool + InstanceId string + KibanaConfiguration struct { + Amount int + Spec string + } + KibanaDomain string + KibanaIPWhitelist []string + KibanaPort int + KibanaPrivateIPWhitelist []string + MasterConfiguration struct { + Amount int + Disk int + DiskType string + Spec string + } + NetworkConfig struct { + Type string + VpcId string + VsArea string + VswitchId string + } + NodeAmount int + NodeSpec struct { + Disk int + DiskEncryption bool + DiskType string + Spec string + } + PaymentType string + Port int + PrivateNetworkIpWhiteList []string + Protocol string + PublicDomain string + PublicIpWhitelist []string + PublicPort int + ResourceGroupId string + Status string + SynonymsDicts []struct { + FileSize int + Name string + SourceType string + Type string + } + UpdatedAt time.Time + VpcInstanceId string + WarmNode bool + WarmNodeConfiguration struct { + Amount int + Disk int + DiskEncryption bool + DiskType string + Spec string + } + ZoneCount int + ZoneInfos []struct { + status string + zoneId string + } +} + +func (self *SElasticSearch) GetTags() (map[string]string, error) { + ret := map[string]string{} + for _, tag := range self.Tags { + if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") { + continue + } + if len(tag.TagKey) > 0 { + ret[tag.TagKey] = tag.TagValue + } + } + return ret, nil +} + +func (self *SElasticSearch) GetSysTags() map[string]string { + ret := map[string]string{} + for _, tag := range self.Tags { + if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") { + if len(tag.TagKey) > 0 { + ret[tag.TagKey] = tag.TagValue + } + } + } + return ret +} + +func (self *SElasticSearch) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} + +func (self *SElasticSearch) GetId() string { + return self.InstanceId +} + +func (self *SElasticSearch) GetGlobalId() string { + return self.InstanceId +} + +func (self *SElasticSearch) GetName() string { + if len(self.Description) > 0 { + return self.Description + } + return self.InstanceId +} + +func (self *SElasticSearch) GetDiskSizeGb() int { + return self.NodeSpec.Disk +} + +func (self *SElasticSearch) GetStorageType() string { + return self.NodeSpec.DiskType +} + +func (self *SElasticSearch) GetCategory() string { + return self.InstanceCategory +} + +func (self *SElasticSearch) GetVersion() string { + return strings.Split(self.EsVersion, "_")[0] +} + +func (self *SElasticSearch) GetVpcId() string { + return self.NetworkConfig.VpcId +} + +func (self *SElasticSearch) GetNetworkId() string { + return self.NetworkConfig.VswitchId +} + +func (self *SElasticSearch) GetZoneId() string { + return self.NetworkConfig.VsArea +} + +func (self *SElasticSearch) IsMultiAz() bool { + return self.ZoneCount > 1 +} + +func (self *SElasticSearch) GetVcpuCount() int { + spec, ok := esSpec[self.NodeSpec.Spec] + if ok { + return spec.VcpuCount + } + return 0 +} + +func (self *SElasticSearch) GetVmemSizeGb() int { + spec, ok := esSpec[self.NodeSpec.Spec] + if ok { + return spec.VmemSizeGb + } + return 0 +} + +func (self *SElasticSearch) GetInstanceType() string { + return self.NodeSpec.Spec +} + +func (self *SElasticSearch) Refresh() error { + es, err := self.region.GetElasitcSearch(self.InstanceId) + if err != nil { + return err + } + return jsonutils.Update(self, es) +} + +func (self *SElasticSearch) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SElasticSearch) GetBillingType() string { + return self.PaymentType +} + +func (self *SElasticSearch) GetProjectId() string { + return self.ResourceGroupId +} + +func (self *SElasticSearch) GetStatus() string { + switch self.Status { + case "active": + return api.ELASTIC_SEARCH_STATUS_AVAILABLE + case "activating": + return api.ELASITC_SEARCH_STATUS_CREATING + case "inactive": + return api.ELASTIC_SEARCH_STATUS_UNAVAILABLE + case "invalid": + return api.ELASTIC_SEARCH_STATUS_DELETING + default: + return self.Status + } +} + +func (self *SElasticSearch) GetAccessInfo() (*cloudprovider.ElasticSearchAccessInfo, error) { + return &cloudprovider.ElasticSearchAccessInfo{ + Domain: self.PublicDomain, + PrivateDomain: self.Domain, + Port: self.PublicPort, + PrivatePort: self.Port, + KibanaUrl: self.KibanaDomain, + }, nil +} + +func (self *SRegion) GetIElasticSearchs() ([]cloudprovider.ICloudElasticSearch, error) { + ret := []SElasticSearch{} + for { + part, total, err := self.GetElasticSearchs(100, len(ret)/100+1) + if err != nil { + return nil, errors.Wrapf(err, "GetElasitcSearchs") + } + ret = append(ret, part...) + if len(ret) >= total { + break + } + } + result := []cloudprovider.ICloudElasticSearch{} + for i := range ret { + ret[i].region = self + result = append(result, &ret[i]) + } + return result, nil +} + +func (self *SRegion) GetIElasticSearchById(id string) (cloudprovider.ICloudElasticSearch, error) { + es, err := self.GetElasitcSearch(id) + if err != nil { + return nil, err + } + return es, nil +} + +func (self *SRegion) GetElasticSearchs(size, page int) ([]SElasticSearch, int, error) { + if size < 1 || size > 100 { + size = 100 + } + if page < 1 { + page = 1 + } + params := map[string]string{ + "PathPattern": "/openapi/instances", + "size": fmt.Sprintf("%d", size), + "page": fmt.Sprintf("%d", page), + } + resp, err := self.esRequest("ListInstance", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "ListInstance") + } + ret := []SElasticSearch{} + err = resp.Unmarshal(&ret, "Result") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + totalCount, _ := resp.Int("Headers", "X-Total-Count") + return ret, int(totalCount), nil +} + +func (self *SRegion) GetElasitcSearch(id string) (*SElasticSearch, error) { + if len(id) == 0 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty id") + } + params := map[string]string{ + "PathPattern": fmt.Sprintf("/openapi/instances/%s", id), + } + resp, err := self.esRequest("DescribeInstance", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeInstance") + } + ret := SElasticSearch{region: self} + err = resp.Unmarshal(&ret, "Result") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return &ret, nil +} + +func (self *SElasticSearch) Delete() error { + return self.region.DeleteElasticSearch(self.InstanceId) +} + +func (self *SRegion) DeleteElasticSearch(id string) error { + params := map[string]string{ + "clientToken": utils.GenRequestId(20), + "deleteType": "immediate", + "PathPattern": fmt.Sprintf("/openapi/instances/%s", id), + } + _, err := self.esRequest("DeleteInstance", params) + return errors.Wrapf(err, "DeleteInstance") +} diff --git a/pkg/multicloud/aliyun/elastic_search_instance_types.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elastic_search_instance_types.go similarity index 100% rename from pkg/multicloud/aliyun/elastic_search_instance_types.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elastic_search_instance_types.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_account.go new file mode 100644 index 0000000000..82810733ce --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_account.go @@ -0,0 +1,212 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://help.aliyun.com/document_detail/95802.html?spm=a2c4g.11186623.6.746.1d4b302ayCuzXB +type SElasticcacheAccount struct { + multicloud.SElasticcacheAccountBase + AliyunTags + + cacheDB *SElasticcache + + AccountStatus string `json:"AccountStatus"` + DatabasePrivileges DatabasePrivileges `json:"DatabasePrivileges"` + InstanceID string `json:"InstanceId"` + AccountName string `json:"AccountName"` + PrivExceeded string `json:"PrivExceeded"` + AccountType string `json:"AccountType"` +} + +type DatabasePrivileges struct { + DatabasePrivilege []DatabasePrivilege `json:"DatabasePrivilege"` +} + +type DatabasePrivilege struct { + AccountPrivilege string `json:"AccountPrivilege"` +} + +func (self *SElasticcacheAccount) GetId() string { + return fmt.Sprintf("%s/%s", self.InstanceID, self.AccountName) +} + +func (self *SElasticcacheAccount) GetName() string { + return self.AccountName +} + +func (self *SElasticcacheAccount) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheAccount) GetStatus() string { + switch strings.ToLower(self.AccountStatus) { + case "unavailable": + return api.ELASTIC_CACHE_ACCOUNT_STATUS_UNAVAILABLE + case "available": + return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE + default: + return self.AccountStatus + } +} + +func (self *SElasticcacheAccount) Refresh() error { + iaccount, err := self.cacheDB.GetICloudElasticcacheAccountByName(self.GetName()) + if err != nil { + return err + } + + err = jsonutils.Update(self, iaccount.(*SElasticcacheAccount)) + if err != nil { + return err + } + + return nil +} + +func (self *SElasticcacheAccount) GetAccountType() string { + if self.AccountName == self.cacheDB.InstanceID { + return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN + } + + switch self.AccountType { + case "Normal": + return api.ELASTIC_CACHE_ACCOUNT_TYPE_NORMAL + case "Super": + return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN + default: + return self.AccountType + } +} + +func (self *SElasticcacheAccount) GetAccountPrivilege() string { + if len(self.DatabasePrivileges.DatabasePrivilege) == 0 { + return "" + } + + privilege := self.DatabasePrivileges.DatabasePrivilege[0].AccountPrivilege + switch privilege { + case "RoleReadOnly": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_READ + case "RoleReadWrite": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE + case "RoleRepl": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_REPL + default: + return privilege + } +} + +// https://help.aliyun.com/document_detail/95941.html?spm=a2c4g.11186623.6.746.523555d8D8Whxq +// https://help.aliyun.com/document_detail/98531.html?spm=5176.11065259.1996646101.searchclickresult.4df474c38Sc2SO +func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + params["AccountPassword"] = input.NewPassword + + err := DoAction(self.cacheDB.region.kvsRequest, "ResetAccountPassword", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.ResetPassword") + } + + if input.NoPasswordAccess != nil { + return cloudprovider.ErrNotSupported + } + + return nil +} + +func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { + if input.Password != nil { + inputPassword := cloudprovider.SCloudElasticCacheAccountResetPasswordInput{} + inputPassword.NewPassword = *input.Password + inputPassword.NoPasswordAccess = input.NoPasswordAccess + err := self.ResetPassword(inputPassword) + if err != nil { + return err + } + } + + if input.Description != nil { + err := self.ModifyAccountDescription(*input.Description) + if err != nil { + return err + } + } + + if input.AccountPrivilege != nil { + err := self.GrantAccountPrivilege(*input.AccountPrivilege) + if err != nil { + return err + } + } + + return nil +} + +// https://help.aliyun.com/document_detail/96020.html?spm=a2c4g.11186623.6.747.5c6f1c717weYEX +func (self *SElasticcacheAccount) ModifyAccountDescription(desc string) error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + params["AccountDescription"] = desc + + err := DoAction(self.cacheDB.region.kvsRequest, "ModifyAccountDescription", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.ModifyAccountDescription") + } + + return nil +} + +// https://help.aliyun.com/document_detail/95897.html?spm=a2c4g.11186623.6.745.28576cf9IqM44R +func (self *SElasticcacheAccount) GrantAccountPrivilege(privilege string) error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + params["AccountPrivilege"] = privilege + + err := DoAction(self.cacheDB.region.kvsRequest, "GrantAccountPrivilege", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.GrantAccountPrivilege") + } + + return nil +} + +// https://help.aliyun.com/document_detail/95988.html?spm=a2c4g.11186623.6.743.cb291c71D1Hlmu +func (self *SElasticcacheAccount) Delete() error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + + err := DoAction(self.cacheDB.region.kvsRequest, "DeleteAccount", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.Delete") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_acl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_acl.go new file mode 100644 index 0000000000..c8a48f5317 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_acl.go @@ -0,0 +1,106 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElasticcacheAcl struct { + multicloud.SElasticcacheAclBase + AliyunTags + + cacheDB *SElasticcache + + SecurityIPList string `json:"SecurityIpList"` + SecurityIPGroupAttribute string `json:"SecurityIpGroupAttribute"` + SecurityIPGroupName string `json:"SecurityIpGroupName"` +} + +func (self *SElasticcacheAcl) GetId() string { + return fmt.Sprintf("%s/%s", self.cacheDB.GetId(), self.SecurityIPGroupName) +} + +func (self *SElasticcacheAcl) GetName() string { + return self.SecurityIPGroupName +} + +func (self *SElasticcacheAcl) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheAcl) GetStatus() string { + return api.ELASTIC_CACHE_ACL_STATUS_AVAILABLE +} + +func (self *SElasticcacheAcl) Refresh() error { + iacl, err := self.cacheDB.GetICloudElasticcacheAcl(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, iacl.(*SElasticcacheAcl)) + if err != nil { + return err + } + + return nil +} + +func (self *SElasticcacheAcl) GetIpList() string { + return self.SecurityIPList +} + +// https://help.aliyun.com/document_detail/61002.html?spm=a2c4g.11186623.6.764.3752782fJpbjxH +func (self *SElasticcacheAcl) Delete() error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["ModifyMode"] = "Delete" + params["SecurityIpGroupName"] = self.GetName() + params["SecurityIps"] = self.SecurityIPList + + err := DoAction(self.cacheDB.region.kvsRequest, "ModifySecurityIps", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAcl.Delete") + } + + return nil +} + +// https://help.aliyun.com/document_detail/61002.html?spm=a2c4g.11186623.6.764.3752782fJpbjxH +func (self *SElasticcacheAcl) UpdateAcl(securityIps string) error { + return self.cacheDB.region.createAcl(self.cacheDB.GetId(), self.GetName(), securityIps) +} + +func (self *SRegion) createAcl(instanceId, aclName, securityIps string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["SecurityIpGroupName"] = aclName + params["ModifyMode"] = "Cover" + params["SecurityIps"] = securityIps + + err := DoAction(self.kvsRequest, "ModifySecurityIps", params, nil, nil) + if err != nil { + return errors.Wrap(err, "region.UpdateAcl") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_backup.go new file mode 100644 index 0000000000..b84eb4817d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_backup.go @@ -0,0 +1,143 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://help.aliyun.com/document_detail/61081.html?spm=a2c4g.11186623.6.752.3d7630beuL57kI +type SElasticcacheBackup struct { + multicloud.SElasticcacheBackupBase + AliyunTags + + cacheDB *SElasticcache + + BackupIntranetDownloadURL string `json:"BackupIntranetDownloadURL"` + BackupType string `json:"BackupType"` + BackupEndTime time.Time `json:"BackupEndTime"` + BackupMethod string `json:"BackupMethod"` + BackupID int64 `json:"BackupId"` + BackupStartTime time.Time `json:"BackupStartTime"` + BackupDownloadURL string `json:"BackupDownloadURL"` + BackupDBNames string `json:"BackupDBNames"` + NodeInstanceID string `json:"NodeInstanceId"` + BackupMode string `json:"BackupMode"` + BackupStatus string `json:"BackupStatus"` + BackupSizeByte int64 `json:"BackupSize"` + EngineVersion string `json:"EngineVersion"` +} + +func (self *SElasticcacheBackup) GetId() string { + return fmt.Sprintf("%d", self.BackupID) +} + +func (self *SElasticcacheBackup) GetName() string { + return self.GetId() +} + +func (self *SElasticcacheBackup) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheBackup) GetStatus() string { + switch self.BackupStatus { + case "Success", "running": + return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS + case "Failed": + return api.ELASTIC_CACHE_BACKUP_STATUS_FAILED + default: + return self.BackupStatus + } +} + +func (self *SElasticcacheBackup) Refresh() error { + ibackup, err := self.cacheDB.GetICloudElasticcacheBackup(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, ibackup.(*SElasticcacheBackup)) + if err != nil { + return err + } + + return nil +} + +func (self *SElasticcacheBackup) GetBackupSizeMb() int { + return int(self.BackupSizeByte / 1024 / 1024) +} + +func (self *SElasticcacheBackup) GetBackupType() string { + switch self.BackupType { + case "FullBackup": + return api.ELASTIC_CACHE_BACKUP_TYPE_FULL + case "IncrementalBackup": + return api.ELASTIC_CACHE_BACKUP_TYPE_INCREMENTAL + default: + return self.BackupType + } +} + +func (self *SElasticcacheBackup) GetBackupMode() string { + switch self.BackupMode { + case "Automated": + return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED + case "Manual": + return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL + default: + return self.BackupMode + } +} + +func (self *SElasticcacheBackup) GetDownloadURL() string { + return self.BackupDownloadURL +} + +func (self *SElasticcacheBackup) GetStartTime() time.Time { + return self.BackupStartTime +} + +func (self *SElasticcacheBackup) GetEndTime() time.Time { + return self.BackupEndTime +} + +func (self *SElasticcacheBackup) Delete() error { + return cloudprovider.ErrNotSupported +} + +// https://help.aliyun.com/document_detail/61083.html?spm=a2c4g.11186623.6.753.216f67ddzpyvTL +func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["BackupId"] = self.GetId() + + // 目前没有查询备份ID的接口,因此,备份ID没什么用 + err := DoAction(self.cacheDB.region.kvsRequest, "RestoreInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.RestoreInstance") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_instance.go new file mode 100644 index 0000000000..842bf6e9f8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_instance.go @@ -0,0 +1,990 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/aokoli/goutils" + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +// https://help.aliyun.com/document_detail/60933.html?spm=a2c4g.11186623.6.726.38f82ca9U1Gtxw +type SElasticcache struct { + multicloud.SElasticcacheBase + AliyunTags + + region *SRegion + attribute *SElasticcacheAttribute + netinfo []SNetInfo + + Config string `json:"Config"` + HasRenewChangeOrder bool `json:"HasRenewChangeOrder"` + InstanceID string `json:"InstanceId"` + UserName string `json:"UserName"` + ArchitectureType string `json:"ArchitectureType"` + ZoneID string `json:"ZoneId"` + PrivateIP string `json:"PrivateIp"` + VSwitchID string `json:"VSwitchId"` + VpcID string `json:"VpcId"` + NetworkType string `json:"NetworkType"` + Qps int64 `json:"QPS"` + PackageType string `json:"PackageType"` + IsRDS bool `json:"IsRds"` + EngineVersion string `json:"EngineVersion"` + ConnectionDomain string `json:"ConnectionDomain"` + InstanceName string `json:"InstanceName"` + ReplacateID string `json:"ReplacateId"` + Bandwidth int64 `json:"Bandwidth"` + ChargeType TChargeType `json:"ChargeType"` + InstanceType string `json:"InstanceType"` + InstanceStatus string `json:"InstanceStatus"` + Port int `json:"Port"` + InstanceClass string `json:"InstanceClass"` + CreateTime time.Time `json:"CreateTime"` + EndTime time.Time `json:"EndTime"` + RegionID string `json:"RegionId"` + NodeType string `json:"NodeType"` + CapacityMB int `json:"Capacity"` + Connections int64 `json:"Connections"` + ResourceGroupId string `json:"ResourceGroupId"` +} + +type SElasticcacheAttribute struct { + Config string `json:"Config"` + HasRenewChangeOrder string `json:"HasRenewChangeOrder"` + InstanceID string `json:"InstanceId"` + ZoneID string `json:"ZoneId"` + ArchitectureType string `json:"ArchitectureType"` + PrivateIP string `json:"PrivateIp"` + VSwitchID string `json:"VSwitchId"` + Engine string `json:"Engine"` + VpcID string `json:"VpcId"` + NetworkType string `json:"NetworkType"` + Qps int64 `json:"QPS"` + PackageType string `json:"PackageType"` + ReplicaID string `json:"ReplicaId"` + IsRDS bool `json:"IsRds"` + MaintainStartTime string `json:"MaintainStartTime"` + VpcAuthMode string `json:"VpcAuthMode"` + ConnectionDomain string `json:"ConnectionDomain"` + EngineVersion string `json:"EngineVersion"` + InstanceName string `json:"InstanceName"` + Bandwidth int64 `json:"Bandwidth"` + ChargeType TChargeType `json:"ChargeType"` + AuditLogRetention string `json:"AuditLogRetention"` + MaintainEndTime string `json:"MaintainEndTime"` + ReplicationMode string `json:"ReplicationMode"` + InstanceType string `json:"InstanceType"` + InstanceStatus string `json:"InstanceStatus"` + Port int64 `json:"Port"` + InstanceClass string `json:"InstanceClass"` + CreateTime time.Time `json:"CreateTime"` + NodeType string `json:"NodeType"` + RegionID string `json:"RegionId"` + AvailabilityValue string `json:"AvailabilityValue"` + CapacityMB int `json:"Capacity"` + Connections int64 `json:"Connections"` + SecurityIPList string `json:"SecurityIPList"` +} + +type SNetInfo struct { + ConnectionString string `json:"ConnectionString"` + Port string `json:"Port"` + DBInstanceNetType string `json:"DBInstanceNetType"` + VPCID string `json:"VPCId"` + VPCInstanceID string `json:"VPCInstanceId"` + IPAddress string `json:"IPAddress"` + IPType string `json:"IPType"` + Upgradeable string `json:"Upgradeable"` + ExpiredTime *string `json:"ExpiredTime,omitempty"` +} + +func (self *SElasticcache) GetId() string { + return self.InstanceID +} + +func (self *SElasticcache) GetName() string { + if len(self.InstanceName) > 0 { + return self.InstanceName + } + + return self.InstanceID +} + +func (self *SElasticcache) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcache) GetStatus() string { + switch self.InstanceStatus { + case "Normal": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "Creating": + return api.ELASTIC_CACHE_STATUS_DEPLOYING + case "Changing": + return api.ELASTIC_CACHE_STATUS_CHANGING + case "Inactive": + return api.ELASTIC_CACHE_STATUS_INACTIVE + case "Flushing": + return api.ELASTIC_CACHE_STATUS_FLUSHING + case "Released": + return api.ELASTIC_CACHE_STATUS_RELEASED + case "Transforming": + return api.ELASTIC_CACHE_STATUS_TRANSFORMING + case "Unavailable": + return api.ELASTIC_CACHE_STATUS_UNAVAILABLE + case "Error": + return api.ELASTIC_CACHE_STATUS_ERROR + case "Migrating": + return api.ELASTIC_CACHE_STATUS_MIGRATING + case "BackupRecovering": + return api.ELASTIC_CACHE_STATUS_BACKUPRECOVERING + case "MinorVersionUpgrading": + return api.ELASTIC_CACHE_STATUS_MINORVERSIONUPGRADING + case "NetworkModifying": + return api.ELASTIC_CACHE_STATUS_NETWORKMODIFYING + case "SSLModifying": + return api.ELASTIC_CACHE_STATUS_SSLMODIFYING + case "MajorVersionUpgrading": + return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING + default: + return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING + } +} + +func (self *SElasticcache) Refresh() error { + cache, err := self.region.GetElasticCacheById(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, cache) + if err != nil { + return err + } + + return nil +} + +func (self *SElasticcache) GetBillingType() string { + return convertChargeType(self.ChargeType) +} + +func (self *SElasticcache) GetCreatedAt() time.Time { + return self.CreateTime +} + +func (self *SElasticcache) GetExpiredAt() time.Time { + return convertExpiredAt(self.EndTime) +} + +func (self *SElasticcache) GetInstanceType() string { + return self.InstanceClass +} + +func (self *SElasticcache) GetCapacityMB() int { + return self.CapacityMB +} + +func (self *SElasticcache) GetArchType() string { + switch self.ArchitectureType { + case "rwsplit": + return api.ELASTIC_CACHE_ARCH_TYPE_RWSPLIT + case "cluster": + return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER + case "standard": + if self.NodeType == "single" { + return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE + } else if self.NodeType == "double" { + return api.ELASTIC_CACHE_ARCH_TYPE_MASTER + } + } + + return "" +} + +func (self *SElasticcache) GetNodeType() string { + return self.NodeType +} + +func (self *SElasticcache) GetEngine() string { + return self.InstanceType +} + +func (self *SElasticcache) GetEngineVersion() string { + return self.EngineVersion +} + +func (self *SElasticcache) GetVpcId() string { + return self.VpcID +} + +func (self *SElasticcache) GetZoneId() string { + zoneId := transZoneIdToEcsZoneId(self.region, "redis", self.ZoneID) + zone, err := self.region.getZoneById(fetchMasterZoneId(zoneId)) + if err != nil { + log.Errorf("failed to find zone for elasticcache %s error: %v", self.GetId(), err) + return "" + } + + return zone.GetGlobalId() +} + +func (self *SElasticcache) GetNetworkType() string { + switch self.NetworkType { + case "VPC": + return api.LB_NETWORK_TYPE_VPC + case "CLASSIC": + return api.LB_NETWORK_TYPE_CLASSIC + default: + return api.LB_NETWORK_TYPE_VPC + } +} + +func (self *SElasticcache) GetNetworkId() string { + return self.VSwitchID +} + +func (self *SElasticcache) GetPrivateDNS() string { + return self.ConnectionDomain +} + +func (self *SElasticcache) GetPrivateIpAddr() string { + return self.PrivateIP +} + +func (self *SElasticcache) GetPrivateConnectPort() int { + return self.Port +} + +func (self *SElasticcache) GetPublicDNS() string { + pub, err := self.GetPublicNetInfo() + if err != nil { + log.Errorf("SElasticcache.GetPublicDNS %s", err) + return "" + } + + if pub != nil { + return pub.ConnectionString + } + + return "" +} + +func (self *SElasticcache) GetPublicIpAddr() string { + pub, err := self.GetPublicNetInfo() + if err != nil { + log.Errorf("SElasticcache.GetPublicIpAddr %s", err) + } + + if pub != nil { + return pub.IPAddress + } + + return "" +} + +func (self *SElasticcache) GetPublicConnectPort() int { + pub, err := self.GetPublicNetInfo() + if err != nil { + log.Errorf("SElasticcache.GetPublicConnectPort %s", err) + } + + if pub != nil { + port, _ := strconv.Atoi(pub.Port) + return port + } + + return 0 +} + +func (self *SElasticcache) GetMaintainStartTime() string { + attr, err := self.GetAttribute() + if err != nil { + log.Errorf("SElasticcache.GetMaintainStartTime %s", err) + } + + if attr != nil { + return attr.MaintainStartTime + } + + return "" +} + +func (self *SElasticcache) GetBandwidth() int { + return int(self.Bandwidth) +} + +func (self *SElasticcache) GetConnections() int { + attr, err := self.GetAttribute() + if err != nil { + log.Errorf("SElasticcache.GetMaintainEndTime %s", err) + } + + if attr != nil { + return int(attr.Connections) + } + return 0 +} + +func (self *SElasticcache) GetMaintainEndTime() string { + attr, err := self.GetAttribute() + if err != nil { + log.Errorf("SElasticcache.GetMaintainEndTime %s", err) + } + + if attr != nil { + return attr.MaintainEndTime + } + + return "" +} + +func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { + accounts, err := self.region.GetElasticCacheAccounts(self.GetId()) + if err != nil { + return nil, err + } + + iaccounts := make([]cloudprovider.ICloudElasticcacheAccount, len(accounts)) + for i := range accounts { + accounts[i].cacheDB = self + iaccounts[i] = &accounts[i] + } + + return iaccounts, nil +} + +func (self *SElasticcache) GetICloudElasticcacheAccountByName(accountName string) (cloudprovider.ICloudElasticcacheAccount, error) { + account, err := self.region.GetElasticCacheAccountByName(self.GetId(), accountName) + if err != nil { + return nil, err + } + + account.cacheDB = self + return account, nil +} + +func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { + acls, err := self.region.GetElasticCacheAcls(self.GetId()) + if err != nil { + return nil, err + } + + iacls := make([]cloudprovider.ICloudElasticcacheAcl, len(acls)) + for i := range acls { + acls[i].cacheDB = self + iacls[i] = &acls[i] + } + + return iacls, nil +} + +func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { + start := self.CreateTime.Format("2006-01-02T15:04Z") + end := time.Now().Format("2006-01-02T15:04Z") + backups, err := self.region.GetElasticCacheBackups(self.GetId(), start, end) + if err != nil { + return nil, err + } + + ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) + for i := range backups { + backups[i].cacheDB = self + ibackups[i] = &backups[i] + } + + return ibackups, nil +} + +func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { + parameters, err := self.region.GetElasticCacheParameters(self.GetId()) + if err != nil { + return nil, err + } + + iparameters := make([]cloudprovider.ICloudElasticcacheParameter, len(parameters)) + for i := range parameters { + parameters[i].cacheDB = self + iparameters[i] = ¶meters[i] + } + + return iparameters, nil +} + +func (self *SElasticcache) GetAttribute() (*SElasticcacheAttribute, error) { + if self.attribute != nil { + return self.attribute, nil + } + + params := make(map[string]string) + params["RegionId"] = self.region.RegionId + params["InstanceId"] = self.GetId() + + rets := []SElasticcacheAttribute{} + err := DoListAll(self.region.kvsRequest, "DescribeInstanceAttribute", params, []string{"Instances", "DBInstanceAttribute"}, &rets) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.GetAttribute") + } + + count := len(rets) + if count >= 1 { + self.attribute = &rets[0] + return self.attribute, nil + } else { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "elasticcache.GetAttribute %s", self.GetId()) + } +} + +func (self *SElasticcache) GetNetInfo() ([]SNetInfo, error) { + params := make(map[string]string) + params["RegionId"] = self.region.RegionId + params["InstanceId"] = self.GetId() + + rets := []SNetInfo{} + err := DoListAll(self.region.kvsRequest, "DescribeDBInstanceNetInfo", params, []string{"NetInfoItems", "InstanceNetInfo"}, &rets) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.GetNetInfo") + } + + self.netinfo = rets + return self.netinfo, nil +} + +// https://help.aliyun.com/document_detail/66742.html?spm=a2c4g.11186623.6.731.54c123d2P02qhk +func (self *SElasticcache) GetPublicNetInfo() (*SNetInfo, error) { + nets, err := self.GetNetInfo() + if err != nil { + return nil, err + } + + for i := range nets { + if nets[i].IPType == "Public" { + return &nets[i], nil + } + } + + return nil, nil +} + +func (self *SRegion) GetElasticCaches(instanceIds []string) ([]SElasticcache, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + if instanceIds != nil && len(instanceIds) > 0 { + params["InstanceIds"] = strings.Join(instanceIds, ",") + } + + ret := []SElasticcache{} + err := DoListAll(self.kvsRequest, "DescribeInstances", params, []string{"Instances", "KVStoreInstance"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCaches") + } + + for i := range ret { + ret[i].region = self + } + + return ret, nil +} + +func (self *SRegion) GetElasticCacheById(instanceId string) (*SElasticcache, error) { + caches, err := self.GetElasticCaches([]string{instanceId}) + if err != nil { + return nil, errors.Wrapf(err, "region.GetElasticCacheById %s", instanceId) + } + + if len(caches) == 1 { + return &caches[0], nil + } else if len(caches) == 0 { + return nil, cloudprovider.ErrNotFound + } else { + return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "region.GetElasticCacheById %s.expect 1 found %d ", instanceId, len(caches)) + } +} + +func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { + ec, err := self.GetElasticCacheById(id) + if err != nil { + return nil, err + } + + return ec, nil +} + +// https://help.aliyun.com/document_detail/95802.html?spm=a2c4g.11186623.6.746.143e782f3Pfkfg +func (self *SRegion) GetElasticCacheAccounts(instanceId string) ([]SElasticcacheAccount, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + + ret := []SElasticcacheAccount{} + err := DoListAll(self.kvsRequest, "DescribeAccounts", params, []string{"Accounts", "Account"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCacheAccounts") + } + + return ret, nil +} + +func (self *SRegion) GetElasticCacheAccountByName(instanceId string, accountName string) (*SElasticcacheAccount, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + params["AccountName"] = accountName + + ret := []SElasticcacheAccount{} + err := DoListAll(self.kvsRequest, "DescribeAccounts", params, []string{"Accounts", "Account"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCacheAccounts") + } + + if len(ret) == 1 { + return &ret[0], nil + } else if len(ret) == 0 { + return nil, cloudprovider.ErrNotFound + } else { + return nil, errors.Wrap(fmt.Errorf("%d account with name %s found", len(ret), accountName), "region.GetElasticCacheAccountByName") + } +} + +// https://help.aliyun.com/document_detail/63889.html?spm=a2c4g.11186623.6.764.3cb43852R7lnoS +func (self *SRegion) GetElasticCacheAcls(instanceId string) ([]SElasticcacheAcl, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + + ret := []SElasticcacheAcl{} + err := DoListAll(self.kvsRequest, "DescribeSecurityIps", params, []string{"SecurityIpGroups", "SecurityIpGroup"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCacheAcls") + } + + return ret, nil +} + +// https://help.aliyun.com/document_detail/61081.html?spm=a2c4g.11186623.6.754.10613852qAbEQV +func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + params["StartTime"] = startTime + params["EndTime"] = endTime + + ret := []SElasticcacheBackup{} + err := DoListAll(self.kvsRequest, "DescribeBackups", params, []string{"Backups", "Backup"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCacheBackups") + } + + return ret, nil +} + +// https://help.aliyun.com/document_detail/93078.html?spm=a2c4g.11186623.6.769.58011975YYL5Gl +func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["DBInstanceId"] = instanceId + + ret := []SElasticcacheParameter{} + err := DoListAll(self.kvsRequest, "DescribeParameters", params, []string{"RunningParameters", "Parameter"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCacheParameters") + } + + return ret, nil +} + +// https://help.aliyun.com/document_detail/60873.html?spm=a2c4g.11174283.6.715.7412dce0qSYemb +func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceClass"] = ec.InstanceType + params["InstanceName"] = ec.InstanceName + params["InstanceType"] = ec.Engine + params["EngineVersion"] = ec.EngineVersion + + if len(ec.Password) > 0 { + params["UserName"] = ec.UserName + params["Password"] = ec.Password + } + + if len(ec.ZoneIds) > 0 { + params["ZoneId"] = transZoneIdFromEcsZoneId(self, "redis", ec.ZoneIds[0]) + } + + if len(ec.PrivateIpAddress) > 0 { + params["PrivateIpAddress"] = ec.PrivateIpAddress + } + + if len(ec.NodeType) > 0 { + switch ec.NodeType { + case "single": + params["NodeType"] = "STAND_ALONE" + case "double": + params["NodeType"] = "MASTER_SLAVE" + } + } + + if len(ec.ProjectId) > 0 { + params["ResourceGroupId"] = ec.ProjectId + } + + params["NetworkType"] = ec.NetworkType + params["VpcId"] = ec.VpcId + params["VSwitchId"] = ec.NetworkId + params["ChargeType"] = "PostPaid" + if ec.BillingCycle != nil { + params["ChargeType"] = "PrePaid" + if ec.BillingCycle.GetMonths() >= 1 && ec.BillingCycle.GetMonths() <= 9 { + params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths()) + } else if ec.BillingCycle.GetMonths() == 12 || ec.BillingCycle.GetMonths() == 24 || ec.BillingCycle.GetMonths() == 36 { + params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths()) + } else { + return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") + } + } + + ret := &SElasticcache{region: self} + err := DoAction(self.kvsRequest, "CreateInstance", params, []string{}, ret) + if err != nil { + return nil, errors.Wrap(err, "region.CreateIElasticcaches") + } + self.SetResourceTags(ALIYUN_SERVICE_KVS, "INSTANCE", ret.InstanceID, ec.Tags, true) + return ret, nil +} + +// https://help.aliyun.com/document_detail/116215.html?spm=a2c4g.11174283.6.736.6b9ddce0c5nsw6 +func (self *SElasticcache) Restart() error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["EffectiveTime"] = "0" // 立即重启 + + err := DoAction(self.region.kvsRequest, "RestartInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.Restart") + } + + return nil +} + +// https://help.aliyun.com/document_detail/60898.html?spm=a2c4g.11186623.6.713.56ec1603KS0xA0 +func (self *SElasticcache) Delete() error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + + err := DoAction(self.region.kvsRequest, "DeleteInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.Delete") + } + + return nil +} + +// https://help.aliyun.com/document_detail/60903.html?spm=a2c4g.11186623.6.711.3f062c92aRJNfw +func (self *SElasticcache) ChangeInstanceSpec(spec string) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["InstanceClass"] = strings.Split(spec, ":")[0] + params["AutoPay"] = "true" // 自动付款 + + err := DoAction(self.region.kvsRequest, "ModifyInstanceSpec", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.ChangeInstanceSpec") + } + + return nil +} + +// https://help.aliyun.com/document_detail/61000.html?spm=a2c4g.11186623.6.730.57d66cb0QlQS86 +func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["MaintainStartTime"] = maintainStartTime + params["MaintainEndTime"] = maintainEndTime + + err := DoAction(self.region.kvsRequest, "ModifyInstanceMaintainTime", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.SetMaintainTime") + } + + return nil +} + +// https://help.aliyun.com/document_detail/125795.html?spm=a2c4g.11186623.6.719.51542b3593cDKO +func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { + if port < 1024 { + port = 6379 + } + + suffix, _ := goutils.RandomAlphabetic(4) + conn := self.GetId() + strings.ToLower(suffix) + + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["Port"] = strconv.Itoa(port) + params["ConnectionStringPrefix"] = conn + + err := DoAction(self.region.kvsRequest, "AllocateInstancePublicConnection", params, nil, nil) + if err != nil { + return "", errors.Wrap(err, "elasticcache.AllocatePublicConnection") + } + + return conn, nil +} + +// https://help.aliyun.com/document_detail/125796.html?spm=a2c4g.11186623.6.720.702a3b23Qayopy +func (self *SElasticcache) ReleasePublicConnection() error { + publicConn := self.GetPublicDNS() + if len(publicConn) == 0 { + log.Debugf("elasticcache.ReleasePublicConnection public connect is empty") + return nil + } + + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["CurrentConnectionString"] = publicConn + + err := DoAction(self.region.kvsRequest, "ReleaseInstancePublicConnection", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.ReleasePublicConnection") + } + + return nil +} + +// https://help.aliyun.com/document_detail/93603.html?spm=a2c4g.11186623.6.732.10666cf9UVgNPb 修改链接地址 + +// https://help.aliyun.com/document_detail/95973.html?spm=a2c4g.11186623.6.742.4698126aH0s4Q5 +func (self *SElasticcache) CreateAccount(input cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["AccountName"] = input.AccountName + params["AccountPassword"] = input.AccountPassword + if len(input.AccountPrivilege) > 0 { + params["AccountPrivilege"] = input.AccountPrivilege + } + + if len(input.Description) > 0 { + params["AccountDescription"] = input.Description + } + + err := DoAction(self.region.kvsRequest, "CreateAccount", params, nil, nil) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.CreateAccount") + } + + return self.GetICloudElasticcacheAccountByName(input.AccountName) +} + +func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { + acl := &SElasticcacheAcl{} + acl.cacheDB = self + acl.SecurityIPGroupName = aclName + acl.SecurityIPList = securityIps + return acl, self.region.createAcl(self.GetId(), aclName, securityIps) +} + +// https://help.aliyun.com/document_detail/61113.html?spm=a2c4g.11186623.6.770.16a61e7admr0xy +func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["Config"] = config.String() + + err := DoAction(self.region.kvsRequest, "ModifyInstanceConfig", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") + } + + return nil +} + +// https://help.aliyun.com/document_detail/61075.html?spm=a2c4g.11186623.6.749.4cba126a2U9xNa +func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + + // 目前没有查询备份ID的接口,因此,备份ID没什么用 + err := DoAction(self.region.kvsRequest, "CreateBackup", params, []string{"BackupJobID"}, nil) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.CreateBackup") + } + + return nil, nil +} + +// https://help.aliyun.com/document_detail/61077.html?spm=a2c4g.11186623.6.750.3d7630be7ziUfg +func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["PreferredBackupPeriod"] = config.PreferredBackupPeriod + params["PreferredBackupTime"] = config.PreferredBackupTime + + err := DoAction(self.region.kvsRequest, "ModifyBackupPolicy", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateBackupPolicy") + } + + return nil +} + +// https://help.aliyun.com/document_detail/60931.html?spm=a2c4g.11186623.6.728.5c57292920UKx3 +func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + + err := DoAction(self.region.kvsRequest, "FlushInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.FlushInstance") + } + + return nil +} + +// https://help.aliyun.com/document_detail/98531.html?spm=5176.11065259.1996646101.searchclickresult.4df474c38Sc2SO +func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool, password string) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + if noPwdAccess { + params["VpcAuthMode"] = "Close" + } else { + params["VpcAuthMode"] = "Open" + } + + err := DoAction(self.region.kvsRequest, "ModifyInstanceVpcAuthMode", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.UpdateAuthMode") + } + + return nil +} + +func (self *SElasticcache) GetProjectId() string { + return self.ResourceGroupId +} + +func (self *SElasticcache) GetAuthMode() string { + attribute, err := self.GetAttribute() + if err != nil { + log.Errorf("elasticcache.GetAuthMode %s", err) + } + switch attribute.VpcAuthMode { + case "Open": + return "on" + default: + return "off" + } +} + +func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { + segs := strings.Split(accountId, "/") + if len(segs) < 2 { + log.Debugf("elasticcache.GetICloudElasticcacheAccount invalid account id %s", accountId) + return nil, errors.Wrap(cloudprovider.ErrNotFound, "invalid account id") + } + + return self.GetICloudElasticcacheAccountByName(segs[1]) +} + +func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { + acls, err := self.GetICloudElasticcacheAcls() + if err != nil { + return nil, err + } + + for _, acl := range acls { + if acl.GetId() == aclId { + return acl, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { + backups, err := self.GetICloudElasticcacheBackups() + if err != nil { + return nil, err + } + + for _, backup := range backups { + if backup.GetId() == backupId { + return backup, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (instance *SElasticcache) SetTags(tags map[string]string, replace bool) error { + return instance.region.SetResourceTags(ALIYUN_SERVICE_KVS, "INSTANCE", instance.GetId(), tags, replace) +} + +func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { + return errors.Wrap(cloudprovider.ErrNotSupported, "UpdateSecurityGroups") +} + +// https://help.aliyun.com/document_detail/60903.html?spm=a2c4g.11174283.6.877.34653436jn6t4C +// https://help.aliyun.com/document_detail/95584.html?spm=a2c4g.11186623.6.907.60e3292bWsVIOE +// https://help.aliyun.com/document_detail/60909.html?spm=a2c4g.11186623.6.910.17664ce0jfir7F +func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { + month := bc.GetMonths() + if month <= 0 { + return errors.Wrap(fmt.Errorf("month should great than 0"), "GetMonths") + } + + if (month >= 1 && month <= 9) || month == 12 || month == 24 || month == 36 { + return errors.Wrap(fmt.Errorf("month %d is invalid, required: 1~9、12、24、36", month), "GetMonths") + } + + params := map[string]string{} + params["InstanceId"] = self.GetId() + params["Period"] = fmt.Sprintf("%d", month) + params["AutoPay"] = "true" + _, err := self.region.kvsRequest("RenewInstance", params) + if err != nil { + return errors.Wrap(err, "RenewInstance") + } + + return nil +} + +func (self *SElasticcache) SetAutoRenew(bc billing.SBillingCycle) error { + params := map[string]string{} + params["DBInstanceId"] = self.GetId() + params["Duration"] = "1" + params["AutoRenew"] = fmt.Sprintf("%v", bc.AutoRenew) + _, err := self.region.kvsRequest("ModifyInstanceAutoRenewalAttribute", params) + if err != nil { + return errors.Wrap(err, "ModifyInstanceAutoRenewalAttribute") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_parameter.go new file mode 100644 index 0000000000..c3ac97d1c7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/elasticcache_parameter.go @@ -0,0 +1,86 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElasticcacheParameter struct { + multicloud.SElasticcacheParameterBase + AliyunTags + + cacheDB *SElasticcache + + ParameterDescription string `json:"ParameterDescription"` + ParameterValue string `json:"ParameterValue"` + ForceRestart string `json:"ForceRestart"` + CheckingCode string `json:"CheckingCode"` + ModifiableStatus string `json:"ModifiableStatus"` + ParameterName string `json:"ParameterName"` +} + +func (self *SElasticcacheParameter) GetId() string { + return fmt.Sprintf("%s/%s", self.cacheDB.InstanceID, self.ParameterName) +} + +func (self *SElasticcacheParameter) GetName() string { + return self.ParameterName +} + +func (self *SElasticcacheParameter) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheParameter) GetStatus() string { + return api.ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE +} + +func (self *SElasticcacheParameter) GetParameterKey() string { + return self.ParameterName +} + +func (self *SElasticcacheParameter) GetParameterValue() string { + return self.ParameterValue +} + +func (self *SElasticcacheParameter) GetParameterValueRange() string { + return self.CheckingCode +} + +func (self *SElasticcacheParameter) GetDescription() string { + return self.ParameterDescription +} + +func (self *SElasticcacheParameter) GetModifiable() bool { + switch self.ModifiableStatus { + case "true": + return true + default: + return false + } +} + +func (self *SElasticcacheParameter) GetForceRestart() bool { + switch self.ForceRestart { + case "true": + return true + default: + return false + } +} diff --git a/pkg/multicloud/aliyun/errors.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/errors.go similarity index 100% rename from pkg/multicloud/aliyun/errors.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/errors.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/events.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/events.go new file mode 100644 index 0000000000..88c087817b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/events.go @@ -0,0 +1,186 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "strings" + "time" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + EVENT_REGION_HANGZHOU = "cn-hangzhou" +) + +type SAttributes struct { + CreationDate time.Time + MfaAuthenticated bool +} + +type SSessionContext struct { + Attributes SAttributes +} + +type SUserIdentity struct { + AccessKeyId string + AccountId string + PrincipalId string + SessionContext SSessionContext + Type string + UserName string +} + +type SEvent struct { + region *SRegion + AdditionalEventData map[string]string + ApiVersion string + EventId string + EventName string + EventSource string + EventTime time.Time + EventType string + EventVersion string + RequestId string + RequestParameters map[string]string + ServiceName string + SourceIpAddress string + UserAgent string + UserIdentity SUserIdentity + ResponseElements map[string]string + IsGlobal bool +} + +func (event *SEvent) GetCreatedAt() time.Time { + return event.EventTime +} + +func (event *SEvent) GetName() string { + return event.EventName +} + +func (event *SEvent) GetAction() string { + return event.ServiceName +} + +func (event *SEvent) GetResourceType() string { + return "" +} + +func (event *SEvent) GetRequestId() string { + return event.RequestId +} + +func (event *SEvent) GetRequest() jsonutils.JSONObject { + return jsonutils.Marshal(event) +} + +func (event *SEvent) GetAccount() string { + if account, ok := event.AdditionalEventData["loginAccount"]; ok { + return account + } + if len(event.UserIdentity.AccessKeyId) > 0 { + return event.UserIdentity.AccessKeyId + } + return event.UserIdentity.UserName +} + +func (event *SEvent) GetService() string { + return event.ServiceName +} + +func (event *SEvent) IsSuccess() bool { + return true +} + +func (region *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { + var ( + events []SEvent + err error + token string + _events []SEvent + iEvents []cloudprovider.ICloudEvent + eventRW string + ) + + eventRW = "Write" + if withReadEvent { + eventRW = "" + } + + for { + _events, token, err = region.GetEvents(start, end, token, eventRW, "") + if err != nil { + return nil, errors.Wrap(err, "region.GetEvents") + } + events = append(events, _events...) + if len(token) == 0 || len(_events) == 0 { + break + } + } + + for i := range events { + if events[i].IsGlobal && region.RegionId != ALIYUN_DEFAULT_REGION { + continue + } + if !withReadEvent && strings.HasPrefix(events[i].EventName, "Query") { // QueryInstanceBill QueryBill + continue + } + iEvents = append(iEvents, &events[i]) + } + return iEvents, nil +} + +func (region *SRegion) GetEvents(start time.Time, end time.Time, token string, eventRW string, requestId string) ([]SEvent, string, error) { + params := map[string]string{ + "RegionId": region.RegionId, + } + if !start.IsZero() { + params["StartTime"] = start.Format("2006-01-02T15:04:05Z") + } + if !end.IsZero() { + params["EndTime"] = end.Format("2006-01-02T15:04:05Z") + } + if utils.IsInStringArray(eventRW, []string{"Read", "Write"}) { + params["LookupAttribute.1.Key"] = "EventRW" + params["LookupAttribute.1.Value"] = eventRW + } + if len(token) > 0 { + params["NextToken"] = token + } + if len(requestId) > 0 { + params["Request"] = requestId + } + resp, err := region.trialRequest("LookupEvents", params) + if err != nil { + if strings.Contains(err.Error(), "no such host") { // cn-wulanchabu not support + return []SEvent{}, "", nil + } + return nil, "", err + } + + events := []SEvent{} + err = resp.Unmarshal(&events, "Events") + if err != nil { + return nil, "", err + } + nextToken, _ := resp.GetString("NextToken") + return events, nextToken, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/filesystem.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/filesystem.go new file mode 100644 index 0000000000..0967a1bced --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/filesystem.go @@ -0,0 +1,362 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SupportedFeatures struct { + SupportedFeature []string +} + +type MountTargets struct { + MountTarget []SMountTarget +} + +type Package struct { +} + +type Packages struct { + Package []Package +} + +type SFileSystem struct { + multicloud.SNasBase + AliyunTags + region *SRegion + + Status string + Description string + StorageType string + MountTargetCountLimit int + Ldap string + ZoneId string + // 2021-03-22T10:08:15CST + CreateTime string + MeteredIASize int + SupportedFeatures SupportedFeatures + MountTargets MountTargets + AutoSnapshotPolicyId string + MeteredSize int64 + EncryptType int + Capacity int64 + ProtocolType string + ChargeType string + Packages Packages + ExpiredTime string + FileSystemType string + FileSystemId string + RegionId string +} + +func (self *SFileSystem) GetId() string { + return self.FileSystemId +} + +func (self *SFileSystem) GetGlobalId() string { + return self.FileSystemId +} + +func (self *SFileSystem) GetName() string { + if len(self.Description) > 0 { + return self.Description + } + return self.FileSystemId +} + +func (self *SFileSystem) GetFileSystemType() string { + return self.FileSystemType +} + +func (self *SFileSystem) GetMountTargetCountLimit() int { + return self.MountTargetCountLimit +} + +func (self *SFileSystem) GetStatus() string { + switch self.Status { + case "", "Running": + return api.NAS_STATUS_AVAILABLE + case "Extending": + return api.NAS_STATUS_EXTENDING + case "Stopping", "Stopped": + return api.NAS_STATUS_UNAVAILABLE + case "Pending": + return api.NAS_STATUS_CREATING + default: + return api.NAS_STATUS_UNKNOWN + } +} + +func (self *SFileSystem) GetBillintType() string { + if self.ChargeType == "PayAsYouGo" { + return billing_api.BILLING_TYPE_POSTPAID + } + return billing_api.BILLING_TYPE_PREPAID +} + +func (self *SFileSystem) GetStorageType() string { + return strings.ToLower(self.StorageType) +} + +func (self *SFileSystem) GetProtocol() string { + return self.ProtocolType +} + +func (self *SFileSystem) GetCapacityGb() int64 { + return self.Capacity +} + +func (self *SFileSystem) GetUsedCapacityGb() int64 { + return self.MeteredSize +} + +func (self *SFileSystem) GetZoneId() string { + return self.ZoneId +} + +func (self *SFileSystem) Delete() error { + return self.region.DeleteFileSystem(self.FileSystemId) +} + +func (self *SFileSystem) GetCreatedAt() time.Time { + ret, _ := time.Parse("2006-01-02T15:04:05CST", self.CreateTime) + if !ret.IsZero() { + ret = ret.Add(time.Hour * 8) + } + return ret +} + +func (self *SFileSystem) GetExpiredAt() time.Time { + ret, _ := time.Parse("2006-01-02T15:04:05CST", self.ExpiredTime) + if !ret.IsZero() { + ret = ret.Add(time.Hour * 8) + } + return ret +} + +func (self *SFileSystem) Refresh() error { + fs, err := self.region.GetFileSystem(self.FileSystemId) + if err != nil { + return errors.Wrapf(err, "GetFileSystem(%s)", self.FileSystemId) + } + return jsonutils.Update(self, fs) +} + +func (self *SRegion) GetFileSystems(id string, pageSize, pageNum int) ([]SFileSystem, int, error) { + if pageSize < 1 || pageSize > 100 { + pageSize = 50 + } + if pageNum < 1 { + pageNum = 1 + } + params := map[string]string{ + "RegionId": self.RegionId, + "PageSize": fmt.Sprintf("%d", pageSize), + "PageNumber": fmt.Sprintf("%d", pageNum), + } + if len(id) > 0 { + params["FileSystemId"] = id + } + resp, err := self.nasRequest("DescribeFileSystems", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeFileSystems") + } + ret := struct { + TotalCount int + FileSystems struct { + FileSystem []SFileSystem + } + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + return ret.FileSystems.FileSystem, ret.TotalCount, nil +} + +func (self *SRegion) GetICloudFileSystems() ([]cloudprovider.ICloudFileSystem, error) { + nas := []SFileSystem{} + num := 1 + for { + part, total, err := self.GetFileSystems("", 100, num) + if err != nil { + return nil, errors.Wrapf(err, "GetFileSystems") + } + nas = append(nas, part...) + if total <= len(nas) { + break + } + num++ + } + + ret := []cloudprovider.ICloudFileSystem{} + for i := range nas { + nas[i].region = self + ret = append(ret, &nas[i]) + } + return ret, nil +} + +func (self *SRegion) GetFileSystem(id string) (*SFileSystem, error) { + if len(id) == 0 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty id") + } + nas, total, err := self.GetFileSystems(id, 1, 1) + if err != nil { + return nil, errors.Wrapf(err, "GetFileSystems") + } + if total == 1 { + nas[0].region = self + return &nas[0], nil + } + if total == 0 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) + } + return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, id) +} + +func (self *SRegion) GetICloudFileSystemById(id string) (cloudprovider.ICloudFileSystem, error) { + fs, err := self.GetFileSystem(id) + if err != nil { + return nil, errors.Wrapf(err, "self.GetFileSystem") + } + return fs, nil +} + +func (self *SRegion) CreateMountTarget(opts *cloudprovider.SMountTargetCreateOptions) (*SMountTarget, error) { + params := map[string]string{ + "RegionId": self.RegionId, + "FileSystemId": opts.FileSystemId, + "AccessGroupName": strings.TrimPrefix(strings.TrimPrefix(opts.AccessGroupId, "extreme/"), "standard/"), + "NetworkType": utils.Capitalize(opts.NetworkType), + "VpcId": opts.VpcId, + "VSwitchId": opts.NetworkId, + } + resp, err := self.nasRequest("CreateMountTarget", params) + if err != nil { + return nil, errors.Wrapf(err, "CreateMountTarget") + } + ret := struct { + MountTargetDomain string + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + mts, _, err := self.GetMountTargets(opts.FileSystemId, ret.MountTargetDomain, 10, 1) + if err != nil { + return nil, errors.Wrapf(err, "self.GetMountTargets") + } + for i := range mts { + if mts[i].MountTargetDomain == ret.MountTargetDomain { + return &mts[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "afeter create with mount domain %s", ret.MountTargetDomain) +} + +func (self *SFileSystem) CreateMountTarget(opts *cloudprovider.SMountTargetCreateOptions) (cloudprovider.ICloudMountTarget, error) { + mt, err := self.region.CreateMountTarget(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateMountTarget") + } + mt.fs = self + return mt, nil +} + +func (self *SRegion) DeleteFileSystem(id string) error { + params := map[string]string{ + "RegionId": self.RegionId, + "FileSystemId": id, + } + _, err := self.nasRequest("DeleteFileSystem", params) + return errors.Wrapf(err, "DeleteFileSystem") +} + +func (self *SRegion) CreateICloudFileSystem(opts *cloudprovider.FileSystemCraeteOptions) (cloudprovider.ICloudFileSystem, error) { + fs, err := self.CreateFileSystem(opts) + if err != nil { + return nil, errors.Wrapf(err, "self.CreateFileSystem") + } + return fs, nil +} + +func (self *SRegion) CreateFileSystem(opts *cloudprovider.FileSystemCraeteOptions) (*SFileSystem, error) { + params := map[string]string{ + "RegionId": self.RegionId, + "ProtocolType": opts.Protocol, + "ZoneId": opts.ZoneId, + "EncryptType": "0", + "FileSystemType": opts.FileSystemType, + "StorageType": opts.StorageType, + "ClientToken": utils.GenRequestId(20), + "Description": opts.Name, + } + + if self.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV { + if opts.FileSystemType == "standard" { + opts.ZoneId = strings.Replace(opts.ZoneId, "cn-shanghai-finance-1", "jr-cn-shanghai-", 1) + opts.ZoneId = strings.Replace(opts.ZoneId, "cn-shenzhen-finance-1", "jr-cn-shenzhen-", 1) + params["ZoneId"] = opts.ZoneId + } + } + + switch opts.FileSystemType { + case "standard": + params["StorageType"] = utils.Capitalize(opts.StorageType) + case "cpfs": + params["ProtocolType"] = "cpfs" + switch opts.StorageType { + case "advance_100": + params["Bandwidth"] = "100" + case "advance_200": + params["Bandwidth"] = "200" + } + case "extreme": + params["Capacity"] = fmt.Sprintf("%d", opts.Capacity) + } + if len(opts.VpcId) > 0 { + params["VpcId"] = opts.VpcId + } + if len(opts.NetworkId) > 0 { + params["VSwitchId"] = opts.NetworkId + } + if opts.BillingCycle != nil { + params["ChargeType"] = "Subscription" + params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetMonths()) + } + resp, err := self.nasRequest("CreateFileSystem", params) + if err != nil { + return nil, errors.Wrapf(err, "CreateFileSystem") + } + fsId, _ := resp.GetString("FileSystemId") + return self.GetFileSystem(fsId) +} + +func (self *SFileSystem) SetTags(tags map[string]string, replace bool) error { + return self.region.SetResourceTags(ALIYUN_SERVICE_NAS, "filesystem", self.FileSystemId, tags, replace) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/host.go new file mode 100644 index 0000000000..669969d2f6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/host.go @@ -0,0 +1,295 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone +} + +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) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms := make([]SInstance, 0) + for { + parts, total, err := self.zone.region.GetInstances(self.zone.ZoneId, nil, len(vms), 50) + if err != nil { + return nil, err + } + vms = append(vms, parts...) + if len(vms) >= total { + break + } + } + 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) VMGlobalId2Id(gid string) string { + return gid +} + +func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) { + id := self.VMGlobalId2Id(gid) + parts, _, err := self.zone.region.GetInstances(self.zone.ZoneId, []string{id}, 0, 1) + if err != nil { + return nil, err + } + if len(parts) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(parts) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + parts[0].host = self + return &parts[0], nil +} + +func (self *SHost) GetId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) +} + +func (self *SHost) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) IsEmulated() bool { + return true +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) Refresh() error { + return nil +} + +func (self *SHost) GetHostStatus() string { + return api.HOST_ONLINE +} + +func (self *SHost) GetEnabled() bool { + return true +} + +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_ALIYUN), "manufacture") + return info +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetCpuCount() int { + 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 api.DISK_TYPE_HYBRID +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_ALIYUN +} + +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(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + vmId, err := self._createVM(desc.Name, desc.Hostname, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, + desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, + desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, desc.UserData, desc.BillingCycle, + desc.ProjectId, desc.OsType, desc.Tags, desc.SPublicIpInfo) + if err != nil { + return nil, err + } + vm, err := self.GetInstanceById(vmId) + if err != nil { + return nil, errors.Wrapf(err, "GetInstanceById") + } + return vm, nil +} + +func (self *SHost) _createVM(name, hostname string, imgId string, + sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, + vswitchId string, ipAddr string, desc string, passwd string, + dataDisks []cloudprovider.SDiskInfo, publicKey string, secgroupId string, + userData string, bc *billing.SBillingCycle, projectId, osType string, + tags map[string]string, publicIp cloudprovider.SPublicIpInfo, +) (string, error) { + net := self.zone.getNetworkById(vswitchId) + if net == nil { + return "", fmt.Errorf("invalid switch ID %s", vswitchId) + } + if net.wire == nil { + log.Errorf("vsiwtch's wire is empty") + return "", fmt.Errorf("vsiwtch's wire is empty") + } + if net.wire.vpc == nil { + log.Errorf("vsiwtch's wire' vpc is empty") + return "", fmt.Errorf("vsiwtch's wire's vpc is empty") + } + + var err error + keypair := "" + if len(publicKey) > 0 { + keypair, err = self.zone.region.syncKeypair(publicKey) + if err != nil { + return "", err + } + } + + img, err := self.zone.region.GetImage(imgId) + if err != nil { + log.Errorf("GetImage 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(dataDisks)+1) + disks[0].Size = img.Size + if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.Size { + disks[0].Size = sysDisk.SizeGB + } + storage, err := self.zone.getStorageByCategory(sysDisk.StorageType) + if err != nil { + return "", fmt.Errorf("Storage %s not avaiable: %s", sysDisk.StorageType, err) + } + disks[0].Category = storage.storageType + + for i, dataDisk := range dataDisks { + disks[i+1].Size = dataDisk.SizeGB + storage, err := self.zone.getStorageByCategory(dataDisk.StorageType) + if err != nil { + return "", fmt.Errorf("Storage %s not avaiable: %s", dataDisk.StorageType, err) + } + disks[i+1].Category = storage.storageType + } + + if len(instanceType) > 0 { + log.Debugf("Try instancetype : %s", instanceType) + vmId, err := self.zone.region.CreateInstance(name, hostname, imgId, instanceType, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId, osType, tags, publicIp) + if err != nil { + log.Errorf("Failed for %s: %s", instanceType, err) + return "", fmt.Errorf("Failed to create specification %s.%s", instanceType, err.Error()) + } + return vmId, nil + } + + 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) + } + + var vmId string + for _, instType := range instanceTypes { + instanceTypeId := instType.InstanceTypeId + log.Debugf("Try instancetype : %s", instanceTypeId) + vmId, err = self.zone.region.CreateInstance(name, hostname, imgId, instanceTypeId, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId, osType, tags, publicIp) + if err != nil { + log.Errorf("Failed for %s: %s", instanceTypeId, err) + } else { + return vmId, nil + } + } + + return "", fmt.Errorf("Failed to create, %s", err.Error()) +} + +func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (host *SHost) GetIsMaintenance() bool { + return false +} + +func (host *SHost) GetVersion() string { + return ALIYUN_API_VERSION +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/image.go new file mode 100644 index 0000000000..b24372d6d6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/image.go @@ -0,0 +1,398 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/aliyun/aliyun-oss-go-sdk/oss" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/apis" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type ImageStatusType string + +const ( + ImageStatusCreating ImageStatusType = "Creating" + ImageStatusAvailable ImageStatusType = "Available" + ImageStatusUnAvailable ImageStatusType = "UnAvailable" + ImageStatusCreateFailed ImageStatusType = "CreateFailed" +) + +type ImageOwnerType string + +const ( + ImageOwnerSystem ImageOwnerType = "system" + ImageOwnerSelf ImageOwnerType = "self" + ImageOwnerOthers ImageOwnerType = "others" + ImageOwnerMarketplace ImageOwnerType = "marketplace" +) + +type ImageUsageType string + +const ( + ImageUsageInstance ImageUsageType = "instance" + ImageUsageNone ImageUsageType = "none" +) + +type SImage struct { + multicloud.SImageBase + AliyunTags + storageCache *SStoragecache + + // normalized image info + imgInfo *imagetools.ImageInfo + + Architecture string + CreationTime time.Time + Description string + ImageId string + ImageName string + OSName string + OSType string + ImageOwnerAlias ImageOwnerType + IsSupportCloudinit bool + IsSupportIoOptimized bool + Platform string + Size int + Status ImageStatusType + Usage string +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SImage) GetId() string { + return self.ImageId +} + +func (self *SImage) GetName() string { + if self.ImageOwnerAlias == ImageOwnerSystem { + return self.OSName + } else { + return self.ImageName + } +} + +func (self *SImage) IsEmulated() bool { + return false +} + +func (self *SImage) Delete(ctx context.Context) error { + return self.storageCache.region.DeleteImage(self.ImageId) +} + +func (self *SImage) GetGlobalId() string { + return self.ImageId +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.storageCache +} + +func (self *SImage) GetStatus() string { + switch self.Status { + case ImageStatusCreating: + return api.CACHED_IMAGE_STATUS_SAVING + case ImageStatusAvailable: + return api.CACHED_IMAGE_STATUS_ACTIVE + case ImageStatusUnAvailable: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + case ImageStatusCreateFailed: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + default: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (self *SImage) GetImageStatus() string { + switch self.Status { + case ImageStatusCreating: + return cloudprovider.IMAGE_STATUS_QUEUED + case ImageStatusAvailable: + return cloudprovider.IMAGE_STATUS_ACTIVE + case ImageStatusUnAvailable: + return cloudprovider.IMAGE_STATUS_DELETED + case ImageStatusCreateFailed: + return cloudprovider.IMAGE_STATUS_KILLED + default: + return cloudprovider.IMAGE_STATUS_KILLED + } +} + +func (self *SImage) Refresh() error { + new, err := self.storageCache.region.GetImage(self.ImageId) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + switch self.ImageOwnerAlias { + case ImageOwnerSystem: + return cloudprovider.ImageTypeSystem + case ImageOwnerSelf: + return cloudprovider.ImageTypeCustomized + case ImageOwnerMarketplace: + return cloudprovider.ImageTypeMarket + case ImageOwnerOthers: + return cloudprovider.ImageTypeShared + default: + return cloudprovider.ImageTypeCustomized + } +} + +func (self *SImage) GetSizeByte() int64 { + return int64(self.Size) * 1024 * 1024 * 1024 +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) +} + +func (self *SImage) GetOsDist() string { + return self.getNormalizedImageInfo().OsDistro +} + +func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if self.imgInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(self.OSName, self.Architecture, self.OSType, self.Platform, "") + self.imgInfo = &imgInfo + } + + return self.imgInfo +} + +func (self *SImage) GetFullOsName() string { + return self.OSName +} + +func (self *SImage) GetOsVersion() string { + return self.getNormalizedImageInfo().OsVersion +} + +func (self *SImage) GetOsLang() string { + return self.getNormalizedImageInfo().OsLang +} + +func (self *SImage) GetOsArch() string { + return self.getNormalizedImageInfo().OsArch +} + +func (self *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return 40 +} + +func (self *SImage) GetImageFormat() string { + return "vhd" +} + +func (self *SImage) GetCreatedAt() time.Time { + return self.CreationTime +} + +type ImageExportTask struct { + ImageId string + RegionId string + // RequestId string + TaskId string +} + +func (self *SRegion) ExportImage(imageId string, bucket *oss.Bucket) (*ImageExportTask, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["ImageId"] = imageId + params["OssBucket"] = bucket.BucketName + params["OssPrefix"] = fmt.Sprintf("%sexport", strings.Replace(imageId, "-", "", -1)) + + if body, err := self.ecsRequest("ExportImage", params); err != nil { + return nil, err + } else { + result := ImageExportTask{} + if err := body.Unmarshal(&result); err != nil { + log.Errorf("unmarshal result error %s", err) + return nil, err + } + return &result, nil + } +} + +// {"ImageId":"m-j6c1qlpa7oebbg1n2k60","RegionId":"cn-hongkong","RequestId":"F8B2F6A1-F6AA-4C92-A54C-C4A309CF811F","TaskId":"t-j6c1qlpa7oebbg1rcl9t"} + +type ImageImportTask struct { + ImageId string + RegionId string + // RequestId string + TaskId string +} + +func (self *SRegion) ImportImage(name string, osArch string, osType string, osDist string, bucket string, key string) (*ImageImportTask, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["ImageName"] = name + if osDist == "RHEL" { + osDist = "CentOS" + } + params["Platform"] = osDist // "Others Linux" + params["OSType"] = osType // "linux" + switch osArch { + case apis.OS_ARCH_I386, apis.OS_ARCH_X86_32: + params["Architecture"] = "i386" + case apis.OS_ARCH_X86, apis.OS_ARCH_X86_64: + params["Architecture"] = "x86_64" + case apis.OS_ARCH_ARM, apis.OS_ARCH_AARCH32, apis.OS_ARCH_AARCH64: + params["Architecture"] = "arm64" + default: + params["Architecture"] = osArch // "x86_64" + } + params["DiskDeviceMapping.1.OSSBucket"] = bucket + params["DiskDeviceMapping.1.OSSObject"] = key + + log.Debugf("Upload image with params %#v", params) + + body, err := self.ecsRequest("ImportImage", params) + if err != nil { + log.Errorf("ImportImage fail %s", err) + return nil, err + } + + log.Infof("%s", body) + result := ImageImportTask{} + err = body.Unmarshal(&result) + if err != nil { + log.Errorf("unmarshal result error %s", err) + return nil, err + } + + return &result, nil +} + +func (self *SRegion) GetImage(imageId string) (*SImage, error) { + images, _, err := self.GetImages("", "", []string{imageId}, "", 0, 1) + if err != nil { + return nil, err + } + if len(images) == 0 { + return nil, cloudprovider.ErrNotFound + } + return &images[0], nil +} + +func (self *SRegion) GetImageByName(name string) (*SImage, error) { + images, _, err := self.GetImages("", "", 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) GetImagesBySnapshot(snapshotId string, offset int, limit int) ([]SImage, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + params["SnapshotId"] = snapshotId + + return self.getImages(params) +} + +func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) { + image, err := self.GetImage(imageId) + if err != nil { + return "", err + } + return image.Status, nil +} + +func (self *SRegion) GetImages(status ImageStatusType, owner ImageOwnerType, imageId []string, name string, offset int, limit int) ([]SImage, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if len(status) > 0 { + params["Status"] = string(status) + } else { + params["Status"] = "Creating,Available,UnAvailable,CreateFailed" + } + if imageId != nil && len(imageId) > 0 { + params["ImageId"] = strings.Join(imageId, ",") + } + if len(owner) > 0 { + params["ImageOwnerAlias"] = string(owner) + } + + if len(name) > 0 { + params["ImageName"] = name + } + + return self.getImages(params) +} + +func (self *SRegion) getImages(params map[string]string) ([]SImage, int, error) { + body, err := self.ecsRequest("DescribeImages", params) + if err != nil { + log.Errorf("DescribeImages fail %s", err) + return nil, 0, err + } + + images := make([]SImage, 0) + err = body.Unmarshal(&images, "Images", "Image") + if err != nil { + log.Errorf("unmarshal images fail %s", err) + return nil, 0, nil + } + total, _ := body.Int("TotalCount") + return images, int(total), nil +} + +func (self *SRegion) DeleteImage(imageId string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["ImageId"] = imageId + params["Force"] = "true" + + _, err := self.ecsRequest("DeleteImage", params) + if err != nil { + log.Errorf("DeleteImage fail %s", err) + return err + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/instance.go new file mode 100644 index 0000000000..4813fa2a6d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/instance.go @@ -0,0 +1,1183 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + "sort" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + "yunion.io/x/pkg/util/seclib" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +const ( + // Running:运行中 + //Starting:启动中 + //Stopping:停止中 + //Stopped:已停止 + + InstanceStatusStopped = "Stopped" + InstanceStatusRunning = "Running" + InstanceStatusStopping = "Stopping" + InstanceStatusStarting = "Starting" +) + +type SDedicatedHostAttribute struct { + DedicatedHostId string + DedicatedHostName string +} + +type SIpAddress struct { + IpAddress []string +} + +type SNetworkInterfaces struct { + NetworkInterface []SNetworkInterface +} + +type SOperationLocks struct { + LockReason []string +} + +type SSecurityGroupIds struct { + SecurityGroupId []string +} + +// {"NatIpAddress":"","PrivateIpAddress":{"IpAddress":["192.168.220.214"]},"VSwitchId":"vsw-2ze9cqwza4upoyujq1thd","VpcId":"vpc-2zer4jy8ix3i8f0coc5uw"} + +type SVpcAttributes struct { + NatIpAddress string + PrivateIpAddress SIpAddress + VSwitchId string + VpcId string +} + +type SInstance struct { + multicloud.SInstanceBase + AliyunTags + + host *SHost + + osInfo *imagetools.ImageInfo + + // idisks []cloudprovider.ICloudDisk + + AutoReleaseTime string + ClusterId string + Cpu int + CreationTime time.Time + DedicatedHostAttribute SDedicatedHostAttribute + Description string + DeviceAvailable bool + EipAddress SEipAddress + ExpiredTime time.Time + GPUAmount int + GPUSpec string + HostName string + ImageId string + InnerIpAddress SIpAddress + InstanceChargeType TChargeType + InstanceId string + InstanceName string + InstanceNetworkType string + InstanceType string + InstanceTypeFamily string + InternetChargeType TInternetChargeType + InternetMaxBandwidthIn int + InternetMaxBandwidthOut int + IoOptimized bool + KeyPairName string + Memory int + NetworkInterfaces SNetworkInterfaces + OSName string + OSType string + OperationLocks SOperationLocks + PublicIpAddress SIpAddress + Recyclable bool + RegionId string + ResourceGroupId string + SaleCycle string + SecurityGroupIds SSecurityGroupIds + SerialNumber string + SpotPriceLimit string + SpotStrategy string + StartTime time.Time + Status string + StoppedMode string + VlanId string + VpcAttributes SVpcAttributes + ZoneId string + Throughput int +} + +// {"AutoReleaseTime":"","ClusterId":"","Cpu":1,"CreationTime":"2018-05-23T07:58Z","DedicatedHostAttribute":{"DedicatedHostId":"","DedicatedHostName":""},"Description":"","DeviceAvailable":true,"EipAddress":{"AllocationId":"","InternetChargeType":"","IpAddress":""},"ExpiredTime":"2018-05-30T16:00Z","GPUAmount":0,"GPUSpec":"","HostName":"iZ2ze57isp1ali72tzkjowZ","ImageId":"centos_7_04_64_20G_alibase_201701015.vhd","InnerIpAddress":{"IpAddress":[]},"InstanceChargeType":"PrePaid","InstanceId":"i-2ze57isp1ali72tzkjow","InstanceName":"gaoxianqi-test-7days","InstanceNetworkType":"vpc","InstanceType":"ecs.t5-lc2m1.nano","InstanceTypeFamily":"ecs.t5","InternetChargeType":"PayByBandwidth","InternetMaxBandwidthIn":-1,"InternetMaxBandwidthOut":0,"IoOptimized":true,"Memory":512,"NetworkInterfaces":{"NetworkInterface":[{"MacAddress":"00:16:3e:10:f0:c9","NetworkInterfaceId":"eni-2zecqsagtpztl6x5hu2r","PrimaryIpAddress":"192.168.220.214"}]},"OSName":"CentOS 7.4 64位","OSType":"linux","OperationLocks":{"LockReason":[]},"PublicIpAddress":{"IpAddress":[]},"Recyclable":false,"RegionId":"cn-beijing","ResourceGroupId":"","SaleCycle":"Week","SecurityGroupIds":{"SecurityGroupId":["sg-2zecqsagtpztl6x9zynl"]},"SerialNumber":"df05d9b4-df3d-4400-88d1-5f843f0dd088","SpotPriceLimit":0.000000,"SpotStrategy":"NoSpot","StartTime":"2018-05-23T07:58Z","Status":"Running","StoppedMode":"Not-applicable","VlanId":"","VpcAttributes":{"NatIpAddress":"","PrivateIpAddress":{"IpAddress":["192.168.220.214"]},"VSwitchId":"vsw-2ze9cqwza4upoyujq1thd","VpcId":"vpc-2zer4jy8ix3i8f0coc5uw"},"ZoneId":"cn-beijing-f"} + +func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit int) ([]SInstance, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if len(zoneId) > 0 { + params["ZoneId"] = zoneId + } + + if ids != nil && len(ids) > 0 { + params["InstanceIds"] = jsonutils.Marshal(ids).String() + } + + body, err := self.ecsRequest("DescribeInstances", params) + if err != nil { + log.Errorf("GetInstances fail %s", err) + return nil, 0, err + } + + instances := make([]SInstance, 0) + err = body.Unmarshal(&instances, "Instances", "Instance") + if err != nil { + log.Errorf("Unmarshal security group details fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return instances, int(total), nil +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + return self.SecurityGroupIds.SecurityGroupId, nil +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetId() string { + return self.InstanceId +} + +func (self *SInstance) GetName() string { + if len(self.InstanceName) > 0 { + return self.InstanceName + } + return self.InstanceId +} + +func (self *SInstance) GetHostname() string { + return self.HostName +} + +func (self *SInstance) GetGlobalId() string { + return self.InstanceId +} + +func (self *SInstance) IsEmulated() bool { + return false +} + +func (self *SInstance) GetInstanceType() string { + return self.InstanceType +} + +func (self *SInstance) getVpc() (*SVpc, error) { + return self.host.zone.region.getVpc(self.VpcAttributes.VpcId) +} + +type byAttachedTime []SDisk + +func (a byAttachedTime) Len() int { return len(a) } +func (a byAttachedTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byAttachedTime) Less(i, j int) bool { + switch a[i].GetDiskType() { + case api.DISK_TYPE_SYS: + return true + case api.DISK_TYPE_SWAP: + switch a[j].GetDiskType() { + case api.DISK_TYPE_SYS: + return false + case api.DISK_TYPE_DATA: + return true + } + case api.DISK_TYPE_DATA: + if a[j].GetDiskType() != api.DISK_TYPE_DATA { + return false + } + } + return a[i].AttachedTime.Before(a[j].AttachedTime) +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks := []SDisk{} + for { + part, total, err := self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, len(disks), 50) + if err != nil { + return nil, errors.Wrapf(err, "GetDisks for %s", self.InstanceId) + } + disks = append(disks, part...) + if len(disks) >= total { + break + } + } + + sort.Sort(byAttachedTime(disks)) + + log.Debugf("%s", jsonutils.Marshal(&disks)) + + 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) { + var ( + networkInterfaces = self.NetworkInterfaces.NetworkInterface + nics []cloudprovider.ICloudNic + ) + for _, networkInterface := range networkInterfaces { + nic := SInstanceNic{ + instance: self, + id: networkInterface.NetworkInterfaceId, + ipAddr: networkInterface.PrimaryIpAddress, + macAddr: networkInterface.MacAddress, + } + nics = append(nics, &nic) + } + for _, classicIp := range self.InnerIpAddress.IpAddress { + nic := SInstanceNic{ + instance: self, + id: fmt.Sprintf("%s-%s", self.InstanceId, classicIp), + ipAddr: classicIp, + classic: true, + } + nics = append(nics, &nic) + } + return nics, nil +} + +func (self *SInstance) GetVcpuCount() int { + 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 (ins *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { + if ins.osInfo == nil { + osInfo := imagetools.NormalizeImageInfo(ins.OSName, "", ins.OSType, "", "") + ins.osInfo = &osInfo + } + return ins.osInfo +} + +func (self *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(osprofile.NormalizeOSType(self.OSType)) +} + +func (self *SInstance) GetFullOsName() string { + return self.OSName +} + +func (ins *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(ins.getNormalizedOsInfo().OsBios) +} + +func (ins *SInstance) GetOsArch() string { + return ins.getNormalizedOsInfo().OsArch +} + +func (ins *SInstance) GetOsDist() string { + return ins.getNormalizedOsInfo().OsDistro +} + +func (ins *SInstance) GetOsVersion() string { + return ins.getNormalizedOsInfo().OsVersion +} + +func (ins *SInstance) GetOsLang() string { + return ins.getNormalizedOsInfo().OsLang +} + +func (self *SInstance) GetMachine() string { + return "pc" +} + +func (self *SInstance) GetStatus() string { + // Running:运行中 + //Starting:启动中 + //Stopping:停止中 + //Stopped:已停止 + switch self.Status { + case InstanceStatusRunning: + return api.VM_RUNNING + case InstanceStatusStarting: + return api.VM_STARTING + case InstanceStatusStopping: + return api.VM_STOPPING + case InstanceStatusStopped: + return api.VM_READY + default: + return api.VM_UNKNOWN + } +} + +func (self *SInstance) Refresh() error { + ins, err := self.host.zone.region.GetInstance(self.InstanceId) + if err != nil { + return err + } + return jsonutils.Update(self, ins) +} + +/* +func (self *SInstance) GetRemoteStatus() string { + // Running:运行中 + //Starting:启动中 + //Stopping:停止中 + //Stopped:已停止 + switch self.Status { + case InstanceStatusRunning: + return cloudprovider.CloudVMStatusRunning + case InstanceStatusStarting: + return cloudprovider.CloudVMStatusStopped + case InstanceStatusStopping: + return cloudprovider.CloudVMStatusRunning + case InstanceStatusStopped: + return cloudprovider.CloudVMStatusStopped + default: + return cloudprovider.CloudVMStatusOther + } +} +*/ + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_ALIYUN +} + +func (self *SInstance) StartVM(ctx context.Context) 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(), api.VM_RUNNING) + if self.GetStatus() == api.VM_RUNNING { + return nil + } else if self.GetStatus() == api.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(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + err := self.host.zone.region.StopVM(self.InstanceId, opts.IsForce, opts.StopCharging) + if err != nil { + return err + } + return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + url, err := self.host.zone.region.GetInstanceVNCUrl(self.InstanceId) + if err != nil { + return nil, err + } + passwd := seclib.RandomPassword(6) + err = self.host.zone.region.ModifyInstanceVNCUrlPassword(self.InstanceId, passwd) + if err != nil { + return nil, err + } + ret := &cloudprovider.ServerVncOutput{ + Url: url, + Password: passwd, + Protocol: "aliyun", + InstanceId: self.InstanceId, + Hypervisor: api.HYPERVISOR_ALIYUN, + } + return ret, nil +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return self.host.zone.region.UpdateVM(self.InstanceId, name, self.OSType) +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + var keypairName string + if len(publicKey) > 0 { + var err error + keypairName, err = self.host.zone.region.syncKeypair(publicKey) + if err != nil { + return err + } + } + + return self.host.zone.region.DeployVM(self.InstanceId, name, password, keypairName, deleteKeypair, description) +} + +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + keypair := "" + if len(desc.PublicKey) > 0 { + var err error + keypair, err = self.host.zone.region.syncKeypair(desc.PublicKey) + if err != nil { + return "", err + } + } + diskId, err := self.host.zone.region.ReplaceSystemDisk(self.InstanceId, desc.ImageId, desc.Password, keypair, desc.SysSizeGB) + if err != nil { + return "", err + } + + return diskId, nil +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + isDowngrade, isPrepaid := false, self.GetBillingType() == billing_api.BILLING_TYPE_PREPAID + if (self.GetVcpuCount() > config.Cpu && config.Cpu > 0) || (self.GetVmemSizeMB() > config.MemoryMB && config.MemoryMB > 0) { + isDowngrade = true + } + + instanceTypes := []string{} + + if len(config.InstanceType) > 0 { + instanceTypes = []string{config.InstanceType} + } else { + specs, err := self.host.zone.region.GetMatchInstanceTypes(config.Cpu, config.MemoryMB, 0, self.ZoneId) + if err != nil { + return errors.Wrapf(err, "GetMatchInstanceTypes") + } + for _, spec := range specs { + instanceTypes = append(instanceTypes, spec.InstanceTypeId) + } + } + + var err error + for _, instanceType := range instanceTypes { + if isPrepaid { + err = self.host.zone.region.ChangePrepaidVMConfig(self.InstanceId, instanceType, isDowngrade) + if err != nil { + log.Errorf("ChangePrepaidVMConfig %s error: %v", instanceType, err) + continue + } + } else { + err = self.host.zone.region.ChangeVMConfig(self.InstanceId, instanceType) + if err != nil { + log.Errorf("ChangeVMConfig %s error: %v", instanceType, err) + continue + } + } + return nil + } + if err != nil { + return errors.Wrapf(err, "ChangeVMConfig") + } + + return fmt.Errorf("Failed to change vm config, specification not supported") +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return self.host.zone.region.AttachDisk(self.InstanceId, diskId) +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return cloudprovider.RetryOnError( + func() error { + return self.host.zone.region.DetachDisk(self.InstanceId, diskId) + }, + []string{ + `"Code":"InvalidOperation.Conflict"`, + }, + 4) +} + +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) CreateInstance(name, hostname string, imageId string, instanceType string, securityGroupId string, + zoneId string, desc string, passwd string, disks []SDisk, vSwitchId string, ipAddr string, + keypair string, userData string, bc *billing.SBillingCycle, projectId, osType string, + tags map[string]string, publicIp cloudprovider.SPublicIpInfo, +) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["ImageId"] = imageId + params["InstanceType"] = instanceType + params["SecurityGroupId"] = securityGroupId + params["ZoneId"] = zoneId + params["InstanceName"] = name + if len(hostname) > 0 { + params["HostName"] = hostname + } + params["Description"] = desc + params["InternetChargeType"] = "PayByTraffic" + params["InternetMaxBandwidthIn"] = "200" + params["InternetMaxBandwidthOut"] = "100" + if publicIp.PublicIpBw > 0 { + params["InternetMaxBandwidthOut"] = fmt.Sprintf("%d", publicIp.PublicIpBw) + } + if publicIp.PublicIpChargeType == cloudprovider.ElasticipChargeTypeByBandwidth { + params["InternetChargeType"] = "PayByBandwidth" + } + if len(passwd) > 0 { + params["Password"] = passwd + } else { + params["PasswordInherit"] = "True" + } + + if len(projectId) > 0 { + params["ResourceGroupId"] = projectId + } + //{"Code":"InvalidSystemDiskCategory.ValueNotSupported","HostId":"ecs.aliyuncs.com","Message":"The specified parameter 'SystemDisk.Category' is not support IoOptimized Instance. Valid Values: cloud_efficiency;cloud_ssd. ","RequestId":"9C9A4E99-5196-42A2-80B6-4762F8F75C90"} + params["IoOptimized"] = "optimized" + for i, d := range disks { + if i == 0 { + params["SystemDisk.Category"] = d.Category + if d.Category == api.STORAGE_CLOUD_ESSD_PL2 { + params["SystemDisk.Category"] = api.STORAGE_CLOUD_ESSD + params["SystemDisk.PerformanceLevel"] = "PL2" + } + if d.Category == api.STORAGE_CLOUD_ESSD_PL3 { + params["SystemDisk.Category"] = api.STORAGE_CLOUD_ESSD + params["SystemDisk.PerformanceLevel"] = "PL3" + } + params["SystemDisk.Size"] = fmt.Sprintf("%d", d.Size) + params["SystemDisk.DiskName"] = d.GetName() + params["SystemDisk.Description"] = d.Description + } else { + params[fmt.Sprintf("DataDisk.%d.Size", i)] = fmt.Sprintf("%d", d.Size) + params[fmt.Sprintf("DataDisk.%d.Category", i)] = d.Category + if d.Category == api.STORAGE_CLOUD_ESSD_PL2 { + params[fmt.Sprintf("DataDisk.%d.Category", i)] = api.STORAGE_CLOUD_ESSD + params[fmt.Sprintf("DataDisk.%d..PerformanceLevel", i)] = "PL2" + } + if d.Category == api.STORAGE_CLOUD_ESSD_PL3 { + params[fmt.Sprintf("DataDisk.%d.Category", i)] = api.STORAGE_CLOUD_ESSD + params[fmt.Sprintf("DataDisk.%d..PerformanceLevel", i)] = "PL3" + } + params[fmt.Sprintf("DataDisk.%d.DiskName", i)] = d.GetName() + params[fmt.Sprintf("DataDisk.%d.Description", i)] = d.Description + params[fmt.Sprintf("DataDisk.%d.Encrypted", i)] = "false" + } + } + params["VSwitchId"] = vSwitchId + params["PrivateIpAddress"] = ipAddr + + if len(keypair) > 0 { + params["KeyPairName"] = keypair + } + + if len(userData) > 0 { + params["UserData"] = userData + } + + if len(tags) > 0 { + tagIdx := 1 + for k, v := range tags { + params[fmt.Sprintf("Tag.%d.Key", tagIdx)] = k + params[fmt.Sprintf("Tag.%d.Value", tagIdx)] = v + tagIdx += 1 + } + } + + if bc != nil { + params["InstanceChargeType"] = "PrePaid" + err := billingCycle2Params(bc, params) + if err != nil { + return "", err + } + if bc.AutoRenew { + params["AutoRenew"] = "true" + params["AutoRenewPeriod"] = "1" + } else { + params["AutoRenew"] = "False" + } + } else { + params["InstanceChargeType"] = "PostPaid" + params["SpotStrategy"] = "NoSpot" + } + + params["ClientToken"] = utils.GenRequestId(20) + + body, err := self.ecsRequest("CreateInstance", params) + if err != nil { + log.Errorf("CreateInstance fail %s", err) + return "", err + } + instanceId, _ := body.GetString("InstanceId") + return instanceId, nil +} + +func (self *SRegion) AllocatePublicIpAddress(instanceId string) (string, error) { + params := map[string]string{ + "InstanceId": instanceId, + } + resp, err := self.ecsRequest("AllocatePublicIpAddress", params) + if err != nil { + return "", errors.Wrapf(err, "AllocatePublicIpAddress") + } + return resp.GetString("IpAddress") +} + +func (self *SInstance) AllocatePublicIpAddress() (string, error) { + return self.host.zone.region.AllocatePublicIpAddress(self.InstanceId) +} + +func (self *SRegion) doStartVM(instanceId string) error { + return self.instanceOperation(instanceId, "StartInstance", nil) +} + +func (self *SRegion) doStopVM(instanceId string, isForce, stopCharging bool) error { + params := make(map[string]string) + if isForce { + params["ForceStop"] = "true" + } else { + params["ForceStop"] = "false" + } + params["StoppedMode"] = "KeepCharging" + if stopCharging { + params["StoppedMode"] = "StopCharging" + } + return self.instanceOperation(instanceId, "StopInstance", params) +} + +func (self *SRegion) doDeleteVM(instanceId string) error { + params := make(map[string]string) + params["TerminateSubscription"] = "true" // terminate expired prepaid instance + params["Force"] = "true" + return self.instanceOperation(instanceId, "DeleteInstance", params) +} + +/*func (self *SRegion) waitInstanceStatus(instanceId string, target string, interval time.Duration, timeout time.Duration) error { + startTime := time.Now() + for time.Now().Sub(startTime) < timeout { + status, err := self.GetInstanceStatus(instanceId) + if err != nil { + return err + } + if status == target { + return nil + } + time.Sleep(interval) + } + return cloudprovider.ErrTimeout +} + +func (self *SInstance) waitStatus(target string, interval time.Duration, timeout time.Duration) error { + return self.host.zone.region.waitInstanceStatus(self.InstanceId, target, interval, timeout) +}*/ + +func (self *SRegion) StartVM(instanceId string) error { + status, err := self.GetInstanceStatus(instanceId) + if err != nil { + log.Errorf("Fail to get instance status on StartVM: %s", err) + return err + } + if status != InstanceStatusStopped { + log.Errorf("StartVM: vm status is %s expect %s", status, InstanceStatusStopped) + return cloudprovider.ErrInvalidStatus + } + return self.doStartVM(instanceId) + // if err != nil { + // return err + // } + // return self.waitInstanceStatus(instanceId, InstanceStatusRunning, time.Second*5, time.Second*180) // 3 minutes to timeout +} + +func (self *SRegion) StopVM(instanceId string, isForce, stopCharging bool) error { + status, err := self.GetInstanceStatus(instanceId) + if err != nil { + log.Errorf("Fail to get instance status on StopVM: %s", err) + return err + } + if status == InstanceStatusStopped { + return nil + } + if status != InstanceStatusRunning { + log.Errorf("StopVM: vm status is %s expect %s", status, InstanceStatusRunning) + return cloudprovider.ErrInvalidStatus + } + return self.doStopVM(instanceId, isForce, stopCharging) + // if err != nil { + // return err + // } + // return self.waitInstanceStatus(instanceId, InstanceStatusStopped, time.Second*10, time.Second*300) // 5 minutes to timeout +} + +func (self *SRegion) DeleteVM(instanceId string) error { + status, err := self.GetInstanceStatus(instanceId) + if err != nil { + log.Errorf("Fail to get instance status on DeleteVM: %s", err) + return err + } + log.Debugf("Instance status on delete is %s", status) + if status != InstanceStatusStopped { + log.Warningf("DeleteVM: vm status is %s expect %s", status, InstanceStatusStopped) + } + return self.doDeleteVM(instanceId) + // if err != nil { + // return err + // } + // err = self.waitInstanceStatus(instanceId, InstanceStatusRunning, time.Second*10, time.Second*300) // 5 minutes to timeout + // if err == cloudprovider.ErrNotFound { + // return nil + // } else if err == nil { + // return cloudprovider.ErrTimeout + // } else { + // return err + // } +} + +func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { + instance, err := self.GetInstance(instanceId) + if err != nil { + return err + } + + // 修改密钥时直接返回 + if deleteKeypair { + err = self.DetachKeyPair(instanceId, instance.KeyPairName) + if err != nil { + return err + } + } + + if len(keypairName) > 0 { + err = self.AttachKeypair(instanceId, keypairName) + if err != nil { + return err + } + } + + params := make(map[string]string) + + // if resetPassword { + // params["Password"] = seclib2.RandomPassword2(12) + // } + // 指定密码的情况下,使用指定的密码 + if len(password) > 0 { + params["Password"] = password + } + + if len(name) > 0 && instance.InstanceName != name { + params["InstanceName"] = name + } + + if len(description) > 0 && instance.Description != description { + params["Description"] = description + } + + if len(params) > 0 { + return self.modifyInstanceAttribute(instanceId, params) + } else { + return nil + } +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + for { + err := self.host.zone.region.DeleteVM(self.InstanceId) + if err != nil { + if isError(err, "IncorrectInstanceStatus.Initializing") { + log.Infof("The instance is initializing, try later ...") + time.Sleep(10 * time.Second) + } else { + log.Errorf("DeleteVM fail: %s", err) + return err + } + } else { + break + } + } + return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes +} + +func (self *SRegion) UpdateVM(instanceId string, name, osType string) error { + /* + api: ModifyInstanceAttribute + https://help.aliyun.com/document_detail/25503.html?spm=a2c4g.11186623.4.1.DrgpjW + */ + params := make(map[string]string) + params["InstanceName"] = name + return self.modifyInstanceAttribute(instanceId, params) +} + +func (self *SRegion) modifyInstanceAttribute(instanceId string, params map[string]string) error { + return self.instanceOperation(instanceId, "ModifyInstanceAttribute", params) +} + +func (self *SRegion) ReplaceSystemDisk(instanceId string, imageId string, passwd string, keypairName string, sysDiskSizeGB int) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + params["ImageId"] = imageId + if len(passwd) > 0 { + params["Password"] = passwd + } else { + params["PasswordInherit"] = "True" + } + if len(keypairName) > 0 { + params["KeyPairName"] = keypairName + } + if sysDiskSizeGB > 0 { + params["SystemDisk.Size"] = fmt.Sprintf("%d", sysDiskSizeGB) + } + body, err := self.ecsRequest("ReplaceSystemDisk", params) + if err != nil { + return "", err + } + // log.Debugf("%s", body.String()) + return body.GetString("DiskId") +} + +func (self *SRegion) ChangePrepaidVMConfig(instanceId string, instanceType string, isDowngrade bool) error { + // todo: support change disk config? + params := make(map[string]string) + params["InstanceType"] = instanceType + params["ClientToken"] = utils.GenRequestId(20) + if isDowngrade { + params["OperatorType"] = "downgrade" + } + err := self.instanceOperation(instanceId, "ModifyPrepayInstanceSpec", params) + if err != nil { + return errors.Wrapf(err, "ModifyPrepayInstanceSpec %s", instanceType) + } + return nil +} + +func (self *SRegion) ChangeVMConfig(instanceId string, instanceType string) error { + // todo: support change disk config? + params := make(map[string]string) + params["InstanceType"] = instanceType + params["ClientToken"] = utils.GenRequestId(20) + err := self.instanceOperation(instanceId, "ModifyInstanceSpec", params) + if err != nil { + return errors.Wrapf(err, "ModifyInstanceSpec %s", instanceType) + } + return nil +} + +func (self *SRegion) DetachDisk(instanceId string, diskId string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["DiskId"] = diskId + log.Infof("Detach instance %s disk %s", instanceId, diskId) + _, err := self.ecsRequest("DetachDisk", params) + if err != nil { + if strings.Contains(err.Error(), "The specified disk has not been attached on the specified instance") { + return nil + } + return errors.Wrap(err, "DetachDisk") + } + + return nil +} + +func (self *SRegion) AttachDisk(instanceId string, diskId string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["DiskId"] = diskId + _, err := self.ecsRequest("AttachDisk", params) + if err != nil { + log.Errorf("AttachDisk %s to %s fail %s", diskId, instanceId, err) + return err + } + + return nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + if len(self.EipAddress.IpAddress) > 0 { + return self.host.zone.region.GetEip(self.EipAddress.AllocationId) + } + 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.InstanceType = EIP_INSTANCE_TYPE_ECS + eip.Status = EIP_STATUS_INUSE + eip.AllocationId = self.InstanceId // fixed + eip.AllocationTime = self.CreationTime + eip.Bandwidth = self.InternetMaxBandwidthOut + eip.ResourceGroupId = self.ResourceGroupId + eip.InternetChargeType = self.InternetChargeType + return &eip, nil + } + return nil, nil +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.host.zone.region.AssignSecurityGroup(secgroupId, self.InstanceId) +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + return self.host.zone.region.SetSecurityGroups(secgroupIds, self.InstanceId) +} + +func (self *SInstance) GetBillingType() string { + return convertChargeType(self.InstanceChargeType) +} + +func (self *SInstance) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SInstance) GetExpiredAt() time.Time { + return convertExpiredAt(self.ExpiredTime) +} + +func (self *SInstance) UpdateUserData(userData string) error { + return self.host.zone.region.updateInstance(self.InstanceId, "", "", "", "", userData) +} + +func (self *SInstance) Renew(bc billing.SBillingCycle) error { + return self.host.zone.region.RenewInstance(self.InstanceId, bc) +} + +func (self *SInstance) GetThroughput() int { + return self.Throughput +} + +func (self *SInstance) GetInternetMaxBandwidthOut() int { + return self.InternetMaxBandwidthOut +} + +func billingCycle2Params(bc *billing.SBillingCycle, params map[string]string) error { + if bc.GetMonths() > 0 { + params["PeriodUnit"] = "Month" + params["Period"] = fmt.Sprintf("%d", bc.GetMonths()) + } else if bc.GetWeeks() > 0 { + params["PeriodUnit"] = "Week" + params["Period"] = fmt.Sprintf("%d", bc.GetWeeks()) + } else { + return fmt.Errorf("invalid renew time period %s", bc.String()) + } + return nil +} + +func (region *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + err := billingCycle2Params(&bc, params) + if err != nil { + return err + } + params["ClientToken"] = utils.GenRequestId(20) + _, err = region.ecsRequest("RenewInstance", params) + if err != nil { + log.Errorf("RenewInstance fail %s", err) + return err + } + return nil +} + +func (self *SInstance) GetProjectId() string { + return self.ResourceGroupId +} + +func (self *SInstance) GetError() error { + return nil +} + +func (region *SRegion) ConvertPublicIpToEip(instanceId string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["RegionId"] = region.RegionId + _, err := region.ecsRequest("ConvertNatPublicIpToEip", params) + return err +} + +func (self *SInstance) ConvertPublicIpToEip() error { + err := self.host.zone.region.ConvertPublicIpToEip(self.InstanceId) + if err != nil { + return errors.Wrapf(err, "ConvertPublicIpToEip") + } + return cloudprovider.Wait(time.Second*5, time.Minute*5, func() (bool, error) { + self.Refresh() + iEip, err := self.GetIEIP() + if err != nil { + return false, errors.Wrapf(err, "GetIEIP") + } + if iEip == nil { + return false, nil + } + if iEip.GetMode() == api.EIP_MODE_STANDALONE_EIP { + return true, self.host.zone.region.VpcMoveResourceGroup("eip", self.ResourceGroupId, iEip.GetId()) + } + return false, nil + }) +} + +func (self *SRegion) VpcMoveResourceGroup(resType, groupId, resId string) error { + params := map[string]string{ + "RegionId": self.RegionId, + "ResourceType": resType, + "NewResourceGroupId": groupId, + "ResourceId": resId, + } + _, err := self.vpcRequest("MoveResourceGroup", params) + return errors.Wrapf(err, "MoveResourceGroup") +} + +// https://help.aliyun.com/document_detail/52843.html +func (region *SRegion) SetInstanceAutoRenew(instanceId string, bc billing.SBillingCycle) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["RegionId"] = region.RegionId + if bc.AutoRenew { + params["RenewalStatus"] = "AutoRenewal" + switch bc.Unit { + case billing.BillingCycleYear: + params["Duration"] = fmt.Sprintf("%d", bc.GetYears()) + params["PeriodUnit"] = "Year" + case billing.BillingCycleMonth: + params["Duration"] = fmt.Sprintf("%d", bc.GetMonths()) + params["PeriodUnit"] = "Month" + case billing.BillingCycleWeek: + params["Duration"] = fmt.Sprintf("%d", bc.GetWeeks()) + params["PeriodUnit"] = "Week" + } + } else { + params["RenewalStatus"] = "Normal" + } + _, err := region.ecsRequest("ModifyInstanceAutoRenewAttribute", params) + return err +} + +type SAutoRenewAttr struct { + Duration int + AutoRenewEnabled bool + RenewalStatus string + PeriodUnit string +} + +func (region *SRegion) GetInstanceAutoRenewAttribute(instanceId string) (*SAutoRenewAttr, error) { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["RegionId"] = region.RegionId + resp, err := region.ecsRequest("DescribeInstanceAutoRenewAttribute", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeInstanceAutoRenewAttribute") + } + attr := []SAutoRenewAttr{} + err = resp.Unmarshal(&attr, "InstanceRenewAttributes", "InstanceRenewAttribute") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + if len(attr) == 1 { + return &attr[0], nil + } + return nil, fmt.Errorf("get %d auto renew info", len(attr)) +} + +func (self *SInstance) IsAutoRenew() bool { + attr, err := self.host.zone.region.GetInstanceAutoRenewAttribute(self.InstanceId) + if err != nil { + log.Errorf("failed to get instance %s auto renew info", self.InstanceId) + return false + } + return attr.AutoRenewEnabled +} + +func (self *SInstance) SetAutoRenew(bc billing.SBillingCycle) error { + return self.host.zone.region.SetInstanceAutoRenew(self.InstanceId, bc) +} + +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { + return self.host.zone.region.SetResourceTags(ALIYUN_SERVICE_ECS, "instance", self.InstanceId, tags, replace) +} + +func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { + params := map[string]string{ + "InstanceId": instanceId, + "ImageName": opts.Name, + "Description": opts.Notes, + "ClientToken": utils.GenRequestId(20), + } + resp, err := self.ecsRequest("CreateImage", params) + if err != nil { + return nil, errors.Wrapf(err, "CreateImage") + } + ret := struct{ ImageId string }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + image, err := self.GetImage(ret.ImageId) + if err != nil { + return nil, errors.Wrapf(err, "GetImage(%s)", ret.ImageId) + } + image.storageCache = self.getStoragecache() + return image, nil +} + +func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { + image, err := self.host.zone.region.SaveImage(self.InstanceId, opts) + if err != nil { + return nil, errors.Wrapf(err, "SaveImage(%s)", opts.Name) + } + return image, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/instancenic.go new file mode 100644 index 0000000000..2143d756cd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/instancenic.go @@ -0,0 +1,234 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "time" + + alierr "github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors" + "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + instance *SInstance + id string + ipAddr string + macAddr string + + classic bool + + cloudprovider.DummyICloudNic +} + +func (self *SInstanceNic) GetId() string { + return self.id +} + +func (self *SInstanceNic) mustGetId() string { + if self.id == "" { + panic("empty network interface id") + } + return self.id +} + +func (self *SInstanceNic) GetIP() string { + return self.ipAddr +} + +func (self *SInstanceNic) GetMAC() string { + if len(self.macAddr) > 0 { + return self.macAddr + } + ip, _ := netutils.NewIPV4Addr(self.GetIP()) + return ip.ToMac("00:16:") +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return self.classic == true +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) GetINetworkId() string { + return self.instance.VpcAttributes.VSwitchId +} + +func (self *SInstanceNic) GetSubAddress() ([]string, error) { + selfId := self.mustGetId() + region := self.instance.host.zone.region + params := map[string]string{ + "RegionId": region.GetId(), + "NetworkInterfaceId.1": selfId, + } + body, err := region.ecsRequest("DescribeNetworkInterfaces", params) + if err != nil { + return nil, err + } + + type DescribeNetworkInterfacesResponse struct { + TotalCount int `json:"TotalCount"` + RequestID string `json:"RequestId"` + PageSize int `json:"PageSize"` + NextToken string `json:"NextToken"` + PageNumber int `json:"PageNumber"` + NetworkInterfaceSets struct { + NetworkInterfaceSet []struct { + Status string `json:"Status"` + PrivateIPAddress string `json:"PrivateIpAddress"` + ZoneID string `json:"ZoneId"` + ResourceGroupID string `json:"ResourceGroupId"` + InstanceID string `json:"InstanceId"` + VSwitchID string `json:"VSwitchId"` + NetworkInterfaceID string `json:"NetworkInterfaceId"` + MacAddress string `json:"MacAddress"` + SecurityGroupIds struct { + SecurityGroupID []string `json:"SecurityGroupId"` + } `json:"SecurityGroupIds"` + Type string `json:"Type"` + Ipv6Sets struct { + Ipv6Set []struct { + Ipv6Address string `json:"Ipv6Address"` + } `json:"Ipv6Set"` + } `json:"Ipv6Sets"` + VpcID string `json:"VpcId"` + OwnerID string `json:"OwnerId"` + AssociatedPublicIP struct { + } `json:"AssociatedPublicIp"` + CreationTime time.Time `json:"CreationTime"` + Tags struct { + Tag []struct { + TagKey string `json:"TagKey"` + TagValue string `json:"TagValue"` + } `json:"Tag"` + } `json:"Tags"` + PrivateIPSets struct { + PrivateIPSet []struct { + PrivateIPAddress string `json:"PrivateIpAddress"` + AssociatedPublicIP struct { + } `json:"AssociatedPublicIp"` + Primary bool `json:"Primary"` + } `json:"PrivateIpSet"` + } `json:"PrivateIpSets"` + } `json:"NetworkInterfaceSet"` + } `json:"NetworkInterfaceSets"` + } + var resp DescribeNetworkInterfacesResponse + if err := body.Unmarshal(&resp); err != nil { + return nil, errors.Wrapf(err, "unmarshal DescribeNetworkInterfacesResponse: %s", body) + } + if got := len(resp.NetworkInterfaceSets.NetworkInterfaceSet); got != 1 { + return nil, errors.Errorf("got %d element(s) in interface set, expect 1", got) + } + var ( + ipAddrs []string + networkInterface = resp.NetworkInterfaceSets.NetworkInterfaceSet[0] + ) + if got := networkInterface.NetworkInterfaceID; got != selfId { + return nil, errors.Errorf("got interface data for %s, expect %s", got, selfId) + } + for _, privateIP := range networkInterface.PrivateIPSets.PrivateIPSet { + if !privateIP.Primary { + ipAddrs = append(ipAddrs, privateIP.PrivateIPAddress) + } + } + return ipAddrs, nil +} + +func (self *SInstanceNic) ipAddrsParams(ipAddrs []string) map[string]string { + region := self.instance.host.zone.region + params := map[string]string{ + "RegionId": region.GetId(), + "NetworkInterfaceId": self.mustGetId(), + } + for i, ipAddr := range ipAddrs { + k := fmt.Sprintf("PrivateIpAddress.%d", i+1) + params[k] = ipAddr + } + return params +} + +func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { + var ( + selfId = self.mustGetId() + instance = self.instance + zone = instance.host.zone + region = zone.region + ) + ecsClient, err := region.getEcsClient() + if err != nil { + return err + } + request := ecs.CreateAssignPrivateIpAddressesRequest() + request.Scheme = "https" + + request.NetworkInterfaceId = selfId + request.PrivateIpAddress = &ipAddrs + resp, err := ecsClient.AssignPrivateIpAddresses(request) + if err != nil { + if aerr, ok := err.(*alierr.ServerError); ok { + if aerr.ErrorCode() == "InvalidOperation.Ipv4CountExceeded" { + return errors.Wrap(cloudprovider.ErrAddressCountExceed, aerr.Message()) + } + } + return errors.Wrapf(err, "AssignPrivateIpAddresses") + } + + allocated := resp.AssignedPrivateIpAddressesSet.PrivateIpSet.PrivateIpAddress + if len(allocated) != len(ipAddrs) { + return errors.Errorf("AssignAddress want %d addresses, got %d", len(ipAddrs), len(allocated)) + } + for i := 0; i < len(ipAddrs); i++ { + ip0 := ipAddrs[i] + ip1 := allocated[i] + if ip0 != ip1 { + return errors.Errorf("AssignAddress address %d does not match: want %s, got %s", i, ip0, ip1) + } + } + return nil +} + +func (self *SInstanceNic) UnassignAddress(ipAddrs []string) error { + var ( + selfId = self.mustGetId() + instance = self.instance + zone = instance.host.zone + region = zone.region + ) + ecsClient, err := region.getEcsClient() + if err != nil { + return err + } + request := ecs.CreateUnassignPrivateIpAddressesRequest() + request.Scheme = "https" + + request.NetworkInterfaceId = selfId + request.PrivateIpAddress = &ipAddrs + resp, err := ecsClient.UnassignPrivateIpAddresses(request) + if err != nil { + if resp.GetHttpStatus() == 404 { + return nil + } + return err + } + return nil +} diff --git a/pkg/multicloud/aliyun/instancetype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/instancetype.go similarity index 100% rename from pkg/multicloud/aliyun/instancetype.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/instancetype.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kafka.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kafka.go new file mode 100644 index 0000000000..339eae2cfa --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kafka.go @@ -0,0 +1,320 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SKafka struct { + multicloud.SBillingBase + multicloud.SVirtualResourceBase + AliyunTags + region *SRegion + + AllConfig string `json:"AllConfig"` + DeployType int `json:"DeployType"` + SpecType string `json:"SpecType"` + PaidType int `json:"PaidType"` + InstanceId string `json:"InstanceId"` + MsgRetain int `json:"MsgRetain"` + ZoneId string `json:"ZoneId"` + IoMax int `json:"IoMax"` + VSwitchId string `json:"VSwitchId"` + VpcId string `json:"VpcId"` + UpgradeServiceDetailInfo struct { + Current2OpenSourceVersion string `json:"Current2OpenSourceVersion"` + } `json:"UpgradeServiceDetailInfo"` + ServiceStatus int `json:"ServiceStatus"` + Name string `json:"Name"` + TopicNumLimit int `json:"TopicNumLimit"` + DiskSize int `json:"DiskSize"` + RegionId string `json:"RegionId"` + CreateTime int64 `json:"CreateTime"` + SslEndPoint string `json:"SslEndPoint"` + EipMax int `json:"EipMax"` + EndPoint string `json:"EndPoint"` + ExpiredTime int64 `json:"ExpiredTime"` + DiskType int `json:"DiskType"` + SecurityGroup string `json:"SecurityGroup"` +} + +func (self *SKafka) GetName() string { + return self.Name +} + +func (self *SKafka) GetGlobalId() string { + return self.InstanceId +} + +func (self *SKafka) GetId() string { + return self.InstanceId +} + +func (self *SKafka) GetVpcId() string { + return self.VpcId +} + +func (self *SKafka) GetNetworkId() string { + return self.VSwitchId +} + +func (self *SKafka) GetCreatedAt() time.Time { + return time.Unix(self.CreateTime/1000, self.CreateTime%1000) +} + +func (self *SKafka) GetBillingType() string { + if self.PaidType == 0 { + return billing_api.BILLING_TYPE_PREPAID + } + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SKafka) GetInstanceType() string { + return self.SpecType +} + +func (self *SKafka) GetDiskSizeGb() int { + return self.DiskSize +} + +func (self *SKafka) GetVersion() string { + return self.UpgradeServiceDetailInfo.Current2OpenSourceVersion +} + +func (self *SKafka) IsMultiAz() bool { + return false +} + +func (self *SKafka) GetStorageType() string { + switch self.DiskType { + case 0: + return api.STORAGE_CLOUD_EFFICIENCY + case 1: + return api.STORAGE_CLOUD_SSD + } + return "" +} + +func (self *SKafka) GetBandwidthMb() int { + if self.EipMax > 0 { + return self.EipMax + } + return self.IoMax +} + +func (self *SKafka) GetEndpoint() string { + ret := []string{} + if len(self.EndPoint) > 0 { + ret = append(ret, self.EndPoint) + } + if len(self.SslEndPoint) > 0 { + ret = append(ret, self.SslEndPoint) + } + return strings.Join(ret, ",") +} + +func (self *SKafka) GetMsgRetentionMinute() int { + return self.MsgRetain * 60 +} + +func (self *SKafka) GetZoneId() string { + if len(self.ZoneId) > 0 { + return fmt.Sprintf("%s-%s", self.RegionId, strings.TrimPrefix(self.ZoneId, "zone")) + } + return "" +} + +func (self *SKafka) GetStatus() string { + switch self.ServiceStatus { + case 0, 1, 2: + return api.KAFKA_STATUS_CREATING + case 5: + return api.KAFKA_STATUS_AVAILABLE + case 15: + return api.KAFKA_STATUS_UNAVAILABLE + } + return api.KAFKA_STATUS_UNKNOWN +} + +func (self *SKafka) Refresh() error { + kafka, err := self.region.GetKafka(self.InstanceId) + if err != nil { + return errors.Wrapf(err, "GetKafka") + } + return jsonutils.Update(self, kafka) +} + +func (self *SKafka) Delete() error { + return self.region.DeleteKafka(self.InstanceId) +} + +func (self *SRegion) GetICloudKafkaById(id string) (cloudprovider.ICloudKafka, error) { + kafka, err := self.GetKafka(id) + if err != nil { + return nil, errors.Wrapf(err, "GetKafka(%s)", id) + } + return kafka, nil +} + +func (self *SRegion) GetICloudKafkas() ([]cloudprovider.ICloudKafka, error) { + kafkas, err := self.GetKafkas(nil) + if err != nil { + return nil, errors.Wrapf(err, "GetKafkas") + } + ret := []cloudprovider.ICloudKafka{} + for i := range kafkas { + kafkas[i].region = self + ret = append(ret, &kafkas[i]) + } + return ret, nil +} + +func (self *SRegion) GetKafka(id string) (*SKafka, error) { + kafkas, err := self.GetKafkas([]string{id}) + if err != nil { + return nil, errors.Wrapf(err, "GetKafkas") + } + for i := range kafkas { + if kafkas[i].GetGlobalId() == id { + kafkas[i].region = self + return &kafkas[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetKafkas(ids []string) ([]SKafka, error) { + params := map[string]string{} + for idx, id := range ids { + params[fmt.Sprintf("InstanceId.%d", idx)] = id + } + resp, err := self.kafkaRequest("GetInstanceList", params) + if err != nil { + return nil, errors.Wrapf(err, "GetInstanceList") + } + ret := struct { + Code int + Message string + RequestId string + Success bool + InstanceList struct { + InstanceVO []SKafka + } + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + if ret.Code != 200 { + return nil, errors.Errorf("message: %s requestId: %s", ret.Message, ret.RequestId) + } + return ret.InstanceList.InstanceVO, nil +} + +func (self *SRegion) DeleteKafka(id string) error { + params := map[string]string{ + "RegionId": self.RegionId, + "InstanceId": id, + } + _, err := self.kafkaRequest("DeleteInstance", params) + return errors.Wrapf(err, "DeleteInstance") +} + +func (self *SRegion) ReleaseKafka(id string) error { + params := map[string]string{ + "RegionId": self.RegionId, + "InstanceId": id, + "ForceDeleteInstance": "true", + } + _, err := self.kafkaRequest("ReleaseInstance", params) + return errors.Wrapf(err, "ReleaseInstance") +} + +func (self *SKafka) GetTopics() ([]cloudprovider.SKafkaTopic, error) { + ret := []cloudprovider.SKafkaTopic{} + pageSize := 100 + for { + part, total, err := self.region.GetKafkaTopics(self.InstanceId, len(ret)/pageSize+1, pageSize) + if err != nil { + return nil, errors.Wrapf(err, "GetKafkaTopics") + } + ret = append(ret, part...) + if len(ret) >= total { + break + } + } + return ret, nil +} + +func (self *SRegion) GetKafkaTopics(id string, page int, pageSize int) ([]cloudprovider.SKafkaTopic, int, error) { + if page < 1 { + page = 1 + } + if pageSize < 1 { + pageSize = 50 + } + params := map[string]string{ + "InstanceId": id, + "CurrentPage": fmt.Sprintf("%d", page), + "PageSize": fmt.Sprintf("%d", pageSize), + } + resp, err := self.kafkaRequest("GetTopicList", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "GetTopicList") + } + result := struct { + Code int + Total int + Message string + TopicList struct { + TopicVO []struct { + CompactTopic bool + CreateTime int + InstanceId string + LocalTopic bool + PartitionNum int + RegionId string + Remark string + Status int + StatusName string + Topic string + } + } + }{} + err = resp.Unmarshal(&result) + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + ret := []cloudprovider.SKafkaTopic{} + for _, topic := range result.TopicList.TopicVO { + ret = append(ret, cloudprovider.SKafkaTopic{ + Id: topic.Topic, + Name: topic.Topic, + Description: topic.Remark, + }) + } + return ret, result.Total, nil +} diff --git a/pkg/multicloud/aliyun/keypair.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/keypair.go similarity index 100% rename from pkg/multicloud/aliyun/keypair.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/keypair.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_cluster.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_cluster.go new file mode 100644 index 0000000000..b4af5b02e6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_cluster.go @@ -0,0 +1,258 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SKubeCluster struct { + multicloud.SResourceBase + + region *SRegion + + Name string `json:"name"` + ClusterId string `json:"cluster_id"` + Size int `json:"size"` + RegionId string `json:"region_id"` + State string `json:"state"` + ClusterType string `json:"cluster_type"` + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` + InitVersion string `json:"init_version"` + CurrentVersion string `json:"current_version"` + MetaData string `json:"meta_data"` + ResourceGroupId string `json:"resource_group_id"` + InstanceType string `json:"instance_type"` + VpcId string `json:"vpc_id"` + VswitchId string `json:"vswitch_id"` + VswitchCidr string `json:"vswitch_cidr"` + DataDiskSize int `json:"data_disk_size"` + DataDiskCategory string `json:"data_disk_category"` + SecurityGroupId string `json:"security_group_id"` + Tags []struct { + Key string + Value string + } + ZoneId string `json:"zone_id"` + NetworkMode string `json:"network_mode"` + SubnetCidr string `json:"subnet_cidr"` + MasterURL string `json:"master_url"` + ExternalLoadbalancerId string `json:"external_loadbalancer_id"` + Port int `json:"port"` + NodeStatus string `json:"node_status"` + ClusterHealthy string `json:"cluster_healthy"` + DockerVersion string `json:"docker_version"` + SwarmMode bool `json:"swarm_mode"` + GwBridge string `json:"gw_bridge"` + UpgradeComponents string `json:"upgrade_components"` + NextVersion string `json:"next_version"` + PrivateZone bool `json:"private_zone"` + ServiceDiscoveryTypes string `json:"service_discovery_types"` + PrivateLink bool `json:"private_link"` + Profile string `json:"profile"` + DeletionProtection bool `json:"deletion_protection"` + ClusterSpec string `json:"cluster_spec"` + MaintenanceWindow struct { + Enable bool `json:"enable"` + MaintenanceTime string `json:"maintenance_time"` + Duration string `json:"duration"` + WeeklyPeriod string `json:"weekly_period"` + } `json:"maintenance_window"` + Capabilities string `json:"capabilities"` + EnabledMigration bool `json:"enabled_migration"` + NeedUpdateAgent bool `json:"need_update_agent"` + Outputs string `json:"outputs"` + Parameters string `json:"parameters"` + WorkerRAMRoleName string `json:"worker_ram_role_name"` + MaintenanceInfo string `json:"maintenance_info"` +} + +func (self *SKubeCluster) GetName() string { + return self.Name +} + +func (self *SKubeCluster) GetStatus() string { + switch self.State { + case "initial": + return apis.STATUS_CREATING + case "failed": + return apis.STATUS_CREATE_FAILED + case "deleting", "deleted": + return apis.STATUS_DELETING + case "delete_failed": + return apis.STATUS_DELETE_FAILED + default: + return self.State + } +} + +func (self *SKubeCluster) GetId() string { + return self.ClusterId +} + +func (self *SKubeCluster) GetGlobalId() string { + return self.ClusterId +} + +func (self *SKubeCluster) GetEnabled() bool { + return true +} + +func (self *SKubeCluster) Refresh() error { + cluster, err := self.region.GetKubeCluster(self.ClusterId) + if err != nil { + return errors.Wrapf(err, "GetKubeCluster(%s)", self.ClusterId) + } + return jsonutils.Update(self, cluster) +} + +func (self *SKubeCluster) GetKubeConfig(private bool, expireMinutes int) (*cloudprovider.SKubeconfig, error) { + return self.region.GetKubeConfig(self.ClusterId, private, expireMinutes) +} + +func (self *SKubeCluster) Delete(isRetain bool) error { + return self.region.DeleteKubeCluster(self.ClusterId, isRetain) +} + +func (self *SKubeCluster) GetTags() (map[string]string, error) { + ret := map[string]string{} + for _, tag := range self.Tags { + ret[tag.Key] = tag.Value + } + return ret, nil +} + +func (self *SKubeCluster) GetSysTags() map[string]string { + return nil +} + +func (self *SKubeCluster) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetKubeConfig(clusterId string, private bool, minutes int) (*cloudprovider.SKubeconfig, error) { + params := map[string]string{ + "PathPattern": fmt.Sprintf("/k8s/%s/user_config", clusterId), + "PrivateIpAddress": fmt.Sprintf("%v", private), + } + if minutes >= 15 && minutes <= 4320 { + params["TemporaryDurationMinutes"] = fmt.Sprintf("%d", minutes) + } + resp, err := self.k8sRequest("DescribeClusterUserKubeconfig", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeClusterUserKubeconfig") + } + result := &cloudprovider.SKubeconfig{} + err = resp.Unmarshal(result) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return result, nil +} + +func (self *SRegion) GetKubeClusters(pageSize, pageNumber int) ([]SKubeCluster, int, error) { + if pageSize < 1 || pageSize > 100 { + pageSize = 100 + } + if pageNumber < 1 { + pageNumber = 1 + } + params := map[string]string{ + "page_size": fmt.Sprintf("%d", pageSize), + "page_number": fmt.Sprintf("%d", pageNumber), + "PathPattern": "/api/v1/clusters", + } + resp, err := self.k8sRequest("DescribeClustersV1", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeClustersV1") + } + clusters := []SKubeCluster{} + err = resp.Unmarshal(&clusters, "clusters") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + totalCnt, _ := resp.Int("page_info", "total_count") + return clusters, int(totalCnt), nil +} + +func (self *SRegion) GetICloudKubeClusters() ([]cloudprovider.ICloudKubeCluster, error) { + clusters := []SKubeCluster{} + for { + part, total, err := self.GetKubeClusters(100, len(clusters)/100+1) + if err != nil { + return nil, errors.Wrapf(err, "GetKubeClusters") + } + clusters = append(clusters, part...) + if len(clusters) >= total || len(part) == 0 { + break + } + } + ret := []cloudprovider.ICloudKubeCluster{} + for i := range clusters { + if clusters[i].RegionId == self.RegionId { + clusters[i].region = self + ret = append(ret, &clusters[i]) + } + } + return ret, nil +} + +func (self *SRegion) GetICloudKubeClusterById(id string) (cloudprovider.ICloudKubeCluster, error) { + cluster, err := self.GetKubeCluster(id) + if err != nil { + return nil, errors.Wrapf(err, "GetKubeCluster(%s)", id) + } + if cluster.RegionId != self.RegionId { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s at region %s", id, cluster.RegionId) + } + return cluster, nil +} + +func (self *SRegion) GetKubeCluster(id string) (*SKubeCluster, error) { + params := map[string]string{ + "PathPattern": fmt.Sprintf("/clusters/%s", id), + } + resp, err := self.k8sRequest("DescribeClusterDetail", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeClusterDetail") + } + cluster := &SKubeCluster{region: self} + err = resp.Unmarshal(&cluster) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return cluster, nil +} + +func (self *SRegion) DeleteKubeCluster(id string, isRetain bool) error { + params := map[string]string{ + "PathPattern": fmt.Sprintf("/clusters/%s", id), + } + if isRetain { + params["retain_all_resources"] = "true" + params["keep_slb"] = "true" + } + _, err := self.k8sRequest("DeleteCluster", params) + return errors.Wrapf(err, "DeleteCluster") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_node.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_node.go new file mode 100644 index 0000000000..13cd69a967 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_node.go @@ -0,0 +1,114 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SKubeNode struct { + multicloud.SResourceBase + AliyunTags + + cluster *SKubeCluster + + HostName string + ImageId string + InstanceChargeType string + InstanceId string + InstanceName string + InstanceRole string + InstanceStatus string + InstanceType string + InstanceTypeFamily string + IpAddress []string + IsAliyunNode bool + NodeName string + NodeStatus string + NodepoolId string + Source string + State string + SpotStrategy string +} + +func (self *SKubeNode) GetGlobalId() string { + return self.NodeName +} + +func (self *SKubeNode) GetId() string { + return self.NodeName +} + +func (self *SKubeNode) GetName() string { + return self.NodeName +} + +func (self *SKubeNode) GetStatus() string { + return self.NodeStatus +} + +func (self *SKubeNode) GetINodePoolId() string { + return self.NodepoolId +} + +func (self *SRegion) GetKubeNodes(clusterId string, pageSize, pageNumber int) ([]SKubeNode, int, error) { + if pageSize < 1 || pageSize > 100 { + pageSize = 100 + } + if pageNumber < 1 { + pageNumber = 1 + } + params := map[string]string{ + "page_size": fmt.Sprintf("%d", pageSize), + "page_number": fmt.Sprintf("%d", pageNumber), + "PathPattern": fmt.Sprintf("/clusters/%s/nodes", clusterId), + } + resp, err := self.k8sRequest("DescribeClusterNodes", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeClusterNodes") + } + nodes := []SKubeNode{} + err = resp.Unmarshal(&nodes, "nodes") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + totalCnt, _ := resp.Int("page", "total_count") + return nodes, int(totalCnt), nil +} + +func (self *SKubeCluster) GetIKubeNodes() ([]cloudprovider.ICloudKubeNode, error) { + nodes := []SKubeNode{} + for { + part, total, err := self.region.GetKubeNodes(self.ClusterId, 100, len(nodes)/100) + if err != nil { + return nil, errors.Wrapf(err, "GetKubeNodes") + } + nodes = append(nodes, part...) + if len(nodes) >= total || len(part) == 0 { + break + } + } + ret := []cloudprovider.ICloudKubeNode{} + for i := range nodes { + nodes[i].cluster = self + ret = append(ret, &nodes[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_node_pools.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_node_pools.go new file mode 100644 index 0000000000..b07c5b88a9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/kube_node_pools.go @@ -0,0 +1,156 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SKubeNodePool struct { + multicloud.SResourceBase + AliyunTags + + cluster *SKubeCluster + + AutoScaling struct { + EipBandwidth int `json:"eip_bandwidth"` + IsBondEip bool `json:"is_bond_eip"` + Enable bool `json:"enable"` + MaxInstances int `json:"max_instances"` + MinInstances int `json:"min_instances"` + Type string `json:"type"` + } `json:"auto_scaling"` + KubernetesConfig struct { + CmsEnabled bool `json:"cms_enabled"` + CpuPolicy string `json:"cpu_policy"` + Runtime string `json:"runtime"` + RuntimeVersion string `json:"runtime_version"` + UserData string `json:"user_data"` + } `json:"kubernetes_config"` + NodepoolInfo struct { + Created string `json:"created"` + IsDefault bool `json:"is_default"` + Name string `json:"name"` + NodepoolId string `json:"nodepool_id"` + RegionId string `json:"region_id"` + ResourceGroupId string `json:"resource_group_id"` + Type string `json:"type"` + Updated string `json:"updated"` + } `json:"nodepool_info"` + ScalingGroup struct { + AutoRenew bool `json:"auto_renew"` + AutoRenewPeriod int `json:"auto_renew_period"` + ImageId string `json:"image_id"` + InstanceChargeType string `json:"instance_charge_type"` + Instance_types []string `json:"instance_types"` + MultiAzPolicy string `json:"multi_az_policy"` + OnDemandBaseCapacity int `json:"on_demand_base_capacity"` + OnDemandPercentageAboveBaseCapacity int `json:"on_demand_percentage_above_base_capacity"` + SpotInstancePools int `json:"spot_instance_pools"` + SpotInstanceRemedy bool `json:"spot_instance_remedy"` + CompensateWithOnDemand bool `json:"compensate_with_on_demand"` + Period int `json:"period"` + PeriodUnit string `json:"period_unit"` + Platform string `json:"platform"` + RamPolicy string `json:"ram_policy"` + SpotStrategy string `json:"spot_strategy"` + SpotPriceLimit []struct { + InstanceType string `json:"instance_type"` + PriceLimit string `json:"price_limit"` + } `json:"spot_price_limit"` + RdsInstances []string `json:"rds_instances"` + ScalingGroupId string `json:"scaling_group_id"` + ScalingPolicy string `json:"scaling_policy"` + SecurityGroupId string `json:"security_group_id"` + SystemDiskCategory string `json:"system_disk_category"` + SystemDiskSize int `json:"system_disk_size"` + VswitchIds []string `json:"vswitch_ids"` + LoginPassword string `json:"login_password"` + KeyPair string `json:"key_pair"` + } `json:"scaling_group"` + Status struct { + FailedNodes string `json:"failed_nodes"` + HealthyNodes string `json:"healthy_nodes"` + InitialNodes string `json:"initial_nodes"` + OfflineNodes string `json:"offline_nodes"` + RemovingNodes string `json:"removing_nodes"` + ServingNodes string `json:"serving_nodes"` + State string `json:"state"` + TotalNodes int `json:"total_nodes"` + } `json:"status"` + TeeConfig struct { + TeeEnable bool `json:"tee_enable"` + } `json:"tee_config"` + Management struct { + Enable bool `json:"enable"` + AutoRepair bool `json:"auto_repair"` + UpgradeConfig struct { + AutoUpgrade bool `json:"auto_upgrade"` + Surge int `json:"surge"` + SurgePercentage int `json:"surge_percentage"` + MaxUnavailable int `json:"max_unavailable"` + } `json:"upgrade_config"` + } `json:"management"` +} + +func (self *SKubeNodePool) GetName() string { + return self.NodepoolInfo.Name +} + +func (self *SKubeNodePool) GetId() string { + return self.NodepoolInfo.NodepoolId +} + +func (self *SKubeNodePool) GetGlobalId() string { + return self.NodepoolInfo.NodepoolId +} + +func (self *SKubeNodePool) GetStatus() string { + return self.Status.State +} + +func (self *SKubeCluster) GetIKubeNodePools() ([]cloudprovider.ICloudKubeNodePool, error) { + pools, err := self.region.GetKubeNodePools(self.ClusterId) + if err != nil { + return nil, errors.Wrapf(err, "GetKubeNodePools") + } + ret := []cloudprovider.ICloudKubeNodePool{} + for i := range pools { + pools[i].cluster = self + ret = append(ret, &pools[i]) + } + return ret, nil +} + +func (self *SRegion) GetKubeNodePools(clusterId string) ([]SKubeNodePool, error) { + params := map[string]string{ + "PathPattern": fmt.Sprintf("/clusters/%s/nodepools", clusterId), + } + resp, err := self.k8sRequest("DescribeClusterNodePools", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeClusterNodePools") + } + pools := []SKubeNodePool{} + err = resp.Unmarshal(&pools, "nodepools") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return pools, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/latitud_and_longitude.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/latitud_and_longitude.go new file mode 100644 index 0000000000..da17fedd57 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/latitud_and_longitude.go @@ -0,0 +1,49 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ + "cn-qingdao": api.RegionQingdao, + "cn-beijing": api.RegionBeijing, + "cn-zhangjiakou": api.RegionZhangjiakou, + "cn-huhehaote": api.RegionHuhehaote, + "cn-huhehaote-nebula-1": api.RegionHuhehaote, + "cn-hangzhou": api.RegionHangzhou, + "cn-shanghai": api.RegionShanghai, + "cn-shanghai-finance-1": api.RegionShanghai, + "cn-shenzhen": api.RegionShenzhen, + "cn-shenzhen-finance-1": api.RegionShenzhen, + "cn-hongkong": api.RegionHongkong, + "cn-chengdu": api.RegionChengdu, + "cn-heyuan": api.RegionHeyuan, + "ap-northeast-1": api.RegionTokyo, + "ap-southeast-1": api.RegionSingapore, + "ap-southeast-2": api.RegionSydney, + "ap-southeast-3": api.RegionKualaLumpur, + "ap-southeast-5": api.RegionJakarta, + "ap-south-1": api.RegionMumbai, + "us-east-1": api.RegionVirginia, + "us-west-1": api.RegionSiliconValley, + "eu-west-1": api.RegionLondon, + "me-east-1": api.RegionDubai, + "eu-central-1": api.RegionFrankfurt, + "cn-wulanchabu": api.RegionWulanchabu, + "cn-guangzhou": api.RegionGuangzhou, +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancer.go new file mode 100644 index 0000000000..71634b6e79 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancer.go @@ -0,0 +1,494 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type ListenerProtocol string + +const ( + ListenerProtocolTCP ListenerProtocol = "tcp" + ListenerProtocolUDP ListenerProtocol = "udp" + ListenerProtocolHTTP ListenerProtocol = "http" + ListenerProtocolHTTPS ListenerProtocol = "https" +) + +type ListenerPorts struct { + ListenerPort []int +} + +type ListenerPortsAndProtocol struct { + ListenerPortAndProtocol []ListenerPortAndProtocol +} + +type ListenerPortAndProtocol struct { + Description string + ListenerPort int + ListenerProtocol ListenerProtocol +} + +type BackendServers struct { + BackendServer []SLoadbalancerDefaultBackend +} + +type SLoadbalancer struct { + multicloud.SLoadbalancerBase + AliyunTags + region *SRegion + + LoadBalancerId string //负载均衡实例ID。 + LoadBalancerName string //负载均衡实例的名称。 + LoadBalancerStatus string //负载均衡实例状态:inactive: 此状态的实例监听不会再转发流量。active: 实例创建后,默认状态为active。 locked: 实例已经被锁定。 + Address string //负载均衡实例的服务地址。 + RegionId string //负载均衡实例的地域ID。 + RegionIdAlias string //负载均衡实例的地域名称。 + AddressType string //负载均衡实例的网络类型。 + VSwitchId string //私网负载均衡实例的交换机ID。 + VpcId string //私网负载均衡实例的专有网络ID。 + NetworkType string //私网负载均衡实例的网络类型:vpc:专有网络实例 classic:经典网络实例 + ListenerPorts ListenerPorts + ListenerPortsAndProtocol ListenerPortsAndProtocol + BackendServers BackendServers + CreateTime time.Time //负载均衡实例的创建时间。 + MasterZoneId string //实例的主可用区ID。 + SlaveZoneId string //实例的备可用区ID。 + InternetChargeType TInternetChargeType //公网实例的计费方式。取值:paybybandwidth:按带宽计费 paybytraffic:按流量计费(默认值) 说明 当 PayType参数的值为PrePay时,只支持按带宽计费。 + InternetChargeTypeAlias TInternetChargeType + + PayType string //实例的计费类型,取值:PayOnDemand:按量付费 PrePay:预付费 + ResourceGroupId string //企业资源组ID。 + LoadBalancerSpec string //负载均衡实例的的性能规格 + Bandwidth int //按带宽计费的公网型实例的带宽峰值 +} + +func (lb *SLoadbalancer) GetName() string { + return lb.LoadBalancerName +} + +func (lb *SLoadbalancer) GetId() string { + return lb.LoadBalancerId +} + +func (lb *SLoadbalancer) GetGlobalId() string { + return lb.LoadBalancerId +} + +func (lb *SLoadbalancer) GetStatus() string { + if lb.LoadBalancerStatus == "active" { + return api.LB_STATUS_ENABLED + } + return api.LB_STATUS_DISABLED +} + +func (lb *SLoadbalancer) GetAddress() string { + return lb.Address +} + +func (lb *SLoadbalancer) GetAddressType() string { + return lb.AddressType +} + +func (lb *SLoadbalancer) GetNetworkType() string { + return lb.NetworkType +} + +func (lb *SLoadbalancer) GetNetworkIds() []string { + return []string{lb.VSwitchId} +} + +func (lb *SLoadbalancer) GetZoneId() string { + zone, err := lb.region.getZoneById(transZoneIdToEcsZoneId(lb.region, "elb", lb.MasterZoneId)) + if err != nil { + log.Errorf("failed to find zone for lb %s error: %v", lb.LoadBalancerName, err) + return "" + } + return zone.GetGlobalId() +} + +func (self *SLoadbalancer) GetZone1Id() string { + return "" +} + +func (lb *SLoadbalancer) IsEmulated() bool { + return false +} + +func (lb *SLoadbalancer) GetVpcId() string { + return lb.VpcId +} + +func (lb *SLoadbalancer) Refresh() error { + loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId) + if err != nil { + return err + } + return jsonutils.Update(lb, loadbalancer) +} + +func (region *SRegion) GetLoadbalancers(ids []string) ([]SLoadbalancer, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + if ids != nil && len(ids) > 0 { + params["LoadBalancerId"] = strings.Join(ids, ",") + } + body, err := region.lbRequest("DescribeLoadBalancers", params) + if err != nil { + return nil, err + } + lbs := []SLoadbalancer{} + return lbs, body.Unmarshal(&lbs, "LoadBalancers", "LoadBalancer") +} + +func (region *SRegion) GetLoadbalancerDetail(loadbalancerId string) (*SLoadbalancer, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + body, err := region.lbRequest("DescribeLoadBalancerAttribute", params) + if err != nil { + return nil, err + } + lb := SLoadbalancer{region: region} + return &lb, body.Unmarshal(&lb) +} + +func (lb *SLoadbalancer) Delete(ctx context.Context) error { + params := map[string]string{} + params["RegionId"] = lb.region.RegionId + params["LoadBalancerId"] = lb.LoadBalancerId + _, err := lb.region.lbRequest("DeleteLoadBalancer", params) + return err +} + +func (lb *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + ibackendgroups := []cloudprovider.ICloudLoadbalancerBackendGroup{} + { + backendgroups, err := lb.region.GetLoadbalancerBackendgroups(lb.LoadBalancerId) + if err != nil { + return nil, err + } + + for i := 0; i < len(backendgroups); i++ { + backendgroups[i].lb = lb + ibackendgroups = append(ibackendgroups, &backendgroups[i]) + } + } + { + iDefaultBackendgroup := SLoadbalancerDefaultBackendGroup{lb: lb} + ibackendgroups = append(ibackendgroups, &iDefaultBackendgroup) + + } + { + backendgroups, err := lb.region.GetLoadbalancerMasterSlaveBackendgroups(lb.LoadBalancerId) + if err != nil { + return nil, err + } + for i := 0; i < len(backendgroups); i++ { + backendgroups[i].lb = lb + ibackendgroups = append(ibackendgroups, &backendgroups[i]) + } + } + return ibackendgroups, nil +} + +func (lb *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + switch group.GroupType { + case api.LB_BACKENDGROUP_TYPE_NORMAL: + group, err := lb.region.CreateLoadbalancerBackendGroup(group.Name, lb.LoadBalancerId, group.Backends) + if err != nil { + return nil, err + } + group.lb = lb + return group, nil + case api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE: + group, err := lb.region.CreateLoadbalancerMasterSlaveBackendGroup(group.Name, lb.LoadBalancerId, group.Backends) + if err != nil { + return nil, err + } + group.lb = lb + return group, nil + default: + return nil, fmt.Errorf("Unsupport backendgroup type %s", group.GroupType) + } +} + +func (lb *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + switch listener.ListenerType { + case api.LB_LISTENER_TYPE_TCP: + return lb.region.CreateLoadbalancerTCPListener(lb, listener) + case api.LB_LISTENER_TYPE_UDP: + return lb.region.CreateLoadbalancerUDPListener(lb, listener) + case api.LB_LISTENER_TYPE_HTTP: + return lb.region.CreateLoadbalancerHTTPListener(lb, listener) + case api.LB_LISTENER_TYPE_HTTPS: + return lb.region.CreateLoadbalancerHTTPSListener(lb, listener) + } + return nil, fmt.Errorf("unsupport listener type %s", listener.ListenerType) +} + +func (lb *SLoadbalancer) GetLoadbalancerSpec() string { + if len(lb.LoadBalancerSpec) == 0 { + lb.Refresh() + } + return lb.LoadBalancerSpec +} + +func (lb *SLoadbalancer) GetChargeType() string { + chargeType := lb.InternetChargeType + if len(lb.InternetChargeTypeAlias) > 0 { + chargeType = lb.InternetChargeTypeAlias + } + switch chargeType { + case "paybybandwidth": + return api.LB_CHARGE_TYPE_BY_BANDWIDTH + case "paybytraffic": + return api.LB_CHARGE_TYPE_BY_TRAFFIC + default: + return string(chargeType) + } +} + +func (lb *SLoadbalancer) GetCreatedAt() time.Time { + return lb.CreateTime +} + +func (lb *SLoadbalancer) GetEgressMbps() int { + if lb.Bandwidth < 1 { + return 0 + } + return lb.Bandwidth +} + +func (lb *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + groups, err := lb.GetILoadBalancerBackendGroups() + if err != nil { + return nil, err + } + for i := 0; i < len(groups); i++ { + if groups[i].GetGlobalId() == groupId { + return groups[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (lb *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { + if lb.AddressType == "internet" { + eip := SEipAddress{ + region: lb.region, + IpAddress: lb.Address, + InstanceId: lb.GetGlobalId(), + InstanceType: EIP_INTANNCE_TYPE_SLB, + Status: EIP_STATUS_INUSE, + AllocationId: lb.GetGlobalId(), + AllocationTime: lb.CreateTime, + Bandwidth: lb.Bandwidth, + } + switch lb.GetChargeType() { + case api.LB_CHARGE_TYPE_BY_BANDWIDTH: + eip.InternetChargeType = InternetChargeByBandwidth + case api.LB_CHARGE_TYPE_BY_TRAFFIC: + eip.InternetChargeType = InternetChargeByTraffic + } + return &eip, nil + } + eips, total, err := lb.region.GetEips("", lb.LoadBalancerId, "", 0, 1) + if err != nil { + return nil, errors.Wrapf(err, "lb.region.GetEips(%s)", lb.LoadBalancerId) + } + if total != 1 { + return nil, cloudprovider.ErrNotFound + } + eips[0].region = lb.region + return &eips[0], nil +} + +func (region *SRegion) loadbalancerOperation(loadbalancerId, status string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["LoadBalancerStatus"] = status + _, err := region.lbRequest("SetLoadBalancerStatus", params) + return err +} + +func (lb *SLoadbalancer) Start() error { + if lb.LoadBalancerStatus != "active" { + return lb.region.loadbalancerOperation(lb.LoadBalancerId, "active") + } + return nil +} + +func (lb *SLoadbalancer) Stop() error { + if lb.LoadBalancerStatus != "inactive" { + return lb.region.loadbalancerOperation(lb.LoadBalancerId, "inactive") + } + return nil +} + +func (lb *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { + listener, err := lb.GetILoadBalancerListeners() + if err != nil { + return nil, err + } + for i := 0; i < len(listener); i++ { + if listener[i].GetGlobalId() == listenerId { + return listener[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (lb *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId) + if err != nil { + return nil, err + } + listeners := []cloudprovider.ICloudLoadbalancerListener{} + for _, listenerInfo := range loadbalancer.ListenerPortsAndProtocol.ListenerPortAndProtocol { + switch listenerInfo.ListenerProtocol { + case ListenerProtocolHTTP: + listener, err := lb.region.GetLoadbalancerHTTPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) + if err != nil { + return nil, err + } + listener.lb = lb + listeners = append(listeners, listener) + case ListenerProtocolHTTPS: + listener, err := lb.region.GetLoadbalancerHTTPSListener(lb.LoadBalancerId, listenerInfo.ListenerPort) + if err != nil { + return nil, err + } + listener.lb = lb + listeners = append(listeners, listener) + case ListenerProtocolTCP: + listener, err := lb.region.GetLoadbalancerTCPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) + if err != nil { + return nil, err + } + listener.lb = lb + listeners = append(listeners, listener) + case ListenerProtocolUDP: + listener, err := lb.region.GetLoadbalancerUDPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) + if err != nil { + return nil, err + } + listener.lb = lb + listeners = append(listeners, listener) + default: + return nil, fmt.Errorf("failed to recognize %s type listener", listenerInfo.ListenerProtocol) + } + } + return listeners, nil +} + +func (lb *SLoadbalancer) GetProjectId() string { + return lb.ResourceGroupId +} + +func (lb *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { + return lb.region.SetResourceTags(ALIYUN_SERVICE_SLB, "instance", lb.LoadBalancerId, tags, replace) +} + +// mapping aliyun finance zoneId to aliyun finance ecs zoneId +func transZoneIdToEcsZoneId(region *SRegion, service, zoneId string) string { + if region.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV { + switch service { + case "elb", "redis": + if utils.IsInStringArray(zoneId, []string{"cn-hangzhou-finance-b", "cn-hangzhou-finance-c", "cn-hangzhou-finance-d"}) { + return strings.Replace(zoneId, "-finance", "", -1) + } + default: + return zoneId + } + } + + return zoneId +} + +// mapping aliyun finance ecs zoneId to dest service zone id +func transZoneIdFromEcsZoneId(region *SRegion, service, zoneId string) string { + if region.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV { + switch service { + case "elb", "redis": + if utils.IsInStringArray(zoneId, []string{"cn-hangzhou-b", "cn-hangzhou-c", "cn-hangzhou-d"}) { + return strings.Replace(zoneId, "cn-hangzhou", "cn-hangzhou-finance", -1) + } + default: + return zoneId + } + } + + return zoneId +} + +// mapping aliyun finance regionId to aliyun finance ecs regionId +func transRegionIdToEcsRegionId(region *SRegion, service string) string { + if region.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV { + switch service { + case "redis": + if region.GetId() == "cn-hangzhou-finance" { + return "cn-hangzhou" + } + default: + return region.GetId() + } + } + + return region.GetId() +} + +// mapping aliyun finance regionId from aliyun finance ecs regionId +func transRegionIdFromEcsRegionId(region *SRegion, service string) string { + if region.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV { + switch service { + case "redis": + if region.GetId() == "cn-hangzhou" { + return "cn-hangzhou-finance" + } + default: + return region.GetId() + } + } + + return region.GetId() +} + +func fetchMasterZoneId(zoneId string) string { + // cn-shenzhen-finance-1MAZ2(d,e) + i := strings.Index(zoneId, "MAZ") + if i > 0 { + s := strings.Index(zoneId, "(") + e := strings.Index(zoneId, ",") + if s >= 0 && e >= 0 { + return zoneId[0:i] + zoneId[s+1:e] + } + } + + return zoneId +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalanceracl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalanceracl.go new file mode 100644 index 0000000000..aa4966a314 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalanceracl.go @@ -0,0 +1,162 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type AclEntrys struct { + AclEntry []AclEntry +} + +type AclEntry struct { + AclEntryComment string + AclEntryIP string +} + +type SLoadbalancerAcl struct { + multicloud.SResourceBase + AliyunTags + region *SRegion + + AclId string + AclName string + + AclEntrys AclEntrys +} + +func (acl *SLoadbalancerAcl) GetAclListenerID() string { + return "" +} + +func (acl *SLoadbalancerAcl) GetName() string { + return acl.AclName +} + +func (acl *SLoadbalancerAcl) GetId() string { + return acl.AclId +} + +func (acl *SLoadbalancerAcl) GetGlobalId() string { + return acl.AclId +} + +func (acl *SLoadbalancerAcl) GetStatus() string { + return "" +} + +func (acl *SLoadbalancerAcl) IsEmulated() bool { + return false +} + +func (acl *SLoadbalancerAcl) Refresh() error { + loadbalancerAcl, err := acl.region.GetLoadbalancerAclDetail(acl.AclId) + if err != nil { + return err + } + return jsonutils.Update(acl, loadbalancerAcl) +} + +func (acl *SLoadbalancerAcl) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { + detail, err := acl.region.GetLoadbalancerAclDetail(acl.AclId) + if err != nil { + log.Errorf("GetLoadbalancerAclDetail %s failed: %v", acl.AclId, err) + return nil + } + entrys := []cloudprovider.SLoadbalancerAccessControlListEntry{} + for _, entry := range detail.AclEntrys.AclEntry { + entrys = append(entrys, cloudprovider.SLoadbalancerAccessControlListEntry{CIDR: entry.AclEntryIP, Comment: entry.AclEntryComment}) + } + return entrys +} + +func (region *SRegion) UpdateAclName(aclId, name string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["AclId"] = aclId + params["AclName"] = name + _, err := region.lbRequest("SetAccessControlListAttribute", params) + return err +} + +func (region *SRegion) RemoveAccessControlListEntry(aclId string, data jsonutils.JSONObject) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["AclId"] = aclId + params["AclEntrys"] = data.String() + _, err := region.lbRequest("RemoveAccessControlListEntry", params) + return err +} + +func (acl *SLoadbalancerAcl) Delete() error { + params := map[string]string{} + params["RegionId"] = acl.region.RegionId + params["AclId"] = acl.AclId + _, err := acl.region.lbRequest("DeleteAccessControlList", params) + return err +} + +func (region *SRegion) GetLoadbalancerAclDetail(aclId string) (*SLoadbalancerAcl, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["AclId"] = aclId + body, err := region.lbRequest("DescribeAccessControlListAttribute", params) + if err != nil { + return nil, err + } + detail := SLoadbalancerAcl{region: region} + return &detail, body.Unmarshal(&detail) +} + +func (region *SRegion) GetLoadBalancerAcls() ([]SLoadbalancerAcl, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + body, err := region.lbRequest("DescribeAccessControlLists", params) + if err != nil { + return nil, err + } + acls := []SLoadbalancerAcl{} + return acls, body.Unmarshal(&acls, "Acls", "Acl") +} + +func (acl *SLoadbalancerAcl) Sync(_acl *cloudprovider.SLoadbalancerAccessControlList) error { + if acl.AclName != _acl.Name { + if err := acl.region.UpdateAclName(acl.AclId, _acl.Name); err != nil { + return err + } + } + entrys := jsonutils.NewArray() + for _, entry := range acl.AclEntrys.AclEntry { + entrys.Add(jsonutils.Marshal(map[string]string{"entry": entry.AclEntryIP, "comment": entry.AclEntryComment})) + } + if entrys.Length() > 0 { + if err := acl.region.RemoveAccessControlListEntry(acl.AclId, entrys); err != nil && !isError(err, "Acl does not have any entry") { + return err + } + } + if len(_acl.Entrys) > 0 { + return acl.region.AddAccessControlListEntry(acl.AclId, _acl.Entrys) + } + return nil +} + +func (acl *SLoadbalancerAcl) GetProjectId() string { + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerbackend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerbackend.go new file mode 100644 index 0000000000..542ec59115 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerbackend.go @@ -0,0 +1,117 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerBackend struct { + multicloud.SResourceBase + AliyunTags + lbbg *SLoadbalancerBackendGroup + + ServerId string + Port int + Weight int +} + +func (backend *SLoadbalancerBackend) GetName() string { + return backend.ServerId +} + +func (backend *SLoadbalancerBackend) GetId() string { + return fmt.Sprintf("%s/%s", backend.lbbg.VServerGroupId, backend.ServerId) +} + +func (backend *SLoadbalancerBackend) GetGlobalId() string { + return backend.GetId() +} + +func (backend *SLoadbalancerBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backend *SLoadbalancerBackend) IsEmulated() bool { + return false +} + +func (backend *SLoadbalancerBackend) Refresh() error { + loadbalancerBackends, err := backend.lbbg.lb.region.GetLoadbalancerBackends(backend.lbbg.VServerGroupId) + if err != nil { + return err + } + for _, loadbalancerBackend := range loadbalancerBackends { + if loadbalancerBackend.ServerId == backend.ServerId { + return jsonutils.Update(backend, loadbalancerBackend) + } + } + return cloudprovider.ErrNotFound +} + +func (backend *SLoadbalancerBackend) GetWeight() int { + return backend.Weight +} + +func (backend *SLoadbalancerBackend) GetPort() int { + return backend.Port +} + +func (backend *SLoadbalancerBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (backend *SLoadbalancerBackend) GetBackendRole() string { + return api.LB_BACKEND_ROLE_DEFAULT +} + +func (backend *SLoadbalancerBackend) GetBackendId() string { + return backend.ServerId +} + +func (backend *SLoadbalancerBackend) GetIpAddress() string { + return "" +} + +func (region *SRegion) GetLoadbalancerBackends(backendgroupId string) ([]SLoadbalancerBackend, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["VServerGroupId"] = backendgroupId + body, err := region.lbRequest("DescribeVServerGroupAttribute", params) + if err != nil { + return nil, err + } + backends := []SLoadbalancerBackend{} + return backends, body.Unmarshal(&backends, "BackendServers", "BackendServer") +} + +func (backend *SLoadbalancerBackend) GetProjectId() string { + return backend.lbbg.GetProjectId() +} + +func (backend *SLoadbalancerBackend) SyncConf(ctx context.Context, port, weight int) error { + err := backend.lbbg.lb.region.RemoveBackendVServer(backend.lbbg.lb.LoadBalancerId, backend.lbbg.VServerGroupId, backend.ServerId, backend.Port) + if err != nil { + return err + } + return backend.lbbg.lb.region.AddBackendVServer(backend.lbbg.lb.LoadBalancerId, backend.lbbg.VServerGroupId, backend.ServerId, weight, port) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerbackendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerbackendgroup.go new file mode 100644 index 0000000000..959bb12218 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerbackendgroup.go @@ -0,0 +1,277 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type Rule struct { + RuleId string + RuleName string + Domain string + Url string +} + +type Rules struct { + Rule []Rule +} + +type Listener struct { + Protocol string + Port int +} + +type Listeners struct { + Listener []Listener +} + +type AssociatedObjects struct { + Rules Rules + Listeners Listeners +} + +type SLoadbalancerBackendGroup struct { + multicloud.SResourceBase + AliyunTags + lb *SLoadbalancer + + VServerGroupId string + VServerGroupName string + AssociatedObjects AssociatedObjects +} + +func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { + return backendgroup.lb +} + +func (backendgroup *SLoadbalancerBackendGroup) GetLoadbalancerId() string { + return backendgroup.lb.GetId() +} + +func (backendgroup *SLoadbalancerBackendGroup) GetProtocolType() string { + return "" +} + +func (backendgroup *SLoadbalancerBackendGroup) GetScheduler() string { + return "" +} + +func (backendgroup *SLoadbalancerBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerBackendGroup) GetName() string { + return backendgroup.VServerGroupName +} + +func (backendgroup *SLoadbalancerBackendGroup) GetId() string { + return backendgroup.VServerGroupId +} + +func (backendgroup *SLoadbalancerBackendGroup) GetGlobalId() string { + return backendgroup.VServerGroupId +} + +func (backendgroup *SLoadbalancerBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backendgroup *SLoadbalancerBackendGroup) IsDefault() bool { + return false +} + +func (backendgroup *SLoadbalancerBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_NORMAL +} + +func (backendgroup *SLoadbalancerBackendGroup) IsEmulated() bool { + return false +} + +func (backendgroup *SLoadbalancerBackendGroup) Refresh() error { + loadbalancerBackendgroups, err := backendgroup.lb.region.GetLoadbalancerBackendgroups(backendgroup.lb.LoadBalancerId) + if err != nil { + return err + } + for _, loadbalancerBackendgroup := range loadbalancerBackendgroups { + if loadbalancerBackendgroup.VServerGroupId == backendgroup.VServerGroupId { + return jsonutils.Update(backendgroup, loadbalancerBackendgroup) + } + } + return cloudprovider.ErrNotFound +} + +func (region *SRegion) GetLoadbalancerBackendgroups(loadbalancerId string) ([]SLoadbalancerBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + body, err := region.lbRequest("DescribeVServerGroups", params) + if err != nil { + return nil, err + } + backendgroups := []SLoadbalancerBackendGroup{} + return backendgroups, body.Unmarshal(&backendgroups, "VServerGroups", "VServerGroup") +} + +func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := backendgroup.lb.region.GetLoadbalancerBackends(backendgroup.VServerGroupId) + if err != nil { + return nil, err + } + ibackends := []cloudprovider.ICloudLoadbalancerBackend{} + for i := 0; i < len(backends); i++ { + backends[i].lbbg = backendgroup + ibackends = append(ibackends, &backends[i]) + } + return ibackends, nil +} + +func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := backendgroup.GetILoadbalancerBackends() + if err != nil { + return nil, err + } + for i := 0; i < len(backends); i++ { + if backends[i].GetGlobalId() == backendId { + return backends[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) CreateLoadbalancerBackendGroup(name, loadbalancerId string, backends []cloudprovider.SLoadbalancerBackend) (*SLoadbalancerBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["VServerGroupName"] = name + params["LoadBalancerId"] = loadbalancerId + if len(backends) > 0 { + servers := jsonutils.NewArray() + for _, backend := range backends { + servers.Add( + jsonutils.Marshal( + map[string]string{ + "ServerId": backend.ExternalID, + "Port": fmt.Sprintf("%d", backend.Port), + "Weight": fmt.Sprintf("%d", backend.Weight), + }, + )) + } + params["BackendServers"] = servers.String() + } + body, err := region.lbRequest("CreateVServerGroup", params) + if err != nil { + return nil, err + } + groupId, err := body.GetString("VServerGroupId") + if err != nil { + return nil, err + } + return region.GetLoadbalancerBackendgroupById(groupId) +} + +func (region *SRegion) GetLoadbalancerBackendgroupById(groupId string) (*SLoadbalancerBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["VServerGroupId"] = groupId + body, err := region.lbRequest("DescribeVServerGroupAttribute", params) + if err != nil { + return nil, err + } + group := &SLoadbalancerBackendGroup{} + return group, body.Unmarshal(group) +} + +func (region *SRegion) UpdateLoadBalancerBackendGroupName(name, groupId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["VServerGroupId"] = groupId + params["VServerGroupName"] = name + _, err := region.lbRequest("SetVServerGroupAttribute", params) + return err +} + +func (backendgroup *SLoadbalancerBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + if group == nil { + return nil + } + + if backendgroup.VServerGroupName != group.Name { + return backendgroup.lb.region.UpdateLoadBalancerBackendGroupName(backendgroup.VServerGroupId, group.Name) + } + return nil +} + +func (region *SRegion) DeleteLoadBalancerBackendGroup(groupId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["VServerGroupId"] = groupId + _, err := region.lbRequest("DeleteVServerGroup", params) + return err +} + +func (backendgroup *SLoadbalancerBackendGroup) Delete(ctx context.Context) error { + return backendgroup.lb.region.DeleteLoadBalancerBackendGroup(backendgroup.VServerGroupId) +} + +func (region *SRegion) AddBackendVServer(loadbalancerId, backendGroupId, serverId string, weight, port int) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["VServerGroupId"] = backendGroupId + servers := jsonutils.NewArray() + servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Weight": fmt.Sprintf("%d", weight), "Port": fmt.Sprintf("%d", port)})) + params["BackendServers"] = servers.String() + _, err := region.lbRequest("AddVServerGroupBackendServers", params) + return err +} + +func (region *SRegion) RemoveBackendVServer(loadbalancerId, backendgroupId, serverId string, port int) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["VServerGroupId"] = backendgroupId + servers := jsonutils.NewArray() + servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Port": fmt.Sprintf("%d", port)})) + params["BackendServers"] = servers.String() + _, err := region.lbRequest("RemoveVServerGroupBackendServers", params) + return err +} + +func (backendgroup *SLoadbalancerBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + if err := backendgroup.lb.region.AddBackendVServer(backendgroup.lb.LoadBalancerId, backendgroup.VServerGroupId, serverId, weight, port); err != nil { + return nil, err + } + return &SLoadbalancerBackend{lbbg: backendgroup, ServerId: serverId, Weight: weight, Port: port}, nil +} + +func (backendgroup *SLoadbalancerBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { + return backendgroup.lb.region.RemoveBackendVServer(backendgroup.lb.LoadBalancerId, backendgroup.VServerGroupId, serverId, port) +} + +func (backendgroup *SLoadbalancerBackendGroup) GetProjectId() string { + return backendgroup.lb.GetProjectId() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerdefaultbackend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerdefaultbackend.go new file mode 100644 index 0000000000..617c47babb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerdefaultbackend.go @@ -0,0 +1,115 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerDefaultBackend struct { + multicloud.SResourceBase + AliyunTags + lbbg *SLoadbalancerDefaultBackendGroup + + ServerId string + Weight int +} + +func (backend *SLoadbalancerDefaultBackend) GetName() string { + return backend.ServerId +} + +func (backend *SLoadbalancerDefaultBackend) GetId() string { + return fmt.Sprintf("%s/%s", backend.lbbg.lb.LoadBalancerId, backend.ServerId) +} + +func (backend *SLoadbalancerDefaultBackend) GetGlobalId() string { + return backend.GetId() +} + +func (backend *SLoadbalancerDefaultBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backend *SLoadbalancerDefaultBackend) IsEmulated() bool { + return false +} + +func (backend *SLoadbalancerDefaultBackend) Refresh() error { + return nil +} + +func (backend *SLoadbalancerDefaultBackend) GetWeight() int { + return backend.Weight +} + +func (backend *SLoadbalancerDefaultBackend) GetPort() int { + return 0 +} + +func (backend *SLoadbalancerDefaultBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (backend *SLoadbalancerDefaultBackend) GetBackendRole() string { + return api.LB_BACKEND_ROLE_DEFAULT +} + +func (backend *SLoadbalancerDefaultBackend) GetBackendId() string { + return backend.ServerId +} + +func (backend *SLoadbalancerDefaultBackend) GetIpAddress() string { + return "" +} + +func (backend *SLoadbalancerDefaultBackend) GetProjectId() string { + return backend.lbbg.GetProjectId() +} + +func (backend *SLoadbalancerDefaultBackend) SyncConf(ctx context.Context, port, weight int) error { + params := map[string]string{} + params["RegionId"] = backend.lbbg.lb.region.RegionId + params["LoadBalancerId"] = backend.lbbg.lb.LoadBalancerId + loadbalancer, err := backend.lbbg.lb.region.GetLoadbalancerDetail(backend.lbbg.lb.LoadBalancerId) + if err != nil { + return err + } + servers := jsonutils.NewArray() + for i := 0; i < len(loadbalancer.BackendServers.BackendServer); i++ { + _backend := loadbalancer.BackendServers.BackendServer[i] + _backend.lbbg = backend.lbbg + if _backend.GetGlobalId() == backend.GetGlobalId() { + _backend.Weight = weight + } + servers.Add( + jsonutils.Marshal( + map[string]string{ + "ServerId": _backend.ServerId, + "Weight": fmt.Sprintf("%d", _backend.Weight), + }, + )) + } + + params["BackendServers"] = servers.String() + _, err = backend.lbbg.lb.region.lbRequest("SetBackendServers", params) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerdefaultbackendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerdefaultbackendgroup.go new file mode 100644 index 0000000000..c7a41723c9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerdefaultbackendgroup.go @@ -0,0 +1,159 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerDefaultBackendGroup struct { + multicloud.SResourceBase + AliyunTags + lb *SLoadbalancer +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { + return backendgroup.lb +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetLoadbalancerId() string { + return backendgroup.lb.GetId() +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetProtocolType() string { + return "" +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetScheduler() string { + return "" +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetName() string { + return fmt.Sprintf("%s(%s)-default", backendgroup.lb.LoadBalancerName, backendgroup.lb.Address) +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetId() string { + return fmt.Sprintf("%s/default", backendgroup.lb.LoadBalancerId) +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetGlobalId() string { + return backendgroup.GetId() +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) IsDefault() bool { + return true +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_DEFAULT +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) IsEmulated() bool { + return false +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) Refresh() error { + return nil +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + loadbalancer, err := backendgroup.lb.region.GetLoadbalancerDetail(backendgroup.lb.LoadBalancerId) + if err != nil { + return nil, err + } + ibackends := []cloudprovider.ICloudLoadbalancerBackend{} + for i := 0; i < len(loadbalancer.BackendServers.BackendServer); i++ { + loadbalancer.BackendServers.BackendServer[i].lbbg = backendgroup + ibackends = append(ibackends, &loadbalancer.BackendServers.BackendServer[i]) + } + return ibackends, nil +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := backendgroup.GetILoadbalancerBackends() + if err != nil { + return nil, err + } + for i := 0; i < len(backends); i++ { + if backends[i].GetGlobalId() == backendId { + return backends[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + return cloudprovider.ErrNotSupported +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) Delete(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (region *SRegion) AddBackendServer(loadbalancerId, serverId string, weight, port int) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + servers := jsonutils.NewArray() + servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Weight": fmt.Sprintf("%d", weight)})) + params["BackendServers"] = servers.String() + _, err := region.lbRequest("AddBackendServers", params) + return err +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + if err := backendgroup.lb.region.AddBackendServer(backendgroup.lb.LoadBalancerId, serverId, weight, port); err != nil { + return nil, err + } + return &SLoadbalancerDefaultBackend{lbbg: backendgroup, ServerId: serverId, Weight: weight}, nil +} + +func (region *SRegion) RemoveBackendServer(loadbalancerId, serverId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + servers := jsonutils.NewArray() + servers.Add(jsonutils.NewString(serverId)) + params["BackendServers"] = servers.String() + _, err := region.lbRequest("RemoveBackendServers", params) + return err +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { + return backendgroup.lb.region.RemoveBackendServer(backendgroup.lb.LoadBalancerId, serverId) +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetProjectId() string { + return backendgroup.lb.GetProjectId() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerhttplistener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerhttplistener.go new file mode 100644 index 0000000000..1519b39e79 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerhttplistener.go @@ -0,0 +1,379 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerHTTPListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + AliyunTags + lb *SLoadbalancer + + ListenerPort int // 负载均衡实例前端使用的端口。 + BackendServerPort int // 负载均衡实例后端使用的端口。 + Bandwidth int // 监听的带宽峰值。 + Status string // 当前监听的状态。取值:starting | running | configuring | stopping | stopped + Description string + + XForwardedFor string // 是否开启通过X-Forwarded-For头字段获取访者真实IP。 + XForwardedFor_SLBIP string // 是否通过SLB-IP头字段获取客户端请求的真实IP。 + XForwardedFor_SLBID string // 是否通过SLB-ID头字段获取负载均衡实例ID。 + XForwardedFor_proto string // 是否通过X-Forwarded-Proto头字段获取负载均衡实例的监听协议。 + Scheduler string // 调度算法。 + StickySession string // 是否开启会话保持。 + StickySessionType string // cookie的处理方式。 + CookieTimeout int // Cookie超时时间。 + Cookie string // 服务器上配置的cookie。 + AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) + + AclType string // 访问控制类型: + //white: 仅转发来自所选访问控制策略组中设置的IP地址或地址段的请求,白名单适用于应用只允许特定IP访问的场景。 + //设置白名单存在一定业务风险。一旦设置白名单,就只有白名单中的IP可以访问负载均衡监听。如果开启了白名单访问,但访问策略组中没有添加任何IP,则负载均衡监听会转发全部请求。 + + //black: 来自所选访问控制策略组中设置的IP地址或地址段的所有请求都不会转发,黑名单适用于应用只限制某些特定IP访问的场景。 + //如果开启了黑名单访问,但访问策略组中没有添加任何IP,则负载均衡监听会转发全部请求。 + + //当AclStatus参数的值为on时,该参数必选。 + + AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 + + HealthCheck string // 是否开启健康检查。 + HealthCheckDomain string // 用于健康检查的域名。 + HealthCheckURI string // 用于健康检查的URI。 + HealthyThreshold int // 健康检查阈值。 + UnhealthyThreshold int // 不健康检查阈值。 + HealthCheckTimeout int // 每次健康检查响应的最大超时间,单位为秒。 + HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 + HealthCheckHttpCode string // 健康检查正常的HTTP状态码。 + HealthCheckConnectPort int // 健康检查的端口。 + Gzip string // 是否开启Gzip压缩。 + EnableHttp2 string // 是否开启HTTP/2特性。取值:on(默认值)|off + + Rules Rules //监听下的转发规则列表,具体请参见RuleList。 + ForwardPort int // HTTP至HTTPS的监听转发端口。暂时只支持将HTTP 80访问重定向转发至HTTPS 443。 说明 如果 ListenerForward的值为 off,该参数不显示。 + ListenerForward string // 表示是否开启HTTP至HTTPS的监听转发。on:表示开启 off:表示未开启 + VServerGroupId string // 绑定的服务器组ID +} + +func (listener *SLoadbalancerHTTPListener) GetName() string { + if len(listener.Description) == 0 { + listener.Refresh() + } + if len(listener.Description) > 0 { + return listener.Description + } + return fmt.Sprintf("HTTP:%d", listener.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPListener) GetId() string { + return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPListener) GetGlobalId() string { + return listerner.GetId() +} + +func (listerner *SLoadbalancerHTTPListener) GetStatus() string { + switch listerner.Status { + case "starting", "running": + return api.LB_STATUS_ENABLED + case "configuring", "stopping", "stopped": + return api.LB_STATUS_DISABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (listerner *SLoadbalancerHTTPListener) IsEmulated() bool { + return false +} + +func (listerner *SLoadbalancerHTTPListener) GetEgressMbps() int { + if listerner.Bandwidth < 1 { + return 0 + } + return listerner.Bandwidth +} + +func (listerner *SLoadbalancerHTTPListener) Refresh() error { + lis, err := listerner.lb.region.GetLoadbalancerHTTPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return err + } + return jsonutils.Update(listerner, lis) +} + +func (listerner *SLoadbalancerHTTPListener) GetListenerType() string { + return "http" +} + +func (listerner *SLoadbalancerHTTPListener) GetListenerPort() int { + return listerner.ListenerPort +} + +func (listerner *SLoadbalancerHTTPListener) GetBackendGroupId() string { + if len(listerner.VServerGroupId) == 0 { + listerner.Refresh() + } + return listerner.VServerGroupId +} + +func (listerner *SLoadbalancerHTTPListener) GetBackendServerPort() int { + return listerner.BackendServerPort +} + +func (listerner *SLoadbalancerHTTPListener) GetScheduler() string { + return listerner.Scheduler +} + +func (listerner *SLoadbalancerHTTPListener) GetAclStatus() string { + return listerner.AclStatus +} + +func (listerner *SLoadbalancerHTTPListener) GetAclType() string { + return listerner.AclType +} + +func (listerner *SLoadbalancerHTTPListener) GetAclId() string { + return listerner.AclId +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheck() string { + return listerner.HealthCheck +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckType() string { + return api.LB_HEALTH_CHECK_HTTP +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckDomain() string { + return listerner.HealthCheckDomain +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckURI() string { + return listerner.HealthCheckURI +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckCode() string { + return listerner.HealthCheckHttpCode +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckRise() int { + return listerner.HealthyThreshold +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckFail() int { + return listerner.UnhealthyThreshold +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckTimeout() int { + return listerner.HealthCheckTimeout +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckInterval() int { + return listerner.HealthCheckInterval +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckReq() string { + return "" +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckExp() string { + return "" +} + +func (listerner *SLoadbalancerHTTPListener) GetStickySession() string { + return listerner.StickySession +} + +func (listerner *SLoadbalancerHTTPListener) GetStickySessionType() string { + return listerner.StickySessionType +} + +func (listerner *SLoadbalancerHTTPListener) GetStickySessionCookie() string { + return listerner.Cookie +} + +func (listerner *SLoadbalancerHTTPListener) GetStickySessionCookieTimeout() int { + return listerner.CookieTimeout +} + +func (listerner *SLoadbalancerHTTPListener) XForwardedForEnabled() bool { + if listerner.XForwardedFor == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPListener) GzipEnabled() bool { + if listerner.Gzip == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPListener) GetCertificateId() string { + return "" +} + +func (listerner *SLoadbalancerHTTPListener) GetTLSCipherPolicy() string { + return "" +} + +func (listerner *SLoadbalancerHTTPListener) HTTP2Enabled() bool { + if listerner.EnableHttp2 == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + rules, err := listerner.lb.region.GetLoadbalancerListenerRules(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return nil, err + } + iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} + for i := 0; i < len(rules); i++ { + rules[i].httpListener = listerner + iRules = append(iRules, &rules[i]) + } + return iRules, nil +} + +func (region *SRegion) GetLoadbalancerHTTPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerHTTPListener, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + body, err := region.lbRequest("DescribeLoadBalancerHTTPListenerAttribute", params) + if err != nil { + return nil, err + } + listener := SLoadbalancerHTTPListener{} + return &listener, body.Unmarshal(&listener) +} + +func (region *SRegion) DeleteLoadbalancerListener(loadbalancerId string, listenerPort int) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + _, err := region.lbRequest("DeleteLoadBalancerListener", params) + return err +} + +func (region *SRegion) CreateLoadbalancerHTTPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + params := region.constructBaseCreateListenerParams(lb, listener) + params = region.constructHTTPCreateListenerParams(params, listener) + _, err := region.lbRequest("CreateLoadBalancerHTTPListener", params) + if err != nil { + return nil, err + } + iListener, err := region.GetLoadbalancerHTTPListener(lb.LoadBalancerId, listener.ListenerPort) + if err != nil { + return nil, err + } + iListener.lb = lb + return iListener, nil +} + +func (listerner *SLoadbalancerHTTPListener) Delete(ctx context.Context) error { + return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + _rule := &SLoadbalancerListenerRule{ + Domain: rule.Domain, + Url: rule.Path, + RuleName: rule.Name, + } + if len(rule.BackendGroupID) > 0 { //&& rule.BackendGroupType == api.LB_BACKENDGROUP_TYPE_NORMAL { + _rule.VServerGroupId = rule.BackendGroupID + } + listenerRule, err := listerner.lb.region.CreateLoadbalancerListenerRule(listerner.ListenerPort, listerner.lb.LoadBalancerId, _rule) + if err != nil { + return nil, err + } + listenerRule.httpListener = listerner + return listenerRule, nil +} + +func (listerner *SLoadbalancerHTTPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + rule, err := listerner.lb.region.GetLoadbalancerListenerRule(ruleId) + if err != nil { + return nil, err + } + rule.httpListener = listerner + return rule, nil +} + +func (region *SRegion) startListener(listenerPort int, loadbalancerId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + _, err := region.lbRequest("StartLoadBalancerListener", params) + return err +} + +func (region *SRegion) stopListener(listenerPort int, loadbalancerId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + _, err := region.lbRequest("StopLoadBalancerListener", params) + return err +} + +func (listerner *SLoadbalancerHTTPListener) Start() error { + return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (listerner *SLoadbalancerHTTPListener) Stop() error { + return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (region *SRegion) SyncLoadbalancerHTTPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { + params := region.constructBaseCreateListenerParams(lb, listener) + params = region.constructHTTPCreateListenerParams(params, listener) + _, err := region.lbRequest("SetLoadBalancerHTTPListenerAttribute", params) + return err +} + +func (listerner *SLoadbalancerHTTPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { + return listerner.lb.region.SyncLoadbalancerHTTPListener(listerner.lb, lblis) +} + +func (listerner *SLoadbalancerHTTPListener) GetProjectId() string { + return listerner.lb.GetProjectId() +} + +func (listerner *SLoadbalancerHTTPListener) GetClientIdleTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerHTTPListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerhttpslistener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerhttpslistener.go new file mode 100644 index 0000000000..bdcd5c483b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerhttpslistener.go @@ -0,0 +1,409 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerHTTPSListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + AliyunTags + lb *SLoadbalancer + + ListenerPort int // 负载均衡实例前端使用的端口。 + BackendServerPort int // 负载均衡实例后端使用的端口。 + Bandwidth int // 监听的带宽峰值。 + Status string // 当前监听的状态。取值:starting | running | configuring | stopping | stopped + Description string + + XForwardedFor string // 是否开启通过X-Forwarded-For头字段获取访者真实IP。 + XForwardedFor_SLBIP string // 是否通过SLB-IP头字段获取客户端请求的真实IP。 + XForwardedFor_SLBID string // 是否通过SLB-ID头字段获取负载均衡实例ID。 + XForwardedFor_proto string // 是否通过X-Forwarded-Proto头字段获取负载均衡实例的监听协议。 + Scheduler string // 调度算法。 + StickySession string // 是否开启会话保持。 + StickySessionType string // cookie的处理方式。 + CookieTimeout int // Cookie超时时间。 + Cookie string // 服务器上配置的cookie。 + AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) + + AclType string // 访问控制类型 + + AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 + + HealthCheck string // 是否开启健康检查。 + HealthCheckDomain string // 用于健康检查的域名。 + HealthCheckURI string // 用于健康检查的URI。 + HealthyThreshold int // 健康检查阈值。 + UnhealthyThreshold int // 不健康检查阈值。 + HealthCheckTimeout int // 每次健康检查响应的最大超时间,单位为秒。 + HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 + HealthCheckHttpCode string // 健康检查正常的HTTP状态码。 + HealthCheckConnectPort int // 健康检查的端口。 + VServerGroupId string // 绑定的服务器组ID。 + ServerCertificateId string // 服务器证书ID。 + CACertificateId string // CA证书ID。 + Gzip string // 是否开启Gzip压缩。 + Rules Rules //监听下的转发规则列表,具体请参见RuleList。 + DomainExtensions string // 域名扩展列表,具体请参见DomainExtensions。 + EnableHttp2 string // 是否开启HTTP/2特性。取值:on(默认值)|off + + TLSCipherPolicy string // +} + +func (listener *SLoadbalancerHTTPSListener) GetName() string { + if len(listener.Description) == 0 { + listener.Refresh() + } + if len(listener.Description) > 0 { + return listener.Description + } + return fmt.Sprintf("HTTPS:%d", listener.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPSListener) GetId() string { + return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPSListener) GetGlobalId() string { + return listerner.GetId() +} + +func (listerner *SLoadbalancerHTTPSListener) GetStatus() string { + switch listerner.Status { + case "starting", "running": + return api.LB_STATUS_ENABLED + case "configuring", "stopping", "stopped": + return api.LB_STATUS_DISABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (listerner *SLoadbalancerHTTPSListener) IsEmulated() bool { + return false +} + +func (listerner *SLoadbalancerHTTPSListener) GetEgressMbps() int { + if listerner.Bandwidth < 1 { + return 0 + } + return listerner.Bandwidth +} + +func (listerner *SLoadbalancerHTTPSListener) Refresh() error { + lis, err := listerner.lb.region.GetLoadbalancerHTTPSListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return err + } + return jsonutils.Update(listerner, lis) +} + +func (listerner *SLoadbalancerHTTPSListener) GetListenerType() string { + return "https" +} + +func (listerner *SLoadbalancerHTTPSListener) GetListenerPort() int { + return listerner.ListenerPort +} + +func (listerner *SLoadbalancerHTTPSListener) GetBackendGroupId() string { + if len(listerner.VServerGroupId) == 0 { + listerner.Refresh() + } + return listerner.VServerGroupId +} + +func (listerner *SLoadbalancerHTTPSListener) GetBackendServerPort() int { + return listerner.BackendServerPort +} + +func (listerner *SLoadbalancerHTTPSListener) GetScheduler() string { + return listerner.Scheduler +} + +func (listerner *SLoadbalancerHTTPSListener) GetAclStatus() string { + return listerner.AclStatus +} + +func (listerner *SLoadbalancerHTTPSListener) GetAclType() string { + return listerner.AclType +} + +func (listerner *SLoadbalancerHTTPSListener) GetAclId() string { + return listerner.AclId +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheck() string { + return listerner.HealthCheck +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckType() string { + return api.LB_HEALTH_CHECK_HTTP +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckDomain() string { + return listerner.HealthCheckDomain +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckURI() string { + return listerner.HealthCheckURI +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckCode() string { + return listerner.HealthCheckHttpCode +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckRise() int { + return listerner.HealthyThreshold +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckFail() int { + return listerner.UnhealthyThreshold +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckTimeout() int { + return listerner.HealthCheckTimeout +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckInterval() int { + return listerner.HealthCheckInterval +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckReq() string { + return "" +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckExp() string { + return "" +} + +func (listerner *SLoadbalancerHTTPSListener) GetStickySession() string { + return listerner.StickySession +} + +func (listerner *SLoadbalancerHTTPSListener) GetStickySessionType() string { + return listerner.StickySessionType +} + +func (listerner *SLoadbalancerHTTPSListener) GetStickySessionCookie() string { + return listerner.Cookie +} + +func (listerner *SLoadbalancerHTTPSListener) GetStickySessionCookieTimeout() int { + return listerner.CookieTimeout +} + +func (listerner *SLoadbalancerHTTPSListener) XForwardedForEnabled() bool { + if listerner.XForwardedFor == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPSListener) GzipEnabled() bool { + if listerner.Gzip == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPSListener) GetCertificateId() string { + return listerner.ServerCertificateId +} + +func (listerner *SLoadbalancerHTTPSListener) GetTLSCipherPolicy() string { + return listerner.TLSCipherPolicy +} + +func (listerner *SLoadbalancerHTTPSListener) HTTP2Enabled() bool { + if listerner.EnableHttp2 == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPSListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + rules, err := listerner.lb.region.GetLoadbalancerListenerRules(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return nil, err + } + iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} + for i := 0; i < len(rules); i++ { + rules[i].httpsListener = listerner + iRules = append(iRules, &rules[i]) + } + return iRules, nil +} + +func (region *SRegion) GetLoadbalancerHTTPSListener(loadbalancerId string, listenerPort int) (*SLoadbalancerHTTPSListener, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + body, err := region.lbRequest("DescribeLoadBalancerHTTPSListenerAttribute", params) + if err != nil { + return nil, err + } + listener := SLoadbalancerHTTPSListener{} + return &listener, body.Unmarshal(&listener) +} + +func (region *SRegion) constructHTTPCreateListenerParams(params map[string]string, listener *cloudprovider.SLoadbalancerListener) map[string]string { + params["HealthCheck"] = listener.HealthCheck + if listener.HealthCheck == "on" { + if len(listener.HealthCheckURI) == 0 { + params["HealthCheckURI"] = "/" + } + //The HealthCheckTimeout parameter is required. + if listener.HealthCheckTimeout < 1 || listener.HealthCheckTimeout > 300 { + listener.HealthCheckTimeout = 5 + } + params["HealthCheckTimeout"] = fmt.Sprintf("%d", listener.HealthCheckTimeout) + } + + if listener.ClientRequestTimeout < 1 || listener.ClientRequestTimeout > 180 { + listener.ClientRequestTimeout = 60 + } + params["RequestTimeout"] = fmt.Sprintf("%d", listener.ClientRequestTimeout) + + if listener.ClientIdleTimeout < 1 || listener.ClientIdleTimeout > 60 { + listener.ClientIdleTimeout = 15 + } + params["IdleTimeout"] = fmt.Sprintf("%d", listener.ClientIdleTimeout) + + params["StickySession"] = listener.StickySession + params["StickySessionType"] = listener.StickySessionType + params["Cookie"] = listener.StickySessionCookie + if listener.StickySessionCookieTimeout < 1 || listener.StickySessionCookieTimeout > 86400 { + listener.StickySessionCookieTimeout = 500 + } + params["CookieTimeout"] = fmt.Sprintf("%d", listener.StickySessionCookieTimeout) + //params["ForwardPort"] = fmt.Sprintf("%d", listener.ForwardPort) //暂不支持 + params["Gzip"] = "off" + if listener.Gzip { + params["Gzip"] = "on" + } + params["XForwardedFor"] = "off" + if listener.XForwardedFor { + params["XForwardedFor"] = "on" + } + return params +} + +func (region *SRegion) CreateLoadbalancerHTTPSListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + params := region.constructBaseCreateListenerParams(lb, listener) + params = region.constructHTTPCreateListenerParams(params, listener) + params["ServerCertificateId"] = listener.CertificateID + if listener.EnableHTTP2 { + params["EnableHttp2"] = "on" + } else { + params["EnableHttp2"] = "off" + } + + if len(listener.TLSCipherPolicy) > 0 { + params["TLSCipherPolicy"] = listener.TLSCipherPolicy + } + _, err := region.lbRequest("CreateLoadBalancerHTTPSListener", params) + if err != nil { + return nil, err + } + iListener, err := region.GetLoadbalancerHTTPSListener(lb.LoadBalancerId, listener.ListenerPort) + if err != nil { + return nil, err + } + iListener.lb = lb + return iListener, nil +} + +func (listerner *SLoadbalancerHTTPSListener) Delete(ctx context.Context) error { + return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPSListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + _rule := &SLoadbalancerListenerRule{ + Domain: rule.Domain, + Url: rule.Path, + RuleName: rule.Name, + } + if len(rule.BackendGroupID) > 0 { //&& rule.BackendGroupType == api.LB_BACKENDGROUP_TYPE_NORMAL { + _rule.VServerGroupId = rule.BackendGroupID + } + listenerRule, err := listerner.lb.region.CreateLoadbalancerListenerRule(listerner.ListenerPort, listerner.lb.LoadBalancerId, _rule) + if err != nil { + return nil, err + } + listenerRule.httpsListener = listerner + return listenerRule, nil +} + +func (listerner *SLoadbalancerHTTPSListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + rule, err := listerner.lb.region.GetLoadbalancerListenerRule(ruleId) + if err != nil { + return nil, err + } + rule.httpsListener = listerner + return rule, nil +} + +func (listerner *SLoadbalancerHTTPSListener) Start() error { + return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (listerner *SLoadbalancerHTTPSListener) Stop() error { + return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (region *SRegion) SyncLoadbalancerHTTPSListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { + params := region.constructBaseCreateListenerParams(lb, listener) + params = region.constructHTTPCreateListenerParams(params, listener) + params["ServerCertificateId"] = listener.CertificateID + if listener.EnableHTTP2 { + params["EnableHttp2"] = "on" + } else { + params["EnableHttp2"] = "off" + } + + if len(lb.LoadBalancerSpec) > 0 && len(listener.TLSCipherPolicy) > 0 { + params["TLSCipherPolicy"] = listener.TLSCipherPolicy + } + _, err := region.lbRequest("SetLoadBalancerHTTPSListenerAttribute", params) + return err +} + +func (listerner *SLoadbalancerHTTPSListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { + return listerner.lb.region.SyncLoadbalancerHTTPSListener(listerner.lb, lblis) +} + +func (listerner *SLoadbalancerHTTPSListener) GetProjectId() string { + return listerner.lb.GetProjectId() +} + +func (listerner *SLoadbalancerHTTPSListener) GetClientIdleTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerHTTPSListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerlistenerrule.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerlistenerrule.go new file mode 100644 index 0000000000..2a8720e666 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerlistenerrule.go @@ -0,0 +1,182 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerListenerRule struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + AliyunTags + httpListener *SLoadbalancerHTTPListener + httpsListener *SLoadbalancerHTTPSListener + + Domain string `json:"Domain"` + ListenerSync string + RuleId string + RuleName string `json:"RuleName"` + Url string `json:"Url"` + VServerGroupId string `json:"VServerGroupId"` +} + +func (lbr *SLoadbalancerListenerRule) GetName() string { + return lbr.RuleName +} + +func (lbr *SLoadbalancerListenerRule) GetId() string { + return lbr.RuleId +} + +func (lbr *SLoadbalancerListenerRule) GetGlobalId() string { + return lbr.RuleId +} + +func (lbr *SLoadbalancerListenerRule) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancerListenerRule) IsDefault() bool { + return false +} + +func (lbr *SLoadbalancerListenerRule) IsEmulated() bool { + return false +} + +func (lbr *SLoadbalancerListenerRule) getRegion() *SRegion { + if lbr.httpListener != nil { + return lbr.httpListener.lb.region + } else if lbr.httpsListener != nil { + return lbr.httpsListener.lb.region + } + return nil +} + +func (lbr *SLoadbalancerListenerRule) Refresh() error { + region := lbr.getRegion() + if region == nil { + return fmt.Errorf("failed to find listener for rule %s", lbr.RuleName) + } + rule, err := region.GetLoadbalancerListenerRule(lbr.RuleId) + if err != nil { + return err + } + return jsonutils.Update(lbr, rule) +} + +func (lbr *SLoadbalancerListenerRule) GetCondition() string { + return "" +} + +func (lbr *SLoadbalancerListenerRule) GetDomain() string { + return lbr.Domain +} + +func (lbr *SLoadbalancerListenerRule) GetPath() string { + return lbr.Url +} + +func (lbr *SLoadbalancerListenerRule) GetProjectId() string { + if lbr.httpListener != nil { + return lbr.httpListener.GetProjectId() + } else if lbr.httpsListener != nil { + return lbr.httpsListener.GetProjectId() + } + + return "" +} + +func (lbr *SLoadbalancerListenerRule) GetBackendGroupId() string { + return lbr.VServerGroupId +} + +func (region *SRegion) GetLoadbalancerListenerRules(loadbalancerId string, listenerPort int) ([]SLoadbalancerListenerRule, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + body, err := region.lbRequest("DescribeRules", params) + if err != nil { + return nil, err + } + rules := []SLoadbalancerListenerRule{} + return rules, body.Unmarshal(&rules, "Rules", "Rule") +} + +func (lbr *SLoadbalancerListenerRule) Delete(ctx context.Context) error { + if lbr.httpListener != nil { + return lbr.httpListener.lb.region.DeleteLoadbalancerListenerRule(lbr.RuleId) + } + if lbr.httpsListener != nil { + return lbr.httpsListener.lb.region.DeleteLoadbalancerListenerRule(lbr.RuleId) + } + return fmt.Errorf("failed to find listener for listener rule %s", lbr.RuleName) +} + +func (region *SRegion) DeleteLoadbalancerListenerRule(ruleId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["RuleIds"] = fmt.Sprintf(`["%s"]`, ruleId) + _, err := region.lbRequest("DeleteRules", params) + return err +} + +func (region *SRegion) CreateLoadbalancerListenerRule(listenerPort int, loadbalancerId string, _rule *SLoadbalancerListenerRule) (*SLoadbalancerListenerRule, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + params["LoadBalancerId"] = loadbalancerId + _rules := jsonutils.NewArray() + _rules.Add(jsonutils.Marshal(_rule)) + params["RuleList"] = _rules.String() + body, err := region.lbRequest("CreateRules", params) + if err != nil { + return nil, err + } + rules := []SLoadbalancerListenerRule{} + if err := body.Unmarshal(&rules, "Rules", "Rule"); err != nil { + return nil, err + } + for _, rule := range rules { + if rule.RuleName == _rule.RuleName { + return region.GetLoadbalancerListenerRule(rule.RuleId) + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetLoadbalancerListenerRule(ruleId string) (*SLoadbalancerListenerRule, error) { + if len(ruleId) == 0 { + return nil, cloudprovider.ErrNotFound + } + params := map[string]string{} + params["RegionId"] = region.RegionId + params["RuleId"] = ruleId + body, err := region.lbRequest("DescribeRuleAttribute", params) + if err != nil { + return nil, err + } + rule := &SLoadbalancerListenerRule{RuleId: ruleId} + return rule, body.Unmarshal(rule) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancermasterslavebackend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancermasterslavebackend.go new file mode 100644 index 0000000000..1007524c4e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancermasterslavebackend.go @@ -0,0 +1,92 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + "strings" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerMasterSlaveBackend struct { + multicloud.SResourceBase + AliyunTags + lbbg *SLoadbalancerMasterSlaveBackendGroup + + ServerId string + Weight int + Port int + ServerType string +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetName() string { + return backend.ServerId +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetId() string { + return fmt.Sprintf("%s/%s", backend.lbbg.MasterSlaveServerGroupId, backend.ServerId) +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetGlobalId() string { + return backend.GetId() +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backend *SLoadbalancerMasterSlaveBackend) IsEmulated() bool { + return false +} + +func (backend *SLoadbalancerMasterSlaveBackend) Refresh() error { + return nil +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetWeight() int { + return backend.Weight +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetPort() int { + return backend.Port +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetBackendRole() string { + return strings.ToLower(backend.ServerType) +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetBackendId() string { + return backend.ServerId +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetIpAddress() string { + return "" +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetProjectId() string { + return backend.lbbg.GetProjectId() +} + +func (backend *SLoadbalancerMasterSlaveBackend) SyncConf(ctx context.Context, port, weight int) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancermasterslavebackendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancermasterslavebackendgroup.go new file mode 100644 index 0000000000..b1f9d09b0e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancermasterslavebackendgroup.go @@ -0,0 +1,214 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerMasterSlaveBackendGroup struct { + multicloud.SResourceBase + AliyunTags + lb *SLoadbalancer + + MasterSlaveServerGroupId string + MasterSlaveServerGroupName string +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetLoadbalancerId() string { + return backendgroup.lb.GetId() +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetProtocolType() string { + return "" +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetScheduler() string { + return "" +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetName() string { + return backendgroup.MasterSlaveServerGroupName +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetId() string { + return backendgroup.MasterSlaveServerGroupId +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetGlobalId() string { + return backendgroup.GetId() +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) IsEmulated() bool { + return false +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Refresh() error { + return nil +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) IsDefault() bool { + return false +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE +} + +func (region *SRegion) GetLoadbalancerMasterSlaveBackendgroups(loadbalancerId string) ([]SLoadbalancerMasterSlaveBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + body, err := region.lbRequest("DescribeMasterSlaveServerGroups", params) + if err != nil { + return nil, err + } + backendgroups := []SLoadbalancerMasterSlaveBackendGroup{} + return backendgroups, body.Unmarshal(&backendgroups, "MasterSlaveServerGroups", "MasterSlaveServerGroup") +} + +func (region *SRegion) GetLoadbalancerMasterSlaveBackends(backendgroupId string) ([]SLoadbalancerMasterSlaveBackend, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["MasterSlaveServerGroupId"] = backendgroupId + body, err := region.lbRequest("DescribeMasterSlaveServerGroupAttribute", params) + if err != nil { + return nil, err + } + backends := []SLoadbalancerMasterSlaveBackend{} + return backends, body.Unmarshal(&backends, "MasterSlaveBackendServers", "MasterSlaveBackendServer") +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := backendgroup.lb.region.GetLoadbalancerMasterSlaveBackends(backendgroup.MasterSlaveServerGroupId) + if err != nil { + return nil, err + } + ibackends := []cloudprovider.ICloudLoadbalancerBackend{} + for i := 0; i < len(backends); i++ { + backends[i].lbbg = backendgroup + ibackends = append(ibackends, &backends[i]) + } + return ibackends, nil +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := backendgroup.GetILoadbalancerBackends() + if err != nil { + return nil, err + } + for i := 0; i < len(backends); i++ { + if backends[i].GetGlobalId() == backendId { + return backends[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) CreateLoadbalancerMasterSlaveBackendGroup(name, loadbalancerId string, backends []cloudprovider.SLoadbalancerBackend) (*SLoadbalancerMasterSlaveBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["MasterSlaveServerGroupName"] = name + params["LoadBalancerId"] = loadbalancerId + if len(backends) != 2 { + return nil, fmt.Errorf("master slave backendgorup must contain two backend") + } + servers := jsonutils.NewArray() + for _, backend := range backends { + serverType := "Slave" + if backend.Index == 0 { + serverType = "Master" + } + servers.Add( + jsonutils.Marshal( + map[string]string{ + "ServerId": backend.ExternalID, + "Port": fmt.Sprintf("%d", backend.Port), + "Weight": fmt.Sprintf("%d", backend.Weight), + "ServerType": serverType, + }, + )) + } + params["MasterSlaveBackendServers"] = servers.String() + body, err := region.lbRequest("CreateMasterSlaveServerGroup", params) + if err != nil { + return nil, err + } + groupId, err := body.GetString("MasterSlaveServerGroupId") + if err != nil { + return nil, err + } + return region.GetLoadbalancerMasterSlaveBackendgroupById(groupId) +} + +func (region *SRegion) GetLoadbalancerMasterSlaveBackendgroupById(groupId string) (*SLoadbalancerMasterSlaveBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["MasterSlaveServerGroupId"] = groupId + params["NeedInstanceDetail"] = "true" + body, err := region.lbRequest("DescribeMasterSlaveServerGroupAttribute", params) + if err != nil { + return nil, err + } + group := &SLoadbalancerMasterSlaveBackendGroup{} + return group, body.Unmarshal(group) +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + return nil +} + +func (region *SRegion) DeleteLoadbalancerMasterSlaveBackendgroup(groupId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["MasterSlaveServerGroupId"] = groupId + _, err := region.lbRequest("DeleteMasterSlaveServerGroup", params) + return err +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Delete(ctx context.Context) error { + return backendgroup.lb.region.DeleteLoadbalancerMasterSlaveBackendgroup(backendgroup.MasterSlaveServerGroupId) +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { + return cloudprovider.ErrNotSupported +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetProjectId() string { + return backendgroup.lb.GetProjectId() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerservercertificate.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerservercertificate.go new file mode 100644 index 0000000000..9cf79fbfb4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerservercertificate.go @@ -0,0 +1,139 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SubjectAlternativeNames struct { + SubjectAlternativeName []string +} + +type SLoadbalancerServerCertificate struct { + multicloud.SResourceBase + AliyunTags + region *SRegion + + ServerCertificateId string // 服务器证书ID。 + ServerCertificateName string // 服务器证书名称。 + Fingerprint string // 服务器证书的指纹。 + CreateTime string // 服务器证书上传的时间。 + CreateTimeStamp uint64 // 服务器证书上传的时间戳。 + IsAliCloudCertificate int // 是否是阿里云证书。0代表不是阿里云证书。 + AliCloudCertificateName string // 阿里云证书名称。 + AliCloudCertificateId string // 阿里云证书ID。 + ExpireTime time.Time // 过期时间。 + ExpireTimeStamp uint64 // 过期时间戳。 + CommonName string // 域名,对应证书的CommonName字段。 + SubjectAlternativeNames SubjectAlternativeNames // 数组格式,返回证书的备用域名列表,对应证书的Subject Alternative Name字段,详情请参见SubjectAlternativeNames。 + ResourceGroupId string // 实例的企业资源组ID + RegionId string // 负载均衡实例的地域。 +} + +func (certificate *SLoadbalancerServerCertificate) GetPublickKey() string { + return "" +} + +func (certificate *SLoadbalancerServerCertificate) GetPrivateKey() string { + return "" +} + +func (certificate *SLoadbalancerServerCertificate) GetName() string { + return certificate.ServerCertificateName +} + +func (certificate *SLoadbalancerServerCertificate) GetId() string { + return certificate.ServerCertificateId +} + +func (certificate *SLoadbalancerServerCertificate) GetGlobalId() string { + return certificate.GetId() +} + +func (certificate *SLoadbalancerServerCertificate) GetStatus() string { + return "" +} + +func (certificate *SLoadbalancerServerCertificate) IsEmulated() bool { + return false +} + +func (certificate *SLoadbalancerServerCertificate) GetCommonName() string { + return certificate.CommonName +} + +func (certificate *SLoadbalancerServerCertificate) GetSubjectAlternativeNames() string { + return strings.Join(certificate.SubjectAlternativeNames.SubjectAlternativeName, ",") +} + +func (certificate *SLoadbalancerServerCertificate) GetFingerprint() string { + return fmt.Sprintf("sha1:%s", strings.Replace(certificate.Fingerprint, ":", "", -1)) +} + +func (certificate *SLoadbalancerServerCertificate) GetExpireTime() time.Time { + return certificate.ExpireTime +} + +func (certificate *SLoadbalancerServerCertificate) Refresh() error { + return nil +} + +func (region *SRegion) UpdateServerCertificateName(certId, name string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["ServerCertificateId"] = certId + params["ServerCertificateName"] = name + _, err := region.lbRequest("SetServerCertificateName", params) + return err +} + +func (certificate *SLoadbalancerServerCertificate) Sync(name string, privateKey string, publicKey string) error { + if certificate.ServerCertificateName != name { + return certificate.region.UpdateServerCertificateName(certificate.ServerCertificateId, name) + } + return nil +} + +func (certificate *SLoadbalancerServerCertificate) Delete() error { + return certificate.region.DeleteServerCertificate(certificate.ServerCertificateId) +} + +func (region *SRegion) DeleteServerCertificate(certId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["ServerCertificateId"] = certId + _, err := region.lbRequest("DeleteServerCertificate", params) + return err +} + +func (region *SRegion) GetLoadbalancerServerCertificates() ([]SLoadbalancerServerCertificate, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + body, err := region.lbRequest("DescribeServerCertificates", params) + if err != nil { + return nil, err + } + certificates := []SLoadbalancerServerCertificate{} + return certificates, body.Unmarshal(&certificates, "ServerCertificates", "ServerCertificate") +} + +func (certificate *SLoadbalancerServerCertificate) GetProjectId() string { + return certificate.ResourceGroupId +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancertcplistener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancertcplistener.go new file mode 100644 index 0000000000..cdf9fcebdf --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancertcplistener.go @@ -0,0 +1,368 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerTCPListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + AliyunTags + lb *SLoadbalancer + + ListenerPort int // 负载均衡实例前端使用的端口。 + BackendServerPort int // 负载均衡实例后端使用的端口。 + Bandwidth int // 监听的带宽峰值。 + Status string // 当前监听的状态,取值:starting | running | configuring | stopping | stopped + Description string + + Scheduler string // 调度算法。 + VServerGroupId string // 绑定的服务器组ID。 + MasterSlaveServerGroupId string // 绑定的主备服务器组ID。 + AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) + PersistenceTimeout int //是否开启了会话保持。取值为0时,表示没有开启。 + + AclType string // 访问控制类型 + + AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 + + HealthCheck string // 是否开启健康检查。 + HealthCheckType string //TCP协议监听的健康检查方式。取值:tcp | http + HealthyThreshold int // 健康检查阈值。 + UnhealthyThreshold int // 不健康检查阈值。 + HealthCheckConnectTimeout int // 每次健康检查响应的最大超时间,单位为秒。 + HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 + HealthCheckConnectPort int // 健康检查的端口。 +} + +func (listener *SLoadbalancerTCPListener) GetName() string { + if len(listener.Description) == 0 { + listener.Refresh() + } + if len(listener.Description) > 0 { + return listener.Description + } + return fmt.Sprintf("TCP:%d", listener.ListenerPort) +} + +func (listerner *SLoadbalancerTCPListener) GetId() string { + return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerTCPListener) GetGlobalId() string { + return listerner.GetId() +} + +func (listerner *SLoadbalancerTCPListener) GetStatus() string { + switch listerner.Status { + case "starting", "running": + return api.LB_STATUS_ENABLED + case "configuring", "stopping", "stopped": + return api.LB_STATUS_DISABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (listerner *SLoadbalancerTCPListener) GetEgressMbps() int { + if listerner.Bandwidth < 1 { + return 0 + } + return listerner.Bandwidth +} + +func (listerner *SLoadbalancerTCPListener) IsEmulated() bool { + return false +} + +func (listerner *SLoadbalancerTCPListener) Refresh() error { + lis, err := listerner.lb.region.GetLoadbalancerTCPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return err + } + return jsonutils.Update(listerner, lis) +} + +func (listerner *SLoadbalancerTCPListener) GetListenerType() string { + return "tcp" +} +func (listerner *SLoadbalancerTCPListener) GetListenerPort() int { + return listerner.ListenerPort +} + +func (listerner *SLoadbalancerTCPListener) GetBackendGroupId() string { + if len(listerner.VServerGroupId) > 0 { + return listerner.VServerGroupId + } + return listerner.MasterSlaveServerGroupId +} + +func (listerner *SLoadbalancerTCPListener) GetScheduler() string { + return listerner.Scheduler +} + +func (listerner *SLoadbalancerTCPListener) GetAclStatus() string { + return listerner.AclStatus +} + +func (listerner *SLoadbalancerTCPListener) GetAclType() string { + return listerner.AclType +} + +func (listerner *SLoadbalancerTCPListener) GetAclId() string { + return listerner.AclId +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheck() string { + return listerner.HealthCheck +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckType() string { + return listerner.HealthCheckType +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckDomain() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckURI() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckCode() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckRise() int { + return listerner.HealthyThreshold +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckFail() int { + return listerner.UnhealthyThreshold +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckTimeout() int { + return listerner.HealthCheckConnectTimeout +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckInterval() int { + return listerner.HealthCheckInterval +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckReq() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckExp() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetStickySession() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetStickySessionType() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetStickySessionCookie() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetStickySessionCookieTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerTCPListener) XForwardedForEnabled() bool { + return false +} + +func (listerner *SLoadbalancerTCPListener) GzipEnabled() bool { + return false +} + +func (listerner *SLoadbalancerTCPListener) GetCertificateId() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetTLSCipherPolicy() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) HTTP2Enabled() bool { + return false +} + +func (listerner *SLoadbalancerTCPListener) GetBackendServerPort() int { + return listerner.BackendServerPort +} + +func (listerner *SLoadbalancerTCPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + return []cloudprovider.ICloudLoadbalancerListenerRule{}, nil +} + +func (region *SRegion) GetLoadbalancerTCPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerTCPListener, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + body, err := region.lbRequest("DescribeLoadBalancerTCPListenerAttribute", params) + if err != nil { + return nil, err + } + listener := SLoadbalancerTCPListener{} + return &listener, body.Unmarshal(&listener) +} + +func (region *SRegion) constructBaseCreateListenerParams(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) map[string]string { + params := map[string]string{} + params["RegionId"] = region.RegionId + if listener.EgressMbps < 1 { + listener.EgressMbps = -1 + } + params["Bandwidth"] = fmt.Sprintf("%d", listener.EgressMbps) + params["ListenerPort"] = fmt.Sprintf("%d", listener.ListenerPort) + params["LoadBalancerId"] = lb.LoadBalancerId + if len(listener.AccessControlListID) > 0 { + params["AclId"] = listener.AccessControlListID + } + if utils.IsInStringArray(listener.AccessControlListStatus, []string{"on", "off"}) { + params["AclStatus"] = listener.AccessControlListStatus + } + if utils.IsInStringArray(listener.AccessControlListType, []string{"white", "black"}) { + params["AclType"] = listener.AccessControlListType + } + switch listener.BackendGroupType { + case api.LB_BACKENDGROUP_TYPE_NORMAL: + params["VServerGroupId"] = listener.BackendGroupID + params["VServerGroup"] = "on" + case api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE: + params["MasterSlaveServerGroupId"] = listener.BackendGroupID + params["MasterSlaveServerGroup"] = "on" + case api.LB_BACKENDGROUP_TYPE_DEFAULT: + params["BackendServerPort"] = fmt.Sprintf("%d", listener.BackendServerPort) + } + if len(listener.Name) > 0 { + params["Description"] = listener.Name + } + + if utils.IsInStringArray(listener.ListenerType, []string{api.LB_LISTENER_TYPE_TCP, api.LB_LISTENER_TYPE_UDP}) { + if listener.HealthCheckTimeout >= 1 && listener.HealthCheckTimeout <= 300 { + params["HealthCheckConnectTimeout"] = fmt.Sprintf("%d", listener.HealthCheckTimeout) + } + } + switch listener.ListenerType { + case api.LB_LISTENER_TYPE_UDP: + if len(listener.HealthCheckReq) > 0 { + params["healthCheckReq"] = listener.HealthCheckReq + } + if len(listener.HealthCheckExp) > 0 { + params["healthCheckExp"] = listener.HealthCheckExp + } + } + + if len(listener.HealthCheckDomain) > 0 { + params["HealthCheckDomain"] = listener.HealthCheckDomain + } + + if len(listener.HealthCheckHttpCode) > 0 { + params["HealthCheckHttpCode"] = listener.HealthCheckHttpCode + } + + if len(listener.HealthCheckURI) > 0 { + params["HealthCheckURI"] = listener.HealthCheckURI + } + + if listener.HealthCheckRise >= 2 && listener.HealthCheckRise <= 10 { + params["HealthyThreshold"] = fmt.Sprintf("%d", listener.HealthCheckRise) + } + + if listener.HealthCheckFail >= 2 && listener.HealthCheckFail <= 10 { + params["UnhealthyThreshold"] = fmt.Sprintf("%d", listener.HealthCheckFail) + } + + if listener.HealthCheckInterval >= 1 && listener.HealthCheckInterval <= 50 { + params["healthCheckInterval"] = fmt.Sprintf("%d", listener.HealthCheckInterval) + } + + params["Scheduler"] = listener.Scheduler + return params +} + +func (region *SRegion) CreateLoadbalancerTCPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + params := region.constructBaseCreateListenerParams(lb, listener) + _, err := region.lbRequest("CreateLoadBalancerTCPListener", params) + if err != nil { + return nil, err + } + iListener, err := region.GetLoadbalancerTCPListener(lb.LoadBalancerId, listener.ListenerPort) + if err != nil { + return nil, err + } + iListener.lb = lb + return iListener, nil +} + +func (listerner *SLoadbalancerTCPListener) Delete(ctx context.Context) error { + return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerTCPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (listerner *SLoadbalancerTCPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (listerner *SLoadbalancerTCPListener) Start() error { + return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (listerner *SLoadbalancerTCPListener) Stop() error { + return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (region *SRegion) SyncLoadbalancerTCPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { + params := region.constructBaseCreateListenerParams(lb, listener) + _, err := region.lbRequest("SetLoadBalancerTCPListenerAttribute", params) + return err +} + +func (listerner *SLoadbalancerTCPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { + return listerner.lb.region.SyncLoadbalancerTCPListener(listerner.lb, lblis) +} + +func (listerner *SLoadbalancerTCPListener) GetProjectId() string { + return listerner.lb.GetProjectId() +} + +func (listerner *SLoadbalancerTCPListener) GetClientIdleTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerTCPListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerudplistener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerudplistener.go new file mode 100644 index 0000000000..4805fda44f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/loadbalancerudplistener.go @@ -0,0 +1,294 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerUDPListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + AliyunTags + lb *SLoadbalancer + + ListenerPort int // 负载均衡实例前端使用的端口。 + BackendServerPort int // 负载均衡实例后端使用的端口。 + Bandwidth int // 监听的带宽峰值。 + Status string // 当前监听的状态,取值:starting | running | configuring | stopping | stopped + Description string + + Scheduler string // 调度算法 + VServerGroupId string // 绑定的服务器组ID。 + MasterSlaveServerGroupId string // 绑定的主备服务器组ID。 + AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) + + AclType string // 访问控制类型: + + AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 + + HealthCheck string // 是否开启健康检查。 + HealthyThreshold int // 健康检查阈值。 + UnhealthyThreshold int // 不健康检查阈值。 + HealthCheckConnectTimeout int // 每次健康检查响应的最大超时间,单位为秒。 + HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 + HealthCheckConnectPort int // 健康检查的端口。 + + HealthCheckExp string // UDP监听健康检查的响应串 + HealthCheckReq string // UDP监听健康检查的请求串 +} + +func (listener *SLoadbalancerUDPListener) GetName() string { + if len(listener.Description) == 0 { + listener.Refresh() + } + if len(listener.Description) > 0 { + return listener.Description + } + return fmt.Sprintf("UDP:%d", listener.ListenerPort) +} + +func (listerner *SLoadbalancerUDPListener) GetId() string { + return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerUDPListener) GetGlobalId() string { + return listerner.GetId() +} + +func (listerner *SLoadbalancerUDPListener) GetStatus() string { + switch listerner.Status { + case "starting", "running": + return api.LB_STATUS_ENABLED + case "configuring", "stopping", "stopped": + return api.LB_STATUS_DISABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (listerner *SLoadbalancerUDPListener) GetEgressMbps() int { + if listerner.Bandwidth < 1 { + return 0 + } + return listerner.Bandwidth +} + +func (listerner *SLoadbalancerUDPListener) IsEmulated() bool { + return false +} + +func (listerner *SLoadbalancerUDPListener) Refresh() error { + lis, err := listerner.lb.region.GetLoadbalancerUDPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return err + } + return jsonutils.Update(listerner, lis) +} + +func (listerner *SLoadbalancerUDPListener) GetListenerType() string { + return "udp" +} + +func (listerner *SLoadbalancerUDPListener) GetListenerPort() int { + return listerner.ListenerPort +} + +func (listerner *SLoadbalancerUDPListener) GetBackendGroupId() string { + if len(listerner.VServerGroupId) > 0 { + return listerner.VServerGroupId + } + return listerner.MasterSlaveServerGroupId +} + +func (listerner *SLoadbalancerUDPListener) GetBackendServerPort() int { + return listerner.BackendServerPort +} + +func (listerner *SLoadbalancerUDPListener) GetScheduler() string { + return listerner.Scheduler +} + +func (listerner *SLoadbalancerUDPListener) GetAclStatus() string { + return listerner.AclStatus +} + +func (listerner *SLoadbalancerUDPListener) GetAclType() string { + return listerner.AclType +} + +func (listerner *SLoadbalancerUDPListener) GetAclId() string { + return listerner.AclId +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheck() string { + return listerner.HealthCheck +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckType() string { + return api.LB_HEALTH_CHECK_UDP +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckDomain() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckURI() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckCode() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckRise() int { + return listerner.HealthyThreshold +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckFail() int { + return listerner.UnhealthyThreshold +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckTimeout() int { + return listerner.HealthCheckConnectTimeout +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckInterval() int { + return listerner.HealthCheckInterval +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckReq() string { + return listerner.HealthCheckReq +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckExp() string { + return listerner.HealthCheckExp +} + +func (listerner *SLoadbalancerUDPListener) GetStickySession() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetStickySessionType() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetStickySessionCookie() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetStickySessionCookieTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerUDPListener) XForwardedForEnabled() bool { + return false +} + +func (listerner *SLoadbalancerUDPListener) GzipEnabled() bool { + return false +} + +func (listerner *SLoadbalancerUDPListener) GetCertificateId() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetTLSCipherPolicy() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) HTTP2Enabled() bool { + return false +} + +func (listerner *SLoadbalancerUDPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + return []cloudprovider.ICloudLoadbalancerListenerRule{}, nil +} + +func (region *SRegion) GetLoadbalancerUDPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerUDPListener, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + body, err := region.lbRequest("DescribeLoadBalancerUDPListenerAttribute", params) + if err != nil { + return nil, err + } + listener := SLoadbalancerUDPListener{} + return &listener, body.Unmarshal(&listener) +} + +func (region *SRegion) CreateLoadbalancerUDPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + params := region.constructBaseCreateListenerParams(lb, listener) + _, err := region.lbRequest("CreateLoadBalancerUDPListener", params) + if err != nil { + return nil, err + } + iListener, err := region.GetLoadbalancerUDPListener(lb.LoadBalancerId, listener.ListenerPort) + if err != nil { + return nil, err + } + iListener.lb = lb + return iListener, nil +} + +func (listerner *SLoadbalancerUDPListener) Delete(ctx context.Context) error { + return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerUDPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (listerner *SLoadbalancerUDPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (listerner *SLoadbalancerUDPListener) Start() error { + return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (listerner *SLoadbalancerUDPListener) Stop() error { + return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (region *SRegion) SyncLoadbalancerUDPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { + params := region.constructBaseCreateListenerParams(lb, listener) + _, err := region.lbRequest("SetLoadBalancerUDPListenerAttribute", params) + return err +} + +func (listerner *SLoadbalancerUDPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { + return listerner.lb.region.SyncLoadbalancerUDPListener(listerner.lb, lblis) +} + +func (listerner *SLoadbalancerUDPListener) GetProjectId() string { + return listerner.lb.GetProjectId() +} + +func (listerner *SLoadbalancerUDPListener) GetClientIdleTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerUDPListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/mongodb.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/mongodb.go new file mode 100644 index 0000000000..19beb006a0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/mongodb.go @@ -0,0 +1,523 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "regexp" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SMOngoDBAttribute struct { + // 实例最大IOPS + MaxIops int + ReplicaSets struct { + ReplicaSet []struct { + ConnectionDomain string `json:"ConnectionDomain"` + } + } + MaxConnections int +} + +type SMongoDB struct { + region *SRegion + AliyunTags + multicloud.SBillingBase + multicloud.SResourceBase + + ConnectionDomain string `json:"ConnectionDomain"` + NetworkAddress string + ChargeType TChargeType `json:"ChargeType"` + LockMode string `json:"LockMode"` + DBInstanceClass string `json:"DBInstanceClass"` + ResourceGroupId string `json:"ResourceGroupId"` + DBInstanceId string `json:"DBInstanceId"` + ZoneId string `json:"ZoneId"` + MongosList struct { + MongosAttribute []struct { + NodeId string `json:"NodeId"` + NodeClass string `json:"NodeClass"` + } `json:"MongosAttribute"` + } `json:"MongosList"` + DBInstanceDescription string `json:"DBInstanceDescription"` + Engine string `json:"Engine"` + CreationTime time.Time `json:"CreationTime"` + NetworkType string `json:"NetworkType"` + ExpireTime time.Time `json:"ExpireTime"` + DBInstanceType string `json:"DBInstanceType"` + RegionId string `json:"RegionId"` + ShardList struct { + ShardAttribute []struct { + NodeId string `json:"NodeId"` + NodeClass string `json:"NodeClass"` + NodeStorage int `json:"NodeStorage"` + } `json:"ShardAttribute"` + } `json:"ShardList"` + EngineVersion string `json:"EngineVersion"` + DBInstanceStatus string `json:"DBInstanceStatus"` + + DBInstanceStorage int `json:"DBInstanceStorage"` + MaintainStartTime string `json:"MaintainStartTime"` + MaintainEndTime string `json:"MaintainEndTime"` + StorageEngine string `json:"StorageEngine"` + VpcId string `json:"VPCId"` + VSwitchId string `json:"VSwitchId"` + VpcAuthMode string `json:"VpcAuthMode"` + ReplicationFactor string `json:"ReplicationFactor"` +} + +var mongoSpec = map[string]struct { + VcpuCount int + VmemSizeGb int +}{} + +func (self *SMongoDB) GetName() string { + if len(self.DBInstanceDescription) > 0 { + return self.DBInstanceDescription + } + return self.DBInstanceId +} + +func (self *SMongoDB) GetId() string { + return self.DBInstanceId +} + +func (self *SMongoDB) GetGlobalId() string { + return self.DBInstanceId +} + +func (self *SMongoDB) GetStatus() string { + switch self.DBInstanceStatus { + case "Creating": + return api.MONGO_DB_STATUS_CREATING + case "DBInstanceClassChanging": + return api.MONGO_DB_STATUS_CHANGE_CONFIG + case "DBInstanceNetTypeChanging", "EngineVersionUpgrading", "GuardSwitching", "HASwitching", "Importing", "ImportingFromOthers", "LinkSwitching", "MinorVersionUpgrading", "NET_CREATING", "NET_DELETING", "NodeCreating", "NodeDeleting", "Restoring", "SSLModifying", "TempDBInstanceCreating", "Transing", "TransingToOthers": + return api.MONGO_DB_STATUS_DEPLOY + case "Deleting": + return api.MONGO_DB_STATUS_DELETING + case "Rebooting": + return api.MONGO_DB_STATUS_REBOOTING + case "Running": + return api.MONGO_DB_STATUS_RUNNING + default: + return strings.ToLower(self.DBInstanceStatus) + } +} + +func (self *SMongoDB) GetProjectId() string { + return self.ResourceGroupId +} + +func (self *SMongoDB) Refresh() error { + db, err := self.region.GetMongoDB(self.DBInstanceId) + if err != nil { + return errors.Wrapf(err, "GetMongoDB") + } + return jsonutils.Update(self, db) +} + +func (self *SMongoDB) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SMongoDB) GetExpiredAt() time.Time { + return self.ExpireTime +} + +func (self *SMongoDB) GetIpAddr() string { + return "" +} + +func (self *SMongoDB) GetEngine() string { + if len(self.StorageEngine) == 0 { + self.Refresh() + } + return self.StorageEngine +} + +func (self *SMongoDB) GetEngineVersion() string { + return self.EngineVersion +} + +func (self *SMongoDB) GetVpcId() string { + if self.NetworkType != "VPC" { + return "" + } + if len(self.VpcId) == 0 { + self.Refresh() + } + return self.VpcId +} + +func (self *SMongoDB) GetNetworkId() string { + if self.NetworkType != "VPC" { + return "" + } + if len(self.VSwitchId) == 0 { + self.Refresh() + } + return self.VSwitchId +} + +func (self *SMongoDB) GetZoneId() string { + if !strings.Contains(self.ZoneId, ",") { + return self.ZoneId + } + if index := strings.Index(self.ZoneId, ",") - 1; index > 0 { + return fmt.Sprintf("%s-%s", self.region.RegionId, string(self.ZoneId[index])) + } + return "" +} + +func (self *SMongoDB) Delete() error { + return self.region.DeleteMongoDB(self.DBInstanceId) +} + +func (self *SMongoDB) GetBillingType() string { + return convertChargeType(self.ChargeType) +} + +func (self *SMongoDB) GetCategory() string { + return self.DBInstanceType +} + +func (self *SMongoDB) GetDiskSizeMb() int { + if self.DBInstanceStorage == 0 { + self.Refresh() + } + return self.DBInstanceStorage * 1024 +} + +func (self *SMongoDB) GetInstanceType() string { + return self.DBInstanceClass +} + +func (self *SMongoDB) GetMaintainTime() string { + return fmt.Sprintf("%s-%s", self.MaintainStartTime, self.MaintainEndTime) +} + +func (self *SMongoDB) GetPort() int { + return 3717 +} + +func (self *SMongoDB) GetReplicationNum() int { + if len(self.ReplicationFactor) == 0 { + self.Refresh() + } + num, _ := strconv.Atoi(self.ReplicationFactor) + return int(num) +} + +func (self *SMongoDB) GetVcpuCount() int { + self.region.GetchMongoSkus() + sku, ok := self.region.mongoSkus[self.DBInstanceClass] + if ok { + return sku.CpuCount + } + return 0 +} + +func (self *SMongoDB) GetVmemSizeMb() int { + self.region.GetchMongoSkus() + sku, ok := self.region.mongoSkus[self.DBInstanceClass] + if ok { + return sku.MemSizeGb * 1024 + } + return 0 +} + +func (self *SMongoDB) GetIops() int { + iops, _ := self.region.GetIops(self.DBInstanceId) + return iops +} + +func (self *SMongoDB) GetMaxConnections() int { + maxConnection, _ := self.region.GetMaxConnections(self.DBInstanceId) + return maxConnection +} + +func (self *SMongoDB) GetNetworkAddress() string { + addr, _ := self.region.GetNetworkAddress(self.DBInstanceId) + return addr +} + +func (self *SRegion) GetMongoDBsByType(mongoType string) ([]SMongoDB, error) { + dbs := []SMongoDB{} + for { + part, total, err := self.GetMongoDBs(mongoType, 100, len(dbs)/100) + if err != nil { + return nil, errors.Wrapf(err, "GetMongoDB") + } + dbs = append(dbs, part...) + if len(dbs) >= total { + break + } + } + return dbs, nil +} + +func (self *SMongoDB) SetTags(tags map[string]string, replace bool) error { + return self.region.SetResourceTags(ALIYUN_SERVICE_MONGO_DB, "INSTANCE", self.GetId(), tags, replace) +} + +func (self *SRegion) GetICloudMongoDBById(id string) (cloudprovider.ICloudMongoDB, error) { + db, err := self.GetMongoDB(id) + if err != nil { + return nil, errors.Wrapf(err, "GetMongoDB(%s)", id) + } + return db, nil +} + +func (self *SRegion) GetICloudMongoDBs() ([]cloudprovider.ICloudMongoDB, error) { + dbs := []SMongoDB{} + for _, mongoType := range []string{"sharding", "replicate", "serverless"} { + part, err := self.GetMongoDBsByType(mongoType) + if err != nil { + return nil, err + } + dbs = append(dbs, part...) + } + ret := []cloudprovider.ICloudMongoDB{} + for i := range dbs { + dbs[i].region = self + ret = append(ret, &dbs[i]) + } + return ret, nil +} + +func (self *SRegion) GetIops(id string) (int, error) { + ret, err := self.GetMongoDBAttribute(id) + if err != nil { + return 0, errors.Wrapf(err, "DescribeDBInstanceAttribute err") + } + if len(ret) == 0 { + return 0, errors.Wrapf(err, "ret missing err") + } + return ret[0].MaxIops, nil +} + +func (self *SRegion) GetMaxConnections(id string) (int, error) { + ret, err := self.GetMongoDBAttribute(id) + if err != nil { + return 0, errors.Wrapf(err, "DescribeDBInstanceAttribute err") + } + if len(ret) == 0 { + return 0, errors.Wrapf(err, "ret missing err") + } + return ret[0].MaxConnections, nil +} + +func (self *SRegion) GetNetworkAddress(id string) (string, error) { + ret, err := self.GetMongoDBAttribute(id) + if err != nil { + return "", errors.Wrapf(err, "DescribeDBInstanceAttribute err") + } + addrList := make([]string, 0) + for _, v := range ret[0].ReplicaSets.ReplicaSet { + addrList = append(addrList, v.ConnectionDomain) + } + addrs := strings.Join(addrList, ",") + return addrs, nil +} + +func (self *SRegion) GetMongoDBAttribute(id string) ([]SMOngoDBAttribute, error) { + params := map[string]string{ + "Action": "DescribeDBInstanceAttribute", + "DBInstanceId": id, + } + resp, err := self.mongodbRequest("DescribeDBInstanceAttribute", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeDBInstanceAttribute err") + } + ret := []SMOngoDBAttribute{} + err = resp.Unmarshal(&ret, "DBInstances", "DBInstance") + if err != nil { + return nil, errors.Wrapf(err, "unmarshal err") + } + return ret, err +} + +func (self *SRegion) GetMongoDBs(mongoType string, pageSize int, pageNum int) ([]SMongoDB, int, error) { + if pageSize < 1 || pageSize > 100 { + pageSize = 100 + } + if pageNum < 1 { + pageNum = 1 + } + + params := map[string]string{ + "PageSize": fmt.Sprintf("%d", pageSize), + "PageNumber": fmt.Sprintf("%d", pageNum), + } + if len(mongoType) > 0 { + params["DBInstanceType"] = mongoType + } + resp, err := self.mongodbRequest("DescribeDBInstances", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeDBInstances") + } + ret := []SMongoDB{} + err = resp.Unmarshal(&ret, "DBInstances", "DBInstance") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + totalCount, _ := resp.Int("TotalCount") + return ret, int(totalCount), nil +} + +func (self *SRegion) GetMongoDB(id string) (*SMongoDB, error) { + params := map[string]string{ + "DBInstanceId": id, + } + resp, err := self.mongodbRequest("DescribeDBInstanceAttribute", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeDBInstanceAttribute") + } + ret := []SMongoDB{} + err = resp.Unmarshal(&ret, "DBInstances", "DBInstance") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + if len(ret) == 1 { + ret[0].region = self + return &ret[0], nil + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) DeleteMongoDB(id string) error { + params := map[string]string{ + "DBInstanceId": id, + "ClientToken": utils.GenRequestId(20), + } + _, err := self.mongodbRequest("DeleteDBInstance", params) + return errors.Wrapf(err, "DeleteDBInstance") +} + +type SMongoDBAvaibaleResource struct { + SupportedDBTypes struct { + SupportedDBType []struct { + DbType string + AvailableZones struct { + AvailableZone []struct { + ZoneId string + RegionId string + SupportedEngineVersions struct { + SupportedEngineVersion []struct { + Version string + SupportedEngines struct { + SupportedEngine []struct { + SupportedNodeTypes struct { + SupportedNodeType []struct { + NetworkTypes string + NodeType string + AvailableResources struct { + AvailableResource []struct { + InstanceClassRemark string + InstanceClass string + } + } + } + } + } + } + } + } + } + } + } + } +} + +func (self *SRegion) GetchMongoSkus() (map[string]struct { + CpuCount int + MemSizeGb int +}, error) { + if len(self.mongoSkus) > 0 { + return self.mongoSkus, nil + } + self.mongoSkus = map[string]struct { + CpuCount int + MemSizeGb int + }{} + res, err := self.GetMongoDBAvailableResource() + if err != nil { + return nil, err + } + for _, dbType := range res.SupportedDBTypes.SupportedDBType { + for _, zone := range dbType.AvailableZones.AvailableZone { + for _, version := range zone.SupportedEngineVersions.SupportedEngineVersion { + for _, engine := range version.SupportedEngines.SupportedEngine { + for _, nodeType := range engine.SupportedNodeTypes.SupportedNodeType { + for _, sku := range nodeType.AvailableResources.AvailableResource { + _, ok := self.mongoSkus[sku.InstanceClass] + if !ok { + self.mongoSkus[sku.InstanceClass] = getMongoDBSkuDetails(sku.InstanceClassRemark) + } + } + } + } + } + } + } + return self.mongoSkus, nil +} + +func getMongoDBSkuDetails(remark string) struct { + CpuCount int + MemSizeGb int +} { + ret := struct { + CpuCount int + MemSizeGb int + }{} + r, _ := regexp.Compile(`(\d{1,3})核(\d{1,3})G+`) + result := r.FindSubmatch([]byte(remark)) + if len(result) > 2 { + cpu, _ := strconv.Atoi(string(result[1])) + ret.CpuCount = int(cpu) + mem, _ := strconv.Atoi(string(result[2])) + ret.MemSizeGb = int(mem) + } else { + log.Warningf("not match sku remark %s", remark) + } + return ret +} + +func (self *SRegion) GetMongoDBAvailableResource() (*SMongoDBAvaibaleResource, error) { + params := map[string]string{} + resp, err := self.mongodbRequest("DescribeAvailableResource", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeAvailableResource") + } + ret := &SMongoDBAvaibaleResource{} + err = resp.Unmarshal(ret) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return ret, nil +} diff --git a/pkg/multicloud/aliyun/mongodb_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/mongodb_backup.go similarity index 98% rename from pkg/multicloud/aliyun/mongodb_backup.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/mongodb_backup.go index 33049d6fb8..8828459ca5 100644 --- a/pkg/multicloud/aliyun/mongodb_backup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/mongodb_backup.go @@ -21,7 +21,7 @@ import ( "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SMongoDBBackup struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/monitor.go new file mode 100644 index 0000000000..ed08c750e5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/monitor.go @@ -0,0 +1,634 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + ALIYUN_API_VERSION_METRICS = "2019-01-01" +) + +func (r *SRegion) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { + return r.client.metricsRequest(action, params) +} + +func (self *SAliyunClient) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient("") + if err != nil { + return nil, errors.Wrap(err, "self.getSdkClient") + } + return jsonRequest(client, "metrics.aliyuncs.com", ALIYUN_API_VERSION_METRICS, action, params, self.debug) +} + +type SResourceLabel struct { + Name string `json:"name"` + Value string `json:"value"` +} + +type SResource struct { + Description string `json:"Description"` + Labels string `json:"Labels"` + Namespace string `json:"Namespace"` +} + +func (r *SRegion) DescribeProjectMeta(limit, offset int) (int, []SResource, error) { + params := make(map[string]string) + if limit <= 0 { + limit = 30 + } + params["PageSize"] = strconv.FormatInt(int64(limit), 10) + if offset > 0 { + pageNum := (offset / limit) + 1 + params["PageNumber"] = strconv.FormatInt(int64(pageNum), 10) + } + body, err := r.metricsRequest("DescribeProjectMeta", params) + if err != nil { + return 0, nil, errors.Wrap(err, "r.metricsRequest DescribeProjectMeta") + } + total, _ := body.Int("Total") + res := make([]SResource, 0) + err = body.Unmarshal(&res, "Resources", "Resource") + if err != nil { + return 0, nil, errors.Wrap(err, "body.Unmarshal Resources Resource") + } + return int(total), res, nil +} + +func (r *SRegion) FetchNamespaces() ([]SResource, error) { + resources := make([]SResource, 0) + total := -1 + for total < 0 || len(resources) < total { + ntotal, res, err := r.DescribeProjectMeta(1000, len(resources)) + if err != nil { + return nil, errors.Wrap(err, "r.DescribeProjectMeta") + } + if len(res) == 0 { + break + } + resources = append(resources, res...) + total = ntotal + } + return resources, nil +} + +type SMetricMeta struct { + Description string `json:"Description"` + MetricName string `json:"MetricName"` + Statistics string `json:"Statistics"` + Labels string `json:"Labels"` + Dimensions string `json:"Dimensions"` + Namespace string `json:"Namespace"` + Periods string `json:"Periods"` + Unit string `json:"Unit"` +} + +func (r *SRegion) DescribeMetricMetaList(ns string, limit, offset int) (int, []SMetricMeta, error) { + params := make(map[string]string) + if limit <= 0 { + limit = 30 + } + params["Namespace"] = ns + params["PageSize"] = strconv.FormatInt(int64(limit), 10) + if offset > 0 { + pageNum := (offset / limit) + 1 + params["PageNumber"] = strconv.FormatInt(int64(pageNum), 10) + } + body, err := r.metricsRequest("DescribeMetricMetaList", params) + if err != nil { + return 0, nil, errors.Wrap(err, "r.metricsRequest DescribeMetricMetaList") + } + total, _ := body.Int("TotalCount") + res := make([]SMetricMeta, 0) + err = body.Unmarshal(&res, "Resources", "Resource") + if err != nil { + return 0, nil, errors.Wrap(err, "body.Unmarshal Resources Resource") + } + return int(total), res, nil +} + +func (r *SRegion) FetchMetrics(ns string) ([]SMetricMeta, error) { + metrics := make([]SMetricMeta, 0) + total := -1 + for total < 0 || len(metrics) < total { + ntotal, res, err := r.DescribeMetricMetaList(ns, 1000, len(metrics)) + if err != nil { + return nil, errors.Wrap(err, "r.DescribeMetricMetaList") + } + if len(res) == 0 { + break + } + metrics = append(metrics, res...) + total = ntotal + } + return metrics, nil +} + +func (r *SRegion) DescribeMetricList(name string, ns string, since time.Time, until time.Time, nextToken string, dimensions []SResourceLabel) ([]jsonutils.JSONObject, string, error) { + params := make(map[string]string) + params["MetricName"] = name + params["Namespace"] = ns + params["Length"] = "2000" + if len(nextToken) > 0 { + params["NextToken"] = nextToken + } + if !since.IsZero() { + params["StartTime"] = strconv.FormatInt(since.Unix()*1000, 10) + } + if !until.IsZero() { + params["EndTime"] = strconv.FormatInt(until.Unix()*1000, 10) + } + if len(dimensions) > 0 { + for _, dimension := range dimensions { + params[dimension.Name] = dimension.Value + } + } + body, err := r.metricsRequest("DescribeMetricList", params) + if err != nil { + return nil, "", errors.Wrap(err, "region.MetricRequest") + } + nToken, _ := body.GetString("NextToken") + dataStr, _ := body.GetString("Datapoints") + if len(dataStr) == 0 { + return nil, "", nil + } + dataJson, err := jsonutils.ParseString(dataStr) + if err != nil { + return nil, "", errors.Wrap(err, "jsonutils.ParseString") + } + dataArray, err := dataJson.GetArray() + if err != nil { + return nil, "", errors.Wrap(err, "dataJson.GetArray") + } + return dataArray, nToken, nil +} + +type MetricData struct { + Timestamp int64 + BucketName string + InstanceId string + UserId string + Value float64 + Average float64 + Minimum float64 + Maximum float64 + + Diskname string + Device string + + // k8s + Cluster string + Node string + Pod string +} + +func (d MetricData) GetValue() float64 { + if d.Average > 0 { + return d.Average + } + if d.Maximum > 0 { + return d.Maximum + } + if d.Minimum > 0 { + return d.Minimum + } + if d.Value > 0 { + return d.Value + } + return 0.0 +} + +func (d MetricData) GetTags() map[string]string { + ret := map[string]string{} + if len(d.Device) > 0 { + ret[cloudprovider.METRIC_TAG_DEVICE] = fmt.Sprintf("%s(%s)", d.Device, d.Diskname) + } + return ret +} + +func (self *SAliyunClient) ListMetrics(ns, metricName string, start, end time.Time) ([]MetricData, error) { + result := []MetricData{} + nextToken := "" + for { + part, next, err := self.listMetrics(ns, metricName, nextToken, start, end) + if err != nil { + return nil, errors.Wrap(err, "listMetrics") + } + result = append(result, part...) + if len(next) == 0 { + break + } + nextToken = next + } + return result, nil +} + +func (self *SAliyunClient) listMetrics(ns, metricName, nextToken string, start, end time.Time) ([]MetricData, string, error) { + params := make(map[string]string) + params["MetricName"] = metricName + params["Namespace"] = ns + params["Length"] = "2000" + if len(nextToken) > 0 { + params["NextToken"] = nextToken + } + params["StartTime"] = fmt.Sprintf("%d", start.UnixMilli()) + params["EndTime"] = fmt.Sprintf("%d", end.UnixMilli()) + resp, err := self.metricsRequest("DescribeMetricList", params) + if err != nil { + return nil, "", errors.Wrap(err, "DescribeMetricList") + } + ret := struct { + NextToken string + Datapoints string + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, "", errors.Wrapf(err, "resp.Unmarshal") + } + obj, err := jsonutils.ParseString(ret.Datapoints) + if err != nil { + return nil, "", errors.Wrap(err, "jsonutils.ParseString") + } + result := []MetricData{} + err = obj.Unmarshal(&result) + if err != nil { + return nil, "", errors.Wrapf(err, "obj.Unmarshal") + } + return result, ret.NextToken, nil +} + +func (r *SRegion) FetchMetricData(name string, ns string, since time.Time, until time.Time) ([]jsonutils.JSONObject, error) { + data := make([]jsonutils.JSONObject, 0) + nextToken := "" + for { + datArray, next, err := r.DescribeMetricList(name, ns, since, until, nextToken, nil) + if err != nil { + return nil, errors.Wrap(err, "r.DescribeMetricList") + } + data = append(data, datArray...) + if len(next) == 0 { + break + } + nextToken = next + } + return data, nil +} + +func (self *SAliyunClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_BUCKET: + return self.GetOssMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: + return self.GetRedisMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_RDS: + return self.GetRdsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_LB: + return self.GetElbMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_K8S: + return self.GetK8sMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) + } +} + +func (self *SAliyunClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricTags, tagKey := map[string]string{}, "" + switch opts.MetricType { + case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: + metricTags = map[string]string{ + "CPUUtilization": "", + } + case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: + metricTags = map[string]string{ + "InternetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, + "IntranetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + } + tagKey = cloudprovider.METRIC_TAG_NET_TYPE + case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: + metricTags = map[string]string{ + "InternetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, + "IntranetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + } + tagKey = cloudprovider.METRIC_TAG_NET_TYPE + case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: + metricTags = map[string]string{ + "DiskReadBPS": "", + } + case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: + metricTags = map[string]string{ + "DiskWriteBPS": "", + } + case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: + metricTags = map[string]string{ + "DiskReadIOPS": "", + } + case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: + metricTags = map[string]string{ + "DiskWriteIOPS": "", + } + case cloudprovider.VM_METRIC_TYPE_MEM_USAGE: + metricTags = map[string]string{ + "memory_usedutilization": "", + } + case cloudprovider.VM_METRIC_TYPE_DISK_USAGE: + metricTags = map[string]string{ + "diskusage_utilization": "", + } + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) + } + ret := []cloudprovider.MetricValues{} + for metric, tag := range metricTags { + result, err := self.ListMetrics("acs_ecs_dashboard", metric, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("ListMetric(%s) error: %v", metric, err) + continue + } + tags := map[string]string{} + if len(tag) > 0 && len(tagKey) > 0 { + tags[tagKey] = tag + } + for i := range result { + dataTag := result[i].GetTags() + for k, v := range tags { + dataTag[k] = v + } + ret = append(ret, cloudprovider.MetricValues{ + Id: result[i].InstanceId, + MetricType: opts.MetricType, + Values: []cloudprovider.MetricValue{ + { + Timestamp: time.UnixMilli(result[i].Timestamp), + Value: result[i].GetValue(), + Tags: dataTag, + }, + }, + }) + } + } + return ret, nil +} + +func (self *SAliyunClient) GetOssMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricTags, tagKey := map[string]string{}, "" + switch opts.MetricType { + case cloudprovider.BUCKET_METRIC_TYPE_LATECY: + metricTags = map[string]string{ + "GetObjectE2eLatency": cloudprovider.METRIC_TAG_REQUST_GET, + "PostObjectE2eLatency": cloudprovider.METRIC_TAG_REQUST_GET, + } + tagKey = cloudprovider.METRIC_TAG_REQUST + case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_TX: + metricTags = map[string]string{ + "InternetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, + "IntranetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + } + tagKey = cloudprovider.METRIC_TAG_REQUST + case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_RX: + metricTags = map[string]string{ + "InternetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, + "IntranetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + } + tagKey = cloudprovider.METRIC_TAG_NET_TYPE + case cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT: + metricTags = map[string]string{ + "GetObjectCount": cloudprovider.METRIC_TAG_REQUST_GET, + "PostObjectCount": cloudprovider.METRIC_TAG_REQUST_POST, + "ServerErrorCount": cloudprovider.METRIC_TAG_REQUST_5XX, + } + tagKey = cloudprovider.METRIC_TAG_REQUST + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) + } + ret := []cloudprovider.MetricValues{} + for metric, tag := range metricTags { + result, err := self.ListMetrics("acs_oss_dashboard", metric, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("ListMetric(%s) error: %v", metric, err) + continue + } + for i := range result { + ret = append(ret, cloudprovider.MetricValues{ + Id: result[i].BucketName, + MetricType: opts.MetricType, + Values: []cloudprovider.MetricValue{ + { + Timestamp: time.UnixMilli(result[i].Timestamp), + Value: result[i].GetValue(), + Tags: map[string]string{ + tagKey: tag, + }, + }, + }, + }) + } + } + return ret, nil +} + +func (self *SAliyunClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metrics := map[cloudprovider.TMetricType]string{ + cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE: "CpuUsage", + cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE: "MemoryUsage", + cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX: "IntranetIn", + cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX: "IntranetOut", + cloudprovider.REDIS_METRIC_TYPE_USED_CONN: "UsedConnection", + cloudprovider.REDIS_METRIC_TYPE_OPT_SES: "UsedQPS", + cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS: "StandardKeys", + cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE: "UsedMemory", + } + metric, ok := metrics[opts.MetricType] + if !ok { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) + } + ret := []cloudprovider.MetricValues{} + result, err := self.ListMetrics("acs_kvstore", metric, opts.StartTime, opts.EndTime) + if err != nil { + return nil, errors.Wrapf(err, "ListMetric(%s)", metric) + } + for i := range result { + tags := map[string]string{} + if strings.Contains(result[i].InstanceId, "-db-") { + tags[cloudprovider.METRIC_TAG_NODE] = result[i].InstanceId + idx := strings.Index(result[i].InstanceId, "-db-") + result[i].InstanceId = result[i].InstanceId[:idx] + } + value := cloudprovider.MetricValues{ + Id: result[i].InstanceId, + MetricType: opts.MetricType, + Values: []cloudprovider.MetricValue{ + { + Timestamp: time.UnixMilli(result[i].Timestamp), + Value: result[i].GetValue(), + Tags: tags, + }, + }, + } + ret = append(ret, value) + } + return ret, nil +} + +func (self *SAliyunClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricTags := map[string]string{} + switch opts.MetricType { + case cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: + metricTags = map[string]string{ + "CpuUsage": "", + } + case cloudprovider.RDS_METRIC_TYPE_MEM_USAGE: + metricTags = map[string]string{ + "MemoryUsage": "", + } + case cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: + metricTags = map[string]string{ + "MySQL_NetworkInNew": "", + "SQLServer_NetworkInNew": "", + } + case cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: + metricTags = map[string]string{ + "MySQL_NetworkOutNew": "", + "SQLServer_NetworkOutNew": "", + } + case cloudprovider.RDS_METRIC_TYPE_DISK_USAGE: + metricTags = map[string]string{ + "DiskUsage": "", + } + case cloudprovider.RDS_METRIC_TYPE_CONN_USAGE: + metricTags = map[string]string{ + "ConnectionUsage": "", + } + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) + } + ret := []cloudprovider.MetricValues{} + for metric := range metricTags { + result, err := self.ListMetrics("acs_rds_dashboard", metric, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("ListMetric(%s) error: %v", metric, err) + continue + } + for i := range result { + ret = append(ret, cloudprovider.MetricValues{ + Id: result[i].InstanceId, + MetricType: opts.MetricType, + Values: []cloudprovider.MetricValue{ + { + Timestamp: time.UnixMilli(result[i].Timestamp), + Value: result[i].GetValue(), + }, + }, + }) + } + } + return ret, nil +} + +func (self *SAliyunClient) GetElbMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricTags, tagKey := map[string]string{}, "" + switch opts.MetricType { + case cloudprovider.LB_METRIC_TYPE_NET_BPS_RX: + metricTags = map[string]string{ + "InstanceTrafficRX": "", + } + case cloudprovider.LB_METRIC_TYPE_NET_BPS_TX: + metricTags = map[string]string{ + "InstanceTrafficTX": "", + } + case cloudprovider.LB_METRIC_TYPE_HRSP_COUNT: + metricTags = map[string]string{ + "InstanceStatusCode2xx": cloudprovider.METRIC_TAG_REQUST_2XX, + "InstanceStatusCode3xx": cloudprovider.METRIC_TAG_REQUST_3XX, + "InstanceStatusCode4xx": cloudprovider.METRIC_TAG_REQUST_4XX, + "InstanceStatusCode5xx": cloudprovider.METRIC_TAG_REQUST_5XX, + } + tagKey = cloudprovider.METRIC_TAG_REQUST + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) + } + ret := []cloudprovider.MetricValues{} + for metric, tag := range metricTags { + result, err := self.ListMetrics("acs_slb_dashboard", metric, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("ListMetric(%s) error: %v", metric, err) + continue + } + tags := map[string]string{} + if len(tag) > 0 && len(tagKey) > 0 { + tags[tagKey] = tag + } + for i := range result { + ret = append(ret, cloudprovider.MetricValues{ + Id: result[i].InstanceId, + MetricType: opts.MetricType, + Values: []cloudprovider.MetricValue{ + { + Timestamp: time.UnixMilli(result[i].Timestamp), + Value: result[i].GetValue(), + Tags: tags, + }, + }, + }) + } + } + return ret, nil +} + +func (self *SAliyunClient) GetK8sMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricName := "" + switch opts.MetricType { + case cloudprovider.K8S_NODE_METRIC_TYPE_CPU_USAGE: + metricName = "node.cpu.utilization" + case cloudprovider.K8S_NODE_METRIC_TYPE_MEM_USAGE: + metricName = "node.memory.utilization" + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) + } + result, err := self.ListMetrics("acs_k8s", metricName, opts.StartTime, opts.EndTime) + if err != nil { + return nil, errors.Wrapf(err, "ListMetrics(%s)", metricName) + } + ret := []cloudprovider.MetricValues{} + for i := range result { + tags := map[string]string{} + if len(result[i].Node) > 0 { + tags[cloudprovider.METRIC_TAG_NODE] = result[i].Node + } + ret = append(ret, cloudprovider.MetricValues{ + Id: result[i].Cluster, + MetricType: opts.MetricType, + Values: []cloudprovider.MetricValue{ + { + Timestamp: time.UnixMilli(result[i].Timestamp), + Value: result[i].GetValue(), + Tags: tags, + }, + }, + }) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/mount_target.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/mount_target.go new file mode 100644 index 0000000000..91dbf65499 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/mount_target.go @@ -0,0 +1,158 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type ClientMasterNode struct { + EcsIp string + EcsId string + DefaultPasswd string +} + +type ClientMasterNodes struct { + ClientMasterNode []ClientMasterNode +} + +type SMountTarget struct { + fs *SFileSystem + + Status string + NetworkType string + VswId string + VpcId string + MountTargetDomain string + AccessGroup string + ClientMasterNodes ClientMasterNodes +} + +func (self *SMountTarget) GetGlobalId() string { + return self.MountTargetDomain +} + +func (self *SMountTarget) GetName() string { + return self.MountTargetDomain +} + +func (self *SMountTarget) GetNetworkType() string { + return strings.ToLower(self.NetworkType) +} + +func (self *SMountTarget) GetStatus() string { + switch self.Status { + case "Active": + return api.MOUNT_TARGET_STATUS_AVAILABLE + case "Inactive": + return api.MOUNT_TARGET_STATUS_UNAVAILABLE + case "Pending": + return api.MOUNT_TARGET_STATUS_CREATING + case "Deleting": + return api.MOUNT_TARGET_STATUS_DELETING + default: + return strings.ToLower(self.Status) + } +} + +func (self *SMountTarget) GetVpcId() string { + return self.VpcId +} + +func (self *SMountTarget) GetNetworkId() string { + return self.VswId +} + +func (self *SMountTarget) GetDomainName() string { + return self.MountTargetDomain +} + +func (self *SMountTarget) GetAccessGroupId() string { + return fmt.Sprintf("%s/%s", self.fs.FileSystemType, self.AccessGroup) +} + +func (self *SMountTarget) Delete() error { + return self.fs.region.DeleteMountTarget(self.fs.FileSystemId, self.MountTargetDomain) +} + +func (self *SRegion) GetMountTargets(fsId, domainName string, pageSize, pageNum int) ([]SMountTarget, int, error) { + if pageSize < 1 || pageSize > 100 { + pageSize = 50 + } + if pageNum < 1 { + pageNum = 1 + } + params := map[string]string{ + "RegionId": self.RegionId, + "FileSystemId": fsId, + "PageSize": fmt.Sprintf("%d", pageSize), + "PageNumber": fmt.Sprintf("%d", pageNum), + } + if len(domainName) > 0 { + params["MountTargetDomain"] = domainName + } + resp, err := self.nasRequest("DescribeMountTargets", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeMountTargets") + } + ret := struct { + TotalCount int + MountTargets struct { + MountTarget []SMountTarget + } + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + return ret.MountTargets.MountTarget, ret.TotalCount, nil +} + +func (self *SFileSystem) GetMountTargets() ([]cloudprovider.ICloudMountTarget, error) { + targets := []SMountTarget{} + num := 1 + for { + part, total, err := self.region.GetMountTargets(self.FileSystemId, "", 50, num) + if err != nil { + return nil, errors.Wrapf(err, "GetMountTargets") + } + targets = append(targets, part...) + if len(part) >= total { + break + } + } + ret := []cloudprovider.ICloudMountTarget{} + for i := range targets { + targets[i].fs = self + ret = append(ret, &targets[i]) + } + return ret, nil +} + +func (self *SRegion) DeleteMountTarget(fsId, id string) error { + params := map[string]string{ + "RegionId": self.RegionId, + "FileSystemId": fsId, + "MountTargetDomain": id, + } + _, err := self.nasRequest("DeleteMountTarget", params) + return errors.Wrapf(err, "DeleteMountTarget") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natdtable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natdtable.go new file mode 100644 index 0000000000..d3507c1dde --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natdtable.go @@ -0,0 +1,187 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strconv" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SForwardTableEntry struct { + multicloud.SResourceBase + AliyunTags + nat *SNatGateway + + ForwardEntryId string + ForwardEntryName string + IpProtocol string + Status string + ExternalIp string + ForwardTableId string + ExternalPort string + InternalPort string + InternalIp string +} + +func (dtable *SForwardTableEntry) GetName() string { + if len(dtable.ForwardEntryName) > 0 { + return dtable.ForwardEntryName + } + return dtable.ForwardEntryId +} + +func (dtable *SForwardTableEntry) GetId() string { + return dtable.ForwardEntryId +} + +func (dtable *SForwardTableEntry) GetGlobalId() string { + return dtable.ForwardEntryId +} + +func (dtable *SForwardTableEntry) GetStatus() string { + switch dtable.Status { + case "Available": + return api.NAT_STAUTS_AVAILABLE + default: + return api.NAT_STATUS_UNKNOWN + } +} + +func (dtable *SForwardTableEntry) GetIpProtocol() string { + return dtable.IpProtocol +} + +func (dtable *SForwardTableEntry) GetExternalIp() string { + return dtable.ExternalIp +} + +func (dtable *SForwardTableEntry) GetExternalPort() int { + port, _ := strconv.Atoi(dtable.ExternalPort) + return port +} + +func (dtable *SForwardTableEntry) GetInternalIp() string { + return dtable.InternalIp +} + +func (dtable *SForwardTableEntry) GetInternalPort() int { + port, _ := strconv.Atoi(dtable.InternalPort) + return port +} + +func (region *SRegion) GetAllDTables(tableId string) ([]SForwardTableEntry, error) { + dtables := []SForwardTableEntry{} + for { + part, total, err := region.GetForwardTableEntries(tableId, len(dtables), 50) + if err != nil { + return nil, err + } + dtables = append(dtables, part...) + if len(dtables) >= total { + break + } + } + return dtables, nil +} + +func (dtable *SForwardTableEntry) Delete() error { + return dtable.nat.vpc.region.DeleteForwardTableEntry(dtable.ForwardTableId, dtable.GetId()) +} + +func (region *SRegion) GetForwardTableEntries(tableId string, offset int, limit int) ([]SForwardTableEntry, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + params["ForwardTableId"] = tableId + + body, err := region.vpcRequest("DescribeForwardTableEntries", params) + if err != nil { + return nil, 0, err + } + + dtables := []SForwardTableEntry{} + err = body.Unmarshal(&dtables, "ForwardTableEntries", "ForwardTableEntry") + if err != nil { + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return dtables, int(total), nil +} + +func (region *SRegion) GetForwardTableEntry(tableID, forwardEntryID string) (SForwardTableEntry, error) { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["ForwardTableId"] = tableID + params["ForwardEntryId"] = forwardEntryID + body, err := region.vpcRequest("DescribeForwardTableEntries", params) + if err != nil { + return SForwardTableEntry{}, err + } + + dtables := []SForwardTableEntry{} + err = body.Unmarshal(&dtables, "ForwardTableEntries", "ForwardTableEntry") + if err != nil { + return SForwardTableEntry{}, err + } + if len(dtables) == 0 { + return SForwardTableEntry{}, cloudprovider.ErrNotFound + } + return dtables[0], nil +} + +func (region *SRegion) DeleteForwardTableEntry(tableId string, entryId string) error { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["ForwardTableId"] = tableId + params["ForwardEntryId"] = entryId + _, err := region.vpcRequest("DeleteForwardEntry", params) + return err +} + +func (region *SRegion) CreateForwardTableEntry(rule cloudprovider.SNatDRule, tableID string) (string, error) { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["ForwardTableId"] = tableID + params["ExternalIp"] = rule.ExternalIP + params["ExternalPort"] = strconv.Itoa(rule.ExternalPort) + params["InternalIp"] = rule.InternalIP + params["InternalPort"] = strconv.Itoa(rule.InternalPort) + params["IpProtocol"] = rule.Protocol + body, err := region.vpcRequest("CreateForwardEntry", params) + if err != nil { + return "", err + } + + entryID, _ := body.GetString("ForwardEntryId") + return entryID, nil +} + +func (dtable *SForwardTableEntry) Refresh() error { + new, err := dtable.nat.vpc.region.GetForwardTableEntry(dtable.ForwardTableId, dtable.ForwardEntryId) + if err != nil { + return err + } + return jsonutils.Update(dtable, new) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natgateway.go new file mode 100644 index 0000000000..3abadbc718 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natgateway.go @@ -0,0 +1,381 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SBandwidthPackageIds struct { + BandwidthPackageId []string +} + +type SForwardTableIds struct { + ForwardTableId []string +} + +type SSnatTableIds struct { + SnatTableId []string +} + +type NatGatewayPrivateInfo struct { + EniInstanceId string + IzNo string + MaxBandwidth int + PrivateIpAddress string + VswitchId string +} + +type SNatGateway struct { + multicloud.SNatGatewayBase + AliyunTags + + vpc *SVpc + + BandwidthPackageIds SBandwidthPackageIds + BusinessStatus string + CreationTime time.Time + ExpiredTime time.Time + Description string + ForwardTableIds SForwardTableIds + SnatTableIds SSnatTableIds + InstanceChargeType TChargeType + Name string + NatGatewayId string + RegionId string + Spec string + Status string + VpcId string + NatGatewayPrivateInfo NatGatewayPrivateInfo +} + +func (nat *SNatGateway) GetId() string { + return nat.NatGatewayId +} + +func (nat *SNatGateway) GetGlobalId() string { + return nat.NatGatewayId +} + +func (nat *SNatGateway) GetName() string { + if len(nat.Name) > 0 { + return nat.Name + } + return nat.NatGatewayId +} + +func (nat *SNatGateway) GetStatus() string { + switch nat.Status { + case "Initiating": + return api.NAT_STATUS_ALLOCATE + case "Available": + return api.NAT_STAUTS_AVAILABLE + case "Pending": + return api.NAT_STATUS_DEPLOYING + default: + return api.NAT_STATUS_UNKNOWN + } +} + +func (self *SNatGateway) GetINetworkId() string { + return self.NatGatewayPrivateInfo.VswitchId +} + +func (self *SNatGateway) GetIpAddr() string { + return self.NatGatewayPrivateInfo.PrivateIpAddress +} + +func (self *SNatGateway) GetBandwidthMb() int { + return self.NatGatewayPrivateInfo.MaxBandwidth +} + +func (self *SNatGateway) Delete() error { + return self.vpc.region.DeleteNatGateway(self.NatGatewayId, false) +} + +func (nat *SNatGateway) GetBillingType() string { + return convertChargeType(nat.InstanceChargeType) +} + +func (nat *SNatGateway) GetNatSpec() string { + if len(nat.Spec) == 0 { + return api.ALIYUN_NAT_SKU_DEFAULT + } + return nat.Spec +} + +func (self *SNatGateway) Refresh() error { + nat, total, err := self.vpc.region.GetNatGateways("", self.NatGatewayId, 0, 1) + if err != nil { + return errors.Wrapf(err, "GetNatGateways") + } + if total > 1 { + return errors.Wrapf(cloudprovider.ErrDuplicateId, "get %d natgateways by id %s", total, self.NatGatewayId) + } + if total == 0 { + return errors.Wrapf(cloudprovider.ErrNotFound, self.NatGatewayId) + } + return jsonutils.Update(self, nat[0]) +} + +func (nat *SNatGateway) GetCreatedAt() time.Time { + return nat.CreationTime +} + +func (nat *SNatGateway) GetExpiredAt() time.Time { + return nat.ExpiredTime +} + +func (nat *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips := []SEipAddress{} + for { + parts, total, err := nat.vpc.region.GetEips("", nat.NatGatewayId, "", len(eips), 50) + if err != nil { + return nil, err + } + eips = append(eips, parts...) + if len(eips) >= total { + break + } + } + ieips := []cloudprovider.ICloudEIP{} + for i := 0; i < len(eips); i++ { + eips[i].region = nat.vpc.region + ieips = append(ieips, &eips[i]) + } + return ieips, nil +} + +func (nat *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { + itables := []cloudprovider.ICloudNatDEntry{} + for _, dtableId := range nat.ForwardTableIds.ForwardTableId { + dtables, err := nat.vpc.region.GetAllDTables(dtableId) + if err != nil { + return nil, err + } + for i := 0; i < len(dtables); i++ { + dtables[i].nat = nat + itables = append(itables, &dtables[i]) + } + } + return itables, nil +} + +func (nat *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { + stables, err := nat.getSnatEntries() + if err != nil { + return nil, err + } + itables := []cloudprovider.ICloudNatSEntry{} + for i := 0; i < len(stables); i++ { + stables[i].nat = nat + itables = append(itables, &stables[i]) + } + return itables, nil +} + +func (nat *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { + dNATEntry, err := nat.vpc.region.GetForwardTableEntry(nat.ForwardTableIds.ForwardTableId[0], id) + if err != nil { + return nil, cloudprovider.ErrNotFound + } + dNATEntry.nat = nat + return &dNATEntry, nil +} + +func (nat *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { + sNATEntry, err := nat.vpc.region.GetSNATEntry(nat.SnatTableIds.SnatTableId[0], id) + if err != nil { + return nil, cloudprovider.ErrNotFound + } + sNATEntry.nat = nat + return &sNATEntry, nil +} + +func (nat *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { + entryID, err := nat.vpc.region.CreateForwardTableEntry(rule, nat.ForwardTableIds.ForwardTableId[0]) + if err != nil { + return nil, errors.Wrapf(err, `create dnat rule for nat gateway %q`, nat.GetId()) + } + return nat.GetINatDEntryByID(entryID) +} + +func (nat *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { + entryID, err := nat.vpc.region.CreateSNATTableEntry(rule, nat.SnatTableIds.SnatTableId[0]) + if err != nil { + return nil, errors.Wrapf(err, `create snat rule for nat gateway %q`, nat.GetId()) + } + return nat.GetINatSEntryByID(entryID) +} + +func (self *SRegion) GetNatGateways(vpcId string, natGwId string, offset, limit int) ([]SNatGateway, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + if len(vpcId) > 0 { + params["VpcId"] = vpcId + } + if len(natGwId) > 0 { + params["NatGatewayId"] = natGwId + } + + body, err := self.vpcRequest("DescribeNatGateways", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeNatGateways") + } + + if self.client.debug { + log.Debugf("%s", body.PrettyString()) + } + + gateways := make([]SNatGateway, 0) + err = body.Unmarshal(&gateways, "NatGateways", "NatGateway") + if err != nil { + return nil, 0, errors.Wrapf(err, "body.Unmarshal") + } + total, _ := body.Int("TotalCount") + return gateways, int(total), nil +} + +func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { + nat, err := self.region.CreateNatGateway(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateNatGateway") + } + nat.vpc = self + return nat, nil +} + +func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGateway, error) { + params := map[string]string{ + "RegionId": self.RegionId, + "VpcId": opts.VpcId, + "VSwitchId": opts.NetworkId, + "NatType": "Enhanced", + "Name": opts.Name, + "Description": opts.Desc, + "ClientToken": utils.GenRequestId(20), + "InstanceChargeType": "PostPaid", + "InternetChargeType": "PayBySpec", + } + if len(opts.NatSpec) == 0 || opts.NatSpec == api.ALIYUN_NAT_SKU_DEFAULT { + params["InternetChargeType"] = "PayByLcu" + } else { + params["Spec"] = opts.NatSpec + } + + if opts.BillingCycle != nil { + params["InstanceChargeType"] = "PrePaid" + params["PricingCycle"] = "Month" + params["AutoPay"] = "false" + if opts.BillingCycle.GetYears() > 0 { + params["PricingCycle"] = "Year" + params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetYears()) + } else if opts.BillingCycle.GetMonths() > 0 { + params["PricingCycle"] = "Year" + params["Duration"] = fmt.Sprintf("%d", opts.BillingCycle.GetMonths()) + } + if opts.BillingCycle.AutoRenew { + params["AutoPay"] = "true" + } + } + resp, err := self.vpcRequest("CreateNatGateway", params) + if err != nil { + return nil, errors.Wrapf(err, "CreateNatGateway") + } + natId, err := resp.GetString("NatGatewayId") + if err != nil { + return nil, errors.Wrapf(err, "resp.Get(NatGatewayId)") + } + if len(natId) == 0 { + return nil, errors.Errorf("empty NatGatewayId after created") + } + + var nat *SNatGateway = nil + err = cloudprovider.Wait(time.Second*5, time.Minute*15, func() (bool, error) { + nats, total, err := self.GetNatGateways("", natId, 0, 1) + if err != nil { + return false, errors.Wrapf(err, "GetNatGateways(%s)", natId) + } + if total > 1 { + return false, errors.Wrapf(cloudprovider.ErrDuplicateId, "get %d nats", total) + } + if total == 0 { + return false, errors.Wrapf(cloudprovider.ErrNotFound, "search %s after %s created", opts.Name, natId) + } + nat = &nats[0] + return true, nil + }) + if err != nil { + return nil, errors.Wrapf(err, "cloudprovider.Wait") + } + + return nat, nil +} + +func (self *SRegion) DeleteNatGateway(natId string, isForce bool) error { + params := map[string]string{ + "RegionId": self.RegionId, + "NatGatewayId": natId, + } + if isForce { + params["Force"] = "true" + } + _, err := self.vpcRequest("DeleteNatGateway", params) + return errors.Wrapf(err, "DeleteNatGateway") +} + +func (self *SNatGateway) GetTags() (map[string]string, error) { + _, tags, err := self.vpc.region.ListSysAndUserTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.NatGatewayId) + if err != nil { + return nil, errors.Wrapf(err, "ListTags") + } + tagMaps := map[string]string{} + for k, v := range tags { + tagMaps[strings.ToLower(k)] = v + } + return tagMaps, nil +} + +func (self *SNatGateway) GetSysTags() map[string]string { + tags, _, err := self.vpc.region.ListSysAndUserTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.NatGatewayId) + if err != nil { + return nil + } + tagMaps := map[string]string{} + for k, v := range tags { + tagMaps[strings.ToLower(k)] = v + } + return tagMaps +} + +func (self *SNatGateway) SetTags(tags map[string]string, replace bool) error { + return self.vpc.region.SetResourceTags(ALIYUN_SERVICE_VPC, "NATGATEWAY", self.GetId(), tags, replace) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natstable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natstable.go new file mode 100644 index 0000000000..ca9790bf1a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/natstable.go @@ -0,0 +1,221 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSNATTableEntry struct { + multicloud.SResourceBase + AliyunTags + nat *SNatGateway + + SnatEntryId string + SnatEntryName string + SnatIp string + SnatTableId string `json:"snat_table_id"` + SourceCIDR string `json:"source_cidr"` + SourceVSwitchId string `json:"source_vswitch_id"` + Status string +} + +func (stable *SSNATTableEntry) GetName() string { + if len(stable.SnatEntryName) > 0 { + return stable.SnatEntryName + } + return stable.SnatEntryId +} + +func (stable *SSNATTableEntry) GetId() string { + return stable.SnatEntryId +} + +func (stable *SSNATTableEntry) GetGlobalId() string { + return stable.SnatEntryId +} + +func (stable *SSNATTableEntry) GetStatus() string { + switch stable.Status { + case "Available": + return api.NAT_STAUTS_AVAILABLE + default: + return api.NAT_STATUS_UNKNOWN + } +} + +func (stable *SSNATTableEntry) GetIP() string { + return stable.SnatIp +} + +func (stable *SSNATTableEntry) GetSourceCIDR() string { + return stable.SourceCIDR +} + +func (stable *SSNATTableEntry) GetNetworkId() string { + return stable.SourceVSwitchId +} + +func (stable *SSNATTableEntry) Delete() error { + return stable.nat.vpc.region.DeleteSnatEntry(stable.SnatTableId, stable.GetId()) +} + +func (self *SRegion) GetSNATEntries(tableId string, offset, limit int) ([]SSNATTableEntry, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + params["SnatTableId"] = tableId + + body, err := self.vpcRequest("DescribeSnatTableEntries", params) + if err != nil { + log.Errorf("DescribeSnatTableEntries fail %s", err) + return nil, 0, err + } + + if self.client.debug { + log.Debugf("%s", body.PrettyString()) + } + + entries := make([]SSNATTableEntry, 0) + err = body.Unmarshal(&entries, "SnatTableEntries", "SnatTableEntry") + if err != nil { + log.Errorf("Unmarshal entries fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return entries, int(total), nil +} + +func (self *SRegion) GetSNATEntry(tableID, SNATEntryID string) (SSNATTableEntry, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SnatTableId"] = tableID + params["SnatEntryId"] = SNATEntryID + + body, err := self.vpcRequest("DescribeSnatTableEntries", params) + if err != nil { + log.Errorf("DescribeSnatTableEntries fail %s", err) + return SSNATTableEntry{}, err + } + + if self.client.debug { + log.Debugf("%s", body.PrettyString()) + } + + entries := make([]SSNATTableEntry, 0) + err = body.Unmarshal(&entries, "SnatTableEntries", "SnatTableEntry") + if err != nil { + log.Errorf("Unmarshal entries fail %s", err) + return SSNATTableEntry{}, err + } + if len(entries) == 0 { + return SSNATTableEntry{}, cloudprovider.ErrNotFound + } + return entries[0], nil + +} + +func (region *SRegion) CreateSNATTableEntry(rule cloudprovider.SNatSRule, tableID string) (string, error) { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["SnatTableId"] = tableID + params["SnatIp"] = rule.ExternalIP + if len(rule.NetworkID) != 0 { + params["SourceVSwitchId"] = rule.NetworkID + } + if len(rule.SourceCIDR) != 0 { + params["SourceCIDR"] = rule.SourceCIDR + } + body, err := region.vpcRequest("CreateSnatEntry", params) + if err != nil { + return "", err + } + + entryID, _ := body.GetString("SnatEntryId") + return entryID, nil +} + +func (region *SRegion) DeleteSnatEntry(tableId string, entryId string) error { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["SnatTableId"] = tableId + params["SnatEntryId"] = entryId + _, err := region.vpcRequest("DeleteSnatEntry", params) + return err +} + +func (nat *SNatGateway) getSnatEntriesForTable(tblId string) ([]SSNATTableEntry, error) { + entries := make([]SSNATTableEntry, 0) + entryTotal := -1 + for entryTotal < 0 || len(entries) < entryTotal { + parts, total, err := nat.vpc.region.GetSNATEntries(tblId, len(entries), 50) + if err != nil { + return nil, err + } + if len(parts) > 0 { + entries = append(entries, parts...) + } + entryTotal = total + } + return entries, nil +} + +func (nat *SNatGateway) getSnatEntries() ([]SSNATTableEntry, error) { + entries := make([]SSNATTableEntry, 0) + for i := range nat.SnatTableIds.SnatTableId { + sentries, err := nat.getSnatEntriesForTable(nat.SnatTableIds.SnatTableId[i]) + if err != nil { + return nil, err + } + entries = append(entries, sentries...) + } + return entries, nil +} + +func (nat *SNatGateway) dissociateWithVswitch(vswitchId string) error { + entries, err := nat.getSnatEntries() + if err != nil { + return err + } + for i := range entries { + log.Debugf("%v", entries[i]) + if entries[i].SourceVSwitchId == vswitchId { + err := nat.vpc.region.DeleteSnatEntry(entries[i].SnatTableId, entries[i].SnatEntryId) + if err != nil { + return err + } + } + } + return nil +} + +func (stable *SSNATTableEntry) Refresh() error { + new, err := stable.nat.vpc.region.GetSNATEntry(stable.SnatTableId, stable.SnatEntryId) + if err != nil { + return err + } + return jsonutils.Update(stable, new) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/networkinterfaces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/networkinterfaces.go new file mode 100644 index 0000000000..8e560a5f5f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/networkinterfaces.go @@ -0,0 +1,167 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SPrivateIp struct { + nic *SNetworkInterface + Primary bool + PrivateIpAddress string +} + +func (ip *SPrivateIp) GetGlobalId() string { + return ip.PrivateIpAddress +} + +func (ip *SPrivateIp) GetINetworkId() string { + return ip.nic.VSwitchId +} + +func (ip *SPrivateIp) GetIP() string { + return ip.PrivateIpAddress +} + +func (ip *SPrivateIp) IsPrimary() bool { + return ip.Primary +} + +type SPrivateIpSets struct { + PrivateIpSet []SPrivateIp +} + +type SNetworkInterface struct { + multicloud.SNetworkInterfaceBase + AliyunTags + region *SRegion + + InstanceId string + CreationTime time.Time + MacAddress string + NetworkInterfaceName string + PrivateIpSets SPrivateIpSets + ResourceGroupId string + SecurityGroupIds SSecurityGroupIds + Status string + Type string + VSwitchId string + VpcId string + ZoneId string + NetworkInterfaceId string + PrimaryIpAddress string + PrivateIpAddress string +} + +func (nic *SNetworkInterface) GetName() string { + return nic.NetworkInterfaceName +} + +func (nic *SNetworkInterface) GetId() string { + return nic.NetworkInterfaceId +} + +func (nic *SNetworkInterface) GetGlobalId() string { + return nic.NetworkInterfaceId +} + +func (nic *SNetworkInterface) GetAssociateId() string { + return nic.InstanceId +} + +func (nic *SNetworkInterface) GetAssociateType() string { + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER +} + +func (nic *SNetworkInterface) GetMacAddress() string { + return nic.MacAddress +} + +func (nic *SNetworkInterface) GetStatus() string { + switch nic.Status { + case "Available": + return api.NETWORK_INTERFACE_STATUS_AVAILABLE + } + return nic.Status +} + +func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { + interfaces := []SNetworkInterface{} + for { + parts, total, err := region.GetNetworkInterfaces("", len(interfaces), 50) + if err != nil { + return nil, err + } + interfaces = append(interfaces, parts...) + if len(interfaces) >= total { + break + } + } + ret := []cloudprovider.ICloudNetworkInterface{} + for i := 0; i < len(interfaces); i++ { + // 阿里云实例的弹性网卡已经在guestnetwork同步了 + if len(interfaces[i].InstanceId) == 0 { + interfaces[i].region = region + ret = append(ret, &interfaces[i]) + } + } + return ret, nil +} + +func (nic *SNetworkInterface) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { + address := []cloudprovider.ICloudInterfaceAddress{} + for i := 0; i < len(nic.PrivateIpSets.PrivateIpSet); i++ { + nic.PrivateIpSets.PrivateIpSet[i].nic = nic + address = append(address, &nic.PrivateIpSets.PrivateIpSet[i]) + } + return address, nil +} + +func (region *SRegion) GetNetworkInterfaces(instanceId string, offset int, limit int) ([]SNetworkInterface, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + + params := map[string]string{ + "RegionId": region.RegionId, + "PageSize": fmt.Sprintf("%d", limit), + "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), + } + + if len(instanceId) > 0 { + params["InstanceId"] = instanceId + } + + body, err := region.ecsRequest("DescribeNetworkInterfaces", params) + if err != nil { + return nil, 0, errors.Wrap(err, "DescribeNetworkInterfaces") + } + + interfaces := []SNetworkInterface{} + err = body.Unmarshal(&interfaces, "NetworkInterfaceSets", "NetworkInterfaceSet") + if err != nil { + return nil, 0, errors.Wrap(err, "Unmarshal") + } + total, _ := body.Int("TotalCount") + return interfaces, int(total), nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/objects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/objects.go new file mode 100644 index 0000000000..0bced49419 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/objects.go @@ -0,0 +1,112 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "net/http" + + "github.com/aliyun/aliyun-oss-go-sdk/oss" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + OSS_META_HEADER = "x-oss-meta-" +) + +type SObject struct { + bucket *SBucket + + cloudprovider.SBaseCloudObject +} + +func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { + return o.bucket +} + +func (o *SObject) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + osscli, err := o.bucket.region.GetOssClient() + if err != nil { + log.Errorf("o.bucket.region.GetOssClient error %s", err) + return acl + } + bucket, err := osscli.Bucket(o.bucket.Name) + if err != nil { + log.Errorf("osscli.Bucket error %s", err) + return acl + } + result, err := bucket.GetObjectACL(o.Key) + if err != nil { + log.Errorf("bucket.GetObjectACL error %s", err) + return acl + } + if result.ACL == string(oss.ACLDefault) { + return o.bucket.GetAcl() + } + acl = cloudprovider.TBucketACLType(result.ACL) + return acl +} + +func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { + acl, err := str2Acl(string(aclStr)) + if err != nil { + return errors.Wrap(err, "str2Acl") + } + osscli, err := o.bucket.region.GetOssClient() + if err != nil { + return errors.Wrap(err, "o.bucket.region.GetOssClient") + } + bucket, err := osscli.Bucket(o.bucket.Name) + if err != nil { + return errors.Wrap(err, "osscli.Bucket") + } + err = bucket.SetObjectACL(o.Key, acl) + if err != nil { + return errors.Wrap(err, "bucket.SetObjectACL") + } + return nil +} + +func (o *SObject) GetMeta() http.Header { + if o.Meta != nil { + return o.Meta + } + osscli, err := o.bucket.region.GetOssClient() + if err != nil { + log.Errorf("o.bucket.region.GetOssClient error %s", err) + return nil + } + bucket, err := osscli.Bucket(o.bucket.Name) + if err != nil { + log.Errorf("osscli.Bucket error %s", err) + return nil + } + result, err := bucket.GetObjectDetailedMeta(o.Key) + if err != nil { + log.Errorf("bucket.GetObjectACL error %s", err) + return nil + } + o.Meta = cloudprovider.FetchMetaFromHttpHeader(OSS_META_HEADER, result) + return o.Meta +} + +func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { + return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/private_zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/private_zone.go new file mode 100644 index 0000000000..94cb338c06 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/private_zone.go @@ -0,0 +1,405 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "strconv" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var allowedTtls = []int64{5, 10, 15, 20, 30, 60, 120, 300, 600, 1800, 3600, 43200, 86400} + +type SPvtzVpc struct { + VpcID string `json:"VpcId"` + RegionName string `json:"RegionName"` + VpcName string `json:"VpcName"` + RegionID string `json:"RegionId"` +} + +type SPvtzBindVpcs struct { + Vpc []SPvtzVpc `json:"Vpc"` +} + +type SPrivateZone struct { + multicloud.SResourceBase + AliyunTags + client *SAliyunClient + + // RequestID string `json:"RequestId"` + ZoneID string `json:"ZoneId"` + SlaveDNS string `json:"SlaveDns"` + ResourceGroupID string `json:"ResourceGroupId"` + ProxyPattern string `json:"ProxyPattern"` + CreateTime string `json:"CreateTime"` + Remark string `json:"Remark"` + ZoneName string `json:"ZoneName"` + UpdateTime string `json:"UpdateTime"` + UpdateTimestamp string `json:"UpdateTimestamp"` + RecordCount int `json:"RecordCount"` + CreateTimestamp int64 `json:"CreateTimestamp"` + BindVpcs SPvtzBindVpcs `json:"BindVpcs"` + IsPtr bool `json:"IsPtr"` +} + +// list return +type sPrivateZones struct { + Zone []SPrivateZone `json:"Zone"` +} + +type SPrivateZones struct { + RequestID string `json:"RequestId"` + PageSize int `json:"PageSize"` + PageNumber int `json:"PageNumber"` + TotalPages int `json:"TotalPages"` + TotalItems int `json:"TotalItems"` + Zones sPrivateZones `json:"Zones"` +} + +// https://help.aliyun.com/document_detail/66243.html?spm=a2c4g.11186623.6.580.761357982tMV0Q +func (client *SAliyunClient) DescribeZones(pageNumber int, pageSize int) (SPrivateZones, error) { + sZones := SPrivateZones{} + params := map[string]string{} + params["Action"] = "DescribeZones" + params["PageNumber"] = strconv.Itoa(pageNumber) + params["PageSize"] = strconv.Itoa(pageSize) + resp, err := client.pvtzRequest("DescribeZones", params) + if err != nil { + return sZones, errors.Wrap(err, "DescribeZones") + } + err = resp.Unmarshal(&sZones) + if err != nil { + return sZones, errors.Wrap(err, "resp.Unmarshal") + } + return sZones, nil +} + +// 没有vpc等详细信息 +func (client *SAliyunClient) GetAllZones() ([]SPrivateZone, error) { + pageNumber := 0 + szones := []SPrivateZone{} + for { + pageNumber++ + zones, err := client.DescribeZones(pageNumber, 20) + if err != nil { + return nil, errors.Wrapf(err, "client.DescribeZones(%d, 20)", pageNumber) + } + szones = append(szones, zones.Zones.Zone...) + if len(szones) >= zones.TotalItems { + break + } + } + return szones, nil +} + +func (client *SAliyunClient) GetAllZonesInfo() ([]SPrivateZone, error) { + spvtzs := []SPrivateZone{} + szones, err := client.GetAllZones() + if err != nil { + return nil, errors.Wrap(err, "client.GetAllZones()") + } + for i := 0; i < len(szones); i++ { + spvtz, err := client.DescribeZoneInfo(szones[i].ZoneID) + if err != nil { + return nil, errors.Wrapf(err, "client.DescribeZoneInfo(%s)", szones[i].ZoneID) + } + spvtzs = append(spvtzs, *spvtz) + } + return spvtzs, nil +} + +func (client *SAliyunClient) GetPrivateICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { + izones := []cloudprovider.ICloudDnsZone{} + szones, err := client.GetAllZonesInfo() + if err != nil { + return nil, errors.Wrap(err, "client.GetAllZonesInfo()") + } + for i := 0; i < len(szones); i++ { + izones = append(izones, &szones[i]) + } + return izones, nil +} + +func (client *SAliyunClient) DescribeZoneInfo(zoneId string) (*SPrivateZone, error) { + params := map[string]string{} + params["Action"] = "DescribeZoneInfo" + params["ZoneId"] = zoneId + resp, err := client.pvtzRequest("DescribeZoneInfo", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeZoneInfo") + } + sZone := &SPrivateZone{client: client} + err = resp.Unmarshal(sZone) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return sZone, nil +} + +func (client *SAliyunClient) GetPrivateICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { + pvtzs, err := client.GetAllZones() + if err != nil { + return nil, errors.Wrap(err, "client.GetAllZones()") + } + index := -1 + for i := 0; i < len(pvtzs); i++ { + if pvtzs[i].ZoneID == id { + index = i + break + } + } + if index < 0 || index >= len(pvtzs) { + return nil, cloudprovider.ErrNotFound + } + izone, err := client.DescribeZoneInfo(id) + if err != nil { + return nil, errors.Wrapf(err, "client.DescribeZoneInfo(%s)", id) + } + return izone, nil +} + +func (client *SAliyunClient) DeleteZone(zoneId string) error { + params := map[string]string{} + params["Action"] = "DeleteZone" + params["ZoneId"] = zoneId + _, err := client.pvtzRequest("DeleteZone", params) + if err != nil { + return errors.Wrap(err, "DeleteZone") + } + return nil +} + +func (client *SAliyunClient) AddZone(zoneName string) (string, error) { + params := map[string]string{} + params["Action"] = "AddZone" + params["ZoneName"] = zoneName + ret, err := client.pvtzRequest("AddZone", params) + if err != nil { + return "", errors.Wrap(err, "AddZone") + } + zoneId := "" + return zoneId, ret.Unmarshal(&zoneId, "ZoneId") +} + +func (client *SAliyunClient) CreateZone(opts *cloudprovider.SDnsZoneCreateOptions) (*SPrivateZone, error) { + zoneId, err := client.AddZone(opts.Name) + if err != nil { + return nil, errors.Wrapf(err, "client.AddZone(%s)", opts.Name) + } + err = client.BindZoneVpcs(zoneId, opts.Vpcs) + if err != nil { + return nil, errors.Wrapf(err, " client.BindZoneVpcs(%s,%s)", zoneId, jsonutils.Marshal(opts.Vpcs).String()) + } + return client.DescribeZoneInfo(zoneId) +} + +func (client *SAliyunClient) CreatePrivateICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { + izone, err := client.CreateZone(opts) + if err != nil { + return nil, errors.Wrapf(err, "client.CreateZone(%s)", jsonutils.Marshal(opts).String()) + } + return izone, nil +} + +func (client *SAliyunClient) BindZoneVpc(ZoneId string, vpc *cloudprovider.SPrivateZoneVpc) error { + params := map[string]string{} + params["Action"] = "BindZoneVpc" + params["ZoneId"] = ZoneId + params["Vpcs.1.RegionId"] = vpc.RegionId + params["Vpcs.1.VpcId"] = vpc.Id + _, err := client.pvtzRequest("BindZoneVpc", params) + if err != nil { + return errors.Wrap(err, "BindZoneVpc") + } + return nil +} + +func (client *SAliyunClient) BindZoneVpcs(zoneId string, vpc []cloudprovider.SPrivateZoneVpc) error { + params := map[string]string{} + params["Action"] = "BindZoneVpc" + params["ZoneId"] = zoneId + index := "" + for i := 0; i < len(vpc); i++ { + index = strconv.Itoa(i + 1) + params["Vpcs."+index+".RegionId"] = vpc[i].RegionId + params["Vpcs."+index+".VpcId"] = vpc[i].Id + } + _, err := client.pvtzRequest("BindZoneVpc", params) + if err != nil { + return errors.Wrap(err, "BindZoneVpc") + } + return nil +} + +func (client *SAliyunClient) UnBindZoneVpcs(zoneId string) error { + params := map[string]string{} + params["Action"] = "BindZoneVpc" + params["ZoneId"] = zoneId + _, err := client.pvtzRequest("BindZoneVpc", params) + if err != nil { + return errors.Wrap(err, "BindZoneVpc") + } + return nil +} + +func (self *SPrivateZone) GetId() string { + return self.ZoneID +} + +func (self *SPrivateZone) GetName() string { + return self.ZoneName +} + +func (self *SPrivateZone) GetGlobalId() string { + return self.GetId() +} + +func (self *SPrivateZone) GetStatus() string { + return api.DNS_ZONE_STATUS_AVAILABLE +} + +func (self *SPrivateZone) Refresh() error { + szone, err := self.client.DescribeZoneInfo(self.ZoneID) + if err != nil { + return errors.Wrapf(err, "self.client.DescribeZoneInfo(%s)", self.ZoneID) + } + return jsonutils.Update(self, szone) +} + +func (self *SPrivateZone) GetZoneType() cloudprovider.TDnsZoneType { + return cloudprovider.PrivateZone +} + +func (self *SPrivateZone) GetOptions() *jsonutils.JSONDict { + return nil +} + +func (self *SPrivateZone) GetICloudVpcIds() ([]string, error) { + var ret []string + for i := 0; i < len(self.BindVpcs.Vpc); i++ { + ret = append(ret, self.BindVpcs.Vpc[i].VpcID) + } + return ret, nil +} + +func (self *SPrivateZone) AddVpc(vpc *cloudprovider.SPrivateZoneVpc) error { + vpcs := []cloudprovider.SPrivateZoneVpc{} + for i := 0; i < len(self.BindVpcs.Vpc); i++ { + vpc := cloudprovider.SPrivateZoneVpc{} + vpc.Id = self.BindVpcs.Vpc[i].VpcID + vpc.RegionId = self.BindVpcs.Vpc[i].RegionID + vpcs = append(vpcs, vpc) + } + vpcs = append(vpcs, *vpc) + return self.client.BindZoneVpcs(self.ZoneID, vpcs) +} + +func (self *SPrivateZone) RemoveVpc(vpc *cloudprovider.SPrivateZoneVpc) error { + vpcs := []cloudprovider.SPrivateZoneVpc{} + for i := 0; i < len(self.BindVpcs.Vpc); i++ { + newVpc := cloudprovider.SPrivateZoneVpc{} + if self.BindVpcs.Vpc[i].VpcID == vpc.Id && self.BindVpcs.Vpc[i].RegionID == vpc.RegionId { + continue + } + newVpc.Id = self.BindVpcs.Vpc[i].VpcID + newVpc.RegionId = self.BindVpcs.Vpc[i].RegionID + vpcs = append(vpcs, newVpc) + } + return self.client.BindZoneVpcs(self.ZoneID, vpcs) +} + +func (self *SPrivateZone) GetIDnsRecordSets() ([]cloudprovider.ICloudDnsRecordSet, error) { + zonerecords, err := self.client.GetAllZoneRecords(self.ZoneID) + if err != nil { + return nil, errors.Wrapf(err, "self.client.GetAllZoneRecords(%s)", self.ZoneID) + } + result := []cloudprovider.ICloudDnsRecordSet{} + for i := 0; i < len(zonerecords); i++ { + zonerecords[i].szone = self + result = append(result, &zonerecords[i]) + } + return result, nil +} + +func (self *SPrivateZone) SyncDnsRecordSets(common, add, del, update []cloudprovider.DnsRecordSet) error { + for i := 0; i < len(del); i++ { + err := self.client.DeleteZoneRecord(del[i].ExternalId) + if err != nil { + return errors.Wrapf(err, "self.client.DeleteZoneRecord(%s)", del[i].ExternalId) + } + } + + for i := 0; i < len(add); i++ { + recordId, err := self.client.AddZoneRecord(self.ZoneID, add[i]) + if err != nil { + return errors.Wrapf(err, "self.client.AddZoneRecord(%s,%s)", self.ZoneID, jsonutils.Marshal(add[i]).String()) + } + if !add[i].Enabled { + err = self.client.SetZoneRecordStatus(recordId, "DISABLE") + if err != nil { + return errors.Wrapf(err, "self.client.SetZoneRecordStatus(%s,%t)", recordId, add[i].Enabled) + } + } + } + + for i := 0; i < len(update); i++ { + // ENABLE: 启用解析 DISABLE: 暂停解析 + status := "ENABLE" + if !update[i].Enabled { + status = "DISABLE" + } + err := self.client.SetZoneRecordStatus(update[i].ExternalId, status) + if err != nil { + return errors.Wrapf(err, "self.client.SetZoneRecordStatus(%s,%t)", update[i].ExternalId, update[i].Enabled) + } + err = self.client.UpdateZoneRecord(update[i]) + if err != nil { + return errors.Wrapf(err, "self.client.UpdateZoneRecord(%s)", jsonutils.Marshal(update[i]).String()) + } + } + + return nil +} + +func (self *SPrivateZone) Delete() error { + if len(self.BindVpcs.Vpc) > 0 { + err := self.client.UnBindZoneVpcs(self.ZoneID) + if err != nil { + return errors.Wrapf(err, "self.client.UnBindZoneVpcs(%s)", self.ZoneID) + } + } + return self.client.DeleteZone(self.ZoneID) +} + +func (self *SPrivateZone) GetDnsProductType() cloudprovider.TDnsProductType { + return "" +} + +func (self *SPrivateZone) GetProperlyTTL(ttl int64) int64 { + if ttl < allowedTtls[0] { + return allowedTtls[0] + } + for i := 0; i < len(allowedTtls)-1; i++ { + if ttl > allowedTtls[i] && ttl < allowedTtls[i+1] { + return allowedTtls[i] + } + } + return allowedTtls[len(allowedTtls)-1] +} diff --git a/pkg/multicloud/aliyun/private_zone_record.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/private_zone_record.go similarity index 98% rename from pkg/multicloud/aliyun/private_zone_record.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/private_zone_record.go index b9134f9994..8d881eb6bc 100644 --- a/pkg/multicloud/aliyun/private_zone_record.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/private_zone_record.go @@ -20,8 +20,8 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SPvtzRecords struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/project.go new file mode 100644 index 0000000000..1e18278098 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/project.go @@ -0,0 +1,145 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SResourceGroup struct { + multicloud.SProjectBase + AliyunTags + client *SAliyunClient + + Status string + AccountId string + DisplayName string + Id string + CreateDate time.Time + Name string +} + +func (self *SResourceGroup) GetGlobalId() string { + return self.Id +} + +func (self *SResourceGroup) GetId() string { + return self.Id +} + +func (self *SResourceGroup) GetName() string { + if len(self.DisplayName) > 0 { + return self.DisplayName + } + return self.Name +} + +func (self *SResourceGroup) Refresh() error { + group, err := self.client.GetResourceGroup(self.Id) + if err != nil { + return errors.Wrap(err, "GetResourceGroup") + } + return jsonutils.Update(self, group) +} + +func (self *SResourceGroup) GetStatus() string { + switch self.Status { + case "Creating": + return api.EXTERNAL_PROJECT_STATUS_CREATING + case "OK": + return api.EXTERNAL_PROJECT_STATUS_AVAILABLE + case "Deleted", "Deleting", "PendingDelete": + return api.EXTERNAL_PROJECT_STATUS_DELETING + default: + return api.EXTERNAL_PROJECT_STATUS_UNKNOWN + } +} + +func (self *SAliyunClient) GetResourceGroups(pageNumber int, pageSize int) ([]SResourceGroup, int, error) { + if pageSize <= 0 || pageSize > 100 { + pageSize = 10 + } + if pageNumber <= 0 { + pageNumber = 1 + } + params := map[string]string{ + "PageNumber": fmt.Sprintf("%d", pageNumber), + "PageSize": fmt.Sprintf("%d", pageSize), + } + resp, err := self.rmRequest("ListResourceGroups", params) + if err != nil { + return nil, 0, errors.Wrap(err, "rmRequest.ListResourceGroups") + } + groups := []SResourceGroup{} + err = resp.Unmarshal(&groups, "ResourceGroups", "ResourceGroup") + if err != nil { + return nil, 0, errors.Wrap(err, "resp.Unmarshal") + } + total, _ := resp.Int("TotalCount") + return groups, int(total), nil +} + +func (self *SAliyunClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + group, err := self.CreateResourceGroup(name) + if err != nil { + return nil, errors.Wrap(err, "CreateProject") + } + return group, nil +} + +func (self *SAliyunClient) CreateResourceGroup(name string) (*SResourceGroup, error) { + params := map[string]string{ + "DisplayName": name, + "Name": name, + } + resp, err := self.rmRequest("CreateResourceGroup", params) + if err != nil { + return nil, errors.Wrap(err, "CreateResourceGroup") + } + group := &SResourceGroup{client: self} + err = resp.Unmarshal(group, "ResourceGroup") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + err = cloudprovider.WaitStatus(group, api.EXTERNAL_PROJECT_STATUS_AVAILABLE, time.Second*5, time.Minute*3) + if err != nil { + return nil, errors.Wrap(err, "WaitStatus") + } + return group, nil +} + +func (self *SAliyunClient) GetResourceGroup(id string) (*SResourceGroup, error) { + params := map[string]string{ + "ResourceGroupId": id, + } + resp, err := self.rmRequest("GetResourceGroup", params) + if err != nil { + return nil, err + } + group := &SResourceGroup{client: self} + err = resp.Unmarshal(group, "ResourceGroup") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return group, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/provider/doc.go new file mode 100644 index 0000000000..b069ae9438 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/aliyun/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/provider/provider.go new file mode 100644 index 0000000000..8c2a134072 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/provider/provider.go @@ -0,0 +1,513 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/aliyun" +) + +type SAliyunProviderFactory struct { + cloudprovider.SPublicCloudBaseProviderFactory +} + +func (self *SAliyunProviderFactory) GetId() string { + return aliyun.CLOUD_PROVIDER_ALIYUN +} + +func (self *SAliyunProviderFactory) GetName() string { + return aliyun.CLOUD_PROVIDER_ALIYUN_CN +} + +func (self *SAliyunProviderFactory) IsCloudeventRegional() bool { + return true +} + +func (self *SAliyunProviderFactory) IsSupportCloudIdService() bool { + return true +} + +func (self *SAliyunProviderFactory) IsSupportCreateCloudgroup() bool { + return true +} + +func (factory *SAliyunProviderFactory) IsSystemCloudpolicyUnified() bool { + return false +} + +func (factory *SAliyunProviderFactory) IsSupportSAMLAuth() bool { + return true +} + +func (self *SAliyunProviderFactory) GetSupportedDnsZoneTypes() []cloudprovider.TDnsZoneType { + return []cloudprovider.TDnsZoneType{ + cloudprovider.PublicZone, + cloudprovider.PrivateZone, + } +} + +func (self *SAliyunProviderFactory) GetSupportedDnsTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType { + return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType{ + cloudprovider.PublicZone: []cloudprovider.TDnsType{ + cloudprovider.DnsTypeA, + cloudprovider.DnsTypeAAAA, + cloudprovider.DnsTypeCAA, + cloudprovider.DnsTypeCNAME, + cloudprovider.DnsTypeMX, + cloudprovider.DnsTypeNS, + cloudprovider.DnsTypeSRV, + cloudprovider.DnsTypeTXT, + cloudprovider.DnsTypePTR, + cloudprovider.DnsTypeFORWARD_URL, + cloudprovider.DnsTypeREDIRECT_URL, + }, + cloudprovider.PrivateZone: []cloudprovider.TDnsType{ + cloudprovider.DnsTypeA, + cloudprovider.DnsTypeAAAA, + cloudprovider.DnsTypeCNAME, + cloudprovider.DnsTypeMX, + cloudprovider.DnsTypeSRV, + cloudprovider.DnsTypeTXT, + cloudprovider.DnsTypePTR, + }, + } +} + +func (self *SAliyunProviderFactory) GetSupportedDnsPolicyTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType { + return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType{ + cloudprovider.PublicZone: []cloudprovider.TDnsPolicyType{ + cloudprovider.DnsPolicyTypeSimple, + cloudprovider.DnsPolicyTypeByCarrier, + cloudprovider.DnsPolicyTypeByGeoLocation, + cloudprovider.DnsPolicyTypeBySearchEngine, + }, + cloudprovider.PrivateZone: []cloudprovider.TDnsPolicyType{ + cloudprovider.DnsPolicyTypeSimple, + }, + } +} + +func (self *SAliyunProviderFactory) GetSupportedDnsPolicyValues() map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue { + return map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue{ + cloudprovider.DnsPolicyTypeByCarrier: []cloudprovider.TDnsPolicyValue{ + cloudprovider.DnsPolicyValueUnicom, + cloudprovider.DnsPolicyValueTelecom, + cloudprovider.DnsPolicyValueChinaMobile, + cloudprovider.DnsPolicyValueCernet, + }, + cloudprovider.DnsPolicyTypeByGeoLocation: []cloudprovider.TDnsPolicyValue{ + cloudprovider.DnsPolicyValueOversea, + }, + cloudprovider.DnsPolicyTypeBySearchEngine: []cloudprovider.TDnsPolicyValue{ + cloudprovider.DnsPolicyValueBaidu, + cloudprovider.DnsPolicyValueGoogle, + cloudprovider.DnsPolicyValueBing, + }, + } +} + +func (self *SAliyunProviderFactory) GetTTLRange(zoneType cloudprovider.TDnsZoneType, productType cloudprovider.TDnsProductType) cloudprovider.TTlRange { + if zoneType == cloudprovider.PublicZone { + if len(productType) > 0 { + switch productType { + case cloudprovider.DnsProductEnterpriseUltimate: + return cloudprovider.TtlRangeAliyunEnterpriseUltimate + case cloudprovider.DnsProductEnterpriseStandard: + return cloudprovider.TtlRangeAliyunEnterpriseStandard + case cloudprovider.DnsProductPersonalProfessional: + return cloudprovider.TtlRangeAliyunPersonal + default: + return cloudprovider.TtlRangeAliyunFree + } + } + return cloudprovider.TtlRangeAliyunFree + } + + if zoneType == cloudprovider.PrivateZone { + return cloudprovider.TtlRangeAliyunPvtz + } + return cloudprovider.TTlRange{} +} + +func (self *SAliyunProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output.AccessUrl = input.Environment + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + return output, nil +} + +func (self *SAliyunProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func validateClientCloudenv(client *aliyun.SAliyunClient) error { + regions := client.GetIRegions() + if len(regions) == 0 { + return nil + } + + isFinanceAccount := false + for i := range regions { + if strings.Contains(regions[i].GetId(), "-finance") { + isFinanceAccount = true + break + } + } + + if isFinanceAccount { + if regions[0].GetCloudEnv() != "FinanceCloud" { + return errors.Wrap(httperrors.ErrInvalidCredential, "aksk is aliyun finance account") + } + } else { + if regions[0].GetCloudEnv() == "FinanceCloud" { + return errors.Wrap(httperrors.ErrInvalidCredential, "aksk is not aliyun finance account") + } + } + + return nil +} + +func (self *SAliyunProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + client, err := aliyun.NewAliyunClient( + aliyun.NewAliyunClientConfig( + cfg.URL, + cfg.Account, + cfg.Secret, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + + err = validateClientCloudenv(client) + if err != nil { + return nil, errors.Wrap(err, "validateClientCloudenv") + } + + return &SAliyunProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SAliyunProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + return map[string]string{ + "ALIYUN_ACCESS_KEY": info.Account, + "ALIYUN_SECRET": info.Secret, + "ALIYUN_REGION": aliyun.ALIYUN_DEFAULT_REGION, + }, nil +} + +func init() { + factory := SAliyunProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SAliyunProvider struct { + cloudprovider.SBaseProvider + client *aliyun.SAliyunClient +} + +func (self *SAliyunProvider) GetSysInfo() (jsonutils.JSONObject, error) { + regions := self.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") + info.Add(jsonutils.NewString(aliyun.ALIYUN_API_VERSION), "api_version") + return info, nil +} + +func (self *SAliyunProvider) GetVersion() string { + return aliyun.ALIYUN_API_VERSION +} + +func (self *SAliyunProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SAliyunProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SAliyunProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SAliyunProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(extId) +} + +func (self *SAliyunProvider) GetBalance() (float64, string, error) { + balance, err := self.client.QueryAccountBalance() + if err != nil { + return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, err + } + status := api.CLOUD_PROVIDER_HEALTH_NORMAL + if balance.CreditAmount+balance.MybankCreditAmount <= 0 { + if balance.AvailableAmount < 0 { + status = api.CLOUD_PROVIDER_HEALTH_ARREARS + } else if balance.AvailableAmount < 100 { + status = api.CLOUD_PROVIDER_HEALTH_INSUFFICIENT + } + } + return balance.AvailableAmount, status, nil +} + +func (self *SAliyunProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SAliyunProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return self.client.CreateIProject(name) +} + +func (self *SAliyunProvider) GetStorageClasses(regionId string) []string { + return []string{ + "Standard", "IA", "Archive", + } +} + +func (self *SAliyunProvider) GetBucketCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SAliyunProvider) GetObjectCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SAliyunProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SAliyunProvider) GetIamLoginUrl() string { + return self.client.GetIamLoginUrl() +} + +func (self *SAliyunProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + return self.client.CreateIClouduser(conf) +} + +func (self *SAliyunProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { + return self.client.GetICloudusers() +} + +func (self *SAliyunProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroups() +} + +func (self *SAliyunProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroupByName(name) +} + +func (self *SAliyunProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.client.GetIClouduserByName(name) +} + +func (self *SAliyunProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + return self.client.CreateICloudgroup(name, desc) +} + +func (self *SAliyunProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetISystemCloudpolicies() +} + +func (self *SAliyunProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetICustomCloudpolicies() +} + +func (self *SAliyunProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { + return self.client.CreateICloudpolicy(opts) +} + +func (self *SAliyunProvider) GetSamlEntityId() string { + return cloudprovider.SAML_ENTITY_ID_ALIYUN_ROLE +} + +func (self *SAliyunProvider) GetICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { + izones := []cloudprovider.ICloudDnsZone{} + privateZone, err := self.client.GetPrivateICloudDnsZones() + if err != nil { + return nil, errors.Wrap(err, "self.client.GetPrivateICloudDnsZones()") + } + publicZone, err := self.client.GetPublicICloudDnsZones() + if err != nil { + return nil, errors.Wrap(err, "self.client.GetPrivateICloudDnsZones()") + } + izones = append(izones, privateZone...) + izones = append(izones, publicZone...) + return izones, nil +} +func (self *SAliyunProvider) GetICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { + privateIzone, err := self.client.GetPrivateICloudDnsZoneById(id) + if err == nil { + return privateIzone, nil + } else { + if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + + publicIzone, err := self.client.GetPublicICloudDnsZoneById(id) + if err == nil { + return publicIzone, nil + } else { + if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SAliyunProvider) CreateICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { + if opts.ZoneType == cloudprovider.PrivateZone { + return self.client.CreatePrivateICloudDnsZone(opts) + } else { + return self.client.CreatePublicICloudDnsZone(opts) + } +} + +func (self *SAliyunProvider) GetICloudInterVpcNetworks() ([]cloudprovider.ICloudInterVpcNetwork, error) { + scens, err := self.client.GetAllCens() + if err != nil { + return nil, errors.Wrap(err, "self.client.GetAllCens()") + } + + iVpcNetworks := []cloudprovider.ICloudInterVpcNetwork{} + for i := range scens { + iVpcNetworks = append(iVpcNetworks, &scens[i]) + } + return iVpcNetworks, nil + +} +func (self *SAliyunProvider) GetICloudInterVpcNetworkById(id string) (cloudprovider.ICloudInterVpcNetwork, error) { + iVpcNetwork, err := self.GetICloudInterVpcNetworks() + if err != nil { + return nil, errors.Wrap(err, "self.GetICloudInterVpcNetworks()") + } + for i := range iVpcNetwork { + if iVpcNetwork[i].GetId() == id { + return iVpcNetwork[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} +func (self *SAliyunProvider) CreateICloudInterVpcNetwork(opts *cloudprovider.SInterVpcNetworkCreateOptions) (cloudprovider.ICloudInterVpcNetwork, error) { + cenId, err := self.client.CreateCen(opts) + if err != nil { + return nil, errors.Wrapf(err, "self.client.CreateCen(%s)", jsonutils.Marshal(opts).String()) + } + ivpcNetwork, err := self.GetICloudInterVpcNetworkById(cenId) + if err != nil { + return nil, errors.Wrapf(err, "self.GetICloudInterVpcNetworkById(%s)", cenId) + } + return ivpcNetwork, nil +} + +func (self *SAliyunProvider) GetCloudRegionExternalIdPrefix() string { + return self.client.GetAccessEnv() + "/" +} + +func (self *SAliyunProvider) GetICloudroles() ([]cloudprovider.ICloudrole, error) { + return self.client.GetICloudroles() +} + +func (self *SAliyunProvider) GetICloudroleById(id string) (cloudprovider.ICloudrole, error) { + info := strings.Split(id, "role/") + if len(info) == 2 { + role, err := self.client.GetRole(info[1]) + if err != nil { + return nil, errors.Wrapf(err, "GetRole(%s)", info[1]) + } + return role, nil + } + return nil, fmt.Errorf("invalid role id %s", id) +} + +func (self *SAliyunProvider) CreateICloudrole(opts *cloudprovider.SRoleCreateOptions) (cloudprovider.ICloudrole, error) { + stetement := fmt.Sprintf(`{"Statement":[{"Action":"sts:AssumeRole","Effect":"Allow","Principal":{"Federated":["%s"]},"Condition":{"StringEquals":{"saml:recipient":"https://signin.aliyun.com/saml-role/sso"}}}],"Version":"1"}`, opts.SAMLProvider) + role, err := self.client.CreateRole(opts.Name, stetement, opts.Desc) + if err != nil { + return nil, errors.Wrapf(err, "CreateRole") + } + return role, nil +} + +func (self *SAliyunProvider) GetICloudroleByName(name string) (cloudprovider.ICloudrole, error) { + role, err := self.client.GetRole(name) + if err != nil { + return nil, errors.Wrapf(err, "GetRole(%s)", name) + } + return role, nil +} + +func (self *SAliyunProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { + return self.client.GetICloudSAMLProviders() +} + +func (self *SAliyunProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { + sp, err := self.client.CreateSAMLProvider(opts.Name, opts.Metadata.String(), "") + if err != nil { + return nil, errors.Wrapf(err, "CreateSAMLProvider") + } + return sp, nil +} + +func (self *SAliyunProvider) GetICloudCDNDomains() ([]cloudprovider.ICloudCDNDomain, error) { + return self.client.GetICloudCDNDomains() +} + +func (self *SAliyunProvider) GetICloudCDNDomainByName(name string) (cloudprovider.ICloudCDNDomain, error) { + return self.client.GetICloudCDNDomainByName(name) +} + +func (self *SAliyunProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetMetrics(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/quota.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/quota.go new file mode 100644 index 0000000000..f7f78a91fd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/quota.go @@ -0,0 +1,136 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strconv" + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type ValueItem struct { + Value string + DiskCategory string +} + +type AttributeValues struct { + ValueItem []ValueItem +} + +type SAccountAttributeItem struct { + AttributeValues AttributeValues + AttributeName string +} + +type SQuota struct { + Name string + UsedCount int + MaxCount int +} + +func (q *SQuota) GetGlobalId() string { + return q.Name +} + +func (q *SQuota) GetDesc() string { + return q.Name +} + +func (q *SQuota) GetQuotaType() string { + return q.Name +} + +func (q *SQuota) GetMaxQuotaCount() int { + return q.MaxCount +} + +func (q *SQuota) GetCurrentQuotaUsedCount() int { + return q.UsedCount +} + +func (region *SRegion) GetAccountAttributes() ([]SAccountAttributeItem, error) { + params := map[string]string{ + "RegionId": region.RegionId, + } + resp, err := region.ecsRequest("DescribeAccountAttributes", params) + if err != nil { + return nil, errors.Wrap(err, "ecsRequest") + } + quotas := []SAccountAttributeItem{} + err = resp.Unmarshal("as, "AccountAttributeItems", "AccountAttributeItem") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return quotas, nil +} + +func (region *SRegion) GetQuotas() ([]SQuota, error) { + attrs, err := region.GetAccountAttributes() + if err != nil { + return nil, errors.Wrap(err, "GetAccountAttributes") + } + quotas := map[string]SQuota{} + for _, attr := range attrs { + for _, item := range attr.AttributeValues.ValueItem { + value, err := strconv.ParseInt(item.Value, 10, 64) + if err != nil { + continue + } + used := false + name := attr.AttributeName + if strings.HasPrefix(name, "used-") { + used = true + name = strings.TrimPrefix(name, "used-") + } + if len(item.DiskCategory) > 0 { + name = fmt.Sprintf("%s/%s", name, item.DiskCategory) + } + if _, ok := quotas[name]; !ok { + quotas[name] = SQuota{ + Name: name, + UsedCount: -1, + } + } + quota := quotas[name] + if used { + quota.UsedCount = int(value) + } else { + quota.MaxCount = int(value) + } + quotas[name] = quota + } + } + ret := []SQuota{} + for _, quota := range quotas { + ret = append(ret, quota) + } + return ret, nil +} + +func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { + quotas, err := region.GetQuotas() + if err != nil { + return nil, errors.Wrap(err, "GetQuotas") + } + ret := []cloudprovider.ICloudQuota{} + for i := range quotas { + ret = append(ret, "as[i]) + } + return ret, nil +} diff --git a/pkg/multicloud/aliyun/ram.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram.go similarity index 100% rename from pkg/multicloud/aliyun/ram.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_group.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_group.go new file mode 100644 index 0000000000..1e79fd79b1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_group.go @@ -0,0 +1,325 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SGroup struct { + client *SAliyunClient + + Comments string + CreatedDate time.Time + GroupName string + UpdateDate time.Time +} + +type sGroups struct { + Group []SGroup +} + +type SGroups struct { + Groups sGroups + Marker string + IsTruncated bool +} + +func (self *SGroup) GetName() string { + return self.GroupName +} + +func (self *SGroup) GetGlobalId() string { + return self.GroupName +} + +func (self *SGroup) GetDescription() string { + return self.Comments +} + +func (self *SGroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { + ret := []cloudprovider.IClouduser{} + offset := "" + for { + part, err := self.client.ListUsersForGroup(self.GroupName, offset, 1000) + if err != nil { + return nil, errors.Wrapf(err, "ListUsersForGroup") + } + for i := range part.Users.User { + part.Users.User[i].client = self.client + ret = append(ret, &part.Users.User[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SGroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := self.client.ListPoliciesForGroup(self.GroupName) + if err != nil { + return nil, errors.Wrapf(err, "ListPoliciesForGroup") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].PolicyType == POLICY_TYPE_SYSTEM { + policies[i].client = self.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (self *SGroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := self.client.ListPoliciesForGroup(self.GroupName) + if err != nil { + return nil, errors.Wrapf(err, "ListPoliciesForGroup") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].PolicyType == POLICY_TYPE_CUSTOM { + policies[i].client = self.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (self *SGroup) AddUser(name string) error { + return self.client.AddUserToGroup(self.GroupName, name) +} + +func (self *SGroup) RemoveUser(name string) error { + return self.client.RemoveUserFromGroup(self.GroupName, name) +} + +func (self *SGroup) AttachSystemPolicy(policyName string) error { + return self.client.AttachPolicyToGroup(POLICY_TYPE_SYSTEM, policyName, self.GroupName) +} + +func (self *SGroup) AttachCustomPolicy(policyName string) error { + return self.client.AttachPolicyToGroup(POLICY_TYPE_CUSTOM, policyName, self.GroupName) +} + +func (self *SGroup) DetachSystemPolicy(policyName string) error { + return self.client.DetachPolicyFromGroup(POLICY_TYPE_SYSTEM, policyName, self.GroupName) +} + +func (self *SGroup) DetachCustomPolicy(policyName string) error { + return self.client.DetachPolicyFromGroup(POLICY_TYPE_CUSTOM, policyName, self.GroupName) +} + +func (self *SGroup) Delete() error { + return self.client.DeleteGroup(self.GroupName) +} + +func (self *SAliyunClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + group, err := self.GetGroup(name) + if err != nil { + return nil, errors.Wrapf(err, "GetGroup(%s)", name) + } + return group, nil +} + +func (self *SAliyunClient) CreateICloudgroup(name string, desc string) (cloudprovider.ICloudgroup, error) { + group, err := self.CreateGroup(name, desc) + if err != nil { + return nil, errors.Wrapf(err, "CreateGroup") + } + return group, nil +} + +func (self *SAliyunClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + ret := []cloudprovider.ICloudgroup{} + offset := "" + for { + part, err := self.ListGroups(offset, 100) + if err != nil { + return nil, errors.Wrap(err, "ListGroups") + } + for i := range part.Groups.Group { + part.Groups.Group[i].client = self + ret = append(ret, &part.Groups.Group[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SAliyunClient) ListGroups(offset string, limit int) (*SGroups, error) { + if limit < 1 || limit > 1000 { + limit = 1000 + } + params := map[string]string{ + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(offset) > 0 { + params["Marker"] = offset + } + groups := SGroups{} + resp, err := self.ramRequest("ListGroups", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.ListGroups") + } + err = resp.Unmarshal(&groups) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return &groups, nil +} + +// https://help.aliyun.com/document_detail/28732.html?spm=a2c4g.11186623.6.777.580735b2m2xUh8 +func (self *SAliyunClient) ListPoliciesForGroup(groupName string) ([]SPolicy, error) { + params := map[string]string{ + "GroupName": groupName, + } + resp, err := self.ramRequest("ListPoliciesForGroup", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.ListPoliciesForGroup") + } + policies := []SPolicy{} + err = resp.Unmarshal(&policies, "Policies", "Policy") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return policies, nil +} + +func (self *SAliyunClient) ListUsersForGroup(groupName string, offset string, limit int) (*SUsers, error) { + if limit < 1 || limit > 1000 { + limit = 1000 + } + params := map[string]string{ + "GroupName": groupName, + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(offset) > 0 { + params["Marker"] = offset + } + resp, err := self.ramRequest("ListUsersForGroup", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.ListUserForGroup") + } + users := &SUsers{} + err = resp.Unmarshal(users) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return users, nil +} + +func (self *SAliyunClient) DeleteGroup(groupName string) error { + params := map[string]string{ + "GroupName": groupName, + } + _, err := self.ramRequest("DeleteGroup", params) + return err +} + +func (self *SAliyunClient) CreateGroup(groupName, comments string) (*SGroup, error) { + params := map[string]string{ + "GroupName": groupName, + } + if len(comments) > 0 { + params["Comments"] = comments + } + resp, err := self.ramRequest("CreateGroup", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.CreateGroup") + } + group := &SGroup{client: self} + err = resp.Unmarshal(group, "Group") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return group, nil +} + +func (self *SAliyunClient) GetGroup(groupName string) (*SGroup, error) { + params := map[string]string{ + "GroupName": groupName, + } + resp, err := self.ramRequest("GetGroup", params) + if err != nil { + return nil, errors.Wrap(err, "GetGroup") + } + group := &SGroup{client: self} + err = resp.Unmarshal(group, "Group") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return group, nil +} + +func (self *SAliyunClient) RemoveUserFromGroup(groupName, userName string) error { + params := map[string]string{ + "GroupName": groupName, + "UserName": userName, + } + _, err := self.ramRequest("RemoveUserFromGroup", params) + if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { + return errors.Wrap(err, "RemoveUserFromGroup") + } + return nil +} + +func (self *SAliyunClient) DetachPolicyFromGroup(policyType, policyName, groupName string) error { + params := map[string]string{ + "GroupName": groupName, + "PolicyName": policyName, + "PolicyType": policyType, + } + _, err := self.ramRequest("DetachPolicyFromGroup", params) + if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { + return errors.Wrap(err, "DetachPolicyFromGroup") + } + return nil +} + +func (self *SAliyunClient) AddUserToGroup(groupName, userName string) error { + params := map[string]string{ + "GroupName": groupName, + "UserName": userName, + } + _, err := self.ramRequest("AddUserToGroup", params) + if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.User.Group") { + return errors.Wrap(err, "AddUserToGroup") + } + return nil +} + +func (self *SAliyunClient) AttachPolicyToGroup(policyType, policyName, groupName string) error { + params := map[string]string{ + "GroupName": groupName, + "PolicyName": policyName, + "PolicyType": policyType, + } + _, err := self.ramRequest("AttachPolicyToGroup", params) + if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.Group.Policy") { + return errors.Wrap(err, "AttachPolicyToGroup") + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_policy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_policy.go new file mode 100644 index 0000000000..8cc9e2236a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_policy.go @@ -0,0 +1,316 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + POLICY_TYPE_SYSTEM = "System" + POLICY_TYPE_CUSTOM = "Custom" +) + +/** + {"AttachmentCount":0, +"CreateDate":"2018-10-12T05:05:16Z", +"DefaultVersion":"v1", +"Description":"只读访问Data Lake Analytics的权限", +"PolicyName":"AliyunDLAReadOnlyAccess", +"PolicyType":"System", +"UpdateDate":"2018-10-12T05:05:16Z"} +*/ + +type SDefaultPolicyVersion struct { + CreateDate time.Time + IsDefaultVersion bool + PolicyDocument string + VersionId string +} + +type SPolicyDetails struct { + Policy SPolicy + DefaultPolicyVersion SDefaultPolicyVersion +} + +type sPolicies struct { + Policy []SPolicy +} + +type SPolicies struct { + Policies sPolicies + Marker string + IsTruncated bool +} + +type SPolicy struct { + client *SAliyunClient + AttachmentCount int + CreateDate time.Time + UpdateDate time.Time + DefaultVersion string + Description string + PolicyName string + PolicyType string +} + +func (policy *SPolicy) GetName() string { + return policy.PolicyName +} + +func (policy *SPolicy) GetDescription() string { + return policy.Description +} + +func (policy *SPolicy) GetGlobalId() string { + return policy.PolicyName +} + +func (policy *SPolicy) UpdateDocument(document *jsonutils.JSONDict) error { + return policy.client.CreatePolicyVersion(policy.PolicyName, document.String(), true) +} + +func (policy *SPolicy) Delete() error { + return policy.client.DeletePolicy(policy.PolicyType, policy.PolicyName) +} + +func (policy *SPolicy) GetDocument() (*jsonutils.JSONDict, error) { + details, err := policy.client.GetPolicy(policy.PolicyType, policy.PolicyName) + if err != nil { + return nil, errors.Wrapf(err, "GetPolicy(%s,%s)", policy.PolicyType, policy.PolicyName) + } + obj, err := jsonutils.Parse([]byte(details.DefaultPolicyVersion.PolicyDocument)) + if err != nil { + return nil, errors.Wrap(err, "jsonutils.Parse") + } + return obj.(*jsonutils.JSONDict), nil +} + +func (self *SAliyunClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + ret := []cloudprovider.ICloudpolicy{} + offset := "" + for { + part, err := self.ListPolicies(POLICY_TYPE_SYSTEM, offset, 1000) + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + for i := range part.Policies.Policy { + part.Policies.Policy[i].client = self + ret = append(ret, &part.Policies.Policy[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SAliyunClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + ret := []cloudprovider.ICloudpolicy{} + offset := "" + for { + part, err := self.ListPolicies(POLICY_TYPE_CUSTOM, offset, 1000) + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + for i := range part.Policies.Policy { + part.Policies.Policy[i].client = self + ret = append(ret, &part.Policies.Policy[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SAliyunClient) AttachPolicyToUser(policyName, policyType, userName string) error { + params := map[string]string{ + "UserName": userName, + "PolicyName": policyName, + "PolicyType": policyType, + } + _, err := self.ramRequest("AttachPolicyToUser", params) + if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.User.Policy") { + return errors.Wrap(err, "AttachPolicyToUser") + } + return nil +} + +func (self *SAliyunClient) DetachPolicyFromUser(policyName, policyType, userName string) error { + if len(policyType) == 0 { + policyType = "System" + } + params := map[string]string{ + "UserName": userName, + "PolicyName": policyName, + "PolicyType": policyType, + } + _, err := self.ramRequest("DetachPolicyFromUser", params) + if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { + return errors.Wrap(err, "DetachPolicyFromUser") + } + return nil +} + +// https://help.aliyun.com/document_detail/28719.html?spm=a2c4g.11174283.6.764.27055662H6TGg5 +func (self *SAliyunClient) ListPolicies(policyType string, offset string, limit int) (*SPolicies, error) { + if limit < 1 || limit > 1000 { + limit = 1000 + } + params := map[string]string{ + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(policyType) > 0 { + params["PolicyType"] = policyType + } + if len(offset) > 0 { + params["Marker"] = offset + } + + body, err := self.ramRequest("ListPolicies", params) + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + policies := &SPolicies{} + + err = body.Unmarshal(&policies) + if err != nil { + return nil, errors.Wrapf(err, "body.Unmarshal") + } + + return policies, nil +} + +func (self *SAliyunClient) GetPolicy(policyType string, policyName string) (*SPolicyDetails, error) { + params := make(map[string]string) + params["PolicyType"] = policyType + params["PolicyName"] = policyName + + body, err := self.ramRequest("GetPolicy", params) + if err != nil { + if isError(err, "EntityNotExist.Role") { + return nil, cloudprovider.ErrNotFound + } + return nil, err + } + + policy := SPolicyDetails{} + + err = body.Unmarshal(&policy) + if err != nil { + return nil, err + } + + return &policy, nil +} + +type SStatement struct { + Action []string `json:"Action,allowempty"` + Effect string `json:"Effect"` + Resource []string `json:"Resource"` +} + +type SPolicyDocument struct { + Statement []SStatement `json:"Statement,allowempty"` + Version string `json:"Version"` +} + +func (self *SAliyunClient) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { + if opts.Document == nil { + return nil, errors.Error("nil document") + } + policy, err := self.CreatePolicy(opts.Name, opts.Document.String(), opts.Desc) + if err != nil { + return nil, errors.Wrapf(err, "CreatePolicy") + } + return policy, nil +} + +func (self *SAliyunClient) CreatePolicy(name string, document string, desc string) (*SPolicy, error) { + params := make(map[string]string) + params["PolicyName"] = name + params["PolicyDocument"] = document + if len(desc) > 0 { + params["Description"] = desc + } + + body, err := self.ramRequest("CreatePolicy", params) + if err != nil { + return nil, err + } + + policy := SPolicy{client: self} + + err = body.Unmarshal(&policy, "Policy") + if err != nil { + return nil, err + } + + return &policy, nil +} + +func (self *SAliyunClient) DeletePolicy(policyType string, policyName string) error { + params := make(map[string]string) + params["PolicyName"] = policyName + params["PolicyType"] = policyType + + _, err := self.ramRequest("DeletePolicy", params) + return err +} + +func (self *SAliyunClient) DeleteRole(roleName string) error { + params := make(map[string]string) + params["RoleName"] = roleName + + _, err := self.ramRequest("DeleteRole", params) + return err +} + +func (self *SAliyunClient) AttachPolicy2Role(policyType string, policyName string, roleName string) error { + params := make(map[string]string) + params["PolicyType"] = policyType + params["PolicyName"] = policyName + params["RoleName"] = roleName + + _, err := self.ramRequest("AttachPolicyToRole", params) + if err != nil { + return errors.Wrap(err, "AttachPolicyToRole") + } + + return nil +} + +func (self *SAliyunClient) CreatePolicyVersion(name, document string, isDefault bool) error { + params := map[string]string{ + "PolicyName": name, + "PolicyDocument": document, + "RotateStrategy": "DeleteOldestNonDefaultVersionWhenLimitExceeded", + } + if isDefault { + params["SetAsDefault"] = "true" + } + _, err := self.ramRequest("CreatePolicyVersion", params) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_role.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_role.go new file mode 100644 index 0000000000..ffc553b611 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_role.go @@ -0,0 +1,224 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type sRoles struct { + Role []SRole +} + +type SRoles struct { + Roles sRoles + Marker string + IsTruncated bool +} + +type SRole struct { + client *SAliyunClient + + Arn string + CreateDate time.Time + Description string + RoleId string + RoleName string + + AssumeRolePolicyDocument string +} + +func (self *SRole) GetGlobalId() string { + return self.Arn +} + +func (self *SRole) GetName() string { + return self.RoleName +} + +func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := self.client.ListPoliciesForRole(self.RoleName) + if err != nil { + return nil, errors.Wrapf(err, "ListPoliciesForRole") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + policies[i].client = self.client + ret = append(ret, &policies[i]) + } + return ret, nil +} + +func (self *SRole) AttachPolicy(policyName string) error { + return self.client.AttachPolicy2Role("System", policyName, self.RoleName) +} + +func (self *SRole) DetachPolicy(policyName string) error { + return self.client.DetachPolicyFromRole("System", policyName, self.RoleName) +} + +func (self *SRole) Delete() error { + return self.client.DeleteRole(self.RoleName) +} + +func (self *SRole) GetDocument() *jsonutils.JSONDict { + role, err := self.client.GetRole(self.RoleName) + if err != nil { + return nil + } + documet, err := jsonutils.Parse([]byte(role.AssumeRolePolicyDocument)) + if err != nil { + return nil + } + return documet.(*jsonutils.JSONDict) +} + +func (self *SRole) GetSAMLProvider() string { + document := self.GetDocument() + if document != nil { + statement, err := document.GetArray("Statement") + if err == nil { + for i := range statement { + if action, _ := statement[i].GetString("Action"); action == "sts:AssumeRole" { + sp, _ := statement[i].GetString("Principal", "Federated") + if len(sp) > 0 { + return sp + } + } + } + } + } + return "" +} + +func (self *SAliyunClient) GetICloudroles() ([]cloudprovider.ICloudrole, error) { + roles := []SRole{} + marker := "" + for { + part, err := self.ListRoles(marker, 1000) + if err != nil { + return nil, errors.Wrapf(err, "ListRoles(%s)", marker) + } + roles = append(roles, part.Roles.Role...) + if len(part.Marker) == 0 { + break + } + marker = part.Marker + } + ret := []cloudprovider.ICloudrole{} + for i := range roles { + roles[i].client = self + ret = append(ret, &roles[i]) + } + return ret, nil +} + +func (self *SAliyunClient) ListRoles(offset string, limit int) (*SRoles, error) { + if limit < 0 || limit > 1000 { + limit = 1000 + } + + params := map[string]string{} + if len(offset) > 0 { + params["Marker"] = offset + } + if limit > 0 { + params["MaxItems"] = fmt.Sprintf("%d", limit) + } + + body, err := self.ramRequest("ListRoles", params) + if err != nil { + return nil, errors.Wrapf(err, "ListRoles") + } + + roles := &SRoles{} + err = body.Unmarshal(roles) + if err != nil { + return nil, errors.Wrap(err, "body.Unmarshal(&") + } + return roles, nil +} + +func (self *SAliyunClient) CreateRole(roleName string, document string, desc string) (*SRole, error) { + params := make(map[string]string) + params["RoleName"] = roleName + params["AssumeRolePolicyDocument"] = document + if len(desc) > 0 { + params["Description"] = desc + } + + body, err := self.ramRequest("CreateRole", params) + if err != nil { + return nil, errors.Wrap(err, "CreateRole") + } + + role := SRole{client: self} + err = body.Unmarshal(&role, "Role") + if err != nil { + return nil, errors.Wrap(err, "body.Unmarshal") + } + + return &role, nil +} + +func (self *SAliyunClient) GetRole(roleName string) (*SRole, error) { + params := make(map[string]string) + params["RoleName"] = roleName + + body, err := self.ramRequest("GetRole", params) + if err != nil { + return nil, errors.Wrap(err, "GetRole") + } + + role := SRole{client: self} + err = body.Unmarshal(&role, "Role") + if err != nil { + return nil, errors.Wrap(err, "body.Unmarshal") + } + + return &role, nil +} + +func (self *SAliyunClient) ListPoliciesForRole(name string) ([]SPolicy, error) { + params := map[string]string{ + "RoleName": name, + } + resp, err := self.ramRequest("ListPoliciesForRole", params) + if err != nil { + return nil, errors.Wrapf(err, "ListPoliciesForRole") + } + policies := []SPolicy{} + err = resp.Unmarshal(&policies, "Policies", "Policy") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return policies, nil +} + +func (self *SAliyunClient) DetachPolicyFromRole(policyType, policyName, roleName string) error { + params := map[string]string{ + "PolicyName": policyName, + "PolicyType": policyType, + "RoleName": roleName, + } + _, err := self.ramRequest("DetachPolicyFromRole", params) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_user.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_user.go new file mode 100644 index 0000000000..31a035b8c7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ram_user.go @@ -0,0 +1,406 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type sUsers struct { + User []SUser +} + +type SUsers struct { + Users sUsers + Marker string + IsTruncated bool +} + +type SUser struct { + client *SAliyunClient + multicloud.SBaseClouduser + + Comments string + CreateDate time.Time + DisplayName string + Email string + MobilePhone string + UserId string + UserName string +} + +func (user *SUser) GetGlobalId() string { + if len(user.UserId) > 0 { + return user.UserId + } + u, err := user.client.GetUser(user.UserName) + if err != nil { + return "" + } + return u.UserId +} + +func (user *SUser) GetName() string { + return user.UserName +} + +func (user *SUser) GetEmailAddr() string { + return user.Email +} + +func (user *SUser) GetInviteUrl() string { + return "" +} + +func (user *SUser) Delete() error { + groups, err := user.client.ListGroupsForUser(user.UserName) + if err != nil { + return errors.Wrap(err, "ListGroupsForUser") + } + for i := range groups { + err = user.client.RemoveUserFromGroup(groups[i].GroupName, user.UserName) + if err != nil { + return errors.Wrapf(err, "RemoveUserFromGroup %s > %s", groups[i].GroupName, user.UserName) + } + } + policies, err := user.client.ListPoliciesForUser(user.UserName) + if err != nil { + return errors.Wrap(err, "ListPoliciesForUser") + } + for i := range policies { + err = user.client.DetachPolicyFromUser(policies[i].PolicyName, policies[i].PolicyType, user.UserName) + if err != nil { + return errors.Wrapf(err, "DetachPolicyFromUser %s %s %s", policies[i].PolicyName, policies[i].PolicyType, user.UserName) + } + } + return user.client.DeleteClouduser(user.UserName) +} + +func (user *SUser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + groups, err := user.client.ListGroupsForUser(user.UserName) + if err != nil { + return nil, errors.Wrapf(err, "ListGroupsForUser") + } + ret := []cloudprovider.ICloudgroup{} + for i := range groups { + groups[i].client = user.client + ret = append(ret, &groups[i]) + } + return ret, nil +} + +func (user *SUser) UpdatePassword(password string) error { + return user.client.UpdateLoginProfile(user.UserName, password) +} + +func (user *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := user.client.ListPoliciesForUser(user.UserName) + if err != nil { + return nil, errors.Wrap(err, "ListPoliciesForUser") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].PolicyType == "System" { + policies[i].client = user.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (user *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := user.client.ListPoliciesForUser(user.UserName) + if err != nil { + return nil, errors.Wrap(err, "ListPoliciesForUser") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].PolicyType == "Custom" { + policies[i].client = user.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (user *SUser) IsConsoleLogin() bool { + _, err := user.client.GetLoginProfile(user.UserName) + if errors.Cause(err) == cloudprovider.ErrNotFound { + return false + } + return true +} + +func (user *SUser) ResetPassword(password string) error { + return user.client.ResetClouduserPassword(user.UserName, password) +} + +func (user *SUser) AttachSystemPolicy(policyName string) error { + return user.client.AttachPolicyToUser(policyName, POLICY_TYPE_SYSTEM, user.UserName) +} + +func (user *SUser) AttachCustomPolicy(policyName string) error { + return user.client.AttachPolicyToUser(policyName, POLICY_TYPE_CUSTOM, user.UserName) +} + +func (user *SUser) DetachSystemPolicy(policyName string) error { + return user.client.DetachPolicyFromUser(policyName, POLICY_TYPE_SYSTEM, user.UserName) +} + +func (user *SUser) DetachCustomPolicy(policyName string) error { + return user.client.DetachPolicyFromUser(policyName, POLICY_TYPE_CUSTOM, user.UserName) +} + +func (self *SAliyunClient) DeleteClouduser(name string) error { + params := map[string]string{ + "UserName": name, + } + _, err := self.ramRequest("DeleteUser", params) + return err +} + +func (self *SAliyunClient) CreateUser(name, phone, email, comments string) (*SUser, error) { + params := map[string]string{ + "UserName": name, + "DisplayName": name, + } + if len(phone) > 0 { + params["MobilePhone"] = phone + } + if len(email) > 0 { + params["Email"] = email + } + if len(comments) > 0 { + params["Comments"] = comments + } + resp, err := self.ramRequest("CreateUser", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.CreateUser") + } + + user := &SUser{client: self} + err = resp.Unmarshal(user, "User") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return user, nil +} + +func (self *SAliyunClient) ListUsers(offset string, limit int) (*SUsers, error) { + params := map[string]string{} + if len(offset) > 0 { + params["Marker"] = offset + } + if limit > 0 { + params["MaxItems"] = fmt.Sprintf("%d", limit) + } + resp, err := self.ramRequest("ListUsers", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.ListUsers") + } + users := &SUsers{} + err = resp.Unmarshal(users) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return users, nil +} + +func (self *SAliyunClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + user, err := self.CreateUser(conf.Name, conf.MobilePhone, conf.Email, conf.Desc) + if err != nil { + return nil, errors.Wrap(err, "CreateUser") + } + if len(conf.Password) > 0 { + _, err := self.CreateLoginProfile(conf.Name, conf.Password) + if err != nil { + return nil, errors.Wrap(err, "CreateLoginProfile") + } + } + for _, policyId := range conf.ExternalPolicyIds { + err := user.AttachSystemPolicy(policyId) + if err != nil { + log.Errorf("attach policy %s for user %s error: %v", policyId, conf.Name, err) + } + } + return user, nil +} + +func (self *SAliyunClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { + ret := []cloudprovider.IClouduser{} + offset := "" + for { + part, err := self.ListUsers(offset, 100) + if err != nil { + return nil, errors.Wrap(err, "GetCloudusers") + } + for i := range part.Users.User { + part.Users.User[i].client = self + ret = append(ret, &part.Users.User[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SAliyunClient) GetUser(name string) (*SUser, error) { + params := map[string]string{ + "UserName": name, + } + resp, err := self.ramRequest("GetUser", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.CreateUser") + } + user := &SUser{client: self} + err = resp.Unmarshal(user, "User") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return user, nil +} + +func (self *SAliyunClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.GetUser(name) +} + +type SLoginProfile struct { + CreateDate string + MFABindRequired bool + PasswordResetRequired bool + UserName string +} + +func (self *SAliyunClient) GetLoginProfile(name string) (*SLoginProfile, error) { + params := map[string]string{ + "UserName": name, + } + resp, err := self.ramRequest("GetLoginProfile", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.GetLoginProfile") + } + profile := &SLoginProfile{} + err = resp.Unmarshal(profile, "LoginProfile") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return profile, nil +} + +func (self *SAliyunClient) DeleteLoginProfile(name string) error { + params := map[string]string{ + "UserName": name, + } + _, err := self.ramRequest("DeleteLoginProfile", params) + return err +} + +func (self *SAliyunClient) CreateLoginProfile(name, password string) (*SLoginProfile, error) { + params := map[string]string{ + "UserName": name, + "Password": password, + } + resp, err := self.ramRequest("CreateLoginProfile", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.CreateLoginProfile") + } + profile := &SLoginProfile{} + err = resp.Unmarshal(profile, "LoginProfile") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return profile, nil +} + +func (self *SAliyunClient) UpdateLoginProfile(name, password string) error { + params := map[string]string{ + "UserName": name, + "Password": password, + } + _, err := self.ramRequest("UpdateLoginProfile", params) + if err != nil { + return errors.Wrap(err, "ramRequest.CreateLoginProfile") + } + return nil +} + +func (self *SAliyunClient) ResetClouduserPassword(name, password string) error { + _, err := self.GetLoginProfile(name) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + _, err = self.CreateLoginProfile(name, password) + return err + } + return errors.Wrap(err, "GetLoginProfile") + } + return self.UpdateLoginProfile(name, password) +} + +func (self *SAliyunClient) GetIamLoginUrl() string { + params := map[string]string{} + resp, err := self.ramRequest("GetAccountAlias", params) + if err != nil { + log.Errorf("GetAccountAlias error: %v", err) + return "" + } + alias, _ := resp.GetString("AccountAlias") + if len(alias) > 0 { + return fmt.Sprintf("https://signin.aliyun.com/%s.onaliyun.com/login.htm", alias) + } + return "" +} + +// https://help.aliyun.com/document_detail/28707.html?spm=a2c4g.11186623.6.752.f4466bbfVy5j0s +func (self *SAliyunClient) ListGroupsForUser(user string) ([]SGroup, error) { + params := map[string]string{ + "UserName": user, + } + resp, err := self.ramRequest("ListGroupsForUser", params) + if err != nil { + return nil, errors.Wrap(err, "ListGroupsForUser") + } + groups := []SGroup{} + err = resp.Unmarshal(&groups, "Groups", "Group") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return groups, nil +} + +// https://help.aliyun.com/document_detail/28732.html?spm=a2c4g.11186623.6.777.580735b2m2xUh8 +func (self *SAliyunClient) ListPoliciesForUser(user string) ([]SPolicy, error) { + params := map[string]string{ + "UserName": user, + } + resp, err := self.ramRequest("ListPoliciesForUser", params) + if err != nil { + return nil, errors.Wrap(err, "ListPoliciesForUser") + } + policies := []SPolicy{} + err = resp.Unmarshal(&policies, "Policies", "Policy") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return policies, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ramimage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ramimage.go new file mode 100644 index 0000000000..6116517764 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/ramimage.go @@ -0,0 +1,203 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + AliyunECSImageImportRole = "AliyunECSImageImportDefaultRole" + AliyunECSImageImportRoleDocument = `{ +"Statement": [ +{ +"Action": "sts:AssumeRole", +"Effect": "Allow", +"Principal": { + "Service": [ + "ecs.aliyuncs.com" + ] +} +} +], +"Version": "1" +}` + + AliyunECSImageImportRolePolicyType = "System" + AliyunECSImageImportRolePolicy = "AliyunECSImageImportRolePolicy" + AliyunECSImageImportRolePolicyDocument = `{ +"Version": "1", +"Statement": [ +{ +"Action": [ + "oss:GetObject", + "oss:GetBucketLocation" +], +"Resource": "*", +"Effect": "Allow" +} +] +}` +) + +func (self *SAliyunClient) EnableImageImport() error { + _, err := self.GetRole(AliyunECSImageImportRole) + if err != nil { + if errors.Cause(err) != cloudprovider.ErrNotFound { + return err + } + _, err = self.CreateRole(AliyunECSImageImportRole, + AliyunECSImageImportRoleDocument, + "Allow Import External Image from OSS") + if err != nil { + return err + } + } + + _, err = self.GetPolicy(AliyunECSImageImportRolePolicyType, AliyunECSImageImportRolePolicy) + if err != nil { + /*if err != cloudprovider.ErrNotFound { + return err + } + _, err = self.createPolicy(AliyunECSImageImportRolePolicy, + AliyunECSImageImportRolePolicyDocument, + "Allow Import External Image policy") + if err != nil { + return err + }*/ + return err + } + + policies, err := self.ListPoliciesForRole(AliyunECSImageImportRole) + if err != nil { + return err + } + for i := 0; i < len(policies); i += 1 { + if policies[i].PolicyType == AliyunECSImageImportRolePolicyType && + policies[i].PolicyName == AliyunECSImageImportRolePolicy { + return nil // find policy + } + } + + err = self.AttachPolicy2Role(AliyunECSImageImportRolePolicyType, AliyunECSImageImportRolePolicy, AliyunECSImageImportRole) + if err != nil { + return err + } + + return nil +} + +const ( + AliyunECSImageExportRole = "AliyunECSImageExportDefaultRole" + AliyunECSImageExportRoleDocument = `{ + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": [ + "ecs.aliyuncs.com" + ] + } + } + ], + "Version": "1" +}` + + AliyunEmptyRoleDocument = `{ + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": [ + "ecs.aliyuncs.com" + ] + } + } + ], + "Version": "1" +}` + + AliyunECSImageExportRolePolicyType = "System" + AliyunECSImageExportRolePolicy = "AliyunECSImageExportRolePolicy" + AliyunECSImageExportRolePolicyDocument = `{ + "Version": "1", + "Statement": [ + { + "Action": [ + "oss:GetObject", + "oss:PutObject", + "oss:DeleteObject", + "oss:GetBucketLocation", + "oss:AbortMultipartUpload", + "oss:ListMultipartUploads", + "oss:ListParts" + ], + "Resource": "*", + "Effect": "Allow" + } + ] + }` +) + +func (self *SAliyunClient) EnableImageExport() error { + _, err := self.GetRole(AliyunECSImageExportRole) + if err != nil { + if err != cloudprovider.ErrNotFound { + return err + } + _, err = self.CreateRole(AliyunECSImageExportRole, + AliyunECSImageExportRoleDocument, + "Allow Export Import to OSS") + if err != nil { + return err + } + } + + _, err = self.GetPolicy(AliyunECSImageExportRolePolicyType, AliyunECSImageExportRolePolicy) + if err != nil { + /*if err != cloudprovider.ErrNotFound { + return err + } + _, err = self.createPolicy(AliyunECSImageImportRolePolicy, + AliyunECSImageImportRolePolicyDocument, + "Allow Import External Image policy") + if err != nil { + return err + }*/ + return err + } + + policies, err := self.ListPoliciesForRole(AliyunECSImageExportRole) + if err != nil { + return err + } + for i := 0; i < len(policies); i += 1 { + if policies[i].PolicyType == AliyunECSImageExportRolePolicyType && + policies[i].PolicyName == AliyunECSImageExportRolePolicy { + return nil // find policy + } + } + + err = self.AttachPolicy2Role(AliyunECSImageExportRolePolicyType, AliyunECSImageExportRolePolicy, AliyunECSImageExportRole) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/region.go new file mode 100644 index 0000000000..9d900d5fe8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/region.go @@ -0,0 +1,1255 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "github.com/aliyun/alibaba-cloud-sdk-go/sdk" + "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" + "github.com/aliyun/aliyun-oss-go-sdk/oss" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/regutils" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + multicloud.SRegion + + client *SAliyunClient + sdkClient *sdk.Client + ossClient *oss.Client + mongoSkus map[string]struct { + CpuCount int + MemSizeGb int + } + + RegionId string + LocalName string + + RegionEndpoint string + + izones []cloudprovider.ICloudZone + + ivpcs []cloudprovider.ICloudVpc + + lbEndpints map[string]string + + storageCache *SStoragecache + + instanceTypes []SInstanceType + + latitude float64 + longitude float64 + fetchLocation bool +} + +func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetClient() *SAliyunClient { + return self.client +} + +func (self *SRegion) getSdkClient() (*sdk.Client, error) { + if self.sdkClient == nil { + cli, err := self.client.getSdkClient(self.RegionId) + if err != nil { + return nil, err + } + self.sdkClient = cli + } + return self.sdkClient, nil +} + +func (self *SRegion) getEcsClient() (*ecs.Client, error) { + sdkClient, err := self.getSdkClient() + if err != nil { + return nil, errors.Wrap(err, "getSdkClient") + } + ecsClient := &ecs.Client{ + Client: *sdkClient, + } + return ecsClient, nil +} + +func (self *SRegion) getOSSExternalDomain() string { + return getOSSExternalDomain(self.RegionId) +} + +func (self *SRegion) getOSSInternalDomain() string { + return getOSSInternalDomain(self.RegionId) +} + +func (self *SRegion) getRegionId() string { + if self.client.cloudEnv == ALIYUN_FINANCE_CLOUDENV { + switch self.RegionId { + case "cn-hangzhou": + return "cn-hzfinance" + case "cn-shanghai-finance-1": + return "cn-shanghai-finance-1-pub" + case "cn-shenzhen-finance-1": + return "cn-szfinance" + } + } + return self.RegionId +} + +func (self *SRegion) GetOssClient() (*oss.Client, error) { + if self.ossClient == nil { + cli, err := self.client.getOssClient(self.getRegionId()) + if err != nil { + return nil, errors.Wrap(err, "self.client.getOssClient") + } + self.ossClient = cli + } + return self.ossClient, nil +} + +func (self *SRegion) ecsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + endpoint := self.RegionEndpoint + if len(endpoint) == 0 { + endpoint = "ecs.aliyuncs.com" + } + params = self.client.SetResourceGropuId(params) + return jsonRequest(client, endpoint, ALIYUN_API_VERSION, apiName, params, self.client.debug) +} + +func (self *SRegion) wafRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + if self.RegionId != "cn-hangzhou" && self.RegionId != "ap-southeast-1" { + return nil, cloudprovider.ErrNotSupported + } + params = self.client.SetResourceGropuId(params) + endpoint := fmt.Sprintf("wafopenapi.%s.aliyuncs.com", self.RegionId) + return jsonRequest(client, endpoint, ALIYUN_WAF_API_VERSION, apiName, params, self.client.debug) +} + +func (self *SRegion) esRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + params = self.client.SetResourceGropuId(params) + domain := fmt.Sprintf("elasticsearch.%s.aliyuncs.com", self.RegionId) + return jsonRequest(client, domain, ALIYUN_ES_API_VERSION, apiName, params, self.client.debug) +} + +func (self *SRegion) kafkaRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + params = self.client.SetResourceGropuId(params) + domain := fmt.Sprintf("alikafka.%s.aliyuncs.com", self.RegionId) + return jsonRequest(client, domain, ALIYUN_KAFKA_API_VERSION, apiName, params, self.client.debug) +} + +func (self *SRegion) rdsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + params = self.client.SetResourceGropuId(params) + return jsonRequest(client, "rds.aliyuncs.com", ALIYUN_RDS_API_VERSION, apiName, params, self.client.debug) +} + +func (self *SRegion) k8sRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + params = self.client.SetResourceGropuId(params) + return jsonRequest(client, fmt.Sprintf("cs.%s.aliyuncs.com", self.RegionId), ALIYUN_K8S_API_VERSION, apiName, params, self.client.debug) +} + +func (self *SRegion) mongodbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + params = self.client.SetResourceGropuId(params) + return jsonRequest(client, "mongodb.aliyuncs.com", ALIYUN_MONGO_DB_API_VERSION, apiName, params, self.client.debug) +} + +func (self *SRegion) vpcRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + params = self.client.SetResourceGropuId(params) + endpoint := self.GetClient().getVpcEndpoint(self.RegionId) + return jsonRequest(client, endpoint, ALIYUN_API_VERSION_VPC, action, params, self.client.debug) +} + +func (self *SRegion) nasRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + switch self.GetCloudEnv() { + case ALIYUN_FINANCE_CLOUDENV: + if strings.Contains(action, "FileSystem") { + if self.RegionId == "cn-hangzhou" { + params["RegionId"] = "cn-hangzhou-dg-a01" + } + } + if strings.Contains(action, "Access") || strings.Contains(action, "MountTarget") { + if self.RegionId == "cn-hangzhou" { + params["RegionId"] = "cn-hangzhou-finance" + } + } + } + + params = self.client.SetResourceGropuId(params) + endpint := self.GetClient().getNasEndpoint(self.RegionId) + return jsonRequest(client, endpint, ALIYUN_NAS_API_VERSION, action, params, self.client.debug) +} + +func (self *SRegion) kvsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + + if _, ok := params["RegionId"]; ok { + params["RegionId"] = transRegionIdFromEcsRegionId(self, "redis") + } + + params = self.client.SetResourceGropuId(params) + return jsonRequest(client, "r-kvstore.aliyuncs.com", ALIYUN_API_VERSION_KVS, action, params, self.client.debug) +} + +type LBRegion struct { + RegionEndpoint string + RegionId string +} + +func (self *SRegion) fetchLBRegions(client *sdk.Client) error { + if len(self.lbEndpints) > 0 { + return nil + } + params := map[string]string{} + result, err := self._lbRequest(client, "DescribeRegions", "slb.aliyuncs.com", params) + if err != nil { + return err + } + self.lbEndpints = map[string]string{} + regions := []LBRegion{} + if err := result.Unmarshal(®ions, "Regions", "Region"); err != nil { + return err + } + for _, region := range regions { + self.lbEndpints[region.RegionId] = region.RegionEndpoint + } + return nil +} + +func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + domain := "slb.aliyuncs.com" + if !utils.IsInStringArray(apiName, []string{"DescribeRegions", "DescribeZones"}) { + if regionId, ok := params["RegionId"]; ok { + if err := self.fetchLBRegions(client); err != nil { + return nil, err + } + endpoint, ok := self.lbEndpints[regionId] + if !ok { + return nil, fmt.Errorf("failed to find endpoint for lb region %s", regionId) + } + domain = endpoint + } + } + params = self.client.SetResourceGropuId(params) + return self._lbRequest(client, apiName, domain, params) +} + +func (self *SRegion) _lbRequest(client *sdk.Client, apiName string, domain string, params map[string]string) (jsonutils.JSONObject, error) { + return jsonRequest(client, domain, ALIYUN_API_VERSION_LB, apiName, params, self.client.debug) +} + +///////////////////////////////////////////////////////////////////////////// +func (self *SRegion) GetId() string { + return self.RegionId +} + +func (self *SRegion) GetName() string { + if self.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV && !strings.Contains(self.LocalName, "金融") { + return fmt.Sprintf("%s %s %s", CLOUD_PROVIDER_ALIYUN_CN, self.LocalName, "金融云") + } else { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_ALIYUN_CN, self.LocalName) + } +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_ALIYUN_EN, self.LocalName) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.RegionId) +} + +func (self *SRegion) IsEmulated() bool { + return false +} + +func (self *SRegion) GetProvider() string { + return CLOUD_PROVIDER_ALIYUN +} + +func (self *SRegion) GetCloudEnv() string { + return self.client.cloudEnv +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + if info, ok := LatitudeAndLongitude[self.RegionId]; ok { + return info + } + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) Refresh() error { + // do nothing + return nil +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if self.izones == nil { + var err error + err = self.fetchInfrastructure() + if err != nil { + return nil, err + } + } + return self.izones, nil +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) getStoragecache() *SStoragecache { + if self.storageCache == nil { + self.storageCache = &SStoragecache{region: self} + } + return self.storageCache +} + +func (self *SRegion) _fetchZones(chargeType TChargeType, spotStrategy SpotStrategyType) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + if len(chargeType) > 0 { + params["InstanceChargeType"] = string(chargeType) + } + if len(spotStrategy) > 0 { + params["SpotStrategy"] = string(spotStrategy) + } + body, err := self.ecsRequest("DescribeZones", params) + if err != nil { + return err + } + + zones := make([]SZone, 0) + err = body.Unmarshal(&zones, "Zones", "Zone") + if err != nil { + return err + } + + self.izones = make([]cloudprovider.ICloudZone, len(zones)) + + for i := 0; i < len(zones); i += 1 { + zones[i].region = self + self.izones[i] = &zones[i] + } + + return nil +} + +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) +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + return self.GetInstance(id) +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return self.getDisk(id) +} + +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) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + ivpcs, err := self.GetIVpcs() + if err != nil { + return nil, err + } + for i := 0; i < len(ivpcs); i += 1 { + if ivpcs[i].GetGlobalId() == id { + return ivpcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) fetchIVpcs() error { + vpcs := make([]SVpc, 0) + for { + part, total, err := self.GetVpcs(nil, len(vpcs), 50) + if err != nil { + return err + } + vpcs = append(vpcs, part...) + if len(vpcs) >= total { + break + } + } + self.ivpcs = make([]cloudprovider.ICloudVpc, len(vpcs)) + for i := 0; i < len(vpcs); i += 1 { + vpcs[i].region = self + self.ivpcs[i] = &vpcs[i] + } + return nil +} + +func (self *SRegion) fetchInfrastructure() error { + err := self._fetchZones(PostPaidInstanceChargeType, NoSpotStrategy) + if err != nil { + return err + } + err = self.fetchIVpcs() + if 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) GetVpcs(vpcId []string, offset int, limit int) ([]SVpc, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if vpcId != nil && len(vpcId) > 0 { + params["VpcId"] = strings.Join(vpcId, ",") + } + + body, err := self.vpcRequest("DescribeVpcs", params) + if err != nil { + log.Errorf("GetVpcs fail %s", err) + return nil, 0, err + } + + vpcs := make([]SVpc, 0) + err = body.Unmarshal(&vpcs, "Vpcs", "Vpc") + if err != nil { + log.Errorf("Unmarshal vpc fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return vpcs, int(total), 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) GetVRouters(offset int, limit int) ([]SVRouter, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + body, err := self.ecsRequest("DescribeVRouters", params) + if err != nil { + log.Errorf("GetVRouters fail %s", err) + return nil, 0, err + } + + vrouters := make([]SVRouter, 0) + err = body.Unmarshal(&vrouters, "VRouters", "VRouter") + if err != nil { + log.Errorf("Unmarshal vrouter fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return vrouters, int(total), nil +} + +func (self *SRegion) GetRouteTables(ids []string, offset int, limit int) ([]SRouteTable, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + if ids != nil && len(ids) > 0 { + params["RouteTableId"] = strings.Join(ids, ",") + } + + body, err := self.ecsRequest("DescribeRouteTables", params) + if err != nil { + log.Errorf("GetRouteTables fail %s", err) + return nil, 0, err + } + + routetables := make([]SRouteTable, 0) + err = body.Unmarshal(&routetables, "RouteTables", "RouteTable") + if err != nil { + log.Errorf("Unmarshal routetables fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return routetables, int(total), nil +} + +func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, gpu int, zoneId string) ([]SInstanceType, error) { + if self.instanceTypes == nil { + types, err := self.GetInstanceTypes() + if err != nil { + log.Errorf("GetInstanceTypes %s", err) + return nil, err + } + self.instanceTypes = types + } + var available []string + if len(zoneId) > 0 { + zone, err := self.getZoneById(zoneId) + if err != nil { + return nil, err + } + available = zone.AvailableInstanceTypes.InstanceTypes + } + ret := make([]SInstanceType, 0) + for _, t := range self.instanceTypes { + if t.CpuCoreCount == cpu && memMB == t.memoryMB() && gpu == t.GPUAmount { + if available == nil || utils.IsInStringArray(t.InstanceTypeId, available) { + ret = append(ret, t) + } + } + } + return ret, nil +} + +func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, memGB int, storageType string, dataDiskSizesGB []int, vswitchId string, passwd 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(vswitchId) + if net != nil { + desc := &cloudprovider.SManagedVMCreateConfig{ + Name: name, + ExternalImageId: imgId, + SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType}, + Cpu: cpu, + MemoryMB: memGB * 1024, + ExternalNetworkId: vswitchId, + Password: passwd, + DataDisks: []cloudprovider.SDiskInfo{}, + PublicKey: publicKey, + } + for _, sizeGB := range dataDiskSizesGB { + desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType}) + } + inst, err := z.getHost().CreateVM(desc) + if err != nil { + return nil, err + } + return inst.(*SInstance), nil + } + } + return nil, fmt.Errorf("cannot find vswitch %s", vswitchId) +} + +func (self *SRegion) instanceOperation(instanceId string, opname string, extra map[string]string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + if extra != nil && len(extra) > 0 { + for k, v := range extra { + params[k] = v + } + } + _, err := self.ecsRequest(opname, params) + return err +} + +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) GetInstanceVNCUrl(instanceId string) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + body, err := self.ecsRequest("DescribeInstanceVncUrl", params) + if err != nil { + return "", err + } + return body.GetString("VncUrl") +} + +func (self *SRegion) ModifyInstanceVNCUrlPassword(instanceId string, passwd string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + params["VncPassword"] = passwd // must be 6 digital + alphabet + _, err := self.ecsRequest("ModifyInstanceVncPasswd", params) + return err +} + +func (self *SRegion) CreateVpc(opts *cloudprovider.VpcCreateOptions) (*SVpc, error) { + params := make(map[string]string) + if len(opts.CIDR) > 0 { + params["CidrBlock"] = opts.CIDR + } + if len(opts.NAME) > 0 { + params["VpcName"] = opts.NAME + } + if len(opts.Desc) > 0 { + params["Description"] = opts.Desc + } + params["ClientToken"] = utils.GenRequestId(20) + body, err := self.ecsRequest("CreateVpc", params) + if err != nil { + return nil, err + } + vpcId, err := body.GetString("VpcId") + if err != nil { + return nil, err + } + err = self.fetchInfrastructure() + if err != nil { + return nil, err + } + return self.getVpc(vpcId) +} + +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + vpc, err := self.CreateVpc(opts) + if err != nil { + return nil, err + } + return vpc, nil +} + +func (self *SRegion) DeleteVpc(vpcId string) error { + params := make(map[string]string) + params["VpcId"] = vpcId + + _, err := self.ecsRequest("DeleteVpc", params) + return err +} + +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 errors.Cause(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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname, userData string) error { + params := make(map[string]string) + params["InstanceId"] = instId + if len(name) > 0 { + params["InstanceName"] = name + } + if len(desc) > 0 { + params["Description"] = desc + } + if len(passwd) > 0 { + params["Password"] = passwd + } + if len(hostname) > 0 { + params["HostName"] = hostname + } + if len(userData) > 0 { + params["UserData"] = userData + } + _, err := self.ecsRequest("ModifyInstanceAttribute", params) + return err +} + +func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error { + return self.updateInstance(instId, "", "", passwd, "", "") +} + +// func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { +// eips, total, err := self.GetSnapshots("", 0, 50) +// if err != nil { +// return nil, err +// } +// for len(eips) < total { +// var parts []SEipAddress +// parts, total, err = self.GetEips("", len(eips), 50) +// if err != nil { +// return nil, err +// } +// eips = append(eips, parts...) +// } +// ret := make([]cloudprovider.ICloudEIP, len(eips)) +// for i := 0; i < len(eips); i += 1 { +// ret[i] = &eips[i] +// } +// return ret, nil +// } + +func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, total, err := self.GetEips("", "", "", 0, 50) + if err != nil { + return nil, err + } + for len(eips) < total { + var parts []SEipAddress + parts, total, err = self.GetEips("", "", "", len(eips), 50) + if err != nil { + return nil, err + } + eips = append(eips, parts...) + } + ret := make([]cloudprovider.ICloudEIP, len(eips)) + for i := 0; i < len(eips); i += 1 { + ret[i] = &eips[i] + } + return ret, nil +} + +func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { + eips, total, err := self.GetEips(eipId, "", "", 0, 1) + 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 (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + secgroup, err := region.GetSecurityGroupDetails(secgroupId) + if err != nil { + return nil, err + } + vpc, err := region.getVpc(secgroup.VpcId) + if err != nil { + return nil, errors.Wrapf(err, "region.getVpc(%s)", secgroup.VpcId) + } + secgroup.vpc = vpc + return secgroup, nil +} + +func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, total, err := region.GetSecurityGroups(opts.VpcId, opts.Name, []string{}, 0, 0) + if err != nil { + return nil, err + } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } + if total > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return &secgroups[0], nil +} + +func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + externalId, err := region.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) + if err != nil { + return nil, err + } + return region.GetISecurityGroupById(externalId) +} + +func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + lbs, err := region.GetLoadbalancers(nil) + if err != nil { + return nil, err + } + ilbs := []cloudprovider.ICloudLoadbalancer{} + for i := 0; i < len(lbs); i++ { + lbs[i].region = region + ilbs = append(ilbs, &lbs[i]) + } + return ilbs, nil +} + +func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { + return region.GetLoadbalancerDetail(loadbalancerId) +} + +func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + certs, err := region.GetLoadbalancerServerCertificates() + if err != nil { + return nil, err + } + for i := 0; i < len(certs); i++ { + if certs[i].GetGlobalId() == certId { + certs[i].region = region + return &certs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["ServerCertificateName"] = cert.Name + params["PrivateKey"] = cert.PrivateKey + params["ServerCertificate"] = cert.Certificate + body, err := region.lbRequest("UploadServerCertificate", params) + if err != nil { + return nil, err + } + certID, err := body.GetString("ServerCertificateId") + if err != nil { + return nil, err + } + return region.GetILoadBalancerCertificateById(certID) +} + +func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { + return region.GetLoadbalancerAclDetail(aclId) +} + +func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { + acls, err := region.GetLoadBalancerAcls() + if err != nil { + return nil, err + } + iAcls := []cloudprovider.ICloudLoadbalancerAcl{} + for i := 0; i < len(acls); i++ { + acls[i].region = region + iAcls = append(iAcls, &acls[i]) + } + return iAcls, nil +} + +func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + certificates, err := region.GetLoadbalancerServerCertificates() + if err != nil { + return nil, err + } + iCertificates := []cloudprovider.ICloudLoadbalancerCertificate{} + for i := 0; i < len(certificates); i++ { + certificates[i].region = region + iCertificates = append(iCertificates, &certificates[i]) + } + return iCertificates, nil +} + +func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerName"] = loadbalancer.Name + if len(loadbalancer.ZoneID) > 0 { + params["MasterZoneId"] = transZoneIdFromEcsZoneId(region, "elb", loadbalancer.ZoneID) + } + + if len(loadbalancer.VpcID) > 0 { + params["VpcId"] = loadbalancer.VpcID + } + + if len(loadbalancer.NetworkIDs) > 0 { + params["VSwitchId"] = loadbalancer.NetworkIDs[0] + } + + if len(loadbalancer.Address) > 0 { + params["Address"] = loadbalancer.Address + } + + if len(loadbalancer.AddressType) > 0 { + params["AddressType"] = loadbalancer.AddressType + } + + if len(loadbalancer.LoadbalancerSpec) > 0 { + params["LoadBalancerSpec"] = loadbalancer.LoadbalancerSpec + } + + if len(loadbalancer.ChargeType) > 0 { + params["InternetChargeType"] = "payby" + loadbalancer.ChargeType + } + + if len(loadbalancer.ProjectId) > 0 { + params["ResourceGroupId"] = loadbalancer.ProjectId + } + + if loadbalancer.ChargeType == api.LB_CHARGE_TYPE_BY_BANDWIDTH && loadbalancer.EgressMbps > 0 { + params["Bandwidth"] = fmt.Sprintf("%d", loadbalancer.EgressMbps) + } + + body, err := region.lbRequest("CreateLoadBalancer", params) + if err != nil { + return nil, err + } + loadBalancerID, err := body.GetString("LoadBalancerId") + if err != nil { + return nil, err + } + region.SetResourceTags(ALIYUN_SERVICE_SLB, "instance", loadBalancerID, loadbalancer.Tags, false) + iLoadbalancer, err := region.GetLoadbalancerDetail(loadBalancerID) + if err != nil { + return nil, err + } + return iLoadbalancer, cloudprovider.WaitStatus(iLoadbalancer, api.LB_STATUS_ENABLED, time.Second*5, time.Minute*5) +} + +func (region *SRegion) AddAccessControlListEntry(aclId string, entrys []cloudprovider.SLoadbalancerAccessControlListEntry) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["AclId"] = aclId + aclArray := jsonutils.NewArray() + for i := 0; i < len(entrys); i++ { + //阿里云AclEntrys参数必须是CIDR格式的。 + if regutils.MatchIPAddr(entrys[i].CIDR) { + entrys[i].CIDR += "/32" + } + aclArray.Add(jsonutils.Marshal(map[string]string{"entry": entrys[i].CIDR, "comment": entrys[i].Comment})) + } + if aclArray.Length() == 0 { + return nil + } + params["AclEntrys"] = aclArray.String() + _, err := region.lbRequest("AddAccessControlListEntry", params) + return err +} + +func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["AclName"] = acl.Name + body, err := region.lbRequest("CreateAccessControlList", params) + if err != nil { + return nil, err + } + aclId, err := body.GetString("AclId") + if err != nil { + return nil, err + } + iAcl, err := region.GetLoadbalancerAclDetail(aclId) + if err != nil { + return nil, err + } + return iAcl, region.AddAccessControlListEntry(aclId, acl.Entrys) +} + +func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + iBuckets, err := region.client.getIBuckets() + if err != nil { + return nil, errors.Wrap(err, "getIBuckets") + } + ret := make([]cloudprovider.ICloudBucket, 0) + for i := range iBuckets { + if iBuckets[i].GetIRegion().GetId() != region.GetId() { + continue + } + ret = append(ret, iBuckets[i]) + } + return ret, nil +} + +func str2StorageClass(storageClassStr string) (oss.StorageClassType, error) { + storageClass := oss.StorageStandard + if strings.EqualFold(storageClassStr, string(oss.StorageStandard)) { + // + } else if strings.EqualFold(storageClassStr, string(oss.StorageIA)) { + storageClass = oss.StorageIA + } else if strings.EqualFold(storageClassStr, string(oss.StorageArchive)) { + storageClass = oss.StorageArchive + } else { + return storageClass, errors.Error("not supported storageClass") + } + return storageClass, nil +} + +func str2Acl(aclStr string) (oss.ACLType, error) { + acl := oss.ACLPrivate + if strings.EqualFold(aclStr, string(oss.ACLPrivate)) { + // private, default + } else if strings.EqualFold(aclStr, string(oss.ACLPublicRead)) { + acl = oss.ACLPublicRead + } else if strings.EqualFold(aclStr, string(oss.ACLPublicReadWrite)) { + acl = oss.ACLPublicReadWrite + } else { + return acl, errors.Error("not supported acl") + } + return acl, nil +} + +func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { + osscli, err := region.GetOssClient() + if err != nil { + return errors.Wrap(err, "region.GetOssClient") + } + opts := make([]oss.Option, 0) + if len(storageClassStr) > 0 { + storageClass, err := str2StorageClass(storageClassStr) + if err != nil { + return err + } + opts = append(opts, oss.StorageClass(storageClass)) + } + if len(aclStr) > 0 { + acl, err := str2Acl(aclStr) + if err != nil { + return err + } + opts = append(opts, oss.ACL(acl)) + } + err = osscli.CreateBucket(name, opts...) + if err != nil { + return errors.Wrap(err, "oss.CreateBucket") + } + region.client.invalidateIBuckets() + return nil +} + +func ossErrorCode(err error) int { + if srvErr, ok := err.(oss.ServiceError); ok { + return srvErr.StatusCode + } + if srvErr, ok := err.(*oss.ServiceError); ok { + return srvErr.StatusCode + } + return -1 +} + +func (region *SRegion) DeleteIBucket(name string) error { + osscli, err := region.GetOssClient() + if err != nil { + return errors.Wrap(err, "region.GetOssClient") + } + err = osscli.DeleteBucket(name) + if err != nil { + if ossErrorCode(err) == 404 { + return nil + } + return errors.Wrap(err, "DeleteBucket") + } + region.client.invalidateIBuckets() + return nil +} + +func (region *SRegion) IBucketExist(name string) (bool, error) { + osscli, err := region.GetOssClient() + if err != nil { + return false, errors.Wrap(err, "region.GetOssClient") + } + exist, err := osscli.IsBucketExist(name) + if err != nil { + return false, errors.Wrap(err, "IsBucketExist") + } + return exist, nil +} + +func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { + osscli, err := region.GetOssClient() + if err != nil { + return nil, errors.Wrap(err, "region.GetOssClient") + } + bi, err := osscli.GetBucketInfo(name) + if err != nil { + return nil, errors.Wrap(err, "Bucket") + } + bInfo := bi.BucketInfo + b := SBucket{ + region: region, + Name: bInfo.Name, + Location: bInfo.Location, + CreationDate: bInfo.CreationDate, + StorageClass: bInfo.StorageClass, + } + return &b, nil +} + +func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { + return region.GetIBucketById(name) +} + +func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { + caches, err := self.GetElasticCaches(nil) + if err != nil { + return nil, err + } + + icaches := make([]cloudprovider.ICloudElasticcache, len(caches)) + for i := range caches { + caches[i].region = self + icaches[i] = &caches[i] + } + + return icaches, nil +} + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} + +func (self *SRegion) trialRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + domain := fmt.Sprintf("actiontrail.%s.aliyuncs.com", self.RegionId) + return jsonRequest(client, domain, ALIYUN_API_VERSION_TRIAL, apiName, params, self.client.debug) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/resource_tags.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/resource_tags.go new file mode 100644 index 0000000000..3c115cb597 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/resource_tags.go @@ -0,0 +1,191 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +func (self *SRegion) tagRequest(serviceType, action string, params map[string]string) (jsonutils.JSONObject, error) { + switch serviceType { + case ALIYUN_SERVICE_ECS: + return self.ecsRequest(action, params) + case ALIYUN_SERVICE_VPC: + return self.vpcRequest(action, params) + case ALIYUN_SERVICE_RDS: + return self.rdsRequest(action, params) + case ALIYUN_SERVICE_SLB: + return self.lbRequest(action, params) + case ALIYUN_SERVICE_KVS: + return self.kvsRequest(action, params) + case ALIYUN_SERVICE_NAS: + return self.nasRequest(action, params) + case ALIYUN_SERVICE_MONGO_DB: + return self.mongodbRequest(action, params) + case ALIYUN_SERVICE_CDN: + return self.client.cdnRequest(action, params) + default: + return nil, fmt.Errorf("invalid service type") + } +} + +// 资源类型。取值范围: +// disk, instance, image, securitygroup, snapshot +func (self *SRegion) ListTags(serviceType string, resourceType string, resourceId string) ([]SAliyunTag, error) { + tags := []SAliyunTag{} + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["ResourceType"] = resourceType + params["ResourceId.1"] = resourceId + nextToken := "" + for { + if len(nextToken) > 0 { + params["NextToken"] = nextToken + } + resp, err := self.tagRequest(serviceType, "ListTagResources", params) + if err != nil { + return nil, errors.Wrapf(err, "%s ListTagResources %s", serviceType, params) + } + part := []SAliyunTag{} + err = resp.Unmarshal(&part, "TagResources", "TagResource") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + tags = append(tags, part...) + nextToken, _ = resp.GetString("NextToken") + if len(nextToken) == 0 { + break + } + } + return tags, nil +} + +func (self *SRegion) UntagResource(serviceType string, resourceType string, resId string, keys []string) error { + if len(resId) == 0 || len(keys) == 0 { + return nil + } + + params := map[string]string{ + "RegionId": self.RegionId, + "ResourceId.1": resId, + "ResourceType": resourceType, + } + for i, key := range keys { + params[fmt.Sprintf("TagKey.%d", i+1)] = key + } + + _, err := self.tagRequest(serviceType, "UntagResources", params) + return errors.Wrapf(err, "UntagResources %s", params) +} + +func (self *SRegion) SetResourceTags(serviceType string, resourceType string, resId string, tags map[string]string, replace bool) error { + _, _tags, err := self.ListSysAndUserTags(serviceType, resourceType, resId) + if err != nil { + return errors.Wrapf(err, "ListTags") + } + keys, upperKeys := []string{}, []string{} + for k := range tags { + keys = append(keys, k) + upperKeys = append(upperKeys, strings.ToUpper(k)) + } + if replace { + if len(tags) > 0 { + removeKeys := []string{} + for k := range _tags { + if !utils.IsInStringArray(k, keys) { + removeKeys = append(removeKeys, k) + } + } + if len(removeKeys) > 0 { + err := self.UntagResource(serviceType, resourceType, resId, removeKeys) + if err != nil { + return errors.Wrapf(err, "UntagResource") + } + } + } + } else { + removeKeys := []string{} + for k := range _tags { + if !utils.IsInStringArray(k, keys) && utils.IsInStringArray(strings.ToUpper(k), upperKeys) { + removeKeys = append(removeKeys, k) + } + } + if len(removeKeys) > 0 { + err := self.UntagResource(serviceType, resourceType, resId, removeKeys) + if err != nil { + return errors.Wrapf(err, "UntagResource") + } + } + } + return self.TagResource(serviceType, resourceType, resId, tags) +} + +func (self *SRegion) TagResource(serviceType string, resourceType string, resourceId string, tags map[string]string) error { + if len(tags) > 20 { + return errors.Wrap(cloudprovider.ErrNotSupported, "tags count exceed 20 for one request") + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["ResourceType"] = resourceType + params["ResourceId.1"] = resourceId + i := 0 + for k, v := range tags { + if strings.HasPrefix(k, "aliyun") || + strings.HasPrefix(k, "acs:") || + strings.HasPrefix(k, "http://") || + strings.HasPrefix(k, "https://") || + strings.HasPrefix(v, "http://") || + strings.HasPrefix(v, "https://") || + strings.HasPrefix(v, "acs:") { + continue + } + params[fmt.Sprintf("Tag.%d.Key", i+1)] = k + params[fmt.Sprintf("Tag.%d.Value", i+1)] = v + i++ + } + action := "TagResources" + if len(tags) == 0 { + action = "UntagResources" + params["All"] = "true" + } + _, err := self.tagRequest(serviceType, action, params) + if err != nil { + return errors.Wrapf(err, "%s %s %s", action, resourceId, params) + } + return nil +} + +func (self *SRegion) ListSysAndUserTags(serviceType string, resourceType string, resourceId string) (map[string]string, map[string]string, error) { + tags, err := self.ListTags(serviceType, resourceType, resourceId) + if err != nil { + return nil, nil, errors.Wrapf(err, "ListTags(%s, %s)", resourceType, resourceId) + } + sys, user := map[string]string{}, map[string]string{} + for _, tag := range tags { + if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") { + sys[tag.TagKey] = tag.TagValue + continue + } + user[tag.TagKey] = tag.TagValue + } + return sys, user, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/routetable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/routetable.go new file mode 100644 index 0000000000..422e00d734 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/routetable.go @@ -0,0 +1,341 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// {"CreationTime":"2017-03-19T13:37:40Z","RouteEntrys":{"RouteEntry":[{"DestinationCidrBlock":"172.31.32.0/20","InstanceId":"","NextHopType":"local","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"},{"DestinationCidrBlock":"100.64.0.0/10","InstanceId":"","NextHopType":"service","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"}]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","RouteTableType":"System","VRouterId":"vrt-j6c00qrol733dg36iq4qj"} + +type SNextHops struct { + NextHop []string +} + +type SRouteEntry struct { + multicloud.SResourceBase + AliyunTags + routeTable *SRouteTable + + RouteTableId string + Type string + DestinationCidrBlock string + NextHopType string + InstanceId string + RouteEntryId string + RouteEntryName string + NextHops SNextHops +} + +func (route *SRouteEntry) GetId() string { + return fmt.Sprintf("%s-%s-%s", route.RouteTableId, route.DestinationCidrBlock, route.NextHopType) +} + +func (route *SRouteEntry) GetName() string { + return route.RouteEntryName +} + +func (route *SRouteEntry) GetGlobalId() string { + return route.GetId() +} + +func (route *SRouteEntry) GetStatus() string { + return api.ROUTE_ENTRY_STATUS_AVAILIABLE +} + +func (route *SRouteEntry) Refresh() error { + return nil +} + +func (route *SRouteEntry) IsEmulated() bool { + return false +} + +// Custom:自定义路由。 System:系统路由。 +func (route *SRouteEntry) GetType() string { + return route.Type +} + +func (route *SRouteEntry) GetCidr() string { + return route.DestinationCidrBlock +} + +func (route *SRouteEntry) GetNextHopType() string { + switch route.NextHopType { + case "Instance": + return api.NEXT_HOP_TYPE_INSTANCE + case "HaVip": + return api.NEXT_HOP_TYPE_HAVIP + case "VpnGateway": + return api.NEXT_HOP_TYPE_VPN + case "NatGateway": + return api.NEXT_HOP_TYPE_NAT + case "NetworkInterface": + return api.NEXT_HOP_TYPE_NETWORK + case "RouterInterface": + return api.NEXT_HOP_TYPE_ROUTER + case "IPv6Gateway": + return api.NEXT_HOP_TYPE_IPV6 + case "InternetGateway": + return api.NEXT_HOP_TYPE_INTERNET + case "Next_HOP_TYPE_EGRESS_INTERNET": + return api.NEXT_HOP_TYPE_EGRESS_INTERNET + default: + return "" + } +} + +func (route *SRouteEntry) GetNextHop() string { + return route.InstanceId +} + +type SRouteEntrys struct { + RouteEntry []*SRouteEntry +} + +type SRouteTable struct { + multicloud.SResourceBase + AliyunTags + region *SRegion + vpc *SVpc + routes []cloudprovider.ICloudRoute + + VpcId string + CreationTime time.Time + RouteEntrys SRouteEntrys + VRouterId string + Description string + + RouteTableId string + RouteTableName string + RouteTableType string + RouterId string + RouterType string + VSwitchIds SRouteTableVSwitchIds +} + +type SRouteTableVSwitchIds struct { + VSwitchId []string +} + +type sDescribeRouteTablesResponseRouteTables struct { + RouteTable []SRouteTable +} + +type sDescribeRouteTablesResponse struct { + RouteTables sDescribeRouteTablesResponseRouteTables + TotalCount int +} + +func (self *SRouteTable) GetDescription() string { + return self.Description +} + +func (self *SRouteTable) GetId() string { + return self.RouteTableId +} + +func (self *SRouteTable) GetGlobalId() string { + return self.RouteTableId +} + +func (self *SRouteTable) GetName() string { + return self.RouteTableName +} + +func (self *SRouteTable) GetRegionId() string { + return self.region.RegionId +} + +// VRouter:VPC路由器。 VBR:边界路由器。 +func (self *SRouteTable) GetType() cloudprovider.RouteTableType { + switch self.RouteTableType { + case "System": + return cloudprovider.RouteTableTypeSystem + case "Custom": + return cloudprovider.RouteTableTypeCustom + default: + return cloudprovider.RouteTableTypeSystem + } +} + +func (self *SRouteTable) GetVpcId() string { + return self.VpcId +} + +func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { + if self.routes == nil { + err := self.fetchRoutes() + if err != nil { + return nil, err + } + } + return self.routes, nil +} + +func (self *SRouteTable) GetStatus() string { + return api.ROUTE_TABLE_AVAILABLE +} + +func (self *SRouteTable) IsEmulated() bool { + return false +} + +func (self *SRouteTable) Refresh() error { + return nil +} + +func (self *SRouteTable) fetchRoutes() error { + routes := []*SRouteEntry{} + for { + parts, total, err := self.RemoteGetRoutes(len(routes), 50) + if err != nil { + return err + } + routes = append(routes, parts...) + if len(routes) >= total { + break + } + } + self.routes = make([]cloudprovider.ICloudRoute, len(routes)) + for i := 0; i < len(routes); i++ { + routes[i].routeTable = self + self.routes[i] = routes[i] + } + return nil +} + +func (self *SRouteTable) RemoteGetRoutes(offset int, limit int) ([]*SRouteEntry, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RouteTableId"] = self.RouteTableId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + body, err := self.region.ecsRequest("DescribeRouteTables", params) + if err != nil { + log.Errorf("RemoteGetRoutes fail %s", err) + return nil, 0, err + } + + resp := sDescribeRouteTablesResponse{} + err = body.Unmarshal(&resp) + if err != nil { + log.Errorf("Unmarshal routeEntrys fail %s", err) + return nil, 0, err + } + routeTables := resp.RouteTables.RouteTable + if len(routeTables) != 1 { + return nil, 0, fmt.Errorf("expecting 1 route table, got %d", len(routeTables)) + } + routeTable := routeTables[0] + return routeTable.RouteEntrys.RouteEntry, resp.TotalCount, nil +} + +func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { + result := []cloudprovider.RouteTableAssociation{} + switch self.RouterType { + case "VRouter": + for i := range self.VSwitchIds.VSwitchId { + association := cloudprovider.RouteTableAssociation{ + AssociationId: self.RouteTableId + ":" + self.VSwitchIds.VSwitchId[i], + AssociationType: cloudprovider.RouteTableAssociaToSubnet, + AssociatedResourceId: self.VSwitchIds.VSwitchId[i], + } + result = append(result, association) + } + case "VBR": + association := cloudprovider.RouteTableAssociation{ + AssociationId: self.RouteTableId + ":" + self.RouterId, + AssociationType: cloudprovider.RouteTableAssociaToRouter, + AssociatedResourceId: self.RouterId, + } + result = append(result, association) + } + + return result +} + +func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SVpc) RemoteGetRouteTableList(offset int, limit int) ([]*SRouteTable, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["VpcId"] = self.VpcId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + body, err := self.region.vpcRequest("DescribeRouteTableList", params) + if err != nil { + log.Errorf("RemoteGetRouteTableList fail %s", err) + return nil, 0, err + } + + routeTables := make([]*SRouteTable, 0) + err = body.Unmarshal(&routeTables, "RouterTableList", "RouterTableListType") + if err != nil { + log.Errorf("Unmarshal routeTables fail %s", err) + return nil, 0, err + } + for _, routeTable := range routeTables { + routeTable.region = self.region + } + total, _ := body.Int("TotalCount") + return routeTables, int(total), nil +} + +func (region *SRegion) AssociateRouteTable(rtableId string, vswitchId string) error { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["RouteTableId"] = rtableId + params["VSwitchId"] = vswitchId + _, err := region.vpcRequest("AssociateRouteTable", params) + return err +} + +func (region *SRegion) UnassociateRouteTable(rtableId string, vswitchId string) error { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["RouteTableId"] = rtableId + params["VSwitchId"] = vswitchId + _, err := region.vpcRequest("UnassociateRouteTable", params) + return err +} + +func (routeTable *SRouteTable) IsSystem() bool { + return strings.ToLower(routeTable.RouteTableType) == "system" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/saml_provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/saml_provider.go new file mode 100644 index 0000000000..e42485db93 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/saml_provider.go @@ -0,0 +1,201 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "encoding/base64" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis/cloudid" + api "yunion.io/x/cloudmux/pkg/apis/cloudid" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/httputils" + "yunion.io/x/onecloud/pkg/util/samlutils" +) + +type SAMLProvider struct { + multicloud.SResourceBase + AliyunTags + client *SAliyunClient + + Arn string + CreateDate time.Time + Description string + SAMLProviderName string + UpdateDate time.Time + + // base64 + EncodedSAMLMetadataDocument string +} + +func (self *SAMLProvider) GetName() string { + return self.SAMLProviderName +} + +func (self *SAMLProvider) GetGlobalId() string { + return self.Arn +} + +func (self *SAMLProvider) GetId() string { + return self.Arn +} + +func (self *SAMLProvider) GetAuthUrl() string { + input := samlutils.SIdpInitiatedLoginInput{ + EntityID: cloudprovider.SAML_ENTITY_ID_ALIYUN_ROLE, + IdpId: self.client.cpcfg.AccountId, + } + return httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, fmt.Sprintf("sso?%s", jsonutils.Marshal(input).QueryString())) +} + +func (self *SAMLProvider) Delete() error { + return self.client.DeleteSAMLProvider(self.SAMLProviderName) +} + +func (self *SAMLProvider) GetStatus() string { + return api.SAML_PROVIDER_STATUS_AVAILABLE +} + +func (self *SAliyunClient) ListSAMLProviders(marker string, maxItems int) ([]SAMLProvider, string, error) { + if maxItems < 1 || maxItems > 100 { + maxItems = 100 + } + params := map[string]string{ + "MaxItems": fmt.Sprintf("%d", maxItems), + } + if len(marker) > 0 { + params["Marker"] = marker + } + resp, err := self.imsRequest("ListSAMLProviders", params) + if err != nil { + return nil, "", errors.Wrapf(err, "ListSAMLProviders") + } + result := []SAMLProvider{} + err = resp.Unmarshal(&result, "SAMLProviders", "SAMLProvider") + if err != nil { + return nil, "", errors.Wrapf(err, "resp.Unmarshal") + } + marker, _ = resp.GetString("Marker") + return result, marker, nil +} + +func (self *SAliyunClient) DeleteSAMLProvider(name string) error { + params := map[string]string{ + "SAMLProviderName": name, + } + _, err := self.imsRequest("DeleteSAMLProvider", params) + if err != nil { + return errors.Wrapf(err, "DeleteSAMLProvider") + } + return nil +} + +func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { + sp, err := self.client.GetSAMLProvider(self.SAMLProviderName) + if err != nil { + return nil, errors.Wrapf(err, "GetSAMLProvider(%s)", self.SAMLProviderName) + } + metadata, err := base64.StdEncoding.DecodeString(sp.EncodedSAMLMetadataDocument) + if err != nil { + return nil, errors.Wrapf(err, "DecodeString") + } + ret, err := samlutils.ParseMetadata(metadata) + if err != nil { + return nil, errors.Wrapf(err, "ParseMetadata") + } + return &ret, nil +} + +func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { + return self.client.UpdateSAMLProvider(self.SAMLProviderName, metadata.String()) +} + +func (self *SAliyunClient) GetSAMLProvider(name string) (*SAMLProvider, error) { + params := map[string]string{ + "SAMLProviderName": name, + } + resp, err := self.imsRequest("GetSAMLProvider", params) + if err != nil { + return nil, errors.Wrapf(err, "GetSAMLProvider") + } + sp := &SAMLProvider{client: self} + err = resp.Unmarshal(sp, "SAMLProvider") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return sp, nil +} + +func (self *SAliyunClient) UpdateSAMLProvider(name string, metadata string) error { + params := map[string]string{ + "SAMLProviderName": name, + "NewEncodedSAMLMetadataDocument": base64.StdEncoding.EncodeToString([]byte(metadata)), + } + _, err := self.imsRequest("UpdateSAMLProvider", params) + if err != nil { + return errors.Wrapf(err, "GetSAMLProvider") + } + return nil +} + +func (self *SAliyunClient) CreateSAMLProvider(name, metadata, desc string) (*SAMLProvider, error) { + name = strings.ReplaceAll(name, ":", "_") + params := map[string]string{ + "EncodedSAMLMetadataDocument": base64.StdEncoding.EncodeToString([]byte(metadata)), + "SAMLProviderName": name, + } + if len(desc) > 0 { + params["Description"] = desc + } + resp, err := self.imsRequest("CreateSAMLProvider", params) + if err != nil { + return nil, errors.Wrapf(err, "CreateSAMLProvider") + } + sp := &SAMLProvider{client: self} + err = resp.Unmarshal(sp, "SAMLProvider") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return sp, nil +} + +func (self *SAliyunClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { + marker := "" + sps := []SAMLProvider{} + for { + part, _marker, err := self.ListSAMLProviders(marker, 100) + if err != nil { + return nil, errors.Wrapf(err, "ListSAMLProviders") + } + sps = append(sps, part...) + if len(_marker) == 0 { + break + } + marker = _marker + } + ret := []cloudprovider.ICloudSAMLProvider{} + for i := range sps { + sps[i].client = self + ret = append(ret, &sps[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/securitygroup.go new file mode 100644 index 0000000000..7bf7fb7f87 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/securitygroup.go @@ -0,0 +1,551 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// {"CreationTime":"2017-03-19T13:37:48Z","Description":"System created security group.","SecurityGroupId":"sg-j6cannq0xxj2r9z0yxwl","SecurityGroupName":"sg-j6cannq0xxj2r9z0yxwl","Tags":{"Tag":[]},"VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"} +// {"Description":"System created security group.","InnerAccessPolicy":"Accept","Permissions":{"Permission":[{"CreateTime":"2017-03-19T13:37:54Z","Description":"","DestCidrIp":"","DestGroupId":"","DestGroupName":"","DestGroupOwnerAccount":"","Direction":"ingress","IpProtocol":"ALL","NicType":"intranet","Policy":"Accept","PortRange":"-1/-1","Priority":110,"SourceCidrIp":"0.0.0.0/0","SourceGroupId":"","SourceGroupName":"","SourceGroupOwnerAccount":""},{"CreateTime":"2017-03-19T13:37:55Z","Description":"","DestCidrIp":"0.0.0.0/0","DestGroupId":"","DestGroupName":"","DestGroupOwnerAccount":"","Direction":"egress","IpProtocol":"ALL","NicType":"intranet","Policy":"Accept","PortRange":"-1/-1","Priority":110,"SourceCidrIp":"","SourceGroupId":"","SourceGroupName":"","SourceGroupOwnerAccount":""}]},"RegionId":"cn-hongkong","RequestId":"FBFE0950-5F2D-40DE-8C3C-E5A62AE7F7DA","SecurityGroupId":"sg-j6cannq0xxj2r9z0yxwl","SecurityGroupName":"sg-j6cannq0xxj2r9z0yxwl","VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"} + +type SecurityGroupPermissionNicType string + +const ( + IntranetNicType SecurityGroupPermissionNicType = "intranet" + InternetNicType SecurityGroupPermissionNicType = "internet" +) + +type SPermission struct { + CreateTime time.Time + Description string + DestCidrIp string + DestGroupId string + DestGroupName string + DestGroupOwnerAccount string + Direction string + IpProtocol string + NicType SecurityGroupPermissionNicType + Policy string + PortRange string + Priority int + SourceCidrIp string + SourceGroupId string + SourceGroupName string + SourceGroupOwnerAccount string +} + +type SPermissions struct { + Permission []SPermission +} + +type SSecurityGroup struct { + multicloud.SSecurityGroup + AliyunTags + + vpc *SVpc + CreationTime time.Time + Description string + SecurityGroupId string + SecurityGroupName string + VpcId string + InnerAccessPolicy string + Permissions SPermissions + RegionId string +} + +func (self *SSecurityGroup) GetVpcId() string { + return self.VpcId +} + +func (self *SSecurityGroup) GetId() string { + return self.SecurityGroupId +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.SecurityGroupId +} + +func (self *SSecurityGroup) GetDescription() string { + return self.Description +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + rules := make([]cloudprovider.SecurityRule, 0) + secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) + if err != nil { + return nil, err + } + for _, permission := range secgrp.Permissions.Permission { + rule, err := permission.toRule() + if err != nil { + log.Errorf("convert rule %s for group %s(%s) error: %v", permission.Description, self.SecurityGroupName, self.SecurityGroupId, err) + continue + } + rules = append(rules, rule) + } + return rules, nil +} + +func (self *SSecurityGroup) GetName() string { + if len(self.SecurityGroupName) > 0 { + return self.SecurityGroupName + } + return self.SecurityGroupId +} + +func (self *SSecurityGroup) GetStatus() string { + return "" +} + +func (self *SSecurityGroup) IsEmulated() bool { + return false +} + +func (self *SSecurityGroup) Refresh() error { + group, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) + if err != nil { + return err + } + return jsonutils.Update(self, group) +} + +func (self *SSecurityGroup) GetReferences() ([]cloudprovider.SecurityGroupReference, error) { + references, err := self.vpc.region.DescribeSecurityGroupReferences(self.SecurityGroupId) + if err != nil { + return nil, errors.Wrapf(err, "DescribeSecurityGroupReferences") + } + ret := []cloudprovider.SecurityGroupReference{} + for _, reference := range references { + if reference.SecurityGroupId == self.SecurityGroupId { + for _, sec := range reference.ReferencingSecurityGroups.ReferencingSecurityGroup { + ret = append(ret, cloudprovider.SecurityGroupReference{ + Id: sec.SecurityGroupId, + }) + } + } + } + return ret, nil +} + +type ReferencingSecurityGroup struct { + AliUid string + SecurityGroupId string +} + +type ReferencingSecurityGroups struct { + ReferencingSecurityGroup []ReferencingSecurityGroup +} + +type SecurityGroupReferences struct { + SecurityGroupId string + ReferencingSecurityGroups ReferencingSecurityGroups +} + +func (self *SRegion) DescribeSecurityGroupReferences(id string) ([]SecurityGroupReferences, error) { + params := map[string]string{ + "RegionId": self.RegionId, + "SecurityGroupId.1": id, + } + resp, err := self.ecsRequest("DescribeSecurityGroupReferences", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeSecurityGroupReferences") + } + ret := []SecurityGroupReferences{} + err = resp.Unmarshal(&ret, "SecurityGroupReferences", "SecurityGroupReference") + return ret, errors.Wrapf(err, "resp.Unmarshal") +} + +func (self *SRegion) GetSecurityGroups(vpcId, name string, securityGroupIds []string, offset int, limit int) ([]SSecurityGroup, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + if len(vpcId) > 0 { + params["VpcId"] = vpcId + } + if len(name) > 0 { + params["SecurityGroupName"] = name + } + + if securityGroupIds != nil && len(securityGroupIds) > 0 { + params["SecurityGroupIds"] = jsonutils.Marshal(securityGroupIds).String() + } + + body, err := self.ecsRequest("DescribeSecurityGroups", params) + if err != nil { + log.Errorf("GetSecurityGroups fail %s", err) + return nil, 0, err + } + + secgrps := make([]SSecurityGroup, 0) + err = body.Unmarshal(&secgrps, "SecurityGroups", "SecurityGroup") + if err != nil { + log.Errorf("Unmarshal security groups fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return secgrps, int(total), nil +} + +func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SecurityGroupId"] = secGroupId + + body, err := self.ecsRequest("DescribeSecurityGroupAttribute", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeSecurityGroupAttribute") + } + + secgrp := SSecurityGroup{} + err = body.Unmarshal(&secgrp) + if err != nil { + return nil, errors.Wrap(err, "body.Unmarshal") + } + return &secgrp, nil +} + +func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (string, error) { + params := make(map[string]string) + if len(vpcId) > 0 { + params["VpcId"] = vpcId + } + + if name == "Default" { + name = "Default-copy" + } + + if len(name) > 0 { + params["SecurityGroupName"] = name + } + if len(desc) > 0 { + params["Description"] = desc + } + params["ClientToken"] = utils.GenRequestId(20) + + body, err := self.ecsRequest("CreateSecurityGroup", params) + if err != nil { + return "", errors.Wrap(err, "CreateSecurityGroup") + } + return body.GetString("SecurityGroupId") +} + +func (self *SRegion) modifySecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SecurityGroupId"] = secGrpId + params["NicType"] = string(IntranetNicType) + params["Description"] = rule.Description + params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) + protocol := rule.Protocol + if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { + protocol = "all" + } + params["IpProtocol"] = protocol + if rule.PortStart < 1 && rule.PortEnd < 1 { + if protocol == "udp" || protocol == "tcp" { + params["PortRange"] = "1/65535" + } else { + params["PortRange"] = "-1/-1" + } + } + if rule.Action == secrules.SecurityRuleAllow { + params["Policy"] = "accept" + } else { + params["Policy"] = "drop" + } + params["Priority"] = fmt.Sprintf("%d", rule.Priority) + if rule.Direction == secrules.SecurityRuleIngress { + if rule.IPNet != nil { + params["SourceCidrIp"] = rule.IPNet.String() + } else { + params["SourceCidrIp"] = "0.0.0.0/0" + } + _, err := self.ecsRequest("ModifySecurityGroupRule", params) + return err + } else { // rule.Direction == secrules.SecurityRuleEgress { + //阿里云不支持出方向API接口调用 + return nil + // if rule.IPNet != nil { + // params["DestCidrIp"] = rule.IPNet.String() + // } else { + // params["DestCidrIp"] = "0.0.0.0/0" + // } + // _, err := self.ecsRequest("ModifySecurityGroupRule", params) + // return err + } +} + +func (self *SRegion) modifySecurityGroup(secGrpId string, name string, desc string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SecurityGroupId"] = secGrpId + params["SecurityGroupName"] = name + if len(desc) > 0 { + params["Description"] = desc + } + _, err := self.ecsRequest("ModifySecurityGroupAttribute", params) + return err +} + +func (self *SRegion) AddSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error { + if len(rule.Ports) != 0 { + for _, port := range rule.Ports { + rule.PortStart, rule.PortEnd = port, port + err := self.addSecurityGroupRule(secGrpId, rule) + if err != nil { + return errors.Wrapf(err, "addSecurityGroupRule %s", rule.String()) + } + } + return nil + } + return self.addSecurityGroupRule(secGrpId, rule) +} + +func (self *SRegion) addSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SecurityGroupId"] = secGrpId + params["NicType"] = string(IntranetNicType) + params["Description"] = rule.Description + params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) + protocol := rule.Protocol + if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { + protocol = "all" + } + params["IpProtocol"] = protocol + if rule.PortStart < 1 && rule.PortEnd < 1 { + if protocol == "udp" || protocol == "tcp" { + params["PortRange"] = "1/65535" + } else { + params["PortRange"] = "-1/-1" + } + } + if rule.Action == secrules.SecurityRuleAllow { + params["Policy"] = "accept" + } else { + params["Policy"] = "drop" + } + + // 忽略地址为0.0.0.0/32这样的阿里云规则 + if rule.IPNet.IP.String() == "0.0.0.0" && rule.IPNet.String() != "0.0.0.0/0" && len(rule.PeerSecgroupId) == 0 { + return nil + } + + params["Priority"] = fmt.Sprintf("%d", rule.Priority) + if rule.Direction == secrules.SecurityRuleIngress { + if len(rule.PeerSecgroupId) > 0 { + params["SourceGroupId"] = rule.PeerSecgroupId + } else if rule.IPNet != nil { + params["SourceCidrIp"] = rule.IPNet.String() + } else { + params["SourceCidrIp"] = "0.0.0.0/0" + } + _, err := self.ecsRequest("AuthorizeSecurityGroup", params) + return err + } else { // rule.Direction == secrules.SecurityRuleEgress { + if len(rule.PeerSecgroupId) > 0 { + params["DestGroupId"] = rule.PeerSecgroupId + } else if rule.IPNet != nil { + params["DestCidrIp"] = rule.IPNet.String() + } else { + params["DestCidrIp"] = "0.0.0.0/0" + } + _, err := self.ecsRequest("AuthorizeSecurityGroupEgress", params) + return err + } +} + +func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SecurityGroupId"] = secGrpId + params["NicType"] = string(IntranetNicType) + params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) + protocol := rule.Protocol + if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { + protocol = "all" + } + params["IpProtocol"] = protocol + if rule.PortStart < 1 && rule.PortEnd < 1 { + if protocol == "udp" || protocol == "tcp" { + params["PortRange"] = "1/65535" + } else { + params["PortRange"] = "-1/-1" + } + } + if rule.Action == secrules.SecurityRuleAllow { + params["Policy"] = "accept" + } else { + params["Policy"] = "drop" + } + params["Priority"] = fmt.Sprintf("%d", rule.Priority) + if rule.Direction == secrules.SecurityRuleIngress { + if len(rule.PeerSecgroupId) > 0 { + params["SourceGroupId"] = rule.PeerSecgroupId + } else if rule.IPNet != nil { + params["SourceCidrIp"] = rule.IPNet.String() + } else { + params["SourceCidrIp"] = "0.0.0.0/0" + } + _, err := self.ecsRequest("RevokeSecurityGroup", params) + return err + } else { // rule.Direction == secrules.SecurityRuleEgress { + if len(rule.PeerSecgroupId) > 0 { + params["DestGroupId"] = rule.PeerSecgroupId + } else if rule.IPNet != nil { + params["DestCidrIp"] = rule.IPNet.String() + } else { + params["DestCidrIp"] = "0.0.0.0/0" + } + _, err := self.ecsRequest("RevokeSecurityGroupEgress", params) + return err + } +} + +func (self *SPermission) toRule() (cloudprovider.SecurityRule, error) { + rule := cloudprovider.SecurityRule{ + PeerSecgroupId: self.SourceGroupId, + SecurityRule: secrules.SecurityRule{ + Action: secrules.SecurityRuleDeny, + Direction: secrules.DIR_IN, + Priority: self.Priority, + Description: self.Description, + PortStart: -1, + PortEnd: -1, + }, + } + if strings.ToLower(self.Policy) == "accept" { + rule.Action = secrules.SecurityRuleAllow + } + + cidr := self.SourceCidrIp + if self.Direction == "egress" { + rule.Direction = secrules.DIR_OUT + cidr = self.DestCidrIp + } + if len(self.SourceGroupId) > 0 || len(self.DestGroupId) > 0 { + cidr = "0.0.0.0/0" + rule.PeerSecgroupId = self.SourceGroupId + self.DestGroupId + } + + rule.ParseCIDR(cidr) + + switch strings.ToLower(self.IpProtocol) { + case "tcp", "udp", "icmp": + rule.Protocol = strings.ToLower(self.IpProtocol) + case "all": + rule.Protocol = secrules.PROTO_ANY + default: + return rule, fmt.Errorf("unsupported protocal %s", self.IpProtocol) + } + + port, ports := "", strings.Split(self.PortRange, "/") + if ports[0] == ports[1] { + if ports[0] != "-1" { + port = ports[0] + } + } else if ports[0] != "1" && ports[1] != "65535" { + port = fmt.Sprintf("%s-%s", ports[0], ports[1]) + } + err := rule.ParsePorts(port) + if err != nil { + return rule, errors.Wrapf(err, "ParsePorts(%s)", port) + } + return rule, nil +} + +func (self *SRegion) AssignSecurityGroup(secgroupId, instanceId string) error { + return self.SetSecurityGroups([]string{secgroupId}, instanceId) +} + +func (self *SRegion) SetSecurityGroups(secgroupIds []string, instanceId string) error { + params := map[string]string{"InstanceId": instanceId} + for _, secgroupId := range secgroupIds { + params["SecurityGroupId"] = secgroupId + if _, err := self.ecsRequest("JoinSecurityGroup", params); err != nil { + return err + } + } + instance, err := self.GetInstance(instanceId) + if err != nil { + return err + } + for _, _secgroupId := range instance.SecurityGroupIds.SecurityGroupId { + if !utils.IsInStringArray(_secgroupId, secgroupIds) { + if err := self.leaveSecurityGroup(_secgroupId, instanceId); err != nil { + return err + } + } + } + return nil +} + +func (self *SRegion) leaveSecurityGroup(secgroupId, instanceId string) error { + params := map[string]string{"InstanceId": instanceId, "SecurityGroupId": secgroupId} + _, err := self.ecsRequest("LeaveSecurityGroup", params) + return err +} + +func (self *SRegion) DeleteSecurityGroup(secGrpId string) error { + params := make(map[string]string) + params["SecurityGroupId"] = secGrpId + + _, err := self.ecsRequest("DeleteSecurityGroup", params) + if err != nil { + log.Errorf("Delete security group fail %s", err) + return err + } + return nil +} + +func (self *SSecurityGroup) Delete() error { + return self.vpc.region.DeleteSecurityGroup(self.SecurityGroupId) +} + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + for _, rule := range append(inDels, outDels...) { + err := self.vpc.region.DelSecurityGroupRule(self.SecurityGroupId, rule) + if err != nil { + return errors.Wrapf(err, "DelSecurityGroupRule(Name:%s priority: %d %s)", rule.Name, rule.Priority, rule.String()) + } + } + for _, rule := range append(inAdds, outAdds...) { + err := self.vpc.region.AddSecurityGroupRules(self.SecurityGroupId, rule) + if err != nil { + return errors.Wrapf(err, "AddSecurityGroupRules(priority: %d %s)", rule.Priority, rule.String()) + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/snapshot.go new file mode 100644 index 0000000000..93aea3621d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/snapshot.go @@ -0,0 +1,223 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SnapshotStatusType string + +const ( + SnapshotStatusAccomplished SnapshotStatusType = "accomplished" + SnapshotStatusProgress SnapshotStatusType = "progressing" + SnapshotStatusFailed SnapshotStatusType = "failed" + + SnapshotTypeSystem string = "System" + SnapshotTypeData string = "Data" +) + +type SSnapshot struct { + multicloud.SResourceBase + AliyunTags + region *SRegion + + Progress string + SnapshotId string + SnapshotName string + SourceDiskId string + SourceDiskSize int32 + SourceDiskType string + Status SnapshotStatusType + Usage string + ResourceGroupId string +} + +func (self *SSnapshot) GetId() string { + return self.SnapshotId +} + +func (self *SSnapshot) GetName() string { + return self.SnapshotName +} + +func (self *SSnapshot) GetStatus() string { + if self.Status == SnapshotStatusAccomplished { + return api.SNAPSHOT_READY + } else if self.Status == SnapshotStatusProgress { + return api.SNAPSHOT_CREATING + } else { // if self.Status == SnapshotStatusFailed + return api.SNAPSHOT_FAILED + } +} + +func (self *SSnapshot) GetSizeMb() int32 { + return self.SourceDiskSize * 1024 +} + +func (self *SSnapshot) GetDiskId() string { + return self.SourceDiskId +} + +func (self *SSnapshot) GetDiskType() string { + if self.SourceDiskType == SnapshotTypeSystem { + return api.DISK_TYPE_SYS + } else if self.SourceDiskType == SnapshotTypeData { + return api.DISK_TYPE_DATA + } else { + return "" + } +} + +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) GetGlobalId() string { + return fmt.Sprintf("%s", self.SnapshotId) +} + +func (self *SSnapshot) IsEmulated() bool { + return false +} + +func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, total, err := self.GetSnapshots("", "", "", []string{}, 0, 50) + if err != nil { + return nil, err + } + for len(snapshots) < total { + var parts []SSnapshot + parts, total, err = self.GetSnapshots("", "", "", []string{}, len(snapshots), 50) + if err != nil { + return nil, err + } + snapshots = append(snapshots, parts...) + } + ret := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := 0; i < len(snapshots); i += 1 { + ret[i] = &snapshots[i] + } + return ret, nil +} + +func (self *SSnapshot) Delete() error { + if self.region == nil { + return fmt.Errorf("not init region for snapshot %s", self.SnapshotId) + } + if err := self.region.SnapshotPreDelete(self.SnapshotId); err != nil { + return err + } + return self.region.DeleteSnapshot(self.SnapshotId) +} + +func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if len(instanceId) > 0 { + params["InstanceId"] = instanceId + } + if len(diskId) > 0 { + params["diskId"] = diskId + } + if len(snapshotName) > 0 { + params["SnapshotName"] = snapshotName + } + if snapshotIds != nil && len(snapshotIds) > 0 { + params["SnapshotIds"] = jsonutils.Marshal(snapshotIds).String() + } + + body, err := self.ecsRequest("DescribeSnapshots", params) + if err != nil { + log.Errorf("GetSnapshots fail %s", err) + return nil, 0, err + } + + snapshots := make([]SSnapshot, 0) + if err := body.Unmarshal(&snapshots, "Snapshots", "Snapshot"); err != nil { + log.Errorf("Unmarshal snapshot details fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + for i := 0; i < len(snapshots); i += 1 { + snapshots[i].region = self + } + return snapshots, int(total), nil +} + +func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) + if err != nil { + return nil, err + } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } else if total > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return &snapshots[0], nil +} + +func (self *SRegion) DeleteSnapshot(snapshotId string) error { + params := make(map[string]string) + params["SnapshotId"] = snapshotId + _, err := self.ecsRequest("DeleteSnapshot", params) + return err +} + +func (self *SSnapshot) GetProjectId() string { + return self.ResourceGroupId +} + +// If snapshot linked images can't be delete +// delete images first -- Aliyun +func (self *SRegion) SnapshotPreDelete(snapshotId string) error { + images, _, err := self.GetImagesBySnapshot(snapshotId, 0, 0) + if err != nil { + return fmt.Errorf("PreDelete get images by snapshot %s error: %s", snapshotId, err) + } + for _, image := range images { + image.storageCache = &SStoragecache{region: self} + if err := image.Delete(context.Background()); err != nil { + return fmt.Errorf("PreDelete image %s error: %s", image.GetId(), err) + } + if err := cloudprovider.WaitDeleted(&image, 3*time.Second, 300*time.Second); err != nil { + return fmt.Errorf("PreDelete waite image %s deleted error: %s", image.GetId(), err) + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/snapshot_policy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/snapshot_policy.go new file mode 100644 index 0000000000..393e6b36d9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/snapshot_policy.go @@ -0,0 +1,303 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "sort" + "strconv" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSnapshotPolicyType string + +const ( + Creating SSnapshotPolicyType = "Creating" + Available SSnapshotPolicyType = "Available" + Normal SSnapshotPolicyType = "Normal" +) + +type SSnapshotPolicy struct { + multicloud.SResourceBase + AliyunTags + region *SRegion + + AutoSnapshotPolicyName string + AutoSnapshotPolicyId string + RepeatWeekdays string + TimePoints string + RetentionDays int + Status SSnapshotPolicyType +} + +func (self *SSnapshotPolicy) GetId() string { + return self.AutoSnapshotPolicyId +} + +func (self *SSnapshotPolicy) GetName() string { + return self.AutoSnapshotPolicyName +} + +func (self *SSnapshotPolicy) GetStatus() string { + // XXX: aliyun文档与实际返回值不符 + if self.Status == Normal || self.Status == Available { + return api.SNAPSHOT_POLICY_READY + } else if self.Status == Creating { + return api.SNAPSHOT_POLICY_CREATING + } else { + return api.SNAPSHOT_POLICY_UNKNOWN + } +} + +func (self *SSnapshotPolicy) Refresh() error { + if snapshotPolicies, total, err := self.region.GetSnapshotPolicies(self.AutoSnapshotPolicyId, 0, 1); err != nil { + return err + } else if total != 1 { + return cloudprovider.ErrNotFound + } else if err := jsonutils.Update(self, snapshotPolicies[0]); err != nil { + return err + } + return nil +} + +func (self *SSnapshotPolicy) IsEmulated() bool { + return false +} + +func (self *SSnapshotPolicy) GetGlobalId() string { + return self.AutoSnapshotPolicyId +} + +func (self *SSnapshotPolicy) GetProjectId() string { + return "" +} + +func (self *SSnapshotPolicy) GetRetentionDays() int { + return self.RetentionDays +} + +func sliceAtoi(sa []string) ([]int, error) { + si := make([]int, 0, len(sa)) + for _, a := range sa { + i, err := strconv.Atoi(a) + if err != nil { + return si, err + } + si = append(si, i) + } + return si, nil +} + +func stringToIntDays(days []string) ([]int, error) { + idays, err := sliceAtoi(days) + if err != nil { + return nil, err + } + sort.Ints(idays) + return idays, nil +} + +func parsePolicy(policy string) ([]int, error) { + tp, err := jsonutils.ParseString(policy) + if err != nil { + return nil, fmt.Errorf("Parse policy %s error %s", policy, err) + } + atp, ok := tp.(*jsonutils.JSONArray) + if !ok { + return nil, fmt.Errorf("Policy %s Wrong format", tp) + } + return stringToIntDays(atp.GetStringArray()) +} + +func (self *SSnapshotPolicy) GetRepeatWeekdays() ([]int, error) { + return parsePolicy(self.RepeatWeekdays) +} + +func (self *SSnapshotPolicy) GetTimePoints() ([]int, error) { + return parsePolicy(self.TimePoints) +} + +func (self *SSnapshotPolicy) IsActivated() bool { + return true +} + +func (self *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { + snapshotPolicies, total, err := self.GetSnapshotPolicies("", 0, 50) + if err != nil { + return nil, err + } + for len(snapshotPolicies) < total { + var parts []SSnapshotPolicy + parts, total, err = self.GetSnapshotPolicies("", len(snapshotPolicies), 50) + if err != nil { + return nil, err + } + snapshotPolicies = append(snapshotPolicies, parts...) + } + ret := make([]cloudprovider.ICloudSnapshotPolicy, len(snapshotPolicies)) + for i := 0; i < len(snapshotPolicies); i += 1 { + ret[i] = &snapshotPolicies[i] + } + return ret, nil +} + +func (self *SRegion) GetSnapshotPolicies(policyId string, offset int, limit int) ([]SSnapshotPolicy, int, error) { + params := make(map[string]string) + + params["RegionId"] = self.RegionId + if limit != 0 { + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + } + + if len(policyId) > 0 { + params["AutoSnapshotPolicyId"] = policyId + } + + body, err := self.ecsRequest("DescribeAutoSnapshotPolicyEx", params) + if err != nil { + return nil, 0, fmt.Errorf("GetSnapshotPolicys fail %s", err) + } + + snapshotPolicies := make([]SSnapshotPolicy, 0) + if err := body.Unmarshal(&snapshotPolicies, "AutoSnapshotPolicies", "AutoSnapshotPolicy"); err != nil { + return nil, 0, fmt.Errorf("Unmarshal snapshot policies details fail %s", err) + } + total, _ := body.Int("TotalCount") + for i := 0; i < len(snapshotPolicies); i += 1 { + snapshotPolicies[i].region = self + } + return snapshotPolicies, int(total), nil +} + +func (self *SSnapshotPolicy) Delete() error { + if self.region == nil { + return fmt.Errorf("Not init region for snapshotPolicy %s", self.AutoSnapshotPolicyId) + } + return self.region.DeleteSnapshotPolicy(self.AutoSnapshotPolicyId) +} + +func (self *SRegion) DeleteSnapshotPolicy(snapshotPolicyId string) error { + params := make(map[string]string) + params["autoSnapshotPolicyId"] = snapshotPolicyId + params["regionId"] = self.RegionId + _, err := self.ecsRequest("DeleteAutoSnapshotPolicy", params) + return err +} + +func (self *SRegion) GetISnapshotPolicyById(snapshotPolicyId string) (cloudprovider.ICloudSnapshotPolicy, error) { + policies, _, err := self.GetSnapshotPolicies(snapshotPolicyId, 0, 1) + if err != nil { + return nil, err + } + if len(policies) == 0 { + return nil, cloudprovider.ErrNotFound + } + return &policies[0], nil +} + +func (self *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput) (string, error) { + if input.RepeatWeekdays == nil { + return "", fmt.Errorf("Can't create snapshot policy with nil repeatWeekdays") + } + if input.TimePoints == nil { + return "", fmt.Errorf("Can't create snapshot policy with nil timePoints") + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["repeatWeekdays"] = jsonutils.Marshal(input.GetStringArrayRepeatWeekdays()).String() + params["timePoints"] = jsonutils.Marshal(input.GetStringArrayTimePoints()).String() + params["retentionDays"] = strconv.Itoa(input.RetentionDays) + params["autoSnapshotPolicyName"] = input.PolicyName + if body, err := self.ecsRequest("CreateAutoSnapshotPolicy", params); err != nil { + return "", fmt.Errorf("CreateAutoSnapshotPolicy fail %s", err) + } else { + return body.GetString("AutoSnapshotPolicyId") + } +} + +func (self *SRegion) UpdateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput, snapshotPolicyId string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + if input.RetentionDays != 0 { + params["retentionDays"] = strconv.Itoa(input.RetentionDays) + } + if input.RepeatWeekdays != nil && len(input.RepeatWeekdays) != 0 { + params["repeatWeekdays"] = jsonutils.Marshal(input.GetStringArrayRepeatWeekdays()).String() + } + if input.TimePoints != nil && len(input.TimePoints) != 0 { + params["timePoints"] = jsonutils.Marshal(input.GetStringArrayTimePoints()).String() + } + _, err := self.ecsRequest("ModifyAutoSnapshotPolicyEx", params) + if err != nil { + return fmt.Errorf("ModifyAutoSnapshotPolicyEx Fail %s", err) + } + return nil +} + +//func (self *SRegion) UpdateSnapshotPolicy( +// snapshotPolicyId string, retentionDays *int, +// repeatWeekdays, timePoints *jsonutils.JSONArray, policyName string, +//) error { +// params := make(map[string]string) +// params["RegionId"] = self.RegionId +// if len(policyName) > 0 { +// params["autoSnapshotPolicyName"] = policyName +// } +// if retentionDays != nil { +// params["retentionDays"] = strconv.Itoa(*retentionDays) +// } +// if repeatWeekdays != nil { +// params["repeatWeekdays"] = repeatWeekdays.String() +// } +// if timePoints != nil { +// params["timePoints"] = timePoints.String() +// } +// _, err := self.ecsRequest("ModifyAutoSnapshotPolicyEx", params) +// if err != nil { +// return fmt.Errorf("ModifyAutoSnapshotPolicyEx Fail %s", err) +// } +// return nil +//} + +func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["autoSnapshotPolicyId"] = snapshotPolicyId + diskIds := []string{diskId} + params["diskIds"] = jsonutils.Marshal(diskIds).String() + _, err := self.ecsRequest("ApplyAutoSnapshotPolicy", params) + if err != nil { + return fmt.Errorf("ApplyAutoSnapshotPolicy Fail %s", err) + } + return nil +} + +func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + diskIds := []string{diskId} + params["diskIds"] = jsonutils.Marshal(diskIds).String() + _, err := self.ecsRequest("CancelAutoSnapshotPolicy", params) + if err != nil { + return fmt.Errorf("CancelAutoSnapshotPolicy Fail %s", err) + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/storage.go new file mode 100644 index 0000000000..b49fcad821 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/storage.go @@ -0,0 +1,191 @@ +// Copyright 2019 Yunion +// +// 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. + +// +// 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 aliyun + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStorage struct { + multicloud.SStorageBase + AliyunTags + zone *SZone + storageType string +} + +func (self *SStorage) GetId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetName() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetGlobalId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) +} + +func (self *SStorage) IsEmulated() bool { + return true +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks := make([]SDisk, 0) + offset := 0 + storageType := self.storageType + if self.storageType == api.STORAGE_CLOUD_ESSD_PL2 || self.storageType == api.STORAGE_CLOUD_ESSD_PL3 { + storageType = api.STORAGE_CLOUD_ESSD + } + for { + parts, total, err := self.zone.region.GetDisks("", self.zone.GetId(), storageType, nil, offset, 50) + if err != nil { + return nil, errors.Wrapf(err, "GetDisks") + } + performanceLevel := "" + switch self.storageType { + case api.STORAGE_CLOUD_ESSD: + performanceLevel = "PL1" + case api.STORAGE_CLOUD_ESSD_PL2: + performanceLevel = "PL2" + case api.STORAGE_CLOUD_ESSD_PL3: + performanceLevel = "PL3" + } + for _, disk := range parts { + if disk.PerformanceLevel == performanceLevel { + disks = append(disks, disk) + } + } + + offset += len(parts) + + if offset >= 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 models.STORAGE_PUBLIC_CLOUD + return self.storageType +} + +func (self *SStorage) GetMediumType() string { + if strings.Contains(self.storageType, "_ssd") { + return api.DISK_TYPE_SSD + } else { + return api.DISK_TYPE_ROTATE + } +} + +func (self *SStorage) GetCapacityMB() int64 { + return 0 // unlimited +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + return conf +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) Refresh() error { + // do nothing + return nil +} + +func (self *SStorage) GetEnabled() bool { + if utils.IsInStringArray(self.storageType, LOCAL_STORAGES) { + return false + } + return true +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.zone.region.getStoragecache() +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + diskId, err := self.zone.region.CreateDisk(self.zone.ZoneId, self.storageType, conf.Name, conf.SizeGb, conf.Desc, conf.ProjectId) + 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) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + disk, err := self.zone.region.getDisk(idStr) + if err != nil { + return nil, err + } + disk.storage = self + return disk, nil +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + if utils.IsInStringArray(self.storageType, self.zone.getSysDiskCategories()) { + return true + } + return false +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/storagecache.go new file mode 100644 index 0000000000..e328daf501 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/storagecache.go @@ -0,0 +1,355 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "context" + "fmt" + "io/ioutil" + "os" + "strings" + "time" + + "github.com/aliyun/aliyun-oss-go-sdk/oss" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +type SStoragecache struct { + multicloud.SResourceBase + AliyunTags + region *SRegion +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) +} + +func (self *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) Refresh() error { + return nil +} + +func (self *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetGlobalId()) +} + +func (self *SStoragecache) IsEmulated() bool { + return false +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + images := make([]SImage, 0) + for { + parts, total, err := self.region.GetImages(ImageStatusType(""), ImageOwnerSelf, nil, "", len(images), 50) + if err != nil { + return nil, errors.Wrapf(err, "GetImages") + } + images = append(images, parts...) + if len(images) >= total { + break + } + } + ret := []cloudprovider.ICloudImage{} + for i := range images { + images[i].storageCache = self + ret = append(ret, &images[i]) + } + return ret, nil +} + +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + img, err := self.region.GetImage(extId) + if err != nil { + return nil, err + } + img.storageCache = self + return img, nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { + if len(image.ExternalId) > 0 { + status, err := self.region.GetImageStatus(image.ExternalId) + if err != nil { + log.Errorf("GetImageStatus error %s", err) + } + // 不能直接删除 ImageStatusCreating 状态的image ,需要先取消importImage Task + if status == ImageStatusCreating { + err := self.region.CancelImageImportTasks() + if err != nil { + log.Errorln(err) + } + } + } + return self.uploadImage(ctx, userCred, image, callback) +} + +func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { + // first upload image to oss + s := auth.GetAdminSession(ctx, options.Options.Region) + + meta, reader, sizeByte, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false) + if err != nil { + return "", err + } + log.Infof("meta data %s", meta) + + bucketName := strings.ToLower(fmt.Sprintf("imgcache-%s-%s", self.region.GetId(), image.ImageId)) + exist, err := self.region.IBucketExist(bucketName) + if err != nil { + return "", errors.Wrapf(err, "IBucketExist(%s)", bucketName) + } + if !exist { + log.Debugf("Bucket %s not exists, to create ...", bucketName) + err = self.region.CreateIBucket(bucketName, "", "") + if err != nil { + return "", errors.Wrapf(err, "CreateIBucket %s", bucketName) + } + } else { + log.Debugf("Bucket %s exists", bucketName) + } + + defer self.region.DeleteIBucket(bucketName) // remove bucket + + bucket, err := self.region.GetIBucketByName(bucketName) + if err != nil { + return "", errors.Wrapf(err, "GetIBucketByName %s", bucketName) + } + log.Debugf("To upload image to bucket %s ...", bucketName) + body := multicloud.NewProgress(sizeByte, 80, reader, callback) + err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeByte, "", "", nil, false) + if err != nil { + return "", errors.Wrapf(err, "UploadObject %s", image.ImageId) + } + + defer bucket.DeleteObject(context.Background(), image.ImageId) // remove object + + imageBaseName := image.ImageId + if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { + imageBaseName = fmt.Sprintf("img%s", image.ImageId) + } + imageName := imageBaseName + nameIdx := 1 + + // check image name, avoid name conflict + for { + _, err = self.region.GetImageByName(imageName) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + break + } else { + return "", err + } + } + imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) + nameIdx += 1 + } + + log.Debugf("Import image %s", imageName) + + // ensure privileges + err = self.region.GetClient().EnableImageImport() + if err != nil { + return "", errors.Wrapf(err, "EnableImageImport") + } + + task, err := self.region.ImportImage(imageName, image.OsArch, image.OsType, image.OsDistribution, bucketName, image.ImageId) + + if err != nil { + return "", errors.Wrapf(err, "ImportImage %s %s", image.ImageId, bucketName) + } + + // timeout: 1hour = 3600 seconds + err = self.region.WaitTaskStatus(ImportImageTask, task.TaskId, TaskStatusFinished, 15*time.Second, 3600*time.Second, 80, 100, callback) + if err != nil { + return task.ImageId, errors.Wrapf(err, "waitTaskStatus") + } + + return task.ImageId, nil +} + +func (self *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + if imageId, err := self.region.createIImage(snapshoutId, 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 + if err := cloudprovider.WaitStatus(iimage[0], cloudprovider.IMAGE_STATUS_ACTIVE, 15*time.Second, 3600*time.Second); err != nil { + return nil, err + } + return iimage[0], nil + } +} + +func (self *SRegion) CheckBucket(bucketName string) (*oss.Bucket, error) { + return self.checkBucket(bucketName) +} + +func (self *SRegion) checkBucket(bucketName string) (*oss.Bucket, error) { + oss, err := self.GetOssClient() + if err != nil { + log.Errorf("GetOssClient err %s", err) + return nil, err + } + if exist, err := oss.IsBucketExist(bucketName); err != nil { + log.Errorf("IsBucketExist err %s", err) + return nil, err + } else if !exist { + log.Debugf("Bucket %s not exists, to create ...", bucketName) + if err := oss.CreateBucket(bucketName); err != nil { + log.Errorf("Create bucket error %s", err) + return nil, err + } + } + log.Debugf("Bucket %s exists", bucketName) + if bucket, err := oss.Bucket(bucketName); err != nil { + log.Errorf("Bucket error %s %s", bucketName, err) + return nil, err + } else { + return bucket, nil + } +} + +func (self *SRegion) CreateImage(snapshoutId, imageName, imageDesc string) (string, error) { + return self.createIImage(snapshoutId, imageName, imageDesc) +} + +func (self *SRegion) createIImage(snapshoutId, imageName, imageDesc string) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["OssBucket"] = strings.ToLower(fmt.Sprintf("imgcache-%s", self.GetId())) + params["SnapshotId"] = snapshoutId + params["ImageName"] = imageName + params["Description"] = imageDesc + + if _, err := self.checkBucket(params["OssBucket"]); err != nil { + return "", err + } + + if body, err := self.ecsRequest("CreateImage", params); err != nil { + log.Errorf("CreateImage fail %s", err) + return "", err + } else { + log.Infof("%s", body) + return body.GetString("ImageId") + } +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return self.downloadImage(userCred, imageId, extId, path) +} + +// 定义进度条监听器。 +type OssProgressListener struct { +} + +// 定义进度变更事件处理函数。 +func (listener *OssProgressListener) ProgressChanged(event *oss.ProgressEvent) { + switch event.EventType { + case oss.TransferStartedEvent: + log.Debugf("Transfer Started, ConsumedBytes: %d, TotalBytes %d.\n", + event.ConsumedBytes, event.TotalBytes) + case oss.TransferDataEvent: + log.Debugf("\rTransfer Data, ConsumedBytes: %d, TotalBytes %d, %d%%.", + event.ConsumedBytes, event.TotalBytes, event.ConsumedBytes*100/event.TotalBytes) + case oss.TransferCompletedEvent: + log.Debugf("\nTransfer Completed, ConsumedBytes: %d, TotalBytes %d.\n", + event.ConsumedBytes, event.TotalBytes) + case oss.TransferFailedEvent: + log.Debugf("\nTransfer Failed, ConsumedBytes: %d, TotalBytes %d.\n", + event.ConsumedBytes, event.TotalBytes) + default: + } +} + +func (self *SStoragecache) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + err := self.region.GetClient().EnableImageExport() + if err != nil { + log.Errorf("fail to enable export privileges: %s", err) + return nil, err + } + + tmpImageFile, err := ioutil.TempFile(path, extId) + if err != nil { + return nil, err + } + defer tmpImageFile.Close() + defer os.Remove(tmpImageFile.Name()) + bucketName := strings.ToLower(fmt.Sprintf("imgcache-%s", self.region.GetId())) + if bucket, err := self.region.checkBucket(bucketName); err != nil { + return nil, err + } else if _, err := self.region.GetImage(extId); err != nil { + return nil, err + } else if task, err := self.region.ExportImage(extId, bucket); err != nil { + return nil, err + } else if err := self.region.waitTaskStatus(ExportImageTask, task.TaskId, TaskStatusFinished, 15*time.Second, 3600*time.Second); err != nil { + return nil, err + } else if imageList, err := bucket.ListObjects(oss.Prefix(fmt.Sprintf("%sexport", strings.Replace(extId, "-", "", -1)))); err != nil { + return nil, err + } else if len(imageList.Objects) != 1 { + return nil, fmt.Errorf("exported image not find") + } else if err := bucket.DownloadFile(imageList.Objects[0].Key, tmpImageFile.Name(), 12*1024*1024, oss.Routines(3), oss.Progress(&OssProgressListener{})); err != nil { + return nil, err + } else { + s := auth.GetAdminSession(context.Background(), options.Options.Region) + params := jsonutils.Marshal(map[string]string{"image_id": imageId, "disk-format": "raw"}) + if result, err := modules.Images.Upload(s, params, tmpImageFile, imageList.Objects[0].Size); err != nil { + return nil, err + } else { + return result, nil + } + } +} + +func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storageCache := region.getStoragecache() + return []cloudprovider.ICloudStoragecache{storageCache}, nil +} + +func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + storageCache := region.getStoragecache() + if id == storageCache.GetGlobalId() { + return storageCache, nil + } + return nil, cloudprovider.ErrNotFound +} diff --git a/pkg/multicloud/aliyun/sts.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/sts.go similarity index 100% rename from pkg/multicloud/aliyun/sts.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/sts.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/tablestore.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/tablestore.go new file mode 100644 index 0000000000..c6596f83bc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/tablestore.go @@ -0,0 +1,107 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +func (self *SAliyunClient) otsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + cli, err := self.getDefaultClient() + if err != nil { + return nil, err + } + regionId, _ := params["RegionId"] + params = self.SetResourceGropuId(params) + return jsonRequest(cli, fmt.Sprintf("ots.%s.aliyuncs.com", regionId), ALIYUN_OTS_API_VERSION, apiName, params, self.debug) +} + +func (self *SRegion) otsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["RegionId"] = self.RegionId + return self.client.otsRequest(apiName, params) +} + +type STablestore struct { + multicloud.SResourceBase + AliyunTags + region *SRegion + + InstanceName string + Timestamp time.Time +} + +func (self *STablestore) GetGlobalId() string { + return self.InstanceName +} + +func (self *STablestore) GetName() string { + return self.InstanceName +} + +func (self *STablestore) GetId() string { + return self.InstanceName +} + +func (self *STablestore) GetStatus() string { + return api.TABLESTORE_STATUS_RUNNING +} + +func (self *STablestore) GetProjectId() string { + return "" +} + +func (self *SRegion) GetTablestoreInstances(pageSize, pageNumber int) ([]STablestore, int, error) { + params := map[string]string{ + "RegionId": self.RegionId, + "PageSize": fmt.Sprintf("%d", pageSize), + "PageNumber": fmt.Sprintf("%d", pageNumber), + } + resp, err := self.otsRequest("ListInstance", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "ListInstance") + } + total, _ := resp.Int("TotalCount") + ret := []STablestore{} + return ret, int(total), resp.Unmarshal(&ret, "InstanceInfos", "InstanceInfo") +} + +func (self *SRegion) GetICloudTablestores() ([]cloudprovider.ICloudTablestore, error) { + ots, pageNumber := []STablestore{}, 1 + for { + part, total, err := self.GetTablestoreInstances(50, pageNumber) + if err != nil { + return nil, err + } + ots = append(ots, part...) + if len(ots) >= total { + break + } + pageNumber++ + } + ret := []cloudprovider.ICloudTablestore{} + for i := range ots { + ots[i].region = self + ret = append(ret, &ots[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/tag_base.go new file mode 100644 index 0000000000..4dfae45055 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/tag_base.go @@ -0,0 +1,78 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type AliyunTags struct { + Tags struct { + Tag []multicloud.STag + + // Kafka + TagVO []multicloud.STag `json:"TagVO" yunion-deprecated-by:"Tag"` + } +} + +func (self *AliyunTags) GetTags() (map[string]string, error) { + ret := map[string]string{} + for _, tag := range self.Tags.Tag { + if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") || + strings.HasSuffix(tag.Key, "aliyun") || strings.HasPrefix(tag.Key, "acs:") || + strings.HasSuffix(tag.Key, "ack.aliyun.com") { // k8s + continue + } + if len(tag.TagKey) > 0 { + ret[tag.TagKey] = tag.TagValue + } else if len(tag.Key) > 0 { + ret[tag.Key] = tag.Value + } + } + + return ret, nil +} + +func (self *AliyunTags) GetSysTags() map[string]string { + ret := map[string]string{} + for _, tag := range self.Tags.Tag { + if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") || + strings.HasPrefix(tag.Key, "aliyun") || strings.HasPrefix(tag.Key, "acs:") || + strings.HasPrefix(tag.Key, "ack.aliyun.com") { // k8s + if len(tag.TagKey) > 0 { + ret[tag.TagKey] = tag.TagValue + } else if len(tag.Key) > 0 { + ret[tag.Key] = tag.Value + } + } + } + return ret +} + +func (self *AliyunTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} + +type SAliyunTag struct { + ResourceId string + ResourceType string + TagKey string + TagValue string +} diff --git a/pkg/multicloud/aliyun/task.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/task.go similarity index 100% rename from pkg/multicloud/aliyun/task.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/task.go diff --git a/pkg/multicloud/aliyun/utils.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/utils.go similarity index 100% rename from pkg/multicloud/aliyun/utils.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/utils.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/vpc.go new file mode 100644 index 0000000000..6767872584 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/vpc.go @@ -0,0 +1,333 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + VpcAvailable = "Available" + VpcPending = "Pending" +) + +// "CidrBlock":"172.31.0.0/16","CreationTime":"2017-03-19T13:37:40Z","Description":"System created default VPC.","IsDefault":true,"RegionId":"cn-hongkong","Status":"Available","UserCidrs":{"UserCidr":[]},"VRouterId":"vrt-j6c00qrol733dg36iq4qj","VSwitchIds":{"VSwitchId":["vsw-j6c3gig5ub4fmi2veyrus"]},"VpcId":"vpc-j6c86z3sh8ufhgsxwme0q","VpcName":"" + +type SUserCIDRs struct { + UserCidr []string +} + +type SVSwitchIds struct { + VSwitchId []string +} + +type SVpc struct { + multicloud.SVpc + AliyunTags + + region *SRegion + + iwires []cloudprovider.ICloudWire + + secgroups []cloudprovider.ICloudSecurityGroup + routeTables []cloudprovider.ICloudRouteTable + + CidrBlock string + CreationTime time.Time + Description string + IsDefault bool + RegionId string + Status string + UserCidrs SUserCIDRs + VRouterId string + VSwitchIds SVSwitchIds + VpcId string + VpcName string +} + +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) IsEmulated() bool { + return false +} + +func (self *SVpc) GetIsDefault() bool { + return self.IsDefault +} + +func (self *SVpc) GetCidrBlock() string { + return self.CidrBlock +} + +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) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +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) 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 + } + } + return nil +} + +func (self *SVpc) fetchVSwitches() error { + switches, total, err := self.region.GetVSwitches(nil, self.VpcId, 0, 50) + if err != nil { + return err + } + if total > len(switches) { + switches, _, err = self.region.GetVSwitches(nil, self.VpcId, 0, total) + if err != nil { + return err + } + } + for i := 0; i < len(switches); i += 1 { + wire := self.getWireByZoneId(switches[i].ZoneId) + if wire != nil { + switches[i].wire = wire + wire.addNetwork(&switches[i]) + } + } + return nil +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + if self.iwires == nil { + err := self.fetchVSwitches() + if err != nil { + return nil, err + } + } + return self.iwires, nil +} + +func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { + if self.iwires == nil { + err := self.fetchVSwitches() + 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) fetchSecurityGroups() error { + secgroups := make([]SSecurityGroup, 0) + for { + parts, total, err := self.region.GetSecurityGroups(self.VpcId, "", []string{}, len(secgroups), 50) + if err != nil { + return err + } + secgroups = append(secgroups, parts...) + if len(secgroups) >= total { + break + } + } + 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 *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) fetchRouteTables() error { + routeTables := make([]*SRouteTable, 0) + for { + parts, total, err := self.RemoteGetRouteTableList(len(routeTables), 50) + if err != nil { + return err + } + routeTables = append(routeTables, parts...) + if len(routeTables) >= total { + break + } + } + self.routeTables = make([]cloudprovider.ICloudRouteTable, len(routeTables)) + for i := 0; i < len(routeTables); i++ { + routeTables[i].vpc = self + self.routeTables[i] = routeTables[i] + } + return nil +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + if self.routeTables == nil { + err := self.fetchRouteTables() + if err != nil { + return nil, err + } + } + return self.routeTables, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + tables, err := self.GetIRouteTables() + if err != nil { + return nil, errors.Wrapf(err, "GetIRouteTables") + } + for i := range tables { + if tables[i].GetGlobalId() == routeTableId { + return tables[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, routeTableId) +} + +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) getNatGateways() ([]SNatGateway, error) { + natgatways := make([]SNatGateway, 0) + gwTotal := -1 + for gwTotal < 0 || len(natgatways) < gwTotal { + parts, total, err := self.region.GetNatGateways(self.VpcId, "", len(natgatways), 50) + if err != nil { + return nil, err + } + if len(parts) > 0 { + natgatways = append(natgatways, parts...) + } + gwTotal = total + } + for i := 0; i < len(natgatways); i += 1 { + natgatways[i].vpc = self + } + return natgatways, nil +} + +func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { + nats := []SNatGateway{} + for { + parts, total, err := self.region.GetNatGateways(self.VpcId, "", len(nats), 50) + if err != nil { + return nil, err + } + nats = append(nats, parts...) + if len(nats) >= total { + break + } + } + inats := []cloudprovider.ICloudNatGateway{} + for i := 0; i < len(nats); i++ { + nats[i].vpc = self + inats = append(inats, &nats[i]) + } + return inats, nil +} + +func (self *SVpc) GetAuthorityOwnerId() string { + return self.region.client.ownerId +} + +func (self *SRegion) GrantInstanceToCen(opts *cloudprovider.SVpcJointInterVpcNetworkOption, instance SCenAttachInstanceInput) error { + params := make(map[string]string) + params["CenId"] = opts.InterVpcNetworkId + params["CenOwnerId"] = opts.NetworkAuthorityOwnerId + + params["InstanceId"] = instance.InstanceId + params["InstanceType"] = instance.InstanceType + params["RegionId"] = instance.InstanceRegion + _, err := self.vpcRequest("GrantInstanceToCen", params) + if err != nil { + return errors.Wrapf(err, `self.vpcRequest("GrantInstanceToCen", %s)`, jsonutils.Marshal(params).String()) + } + return nil +} + +func (self *SVpc) ProposeJoinICloudInterVpcNetwork(opts *cloudprovider.SVpcJointInterVpcNetworkOption) error { + instance := SCenAttachInstanceInput{ + InstanceType: "VPC", + InstanceId: self.GetId(), + InstanceRegion: self.region.GetId(), + } + err := self.region.GrantInstanceToCen(opts, instance) + if err != nil { + return errors.Wrapf(err, "self.region.GrantInstanceToCen(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) + } + return nil +} diff --git a/pkg/multicloud/aliyun/vrouter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/vrouter.go similarity index 100% rename from pkg/multicloud/aliyun/vrouter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/vrouter.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/vswitch.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/vswitch.go new file mode 100644 index 0000000000..7797438672 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/vswitch.go @@ -0,0 +1,276 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/util/netutils" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +// {"AvailableIpAddressCount":4091,"CidrBlock":"172.31.32.0/20","CreationTime":"2017-03-19T13:37:44Z","Description":"System created default virtual switch.","IsDefault":true,"Status":"Available","VSwitchId":"vsw-j6c3gig5ub4fmi2veyrus","VSwitchName":"","VpcId":"vpc-j6c86z3sh8ufhgsxwme0q","ZoneId":"cn-hongkong-b"} + +const ( + VSwitchPending = "Pending" + VSwitchAvailable = "Available" +) + +type SCloudResources struct { + CloudResourceSetType []string +} + +type SVSwitch struct { + multicloud.SResourceBase + AliyunTags + wire *SWire + + AvailableIpAddressCount int + + CidrBlock string + Ipv6CidrBlock string + CreationTime time.Time + Description string + IsDefault bool + Status string + VSwitchId string + VSwitchName string + VpcId string + ZoneId string + + CloudResources SCloudResources + ResourceGroupId string + RouteTable SRouteTable +} + +func (self *SVSwitch) GetId() string { + return self.VSwitchId +} + +func (self *SVSwitch) GetName() string { + if len(self.VSwitchName) > 0 { + return self.VSwitchName + } + return self.VSwitchId +} + +func (self *SVSwitch) GetGlobalId() string { + return self.VSwitchId +} + +func (self *SVSwitch) IsEmulated() bool { + return false +} + +func (self *SVSwitch) GetStatus() string { + return strings.ToLower(self.Status) +} + +func (self *SVSwitch) Refresh() error { + log.Debugf("vsiwtch refresh %s", self.VSwitchId) + new, err := self.wire.zone.region.GetVSwitchAttributes(self.VSwitchId) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SVSwitch) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SVSwitch) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String() +} + +func (self *SVSwitch) 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 *SVSwitch) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + return pref.MaskLen +} + +func (self *SVSwitch) GetGateway() string { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + return endIp.String() +} + +func (self *SVSwitch) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SVSwitch) GetIsPublic() bool { + // return self.IsDefault + return true +} + +func (self *SVSwitch) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SRegion) createVSwitch(zoneId string, vpcId string, name string, cidr string, desc string) (string, error) { + params := make(map[string]string) + params["ZoneId"] = zoneId + params["VpcId"] = vpcId + params["CidrBlock"] = cidr + params["VSwitchName"] = name + if len(desc) > 0 { + params["Description"] = desc + } + params["ClientToken"] = utils.GenRequestId(20) + + body, err := self.vpcRequest("CreateVSwitch", params) + if err != nil { + return "", err + } + return body.GetString("VSwitchId") +} + +func (self *SRegion) DeleteVSwitch(vswitchId string) error { + params := make(map[string]string) + params["VSwitchId"] = vswitchId + + _, err := self.vpcRequest("DeleteVSwitch", params) + return err +} + +func (self *SVSwitch) Delete() error { + err := self.Refresh() + if err != nil { + log.Errorf("refresh vswitch fail %s", err) + return err + } + if len(self.RouteTable.RouteTableId) > 0 && !self.RouteTable.IsSystem() { + err = self.wire.zone.region.UnassociateRouteTable(self.RouteTable.RouteTableId, self.VSwitchId) + if err != nil { + log.Errorf("unassociate routetable fail %s", err) + return err + } + } + err = self.dissociateWithSNAT() + if err != nil { + log.Errorf("fail to dissociateWithSNAT") + return err + } + err = cloudprovider.Wait(10*time.Second, 60*time.Second, func() (bool, error) { + err := self.wire.zone.region.DeleteVSwitch(self.VSwitchId) + if err != nil { + // delete network immediately after deleting vm on it + // \"Code\":\"DependencyViolation\",\"Message\":\"Specified object has dependent resources.\"} + if isError(err, "DependencyViolation") { + return false, nil + } + return false, err + } else { + return true, nil + } + }) + return err +} + +func (self *SVSwitch) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (self *SRegion) GetVSwitches(ids []string, vpcId string, offset int, limit int) ([]SVSwitch, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + if ids != nil && len(ids) > 0 { + params["VSwitchId"] = strings.Join(ids, ",") + } + if len(vpcId) > 0 { + params["VpcId"] = vpcId + } + + body, err := self.vpcRequest("DescribeVSwitches", params) + if err != nil { + log.Errorf("GetVSwitches fail %s", err) + return nil, 0, err + } + + switches := make([]SVSwitch, 0) + err = body.Unmarshal(&switches, "VSwitches", "VSwitch") + if err != nil { + log.Errorf("Unmarshal vswitches fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return switches, int(total), nil +} + +func (self *SRegion) GetVSwitchAttributes(idstr string) (*SVSwitch, error) { + params := make(map[string]string) + params["VSwitchId"] = idstr + + body, err := self.vpcRequest("DescribeVSwitchAttributes", params) + if err != nil { + log.Errorf("DescribeVSwitchAttributes fail %s", err) + return nil, err + } + if self.client.debug { + log.Debugf("%s", body.PrettyString()) + } + switches := SVSwitch{} + err = body.Unmarshal(&switches) + if err != nil { + log.Errorf("Unmarshal vswitches fail %s", err) + return nil, err + } + return &switches, nil +} + +func (vsw *SVSwitch) dissociateWithSNAT() error { + natgatways, err := vsw.wire.vpc.getNatGateways() + if err != nil { + return err + } + for i := range natgatways { + err = natgatways[i].dissociateWithVswitch(vsw.VSwitchId) + if err != nil { + return err + } + } + return nil +} + +func (self *SVSwitch) GetProjectId() string { + return self.ResourceGroupId +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/waf.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/waf.go new file mode 100644 index 0000000000..d1f760cdf6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/waf.go @@ -0,0 +1,61 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceSpecs struct { + Code int + Value bool +} + +type SWafInstance struct { + Version string + InstanceSpecInfos []SInstanceSpecs + InstanceId string + ExpireTime uint64 +} + +func (self *SRegion) DescribeInstanceSpecInfo() (*SWafInstance, error) { + params := map[string]string{ + "RegionId": self.RegionId, + } + resp, err := self.wafRequest("DescribeInstanceSpecInfo", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeInstanceSpecInfo") + } + ret := &SWafInstance{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + if len(ret.InstanceId) == 0 { + return nil, cloudprovider.ErrNotFound + } + return ret, nil +} + +func (self *SRegion) DeleteInstance(id string) error { + params := map[string]string{ + "RegionId": self.RegionId, + "InstanceId": id, + } + _, err := self.wafRequest("DeleteInstance", params) + return errors.Wrapf(err, "DeleteInstance") +} diff --git a/pkg/multicloud/aliyun/waf_domain.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/waf_domain.go similarity index 98% rename from pkg/multicloud/aliyun/waf_domain.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/waf_domain.go index 76bdb27716..dcbcc66820 100644 --- a/pkg/multicloud/aliyun/waf_domain.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/waf_domain.go @@ -20,14 +20,14 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SWafDomain struct { multicloud.SResourceBase - multicloud.AliyunTags + AliyunTags region *SRegion insId string diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/wire.go new file mode 100644 index 0000000000..b58b6979d8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/wire.go @@ -0,0 +1,140 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + AliyunTags + 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) IsEmulated() bool { + return true +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SWire) Refresh() error { + return nil +} + +func (self *SWire) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.zone.GetGlobalId()) +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SWire) addNetwork(vswitch *SVSwitch) { + 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() == vswitch.VSwitchId { + find = true + break + } + } + if !find { + self.inetworks = append(self.inetworks, vswitch) + } +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + if self.inetworks == nil { + err := self.vpc.fetchVSwitches() + if err != nil { + return nil, err + } + } + return self.inetworks, nil +} + +func (self *SWire) getNetworkById(vswitchId string) *SVSwitch { + 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].(*SVSwitch) + if network.VSwitchId == vswitchId { + return network + } + } + return nil +} + +func (self *SWire) GetBandwidth() int { + return 10000 +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + vswitchId, err := self.zone.region.createVSwitch(self.zone.ZoneId, self.vpc.VpcId, opts.Name, opts.Cidr, opts.Desc) + if err != nil { + log.Errorf("createVSwitch error %s", err) + return nil, err + } + self.inetworks = nil + vswitch := self.getNetworkById(vswitchId) + if vswitch == nil { + log.Errorf("cannot find vswitch after create????") + return nil, cloudprovider.ErrNotFound + } + return vswitch, nil +} + +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 +} diff --git a/pkg/multicloud/aliyun/wrapper.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/wrapper.go similarity index 100% rename from pkg/multicloud/aliyun/wrapper.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/wrapper.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/zone.go new file mode 100644 index 0000000000..e7290da065 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aliyun/zone.go @@ -0,0 +1,304 @@ +// Copyright 2019 Yunion +// +// 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 aliyun + +import ( + "fmt" + "strings" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type TChargeType string + +var LOCAL_STORAGES = []string{ + api.STORAGE_LOCAL_HDD_PRO, + api.STORAGE_LOCAL_SSD_PRO, +} + +const ( + PrePaidInstanceChargeType TChargeType = "PrePaid" + PrePaidDBInstanceChargeType TChargeType = "Prepaid" + PostPaidInstanceChargeType TChargeType = "PostPaid" + PostPaidDBInstanceChargeType TChargeType = "Postpaid" + DefaultInstanceChargeType = PostPaidInstanceChargeType +) + +type SpotStrategyType string + +const ( + NoSpotStrategy SpotStrategyType = "NoSpot" + SpotWithPriceLimitStrategy SpotStrategyType = "SpotWithPriceLimit" + SpotAsPriceGoStrategy SpotStrategyType = "SpotAsPriceGo" + DefaultSpotStrategy = NoSpotStrategy +) + +type SDedicatedHostGenerations struct { + DedicatedHostGeneration []string +} + +type SVolumeCategories struct { + VolumeCategories []string +} + +type SSupportedDataDiskCategories struct { + SupportedDataDiskCategory []string +} + +type SSupportedInstanceGenerations struct { + SupportedInstanceGeneration []string +} + +type SSupportedInstanceTypeFamilies struct { + SupportedInstanceTypeFamily []string +} + +type SSupportedInstanceTypes struct { + SupportedInstanceType []string +} + +type SSupportedNetworkTypes struct { + SupportedNetworkCategory []string +} + +type SSupportedSystemDiskCategories struct { + SupportedSystemDiskCategory []string +} + +type SResourcesInfo struct { + DataDiskCategories SSupportedDataDiskCategories + InstanceGenerations SSupportedInstanceGenerations + InstanceTypeFamilies SSupportedInstanceTypeFamilies + InstanceTypes SSupportedInstanceTypes + IoOptimized bool + NetworkTypes SSupportedNetworkTypes + SystemDiskCategories SSupportedSystemDiskCategories +} + +type SResources struct { + ResourcesInfo []SResourcesInfo +} + +type SResourceCreation struct { + ResourceTypes []string +} + +type SInstanceTypes struct { + InstanceTypes []string +} + +type SDiskCategories struct { + DiskCategories []string +} + +type SDedicatedHostTypes struct { + DedicatedHostType []string +} + +type SZone struct { + multicloud.SResourceBase + AliyunTags + region *SRegion + + iwires []cloudprovider.ICloudWire + + host *SHost + + istorages []cloudprovider.ICloudStorage + + ZoneId string + LocalName string + DedicatedHostGenerations SDedicatedHostGenerations + AvailableVolumeCategories SVolumeCategories + /* 可供创建的具体资源,AvailableResourcesType 组成的数组 */ + AvailableResources SResources + /* 允许创建的资源类型集合 */ + AvailableResourceCreation SResourceCreation + /* 允许创建的实例规格类型 */ + AvailableInstanceTypes SInstanceTypes + /* 支持的磁盘种类集合 */ + AvailableDiskCategories SDiskCategories + AvailableDedicatedHostTypes SDedicatedHostTypes +} + +func (self *SZone) GetId() string { + return self.ZoneId +} + +func (self *SZone) GetName() string { + if self.region.GetCloudEnv() == ALIYUN_FINANCE_CLOUDENV && !strings.Contains(self.LocalName, "金融") { + i := strings.Index(self.LocalName, "可用") + var localname string + if i >= 0 { + localname = self.LocalName[0:i] + "金融云 " + self.LocalName[i:] + } else { + localname = self.LocalName + " 金融云" + } + + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_ALIYUN_CN, localname) + } else { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_ALIYUN_CN, self.LocalName) + } +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) + return table +} + +func (self *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneId) +} + +func (self *SZone) IsEmulated() bool { + return false +} + +func (self *SZone) GetStatus() string { + if len(self.AvailableResourceCreation.ResourceTypes) == 0 || !utils.IsInStringArray("Instance", self.AvailableResourceCreation.ResourceTypes) { + return api.ZONE_SOLDOUT + } else { + return api.ZONE_ENABLE + } +} + +func (self *SZone) Refresh() error { + // do nothing + return nil +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) fetchStorages() error { + categories := self.AvailableDiskCategories.DiskCategories + self.istorages = []cloudprovider.ICloudStorage{} + for _, sc := range categories { + storage := SStorage{zone: self, storageType: sc} + self.istorages = append(self.istorages, &storage) + if sc == api.STORAGE_CLOUD_ESSD { + storage_l2 := SStorage{zone: self, storageType: api.STORAGE_CLOUD_ESSD_PL2} + self.istorages = append(self.istorages, &storage_l2) + storage_l3 := SStorage{zone: self, storageType: api.STORAGE_CLOUD_ESSD_PL3} + self.istorages = append(self.istorages, &storage_l3) + } + } + for _, localStorage := range LOCAL_STORAGES { + storage := SStorage{zone: self, storageType: localStorage} + self.istorages = append(self.istorages, &storage) + } + return nil +} + +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 *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "fetchStorages") + } + } + return self.istorages, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "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) getHost() *SHost { + if self.host == nil { + self.host = &SHost{zone: self} + } + return self.host +} + +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) addWire(wire *SWire) { + if self.iwires == nil { + self.iwires = make([]cloudprovider.ICloudWire, 0) + } + self.iwires = append(self.iwires, wire) +} + +func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { + return self.iwires, nil +} + +func (self *SZone) getNetworkById(vswitchId string) *SVSwitch { + 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(vswitchId) + if net != nil { + return net + } + } + return nil +} + +func (self *SZone) getSysDiskCategories() []string { + if len(self.AvailableResources.ResourcesInfo) > 0 { + if utils.IsInStringArray(api.STORAGE_CLOUD_ESSD, self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory) { + self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory = append(self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory, api.STORAGE_CLOUD_ESSD_PL2) + self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory = append(self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory, api.STORAGE_CLOUD_ESSD_PL3) + } + return self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory + } + return nil +} diff --git a/pkg/multicloud/apsara/apsara.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/apsara.go similarity index 99% rename from pkg/multicloud/apsara/apsara.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/apsara.go index e4ba985b4f..4c1998c17d 100644 --- a/pkg/multicloud/apsara/apsara.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/apsara.go @@ -35,8 +35,8 @@ import ( v "yunion.io/x/pkg/util/version" "yunion.io/x/pkg/utils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/bucket.go new file mode 100644 index 0000000000..97c1fa8946 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/bucket.go @@ -0,0 +1,541 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + "io" + "net/http" + "strconv" + "time" + + "github.com/aliyun/aliyun-oss-go-sdk/oss" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SBucket struct { + multicloud.SBaseBucket + ApsaraTags + + region *SRegion + + Name string + Location string + CreationDate time.Time + StorageClass string + + ExtranetEndpoint string + IntranetEndpoint string + DepartmentInfo +} + +func (b *SBucket) GetGlobalId() string { + return b.Name +} + +func (b *SBucket) GetName() string { + return b.Name +} + +func (self *SBucket) GetOssClient() (*oss.Client, error) { + return self.region.GetOssClient() +} + +func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { + acl := b.region.GetBucketAcl(b.Name) + return cloudprovider.TBucketACLType(acl) +} + +func (self *SRegion) GetBucketAcl(bucket string) string { + params := map[string]string{ + "AccountInfo": "aaa", + "x-acs-instanceid": bucket, + "Params": jsonutils.Marshal(map[string]string{"BucketName": bucket, "acl": "acl"}).String(), + } + resp, err := self.ossRequest("GetBucketAcl", params) + if err != nil { + return "" + } + acl, _ := resp.GetString("Data", "AccessControlPolicy", "AccessControlList", "Grant") + return acl +} + +func (b *SBucket) GetLocation() string { + return b.Location +} + +func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { + return b.region +} + +func (b *SBucket) GetCreatedAt() time.Time { + return b.CreationDate +} + +func (b *SBucket) GetStorageClass() string { + return b.StorageClass +} + +func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { + return []cloudprovider.SBucketAccessUrl{ + { + Url: fmt.Sprintf("%s.%s", b.Name, b.ExtranetEndpoint), + Description: "ExtranetEndpoint", + Primary: true, + }, + } +} + +func (self *SRegion) GetBucketSize(bucket string, department int) (int64, error) { + params := map[string]string{ + "Namespace": "acs_oss_dashboard", + "MetricName": "MeteringStorageUtilization", + "Period": "3600", + "Dimensions": jsonutils.Marshal([]map[string]string{ + {"BucketName": bucket}, + }).String(), + "Department": fmt.Sprintf("%d", department), + "StartTime": strconv.FormatInt(time.Now().Add(time.Hour*-24*2).Unix()*1000, 10), + "EndTime": strconv.FormatInt(time.Now().Unix()*1000, 10), + } + resp, err := self.client.metricsRequest("DescribeMetricList", params) + if err != nil { + return 0, nil + } + datapoints, err := resp.GetString("Datapoints") + if err != nil { + return 0, errors.Wrapf(err, "get datapoints") + } + obj, err := jsonutils.ParseString(datapoints) + if err != nil { + return 0, errors.Wrapf(err, "ParseString") + } + data := []struct { + Timestamp int64 + Value int64 + }{} + obj.Unmarshal(&data) + for i := range data { + return data[i].Value, nil + } + return 0, fmt.Errorf("no storage metric found") +} + +func (b *SBucket) GetStats() cloudprovider.SBucketStats { + ret := cloudprovider.SBucketStats{ + SizeBytes: -1, + ObjectCount: -1, + } + dep, _ := strconv.Atoi(b.Department) + size, _ := b.region.GetBucketSize(b.Name, dep) + if size > 0 { + ret.SizeBytes = size + } + return ret +} + +func (self *SRegion) GetBucketCapacity(bucket string, department int) (int64, error) { + params := map[string]string{ + "Params": jsonutils.Marshal(map[string]string{ + "BucketName": bucket, + "region": self.RegionId, + }).String(), + // 此参数必传,可以设任意值 + "AccountInfo": "aaa", + "Department": fmt.Sprintf("%d", department), + } + resp, err := self.ossRequest("GetBucketStorageCapacity", params) + if err != nil { + return 0, errors.Wrapf(err, "GetBucketStorageCapacity") + } + return resp.Int("Data", "BucketUserQos", "StorageCapacity") +} + +func (b *SBucket) GetLimit() cloudprovider.SBucketStats { + ret := cloudprovider.SBucketStats{ + SizeBytes: -1, + ObjectCount: -1, + } + dep, _ := strconv.Atoi(b.Department) + capa, _ := b.region.GetBucketCapacity(b.Name, dep) + if capa > 0 { + ret.SizeBytes = capa * 1024 * 1024 * 1024 + } + return ret +} + +func (b *SBucket) LimitSupport() cloudprovider.SBucketStats { + return b.GetLimit() +} + +func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error { + osscli, err := b.GetOssClient() + if err != nil { + return errors.Wrap(err, "b.region.GetOssClient") + } + acl, err := str2Acl(string(aclStr)) + if err != nil { + return errors.Wrap(err, "str2Acl") + } + err = osscli.SetBucketACL(b.Name, acl) + if err != nil { + return errors.Wrap(err, "SetBucketACL") + } + return nil +} + +func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { + result := cloudprovider.SListObjectResult{} + osscli, err := b.GetOssClient() + if err != nil { + return result, errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return result, errors.Wrap(err, "Bucket") + } + opts := make([]oss.Option, 0) + if len(prefix) > 0 { + opts = append(opts, oss.Prefix(prefix)) + } + if len(delimiter) > 0 { + opts = append(opts, oss.Delimiter(delimiter)) + } + if len(marker) > 0 { + opts = append(opts, oss.Marker(marker)) + } + if maxCount > 0 { + opts = append(opts, oss.MaxKeys(maxCount)) + } + oResult, err := bucket.ListObjects(opts...) + if err != nil { + return result, errors.Wrap(err, "ListObjects") + } + result.Objects = make([]cloudprovider.ICloudObject, 0) + for _, object := range oResult.Objects { + obj := &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + StorageClass: object.StorageClass, + Key: object.Key, + SizeBytes: object.Size, + ETag: object.ETag, + LastModified: object.LastModified, + }, + } + result.Objects = append(result.Objects, obj) + } + if oResult.CommonPrefixes != nil { + result.CommonPrefixes = make([]cloudprovider.ICloudObject, len(oResult.CommonPrefixes)) + for i, commPrefix := range oResult.CommonPrefixes { + result.CommonPrefixes[i] = &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{Key: commPrefix}, + } + } + } + result.IsTruncated = oResult.IsTruncated + result.NextMarker = oResult.NextMarker + return result, nil +} + +func metaOpts(opts []oss.Option, meta http.Header) []oss.Option { + for k, v := range meta { + if len(v) == 0 { + continue + } + switch http.CanonicalHeaderKey(k) { + case cloudprovider.META_HEADER_CONTENT_TYPE: + opts = append(opts, oss.ContentType(v[0])) + case cloudprovider.META_HEADER_CONTENT_MD5: + opts = append(opts, oss.ContentMD5(v[0])) + case cloudprovider.META_HEADER_CONTENT_LANGUAGE: + opts = append(opts, oss.ContentLanguage(v[0])) + case cloudprovider.META_HEADER_CONTENT_ENCODING: + opts = append(opts, oss.ContentEncoding(v[0])) + case cloudprovider.META_HEADER_CONTENT_DISPOSITION: + opts = append(opts, oss.ContentDisposition(v[0])) + case cloudprovider.META_HEADER_CACHE_CONTROL: + opts = append(opts, oss.CacheControl(v[0])) + default: + opts = append(opts, oss.Meta(http.CanonicalHeaderKey(k), v[0])) + } + } + return opts +} + +func (b *SBucket) PutObject(ctx context.Context, key string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + osscli, err := b.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return errors.Wrap(err, "Bucket") + } + opts := make([]oss.Option, 0) + if sizeBytes > 0 { + opts = append(opts, oss.ContentLength(sizeBytes)) + } + if meta != nil { + opts = metaOpts(opts, meta) + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + acl, err := str2Acl(string(cannedAcl)) + if err != nil { + return errors.Wrap(err, "") + } + opts = append(opts, oss.ObjectACL(acl)) + if len(storageClassStr) > 0 { + storageClass, err := str2StorageClass(storageClassStr) + if err != nil { + return errors.Wrap(err, "str2StorageClass") + } + opts = append(opts, oss.ObjectStorageClass(storageClass)) + } + return bucket.PutObject(key, input, opts...) +} + +func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + osscli, err := b.GetOssClient() + if err != nil { + return "", errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return "", errors.Wrap(err, "Bucket") + } + opts := make([]oss.Option, 0) + if meta != nil { + opts = metaOpts(opts, meta) + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + acl, err := str2Acl(string(cannedAcl)) + if err != nil { + return "", errors.Wrap(err, "str2Acl") + } + opts = append(opts, oss.ObjectACL(acl)) + if len(storageClassStr) > 0 { + storageClass, err := str2StorageClass(storageClassStr) + if err != nil { + return "", errors.Wrap(err, "str2StorageClass") + } + opts = append(opts, oss.ObjectStorageClass(storageClass)) + } + result, err := bucket.InitiateMultipartUpload(key, opts...) + if err != nil { + return "", errors.Wrap(err, "bucket.InitiateMultipartUpload") + } + return result.UploadID, nil +} + +func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { + osscli, err := b.GetOssClient() + if err != nil { + return "", errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return "", errors.Wrap(err, "Bucket") + } + imur := oss.InitiateMultipartUploadResult{ + Bucket: b.Name, + Key: key, + UploadID: uploadId, + } + part, err := bucket.UploadPart(imur, input, partSize, partIndex) + if err != nil { + return "", errors.Wrap(err, "bucket.UploadPart") + } + if b.region.client.debug { + log.Debugf("upload part key:%s uploadId:%s partIndex:%d etag:%s", key, uploadId, partIndex, part.ETag) + } + return part.ETag, nil +} + +func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { + osscli, err := b.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return errors.Wrap(err, "Bucket") + } + imur := oss.InitiateMultipartUploadResult{ + Bucket: b.Name, + Key: key, + UploadID: uploadId, + } + parts := make([]oss.UploadPart, len(partEtags)) + for i := range partEtags { + parts[i] = oss.UploadPart{ + PartNumber: i + 1, + ETag: partEtags[i], + } + } + result, err := bucket.CompleteMultipartUpload(imur, parts) + if err != nil { + return errors.Wrap(err, "bucket.CompleteMultipartUpload") + } + if b.region.client.debug { + log.Debugf("CompleteMultipartUpload bucket:%s key:%s etag:%s location:%s", result.Bucket, result.Key, result.ETag, result.Location) + } + return nil +} + +func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { + osscli, err := b.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return errors.Wrap(err, "Bucket") + } + imur := oss.InitiateMultipartUploadResult{ + Bucket: b.Name, + Key: key, + UploadID: uploadId, + } + err = bucket.AbortMultipartUpload(imur) + if err != nil { + return errors.Wrap(err, "AbortMultipartUpload") + } + return nil +} + +func (b *SBucket) DeleteObject(ctx context.Context, key string) error { + osscli, err := b.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return errors.Wrap(err, "Bucket") + } + err = bucket.DeleteObject(key) + if err != nil { + return errors.Wrap(err, "DeleteObject") + } + return nil +} + +func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { + if method != "GET" && method != "PUT" && method != "DELETE" { + return "", errors.Error("unsupported method") + } + osscli, err := b.GetOssClient() + if err != nil { + return "", errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return "", errors.Wrap(err, "Bucket") + } + urlStr, err := bucket.SignURL(key, oss.HTTPMethod(method), int64(expire/time.Second)) + if err != nil { + return "", errors.Wrap(err, "SignURL") + } + return urlStr, nil +} + +func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + osscli, err := b.GetOssClient() + if err != nil { + return errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return errors.Wrap(err, "Bucket") + } + opts := make([]oss.Option, 0) + if meta != nil { + opts = metaOpts(opts, meta) + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + acl, err := str2Acl(string(cannedAcl)) + if err != nil { + return errors.Wrap(err, "str2Acl") + } + opts = append(opts, oss.ObjectACL(acl)) + if len(storageClassStr) > 0 { + storageClass, err := str2StorageClass(storageClassStr) + if err != nil { + return errors.Wrap(err, "str2StorageClass") + } + opts = append(opts, oss.ObjectStorageClass(storageClass)) + } + _, err = bucket.CopyObjectFrom(srcBucket, srcKey, destKey, opts...) + if err != nil { + return errors.Wrap(err, "CopyObjectFrom") + } + return nil +} + +func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { + osscli, err := b.GetOssClient() + if err != nil { + return nil, errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return nil, errors.Wrap(err, "Bucket") + } + opts := make([]oss.Option, 0) + if rangeOpt != nil { + opts = append(opts, oss.NormalizedRange(rangeOpt.String())) + } + output, err := bucket.GetObject(key, opts...) + if err != nil { + return nil, errors.Wrap(err, "bucket.GetObject") + } + return output, nil +} + +func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partNumber int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { + osscli, err := b.GetOssClient() + if err != nil { + return "", errors.Wrap(err, "GetOssClient") + } + bucket, err := osscli.Bucket(b.Name) + if err != nil { + return "", errors.Wrap(err, "Bucket") + } + imur := oss.InitiateMultipartUploadResult{ + Bucket: b.Name, + Key: key, + UploadID: uploadId, + } + opts := make([]oss.Option, 0) + part, err := bucket.UploadPartCopy(imur, srcBucket, srcKey, srcOffset, srcLength, partNumber, opts...) + if err != nil { + return "", errors.Wrap(err, "bucket.UploadPartCopy") + } + return part.ETag, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/charge.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/charge.go new file mode 100644 index 0000000000..1ac2d9c6ee --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/charge.go @@ -0,0 +1,42 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "time" + + api "yunion.io/x/cloudmux/pkg/apis/billing" +) + +func convertChargeType(ct TChargeType) string { + switch ct { + case PrePaidInstanceChargeType: + return api.BILLING_TYPE_PREPAID + case PostPaidInstanceChargeType, PostPaidDBInstanceChargeType: + return api.BILLING_TYPE_POSTPAID + default: + return "" + } +} + +func convertExpiredAt(expired time.Time) time.Time { + if !expired.IsZero() { + now := time.Now() + if expired.Sub(now) < time.Hour*24*365*6 { + return expired + } + } + return time.Time{} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance.go new file mode 100644 index 0000000000..d4a82de8a7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance.go @@ -0,0 +1,802 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/rand" +) + +type SReadOnlyDBInstanceIds struct { + ReadOnlyDBInstanceId []string +} + +type SDBInstanceId struct { + DBInstanceId []string +} + +type SDBInstanceExtra struct { + DBInstanceId SDBInstanceId +} + +type SDBInstance struct { + multicloud.SDBInstanceBase + ApsaraTags + + netInfo []SDBInstanceNetwork + + region *SRegion + + AccountMaxQuantity int + AccountType string + CanTempUpgrade bool + Category string + AvailabilityValue string + DBInstanceDescription string + DBInstanceId string + ConnectionMode string + ConnectionString string + CurrentKernelVersion string + DBInstanceCPU int + CreateTime time.Time + DBInstanceClass string + DBInstanceClassType string + DBInstanceNetType string + DBInstanceStatus string + DBInstanceType string + DBInstanceDiskUsed int64 + DBInstanceStorage int + DBInstanceStorageType string + MasterInstanceId string + DBInstanceMemory int + DBMaxQuantity int + IPType string + LatestKernelVersion string + DispenseMode string + Engine string + EngineVersion string + ExpireTime time.Time + InstanceNetworkType string + LockMode string + LockReason string + MutriORsignle bool + MaintainTime string + MaxConnections int + MaxIOPS int + Port int + PayType TChargeType + ReadOnlyDBInstanceIds SReadOnlyDBInstanceIds + RegionId string + VSwitchId string + VpcCloudInstanceId string + VpcId string + ZoneId string + Extra SDBInstanceExtra + SecurityIPList string + SecurityIPMode string + SupportCreateSuperAccount string + SupportUpgradeAccountType string + TempUpgradeTimeEnd time.Time + TempUpgradeTimeStart time.Time + DepartmentInfo +} + +func (rds *SDBInstance) GetName() string { + if len(rds.DBInstanceDescription) > 0 { + return rds.DBInstanceDescription + } + return rds.DBInstanceId +} + +func (rds *SDBInstance) GetId() string { + return rds.DBInstanceId +} + +func (rds *SDBInstance) GetGlobalId() string { + return rds.GetId() +} + +// Creating 创建中 +// Running 使用中 +// Deleting 删除中 +// Rebooting 重启中 +// DBInstanceClassChanging 升降级中 +// TRANSING 迁移中 +// EngineVersionUpgrading 迁移版本中 +// TransingToOthers 迁移数据到其他RDS中 +// GuardDBInstanceCreating 生产灾备实例中 +// Restoring 备份恢复中 +// Importing 数据导入中 +// ImportingFromOthers 从其他RDS实例导入数据中 +// DBInstanceNetTypeChanging 内外网切换中 +// GuardSwitching 容灾切换中 +// INS_CLONING 实例克隆中 +func (rds *SDBInstance) GetStatus() string { + switch rds.DBInstanceStatus { + case "Creating", "GuardDBInstanceCreating", "DBInstanceNetTypeChanging", "GuardSwitching", "NET_CREATING", "NET_DELETING": + return api.DBINSTANCE_DEPLOYING + case "DBInstanceClassChanging": + return api.DBINSTANCE_CHANGE_CONFIG + case "Running": + return api.DBINSTANCE_RUNNING + case "Deleting": + return api.DBINSTANCE_DELETING + case "Rebooting": + return api.DBINSTANCE_REBOOTING + case "TRANSING", "EngineVersionUpgrading", "TransingToOthers": + return api.DBINSTANCE_MIGRATING + case "Restoring": + return api.DBINSTANCE_RESTORING + case "Importing", "ImportingFromOthers": + return api.DBINSTANCE_IMPORTING + case "INS_CLONING": + return api.DBINSTANCE_CLONING + default: + log.Errorf("Unknown dbinstance status %s", rds.DBInstanceStatus) + return api.DBINSTANCE_UNKNOWN + } +} + +func (rds *SDBInstance) GetBillingType() string { + return convertChargeType(rds.PayType) +} + +func (rds *SDBInstance) GetExpiredAt() time.Time { + return rds.ExpireTime +} + +func (rds *SDBInstance) GetCreatedAt() time.Time { + return rds.CreateTime +} + +func (rds *SDBInstance) GetStorageType() string { + return rds.DBInstanceStorageType +} + +func (rds *SDBInstance) GetIops() int { + return rds.MaxIOPS +} + +func (rds *SDBInstance) GetEngine() string { + switch rds.Engine { + case "MySQL": + return api.DBINSTANCE_TYPE_MYSQL + case "SQLServer": + return api.DBINSTANCE_TYPE_SQLSERVER + case "PostgreSQL": + return api.DBINSTANCE_TYPE_POSTGRESQL + case "PPAS": + return api.DBINSTANCE_TYPE_PPAS + case "MariaDB": + return api.DBINSTANCE_TYPE_MARIADB + } + return rds.Engine +} + +func (rds *SDBInstance) GetEngineVersion() string { + return rds.EngineVersion +} + +func (rds *SDBInstance) GetInstanceType() string { + return rds.DBInstanceClass +} + +func (rds *SDBInstance) GetCategory() string { + switch rds.Category { + case "Basic": + return api.ALIYUN_DBINSTANCE_CATEGORY_BASIC + case "HighAvailability": + return api.ALIYUN_DBINSTANCE_CATEGORY_HA + case "AlwaysOn": + return api.ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON + case "Finance": + return api.ALIYUN_DBINSTANCE_CATEGORY_FINANCE + } + return rds.Category +} + +func (rds *SDBInstance) GetVcpuCount() int { + if rds.DBInstanceCPU == 0 { + rds.Refresh() + } + return rds.DBInstanceCPU +} + +func (rds *SDBInstance) GetVmemSizeMB() int { + if rds.DBInstanceMemory == 0 { + rds.Refresh() + } + return rds.DBInstanceMemory +} + +func (rds *SDBInstance) GetDiskSizeGB() int { + if rds.DBInstanceStorage == 0 { + rds.Refresh() + } + return rds.DBInstanceStorage +} + +func (rds *SDBInstance) GetDiskSizeUsedMB() int { + if rds.DBInstanceDiskUsed == 0 { + rds.Refresh() + } + return int(rds.DBInstanceDiskUsed / 1024 / 1024) +} + +func (rds *SDBInstance) GetPort() int { + if rds.Port == 0 { + rds.Refresh() + } + return rds.Port +} + +func (rds *SDBInstance) GetMaintainTime() string { + return rds.MaintainTime +} + +func (rds *SDBInstance) GetIVpcId() string { + return rds.VpcId +} + +func (rds *SDBInstance) Refresh() error { + instance, err := rds.region.GetDBInstanceDetail(rds.DBInstanceId) + if err != nil { + return err + } + return jsonutils.Update(rds, instance) +} + +func (rds *SDBInstance) getZoneId(index int) string { + zoneId := rds.getZone(index) + if len(zoneId) > 0 { + zone, err := rds.region.getZoneById(zoneId) + if err != nil { + log.Errorf("failed to found zone %s for rds %s", zoneId, rds.GetName()) + return "" + } + return zone.GetGlobalId() + } + return "" +} + +func (rds *SDBInstance) GetZone1Id() string { + return rds.getZoneId(1) +} + +func (rds *SDBInstance) GetZone2Id() string { + return rds.getZoneId(2) +} + +func (rds *SDBInstance) GetZone3Id() string { + return rds.getZoneId(3) +} + +func (rds *SDBInstance) getZone(index int) string { + zoneStr := strings.Replace(rds.ZoneId, ")", "", -1) + zoneInfo := strings.Split(zoneStr, ",") + if len(zoneInfo) < index { + return "" + } + zone := zoneInfo[index-1] + zoneCode := zone[len(zone)-1] + if strings.HasPrefix(rds.ZoneId, fmt.Sprintf("%s-", rds.RegionId)) { + return fmt.Sprintf("%s-%s", rds.RegionId, string(zoneCode)) + } + return fmt.Sprintf("%s%s", rds.RegionId, string(zoneCode)) +} + +func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { + netInfo, err := rds.region.GetDBInstanceNetInfo(rds.DBInstanceId) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceNetInfo") + } + networks := []cloudprovider.SDBInstanceNetwork{} + for _, net := range netInfo { + if net.IPType == "Private" { + network := cloudprovider.SDBInstanceNetwork{} + network.IP = net.IPAddress + network.NetworkId = net.VSwitchId + networks = append(networks, network) + } + } + return networks, nil +} + +func (rds *SDBInstance) fetchNetInfo() error { + if len(rds.netInfo) > 0 { + return nil + } + netInfo, err := rds.region.GetDBInstanceNetInfo(rds.DBInstanceId) + if err != nil { + return errors.Wrap(err, "GetDBInstanceNetInfo") + } + rds.netInfo = netInfo + return nil +} + +func (rds *SDBInstance) GetInternalConnectionStr() string { + err := rds.fetchNetInfo() + if err != nil { + log.Errorf("failed to fetch netInfo error: %v", err) + return "" + } + + for _, net := range rds.netInfo { + if net.IPType != "Public" { + return net.ConnectionString + } + } + return "" +} + +func (rds *SDBInstance) GetConnectionStr() string { + err := rds.fetchNetInfo() + if err != nil { + log.Errorf("failed to fetch netInfo error: %v", err) + return "" + } + + for _, net := range rds.netInfo { + if net.IPType == "Public" { + return net.ConnectionString + } + } + return "" +} + +func (region *SRegion) GetDBInstances(ids []string, offset int, limit int) ([]SDBInstance, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + body, err := region.rdsRequest("DescribeDBInstances", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "GetDBInstances") + } + instances := []SDBInstance{} + err = body.Unmarshal(&instances, "Items", "DBInstance") + if err != nil { + return nil, 0, errors.Wrapf(err, "GetDBInstances.Unmarshal") + } + total, _ := body.Int("TotalRecordCount") + return instances, int(total), nil +} + +func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { + rds, err := region.GetDBInstanceDetail(instanceId) + if err != nil { + return nil, err + } + rds.region = region + return rds, nil +} + +func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { + instances := []SDBInstance{} + for { + part, total, err := region.GetDBInstances([]string{}, len(instances), 50) + if err != nil { + return nil, err + } + instances = append(instances, part...) + if len(instances) >= total { + break + } + } + idbinstances := []cloudprovider.ICloudDBInstance{} + for i := 0; i < len(instances); i++ { + instances[i].region = region + idbinstances = append(idbinstances, &instances[i]) + } + return idbinstances, nil +} + +func (region *SRegion) GetDBInstanceDetail(instanceId string) (*SDBInstance, error) { + if len(instanceId) == 0 { + return nil, cloudprovider.ErrNotFound + } + params := map[string]string{} + params["RegionId"] = region.RegionId + params["DBInstanceId"] = instanceId + body, err := region.rdsRequest("DescribeDBInstanceAttribute", params) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceDetail") + } + instances := []SDBInstance{} + err = body.Unmarshal(&instances, "Items", "DBInstanceAttribute") + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceDetail.Unmarshal") + } + if len(instances) == 1 { + instances[0].region = region + return &instances[0], nil + } + if len(instances) == 0 { + return nil, cloudprovider.ErrNotFound + } + return nil, cloudprovider.ErrDuplicateId +} + +func (region *SRegion) DeleteDBInstance(instanceId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["DBInstanceId"] = instanceId + _, err := region.rdsRequest("DeleteDBInstance", params) + return err +} + +type SDBInstanceWeight struct { +} + +type SDBInstanceWeights struct { + DBInstanceWeight []SDBInstanceWeight +} + +type SsecurityIPGroup struct { +} + +type SSecurityIPGroups struct { + securityIPGroup []SsecurityIPGroup +} + +type SDBInstanceNetwork struct { + ConnectionString string + ConnectionStringType string + DBInstanceWeights SDBInstanceWeights + IPAddress string + IPType string + Port int + SecurityIPGroups SSecurityIPGroups + Upgradeable string + VPCId string + VSwitchId string +} + +func (network *SDBInstanceNetwork) GetGlobalId() string { + return network.IPAddress +} + +func (network *SDBInstanceNetwork) GetINetworkId() string { + return network.VSwitchId +} + +func (network *SDBInstanceNetwork) GetIP() string { + return network.IPAddress +} + +func (region *SRegion) GetDBInstanceNetInfo(instanceId string) ([]SDBInstanceNetwork, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["DBInstanceId"] = instanceId + body, err := region.rdsRequest("DescribeDBInstanceNetInfo", params) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceNetwork") + } + networks := []SDBInstanceNetwork{} + err = body.Unmarshal(&networks, "DBInstanceNetInfos", "DBInstanceNetInfo") + if err != nil { + return nil, err + } + return networks, nil +} + +func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { + parameters, err := rds.region.GetDBInstanceParameters(rds.DBInstanceId) + if err != nil { + return nil, err + } + iparameters := []cloudprovider.ICloudDBInstanceParameter{} + for i := 0; i < len(parameters); i++ { + iparameters = append(iparameters, ¶meters[i]) + } + return iparameters, nil +} + +func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { + backups, err := region.GetIDBInstanceBackups() + if err != nil { + return nil, errors.Wrap(err, "region.GetIDBInstanceBackups") + } + for _, backup := range backups { + if backup.GetGlobalId() == backupId { + return backup, nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (rds *SDBInstance) Reboot() error { + return rds.region.RebootDBInstance(rds.DBInstanceId) +} + +func (rds *SDBInstance) Delete() error { + return rds.region.DeleteDBInstance(rds.DBInstanceId) +} + +func (region *SRegion) RebootDBInstance(instanceId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["DBInstanceId"] = instanceId + _, err := region.rdsRequest("RestartDBInstance", params) + return err +} + +func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { + databases := []SDBInstanceDatabase{} + for { + parts, total, err := rds.region.GetDBInstanceDatabases(rds.DBInstanceId, "", len(databases), 500) + if err != nil { + return nil, err + } + databases = append(databases, parts...) + if len(databases) >= total { + break + } + } + + idatabase := []cloudprovider.ICloudDBInstanceDatabase{} + for i := 0; i < len(databases); i++ { + databases[i].instance = rds + idatabase = append(idatabase, &databases[i]) + } + return idatabase, nil +} + +func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { + accounts := []SDBInstanceAccount{} + for { + parts, total, err := rds.region.GetDBInstanceAccounts(rds.DBInstanceId, len(accounts), 50) + if err != nil { + return nil, err + } + accounts = append(accounts, parts...) + if len(accounts) >= total { + break + } + } + + iaccounts := []cloudprovider.ICloudDBInstanceAccount{} + for i := 0; i < len(accounts); i++ { + accounts[i].instance = rds + iaccounts = append(iaccounts, &accounts[i]) + } + return iaccounts, nil +} + +func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { + return rds.region.ChangeDBInstanceConfig(rds.DBInstanceId, string(rds.PayType), desc) +} + +func (region *SRegion) ChangeDBInstanceConfig(instanceId, payType string, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { + params := map[string]string{ + "RegionId": region.RegionId, + "DBInstanceId": instanceId, + "PayType": payType, + "DBInstanceClass": desc.InstanceType, + "DBInstanceStorage": fmt.Sprintf("%d", desc.DiskSizeGB), + } + + _, err := region.rdsRequest("ModifyDBInstanceSpec", params) + if err != nil { + return errors.Wrap(err, "region.rdsRequest.ModifyDBInstanceSpec") + } + return nil +} + +func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + params := map[string]string{ + "RegionId": region.RegionId, + "Engine": desc.Engine, + "EngineVersion": desc.EngineVersion, + "DBInstanceStorage": fmt.Sprintf("%d", desc.DiskSizeGB), + "DBInstanceNetType": "Intranet", + "PayType": "Postpaid", + "SecurityIPList": "0.0.0.0/0", + "DBInstanceDescription": desc.Name, + "InstanceNetworkType": "VPC", + "VPCId": desc.VpcId, + "VSwitchId": desc.NetworkId, + "DBInstanceStorageType": desc.StorageType, + "DBInstanceClass": desc.InstanceType, + "ZoneId": desc.ZoneId, + "ClientToken": utils.GenRequestId(20), + } + switch desc.Category { + case api.ALIYUN_DBINSTANCE_CATEGORY_HA: + params["Category"] = "HighAvailability" + case api.ALIYUN_DBINSTANCE_CATEGORY_BASIC: + params["Category"] = "Basic" + case api.ALIYUN_DBINSTANCE_CATEGORY_ALWAYSON: + params["Category"] = "AlwaysOn" + case api.ALIYUN_DBINSTANCE_CATEGORY_FINANCE: + params["Category"] = "Finance" + } + + if len(desc.Address) > 0 { + params["PrivateIpAddress"] = desc.Address + } + if len(desc.ProjectId) > 0 { + params["ResourceGroupId"] = desc.ProjectId + } + if desc.BillingCycle != nil { + params["PayType"] = "Prepaid" + if desc.BillingCycle.GetMonths() > 0 { + params["Period"] = "Month" + params["UsedTime"] = fmt.Sprintf("%d", desc.BillingCycle.GetMonths()) + } else { + params["Period"] = "Year" + params["UsedTime"] = fmt.Sprintf("%d", desc.BillingCycle.GetYears()) + } + params["AutoRenew"] = "False" + } + + action := "CreateDBInstance" + if len(desc.MasterInstanceId) > 0 { + action = "CreateReadOnlyDBInstance" + params["DBInstanceId"] = desc.MasterInstanceId + } + + resp, err := region.rdsRequest(action, params) + if err != nil { + return nil, errors.Wrapf(err, "rdsRequest") + } + instanceId, err := resp.GetString("DBInstanceId") + if err != nil { + return nil, errors.Wrap(err, `resp.GetString("DBInstanceId")`) + } + region.SetResourceTags("rds", "INSTANCE", []string{instanceId}, desc.Tags, false) + return region.GetIDBInstanceById(instanceId) +} + +func (rds *SDBInstance) GetMasterInstanceId() string { + if len(rds.MasterInstanceId) > 0 { + return rds.MasterInstanceId + } + rds.Refresh() + return rds.MasterInstanceId +} + +func (region *SRegion) OpenPublicConnection(instanceId string) error { + rds, err := region.GetDBInstanceDetail(instanceId) + if err != nil { + return err + } + params := map[string]string{ + "RegionId": region.RegionId, + "ConnectionStringPrefix": rds.DBInstanceId + rand.String(3), + "DBInstanceId": rds.DBInstanceId, + "Port": fmt.Sprintf("%d", rds.Port), + } + _, err = rds.region.rdsRequest("AllocateInstancePublicConnection", params) + if err != nil { + return errors.Wrap(err, "rdsRequest(AllocateInstancePublicConnection)") + } + return nil +} + +func (rds *SDBInstance) OpenPublicConnection() error { + if url := rds.GetConnectionStr(); len(url) == 0 { + err := rds.region.OpenPublicConnection(rds.DBInstanceId) + if err != nil { + return err + } + rds.netInfo = []SDBInstanceNetwork{} + } + return nil +} + +func (region *SRegion) ClosePublicConnection(instanceId string) error { + netInfo, err := region.GetDBInstanceNetInfo(instanceId) + if err != nil { + return errors.Wrap(err, "GetDBInstanceNetInfo") + } + + for _, net := range netInfo { + if net.IPType == "Public" { + params := map[string]string{ + "RegionId": region.RegionId, + "CurrentConnectionString": net.ConnectionString, + "DBInstanceId": instanceId, + } + _, err = region.rdsRequest("ReleaseInstancePublicConnection", params) + if err != nil { + return errors.Wrap(err, "rdsRequest(ReleaseInstancePublicConnection)") + } + + } + } + return nil + +} + +func (rds *SDBInstance) ClosePublicConnection() error { + return rds.region.ClosePublicConnection(rds.DBInstanceId) +} + +func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { + if len(conf.OriginDBInstanceExternalId) == 0 { + conf.OriginDBInstanceExternalId = rds.DBInstanceId + } + return rds.region.RecoveryDBInstanceFromBackup(conf.OriginDBInstanceExternalId, rds.DBInstanceId, conf.BackupId, conf.Databases) +} + +func (region *SRegion) RecoveryDBInstanceFromBackup(srcId, destId string, backupId string, databases map[string]string) error { + params := map[string]string{ + "RegionId": region.RegionId, + "DBInstanceId": srcId, + "TargetDBInstanceId": destId, + "BackupId": backupId, + "DbNames": jsonutils.Marshal(databases).String(), + } + _, err := region.rdsRequest("RecoveryDBInstance", params) + if err != nil { + return errors.Wrap(err, "rdsRequest.RecoveryDBInstance") + } + return nil +} + +func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { + return rds.region.CreateDBInstanceDatabae(rds.DBInstanceId, conf.CharacterSet, conf.Name, conf.Description) +} + +func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { + return rds.region.CreateDBInstanceAccount(rds.DBInstanceId, conf.Name, conf.Password, conf.Description) +} + +func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { + return rds.region.RenewInstance(rds.DBInstanceId, bc) +} + +func (region *SRegion) RenewDBInstance(instanceId string, bc billing.SBillingCycle) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "Period": fmt.Sprintf("%d", bc.GetMonths()), + "ClientToken": utils.GenRequestId(20), + } + _, err := region.rdsRequest("RenewInstance", params) + return err +} + +func (rds *SDBInstance) GetTags() (map[string]string, error) { + tags, err := rds.region.ListResourceTags("rds", "INSTANCE", []string{rds.GetId()}) + if err != nil { + return nil, errors.Wrap(err, "rds.region.ListResourceTags") + } + if _, ok := tags[rds.GetId()]; !ok { + return map[string]string{}, nil + } + return *tags[rds.GetId()], nil +} + +func (rds *SDBInstance) SetTags(tags map[string]string, replace bool) error { + return rds.region.SetResourceTags("rds", "INSTANCE", []string{rds.GetId()}, tags, replace) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_account.go new file mode 100644 index 0000000000..dde0a303ed --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_account.go @@ -0,0 +1,178 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDatabasePrivileges struct { + DatabasePrivilege []SDatabasePrivilege +} + +type SDBInstanceAccount struct { + multicloud.SDBInstanceAccountBase + ApsaraTags + instance *SDBInstance + + AccountDescription string + AccountName string + AccountStatus string + AccountType string + DBInstanceId string + DatabasePrivileges SDatabasePrivileges + PrivExceeded string +} + +func (account *SDBInstanceAccount) GetName() string { + return account.AccountName +} + +func (account *SDBInstanceAccount) Delete() error { + return account.instance.region.DeleteDBInstanceAccount(account.DBInstanceId, account.AccountName) +} + +func (account *SDBInstanceAccount) RevokePrivilege(database string) error { + return account.instance.region.RevokeDBInstancePrivilege(account.DBInstanceId, account.AccountName, database) +} + +func (region *SRegion) RevokeDBInstancePrivilege(instanceId, account, database string) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "AccountName": account, + "DBName": database, + } + _, err := region.rdsRequest("RevokeAccountPrivilege", params) + return err +} + +func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { + return account.instance.region.GrantDBInstancePrivilege(account.DBInstanceId, account.AccountName, database, privilege) +} + +func (region *SRegion) GrantDBInstancePrivilege(instanceId, account, database, privilege string) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "AccountName": account, + "DBName": database, + } + switch privilege { + case api.DATABASE_PRIVILEGE_R: + params["AccountPrivilege"] = "ReadOnly" + case api.DATABASE_PRIVILEGE_RW: + params["AccountPrivilege"] = "ReadWrite" + case api.DATABASE_PRIVILEGE_DDL: + params["AccountPrivilege"] = "DDLOnly" + case api.DATABASE_PRIVILEGE_DML: + params["AccountPrivilege"] = "DMLOnly" + case api.DATABASE_PRIVILEGE_OWNER: + params["AccountPrivilege"] = "DBOwner" + default: + return fmt.Errorf("Unknown privilege [%s]", privilege) + } + _, err := region.rdsRequest("GrantAccountPrivilege", params) + return err +} + +func (account *SDBInstanceAccount) ResetPassword(password string) error { + return account.instance.region.ResetDBInstanceAccountPassword(account.DBInstanceId, account.AccountName, password, account.AccountType) +} + +func (region *SRegion) ResetDBInstanceAccountPassword(instanceId, account, password, accountType string) error { + action := "ResetAccountPassword" + if accountType == "Super" { + action = "ResetAccount" + } + params := map[string]string{ + "DBInstanceId": instanceId, + "AccountName": account, + "AccountPassword": password, + } + _, err := region.rdsRequest(action, params) + return err +} + +func (account *SDBInstanceAccount) GetStatus() string { + switch account.AccountStatus { + case "Available": + return api.DBINSTANCE_USER_AVAILABLE + case "Unavailable": + return api.DBINSTANCE_USER_UNAVAILABLE + } + return account.AccountStatus +} + +func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { + privileves := []cloudprovider.ICloudDBInstanceAccountPrivilege{} + for i := 0; i < len(account.DatabasePrivileges.DatabasePrivilege); i++ { + account.DatabasePrivileges.DatabasePrivilege[i].account = account + privileves = append(privileves, &account.DatabasePrivileges.DatabasePrivilege[i]) + } + return privileves, nil +} + +func (region *SRegion) GetDBInstanceAccounts(instanceId string, offset int, limit int) ([]SDBInstanceAccount, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := map[string]string{ + "RegionId": region.RegionId, + "PageSize": fmt.Sprintf("%d", limit), + "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), + "DBInstanceId": instanceId, + } + body, err := region.rdsRequest("DescribeAccounts", params) + if err != nil { + return nil, 0, errors.Wrap(err, "DescribeAccounts") + } + accounts := []SDBInstanceAccount{} + err = body.Unmarshal(&accounts, "Accounts", "DBInstanceAccount") + if err != nil { + return nil, 0, errors.Wrap(err, "Unmarshal") + } + total, _ := body.Int("TotalRecordCount") + return accounts, int(total), nil +} + +func (region *SRegion) DeleteDBInstanceAccount(instanceId string, accountName string) error { + params := map[string]string{ + "RegionId": region.RegionId, + "DBInstanceId": instanceId, + "AccountName": accountName, + } + + _, err := region.rdsRequest("DeleteAccount", params) + return err +} + +func (region *SRegion) CreateDBInstanceAccount(instanceId string, name string, password string, desc string) error { + params := map[string]string{ + "RegionId": region.RegionId, + "DBInstanceId": instanceId, + "AccountName": name, + "AccountPassword": password, + "AccountDescription": desc, + } + + _, err := region.rdsRequest("CreateAccount", params) + return err + +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_backup.go new file mode 100644 index 0000000000..8165fc140d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_backup.go @@ -0,0 +1,304 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strings" + "time" + + "github.com/coredns/coredns/plugin/pkg/log" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceBackup struct { + multicloud.SDBInstanceBackupBase + ApsaraTags + region *SRegion + + BackupDBNames string + BackupIntranetDownloadURL string + BackupDownloadURL string + BackupEndTime time.Time + BackupId string + BackupLocation string + BackupMethod string + BackupMode string + BackupScale string + BackupSize int + BackupStartTime time.Time + BackupStatus string + BackupType string + DBInstanceId string + HostInstanceID int + MetaStatus string + StoreStatus string +} + +func (backup *SDBInstanceBackup) GetId() string { + return backup.BackupId +} + +func (backup *SDBInstanceBackup) GetGlobalId() string { + return backup.BackupId +} + +func (backup *SDBInstanceBackup) GetName() string { + return backup.BackupId +} + +func (backup *SDBInstanceBackup) GetStartTime() time.Time { + return backup.BackupStartTime +} + +func (backup *SDBInstanceBackup) GetEndTime() time.Time { + return backup.BackupEndTime +} + +func (backup *SDBInstanceBackup) GetBackupMode() string { + switch backup.BackupMode { + case "Manual": + return api.BACKUP_MODE_MANUAL + default: + return api.BACKUP_MODE_AUTOMATED + } +} + +func (backup *SDBInstanceBackup) GetStatus() string { + switch backup.BackupStatus { + case "Success": + return api.DBINSTANCE_BACKUP_READY + case "Failed": + return api.DBINSTANCE_BACKUP_FAILED + default: + return api.DBINSTANCE_BACKUP_UNKNOWN + } +} + +func (backup *SDBInstanceBackup) GetBackupSizeMb() int { + return backup.BackupSize / 1024 / 1024 +} + +func (backup *SDBInstanceBackup) GetDBNames() string { + return backup.BackupDBNames +} + +func (backup *SDBInstanceBackup) GetEngine() string { + instance, _ := backup.region.GetDBInstanceDetail(backup.DBInstanceId) + if instance != nil { + return instance.Engine + } + return "" +} + +func (backup *SDBInstanceBackup) GetEngineVersion() string { + instance, _ := backup.region.GetDBInstanceDetail(backup.DBInstanceId) + if instance != nil { + return instance.EngineVersion + } + return "" +} + +func (backup *SDBInstanceBackup) GetDBInstanceId() string { + return backup.DBInstanceId +} + +func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string, offset int, limit int) ([]SDBInstanceBackup, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := map[string]string{ + "RegionId": region.RegionId, + "PageSize": fmt.Sprintf("%d", limit), + "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), + "DBInstanceId": instanceId, + } + if len(backupId) > 0 { + params["BackupId"] = backupId + } + body, err := region.rdsRequest("DescribeBackups", params) + if err != nil { + return nil, 0, errors.Wrap(err, "DescribeBackups") + } + backups := []SDBInstanceBackup{} + err = body.Unmarshal(&backups, "Items", "Backup") + if err != nil { + return nil, 0, errors.Wrap(err, "Unmarshal") + } + total, _ := body.Int("TotalRecordCount") + return backups, int(total), nil +} + +func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + dbinstnaces, err := region.GetIDBInstances() + if err != nil { + return nil, err + } + ibackups := []cloudprovider.ICloudDBInstanceBackup{} + for i := 0; i < len(dbinstnaces); i++ { + _dbinstance := dbinstnaces[i].(*SDBInstance) + _ibackup, err := _dbinstance.GetIDBInstanceBackups() + if err != nil { + return nil, errors.Wrapf(err, "_dbinstance(%v).GetIDBInstanceBackups", _dbinstance) + } + ibackups = append(ibackups, _ibackup...) + } + return ibackups, nil +} + +func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + backups := []SDBInstanceBackup{} + for { + parts, total, err := rds.region.GetDBInstanceBackups(rds.DBInstanceId, "", len(backups), 50) + if err != nil { + return nil, err + } + backups = append(backups, parts...) + if len(backups) >= total { + break + } + } + + ibackups := []cloudprovider.ICloudDBInstanceBackup{} + for i := 0; i < len(backups); i++ { + backups[i].region = rds.region + ibackups = append(ibackups, &backups[i]) + } + return ibackups, nil +} + +func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { + params := map[string]string{ + "DBInstanceId": rds.DBInstanceId, + } + switch rds.Engine { + case api.DBINSTANCE_TYPE_MYSQL: + if utils.IsInStringArray(rds.EngineVersion, []string{"5.7", "8.0"}) && ((utils.IsInStringArray(rds.GetStorageType(), []string{ + api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_ESSD, + api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD, + }) && rds.GetCategory() == api.ALIYUN_DBINSTANCE_CATEGORY_HA) || + (rds.GetStorageType() == api.ALIYUN_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD && + rds.GetCategory() == api.ALIYUN_DBINSTANCE_CATEGORY_BASIC)) { + params["BackupMethod"] = "Snapshot" + } else { + params["BackupMethod"] = "Physical" + if len(conf.Databases) > 0 { + params["BackupStrategy"] = "db" + params["DBName"] = strings.Join(conf.Databases, ",") + params["BackupMethod"] = "Logical" + } + } + case api.DBINSTANCE_TYPE_MARIADB: + params["BackupMethod"] = "Snapshot" + case api.DBINSTANCE_TYPE_SQLSERVER: + params["BackupMethod"] = "Physical" + case api.DBINSTANCE_TYPE_POSTGRESQL: + if rds.GetStorageType() == api.ALIYUN_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD { + params["BackupMethod"] = "Physical" + } else { + params["BackupMethod"] = "Snapshot" + } + case api.DBINSTANCE_TYPE_PPAS: + params["BackupMethod"] = "Physical" + } + body, err := rds.region.rdsRequest("CreateBackup", params) + if err != nil { + return "", errors.Wrap(err, "CreateBackup") + } + jobId, err := body.GetString("BackupJobId") + if err != nil { + return "", errors.Wrap(err, "body.BackupJobId") + } + return "", rds.region.waitBackupCreateComplete(rds.DBInstanceId, jobId) +} + +func (backup *SDBInstanceBackup) Delete() error { + return backup.region.DeleteDBInstanceBackup(backup.DBInstanceId, backup.BackupId) +} + +func (region *SRegion) DeleteDBInstanceBackup(instanceId string, backupId string) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "BackupId": backupId, + } + _, err := region.rdsRequest("DeleteBackup", params) + return err +} + +type SDBInstanceBackupJob struct { + BackupProgressStatus string + Process string + JobMode string + TaskAction string + BackupStatus string + BackupJobId string +} + +type SDBInstanceBackupJobs struct { + BackupJob []SDBInstanceBackupJob +} + +func (region *SRegion) GetDBInstanceBackupJobs(instanceId, jobId string) (*SDBInstanceBackupJobs, error) { + params := map[string]string{ + "DBInstanceId": instanceId, + "ClientToken": utils.GenRequestId(20), + "BackupMode": "Manual", + } + if len(jobId) > 0 { + params["BackupJobId"] = jobId + } + body, err := region.rdsRequest("DescribeBackupTasks", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeBackupTasks") + } + + jobs := SDBInstanceBackupJobs{} + + err = body.Unmarshal(&jobs, "Items") + if err != nil { + return nil, errors.Wrapf(err, "body.Unmarshal(%s)", body) + } + + return &jobs, nil +} + +func (region *SRegion) waitBackupCreateComplete(instanceId, jobId string) error { + for i := 0; i < 20*40; i++ { + jobs, err := region.GetDBInstanceBackupJobs(instanceId, jobId) + if err != nil { + return errors.Wrapf(err, "region.GetDBInstanceBackupJobs(%s, %s)", instanceId, jobId) + } + if len(jobs.BackupJob) == 0 { + return nil + } + for _, job := range jobs.BackupJob { + log.Infof("instance %s backup job %s status: %s(%s)", instanceId, jobId, job.BackupStatus, job.Process) + if job.BackupStatus == "Finished" && job.BackupJobId == jobId { + return nil + } + if job.BackupStatus == "Failed" && job.BackupJobId == jobId { + return fmt.Errorf("instance %s backup job %s failed", instanceId, jobId) + } + } + time.Sleep(time.Second * 3) + } + return fmt.Errorf("timeout for waiting create job complete") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_database.go new file mode 100644 index 0000000000..4939ce659c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_database.go @@ -0,0 +1,118 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceDatabase struct { + multicloud.SDBInstanceDatabaseBase + ApsaraTags + instance *SDBInstance + + CharacterSetName string + DBDescription string + DBInstanceId string + DBName string + DBStatus string + Engine string +} + +func (database *SDBInstanceDatabase) GetId() string { + return database.DBName +} + +func (database *SDBInstanceDatabase) GetGlobalId() string { + return database.DBName +} + +func (database *SDBInstanceDatabase) GetName() string { + return database.DBName +} + +func (database *SDBInstanceDatabase) GetStatus() string { + switch database.DBStatus { + case "Creating": + return api.DBINSTANCE_DATABASE_CREATING + case "Running": + return api.DBINSTANCE_DATABASE_RUNNING + case "Deleting": + return api.DBINSTANCE_DATABASE_DELETING + } + return database.DBStatus +} + +func (database *SDBInstanceDatabase) GetCharacterSet() string { + return database.CharacterSetName +} + +func (database *SDBInstanceDatabase) Delete() error { + return database.instance.region.DeleteDBInstanceDatabase(database.DBInstanceId, database.DBName) +} + +func (region *SRegion) DeleteDBInstanceDatabase(instanceId string, dbName string) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "DBName": dbName, + } + + _, err := region.rdsRequest("DeleteDatabase", params) + return err +} + +func (region *SRegion) CreateDBInstanceDatabae(instanceId, characterSet, dbName, desc string) error { + params := map[string]string{ + "DBInstanceId": instanceId, + "DBName": dbName, + "CharacterSetName": characterSet, + "DBDescription": desc, + } + + _, err := region.rdsRequest("CreateDatabase", params) + return err + +} + +func (region *SRegion) GetDBInstanceDatabases(instanceId, dbName string, offset int, limit int) ([]SDBInstanceDatabase, int, error) { + if limit > 500 || limit <= 0 { + limit = 500 + } + params := map[string]string{ + "RegionId": region.RegionId, + "PageSize": fmt.Sprintf("%d", limit), + "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), + "DBInstanceId": instanceId, + } + if len(dbName) > 0 { + params["DBName"] = dbName + } + body, err := region.rdsRequest("DescribeDatabases", params) + if err != nil { + return nil, 0, errors.Wrap(err, "DescribeDatabases") + } + databases := []SDBInstanceDatabase{} + err = body.Unmarshal(&databases, "Databases", "Database") + if err != nil { + return nil, 0, errors.Wrap(err, "Unmarshal") + } + total, _ := body.Int("TotalRecordCount") + return databases, int(total), nil +} diff --git a/pkg/multicloud/apsara/dbinstance_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_parameter.go similarity index 100% rename from pkg/multicloud/apsara/dbinstance_parameter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_parameter.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_privilege.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_privilege.go new file mode 100644 index 0000000000..95256acc3b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/dbinstance_privilege.go @@ -0,0 +1,55 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +type SDatabasePrivilege struct { + account *SDBInstanceAccount + + AccountPrivilege string + AccountPrivilegeDetail string + DBName string +} + +func (privilege *SDatabasePrivilege) GetGlobalId() string { + return fmt.Sprintf("%s/%s", privilege.account.GetName(), privilege.DBName) +} + +func (privilege *SDatabasePrivilege) GetPrivilege() string { + switch privilege.AccountPrivilege { + case "ReadWrite": + return api.DATABASE_PRIVILEGE_RW + case "ReadOnly": + return api.DATABASE_PRIVILEGE_R + case "DDLOnly": + return api.DATABASE_PRIVILEGE_DDL + case "DMLOnly": + return api.DATABASE_PRIVILEGE_DML + case "DBOwner": + return api.DATABASE_PRIVILEGE_OWNER + case "Custom": + return api.DBINSTANCE_DATABASE_CREATING + } + return privilege.AccountPrivilege +} + +func (privilege *SDatabasePrivilege) GetDBName() string { + return privilege.DBName +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/disk.go new file mode 100644 index 0000000000..54d9fac5c0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/disk.go @@ -0,0 +1,439 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SMountInstances struct { + MountInstance []string +} + +type STags struct { + Tag []string +} + +type SDisk struct { + multicloud.SResourceBase + ApsaraTags + storage *SStorage + multicloud.SDisk + + AttachedTime time.Time + AutoSnapshotPolicyId string + Category string + PerformanceLevel string + CreationTime time.Time + DeleteAutoSnapshot bool + DeleteWithInstance bool + Description string + DetachedTime time.Time + Device string + DiskChargeType TChargeType + DiskId string + DiskName string + EnableAutoSnapshot bool + EnableAutomatedSnapshotPolicy bool + Encrypted bool + ExpiredTime time.Time + ImageId string + InstanceId string + MountInstances SMountInstances + OperationLocks SOperationLocks + Portable bool + ProductCode string + RegionId string + Size int + SourceSnapshotId string + Status string + Tags STags + Type string + ZoneId string + DepartmentInfo +} + +func (self *SRegion) GetDisks(instanceId string, zoneId string, category string, diskIds []string, offset int, limit int) ([]SDisk, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if len(instanceId) > 0 { + params["InstanceId"] = instanceId + } + if len(zoneId) > 0 { + params["ZoneId"] = zoneId + } + if len(category) > 0 { + params["Category"] = category + } + if diskIds != nil && len(diskIds) > 0 { + params["DiskIds"] = jsonutils.Marshal(diskIds).String() + } + + body, err := self.ecsRequest("DescribeDisks", params) + if err != nil { + log.Errorf("GetDisks fail %s", err) + return nil, 0, err + } + + disks := make([]SDisk, 0) + err = body.Unmarshal(&disks, "Disks", "Disk") + if err != nil { + log.Errorf("Unmarshal disk details fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return disks, int(total), nil +} + +func (self *SDisk) GetId() string { + return self.DiskId +} + +func (self *SDisk) Delete(ctx context.Context) error { + _, err := self.storage.zone.region.getDisk(self.DiskId) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + // 未找到disk, 说明disk已经被删除了. 避免回收站中disk-delete循环删除失败 + return nil + } + log.Errorf("Failed to find disk %s when delete: %s", self.DiskId, err) + return err + } + + for { + err := self.storage.zone.region.DeleteDisk(self.DiskId) + if err != nil { + if isError(err, "IncorrectDiskStatus") { + log.Infof("The disk is initializing, try later ...") + time.Sleep(10 * time.Second) + } else { + log.Errorf("DeleteDisk fail: %s", err) + return err + } + } else { + break + } + } + return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes +} + +func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { + return self.storage.zone.region.resizeDisk(self.DiskId, sizeMb) +} + +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) IsEmulated() bool { + return false +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +func (self *SDisk) GetStatus() string { + // In_use Available Attaching Detaching Creating ReIniting All + switch self.Status { + case "Creating", "ReIniting": + return api.DISK_ALLOCATING + default: + return api.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) ResizeDisk(newSize int64) error { + // newSize 单位为 GB. 范围在20 ~2000. 只能往大调。不能调小 + // https://help.apsara.com/document_detail/25522.html?spm=a2c4g.11174283.6.897.aHwqkS + return self.storage.zone.region.resizeDisk(self.DiskId, newSize) +} + +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 { + switch self.Type { + case "system": + return api.DISK_TYPE_SYS + case "data": + return api.DISK_TYPE_DATA + default: + return api.DISK_TYPE_DATA + } +} + +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 *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, desc string, projectId string) (string, error) { + params := make(map[string]string) + params["ZoneId"] = zoneId + params["DiskName"] = name + if len(desc) > 0 { + params["Description"] = desc + } + params["Encrypted"] = "false" + params["DiskCategory"] = category + if category == api.STORAGE_CLOUD_ESSD_PL2 { + params["DiskCategory"] = api.STORAGE_CLOUD_ESSD + params["PerformanceLevel"] = "PL2" + } + if category == api.STORAGE_CLOUD_ESSD_PL3 { + params["DiskCategory"] = api.STORAGE_CLOUD_ESSD + params["PerformanceLevel"] = "PL3" + } + + if len(projectId) > 0 { + params["ResourceGroupId"] = projectId + } + params["Size"] = fmt.Sprintf("%d", sizeGb) + params["ClientToken"] = utils.GenRequestId(20) + + body, err := self.ecsRequest("CreateDisk", params) + if err != nil { + return "", err + } + return body.GetString("DiskId") +} + +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 { + params := make(map[string]string) + params["DiskId"] = diskId + + _, err := self.ecsRequest("DeleteDisk", params) + return err +} + +func (self *SRegion) resizeDisk(diskId string, sizeMb int64) error { + sizeGb := sizeMb / 1024 + params := make(map[string]string) + params["DiskId"] = diskId + params["NewSize"] = fmt.Sprintf("%d", sizeGb) + + _, err := self.ecsRequest("ResizeDisk", params) + if err != nil { + log.Errorf("resizing disk (%s) to %d GiB failed: %s", diskId, sizeGb, err) + return err + } + + return nil +} + +func (self *SRegion) resetDisk(diskId, snapshotId string) error { + params := make(map[string]string) + params["DiskId"] = diskId + params["SnapshotId"] = snapshotId + _, err := self.ecsRequest("ResetDisk", params) + if err != nil { + log.Errorf("ResetDisk %s to snapshot %s fail %s", diskId, snapshotId, err) + return err + } + + return nil +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name, 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, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil { + return nil, err + } + return snapshot, nil + } +} + +func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["DiskId"] = diskId + params["SnapshotName"] = name + params["Description"] = desc + + if body, err := self.ecsRequest("CreateSnapshot", params); err != nil { + log.Errorf("CreateSnapshot fail %s", err) + return "", err + } else { + return body.GetString("SnapshotId") + } +} + +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) 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 *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) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", self.storage.zone.region.resetDisk(self.DiskId, snapshotId) +} + +func (self *SDisk) GetBillingType() string { + return convertChargeType(self.DiskChargeType) +} + +func (self *SDisk) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { + if len(self.AutoSnapshotPolicyId) == 0 { + return []string{}, nil + } + return []string{self.AutoSnapshotPolicyId}, nil +} + +func (self *SDisk) GetExpiredAt() time.Time { + return convertExpiredAt(self.ExpiredTime) +} + +func (self *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + err := self.storage.zone.region.rebuildDisk(self.DiskId) + if err != nil { + if isError(err, "IncorrectInstanceStatus") { + return nil + } + log.Errorf("rebuild disk fail %s", err) + return err + } + return nil +} + +func (self *SRegion) rebuildDisk(diskId string) error { + params := make(map[string]string) + params["DiskId"] = diskId + _, err := self.ecsRequest("ReInitDisk", params) + if err != nil { + log.Errorf("ReInitDisk %s fail %s", diskId, err) + return err + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/doc.go new file mode 100644 index 0000000000..10d9b8ea2b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 apsara // import "yunion.io/x/cloudmux/pkg/multicloud/apsara" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/eip.go new file mode 100644 index 0000000000..2e9774055a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/eip.go @@ -0,0 +1,378 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type TInternetChargeType string + +const ( + InternetChargeByTraffic = TInternetChargeType("PayByTraffic") + InternetChargeByBandwidth = TInternetChargeType("PayByBandwidth") +) + +const ( + EIP_STATUS_ASSOCIATING = "Associating" + EIP_STATUS_UNASSOCIATING = "Unassociating" + EIP_STATUS_INUSE = "InUse" + EIP_STATUS_AVAILABLE = "Available" + + EIP_OPERATION_LOCK_FINANCIAL = "financial" + EIP_OPERATION_LOCK_SECURITY = "security" + + EIP_INSTANCE_TYPE_ECS = "EcsInstance" // (默认值):VPC类型的ECS实例 + EIP_INTANNCE_TYPE_SLB = "SlbInstance" // :VPC类型的SLB实例 + EIP_INSTANCE_TYPE_NAT = "Nat" // :NAT网关 + EIP_INSTANCE_TYPE_HAVIP = "HaVip" // :HAVIP +) + +/* +{ + "AllocationId":"eip-2zeddtan63ou44dtyt9s3", + "AllocationTime":"2019-02-23T06:48:36Z", + "Bandwidth":"100", + "ChargeType":"PostPaid", + "ExpiredTime":"", + "InstanceId":"", + "InstanceType":"", + "InternetChargeType":"PayByTraffic", + "IpAddress":"39.105.131.32", + "OperationLocks":{"LockReason":[]}, + "RegionId":"cn-beijing", + "Status":"Available" +} +*/ + +type SEipAddress struct { + region *SRegion + multicloud.SEipBase + ApsaraTags + + AllocationId string + + InternetChargeType TInternetChargeType + + IpAddress string + Status string + + InstanceType string + InstanceId string + Bandwidth int /* Mbps */ + + AllocationTime time.Time + + OperationLocks string + + ChargeType TChargeType + ExpiredTime time.Time + DepartmentInfo +} + +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 { + case EIP_STATUS_AVAILABLE, EIP_STATUS_INUSE: + return api.EIP_STATUS_READY + case EIP_STATUS_ASSOCIATING: + return api.EIP_STATUS_ASSOCIATE + case EIP_STATUS_UNASSOCIATING: + return api.EIP_STATUS_DISSOCIATE + default: + return api.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 { + // fixed Public IP + return true + } else { + return false + } +} + +func (self *SEipAddress) GetIpAddr() string { + return self.IpAddress +} + +func (self *SEipAddress) GetMode() string { + if self.InstanceId == self.AllocationId { + return api.EIP_MODE_INSTANCE_PUBLICIP + } else { + return api.EIP_MODE_STANDALONE_EIP + } +} + +func (self *SEipAddress) GetAssociationType() string { + switch self.InstanceType { + case EIP_INSTANCE_TYPE_ECS, "NetworkInterface": + return api.EIP_ASSOCIATE_TYPE_SERVER + case EIP_INSTANCE_TYPE_NAT: + return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY + case EIP_INTANNCE_TYPE_SLB: + return api.EIP_ASSOCIATE_TYPE_LOADBALANCER + default: + return self.InstanceType + } +} + +func (self *SEipAddress) GetAssociationExternalId() string { + return self.InstanceId +} + +func (self *SEipAddress) GetBillingType() string { + return convertChargeType(self.ChargeType) +} + +func (self *SEipAddress) GetCreatedAt() time.Time { + return self.AllocationTime +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return convertExpiredAt(self.ExpiredTime) +} + +func (self *SEipAddress) Delete() error { + return self.region.DeallocateEIP(self.AllocationId) +} + +func (self *SEipAddress) GetBandwidth() int { + return self.Bandwidth +} + +func (self *SEipAddress) GetINetworkId() string { + return "" +} + +func (self *SEipAddress) GetInternetChargeType() string { + switch self.InternetChargeType { + case InternetChargeByTraffic: + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + case InternetChargeByBandwidth: + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH + default: + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + } +} + +func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { + err := cloudprovider.Wait(20*time.Second, 60*time.Second, func() (bool, error) { + err := self.region.AssociateEip(self.AllocationId, conf.InstanceId) + if err != nil { + if isError(err, "IncorrectInstanceStatus") { + return false, nil + } + return false, errors.Wrap(err, "region.AssociateEip") + } + return true, nil + }) + err = cloudprovider.WaitStatus(self, api.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, api.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 (region *SRegion) GetEips(eipId string, associatedId string, offset int, limit int) ([]SEipAddress, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if len(eipId) > 0 { + params["AllocationId"] = eipId + } + + if len(associatedId) > 0 { + params["AssociatedInstanceId"] = associatedId + for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "ngw-": "Nat", "lb-": "SlbInstance"} { + if strings.HasPrefix(associatedId, prefix) { + params["AssociatedInstanceType"] = instanceType + } + } + } + + body, err := region.vpcRequest("DescribeEipAddresses", params) + if err != nil { + log.Errorf("DescribeEipAddresses fail %s", err) + return nil, 0, err + } + + eips := make([]SEipAddress, 0) + err = body.Unmarshal(&eips, "EipAddresses", "EipAddress") + if err != nil { + log.Errorf("Unmarshal EipAddress details fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + for i := 0; i < len(eips); i += 1 { + eips[i].region = region + } + return eips, int(total), nil +} + +func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { + eips, total, err := region.GetEips(eipId, "", 0, 1) + if err != nil { + return nil, err + } + if total != 1 { + return nil, cloudprovider.ErrNotFound + } + return &eips[0], nil +} + +func (region *SRegion) AllocateEIP(bwMbps int, chargeType TInternetChargeType, projectId string) (*SEipAddress, error) { + params := make(map[string]string) + + params["Bandwidth"] = fmt.Sprintf("%d", bwMbps) + params["InternetChargeType"] = string(chargeType) + params["InstanceChargeType"] = "PostPaid" + params["ClientToken"] = utils.GenRequestId(20) + if len(projectId) > 0 { + params["ResourceGroup"] = projectId + } + + body, err := region.vpcRequest("AllocateEipAddress", params) + if err != nil { + log.Errorf("AllocateEipAddress fail %s", err) + return nil, err + } + + eipId, err := body.GetString("AllocationId") + if err != nil { + log.Errorf("fail to get AllocationId after EIP allocation??? %s", err) + return nil, err + } + + return region.GetEip(eipId) +} + +func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + var ctype TInternetChargeType + switch eip.ChargeType { + case api.EIP_CHARGE_TYPE_BY_TRAFFIC: + ctype = InternetChargeByTraffic + case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: + ctype = InternetChargeByBandwidth + } + return region.AllocateEIP(eip.BandwidthMbps, ctype, eip.ProjectId) +} + +func (region *SRegion) DeallocateEIP(eipId string) error { + params := make(map[string]string) + params["AllocationId"] = eipId + + _, err := region.ecsRequest("ReleaseEipAddress", params) + if err != nil { + log.Errorf("ReleaseEipAddress fail %s", err) + } + return err +} + +func (region *SRegion) AssociateEip(eipId string, instanceId string) error { + params := make(map[string]string) + params["AllocationId"] = eipId + params["InstanceId"] = instanceId + for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "lb-": "SlbInstance", "ngw-": "Nat"} { + if strings.HasPrefix(instanceId, prefix) { + params["InstanceType"] = instanceType + } + } + + _, err := region.ecsRequest("AssociateEipAddress", params) + if err != nil { + log.Errorf("AssociateEipAddress fail %s", err) + } + return err +} + +func (region *SRegion) DissociateEip(eipId string, instanceId string) error { + params := make(map[string]string) + params["AllocationId"] = eipId + params["InstanceId"] = instanceId + for prefix, instanceType := range map[string]string{"i-": "EcsInstance", "lb-": "SlbInstance", "ngw-": "Nat"} { + if strings.HasPrefix(instanceId, prefix) { + params["InstanceType"] = instanceType + } + } + + _, err := region.ecsRequest("UnassociateEipAddress", params) + if err != nil { + log.Errorf("UnassociateEipAddress fail %s", err) + } + return err +} + +func (region *SRegion) UpdateEipBandwidth(eipId string, bw int) error { + params := make(map[string]string) + params["AllocationId"] = eipId + params["Bandwidth"] = fmt.Sprintf("%d", bw) + + _, err := region.ecsRequest("ModifyEipAddressAttribute", params) + if err != nil { + log.Errorf("ModifyEipAddressAttribute fail %s", err) + } + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_account.go new file mode 100644 index 0000000000..91929d3fac --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_account.go @@ -0,0 +1,212 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://help.apsara.com/document_detail/95802.html?spm=a2c4g.11186623.6.746.1d4b302ayCuzXB +type SElasticcacheAccount struct { + multicloud.SElasticcacheAccountBase + ApsaraTags + + cacheDB *SElasticcache + + AccountStatus string `json:"AccountStatus"` + DatabasePrivileges DatabasePrivileges `json:"DatabasePrivileges"` + InstanceID string `json:"InstanceId"` + AccountName string `json:"AccountName"` + PrivExceeded string `json:"PrivExceeded"` + AccountType string `json:"AccountType"` +} + +type DatabasePrivileges struct { + DatabasePrivilege []DatabasePrivilege `json:"DatabasePrivilege"` +} + +type DatabasePrivilege struct { + AccountPrivilege string `json:"AccountPrivilege"` +} + +func (self *SElasticcacheAccount) GetId() string { + return fmt.Sprintf("%s/%s", self.InstanceID, self.AccountName) +} + +func (self *SElasticcacheAccount) GetName() string { + return self.AccountName +} + +func (self *SElasticcacheAccount) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheAccount) GetStatus() string { + switch strings.ToLower(self.AccountStatus) { + case "unavailable": + return api.ELASTIC_CACHE_ACCOUNT_STATUS_UNAVAILABLE + case "available": + return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE + default: + return self.AccountStatus + } +} + +func (self *SElasticcacheAccount) Refresh() error { + iaccount, err := self.cacheDB.GetICloudElasticcacheAccountByName(self.GetName()) + if err != nil { + return err + } + + err = jsonutils.Update(self, iaccount.(*SElasticcacheAccount)) + if err != nil { + return err + } + + return nil +} + +func (self *SElasticcacheAccount) GetAccountType() string { + if self.AccountName == self.cacheDB.InstanceID { + return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN + } + + switch self.AccountType { + case "Normal": + return api.ELASTIC_CACHE_ACCOUNT_TYPE_NORMAL + case "Super": + return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN + default: + return self.AccountType + } +} + +func (self *SElasticcacheAccount) GetAccountPrivilege() string { + if len(self.DatabasePrivileges.DatabasePrivilege) == 0 { + return "" + } + + privilege := self.DatabasePrivileges.DatabasePrivilege[0].AccountPrivilege + switch privilege { + case "RoleReadOnly": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_READ + case "RoleReadWrite": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE + case "RoleRepl": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_REPL + default: + return privilege + } +} + +// https://help.apsara.com/document_detail/95941.html?spm=a2c4g.11186623.6.746.523555d8D8Whxq +// https://help.apsara.com/document_detail/98531.html?spm=5176.11065259.1996646101.searchclickresult.4df474c38Sc2SO +func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + params["AccountPassword"] = input.NewPassword + + err := DoAction(self.cacheDB.region.kvsRequest, "ResetAccountPassword", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.ResetPassword") + } + + if input.NoPasswordAccess != nil { + return cloudprovider.ErrNotSupported + } + + return nil +} + +func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { + if input.Password != nil { + inputPassword := cloudprovider.SCloudElasticCacheAccountResetPasswordInput{} + inputPassword.NewPassword = *input.Password + inputPassword.NoPasswordAccess = input.NoPasswordAccess + err := self.ResetPassword(inputPassword) + if err != nil { + return err + } + } + + if input.Description != nil { + err := self.ModifyAccountDescription(*input.Description) + if err != nil { + return err + } + } + + if input.AccountPrivilege != nil { + err := self.GrantAccountPrivilege(*input.AccountPrivilege) + if err != nil { + return err + } + } + + return nil +} + +// https://help.apsara.com/document_detail/96020.html?spm=a2c4g.11186623.6.747.5c6f1c717weYEX +func (self *SElasticcacheAccount) ModifyAccountDescription(desc string) error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + params["AccountDescription"] = desc + + err := DoAction(self.cacheDB.region.kvsRequest, "ModifyAccountDescription", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.ModifyAccountDescription") + } + + return nil +} + +// https://help.apsara.com/document_detail/95897.html?spm=a2c4g.11186623.6.745.28576cf9IqM44R +func (self *SElasticcacheAccount) GrantAccountPrivilege(privilege string) error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + params["AccountPrivilege"] = privilege + + err := DoAction(self.cacheDB.region.kvsRequest, "GrantAccountPrivilege", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.GrantAccountPrivilege") + } + + return nil +} + +// https://help.apsara.com/document_detail/95988.html?spm=a2c4g.11186623.6.743.cb291c71D1Hlmu +func (self *SElasticcacheAccount) Delete() error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.GetName() + + err := DoAction(self.cacheDB.region.kvsRequest, "DeleteAccount", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.Delete") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_acl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_acl.go new file mode 100644 index 0000000000..493ec9269e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_acl.go @@ -0,0 +1,106 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElasticcacheAcl struct { + multicloud.SElasticcacheAclBase + ApsaraTags + + cacheDB *SElasticcache + + SecurityIPList string `json:"SecurityIpList"` + SecurityIPGroupAttribute string `json:"SecurityIpGroupAttribute"` + SecurityIPGroupName string `json:"SecurityIpGroupName"` +} + +func (self *SElasticcacheAcl) GetId() string { + return fmt.Sprintf("%s/%s", self.cacheDB.GetId(), self.SecurityIPGroupName) +} + +func (self *SElasticcacheAcl) GetName() string { + return self.SecurityIPGroupName +} + +func (self *SElasticcacheAcl) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheAcl) GetStatus() string { + return api.ELASTIC_CACHE_ACL_STATUS_AVAILABLE +} + +func (self *SElasticcacheAcl) Refresh() error { + iacl, err := self.cacheDB.GetICloudElasticcacheAcl(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, iacl.(*SElasticcacheAcl)) + if err != nil { + return err + } + + return nil +} + +func (self *SElasticcacheAcl) GetIpList() string { + return self.SecurityIPList +} + +// https://help.apsara.com/document_detail/61002.html?spm=a2c4g.11186623.6.764.3752782fJpbjxH +func (self *SElasticcacheAcl) Delete() error { + params := make(map[string]string) + params["InstanceId"] = self.cacheDB.GetId() + params["ModifyMode"] = "Delete" + params["SecurityIpGroupName"] = self.GetName() + params["SecurityIps"] = self.SecurityIPList + + err := DoAction(self.cacheDB.region.kvsRequest, "ModifySecurityIps", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAcl.Delete") + } + + return nil +} + +// https://help.apsara.com/document_detail/61002.html?spm=a2c4g.11186623.6.764.3752782fJpbjxH +func (self *SElasticcacheAcl) UpdateAcl(securityIps string) error { + return self.cacheDB.region.createAcl(self.cacheDB.GetId(), self.GetName(), securityIps) +} + +func (self *SRegion) createAcl(instanceId, aclName, securityIps string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["SecurityIpGroupName"] = aclName + params["ModifyMode"] = "Cover" + params["SecurityIps"] = securityIps + + err := DoAction(self.kvsRequest, "ModifySecurityIps", params, nil, nil) + if err != nil { + return errors.Wrap(err, "region.UpdateAcl") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_backup.go new file mode 100644 index 0000000000..ea931dcff2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_backup.go @@ -0,0 +1,143 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://help.apsara.com/document_detail/61081.html?spm=a2c4g.11186623.6.752.3d7630beuL57kI +type SElasticcacheBackup struct { + multicloud.SElasticcacheBackupBase + ApsaraTags + + cacheDB *SElasticcache + + BackupIntranetDownloadURL string `json:"BackupIntranetDownloadURL"` + BackupType string `json:"BackupType"` + BackupEndTime time.Time `json:"BackupEndTime"` + BackupMethod string `json:"BackupMethod"` + BackupID int64 `json:"BackupId"` + BackupStartTime time.Time `json:"BackupStartTime"` + BackupDownloadURL string `json:"BackupDownloadURL"` + BackupDBNames string `json:"BackupDBNames"` + NodeInstanceID string `json:"NodeInstanceId"` + BackupMode string `json:"BackupMode"` + BackupStatus string `json:"BackupStatus"` + BackupSizeByte int64 `json:"BackupSize"` + EngineVersion string `json:"EngineVersion"` +} + +func (self *SElasticcacheBackup) GetId() string { + return fmt.Sprintf("%d", self.BackupID) +} + +func (self *SElasticcacheBackup) GetName() string { + return self.GetId() +} + +func (self *SElasticcacheBackup) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheBackup) GetStatus() string { + switch self.BackupStatus { + case "Success", "running": + return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS + case "Failed": + return api.ELASTIC_CACHE_BACKUP_STATUS_FAILED + default: + return self.BackupStatus + } +} + +func (self *SElasticcacheBackup) Refresh() error { + ibackup, err := self.cacheDB.GetICloudElasticcacheBackup(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, ibackup.(*SElasticcacheBackup)) + if err != nil { + return err + } + + return nil +} + +func (self *SElasticcacheBackup) GetBackupSizeMb() int { + return int(self.BackupSizeByte / 1024 / 1024) +} + +func (self *SElasticcacheBackup) GetBackupType() string { + switch self.BackupType { + case "FullBackup": + return api.ELASTIC_CACHE_BACKUP_TYPE_FULL + case "IncrementalBackup": + return api.ELASTIC_CACHE_BACKUP_TYPE_INCREMENTAL + default: + return self.BackupType + } +} + +func (self *SElasticcacheBackup) GetBackupMode() string { + switch self.BackupMode { + case "Automated": + return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED + case "Manual": + return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL + default: + return self.BackupMode + } +} + +func (self *SElasticcacheBackup) GetDownloadURL() string { + return self.BackupDownloadURL +} + +func (self *SElasticcacheBackup) GetStartTime() time.Time { + return self.BackupStartTime +} + +func (self *SElasticcacheBackup) GetEndTime() time.Time { + return self.BackupEndTime +} + +func (self *SElasticcacheBackup) Delete() error { + return cloudprovider.ErrNotSupported +} + +// https://help.apsara.com/document_detail/61083.html?spm=a2c4g.11186623.6.753.216f67ddzpyvTL +func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["BackupId"] = self.GetId() + + // 目前没有查询备份ID的接口,因此,备份ID没什么用 + err := DoAction(self.cacheDB.region.kvsRequest, "RestoreInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.RestoreInstance") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_instance.go new file mode 100644 index 0000000000..be7eb76f87 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_instance.go @@ -0,0 +1,941 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/aokoli/goutils" + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + billingapi "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +// https://help.apsara.com/document_detail/60933.html?spm=a2c4g.11186623.6.726.38f82ca9U1Gtxw +type SElasticcache struct { + multicloud.SElasticcacheBase + multicloud.SBillingBase + ApsaraTags + + region *SRegion + attribute *SElasticcacheAttribute + netinfo []SNetInfo + + Config string `json:"Config"` + HasRenewChangeOrder bool `json:"HasRenewChangeOrder"` + InstanceID string `json:"InstanceId"` + UserName string `json:"UserName"` + ArchitectureType string `json:"ArchitectureType"` + ZoneID string `json:"ZoneId"` + PrivateIP string `json:"PrivateIp"` + VSwitchID string `json:"VSwitchId"` + VpcID string `json:"VpcId"` + NetworkType string `json:"NetworkType"` + Qps int64 `json:"QPS"` + PackageType string `json:"PackageType"` + IsRDS bool `json:"IsRds"` + EngineVersion string `json:"EngineVersion"` + ConnectionDomain string `json:"ConnectionDomain"` + InstanceName string `json:"InstanceName"` + ReplacateID string `json:"ReplacateId"` + Bandwidth int64 `json:"Bandwidth"` + ChargeType TChargeType `json:"ChargeType"` + InstanceType string `json:"InstanceType"` + Tags Tags `json:"Tags"` + InstanceStatus string `json:"InstanceStatus"` + Port int `json:"Port"` + InstanceClass string `json:"InstanceClass"` + CreateTime time.Time `json:"CreateTime"` + EndTime time.Time `json:"EndTime"` + RegionID string `json:"RegionId"` + NodeType string `json:"NodeType"` + CapacityMB int `json:"Capacity"` + Connections int64 `json:"Connections"` + + DepartmentInfo +} + +type SElasticcacheAttribute struct { + Config string `json:"Config"` + HasRenewChangeOrder string `json:"HasRenewChangeOrder"` + InstanceID string `json:"InstanceId"` + ZoneID string `json:"ZoneId"` + ArchitectureType string `json:"ArchitectureType"` + PrivateIP string `json:"PrivateIp"` + VSwitchID string `json:"VSwitchId"` + Engine string `json:"Engine"` + VpcID string `json:"VpcId"` + NetworkType string `json:"NetworkType"` + Qps int64 `json:"QPS"` + PackageType string `json:"PackageType"` + ReplicaID string `json:"ReplicaId"` + IsRDS bool `json:"IsRds"` + MaintainStartTime string `json:"MaintainStartTime"` + VpcAuthMode string `json:"VpcAuthMode"` + ConnectionDomain string `json:"ConnectionDomain"` + EngineVersion string `json:"EngineVersion"` + InstanceName string `json:"InstanceName"` + Bandwidth int64 `json:"Bandwidth"` + ChargeType TChargeType `json:"ChargeType"` + AuditLogRetention string `json:"AuditLogRetention"` + MaintainEndTime string `json:"MaintainEndTime"` + ReplicationMode string `json:"ReplicationMode"` + InstanceType string `json:"InstanceType"` + InstanceStatus string `json:"InstanceStatus"` + Tags Tags `json:"Tags"` + Port int64 `json:"Port"` + InstanceClass string `json:"InstanceClass"` + CreateTime time.Time `json:"CreateTime"` + NodeType string `json:"NodeType"` + RegionID string `json:"RegionId"` + AvailabilityValue string `json:"AvailabilityValue"` + CapacityMB int `json:"Capacity"` + Connections int64 `json:"Connections"` + SecurityIPList string `json:"SecurityIPList"` +} + +type SNetInfo struct { + ConnectionString string `json:"ConnectionString"` + Port string `json:"Port"` + DBInstanceNetType string `json:"DBInstanceNetType"` + VPCID string `json:"VPCId"` + VPCInstanceID string `json:"VPCInstanceId"` + IPAddress string `json:"IPAddress"` + IPType string `json:"IPType"` + Upgradeable string `json:"Upgradeable"` + ExpiredTime *string `json:"ExpiredTime,omitempty"` +} + +func (self *SElasticcache) GetId() string { + return self.InstanceID +} + +func (self *SElasticcache) GetName() string { + return self.InstanceName +} + +func (self *SElasticcache) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcache) GetStatus() string { + switch self.InstanceStatus { + case "Normal": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "Creating": + return api.ELASTIC_CACHE_STATUS_DEPLOYING + case "Changing": + return api.ELASTIC_CACHE_STATUS_CHANGING + case "Inactive": + return api.ELASTIC_CACHE_STATUS_INACTIVE + case "Flushing": + return api.ELASTIC_CACHE_STATUS_FLUSHING + case "Released": + return api.ELASTIC_CACHE_STATUS_RELEASED + case "Transforming": + return api.ELASTIC_CACHE_STATUS_TRANSFORMING + case "Unavailable": + return api.ELASTIC_CACHE_STATUS_UNAVAILABLE + case "Error": + return api.ELASTIC_CACHE_STATUS_ERROR + case "Migrating": + return api.ELASTIC_CACHE_STATUS_MIGRATING + case "BackupRecovering": + return api.ELASTIC_CACHE_STATUS_BACKUPRECOVERING + case "MinorVersionUpgrading": + return api.ELASTIC_CACHE_STATUS_MINORVERSIONUPGRADING + case "NetworkModifying": + return api.ELASTIC_CACHE_STATUS_NETWORKMODIFYING + case "SSLModifying": + return api.ELASTIC_CACHE_STATUS_SSLMODIFYING + case "MajorVersionUpgrading": + return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING + default: + return api.ELASTIC_CACHE_STATUS_MAJORVERSIONUPGRADING + } +} + +func (self *SElasticcache) Refresh() error { + cache, err := self.region.GetElasticCacheById(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, cache) + if err != nil { + return err + } + + return nil +} + +func (self *SElasticcache) GetBillingType() string { + return convertChargeType(self.ChargeType) +} + +func (self *SElasticcache) GetCreatedAt() time.Time { + return self.CreateTime +} + +func (self *SElasticcache) GetExpiredAt() time.Time { + return convertExpiredAt(self.EndTime) +} + +func (self *SElasticcache) GetInstanceType() string { + return self.InstanceClass +} + +func (self *SElasticcache) GetCapacityMB() int { + return self.CapacityMB +} + +func (self *SElasticcache) GetArchType() string { + switch self.ArchitectureType { + case "rwsplit": + return api.ELASTIC_CACHE_ARCH_TYPE_RWSPLIT + case "cluster": + return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER + case "standard": + if self.NodeType == "single" { + return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE + } else if self.NodeType == "double" { + return api.ELASTIC_CACHE_ARCH_TYPE_MASTER + } + } + + return "" +} + +func (self *SElasticcache) GetNodeType() string { + return self.NodeType +} + +func (self *SElasticcache) GetEngine() string { + return self.InstanceType +} + +func (self *SElasticcache) GetEngineVersion() string { + return self.EngineVersion +} + +func (self *SElasticcache) GetVpcId() string { + return self.VpcID +} + +func (self *SElasticcache) GetZoneId() string { + zone, err := self.region.getZoneById(self.ZoneID) + if err != nil { + log.Errorf("failed to find zone for elasticcache %s error: %v", self.GetId(), err) + return "" + } + return zone.GetGlobalId() +} + +func (self *SElasticcache) GetNetworkType() string { + switch self.NetworkType { + case "VPC": + return api.LB_NETWORK_TYPE_VPC + case "CLASSIC": + return api.LB_NETWORK_TYPE_CLASSIC + default: + return api.LB_NETWORK_TYPE_VPC + } +} + +func (self *SElasticcache) GetNetworkId() string { + return self.VSwitchID +} + +func (self *SElasticcache) GetPrivateDNS() string { + return self.ConnectionDomain +} + +func (self *SElasticcache) GetPrivateIpAddr() string { + return self.PrivateIP +} + +func (self *SElasticcache) GetPrivateConnectPort() int { + return self.Port +} + +func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetPublicDNS() string { + pub, err := self.GetPublicNetInfo() + if err != nil { + log.Errorf("SElasticcache.GetPublicDNS %s", err) + return "" + } + + if pub != nil { + return pub.ConnectionString + } + + return "" +} + +func (self *SElasticcache) GetPublicIpAddr() string { + pub, err := self.GetPublicNetInfo() + if err != nil { + log.Errorf("SElasticcache.GetPublicIpAddr %s", err) + } + + if pub != nil { + return pub.IPAddress + } + + return "" +} + +func (self *SElasticcache) GetPublicConnectPort() int { + pub, err := self.GetPublicNetInfo() + if err != nil { + log.Errorf("SElasticcache.GetPublicConnectPort %s", err) + } + + if pub != nil { + port, _ := strconv.Atoi(pub.Port) + return port + } + + return 0 +} + +func (self *SElasticcache) GetMaintainStartTime() string { + attr, err := self.GetAttribute() + if err != nil { + log.Errorf("SElasticcache.GetMaintainStartTime %s", err) + } + + if attr != nil { + return attr.MaintainStartTime + } + + return "" +} + +func (self *SElasticcache) GetMaintainEndTime() string { + attr, err := self.GetAttribute() + if err != nil { + log.Errorf("SElasticcache.GetMaintainEndTime %s", err) + } + + if attr != nil { + return attr.MaintainEndTime + } + + return "" +} + +func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { + accounts, err := self.region.GetElasticCacheAccounts(self.GetId()) + if err != nil { + return nil, err + } + + iaccounts := make([]cloudprovider.ICloudElasticcacheAccount, len(accounts)) + for i := range accounts { + accounts[i].cacheDB = self + iaccounts[i] = &accounts[i] + } + + return iaccounts, nil +} + +func (self *SElasticcache) GetICloudElasticcacheAccountByName(accountName string) (cloudprovider.ICloudElasticcacheAccount, error) { + account, err := self.region.GetElasticCacheAccountByName(self.GetId(), accountName) + if err != nil { + return nil, err + } + + account.cacheDB = self + return account, nil +} + +func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { + acls, err := self.region.GetElasticCacheAcls(self.GetId()) + if err != nil { + return nil, err + } + + iacls := make([]cloudprovider.ICloudElasticcacheAcl, len(acls)) + for i := range acls { + acls[i].cacheDB = self + iacls[i] = &acls[i] + } + + return iacls, nil +} + +func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { + start := self.CreateTime.Format("2006-01-02T15:04Z") + end := time.Now().Format("2006-01-02T15:04Z") + backups, err := self.region.GetElasticCacheBackups(self.GetId(), start, end) + if err != nil { + return nil, err + } + + ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) + for i := range backups { + backups[i].cacheDB = self + ibackups[i] = &backups[i] + } + + return ibackups, nil +} + +func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { + parameters, err := self.region.GetElasticCacheParameters(self.GetId()) + if err != nil { + return nil, err + } + + iparameters := make([]cloudprovider.ICloudElasticcacheParameter, len(parameters)) + for i := range parameters { + parameters[i].cacheDB = self + iparameters[i] = ¶meters[i] + } + + return iparameters, nil +} + +func (self *SElasticcache) GetAttribute() (*SElasticcacheAttribute, error) { + if self.attribute != nil { + return self.attribute, nil + } + + params := make(map[string]string) + params["RegionId"] = self.region.RegionId + params["InstanceId"] = self.GetId() + + rets := []SElasticcacheAttribute{} + err := DoListAll(self.region.kvsRequest, "DescribeInstanceAttribute", params, []string{"Instances", "DBInstanceAttribute"}, &rets) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.GetAttribute") + } + + count := len(rets) + if count >= 1 { + self.attribute = &rets[0] + return self.attribute, nil + } else { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "elasticcache.GetAttribute %s", self.GetId()) + } +} + +func (self *SElasticcache) GetNetInfo() ([]SNetInfo, error) { + params := make(map[string]string) + params["RegionId"] = self.region.RegionId + params["InstanceId"] = self.GetId() + + rets := []SNetInfo{} + err := DoListAll(self.region.kvsRequest, "DescribeDBInstanceNetInfo", params, []string{"NetInfoItems", "InstanceNetInfo"}, &rets) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.GetNetInfo") + } + + self.netinfo = rets + return self.netinfo, nil +} + +// https://help.apsara.com/document_detail/66742.html?spm=a2c4g.11186623.6.731.54c123d2P02qhk +func (self *SElasticcache) GetPublicNetInfo() (*SNetInfo, error) { + nets, err := self.GetNetInfo() + if err != nil { + return nil, err + } + + for i := range nets { + if nets[i].IPType == "Public" { + return &nets[i], nil + } + } + + return nil, nil +} + +func (self *SRegion) GetElasticCaches(instanceIds []string) ([]SElasticcache, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + if instanceIds != nil && len(instanceIds) > 0 { + params["InstanceIds"] = strings.Join(instanceIds, ",") + } + + ret := []SElasticcache{} + err := DoListAll(self.kvsRequest, "DescribeInstances", params, []string{"Instances", "KVStoreInstance"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCaches") + } + + for i := range ret { + ret[i].region = self + } + + return ret, nil +} + +func (self *SRegion) GetElasticCacheById(instanceId string) (*SElasticcache, error) { + caches, err := self.GetElasticCaches([]string{instanceId}) + if err != nil { + return nil, errors.Wrapf(err, "region.GetElasticCacheById %s", instanceId) + } + + if len(caches) == 1 { + return &caches[0], nil + } else if len(caches) == 0 { + return nil, cloudprovider.ErrNotFound + } else { + return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "region.GetElasticCacheById %s.expect 1 found %d ", instanceId, len(caches)) + } +} + +func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { + ec, err := self.GetElasticCacheById(id) + if err != nil { + return nil, err + } + + return ec, nil +} + +// https://help.apsara.com/document_detail/95802.html?spm=a2c4g.11186623.6.746.143e782f3Pfkfg +func (self *SRegion) GetElasticCacheAccounts(instanceId string) ([]SElasticcacheAccount, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + + ret := []SElasticcacheAccount{} + err := DoListAll(self.kvsRequest, "DescribeAccounts", params, []string{"Accounts", "Account"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCacheAccounts") + } + + return ret, nil +} + +func (self *SRegion) GetElasticCacheAccountByName(instanceId string, accountName string) (*SElasticcacheAccount, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + params["AccountName"] = accountName + + ret := []SElasticcacheAccount{} + err := DoListAll(self.kvsRequest, "DescribeAccounts", params, []string{"Accounts", "Account"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCacheAccounts") + } + + if len(ret) == 1 { + return &ret[0], nil + } else if len(ret) == 0 { + return nil, cloudprovider.ErrNotFound + } else { + return nil, errors.Wrap(fmt.Errorf("%d account with name %s found", len(ret), accountName), "region.GetElasticCacheAccountByName") + } +} + +// https://help.apsara.com/document_detail/63889.html?spm=a2c4g.11186623.6.764.3cb43852R7lnoS +func (self *SRegion) GetElasticCacheAcls(instanceId string) ([]SElasticcacheAcl, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + + ret := []SElasticcacheAcl{} + err := DoListAll(self.kvsRequest, "DescribeSecurityIps", params, []string{"SecurityIpGroups", "SecurityIpGroup"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCacheAcls") + } + + return ret, nil +} + +// https://help.apsara.com/document_detail/61081.html?spm=a2c4g.11186623.6.754.10613852qAbEQV +func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + params["StartTime"] = startTime + params["EndTime"] = endTime + + ret := []SElasticcacheBackup{} + err := DoListAll(self.kvsRequest, "DescribeBackups", params, []string{"Backups", "Backup"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCacheBackups") + } + + return ret, nil +} + +// https://help.apsara.com/document_detail/93078.html?spm=a2c4g.11186623.6.769.58011975YYL5Gl +func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["DBInstanceId"] = instanceId + + ret := []SElasticcacheParameter{} + err := DoListAll(self.kvsRequest, "DescribeParameters", params, []string{"RunningParameters", "Parameter"}, &ret) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCacheParameters") + } + + return ret, nil +} + +// https://help.apsara.com/document_detail/60873.html?spm=a2c4g.11174283.6.715.7412dce0qSYemb +func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceClass"] = ec.InstanceType + params["InstanceName"] = ec.InstanceName + params["InstanceType"] = ec.Engine + params["EngineVersion"] = ec.EngineVersion + + if len(ec.Password) > 0 { + params["UserName"] = ec.UserName + params["Password"] = ec.Password + } + + if len(ec.ZoneIds) > 0 { + params["ZoneId"] = ec.ZoneIds[0] + } + + if len(ec.PrivateIpAddress) > 0 { + params["PrivateIpAddress"] = ec.PrivateIpAddress + } + + if len(ec.NodeType) > 0 { + params["NodeType"] = ec.NodeType + } + + if len(ec.ProjectId) > 0 { + params["ResourceGroupId"] = ec.ProjectId + } + + params["NetworkType"] = ec.NetworkType + params["VpcId"] = ec.VpcId + params["VSwitchId"] = ec.NetworkId + params["ChargeType"] = ec.ChargeType + if strings.ToLower(ec.ChargeType) == billingapi.BILLING_TYPE_PREPAID && ec.BillingCycle != nil { + if ec.BillingCycle.GetMonths() >= 1 && ec.BillingCycle.GetMonths() <= 9 { + params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths()) + } else if ec.BillingCycle.GetMonths() == 12 || ec.BillingCycle.GetMonths() == 24 || ec.BillingCycle.GetMonths() == 36 { + params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths()) + } else { + return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") + } + } + + ret := &SElasticcache{} + err := DoAction(self.kvsRequest, "CreateInstance", params, []string{}, ret) + if err != nil { + return nil, errors.Wrap(err, "region.CreateIElasticcaches") + } + self.SetResourceTags("kvs", "INSTANCE", []string{ret.InstanceID}, ec.Tags, false) + + ret.region = self + return ret, nil +} + +// https://help.apsara.com/document_detail/116215.html?spm=a2c4g.11174283.6.736.6b9ddce0c5nsw6 +func (self *SElasticcache) Restart() error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["EffectiveTime"] = "0" // 立即重启 + + err := DoAction(self.region.kvsRequest, "RestartInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.Restart") + } + + return nil +} + +// https://help.apsara.com/document_detail/60898.html?spm=a2c4g.11186623.6.713.56ec1603KS0xA0 +func (self *SElasticcache) Delete() error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + + err := DoAction(self.region.kvsRequest, "DeleteInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.Delete") + } + + return nil +} + +// https://help.apsara.com/document_detail/60903.html?spm=a2c4g.11186623.6.711.3f062c92aRJNfw +func (self *SElasticcache) ChangeInstanceSpec(spec string) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["InstanceClass"] = strings.Split(spec, ":")[0] + params["AutoPay"] = "true" // 自动付款 + + err := DoAction(self.region.kvsRequest, "ModifyInstanceSpec", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.ChangeInstanceSpec") + } + + return nil +} + +// https://help.apsara.com/document_detail/61000.html?spm=a2c4g.11186623.6.730.57d66cb0QlQS86 +func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["MaintainStartTime"] = maintainStartTime + params["MaintainEndTime"] = maintainEndTime + + err := DoAction(self.region.kvsRequest, "ModifyInstanceMaintainTime", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.SetMaintainTime") + } + + return nil +} + +// https://help.apsara.com/document_detail/125795.html?spm=a2c4g.11186623.6.719.51542b3593cDKO +func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { + if port < 1024 { + port = 6379 + } + + suffix, _ := goutils.RandomAlphabetic(4) + conn := self.GetId() + strings.ToLower(suffix) + + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["Port"] = strconv.Itoa(port) + params["ConnectionStringPrefix"] = conn + + err := DoAction(self.region.kvsRequest, "AllocateInstancePublicConnection", params, nil, nil) + if err != nil { + return "", errors.Wrap(err, "elasticcache.AllocatePublicConnection") + } + + return conn, nil +} + +// https://help.apsara.com/document_detail/125796.html?spm=a2c4g.11186623.6.720.702a3b23Qayopy +func (self *SElasticcache) ReleasePublicConnection() error { + publicConn := self.GetPublicDNS() + if len(publicConn) == 0 { + log.Debugf("elasticcache.ReleasePublicConnection public connect is empty") + return nil + } + + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["CurrentConnectionString"] = publicConn + + err := DoAction(self.region.kvsRequest, "ReleaseInstancePublicConnection", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.ReleasePublicConnection") + } + + return nil +} + +// https://help.apsara.com/document_detail/93603.html?spm=a2c4g.11186623.6.732.10666cf9UVgNPb 修改链接地址 + +// https://help.apsara.com/document_detail/95973.html?spm=a2c4g.11186623.6.742.4698126aH0s4Q5 +func (self *SElasticcache) CreateAccount(input cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["AccountName"] = input.AccountName + params["AccountPassword"] = input.AccountPassword + if len(input.AccountPrivilege) > 0 { + params["AccountPrivilege"] = input.AccountPrivilege + } + + if len(input.Description) > 0 { + params["AccountDescription"] = input.Description + } + + err := DoAction(self.region.kvsRequest, "CreateAccount", params, nil, nil) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.CreateAccount") + } + + return self.GetICloudElasticcacheAccountByName(input.AccountName) +} + +func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { + acl := &SElasticcacheAcl{} + acl.cacheDB = self + acl.SecurityIPGroupName = aclName + acl.SecurityIPList = securityIps + return acl, self.region.createAcl(self.GetId(), aclName, securityIps) +} + +// https://help.apsara.com/document_detail/61113.html?spm=a2c4g.11186623.6.770.16a61e7admr0xy +func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["Config"] = config.String() + + err := DoAction(self.region.kvsRequest, "ModifyInstanceConfig", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") + } + + return nil +} + +// https://help.apsara.com/document_detail/61075.html?spm=a2c4g.11186623.6.749.4cba126a2U9xNa +func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + + // 目前没有查询备份ID的接口,因此,备份ID没什么用 + err := DoAction(self.region.kvsRequest, "CreateBackup", params, []string{"BackupJobID"}, nil) + if err != nil { + return nil, errors.Wrap(err, "elasticcache.CreateBackup") + } + + return nil, nil +} + +// https://help.apsara.com/document_detail/61077.html?spm=a2c4g.11186623.6.750.3d7630be7ziUfg +func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + params["PreferredBackupPeriod"] = config.PreferredBackupPeriod + params["PreferredBackupTime"] = config.PreferredBackupTime + + err := DoAction(self.region.kvsRequest, "ModifyBackupPolicy", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateBackupPolicy") + } + + return nil +} + +// https://help.apsara.com/document_detail/60931.html?spm=a2c4g.11186623.6.728.5c57292920UKx3 +func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + + err := DoAction(self.region.kvsRequest, "FlushInstance", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.FlushInstance") + } + + return nil +} + +// https://help.apsara.com/document_detail/98531.html?spm=5176.11065259.1996646101.searchclickresult.4df474c38Sc2SO +func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool, password string) error { + params := make(map[string]string) + params["InstanceId"] = self.GetId() + if noPwdAccess { + params["VpcAuthMode"] = "Close" + } else { + params["VpcAuthMode"] = "Open" + } + + err := DoAction(self.region.kvsRequest, "ModifyInstanceVpcAuthMode", params, nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.UpdateAuthMode") + } + + return nil +} + +func (self *SElasticcache) GetAuthMode() string { + attribute, err := self.GetAttribute() + if err != nil { + log.Errorf("elasticcache.GetAuthMode %s", err) + } + switch attribute.VpcAuthMode { + case "Open": + return "on" + default: + return "off" + } +} + +func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { + segs := strings.Split(accountId, "/") + if len(segs) < 2 { + return nil, errors.Wrap(fmt.Errorf("%s", accountId), "elasticcache.GetICloudElasticcacheAccount invalid account id ") + } + + return self.GetICloudElasticcacheAccountByName(segs[1]) +} + +func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { + acls, err := self.GetICloudElasticcacheAcls() + if err != nil { + return nil, err + } + + for _, acl := range acls { + if acl.GetId() == aclId { + return acl, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { + backups, err := self.GetICloudElasticcacheBackups() + if err != nil { + return nil, err + } + + for _, backup := range backups { + if backup.GetId() == backupId { + return backup, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (instance *SElasticcache) GetTags() (map[string]string, error) { + tags, err := instance.region.ListResourceTags("kvs", "INSTANCE", []string{instance.GetId()}) + if err != nil { + return nil, errors.Wrap(err, "instance.region.ListResourceTags") + } + if _, ok := tags[instance.GetId()]; !ok { + return map[string]string{}, nil + } + return *tags[instance.GetId()], nil +} + +func (instance *SElasticcache) SetTags(tags map[string]string, replace bool) error { + return instance.region.SetResourceTags(APSARA_PRODUCT_KVSTORE, "INSTANCE", []string{instance.GetId()}, tags, replace) +} + +func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { + return errors.Wrap(cloudprovider.ErrNotSupported, "UpdateSecurityGroups") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_parameter.go new file mode 100644 index 0000000000..9f5b9b30d5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/elasticcache_parameter.go @@ -0,0 +1,86 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElasticcacheParameter struct { + multicloud.SElasticcacheParameterBase + ApsaraTags + + cacheDB *SElasticcache + + ParameterDescription string `json:"ParameterDescription"` + ParameterValue string `json:"ParameterValue"` + ForceRestart string `json:"ForceRestart"` + CheckingCode string `json:"CheckingCode"` + ModifiableStatus string `json:"ModifiableStatus"` + ParameterName string `json:"ParameterName"` +} + +func (self *SElasticcacheParameter) GetId() string { + return fmt.Sprintf("%s/%s", self.cacheDB.InstanceID, self.ParameterName) +} + +func (self *SElasticcacheParameter) GetName() string { + return self.ParameterName +} + +func (self *SElasticcacheParameter) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheParameter) GetStatus() string { + return api.ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE +} + +func (self *SElasticcacheParameter) GetParameterKey() string { + return self.ParameterName +} + +func (self *SElasticcacheParameter) GetParameterValue() string { + return self.ParameterValue +} + +func (self *SElasticcacheParameter) GetParameterValueRange() string { + return self.CheckingCode +} + +func (self *SElasticcacheParameter) GetDescription() string { + return self.ParameterDescription +} + +func (self *SElasticcacheParameter) GetModifiable() bool { + switch self.ModifiableStatus { + case "true": + return true + default: + return false + } +} + +func (self *SElasticcacheParameter) GetForceRestart() bool { + switch self.ForceRestart { + case "true": + return true + default: + return false + } +} diff --git a/pkg/multicloud/apsara/errors.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/errors.go similarity index 100% rename from pkg/multicloud/apsara/errors.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/errors.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/host.go new file mode 100644 index 0000000000..e01d59814b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/host.go @@ -0,0 +1,295 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone +} + +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) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms := make([]SInstance, 0) + for { + parts, total, err := self.zone.region.GetInstances(self.zone.ZoneId, nil, len(vms), 50) + if err != nil { + return nil, err + } + vms = append(vms, parts...) + if len(vms) >= total { + break + } + } + 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) VMGlobalId2Id(gid string) string { + return gid +} + +func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) { + id := self.VMGlobalId2Id(gid) + parts, _, err := self.zone.region.GetInstances(self.zone.ZoneId, []string{id}, 0, 1) + if err != nil { + return nil, err + } + if len(parts) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(parts) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + parts[0].host = self + return &parts[0], nil +} + +func (self *SHost) GetId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) +} + +func (self *SHost) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) IsEmulated() bool { + return true +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) Refresh() error { + return nil +} + +func (self *SHost) GetHostStatus() string { + return api.HOST_ONLINE +} + +func (self *SHost) GetEnabled() bool { + return true +} + +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_APSARA), "manufacture") + return info +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetCpuCount() int { + 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 api.DISK_TYPE_HYBRID +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_APSARA +} + +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(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + vmId, err := self._createVM(desc.Name, desc.Hostname, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, + desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, + desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, desc.UserData, desc.BillingCycle, + desc.ProjectId, desc.OsType, desc.Tags) + if err != nil { + return nil, err + } + vm, err := self.GetInstanceById(vmId) + if err != nil { + return nil, err + } + // err = vm.waitStatus(InstanceStatusStopped, time.Second*10, time.Second*1800) + return vm, err +} + +func (self *SHost) _createVM(name, hostname string, imgId string, + sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, + vswitchId string, ipAddr string, desc string, passwd string, + dataDisks []cloudprovider.SDiskInfo, publicKey string, secgroupId string, + userData string, bc *billing.SBillingCycle, projectId, osType string, + tags map[string]string, +) (string, error) { + net := self.zone.getNetworkById(vswitchId) + if net == nil { + return "", fmt.Errorf("invalid switch ID %s", vswitchId) + } + if net.wire == nil { + log.Errorf("vsiwtch's wire is empty") + return "", fmt.Errorf("vsiwtch's wire is empty") + } + if net.wire.vpc == nil { + log.Errorf("vsiwtch's wire' vpc is empty") + return "", fmt.Errorf("vsiwtch's wire's vpc is empty") + } + + var err error + keypair := "" + if len(publicKey) > 0 { + keypair, err = self.zone.region.syncKeypair(publicKey) + if err != nil { + return "", err + } + } + + img, err := self.zone.region.GetImage(imgId) + if err != nil { + log.Errorf("GetImage 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(dataDisks)+1) + disks[0].Size = img.Size + if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.Size { + disks[0].Size = sysDisk.SizeGB + } + storage, err := self.zone.getStorageByCategory(sysDisk.StorageType) + if err != nil { + return "", fmt.Errorf("Storage %s not avaiable: %s", sysDisk.StorageType, err) + } + disks[0].Category = storage.storageType + + for i, dataDisk := range dataDisks { + disks[i+1].Size = dataDisk.SizeGB + storage, err := self.zone.getStorageByCategory(dataDisk.StorageType) + if err != nil { + return "", fmt.Errorf("Storage %s not avaiable: %s", dataDisk.StorageType, err) + } + disks[i+1].Category = storage.storageType + } + + if len(instanceType) > 0 { + log.Debugf("Try instancetype : %s", instanceType) + vmId, err := self.zone.region.CreateInstance(name, hostname, imgId, instanceType, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId, osType, tags) + if err != nil { + log.Errorf("Failed for %s: %s", instanceType, err) + return "", fmt.Errorf("Failed to create specification %s.%s", instanceType, err.Error()) + } + return vmId, nil + } + + 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) + } + + var vmId string + for _, instType := range instanceTypes { + instanceTypeId := instType.InstanceTypeId + log.Debugf("Try instancetype : %s", instanceTypeId) + vmId, err = self.zone.region.CreateInstance(name, hostname, imgId, instanceTypeId, secgroupId, self.zone.ZoneId, desc, passwd, disks, vswitchId, ipAddr, keypair, userData, bc, projectId, osType, tags) + if err != nil { + log.Errorf("Failed for %s: %s", instanceTypeId, err) + } else { + return vmId, nil + } + } + + return "", fmt.Errorf("Failed to create, %s", err.Error()) +} + +func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (host *SHost) GetIsMaintenance() bool { + return false +} + +func (host *SHost) GetVersion() string { + return APSARA_API_VERSION +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/image.go new file mode 100644 index 0000000000..d64ffb55ae --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/image.go @@ -0,0 +1,390 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type ImageStatusType string + +const ( + ImageStatusCreating ImageStatusType = "Creating" + ImageStatusAvailable ImageStatusType = "Available" + ImageStatusUnAvailable ImageStatusType = "UnAvailable" + ImageStatusCreateFailed ImageStatusType = "CreateFailed" +) + +type ImageOwnerType string + +const ( + ImageOwnerSystem ImageOwnerType = "system" + ImageOwnerSelf ImageOwnerType = "self" + ImageOwnerOthers ImageOwnerType = "others" + ImageOwnerMarketplace ImageOwnerType = "marketplace" +) + +type ImageUsageType string + +const ( + ImageUsageInstance ImageUsageType = "instance" + ImageUsageNone ImageUsageType = "none" +) + +type SImage struct { + multicloud.SImageBase + ApsaraTags + storageCache *SStoragecache + + // normalized image info + imgInfo *imagetools.ImageInfo + + Architecture string + CreationTime time.Time + Description string + ImageId string + ImageName string + OSName string + OSType string + ImageOwnerAlias ImageOwnerType + IsSupportCloudinit bool + IsSupportIoOptimized bool + Platform string + Size int + Status ImageStatusType + Usage string +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SImage) GetId() string { + return self.ImageId +} + +func (self *SImage) GetName() string { + if self.ImageOwnerAlias == ImageOwnerSystem { + return self.OSName + } else { + return self.ImageName + } +} + +func (self *SImage) IsEmulated() bool { + return false +} + +func (self *SImage) Delete(ctx context.Context) error { + return self.storageCache.region.DeleteImage(self.ImageId) +} + +func (self *SImage) GetGlobalId() string { + return self.ImageId +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.storageCache +} + +func (self *SImage) GetStatus() string { + switch self.Status { + case ImageStatusCreating: + return api.CACHED_IMAGE_STATUS_SAVING + case ImageStatusAvailable: + return api.CACHED_IMAGE_STATUS_ACTIVE + case ImageStatusUnAvailable: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + case ImageStatusCreateFailed: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + default: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (self *SImage) GetImageStatus() string { + switch self.Status { + case ImageStatusCreating: + return cloudprovider.IMAGE_STATUS_QUEUED + case ImageStatusAvailable: + return cloudprovider.IMAGE_STATUS_ACTIVE + case ImageStatusUnAvailable: + return cloudprovider.IMAGE_STATUS_DELETED + case ImageStatusCreateFailed: + return cloudprovider.IMAGE_STATUS_KILLED + default: + return cloudprovider.IMAGE_STATUS_KILLED + } +} + +func (self *SImage) Refresh() error { + new, err := self.storageCache.region.GetImage(self.ImageId) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + switch self.ImageOwnerAlias { + case ImageOwnerSystem: + return cloudprovider.ImageTypeSystem + case ImageOwnerSelf: + return cloudprovider.ImageTypeCustomized + case ImageOwnerMarketplace: + return cloudprovider.ImageTypeMarket + case ImageOwnerOthers: + return cloudprovider.ImageTypeShared + default: + return cloudprovider.ImageTypeCustomized + } +} + +func (self *SImage) GetSizeByte() int64 { + return int64(self.Size) * 1024 * 1024 * 1024 +} + +func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if self.imgInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(self.OSName, self.Architecture, self.OSType, self.Platform, "") + self.imgInfo = &imgInfo + } + + return self.imgInfo +} + +func (self *SImage) GetFullOsName() string { + return self.OSName +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) +} + +func (self *SImage) GetOsDist() string { + return self.getNormalizedImageInfo().OsDistro +} + +func (self *SImage) GetOsVersion() string { + return self.getNormalizedImageInfo().OsVersion +} + +func (self *SImage) GetOsLang() string { + return self.getNormalizedImageInfo().OsLang +} + +func (self *SImage) GetOsArch() string { + return self.getNormalizedImageInfo().OsArch +} + +func (self *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return 40 +} + +func (self *SImage) GetImageFormat() string { + return "vhd" +} + +func (self *SImage) GetCreatedAt() time.Time { + return self.CreationTime +} + +type ImageExportTask struct { + ImageId string + RegionId string + // RequestId string + TaskId string +} + +func (self *SRegion) ExportImage(imageId string, bucketName string) (*ImageExportTask, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["ImageId"] = imageId + params["OssBucket"] = bucketName + params["OssPrefix"] = fmt.Sprintf("%sexport", strings.Replace(imageId, "-", "", -1)) + + if body, err := self.ecsRequest("ExportImage", params); err != nil { + return nil, err + } else { + result := ImageExportTask{} + if err := body.Unmarshal(&result); err != nil { + log.Errorf("unmarshal result error %s", err) + return nil, err + } + return &result, nil + } +} + +// {"ImageId":"m-j6c1qlpa7oebbg1n2k60","RegionId":"cn-hongkong","RequestId":"F8B2F6A1-F6AA-4C92-A54C-C4A309CF811F","TaskId":"t-j6c1qlpa7oebbg1rcl9t"} + +type ImageImportTask struct { + ImageId string + RegionId string + // RequestId string + TaskId string +} + +func (self *SRegion) ImportImage(name string, osArch string, osType string, osDist string, bucket string, key string) (*ImageImportTask, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["ImageName"] = name + if osDist == "RHEL" { + osDist = "CentOS" + } + params["Platform"] = osDist // "Others Linux" + params["OSType"] = osType // "linux" + params["Architecture"] = osArch // "x86_64" + params["DiskDeviceMapping.1.OSSBucket"] = bucket + params["DiskDeviceMapping.1.OSSObject"] = key + + log.Debugf("Upload image with params %#v", params) + + body, err := self.ecsRequest("ImportImage", params) + if err != nil { + log.Errorf("ImportImage fail %s", err) + return nil, err + } + + log.Infof("%s", body) + result := ImageImportTask{} + err = body.Unmarshal(&result) + if err != nil { + log.Errorf("unmarshal result error %s", err) + return nil, err + } + + return &result, nil +} + +func (self *SRegion) GetImage(imageId string) (*SImage, error) { + for _, owner := range []ImageOwnerType{ImageOwnerSelf, ImageOwnerSystem} { + images, _, err := self.GetImages("", owner, []string{imageId}, "", 0, 1) + if err != nil { + return nil, err + } + if len(images) == 1 { + return &images[0], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetImageByName(name string) (*SImage, error) { + for _, owner := range []ImageOwnerType{ImageOwnerSelf, ImageOwnerSystem} { + images, _, err := self.GetImages("", owner, nil, name, 0, 1) + if err != nil { + return nil, err + } + if len(images) == 1 { + return &images[0], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetImagesBySnapshot(snapshotId string, offset int, limit int) ([]SImage, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + params["SnapshotId"] = snapshotId + + return self.getImages(params) +} + +func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) { + image, err := self.GetImage(imageId) + if err != nil { + return "", err + } + return image.Status, nil +} + +func (self *SRegion) GetImages(status ImageStatusType, owner ImageOwnerType, imageId []string, name string, offset int, limit int) ([]SImage, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if len(status) > 0 { + params["Status"] = string(status) + } else { + params["Status"] = "Creating,Available,UnAvailable,CreateFailed" + } + if imageId != nil && len(imageId) > 0 { + params["ImageId"] = strings.Join(imageId, ",") + } + if len(owner) > 0 { + params["ImageOwnerAlias"] = string(owner) + } + + if len(name) > 0 { + params["ImageName"] = name + } + + return self.getImages(params) +} + +func (self *SRegion) getImages(params map[string]string) ([]SImage, int, error) { + body, err := self.ecsRequest("DescribeImages", params) + if err != nil { + log.Errorf("DescribeImages fail %s", err) + return nil, 0, err + } + + images := make([]SImage, 0) + err = body.Unmarshal(&images, "Images", "Image") + if err != nil { + log.Errorf("unmarshal images fail %s", err) + return nil, 0, nil + } + total, _ := body.Int("TotalCount") + return images, int(total), nil +} + +func (self *SRegion) DeleteImage(imageId string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["ImageId"] = imageId + params["Force"] = "true" + + _, err := self.ecsRequest("DeleteImage", params) + if err != nil { + log.Errorf("DeleteImage fail %s", err) + return err + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instance.go new file mode 100644 index 0000000000..54e230415c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instance.go @@ -0,0 +1,1043 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + "sort" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + "yunion.io/x/pkg/util/seclib" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +const ( + // Running:运行中 + //Starting:启动中 + //Stopping:停止中 + //Stopped:已停止 + + InstanceStatusStopped = "Stopped" + InstanceStatusRunning = "Running" + InstanceStatusStopping = "Stopping" + InstanceStatusStarting = "Starting" +) + +type SDedicatedHostAttribute struct { + DedicatedHostId string + DedicatedHostName string +} + +type SIpAddress struct { + IpAddress []string +} + +type SNetworkInterfaces struct { + NetworkInterface []SNetworkInterface +} + +type SOperationLocks struct { + LockReason []string +} + +type SSecurityGroupIds struct { + SecurityGroupId []string +} + +// {"NatIpAddress":"","PrivateIpAddress":{"IpAddress":["192.168.220.214"]},"VSwitchId":"vsw-2ze9cqwza4upoyujq1thd","VpcId":"vpc-2zer4jy8ix3i8f0coc5uw"} + +type SVpcAttributes struct { + NatIpAddress string + PrivateIpAddress SIpAddress + VSwitchId string + VpcId string +} + +type SInstance struct { + multicloud.SInstanceBase + ApsaraTags + + host *SHost + + osInfo *imagetools.ImageInfo + + // idisks []cloudprovider.ICloudDisk + + AutoReleaseTime string + ClusterId string + Cpu int + CreationTime time.Time + DedicatedHostAttribute SDedicatedHostAttribute + Description string + DeviceAvailable bool + EipAddress SEipAddress + ExpiredTime time.Time + GPUAmount int + GPUSpec string + HostName string + ImageId string + InnerIpAddress SIpAddress + InstanceChargeType TChargeType + InstanceId string + InstanceName string + InstanceNetworkType string + InstanceType string + InstanceTypeFamily string + InternetChargeType TInternetChargeType + InternetMaxBandwidthIn int + InternetMaxBandwidthOut int + IoOptimized bool + KeyPairName string + Memory int + NetworkInterfaces SNetworkInterfaces + OSName string + OSType string + OperationLocks SOperationLocks + PublicIpAddress SIpAddress + Recyclable bool + RegionId string + SaleCycle string + SecurityGroupIds SSecurityGroupIds + SerialNumber string + SpotPriceLimit string + SpotStrategy string + StartTime time.Time + Status string + StoppedMode string + VlanId string + VpcAttributes SVpcAttributes + ZoneId string + + DepartmentInfo +} + +// {"AutoReleaseTime":"","ClusterId":"","Cpu":1,"CreationTime":"2018-05-23T07:58Z","DedicatedHostAttribute":{"DedicatedHostId":"","DedicatedHostName":""},"Description":"","DeviceAvailable":true,"EipAddress":{"AllocationId":"","InternetChargeType":"","IpAddress":""},"ExpiredTime":"2018-05-30T16:00Z","GPUAmount":0,"GPUSpec":"","HostName":"iZ2ze57isp1ali72tzkjowZ","ImageId":"centos_7_04_64_20G_alibase_201701015.vhd","InnerIpAddress":{"IpAddress":[]},"InstanceChargeType":"PrePaid","InstanceId":"i-2ze57isp1ali72tzkjow","InstanceName":"gaoxianqi-test-7days","InstanceNetworkType":"vpc","InstanceType":"ecs.t5-lc2m1.nano","InstanceTypeFamily":"ecs.t5","InternetChargeType":"PayByBandwidth","InternetMaxBandwidthIn":-1,"InternetMaxBandwidthOut":0,"IoOptimized":true,"Memory":512,"NetworkInterfaces":{"NetworkInterface":[{"MacAddress":"00:16:3e:10:f0:c9","NetworkInterfaceId":"eni-2zecqsagtpztl6x5hu2r","PrimaryIpAddress":"192.168.220.214"}]},"OSName":"CentOS 7.4 64位","OSType":"linux","OperationLocks":{"LockReason":[]},"PublicIpAddress":{"IpAddress":[]},"Recyclable":false,"RegionId":"cn-beijing","ResourceGroupId":"","SaleCycle":"Week","SecurityGroupIds":{"SecurityGroupId":["sg-2zecqsagtpztl6x9zynl"]},"SerialNumber":"df05d9b4-df3d-4400-88d1-5f843f0dd088","SpotPriceLimit":0.000000,"SpotStrategy":"NoSpot","StartTime":"2018-05-23T07:58Z","Status":"Running","StoppedMode":"Not-applicable","VlanId":"","VpcAttributes":{"NatIpAddress":"","PrivateIpAddress":{"IpAddress":["192.168.220.214"]},"VSwitchId":"vsw-2ze9cqwza4upoyujq1thd","VpcId":"vpc-2zer4jy8ix3i8f0coc5uw"},"ZoneId":"cn-beijing-f"} + +func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit int) ([]SInstance, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if len(zoneId) > 0 { + params["ZoneId"] = zoneId + } + + if ids != nil && len(ids) > 0 { + params["InstanceIds"] = jsonutils.Marshal(ids).String() + } + + body, err := self.ecsRequest("DescribeInstances", params) + if err != nil { + log.Errorf("GetInstances fail %s", err) + return nil, 0, err + } + + instances := make([]SInstance, 0) + err = body.Unmarshal(&instances, "Instances", "Instance") + if err != nil { + log.Errorf("Unmarshal security group details fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return instances, int(total), nil +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + return self.SecurityGroupIds.SecurityGroupId, nil +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetId() string { + return self.InstanceId +} + +func (self *SInstance) GetName() string { + if len(self.InstanceName) > 0 { + return self.InstanceName + } + return self.InstanceId +} + +func (self *SInstance) GetHostname() string { + return self.HostName +} + +func (self *SInstance) GetGlobalId() string { + return self.InstanceId +} + +func (self *SInstance) IsEmulated() bool { + return false +} + +func (self *SInstance) GetInstanceType() string { + return self.InstanceType +} + +func (self *SInstance) GetInternetMaxBandwidthOut() int { + return self.InternetMaxBandwidthOut +} + +func (self *SInstance) getVpc() (*SVpc, error) { + return self.host.zone.region.getVpc(self.VpcAttributes.VpcId) +} + +type byAttachedTime []SDisk + +func (a byAttachedTime) Len() int { return len(a) } +func (a byAttachedTime) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byAttachedTime) Less(i, j int) bool { + switch a[i].GetDiskType() { + case api.DISK_TYPE_SYS: + return true + case api.DISK_TYPE_SWAP: + switch a[j].GetDiskType() { + case api.DISK_TYPE_SYS: + return false + case api.DISK_TYPE_DATA: + return true + } + case api.DISK_TYPE_DATA: + if a[j].GetDiskType() != api.DISK_TYPE_DATA { + return false + } + } + return a[i].AttachedTime.Before(a[j].AttachedTime) +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks := []SDisk{} + for { + part, total, err := self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, len(disks), 50) + if err != nil { + return nil, errors.Wrapf(err, "GetDisks for %s", self.InstanceId) + } + disks = append(disks, part...) + if len(disks) >= total { + break + } + } + + sort.Sort(byAttachedTime(disks)) + + 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) { + var ( + networkInterfaces = self.NetworkInterfaces.NetworkInterface + nics []cloudprovider.ICloudNic + ) + for _, networkInterface := range networkInterfaces { + nic := SInstanceNic{ + instance: self, + id: networkInterface.NetworkInterfaceId, + ipAddr: networkInterface.PrimaryIpAddress, + macAddr: networkInterface.MacAddress, + } + nics = append(nics, &nic) + } + return nics, nil +} + +func (self *SInstance) GetVcpuCount() int { + 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() cloudprovider.TOsType { + return cloudprovider.TOsType(osprofile.NormalizeOSType(self.OSType)) +} + +func (self *SInstance) GetFullOsName() string { + return self.OSName +} + +func (ins *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { + if ins.osInfo == nil { + osInfo := imagetools.NormalizeImageInfo(ins.OSName, "", ins.OSType, "", "") + ins.osInfo = &osInfo + } + return ins.osInfo +} + +func (ins *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(ins.getNormalizedOsInfo().OsBios) +} + +func (ins *SInstance) GetOsArch() string { + return ins.getNormalizedOsInfo().OsArch +} + +func (ins *SInstance) GetOsDist() string { + return ins.getNormalizedOsInfo().OsDistro +} + +func (ins *SInstance) GetOsVersion() string { + return ins.getNormalizedOsInfo().OsVersion +} + +func (ins *SInstance) GetOsLang() string { + return ins.getNormalizedOsInfo().OsLang +} + +func (self *SInstance) GetMachine() string { + return "pc" +} + +func (self *SInstance) GetStatus() string { + // Running:运行中 + //Starting:启动中 + //Stopping:停止中 + //Stopped:已停止 + switch self.Status { + case InstanceStatusRunning: + return api.VM_RUNNING + case InstanceStatusStarting: + return api.VM_STARTING + case InstanceStatusStopping: + return api.VM_STOPPING + case InstanceStatusStopped: + return api.VM_READY + default: + return api.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) GetRemoteStatus() string { + // Running:运行中 + //Starting:启动中 + //Stopping:停止中 + //Stopped:已停止 + switch self.Status { + case InstanceStatusRunning: + return cloudprovider.CloudVMStatusRunning + case InstanceStatusStarting: + return cloudprovider.CloudVMStatusStopped + case InstanceStatusStopping: + return cloudprovider.CloudVMStatusRunning + case InstanceStatusStopped: + return cloudprovider.CloudVMStatusStopped + default: + return cloudprovider.CloudVMStatusOther + } +} +*/ + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_APSARA +} + +func (self *SInstance) StartVM(ctx context.Context) 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(), api.VM_RUNNING) + if self.GetStatus() == api.VM_RUNNING { + return nil + } else if self.GetStatus() == api.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(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + err := self.host.zone.region.StopVM(self.InstanceId, opts.IsForce) + if err != nil { + return err + } + return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + url, err := self.host.zone.region.GetInstanceVNCUrl(self.InstanceId) + if err != nil { + return nil, err + } + passwd := seclib.RandomPassword(6) + err = self.host.zone.region.ModifyInstanceVNCUrlPassword(self.InstanceId, passwd) + if err != nil { + return nil, err + } + ret := &cloudprovider.ServerVncOutput{ + Url: url, + Password: passwd, + Protocol: "apsara", + InstanceId: self.InstanceId, + Hypervisor: api.HYPERVISOR_APSARA, + } + return ret, nil +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return self.host.zone.region.UpdateVM(self.InstanceId, name) +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + var keypairName string + if len(publicKey) > 0 { + var err error + keypairName, err = self.host.zone.region.syncKeypair(publicKey) + if err != nil { + return err + } + } + + return self.host.zone.region.DeployVM(self.InstanceId, name, password, keypairName, deleteKeypair, description) +} + +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + keypair := "" + if len(desc.PublicKey) > 0 { + var err error + keypair, err = self.host.zone.region.syncKeypair(desc.PublicKey) + if err != nil { + return "", err + } + } + diskId, err := self.host.zone.region.ReplaceSystemDisk(self.InstanceId, desc.ImageId, desc.Password, keypair, desc.SysSizeGB) + if err != nil { + return "", err + } + + return diskId, nil +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + if len(config.InstanceType) > 0 { + return self.host.zone.region.ChangeVMConfig2(self.ZoneId, self.InstanceId, config.InstanceType, nil) + } + return self.host.zone.region.ChangeVMConfig(self.ZoneId, self.InstanceId, config.Cpu, config.MemoryMB, nil) +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return self.host.zone.region.AttachDisk(self.InstanceId, diskId) +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return cloudprovider.RetryOnError( + func() error { + return self.host.zone.region.DetachDisk(self.InstanceId, diskId) + }, + []string{ + `"Code":"InvalidOperation.Conflict"`, + }, + 4) +} + +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) CreateInstance(name, hostname string, imageId string, instanceType string, securityGroupId string, + zoneId string, desc string, passwd string, disks []SDisk, vSwitchId string, ipAddr string, + keypair string, userData string, bc *billing.SBillingCycle, projectId, osType string, + tags map[string]string, +) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["ImageId"] = imageId + params["InstanceType"] = instanceType + params["SecurityGroupId"] = securityGroupId + params["ZoneId"] = zoneId + params["InstanceName"] = name + if len(hostname) > 0 { + params["HostName"] = hostname + } + params["Description"] = desc + params["InternetChargeType"] = "PayByTraffic" + params["InternetMaxBandwidthIn"] = "200" + params["InternetMaxBandwidthOut"] = "100" + if len(passwd) > 0 { + params["Password"] = passwd + } else { + params["PasswordInherit"] = "True" + } + + if len(projectId) > 0 { + params["ResourceGroupId"] = projectId + } + //{"Code":"InvalidSystemDiskCategory.ValueNotSupported","HostId":"ecs.apsaracs.com","Message":"The specified parameter 'SystemDisk.Category' is not support IoOptimized Instance. Valid Values: cloud_efficiency;cloud_ssd. ","RequestId":"9C9A4E99-5196-42A2-80B6-4762F8F75C90"} + params["IoOptimized"] = "optimized" + for i, d := range disks { + if i == 0 { + params["SystemDisk.Category"] = d.Category + if d.Category == api.STORAGE_CLOUD_ESSD_PL2 { + params["SystemDisk.Category"] = api.STORAGE_CLOUD_ESSD + params["SystemDisk.PerformanceLevel"] = "PL2" + } + if d.Category == api.STORAGE_CLOUD_ESSD_PL3 { + params["SystemDisk.Category"] = api.STORAGE_CLOUD_ESSD + params["SystemDisk.PerformanceLevel"] = "PL3" + } + params["SystemDisk.Size"] = fmt.Sprintf("%d", d.Size) + params["SystemDisk.DiskName"] = d.GetName() + params["SystemDisk.Description"] = d.Description + } else { + params[fmt.Sprintf("DataDisk.%d.Size", i)] = fmt.Sprintf("%d", d.Size) + params[fmt.Sprintf("DataDisk.%d.Category", i)] = d.Category + if d.Category == api.STORAGE_CLOUD_ESSD_PL2 { + params[fmt.Sprintf("DataDisk.%d.Category", i)] = api.STORAGE_CLOUD_ESSD + params[fmt.Sprintf("DataDisk.%d..PerformanceLevel", i)] = "PL2" + } + if d.Category == api.STORAGE_CLOUD_ESSD_PL3 { + params[fmt.Sprintf("DataDisk.%d.Category", i)] = api.STORAGE_CLOUD_ESSD + params[fmt.Sprintf("DataDisk.%d..PerformanceLevel", i)] = "PL3" + } + params[fmt.Sprintf("DataDisk.%d.DiskName", i)] = d.GetName() + params[fmt.Sprintf("DataDisk.%d.Description", i)] = d.Description + params[fmt.Sprintf("DataDisk.%d.Encrypted", i)] = "false" + } + } + params["VSwitchId"] = vSwitchId + params["PrivateIpAddress"] = ipAddr + + if len(keypair) > 0 { + params["KeyPairName"] = keypair + } + + if len(userData) > 0 { + params["UserData"] = userData + } + + if len(tags) > 0 { + tagIdx := 0 + for k, v := range tags { + params[fmt.Sprintf("Tag.%d.Key", tagIdx)] = k + params[fmt.Sprintf("Tag.%d.Value", tagIdx)] = v + tagIdx += 1 + } + } + + if bc != nil { + params["InstanceChargeType"] = "PrePaid" + err := billingCycle2Params(bc, params) + if err != nil { + return "", err + } + if bc.AutoRenew { + params["AutoRenew"] = "true" + params["AutoRenewPeriod"] = "1" + } else { + params["AutoRenew"] = "False" + } + } else { + params["InstanceChargeType"] = "PostPaid" + params["SpotStrategy"] = "NoSpot" + } + + params["ClientToken"] = utils.GenRequestId(20) + + body, err := self.ecsRequest("CreateInstance", params) + if err != nil { + log.Errorf("CreateInstance fail %s", err) + return "", err + } + instanceId, _ := body.GetString("InstanceId") + return instanceId, nil +} + +func (self *SRegion) doStartVM(instanceId string) error { + return self.instanceOperation(instanceId, "StartInstance", nil) +} + +func (self *SRegion) doStopVM(instanceId string, isForce bool) error { + params := make(map[string]string) + if isForce { + params["ForceStop"] = "true" + } else { + params["ForceStop"] = "false" + } + params["StoppedMode"] = "KeepCharging" + return self.instanceOperation(instanceId, "StopInstance", params) +} + +func (self *SRegion) doDeleteVM(instanceId string) error { + params := make(map[string]string) + params["TerminateSubscription"] = "true" // terminate expired prepaid instance + params["Force"] = "true" + return self.instanceOperation(instanceId, "DeleteInstance", params) +} + +/*func (self *SRegion) waitInstanceStatus(instanceId string, target string, interval time.Duration, timeout time.Duration) error { + startTime := time.Now() + for time.Now().Sub(startTime) < timeout { + status, err := self.GetInstanceStatus(instanceId) + if err != nil { + return err + } + if status == target { + return nil + } + time.Sleep(interval) + } + return cloudprovider.ErrTimeout +} + +func (self *SInstance) waitStatus(target string, interval time.Duration, timeout time.Duration) error { + return self.host.zone.region.waitInstanceStatus(self.InstanceId, target, interval, timeout) +}*/ + +func (self *SRegion) StartVM(instanceId string) error { + status, err := self.GetInstanceStatus(instanceId) + if err != nil { + log.Errorf("Fail to get instance status on StartVM: %s", err) + return err + } + if status != InstanceStatusStopped { + log.Errorf("StartVM: vm status is %s expect %s", status, InstanceStatusStopped) + return cloudprovider.ErrInvalidStatus + } + return self.doStartVM(instanceId) + // if err != nil { + // return err + // } + // return self.waitInstanceStatus(instanceId, InstanceStatusRunning, time.Second*5, time.Second*180) // 3 minutes to timeout +} + +func (self *SRegion) StopVM(instanceId string, isForce bool) error { + status, err := self.GetInstanceStatus(instanceId) + if err != nil { + log.Errorf("Fail to get instance status on StopVM: %s", err) + return err + } + if status == InstanceStatusStopped { + return nil + } + if status != InstanceStatusRunning { + log.Errorf("StopVM: vm status is %s expect %s", status, InstanceStatusRunning) + return cloudprovider.ErrInvalidStatus + } + return self.doStopVM(instanceId, isForce) + // if err != nil { + // return err + // } + // return self.waitInstanceStatus(instanceId, InstanceStatusStopped, time.Second*10, time.Second*300) // 5 minutes to timeout +} + +func (self *SRegion) DeleteVM(instanceId string) error { + status, err := self.GetInstanceStatus(instanceId) + if err != nil { + log.Errorf("Fail to get instance status on DeleteVM: %s", err) + return err + } + log.Debugf("Instance status on delete is %s", status) + if status != InstanceStatusStopped { + log.Warningf("DeleteVM: vm status is %s expect %s", status, InstanceStatusStopped) + } + return self.doDeleteVM(instanceId) + // if err != nil { + // return err + // } + // err = self.waitInstanceStatus(instanceId, InstanceStatusRunning, time.Second*10, time.Second*300) // 5 minutes to timeout + // if err == cloudprovider.ErrNotFound { + // return nil + // } else if err == nil { + // return cloudprovider.ErrTimeout + // } else { + // return err + // } +} + +func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { + instance, err := self.GetInstance(instanceId) + if err != nil { + return err + } + + // 修改密钥时直接返回 + if deleteKeypair { + err = self.DetachKeyPair(instanceId, instance.KeyPairName) + if err != nil { + return err + } + } + + if len(keypairName) > 0 { + err = self.AttachKeypair(instanceId, keypairName) + if err != nil { + return err + } + } + + params := make(map[string]string) + + // if resetPassword { + // params["Password"] = seclib2.RandomPassword2(12) + // } + // 指定密码的情况下,使用指定的密码 + if len(password) > 0 { + params["Password"] = password + } + + if len(name) > 0 && instance.InstanceName != name { + params["InstanceName"] = name + } + + if len(description) > 0 && instance.Description != description { + params["Description"] = description + } + + if len(params) > 0 { + return self.modifyInstanceAttribute(instanceId, params) + } else { + return nil + } +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + for { + err := self.host.zone.region.DeleteVM(self.InstanceId) + if err != nil { + if isError(err, "IncorrectInstanceStatus.Initializing") { + log.Infof("The instance is initializing, try later ...") + time.Sleep(10 * time.Second) + } else { + log.Errorf("DeleteVM fail: %s", err) + return err + } + } else { + break + } + } + return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes +} + +func (self *SRegion) UpdateVM(instanceId string, name string) error { + /* + api: ModifyInstanceAttribute + https://help.apsara.com/document_detail/25503.html?spm=a2c4g.11186623.4.1.DrgpjW + */ + params := make(map[string]string) + params["InstanceName"] = name + return self.modifyInstanceAttribute(instanceId, params) +} + +func (self *SRegion) modifyInstanceAttribute(instanceId string, params map[string]string) error { + params["x-acs-instanceid"] = instanceId + return self.instanceOperation(instanceId, "ModifyInstanceAttribute", params) +} + +func (self *SRegion) ReplaceSystemDisk(instanceId string, imageId string, passwd string, keypairName string, sysDiskSizeGB int) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + params["ImageId"] = imageId + if len(passwd) > 0 { + params["Password"] = passwd + } else { + params["PasswordInherit"] = "True" + } + if len(keypairName) > 0 { + params["KeyPairName"] = keypairName + } + if sysDiskSizeGB > 0 { + params["SystemDisk.Size"] = fmt.Sprintf("%d", sysDiskSizeGB) + } + params["x-acs-instanceid"] = instanceId + body, err := self.ecsRequest("ReplaceSystemDisk", params) + if err != nil { + return "", err + } + // log.Debugf("%s", body.String()) + return body.GetString("DiskId") +} + +func (self *SRegion) ChangeVMConfig(zoneId string, instanceId string, ncpu int, vmem int, disks []*SDisk) error { + // todo: support change disk config? + params := make(map[string]string) + instanceTypes, e := self.GetMatchInstanceTypes(ncpu, vmem, 0, zoneId) + if e != nil { + return e + } + + for _, instancetype := range instanceTypes { + params["InstanceType"] = instancetype.InstanceTypeId + params["ClientToken"] = utils.GenRequestId(20) + if err := self.instanceOperation(instanceId, "ModifyInstanceSpec", params); 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) ChangeVMConfig2(zoneId string, instanceId string, instanceType string, disks []*SDisk) error { + // todo: support change disk config? + params := make(map[string]string) + params["InstanceType"] = instanceType + params["ClientToken"] = utils.GenRequestId(20) + if err := self.instanceOperation(instanceId, "ModifyInstanceSpec", params); err != nil { + log.Errorf("Failed for %s: %s", instanceType, err) + return fmt.Errorf("Failed to change vm config, specification not supported") + } else { + return nil + } +} + +func (self *SRegion) DetachDisk(instanceId string, diskId string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["DiskId"] = diskId + log.Infof("Detach instance %s disk %s", instanceId, diskId) + params["x-acs-instanceid"] = instanceId + _, err := self.ecsRequest("DetachDisk", params) + if err != nil { + if strings.Contains(err.Error(), "The specified disk has not been attached on the specified instance") { + return nil + } + return errors.Wrap(err, "DetachDisk") + } + + return nil +} + +func (self *SRegion) AttachDisk(instanceId string, diskId string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["DiskId"] = diskId + params["x-acs-instanceid"] = instanceId + _, err := self.ecsRequest("AttachDisk", params) + if err != nil { + log.Errorf("AttachDisk %s to %s fail %s", diskId, instanceId, err) + return err + } + + return nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + if len(self.EipAddress.IpAddress) > 0 { + return self.host.zone.region.GetEip(self.EipAddress.AllocationId) + } + 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.InstanceType = EIP_INSTANCE_TYPE_ECS + eip.Status = EIP_STATUS_INUSE + eip.AllocationId = self.InstanceId // fixed + eip.AllocationTime = self.CreationTime + eip.Bandwidth = self.InternetMaxBandwidthOut + eip.InternetChargeType = self.InternetChargeType + return &eip, nil + } + return nil, nil +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.host.zone.region.AssignSecurityGroup(secgroupId, self.InstanceId) +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + return self.host.zone.region.SetSecurityGroups(secgroupIds, self.InstanceId) +} + +func (self *SInstance) GetBillingType() string { + return convertChargeType(self.InstanceChargeType) +} + +func (self *SInstance) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SInstance) GetExpiredAt() time.Time { + return convertExpiredAt(self.ExpiredTime) +} + +func (self *SInstance) UpdateUserData(userData string) error { + return self.host.zone.region.updateInstance(self.InstanceId, "", "", "", "", userData) +} + +func (self *SInstance) Renew(bc billing.SBillingCycle) error { + return self.host.zone.region.RenewInstance(self.InstanceId, bc) +} + +func billingCycle2Params(bc *billing.SBillingCycle, params map[string]string) error { + if bc.GetMonths() > 0 { + params["PeriodUnit"] = "Month" + params["Period"] = fmt.Sprintf("%d", bc.GetMonths()) + } else if bc.GetWeeks() > 0 { + params["PeriodUnit"] = "Week" + params["Period"] = fmt.Sprintf("%d", bc.GetWeeks()) + } else { + return fmt.Errorf("invalid renew time period %s", bc.String()) + } + return nil +} + +func (region *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + err := billingCycle2Params(&bc, params) + if err != nil { + return err + } + params["ClientToken"] = utils.GenRequestId(20) + params["x-acs-instanceid"] = instanceId + _, err = region.ecsRequest("RenewInstance", params) + if err != nil { + log.Errorf("RenewInstance fail %s", err) + return err + } + return nil +} + +func (self *SInstance) GetError() error { + return nil +} + +func (region *SRegion) ConvertPublicIpToEip(instanceId string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["RegionId"] = region.RegionId + _, err := region.ecsRequest("ConvertNatPublicIpToEip", params) + return err +} + +func (self *SInstance) ConvertPublicIpToEip() error { + return self.host.zone.region.ConvertPublicIpToEip(self.InstanceId) +} + +func (region *SRegion) SetInstanceAutoRenew(instanceId string, autoRenew bool) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["RegionId"] = region.RegionId + if autoRenew { + params["RenewalStatus"] = "AutoRenewal" + params["Duration"] = "1" + } else { + params["RenewalStatus"] = "Normal" + } + params["x-acs-instanceid"] = instanceId + _, err := region.ecsRequest("ModifyInstanceAutoRenewAttribute", params) + return err +} + +type SAutoRenewAttr struct { + Duration int + AutoRenewEnabled bool + RenewalStatus string + PeriodUnit string +} + +func (region *SRegion) GetInstanceAutoRenewAttribute(instanceId string) (*SAutoRenewAttr, error) { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["RegionId"] = region.RegionId + resp, err := region.ecsRequest("DescribeInstanceAutoRenewAttribute", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeInstanceAutoRenewAttribute") + } + attr := []SAutoRenewAttr{} + err = resp.Unmarshal(&attr, "InstanceRenewAttributes", "InstanceRenewAttribute") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + if len(attr) == 1 { + return &attr[0], nil + } + return nil, fmt.Errorf("get %d auto renew info", len(attr)) +} + +func (self *SInstance) IsAutoRenew() bool { + attr, err := self.host.zone.region.GetInstanceAutoRenewAttribute(self.InstanceId) + if err != nil { + log.Errorf("failed to get instance %s auto renew info", self.InstanceId) + return false + } + return attr.AutoRenewEnabled +} + +func (self *SInstance) SetAutoRenew(bc billing.SBillingCycle) error { + return self.host.zone.region.SetInstanceAutoRenew(self.InstanceId, bc.AutoRenew) +} + +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { + return self.host.zone.region.SetResourceTags("ecs", "instance", []string{self.InstanceId}, tags, replace) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instancenic.go new file mode 100644 index 0000000000..8635eb237b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instancenic.go @@ -0,0 +1,52 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + instance *SInstance + id string + ipAddr string + macAddr string + + cloudprovider.DummyICloudNic +} + +func (self *SInstanceNic) GetId() string { + return self.id +} + +func (self *SInstanceNic) GetIP() string { + return self.ipAddr +} + +func (self *SInstanceNic) GetMAC() string { + return self.macAddr +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) GetINetworkId() string { + return self.instance.VpcAttributes.VSwitchId +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instancetype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instancetype.go new file mode 100644 index 0000000000..b00f1bd680 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/instancetype.go @@ -0,0 +1,194 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// {"CpuCoreCount":1,"EniQuantity":1,"GPUAmount":0,"GPUSpec":"","InstanceTypeFamily":"ecs.t1","InstanceTypeId":"ecs.t1.xsmall","LocalStorageCategory":"","MemorySize":0.500000} +// InstanceBandwidthRx":26214400,"InstanceBandwidthTx":26214400,"InstancePpsRx":4500000,"InstancePpsTx":4500000 + +type SInstanceType struct { + multicloud.SResourceBase + ApsaraTags + BaselineCredit int + CpuCoreCount int + MemorySize float32 + EniQuantity int // 实例规格支持网卡数量 + GPUAmount int + GPUSpec string + InstanceTypeFamily string + InstanceFamilyLevel string + InstanceTypeId string + LocalStorageCategory string + LocalStorageAmount int + LocalStorageCapacity int64 + InstanceBandwidthRx int + InstanceBandwidthTx int + InstancePpsRx int + InstancePpsTx int +} + +func (self *SRegion) GetInstanceTypes() ([]SInstanceType, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + + body, err := self.client.ascmRequest("DescribeInstanceTypes", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeInstanceTypes") + } + + instanceTypes := make([]SInstanceType, 0) + err = body.Unmarshal(&instanceTypes, "data") + if err != nil { + log.Errorf("Unmarshal instance type details fail %s", err) + return nil, err + } + return instanceTypes, nil +} + +func (self *SInstanceType) memoryMB() int { + return int(self.MemorySize * 1024) +} + +func (self *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { + skus, err := self.GetInstanceTypes() + if err != nil { + return nil, errors.Wrapf(err, "GetInstanceTypes") + } + ret := []cloudprovider.ICloudSku{} + for i := range skus { + ret = append(ret, &skus[i]) + } + return ret, nil +} + +func (self *SInstanceType) GetStatus() string { + return "" +} + +func (self *SInstanceType) Delete() error { + return nil +} + +func (self *SInstanceType) GetName() string { + return self.InstanceTypeId +} + +func (self *SInstanceType) GetId() string { + return self.InstanceTypeId +} + +func (self *SInstanceType) GetGlobalId() string { + return self.InstanceTypeId +} + +func (self *SInstanceType) GetInstanceTypeFamily() string { + return self.InstanceTypeFamily +} + +func (self *SInstanceType) GetInstanceTypeCategory() string { + return self.GetName() +} + +func (self *SInstanceType) GetPrepaidStatus() string { + return api.SkuStatusSoldout +} + +func (self *SInstanceType) GetPostpaidStatus() string { + return api.SkuStatusAvailable +} + +func (self *SInstanceType) GetCpuArch() string { + return "" +} + +func (self *SInstanceType) GetCpuCoreCount() int { + return int(self.CpuCoreCount) +} + +func (self *SInstanceType) GetMemorySizeMB() int { + return int(self.MemorySize * 1024) +} + +func (self *SInstanceType) GetOsName() string { + return "Any" +} + +func (self *SInstanceType) GetSysDiskResizable() bool { + return true +} + +func (self *SInstanceType) GetSysDiskType() string { + return "" +} + +func (self *SInstanceType) GetSysDiskMinSizeGB() int { + return 0 +} + +func (self *SInstanceType) GetSysDiskMaxSizeGB() int { + return 0 +} + +func (self *SInstanceType) GetAttachedDiskType() string { + return "iscsi" +} + +func (self *SInstanceType) GetAttachedDiskSizeGB() int { + return 0 +} + +func (self *SInstanceType) GetAttachedDiskCount() int { + return 0 +} + +func (self *SInstanceType) GetDataDiskTypes() string { + return "" +} + +func (self *SInstanceType) GetDataDiskMaxCount() int { + return 6 +} + +func (self *SInstanceType) GetNicType() string { + return "vpc" +} + +func (self *SInstanceType) GetNicMaxCount() int { + return 1 +} + +func (self *SInstanceType) GetGpuAttachable() bool { + return false +} + +func (self *SInstanceType) GetGpuSpec() string { + return "" +} + +func (self *SInstanceType) GetGpuCount() int { + return 0 +} + +func (self *SInstanceType) GetGpuMaxCount() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ipv6_gateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ipv6_gateway.go new file mode 100644 index 0000000000..2fc43e0e23 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ipv6_gateway.go @@ -0,0 +1,132 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "time" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SIPv6Gateway struct { + multicloud.SResourceBase + ApsaraTags + region *SRegion + + Status string `json:"Status"` + Description string `json:"Description"` + InstanceChargeType string `json:"InstanceChargeType"` + Ipv6GatewayId string `json:"Ipv6GatewayId"` + BusinessStatus string `json:"BusinessStatus"` + Name string `json:"Name"` + VpcID string `json:"VpcId"` + ExpiredTime string `json:"ExpiredTime"` + CreationTime time.Time `json:"CreationTime"` + RegionId string `json:"RegionId"` + Spec string `json:"Spec"` + + DepartmentInfo +} + +func (self *SIPv6Gateway) GetGlobalId() string { + return self.Ipv6GatewayId +} + +func (self *SIPv6Gateway) GetId() string { + return self.Ipv6GatewayId +} + +func (self *SIPv6Gateway) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.Ipv6GatewayId +} + +func (self *SIPv6Gateway) GetStatus() string { + return self.Status +} + +func (self *SIPv6Gateway) GetInstanceType() string { + return self.Spec +} + +func (self *SIPv6Gateway) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SRegion) GetIPv6Gateways(vpcId string, pageNumber, pageSize int) ([]SIPv6Gateway, int, error) { + if pageSize < 1 { + pageSize = 50 + } + if pageNumber < 1 { + pageNumber = 1 + } + params := map[string]string{ + "PageSize": fmt.Sprintf("%d", pageSize), + "PageNumber": fmt.Sprintf("%d", 1), + } + if len(vpcId) > 0 { + params["VpcId"] = vpcId + } + resp, err := self.vpcRequest("DescribeIpv6Gateways", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeIpv6Gateways") + } + ret := []SIPv6Gateway{} + err = resp.Unmarshal(&ret, "Ipv6Gateways", "Ipv6Gateway") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + totalCount, _ := resp.Int("TotalCount") + return ret, int(totalCount), nil +} + +func (self *SRegion) GetIPv6Gateway(id string) (*SIPv6Gateway, error) { + params := map[string]string{ + "Ipv6GatewayId": id, + } + resp, err := self.vpcRequest("DescribeIpv6GatewayAttribute", params) + if err != nil { + return nil, err + } + ret := &SIPv6Gateway{region: self} + return ret, resp.Unmarshal(ret) +} + +func (self *SVpc) GetICloudIPv6Gateways() ([]cloudprovider.ICloudIPv6Gateway, error) { + res, pageNumber := []SIPv6Gateway{}, 1 + for { + part, total, err := self.region.GetIPv6Gateways(self.VpcId, pageNumber, 50) + if err != nil { + return nil, err + } + res = append(res, part...) + if len(res) >= total { + break + } + pageNumber++ + } + ret := []cloudprovider.ICloudIPv6Gateway{} + for i := range res { + res[i].region = self.region + ret = append(ret, &res[i]) + } + return ret, nil +} diff --git a/pkg/multicloud/apsara/keypair.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/keypair.go similarity index 100% rename from pkg/multicloud/apsara/keypair.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/keypair.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancer.go new file mode 100644 index 0000000000..433cda0f3f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancer.go @@ -0,0 +1,410 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type ListenerProtocol string + +const ( + ListenerProtocolTCP ListenerProtocol = "tcp" + ListenerProtocolUDP ListenerProtocol = "udp" + ListenerProtocolHTTP ListenerProtocol = "http" + ListenerProtocolHTTPS ListenerProtocol = "https" +) + +type ListenerPorts struct { + ListenerPort []int +} + +type ListenerPortsAndProtocol struct { + ListenerPortAndProtocol []ListenerPortAndProtocol +} + +type ListenerPortAndProtocol struct { + Description string + ListenerPort int + ListenerProtocol ListenerProtocol +} + +type BackendServers struct { + BackendServer []SLoadbalancerDefaultBackend +} + +type SLoadbalancer struct { + multicloud.SLoadbalancerBase + ApsaraTags + region *SRegion + + LoadBalancerId string //负载均衡实例ID。 + LoadBalancerName string //负载均衡实例的名称。 + LoadBalancerStatus string //负载均衡实例状态:inactive: 此状态的实例监听不会再转发流量。active: 实例创建后,默认状态为active。 locked: 实例已经被锁定。 + Address string //负载均衡实例的服务地址。 + RegionId string //负载均衡实例的地域ID。 + RegionIdAlias string //负载均衡实例的地域名称。 + AddressType string //负载均衡实例的网络类型。 + VSwitchId string //私网负载均衡实例的交换机ID。 + VpcId string //私网负载均衡实例的专有网络ID。 + NetworkType string //私网负载均衡实例的网络类型:vpc:专有网络实例 classic:经典网络实例 + ListenerPorts ListenerPorts + ListenerPortsAndProtocol ListenerPortsAndProtocol + BackendServers BackendServers + CreateTime time.Time //负载均衡实例的创建时间。 + MasterZoneId string //实例的主可用区ID。 + SlaveZoneId string //实例的备可用区ID。 + InternetChargeType TInternetChargeType //公网实例的计费方式。取值:paybybandwidth:按带宽计费 paybytraffic:按流量计费(默认值) 说明 当 PayType参数的值为PrePay时,只支持按带宽计费。 + PayType string //实例的计费类型,取值:PayOnDemand:按量付费 PrePay:预付费 + LoadBalancerSpec string //负载均衡实例的的性能规格 + Bandwidth int //按带宽计费的公网型实例的带宽峰值 + DepartmentInfo +} + +func (lb *SLoadbalancer) GetName() string { + return lb.LoadBalancerName +} + +func (lb *SLoadbalancer) GetId() string { + return lb.LoadBalancerId +} + +func (lb *SLoadbalancer) GetGlobalId() string { + return lb.LoadBalancerId +} + +func (lb *SLoadbalancer) GetStatus() string { + if lb.LoadBalancerStatus == "active" { + return api.LB_STATUS_ENABLED + } + return api.LB_STATUS_DISABLED +} + +func (lb *SLoadbalancer) GetTags() (map[string]string, error) { + tags, err := lb.region.ListResourceTags("slb", "instance", []string{lb.GetId()}) + if err != nil { + return nil, errors.Wrap(err, "lb.region.ListResourceTags") + } + if _, ok := tags[lb.GetId()]; !ok { + return map[string]string{}, nil + } + return *tags[lb.GetId()], nil +} + +func (lb *SLoadbalancer) GetAddress() string { + return lb.Address +} + +func (lb *SLoadbalancer) GetAddressType() string { + return lb.AddressType +} + +func (lb *SLoadbalancer) GetNetworkType() string { + return lb.NetworkType +} + +func (lb *SLoadbalancer) GetNetworkIds() []string { + return []string{lb.VSwitchId} +} + +func (lb *SLoadbalancer) GetZoneId() string { + zone, err := lb.region.getZoneById(lb.MasterZoneId) + if err != nil { + log.Errorf("failed to find zone for lb %s error: %v", lb.LoadBalancerName, err) + return "" + } + return zone.GetGlobalId() +} + +func (self *SLoadbalancer) GetZone1Id() string { + return "" +} + +func (lb *SLoadbalancer) IsEmulated() bool { + return false +} + +func (lb *SLoadbalancer) GetVpcId() string { + return lb.VpcId +} + +func (lb *SLoadbalancer) Refresh() error { + loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId) + if err != nil { + return err + } + return jsonutils.Update(lb, loadbalancer) +} + +func (region *SRegion) GetLoadbalancers(ids []string) ([]SLoadbalancer, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + if ids != nil && len(ids) > 0 { + params["LoadBalancerId"] = strings.Join(ids, ",") + } + body, err := region.lbRequest("DescribeLoadBalancers", params) + if err != nil { + return nil, err + } + lbs := []SLoadbalancer{} + return lbs, body.Unmarshal(&lbs, "LoadBalancers", "LoadBalancer") +} + +func (region *SRegion) GetLoadbalancerDetail(loadbalancerId string) (*SLoadbalancer, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + body, err := region.lbRequest("DescribeLoadBalancerAttribute", params) + if err != nil { + return nil, err + } + lb := SLoadbalancer{region: region} + return &lb, body.Unmarshal(&lb) +} + +func (lb *SLoadbalancer) Delete(ctx context.Context) error { + params := map[string]string{} + params["RegionId"] = lb.region.RegionId + params["LoadBalancerId"] = lb.LoadBalancerId + _, err := lb.region.lbRequest("DeleteLoadBalancer", params) + return err +} + +func (lb *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + ibackendgroups := []cloudprovider.ICloudLoadbalancerBackendGroup{} + { + backendgroups, err := lb.region.GetLoadbalancerBackendgroups(lb.LoadBalancerId) + if err != nil { + return nil, err + } + + for i := 0; i < len(backendgroups); i++ { + backendgroups[i].lb = lb + ibackendgroups = append(ibackendgroups, &backendgroups[i]) + } + } + { + iDefaultBackendgroup := SLoadbalancerDefaultBackendGroup{lb: lb} + ibackendgroups = append(ibackendgroups, &iDefaultBackendgroup) + + } + { + backendgroups, err := lb.region.GetLoadbalancerMasterSlaveBackendgroups(lb.LoadBalancerId) + if err != nil { + return nil, err + } + for i := 0; i < len(backendgroups); i++ { + backendgroups[i].lb = lb + ibackendgroups = append(ibackendgroups, &backendgroups[i]) + } + } + return ibackendgroups, nil +} + +func (lb *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + switch group.GroupType { + case api.LB_BACKENDGROUP_TYPE_NORMAL: + group, err := lb.region.CreateLoadbalancerBackendGroup(group.Name, lb.LoadBalancerId, group.Backends) + if err != nil { + return nil, err + } + group.lb = lb + return group, nil + case api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE: + group, err := lb.region.CreateLoadbalancerMasterSlaveBackendGroup(group.Name, lb.LoadBalancerId, group.Backends) + if err != nil { + return nil, err + } + group.lb = lb + return group, nil + default: + return nil, fmt.Errorf("Unsupport backendgroup type %s", group.GroupType) + } +} + +func (lb *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + switch listener.ListenerType { + case api.LB_LISTENER_TYPE_TCP: + return lb.region.CreateLoadbalancerTCPListener(lb, listener) + case api.LB_LISTENER_TYPE_UDP: + return lb.region.CreateLoadbalancerUDPListener(lb, listener) + case api.LB_LISTENER_TYPE_HTTP: + return lb.region.CreateLoadbalancerHTTPListener(lb, listener) + case api.LB_LISTENER_TYPE_HTTPS: + return lb.region.CreateLoadbalancerHTTPSListener(lb, listener) + } + return nil, fmt.Errorf("unsupport listener type %s", listener.ListenerType) +} + +func (lb *SLoadbalancer) GetLoadbalancerSpec() string { + if len(lb.LoadBalancerSpec) == 0 { + lb.Refresh() + } + return lb.LoadBalancerSpec +} + +func (lb *SLoadbalancer) GetChargeType() string { + switch lb.InternetChargeType { + case "paybybandwidth": + return api.LB_CHARGE_TYPE_BY_BANDWIDTH + case "paybytraffic": + return api.LB_CHARGE_TYPE_BY_TRAFFIC + } + return "unknown" +} + +func (lb *SLoadbalancer) GetCreatedAt() time.Time { + return lb.CreateTime +} + +func (lb *SLoadbalancer) GetEgressMbps() int { + if lb.Bandwidth < 1 { + return 0 + } + return lb.Bandwidth +} + +func (lb *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + groups, err := lb.GetILoadBalancerBackendGroups() + if err != nil { + return nil, err + } + for i := 0; i < len(groups); i++ { + if groups[i].GetGlobalId() == groupId { + return groups[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (lb *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { + if lb.AddressType == "internet" { + eip := SEipAddress{ + region: lb.region, + IpAddress: lb.Address, + InstanceId: lb.GetGlobalId(), + InstanceType: EIP_INTANNCE_TYPE_SLB, + Status: EIP_STATUS_INUSE, + AllocationId: lb.GetGlobalId(), + AllocationTime: lb.CreateTime, + Bandwidth: lb.Bandwidth, + InternetChargeType: lb.InternetChargeType, + } + return &eip, nil + } + eips, total, err := lb.region.GetEips("", lb.LoadBalancerId, 0, 1) + if err != nil { + return nil, errors.Wrapf(err, "lb.region.GetEips(%s)", lb.LoadBalancerId) + } + if total != 1 { + return nil, cloudprovider.ErrNotFound + } + eips[0].region = lb.region + return &eips[0], nil +} + +func (region *SRegion) loadbalancerOperation(loadbalancerId, status string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["LoadBalancerStatus"] = status + _, err := region.lbRequest("SetLoadBalancerStatus", params) + return err +} + +func (lb *SLoadbalancer) Start() error { + if lb.LoadBalancerStatus != "active" { + return lb.region.loadbalancerOperation(lb.LoadBalancerId, "active") + } + return nil +} + +func (lb *SLoadbalancer) Stop() error { + if lb.LoadBalancerStatus != "inactive" { + return lb.region.loadbalancerOperation(lb.LoadBalancerId, "inactive") + } + return nil +} + +func (lb *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { + listener, err := lb.GetILoadBalancerListeners() + if err != nil { + return nil, err + } + for i := 0; i < len(listener); i++ { + if listener[i].GetGlobalId() == listenerId { + return listener[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (lb *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + loadbalancer, err := lb.region.GetLoadbalancerDetail(lb.LoadBalancerId) + if err != nil { + return nil, err + } + listeners := []cloudprovider.ICloudLoadbalancerListener{} + for _, listenerInfo := range loadbalancer.ListenerPortsAndProtocol.ListenerPortAndProtocol { + switch listenerInfo.ListenerProtocol { + case ListenerProtocolHTTP: + listener, err := lb.region.GetLoadbalancerHTTPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) + if err != nil { + return nil, err + } + listener.lb = lb + listeners = append(listeners, listener) + case ListenerProtocolHTTPS: + listener, err := lb.region.GetLoadbalancerHTTPSListener(lb.LoadBalancerId, listenerInfo.ListenerPort) + if err != nil { + return nil, err + } + listener.lb = lb + listeners = append(listeners, listener) + case ListenerProtocolTCP: + listener, err := lb.region.GetLoadbalancerTCPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) + if err != nil { + return nil, err + } + listener.lb = lb + listeners = append(listeners, listener) + case ListenerProtocolUDP: + listener, err := lb.region.GetLoadbalancerUDPListener(lb.LoadBalancerId, listenerInfo.ListenerPort) + if err != nil { + return nil, err + } + listener.lb = lb + listeners = append(listeners, listener) + default: + return nil, fmt.Errorf("failed to recognize %s type listener", listenerInfo.ListenerProtocol) + } + } + return listeners, nil +} + +func (lb *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { + return lb.region.SetResourceTags("slb", "instance", []string{lb.LoadBalancerId}, tags, replace) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalanceracl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalanceracl.go new file mode 100644 index 0000000000..97f040fa9e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalanceracl.go @@ -0,0 +1,160 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type AclEntrys struct { + AclEntry []AclEntry +} + +type AclEntry struct { + AclEntryComment string + AclEntryIP string +} + +type SLoadbalancerAcl struct { + multicloud.SResourceBase + ApsaraTags + region *SRegion + + AclId string + AclName string + + AclEntrys AclEntrys + + DepartmentInfo +} + +func (acl *SLoadbalancerAcl) GetAclListenerID() string { + return "" +} + +func (acl *SLoadbalancerAcl) GetName() string { + return acl.AclName +} + +func (acl *SLoadbalancerAcl) GetId() string { + return acl.AclId +} + +func (acl *SLoadbalancerAcl) GetGlobalId() string { + return acl.AclId +} + +func (acl *SLoadbalancerAcl) GetStatus() string { + return "" +} + +func (acl *SLoadbalancerAcl) IsEmulated() bool { + return false +} + +func (acl *SLoadbalancerAcl) Refresh() error { + loadbalancerAcl, err := acl.region.GetLoadbalancerAclDetail(acl.AclId) + if err != nil { + return err + } + return jsonutils.Update(acl, loadbalancerAcl) +} + +func (acl *SLoadbalancerAcl) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { + detail, err := acl.region.GetLoadbalancerAclDetail(acl.AclId) + if err != nil { + log.Errorf("GetLoadbalancerAclDetail %s failed: %v", acl.AclId, err) + return nil + } + entrys := []cloudprovider.SLoadbalancerAccessControlListEntry{} + for _, entry := range detail.AclEntrys.AclEntry { + entrys = append(entrys, cloudprovider.SLoadbalancerAccessControlListEntry{CIDR: entry.AclEntryIP, Comment: entry.AclEntryComment}) + } + return entrys +} + +func (region *SRegion) UpdateAclName(aclId, name string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["AclId"] = aclId + params["AclName"] = name + _, err := region.lbRequest("SetAccessControlListAttribute", params) + return err +} + +func (region *SRegion) RemoveAccessControlListEntry(aclId string, data jsonutils.JSONObject) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["AclId"] = aclId + params["AclEntrys"] = data.String() + _, err := region.lbRequest("RemoveAccessControlListEntry", params) + return err +} + +func (acl *SLoadbalancerAcl) Delete() error { + params := map[string]string{} + params["RegionId"] = acl.region.RegionId + params["AclId"] = acl.AclId + _, err := acl.region.lbRequest("DeleteAccessControlList", params) + return err +} + +func (region *SRegion) GetLoadbalancerAclDetail(aclId string) (*SLoadbalancerAcl, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["AclId"] = aclId + body, err := region.lbRequest("DescribeAccessControlListAttribute", params) + if err != nil { + return nil, err + } + detail := SLoadbalancerAcl{region: region} + return &detail, body.Unmarshal(&detail) +} + +func (region *SRegion) GetLoadBalancerAcls() ([]SLoadbalancerAcl, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + body, err := region.lbRequest("DescribeAccessControlLists", params) + if err != nil { + return nil, err + } + acls := []SLoadbalancerAcl{} + return acls, body.Unmarshal(&acls, "Acls", "Acl") +} + +func (acl *SLoadbalancerAcl) Sync(_acl *cloudprovider.SLoadbalancerAccessControlList) error { + if acl.AclName != _acl.Name { + if err := acl.region.UpdateAclName(acl.AclId, _acl.Name); err != nil { + return err + } + } + entrys := jsonutils.NewArray() + for _, entry := range acl.AclEntrys.AclEntry { + entrys.Add(jsonutils.Marshal(map[string]string{"entry": entry.AclEntryIP, "comment": entry.AclEntryComment})) + } + if entrys.Length() > 0 { + if err := acl.region.RemoveAccessControlListEntry(acl.AclId, entrys); err != nil && !isError(err, "Acl does not have any entry") { + return err + } + } + if len(_acl.Entrys) > 0 { + return acl.region.AddAccessControlListEntry(acl.AclId, _acl.Entrys) + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerbackend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerbackend.go new file mode 100644 index 0000000000..56ee690a90 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerbackend.go @@ -0,0 +1,114 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerBackend struct { + multicloud.SResourceBase + ApsaraTags + lbbg *SLoadbalancerBackendGroup + + ServerId string + Port int + Weight int + DepartmentInfo +} + +func (backend *SLoadbalancerBackend) GetName() string { + return backend.ServerId +} + +func (backend *SLoadbalancerBackend) GetId() string { + return fmt.Sprintf("%s/%s", backend.lbbg.VServerGroupId, backend.ServerId) +} + +func (backend *SLoadbalancerBackend) GetGlobalId() string { + return backend.GetId() +} + +func (backend *SLoadbalancerBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backend *SLoadbalancerBackend) IsEmulated() bool { + return false +} + +func (backend *SLoadbalancerBackend) Refresh() error { + loadbalancerBackends, err := backend.lbbg.lb.region.GetLoadbalancerBackends(backend.lbbg.VServerGroupId) + if err != nil { + return err + } + for _, loadbalancerBackend := range loadbalancerBackends { + if loadbalancerBackend.ServerId == backend.ServerId { + return jsonutils.Update(backend, loadbalancerBackend) + } + } + return cloudprovider.ErrNotFound +} + +func (backend *SLoadbalancerBackend) GetWeight() int { + return backend.Weight +} + +func (backend *SLoadbalancerBackend) GetPort() int { + return backend.Port +} + +func (backend *SLoadbalancerBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (backend *SLoadbalancerBackend) GetBackendRole() string { + return api.LB_BACKEND_ROLE_DEFAULT +} + +func (backend *SLoadbalancerBackend) GetBackendId() string { + return backend.ServerId +} + +func (backend *SLoadbalancerBackend) GetIpAddress() string { + return "" +} + +func (region *SRegion) GetLoadbalancerBackends(backendgroupId string) ([]SLoadbalancerBackend, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["VServerGroupId"] = backendgroupId + body, err := region.lbRequest("DescribeVServerGroupAttribute", params) + if err != nil { + return nil, err + } + backends := []SLoadbalancerBackend{} + return backends, body.Unmarshal(&backends, "BackendServers", "BackendServer") +} + +func (backend *SLoadbalancerBackend) SyncConf(ctx context.Context, port, weight int) error { + err := backend.lbbg.lb.region.RemoveBackendVServer(backend.lbbg.lb.LoadBalancerId, backend.lbbg.VServerGroupId, backend.ServerId, backend.Port) + if err != nil { + return err + } + return backend.lbbg.lb.region.AddBackendVServer(backend.lbbg.lb.LoadBalancerId, backend.lbbg.VServerGroupId, backend.ServerId, weight, port) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerbackendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerbackendgroup.go new file mode 100644 index 0000000000..28cbb239ef --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerbackendgroup.go @@ -0,0 +1,274 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type Rule struct { + RuleId string + RuleName string + Domain string + Url string +} + +type Rules struct { + Rule []Rule +} + +type Listener struct { + Protocol string + Port int +} + +type Listeners struct { + Listener []Listener +} + +type AssociatedObjects struct { + Rules Rules + Listeners Listeners +} + +type SLoadbalancerBackendGroup struct { + multicloud.SResourceBase + ApsaraTags + lb *SLoadbalancer + + VServerGroupId string + VServerGroupName string + AssociatedObjects AssociatedObjects + DepartmentInfo +} + +func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { + return backendgroup.lb +} + +func (backendgroup *SLoadbalancerBackendGroup) GetLoadbalancerId() string { + return backendgroup.lb.GetId() +} + +func (backendgroup *SLoadbalancerBackendGroup) GetProtocolType() string { + return "" +} + +func (backendgroup *SLoadbalancerBackendGroup) GetScheduler() string { + return "" +} + +func (backendgroup *SLoadbalancerBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerBackendGroup) GetName() string { + return backendgroup.VServerGroupName +} + +func (backendgroup *SLoadbalancerBackendGroup) GetId() string { + return backendgroup.VServerGroupId +} + +func (backendgroup *SLoadbalancerBackendGroup) GetGlobalId() string { + return backendgroup.VServerGroupId +} + +func (backendgroup *SLoadbalancerBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backendgroup *SLoadbalancerBackendGroup) IsDefault() bool { + return false +} + +func (backendgroup *SLoadbalancerBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_NORMAL +} + +func (backendgroup *SLoadbalancerBackendGroup) IsEmulated() bool { + return false +} + +func (backendgroup *SLoadbalancerBackendGroup) Refresh() error { + loadbalancerBackendgroups, err := backendgroup.lb.region.GetLoadbalancerBackendgroups(backendgroup.lb.LoadBalancerId) + if err != nil { + return err + } + for _, loadbalancerBackendgroup := range loadbalancerBackendgroups { + if loadbalancerBackendgroup.VServerGroupId == backendgroup.VServerGroupId { + return jsonutils.Update(backendgroup, loadbalancerBackendgroup) + } + } + return cloudprovider.ErrNotFound +} + +func (region *SRegion) GetLoadbalancerBackendgroups(loadbalancerId string) ([]SLoadbalancerBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + body, err := region.lbRequest("DescribeVServerGroups", params) + if err != nil { + return nil, err + } + backendgroups := []SLoadbalancerBackendGroup{} + return backendgroups, body.Unmarshal(&backendgroups, "VServerGroups", "VServerGroup") +} + +func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := backendgroup.lb.region.GetLoadbalancerBackends(backendgroup.VServerGroupId) + if err != nil { + return nil, err + } + ibackends := []cloudprovider.ICloudLoadbalancerBackend{} + for i := 0; i < len(backends); i++ { + backends[i].lbbg = backendgroup + ibackends = append(ibackends, &backends[i]) + } + return ibackends, nil +} + +func (backendgroup *SLoadbalancerBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := backendgroup.GetILoadbalancerBackends() + if err != nil { + return nil, err + } + for i := 0; i < len(backends); i++ { + if backends[i].GetGlobalId() == backendId { + return backends[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) CreateLoadbalancerBackendGroup(name, loadbalancerId string, backends []cloudprovider.SLoadbalancerBackend) (*SLoadbalancerBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["VServerGroupName"] = name + params["LoadBalancerId"] = loadbalancerId + if len(backends) > 0 { + servers := jsonutils.NewArray() + for _, backend := range backends { + servers.Add( + jsonutils.Marshal( + map[string]string{ + "ServerId": backend.ExternalID, + "Port": fmt.Sprintf("%d", backend.Port), + "Weight": fmt.Sprintf("%d", backend.Weight), + }, + )) + } + params["BackendServers"] = servers.String() + } + body, err := region.lbRequest("CreateVServerGroup", params) + if err != nil { + return nil, err + } + groupId, err := body.GetString("VServerGroupId") + if err != nil { + return nil, err + } + return region.GetLoadbalancerBackendgroupById(groupId) +} + +func (region *SRegion) GetLoadbalancerBackendgroupById(groupId string) (*SLoadbalancerBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["VServerGroupId"] = groupId + body, err := region.lbRequest("DescribeVServerGroupAttribute", params) + if err != nil { + return nil, err + } + group := &SLoadbalancerBackendGroup{} + return group, body.Unmarshal(group) +} + +func (region *SRegion) UpdateLoadBalancerBackendGroupName(name, groupId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["VServerGroupId"] = groupId + params["VServerGroupName"] = name + _, err := region.lbRequest("SetVServerGroupAttribute", params) + return err +} + +func (backendgroup *SLoadbalancerBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + if group == nil { + return nil + } + + if backendgroup.VServerGroupName != group.Name { + return backendgroup.lb.region.UpdateLoadBalancerBackendGroupName(backendgroup.VServerGroupId, group.Name) + } + return nil +} + +func (region *SRegion) DeleteLoadBalancerBackendGroup(groupId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["VServerGroupId"] = groupId + _, err := region.lbRequest("DeleteVServerGroup", params) + return err +} + +func (backendgroup *SLoadbalancerBackendGroup) Delete(ctx context.Context) error { + return backendgroup.lb.region.DeleteLoadBalancerBackendGroup(backendgroup.VServerGroupId) +} + +func (region *SRegion) AddBackendVServer(loadbalancerId, backendGroupId, serverId string, weight, port int) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["VServerGroupId"] = backendGroupId + servers := jsonutils.NewArray() + servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Weight": fmt.Sprintf("%d", weight), "Port": fmt.Sprintf("%d", port)})) + params["BackendServers"] = servers.String() + _, err := region.lbRequest("AddVServerGroupBackendServers", params) + return err +} + +func (region *SRegion) RemoveBackendVServer(loadbalancerId, backendgroupId, serverId string, port int) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["VServerGroupId"] = backendgroupId + servers := jsonutils.NewArray() + servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Port": fmt.Sprintf("%d", port)})) + params["BackendServers"] = servers.String() + _, err := region.lbRequest("RemoveVServerGroupBackendServers", params) + return err +} + +func (backendgroup *SLoadbalancerBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + if err := backendgroup.lb.region.AddBackendVServer(backendgroup.lb.LoadBalancerId, backendgroup.VServerGroupId, serverId, weight, port); err != nil { + return nil, err + } + return &SLoadbalancerBackend{lbbg: backendgroup, ServerId: serverId, Weight: weight, Port: port}, nil +} + +func (backendgroup *SLoadbalancerBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { + return backendgroup.lb.region.RemoveBackendVServer(backendgroup.lb.LoadBalancerId, backendgroup.VServerGroupId, serverId, port) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerdefaultbackend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerdefaultbackend.go new file mode 100644 index 0000000000..179ef6bb09 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerdefaultbackend.go @@ -0,0 +1,112 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerDefaultBackend struct { + multicloud.SResourceBase + ApsaraTags + lbbg *SLoadbalancerDefaultBackendGroup + + ServerId string + Weight int + DepartmentInfo +} + +func (backend *SLoadbalancerDefaultBackend) GetName() string { + return backend.ServerId +} + +func (backend *SLoadbalancerDefaultBackend) GetId() string { + return fmt.Sprintf("%s/%s", backend.lbbg.lb.LoadBalancerId, backend.ServerId) +} + +func (backend *SLoadbalancerDefaultBackend) GetGlobalId() string { + return backend.GetId() +} + +func (backend *SLoadbalancerDefaultBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backend *SLoadbalancerDefaultBackend) IsEmulated() bool { + return false +} + +func (backend *SLoadbalancerDefaultBackend) Refresh() error { + return nil +} + +func (backend *SLoadbalancerDefaultBackend) GetWeight() int { + return backend.Weight +} + +func (backend *SLoadbalancerDefaultBackend) GetPort() int { + return 0 +} + +func (backend *SLoadbalancerDefaultBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (backend *SLoadbalancerDefaultBackend) GetBackendRole() string { + return api.LB_BACKEND_ROLE_DEFAULT +} + +func (backend *SLoadbalancerDefaultBackend) GetBackendId() string { + return backend.ServerId +} + +func (backend *SLoadbalancerDefaultBackend) GetIpAddress() string { + return "" +} + +func (backend *SLoadbalancerDefaultBackend) SyncConf(ctx context.Context, port, weight int) error { + params := map[string]string{} + params["RegionId"] = backend.lbbg.lb.region.RegionId + params["LoadBalancerId"] = backend.lbbg.lb.LoadBalancerId + loadbalancer, err := backend.lbbg.lb.region.GetLoadbalancerDetail(backend.lbbg.lb.LoadBalancerId) + if err != nil { + return err + } + servers := jsonutils.NewArray() + for i := 0; i < len(loadbalancer.BackendServers.BackendServer); i++ { + _backend := loadbalancer.BackendServers.BackendServer[i] + _backend.lbbg = backend.lbbg + if _backend.GetGlobalId() == backend.GetGlobalId() { + _backend.Weight = weight + } + servers.Add( + jsonutils.Marshal( + map[string]string{ + "ServerId": _backend.ServerId, + "Weight": fmt.Sprintf("%d", _backend.Weight), + }, + )) + } + + params["BackendServers"] = servers.String() + _, err = backend.lbbg.lb.region.lbRequest("SetBackendServers", params) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerdefaultbackendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerdefaultbackendgroup.go new file mode 100644 index 0000000000..f062c89e10 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerdefaultbackendgroup.go @@ -0,0 +1,156 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerDefaultBackendGroup struct { + multicloud.SResourceBase + ApsaraTags + lb *SLoadbalancer + DepartmentInfo +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { + return backendgroup.lb +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetLoadbalancerId() string { + return backendgroup.lb.GetId() +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetProtocolType() string { + return "" +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetScheduler() string { + return "" +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetName() string { + return fmt.Sprintf("%s(%s)-default", backendgroup.lb.LoadBalancerName, backendgroup.lb.Address) +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetId() string { + return fmt.Sprintf("%s/default", backendgroup.lb.LoadBalancerId) +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetGlobalId() string { + return backendgroup.GetId() +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) IsDefault() bool { + return true +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_DEFAULT +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) IsEmulated() bool { + return false +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) Refresh() error { + return nil +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + loadbalancer, err := backendgroup.lb.region.GetLoadbalancerDetail(backendgroup.lb.LoadBalancerId) + if err != nil { + return nil, err + } + ibackends := []cloudprovider.ICloudLoadbalancerBackend{} + for i := 0; i < len(loadbalancer.BackendServers.BackendServer); i++ { + loadbalancer.BackendServers.BackendServer[i].lbbg = backendgroup + ibackends = append(ibackends, &loadbalancer.BackendServers.BackendServer[i]) + } + return ibackends, nil +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := backendgroup.GetILoadbalancerBackends() + if err != nil { + return nil, err + } + for i := 0; i < len(backends); i++ { + if backends[i].GetGlobalId() == backendId { + return backends[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + return cloudprovider.ErrNotSupported +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) Delete(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (region *SRegion) AddBackendServer(loadbalancerId, serverId string, weight, port int) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + servers := jsonutils.NewArray() + servers.Add(jsonutils.Marshal(map[string]string{"ServerId": serverId, "Weight": fmt.Sprintf("%d", weight)})) + params["BackendServers"] = servers.String() + _, err := region.lbRequest("AddBackendServers", params) + return err +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + if err := backendgroup.lb.region.AddBackendServer(backendgroup.lb.LoadBalancerId, serverId, weight, port); err != nil { + return nil, err + } + return &SLoadbalancerDefaultBackend{lbbg: backendgroup, ServerId: serverId, Weight: weight}, nil +} + +func (region *SRegion) RemoveBackendServer(loadbalancerId, serverId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + servers := jsonutils.NewArray() + servers.Add(jsonutils.NewString(serverId)) + params["BackendServers"] = servers.String() + _, err := region.lbRequest("RemoveBackendServers", params) + return err +} + +func (backendgroup *SLoadbalancerDefaultBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { + return backendgroup.lb.region.RemoveBackendServer(backendgroup.lb.LoadBalancerId, serverId) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerhttplistener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerhttplistener.go new file mode 100644 index 0000000000..48d37afdd5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerhttplistener.go @@ -0,0 +1,376 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerHTTPListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + ApsaraTags + lb *SLoadbalancer + + ListenerPort int // 负载均衡实例前端使用的端口。 + BackendServerPort int // 负载均衡实例后端使用的端口。 + Bandwidth int // 监听的带宽峰值。 + Status string // 当前监听的状态。取值:starting | running | configuring | stopping | stopped + Description string + + XForwardedFor string // 是否开启通过X-Forwarded-For头字段获取访者真实IP。 + XForwardedFor_SLBIP string // 是否通过SLB-IP头字段获取客户端请求的真实IP。 + XForwardedFor_SLBID string // 是否通过SLB-ID头字段获取负载均衡实例ID。 + XForwardedFor_proto string // 是否通过X-Forwarded-Proto头字段获取负载均衡实例的监听协议。 + Scheduler string // 调度算法。 + StickySession string // 是否开启会话保持。 + StickySessionType string // cookie的处理方式。 + CookieTimeout int // Cookie超时时间。 + Cookie string // 服务器上配置的cookie。 + AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) + + AclType string // 访问控制类型: + //white: 仅转发来自所选访问控制策略组中设置的IP地址或地址段的请求,白名单适用于应用只允许特定IP访问的场景。 + //设置白名单存在一定业务风险。一旦设置白名单,就只有白名单中的IP可以访问负载均衡监听。如果开启了白名单访问,但访问策略组中没有添加任何IP,则负载均衡监听会转发全部请求。 + + //black: 来自所选访问控制策略组中设置的IP地址或地址段的所有请求都不会转发,黑名单适用于应用只限制某些特定IP访问的场景。 + //如果开启了黑名单访问,但访问策略组中没有添加任何IP,则负载均衡监听会转发全部请求。 + + //当AclStatus参数的值为on时,该参数必选。 + + AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 + + HealthCheck string // 是否开启健康检查。 + HealthCheckDomain string // 用于健康检查的域名。 + HealthCheckURI string // 用于健康检查的URI。 + HealthyThreshold int // 健康检查阈值。 + UnhealthyThreshold int // 不健康检查阈值。 + HealthCheckTimeout int // 每次健康检查响应的最大超时间,单位为秒。 + HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 + HealthCheckHttpCode string // 健康检查正常的HTTP状态码。 + HealthCheckConnectPort int // 健康检查的端口。 + Gzip string // 是否开启Gzip压缩。 + EnableHttp2 string // 是否开启HTTP/2特性。取值:on(默认值)|off + + Rules Rules //监听下的转发规则列表,具体请参见RuleList。 + ForwardPort int // HTTP至HTTPS的监听转发端口。暂时只支持将HTTP 80访问重定向转发至HTTPS 443。 说明 如果 ListenerForward的值为 off,该参数不显示。 + ListenerForward string // 表示是否开启HTTP至HTTPS的监听转发。on:表示开启 off:表示未开启 + VServerGroupId string // 绑定的服务器组ID + DepartmentInfo +} + +func (listener *SLoadbalancerHTTPListener) GetName() string { + if len(listener.Description) == 0 { + listener.Refresh() + } + if len(listener.Description) > 0 { + return listener.Description + } + return fmt.Sprintf("HTTP:%d", listener.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPListener) GetId() string { + return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPListener) GetGlobalId() string { + return listerner.GetId() +} + +func (listerner *SLoadbalancerHTTPListener) GetStatus() string { + switch listerner.Status { + case "starting", "running": + return api.LB_STATUS_ENABLED + case "configuring", "stopping", "stopped": + return api.LB_STATUS_DISABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (listerner *SLoadbalancerHTTPListener) IsEmulated() bool { + return false +} + +func (listerner *SLoadbalancerHTTPListener) GetEgressMbps() int { + if listerner.Bandwidth < 1 { + return 0 + } + return listerner.Bandwidth +} + +func (listerner *SLoadbalancerHTTPListener) Refresh() error { + lis, err := listerner.lb.region.GetLoadbalancerHTTPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return err + } + return jsonutils.Update(listerner, lis) +} + +func (listerner *SLoadbalancerHTTPListener) GetListenerType() string { + return "http" +} + +func (listerner *SLoadbalancerHTTPListener) GetListenerPort() int { + return listerner.ListenerPort +} + +func (listerner *SLoadbalancerHTTPListener) GetBackendGroupId() string { + if len(listerner.VServerGroupId) == 0 { + listerner.Refresh() + } + return listerner.VServerGroupId +} + +func (listerner *SLoadbalancerHTTPListener) GetBackendServerPort() int { + return listerner.BackendServerPort +} + +func (listerner *SLoadbalancerHTTPListener) GetScheduler() string { + return listerner.Scheduler +} + +func (listerner *SLoadbalancerHTTPListener) GetAclStatus() string { + return listerner.AclStatus +} + +func (listerner *SLoadbalancerHTTPListener) GetAclType() string { + return listerner.AclType +} + +func (listerner *SLoadbalancerHTTPListener) GetAclId() string { + return listerner.AclId +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheck() string { + return listerner.HealthCheck +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckType() string { + return api.LB_HEALTH_CHECK_HTTP +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckDomain() string { + return listerner.HealthCheckDomain +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckURI() string { + return listerner.HealthCheckURI +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckCode() string { + return listerner.HealthCheckHttpCode +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckRise() int { + return listerner.HealthyThreshold +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckFail() int { + return listerner.UnhealthyThreshold +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckTimeout() int { + return listerner.HealthCheckTimeout +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckInterval() int { + return listerner.HealthCheckInterval +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckReq() string { + return "" +} + +func (listerner *SLoadbalancerHTTPListener) GetHealthCheckExp() string { + return "" +} + +func (listerner *SLoadbalancerHTTPListener) GetStickySession() string { + return listerner.StickySession +} + +func (listerner *SLoadbalancerHTTPListener) GetStickySessionType() string { + return listerner.StickySessionType +} + +func (listerner *SLoadbalancerHTTPListener) GetStickySessionCookie() string { + return listerner.Cookie +} + +func (listerner *SLoadbalancerHTTPListener) GetStickySessionCookieTimeout() int { + return listerner.CookieTimeout +} + +func (listerner *SLoadbalancerHTTPListener) XForwardedForEnabled() bool { + if listerner.XForwardedFor == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPListener) GzipEnabled() bool { + if listerner.Gzip == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPListener) GetCertificateId() string { + return "" +} + +func (listerner *SLoadbalancerHTTPListener) GetTLSCipherPolicy() string { + return "" +} + +func (listerner *SLoadbalancerHTTPListener) HTTP2Enabled() bool { + if listerner.EnableHttp2 == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + rules, err := listerner.lb.region.GetLoadbalancerListenerRules(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return nil, err + } + iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} + for i := 0; i < len(rules); i++ { + rules[i].httpListener = listerner + iRules = append(iRules, &rules[i]) + } + return iRules, nil +} + +func (region *SRegion) GetLoadbalancerHTTPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerHTTPListener, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + body, err := region.lbRequest("DescribeLoadBalancerHTTPListenerAttribute", params) + if err != nil { + return nil, err + } + listener := SLoadbalancerHTTPListener{} + return &listener, body.Unmarshal(&listener) +} + +func (region *SRegion) DeleteLoadbalancerListener(loadbalancerId string, listenerPort int) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + _, err := region.lbRequest("DeleteLoadBalancerListener", params) + return err +} + +func (region *SRegion) CreateLoadbalancerHTTPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + params := region.constructBaseCreateListenerParams(lb, listener) + params = region.constructHTTPCreateListenerParams(params, listener) + _, err := region.lbRequest("CreateLoadBalancerHTTPListener", params) + if err != nil { + return nil, err + } + iListener, err := region.GetLoadbalancerHTTPListener(lb.LoadBalancerId, listener.ListenerPort) + if err != nil { + return nil, err + } + iListener.lb = lb + return iListener, nil +} + +func (listerner *SLoadbalancerHTTPListener) Delete(ctx context.Context) error { + return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + _rule := &SLoadbalancerListenerRule{ + Domain: rule.Domain, + Url: rule.Path, + RuleName: rule.Name, + } + if len(rule.BackendGroupID) > 0 { //&& rule.BackendGroupType == api.LB_BACKENDGROUP_TYPE_NORMAL { + _rule.VServerGroupId = rule.BackendGroupID + } + listenerRule, err := listerner.lb.region.CreateLoadbalancerListenerRule(listerner.ListenerPort, listerner.lb.LoadBalancerId, _rule) + if err != nil { + return nil, err + } + listenerRule.httpListener = listerner + return listenerRule, nil +} + +func (listerner *SLoadbalancerHTTPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + rule, err := listerner.lb.region.GetLoadbalancerListenerRule(ruleId) + if err != nil { + return nil, err + } + rule.httpListener = listerner + return rule, nil +} + +func (region *SRegion) startListener(listenerPort int, loadbalancerId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + _, err := region.lbRequest("StartLoadBalancerListener", params) + return err +} + +func (region *SRegion) stopListener(listenerPort int, loadbalancerId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + _, err := region.lbRequest("StopLoadBalancerListener", params) + return err +} + +func (listerner *SLoadbalancerHTTPListener) Start() error { + return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (listerner *SLoadbalancerHTTPListener) Stop() error { + return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (region *SRegion) SyncLoadbalancerHTTPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { + params := region.constructBaseCreateListenerParams(lb, listener) + params = region.constructHTTPCreateListenerParams(params, listener) + _, err := region.lbRequest("SetLoadBalancerHTTPListenerAttribute", params) + return err +} + +func (listerner *SLoadbalancerHTTPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { + return listerner.lb.region.SyncLoadbalancerHTTPListener(listerner.lb, lblis) +} + +func (listerner *SLoadbalancerHTTPListener) GetClientIdleTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerHTTPListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerhttpslistener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerhttpslistener.go new file mode 100644 index 0000000000..85c014308f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerhttpslistener.go @@ -0,0 +1,406 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerHTTPSListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + ApsaraTags + lb *SLoadbalancer + + ListenerPort int // 负载均衡实例前端使用的端口。 + BackendServerPort int // 负载均衡实例后端使用的端口。 + Bandwidth int // 监听的带宽峰值。 + Status string // 当前监听的状态。取值:starting | running | configuring | stopping | stopped + Description string + + XForwardedFor string // 是否开启通过X-Forwarded-For头字段获取访者真实IP。 + XForwardedFor_SLBIP string // 是否通过SLB-IP头字段获取客户端请求的真实IP。 + XForwardedFor_SLBID string // 是否通过SLB-ID头字段获取负载均衡实例ID。 + XForwardedFor_proto string // 是否通过X-Forwarded-Proto头字段获取负载均衡实例的监听协议。 + Scheduler string // 调度算法。 + StickySession string // 是否开启会话保持。 + StickySessionType string // cookie的处理方式。 + CookieTimeout int // Cookie超时时间。 + Cookie string // 服务器上配置的cookie。 + AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) + + AclType string // 访问控制类型 + + AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 + + HealthCheck string // 是否开启健康检查。 + HealthCheckDomain string // 用于健康检查的域名。 + HealthCheckURI string // 用于健康检查的URI。 + HealthyThreshold int // 健康检查阈值。 + UnhealthyThreshold int // 不健康检查阈值。 + HealthCheckTimeout int // 每次健康检查响应的最大超时间,单位为秒。 + HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 + HealthCheckHttpCode string // 健康检查正常的HTTP状态码。 + HealthCheckConnectPort int // 健康检查的端口。 + VServerGroupId string // 绑定的服务器组ID。 + ServerCertificateId string // 服务器证书ID。 + CACertificateId string // CA证书ID。 + Gzip string // 是否开启Gzip压缩。 + Rules Rules //监听下的转发规则列表,具体请参见RuleList。 + DomainExtensions string // 域名扩展列表,具体请参见DomainExtensions。 + EnableHttp2 string // 是否开启HTTP/2特性。取值:on(默认值)|off + + TLSCipherPolicy string // + DepartmentInfo +} + +func (listener *SLoadbalancerHTTPSListener) GetName() string { + if len(listener.Description) == 0 { + listener.Refresh() + } + if len(listener.Description) > 0 { + return listener.Description + } + return fmt.Sprintf("HTTPS:%d", listener.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPSListener) GetId() string { + return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPSListener) GetGlobalId() string { + return listerner.GetId() +} + +func (listerner *SLoadbalancerHTTPSListener) GetStatus() string { + switch listerner.Status { + case "starting", "running": + return api.LB_STATUS_ENABLED + case "configuring", "stopping", "stopped": + return api.LB_STATUS_DISABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (listerner *SLoadbalancerHTTPSListener) IsEmulated() bool { + return false +} + +func (listerner *SLoadbalancerHTTPSListener) GetEgressMbps() int { + if listerner.Bandwidth < 1 { + return 0 + } + return listerner.Bandwidth +} + +func (listerner *SLoadbalancerHTTPSListener) Refresh() error { + lis, err := listerner.lb.region.GetLoadbalancerHTTPSListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return err + } + return jsonutils.Update(listerner, lis) +} + +func (listerner *SLoadbalancerHTTPSListener) GetListenerType() string { + return "https" +} + +func (listerner *SLoadbalancerHTTPSListener) GetListenerPort() int { + return listerner.ListenerPort +} + +func (listerner *SLoadbalancerHTTPSListener) GetBackendGroupId() string { + if len(listerner.VServerGroupId) == 0 { + listerner.Refresh() + } + return listerner.VServerGroupId +} + +func (listerner *SLoadbalancerHTTPSListener) GetBackendServerPort() int { + return listerner.BackendServerPort +} + +func (listerner *SLoadbalancerHTTPSListener) GetScheduler() string { + return listerner.Scheduler +} + +func (listerner *SLoadbalancerHTTPSListener) GetAclStatus() string { + return listerner.AclStatus +} + +func (listerner *SLoadbalancerHTTPSListener) GetAclType() string { + return listerner.AclType +} + +func (listerner *SLoadbalancerHTTPSListener) GetAclId() string { + return listerner.AclId +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheck() string { + return listerner.HealthCheck +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckType() string { + return api.LB_HEALTH_CHECK_HTTP +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckDomain() string { + return listerner.HealthCheckDomain +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckURI() string { + return listerner.HealthCheckURI +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckCode() string { + return listerner.HealthCheckHttpCode +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckRise() int { + return listerner.HealthyThreshold +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckFail() int { + return listerner.UnhealthyThreshold +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckTimeout() int { + return listerner.HealthCheckTimeout +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckInterval() int { + return listerner.HealthCheckInterval +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckReq() string { + return "" +} + +func (listerner *SLoadbalancerHTTPSListener) GetHealthCheckExp() string { + return "" +} + +func (listerner *SLoadbalancerHTTPSListener) GetStickySession() string { + return listerner.StickySession +} + +func (listerner *SLoadbalancerHTTPSListener) GetStickySessionType() string { + return listerner.StickySessionType +} + +func (listerner *SLoadbalancerHTTPSListener) GetStickySessionCookie() string { + return listerner.Cookie +} + +func (listerner *SLoadbalancerHTTPSListener) GetStickySessionCookieTimeout() int { + return listerner.CookieTimeout +} + +func (listerner *SLoadbalancerHTTPSListener) XForwardedForEnabled() bool { + if listerner.XForwardedFor == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPSListener) GzipEnabled() bool { + if listerner.Gzip == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPSListener) GetCertificateId() string { + return listerner.ServerCertificateId +} + +func (listerner *SLoadbalancerHTTPSListener) GetTLSCipherPolicy() string { + return listerner.TLSCipherPolicy +} + +func (listerner *SLoadbalancerHTTPSListener) HTTP2Enabled() bool { + if listerner.EnableHttp2 == "on" { + return true + } + return false +} + +func (listerner *SLoadbalancerHTTPSListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + rules, err := listerner.lb.region.GetLoadbalancerListenerRules(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return nil, err + } + iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} + for i := 0; i < len(rules); i++ { + rules[i].httpsListener = listerner + iRules = append(iRules, &rules[i]) + } + return iRules, nil +} + +func (region *SRegion) GetLoadbalancerHTTPSListener(loadbalancerId string, listenerPort int) (*SLoadbalancerHTTPSListener, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + body, err := region.lbRequest("DescribeLoadBalancerHTTPSListenerAttribute", params) + if err != nil { + return nil, err + } + listener := SLoadbalancerHTTPSListener{} + return &listener, body.Unmarshal(&listener) +} + +func (region *SRegion) constructHTTPCreateListenerParams(params map[string]string, listener *cloudprovider.SLoadbalancerListener) map[string]string { + params["HealthCheck"] = listener.HealthCheck + if listener.HealthCheck == "on" { + if len(listener.HealthCheckURI) == 0 { + params["HealthCheckURI"] = "/" + } + //The HealthCheckTimeout parameter is required. + if listener.HealthCheckTimeout < 1 || listener.HealthCheckTimeout > 300 { + listener.HealthCheckTimeout = 5 + } + params["HealthCheckTimeout"] = fmt.Sprintf("%d", listener.HealthCheckTimeout) + } + + if listener.ClientRequestTimeout < 1 || listener.ClientRequestTimeout > 180 { + listener.ClientRequestTimeout = 60 + } + params["RequestTimeout"] = fmt.Sprintf("%d", listener.ClientRequestTimeout) + + if listener.ClientIdleTimeout < 1 || listener.ClientIdleTimeout > 60 { + listener.ClientIdleTimeout = 15 + } + params["IdleTimeout"] = fmt.Sprintf("%d", listener.ClientIdleTimeout) + + params["StickySession"] = listener.StickySession + params["StickySessionType"] = listener.StickySessionType + params["Cookie"] = listener.StickySessionCookie + if listener.StickySessionCookieTimeout < 1 || listener.StickySessionCookieTimeout > 86400 { + listener.StickySessionCookieTimeout = 500 + } + params["CookieTimeout"] = fmt.Sprintf("%d", listener.StickySessionCookieTimeout) + //params["ForwardPort"] = fmt.Sprintf("%d", listener.ForwardPort) //暂不支持 + params["Gzip"] = "off" + if listener.Gzip { + params["Gzip"] = "on" + } + params["XForwardedFor"] = "off" + if listener.XForwardedFor { + params["XForwardedFor"] = "on" + } + return params +} + +func (region *SRegion) CreateLoadbalancerHTTPSListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + params := region.constructBaseCreateListenerParams(lb, listener) + params = region.constructHTTPCreateListenerParams(params, listener) + params["ServerCertificateId"] = listener.CertificateID + if listener.EnableHTTP2 { + params["EnableHttp2"] = "on" + } else { + params["EnableHttp2"] = "off" + } + + if len(listener.TLSCipherPolicy) > 0 { + params["TLSCipherPolicy"] = listener.TLSCipherPolicy + } + _, err := region.lbRequest("CreateLoadBalancerHTTPSListener", params) + if err != nil { + return nil, err + } + iListener, err := region.GetLoadbalancerHTTPSListener(lb.LoadBalancerId, listener.ListenerPort) + if err != nil { + return nil, err + } + iListener.lb = lb + return iListener, nil +} + +func (listerner *SLoadbalancerHTTPSListener) Delete(ctx context.Context) error { + return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerHTTPSListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + _rule := &SLoadbalancerListenerRule{ + Domain: rule.Domain, + Url: rule.Path, + RuleName: rule.Name, + } + if len(rule.BackendGroupID) > 0 { //&& rule.BackendGroupType == api.LB_BACKENDGROUP_TYPE_NORMAL { + _rule.VServerGroupId = rule.BackendGroupID + } + listenerRule, err := listerner.lb.region.CreateLoadbalancerListenerRule(listerner.ListenerPort, listerner.lb.LoadBalancerId, _rule) + if err != nil { + return nil, err + } + listenerRule.httpsListener = listerner + return listenerRule, nil +} + +func (listerner *SLoadbalancerHTTPSListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + rule, err := listerner.lb.region.GetLoadbalancerListenerRule(ruleId) + if err != nil { + return nil, err + } + rule.httpsListener = listerner + return rule, nil +} + +func (listerner *SLoadbalancerHTTPSListener) Start() error { + return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (listerner *SLoadbalancerHTTPSListener) Stop() error { + return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (region *SRegion) SyncLoadbalancerHTTPSListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { + params := region.constructBaseCreateListenerParams(lb, listener) + params = region.constructHTTPCreateListenerParams(params, listener) + params["ServerCertificateId"] = listener.CertificateID + if listener.EnableHTTP2 { + params["EnableHttp2"] = "on" + } else { + params["EnableHttp2"] = "off" + } + + if len(lb.LoadBalancerSpec) > 0 && len(listener.TLSCipherPolicy) > 0 { + params["TLSCipherPolicy"] = listener.TLSCipherPolicy + } + _, err := region.lbRequest("SetLoadBalancerHTTPSListenerAttribute", params) + return err +} + +func (listerner *SLoadbalancerHTTPSListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { + return listerner.lb.region.SyncLoadbalancerHTTPSListener(listerner.lb, lblis) +} + +func (listerner *SLoadbalancerHTTPSListener) GetClientIdleTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerHTTPSListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerlistenerrule.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerlistenerrule.go new file mode 100644 index 0000000000..b934aaf434 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerlistenerrule.go @@ -0,0 +1,173 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerListenerRule struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + ApsaraTags + httpListener *SLoadbalancerHTTPListener + httpsListener *SLoadbalancerHTTPSListener + + Domain string `json:"Domain"` + ListenerSync string + RuleId string + RuleName string `json:"RuleName"` + Url string `json:"Url"` + VServerGroupId string `json:"VServerGroupId"` + DepartmentInfo +} + +func (lbr *SLoadbalancerListenerRule) GetName() string { + return lbr.RuleName +} + +func (lbr *SLoadbalancerListenerRule) GetId() string { + return lbr.RuleId +} + +func (lbr *SLoadbalancerListenerRule) GetGlobalId() string { + return lbr.RuleId +} + +func (lbr *SLoadbalancerListenerRule) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancerListenerRule) IsDefault() bool { + return false +} + +func (lbr *SLoadbalancerListenerRule) IsEmulated() bool { + return false +} + +func (lbr *SLoadbalancerListenerRule) getRegion() *SRegion { + if lbr.httpListener != nil { + return lbr.httpListener.lb.region + } else if lbr.httpsListener != nil { + return lbr.httpsListener.lb.region + } + return nil +} + +func (lbr *SLoadbalancerListenerRule) Refresh() error { + region := lbr.getRegion() + if region == nil { + return fmt.Errorf("failed to find listener for rule %s", lbr.RuleName) + } + rule, err := region.GetLoadbalancerListenerRule(lbr.RuleId) + if err != nil { + return err + } + return jsonutils.Update(lbr, rule) +} + +func (lbr *SLoadbalancerListenerRule) GetCondition() string { + return "" +} + +func (lbr *SLoadbalancerListenerRule) GetDomain() string { + return lbr.Domain +} + +func (lbr *SLoadbalancerListenerRule) GetPath() string { + return lbr.Url +} + +func (lbr *SLoadbalancerListenerRule) GetBackendGroupId() string { + return lbr.VServerGroupId +} + +func (region *SRegion) GetLoadbalancerListenerRules(loadbalancerId string, listenerPort int) ([]SLoadbalancerListenerRule, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + body, err := region.lbRequest("DescribeRules", params) + if err != nil { + return nil, err + } + rules := []SLoadbalancerListenerRule{} + return rules, body.Unmarshal(&rules, "Rules", "Rule") +} + +func (lbr *SLoadbalancerListenerRule) Delete(ctx context.Context) error { + if lbr.httpListener != nil { + return lbr.httpListener.lb.region.DeleteLoadbalancerListenerRule(lbr.RuleId) + } + if lbr.httpsListener != nil { + return lbr.httpsListener.lb.region.DeleteLoadbalancerListenerRule(lbr.RuleId) + } + return fmt.Errorf("failed to find listener for listener rule %s", lbr.RuleName) +} + +func (region *SRegion) DeleteLoadbalancerListenerRule(ruleId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["RuleIds"] = fmt.Sprintf(`["%s"]`, ruleId) + _, err := region.lbRequest("DeleteRules", params) + return err +} + +func (region *SRegion) CreateLoadbalancerListenerRule(listenerPort int, loadbalancerId string, _rule *SLoadbalancerListenerRule) (*SLoadbalancerListenerRule, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + params["LoadBalancerId"] = loadbalancerId + _rules := jsonutils.NewArray() + _rules.Add(jsonutils.Marshal(_rule)) + params["RuleList"] = _rules.String() + body, err := region.lbRequest("CreateRules", params) + if err != nil { + return nil, err + } + rules := []SLoadbalancerListenerRule{} + if err := body.Unmarshal(&rules, "Rules", "Rule"); err != nil { + return nil, err + } + for _, rule := range rules { + if rule.RuleName == _rule.RuleName { + return region.GetLoadbalancerListenerRule(rule.RuleId) + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetLoadbalancerListenerRule(ruleId string) (*SLoadbalancerListenerRule, error) { + if len(ruleId) == 0 { + return nil, cloudprovider.ErrNotFound + } + params := map[string]string{} + params["RegionId"] = region.RegionId + params["RuleId"] = ruleId + body, err := region.lbRequest("DescribeRuleAttribute", params) + if err != nil { + return nil, err + } + rule := &SLoadbalancerListenerRule{RuleId: ruleId} + return rule, body.Unmarshal(rule) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancermasterslavebackend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancermasterslavebackend.go new file mode 100644 index 0000000000..b2428a9701 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancermasterslavebackend.go @@ -0,0 +1,89 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + "strings" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerMasterSlaveBackend struct { + multicloud.SResourceBase + ApsaraTags + lbbg *SLoadbalancerMasterSlaveBackendGroup + + ServerId string + Weight int + Port int + ServerType string + DepartmentInfo +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetName() string { + return backend.ServerId +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetId() string { + return fmt.Sprintf("%s/%s", backend.lbbg.MasterSlaveServerGroupId, backend.ServerId) +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetGlobalId() string { + return backend.GetId() +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backend *SLoadbalancerMasterSlaveBackend) IsEmulated() bool { + return false +} + +func (backend *SLoadbalancerMasterSlaveBackend) Refresh() error { + return nil +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetWeight() int { + return backend.Weight +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetPort() int { + return backend.Port +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetBackendRole() string { + return strings.ToLower(backend.ServerType) +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetBackendId() string { + return backend.ServerId +} + +func (backend *SLoadbalancerMasterSlaveBackend) GetIpAddress() string { + return "" +} + +func (backend *SLoadbalancerMasterSlaveBackend) SyncConf(ctx context.Context, port, weight int) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancermasterslavebackendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancermasterslavebackendgroup.go new file mode 100644 index 0000000000..48dbd8c72b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancermasterslavebackendgroup.go @@ -0,0 +1,211 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerMasterSlaveBackendGroup struct { + multicloud.SResourceBase + ApsaraTags + lb *SLoadbalancer + + MasterSlaveServerGroupId string + MasterSlaveServerGroupName string + DepartmentInfo +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetLoadbalancerId() string { + return backendgroup.lb.GetId() +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetProtocolType() string { + return "" +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetScheduler() string { + return "" +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + return nil, nil +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetName() string { + return backendgroup.MasterSlaveServerGroupName +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetId() string { + return backendgroup.MasterSlaveServerGroupId +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetGlobalId() string { + return backendgroup.GetId() +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) IsEmulated() bool { + return false +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Refresh() error { + return nil +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) IsDefault() bool { + return false +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE +} + +func (region *SRegion) GetLoadbalancerMasterSlaveBackendgroups(loadbalancerId string) ([]SLoadbalancerMasterSlaveBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + body, err := region.lbRequest("DescribeMasterSlaveServerGroups", params) + if err != nil { + return nil, err + } + backendgroups := []SLoadbalancerMasterSlaveBackendGroup{} + return backendgroups, body.Unmarshal(&backendgroups, "MasterSlaveServerGroups", "MasterSlaveServerGroup") +} + +func (region *SRegion) GetLoadbalancerMasterSlaveBackends(backendgroupId string) ([]SLoadbalancerMasterSlaveBackend, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["MasterSlaveServerGroupId"] = backendgroupId + body, err := region.lbRequest("DescribeMasterSlaveServerGroupAttribute", params) + if err != nil { + return nil, err + } + backends := []SLoadbalancerMasterSlaveBackend{} + return backends, body.Unmarshal(&backends, "MasterSlaveBackendServers", "MasterSlaveBackendServer") +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := backendgroup.lb.region.GetLoadbalancerMasterSlaveBackends(backendgroup.MasterSlaveServerGroupId) + if err != nil { + return nil, err + } + ibackends := []cloudprovider.ICloudLoadbalancerBackend{} + for i := 0; i < len(backends); i++ { + backends[i].lbbg = backendgroup + ibackends = append(ibackends, &backends[i]) + } + return ibackends, nil +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := backendgroup.GetILoadbalancerBackends() + if err != nil { + return nil, err + } + for i := 0; i < len(backends); i++ { + if backends[i].GetGlobalId() == backendId { + return backends[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) CreateLoadbalancerMasterSlaveBackendGroup(name, loadbalancerId string, backends []cloudprovider.SLoadbalancerBackend) (*SLoadbalancerMasterSlaveBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["MasterSlaveServerGroupName"] = name + params["LoadBalancerId"] = loadbalancerId + if len(backends) != 2 { + return nil, fmt.Errorf("master slave backendgorup must contain two backend") + } + servers := jsonutils.NewArray() + for _, backend := range backends { + serverType := "Slave" + if backend.Index == 0 { + serverType = "Master" + } + servers.Add( + jsonutils.Marshal( + map[string]string{ + "ServerId": backend.ExternalID, + "Port": fmt.Sprintf("%d", backend.Port), + "Weight": fmt.Sprintf("%d", backend.Weight), + "ServerType": serverType, + }, + )) + } + params["MasterSlaveBackendServers"] = servers.String() + body, err := region.lbRequest("CreateMasterSlaveServerGroup", params) + if err != nil { + return nil, err + } + groupId, err := body.GetString("MasterSlaveServerGroupId") + if err != nil { + return nil, err + } + return region.GetLoadbalancerMasterSlaveBackendgroupById(groupId) +} + +func (region *SRegion) GetLoadbalancerMasterSlaveBackendgroupById(groupId string) (*SLoadbalancerMasterSlaveBackendGroup, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["MasterSlaveServerGroupId"] = groupId + params["NeedInstanceDetail"] = "true" + body, err := region.lbRequest("DescribeMasterSlaveServerGroupAttribute", params) + if err != nil { + return nil, err + } + group := &SLoadbalancerMasterSlaveBackendGroup{} + return group, body.Unmarshal(group) +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + return nil +} + +func (region *SRegion) DeleteLoadbalancerMasterSlaveBackendgroup(groupId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["MasterSlaveServerGroupId"] = groupId + _, err := region.lbRequest("DeleteMasterSlaveServerGroup", params) + return err +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) Delete(ctx context.Context) error { + return backendgroup.lb.region.DeleteLoadbalancerMasterSlaveBackendgroup(backendgroup.MasterSlaveServerGroupId) +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) AddBackendServer(serverId string, weight, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerservercertificate.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerservercertificate.go new file mode 100644 index 0000000000..66a1591e94 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerservercertificate.go @@ -0,0 +1,135 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SubjectAlternativeNames struct { + SubjectAlternativeName []string +} + +type SLoadbalancerServerCertificate struct { + multicloud.SResourceBase + ApsaraTags + region *SRegion + + ServerCertificateId string // 服务器证书ID。 + ServerCertificateName string // 服务器证书名称。 + Fingerprint string // 服务器证书的指纹。 + CreateTime string // 服务器证书上传的时间。 + CreateTimeStamp uint64 // 服务器证书上传的时间戳。 + IsAliCloudCertificate int // 是否是阿里云证书。0代表不是阿里云证书。 + AliCloudCertificateName string // 阿里云证书名称。 + AliCloudCertificateId string // 阿里云证书ID。 + ExpireTime time.Time // 过期时间。 + ExpireTimeStamp uint64 // 过期时间戳。 + CommonName string // 域名,对应证书的CommonName字段。 + SubjectAlternativeNames SubjectAlternativeNames // 数组格式,返回证书的备用域名列表,对应证书的Subject Alternative Name字段,详情请参见SubjectAlternativeNames。 + RegionId string // 负载均衡实例的地域。 + DepartmentInfo +} + +func (certificate *SLoadbalancerServerCertificate) GetPublickKey() string { + return "" +} + +func (certificate *SLoadbalancerServerCertificate) GetPrivateKey() string { + return "" +} + +func (certificate *SLoadbalancerServerCertificate) GetName() string { + return certificate.ServerCertificateName +} + +func (certificate *SLoadbalancerServerCertificate) GetId() string { + return certificate.ServerCertificateId +} + +func (certificate *SLoadbalancerServerCertificate) GetGlobalId() string { + return certificate.GetId() +} + +func (certificate *SLoadbalancerServerCertificate) GetStatus() string { + return "" +} + +func (certificate *SLoadbalancerServerCertificate) IsEmulated() bool { + return false +} + +func (certificate *SLoadbalancerServerCertificate) GetCommonName() string { + return certificate.CommonName +} + +func (certificate *SLoadbalancerServerCertificate) GetSubjectAlternativeNames() string { + return strings.Join(certificate.SubjectAlternativeNames.SubjectAlternativeName, ",") +} + +func (certificate *SLoadbalancerServerCertificate) GetFingerprint() string { + return fmt.Sprintf("sha1:%s", strings.Replace(certificate.Fingerprint, ":", "", -1)) +} + +func (certificate *SLoadbalancerServerCertificate) GetExpireTime() time.Time { + return certificate.ExpireTime +} + +func (certificate *SLoadbalancerServerCertificate) Refresh() error { + return nil +} + +func (region *SRegion) UpdateServerCertificateName(certId, name string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["ServerCertificateId"] = certId + params["ServerCertificateName"] = name + _, err := region.lbRequest("SetServerCertificateName", params) + return err +} + +func (certificate *SLoadbalancerServerCertificate) Sync(name string, privateKey string, publicKey string) error { + if certificate.ServerCertificateName != name { + return certificate.region.UpdateServerCertificateName(certificate.ServerCertificateId, name) + } + return nil +} + +func (certificate *SLoadbalancerServerCertificate) Delete() error { + return certificate.region.DeleteServerCertificate(certificate.ServerCertificateId) +} + +func (region *SRegion) DeleteServerCertificate(certId string) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["ServerCertificateId"] = certId + _, err := region.lbRequest("DeleteServerCertificate", params) + return err +} + +func (region *SRegion) GetLoadbalancerServerCertificates() ([]SLoadbalancerServerCertificate, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + body, err := region.lbRequest("DescribeServerCertificates", params) + if err != nil { + return nil, err + } + certificates := []SLoadbalancerServerCertificate{} + return certificates, body.Unmarshal(&certificates, "ServerCertificates", "ServerCertificate") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancertcplistener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancertcplistener.go new file mode 100644 index 0000000000..910a6c5969 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancertcplistener.go @@ -0,0 +1,365 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerTCPListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + ApsaraTags + lb *SLoadbalancer + + ListenerPort int // 负载均衡实例前端使用的端口。 + BackendServerPort int // 负载均衡实例后端使用的端口。 + Bandwidth int // 监听的带宽峰值。 + Status string // 当前监听的状态,取值:starting | running | configuring | stopping | stopped + Description string + + Scheduler string // 调度算法。 + VServerGroupId string // 绑定的服务器组ID。 + MasterSlaveServerGroupId string // 绑定的主备服务器组ID。 + AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) + PersistenceTimeout int //是否开启了会话保持。取值为0时,表示没有开启。 + + AclType string // 访问控制类型 + + AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 + + HealthCheck string // 是否开启健康检查。 + HealthCheckType string //TCP协议监听的健康检查方式。取值:tcp | http + HealthyThreshold int // 健康检查阈值。 + UnhealthyThreshold int // 不健康检查阈值。 + HealthCheckConnectTimeout int // 每次健康检查响应的最大超时间,单位为秒。 + HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 + HealthCheckConnectPort int // 健康检查的端口。 + DepartmentInfo +} + +func (listener *SLoadbalancerTCPListener) GetName() string { + if len(listener.Description) == 0 { + listener.Refresh() + } + if len(listener.Description) > 0 { + return listener.Description + } + return fmt.Sprintf("TCP:%d", listener.ListenerPort) +} + +func (listerner *SLoadbalancerTCPListener) GetId() string { + return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerTCPListener) GetGlobalId() string { + return listerner.GetId() +} + +func (listerner *SLoadbalancerTCPListener) GetStatus() string { + switch listerner.Status { + case "starting", "running": + return api.LB_STATUS_ENABLED + case "configuring", "stopping", "stopped": + return api.LB_STATUS_DISABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (listerner *SLoadbalancerTCPListener) GetEgressMbps() int { + if listerner.Bandwidth < 1 { + return 0 + } + return listerner.Bandwidth +} + +func (listerner *SLoadbalancerTCPListener) IsEmulated() bool { + return false +} + +func (listerner *SLoadbalancerTCPListener) Refresh() error { + lis, err := listerner.lb.region.GetLoadbalancerTCPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return err + } + return jsonutils.Update(listerner, lis) +} + +func (listerner *SLoadbalancerTCPListener) GetListenerType() string { + return "tcp" +} +func (listerner *SLoadbalancerTCPListener) GetListenerPort() int { + return listerner.ListenerPort +} + +func (listerner *SLoadbalancerTCPListener) GetBackendGroupId() string { + if len(listerner.VServerGroupId) > 0 { + return listerner.VServerGroupId + } + return listerner.MasterSlaveServerGroupId +} + +func (listerner *SLoadbalancerTCPListener) GetScheduler() string { + return listerner.Scheduler +} + +func (listerner *SLoadbalancerTCPListener) GetAclStatus() string { + return listerner.AclStatus +} + +func (listerner *SLoadbalancerTCPListener) GetAclType() string { + return listerner.AclType +} + +func (listerner *SLoadbalancerTCPListener) GetAclId() string { + return listerner.AclId +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheck() string { + return listerner.HealthCheck +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckType() string { + return listerner.HealthCheckType +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckDomain() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckURI() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckCode() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckRise() int { + return listerner.HealthyThreshold +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckFail() int { + return listerner.UnhealthyThreshold +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckTimeout() int { + return listerner.HealthCheckConnectTimeout +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckInterval() int { + return listerner.HealthCheckInterval +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckReq() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetHealthCheckExp() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetStickySession() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetStickySessionType() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetStickySessionCookie() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetStickySessionCookieTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerTCPListener) XForwardedForEnabled() bool { + return false +} + +func (listerner *SLoadbalancerTCPListener) GzipEnabled() bool { + return false +} + +func (listerner *SLoadbalancerTCPListener) GetCertificateId() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) GetTLSCipherPolicy() string { + return "" +} + +func (listerner *SLoadbalancerTCPListener) HTTP2Enabled() bool { + return false +} + +func (listerner *SLoadbalancerTCPListener) GetBackendServerPort() int { + return listerner.BackendServerPort +} + +func (listerner *SLoadbalancerTCPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + return []cloudprovider.ICloudLoadbalancerListenerRule{}, nil +} + +func (region *SRegion) GetLoadbalancerTCPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerTCPListener, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + body, err := region.lbRequest("DescribeLoadBalancerTCPListenerAttribute", params) + if err != nil { + return nil, err + } + listener := SLoadbalancerTCPListener{} + return &listener, body.Unmarshal(&listener) +} + +func (region *SRegion) constructBaseCreateListenerParams(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) map[string]string { + params := map[string]string{} + params["RegionId"] = region.RegionId + if listener.EgressMbps < 1 { + listener.EgressMbps = -1 + } + params["Bandwidth"] = fmt.Sprintf("%d", listener.EgressMbps) + params["ListenerPort"] = fmt.Sprintf("%d", listener.ListenerPort) + params["LoadBalancerId"] = lb.LoadBalancerId + if len(listener.AccessControlListID) > 0 { + params["AclId"] = listener.AccessControlListID + } + if utils.IsInStringArray(listener.AccessControlListStatus, []string{"on", "off"}) { + params["AclStatus"] = listener.AccessControlListStatus + } + if utils.IsInStringArray(listener.AccessControlListType, []string{"white", "black"}) { + params["AclType"] = listener.AccessControlListType + } + switch listener.BackendGroupType { + case api.LB_BACKENDGROUP_TYPE_NORMAL: + params["VServerGroupId"] = listener.BackendGroupID + params["VServerGroup"] = "on" + case api.LB_BACKENDGROUP_TYPE_MASTER_SLAVE: + params["MasterSlaveServerGroupId"] = listener.BackendGroupID + params["MasterSlaveServerGroup"] = "on" + case api.LB_BACKENDGROUP_TYPE_DEFAULT: + params["BackendServerPort"] = fmt.Sprintf("%d", listener.BackendServerPort) + } + if len(listener.Name) > 0 { + params["Description"] = listener.Name + } + + if utils.IsInStringArray(listener.ListenerType, []string{api.LB_LISTENER_TYPE_TCP, api.LB_LISTENER_TYPE_UDP}) { + if listener.HealthCheckTimeout >= 1 && listener.HealthCheckTimeout <= 300 { + params["HealthCheckConnectTimeout"] = fmt.Sprintf("%d", listener.HealthCheckTimeout) + } + } + switch listener.ListenerType { + case api.LB_LISTENER_TYPE_UDP: + if len(listener.HealthCheckReq) > 0 { + params["healthCheckReq"] = listener.HealthCheckReq + } + if len(listener.HealthCheckExp) > 0 { + params["healthCheckExp"] = listener.HealthCheckExp + } + } + + if len(listener.HealthCheckDomain) > 0 { + params["HealthCheckDomain"] = listener.HealthCheckDomain + } + + if len(listener.HealthCheckHttpCode) > 0 { + params["HealthCheckHttpCode"] = listener.HealthCheckHttpCode + } + + if len(listener.HealthCheckURI) > 0 { + params["HealthCheckURI"] = listener.HealthCheckURI + } + + if listener.HealthCheckRise >= 2 && listener.HealthCheckRise <= 10 { + params["HealthyThreshold"] = fmt.Sprintf("%d", listener.HealthCheckRise) + } + + if listener.HealthCheckFail >= 2 && listener.HealthCheckFail <= 10 { + params["UnhealthyThreshold"] = fmt.Sprintf("%d", listener.HealthCheckFail) + } + + if listener.HealthCheckInterval >= 1 && listener.HealthCheckInterval <= 50 { + params["healthCheckInterval"] = fmt.Sprintf("%d", listener.HealthCheckInterval) + } + + params["Scheduler"] = listener.Scheduler + return params +} + +func (region *SRegion) CreateLoadbalancerTCPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + params := region.constructBaseCreateListenerParams(lb, listener) + _, err := region.lbRequest("CreateLoadBalancerTCPListener", params) + if err != nil { + return nil, err + } + iListener, err := region.GetLoadbalancerTCPListener(lb.LoadBalancerId, listener.ListenerPort) + if err != nil { + return nil, err + } + iListener.lb = lb + return iListener, nil +} + +func (listerner *SLoadbalancerTCPListener) Delete(ctx context.Context) error { + return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerTCPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (listerner *SLoadbalancerTCPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (listerner *SLoadbalancerTCPListener) Start() error { + return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (listerner *SLoadbalancerTCPListener) Stop() error { + return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (region *SRegion) SyncLoadbalancerTCPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { + params := region.constructBaseCreateListenerParams(lb, listener) + _, err := region.lbRequest("SetLoadBalancerTCPListenerAttribute", params) + return err +} + +func (listerner *SLoadbalancerTCPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { + return listerner.lb.region.SyncLoadbalancerTCPListener(listerner.lb, lblis) +} + +func (listerner *SLoadbalancerTCPListener) GetClientIdleTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerTCPListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerudplistener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerudplistener.go new file mode 100644 index 0000000000..da62832846 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/loadbalancerudplistener.go @@ -0,0 +1,291 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerUDPListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + ApsaraTags + lb *SLoadbalancer + + ListenerPort int // 负载均衡实例前端使用的端口。 + BackendServerPort int // 负载均衡实例后端使用的端口。 + Bandwidth int // 监听的带宽峰值。 + Status string // 当前监听的状态,取值:starting | running | configuring | stopping | stopped + Description string + + Scheduler string // 调度算法 + VServerGroupId string // 绑定的服务器组ID。 + MasterSlaveServerGroupId string // 绑定的主备服务器组ID。 + AclStatus string // 是否开启访问控制功能。取值:on | off(默认值) + + AclType string // 访问控制类型: + + AclId string // 监听绑定的访问策略组ID。当AclStatus参数的值为on时,该参数必选。 + + HealthCheck string // 是否开启健康检查。 + HealthyThreshold int // 健康检查阈值。 + UnhealthyThreshold int // 不健康检查阈值。 + HealthCheckConnectTimeout int // 每次健康检查响应的最大超时间,单位为秒。 + HealthCheckInterval int // 健康检查的时间间隔,单位为秒。 + HealthCheckConnectPort int // 健康检查的端口。 + + HealthCheckExp string // UDP监听健康检查的响应串 + HealthCheckReq string // UDP监听健康检查的请求串 + DepartmentInfo +} + +func (listener *SLoadbalancerUDPListener) GetName() string { + if len(listener.Description) == 0 { + listener.Refresh() + } + if len(listener.Description) > 0 { + return listener.Description + } + return fmt.Sprintf("UDP:%d", listener.ListenerPort) +} + +func (listerner *SLoadbalancerUDPListener) GetId() string { + return fmt.Sprintf("%s/%d", listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerUDPListener) GetGlobalId() string { + return listerner.GetId() +} + +func (listerner *SLoadbalancerUDPListener) GetStatus() string { + switch listerner.Status { + case "starting", "running": + return api.LB_STATUS_ENABLED + case "configuring", "stopping", "stopped": + return api.LB_STATUS_DISABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (listerner *SLoadbalancerUDPListener) GetEgressMbps() int { + if listerner.Bandwidth < 1 { + return 0 + } + return listerner.Bandwidth +} + +func (listerner *SLoadbalancerUDPListener) IsEmulated() bool { + return false +} + +func (listerner *SLoadbalancerUDPListener) Refresh() error { + lis, err := listerner.lb.region.GetLoadbalancerUDPListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) + if err != nil { + return err + } + return jsonutils.Update(listerner, lis) +} + +func (listerner *SLoadbalancerUDPListener) GetListenerType() string { + return "udp" +} + +func (listerner *SLoadbalancerUDPListener) GetListenerPort() int { + return listerner.ListenerPort +} + +func (listerner *SLoadbalancerUDPListener) GetBackendGroupId() string { + if len(listerner.VServerGroupId) > 0 { + return listerner.VServerGroupId + } + return listerner.MasterSlaveServerGroupId +} + +func (listerner *SLoadbalancerUDPListener) GetBackendServerPort() int { + return listerner.BackendServerPort +} + +func (listerner *SLoadbalancerUDPListener) GetScheduler() string { + return listerner.Scheduler +} + +func (listerner *SLoadbalancerUDPListener) GetAclStatus() string { + return listerner.AclStatus +} + +func (listerner *SLoadbalancerUDPListener) GetAclType() string { + return listerner.AclType +} + +func (listerner *SLoadbalancerUDPListener) GetAclId() string { + return listerner.AclId +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheck() string { + return listerner.HealthCheck +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckType() string { + return api.LB_HEALTH_CHECK_UDP +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckDomain() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckURI() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckCode() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckRise() int { + return listerner.HealthyThreshold +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckFail() int { + return listerner.UnhealthyThreshold +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckTimeout() int { + return listerner.HealthCheckConnectTimeout +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckInterval() int { + return listerner.HealthCheckInterval +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckReq() string { + return listerner.HealthCheckReq +} + +func (listerner *SLoadbalancerUDPListener) GetHealthCheckExp() string { + return listerner.HealthCheckExp +} + +func (listerner *SLoadbalancerUDPListener) GetStickySession() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetStickySessionType() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetStickySessionCookie() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetStickySessionCookieTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerUDPListener) XForwardedForEnabled() bool { + return false +} + +func (listerner *SLoadbalancerUDPListener) GzipEnabled() bool { + return false +} + +func (listerner *SLoadbalancerUDPListener) GetCertificateId() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) GetTLSCipherPolicy() string { + return "" +} + +func (listerner *SLoadbalancerUDPListener) HTTP2Enabled() bool { + return false +} + +func (listerner *SLoadbalancerUDPListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + return []cloudprovider.ICloudLoadbalancerListenerRule{}, nil +} + +func (region *SRegion) GetLoadbalancerUDPListener(loadbalancerId string, listenerPort int) (*SLoadbalancerUDPListener, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerId"] = loadbalancerId + params["ListenerPort"] = fmt.Sprintf("%d", listenerPort) + body, err := region.lbRequest("DescribeLoadBalancerUDPListenerAttribute", params) + if err != nil { + return nil, err + } + listener := SLoadbalancerUDPListener{} + return &listener, body.Unmarshal(&listener) +} + +func (region *SRegion) CreateLoadbalancerUDPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + params := region.constructBaseCreateListenerParams(lb, listener) + _, err := region.lbRequest("CreateLoadBalancerUDPListener", params) + if err != nil { + return nil, err + } + iListener, err := region.GetLoadbalancerUDPListener(lb.LoadBalancerId, listener.ListenerPort) + if err != nil { + return nil, err + } + iListener.lb = lb + return iListener, nil +} + +func (listerner *SLoadbalancerUDPListener) Delete(ctx context.Context) error { + return listerner.lb.region.DeleteLoadbalancerListener(listerner.lb.LoadBalancerId, listerner.ListenerPort) +} + +func (listerner *SLoadbalancerUDPListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (listerner *SLoadbalancerUDPListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (listerner *SLoadbalancerUDPListener) Start() error { + return listerner.lb.region.startListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (listerner *SLoadbalancerUDPListener) Stop() error { + return listerner.lb.region.stopListener(listerner.ListenerPort, listerner.lb.LoadBalancerId) +} + +func (region *SRegion) SyncLoadbalancerUDPListener(lb *SLoadbalancer, listener *cloudprovider.SLoadbalancerListener) error { + params := region.constructBaseCreateListenerParams(lb, listener) + _, err := region.lbRequest("SetLoadBalancerUDPListenerAttribute", params) + return err +} + +func (listerner *SLoadbalancerUDPListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { + return listerner.lb.region.SyncLoadbalancerUDPListener(listerner.lb, lblis) +} + +func (listerner *SLoadbalancerUDPListener) GetClientIdleTimeout() int { + return 0 +} + +func (listerner *SLoadbalancerUDPListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/monitor.go new file mode 100644 index 0000000000..ffeebe9e70 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/monitor.go @@ -0,0 +1,457 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + APSARA_API_VERSION_METRICS = "2019-01-01" +) + +func (self *SApsaraClient) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getDefaultClient("") + if err != nil { + return nil, errors.Wrap(err, "getDefaultClient") + } + domain := self.getDomain(APSARA_PRODUCT_METRICS) + return productRequest(client, APSARA_PRODUCT_METRICS, domain, APSARA_API_VERSION_METRICS, action, params, self.debug) +} + +type MetricData struct { + Timestamp int64 + BucketName string + InstanceId string + UserId string + Value float64 + Average float64 + Minimum float64 + Maximum float64 + Diskname string + Device string +} + +func (d MetricData) GetValue() float64 { + if d.Average > 0 { + return d.Average + } + if d.Maximum > 0 { + return d.Maximum + } + if d.Minimum > 0 { + return d.Minimum + } + if d.Value > 0 { + return d.Value + } + return 0.0 +} + +func (d MetricData) GetTags() map[string]string { + ret := map[string]string{} + if len(d.Device) > 0 { + ret[cloudprovider.METRIC_TAG_DEVICE] = fmt.Sprintf("%s(%s)", d.Device, d.Diskname) + } + return ret +} + +func (self *SApsaraClient) ListMetrics(ns, metricName string, start, end time.Time) ([]MetricData, error) { + result := []MetricData{} + nextToken := "" + for { + part, next, err := self.listMetrics(ns, metricName, nextToken, start, end) + if err != nil { + return nil, errors.Wrap(err, "listMetrics") + } + result = append(result, part...) + if len(next) == 0 { + break + } + nextToken = next + } + return result, nil +} + +func (self *SApsaraClient) listMetrics(ns, metricName, nextToken string, start, end time.Time) ([]MetricData, string, error) { + params := make(map[string]string) + params["MetricName"] = metricName + params["Namespace"] = ns + params["Length"] = "2000" + if len(nextToken) > 0 { + params["NextToken"] = nextToken + } + if len(self.organizationId) > 0 { + params["Department"] = self.organizationId + } + params["StartTime"] = fmt.Sprintf("%d", start.UnixMilli()) + params["EndTime"] = fmt.Sprintf("%d", end.UnixMilli()) + resp, err := self.metricsRequest("DescribeMetricList", params) + if err != nil { + return nil, "", errors.Wrap(err, "DescribeMetricList") + } + ret := struct { + NextToken string + Datapoints string + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, "", errors.Wrapf(err, "resp.Unmarshal") + } + obj, err := jsonutils.ParseString(ret.Datapoints) + if err != nil { + return nil, "", errors.Wrap(err, "jsonutils.ParseString") + } + result := []MetricData{} + err = obj.Unmarshal(&result) + if err != nil { + return nil, "", errors.Wrapf(err, "obj.Unmarshal") + } + return result, ret.NextToken, nil +} + +func (self *SApsaraClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_BUCKET: + return self.GetOssMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: + return self.GetRedisMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_RDS: + return self.GetRdsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_LB: + return self.GetElbMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) + } +} + +func (self *SApsaraClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricTags, tagKey := map[string]string{}, "" + switch opts.MetricType { + case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: + metricTags = map[string]string{ + "CPUUtilization": "", + } + case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: + metricTags = map[string]string{ + "InternetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, + "IntranetInRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + } + tagKey = cloudprovider.METRIC_TAG_NET_TYPE + case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: + metricTags = map[string]string{ + "InternetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, + "IntranetOutRate": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + } + tagKey = cloudprovider.METRIC_TAG_NET_TYPE + case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: + metricTags = map[string]string{ + "DiskReadBPS": "", + } + case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: + metricTags = map[string]string{ + "DiskWriteBPS": "", + } + case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: + metricTags = map[string]string{ + "DiskReadIOPS": "", + } + case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: + metricTags = map[string]string{ + "DiskWriteIOPS": "", + } + case cloudprovider.VM_METRIC_TYPE_MEM_USAGE: + metricTags = map[string]string{ + "memory_usedutilization": "", + } + case cloudprovider.VM_METRIC_TYPE_DISK_USAGE: + metricTags = map[string]string{ + "diskusage_utilization": "", + } + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) + } + ret := []cloudprovider.MetricValues{} + for metric, tag := range metricTags { + result, err := self.ListMetrics("acs_ecs_dashboard", metric, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("ListMetric(%s) error: %v", metric, err) + continue + } + tags := map[string]string{} + if len(tag) > 0 && len(tagKey) > 0 { + tags[tagKey] = tag + } + for i := range result { + dataTag := result[i].GetTags() + for k, v := range tags { + dataTag[k] = v + } + ret = append(ret, cloudprovider.MetricValues{ + Id: result[i].InstanceId, + MetricType: opts.MetricType, + Values: []cloudprovider.MetricValue{ + { + Timestamp: time.UnixMilli(result[i].Timestamp), + Value: result[i].GetValue(), + Tags: dataTag, + }, + }, + }) + } + } + return ret, nil +} + +func (self *SApsaraClient) GetOssMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricTags, tagKey := map[string]string{}, "" + switch opts.MetricType { + case cloudprovider.BUCKET_METRIC_TYPE_LATECY: + metricTags = map[string]string{ + "GetObjectE2eLatency": cloudprovider.METRIC_TAG_REQUST_GET, + "PostObjectE2eLatency": cloudprovider.METRIC_TAG_REQUST_GET, + } + tagKey = cloudprovider.METRIC_TAG_REQUST + case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_TX: + metricTags = map[string]string{ + "InternetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, + "IntranetSend": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + } + tagKey = cloudprovider.METRIC_TAG_REQUST + case cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_RX: + metricTags = map[string]string{ + "InternetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, + "IntranetRecv": cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + } + tagKey = cloudprovider.METRIC_TAG_NET_TYPE + case cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT: + metricTags = map[string]string{ + "GetObjectCount": cloudprovider.METRIC_TAG_REQUST_GET, + "PostObjectCount": cloudprovider.METRIC_TAG_REQUST_POST, + "ServerErrorCount": cloudprovider.METRIC_TAG_REQUST_5XX, + } + tagKey = cloudprovider.METRIC_TAG_REQUST + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) + } + ret := []cloudprovider.MetricValues{} + for metric, tag := range metricTags { + result, err := self.ListMetrics("acs_oss_dashboard", metric, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("ListMetric(%s) error: %v", metric, err) + continue + } + for i := range result { + ret = append(ret, cloudprovider.MetricValues{ + Id: result[i].BucketName, + MetricType: opts.MetricType, + Values: []cloudprovider.MetricValue{ + { + Timestamp: time.UnixMilli(result[i].Timestamp), + Value: result[i].GetValue(), + Tags: map[string]string{ + tagKey: tag, + }, + }, + }, + }) + } + } + return ret, nil +} + +func (self *SApsaraClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricTags, tagKey := map[string]string{}, "" + switch opts.MetricType { + case cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE: + metricTags = map[string]string{ + "CpuUsage": "", + } + case cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE: + metricTags = map[string]string{ + "MemoryUsage": "", + } + case cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX: + metricTags = map[string]string{ + "IntranetIn": "", + } + case cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX: + metricTags = map[string]string{ + "IntranetOut": "", + } + case cloudprovider.REDIS_METRIC_TYPE_USED_CONN: + metricTags = map[string]string{ + "UsedConnection": "", + } + case cloudprovider.REDIS_METRIC_TYPE_OPT_SES: + metricTags = map[string]string{ + "UsedQPS": "", + } + case cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS: + metricTags = map[string]string{ + "Keys": "", + } + case cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS: + metricTags = map[string]string{ + "ExpiredKeys": "", + } + case cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE: + metricTags = map[string]string{ + "UsedMemory": "", + } + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) + } + ret := []cloudprovider.MetricValues{} + for metric, tag := range metricTags { + result, err := self.ListMetrics("acs_kvstore", metric, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("ListMetric(%s) error: %v", metric, err) + continue + } + tags := map[string]string{} + if len(tag) > 0 && len(tagKey) > 0 { + tags[tagKey] = tag + } + for i := range result { + ret = append(ret, cloudprovider.MetricValues{ + Id: result[i].InstanceId, + MetricType: opts.MetricType, + Values: []cloudprovider.MetricValue{ + { + Timestamp: time.UnixMilli(result[i].Timestamp), + Value: result[i].GetValue(), + Tags: tags, + }, + }, + }) + } + } + return ret, nil +} + +func (self *SApsaraClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metrics := map[string]string{} + switch opts.MetricType { + case cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: + metrics = map[string]string{ + "CpuUsage": "", + } + case cloudprovider.RDS_METRIC_TYPE_MEM_USAGE: + metrics = map[string]string{ + "MemoryUsage": "", + } + case cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: + metrics = map[string]string{ + "MySQL_NetworkInNew": "", + "SQLServer_NetworkInNew": "", + } + case cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: + metrics = map[string]string{ + "MySQL_NetworkOutNew": "", + "SQLServer_NetworkOutNew": "", + } + case cloudprovider.RDS_METRIC_TYPE_DISK_USAGE: + metrics = map[string]string{ + "DiskUsage": "", + } + case cloudprovider.RDS_METRIC_TYPE_CONN_USAGE: + metrics = map[string]string{ + "ConnectionUsage": "", + } + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) + } + ret := []cloudprovider.MetricValues{} + for metric := range metrics { + result, err := self.ListMetrics("acs_rds_dashboard", metric, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("ListMetric(%s) error: %v", metric, err) + continue + } + for i := range result { + ret = append(ret, cloudprovider.MetricValues{ + Id: result[i].InstanceId, + MetricType: opts.MetricType, + Values: []cloudprovider.MetricValue{ + { + Timestamp: time.UnixMilli(result[i].Timestamp), + Value: result[i].GetValue(), + }, + }, + }) + } + } + return ret, nil +} + +func (self *SApsaraClient) GetElbMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricTags, tagKey := map[string]string{}, "" + switch opts.MetricType { + case cloudprovider.LB_METRIC_TYPE_NET_BPS_RX: + metricTags = map[string]string{ + "InstanceTrafficRX": "", + } + case cloudprovider.LB_METRIC_TYPE_NET_BPS_TX: + metricTags = map[string]string{ + "InstanceTrafficTX": "", + } + case cloudprovider.LB_METRIC_TYPE_HRSP_COUNT: + metricTags = map[string]string{ + "InstanceStatusCode2xx": cloudprovider.METRIC_TAG_REQUST_2XX, + "InstanceStatusCode3xx": cloudprovider.METRIC_TAG_REQUST_3XX, + "InstanceStatusCode4xx": cloudprovider.METRIC_TAG_REQUST_4XX, + "InstanceStatusCode5xx": cloudprovider.METRIC_TAG_REQUST_5XX, + } + tagKey = cloudprovider.METRIC_TAG_REQUST + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.MetricType) + } + ret := []cloudprovider.MetricValues{} + for metric, tag := range metricTags { + result, err := self.ListMetrics("acs_slb_dashboard", metric, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("ListMetric(%s) error: %v", metric, err) + continue + } + tags := map[string]string{} + if len(tag) > 0 && len(tagKey) > 0 { + tags[tagKey] = tag + } + for i := range result { + ret = append(ret, cloudprovider.MetricValues{ + Id: result[i].InstanceId, + MetricType: opts.MetricType, + Values: []cloudprovider.MetricValue{ + { + Timestamp: time.UnixMilli(result[i].Timestamp), + Value: result[i].GetValue(), + Tags: tags, + }, + }, + }) + } + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natdtable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natdtable.go new file mode 100644 index 0000000000..270896fda0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natdtable.go @@ -0,0 +1,187 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strconv" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SForwardTableEntry struct { + multicloud.SResourceBase + ApsaraTags + nat *SNatGetway + + ForwardEntryId string + ForwardEntryName string + IpProtocol string + Status string + ExternalIp string + ForwardTableId string + ExternalPort string + InternalPort string + InternalIp string +} + +func (dtable *SForwardTableEntry) GetName() string { + if len(dtable.ForwardEntryName) > 0 { + return dtable.ForwardEntryName + } + return dtable.ForwardEntryId +} + +func (dtable *SForwardTableEntry) GetId() string { + return dtable.ForwardEntryId +} + +func (dtable *SForwardTableEntry) GetGlobalId() string { + return dtable.ForwardEntryId +} + +func (dtable *SForwardTableEntry) GetStatus() string { + switch dtable.Status { + case "Available": + return api.NAT_STAUTS_AVAILABLE + default: + return api.NAT_STATUS_UNKNOWN + } +} + +func (dtable *SForwardTableEntry) GetIpProtocol() string { + return dtable.IpProtocol +} + +func (dtable *SForwardTableEntry) GetExternalIp() string { + return dtable.ExternalIp +} + +func (dtable *SForwardTableEntry) GetExternalPort() int { + port, _ := strconv.Atoi(dtable.ExternalPort) + return port +} + +func (dtable *SForwardTableEntry) GetInternalIp() string { + return dtable.InternalIp +} + +func (dtable *SForwardTableEntry) GetInternalPort() int { + port, _ := strconv.Atoi(dtable.InternalPort) + return port +} + +func (region *SRegion) GetAllDTables(tableId string) ([]SForwardTableEntry, error) { + dtables := []SForwardTableEntry{} + for { + part, total, err := region.GetForwardTableEntries(tableId, len(dtables), 50) + if err != nil { + return nil, err + } + dtables = append(dtables, part...) + if len(dtables) >= total { + break + } + } + return dtables, nil +} + +func (dtable *SForwardTableEntry) Delete() error { + return dtable.nat.vpc.region.DeleteForwardTableEntry(dtable.ForwardTableId, dtable.GetId()) +} + +func (region *SRegion) GetForwardTableEntries(tableId string, offset int, limit int) ([]SForwardTableEntry, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + params["ForwardTableId"] = tableId + + body, err := region.vpcRequest("DescribeForwardTableEntries", params) + if err != nil { + return nil, 0, err + } + + dtables := []SForwardTableEntry{} + err = body.Unmarshal(&dtables, "ForwardTableEntries", "ForwardTableEntry") + if err != nil { + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return dtables, int(total), nil +} + +func (region *SRegion) GetForwardTableEntry(tableID, forwardEntryID string) (SForwardTableEntry, error) { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["ForwardTableId"] = tableID + params["ForwardEntryId"] = forwardEntryID + body, err := region.vpcRequest("DescribeForwardTableEntries", params) + if err != nil { + return SForwardTableEntry{}, err + } + + dtables := []SForwardTableEntry{} + err = body.Unmarshal(&dtables, "ForwardTableEntries", "ForwardTableEntry") + if err != nil { + return SForwardTableEntry{}, err + } + if len(dtables) == 0 { + return SForwardTableEntry{}, cloudprovider.ErrNotFound + } + return dtables[0], nil +} + +func (region *SRegion) DeleteForwardTableEntry(tableId string, entryId string) error { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["ForwardTableId"] = tableId + params["ForwardEntryId"] = entryId + _, err := region.vpcRequest("DeleteForwardEntry", params) + return err +} + +func (region *SRegion) CreateForwardTableEntry(rule cloudprovider.SNatDRule, tableID string) (string, error) { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["ForwardTableId"] = tableID + params["ExternalIp"] = rule.ExternalIP + params["ExternalPort"] = strconv.Itoa(rule.ExternalPort) + params["InternalIp"] = rule.InternalIP + params["InternalPort"] = strconv.Itoa(rule.InternalPort) + params["IpProtocol"] = rule.Protocol + body, err := region.vpcRequest("CreateForwardEntry", params) + if err != nil { + return "", err + } + + entryID, _ := body.GetString("ForwardEntryId") + return entryID, nil +} + +func (dtable *SForwardTableEntry) Refresh() error { + new, err := dtable.nat.vpc.region.GetForwardTableEntry(dtable.ForwardTableId, dtable.ForwardEntryId) + if err != nil { + return err + } + return jsonutils.Update(dtable, new) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natgateway.go new file mode 100644 index 0000000000..03eaf4dacf --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natgateway.go @@ -0,0 +1,227 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SBandwidthPackageIds struct { + BandwidthPackageId []string +} + +type SForwardTableIds struct { + ForwardTableId []string +} + +type SSnatTableIds struct { + SnatTableId []string +} + +type SNatGetway struct { + multicloud.SNatGatewayBase + ApsaraTags + + vpc *SVpc + + BandwidthPackageIds SBandwidthPackageIds + BusinessStatus string + CreationTime time.Time + ExpiredTime time.Time + Description string + ForwardTableIds SForwardTableIds + SnatTableIds SSnatTableIds + InstanceChargeType TChargeType + Name string + NatGatewayId string + RegionId string + Spec string + Status string + VpcId string +} + +func (nat *SNatGetway) GetId() string { + return nat.NatGatewayId +} + +func (nat *SNatGetway) GetGlobalId() string { + return nat.NatGatewayId +} + +func (nat *SNatGetway) GetName() string { + if len(nat.Name) > 0 { + return nat.Name + } + return nat.NatGatewayId +} + +func (self *SNatGetway) GetINetworkId() string { + return "" +} + +func (nat *SNatGetway) GetStatus() string { + switch nat.Status { + case "Initiating": + return api.NAT_STATUS_ALLOCATE + case "Available": + return api.NAT_STAUTS_AVAILABLE + case "Pending": + return api.NAT_STATUS_DEPLOYING + default: + return api.NAT_STATUS_UNKNOWN + } + +} + +func (nat *SNatGetway) GetBillingType() string { + return convertChargeType(nat.InstanceChargeType) +} + +func (nat *SNatGetway) GetNatSpec() string { + return nat.Spec +} + +func (nat *SNatGetway) GetCreatedAt() time.Time { + return nat.CreationTime +} + +func (nat *SNatGetway) GetExpiredAt() time.Time { + return nat.ExpiredTime +} + +func (nat *SNatGetway) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips := []SEipAddress{} + for { + parts, total, err := nat.vpc.region.GetEips("", nat.NatGatewayId, len(eips), 50) + if err != nil { + return nil, err + } + eips = append(eips, parts...) + if len(eips) >= total { + break + } + } + ieips := []cloudprovider.ICloudEIP{} + for i := 0; i < len(eips); i++ { + eips[i].region = nat.vpc.region + ieips = append(ieips, &eips[i]) + } + return ieips, nil +} + +func (nat *SNatGetway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { + itables := []cloudprovider.ICloudNatDEntry{} + for _, dtableId := range nat.ForwardTableIds.ForwardTableId { + dtables, err := nat.vpc.region.GetAllDTables(dtableId) + if err != nil { + return nil, err + } + for i := 0; i < len(dtables); i++ { + dtables[i].nat = nat + itables = append(itables, &dtables[i]) + } + } + return itables, nil +} + +func (nat *SNatGetway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { + stables, err := nat.getSnatEntries() + if err != nil { + return nil, err + } + itables := []cloudprovider.ICloudNatSEntry{} + for i := 0; i < len(stables); i++ { + stables[i].nat = nat + itables = append(itables, &stables[i]) + } + return itables, nil +} + +func (nat *SNatGetway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { + dNATEntry, err := nat.vpc.region.GetForwardTableEntry(nat.ForwardTableIds.ForwardTableId[0], id) + if err != nil { + return nil, cloudprovider.ErrNotFound + } + dNATEntry.nat = nat + return &dNATEntry, nil +} + +func (nat *SNatGetway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { + sNATEntry, err := nat.vpc.region.GetSNATEntry(nat.SnatTableIds.SnatTableId[0], id) + if err != nil { + return nil, cloudprovider.ErrNotFound + } + sNATEntry.nat = nat + return &sNATEntry, nil +} + +func (nat *SNatGetway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { + entryID, err := nat.vpc.region.CreateForwardTableEntry(rule, nat.ForwardTableIds.ForwardTableId[0]) + if err != nil { + return nil, errors.Wrapf(err, `create dnat rule for nat gateway %q`, nat.GetId()) + } + return nat.GetINatDEntryByID(entryID) +} + +func (nat *SNatGetway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { + entryID, err := nat.vpc.region.CreateSNATTableEntry(rule, nat.SnatTableIds.SnatTableId[0]) + if err != nil { + return nil, errors.Wrapf(err, `create snat rule for nat gateway %q`, nat.GetId()) + } + return nat.GetINatSEntryByID(entryID) +} + +func (self *SRegion) GetNatGateways(vpcId string, natGwId string, offset, limit int) ([]SNatGetway, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + if len(vpcId) > 0 { + params["VpcId"] = vpcId + } + if len(natGwId) > 0 { + params["NatGatewayId"] = natGwId + } + + body, err := self.vpcRequest("DescribeNatGateways", params) + if err != nil { + log.Errorf("GetVSwitches fail %s", err) + return nil, 0, err + } + + if self.client.debug { + log.Debugf("%s", body.PrettyString()) + } + + gateways := make([]SNatGetway, 0) + err = body.Unmarshal(&gateways, "NatGateways", "NatGateway") + if err != nil { + log.Errorf("Unmarshal gateways fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return gateways, int(total), nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natstable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natstable.go new file mode 100644 index 0000000000..98baa7d90b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/natstable.go @@ -0,0 +1,221 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSNATTableEntry struct { + multicloud.SResourceBase + ApsaraTags + nat *SNatGetway + + SnatEntryId string + SnatEntryName string + SnatIp string + SnatTableId string `json:"snat_table_id"` + SourceCIDR string `json:"source_cidr"` + SourceVSwitchId string `json:"source_vswitch_id"` + Status string +} + +func (stable *SSNATTableEntry) GetName() string { + if len(stable.SnatEntryName) > 0 { + return stable.SnatEntryName + } + return stable.SnatEntryId +} + +func (stable *SSNATTableEntry) GetId() string { + return stable.SnatEntryId +} + +func (stable *SSNATTableEntry) GetGlobalId() string { + return stable.SnatEntryId +} + +func (stable *SSNATTableEntry) GetStatus() string { + switch stable.Status { + case "Available": + return api.NAT_STAUTS_AVAILABLE + default: + return api.NAT_STATUS_UNKNOWN + } +} + +func (stable *SSNATTableEntry) GetIP() string { + return stable.SnatIp +} + +func (stable *SSNATTableEntry) GetSourceCIDR() string { + return stable.SourceCIDR +} + +func (stable *SSNATTableEntry) GetNetworkId() string { + return stable.SourceVSwitchId +} + +func (stable *SSNATTableEntry) Delete() error { + return stable.nat.vpc.region.DeleteSnatEntry(stable.SnatTableId, stable.GetId()) +} + +func (self *SRegion) GetSNATEntries(tableId string, offset, limit int) ([]SSNATTableEntry, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + params["SnatTableId"] = tableId + + body, err := self.vpcRequest("DescribeSnatTableEntries", params) + if err != nil { + log.Errorf("DescribeSnatTableEntries fail %s", err) + return nil, 0, err + } + + if self.client.debug { + log.Debugf("%s", body.PrettyString()) + } + + entries := make([]SSNATTableEntry, 0) + err = body.Unmarshal(&entries, "SnatTableEntries", "SnatTableEntry") + if err != nil { + log.Errorf("Unmarshal entries fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return entries, int(total), nil +} + +func (self *SRegion) GetSNATEntry(tableID, SNATEntryID string) (SSNATTableEntry, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SnatTableId"] = tableID + params["SnatEntryId"] = SNATEntryID + + body, err := self.vpcRequest("DescribeSnatTableEntries", params) + if err != nil { + log.Errorf("DescribeSnatTableEntries fail %s", err) + return SSNATTableEntry{}, err + } + + if self.client.debug { + log.Debugf("%s", body.PrettyString()) + } + + entries := make([]SSNATTableEntry, 0) + err = body.Unmarshal(&entries, "SnatTableEntries", "SnatTableEntry") + if err != nil { + log.Errorf("Unmarshal entries fail %s", err) + return SSNATTableEntry{}, err + } + if len(entries) == 0 { + return SSNATTableEntry{}, cloudprovider.ErrNotFound + } + return entries[0], nil + +} + +func (region *SRegion) CreateSNATTableEntry(rule cloudprovider.SNatSRule, tableID string) (string, error) { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["SnatTableId"] = tableID + params["SnatIp"] = rule.ExternalIP + if len(rule.NetworkID) != 0 { + params["SourceVSwitchId"] = rule.NetworkID + } + if len(rule.SourceCIDR) != 0 { + params["SourceCIDR"] = rule.SourceCIDR + } + body, err := region.vpcRequest("CreateSnatEntry", params) + if err != nil { + return "", err + } + + entryID, _ := body.GetString("SnatEntryId") + return entryID, nil +} + +func (region *SRegion) DeleteSnatEntry(tableId string, entryId string) error { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["SnatTableId"] = tableId + params["SnatEntryId"] = entryId + _, err := region.vpcRequest("DeleteSnatEntry", params) + return err +} + +func (nat *SNatGetway) getSnatEntriesForTable(tblId string) ([]SSNATTableEntry, error) { + entries := make([]SSNATTableEntry, 0) + entryTotal := -1 + for entryTotal < 0 || len(entries) < entryTotal { + parts, total, err := nat.vpc.region.GetSNATEntries(tblId, len(entries), 50) + if err != nil { + return nil, err + } + if len(parts) > 0 { + entries = append(entries, parts...) + } + entryTotal = total + } + return entries, nil +} + +func (nat *SNatGetway) getSnatEntries() ([]SSNATTableEntry, error) { + entries := make([]SSNATTableEntry, 0) + for i := range nat.SnatTableIds.SnatTableId { + sentries, err := nat.getSnatEntriesForTable(nat.SnatTableIds.SnatTableId[i]) + if err != nil { + return nil, err + } + entries = append(entries, sentries...) + } + return entries, nil +} + +func (nat *SNatGetway) dissociateWithVswitch(vswitchId string) error { + entries, err := nat.getSnatEntries() + if err != nil { + return err + } + for i := range entries { + log.Debugf("%v", entries[i]) + if entries[i].SourceVSwitchId == vswitchId { + err := nat.vpc.region.DeleteSnatEntry(entries[i].SnatTableId, entries[i].SnatEntryId) + if err != nil { + return err + } + } + } + return nil +} + +func (stable *SSNATTableEntry) Refresh() error { + new, err := stable.nat.vpc.region.GetSNATEntry(stable.SnatTableId, stable.SnatEntryId) + if err != nil { + return err + } + return jsonutils.Update(stable, new) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/networkinterfaces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/networkinterfaces.go new file mode 100644 index 0000000000..377837afed --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/networkinterfaces.go @@ -0,0 +1,167 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SPrivateIp struct { + nic *SNetworkInterface + Primary bool + PrivateIpAddress string +} + +func (ip *SPrivateIp) GetGlobalId() string { + return ip.PrivateIpAddress +} + +func (ip *SPrivateIp) GetINetworkId() string { + return ip.nic.VSwitchId +} + +func (ip *SPrivateIp) GetIP() string { + return ip.PrivateIpAddress +} + +func (ip *SPrivateIp) IsPrimary() bool { + return ip.Primary +} + +type SPrivateIpSets struct { + PrivateIpSet []SPrivateIp +} + +type SNetworkInterface struct { + multicloud.SNetworkInterfaceBase + ApsaraTags + region *SRegion + + InstanceId string + CreationTime time.Time + MacAddress string + NetworkInterfaceName string + PrivateIpSets SPrivateIpSets + SecurityGroupIds SSecurityGroupIds + Status string + Type string + VSwitchId string + VpcId string + ZoneId string + NetworkInterfaceId string + PrimaryIpAddress string + PrivateIpAddress string + DepartmentInfo +} + +func (nic *SNetworkInterface) GetName() string { + return nic.NetworkInterfaceName +} + +func (nic *SNetworkInterface) GetId() string { + return nic.NetworkInterfaceId +} + +func (nic *SNetworkInterface) GetGlobalId() string { + return nic.NetworkInterfaceId +} + +func (nic *SNetworkInterface) GetAssociateId() string { + return nic.InstanceId +} + +func (nic *SNetworkInterface) GetAssociateType() string { + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER +} + +func (nic *SNetworkInterface) GetMacAddress() string { + return nic.MacAddress +} + +func (nic *SNetworkInterface) GetStatus() string { + switch nic.Status { + case "Available": + return api.NETWORK_INTERFACE_STATUS_AVAILABLE + } + return nic.Status +} + +func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { + interfaces := []SNetworkInterface{} + for { + parts, total, err := region.GetNetworkInterfaces("", len(interfaces), 50) + if err != nil { + return nil, err + } + interfaces = append(interfaces, parts...) + if len(interfaces) >= total { + break + } + } + ret := []cloudprovider.ICloudNetworkInterface{} + for i := 0; i < len(interfaces); i++ { + // 阿里云实例的弹性网卡已经在guestnetwork同步了 + if len(interfaces[i].InstanceId) == 0 { + interfaces[i].region = region + ret = append(ret, &interfaces[i]) + } + } + return ret, nil +} + +func (nic *SNetworkInterface) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { + address := []cloudprovider.ICloudInterfaceAddress{} + for i := 0; i < len(nic.PrivateIpSets.PrivateIpSet); i++ { + nic.PrivateIpSets.PrivateIpSet[i].nic = nic + address = append(address, &nic.PrivateIpSets.PrivateIpSet[i]) + } + return address, nil +} + +func (region *SRegion) GetNetworkInterfaces(instanceId string, offset int, limit int) ([]SNetworkInterface, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + + params := map[string]string{ + "RegionId": region.RegionId, + "PageSize": fmt.Sprintf("%d", limit), + "PageNumber": fmt.Sprintf("%d", (offset/limit)+1), + } + + if len(instanceId) > 0 { + params["InstanceId"] = instanceId + } + + body, err := region.ecsRequest("DescribeNetworkInterfaces", params) + if err != nil { + return nil, 0, errors.Wrap(err, "DescribeNetworkInterfaces") + } + + interfaces := []SNetworkInterface{} + err = body.Unmarshal(&interfaces, "NetworkInterfaceSets", "NetworkInterfaceSet") + if err != nil { + return nil, 0, errors.Wrap(err, "Unmarshal") + } + total, _ := body.Int("TotalCount") + return interfaces, int(total), nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/objects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/objects.go new file mode 100644 index 0000000000..81d4874d74 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/objects.go @@ -0,0 +1,112 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "net/http" + + "github.com/aliyun/aliyun-oss-go-sdk/oss" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + OSS_META_HEADER = "x-oss-meta-" +) + +type SObject struct { + bucket *SBucket + + cloudprovider.SBaseCloudObject +} + +func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { + return o.bucket +} + +func (o *SObject) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + osscli, err := o.bucket.GetOssClient() + if err != nil { + log.Errorf("o.bucket.region.GetOssClient error %s", err) + return acl + } + bucket, err := osscli.Bucket(o.bucket.Name) + if err != nil { + log.Errorf("osscli.Bucket error %s", err) + return acl + } + result, err := bucket.GetObjectACL(o.Key) + if err != nil { + log.Errorf("bucket.GetObjectACL error %s", err) + return acl + } + if result.ACL == string(oss.ACLDefault) { + return o.bucket.GetAcl() + } + acl = cloudprovider.TBucketACLType(result.ACL) + return acl +} + +func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { + acl, err := str2Acl(string(aclStr)) + if err != nil { + return errors.Wrap(err, "str2Acl") + } + osscli, err := o.bucket.GetOssClient() + if err != nil { + return errors.Wrap(err, "o.bucket.region.GetOssClient") + } + bucket, err := osscli.Bucket(o.bucket.Name) + if err != nil { + return errors.Wrap(err, "osscli.Bucket") + } + err = bucket.SetObjectACL(o.Key, acl) + if err != nil { + return errors.Wrap(err, "bucket.SetObjectACL") + } + return nil +} + +func (o *SObject) GetMeta() http.Header { + if o.Meta != nil { + return o.Meta + } + osscli, err := o.bucket.GetOssClient() + if err != nil { + log.Errorf("o.bucket.GetOssClient error %s", err) + return nil + } + bucket, err := osscli.Bucket(o.bucket.Name) + if err != nil { + log.Errorf("osscli.Bucket error %s", err) + return nil + } + result, err := bucket.GetObjectDetailedMeta(o.Key) + if err != nil { + log.Errorf("bucket.GetObjectACL error %s", err) + return nil + } + o.Meta = cloudprovider.FetchMetaFromHttpHeader(OSS_META_HEADER, result) + return o.Meta +} + +func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { + return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) +} diff --git a/pkg/multicloud/apsara/organization.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/organization.go similarity index 97% rename from pkg/multicloud/apsara/organization.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/organization.go index 6d0065d0c6..b9965334bf 100644 --- a/pkg/multicloud/apsara/organization.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/organization.go @@ -20,9 +20,9 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SResourceGroupList struct { diff --git a/pkg/multicloud/apsara/ots.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ots.go similarity index 94% rename from pkg/multicloud/apsara/ots.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ots.go index e2675c884f..e362ea958b 100644 --- a/pkg/multicloud/apsara/ots.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ots.go @@ -21,9 +21,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) func (self *SRegion) otsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { @@ -37,7 +37,7 @@ func (self *SRegion) otsRequest(apiName string, params map[string]string) (jsonu type STablestore struct { multicloud.SResourceBase - multicloud.ApsaraTags + ApsaraTags region *SRegion InstanceName string diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/project.go new file mode 100644 index 0000000000..c49f44839e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/project.go @@ -0,0 +1,149 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type DepartmentInfo struct { + Department string + DepartmentName string + ResourceGroup string + ResourceGroupName string + ResourceGroupId string +} + +func (self DepartmentInfo) GetProjectId() string { + return self.ResourceGroup +} + +type SResourceGroup struct { + multicloud.SProjectBase + ApsaraTags + client *SApsaraClient + + Creator string + GmtCreated string + Id string + OrganizationId string + OrganizationName string + ResourceGroupName string + RsId string +} + +func (self *SResourceGroup) GetGlobalId() string { + return self.Id +} + +func (self *SResourceGroup) GetId() string { + return self.Id +} + +func (self *SResourceGroup) GetDomainName() string { + return "" +} + +func (self *SResourceGroup) GetDomainId() string { + return "" +} + +func (self *SResourceGroup) GetName() string { + return self.ResourceGroupName +} + +func (self *SResourceGroup) Refresh() error { + return nil +} + +func (self *SResourceGroup) GetStatus() string { + return api.EXTERNAL_PROJECT_STATUS_AVAILABLE +} + +func (self *SApsaraClient) GetResourceGroups(pageNumber int, pageSize int) ([]SResourceGroup, int, error) { + if pageSize <= 0 || pageSize > 100 { + pageSize = 10 + } + if pageNumber <= 0 { + pageNumber = 1 + } + params := map[string]string{ + "PageNumber": fmt.Sprintf("%d", pageNumber), + "PageSize": fmt.Sprintf("%d", pageSize), + } + resp, err := self.ascmRequest("ListResourceGroup", params) + if err != nil { + return nil, 0, errors.Wrap(err, "rmRequest.ListResourceGroup") + } + groups := []SResourceGroup{} + err = resp.Unmarshal(&groups, "data") + if err != nil { + return nil, 0, errors.Wrap(err, "resp.Unmarshal") + } + total, _ := resp.Int("pageInfo", "total") + return groups, int(total), nil +} + +func (self *SApsaraClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + group, err := self.CreateResourceGroup(name) + if err != nil { + return nil, errors.Wrap(err, "CreateProject") + } + return group, nil +} + +func (self *SApsaraClient) CreateResourceGroup(name string) (*SResourceGroup, error) { + params := map[string]string{ + "DisplayName": name, + "Name": name, + } + resp, err := self.ascmRequest("CreateResourceGroup", params) + if err != nil { + return nil, errors.Wrap(err, "CreateResourceGroup") + } + group := &SResourceGroup{client: self} + err = resp.Unmarshal(group, "ResourceGroup") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + err = cloudprovider.WaitStatus(group, api.EXTERNAL_PROJECT_STATUS_AVAILABLE, time.Second*5, time.Minute*3) + if err != nil { + return nil, errors.Wrap(err, "WaitStatus") + } + return group, nil +} + +func (self *SApsaraClient) GetResourceGroup(id string) (*SResourceGroup, error) { + params := map[string]string{ + "ResourceGroupId": id, + } + resp, err := self.ascmRequest("GetResourceGroup", params) + if err != nil { + return nil, err + } + group := &SResourceGroup{client: self} + err = resp.Unmarshal(group, "ResourceGroup") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return group, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/provider/doc.go new file mode 100644 index 0000000000..6e159e1db1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/apsara/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/provider/provider.go new file mode 100644 index 0000000000..12c8f48412 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/provider/provider.go @@ -0,0 +1,246 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/apsara" +) + +type SApsaraProviderFactory struct { + cloudprovider.SPrivateCloudBaseProviderFactory +} + +func (self *SApsaraProviderFactory) GetId() string { + return apsara.CLOUD_PROVIDER_APSARA +} + +func (self *SApsaraProviderFactory) GetName() string { + return apsara.CLOUD_PROVIDER_APSARA_CN +} + +func (self *SApsaraProviderFactory) IsMultiTenant() bool { + return true +} + +func (self *SApsaraProviderFactory) IsNeedForceAutoCreateProject() bool { + return true +} + +func (self *SApsaraProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output.Account = input.AccessKeyId + if input.OrganizationId > 0 { + output.Account = fmt.Sprintf("%s/%d", input.AccessKeyId, input.OrganizationId) + } + output.Secret = input.AccessKeySecret + if len(input.Endpoint) == 0 { + return output, httperrors.NewMissingParameterError("endpoint") + } + output.AccessUrl = input.Endpoint + if len(input.DefaultRegion) == 0 { + return output, httperrors.NewMissingParameterError("default_region") + } + return output, nil +} + +func (self *SApsaraProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + account := input.AccessKeyId + if input.OrganizationId > 0 { + account = fmt.Sprintf("%s/%d", input.AccessKeyId, input.OrganizationId) + } + output = cloudprovider.SCloudaccount{ + Account: account, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func (self *SApsaraProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + client, err := apsara.NewApsaraClient( + apsara.NewApsaraClientConfig( + cfg.Account, + cfg.Secret, + cfg.URL, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SApsaraProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SApsaraProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + region := "" + if info.Options != nil { + region, _ = info.Options.GetString("default_region") + } + return map[string]string{ + "APSARA_ACCESS_KEY": info.Account, + "APSARA_SECRET": info.Secret, + "APSARA_ENDPOINT": info.Url, + "APSARA_REGION": region, + }, nil +} + +func init() { + factory := SApsaraProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SApsaraProvider struct { + cloudprovider.SBaseProvider + client *apsara.SApsaraClient +} + +func (self *SApsaraProvider) WithClient(client *apsara.SApsaraClient) *SApsaraProvider { + self.client = client + return self +} + +func (self *SApsaraProvider) GetSysInfo() (jsonutils.JSONObject, error) { + regions := self.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") + info.Add(jsonutils.NewString(apsara.APSARA_API_VERSION), "api_version") + return info, nil +} + +func (self *SApsaraProvider) GetVersion() string { + return apsara.APSARA_API_VERSION +} + +func (self *SApsaraProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SApsaraProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SApsaraProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SApsaraProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(extId) +} + +func (self *SApsaraProvider) GetBalance() (float64, string, error) { + return 0, api.CLOUD_PROVIDER_HEALTH_NORMAL, nil +} + +func (self *SApsaraProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SApsaraProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return self.client.CreateIProject(name) +} + +func (self *SApsaraProvider) GetStorageClasses(regionId string) []string { + return []string{ + "Standard", "IA", "Archive", + } +} + +func (self *SApsaraProvider) GetBucketCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SApsaraProvider) GetObjectCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SApsaraProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SApsaraProvider) GetIamLoginUrl() string { + return self.client.GetIamLoginUrl() +} + +func (self *SApsaraProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + return self.client.CreateIClouduser(conf) +} + +func (self *SApsaraProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { + return self.client.GetICloudusers() +} + +func (self *SApsaraProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroups() +} + +func (self *SApsaraProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroupByName(name) +} + +func (self *SApsaraProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.client.GetIClouduserByName(name) +} + +func (self *SApsaraProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + return self.client.CreateICloudgroup(name, desc) +} + +func (self *SApsaraProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetISystemCloudpolicies() +} + +func (self *SApsaraProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetICustomCloudpolicies() +} + +func (self *SApsaraProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { + return self.client.CreateICloudpolicy(opts) +} + +func (self *SApsaraProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetMetrics(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/quota.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/quota.go new file mode 100644 index 0000000000..b70fd50d1d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/quota.go @@ -0,0 +1,136 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strconv" + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type ValueItem struct { + Value string + DiskCategory string +} + +type AttributeValues struct { + ValueItem []ValueItem +} + +type SAccountAttributeItem struct { + AttributeValues AttributeValues + AttributeName string +} + +type SQuota struct { + Name string + UsedCount int + MaxCount int +} + +func (q *SQuota) GetGlobalId() string { + return q.Name +} + +func (q *SQuota) GetDesc() string { + return q.Name +} + +func (q *SQuota) GetQuotaType() string { + return q.Name +} + +func (q *SQuota) GetMaxQuotaCount() int { + return q.MaxCount +} + +func (q *SQuota) GetCurrentQuotaUsedCount() int { + return q.UsedCount +} + +func (region *SRegion) GetAccountAttributes() ([]SAccountAttributeItem, error) { + params := map[string]string{ + "RegionId": region.RegionId, + } + resp, err := region.ecsRequest("DescribeAccountAttributes", params) + if err != nil { + return nil, errors.Wrap(err, "ecsRequest") + } + quotas := []SAccountAttributeItem{} + err = resp.Unmarshal("as, "AccountAttributeItems", "AccountAttributeItem") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return quotas, nil +} + +func (region *SRegion) GetQuotas() ([]SQuota, error) { + attrs, err := region.GetAccountAttributes() + if err != nil { + return nil, errors.Wrap(err, "GetAccountAttributes") + } + quotas := map[string]SQuota{} + for _, attr := range attrs { + for _, item := range attr.AttributeValues.ValueItem { + value, err := strconv.ParseInt(item.Value, 10, 64) + if err != nil { + continue + } + used := false + name := attr.AttributeName + if strings.HasPrefix(name, "used-") { + used = true + name = strings.TrimPrefix(name, "used-") + } + if len(item.DiskCategory) > 0 { + name = fmt.Sprintf("%s/%s", name, item.DiskCategory) + } + if _, ok := quotas[name]; !ok { + quotas[name] = SQuota{ + Name: name, + UsedCount: -1, + } + } + quota := quotas[name] + if used { + quota.UsedCount = int(value) + } else { + quota.MaxCount = int(value) + } + quotas[name] = quota + } + } + ret := []SQuota{} + for _, quota := range quotas { + ret = append(ret, quota) + } + return ret, nil +} + +func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { + quotas, err := region.GetQuotas() + if err != nil { + return nil, errors.Wrap(err, "GetQuotas") + } + ret := []cloudprovider.ICloudQuota{} + for i := range quotas { + ret = append(ret, "as[i]) + } + return ret, nil +} diff --git a/pkg/multicloud/apsara/ram.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram.go similarity index 100% rename from pkg/multicloud/apsara/ram.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_group.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_group.go new file mode 100644 index 0000000000..435f159212 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_group.go @@ -0,0 +1,325 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SGroup struct { + client *SApsaraClient + + Comments string + CreatedDate time.Time + GroupName string + UpdateDate time.Time +} + +type sGroups struct { + Group []SGroup +} + +type SGroups struct { + Groups sGroups + Marker string + IsTruncated bool +} + +func (self *SGroup) GetName() string { + return self.GroupName +} + +func (self *SGroup) GetGlobalId() string { + return self.GroupName +} + +func (self *SGroup) GetDescription() string { + return self.Comments +} + +func (self *SGroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { + ret := []cloudprovider.IClouduser{} + offset := "" + for { + part, err := self.client.ListUsersForGroup(self.GroupName, offset, 1000) + if err != nil { + return nil, errors.Wrapf(err, "ListUsersForGroup") + } + for i := range part.Users.User { + part.Users.User[i].client = self.client + ret = append(ret, &part.Users.User[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SGroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := self.client.ListPoliciesForGroup(self.GroupName) + if err != nil { + return nil, errors.Wrapf(err, "ListPoliciesForGroup") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].PolicyType == POLICY_TYPE_SYSTEM { + policies[i].client = self.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (self *SGroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := self.client.ListPoliciesForGroup(self.GroupName) + if err != nil { + return nil, errors.Wrapf(err, "ListPoliciesForGroup") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].PolicyType == POLICY_TYPE_CUSTOM { + policies[i].client = self.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (self *SGroup) AddUser(name string) error { + return self.client.AddUserToGroup(self.GroupName, name) +} + +func (self *SGroup) RemoveUser(name string) error { + return self.client.RemoveUserFromGroup(self.GroupName, name) +} + +func (self *SGroup) AttachSystemPolicy(policyName string) error { + return self.client.AttachPolicyToGroup(POLICY_TYPE_SYSTEM, policyName, self.GroupName) +} + +func (self *SGroup) AttachCustomPolicy(policyName string) error { + return self.client.AttachPolicyToGroup(POLICY_TYPE_CUSTOM, policyName, self.GroupName) +} + +func (self *SGroup) DetachSystemPolicy(policyName string) error { + return self.client.DetachPolicyFromGroup(POLICY_TYPE_SYSTEM, policyName, self.GroupName) +} + +func (self *SGroup) DetachCustomPolicy(policyName string) error { + return self.client.DetachPolicyFromGroup(POLICY_TYPE_CUSTOM, policyName, self.GroupName) +} + +func (self *SGroup) Delete() error { + return self.client.DeleteGroup(self.GroupName) +} + +func (self *SApsaraClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + group, err := self.GetGroup(name) + if err != nil { + return nil, errors.Wrapf(err, "GetGroup(%s)", name) + } + return group, nil +} + +func (self *SApsaraClient) CreateICloudgroup(name string, desc string) (cloudprovider.ICloudgroup, error) { + group, err := self.CreateGroup(name, desc) + if err != nil { + return nil, errors.Wrapf(err, "CreateGroup") + } + return group, nil +} + +func (self *SApsaraClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + ret := []cloudprovider.ICloudgroup{} + offset := "" + for { + part, err := self.ListGroups(offset, 100) + if err != nil { + return nil, errors.Wrap(err, "ListGroups") + } + for i := range part.Groups.Group { + part.Groups.Group[i].client = self + ret = append(ret, &part.Groups.Group[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SApsaraClient) ListGroups(offset string, limit int) (*SGroups, error) { + if limit < 1 || limit > 1000 { + limit = 1000 + } + params := map[string]string{ + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(offset) > 0 { + params["Marker"] = offset + } + groups := SGroups{} + resp, err := self.ramRequest("ListGroups", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.ListGroups") + } + err = resp.Unmarshal(&groups) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return &groups, nil +} + +// https://help.apsara.com/document_detail/28732.html?spm=a2c4g.11186623.6.777.580735b2m2xUh8 +func (self *SApsaraClient) ListPoliciesForGroup(groupName string) ([]SPolicy, error) { + params := map[string]string{ + "GroupName": groupName, + } + resp, err := self.ramRequest("ListPoliciesForGroup", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.ListPoliciesForGroup") + } + policies := []SPolicy{} + err = resp.Unmarshal(&policies, "Policies", "Policy") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return policies, nil +} + +func (self *SApsaraClient) ListUsersForGroup(groupName string, offset string, limit int) (*SUsers, error) { + if limit < 1 || limit > 1000 { + limit = 1000 + } + params := map[string]string{ + "GroupName": groupName, + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(offset) > 0 { + params["Marker"] = offset + } + resp, err := self.ramRequest("ListUsersForGroup", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.ListUserForGroup") + } + users := &SUsers{} + err = resp.Unmarshal(users) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return users, nil +} + +func (self *SApsaraClient) DeleteGroup(groupName string) error { + params := map[string]string{ + "GroupName": groupName, + } + _, err := self.ramRequest("DeleteGroup", params) + return err +} + +func (self *SApsaraClient) CreateGroup(groupName, comments string) (*SGroup, error) { + params := map[string]string{ + "GroupName": groupName, + } + if len(comments) > 0 { + params["Comments"] = comments + } + resp, err := self.ramRequest("CreateGroup", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.CreateGroup") + } + group := &SGroup{client: self} + err = resp.Unmarshal(group, "Group") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return group, nil +} + +func (self *SApsaraClient) GetGroup(groupName string) (*SGroup, error) { + params := map[string]string{ + "GroupName": groupName, + } + resp, err := self.ramRequest("GetGroup", params) + if err != nil { + return nil, errors.Wrap(err, "GetGroup") + } + group := &SGroup{client: self} + err = resp.Unmarshal(group, "Group") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return group, nil +} + +func (self *SApsaraClient) RemoveUserFromGroup(groupName, userName string) error { + params := map[string]string{ + "GroupName": groupName, + "UserName": userName, + } + _, err := self.ramRequest("RemoveUserFromGroup", params) + if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { + return errors.Wrap(err, "RemoveUserFromGroup") + } + return nil +} + +func (self *SApsaraClient) DetachPolicyFromGroup(policyType, policyName, groupName string) error { + params := map[string]string{ + "GroupName": groupName, + "PolicyName": policyName, + "PolicyType": policyType, + } + _, err := self.ramRequest("DetachPolicyFromGroup", params) + if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { + return errors.Wrap(err, "DetachPolicyFromGroup") + } + return nil +} + +func (self *SApsaraClient) AddUserToGroup(groupName, userName string) error { + params := map[string]string{ + "GroupName": groupName, + "UserName": userName, + } + _, err := self.ramRequest("AddUserToGroup", params) + if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.User.Group") { + return errors.Wrap(err, "AddUserToGroup") + } + return nil +} + +func (self *SApsaraClient) AttachPolicyToGroup(policyType, policyName, groupName string) error { + params := map[string]string{ + "GroupName": groupName, + "PolicyName": policyName, + "PolicyType": policyType, + } + _, err := self.ramRequest("AttachPolicyToGroup", params) + if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.Group.Policy") { + return errors.Wrap(err, "AttachPolicyToGroup") + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_policy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_policy.go new file mode 100644 index 0000000000..558565a659 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_policy.go @@ -0,0 +1,316 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + POLICY_TYPE_SYSTEM = "System" + POLICY_TYPE_CUSTOM = "Custom" +) + +/** + {"AttachmentCount":0, +"CreateDate":"2018-10-12T05:05:16Z", +"DefaultVersion":"v1", +"Description":"只读访问Data Lake Analytics的权限", +"PolicyName":"ApsaraDLAReadOnlyAccess", +"PolicyType":"System", +"UpdateDate":"2018-10-12T05:05:16Z"} +*/ + +type SDefaultPolicyVersion struct { + CreateDate time.Time + IsDefaultVersion bool + PolicyDocument string + VersionId string +} + +type SPolicyDetails struct { + Policy SPolicy + DefaultPolicyVersion SDefaultPolicyVersion +} + +type sPolicies struct { + Policy []SPolicy +} + +type SPolicies struct { + Policies sPolicies + Marker string + IsTruncated bool +} + +type SPolicy struct { + client *SApsaraClient + AttachmentCount int + CreateDate time.Time + UpdateDate time.Time + DefaultVersion string + Description string + PolicyName string + PolicyType string +} + +func (policy *SPolicy) GetName() string { + return policy.PolicyName +} + +func (policy *SPolicy) GetDescription() string { + return policy.Description +} + +func (policy *SPolicy) GetGlobalId() string { + return policy.PolicyName +} + +func (policy *SPolicy) UpdateDocument(document *jsonutils.JSONDict) error { + return policy.client.CreatePolicyVersion(policy.PolicyName, document.String(), true) +} + +func (policy *SPolicy) Delete() error { + return policy.client.DeletePolicy(policy.PolicyType, policy.PolicyName) +} + +func (policy *SPolicy) GetDocument() (*jsonutils.JSONDict, error) { + details, err := policy.client.GetPolicy(policy.PolicyType, policy.PolicyName) + if err != nil { + return nil, errors.Wrapf(err, "GetPolicy(%s,%s)", policy.PolicyType, policy.PolicyName) + } + obj, err := jsonutils.Parse([]byte(details.DefaultPolicyVersion.PolicyDocument)) + if err != nil { + return nil, errors.Wrap(err, "jsonutils.Parse") + } + return obj.(*jsonutils.JSONDict), nil +} + +func (self *SApsaraClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + ret := []cloudprovider.ICloudpolicy{} + offset := "" + for { + part, err := self.ListPolicies(POLICY_TYPE_SYSTEM, offset, 1000) + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + for i := range part.Policies.Policy { + part.Policies.Policy[i].client = self + ret = append(ret, &part.Policies.Policy[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SApsaraClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + ret := []cloudprovider.ICloudpolicy{} + offset := "" + for { + part, err := self.ListPolicies(POLICY_TYPE_CUSTOM, offset, 1000) + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + for i := range part.Policies.Policy { + part.Policies.Policy[i].client = self + ret = append(ret, &part.Policies.Policy[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SApsaraClient) AttachPolicyToUser(policyName, policyType, userName string) error { + params := map[string]string{ + "UserName": userName, + "PolicyName": policyName, + "PolicyType": policyType, + } + _, err := self.ramRequest("AttachPolicyToUser", params) + if err != nil && !strings.Contains(err.Error(), "EntityAlreadyExists.User.Policy") { + return errors.Wrap(err, "AttachPolicyToUser") + } + return nil +} + +func (self *SApsaraClient) DetachPolicyFromUser(policyName, policyType, userName string) error { + if len(policyType) == 0 { + policyType = "System" + } + params := map[string]string{ + "UserName": userName, + "PolicyName": policyName, + "PolicyType": policyType, + } + _, err := self.ramRequest("DetachPolicyFromUser", params) + if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { + return errors.Wrap(err, "DetachPolicyFromUser") + } + return nil +} + +// https://help.apsara.com/document_detail/28719.html?spm=a2c4g.11174283.6.764.27055662H6TGg5 +func (self *SApsaraClient) ListPolicies(policyType string, offset string, limit int) (*SPolicies, error) { + if limit < 1 || limit > 1000 { + limit = 1000 + } + params := map[string]string{ + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(policyType) > 0 { + params["PolicyType"] = policyType + } + if len(offset) > 0 { + params["Marker"] = offset + } + + body, err := self.ramRequest("ListPolicies", params) + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + policies := &SPolicies{} + + err = body.Unmarshal(&policies) + if err != nil { + return nil, errors.Wrapf(err, "body.Unmarshal") + } + + return policies, nil +} + +func (self *SApsaraClient) GetPolicy(policyType string, policyName string) (*SPolicyDetails, error) { + params := make(map[string]string) + params["PolicyType"] = policyType + params["PolicyName"] = policyName + + body, err := self.ramRequest("GetPolicy", params) + if err != nil { + if isError(err, "EntityNotExist.Role") { + return nil, cloudprovider.ErrNotFound + } + return nil, err + } + + policy := SPolicyDetails{} + + err = body.Unmarshal(&policy) + if err != nil { + return nil, err + } + + return &policy, nil +} + +type SStatement struct { + Action []string `json:"Action,allowempty"` + Effect string `json:"Effect"` + Resource []string `json:"Resource"` +} + +type SPolicyDocument struct { + Statement []SStatement `json:"Statement,allowempty"` + Version string `json:"Version"` +} + +func (self *SApsaraClient) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { + if opts.Document == nil { + return nil, errors.Error("nil document") + } + policy, err := self.CreatePolicy(opts.Name, opts.Document.String(), opts.Desc) + if err != nil { + return nil, errors.Wrapf(err, "CreatePolicy") + } + return policy, nil +} + +func (self *SApsaraClient) CreatePolicy(name string, document string, desc string) (*SPolicy, error) { + params := make(map[string]string) + params["PolicyName"] = name + params["PolicyDocument"] = document + if len(desc) > 0 { + params["Description"] = desc + } + + body, err := self.ramRequest("CreatePolicy", params) + if err != nil { + return nil, err + } + + policy := SPolicy{client: self} + + err = body.Unmarshal(&policy, "Policy") + if err != nil { + return nil, err + } + + return &policy, nil +} + +func (self *SApsaraClient) DeletePolicy(policyType string, policyName string) error { + params := make(map[string]string) + params["PolicyName"] = policyName + params["PolicyType"] = policyType + + _, err := self.ramRequest("DeletePolicy", params) + return err +} + +func (self *SApsaraClient) DeleteRole(roleName string) error { + params := make(map[string]string) + params["RoleName"] = roleName + + _, err := self.ramRequest("DeleteRole", params) + return err +} + +func (self *SApsaraClient) AttachPolicy2Role(policyType string, policyName string, roleName string) error { + params := make(map[string]string) + params["PolicyType"] = policyType + params["PolicyName"] = policyName + params["RoleName"] = roleName + + _, err := self.ramRequest("AttachPolicyToRole", params) + if err != nil { + return errors.Wrap(err, "AttachPolicyToRole") + } + + return nil +} + +func (self *SApsaraClient) CreatePolicyVersion(name, document string, isDefault bool) error { + params := map[string]string{ + "PolicyName": name, + "PolicyDocument": document, + "RotateStrategy": "DeleteOldestNonDefaultVersionWhenLimitExceeded", + } + if isDefault { + params["SetAsDefault"] = "true" + } + _, err := self.ramRequest("CreatePolicyVersion", params) + return err +} diff --git a/pkg/multicloud/apsara/ram_role.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_role.go similarity index 100% rename from pkg/multicloud/apsara/ram_role.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_role.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_user.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_user.go new file mode 100644 index 0000000000..aa3ee46c46 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ram_user.go @@ -0,0 +1,406 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type sUsers struct { + User []SUser +} + +type SUsers struct { + Users sUsers + Marker string + IsTruncated bool +} + +type SUser struct { + client *SApsaraClient + multicloud.SBaseClouduser + + Comments string + CreateDate time.Time + DisplayName string + Email string + MobilePhone string + UserId string + UserName string +} + +func (user *SUser) GetEmailAddr() string { + return "" +} + +func (user *SUser) GetInviteUrl() string { + return "" +} + +func (user *SUser) GetGlobalId() string { + if len(user.UserId) > 0 { + return user.UserId + } + u, err := user.client.GetUser(user.UserName) + if err != nil { + return "" + } + return u.UserId +} + +func (user *SUser) GetName() string { + return user.UserName +} + +func (user *SUser) Delete() error { + groups, err := user.client.ListGroupsForUser(user.UserName) + if err != nil { + return errors.Wrap(err, "ListGroupsForUser") + } + for i := range groups { + err = user.client.RemoveUserFromGroup(groups[i].GroupName, user.UserName) + if err != nil { + return errors.Wrapf(err, "RemoveUserFromGroup %s > %s", groups[i].GroupName, user.UserName) + } + } + policies, err := user.client.ListPoliciesForUser(user.UserName) + if err != nil { + return errors.Wrap(err, "ListPoliciesForUser") + } + for i := range policies { + err = user.client.DetachPolicyFromUser(policies[i].PolicyName, policies[i].PolicyType, user.UserName) + if err != nil { + return errors.Wrapf(err, "DetachPolicyFromUser %s %s %s", policies[i].PolicyName, policies[i].PolicyType, user.UserName) + } + } + return user.client.DeleteClouduser(user.UserName) +} + +func (user *SUser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + groups, err := user.client.ListGroupsForUser(user.UserName) + if err != nil { + return nil, errors.Wrapf(err, "ListGroupsForUser") + } + ret := []cloudprovider.ICloudgroup{} + for i := range groups { + groups[i].client = user.client + ret = append(ret, &groups[i]) + } + return ret, nil +} + +func (user *SUser) UpdatePassword(password string) error { + return user.client.UpdateLoginProfile(user.UserName, password) +} + +func (user *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := user.client.ListPoliciesForUser(user.UserName) + if err != nil { + return nil, errors.Wrap(err, "ListPoliciesForUser") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].PolicyType == "System" { + policies[i].client = user.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (user *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := user.client.ListPoliciesForUser(user.UserName) + if err != nil { + return nil, errors.Wrap(err, "ListPoliciesForUser") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].PolicyType == "Custom" { + policies[i].client = user.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (user *SUser) IsConsoleLogin() bool { + _, err := user.client.GetLoginProfile(user.UserName) + if errors.Cause(err) == cloudprovider.ErrNotFound { + return false + } + return true +} + +func (user *SUser) ResetPassword(password string) error { + return user.client.ResetClouduserPassword(user.UserName, password) +} + +func (user *SUser) AttachSystemPolicy(policyName string) error { + return user.client.AttachPolicyToUser(policyName, POLICY_TYPE_SYSTEM, user.UserName) +} + +func (user *SUser) AttachCustomPolicy(policyName string) error { + return user.client.AttachPolicyToUser(policyName, POLICY_TYPE_CUSTOM, user.UserName) +} + +func (user *SUser) DetachSystemPolicy(policyName string) error { + return user.client.DetachPolicyFromUser(policyName, POLICY_TYPE_SYSTEM, user.UserName) +} + +func (user *SUser) DetachCustomPolicy(policyName string) error { + return user.client.DetachPolicyFromUser(policyName, POLICY_TYPE_CUSTOM, user.UserName) +} + +func (self *SApsaraClient) DeleteClouduser(name string) error { + params := map[string]string{ + "UserName": name, + } + _, err := self.ramRequest("DeleteUser", params) + return err +} + +func (self *SApsaraClient) CreateUser(name, phone, email, comments string) (*SUser, error) { + params := map[string]string{ + "UserName": name, + "DisplayName": name, + } + if len(phone) > 0 { + params["MobilePhone"] = phone + } + if len(email) > 0 { + params["Email"] = email + } + if len(comments) > 0 { + params["Comments"] = comments + } + resp, err := self.ramRequest("CreateUser", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.CreateUser") + } + + user := &SUser{client: self} + err = resp.Unmarshal(user, "User") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return user, nil +} + +func (self *SApsaraClient) ListUsers(offset string, limit int) (*SUsers, error) { + params := map[string]string{} + if len(offset) > 0 { + params["Marker"] = offset + } + if limit > 0 { + params["MaxItems"] = fmt.Sprintf("%d", limit) + } + resp, err := self.ramRequest("ListUsers", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.ListUsers") + } + users := &SUsers{} + err = resp.Unmarshal(users) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return users, nil +} + +func (self *SApsaraClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + user, err := self.CreateUser(conf.Name, conf.MobilePhone, conf.Email, conf.Desc) + if err != nil { + return nil, errors.Wrap(err, "CreateUser") + } + if len(conf.Password) > 0 { + _, err := self.CreateLoginProfile(conf.Name, conf.Password) + if err != nil { + return nil, errors.Wrap(err, "CreateLoginProfile") + } + } + for _, policyId := range conf.ExternalPolicyIds { + err := user.AttachSystemPolicy(policyId) + if err != nil { + log.Errorf("attach policy %s for user %s error: %v", policyId, conf.Name, err) + } + } + return user, nil +} + +func (self *SApsaraClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { + ret := []cloudprovider.IClouduser{} + offset := "" + for { + part, err := self.ListUsers(offset, 100) + if err != nil { + return nil, errors.Wrap(err, "GetCloudusers") + } + for i := range part.Users.User { + part.Users.User[i].client = self + ret = append(ret, &part.Users.User[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SApsaraClient) GetUser(name string) (*SUser, error) { + params := map[string]string{ + "UserName": name, + } + resp, err := self.ramRequest("GetUser", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.CreateUser") + } + user := &SUser{client: self} + err = resp.Unmarshal(user, "User") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return user, nil +} + +func (self *SApsaraClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.GetUser(name) +} + +type SLoginProfile struct { + CreateDate string + MFABindRequired bool + PasswordResetRequired bool + UserName string +} + +func (self *SApsaraClient) GetLoginProfile(name string) (*SLoginProfile, error) { + params := map[string]string{ + "UserName": name, + } + resp, err := self.ramRequest("GetLoginProfile", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.GetLoginProfile") + } + profile := &SLoginProfile{} + err = resp.Unmarshal(profile, "LoginProfile") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return profile, nil +} + +func (self *SApsaraClient) DeleteLoginProfile(name string) error { + params := map[string]string{ + "UserName": name, + } + _, err := self.ramRequest("DeleteLoginProfile", params) + return err +} + +func (self *SApsaraClient) CreateLoginProfile(name, password string) (*SLoginProfile, error) { + params := map[string]string{ + "UserName": name, + "Password": password, + } + resp, err := self.ramRequest("CreateLoginProfile", params) + if err != nil { + return nil, errors.Wrap(err, "ramRequest.CreateLoginProfile") + } + profile := &SLoginProfile{} + err = resp.Unmarshal(profile, "LoginProfile") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return profile, nil +} + +func (self *SApsaraClient) UpdateLoginProfile(name, password string) error { + params := map[string]string{ + "UserName": name, + "Password": password, + } + _, err := self.ramRequest("UpdateLoginProfile", params) + if err != nil { + return errors.Wrap(err, "ramRequest.CreateLoginProfile") + } + return nil +} + +func (self *SApsaraClient) ResetClouduserPassword(name, password string) error { + _, err := self.GetLoginProfile(name) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + _, err = self.CreateLoginProfile(name, password) + return err + } + return errors.Wrap(err, "GetLoginProfile") + } + return self.UpdateLoginProfile(name, password) +} + +func (self *SApsaraClient) GetIamLoginUrl() string { + params := map[string]string{} + resp, err := self.ramRequest("GetAccountAlias", params) + if err != nil { + log.Errorf("GetAccountAlias error: %v", err) + return "" + } + alias, _ := resp.GetString("AccountAlias") + if len(alias) > 0 { + return fmt.Sprintf("https://signin.apsara.com/%s.onapsara.com/login.htm", alias) + } + return "" +} + +// https://help.apsara.com/document_detail/28707.html?spm=a2c4g.11186623.6.752.f4466bbfVy5j0s +func (self *SApsaraClient) ListGroupsForUser(user string) ([]SGroup, error) { + params := map[string]string{ + "UserName": user, + } + resp, err := self.ramRequest("ListGroupsForUser", params) + if err != nil { + return nil, errors.Wrap(err, "ListGroupsForUser") + } + groups := []SGroup{} + err = resp.Unmarshal(&groups, "Groups", "Group") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return groups, nil +} + +// https://help.apsara.com/document_detail/28732.html?spm=a2c4g.11186623.6.777.580735b2m2xUh8 +func (self *SApsaraClient) ListPoliciesForUser(user string) ([]SPolicy, error) { + params := map[string]string{ + "UserName": user, + } + resp, err := self.ramRequest("ListPoliciesForUser", params) + if err != nil { + return nil, errors.Wrap(err, "ListPoliciesForUser") + } + policies := []SPolicy{} + err = resp.Unmarshal(&policies, "Policies", "Policy") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return policies, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ramimage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ramimage.go new file mode 100644 index 0000000000..12be7e97b5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/ramimage.go @@ -0,0 +1,201 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + ApsaraECSImageImportRole = "ApsaraECSImageImportDefaultRole" + ApsaraECSImageImportRoleDocument = `{ +"Statement": [ +{ +"Action": "sts:AssumeRole", +"Effect": "Allow", +"Principal": { + "Service": [ + "ecs.apsaracs.com" + ] +} +} +], +"Version": "1" +}` + + ApsaraECSImageImportRolePolicyType = "System" + ApsaraECSImageImportRolePolicy = "ApsaraECSImageImportRolePolicy" + ApsaraECSImageImportRolePolicyDocument = `{ +"Version": "1", +"Statement": [ +{ +"Action": [ + "oss:GetObject", + "oss:GetBucketLocation" +], +"Resource": "*", +"Effect": "Allow" +} +] +}` +) + +func (self *SApsaraClient) EnableImageImport() error { + _, err := self.GetRole(ApsaraECSImageImportRole) + if err != nil { + if err != cloudprovider.ErrNotFound { + return err + } + _, err = self.CreateRole(ApsaraECSImageImportRole, + ApsaraECSImageImportRoleDocument, + "Allow Import External Image from OSS") + if err != nil { + return err + } + } + + _, err = self.GetPolicy(ApsaraECSImageImportRolePolicyType, ApsaraECSImageImportRolePolicy) + if err != nil { + /*if err != cloudprovider.ErrNotFound { + return err + } + _, err = self.createPolicy(ApsaraECSImageImportRolePolicy, + ApsaraECSImageImportRolePolicyDocument, + "Allow Import External Image policy") + if err != nil { + return err + }*/ + return err + } + + policies, err := self.ListPoliciesForRole(ApsaraECSImageImportRole) + if err != nil { + return err + } + for i := 0; i < len(policies); i += 1 { + if policies[i].PolicyType == ApsaraECSImageImportRolePolicyType && + policies[i].PolicyName == ApsaraECSImageImportRolePolicy { + return nil // find policy + } + } + + err = self.AttachPolicy2Role(ApsaraECSImageImportRolePolicyType, ApsaraECSImageImportRolePolicy, ApsaraECSImageImportRole) + if err != nil { + return err + } + + return nil +} + +const ( + ApsaraECSImageExportRole = "ApsaraECSImageExportDefaultRole" + ApsaraECSImageExportRoleDocument = `{ + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": [ + "ecs.apsaracs.com" + ] + } + } + ], + "Version": "1" +}` + + ApsaraEmptyRoleDocument = `{ + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": [ + "ecs.apsaracs.com" + ] + } + } + ], + "Version": "1" +}` + + ApsaraECSImageExportRolePolicyType = "System" + ApsaraECSImageExportRolePolicy = "ApsaraECSImageExportRolePolicy" + ApsaraECSImageExportRolePolicyDocument = `{ + "Version": "1", + "Statement": [ + { + "Action": [ + "oss:GetObject", + "oss:PutObject", + "oss:DeleteObject", + "oss:GetBucketLocation", + "oss:AbortMultipartUpload", + "oss:ListMultipartUploads", + "oss:ListParts" + ], + "Resource": "*", + "Effect": "Allow" + } + ] + }` +) + +func (self *SApsaraClient) EnableImageExport() error { + _, err := self.GetRole(ApsaraECSImageExportRole) + if err != nil { + if err != cloudprovider.ErrNotFound { + return err + } + _, err = self.CreateRole(ApsaraECSImageExportRole, + ApsaraECSImageExportRoleDocument, + "Allow Export Import to OSS") + if err != nil { + return err + } + } + + _, err = self.GetPolicy(ApsaraECSImageExportRolePolicyType, ApsaraECSImageExportRolePolicy) + if err != nil { + /*if err != cloudprovider.ErrNotFound { + return err + } + _, err = self.createPolicy(ApsaraECSImageImportRolePolicy, + ApsaraECSImageImportRolePolicyDocument, + "Allow Import External Image policy") + if err != nil { + return err + }*/ + return err + } + + policies, err := self.ListPoliciesForRole(ApsaraECSImageExportRole) + if err != nil { + return err + } + for i := 0; i < len(policies); i += 1 { + if policies[i].PolicyType == ApsaraECSImageExportRolePolicyType && + policies[i].PolicyName == ApsaraECSImageExportRolePolicy { + return nil // find policy + } + } + + err = self.AttachPolicy2Role(ApsaraECSImageExportRolePolicyType, ApsaraECSImageExportRolePolicy, ApsaraECSImageExportRole) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/region.go new file mode 100644 index 0000000000..8b18bf1d93 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/region.go @@ -0,0 +1,1100 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strings" + "time" + + "github.com/aliyun/alibaba-cloud-sdk-go/sdk" + "github.com/aliyun/aliyun-oss-go-sdk/oss" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/regutils" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + multicloud.SRegion + + client *SApsaraClient + sdkClient *sdk.Client + + RegionId string + LocalName string + + izones []cloudprovider.ICloudZone + + ivpcs []cloudprovider.ICloudVpc + + lbEndpints map[string]string + + storageCache *SStoragecache + + instanceTypes []SInstanceType + + latitude float64 + longitude float64 + fetchLocation bool + + ossEndpoint string +} + +func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetClient() *SApsaraClient { + return self.client +} + +func (self *SRegion) getSdkClient() (*sdk.Client, error) { + if self.sdkClient == nil { + var err error + self.sdkClient, err = self.GetClient().getDefaultClient(self.RegionId) + if err != nil { + return nil, err + } + } + return self.sdkClient, nil +} + +func (self *SRegion) GetOssClient() (*oss.Client, error) { + if len(self.ossEndpoint) == 0 { + _, err := self.GetBuckets() + if err != nil { + return nil, err + } + if len(self.ossEndpoint) == 0 { + return nil, fmt.Errorf("no available buckets") + } + } + return self.client.getOssClient(self.ossEndpoint) +} + +func (self *SRegion) productRequest(client *sdk.Client, product, domain, apiVersion, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { + params["Product"] = product + return jsonRequest(client, domain, apiVersion, apiName, params, debug) +} + +func (self *SRegion) ossRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["RegionId"] = self.RegionId + return self.client.ossRequest(apiName, params) +} + +func (self *SRegion) ecsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + domain := self.client.getDomain(APSARA_PRODUCT_ECS) + params["Product"] = APSARA_PRODUCT_ECS + return jsonRequest(client, domain, APSARA_API_VERSION, apiName, params, self.client.debug) +} + +func (self *SRegion) rdsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + domain := self.client.getDomain(APSARA_PRODUCT_RDS) + return self.productRequest(client, APSARA_PRODUCT_RDS, domain, APSARA_API_VERION_RDS, apiName, params, self.client.debug) +} + +func (self *SRegion) vpcRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + domain := self.client.getDomain(APSARA_PRODUCT_VPC) + return self.productRequest(client, APSARA_PRODUCT_VPC, domain, APSARA_API_VERSION_VPC, action, params, self.client.debug) +} + +func (self *SRegion) kvsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + domain := self.client.getDomain(APSARA_PRODUCT_KVSTORE) + return self.productRequest(client, APSARA_PRODUCT_KVSTORE, domain, APSARA_API_VERSION_KVS, action, params, self.client.debug) +} + +func (self *SRegion) tagRequest(serviceType string, action string, params map[string]string) (jsonutils.JSONObject, error) { + switch serviceType { + case APSARA_PRODUCT_ECS: + return self.ecsRequest(action, params) + case APSARA_PRODUCT_RDS: + return self.rdsRequest(action, params) + case APSARA_PRODUCT_SLB: + return self.lbRequest(action, params) + case APSARA_PRODUCT_KVSTORE: + return self.kvsRequest(action, params) + default: + return nil, errors.Wrapf(errors.ErrNotSupported, "not support %s service tag", serviceType) + } +} + +func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := self.getSdkClient() + if err != nil { + return nil, err + } + domain := self.client.getDomain(APSARA_PRODUCT_SLB) + return self.productRequest(client, APSARA_PRODUCT_SLB, domain, APSARA_API_VERSION_LB, apiName, params, self.client.debug) +} + +///////////////////////////////////////////////////////////////////////////// +func (self *SRegion) GetId() string { + return self.RegionId +} + +func (self *SRegion) GetName() string { + switch self.client.cpcfg.Vendor { + case api.CLOUD_PROVIDER_APSARA: + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_APSARA_CN, self.LocalName) + default: + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_APSARA_CN, self.LocalName) + } +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_APSARA_EN, self.LocalName) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_APSARA, self.RegionId) +} + +func (self *SRegion) IsEmulated() bool { + return false +} + +func (self *SRegion) GetProvider() string { + return self.client.cpcfg.Vendor +} + +func (self *SRegion) GetCloudEnv() string { + return "" +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) Refresh() error { + // do nothing + return nil +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if self.izones == nil { + var err error + err = self.fetchInfrastructure() + if err != nil { + return nil, err + } + } + return self.izones, nil +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) getStoragecache() *SStoragecache { + if self.storageCache == nil { + self.storageCache = &SStoragecache{region: self} + } + return self.storageCache +} + +func (self *SRegion) _fetchZones(chargeType TChargeType, spotStrategy SpotStrategyType) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + if len(chargeType) > 0 { + params["InstanceChargeType"] = string(chargeType) + } + if len(spotStrategy) > 0 { + params["SpotStrategy"] = string(spotStrategy) + } + body, err := self.ecsRequest("DescribeZones", params) + if err != nil { + return err + } + + zones := make([]SZone, 0) + err = body.Unmarshal(&zones, "Zones", "Zone") + if err != nil { + return err + } + + self.izones = make([]cloudprovider.ICloudZone, len(zones)) + + for i := 0; i < len(zones); i += 1 { + zones[i].region = self + self.izones[i] = &zones[i] + } + + return nil +} + +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) +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + return self.GetInstance(id) +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return self.getDisk(id) +} + +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) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + ivpcs, err := self.GetIVpcs() + if err != nil { + return nil, err + } + for i := 0; i < len(ivpcs); i += 1 { + if ivpcs[i].GetGlobalId() == id { + return ivpcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) fetchIVpcs() error { + vpcs := make([]SVpc, 0) + for { + part, total, err := self.GetVpcs(nil, len(vpcs), 50) + if err != nil { + return err + } + vpcs = append(vpcs, part...) + if len(vpcs) >= total { + break + } + } + self.ivpcs = make([]cloudprovider.ICloudVpc, len(vpcs)) + for i := 0; i < len(vpcs); i += 1 { + vpcs[i].region = self + self.ivpcs[i] = &vpcs[i] + } + return nil +} + +func (self *SRegion) fetchInfrastructure() error { + err := self._fetchZones(PostPaidInstanceChargeType, NoSpotStrategy) + if err != nil { + return err + } + err = self.fetchIVpcs() + if 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) GetVpcs(vpcId []string, offset int, limit int) ([]SVpc, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if vpcId != nil && len(vpcId) > 0 { + params["VpcId"] = strings.Join(vpcId, ",") + } + + body, err := self.ecsRequest("DescribeVpcs", params) + if err != nil { + log.Errorf("GetVpcs fail %s", err) + return nil, 0, err + } + + vpcs := make([]SVpc, 0) + err = body.Unmarshal(&vpcs, "Vpcs", "Vpc") + if err != nil { + log.Errorf("Unmarshal vpc fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return vpcs, int(total), 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) GetVRouters(offset int, limit int) ([]SVRouter, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + body, err := self.ecsRequest("DescribeVRouters", params) + if err != nil { + log.Errorf("GetVRouters fail %s", err) + return nil, 0, err + } + + vrouters := make([]SVRouter, 0) + err = body.Unmarshal(&vrouters, "VRouters", "VRouter") + if err != nil { + log.Errorf("Unmarshal vrouter fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return vrouters, int(total), nil +} + +func (self *SRegion) GetRouteTables(ids []string, offset int, limit int) ([]SRouteTable, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + if ids != nil && len(ids) > 0 { + params["RouteTableId"] = strings.Join(ids, ",") + } + + body, err := self.ecsRequest("DescribeRouteTables", params) + if err != nil { + log.Errorf("GetRouteTables fail %s", err) + return nil, 0, err + } + + routetables := make([]SRouteTable, 0) + err = body.Unmarshal(&routetables, "RouteTables", "RouteTable") + if err != nil { + log.Errorf("Unmarshal routetables fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return routetables, int(total), nil +} + +func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, gpu int, zoneId string) ([]SInstanceType, error) { + if self.instanceTypes == nil { + types, err := self.GetInstanceTypes() + if err != nil { + log.Errorf("GetInstanceTypes %s", err) + return nil, err + } + self.instanceTypes = types + } + var available []string + if len(zoneId) > 0 { + zone, err := self.getZoneById(zoneId) + if err != nil { + return nil, err + } + available = zone.AvailableInstanceTypes.InstanceTypes + } + ret := make([]SInstanceType, 0) + for _, t := range self.instanceTypes { + if t.CpuCoreCount == cpu && memMB == t.memoryMB() && gpu == t.GPUAmount { + if available == nil || utils.IsInStringArray(t.InstanceTypeId, available) { + ret = append(ret, t) + } + } + } + return ret, nil +} + +func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, memGB int, storageType string, dataDiskSizesGB []int, vswitchId string, passwd 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(vswitchId) + if net != nil { + desc := &cloudprovider.SManagedVMCreateConfig{ + Name: name, + ExternalImageId: imgId, + SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType}, + Cpu: cpu, + MemoryMB: memGB * 1024, + ExternalNetworkId: vswitchId, + Password: passwd, + DataDisks: []cloudprovider.SDiskInfo{}, + PublicKey: publicKey, + } + for _, sizeGB := range dataDiskSizesGB { + desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType}) + } + inst, err := z.getHost().CreateVM(desc) + if err != nil { + return nil, err + } + return inst.(*SInstance), nil + } + } + return nil, fmt.Errorf("cannot find vswitch %s", vswitchId) +} + +func (self *SRegion) instanceOperation(instanceId string, opname string, extra map[string]string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + if extra != nil && len(extra) > 0 { + for k, v := range extra { + params[k] = v + } + } + _, err := self.ecsRequest(opname, params) + return err +} + +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) GetInstanceVNCUrl(instanceId string) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + body, err := self.ecsRequest("DescribeInstanceVncUrl", params) + if err != nil { + return "", err + } + return body.GetString("VncUrl") +} + +func (self *SRegion) ModifyInstanceVNCUrlPassword(instanceId string, passwd string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["InstanceId"] = instanceId + params["VncPassword"] = passwd // must be 6 digital + alphabet + _, err := self.ecsRequest("ModifyInstanceVncPasswd", params) + return err +} + +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + params := make(map[string]string) + if len(opts.CIDR) > 0 { + params["CidrBlock"] = opts.CIDR + } + if len(opts.NAME) > 0 { + params["VpcName"] = opts.NAME + } + if len(opts.Desc) > 0 { + params["Description"] = opts.Desc + } + params["ClientToken"] = utils.GenRequestId(20) + body, err := self.ecsRequest("CreateVpc", params) + if err != nil { + return nil, err + } + vpcId, err := body.GetString("VpcId") + if err != nil { + return nil, err + } + err = self.fetchInfrastructure() + if err != nil { + return nil, err + } + return self.GetIVpcById(vpcId) +} + +func (self *SRegion) DeleteVpc(vpcId string) error { + params := make(map[string]string) + params["VpcId"] = vpcId + + _, err := self.ecsRequest("DeleteVpc", params) + return err +} + +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) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname, userData string) error { + params := make(map[string]string) + params["InstanceId"] = instId + if len(name) > 0 { + params["InstanceName"] = name + } + if len(desc) > 0 { + params["Description"] = desc + } + if len(passwd) > 0 { + params["Password"] = passwd + } + if len(hostname) > 0 { + params["HostName"] = hostname + } + if len(userData) > 0 { + params["UserData"] = userData + } + _, err := self.ecsRequest("ModifyInstanceAttribute", params) + return err +} + +func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error { + return self.updateInstance(instId, "", "", passwd, "", "") +} + +// func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { +// eips, total, err := self.GetSnapshots("", 0, 50) +// if err != nil { +// return nil, err +// } +// for len(eips) < total { +// var parts []SEipAddress +// parts, total, err = self.GetEips("", len(eips), 50) +// if err != nil { +// return nil, err +// } +// eips = append(eips, parts...) +// } +// ret := make([]cloudprovider.ICloudEIP, len(eips)) +// for i := 0; i < len(eips); i += 1 { +// ret[i] = &eips[i] +// } +// return ret, nil +// } + +func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, total, err := self.GetEips("", "", 0, 50) + if err != nil { + return nil, err + } + for len(eips) < total { + var parts []SEipAddress + parts, total, err = self.GetEips("", "", len(eips), 50) + if err != nil { + return nil, err + } + eips = append(eips, parts...) + } + ret := make([]cloudprovider.ICloudEIP, len(eips)) + for i := 0; i < len(eips); i += 1 { + ret[i] = &eips[i] + } + return ret, nil +} + +func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { + eips, total, err := self.GetEips(eipId, "", 0, 1) + 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 (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + secgroup, err := region.GetSecurityGroupDetails(secgroupId) + if err != nil { + return nil, err + } + vpc, err := region.getVpc(secgroup.VpcId) + if err != nil { + return nil, errors.Wrapf(err, "region.getVpc(%s)", secgroup.VpcId) + } + secgroup.vpc = vpc + return secgroup, nil +} + +func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, total, err := region.GetSecurityGroups(opts.VpcId, opts.Name, []string{}, 0, 0) + if err != nil { + return nil, err + } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } + if total > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return &secgroups[0], nil +} + +func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + externalId, err := region.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) + if err != nil { + return nil, err + } + return region.GetISecurityGroupById(externalId) +} + +func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + lbs, err := region.GetLoadbalancers(nil) + if err != nil { + return nil, err + } + ilbs := []cloudprovider.ICloudLoadbalancer{} + for i := 0; i < len(lbs); i++ { + lbs[i].region = region + ilbs = append(ilbs, &lbs[i]) + } + return ilbs, nil +} + +func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { + return region.GetLoadbalancerDetail(loadbalancerId) +} + +func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + certs, err := region.GetLoadbalancerServerCertificates() + if err != nil { + return nil, err + } + for i := 0; i < len(certs); i++ { + if certs[i].GetGlobalId() == certId { + certs[i].region = region + return &certs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["ServerCertificateName"] = cert.Name + params["PrivateKey"] = cert.PrivateKey + params["ServerCertificate"] = cert.Certificate + body, err := region.lbRequest("UploadServerCertificate", params) + if err != nil { + return nil, err + } + certID, err := body.GetString("ServerCertificateId") + if err != nil { + return nil, err + } + return region.GetILoadBalancerCertificateById(certID) +} + +func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + certificates, err := region.GetLoadbalancerServerCertificates() + if err != nil { + return nil, err + } + iCertificates := []cloudprovider.ICloudLoadbalancerCertificate{} + for i := 0; i < len(certificates); i++ { + certificates[i].region = region + iCertificates = append(iCertificates, &certificates[i]) + } + return iCertificates, nil +} + +func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["LoadBalancerName"] = loadbalancer.Name + if len(loadbalancer.ZoneID) > 0 { + params["MasterZoneId"] = loadbalancer.ZoneID + } + + if len(loadbalancer.VpcID) > 0 { + params["VpcId"] = loadbalancer.VpcID + } + + if len(loadbalancer.NetworkIDs) > 0 { + params["VSwitchId"] = loadbalancer.NetworkIDs[0] + } + + if len(loadbalancer.Address) > 0 { + params["Address"] = loadbalancer.Address + } + + if len(loadbalancer.AddressType) > 0 { + params["AddressType"] = loadbalancer.AddressType + } + + if len(loadbalancer.LoadbalancerSpec) > 0 { + params["LoadBalancerSpec"] = loadbalancer.LoadbalancerSpec + } + + if len(loadbalancer.ChargeType) > 0 { + params["InternetChargeType"] = "payby" + loadbalancer.ChargeType + } + + if len(loadbalancer.ProjectId) > 0 { + params["ResourceGroupId"] = loadbalancer.ProjectId + } + + if loadbalancer.ChargeType == api.LB_CHARGE_TYPE_BY_BANDWIDTH && loadbalancer.EgressMbps > 0 { + params["Bandwidth"] = fmt.Sprintf("%d", loadbalancer.EgressMbps) + } + + body, err := region.lbRequest("CreateLoadBalancer", params) + if err != nil { + return nil, err + } + loadBalancerID, err := body.GetString("LoadBalancerId") + if err != nil { + return nil, err + } + region.SetResourceTags("slb", "instance", []string{loadBalancerID}, loadbalancer.Tags, false) + iLoadbalancer, err := region.GetLoadbalancerDetail(loadBalancerID) + if err != nil { + return nil, err + } + return iLoadbalancer, cloudprovider.WaitStatus(iLoadbalancer, api.LB_STATUS_ENABLED, time.Second*5, time.Minute*5) +} + +func (region *SRegion) AddAccessControlListEntry(aclId string, entrys []cloudprovider.SLoadbalancerAccessControlListEntry) error { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["AclId"] = aclId + aclArray := jsonutils.NewArray() + for i := 0; i < len(entrys); i++ { + //阿里云AclEntrys参数必须是CIDR格式的。 + if regutils.MatchIPAddr(entrys[i].CIDR) { + entrys[i].CIDR += "/32" + } + aclArray.Add(jsonutils.Marshal(map[string]string{"entry": entrys[i].CIDR, "comment": entrys[i].Comment})) + } + if aclArray.Length() == 0 { + return nil + } + params["AclEntrys"] = aclArray.String() + _, err := region.lbRequest("AddAccessControlListEntry", params) + return err +} + +func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + params := map[string]string{} + params["RegionId"] = region.RegionId + params["AclName"] = acl.Name + body, err := region.lbRequest("CreateAccessControlList", params) + if err != nil { + return nil, err + } + aclId, err := body.GetString("AclId") + if err != nil { + return nil, err + } + iAcl, err := region.GetLoadbalancerAclDetail(aclId) + if err != nil { + return nil, err + } + return iAcl, region.AddAccessControlListEntry(aclId, acl.Entrys) +} + +func (self *SRegion) GetBuckets() ([]SBucket, error) { + resp, err := self.ossRequest("GetService", map[string]string{}) + if err != nil { + return nil, err + } + if !resp.Contains("Data") { + if self.client.cpcfg.UpdatePermission != nil { + self.client.cpcfg.UpdatePermission("oss", "ListBuckets") + } + return []SBucket{}, nil + } + ret := []SBucket{} + err = resp.Unmarshal(&ret, "Data", "ListAllMyBucketsResult", "Buckets", "Bucket") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + if len(ret) > 0 { + self.ossEndpoint = ret[0].IntranetEndpoint + } + return ret, nil +} + +func (self *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + buckets, err := self.GetBuckets() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudBucket{} + for i := range buckets { + buckets[i].region = self + ret = append(ret, &buckets[i]) + } + return ret, nil +} + +func str2StorageClass(storageClassStr string) (oss.StorageClassType, error) { + storageClass := oss.StorageStandard + if strings.EqualFold(storageClassStr, string(oss.StorageStandard)) { + // + } else if strings.EqualFold(storageClassStr, string(oss.StorageIA)) { + storageClass = oss.StorageIA + } else if strings.EqualFold(storageClassStr, string(oss.StorageArchive)) { + storageClass = oss.StorageArchive + } else { + return storageClass, errors.Error("not supported storageClass") + } + return storageClass, nil +} + +func str2Acl(aclStr string) (oss.ACLType, error) { + acl := oss.ACLPrivate + if strings.EqualFold(aclStr, string(oss.ACLPrivate)) { + // private, default + } else if strings.EqualFold(aclStr, string(oss.ACLPublicRead)) { + acl = oss.ACLPublicRead + } else if strings.EqualFold(aclStr, string(oss.ACLPublicReadWrite)) { + acl = oss.ACLPublicReadWrite + } else { + return acl, errors.Error("not supported acl") + } + return acl, nil +} + +func (self *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { + osscli, err := self.GetOssClient() + if err != nil { + return errors.Wrap(err, "region.GetOssClient") + } + opts := make([]oss.Option, 0) + if len(storageClassStr) > 0 { + storageClass, err := str2StorageClass(storageClassStr) + if err != nil { + return err + } + opts = append(opts, oss.StorageClass(storageClass)) + } + if len(aclStr) > 0 { + acl, err := str2Acl(aclStr) + if err != nil { + return err + } + opts = append(opts, oss.ACL(acl)) + } + return osscli.CreateBucket(name, opts...) +} + +func ossErrorCode(err error) int { + if srvErr, ok := err.(oss.ServiceError); ok { + return srvErr.StatusCode + } + if srvErr, ok := err.(*oss.ServiceError); ok { + return srvErr.StatusCode + } + return -1 +} + +func (self *SRegion) DeleteIBucket(name string) error { + cli, err := self.GetOssClient() + if err != nil { + return err + } + return cli.DeleteBucket(name) +} + +func (self *SRegion) GetBucket(name string) (*SBucket, error) { + params := map[string]string{ + "AccountInfo": "aaa", + "x-acs-instanceid": name, + "Params": jsonutils.Marshal(map[string]string{"BucketName": name}).String(), + } + resp, err := self.ossRequest("GetBucketInfo", params) + if err != nil { + return nil, errors.Wrapf(err, "GetBucketInfo") + } + bucket := &SBucket{region: self} + return bucket, resp.Unmarshal(bucket, "Data", "BucketInfo", "Bucket") +} + +func (self *SRegion) IBucketExist(name string) (bool, error) { + _, err := self.GetBucket(name) + if err != nil { + return false, err + } + return true, nil +} + +func (self *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { + buckets, err := self.GetBuckets() + if err != nil { + return nil, err + } + for i := range buckets { + if buckets[i].GetName() == name { + buckets[i].region = self + return &buckets[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) +} + +func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { + return region.GetIBucketById(name) +} + +func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { + caches, err := self.GetElasticCaches(nil) + if err != nil { + return nil, err + } + + icaches := make([]cloudprovider.ICloudElasticcache, len(caches)) + for i := range caches { + caches[i].region = self + icaches[i] = &caches[i] + } + + return icaches, nil +} + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/resource_tags.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/resource_tags.go new file mode 100644 index 0000000000..5ee78a5518 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/resource_tags.go @@ -0,0 +1,244 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type STagResource struct { + ResourceType string `json:"ResourceType"` + TagValue string `json:"TagValue"` + ResourceID string `json:"ResourceId"` + TagKey string `json:"TagKey"` +} + +func (self *SRegion) rawListTagResources(serviceType string, resourceType string, resIds []string, token string) ([]STagResource, string, error) { + if len(resIds) > 50 { + return nil, "", errors.Wrap(cloudprovider.ErrNotSupported, "resource count exceed 50 for one request") + } + params := make(map[string]string) + params["ResourceType"] = resourceType + for i := range resIds { + params[fmt.Sprintf("ResourceId.%d", i+1)] = resIds[i] + } + if len(token) != 0 { + params["NextToken"] = token + } + ret, err := self.tagRequest(serviceType, "ListTagResources", params) + if err != nil { + return nil, "", errors.Wrapf(err, `self.tagRequest(%s,"ListTagResources", %s)`, serviceType, jsonutils.Marshal(params).String()) + } + tagResources := []STagResource{} + err = ret.Unmarshal(&tagResources, "TagResources", "TagResource") + if err != nil { + return nil, "", errors.Wrapf(err, "(%s).Unmarshal(&tagResources)", ret.String()) + } + nextToken, _ := ret.GetString("NextToken") + return tagResources, nextToken, nil +} + +func splitStringSlice(resIds []string, stride int) [][]string { + result := [][]string{} + i := 0 + for i < len(resIds)/stride { + result = append(result, resIds[i*stride:i*stride+stride]) + i++ + } + remainder := len(resIds) % stride + if remainder != 0 { + result = append(result, resIds[i*stride:i*stride+remainder]) + } + return result +} + +func splitTags(tags map[string]string, stride int) []map[string]string { + tagsGroups := []map[string]string{} + tagsGroup := map[string]string{} + for k, v := range tags { + tagsGroup[k] = v + if len(tagsGroup) == stride { + tagsGroups = append(tagsGroups, tagsGroup) + tagsGroup = map[string]string{} + } + } + if len(tagsGroup) > 0 { + tagsGroups = append(tagsGroups, tagsGroup) + } + return tagsGroups +} + +func (self *SRegion) ListResourceTags(serviceType string, resourceType string, resIds []string) (map[string]*map[string]string, error) { + tags := make(map[string]*map[string]string) + tagReources := []STagResource{} + nextToken := "" + resIdsGroups := splitStringSlice(resIds, 50) + for i := range resIdsGroups { + for { + _tagResource, nextToken, err := self.rawListTagResources(serviceType, resourceType, resIdsGroups[i], nextToken) + if err != nil { + return nil, errors.Wrapf(err, "self.rawListTagResources(%s,%s,%s)", resourceType, resIds, nextToken) + } + tagReources = append(tagReources, _tagResource...) + if len(_tagResource) == 0 || len(nextToken) == 0 { + break + } + + } + } + for _, r := range tagReources { + if tagMapPtr, ok := tags[r.ResourceID]; !ok { + tagMap := map[string]string{ + r.TagKey: r.TagValue, + } + tags[r.ResourceID] = &tagMap + } else { + tagMap := *tagMapPtr + tagMap[r.TagKey] = r.TagValue + } + } + return tags, nil +} + +func (self *SRegion) rawTagResources(serviceType string, resourceType string, resIds []string, tags map[string]string) error { + if len(resIds) > 50 { + return errors.Wrap(cloudprovider.ErrNotSupported, "resource count exceed 50 for one request") + } + if len(tags) > 20 { + return errors.Wrap(cloudprovider.ErrNotSupported, "tags count exceed 20 for one request") + } + params := make(map[string]string) + params["ResourceType"] = resourceType + for i := range resIds { + params[fmt.Sprintf("ResourceId.%d", i+1)] = resIds[i] + } + i := 0 + for k, v := range tags { + params[fmt.Sprintf("Tag.%d.Key", i+1)] = k + params[fmt.Sprintf("Tag.%d.Value", i+1)] = v + i++ + } + _, err := self.tagRequest(serviceType, "TagResources", params) + if err != nil { + return errors.Wrapf(err, `self.tagRequest(%s,"TagResources", %s)`, serviceType, jsonutils.Marshal(params).String()) + } + return nil +} + +func (self *SRegion) TagResources(serviceType string, resourceType string, resIds []string, tags map[string]string) error { + if len(resIds) == 0 || len(tags) == 0 { + return nil + } + resIdsGroups := splitStringSlice(resIds, 50) + tagsGroups := splitTags(tags, 20) + for i := range resIdsGroups { + for j := range tagsGroups { + err := self.rawTagResources(serviceType, resourceType, resIdsGroups[i], tagsGroups[j]) + if err != nil { + return errors.Wrapf(err, "self.rawTagResources(resourceType, resIdsGroups[i], tagsGroups[i])") + } + } + } + return nil +} + +func (self *SRegion) rawUntagResources(serviceType string, resourceType string, resIds []string, tags []string) error { + if len(resIds) > 50 { + return errors.Wrap(cloudprovider.ErrNotSupported, "resource count exceed 50 for one request") + } + if len(tags) > 20 { + return errors.Wrap(cloudprovider.ErrNotSupported, "tags count exceed 20 for one request") + } + params := make(map[string]string) + params["ResourceType"] = resourceType + for i := range resIds { + params[fmt.Sprintf("ResourceId.%d", i+1)] = resIds[i] + } + for i := range tags { + params[fmt.Sprintf("TagKey.%d", i+1)] = tags[i] + } + _, err := self.tagRequest(serviceType, "UntagResources", params) + if err != nil { + return errors.Wrapf(err, `self.tagRequest(%s,"UntagResources", %s)`, serviceType, jsonutils.Marshal(params).String()) + } + return nil +} + +func (self *SRegion) UntagResources(serviceType string, resourceType string, resIds []string, tags []string) error { + if len(resIds) == 0 || len(tags) == 0 { + return nil + } + resIdsGroups := splitStringSlice(resIds, 50) + tagsGroups := splitStringSlice(tags, 20) + for i := range resIdsGroups { + for j := range tagsGroups { + err := self.rawUntagResources(serviceType, resourceType, resIdsGroups[i], tagsGroups[j]) + if err != nil { + return errors.Wrapf(err, "self.rawTagResources(resourceType, resIdsGroups[i], tagsGroups[i])") + } + } + } + return nil +} + +func (self *SRegion) SetResourceTags(serviceType string, resourceType string, resIds []string, tags map[string]string, replace bool) error { + oldTags, err := self.ListResourceTags(serviceType, resourceType, resIds) + if err != nil { + return errors.Wrapf(err, "self.ListResourceTags(%s,%s)", resourceType, resIds) + } + for i := range resIds { + _, ok := oldTags[resIds[i]] + if !ok { + err := self.TagResources(serviceType, resourceType, []string{resIds[i]}, tags) + if err != nil { + return errors.Wrap(err, "self.TagResources(resourceType, []string{resIds[i]}, tags)") + } + } else { + oldResourceTags := *oldTags[resIds[i]] + addTags := map[string]string{} + for k, v := range tags { + if _, ok := oldResourceTags[k]; !ok { + addTags[k] = v + } else { + if oldResourceTags[k] != v { + addTags[k] = v + } + } + } + delTags := []string{} + if replace { + for k := range oldResourceTags { + if _, ok := tags[k]; !ok { + delTags = append(delTags, k) + } + } + } + err := self.UntagResources(serviceType, resourceType, []string{resIds[i]}, delTags) + if err != nil { + return errors.Wrap(err, "self.UntagResources(resourceType, []string{resIds[i]}, delTags)") + } + err = self.TagResources(serviceType, resourceType, []string{resIds[i]}, addTags) + if err != nil { + return errors.Wrap(err, "self.TagResources(resourceType, []string{resIds[i]}, addTags)") + } + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/routetable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/routetable.go new file mode 100644 index 0000000000..fb9027558c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/routetable.go @@ -0,0 +1,319 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// {"CreationTime":"2017-03-19T13:37:40Z","RouteEntrys":{"RouteEntry":[{"DestinationCidrBlock":"172.31.32.0/20","InstanceId":"","NextHopType":"local","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"},{"DestinationCidrBlock":"100.64.0.0/10","InstanceId":"","NextHopType":"service","NextHops":{"NextHop":[]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","Status":"Available","Type":"System"}]},"RouteTableId":"vtb-j6c60lectdi80rk5xz43g","RouteTableType":"System","VRouterId":"vrt-j6c00qrol733dg36iq4qj"} + +type SNextHops struct { + NextHop []string +} + +type SRouteEntry struct { + multicloud.SResourceBase + ApsaraTags + routeTable *SRouteTable + + RouteTableId string + Type string + DestinationCidrBlock string + NextHopType string + InstanceId string + RouteEntryId string + RouteEntryName string + NextHops SNextHops +} + +func (route *SRouteEntry) GetId() string { + return route.RouteEntryId +} + +func (route *SRouteEntry) GetName() string { + return route.RouteEntryName +} + +func (route *SRouteEntry) GetGlobalId() string { + return route.GetId() +} + +func (route *SRouteEntry) GetStatus() string { + return "" +} + +func (route *SRouteEntry) Refresh() error { + return nil +} + +func (route *SRouteEntry) IsEmulated() bool { + return false +} + +// Custom:自定义路由。 System:系统路由。 +func (route *SRouteEntry) GetType() string { + return route.Type +} + +func (route *SRouteEntry) GetCidr() string { + return route.DestinationCidrBlock +} + +func (route *SRouteEntry) GetNextHopType() string { + return route.NextHopType +} + +func (route *SRouteEntry) GetNextHop() string { + return route.InstanceId +} + +type SRouteEntrys struct { + RouteEntry []*SRouteEntry +} + +type SRouteTable struct { + multicloud.SResourceBase + ApsaraTags + region *SRegion + vpc *SVpc + routes []cloudprovider.ICloudRoute + + VpcId string + CreationTime time.Time + RouteEntrys SRouteEntrys + VRouterId string + Description string + + RouteTableId string + RouteTableName string + RouteTableType string + RouterId string + RouterType string + VSwitchIds SRouteTableVSwitchIds +} + +type SRouteTableVSwitchIds struct { + VSwitchId []string +} + +type sDescribeRouteTablesResponseRouteTables struct { + RouteTable []SRouteTable +} + +type sDescribeRouteTablesResponse struct { + RouteTables sDescribeRouteTablesResponseRouteTables + TotalCount int +} + +func (self *SRouteTable) GetDescription() string { + return self.Description +} + +func (self *SRouteTable) GetId() string { + return self.GetGlobalId() +} + +func (self *SRouteTable) GetGlobalId() string { + return self.RouteTableId +} + +func (self *SRouteTable) GetName() string { + return self.RouteTableName +} + +func (self *SRouteTable) GetRegionId() string { + return self.region.RegionId +} + +// VRouter:VPC路由器。 VBR:边界路由器。 +func (self *SRouteTable) GetType() cloudprovider.RouteTableType { + switch self.RouteTableType { + case "System": + return cloudprovider.RouteTableTypeSystem + case "Custom": + return cloudprovider.RouteTableTypeCustom + default: + return cloudprovider.RouteTableTypeSystem + } +} + +func (self *SRouteTable) GetVpcId() string { + return self.VpcId +} + +func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { + if self.routes == nil { + err := self.fetchRoutes() + if err != nil { + return nil, err + } + } + return self.routes, nil +} + +func (self *SRouteTable) GetStatus() string { + return "" +} + +func (self *SRouteTable) IsEmulated() bool { + return false +} + +func (self *SRouteTable) Refresh() error { + return nil +} + +func (self *SRouteTable) fetchRoutes() error { + routes := make([]*SRouteEntry, 0) + for { + parts, total, err := self.RemoteGetRoutes(len(routes), 50) + if err != nil { + return err + } + routes = append(routes, parts...) + if len(routes) >= total { + break + } + } + self.routes = make([]cloudprovider.ICloudRoute, len(routes)) + for i := 0; i < len(routes); i++ { + routes[i].routeTable = self + self.routes[i] = routes[i] + } + return nil +} + +func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { + result := []cloudprovider.RouteTableAssociation{} + switch self.RouterType { + case "VRouter": + for i := range self.VSwitchIds.VSwitchId { + association := cloudprovider.RouteTableAssociation{ + AssociationId: self.RouteTableId + ":" + self.VSwitchIds.VSwitchId[i], + AssociationType: cloudprovider.RouteTableAssociaToSubnet, + AssociatedResourceId: self.VSwitchIds.VSwitchId[i], + } + result = append(result, association) + } + case "VBR": + association := cloudprovider.RouteTableAssociation{ + AssociationId: self.RouteTableId + ":" + self.RouterId, + AssociationType: cloudprovider.RouteTableAssociaToRouter, + AssociatedResourceId: self.RouterId, + } + result = append(result, association) + } + + return result +} + +func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteTable) RemoteGetRoutes(offset int, limit int) ([]*SRouteEntry, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RouteTableId"] = self.RouteTableId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + body, err := self.region.ecsRequest("DescribeRouteTables", params) + if err != nil { + log.Errorf("RemoteGetRoutes fail %s", err) + return nil, 0, err + } + + resp := sDescribeRouteTablesResponse{} + err = body.Unmarshal(&resp) + if err != nil { + log.Errorf("Unmarshal routeEntrys fail %s", err) + return nil, 0, err + } + routeTables := resp.RouteTables.RouteTable + if len(routeTables) != 1 { + return nil, 0, fmt.Errorf("expecting 1 route table, got %d", len(routeTables)) + } + routeTable := routeTables[0] + return routeTable.RouteEntrys.RouteEntry, resp.TotalCount, nil +} + +func (self *SVpc) RemoteGetRouteTableList(offset int, limit int) ([]*SRouteTable, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["VpcId"] = self.VpcId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + body, err := self.region.vpcRequest("DescribeRouteTableList", params) + if err != nil { + log.Errorf("RemoteGetRouteTableList fail %s", err) + return nil, 0, err + } + + routeTables := make([]*SRouteTable, 0) + err = body.Unmarshal(&routeTables, "RouterTableList", "RouterTableListType") + if err != nil { + log.Errorf("Unmarshal routeTables fail %s", err) + return nil, 0, err + } + for _, routeTable := range routeTables { + routeTable.region = self.region + } + total, _ := body.Int("TotalCount") + return routeTables, int(total), nil +} + +func (region *SRegion) AssociateRouteTable(rtableId string, vswitchId string) error { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["RouteTableId"] = rtableId + params["VSwitchId"] = vswitchId + _, err := region.vpcRequest("AssociateRouteTable", params) + return err +} + +func (region *SRegion) UnassociateRouteTable(rtableId string, vswitchId string) error { + params := make(map[string]string) + params["RegionId"] = region.RegionId + params["RouteTableId"] = rtableId + params["VSwitchId"] = vswitchId + _, err := region.vpcRequest("UnassociateRouteTable", params) + return err +} + +func (routeTable *SRouteTable) IsSystem() bool { + return strings.ToLower(routeTable.RouteTableType) == "system" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/securitygroup.go new file mode 100644 index 0000000000..97fed78ee0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/securitygroup.go @@ -0,0 +1,512 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// {"CreationTime":"2017-03-19T13:37:48Z","Description":"System created security group.","SecurityGroupId":"sg-j6cannq0xxj2r9z0yxwl","SecurityGroupName":"sg-j6cannq0xxj2r9z0yxwl","Tags":{"Tag":[]},"VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"} +// {"Description":"System created security group.","InnerAccessPolicy":"Accept","Permissions":{"Permission":[{"CreateTime":"2017-03-19T13:37:54Z","Description":"","DestCidrIp":"","DestGroupId":"","DestGroupName":"","DestGroupOwnerAccount":"","Direction":"ingress","IpProtocol":"ALL","NicType":"intranet","Policy":"Accept","PortRange":"-1/-1","Priority":110,"SourceCidrIp":"0.0.0.0/0","SourceGroupId":"","SourceGroupName":"","SourceGroupOwnerAccount":""},{"CreateTime":"2017-03-19T13:37:55Z","Description":"","DestCidrIp":"0.0.0.0/0","DestGroupId":"","DestGroupName":"","DestGroupOwnerAccount":"","Direction":"egress","IpProtocol":"ALL","NicType":"intranet","Policy":"Accept","PortRange":"-1/-1","Priority":110,"SourceCidrIp":"","SourceGroupId":"","SourceGroupName":"","SourceGroupOwnerAccount":""}]},"RegionId":"cn-hongkong","RequestId":"FBFE0950-5F2D-40DE-8C3C-E5A62AE7F7DA","SecurityGroupId":"sg-j6cannq0xxj2r9z0yxwl","SecurityGroupName":"sg-j6cannq0xxj2r9z0yxwl","VpcId":"vpc-j6c86z3sh8ufhgsxwme0q"} + +type SecurityGroupPermissionNicType string + +const ( + IntranetNicType SecurityGroupPermissionNicType = "intranet" + InternetNicType SecurityGroupPermissionNicType = "internet" +) + +type SPermission struct { + CreateTime time.Time + Description string + DestCidrIp string + DestGroupId string + DestGroupName string + DestGroupOwnerAccount string + Direction string + IpProtocol string + NicType SecurityGroupPermissionNicType + Policy string + PortRange string + Priority int + SourceCidrIp string + SourceGroupId string + SourceGroupName string + SourceGroupOwnerAccount string +} + +type SPermissions struct { + Permission []SPermission +} + +type Tags struct { + Tag []Tag +} + +type Tag struct { + TagKey string + TagValue string +} + +type SSecurityGroup struct { + multicloud.SSecurityGroup + ApsaraTags + + vpc *SVpc + CreationTime time.Time + Description string + SecurityGroupId string + SecurityGroupName string + VpcId string + InnerAccessPolicy string + Permissions SPermissions + RegionId string + Tags Tags + + DepartmentInfo +} + +func (self *SSecurityGroup) GetVpcId() string { + return self.VpcId +} + +func (self *SSecurityGroup) GetTags() (map[string]string, error) { + tags := map[string]string{} + for _, value := range self.Tags.Tag { + tags[value.TagKey] = value.TagValue + } + return tags, nil +} + +func (self *SSecurityGroup) GetId() string { + return self.SecurityGroupId +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.SecurityGroupId +} + +func (self *SSecurityGroup) GetDescription() string { + return self.Description +} + +func (self *SSecurityGroup) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + rules := make([]cloudprovider.SecurityRule, 0) + secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) + if err != nil { + return nil, err + } + for _, permission := range secgrp.Permissions.Permission { + rule, err := permission.toRule() + if err != nil { + log.Errorf("convert rule %s for group %s(%s) error: %v", permission.Description, self.SecurityGroupName, self.SecurityGroupId, err) + continue + } + rules = append(rules, rule) + } + return rules, nil +} + +func (self *SSecurityGroup) GetName() string { + if len(self.SecurityGroupName) > 0 { + return self.SecurityGroupName + } + return self.SecurityGroupId +} + +func (self *SSecurityGroup) GetStatus() string { + return "" +} + +func (self *SSecurityGroup) IsEmulated() bool { + return false +} + +func (self *SSecurityGroup) Refresh() error { + group, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) + if err != nil { + return err + } + return jsonutils.Update(self, group) +} + +func (self *SRegion) GetSecurityGroups(vpcId, name string, securityGroupIds []string, offset int, limit int) ([]SSecurityGroup, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + if len(vpcId) > 0 { + params["VpcId"] = vpcId + } + if len(name) > 0 { + params["SecurityGroupName"] = name + } + + if securityGroupIds != nil && len(securityGroupIds) > 0 { + params["SecurityGroupIds"] = jsonutils.Marshal(securityGroupIds).String() + } + + body, err := self.ecsRequest("DescribeSecurityGroups", params) + if err != nil { + log.Errorf("GetSecurityGroups fail %s", err) + return nil, 0, err + } + + secgrps := make([]SSecurityGroup, 0) + err = body.Unmarshal(&secgrps, "SecurityGroups", "SecurityGroup") + if err != nil { + log.Errorf("Unmarshal security groups fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return secgrps, int(total), nil +} + +func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SecurityGroupId"] = secGroupId + + body, err := self.ecsRequest("DescribeSecurityGroupAttribute", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeSecurityGroupAttribute") + } + + secgrp := SSecurityGroup{} + err = body.Unmarshal(&secgrp) + if err != nil { + return nil, errors.Wrap(err, "body.Unmarshal") + } + return &secgrp, nil +} + +func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (string, error) { + params := make(map[string]string) + if len(vpcId) > 0 { + params["VpcId"] = vpcId + } + + if name == "Default" { + name = "Default-copy" + } + + if len(name) > 0 { + params["SecurityGroupName"] = name + } + if len(desc) > 0 { + params["Description"] = desc + } + params["ClientToken"] = utils.GenRequestId(20) + + body, err := self.ecsRequest("CreateSecurityGroup", params) + if err != nil { + return "", errors.Wrap(err, "CreateSecurityGroup") + } + return body.GetString("SecurityGroupId") +} + +func (self *SRegion) modifySecurityGroupRule(secGrpId string, rule *secrules.SecurityRule) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SecurityGroupId"] = secGrpId + params["NicType"] = string(IntranetNicType) + params["Description"] = rule.Description + params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) + protocol := rule.Protocol + if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { + protocol = "all" + } + params["IpProtocol"] = protocol + if rule.PortStart < 1 && rule.PortEnd < 1 { + if protocol == "udp" || protocol == "tcp" { + params["PortRange"] = "1/65535" + } else { + params["PortRange"] = "-1/-1" + } + } + if rule.Action == secrules.SecurityRuleAllow { + params["Policy"] = "accept" + } else { + params["Policy"] = "drop" + } + params["Priority"] = fmt.Sprintf("%d", rule.Priority) + if rule.Direction == secrules.SecurityRuleIngress { + if rule.IPNet != nil { + params["SourceCidrIp"] = rule.IPNet.String() + } else { + params["SourceCidrIp"] = "0.0.0.0/0" + } + _, err := self.ecsRequest("ModifySecurityGroupRule", params) + return err + } else { // rule.Direction == secrules.SecurityRuleEgress { + //阿里云不支持出方向API接口调用 + return nil + // if rule.IPNet != nil { + // params["DestCidrIp"] = rule.IPNet.String() + // } else { + // params["DestCidrIp"] = "0.0.0.0/0" + // } + // _, err := self.ecsRequest("ModifySecurityGroupRule", params) + // return err + } +} + +func (self *SRegion) modifySecurityGroup(secGrpId string, name string, desc string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SecurityGroupId"] = secGrpId + params["SecurityGroupName"] = name + if len(desc) > 0 { + params["Description"] = desc + } + _, err := self.ecsRequest("ModifySecurityGroupAttribute", params) + return err +} + +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 + err := self.addSecurityGroupRule(secGrpId, rule) + if err != nil { + return errors.Wrapf(err, "addSecurityGroupRule %s", rule.String()) + } + } + return nil + } + return self.addSecurityGroupRule(secGrpId, rule) +} + +func (self *SRegion) addSecurityGroupRule(secGrpId string, rule secrules.SecurityRule) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SecurityGroupId"] = secGrpId + params["NicType"] = string(IntranetNicType) + params["Description"] = rule.Description + params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) + protocol := rule.Protocol + if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { + protocol = "all" + } + params["IpProtocol"] = protocol + if rule.PortStart < 1 && rule.PortEnd < 1 { + if protocol == "udp" || protocol == "tcp" { + params["PortRange"] = "1/65535" + } else { + params["PortRange"] = "-1/-1" + } + } + if rule.Action == secrules.SecurityRuleAllow { + params["Policy"] = "accept" + } else { + params["Policy"] = "drop" + } + + // 忽略地址为0.0.0.0/32这样的阿里云规则 + if rule.IPNet.IP.String() == "0.0.0.0" && rule.IPNet.String() != "0.0.0.0/0" { + return nil + } + + params["Priority"] = fmt.Sprintf("%d", rule.Priority) + if rule.Direction == secrules.SecurityRuleIngress { + if rule.IPNet != nil { + params["SourceCidrIp"] = rule.IPNet.String() + } else { + params["SourceCidrIp"] = "0.0.0.0/0" + } + _, err := self.ecsRequest("AuthorizeSecurityGroup", params) + return err + } else { // rule.Direction == secrules.SecurityRuleEgress { + if rule.IPNet != nil { + params["DestCidrIp"] = rule.IPNet.String() + } else { + params["DestCidrIp"] = "0.0.0.0/0" + } + _, err := self.ecsRequest("AuthorizeSecurityGroupEgress", params) + return err + } +} + +func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule secrules.SecurityRule) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["SecurityGroupId"] = secGrpId + params["NicType"] = string(IntranetNicType) + params["PortRange"] = fmt.Sprintf("%d/%d", rule.PortStart, rule.PortEnd) + protocol := rule.Protocol + if len(rule.Protocol) == 0 || rule.Protocol == secrules.PROTO_ANY { + protocol = "all" + } + params["IpProtocol"] = protocol + if rule.PortStart < 1 && rule.PortEnd < 1 { + if protocol == "udp" || protocol == "tcp" { + params["PortRange"] = "1/65535" + } else { + params["PortRange"] = "-1/-1" + } + } + if rule.Action == secrules.SecurityRuleAllow { + params["Policy"] = "accept" + } else { + params["Policy"] = "drop" + } + params["Priority"] = fmt.Sprintf("%d", rule.Priority) + if rule.Direction == secrules.SecurityRuleIngress { + if rule.IPNet != nil { + params["SourceCidrIp"] = rule.IPNet.String() + } else { + params["SourceCidrIp"] = "0.0.0.0/0" + } + _, err := self.ecsRequest("RevokeSecurityGroup", params) + return err + } else { // rule.Direction == secrules.SecurityRuleEgress { + if rule.IPNet != nil { + params["DestCidrIp"] = rule.IPNet.String() + } else { + params["DestCidrIp"] = "0.0.0.0/0" + } + _, err := self.ecsRequest("RevokeSecurityGroupEgress", params) + return err + } +} + +func (self *SPermission) toRule() (cloudprovider.SecurityRule, error) { + rule := cloudprovider.SecurityRule{ + SecurityRule: secrules.SecurityRule{ + Action: secrules.SecurityRuleDeny, + Direction: secrules.DIR_IN, + Priority: self.Priority, + Description: self.Description, + PortStart: -1, + PortEnd: -1, + }, + } + if strings.ToLower(self.Policy) == "accept" { + rule.Action = secrules.SecurityRuleAllow + } + + cidr := self.SourceCidrIp + if self.Direction == "egress" { + rule.Direction = secrules.DIR_OUT + cidr = self.DestCidrIp + } + + rule.ParseCIDR(cidr) + + switch strings.ToLower(self.IpProtocol) { + case "tcp", "udp", "icmp": + rule.Protocol = strings.ToLower(self.IpProtocol) + case "all": + rule.Protocol = secrules.PROTO_ANY + default: + return rule, fmt.Errorf("unsupported protocal %s", self.IpProtocol) + } + + port, ports := "", strings.Split(self.PortRange, "/") + if ports[0] == ports[1] { + if ports[0] != "-1" { + port = ports[0] + } + } else if ports[0] != "1" && ports[1] != "65535" { + port = fmt.Sprintf("%s-%s", ports[0], ports[1]) + } + err := rule.ParsePorts(port) + if err != nil { + return rule, errors.Wrapf(err, "ParsePorts(%s)", port) + } + return rule, nil +} + +func (self *SRegion) AssignSecurityGroup(secgroupId, instanceId string) error { + return self.SetSecurityGroups([]string{secgroupId}, instanceId) +} + +func (self *SRegion) SetSecurityGroups(secgroupIds []string, instanceId string) error { + params := map[string]string{"InstanceId": instanceId} + for _, secgroupId := range secgroupIds { + params["SecurityGroupId"] = secgroupId + if _, err := self.ecsRequest("JoinSecurityGroup", params); err != nil { + return err + } + } + instance, err := self.GetInstance(instanceId) + if err != nil { + return err + } + for _, _secgroupId := range instance.SecurityGroupIds.SecurityGroupId { + if !utils.IsInStringArray(_secgroupId, secgroupIds) { + if err := self.leaveSecurityGroup(_secgroupId, instanceId); err != nil { + return err + } + } + } + return nil +} + +func (self *SRegion) leaveSecurityGroup(secgroupId, instanceId string) error { + params := map[string]string{"InstanceId": instanceId, "SecurityGroupId": secgroupId} + _, err := self.ecsRequest("LeaveSecurityGroup", params) + return err +} + +func (self *SRegion) DeleteSecurityGroup(secGrpId string) error { + params := make(map[string]string) + params["SecurityGroupId"] = secGrpId + + _, err := self.ecsRequest("DeleteSecurityGroup", params) + if err != nil { + log.Errorf("Delete security group fail %s", err) + return err + } + return nil +} + +func (self *SSecurityGroup) Delete() error { + return self.vpc.region.DeleteSecurityGroup(self.SecurityGroupId) +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + for _, rule := range append(inDels, outDels...) { + err := self.vpc.region.DelSecurityGroupRule(self.SecurityGroupId, rule.SecurityRule) + if err != nil { + return errors.Wrapf(err, "DelSecurityGroupRule(Name:%s priority: %d %s)", rule.Name, rule.Priority, rule.String()) + } + } + for _, rule := range append(inAdds, outAdds...) { + err := self.vpc.region.AddSecurityGroupRules(self.SecurityGroupId, rule.SecurityRule) + if err != nil { + return errors.Wrapf(err, "AddSecurityGroupRules(priority: %d %s)", rule.Priority, rule.String()) + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/snapshot.go new file mode 100644 index 0000000000..216a1dd68c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/snapshot.go @@ -0,0 +1,219 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SnapshotStatusType string + +const ( + SnapshotStatusAccomplished SnapshotStatusType = "accomplished" + SnapshotStatusProgress SnapshotStatusType = "progressing" + SnapshotStatusFailed SnapshotStatusType = "failed" + + SnapshotTypeSystem string = "System" + SnapshotTypeData string = "Data" +) + +type SSnapshot struct { + multicloud.SResourceBase + ApsaraTags + region *SRegion + + Progress string + SnapshotId string + SnapshotName string + SourceDiskId string + SourceDiskSize int32 + SourceDiskType string + Status SnapshotStatusType + Usage string + DepartmentInfo +} + +func (self *SSnapshot) GetId() string { + return self.SnapshotId +} + +func (self *SSnapshot) GetName() string { + return self.SnapshotName +} + +func (self *SSnapshot) GetStatus() string { + if self.Status == SnapshotStatusAccomplished { + return api.SNAPSHOT_READY + } else if self.Status == SnapshotStatusProgress { + return api.SNAPSHOT_CREATING + } else { // if self.Status == SnapshotStatusFailed + return api.SNAPSHOT_FAILED + } +} + +func (self *SSnapshot) GetSizeMb() int32 { + return self.SourceDiskSize * 1024 +} + +func (self *SSnapshot) GetDiskId() string { + return self.SourceDiskId +} + +func (self *SSnapshot) GetDiskType() string { + if self.SourceDiskType == SnapshotTypeSystem { + return api.DISK_TYPE_SYS + } else if self.SourceDiskType == SnapshotTypeData { + return api.DISK_TYPE_DATA + } else { + return "" + } +} + +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) GetGlobalId() string { + return fmt.Sprintf("%s", self.SnapshotId) +} + +func (self *SSnapshot) IsEmulated() bool { + return false +} + +func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, total, err := self.GetSnapshots("", "", "", []string{}, 0, 50) + if err != nil { + return nil, err + } + for len(snapshots) < total { + var parts []SSnapshot + parts, total, err = self.GetSnapshots("", "", "", []string{}, len(snapshots), 50) + if err != nil { + return nil, err + } + snapshots = append(snapshots, parts...) + } + ret := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := 0; i < len(snapshots); i += 1 { + ret[i] = &snapshots[i] + } + return ret, nil +} + +func (self *SSnapshot) Delete() error { + if self.region == nil { + return fmt.Errorf("not init region for snapshot %s", self.SnapshotId) + } + if err := self.region.SnapshotPreDelete(self.SnapshotId); err != nil { + return err + } + return self.region.DeleteSnapshot(self.SnapshotId) +} + +func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + + if len(instanceId) > 0 { + params["InstanceId"] = instanceId + } + if len(diskId) > 0 { + params["diskId"] = diskId + } + if len(snapshotName) > 0 { + params["SnapshotName"] = snapshotName + } + if snapshotIds != nil && len(snapshotIds) > 0 { + params["SnapshotIds"] = jsonutils.Marshal(snapshotIds).String() + } + + body, err := self.ecsRequest("DescribeSnapshots", params) + if err != nil { + log.Errorf("GetSnapshots fail %s", err) + return nil, 0, err + } + + snapshots := make([]SSnapshot, 0) + if err := body.Unmarshal(&snapshots, "Snapshots", "Snapshot"); err != nil { + log.Errorf("Unmarshal snapshot details fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + for i := 0; i < len(snapshots); i += 1 { + snapshots[i].region = self + } + return snapshots, int(total), nil +} + +func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) + if err != nil { + return nil, err + } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } else if total > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return &snapshots[0], nil +} + +func (self *SRegion) DeleteSnapshot(snapshotId string) error { + params := make(map[string]string) + params["SnapshotId"] = snapshotId + _, err := self.ecsRequest("DeleteSnapshot", params) + return err +} + +// If snapshot linked images can't be delete +// delete images first -- Apsara +func (self *SRegion) SnapshotPreDelete(snapshotId string) error { + images, _, err := self.GetImagesBySnapshot(snapshotId, 0, 0) + if err != nil { + return fmt.Errorf("PreDelete get images by snapshot %s error: %s", snapshotId, err) + } + for _, image := range images { + image.storageCache = &SStoragecache{region: self} + if err := image.Delete(context.Background()); err != nil { + return fmt.Errorf("PreDelete image %s error: %s", image.GetId(), err) + } + if err := cloudprovider.WaitDeleted(&image, 3*time.Second, 300*time.Second); err != nil { + return fmt.Errorf("PreDelete waite image %s deleted error: %s", image.GetId(), err) + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/snapshot_policy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/snapshot_policy.go new file mode 100644 index 0000000000..92cab8809e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/snapshot_policy.go @@ -0,0 +1,300 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "sort" + "strconv" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSnapshotPolicyType string + +const ( + Creating SSnapshotPolicyType = "Creating" + Available SSnapshotPolicyType = "Available" + Normal SSnapshotPolicyType = "Normal" +) + +type SSnapshotPolicy struct { + multicloud.SResourceBase + ApsaraTags + region *SRegion + + AutoSnapshotPolicyName string + AutoSnapshotPolicyId string + RepeatWeekdays string + TimePoints string + RetentionDays int + Status SSnapshotPolicyType + DepartmentInfo +} + +func (self *SSnapshotPolicy) GetId() string { + return self.AutoSnapshotPolicyId +} + +func (self *SSnapshotPolicy) GetName() string { + return self.AutoSnapshotPolicyName +} + +func (self *SSnapshotPolicy) GetStatus() string { + // XXX: apsara文档与实际返回值不符 + if self.Status == Normal || self.Status == Available { + return api.SNAPSHOT_POLICY_READY + } else if self.Status == Creating { + return api.SNAPSHOT_POLICY_CREATING + } else { + return api.SNAPSHOT_POLICY_UNKNOWN + } +} + +func (self *SSnapshotPolicy) Refresh() error { + if snapshotPolicies, total, err := self.region.GetSnapshotPolicies(self.AutoSnapshotPolicyId, 0, 1); err != nil { + return err + } else if total != 1 { + return cloudprovider.ErrNotFound + } else if err := jsonutils.Update(self, snapshotPolicies[0]); err != nil { + return err + } + return nil +} + +func (self *SSnapshotPolicy) IsEmulated() bool { + return false +} + +func (self *SSnapshotPolicy) GetGlobalId() string { + return self.AutoSnapshotPolicyId +} + +func (self *SSnapshotPolicy) GetRetentionDays() int { + return self.RetentionDays +} + +func sliceAtoi(sa []string) ([]int, error) { + si := make([]int, 0, len(sa)) + for _, a := range sa { + i, err := strconv.Atoi(a) + if err != nil { + return si, err + } + si = append(si, i) + } + return si, nil +} + +func stringToIntDays(days []string) ([]int, error) { + idays, err := sliceAtoi(days) + if err != nil { + return nil, err + } + sort.Ints(idays) + return idays, nil +} + +func parsePolicy(policy string) ([]int, error) { + tp, err := jsonutils.ParseString(policy) + if err != nil { + return nil, fmt.Errorf("Parse policy %s error %s", policy, err) + } + atp, ok := tp.(*jsonutils.JSONArray) + if !ok { + return nil, fmt.Errorf("Policy %s Wrong format", tp) + } + return stringToIntDays(atp.GetStringArray()) +} + +func (self *SSnapshotPolicy) GetRepeatWeekdays() ([]int, error) { + return parsePolicy(self.RepeatWeekdays) +} + +func (self *SSnapshotPolicy) GetTimePoints() ([]int, error) { + return parsePolicy(self.TimePoints) +} + +func (self *SSnapshotPolicy) IsActivated() bool { + return true +} + +func (self *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { + snapshotPolicies, total, err := self.GetSnapshotPolicies("", 0, 50) + if err != nil { + return nil, err + } + for len(snapshotPolicies) < total { + var parts []SSnapshotPolicy + parts, total, err = self.GetSnapshotPolicies("", len(snapshotPolicies), 50) + if err != nil { + return nil, err + } + snapshotPolicies = append(snapshotPolicies, parts...) + } + ret := make([]cloudprovider.ICloudSnapshotPolicy, len(snapshotPolicies)) + for i := 0; i < len(snapshotPolicies); i += 1 { + ret[i] = &snapshotPolicies[i] + } + return ret, nil +} + +func (self *SRegion) GetSnapshotPolicies(policyId string, offset int, limit int) ([]SSnapshotPolicy, int, error) { + params := make(map[string]string) + + params["RegionId"] = self.RegionId + if limit != 0 { + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + } + + if len(policyId) > 0 { + params["AutoSnapshotPolicyId"] = policyId + } + + body, err := self.ecsRequest("DescribeAutoSnapshotPolicyEx", params) + if err != nil { + return nil, 0, fmt.Errorf("GetSnapshotPolicys fail %s", err) + } + + snapshotPolicies := make([]SSnapshotPolicy, 0) + if err := body.Unmarshal(&snapshotPolicies, "AutoSnapshotPolicies", "AutoSnapshotPolicy"); err != nil { + return nil, 0, fmt.Errorf("Unmarshal snapshot policies details fail %s", err) + } + total, _ := body.Int("TotalCount") + for i := 0; i < len(snapshotPolicies); i += 1 { + snapshotPolicies[i].region = self + } + return snapshotPolicies, int(total), nil +} + +func (self *SSnapshotPolicy) Delete() error { + if self.region == nil { + return fmt.Errorf("Not init region for snapshotPolicy %s", self.AutoSnapshotPolicyId) + } + return self.region.DeleteSnapshotPolicy(self.AutoSnapshotPolicyId) +} + +func (self *SRegion) DeleteSnapshotPolicy(snapshotPolicyId string) error { + params := make(map[string]string) + params["autoSnapshotPolicyId"] = snapshotPolicyId + params["regionId"] = self.RegionId + _, err := self.ecsRequest("DeleteAutoSnapshotPolicy", params) + return err +} + +func (self *SRegion) GetISnapshotPolicyById(snapshotPolicyId string) (cloudprovider.ICloudSnapshotPolicy, error) { + policies, _, err := self.GetSnapshotPolicies(snapshotPolicyId, 0, 1) + if err != nil { + return nil, err + } + if len(policies) == 0 { + return nil, cloudprovider.ErrNotFound + } + return &policies[0], nil +} + +func (self *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput) (string, error) { + if input.RepeatWeekdays == nil { + return "", fmt.Errorf("Can't create snapshot policy with nil repeatWeekdays") + } + if input.TimePoints == nil { + return "", fmt.Errorf("Can't create snapshot policy with nil timePoints") + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["repeatWeekdays"] = jsonutils.Marshal(input.GetStringArrayRepeatWeekdays()).String() + params["timePoints"] = jsonutils.Marshal(input.GetStringArrayTimePoints()).String() + params["retentionDays"] = strconv.Itoa(input.RetentionDays) + params["autoSnapshotPolicyName"] = input.PolicyName + if body, err := self.ecsRequest("CreateAutoSnapshotPolicy", params); err != nil { + return "", fmt.Errorf("CreateAutoSnapshotPolicy fail %s", err) + } else { + return body.GetString("AutoSnapshotPolicyId") + } +} + +func (self *SRegion) UpdateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput, snapshotPolicyId string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + if input.RetentionDays != 0 { + params["retentionDays"] = strconv.Itoa(input.RetentionDays) + } + if input.RepeatWeekdays != nil && len(input.RepeatWeekdays) != 0 { + params["repeatWeekdays"] = jsonutils.Marshal(input.GetStringArrayRepeatWeekdays()).String() + } + if input.TimePoints != nil && len(input.TimePoints) != 0 { + params["timePoints"] = jsonutils.Marshal(input.GetStringArrayTimePoints()).String() + } + _, err := self.ecsRequest("ModifyAutoSnapshotPolicyEx", params) + if err != nil { + return fmt.Errorf("ModifyAutoSnapshotPolicyEx Fail %s", err) + } + return nil +} + +//func (self *SRegion) UpdateSnapshotPolicy( +// snapshotPolicyId string, retentionDays *int, +// repeatWeekdays, timePoints *jsonutils.JSONArray, policyName string, +//) error { +// params := make(map[string]string) +// params["RegionId"] = self.RegionId +// if len(policyName) > 0 { +// params["autoSnapshotPolicyName"] = policyName +// } +// if retentionDays != nil { +// params["retentionDays"] = strconv.Itoa(*retentionDays) +// } +// if repeatWeekdays != nil { +// params["repeatWeekdays"] = repeatWeekdays.String() +// } +// if timePoints != nil { +// params["timePoints"] = timePoints.String() +// } +// _, err := self.ecsRequest("ModifyAutoSnapshotPolicyEx", params) +// if err != nil { +// return fmt.Errorf("ModifyAutoSnapshotPolicyEx Fail %s", err) +// } +// return nil +//} + +func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["autoSnapshotPolicyId"] = snapshotPolicyId + diskIds := []string{diskId} + params["diskIds"] = jsonutils.Marshal(diskIds).String() + _, err := self.ecsRequest("ApplyAutoSnapshotPolicy", params) + if err != nil { + return fmt.Errorf("ApplyAutoSnapshotPolicy Fail %s", err) + } + return nil +} + +func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { + params := make(map[string]string) + params["RegionId"] = self.RegionId + diskIds := []string{diskId} + params["diskIds"] = jsonutils.Marshal(diskIds).String() + _, err := self.ecsRequest("CancelAutoSnapshotPolicy", params) + if err != nil { + return fmt.Errorf("CancelAutoSnapshotPolicy Fail %s", err) + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/storage.go new file mode 100644 index 0000000000..d02e1a8a8b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/storage.go @@ -0,0 +1,179 @@ +// Copyright 2019 Yunion +// +// 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. + +// +// 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 apsara + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStorage struct { + multicloud.SStorageBase + ApsaraTags + zone *SZone + storageType string +} + +func (self *SStorage) GetId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetName() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetGlobalId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) +} + +func (self *SStorage) IsEmulated() bool { + return false +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SStorage) getDisks() ([]SDisk, error) { + if len(self.zone.disks) > 0 { + return self.zone.disks, nil + } + self.zone.disks = []SDisk{} + for { + part, total, err := self.zone.region.GetDisks("", self.zone.GetId(), "", nil, len(self.zone.disks), 100) + if err != nil { + return nil, errors.Wrapf(err, "GetDisks") + } + self.zone.disks = append(self.zone.disks, part...) + if len(self.zone.disks) >= total { + break + } + } + return self.zone.disks, nil +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := self.getDisks() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudDisk{} + for i := 0; i < len(disks); i += 1 { + if disks[i].Category == self.storageType { + disks[i].storage = self + ret = append(ret, &disks[i]) + } + } + return ret, nil +} + +func (self *SStorage) GetStorageType() string { + return self.storageType +} + +func (self *SStorage) GetMediumType() string { + if strings.Contains(self.storageType, "_ssd") { + return api.DISK_TYPE_SSD + } else { + return api.DISK_TYPE_ROTATE + } +} + +func (self *SStorage) GetCapacityMB() int64 { + return 0 // unlimited +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + return conf +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) Refresh() error { + // do nothing + return nil +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.zone.region.getStoragecache() +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + diskId, err := self.zone.region.CreateDisk(self.zone.ZoneId, self.storageType, conf.Name, conf.SizeGb, conf.Desc, conf.ProjectId) + 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) GetIDiskById(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 + } +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + if utils.IsInStringArray(self.storageType, self.zone.getSysDiskCategories()) { + return true + } + return false +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/storagecache.go new file mode 100644 index 0000000000..b0fc4119d4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/storagecache.go @@ -0,0 +1,324 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/aliyun/aliyun-oss-go-sdk/oss" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +type SStoragecache struct { + multicloud.SResourceBase + ApsaraTags + region *SRegion + + iimages []cloudprovider.ICloudImage +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) +} + +func (self *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) Refresh() error { + return nil +} + +func (self *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetGlobalId()) +} + +func (self *SStoragecache) IsEmulated() bool { + return false +} + +func (self *SStoragecache) getImages(owner ImageOwnerType) ([]SImage, error) { + images := make([]SImage, 0) + for { + parts, total, err := self.region.GetImages(ImageStatusType(""), owner, nil, "", len(images), 50) + if err != nil { + return nil, err + } + images = append(images, parts...) + if len(images) >= total { + break + } + } + return images, nil +} + +func (self *SStoragecache) fetchImages() error { + images := make([]SImage, 0) + for _, owner := range []ImageOwnerType{ImageOwnerSelf, ImageOwnerSystem} { + _images, err := self.getImages(owner) + if err != nil { + return errors.Wrapf(err, "GetImage(%s)", owner) + } + images = append(images, _images...) + } + 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) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + if self.iimages == nil { + err := self.fetchImages() + if err != nil { + return nil, err + } + } + return self.iimages, nil +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + img, err := self.region.GetImage(extId) + if err != nil { + return nil, err + } + img.storageCache = self + return img, nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + + if len(image.ExternalId) > 0 { + status, err := self.region.GetImageStatus(image.ExternalId) + if err != nil { + log.Errorf("GetImageStatus error %s", err) + } + log.Debugf("UploadImage: Image external ID %s exists, status %s", image.ExternalId, status) + // 不能直接删除 ImageStatusCreating 状态的image ,需要先取消importImage Task + if status == ImageStatusCreating { + err := self.region.CancelImageImportTasks() + if err != nil { + log.Errorln(err) + } + } + } + + return self.uploadImage(ctx, userCred, image, callback) +} + +func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + // first upload image to oss + s := auth.GetAdminSession(ctx, options.Options.Region) + + meta, reader, sizeByte, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false) + if err != nil { + return "", err + } + log.Infof("meta data %s", meta) + + bucketName := strings.ToLower(fmt.Sprintf("imgcache-%s-%s", self.region.GetId(), image.ImageId)) + exist, err := self.region.IBucketExist(bucketName) + if err != nil { + log.Errorf("IsBucketExist err %s", err) + return "", err + } + if !exist { + log.Debugf("Bucket %s not exists, to create ...", bucketName) + err = self.region.CreateIBucket(bucketName, "", "") + if err != nil { + log.Errorf("Create bucket error %s", err) + return "", err + } + } else { + log.Debugf("Bucket %s exists", bucketName) + } + + defer self.region.DeleteIBucket(bucketName) // remove bucket + + bucket, err := self.region.GetIBucketByName(bucketName) + if err != nil { + log.Errorf("Bucket error %s %s", bucketName, err) + return "", err + } + log.Debugf("To upload image to bucket %s ...", bucketName) + body := multicloud.NewProgress(sizeByte, 80, reader, callback) + err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeByte, "", "", nil, false) + // err = bucket.PutObject(image.ImageId, reader) + if err != nil { + log.Errorf("PutObject error %s %s", image.ImageId, err) + return "", err + } + + defer bucket.DeleteObject(context.Background(), image.ImageId) // remove object + + imageBaseName := image.ImageId + if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { + imageBaseName = fmt.Sprintf("img%s", image.ImageId) + } + imageName := imageBaseName + nameIdx := 1 + + // check image name, avoid name conflict + for { + _, err = self.region.GetImageByName(imageName) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + break + } else { + return "", err + } + } + imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) + nameIdx += 1 + } + + log.Debugf("Import image %s", imageName) + + // ensure privileges + err = self.region.GetClient().EnableImageImport() + if err != nil { + log.Errorf("fail to enable import privileges: %s", err) + return "", err + } + + task, err := self.region.ImportImage(imageName, image.OsArch, image.OsType, image.OsDistribution, bucketName, image.ImageId) + + if err != nil { + log.Errorf("ImportImage error %s %s %s", image.ImageId, bucketName, err) + return "", err + } + + // timeout: 1hour = 3600 seconds + err = self.region.waitTaskStatus(ImportImageTask, task.TaskId, TaskStatusFinished, 15*time.Second, 3600*time.Second) + if err != nil { + log.Errorf("waitTaskStatus %s", err) + return task.ImageId, err + } + + if callback != nil { + callback(100) + } + + return task.ImageId, nil +} + +func (self *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + if imageId, err := self.region.createIImage(snapshoutId, 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 + if err := cloudprovider.WaitStatus(iimage[0], cloudprovider.IMAGE_STATUS_ACTIVE, 15*time.Second, 3600*time.Second); err != nil { + return nil, err + } + return iimage[0], nil + } +} + +func (self *SRegion) CreateImage(snapshoutId, imageName, imageDesc string) (string, error) { + return self.createIImage(snapshoutId, imageName, imageDesc) +} + +func (self *SRegion) createIImage(snapshoutId, imageName, imageDesc string) (string, error) { + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["OssBucket"] = strings.ToLower(fmt.Sprintf("imgcache-%s", self.GetId())) + params["SnapshotId"] = snapshoutId + params["ImageName"] = imageName + params["Description"] = imageDesc + + if body, err := self.ecsRequest("CreateImage", params); err != nil { + log.Errorf("CreateImage fail %s", err) + return "", err + } else { + log.Infof("%s", body) + return body.GetString("ImageId") + } +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return self.downloadImage(userCred, imageId, extId, path) +} + +// 定义进度条监听器。 +type OssProgressListener struct { +} + +// 定义进度变更事件处理函数。 +func (listener *OssProgressListener) ProgressChanged(event *oss.ProgressEvent) { + switch event.EventType { + case oss.TransferStartedEvent: + log.Debugf("Transfer Started, ConsumedBytes: %d, TotalBytes %d.\n", + event.ConsumedBytes, event.TotalBytes) + case oss.TransferDataEvent: + log.Debugf("\rTransfer Data, ConsumedBytes: %d, TotalBytes %d, %d%%.", + event.ConsumedBytes, event.TotalBytes, event.ConsumedBytes*100/event.TotalBytes) + case oss.TransferCompletedEvent: + log.Debugf("\nTransfer Completed, ConsumedBytes: %d, TotalBytes %d.\n", + event.ConsumedBytes, event.TotalBytes) + case oss.TransferFailedEvent: + log.Debugf("\nTransfer Failed, ConsumedBytes: %d, TotalBytes %d.\n", + event.ConsumedBytes, event.TotalBytes) + default: + } +} + +func (self *SStoragecache) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storageCache := region.getStoragecache() + return []cloudprovider.ICloudStoragecache{storageCache}, nil +} + +func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + storageCache := region.getStoragecache() + if id == storageCache.GetGlobalId() { + return storageCache, nil + } + return nil, cloudprovider.ErrNotFound +} diff --git a/pkg/multicloud/apsara/sts.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/sts.go similarity index 100% rename from pkg/multicloud/apsara/sts.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/sts.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/tag_base.go new file mode 100644 index 0000000000..6f94f5692e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/tag_base.go @@ -0,0 +1,65 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type ApsaraTags struct { + Tags struct { + Tag []multicloud.STag + } +} + +func (self *ApsaraTags) GetTags() (map[string]string, error) { + ret := map[string]string{} + for _, tag := range self.Tags.Tag { + if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") || + strings.HasSuffix(tag.Key, "aliyun") || strings.HasPrefix(tag.Key, "acs:") { + continue + } + if len(tag.TagKey) > 0 { + ret[tag.TagKey] = tag.TagValue + } else if len(tag.Key) > 0 { + ret[tag.Key] = tag.Value + } + } + return ret, nil +} + +func (self *ApsaraTags) GetSysTags() map[string]string { + ret := map[string]string{} + for _, tag := range self.Tags.Tag { + if strings.HasPrefix(tag.TagKey, "aliyun") || strings.HasPrefix(tag.TagKey, "acs:") || + strings.HasPrefix(tag.Key, "aliyun") || strings.HasPrefix(tag.Key, "acs:") { + if len(tag.TagKey) > 0 { + ret[tag.TagKey] = tag.TagValue + } else if len(tag.Key) > 0 { + ret[tag.Key] = tag.Value + } + } + } + return ret +} + +func (self *ApsaraTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/pkg/multicloud/apsara/task.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/task.go similarity index 100% rename from pkg/multicloud/apsara/task.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/task.go diff --git a/pkg/multicloud/apsara/utils.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/utils.go similarity index 100% rename from pkg/multicloud/apsara/utils.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/utils.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/vpc.go new file mode 100644 index 0000000000..b5a97a14a0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/vpc.go @@ -0,0 +1,317 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + VpcAvailable = "Available" + VpcPending = "Pending" +) + +// "CidrBlock":"172.31.0.0/16","CreationTime":"2017-03-19T13:37:40Z","Description":"System created default VPC.","IsDefault":true,"RegionId":"cn-hongkong","Status":"Available","UserCidrs":{"UserCidr":[]},"VRouterId":"vrt-j6c00qrol733dg36iq4qj","VSwitchIds":{"VSwitchId":["vsw-j6c3gig5ub4fmi2veyrus"]},"VpcId":"vpc-j6c86z3sh8ufhgsxwme0q","VpcName":"" + +type SUserCIDRs struct { + UserCidr []string +} + +type SVSwitchIds struct { + VSwitchId []string +} + +type SVpc struct { + multicloud.SVpc + ApsaraTags + + region *SRegion + + iwires []cloudprovider.ICloudWire + + secgroups []cloudprovider.ICloudSecurityGroup + routeTables []cloudprovider.ICloudRouteTable + + CidrBlock string + CreationTime time.Time + Description string + IsDefault bool + RegionId string + Status string + UserCidrs SUserCIDRs + VRouterId string + VSwitchIds SVSwitchIds + VpcId string + VpcName string + + DepartmentInfo +} + +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) IsEmulated() bool { + return false +} + +func (self *SVpc) GetIsDefault() bool { + return self.IsDefault +} + +func (self *SVpc) GetCidrBlock() string { + return self.CidrBlock +} + +func (self *SVpc) GetStatus() string { + return strings.ToLower(self.Status) +} + +func (self *SVpc) GetCreatedAt() time.Time { + return self.CreationTime +} + +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) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetSysTags() map[string]string { + tags := self.ApsaraTags.GetSysTags() + if len(self.ResourceGroup) > 0 { + tags["ResourceGroup"] = self.ResourceGroup + } + if len(self.ResourceGroupId) > 0 { + tags["ResourceGroupId"] = self.ResourceGroupId + } + if len(self.Department) > 0 { + tags["Department"] = self.Department + } + if len(self.DepartmentName) > 0 { + tags["DepartmentName"] = self.DepartmentName + } + if len(self.ResourceGroupName) > 0 { + groupName := strings.TrimPrefix(self.ResourceGroupName, "ResourceSet(") + groupName = strings.TrimSuffix(groupName, ")") + tags["ResourceGroupName"] = groupName + } + return tags +} + +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) 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 + } + } + return nil +} + +func (self *SVpc) fetchVSwitches() error { + switches, total, err := self.region.GetVSwitches(nil, self.VpcId, 0, 50) + if err != nil { + return err + } + if total > len(switches) { + switches, _, err = self.region.GetVSwitches(nil, self.VpcId, 0, total) + if err != nil { + return err + } + } + for i := 0; i < len(switches); i += 1 { + wire := self.getWireByZoneId(switches[i].ZoneId) + switches[i].wire = wire + wire.addNetwork(&switches[i]) + } + return nil +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + if self.iwires == nil { + err := self.fetchVSwitches() + if err != nil { + return nil, err + } + } + return self.iwires, nil +} + +func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { + if self.iwires == nil { + err := self.fetchVSwitches() + 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) fetchSecurityGroups() error { + secgroups := make([]SSecurityGroup, 0) + for { + parts, total, err := self.region.GetSecurityGroups(self.VpcId, "", []string{}, len(secgroups), 50) + if err != nil { + return err + } + secgroups = append(secgroups, parts...) + if len(secgroups) >= total { + break + } + } + 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 *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) fetchRouteTables() error { + routeTables := make([]*SRouteTable, 0) + for { + parts, total, err := self.RemoteGetRouteTableList(len(routeTables), 50) + if err != nil { + return err + } + routeTables = append(routeTables, parts...) + if len(routeTables) >= total { + break + } + } + self.routeTables = make([]cloudprovider.ICloudRouteTable, len(routeTables)) + for i := 0; i < len(routeTables); i++ { + routeTables[i].vpc = self + self.routeTables[i] = routeTables[i] + } + return nil +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + if self.routeTables == nil { + err := self.fetchRouteTables() + if err != nil { + return nil, err + } + } + return self.routeTables, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotSupported +} + +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) getNatGateways() ([]SNatGetway, error) { + natgatways := make([]SNatGetway, 0) + gwTotal := -1 + for gwTotal < 0 || len(natgatways) < gwTotal { + parts, total, err := self.region.GetNatGateways(self.VpcId, "", len(natgatways), 50) + if err != nil { + return nil, err + } + if len(parts) > 0 { + natgatways = append(natgatways, parts...) + } + gwTotal = total + } + for i := 0; i < len(natgatways); i += 1 { + natgatways[i].vpc = self + } + return natgatways, nil +} + +func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { + nats := []SNatGetway{} + for { + parts, total, err := self.region.GetNatGateways(self.VpcId, "", len(nats), 50) + if err != nil { + return nil, err + } + nats = append(nats, parts...) + if len(nats) >= total { + break + } + } + inats := []cloudprovider.ICloudNatGateway{} + for i := 0; i < len(nats); i++ { + nats[i].vpc = self + inats = append(inats, &nats[i]) + } + return inats, nil +} diff --git a/pkg/multicloud/apsara/vrouter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/vrouter.go similarity index 100% rename from pkg/multicloud/apsara/vrouter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/vrouter.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/vswitch.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/vswitch.go new file mode 100644 index 0000000000..2ca4b7026b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/vswitch.go @@ -0,0 +1,272 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/util/netutils" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +// {"AvailableIpAddressCount":4091,"CidrBlock":"172.31.32.0/20","CreationTime":"2017-03-19T13:37:44Z","Description":"System created default virtual switch.","IsDefault":true,"Status":"Available","VSwitchId":"vsw-j6c3gig5ub4fmi2veyrus","VSwitchName":"","VpcId":"vpc-j6c86z3sh8ufhgsxwme0q","ZoneId":"cn-hongkong-b"} + +const ( + VSwitchPending = "Pending" + VSwitchAvailable = "Available" +) + +type SCloudResources struct { + CloudResourceSetType []string +} + +type SVSwitch struct { + multicloud.SResourceBase + ApsaraTags + wire *SWire + + AvailableIpAddressCount int + + CidrBlock string + Ipv6CidrBlock string + CreationTime time.Time + Description string + IsDefault bool + Status string + VSwitchId string + VSwitchName string + VpcId string + ZoneId string + + CloudResources SCloudResources + RouteTable SRouteTable + DepartmentInfo +} + +func (self *SVSwitch) GetId() string { + return self.VSwitchId +} + +func (self *SVSwitch) GetName() string { + if len(self.VSwitchName) > 0 { + return self.VSwitchName + } + return self.VSwitchId +} + +func (self *SVSwitch) GetGlobalId() string { + return self.VSwitchId +} + +func (self *SVSwitch) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SVSwitch) GetStatus() string { + return strings.ToLower(self.Status) +} + +func (self *SVSwitch) Refresh() error { + log.Debugf("vsiwtch refresh %s", self.VSwitchId) + new, err := self.wire.zone.region.GetVSwitchAttributes(self.VSwitchId) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SVSwitch) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SVSwitch) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String() +} + +func (self *SVSwitch) 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 *SVSwitch) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + return pref.MaskLen +} + +func (self *SVSwitch) GetGateway() string { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + return endIp.String() +} + +func (self *SVSwitch) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SVSwitch) GetIsPublic() bool { + // return self.IsDefault + return true +} + +func (self *SVSwitch) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SRegion) createVSwitch(zoneId string, vpcId string, name string, cidr string, desc string) (string, error) { + params := make(map[string]string) + params["ZoneId"] = zoneId + params["VpcId"] = vpcId + params["CidrBlock"] = cidr + params["VSwitchName"] = name + if len(desc) > 0 { + params["Description"] = desc + } + params["ClientToken"] = utils.GenRequestId(20) + + body, err := self.vpcRequest("CreateVSwitch", params) + if err != nil { + return "", err + } + return body.GetString("VSwitchId") +} + +func (self *SRegion) DeleteVSwitch(vswitchId string) error { + params := make(map[string]string) + params["VSwitchId"] = vswitchId + + _, err := self.vpcRequest("DeleteVSwitch", params) + return err +} + +func (self *SVSwitch) Delete() error { + err := self.Refresh() + if err != nil { + log.Errorf("refresh vswitch fail %s", err) + return err + } + if len(self.RouteTable.RouteTableId) > 0 && !self.RouteTable.IsSystem() { + err = self.wire.zone.region.UnassociateRouteTable(self.RouteTable.RouteTableId, self.VSwitchId) + if err != nil { + log.Errorf("unassociate routetable fail %s", err) + return err + } + } + err = self.dissociateWithSNAT() + if err != nil { + log.Errorf("fail to dissociateWithSNAT") + return err + } + err = cloudprovider.Wait(10*time.Second, 60*time.Second, func() (bool, error) { + err := self.wire.zone.region.DeleteVSwitch(self.VSwitchId) + if err != nil { + // delete network immediately after deleting vm on it + // \"Code\":\"DependencyViolation\",\"Message\":\"Specified object has dependent resources.\"} + if isError(err, "DependencyViolation") { + return false, nil + } + return false, err + } else { + return true, nil + } + }) + return err +} + +func (self *SVSwitch) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (self *SRegion) GetVSwitches(ids []string, vpcId string, offset int, limit int) ([]SVSwitch, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["RegionId"] = self.RegionId + params["PageSize"] = fmt.Sprintf("%d", limit) + params["PageNumber"] = fmt.Sprintf("%d", (offset/limit)+1) + if ids != nil && len(ids) > 0 { + params["VSwitchId"] = strings.Join(ids, ",") + } + if len(vpcId) > 0 { + params["VpcId"] = vpcId + } + + body, err := self.vpcRequest("DescribeVSwitches", params) + if err != nil { + log.Errorf("GetVSwitches fail %s", err) + return nil, 0, err + } + + switches := make([]SVSwitch, 0) + err = body.Unmarshal(&switches, "VSwitches", "VSwitch") + if err != nil { + log.Errorf("Unmarshal vswitches fail %s", err) + return nil, 0, err + } + total, _ := body.Int("TotalCount") + return switches, int(total), nil +} + +func (self *SRegion) GetVSwitchAttributes(idstr string) (*SVSwitch, error) { + params := make(map[string]string) + params["VSwitchId"] = idstr + + body, err := self.vpcRequest("DescribeVSwitchAttributes", params) + if err != nil { + log.Errorf("DescribeVSwitchAttributes fail %s", err) + return nil, err + } + if self.client.debug { + log.Debugf("%s", body.PrettyString()) + } + switches := SVSwitch{} + err = body.Unmarshal(&switches) + if err != nil { + log.Errorf("Unmarshal vswitches fail %s", err) + return nil, err + } + return &switches, nil +} + +func (vsw *SVSwitch) dissociateWithSNAT() error { + natgatways, err := vsw.wire.vpc.getNatGateways() + if err != nil { + return err + } + for i := range natgatways { + err = natgatways[i].dissociateWithVswitch(vsw.VSwitchId) + if err != nil { + return err + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/wire.go new file mode 100644 index 0000000000..7655c651b9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/wire.go @@ -0,0 +1,140 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + ApsaraTags + 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) IsEmulated() bool { + return true +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SWire) Refresh() error { + return nil +} + +func (self *SWire) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.zone.GetGlobalId()) +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SWire) addNetwork(vswitch *SVSwitch) { + 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() == vswitch.VSwitchId { + find = true + break + } + } + if !find { + self.inetworks = append(self.inetworks, vswitch) + } +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + if self.inetworks == nil { + err := self.vpc.fetchVSwitches() + if err != nil { + return nil, err + } + } + return self.inetworks, nil +} + +func (self *SWire) getNetworkById(vswitchId string) *SVSwitch { + 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].(*SVSwitch) + if network.VSwitchId == vswitchId { + return network + } + } + return nil +} + +func (self *SWire) GetBandwidth() int { + return 10000 +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + vswitchId, err := self.zone.region.createVSwitch(self.zone.ZoneId, self.vpc.VpcId, opts.Name, opts.Cidr, opts.Desc) + if err != nil { + log.Errorf("createVSwitch error %s", err) + return nil, err + } + self.inetworks = nil + vswitch := self.getNetworkById(vswitchId) + if vswitch == nil { + log.Errorf("cannot find vswitch after create????") + return nil, cloudprovider.ErrNotFound + } + return vswitch, nil +} + +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 +} diff --git a/pkg/multicloud/apsara/wrapper.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/wrapper.go similarity index 100% rename from pkg/multicloud/apsara/wrapper.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/wrapper.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/zone.go new file mode 100644 index 0000000000..f662dec5cf --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/apsara/zone.go @@ -0,0 +1,288 @@ +// Copyright 2019 Yunion +// +// 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 apsara + +import ( + "fmt" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type TChargeType string + +const ( + PrePaidInstanceChargeType TChargeType = "PrePaid" + PostPaidInstanceChargeType TChargeType = "PostPaid" + PostPaidDBInstanceChargeType TChargeType = "Postpaid" + DefaultInstanceChargeType = PostPaidInstanceChargeType +) + +type SpotStrategyType string + +const ( + NoSpotStrategy SpotStrategyType = "NoSpot" + SpotWithPriceLimitStrategy SpotStrategyType = "SpotWithPriceLimit" + SpotAsPriceGoStrategy SpotStrategyType = "SpotAsPriceGo" + DefaultSpotStrategy = NoSpotStrategy +) + +type SDedicatedHostGenerations struct { + DedicatedHostGeneration []string +} + +type SVolumeCategories struct { + VolumeCategories []string +} + +type SSupportedDataDiskCategories struct { + SupportedDataDiskCategory []string +} + +type SSupportedInstanceGenerations struct { + SupportedInstanceGeneration []string +} + +type SSupportedInstanceTypeFamilies struct { + SupportedInstanceTypeFamily []string +} + +type SSupportedInstanceTypes struct { + SupportedInstanceType []string +} + +type SSupportedNetworkTypes struct { + SupportedNetworkCategory []string +} + +type SSupportedSystemDiskCategories struct { + SupportedSystemDiskCategory []string +} + +type SResourcesInfo struct { + DataDiskCategories SSupportedDataDiskCategories + InstanceGenerations SSupportedInstanceGenerations + InstanceTypeFamilies SSupportedInstanceTypeFamilies + InstanceTypes SSupportedInstanceTypes + IoOptimized bool + NetworkTypes SSupportedNetworkTypes + SystemDiskCategories SSupportedSystemDiskCategories +} + +type SResources struct { + ResourcesInfo []SResourcesInfo +} + +type SResourceCreation struct { + ResourceTypes []string +} + +type SInstanceTypes struct { + InstanceTypes []string +} + +type SDiskCategories struct { + DiskCategories []string +} + +type SDedicatedHostTypes struct { + DedicatedHostType []string +} + +type SZone struct { + multicloud.SResourceBase + ApsaraTags + region *SRegion + + iwires []cloudprovider.ICloudWire + + host *SHost + + istorages []cloudprovider.ICloudStorage + + ZoneId string + LocalName string + DedicatedHostGenerations SDedicatedHostGenerations + AvailableVolumeCategories SVolumeCategories + /* 可供创建的具体资源,AvailableResourcesType 组成的数组 */ + AvailableResources SResources + /* 允许创建的资源类型集合 */ + AvailableResourceCreation SResourceCreation + /* 允许创建的实例规格类型 */ + AvailableInstanceTypes SInstanceTypes + /* 支持的磁盘种类集合 */ + AvailableDiskCategories SDiskCategories + AvailableDedicatedHostTypes SDedicatedHostTypes + + disks []SDisk +} + +func (self *SZone) GetId() string { + return self.ZoneId +} + +func (self *SZone) GetName() string { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_APSARA_CN, self.LocalName) +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_APSARA_EN, self.LocalName) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneId) +} + +func (self *SZone) IsEmulated() bool { + return false +} + +func (self *SZone) GetStatus() string { + if len(self.AvailableResourceCreation.ResourceTypes) == 0 || !utils.IsInStringArray("Instance", self.AvailableResourceCreation.ResourceTypes) { + return api.ZONE_SOLDOUT + } else { + return api.ZONE_ENABLE + } +} + +func (self *SZone) Refresh() error { + // do nothing + return nil +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) fetchStorages() error { + categories := self.AvailableDiskCategories.DiskCategories + // if len(self.AvailableResources.ResourcesInfo) > 0 { + // categories = self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory + // } + self.istorages = []cloudprovider.ICloudStorage{} + + for _, sc := range categories { + storage := SStorage{zone: self, storageType: sc} + self.istorages = append(self.istorages, &storage) + if sc == api.STORAGE_CLOUD_ESSD { + storage_l2 := SStorage{zone: self, storageType: api.STORAGE_CLOUD_ESSD_PL2} + self.istorages = append(self.istorages, &storage_l2) + storage_l3 := SStorage{zone: self, storageType: api.STORAGE_CLOUD_ESSD_PL3} + self.istorages = append(self.istorages, &storage_l3) + } + } + return nil +} + +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 *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "fetchStorages") + } + } + return self.istorages, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "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) getHost() *SHost { + if self.host == nil { + self.host = &SHost{zone: self} + } + return self.host +} + +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) addWire(wire *SWire) { + if self.iwires == nil { + self.iwires = make([]cloudprovider.ICloudWire, 0) + } + self.iwires = append(self.iwires, wire) +} + +func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { + return self.iwires, nil +} + +func (self *SZone) getNetworkById(vswitchId string) *SVSwitch { + 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(vswitchId) + if net != nil { + return net + } + } + return nil +} + +func (self *SZone) getSysDiskCategories() []string { + if len(self.AvailableResources.ResourcesInfo) > 0 { + if utils.IsInStringArray(api.STORAGE_CLOUD_ESSD, self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory) { + self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory = append(self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory, api.STORAGE_CLOUD_ESSD_PL2) + self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory = append(self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory, api.STORAGE_CLOUD_ESSD_PL3) + } + return self.AvailableResources.ResourcesInfo[0].SystemDiskCategories.SupportedSystemDiskCategory + } + return nil +} diff --git a/pkg/multicloud/aws/aws.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/aws.go similarity index 99% rename from pkg/multicloud/aws/aws.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/aws.go index 1c5f79ca41..f522d40430 100644 --- a/pkg/multicloud/aws/aws.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/aws.go @@ -37,8 +37,8 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" ) diff --git a/pkg/multicloud/aws/aws_request.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/aws_request.go similarity index 99% rename from pkg/multicloud/aws/aws_request.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/aws_request.go index 10f83063bc..030e041671 100644 --- a/pkg/multicloud/aws/aws_request.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/aws_request.go @@ -35,7 +35,7 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) var UnmarshalHandler = request.NamedHandler{Name: "yunion.query.Unmarshal", Fn: Unmarshal} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/bucket.go new file mode 100644 index 0000000000..81117014c3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/bucket.go @@ -0,0 +1,800 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/s3" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/s3cli" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/fileutils2" +) + +type SBucket struct { + multicloud.SBaseBucket + AwsTags + + region *SRegion + + Name string + CreationDate time.Time + Location string + + acl cloudprovider.TBucketACLType +} + +func (b *SBucket) GetProjectId() string { + return "" +} + +func (b *SBucket) GetGlobalId() string { + return b.Name +} + +func (b *SBucket) GetName() string { + return b.Name +} + +func (b *SBucket) GetLocation() string { + return b.Location +} + +func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { + return b.region +} + +func (b *SBucket) GetCreatedAt() time.Time { + return b.CreationDate +} + +func (b *SBucket) GetStorageClass() string { + return "" +} + +func s3ToCannedAcl(acls []*s3.Grant) cloudprovider.TBucketACLType { + switch { + case len(acls) == 1: + if acls[0].Grantee.URI == nil && *acls[0].Permission == s3cli.PERMISSION_FULL_CONTROL { + return cloudprovider.ACLPrivate + } + case len(acls) == 2: + for _, g := range acls { + if *g.Grantee.Type == s3cli.GRANTEE_TYPE_GROUP && *g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_AUTH_USERS && *g.Permission == s3cli.PERMISSION_READ { + return cloudprovider.ACLAuthRead + } + if *g.Grantee.Type == s3cli.GRANTEE_TYPE_GROUP && *g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && *g.Permission == s3cli.PERMISSION_READ { + return cloudprovider.ACLPublicRead + } + } + case len(acls) == 3: + for _, g := range acls { + if *g.Grantee.Type == s3cli.GRANTEE_TYPE_GROUP && *g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && *g.Permission == s3cli.PERMISSION_WRITE { + return cloudprovider.ACLPublicReadWrite + } + } + } + return cloudprovider.ACLUnknown +} + +func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + s3cli, err := b.region.GetS3Client() + if err != nil { + log.Errorf("b.region.GetS3Client fail %s", err) + return acl + } + input := &s3.GetBucketAclInput{} + input.SetBucket(b.Name) + output, err := s3cli.GetBucketAcl(input) + if err != nil { + log.Errorf("s3cli.GetBucketAcl fail %s", err) + return acl + } + return s3ToCannedAcl(output.Grants) +} + +func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error { + s3cli, err := b.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "b.region.GetS3Client") + } + input := &s3.PutBucketAclInput{} + input.SetBucket(b.Name) + input.SetACL(string(aclStr)) + _, err = s3cli.PutBucketAcl(input) + if err != nil { + return errors.Wrap(err, "PutBucketAcl") + } + return nil +} + +func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { + return []cloudprovider.SBucketAccessUrl{ + { + Url: fmt.Sprintf("https://%s.%s", b.Name, b.region.getS3Endpoint()), + Description: "bucket domain", + Primary: true, + }, + { + Url: fmt.Sprintf("https://%s/%s", b.region.getS3Endpoint(), b.Name), + Description: "s3 domain", + }, + } +} + +func (b *SBucket) GetWebsiteUrl() string { + return fmt.Sprintf("http://%s.%s", b.Name, b.region.getS3WebsiteEndpoint()) +} + +func (b *SBucket) GetStats() cloudprovider.SBucketStats { + stats, _ := cloudprovider.GetIBucketStats(b) + return stats +} + +func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { + result := cloudprovider.SListObjectResult{} + s3cli, err := b.region.GetS3Client() + if err != nil { + return result, errors.Wrap(err, "GetS3Client") + } + input := &s3.ListObjectsInput{} + input.SetBucket(b.Name) + if len(prefix) > 0 { + input.SetPrefix(prefix) + } + if len(marker) > 0 { + input.SetMarker(marker) + } + if len(delimiter) > 0 { + input.SetDelimiter(delimiter) + } + if maxCount > 0 { + input.SetMaxKeys(int64(maxCount)) + } + oResult, err := s3cli.ListObjects(input) + if err != nil { + return result, errors.Wrap(err, "ListObjects") + } + result.Objects = make([]cloudprovider.ICloudObject, 0) + for _, object := range oResult.Contents { + obj := &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + StorageClass: *object.StorageClass, + Key: *object.Key, + SizeBytes: *object.Size, + ETag: *object.ETag, + LastModified: *object.LastModified, + }, + } + result.Objects = append(result.Objects, obj) + } + if oResult.CommonPrefixes != nil { + result.CommonPrefixes = make([]cloudprovider.ICloudObject, len(oResult.CommonPrefixes)) + for i, commPrefix := range oResult.CommonPrefixes { + result.CommonPrefixes[i] = &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{Key: *commPrefix.Prefix}, + } + } + } + if oResult.IsTruncated != nil { + result.IsTruncated = *oResult.IsTruncated + } + if oResult.NextMarker != nil { + result.NextMarker = *oResult.NextMarker + } + return result, nil +} + +func (b *SBucket) PutObject(ctx context.Context, key string, body io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + if sizeBytes < 0 { + return errors.Error("content length expected") + } + s3cli, err := b.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + input := &s3.PutObjectInput{} + input.SetBucket(b.Name) + input.SetKey(key) + seeker, err := fileutils2.NewReadSeeker(body, sizeBytes) + if err != nil { + return errors.Wrap(err, "newFakeSeeker") + } + defer seeker.Close() + input.SetBody(seeker) + input.SetContentLength(sizeBytes) + if meta != nil { + metaHdr := make(map[string]*string) + for k, v := range meta { + if len(v) == 0 || len(v[0]) == 0 { + continue + } + switch http.CanonicalHeaderKey(k) { + case cloudprovider.META_HEADER_CACHE_CONTROL: + input.SetCacheControl(v[0]) + case cloudprovider.META_HEADER_CONTENT_TYPE: + input.SetContentType(v[0]) + case cloudprovider.META_HEADER_CONTENT_MD5: + input.SetContentMD5(v[0]) + case cloudprovider.META_HEADER_CONTENT_LANGUAGE: + input.SetContentLanguage(v[0]) + case cloudprovider.META_HEADER_CONTENT_ENCODING: + input.SetContentEncoding(v[0]) + case cloudprovider.META_HEADER_CONTENT_DISPOSITION: + input.SetContentDisposition(v[0]) + default: + metaHdr[k] = &v[0] + } + } + if len(metaHdr) > 0 { + input.SetMetadata(metaHdr) + } + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.SetACL(string(cannedAcl)) + if len(storageClassStr) > 0 { + input.SetStorageClass(storageClassStr) + } + _, err = s3cli.PutObjectWithContext(ctx, input) + if err != nil { + return errors.Wrap(err, "PutObjectWithContext") + } + return nil +} + +func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + s3cli, err := b.region.GetS3Client() + if err != nil { + return "", errors.Wrap(err, "GetS3Client") + } + input := &s3.CreateMultipartUploadInput{} + input.SetBucket(b.Name) + input.SetKey(key) + if meta != nil { + metaHdr := make(map[string]*string) + for k, v := range meta { + if len(v) == 0 || len(v[0]) == 0 { + continue + } + switch http.CanonicalHeaderKey(k) { + case cloudprovider.META_HEADER_CACHE_CONTROL: + input.SetCacheControl(v[0]) + case cloudprovider.META_HEADER_CONTENT_TYPE: + input.SetContentType(v[0]) + case cloudprovider.META_HEADER_CONTENT_LANGUAGE: + input.SetContentLanguage(v[0]) + case cloudprovider.META_HEADER_CONTENT_ENCODING: + input.SetContentEncoding(v[0]) + case cloudprovider.META_HEADER_CONTENT_DISPOSITION: + input.SetContentDisposition(v[0]) + default: + metaHdr[k] = &v[0] + } + } + if len(metaHdr) > 0 { + input.SetMetadata(metaHdr) + } + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.SetACL(string(cannedAcl)) + if len(storageClassStr) > 0 { + input.SetStorageClass(storageClassStr) + } + output, err := s3cli.CreateMultipartUploadWithContext(ctx, input) + if err != nil { + return "", errors.Wrap(err, "CreateMultipartUpload") + } + return *output.UploadId, nil +} + +func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, part io.Reader, partSize int64, offset, totalSize int64) (string, error) { + s3cli, err := b.region.GetS3Client() + if err != nil { + return "", errors.Wrap(err, "GetS3Client") + } + input := &s3.UploadPartInput{} + input.SetBucket(b.Name) + input.SetKey(key) + input.SetUploadId(uploadId) + input.SetPartNumber(int64(partIndex)) + seeker, err := fileutils2.NewReadSeeker(part, partSize) + if err != nil { + return "", errors.Wrap(err, "newFakeSeeker") + } + defer seeker.Close() + input.SetBody(seeker) + input.SetContentLength(partSize) + output, err := s3cli.UploadPartWithContext(ctx, input) + if err != nil { + return "", errors.Wrap(err, "UploadPartWithContext") + } + return *output.ETag, nil +} + +func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { + s3cli, err := b.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + input := &s3.CompleteMultipartUploadInput{} + input.SetBucket(b.Name) + input.SetKey(key) + input.SetUploadId(uploadId) + uploads := &s3.CompletedMultipartUpload{} + parts := make([]*s3.CompletedPart, len(partEtags)) + for i := range partEtags { + parts[i] = &s3.CompletedPart{} + parts[i].SetPartNumber(int64(i + 1)) + parts[i].SetETag(partEtags[i]) + } + uploads.SetParts(parts) + input.SetMultipartUpload(uploads) + _, err = s3cli.CompleteMultipartUploadWithContext(ctx, input) + if err != nil { + return errors.Wrap(err, "CompleteMultipartUploadWithContext") + } + return nil +} + +func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { + s3cli, err := b.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + input := &s3.AbortMultipartUploadInput{} + input.SetBucket(b.Name) + input.SetKey(key) + input.SetUploadId(uploadId) + _, err = s3cli.AbortMultipartUploadWithContext(ctx, input) + if err != nil { + return errors.Wrap(err, "AbortMultipartUploadWithContext") + } + return nil +} + +func (b *SBucket) DeleteObject(ctx context.Context, key string) error { + s3cli, err := b.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + input := &s3.DeleteObjectInput{} + input.SetBucket(b.Name) + input.SetKey(key) + _, err = s3cli.DeleteObjectWithContext(ctx, input) + if err != nil { + return errors.Wrap(err, "DeleteObject") + } + return nil +} + +func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { + s3cli, err := b.region.GetS3Client() + if err != nil { + return "", errors.Wrap(err, "GetS3Client") + } + var request *request.Request + switch method { + case "GET": + input := &s3.GetObjectInput{} + input.SetBucket(b.Name) + input.SetKey(key) + request, _ = s3cli.GetObjectRequest(input) + case "PUT": + input := &s3.PutObjectInput{} + input.SetBucket(b.Name) + input.SetKey(key) + request, _ = s3cli.PutObjectRequest(input) + case "DELETE": + input := &s3.DeleteObjectInput{} + input.SetBucket(b.Name) + input.SetKey(key) + request, _ = s3cli.DeleteObjectRequest(input) + default: + return "", errors.Error("unsupported method") + } + url, _, err := request.PresignRequest(expire) + if err != nil { + return "", errors.Wrap(err, "request.PresignRequest") + } + return url, nil +} + +func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + s3cli, err := b.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + log.Debugf("copy from %s/%s to %s/%s", srcBucket, srcKey, b.Name, destKey) + input := &s3.CopyObjectInput{} + input.SetBucket(b.Name) + input.SetKey(destKey) + input.SetCopySource(fmt.Sprintf("%s/%s", srcBucket, url.PathEscape(srcKey))) + input.SetStorageClass(storageClassStr) + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.SetACL(string(cannedAcl)) + var metaDir string + if meta != nil { + metaHdr := make(map[string]*string) + for k, v := range meta { + if len(v) == 0 || len(v[0]) == 0 { + continue + } + switch http.CanonicalHeaderKey(k) { + case cloudprovider.META_HEADER_CACHE_CONTROL: + input.SetCacheControl(v[0]) + case cloudprovider.META_HEADER_CONTENT_TYPE: + input.SetContentType(v[0]) + case cloudprovider.META_HEADER_CONTENT_LANGUAGE: + input.SetContentLanguage(v[0]) + case cloudprovider.META_HEADER_CONTENT_ENCODING: + input.SetContentEncoding(v[0]) + case cloudprovider.META_HEADER_CONTENT_DISPOSITION: + input.SetContentDisposition(v[0]) + default: + metaHdr[k] = &v[0] + } + } + if len(metaHdr) > 0 { + input.SetMetadata(metaHdr) + } + metaDir = "REPLACE" + } else { + metaDir = "COPY" + } + input.SetMetadataDirective(metaDir) + _, err = s3cli.CopyObject(input) + if err != nil { + return errors.Wrap(err, "CopyObject") + } + return nil +} + +func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { + s3cli, err := b.region.GetS3Client() + if err != nil { + return nil, errors.Wrap(err, "GetS3Client") + } + input := &s3.GetObjectInput{} + input.SetBucket(b.Name) + input.SetKey(key) + if rangeOpt != nil { + input.SetRange(rangeOpt.String()) + } + output, err := s3cli.GetObject(input) + if err != nil { + return nil, errors.Wrap(err, "GetObject") + } + return output.Body, nil +} + +func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partNumber int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { + s3cli, err := b.region.GetS3Client() + if err != nil { + return "", errors.Wrap(err, "GetS3Client") + } + input := &s3.UploadPartCopyInput{} + input.SetBucket(b.Name) + input.SetKey(key) + input.SetUploadId(uploadId) + input.SetPartNumber(int64(partNumber)) + input.SetCopySource(fmt.Sprintf("/%s/%s", srcBucket, url.PathEscape(srcKey))) + if srcLength > 0 { + input.SetCopySourceRange(fmt.Sprintf("bytes=%d-%d", srcOffset, srcOffset+srcLength-1)) + } + output, err := s3cli.UploadPartCopy(input) + if err != nil { + return "", errors.Wrap(err, "s3cli.UploadPartCopy") + } + return *output.CopyPartResult.ETag, nil +} + +func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { + s3cli, err := b.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + s3WebConf := s3.WebsiteConfiguration{} + s3WebConf.SetIndexDocument(&s3.IndexDocument{Suffix: &websitConf.Index}) + s3WebConf.SetErrorDocument(&s3.ErrorDocument{Key: &websitConf.ErrorDocument}) + input := s3.PutBucketWebsiteInput{} + input.SetBucket(b.Name) + input.SetWebsiteConfiguration(&s3WebConf) + _, err = s3cli.PutBucketWebsite(&input) + if err != nil { + return errors.Wrapf(err, "s3cli.PutBucketWebsite(%s)", jsonutils.Marshal(input).String()) + } + return nil +} + +func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { + result := cloudprovider.SBucketWebsiteConf{} + s3cli, err := b.region.GetS3Client() + if err != nil { + return result, errors.Wrap(err, "GetS3Client") + } + input := s3.GetBucketWebsiteInput{} + input.SetBucket(b.Name) + webconfResult, err := s3cli.GetBucketWebsite(&input) + if err != nil { + return result, errors.Wrapf(err, "s3cli.GetBucketWebsite(%s)", b.Name) + } + + if webconfResult.IndexDocument != nil && webconfResult.IndexDocument.Suffix != nil { + result.Index = *webconfResult.IndexDocument.Suffix + } + if webconfResult.ErrorDocument != nil && webconfResult.ErrorDocument.Key != nil { + result.ErrorDocument = *webconfResult.ErrorDocument.Key + } + result.Url = b.GetWebsiteUrl() + return result, nil +} + +func (b *SBucket) DeleteWebSiteConf() error { + s3cli, err := b.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + input := s3.DeleteBucketWebsiteInput{} + input.SetBucket(b.Name) + _, err = s3cli.DeleteBucketWebsite(&input) + if err != nil { + return errors.Wrapf(err, "s3cli.DeleteBucketWebsite(%s)", b.Name) + } + return nil +} + +func InputToAwsApiSliceString(input []string) []*string { + result := []*string{} + for i := range input { + result = append(result, &input[i]) + } + return result +} + +func InputToAwsApiInt64(input int64) *int64 { + return &input +} + +func AwsApiSliceStringToOutput(input []*string) []string { + result := []string{} + for i := range input { + if input[i] != nil { + result = append(result, *input[i]) + } else { + result = append(result, "") + } + } + return result +} + +func AwsApiInt64ToOutput(input *int64) int64 { + if input == nil { + return 0 + } + return *input +} + +func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { + s3cli, err := b.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + opts := []*s3.CORSRule{} + for i := range rules { + opts = append(opts, &s3.CORSRule{ + AllowedOrigins: InputToAwsApiSliceString(rules[i].AllowedOrigins), + AllowedMethods: InputToAwsApiSliceString(rules[i].AllowedMethods), + AllowedHeaders: InputToAwsApiSliceString(rules[i].AllowedHeaders), + MaxAgeSeconds: InputToAwsApiInt64(int64(rules[i].MaxAgeSeconds)), + ExposeHeaders: InputToAwsApiSliceString(rules[i].ExposeHeaders), + }) + } + + input := s3.PutBucketCorsInput{} + input.SetBucket(b.Name) + input.SetCORSConfiguration(&s3.CORSConfiguration{CORSRules: opts}) + _, err = s3cli.PutBucketCors(&input) + if err != nil { + return errors.Wrapf(err, "s3cli.PutBucketCors(%s)", input) + } + return nil +} + +func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { + s3cli, err := b.region.GetS3Client() + if err != nil { + return nil, errors.Wrap(err, "GetS3Client") + } + input := s3.GetBucketCorsInput{} + input.SetBucket(b.Name) + conf, err := s3cli.GetBucketCors(&input) + if err != nil { + if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") { + return nil, errors.Wrapf(err, "s3cli.GetBucketCors(%s)", b.Name) + } + } + if conf == nil { + return nil, nil + } + result := []cloudprovider.SBucketCORSRule{} + for i := range conf.CORSRules { + result = append(result, cloudprovider.SBucketCORSRule{ + AllowedOrigins: AwsApiSliceStringToOutput(conf.CORSRules[i].AllowedOrigins), + AllowedMethods: AwsApiSliceStringToOutput(conf.CORSRules[i].AllowedMethods), + AllowedHeaders: AwsApiSliceStringToOutput(conf.CORSRules[i].AllowedHeaders), + MaxAgeSeconds: int(AwsApiInt64ToOutput(conf.CORSRules[i].MaxAgeSeconds)), + ExposeHeaders: AwsApiSliceStringToOutput(conf.CORSRules[i].ExposeHeaders), + Id: strconv.Itoa(i), + }) + } + return result, nil +} + +func (b *SBucket) DeleteCORS() error { + s3cli, err := b.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + + input := s3.DeleteBucketCorsInput{} + input.SetBucket(b.Name) + _, err = s3cli.DeleteBucketCors(&input) + if err != nil { + return errors.Wrapf(err, "s3cli.DeleteBucketCors(%s)", b.Name) + } + return nil +} + +func (b *SBucket) GetTags() (map[string]string, error) { + s3cli, err := b.region.GetS3Client() + if err != nil { + return nil, errors.Wrap(err, "GetS3Client") + } + tagresult, err := s3cli.GetBucketTagging(&s3.GetBucketTaggingInput{Bucket: &b.Name}) + if err != nil { + if strings.Contains(err.Error(), "NoSuchTagSet") { + return nil, nil + } + return nil, errors.Wrapf(err, "osscli.GetBucketTagging(%s)", b.Name) + } + if tagresult == nil { + return nil, nil + } + result := map[string]string{} + for i := range tagresult.TagSet { + if tagresult.TagSet[i].Key != nil && tagresult.TagSet[i].Value != nil { + result[*tagresult.TagSet[i].Key] = *tagresult.TagSet[i].Value + } + + } + return result, nil +} + +func (b *SBucket) SetTags(tags map[string]string, replace bool) error { + if !replace { + return cloudprovider.ErrNotSupported + } + s3cli, err := b.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + + _, err = s3cli.DeleteBucketTagging(&s3.DeleteBucketTaggingInput{Bucket: &b.Name}) + if err != nil { + return errors.Wrapf(err, "DeleteBucketTagging") + } + + if len(tags) == 0 { + return nil + } + + input := s3.PutBucketTaggingInput{Tagging: &s3.Tagging{}} + input.Bucket = &b.Name + apiTagKeys := []string{} + apiTagValues := []string{} + for k, v := range tags { + apiTagKeys = append(apiTagKeys, k) + apiTagValues = append(apiTagValues, v) + + } + for i := range apiTagKeys { + input.Tagging.TagSet = append(input.Tagging.TagSet, &s3.Tag{Key: &apiTagKeys[i], Value: &apiTagValues[i]}) + } + + _, err = s3cli.PutBucketTagging(&input) + if err != nil { + return errors.Wrapf(err, "obscli.SetBucketTagging(%s)", jsonutils.Marshal(input)) + } + return nil +} + +func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { + s3cli, err := b.region.GetS3Client() + if err != nil { + return nil, errors.Wrap(err, "GetS3Client") + } + result := []cloudprovider.SBucketMultipartUploads{} + + input := s3.ListMultipartUploadsInput{} + input.SetBucket(b.Name) + keyMarker := "" + uploadIDMarker := "" + for { + if len(keyMarker) > 0 { + input.SetKeyMarker(keyMarker) + } + if len(uploadIDMarker) > 0 { + input.SetUploadIdMarker(uploadIDMarker) + } + output, err := s3cli.ListMultipartUploads(&input) + if err != nil { + return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") + } + if output == nil { + return nil, nil + } + for i := range output.Uploads { + temp := cloudprovider.SBucketMultipartUploads{} + if output.Uploads[i].Key != nil { + temp.ObjectName = *output.Uploads[i].Key + } + if output.Uploads[i].Initiator != nil { + temp.Initiator = *output.Uploads[i].Initiator.DisplayName + } + if output.Uploads[i].Initiated != nil { + temp.Initiated = *output.Uploads[i].Initiated + } + if output.Uploads[i].UploadId != nil { + temp.UploadID = *output.Uploads[i].UploadId + } + result = append(result, temp) + } + if output.NextKeyMarker != nil { + keyMarker = *output.NextKeyMarker + } + if output.NextUploadIdMarker != nil { + uploadIDMarker = *output.NextUploadIdMarker + } + + if output.IsTruncated == nil || !*output.IsTruncated { + break + } + } + + return result, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/cloudtrail.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/cloudtrail.go new file mode 100644 index 0000000000..3e20b41b2f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/cloudtrail.go @@ -0,0 +1,201 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/cloudtrail" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SEventResource struct { + // The name of the resource referenced by the event returned. These are user-created + // names whose values will depend on the environment. For example, the resource + // name might be "auto-scaling-test-group" for an Auto Scaling Group or "i-1234567" + // for an EC2 Instance. + ResourceName string `type:"string"` + + // The type of a resource referenced by the event returned. When the resource + // type cannot be determined, null is returned. Some examples of resource types + // are: Instance for EC2, Trail for CloudTrail, DBInstance for RDS, and AccessKey + // for IAM. To learn more about how to look up and filter events by the resource + // types supported for a service, see Filtering CloudTrail Events (https://docs.aws.amazon.com/awscloudtrail/latest/userguide/view-cloudtrail-events-console.html#filtering-cloudtrail-events). + ResourceType string `type:"string"` +} + +type SEvent struct { + // The AWS access key ID that was used to sign the request. If the request was + // made with temporary security credentials, this is the access key ID of the + // temporary credentials. + AccessKeyId string `type:"string"` + + // A JSON string that contains a representation of the event returned. + CloudTrailEvent string `type:"string"` + + // The CloudTrail ID of the event returned. + EventId string `type:"string"` + + // The name of the event returned. + EventName string `type:"string"` + + // The AWS service that the request was made to. + EventSource string `type:"string"` + + // The date and time of the event returned. + EventTime time.Time `type:"timestamp"` + + // Information about whether the event is a write event or a read event. + ReadOnly string `type:"string"` + + // A list of resources referenced by the event returned. + Resources []SEventResource `type:"list"` + + // A user name or role name of the requester that called the API in the event + // returned. + Username string `type:"string"` +} + +func (self *SEvent) GetName() string { + return self.EventName +} + +func (self *SEvent) GetService() string { + return self.EventSource +} + +func (self *SEvent) GetAction() string { + return self.EventName +} + +func (self *SEvent) GetResourceType() string { + return self.EventSource +} + +func (self *SEvent) GetRequestId() string { + return self.EventId +} + +func (self *SEvent) GetRequest() jsonutils.JSONObject { + obj, _ := jsonutils.Parse([]byte(self.CloudTrailEvent)) + return obj +} + +func (self *SEvent) GetAccount() string { + return fmt.Sprintf("%s(%s)", self.AccessKeyId, self.Username) +} + +func (self *SEvent) IsSuccess() bool { + return !strings.Contains(self.CloudTrailEvent, "errorMessage") +} + +func (self *SEvent) GetCreatedAt() time.Time { + return self.EventTime +} + +func (self *SRegion) getAwsCloudtrailSession() (*session.Session, error) { + session, err := self.getAwsSession() + if err != nil { + return nil, errors.Wrap(err, "client.getDefaultSession()") + } + session.ClientConfig(CLOUD_TRAIL_SERVICE_NAME) + return session, nil +} + +func (self *SRegion) LookupEvents(start, end time.Time, withReadEvent bool) ([]SEvent, error) { + s, err := self.getAwsCloudtrailSession() + if err != nil { + return nil, errors.Wrapf(err, "getAwsCloudtrailSession") + } + client := cloudtrail.New(s) + input := &cloudtrail.LookupEventsInput{LookupAttributes: []*cloudtrail.LookupAttribute{}} + if !start.IsZero() { + input.SetStartTime(start) + } + if !end.IsZero() { + input.SetEndTime(end) + } + if !withReadEvent { + readonly := "ReadOnly" + val := "false" + input.LookupAttributes = append(input.LookupAttributes, &cloudtrail.LookupAttribute{ + AttributeKey: &readonly, + AttributeValue: &val, + }) + } + events := []SEvent{} + nextToken := "" + for { + if len(nextToken) > 0 { + input.SetNextToken(nextToken) + } + var output *cloudtrail.LookupEventsOutput = nil + for { + output, err = client.LookupEvents(input) + if err != nil { + if strings.Contains(err.Error(), "ThrottlingException") { + log.Warningf("LookupEvents ThrottlingException, try after 3 seconds") + time.Sleep(time.Second * 3) + continue + } + return nil, errors.Wrapf(err, "LookupEvents(%s, %s)", start, end) + } + break + } + for i := range output.Events { + err := FillZero(output.Events[i]) + if err != nil { + return nil, errors.Wrapf(err, "FillZero") + } + event := SEvent{} + err = jsonutils.Update(&event, jsonutils.Marshal(output.Events[i])) + if err != nil { + return nil, errors.Wrapf(err, "jsonutils.Update") + } + if strings.Contains(event.CloudTrailEvent, "awsRegion") && !strings.Contains(event.CloudTrailEvent, fmt.Sprintf(`"awsRegion":"%s"`, self.RegionId)) { + continue + } + events = append(events, event) + } + nextToken = "" + if output.NextToken != nil { + nextToken = *output.NextToken + } + if len(nextToken) == 0 { + break + } + } + return events, nil +} + +func (self *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { + events, err := self.LookupEvents(start, end, withReadEvent) + if err != nil { + return nil, errors.Wrapf(err, "LookupEvents(%s, %s)", start, end) + } + ret := []cloudprovider.ICloudEvent{} + for i := range events { + ret = append(ret, &events[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance.go new file mode 100644 index 0000000000..cb91a17e4b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance.go @@ -0,0 +1,655 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBParameterGroup struct { + DBParameterGroupName string `xml:"DBParameterGroupName"` + ParameterApplyStatus string `xml:"ParameterApplyStatus"` +} + +type SOptionGroupMembership struct { + OptionGroupName string `xml:"OptionGroupName"` + Status string `xml:"Status"` +} + +type SEndpoint struct { + HostedZoneId string `xml:"HostedZoneId"` + Address string `xml:"Address"` + Port int `xml:"Port"` +} + +type SSubnetAvailabilityZone struct { + Name string `xml:"Name"` +} + +type SSubnet struct { + SubnetIdentifier string `xml:"SubnetIdentifier"` + SubnetStatus string `xml:"SubnetStatus"` + SubnetAvailabilityZone SSubnetAvailabilityZone `xml:"SubnetAvailabilityZone"` +} + +type SDBSubnetGroup struct { + VpcId string `xml:"VpcId"` + Subnets []SSubnet `xml:"Subnets>Subnet"` + SubnetGroupStatus string `xml:"SubnetGroupStatus"` + DBSubnetGroupDescription string `xml:"DBSubnetGroupDescription"` + DBSubnetGroupName string `xml:"DBSubnetGroupName"` +} + +type SVpcSecurityGroupMembership struct { + VpcSecurityGroupId string `xml:"VpcSecurityGroupId"` + Status string `xml:"Status"` +} + +type SVpcSecurityGroups struct { + VpcSecurityGroupMembership SVpcSecurityGroupMembership `xml:"VpcSecurityGroupMembership"` +} + +type SDBInstance struct { + multicloud.SDBInstanceBase + AwsTags + + region *SRegion + + AllocatedStorage int `xml:"AllocatedStorage"` + //AssociatedRoles string `xml:"AssociatedRoles"` + DBParameterGroups []SDBParameterGroup `xml:"DBParameterGroups>DBParameterGroup"` + AvailabilityZone string `xml:"AvailabilityZone"` + DBSecurityGroups string `xml:"DBSecurityGroups"` + EngineVersion string `xml:"EngineVersion"` + MasterUsername string `xml:"MasterUsername"` + InstanceCreateTime time.Time `xml:"InstanceCreateTime"` + DBInstanceClass string `xml:"DBInstanceClass"` + HttpEndpointEnabled bool `xml:"HttpEndpointEnabled"` + //ReadReplicaDBInstanceIdentifiers string `xml:"ReadReplicaDBInstanceIdentifiers"` + MonitoringInterval int `xml:"MonitoringInterval"` + DBInstanceStatus string `xml:"DBInstanceStatus"` + BackupRetentionPeriod int `xml:"BackupRetentionPeriod"` + OptionGroupMemberships []SOptionGroupMembership `xml:"OptionGroupMemberships>OptionGroupMembership"` + CACertificateIdentifier string `xml:"CACertificateIdentifier"` + DbInstancePort int `xml:"DbInstancePort"` + DbiResourceId string `xml:"DbiResourceId"` + PreferredBackupWindow string `xml:"PreferredBackupWindow"` + DeletionProtection bool `xml:"DeletionProtection"` + DBInstanceIdentifier string `xml:"DBInstanceIdentifier"` + DBInstanceArn string `xml:"DBInstanceArn"` + Endpoint SEndpoint `xml:"Endpoint"` + Engine string `xml:"Engine"` + PubliclyAccessible bool `xml:"PubliclyAccessible"` + IAMDatabaseAuthenticationEnabled bool `xml:"IAMDatabaseAuthenticationEnabled"` + PerformanceInsightsEnabled bool `xml:"PerformanceInsightsEnabled"` + DBName string `xml:"DBName"` + MultiAZ bool `xml:"MultiAZ"` + //DomainMemberships string `xml:"DomainMemberships"` + StorageEncrypted bool `xml:"StorageEncrypted"` + DBSubnetGroup SDBSubnetGroup `xml:"DBSubnetGroup"` + VpcSecurityGroups SVpcSecurityGroups `xml:"VpcSecurityGroups"` + LicenseModel string `xml:"LicenseModel"` + PreferredMaintenanceWindow string `xml:"PreferredMaintenanceWindow"` + StorageType string `xml:"StorageType"` + AutoMinorVersionUpgrade bool `xml:"AutoMinorVersionUpgrade"` + CopyTagsToSnapshot bool `xml:"CopyTagsToSnapshot"` +} + +type SDBInstances struct { + DBInstances []SDBInstance `xml:"DBInstances>DBInstance"` + Marker string `xml:"Marker"` +} + +func (rds *SDBInstance) GetName() string { + return rds.DBInstanceIdentifier +} + +func (rds *SDBInstance) GetId() string { + return rds.DbiResourceId +} + +func (rds *SDBInstance) GetGlobalId() string { + return rds.GetId() +} + +// https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/accessing-monitoring.html#Overview.DBInstance.Status +func (rds *SDBInstance) GetStatus() string { + switch rds.DBInstanceStatus { + case "creating", "backing-up": + return api.DBINSTANCE_DEPLOYING + case "available": + return api.DBINSTANCE_RUNNING + case "deleting": + return api.DBINSTANCE_DELETING + case "rebooting": + return api.DBINSTANCE_REBOOTING + default: + log.Errorf("Unknown db instance status: %s", rds.DBInstanceStatus) + return api.DBINSTANCE_UNKNOWN + } +} + +func (rds *SDBInstance) GetBillingType() string { + return billing.BILLING_TYPE_POSTPAID +} + +func (rds *SDBInstance) GetExpiredAt() time.Time { + return time.Time{} +} + +func (rds *SDBInstance) GetCreatedAt() time.Time { + return rds.InstanceCreateTime +} + +func (rds *SDBInstance) Reboot() error { + return rds.region.RebootDBInstance(rds.DBInstanceIdentifier) +} + +func (self *SDBInstance) GetCategory() string { + switch self.Engine { + case "aurora", "aurora-mysql": + return api.DBINSTANCE_TYPE_MYSQL + case "aurora-postgresql": + return api.DBINSTANCE_TYPE_POSTGRESQL + case "oracle-ee", "sqlserver-ee": + return api.AWS_DBINSTANCE_CATEGORY_ENTERPRISE_EDITION + case "oracle-se2": + return api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION_TWO + case "sqlserver-se": + return api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION + case "sqlserver-ex": + return api.AWS_DBINSTANCE_CATEGORY_EXPRESS_EDITION + case "sqlserver-web": + return api.AWS_DBINSTANCE_CATEGORY_WEB_EDITION + default: + if strings.HasPrefix(self.DBInstanceClass, "db.r") || strings.HasPrefix(self.DBInstanceClass, "db.x") || strings.HasPrefix(self.DBInstanceClass, "db.d") { + return api.AWS_DBINSTANCE_CATEGORY_MEMORY_OPTIMIZED + } + return api.AWS_DBINSTANCE_CATEGORY_GENERAL_PURPOSE + } +} + +func (rds *SDBInstance) GetStorageType() string { + return rds.StorageType +} + +func (rds *SDBInstance) GetEngine() string { + if strings.Contains(rds.Engine, "aurora") { + return api.DBINSTANCE_TYPE_AURORA + } + if strings.Contains(rds.Engine, "oracle") { + return api.DBINSTANCE_TYPE_ORACLE + } + if strings.Contains(rds.Engine, "sqlserver") { + return api.DBINSTANCE_TYPE_SQLSERVER + } + for k, v := range map[string]string{ + "mariadb": api.DBINSTANCE_TYPE_MARIADB, + "mysql": api.DBINSTANCE_TYPE_MYSQL, + "postgres": api.DBINSTANCE_TYPE_POSTGRESQL, + } { + if rds.Engine == k { + return v + } + } + return rds.Engine +} + +func (rds *SDBInstance) GetEngineVersion() string { + return rds.EngineVersion +} + +func (rds *SDBInstance) GetInstanceType() string { + return rds.DBInstanceClass +} + +func (rds *SDBInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedDBInstanceChangeConfig) error { + params := map[string]string{ + "DBInstanceIdentifier": rds.DBInstanceIdentifier, + "ApplyImmediately": "true", + } + if config.DiskSizeGB > 0 && rds.GetEngine() != api.DBINSTANCE_TYPE_AURORA { + params["AllocatedStorage"] = fmt.Sprintf("%d", config.DiskSizeGB) + } + if len(config.InstanceType) > 0 { + params["DBInstanceClass"] = config.InstanceType + } + return rds.region.rdsRequest("ModifyDBInstance", params, nil) +} + +func (rds *SDBInstance) GetVcpuCount() int { + if spec, ok := DBInstanceSpecs[rds.DBInstanceClass]; ok { + return spec.VcpuCount + } + return 0 +} + +func (rds *SDBInstance) GetVmemSizeMB() int { + if spec, ok := DBInstanceSpecs[rds.DBInstanceClass]; ok { + return spec.VmemSizeMb + } + return 0 +} + +func (rds *SDBInstance) GetDiskSizeGB() int { + return rds.AllocatedStorage +} + +func (rds *SDBInstance) GetPort() int { + return rds.Endpoint.Port +} + +func (rds *SDBInstance) GetMaintainTime() string { + return rds.PreferredMaintenanceWindow +} + +func (rds *SDBInstance) GetIVpcId() string { + return rds.DBSubnetGroup.VpcId +} + +func (rds *SDBInstance) Refresh() error { + instance, err := rds.region.GetDBInstance(rds.DbiResourceId) + if err != nil { + return err + } + rds.AwsTags = instance.AwsTags + return jsonutils.Update(rds, instance) +} + +func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { + instances, _, err := region.GetDBInstances(instanceId, "") + if err != nil { + return nil, errors.Wrap(err, "GetDBInstances") + } + + if len(instances) == 1 { + if instances[0].DbiResourceId == instanceId { + instances[0].region = region + return &instances[0], nil + } + return nil, cloudprovider.ErrNotFound + } + + if len(instances) == 0 { + return nil, cloudprovider.ErrNotFound + } + + return nil, cloudprovider.ErrDuplicateId +} + +func (rds *SDBInstance) GetZone1Id() string { + if len(rds.AvailabilityZone) > 0 { + zone, err := rds.region.getZoneById(rds.AvailabilityZone) + if err != nil { + log.Errorf("rds.GetIZoneId %s error: %v", rds.DBInstanceIdentifier, err) + return "" + } + return zone.GetGlobalId() + } + return "" +} + +func (rds *SDBInstance) GetZone2Id() string { + return "" +} + +func (rds *SDBInstance) GetZone3Id() string { + return "" +} + +func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { + accounts := []cloudprovider.ICloudDBInstanceAccount{} + if len(rds.MasterUsername) > 0 { + account := &SDBInstanceAccount{instance: rds, AccountName: rds.MasterUsername} + accounts = append(accounts, account) + } + return accounts, nil +} + +func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { + return []cloudprovider.SDBInstanceNetwork{}, nil +} + +func (rds *SDBInstance) GetInternalConnectionStr() string { + return rds.Endpoint.Address +} + +func (rds *SDBInstance) GetConnectionStr() string { + if rds.PubliclyAccessible { + return rds.Endpoint.Address + } + return "" +} + +func (rds *SDBInstance) OpenPublicConnection() error { + params := map[string]string{ + "DBInstanceIdentifier": rds.DBInstanceIdentifier, + "PubliclyAccessible": "true", + } + return rds.region.rdsRequest("ModifyDBInstance", params, nil) +} + +func (rds *SDBInstance) ClosePublicConnection() error { + params := map[string]string{ + "DBInstanceIdentifier": rds.DBInstanceIdentifier, + "PubliclyAccessible": "false", + } + return rds.region.rdsRequest("ModifyDBInstance", params, nil) +} + +func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { + parameters, err := rds.region.GetDBInstanceParameters(rds.DBParameterGroups[0].DBParameterGroupName) + if err != nil { + return nil, errors.Wrap(err, "GetDBInstanceParameters") + } + iparams := []cloudprovider.ICloudDBInstanceParameter{} + for i := 0; i < len(parameters); i++ { + parameters[i].instance = rds + iparams = append(iparams, ¶meters[i]) + } + return iparams, nil +} + +func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { + idatabases := []cloudprovider.ICloudDBInstanceDatabase{} + if len(rds.DBName) > 0 { + database := &SDBInstanceDatabase{DBName: rds.DBName} + idatabases = append(idatabases, database) + } + return idatabases, nil +} + +func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + backups, err := rds.region.GetDBInstanceSnapshots(rds.DBInstanceIdentifier, "") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudDBInstanceBackup{} + for i := range backups { + backups[i].region = rds.region + ret = append(ret, &backups[i]) + } + return ret, nil +} + +func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { + params := map[string]string{ + "DBInstanceIdentifier": rds.DBInstanceIdentifier, + "DBSnapshotIdentifier": conf.Name, + } + ret := struct { + DBSnapshot SDBInstanceSnapshot `xml:"DBSnapshot"` + }{} + err := rds.region.rdsRequest("CreateDBSnapshot", params, &ret) + if err != nil { + return "", err + } + ret.DBSnapshot.region = rds.region + cloudprovider.WaitStatus(&ret.DBSnapshot, api.DBINSTANCE_BACKUP_READY, time.Second*10, time.Hour*2) + return ret.DBSnapshot.GetGlobalId(), nil +} + +func (region *SRegion) GetDBInstances(instanceId, marker string) ([]SDBInstance, string, error) { + instances := SDBInstances{} + params := map[string]string{} + idx := 1 + if len(instanceId) > 0 { + params[fmt.Sprintf("Filters.Filter.%d.Name", idx)] = "dbi-resource-id" + params[fmt.Sprintf("Filters.Filter.%d.Values.Value.1", idx)] = instanceId + } + + if len(marker) > 0 { + params["Marker"] = marker + } + + err := region.rdsRequest("DescribeDBInstances", params, &instances) + if err != nil { + return nil, "", errors.Wrap(err, "DescribeDBInstances") + } + return instances.DBInstances, instances.Marker, nil +} + +func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { + idbinstances := []cloudprovider.ICloudDBInstance{} + instances, marker, err := region.GetDBInstances("", "") + if err != nil { + return nil, errors.Wrap(err, "GetDBInstances") + } + for i := 0; i < len(instances); i++ { + instances[i].region = region + idbinstances = append(idbinstances, &instances[i]) + } + for len(marker) > 0 { + instances, marker, err = region.GetDBInstances("", marker) + if err != nil { + return nil, errors.Wrap(err, "GetDBInstances") + } + for i := 0; i < len(instances); i++ { + instances[i].region = region + idbinstances = append(idbinstances, &instances[i]) + } + } + return idbinstances, nil +} + +func (self *SRegion) GetIDBInstanceById(id string) (cloudprovider.ICloudDBInstance, error) { + instances, _, err := self.GetDBInstances(id, "") + if err != nil { + return nil, errors.Wrap(err, "GetDBInstances") + } + + if len(instances) > 1 { + return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, id) + } + + if len(instances) == 0 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) + } + + instances[0].region = self + return &instances[0], nil +} + +func (self *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + params := map[string]string{ + "DBInstanceClass": desc.InstanceType, + "DBInstanceIdentifier": desc.Name, + "EngineVersion": desc.EngineVersion, + "MasterUsername": "admin", + } + if len(desc.Password) > 0 { + params["MasterUserPassword"] = desc.Password + } + + if desc.Engine != api.DBINSTANCE_TYPE_AURORA { + params["StorageType"] = desc.StorageType + params["AllocatedStorage"] = fmt.Sprintf("%d", desc.DiskSizeGB) + for i, sec := range desc.SecgroupIds { + params[fmt.Sprintf("VpcSecurityGroupIds.VpcSecurityGroupId.%d", i+1)] = sec + } + } + if desc.MultiAz { + params["MultiAZ"] = "true" + } + if desc.StorageType == api.STORAGE_IO1_SSD { + params["Iops"] = "3000" + } + switch desc.Engine { + case api.DBINSTANCE_TYPE_MYSQL: + params["Engine"] = "mysql" + case api.DBINSTANCE_TYPE_POSTGRESQL: + params["Engine"] = "postgres" + params["MasterUsername"] = "postgres" + case api.DBINSTANCE_TYPE_MARIADB: + params["Engine"] = "mariadb" + case api.DBINSTANCE_TYPE_SQLSERVER: + params["LicenseModel"] = "license-included" + switch desc.Category { + case api.AWS_DBINSTANCE_CATEGORY_ENTERPRISE_EDITION: + params["Engine"] = "sqlserver-ee" + case api.AWS_DBINSTANCE_CATEGORY_EXPRESS_EDITION: + params["Engine"] = "sqlserver-ex" + params["MultiAZ"] = "false" + case api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION: + params["Engine"] = "sqlserver-se" + case api.AWS_DBINSTANCE_CATEGORY_WEB_EDITION: + params["Engine"] = "sqlserver-web" + params["MultiAZ"] = "false" + default: + return nil, fmt.Errorf("invalid category %s for engine %s", desc.Category, desc.Engine) + } + case api.DBINSTANCE_TYPE_AURORA: + delete(params, "MultiAZ") + switch desc.Category { + case api.DBINSTANCE_TYPE_MYSQL: + params["Engine"] = "aurora" + if !strings.HasPrefix(desc.EngineVersion, "5.6") { + params["Engine"] = "aurora-mysql" + } + case api.DBINSTANCE_TYPE_POSTGRESQL: + params["Engine"] = "aurora-postgresql" + params["MasterUsername"] = "postgres" + default: + return nil, fmt.Errorf("invalid category %s for engine %s", desc.Category, desc.Engine) + } + case api.DBINSTANCE_TYPE_ORACLE: + params["LicenseModel"] = "bring-your-own-license" + switch desc.Category { + case api.AWS_DBINSTANCE_CATEGORY_ENTERPRISE_EDITION: + params["Engine"] = "oracle-ee" + case api.AWS_DBINSTANCE_CATEGORY_STANDARD_EDITION_TWO: + params["Engine"] = "oracle-se2" + default: + return nil, fmt.Errorf("invalid category %s for engine %s", desc.Category, desc.Engine) + } + } + i := 1 + for k, v := range desc.Tags { + params[fmt.Sprintf("Tags.Tag.%d.Key", i)] = k + params[fmt.Sprintf("Tags.Tag.%d.Value", i)] = v + i++ + } + result := struct { + DBInstance SDBInstance `xml:"DBInstance"` + }{} + result.DBInstance.region = self + return &result.DBInstance, self.rdsRequest("CreateDBInstance", params, &result) +} + +func (self *SDBInstance) Delete() error { + params := map[string]string{ + "DBInstanceIdentifier": self.DBInstanceIdentifier, + "SkipFinalSnapshot": "true", + } + return self.region.rdsRequest("DeleteDBInstance", params, nil) +} + +func (self *SRegion) RebootDBInstance(id string) error { + params := map[string]string{ + "DBInstanceIdentifier": id, + } + return self.rdsRequest("RebootDBInstance", params, nil) +} + +func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error { + oldTags, err := self.region.ListRdsResourceTags(self.DBInstanceArn) + if err != nil { + return errors.Wrapf(err, "ListRdsResourceTags") + } + added, removed := map[string]string{}, map[string]string{} + for k, v := range tags { + oldValue, ok := oldTags[k] + if !ok { + added[k] = v + } else if oldValue != v { + removed[k] = oldValue + added[k] = v + } + } + if replace { + for k, v := range oldTags { + newValue, ok := tags[k] + if !ok { + removed[k] = v + } else if v != newValue { + added[k] = newValue + removed[k] = v + } + } + } + if len(removed) > 0 { + err = self.region.RemoveRdsTagsFromResource(self.DBInstanceArn, removed) + if err != nil { + return errors.Wrapf(err, "RemoveRdsTagsFromResource %s", removed) + } + } + if len(added) > 0 { + return self.region.AddRdsTagsToResource(self.DBInstanceArn, added) + } + return nil +} + +func (self *SRegion) ListRdsResourceTags(arn string) (map[string]string, error) { + params := map[string]string{ + "ResourceName": arn, + } + tags := AwsTags{} + err := self.rdsRequest("ListTagsForResource", params, &tags) + if err != nil { + return nil, errors.Wrapf(err, "ListTagsForResource") + } + return tags.GetTags() +} + +func (self *SRegion) AddRdsTagsToResource(arn string, tags map[string]string) error { + if len(tags) == 0 { + return nil + } + params := map[string]string{ + "ResourceName": arn, + } + i := 1 + for k, v := range tags { + params[fmt.Sprintf("Tags.member.%d.Key", i)] = k + params[fmt.Sprintf("Tags.member.%d.Value", i)] = v + } + return self.rdsRequest("AddTagsToResource", params, nil) +} + +func (self *SRegion) RemoveRdsTagsFromResource(arn string, tags map[string]string) error { + if len(tags) == 0 { + return nil + } + params := map[string]string{ + "ResourceName": arn, + } + i := 1 + for k := range tags { + params[fmt.Sprintf("TagKeys.member.%d", i)] = k + } + return self.rdsRequest("RemoveTagsFromResource", params, nil) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_account.go new file mode 100644 index 0000000000..6528119b89 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_account.go @@ -0,0 +1,30 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceAccount struct { + multicloud.SDBInstanceAccountBase + instance *SDBInstance + + AccountName string +} + +func (account *SDBInstanceAccount) GetName() string { + return account.AccountName +} diff --git a/pkg/multicloud/aws/dbinstance_const.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_const.go similarity index 100% rename from pkg/multicloud/aws/dbinstance_const.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_const.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_database.go new file mode 100644 index 0000000000..5e1ab4f20c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_database.go @@ -0,0 +1,47 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceDatabase struct { + multicloud.SDBInstanceDatabaseBase + AwsTags + + DBName string +} + +func (database *SDBInstanceDatabase) GetId() string { + return database.DBName +} + +func (database *SDBInstanceDatabase) GetGlobalId() string { + return database.DBName +} + +func (database *SDBInstanceDatabase) GetName() string { + return database.DBName +} + +func (database *SDBInstanceDatabase) GetStatus() string { + return api.DBINSTANCE_DATABASE_RUNNING +} + +func (database *SDBInstanceDatabase) GetCharacterSet() string { + return "" +} diff --git a/pkg/multicloud/aws/dbinstance_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_parameter.go similarity index 100% rename from pkg/multicloud/aws/dbinstance_parameter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_parameter.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_snapshot.go new file mode 100644 index 0000000000..3f4dcb1008 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dbinstance_snapshot.go @@ -0,0 +1,194 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceSnapshot struct { + multicloud.SDBInstanceBackupBase + AwsTags + region *SRegion + + AllocatedStorage int `xml:"AllocatedStorage"` + AvailabilityZone string `xml:"AvailabilityZone"` + DbiResourceId string `xml:"DbiResourceId"` + DBInstanceIdentifier string `xml:"DBInstanceIdentifier"` + Engine string `xml:"Engine"` + VpcId string `xml:"VpcId"` + PercentProgress int `xml:"PercentProgress"` + IAMDatabaseAuthenticationEnabled bool `xml:"IAMDatabaseAuthenticationEnabled"` + DBSnapshotIdentifier string `xml:"DBSnapshotIdentifier"` + OptionGroupName string `xml:"OptionGroupName"` + EngineVersion string `xml:"EngineVersion"` + MasterUsername string `xml:"MasterUsername"` + SnapshotType string `xml:"SnapshotType"` + InstanceCreateTime time.Time `xml:"InstanceCreateTime"` + DBSnapshotArn string `xml:"DBSnapshotArn"` + Encrypted bool `xml:"Encrypted"` + Port int `xml:"Port"` + LicenseModel string `xml:"LicenseModel"` + SnapshotCreateTime time.Time `xml:"SnapshotCreateTime"` + StorageType string `xml:"StorageType"` + Status string `xml:"Status"` +} + +type SDBInstanceSnapshots struct { + Snapshots []SDBInstanceSnapshot `xml:"DBSnapshots>DBSnapshot"` + Marker string `xml:"Marker"` +} + +func (snapshot *SDBInstanceSnapshot) GetId() string { + return snapshot.DBSnapshotIdentifier +} + +func (snapshot *SDBInstanceSnapshot) GetGlobalId() string { + return snapshot.DBSnapshotIdentifier +} + +func (snapshot *SDBInstanceSnapshot) GetName() string { + return snapshot.DBSnapshotIdentifier +} + +func (snapshot *SDBInstanceSnapshot) GetEngine() string { + return snapshot.Engine +} + +func (snapshot *SDBInstanceSnapshot) GetEngineVersion() string { + return snapshot.EngineVersion +} + +func (snapshot *SDBInstanceSnapshot) GetStartTime() time.Time { + return snapshot.SnapshotCreateTime +} + +func (snapshot *SDBInstanceSnapshot) GetEndTime() time.Time { + return snapshot.SnapshotCreateTime +} + +func (snapshot *SDBInstanceSnapshot) GetBackupMode() string { + switch snapshot.SnapshotType { + case "manual": + return api.BACKUP_MODE_MANUAL + default: + return api.BACKUP_MODE_AUTOMATED + } +} + +func (snapshot *SDBInstanceSnapshot) GetStatus() string { + switch snapshot.Status { + case "available": + return api.DBINSTANCE_BACKUP_READY + default: + log.Errorf("unknown dbinstance snapshot status: %s", snapshot.Status) + return api.DBINSTANCE_BACKUP_UNKNOWN + } +} + +func (self *SDBInstanceSnapshot) Refresh() error { + snap, err := self.region.GetRdsSnapshot(self.DBSnapshotIdentifier) + if err != nil { + return err + } + return jsonutils.Update(self, snap) +} + +func (snapshot *SDBInstanceSnapshot) GetBackupSizeMb() int { + return snapshot.AllocatedStorage * 1024 +} + +func (snapshot *SDBInstanceSnapshot) GetDBNames() string { + return "" +} + +func (snapshot *SDBInstanceSnapshot) GetDBInstanceId() string { + return snapshot.DbiResourceId +} + +func (self *SDBInstanceSnapshot) Delete() error { + return self.region.DeleteRdsSnapshot(self.DBSnapshotIdentifier) +} + +func (self *SRegion) DeleteRdsSnapshot(id string) error { + params := map[string]string{ + "DBSnapshotIdentifier": id, + } + return self.rdsRequest("DeleteDBSnapshot", params, nil) +} + +func (region *SRegion) GetDBInstanceSnapshots(instanceId, backupId string) ([]SDBInstanceSnapshot, error) { + params := map[string]string{} + if len(instanceId) > 0 { + params["DBInstanceIdentifier"] = instanceId + } + if len(backupId) > 0 { + params["DBSnapshotIdentifier"] = backupId + } + ret, marker := []SDBInstanceSnapshot{}, "" + for { + snapshots := SDBInstanceSnapshots{} + params["Marker"] = marker + err := region.rdsRequest("DescribeDBSnapshots", params, &snapshots) + if err != nil { + return nil, errors.Wrap(err, "DescribeDBSnapshots") + } + ret = append(ret, snapshots.Snapshots...) + if len(snapshots.Marker) == 0 { + break + } + marker = snapshots.Marker + } + return ret, nil +} + +func (self *SRegion) GetRdsSnapshot(id string) (*SDBInstanceSnapshot, error) { + if len(id) == 0 { + return nil, cloudprovider.ErrNotFound + } + backups, err := self.GetDBInstanceSnapshots("", id) + if err != nil { + return nil, err + } + if len(backups) == 1 { + backups[0].region = self + return &backups[0], nil + } + if len(backups) == 0 { + return nil, cloudprovider.ErrNotFound + } + return nil, cloudprovider.ErrDuplicateId +} + +func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + snapshots, err := region.GetDBInstanceSnapshots("", "") + if err != nil { + return nil, errors.Wrap(err, "GetDBInstanceSnapshots") + } + isnapshots := []cloudprovider.ICloudDBInstanceBackup{} + for i := 0; i < len(snapshots); i++ { + snapshots[i].region = region + isnapshots = append(isnapshots, &snapshots[i]) + } + return isnapshots, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/disk.go new file mode 100644 index 0000000000..76f8e022e4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/disk.go @@ -0,0 +1,552 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "fmt" + "sort" + "strings" + "time" + + "github.com/aws/aws-sdk-go/service/ec2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SMountInstances struct { + MountInstance []string +} + +type SDisk struct { + storage *SStorage + multicloud.SDisk + AwsTags + + RegionId string + ZoneId string // AvailabilityZone + DiskId string // VolumeId + + DiskName string // Tag Name + Size int // Size GB + 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 + + 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) GetIops() int { + return self.Iops +} + +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 api.DISK_ALLOCATING + case "deleting": + return api.DISK_DEALLOC + case "error": + return api.DISK_ALLOC_FAILED + default: + return api.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) GetBillingType() string { + // todo: implement me + return billing.BILLING_TYPE_POSTPAID +} + +func (self *SDisk) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SDisk) GetExpiredAt() time.Time { + return self.ExpiredTime +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +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(ctx context.Context) error { + if _, err := self.storage.zone.region.GetDisk(self.DiskId); err != nil && errors.Cause(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(ctx context.Context, 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, errors.Wrap(err, "CreateSnapshot") + } else if snapshot, err := self.getSnapshot(snapshotId); err != nil { + log.Errorf("getSnapshot %s", snapshotId) + return nil, errors.Wrap(err, "getSnapshot") + } else { + snapshot.region = self.storage.zone.region + if err := cloudprovider.WaitStatus(snapshot, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil { + return nil, errors.Wrap(err, "WaitStatus.snapshot") + } + return snapshot, nil + } +} + +func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + if snapshot, err := self.getSnapshot(snapshotId); err != nil { + return nil, errors.Wrap(err, "getSnapshot") + } 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("GetSnapshots fail %s", err) + return nil, errors.Wrap(err, "GetSnapshots") + } 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(ctx context.Context, newSizeMb int64) error { + err := self.storage.zone.region.resizeDisk(self.DiskId, newSizeMb) + if err != nil { + return err + } + + return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 5*time.Second, 5*time.Second, 90*time.Second) +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return self.storage.zone.region.resetDisk(self.DiskId, snapshotId) +} + +func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) { + if len(snapshotId) == 0 { + return nil, fmt.Errorf("GetSnapshot snapshot id should not be empty.") + } + + if snapshots, total, err := self.storage.zone.region.GetSnapshots("", "", "", []string{snapshotId}, 0, 1); err != nil { + return nil, errors.Wrap(err, "GetSnapshots") + } else if total != 1 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetSnapshots") + } 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)) + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, 0, errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.DescribeVolumes(params) + if err != nil { + return nil, 0, errors.Wrap(err, "DescribeVolumes") + } + + 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 + jsonutils.Update(&disk.AwsTags.TagSet, item.Tags) + 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.Debugf("%s", err) + return nil, 0, err + } + + if disk.Device == instance.RootDeviceName { + disk.Type = api.DISK_TYPE_SYS + disk.ImageId = instance.ImageId + } else { + disk.Type = api.DISK_TYPE_DATA + } + } else { + disk.Type = api.DISK_TYPE_DATA + } + } + + disks = append(disks, disk) + } + + // 系统盘必须放在第零个位置 + sort.Slice(disks, func(i, j int) bool { + if disks[i].Type == api.DISK_TYPE_SYS { + return true + } + + if disks[j].Type != api.DISK_TYPE_SYS && disks[i].Device < disks[j].Device { + return true + } + + return false + }) + + return disks, len(disks), nil +} + +func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { + if len(diskId) == 0 { + // return nil, fmt.Errorf("GetDisk diskId should not be empty.") + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetDisk") + } + disks, total, err := self.GetDisks("", "", "", []string{diskId}, 0, 1) + if err != nil { + if strings.Contains(err.Error(), "InvalidVolume.NotFound") { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetDisks") + } else { + return nil, errors.Wrap(err, "GetDisks") + } + } + if total != 1 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetDisk") + } + 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) + log.Debugf("DeleteDisk with params: %s", params.String()) + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.DeleteVolume(params) + return err +} + +func (self *SRegion) resizeDisk(diskId string, sizeMb int64) error { + // https://docs.aws.amazon.com/zh_cn/AWSEC2/latest/UserGuide/volume_constraints.html + // MBR -> 2 TiB + // GPT -> 16 TiB + // size unit GiB + sizeGb := sizeMb / 1024 + params := &ec2.ModifyVolumeInput{} + if sizeGb > 0 { + params.SetSize(sizeGb) + } 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) + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.ModifyVolume(params) + return err +} + +func (self *SRegion) resetDisk(diskId, snapshotId string) (string, error) { + // 这里实际是回滚快照 + disk, err := self.GetDisk(diskId) + if err != nil { + log.Debugf("resetDisk %s:%s", diskId, err.Error()) + return "", err + } + + params := &ec2.CreateVolumeInput{} + if len(snapshotId) > 0 { + params.SetSnapshotId(snapshotId) + } + params.SetSize(int64(disk.Size)) + params.SetVolumeType(disk.Category) + params.SetAvailabilityZone(disk.ZoneId) + //tags, _ := disk.Tags.GetTagSpecifications() + //params.SetTagSpecifications([]*ec2.TagSpecification{tags}) + + ec2Client, err := self.getEc2Client() + if err != nil { + return "", errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.CreateVolume(params) + if err != nil { + log.Debugf("resetDisk %s: %s", params.String(), err.Error()) + return "", err + } + + // detach disk + if disk.Status == ec2.VolumeStateInUse { + err := self.DetachDisk(disk.InstanceId, diskId) + if err != nil { + log.Debugf("resetDisk %s %s: %s", disk.InstanceId, diskId, err.Error()) + return "", err + } + + err = ec2Client.WaitUntilVolumeAvailable(&ec2.DescribeVolumesInput{VolumeIds: []*string{&diskId}}) + if err != nil { + log.Debugf("resetDisk :%s", err.Error()) + return "", err + } + } + + err = self.AttachDisk(disk.InstanceId, *ret.VolumeId, disk.Device) + if err != nil { + log.Debugf("resetDisk %s %s %s: %s", disk.InstanceId, *ret.VolumeId, disk.Device, err.Error()) + return "", err + } + + // 绑定成功后删除原磁盘 + return StrVal(ret.VolumeId), self.DeleteDisk(diskId) +} + +// io1类型的卷需要指定IOPS参数,最大不超过32000。这里根据aws网站的建议值进行设置 +// io2类型的卷需要指定IOPS参数,最大不超过64000。 +// GenDiskIops Base 100, 卷每增加2G。IOPS增加1。最多到3000 iops +func GenDiskIops(diskType string, sizeGB int) int64 { + if diskType == api.STORAGE_IO1_SSD || diskType == api.STORAGE_IO2_SSD { + iops := int64(100 + sizeGB/2) + if iops < 3000 { + return iops + } else { + return 3000 + } + } + + return 0 +} + +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) + } + + if iops := GenDiskIops(category, sizeGb); iops > 0 { + params.SetIops(iops) + } + + params.SetTagSpecifications([]*ec2.TagSpecification{ec2Tags}) + + ec2Client, err := self.getEc2Client() + if err != nil { + return "", errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.CreateVolume(params) + if err != nil { + return "", err + } + + paramsWait := &ec2.DescribeVolumesInput{} + paramsWait.SetVolumeIds([]*string{ret.VolumeId}) + err = ec2Client.WaitUntilVolumeAvailable(paramsWait) + if err != nil { + return "", err + } + return StrVal(ret.VolumeId), nil +} + +func (disk *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + _, err := self.storage.zone.region.resetDisk(self.DiskId, "") + return err +} + +func (self *SDisk) GetProjectId() string { + return "" +} diff --git a/pkg/multicloud/aws/dnshostedzone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dnshostedzone.go similarity index 98% rename from pkg/multicloud/aws/dnshostedzone.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dnshostedzone.go index 825b180b3a..23f84002ae 100644 --- a/pkg/multicloud/aws/dnshostedzone.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dnshostedzone.go @@ -23,9 +23,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type HostedZoneConfig struct { @@ -40,7 +40,7 @@ type AssociatedVPC struct { type SHostedZone struct { multicloud.SResourceBase - multicloud.AwsTags + AwsTags client *SAwsClient ID string `json:"Id"` diff --git a/pkg/multicloud/aws/dnsrecordset.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dnsrecordset.go similarity index 99% rename from pkg/multicloud/aws/dnsrecordset.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dnsrecordset.go index 1781f9aae5..a2bb76493f 100644 --- a/pkg/multicloud/aws/dnsrecordset.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dnsrecordset.go @@ -25,8 +25,8 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/stringutils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type resourceRecord struct { diff --git a/pkg/multicloud/aws/dnstrafficpolicy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dnstrafficpolicy.go similarity index 100% rename from pkg/multicloud/aws/dnstrafficpolicy.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/dnstrafficpolicy.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/doc.go new file mode 100644 index 0000000000..5cfe043e11 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 aws // import "yunion.io/x/cloudmux/pkg/multicloud/aws" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/eip.go new file mode 100644 index 0000000000..ed7ab7f48c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/eip.go @@ -0,0 +1,296 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + EIP_STATUS_INUSE = "InUse" + EIP_STATUS_AVAILABLE = "Available" +) + +type SEipAddress struct { + region *SRegion + multicloud.SEipBase + AwsTags + + AllocationId string `xml:"allocationId"` + AssociationId string `xml:"associationId"` + CarrierIp string `xml:"carrierIp"` + CustomerOwnedIp string `xml:"customerOwnedIp"` + CustomerOwnedIpv4Pool string `xml:"customerOwnedIpv4Pool"` + Domain string `xml:"domain"` + InstanceId string `xml:"instanceId"` + NetworkBorderGroup string `xml:"networkBorderGroup"` + NetworkInterfaceId string `xml:"networkInterfaceId"` + NetworkInterfaceOwnerId string `xml:"networkInterfaceOwnerId"` + PrivateIpAddress string `xml:"privateIpAddress"` + PublicIp string `xml:"publicIp"` + PublicIpv4Pool string `xml:"publicIpv4Pool"` +} + +func (self *SEipAddress) GetId() string { + return self.AllocationId +} + +func (self *SEipAddress) GetName() string { + name := self.AwsTags.GetName() + if len(name) > 0 { + return name + } + return self.AllocationId +} + +func (self *SEipAddress) GetGlobalId() string { + return self.AllocationId +} + +func (self *SEipAddress) GetStatus() string { + return api.EIP_STATUS_READY +} + +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) GetIpAddr() string { + return self.PublicIp +} + +func (self *SEipAddress) GetMode() string { + if self.InstanceId == self.AllocationId { + return api.EIP_MODE_INSTANCE_PUBLICIP + } + return api.EIP_MODE_STANDALONE_EIP +} + +func (self *SEipAddress) GetAssociationType() string { + if len(self.InstanceId) > 0 { + return api.EIP_ASSOCIATE_TYPE_SERVER + } + if len(self.NetworkInterfaceId) > 0 { + net, err := self.region.GetNetworkInterface(self.NetworkInterfaceId) + if err != nil { + return "" + } + switch net.InterfaceType { + case "nat_gateway": + return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY + default: + return net.InterfaceType + } + } + return "" +} + +func (self *SEipAddress) GetAssociationExternalId() string { + if len(self.InstanceId) > 0 { + return self.InstanceId + } + if len(self.NetworkInterfaceId) > 0 { + net, err := self.region.GetNetworkInterface(self.NetworkInterfaceId) + if err != nil { + return "" + } + switch net.InterfaceType { + case "nat_gateway": + nats, err := self.region.GetNatGateways(nil, net.VpcId, net.SubnetId) + if err != nil { + return "" + } + for i := range nats { + for _, addr := range nats[i].NatGatewayAddresses { + if addr.PublicIp == self.PublicIp { + return nats[i].GetGlobalId() + } + } + } + return "" + } + } + return self.InstanceId +} + +func (self *SEipAddress) GetBandwidth() int { + return 0 +} + +func (self *SEipAddress) GetINetworkId() string { + return "" +} + +func (self *SEipAddress) GetInternetChargeType() string { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC +} + +func (self *SEipAddress) Delete() error { + return self.region.DeallocateEIP(self.AllocationId) +} + +func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { + return self.region.AssociateEip(self.AllocationId, conf.InstanceId) +} + +func (self *SEipAddress) Dissociate() error { + return self.region.DissociateEip(self.AssociationId) +} + +func (self *SEipAddress) ChangeBandwidth(bw int) error { + return self.region.UpdateEipBandwidth(self.AllocationId, bw) +} + +func (self *SRegion) GetEips(id, ip, associateId string) ([]SEipAddress, error) { + params := map[string]string{} + if len(id) > 0 { + params["AllocationId.1"] = id + } + if len(ip) > 0 { + params["PublicIp.1"] = ip + } + idx := 1 + if len(associateId) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "association-id" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = associateId + idx++ + } + result := struct { + AddressesSet []SEipAddress `xml:"addressesSet>item"` + }{} + err := self.ec2Request("DescribeAddresses", params, &result) + if err != nil { + return nil, errors.Wrapf(err, "DescribeAddresses") + } + return result.AddressesSet, nil +} + +func (self *SRegion) GetEip(id string) (*SEipAddress, error) { + eips, err := self.GetEips(id, "", "") + if err != nil { + return nil, errors.Wrapf(err, "GetEips") + } + for i := range eips { + if eips[i].GetGlobalId() == id { + eips[i].region = self + return &eips[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetEipByIpAddress(eipAddress string) (*SEipAddress, error) { + eips, err := self.GetEips("", eipAddress, "") + if err != nil { + return nil, errors.Wrapf(err, "GetEips") + } + for i := range eips { + if eips[i].GetIpAddr() == eipAddress { + eips[i].region = self + return &eips[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, eipAddress) +} + +func (self *SRegion) AllocateEIP(opts *cloudprovider.SEip) (*SEipAddress, error) { + params := map[string]string{ + "Domain": "vpc", + } + if len(opts.Name) > 0 { + params["TagSpecification.1.ResourceType"] = "elastic-ip" + params["TagSpecification.1.Tag.1.Key"] = "Name" + params["TagSpecification.1.Tag.1.Value"] = opts.Name + } + ret := SEipAddress{region: self} + err := self.ec2Request("AllocateAddress", params, &ret) + if err != nil { + return nil, errors.Wrapf(err, "AllocateAddress") + } + return &ret, nil +} + +func (self *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + eip, err := self.AllocateEIP(opts) + if err != nil { + return nil, errors.Wrapf(err, "AllocateEIP") + } + return eip, nil +} + +func (self *SRegion) DeallocateEIP(eipId string) error { + params := map[string]string{ + "AllocationId": eipId, + } + return self.ec2Request("ReleaseAddress", params, nil) +} + +func (self *SRegion) AssociateEip(eipId string, instanceId string) error { + params := map[string]string{ + "AllocationId": eipId, + "InstanceId": instanceId, + } + return self.ec2Request("AssociateAddress", params, nil) +} + +func (self *SRegion) DissociateEip(insId string) error { + params := map[string]string{ + "AssociationId": insId, + } + return self.ec2Request("DisassociateAddress", params, nil) +} + +func (self *SRegion) UpdateEipBandwidth(eipId string, bw int) error { + return cloudprovider.ErrNotSupported +} + +func (self *SEipAddress) GetBillingType() string { + return billing.BILLING_TYPE_POSTPAID +} + +func (self *SEipAddress) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SEipAddress) GetProjectId() string { + return "" +} diff --git a/pkg/multicloud/aws/elasticache_instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_instance.go similarity index 98% rename from pkg/multicloud/aws/elasticache_instance.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_instance.go index 675ba24805..0d42aba87a 100644 --- a/pkg/multicloud/aws/elasticache_instance.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_instance.go @@ -26,10 +26,10 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - billingapi "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + billingapi "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/billing" ) @@ -189,7 +189,7 @@ func (region *SRegion) DescribeCacheSubnetGroups(Id string) ([]*elasticache.Cach type SElasticache struct { multicloud.SElasticcacheBase - multicloud.AwsTags + AwsTags region *SRegion replicaGroup *elasticache.ReplicationGroup diff --git a/pkg/multicloud/aws/elasticache_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_parameter.go similarity index 96% rename from pkg/multicloud/aws/elasticache_parameter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_parameter.go index 137744c4ce..b78b02505e 100644 --- a/pkg/multicloud/aws/elasticache_parameter.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_parameter.go @@ -21,8 +21,8 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" ) func (region *SRegion) DescribeCacheParameters(parameterGroupId string) ([]*elasticache.Parameter, error) { @@ -63,7 +63,7 @@ func (region *SRegion) DescribeCacheParameters(parameterGroupId string) ([]*elas type SElasticacheParameter struct { multicloud.SElasticcacheParameterBase - multicloud.AwsTags + AwsTags parameterGroup string parameter *elasticache.Parameter } diff --git a/pkg/multicloud/aws/elasticache_snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_snapshot.go similarity index 97% rename from pkg/multicloud/aws/elasticache_snapshot.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_snapshot.go index 8db92f03b2..b3ba9797cd 100644 --- a/pkg/multicloud/aws/elasticache_snapshot.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_snapshot.go @@ -23,9 +23,9 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) func (region *SRegion) DescribeSnapshots(replicaGroupId string, snapshotName string) ([]*elasticache.Snapshot, error) { @@ -68,7 +68,7 @@ func (region *SRegion) DescribeSnapshots(replicaGroupId string, snapshotName str type SElasticacheSnapshop struct { multicloud.SElasticcacheBackupBase - multicloud.AwsTags + AwsTags region *SRegion snapshot *elasticache.Snapshot diff --git a/pkg/multicloud/aws/elasticache_user.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_user.go similarity index 95% rename from pkg/multicloud/aws/elasticache_user.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_user.go index 7934e76093..ef665b8429 100644 --- a/pkg/multicloud/aws/elasticache_user.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/elasticache_user.go @@ -19,9 +19,9 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) func (region *SRegion) DescribeUsers(engine string) ([]*elasticache.User, error) { @@ -61,7 +61,7 @@ func (region *SRegion) DescribeUsers(engine string) ([]*elasticache.User, error) type SElasticacheUser struct { multicloud.SElasticcacheAccountBase - multicloud.AwsTags + AwsTags region *SRegion user *elasticache.User } diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/host.go new file mode 100644 index 0000000000..488b62d381 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/host.go @@ -0,0 +1,288 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone +} + +func (self *SHost) GetId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) +} + +func (self *SHost) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) Refresh() error { + return nil +} + +func (self *SHost) IsEmulated() bool { + return true +} + +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, errors.Wrap(err, "GetInstances") + } + + 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) { + if len(gid) == 0 { + log.Errorf("GetIVMById guest id is empty") + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIVMById") + } + + ivms, _, err := self.zone.region.GetInstances(self.zone.ZoneId, []string{gid}, 0, 1) + if err != nil { + return nil, errors.Wrap(err, "GetInstances") + } + if len(ivms) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetInstances") + } + 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 api.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() int { + 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 api.DISK_TYPE_HYBRID +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_AWS +} + +func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) { + inst, err := self.zone.region.GetInstance(instanceId) + if err != nil { + log.Errorf("GetInstance %s: %s", instanceId, err) + return nil, errors.Wrap(err, "GetInstance") + } + inst.host = self + return inst, nil +} + +func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.InstanceType, + desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, + desc.PublicKey, desc.ExternalSecgroupId, desc.UserData, desc.Tags) + if err != nil { + return nil, errors.Wrap(err, "_createVM") + } + + vm, err := self.GetInstanceById(vmId) + if err != nil { + log.Errorf("GetInstanceById %s: %s", vmId, err) + return nil, errors.Wrap(err, "GetInstanceById") + } + + return vm, err +} + +func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo, instanceType string, + networkId, ipAddr, desc, passwd string, + dataDisks []cloudprovider.SDiskInfo, publicKey string, secgroupId string, userData string, + tags map[string]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 + var err error + keypair := "" + if len(publicKey) > 0 { + 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 %s fail %s", imgId, 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(dataDisks)+1) + disks[0].Size = img.SizeGB + if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.SizeGB { + disks[0].Size = sysDisk.SizeGB + } + disks[0].Category = sysDisk.StorageType + + for i, dataDisk := range dataDisks { + disks[i+1].Size = dataDisk.SizeGB + disks[i+1].Category = dataDisk.StorageType + } + + // 创建实例 + if len(instanceType) > 0 { + log.Debugf("Try instancetype : %s", instanceType) + vmId, err := self.zone.region.CreateInstance(name, img, instanceType, networkId, secgroupId, self.zone.ZoneId, desc, disks, ipAddr, keypair, userData, tags) + if err != nil { + log.Errorf("Failed for %s: %s", instanceType, err) + return "", fmt.Errorf("Failed to create specification %s.%s", instanceType, err.Error()) + } else { + return vmId, nil + } + } + + return "", fmt.Errorf("Failed to create, instance type should not be empty") +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SHost) GetIsMaintenance() bool { + return false +} + +func (self *SHost) GetVersion() string { + return AWS_API_VERSION +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_group.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_group.go new file mode 100644 index 0000000000..8a2821827d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_group.go @@ -0,0 +1,329 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "time" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SGroups struct { + Groups []SGroup `xml:"Groups>member"` + IsTruncated bool `xml:"IsTruncated"` + Marker string `xml:"Marker"` +} + +type SGroup struct { + client *SAwsClient + + Path string `xml:"Path"` + GroupName string `xml:"GroupName"` + GroupId string `xml:"GroupId"` + Arn string `xml:"Arn"` + CreateDate time.Time `xml:"CreateDate"` +} + +func (self *SGroup) GetName() string { + return self.GroupName +} + +func (self *SGroup) GetDescription() string { + return "" +} + +func (self *SGroup) GetGlobalId() string { + return self.GroupName +} + +func (self *SGroup) AddUser(userName string) error { + return self.client.AddUserToGroup(self.GroupName, userName) +} + +func (self *SGroup) RemoveUser(userName string) error { + return self.client.RemoveUserFromGroup(self.GroupName, userName) +} + +func (self *SGroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { + users, err := self.client.ListGroupUsers(self.GroupName) + if err != nil { + return nil, errors.Wrapf(err, "ListGroupUsers") + } + ret := []cloudprovider.IClouduser{} + for i := range users { + users[i].client = self.client + ret = append(ret, &users[i]) + } + return ret, nil +} + +func (self *SGroup) AttachSystemPolicy(policyId string) error { + return self.client.AttachGroupPolicy(self.GroupName, self.client.getIamArn(policyId)) +} + +func (self *SGroup) AttachCustomPolicy(policyId string) error { + return self.client.AttachGroupPolicy(self.GroupName, self.client.getIamArn(policyId)) +} + +func (self *SGroup) DetachSystemPolicy(policyId string) error { + return self.client.DetachGroupPolicy(self.GroupName, self.client.getIamArn(policyId)) +} + +func (self *SGroup) DetachCustomPolicy(policyId string) error { + return self.client.DetachGroupPolicy(self.GroupName, self.client.getIamArn(policyId)) +} + +func (self *SGroup) Delete() error { + return self.client.DeleteGroup(self.GroupName) +} + +func (self *SAwsClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + return self.CreateGroup(name, "") +} + +func (self *SGroup) ListPolicies() ([]SAttachedPolicy, error) { + policies := []SAttachedPolicy{} + offset := "" + for { + part, err := self.client.ListAttachedGroupPolicies(self.GroupName, offset, 1000) + if err != nil { + return nil, errors.Wrapf(err, "ListAttachedGroupPolicies") + } + for i := range part.AttachedPolicies { + part.AttachedPolicies[i].client = self.client + policies = append(policies, part.AttachedPolicies[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return policies, nil +} + +func (self *SGroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := self.ListPolicies() + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + customMaps, err := self.client.GetCustomPolicyMaps() + if err != nil { + return nil, errors.Wrapf(err, "GetCustomPolicyMaps") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + _, ok := customMaps[policies[i].PolicyName] + if !ok { + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (self *SGroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := self.ListPolicies() + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + customMaps, err := self.client.GetCustomPolicyMaps() + if err != nil { + return nil, errors.Wrapf(err, "GetCustomPolicyMaps") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + _, ok := customMaps[policies[i].PolicyName] + if ok { + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (self *SAwsClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + ret := []cloudprovider.ICloudgroup{} + offset := "" + for { + part, err := self.ListGroups(offset, 1000, "") + if err != nil { + return nil, errors.Wrapf(err, "ListGroups") + } + for i := range part.Groups { + part.Groups[i].client = self + ret = append(ret, &part.Groups[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SAwsClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + group, err := self.GetGroup(name, "", 1) + if err != nil { + return nil, errors.Wrapf(err, "GetGroup(%s)", name) + } + group.Group.client = self + return &group.Group, nil +} + +func (self *SAwsClient) ListGroupUsers(groupName string) ([]SUser, error) { + users := []SUser{} + offset := "" + for { + part, err := self.GetGroup(groupName, offset, 1000) + if err != nil { + return nil, errors.Wrap(err, "GetGroup") + } + users = append(users, part.Users...) + offset = part.Marker + if len(offset) == 0 { + break + } + } + return users, nil +} + +func (self *SAwsClient) CreateGroup(name string, path string) (*SGroup, error) { + params := map[string]string{ + "Path": "/", + "GroupName": name, + } + if len(path) > 0 { + params["Path"] = path + } + group := struct { + Group SGroup `xml:"Group"` + }{} + err := self.iamRequest("CreateGroup", params, &group) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.CreateGroup") + } + return &group.Group, nil +} + +func (self *SAwsClient) ListGroups(offset string, limit int, pathPrefix string) (*SGroups, error) { + if limit <= 0 || limit > 1000 { + limit = 1000 + } + params := map[string]string{ + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(offset) > 0 { + params["Marker"] = offset + } + if len(pathPrefix) > 0 { + params["PathPrefix"] = pathPrefix + } + groups := &SGroups{} + err := self.iamRequest("ListGroups", params, groups) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.ListGroups") + } + return groups, nil +} + +func (self *SAwsClient) DeleteGroup(name string) error { + params := map[string]string{ + "GroupName": name, + } + return self.iamRequest("DeleteGroup", params, nil) +} + +type SGroupDetails struct { + Group SGroup `xml:"Group"` + Users []SUser `xml:"Users>member"` + IsTruncated bool `xml:"IsTruncated"` + Marker string `xml:"Marker"` +} + +func (self *SAwsClient) GetGroup(name string, offset string, limit int) (*SGroupDetails, error) { + if limit <= 0 || limit > 1000 { + limit = 1000 + } + params := map[string]string{ + "GroupName": name, + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(offset) > 0 { + params["Marker"] = offset + } + group := &SGroupDetails{} + err := self.iamRequest("GetGroup", params, group) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.GetGroup") + } + return group, nil +} + +func (self *SAwsClient) ListGroupPolicies(name string, offset string, limit int) (*SPolicies, error) { + if limit <= 0 || limit > 1000 { + limit = 1000 + } + + params := map[string]string{ + "GroupName": name, + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(offset) > 0 { + params["Marker"] = offset + } + policies := &SPolicies{} + err := self.iamRequest("ListGroupPolicies", params, policies) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.ListGroupPolicies") + } + return policies, nil +} + +func (self *SAwsClient) AddUserToGroup(groupName, userName string) error { + params := map[string]string{ + "GroupName": groupName, + "UserName": userName, + } + return self.iamRequest("AddUserToGroup", params, nil) +} + +func (self *SAwsClient) RemoveUserFromGroup(groupName, userName string) error { + params := map[string]string{ + "GroupName": groupName, + "UserName": userName, + } + return self.iamRequest("RemoveUserFromGroup", params, nil) +} + +func (self *SAwsClient) AttachGroupPolicy(groupName, policyArn string) error { + params := map[string]string{ + "GroupName": groupName, + "PolicyArn": policyArn, + } + return self.iamRequest("AttachGroupPolicy", params, nil) +} + +func (self *SAwsClient) DetachGroupPolicy(groupName, policyArn string) error { + params := map[string]string{ + "GroupName": groupName, + "PolicyArn": policyArn, + } + err := self.iamRequest("DetachGroupPolicy", params, nil) + if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { + return errors.Wrap(err, "DetachGroupPolicy") + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_policy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_policy.go new file mode 100644 index 0000000000..d9101d5fca --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_policy.go @@ -0,0 +1,476 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SPolicies struct { + IsTruncated bool `xml:"IsTruncated"` + Marker string `xml:"Marker"` + Policies []SPolicy `xml:"Policies>member"` +} + +type SPolicy struct { + client *SAwsClient + + PermissionsBoundaryUsageCount int `xml:"PermissionsBoundaryUsageCount"` + PolicyName string `xml:"PolicyName"` + Description string `xml:"Description"` + DefaultVersionId string `xml:"DefaultVersionId"` + PolicyId string `xml:"PolicyId"` + Path string `xml:"Path"` + Arn string `xml:"Arn"` + IsAttachable bool `xml:"IsAttachable"` + AttachmentCount int `xml:"AttachmentCount"` + CreateDate time.Time `xml:"CreateDate"` + UpdateDate time.Time `xml:"UpdateDate"` +} + +func (self *SPolicy) GetName() string { + return self.PolicyName +} + +func (self *SPolicy) GetGlobalId() string { + return self.client.getIamCommonArn(self.Arn) +} + +func (self *SPolicy) GetDescription() string { + policy, err := self.client.GetPolicy(self.Arn) + if err != nil { + return "" + } + return policy.Description +} + +type SUserPolicies struct { + PolicyNames []string `xml:"PolicyNames>member"` + IsTruncated bool `xml:"IsTruncated"` +} + +func (self *SAwsClient) GetCustomPolicyMaps() (map[string]string, error) { + policyMaps := map[string]string{} + offset := "" + for { + part, err := self.ListPolicies(offset, 1000, false, "", "", "Local") + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + for _, policy := range part.Policies { + policyMaps[policy.PolicyName] = policy.PolicyId + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return policyMaps, nil +} + +func (self *SAwsClient) ListUserPolicies(userName string, marker string, maxItems int) (*SUserPolicies, error) { + if maxItems <= 0 || maxItems > 1000 { + maxItems = 1000 + } + params := map[string]string{ + "UserName": userName, + "MaxItems": fmt.Sprintf("%d", maxItems), + } + if len(marker) > 0 { + params["Marker"] = marker + } + policies := SUserPolicies{} + err := self.iamRequest("ListUserPolicies", params, &policies) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.ListUserPolicies") + } + return &policies, nil +} + +func (self *SPolicy) Delete() error { + return self.client.DeletePolicy(self.Arn) +} + +func (self *SPolicy) UpdateDocument(document *jsonutils.JSONDict) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SPolicy) GetDocument() (*jsonutils.JSONDict, error) { + return self.client.GetDocument(self.Arn, self.DefaultVersionId) +} + +func (self *SAwsClient) GetDocument(arn, versionId string) (*jsonutils.JSONDict, error) { + version, err := self.GetPolicyVersion(arn, versionId) + if err != nil { + return nil, errors.Wrapf(err, "GetPolicyVersion(%s, %s)", arn, versionId) + } + document, err := url.PathUnescape(version.Document) + if err != nil { + return nil, errors.Wrapf(err, "url.PathUnescape.document") + } + jsonObj, err := jsonutils.Parse([]byte(document)) + if err != nil { + return nil, errors.Wrap(err, "jsonutils.Parse") + } + return jsonObj.(*jsonutils.JSONDict), nil +} + +func (self *SAwsClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + ret := []cloudprovider.ICloudpolicy{} + marker := "" + for { + part, err := self.ListPolicies(marker, 1000, false, "", "PermissionsPolicy", "AWS") + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + for i := range part.Policies { + part.Policies[i].client = self + ret = append(ret, &part.Policies[i]) + } + marker = part.Marker + if len(marker) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SAwsClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + ret := []cloudprovider.ICloudpolicy{} + marker := "" + for { + part, err := self.ListPolicies(marker, 1000, false, "", "PermissionsPolicy", "Local") + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + for i := range part.Policies { + part.Policies[i].client = self + ret = append(ret, &part.Policies[i]) + } + marker = part.Marker + if len(marker) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +func (self *SAwsClient) ListPolicies(marker string, maxItems int, onlyAttached bool, pathPrefix string, policyUsageFilter string, scope string) (*SPolicies, error) { + if maxItems <= 0 || maxItems > 1000 { + maxItems = 1000 + } + + params := map[string]string{ + "MaxItems": fmt.Sprintf("%d", maxItems), + } + if len(marker) > 0 { + params["Marker"] = marker + } + if onlyAttached { + params["OnlyAttached"] = "true" + } + if len(pathPrefix) > 0 { + params["PathPrefix"] = pathPrefix + } + if len(policyUsageFilter) > 0 { + params["PolicyUsageFilter"] = policyUsageFilter + } + if len(scope) > 0 { + params["Scope"] = scope + } + policies := &SPolicies{} + err := self.iamRequest("ListPolicies", params, policies) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.ListPolicies") + } + return policies, nil +} + +func (self *SAwsClient) ListAttachedUserPolicies(userName string, marker string, maxItems int, pathPrefix string) (*SAttachedPolicies, error) { + if maxItems <= 0 || maxItems > 1000 { + maxItems = 1000 + } + params := map[string]string{ + "MaxItems": fmt.Sprintf("%d", maxItems), + } + if len(marker) > 0 { + params["Marker"] = marker + } + if len(pathPrefix) > 0 { + params["PathPrefix"] = pathPrefix + } + if len(userName) > 0 { + params["UserName"] = userName + } + policies := &SAttachedPolicies{} + err := self.iamRequest("ListAttachedUserPolicies", params, policies) + if err != nil { + return nil, errors.Wrap(err, "ListAttachedUserPolicies") + } + return policies, nil +} + +type SAttachedPolicies struct { + IsTruncated bool `xml:"IsTruncated"` + Marker string `xml:"Marker"` + AttachedPolicies []SAttachedPolicy `xml:"AttachedPolicies>member"` +} + +type SAttachedPolicy struct { + client *SAwsClient + + PolicyName string `xml:"PolicyName"` + PolicyArn string `xml:"PolicyArn"` +} + +func (self *SAttachedPolicy) GetGlobalId() string { + return self.client.getIamCommonArn(self.PolicyArn) +} + +func (self *SAttachedPolicy) GetName() string { + return self.PolicyName +} + +func (self *SAttachedPolicy) GetDescription() string { + return "" +} + +func (self *SAttachedPolicy) UpdateDocument(document *jsonutils.JSONDict) error { + return self.client.CreatePolicyVersion(self.PolicyArn, document.String(), true) +} + +func (self *SAttachedPolicy) GetDocument() (*jsonutils.JSONDict, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SAttachedPolicy) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SAwsClient) ListAttachedGroupPolicies(name string, marker string, maxItems int) (*SAttachedPolicies, error) { + if maxItems <= 0 || maxItems > 1000 { + maxItems = 1000 + } + + params := map[string]string{ + "GroupName": name, + "MaxItems": fmt.Sprintf("%d", maxItems), + } + if len(marker) > 0 { + params["Marker"] = marker + } + policies := &SAttachedPolicies{} + err := self.iamRequest("ListAttachedGroupPolicies", params, policies) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.ListGroupPolicies") + } + return policies, nil +} + +type SPolicyNames struct { + PolicyNames []string `xml:"PolicyNames>member"` + IsTruncated bool `xml:"IsTruncated"` +} + +func (self *SAwsClient) ListRolePolicies(roleName string, marker string, maxItems int) (*SPolicyNames, error) { + if maxItems < 1 || maxItems > 1000 { + maxItems = 1000 + } + params := map[string]string{ + "RoleName": roleName, + "MaxItems": fmt.Sprintf("%d", maxItems), + } + if len(marker) > 0 { + params["Marker"] = marker + } + names := &SPolicyNames{} + err := self.iamRequest("ListRolePolicies", params, names) + if err != nil { + return nil, errors.Wrapf(err, "ListRolePolicies") + } + return names, nil +} + +func (self *SAwsClient) ListAttachedRolePolicies(roleName string, marker string, maxItems int, pathPrefix string) (*SAttachedPolicies, error) { + if maxItems < 1 || maxItems > 1000 { + maxItems = 1000 + } + params := map[string]string{ + "RoleName": roleName, + "MaxItems": fmt.Sprintf("%d", maxItems), + } + if len(marker) > 0 { + params["marker"] = marker + } + policies := &SAttachedPolicies{} + err := self.iamRequest("ListAttachedRolePolicies", params, policies) + if err != nil { + return nil, errors.Wrapf(err, "ListAttachedRolePolicies") + } + return policies, nil +} + +func (self *SAwsClient) AttachRolePolicy(roleName, policyArn string) error { + params := map[string]string{ + "PolicyArn": policyArn, + "RoleName": roleName, + } + return self.iamRequest("AttachRolePolicy", params, nil) +} + +func (self *SAwsClient) DetachRolePolicy(roleName string, policyArn string) error { + params := map[string]string{ + "PolicyArn": policyArn, + "RoleName": roleName, + } + err := self.iamRequest("DetachRolePolicy", params, nil) + if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { + return errors.Wrap(err, "DetachRolePolicy") + } + return nil +} + +type SPolicyVersion struct { + Document string `xml:"Document"` + IsDefaultVersion bool `xml:"IsDefaultVersion"` + VersionId string `xml:"VersionId"` + CreateDate time.Time `xml:"CreateDate"` +} + +type SPolicyVersions struct { + Versions []SPolicyVersion `xml:"Versions>member"` + IsTruncated bool `xml:"IsTruncated"` + Marker string `xml:"Marker"` +} + +func (self *SAwsClient) ListPolicyVersions(marker string, maxItems int, arn string) (*SPolicyVersions, error) { + if maxItems < 1 || maxItems > 1000 { + maxItems = 1000 + } + params := map[string]string{ + "MaxItems": fmt.Sprintf("%d", maxItems), + "PolicyArn": arn, + } + if len(marker) > 0 { + params["Marker"] = marker + } + versions := &SPolicyVersions{} + err := self.iamRequest("ListPolicyVersions", params, versions) + if err != nil { + return nil, errors.Wrapf(err, "ListPolicyVersions") + } + return versions, nil +} + +func (self *SAwsClient) GetPolicyVersion(arn, versionId string) (*SPolicyVersion, error) { + params := map[string]string{ + "PolicyArn": arn, + "VersionId": versionId, + } + result := struct { + Version SPolicyVersion `xml:"PolicyVersion"` + }{} + err := self.iamRequest("GetPolicyVersion", params, &result) + if err != nil { + return nil, errors.Wrapf(err, "GetPolicyVersion") + } + return &result.Version, nil +} + +func (self *SAwsClient) GetPolicy(arn string) (*SPolicy, error) { + params := map[string]string{ + "PolicyArn": arn, + } + result := struct { + Policy SPolicy `xml:"Policy"` + }{} + err := self.iamRequest("GetPolicy", params, &result) + if err != nil { + return nil, errors.Wrapf(err, "GetPolicy") + } + return &result.Policy, nil +} + +func (self *SAwsClient) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { + policy, err := self.CreatePolicy(opts.Name, opts.Document.String(), "", opts.Desc) + if err != nil { + return nil, errors.Wrapf(err, "CreatePolicy") + } + return policy, nil +} + +func (self *SAwsClient) CreatePolicy(name, document, path, desc string) (*SPolicy, error) { + document = self.convertDocument(document) + params := map[string]string{ + "PolicyName": name, + "PolicyDocument": document, + } + if len(path) > 0 { + params["Path"] = path + } + if len(desc) > 0 { + params["Description"] = desc + } + ret := struct { + Policy SPolicy `xml:"Policy"` + }{} + err := self.iamRequest("CreatePolicy", params, &ret) + if err != nil { + return nil, errors.Wrapf(err, "CreatePolicy") + } + ret.Policy.client = self + return &ret.Policy, nil +} + +func (self *SAwsClient) DeletePolicy(arn string) error { + params := map[string]string{ + "PolicyArn": arn, + } + err := self.iamRequest("DeletePolicy", params, nil) + if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { + return err + } + return nil +} + +func (self *SAwsClient) convertDocument(document string) string { + switch self.GetAccessEnv() { + case api.CLOUD_ACCESS_ENV_AWS_GLOBAL: + return strings.ReplaceAll(document, "arn:aws-cn", "arn:aws") + default: + return strings.ReplaceAll(document, "arn:aws", "arn:aws-cn") + } +} + +func (self *SAwsClient) CreatePolicyVersion(arn, document string, isDefault bool) error { + document = self.convertDocument(document) + params := map[string]string{ + "PolicyArn": arn, + "PolicyDocument": document, + } + if isDefault { + params["SetAsDefault"] = "true" + } + return self.iamRequest("CreatePolicyVersion", params, nil) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_role.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_role.go new file mode 100644 index 0000000000..ae060213d2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_role.go @@ -0,0 +1,211 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "net/url" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +var ( + samlRole = `{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"sts:AssumeRoleWithSAML","Principal":{"Federated":"%s"},"Condition":{"StringEquals":{"SAML:aud":["%s"]}}}]}` +) + +type SRole struct { + client *SAwsClient + + Path string `xml:"Path"` + AssumeRolePolicyDocument string `xml:"AssumeRolePolicyDocument"` + MaxSessionDuration int `xml:"MaxSessionDuration"` + RoleId string `xml:"RoleId"` + RoleName string `xml:"RoleName"` + Description string `xml:"Description"` + Arn string `xml:"Arn"` + CreateDate time.Time `xml:"CreateDate"` +} + +func (self *SRole) GetGlobalId() string { + return self.Arn +} + +func (self *SRole) GetName() string { + return self.RoleName +} + +func (self *SRole) Delete() error { + return self.client.DeleteRole(self.RoleName) +} + +func (self *SRole) GetDocument() *jsonutils.JSONDict { + data, err := url.QueryUnescape(self.AssumeRolePolicyDocument) + if err != nil { + return nil + } + document, err := jsonutils.Parse([]byte(data)) + if err != nil { + return nil + } + return document.(*jsonutils.JSONDict) +} + +//[{"Action":"sts:AssumeRoleWithSAML","Condition":{"StringEquals":{"SAML:aud":"https://signin.aws.amazon.com/saml"}},"Effect":"Allow","Principal":{"Federated":"arn:aws:iam::879324515906:saml-provider/quxuan"}}] +func (self *SRole) GetSAMLProvider() string { + document := self.GetDocument() + if document != nil { + statement, err := document.GetArray("Statement") + if err == nil { + for i := range statement { + if action, _ := statement[i].GetString("Action"); action == "sts:AssumeRoleWithSAML" { + sp, _ := statement[i].GetString("Principal", "Federated") + if len(sp) > 0 { + return sp + } + } + } + } + } + return "" +} + +func (self *SRole) AttachPolicy(id string) error { + return self.client.AttachRolePolicy(self.RoleName, self.client.getIamArn(id)) +} + +func (self *SRole) DetachPolicy(id string) error { + return self.client.DetachRolePolicy(self.RoleName, self.client.getIamArn(id)) +} + +func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies := []SAttachedPolicy{} + marker := "" + for { + part, err := self.client.ListAttachedRolePolicies(self.RoleName, marker, 100, "") + if err != nil { + return nil, errors.Wrapf(err, "ListAttachedRolePolicies") + } + policies = append(policies, part.AttachedPolicies...) + marker = part.Marker + if len(marker) == 0 { + break + } + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + policies[i].client = self.client + ret = append(ret, &policies[i]) + } + return ret, nil +} + +type SRoles struct { + Roles []SRole `xml:"Roles>member"` + IsTruncated bool `xml:"IsTruncated"` + Marker string `xml:"Marker"` +} + +func (self *SAwsClient) ListRoles(offset string, limit int, prefix string) (*SRoles, error) { + if limit < 1 || limit > 1000 { + limit = 1000 + } + params := map[string]string{ + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(offset) > 0 { + params["Marker"] = offset + } + if len(prefix) > 0 { + params["PathPrefix"] = prefix + } + roles := &SRoles{} + err := self.iamRequest("ListRoles", params, roles) + if err != nil { + return nil, errors.Wrapf(err, "ListRoles") + } + return roles, nil +} + +func (self *SAwsClient) GetRole(roleName string) (*SRole, error) { + params := map[string]string{ + "RoleName": roleName, + } + result := struct { + Role SRole `xml:"Role"` + }{} + err := self.iamRequest("GetRole", params, &result) + if err != nil { + return nil, errors.Wrap(err, "GetRole") + } + return &result.Role, nil +} + +func (self *SAwsClient) DeleteRole(name string) error { + params := map[string]string{ + "RoleName": name, + } + return self.iamRequest("DeleteRole", params, nil) +} + +func (self *SAwsClient) GetICloudroles() ([]cloudprovider.ICloudrole, error) { + roles := []SRole{} + marker := "" + for { + part, err := self.ListRoles(marker, 100, "") + if err != nil { + return nil, errors.Wrapf(err, "ListRoles") + } + roles = append(roles, part.Roles...) + marker = part.Marker + if len(marker) == 0 { + break + } + } + ret := []cloudprovider.ICloudrole{} + for i := range roles { + roles[i].client = self + ret = append(ret, &roles[i]) + } + return ret, nil +} + +func (self *SAwsClient) CreateRole(opts *cloudprovider.SRoleCreateOptions) (*SRole, error) { + if len(opts.SAMLProvider) > 0 { + aud := "https://signin.amazonaws.cn/saml" + if self.GetAccessEnv() == api.CLOUD_ACCESS_ENV_AWS_GLOBAL { + aud = "https://signin.aws.amazon.com/saml" + } + params := map[string]string{ + "RoleName": opts.Name, + "Description": opts.Desc, + "AssumeRolePolicyDocument": fmt.Sprintf(samlRole, opts.SAMLProvider, aud), + } + role := struct { + Role SRole + }{} + err := self.iamRequest("CreateRole", params, &role) + if err != nil { + return nil, errors.Wrapf(err, "CreateRole") + } + role.Role.client = self + return &role.Role, nil + } + return nil, cloudprovider.ErrNotImplemented +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_user.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_user.go new file mode 100644 index 0000000000..2cb61815e0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/iam_user.go @@ -0,0 +1,399 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SUsers struct { + Users []SUser `xml:"Users>member"` + IsTruncated bool `xml:"IsTruncated"` + Marker string `xml:"Marker"` +} + +type SUser struct { + client *SAwsClient + multicloud.SBaseClouduser + + UserId string `xml:"UserId"` + Path string `xml:"Path"` + UserName string `xml:"UserName"` + Arn string `xml:"Arn"` + CreateDate time.Time `xml:"CreateDate"` + PasswordLastUsed time.Time `xml:"PasswordLastUsed"` +} + +func (user *SUser) GetEmailAddr() string { + return "" +} + +func (user *SUser) GetInviteUrl() string { + return "" +} + +func (user *SUser) AttachSystemPolicy(policyArn string) error { + return user.client.AttachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) +} + +func (user *SUser) AttachCustomPolicy(policyArn string) error { + return user.client.AttachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) +} + +func (user *SUser) DetachSystemPolicy(policyArn string) error { + return user.client.DetachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) +} + +func (user *SUser) DetachCustomPolicy(policyArn string) error { + return user.client.DetachUserPolicy(user.UserName, user.client.getIamArn(policyArn)) +} + +func (user *SUser) GetGlobalId() string { + return user.UserId +} + +func (user *SUser) GetName() string { + return user.UserName +} + +func (user *SUser) ResetPassword(password string) error { + return user.client.ResetUserPassword(user.UserName, password) +} + +func (user *SUser) IsConsoleLogin() bool { + _, err := user.client.GetLoginProfile(user.UserName) + if errors.Cause(err) == cloudprovider.ErrNotFound { + return false + } + return true +} + +func (user *SUser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + groups, err := user.ListGroups() + if err != nil { + return nil, errors.Wrapf(err, "ListGroups") + } + ret := []cloudprovider.ICloudgroup{} + for i := range groups { + groups[i].client = user.client + ret = append(ret, &groups[i]) + } + return ret, nil +} + +func (self *SUser) ListPolicies() ([]SAttachedPolicy, error) { + policies := []SAttachedPolicy{} + offset := "" + for { + part, err := self.client.ListAttachedUserPolicies(self.UserName, offset, 1000, "") + if err != nil { + return nil, errors.Wrap(err, "ListAttachedUserPolicies") + } + for i := range part.AttachedPolicies { + part.AttachedPolicies[i].client = self.client + policies = append(policies, part.AttachedPolicies[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return policies, nil +} + +func (self *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := self.ListPolicies() + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + customMaps, err := self.client.GetCustomPolicyMaps() + if err != nil { + return nil, errors.Wrapf(err, "GetCustomPolicyMaps") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + _, ok := customMaps[policies[i].PolicyName] + if !ok { + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (self *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := self.ListPolicies() + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + customMaps, err := self.client.GetCustomPolicyMaps() + if err != nil { + return nil, errors.Wrapf(err, "GetCustomPolicyMaps") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + _, ok := customMaps[policies[i].PolicyName] + if ok { + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (user *SUser) ListGroups() ([]SGroup, error) { + groups := []SGroup{} + offset := "" + for { + part, err := user.client.ListGroupsForUser(user.UserName, offset, 1000) + if err != nil { + return nil, errors.Wrap(err, "ListGroupsForUser") + } + groups = append(groups, part.Groups...) + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return groups, nil +} + +func (user *SUser) Delete() error { + groups, err := user.ListGroups() + if err != nil { + return errors.Wrapf(err, "ListGroups") + } + for _, group := range groups { + err = user.client.RemoveUserFromGroup(group.GroupName, user.UserName) + if err != nil { + return errors.Wrap(err, "RemoveUserFromGroup") + } + } + policies, err := user.ListPolicies() + if err != nil { + return errors.Wrapf(err, "ListPolicies") + } + for _, policy := range policies { + err = user.client.DetachUserPolicy(user.UserName, policy.PolicyArn) + if err != nil { + return errors.Wrap(err, "DetachPolicy") + } + } + return user.client.DeleteUser(user.UserName) +} + +func (self *SAwsClient) ListUsers(offset string, limit int, pathPrefix string) (*SUsers, error) { + if limit <= 0 || limit > 1000 { + limit = 1000 + } + params := map[string]string{ + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(offset) > 0 { + params["Marker"] = offset + } + if len(pathPrefix) > 0 { + params["PathPrefix"] = pathPrefix + } + users := &SUsers{} + err := self.iamRequest("ListUsers", params, users) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.ListUsers") + } + return users, nil +} + +func (self *SAwsClient) CreateUser(path string, username string) (*SUser, error) { + params := map[string]string{ + "UserName": username, + } + if len(path) > 0 { + params["Path"] = path + } + user := struct { + User SUser `xml:"User"` + }{} + err := self.iamRequest("CreateUser", params, &user) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.CreateUser") + } + user.User.client = self + return &user.User, nil +} + +func (self *SAwsClient) DeleteUser(name string) error { + self.DeleteLoginProfile(name) + params := map[string]string{ + "UserName": name, + } + return self.iamRequest("DeleteUser", params, nil) +} + +func (self *SAwsClient) AttachUserPolicy(userName string, policyArn string) error { + params := map[string]string{ + "PolicyArn": policyArn, + "UserName": userName, + } + return self.iamRequest("AttachUserPolicy", params, nil) +} + +func (self *SAwsClient) DetachUserPolicy(userName string, policyArn string) error { + params := map[string]string{ + "PolicyArn": policyArn, + "UserName": userName, + } + err := self.iamRequest("DetachUserPolicy", params, nil) + if err != nil && errors.Cause(err) != cloudprovider.ErrNotFound { + return errors.Wrap(err, "DetachUserPolicy") + } + return nil +} + +func (self *SAwsClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + user, err := self.CreateUser("", conf.Name) + if err != nil { + return nil, errors.Wrap(err, "CreateUser") + } + if len(conf.Password) > 0 { + _, err := self.CreateLoginProfile(conf.Name, conf.Password) + if err != nil { + log.Errorf("failed to create loginProfile for user %s error: %v", conf.Name, err) + } + } + return user, nil +} + +func (self *SAwsClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.GetUser(name) +} + +func (self *SAwsClient) GetUser(name string) (*SUser, error) { + user := struct { + User SUser `xml:"User"` + }{} + params := map[string]string{ + "UserName": name, + } + err := self.iamRequest("GetUser", params, &user) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.GetUser") + } + user.User.client = self + return &user.User, nil +} + +func (self *SAwsClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { + ret := []cloudprovider.IClouduser{} + offset := "" + for { + part, err := self.ListUsers(offset, 1000, "") + if err != nil { + return nil, errors.Wrap(err, "ListUsers") + } + for i := range part.Users { + part.Users[i].client = self + ret = append(ret, &part.Users[i]) + } + offset = part.Marker + if len(offset) == 0 || !part.IsTruncated { + break + } + } + return ret, nil +} + +type LoginProfile struct { + UserName string `xml:"UserName"` + CreateDate time.Time `xml:"CreateDate"` +} +type SLoginProfile struct { + LoginProfile LoginProfile `xml:"LoginProfile"` +} + +func (self *SAwsClient) GetLoginProfile(name string) (*SLoginProfile, error) { + params := map[string]string{ + "UserName": name, + } + loginProfix := &SLoginProfile{} + err := self.iamRequest("GetLoginProfile", params, loginProfix) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.GetLoginProfie") + } + return loginProfix, nil +} + +func (self *SAwsClient) DeleteLoginProfile(name string) error { + params := map[string]string{ + "UserName": name, + } + return self.iamRequest("DeleteLoginProfile", params, nil) +} + +func (self *SAwsClient) CreateLoginProfile(name, password string) (*SLoginProfile, error) { + params := map[string]string{ + "UserName": name, + "Password": password, + } + loginProfile := &SLoginProfile{} + err := self.iamRequest("CreateLoginProfile", params, loginProfile) + if err != nil { + return nil, errors.Wrap(err, "iamRequest.GetLoginProfie") + } + return loginProfile, nil +} + +func (self *SAwsClient) UpdateLoginProfile(name, password string) error { + params := map[string]string{ + "UserName": name, + "Password": password, + } + return self.iamRequest("UpdateLoginProfile", params, nil) +} + +func (self *SAwsClient) ResetUserPassword(name, password string) error { + _, err := self.GetLoginProfile(name) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + _, err = self.CreateLoginProfile(name, password) + return err + } + return errors.Wrap(err, "GetLoginProfile") + } + return self.UpdateLoginProfile(name, password) +} + +func (self *SAwsClient) ListGroupsForUser(name string, offset string, limit int) (*SGroups, error) { + if limit < 1 || limit > 1000 { + limit = 1000 + } + params := map[string]string{ + "UserName": name, + "MaxItems": fmt.Sprintf("%d", limit), + } + if len(offset) > 0 { + params["Marker"] = offset + } + groups := &SGroups{} + err := self.iamRequest("ListGroupsForUser", params, groups) + if err != nil { + return nil, errors.Wrap(err, "ListGroupsForUser") + } + return groups, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/image.go new file mode 100644 index 0000000000..05187c2fd6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/image.go @@ -0,0 +1,589 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "fmt" + "time" + + "github.com/aws/aws-sdk-go/service/ec2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/timeutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type ImageStatusType string + +const ( + ImageStatusCreating ImageStatusType = "pending" + ImageStatusAvailable ImageStatusType = "available" + ImageStatusCreateFailed ImageStatusType = "failed" + + ImageImportStatusCompleted = "completed" + ImageImportStatusUncompleted = "uncompleted" + ImageImportStatusError = "error" + ImageImportStatusDeleted = "deleted" +) + +type TImageOwnerType string + +const ( + ImageOwnerTypeSystem = TImageOwnerType("system") + ImageOwnerTypeSelf = TImageOwnerType("self") + ImageOwnerTypeOther = TImageOwnerType("other") +) + +var ( + ImageOwnerAll = []TImageOwnerType(nil) + ImageOwnerSelf = []TImageOwnerType{ImageOwnerTypeSelf} + ImageOwnerSystem = []TImageOwnerType{ImageOwnerTypeSystem} + ImageOwnerSelfSystem = []TImageOwnerType{ImageOwnerTypeSystem, ImageOwnerTypeSelf} +) + +type ImageImportTask struct { + multicloud.SResourceBase + region *SRegion + + ImageId string + RegionId string + TaskId string + Status string +} + +type RootDevice struct { + SnapshotId string + Size int // GB + Category string // VolumeType +} + +type SImage struct { + multicloud.SImageBase + AwsTags + storageCache *SStoragecache + + // normalized image info + imgInfo *imagetools.ImageInfo + + Architecture string + CreationTime time.Time + Description string + ImageId string + ImageName string + OSType string + ImageType cloudprovider.TImageType + // IsSupportCloudinit bool + EnaSupport bool + Platform string + SizeGB int + Status ImageStatusType + OwnerType string + // Usage string + RootDevice RootDevice + RootDeviceName string + // devices + BlockDevicesNames []string + + Public bool + Hypervisor string + VirtualizationType string + OwnerId string + + ProductCodes []*ec2.ProductCode + + OSVersion string + OSDist string + OSBuildId string +} + +func (self *ImageImportTask) GetId() string { + return self.TaskId +} + +func (self *ImageImportTask) GetName() string { + return self.GetId() +} + +func (self *ImageImportTask) GetGlobalId() string { + return self.GetId() +} + +func (self *ImageImportTask) Refresh() error { + ec2Client, err := self.region.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.DescribeImportImageTasks(&ec2.DescribeImportImageTasksInput{ImportTaskIds: []*string{&self.TaskId}}) + if err != nil { + log.Errorf("DescribeImportImageTasks %s", err) + return errors.Wrap(err, "ImageImportTask.Refresh.DescribeImportImageTasks") + } + + err = FillZero(ret) + if err != nil { + log.Errorf("DescribeImportImageTask.FillZero %s", err) + return errors.Wrap(err, "ImageImportTask.Refresh.FillZero") + } + + // 打印上传进度 + log.Debugf("DescribeImportImage Task %s", ret.String()) + for _, item := range ret.ImportImageTasks { + if StrVal(item.ImportTaskId) == self.TaskId { + self.ImageId = StrVal(item.ImageId) + self.Status = StrVal(item.Status) + } + } + + return nil +} + +func (self *ImageImportTask) IsEmulated() bool { + return true +} + +func (self *ImageImportTask) GetStatus() string { + self.Refresh() + if self.Status == "completed" { + return ImageImportStatusCompleted + } else if self.Status == "deleted" { + return ImageImportStatusDeleted + } else { + return ImageImportStatusUncompleted + } +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SImage) GetId() string { + return self.ImageId +} + +func (self *SImage) GetName() string { + if len(self.ImageName) > 0 { + return self.ImageName + } + + return self.GetId() +} + +func (self *SImage) GetGlobalId() string { + return self.ImageId +} + +func (self *SImage) GetStatus() string { + switch self.Status { + case ImageStatusCreating: + return api.CACHED_IMAGE_STATUS_CACHING + case ImageStatusAvailable: + return api.CACHED_IMAGE_STATUS_ACTIVE + case ImageStatusCreateFailed: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + default: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (self *SImage) GetImageStatus() string { + switch self.Status { + case ImageStatusCreating: + return cloudprovider.IMAGE_STATUS_QUEUED + case ImageStatusAvailable: + return cloudprovider.IMAGE_STATUS_ACTIVE + case ImageStatusCreateFailed: + return cloudprovider.IMAGE_STATUS_KILLED + default: + return cloudprovider.IMAGE_STATUS_KILLED + } +} + +func (self *SImage) Refresh() error { + new, err := self.storageCache.region.GetImage(self.ImageId) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + return self.ImageType +} + +func (self *SImage) GetSizeByte() int64 { + return int64(self.SizeGB) * 1024 * 1024 * 1024 +} + +func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if self.imgInfo == nil { + imgInfo := imagetools.NormalizeImageInfo("", self.Architecture, self.OSType, self.OSDist, self.OSVersion) + self.imgInfo = &imgInfo + } + return self.imgInfo +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) +} + +func (self *SImage) GetOsArch() string { + return self.getNormalizedImageInfo().OsArch +} + +func (self *SImage) GetOsDist() string { + return self.getNormalizedImageInfo().OsDistro +} + +func (self *SImage) GetOsVersion() string { + return self.getNormalizedImageInfo().OsVersion +} + +func (self *SImage) GetOsLang() string { + return self.getNormalizedImageInfo().OsLang +} + +func (self *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) +} + +func (self *SImage) GetFullOsName() string { + return self.getNormalizedImageInfo().GetFullOsName() +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return self.SizeGB +} + +func (self *SImage) GetImageFormat() string { + return "vhd" +} + +func (self *SImage) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SImage) IsEmulated() bool { + return false +} + +func (self *SImage) Delete(ctx context.Context) 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) // Linux|Windows + // 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 - %s", name, osDist)) + 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? + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.ImportImage(params) + if err != nil { + return nil, errors.Wrap(err, "ImportImage") + } + log.Debugf("ImportImage task: %s", ret.String()) + return &ImageImportTask{ImageId: StrVal(ret.ImageId), RegionId: self.RegionId, TaskId: *ret.ImportTaskId, Status: StrVal(ret.Status), region: self}, 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) + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.CreateInstanceExportTask(params) + if err != nil { + return nil, errors.Wrap(err, "CreateInstanceExportTask") + } + + return &ImageExportTask{ImageId: imageId, RegionId: self.RegionId, TaskId: *ret.ExportTask.ExportTaskId}, nil +} + +func (self *SRegion) GetImage(imageId string) (*SImage, error) { + if len(imageId) == 0 { + return nil, fmt.Errorf("GetImage image id should not be empty") + } + + images, err := self.getImages("", ImageOwnerAll, []string{imageId}, "", "", nil, "") + if err != nil { + return nil, errors.Wrap(err, "getImages") + } + if len(images) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "getImages") + } + return &images[0], nil +} + +func (self *SRegion) GetImageByName(name string, owners []TImageOwnerType) (*SImage, error) { + if len(name) == 0 { + return nil, fmt.Errorf("image name should not be empty") + } + + images, err := self.getImages("", owners, nil, name, "hvm", nil, "") + if err != nil { + return nil, errors.Wrap(err, "getImages") + } + if len(images) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "getImages") + } + + log.Debugf("%d image found match name %s", len(images), name) + 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 && volume.Ebs != nil && volume.Ebs.VolumeSize != nil { + return int(*volume.Ebs.VolumeSize), nil + } + } + return 0, fmt.Errorf("image size not found: %s", image.String()) +} + +func getLatestImage(images []SImage) SImage { + var latestBuild string + latestBuildIdx := -1 + for i := range images { + if latestBuildIdx < 0 || comapreImageBuildIds(latestBuild, images[i]) < 0 { + latestBuild = images[i].OSBuildId + latestBuildIdx = i + } + } + return images[latestBuildIdx] +} + +func (self *SRegion) GetImages(status ImageStatusType, owners []TImageOwnerType, imageId []string, name string, virtualizationType string, ownerIds []string, volumeType string, latest bool) ([]SImage, error) { + images, err := self.getImages(status, owners, imageId, name, virtualizationType, ownerIds, volumeType) + if err != nil { + return nil, errors.Wrap(err, "getImages") + } + if !latest { + return images, err + } + noVersionImages := make([]SImage, 0) + versionedImages := make(map[string][]SImage) + for i := range images { + key := fmt.Sprintf("%s%s", images[i].OSDist, images[i].OSVersion) + if len(key) == 0 { + noVersionImages = append(noVersionImages, images[i]) + continue + } + if _, ok := versionedImages[key]; !ok { + versionedImages[key] = make([]SImage, 0) + } + versionedImages[key] = append(versionedImages[key], images[i]) + } + for key := range versionedImages { + noVersionImages = append(noVersionImages, getLatestImage(versionedImages[key])) + } + return noVersionImages, nil +} + +func (self *SRegion) getImages(status ImageStatusType, owners []TImageOwnerType, imageId []string, name string, virtualizationType string, ownerIds []string, volumeType string) ([]SImage, 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(virtualizationType) > 0 { + filters = AppendSingleValueFilter(filters, "virtualization-type", virtualizationType) + } + + if len(volumeType) > 0 { + filters = AppendSingleValueFilter(filters, "block-device-mapping.volume-type", volumeType) + } + + filters = AppendSingleValueFilter(filters, "image-type", "machine") + + if len(owners) > 0 || len(ownerIds) > 0 { + params.SetOwners(imageOwnerTypes2Strings(owners, ownerIds)) + } + + if len(imageId) > 0 { + params.SetImageIds(ConvertedList(imageId)) + } + + if len(filters) > 0 { + params.SetFilters(filters) + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.DescribeImages(params) + err = parseNotFoundError(err) + if err != nil { + return nil, errors.Wrap(err, "parseNotFoundError") + } + + images := []SImage{} + for i := range ret.Images { + image := ret.Images[i] + + if err := FillZero(image); err != nil { + return nil, errors.Wrap(err, "FillZero.image") + } + + tagspec := TagSpec{} + tagspec.LoadingEc2Tags(image.Tags) + + size, err := getRootDiskSize(image) + if err != nil { + // fail to get disk size, ignore the image + /// log.Debugln(err) + continue + } + + var rootDevice RootDevice + devicesName := []string{} + 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) + } + + devicesName = append(devicesName, *block.DeviceName) + } + + osType := "" + if StrVal(image.Platform) != "windows" { + osType = "Linux" + } else { + osType = "Windows" + } + + createTime, _ := timeutils.ParseTimeStr(*image.CreationDate) + + name := tagspec.GetNameTag() + if len(name) == 0 && image.Name != nil { + name = *image.Name + } + + sImage := SImage{ + storageCache: self.getStoragecache(), + Architecture: *image.Architecture, + Description: *image.Description, + ImageId: *image.ImageId, + Public: *image.Public, + ImageName: name, + OSType: osType, + // ImageType: *image.ImageType, + OwnerType: *image.ImageOwnerAlias, + EnaSupport: *image.EnaSupport, + Platform: *image.Platform, + RootDeviceName: *image.RootDeviceName, + BlockDevicesNames: devicesName, + Status: ImageStatusType(*image.State), + CreationTime: createTime, + SizeGB: size, + RootDevice: rootDevice, + VirtualizationType: *image.VirtualizationType, + Hypervisor: *image.Hypervisor, + ProductCodes: image.ProductCodes, + OwnerId: *image.OwnerId, + } + sImage.ImageType = getImageType(sImage) + sImage.OSType = getImageOSType(sImage) + sImage.OSDist = getImageOSDist(sImage) + sImage.OSVersion = getImageOSVersion(sImage) + sImage.OSBuildId = getImageOSBuildID(sImage) + images = append(images, sImage) + } + + return images, nil +} + +func (self *SRegion) DeleteImage(imageId string) error { + params := &ec2.DeregisterImageInput{} + params.SetImageId(imageId) + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.DeregisterImage(params) + return errors.Wrap(err, "DeregisterImage") +} + +func (self *SRegion) addTags(resId string, key string, value string) error { + input := &ec2.CreateTagsInput{} + input.SetResources([]*string{&resId}) + tag := ec2.Tag{} + tag.Key = &key + tag.Value = &value + input.SetTags([]*ec2.Tag{&tag}) + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.CreateTags(input) + if err != nil { + return errors.Wrap(err, "CreateTags") + } + return nil +} diff --git a/pkg/multicloud/aws/imageowners.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/imageowners.go similarity index 99% rename from pkg/multicloud/aws/imageowners.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/imageowners.go index 77bab10df9..cfc01d1a65 100644 --- a/pkg/multicloud/aws/imageowners.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/imageowners.go @@ -22,7 +22,7 @@ import ( "yunion.io/x/pkg/util/regutils" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) func getSystemOwnerIds() []string { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/instance.go new file mode 100644 index 0000000000..34fb267915 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/instance.go @@ -0,0 +1,1376 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "encoding/base64" + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go/service/ec2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/apis" + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/cloudinit" +) + +const ( + InstanceStatusPending = "pending" + InstanceStatusRunning = "running" + InstanceStatusShutting = "shutting-down" + InstanceStatusTerminated = "terminated" + InstanceStatusStopping = "stopping" + InstanceStatusStopped = "stopped" +) + +type InstanceChargeType string + +type SIpAddress struct { + IpAddress []string +} + +type SSecurityGroupIds struct { + SecurityGroupId []string +} + +type SVpcAttributes struct { + PrivateIpAddress SIpAddress + NetworkId string // subnet id + VpcId string +} + +type SInstance struct { + multicloud.SInstanceBase + + host *SHost + img *SImage + RegionId string + ZoneId string + InstanceId string + ImageId string + + HostName string + InstanceName string + InstanceType string + Cpu int + Memory int // MB + 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 []SNetworkInterface + EipAddress SEipAddress + Disks []string + DeviceNames []string + OSName string + OSType string + Description string + InternetMaxBandwidthOut int + Throughput int + + TagSpec TagSpec + + // 这些貌似都没啥用 + // 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 { + udata := &ec2.BlobAttributeValue{} + udata.SetValue([]byte(userData)) + + input := &ec2.ModifyInstanceAttributeInput{} + input.SetUserData(udata) + input.SetInstanceId(self.GetId()) + ec2Client, err := self.host.zone.region.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.ModifyInstanceAttribute(input) + if err != nil { + return errors.Wrap(err, "ModifyInstanceAttribute") + } + + return nil +} + +func (self *SInstance) GetUserData() (string, error) { + input := &ec2.DescribeInstanceAttributeInput{} + input.SetInstanceId(self.GetId()) + input.SetAttribute("userData") + ec2Client, err := self.host.zone.region.getEc2Client() + if err != nil { + return "", errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.DescribeInstanceAttribute(input) + if err != nil { + return "", err + } + + d := StrVal(ret.UserData.Value) + udata, err := base64.StdEncoding.DecodeString(d) + if err != nil { + return "", fmt.Errorf("GetUserData decode user data %s", err) + } + + return string(udata), nil +} + +func (self *SInstance) GetId() string { + return self.InstanceId +} + +func (self *SInstance) GetName() string { + if len(self.InstanceName) > 0 { + return self.InstanceName + } + + return self.GetId() +} + +func (self *SInstance) GetHostname() string { + return self.GetName() +} + +func (self *SInstance) GetGlobalId() string { + return self.InstanceId +} + +func (self *SInstance) GetStatus() string { + switch self.Status { + case InstanceStatusRunning: + return api.VM_RUNNING + case InstanceStatusPending: // todo: pending ? + return api.VM_STARTING + case InstanceStatusStopping: + return api.VM_STOPPING + case InstanceStatusStopped: + return api.VM_READY + default: + return api.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) GetInstanceType() string { + return self.InstanceType +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + return self.SecurityGroupIds.SecurityGroupId, nil +} + +func (self *SInstance) GetTags() (map[string]string, error) { + return self.TagSpec.GetTags() +} + +func (self *SInstance) GetSysTags() map[string]string { + return map[string]string{} +} + +func (self *SInstance) GetBillingType() string { + // todo: implement me + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SInstance) GetCreatedAt() time.Time { + return self.CreationTime +} + +func (self *SInstance) GetExpiredAt() time.Time { + return self.ExpiredTime +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetThroughput() int { + return self.Throughput +} + +func (self *SInstance) GetInternetMaxBandwidthOut() int { + return self.InternetMaxBandwidthOut +} + +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, errors.Wrap(err, "GetDisks") + } + + 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, errors.Wrap(err, "getStorageByCategory") + } + disks[i].storage = store + idisks[i] = &disks[i] + } + return idisks, nil +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + var ( + networkInterfaces = self.NetworkInterfaces + nics = make([]cloudprovider.ICloudNic, 0) + ) + for _, networkInterface := range networkInterfaces { + nic := SInstanceNic{ + instance: self, + id: networkInterface.NetworkInterfaceId, + ipAddr: networkInterface.PrivateIpAddress, + macAddr: networkInterface.MacAddress, + } + nics = append(nics, &nic) + } + return nics, nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + if len(self.EipAddress.PublicIp) > 0 { + return self.host.zone.region.GetEipByIpAddress(self.EipAddress.PublicIp) + } + if len(self.PublicIpAddress.IpAddress) > 0 { + eip := SEipAddress{region: self.host.zone.region} + eip.region = self.host.zone.region + eip.PublicIp = self.PublicIpAddress.IpAddress[0] + eip.InstanceId = self.InstanceId + eip.AllocationId = self.InstanceId // fixed. AllocationId等于InstanceId即表示为 仿真EIP。 + return &eip, nil + } + return nil, nil +} + +func (self *SInstance) GetVcpuCount() int { + 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() cloudprovider.TOsType { + return cloudprovider.TOsType(osprofile.NormalizeOSType(self.OSType)) +} + +func (self *SInstance) GetFullOsName() string { + return self.OSName +} + +func (self *SInstance) GetBios() cloudprovider.TBiosType { + img, err := self.GetImage() + if err != nil { + log.Errorf("GetImage fail %s", err) + return cloudprovider.BIOS + } + return img.GetBios() +} + +func (self *SInstance) GetOsArch() string { + img, err := self.GetImage() + if err != nil { + log.Errorf("GetImage fail %s", err) + return apis.OS_ARCH_X86_64 + } + return img.GetOsArch() +} + +func (self *SInstance) GetOsDist() string { + img, err := self.GetImage() + if err != nil { + log.Errorf("GetImage fail %s", err) + return "" + } + return img.GetOsDist() +} + +func (self *SInstance) GetOsVersion() string { + img, err := self.GetImage() + if err != nil { + log.Errorf("GetImage fail %s", err) + return "" + } + return img.GetOsVersion() +} + +func (self *SInstance) GetOsLang() string { + img, err := self.GetImage() + if err != nil { + log.Errorf("GetImage fail %s", err) + return "" + } + return img.GetOsLang() +} + +func (self *SInstance) GetMachine() string { + return "pc" +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.SetSecurityGroups([]string{secgroupId}) +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + ids := []*string{} + for i := 0; i < len(secgroupIds); i++ { + ids = append(ids, &secgroupIds[i]) + } + return self.host.zone.region.assignSecurityGroups(ids, self.InstanceId) +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_AWS +} + +func (self *SInstance) StartVM(ctx context.Context) 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 + } + + if self.GetStatus() == api.VM_RUNNING { + return nil + } else if self.GetStatus() == api.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(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + err := self.host.zone.region.StopVM(self.InstanceId, opts.IsForce) + if err != nil { + return err + } + return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + for { + err := self.host.zone.region.DeleteVM(self.InstanceId) + if err != nil && self.Status != InstanceStatusTerminated { + return err + } else { + break + } + } + + params := &ec2.DescribeInstancesInput{InstanceIds: []*string{&self.InstanceId}} + ec2Client, err := self.host.zone.region.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + return ec2Client.WaitUntilInstanceTerminated(params) +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + addTags := map[string]string{} + addTags["Name"] = name + Arn := self.GetArn() + err := self.host.zone.region.TagResources([]string{Arn}, addTags) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.TagResources([]string{%s}, %s)", Arn, jsonutils.Marshal(addTags).String()) + } + return nil +} + +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + udata, err := self.GetUserData() + if err != nil { + return "", err + } + + // compare sysSizeGB + image, err := self.host.zone.region.GetImage(desc.ImageId) + if err != nil { + return "", err + } else { + minSizeGB := image.GetMinOsDiskSizeGb() + if minSizeGB > desc.SysSizeGB { + desc.SysSizeGB = minSizeGB + } + } + + // upload keypair + keypairName := self.KeyPairName + if len(desc.PublicKey) > 0 { + keypairName, err = self.host.zone.region.syncKeypair(desc.PublicKey) + if err != nil { + return "", fmt.Errorf("RebuildRoot.syncKeypair %s", err) + } + } + + userdata := "" + srcOsType := strings.ToLower(string(self.GetOsType())) + destOsType := strings.ToLower(string(image.GetOsType())) + winOS := strings.ToLower(osprofile.OS_TYPE_WINDOWS) + + cloudconfig := &cloudinit.SCloudConfig{} + if srcOsType != winOS && len(udata) > 0 { + _cloudconfig, err := cloudinit.ParseUserDataBase64(udata) + if err != nil { + // 忽略无效的用户数据 + log.Debugf("RebuildRoot invalid instance user data %s", udata) + } else { + cloudconfig = _cloudconfig + } + } + + if (srcOsType != winOS && destOsType != winOS) || (srcOsType == winOS && destOsType != winOS) { + // linux/windows to linux + loginUser := cloudinit.NewUser(api.VM_AWS_DEFAULT_LOGIN_USER) + loginUser.SudoPolicy(cloudinit.USER_SUDO_NOPASSWD) + if len(desc.PublicKey) > 0 { + loginUser.SshKey(desc.PublicKey) + cloudconfig.MergeUser(loginUser) + } else if len(desc.Password) > 0 { + cloudconfig.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON + loginUser.Password(desc.Password) + cloudconfig.MergeUser(loginUser) + } + + userdata = cloudconfig.UserDataBase64() + } else { + // linux/windows to windows + data := "" + if len(desc.Password) > 0 { + cloudconfig.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON + loginUser := cloudinit.NewUser(api.VM_AWS_DEFAULT_WINDOWS_LOGIN_USER) + loginUser.SudoPolicy(cloudinit.USER_SUDO_NOPASSWD) + loginUser.Password(desc.Password) + cloudconfig.MergeUser(loginUser) + data = fmt.Sprintf("%s", cloudconfig.UserDataPowerShell()) + } else { + if len(udata) > 0 { + data = fmt.Sprintf("%s", udata) + } + } + + userdata = base64.StdEncoding.EncodeToString([]byte(data)) + } + + diskId, err := self.host.zone.region.ReplaceSystemDisk(ctx, self.InstanceId, image, desc.SysSizeGB, keypairName, userdata) + if err != nil { + return "", err + } + + return diskId, nil +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username 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(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + if len(config.InstanceType) > 0 { + return self.ChangeConfig2(ctx, config.InstanceType) + } + return errors.Wrap(errors.ErrClient, "Instance.ChangeConfig.InstanceTypeIsEmpty") +} + +func (self *SInstance) ChangeConfig2(ctx context.Context, instanceType string) error { + return self.host.zone.region.ChangeVMConfig2(self.ZoneId, self.InstanceId, instanceType, nil) +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetImage() (*SImage, error) { + if self.img != nil { + return self.img, nil + } + + img, err := self.host.zone.region.GetImage(self.ImageId) + if err != nil { + return nil, errors.Wrap(err, "GetImage") + } + + self.img = img + return self.img, nil +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + img, err := self.GetImage() + if err != nil { + return errors.Wrap(err, "GetImage") + } + + // mix in image block device names + for i := range img.BlockDevicesNames { + if !utils.IsInStringArray(img.BlockDevicesNames[i], self.DeviceNames) { + self.DeviceNames = append(self.DeviceNames, img.BlockDevicesNames[i]) + } + } + + name, err := NextDeviceName(self.DeviceNames) + if err != nil { + return err + } + + err = self.host.zone.region.AttachDisk(self.InstanceId, diskId, name) + if err != nil { + return err + } + + self.DeviceNames = append(self.DeviceNames, name) + return nil +} + +func (self *SInstance) DetachDisk(ctx context.Context, 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) + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, 0, errors.Wrap(err, "getEc2Client") + } + res, err := ec2Client.DescribeInstances(params) + if err != nil { + if strings.Contains(err.Error(), "InvalidInstanceID.NotFound") { + return nil, 0, errors.Wrap(cloudprovider.ErrNotFound, "DescribeInstances") + } else { + return nil, 0, err + } + } + + instances := []SInstance{} + for _, reservation := range res.Reservations { + for _, instance := range reservation.Instances { + if err := FillZero(instance); err != nil { + return nil, 0, err + } + + // 不同步已经terminated的主机 + if *instance.State.Name == ec2.InstanceStateNameTerminated { + continue + } + + 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) + } + } + + networkInterfaces := []SNetworkInterface{} + eipAddress := SEipAddress{} + for _, n := range instance.NetworkInterfaces { + i := SNetworkInterface{ + MacAddress: *n.MacAddress, + NetworkInterfaceId: *n.NetworkInterfaceId, + PrivateIpAddress: *n.PrivateIpAddress, + } + networkInterfaces = append(networkInterfaces, i) + + // todo: 可能有多个EIP的情况。目前只支持一个EIP + if n.Association != nil && StrVal(n.Association.IpOwnerId) != "amazon" { + if eipAddress.PublicIp == "" && len(StrVal(n.Association.PublicIp)) > 0 { + eipAddress.PublicIp = *n.Association.PublicIp + } + } + } + + 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) + } + + publicIpAddress := SIpAddress{} + if len(*instance.PublicIpAddress) > 0 { + publicIpAddress.IpAddress = []string{*instance.PublicIpAddress} + } + + innerIpAddress := SIpAddress{} + if len(*instance.PrivateIpAddress) > 0 { + innerIpAddress.IpAddress = []string{*instance.PrivateIpAddress} + } + + szone, err := self.getZoneById(*instance.Placement.AvailabilityZone) + if err != nil { + log.Errorf("getZoneById %s fail %s", *instance.Placement.AvailabilityZone, err) + return nil, 0, err + } + + osType := "Linux" + if instance.Platform != nil && len(*instance.Platform) > 0 { + osType = *instance.Platform + } + + host := szone.getHost() + vcpu := int(*instance.CpuOptions.CoreCount) * int(*instance.CpuOptions.ThreadsPerCore) + sinstance := SInstance{ + RegionId: self.RegionId, + host: host, + ZoneId: *instance.Placement.AvailabilityZone, + InstanceId: *instance.InstanceId, + ImageId: *instance.ImageId, + InstanceType: *instance.InstanceType, + Cpu: vcpu, + IoOptimized: *instance.EbsOptimized, + KeyPairName: *instance.KeyName, + CreationTime: *instance.LaunchTime, + PublicDNSName: *instance.PublicDnsName, + RootDeviceName: *instance.RootDeviceName, + Status: *instance.State.Name, + InnerIpAddress: innerIpAddress, + PublicIpAddress: publicIpAddress, + EipAddress: eipAddress, + InstanceName: tagspec.GetNameTag(), + Description: tagspec.GetDescTag(), + Disks: disks, + DeviceNames: devicenames, + SecurityGroupIds: secgroups, + NetworkInterfaces: networkInterfaces, + VpcAttributes: vpcattr, + ProductCodes: productCodes, + OSName: osType, // todo: 这里在model层回写OSName信息 + OSType: osType, + + TagSpec: tagspec, + // ExpiredTime: + // VlanId: + // OSType: + } + + instances = append(instances, sinstance) + } + } + + return instances, len(instances), nil +} + +func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) { + if len(instanceId) == 0 { + return nil, fmt.Errorf("GetInstance instanceId should not be empty.") + } + + instances, _, err := self.GetInstances("", []string{instanceId}, 0, 1) + if err != nil { + log.Errorf("GetInstances %s: %s", instanceId, err) + return nil, errors.Wrap(err, "GetInstances") + } + if len(instances) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetInstances") + } + 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) + + ec2Client, err := self.getEc2Client() + if err != nil { + return "", errors.Wrap(err, "getEc2Client") + } + ret, err := 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, image *SImage, instanceType string, SubnetId string, securityGroupId string, + zoneId string, desc string, disks []SDisk, ipAddr string, + keypair string, userData string, ntags map[string]string, +) (string, error) { + var count int64 = 1 + // disk + blockDevices := []*ec2.BlockDeviceMapping{} + for i := range disks { + var ebs ec2.EbsBlockDevice + var deviceName string + var err error + disk := disks[i] + + if i == 0 { + var size int64 + deleteOnTermination := true + size = int64(disk.Size) + ebs = ec2.EbsBlockDevice{ + DeleteOnTermination: &deleteOnTermination, + // 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, + } + + if len(image.RootDeviceName) > 0 { + deviceName = image.RootDeviceName + } else { + deviceName = fmt.Sprintf("/dev/sda1") + } + } else { + var size int64 + size = int64(disk.Size) + ebs = ec2.EbsBlockDevice{ + DeleteOnTermination: &disk.DeleteWithInstance, + Encrypted: &disk.Encrypted, + VolumeSize: &size, + VolumeType: &disk.Category, + } + + deviceName, err = NextDeviceName(image.BlockDevicesNames) + if err != nil { + return "", errors.Wrap(err, "NextDeviceName") + } + } + + if iops := GenDiskIops(disk.Category, disk.Size); iops > 0 { + ebs.SetIops(iops) + } + + blockDevice := &ec2.BlockDeviceMapping{ + DeviceName: &deviceName, + Ebs: &ebs, + } + + blockDevices = append(blockDevices, blockDevice) + } + + // tags + tags := TagSpec{ResourceType: "instance"} + tags.SetNameTag(name) + tags.SetDescTag(desc) + + if len(ntags) > 0 { + for k, v := range ntags { + tags.SetTag(k, v) + } + } + + ec2TagSpec, err := tags.GetTagSpecifications() + if err != nil { + return "", err + } + + imgId := image.GetId() + params := ec2.RunInstancesInput{ + ImageId: &imgId, + InstanceType: &instanceType, + MaxCount: &count, + MinCount: &count, + BlockDeviceMappings: blockDevices, + Placement: &ec2.Placement{AvailabilityZone: &zoneId}, + TagSpecifications: []*ec2.TagSpecification{ec2TagSpec}, + } + params.Monitoring = &ec2.RunInstancesMonitoringEnabled{ + Enabled: &options.Options.EnableAwsMonitorAgent, + } + + // keypair + if len(keypair) > 0 { + params.SetKeyName(keypair) + } + + // user data + if len(userData) > 0 { + params.SetUserData(userData) + } + + // ip address + if len(ipAddr) > 0 { + params.SetPrivateIpAddress(ipAddr) + } + + // subnet id + if len(SubnetId) > 0 { + params.SetSubnetId(SubnetId) + } + + // security group + if len(securityGroupId) > 0 { + params.SetSecurityGroupIds([]*string{&securityGroupId}) + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return "", errors.Wrap(err, "getEc2Client") + } + res, err := ec2Client.RunInstances(¶ms) + 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: %d 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) StartVM(instanceId string) error { + params := &ec2.StartInstancesInput{} + params.SetInstanceIds([]*string{&instanceId}) + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.StartInstances(params) + return errors.Wrap(err, "StartInstances") +} + +func (self *SRegion) StopVM(instanceId string, isForce bool) error { + params := &ec2.StopInstancesInput{} + params.SetInstanceIds([]*string{&instanceId}) + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.StopInstances(params) + return errors.Wrap(err, "StopInstances") +} + +func (self *SRegion) DeleteVM(instanceId string) error { + // 检查删除保护状态.如果已开启则先关闭删除保护再进行删除操作 + protect, err := self.deleteProtectStatusVM(instanceId) + if err != nil { + return err + } + + if protect { + log.Warningf("DeleteVM instance %s which termination protect is in open status", instanceId) + err = self.deleteProtectVM(instanceId, false) + if err != nil { + return err + } + } + + params := &ec2.TerminateInstancesInput{} + params.SetInstanceIds([]*string{&instanceId}) + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.TerminateInstances(params) + return errors.Wrap(err, "TerminateInstances") +} + +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) + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + ec2Tag, _ := tagspec.GetTagSpecifications() + if len(ec2Tag.Tags) > 0 { + params.SetTags(ec2Tag.Tags) + _, err := 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 cloudprovider.ErrNotSupported +} + +func (self *SRegion) ReplaceSystemDisk(ctx context.Context, instanceId string, image *SImage, sysDiskSizeGB int, keypair string, userdata string) (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 == api.DISK_TYPE_SYS { + rootDisk = &disk + break + } + } + + if rootDisk == nil { + return "", fmt.Errorf("can not find root disk of instance %s", instanceId) + } + log.Debugf("ReplaceSystemDisk replace root disk %s", rootDisk.DiskId) + + subnetId := "" + if len(instance.VpcAttributes.NetworkId) > 0 { + subnetId = instance.VpcAttributes.NetworkId + } + + // create tmp server + tempName := fmt.Sprintf("__tmp_%s", instance.GetName()) + _id, err := self.CreateInstance(tempName, + image, + instance.InstanceType, + subnetId, + "", + instance.ZoneId, + instance.Description, + []SDisk{{Size: sysDiskSizeGB, Category: rootDisk.Category}}, + "", + keypair, + userdata, + nil, + ) + if err == nil { + defer self.DeleteVM(_id) + } else { + log.Debugf("ReplaceSystemDisk create temp server failed. %s", err) + return "", fmt.Errorf("ReplaceSystemDisk create temp server failed.") + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return "", errors.Wrap(err, "getEc2Client") + } + + ec2Client.WaitUntilInstanceRunning(&ec2.DescribeInstancesInput{InstanceIds: []*string{&_id}}) + err = self.StopVM(_id, true) + if err != nil { + log.Debugf("ReplaceSystemDisk stop temp server failed %s", err) + return "", fmt.Errorf("ReplaceSystemDisk stop temp server failed") + } + ec2Client.WaitUntilInstanceStopped(&ec2.DescribeInstancesInput{InstanceIds: []*string{&_id}}) + + // detach disks + tempInstance, err := self.GetInstance(_id) + if err != nil { + log.Debugf("ReplaceSystemDisk get temp server failed %s", err) + return "", fmt.Errorf("ReplaceSystemDisk get temp server failed") + } + + err = self.DetachDisk(instance.GetId(), rootDisk.DiskId) + if err != nil { + log.Debugf("ReplaceSystemDisk detach disk %s: %s", rootDisk.DiskId, err) + return "", err + } + + err = self.DetachDisk(tempInstance.GetId(), tempInstance.Disks[0]) + if err != nil { + log.Debugf("ReplaceSystemDisk detach disk %s: %s", tempInstance.Disks[0], err) + return "", err + } + ec2Client.WaitUntilVolumeAvailable(&ec2.DescribeVolumesInput{VolumeIds: []*string{&rootDisk.DiskId}}) + ec2Client.WaitUntilVolumeAvailable(&ec2.DescribeVolumesInput{VolumeIds: []*string{&tempInstance.Disks[0]}}) + + err = self.AttachDisk(instance.GetId(), tempInstance.Disks[0], rootDisk.Device) + if err != nil { + log.Debugf("ReplaceSystemDisk attach disk %s: %s", tempInstance.Disks[0], err) + return "", err + } + ec2Client.WaitUntilInstanceStopped(&ec2.DescribeInstancesInput{InstanceIds: []*string{&instanceId}}) + ec2Client.WaitUntilVolumeInUse(&ec2.DescribeVolumesInput{VolumeIds: []*string{&tempInstance.Disks[0]}}) + + userdataText, err := base64.StdEncoding.DecodeString(userdata) + if err != nil { + return "", errors.Wrap(err, "SRegion.ReplaceSystemDisk.DecodeString") + } + err = instance.UpdateUserData(string(userdataText)) + if err != nil { + log.Debugf("ReplaceSystemDisk update user data %s", err) + return "", fmt.Errorf("ReplaceSystemDisk update user data failed") + } + + err = self.DeleteDisk(rootDisk.DiskId) + if err != nil { + log.Debugf("ReplaceSystemDisk delete old disk %s: %s", rootDisk.DiskId, err) + } + return tempInstance.Disks[0], nil +} + +func (self *SRegion) ChangeVMConfig2(zoneId string, instanceId string, instanceType string, disks []*SDisk) error { + params := &ec2.ModifyInstanceAttributeInput{} + params.SetInstanceId(instanceId) + + t := &ec2.AttributeValue{Value: &instanceType} + params.SetInstanceType(t) + + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.ModifyInstanceAttribute(params) + if err != nil { + return fmt.Errorf("Failed to change vm config, specification not supported. %s", err.Error()) + } else { + return nil + } +} + +func (self *SRegion) DetachDisk(instanceId string, diskId string) error { + params := &ec2.DetachVolumeInput{} + params.SetInstanceId(instanceId) + params.SetVolumeId(diskId) + log.Debugf("DetachDisk %s", params.String()) + + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + _, err = ec2Client.DetachVolume(params) + if err != nil { + if strings.Contains(err.Error(), fmt.Sprintf("'%s'is in the 'available' state", diskId)) { + return nil + } + //InvalidVolume.NotFound: The volume 'vol-0a9eeda0a70a8d7fe' does not exist + if strings.Contains(err.Error(), "InvalidVolume.NotFound") { + return nil + } + return errors.Wrap(err, "ec2Client.DetachVolume") + } + return nil +} + +func (self *SRegion) AttachDisk(instanceId string, diskId string, deviceName string) error { + params := &ec2.AttachVolumeInput{} + params.SetInstanceId(instanceId) + params.SetVolumeId(diskId) + params.SetDevice(deviceName) + log.Debugf("AttachDisk %s", params.String()) + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.AttachVolume(params) + return errors.Wrap(err, "AttachVolume") +} + +func (self *SRegion) deleteProtectStatusVM(instanceId string) (bool, error) { + p := &ec2.DescribeInstanceAttributeInput{} + p.SetInstanceId(instanceId) + p.SetAttribute("disableApiTermination") + ec2Client, err := self.getEc2Client() + if err != nil { + return false, errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.DescribeInstanceAttribute(p) + if err != nil { + return false, err + } + + return *ret.DisableApiTermination.Value, nil +} + +func (self *SRegion) deleteProtectVM(instanceId string, disableDelete bool) error { + p2 := &ec2.ModifyInstanceAttributeInput{ + DisableApiTermination: &ec2.AttributeBooleanValue{Value: &disableDelete}, + InstanceId: &instanceId, + } + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.ModifyInstanceAttribute(p2) + return errors.Wrap(err, "ModifyInstanceAttribute") +} + +func (self *SRegion) getPasswordData(instanceId string) (string, error) { + params := &ec2.GetPasswordDataInput{} + params.SetInstanceId(instanceId) + + ec2Client, err := self.getEc2Client() + if err != nil { + return "", errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.GetPasswordData(params) + if err != nil { + return "", err + } + + return *ret.PasswordData, nil +} + +func (self *SInstance) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetProjectId() string { + return "" +} + +func (self *SInstance) GetError() error { + return nil +} + +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { + ec2Client, err := self.host.zone.region.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + oldTagsJson, err := FetchTags(ec2Client, self.InstanceId) + if err != nil { + return errors.Wrapf(err, "FetchTags(self.host.zone.region.ec2Client, %s)", self.InstanceId) + } + oldTags := map[string]string{} + err = oldTagsJson.Unmarshal(oldTags) + if err != nil { + return errors.Wrapf(err, "(%s).Unmarshal(oldTags)", oldTagsJson.String()) + } + addTags := map[string]string{} + for k, v := range tags { + if strings.HasPrefix(k, "aws:") { + return errors.Wrap(cloudprovider.ErrNotSupported, "The aws: prefix is reserved for AWS use") + } + if _, ok := oldTags[k]; !ok { + addTags[k] = v + } else { + if oldTags[k] != v { + addTags[k] = v + } + } + } + delTags := []string{} + if replace { + for k := range oldTags { + if _, ok := tags[k]; !ok { + if !strings.HasPrefix(k, "aws:") && k != "Name" { + delTags = append(delTags, k) + } + } + } + } + Arn := self.GetArn() + err = self.host.zone.region.UntagResources([]string{Arn}, delTags) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.UntagResources([]string{%s}, %s)", Arn, jsonutils.Marshal(delTags).String()) + } + delete(addTags, "Name") + err = self.host.zone.region.TagResources([]string{Arn}, addTags) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.TagResources([]string{%s}, %s)", Arn, jsonutils.Marshal(addTags).String()) + } + return nil +} + +func (self *SInstance) GetAccountId() string { + identity, err := self.host.zone.region.client.GetCallerIdentity() + if err != nil { + log.Errorf(err.Error() + "self.region.client.GetCallerIdentity()") + return "" + } + return identity.Account +} + +func (self *SInstance) GetArn() string { + partition := "" + switch self.host.zone.region.client.GetAccessEnv() { + case api.CLOUD_ACCESS_ENV_AWS_GLOBAL: + partition = "aws" + case api.CLOUD_ACCESS_ENV_AWS_CHINA: + partition = "aws-cn" + default: + partition = "aws" + } + return fmt.Sprintf("arn:%s:ec2:%s:%s:instance/%s", partition, self.host.zone.region.GetId(), self.GetAccountId(), self.InstanceId) +} + +func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { + params := map[string]string{ + "Description": opts.Notes, + "InstanceId": instanceId, + "Name": opts.Name, + } + ret := struct { + ImageId string `xml:"imageId"` + }{} + err := self.ec2Request("CreateImage", params, &ret) + if err != nil { + return nil, errors.Wrapf(err, "CreateImage") + } + err = cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) { + _, err := self.GetImage(ret.ImageId) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return false, nil + } + return false, errors.Wrapf(err, "GetImage(%s)", ret.ImageId) + } + return true, nil + }) + if err != nil { + return nil, errors.Wrapf(err, "wait for image created") + } + image, err := self.GetImage(ret.ImageId) + if err != nil { + return nil, errors.Wrapf(err, "GetImage(%s)", ret.ImageId) + } + image.storageCache = self.getStoragecache() + return image, nil +} + +func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { + image, err := self.host.zone.region.SaveImage(self.InstanceId, opts) + if err != nil { + return nil, errors.Wrapf(err, "SaveImage") + } + return image, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/instancenic.go new file mode 100644 index 0000000000..6d0bc842e8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/instancenic.go @@ -0,0 +1,149 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/ec2" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + instance *SInstance + + id string + ipAddr string + macAddr string + + cloudprovider.DummyICloudNic +} + +func (self *SInstanceNic) GetId() string { + return self.id +} + +func (self *SInstanceNic) GetIP() string { + return self.ipAddr +} + +func (self *SInstanceNic) GetMAC() string { + return self.macAddr +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) GetINetworkId() string { + return self.instance.VpcAttributes.NetworkId +} + +func (self *SInstanceNic) getEc2Client() *ec2.EC2 { + ec2Client, err := self.instance.host.zone.region.getEc2Client() + if err != nil { + return nil + } + return ec2Client +} + +func (self *SInstanceNic) GetSubAddress() ([]string, error) { + var ( + ec2Client = self.getEc2Client() + id = self.GetId() + input = &ec2.DescribeNetworkInterfacesInput{ + NetworkInterfaceIds: []*string{ + aws.String(id), + }, + } + ) + output, err := ec2Client.DescribeNetworkInterfaces(input) + if err != nil { + return nil, errors.Wrapf(err, "aws ec2 DescribeNetworkInterfaces") + } + if got := len(output.NetworkInterfaces); got != 1 { + return nil, errors.Errorf("got aws %d network interface, want 1", got) + } + networkInterface := output.NetworkInterfaces[0] + if got := aws.StringValue(networkInterface.NetworkInterfaceId); got != id { + return nil, errors.Errorf("got aws network interface %s, want %s", got, id) + } + var ipAddrs []string + for _, privateIp := range networkInterface.PrivateIpAddresses { + if !aws.BoolValue(privateIp.Primary) { + ipAddrs = append(ipAddrs, *privateIp.PrivateIpAddress) + } + } + return ipAddrs, nil +} + +func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { + var ( + ec2Client = self.getEc2Client() + id = self.GetId() + input = &ec2.AssignPrivateIpAddressesInput{ + NetworkInterfaceId: aws.String(id), + PrivateIpAddresses: aws.StringSlice(ipAddrs), + } + ) + _, err := ec2Client.AssignPrivateIpAddresses(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case "PrivateIpAddressLimitExceeded": + return errors.Wrapf(cloudprovider.ErrAddressCountExceed, "aws ec2 AssignPrivateIpAddresses: %v", err) + } + } + return errors.Wrapf(err, "aws ec2 AssignPrivateIpAddresses") + } + return nil +} + +func (self *SInstanceNic) UnassignAddress(ipAddrs []string) error { + var ( + ec2Client = self.getEc2Client() + id = self.GetId() + input = &ec2.UnassignPrivateIpAddressesInput{ + NetworkInterfaceId: aws.String(id), + PrivateIpAddresses: aws.StringSlice(ipAddrs), + } + ) + _, err := ec2Client.UnassignPrivateIpAddresses(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case "InvalidNetworkInterfaceID.NotFound": + return nil + case "InvalidParameterValue": + msg := aerr.Message() + // "Some of the specified addresses are not assigned to interface eni-xxxxxxxxxxxxxxxxx" + if strings.Contains(msg, " addresses are not assigned to interface ") { + return nil + } + } + } + return errors.Wrapf(err, "aws ec2 UnassignPrivateIpAddresses") + } + return nil +} diff --git a/pkg/multicloud/aws/internetgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/internetgateway.go similarity index 93% rename from pkg/multicloud/aws/internetgateway.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/internetgateway.go index 36809d056d..9b48b64468 100644 --- a/pkg/multicloud/aws/internetgateway.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/internetgateway.go @@ -17,13 +17,13 @@ package aws import ( "github.com/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SInternetGateway struct { multicloud.SResourceBase - multicloud.AwsTags + AwsTags region *SRegion Attachments []InternetGatewayAttachment `json:"Attachments"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/keypair.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/keypair.go new file mode 100644 index 0000000000..dedd986af9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/keypair.go @@ -0,0 +1,175 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "bytes" + "crypto/md5" + "crypto/rsa" + "crypto/x509" + "fmt" + "strconv" + "time" + + "github.com/aokoli/goutils" + "github.com/aws/aws-sdk-go/service/ec2" + "golang.org/x/crypto/ssh" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SKeypair struct { + KeyPairFingerPrint string + KeyPairName string +} + +// 只支持计算Openssh ras 格式公钥转换成DER格式后的MD5。 +func md5Fingerprint(publickey string) (string, error) { + pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publickey)) + if err != nil { + return "", fmt.Errorf("publicKey error %s", err) + } + + der := []byte{} + cryptoPub, ok := pk.(ssh.CryptoPublicKey) + if !ok { + return "", fmt.Errorf("public key trans to crypto public key failed") + } + + switch pk.Type() { + case ssh.KeyAlgoRSA: + rsaPK, ok := cryptoPub.CryptoPublicKey().(*rsa.PublicKey) + if !ok { + return "", fmt.Errorf("crypto public key trans to ras publickey failed") + } + der, err = x509.MarshalPKIXPublicKey(rsaPK) + if err != nil { + return "", fmt.Errorf("MarshalPKIXPublicKey ras publickey failed") + } + default: + return "", fmt.Errorf("unsupport public key format.Only ssh-rsa supported") + } + + var ret bytes.Buffer + fp := md5.Sum(der) + for i, b := range fp { + ret.WriteString(fmt.Sprintf("%02x", b)) + if i < len(fp)-1 { + ret.WriteString(":") + } + } + + return ret.String(), nil +} + +func (self *SRegion) GetKeypairs(finger string, name string, offset int, limit int) ([]SKeypair, int, error) { + params := &ec2.DescribeKeyPairsInput{} + filters := []*ec2.Filter{} + if len(finger) > 0 { + filters = AppendSingleValueFilter(filters, "fingerprint", finger) + } + + if len(name) > 0 { + params.SetKeyNames([]*string{&name}) + } + + if len(filters) > 0 { + params.SetFilters(filters) + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, 0, errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.DescribeKeyPairs(params) + 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 +} + +// Aws貌似不支持ssh-dss格式密钥 +func (self *SRegion) ImportKeypair(name string, pubKey string) (*SKeypair, error) { + params := &ec2.ImportKeyPairInput{} + params.SetKeyName(name) + params.SetPublicKeyMaterial([]byte(pubKey)) + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.ImportKeyPair(params) + if err != nil { + return nil, errors.Wrap(err, "ImportKeyPair") + } 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) { + // https://docs.amazonaws.cn/AWSEC2/latest/UserGuide/ec2-key-pairs.html + fingerprint, err := md5Fingerprint(publicKey) + if err != nil { + return "", err + } + + 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) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/latitude_and_longitude.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/latitude_and_longitude.go new file mode 100644 index 0000000000..41fbf35d24 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/latitude_and_longitude.go @@ -0,0 +1,49 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +// https://docs.aws.amazon.com/general/latest/gr/rande.html + +var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ + "us-east-1": api.RegionNothVirginia, + "us-east-2": api.RegionOhio, + "us-west-1": api.RegionNorthCalifornia, + "us-west-2": api.RegionOregon, + "ap-south-1": api.RegionMumbai, + "ap-northeast-3": api.RegionOsaka, + "ap-northeast-2": api.RegionSeoul, + "ap-southeast-1": api.RegionSingapore, + "ap-southeast-2": api.RegionSydney, + "ap-northeast-1": api.RegionTokyo, + "ap-east-1": api.RegionHongkong, + "ca-central-1": api.RegionCanadaCentral, + "cn-north-1": api.RegionBeijing, + "cn-northwest-1": api.RegionNingxia, + "eu-central-1": api.RegionFrankfurt, + "eu-west-1": api.RegionIreland, + "eu-west-2": api.RegionLondon, + "eu-west-3": api.RegionParis, + "eu-north-1": api.RegionStockholm, + "sa-east-1": api.RegionSaoPaulo, + "us-gov-west-1": api.RegionUSGOVWest, + + "af-south-1": api.RegionCapeTown, + "me-south-1": api.RegionBahrain, +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancer.go new file mode 100644 index 0000000000..ae14e6a781 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancer.go @@ -0,0 +1,516 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "fmt" + "sort" + "strconv" + "strings" + + "github.com/aws/aws-sdk-go/service/elbv2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +/* +https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/Welcome.html +*/ + +type SElb struct { + multicloud.SResourceBase + region *SRegion + + Type string `json:"Type"` + Scheme string `json:"Scheme"` + IPAddressType string `json:"IpAddressType"` + VpcID string `json:"VpcId"` + AvailabilityZones []AvailabilityZone `json:"AvailabilityZones"` + CreatedTime string `json:"CreatedTime"` + CanonicalHostedZoneID string `json:"CanonicalHostedZoneId"` + DNSName string `json:"DNSName"` + SecurityGroups []string `json:"SecurityGroups"` + LoadBalancerName string `json:"LoadBalancerName"` + State State `json:"State"` + LoadBalancerArn string `json:"LoadBalancerArn"` +} + +type AvailabilityZone struct { + LoadBalancerAddresses []LoadBalancerAddress `json:"LoadBalancerAddresses"` + ZoneName string `json:"ZoneName"` + SubnetID string `json:"SubnetId"` +} + +type LoadBalancerAddress struct { + IPAddress string `json:"IpAddress"` + AllocationID string `json:"AllocationId"` +} + +type State struct { + Code string `json:"Code"` +} + +func (self *SElb) GetId() string { + return self.LoadBalancerArn +} + +func (self *SElb) GetName() string { + return self.LoadBalancerName +} + +func (self *SElb) GetGlobalId() string { + return self.GetId() +} + +func (self *SElb) GetStatus() string { + switch self.State.Code { + case "provisioning": + return api.LB_STATUS_INIT + case "active": + return api.LB_STATUS_ENABLED + case "failed": + return api.LB_STATUS_START_FAILED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (self *SElb) Refresh() error { + ielb, err := self.region.GetILoadBalancerById(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, ielb) + if err != nil { + return err + } + + return nil +} + +func (self *SElb) IsEmulated() bool { + return false +} + +func (self *SElb) GetSysTags() map[string]string { + data := map[string]string{} + data["loadbalance_type"] = self.Type + attrs, err := self.region.getElbAttributesById(self.GetId()) + if err != nil { + log.Errorf("SElb GetSysTags %s", err) + return data + } + + for k, v := range attrs { + data[k] = v + } + return data +} + +func (self *SElb) GetTags() (map[string]string, error) { + tags, err := self.region.FetchElbTags(self.LoadBalancerArn) + if err != nil { + return nil, errors.Wrap(err, "self.region.FetchElbTags") + } + return tags, nil +} + +func (self *SElb) GetProjectId() string { + return "" +} + +func (self *SElb) GetAddress() string { + return self.DNSName +} + +func (self *SElb) GetAddressType() string { + switch self.Scheme { + case "internal": + return api.LB_ADDR_TYPE_INTRANET + case "internet-facing": + return api.LB_ADDR_TYPE_INTERNET + default: + return api.LB_ADDR_TYPE_INTRANET + } +} + +func (self *SElb) GetNetworkType() string { + return api.LB_NETWORK_TYPE_VPC +} + +func (self *SElb) GetNetworkIds() []string { + ret := []string{} + for i := range self.AvailabilityZones { + ret = append(ret, self.AvailabilityZones[i].SubnetID) + } + + return ret +} + +func (self *SElb) GetVpcId() string { + return self.VpcID +} + +func (self *SElb) GetZoneId() string { + zones := []string{} + for i := range self.AvailabilityZones { + zones = append(zones, self.AvailabilityZones[i].ZoneName) + } + + sort.Strings(zones) + if len(zones) > 0 { + z, err := self.region.getZoneById(zones[0]) + if err != nil { + log.Infof("getZoneById %s %s", zones[0], err) + return "" + } + + return z.GetGlobalId() + } + + return "" +} + +func (self *SElb) GetZone1Id() string { + return "" +} + +func (self *SElb) GetLoadbalancerSpec() string { + return self.Type +} + +func (self *SElb) GetChargeType() string { + return api.LB_CHARGE_TYPE_BY_TRAFFIC +} + +func (self *SElb) GetEgressMbps() int { + return 0 +} + +func (self *SElb) Delete(ctx context.Context) error { + return self.region.DeleteElb(self.GetId()) +} + +func (self *SElb) Start() error { + return nil +} + +func (self *SElb) Stop() error { + return cloudprovider.ErrNotSupported +} + +func (self *SElb) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + listeners, err := self.region.GetElbListeners(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "GetElbListeners") + } + + ret := make([]cloudprovider.ICloudLoadbalancerListener, len(listeners)) + for i := range listeners { + listeners[i].lb = self + ret[i] = &listeners[i] + } + + return ret, nil +} + +func (self *SElb) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + backendgroups, err := self.region.GetElbBackendgroups(self.GetId(), nil) + if err != nil { + return nil, errors.Wrap(err, "GetElbBackendgroups") + } + + ibackendgroups := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(backendgroups)) + for i := range backendgroups { + backendgroups[i].lb = self + ibackendgroups[i] = &backendgroups[i] + } + + return ibackendgroups, nil +} + +func (self *SElb) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + backendgroup, err := self.region.CreateElbBackendgroup(group) + if err != nil { + return nil, errors.Wrap(err, "CreateElbBackendgroup") + } + + backendgroup.lb = self + return backendgroup, nil +} + +func (self *SElb) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return self.region.GetElbBackendgroup(groupId) +} + +func (self *SElb) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + ret, err := self.region.CreateElbListener(listener) + if err != nil { + return nil, errors.Wrap(err, "CreateElbListener") + } + + ret.lb = self + return ret, nil +} + +func (self *SElb) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { + if listenerId == "" { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerListenerById") + } + + return self.region.GetElbListener(listenerId) +} + +func (self *SElb) GetIEIP() (cloudprovider.ICloudEIP, error) { + return nil, nil +} + +func (self *SRegion) DeleteElb(elbId string) error { + client, err := self.GetElbV2Client() + if err != nil { + return errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DeleteLoadBalancerInput{} + params.SetLoadBalancerArn(elbId) + _, err = client.DeleteLoadBalancer(params) + if err != nil { + return errors.Wrap(err, "DeleteLoadBalancer") + } + + return nil +} + +func (self *SRegion) GetElbBackendgroups(elbId string, backendgroupIds []string) ([]SElbBackendGroup, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DescribeTargetGroupsInput{} + if len(elbId) > 0 { + params.SetLoadBalancerArn(elbId) + } + + if len(backendgroupIds) > 0 { + v := make([]*string, len(backendgroupIds)) + for i := range backendgroupIds { + v[i] = &backendgroupIds[i] + } + + params.SetTargetGroupArns(v) + } + + ret, err := client.DescribeTargetGroups(params) + if err != nil { + return nil, errors.Wrap(err, "DescribeTargetGroups") + } + + backendgroups := []SElbBackendGroup{} + err = unmarshalAwsOutput(ret, "TargetGroups", &backendgroups) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.TargetGroups") + } + + for i := range backendgroups { + backendgroups[i].region = self + } + + return backendgroups, nil +} + +func (self *SRegion) GetElbBackendgroup(backendgroupId string) (*SElbBackendGroup, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DescribeTargetGroupsInput{} + params.SetTargetGroupArns([]*string{&backendgroupId}) + + ret, err := client.DescribeTargetGroups(params) + if err != nil { + if strings.Contains(err.Error(), "TargetGroupNotFound") { + return nil, cloudprovider.ErrNotFound + } + return nil, errors.Wrap(err, "DescribeTargetGroups") + } + + backendgroups := []SElbBackendGroup{} + err = unmarshalAwsOutput(ret, "TargetGroups", &backendgroups) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.TargetGroups") + } + + if len(backendgroups) == 1 { + backendgroups[0].region = self + return &backendgroups[0], nil + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetElbBackendgroup") +} + +func ToAwsHealthCode(s string) string { + ret := []string{} + + segs := strings.Split(s, ",") + for _, seg := range segs { + if seg == api.LB_HEALTH_CHECK_HTTP_CODE_4xx && !utils.IsInStringArray("400-499", ret) { + ret = append(ret, "400-499") + } else if seg == api.LB_HEALTH_CHECK_HTTP_CODE_3xx && !utils.IsInStringArray("300-399", ret) { + ret = append(ret, "300-399") + } else if seg == api.LB_HEALTH_CHECK_HTTP_CODE_2xx && !utils.IsInStringArray("200-299", ret) { + ret = append(ret, "200-299") + } + } + + return strings.Join(ret, ",") +} + +func ToOnecloudHealthCode(s string) string { + ret := []string{} + + segs := strings.Split(s, ",") + for _, seg := range segs { + codes := strings.Split(seg, "-") + for _, code := range codes { + c, _ := strconv.Atoi(code) + if c >= 400 && !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_4xx, ret) { + ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_4xx) + } else if c >= 300 && !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_3xx, ret) { + ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_3xx) + } else if c >= 200 && !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_2xx, ret) { + ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_2xx) + } + } + + if len(codes) == 2 { + min, _ := strconv.Atoi(codes[0]) + max, _ := strconv.Atoi(codes[1]) + + if min >= 200 && max >= 400 { + if !utils.IsInStringArray(api.LB_HEALTH_CHECK_HTTP_CODE_3xx, ret) { + ret = append(ret, api.LB_HEALTH_CHECK_HTTP_CODE_3xx) + } + } + } + } + + return strings.Join(ret, ",") +} + +// 目前只支持target type :instance +func (self *SRegion) CreateElbBackendgroup(group *cloudprovider.SLoadbalancerBackendGroup) (*SElbBackendGroup, error) { + params := &elbv2.CreateTargetGroupInput{} + params.SetProtocol(strings.ToUpper(group.ListenType)) + params.SetPort(int64(group.ListenPort)) + params.SetVpcId(group.VpcId) + params.SetName(group.Name) + params.SetTargetType("instance") + if group.HealthCheck != nil { + params.SetHealthCheckPort("traffic-port") + params.SetHealthCheckProtocol(strings.ToUpper(group.HealthCheck.HealthCheckType)) + params.SetHealthCheckIntervalSeconds(int64(group.HealthCheck.HealthCheckInterval)) + params.SetHealthyThresholdCount(int64(group.HealthCheck.HealthCheckRise)) + + if len(group.HealthCheck.HealthCheckURI) > 0 { + params.SetHealthCheckPath(group.HealthCheck.HealthCheckURI) + } + + if utils.IsInStringArray(group.ListenType, []string{api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS}) { + params.SetHealthCheckTimeoutSeconds(int64(group.HealthCheck.HealthCheckTimeout)) + params.SetUnhealthyThresholdCount(int64(group.HealthCheck.HealthCheckFail)) + + codes := ToAwsHealthCode(group.HealthCheck.HealthCheckHttpCode) + if len(codes) > 0 { + matcher := &elbv2.Matcher{} + matcher.SetHttpCode(codes) + params.SetMatcher(matcher) + } + } else { + // tcp & udp 健康检查阈值与不健康阈值需相同 + params.SetUnhealthyThresholdCount(int64(group.HealthCheck.HealthCheckRise)) + } + } + + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + ret, err := client.CreateTargetGroup(params) + if err != nil { + return nil, errors.Wrap(err, "CreateTargetGroup") + } + + backendgroups := []SElbBackendGroup{} + err = unmarshalAwsOutput(ret, "TargetGroups", &backendgroups) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.TargetGroups") + } + + if len(backendgroups) == 1 { + backendgroups[0].region = self + return &backendgroups[0], nil + } + + return nil, fmt.Errorf("CreateElbBackendgroup error: %#v", backendgroups) +} + +func (self *SElb) SetTags(tags map[string]string, replace bool) error { + oldTags, err := self.region.FetchElbTags(self.LoadBalancerArn) + if err != nil { + return errors.Wrapf(err, "self.region.FetchElbTags(%s)", self.LoadBalancerArn) + } + err = self.region.UpdateResourceTags(self.LoadBalancerArn, oldTags, tags, replace) + if err != nil { + return errors.Wrap(err, "self.region.UpdateResourceTags(self.LoadBalancerArn, oldTags, tags, replace)") + } + return nil +} + +func (self *SRegion) FetchElbTags(arn string) (map[string]string, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + params := elbv2.DescribeTagsInput{} + params.SetResourceArns([]*string{&arn}) + output, err := client.DescribeTags(¶ms) + if err != nil { + return nil, errors.Wrapf(err, "client.DescribeTags(%s)", jsonutils.Marshal(params).String()) + } + result := map[string]string{} + for i := range output.TagDescriptions { + if output.TagDescriptions[i].ResourceArn != nil && *output.TagDescriptions[i].ResourceArn == arn { + for j := range output.TagDescriptions[i].Tags { + if output.TagDescriptions[i].Tags[j].Key != nil && output.TagDescriptions[i].Tags[j].Value != nil { + result[*output.TagDescriptions[i].Tags[j].Key] = *output.TagDescriptions[i].Tags[j].Value + } + } + return result, nil + } + } + return nil, cloudprovider.ErrNotFound +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerbackend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerbackend.go new file mode 100644 index 0000000000..5ed7948b78 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerbackend.go @@ -0,0 +1,114 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElbBackend struct { + multicloud.SResourceBase + AwsTags + region *SRegion + group *SElbBackendGroup + + Target Target `json:"Target"` + TargetHealth TargetHealth `json:"TargetHealth"` +} + +type Target struct { + ID string `json:"Id"` + Port int `json:"Port"` +} + +type TargetHealth struct { + State string `json:"State"` + Reason string `json:"Reason"` + Description string `json:"Description"` +} + +func (self *SElbBackend) GetId() string { + return fmt.Sprintf("%s::%s::%d", self.group.GetId(), self.Target.ID, self.Target.Port) +} + +func (self *SElbBackend) GetName() string { + return self.GetId() +} + +func (self *SElbBackend) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbBackend) Refresh() error { + return nil +} + +func (self *SElbBackend) IsEmulated() bool { + return false +} + +func (self *SElbBackend) GetProjectId() string { + return "" +} + +func (self *SElbBackend) GetWeight() int { + return 0 +} + +func (self *SElbBackend) GetPort() int { + return self.Target.Port +} + +func (self *SElbBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (self *SElbBackend) GetBackendRole() string { + return api.LB_BACKEND_ROLE_DEFAULT +} + +func (self *SElbBackend) GetBackendId() string { + return self.Target.ID +} + +func (self *SElbBackend) SyncConf(ctx context.Context, port, weight int) error { + return self.region.SyncElbBackend(self.GetId(), self.GetBackendId(), self.Target.Port, port) +} + +func (self *SElbBackend) GetIpAddress() string { + return "" +} + +func (self *SRegion) SyncElbBackend(backendId, serverId string, oldPort, newPort int) error { + err := self.RemoveElbBackend(backendId, serverId, 0, oldPort) + if err != nil { + return err + } + + _, err = self.AddElbBackend(backendId, serverId, 0, newPort) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerbackendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerbackendgroup.go new file mode 100644 index 0000000000..a97e2f4a64 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerbackendgroup.go @@ -0,0 +1,521 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElbBackendGroup struct { + multicloud.SResourceBase + AwsTags + region *SRegion + lb *SElb + + TargetGroupName string `json:"TargetGroupName"` + Protocol string `json:"Protocol"` + Port int64 `json:"Port"` + VpcID string `json:"VpcId"` + TargetType string `json:"TargetType"` + HealthyThresholdCount int `json:"HealthyThresholdCount"` + Matcher Matcher `json:"Matcher"` + UnhealthyThresholdCount int `json:"UnhealthyThresholdCount"` + HealthCheckPath string `json:"HealthCheckPath"` + HealthCheckProtocol string `json:"HealthCheckProtocol"` + HealthCheckPort string `json:"HealthCheckPort"` + HealthCheckIntervalSeconds int `json:"HealthCheckIntervalSeconds"` + HealthCheckTimeoutSeconds int `json:"HealthCheckTimeoutSeconds"` + TargetGroupArn string `json:"TargetGroupArn"` + LoadBalancerArns []string `json:"LoadBalancerArns"` +} + +func (self *SElbBackendGroup) GetLoadbalancerId() string { + if len(self.LoadBalancerArns) > 0 { + return self.LoadBalancerArns[0] + } + + return "" +} + +func (self *SElbBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { + return self.lb +} + +type Matcher struct { + HTTPCode string `json:"HttpCode"` +} + +func (self *SElbBackendGroup) GetId() string { + return self.TargetGroupArn +} + +func (self *SElbBackendGroup) GetName() string { + return self.TargetGroupName +} + +func (self *SElbBackendGroup) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbBackendGroup) Refresh() error { + lbbg, err := self.region.GetElbBackendgroup(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, lbbg) + if err != nil { + return err + } + + return nil +} + +func (self *SElbBackendGroup) IsEmulated() bool { + return false +} + +func (self *SElbBackendGroup) GetSysTags() map[string]string { + data := map[string]string{} + data["port"] = strconv.FormatInt(self.Port, 10) + data["target_type"] = self.TargetType + data["health_check_protocol"] = strings.ToLower(self.HealthCheckProtocol) + data["health_check_interval"] = strconv.Itoa(self.HealthCheckIntervalSeconds) + return data +} + +func (self *SElbBackendGroup) GetProjectId() string { + return "" +} + +func (self *SElbBackendGroup) IsDefault() bool { + return false +} + +func (self *SElbBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_NORMAL +} + +func (self *SElbBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := self.region.GetELbBackends(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "GetELbBackends") + } + + ibackends := make([]cloudprovider.ICloudLoadbalancerBackend, len(backends)) + for i := range backends { + backends[i].region = self.region + backends[i].group = self + ibackends[i] = &backends[i] + } + + return ibackends, nil +} + +func (self *SElbBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + backend, err := self.region.GetELbBackend(backendId) + if err != nil { + return nil, errors.Wrap(err, "GetELbBackend") + } + + backend.group = self + return backend, nil +} + +func (self *SElbBackendGroup) GetProtocolType() string { + switch self.Protocol { + case "TCP": + return api.LB_LISTENER_TYPE_TCP + case "UDP": + return api.LB_LISTENER_TYPE_UDP + case "HTTP": + return api.LB_LISTENER_TYPE_HTTP + case "HTTPS": + return api.LB_LISTENER_TYPE_HTTPS + case "TCP_UDP": + return api.LB_LISTENER_TYPE_TCP_UDP + default: + return "" + } +} + +func (self *SElbBackendGroup) GetScheduler() string { + return "" +} + +func (self *SElbBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + health := &cloudprovider.SLoadbalancerHealthCheck{} + health.HealthCheck = api.LB_BOOL_ON + health.HealthCheckRise = self.HealthyThresholdCount + health.HealthCheckFail = self.UnhealthyThresholdCount + health.HealthCheckInterval = self.HealthCheckIntervalSeconds + health.HealthCheckURI = self.HealthCheckPath + health.HealthCheckType = strings.ToLower(self.HealthCheckProtocol) + health.HealthCheckTimeout = self.HealthCheckTimeoutSeconds + health.HealthCheckHttpCode = ToOnecloudHealthCode(self.Matcher.HTTPCode) + return health, nil +} + +func (self *SElbBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + attrs, err := self.region.GetElbBackendgroupAttributesById(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "GetElbBackendgroupAttributesById") + } + + cookieTime := 0 + if t, ok := attrs["stickiness.lb_cookie.duration_seconds"]; !ok { + cookieTime, err = strconv.Atoi(t) + } + + ret := &cloudprovider.SLoadbalancerStickySession{ + StickySession: attrs["stickiness.enabled"], + StickySessionCookie: "", + StickySessionType: api.LB_STICKY_SESSION_TYPE_INSERT, + StickySessionCookieTimeout: cookieTime, + } + + return ret, nil +} + +func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + backend, err := self.region.AddElbBackend(self.GetId(), serverId, weight, port) + if err != nil { + return nil, errors.Wrap(err, "AddElbBackend") + } + + backend.region = self.region + backend.group = self + return backend, nil +} + +func (self *SElbBackendGroup) RemoveBackendServer(serverId string, weight int, port int) error { + return self.region.RemoveElbBackend(self.GetId(), serverId, weight, port) +} + +func (self *SElbBackendGroup) Delete(ctx context.Context) error { + return self.region.DeleteElbBackendGroup(self.GetId()) +} + +func (self *SElbBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + return self.region.SyncELbBackendGroup(self.GetId(), group) +} + +func (self *SRegion) GetELbBackends(backendgroupId string) ([]SElbBackend, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + group, err := self.GetElbBackendgroup(backendgroupId) + if err != nil { + return nil, errors.Wrap(err, "GetElbBackendgroup") + } + + params := &elbv2.DescribeTargetHealthInput{} + params.SetTargetGroupArn(backendgroupId) + output, err := client.DescribeTargetHealth(params) + if err != nil { + return nil, errors.Wrap(err, "DescribeTargetHealth") + } + + backends := []SElbBackend{} + err = unmarshalAwsOutput(output, "TargetHealthDescriptions", &backends) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.TargetHealthDescriptions") + } + + ret := []SElbBackend{} + for i := range backends { + if !utils.IsInStringArray(backends[i].TargetHealth.Reason, []string{"Target.InvalidState", "Target.NotInUse", "Target.DeregistrationInProgress"}) { + backends[i].region = self + backends[i].group = group + ret = append(ret, backends[i]) + } + } + + return ret, nil +} + +func (self *SRegion) GetELbBackend(backendId string) (*SElbBackend, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + groupId, instanceId, port, err := parseElbBackendId(backendId) + if err != nil { + log.Errorf("parseElbBackendId %s: %s", backendId, err) + return nil, errors.Wrap(err, "parseElbBackendId") + } + + params := &elbv2.DescribeTargetHealthInput{} + desc := &elbv2.TargetDescription{} + desc.SetPort(int64(port)) + desc.SetId(instanceId) + params.SetTargets([]*elbv2.TargetDescription{desc}) + params.SetTargetGroupArn(groupId) + ret, err := client.DescribeTargetHealth(params) + if err != nil { + return nil, errors.Wrap(err, "DescribeTargetHealth") + } + + backends := []SElbBackend{} + err = unmarshalAwsOutput(ret, "TargetHealthDescriptions", &backends) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.TargetHealthDescriptions") + } + + if len(backends) == 1 { + backends[0].region = self + return &backends[0], nil + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetELbBackend") +} + +func parseElbBackendId(id string) (string, string, int, error) { + segs := strings.Split(id, "::") + if len(segs) != 3 { + return "", "", 0, fmt.Errorf("%s is not a valid backend id", id) + } + + port, err := strconv.Atoi(segs[2]) + if err != nil { + return "", "", 0, fmt.Errorf("%s is not a valid backend id, %s", id, err) + } + + return segs[0], segs[1], port, nil +} + +func genElbBackendId(backendgroupId string, serverId string, port int) string { + return strings.Join([]string{backendgroupId, serverId, strconv.Itoa(port)}, "::") +} + +func (self *SRegion) AddElbBackend(backendgroupId, serverId string, weight int, port int) (*SElbBackend, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.RegisterTargetsInput{} + params.SetTargetGroupArn(backendgroupId) + desc := &elbv2.TargetDescription{} + desc.SetId(serverId) + desc.SetPort(int64(port)) + params.SetTargets([]*elbv2.TargetDescription{desc}) + _, err = client.RegisterTargets(params) + if err != nil { + return nil, errors.Wrap(err, "RegisterTargets") + } + + return self.GetELbBackend(genElbBackendId(backendgroupId, serverId, port)) +} + +func (self *SRegion) RemoveElbBackend(backendgroupId, serverId string, weight int, port int) error { + client, err := self.GetElbV2Client() + if err != nil { + return errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DeregisterTargetsInput{} + params.SetTargetGroupArn(backendgroupId) + desc := &elbv2.TargetDescription{} + desc.SetId(serverId) + desc.SetPort(int64(port)) + params.SetTargets([]*elbv2.TargetDescription{desc}) + _, err = client.DeregisterTargets(params) + if err != nil { + return errors.Wrap(err, "DeregisterTargets") + } + + return nil +} + +func (self *SRegion) DeleteElbBackendGroup(backendgroupId string) error { + client, err := self.GetElbV2Client() + if err != nil { + return errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DeleteTargetGroupInput{} + params.SetTargetGroupArn(backendgroupId) + _, err = client.DeleteTargetGroup(params) + if err != nil { + return errors.Wrap(err, "DeleteTargetGroup") + } + + return nil +} + +func (self *SRegion) SyncELbBackendGroup(backendgroupId string, group *cloudprovider.SLoadbalancerBackendGroup) error { + err := self.modifyELbBackendGroup(backendgroupId, group.HealthCheck) + if err != nil { + return errors.Wrap(err, "modifyELbBackendGroup") + } + + err = self.RemoveElbBackends(backendgroupId) + if err != nil { + log.Errorf("RemoveElbBackends %s: %s", backendgroupId, err) + return errors.Wrap(err, "RemoveElbBackends") + } + + return self.AddElbBackends(backendgroupId, group.Backends) +} + +func (self *SRegion) modifyELbBackendGroup(backendgroupId string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) error { + client, err := self.GetElbV2Client() + if err != nil { + return err + } + + params := &elbv2.ModifyTargetGroupInput{} + params.SetTargetGroupArn(backendgroupId) + params.SetHealthCheckProtocol(strings.ToUpper(healthCheck.HealthCheckType)) + params.SetHealthyThresholdCount(int64(healthCheck.HealthCheckRise)) + + if utils.IsInStringArray(healthCheck.HealthCheckType, []string{api.LB_HEALTH_CHECK_HTTP, api.LB_LISTENER_TYPE_HTTPS}) { + params.SetUnhealthyThresholdCount(int64(healthCheck.HealthCheckFail)) + params.SetHealthCheckTimeoutSeconds(int64(healthCheck.HealthCheckTimeout)) + params.SetHealthCheckIntervalSeconds(int64(healthCheck.HealthCheckInterval)) + if len(healthCheck.HealthCheckURI) > 0 { + params.SetHealthCheckPath(healthCheck.HealthCheckURI) + } + + codes := ToAwsHealthCode(healthCheck.HealthCheckHttpCode) + if len(codes) > 0 { + matcher := &elbv2.Matcher{} + matcher.SetHttpCode(codes) + params.SetMatcher(matcher) + } + } + + _, err = client.ModifyTargetGroup(params) + if err != nil { + return errors.Wrap(err, "ModifyTargetGroup") + } + + return nil +} + +func (self *SRegion) RemoveElbBackends(backendgroupId string) error { + client, err := self.GetElbV2Client() + if err != nil { + return err + } + + backends, err := self.GetELbBackends(backendgroupId) + if err != nil { + return errors.Wrap(err, "GetELbBackends") + } + + if len(backends) == 0 { + return nil + } + + targets := []*elbv2.TargetDescription{} + for i := range backends { + target := &elbv2.TargetDescription{} + target.SetId(backends[i].GetBackendId()) + target.SetPort(int64(backends[i].GetPort())) + targets = append(targets, target) + } + + params := &elbv2.DeregisterTargetsInput{} + params.SetTargetGroupArn(backendgroupId) + params.SetTargets(targets) + _, err = client.DeregisterTargets(params) + if err != nil { + return errors.Wrap(err, "DeregisterTargets") + } + + return nil +} + +func (self *SRegion) AddElbBackends(backendgroupId string, backends []cloudprovider.SLoadbalancerBackend) error { + client, err := self.GetElbV2Client() + if err != nil { + return err + } + + if len(backends) == 0 { + return nil + } + + params := &elbv2.RegisterTargetsInput{} + params.SetTargetGroupArn(backendgroupId) + targets := []*elbv2.TargetDescription{} + for i := range backends { + desc := &elbv2.TargetDescription{} + desc.SetId(backends[i].ExternalID) + desc.SetPort(int64(backends[i].Port)) + targets = append(targets, desc) + } + + params.SetTargets(targets) + _, err = client.RegisterTargets(params) + if err != nil { + return errors.Wrap(err, "RegisterTargets") + } + + return nil +} + +func (self *SRegion) GetElbBackendgroupAttributesById(backendgroupId string) (map[string]string, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DescribeTargetGroupAttributesInput{} + params.SetTargetGroupArn(backendgroupId) + + output, err := client.DescribeTargetGroupAttributes(params) + if err != nil { + return nil, errors.Wrap(err, "DescribeTargetGroupAttributes") + } + + attrs := []map[string]string{} + err = unmarshalAwsOutput(output, "Attributes", &attrs) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.Attributes") + } + + ret := map[string]string{} + for i := range attrs { + for k, v := range attrs[i] { + ret[k] = v + } + } + + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancercert.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancercert.go new file mode 100644 index 0000000000..5a87ef8503 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancercert.go @@ -0,0 +1,199 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "crypto/sha1" + "crypto/x509" + "encoding/pem" + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go/service/iam" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElbCertificate struct { + multicloud.SResourceBase + AwsTags + region *SRegion + cert *x509.Certificate + + Path string `json:"Path"` + ServerCertificateName string `json:"ServerCertificateName"` + ServerCertificateID string `json:"ServerCertificateId"` + Arn string `json:"Arn"` + UploadDate time.Time `json:"UploadDate"` + Expiration time.Time `json:"Expiration"` + PublicKey string +} + +func (self *SElbCertificate) GetId() string { + return self.Arn +} + +func (self *SElbCertificate) GetName() string { + return self.ServerCertificateName +} + +func (self *SElbCertificate) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbCertificate) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbCertificate) Refresh() error { + icert, err := self.region.GetILoadBalancerCertificateById(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, icert) + if err != nil { + return err + } + + return nil +} + +func (self *SElbCertificate) IsEmulated() bool { + return false +} + +func (self *SElbCertificate) GetProjectId() string { + return "" +} + +func (self *SElbCertificate) Sync(name, privateKey, publickKey string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SElbCertificate) Delete() error { + return self.region.deleteElbCertificate(self.GetName()) +} + +func (self *SElbCertificate) GetCommonName() string { + cert, err := self.ParsePublicKey() + if err != nil { + return "" + } + + return cert.Issuer.CommonName +} + +func (self *SElbCertificate) GetSubjectAlternativeNames() string { + // todo: fix me + _, err := self.ParsePublicKey() + if err != nil { + return "" + } + + return "" +} + +func (self *SElbCertificate) GetFingerprint() string { + publicKey := self.GetPublickKey() + if len(publicKey) == 0 { + return "" + } + + _fp := sha1.Sum([]byte(publicKey)) + fp := fmt.Sprintf("sha1:% x", _fp) + return strings.Replace(fp, " ", ":", -1) +} + +func (self *SElbCertificate) GetExpireTime() time.Time { + return self.Expiration +} + +func (self *SElbCertificate) GetPublickKey() string { + if self.PublicKey == "" { + ret, err := self.region.getPublicKey(self.GetName()) + if err != nil { + log.Errorf("GetPublickKey %s", err) + return "" + } + + self.PublicKey = ret + } + + return self.PublicKey +} + +func (self *SElbCertificate) GetPrivateKey() string { + return "" +} + +func (self *SElbCertificate) ParsePublicKey() (*x509.Certificate, error) { + if self.cert != nil { + return self.cert, nil + } + + publicKey := self.GetPublickKey() + if len(publicKey) == 0 { + return nil, fmt.Errorf("SElbCertificate ParsePublicKey public key is empty") + } + + block, _ := pem.Decode([]byte(publicKey)) + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, errors.Wrap(err, "ParseCertificate") + } + + self.cert = cert + return cert, nil +} + +func (self *SRegion) getPublicKey(certName string) (string, error) { + client, err := self.getIamClient() + if err != nil { + return "", err + } + + params := &iam.GetServerCertificateInput{} + params.SetServerCertificateName(certName) + ret, err := client.GetServerCertificate(params) + if err != nil { + return "", err + } + + return StrVal(ret.ServerCertificate.CertificateBody), nil +} + +func (self *SRegion) deleteElbCertificate(certName string) error { + client, err := self.getIamClient() + if err != nil { + return err + } + + params := &iam.DeleteServerCertificateInput{} + params.SetServerCertificateName(certName) + _, err = client.DeleteServerCertificate(params) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerlistener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerlistener.go new file mode 100644 index 0000000000..2d22cdeb93 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerlistener.go @@ -0,0 +1,768 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "encoding/json" + "fmt" + "strconv" + "strings" + "time" + + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElbListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + AwsTags + region *SRegion + lb *SElb + group *SElbBackendGroup + + Port int `json:"Port"` + Protocol string `json:"Protocol"` + DefaultActions []DefaultAction `json:"DefaultActions"` + SSLPolicy string `json:"SslPolicy"` + Certificates []Certificate `json:"Certificates"` + LoadBalancerArn string `json:"LoadBalancerArn"` + ListenerArn string `json:"ListenerArn"` +} + +type Certificate struct { + CertificateArn string `json:"CertificateArn"` +} + +type DefaultAction struct { + TargetGroupArn string `json:"TargetGroupArn"` + Type string `json:"Type"` +} + +func (self *SElbListener) GetId() string { + return self.ListenerArn +} + +func (self *SElbListener) GetName() string { + segs := strings.Split(self.ListenerArn, "/") + return segs[len(segs)-1] +} + +func (self *SElbListener) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbListener) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbListener) Refresh() error { + listener, err := self.region.GetElbListener(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, listener) + if err != nil { + return err + } + + return nil +} + +func (self *SElbListener) IsEmulated() bool { + return false +} + +func (self *SElbListener) GetProjectId() string { + return "" +} + +func (self *SElbListener) GetListenerType() string { + switch self.Protocol { + case "TCP": + return api.LB_LISTENER_TYPE_TCP + case "UDP": + return api.LB_LISTENER_TYPE_UDP + case "HTTP": + return api.LB_LISTENER_TYPE_HTTP + case "HTTPS": + return api.LB_LISTENER_TYPE_HTTPS + case "TCP_SSL": + return api.LB_LISTENER_TYPE_TCP + case "TCP_UDP": + return api.LB_LISTENER_TYPE_TCP_UDP + default: + return "" + } +} + +func (self *SElbListener) GetListenerPort() int { + return self.Port +} + +func (self *SElbListener) GetScheduler() string { + // api.LB_SCHEDULER_RR ? + return "" +} + +func (self *SElbListener) GetAclStatus() string { + return api.LB_BOOL_OFF +} + +func (self *SElbListener) GetAclType() string { + return "" +} + +func (self *SElbListener) GetAclId() string { + return "" +} + +func (self *SElbListener) GetEgressMbps() int { + return 0 +} + +func (self *SElbListener) GetHealthCheck() string { + group, err := self.getBackendGroup() + if err != nil { + return "" + } + + health, err := group.GetHealthCheck() + if err != nil { + return "" + } + + return health.HealthCheck +} + +func (self *SElbListener) getBackendGroup() (*SElbBackendGroup, error) { + if self.group != nil { + return self.group, nil + } + + lbbg, err := self.region.GetElbBackendgroup(self.DefaultActions[0].TargetGroupArn) + if err != nil { + return nil, errors.Wrap(err, "GetElbBackendgroup") + } + + self.group = lbbg + return self.group, nil +} + +func (self *SElbListener) GetHealthCheckType() string { + group, err := self.getBackendGroup() + if err != nil { + return "" + } + + health, err := group.GetHealthCheck() + if err != nil { + return "" + } + + return health.HealthCheckType +} + +func (self *SElbListener) GetHealthCheckTimeout() int { + group, err := self.getBackendGroup() + if err != nil { + return 0 + } + + health, err := group.GetHealthCheck() + if err != nil { + return 0 + } + + return health.HealthCheckTimeout +} + +func (self *SElbListener) GetHealthCheckInterval() int { + group, err := self.getBackendGroup() + if err != nil { + return 0 + } + + health, err := group.GetHealthCheck() + if err != nil { + return 0 + } + + return health.HealthCheckInterval +} + +func (self *SElbListener) GetHealthCheckRise() int { + group, err := self.getBackendGroup() + if err != nil { + return 0 + } + + health, err := group.GetHealthCheck() + if err != nil { + return 0 + } + + return health.HealthCheckRise +} + +func (self *SElbListener) GetHealthCheckFail() int { + group, err := self.getBackendGroup() + if err != nil { + return 0 + } + + health, err := group.GetHealthCheck() + if err != nil { + return 0 + } + + return health.HealthCheckFail +} + +func (self *SElbListener) GetHealthCheckReq() string { + group, err := self.getBackendGroup() + if err != nil { + return "" + } + + health, err := group.GetHealthCheck() + if err != nil { + return "" + } + + return health.HealthCheckReq +} + +func (self *SElbListener) GetHealthCheckExp() string { + group, err := self.getBackendGroup() + if err != nil { + return "" + } + + health, err := group.GetHealthCheck() + if err != nil { + return "" + } + + return health.HealthCheckExp +} + +func (self *SElbListener) GetBackendGroupId() string { + return self.DefaultActions[0].TargetGroupArn +} + +func (self *SElbListener) GetBackendServerPort() int { + return 0 +} + +func (self *SElbListener) GetHealthCheckDomain() string { + group, err := self.getBackendGroup() + if err != nil { + return "" + } + + health, err := group.GetHealthCheck() + if err != nil { + return "" + } + + return health.HealthCheckDomain +} + +func (self *SElbListener) GetHealthCheckURI() string { + group, err := self.getBackendGroup() + if err != nil { + return "" + } + + health, err := group.GetHealthCheck() + if err != nil { + return "" + } + + return health.HealthCheckURI +} + +func (self *SElbListener) GetHealthCheckCode() string { + group, err := self.getBackendGroup() + if err != nil { + return "" + } + + health, err := group.GetHealthCheck() + if err != nil { + return "" + } + + return health.HealthCheckHttpCode +} + +func (self *SElbListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + rules, err := self.GetILoadbalancerListenerRules() + if err != nil { + return nil, errors.Wrap(err, "GetILoadbalancerListenerRules") + } else { + if err := self.region.UpdateRulesPriority(rules); err != nil { + return nil, errors.Wrap(err, "UpdateRulesPriority") + } + } + + ret, err := self.region.CreateElbListenerRule(self.GetId(), rule) + if err != nil { + return nil, errors.Wrap(err, "CreateElbListenerRule") + } + + ret.listener = self + ret.region = self.region + return ret, nil +} + +func (self *SElbListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + rule, err := self.region.GetElbListenerRuleById(ruleId) + if err != nil { + return nil, errors.Wrap(err, "GetElbListenerRuleById") + } + + rule.listener = self + return rule, nil +} + +func (self *SElbListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + rules, err := self.region.GetElbListenerRules(self.GetId(), "") + if err != nil { + return nil, errors.Wrap(err, "GetElbListenerRules") + } + + irules := make([]cloudprovider.ICloudLoadbalancerListenerRule, len(rules)) + for i := range rules { + rules[i].listener = self + irules[i] = &rules[i] + } + + return irules, nil +} + +func (self *SElbListener) GetStickySession() string { + group, err := self.getBackendGroup() + if err != nil { + return "" + } + + session, err := group.GetStickySession() + if err != nil { + return "" + } + + return session.StickySession +} + +func (self *SElbListener) GetStickySessionType() string { + group, err := self.getBackendGroup() + if err != nil { + return "" + } + + session, err := group.GetStickySession() + if err != nil { + return "" + } + + return session.StickySessionType +} + +func (self *SElbListener) GetStickySessionCookie() string { + group, err := self.getBackendGroup() + if err != nil { + return "" + } + + session, err := group.GetStickySession() + if err != nil { + return "" + } + + return session.StickySessionCookie +} + +func (self *SElbListener) GetStickySessionCookieTimeout() int { + group, err := self.getBackendGroup() + if err != nil { + return 0 + } + + session, err := group.GetStickySession() + if err != nil { + return 0 + } + + return session.StickySessionCookieTimeout +} + +func (self *SElbListener) XForwardedForEnabled() bool { + return false +} + +func (self *SElbListener) GzipEnabled() bool { + return false +} + +func (self *SElbListener) GetCertificateId() string { + if len(self.Certificates) > 0 { + return self.Certificates[0].CertificateArn + } + + return "" +} + +func (self *SElbListener) GetTLSCipherPolicy() string { + return self.SSLPolicy +} + +func (self *SElbListener) HTTP2Enabled() bool { + return false +} + +func (self *SElbListener) GetClientIdleTimeout() int { + return 0 +} + +func (self *SElbListener) GetBackendConnectTimeout() int { + return 0 +} + +func (self *SElbListener) Start() error { + return nil +} + +func (self *SElbListener) Stop() error { + return cloudprovider.ErrNotSupported +} + +func (self *SElbListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { + return self.region.SyncElbListener(self, listener) +} + +func (self *SElbListener) Delete(ctx context.Context) error { + return self.region.DeleteElbListener(self.GetId()) +} + +func (self *SRegion) GetElbListeners(elbId string) ([]SElbListener, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DescribeListenersInput{} + params.SetLoadBalancerArn(elbId) + ret, err := client.DescribeListeners(params) + if err != nil { + return nil, errors.Wrap(err, "DescribeListeners") + } + + listeners := []SElbListener{} + err = unmarshalAwsOutput(ret, "Listeners", &listeners) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.Listeners") + } + + for i := range listeners { + listeners[i].region = self + } + + return listeners, nil +} + +func unmarshalAwsOutput(output interface{}, respKey string, result interface{}) error { + _ret, err := json.Marshal(output) + if err != nil { + return err + } + + obj, err := jsonutils.Parse(_ret) + if err != nil { + return err + } + + if len(respKey) == 0 { + err = obj.Unmarshal(result) + if err != nil { + return err + } + } else { + err = obj.Unmarshal(result, respKey) + if err != nil { + return err + } + } + + return nil +} + +func (self *SRegion) GetElbListener(listenerId string) (*SElbListener, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DescribeListenersInput{} + params.SetListenerArns([]*string{&listenerId}) + ret, err := client.DescribeListeners(params) + if err != nil { + return nil, errors.Wrap(err, "DescribeListeners") + } + + listeners := []SElbListener{} + err = unmarshalAwsOutput(ret, "Listeners", &listeners) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.Listeners") + } + + if len(listeners) == 1 { + listeners[0].region = self + return &listeners[0], nil + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetElbListener") +} + +func (self *SRegion) CreateElbListener(listener *cloudprovider.SLoadbalancerListener) (*SElbListener, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + listenerType := strings.ToUpper(listener.ListenerType) + params := &elbv2.CreateListenerInput{} + params.SetLoadBalancerArn(listener.LoadbalancerID) + params.SetPort(int64(listener.ListenerPort)) + params.SetProtocol(listenerType) + action := &elbv2.Action{} + action.SetType("forward") + action.SetTargetGroupArn(listener.BackendGroupID) + params.SetDefaultActions([]*elbv2.Action{action}) + if listenerType == "HTTPS" { + cert := &elbv2.Certificate{ + CertificateArn: &listener.CertificateID, + } + + params.SetCertificates([]*elbv2.Certificate{cert}) + params.SetSslPolicy("ELBSecurityPolicy-2016-08") + } + + ret, err := client.CreateListener(params) + if err != nil { + // aws 比较诡异,证书能查询到,但是如果立即创建会报错,这里只能等待一会重试 + time.Sleep(10 * time.Second) + if strings.Contains(err.Error(), "CertificateNotFound") { + ret, err = client.CreateListener(params) + if err != nil { + return nil, errors.Wrap(err, "Region.CreateElbListener.Retry") + } + } else { + return nil, errors.Wrap(err, "Region.CreateElbListener") + } + } + + listeners := []SElbListener{} + err = unmarshalAwsOutput(ret, "Listeners", &listeners) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.Listeners") + } + + if len(listeners) == 1 { + listeners[0].region = self + return &listeners[0], nil + } + + return nil, fmt.Errorf("CreateElbListener err %#v", listeners) +} + +func (self *SRegion) GetElbListenerRules(listenerId string, ruleId string) ([]SElbListenerRule, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DescribeRulesInput{} + if len(listenerId) > 0 { + params.SetListenerArn(listenerId) + } + + if len(ruleId) > 0 { + params.SetRuleArns([]*string{&ruleId}) + } + + ret, err := client.DescribeRules(params) + if err != nil { + return nil, errors.Wrap(err, "DescribeRules") + } + + rules := []SElbListenerRule{} + err = unmarshalAwsOutput(ret, "Rules", &rules) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.Rules") + } + + for i := range rules { + rules[i].region = self + } + + return rules, nil +} + +func (self *SRegion) GetElbListenerRuleById(ruleId string) (*SElbListenerRule, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DescribeRulesInput{} + if len(ruleId) > 0 { + params.SetRuleArns([]*string{&ruleId}) + } + + ret, err := client.DescribeRules(params) + if err != nil { + return nil, errors.Wrap(err, "DescribeRules") + } + + rules := []SElbListenerRule{} + err = unmarshalAwsOutput(ret, "Rules", &rules) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.Rules") + } + + if len(rules) == 1 { + rules[0].region = self + return &rules[0], nil + } else { + log.Errorf("GetElbListenerRuleById %s %d found", ruleId, len(rules)) + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetElbListenerRuleById") + } +} + +func (self *SRegion) DeleteElbListener(listenerId string) error { + client, err := self.GetElbV2Client() + if err != nil { + return err + } + + params := &elbv2.DeleteListenerInput{} + params.SetListenerArn(listenerId) + _, err = client.DeleteListener(params) + if err != nil { + return err + } + + return nil +} + +func (self *SRegion) SyncElbListener(listener *SElbListener, config *cloudprovider.SLoadbalancerListener) error { + client, err := self.GetElbV2Client() + if err != nil { + return err + } + + params := &elbv2.ModifyListenerInput{} + params.SetListenerArn(listener.GetId()) + params.SetPort(int64(config.ListenerPort)) + params.SetProtocol(strings.ToUpper(config.ListenerType)) + action := &elbv2.Action{} + action.SetType("forward") + action.SetTargetGroupArn(config.BackendGroupID) + params.SetDefaultActions([]*elbv2.Action{action}) + + if config.ListenerType == api.LB_LISTENER_TYPE_HTTPS { + cert := &elbv2.Certificate{} + cert.SetCertificateArn(config.CertificateID) + params.SetCertificates([]*elbv2.Certificate{cert}) + } + + _, err = client.ModifyListener(params) + if err != nil { + if strings.Contains(err.Error(), "CertificateNotFound") { + // aws 比较诡异,证书能查询到,但是如果立即创建会报错,这里只能等待一会重试 + time.Sleep(10 * time.Second) + _, err = client.ModifyListener(params) + if err != nil { + return errors.Wrap(err, "SRegion.SyncElbListener.ModifyListener.Retry") + } + } + + return errors.Wrap(err, "SRegion.SyncElbListener.ModifyListener") + } + + hc := &cloudprovider.SLoadbalancerHealthCheck{ + HealthCheckType: config.HealthCheckType, + HealthCheckReq: config.HealthCheckReq, + HealthCheckExp: config.HealthCheckExp, + HealthCheck: config.HealthCheck, + HealthCheckTimeout: config.HealthCheckTimeout, + HealthCheckDomain: config.HealthCheckDomain, + HealthCheckHttpCode: config.HealthCheckHttpCode, + HealthCheckURI: config.HealthCheckURI, + HealthCheckInterval: config.HealthCheckInterval, + HealthCheckRise: config.HealthCheckRise, + HealthCheckFail: config.HealthCheckFail, + } + err = self.modifyELbBackendGroup(config.BackendGroupID, hc) + if err != nil { + return errors.Wrap(err, "region.SyncElbListener.updateELbBackendGroup") + } + + return nil +} + +func (self *SRegion) UpdateRulesPriority(rules []cloudprovider.ICloudLoadbalancerListenerRule) error { + client, err := self.GetElbV2Client() + if err != nil { + return err + } + + ps := []*elbv2.RulePriorityPair{} + for i := range rules { + rule := rules[i].(*SElbListenerRule) + if !rule.IsDefaultRule { + v, _ := strconv.Atoi(rule.Priority) + p := &elbv2.RulePriorityPair{} + p.SetRuleArn(rules[i].GetId()) + p.SetPriority(int64(v + 1)) + + ps = append(ps, p) + } + } + + if len(ps) == 0 { + return nil + } + + params := &elbv2.SetRulePrioritiesInput{} + params.SetRulePriorities(ps) + _, err = client.SetRulePriorities(params) + if err != nil { + return err + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerlistenerrule.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerlistenerrule.go new file mode 100644 index 0000000000..fb18b3faf9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/loadbalancerlistenerrule.go @@ -0,0 +1,490 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "encoding/json" + "fmt" + "strings" + + "github.com/aws/aws-sdk-go/service/elbv2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElbListenerRule struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + AwsTags + listener *SElbListener + region *SRegion + + Priority string `json:"Priority"` + IsDefaultRule bool `json:"IsDefault"` + Actions []Action `json:"Actions"` + RuleArn string `json:"RuleArn"` + Conditions []Condition `json:"Conditions"` +} + +type Action struct { + TargetGroupArn string `json:"TargetGroupArn"` + Type string `json:"Type"` +} + +type Condition struct { + Field string `json:"field"` + HTTPRequestMethodConfig *Config `json:"httpRequestMethodConfig,omitempty"` + Values []string `json:"values"` + SourceIPConfig *Config `json:"sourceIpConfig,omitempty"` + QueryStringConfig *QueryStringConfig `json:"queryStringConfig,omitempty"` + HTTPHeaderConfig *HTTPHeaderConfig `json:"httpHeaderConfig,omitempty"` + PathPatternConfig *Config `json:"pathPatternConfig,omitempty"` + HostHeaderConfig *Config `json:"hostHeaderConfig,omitempty"` +} + +type HTTPHeaderConfig struct { + HTTPHeaderName string `json:"HttpHeaderName"` + Values []string `json:"values"` +} + +type Config struct { + Values []string `json:"values"` +} + +type QueryStringConfig struct { + Values []Query `json:"values"` +} + +type Query struct { + Key string `json:"key"` + Value string `json:"value"` +} + +func (self *SElbListenerRule) GetId() string { + return self.RuleArn +} + +func (self *SElbListenerRule) GetName() string { + segs := strings.Split(self.RuleArn, "/") + return segs[len(segs)-1] +} + +func (self *SElbListenerRule) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbListenerRule) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbListenerRule) Refresh() error { + rule, err := self.region.GetElbListenerRuleById(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, rule) + if err != nil { + return err + } + + return nil +} + +func (self *SElbListenerRule) IsDefault() bool { + return self.IsDefaultRule +} + +func (self *SElbListenerRule) IsEmulated() bool { + return false +} + +func (self *SElbListenerRule) GetProjectId() string { + return "" +} + +func (self *SElbListenerRule) GetDomain() string { + for _, condition := range self.Conditions { + if condition.Field == "host-header" { + return strings.Join(condition.Values, ",") + } + } + + return "" +} + +func (self *SElbListenerRule) GetCondition() string { + conditon, err := json.Marshal(self.Conditions) + if err != nil { + log.Errorf("GetCondition %s", err) + return "" + } + + return string(conditon) +} + +func (self *SElbListenerRule) GetPath() string { + for _, condition := range self.Conditions { + if condition.Field == "path-pattern" { + return strings.Join(condition.Values, ",") + } + } + + return "" +} + +func (self *SElbListenerRule) GetBackendGroupId() string { + for _, action := range self.Actions { + if action.Type == "forward" { + return action.TargetGroupArn + } + } + + return "" +} + +func (self *SElbListenerRule) Delete(ctx context.Context) error { + return self.region.DeleteElbListenerRule(self.GetId()) +} + +func (self *SRegion) DeleteElbListenerRule(ruleId string) error { + client, err := self.GetElbV2Client() + if err != nil { + return err + } + + params := &elbv2.DeleteRuleInput{} + params.SetRuleArn(ruleId) + _, err = client.DeleteRule(params) + if err != nil { + return err + } + + return nil +} + +func (self *SRegion) CreateElbListenerRule(listenerId string, config *cloudprovider.SLoadbalancerListenerRule) (*SElbListenerRule, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + forward := "forward" + action := &elbv2.Action{ + TargetGroupArn: &config.BackendGroupID, + Type: &forward, + } + + condtions, err := parseConditions(config.Condition) + if err != nil { + return nil, errors.Wrap(err, "parseConditions") + } + + params := &elbv2.CreateRuleInput{} + params.SetListenerArn(listenerId) + params.SetActions([]*elbv2.Action{action}) + params.SetConditions(condtions) + params.SetPriority(int64(1)) + ret, err := client.CreateRule(params) + if err != nil { + return nil, errors.Wrap(err, "CreateRule") + } + + if len(ret.Rules) == 0 { + return nil, errors.Wrap(fmt.Errorf("empty rules"), "Region.CreateElbListenerRule.len") + } + + rule := SElbListenerRule{} + err = unmarshalAwsOutput(ret.Rules[0], "", &rule) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.rule") + } + + rule.region = self + return &rule, nil +} + +func parseConditions(conditions string) ([]*elbv2.RuleCondition, error) { + obj, err := jsonutils.ParseString(conditions) + if err != nil { + return nil, errors.Wrap(err, "ParseString.conditions") + } + + conditionArray, ok := obj.(*jsonutils.JSONArray) + if !ok { + return nil, fmt.Errorf("parseConditions invalid condition fromat.") + } + + ret := []*elbv2.RuleCondition{} + cs, _ := conditionArray.GetArray() + for i := range cs { + c, err := parseCondition(cs[i]) + if err != nil { + return nil, errors.Wrap(err, "parseCondition") + } + + ret = append(ret, c) + } + + return ret, nil +} + +func parseCondition(condition jsonutils.JSONObject) (*elbv2.RuleCondition, error) { + conditionDict, ok := condition.(*jsonutils.JSONDict) + if !ok { + return nil, fmt.Errorf("parseCondition invalid condition fromat.") + } + + dict, _ := conditionDict.GetMap() + field, ok := dict["field"] + if !ok { + return nil, fmt.Errorf("parseCondition invalid condition, missing field: %#v", condition) + } + + f, _ := field.GetString() + switch f { + case "http-header": + return parseHttpHeaderCondition(conditionDict) + case "path-pattern": + return parsePathPatternCondition(conditionDict) + case "http-request-method": + return parseRequestModthdCondition(conditionDict) + case "host-header": + return parseHostHeaderCondition(conditionDict) + case "query-string": + return parseQueryStringCondition(conditionDict) + case "source-ip": + return parseSourceIpCondition(conditionDict) + default: + return nil, fmt.Errorf("parseCondition invalid condition key %#v", field) + } +} + +func parseHttpHeaderCondition(conditon *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { + ret := &elbv2.RuleCondition{} + ret.SetField("http-header") + + values, err := conditon.GetMap("httpHeaderConfig") + if err != nil { + return nil, errors.Wrap(err, "GetMap") + } + + name, ok := values["HttpHeaderName"] + if !ok { + return nil, fmt.Errorf("parseHttpHeaderCondition missing filed HttpHeaderName") + } + + nameObj, ok := name.(*jsonutils.JSONString) + if !ok { + return nil, fmt.Errorf("parseHttpHeaderCondition missing invalid data %#v", name) + } + + headname, _ := nameObj.GetString() + config := &elbv2.HttpHeaderConditionConfig{} + config.SetHttpHeaderName(headname) + + vs, ok := values["values"] + if !ok { + return nil, fmt.Errorf("parseHttpHeaderCondition missing filed values") + } + + _vs, err := parseConditionStringArrayValues(vs) + if err != nil { + return nil, errors.Wrap(err, "parseConditionStringArrayValues") + } + config.SetValues(_vs) + ret.SetHttpHeaderConfig(config) + return ret, nil +} + +func parsePathPatternCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { + ret := &elbv2.RuleCondition{} + ret.SetField("path-pattern") + + values, err := condition.GetMap("pathPatternConfig") + if err != nil { + return nil, errors.Wrap(err, "GetMap") + } + + config := &elbv2.PathPatternConditionConfig{} + vs, ok := values["values"] + if !ok { + return nil, fmt.Errorf("parsePathPatternCondition missing filed values") + } + + _vs, err := parseConditionStringArrayValues(vs) + if err != nil { + return nil, errors.Wrap(err, "parseConditionStringArrayValues") + } + config.SetValues(_vs) + ret.SetPathPatternConfig(config) + return ret, nil + +} + +func parseRequestModthdCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { + ret := &elbv2.RuleCondition{} + ret.SetField("http-request-method") + + values, err := condition.GetMap("httpRequestMethodConfig") + if err != nil { + return nil, errors.Wrap(err, "GetMap.httpRequestMethodConfig") + } + + config := &elbv2.HttpRequestMethodConditionConfig{} + vs, ok := values["values"] + if !ok { + return nil, fmt.Errorf("parseRequestModthdCondition missing filed values") + } + + _vs, err := parseConditionStringArrayValues(vs) + if err != nil { + return nil, errors.Wrap(err, "parseConditionStringArrayValues") + } + config.SetValues(_vs) + return ret, nil +} + +func parseHostHeaderCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { + ret := &elbv2.RuleCondition{} + ret.SetField("host-header") + + values, err := condition.GetMap("hostHeaderConfig") + if err != nil { + return nil, errors.Wrap(err, "GetMap.hostHeaderConfig") + } + + config := &elbv2.HostHeaderConditionConfig{} + vs, ok := values["values"] + if !ok { + return nil, fmt.Errorf("parseHostHeaderCondition missing filed values") + } + + _vs, err := parseConditionStringArrayValues(vs) + if err != nil { + return nil, errors.Wrap(err, "parseConditionStringArrayValues") + } + config.SetValues(_vs) + ret.SetHostHeaderConfig(config) + return ret, nil +} + +func parseQueryStringCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { + ret := &elbv2.RuleCondition{} + ret.SetField("query-string") + + values, err := condition.GetMap("queryStringConfig") + if err != nil { + return nil, errors.Wrap(err, "GetMap.queryStringConfig") + } + + config := &elbv2.QueryStringConditionConfig{} + vs, ok := values["values"] + if !ok { + return nil, fmt.Errorf("parseQueryStringCondition missing filed values") + } + + _vs, err := parseConditionDictArrayValues(vs) + if err != nil { + return nil, errors.Wrap(err, "parseConditionDictArrayValues") + } + config.SetValues(_vs) + ret.SetQueryStringConfig(config) + return ret, nil +} + +func parseSourceIpCondition(condition *jsonutils.JSONDict) (*elbv2.RuleCondition, error) { + ret := &elbv2.RuleCondition{} + ret.SetField("source-ip") + + values, err := condition.GetMap("sourceIpConfig") + if err != nil { + return nil, errors.Wrap(err, "GetMap.sourceIpConfig") + } + + config := &elbv2.SourceIpConditionConfig{} + vs, ok := values["values"] + if !ok { + return nil, fmt.Errorf("parseSourceIpCondition missing filed values") + } + + _vs, err := parseConditionStringArrayValues(vs) + if err != nil { + return nil, errors.Wrap(err, "parseConditionStringArrayValues") + } + config.SetValues(_vs) + return ret, nil +} + +func parseConditionStringArrayValues(values jsonutils.JSONObject) ([]*string, error) { + objs, ok := values.(*jsonutils.JSONArray) + if !ok { + return nil, fmt.Errorf("parseConditionStringArrayValues invalid values format, required array: %#v", values) + } + + ret := []*string{} + vs, _ := objs.GetArray() + for i := range vs { + v, ok := vs[i].(*jsonutils.JSONString) + if !ok { + return nil, fmt.Errorf("parseConditionStringArrayValues invalid value, required string: %#v", v) + } + + _v, _ := v.GetString() + ret = append(ret, &_v) + } + + return ret, nil +} + +func parseConditionDictArrayValues(values jsonutils.JSONObject) ([]*elbv2.QueryStringKeyValuePair, error) { + objs, ok := values.(*jsonutils.JSONArray) + if !ok { + return nil, fmt.Errorf("parseConditionDictArrayValues invalid values format, required array: %#v", values) + } + + ret := []*elbv2.QueryStringKeyValuePair{} + vs, _ := objs.GetArray() + for i := range vs { + v, ok := vs[i].(*jsonutils.JSONDict) + if !ok { + return nil, fmt.Errorf("parseConditionDictArrayValues invalid value, required dict: %#v", v) + } + + key, err := v.GetString("key") + if err != nil { + return nil, errors.Wrap(err, "GetString.key") + } + + value, err := v.GetString("value") + if err != nil { + return nil, errors.Wrap(err, "GetString.value") + } + + pair := &elbv2.QueryStringKeyValuePair{} + pair.SetKey(key) + pair.SetValue(value) + ret = append(ret, pair) + } + + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/monitor.go new file mode 100644 index 0000000000..b9fbb41866 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/monitor.go @@ -0,0 +1,193 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +func (self *SAwsClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + if len(opts.ResourceId) == 0 { + return nil, fmt.Errorf("missing resource id") + } + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_RDS: + return self.GetRdsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: + return self.GetRedisMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) + } +} + +func (self *SAwsClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ + cloudprovider.VM_METRIC_TYPE_CPU_USAGE: { + "CPUUtilization": "", + }, + cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: { + "DiskReadOps": "", + "EBSReadOps": cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE, + }, + cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: { + "DiskWriteOps": "", + "EBSWriteOps": cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE, + }, + cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: { + "DiskReadBytes": "", + "EBSReadBytes": cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE, + }, + cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: { + "DiskWriteBytes": "", + "EBSWriteBytes": cloudprovider.METRIC_TAG_TYPE_DISK_TYPE + ":" + cloudprovider.METRIC_TAG_TYPE_DISK_TYPE, + }, + cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: { + "NetworkIn": "", + }, + cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: { + "NetworkOut": "", + }, + } { + part, err := self.getMetrics(opts.RegionExtId, "AWS/EC2", metricType, metricNames, "InstanceId", opts.ResourceId, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("getMetrics error: %v", err) + continue + } + ret = append(ret, part...) + } + return ret, nil +} + +type Datapoint struct { + Average float64 `xml:"Average"` + ExtendedStatistics struct { + Key string `xml:"Key"` + Value string `xml:"Value"` + } `xml:"ExtendedStatistics>entry"` + Maximum float64 `xml:"Maximum"` + Minimum float64 `xml:"Minimum"` + SampleCount float64 `xml:"SampleCount"` + Sum float64 `xml:"Sum"` + Timestamp time.Time `xml:"Timestamp"` + Unit string `xml:"Unit"` +} + +func (self Datapoint) GetValue() float64 { + return self.Average + self.Average + self.Minimum + self.Sum +} + +type Datapoints struct { + Datapoints []Datapoint `xml:"Datapoints>member"` + Label string `xml:"Label"` +} + +func (self *SAwsClient) getMetrics(regionId, ns string, metricType cloudprovider.TMetricType, metrics map[string]string, dimensionName, dimensionValue string, start, end time.Time) ([]cloudprovider.MetricValues, error) { + result := []cloudprovider.MetricValues{} + for metricName, tagValue := range metrics { + params := map[string]string{ + "EndTime": end.Format(time.RFC3339), + "MetricName": metricName, + "Dimensions.member.1.Name": dimensionName, + "Dimensions.member.1.Value": dimensionValue, + "Namespace": ns, + "Period": "1", + "StartTime": start.Format(time.RFC3339), + "Statistics.member.1": "Average", + } + ret := Datapoints{} + err := self.monitorRequest(regionId, "GetMetricStatistics", params, &ret) + if err != nil { + log.Errorf("GetMetricStatistics error: %v", err) + continue + } + metric := cloudprovider.MetricValues{} + metric.Id = dimensionValue + metric.MetricType = metricType + tags := map[string]string{} + idx := strings.Index(tagValue, ":") + if idx > 0 { + tags[tagValue[:idx]] = tagValue[idx+1:] + } + for _, data := range ret.Datapoints { + metricValue := cloudprovider.MetricValue{} + metricValue.Tags = tags + metricValue.Timestamp = data.Timestamp + metricValue.Value = data.GetValue() + metric.Values = append(metric.Values, metricValue) + } + result = append(result, metric) + } + return result, nil +} + +func (self *SAwsClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ + cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: { + "CPUUtilization": "", + }, + cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: { + "NetworkReceiveThroughput": "", + }, + cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: { + "NetworkTransmitThroughput": "", + }, + cloudprovider.RDS_METRIC_TYPE_CONN_COUNT: { + "DatabaseConnections": "", + }, + } { + part, err := self.getMetrics(opts.RegionExtId, "AWS/RDS", metricType, metricNames, "DBInstanceIdentifier", opts.ResourceId, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("getMetrics error: %v", err) + continue + } + ret = append(ret, part...) + } + return ret, nil + +} + +func (self *SAwsClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ + cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE: { + "CPUUtilization": "", + }, + cloudprovider.REDIS_METRIC_TYPE_USED_CONN: { + "CurrConnections": "", + }, + cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS: { + "Reclaimed": "", + }, + } { + part, err := self.getMetrics(opts.RegionExtId, "AWS/ElastiCache", metricType, metricNames, "CacheClusterId", opts.ResourceId, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("getMetrics error: %v", err) + continue + } + ret = append(ret, part...) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/natgateway.go new file mode 100644 index 0000000000..761c9ed86d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/natgateway.go @@ -0,0 +1,244 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type NatGatewayAddress struct { + AllocationId string `xml:"allocationId"` + NetworkInterfaceId string `xml:"networkInterfaceId"` + PrivateIp string `xml:"privateIp"` + PublicIp string `xml:"publicIp"` +} + +type ProvisionedBandwidth struct { + ProvisionTime time.Time `xml:"provisionTime"` + Provisioned string `xml:"provisioned"` + RequestTime time.Time `xml:"requestTime"` + Requested string `xml:"requested"` + Status string `xml:"status"` +} + +type SNatGateway struct { + multicloud.SNatGatewayBase + AwsTags + + region *SRegion + + ConnectivityType string `xml:"connectivityType"` + CreateTime time.Time `xml:"createTime"` + DeleteTime time.Time `xml:"deleteTime"` + FailureCode string `xml:"failureCode"` + FailureMessage string `xml:"failureMessage"` + NatGatewayAddresses []NatGatewayAddress `xml:"natGatewayAddressSet>item"` + NatGatewayId string `xml:"natGatewayId"` + ProvisionedBandwidth ProvisionedBandwidth `xml:"provisionedBandwidth"` + // pending | failed | available | deleting | deleted + State string `xml:"state"` + SubnetId string `xml:"subnetId"` + VpcId string `xml:"vpcId"` +} + +func (self *SNatGateway) GetName() string { + name := self.AwsTags.GetName() + if len(name) > 0 { + return name + } + return self.NatGatewayId +} + +func (self *SNatGateway) GetId() string { + return self.NatGatewayId +} + +func (self *SNatGateway) GetGlobalId() string { + return self.NatGatewayId +} + +func (self *SNatGateway) GetStatus() string { + switch self.State { + case "pending": + return api.NAT_STATUS_ALLOCATE + case "failed": + return api.NAT_STATUS_CREATE_FAILED + case "available": + return api.NAT_STAUTS_AVAILABLE + case "deleting", "deleted": + return api.NAT_STATUS_DELETING + default: + return api.NAT_STATUS_UNKNOWN + } +} + +func (self *SNatGateway) GetNatSpec() string { + return "" +} + +func (self *SNatGateway) Refresh() error { + nat, err := self.region.GetNatGateway(self.NatGatewayId) + if err != nil { + return err + } + return jsonutils.Update(self, nat) +} + +func (self *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, err := self.region.GetEips("", "", self.NatGatewayId) + if err != nil { + return nil, errors.Wrapf(err, "GetEIPs") + } + ret := []cloudprovider.ICloudEIP{} + for i := range eips { + eips[i].region = self.region + ret = append(ret, &eips[i]) + } + return ret, nil +} + +func (self *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { + return []cloudprovider.ICloudNatDEntry{}, nil +} + +func (self *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { + return []cloudprovider.ICloudNatSEntry{}, nil +} + +func (self *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SNatGateway) GetINetworkId() string { + return self.SubnetId +} + +func (self *SNatGateway) GetBandwidthMb() int { + return 0 +} + +func (self *SNatGateway) GetIpAddr() string { + ipAddrs := []string{} + for _, addr := range self.NatGatewayAddresses { + if len(addr.PrivateIp) > 0 { + ipAddrs = append(ipAddrs, addr.PrivateIp) + } + } + return strings.Join(ipAddrs, ",") +} + +func (self *SNatGateway) Delete() error { + return self.region.DeleteNatgateway(self.NatGatewayId) +} + +func (self *SRegion) DeleteNatgateway(id string) error { + params := map[string]string{ + "NatGatewayId": id, + } + return self.ec2Request("DeleteNatGateway", params, nil) +} + +func (self *SRegion) GetNatGateways(ids []string, vpcId, subnetId string) ([]SNatGateway, error) { + params := map[string]string{} + for i, id := range ids { + params[fmt.Sprintf("NatGatewayId.%d", i+1)] = id + } + idx := 1 + if len(vpcId) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "vpc-id" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = vpcId + idx++ + } + if len(subnetId) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "subnet-id" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = subnetId + idx++ + } + params[fmt.Sprintf("Filter.%d.Name", idx)] = "state" + for i, state := range []string{ + "pending", + "failed", + "available", + "deleting", + } { + params[fmt.Sprintf("Filter.%d.Value.%d", idx, i+1)] = state + } + idx++ + ret := []SNatGateway{} + for { + result := struct { + Nats []SNatGateway `xml:"natGatewaySet>item"` + NextToken string `xml:"nextToken"` + }{} + err := self.ec2Request("DescribeNatGateways", params, &result) + if err != nil { + return nil, errors.Wrapf(err, "DescribeNatGateways") + } + ret = append(ret, result.Nats...) + if len(result.NextToken) == 0 || len(result.Nats) == 0 { + break + } + params["NextToken"] = result.NextToken + } + return ret, nil +} + +func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) { + nats, err := self.GetNatGateways([]string{id}, "", "") + if err != nil { + return nil, errors.Wrapf(err, "GetNatGateways") + } + for i := range nats { + if nats[i].GetGlobalId() == id { + nats[i].region = self + return &nats[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { + nats, err := self.region.GetNatGateways(nil, self.VpcId, "") + if err != nil { + return nil, errors.Wrapf(err, "GetINatGateways") + } + ret := []cloudprovider.ICloudNatGateway{} + for i := range nats { + nats[i].region = self.region + ret = append(ret, &nats[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/network.go new file mode 100644 index 0000000000..1abdc7ac7b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/network.go @@ -0,0 +1,273 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/aws/aws-sdk-go/service/ec2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + AwsTags + 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 { + if len(self.NetworkName) == 0 { + return self.NetworkId + } + + return self.NetworkName +} + +func (self *SNetwork) GetGlobalId() string { + return self.NetworkId +} + +func (self *SNetwork) GetStatus() string { + if self.wire != nil && self.wire.vpc != nil && self.wire.vpc.InstanceTenancy == "dedicated" { + return api.NETWORK_STATUS_UNAVAILABLE + } + + return strings.ToLower(self.Status) +} + +func (self *SNetwork) Refresh() error { + 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) GetSysTags() map[string]string { + data := map[string]string{} + routes, _ := self.wire.vpc.region.GetRouteTablesByNetworkId(self.GetId()) + if len(routes) == 0 { + routes, _ = self.wire.vpc.region.GetRouteTables(self.VpcId, true) + } + + support_eip := false + if len(routes) >= 1 { + for i := range routes[0].Routes { + route := routes[0].Routes[i] + if route.GetNextHopType() == api.NEXT_HOP_TYPE_INTERNET { + support_eip = true + } + } + } + data["support_eip"] = strconv.FormatBool(support_eip) + return data +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +// 每个子网 CIDR 块中的前四个 IP 地址和最后一个 IP 地址无法使用 +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + startIp = startIp.StepUp() // 2 + startIp = startIp.StepUp() // 3 + startIp = startIp.StepUp() // 4 + return startIp.String() +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + 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 api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetIsPublic() bool { + return true +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +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) + + ec2Client, err := self.getEc2Client() + if err != nil { + return "", errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.CreateSubnet(params) + if err != nil { + return "", err + } else { + paramsTags := &ec2.CreateTagsInput{} + tagspec := TagSpec{ResourceType: "subnet"} + tagspec.SetNameTag(name) + tagspec.SetDescTag(desc) + ec2Tag, _ := tagspec.GetTagSpecifications() + paramsTags.SetResources([]*string{ret.Subnet.SubnetId}) + paramsTags.SetTags(ec2Tag.Tags) + _, err := ec2Client.CreateTags(paramsTags) + if err != nil { + log.Infof("createNetwork write tags failed:%s", err) + } + return *ret.Subnet.SubnetId, nil + } +} + +func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) { + if len(networkId) == 0 { + return nil, fmt.Errorf("GetNetwork networkId should not be empty.") + } + networks, err := self.GetNetwroks([]string{networkId}, "") + if err != nil { + return nil, errors.Wrap(err, "GetNetwroks") + } + if len(networks) != 1 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "getNetwork") + } + return &networks[0], nil +} + +func (self *SRegion) deleteNetwork(networkId string) error { + params := &ec2.DeleteSubnetInput{} + params.SetSubnetId(networkId) + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.DeleteSubnet(params) + return errors.Wrap(err, "DeleteSubnet") +} + +func (self *SRegion) GetNetwroks(ids []string, vpcId string) ([]SNetwork, 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) + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + ret, err := ec2Client.DescribeSubnets(params) + err = parseNotFoundError(err) + if err != nil { + return nil, err + } + + subnets := []SNetwork{} + for i := range ret.Subnets { + item := ret.Subnets[i] + if err := FillZero(item); err != nil { + return nil, err + } + + tagspec := TagSpec{ResourceType: "subnet"} + tagspec.LoadingEc2Tags(item.Tags) + + 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 = tagspec.GetNameTag() + jsonutils.Update(&subnet.AwsTags.TagSet, item.Tags) + subnets = append(subnets, subnet) + } + return subnets, nil +} + +func (self *SNetwork) GetProjectId() string { + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/networkinterface.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/networkinterface.go new file mode 100644 index 0000000000..5023a9dc9a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/networkinterface.go @@ -0,0 +1,100 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "time" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SGroupSet struct { + GroupId string `xml:"groupId"` + GroupName string `xml:"groupName"` +} + +type SPrivateIpAddress struct { + PrivateIpAddress string `xml:"privateIpAddress"` + PrivateDnsName string `xml:"privateDnsName"` + Primary bool `xml:"primary"` +} + +type SAttachment struct { + AttachmentId string `xml:"attachmentId"` + InstanceOwnerId string `xml:"instanceOwnerId"` + DeviceIndex int `xml:"deviceIndex"` + Status string `xml:"status"` + AttachTime time.Time `xml:"attachTime"` + DeleteOnTermination bool `xml:"deleteOnTermination"` +} + +type SNetworkInterface struct { + NetworkInterfaceId string `xml:"networkInterfaceId"` + SubnetId string `xml:"subnetId"` + VpcId string `xml:"vpcId"` + AvailabilityZone string `xml:"availabilityZone"` + Description string `xml:"description"` + OwnerId string `xml:"ownerId"` + RequesterId string `xml:"requesterId"` + RequesterManaged bool `xml:"requesterManaged"` + Status string `xml:"status"` + MacAddress string `xml:"macAddress"` + PrivateIpAddress string `xml:"privateIpAddress"` + PrivateDnsName string `xml:"privateDnsName"` + SourceDestCheck bool `xml:"sourceDestCheck"` + GroupSet []SGroupSet `xml:"groupSet>item"` + Attachment SAttachment `xml:"attachment"` + PrivateIpAddressesSet []SPrivateIpAddress `xml:"privateIpAddressesSet>item"` + InterfaceType string `xml:"interfaceType"` +} + +func (self *SRegion) GetNetworkInterface(id string) (*SNetworkInterface, error) { + nets, err := self.GetNetworkInterfaces(id) + if err != nil { + return nil, errors.Wrapf(err, "GetNetworkInterface") + } + for i := range nets { + if nets[i].NetworkInterfaceId == id { + return &nets[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetNetworkInterfaces(id string) ([]SNetworkInterface, error) { + params := map[string]string{} + if len(id) > 0 { + params["NetworkInterfaceId.1"] = id + } + ret := []SNetworkInterface{} + for { + result := struct { + NetworkInterfaceSet []SNetworkInterface `xml:"networkInterfaceSet>item"` + NextToken string `xml:"nextToken"` + }{} + err := self.ec2Request("DescribeNetworkInterfaces", params, &result) + if err != nil { + return nil, errors.Wrap(err, "DescribeNetworkInterfaces") + } + ret = append(ret, result.NetworkInterfaceSet...) + if len(result.NextToken) == 0 || len(result.NetworkInterfaceSet) == 0 { + break + } + params["NextToken"] = result.NextToken + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/organizations.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/organizations.go new file mode 100644 index 0000000000..4d27333bd4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/organizations.go @@ -0,0 +1,296 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go/service/organizations" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +/* + * {"arn":"arn:aws:organizations::285906155448:account/o-vgh74bqhdw/285906155448","email":"swordqiu@gmail.com","id":"285906155448","joined_method":"INVITED","joined_timestamp":"2021-02-09T03:55:27.724000Z","name":"qiu jian","status":"ACTIVE"} + */ +type SAccount struct { + ID string `json:"id"` + Name string `json:"name"` + Arn string `json:"arn"` + Email string `json:"email"` + Status string `json:"status"` + + JoinedMethod string `json:"joined_method"` + JoinedTimestamp time.Time `json:"joined_timestamp"` + + IsMaster bool `json:"is_master"` +} + +/* + * { + * Arn: "arn:aws:organizations::031871565791:policy/o-gn75phg8ge/service_control_policy/p-4l9recev", + * AwsManaged: false, + * Description: "Create Preventive SCP Guardrails", + * Id: "p-4l9recev", + * Name: "SCP-PREVENTIVE-GUARDRAILS", + * Type: "SERVICE_CONTROL_POLICY" + * } + */ +type SOrgPolicy struct { + Arn string `json:"arn"` + AwsManaged bool `json:"aws_managed"` + Description string `json:"description"` + Id string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` +} + +const ( + SERVICE_CONTROL_POLICY = "SERVICE_CONTROL_POLICY" + TAG_POLICY = "TAG_POLICY" + BACKUP_POLICY = "BACKUP_POLICY" + AISERVICES_OPT_OUT_POLICY = "AISERVICES_OPT_OUT_POLICY" +) + +func (r *SRegion) ListPolicies(filter string) ([]SOrgPolicy, error) { + orgCli, err := r.getOrganizationClient() + if err != nil { + return nil, errors.Wrap(err, "GetOrganizationClient") + } + var nextToken *string + policies := make([]SOrgPolicy, 0) + + for { + input := organizations.ListPoliciesInput{} + input.SetFilter(filter) + if nextToken != nil { + input.SetNextToken(*nextToken) + } + parts, err := orgCli.ListPolicies(&input) + if err != nil { + return nil, errors.Wrap(err, "ListPolicies") + } + for _, pPtr := range parts.Policies { + p := SOrgPolicy{ + Arn: *pPtr.Arn, + AwsManaged: *pPtr.AwsManaged, + Description: *pPtr.Description, + Id: *pPtr.Id, + Name: *pPtr.Name, + Type: *pPtr.Type, + } + policies = append(policies, p) + } + if parts.NextToken == nil || len(*parts.NextToken) == 0 { + break + } else { + nextToken = parts.NextToken + } + } + return policies, nil +} + +func (r *SRegion) ListPoliciesForTarget(filter string, targetId string) ([]SOrgPolicy, error) { + orgCli, err := r.getOrganizationClient() + if err != nil { + return nil, errors.Wrap(err, "GetOrganizationClient") + } + var nextToken *string + policies := make([]SOrgPolicy, 0) + + for { + input := organizations.ListPoliciesForTargetInput{} + input.SetFilter(filter) + input.SetTargetId(targetId) + if nextToken != nil { + input.SetNextToken(*nextToken) + } + parts, err := orgCli.ListPoliciesForTarget(&input) + if err != nil { + return nil, errors.Wrap(err, "ListPoliciesForTarget") + } + for _, pPtr := range parts.Policies { + p := SOrgPolicy{ + Arn: *pPtr.Arn, + AwsManaged: *pPtr.AwsManaged, + Description: *pPtr.Description, + Id: *pPtr.Id, + Name: *pPtr.Name, + Type: *pPtr.Type, + } + policies = append(policies, p) + } + if parts.NextToken == nil || len(*parts.NextToken) == 0 { + break + } else { + nextToken = parts.NextToken + } + } + return policies, nil +} + +func (r *SRegion) DescribeOrgPolicy(pId string) (jsonutils.JSONObject, error) { + orgCli, err := r.getOrganizationClient() + if err != nil { + return nil, errors.Wrap(err, "GetOrganizationClient") + } + input := organizations.DescribePolicyInput{} + input.SetPolicyId(pId) + output, err := orgCli.DescribePolicy(&input) + if err != nil { + return nil, errors.Wrap(err, "DescribePolicy") + } + content, err := jsonutils.ParseString(*output.Policy.Content) + if err != nil { + return nil, errors.Wrap(err, "ParseJSON") + } + return content, nil +} + +func (r *SRegion) ListAccounts() ([]SAccount, error) { + orgCli, err := r.getOrganizationClient() + if err != nil { + return nil, errors.Wrap(err, "GetOrganizationClient") + } + input := organizations.DescribeOrganizationInput{} + orgOutput, err := orgCli.DescribeOrganization(&input) + if err != nil { + log.Errorf("%#v", err) + return nil, errors.Wrap(err, "DescribeOrganization") + } + + var nextToken *string + accounts := make([]SAccount, 0) + for { + input := organizations.ListAccountsInput{} + if nextToken != nil { + input.NextToken = nextToken + } + parts, err := orgCli.ListAccounts(&input) + if err != nil { + return nil, errors.Wrap(err, "ListAccounts") + } + for _, actPtr := range parts.Accounts { + account := SAccount{ + ID: *actPtr.Id, + Name: *actPtr.Name, + Arn: *actPtr.Arn, + Email: *actPtr.Email, + Status: *actPtr.Status, + JoinedMethod: *actPtr.JoinedMethod, + JoinedTimestamp: *actPtr.JoinedTimestamp, + } + if *orgOutput.Organization.MasterAccountId == *actPtr.Id { + account.IsMaster = true + } + accounts = append(accounts, account) + } + if parts.NextToken == nil || len(*parts.NextToken) == 0 { + break + } else { + nextToken = parts.NextToken + } + } + return accounts, nil +} + +func (self *SAwsClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + defRegion, err := self.getDefaultRegion() + if err != nil { + return nil, errors.Wrapf(err, "getDefaultRegion") + } + accounts, err := defRegion.ListAccounts() + if err != nil { + // find errors + if strings.Contains(err.Error(), "AWSOrganizationsNotInUseException") || strings.Contains(err.Error(), "AccessDeniedException") { + // permission denied, fall back to single account mode + subAccount := cloudprovider.SSubAccount{} + subAccount.Name = self.cpcfg.Name + subAccount.Account = self.accessKey + subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL + return []cloudprovider.SSubAccount{subAccount}, nil + } else { + return nil, errors.Wrap(err, "ListAccounts") + } + } else { + // check if caller is a root caller + caller, _ := self.GetCallerIdentity() + isRootAccount := false + // arn:aws:iam::285906155448:root + if caller != nil && strings.HasSuffix(caller.Arn, ":root") { + log.Debugf("root %s", caller.Arn) + isRootAccount = true + } + subAccounts := []cloudprovider.SSubAccount{} + for _, account := range accounts { + subAccount := cloudprovider.SSubAccount{} + if account.Status == "ACTIVE" { + subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL + } else { + subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_SUSPENDED + } + if account.IsMaster { + subAccount.Name = fmt.Sprintf("%s/%s", account.Name, self.cpcfg.Name) + subAccount.Account = self.accessKey + } else { + if isRootAccount { + log.Warningf("Cannot access non-master account with root account!!") + subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NO_PERMISSION + } + subAccount.Name = fmt.Sprintf("%s/%s", account.Name, account.ID) + subAccount.Account = fmt.Sprintf("%s/%s", self.accessKey, account.ID) + } + subAccounts = append(subAccounts, subAccount) + } + return subAccounts, nil + } +} + +func (r *SRegion) ListParents(childId string) error { + orgCli, err := r.getOrganizationClient() + if err != nil { + return errors.Wrap(err, "GetOrganizationClient") + } + input := organizations.ListParentsInput{} + input.SetChildId(childId) + parents, err := orgCli.ListParents(&input) + if err != nil { + return errors.Wrap(err, "ListParents") + } + log.Debugf("%#v", parents) + return nil +} + +func (r *SRegion) DescribeOrganizationalUnit(ouId string) error { + orgCli, err := r.getOrganizationClient() + if err != nil { + return errors.Wrap(err, "GetOrganizationClient") + } + input := organizations.DescribeOrganizationalUnitInput{} + input.SetOrganizationalUnitId(ouId) + output, err := orgCli.DescribeOrganizationalUnit(&input) + if err != nil { + return errors.Wrap(err, "DescribeOrganizationUnit") + } + log.Debugf("%#v", output) + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/provider/doc.go new file mode 100644 index 0000000000..0cb2dd522b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/aws/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/provider/provider.go new file mode 100644 index 0000000000..f2e2d0574c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/provider/provider.go @@ -0,0 +1,410 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/aws" +) + +type SAwsProviderFactory struct { + cloudprovider.SPublicCloudBaseProviderFactory +} + +func (self *SAwsProviderFactory) GetId() string { + return aws.CLOUD_PROVIDER_AWS +} + +func (self *SAwsProviderFactory) GetName() string { + return aws.CLOUD_PROVIDER_AWS_CN +} + +func (self *SAwsProviderFactory) IsCloudeventRegional() bool { + return true +} + +func (self *SAwsProviderFactory) GetMaxCloudEventSyncDays() int { + return 1 +} + +func (self *SAwsProviderFactory) GetMaxCloudEventKeepDays() int { + return 90 +} + +func (self *SAwsProviderFactory) IsSupportPrepaidResources() bool { + return false +} + +func (self *SAwsProviderFactory) IsSupportCloudIdService() bool { + return true +} + +func (self *SAwsProviderFactory) IsSupportCreateCloudgroup() bool { + return true +} + +func (factory *SAwsProviderFactory) IsSystemCloudpolicyUnified() bool { + return false +} + +func (factory *SAwsProviderFactory) IsSupportSAMLAuth() bool { + return true +} + +func (self *SAwsProviderFactory) GetSupportedDnsZoneTypes() []cloudprovider.TDnsZoneType { + return []cloudprovider.TDnsZoneType{ + cloudprovider.PublicZone, + cloudprovider.PrivateZone, + } +} + +func (self *SAwsProviderFactory) GetSupportedDnsTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType { + return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType{ + cloudprovider.PublicZone: []cloudprovider.TDnsType{ + cloudprovider.DnsTypeA, + cloudprovider.DnsTypeAAAA, + cloudprovider.DnsTypeCAA, + cloudprovider.DnsTypeCNAME, + cloudprovider.DnsTypeMX, + cloudprovider.DnsTypeNS, + cloudprovider.DnsTypeSRV, + cloudprovider.DnsTypeSOA, + cloudprovider.DnsTypeTXT, + cloudprovider.DnsTypePTR, + cloudprovider.DnsTypeNAPTR, + cloudprovider.DnsTypeSPF, + }, + cloudprovider.PrivateZone: []cloudprovider.TDnsType{ + cloudprovider.DnsTypeA, + cloudprovider.DnsTypeAAAA, + cloudprovider.DnsTypeCAA, + cloudprovider.DnsTypeCNAME, + cloudprovider.DnsTypeMX, + cloudprovider.DnsTypeNS, + cloudprovider.DnsTypeSRV, + cloudprovider.DnsTypeSOA, + cloudprovider.DnsTypeTXT, + cloudprovider.DnsTypePTR, + cloudprovider.DnsTypeNAPTR, + cloudprovider.DnsTypeSPF, + }, + } +} + +func (self *SAwsProviderFactory) GetSupportedDnsPolicyTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType { + return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType{ + cloudprovider.PublicZone: []cloudprovider.TDnsPolicyType{ + cloudprovider.DnsPolicyTypeSimple, + cloudprovider.DnsPolicyTypeByGeoLocation, + cloudprovider.DnsPolicyTypeWeighted, + cloudprovider.DnsPolicyTypeFailover, + cloudprovider.DnsPolicyTypeMultiValueAnswer, + cloudprovider.DnsPolicyTypeLatency, + }, + cloudprovider.PrivateZone: []cloudprovider.TDnsPolicyType{ + cloudprovider.DnsPolicyTypeSimple, + cloudprovider.DnsPolicyTypeWeighted, + cloudprovider.DnsPolicyTypeFailover, + cloudprovider.DnsPolicyTypeMultiValueAnswer, + cloudprovider.DnsPolicyTypeLatency, + }, + } +} + +func (self *SAwsProviderFactory) GetSupportedDnsPolicyValues() map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue { + return map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue{ + cloudprovider.DnsPolicyTypeByGeoLocation: cloudprovider.AwsGeoLocations, + cloudprovider.DnsPolicyTypeLatency: cloudprovider.AwsRegions, + cloudprovider.DnsPolicyTypeFailover: cloudprovider.AwsFailovers, + } +} + +func (factory *SAwsProviderFactory) IsSupportCrossCloudEnvVpcPeering() bool { + return false +} + +func (factory *SAwsProviderFactory) IsSupportCrossRegionVpcPeering() bool { + return true +} + +func (factory *SAwsProviderFactory) IsSupportVpcPeeringVpcCidrOverlap() bool { + return false +} + +func (factory *SAwsProviderFactory) IsSupportModifyRouteTable() bool { + return true +} + +func (self *SAwsProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + if len(input.Environment) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "environment") + } + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + output.AccessUrl = input.Environment + return output, nil +} + +func (self *SAwsProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func parseAccount(account, secret string) (accessKey string, secretKey string, accountId string) { + slash := strings.Index(account, "/") + if slash > 0 { + accessKey = account[:slash] + accountId = account[slash+1:] + } else { + accessKey = account + } + secretKey = secret + return +} + +func (self *SAwsProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + extra := cloudprovider.SAWSExtraOptions{} + if cfg.Options != nil { + cfg.Options.Unmarshal(&extra) + } + accessKey, secret, accountId := parseAccount(cfg.Account, cfg.Secret) + client, err := aws.NewAwsClient( + aws.NewAwsClientConfig( + cfg.URL, accessKey, secret, accountId, + ).SetAssumeRole(extra.AWSAssumeRoleName).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, errors.Wrap(err, "NewAwsClient") + } + return &SAwsProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SAwsProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + accessKey, secret, accountId := parseAccount(info.Account, info.Secret) + return map[string]string{ + "AWS_ACCESS_URL": info.Url, + "AWS_ACCESS_KEY": accessKey, + "AWS_SECRET": secret, + "AWS_REGION": aws.GetDefaultRegionId(info.Url), + "AWS_ACCOUNT_ID": accountId, + }, nil +} + +func init() { + factory := SAwsProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SAwsProvider struct { + cloudprovider.SBaseProvider + client *aws.SAwsClient +} + +func (self *SAwsProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SAwsProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SAwsProvider) GetIamLoginUrl() string { + return self.client.GetIamLoginUrl() +} + +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) GetVersion() string { + return aws.AWS_API_VERSION +} + +func (self *SAwsProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(id) +} + +func (self *SAwsProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SAwsProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SAwsProvider) GetStorageClasses(regionId string) []string { + return []string{ + "STANDARD", + "STANDARD_IA", + "ONEZONE_IA", + "GLACIER", + "DEEP_ARCHIVE", + "INTELLIGENT_TIERING", + } +} + +func (self *SAwsProvider) GetBucketCannedAcls(regionId string) []string { + return self.client.GetBucketCannedAcls() +} + +func (self *SAwsProvider) GetObjectCannedAcls(regionId string) []string { + return self.client.GetObjectCannedAcls() +} + +func (self *SAwsProvider) GetCloudRegionExternalIdPrefix() string { + return self.client.GetAccessEnv() + "/" +} + +func (self *SAwsProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SAwsProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + return self.client.CreateIClouduser(conf) +} + +func (self *SAwsProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { + return self.client.GetICloudusers() +} + +func (self *SAwsProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroups() +} + +func (self *SAwsProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroupByName(name) +} + +func (self *SAwsProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + return self.client.CreateICloudgroup(name, desc) +} + +func (self *SAwsProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetISystemCloudpolicies() +} + +func (self *SAwsProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetICustomCloudpolicies() +} + +func (self *SAwsProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.client.GetIClouduserByName(name) +} + +func (self *SAwsProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { + return self.client.CreateICloudpolicy(opts) +} + +func (self *SAwsProvider) GetSamlEntityId() string { + return self.client.GetSamlEntityId() +} + +func (self *SAwsProvider) GetICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { + return self.client.GetICloudDnsZones() +} + +func (self *SAwsProvider) GetICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { + return self.client.GetHostedZoneById(id) +} + +func (self *SAwsProvider) CreateICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { + return self.client.CreateHostedZone(opts) +} + +func (self *SAwsProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { + return self.client.GetICloudSAMLProviders() +} + +func (self *SAwsProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { + sp, err := self.client.CreateSAMLProvider(opts.Name, opts.Metadata.String()) + if err != nil { + return nil, errors.Wrap(err, "CreateSAMLProvider") + } + return sp, nil +} + +func (self *SAwsProvider) GetICloudroles() ([]cloudprovider.ICloudrole, error) { + return self.client.GetICloudroles() +} + +func (self *SAwsProvider) GetICloudroleById(id string) (cloudprovider.ICloudrole, error) { + roles, err := self.GetICloudroles() + if err != nil { + return nil, errors.Wrapf(err, "GetICloudroles") + } + for i := range roles { + if roles[i].GetGlobalId() == id { + return roles[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SAwsProvider) GetICloudroleByName(name string) (cloudprovider.ICloudrole, error) { + role, err := self.client.GetRole(name) + if err != nil { + return nil, errors.Wrapf(err, "GetRole(%s)", name) + } + return role, nil +} + +func (self *SAwsProvider) CreateICloudrole(opts *cloudprovider.SRoleCreateOptions) (cloudprovider.ICloudrole, error) { + role, err := self.client.CreateRole(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateRole") + } + return role, nil +} + +func (self *SAwsProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetMetrics(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/region.go new file mode 100644 index 0000000000..8e9f3fb5ff --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/region.go @@ -0,0 +1,1071 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "strings" + "sync" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/acm" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/aws/aws-sdk-go/service/iam" + "github.com/aws/aws-sdk-go/service/organizations" + "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + "github.com/aws/aws-sdk-go/service/s3" + "github.com/aws/aws-sdk-go/service/wafv2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var ( + lock sync.RWMutex +) + +var RegionLocations = map[string]string{ + "us-east-2": "美国东部(俄亥俄州)", + "us-east-1": "美国东部(弗吉尼亚北部)", + "us-west-1": "美国西部(加利福尼亚北部)", + "us-west-2": "美国西部(俄勒冈)", + "ap-east-1": "亚太区域(香港)", + "ap-south-1": "亚太区域(孟买)", + "ap-northeast-3": "亚太区域(大阪-本地)", + "ap-northeast-2": "亚太区域(首尔)", + "ap-southeast-1": "亚太区域(新加坡)", + "ap-southeast-2": "亚太区域(悉尼)", + "ap-northeast-1": "亚太区域(东京)", + "ca-central-1": "加拿大(中部)", + "cn-north-1": "中国(北京)", + "cn-northwest-1": "中国(宁夏)", + "eu-central-1": "欧洲(法兰克福)", + "eu-west-1": "欧洲(爱尔兰)", + "eu-west-2": "欧洲(伦敦)", + "eu-south-1": "欧洲(米兰)", + "eu-west-3": "欧洲(巴黎)", + "eu-north-1": "欧洲(斯德哥尔摩)", + "me-south-1": "中东(巴林)", + "sa-east-1": "南美洲(圣保罗)", + "us-gov-west-1": "AWS GovCloud(美国西部)", + "us-gov-east-1": "AWS GovCloud(美国东部)", + + "af-south-1": "非洲(开普敦)", +} + +var RegionLocationsEN = map[string]string{ + "us-east-1": "US East (N. Virginia)", + "us-east-2": "US East (Ohio)", + "us-west-1": "US West (N. California)", + "us-west-2": "US West (Oregon)", + "af-south-1": "Africa (Cape Town)", + "ap-east-1": "Asia Pacific (Hong Kong)", + "ap-south-1": "Asia Pacific (Mumbai)", + "ap-northeast-3": "Asia Pacific (Osaka)", + "ap-northeast-2": "Asia Pacific (Seoul)", + "ap-southeast-1": "Asia Pacific (Singapore)", + "ap-southeast-2": "Asia Pacific (Sydney)", + "ap-northeast-1": "Asia Pacific (Tokyo)", + "ca-central-1": "Canada (Central)", + "eu-central-1": "Europe (Frankfurt)", + "eu-west-1": "Europe (Ireland)", + "eu-west-2": "Europe (London)", + "eu-south-1": "Europe (Milan)", + "eu-west-3": "Europe (Paris)", + "eu-north-1": "Europe (Stockholm)", + "me-south-1": "Middle East (Bahrain)", + "sa-east-1": "South America (São Paulo)", + "cn-north-1": "China (Beijing)", + "cn-northwest-1": "China (Ninxia)", + "us-gov-west-1": "AWS GovCloud(US West)", + "us-gov-east-1": "AWS GovCloud(US East)", +} + +const ( + RDS_SERVICE_NAME = "rds" + RDS_SERVICE_ID = "RDS" + + EC2_SERVICE_NAME = "ec2" + EC2_SERVICE_ID = "EC2" + + IAM_SERVICE_NAME = "iam" + IAM_SERVICE_ID = "IAM" + + STS_SERVICE_NAME = "sts" + STS_SERVICE_ID = "STS" + + CLOUDWATCH_SERVICE_NAME = "monitoring" + CLOUDWATCH_SERVICE_ID = "CloudWatch" + + CLOUD_TRAIL_SERVICE_NAME = "CloudTrail" + CLOUD_TRAIL_SERVICE_ID = "cloudtrail" + + ROUTE53_SERVICE_NAME = "route53" + + ELASTICACHE_SERVICE_NAME = "elasticache" +) + +type SRegion struct { + multicloud.SRegion + + client *SAwsClient + ec2Client *ec2.EC2 + iamClient *iam.IAM + s3Client *s3.S3 + elbv2Client *elbv2.ELBV2 + acmClient *acm.ACM + wafClient *wafv2.WAFV2 + organizationClient *organizations.Organizations + resourceGroupTagClient *resourcegroupstaggingapi.ResourceGroupsTaggingAPI + + izones []cloudprovider.ICloudZone + ivpcs []cloudprovider.ICloudVpc + + storageCache *SStoragecache + + RegionEndpoint string + RegionId string // 这里为保持一致沿用阿里云RegionId的叫法, 与AWS RegionName字段对应 +} + +///////////////////////////////////////////////////////////////////////////// +/* 请不要使用这个client(AWS_DEFAULT_REGION)跨region查信息.有可能导致查询返回的信息为空。比如DescribeAvailabilityZones*/ +func (self *SRegion) GetClient() *SAwsClient { + return self.client +} + +func (self *SRegion) getAwsSession() (*session.Session, error) { + return self.client.getAwsSession(self.RegionId, true) +} + +func (self *SRegion) getEc2Client() (*ec2.EC2, error) { + if self.ec2Client == nil { + s, err := self.getAwsSession() + + if err != nil { + return nil, errors.Wrap(err, "getAwsSession") + } + + self.ec2Client = ec2.New(s) + } + + return self.ec2Client, nil +} + +func (self *SRegion) getIamClient() (*iam.IAM, error) { + if self.iamClient == nil { + s, err := self.getAwsSession() + + if err != nil { + return nil, errors.Wrap(err, "getAwsSession") + } + + self.iamClient = iam.New(s) + } + + return self.iamClient, nil +} + +func (self *SRegion) getWafClient() (*wafv2.WAFV2, error) { + if self.wafClient == nil { + s, err := self.getAwsSession() + if err != nil { + return nil, errors.Wrapf(err, "getAwsSession") + } + self.wafClient = wafv2.New(s) + } + return self.wafClient, nil +} + +func (self *SRegion) GetS3Client() (*s3.S3, error) { + if self.s3Client == nil { + s, err := self.getAwsSession() + if err != nil { + return nil, errors.Wrap(err, "getAwsSession") + } + self.s3Client = s3.New(s, + &aws.Config{ + DisableRestProtocolURICleaning: aws.Bool(true), + }) + } + return self.s3Client, nil +} + +func (r *SRegion) getOrganizationClient() (*organizations.Organizations, error) { + if r.organizationClient == nil { + s, err := r.getAwsSession() + if err != nil { + return nil, errors.Wrap(err, "getAwsSession") + } + r.organizationClient = organizations.New(s) + } + return r.organizationClient, nil +} + +func (self *SRegion) getResourceGroupTagClient() (*resourcegroupstaggingapi.ResourceGroupsTaggingAPI, error) { + if self.resourceGroupTagClient == nil { + s, err := self.getAwsSession() + if err != nil { + return nil, errors.Wrap(err, "getAwsSession") + } + self.resourceGroupTagClient = resourcegroupstaggingapi.New(s) + } + return self.resourceGroupTagClient, nil +} + +func (self *SRegion) rdsRequest(apiName string, params map[string]string, retval interface{}) error { + return self.client.request(self.RegionId, RDS_SERVICE_NAME, RDS_SERVICE_ID, "2014-10-31", apiName, params, retval, true) +} + +func (self *SRegion) ec2Request(apiName string, params map[string]string, retval interface{}) error { + return self.client.request(self.RegionId, EC2_SERVICE_NAME, EC2_SERVICE_ID, "2016-11-15", apiName, params, retval, true) +} + +func (self *SAwsClient) monitorRequest(regionId, apiName string, params map[string]string, retval interface{}) error { + return self.request(regionId, CLOUDWATCH_SERVICE_NAME, CLOUDWATCH_SERVICE_ID, "2010-08-01", apiName, params, retval, true) +} + +func (self *SRegion) GetElbV2Client() (*elbv2.ELBV2, error) { + if self.elbv2Client == nil { + s, err := self.getAwsSession() + + if err != nil { + return nil, errors.Wrap(err, "getAwsSession") + } + + self.elbv2Client = elbv2.New(s) + } + + return self.elbv2Client, nil +} + +///////////////////////////////////////////////////////////////////////////// +func (self *SRegion) fetchZones() error { + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + // todo: 这里将过滤出指定region下全部的zones。是否只过滤出可用的zone即可? The state of the Availability Zone (available | information | impaired | unavailable) + zones, err := ec2Client.DescribeAvailabilityZones(&ec2.DescribeAvailabilityZonesInput{}) + if err != nil { + return errors.Wrap(err, "DescribeAvailabilityZones") + } + 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 { + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + vpcs, err := ec2Client.DescribeVpcs(&ec2.DescribeVpcsInput{}) + if err != nil { + return err + } + + self.ivpcs = make([]cloudprovider.ICloudVpc, 0) + for _, vpc := range vpcs.Vpcs { + cidrBlockAssociationSet := []string{} + for i := range vpc.CidrBlockAssociationSet { + cidr := vpc.CidrBlockAssociationSet[i] + if cidr.CidrBlockState.State != nil && *cidr.CidrBlockState.State == "associated" { + cidrBlockAssociationSet = append(cidrBlockAssociationSet, *cidr.CidrBlock) + } + } + + tagspec := TagSpec{ResourceType: "vpc"} + tagspec.LoadingEc2Tags(vpc.Tags) + ivpc := &SVpc{region: self, + CidrBlock: *vpc.CidrBlock, + CidrBlockAssociationSet: cidrBlockAssociationSet, + IsDefault: *vpc.IsDefault, + RegionId: self.RegionId, + Status: *vpc.State, + VpcId: *vpc.VpcId, + VpcName: tagspec.GetNameTag(), + InstanceTenancy: *vpc.InstanceTenancy, + } + jsonutils.Update(&ivpc.AwsTags.TagSet, vpc.Tags) + self.ivpcs = append(self.ivpcs, ivpc) + } + + 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 { + if localName, ok := RegionLocations[self.RegionId]; ok { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_CN, localName) + } + + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_CN, self.RegionId) +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + var en string + if localName, ok := RegionLocationsEN[self.RegionId]; ok { + en = fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_EN, localName) + } else { + en = fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_EN, self.RegionId) + } + + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.RegionId) +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) Refresh() error { + return nil +} + +func (self *SRegion) IsEmulated() bool { + return false +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + if info, ok := LatitudeAndLongitude[self.RegionId]; ok { + return info + } + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if self.izones == nil { + if err := self.fetchInfrastructure(); err != nil { + return nil, errors.Wrap(err, "fetchInfrastructure") + } + } + return self.izones, nil +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + if self.ivpcs == nil { + err := self.fetchInfrastructure() + if err != nil { + return nil, errors.Wrap(err, "fetchInfrastructure") + } + } + return self.ivpcs, nil +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + return self.GetInstance(id) +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return self.GetDisk(id) +} + +func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, err := self.GetEips("", "", "") + if err != nil { + return nil, errors.Wrap(err, "GetEips") + } + ret := []cloudprovider.ICloudEIP{} + for i := range eips { + eips[i].region = self + ret = append(ret, &eips[i]) + } + return ret, nil +} + +func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, _, err := self.GetSnapshots("", "", "", []string{}, 0, 0) + if err != nil { + return nil, errors.Wrap(err, "GetSnapshots") + } + + 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, errors.Wrap(err, "GetIZones") + } + + for _, zone := range izones { + if zone.GetGlobalId() == id { + return zone, nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIZoneById") +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + ivpcs, err := self.GetIVpcs() + if err != nil { + return nil, errors.Wrap(err, "GetIVpcs") + } + + for _, vpc := range ivpcs { + if vpc.GetGlobalId() == id { + return vpc, nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIVpcById") +} + +func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + izones, err := self.GetIZones() + if err != nil { + return nil, errors.Wrap(err, "GetIZones") + } + for i := 0; i < len(izones); i += 1 { + ihost, err := izones[i].GetIHostById(id) + if err == nil { + return ihost, nil + } else if errors.Cause(err) != cloudprovider.ErrNotFound { + log.Errorf("GetIHostById %s: %s", id, err) + return nil, errors.Wrap(err, "GetIHostById") + } + } + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIHostById") +} + +func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + izones, err := self.GetIZones() + if err != nil { + return nil, errors.Wrap(err, "GetIZones") + } + for i := 0; i < len(izones); i += 1 { + istore, err := izones[i].GetIStorageById(id) + if err == nil { + return istore, nil + } else if errors.Cause(err) != cloudprovider.ErrNotFound { + log.Errorf("GetIStorageById %s: %s", id, err) + return nil, errors.Wrap(err, "GetIStorageById") + } + } + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIStorageById") +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, errors.Wrap(err, "GetIZones") + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, errors.Wrap(err, "GetIHosts") + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, errors.Wrap(err, "GetIZones") + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, errors.Wrap(err, "GetIStorages") + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +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, errors.Wrap(cloudprovider.ErrNotFound, "GetIStoragecacheById") + +} + +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + tagspec := TagSpec{ResourceType: "vpc"} + if len(opts.NAME) > 0 { + tagspec.SetNameTag(opts.NAME) + } + + if len(opts.Desc) > 0 { + tagspec.SetDescTag(opts.Desc) + } + + spec, err := tagspec.GetTagSpecifications() + if err != nil { + return nil, errors.Wrap(err, "GetTagSpecifications") + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + // start create vpc + vpc, err := ec2Client.CreateVpc(&ec2.CreateVpcInput{CidrBlock: &opts.CIDR}) + if err != nil { + return nil, errors.Wrap(err, "CreateVpc") + } + + tagsParams := &ec2.CreateTagsInput{Resources: []*string{vpc.Vpc.VpcId}, Tags: spec.Tags} + _, err = ec2Client.CreateTags(tagsParams) + if err != nil { + log.Debugf("CreateIVpc add tag failed %s", err.Error()) + } + + err = self.fetchInfrastructure() + if err != nil { + return nil, errors.Wrap(err, "fetchInfrastructure") + } + return self.GetIVpcById(*vpc.Vpc.VpcId) +} + +func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { + eip, err := self.GetEip(id) + if err != nil { + return nil, errors.Wrap(err, "GetEip") + } + return eip, nil +} + +func (self *SRegion) GetProvider() string { + return CLOUD_PROVIDER_AWS +} + +func (self *SRegion) GetCloudEnv() string { + return self.client.accessUrl +} + +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, errors.Wrap(err, "GetIZones") + } + 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 { + desc := &cloudprovider.SManagedVMCreateConfig{ + Name: name, + ExternalImageId: imgId, + SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType}, + Cpu: cpu, + MemoryMB: memGB * 1024, + ExternalNetworkId: networkId, + DataDisks: []cloudprovider.SDiskInfo{}, + PublicKey: publicKey, + } + for _, sizeGB := range dataDiskSizesGB { + desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType}) + } + inst, err := z.getHost().CreateVM(desc) + if err != nil { + return nil, errors.Wrap(err, "CreateVM") + } + return inst.(*SInstance), nil + } + } + return nil, fmt.Errorf("cannot find vswitch %s", networkId) +} + +func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DescribeLoadBalancersInput{} + ret, err := client.DescribeLoadBalancers(params) + if err != nil { + return nil, errors.Wrap(err, "DescribeLoadBalancers") + } + + result := make([]SElb, 0) + err = unmarshalAwsOutput(ret, "LoadBalancers", &result) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.LoadBalancers") + } + + ielbs := make([]cloudprovider.ICloudLoadbalancer, len(result)) + for i := range result { + result[i].region = self + ielbs[i] = &result[i] + } + + return ielbs, nil +} + +func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DescribeLoadBalancersInput{} + params.SetLoadBalancerArns([]*string{&loadbalancerId}) + ret, err := client.DescribeLoadBalancers(params) + if err != nil { + if strings.Contains(err.Error(), "LoadBalancerNotFound") { + return nil, cloudprovider.ErrNotFound + } + + return nil, errors.Wrap(err, "DescribeLoadBalancers") + } + + elbs := []SElb{} + err = unmarshalAwsOutput(ret, "LoadBalancers", &elbs) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.LoadBalancers") + } + + if len(elbs) == 1 { + elbs[0].region = self + return &elbs[0], nil + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerById") +} + +func (self *SRegion) getElbAttributesById(loadbalancerId string) (map[string]string, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.DescribeLoadBalancerAttributesInput{} + params.SetLoadBalancerArn(loadbalancerId) + output, err := client.DescribeLoadBalancerAttributes(params) + if err != nil { + return nil, errors.Wrap(err, "DescribeLoadBalancerAttributes") + } + + attrs := []map[string]string{} + err = unmarshalAwsOutput(output, "Attributes", &attrs) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.Attributes") + } + + ret := map[string]string{} + for i := range attrs { + for k, v := range attrs[i] { + ret[k] = v + } + } + + return ret, nil +} + +func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + certs, err := self.GetILoadBalancerCertificates() + if err != nil { + return nil, errors.Wrap(err, "GetILoadBalancerCertificates") + } + + for i := range certs { + if certs[i].GetId() == certId { + return certs[i], nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerCertificateById") +} + +func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + client, err := self.getIamClient() + if err != nil { + return nil, errors.Wrap(err, "region.CreateILoadBalancerCertificate.getIamClient") + } + + params := &iam.UploadServerCertificateInput{} + params.SetServerCertificateName(cert.Name) + params.SetPrivateKey(cert.PrivateKey) + params.SetCertificateBody(cert.Certificate) + ret, err := client.UploadServerCertificate(params) + if err != nil { + return nil, errors.Wrap(err, "region.CreateILoadBalancerCertificate.UploadServerCertificate") + } + + // wait upload cert success + err = cloudprovider.Wait(5*time.Second, 30*time.Second, func() (bool, error) { + _, err := self.GetILoadBalancerCertificateById(*ret.ServerCertificateMetadata.Arn) + if err == nil { + return true, nil + } + + if errors.Cause(err) == cloudprovider.ErrNotFound { + return false, nil + } else { + return false, err + } + }) + if err != nil { + return nil, errors.Wrap(err, "region.CreateILoadBalancerCertificate.Wait") + } + + return self.GetILoadBalancerCertificateById(*ret.ServerCertificateMetadata.Arn) +} + +func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + client, err := self.getIamClient() + if err != nil { + return nil, errors.Wrap(err, "getIamClient") + } + + params := &iam.ListServerCertificatesInput{} + ret, err := client.ListServerCertificates(params) + if err != nil { + return nil, errors.Wrap(err, "ListServerCertificates") + } + + certs := []SElbCertificate{} + err = unmarshalAwsOutput(ret, "ServerCertificateMetadataList", &certs) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.ServerCertificateMetadataList") + } + + icerts := make([]cloudprovider.ICloudLoadbalancerCertificate, len(certs)) + for i := range certs { + certs[i].region = self + icerts[i] = &certs[i] + } + + return icerts, nil +} + +func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + client, err := self.GetElbV2Client() + if err != nil { + return nil, errors.Wrap(err, "GetElbV2Client") + } + + params := &elbv2.CreateLoadBalancerInput{} + params.SetName(loadbalancer.Name) + params.SetType(loadbalancer.LoadbalancerSpec) + params.SetIpAddressType("ipv4") + if loadbalancer.AddressType == api.LB_ADDR_TYPE_INTERNET { + params.SetScheme("internet-facing") + } else { + params.SetScheme("internal") + } + + // params.SetSecurityGroups() + params.SetSubnets(ConvertedList(loadbalancer.NetworkIDs)) + + tagInput := []*elbv2.Tag{} + keys := []string{} + values := []string{} + for k, v := range loadbalancer.Tags { + keys = append(keys, k) + values = append(values, v) + } + for i := range keys { + tagInput = append(tagInput, &elbv2.Tag{ + Key: &keys[i], + Value: &values[i], + }) + } + if len(loadbalancer.Tags) > 0 { + params.SetTags(tagInput) + } + + ret, err := client.CreateLoadBalancer(params) + if err != nil { + return nil, errors.Wrap(err, "CreateLoadBalancer") + } + + elbs := []SElb{} + err = unmarshalAwsOutput(ret, "LoadBalancers", &elbs) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput.LoadBalancers") + } + + if len(elbs) == 1 { + elbs[0].region = self + return &elbs[0], nil + } + + return nil, fmt.Errorf("CreateILoadBalancer error %#v", elbs) +} + +func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + iBuckets, err := region.client.getIBuckets() + if err != nil { + return nil, errors.Wrap(err, "getIBuckets") + } + ret := make([]cloudprovider.ICloudBucket, 0) + for i := range iBuckets { + if iBuckets[i].GetLocation() != region.GetId() { + continue + } + ret = append(ret, iBuckets[i]) + } + return ret, nil +} + +func (region *SRegion) CreateIBucket(name string, storageClassStr string, acl string) error { + s3cli, err := region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + input := &s3.CreateBucketInput{} + input.SetBucket(name) + if region.GetId() != DEFAULT_S3_REGION_ID { + location := region.GetId() + input.CreateBucketConfiguration = &s3.CreateBucketConfiguration{} + input.CreateBucketConfiguration.SetLocationConstraint(location) + } + _, err = s3cli.CreateBucket(input) + if err != nil { + return errors.Wrap(err, "CreateBucket") + } + region.client.invalidateIBuckets() + // if *output.Location != region.GetId() { + // log.Warningf("Request location %s != got locaiton %s", region.GetId(), *output.Location) + // } + return nil +} + +func (region *SRegion) DeleteIBucket(name string) error { + s3cli, err := region.GetS3Client() + if err != nil { + return errors.Wrap(err, "GetS3Client") + } + input := &s3.DeleteBucketInput{} + input.Bucket = &name + _, err = s3cli.DeleteBucket(input) + if err != nil { + if region.client.debug { + log.Debugf("%#v %s", err, err) + } + if strings.Index(err.Error(), "NoSuchBucket:") >= 0 { + return nil + } + return errors.Wrap(err, "DeleteBucket") + } + region.client.invalidateIBuckets() + return nil +} + +func (region *SRegion) IBucketExist(name string) (bool, error) { + s3cli, err := region.GetS3Client() + if err != nil { + return false, errors.Wrap(err, "GetS3Client") + } + input := &s3.HeadBucketInput{} + input.Bucket = &name + _, err = s3cli.HeadBucket(input) + if err != nil { + if region.client.debug { + log.Debugf("%#v %s", err, err) + } + if strings.Index(err.Error(), "NotFound:") >= 0 { + return false, nil + } + return false, errors.Wrap(err, "IsBucketExist") + } + return true, nil +} + +func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { + return cloudprovider.GetIBucketById(region, name) +} + +func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { + return region.GetIBucketById(name) +} + +func (region *SRegion) getBaseEndpoint() string { + if len(region.RegionEndpoint) > 4 { + return region.RegionEndpoint[4:] + } + return "" +} + +func (region *SRegion) getS3Endpoint() string { + base := region.getBaseEndpoint() + if len(base) > 0 { + return "s3." + base + } + return "" +} + +func (region *SRegion) getS3WebsiteEndpoint() string { + base := region.getBaseEndpoint() + if len(base) > 0 { + return "s3-website." + base + } + return "" +} + +func (region *SRegion) getEc2Endpoint() string { + return region.RegionEndpoint +} + +func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + backendgroups, err := self.GetElbBackendgroups("", nil) + if err != nil { + return nil, errors.Wrap(err, "GetElbBackendgroups") + } + + ret := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(backendgroups)) + for i := range backendgroups { + ret[i] = &backendgroups[i] + } + + return ret, nil +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, total, err := self.GetSecurityGroups("", "", secgroupId, 0, 1) + if err != nil { + return nil, errors.Wrap(err, "GetSecurityGroups") + } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } + if total > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return &secgroups[0], nil +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, total, err := self.GetSecurityGroups(opts.VpcId, opts.Name, "", 0, 1) + if err != nil { + return nil, errors.Wrap(err, "GetSecurityGroups") + } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } + if total > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return &secgroups[0], nil +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + groupId, err := self.CreateSecurityGroup(conf.VpcId, conf.Name, "", conf.Desc) + if err != nil { + return nil, errors.Wrap(err, "CreateSecurityGroup") + } + return self.GetISecurityGroupById(groupId) +} + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} + +func (region *SRegion) CreateInternetGateway() (cloudprovider.ICloudInternetGateway, error) { + ec2Client, err := region.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + input := ec2.CreateInternetGatewayInput{} + output, err := ec2Client.CreateInternetGateway(&input) + if err != nil { + return nil, errors.Wrap(err, "CreateInternetGateway") + } + + ret := &SInternetGateway{} + ret.region = region + err = unmarshalAwsOutput(output, "InternetGateway", ret) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput") + } + + return ret, nil +} diff --git a/pkg/multicloud/aws/reservedinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/reservedinstance.go similarity index 100% rename from pkg/multicloud/aws/reservedinstance.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/reservedinstance.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/resource_tag.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/resource_tag.go new file mode 100644 index 0000000000..7033e9278d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/resource_tag.go @@ -0,0 +1,121 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "strings" + + "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +func (self *SRegion) TagResources(arns []string, tags map[string]string) error { + if len(tags) == 0 { + return nil + } + client, err := self.getResourceGroupTagClient() + if err != nil { + return errors.Wrap(err, "self.getResourceGroupTagClient()") + } + params := resourcegroupstaggingapi.TagResourcesInput{} + arnInput := []*string{} + for i := range arns { + arnInput = append(arnInput, &arns[i]) + } + tagsInput := make(map[string]*string) + tagValues := []string{} + for k, v := range tags { + tagValues = append(tagValues, v) + tagsInput[k] = &tagValues[len(tagValues)-1] + } + params.SetResourceARNList(arnInput) + params.SetTags(tagsInput) + out, err := client.TagResources(¶ms) + if err != nil { + return errors.Wrapf(err, "client.TagResources(%s)", jsonutils.Marshal(params).String()) + } + if out != nil && len(out.FailedResourcesMap) > 0 { + return errors.Wrapf(cloudprovider.ErrNotSupported, "client.TagResources(%s),error:%s", jsonutils.Marshal(params).String(), jsonutils.Marshal(out).String()) + } + return nil +} + +func (self *SRegion) UntagResources(arns []string, tagKeys []string) error { + if len(tagKeys) == 0 { + return nil + } + client, err := self.getResourceGroupTagClient() + if err != nil { + return errors.Wrap(err, "self.getResourceGroupTagClient()") + } + params := resourcegroupstaggingapi.UntagResourcesInput{} + arnInput := []*string{} + for i := range arns { + arnInput = append(arnInput, &arns[i]) + } + delTagKeysInput := []*string{} + for i := range tagKeys { + delTagKeysInput = append(delTagKeysInput, &tagKeys[i]) + } + params.SetResourceARNList(arnInput) + params.SetTagKeys(delTagKeysInput) + out, err := client.UntagResources(¶ms) + if err != nil { + return errors.Wrapf(err, "client.UntagResources(%s)", jsonutils.Marshal(params).String()) + } + if out != nil && len(out.FailedResourcesMap) > 0 { + return errors.Wrapf(cloudprovider.ErrNotSupported, "client.UntagResources(%s),error:%s", jsonutils.Marshal(params).String(), jsonutils.Marshal(out).String()) + } + return nil +} + +func (self *SRegion) UpdateResourceTags(arn string, oldTags, tags map[string]string, replace bool) error { + addTags := map[string]string{} + for k, v := range tags { + if strings.HasPrefix(k, "aws:") { + return errors.Wrap(cloudprovider.ErrNotSupported, "The aws: prefix is reserved for AWS use") + } + if _, ok := oldTags[k]; !ok { + addTags[k] = v + } else { + if oldTags[k] != v { + addTags[k] = v + } + } + } + delTags := []string{} + if replace { + for k := range oldTags { + if _, ok := tags[k]; !ok { + if !strings.HasPrefix(k, "aws:") { + delTags = append(delTags, k) + } + } + } + } + err := self.UntagResources([]string{arn}, delTags) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.UntagResources([]string{%s}, %s)", arn, jsonutils.Marshal(delTags).String()) + } + err = self.TagResources([]string{arn}, addTags) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.TagResources([]string{%s}, %s)", arn, jsonutils.Marshal(addTags).String()) + } + return nil +} diff --git a/pkg/multicloud/aws/route.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/route.go similarity index 96% rename from pkg/multicloud/aws/route.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/route.go index 1051769146..56c44787c9 100644 --- a/pkg/multicloud/aws/route.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/route.go @@ -17,13 +17,13 @@ package aws import ( "strings" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SRoute struct { multicloud.SResourceBase - multicloud.AwsTags + AwsTags routetable *SRouteTable DestinationCIDRBlock string `json:"DestinationCidrBlock"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/routetable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/routetable.go new file mode 100644 index 0000000000..101ebdb2b6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/routetable.go @@ -0,0 +1,365 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "strings" + + "github.com/aws/aws-sdk-go/service/ec2" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRouteTable struct { + multicloud.SResourceBase + AwsTags + region *SRegion + vpc *SVpc + + Associations []Association `json:"Associations"` + PropagatingVgws []string `json:"PropagatingVgws"` + RouteTableID string `json:"RouteTableId"` + Routes []SRoute `json:"Routes"` + VpcID string `json:"VpcId"` + OwnerID string `json:"OwnerId"` +} + +type Association struct { + Main bool `json:"Main"` + RouteTableAssociationID string `json:"RouteTableAssociationId"` + RouteTableID string `json:"RouteTableId"` + GatewayID *string `json:"GatewayId,omitempty"` + SubnetID *string `json:"SubnetId,omitempty"` +} + +func (self *SRouteTable) GetId() string { + return self.RouteTableID +} + +func (self *SRouteTable) GetName() string { + return "" +} + +func (self *SRouteTable) GetGlobalId() string { + return self.GetId() +} + +func (self *SRouteTable) GetStatus() string { + return api.ROUTE_TABLE_AVAILABLE +} + +func (self *SRouteTable) Refresh() error { + ret, err := self.region.GetRouteTable(self.GetId()) + if err != nil { + return errors.Wrap(err, "SRouteTable.Refresh.GetRouteTable") + } + + err = jsonutils.Update(self, ret) + if err != nil { + return errors.Wrap(err, "SRouteTable.Refresh.Update") + } + + return nil +} + +func (self *SRouteTable) IsEmulated() bool { + return false +} + +func (self *SRouteTable) GetDescription() string { + return "" +} + +func (self *SRouteTable) GetRegionId() string { + return self.region.GetId() +} + +func (self *SRouteTable) GetVpcId() string { + return self.VpcID +} + +func (self *SRouteTable) GetType() cloudprovider.RouteTableType { + for i := range self.Associations { + if self.Associations[i].Main { + return cloudprovider.RouteTableTypeSystem + } + } + return cloudprovider.RouteTableTypeCustom +} + +func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { + result := []cloudprovider.RouteTableAssociation{} + for i := range self.Associations { + if self.Associations[i].GatewayID != nil { + association := cloudprovider.RouteTableAssociation{ + AssociationId: self.Associations[i].RouteTableAssociationID, + AssociationType: cloudprovider.RouteTableAssociaToRouter, + AssociatedResourceId: *self.Associations[i].GatewayID, + } + result = append(result, association) + } + if self.Associations[i].SubnetID != nil { + association := cloudprovider.RouteTableAssociation{ + AssociationId: self.Associations[i].RouteTableAssociationID, + AssociationType: cloudprovider.RouteTableAssociaToSubnet, + AssociatedResourceId: *self.Associations[i].SubnetID, + } + result = append(result, association) + } + } + return result +} + +func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { + err := self.region.CreateRoute(self.RouteTableID, route.Destination, route.NextHop) + if err != nil { + return errors.Wrapf(err, "self.region.CreateRoute(%s,%s,%s)", self.RouteTableID, route.Destination, route.NextHop) + } + return nil +} + +func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { + routeInfo := strings.Split(route.RouteId, ":") + if len(routeInfo) != 2 { + return errors.Wrap(cloudprovider.ErrNotSupported, "invalid route info") + } + err := self.region.RemoveRoute(self.RouteTableID, routeInfo[0]) + if err != nil { + return errors.Wrapf(err, "self.region.RemoveRoute(%s,%s)", self.RouteTableID, route.Destination) + } + + err = self.CreateRoute(route) + if err != nil { + return errors.Wrapf(err, "self.CreateRoute(%s)", jsonutils.Marshal(route).String()) + } + return nil +} + +func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { + err := self.region.RemoveRoute(self.RouteTableID, route.Destination) + if err != nil { + return errors.Wrapf(err, "self.region.RemoveRoute(%s,%s)", self.RouteTableID, route.Destination) + } + return nil +} + +func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { + iroutes := make([]cloudprovider.ICloudRoute, len(self.Routes)) + for i := range self.Routes { + self.Routes[i].routetable = self + iroutes[i] = &self.Routes[i] + } + + return iroutes, nil +} + +func (self *SRegion) GetRouteTables(vpcId string, mainRouteOnly bool) ([]SRouteTable, error) { + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + input := &ec2.DescribeRouteTablesInput{} + filters := make([]*ec2.Filter, 0) + filters = AppendSingleValueFilter(filters, "vpc-id", vpcId) + if mainRouteOnly { + filters = AppendSingleValueFilter(filters, "association.main", "true") + } + + input.SetFilters(filters) + + ret, err := ec2Client.DescribeRouteTables(input) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetRouteTables.DescribeRouteTables") + } + + routeTables := make([]SRouteTable, len(ret.RouteTables)) + err = unmarshalAwsOutput(ret, "RouteTables", routeTables) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetRouteTables.unmarshalAwsOutput") + } + + for i := range routeTables { + routeTables[i].region = self + } + + return routeTables, nil +} + +func (self *SRegion) CreateRoute(routeTableId string, DestinationCIDRBlock string, targetId string) error { + input := &ec2.CreateRouteInput{} + input.RouteTableId = &routeTableId + input.DestinationCidrBlock = &DestinationCIDRBlock + segs := strings.Split(targetId, "-") + if len(segs) == 0 { + return fmt.Errorf("invalid aws vpc targetid:%s", targetId) + } + switch segs[0] { + case "i": + input.InstanceId = &targetId + case "igw", "vgw": + input.GatewayId = &targetId + case "pcx": + input.VpcPeeringConnectionId = &targetId + case "eni": + input.NetworkInterfaceId = &targetId + case "nat": + input.NatGatewayId = &targetId + case "eigw": + input.EgressOnlyInternetGatewayId = &targetId + default: + return fmt.Errorf("invalid aws vpc targetid:%s", targetId) + } + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.CreateRoute(input) + if err != nil { + return errors.Wrapf(err, "self.ec2Client.CreateRoute(%s)", jsonutils.Marshal(input).String()) + } + return nil +} + +func (self *SRegion) ReplaceRoute(routeTableId string, DestinationCIDRBlock string, targetId string) error { + input := &ec2.ReplaceRouteInput{} + input.RouteTableId = &routeTableId + input.DestinationCidrBlock = &DestinationCIDRBlock + segs := strings.Split(targetId, "-") + if len(segs) == 0 { + return fmt.Errorf("invalid aws vpc targetid:%s", targetId) + } + switch segs[0] { + case "i": + input.InstanceId = &targetId + case "igw", "vgw": + input.GatewayId = &targetId + case "pcx": + input.VpcPeeringConnectionId = &targetId + case "eni": + input.NetworkInterfaceId = &targetId + case "nat": + input.NatGatewayId = &targetId + case "eigw": + input.EgressOnlyInternetGatewayId = &targetId + default: + return fmt.Errorf("invalid aws vpc targetid:%s", targetId) + } + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.ReplaceRoute(input) + if err != nil { + return errors.Wrapf(err, "self.ec2Client.ReplaceRouteInput(%s)", jsonutils.Marshal(input).String()) + } + return nil +} + +func (self *SRegion) RemoveRoute(routeTableId string, DestinationCIDRBlock string) error { + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + input := &ec2.DeleteRouteInput{} + input.RouteTableId = &routeTableId + input.DestinationCidrBlock = &DestinationCIDRBlock + _, err = ec2Client.DeleteRoute(input) + if err != nil { + return errors.Wrapf(err, "self.ec2Client.DeleteRoute(%s)", jsonutils.Marshal(input).String()) + } + return nil +} + +func (self *SRegion) GetRouteTablesByNetworkId(netId string) ([]SRouteTable, error) { + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + input := &ec2.DescribeRouteTablesInput{} + filter := &ec2.Filter{} + filter.SetName("association.subnet-id") + filter.SetValues([]*string{&netId}) + input.SetFilters([]*ec2.Filter{filter}) + + ret, err := ec2Client.DescribeRouteTables(input) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetRouteTables.DescribeRouteTables") + } + + routeTables := make([]SRouteTable, len(ret.RouteTables)) + err = unmarshalAwsOutput(ret, "RouteTables", routeTables) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetRouteTables.unmarshalAwsOutput") + } + + for i := range routeTables { + routeTables[i].region = self + } + + return routeTables, nil +} + +func (self *SRegion) GetRouteTable(id string) (*SRouteTable, error) { + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + input := &ec2.DescribeRouteTablesInput{} + input.RouteTableIds = []*string{&id} + ret, err := ec2Client.DescribeRouteTables(input) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetRouteTables.DescribeRouteTables") + } + + routeTables := make([]SRouteTable, len(ret.RouteTables)) + err = unmarshalAwsOutput(ret, "RouteTables", routeTables) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetRouteTables.unmarshalAwsOutput") + } + + if len(routeTables) == 1 { + routeTables[0].region = self + return &routeTables[0], nil + } else if len(routeTables) == 0 { + return nil, errors.ErrNotFound + } else { + return nil, errors.ErrDuplicateId + } +} + +func (self *SRegion) DeleteRouteTable(rid string) error { + input := &ec2.DeleteRouteTableInput{} + input.SetRouteTableId(rid) + + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.DeleteRouteTable(input) + if err != nil { + return errors.Wrap(err, "DeleteRouteTable") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/s3object.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/s3object.go new file mode 100644 index 0000000000..a245005d86 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/s3object.go @@ -0,0 +1,116 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "net/http" + + "github.com/aws/aws-sdk-go/service/s3" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SObject struct { + bucket *SBucket + + cloudprovider.SBaseCloudObject +} + +func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { + return o.bucket +} + +func (o *SObject) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + s3cli, err := o.bucket.region.GetS3Client() + if err != nil { + log.Errorf("o.bucket.region.GetS3Client error %s", err) + return acl + } + input := &s3.GetObjectAclInput{} + input.SetBucket(o.bucket.Name) + input.SetKey(o.Key) + output, err := s3cli.GetObjectAcl(input) + if err != nil { + log.Errorf("s3cli.GetObjectAcl error %s", err) + return acl + } + return s3ToCannedAcl(output.Grants) +} + +func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { + s3cli, err := o.bucket.region.GetS3Client() + if err != nil { + return errors.Wrap(err, "o.bucket.region.GetS3Client") + } + input := &s3.PutObjectAclInput{} + input.SetBucket(o.bucket.Name) + input.SetKey(o.Key) + input.SetACL(string(aclStr)) + _, err = s3cli.PutObjectAcl(input) + if err != nil { + return errors.Wrap(err, "s3cli.PutObjectAcl") + } + return nil +} + +func (o *SObject) GetMeta() http.Header { + if o.Meta != nil { + return o.Meta + } + s3cli, err := o.bucket.region.GetS3Client() + if err != nil { + log.Errorf("o.bucket.region.GetS3Client fail %s", err) + return nil + } + input := &s3.HeadObjectInput{} + input.SetBucket(o.bucket.Name) + input.SetKey(o.Key) + output, err := s3cli.HeadObject(input) + if err != nil { + log.Errorf("s3cli.HeadObject fail %s", err) + return nil + } + ret := http.Header{} + for k, v := range output.Metadata { + if v != nil && len(*v) > 0 { + ret.Add(k, *v) + } + } + if output.CacheControl != nil && len(*output.CacheControl) > 0 { + ret.Set(cloudprovider.META_HEADER_CACHE_CONTROL, *output.CacheControl) + } + if output.ContentType != nil && len(*output.ContentType) > 0 { + ret.Set(cloudprovider.META_HEADER_CONTENT_TYPE, *output.ContentType) + } + if output.ContentDisposition != nil && len(*output.ContentDisposition) > 0 { + ret.Set(cloudprovider.META_HEADER_CONTENT_DISPOSITION, *output.ContentDisposition) + } + if output.ContentEncoding != nil && len(*output.ContentEncoding) > 0 { + ret.Set(cloudprovider.META_HEADER_CONTENT_ENCODING, *output.ContentEncoding) + } + if output.ContentLanguage != nil && len(*output.ContentLanguage) > 0 { + ret.Set(cloudprovider.META_HEADER_CONTENT_LANGUAGE, *output.ContentLanguage) + } + return ret +} + +func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { + return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/saml_provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/saml_provider.go new file mode 100644 index 0000000000..f89bb5f9af --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/saml_provider.go @@ -0,0 +1,179 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "strings" + "time" + "unicode" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis/cloudid" + api "yunion.io/x/cloudmux/pkg/apis/cloudid" + compute_api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudid/options" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/httputils" + "yunion.io/x/onecloud/pkg/util/samlutils" +) + +type SAMLProvider struct { + multicloud.SResourceBase + AwsTags + client *SAwsClient + + SAMLMetadataDocument string `xml:"SAMLMetadataDocument"` + Arn string `xml:"Arn"` + ValidUntil time.Time `xml:"ValidUntil"` + CreateDate time.Time `xml:"CreateDate"` +} + +func (self *SAMLProvider) GetGlobalId() string { + return self.Arn +} + +func (self *SAMLProvider) GetId() string { + return self.Arn +} + +func (self *SAMLProvider) GetName() string { + if info := strings.Split(self.Arn, "/"); len(info) > 0 { + return info[len(info)-1] + } + return self.Arn +} + +func (self *SAMLProvider) GetStatus() string { + return api.SAML_PROVIDER_STATUS_AVAILABLE +} + +func (self *SAMLProvider) Delete() error { + return self.client.DeleteSAMLProvider(self.Arn) +} + +func (self *SAMLProvider) GetAuthUrl() string { + input := samlutils.SIdpInitiatedLoginInput{ + EntityID: cloudprovider.SAML_ENTITY_ID_AWS_CN, + IdpId: self.client.cpcfg.AccountId, + } + if self.client.GetAccessEnv() == compute_api.CLOUD_ACCESS_ENV_AWS_GLOBAL { + input.EntityID = cloudprovider.SAML_ENTITY_ID_AWS + } + return httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, fmt.Sprintf("sso?%s", jsonutils.Marshal(input).QueryString())) +} + +func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { + saml, err := self.client.GetSAMLProvider(self.Arn) + if err != nil { + return nil, errors.Wrapf(err, "GetSAMLProvider(%s)", self.Arn) + } + metadata, err := samlutils.ParseMetadata([]byte(saml.SAMLMetadataDocument)) + if err != nil { + return nil, errors.Wrapf(err, "ParseMetadata") + } + return &metadata, nil +} + +func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { + _, err := self.client.UpdateSAMLProvider(self.Arn, metadata.String()) + return err +} + +type SAMLProviders struct { + SAMLProviderList []SAMLProvider `xml:"SAMLProviderList>member"` +} + +func (self *SAwsClient) ListSAMLProviders() ([]SAMLProvider, error) { + result := SAMLProviders{} + err := self.iamRequest("ListSAMLProviders", nil, &result) + if err != nil { + return nil, errors.Wrapf(err, "ListSAMLProviders") + } + return result.SAMLProviderList, nil +} + +func (self *SAwsClient) GetSAMLProvider(arn string) (*SAMLProvider, error) { + result := &SAMLProvider{client: self, Arn: arn} + params := map[string]string{"SAMLProviderArn": arn} + err := self.iamRequest("GetSAMLProvider", params, result) + if err != nil { + return nil, errors.Wrapf(err, "GetSAMLProvider") + } + return result, nil +} + +func (self *SAwsClient) DeleteSAMLProvider(arn string) error { + params := map[string]string{"SAMLProviderArn": arn} + return self.iamRequest("DeleteSAMLProvider", params, nil) +} + +func (self *SAwsClient) CreateSAMLProvider(name, metadata string) (*SAMLProvider, error) { + name = func() string { + ret := "" + for _, s := range name { + if unicode.IsLetter(s) || unicode.IsNumber(s) || s == '.' || s == '_' || s == '-' { + ret += string(s) + } else { + ret += "-" + } + } + if len(ret) > 128 { + ret = ret[:128] + } + return ret + }() + params := map[string]string{ + "Name": name, + "SAMLMetadataDocument": metadata, + } + result := struct { + SAMLProviderArn string `xml:"SAMLProviderArn"` + }{} + err := self.iamRequest("CreateSAMLProvider", params, &result) + if err != nil { + return nil, errors.Wrapf(err, "CreateSAMLProvider") + } + return self.GetSAMLProvider(result.SAMLProviderArn) +} + +func (self *SAwsClient) UpdateSAMLProvider(arn, metadata string) (*SAMLProvider, error) { + params := map[string]string{ + "SAMLProviderArn": arn, + "SAMLMetadataDocument": metadata, + } + saml := &SAMLProvider{client: self} + err := self.iamRequest("UpdateSAMLProvider", params, saml) + if err != nil { + return nil, errors.Wrapf(err, "UpdateSAMLProvider") + } + return saml, nil +} + +func (self *SAwsClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { + providers, err := self.ListSAMLProviders() + if err != nil { + return nil, errors.Wrapf(err, "ListSAMLProviders") + } + ret := []cloudprovider.ICloudSAMLProvider{} + for i := range providers { + providers[i].client = self + ret = append(ret, &providers[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/securitygroup.go new file mode 100644 index 0000000000..054544a856 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/securitygroup.go @@ -0,0 +1,491 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "math/rand" + "strings" + "time" + + "github.com/aws/aws-sdk-go/service/ec2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSecurityGroup struct { + multicloud.SSecurityGroup + AwsTags + vpc *SVpc + + RegionId string + VpcId string + SecurityGroupId string + Description string + SecurityGroupName string + Permissions []cloudprovider.SecurityRule + + // CreationTime time.Time + // InnerAccessPolicy string +} + +func randomString(prefix string, length int) string { + bytes := []byte("0123456789abcdefghijklmnopqrstuvwxyz") + result := []byte{} + r := rand.New(rand.NewSource(time.Now().UnixNano())) + for i := 0; i < length; i++ { + result = append(result, bytes[r.Intn(len(bytes))]) + } + return prefix + string(result) +} + +func (self *SSecurityGroup) GetId() string { + return self.SecurityGroupId +} + +func (self *SSecurityGroup) GetVpcId() string { + return self.VpcId +} + +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) GetDescription() string { + return self.Description +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + secgrp, err := self.vpc.region.GetSecurityGroupDetails(self.SecurityGroupId) + if err != nil { + return nil, errors.Wrap(err, "GetSecurityGroupDetails") + } + return secgrp.Permissions, nil +} + +func (self *SRegion) addSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error { + if len(rule.Ports) != 0 { + for _, port := range rule.Ports { + rule.PortStart, rule.PortEnd = port, port + err := self.addSecurityGroupRule(secGrpId, rule) + if err != nil { + return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", rule.Priority, rule.String()) + } + } + return nil + } + return self.addSecurityGroupRule(secGrpId, rule) +} + +func (self *SRegion) addSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + 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 = ec2Client.AuthorizeSecurityGroupIngress(params) + } + + if rule.Direction == secrules.SecurityRuleEgress { + params := &ec2.AuthorizeSecurityGroupEgressInput{} + params.SetGroupId(secGrpId) + params.SetIpPermissions(ipPermissions) + _, err = ec2Client.AuthorizeSecurityGroupEgress(params) + } + + if err != nil && strings.Contains(err.Error(), "InvalidPermission.Duplicate") { + log.Debugf("addSecurityGroupRule %s %s", rule.Direction, err.Error()) + return nil + } + + return err +} + +func (self *SRegion) DelSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + ipPermissions, err := YunionSecRuleToAws(rule) + if err != nil { + return err + } + + if rule.Direction == secrules.SecurityRuleIngress { + params := &ec2.RevokeSecurityGroupIngressInput{} + params.SetGroupId(secGrpId) + params.SetIpPermissions(ipPermissions) + _, err = ec2Client.RevokeSecurityGroupIngress(params) + } + + if rule.Direction == secrules.SecurityRuleEgress { + params := &ec2.RevokeSecurityGroupEgressInput{} + params.SetGroupId(secGrpId) + params.SetIpPermissions(ipPermissions) + _, err = ec2Client.RevokeSecurityGroupEgress(params) + } + + if err != nil { + log.Debugf("delSecurityGroupRule %s %s", rule.Direction, err.Error()) + return err + } + return nil +} + +func (self *SRegion) updateSecurityGroupRuleDescription(secGrpId string, rule cloudprovider.SecurityRule) error { + ipPermissions, err := YunionSecRuleToAws(rule) + if err != nil { + return err + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + if rule.Direction == secrules.SecurityRuleIngress { + params := &ec2.UpdateSecurityGroupRuleDescriptionsIngressInput{} + params.SetGroupId(secGrpId) + params.SetIpPermissions(ipPermissions) + ret, err := 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 := 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) { + ec2Client, err := self.getEc2Client() + if err != nil { + return "", errors.Wrap(err, "getEc2Client") + } + + params := &ec2.CreateSecurityGroupInput{} + params.SetVpcId(vpcId) + // 这里的描述aws 上层代码拼接的描述。并非用户提交的描述,用户描述放置在Yunion本地数据库中。) + if len(desc) == 0 { + desc = "vpc default group" + } + params.SetDescription(desc) + if strings.ToLower(name) == "default" { + name = randomString(fmt.Sprintf("%s-", vpcId), 9) + } + params.SetGroupName(name) + + group, err := ec2Client.CreateSecurityGroup(params) + if err != nil { + return "", err + } + + tagspec := TagSpec{ResourceType: "security-group"} + if len(secgroupIdTag) > 0 { + tagspec.SetTag("id", secgroupIdTag) + } + tagspec.SetNameTag(name) + tagspec.SetDescTag(desc) + tags, _ := tagspec.GetTagSpecifications() + tagParams := &ec2.CreateTagsInput{} + tagParams.SetResources([]*string{group.GroupId}) + tagParams.SetTags(tags.Tags) + _, err = ec2Client.CreateTags(tagParams) + if err != nil { + return "", err + } + + return *group.GroupId, nil +} + +func (self *SRegion) createDefaultSecurityGroup(vpcId string) (string, error) { + name := randomString(fmt.Sprintf("%s-", vpcId), 9) + secId, err := self.CreateSecurityGroup(vpcId, name, "default", "vpc default group") + if err != nil { + return "", err + } + + rule := cloudprovider.SecurityRule{ + SecurityRule: 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) { + if len(secGroupId) == 0 { + return nil, fmt.Errorf("GetSecurityGroupDetails security group id should not be empty.") + } + params := &ec2.DescribeSecurityGroupsInput{} + params.SetGroupIds([]*string{&secGroupId}) + + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.DescribeSecurityGroups(params) + err = parseNotFoundError(err) + if err != nil { + return nil, errors.Wrap(err, "DescribeSecurityGroups") + } + + if len(ret.SecurityGroups) == 1 { + s := ret.SecurityGroups[0] + vpc, err := self.getVpc(*s.VpcId) + if err != nil { + return 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) getSecurityGroupById(vpcId, secgroupId string) (*SSecurityGroup, error) { + if len(secgroupId) == 0 { + return nil, httperrors.NewInputParameterError("security group id should not be empty") + } + + secgroups, total, err := self.GetSecurityGroups(vpcId, "", secgroupId, 0, 0) + if err != nil { + log.Errorf("GetSecurityGroups vpc %s secgroupId %s: %s", vpcId, secgroupId, err) + return nil, errors.Wrap(err, "GetSecurityGroups") + } + + 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}) + + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + _, err = ec2Client.CreateTags(params) + if err != nil { + return errors.Wrap(err, "CreateTags") + } + + return nil +} + +func (self *SRegion) getSecRules(ingress []*ec2.IpPermission, egress []*ec2.IpPermission) []cloudprovider.SecurityRule { + rules := []cloudprovider.SecurityRule{} + for _, p := range ingress { + ret, err := AwsIpPermissionToYunion(secrules.SecurityRuleIngress, *p) + if err != nil { + log.Debugln(err) + } + + for _, rule := range ret { + rules = append(rules, rule) + } + } + + for _, p := range egress { + ret, err := AwsIpPermissionToYunion(secrules.SecurityRuleEgress, *p) + if err != nil { + log.Debugln(err) + } + + for _, rule := range ret { + rules = append(rules, rule) + } + } + + return rules +} + +func (self *SRegion) GetSecurityGroups(vpcId string, name string, secgroupId 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(name) > 0 { + filters = AppendSingleValueFilter(filters, "group-name", name) + } + + if len(secgroupId) > 0 { + params.SetGroupIds([]*string{&secgroupId}) + } + + if len(filters) > 0 { + params.SetFilters(filters) + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, 0, errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.DescribeSecurityGroups(params) + err = parseNotFoundError(err) + 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 +} + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + for _, r := range append(inDels, outDels...) { + err := self.vpc.region.DelSecurityGroupRule(self.SecurityGroupId, r) + if err != nil { + if strings.Contains(err.Error(), "InvalidPermission.NotFound") { + continue + } + return errors.Wrapf(err, "delSecurityGroupRule %s %d %s", r.Name, r.Priority, r.String()) + } + } + + for _, r := range append(inAdds, outAdds...) { + err := self.vpc.region.addSecurityGroupRules(self.SecurityGroupId, r) + if err != nil { + return errors.Wrapf(err, "addSecurityGroupRules %d %s", r.Priority, r.String()) + } + } + return nil +} + +func (self *SSecurityGroup) Delete() error { + return self.vpc.region.DeleteSecurityGroup(self.SecurityGroupId) +} diff --git a/pkg/multicloud/aws/sku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/sku.go similarity index 100% rename from pkg/multicloud/aws/sku.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/sku.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/snapshot.go new file mode 100644 index 0000000000..066daef1fe --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/snapshot.go @@ -0,0 +1,235 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "strings" + + "github.com/aws/aws-sdk-go/service/ec2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SnapshotStatusType string + +const ( + SnapshotStatusAccomplished SnapshotStatusType = "completed" + SnapshotStatusProgress SnapshotStatusType = "pending" + SnapshotStatusFailed SnapshotStatusType = "error" +) + +type SSnapshot struct { + multicloud.SResourceBase + AwsTags + region *SRegion + + Progress string + SnapshotId string + SnapshotName string + SourceDiskId string + SourceDiskSize int32 + SourceDiskType string + Status SnapshotStatusType + Usage string + //TagSpec TagSpec +} + +func (self *SSnapshot) GetDiskType() string { + // todo: self.SourceDiskType + return "" +} + +func (self *SSnapshot) GetId() string { + return self.SnapshotId +} + +func (self *SSnapshot) GetName() string { + if len(self.SnapshotName) == 0 { + return self.SnapshotId + } + + 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 api.SNAPSHOT_READY + } else if self.Status == SnapshotStatusProgress { + return api.SNAPSHOT_CREATING + } else { // if self.Status == SnapshotStatusFailed + return api.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 errors.Wrap(cloudprovider.ErrNotFound, "GetSnapshots") + } else if err := jsonutils.Update(self, snapshots[0]); err != nil { + return err + } + return nil +} + +func (self *SSnapshot) IsEmulated() bool { + return false +} + +func (self *SSnapshot) GetSizeMb() int32 { + return self.SourceDiskSize * 1024 +} + +func (self *SSnapshot) GetDiskId() string { + return self.SourceDiskId +} + +func (self *SSnapshot) Delete() error { + return self.region.DeleteSnapshot(self.SnapshotId) +} + +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) + } + + if len(snapshotName) > 0 { + filters = AppendSingleValueFilter(filters, "tag:Name", snapshotName) + } + + if len(filters) > 0 { + params.SetFilters(filters) + } + + if len(snapshotIds) > 0 { + params.SetSnapshotIds(ConvertedList(snapshotIds)) + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, 0, errors.Wrap(err, "getEc2Client") + } + ret, err := ec2Client.DescribeSnapshots(params) + err = parseNotFoundError(err) + if err != nil { + if strings.Contains(err.Error(), "InvalidSnapshot.NotFound") { + return nil, 0, errors.Wrap(cloudprovider.ErrNotFound, "parseNotFoundError") + } + + return nil, 0, err + } + + snapshots := []SSnapshot{} + for _, item := range ret.Snapshots { + if err := FillZero(item); err != nil { + return nil, 0, err + } + + tagspec := TagSpec{ResourceType: "snapshot"} + tagspec.LoadingEc2Tags(item.Tags) + + 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 + snapshot.SnapshotName = tagspec.GetNameTag() + jsonutils.Update(&snapshot.AwsTags.TagSet, item.Tags) + 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, errors.Wrap(err, "GetSnapshots") + } else if total != 1 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetSnapshots") + } 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) + log.Debugf("CreateSnapshots with params %s", params) + ec2Client, err := self.getEc2Client() + if err != nil { + return "", errors.Wrap(err, "getEc2Client") + } + + ret, err := ec2Client.CreateSnapshot(params) + if err != nil { + return "", errors.Wrap(err, "CreateSnapshot") + } + return StrVal(ret.SnapshotId), nil +} + +func (self *SRegion) DeleteSnapshot(snapshotId string) error { + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + params := &ec2.DeleteSnapshotInput{} + params.SetSnapshotId(snapshotId) + _, err = ec2Client.DeleteSnapshot(params) + return errors.Wrap(err, "DeleteSnapshot") +} + +func (self *SSnapshot) GetProjectId() string { + return "" +} diff --git a/pkg/multicloud/aws/snapshot_policy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/snapshot_policy.go similarity index 100% rename from pkg/multicloud/aws/snapshot_policy.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/snapshot_policy.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/storage.go new file mode 100644 index 0000000000..960e1175ab --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/storage.go @@ -0,0 +1,166 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStorage struct { + multicloud.SStorageBase + multicloud.STagBase + zone *SZone + storageType string +} + +func (self *SStorage) GetId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetName() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetGlobalId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) +} + +func (self *SStorage) GetStatus() string { + if self.storageType == api.STORAGE_IO2_SSD { + regionId := self.zone.region.RegionId + // hard code + if utils.IsInStringArray(regionId, []string{ + "sa-east-1", + "eu-west-3", + "ap-northeast-3", + "ap-southeast-3", + "af-south-1", + + "cn-northwest-1", + "cn-north-1", + }) { + return api.STORAGE_OFFLINE + } + } + return api.STORAGE_ONLINE +} + +func (self *SStorage) Refresh() error { + return nil +} + +func (self *SStorage) IsEmulated() bool { + return true +} + +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, errors.Wrap(err, "GetDisks") + } + 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 == api.STORAGE_GP2_SSD || self.storageType == api.STORAGE_IO1_SSD || self.storageType == api.STORAGE_IO2_SSD { + return api.DISK_TYPE_SSD + } else { + return api.DISK_TYPE_ROTATE + } +} + +func (self *SStorage) GetCapacityMB() int64 { + return 0 // unlimited +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + return conf +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + diskId, err := self.zone.region.CreateDisk(self.zone.ZoneId, self.storageType, conf.Name, conf.SizeGb, "", conf.Desc) + if err != nil { + log.Errorf("createDisk fail %s", err) + return nil, errors.Wrap(err, "CreateDisk") + } + disk, err := self.zone.region.GetDisk(diskId) + if err != nil { + log.Errorf("getDisk %s fail %s", diskId, err) + return nil, errors.Wrap(err, "GetDisk") + } + disk.storage = self + return disk, nil +} + +func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + if disk, err := self.zone.region.GetDisk(idStr); err != nil { + log.Errorf("GetDisk %s: %s", idStr, err) + return nil, errors.Wrap(err, "GetDisk") + } else { + disk.storage = self + return disk, nil + } +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/storagecache.go new file mode 100644 index 0000000000..b804752860 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/storagecache.go @@ -0,0 +1,496 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "context" + "fmt" + "strings" + "time" + + "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/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +type SStoragecache struct { + multicloud.SResourceBase + AwsTags + region *SRegion +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) +} + +func (self *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) +} + +func (self *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, 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) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + images, err := self.region.GetImages("", ImageOwnerSelf, nil, "", "hvm", nil, "", true) + if err != nil { + return nil, errors.Wrapf(err, "GetImages") + } + ret := []cloudprovider.ICloudImage{} + for i := 0; i < len(images); i += 1 { + images[i].storageCache = self + ret = append(ret, &images[i]) + } + return ret, nil +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + if len(extId) == 0 { + return nil, fmt.Errorf("GetIImageById image id should not be empty") + } + + part, err := self.region.GetImage(extId) + if err != nil { + log.Errorf("GetImage %s %s", extId, err) + return nil, errors.Wrap(err, "GetImage") + } + part.storageCache = self + return part, nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + imageId, err := self.region.createIImage(snapshotId, imageName, imageDesc) + if err != nil { + log.Errorf("createIImage %s %s %s: %s", snapshotId, imageName, imageDesc, err) + return nil, errors.Wrap(err, "createIImage") + } + image, err := self.region.GetImage(imageId) + if err != nil { + log.Errorf("GetImage %s: %s", imageId, err) + return nil, errors.Wrap(err, "GetImage") + } + 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, errors.Wrap(err, "WaitStatus.iimage") + } + 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(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return self.uploadImage(ctx, userCred, image, callback) + +} + +func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + err := self.region.initVmimport() + if err != nil { + return "", errors.Wrap(err, "initVmimport") + } + + bucketName := GetBucketName(self.region.GetId(), image.ImageId) + + exist, err := self.region.IBucketExist(bucketName) + if err != nil { + return "", errors.Wrap(err, "IBucketExist") + } + + if !exist { + err = self.region.CreateIBucket(bucketName, "", "") + if err != nil { + return "", errors.Wrap(err, "CreateIBucket") + } + } + + defer self.region.DeleteIBucket(bucketName) + + s := auth.GetAdminSession(ctx, options.Options.Region) + meta, reader, sizeBytes, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) + if err != nil { + return "", errors.Wrap(err, "Images.Download") + } + log.Debugf("Images meta data %s", meta) + + diskFormat, _ := meta.GetString("disk_format") + + bucket, err := self.region.GetIBucketByName(bucketName) + if err != nil { + return "", errors.Wrap(err, "GetIBucketByName") + } + body := multicloud.NewProgress(sizeBytes, 80, reader, callback) + err = cloudprovider.UploadObject(ctx, bucket, image.ImageId, 0, body, sizeBytes, "", "", nil, false) + if err != nil { + return "", errors.Wrap(err, "cloudprovider.UploadObject") + } + + defer bucket.DeleteObject(ctx, image.ImageId) + + imageBaseName := image.ImageId + if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { + imageBaseName = fmt.Sprintf("img%s", image.ImageId) + } + imageName := imageBaseName + nameIdx := 1 + + // check image name, avoid name conflict + for { + _, err = self.region.GetImageByName(imageName, ImageOwnerSelf) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + break + } else { + return "", err + } + } + + imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) + nameIdx += 1 + log.Debugf("uploadImage Match remote name %s", imageName) + } + + task, err := self.region.ImportImage(imageName, image.OsArch, image.OsType, image.OsDistribution, diskFormat, bucketName, image.ImageId) + + if err != nil { + log.Errorf("ImportImage error %s %s %s", image.ImageId, bucketName, err) + return "", err + } + + err = cloudprovider.Wait(2*time.Minute, 4*time.Hour, func() (bool, error) { + status := task.GetStatus() + if status == ImageImportStatusDeleted { + return false, errors.Wrap(errors.ErrInvalidStatus, "SStoragecache.ImageImportStatusDeleted") + } + + if status == ImageImportStatusCompleted { + return true, nil + } + + return false, nil + }) + if err != nil { + return "", errors.Wrap(err, "SStoragecache.Wait") + } + + // add name tag + self.region.addTags(task.ImageId, "Name", image.ImageId) + if callback != nil { + callback(100) + } + return task.ImageId, nil +} + +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 := GetBucketName(self.region.GetId(), imageId) + if err := self.region.checkBucket(bucketName); err != nil { + log.Errorf("checkBucket %s: %s", bucketName, err) + return nil, errors.Wrap(err, "checkBucket") + } + + instanceId, err := self.region.GetInstanceIdByImageId(extId) + if err != nil { + log.Errorf("GetInstanceIdByImageId %s: %s", extId, err) + return nil, errors.Wrap(err, "GetInstanceIdByImageId") + } + + ec2Client, err := self.region.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + task, err := self.region.ExportImage(instanceId, imageId) + if err != nil { + log.Errorf("ExportImage %s %s: %s", instanceId, imageId, err) + return nil, errors.Wrap(err, "ExportImage") + } + + taskParams := &ec2.DescribeExportTasksInput{} + taskParams.SetExportTaskIds([]*string{&task.TaskId}) + if err := ec2Client.WaitUntilExportTaskCompleted(taskParams); err != nil { + log.Errorf("WaitUntilExportTaskCompleted %#v %s", taskParams, err) + return nil, errors.Wrap(err, "WaitUntilExportTaskCompleted") + } + + s3Client, err := self.region.GetS3Client() + if err != nil { + return nil, errors.Wrap(err, "GetS3Client") + } + + i := &s3.GetObjectInput{} + i.SetBucket(bucketName) + i.SetKey(fmt.Sprintf("%s.%s", task.TaskId, "ova")) + ret, err := s3Client.GetObject(i) + if err != nil { + log.Errorf("GetObject %#v: %s", i, err) + return nil, errors.Wrap(err, "GetObject") + } + + s := auth.GetAdminSession(context.Background(), 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, errors.Wrap(err, "Images.Images") + } 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 { + log.Errorf("IsBucketExist %s: %s", bucketName, err) + return errors.Wrap(err, "IsBucketExist") + } + + 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, errors.Wrap(err, "IsBucketExist.GetS3Client") + } + + params := &s3.ListBucketsInput{} + ret, err := s3Client.ListBuckets(params) + if err != nil { + return false, errors.Wrap(err, "ListBuckets") + } + + for _, bucket := range ret.Buckets { + if bucket.Name != nil && *bucket.Name == bucketName { + return true, nil + } + } + + return false, nil +} + +func (self *SRegion) GetBucketRegionId(bucketName string) (string, error) { + s3Client, err := self.GetS3Client() + if err != nil { + return "", err + } + + params := &s3.GetBucketLocationInput{Bucket: &bucketName} + ret, err := s3Client.GetBucketLocation(params) + if err != nil { + return "", err + } + + return StrVal(ret.LocationConstraint), 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-*")) + params.SetPolicyName(policyName) + params.SetRoleName(roleName) + _, err = iamClient.PutRolePolicy(params) + return err + } +} + +func (self *SRegion) initVmimport() error { + if err := self.initVmimportRole(); err != nil { + return err + } + + if err := self.initVmimportRolePolicy(); 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) + + ec2Client, err := self.getEc2Client() + if err != nil { + return "", errors.Wrap(err, "getEc2Client") + } + ret, err := 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 +} + +func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storageCache := region.getStoragecache() + return []cloudprovider.ICloudStoragecache{storageCache}, nil +} diff --git a/pkg/multicloud/aws/sts.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/sts.go similarity index 100% rename from pkg/multicloud/aws/sts.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/sts.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/tag_base.go new file mode 100644 index 0000000000..a42dbaf607 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/tag_base.go @@ -0,0 +1,73 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SAwsTag struct { + Key string `xml:"key"` + Value string `xml:"value"` +} + +type SAwsRdsTag struct { + Key string `xml:"Key"` + Value string `xml:"Value"` +} + +type AwsTags struct { + TagSet []SAwsTag `xml:"tagSet>item"` + // rds + TagList []SAwsRdsTag `xml:"TagList>Tag"` +} + +func (self AwsTags) GetName() string { + for _, tag := range self.TagSet { + if strings.ToLower(tag.Key) == "name" { + return tag.Value + } + } + return "" +} + +func (self *AwsTags) GetTags() (map[string]string, error) { + ret := map[string]string{} + for _, tag := range self.TagSet { + if tag.Key == "Name" || tag.Key == "Description" { + continue + } + ret[tag.Key] = tag.Value + } + for _, tag := range self.TagList { + if strings.ToLower(tag.Key) == "name" || strings.ToLower(tag.Key) == "description" { + continue + } + ret[tag.Key] = tag.Value + } + return ret, nil +} + +func (self *AwsTags) GetSysTags() map[string]string { + return nil +} + +func (self *AwsTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/utils.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/utils.go new file mode 100644 index 0000000000..bc7cacc33c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/utils.go @@ -0,0 +1,513 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "net" + "reflect" + "sort" + "strings" + + "github.com/aws/aws-sdk-go/service/ec2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +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) GetTags() (map[string]string, error) { + ret := map[string]string{} + for k, v := range self.Tags { + if k == "Name" || k == "Description" { + continue + } + ret[k] = v + } + return ret, nil +} + +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 i := range list { + if len(list[i]) > 0 { + result = append(result, &list[i]) + } + } + + return result +} + +func GetBucketName(regionId string, imageId string) string { + return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), imageId) +} + +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 +} + +// SecurityRuleSet to allow list +// 将安全组规则全部转换为等价的allow规则 +func SecurityRuleSetToAllowSet(srs secrules.SecurityRuleSet) secrules.SecurityRuleSet { + inRuleSet := secrules.SecurityRuleSet{} + outRuleSet := secrules.SecurityRuleSet{} + + for _, rule := range srs { + if rule.Direction == secrules.SecurityRuleIngress { + inRuleSet = append(inRuleSet, rule) + } + + if rule.Direction == secrules.SecurityRuleEgress { + outRuleSet = append(outRuleSet, rule) + } + } + + sort.Sort(inRuleSet) + sort.Sort(outRuleSet) + + inRuleSet = inRuleSet.AllowList() + outRuleSet = outRuleSet.AllowList() + + ret := secrules.SecurityRuleSet{} + ret = append(ret, inRuleSet...) + ret = append(ret, outRuleSet...) + return ret +} + +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 cloudprovider.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 cloudprovider.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 i := range r.Ports { + port := r.Ports[i] + 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) ([]cloudprovider.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 := []cloudprovider.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 cloudprovider.SecurityRule + if isAllPorts { + rule = cloudprovider.SecurityRule{ + SecurityRule: secrules.SecurityRule{ + Action: secrules.SecurityRuleAllow, + IPNet: ipNet, + Protocol: protocol, + Direction: direction, + Priority: 1, + Description: StrVal(ip.Description), + }, + } + } else { + rule = cloudprovider.SecurityRule{ + SecurityRule: 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 +} + +// YunionSecRuleToAws 不能保证无损转换 +// 规则描述如果包含中文等字符,将被丢弃掉 +func YunionSecRuleToAws(rule cloudprovider.SecurityRule) ([]*ec2.IpPermission, error) { + iprange := rule.IPNet.String() + if iprange == "" { + return nil, fmt.Errorf("YunionSecRuleToAws ignored ipnet should not be empty") + } + + ipranges := []*ec2.IpRange{} + ipranges = append(ipranges, &ec2.IpRange{CidrIp: &iprange}) + + portranges := yunionPortRangeToAws(rule) + protocol := yunionProtocolToAws(rule) + permissions := []*ec2.IpPermission{} + if rule.Protocol != secrules.PROTO_ANY { + for i := range portranges { + port := portranges[i] + permission := ec2.IpPermission{ + FromPort: &port.Start, + IpProtocol: &protocol, + IpRanges: ipranges, + ToPort: &port.End, + } + + permissions = append(permissions, &permission) + } + } else { + permissions = append(permissions, &ec2.IpPermission{ + IpProtocol: &protocol, + IpRanges: ipranges, + }) + } + + 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%c", byte(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%c", byte(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 +} + +// error +func parseNotFoundError(err error) error { + if err == nil { + return nil + } + + if strings.Contains(err.Error(), ".NotFound") { + return errors.Wrap(cloudprovider.ErrNotFound, "parseNotFoundError") + } else { + return err + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/vpc.go new file mode 100644 index 0000000000..4c8b5b8e58 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/vpc.go @@ -0,0 +1,723 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + "strings" + "time" + + "github.com/aws/aws-sdk-go/service/ec2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SUserCIDRs struct { + UserCidr []string +} + +type SVpc struct { + multicloud.SVpc + AwsTags + + region *SRegion + + iwires []cloudprovider.ICloudWire + secgroups []cloudprovider.ICloudSecurityGroup + + RegionId string + VpcId string + VpcName string + CidrBlock string + CidrBlockAssociationSet []string + IsDefault bool + Status string + InstanceTenancy 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 { + // 目前不支持专用主机 + if self.InstanceTenancy == "dedicated" { + return api.VPC_STATUS_UNAVAILABLE + } + 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) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetIsDefault() bool { + return self.IsDefault +} + +func (self *SVpc) GetCidrBlock() string { + return strings.Join(self.CidrBlockAssociationSet, ",") +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + if self.iwires == nil { + err := self.fetchNetworks() + if err != nil { + return nil, errors.Wrap(err, "fetchNetworks") + } + } + return self.iwires, nil +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + if self.secgroups == nil { + err := self.fetchSecurityGroups() + if err != nil { + return nil, errors.Wrap(err, "fetchSecurityGroups") + } + } + return self.secgroups, nil +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + tables, err := self.region.GetRouteTables(self.GetId(), false) + if err != nil { + return nil, errors.Wrap(err, "SVpc.GetIRouteTables") + } + + itables := make([]cloudprovider.ICloudRouteTable, len(tables)) + for i := range tables { + tables[i].vpc = self + itables[i] = &tables[i] + } + + return itables, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + routeTable, err := self.region.GetRouteTable(routeTableId) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetRouteTable(routeTableId:%s)", routeTableId) + } + routeTable.vpc = self + return routeTable, nil +} + +/* +Deletes the specified VPC. You must detach or delete all gateways and resources that are associated with +the VPC before you can delete it. For example, you must terminate all instances running in the VPC, +delete all security groups associated with the VPC (except the default one), +delete all route tables associated with the VPC (except the default one), and so on. +*/ +func (self *SVpc) Delete() error { + err := self.DeleteInternetGateways() + if err != nil { + return errors.Wrap(err, "DeleteInternetGateways") + } + + // 删除路由表. todo: 3.7版本路由表开放之后,需要同步状态到平台 + rts, err := self.GetIRouteTables() + if err != nil { + return errors.Wrap(err, "GetIRouteTables") + } + + for i := range rts { + // 主路由表不允许删除 + rt := rts[i].(*SRouteTable) + if len(rt.Associations) > 0 { + if rt.Associations[0].Main { + log.Debugf("Delete.RouteTable skipped main route table %s(%s)", rt.GetName(), rt.GetId()) + continue + } + } + + err = self.region.DeleteRouteTable(rts[i].GetId()) + if err != nil { + return errors.Wrap(err, "DeleteRouteTable") + } + } + + 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, errors.Wrap(err, "fetchNetworks") + } + } + for i := 0; i < len(self.iwires); i += 1 { + if self.iwires[i].GetGlobalId() == wireId { + return self.iwires[i], nil + } + } + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetIWireById") +} + +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) + if err != nil { + return errors.Wrapf(err, "GetNetwroks(%s)", self.VpcId) + } + + 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 { + if len(self.VpcId) == 0 { + return fmt.Errorf("fetchSecurityGroups vpc id is empty") + } + + secgroups, _, err := self.region.GetSecurityGroups(self.VpcId, "", "", 0, 0) + if err != nil { + return errors.Wrap(err, "GetSecurityGroups") + } + + 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 *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPCs, err := self.getRequesterVpcPeeringConnections() + if err != nil { + return nil, errors.Wrap(err, "self.getSVpcPeeringConnections()") + } + ret := []cloudprovider.ICloudVpcPeeringConnection{} + for i := range svpcPCs { + ret = append(ret, svpcPCs[i]) + } + return ret, nil +} + +func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPCs, err := self.getAccepterVpcPeeringConnections() + if err != nil { + return nil, errors.Wrap(err, "self.getAccepterVpcPeeringConnections()") + } + ret := []cloudprovider.ICloudVpcPeeringConnection{} + for i := range svpcPCs { + ret = append(ret, svpcPCs[i]) + } + return ret, nil +} + +func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { + vpcPc, err := self.getSVpcPeeringConnectionById(id) + if err != nil { + return nil, errors.Wrapf(err, "getSVpcPeeringConnectionById(%s)", id) + } + return vpcPc, nil +} + +func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { + return self.createSVpcPeeringConnection(opts) +} + +func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { + return self.acceptSVpcPeeringConnection(id) +} + +func (self *SVpc) GetAuthorityOwnerId() string { + identity, err := self.region.client.GetCallerIdentity() + if err != nil { + log.Errorf(err.Error() + "self.region.client.GetCallerIdentity()") + return "" + } + return identity.Account +} + +func (self *SVpc) getSVpcPeeringConnectionById(id string) (*SVpcPeeringConnection, error) { + vpcPC, err := self.region.GetVpcPeeringConnectionById(id) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetVpcPeeringConnectionById(%s)", id) + } + if vpcPC.Status.Code != nil && (*vpcPC.Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleted || + *vpcPC.Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleting) { + return nil, cloudprovider.ErrNotFound + } + svpcPC := SVpcPeeringConnection{} + svpcPC.vpc = self + svpcPC.vpcPC = vpcPC + return &svpcPC, nil +} + +func (self *SVpc) getRequesterVpcPeeringConnections() ([]*SVpcPeeringConnection, error) { + vpcPCs, err := self.region.DescribeRequesterVpcPeeringConnections(self.VpcId) + if err != nil { + return nil, errors.Wrap(err, "self.region.DescribeRequesterVpcPeeringConnections()") + } + ivpcPCs := []*SVpcPeeringConnection{} + for i := range vpcPCs { + if vpcPCs[i].Status.Code != nil && (*vpcPCs[i].Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleted || + *vpcPCs[i].Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleting) { + continue + } + svpcPC := SVpcPeeringConnection{} + svpcPC.vpc = self + svpcPC.vpcPC = vpcPCs[i] + ivpcPCs = append(ivpcPCs, &svpcPC) + } + return ivpcPCs, nil +} + +func (self *SVpc) getAccepterVpcPeeringConnections() ([]*SVpcPeeringConnection, error) { + vpcPCs, err := self.region.DescribeAccepterVpcPeeringConnections(self.VpcId) + if err != nil { + return nil, errors.Wrap(err, "self.region.DescribeAccepterVpcPeeringConnections()") + } + ivpcPCs := []*SVpcPeeringConnection{} + for i := range vpcPCs { + if vpcPCs[i].Status.Code != nil && (*vpcPCs[i].Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleted || + *vpcPCs[i].Status.Code == ec2.VpcPeeringConnectionStateReasonCodeDeleting) { + continue + } + svpcPC := SVpcPeeringConnection{} + svpcPC.vpc = self + svpcPC.vpcPC = vpcPCs[i] + ivpcPCs = append(ivpcPCs, &svpcPC) + } + return ivpcPCs, nil +} + +func (self *SVpc) createSVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPeeringConnection, error) { + svpcPC := SVpcPeeringConnection{} + vpcPC, err := self.region.CreateVpcPeeringConnection(self.VpcId, opts) + if err != nil { + return nil, errors.Wrapf(err, " self.region.CreateVpcPeeringConnection(%s,%s)", self.VpcId, jsonutils.Marshal(opts).String()) + } + svpcPC.vpc = self + svpcPC.vpcPC = vpcPC + err = cloudprovider.WaitMultiStatus(&svpcPC, []string{api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT, + api.VPC_PEERING_CONNECTION_STATUS_ACTIVE, + api.VPC_PEERING_CONNECTION_STATUS_DELETING}, 5*time.Second, 60*time.Second) + if err != nil { + return nil, errors.Wrap(err, "cloudprovider.WaitMultiStatus") + } + if svpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_DELETING { + return nil, errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcpeeringconnection:%s invalidate status", jsonutils.Marshal(svpcPC.vpcPC).String()) + } + return &svpcPC, nil +} + +func (self *SVpc) acceptSVpcPeeringConnection(id string) error { + svpcPC, err := self.getSVpcPeeringConnectionById(id) + if err != nil { + return errors.Wrapf(err, "self.getSVpcPeeringConnectionById(%s)", id) + } + // 其他region 创建的连接请求,有短暂的provisioning状态 + err = cloudprovider.WaitMultiStatus(svpcPC, []string{api.VPC_PEERING_CONNECTION_STATUS_ACTIVE, + api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT, + api.VPC_PEERING_CONNECTION_STATUS_DELETING}, 5*time.Second, 60*time.Second) + if err != nil { + return errors.Wrap(err, "cloudprovider.WaitMultiStatus") + } + if svpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_DELETING { + return errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcpeeringconnection:%s invalidate status", jsonutils.Marshal(svpcPC.vpcPC).String()) + } + + if svpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT { + _, err := self.region.AcceptVpcPeeringConnection(id) + if err != nil { + return errors.Wrapf(err, "self.region.AcceptVpcPeeringConnection(%s)", id) + } + } + err = cloudprovider.WaitMultiStatus(svpcPC, []string{api.VPC_PEERING_CONNECTION_STATUS_ACTIVE, + api.VPC_PEERING_CONNECTION_STATUS_DELETING}, 5*time.Second, 60*time.Second) + if err != nil { + return errors.Wrap(err, "cloudprovider.WaitMultiStatus") + } + if svpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_DELETING { + return errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcpeeringconnection:%s invalidate status", jsonutils.Marshal(svpcPC.vpcPC).String()) + } + return nil +} + +func (self *SVpc) IsSupportSetExternalAccess() bool { + return true +} + +func (self *SVpc) GetExternalAccessMode() string { + igws, err := self.region.GetInternetGateways(self.GetId()) + if err != nil { + log.Errorf("GetExternalAccessMode.GetInternetGateways %s", err) + } + + if len(igws) > 0 { + return api.VPC_EXTERNAL_ACCESS_MODE_EIP + } + + return api.VPC_EXTERNAL_ACCESS_MODE_NONE +} + +func (self *SVpc) AttachInternetGateway(igwId string) error { + ec2Client, err := self.region.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + input := ec2.AttachInternetGatewayInput{} + input.SetInternetGatewayId(igwId) + input.SetVpcId(self.GetId()) + + _, err = ec2Client.AttachInternetGateway(&input) + if err != nil { + return errors.Wrap(err, "AttachInternetGateway") + } + + err = self.AddDefaultInternetGatewayRoute(igwId) + if err != nil { + return errors.Wrap(err, "AddDefaultInternetGatewayRoute") + } + + return nil +} + +func (self *SVpc) AddDefaultInternetGatewayRoute(igwId string) error { + rt, err := self.GetMainRouteTable() + if err != nil { + return errors.Wrap(err, "GetMainRouteTable") + } + + defaultRoute := cloudprovider.RouteSet{} + defaultRoute.NextHop = igwId + defaultRoute.Destination = "0.0.0.0/0" + err = rt.CreateRoute(defaultRoute) + if err != nil { + return errors.Wrap(err, "CreateRoute") + } + + return nil +} + +func (self *SVpc) GetMainRouteTable() (*SRouteTable, error) { + rt, err := self.region.GetRouteTables(self.GetId(), true) + if err != nil { + return nil, errors.Wrap(err, "GetRouteTables") + } + + if len(rt) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotSupported, "GetMainRouteTable") + } + + return &rt[0], nil +} + +func (self *SVpc) DetachInternetGateways() error { + igws, err := self.region.GetInternetGateways(self.GetId()) + if err != nil { + return errors.Wrap(err, "GetInternetGateways") + } + + if len(igws) > 0 { + for i := range igws { + err = self.DetachInternetGateway(igws[i].GetId()) + if err != nil { + return errors.Wrap(err, "DetachInternetGateway") + } + } + } + + return nil +} + +func (self *SVpc) DetachInternetGateway(igwId string) error { + ec2Client, err := self.region.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + input := ec2.DetachInternetGatewayInput{} + input.SetInternetGatewayId(igwId) + input.SetVpcId(self.GetId()) + + _, err = ec2Client.DetachInternetGateway(&input) + if err != nil { + return errors.Wrap(err, "DetachInternetGateway") + } + + return nil +} + +func (self *SVpc) DeleteInternetGateway(igwId string) error { + ec2Client, err := self.region.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + input := ec2.DeleteInternetGatewayInput{} + input.SetInternetGatewayId(igwId) + + _, err = ec2Client.DeleteInternetGateway(&input) + if err != nil { + return errors.Wrap(err, "DeleteInternetGateway") + } + + return nil +} + +func (self *SVpc) DeleteInternetGateways() error { + igws, err := self.region.GetInternetGateways(self.GetId()) + if err != nil { + return errors.Wrap(err, "GetInternetGateways") + } + + if len(igws) > 0 { + for i := range igws { + err = self.DetachInternetGateway(igws[i].GetId()) + if err != nil { + return errors.Wrap(err, "DetachInternetGateway") + } + + err = self.DeleteInternetGateway(igws[i].GetId()) + if err != nil { + return errors.Wrap(err, "DeleteInternetGateway") + } + } + } + + return nil +} + +func (self *SRegion) getVpc(vpcId string) (*SVpc, error) { + if len(vpcId) == 0 { + return nil, fmt.Errorf("GetVpc vpc id should not be empty.") + } + + vpcs, err := self.GetVpcs([]string{vpcId}) + if err != nil { + return nil, errors.Wrap(err, "GetVpcs") + } + if len(vpcs) != 1 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "getVpc") + } + vpcs[0].region = self + return &vpcs[0], nil +} + +func (self *SRegion) revokeSecurityGroup(secgroupId, instanceId string, keep bool) error { + // todo : keep ? 直接使用assignSecurityGroup 即可? + return nil +} + +func (self *SRegion) assignSecurityGroup(secgroupId, instanceId string) error { + return self.assignSecurityGroups([]*string{&secgroupId}, instanceId) +} + +func (self *SRegion) assignSecurityGroups(secgroupIds []*string, instanceId string) error { + instance, err := self.GetInstance(instanceId) + if err != nil { + return errors.Wrap(err, "GetInstance") + } + + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + for _, eth := range instance.NetworkInterfaces { + params := &ec2.ModifyNetworkInterfaceAttributeInput{} + params.SetNetworkInterfaceId(eth.NetworkInterfaceId) + params.SetGroups(secgroupIds) + + _, err := ec2Client.ModifyNetworkInterfaceAttribute(params) + if err != nil { + return err + } + } + + return nil +} + +func (self *SRegion) DeleteSecurityGroup(secGrpId string) error { + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + params := &ec2.DeleteSecurityGroupInput{} + params.SetGroupId(secGrpId) + + _, err = ec2Client.DeleteSecurityGroup(params) + return errors.Wrap(err, "DeleteSecurityGroup") +} + +func (self *SRegion) DeleteVpc(vpcId string) error { + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + params := &ec2.DeleteVpcInput{} + params.SetVpcId(vpcId) + + _, err = ec2Client.DeleteVpc(params) + return errors.Wrap(err, "DeleteVpc") +} + +func (self *SRegion) GetVpcs(vpcId []string) ([]SVpc, error) { + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + params := &ec2.DescribeVpcsInput{} + if len(vpcId) > 0 { + params.SetVpcIds(ConvertedList(vpcId)) + } + + ret, err := ec2Client.DescribeVpcs(params) + err = parseNotFoundError(err) + if err != nil { + return nil, err + } + + vpcs := []SVpc{} + for _, item := range ret.Vpcs { + if err := FillZero(item); err != nil { + return nil, err + } + cidrBlockAssociationSet := []string{} + for i := range item.CidrBlockAssociationSet { + cidr := item.CidrBlockAssociationSet[i] + if cidr.CidrBlockState.State != nil && *cidr.CidrBlockState.State == "associated" { + cidrBlockAssociationSet = append(cidrBlockAssociationSet, *cidr.CidrBlock) + } + } + + tagspec := TagSpec{ResourceType: "vpc"} + tagspec.LoadingEc2Tags(item.Tags) + + vpc := SVpc{ + region: self, + RegionId: self.RegionId, + VpcId: *item.VpcId, + VpcName: tagspec.GetNameTag(), + CidrBlock: *item.CidrBlock, + CidrBlockAssociationSet: cidrBlockAssociationSet, + IsDefault: *item.IsDefault, + Status: *item.State, + InstanceTenancy: *item.InstanceTenancy, + } + jsonutils.Update(&vpc.AwsTags.TagSet, item.Tags) + vpcs = append(vpcs, vpc) + } + + return vpcs, nil +} + +func (self *SRegion) GetInternetGateways(vpcId string) ([]SInternetGateway, error) { + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + input := ec2.DescribeInternetGatewaysInput{} + filters := make([]*ec2.Filter, 0) + if len(vpcId) > 0 { + filters = AppendSingleValueFilter(filters, "attachment.vpc-id", vpcId) + } + + if len(filters) > 0 { + input.SetFilters(filters) + } + output, err := ec2Client.DescribeInternetGateways(&input) + if err != nil { + return nil, errors.Wrap(err, "DescribeInternetGateways") + } + + igws := make([]SInternetGateway, len(output.InternetGateways)) + err = unmarshalAwsOutput(output, "InternetGateways", &igws) + if err != nil { + return nil, errors.Wrap(err, "unmarshalAwsOutput") + } + + for i := range igws { + igws[i].region = self + } + + return igws, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/vpc_peering_connection.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/vpc_peering_connection.go new file mode 100644 index 0000000000..b2a1f43a12 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/vpc_peering_connection.go @@ -0,0 +1,323 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "github.com/aws/aws-sdk-go/service/ec2" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +func (self *SRegion) DescribeVpcPeeringConnections(vpcId string) ([]*ec2.VpcPeeringConnection, error) { + result := []*ec2.VpcPeeringConnection{} + requestvpcPCs, err := self.DescribeRequesterVpcPeeringConnections(vpcId) + if err != nil { + return nil, errors.Wrapf(err, "self.DescribeRequesterVpcPeeringConnections(%s)", vpcId) + } + result = append(result, requestvpcPCs...) + acceptvpcPCs, err := self.DescribeAccepterVpcPeeringConnections(vpcId) + if err != nil { + return nil, errors.Wrapf(err, "self.DescribeRequesterVpcPeeringConnections(%s)", vpcId) + } + result = append(result, acceptvpcPCs...) + return result, nil +} + +func (self *SRegion) DescribeRequesterVpcPeeringConnections(vpcId string) ([]*ec2.VpcPeeringConnection, error) { + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + params := ec2.DescribeVpcPeeringConnectionsInput{} + result := []*ec2.VpcPeeringConnection{} + var maxResult int64 = 20 + params.MaxResults = &maxResult + filter := ec2.Filter{} + filter.Values = []*string{&vpcId} + // request peeringConnection + filterName := "requester-vpc-info.vpc-id" + + filter.Name = &filterName + params.Filters = []*ec2.Filter{&filter} + for { + ret, err := ec2Client.DescribeVpcPeeringConnections(¶ms) + if err != nil { + return nil, errors.Wrapf(err, "self.ec2Client.DescribeVpcPeeringConnections(%s)", jsonutils.Marshal(params).String()) + } + result = append(result, ret.VpcPeeringConnections...) + if ret.NextToken == nil { + break + } + params.NextToken = ret.NextToken + } + return result, nil +} + +func (self *SRegion) DescribeAccepterVpcPeeringConnections(vpcId string) ([]*ec2.VpcPeeringConnection, error) { + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + params := ec2.DescribeVpcPeeringConnectionsInput{} + result := []*ec2.VpcPeeringConnection{} + var maxResult int64 = 20 + params.MaxResults = &maxResult + filter := ec2.Filter{} + filter.Values = []*string{&vpcId} + // accept peeringConnection + filterName := "accepter-vpc-info.vpc-id" + filter.Name = &filterName + params.Filters = []*ec2.Filter{&filter} + for { + ret, err := ec2Client.DescribeVpcPeeringConnections(¶ms) + if err != nil { + return nil, errors.Wrapf(err, "self.ec2Client.DescribeVpcPeeringConnections(%s)", jsonutils.Marshal(params).String()) + } + result = append(result, ret.VpcPeeringConnections...) + if ret.NextToken == nil { + break + } + params.NextToken = ret.NextToken + } + return result, nil +} + +func (self *SRegion) GetVpcPeeringConnectionById(Id string) (*ec2.VpcPeeringConnection, error) { + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + params := ec2.DescribeVpcPeeringConnectionsInput{} + result := []*ec2.VpcPeeringConnection{} + var maxResult int64 = 20 + params.MaxResults = &maxResult + filter := ec2.Filter{} + filter.Values = []*string{&Id} + filterName := "vpc-peering-connection-id" + filter.Name = &filterName + params.Filters = []*ec2.Filter{&filter} + for { + ret, err := ec2Client.DescribeVpcPeeringConnections(¶ms) + if err != nil { + return nil, errors.Wrapf(err, "self.ec2Client.DescribeVpcPeeringConnections(%s)", jsonutils.Marshal(params).String()) + } + result = append(result, ret.VpcPeeringConnections...) + if ret.NextToken == nil { + break + } + params.NextToken = ret.NextToken + } + if len(result) < 1 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetVpcPeeringConnectionById(%s)", Id) + } + if len(result) > 1 { + return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "GetVpcPeeringConnectionById(%s)", Id) + } + return result[0], nil +} + +func (self *SRegion) CreateVpcPeeringConnection(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*ec2.VpcPeeringConnection, error) { + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + params := ec2.CreateVpcPeeringConnectionInput{} + params.VpcId = &vpcId + params.PeerVpcId = &opts.PeerVpcId + params.PeerRegion = &opts.PeerRegionId + params.PeerOwnerId = &opts.PeerAccountId + ret, err := ec2Client.CreateVpcPeeringConnection(¶ms) + if err != nil { + return nil, errors.Wrapf(err, "self.ec2Client.CreateVpcPeeringConnection(%s)", jsonutils.Marshal(params).String()) + } + // add tags + tagParams := ec2.CreateTagsInput{} + tagParams.Resources = []*string{ret.VpcPeeringConnection.VpcPeeringConnectionId} + nametag := "Name" + desctag := "Description" + tagParams.Tags = []*ec2.Tag{{Key: &nametag, Value: &opts.Name}, {Key: &desctag, Value: &opts.Desc}} + _, err = ec2Client.CreateTags(&tagParams) + if err != nil { + return nil, errors.Wrapf(err, "self.ec2Client.CreateTags(%s)", jsonutils.Marshal(tagParams).String()) + } + ret.VpcPeeringConnection.Tags = tagParams.Tags + return ret.VpcPeeringConnection, nil +} + +func (self *SRegion) DeleteVpcPeeringConnection(vpcPeeringConnectionId string) error { + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + params := ec2.DeleteVpcPeeringConnectionInput{} + params.VpcPeeringConnectionId = &vpcPeeringConnectionId + _, err = ec2Client.DeleteVpcPeeringConnection(¶ms) + if err != nil { + return errors.Wrapf(err, "self.ec2Client.DeleteVpcPeeringConnection(%s)", jsonutils.Marshal(params).String()) + } + return nil +} + +func (self *SRegion) AcceptVpcPeeringConnection(vpcPeeringConnectionId string) (*ec2.VpcPeeringConnection, error) { + ec2Client, err := self.getEc2Client() + if err != nil { + return nil, errors.Wrap(err, "getEc2Client") + } + + params := ec2.AcceptVpcPeeringConnectionInput{} + params.VpcPeeringConnectionId = &vpcPeeringConnectionId + ret, err := ec2Client.AcceptVpcPeeringConnection(¶ms) + if err != nil { + return nil, errors.Wrapf(err, "self.ec2Client.AcceptVpcPeeringConnection(%s)", jsonutils.Marshal(params).String()) + } + return ret.VpcPeeringConnection, nil +} + +func (self *SRegion) DeleteVpcPeeringConnectionRoute(vpcPeeringConnectionId string) error { + ec2Client, err := self.getEc2Client() + if err != nil { + return errors.Wrap(err, "getEc2Client") + } + + input := &ec2.DescribeRouteTablesInput{} + filters := make([]*ec2.Filter, 0) + filters = AppendSingleValueFilter(filters, "association.main", "true") + filters = AppendSingleValueFilter(filters, "route.vpc-peering-connection-id", vpcPeeringConnectionId) + input.SetFilters(filters) + routeTables := []*ec2.RouteTable{} + for { + ret, err := ec2Client.DescribeRouteTables(input) + if err != nil { + return errors.Wrap(err, "SRegion.GetRouteTables.DescribeRouteTables") + } + routeTables = append(routeTables, ret.RouteTables...) + input.NextToken = ret.NextToken + if ret.NextToken == nil { + break + } + } + for i := range routeTables { + if routeTables[i] != nil && routeTables[i].RouteTableId != nil && routeTables[i].Routes != nil { + for j := range routeTables[i].Routes { + if routeTables[i].Routes[j] != nil && + routeTables[i].Routes[j].VpcPeeringConnectionId != nil && + *routeTables[i].Routes[j].VpcPeeringConnectionId == vpcPeeringConnectionId && + routeTables[i].Routes[j].DestinationCidrBlock != nil { + err := self.RemoveRoute(*routeTables[i].RouteTableId, *routeTables[i].Routes[j].DestinationCidrBlock) + if err != nil { + return errors.Wrapf(err, "self.RemoveRoute(%s,%s)", *routeTables[i].RouteTableId, *routeTables[i].Routes[j].DestinationCidrBlock) + } + } + } + } + } + return nil +} + +type SVpcPeeringConnection struct { + multicloud.SResourceBase + AwsTags + vpc *SVpc + vpcPC *ec2.VpcPeeringConnection +} + +func (self *SVpcPeeringConnection) GetId() string { + if self.vpcPC.VpcPeeringConnectionId != nil { + return *self.vpcPC.VpcPeeringConnectionId + } + return "" +} + +// tags? +func (self *SVpcPeeringConnection) GetName() string { + for i := range self.vpcPC.Tags { + if self.vpcPC.Tags[i] != nil && self.vpcPC.Tags[i].Key != nil && + *self.vpcPC.Tags[i].Key == "Name" && self.vpcPC.Tags[i].Value != nil { + return *self.vpcPC.Tags[i].Value + } + } + return self.GetId() +} + +func (self *SVpcPeeringConnection) GetGlobalId() string { + return self.GetId() +} + +func (self *SVpcPeeringConnection) GetStatus() string { + if self.vpcPC.Status.Code != nil { + switch *self.vpcPC.Status.Code { + case ec2.VpcPeeringConnectionStateReasonCodeInitiatingRequest, ec2.VpcPeeringConnectionStateReasonCodeProvisioning: + return api.VPC_PEERING_CONNECTION_STATUS_CREATING + case ec2.VpcPeeringConnectionStateReasonCodePendingAcceptance: + return api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT + case ec2.VpcPeeringConnectionStateReasonCodeActive: + return api.VPC_PEERING_CONNECTION_STATUS_ACTIVE + case ec2.VpcPeeringConnectionStateReasonCodeDeleted, ec2.VpcPeeringConnectionStateReasonCodeDeleting: + return api.VPC_PEERING_CONNECTION_STATUS_DELETING + default: + return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN + } + } + return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN +} + +func (self *SVpcPeeringConnection) Refresh() error { + vpcPC, err := self.vpc.region.GetVpcPeeringConnectionById(self.GetId()) + if err != nil { + return errors.Wrapf(err, "self.vpc.region.GetVpcPeeringConnectionById(%s)", self.GetId()) + } + self.vpcPC = vpcPC + return nil +} + +func (self *SVpcPeeringConnection) GetPeerVpcId() string { + if self.vpcPC.AccepterVpcInfo != nil { + if self.vpcPC.AccepterVpcInfo.VpcId != nil { + return *self.vpcPC.AccepterVpcInfo.VpcId + } + } + return "" +} + +func (self *SVpcPeeringConnection) GetPeerAccountId() string { + if self.vpcPC.AccepterVpcInfo != nil { + if self.vpcPC.AccepterVpcInfo.OwnerId != nil { + return *self.vpcPC.AccepterVpcInfo.OwnerId + } + } + return "" +} + +func (self *SVpcPeeringConnection) Delete() error { + err := self.vpc.region.DeleteVpcPeeringConnection(self.GetId()) + if err != nil { + return errors.Wrapf(err, "self.region.DeleteVpcPeeringConnection(%s)", self.GetId()) + } + return nil +} + +func (self *SVpcPeeringConnection) GetEnabled() bool { + return true +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf.go new file mode 100644 index 0000000000..4ee3548cc8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf.go @@ -0,0 +1,545 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "strconv" + "strings" + + "github.com/aws/aws-sdk-go/service/wafv2" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + SCOPE_REGIONAL = "REGIONAL" + SCOPE_CLOUDFRONT = "CLOUDFRONT" +) + +var ( + WAF_SCOPES = []string{ + SCOPE_REGIONAL, + SCOPE_CLOUDFRONT, + } +) + +type SWafRule struct { + Action struct { + Block struct { + } `json:"Block"` + } `json:"Action"` + Name string `json:"Name"` +} + +type SVisibilityConfig struct { + CloudWatchMetricsEnabled bool + MetricName string + SampledRequestsEnabled bool +} + +type SWebAcl struct { + multicloud.SResourceBase + AwsTags + region *SRegion + *wafv2.WebACL + + scope string + LockToken string +} + +func (self *SRegion) ListWebACLs(scope string) ([]SWebAcl, error) { + if scope == SCOPE_CLOUDFRONT && self.RegionId != "us-east-1" { + return []SWebAcl{}, nil + } + client, err := self.getWafClient() + if err != nil { + return nil, errors.Wrapf(err, "getWafClient") + } + ret := []SWebAcl{} + input := wafv2.ListWebACLsInput{} + input.SetScope(scope) + for { + resp, err := client.ListWebACLs(&input) + if err != nil { + return nil, errors.Wrapf(err, "ListWebACLs") + } + part := []SWebAcl{} + jsonutils.Update(&part, resp.WebACLs) + ret = append(ret, part...) + if resp.NextMarker == nil || len(*resp.NextMarker) == 0 { + break + } + input.SetNextMarker(*resp.NextMarker) + } + return ret, nil +} + +func (self *SRegion) GetWebAcl(id, name, scope string) (*SWebAcl, error) { + client, err := self.getWafClient() + if err != nil { + return nil, errors.Wrapf(err, "getWafClient") + } + input := wafv2.GetWebACLInput{} + input.SetId(id) + input.SetName(name) + input.SetScope(scope) + resp, err := client.GetWebACL(&input) + if err != nil { + if _, ok := err.(*wafv2.WAFNonexistentItemException); ok { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, err.Error()) + } + return nil, errors.Wrapf(err, "GetWebAcl") + } + ret := &SWebAcl{region: self, scope: scope, WebACL: resp.WebACL, LockToken: *resp.LockToken} + return ret, nil +} + +func (self *SRegion) DeleteWebAcl(id, name, scope, lockToken string) error { + client, err := self.getWafClient() + if err != nil { + return errors.Wrapf(err, "getWafClient") + } + input := wafv2.DeleteWebACLInput{} + input.SetId(id) + input.SetName(name) + input.SetScope(scope) + input.SetLockToken(lockToken) + _, err = client.DeleteWebACL(&input) + return errors.Wrapf(err, "DeleteWebACL") +} + +func (self *SRegion) ListResourcesForWebACL(resType, arn string) ([]string, error) { + client, err := self.getWafClient() + if err != nil { + return nil, errors.Wrapf(err, "getWafClient") + } + input := wafv2.ListResourcesForWebACLInput{} + input.SetResourceType(resType) + input.SetWebACLArn(arn) + resp, err := client.ListResourcesForWebACL(&input) + if err != nil { + return nil, errors.Wrapf(err, "ListResourcesForWebACL") + } + ret := []string{} + for _, id := range resp.ResourceArns { + ret = append(ret, *id) + } + return ret, nil +} + +func (self *SRegion) GetICloudWafInstanceById(id string) (cloudprovider.ICloudWafInstance, error) { + idInfo := strings.Split(id, "/") + if len(idInfo) != 4 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "invalid arn %s", id) + } + scope := SCOPE_CLOUDFRONT + if strings.HasSuffix(idInfo[0], "regional") { + scope = SCOPE_REGIONAL + } + ins, err := self.GetWebAcl(idInfo[3], idInfo[2], scope) + if err != nil { + return nil, errors.Wrapf(err, "GetWebAcl(%s, %s, %s)", idInfo[3], idInfo[2], scope) + } + return ins, nil +} + +func (self *SRegion) GetICloudWafInstances() ([]cloudprovider.ICloudWafInstance, error) { + ret := []cloudprovider.ICloudWafInstance{} + for _, scope := range WAF_SCOPES { + ins, err := self.ListWebACLs(scope) + if err != nil { + return nil, errors.Wrapf(err, "ListWebACLs") + } + for i := range ins { + ins[i].region = self + ins[i].scope = scope + ret = append(ret, &ins[i]) + } + } + return ret, nil +} + +func (self *SWebAcl) GetEnabled() bool { + return true +} + +func (self *SWebAcl) GetGlobalId() string { + return *self.ARN +} + +func (self *SWebAcl) GetName() string { + return *self.Name +} + +func (self *SWebAcl) GetId() string { + return *self.ARN +} + +func (self *SWebAcl) GetWafType() cloudprovider.TWafType { + if self.scope == SCOPE_CLOUDFRONT { + return cloudprovider.WafTypeCloudFront + } + return cloudprovider.WafTypeRegional +} + +func (self *SWebAcl) GetStatus() string { + return api.WAF_STATUS_AVAILABLE +} + +func (self *SWebAcl) GetDefaultAction() *cloudprovider.DefaultAction { + ret := &cloudprovider.DefaultAction{} + if self.WebACL.DefaultAction == nil { + self.Refresh() + } + if self.WebACL.DefaultAction != nil { + action := self.WebACL.DefaultAction + if action.Allow != nil { + ret.Action = cloudprovider.WafActionAllow + } else if action.Block != nil { + ret.Action = cloudprovider.WafActionBlock + } + } + return ret +} + +func (self *SWebAcl) Refresh() error { + acl, err := self.region.GetWebAcl(*self.Id, *self.Name, self.scope) + if err != nil { + return errors.Wrapf(err, "GetWebAcl") + } + self.WebACL = acl.WebACL + return jsonutils.Update(self, acl) +} + +func (self *SWebAcl) Delete() error { + return self.region.DeleteWebAcl(*self.Id, *self.Name, self.scope, self.LockToken) +} + +func (self *SRegion) CreateICloudWafInstance(opts *cloudprovider.WafCreateOptions) (cloudprovider.ICloudWafInstance, error) { + waf, err := self.CreateWebAcl(opts.Name, opts.Desc, opts.Type, opts.DefaultAction) + if err != nil { + return nil, errors.Wrapf(err, "CreateWebAcl") + } + return waf, nil +} + +func (self *SRegion) CreateWebAcl(name, desc string, wafType cloudprovider.TWafType, action *cloudprovider.DefaultAction) (*SWebAcl, error) { + input := wafv2.CreateWebACLInput{} + input.SetName(name) + if len(desc) > 0 { + input.SetDescription(desc) + } + switch wafType { + case cloudprovider.WafTypeRegional, cloudprovider.WafTypeCloudFront: + input.SetScope(strings.ToUpper(string(wafType))) + default: + return nil, errors.Errorf("invalid waf type %s", wafType) + } + if action != nil { + defaultAction := wafv2.DefaultAction{} + switch action.Action { + case cloudprovider.WafActionAllow: + defaultAction.Allow = &wafv2.AllowAction{} + case cloudprovider.WafActionBlock: + defaultAction.Block = &wafv2.BlockAction{} + } + input.SetDefaultAction(&defaultAction) + } + visib := &wafv2.VisibilityConfig{} + visib.SetSampledRequestsEnabled(true) + visib.SetCloudWatchMetricsEnabled(true) + visib.SetMetricName(name) + input.SetVisibilityConfig(visib) + client, err := self.getWafClient() + if err != nil { + return nil, errors.Wrapf(err, "getWafClient") + } + output, err := client.CreateWebACL(&input) + if err != nil { + return nil, errors.Wrapf(err, "CreateWebAcl") + } + return self.GetWebAcl(*output.Summary.Id, name, *input.Scope) +} + +func reverseConvertField(opts cloudprovider.SWafStatement) *wafv2.FieldToMatch { + ret := &wafv2.FieldToMatch{} + switch opts.MatchField { + case cloudprovider.WafMatchFieldBody: + body := &wafv2.Body{} + ret.SetBody(body) + case cloudprovider.WafMatchFieldJsonBody: + case cloudprovider.WafMatchFieldMethod: + method := &wafv2.Method{} + ret.SetMethod(method) + case cloudprovider.WafMatchFieldQuery: + switch opts.MatchFieldKey { + case "SingleArgument": + query := &wafv2.SingleQueryArgument{} + ret.SetSingleQueryArgument(query) + case "AllArguments": + query := &wafv2.AllQueryArguments{} + ret.SetAllQueryArguments(query) + default: + query := &wafv2.QueryString{} + ret.SetQueryString(query) + } + case cloudprovider.WafMatchFiledHeader: + head := &wafv2.SingleHeader{} + head.SetName(opts.MatchFieldKey) + ret.SetSingleHeader(head) + case cloudprovider.WafMatchFiledUriPath: + uri := &wafv2.UriPath{} + ret.SetUriPath(uri) + } + return ret +} + +func reverseConvertStatement(statement cloudprovider.SWafStatement) *wafv2.Statement { + ret := &wafv2.Statement{} + trans := []*wafv2.TextTransformation{} + if statement.Transformations != nil { + for i, tran := range *statement.Transformations { + t := &wafv2.TextTransformation{} + switch tran { + case cloudprovider.WafTextTransformationNone: + t.SetType(wafv2.TextTransformationTypeNone) + case cloudprovider.WafTextTransformationLowercase: + t.SetType(wafv2.TextTransformationTypeLowercase) + case cloudprovider.WafTextTransformationCmdLine: + t.SetType(wafv2.TextTransformationTypeCmdLine) + case cloudprovider.WafTextTransformationUrlDecode: + t.SetType(wafv2.TextTransformationTypeUrlDecode) + case cloudprovider.WafTextTransformationHtmlEntityDecode: + t.SetType(wafv2.TextTransformationTypeHtmlEntityDecode) + case cloudprovider.WafTextTransformationCompressWithSpace: + t.SetType(wafv2.TextTransformationTypeCompressWhiteSpace) + } + t.SetPriority(int64(i)) + trans = append(trans, t) + } + } + rules := []*wafv2.ExcludedRule{} + if statement.ExcludeRules != nil { + for _, r := range *statement.ExcludeRules { + name := r.Name + rules = append(rules, &wafv2.ExcludedRule{ + Name: &name, + }) + } + } + field := reverseConvertField(statement) + switch statement.Type { + case cloudprovider.WafStatementTypeRate: + rate := &wafv2.RateBasedStatement{} + limit := int(0) + if statement.MatchFieldValues != nil && len(*statement.MatchFieldValues) == 1 { + limit, _ = strconv.Atoi((*statement.MatchFieldValues)[0]) + } + rate.SetLimit(int64(limit)) + fd := &wafv2.ForwardedIPConfig{} + if len(statement.ForwardedIPHeader) > 0 { + fd.SetHeaderName(statement.ForwardedIPHeader) + rate.SetForwardedIPConfig(fd) + } + ret.SetRateBasedStatement(rate) + case cloudprovider.WafStatementTypeIPSet: + ipset := &wafv2.IPSetReferenceStatement{} + ipset.SetARN(statement.IPSetId) + fd := &wafv2.IPSetForwardedIPConfig{} + if len(statement.ForwardedIPHeader) > 0 { + fd.SetHeaderName(statement.ForwardedIPHeader) + ipset.SetIPSetForwardedIPConfig(fd) + } + ret.SetIPSetReferenceStatement(ipset) + case cloudprovider.WafStatementTypeXssMatch: + xss := &wafv2.XssMatchStatement{} + if len(trans) > 0 { + xss.SetTextTransformations(trans) + } + field := &wafv2.FieldToMatch{} + xss.SetFieldToMatch(field) + xss.SetTextTransformations(trans) + ret.SetXssMatchStatement(xss) + case cloudprovider.WafStatementTypeSize: + size := &wafv2.SizeConstraintStatement{} + size.SetFieldToMatch(field) + value := int(0) + if statement.MatchFieldValues != nil && len(*statement.MatchFieldValues) == 1 { + value, _ = strconv.Atoi((*statement.MatchFieldValues)[0]) + } + size.SetSize(int64(value)) + ret.SetSizeConstraintStatement(size) + case cloudprovider.WafStatementTypeGeoMatch: + geo := &wafv2.GeoMatchStatement{} + values := []*string{} + if statement.MatchFieldValues != nil { + for i := range *statement.MatchFieldValues { + v := (*statement.MatchFieldValues)[i] + values = append(values, &v) + } + geo.SetCountryCodes(values) + } + fd := &wafv2.ForwardedIPConfig{} + if len(statement.ForwardedIPHeader) > 0 { + fd.SetHeaderName(statement.ForwardedIPHeader) + geo.SetForwardedIPConfig(fd) + } + ret.SetGeoMatchStatement(geo) + case cloudprovider.WafStatementTypeRegexSet: + regex := &wafv2.RegexPatternSetReferenceStatement{} + regex.SetARN(statement.RegexSetId) + if len(trans) > 0 { + regex.SetTextTransformations(trans) + } + regex.SetFieldToMatch(field) + ret.SetRegexPatternSetReferenceStatement(regex) + case cloudprovider.WafStatementTypeByteMatch: + bm := &wafv2.ByteMatchStatement{} + if len(trans) > 0 { + bm.SetTextTransformations(trans) + } + bm.SetSearchString([]byte(statement.SearchString)) + if len(statement.Operator) > 0 { + bm.SetPositionalConstraint(string(statement.Operator)) + } + bm.SetFieldToMatch(field) + ret.SetByteMatchStatement(bm) + case cloudprovider.WafStatementTypeRuleGroup: + rg := &wafv2.RuleGroupReferenceStatement{} + rg.SetARN(statement.RuleGroupId) + if len(rules) > 0 { + rg.SetExcludedRules(rules) + } + ret.SetRuleGroupReferenceStatement(rg) + case cloudprovider.WafStatementTypeSqliMatch: + sqli := &wafv2.SqliMatchStatement{} + if len(trans) > 0 { + sqli.SetTextTransformations(trans) + } + sqli.SetFieldToMatch(field) + ret.SetSqliMatchStatement(sqli) + case cloudprovider.WafStatementTypeLabelMatch: + case cloudprovider.WafStatementTypeManagedRuleGroup: + rg := &wafv2.ManagedRuleGroupStatement{} + rg.SetName(statement.ManagedRuleGroupName) + rg.SetVendorName("aws") + if len(rules) > 0 { + rg.SetExcludedRules(rules) + } + ret.SetManagedRuleGroupStatement(rg) + } + return ret +} + +func (self *SWebAcl) AddRule(opts *cloudprovider.SWafRule) (cloudprovider.ICloudWafRule, error) { + input := &wafv2.UpdateWebACLInput{} + input.SetLockToken(self.LockToken) + input.SetId(*self.Id) + input.SetName(*self.Name) + input.SetScope(self.scope) + input.SetDescription(*self.Description) + input.SetDefaultAction(self.DefaultAction) + input.SetVisibilityConfig(self.WebACL.VisibilityConfig) + rules := self.Rules + rule := &wafv2.Rule{} + rule.SetName(opts.Name) + rule.SetPriority(int64(opts.Priority)) + action := &wafv2.RuleAction{} + if opts.Action != nil { + switch opts.Action.Action { + case cloudprovider.WafActionAllow: + allow := &wafv2.AllowAction{} + action.SetAllow(allow) + case cloudprovider.WafActionBlock: + block := &wafv2.BlockAction{} + action.SetBlock(block) + case cloudprovider.WafActionCount: + count := &wafv2.CountAction{} + action.SetCount(count) + } + } + rule.SetAction(action) + visib := &wafv2.VisibilityConfig{} + visib.SetSampledRequestsEnabled(false) + visib.SetCloudWatchMetricsEnabled(true) + visib.SetMetricName(opts.Name) + rule.SetVisibilityConfig(visib) + statement := &wafv2.Statement{} + switch opts.StatementCondition { + case cloudprovider.WafStatementConditionOr: + ss := &wafv2.OrStatement{} + for _, s := range opts.Statements { + ss.Statements = append(ss.Statements, reverseConvertStatement(s)) + } + statement.SetOrStatement(ss) + case cloudprovider.WafStatementConditionAnd: + ss := &wafv2.AndStatement{} + for _, s := range opts.Statements { + ss.Statements = append(ss.Statements, reverseConvertStatement(s)) + } + statement.SetAndStatement(ss) + case cloudprovider.WafStatementConditionNot: + ss := &wafv2.NotStatement{} + for _, s := range opts.Statements { + ss.SetStatement(reverseConvertStatement(s)) + break + } + statement.SetNotStatement(ss) + case cloudprovider.WafStatementConditionNone: + for _, s := range opts.Statements { + statement = reverseConvertStatement(s) + break + } + } + rule.SetStatement(statement) + rules = append(rules, rule) + input.SetRules(rules) + client, err := self.region.getWafClient() + if err != nil { + return nil, errors.Wrapf(err, "getWafClient") + } + _, err = client.UpdateWebACL(input) + if err != nil { + return nil, errors.Wrapf(err, "UpdateWebACL") + } + ret := &sWafRule{waf: self, Rule: rule} + return ret, nil +} + +func (self *SWebAcl) GetCloudResources() ([]cloudprovider.SCloudResource, error) { + ret := []cloudprovider.SCloudResource{} + if self.scope != SCOPE_REGIONAL { + return ret, nil + } + for _, resType := range []string{"APPLICATION_LOAD_BALANCER", "API_GATEWAY", "APPSYNC"} { + resIds, err := self.region.ListResourcesForWebACL(resType, *self.ARN) + if err != nil { + return nil, errors.Wrapf(err, "ListResourcesForWebACL(%s, %s)", resType, *self.ARN) + } + for _, resId := range resIds { + ret = append(ret, cloudprovider.SCloudResource{ + Id: resId, + Name: resId, + Type: resType, + }) + } + } + return ret, nil +} diff --git a/pkg/multicloud/aws/waf_ipsets.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf_ipsets.go similarity index 98% rename from pkg/multicloud/aws/waf_ipsets.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf_ipsets.go index afc09b84e4..36aa85bb41 100644 --- a/pkg/multicloud/aws/waf_ipsets.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf_ipsets.go @@ -20,7 +20,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SWafIPSet struct { diff --git a/pkg/multicloud/aws/waf_regexsets.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf_regexsets.go similarity index 99% rename from pkg/multicloud/aws/waf_regexsets.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf_regexsets.go index 5c7ae8995b..99db26ace0 100644 --- a/pkg/multicloud/aws/waf_regexsets.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf_regexsets.go @@ -20,7 +20,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type RegularExpression struct { diff --git a/pkg/multicloud/aws/waf_rule_groups.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf_rule_groups.go similarity index 100% rename from pkg/multicloud/aws/waf_rule_groups.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf_rule_groups.go diff --git a/pkg/multicloud/aws/waf_rules.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf_rules.go similarity index 99% rename from pkg/multicloud/aws/waf_rules.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf_rules.go index 3bd8f2713e..53a0189dae 100644 --- a/pkg/multicloud/aws/waf_rules.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/waf_rules.go @@ -23,7 +23,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type sWafRule struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/wire.go new file mode 100644 index 0000000000..9caed192df --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/wire.go @@ -0,0 +1,141 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + AwsTags + 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 api.WIRE_STATUS_AVAILABLE +} + +func (self *SWire) Refresh() error { + return nil +} + +func (self *SWire) IsEmulated() bool { + return true +} + +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, errors.Wrap(err, "fetchNetworks") + } + } + 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, errors.Wrap(err, "GetINetworks") + } + for i := 0; i < len(networks); i += 1 { + if networks[i].GetGlobalId() == netid { + return networks[i], nil + } + } + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetINetworkById") +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + networkId, err := self.zone.region.createNetwork(self.zone.ZoneId, self.vpc.VpcId, opts.Name, opts.Cidr, opts.Desc) + if err != nil { + log.Errorf("createNetwork error %s", err) + return nil, errors.Wrap(err, "createNetwork") + } + self.inetworks = nil + network := self.getNetworkById(networkId) + if network == nil { + log.Errorf("cannot find network after create????") + return nil, errors.Wrap(cloudprovider.ErrNotFound, "getNetworkById") + } + 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) + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/zone.go new file mode 100644 index 0000000000..8044422c17 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/aws/zone.go @@ -0,0 +1,209 @@ +// Copyright 2019 Yunion +// +// 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 aws + +import ( + "fmt" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var StorageTypes = []string{ + api.STORAGE_GP2_SSD, + api.STORAGE_GP3_SSD, + api.STORAGE_IO1_SSD, + api.STORAGE_IO2_SSD, + api.STORAGE_ST1_HDD, + api.STORAGE_SC1_HDD, + api.STORAGE_STANDARD_HDD, +} + +type SZone struct { + multicloud.SResourceBase + AwsTags + region *SRegion + host *SHost + + iwires []cloudprovider.ICloudWire + + ZoneId string // 沿用阿里云ZoneId,对应Aws ZoneName + LocalName string + State 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) 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) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_AWS_EN, self.LocalName) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +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 api.ZONE_SOLDOUT + } else { + return api.ZONE_ENABLE + } +} + +func (self *SZone) Refresh() error { + return nil +} + +func (self *SZone) IsEmulated() bool { + return false +} + +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, errors.Wrap(cloudprovider.ErrNotFound, "GetIHostById") +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + ret := []cloudprovider.ICloudStorage{} + for i := range StorageTypes { + storage := &SStorage{zone: self, storageType: StorageTypes[i]} + ret = append(ret, storage) + } + return ret, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storages, err := self.GetIStorages() + if err != nil { + return nil, err + } + for i := 0; i < len(storages); i += 1 { + if storages[i].GetGlobalId() == id { + return storages[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "not found %s", id) +} + +func (self *SZone) getStorageByCategory(category string) (*SStorage, error) { + storages, err := self.GetIStorages() + if err != nil { + return nil, errors.Wrap(err, "GetIStorages") + } + 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, errors.Wrap(err, "GetIZones") + } + 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) +} + +func (self *SRegion) TestStorageAvailable(zoneId, storageType string) (bool, error) { + params := map[string]string{ + "AvailabilityZone": zoneId, + "ClientToken": utils.GenRequestId(20), + "DryRun": "true", + "Size": "125", + "VolumeType": storageType, + } + iops, ok := map[string]string{ + api.STORAGE_GP3_SSD: "3000", + api.STORAGE_IO1_SSD: "100", + api.STORAGE_IO2_SSD: "100", + }[storageType] + if ok { + params["Iops"] = iops + } + ret := struct{}{} + err := self.ec2Request("CreateVolume", params, &ret) + if err != nil { + if e, ok := err.(*sAwsError); ok && e.Errors.Code == "DryRunOperation" { + return true, nil + } + return false, errors.Wrapf(err, "CreateVolume") + } + return true, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/app_gateways.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/app_gateways.go new file mode 100644 index 0000000000..db758e7875 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/app_gateways.go @@ -0,0 +1,216 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "net/url" + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SGatewayipconfiguration struct { + Name string `json:"name"` + ID string `json:"id"` + Etag string `json:"etag"` + Properties struct { + Provisioningstate string `json:"provisioningState"` + Subnet struct { + ID string `json:"id"` + } `json:"subnet"` + } `json:"properties"` + Type string `json:"type"` +} + +type SFrontendipconfiguration struct { + Name string `json:"name"` + ID string `json:"id"` + Etag string `json:"etag"` + Type string `json:"type"` + Properties struct { + Provisioningstate string `json:"provisioningState"` + Privateipallocationmethod string `json:"privateIPAllocationMethod"` + PublicIPAddress struct { + ID string + } + PrivateIPAddress string + Subnet struct { + ID string `json:"id"` + } `json:"subnet"` + Httplisteners []struct { + ID string `json:"id"` + } `json:"httpListeners"` + } `json:"properties"` +} + +type SFrontendport struct { + Name string `json:"name"` + ID string `json:"id"` + Etag string `json:"etag"` + Properties struct { + Provisioningstate string `json:"provisioningState"` + Port int `json:"port"` + Httplisteners []struct { + ID string `json:"id"` + } `json:"httpListeners"` + } `json:"properties"` + Type string `json:"type"` +} + +type SBackendaddresspool struct { + Name string `json:"name"` + ID string `json:"id"` + Etag string `json:"etag"` + Properties struct { + Provisioningstate string `json:"provisioningState"` + Backendaddresses []interface{} `json:"backendAddresses"` + Requestroutingrules []struct { + ID string `json:"id"` + } `json:"requestRoutingRules"` + } `json:"properties"` + Type string `json:"type"` +} + +type SBackendhttpsettingscollection struct { + Name string `json:"name"` + ID string `json:"id"` + Etag string `json:"etag"` + Properties struct { + Provisioningstate string `json:"provisioningState"` + Port int `json:"port"` + Protocol string `json:"protocol"` + Cookiebasedaffinity string `json:"cookieBasedAffinity"` + Pickhostnamefrombackendaddress bool `json:"pickHostNameFromBackendAddress"` + Requesttimeout int `json:"requestTimeout"` + Requestroutingrules []struct { + ID string `json:"id"` + } `json:"requestRoutingRules"` + } `json:"properties"` + Type string `json:"type"` +} + +type SHttplistener struct { + Name string `json:"name"` + ID string `json:"id"` + Etag string `json:"etag"` + Properties struct { + Provisioningstate string `json:"provisioningState"` + Frontendipconfiguration struct { + ID string `json:"id"` + } `json:"frontendIPConfiguration"` + Frontendport struct { + ID string `json:"id"` + } `json:"frontendPort"` + Protocol string `json:"protocol"` + Requireservernameindication bool `json:"requireServerNameIndication"` + Requestroutingrules []struct { + ID string `json:"id"` + } `json:"requestRoutingRules"` + } `json:"properties"` + Type string `json:"type"` +} + +type SRequestroutingrule struct { + Name string `json:"name"` + ID string `json:"id"` + Etag string `json:"etag"` + Properties struct { + Provisioningstate string `json:"provisioningState"` + Ruletype string `json:"ruleType"` + Httplistener struct { + ID string `json:"id"` + } `json:"httpListener"` + Backendaddresspool struct { + ID string `json:"id"` + } `json:"backendAddressPool"` + Backendhttpsettings struct { + ID string `json:"id"` + } `json:"backendHttpSettings"` + } `json:"properties"` + Type string `json:"type"` +} + +type SApplicationGatewayProperties struct { + Provisioningstate string `json:"provisioningState"` + Resourceguid string `json:"resourceGuid"` + Sku struct { + Name string `json:"name"` + Tier string `json:"tier"` + Capacity string `json:"capacity"` + } `json:"sku"` + Operationalstate string `json:"operationalState"` + Gatewayipconfigurations []SGatewayipconfiguration `json:"gatewayIPConfigurations"` + Sslcertificates []interface{} `json:"sslCertificates"` + Authenticationcertificates []interface{} `json:"authenticationCertificates"` + Frontendipconfigurations []SFrontendipconfiguration `json:"frontendIPConfigurations"` + Frontendports []SFrontendport `json:"frontendPorts"` + Backendaddresspools []SBackendaddresspool `json:"backendAddressPools"` + Backendhttpsettingscollection []SBackendhttpsettingscollection `json:"backendHttpSettingsCollection"` + Httplisteners []SHttplistener `json:"httpListeners"` + Urlpathmaps []interface{} `json:"urlPathMaps"` + Requestroutingrules []SRequestroutingrule `json:"requestRoutingRules"` + Probes []interface{} `json:"probes"` + Redirectconfigurations []interface{} `json:"redirectConfigurations"` + Webapplicationfirewallconfiguration struct { + Enabled bool `json:"enabled"` + Firewallmode string `json:"firewallMode"` + Rulesettype string `json:"ruleSetType"` + Rulesetversion string `json:"ruleSetVersion"` + Disabledrulegroups []interface{} `json:"disabledRuleGroups"` + Requestbodycheck bool `json:"requestBodyCheck"` + } `json:"webApplicationFirewallConfiguration"` + Enablehttp2 bool `json:"enableHttp2"` +} + +type SApplicationGateway struct { + region *SRegion + multicloud.SResourceBase + AzureTags + + Name string `json:"name"` + Id string `json:"id"` + Etag string `json:"etag"` + Type string `json:"type"` + Location string `json:"location"` + Properties SApplicationGatewayProperties `json:"properties"` +} + +func (self *SApplicationGateway) GetName() string { + return self.Name +} + +func (self *SApplicationGateway) GetId() string { + return self.Id +} + +func (self *SApplicationGateway) GetGlobalId() string { + return strings.ToLower(self.Id) +} + +func (self *SRegion) ListAppGateways() ([]SApplicationGateway, error) { + apps := []SApplicationGateway{} + err := self.list("Microsoft.Network/applicationGateways", url.Values{}, &apps) + if err != nil { + return nil, errors.Wrapf(err, "list") + } + return apps, nil +} + +func (self *SRegion) GetApplicationGateway(id string) (*SApplicationGateway, error) { + ret := &SApplicationGateway{region: self} + return ret, self.get(id, url.Values{}, ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/app_service_plan.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/app_service_plan.go new file mode 100644 index 0000000000..69a3e7f016 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/app_service_plan.go @@ -0,0 +1,197 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + + "yunion.io/x/pkg/errors" +) + +type SAppServicePlan struct { + AzureTags + region *SRegion + + Properties SAppServicePlanProperties + ID string + Kind string + Location string + Name string + Type string + Sku SSkuDescription +} + +type SAppServicePlanProperties struct { + FreeOfferExpirationTime string + GeoRegion string + HostingEnvironmentProfile SHostingEnvironmentProfile + HyperV bool + IsSpot bool + MaximumElasticWorkerCount int + MaximumNumberOfWorkers int + NumberOfSites int + PerSiteScaling bool + // 应用服务环境的预配状态 + ProvisioningState string + Reserved bool + ResourceGroup string + SpotExpirationTime string + // Creating Pending Ready + Status string + Subscription string + TargetWorkerCount int + TargetWorkerSizeId int + WorkerTierName string +} + +type SHostingEnvironmentProfile struct { + ID string + Name string + Type string +} + +type SSkuDescription struct { + Capabilities []SCapability + Capacity int + Family string + locations []string + Name string + Size string + SkuCapacity SSkuCapacity + Tier string +} + +type SCapability struct { + Name string + Reason string + Value string +} + +type SSkuCapacity struct { + Default int + Maximum int + Minimum int + ScaleType string +} + +func (r *SRegion) GetAppServicePlanWithCache(id string) (*SAppServicePlan, error) { + if r.appServicePlans == nil { + plans, err := r.GetAppServicePlans() + if err != nil { + return nil, err + } + appServicePlans := make(map[string]*SAppServicePlan, len(plans)) + for i := range plans { + appServicePlans[plans[i].ID] = &plans[i] + } + r.appServicePlans = appServicePlans + } + if ret, ok := r.appServicePlans[id]; ok { + return ret, nil + } + return r.GetAppServicePlan(id) +} + +func (r *SRegion) GetAppServicePlans() ([]SAppServicePlan, error) { + result := []SAppServicePlan{} + resource := "Microsoft.Web/serverfarms" + err := r.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) + if err != nil { + return nil, err + } + for i := range result { + result[i].region = r + } + return result, nil +} + +func (r *SRegion) GetAppServicePlan(planId string) (*SAppServicePlan, error) { + asp := &SAppServicePlan{region: r} + params := url.Values{"api-version": []string{"2019-08-01"}} + return asp, r.get(planId, params, asp) +} + +type SServerFarmSku struct { + ResourceType string + Sku SSkuSpec + Capacity SSkuCapacity +} + +type SSkuSpec struct { + Name string + Tier string +} + +func (asp *SAppServicePlan) GetSkus() ([]SServerFarmSku, error) { + result := []SServerFarmSku{} + resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/serverfarms/%s/skus", asp.region.client._subscriptionId(), asp.Properties.ResourceGroup, asp.Name) + err := asp.region.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) + if err != nil { + return nil, err + } + return result, nil +} + +type SAppServicePlanVnet struct { + Id string + Name string + Properties SASPVnetProperties +} + +type SASPVnetProperties struct { + VnetResourceId string +} + +func (asp *SAppServicePlan) GetNetworks() ([]SNetwork, error) { + vnets, err := asp.GetVnets() + if err != nil { + return nil, errors.Wrap(err, "unable to get Vnets") + } + networks := make([]SNetwork, 0, len(vnets)) + for i := range vnets { + network, err := asp.region.GetNetwork(vnets[i].Properties.VnetResourceId) + if err != nil { + return nil, errors.Wrap(err, "unable to get Network") + } + networks = append(networks, *network) + } + return networks, nil +} + +func (asp *SAppServicePlan) GetVnets() ([]SAppServicePlanVnet, error) { + result := []SAppServicePlanVnet{} + resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/serverfarms/%s/virtualNetworkConnections", asp.region.client._subscriptionId(), asp.Properties.ResourceGroup, asp.Name) + err := asp.region.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) + if err != nil { + return nil, err + } + return result, nil +} + +type SSkuInfos struct { + ResourceType string + Skus []SResourceSku +} + +func (r *SRegion) GetAppServiceSkus() ([]SSkuInfos, error) { + result := []SSkuInfos{} + resource := "Microsoft.Web/skus" + err := r.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) + if err != nil { + return nil, err + } + return result, err +} diff --git a/pkg/multicloud/azure/autoscale_setting.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/autoscale_setting.go similarity index 98% rename from pkg/multicloud/azure/autoscale_setting.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/autoscale_setting.go index afbd725871..968cc6e81a 100644 --- a/pkg/multicloud/azure/autoscale_setting.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/autoscale_setting.go @@ -16,12 +16,10 @@ package azure import ( "net/url" - - "yunion.io/x/onecloud/pkg/multicloud" ) type SAutoscaleSettingResource struct { - multicloud.AzureTags + AzureTags region *SRegion Properties SAutoscaleSettingProperties diff --git a/pkg/multicloud/azure/azure.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/azure.go similarity index 99% rename from pkg/multicloud/azure/azure.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/azure.go index 431bdb8dab..bd2e835301 100644 --- a/pkg/multicloud/azure/azure.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/azure.go @@ -47,8 +47,8 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/utils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/pkg/multicloud/azure/blobobject.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/blobobject.go similarity index 98% rename from pkg/multicloud/azure/blobobject.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/blobobject.go index 89332ff723..9cdad09a0b 100644 --- a/pkg/multicloud/azure/blobobject.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/blobobject.go @@ -23,7 +23,7 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SObject struct { diff --git a/pkg/multicloud/azure/classic_disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_disk.go similarity index 95% rename from pkg/multicloud/azure/classic_disk.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_disk.go index 40d19b53b3..43159a7f92 100644 --- a/pkg/multicloud/azure/classic_disk.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_disk.go @@ -22,10 +22,10 @@ import ( "yunion.io/x/pkg/errors" - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type ClassicProperties struct { @@ -44,7 +44,7 @@ type ClassicProperties struct { type SClassicDisk struct { multicloud.SDisk - multicloud.AzureTags + AzureTags region *SRegion Id string diff --git a/pkg/multicloud/azure/classic_eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_eip.go similarity index 95% rename from pkg/multicloud/azure/classic_eip.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_eip.go index dc93bc8a5c..438a032233 100644 --- a/pkg/multicloud/azure/classic_eip.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_eip.go @@ -22,10 +22,10 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type ClassicEipProperties struct { @@ -39,7 +39,7 @@ type ClassicEipProperties struct { type SClassicEipAddress struct { region *SRegion multicloud.SEipBase - multicloud.AzureTags + AzureTags ID string instanceId string diff --git a/pkg/multicloud/azure/classic_host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_host.go similarity index 96% rename from pkg/multicloud/azure/classic_host.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_host.go index bd4eab8abd..bdc3405d98 100644 --- a/pkg/multicloud/azure/classic_host.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_host.go @@ -20,9 +20,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SClassicHost struct { diff --git a/pkg/multicloud/azure/classic_instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_instance.go similarity index 98% rename from pkg/multicloud/azure/classic_instance.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_instance.go index 27a4a931d0..d61021048e 100644 --- a/pkg/multicloud/azure/classic_instance.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_instance.go @@ -26,11 +26,11 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/util/osprofile" - "yunion.io/x/onecloud/pkg/apis" - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/apis" + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/billing" ) @@ -136,7 +136,7 @@ type ClassicVirtualMachineProperties struct { type SClassicInstance struct { multicloud.SInstanceBase - multicloud.AzureTags + AzureTags host *SClassicHost diff --git a/pkg/multicloud/azure/classic_instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_instancenic.go similarity index 97% rename from pkg/multicloud/azure/classic_instancenic.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_instancenic.go index c50b1a7c8f..229f276d37 100644 --- a/pkg/multicloud/azure/classic_instancenic.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_instancenic.go @@ -19,7 +19,7 @@ import ( "yunion.io/x/pkg/util/netutils" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SClassicInstanceNic struct { diff --git a/pkg/multicloud/azure/classic_instancesize.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_instancesize.go similarity index 100% rename from pkg/multicloud/azure/classic_instancesize.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_instancesize.go diff --git a/pkg/multicloud/azure/classic_network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_network.go similarity index 96% rename from pkg/multicloud/azure/classic_network.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_network.go index c97adf874c..4d9a91eda1 100644 --- a/pkg/multicloud/azure/classic_network.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_network.go @@ -20,15 +20,15 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/util/netutils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/rbacutils" ) type SClassicNetwork struct { multicloud.SResourceBase - multicloud.AzureTags + AzureTags wire *SClassicWire id string diff --git a/pkg/multicloud/azure/classic_secruitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_secruitygroup.go similarity index 98% rename from pkg/multicloud/azure/classic_secruitygroup.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_secruitygroup.go index 0b5a36523b..51c2a4fca8 100644 --- a/pkg/multicloud/azure/classic_secruitygroup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_secruitygroup.go @@ -27,13 +27,13 @@ import ( "yunion.io/x/pkg/util/secrules" "yunion.io/x/pkg/utils" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SClassicSecurityGroup struct { multicloud.SSecurityGroup - multicloud.AzureTags + AzureTags region *SRegion vpc *SClassicVpc Properties ClassicSecurityGroupProperties `json:"properties,omitempty"` diff --git a/pkg/multicloud/azure/classic_snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_snapshot.go similarity index 93% rename from pkg/multicloud/azure/classic_snapshot.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_snapshot.go index 1a21d83560..dd262362f3 100644 --- a/pkg/multicloud/azure/classic_snapshot.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_snapshot.go @@ -17,14 +17,14 @@ package azure import ( "fmt" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SClassicSnapshot struct { multicloud.SResourceBase - multicloud.AzureTags + AzureTags region *SRegion Name string diff --git a/pkg/multicloud/azure/classic_storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_storage.go similarity index 95% rename from pkg/multicloud/azure/classic_storage.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_storage.go index 39c9d2d582..596e823061 100644 --- a/pkg/multicloud/azure/classic_storage.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_storage.go @@ -21,9 +21,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) const ( @@ -33,7 +33,7 @@ const ( type SClassicStorage struct { multicloud.SStorageBase - multicloud.AzureTags + AzureTags region *SRegion AccountType string diff --git a/pkg/multicloud/azure/classic_vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_vpc.go similarity index 95% rename from pkg/multicloud/azure/classic_vpc.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_vpc.go index ab61e70313..e3d672aec5 100644 --- a/pkg/multicloud/azure/classic_vpc.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_vpc.go @@ -20,9 +20,9 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type ClassicAddressSpace struct { @@ -45,7 +45,7 @@ type ClassicVpcProperties struct { type SClassicVpc struct { multicloud.SVpc - multicloud.AzureTags + AzureTags region *SRegion diff --git a/pkg/multicloud/azure/classic_wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_wire.go similarity index 94% rename from pkg/multicloud/azure/classic_wire.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_wire.go index 5137802c5a..f67e10d9ab 100644 --- a/pkg/multicloud/azure/classic_wire.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/classic_wire.go @@ -20,14 +20,14 @@ import ( "yunion.io/x/log" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SClassicWire struct { multicloud.SResourceBase - multicloud.AzureTags + AzureTags zone *SZone vpc *SClassicVpc diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/cloudgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/cloudgroup.go new file mode 100644 index 0000000000..2daee24d25 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/cloudgroup.go @@ -0,0 +1,247 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SCloudgroup struct { + client *SAzureClient + + Id string + DeletionTimestamp string + Description string + DirSyncEnabled string + DisplayName string + LastDirSyncTime string + Mail string + MailNickname string + MailEnabled bool + ProxyAddresses []string +} + +func (group *SCloudgroup) GetName() string { + return group.DisplayName +} + +func (group *SCloudgroup) GetGlobalId() string { + return group.Id +} + +func (group *SCloudgroup) GetDescription() string { + return group.Description +} + +func (group *SCloudgroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := group.client.GetCloudpolicies(group.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetCloudpolicies(%s)", group.Id) + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].Properties.Type == "BuiltInRole" { + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (group *SCloudgroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := group.client.GetCloudpolicies(group.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetCloudpolicies(%s)", group.Id) + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].Properties.Type != "BuiltInRole" { + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (group *SCloudgroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { + users, err := group.client.ListGroupMemebers(group.Id) + if err != nil { + return nil, errors.Wrap(err, "ListGroupMemebers") + } + ret := []cloudprovider.IClouduser{} + for i := range users { + users[i].client = group.client + ret = append(ret, &users[i]) + } + return ret, nil +} + +func (group *SCloudgroup) AddUser(name string) error { + return group.client.AddGroupUser(group.Id, name) +} + +func (group *SCloudgroup) RemoveUser(name string) error { + return group.client.RemoveGroupUser(group.Id, name) +} + +func (group *SCloudgroup) AttachSystemPolicy(policyId string) error { + return group.client.AssignPolicy(group.Id, policyId, "") +} + +func (group *SCloudgroup) AttachCustomPolicy(policyId string) error { + return group.client.AssignPolicy(group.Id, policyId, "") +} + +func (group *SCloudgroup) DetachSystemPolicy(policyId string) error { + assignments, err := group.client.GetAssignments(group.Id) + if err != nil { + return errors.Wrapf(err, "GetAssignments(%s)", group.Id) + } + for _, assignment := range assignments { + role, err := group.client.GetRole(assignment.Properties.RoleDefinitionId) + if err != nil { + return errors.Wrapf(err, "GetRule(%s)", assignment.Properties.RoleDefinitionId) + } + if role.Properties.RoleName == policyId { + return group.client.gdel(assignment.Id) + } + } + return nil +} + +func (group *SCloudgroup) DetachCustomPolicy(policyId string) error { + return group.DetachSystemPolicy(policyId) +} + +func (group *SCloudgroup) Delete() error { + return group.client.DeleteGroup(group.Id) +} + +func (self *SAzureClient) GetCloudgroups(name string) ([]SCloudgroup, error) { + groups := []SCloudgroup{} + params := url.Values{} + if len(name) > 0 { + params.Set("$filter", fmt.Sprintf("displayName eq '%s'", name)) + } + err := self.glist("groups", params, &groups) + if err != nil { + return nil, err + } + return groups, nil +} + +func (self *SAzureClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + groups, err := self.GetCloudgroups("") + if err != nil { + return nil, errors.Wrap(err, "GetCloudgroups") + } + ret := []cloudprovider.ICloudgroup{} + for i := range groups { + groups[i].client = self + ret = append(ret, &groups[i]) + } + return ret, nil +} + +func (self *SAzureClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + groups, err := self.GetCloudgroups(name) + if err != nil { + return nil, errors.Wrapf(err, "GetCloudgroups(%s)", name) + } + if len(groups) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(groups) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + groups[0].client = self + return &groups[0], nil +} + +func (self *SAzureClient) ListGroupMemebers(id string) ([]SClouduser, error) { + users := []SClouduser{} + resource := fmt.Sprintf("groups/%s/members", id) + err := self.glist(resource, nil, &users) + if err != nil { + return nil, err + } + return users, nil +} + +func (self *SAzureClient) DeleteGroup(id string) error { + return self.gdel(fmt.Sprintf("groups/%s", id)) +} + +func (self *SAzureClient) CreateGroup(name, desc string) (*SCloudgroup, error) { + params := map[string]interface{}{ + "displayName": name, + "mailEnabled": false, + "securityEnabled": true, + } + nickName := "" + for _, s := range name { + if s >= 0 && s <= 127 { + nickName += string(s) + } + } + params["mailNickname"] = nickName + if len(desc) > 0 { + params["Description"] = desc + } + group := SCloudgroup{client: self} + err := self.gcreate("groups", jsonutils.Marshal(params), &group) + if err != nil { + return nil, errors.Wrap(err, "Create") + } + return &group, nil +} + +func (self *SAzureClient) RemoveGroupUser(id, userName string) error { + user, err := self.GetClouduser(userName) + if err != nil { + return errors.Wrapf(err, "GetCloudusers(%s)", userName) + } + return self.gdel(fmt.Sprintf("/groups/%s/members/%s/$ref", id, user.Id)) +} + +func (self *SAzureClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + group, err := self.CreateGroup(name, desc) + if err != nil { + return nil, errors.Wrap(err, "CreateGroup") + } + group.client = self + return group, nil +} + +func (self *SAzureClient) AddGroupUser(id, userName string) error { + user, err := self.GetClouduser(userName) + if err != nil { + return errors.Wrapf(err, "GetCloudusers(%s)", userName) + } + resource := fmt.Sprintf("groups/%s/members/$ref", id) + params := map[string]string{ + "@odata.id": fmt.Sprintf("https://graph.microsoft.com/v1.0/directoryObjects/%s", user.Id), + } + err = self.gcreate(resource, jsonutils.Marshal(params), nil) + if err != nil && !strings.Contains(err.Error(), "One or more added object references already exist for the following modified properties") { + return err + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/cloudpolicy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/cloudpolicy.go new file mode 100644 index 0000000000..bcedcb6615 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/cloudpolicy.go @@ -0,0 +1,207 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/stringutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SPermission struct { + Actions []string + NotActions []string + DataActions []string + NotDataActions []string +} + +type SRoleProperties struct { + RoleName string + Type string + Description string + AssignableScopes []string + Permissions []SPermission +} + +type SCloudpolicy struct { + Id string + Type string + Name string + Properties SRoleProperties +} + +func (role *SCloudpolicy) GetName() string { + return role.Properties.RoleName +} + +func (role *SCloudpolicy) GetGlobalId() string { + return role.Properties.RoleName +} + +func (role *SCloudpolicy) GetDescription() string { + return role.Properties.Description +} + +func (role *SCloudpolicy) UpdateDocument(document *jsonutils.JSONDict) error { + return cloudprovider.ErrNotImplemented +} + +func (role *SCloudpolicy) GetDocument() (*jsonutils.JSONDict, error) { + return jsonutils.Marshal(role.Properties).(*jsonutils.JSONDict), nil +} + +func (role *SCloudpolicy) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (cli *SAzureClient) GetRoles(name, policyType string) ([]SCloudpolicy, error) { + ret := []SCloudpolicy{} + filter := []string{} + if len(name) > 0 { + filter = append(filter, fmt.Sprintf("roleName eq '%s'", name)) + } + if len(policyType) > 0 { + filter = append(filter, fmt.Sprintf("Type eq '%s'", policyType)) + } + params := url.Values{} + if len(filter) > 0 { + params.Set("$filter", strings.Join(filter, " and ")) + } + resource := "Microsoft.Authorization/roleDefinitions" + err := cli.list(resource, params, &ret) + if err != nil { + return nil, errors.Wrap(err, "list") + } + return ret, nil +} + +func (cli *SAzureClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + roles, err := cli.GetRoles("", "BuiltInRole") + if err != nil { + return nil, errors.Wrap(err, "GetRoles") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range roles { + ret = append(ret, &roles[i]) + } + return ret, nil +} + +func (cli *SAzureClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + roles, err := cli.GetRoles("", "CustomRole") + if err != nil { + return nil, errors.Wrap(err, "GetRoles") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range roles { + ret = append(ret, &roles[i]) + } + return ret, nil +} + +func (cli *SAzureClient) AssignPolicy(objectId, roleName, subscriptionId string) error { + roles, err := cli.GetRoles(roleName, "") + if err != nil { + return errors.Wrapf(err, "GetRoles(%s)", roleName) + } + if len(roles) == 0 { + return errors.Wrap(cloudprovider.ErrNotFound, roleName) + } + if len(roles) > 1 { + return errors.Wrap(cloudprovider.ErrDuplicateId, roleName) + } + body := map[string]interface{}{ + "properties": map[string]interface{}{ + "roleDefinitionId": roles[0].Id, + "principalId": objectId, + }, + } + subscriptionIds := []string{} + if len(subscriptionId) == 0 { + for _, subscription := range cli.subscriptions { + subscriptionIds = append(subscriptionIds, subscription.SubscriptionId) + } + } + for _, subscriptionId := range subscriptionIds { + resource := fmt.Sprintf("subscriptions/%s/providers/Microsoft.Authorization/roleAssignments/%s", subscriptionId, stringutils.UUID4()) + _, err = cli.put(resource, jsonutils.Marshal(body)) + if err != nil { + if e, ok := err.(*AzureResponseError); ok && e.AzureError.Code == "ReadOnlyDisabledSubscription" || e.AzureError.Code == "PrincipalNotFound" { + continue + } + return errors.Wrapf(err, "AssignPolicy %s for subscription %s", roleName, subscriptionId) + } + } + return nil +} + +type SAssignmentProperties struct { + RoleDefinitionId string + PrincipalId string + PrincipalType string + Scope string +} + +type SAssignment struct { + Id string + Name string + Type string + Properties SAssignmentProperties +} + +func (cli *SAzureClient) GetAssignments(objectId string) ([]SAssignment, error) { + ret := []SAssignment{} + params := url.Values{} + if len(objectId) > 0 { + params.Set("$filter", fmt.Sprintf("principalId eq '%s'", objectId)) + } + resource := "Microsoft.Authorization/roleAssignments" + err := cli.list(resource, params, &ret) + if err != nil { + return nil, errors.Wrap(err, "list") + } + return ret, nil +} + +func (cli *SAzureClient) GetRole(roleId string) (*SCloudpolicy, error) { + role := &SCloudpolicy{} + err := cli.get(roleId, nil, role) + if err != nil { + return nil, errors.Wrapf(err, "GetRole(%s)", roleId) + } + return role, nil +} + +func (cli *SAzureClient) GetCloudpolicies(objectId string) ([]SCloudpolicy, error) { + assignments, err := cli.GetAssignments(objectId) + if err != nil { + return nil, errors.Wrapf(err, "GetAssignments(%s)", objectId) + } + ret := []SCloudpolicy{} + for _, assignment := range assignments { + role, err := cli.GetRole(assignment.Properties.RoleDefinitionId) + if err != nil { + return nil, errors.Wrapf(err, "GetRule(%s)", assignment.Properties.RoleDefinitionId) + } + ret = append(ret, *role) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/clouduser.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/clouduser.go new file mode 100644 index 0000000000..692db2519c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/clouduser.go @@ -0,0 +1,359 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type SClouduserPasswordProfile struct { + Password string + forceChangePasswordNextLogin bool + enforceChangePasswordPolicy bool +} + +type SClouduser struct { + client *SAzureClient + multicloud.SBaseClouduser + + OdataType string `json:"odata.type"` + ObjectType string + Id string + DeletionTimestamp string + AccountEnabled bool + AgeGroup string + City string + CompanyName string + ConsentProvidedForMinor string + Country string + CreatedDateTime time.Time + CreationType string + Department string + DirSyncEnabled string + DisplayName string + EmployeeId string + FacsimileTelephoneNumber string + GivenName string + ImmutableId string + IsCompromised string + JobTitle string + LastDirSyncTime string + LegalAgeGroupClassification string + Mail string + MailNickname string + Mobile string + OnPremisesDistinguishedName string + OnPremisesSecurityIdentifier string + PasswordPolicies string + PasswordProfile SClouduserPasswordProfile + PhysicalDeliveryOfficeName string + PostalCode string + PreferredLanguage string + RefreshTokensValidFromDateTime time.Time + ShowInAddressList string + SipProxyAddress string + State string + StreetAddress string + Surname string + TelephoneNumber string + ThumbnailPhotoOdataMediaEditLink string `json:"thumbnailPhoto@odata.mediaEditLink"` + UsageLocation string + UserPrincipalName string + UserState string + UserStateChangedOn string + UserType string + + inviteRedeemUrl string +} + +func (user *SClouduser) GetName() string { + return user.UserPrincipalName +} + +func (user *SClouduser) GetGlobalId() string { + return user.Id +} + +func (user *SClouduser) GetEmailAddr() string { + return user.Mail +} + +func (user *SClouduser) GetInviteUrl() string { + return user.inviteRedeemUrl +} + +func (user *SClouduser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := user.client.GetCloudpolicies(user.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetCloudpolicies(%s)", user.Id) + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].Properties.Type == "BuiltInRole" { + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (user *SClouduser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := user.client.GetCloudpolicies(user.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetCloudpolicies(%s)", user.Id) + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].Properties.Type != "BuiltInRole" { + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (user *SClouduser) AttachSystemPolicy(policyId string) error { + for _, subscription := range user.client.subscriptions { + err := user.client.AssignPolicy(user.Id, policyId, subscription.SubscriptionId) + if err != nil { + return errors.Wrapf(err, "AssignPolicy for subscription %s", subscription.SubscriptionId) + } + } + return nil +} + +func (user *SClouduser) AttachCustomPolicy(policyId string) error { + for _, subscription := range user.client.subscriptions { + err := user.client.AssignPolicy(user.Id, policyId, subscription.SubscriptionId) + if err != nil { + return errors.Wrapf(err, "AssignPolicy for subscription %s", subscription.SubscriptionId) + } + } + return nil +} + +func (user *SClouduser) DetachSystemPolicy(policyId string) error { + assignments, err := user.client.GetAssignments(user.Id) + if err != nil { + return errors.Wrapf(err, "GetAssignments(%s)", user.Id) + } + for _, assignment := range assignments { + role, err := user.client.GetRole(assignment.Properties.RoleDefinitionId) + if err != nil { + return errors.Wrapf(err, "GetRule(%s)", assignment.Properties.RoleDefinitionId) + } + if role.Properties.RoleName == policyId { + return user.client.gdel(assignment.Id) + } + } + return nil +} + +func (user *SClouduser) DetachCustomPolicy(policyId string) error { + return user.DetachSystemPolicy(policyId) +} + +func (user *SClouduser) IsConsoleLogin() bool { + return true +} + +// 需要当前应用有User administrator权限 +func (user *SClouduser) Delete() error { + return user.client.DeleteClouduser(user.UserPrincipalName) +} + +func (user *SClouduser) ResetPassword(password string) error { + return user.client.ResetClouduserPassword(user.Id, password) +} + +func (user *SClouduser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + groups, err := user.client.GetUserGroups(user.Id) + if err != nil { + return nil, errors.Wrap(err, "GetUserGroups") + } + ret := []cloudprovider.ICloudgroup{} + for i := range groups { + groups[i].client = user.client + ret = append(ret, &groups[i]) + } + return ret, nil +} + +func (self *SAzureClient) GetUserGroups(userId string) ([]SCloudgroup, error) { + resource := fmt.Sprintf("users/%s/memberOf", userId) + groups := []SCloudgroup{} + err := self.glist(resource, url.Values{}, &groups) + return groups, err +} + +func (self *SAzureClient) ResetClouduserPassword(id, password string) error { + body := jsonutils.Marshal(map[string]interface{}{ + "passwordPolicies": "DisablePasswordExpiration, DisableStrongPassword", + "passwordProfile": map[string]interface{}{ + "password": password, + }, + }) + resource := fmt.Sprintf("%s/users/%s", self.tenantId, id) + _, err := self.gpatch(resource, body) + return err +} + +func (self *SAzureClient) GetClouduser(name string) (*SClouduser, error) { + users, err := self.GetCloudusers() + if err != nil { + return nil, err + } + for i := range users { + if users[i].DisplayName == name || users[i].UserPrincipalName == name { + users[i].client = self + return &users[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SAzureClient) GetCloudusers() ([]SClouduser, error) { + users := []SClouduser{} + params := url.Values{} + err := self.glist("users", params, &users) + if err != nil { + return nil, err + } + return users, nil +} + +func (self *SAzureClient) DeleteClouduser(id string) error { + _, err := self.msGraphRequest(string(httputils.DELETE), "users/"+id, nil) + return err +} + +func (self *SAzureClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { + users, err := self.ListGraphUsers() + if err != nil { + return nil, errors.Wrap(err, "ListGraphUsers") + } + ret := []cloudprovider.IClouduser{} + for i := range users { + users[i].client = self + ret = append(ret, &users[i]) + } + return ret, nil +} + +func (self *SAzureClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + user, err := self.GetClouduser(name) + if err != nil { + return nil, errors.Wrap(err, "GetCloudusers") + } + return user, nil +} + +func (self *SAzureClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + if conf.UserType == "Guest" { + return self.InviteUser(conf.Email) + } + return self.CreateClouduser(conf.Name, conf.Password) +} + +type SDomain struct { + Name string + AuthenticationType string + AvailabilityStatus string + IsAdminManaged bool + IsDefault bool + IsDefaultForCloudRedirections bool + IsInitial bool + IsRoot bool + IsVerified bool + ForceDeleteState string + State string + PasswordValidityPeriodInDays string + PasswordNotificationWindowInDays string +} + +func (self *SAzureClient) GetDomains() ([]SDomain, error) { + domains := []SDomain{} + err := self.glist("domains", nil, &domains) + if err != nil { + return nil, errors.Wrap(err, "glist") + } + return domains, nil +} + +func (self *SAzureClient) GetDefaultDomain() (string, error) { + users, err := self.ListGraphUsers() + if err != nil { + return "", errors.Wrapf(err, "ListGraphUsers") + } + for i := range users { + idx := strings.Index(users[i].UserPrincipalName, "@") + if idx > -1 { + return users[i].UserPrincipalName[idx+1:], nil + } + } + return "", cloudprovider.ErrNotFound +} + +func (self *SAzureClient) CreateClouduser(name, password string) (*SClouduser, error) { + passwordProfile := map[string]interface{}{ + "password": "Lomo1824", + } + if len(password) > 0 { + passwordProfile["password"] = password + } + params := map[string]interface{}{ + "accountEnabled": true, + "displayName": name, + "mailNickname": name, + "passwordProfile": passwordProfile, + "userPrincipalName": name, + } + domain, err := self.GetDefaultDomain() + if err != nil { + return nil, errors.Wrap(err, "GetDefaultDomain") + } + params["userPrincipalName"] = fmt.Sprintf("%s@%s", name, domain) + user := SClouduser{client: self} + resp, err := self.msGraphRequest(string(httputils.POST), "users", jsonutils.Marshal(params)) + if err != nil { + return nil, errors.Wrap(err, "Create") + } + err = resp.Unmarshal(&user) + if err != nil { + return nil, err + } + return &user, nil +} + +func (self *SAzureClient) ListGraphUsers() ([]SClouduser, error) { + resp, err := self.msGraphRequest("GET", "users", nil) + if err != nil { + return nil, errors.Wrapf(err, "msGraphRequest.users") + } + users := []SClouduser{} + err = resp.Unmarshal(&users, "value") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return users, nil +} diff --git a/pkg/multicloud/azure/concurrent/balancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/balancer.go similarity index 100% rename from pkg/multicloud/azure/concurrent/balancer.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/balancer.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/doc.go new file mode 100644 index 0000000000..cac2ce8a19 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 concurrent // import "yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent" diff --git a/pkg/multicloud/azure/concurrent/pool.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/pool.go similarity index 100% rename from pkg/multicloud/azure/concurrent/pool.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/pool.go diff --git a/pkg/multicloud/azure/concurrent/request.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/request.go similarity index 100% rename from pkg/multicloud/azure/concurrent/request.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/request.go diff --git a/pkg/multicloud/azure/concurrent/worker.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/worker.go similarity index 100% rename from pkg/multicloud/azure/concurrent/worker.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent/worker.go diff --git a/pkg/multicloud/azure/data_disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/data_disk.go similarity index 96% rename from pkg/multicloud/azure/data_disk.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/data_disk.go index 6435256bdd..9d22a64a97 100644 --- a/pkg/multicloud/azure/data_disk.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/data_disk.go @@ -20,14 +20,14 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SDataDisk struct { multicloud.SDisk - multicloud.AzureTags + AzureTags region *SRegion Lun int32 diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance.go new file mode 100644 index 0000000000..2f0f2d3985 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance.go @@ -0,0 +1,406 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceVirtualNetworkRule struct { + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Properties SDBInstanceVirtualNetworkRuleProperties `json:"properties"` +} + +type SDBInstanceVirtualNetworkRuleProperties struct { + IgnoreMissingVnetServiceEndpoint bool `json:"ignoreMissingVnetServiceEndpoint"` + State string `json:"state"` + VirtualNetworkSubnetID string `json:"virtualNetworkSubnetId"` +} + +type SDBInstanceSku struct { + Name string `json:"name"` + Tier string `json:"tier"` + Family string `json:"family"` + Capacity int `json:"capacity"` +} + +type SDBInstanceStorageProfile struct { + StorageMB int `json:"storageMB"` + BackupRetentionDays int `json:"backupRetentionDays"` + StorageIops int `json:"storageIops"` + GeoRedundantBackup string `json:"geoRedundantBackup"` +} + +type SDBInstanceDelegatedSubnetArguments struct { + SubnetArmResourceId string `json:"subnetArmResourceId"` +} + +type SDBInstanceProperties struct { + AdministratorLogin string `json:"administratorLogin"` + StorageProfile SDBInstanceStorageProfile `json:"storageProfile"` + Version string `json:"version"` + SslEnforcement string `json:"sslEnforcement"` + UserVisibleState string `json:"userVisibleState"` + FullyQualifiedDomainName string `json:"fullyQualifiedDomainName"` + EarliestRestoreDate time.Time `json:"earliestRestoreDate"` + + ReplicationRole string `json:"replicationRole"` + MasterServerId string `json:"masterServerId"` + ReplicaCapacity int `json:"replicaCapacity"` + DelegatedSubnetArguments SDBInstanceDelegatedSubnetArguments `json:"delegatedSubnetArguments"` +} + +type SDBInstance struct { + region *SRegion + multicloud.SDBInstanceBase + AzureTags + Sku SDBInstanceSku `json:"sku"` + Properties SDBInstanceProperties `json:"properties"` + Location string `json:"location"` + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` +} + +func (self *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { + instanceTypes := []string{ + "Microsoft.DBForMariaDB/servers", + "Microsoft.DBforMySQL/servers", + "Microsoft.DBforMySQL/flexibleServers", + "Microsoft.DBforPostgreSQL/servers", + "Microsoft.DBforPostgreSQL/flexibleServers", + } + DBInstances := []SDBInstance{} + for i := range instanceTypes { + instances, err := self.ListDBInstance(instanceTypes[i]) + if err != nil { + if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, errors.Wrap(err, "self.ListDBInstance()") + } + } + DBInstances = append(DBInstances, instances...) + } + result := []cloudprovider.ICloudDBInstance{} + for i := range DBInstances { + DBInstances[i].region = self + result = append(result, &DBInstances[i]) + } + sqlServers, err := self.ListSQLServer() + if err != nil { + return nil, errors.Wrapf(err, "ListSQLServer") + } + for i := range sqlServers { + sqlServers[i].region = self + result = append(result, &sqlServers[i]) + } + managedSQLServers, err := self.ListManagedSQLServer() + if err != nil { + return nil, errors.Wrapf(err, "ListManagedSQLServer") + } + for i := range managedSQLServers { + managedSQLServers[i].region = self + result = append(result, &managedSQLServers[i]) + } + return result, nil +} + +func (self *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { + if strings.Index(strings.ToLower(instanceId), "microsoft.sql/servers") > 0 { + return self.GetSQLServer(instanceId) + } + if strings.Index(strings.ToLower(instanceId), "microsoft.sql/managedinstances") > 0 { + return self.GetManagedSQLServer(instanceId) + } + rds, err := self.GetDBInstanceById(instanceId) + if err != nil { + return nil, errors.Wrapf(err, "self.get(%s, url.Values{}, &newrds)", instanceId) + } + return rds, nil +} + +func (self *SRegion) GetDBInstanceById(instanceId string) (*SDBInstance, error) { + rds := SDBInstance{} + err := self.get(instanceId, url.Values{}, &rds) + if err != nil { + return nil, errors.Wrapf(err, "self.get(%s, url.Values{}, &newrds)", instanceId) + } + rds.region = self + return &rds, nil +} + +func (self *SRegion) ListDBInstance(instanceType string) ([]SDBInstance, error) { + result := []SDBInstance{} + err := self.list(instanceType, url.Values{}, &result) + if err != nil { + return nil, errors.Wrapf(err, "list(%s)", instanceType) + } + for i := range result { + result[i].region = self + } + return result, nil +} + +func (self *SRegion) ListDBInstanceReplica(Id string) ([]SDBInstance, error) { + type replicas struct { + Value []SDBInstance + } + result := replicas{} + err := self.get(fmt.Sprintf("%s/replicas", Id), url.Values{}, &result) + if err != nil { + return nil, errors.Wrapf(err, "get(%s)", Id) + } + for i := range result.Value { + result.Value[i].region = self + } + return result.Value, nil +} + +func (self *SRegion) ListDBInstanceVirtualNetworkRule(Id string) ([]SDBInstanceVirtualNetworkRule, error) { + type networksRules struct { + Value []SDBInstanceVirtualNetworkRule + } + result := networksRules{} + err := self.get(fmt.Sprintf("%s/virtualNetworkRules", Id), url.Values{}, &result) + if err != nil { + return nil, errors.Wrapf(err, "get(%s)", Id) + } + return result.Value, nil +} + +func (rds *SDBInstance) GetName() string { + return rds.Name +} + +func (rds *SDBInstance) GetId() string { + return strings.ToLower(rds.ID) +} + +func (rds *SDBInstance) GetGlobalId() string { + return rds.GetId() +} + +func (rds *SDBInstance) GetStatus() string { + return api.DBINSTANCE_RUNNING +} + +func (self *SDBInstance) GetProjectId() string { + return getResourceGroup(self.ID) +} + +func (rds *SDBInstance) GetExpiredAt() time.Time { + return time.Time{} +} + +func (rds *SDBInstance) GetStorageType() string { + switch rds.Sku.Tier { + case "Basic": + return api.STORAGE_AZURE_BASIC + case "General Purpose": + return api.STORAGE_AZURE_GENERAL_PURPOSE + case "Memory Optimized": + return api.STORAGE_AZURE_GENERAL_PURPOSE + default: + return api.STORAGE_AZURE_BASIC + } +} + +func (rds *SDBInstance) Refresh() error { + newrds := SDBInstance{} + err := rds.region.get(rds.ID, url.Values{}, &newrds) + if err != nil { + return errors.Wrapf(err, "rds.region.get(%s, url.Values{}, &newdb)", rds.ID) + } + + err = jsonutils.Update(rds, newrds) + if err != nil { + return err + } + rds.Tags = newrds.Tags + return nil +} + +func (rds *SDBInstance) GetMasterInstanceId() string { + if len(rds.Properties.MasterServerId) > 0 { + return strings.ToLower(rds.Properties.MasterServerId) + } + return "" +} + +func (rds *SDBInstance) GetPort() int { + switch rds.GetEngine() { + case api.DBINSTANCE_TYPE_POSTGRESQL: + return 5432 + case api.DBINSTANCE_TYPE_MYSQL: + return 3306 + case api.DBINSTANCE_TYPE_MARIADB: + return 3306 + default: + return 0 + } +} + +func (rds *SDBInstance) GetEngine() string { + databaseType := strings.Split(rds.Type, "/") + switch databaseType[0] { + case "Microsoft.DBforPostgreSQL": + return api.DBINSTANCE_TYPE_POSTGRESQL + case "Microsoft.DBforMySQL": + return api.DBINSTANCE_TYPE_MYSQL + case "Microsoft.DBforMariaDB": + return api.DBINSTANCE_TYPE_MARIADB + default: + return "" + } +} + +func (rds *SDBInstance) GetEngineVersion() string { + return rds.Properties.Version +} + +func (rds *SDBInstance) GetInstanceType() string { + return rds.Sku.Name +} + +func (rds *SDBInstance) GetVcpuCount() int { + return rds.Sku.Capacity +} + +func (rds *SDBInstance) GetVmemSizeMB() int { + if strings.Contains(rds.Type, "server") { + switch rds.Sku.Tier { + case "Basic": + return rds.Sku.Capacity * 2 * 1024 + case "General Purpose": + return rds.Sku.Capacity * 5 * 1024 + case "GeneralPurpose": + return int(float32(rds.Sku.Capacity) * 5.2 * 1024) + case "Memory Optimized": + return rds.Sku.Capacity * 10 * 1024 + default: + return 0 + } + } + return 0 +} + +func (rds *SDBInstance) GetDiskSizeGB() int { + return rds.Properties.StorageProfile.StorageMB / 1024 +} + +func (rds *SDBInstance) GetCategory() string { + return rds.Sku.Tier +} + +func (rds *SDBInstance) GetMaintainTime() string { + return "" +} + +func (rds *SDBInstance) GetConnectionStr() string { + return rds.Properties.FullyQualifiedDomainName +} + +// func (rds *SDBInstance) GetInternalConnectionStr() string + +func (rds *SDBInstance) GetIVpcId() string { + splited := strings.Split(rds.Properties.DelegatedSubnetArguments.SubnetArmResourceId, "/subnets") + return splited[0] +} + +func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { + result := []cloudprovider.SDBInstanceNetwork{} + delegateNet := cloudprovider.SDBInstanceNetwork{NetworkId: rds.Properties.DelegatedSubnetArguments.SubnetArmResourceId} + result = append(result, delegateNet) + return result, nil +} + +func (rds *SDBInstance) GetZone1Id() string { + return "" +} + +func (rds *SDBInstance) GetZone2Id() string { + return "" +} + +func (rds *SDBInstance) GetZone3Id() string { + return "" +} + +func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { + configs, err := rds.region.ListDBInstanceConfiguration(rds.ID) + if err != nil { + return nil, errors.Wrapf(err, "rds.region.ListDBInstanceConfiguration(%s)", rds.ID) + } + result := []cloudprovider.ICloudDBInstanceParameter{} + for i := range configs { + result = append(result, &configs[i]) + } + return result, nil +} + +func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { + db, err := rds.region.ListSDBInstanceDatabase(rds.ID) + if err != nil { + return nil, errors.Wrapf(err, "rds.region.ListSDBInstanceDatabase(%s)", rds.ID) + } + result := []cloudprovider.ICloudDBInstanceDatabase{} + for i := range db { + result = append(result, &db[i]) + } + return result, nil +} + +func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { + accounts := []cloudprovider.ICloudDBInstanceAccount{} + if len(rds.Properties.AdministratorLogin) > 0 { + account := &SDBInstanceAccount{instance: rds, AccountName: rds.Properties.AdministratorLogin} + accounts = append(accounts, account) + } + return accounts, nil +} + +func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + return []cloudprovider.ICloudDBInstanceBackup{}, nil +} + +func (rds *SDBInstance) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error { + if !replace { + for k, v := range self.Tags { + if _, ok := tags[k]; !ok { + tags[k] = v + } + } + } + _, err := self.region.client.SetTags(self.ID, tags) + if err != nil { + return errors.Wrapf(err, "self.region.client.SetTags(%s,%s)", self.ID, jsonutils.Marshal(tags).String()) + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance_account.go new file mode 100644 index 0000000000..d066049039 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance_account.go @@ -0,0 +1,29 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import "yunion.io/x/cloudmux/pkg/multicloud" + +type SDBInstanceAccount struct { + multicloud.SDBInstanceAccountBase + AzureTags + instance *SDBInstance + + AccountName string +} + +func (account *SDBInstanceAccount) GetName() string { + return account.AccountName + "@" + account.instance.Name +} diff --git a/pkg/multicloud/azure/dbinstance_configuration.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance_configuration.go similarity index 100% rename from pkg/multicloud/azure/dbinstance_configuration.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance_configuration.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance_database.go new file mode 100644 index 0000000000..b86fb7fb45 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/dbinstance_database.go @@ -0,0 +1,89 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceDatabase struct { + region *SRegion + multicloud.SDBInstanceDatabaseBase + AzureTags + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` + Properties SDBInstanceDatabaseProperties `json:"properties"` +} + +type SDBInstanceDatabaseProperties struct { + Charset string `json:"charset"` + Collation string `json:"collation"` +} + +func (self *SRegion) ListSDBInstanceDatabase(Id string) ([]SDBInstanceDatabase, error) { + type databases struct { + Value []SDBInstanceDatabase + } + + result := databases{} + err := self.get(fmt.Sprintf("%s/databases", Id), url.Values{}, &result) + if err != nil { + return nil, errors.Wrapf(err, "get(%s/databases)", Id) + } + return result.Value, nil +} + +func (database *SDBInstanceDatabase) GetCharacterSet() string { + return database.Properties.Charset +} + +func (database *SDBInstanceDatabase) GetName() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetGlobalId() string { + return strings.ToLower(database.ID) +} + +func (database *SDBInstanceDatabase) GetId() string { + return strings.ToLower(database.ID) +} + +func (database *SDBInstanceDatabase) IsEmulated() bool { + return false +} + +func (database *SDBInstanceDatabase) Refresh() error { + newdb := SDBInstanceDatabase{} + err := database.region.get(database.ID, url.Values{}, &newdb) + if err != nil { + return errors.Wrapf(err, "database.region.get(%s, url.Values{}, &newdb)", database.ID) + } + + return jsonutils.Update(database, newdb) +} + +func (database *SDBInstanceDatabase) GetStatus() string { + return api.DBINSTANCE_DATABASE_RUNNING +} diff --git a/pkg/multicloud/azure/debug.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/debug.go similarity index 100% rename from pkg/multicloud/azure/debug.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/debug.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/disk.go new file mode 100644 index 0000000000..fab657754e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/disk.go @@ -0,0 +1,337 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "context" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type DiskSku struct { + Name string `json:"name,omitempty"` + Tier string `json:"tier,omitempty"` +} + +type ImageDiskReference struct { + ID string + Lun int32 `json:"lun,omitempty"` +} + +type CreationData struct { + CreateOption string `json:"createOption,omitempty"` + StorageAccountID string + // ImageReference *ImageDiskReference `json:"imageReference,omitempty"` + ImageReference *ImageReference `json:"imageReference,omitempty"` + SourceURI string `json:"sourceUri,omitempty"` + SourceResourceID string `json:"sourceResourceId,omitempty"` +} + +type TAzureInt32 string + +func (ai TAzureInt32) Int32() int32 { + num, _ := strconv.Atoi(strings.Trim(string(ai), "\t")) + return int32(num) +} + +type DiskProperties struct { + TimeCreated time.Time `json:"timeCreated,omitempty"` + OsType string `json:"osType,omitempty"` + CreationData CreationData `json:"creationData,omitempty"` + DiskSizeGB TAzureInt32 `json:"diskSizeGB,omitempty"` + ProvisioningState string `json:"provisioningState,omitempty"` + DiskState string `json:"diskState,omitempty"` +} + +type SDisk struct { + storage *SStorage + multicloud.SDisk + AzureTags + + ManagedBy string `json:"managedBy,omitempty"` + Sku DiskSku `json:"sku,omitempty"` + Zones []string `json:"zones,omitempty"` + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` + Location string `json:"location,omitempty"` + Properties DiskProperties `json:"properties,omitempty"` +} + +func (self *SRegion) CreateDisk(storageType string, name string, sizeGb int32, imageId, snapshotId, resourceGroup string) (*SDisk, error) { + params := jsonutils.Marshal(map[string]interface{}{ + "Name": name, + "Location": self.Name, + "Sku": map[string]string{ + "Name": storageType, + }, + "Type": "Microsoft.Compute/disks", + }).(*jsonutils.JSONDict) + properties := map[string]interface{}{ + "CreationData": map[string]string{ + "CreateOption": "Empty", + }, + "DiskSizeGB": sizeGb, + } + if len(imageId) > 0 { + image, err := self.GetImageById(imageId) + if err != nil { + return nil, errors.Wrapf(err, "GetImageById(%s)", imageId) + } + // 通过镜像创建的磁盘只能传ID参数,不能通过sku,offer等参数创建. + imageId, err := self.getOfferedImageId(&image) + if err != nil { + return nil, errors.Wrapf(err, "getOfferedImageId") + } + properties = map[string]interface{}{ + "CreationData": map[string]interface{}{ + "CreateOption": "FromImage", + "ImageReference": map[string]string{ + "Id": imageId, + }, + }, + } + } else if len(snapshotId) > 0 { + properties = map[string]interface{}{ + "CreationData": map[string]interface{}{ + "CreateOption": "Copy", + "sourceResourceId": snapshotId, + }, + } + } + params.Add(jsonutils.Marshal(properties), "Properties") + disk := &SDisk{} + return disk, self.create(resourceGroup, params, disk) +} + +func (self *SRegion) DeleteDisk(diskId string) error { + return cloudprovider.Wait(time.Second*5, time.Minute*5, func() (bool, error) { + err := self.del(diskId) + if err == nil { + return true, nil + } + // Disk vdisk_stress-testvm-azure-1-1_1555940308395625000 is attached to VM /subscriptions/d4f0ec08-3e28-4ae5-bdf9-3dc7c5b0eeca/resourceGroups/Default/providers/Microsoft.Compute/virtualMachines/stress-testvm-azure-1. + // 更换系统盘后,数据未刷新会出现如上错误,多尝试几次即可 + if strings.Contains(err.Error(), "is attached to VM") { + return false, nil + } + return false, err + }) +} + +func (self *SRegion) ResizeDisk(diskId string, sizeGb int32) error { + disk, err := self.GetDisk(diskId) + if err != nil { + return err + } + disk.Properties.DiskSizeGB = TAzureInt32(fmt.Sprintf("%d", sizeGb)) + disk.Properties.ProvisioningState = "" + return self.update(jsonutils.Marshal(disk), nil) +} + +func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { + disk := SDisk{} + return &disk, self.get(diskId, url.Values{}, &disk) +} + +func (self *SRegion) GetDisks() ([]SDisk, error) { + disks := []SDisk{} + err := self.list("Microsoft.Compute/disks", url.Values{}, &disks) + if err != nil { + return nil, err + } + return disks, nil +} + +func (self *SDisk) GetTags() (map[string]string, error) { + return self.Tags, nil +} + +func (self *SDisk) GetStatus() string { + // 为了不统计这种磁盘挂载率, 单独设置一个状态 + if self.Properties.DiskState == "ActiveSAS" { + return self.Properties.DiskState + } + status := self.Properties.ProvisioningState + switch status { + case "Updating": + return api.DISK_ALLOCATING + case "Succeeded": + return api.DISK_READY + default: + log.Errorf("Unknow azure disk %s status: %s", self.ID, status) + return api.DISK_UNKNOWN + } +} + +func (self *SDisk) GetId() string { + return self.ID +} + +func (self *SDisk) Refresh() error { + disk, err := self.storage.zone.region.GetDisk(self.ID) + if err != nil { + return errors.Wrapf(err, "GetDisk(%s)", self.ID) + } + return jsonutils.Update(self, disk) +} + +func (self *SDisk) Delete(ctx context.Context) error { + return self.storage.zone.region.DeleteDisk(self.ID) +} + +func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { + return self.storage.zone.region.ResizeDisk(self.ID, int32(sizeMb/1024)) +} + +func (self *SDisk) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.ID +} + +func (self *SDisk) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SDisk) IsEmulated() bool { + return false +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +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) GetDiskFormat() string { + return "vhd" +} + +func (self *SDisk) GetDiskSizeMB() int { + return int(self.Properties.DiskSizeGB.Int32()) * 1024 +} + +func (self *SDisk) GetIsAutoDelete() bool { + return false +} + +func (self *SDisk) GetTemplateId() string { + if self.Properties.CreationData.ImageReference != nil { + return self.Properties.CreationData.ImageReference.ID + } + return "" +} + +func (self *SDisk) GetDiskType() string { + if len(self.Properties.OsType) > 0 { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := self.storage.zone.region.CreateSnapshot(self.ID, name, desc) + if err != nil { + return nil, errors.Wrapf(err, "CreateSnapshot") + } + return snapshot, nil +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := self.storage.zone.region.ListSnapshots() + if err != nil { + return nil, errors.Wrapf(err, "ListSnapshots") + } + ret := []cloudprovider.ICloudSnapshot{} + for i := range snapshots { + if strings.ToLower(snapshots[i].Properties.CreationData.SourceResourceID) == strings.ToLower(self.ID) { + snapshots[i].region = self.storage.zone.region + ret = append(ret, &snapshots[i]) + } + } + return ret, nil +} + +func (self *SDisk) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SDisk) GetCreatedAt() time.Time { + return self.Properties.TimeCreated +} + +func (self *SDisk) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + if self.Properties.DiskState != "Unattached" { + return "", fmt.Errorf("Azure reset disk needs to be done in the Unattached state, current status: %s", self.Properties.DiskState) + } + disk, err := self.storage.zone.region.CreateDisk(self.Sku.Name, self.Name, 0, "", snapshotId, self.GetProjectId()) + if err != nil { + return "", errors.Wrap(err, "CreateDisk") + } + err = self.storage.zone.region.DeleteDisk(self.ID) + if err != nil { + log.Warningf("delete old disk %s error: %v", self.ID, err) + } + return disk.ID, nil +} + +func (disk *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + // TODO + return cloudprovider.ErrNotSupported +} + +func (self *SDisk) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/doc.go new file mode 100644 index 0000000000..efce092a19 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 azure // import "yunion.io/x/cloudmux/pkg/multicloud/azure" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/eip.go new file mode 100644 index 0000000000..2952a9e245 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/eip.go @@ -0,0 +1,273 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type PublicIPAddressSku struct { + Name string +} + +type IPConfigurationPropertiesFormat struct { + PrivateIPAddress string +} + +type IPConfiguration struct { + Name string + ID string +} + +type PublicIPAddressPropertiesFormat struct { + PublicIPAddressVersion string `json:"publicIPAddressVersion,omitempty"` + IPAddress string `json:"ipAddress,omitempty"` + PublicIPAllocationMethod string `json:"publicIPAllocationMethod,omitempty"` + ProvisioningState string `json:"provisioningState,omitempty"` + IPConfiguration IPConfiguration `json:"ipConfiguration,omitempty"` +} + +type SEipAddress struct { + region *SRegion + multicloud.SEipBase + AzureTags + + ID string + Name string + Location string + Properties PublicIPAddressPropertiesFormat `json:"properties,omitempty"` + Type string + Sku *PublicIPAddressSku +} + +func (self *SRegion) AllocateEIP(name, projectId string) (*SEipAddress, error) { + params := map[string]interface{}{ + "Location": self.Name, + "Name": name, + "Properties": map[string]string{ + "PublicIPAddressVersion": "IPv4", + "PublicIPAllocationMethod": "Static", + }, + "Type": "Microsoft.Network/publicIPAddresses", + } + eip := &SEipAddress{region: self} + err := self.create(projectId, jsonutils.Marshal(params), eip) + if err != nil { + return nil, err + } + return eip, cloudprovider.WaitStatus(eip, api.EIP_STATUS_READY, 10*time.Second, 300*time.Second) +} + +func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + return region.AllocateEIP(eip.Name, eip.ProjectId) +} + +func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { + eip := SEipAddress{region: region} + return &eip, region.get(eipId, url.Values{}, &eip) +} + +func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { + return self.region.AssociateEip(self.ID, conf.InstanceId) +} + +func (region *SRegion) AssociateEip(eipId string, instanceId string) error { + instance, err := region.GetInstance(instanceId) + if err != nil { + return err + } + if len(instance.Properties.NetworkProfile.NetworkInterfaces) > 0 { + nic, err := region.GetNetworkInterface(instance.Properties.NetworkProfile.NetworkInterfaces[0].ID) + if err != nil { + return err + } + if len(nic.Properties.IPConfigurations) > 0 { + nic.Properties.IPConfigurations[0].Properties.PublicIPAddress = &PublicIPAddress{ID: eipId} + return region.update(jsonutils.Marshal(nic), nil) + } + return fmt.Errorf("network interface with no IPConfigurations") + } + return fmt.Errorf("Instance with no interface") +} + +func (region *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { + return region.GetEip(eipId) +} + +func (self *SEipAddress) ChangeBandwidth(bw int) error { + return cloudprovider.ErrNotSupported +} + +func (self *SEipAddress) Delete() error { + self.Dissociate() //避免eip挂载在弹性网卡之上,导致删除失败 + return self.region.DeallocateEIP(self.ID) +} + +func (region *SRegion) DeallocateEIP(eipId string) error { + return cloudprovider.Wait(time.Second*5, time.Minute*5, func() (bool, error) { + err := region.del(eipId) + if err == nil { + return true, nil + } + // {"error":{"code":"PublicIPAddressCannotBeDeleted","details":[],"message":"Public IP address /subscriptions/d4f0ec08-3e28-4ae5-bdf9-3dc7c5b0eeca/resourceGroups/Default/providers/Microsoft.Network/publicIPAddresses/eip-for-test-wwl can not be deleted since it is still allocated to resource /subscriptions/d4f0ec08-3e28-4ae5-bdf9-3dc7c5b0eeca/resourceGroups/Default/providers/Microsoft.Network/networkInterfaces/test-wwl-ipconfig."}} + // 刚解绑eip后可能数据未刷新,需要再次尝试 + if strings.Contains(err.Error(), "it is still allocated to resource") { + return false, nil + } + return false, errors.Wrapf(err, "del(%s)", eipId) + }) +} + +func (self *SEipAddress) Dissociate() error { + return self.region.DissociateEip(self.ID) +} + +func (region *SRegion) DissociateEip(eipId string) error { + eip, err := region.GetEip(eipId) + if err != nil { + return errors.Wrapf(err, "GetEip(%s)", eipId) + } + interfaceId := eip.Properties.IPConfiguration.ID + if strings.Index(interfaceId, "/ipConfigurations/") > 0 { + interfaceId = strings.Split(interfaceId, "/ipConfigurations/")[0] + } + nic, err := region.GetNetworkInterface(interfaceId) + if err != nil { + return err + } + for i := 0; i < len(nic.Properties.IPConfigurations); i++ { + if nic.Properties.IPConfigurations[i].Properties.PublicIPAddress != nil && nic.Properties.IPConfigurations[i].Properties.PublicIPAddress.ID == eipId { + nic.Properties.IPConfigurations[i].Properties.PublicIPAddress = nil + break + } + } + return region.update(jsonutils.Marshal(nic), nil) +} + +func (self *SEipAddress) GetAssociationExternalId() string { + if self.GetAssociationType() == api.EIP_ASSOCIATE_TYPE_SERVER { + info := strings.Split(self.Properties.IPConfiguration.ID, "/") + nic, _ := self.region.GetNetworkInterface(strings.Join(info[:len(info)-2], "/")) + if nic != nil { + return strings.ToLower(nic.Properties.VirtualMachine.ID) + } + } + return "" +} + +func (self *SEipAddress) GetAssociationType() string { + if len(self.Properties.IPConfiguration.ID) == 0 { + return "" + } + if info := strings.Split(self.Properties.IPConfiguration.ID, "/"); len(info) > 7 { + resType := strings.ToLower(info[7]) + if utils.IsInStringArray(resType, []string{"networkinterfaces"}) { + return api.EIP_ASSOCIATE_TYPE_SERVER + } + return resType + } + return "" +} + +func (self *SEipAddress) GetBandwidth() int { + return 0 +} + +func (self *SEipAddress) GetINetworkId() string { + return "" +} + +func (self *SEipAddress) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SEipAddress) GetId() string { + return self.ID +} + +func (self *SEipAddress) GetInternetChargeType() string { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC +} + +func (self *SEipAddress) GetIpAddr() string { + return self.Properties.IPAddress +} + +func (self *SEipAddress) GetMode() string { + if self.IsEmulated() { + return api.EIP_MODE_INSTANCE_PUBLICIP + } + return api.EIP_MODE_STANDALONE_EIP +} + +func (self *SEipAddress) GetName() string { + return self.Name +} + +func (self *SEipAddress) GetStatus() string { + switch self.Properties.ProvisioningState { + case "Succeeded", "": + return api.EIP_STATUS_READY + case "Updating": + return api.EIP_STATUS_ALLOCATE + default: + log.Errorf("Unknown eip status: %s", self.Properties.ProvisioningState) + return api.EIP_STATUS_UNKNOWN + } +} + +func (self *SEipAddress) IsEmulated() bool { + if strings.ToLower(self.Properties.PublicIPAllocationMethod) == "Dynamic" || len(self.Properties.IPAddress) == 0 { + return true + } + return false +} + +func (self *SEipAddress) Refresh() error { + eip, err := self.region.GetEip(self.ID) + if err != nil { + return err + } + return jsonutils.Update(self, eip) +} + +func (self *SEipAddress) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SEipAddress) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SEipAddress) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/enrollment_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/enrollment_account.go new file mode 100644 index 0000000000..9440b4012a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/enrollment_account.go @@ -0,0 +1,100 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SEnrollmentAccountProperties struct { + PrincipalName string + OfferTypes []string +} + +type SEnrollmentAccount struct { + Id string + Name string + Type string + Properties SEnrollmentAccountProperties +} + +func (cli *SAzureClient) GetEnrollmentAccounts() ([]cloudprovider.SEnrollmentAccount, error) { + accounts := []SEnrollmentAccount{} + err := cli.list("providers/Microsoft.Billing/enrollmentAccounts", nil, &accounts) + if err != nil { + return nil, err + } + eas := []cloudprovider.SEnrollmentAccount{} + for i := range accounts { + ea := cloudprovider.SEnrollmentAccount{ + Id: accounts[i].Name, + Name: accounts[i].Properties.PrincipalName, + Type: accounts[i].Type, + } + eas = append(eas, ea) + } + return eas, nil +} + +func (cli *SAzureClient) CreateSubscription(name string, eaId string, offerType string) error { + appId, err := cli.GetAppObjectId() + if err != nil { + log.Errorf("GetAppObjectId error: %v", err) + } + owners := []map[string]string{} + if len(appId) > 0 { + owners = append(owners, map[string]string{"objectId": appId}) + } + body := map[string]interface{}{ + "displayName": name, + "offerType": offerType, + "owners": owners, + } + resource := fmt.Sprintf("providers/Microsoft.Billing/enrollmentAccounts/%s/providers/Microsoft.Subscription/createSubscription", eaId) + _, err = cli.post(resource, jsonutils.Marshal(body)) + return err +} + +type SServicePrincipal struct { + AppId string + ObjectId string +} + +func (cli *SAzureClient) GetAppObjectId() (string, error) { + result, err := cli.ListServicePrincipal(cli.clientId) + if err != nil { + return "", errors.Wrap(err, "ListServicePrincipal") + } + if len(result) == 1 { + return result[0].ObjectId, nil + } + return "", nil +} + +func (cli *SAzureClient) ListServicePrincipal(appId string) ([]SServicePrincipal, error) { + params := url.Values{} + if len(appId) > 0 { + params.Set("$filter", fmt.Sprintf(`appId eq '%s'`, cli.clientId)) + } + result := []SServicePrincipal{} + return result, cli.glist("servicePrincipals", params, &result) +} diff --git a/pkg/multicloud/azure/enterprise_redis.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/enterprise_redis.go similarity index 98% rename from pkg/multicloud/azure/enterprise_redis.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/enterprise_redis.go index 2c4fcea284..5b35125c94 100644 --- a/pkg/multicloud/azure/enterprise_redis.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/enterprise_redis.go @@ -21,14 +21,14 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SEnterpriseRedisCache struct { multicloud.SElasticcacheBase - multicloud.AzureTags + AzureTags region *SRegion ID string `json:"id"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/event.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/event.go new file mode 100644 index 0000000000..91af92c8bb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/event.go @@ -0,0 +1,154 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SAuthorization struct { + Action string + Scope string +} + +type SClaims struct { + Aud string + Iss string + Iat string + Nbf string + Exp string + Aio string + Appid string + Appidacr string + Uti string + Ver string +} + +type SLocalized struct { + Value string + LocalizedValue string +} + +type SEvent struct { + region *SRegion + + Authorization SAuthorization + Channels string + Claims SClaims + CorrelationId string + Description string + EventDataId string + EventName SLocalized + Category SLocalized + Level string + ResourceGroupName string + ResourceProviderName SLocalized + ResourceId string + ResourceType SLocalized + OperationId string + OperationName SLocalized + Properties string + Status SLocalized + SubStatus SLocalized + Caller string + EventTimestamp time.Time + SubmissionTimestamp time.Time + SubscriptionId string + TenantId string + ID string + Name string +} + +func (event *SEvent) GetName() string { + return event.ResourceId +} + +func (event *SEvent) GetService() string { + return event.ResourceProviderName.Value +} + +func (event *SEvent) GetAction() string { + return event.OperationName.Value +} + +func (event *SEvent) GetResourceType() string { + return event.ResourceType.Value +} + +func (event *SEvent) GetRequestId() string { + return event.CorrelationId +} + +func (event *SEvent) GetRequest() jsonutils.JSONObject { + return jsonutils.Marshal(event) +} + +func (event *SEvent) GetAccount() string { + return event.Claims.Appid +} + +func (event *SEvent) IsSuccess() bool { + return event.Status.Value != "Failed" +} + +func (event *SEvent) GetCreatedAt() time.Time { + return event.EventTimestamp +} + +func (region *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { + events, err := region.GetEvents(start, end) + if err != nil { + return nil, err + } + iEvents := []cloudprovider.ICloudEvent{} + for i := range events { + read := false + for _, k := range []string{"read", "listKeys"} { + if strings.Contains(events[i].Authorization.Action, k) { + read = true + break + } + } + if withReadEvent || !read { + iEvents = append(iEvents, &events[i]) + } + } + return iEvents, nil +} + +func (region *SRegion) GetEvents(start time.Time, end time.Time) ([]SEvent, error) { + events := []SEvent{} + if start.IsZero() { + start = time.Now().AddDate(0, 0, -7) + } + if end.IsZero() { + end = time.Now() + } + params := url.Values{} + params.Set("$filter", fmt.Sprintf("eventTimestamp ge '%s' and eventTimestamp le '%s' and eventChannels eq 'Admin, Operation' and levels eq 'Critical,Error,Warning,Informational'", start.Format("2006-01-02T15:04:05Z"), end.Format("2006-01-02T15:04:05Z"))) + resource := fmt.Sprintf("microsoft.insights/eventtypes/management/values") + err := region.client.list(resource, params, &events) + if err != nil { + return nil, err + } + return events, nil +} diff --git a/pkg/multicloud/azure/geographicinfo.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/geographicinfo.go similarity index 97% rename from pkg/multicloud/azure/geographicinfo.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/geographicinfo.go index 84c27a2720..5250fd54f4 100644 --- a/pkg/multicloud/azure/geographicinfo.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/geographicinfo.go @@ -15,8 +15,8 @@ package azure import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) var AzureGeographicInfo = map[string]cloudprovider.SGeographicInfo{ diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/host.go new file mode 100644 index 0000000000..9decb387cb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/host.go @@ -0,0 +1,309 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/seclib2" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone +} + +func (self *SHost) GetId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) GetName() string { + return fmt.Sprintf("%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId) +} + +func (self *SHost) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId) +} + +func (self *SHost) IsEmulated() bool { + return true +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) Refresh() error { + return nil +} + +func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + nic, err := self.zone.region.CreateNetworkInterface(desc.ProjectId, fmt.Sprintf("%s-ipconfig", desc.NameEn), desc.IpAddr, desc.ExternalNetworkId, desc.ExternalSecgroupId) + if err != nil { + return nil, errors.Wrapf(err, "CreateNetworkInterface") + } + + instance, err := self.zone.region._createVM(desc, nic.ID) + if err != nil { + self.zone.region.DeleteNetworkInterface(nic.ID) + return nil, err + } + instance.host = self + return instance, nil +} + +func (self *SRegion) _createVM(desc *cloudprovider.SManagedVMCreateConfig, nicId string) (*SInstance, error) { + image, err := self.GetImageById(desc.ExternalImageId) + if err != nil { + return nil, errors.Wrapf(err, "GetImageById(%s)", desc.ExternalImageId) + } + + if len(desc.Password) == 0 { + //Azure创建必须要设置密码 + desc.Password = seclib2.RandomPassword2(12) + } + + if image.Properties.ProvisioningState != ImageStatusAvailable { + return nil, fmt.Errorf("image %s not ready status: %s", desc.ExternalImageId, image.Properties.ProvisioningState) + } + if !utils.IsInStringArray(desc.OsType, []string{osprofile.OS_TYPE_LINUX, osprofile.OS_TYPE_WINDOWS}) { + desc.OsType = string(image.GetOsType()) + } + computeName := desc.Hostname + for _, k := range "`~!@#$%^&*()=+_[]{}\\|;:.'\",<>/?" { + computeName = strings.Replace(computeName, string(k), "", -1) + } + if len(computeName) > 15 { + computeName = computeName[:15] + } + osProfile := map[string]string{ + "ComputerName": computeName, + "AdminUsername": api.VM_AZURE_DEFAULT_LOGIN_USER, + "AdminPassword": desc.Password, + } + if len(desc.UserData) > 0 { + osProfile["CustomData"] = desc.UserData + } + params := jsonutils.Marshal(map[string]interface{}{ + "Name": desc.NameEn, + "Location": self.Name, + "Properties": map[string]interface{}{ + "HardwareProfile": map[string]string{ + "VMSize": "", + }, + "OsProfile": osProfile, + "NetworkProfile": map[string]interface{}{ + "NetworkInterfaces": []map[string]string{ + map[string]string{ + "Id": nicId, + }, + }, + }, + "StorageProfile": map[string]interface{}{ + "ImageReference": image.getImageReference(), + "OsDisk": map[string]interface{}{ + "Name": fmt.Sprintf("vdisk_%s_%d", desc.Name, time.Now().UnixNano()), + "Caching": "ReadWrite", + "ManagedDisk": map[string]string{ + "StorageAccountType": desc.SysDisk.StorageType, + }, + "CreateOption": "FromImage", + "DiskSizeGB": desc.SysDisk.SizeGB, + "OsType": desc.OsType, + }, + }, + }, + "Type": "Microsoft.Compute/virtualMachines", + }).(*jsonutils.JSONDict) + if len(desc.PublicKey) > 0 && desc.OsType == osprofile.OS_TYPE_LINUX { + linuxConfiguration := map[string]interface{}{ + "DisablePasswordAuthentication": false, + "SSH": map[string]interface{}{ + "PublicKeys": []map[string]string{ + map[string]string{ + "KeyData": desc.PublicKey, + "Path": fmt.Sprintf("/home/%s/.ssh/authorized_keys", api.VM_AZURE_DEFAULT_LOGIN_USER), + }, + }, + }, + } + params.Add(jsonutils.Marshal(linuxConfiguration), "Properties", "OsProfile", "LinuxConfiguration") + } + if len(desc.Tags) > 0 { + params.Add(jsonutils.Marshal(desc.Tags), "tags") + } + + dataDisks := jsonutils.NewArray() + for i := 0; i < len(desc.DataDisks); i++ { + dataDisk := jsonutils.Marshal(map[string]interface{}{ + "Name": fmt.Sprintf("vdisk_%s_%d", desc.Name, time.Now().UnixNano()), + "DiskSizeGB": desc.DataDisks[i].SizeGB, + "CreateOption": "Empty", + "ManagedDisk": map[string]string{ + "StorageAccountType": desc.DataDisks[i].StorageType, + }, + "Lun": i, + }) + dataDisks.Add(dataDisk) + } + if dataDisks.Length() > 0 { + params.Add(dataDisks, "Properties", "StorageProfile", "DataDisks") + } + + instance := &SInstance{} + if len(desc.InstanceType) > 0 { + params.Add(jsonutils.NewString(desc.InstanceType), "Properties", "HardwareProfile", "VMSize") + log.Debugf("Try HardwareProfile : %s", desc.InstanceType) + err = self.create(desc.ProjectId, params, instance) + if err != nil { + return nil, errors.Wrapf(err, "create") + } + return instance, nil + } + + for _, profile := range self.getHardwareProfile(desc.Cpu, desc.MemoryMB) { + params.Add(jsonutils.NewString(profile), "Properties", "HardwareProfile", "VMSize") + log.Debugf("Try HardwareProfile : %s", profile) + err = self.create(desc.ProjectId, params, &instance) + if err != nil { + for _, key := range []string{`"code":"InvalidParameter"`, `"code":"NicInUse"`} { + if strings.Contains(err.Error(), key) { + return nil, err + } + } + log.Errorf("Failed for %s: %s", profile, err) + continue + } + return instance, nil + } + if err != nil { + return nil, err + } + return nil, fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB) +} + +func (self *SHost) GetAccessIp() string { + return "" +} + +func (self *SHost) GetAccessMac() string { + return "" +} + +func (self *SHost) GetCpuCount() int { + 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) GetEnabled() bool { + return true +} + +func (self *SHost) GetHostStatus() string { + return api.HOST_ONLINE +} +func (self *SHost) GetNodeCount() int8 { + return 0 +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_AZURE +} + +func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return self.zone.GetIStorageById(id) +} + +func (self *SHost) GetSysInfo() jsonutils.JSONObject { + info := jsonutils.NewDict() + info.Add(jsonutils.NewString(CLOUD_PROVIDER_AZURE), "manufacture") + return info +} + +func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + return self.zone.getIStorages(), nil +} + +func (self *SHost) GetIVMById(instanceId string) (cloudprovider.ICloudVM, error) { + instance, err := self.zone.region.GetInstance(instanceId) + if err != nil { + return nil, err + } + instance.host = self + return instance, nil +} + +func (self *SHost) GetStorageSizeMB() int { + return 0 +} + +func (self *SHost) GetStorageType() string { + return api.DISK_TYPE_HYBRID +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms, err := self.zone.region.GetInstances() + if err != nil { + return nil, err + } + ivms := make([]cloudprovider.ICloudVM, len(vms)) + for i := 0; i < len(vms); i++ { + vms[i].host = self + ivms[i] = &vms[i] + log.Debugf("find vm %s for host %s", vms[i].GetName(), self.GetName()) + } + return ivms, nil +} + +func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + return self.zone.GetIWires() +} + +func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (host *SHost) GetIsMaintenance() bool { + return false +} + +func (host *SHost) GetVersion() string { + return AZURE_API_VERSION +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/image.go new file mode 100644 index 0000000000..6f181933e4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/image.go @@ -0,0 +1,607 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/apis" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type ImageStatusType string + +const ( + ImageStatusCreating ImageStatusType = "Creating" + ImageStatusAvailable ImageStatusType = "Succeeded" + ImageStatusUnAvailable ImageStatusType = "UnAvailable" + ImageStatusCreateFailed ImageStatusType = "CreateFailed" +) + +type OperatingSystemStateTypes string + +type ImageOSDisk struct { + OsType string `json:"osType,omitempty"` + OsState string `json:"osState,omitempty"` + Snapshot *SubResource `json:"snapshot,omitempty"` + ManagedDisk *SubResource + BlobURI string `json:"blobUri,omitempty"` + Caching string `json:"caching,omitempty"` + DiskSizeGB int32 `json:"diskSizeGB,omitzero"` + StorageAccountType string `json:"storageAccountType,omitempty"` + OperatingSystem string `json:"operatingSystem,omitempty"` +} + +type ImageDataDisk struct { + Lun int32 + Snapshot SubResource + ManagedDisk SubResource + BlobURI string + Caching string + DiskSizeGB int32 `json:"diskSizeGB,omitzero"` + StorageAccountType string +} + +type ImageStorageProfile struct { + OsDisk ImageOSDisk `json:"osDisk,omitempty"` + DataDisks []ImageDataDisk `json:"dataDisks,omitempty"` + ZoneResilient bool `json:"zoneResilient,omitfalse"` +} + +type SAutomaticOSUpgradeProperties struct { + AutomaticOSUpgradeSupported bool +} + +type ImageProperties struct { + SourceVirtualMachine *SubResource + StorageProfile ImageStorageProfile `json:"storageProfile,omitempty"` + ProvisioningState ImageStatusType + HyperVGeneration string `json:"hyperVGeneration,omitempty"` +} + +type SImage struct { + multicloud.SImageBase + AzureTags + storageCache *SStoragecache + + Properties ImageProperties `json:"properties,omitempty"` + ID string `json:"id,omitempty"` + Name string + Type string + Location string + + Publisher string + Offer string + Sku string + Version string + + ImageType cloudprovider.TImageType +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SImage) GetSysTags() map[string]string { + data := map[string]string{} + osType := string(self.Properties.StorageProfile.OsDisk.OsType) + if len(osType) > 0 { + data["os_name"] = osType + } + return data +} + +func (self *SImage) GetId() string { + return self.ID +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (self *SImage) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SImage) GetStatus() string { + switch self.Properties.ProvisioningState { + case "created": + return api.CACHED_IMAGE_STATUS_CACHING + case "Succeeded": + return api.CACHED_IMAGE_STATUS_ACTIVE + default: + log.Errorf("Unknow image status: %s", self.Properties.ProvisioningState) + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (self *SImage) GetImageStatus() string { + switch self.Properties.ProvisioningState { + case "created": + return cloudprovider.IMAGE_STATUS_QUEUED + case "Succeeded": + return cloudprovider.IMAGE_STATUS_ACTIVE + default: + log.Errorf("Unknow image status: %s", self.Properties.ProvisioningState) + return cloudprovider.IMAGE_STATUS_KILLED + } +} + +func (self *SImage) Refresh() error { + image, err := self.storageCache.region.GetImageById(self.ID) + if err != nil { + return err + } + return jsonutils.Update(self, image) +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + return cloudprovider.TImageType(self.ImageType) +} + +func (self *SImage) GetSizeByte() int64 { + return int64(self.Properties.StorageProfile.OsDisk.DiskSizeGB) * 1024 * 1024 * 1024 +} + +func (i *SImage) GetFullOsName() string { + return "" +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + osType := self.Properties.StorageProfile.OsDisk.OsType + if len(osType) == 0 { + osType = publisherGetOsType(self.Publisher) + } + return cloudprovider.TOsType(osType) +} + +func (self *SImage) GetOsArch() string { + if self.GetImageType() == cloudprovider.ImageTypeCustomized { + return apis.OS_ARCH_X86_64 + } + return publisherGetOsArch(self.Publisher, self.Offer, self.Sku, self.Version) +} + +func (self *SImage) GetOsDist() string { + if self.GetImageType() == cloudprovider.ImageTypeCustomized { + return "" + } + return publisherGetOsDist(self.Publisher, self.Offer, self.Sku, self.Version) +} + +func (self *SImage) GetOsVersion() string { + return publisherGetOsVersion(self.Publisher, self.Offer, self.Sku, self.Version) +} + +func (self *SImage) GetOsLang() string { + return "" +} + +func (i *SImage) GetBios() cloudprovider.TBiosType { + if i.Properties.HyperVGeneration == "V2" { + return cloudprovider.UEFI + } else { + return cloudprovider.BIOS + } +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + if self.Properties.StorageProfile.OsDisk.DiskSizeGB > 0 { + return int(self.Properties.StorageProfile.OsDisk.DiskSizeGB) + } + return 30 +} + +func (self *SImage) GetImageFormat() string { + return "vhd" +} + +func (self *SImage) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.storageCache +} + +func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) { + if image, err := self.GetImageById(imageId); err != nil { + return "", err + } else { + return image.Properties.ProvisioningState, nil + } +} + +func isPrivateImageID(imageId string) bool { + return strings.HasPrefix(strings.ToLower(imageId), "/subscriptions/") +} + +func (self *SRegion) GetImageById(imageId string) (SImage, error) { + if isPrivateImageID(imageId) { + return self.getPrivateImage(imageId) + } else { + return self.getOfferedImage(imageId) + } +} + +func (self *SRegion) getPrivateImage(imageId string) (SImage, error) { + image := SImage{} + err := self.get(imageId, url.Values{}, &image) + if err != nil { + return image, err + } + return image, nil +} + +func (self *SRegion) CreateImageByBlob(imageName, osType, blobURI string, diskSizeGB int32) (*SImage, error) { + if diskSizeGB < 1 || diskSizeGB > 4095 { + diskSizeGB = 30 + } + image := SImage{ + Name: imageName, + Location: self.Name, + Properties: ImageProperties{ + StorageProfile: ImageStorageProfile{ + OsDisk: ImageOSDisk{ + OsType: osType, + OsState: "Generalized", + BlobURI: blobURI, + DiskSizeGB: diskSizeGB, + }, + }, + }, + Type: "Microsoft.Compute/images", + } + return &image, self.create("", jsonutils.Marshal(image), &image) +} + +func (self *SRegion) CreateImage(snapshotId, imageName, osType, imageDesc string) (*SImage, error) { + image := SImage{ + Name: imageName, + Location: self.Name, + Properties: ImageProperties{ + StorageProfile: ImageStorageProfile{ + OsDisk: ImageOSDisk{ + OsType: osType, + OsState: "Generalized", + Snapshot: &SubResource{ + ID: snapshotId, + }, + }, + }, + }, + Type: "Microsoft.Compute/images", + } + return &image, self.create("", jsonutils.Marshal(image), &image) +} + +func (self *SRegion) getOfferedImages(publishersFilter []string, offersFilter []string, skusFilter []string, verFilter []string, imageType cloudprovider.TImageType, latestVer bool) ([]SImage, error) { + images := make([]SImage, 0) + idMap, err := self.GetOfferedImageIDs(publishersFilter, offersFilter, skusFilter, verFilter, latestVer) + if err != nil { + return nil, err + } + for id, _image := range idMap { + image, err := self.getOfferedImage(id) + if err == nil { + image.ImageType = imageType + image.Properties.StorageProfile.OsDisk.DiskSizeGB = int32(_image.Properties.OsDiskImage.SizeInGb) + image.Properties.StorageProfile.OsDisk.OsType = _image.Properties.OsDiskImage.OperatingSystem + image.Properties.HyperVGeneration = _image.Properties.HyperVGeneration + images = append(images, image) + } + } + return images, nil +} + +func (self *SRegion) GetOfferedImageIDs(publishersFilter []string, offersFilter []string, skusFilter []string, verFilter []string, latestVer bool) (map[string]SAzureImageResource, error) { + idMap := map[string]SAzureImageResource{} + publishers, err := self.GetImagePublishers(toLowerStringArray(publishersFilter)) + if err != nil { + return nil, err + } + for _, publisher := range publishers { + offers, err := self.getImageOffers(publisher, toLowerStringArray(offersFilter)) + if err != nil { + log.Errorf("failed to found offers for publisher %s error: %v", publisher, err) + if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, errors.Wrap(err, "getImageOffers") + } + continue + } + for _, offer := range offers { + skus, err := self.getImageSkus(publisher, offer, toLowerStringArray(skusFilter)) + if err != nil { + if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, errors.Wrap(err, "getImageSkus") + } + log.Errorf("failed to found skus for publisher %s offer %s error: %v", publisher, offer, err) + continue + } + for _, sku := range skus { + verFilter = toLowerStringArray(verFilter) + vers, err := self.getImageVersions(publisher, offer, sku, verFilter, latestVer) + if err != nil { + if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, errors.Wrap(err, "getImageVersions") + } + log.Errorf("failed to found publisher %s offer %s sku %s version error: %v", publisher, offer, sku, err) + continue + } + for _, ver := range vers { + idStr := strings.Join([]string{publisher, offer, sku, ver}, "/") + image, err := self.getImageDetail(publisher, offer, sku, ver) + if err != nil { + return nil, err + } + idMap[idStr] = image + } + } + } + } + return idMap, nil +} + +func (self *SRegion) getPrivateImages() ([]SImage, error) { + result := []SImage{} + images := []SImage{} + err := self.client.list("Microsoft.Compute/images", url.Values{}, &images) + if err != nil { + return nil, err + } + for i := 0; i < len(images); i++ { + if images[i].Location == self.Name { + images[i].ImageType = cloudprovider.ImageTypeCustomized + result = append(result, images[i]) + } + } + return result, nil +} + +func toLowerStringArray(input []string) []string { + output := make([]string, len(input)) + for i := range input { + output[i] = strings.ToLower(input[i]) + } + return output +} + +func (self *SRegion) GetImages(imageType cloudprovider.TImageType) ([]SImage, error) { + images := make([]SImage, 0) + if len(imageType) == 0 { + ret, _ := self.getPrivateImages() + if len(ret) > 0 { + images = append(images, ret...) + } + ret, _ = self.getOfferedImages(knownPublishers, nil, nil, nil, cloudprovider.ImageTypeSystem, true) + if len(ret) > 0 { + images = append(images, ret...) + } + return images, nil + } + switch imageType { + case cloudprovider.ImageTypeCustomized: + return self.getPrivateImages() + case cloudprovider.ImageTypeSystem: + return self.getOfferedImages(knownPublishers, nil, nil, nil, cloudprovider.ImageTypeSystem, true) + default: + return self.getOfferedImages(nil, nil, nil, nil, cloudprovider.ImageTypeMarket, true) + } +} + +func (self *SRegion) DeleteImage(imageId string) error { + return self.del(imageId) +} + +func (self *SImage) GetBlobUri() string { + return self.Properties.StorageProfile.OsDisk.BlobURI +} + +func (self *SImage) Delete(ctx context.Context) error { + return self.storageCache.region.DeleteImage(self.ID) +} + +type SOsDiskImage struct { + OperatingSystem string `json:"operatingSystem"` + SizeInGb int `json:"sizeInGb"` +} + +type SAzureImageResourceProperties struct { + ReplicaType string `json:"replicaType"` + OsDiskImage SOsDiskImage `json:"osDiskImage"` + HyperVGeneration string `json:"hyperVGeneration,omitempty"` +} + +type SAzureImageResource struct { + Id string + Name string + Location string + Properties SAzureImageResourceProperties +} + +func (region *SRegion) GetImagePublishers(filter []string) ([]string, error) { + publishers := make([]SAzureImageResource, 0) + // TODO + err := region.client.list(fmt.Sprintf("Microsoft.Compute/locations/%s/publishers", region.Name), url.Values{}, &publishers) + if err != nil { + return nil, err + } + ret := make([]string, 0) + for i := range publishers { + if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(publishers[i].Name), filter) { + ret = append(ret, publishers[i].Name) + } + } + return ret, nil +} + +func (region *SRegion) getImageOffers(publisher string, filter []string) ([]string, error) { + ret := make([]string, 0) + if driver, ok := publisherDrivers[strings.ToLower(publisher)]; ok { + offers := driver.GetOffers() + if len(offers) > 0 { + for _, offer := range offers { + if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(offer), filter) { + ret = append(ret, offer) + } + } + return offers, nil + } + } else { + log.Warningf("failed to get publisher %s driver", publisher) + } + offers := make([]SAzureImageResource, 0) + err := region.client.list(fmt.Sprintf("Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers", region.Name, publisher), url.Values{}, &offers) + if err != nil { + return nil, err + } + for i := range offers { + if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(offers[i].Name), filter) { + ret = append(ret, offers[i].Name) + } + } + return ret, nil +} + +func (region *SRegion) getImageSkus(publisher string, offer string, filter []string) ([]string, error) { + ret := make([]string, 0) + if driver, ok := publisherDrivers[strings.ToLower(publisher)]; ok { + skus := driver.GetSkus(offer) + if len(skus) > 0 { + for _, sku := range skus { + if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(sku), filter) { + ret = append(ret, sku) + } + } + return ret, nil + } + } + skus := make([]SAzureImageResource, 0) + err := region.client.list(fmt.Sprintf("Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers/%s/skus", region.Name, publisher, offer), url.Values{}, &skus) + if err != nil { + return nil, err + } + for i := range skus { + if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(skus[i].Name), filter) { + ret = append(ret, skus[i].Name) + } + } + return ret, nil +} + +func (region *SRegion) getImageVersions(publisher string, offer string, sku string, filter []string, latestVer bool) ([]string, error) { + vers := make([]SAzureImageResource, 0) + resource := fmt.Sprintf("Microsoft.Compute/locations/%s/publishers/%s/artifacttypes/vmimage/offers/%s/skus/%s/versions", region.Name, publisher, offer, sku) + params := url.Values{} + if latestVer { + params.Set("$top", "1") + params.Set("orderby", "name desc") + } + err := region.client.list(resource, params, &vers) + if err != nil { + return nil, err + } + ret := make([]string, 0) + for i := range vers { + if len(filter) == 0 || utils.IsInStringArray(strings.ToLower(vers[i].Name), filter) { + ret = append(ret, vers[i].Name) + } + } + return ret, nil +} + +func (region *SRegion) getImageDetail(publisher string, offer string, sku string, version string) (SAzureImageResource, error) { + image := SAzureImageResource{} + id := "/Subscriptions/" + region.client.subscriptionId + + "/Providers/Microsoft.Compute/locations/" + region.Name + + "/publishers/" + publisher + + "/artifacttypes/vmimage/offers/" + offer + + "/skus/" + sku + + "/versions/" + version + return image, region.get(id, url.Values{}, &image) +} + +func (region *SRegion) getOfferedImage(offerId string) (SImage, error) { + image := SImage{} + + parts := strings.Split(offerId, "/") + if len(parts) < 4 { + return image, fmt.Errorf("invalid image ID %s", offerId) + } + publisher := parts[0] + offer := parts[1] + sku := parts[2] + version := parts[3] + for _publish := range publisherDrivers { + if strings.ToLower(_publish) == publisher { + publisher = _publish + break + } + } + image.ID = offerId + image.Location = region.Name + image.Type = "Microsoft.Compute/vmimage" + image.Name = publisherGetName(publisher, offer, sku, version) + image.Publisher = publisher + image.Offer = offer + image.Sku = sku + image.Version = version + image.Properties.ProvisioningState = ImageStatusAvailable + _image, err := region.getImageDetail(publisher, offer, sku, version) + if err == nil { + image.Properties.StorageProfile.OsDisk.DiskSizeGB = int32(_image.Properties.OsDiskImage.SizeInGb) + image.Properties.StorageProfile.OsDisk.OperatingSystem = _image.Properties.OsDiskImage.OperatingSystem + image.Properties.HyperVGeneration = _image.Properties.HyperVGeneration + } + return image, nil +} + +func (region *SRegion) getOfferedImageId(image *SImage) (string, error) { + if isPrivateImageID(image.ID) { + return image.ID, nil + } + _image, err := region.getImageDetail(image.Publisher, image.Offer, image.Sku, image.Version) + if err != nil { + log.Errorf("failed to get offered image ID from %s error: %v", jsonutils.Marshal(image).PrettyString(), err) + return "", err + } + return _image.Id, nil +} + +func (image *SImage) getImageReference() ImageReference { + if isPrivateImageID(image.ID) { + return ImageReference{ + ID: image.ID, + } + } else { + return ImageReference{ + Sku: image.Sku, + Publisher: image.Publisher, + Version: image.Version, + Offer: image.Offer, + } + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/instance.go new file mode 100644 index 0000000000..143983dbcc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/instance.go @@ -0,0 +1,1122 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + + "yunion.io/x/cloudmux/pkg/apis" + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/version" +) + +const ( + DEFAULT_EXTENSION_NAME = "enablevmaccess" +) + +type HardwareProfile struct { + VMSize string `json:"vmSize,omitempty"` +} + +type ImageReference struct { + Publisher string `json:"publisher,omitempty"` + Offer string `json:"offer,omitempty"` + Sku string `json:"sku,omitempty"` + Version string `json:"version,omitempty"` + ID string `json:"id,omitempty"` +} + +type VirtualHardDisk struct { + Uri string `json:"uri,omitempty"` +} + +type ManagedDiskParameters struct { + StorageAccountType string `json:"storageAccountType,omitempty"` + ID string +} + +type StorageProfile struct { + ImageReference ImageReference `json:"imageReference,omitempty"` + OsDisk SOsDisk `json:"osDisk,omitempty"` + DataDisks []SDataDisk `json:"dataDisks,allowempty"` +} + +type SSHPublicKey struct { + Path string `json:"path,omitempty"` + KeyData string `json:"keyData,omitempty"` +} + +type SSHConfiguration struct { + PublicKeys []SSHPublicKey `json:"publicKeys,omitempty"` +} + +type LinuxConfiguration struct { + DisablePasswordAuthentication bool `json:"disablePasswordAuthentication,omitempty"` + SSH *SSHConfiguration `json:"ssh,omitempty"` +} + +type VaultCertificate struct { + CertificateURL string `json:"certificateURL,omitempty"` + CertificateStore string `json:"certificateStore,omitempty"` +} + +type VaultSecretGroup struct { + SourceVault SubResource `json:"sourceVault,omitempty"` + VaultCertificates []VaultCertificate `json:"vaultCertificates,omitempty"` +} + +type OsProfile struct { + ComputerName string `json:"computerName,omitempty"` + AdminUsername string `json:"adminUsername,omitempty"` + AdminPassword string `json:"adminPassword,omitempty"` + CustomData string `json:"customData,omitempty"` + LinuxConfiguration *LinuxConfiguration `json:"linuxConfiguration,omitempty"` + Secrets []VaultSecretGroup `json:"secrets,omitempty"` +} + +type NetworkInterfaceReference struct { + ID string +} + +type NetworkProfile struct { + NetworkInterfaces []NetworkInterfaceReference `json:"networkInterfaces,omitempty"` +} + +type Statuses struct { + Code string + Level string + DisplayStatus string `json:"displayStatus,omitempty"` + Message string + //Time time.Time +} + +type SVMAgent struct { + VmAgentVersion string `json:"vmAgentVersion,omitempty"` + Statuses []Statuses `json:"statuses,omitempty"` +} + +type SExtension struct { + Name string + Type string + TypeHandlerVersion string `json:"typeHandlerVersion,omitempty"` + Statuses []Statuses `json:"statuses,omitempty"` +} + +type VirtualMachineInstanceView struct { + Statuses []Statuses `json:"statuses,omitempty"` + VMAgent SVMAgent `json:"vmAgent,omitempty"` + Extensions []SExtension `json:"extensions,omitempty"` +} + +type DomainName struct { + Id string + Name string + Type string +} + +type DebugProfile struct { + BootDiagnosticsEnabled *bool `json:"bootDiagnosticsEnabled,omitempty"` + ConsoleScreenshotBlobUri string `json:"consoleScreenshotBlobUri,omitempty"` + SerialOutputBlobUri string `json:"serialOutputBlobUri,omitempty"` +} + +type VirtualMachineProperties struct { + ProvisioningState string `json:"provisioningState,omitempty"` + InstanceView *VirtualMachineInstanceView `json:"instanceView,omitempty"` + DomainName *DomainName `json:"domainName,omitempty"` + HardwareProfile HardwareProfile `json:"hardwareProfile,omitempty"` + NetworkProfile NetworkProfile `json:"networkProfile,omitempty"` + StorageProfile StorageProfile `json:"storageProfile,omitempty"` + DebugProfile *DebugProfile `json:"debugProfile,omitempty"` + OsProfile OsProfile `json:"osProfile,omitempty"` + VmId string `json:"vmId,omitempty"` + TimeCreated time.Time `json:"timeCreated,omitempty"` +} + +type SExtensionResourceProperties struct { + AutoUpgradeMinorVersion bool + ProvisioningState string + Publisher string + Type string + TypeHandlerVersion string +} + +type SExtensionResource struct { + Id string + Name string + Type string + Location string + + Properties SExtensionResourceProperties +} + +type SInstance struct { + multicloud.SInstanceBase + AzureTags + host *SHost + + Properties VirtualMachineProperties + ID string + Name string + Type string + Location string + vmSize *SVMSize + + Resources []SExtensionResource +} + +func (self *SRegion) GetInstance(instanceId string) (*SInstance, error) { + instance := SInstance{} + params := url.Values{} + params.Set("$expand", "instanceView") + return &instance, self.get(instanceId, params, &instance) +} + +func (self *SRegion) GetInstanceScaleSets() ([]SInstance, error) { + instance := []SInstance{} + return instance, self.client.list("Microsoft.Compute/virtualMachineScaleSets", url.Values{}, &instance) +} + +func (self *SRegion) GetInstances() ([]SInstance, error) { + result := []SInstance{} + resource := fmt.Sprintf("Microsoft.Compute/locations/%s/virtualMachines", self.Name) + err := self.client.list(resource, url.Values{}, &result) + if err != nil { + return nil, err + } + return result, nil +} + +func (self *SRegion) doDeleteVM(instanceId string) error { + return self.del(instanceId) +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + secgroupIds := []string{} + if nics, err := self.getNics(); err == nil { + for _, nic := range nics { + if len(nic.Properties.NetworkSecurityGroup.ID) > 0 { + secgroupIds = append(secgroupIds, strings.ToLower(nic.Properties.NetworkSecurityGroup.ID)) + } + } + } + return secgroupIds, nil +} + +func (self *SInstance) GetSysTags() map[string]string { + data := map[string]string{} + if osDistribution := self.Properties.StorageProfile.ImageReference.Publisher; len(osDistribution) > 0 { + data["os_distribution"] = osDistribution + } + if loginAccount := self.Properties.OsProfile.AdminUsername; len(loginAccount) > 0 { + data["login_account"] = loginAccount + } + if loginKey := self.Properties.OsProfile.AdminPassword; len(loginKey) > 0 { + data["login_key"] = loginKey + } + for _, res := range self.Resources { + if strings.HasSuffix(strings.ToLower(res.Id), "databricksbootstrap") { + data[apis.IS_SYSTEM] = "true" + break + } + } + return data +} + +func (self *SInstance) GetTags() (map[string]string, error) { + return self.Tags, nil +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_AZURE +} + +func (self *SInstance) GetInstanceType() string { + return self.Properties.HardwareProfile.VMSize +} + +func (self *SInstance) WaitVMAgentReady() error { + status := "" + err := cloudprovider.Wait(time.Second*5, time.Minute*5, func() (bool, error) { + if self.Properties.InstanceView == nil { + self.Refresh() + return false, nil + } + + for _, vmAgent := range self.Properties.InstanceView.VMAgent.Statuses { + status = vmAgent.DisplayStatus + if status == "Ready" { + break + } + log.Debugf("vmAgent %s status: %s waite for ready", self.Properties.InstanceView.VMAgent.VmAgentVersion, vmAgent.DisplayStatus) + } + if status == "Ready" { + return true, nil + } + return false, self.Refresh() + }) + if err != nil { + return errors.Wrapf(err, "waitting vmAgent ready, current status: %s", status) + } + return nil + +} + +func (self *SInstance) WaitEnableVMAccessReady() error { + if self.Properties.InstanceView == nil { + return fmt.Errorf("instance may not install VMAgent or VMAgent not running") + } + if len(self.Properties.InstanceView.VMAgent.VmAgentVersion) > 0 { + return self.WaitVMAgentReady() + } + + for _, extension := range self.Properties.InstanceView.Extensions { + if extension.Name == "enablevmaccess" { + displayStatus := "" + for _, status := range extension.Statuses { + displayStatus = status.DisplayStatus + if displayStatus == "Provisioning succeeded" { + return nil + } + } + return self.host.zone.region.deleteExtension(self.ID, "enablevmaccess") + } + } + + return fmt.Errorf("instance may not install VMAgent or VMAgent not running") +} + +func (self *SInstance) getNics() ([]SInstanceNic, error) { + nics := []SInstanceNic{} + for _, _nic := range self.Properties.NetworkProfile.NetworkInterfaces { + nic, err := self.host.zone.region.GetNetworkInterface(_nic.ID) + if err != nil { + return nil, errors.Wrapf(err, "GetNetworkInterface(%s)", _nic.ID) + } + nic.instance = self + nics = append(nics, *nic) + } + return nics, nil +} + +func (self *SInstance) Refresh() error { + instance, err := self.host.zone.region.GetInstance(self.ID) + if err != nil { + return err + } + err = jsonutils.Update(self, instance) + if err != nil { + return err + } + self.Tags = instance.Tags + return nil +} + +func (self *SInstance) GetStatus() string { + if self.Properties.InstanceView == nil { + err := self.Refresh() + if err != nil { + log.Errorf("failed to get status for instance %s", self.Name) + return api.VM_UNKNOWN + } + } + for _, statuses := range self.Properties.InstanceView.Statuses { + if code := strings.Split(statuses.Code, "/"); len(code) == 2 { + if code[0] == "PowerState" { + switch code[1] { + case "stopped", "deallocated": + return api.VM_READY + case "running": + return api.VM_RUNNING + case "stopping": + return api.VM_STOPPING + case "starting": + return api.VM_STARTING + case "deleting": + return api.VM_DELETING + default: + log.Errorf("Unknow instance status %s", code[1]) + return api.VM_UNKNOWN + } + } + } + if statuses.Level == "Error" { + log.Errorf("Find error code: [%s] message: %s", statuses.Code, statuses.Message) + } + } + return api.VM_UNKNOWN +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return self.host.zone.region.AttachDisk(self.ID, diskId) +} + +func (region *SRegion) AttachDisk(instanceId, diskId string) error { + instance, err := region.GetInstance(instanceId) + if err != nil { + return errors.Wrapf(err, "GetInstance(%s)", instanceId) + } + lunMaps := map[int32]bool{} + dataDisks := jsonutils.NewArray() + for _, disk := range instance.Properties.StorageProfile.DataDisks { + if disk.ManagedDisk != nil && strings.ToLower(disk.ManagedDisk.ID) == strings.ToLower(diskId) { + return nil + } + lunMaps[disk.Lun] = true + dataDisks.Add(jsonutils.Marshal(disk)) + } + lun := func() int32 { + idx := int32(0) + for { + if _, ok := lunMaps[idx]; !ok { + return idx + } + idx++ + } + }() + dataDisks.Add(jsonutils.Marshal(map[string]interface{}{ + "Lun": lun, + "CreateOption": "Attach", + "ManagedDisk": map[string]string{ + "Id": diskId, + }, + })) + params := jsonutils.NewDict() + params.Add(dataDisks, "Properties", "StorageProfile", "DataDisks") + params.Add(jsonutils.Marshal(instance.Properties.StorageProfile.OsDisk), "Properties", "StorageProfile", "OsDisk") + _, err = region.patch(instanceId, params) + return err +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return self.host.zone.region.DetachDisk(self.ID, diskId) +} + +func (region *SRegion) DetachDisk(instanceId, diskId string) error { + instance, err := region.GetInstance(instanceId) + if err != nil { + return errors.Wrapf(err, "GetInstance(%s)", instanceId) + } + diskMaps := map[string]bool{} + dataDisks := jsonutils.NewArray() + for _, disk := range instance.Properties.StorageProfile.DataDisks { + if disk.ManagedDisk != nil { + diskMaps[strings.ToLower(disk.ManagedDisk.ID)] = true + if strings.ToLower(disk.ManagedDisk.ID) == strings.ToLower(diskId) { + continue + } + } + dataDisks.Add(jsonutils.Marshal(disk)) + } + if _, ok := diskMaps[strings.ToLower(diskId)]; !ok { + log.Warningf("not find disk %s with instance %s", diskId, instance.Name) + return nil + } + params := jsonutils.NewDict() + params.Add(dataDisks, "Properties", "StorageProfile", "DataDisks") + params.Add(jsonutils.Marshal(instance.Properties.StorageProfile.OsDisk), "Properties", "StorageProfile", "OsDisk") + _, err = region.patch(instanceId, params) + return err +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + if len(config.InstanceType) > 0 { + return self.host.zone.region.ChangeConfig(self.ID, config.InstanceType) + } + var err error + for _, vmSize := range self.host.zone.region.getHardwareProfile(config.Cpu, config.MemoryMB) { + log.Debugf("Try HardwareProfile : %s", vmSize) + err = self.host.zone.region.ChangeConfig(self.ID, vmSize) + if err == nil { + return nil + } + } + if err != nil { + return errors.Wrap(err, "ChangeConfig") + } + return fmt.Errorf("Failed to change vm config, specification not supported") +} + +func (self *SRegion) ChangeConfig(instanceId, instanceType string) error { + params := map[string]interface{}{ + "Properties": map[string]interface{}{ + "HardwareProfile": map[string]string{ + "vmSize": instanceType, + }, + }, + } + log.Debugf("Try HardwareProfile : %s", instanceType) + _, err := self.patch(instanceId, jsonutils.Marshal(params)) + return err +} + +func (region *SRegion) ChangeVMConfig(ctx context.Context, instanceId string, ncpu int, vmem int) error { + instacen, err := region.GetInstance(instanceId) + if err != nil { + return err + } + return instacen.ChangeConfig(ctx, &cloudprovider.SManagedVMChangeConfig{Cpu: ncpu, MemoryMB: vmem}) +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + if len(publicKey) > 0 || len(password) > 0 { + // 先判断系统是否安装了vmAgent,然后等待扩展准备完成后再重置密码 + err := self.WaitEnableVMAccessReady() + if err != nil { + return err + } + } + return self.host.zone.region.DeployVM(ctx, self.ID, string(self.GetOsType()), name, password, publicKey, deleteKeypair, description) +} + +type VirtualMachineExtensionProperties struct { + Publisher string `json:"publisher,omitempty"` + Type string `json:"type,omitempty"` + TypeHandlerVersion string `json:"typeHandlerVersion,omitempty"` + ProtectedSettings interface{} `json:"protectedSettings,omitempty"` + Settings interface{} `json:"settings,omitempty"` +} + +type SVirtualMachineExtension struct { + Location string `json:"location,omitempty"` + Properties VirtualMachineExtensionProperties `json:"properties,omitempty"` +} + +func (region *SRegion) execOnLinux(instanceId string, command string) error { + extension := SVirtualMachineExtension{ + Location: region.Name, + Properties: VirtualMachineExtensionProperties{ + Publisher: "Microsoft.Azure.Extensions", + Type: "CustomScript", + TypeHandlerVersion: "2.0", + Settings: map[string]string{"commandToExecute": command}, + }, + } + resource := fmt.Sprintf("%s/extensions/CustomScript", instanceId) + _, err := region.put(resource, jsonutils.Marshal(extension)) + return err +} + +func (region *SRegion) resetOvsEnv(instanceId string) error { + ovsEnv, err := region.getOvsEnv(instanceId) + if err != nil { + return err + } + err = region.execOnLinux(instanceId, fmt.Sprintf(`echo '%s' > /var/lib/waagent/ovf-env.xml`, ovsEnv)) + if err != nil { + return err + } + return region.execOnLinux(instanceId, "systemctl restart wagent") +} + +func (region *SRegion) deleteExtension(instanceId, extensionName string) error { + return region.del(fmt.Sprintf("%s/extensions/%s", instanceId, extensionName)) +} +func (region *SRegion) resetLoginInfo(osType, instanceId string, setting map[string]interface{}) error { + // https://github.com/Azure/azure-linux-extensions/blob/master/VMAccess/README.md + handlerVersion := "1.5" + properties := map[string]interface{}{ + "Publisher": "Microsoft.OSTCExtensions", + "Type": "VMAccessForLinux", + "TypeHandlerVersion": handlerVersion, + "Settings": map[string]string{}, + "protectedSettings": setting, + + "autoUpgradeMinorVersion": true, + } + if osType == osprofile.OS_TYPE_WINDOWS { + // https://github.com/Azure/azure-cli/blob/dev/src/azure-cli/azure/cli/command_modules/vm/custom.py + handlerVersion = "2.4" + properties["TypeHandlerVersion"] = handlerVersion + properties["Publisher"] = "Microsoft.Compute" + properties["Type"] = "VMAccessAgent" + } + params := map[string]interface{}{ + "Location": region.Name, + "Properties": properties, + } + instance, err := region.GetInstance(instanceId) + if err != nil { + return errors.Wrapf(err, "GetInstance(%s)", instanceId) + } + for _, extension := range instance.Resources { + if extension.Name == "enablevmaccess" { + if version.GT(extension.Properties.TypeHandlerVersion, handlerVersion) { + properties["TypeHandlerVersion"] = extension.Properties.TypeHandlerVersion + break + } + } + } + resource := fmt.Sprintf("%s/extensions/enablevmaccess", instanceId) + _, err = region.put(resource, jsonutils.Marshal(params)) + if err != nil { + switch osType { + case osprofile.OS_TYPE_WINDOWS: + return err + default: + err = region.deleteExtension(instanceId, "enablevmaccess") + if err != nil { + return err + } + err = region.resetOvsEnv(instanceId) + if err != nil { + return err + } + resource := fmt.Sprintf("%s/extensions/enablevmaccess", instanceId) + _, err = region.put(resource, jsonutils.Marshal(params)) + return err + } + } + err = cloudprovider.Wait(time.Second*5, time.Minute*5, func() (bool, error) { + instance, err := region.GetInstance(instanceId) + if err != nil { + return false, errors.Wrapf(err, "GetInstance(%s)", instanceId) + } + for _, extension := range instance.Resources { + if extension.Name == "enablevmaccess" { + if extension.Properties.ProvisioningState == "Succeeded" { + return true, nil + } + log.Debugf("enablevmaccess status %s expect Succeeded", extension.Properties.ProvisioningState) + if extension.Properties.ProvisioningState == "Failed" { + if instance.Properties.InstanceView != nil { + for _, info := range instance.Properties.InstanceView.Extensions { + if info.Name == "enablevmaccess" && len(info.Statuses) > 0 { + return false, fmt.Errorf("details: %s", jsonutils.Marshal(info.Statuses)) + } + } + } + return false, fmt.Errorf("reset passwod failed") + } + } + } + return false, nil + }) + if err != nil { + return errors.Wrapf(err, "wait for enablevmaccess error: %v", err) + } + return nil +} + +func (region *SRegion) resetPublicKey(osType, instanceId string, username, publicKey string) error { + setting := map[string]interface{}{ + "username": username, + "ssh_key": publicKey, + } + return region.resetLoginInfo(osType, instanceId, setting) +} + +func (region *SRegion) resetPassword(osType, instanceId, username, password string) error { + setting := map[string]interface{}{ + "username": username, + "password": password, + } + return region.resetLoginInfo(osType, instanceId, setting) +} + +func (region *SRegion) DeployVM(ctx context.Context, instanceId, osType, name, password, publicKey string, deleteKeypair bool, description string) error { + instance, err := region.GetInstance(instanceId) + if err != nil { + return err + } + if deleteKeypair { + return nil + } + if len(publicKey) > 0 { + return region.resetPublicKey(osType, instanceId, instance.Properties.OsProfile.AdminUsername, publicKey) + } + if len(password) > 0 { + return region.resetPassword(osType, instanceId, instance.Properties.OsProfile.AdminUsername, password) + } + return nil +} + +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + cpu := self.GetVcpuCount() + memoryMb := self.GetVmemSizeMB() + opts := &cloudprovider.ServerStopOptions{ + IsForce: true, + } + self.StopVM(ctx, opts) + return self.host.zone.region.ReplaceSystemDisk(self, cpu, memoryMb, desc.ImageId, desc.Password, desc.PublicKey, desc.SysSizeGB) +} + +func (region *SRegion) ReplaceSystemDisk(instance *SInstance, cpu int, memoryMb int, imageId, passwd, publicKey string, sysSizeGB int) (string, error) { + log.Debugf("ReplaceSystemDisk %s image: %s", instance.ID, imageId) + storageType := instance.Properties.StorageProfile.OsDisk.ManagedDisk.StorageAccountType + if len(storageType) == 0 { + _disk, err := region.GetDisk(instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID) + if err != nil { + return "", err + } + storageType = _disk.Sku.Name + } + image, err := region.GetImageById(imageId) + if err != nil { + return "", errors.Wrapf(err, "GetImageById(%s)", imageId) + } + if minOsDiskSizeGB := image.GetMinOsDiskSizeGb(); minOsDiskSizeGB > sysSizeGB { + sysSizeGB = minOsDiskSizeGB + } + osType := instance.Properties.StorageProfile.OsDisk.OsType + // https://support.microsoft.com/zh-cn/help/4018933/the-default-size-of-windows-server-images-in-azure-is-changed-from-128 + // windows默认系统盘是128G, 若重装系统时,系统盘小于128G,则会出现 {"error":{"code":"ResizeDiskError","message":"Disk size reduction is not supported. Current size is 137438953472 bytes, requested size is 33285996544 bytes.","target":"osDisk.diskSizeGB"}} 错误 + if osType == osprofile.OS_TYPE_WINDOWS && sysSizeGB < 128 { + sysSizeGB = 128 + } + nicId := instance.Properties.NetworkProfile.NetworkInterfaces[0].ID + nic, err := region.GetNetworkInterface(nicId) + if err != nil { + return "", errors.Wrapf(err, "GetNetworkInterface(%s)", nicId) + } + if len(nic.Properties.IPConfigurations) == 0 { + return "", fmt.Errorf("failed to find networkId for nic %s", nicId) + } + networkId := nic.Properties.IPConfigurations[0].Properties.Subnet.ID + + nic, err = region.CreateNetworkInterface("", fmt.Sprintf("%s-temp-ifconfig", instance.Name), "", networkId, "") + if err != nil { + return "", errors.Wrapf(err, "CreateNetworkInterface") + } + + newInstance, err := region.CreateInstanceSimple(instance.Name+"-rebuild", imageId, osType, cpu, memoryMb, sysSizeGB, storageType, []int{}, nic.ID, passwd, publicKey) + newInstance.host = instance.host + cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) { + err = newInstance.WaitVMAgentReady() + if err != nil { + log.Warningf("WaitVMAgentReady for %s error: %v", newInstance.Name, err) + return false, nil + } + return true, nil + }) + + opts := &cloudprovider.ServerStopOptions{ + IsForce: true, + } + newInstance.StopVM(context.Background(), opts) + + pruneDiskId := instance.Properties.StorageProfile.OsDisk.ManagedDisk.ID + newDiskId := newInstance.Properties.StorageProfile.OsDisk.ManagedDisk.ID + + err = newInstance.deleteVM(context.TODO(), true) + if err != nil { + log.Warningf("delete vm %s error: %v", newInstance.ID, err) + } + + defer func() { + if len(pruneDiskId) > 0 { + err := cloudprovider.Wait(time.Second*3, time.Minute, func() (bool, error) { + err = region.DeleteDisk(pruneDiskId) + if err != nil { + log.Errorf("delete prune disk %s error: %v", pruneDiskId, err) + return false, nil + } + return true, nil + }) + if err != nil { + log.Errorf("timeout for delete prune disk %s", pruneDiskId) + } + } + }() + + //交换系统盘 + params := map[string]interface{}{ + "Id": instance.ID, + "Location": instance.Location, + "Properties": map[string]interface{}{ + "StorageProfile": map[string]interface{}{ + "OsDisk": map[string]interface{}{ + "createOption": "FromImage", + "ManagedDisk": map[string]interface{}{ + "Id": newDiskId, + "storageAccountType": nil, + }, + "osType": osType, + "DiskSizeGB": nil, + }, + }, + }, + } + err = region.update(jsonutils.Marshal(params), nil) + if err != nil { + // 更新失败,需要删除新建的系统盘 + pruneDiskId = newDiskId + return "", errors.Wrapf(err, "region.update") + } + return strings.ToLower(newDiskId), nil +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetId() string { + return self.ID +} + +func (self *SInstance) GetName() string { + return self.Name +} + +func (self *SInstance) GetHostname() string { + return self.Name +} + +func (self *SInstance) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SRegion) DeleteVM(instanceId string) error { + return self.doDeleteVM(instanceId) +} + +func (self *SInstance) deleteVM(ctx context.Context, keepSysDisk bool) error { + sysDiskId := "" + if self.Properties.StorageProfile.OsDisk.ManagedDisk != nil { + sysDiskId = self.Properties.StorageProfile.OsDisk.ManagedDisk.ID + } + err := self.host.zone.region.DeleteVM(self.ID) + if err != nil { + return err + } + if len(sysDiskId) > 0 && !keepSysDisk { + err := self.host.zone.region.DeleteDisk(sysDiskId) + if err != nil { + return err + } + } + + nics, err := self.getNics() + if err != nil { + return err + } + for _, nic := range nics { + if err := nic.Delete(); err != nil { + if err != cloudprovider.ErrNotFound { + return err + } + } + } + return nil +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + return self.deleteVM(ctx, false) +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks := []cloudprovider.ICloudDisk{} + self.Properties.StorageProfile.OsDisk.region = self.host.zone.region + disks = append(disks, &self.Properties.StorageProfile.OsDisk) + for i := range self.Properties.StorageProfile.DataDisks { + self.Properties.StorageProfile.DataDisks[i].region = self.host.zone.region + disks = append(disks, &self.Properties.StorageProfile.DataDisks[i]) + } + return disks, nil +} + +func (self *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(osprofile.NormalizeOSType(string(self.Properties.StorageProfile.OsDisk.OsType))) +} + +func (self *SInstance) GetFullOsName() string { + return self.Properties.StorageProfile.ImageReference.Offer +} + +func (self *SInstance) GetBios() cloudprovider.TBiosType { + return "BIOS" +} + +func (i *SInstance) GetOsDist() string { + return "" +} + +func (i *SInstance) GetOsVersion() string { + return "" +} + +func (i *SInstance) GetOsLang() string { + return "" +} + +func (i *SInstance) GetOsArch() string { + return apis.OS_ARCH_X86_64 +} + +func (self *SRegion) getOvsEnv(instanceId string) (string, error) { + instance, err := self.GetInstance(instanceId) + if err != nil { + return "", err + } + kms := map[string]string{ + "AzureGermanCloud": "kms.core.cloudapi.de", + "AzureChinaCloud": "kms.core.chinacloudapi.cn", + "AzureUSGovernmentCloud": "kms.core.usgovcloudapi.net", + "AzurePublicCloud": "kms.core.windows.net", + } + kmsServer := "kms.core.chinacloudapi.cn" + if _kmsServer, ok := kms[self.client.envName]; ok { + kmsServer = _kmsServer + } + return fmt.Sprintf(` + + + 1.0 + + LinuxProvisioningConfiguration + %s + false + %s + REDACTED + + + + 1.0 + + %s + true + + true + true + false + false + + + `, instance.Properties.OsProfile.AdminUsername, instance.Properties.OsProfile.ComputerName, kmsServer), nil +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics := make([]cloudprovider.ICloudNic, 0) + _nics, err := self.getNics() + if err != nil { + return nil, err + } + for i := 0; i < len(_nics); i++ { + _nics[i].instance = self + nics = append(nics, &_nics[i]) + } + return nics, nil +} + +func (self *SInstance) GetMachine() string { + return "pc" +} + +func (self *SInstance) GetBootOrder() string { + return "dcn" +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (self *SInstance) fetchVMSize() error { + if self.vmSize == nil { + vmSize, err := self.host.zone.region.getVMSize(self.Properties.HardwareProfile.VMSize) + if err != nil { + return err + } + self.vmSize = vmSize + } + return nil +} + +func (self *SInstance) GetVcpuCount() int { + err := self.fetchVMSize() + if err != nil { + log.Errorf("fetchVMSize error: %v", err) + return 0 + } + return self.vmSize.NumberOfCores +} + +func (self *SInstance) GetVmemSizeMB() int { + err := self.fetchVMSize() + if err != nil { + log.Errorf("fetchVMSize error: %v", err) + return 0 + } + return int(self.vmSize.MemoryInMB) +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) StartVM(instanceId string) error { + _, err := self.perform(instanceId, "start", nil) + return err +} + +func (self *SInstance) StartVM(ctx context.Context) error { + if err := self.host.zone.region.StartVM(self.ID); err != nil { + return err + } + self.host.zone.region.patch(self.ID, jsonutils.Marshal(self)) + return cloudprovider.WaitStatus(self, api.VM_RUNNING, 10*time.Second, 300*time.Second) +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + err := self.host.zone.region.StopVM(self.ID, opts.IsForce) + if err != nil { + return err + } + self.host.zone.region.patch(self.ID, jsonutils.Marshal(self)) + return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) +} + +func (self *SRegion) StopVM(instanceId string, isForce bool) error { + _, err := self.perform(instanceId, "deallocate", nil) + return err +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + nics, err := self.getNics() + if err != nil { + return nil, err + } + for _, nic := range nics { + for _, ip := range nic.Properties.IPConfigurations { + if ip.Properties.PublicIPAddress != nil && len(ip.Properties.PublicIPAddress.ID) > 0 { + eip, err := self.host.zone.region.GetEip(ip.Properties.PublicIPAddress.ID) + if err != nil { + return nil, errors.Wrapf(err, "GetEip(%s)", ip.Properties.PublicIPAddress.ID) + } + if len(eip.Properties.IPAddress) > 0 { + return eip, nil + } + } + } + } + return nil, nil +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.host.zone.region.SetSecurityGroup(self.ID, secgroupId) +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + if len(secgroupIds) == 1 { + return self.host.zone.region.SetSecurityGroup(self.ID, secgroupIds[0]) + } + return fmt.Errorf("Unexpect segroup count %d", len(secgroupIds)) +} + +func (self *SInstance) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SInstance) GetCreatedAt() time.Time { + return self.Properties.TimeCreated +} + +func (self *SInstance) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetProjectId() string { + return getResourceGroup(self.ID) +} + +func (self *SInstance) GetError() error { + if self.Properties.InstanceView != nil { + for _, status := range self.Properties.InstanceView.Statuses { + if status.Code == "ProvisioningState/failed/AllocationFailed" { + return errors.Errorf("%s %s", status.Code, status.Message) + } + } + } + return nil +} + +func (self *SRegion) SaveImage(osType, diskId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { + params := map[string]interface{}{ + "Location": self.Name, + "Name": opts.Name, + "Properties": map[string]interface{}{ + "storageProfile": map[string]interface{}{ + "osDisk": map[string]interface{}{ + "osType": osType, + "managedDisk": map[string]string{ + "id": diskId, + }, + "osState": "Generalized", + }, + }, + }, + "Type": "Microsoft.Compute/images", + } + image := &SImage{storageCache: self.getStoragecache()} + err := self.create("", jsonutils.Marshal(params), image) + if err != nil { + return nil, errors.Wrapf(err, "create image") + } + return image, nil +} + +func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { + if self.Properties.StorageProfile.OsDisk.ManagedDisk == nil { + return nil, fmt.Errorf("invalid os disk for save image") + } + image, err := self.host.zone.region.SaveImage(string(self.GetOsType()), self.Properties.StorageProfile.OsDisk.ManagedDisk.ID, opts) + if err != nil { + return nil, errors.Wrapf(err, "SaveImage") + } + return image, nil +} + +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { + if !replace { + for k, v := range self.Tags { + if _, ok := tags[k]; !ok { + tags[k] = v + } + } + } + _, err := self.host.zone.region.client.SetTags(self.ID, tags) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.client.SetTags(%s,%s)", self.ID, jsonutils.Marshal(tags).String()) + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/instancenic.go new file mode 100644 index 0000000000..c79aa7fce0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/instancenic.go @@ -0,0 +1,235 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type PublicIPAddress struct { + ID string + Name string + Location string + Properties PublicIPAddressPropertiesFormat +} + +type InterfaceIPConfigurationPropertiesFormat struct { + PrivateIPAddress string `json:"privateIPAddress,omitempty"` + PrivateIPAddressVersion string `json:"privateIPAddressVersion,omitempty"` + PrivateIPAllocationMethod string `json:"privateIPAllocationMethod,omitempty"` + Subnet SNetwork `json:"subnet,omitempty"` + Primary bool `json:"primary,omitempty"` + PublicIPAddress *PublicIPAddress `json:"publicIPAddress,omitempty"` +} + +type InterfaceIPConfiguration struct { + Properties InterfaceIPConfigurationPropertiesFormat `json:"properties,omitempty"` + Name string + ID string +} + +type InterfacePropertiesFormat struct { + NetworkSecurityGroup SSecurityGroup `json:"networkSecurityGroup,omitempty"` + IPConfigurations []InterfaceIPConfiguration `json:"ipConfigurations,omitempty"` + MacAddress string `json:"macAddress,omitempty"` + Primary bool `json:"primary,omitempty"` + VirtualMachine SubResource `json:"virtualMachine,omitempty"` +} + +type SInstanceNic struct { + multicloud.SResourceBase + AzureTags + + instance *SInstance + ID string + Name string + Type string + Location string + Properties InterfacePropertiesFormat `json:"properties,omitempty"` + + cloudprovider.DummyICloudNic +} + +func (self *SInstanceNic) GetIP() string { + if len(self.Properties.IPConfigurations) > 0 { + return self.Properties.IPConfigurations[0].Properties.PrivateIPAddress + } + return "" +} + +func (region *SRegion) DeleteNetworkInterface(interfaceId string) error { + return region.del(interfaceId) +} + +func (self *SInstanceNic) Delete() error { + return self.instance.host.zone.region.DeleteNetworkInterface(self.ID) +} + +func (self *SInstanceNic) GetMAC() string { + mac := self.Properties.MacAddress + return strings.Replace(strings.ToLower(mac), "-", ":", -1) +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) updateSecurityGroup(secgroupId string) error { + region := self.instance.host.zone.region + if len(secgroupId) > 0 { + self.Properties.NetworkSecurityGroup = SSecurityGroup{ID: secgroupId} + } + return region.update(jsonutils.Marshal(self), nil) +} + +func (self *SInstanceNic) revokeSecurityGroup() error { + return self.updateSecurityGroup("") +} + +func (self *SInstanceNic) assignSecurityGroup(secgroupId string) error { + return self.updateSecurityGroup(secgroupId) +} + +func (self *SInstanceNic) GetINetworkId() string { + if len(self.Properties.IPConfigurations) > 0 { + return strings.ToLower(self.Properties.IPConfigurations[0].Properties.Subnet.ID) + } + return "" +} + +func (self *SRegion) GetNetworkInterface(interfaceId string) (*SInstanceNic, error) { + instancenic := SInstanceNic{} + return &instancenic, self.get(interfaceId, url.Values{}, &instancenic) +} + +func (self *SRegion) GetNetworkInterfaces() ([]SInstanceNic, error) { + interfaces := []SInstanceNic{} + err := self.list("Microsoft.Network/networkInterfaces", url.Values{}, &interfaces) + if err != nil { + return nil, err + } + return interfaces, nil +} + +func (self *SRegion) CreateNetworkInterface(resourceGroup string, nicName string, ipAddr string, subnetId string, secgrpId string) (*SInstanceNic, error) { + allocMethod := "Static" + if len(ipAddr) == 0 { + allocMethod = "Dynamic" + } + params := jsonutils.Marshal(map[string]interface{}{ + "Name": nicName, + "Location": self.Name, + "Properties": map[string]interface{}{ + "IPConfigurations": []map[string]interface{}{ + map[string]interface{}{ + "Name": nicName, + "Properties": map[string]interface{}{ + "PrivateIPAddress": ipAddr, + "PrivateIPAddressVersion": "IPv4", + "PrivateIPAllocationMethod": allocMethod, + "Subnet": map[string]string{ + "Id": subnetId, + }, + }, + }, + }, + }, + "Type": "Microsoft.Network/networkInterfaces", + }).(*jsonutils.JSONDict) + if len(secgrpId) > 0 { + params.Add(jsonutils.Marshal(map[string]string{"id": secgrpId}), "Properties", "NetworkSecurityGroup") + } + nic := SInstanceNic{} + return &nic, self.create(resourceGroup, params, &nic) +} + +func (self *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { + nics, err := self.GetNetworkInterfaces() + if err != nil { + return nil, errors.Wrapf(err, "GetNetworkInterfaces") + } + ret := []cloudprovider.ICloudNetworkInterface{} + for i := range nics { + if len(nics[i].Properties.VirtualMachine.ID) > 0 { + continue + } + ret = append(ret, &nics[i]) + } + return ret, nil +} + +func (self *SInstanceNic) GetAssociateId() string { + return "" +} + +func (self *SInstanceNic) GetAssociateType() string { + return "" +} + +func (self *SInstanceNic) GetId() string { + return self.ID +} + +func (self *SInstanceNic) GetName() string { + return self.Name +} + +func (self *SInstanceNic) GetStatus() string { + return api.NETWORK_INTERFACE_STATUS_AVAILABLE +} + +func (self *SInstanceNic) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SInstanceNic) GetMacAddress() string { + return self.Properties.MacAddress +} + +func (self *SInstanceNic) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { + addrs := []cloudprovider.ICloudInterfaceAddress{} + for i := range self.Properties.IPConfigurations { + addrs = append(addrs, &self.Properties.IPConfigurations[i]) + } + return addrs, nil +} + +func (self *InterfaceIPConfiguration) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *InterfaceIPConfiguration) GetINetworkId() string { + return strings.ToLower(self.Properties.Subnet.ID) +} + +func (self *InterfaceIPConfiguration) GetIP() string { + return self.Properties.PrivateIPAddress +} + +func (self *InterfaceIPConfiguration) IsPrimary() bool { + return self.Properties.Primary +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/kube_cluster.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/kube_cluster.go new file mode 100644 index 0000000000..3beab9801b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/kube_cluster.go @@ -0,0 +1,220 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "encoding/base64" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SKubeCluster struct { + multicloud.SResourceBase + AzureTags + region *SRegion + + Id string `json:"id"` + Location string `json:"location"` + Name string `json:"name"` + Type string `json:"type"` + Properties struct { + ProvisioningState string `json:"provisioningState"` + PowerState struct { + Code string `json:"code"` + } `json:"powerState"` + KubernetesVersion string `json:"kubernetesVersion"` + DNSPrefix string `json:"dnsPrefix"` + Fqdn string `json:"fqdn"` + AzurePortalFQDN string `json:"azurePortalFQDN"` + AgentPoolProfiles []SKubeNodePool `json:"agentPoolProfiles"` + ServicePrincipalProfile struct { + ClientId string `json:"clientId"` + } `json:"servicePrincipalProfile"` + AddonProfiles struct { + Azurepolicy struct { + Enabled bool `json:"enabled"` + Config string `json:"config"` + } `json:"azurepolicy"` + HTTPApplicationRouting struct { + Enabled bool `json:"enabled"` + Config struct { + HTTPApplicationRoutingZoneName string `json:"HTTPApplicationRoutingZoneName"` + } `json:"config"` + } `json:"httpApplicationRouting"` + OmsAgent struct { + Enabled bool `json:"enabled"` + Config struct { + LogAnalyticsWorkspaceResourceId string `json:"logAnalyticsWorkspaceResourceId"` + } `json:"config"` + Identity struct { + ResourceId string `json:"resourceId"` + ClientId string `json:"clientId"` + ObjectId string `json:"objectId"` + } `json:"identity"` + } `json:"omsAgent"` + } `json:"addonProfiles"` + NodeResourceGroup string `json:"nodeResourceGroup"` + EnableRBAC bool `json:"enableRBAC"` + NetworkProfile struct { + NetworkPlugin string `json:"networkPlugin"` + LoadBalancerSku string `json:"loadBalancerSku"` + LoadBalancerProfile struct { + ManagedOutboundIPs struct { + Count int `json:"count"` + } `json:"managedOutboundIPs"` + EffectiveOutboundIPs []struct { + Id string `json:"id"` + } `json:"effectiveOutboundIPs"` + } `json:"loadBalancerProfile"` + PodCidr string `json:"podCidr"` + ServiceCidr string `json:"serviceCidr"` + DNSServiceIP string `json:"dnsServiceIP"` + DockerBridgeCidr string `json:"dockerBridgeCidr"` + OutboundType string `json:"outboundType"` + } `json:"networkProfile"` + MaxAgentPools int `json:"maxAgentPools"` + APIServerAccessProfile struct { + EnablePrivateCluster bool `json:"enablePrivateCluster"` + } `json:"apiServerAccessProfile"` + IdentityProfile struct { + Kubeletidentity struct { + ResourceId string `json:"resourceId"` + ClientId string `json:"clientId"` + ObjectId string `json:"objectId"` + } `json:"kubeletidentity"` + } `json:"identityProfile"` + } `json:"properties"` + Identity struct { + Type string `json:"type"` + PrincipalId string `json:"principalId"` + TenantId string `json:"tenantId"` + } `json:"identity"` + Sku struct { + Name string `json:"name"` + Tier string `json:"tier"` + } `json:"sku"` +} + +func (self *SKubeCluster) GetName() string { + return self.Name +} + +func (self *SKubeCluster) GetId() string { + return self.Id +} + +func (self *SKubeCluster) GetGlobalId() string { + return strings.ToLower(self.Id) +} + +func (self *SKubeCluster) Refresh() error { + cluster, err := self.region.GetKubeCluster(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, cluster) +} + +func (self *SKubeCluster) GetStatus() string { + return strings.ToLower(self.Properties.PowerState.Code) +} + +func (self *SKubeCluster) Delete(isRetain bool) error { + return self.region.Delete(self.Id) +} + +func (self *SKubeCluster) GetEnabled() bool { + return true +} + +func (self *SKubeCluster) GetIKubeNodes() ([]cloudprovider.ICloudKubeNode, error) { + return []cloudprovider.ICloudKubeNode{}, nil +} + +func (self *SKubeCluster) GetIKubeNodePools() ([]cloudprovider.ICloudKubeNodePool, error) { + ret := []cloudprovider.ICloudKubeNodePool{} + for i := range self.Properties.AgentPoolProfiles { + self.Properties.AgentPoolProfiles[i].cluster = self + ret = append(ret, &self.Properties.AgentPoolProfiles[i]) + } + return ret, nil +} + +func (self *SKubeCluster) GetKubeConfig(private bool, expireMinute int) (*cloudprovider.SKubeconfig, error) { + return self.region.GetKubeConfig(self.Id) +} + +func (self *SRegion) GetICloudKubeClusters() ([]cloudprovider.ICloudKubeCluster, error) { + clusters, err := self.GetKubeClusters() + if err != nil { + return nil, errors.Wrapf(err, "GetKubClusters") + } + ret := []cloudprovider.ICloudKubeCluster{} + for i := range clusters { + clusters[i].region = self + ret = append(ret, &clusters[i]) + } + return ret, nil +} + +func (self *SRegion) GetICloudKubeClusterById(id string) (cloudprovider.ICloudKubeCluster, error) { + cluster, err := self.GetKubeCluster(id) + if err != nil { + return nil, errors.Wrapf(err, "GetKubeCluster(%s)", id) + } + return cluster, nil +} + +func (self *SRegion) GetKubeCluster(id string) (*SKubeCluster, error) { + ret := &SKubeCluster{region: self} + return ret, self.get(id, nil, ret) +} + +func (self *SRegion) GetKubeClusters() ([]SKubeCluster, error) { + clusters := []SKubeCluster{} + return clusters, self.list("Microsoft.ContainerService/managedClusters", nil, &clusters) +} + +func (self *SRegion) GetKubeConfig(id string) (*cloudprovider.SKubeconfig, error) { + resp, err := self.perform(id, "listClusterAdminCredential", nil) + if err != nil { + return nil, errors.Wrapf(err, "listClusterAdminCredential") + } + ret := struct { + Kubeconfigs []struct { + Name string + Value string + } + }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + if len(ret.Kubeconfigs) == 0 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty kubeconfig") + } + result := &cloudprovider.SKubeconfig{} + config, err := base64.StdEncoding.DecodeString(ret.Kubeconfigs[0].Value) + if err != nil { + return nil, errors.Wrapf(err, "base64.decode") + } + result.Config = string(config) + return result, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/kube_node_pools.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/kube_node_pools.go new file mode 100644 index 0000000000..75eb5032d7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/kube_node_pools.go @@ -0,0 +1,64 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "strings" + + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SKubeNodePool struct { + multicloud.SResourceBase + AzureTags + + cluster *SKubeCluster + + Name string `json:"name"` + Count int `json:"count"` + VMSize string `json:"vmSize"` + OsDiskSizeGB int `json:"osDiskSizeGB"` + OsDiskType string `json:"osDiskType"` + KubeletDiskType string `json:"kubeletDiskType"` + MaxPods int `json:"maxPods"` + Type string `json:"type"` + EnableAutoScaling bool `json:"enableAutoScaling"` + ProvisioningState string `json:"provisioningState"` + PowerState struct { + Code string `json:"code"` + } `json:"powerState"` + OrchestratorVersion string `json:"orchestratorVersion"` + Mode string `json:"mode"` + OsType string `json:"osType"` + OsSKU string `json:"osSKU"` + NodeImageVersion string `json:"nodeImageVersion"` + EnableFIPS bool `json:"enableFIPS"` +} + +func (self *SKubeNodePool) GetName() string { + return self.Name +} + +func (self *SKubeNodePool) GetId() string { + return self.Name +} + +func (self *SKubeNodePool) GetGlobalId() string { + return self.Name +} + +func (self *SKubeNodePool) GetStatus() string { + return strings.ToLower(self.PowerState.Code) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancer.go new file mode 100644 index 0000000000..e7702f622d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancer.go @@ -0,0 +1,751 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "context" + "strconv" + "strings" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancer struct { + multicloud.SResourceBase + region *SRegion + eips []cloudprovider.ICloudEIP + lbbgs []cloudprovider.ICloudLoadbalancerBackendGroup + listeners []cloudprovider.ICloudLoadbalancerListener + + Name string `json:"name"` + ID string `json:"id"` + Etag string `json:"etag"` + Type string `json:"type"` + Tags map[string]string `json:"tags"` + Location string `json:"location"` + Properties SLoadbalancerProperties `json:"properties"` + Sku Sku `json:"sku"` +} + +func (self *SLoadbalancer) GetId() string { + return self.ID +} + +func (self *SLoadbalancer) GetName() string { + return self.Name +} + +func (self *SLoadbalancer) GetGlobalId() string { + return strings.ToLower(self.GetId()) +} + +func (self *SLoadbalancer) GetStatus() string { + switch self.Properties.ProvisioningState { + case "Deleting": + return api.LB_STATUS_DELETING + case "Failed": + return api.LB_STATUS_START_FAILED + case "Updating": + return api.LB_SYNC_CONF + } + + switch self.Properties.OperationalState { + case "Running": + return api.LB_STATUS_ENABLED + case "Stopped": + return api.LB_STATUS_DISABLED + case "Starting", "Stopping": + return api.LB_SYNC_CONF + default: + if self.Properties.ProvisioningState == "Succeeded" { + return api.LB_STATUS_ENABLED + } + + return api.LB_STATUS_UNKNOWN + } +} + +func (self *SLoadbalancer) Refresh() error { + lb, err := self.region.GetILoadBalancerById(self.GetId()) + if err != nil { + return errors.Wrap(err, "GetILoadBalancerById.Refresh") + } + + err = jsonutils.Update(self, lb) + if err != nil { + return errors.Wrap(err, "jsonutils.Update") + } + + self.eips = nil + self.lbbgs = nil + self.listeners = nil + return nil +} + +func (self *SLoadbalancer) IsEmulated() bool { + return false +} + +func (self *SLoadbalancer) GetSysTags() map[string]string { + data := map[string]string{} + data["loadbalance_type"] = self.Type + data["capacity"] = self.Properties.Sku.Capacity + data["max_capacity"] = strconv.Itoa(self.Properties.AutoscaleConfiguration.MaxCapacity) + data["min_capacity"] = strconv.Itoa(self.Properties.AutoscaleConfiguration.MinCapacity) + data["properties"] = jsonutils.Marshal(self.Properties).String() + return data +} + +func (self *SLoadbalancer) GetTags() (map[string]string, error) { + return self.Tags, nil +} + +func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} + +func (self *SLoadbalancer) GetProjectId() string { + return getResourceGroup(self.ID) +} + +func (self *SLoadbalancer) getAddresses() [][]string { + ret := [][]string{[]string{}, []string{}} + for _, fip := range self.Properties.FrontendIPConfigurations { + eip := fip.Properties.PublicIPAddress + if eip != nil && len(eip.Properties.IPAddress) > 0 { + ret[0] = append(ret[0], fip.Properties.PublicIPAddress.Properties.IPAddress) + continue + } + + if len(fip.Properties.PrivateIPAddress) > 0 { + ret[1] = append(ret[1], fip.Properties.PrivateIPAddress) + continue + } + } + + return ret +} + +func (self *SLoadbalancer) GetAddress() string { + ips := self.getAddresses() + if len(ips[0]) > 0 { + return ips[0][0] + } else if len(ips[1]) > 0 { + return ips[1][0] + } else { + return "" + } +} + +func (self *SLoadbalancer) GetAddressType() string { + ips := self.getAddresses() + if len(ips[0]) > 0 { + return api.LB_ADDR_TYPE_INTERNET + } else if len(ips[1]) > 0 { + return api.LB_ADDR_TYPE_INTRANET + } else { + return api.LB_ADDR_TYPE_INTRANET + } +} + +func (self *SLoadbalancer) GetNetworkType() string { + return api.LB_NETWORK_TYPE_VPC +} + +func (self *SLoadbalancer) getNetworkIds() []string { + ret := []string{} + for _, fip := range self.Properties.FrontendIPConfigurations { + subnet := fip.Properties.Subnet + if len(subnet.ID) > 0 { + ret = append(ret, subnet.ID) + } + } + + return ret +} + +func (self *SLoadbalancer) getLbbgNetworkIds() []string { + ret := []string{} + for _, b := range self.Properties.BackendAddressPools { + bips := b.Properties.BackendIPConfigurations + if len(bips) > 0 { + for _, ip := range bips { + if strings.Contains(ip.ID, "Microsoft.Network/networkInterfaces") { + nic, _ := self.region.GetNetworkInterface(strings.Split(ip.ID, "/ipConfigurations")[0]) + if nic != nil && len(nic.Properties.IPConfigurations) > 0 { + ipc := nic.Properties.IPConfigurations[0] + if len(ipc.Properties.Subnet.ID) > 0 { + return []string{ipc.Properties.Subnet.ID} + } + } + } + } + } + } + + return ret +} + +func (self *SLoadbalancer) GetNetworkIds() []string { + return self.getNetworkIds() +} + +func (self *SLoadbalancer) GetVpcId() string { + if self.Type == "Microsoft.Network/loadBalancers" { + subnets := self.GetNetworkIds() + if len(subnets) == 0 { + subnets = self.getLbbgNetworkIds() + } + + if len(subnets) > 0 { + network, err := self.region.GetNetwork(subnets[0]) + if network != nil { + return strings.Split(network.GetId(), "/subnets")[0] + } + + log.Errorf("GetNetwork %s: %s", subnets[0], err) + } + } else { + gips := self.Properties.GatewayIPConfigurations + for i := range gips { + netId := gips[i].Properties.Subnet.ID + if len(netId) > 0 { + network, err := self.region.GetNetwork(netId) + if network != nil { + return strings.Split(network.GetId(), "/subnets")[0] + } + log.Errorf("GetNetwork %s: %s", netId, err) + } + } + } + + return "" +} + +func (self *SLoadbalancer) GetZoneId() string { + ips := self.Properties.FrontendIPConfigurations + if len(ips) > 0 && len(ips[0].Zones) > 0 { + return ips[0].Zones[0] + } + + return "" +} + +func (self *SLoadbalancer) GetZone1Id() string { + ips := self.Properties.FrontendIPConfigurations + if len(ips) > 0 && len(ips[0].Zones) > 1 { + return ips[0].Zones[1] + } + + return "" +} + +func (self *SLoadbalancer) GetLoadbalancerSpec() string { + if len(self.Properties.Sku.Name) > 0 { + return self.Properties.Sku.Name + } + + if len(self.Sku.Name) > 0 { + return self.Sku.Name + } + return "" +} + +func (self *SLoadbalancer) GetChargeType() string { + return api.LB_CHARGE_TYPE_BY_TRAFFIC +} + +func (self *SLoadbalancer) GetEgressMbps() int { + return 0 +} + +func (self *SLoadbalancer) getEipIds() []string { + ret := []string{} + for _, fip := range self.Properties.FrontendIPConfigurations { + eip := fip.Properties.PublicIPAddress + if eip != nil && len(eip.ID) > 0 { + ret = append(ret, eip.ID) + continue + } + } + + return ret +} + +func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { + ieips, err := self.GetIEIPS() + if err != nil { + return nil, errors.Wrap(err, "GetIEIPS") + } + + if len(ieips) > 0 { + return self.eips[0], nil + } + + return nil, nil +} + +func (self *SLoadbalancer) GetIEIPById(eipId string) (cloudprovider.ICloudEIP, error) { + ieips, err := self.GetIEIPS() + if err != nil { + return nil, errors.Wrap(err, "GetIEIPS") + } + + for i := range ieips { + if ieips[i].GetId() == eipId { + return ieips[i], nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, eipId) +} + +func (self *SLoadbalancer) GetIEIPS() ([]cloudprovider.ICloudEIP, error) { + if self.eips != nil { + return self.eips, nil + } + + eips := self.getEipIds() + ieips := make([]cloudprovider.ICloudEIP, 0) + for i := range eips { + ieip, err := self.region.GetIEipById(eips[i]) + if err != nil { + return nil, errors.Wrap(err, "GetIEIP") + } + ieips = append(ieips, ieip) + } + + if len(ieips) > 0 { + self.eips = ieips + } + + return self.eips, nil +} + +func (self *SLoadbalancer) Delete(ctx context.Context) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Delete") +} + +func (self *SLoadbalancer) Start() error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Start") +} + +func (self *SLoadbalancer) Stop() error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Stop") +} + +/* +应用型LB: urlPathMaps(defaultBackendAddressPool+defaultBackendHttpSettings+requestRoutingRules+httpListeners)= Onecloud监听器 +4层LB: loadBalancingRules(前端) = Onecloud监听器 +*/ +func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + if self.listeners != nil { + return self.listeners, nil + } + + var err error + if self.Type == "Microsoft.Network/applicationGateways" { + self.listeners, err = self.getAppLBListeners() + } else { + self.listeners, err = self.getNetworkLBListeners() + } + + return self.listeners, err +} + +func (self *SLoadbalancer) getFrontendIPConfiguration(id string) *FrontendIPConfiguration { + fips := self.Properties.FrontendIPConfigurations + for i := range fips { + if fips[i].ID == id { + return &fips[i] + } + } + log.Debugf("getFrontendIPConfiguration %s not found", id) + return nil +} + +func (self *SLoadbalancer) getHttpListener(id string) *HTTPListener { + ss := self.Properties.HTTPListeners + for i := range ss { + if ss[i].ID == id { + return &ss[i] + } + + for j := range ss[i].Properties.RequestRoutingRules { + if ss[i].Properties.RequestRoutingRules[j].ID == id { + return &ss[i] + } + } + } + log.Debugf("getHttpListener %s not found", id) + return nil +} + +func (self *SLoadbalancer) getBackendAddressPool(id string) *BackendAddressPool { + ss := self.Properties.BackendAddressPools + for i := range ss { + if ss[i].ID == id { + return &ss[i] + } + } + log.Debugf("getBackendAddressPool %s not found", id) + return nil +} + +func (self *SLoadbalancer) getBackendHTTPSettingsCollection(id string) *BackendHTTPSettingsCollection { + ss := self.Properties.BackendHTTPSettingsCollection + for i := range ss { + if ss[i].ID == id { + return &ss[i] + } + } + log.Debugf("getBackendHTTPSettingsCollection %s not found", id) + return nil +} + +func (self *SLoadbalancer) getRedirectConfiguration(id string) *RedirectConfiguration { + ss := self.Properties.RedirectConfigurations + for i := range ss { + if ss[i].ID == id { + return &ss[i] + } + } + log.Debugf("getRedirectConfiguration %s not found", id) + return nil +} + +func (self *SLoadbalancer) getProbe(id string) *Probe { + ss := self.Properties.Probes + for i := range ss { + if ss[i].ID == id { + return &ss[i] + } + } + log.Debugf("getProbe %s not found", id) + return nil +} + +func (self *SLoadbalancer) getFrontendPort(id string) *FrontendPort { + ss := self.Properties.FrontendPorts + for i := range ss { + if ss[i].ID == id { + return &ss[i] + } + } + log.Debugf("getFrontendPort %s not found", id) + return nil +} + +func (self *SLoadbalancer) getRequestRoutingRule(id string) *RequestRoutingRule { + ss := self.Properties.RequestRoutingRules + for i := range ss { + if ss[i].ID == id { + return &ss[i] + } + } + log.Debugf("getRequestRoutingRule %s not found", id) + return nil +} + +func (self *SLoadbalancer) getURLPathMap(id string) *URLPathMap { + ss := self.Properties.URLPathMaps + for i := range ss { + if ss[i].ID == id { + return &ss[i] + } + } + log.Debugf("getURLPathMap %s not found", id) + return nil +} + +/* +应用型LB: urlPathMaps(defaultBackendAddressPool+defaultBackendHttpSettings+requestRoutingRules+httpListeners)= Onecloud监听器 +*/ +func (self *SLoadbalancer) getAppLBListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + lbls := []cloudprovider.ICloudLoadbalancerListener{} + for i := range self.Properties.RequestRoutingRules { + r := self.Properties.RequestRoutingRules[i] + uid := strings.Replace(r.ID, "requestRoutingRules", "urlPathMaps", 1) + u := self.getURLPathMap(uid) + lbl := self.getAppLBListener(&r, u) + if lbl != nil { + lbls = append(lbls, lbl) + } + } + + return lbls, nil +} + +func (self *SLoadbalancer) getAppLBListener(r *RequestRoutingRule, u *URLPathMap) *SLoadBalancerListener { + var redirect *RedirectConfiguration + var listener *HTTPListener + var fp *FrontendIPConfiguration + var fpp *FrontendPort + // frontendPort, frontendIPConfiguration, sslCertificate, requestRoutingRules + listener = self.getHttpListener(r.Properties.HTTPListener.ID) + // frontendPorts + fp = self.getFrontendIPConfiguration(listener.Properties.FrontendIPConfiguration.ID) + fpp = self.getFrontendPort(listener.Properties.FrontendPort.ID) + // 配置有异常?? + if fpp == nil || listener == nil { + return nil + } + + lbbgId := r.Properties.BackendAddressPool.ID + lbbgSettingId := r.Properties.BackendHTTPSettings.ID + provisioningState := "Succeeded" + rules := make([]PathRule, 0) + var backendGroup *BackendAddressPool + var backendSetting *BackendHTTPSettingsCollection + var backendPort int + var healthcheck *Probe + if u != nil { + provisioningState = u.Properties.ProvisioningState + rules = u.Properties.PathRules + if u.Properties.DefaultRedirectConfiguration != nil { + redirect = self.getRedirectConfiguration(u.Properties.DefaultRedirectConfiguration.ID) + } + + if len(lbbgId) == 0 && u.Properties.DefaultBackendAddressPool != nil { + lbbgId = u.Properties.DefaultBackendAddressPool.ID + } + + if len(lbbgSettingId) == 0 && u.Properties.DefaultBackendHTTPSettings != nil { + lbbgSettingId = u.Properties.DefaultBackendHTTPSettings.ID + } + } + + if len(lbbgId) > 0 { + backendGroup = self.getBackendAddressPool(lbbgId) + } + + if len(lbbgSettingId) > 0 { + backendSetting = self.getBackendHTTPSettingsCollection(lbbgSettingId) + backendPort = backendSetting.Properties.Port + } + + if backendSetting != nil && backendSetting.Properties.Probe != nil { + healthcheck = self.getProbe(backendSetting.Properties.Probe.ID) + } + + return &SLoadBalancerListener{ + lb: self, + fp: fp, + listener: listener, + backendSetting: backendSetting, + backendGroup: backendGroup, + redirect: redirect, + healthcheck: healthcheck, + Name: r.Name, + ID: r.ID, + ProvisioningState: provisioningState, + IPVersion: "", + Protocol: listener.Properties.Protocol, + LoadDistribution: "", + FrontendPort: fpp.Properties.Port, + BackendPort: backendPort, + ClientIdleTimeout: 0, + EnableFloatingIP: false, + EnableTcpReset: false, + rules: rules, + } +} + +func (self *SLoadbalancer) getNetworkLBListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + lbls := []cloudprovider.ICloudLoadbalancerListener{} + for i := range self.Properties.LoadBalancingRules { + u := self.Properties.LoadBalancingRules[i] + lbl := self.getNetworkLBListener(&u) + lbls = append(lbls, &lbl) + } + + return lbls, nil +} + +func (self *SLoadbalancer) getNetworkLBListener(u *LoadBalancingRule) SLoadBalancerListener { + fp := self.getFrontendIPConfiguration(u.Properties.FrontendIPConfiguration.ID) + backendGroup := self.getBackendAddressPool(u.Properties.BackendAddressPool.ID) + healthcheck := self.getProbe(u.Properties.Probe.ID) + + return SLoadBalancerListener{ + lb: self, + fp: fp, + backendGroup: backendGroup, + healthcheck: healthcheck, + Name: u.Name, + ID: u.ID, + ProvisioningState: u.Properties.ProvisioningState, + IPVersion: "", + Protocol: u.Properties.Protocol, + LoadDistribution: u.Properties.LoadDistribution, + FrontendPort: u.Properties.FrontendPort, + BackendPort: u.Properties.BackendPort, + ClientIdleTimeout: u.Properties.IdleTimeoutInMinutes * 60, + EnableFloatingIP: u.Properties.EnableFloatingIP, + EnableTcpReset: u.Properties.EnableTCPReset, + } +} + +// 应用型LB: HTTP 设置 + 后端池 = onecloud 后端服务器组 +// 4层LB: loadBalancingRules(backendPort)+ 后端池 = onecloud 后端服务器组 +func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + if self.lbbgs != nil { + return self.lbbgs, nil + } + + lbls, err := self.GetILoadBalancerListeners() + if err != nil { + return nil, errors.Wrap(err, "GetILoadBalancerListeners") + } + + bgIds := []string{} + ilbbgs := []cloudprovider.ICloudLoadbalancerBackendGroup{} + for i := range lbls { + lbl := lbls[i].(*SLoadBalancerListener) + if lbl.backendGroup == nil { + continue + } + + bg := SLoadbalancerBackendGroup{ + lb: self, + Pool: *lbl.backendGroup, + DefaultPort: lbl.BackendPort, + HttpSettings: lbl.backendSetting, + BackendIps: lbl.backendGroup.Properties.BackendIPConfigurations, + } + + if !utils.IsInStringArray(bg.GetId(), bgIds) { + bgIds = append(bgIds, bg.GetId()) + ilbbgs = append(ilbbgs, &bg) + } + + // sync rules lbbg + if utils.IsInStringArray(lbl.GetListenerType(), []string{api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS}) { + rules, err := lbl.GetILoadbalancerListenerRules() + if err != nil { + return nil, errors.Wrap(err, "GetILoadbalancerListenerRules") + } + + for j := range rules { + rule := rules[j].(*SLoadbalancerListenerRule) + if rule.lbbg != nil && !utils.IsInStringArray(rule.lbbg.GetId(), bgIds) { + bgIds = append(bgIds, bg.GetId()) + ilbbgs = append(ilbbgs, &bg) + } + } + } + } + + self.lbbgs = ilbbgs + return ilbbgs, nil +} + +func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + lbbgs, err := self.GetILoadBalancerBackendGroups() + if err != nil { + return nil, errors.Wrap(err, "GetILoadBalancerBackendGroups") + } + + for i := range lbbgs { + if lbbgs[i].GetId() == groupId { + return lbbgs[i], nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerBackendGroupById") +} + +func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "CreateILoadBalancerBackendGroup") +} + +func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "CreateILoadBalancerListener") +} + +func (self *SLoadbalancer) getNetworkLBListenerById(id string) (cloudprovider.ICloudLoadbalancerListener, error) { + for i := range self.Properties.LoadBalancingRules { + u := self.Properties.LoadBalancingRules[i] + if u.ID == id { + lbl := self.getNetworkLBListener(&u) + return &lbl, nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "getNetworkLBListenerById") +} + +func (self *SLoadbalancer) getAppLBListenerById(id string) (cloudprovider.ICloudLoadbalancerListener, error) { + for i := range self.Properties.RequestRoutingRules { + r := self.Properties.RequestRoutingRules[i] + if r.ID == id { + u := self.getURLPathMap(strings.Replace(r.ID, "requestRoutingRules", "urlPathMaps", 1)) + return self.getAppLBListener(&r, u), nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "getAppLBListenerById") +} + +func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { + if self.Type == "Microsoft.Network/applicationGateways" { + return self.getAppLBListenerById(listenerId) + } else { + return self.getNetworkLBListenerById(listenerId) + } +} + +func (self *SLoadbalancer) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + icerts := []cloudprovider.ICloudLoadbalancerCertificate{} + ssl := self.Properties.SSLCertificates + for i := range ssl { + s := ssl[i] + cert := SLoadbalancerCert{ + lb: self, + Name: s.Name, + ID: s.ID, + PublicKey: s.Properties.PublicCertData, + } + + icerts = append(icerts, &cert) + } + + return icerts, nil +} + +func (self *SLoadbalancer) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + ssl := self.Properties.SSLCertificates + for i := range ssl { + s := ssl[i] + if s.ID == certId { + return &SLoadbalancerCert{ + lb: self, + Name: s.Name, + ID: s.ID, + PublicKey: s.Properties.PublicCertData, + }, nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerCertificateById") +} diff --git a/pkg/multicloud/azure/loadbalancer_props.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancer_props.go similarity index 100% rename from pkg/multicloud/azure/loadbalancer_props.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancer_props.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerbackend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerbackend.go new file mode 100644 index 0000000000..60fd15dfc7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerbackend.go @@ -0,0 +1,99 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "context" + "strconv" + "strings" + + "github.com/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerBackend struct { + multicloud.SResourceBase + + lbbg *SLoadbalancerBackendGroup + // networkInterfaces 通过接口地址反查虚拟机地址 + Name string `json:"name"` + ID string `json:"id"` + Type string `json:"type"` + BackendPort int + BackendIP string +} + +func (self *SLoadbalancerBackend) GetId() string { + return self.ID + "::" + strconv.Itoa(self.BackendPort) +} + +func (self *SLoadbalancerBackend) GetName() string { + return self.Name +} + +func (self *SLoadbalancerBackend) GetGlobalId() string { + return strings.ToLower(self.GetId()) +} + +func (self *SLoadbalancerBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancerBackend) GetSysTags() map[string]string { + return nil +} + +func (self *SLoadbalancerBackend) GetTags() (map[string]string, error) { + return nil, nil +} + +func (self *SLoadbalancerBackend) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} + +func (self *SLoadbalancerBackend) GetProjectId() string { + return getResourceGroup(self.ID) +} + +func (self *SLoadbalancerBackend) GetWeight() int { + return 0 +} + +func (self *SLoadbalancerBackend) GetPort() int { + return self.BackendPort +} + +func (self *SLoadbalancerBackend) GetBackendType() string { + return self.Type +} + +func (self *SLoadbalancerBackend) GetBackendRole() string { + return api.LB_BACKEND_ROLE_DEFAULT +} + +func (self *SLoadbalancerBackend) GetBackendId() string { + return self.ID +} + +func (self *SLoadbalancerBackend) GetIpAddress() string { + return self.BackendIP +} + +func (self *SLoadbalancerBackend) SyncConf(ctx context.Context, port, weight int) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SyncConf") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerbackendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerbackendgroup.go new file mode 100644 index 0000000000..14204ca17c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerbackendgroup.go @@ -0,0 +1,221 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "context" + "fmt" + "strconv" + "strings" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// todo: 虚拟机规模集不支持 +// 注: 因为与onecloud后端服务器组存在配置差异,不支持同步未关联的后端服务器组 +// 应用型LB: HTTP 设置 + 后端池 = onecloud 后端服务器组 +// 4层LB: loadBalancingRules(backendPort)+ 后端池 = onecloud 后端服务器组 +type SLoadbalancerBackendGroup struct { + multicloud.SResourceBase + lb *SLoadbalancer + lbbs []cloudprovider.ICloudLoadbalancerBackend + + Pool BackendAddressPool + DefaultPort int + HttpSettings *BackendHTTPSettingsCollection + + BackendIps []BackendIPConfiguration +} + +func (self *SLoadbalancerBackendGroup) GetId() string { + return self.Pool.ID + "::" + strconv.Itoa(self.DefaultPort) +} + +func (self *SLoadbalancerBackendGroup) GetName() string { + if self.HttpSettings != nil { + return self.Pool.Name + "::" + self.HttpSettings.Name + } + + return self.Pool.Name + "::" + strconv.Itoa(self.DefaultPort) +} + +func (self *SLoadbalancerBackendGroup) GetGlobalId() string { + return strings.ToLower(self.GetId()) +} + +func (self *SLoadbalancerBackendGroup) GetStatus() string { + switch self.Pool.Properties.ProvisioningState { + case "Succeeded": + return api.LB_STATUS_ENABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (self *SLoadbalancerBackendGroup) Refresh() error { + lbbg, err := self.lb.GetILoadBalancerBackendGroupById(self.GetId()) + if err != nil { + return errors.Wrap(err, "GetILoadBalancerBackendGroupById") + } + + err = jsonutils.Update(self, lbbg) + if err != nil { + return errors.Wrap(err, "refresh.Update") + } + + self.lbbs = nil + return nil +} + +func (self *SLoadbalancerBackendGroup) IsEmulated() bool { + return true +} + +func (self *SLoadbalancerBackendGroup) GetSysTags() map[string]string { + return nil +} + +func (self *SLoadbalancerBackendGroup) GetTags() (map[string]string, error) { + return map[string]string{}, nil +} + +func (self *SLoadbalancerBackendGroup) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} + +func (self *SLoadbalancerBackendGroup) GetProjectId() string { + return getResourceGroup(self.GetId()) +} + +func (self *SLoadbalancerBackendGroup) IsDefault() bool { + return false +} + +func (self *SLoadbalancerBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_NORMAL +} + +func (self *SLoadbalancerBackendGroup) GetLoadbalancerId() string { + return self.lb.GetId() +} + +func (self *SLoadbalancerBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + if self.lbbs != nil { + return self.lbbs, nil + } + + var ret []cloudprovider.ICloudLoadbalancerBackend + ips := self.Pool.Properties.BackendIPConfigurations + for i := range ips { + ip := ips[i] + nic, err := self.lb.region.GetNetworkInterface(strings.Split(ip.ID, "/ipConfigurations")[0]) + if err != nil { + return nil, errors.Wrap(err, "GetNetworkInterface") + } + + if len(nic.Properties.VirtualMachine.ID) == 0 { + continue + } + + name := nic.Properties.VirtualMachine.Name + vid := nic.Properties.VirtualMachine.ID + if len(name) == 0 && len(vid) > 0 { + segs := strings.Split(vid, "/virtualMachines/") + name = segs[len(segs)-1] + } + bg := SLoadbalancerBackend{ + SResourceBase: multicloud.SResourceBase{}, + lbbg: self, + Name: name, + ID: vid, + Type: api.LB_BACKEND_GUEST, + BackendPort: self.DefaultPort, + } + + ret = append(ret, &bg) + } + + ips2 := self.Pool.Properties.BackendAddresses + for i := range ips2 { + name := fmt.Sprintf("ip-%s", ips2[i].IPAddress) + bg := SLoadbalancerBackend{ + SResourceBase: multicloud.SResourceBase{}, + lbbg: self, + Name: name, + ID: fmt.Sprintf("%s-%s", self.GetId(), name), + Type: api.LB_BACKEND_IP, + BackendIP: ips2[i].IPAddress, + BackendPort: self.DefaultPort, + } + + ret = append(ret, &bg) + } + + self.lbbs = ret + return ret, nil +} + +func (self *SLoadbalancerBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + lbbs, err := self.GetILoadbalancerBackends() + if err != nil { + return nil, errors.Wrap(err, "GetILoadbalancerBackends") + } + + for i := range lbbs { + if lbbs[i].GetId() == backendId { + return lbbs[i], nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadbalancerBackendById") +} + +func (self *SLoadbalancerBackendGroup) GetProtocolType() string { + return "" +} + +func (self *SLoadbalancerBackendGroup) GetScheduler() string { + return "" +} + +func (self *SLoadbalancerBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + return nil, nil +} + +func (self *SLoadbalancerBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + return nil, nil +} + +func (self *SLoadbalancerBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "AddBackendServer") +} + +func (self *SLoadbalancerBackendGroup) RemoveBackendServer(serverId string, weight int, port int) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "RemoveBackendServer") +} + +func (self *SLoadbalancerBackendGroup) Delete(ctx context.Context) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Delete") +} + +func (self *SLoadbalancerBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Sync") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancercert.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancercert.go new file mode 100644 index 0000000000..78a3447868 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancercert.go @@ -0,0 +1,183 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "bytes" + "crypto/sha1" + "crypto/x509" + "encoding/pem" + "fmt" + "strings" + "time" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerCert struct { + multicloud.SResourceBase + lb *SLoadbalancer + cert *x509.Certificate + Name string `json:"name"` + ID string `json:"id"` + PublicKey string `json:"public_key"` +} + +func (self *SLoadbalancerCert) GetId() string { + return self.ID +} + +func (self *SLoadbalancerCert) GetName() string { + return self.Name +} + +func (self *SLoadbalancerCert) GetGlobalId() string { + return strings.ToLower(self.GetId()) +} + +func (self *SLoadbalancerCert) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancerCert) Refresh() error { + cert, err := self.lb.GetILoadBalancerCertificateById(self.GetId()) + if err != nil { + return errors.Wrap(err, "GetILoadBalancerCertificateById") + } + + err = jsonutils.Update(self, cert) + if err != nil { + return errors.Wrap(err, "Update") + } + + return nil +} + +func (self *SLoadbalancerCert) IsEmulated() bool { + return false +} + +func (self *SLoadbalancerCert) GetSysTags() map[string]string { + return nil +} + +func (self *SLoadbalancerCert) GetTags() (map[string]string, error) { + return nil, nil +} + +func (self *SLoadbalancerCert) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} + +func (self *SLoadbalancerCert) GetProjectId() string { + return getResourceGroup(self.GetId()) +} + +func (self *SLoadbalancerCert) Sync(name, privateKey, publickKey string) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Sync") +} + +func (self *SLoadbalancerCert) Delete() error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Delete") +} + +func (self *SLoadbalancerCert) ParsePublicKey() (*x509.Certificate, error) { + if self.cert != nil { + return self.cert, nil + } + + publicKey := self.GetPublickKey() + if len(publicKey) == 0 { + return nil, fmt.Errorf("SElbCertificate ParsePublicKey public key is empty") + } + + block, _ := pem.Decode([]byte(publicKey)) + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, errors.Wrap(err, "ParseCertificate") + } + + self.cert = cert + return cert, nil +} + +func (self *SLoadbalancerCert) GetCommonName() string { + cert, err := self.ParsePublicKey() + if err != nil { + return "" + } + + return cert.Issuer.CommonName +} + +func (self *SLoadbalancerCert) GetSubjectAlternativeNames() string { + _, err := self.ParsePublicKey() + if err != nil { + return "" + } + + return "" +} + +func (self *SLoadbalancerCert) GetFingerprint() string { + publicKey := self.GetPublickKey() + if len(publicKey) == 0 { + return "" + } + + _fp := sha1.Sum([]byte(publicKey)) + fp := fmt.Sprintf("sha1:% x", _fp) + return strings.Replace(fp, " ", ":", -1) +} + +func (self *SLoadbalancerCert) GetExpireTime() time.Time { + cert, err := self.ParsePublicKey() + if err != nil { + return time.Time{} + } + + return cert.NotAfter +} + +func (self *SLoadbalancerCert) GetPublickKey() string { + if len(self.PublicKey) > 0 { + var pk bytes.Buffer + pk.WriteString("-----BEGIN CERTIFICATE-----\r\n") + content := bytes.NewBufferString(self.PublicKey) + for { + l := content.Next(64) + if len(l) == 64 { + pk.WriteString(fmt.Sprintf("%s\r\n", l)) + } else { + pk.WriteString(fmt.Sprintf("%s\r\n", l)) + break + } + } + pk.WriteString("-----END CERTIFICATE-----") + return pk.String() + } + + return "" +} + +func (self *SLoadbalancerCert) GetPrivateKey() string { + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerlistener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerlistener.go new file mode 100644 index 0000000000..6842aa2fb7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerlistener.go @@ -0,0 +1,600 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "context" + "net/url" + "regexp" + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// todo: 目前不支持 入站 NAT 规则 +// todo: HTTP 设置(端口+协议,其余信息丢弃) + 后端池 = onecloud 路径的路由 的 onecloud 后端服务器组 +/* +应用型LB: urlPathMaps(defaultBackendAddressPool+defaultBackendHttpSettings+requestRoutingRules+httpListeners)= Onecloud监听器 +4层LB: loadBalancingRules(前端) = Onecloud监听器 +*/ +type SLoadBalancerListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + + lb *SLoadbalancer + lbrs []cloudprovider.ICloudLoadbalancerListenerRule + + /* + IPVersion string + FrontendIP string // 前端IP + FrontendIPId string // 前端IP ID + */ + fp *FrontendIPConfiguration + + /* + Protocol string // 监听协议 + HostName string // 监听器 监听域名 + FrontendPort int // 前端端口 + */ + listener *HTTPListener + + /* + Protocol string // 后端协议 + BackendPort int // 后端端口 + IdleTimeoutInMinutes int // 空闲超时(分钟) + LoadDistribution string // 会话保持方法SourceIP|SourceIPProtocol + CookieBasedAffinity string // cookies 关联 + CookieName string // cookie 名称 + EnabledConnectionDraining bool // 排出超时这应用于通过 API 调用从后端池明确删除的后端实例,以及运行状况探测报告的运行不正常的实例。 + ConnectionDrainingSec int // 排出超时时长(秒) + RequestTimeout int // 请求超时时间(秒) + probe // 健康检查 + */ + backendSetting *BackendHTTPSettingsCollection + + // + backendGroup *BackendAddressPool + + /* + redirectType string // 重定向类型 + targetListener // 重定向到监听 + */ + redirect *RedirectConfiguration + + /* + "protocol": "Http", + "host": "baidu.com", + "path": "/test", + "interval": 30, + "timeout": 30, + "unhealthyThreshold": 3, + "pickHostNameFromBackendHttpSettings": false, + "minServers": 0, + "match": { + "body": "500", + "statusCodes": [ + "200-399" + ] + }, + */ + healthcheck *Probe + + Name string + ID string + ProvisioningState string + IPVersion string + Protocol string // 监听协议 + LoadDistribution string // 调度算法 + FrontendPort int // 前端端口 + BackendPort int // 后端端口 + ClientIdleTimeout int // 客户端连接超时 + EnableFloatingIP bool // 浮动 IP + EnableTcpReset bool + + rules []PathRule +} + +func (self *SLoadBalancerListener) GetId() string { + return self.ID +} + +func (self *SLoadBalancerListener) GetName() string { + return self.Name +} + +func (self *SLoadBalancerListener) GetGlobalId() string { + return strings.ToLower(self.GetId()) +} + +func (self *SLoadBalancerListener) GetStatus() string { + switch self.ProvisioningState { + case "Succeeded", "Updating", "Deleting": + return api.LB_STATUS_ENABLED + case "Failed": + return api.LB_STATUS_DISABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (self *SLoadBalancerListener) Refresh() error { + lbl, err := self.lb.GetILoadBalancerListenerById(self.GetId()) + if err != nil { + return errors.Wrap(err, "GetILoadBalancerListenerById") + } + + err = jsonutils.Update(self, lbl) + if err != nil { + return errors.Wrap(err, "refresh.Update") + } + + self.lbrs = nil + return nil +} + +func (self *SLoadBalancerListener) IsEmulated() bool { + return false +} + +func (self *SLoadBalancerListener) GetSysTags() map[string]string { + return nil +} + +func (self *SLoadBalancerListener) GetTags() (map[string]string, error) { + if self.fp != nil { + if self.fp.Properties.PublicIPAddress != nil && len(self.fp.Properties.PublicIPAddress.ID) > 0 { + eip, _ := self.lb.GetIEIPById(self.fp.Properties.PublicIPAddress.ID) + if eip != nil { + return map[string]string{"FrontendIP": eip.GetIpAddr()}, nil + } + } + + if len(self.fp.Properties.PrivateIPAddress) > 0 { + return map[string]string{"FrontendIP": self.fp.Properties.PrivateIPAddress}, nil + } + } + + return map[string]string{}, nil +} + +func (self *SLoadBalancerListener) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} + +func (self *SLoadBalancerListener) GetProjectId() string { + return getResourceGroup(self.GetId()) +} + +func (self *SLoadBalancerListener) GetListenerType() string { + switch strings.ToLower(self.Protocol) { + case "tcp": + return api.LB_LISTENER_TYPE_TCP + case "udp": + return api.LB_LISTENER_TYPE_UDP + case "http": + return api.LB_LISTENER_TYPE_HTTP + case "https": + return api.LB_LISTENER_TYPE_HTTPS + default: + return "" + } +} + +func (self *SLoadBalancerListener) GetListenerPort() int { + return int(self.FrontendPort) +} + +func (self *SLoadBalancerListener) GetScheduler() string { + switch self.LoadDistribution { + case "SourceIPProtocol", "SourceIP": + return api.LB_SCHEDULER_SCH + default: + return "" + } +} + +func (self *SLoadBalancerListener) GetAclStatus() string { + return api.LB_BOOL_OFF +} + +func (self *SLoadBalancerListener) GetAclType() string { + return "" +} + +func (self *SLoadBalancerListener) GetAclId() string { + return "" +} + +func (self *SLoadBalancerListener) GetEgressMbps() int { + return 0 +} + +func (self *SLoadBalancerListener) GetHealthCheck() string { + // if self.probe != nil + if self.healthcheck != nil { + return api.LB_BOOL_ON + } + + return api.LB_BOOL_OFF +} + +func (self *SLoadBalancerListener) GetHealthCheckType() string { + if self.healthcheck == nil { + return "" + } + switch strings.ToLower(self.healthcheck.Properties.Protocol) { + case "tcp": + return api.LB_HEALTH_CHECK_TCP + case "udp": + return api.LB_HEALTH_CHECK_UDP + case "http": + return api.LB_HEALTH_CHECK_HTTP + case "https": + return api.LB_HEALTH_CHECK_HTTPS + default: + return "" + } +} + +func (self *SLoadBalancerListener) GetHealthCheckTimeout() int { + if self.healthcheck == nil { + return 0 + } + switch self.GetHealthCheckType() { + case api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS: + return self.healthcheck.Properties.Timeout + } + + return self.healthcheck.Properties.IntervalInSeconds +} + +func (self *SLoadBalancerListener) GetHealthCheckInterval() int { + if self.healthcheck == nil { + return 0 + } + switch self.GetHealthCheckType() { + case api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS: + if self.healthcheck.Properties.Interval > 0 { + return self.healthcheck.Properties.Interval + } + } + + return self.healthcheck.Properties.IntervalInSeconds +} + +func (self *SLoadBalancerListener) GetHealthCheckRise() int { + return 0 +} + +func (self *SLoadBalancerListener) GetHealthCheckFail() int { + if self.healthcheck == nil { + return 0 + } + switch self.GetHealthCheckType() { + case api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS: + if self.healthcheck.Properties.UnhealthyThreshold > 0 { + return self.healthcheck.Properties.UnhealthyThreshold + } + } + + return self.healthcheck.Properties.NumberOfProbes +} + +func (self *SLoadBalancerListener) GetHealthCheckReq() string { + return "" +} + +func (self *SLoadBalancerListener) GetHealthCheckExp() string { + return "" +} + +func (self *SLoadBalancerListener) GetBackendGroupId() string { + if self.backendGroup != nil { + return self.backendGroup.ID + "::" + strconv.Itoa(self.BackendPort) + } + + return "" +} + +func (self *SLoadBalancerListener) GetBackendServerPort() int { + return self.BackendPort +} + +func (self *SLoadBalancerListener) GetHealthCheckDomain() string { + if self.healthcheck == nil { + return "" + } + switch self.GetHealthCheckType() { + case api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS: + return self.healthcheck.Properties.Host + } + + return "" +} + +func (self *SLoadBalancerListener) GetHealthCheckURI() string { + if self.healthcheck == nil { + return "" + } + switch self.GetHealthCheckType() { + case api.LB_HEALTH_CHECK_HTTP, api.LB_HEALTH_CHECK_HTTPS: + return self.healthcheck.Properties.Path + } + + return "" +} + +/* +todo: 和onecloud code不兼容? +与此处输入的 HTTP 状态代码或代码范围相匹配的响应将被视为成功。请输入逗号分隔的代码列表(例如 200, 201)或者输入一个代码范围(例如 220-226) +*/ +func (self *SLoadBalancerListener) GetHealthCheckCode() string { + return "" +} + +func (self *SLoadBalancerListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "CreateILoadBalancerListenerRule") +} + +func (self *SLoadBalancerListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + lbrs, err := self.GetILoadbalancerListenerRules() + if err != nil { + return nil, errors.Wrap(err, "GetILoadbalancerListenerRules") + } + + for i := range lbrs { + if lbrs[i].GetId() == ruleId { + return lbrs[i], nil + } + } + + return nil, errors.Wrap(err, "GetILoadBalancerListenerRuleById") +} + +func (self *SLoadBalancerListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + if self.lbrs != nil { + return self.lbrs, nil + } + + irules := []cloudprovider.ICloudLoadbalancerListenerRule{} + for i := range self.rules { + r := self.rules[i] + var redirect *RedirectConfiguration + var lbbg *SLoadbalancerBackendGroup + if r.Properties.RedirectConfiguration != nil { + redirect = self.lb.getRedirectConfiguration(r.Properties.RedirectConfiguration.ID) + } else { + if r.Properties.BackendAddressPool == nil || r.Properties.BackendHTTPSettings == nil { + continue + } + + pool := self.lb.getBackendAddressPool(r.Properties.BackendAddressPool.ID) + if pool == nil { + log.Debugf("getBackendAddressPool %s not found", r.Properties.BackendAddressPool.ID) + continue + } + backsetting := self.lb.getBackendHTTPSettingsCollection(r.Properties.BackendHTTPSettings.ID) + if backsetting == nil { + log.Debugf("getBackendHTTPSettingsCollection %s not found", r.Properties.BackendHTTPSettings.ID) + continue + } + + lbbg = &SLoadbalancerBackendGroup{ + lb: self.lb, + Pool: *pool, + DefaultPort: backsetting.Properties.Port, + HttpSettings: backsetting, + BackendIps: pool.Properties.BackendIPConfigurations, + } + } + + domain := "" + if self.listener != nil { + domain = self.listener.Properties.HostName + } + + rule := SLoadbalancerListenerRule{ + SResourceBase: multicloud.SResourceBase{}, + listener: self, + lbbg: lbbg, + redirect: redirect, + Name: r.Name, + ID: r.ID, + Domain: domain, + Properties: r.Properties, + } + irules = append(irules, &rule) + } + + return irules, nil +} + +func (self *SLoadBalancerListener) GetStickySession() string { + if self.backendSetting == nil { + return api.LB_BOOL_OFF + } + + if self.backendSetting.Properties.CookieBasedAffinity == "Enabled" { + return api.LB_BOOL_ON + } else { + return api.LB_BOOL_OFF + } +} + +func (self *SLoadBalancerListener) GetStickySessionType() string { + if self.GetStickySession() == api.LB_BOOL_ON { + return api.LB_STICKY_SESSION_TYPE_INSERT + } + return "" +} + +func (self *SLoadBalancerListener) GetStickySessionCookie() string { + if self.backendSetting == nil { + return "" + } + + return self.backendSetting.Properties.AffinityCookieName +} + +func (self *SLoadBalancerListener) GetStickySessionCookieTimeout() int { + if self.backendSetting == nil { + return 0 + } + + if self.backendSetting.Properties.ConnectionDraining.Enabled { + _sec := strings.TrimSpace(self.backendSetting.Properties.ConnectionDraining.DrainTimeoutInSEC) + sec, _ := strconv.ParseInt(_sec, 10, 64) + return int(sec) + } + + return 0 +} + +func (self *SLoadBalancerListener) XForwardedForEnabled() bool { + return false +} + +func (self *SLoadBalancerListener) GzipEnabled() bool { + return false +} + +func (self *SLoadBalancerListener) GetCertificateId() string { + if self.listener != nil { + return self.listener.Properties.SSLCertificate.ID + } + + return "" +} + +func (self *SLoadBalancerListener) GetTLSCipherPolicy() string { + return "" +} + +func (self *SLoadBalancerListener) HTTP2Enabled() bool { + return self.lb.Properties.EnableHttp2 +} + +func (self *SLoadBalancerListener) Start() error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Start") +} + +func (self *SLoadBalancerListener) Stop() error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Stop") +} + +func (self *SLoadBalancerListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Sync") +} + +func (self *SLoadBalancerListener) Delete(ctx context.Context) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Delete") +} + +func (self *SLoadBalancerListener) GetRedirect() string { + if self.redirect != nil { + return api.LB_REDIRECT_RAW + } + + return api.LB_REDIRECT_OFF +} + +func (self *SLoadBalancerListener) GetRedirectCode() int64 { + if self.redirect == nil { + return 0 + } + + switch self.redirect.Properties.RedirectType { + case "Permanent": + return api.LB_REDIRECT_CODE_301 + case "Found": + return api.LB_REDIRECT_CODE_302 + case "Temporary", "SeeOther": + return api.LB_REDIRECT_CODE_307 + default: + return 0 + } +} + +func (self *SLoadBalancerListener) getRedirectUrl() *url.URL { + if self.redirect == nil { + return nil + } + + if len(self.redirect.Properties.TargetUrl) == 0 { + return nil + } + + _url := self.redirect.Properties.TargetUrl + if matched, _ := regexp.MatchString("^\\w{0,5}://", _url); !matched { + _url = "http://" + _url + } + + u, err := url.Parse(_url) + if err != nil { + log.Debugf("url Parse %s : %s", self.redirect.Properties.TargetUrl, err) + return nil + } + + return u +} +func (self *SLoadBalancerListener) GetRedirectScheme() string { + u := self.getRedirectUrl() + if u == nil { + return "" + } + + return strings.ToLower(u.Scheme) +} + +func (self *SLoadBalancerListener) GetRedirectHost() string { + u := self.getRedirectUrl() + if u == nil { + if self.redirect != nil && len(self.redirect.Properties.TargetListener.ID) > 0 { + segs := strings.Split(self.redirect.Properties.TargetListener.ID, "/") + return segs[len(segs)-1] + } + return "" + } + + return u.Host +} + +func (self *SLoadBalancerListener) GetRedirectPath() string { + u := self.getRedirectUrl() + if u == nil { + return "" + } + + return u.Path +} + +func (self *SLoadBalancerListener) GetClientIdleTimeout() int { + return self.ClientIdleTimeout +} + +func (self *SLoadBalancerListener) GetBackendConnectTimeout() int { + if self.backendSetting == nil { + return 0 + } + + return self.backendSetting.Properties.RequestTimeout +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerlistenerrule.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerlistenerrule.go new file mode 100644 index 0000000000..477e94360d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loadbalancerlistenerrule.go @@ -0,0 +1,192 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "context" + "net/url" + "regexp" + "strings" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerListenerRule struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + + listener *SLoadBalancerListener + lbbg *SLoadbalancerBackendGroup + redirect *RedirectConfiguration + // urlPathMaps -> pathRules + Name string `json:"name"` + ID string `json:"id"` + Domain string `json:"domain"` + Properties PathRuleProperties `json:"properties"` +} + +func (self *SLoadbalancerListenerRule) GetId() string { + return self.ID +} + +func (self *SLoadbalancerListenerRule) GetName() string { + return self.Name +} + +func (self *SLoadbalancerListenerRule) GetGlobalId() string { + return strings.ToLower(self.GetId()) +} + +func (self *SLoadbalancerListenerRule) GetStatus() string { + switch self.Properties.ProvisioningState { + case "Succeeded": + return api.LB_STATUS_ENABLED + case "Failed": + return api.LB_STATUS_DISABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (self *SLoadbalancerListenerRule) GetSysTags() map[string]string { + return nil +} + +func (self *SLoadbalancerListenerRule) GetTags() (map[string]string, error) { + return nil, nil +} + +func (self *SLoadbalancerListenerRule) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} + +func (self *SLoadbalancerListenerRule) GetProjectId() string { + return getResourceGroup(self.GetId()) +} + +func (self *SLoadbalancerListenerRule) IsDefault() bool { + return false +} + +func (self *SLoadbalancerListenerRule) GetDomain() string { + return self.Domain +} + +func (self *SLoadbalancerListenerRule) GetPath() string { + if len(self.Properties.Paths) > 0 { + return self.Properties.Paths[0] + } + + return "" +} + +func (self *SLoadbalancerListenerRule) GetCondition() string { + return "" +} + +func (self *SLoadbalancerListenerRule) GetBackendGroupId() string { + if self.lbbg != nil { + return self.lbbg.GetId() + } + + return "" +} + +func (self *SLoadbalancerListenerRule) Delete(ctx context.Context) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "Delete") +} + +func (self *SLoadbalancerListenerRule) GetRedirect() string { + if self.redirect != nil { + return api.LB_REDIRECT_RAW + } + + return api.LB_REDIRECT_OFF +} + +func (self *SLoadbalancerListenerRule) GetRedirectCode() int64 { + if self.redirect == nil { + return 0 + } + + switch self.redirect.Properties.RedirectType { + case "Permanent": + return api.LB_REDIRECT_CODE_301 + case "Found": + return api.LB_REDIRECT_CODE_302 + case "Temporary", "SeeOther": + return api.LB_REDIRECT_CODE_307 + default: + return 0 + } +} + +func (self *SLoadbalancerListenerRule) getRedirectUrl() *url.URL { + if self.redirect == nil { + return nil + } + + if len(self.redirect.Properties.TargetUrl) == 0 { + return nil + } + + _url := self.redirect.Properties.TargetUrl + if matched, _ := regexp.MatchString("^\\w{0,5}://", _url); !matched { + _url = "http://" + _url + } + + u, err := url.Parse(_url) + if err != nil { + log.Debugf("url Parse %s : %s", self.redirect.Properties.TargetUrl, err) + return nil + } + + return u +} +func (self *SLoadbalancerListenerRule) GetRedirectScheme() string { + u := self.getRedirectUrl() + if u == nil { + return "" + } + + return strings.ToLower(u.Scheme) +} + +func (self *SLoadbalancerListenerRule) GetRedirectHost() string { + u := self.getRedirectUrl() + if u == nil { + if self.redirect != nil && len(self.redirect.Properties.TargetListener.ID) > 0 { + segs := strings.Split(self.redirect.Properties.TargetListener.ID, "/") + return segs[len(segs)-1] + } + return "" + } + + return u.Host +} + +func (self *SLoadbalancerListenerRule) GetRedirectPath() string { + u := self.getRedirectUrl() + if u == nil { + return "" + } + + return u.Path +} diff --git a/pkg/multicloud/azure/loganalytics.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loganalytics.go similarity index 100% rename from pkg/multicloud/azure/loganalytics.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/loganalytics.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/monitor.go new file mode 100644 index 0000000000..9f5d9eec84 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/monitor.go @@ -0,0 +1,506 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "context" + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/timeutils" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type ResponseMetirc struct { + // Cost - The integer value representing the cost of the query, for data case. + Cost float64 `json:"cost,omitempty"` + // Timespan - The timespan for which the data was retrieved. Its value consists of two datetimes concatenated, separated by '/'. This may be adjusted in the future and returned back from what was originally requested. + Timespan string `json:"timespan,omitempty"` + // Interval - The interval (window size) for which the metric data was returned in. This may be adjusted in the future and returned back from what was originally requested. This is not present if a metadata request was made. + Interval string `json:"interval,omitempty"` + // Namespace - The namespace of the metrics been queried + Namespace string `json:"namespace,omitempty"` + // Resourceregion - The region of the resource been queried for metrics. + Resourceregion string `json:"resourceregion,omitempty"` + // Value - the value of the collection. + Value []Metric `json:"value,omitempty"` +} + +// Metric the result data of a query. +type Metric struct { + // ID - the metric Id. + ID string `json:"id,omitempty"` + // Type - the resource type of the metric resource. + Type string `json:"type,omitempty"` + // Name - the name and the display name of the metric, i.e. it is localizable string. + Name LocalizableString `json:"name,omitempty"` + // Unit - the unit of the metric. Possible values include: 'UnitCount', 'UnitBytes', 'UnitSeconds', 'UnitCountPerSecond', 'UnitBytesPerSecond', 'UnitPercent', 'UnitMilliSeconds', 'UnitByteSeconds', 'UnitUnspecified', 'UnitCores', 'UnitMilliCores', 'UnitNanoCores', 'UnitBitsPerSecond' + Unit string `json:"unit,omitempty"` + // Timeseries - the time series returned when a data query is performed. + Timeseries []TimeSeriesElement `json:"timeseries,omitempty"` +} + +type TimeSeriesElement struct { + // Metadatavalues - the metadata values returned if $filter was specified in the call. + Metadatavalues []MetadataValue `json:"metadatavalues,omitempty"` + // Data - An array of data points representing the metric values. This is only returned if a result type of data is specified. + Data []MetricValue `json:"data,omitempty"` +} + +type MetadataValue struct { + // Name - the name of the metadata. + Name LocalizableString `json:"name,omitempty"` + // Value - the value of the metadata. + Value string `json:"value,omitempty"` +} + +type LocalizableString struct { + // Value - the invariant value. + Value string `json:"value,omitempty"` + // LocalizedValue - the locale specific value. + LocalizedValue string `json:"localizedValue,omitempty"` +} + +type MetricValue struct { + // TimeStamp - the timestamp for the metric value in ISO 8601 format. + TimeStamp time.Time `json:"timeStamp,omitempty"` + // Average - the average value in the time range. + Average float64 `json:"average,omitempty"` + // Minimum - the least value in the time range. + Minimum float64 `json:"minimum,omitempty"` + // Maximum - the greatest value in the time range. + Maximum float64 `json:"maximum,omitempty"` + // Total - the sum of all of the values in the time range. + Total float64 `json:"total,omitempty"` + // Count - the number of samples in the time range. Can be used to determine the number of values that contributed to the average value. + Count float64 `json:"count,omitempty"` +} + +func (self MetricValue) GetValue() float64 { + if self.Average > 0 { + return self.Average + } + if self.Total > 0 { + return self.Total + } + if self.Count > 0 { + return self.Count + } + if self.Minimum > 0 { + return self.Minimum + } + return self.Maximum +} + +const ( + RDS_TYPE_SERVERS = "servers" + RDS_TYPE_FLEXIBLE_SERVERS = "flexibleServers" +) + +// https://docs.microsoft.com/en-us/azure/azure-monitor/essentials/metrics-supported +func (self *SAzureClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_RDS: + return self.GetRdsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: + return self.GetRedisMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_LB: + return self.GetLbMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_K8S: + return self.GetK8sMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) + } +} + +type AzureTableMetricDataValue struct { + Timestamp time.Time + Average float64 + Count float64 + CounterName string + DeploymentId string + Host string + Total float64 + Maximum float64 + Minimum float64 +} + +func (self AzureTableMetricDataValue) GetValue() float64 { + if self.Average > 0 { + return self.Average + } + if self.Count > 0 { + return self.Count + } + if self.Minimum > 0 { + return self.Minimum + } + return self.Maximum +} + +type AzureTableMetricData struct { + Value []AzureTableMetricDataValue +} + +func (self *SAzureClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricnamespace := "Microsoft.Compute/virtualMachines" + metricnames := "Percentage CPU,Network In Total,Network Out Total,Disk Read Bytes,Disk Write Bytes,Disk Read Operations/Sec,Disk Write Operations/Sec" + if strings.Contains(opts.ResourceId, "microsoft.classiccompute/virtualmachines") { + metricnamespace = "microsoft.classiccompute/virtualmachines" + } + ret, err := self.getMetricValues(opts.ResourceId, metricnamespace, metricnames, nil, "", opts.StartTime, opts.EndTime) + if err != nil { + return nil, err + } + + for metricType, names := range map[cloudprovider.TMetricType][]string{ + cloudprovider.VM_METRIC_TYPE_MEM_USAGE: {"/builtin/memory/percentusedmemory", "\\Memory\\% Committed Bytes In Use"}, + cloudprovider.VM_METRIC_TYPE_DISK_USAGE: {"/builtin/filesystem/percentusedspace", "\\LogicalDisk(_Total)\\% Free Space"}, + } { + filters := []string{} + for _, name := range names { + filter := fmt.Sprintf("name.value eq '%s'", name) + filters = append(filters, filter) + } + metricDefinitions, err := self.getMetricDefinitions(opts.ResourceId, strings.Join(filters, " or ")) + if err != nil { + log.Errorf("getMetricDefinitions error: %v", err) + continue + } + metric := cloudprovider.MetricValues{} + metric.MetricType = metricType + header := http.Header{} + header.Set("accept", "application/json;odata=minimalmetadata") + for _, definition := range metricDefinitions.Value { + for _, tables := range definition.MetricAvailabilities { + if tables.TimeGrain != "PT1M" { + continue + } + for _, table := range tables.Location.TableInfo { + if table.EndTime.Before(opts.EndTime) { + continue + } + url := fmt.Sprintf("%s%s%s", tables.Location.TableEndpoint, table.TableName, table.SasToken) + _, resp, err := httputils.JSONRequest(httputils.GetDefaultClient(), context.Background(), httputils.GET, url, header, nil, self.debug) + if err != nil { + log.Errorf("request %s error: %v", url, err) + continue + } + values := &AzureTableMetricData{} + resp.Unmarshal(values) + for _, v := range values.Value { + name := strings.ReplaceAll(v.CounterName, `\\`, `\`) + if !utils.IsInStringArray(name, names) { + continue + } + if v.Timestamp.After(opts.StartTime) && v.Timestamp.Before(opts.EndTime) { + value := v.GetValue() + if metricType == cloudprovider.VM_METRIC_TYPE_DISK_USAGE && strings.Contains(strings.ToLower(name), "free") { + value = 100 - value + } + metric.Values = append(metric.Values, cloudprovider.MetricValue{ + Timestamp: v.Timestamp, + Value: value, + }) + } + } + } + } + } + if len(metric.Values) > 0 { + ret = append(ret, metric) + } + } + + if len(opts.OsType) == 0 || strings.Contains(strings.ToLower(opts.OsType), "win") { + workspaces, err := self.GetLoganalyticsWorkspaces() + if err != nil { + return ret, nil + } + winmetric := cloudprovider.MetricValues{} + winmetric.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_USAGE + winmetric.Values = []cloudprovider.MetricValue{} + for i := range workspaces { + data, err := self.GetInstanceDiskUsage(workspaces[i].SLoganalyticsWorkspaceProperties.CustomerId, opts.ResourceId, opts.StartTime, opts.EndTime) + if err != nil { + continue + } + for i := range data { + for j := range data[i].Rows { + if len(data[i].Rows[j]) == 5 { + date, device, free := data[i].Rows[j][0], data[i].Rows[j][1], data[i].Rows[j][2] + dataTime, err := timeutils.ParseTimeStr(date) + if err != nil { + continue + } + if dataTime.Second() > 15 { + continue + } + freeSize, err := strconv.ParseFloat(free, 64) + if err != nil { + continue + } + winmetric.Values = append(winmetric.Values, cloudprovider.MetricValue{ + Timestamp: dataTime, + Value: 100 - freeSize, + Tags: map[string]string{cloudprovider.METRIC_TAG_DEVICE: device}, + }) + } + } + } + } + if len(winmetric.Values) > 0 { + ret = append(ret, winmetric) + } + } + + return ret, nil +} + +func (self *SAzureClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricnamespace := "Microsoft.Cache/redis" + metricnames := "percentProcessorTime,usedmemorypercentage,connectedclients,operationsPerSecond,alltotalkeys,expiredkeys,usedmemory" + return self.getMetricValues(opts.ResourceId, metricnamespace, metricnames, nil, "", opts.StartTime, opts.EndTime) +} + +func (self *SAzureClient) GetLbMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricnamespace := "Microsoft.Network/loadBalancers" + metricnames := "SnatConnectionCount,UsedSnatPorts" + return self.getMetricValues(opts.ResourceId, metricnamespace, metricnames, nil, "", opts.StartTime, opts.EndTime) +} + +func (self *SAzureClient) GetK8sMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricnamespace := "Microsoft.ContainerService/managedClusters" + metricnames := "node_cpu_usage_percentage,node_memory_rss_percentage,node_disk_usage_percentage,node_network_in_bytes,node_network_out_bytes" + filter := fmt.Sprintf("node eq '*'") + return self.getMetricValues(opts.ResourceId, metricnamespace, metricnames, nil, filter, opts.StartTime, opts.EndTime) +} + +func (self *SAzureClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + metricnamespace, metricnames := "", "" + rdsType := RDS_TYPE_SERVERS + if strings.Contains(opts.ResourceId, strings.ToLower(RDS_TYPE_FLEXIBLE_SERVERS)) { + rdsType = RDS_TYPE_FLEXIBLE_SERVERS + } + switch opts.Engine { + case api.DBINSTANCE_TYPE_MYSQL: + metricnamespace = fmt.Sprintf("Microsoft.DBforMySQL/%s", rdsType) + metricnames = "cpu_percent,memory_percent,storage_percent,network_bytes_ingress,network_bytes_egress,io_consumption_percent,connections_failed,active_connections" + case api.DBINSTANCE_TYPE_MARIADB: + metricnamespace = "Microsoft.DBforMariaDB/servers" + metricnames = "cpu_percent,memory_percent,storage_percent,network_bytes_ingress,network_bytes_egress,io_consumption_percent,connections_failed,active_connections" + case api.DBINSTANCE_TYPE_SQLSERVER: + metricnamespace = "Microsoft.Sql/servers/databases" + metricnames = "cpu_percent,connection_successful,sqlserver_process_memory_percent,connection_successful,connection_failed" + result := struct { + Value []SSQLServerDatabase + }{} + err := self.get(opts.ResourceId+"/databases", url.Values{}, &result) + if err != nil { + return nil, err + } + for i := range result.Value { + if result.Value[i].Name == "master" { + continue + } + metrics, err := self.getMetricValues(result.Value[i].ID, metricnamespace, metricnames, map[string]string{cloudprovider.METRIC_TAG_DATABASE: result.Value[i].Name}, "", opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("error: %v", err) + continue + } + for j := range metrics { + metrics[j].Id = opts.ResourceId + ret = append(ret, metrics[j]) + } + } + return ret, nil + case api.DBINSTANCE_TYPE_POSTGRESQL: + metricnamespace = fmt.Sprintf("Microsoft.DBforPostgreSQL/%s", rdsType) + metricnames = "cpu_percent,memory_percent,storage_percent,network_bytes_ingress,network_bytes_egress,io_consumption_percent,connections_failed,active_connections" + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, opts.Engine) + } + return self.getMetricValues(opts.ResourceId, metricnamespace, metricnames, nil, "", opts.StartTime, opts.EndTime) +} + +type MetrifDefinitions struct { + Id string + Value []MetrifDefinition +} + +type MetrifDefinition struct { + Name struct { + Value string + LocalizedValue string + } + Category string + Unit string + PrimaryAggregationType string + ResourceUri string + ResourceId string + MetricAvailabilities []struct { + TimeGrain string + Retention string + Location struct { + TableEndpoint string + TableInfo []struct { + TableName string + StartTime time.Time + EndTime time.Time + SasToken string + SasTokenExpirationTime string + } + PartitionKey string + } + } + Id string +} + +func (self *SAzureClient) getMetricDefinitions(resourceId, filter string) (*MetrifDefinitions, error) { + params := url.Values{} + params.Set("api-version", "2015-07-01") + resource := fmt.Sprintf("%s/providers/microsoft.insights/metricDefinitions", resourceId) + if len(filter) > 0 { + params.Set("$filter", filter) + } + result := &MetrifDefinitions{} + err := self.get(resource, params, &result) + if err != nil { + return nil, err + } + return result, nil +} + +func (self *SAzureClient) getMetricValues(resourceId, metricnamespace, metricnames string, metricTag map[string]string, filter string, startTime, endTime time.Time) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + params := url.Values{} + params.Set("interval", "PT1M") + params.Set("api-version", "2018-01-01") + params.Set("timespan", startTime.UTC().Format(time.RFC3339)+"/"+endTime.UTC().Format(time.RFC3339)) + resource := fmt.Sprintf("%s/providers/microsoft.insights/metrics", resourceId) + params.Set("aggregation", "Average,Count,Maximum,Total") + params.Set("metricnamespace", metricnamespace) + params.Set("metricnames", metricnames) + if len(filter) > 0 { + params.Set("$filter", filter) + } + elements := ResponseMetirc{} + err := self.get(resource, params, &elements) + if err != nil { + return ret, err + } + for i := range elements.Value { + element := elements.Value[i] + metric := cloudprovider.MetricValues{ + Unit: element.Unit, + } + switch element.Name.Value { + case "cpu_percent": + metric.MetricType = cloudprovider.RDS_METRIC_TYPE_CPU_USAGE + case "memory_percent", "sqlserver_process_memory_percent": + metric.MetricType = cloudprovider.RDS_METRIC_TYPE_MEM_USAGE + case "storage_percent": + metric.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_USAGE + case "network_bytes_ingress": + metric.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX + case "network_bytes_egress": + metric.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX + case "io_consumption_percent": + metric.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_IO_PERCENT + case "connections_failed", "connection_failed": + metric.MetricType = cloudprovider.RDS_METRIC_TYPE_CONN_FAILED + case "active_connections", "connection_successful": + metric.MetricType = cloudprovider.RDS_METRIC_TYPE_CONN_ACTIVE + case "Percentage CPU": + metric.MetricType = cloudprovider.VM_METRIC_TYPE_CPU_USAGE + case "Network In Total": + metric.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_RX + case "Network Out Total": + metric.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_TX + case "Disk Read Bytes": + metric.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS + case "Disk Write Bytes": + metric.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS + case "Disk Read Operations/Sec": + metric.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS + case "Disk Write Operations/Sec": + metric.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS + case "percentProcessorTime": + metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE + case "usedmemorypercentage": + metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE + case "connectedclients": + metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_USED_CONN + case "operationsPerSecond": + metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_OPT_SES + case "alltotalkeys": + metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS + case "expiredkeys": + metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS + case "usedmemory": + metric.MetricType = cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE + case "SnatConnectionCount": + metric.MetricType = cloudprovider.LB_METRIC_TYPE_SNAT_PORT + case "UsedSnatPorts": + metric.MetricType = cloudprovider.LB_METRIC_TYPE_SNAT_CONN_COUNT + case "node_cpu_usage_percentage": + metric.MetricType = cloudprovider.K8S_NODE_METRIC_TYPE_CPU_USAGE + case "node_memory_rss_percentage": + metric.MetricType = cloudprovider.K8S_NODE_METRIC_TYPE_MEM_USAGE + case "node_disk_usage_percentage": + metric.MetricType = cloudprovider.K8S_NODE_METRIC_TYPE_DISK_USAGE + case "node_network_in_bytes": + metric.MetricType = cloudprovider.K8S_NODE_METRIC_TYPE_NET_BPS_RX + case "node_network_out_bytes": + metric.MetricType = cloudprovider.K8S_NODE_METRIC_TYPE_NET_BPS_TX + default: + log.Warningf("incognizance metric type %s", element.Name.Value) + continue + } + for _, timeserie := range element.Timeseries { + tags := map[string]string{} + for _, metadata := range timeserie.Metadatavalues { + if metadata.Name.Value == "node" { //k8s node + tags[cloudprovider.METRIC_TAG_NODE] = metadata.Value + } + } + for k, v := range metricTag { + tags[k] = v + } + for _, data := range timeserie.Data { + metric.Values = append(metric.Values, cloudprovider.MetricValue{ + Timestamp: data.TimeStamp, + Value: data.GetValue(), + Tags: tags, + }) + } + } + ret = append(ret, metric) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/network.go new file mode 100644 index 0000000000..704b9d3172 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/network.go @@ -0,0 +1,125 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + AzureTags + wire *SWire + + //AvailableIpAddressCount int `json:"availableIpAddressCount,omitempty"` + ID string + Name string + Properties SubnetPropertiesFormat + AddressPrefix string `json:"addressPrefix,omitempty"` +} + +func (self *SNetwork) GetTags() (map[string]string, error) { + return self.Tags, nil +} + +func (self *SNetwork) GetId() string { + return self.ID +} + +func (self *SNetwork) GetName() string { + return self.Name +} + +func (self *SNetwork) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SNetwork) GetStatus() string { + return api.NETWORK_STATUS_AVAILABLE +} + +func (self *SNetwork) Delete() error { + return self.wire.vpc.region.del(self.ID) +} + +func (self *SNetwork) GetGateway() string { + pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + return endIp.String() +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + return endIp.String() +} + +func (self *SNetwork) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) + return pref.MaskLen +} + +// https://docs.microsoft.com/en-us/azure/virtual-network/virtual-networks-faq +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.Properties.AddressPrefix) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + startIp = startIp.StepUp() // 2 + startIp = startIp.StepUp() // 3 + startIp = startIp.StepUp() // 4 + return startIp.String() +} + +func (self *SNetwork) GetIsPublic() bool { + return true +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) Refresh() error { + network, err := self.wire.zone.region.GetNetwork(self.ID) + if err != nil { + return err + } + return jsonutils.Update(self, network) +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (self *SNetwork) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/pkg/multicloud/azure/os_disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/os_disk.go similarity index 96% rename from pkg/multicloud/azure/os_disk.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/os_disk.go index 90595e739e..0c1c03b3cd 100644 --- a/pkg/multicloud/azure/os_disk.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/os_disk.go @@ -20,14 +20,14 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SOsDisk struct { multicloud.SDisk - multicloud.AzureTags + AzureTags region *SRegion OsType string `json:"osType,omitempty"` diff --git a/pkg/multicloud/azure/policy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/policy.go similarity index 100% rename from pkg/multicloud/azure/policy.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/policy.go diff --git a/pkg/multicloud/azure/progress/computeStats.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/progress/computeStats.go similarity index 100% rename from pkg/multicloud/azure/progress/computeStats.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/progress/computeStats.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/progress/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/progress/doc.go new file mode 100644 index 0000000000..24ef6734fb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/progress/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 progress // import "yunion.io/x/cloudmux/pkg/multicloud/azure/progress" diff --git a/pkg/multicloud/azure/progress/readerWithProgress.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/progress/readerWithProgress.go similarity index 100% rename from pkg/multicloud/azure/progress/readerWithProgress.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/progress/readerWithProgress.go diff --git a/pkg/multicloud/azure/progress/status.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/progress/status.go similarity index 100% rename from pkg/multicloud/azure/progress/status.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/progress/status.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/provider/doc.go new file mode 100644 index 0000000000..9e8b562292 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/azure/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/provider/provider.go new file mode 100644 index 0000000000..043889bee0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/provider/provider.go @@ -0,0 +1,297 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/azure" +) + +type SAzureProviderFactory struct { + cloudprovider.SPublicCloudBaseProviderFactory +} + +func (self *SAzureProviderFactory) GetId() string { + return azure.CLOUD_PROVIDER_AZURE +} + +func (self *SAzureProviderFactory) GetName() string { + return azure.CLOUD_PROVIDER_AZURE_CN +} + +func (self *SAzureProviderFactory) GetMaxCloudEventKeepDays() int { + return 90 +} + +func (self *SAzureProviderFactory) GetMaxCloudEventSyncDays() int { + return 7 +} + +func (self *SAzureProviderFactory) IsCloudeventRegional() bool { + return false +} + +func (self *SAzureProviderFactory) IsSupportSAMLAuth() bool { + return true +} + +func (self *SAzureProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { + return fmt.Errorf("Changing %s bandwidth is not supported", azure.CLOUD_PROVIDER_AZURE) +} + +func (self *SAzureProviderFactory) IsSupportPrepaidResources() bool { + return false +} + +func (self *SAzureProviderFactory) IsSupportCloudIdService() bool { + return true +} + +func (self *SAzureProviderFactory) IsSupportCreateCloudgroup() bool { + return true +} + +func (self *SAzureProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.DirectoryId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "directory_id") + } + if len(input.ClientId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "client_id") + } + if len(input.ClientSecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "client_secret") + } + if len(input.Environment) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "environment") + } + output.Account = input.DirectoryId + output.Secret = fmt.Sprintf("%s/%s", input.ClientId, input.ClientSecret) + output.AccessUrl = input.Environment + return output, nil +} + +func (self *SAzureProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.ClientId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "client_id") + } + if len(input.ClientSecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "client_secret") + } + output = cloudprovider.SCloudaccount{ + Account: cloudaccount, + Secret: fmt.Sprintf("%s/%s", input.ClientId, input.ClientSecret), + } + return output, nil +} + +func parseAccount(account, secret string) (tenantId string, appId string, appKey string, subId string) { + clientInfo := strings.Split(secret, "/") + accountInfo := strings.Split(account, "/") + tenantId = accountInfo[0] + if len(accountInfo) > 1 { + subId = strings.Join(accountInfo[1:], "/") + } + appId = clientInfo[0] + if len(clientInfo) > 1 { + appKey = strings.Join(clientInfo[1:], "/") + } + return +} + +func (self *SAzureProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + tenantId, appId, appKey, subId := parseAccount(cfg.Account, cfg.Secret) + if client, err := azure.NewAzureClient( + azure.NewAzureClientConfig( + cfg.URL, tenantId, appId, appKey, + ).SubscriptionId(subId).CloudproviderConfig(cfg), + ); err != nil { + return nil, err + } else { + return &SAzureProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil + } +} + +func (self *SAzureProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + tenantId, appId, appKey, subId := parseAccount(info.Account, info.Secret) + defaultRegion := "" + switch info.Url { + case "AzurePublicCloud": + defaultRegion = "eastus" + case "AzureChinaCloud": + defaultRegion = "chinaeast2" + } + return map[string]string{ + "AZURE_DIRECTORY_ID": tenantId, + "AZURE_SUBSCRIPTION_ID": subId, + "AZURE_APPLICATION_ID": appId, + "AZURE_APPLICATION_KEY": appKey, + "AZURE_REGION_ID": defaultRegion, + "AZURE_CLOUD_ENV": info.Url, + }, nil +} + +func init() { + factory := SAzureProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SAzureProvider struct { + cloudprovider.SBaseProvider + client *azure.SAzureClient +} + +func (self *SAzureProvider) GetSysInfo() (jsonutils.JSONObject, error) { + regions := self.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") + info.Add(jsonutils.NewString(azure.AZURE_API_VERSION), "api_version") + return info, nil +} + +func (self *SAzureProvider) GetVersion() string { + return azure.AZURE_API_VERSION +} + +func (self *SAzureProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SAzureProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SAzureProvider) GetIamLoginUrl() string { + return self.client.GetIamLoginUrl() +} + +func (self *SAzureProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SAzureProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(id) +} + +func (self *SAzureProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SAzureProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SAzureProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return self.client.CreateIProject(name) +} + +func (self *SAzureProvider) GetStorageClasses(regionId string) []string { + sc, err := self.client.GetStorageClasses(regionId) + if err != nil { + log.Errorf("Fail to find storage classes: %s", err) + return nil + } + return sc +} + +func (self *SAzureProvider) GetBucketCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLPublicRead), + } +} + +func (self *SAzureProvider) GetObjectCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLPublicRead), + } +} + +func (self *SAzureProvider) GetCloudRegionExternalIdPrefix() string { + return self.client.GetAccessEnv() + "/" +} + +func (self *SAzureProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SAzureProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + return self.client.CreateIClouduser(conf) +} + +func (self *SAzureProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { + return self.client.GetICloudusers() +} + +func (self *SAzureProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.client.GetIClouduserByName(name) +} + +func (self *SAzureProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroups() +} + +func (self *SAzureProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + return self.client.CreateICloudgroup(name, desc) +} + +func (self *SAzureProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroupByName(name) +} + +func (self *SAzureProvider) GetEnrollmentAccounts() ([]cloudprovider.SEnrollmentAccount, error) { + return self.client.GetEnrollmentAccounts() +} + +func (self *SAzureProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetISystemCloudpolicies() +} + +func (self *SAzureProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetICustomCloudpolicies() +} + +func (self *SAzureProvider) CreateSubscription(input cloudprovider.SubscriptionCreateInput) error { + return self.client.CreateSubscription(input.Name, input.EnrollmentAccountId, input.OfferType) +} + +// fake func +func (self *SAzureProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { + return self.client.CreateSAMLProvider(opts) +} + +func (self *SAzureProvider) GetSamlEntityId() string { + return cloudprovider.SAML_ENTITY_ID_AZURE +} + +func (self *SAzureProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetMetrics(opts) +} diff --git a/pkg/multicloud/azure/publisher.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/publisher.go similarity index 99% rename from pkg/multicloud/azure/publisher.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/publisher.go index 2c0a06a6c1..377a596e2e 100644 --- a/pkg/multicloud/azure/publisher.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/publisher.go @@ -18,7 +18,7 @@ import ( "fmt" "strings" - "yunion.io/x/onecloud/pkg/apis" + "yunion.io/x/cloudmux/pkg/apis" ) type SPublisherDriver struct { diff --git a/pkg/multicloud/azure/rds_managed_sqlserver.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_managed_sqlserver.go similarity index 97% rename from pkg/multicloud/azure/rds_managed_sqlserver.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_managed_sqlserver.go index df9c38d99a..0182232d62 100644 --- a/pkg/multicloud/azure/rds_managed_sqlserver.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_managed_sqlserver.go @@ -20,14 +20,14 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SManagedSQLServer struct { region *SRegion multicloud.SDBInstanceBase - multicloud.AzureTags + AzureTags Location string `json:"location"` ID string `json:"id"` diff --git a/pkg/multicloud/azure/rds_managed_sqlserver_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_managed_sqlserver_account.go similarity index 93% rename from pkg/multicloud/azure/rds_managed_sqlserver_account.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_managed_sqlserver_account.go index 0f132a0186..f636d67fac 100644 --- a/pkg/multicloud/azure/rds_managed_sqlserver_account.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_managed_sqlserver_account.go @@ -15,8 +15,8 @@ package azure import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SManagedSQLServerAccount struct { diff --git a/pkg/multicloud/azure/rds_managed_sqlserver_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_managed_sqlserver_database.go similarity index 94% rename from pkg/multicloud/azure/rds_managed_sqlserver_database.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_managed_sqlserver_database.go index 5f856f56d4..54b4aff70e 100644 --- a/pkg/multicloud/azure/rds_managed_sqlserver_database.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_managed_sqlserver_database.go @@ -21,14 +21,14 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SManagedSQLServerDatabase struct { multicloud.SDBInstanceDatabaseBase - multicloud.AzureTags + AzureTags rds *SManagedSQLServer ID string `json:"id"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver.go new file mode 100644 index 0000000000..d51396320d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver.go @@ -0,0 +1,215 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SPrivateendpointconnection struct { + ID string `json:"id"` + Properties struct { + Provisioningstate string `json:"provisioningState"` + Privateendpoint struct { + ID string `json:"id"` + } `json:"privateEndpoint"` + Privatelinkserviceconnectionstate struct { + Status string `json:"status"` + Description string `json:"description"` + Actionsrequired string `json:"actionsRequired"` + } `json:"privateLinkServiceConnectionState"` + } `json:"properties"` +} + +type SSQLServer struct { + region *SRegion + multicloud.SDBInstanceBase + AzureTags + + dbs []SSQLServerDatabase + + Kind string `json:"kind"` + Properties struct { + Administratorlogin string `json:"administratorLogin"` + Version string `json:"version"` + State string `json:"state"` + Fullyqualifieddomainname string `json:"fullyQualifiedDomainName"` + Privateendpointconnections []SPrivateendpointconnection `json:"privateEndpointConnections"` + Publicnetworkaccess string `json:"publicNetworkAccess"` + } `json:"properties"` + Location string `json:"location"` + ID string `json:"id"` + Name string `json:"name"` + Type string `json:"type"` +} + +func (self *SRegion) ListSQLServer() ([]SSQLServer, error) { + rds := []SSQLServer{} + err := self.list("Microsoft.Sql/servers", url.Values{}, &rds) + if err != nil { + return nil, errors.Wrapf(err, "list") + } + return rds, nil +} + +func (self *SRegion) GetSQLServer(id string) (*SSQLServer, error) { + rds := &SSQLServer{region: self} + return rds, self.get(id, url.Values{}, rds) +} + +func (self *SSQLServer) GetDiskSizeGB() int { + dbs, err := self.fetchDatabase() + if err != nil { + return 0 + } + sizeMb := 0 + for _, db := range dbs { + sizeMb += db.GetDiskSizeMb() + } + return sizeMb / 1024 +} + +func (self *SSQLServer) GetEngine() string { + return api.DBINSTANCE_TYPE_SQLSERVER +} + +func (self *SSQLServer) GetEngineVersion() string { + return self.Properties.Version +} + +func (self *SSQLServer) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SSQLServer) GetProjectId() string { + return getResourceGroup(self.ID) +} + +func (self *SSQLServer) GetCategory() string { + return api.AZURE_DBINSTANCE_CATEGORY_BASIC +} + +func (self *SSQLServer) GetIVpcId() string { + return "" +} + +func (self *SSQLServer) GetId() string { + return self.ID +} + +func (self *SSQLServer) GetInstanceType() string { + return "" +} + +func (self *SSQLServer) GetMaintainTime() string { + return "" +} + +func (self *SSQLServer) GetName() string { + return self.Name +} + +func (self *SSQLServer) GetPort() int { + return 1433 +} + +func (self *SSQLServer) GetStatus() string { + switch self.Properties.State { + case "Ready": + return api.DBINSTANCE_RUNNING + default: + return self.Properties.State + } +} + +func (self *SSQLServer) GetStorageType() string { + return api.AZURE_DBINSTANCE_STORAGE_TYPE_DEFAULT +} + +func (self *SSQLServer) fetchDatabase() ([]SSQLServerDatabase, error) { + if len(self.dbs) > 0 { + return self.dbs, nil + } + var err error + self.dbs, err = self.region.GetSQLServerDatabases(self.ID) + return self.dbs, err +} + +func (self *SSQLServer) GetVcpuCount() int { + dbs, err := self.fetchDatabase() + if err != nil { + return 0 + } + vcpu := 0 + for _, db := range dbs { + vcpu += db.GetVcpuCount() + } + return vcpu +} + +func (self *SSQLServer) GetVmemSizeMB() int { + dbs, err := self.fetchDatabase() + if err != nil { + return 0 + } + mem := 0 + for _, db := range dbs { + mem += db.GetVmemSizeMb() + } + return mem +} + +func (self *SSQLServer) GetSysTags() map[string]string { + dtu := self.GetDTU() + if dtu > 0 { + return map[string]string{"DTU": fmt.Sprintf("%d", dtu)} + } + return nil +} + +func (self *SSQLServer) GetDTU() int { + dbs, err := self.fetchDatabase() + if err != nil { + return 0 + } + dtu := 0 + for _, db := range dbs { + dtu += db.GetDTU() + } + return dtu +} + +func (self *SSQLServer) GetZone1Id() string { + return "" +} + +func (self *SSQLServer) GetZone2Id() string { + return "" +} + +func (self *SSQLServer) GetZone3Id() string { + return "" +} + +func (self *SSQLServer) GetConnectionStr() string { + return self.Properties.Fullyqualifieddomainname +} diff --git a/pkg/multicloud/azure/rds_sqlserver_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver_account.go similarity index 93% rename from pkg/multicloud/azure/rds_sqlserver_account.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver_account.go index f8f21ab82d..1aef9eddd0 100644 --- a/pkg/multicloud/azure/rds_sqlserver_account.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver_account.go @@ -15,8 +15,8 @@ package azure import ( - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SSQLServerAccount struct { diff --git a/pkg/multicloud/azure/rds_sqlserver_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver_backup.go similarity index 95% rename from pkg/multicloud/azure/rds_sqlserver_backup.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver_backup.go index b1bc713357..5ae967d9a2 100644 --- a/pkg/multicloud/azure/rds_sqlserver_backup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver_backup.go @@ -22,15 +22,15 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SSQLServerBackup struct { rds *SSQLServer multicloud.SDBInstanceBackupBase - multicloud.AzureTags + AzureTags ID string `json:"id"` Name string `json:"name"` diff --git a/pkg/multicloud/azure/rds_sqlserver_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver_database.go similarity index 96% rename from pkg/multicloud/azure/rds_sqlserver_database.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver_database.go index 6a280be210..7e4af0f191 100644 --- a/pkg/multicloud/azure/rds_sqlserver_database.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/rds_sqlserver_database.go @@ -21,14 +21,14 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SSQLServerDatabase struct { multicloud.SDBInstanceDatabaseBase - multicloud.AzureTags + AzureTags rds *SSQLServer Sku struct { Name string `json:"name"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/redis.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/redis.go new file mode 100644 index 0000000000..25c490c5b4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/redis.go @@ -0,0 +1,402 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRedisCache struct { + multicloud.SElasticcacheBase + AzureTags + + region *SRegion + ID string `json:"id"` + Location string `json:"location"` + Name string `json:"name"` + Type string `json:"type"` + Properties struct { + Provisioningstate string `json:"provisioningState"` + Redisversion string `json:"redisVersion"` + Sku struct { + Name string `json:"name"` + Family string `json:"family"` + Capacity int `json:"capacity"` + } `json:"sku"` + Enablenonsslport bool `json:"enableNonSslPort"` + Instances []struct { + Sslport int `json:"sslPort"` + Shardid int `json:"shardId"` + Ismaster bool `json:"isMaster"` + } `json:"instances"` + Publicnetworkaccess string `json:"publicNetworkAccess"` + Redisconfiguration struct { + Maxclients string `json:"maxclients"` + MaxmemoryReserved string `json:"maxmemory-reserved"` + MaxfragmentationmemoryReserved string `json:"maxfragmentationmemory-reserved"` + MaxmemoryDelta string `json:"maxmemory-delta"` + } `json:"redisConfiguration"` + Accesskeys interface{} `json:"accessKeys"` + Hostname string `json:"hostName"` + Port int `json:"port"` + Sslport int `json:"sslPort"` + Shardcount int `json:"shardCount"` + SubnetId string `json:"subnetId"` + StaticIP string `json:"staticIP"` + Linkedservers []interface{} `json:"linkedServers"` + } `json:"properties"` +} + +func (self *SRegion) GetRedisCache(id string) (*SRedisCache, error) { + cache := &SRedisCache{region: self} + return cache, self.get(id, url.Values{}, cache) +} + +func (self *SRegion) GetRedisCaches() ([]SRedisCache, error) { + redis := []SRedisCache{} + err := self.list("Microsoft.Cache/redis", url.Values{}, &redis) + if err != nil { + return nil, errors.Wrapf(err, "list") + } + return redis, nil +} + +func (self *SRedisCache) GetId() string { + return self.ID +} + +func (self *SRedisCache) GetName() string { + return self.Name +} + +func (self *SRedisCache) GetProjectId() string { + return getResourceGroup(self.ID) +} + +func (self *SRedisCache) GetStatus() string { + switch self.Properties.Provisioningstate { + case "Creating": + return api.ELASTIC_CACHE_STATUS_DEPLOYING + case "Deleting": + return api.ELASTIC_CACHE_STATUS_DELETING + case "Disabled": + return api.ELASTIC_CACHE_STATUS_INACTIVE + case "Failed": + return api.ELASTIC_CACHE_STATUS_CREATE_FAILED + case "Linking": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "Provisioning": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "RecoveringScaleFailure": + return api.ELASTIC_CACHE_STATUS_CHANGE_FAILED + case "Scaling": + return api.ELASTIC_CACHE_STATUS_CHANGING + case "Succeeded": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "Unlinking": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "Unprovisioning": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "Updating": + return api.ELASTIC_CACHE_STATUS_RUNNING + default: + return strings.ToLower(self.Properties.Provisioningstate) + } +} + +func (self *SRedisCache) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SRedisCache) GetInstanceType() string { + return self.Properties.Sku.Name +} + +func (self *SRedisCache) GetCapacityMB() int { + switch self.Properties.Sku.Family { + case "P": + switch self.Properties.Sku.Capacity { + case 1: + return 6 * 1024 + case 2: + return 13 * 1024 + case 3: + return 26 * 1024 + case 4: + return 53 * 1024 + case 5: + return 120 * 1024 + } + case "C": + switch self.Properties.Sku.Capacity { + case 0: + return 250 + case 1: + return 1024 + case 2: + return 2.5 * 1024 + case 3: + return 6 * 1024 + case 4: + return 13 * 1024 + case 5: + return 26 * 1024 + case 6: + return 53 * 1024 + } + } + return 0 +} + +func (self *SRedisCache) GetArchType() string { + if self.Properties.Sku.Family == "P" { + return api.ELASTIC_CACHE_ARCH_TYPE_MASTER + } + return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE +} + +func (self *SRedisCache) GetNodeType() string { + switch len(self.Properties.Instances) { + case 1: + return api.ELASTIC_CACHE_NODE_TYPE_SINGLE + case 2: + return api.ELASTIC_CACHE_NODE_TYPE_DOUBLE + case 3: + return api.ELASTIC_CACHE_NODE_TYPE_THREE + case 4: + return api.ELASTIC_CACHE_NODE_TYPE_FOUR + case 5: + return api.ELASTIC_CACHE_NODE_TYPE_FIVE + case 6: + return api.ELASTIC_CACHE_NODE_TYPE_SIX + } + return fmt.Sprintf("%d", self.Properties.Shardcount) +} + +func (self *SRedisCache) GetEngine() string { + return "Redis" +} + +func (self *SRedisCache) GetEngineVersion() string { + return self.Properties.Redisversion +} + +func (self *SRedisCache) GetVpcId() string { + if len(self.Properties.SubnetId) > 0 { + info := strings.Split(self.Properties.SubnetId, "/") + if len(info) > 2 { + return strings.Join(info[:len(info)-2], "/") + } + } + return "" +} + +func (self *SRedisCache) GetZoneId() string { + return self.region.getZone().GetGlobalId() +} + +func (self *SRedisCache) GetNetworkType() string { + if len(self.Properties.SubnetId) > 0 { + return api.LB_NETWORK_TYPE_VPC + } + return api.LB_NETWORK_TYPE_CLASSIC +} + +func (self *SRedisCache) GetNetworkId() string { + return strings.ToLower(self.Properties.SubnetId) +} + +func (self *SRedisCache) GetPrivateDNS() string { + return "" +} + +func (self *SRedisCache) GetPrivateIpAddr() string { + return self.Properties.StaticIP +} + +func (self *SRedisCache) GetPrivateConnectPort() int { + return self.Properties.Port +} + +func (self *SRedisCache) GetPublicDNS() string { + return self.Properties.Hostname +} + +func (self *SRedisCache) GetPublicIpAddr() string { + return "" +} + +func (self *SRedisCache) GetPublicConnectPort() int { + return self.Properties.Sslport +} + +func (self *SRedisCache) GetMaintainStartTime() string { + return "" +} + +func (self *SRedisCache) GetMaintainEndTime() string { + return "" +} + +func (self *SRedisCache) AllocatePublicConnection(port int) (string, error) { + return "", errors.Wrapf(cloudprovider.ErrNotImplemented, "AllocatePublicConnection") +} + +func (self *SRedisCache) ChangeInstanceSpec(spec string) error { + return errors.Wrapf(cloudprovider.ErrNotImplemented, "ChangeInstanceSpec") +} + +func (self *SRedisCache) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "CreateAccount") +} + +func (self *SRedisCache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "CreateAcl") +} + +func (self *SRedisCache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "CreateBackup") +} + +func (self *SRedisCache) Delete() error { + return self.region.Delete(self.ID) +} + +func (self *SRedisCache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { + return errors.Wrapf(cloudprovider.ErrNotSupported, "FlushInstance") +} + +func (self *SRedisCache) GetAuthMode() string { + return "on" +} + +func (self *SRedisCache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetICloudElasticcacheAccounts") +} + +func (self *SRedisCache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { + acls, err := self.region.GetRedisAcls(self.ID) + if err != nil { + return nil, errors.Wrapf(err, "GetRedisAcls") + } + ret := []cloudprovider.ICloudElasticcacheAcl{} + for i := range acls { + acls[i].redis = self + ret = append(ret, &acls[i]) + } + return ret, nil +} + +func (self *SRedisCache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { + acl, err := self.region.GetRedisAcl(aclId) + if err != nil { + return nil, errors.Wrapf(err, "GetRedisAcl") + } + acl.redis = self + return acl, nil +} + +func (self *SRedisCache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { + return []cloudprovider.ICloudElasticcacheBackup{}, nil +} + +func (self *SRedisCache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { + return []cloudprovider.ICloudElasticcacheParameter{}, nil +} + +func (self *SRedisCache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SRedisCache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SRedisCache) GetSecurityGroupIds() ([]string, error) { + return []string{}, nil +} + +func (self *SRedisCache) ReleasePublicConnection() error { + return cloudprovider.ErrNotSupported +} + +func (self *SRedisCache) Restart() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRedisCache) SetMaintainTime(start, end string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRedisCache) UpdateAuthMode(noPasswordAccess bool, password string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRedisCache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRedisCache) UpdateInstanceParameters(config jsonutils.JSONObject) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRedisCache) UpdateSecurityGroups(secgroupIds []string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { + redis, err := self.GetRedisCaches() + if err != nil { + return nil, errors.Wrapf(err, "GetRedisCaches") + } + ret := []cloudprovider.ICloudElasticcache{} + for i := range redis { + redis[i].region = self + ret = append(ret, &redis[i]) + } + switch self.client.GetAccessEnv() { + // 国际区才有企业版 + case api.CLOUD_ACCESS_ENV_AZURE_GLOBAL: + enterpriseRedis, err := self.GetEnterpriseRedisCaches() + if err != nil { + return nil, errors.Wrapf(err, "GetEnterpriseRedisCaches") + } + for i := range enterpriseRedis { + enterpriseRedis[i].region = self + ret = append(ret, &enterpriseRedis[i]) + } + } + return ret, nil +} + +func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { + id = strings.ToLower(id) + if strings.Index(id, "microsoft.cache/redis") > 0 { + return self.GetRedisCache(id) + } else if strings.Index(id, "Microsoft.Cache/redisEnterprise") > 0 { + return self.GetEnterpriseRedisCache(id) + } else { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) + } +} diff --git a/pkg/multicloud/azure/redis_acl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/redis_acl.go similarity index 93% rename from pkg/multicloud/azure/redis_acl.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/redis_acl.go index 89117eb82d..0cd5f38489 100644 --- a/pkg/multicloud/azure/redis_acl.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/redis_acl.go @@ -22,15 +22,15 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SRedisAcl struct { redis *SRedisCache multicloud.SResourceBase - multicloud.AzureTags + AzureTags ID string `json:"id"` Name string `json:"name"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/region.go new file mode 100644 index 0000000000..fd49689de0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/region.go @@ -0,0 +1,731 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVMSize struct { + //MaxDataDiskCount int32 `json:"maxDataDiskCount,omitempty"` //Unmarshal会出错 + MemoryInMB int32 `json:"memoryInMB,omitempty"` + NumberOfCores int `json:"numberOfCores,omitempty"` + Name string + OsDiskSizeInMB int32 `json:"osDiskSizeInMB,omitempty"` + ResourceDiskSizeInMB int32 `json:"resourceDiskSizeInMB,omitempty"` +} + +type SRegion struct { + multicloud.SRegion + client *SAzureClient + + storageCache *SStoragecache + appServicePlans map[string]*SAppServicePlan + + ID string + Name string + DisplayName string + Latitude string + Longitude string +} + +func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotImplemented +} + +///////////////////////////////////////////////////////////////////////////// +func (self *SRegion) Refresh() error { + // do nothing + return nil +} + +func (self *SRegion) GetClient() *SAzureClient { + return self.client +} + +func (self *SRegion) ListVmSizes() ([]SVMSize, error) { + result := []SVMSize{} + resource := fmt.Sprintf("Microsoft.Compute/locations/%s/vmSizes", self.Name) + return result, self.client.list(resource, url.Values{}, &result) +} + +func (self *SRegion) getHardwareProfile(cpu, memMB int) []string { + vmSizes, err := self.ListVmSizes() + if err != nil { + return []string{} + } + result := []string{} + for i := range vmSizes { + if vmSizes[i].MemoryInMB == int32(memMB) && vmSizes[i].NumberOfCores == cpu { + result = append(result, vmSizes[i].Name) + } + } + return result +} + +func (self *SRegion) getVMSize(name string) (*SVMSize, error) { + vmSizes, err := self.ListVmSizes() + if err != nil { + return nil, errors.Wrapf(err, "ListVmSizes") + } + for i := range vmSizes { + if vmSizes[i].Name == name { + return &vmSizes[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) +} + +func (self *SRegion) GetId() string { + return self.Name +} + +func (self *SRegion) GetName() string { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_AZURE_CN, self.DisplayName) +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_AZURE_EN, self.DisplayName) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.Name) +} + +func (self *SRegion) IsEmulated() bool { + return false +} + +func (self *SRegion) GetProvider() string { + return CLOUD_PROVIDER_AZURE +} + +func (self *SRegion) GetCloudEnv() string { + return self.client.envName +} + +func (self *SRegion) trimGeographicString(geographic string) string { + return strings.TrimFunc(geographic, func(r rune) bool { + return !((r >= '0' && r <= '9') || r == '.' || r == '-') + }) +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + info := cloudprovider.SGeographicInfo{} + if geographicInfo, ok := AzureGeographicInfo[self.Name]; ok { + info = geographicInfo + } + + self.Latitude = self.trimGeographicString(self.Latitude) + self.Longitude = self.trimGeographicString(self.Longitude) + + latitude, err := strconv.ParseFloat(self.Latitude, 32) + if err != nil { + log.Errorf("Parse azure region %s latitude %s error: %v", self.Name, self.Latitude, err) + } else { + info.Latitude = float32(latitude) + } + + longitude, err := strconv.ParseFloat(self.Longitude, 32) + if err != nil { + log.Errorf("Parse azure region %s longitude %s error: %v", self.Name, self.Longitude, err) + } else { + info.Longitude = float32(longitude) + } + return info +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + vpc := SVpc{ + region: self, + Name: opts.NAME, + Location: self.Name, + Properties: VirtualNetworkPropertiesFormat{ + AddressSpace: AddressSpace{ + AddressPrefixes: []string{opts.CIDR}, + }, + }, + Type: "Microsoft.Network/virtualNetworks", + } + return &vpc, self.create("", jsonutils.Marshal(vpc), &vpc) +} + +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) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + return self.GetInstance(id) +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return self.GetDisk(id) +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + if storageCache.GetGlobalId() == id { + return self.storageCache, 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 i := 0; i < len(ivpcs); i++ { + if ivpcs[i].GetGlobalId() == id { + return ivpcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + if izones, err := self.GetIZones(); err != nil { + return nil, err + } else { + for i := 0; i < len(izones); i += 1 { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) getZone() *SZone { + return &SZone{region: self, Name: self.Name} +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + return []cloudprovider.ICloudZone{self.getZone()}, nil +} + +func (self *SRegion) getStoragecache() *SStoragecache { + if self.storageCache == nil { + self.storageCache = &SStoragecache{region: self} + } + return self.storageCache +} + +func (self *SRegion) ListVpcs() ([]SVpc, error) { + result := []SVpc{} + err := self.list("Microsoft.Network/virtualNetworks", url.Values{}, &result) + if err != nil { + return nil, errors.Wrapf(err, "list") + } + return result, nil +} + +func (self *SRegion) ListClassicVpcs() ([]SClassicVpc, error) { + result := []SClassicVpc{} + err := self.list("Microsoft.ClassicNetwork/virtualNetworks", url.Values{}, &result) + if err != nil { + return nil, errors.Wrapf(err, "ListClassicVpcs") + } + return result, nil +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + vpcs, err := self.ListVpcs() + if err != nil { + return nil, errors.Wrapf(err, "ListVpcs") + } + classicVpcs, err := self.ListClassicVpcs() + if err != nil { + return nil, errors.Wrapf(err, "ListClassicVpcs") + } + ret := []cloudprovider.ICloudVpc{} + for i := range vpcs { + vpcs[i].region = self + ret = append(ret, &vpcs[i]) + } + for i := range classicVpcs { + classicVpcs[i].region = self + ret = append(ret, &classicVpcs[i]) + } + return ret, nil +} + +func (self *SRegion) CreateInstanceSimple(name string, imgId, osType string, cpu int, memMb int, sysDiskSizeGB int, storageType string, dataDiskSizesGB []int, nicId string, passwd string, publicKey string) (*SInstance, error) { + desc := &cloudprovider.SManagedVMCreateConfig{ + Name: name, + ExternalImageId: imgId, + SysDisk: cloudprovider.SDiskInfo{SizeGB: sysDiskSizeGB, StorageType: storageType}, + Cpu: cpu, + MemoryMB: memMb, + Password: passwd, + DataDisks: []cloudprovider.SDiskInfo{}, + PublicKey: publicKey, + OsType: osType, + } + if len(passwd) > 0 { + desc.Password = passwd + } + for _, sizeGB := range dataDiskSizesGB { + desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType}) + } + return self._createVM(desc, nicId) +} + +func (region *SRegion) GetEips() ([]SEipAddress, error) { + eips := []SEipAddress{} + err := region.client.list("Microsoft.Network/publicIPAddresses", url.Values{}, &eips) + if err != nil { + return nil, err + } + result := []SEipAddress{} + for i := 0; i < len(eips); i++ { + if eips[i].Location == region.Name { + eips[i].region = region + result = append(result, eips[i]) + } + } + return result, nil +} + +func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, err := region.GetEips() + if err != nil { + return nil, errors.Wrapf(err, "GetEips") + } + classicEips, err := region.GetClassicEips() + if err != nil { + return nil, errors.Wrapf(err, "GetClassicEips") + } + ieips := []cloudprovider.ICloudEIP{} + for i := 0; i < len(eips); i++ { + if len(eips[i].GetIpAddr()) == 0 { + continue + } + _, err := netutils.NewIPV4Addr(eips[i].GetIpAddr()) + if err != nil { + continue + } + eips[i].region = region + ieips = append(ieips, &eips[i]) + } + for i := 0; i < len(classicEips); i++ { + if len(classicEips[i].GetIpAddr()) == 0 { + continue + } + _, err := netutils.NewIPV4Addr(eips[i].GetIpAddr()) + if err != nil { + continue + } + classicEips[i].region = region + ieips = append(ieips, &classicEips[i]) + } + return ieips, nil +} + +func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + if strings.Contains(strings.ToLower(secgroupId), "microsoft.classicnetwork") { + return region.GetClassicSecurityGroupDetails(secgroupId) + } + return region.GetSecurityGroupDetails(secgroupId) +} + +func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + if strings.Contains(strings.ToLower(opts.VpcId), "microsoft.classicnetwork") { + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "not support classic secgroup") + } + resource := fmt.Sprintf("subscriptions/%s/resourcegroups/%s/providers/microsoft.network/networksecuritygroups/%s", region.client.subscriptionId, opts.ProjectId, opts.Name) + secgroup := &SSecurityGroup{region: region} + err := region.get(resource, url.Values{}, secgroup) + if err != nil { + return nil, errors.Wrapf(err, "get(%s)", resource) + } + return secgroup, nil +} + +func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + if conf.VpcId == "classic" { + return region.CreateClassicSecurityGroup(conf.Name) + } + return region.CreateSecurityGroup(conf.Name) +} + +func (region *SRegion) getIAppLBs() ([]cloudprovider.ICloudLoadbalancer, error) { + lbs := []SLoadbalancer{} + params := url.Values{} + params.Set("api-version", "2021-02-01") + err := region.list("Microsoft.Network/applicationGateways", params, &lbs) + if err != nil { + return nil, errors.Wrapf(err, "list") + } + + ilbs := make([]cloudprovider.ICloudLoadbalancer, len(lbs)) + for i := range lbs { + lbs[i].region = region + ilbs[i] = &lbs[i] + } + + return ilbs, nil +} + +func (region *SRegion) getINetworkLBs() ([]cloudprovider.ICloudLoadbalancer, error) { + lbs := []SLoadbalancer{} + params := url.Values{} + params.Set("api-version", "2021-02-01") + err := region.list("Microsoft.Network/loadBalancers", params, &lbs) + if err != nil { + return nil, errors.Wrapf(err, "list") + } + + ilbs := make([]cloudprovider.ICloudLoadbalancer, len(lbs)) + for i := range lbs { + lbs[i].region = region + ilbs[i] = &lbs[i] + } + + return ilbs, nil +} + +func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + appLbs, err := region.getIAppLBs() + if err != nil { + return nil, errors.Wrap(err, "GetIAppLBs") + } + + netLbs, err := region.getINetworkLBs() + if err != nil { + return nil, errors.Wrap(err, "GetINetworkLBs") + } + + lbs := []cloudprovider.ICloudLoadbalancer{} + lbs = append(lbs, appLbs...) + lbs = append(lbs, netLbs...) + return lbs, nil +} + +func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { + lb := SLoadbalancer{} + params := url.Values{} + params.Set("api-version", "2021-02-01") + err := region.get(loadbalancerId, params, &lb) + if err != nil { + return nil, errors.Wrapf(err, "get") + } + + lb.region = region + return &lb, nil +} + +func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, errors.Wrap(cloudprovider.ErrNotSupported, "GetILoadBalancerAclById") +} + +func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + segs := strings.Split(certId, "/sslCertificates") + if len(segs[0]) > 0 { + lb, err := region.GetILoadBalancerById(segs[0]) + if err != nil { + return nil, errors.Wrap(err, "GetILoadBalancerById") + } + + return lb.(*SLoadbalancer).GetILoadBalancerCertificateById(certId) + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetILoadBalancerCertificateById") +} + +func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + lbs, err := region.GetILoadBalancers() + if err != nil { + return nil, errors.Wrap(err, "GetILoadBalancers") + } + + certs := []cloudprovider.ICloudLoadbalancerCertificate{} + for i := range lbs { + _certs, err := lbs[i].(*SLoadbalancer).GetILoadBalancerCertificates() + if err != nil { + return nil, errors.Wrap(err, "GetILoadBalancerCertificates") + } + certs = append(certs, _certs...) + } + + return certs, nil +} + +func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "CreateILoadBalancerCertificate") +} + +func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, errors.Wrap(cloudprovider.ErrNotSupported, "GetILoadBalancerAcls") +} + +func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "GetILoadBalancerCertificates") +} + +func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "CreateILoadBalancerAcl") +} + +func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + accounts, err := region.ListStorageAccounts() + if err != nil { + return nil, errors.Wrapf(err, "ListStorageAccounts") + } + ret := make([]cloudprovider.ICloudBucket, 0) + for i := range accounts { + ret = append(ret, &accounts[i]) + } + return ret, nil +} + +func (region *SRegion) CreateIBucket(name string, storageClassStr string, acl string) error { + _, err := region.createStorageAccount(name, storageClassStr) + if err != nil { + return errors.Wrapf(err, "region.createStorageAccount name=%s storageClass=%s acl=%s", name, storageClassStr, acl) + } + return nil +} + +func (region *SRegion) DeleteIBucket(name string) error { + accounts, err := region.listStorageAccounts() + if err != nil { + return errors.Wrap(err, "ListStorageAccounts") + } + for i := range accounts { + if accounts[i].Name == name { + err = region.del(accounts[i].ID) + if err != nil { + return errors.Wrapf(err, "region.del") + } + return nil + } + } + return nil +} + +func (region *SRegion) IBucketExist(name string) (bool, error) { + return region.checkStorageAccountNameExist(name) +} + +func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { + return cloudprovider.GetIBucketById(region, name) +} + +func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { + return region.GetIBucketById(name) +} + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} + +func (self *SRegion) get(resource string, params url.Values, retVal interface{}) error { + return self.client.get(resource, params, retVal) +} + +func (self *SRegion) Show(resource string) (jsonutils.JSONObject, error) { + ret := jsonutils.NewDict() + err := self.get(resource, url.Values{}, ret) + if err != nil { + return nil, err + } + return ret, nil +} + +func (self *SRegion) del(resource string) error { + return self.client.del(resource) +} + +func (self *SRegion) Delete(resource string) error { + return self.del(resource) +} + +func (self *SRegion) checkResourceGroup(resourceGroup string) (string, error) { + if len(resourceGroup) == 0 { + resourceGroup = "Default" + } + resourceGroups, err := self.client.ListResourceGroups() + if err != nil { + return "", errors.Wrapf(err, "ListResourceGroups") + } + + for i := range resourceGroups { + proj := resourceGroups[i] + if strings.ToLower(proj.GetName()) == strings.ToLower(resourceGroup) || + proj.GetGlobalId() == resourceGroup || + (strings.Contains(resourceGroup, "/") && strings.HasSuffix(proj.GetGlobalId(), resourceGroup)) { + return resourceGroup, nil + } + } + _, err = self.CreateResourceGroup(resourceGroup) + return resourceGroup, err +} + +type sInfo struct { + Location string `json:"Location"` + Name string `json:"Name"` + Type string `json:"Type"` +} + +func (self *SRegion) createInfo(body jsonutils.JSONObject) (sInfo, error) { + info := sInfo{} + err := body.Unmarshal(&info) + if err != nil { + return info, errors.Wrapf(err, "body.Unmarshal") + } + if len(info.Name) == 0 { + return info, fmt.Errorf("Missing name params") + } + if len(info.Type) == 0 { + return info, fmt.Errorf("Missing type params") + } + return info, nil +} + +func (self *SRegion) create(resourceGroup string, _body jsonutils.JSONObject, retVal interface{}) error { + body := _body.(*jsonutils.JSONDict) + info, err := self.createInfo(_body) + if err != nil { + return errors.Wrapf(err, "createInfo") + } + resourceGroup, err = self.checkResourceGroup(resourceGroup) + if err != nil { + return errors.Wrapf(err, "checkResourceGroup(%s)", resourceGroup) + } + info.Name, err = self.client.getUniqName(resourceGroup, info.Type, info.Name) + if err != nil { + return errors.Wrapf(err, "getUniqName") + } + info.Location = self.Name + body.Update(jsonutils.Marshal(info)) + body.Remove("location") + body.Remove("name") + body.Remove("type") + return self.client.create(resourceGroup, info.Type, info.Name, body, retVal) +} + +func (self *SRegion) update(body jsonutils.JSONObject, retVal interface{}) error { + return self.client.update(body, retVal) +} + +func (self *SRegion) perform(id, action string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.client.perform(id, action, body) +} + +func (self *SRegion) put(resource string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.client.put(resource, body) +} + +func (self *SRegion) patch(resource string, body jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.client.patch(resource, body) +} + +func (self *SRegion) list(resource string, params url.Values, retVal interface{}) error { + result := []jsonutils.JSONObject{} + err := self.client.list(resource, params, &result) + if err != nil { + return errors.Wrapf(err, "client.list") + } + ret := []jsonutils.JSONObject{} + for i := range result { + location, _ := result[i].GetString("location") + if len(location) == 0 || strings.ToLower(self.Name) == strings.ToLower(strings.Replace(location, " ", "", -1)) { + ret = append(ret, result[i]) + } + } + return jsonutils.Update(retVal, ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/resourcegroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/resourcegroup.go new file mode 100644 index 0000000000..1197c2db19 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/resourcegroup.go @@ -0,0 +1,88 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type GroupProperties struct { + ProvisioningState string +} + +type SResourceGroup struct { + multicloud.SProjectBase + AzureTags + client *SAzureClient + + ID string + Name string + Location string + Properties GroupProperties + ManagedBy string + subId string +} + +func (self *SRegion) GetResourceGroupDetail(groupName string) (*SResourceGroup, error) { + resourceGroup := SResourceGroup{client: self.client, subId: self.client._subscriptionId()} + idStr := fmt.Sprintf("subscriptions/%s/resourcegroups/%s", self.client._subscriptionId(), groupName) + return &resourceGroup, self.get(idStr, url.Values{}, &resourceGroup) +} + +// not support update, resource group name is immutable??? +func (self *SRegion) UpdateResourceGroup(groupName string, newName string) error { + resourceGroup := SResourceGroup{Name: newName, client: self.client, subId: self.client._subscriptionId()} + resource := fmt.Sprintf("subscriptions/%s/resourcegroups/%s", self.client.subscriptionId, groupName) + _, err := self.client.patch(resource, jsonutils.Marshal(&resourceGroup)) + return err +} + +func (self *SRegion) CreateResourceGroup(groupName string) (jsonutils.JSONObject, error) { + resourceGroup := SResourceGroup{Location: self.Name, client: self.client, subId: self.client._subscriptionId()} + idStr := fmt.Sprintf("subscriptions/%s/resourcegroups/%s", self.client._subscriptionId(), groupName) + return self.client.put(idStr, jsonutils.Marshal(resourceGroup)) +} + +func (self *SRegion) DeleteResourceGroup(groupName string) error { + idStr := fmt.Sprintf("subscriptions/%s/resourcegroups/%s", self.client._subscriptionId(), groupName) + return self.del(idStr) +} + +func (r *SResourceGroup) GetName() string { + return r.Name +} + +func (r *SResourceGroup) GetId() string { + return r.ID +} + +func (self *SResourceGroup) GetAccountId() string { + return fmt.Sprintf("%s/%s", self.client.tenantId, self.subId) +} + +func (r *SResourceGroup) GetGlobalId() string { + return strings.ToLower(fmt.Sprintf("%s/%s", r.subId, r.Name)) +} + +func (r *SResourceGroup) GetStatus() string { + return api.EXTERNAL_PROJECT_STATUS_AVAILABLE +} diff --git a/pkg/multicloud/azure/resourcesku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/resourcesku.go similarity index 100% rename from pkg/multicloud/azure/resourcesku.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/resourcesku.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/saml_provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/saml_provider.go new file mode 100644 index 0000000000..a1a257d2fe --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/saml_provider.go @@ -0,0 +1,137 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis/cloudid" + api "yunion.io/x/cloudmux/pkg/apis/cloudid" + compute_api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudid/options" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/httputils" + "yunion.io/x/onecloud/pkg/util/samlutils" +) + +type SAMLProvider struct { + multicloud.SResourceBase + AzureTags + client *SAzureClient + + Name string + Metadata samlutils.EntityDescriptor +} + +func (self *SAMLProvider) Delete() error { + return nil +} + +func (self *SAMLProvider) GetGlobalId() string { + return strings.TrimPrefix(options.Options.ApiServer, "https://") +} + +func (self *SAMLProvider) GetId() string { + return options.Options.ApiServer +} + +func (self *SAMLProvider) GetName() string { + return self.Name +} + +func (self *SAMLProvider) GetStatus() string { + return api.SAML_PROVIDER_STATUS_AVAILABLE +} + +func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { + return nil +} + +func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { + return &self.Metadata, nil +} + +func (self *SAMLProvider) GetAuthUrl() string { + input := samlutils.SIdpInitiatedLoginInput{ + EntityID: cloudprovider.SAML_ENTITY_ID_AZURE, + IdpId: self.client.cpcfg.AccountId, + } + if self.client.GetAccessEnv() != compute_api.CLOUD_ACCESS_ENV_AZURE_GLOBAL { + return "" + } + return httputils.JoinPath(options.Options.ApiServer, cloudid.SAML_IDP_PREFIX, fmt.Sprintf("sso?%s", jsonutils.Marshal(input).QueryString())) +} + +func (self *SAzureClient) ListSAMLProviders() ([]SAMLProvider, error) { + _, err := self.msGraphRequest("GET", "identityProviders", nil) + if err != nil { + return nil, err + } + return []SAMLProvider{}, nil +} + +func (self *SAzureClient) InviteUser(email string) (*SClouduser, error) { + body := jsonutils.Marshal(map[string]string{ + "invitedUserEmailAddress": email, + "inviteRedirectUrl": fmt.Sprintf("https://portal.azure.com/%s?login_hint=%s", self.tenantId, email), + }) + resp, err := self.msGraphRequest("POST", "invitations", body) + if err != nil { + return nil, errors.Wrapf(err, "msGraphRequest.invitations") + } + inviteUrl, _ := resp.GetString("inviteRedeemUrl") + err = cloudprovider.Wait(time.Second*2, time.Minute, func() (bool, error) { + users, err := self.ListGraphUsers() + if err != nil { + return false, errors.Wrapf(err, "GetCloudusers") + } + for i := range users { + users[i].inviteRedeemUrl = inviteUrl + if users[i].GetEmailAddr() == email { + return true, nil + } + } + return false, nil + }) + if err != nil { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "after invite %s", email) + } + users, err := self.ListGraphUsers() + if err != nil { + return nil, errors.Wrapf(err, "GetCloudusers") + } + for i := range users { + users[i].inviteRedeemUrl = inviteUrl + if users[i].GetEmailAddr() == email { + return &users[i], nil + } + } + + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "after invite %s", email) +} + +func (self *SAzureClient) CreateSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (*SAMLProvider, error) { + return &SAMLProvider{ + client: self, + Name: opts.Name, + Metadata: opts.Metadata, + }, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/securitygroup.go new file mode 100644 index 0000000000..307a1d7f62 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/securitygroup.go @@ -0,0 +1,489 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net" + "net/url" + "strconv" + "strings" + "unicode" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/regutils" + "yunion.io/x/pkg/util/secrules" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SecurityRulePropertiesFormat struct { + Description string `json:"description,omitempty"` + Protocol string `json:"protocol,omitempty"` + SourcePortRange string `json:"sourcePortRange,omitempty"` + DestinationPortRange string `json:"destinationPortRange,omitempty"` + SourceAddressPrefix string `json:"sourceAddressPrefix,omitempty"` + SourceAddressPrefixes []string `json:"sourceAddressPrefixes,omitempty"` + DestinationAddressPrefix string `json:"destinationAddressPrefix,omitempty"` + DestinationAddressPrefixes []string `json:"destinationAddressPrefixes,omitempty"` + SourcePortRanges []string `json:"sourcePortRanges,omitempty"` + DestinationPortRanges []string `json:"destinationPortRanges,omitempty"` + Access string `json:"access,omitempty"` // Allow or Deny + Priority int32 `json:"priority,omitempty"` + Direction string `json:"direction,omitempty"` //Inbound or Outbound + ProvisioningState string `json:"-"` +} +type SecurityRules struct { + Properties SecurityRulePropertiesFormat + Name string + ID string +} + +type Interface struct { + ID string +} + +type SecurityGroupPropertiesFormat struct { + SecurityRules []SecurityRules `json:"securityRules,omitempty"` + DefaultSecurityRules []SecurityRules `json:"defaultSecurityRules,omitempty"` + NetworkInterfaces *[]Interface `json:"networkInterfaces,omitempty"` + Subnets *[]SNetwork `json:"subnets,omitempty"` + ProvisioningState string //Possible values are: 'Updating', 'Deleting', and 'Failed' +} +type SSecurityGroup struct { + multicloud.SSecurityGroup + AzureTags + + region *SRegion + Properties *SecurityGroupPropertiesFormat `json:"properties,omitempty"` + ID string + Name string + Location string + Type string +} + +func parseCIDR(cidr string) (*net.IPNet, error) { + if cidr == "*" || strings.ToLower(cidr) == "internet" { + cidr = "0.0.0.0/0" + } + if strings.Index(cidr, "/") > 0 { + _, ipnet, err := net.ParseCIDR(cidr) + return ipnet, err + } + ip := net.ParseIP(cidr) + if ip == nil { + return nil, fmt.Errorf("Parse ip %s error", cidr) + } + return &net.IPNet{IP: ip, Mask: net.CIDRMask(32, 32)}, nil +} + +type rulePorts struct { + ports []int + portStart int + portEnd int +} + +func parsePorts(ports string) (rulePorts, error) { + result := rulePorts{ + portStart: -1, + portEnd: -1, + ports: []int{}, + } + if ports == "*" { + return result, nil + } else if strings.Index(ports, ",") > 0 { + for _, _port := range strings.Split(ports, ",") { + port, err := strconv.Atoi(_port) + if err != nil { + msg := fmt.Sprintf("parse rule port %s error: %v", ports, err) + log.Errorf(msg) + return result, fmt.Errorf(msg) + } + result.ports = append(result.ports, port) + } + } else if strings.Index(ports, "-") > 0 { + _ports := strings.Split(ports, "-") + if len(_ports) == 2 { + portStart, err := strconv.Atoi(_ports[0]) + if err != nil { + msg := fmt.Sprintf("parse rule port %s error: %v", ports, err) + log.Errorf(msg) + return result, fmt.Errorf(msg) + } + result.portStart = portStart + portEnd, err := strconv.Atoi(_ports[1]) + if err != nil { + msg := fmt.Sprintf("parse rule port %s error: %v", ports, err) + log.Errorf(msg) + return result, fmt.Errorf(msg) + } + result.portEnd = portEnd + } + } else { + _port, err := strconv.Atoi(ports) + if err != nil { + msg := fmt.Sprintf("parse rule port %s error: %v", ports, err) + log.Errorf(msg) + return result, fmt.Errorf(msg) + } + result.ports = append(result.ports, _port) + } + return result, nil +} + +func paresPortsWithIpNet(port string, ports []string, ip string, ips []string) ([]rulePorts, []*net.IPNet, error) { + portsResult, ipResult := []rulePorts{}, []*net.IPNet{} + if len(port) > 0 { + _ports, err := parsePorts(port) + if err != nil { + return nil, nil, err + } + portsResult = append(portsResult, _ports) + } else if len(ports) > 0 { + for i := 0; i < len(ports); i++ { + _ports, err := parsePorts(ports[i]) + if err != nil { + return nil, nil, err + } + portsResult = append(portsResult, _ports) + } + } + + if len(ip) > 0 { + ipnet, err := parseCIDR(ip) + if err != nil { + return nil, nil, err + } + ipResult = append(ipResult, ipnet) + } else if len(ips) > 0 { + for i := 0; i < len(ips); i++ { + ipnet, err := parseCIDR(ips[i]) + if err != nil { + return nil, nil, err + } + ipResult = append(ipResult, ipnet) + } + } + return portsResult, ipResult, nil +} + +func (self *SecurityRulePropertiesFormat) toRules() ([]cloudprovider.SecurityRule, error) { + result := []cloudprovider.SecurityRule{} + rule := cloudprovider.SecurityRule{ + SecurityRule: secrules.SecurityRule{ + Action: secrules.TSecurityRuleAction(strings.ToLower(self.Access)), + Direction: secrules.TSecurityRuleDirection(strings.Replace(strings.ToLower(self.Direction), "bound", "", -1)), + Protocol: strings.ToLower(self.Protocol), + Priority: int(self.Priority), + Description: self.Description, + }} + + if rule.Protocol == "*" { + rule.Protocol = "any" + } + + addressPrefix, addressPrefixes := "", []string{} + if rule.Direction == secrules.DIR_IN { + addressPrefix, addressPrefixes = self.SourceAddressPrefix, self.SourceAddressPrefixes + } else { + addressPrefix, addressPrefixes = self.DestinationAddressPrefix, self.DestinationAddressPrefixes + } + + if strings.ToLower(addressPrefix) == "internet" || addressPrefix == "*" { + addressPrefix = "0.0.0.0/0" + } + + if !regutils.MatchIPAddr(addressPrefix) && !regutils.MatchCIDR(addressPrefix) && len(addressPrefixes) == 0 { + return nil, nil + } + + ports, ips, err := paresPortsWithIpNet(self.DestinationPortRange, self.DestinationPortRanges, addressPrefix, addressPrefixes) + if err != nil { + return nil, err + } + + for i := 0; i < len(ips); i++ { + rule.IPNet = ips[i] + for j := 0; j < len(ports); j++ { + rule.Ports = ports[j].ports + rule.PortStart = ports[j].portStart + rule.PortEnd = ports[j].portEnd + err := rule.ValidateRule() + if err != nil && err != secrules.ErrInvalidPriority { + return nil, err + } + result = append(result, rule) + } + } + + return result, nil +} + +func (self *SecurityRulePropertiesFormat) String() string { + rules, err := self.toRules() + if err != nil { + log.Errorf("convert secrules error: %v", err) + return "" + } + result := []string{} + for i := 0; i < len(rules); i++ { + result = append(result, rules[i].String()) + } + return strings.Join(result, ";") +} + +func (self *SSecurityGroup) GetId() string { + return self.ID +} + +func (self *SSecurityGroup) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SSecurityGroup) GetDescription() string { + return "" +} + +func (self *SSecurityGroup) GetName() string { + return self.Name +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + rules := make([]cloudprovider.SecurityRule, 0) + if self.Properties == nil || self.Properties.SecurityRules == nil { + return rules, nil + } + for _, _rule := range self.Properties.SecurityRules { + secRules, err := _rule.Properties.toRules() + if err != nil { + return nil, errors.Wrap(err, "_rule.Properties.toRules") + } + for i := range secRules { + secRules[i].Name = _rule.Name + rules = append(rules, secRules[i]) + } + } + return rules, nil +} + +func (self *SSecurityGroup) GetStatus() string { + return "" +} + +func (self *SSecurityGroup) IsEmulated() bool { + return false +} + +func (self *SSecurityGroup) GetVpcId() string { + return "normal" +} + +func (region *SRegion) CreateSecurityGroup(secName string) (*SSecurityGroup, error) { + if secName == "Default" { + secName = "Default-copy" + } + secgroup := &SSecurityGroup{region: region} + params := map[string]string{ + "Name": secName, + "Type": "Microsoft.Network/networkSecurityGroups", + "Location": region.Name, + } + return secgroup, region.create("", jsonutils.Marshal(params), secgroup) +} + +func (region *SRegion) ListSecgroups() ([]SSecurityGroup, error) { + secgroups := []SSecurityGroup{} + err := region.list("Microsoft.Network/networkSecurityGroups", url.Values{}, &secgroups) + if err != nil { + return nil, errors.Wrapf(err, "list") + } + return secgroups, nil +} + +func (region *SRegion) GetSecurityGroupDetails(secgroupId string) (*SSecurityGroup, error) { + secgroup := SSecurityGroup{region: region} + return &secgroup, region.get(secgroupId, url.Values{}, &secgroup) +} + +func (self *SSecurityGroup) Refresh() error { + sec, err := self.region.GetSecurityGroupDetails(self.ID) + if err != nil { + return err + } + return jsonutils.Update(self, sec) +} + +func convertRulePort(rule cloudprovider.SecurityRule) []string { + ports := []string{} + if len(rule.Ports) > 0 { + for i := 0; i < len(rule.Ports); i++ { + ports = append(ports, fmt.Sprintf("%d", rule.Ports[i])) + } + return ports + } + if rule.PortStart > 0 && rule.PortEnd < 65535 { + if rule.PortStart == rule.PortEnd { + return []string{fmt.Sprintf("%d", rule.PortStart)} + } + ports = append(ports, fmt.Sprintf("%d-%d", rule.PortStart, rule.PortEnd)) + } + return ports +} + +func convertSecurityGroupRule(rule cloudprovider.SecurityRule) *SecurityRules { + if len(rule.Name) == 0 { + rule.Name = fmt.Sprintf("%s_%d", rule.String(), rule.Priority) + } + rule.Name = func(name string) string { + // 名称必须以字母或数字开头,以字母、数字或下划线结尾,并且只能包含字母、数字、下划线、句点或连字符 + for _, s := range name { + if !(unicode.IsDigit(s) || unicode.IsLetter(s) || s == '.' || s == '-' || s == '_') { + name = strings.ReplaceAll(name, string(s), "_") + } + } + if !unicode.IsDigit(rune(name[0])) && !unicode.IsLetter(rune(name[0])) { + name = fmt.Sprintf("r_%s", name) + } + last := len(name) - 1 + if !unicode.IsDigit(rune(name[last])) && !unicode.IsLetter(rune(name[last])) && name[last] != '_' { + name = fmt.Sprintf("%s_", name) + } + return name + }(rule.Name) + destRule := SecurityRules{ + Name: rule.Name, + Properties: SecurityRulePropertiesFormat{ + Access: utils.Capitalize(string(rule.Action)), + Priority: int32(rule.Priority), + Protocol: "*", + Direction: utils.Capitalize((string(rule.Direction) + "bound")), + Description: rule.Description, + DestinationAddressPrefix: "*", + DestinationPortRanges: convertRulePort(rule), + SourcePortRange: "*", + SourceAddressPrefix: "*", + DestinationPortRange: "*", + }, + } + if rule.Protocol != secrules.PROTO_ANY { + destRule.Properties.Protocol = utils.Capitalize(rule.Protocol) + } + + if len(destRule.Properties.DestinationPortRanges) > 0 { + destRule.Properties.DestinationPortRange = "" + } + + ipAddr := "*" + if rule.IPNet != nil { + ipAddr = rule.IPNet.String() + } + if rule.Direction == secrules.DIR_IN { + destRule.Properties.SourceAddressPrefix = ipAddr + } else { + destRule.Properties.DestinationAddressPrefix = ipAddr + } + return &destRule +} + +func (region *SRegion) AttachSecurityToInterfaces(secgroupId string, nicIds []string) error { + for _, nicId := range nicIds { + nic, err := region.GetNetworkInterface(nicId) + if err != nil { + return err + } + nic.Properties.NetworkSecurityGroup = SSecurityGroup{ID: secgroupId} + if err := region.update(jsonutils.Marshal(nic), nil); err != nil { + return err + } + } + return nil +} + +func (region *SRegion) SetSecurityGroup(instanceId, secgroupId string) error { + instance, err := region.GetInstance(instanceId) + if err != nil { + return err + } + nicIds := []string{} + for _, nic := range instance.Properties.NetworkProfile.NetworkInterfaces { + nicIds = append(nicIds, nic.ID) + } + return region.AttachSecurityToInterfaces(secgroupId, nicIds) +} + +func (self *SSecurityGroup) GetProjectId() string { + return getResourceGroup(self.ID) +} + +func (self *SSecurityGroup) Delete() error { + if self.Properties != nil && self.Properties.NetworkInterfaces != nil { + for _, nic := range *self.Properties.NetworkInterfaces { + nic, err := self.region.GetNetworkInterface(nic.ID) + if err != nil { + return err + } + if err := self.region.update(jsonutils.Marshal(nic), nil); err != nil { + return err + } + } + } + return self.region.del(self.ID) +} + +func (self *SSecurityGroup) SetRules(rules []cloudprovider.SecurityRule) error { + names := []string{} + securityRules := []SecurityRules{} + for i := 0; i < len(rules); i++ { + rule := convertSecurityGroupRule(rules[i]) + if rule != nil { + for { + if !utils.IsInStringArray(rule.Name, names) { + names = append(names, rule.Name) + break + } + rule.Name = fmt.Sprintf("%s_", rule.Name) + } + securityRules = append(securityRules, *rule) + } + } + if self.Properties == nil { + self.Properties = &SecurityGroupPropertiesFormat{} + } + self.Properties.SecurityRules = securityRules + self.Properties.ProvisioningState = "" + return self.region.update(jsonutils.Marshal(self), nil) +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + for i := range common { + switch common[i].Direction { + case secrules.DIR_IN: + inAdds = append(inAdds, common[i]) + case secrules.DIR_OUT: + outAdds = append(outAdds, common[i]) + default: + return fmt.Errorf("invalid rule %s direction %s", common[i].String(), common[i].Direction) + } + } + // Azure 不允许同方向的规则优先级相同 + inRules := cloudprovider.SortUniqPriority(inAdds) + outRules := cloudprovider.SortUniqPriority(outAdds) + rules := append(inRules, outRules...) + return self.SetRules(rules) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/service.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/service.go new file mode 100644 index 0000000000..5daa981fee --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/service.go @@ -0,0 +1,95 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SServices struct { + Value []SService `json:"value,omitempty"` +} + +type SService struct { + ID string `json:"id,omitempty"` + Namespace string `json:"namespace,omitempty"` + RegistrationState string `json:"registrationState,omitempty"` + ResourceTypes []ResourceType `json:"resourceTypes,omitempty"` +} + +type ResourceType struct { + ApiVersions []string `json:"apiVersions,omitempty"` + Capabilities string `json:"capabilities,omitempty"` + Locations []string `json:"locations,omitempty"` + ResourceType string `json:"resourceType,omitempty"` +} + +func (self *SAzureClient) ListServices() ([]SService, error) { + services := []SService{} + return services, self.list("providers", url.Values{}, &services) +} + +func (self *SAzureClient) GetSercice(serviceType string) (*SService, error) { + service := SService{} + return &service, self.get("providers/"+serviceType, url.Values{}, &service) +} + +func (self *SAzureClient) serviceOperation(serviceType, operation string) error { + resource := fmt.Sprintf("subscriptions/%s/providers/%s", self.subscriptionId, serviceType) + _, err := self.perform(resource, operation, nil) + return err +} + +func (self *SAzureClient) waitServiceStatus(serviceType, status string) error { + return cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) { + services, err := self.ListServices() + if err != nil { + return false, errors.Wrapf(err, "ListServices") + } + for _, service := range services { + if strings.ToLower(service.Namespace) == strings.ToLower(serviceType) { + if service.RegistrationState == status { + return true, nil + } + log.Debugf("service %s status: %s expect %s", serviceType, service.RegistrationState, status) + } + } + return false, nil + }) +} + +func (self *SAzureClient) ServiceRegister(serviceType string) error { + err := self.serviceOperation(serviceType, "register") + if err != nil { + return errors.Wrapf(err, "serviceOperation(%s)", "register") + } + return self.waitServiceStatus(serviceType, "Registered") +} + +func (self *SAzureClient) ServiceUnRegister(serviceType string) error { + err := self.serviceOperation(serviceType, "unregister") + if err != nil { + return errors.Wrapf(err, "serviceOperation(%s)", "unregister") + } + return self.waitServiceStatus(serviceType, "NotRegistered") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/snapshot.go new file mode 100644 index 0000000000..3a28568bd0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/snapshot.go @@ -0,0 +1,173 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SnapshotSku struct { + Name string + Tier string +} + +type SSnapshot struct { + multicloud.SResourceBase + AzureTags + region *SRegion + + ID string + Name string + Location string + ManagedBy string + Sku *SnapshotSku + Properties DiskProperties + Type string +} + +func (self *SSnapshot) GetId() string { + return self.ID +} + +func (self *SSnapshot) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SSnapshot) GetName() string { + return self.Name +} + +func (self *SSnapshot) GetStatus() string { + switch self.Properties.ProvisioningState { + case "Succeeded": + return api.SNAPSHOT_READY + default: + log.Errorf("Unknow azure snapshot %s status: %s", self.ID, self.Properties.ProvisioningState) + return api.SNAPSHOT_UNKNOWN + } +} + +func (self *SRegion) CreateSnapshot(diskId, name, desc string) (*SSnapshot, error) { + params := map[string]interface{}{ + "Name": name, + "Location": self.Name, + "Properties": map[string]interface{}{ + "CreationData": map[string]string{ + "CreateOption": "Copy", + "SourceResourceID": diskId, + }, + }, + "Type": "Microsoft.Compute/snapshots", + } + snapshot := &SSnapshot{region: self} + return snapshot, self.create("", jsonutils.Marshal(params), snapshot) +} + +func (self *SSnapshot) Delete() error { + return self.region.DeleteSnapshot(self.ID) +} + +func (self *SSnapshot) GetSizeMb() int32 { + return self.Properties.DiskSizeGB.Int32() * 1024 +} + +func (self *SRegion) DeleteSnapshot(snapshotId string) error { + return self.del(snapshotId) +} + +type AccessURIOutput struct { + AccessSas string +} + +type AccessProperties struct { + Output AccessURIOutput +} + +type AccessURI struct { + Name string + Properties AccessProperties +} + +func (self *SRegion) GrantAccessSnapshot(snapshotId string) (string, error) { + params := map[string]interface{}{ + "access": "Read", + "durationInSeconds": 3600 * 24, + } + body, err := self.perform(snapshotId, "beginGetAccess", jsonutils.Marshal(params)) + if err != nil { + return "", err + } + accessURI := AccessURI{} + return accessURI.Properties.Output.AccessSas, body.Unmarshal(&accessURI) +} + +func (self *SSnapshot) Refresh() error { + snapshot, err := self.region.GetSnapshot(self.ID) + if err != nil { + return err + } + return jsonutils.Update(self, snapshot) +} + +func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + return self.GetSnapshot(snapshotId) +} + +func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := self.ListSnapshots() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudSnapshot{} + for i := range snapshots { + snapshots[i].region = self + ret = append(ret, &snapshots[i]) + } + return ret, nil +} + +func (self *SSnapshot) GetDiskId() string { + return strings.ToLower(self.Properties.CreationData.SourceResourceID) +} + +func (self *SSnapshot) GetDiskType() string { + return "" +} + +func (self *SSnapshot) GetProjectId() string { + return getResourceGroup(self.ID) +} + +func (region *SRegion) GetSnapshot(snapshotId string) (*SSnapshot, error) { + snapshot := SSnapshot{region: region} + return &snapshot, region.get(snapshotId, url.Values{}, &snapshot) +} + +func (region *SRegion) ListSnapshots() ([]SSnapshot, error) { + result := []SSnapshot{} + err := region.list("Microsoft.Compute/snapshots", url.Values{}, &result) + if err != nil { + return nil, err + } + return result, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storage.go new file mode 100644 index 0000000000..9c4be7621e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storage.go @@ -0,0 +1,155 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type Capabilitie struct { + Name string + Value string +} + +const ( + STORAGE_STD_LRS = "Standard_LRS" + STORAGE_PRE_LRS = "Premium_LRS" + STORAGE_STD_SSD = "StandardSSD_LRS" +) + +var STORAGETYPES = []string{STORAGE_STD_LRS, STORAGE_PRE_LRS, STORAGE_STD_SSD} + +type SStorage struct { + multicloud.SStorageBase + AzureTags + zone *SZone + + storageType string + ResourceType string + Tier string + Kind string + Locations []string + Capabilities []Capabilitie +} + +func (self *SStorage) GetId() string { + return fmt.Sprintf("%s/%s", self.zone.GetGlobalId(), strings.ToLower(self.storageType)) +} + +func (self *SStorage) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, strings.ToLower(self.storageType)) +} + +func (self *SStorage) GetGlobalId() string { + return fmt.Sprintf("%s/%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId, strings.ToLower(self.storageType)) +} + +func (self *SStorage) IsEmulated() bool { + return true +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) GetCapacityMB() int64 { + return 0 // unlimited +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + disk, err := self.zone.region.CreateDisk(self.storageType, conf.Name, int32(conf.SizeGb), "", "", conf.ProjectId) + if err != nil { + return nil, err + } + disk.storage = self + return disk, nil +} + +func (self *SStorage) GetIDiskById(diskId string) (cloudprovider.ICloudDisk, error) { + if disk, err := self.zone.region.GetDisk(diskId); err != nil { + return nil, err + } else { + disk.storage = self + return disk, nil + } +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := self.zone.region.GetDisks() + if err != nil { + return nil, err + } + idisks := make([]cloudprovider.ICloudDisk, 0) + for i := 0; i < len(disks); i++ { + storageType := strings.ToLower(string(disks[i].Sku.Name)) + if storageType == strings.ToLower(self.storageType) { + disks[i].storage = self + idisks = append(idisks, &disks[i]) + } + } + return idisks, nil +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.zone.region.getStoragecache() +} + +func (self *SStorage) GetMediumType() string { + if strings.HasPrefix(self.storageType, "premium") { + return api.DISK_TYPE_SSD + } + return api.DISK_TYPE_ROTATE +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + return conf +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) GetStorageType() string { + return strings.ToLower(self.storageType) +} + +func (self *SStorage) Refresh() error { + // do nothing + return nil +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storageaccount.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storageaccount.go new file mode 100644 index 0000000000..bc18a0e627 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storageaccount.go @@ -0,0 +1,1305 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "context" + "encoding/base64" + "fmt" + "io" + "math/rand" + "net/http" + "net/url" + "path" + "strconv" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/storage" + azureenv "github.com/Azure/go-autorest/autorest/azure" + "github.com/Microsoft/azure-vhd-utils/vhdcore/common" + "github.com/Microsoft/azure-vhd-utils/vhdcore/diskstream" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SContainer struct { + storageaccount *SStorageAccount + Name string +} + +type SSku struct { + Name string + Tier string + Kind string + ResourceType string +} + +type Identity struct { + PrincipalID string + TenantID string + Type string +} + +type SStorageEndpoints struct { + Blob string + Queue string + Table string + File string +} + +type AccountProperties struct { + //normal + PrimaryEndpoints SStorageEndpoints `json:"primaryEndpoints,omitempty"` + ProvisioningState string + PrimaryLocation string + SecondaryEndpoints SStorageEndpoints `json:"secondaryEndpoints,omitempty"` + SecondaryLocation string + //CreationTime time.Time + AccessTier string `json:"accessTier,omitempty"` + EnableHTTPSTrafficOnly *bool `json:"supportsHttpsTrafficOnly,omitempty"` + IsHnsEnabled bool `json:"isHnsEnabled,omitempty"` + AzureFilesAadIntegration bool `json:"azureFilesAadIntegration,omitempty"` +} + +type SStorageAccount struct { + multicloud.SBaseBucket + AzureTags + + region *SRegion + + accountKey string + + Sku SSku `json:"sku,omitempty"` + Kind string `json:"kind,omitempty"` + Identity *Identity + Location string `json:"location,omitempty"` + ID string `json:"id,omitempty"` + Name string `json:"name,omitempty"` + Type string `json:"type,omitempty"` + + Properties AccountProperties `json:"properties"` +} + +func (self *SRegion) listStorageAccounts() ([]SStorageAccount, error) { + accounts := []SStorageAccount{} + err := self.list("Microsoft.Storage/storageAccounts", url.Values{}, &accounts) + if err != nil { + return nil, errors.Wrapf(err, "list") + } + result := []SStorageAccount{} + for i := range accounts { + accounts[i].region = self + result = append(result, accounts[i]) + } + return result, nil +} + +func (self *SRegion) ListStorageAccounts() ([]SStorageAccount, error) { + return self.listStorageAccounts() +} + +func randomString(prefix string, length int) string { + bytes := []byte("0123456789abcdefghijklmnopqrstuvwxyz") + result := []byte{} + r := rand.New(rand.NewSource(time.Now().UnixNano())) + for i := 0; i < length; i++ { + result = append(result, bytes[r.Intn(len(bytes))]) + } + return prefix + string(result) +} + +func (self *SRegion) GetUniqStorageAccountName() (string, error) { + for i := 0; i < 20; i++ { + name := randomString("storage", 8) + exist, err := self.checkStorageAccountNameExist(name) + if err == nil && !exist { + return name, nil + } + } + return "", fmt.Errorf("failed to found uniq storage name") +} + +type sNameAvailableOutput struct { + NameAvailable bool `json:"nameAvailable"` + Reason string `json:"reason"` + Message string `json:"message"` +} + +func (self *SRegion) checkStorageAccountNameExist(name string) (bool, error) { + ok, err := self.client.CheckNameAvailability("Microsoft.Storage/storageAccounts", name) + if err != nil { + return false, errors.Wrapf(err, "CheckNameAvailability(%s)", name) + } + return !ok, nil +} + +type SStorageAccountSku struct { + ResourceType string `json:"resourceType"` + Name string `json:"name"` + Tier string `json:"tier"` + Kind string `json:"kind"` + Locations []string `json:"locations"` + Capabilities []struct { + Name string `json:"name"` + Value string `json:"value"` + } `json:"capabilities"` + Restrictions []struct { + Type string `json:"type"` + Values []string `json:"values"` + ReasonCode string `json:"reasonCode"` + } `json:"restrictions"` +} + +func (self *SRegion) GetStorageAccountSkus() ([]SStorageAccountSku, error) { + skus := make([]SStorageAccountSku, 0) + err := self.client.list("Microsoft.Storage/skus", url.Values{}, &skus) + if err != nil { + return nil, errors.Wrap(err, "List") + } + ret := make([]SStorageAccountSku, 0) + for i := range skus { + if utils.IsInStringArray(self.GetId(), skus[i].Locations) { + ret = append(ret, skus[i]) + } + } + return ret, nil +} + +func (self *SRegion) getStorageAccountSkuByName(name string) (*SStorageAccountSku, error) { + skus, err := self.GetStorageAccountSkus() + if err != nil { + return nil, errors.Wrap(err, "getStorageAccountSkus") + } + for _, kind := range []string{ + "StorageV2", + "Storage", + } { + for i := range skus { + if skus[i].Name == name && skus[i].Kind == kind { + return &skus[i], nil + } + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) createStorageAccount(name string, skuName string) (*SStorageAccount, error) { + storageKind := "Storage" + if len(skuName) > 0 { + sku, err := self.getStorageAccountSkuByName(skuName) + if err != nil { + return nil, errors.Wrap(err, "getStorageAccountSkuByName") + } + skuName = sku.Name + storageKind = sku.Kind + } else { + skuName = "Standard_GRS" + } + storageaccount := SStorageAccount{ + region: self, + Location: self.Name, + Sku: SSku{ + Name: skuName, + }, + Kind: storageKind, + Properties: AccountProperties{ + IsHnsEnabled: true, + AzureFilesAadIntegration: true, + }, + Name: name, + Type: "Microsoft.Storage/storageAccounts", + } + + err := self.create("", jsonutils.Marshal(storageaccount), &storageaccount) + if err != nil { + return nil, errors.Wrap(err, "Create") + } + return &storageaccount, nil +} + +func (self *SRegion) CreateStorageAccount(storageAccount string) (*SStorageAccount, error) { + account, err := self.getStorageAccountID(storageAccount) + if err == nil { + return account, nil + } + if errors.Cause(err) == cloudprovider.ErrNotFound { + uniqName, err := self.GetUniqStorageAccountName() + if err != nil { + return nil, errors.Wrapf(err, "GetUniqStorageAccountName") + } + storageaccount := SStorageAccount{ + region: self, + Sku: SSku{ + Name: "Standard_GRS", + }, + Location: self.Name, + Kind: "Storage", + Properties: AccountProperties{ + IsHnsEnabled: true, + AzureFilesAadIntegration: true, + }, + Name: uniqName, + Type: "Microsoft.Storage/storageAccounts", + } + storageaccount.Tags = map[string]string{"id": storageAccount} + return &storageaccount, self.create("", jsonutils.Marshal(storageaccount), &storageaccount) + } + return nil, err +} + +func (self *SRegion) getStorageAccountID(storageAccount string) (*SStorageAccount, error) { + accounts, err := self.ListStorageAccounts() + if err != nil { + return nil, errors.Wrapf(err, "ListStorageAccounts") + } + for i := 0; i < len(accounts); i++ { + for k, v := range accounts[i].Tags { + if k == "id" && v == storageAccount { + accounts[i].region = self + return &accounts[i], nil + } + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetStorageAccountDetail(accountId string) (*SStorageAccount, error) { + account := SStorageAccount{region: self} + err := self.get(accountId, url.Values{}, &account) + if err != nil { + return nil, err + } + return &account, nil +} + +type AccountKeys struct { + KeyName string + Permissions string + Value string +} + +func (self *SRegion) GetStorageAccountKey(accountId string) (string, error) { + body, err := self.perform(accountId, "listKeys", nil) + if err != nil { + return "", err + } + if body.Contains("keys") { + keys := []AccountKeys{} + err = body.Unmarshal(&keys, "keys") + if err != nil { + return "", err + } + for _, key := range keys { + if strings.ToLower(key.Permissions) == "full" { + return key.Value, nil + } + } + return "", fmt.Errorf("not find storageaccount %s key", accountId) + } + return body.GetString("primaryKey") +} + +func (self *SRegion) DeleteStorageAccount(accountId string) error { + return self.del(accountId) +} + +func (self *SRegion) ListClassicStorageAccounts() ([]SStorageAccount, error) { + accounts := make([]SStorageAccount, 0) + err := self.list("Microsoft.ClassicStorage/storageAccounts", url.Values{}, &accounts) + if err != nil { + return nil, err + } + return accounts, nil +} + +func (self *SRegion) GetClassicStorageAccount(id string) (*SStorageAccount, error) { + account := &SStorageAccount{} + err := self.get(id, url.Values{}, account) + if err != nil { + return nil, errors.Wrapf(err, "get(%s)", id) + } + return account, nil +} + +func (self *SStorageAccount) GetAccountKey() (accountKey string, err error) { + if len(self.accountKey) > 0 { + return self.accountKey, nil + } + self.accountKey, err = self.region.GetStorageAccountKey(self.ID) + return self.accountKey, err +} + +func (self *SStorageAccount) getBlobServiceClient() (*storage.BlobStorageClient, error) { + accessKey, err := self.GetAccountKey() + if err != nil { + return nil, err + } + env, err := azureenv.EnvironmentFromName(self.region.client.envName) + if err != nil { + return nil, errors.Wrapf(err, "azureenv.EnvironmentFromName(%s)", self.region.client.envName) + } + client, err := storage.NewBasicClientOnSovereignCloud(self.Name, accessKey, env) + if err != nil { + return nil, err + } + srv := client.GetBlobService() + return &srv, nil +} + +func (self *SStorageAccount) CreateContainer(containerName string) (*SContainer, error) { + blobService, err := self.getBlobServiceClient() + if err != nil { + return nil, errors.Wrap(err, "getBlobServiceClient") + } + containerRef := blobService.GetContainerReference(containerName) + err = containerRef.Create(&storage.CreateContainerOptions{}) + if err != nil { + return nil, errors.Wrap(err, "Create") + } + container := SContainer{ + storageaccount: self, + Name: containerName, + } + return &container, nil +} + +func (self *SStorageAccount) GetContainers() ([]SContainer, error) { + blobService, err := self.getBlobServiceClient() + if err != nil { + return nil, errors.Wrap(err, "getBlobServiceClient") + } + result, err := blobService.ListContainers(storage.ListContainersParameters{}) + if err != nil { + return nil, err + } + containers := []SContainer{} + err = jsonutils.Update(&containers, result.Containers) + if err != nil { + return nil, err + } + for i := 0; i < len(containers); i++ { + containers[i].storageaccount = self + } + return containers, nil +} + +func (self *SStorageAccount) GetContainer(name string) (*SContainer, error) { + containers, err := self.GetContainers() + if err != nil { + return nil, err + } + for i := range containers { + if containers[i].Name == name { + return &containers[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SContainer) ListAllFiles(include *storage.IncludeBlobDataset) ([]storage.Blob, error) { + blobs := make([]storage.Blob, 0) + var marker string + for { + result, err := self.ListFiles("", marker, "", 5000, include) + if err != nil { + return nil, errors.Wrap(err, "ListFiles") + } + if len(result.Blobs) > 0 { + blobs = append(blobs, result.Blobs...) + } + if len(result.NextMarker) == 0 { + break + } else { + marker = result.NextMarker + } + } + return blobs, nil +} + +func (self *SContainer) ListFiles(prefix string, marker string, delimiter string, maxCount int, include *storage.IncludeBlobDataset) (storage.BlobListResponse, error) { + var result storage.BlobListResponse + blobService, err := self.storageaccount.getBlobServiceClient() + if err != nil { + return result, errors.Wrap(err, "getBlobServiceClient") + } + params := storage.ListBlobsParameters{Include: include} + if len(prefix) > 0 { + params.Prefix = prefix + } + if len(marker) > 0 { + params.Marker = marker + } + if len(delimiter) > 0 { + params.Delimiter = delimiter + } + if maxCount > 0 { + params.MaxResults = uint(maxCount) + } + result, err = blobService.GetContainerReference(self.Name).ListBlobs(params) + if err != nil { + return result, err + } + return result, nil +} + +func (self *SContainer) getContainerRef() (*storage.Container, error) { + blobService, err := self.storageaccount.getBlobServiceClient() + if err != nil { + return nil, errors.Wrap(err, "getBlobServiceClient") + } + return blobService.GetContainerReference(self.Name), nil +} + +func (self *SContainer) Delete(fileName string) error { + containerRef, err := self.getContainerRef() + if err != nil { + return err + } + blobRef := containerRef.GetBlobReference(fileName) + _, err = blobRef.DeleteIfExists(&storage.DeleteBlobOptions{}) + return err +} + +func (self *SContainer) CopySnapshot(snapshotId, fileName string) (*storage.Blob, error) { + containerRef, err := self.getContainerRef() + if err != nil { + return nil, err + } + blobRef := containerRef.GetBlobReference(fileName) + uri, err := self.storageaccount.region.GrantAccessSnapshot(snapshotId) + if err != nil { + return nil, err + } + err = blobRef.Copy(uri, &storage.CopyOptions{}) + if err != nil { + return nil, err + } + return blobRef, blobRef.GetProperties(&storage.GetBlobPropertiesOptions{}) +} + +func setBlobRefMeta(blobRef *storage.Blob, meta http.Header) (bool, bool) { + propChanged := false + metaChanged := false + for k, v := range meta { + if len(v) == 0 || len(v[0]) == 0 { + continue + } + switch http.CanonicalHeaderKey(k) { + case cloudprovider.META_HEADER_CACHE_CONTROL: + blobRef.Properties.CacheControl = v[0] + propChanged = true + case cloudprovider.META_HEADER_CONTENT_TYPE: + blobRef.Properties.ContentType = v[0] + propChanged = true + case cloudprovider.META_HEADER_CONTENT_MD5: + blobRef.Properties.ContentMD5 = v[0] + propChanged = true + case cloudprovider.META_HEADER_CONTENT_ENCODING: + blobRef.Properties.ContentEncoding = v[0] + propChanged = true + case cloudprovider.META_HEADER_CONTENT_LANGUAGE: + blobRef.Properties.ContentLanguage = v[0] + propChanged = true + case cloudprovider.META_HEADER_CONTENT_DISPOSITION: + blobRef.Properties.ContentDisposition = v[0] + propChanged = true + default: + if blobRef.Metadata == nil { + blobRef.Metadata = storage.BlobMetadata{} + } + blobRef.Metadata[k] = v[0] + metaChanged = true + } + } + return propChanged, metaChanged +} + +func (self *SContainer) UploadStream(key string, reader io.Reader, meta http.Header) error { + blobService, err := self.storageaccount.getBlobServiceClient() + if err != nil { + return errors.Wrap(err, "getBlobServiceClient") + } + containerRef := blobService.GetContainerReference(self.Name) + blobRef := containerRef.GetBlobReference(key) + blobRef.Properties.BlobType = storage.BlobTypeBlock + if meta != nil { + setBlobRefMeta(blobRef, meta) + } + return blobRef.CreateBlockBlobFromReader(reader, &storage.PutBlobOptions{}) +} + +func (self *SContainer) SignUrl(method string, key string, expire time.Duration) (string, error) { + blobService, err := self.storageaccount.getBlobServiceClient() + if err != nil { + return "", errors.Wrap(err, "getBlobServiceClient") + } + containerRef := blobService.GetContainerReference(self.Name) + sas := storage.BlobSASOptions{} + sas.Start = time.Now() + sas.Expiry = sas.Start.Add(expire) + sas.UseHTTPS = true + switch method { + case "GET": + sas.Read = true + case "PUT": + sas.Read = true + sas.Add = true + sas.Create = true + sas.Write = true + case "DELETE": + sas.Read = true + sas.Write = true + sas.Delete = true + default: + return "", errors.Error("unsupport method") + } + blobRef := containerRef.GetBlobReference(key) + return blobRef.GetSASURI(sas) +} + +func (self *SContainer) UploadFile(filePath string, callback func(progress float32)) (string, error) { + blobService, err := self.storageaccount.getBlobServiceClient() + if err != nil { + return "", errors.Wrap(err, "getBlobServiceClient") + } + containerRef := blobService.GetContainerReference(self.Name) + + err = ensureVHDSanity(filePath) + if err != nil { + return "", err + } + diskStream, err := diskstream.CreateNewDiskStream(filePath) + if err != nil { + return "", err + } + defer diskStream.Close() + blobName := path.Base(filePath) + blobRef := containerRef.GetBlobReference(blobName) + blobRef.Properties.ContentLength = diskStream.GetSize() + err = blobRef.PutPageBlob(&storage.PutBlobOptions{}) + if err != nil { + return "", err + } + var rangesToSkip []*common.IndexRange + uploadableRanges, err := LocateUploadableRanges(diskStream, rangesToSkip, DefaultReadBlockSize) + if err != nil { + return "", err + } + uploadableRanges, err = DetectEmptyRanges(diskStream, uploadableRanges) + if err != nil { + return "", err + } + + cxt := &DiskUploadContext{ + VhdStream: diskStream, + UploadableRanges: uploadableRanges, + AlreadyProcessedBytes: common.TotalRangeLength(rangesToSkip), + BlobServiceClient: *blobService, + ContainerName: self.Name, + BlobName: blobName, + Parallelism: 3, + Resume: false, + MD5Hash: []byte(""), //localMetaData.FileMetaData.MD5Hash, + } + + if err := Upload(cxt, callback); err != nil { + return "", err + } + return blobRef.GetURL(), nil +} + +func (self *SContainer) getAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + containerRef, err := self.getContainerRef() + if err != nil { + log.Errorf("getContainerRef fail %s", err) + return acl + } + output, err := containerRef.GetPermissions(nil) + if err != nil { + log.Errorf("containerRef.GetPermissions fail %s", err) + return acl + } + switch output.AccessType { + case storage.ContainerAccessTypePrivate: + acl = cloudprovider.ACLPrivate + case storage.ContainerAccessTypeContainer: + acl = cloudprovider.ACLPublicRead + } + return acl +} + +func (self *SContainer) setAcl(aclStr cloudprovider.TBucketACLType) error { + perm := storage.ContainerPermissions{} + switch aclStr { + case cloudprovider.ACLPublicRead: + perm.AccessType = storage.ContainerAccessTypeContainer + case cloudprovider.ACLPrivate: + perm.AccessType = storage.ContainerAccessTypePrivate + default: + return errors.Error("unsupported ACL:" + string(aclStr)) + } + containerRef, err := self.getContainerRef() + if err != nil { + return errors.Wrap(err, "getContainerRef") + } + err = containerRef.SetPermissions(perm, nil) + if err != nil { + return errors.Wrap(err, "SetPermissions") + } + return nil +} + +func (self *SStorageAccount) UploadFile(containerName string, filePath string, callback func(progress float32)) (string, error) { + container, err := self.getOrCreateContainer(containerName, true) + if err != nil { + return "", errors.Wrap(err, "getOrCreateContainer") + } + return container.UploadFile(filePath, callback) +} + +func (self *SStorageAccount) getOrCreateContainer(containerName string, create bool) (*SContainer, error) { + containers, err := self.GetContainers() + if err != nil { + return nil, errors.Wrap(err, "GetContainers") + } + var container *SContainer + find := false + for i := 0; i < len(containers); i++ { + if containers[i].Name == containerName { + container = &containers[i] + find = true + break + } + } + if !find { + if !create { + return nil, cloudprovider.ErrNotFound + } + container, err = self.CreateContainer(containerName) + if err != nil { + return nil, errors.Wrap(err, "CreateContainer") + } + } + return container, nil +} + +func (self *SStorageAccount) UploadStream(containerName string, key string, reader io.Reader, meta http.Header) error { + container, err := self.getOrCreateContainer(containerName, true) + if err != nil { + return errors.Wrap(err, "getOrCreateContainer") + } + return container.UploadStream(key, reader, meta) +} + +func (b *SStorageAccount) MaxPartSizeBytes() int64 { + return 100 * 1000 * 1000 +} + +func (b *SStorageAccount) MaxPartCount() int { + return 50000 +} + +func (b *SStorageAccount) GetTags() (map[string]string, error) { + return b.Tags, nil +} + +func (b *SStorageAccount) GetProjectId() string { + return getResourceGroup(b.ID) +} + +func (b *SStorageAccount) GetGlobalId() string { + return b.Name +} + +func (b *SStorageAccount) GetName() string { + return b.Name +} + +func (b *SStorageAccount) GetLocation() string { + return b.Location +} + +func (b *SStorageAccount) GetIRegion() cloudprovider.ICloudRegion { + return b.region +} + +func (b *SStorageAccount) GetCreatedAt() time.Time { + return time.Time{} +} + +func (b *SStorageAccount) GetStorageClass() string { + return b.Sku.Tier +} + +// get the common ACL of all containers +func (b *SStorageAccount) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + containers, err := b.GetContainers() + if err != nil { + log.Errorf("GetContainers error %s", err) + return acl + } + for i := range containers { + aclC := containers[i].getAcl() + if i == 0 { + if aclC != acl { + acl = aclC + } + } else if aclC != acl { + acl = cloudprovider.ACLPrivate + } + } + return acl +} + +func (b *SStorageAccount) SetAcl(aclStr cloudprovider.TBucketACLType) error { + containers, err := b.GetContainers() + if err != nil { + return errors.Wrap(err, "GetContainers") + } + for i := range containers { + err = containers[i].setAcl(aclStr) + if err != nil { + return errors.Wrap(err, "containers.setAcl") + } + } + return nil +} + +func getDesc(prefix, name string) string { + if len(prefix) > 0 { + return prefix + "-" + name + } else { + return name + } +} + +func (ep SStorageEndpoints) getUrls(prefix string) []cloudprovider.SBucketAccessUrl { + ret := make([]cloudprovider.SBucketAccessUrl, 0) + if len(ep.Blob) > 0 { + ret = append(ret, cloudprovider.SBucketAccessUrl{ + Url: ep.Blob, + Description: getDesc(prefix, "blob"), + Primary: true, + }) + } + if len(ep.Queue) > 0 { + ret = append(ret, cloudprovider.SBucketAccessUrl{ + Url: ep.Queue, + Description: getDesc(prefix, "queue"), + }) + } + if len(ep.Table) > 0 { + ret = append(ret, cloudprovider.SBucketAccessUrl{ + Url: ep.Table, + Description: getDesc(prefix, "table"), + }) + } + if len(ep.File) > 0 { + ret = append(ret, cloudprovider.SBucketAccessUrl{ + Url: ep.File, + Description: getDesc(prefix, "file"), + }) + } + return ret +} + +func (b *SStorageAccount) GetAccessUrls() []cloudprovider.SBucketAccessUrl { + primary := b.Properties.PrimaryEndpoints.getUrls("") + secondary := b.Properties.SecondaryEndpoints.getUrls("secondary") + if len(secondary) > 0 { + primary = append(primary, secondary...) + } + return primary +} + +func (b *SStorageAccount) GetStats() cloudprovider.SBucketStats { + stats, _ := cloudprovider.GetIBucketStats(b) + return stats +} + +func getBlobRefMeta(blob *storage.Blob) http.Header { + meta := http.Header{} + for k, v := range blob.Metadata { + meta.Add(k, v) + } + if len(blob.Properties.CacheControl) > 0 { + meta.Set(cloudprovider.META_HEADER_CACHE_CONTROL, blob.Properties.CacheControl) + } + if len(blob.Properties.ContentType) > 0 { + meta.Set(cloudprovider.META_HEADER_CONTENT_TYPE, blob.Properties.ContentType) + } + if len(blob.Properties.ContentDisposition) > 0 { + meta.Set(cloudprovider.META_HEADER_CONTENT_DISPOSITION, blob.Properties.ContentDisposition) + } + if len(blob.Properties.ContentLanguage) > 0 { + meta.Set(cloudprovider.META_HEADER_CONTENT_LANGUAGE, blob.Properties.ContentLanguage) + } + if len(blob.Properties.ContentEncoding) > 0 { + meta.Set(cloudprovider.META_HEADER_CONTENT_ENCODING, blob.Properties.ContentEncoding) + } + if len(blob.Properties.ContentMD5) > 0 { + meta.Set(cloudprovider.META_HEADER_CONTENT_MD5, blob.Properties.ContentMD5) + } + return meta +} + +func (b *SStorageAccount) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { + result := cloudprovider.SListObjectResult{} + containers, err := b.GetContainers() + if err != nil { + return result, errors.Wrap(err, "GetContainers") + } + result.Objects = make([]cloudprovider.ICloudObject, 0) + result.CommonPrefixes = make([]cloudprovider.ICloudObject, 0) + for i := 0; i < len(containers); i += 1 { + container := containers[i] + matchLen := len(container.Name) + if matchLen > len(prefix) { + matchLen = len(prefix) + } + var subMarker string + if len(marker) < len(container.Name) { + if marker > container.Name { + continue + } + subMarker = "" + } else { + containerMarker := marker[:len(container.Name)] + if containerMarker > container.Name { + continue + } + subMarker = marker[len(container.Name)+1:] + } + if marker > container.Name { + continue + } + if maxCount <= 0 { + break + } + // container name matches prefix + if container.Name[:matchLen] == prefix[:matchLen] && (len(prefix) <= len(container.Name) || strings.HasPrefix(prefix, container.Name+"/")) { + if delimiter == "/" && len(prefix) == 0 { + // populate CommonPrefixes + o := &SObject{ + container: &container, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + Key: container.Name + "/", + }, + } + result.CommonPrefixes = append(result.CommonPrefixes, o) + maxCount -= 1 + } else if delimiter == "/" && prefix == container.Name+delimiter { + // do nothing + } else if len(prefix) <= len(container.Name)+1 { + // returns contain names only + o := &SObject{ + container: &container, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + Key: container.Name + "/", + }, + } + result.Objects = append(result.Objects, o) + maxCount -= 1 + } + if delimiter == "" || len(prefix) >= len(container.Name)+1 { + subPrefix := "" + if len(prefix) >= len(container.Name)+1 { + subPrefix = prefix[len(container.Name)+1:] + } + oResult, err := container.ListFiles(subPrefix, subMarker, delimiter, maxCount, nil) + if err != nil { + return result, errors.Wrap(err, "ListFiles") + } + for i := range oResult.Blobs { + blob := oResult.Blobs[i] + o := &SObject{ + container: &container, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + Key: container.Name + "/" + blob.Name, + SizeBytes: blob.Properties.ContentLength, + StorageClass: "", + ETag: blob.Properties.Etag, + LastModified: time.Time(blob.Properties.LastModified), + }, + } + result.Objects = append(result.Objects, o) + maxCount -= 1 + if maxCount == 0 { + break + } + result.NextMarker = blob.Name + } + for i := range oResult.BlobPrefixes { + o := &SObject{ + container: &container, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + Key: container.Name + "/" + oResult.BlobPrefixes[i], + }, + } + result.CommonPrefixes = append(result.CommonPrefixes, o) + maxCount -= 1 + } + if len(oResult.NextMarker) > 0 { + result.NextMarker = container.Name + "/" + oResult.NextMarker + result.IsTruncated = true + break + } + } + } + } + return result, nil +} + +func splitKey(key string) (string, string, error) { + slashPos := strings.IndexByte(key, '/') + if slashPos <= 0 { + return "", "", errors.Wrap(httperrors.ErrForbidden, "cannot put object to root") + } + containerName := key[:slashPos] + key = key[slashPos+1:] + return containerName, key, nil +} + +func splitKeyAndBlob(path string) (string, string, error) { + containerName, key, err := splitKey(path) + if err != nil { + return "", "", errors.Wrapf(err, "splitKey: %s", path) + } + if len(key) == 0 { + return "", "", errors.Error("empty blob path") + } + return containerName, key, nil +} + +func (b *SStorageAccount) PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + containerName, blob, err := splitKey(key) + if err != nil { + return errors.Wrap(err, "splitKey") + } + if len(blob) > 0 { + // put blob + err = b.UploadStream(containerName, blob, reader, meta) + if err != nil { + return errors.Wrap(err, "UploadStream") + } + } else { + // create container + if sizeBytes > 0 { + return errors.Wrap(httperrors.ErrForbidden, "not allow to create blob outsize of container") + } + _, err = b.getOrCreateContainer(containerName, true) + if err != nil { + return errors.Wrap(err, "getOrCreateContainer") + } + } + return nil +} + +func (b *SStorageAccount) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + containerName, blob, err := splitKeyAndBlob(key) + if err != nil { + return "", errors.Wrap(err, "splitKey") + } + container, err := b.getOrCreateContainer(containerName, true) + if err != nil { + return "", errors.Wrap(err, "getOrCreateContainer") + } + containerRef, err := container.getContainerRef() + if err != nil { + return "", errors.Wrap(err, "getContainerRef") + } + blobRef := containerRef.GetBlobReference(blob) + if meta != nil { + setBlobRefMeta(blobRef, meta) + } + err = blobRef.CreateBlockBlob(&storage.PutBlobOptions{}) + if err != nil { + return "", errors.Wrap(err, "CreateBlockBlob") + } + uploadId, err := blobRef.AcquireLease(-1, "", nil) + if err != nil { + return "", errors.Wrap(err, "blobRef.AcquireLease") + } + + return uploadId, nil +} + +func partIndex2BlockId(partIndex int) string { + return base64.URLEncoding.EncodeToString([]byte(strconv.FormatInt(int64(partIndex), 10))) +} + +func (b *SStorageAccount) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { + containerName, blob, err := splitKeyAndBlob(key) + if err != nil { + return "", errors.Wrap(err, "splitKey") + } + container, err := b.getOrCreateContainer(containerName, true) + if err != nil { + return "", errors.Wrap(err, "getOrCreateContainer") + } + containerRef, err := container.getContainerRef() + if err != nil { + return "", errors.Wrap(err, "getContainerRef") + } + blobRef := containerRef.GetBlobReference(blob) + + opts := &storage.PutBlockOptions{} + opts.LeaseID = uploadId + + blockId := partIndex2BlockId(partIndex) + err = blobRef.PutBlockWithLength(blockId, uint64(partSize), input, opts) + if err != nil { + return "", errors.Wrap(err, "PutBlockWithLength") + } + + return blockId, nil +} + +func (b *SStorageAccount) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, blockIds []string) error { + containerName, blob, err := splitKeyAndBlob(key) + if err != nil { + return errors.Wrap(err, "splitKey") + } + container, err := b.getOrCreateContainer(containerName, true) + if err != nil { + return errors.Wrap(err, "getOrCreateContainer") + } + containerRef, err := container.getContainerRef() + if err != nil { + return errors.Wrap(err, "getContainerRef") + } + blobRef := containerRef.GetBlobReference(blob) + + blocks := make([]storage.Block, len(blockIds)) + for i := range blockIds { + blocks[i] = storage.Block{ + ID: blockIds[i], + Status: storage.BlockStatusLatest, + } + } + opts := &storage.PutBlockListOptions{} + opts.LeaseID = uploadId + err = blobRef.PutBlockList(blocks, opts) + if err != nil { + return errors.Wrap(err, "PutBlockList") + } + + err = blobRef.ReleaseLease(uploadId, nil) + if err != nil { + return errors.Wrap(err, "ReleaseLease") + } + + return nil +} + +func (b *SStorageAccount) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { + containerName, blob, err := splitKeyAndBlob(key) + if err != nil { + return errors.Wrap(err, "splitKey") + } + container, err := b.getOrCreateContainer(containerName, false) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return errors.Wrap(err, "getOrCreateContainer") + } + containerRef, err := container.getContainerRef() + if err != nil { + return errors.Wrap(err, "getContainerRef") + } + + blobRef := containerRef.GetBlobReference(blob) + err = blobRef.ReleaseLease(uploadId, nil) + if err != nil { + return errors.Wrap(err, "ReleaseLease") + } + + opts := &storage.DeleteBlobOptions{} + deleteSnapshots := true + opts.DeleteSnapshots = &deleteSnapshots + _, err = blobRef.DeleteIfExists(opts) + if err != nil { + return errors.Wrap(err, "DeleteIfExists") + } + + return nil +} + +func (b *SStorageAccount) DeleteObject(ctx context.Context, key string) error { + containerName, blob, err := splitKey(key) + if err != nil { + return errors.Wrap(err, "splitKey") + } + blobService, err := b.getBlobServiceClient() + if err != nil { + return errors.Wrap(err, "getBlobServiceClient") + } + containerRef := blobService.GetContainerReference(containerName) + if len(blob) > 0 { + // delete object + blobRef := containerRef.GetBlobReference(blob) + _, err = blobRef.DeleteIfExists(nil) + if err != nil { + return errors.Wrap(err, "blobRef.DeleteIfExists") + } + } else { + // delete container + _, err = containerRef.DeleteIfExists(nil) + if err != nil { + return errors.Wrap(err, "containerRef.DeleteIfExists") + } + } + return nil +} + +func (b *SStorageAccount) GetTempUrl(method string, key string, expire time.Duration) (string, error) { + containerName, blob, err := splitKeyAndBlob(key) + if err != nil { + return "", errors.Wrap(err, "splitKey") + } + container, err := b.getOrCreateContainer(containerName, false) + if err != nil { + return "", errors.Wrap(err, "getOrCreateContainer") + } + return container.SignUrl(method, blob, expire) +} + +func (b *SStorageAccount) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + srcIBucket, err := b.region.GetIBucketByName(srcBucket) + if err != nil { + return errors.Wrap(err, "GetIBucketByName") + } + srcAccount := srcIBucket.(*SStorageAccount) + srcContName, srcBlob, err := splitKeyAndBlob(srcKey) + if err != nil { + return errors.Wrap(err, "src splitKey") + } + srcCont, err := srcAccount.getOrCreateContainer(srcContName, false) + if err != nil { + return errors.Wrap(err, "src getOrCreateContainer") + } + srcContRef, err := srcCont.getContainerRef() + if err != nil { + return errors.Wrap(err, "src getContainerRef") + } + srcBlobRef := srcContRef.GetBlobReference(srcBlob) + + containerName, blobName, err := splitKeyAndBlob(destKey) + if err != nil { + return errors.Wrap(err, "dest splitKey") + } + container, err := b.getOrCreateContainer(containerName, true) + if err != nil { + return errors.Wrap(err, "dest getOrCreateContainer") + } + containerRef, err := container.getContainerRef() + if err != nil { + return errors.Wrap(err, "dest getContainerRef") + } + blobRef := containerRef.GetBlobReference(blobName) + if meta != nil { + setBlobRefMeta(blobRef, meta) + } + opts := &storage.CopyOptions{} + err = blobRef.Copy(srcBlobRef.GetURL(), opts) + if err != nil { + return errors.Wrap(err, "blboRef.Copy") + } + return nil +} + +func (b *SStorageAccount) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { + containerName, blob, err := splitKeyAndBlob(key) + if err != nil { + return nil, errors.Wrap(err, "splitKey") + } + container, err := b.getOrCreateContainer(containerName, false) + if err != nil { + return nil, errors.Wrap(err, "getOrCreateContainer") + } + containerRef, err := container.getContainerRef() + if err != nil { + return nil, errors.Wrap(err, "container.getContainerRef") + } + blobRef := containerRef.GetBlobReference(blob) + if rangeOpt != nil { + opts := &storage.GetBlobRangeOptions{} + opts.Range = &storage.BlobRange{ + Start: uint64(rangeOpt.Start), + End: uint64(rangeOpt.End), + } + return blobRef.GetRange(opts) + } else { + opts := &storage.GetBlobOptions{} + return blobRef.Get(opts) + } +} + +func (b *SStorageAccount) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { + srcIBucket, err := b.region.GetIBucketByName(srcBucket) + if err != nil { + return "", errors.Wrap(err, "GetIBucketByName") + } + srcAccount := srcIBucket.(*SStorageAccount) + srcContName, srcBlob, err := splitKeyAndBlob(srcKey) + if err != nil { + return "", errors.Wrap(err, "src splitKey") + } + srcCont, err := srcAccount.getOrCreateContainer(srcContName, false) + if err != nil { + return "", errors.Wrap(err, "src getOrCreateContainer") + } + srcContRef, err := srcCont.getContainerRef() + if err != nil { + return "", errors.Wrap(err, "src getContainerRef") + } + srcBlobRef := srcContRef.GetBlobReference(srcBlob) + + containerName, blob, err := splitKeyAndBlob(key) + if err != nil { + return "", errors.Wrap(err, "splitKey") + } + container, err := b.getOrCreateContainer(containerName, true) + if err != nil { + return "", errors.Wrap(err, "getOrCreateContainer") + } + containerRef, err := container.getContainerRef() + if err != nil { + return "", errors.Wrap(err, "getContainerRef") + } + blobRef := containerRef.GetBlobReference(blob) + + opts := &storage.PutBlockFromURLOptions{} + opts.LeaseID = uploadId + + blockId := partIndex2BlockId(partIndex) + err = blobRef.PutBlockFromURL(blockId, srcBlobRef.GetURL(), srcOffset, uint64(srcLength), opts) + if err != nil { + return "", errors.Wrap(err, "PutBlockFromUrl") + } + + return blockId, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storagecache.go new file mode 100644 index 0000000000..585316cc26 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/storagecache.go @@ -0,0 +1,290 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "context" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/fileutils2" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +const ( + DefaultStorageAccount string = "image" + DefaultContainer string = "image-cache" + + DefaultReadBlockSize int64 = 4 * 1024 * 1024 +) + +type SStoragecache struct { + multicloud.SResourceBase + AzureTags + region *SRegion +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) +} + +func (self *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) Refresh() error { + return nil +} + +func (self *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetGlobalId()) +} + +func (self *SStoragecache) IsEmulated() bool { + return false +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + images, err := self.region.GetImages(cloudprovider.ImageTypeCustomized) + if err != nil { + return nil, errors.Wrapf(err, "GetImages") + } + ret := []cloudprovider.ICloudImage{} + for i := 0; i < len(images); i++ { + images[i].storageCache = self + ret = append(ret, &images[i]) + } + return ret, nil +} + +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + img, err := self.region.GetImageById(extId) + if err != nil { + return nil, err + } + img.storageCache = self + return &img, nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + err := os.MkdirAll(options.Options.TempPath, os.ModePerm) + if err != nil { + log.Warningf("failed to create tmp path %s error: %v", options.Options.TempPath, err) + } + return self.uploadImage(ctx, userCred, image, options.Options.TempPath, callback) +} + +func (self *SStoragecache) checkStorageAccount() (*SStorageAccount, error) { + storageaccounts, err := self.region.ListStorageAccounts() + if err != nil { + return nil, errors.Wrap(err, "ListStorageAccounts") + } + if len(storageaccounts) == 0 { + storageaccount, err := self.region.CreateStorageAccount(self.region.Name) + if err != nil { + return nil, errors.Wrap(err, "CreateStorageAccount") + } + return storageaccount, nil + } + for i := 0; i < len(storageaccounts); i++ { + if id, ok := storageaccounts[i].Tags["id"]; ok && id == self.region.Name { + return &storageaccounts[i], nil + } + } + + storageaccount := &storageaccounts[0] + if storageaccount.Tags == nil { + storageaccount.Tags = map[string]string{} + } + storageaccount.Tags["id"] = self.region.Name + err = self.region.update(jsonutils.Marshal(storageaccount), nil) + if err != nil { + return nil, errors.Wrapf(err, "Update(%s)", jsonutils.Marshal(storageaccount).String()) + } + return storageaccount, nil +} + +func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, tmpPath string, callback func(progress float32)) (string, error) { + s := auth.GetAdminSession(ctx, options.Options.Region) + meta, reader, sizeBytes, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VHD), false) + if err != nil { + return "", err + } + // { + // "checksum":"d0ab0450979977c6ada8d85066a6e484", + // "container_format":"bare", + // "created_at":"2018-08-10T04:18:07", + // "deleted":"False", + // "disk_format":"vhd", + // "id":"64189033-3ad4-413c-b074-6bf0b6be8508", + // "is_public":"False", + // "min_disk":"0", + // "min_ram":"0", + // "name":"centos-7.3.1611-20180104.vhd", + // "owner":"5124d80475434da8b41fee48d5be94df", + // "properties":{ + // "os_arch":"x86_64", + // "os_distribution":"CentOS", + // "os_type":"Linux", + // "os_version":"7.3.1611-VHD" + // }, + // "protected":"False", + // "size":"2028505088", + // "status":"active", + // "updated_at":"2018-08-10T04:20:59" + // } + log.Infof("meta data %s", meta) + + imageNameOnBlob, _ := meta.GetString("name") + if !strings.HasSuffix(imageNameOnBlob, ".vhd") { + imageNameOnBlob = fmt.Sprintf("%s.vhd", imageNameOnBlob) + } + tmpFile := fmt.Sprintf("%s/%s", tmpPath, imageNameOnBlob) + defer os.Remove(tmpFile) + f, err := os.Create(tmpFile) + if err != nil { + return "", errors.Wrap(err, "os.Create(tmpFile)") + } + defer f.Close() + + // 下载占33% + r := multicloud.NewProgress(sizeBytes, 33, reader, callback) + if _, err := io.Copy(f, r); err != nil { + return "", errors.Wrap(err, "io.Copy(f, reader)") + } + + storageaccount, err := self.checkStorageAccount() + if err != nil { + return "", errors.Wrap(err, "self.checkStorageAccount") + } + + blobURI, err := storageaccount.UploadFile("image-cache", tmpFile, callback) + if err != nil { + return "", errors.Wrap(err, "storageaccount.UploadFile") + } + + // size, _ := meta.Int("size") + + img, err := self.region.CreateImageByBlob(image.ImageId, image.OsType, blobURI, int32(sizeBytes>>30)) + if err != nil { + return "", errors.Wrap(err, "CreateImageByBlob") + } + if callback != nil { + callback(100) + } + return img.GetGlobalId(), nil +} + +func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + if image, err := self.region.CreateImage(snapshotId, imageName, osType, imageDesc); err != nil { + return nil, err + } else { + image.storageCache = self + return image, nil + } +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return self.downloadImage(userCred, imageId, extId, path) +} + +func (self *SStoragecache) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + // TODO: need to fix scenarios where image is a public image + // XXX Qiu Jian + if image, err := self.region.getPrivateImage(extId); err != nil { + return nil, err + } else if snapshotId := image.Properties.StorageProfile.OsDisk.Snapshot.ID; len(snapshotId) == 0 { + return nil, cloudprovider.ErrNotFound + } else if uri, err := self.region.GrantAccessSnapshot(snapshotId); err != nil { + return nil, err + } else if resp, err := http.Get(uri); err != nil { + return nil, err + } else { + tmpImageFile, err := ioutil.TempFile(path, "temp") + if err != nil { + return nil, err + } + defer tmpImageFile.Close() + defer os.Remove(tmpImageFile.Name()) + { + sf := fileutils2.NewSparseFileWriter(tmpImageFile) + data := make([]byte, DefaultReadBlockSize) + written := int64(0) + for { + n, err := resp.Body.Read(data) + if n > 0 { + if n, err := sf.Write(data); err != nil { + return nil, err + } else { + written += int64(n) + } + } else if err == io.EOF { + if written <= resp.ContentLength { + return nil, fmt.Errorf("got eof: expecting %d bytes, got %d", resp.ContentLength, written) + } + break + } else { + return nil, err + } + } + if err := sf.PreClose(); err != nil { + return nil, err + } + } + + if _, err := tmpImageFile.Seek(0, os.SEEK_SET); err != nil { + return nil, errors.Wrap(err, "seek") + } + s := auth.GetAdminSession(context.Background(), options.Options.Region) + params := jsonutils.Marshal(map[string]string{"image_id": imageId, "disk-format": "raw"}) + if result, err := modules.Images.Upload(s, params, tmpImageFile, resp.ContentLength); err != nil { + return nil, err + } else { + return result, nil + } + + } +} + +func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storageCache := region.getStoragecache() + return []cloudprovider.ICloudStoragecache{storageCache}, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/subscription.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/subscription.go new file mode 100644 index 0000000000..a7fd5ea286 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/subscription.go @@ -0,0 +1,40 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "net/url" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +type SSubscription struct { + SubscriptionId string `json:"subscriptionId"` + State string + DisplayName string `json:"displayName"` +} + +func (self *SSubscription) GetHealthStatus() string { + if self.State == "Enabled" { + return api.CLOUD_PROVIDER_HEALTH_NORMAL + } + return api.CLOUD_PROVIDER_HEALTH_SUSPENDED +} + +func (self *SAzureClient) ListSubscriptions() ([]SSubscription, error) { + result := []SSubscription{} + err := self.list("subscriptions", url.Values{}, &result) + return result, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/tag_base.go new file mode 100644 index 0000000000..dbb6796173 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/tag_base.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type AzureTags struct { + Tags map[string]string +} + +func (self *AzureTags) GetTags() (map[string]string, error) { + return self.Tags, nil +} + +func (self *AzureTags) GetSysTags() map[string]string { + return nil +} + +func (self *AzureTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/pkg/multicloud/azure/upload.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/upload.go similarity index 98% rename from pkg/multicloud/azure/upload.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/upload.go index 026eb631eb..f484d0b02c 100644 --- a/pkg/multicloud/azure/upload.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/upload.go @@ -29,8 +29,8 @@ import ( "github.com/Microsoft/azure-vhd-utils/vhdcore/footer" "github.com/Microsoft/azure-vhd-utils/vhdcore/validator" - "yunion.io/x/onecloud/pkg/multicloud/azure/concurrent" - "yunion.io/x/onecloud/pkg/multicloud/azure/progress" + "yunion.io/x/cloudmux/pkg/multicloud/azure/concurrent" + "yunion.io/x/cloudmux/pkg/multicloud/azure/progress" ) // DiskUploadContext type describes VHD upload context, this includes the disk stream to read from, the ranges of diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/usage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/usage.go new file mode 100644 index 0000000000..79ac1c48f2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/usage.go @@ -0,0 +1,82 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type UsageName struct { + Value string + LocalizedValue string +} + +// {"value":[{"unit":"Count","currentValue":0,"limit":250,"name":{"value":"StorageAccounts","localizedValue":"Storage Accounts"}}]} +type SUsage struct { + Unit string + CurrentValue int + Limit int + Name UsageName +} + +func (u *SUsage) GetGlobalId() string { + return strings.ToLower(u.Name.Value) +} + +func (u *SUsage) GetQuotaType() string { + return u.Name.Value +} + +func (u *SUsage) GetDesc() string { + return u.Name.LocalizedValue +} + +func (u *SUsage) GetMaxQuotaCount() int { + return u.Limit +} + +func (u *SUsage) GetCurrentQuotaUsedCount() int { + return u.CurrentValue +} + +func (region *SRegion) GetUsage(resourceType string) ([]SUsage, error) { + usage := []SUsage{} + resource := fmt.Sprintf("%s/locations/%s/usages", resourceType, region.Name) + err := region.client.list(resource, url.Values{}, &usage) + if err != nil { + return nil, errors.Wrapf(err, "ListAll(%s)", resource) + } + return usage, nil +} + +func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { + ret := []cloudprovider.ICloudQuota{} + for _, resourceType := range []string{"Microsoft.Network", "Microsoft.Storage", "Microsoft.Compute"} { + usages, err := region.GetUsage(resourceType) + if err != nil { + return nil, errors.Wrap(err, "GetUsage") + } + for i := range usages { + ret = append(ret, &usages[i]) + } + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/vpc.go new file mode 100644 index 0000000000..216dea656a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/vpc.go @@ -0,0 +1,167 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type AddressSpace struct { + AddressPrefixes []string `json:"addressPrefixes,omitempty"` +} + +type SubnetPropertiesFormat struct { + AddressPrefix string `json:"addressPrefix,omitempty"` + //ProvisioningState string +} + +type VirtualNetworkPropertiesFormat struct { + ProvisioningState string + Status string + VirtualNetworkSiteName string + AddressSpace AddressSpace `json:"addressSpace,omitempty"` + Subnets []SNetwork `json:"subnets,omitempty"` +} + +type SVpc struct { + multicloud.SVpc + AzureTags + region *SRegion + + ID string + Name string + Etag string + Type string + Location string + Properties VirtualNetworkPropertiesFormat `json:"properties,omitempty"` +} + +func (self *SVpc) GetTags() (map[string]string, error) { + return self.Tags, nil +} + +func (self *SVpc) GetId() string { + return self.ID +} + +func (self *SVpc) GetName() string { + return self.Name +} + +func (self *SVpc) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SVpc) IsEmulated() bool { + return false +} + +func (self *SVpc) GetIsDefault() bool { + return true +} + +func (self *SVpc) GetCidrBlock() string { + if len(self.Properties.AddressSpace.AddressPrefixes) > 0 { + return self.Properties.AddressSpace.AddressPrefixes[0] + } + return "" +} + +func (self *SVpc) Delete() error { + return self.region.DeleteVpc(self.ID) +} + +func (self *SRegion) DeleteVpc(vpcId string) error { + return self.del(vpcId) +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := self.region.ListSecgroups() + if err != nil { + return nil, errors.Wrapf(err, "ListSecgroups") + } + ret := []cloudprovider.ICloudSecurityGroup{} + for i := range secgroups { + secgroups[i].region = self.region + ret = append(ret, &secgroups[i]) + } + return ret, nil +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + rts := []cloudprovider.ICloudRouteTable{} + return rts, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { + wire := self.getWire() + if wire.GetGlobalId() != wireId { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, wireId) + } + return wire, nil +} + +func (self *SVpc) getWire() *SWire { + zone := self.region.getZone() + return &SWire{zone: zone, vpc: self} +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + return []cloudprovider.ICloudWire{self.getWire()}, nil +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetStatus() string { + if strings.ToLower(self.Properties.ProvisioningState) == "succeeded" { + return "available" + } + return "disabled" +} + +func (region *SRegion) GetVpc(vpcId string) (*SVpc, error) { + vpc := SVpc{region: region} + return &vpc, region.get(vpcId, url.Values{}, &vpc) +} + +func (self *SVpc) Refresh() error { + vpc, err := self.region.GetVpc(self.ID) + if err != nil { + return err + } + return jsonutils.Update(self, vpc) +} + +func (self *SVpc) GetNetworks() []SNetwork { + return self.Properties.Subnets +} + +func (self *SRegion) GetNetwork(networkId string) (*SNetwork, error) { + network := SNetwork{} + return &network, self.get(networkId, url.Values{}, &network) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/waf.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/waf.go new file mode 100644 index 0000000000..61a838d533 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/waf.go @@ -0,0 +1,656 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SMatchvariable struct { + Variablename string `json:"variableName"` + Selector string `json:"selector"` +} + +type SMatchcondition struct { + Matchvariables []SMatchvariable `json:"matchVariables"` + Operator string `json:"operator"` + Negationconditon bool `json:"negationConditon"` + Matchvalues []string `json:"matchValues"` + Transforms []string `json:"transforms"` +} + +type CustomRule struct { + waf *SAppGatewayWaf + + Name string `json:"name"` + Priority int `json:"priority"` + Ruletype string `json:"ruleType"` + //RateLimitThreshold *int `json:"rateLimitThreshold"` + Matchconditions []SMatchcondition `json:"matchConditions"` + Action string `json:"action"` +} + +func (self *CustomRule) GetName() string { + return self.Name +} + +func (self *CustomRule) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.waf.GetGlobalId(), self.GetName()) +} + +func (self *CustomRule) GetDesc() string { + return "" +} + +func (self *CustomRule) GetPriority() int { + return self.Priority +} + +func (self *CustomRule) Delete() error { + rules := []CustomRule{} + for _, rule := range self.waf.Properties.Customrules { + if rule.Name != self.Name { + rules = append(rules, rule) + } + } + self.waf.Properties.Customrules = rules + return self.waf.region.update(jsonutils.Marshal(self.waf), nil) +} + +func wafMatchFieldAndKeyLocal2Cloud(opts cloudprovider.SWafStatement) ([]SMatchvariable, error) { + ret := []SMatchvariable{} + switch opts.MatchField { + case cloudprovider.WafMatchFieldQuery: + ret = append(ret, SMatchvariable{ + Variablename: "QueryString", + }) + case cloudprovider.WafMatchFieldMethod: + ret = append(ret, SMatchvariable{ + Variablename: "RequestMethod", + }) + case cloudprovider.WafMatchFiledUriPath: + ret = append(ret, SMatchvariable{ + Variablename: "RequestUri", + }) + case cloudprovider.WafMatchFiledHeader: + ret = append(ret, SMatchvariable{ + Variablename: "RequestHeaders", + Selector: opts.MatchFieldKey, + }) + case cloudprovider.WafMatchFiledPostArgs: + ret = append(ret, SMatchvariable{ + Variablename: "PostArgs", + Selector: opts.MatchFieldKey, + }) + case cloudprovider.WafMatchFieldBody: + ret = append(ret, SMatchvariable{ + Variablename: "RequestBody", + }) + case cloudprovider.WafMatchFiledCookie: + ret = append(ret, SMatchvariable{ + Variablename: "RequestCookies", + Selector: opts.MatchFieldKey, + }) + default: + return ret, fmt.Errorf("unsupported match filed %s", opts.MatchField) + } + return ret, nil +} + +func wafMatchFieldAndKeyCloud2Local(v SMatchvariable) (cloudprovider.TWafMatchField, string, error) { + switch v.Variablename { + case "QueryString": + return cloudprovider.WafMatchFieldQuery, v.Selector, nil + case "RequestMethod": + return cloudprovider.WafMatchFieldMethod, "", nil + case "RequestUri": + return cloudprovider.WafMatchFiledUriPath, "", nil + case "RequestHeaders": + return cloudprovider.WafMatchFiledHeader, v.Selector, nil + case "PostArgs": + return cloudprovider.WafMatchFiledPostArgs, v.Selector, nil + case "RequestBody": + return cloudprovider.WafMatchFieldBody, "", nil + case "RequestCookies": + return cloudprovider.WafMatchFiledCookie, v.Selector, nil + case "RemoteAddr": + return cloudprovider.WafMatchFiledHeader, v.Selector, nil + default: + return "", "", fmt.Errorf("invalid variablename %s", v.Variablename) + } +} + +func wafStatementLocal2Cloud(opts cloudprovider.SWafStatement) (SMatchcondition, error) { + ret := SMatchcondition{} + if opts.Transformations != nil { + for _, tran := range *opts.Transformations { + ret.Transforms = append(ret.Transforms, string(tran)) + } + } + if opts.MatchFieldValues != nil { + ret.Matchvalues = *opts.MatchFieldValues + } + ret.Negationconditon = opts.Negation + ret.Operator = string(opts.Operator) + var err error + switch opts.Type { + case cloudprovider.WafStatementTypeIPSet: + ret.Operator = "IPMatch" + ret.Matchvariables = []SMatchvariable{ + SMatchvariable{ + Variablename: "RemoteAddr", + }, + } + case cloudprovider.WafStatementTypeGeoMatch: + ret.Operator = "GeoMatch" + if len(opts.ForwardedIPHeader) == 0 { + ret.Matchvariables = []SMatchvariable{ + SMatchvariable{ + Variablename: "RemoteAddr", + }, + } + } else { + ret.Matchvariables = []SMatchvariable{ + SMatchvariable{ + Variablename: "RequestHeaders", + Selector: opts.ForwardedIPHeader, + }, + } + } + case cloudprovider.WafStatementTypeSize: + switch opts.Operator { + case "LT": + ret.Operator = "LessThan" + case "LE": + ret.Operator = "LessThanOrEqual" + case "GT": + ret.Operator = "GreaterThan" + default: + return ret, fmt.Errorf("invalid operator %s for %s", opts.Operator, opts.Type) + } + ret.Matchvariables, err = wafMatchFieldAndKeyLocal2Cloud(opts) + if err != nil { + return ret, errors.Wrapf(err, "wafMatchFieldAndKeyLocal2Cloud") + } + case cloudprovider.WafStatementTypeByteMatch: + switch opts.Operator { + case "Contains", "EndsWith", "Regex": + case "StartsWith": + ret.Operator = "BeginsWith" + case "Exactly": + ret.Operator = "Equal" + default: + return ret, fmt.Errorf("invalid operator %s for %s", opts.Operator, opts.Type) + } + ret.Matchvariables, err = wafMatchFieldAndKeyLocal2Cloud(opts) + if err != nil { + return ret, errors.Wrapf(err, "wafMatchFieldAndKeyLocal2Cloud") + } + } + return ret, nil +} + +func wafRuleLocal2Cloud(opts *cloudprovider.SWafRule) (*CustomRule, error) { + ret := &CustomRule{} + ret.Name = opts.Name + ret.Priority = opts.Priority + ret.Ruletype = "MatchRule" + ret.Matchconditions = []SMatchcondition{} + for _, s := range opts.Statements { + cds, err := wafStatementLocal2Cloud(s) + if err != nil { + return nil, errors.Wrapf(err, "wafStatementLocal2Cloud") + } + ret.Matchconditions = append(ret.Matchconditions, cds) + } + ret.Action = "Block" + if opts.Action != nil { + ret.Action = string(opts.Action.Action) + } + return ret, nil +} + +func (self *CustomRule) Update(opts *cloudprovider.SWafRule) error { + rules := []CustomRule{} + for _, rule := range self.waf.Properties.Customrules { + if rule.Name != self.Name { + rules = append(rules, rule) + } else { + rule, err := wafRuleLocal2Cloud(opts) + if err != nil { + return errors.Wrapf(err, "wafRuleLocal2Cloud") + } + rules = append(rules, *rule) + } + } + self.waf.Properties.Customrules = rules + return self.waf.region.update(jsonutils.Marshal(self.waf), nil) +} + +func (self *CustomRule) GetAction() *cloudprovider.DefaultAction { + return &cloudprovider.DefaultAction{ + Action: cloudprovider.TWafAction(self.Action), + } +} + +func (self *CustomRule) GetStatementCondition() cloudprovider.TWafStatementCondition { + return cloudprovider.WafStatementConditionAnd +} + +func (self *CustomRule) GetStatements() ([]cloudprovider.SWafStatement, error) { + ret := []cloudprovider.SWafStatement{} + for _, condition := range self.Matchconditions { + trans := cloudprovider.TextTransformations{} + for _, tran := range condition.Transforms { + trans = append(trans, cloudprovider.TWafTextTransformation(tran)) + } + values := cloudprovider.TWafMatchFieldValues(condition.Matchvalues) + statement := cloudprovider.SWafStatement{ + Negation: condition.Negationconditon, + Transformations: &trans, + MatchFieldValues: &values, + } + switch condition.Operator { + case "IPMatch": + statement.Type = cloudprovider.WafStatementTypeIPSet + case "GeoMatch": + statement.Type = cloudprovider.WafStatementTypeGeoMatch + case "LessThan": + statement.Type = cloudprovider.WafStatementTypeSize + statement.Operator = cloudprovider.WafOperatorLT + case "LessThanOrEqual": + statement.Type = cloudprovider.WafStatementTypeSize + statement.Operator = cloudprovider.WafOperatorLE + case "GreaterThan": + statement.Type = cloudprovider.WafStatementTypeSize + statement.Operator = cloudprovider.WafOperatorGT + case "BeginsWith": + statement.Type = cloudprovider.WafStatementTypeByteMatch + statement.Operator = cloudprovider.WafOperatorStartsWith + case "Contains", "EndsWith", "Regex": + statement.Type = cloudprovider.WafStatementTypeByteMatch + statement.Operator = cloudprovider.TWafOperator(condition.Operator) + case "Equal": + statement.Type = cloudprovider.WafStatementTypeByteMatch + statement.Operator = cloudprovider.WafOperatorExactly + default: + statement.Type = cloudprovider.WafStatementTypeByteMatch + } + + var err error + for _, v := range condition.Matchvariables { + statement.MatchField, statement.MatchFieldKey, err = wafMatchFieldAndKeyCloud2Local(v) + if err != nil { + log.Errorf("wafMatchFieldAndKeyCloud2Local %s error: %v", v, err) + continue + } + ret = append(ret, statement) + } + } + return ret, nil +} + +type ManagedRule struct { + Rulesettype string `json:"ruleSetType"` + Rulesetversion string `json:"ruleSetVersion"` +} + +type ManagedRules struct { + waf *SAppGatewayWaf + Managedrulesets []ManagedRule `json:"managedRuleSets"` +} + +func (self *ManagedRules) GetName() string { + return fmt.Sprintf("%s Managed rules", self.waf.GetName()) +} + +func (self *ManagedRules) GetGlobalId() string { + return self.waf.GetGlobalId() +} + +func (self *ManagedRules) GetDesc() string { + return "" +} + +func (self *ManagedRules) GetPriority() int { + return 0 +} + +func (self *ManagedRules) GetAction() *cloudprovider.DefaultAction { + return nil +} + +func (self *ManagedRules) Delete() error { + return cloudprovider.ErrNotSupported +} + +func (self *ManagedRules) Update(opts *cloudprovider.SWafRule) error { + rules := []ManagedRule{} + for _, s := range opts.Statements { + if len(s.ManagedRuleGroupName) == 0 { + return fmt.Errorf("missing managed rule group name") + } + names := strings.Split(s.ManagedRuleGroupName, "_") + if len(names) != 2 { + return fmt.Errorf("invalid managed rule group name %s", s.ManagedRuleGroupName) + } + rules = append(rules, ManagedRule{ + Rulesettype: names[0], + Rulesetversion: names[1], + }) + } + if len(rules) == 0 { + return fmt.Errorf("missing statements") + } + self.waf.Properties.Managedrules = ManagedRules{ + Managedrulesets: rules, + } + return self.waf.region.update(jsonutils.Marshal(self.waf), nil) +} + +func (self *ManagedRules) GetStatementCondition() cloudprovider.TWafStatementCondition { + return cloudprovider.WafStatementConditionAnd +} + +func (self *ManagedRules) GetStatements() ([]cloudprovider.SWafStatement, error) { + ret := []cloudprovider.SWafStatement{} + for i := range self.Managedrulesets { + ruleGroupName := fmt.Sprintf("%s_%s", self.Managedrulesets[i].Rulesettype, self.Managedrulesets[i].Rulesetversion) + ret = append(ret, cloudprovider.SWafStatement{ + ManagedRuleGroupName: ruleGroupName, + Type: cloudprovider.WafStatementTypeManagedRuleGroup, + RuleGroupId: ruleGroupName, + }) + } + return ret, nil +} + +type SAppGatewayWaf struct { + multicloud.SResourceBase + AzureTags + region *SRegion + + Name string `json:"name"` + ID string `json:"id"` + Type string `json:"type"` + Location string `json:"location"` + Properties struct { + ApplicationGateways []SApplicationGateway + HttpListeners []struct { + Id string + } + PathBasedRules []struct { + Id string + } + Resourcestate string `json:"resourceState"` + Provisioningstate string `json:"provisioningState"` + Policysettings struct { + State string `json:"state"` + Mode string `json:"mode"` + Maxrequestbodysizeinkb int `json:"maxRequestBodySizeInKb"` + Fileuploadlimitinmb int `json:"fileUploadLimitInMb"` + Requestbodycheck bool `json:"requestBodyCheck"` + } `json:"policySettings"` + Customrules []CustomRule `json:"customRules"` + Managedrules ManagedRules `json:"managedRules"` + } `json:"properties"` +} + +func (self *SAppGatewayWaf) GetEnabled() bool { + return self.Properties.Policysettings.State == "Enabled" +} + +func (self *SAppGatewayWaf) GetName() string { + return self.Name +} + +func (self *SAppGatewayWaf) GetId() string { + return self.ID +} + +func (self *SAppGatewayWaf) GetGlobalId() string { + return strings.ToLower(self.ID) +} + +func (self *SAppGatewayWaf) Delete() error { + return self.region.del(self.ID) +} + +func (self *SAppGatewayWaf) GetWafType() cloudprovider.TWafType { + return cloudprovider.WafTypeAppGateway +} + +func (self *SAppGatewayWaf) AddRule(opts *cloudprovider.SWafRule) (cloudprovider.ICloudWafRule, error) { + rule, err := wafRuleLocal2Cloud(opts) + if err != nil { + return nil, errors.Wrapf(err, "wafRuleLocal2Cloud") + } + rule.waf = self + self.Properties.Customrules = append(self.Properties.Customrules, *rule) + err = self.region.update(jsonutils.Marshal(self), nil) + if err != nil { + return nil, errors.Wrapf(err, "update") + } + return rule, nil +} + +func (self *SAppGatewayWaf) GetStatus() string { + switch self.Properties.Provisioningstate { + case "Deleting": + return api.WAF_STATUS_DELETING + case "Failed": + return api.WAF_STATUS_CREATE_FAILED + case "Succeeded": + return api.WAF_STATUS_AVAILABLE + case "Updating": + return api.WAF_STATUS_UPDATING + default: + return self.Properties.Provisioningstate + } +} + +func (self *SAppGatewayWaf) GetRules() ([]cloudprovider.ICloudWafRule, error) { + ret := []cloudprovider.ICloudWafRule{} + for i := range self.Properties.Customrules { + self.Properties.Customrules[i].waf = self + ret = append(ret, &self.Properties.Customrules[i]) + } + self.Properties.Managedrules.waf = self + ret = append(ret, &self.Properties.Managedrules) + return ret, nil +} + +func (self *SAppGatewayWaf) Refresh() error { + waf, err := self.region.GetAppGatewayWaf(self.ID) + if err != nil { + return errors.Wrapf(err, "GetAppGatewayWa") + } + return jsonutils.Update(self, waf) +} + +func (self *SAppGatewayWaf) GetDefaultAction() *cloudprovider.DefaultAction { + return &cloudprovider.DefaultAction{ + Action: cloudprovider.TWafAction(self.Properties.Policysettings.Mode), + } +} + +func (self *SRegion) ListAppWafs() ([]SAppGatewayWaf, error) { + ret := []SAppGatewayWaf{} + err := self.list("Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies", url.Values{}, &ret) + if err != nil { + return nil, errors.Wrapf(err, "list") + } + return ret, nil +} + +type SAppWafRuleGroup struct { + Name string `json:"name"` + ID string `json:"id"` + Type string `json:"type"` + Properties struct { + Provisioningstate string `json:"provisioningState"` + Rulesettype string `json:"ruleSetType"` + Rulesetversion string `json:"ruleSetVersion"` + Rulegroups []struct { + Rulegroupname string `json:"ruleGroupName"` + Description string `json:"description"` + Rules []struct { + Ruleid int `json:"ruleId"` + Description string `json:"description"` + } `json:"rules"` + } `json:"ruleGroups"` + } `json:"properties"` +} + +func (self *SRegion) CreateICloudWafInstance(opts *cloudprovider.WafCreateOptions) (cloudprovider.ICloudWafInstance, error) { + switch opts.Type { + case cloudprovider.WafTypeAppGateway: + return self.CreateAppWafInstance(opts.Name, opts.DefaultAction) + default: + return nil, errors.Wrapf(cloudprovider.ErrNoSuchProvder, "invalid waf type %s", opts.Type) + } +} + +func (self *SRegion) GetICloudWafInstanceById(id string) (cloudprovider.ICloudWafInstance, error) { + if strings.Contains(id, "microsoft.network/applicationgatewaywebapplicationfirewallpolicies") { + return self.GetAppGatewayWaf(id) + } + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, id) +} + +func (self *SRegion) CreateAppWafInstance(name string, action *cloudprovider.DefaultAction) (*SAppGatewayWaf, error) { + mode := cloudprovider.WafActionDetection + if action != nil { + switch action.Action { + case cloudprovider.WafActionDetection, cloudprovider.WafActionPrevention: + mode = action.Action + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "invalid action %s", action.Action) + } + } + params := map[string]interface{}{ + "Type": "Microsoft.Network/applicationGatewayWebApplicationFirewallPolicies", + "Name": name, + "Location": self.Name, + "properties": map[string]interface{}{ + "customRules": []string{}, + "policySettings": map[string]interface{}{ + "fileUploadLimitInMb": 100, + "maxRequestBodySizeInKb": 128, + "mode": mode, + "requestBodyCheck": true, + "state": "Enabled", + }, + "managedRules": map[string]interface{}{ + "exclusions": []string{}, + "managedRuleSets": []map[string]interface{}{ + map[string]interface{}{ + "ruleSetType": "OWASP", + "ruleSetVersion": "3.1", + "ruleGroupOverrides": []string{}, + }, + }, + }, + }, + } + ret := &SAppGatewayWaf{region: self} + err := self.create("", jsonutils.Marshal(params), ret) + if err != nil { + return nil, err + } + return ret, nil +} + +func (self *SRegion) GetAppGatewayWaf(id string) (*SAppGatewayWaf, error) { + res := &SAppGatewayWaf{region: self} + return res, self.get(id, nil, &res) +} + +func (self *SRegion) ListAppWafManagedRuleGroup() ([]SAppWafRuleGroup, error) { + ret := []SAppWafRuleGroup{} + err := self.list("Microsoft.Network/applicationGatewayAvailableWafRuleSets", url.Values{}, &ret) + if err != nil { + return nil, errors.Wrapf(err, "list") + } + return ret, nil +} + +func (self *SRegion) GetICloudWafInstances() ([]cloudprovider.ICloudWafInstance, error) { + wafs, err := self.ListAppWafs() + if err != nil { + return nil, errors.Wrapf(err, "ListAppWafs") + } + ret := []cloudprovider.ICloudWafInstance{} + for i := range wafs { + wafs[i].region = self + ret = append(ret, &wafs[i]) + } + return ret, nil +} + +func (self *SAppGatewayWaf) GetCloudResources() ([]cloudprovider.SCloudResource, error) { + ret := []cloudprovider.SCloudResource{} + for _, ag := range self.Properties.ApplicationGateways { + ret = append(ret, cloudprovider.SCloudResource{ + Id: ag.Id, + Name: ag.Id[strings.LastIndex(ag.Id, "/")+1:], + Type: "Application Gateway", + CanDissociate: true, + }) + } + for _, lis := range self.Properties.HttpListeners { + ret = append(ret, cloudprovider.SCloudResource{ + Id: lis.Id, + Name: lis.Id[strings.LastIndex(lis.Id, "/")+1:], + Type: "HTTP Listener", + CanDissociate: true, + }) + } + for _, route := range self.Properties.PathBasedRules { + ret = append(ret, cloudprovider.SCloudResource{ + Id: route.Id, + Name: route.Id[strings.LastIndex(route.Id, "/")+1:], + Type: "Route Path", + CanDissociate: true, + }) + + } + return ret, nil +} + +func (self *SAppGatewayWaf) SetTags(tags map[string]string, replace bool) error { + if !replace { + for k, v := range self.Tags { + if _, ok := tags[k]; !ok { + tags[k] = v + } + } + } + _, err := self.region.client.SetTags(self.ID, tags) + if err != nil { + return errors.Wrapf(err, "SetTags") + } + return nil +} diff --git a/pkg/multicloud/azure/waf_front_doors.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/waf_front_doors.go similarity index 100% rename from pkg/multicloud/azure/waf_front_doors.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/waf_front_doors.go diff --git a/pkg/multicloud/azure/waf_rule_groups.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/waf_rule_groups.go similarity index 100% rename from pkg/multicloud/azure/waf_rule_groups.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/waf_rule_groups.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/web_app.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/web_app.go new file mode 100644 index 0000000000..61470a8437 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/web_app.go @@ -0,0 +1,316 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SAppSite struct { + multicloud.SResourceBase + AzureTags + region *SRegion + appServicePlan *SAppServicePlan + + Properties SAppSiteProperties + Id string + Name string + Kind string + Location string + Type string + + stack *string +} + +type SAppSiteProperties struct { + AvailabilityState string + DefaultHostName string + Enabled bool + EnabledHostNames []string + HostNameSslStates []SHostNameSslState + HostNames []string + HttpsOnly bool + OutboundIpAddresses string + ResourceGroup string + ServerFarmId string + SiteConfig SSiteConfig + State string +} + +type SSiteConfig struct { + // TODO +} + +type SHostNameSslState struct { + HostType string + Name string + SslState string + Thumbprint string + ToUpdate bool + VirtualIP string +} + +func (r *SRegion) GetAppSites() ([]SAppSite, error) { + result := []SAppSite{} + resource := "Microsoft.Web/sites" + err := r.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) + if err != nil { + return nil, err + } + for i := range result { + result[i].region = r + } + return result, nil +} + +func (r *SRegion) GetICloudApps() ([]cloudprovider.ICloudApp, error) { + ass, err := r.GetAppSites() + if err != nil { + return nil, err + } + apps := make([]cloudprovider.ICloudApp, 0, len(ass)) + for i := range ass { + apps = append(apps, &SApp{ + SAppSite: ass[i], + }) + } + return apps, nil +} + +func (r *SRegion) GetICloudAppById(id string) (cloudprovider.ICloudApp, error) { + as, err := r.GetAppSite(id) + if err != nil { + return nil, err + } + return &SApp{ + SAppSite: *as, + }, nil +} + +func (as *SAppSite) GetSlots() ([]SAppSite, error) { + result := []SAppSite{} + resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/slots", as.region.client.subscriptionId, as.Properties.ResourceGroup, as.Name) + err := as.region.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) + if err != nil { + return nil, err + } + return result, nil +} + +func (r *SRegion) GetAppSite(siteId string) (*SAppSite, error) { + as := &SAppSite{region: r} + params := url.Values{"api-version": []string{"2019-08-01"}} + return as, r.get(siteId, params, as) +} + +func (as *SAppSite) GetAppServicePlan() (*SAppServicePlan, error) { + if as.appServicePlan != nil { + return as.appServicePlan, nil + } + plan, err := as.region.GetAppServicePlanWithCache(as.Properties.ServerFarmId) + if err != nil { + return nil, errors.Wrap(err, "unable to get AppServicePlan") + } + as.appServicePlan = plan + return plan, nil +} + +type SDeployment struct { + ID string + Name string + Kind string + Type string + Properties SDeploymentProperties +} + +type SDeploymentProperties struct { + Active bool + Author string + AuthorEmail string + Deployer string + Details string + EndTime string + Message string + StartTime string + Status string +} + +func (as *SAppSite) GetDeployments() ([]SDeployment, error) { + result := []SDeployment{} + resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/deployments", as.region.client._subscriptionId(), as.Properties.ResourceGroup, as.Name) + err := as.region.client.list(resource, url.Values{"api-version": []string{"2019-08-01"}}, &result) + if err != nil { + return nil, err + } + return result, nil +} + +type SStringDictionary struct { + Id string + Kind string + Name string + Type string + Properties map[string]string +} + +func (as *SAppSite) GetStack() (string, error) { + if as.stack != nil { + return *as.stack, nil + } + // result := SStringDictionary{} + resource := fmt.Sprintf("subscriptions/%s/resourceGroups/%s/providers/Microsoft.Web/sites/%s/config/metadata", as.region.client.subscriptionId, as.Properties.ResourceGroup, as.Name) + + params := url.Values{} + params.Set("api-version", "2019-08-01") + path := resource + "/list" + response, err := as.region.client.jsonRequest("POST", path, nil, params, true) + if err != nil { + return "", err + } + stack, err := response.GetString("properties", "CURRENT_STACK") + if err != nil { + return "", errors.Wrapf(err, "unable to parse response correctly, response: %s", response) + } + as.stack = &stack + return stack, nil +} + +func (as *SAppSite) GetId() string { + return as.Id +} + +func (as *SAppSite) GetName() string { + return as.Name +} + +func (as *SAppSite) GetGlobalId() string { + return strings.ToLower(as.Id) +} + +func (as *SAppSite) GetStatus() string { + return "ready" +} + +func (as *SAppSite) GetProjectId() string { + return strings.ToLower(as.Properties.ResourceGroup) +} + +type SApp struct { + SAppSite +} + +type SAppEnvironment struct { + multicloud.SResourceBase + AzureTags + SAppSite +} + +func (ae *SAppEnvironment) GetInstanceType() (string, error) { + asp, err := ae.SAppSite.GetAppServicePlan() + if err != nil { + return "", err + } + return asp.Sku.Name, nil +} + +func (ae *SAppEnvironment) GetInstanceNumber() (int, error) { + asp, err := ae.SAppSite.GetAppServicePlan() + if err != nil { + return 0, err + } + return asp.Sku.Capacity, nil +} + +func (a *SApp) GetEnvironments() ([]cloudprovider.ICloudAppEnvironment, error) { + sites, err := a.SAppSite.GetSlots() + if err != nil { + return nil, err + } + aes := make([]cloudprovider.ICloudAppEnvironment, 0, len(sites)+1) + aes = append(aes, &SAppEnvironment{ + SAppSite: a.SAppSite, + }) + for i := range sites { + sites[i].region = a.region + aes = append(aes, &SAppEnvironment{ + SAppSite: sites[i], + }) + } + return aes, nil +} + +var techStacks = map[string]string{ + "dotnet": ".NET", + "dotnetcore": ".NET Core", + "aspdotnet": "ASP.NET", + "node": "Node", + "python": "Python", + "php": "PHP", + "ruby": "Ruby", + "java": "Java", + "javacontainers": "Jave Containers", +} + +func (a *SApp) GetTechStack() string { + if strings.Contains(a.SAppSite.Kind, "container") { + return "Docker container" + } + stack, err := a.GetStack() + if err != nil { + log.Errorf("unable to GetStack: %v", err) + } + if s, ok := techStacks[stack]; ok { + return s + } + return stack +} + +func (a *SApp) GetType() string { + return "web" +} + +func (a *SApp) GetKind() string { + return a.Kind +} + +func (a *SApp) GetOsType() cloudprovider.TOsType { + if strings.Contains(a.Kind, "linux") { + return cloudprovider.OsTypeLinux + } + return cloudprovider.OsTypeWindows +} + +func (self *SApp) SetTags(tags map[string]string, replace bool) error { + if !replace { + for k, v := range self.Tags { + if _, ok := tags[k]; !ok { + tags[k] = v + } + } + } + _, err := self.region.client.SetTags(self.Id, tags) + if err != nil { + return errors.Wrapf(err, "SetTags") + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/wire.go new file mode 100644 index 0000000000..85f03272fd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/wire.go @@ -0,0 +1,120 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + AzureTags + + zone *SZone + vpc *SVpc + inetworks []cloudprovider.ICloudNetwork +} + +func (self *SWire) GetId() string { + return fmt.Sprintf("%s/%s/%s", self.zone.region.GetGlobalId(), self.zone.region.client.subscriptionId, self.vpc.GetName()) +} + +func (self *SWire) GetGlobalId() string { + return strings.ToLower(self.GetId()) +} + +func (self *SWire) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.vpc.GetName()) +} + +func (self *SWire) IsEmulated() bool { + return true +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SRegion) CreateNetwork(vpcId, name string, cidr string, desc string) (*SNetwork, error) { + params := map[string]interface{}{ + "Name": name, + "Properties": map[string]interface{}{ + "AddressPrefix": cidr, + }, + } + resource := fmt.Sprintf("%s/subnets/%s", vpcId, name) + network := &SNetwork{} + resp, err := self.put(resource, jsonutils.Marshal(params)) + if err != nil { + return nil, errors.Wrapf(err, "put(%s)", resource) + } + err = resp.Unmarshal(network) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return network, nil +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + network, err := self.zone.region.CreateNetwork(self.vpc.ID, opts.Name, opts.Cidr, opts.Desc) + if err != nil { + return nil, err + } + network.wire = self + return network, 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() == strings.ToLower(netid) { + return networks[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, netid) +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + ret := []cloudprovider.ICloudNetwork{} + networks := self.vpc.GetNetworks() + for i := range networks { + networks[i].wire = self + ret = append(ret, &networks[i]) + } + return ret, nil +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return self.zone +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/zone.go new file mode 100644 index 0000000000..8849e52344 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/azure/zone.go @@ -0,0 +1,178 @@ +// Copyright 2019 Yunion +// +// 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 azure + +import ( + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SZone struct { + multicloud.SResourceBase + AzureTags + region *SRegion + + Name string +} + +func (self *SZone) GetId() string { + return self.region.client.cpcfg.Id +} + +func (self *SZone) GetName() string { + return self.region.GetName() +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + return self.region.GetI18n() +} + +func (self *SZone) GetGlobalId() string { + return self.region.GetGlobalId() +} + +func (self *SZone) IsEmulated() bool { + return true +} + +func (self *SZone) GetStatus() string { + return api.ZONE_ENABLE +} + +func (self *SZone) Refresh() error { + // do nothing + return nil +} + +func (self *SZone) getHost() *SHost { + return &SHost{zone: self} +} + +func (self *SZone) getClassicHost() *SClassicHost { + return &SClassicHost{zone: self} +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) ListStorageTypes() []SStorage { + storages := []SStorage{} + for _, storageType := range STORAGETYPES { + storage := SStorage{zone: self, storageType: storageType} + storages = append(storages, storage) + } + return storages +} + +func (self *SRegion) ListClassicStorageTypes() []SClassicStorage { + storages := []SClassicStorage{} + for _, storageType := range []string{STORAGE_LRS, STORAGE_GRS} { + storage := SClassicStorage{AccountType: storageType, region: self} + storages = append(storages, storage) + } + return storages +} + +func (self *SZone) GetIClassicStorages() []cloudprovider.ICloudStorage { + ret := []cloudprovider.ICloudStorage{} + storages := self.region.ListClassicStorageTypes() + for i := range storages { + ret = append(ret, &storages[i]) + } + return ret +} + +func (self *SZone) getIStorages() []cloudprovider.ICloudStorage { + ret := []cloudprovider.ICloudStorage{} + storages := self.ListStorageTypes() + for i := range storages { + storages[i].zone = self + ret = append(ret, &storages[i]) + } + return ret +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + ret := self.getIStorages() + ret = append(ret, self.GetIClassicStorages()...) + return ret, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storages, err := self.GetIStorages() + if err != nil { + return nil, errors.Wrapf(err, "GetIStorages") + } + for i := range storages { + if storages[i].GetGlobalId() == id { + return storages[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + hosts, err := self.GetIHosts() + if err != nil { + return nil, errors.Wrapf(err, "GetIHosts") + } + for i := range hosts { + if hosts[i].GetGlobalId() == id { + return hosts[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + return []cloudprovider.ICloudHost{self.getHost(), self.getClassicHost()}, nil +} + +func (self *SZone) GetIClassicWires() ([]cloudprovider.ICloudWire, error) { + wires := []cloudprovider.ICloudWire{} + classicVpcs, err := self.region.ListClassicVpcs() + if err != nil { + return nil, errors.Wrapf(err, "ListClassicVpcs") + } + for i := range classicVpcs { + classicVpcs[i].region = self.region + wire := &SClassicWire{vpc: &classicVpcs[i], zone: self} + wires = append(wires, wire) + } + return wires, nil +} + +func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { + vpcs, err := self.region.ListVpcs() + if err != nil { + return nil, errors.Wrapf(err, "ListVpcs") + } + wires := []cloudprovider.ICloudWire{} + for i := range vpcs { + vpcs[i].region = self.region + wire := &SWire{vpc: &vpcs[i], zone: self} + wires = append(wires, wire) + } + classWires, err := self.GetIClassicWires() + if err != nil { + return nil, errors.Wrapf(err, "GetIClassicWires") + } + wires = append(wires, classWires...) + return wires, nil +} diff --git a/pkg/multicloud/billing_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/billing_base.go similarity index 96% rename from pkg/multicloud/billing_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/billing_base.go index 8a0e4694c9..90c8a37032 100644 --- a/pkg/multicloud/billing_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/billing_base.go @@ -19,7 +19,7 @@ import ( "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/billing" ) diff --git a/pkg/multicloud/bingocloud/bingo.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/bingo.go similarity index 98% rename from pkg/multicloud/bingocloud/bingo.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/bingo.go index 6480cdcfc8..956b7f3789 100644 --- a/pkg/multicloud/bingocloud/bingo.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/bingo.go @@ -34,8 +34,8 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/cluster.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/cluster.go new file mode 100644 index 0000000000..991fe4be87 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/cluster.go @@ -0,0 +1,105 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SCluster struct { + multicloud.SResourceBase + multicloud.STagBase + + region *SRegion + + ClusterControllerSet []struct { + Address string + Role string + } + ClusterId string + ClusterName string + CreateVolumeMode string + ExtendDiskMode string + Hypervisor string + MaxVolumeStorage string + SchedPolicy string + Status string +} + +func (self *SCluster) GetGlobalId() string { + return self.ClusterId +} + +func (self *SCluster) GetId() string { + return self.ClusterId +} + +func (self *SCluster) GetName() string { + return self.ClusterName +} + +func (self *SCluster) GetStatus() string { + if self.Status == "available" { + return api.ZONE_ENABLE + } + return api.ZONE_DISABLE +} + +func (self *SCluster) GetI18n() cloudprovider.SModelI18nTable { + return cloudprovider.SModelI18nTable{} +} + +func (self *SCluster) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + clusters, err := self.GetClusters() + if err != nil { + return nil, errors.Wrapf(err, "GetClusters") + } + ret := []cloudprovider.ICloudZone{} + for i := range clusters { + clusters[i].region = self + ret = append(ret, &clusters[i]) + } + return ret, nil +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + zones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := range zones { + if zones[i].GetGlobalId() == id { + return zones[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetClusters() ([]SCluster, error) { + resp, err := self.invoke("DescribeClusters", nil) + if err != nil { + return nil, err + } + ret := []SCluster{} + return ret, resp.Unmarshal(&ret, "clusterSet") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/disk.go new file mode 100644 index 0000000000..4dabadeee2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/disk.go @@ -0,0 +1,255 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "context" + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDisk struct { + BingoTags + multicloud.SDisk + + storage *SStorage + + AttachmentSet []AttachmentSet `json:"attachmentSet"` + AvailabilityZone string `json:"availabilityZone"` + CreateTime string `json:"createTime"` + Description string `json:"description"` + DetachBehavior string `json:"detachBehavior"` + Goal string `json:"goal"` + Iops string `json:"iops"` + IsDeductQuota string `json:"isDeductQuota"` + IsEncrypt string `json:"isEncrypt"` + IsForSleepInst string `json:"isForSleepInst"` + IsMirrorVolume string `json:"isMirrorVolume"` + IsMultiAttach string `json:"isMultiAttach"` + IsOneInst string `json:"isOneInst"` + IsRoot string `json:"isRoot"` + Location string `json:"location"` + MirrorFrom string `json:"mirrorFrom"` + MirrorProcess string `json:"mirrorProcess"` + MirrorStatus string `json:"mirrorStatus"` + NodeId string `json:"nodeId"` + Owner string `json:"owner"` + Passphrase string `json:"passphrase"` + Readonly string `json:"readonly"` + Size int `json:"size"` + SnapshotId string `json:"snapshotId"` + Status string `json:"status"` + StorageId string `json:"storageId"` + VolumeId string `json:"volumeId"` + VolumeName string `json:"volumeName"` +} + +type AttachmentSet struct { + AttachTime string `json:"attachTime"` + Cache string `json:"cache"` + DeleteOnTermination string `json:"deleteOnTermination"` + Device string `json:"device"` + InstanceId string `json:"instanceId"` + Status string `json:"status"` + VolumeId string `json:"volumeId"` +} + +func (self *SDisk) GetName() string { + return self.VolumeName +} + +func (self *SDisk) GetId() string { + return self.VolumeId +} + +func (self *SDisk) GetGlobalId() string { + return self.GetId() +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +func (self *SDisk) GetIStorageId() string { + return self.StorageId +} + +func (self *SDisk) GetDiskFormat() string { + return "raw" +} + +func (self *SDisk) GetDiskSizeMB() int { + return self.Size * 1024 +} + +func (self *SDisk) GetIsAutoDelete() bool { + return self.IsRoot == "true" +} + +func (self *SDisk) GetTemplateId() string { + return "" +} + +func (self *SDisk) GetDiskType() string { + if self.IsRoot == "true" { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +func (self *SDisk) GetFsFormat() string { + return "" +} + +func (self *SDisk) GetIsNonPersistent() bool { + return false +} + +func (self *SDisk) GetDriver() string { + return "virtio" +} + +func (self *SDisk) GetCacheMode() string { + return "none" +} + +func (self *SDisk) GetMountpoint() string { + for _, att := range self.AttachmentSet { + return att.Device + } + return "" +} + +func (self *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { + return []string{}, nil +} + +func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SDisk) GetStatus() string { + switch self.Status { + case "available", "in-use": + return api.DISK_READY + default: + return self.Status + } +} + +func (self *SRegion) GetDisks(id string, maxResult int, nextToken string) ([]SDisk, string, error) { + params := map[string]string{} + idx := 1 + if len(id) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "volume-id" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = id + idx++ + } + + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + if maxResult > 0 { + params["maxRecords"] = fmt.Sprintf("%d", maxResult) + } + resp, err := self.invoke("DescribeVolumes", params) + if err != nil { + return nil, "", err + } + ret := struct { + NextToken string + VolumeSet []SDisk + }{} + resp.Unmarshal(&ret) + return ret.VolumeSet, ret.NextToken, nil +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + part, nextToken, err := self.cluster.region.GetDisks("", MAX_RESULT, "") + if err != nil { + return nil, err + } + disks := []SDisk{} + disks = append(disks, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.cluster.region.GetDisks("", MAX_RESULT, nextToken) + if err != nil { + return nil, err + } + disks = append(disks, part...) + } + ret := []cloudprovider.ICloudDisk{} + for i := range disks { + if disks[i].StorageId == self.StorageId { + disks[i].storage = self + ret = append(ret, &disks[i]) + } + } + return ret, nil +} + +func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disk, err := self.cluster.region.GetDisk(id) + if err != nil { + return nil, err + } + if disk.StorageId != self.StorageId { + return nil, cloudprovider.ErrNotFound + } + disk.storage = self + return disk, nil +} + +func (self *SRegion) GetDisk(id string) (*SDisk, error) { + disks, _, err := self.GetDisks(id, 1, "") + if err != nil { + return nil, err + } + for i := range disks { + if disks[i].GetGlobalId() == id { + return &disks[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/doc.go new file mode 100644 index 0000000000..f38bc7a2cc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud // import "yunion.io/x/cloudmux/pkg/multicloud/bingocloud" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/eip.go new file mode 100644 index 0000000000..ed3891838c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/eip.go @@ -0,0 +1,174 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SEip struct { + multicloud.SEipBase + BingoTags + + region *SRegion + + AddressId string + AddressType string + Bandtype string + Bandwidth int + CanAssociate bool + InstanceId string + Owner string + PublicIp string + SubnetId string + VpcId string +} + +func (self *SEip) GetId() string { + return self.PublicIp +} + +func (self *SEip) GetGlobalId() string { + return self.PublicIp +} + +func (self *SEip) GetName() string { + return self.PublicIp +} + +func (self *SEip) GetIpAddr() string { + return self.PublicIp +} + +func (self *SEip) GetMode() string { + return api.EIP_MODE_STANDALONE_EIP +} + +func (self *SEip) GetINetworkId() string { + return self.SubnetId +} + +func (self *SEip) GetAssociationType() string { + if len(self.InstanceId) > 0 { + return api.EIP_ASSOCIATE_TYPE_SERVER + } + return "" +} + +func (self *SEip) GetAssociationExternalId() string { + return self.InstanceId +} + +func (self *SEip) GetBandwidth() int { + return self.Bandwidth +} + +func (self *SEip) GetInternetChargeType() string { + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH +} + +func (self *SEip) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SEip) Associate(conf *cloudprovider.AssociateConfig) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SEip) Dissociate() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SEip) ChangeBandwidth(bw int) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SEip) GetProjectId() string { + return "" +} + +func (self *SEip) GetStatus() string { + return api.EIP_STATUS_READY +} + +func (self *SRegion) GetEips(ip, instanceId, nextToken string) ([]SEip, string, error) { + params := map[string]string{} + if len(ip) > 0 { + params["publicIp"] = ip + } + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + + idx := 1 + if len(instanceId) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "instance-id" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = instanceId + idx++ + } + + resp, err := self.invoke("DescribeAddresses", params) + if err != nil { + return nil, "", errors.Wrapf(err, "DescribeAddresses") + } + ret := struct { + AddressesSet []SEip + NextToken string + }{} + resp.Unmarshal(&ret) + return ret.AddressesSet, ret.NextToken, nil +} + +func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + part, nextToken, err := self.GetEips("", "", "") + if err != nil { + return nil, err + } + eips := []SEip{} + eips = append(eips, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.GetEips("", "", nextToken) + if err != nil { + return nil, err + } + eips = append(eips, part...) + } + ret := []cloudprovider.ICloudEIP{} + for i := range eips { + eips[i].region = self + ret = append(ret, &eips[i]) + } + return ret, nil +} + +func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { + eips, _, err := self.GetEips(id, "", "") + if err != nil { + return nil, err + } + for i := range eips { + if eips[i].GetGlobalId() == id { + eips[i].region = self + return &eips[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} diff --git a/pkg/multicloud/bingocloud/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/host.go similarity index 100% rename from pkg/multicloud/bingocloud/host.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/host.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/image.go new file mode 100644 index 0000000000..a36278da03 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/image.go @@ -0,0 +1,245 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "context" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SImage struct { + multicloud.SResourceBase + BingoTags + cache *SStoragecache + + imageInfo *imagetools.ImageInfo + + Architecture string `json:"architecture"` + BlockDeviceMapping string `json:"blockDeviceMapping"` + Bootloader string `json:"bootloader"` + Clonemode string `json:"clonemode"` + ClusterId string `json:"clusterId"` + Contentmode string `json:"contentmode"` + DefaultStorageId string `json:"defaultStorageId"` + Description string `json:"description"` + DiskBus string `json:"diskBus"` + ExtendDisk string `json:"extendDisk"` + Features string `json:"features"` + Hypervisor string `json:"hypervisor"` + ImageId string `json:"imageId"` + ImageLocation string `json:"imageLocation"` + ImageOwnerId string `json:"imageOwnerId"` + ImagePath string `json:"imagePath"` + ImageSize int64 `json:"imageSize"` + ImageState string `json:"imageState"` + ImageType string `json:"imageType"` + IsBareMetal string `json:"isBareMetal"` + IsPublic bool `json:"isPublic"` + KernelId string `json:"kernelId"` + Name string `json:"name"` + OsId string `json:"osId"` + OSName string `json:"osName"` + Platform string `json:"platform"` + RamdiskId string `json:"ramdiskId"` + RootDeviceName string `json:"rootDeviceName"` + RootDeviceType string `json:"rootDeviceType"` + ScheduleTags string `json:"scheduleTags"` + Shared string `json:"shared"` + Sharemode string `json:"sharemode"` + StateReason string `json:"stateReason"` + StorageId string `json:"storageId"` +} + +func (self *SImage) GetId() string { + return self.ImageId +} + +func (self *SImage) GetGlobalId() string { + return self.GetId() +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (self *SImage) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.cache +} + +func (self *SImage) GetSizeByte() int64 { + return self.ImageSize +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + if self.IsPublic { + return cloudprovider.ImageTypeSystem + } + return cloudprovider.ImageTypeCustomized +} + +func (self *SImage) GetImageStatus() string { + return "" +} + +func (i *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if i.imageInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(i.OSName, i.Architecture, i.Platform, "", "") + i.imageInfo = &imgInfo + } + return i.imageInfo +} + +func (i *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(i.getNormalizedImageInfo().OsType) +} + +func (i *SImage) GetFullOsName() string { + return i.OSName +} + +func (i *SImage) GetOsArch() string { + return i.getNormalizedImageInfo().OsArch +} + +func (i *SImage) GetOsDist() string { + return i.getNormalizedImageInfo().OsDistro +} + +func (i *SImage) GetOsVersion() string { + return i.getNormalizedImageInfo().OsVersion +} + +func (i *SImage) GetOsLang() string { + return i.getNormalizedImageInfo().OsLang +} + +func (i *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(i.getNormalizedImageInfo().OsBios) +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return 0 +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SImage) GetImageFormat() string { + return "raw" +} + +func (self *SImage) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SImage) UEFI() bool { + return self.Bootloader == "uefi" +} + +func (self *SImage) GetPublicScope() rbacutils.TRbacScope { + if self.Shared == "true" { + return rbacutils.ScopeSystem + } + return rbacutils.ScopeDomain +} + +func (self *SImage) GetSubImages() []cloudprovider.SSubImage { + return []cloudprovider.SSubImage{} +} + +func (self *SImage) GetProjectId() string { + return "" +} + +func (self *SImage) GetStatus() string { + switch self.ImageState { + case "available": + return api.CACHED_IMAGE_STATUS_ACTIVE + default: + return self.ImageState + } +} + +func (self *SRegion) GetImages(id, nextToken string) ([]SImage, string, error) { + params := map[string]string{} + if len(id) > 0 { + params["imageId"] = id + } + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + resp, err := self.invoke("DescribeImages", params) + if err != nil { + return nil, "", err + } + ret := struct { + NextToken string + ImagesSet []SImage + }{} + resp.Unmarshal(&ret) + return ret.ImagesSet, ret.NextToken, nil +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + part, nextToken, err := self.region.GetImages("", "") + if err != nil { + return nil, err + } + images := []SImage{} + images = append(images, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.region.GetImages("", nextToken) + if err != nil { + return nil, err + } + images = append(images, part...) + } + ret := []cloudprovider.ICloudImage{} + for i := range images { + if images[i].StorageId == self.storageId { + images[i].cache = self + ret = append(ret, &images[i]) + } + } + return ret, nil +} + +func (self *SStoragecache) GetIImageById(id string) (cloudprovider.ICloudImage, error) { + images, _, err := self.region.GetImages(id, "") + if err != nil { + return nil, err + } + for i := range images { + if images[i].GetGlobalId() == id && images[i].StorageId == self.storageId { + images[i].cache = self + return &images[i], nil + } + } + + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/instance.go new file mode 100644 index 0000000000..6c67d6eaa6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/instance.go @@ -0,0 +1,384 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/cloudmux/pkg/apis" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SInstance struct { + BingoTags + multicloud.SInstanceBase + node *SNode + + ReservationId string `json:"reservationId"` + OwnerId string + GroupSet []struct { + GroupId string + GroupName string + } + InstancesSet struct { + InstanceId string `json:"instanceId"` + InstanceName string `json:"instanceName"` + HostName string `json:"hostName"` + ImageId string `json:"imageId"` + InstanceState struct { + Code int `json:"code"` + Name string `json:"name"` + PendingProgress string `json:"pendingProgress"` + } `json:"instanceState"` + PrivateDNSName string `json:"privateDnsName"` + DNSName string `json:"dnsName"` + PrivateIPAddress string `json:"privateIpAddress"` + PrivateIPAddresses string `json:"privateIpAddresses"` + IPAddress string `json:"ipAddress"` + NifInfo string `json:"nifInfo"` + KeyName string `json:"keyName"` + AmiLaunchIndex int `json:"amiLaunchIndex"` + ProductCodesSet []struct { + ProductCode string `json:"productCode"` + } `json:"productCodesSet"` + InstanceType string `json:"instanceType"` + VmtypeCPU int `json:"vmtype_cpu"` + VmtypeMem int `json:"vmtype_mem"` + VmtypeDisk int `json:"vmtype_disk"` + VmtypeGpu int `json:"vmtype_gpu"` + VmtypeSsd int `json:"vmtype_ssd"` + VmtypeHdd int `json:"vmtype_hdd"` + VmtypeHba int `json:"vmtype_hba"` + VmtypeSriov int `json:"vmtype_sriov"` + LaunchTime time.Time `json:"launchTime"` + RootDeviceType string `json:"rootDeviceType"` + HostAddress string `json:"hostAddress"` + Platform string `json:"platform"` + UseCompactMode bool `json:"useCompactMode"` + ExtendDisk bool `json:"extendDisk"` + Placement struct { + AvailabilityZone string `json:"availabilityZone"` + } `json:"placement"` + Namespace string `json:"namespace"` + KernelId string `json:"kernelId"` + RamdiskId string `json:"ramdiskId"` + OperName string `json:"operName"` + OperProgress int `json:"operProgress"` + Features string `json:"features"` + Monitoring struct { + State string `json:"state"` + } `json:"monitoring"` + SubnetId string `json:"subnetId"` + VpcId string `json:"vpcId"` + StorageId string `json:"storageId"` + DisableAPITermination bool `json:"disableApiTermination"` + Vncdisabled bool `json:"vncdisabled"` + StartTime time.Time `json:"startTime"` + CustomStatus string `json:"customStatus"` + SystemStatus int `json:"systemStatus"` + NetworkStatus int `json:"networkStatus"` + ScheduleTags string `json:"scheduleTags"` + StorageScheduleTags string `json:"storageScheduleTags"` + IsEncrypt bool `json:"isEncrypt"` + IsImported bool `json:"isImported"` + Ec2Version string `json:"ec2Version"` + Passphrase string `json:"passphrase"` + DrsEnabled bool `json:"drs_enabled"` + LaunchPriority int `json:"launchPriority"` + CPUPriority int `json:"cpuPriority"` + MemPriority int `json:"memPriority"` + CPUQuota int `json:"cpuQuota"` + AutoMigrate bool `json:"autoMigrate"` + DrMirrorId string `json:"drMirrorId"` + BlockDeviceMapping []struct { + DeviceName string `json:"deviceName"` + Ebs struct { + AttachTime time.Time `json:"attachTime"` + DeleteOnTermination bool `json:"deleteOnTermination"` + Status string `json:"status"` + VolumeId string `json:"volumeId"` + Size int `json:"size"` + } `json:"ebs"` + } `json:"blockDeviceMapping"` + EnableLiveScaleup bool `json:"enableLiveScaleup"` + ImageBytes int64 `json:"imageBytes"` + StatusReason string `json:"statusReason"` + Hypervisor string `json:"hypervisor"` + Bootloader string `json:"bootloader"` + BmMachineId string `json:"bmMachineId"` + } +} + +func (self *SInstance) GetId() string { + return self.InstancesSet.InstanceId +} + +func (self *SInstance) GetGlobalId() string { + return self.GetId() +} + +func (self *SInstance) GetName() string { + if len(self.InstancesSet.InstanceName) > 0 { + return self.InstancesSet.InstanceName + } + return self.GetId() +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + ret := []string{} + for _, sec := range self.GroupSet { + ret = append(ret, sec.GroupId) + } + return ret, nil +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) GetVcpuCount() int { + return self.InstancesSet.VmtypeCPU +} + +func (self *SInstance) GetVmemSizeMB() int { + return self.InstancesSet.VmtypeMem +} + +func (self *SInstance) GetBootOrder() string { + return "cdn" +} + +func (self *SInstance) GetVga() string { + return "" +} + +func (self *SInstance) GetVdi() string { + return "" +} + +func (self *SInstance) GetOsArch() string { + return apis.OS_ARCH_X86_64 +} + +func (self *SInstance) GetOsType() cloudprovider.TOsType { + if self.InstancesSet.Platform == "linux" { + return cloudprovider.OsTypeLinux + } + return cloudprovider.OsTypeWindows +} + +func (self *SInstance) GetFullOsName() string { + return "" +} + +func (self *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(self.InstancesSet.Bootloader) +} + +func (i *SInstance) GetOsDist() string { + return "" +} + +func (i *SInstance) GetOsVersion() string { + return "" +} + +func (i *SInstance) GetOsLang() string { + return "" +} + +func (self *SInstance) GetMachine() string { + return "" +} + +func (self *SInstance) GetInstanceType() string { + return self.InstancesSet.InstanceType +} + +func (self *SInstance) GetError() error { + return nil +} + +func (self *SInstance) GetHostname() string { + return self.InstancesSet.HostName +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.node +} + +func (self *SInstance) GetIHostId() string { + info := strings.Split(self.InstancesSet.HostAddress, "@") + if len(info) == 2 { + return info[1] + } + return "" +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_BINGO_CLOUD +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + storages, err := self.node.cluster.region.getStorages() + if err != nil { + return nil, err + } + storageMaps := map[string]SStorage{} + for i := range storages { + storageMaps[storages[i].StorageId] = storages[i] + } + ret := []cloudprovider.ICloudDisk{} + for _, _disk := range self.InstancesSet.BlockDeviceMapping { + disk, err := self.node.cluster.region.GetDisk(_disk.Ebs.VolumeId) + if err != nil { + return nil, err + } + storage, ok := storageMaps[disk.StorageId] + if ok { + storage.cluster = self.node.cluster + disk.storage = &storage + ret = append(ret, disk) + } + } + return ret, nil +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics, err := self.node.cluster.region.GetInstanceNics(self.InstancesSet.InstanceId) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNic{} + for i := range nics { + ret = append(ret, &nics[i]) + } + return ret, nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + eips, _, err := self.node.cluster.region.GetEips("", self.InstancesSet.InstanceId, "") + if err != nil { + return nil, err + } + for i := range eips { + eips[i].region = self.node.cluster.region + return &eips[i], nil + } + return nil, nil +} + +func (self *SInstance) GetProjectId() string { + return "" +} + +func (self *SInstance) GetStatus() string { + switch self.InstancesSet.InstanceState.Name { + case "stopped": + return api.VM_READY + default: + return self.InstancesSet.InstanceState.Name + } +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (self *SInstance) StartVM(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetInstances(id, nodeId string, maxResult int, nextToken string) ([]SInstance, string, error) { + params := map[string]string{} + if maxResult > 0 { + params["maxRecords"] = fmt.Sprintf("%d", maxResult) + } + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + + idx := 1 + if len(nodeId) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "node-id" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = nodeId + idx++ + } + + if len(id) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "instance-id" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = id + idx++ + } + + resp, err := self.invoke("DescribeInstances", params) + if err != nil { + return nil, "", err + } + result := struct { + NextToken string + ReservationSet []SInstance + }{} + err = resp.Unmarshal(&result) + if err != nil { + return nil, "", err + } + return result.ReservationSet, result.NextToken, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/instancenic.go new file mode 100644 index 0000000000..5fa7d48b78 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/instancenic.go @@ -0,0 +1,113 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import "yunion.io/x/cloudmux/pkg/cloudprovider" + +type SInstanceNic struct { + Association string `json:"association"` + Attachment struct { + AttachTime string `json:"attachTime"` + AttachmentId string `json:"attachmentId"` + DeleteOnTermination string `json:"deleteOnTermination"` + DeviceIndex string `json:"deviceIndex"` + InstanceId string `json:"instanceId"` + InstanceOwnerId string `json:"instanceOwnerId"` + Status string `json:"status"` + } `json:"attachment"` + AvailabilityZone string `json:"availabilityZone"` + Description string `json:"description"` + FirstPacketLimit string `json:"firstPacketLimit"` + MACAddress string `json:"macAddress"` + Model string `json:"model"` + NetworkInterfaceId string `json:"networkInterfaceId"` + NoMatchPort string `json:"noMatchPort"` + OwnerId string `json:"ownerId"` + PrivateDNSName string `json:"privateDnsName"` + PrivateIPAddress string `json:"privateIpAddress"` + PrivateIPAddressesSet []struct { + Association string `json:"association"` + Primary string `json:"primary"` + PrivateDNSName string `json:"privateDnsName"` + PrivateIPAddress string `json:"privateIpAddress"` + } `json:"privateIpAddressesSet"` + RequesterManaged string `json:"requesterManaged"` + SourceDestCheck string `json:"sourceDestCheck"` + Status string `json:"status"` + SubnetId string `json:"subnetId"` + VpcId string `json:"vpcId"` +} + +func (self *SInstanceNic) GetId() string { + return self.NetworkInterfaceId +} + +func (self *SInstanceNic) GetIP() string { + return self.PrivateIPAddress +} + +func (self *SInstanceNic) GetMAC() string { + return self.MACAddress +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) GetDriver() string { + return self.Model +} + +func (self *SInstanceNic) GetINetworkId() string { + return self.SubnetId +} + +func (self *SInstanceNic) GetSubAddress() ([]string, error) { + ret := []string{} + for _, ip := range self.PrivateIPAddressesSet { + if ip.PrivateIPAddress != self.PrivateIPAddress { + ret = append(ret, ip.PrivateIPAddress) + } + } + return ret, nil +} + +func (self *SInstanceNic) AssignNAddress(count int) ([]string, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstanceNic) UnassignAddress(ipAddrs []string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetInstanceNics(insId string) ([]SInstanceNic, error) { + params := map[string]string{} + if len(insId) > 0 { + params["instanceId"] = insId + } + resp, err := self.invoke("DescribeNetworkInterfaces", params) + if err != nil { + return nil, err + } + ret := struct { + NetworkInterfaceSet []SInstanceNic + }{} + resp.Unmarshal(&ret) + return ret.NetworkInterfaceSet, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/monitor.go new file mode 100644 index 0000000000..65796d83d1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/monitor.go @@ -0,0 +1,144 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "fmt" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type MetricOutput struct { + Datapoints Datapoints + ObjName string + Period int64 +} + +type DatapointMember struct { + Average float64 + Maximum float64 + Minimum float64 + SampleCount float64 + Sum float64 + Timestamp time.Time + Unit string +} + +func (self DatapointMember) GetValue() float64 { + return self.Average + self.Maximum + self.Minimum + self.Sum +} + +type Datapoints struct { + Member []DatapointMember +} + +func (self *SBingoCloudClient) DescribeMetricList(ns, metricNm, dimensionName, dimensionValue string, since time.Time, until time.Time) (*MetricOutput, error) { + params := map[string]string{} + params["Namespace"] = ns + params["MetricName"] = metricNm + params["Dimensions.member.1.Name"] = dimensionName + params["Dimensions.member.1.Value"] = dimensionValue + params["StartTime"] = since.Format(time.RFC3339) + params["EndTime"] = until.Format(time.RFC3339) + params["Statistics.member.1"] = "Average" + params["Period"] = "60" + resp, err := self.invoke("GetMetricStatistics", params) + if err != nil { + return nil, errors.Wrap(err, "GetMetricStatistics err") + } + ret := &MetricOutput{} + return ret, resp.Unmarshal(ret, "GetMetricStatisticsResult") +} + +func (self *SBingoCloudClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + if len(opts.ResourceId) == 0 { + return nil, fmt.Errorf("missing resourceId") + } + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_HOST: + return self.GetHostMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) + } +} + +func (self *SBingoCloudClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + for metricType, metricName := range map[cloudprovider.TMetricType]string{ + cloudprovider.VM_METRIC_TYPE_CPU_USAGE: "CPUUtilization", + cloudprovider.VM_METRIC_TYPE_MEM_USAGE: "MemeryUsage", + cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: "NetworkIn", + cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: "NetworkOut", + cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: "DiskReadBytes", + cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: "DiskWriteBytes", + cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: "DiskReadOps", + cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: "DiskWriteOps", + } { + data, err := self.DescribeMetricList("AWS/EC2", metricName, "InstanceId", opts.ResourceId, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("DescribeMetricList error: %v", err) + continue + } + metric := cloudprovider.MetricValues{} + metric.Id = opts.ResourceId + metric.MetricType = metricType + for _, value := range data.Datapoints.Member { + metricValue := cloudprovider.MetricValue{} + metricValue.Timestamp = value.Timestamp + metricValue.Value = value.GetValue() + metric.Values = append(metric.Values, metricValue) + } + ret = append(ret, metric) + } + return ret, nil +} + +func (self *SBingoCloudClient) GetHostMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + for metricType, metricName := range map[cloudprovider.TMetricType]string{ + cloudprovider.VM_METRIC_TYPE_CPU_USAGE: "CPUUtilization", + cloudprovider.VM_METRIC_TYPE_MEM_USAGE: "MemeryUsage", + cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: "NetworkIn", + cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: "NetworkOut", + cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: "DiskReadBytes", + cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: "DiskWriteBytes", + cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: "DiskReadOps", + cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: "DiskWriteOps", + } { + data, err := self.DescribeMetricList("AWS/HOST", metricName, "HostId", opts.ResourceId, opts.StartTime, opts.EndTime) + if err != nil { + log.Errorf("DescribeMetricList error: %v", err) + continue + } + metric := cloudprovider.MetricValues{} + metric.Id = opts.ResourceId + metric.MetricType = metricType + for _, value := range data.Datapoints.Member { + metricValue := cloudprovider.MetricValue{} + metricValue.Timestamp = value.Timestamp + metricValue.Value = value.GetValue() + metric.Values = append(metric.Values, metricValue) + } + ret = append(ret, metric) + } + return ret, nil + +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/network.go new file mode 100644 index 0000000000..e240545ce5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/network.go @@ -0,0 +1,199 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "fmt" + "strings" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + multicloud.STagBase + wire *SWire + + CidrBlock string `json:"cidrBlock"` + MapPublicIPOnLaunch string `json:"mapPublicIpOnLaunch"` + RouterId string `json:"routerId"` + NetworkFrom string `json:"networkFrom"` + NetworkNode string `json:"networkNode"` + IsManagedNetwork string `json:"isManagedNetwork"` + SubnetName string `json:"subnetName"` + NetworkMask string `json:"networkMask"` + NetName string `json:"netName"` + Index string `json:"index"` + VpcIsPublic string `json:"vpcIsPublic"` + Description string `json:"description"` + MicroSegmentation string `json:"microSegmentation"` + State string `json:"state"` + DefaultForAz string `json:"defaultForAz"` + Router string `json:"router"` + Active string `json:"active"` + VpcShared string `json:"vpcShared"` + DvswitchName string `json:"dvswitchName"` + AvailableIPAddressCount string `json:"availableIpAddressCount"` + VlanNum string `json:"vlanNum"` + RouterCc2 string `json:"router_cc2"` + ResStatus string `json:"res_status"` + IPAddressCount string `json:"ipAddressCount"` + RouterCc string `json:"router_cc"` + VpcId string `json:"vpcId"` + NetworkTo string `json:"networkTo"` + Broadcast string `json:"broadcast"` + UserName string `json:"userName"` + IPVersion string `json:"ipVersion"` + AvailabilityZone string `json:"availabilityZone"` + Network string `json:"network"` + RouterMac string `json:"router_mac"` + CheckIP string `json:"checkIp"` + FloatingPool string `json:"floatingPool"` + StaticPool string `json:"staticPool"` + DvsPortGroup string `json:"dvsPortGroup"` + SubnetId string `json:"subnetId"` +} + +func (self *SNetwork) GetId() string { + return self.SubnetId +} + +func (self *SNetwork) GetGlobalId() string { + return self.SubnetId +} + +func (self *SNetwork) GetName() string { + if len(self.SubnetName) > 0 { + return self.SubnetName + } + return self.SubnetId +} + +func (self *SNetwork) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 300 +} + +func (self *SNetwork) GetGateway() string { + prefix, err := netutils.NewIPV4Prefix(self.CidrBlock) + if err == nil { + return prefix.Address.StepUp().String() + } + return "" +} + +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) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetProjectId() string { + return "" +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetStatus() string { + return strings.ToLower(self.State) +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + networks, err := self.vpc.region.GetNetworks("", self.cluster.ClusterId, self.vpc.VpcId) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNetwork{} + for i := range networks { + networks[i].wire = self + ret = append(ret, &networks[i]) + } + return ret, nil +} + +func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { + networks, err := self.GetINetworks() + if err != nil { + return nil, err + } + for i := range networks { + if networks[i].GetGlobalId() == id { + return networks[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetNetworks(id, clusterId, vpcId string) ([]SNetwork, error) { + params := map[string]string{} + if len(id) > 0 { + params["subnetId"] = id + } + idx := 1 + if len(clusterId) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "availability-zone" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = clusterId + idx++ + } + if len(vpcId) > 0 { + params[fmt.Sprintf("Filter.%d.Name", idx)] = "vpc-id" + params[fmt.Sprintf("Filter.%d.Value.1", idx)] = vpcId + idx++ + } + resp, err := self.invoke("DescribeSubnets", params) + if err != nil { + return nil, err + } + networks := []SNetwork{} + return networks, resp.Unmarshal(&networks, "subnetSet") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/node.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/node.go new file mode 100644 index 0000000000..e37afd1bf2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/node.go @@ -0,0 +1,270 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SNode struct { + multicloud.SHostBase + multicloud.STagBase + + cluster *SCluster + + ClusterId string + CpuCores int + CpuMax int + CpuModel string + CpuNode int + CpuSockets int + CpuUsed int + DiskMax int + DiskNode int + DiskUsed int + MemNode int + MemoryMax int + MemoryUsed int + NodeId string + NodeName string + ScheduleTags string + Status string +} + +func (self *SRegion) GetNodes(clusterId, nodeId string) ([]SNode, error) { + params := map[string]string{} + if len(clusterId) > 0 { + params["clusterId"] = clusterId + } + if len(clusterId) > 0 { + params["nodeId"] = nodeId + } + resp, err := self.invoke("DescribeNodes", params) + if err != nil { + return nil, err + } + ret := []SNode{} + return ret, resp.Unmarshal(&ret, "nodeSet") +} + +func (self *SNode) GetId() string { + return self.NodeId +} + +func (self *SNode) GetGlobalId() string { + return self.NodeId +} + +func (self *SNode) GetName() string { + return self.NodeName +} + +func (self *SNode) GetAccessIp() string { + info := strings.Split(self.NodeId, "@") + if len(info) == 2 { + return info[1] + } + return "" +} + +func (self *SNode) GetAccessMac() string { + return "" +} + +func (self *SNode) GetSysInfo() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (self *SNode) GetSN() string { + return "" +} + +func (self *SNode) GetCpuCount() int { + return self.CpuNode +} + +func (self *SNode) GetNodeCount() int8 { + return int8(self.CpuSockets) +} + +func (self *SNode) GetCpuDesc() string { + return self.CpuModel +} + +func (self *SNode) GetCpuMhz() int { + return 0 +} + +func (self *SNode) GetCpuCmtbound() float32 { + if self.CpuMax > self.CpuNode { + return float32(self.CpuMax) / float32(self.CpuNode) + } + return 1 +} + +func (self *SNode) GetMemSizeMB() int { + return self.MemNode +} + +func (self *SNode) GetMemCmtbound() float32 { + if self.MemoryMax > self.MemNode { + return float32(self.MemoryMax) / float32(self.MemNode) + } + return 1 +} + +func (self *SNode) GetReservedMemoryMb() int { + return 0 +} + +func (self *SNode) GetStorageSizeMB() int { + if self.DiskMax > 0 { + return self.DiskMax * 1024 + } + return self.DiskNode * 1024 +} + +func (self *SNode) GetStorageType() string { + return api.STORAGE_LOCAL_SSD +} + +func (self *SNode) GetNodeType() string { + return api.HOST_TYPE_BINGO_CLOUD +} + +func (self *SNode) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SNode) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + return self.cluster.GetIStorages() +} + +func (self *SNode) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return self.cluster.GetIStorageById(id) +} + +func (self *SNode) GetEnabled() bool { + return true +} + +func (self *SNode) GetNodeStatus() string { + if self.Status == "available" { + return api.HOST_ONLINE + } + return api.HOST_OFFLINE +} + +func (self *SNode) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SNode) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms := []SInstance{} + part, nextToken, err := self.cluster.region.GetInstances("", self.NodeId, MAX_RESULT, "") + vms = append(vms, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.cluster.region.GetInstances("", self.NodeId, MAX_RESULT, nextToken) + if err != nil { + return nil, err + } + vms = append(vms, part...) + } + ret := []cloudprovider.ICloudVM{} + for i := range vms { + vms[i].node = self + ret = append(ret, &vms[i]) + } + return ret, nil +} + +func (self *SNode) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vms, _, err := self.cluster.region.GetInstances(id, self.NodeId, 1, "") + if err != nil { + return nil, err + } + for i := range vms { + if vms[i].GetGlobalId() == id { + vms[i].node = self + return &vms[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SNode) GetIWires() ([]cloudprovider.ICloudWire, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SNode) GetSchedtags() ([]string, error) { + return []string{}, nil +} + +func (self *SNode) GetIsMaintenance() bool { + return self.Status == "maintain" +} + +func (self *SNode) GetVersion() string { + return "" +} + +func (self *SNode) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SNode) GetHostStatus() string { + if self.Status != "available" { + return api.HOST_OFFLINE + } + return api.HOST_ONLINE +} + +func (self *SNode) GetHostType() string { + return api.HOST_TYPE_BINGO_CLOUD +} + +func (self *SCluster) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + nodes, err := self.region.GetNodes(self.ClusterId, id) + if err != nil { + return nil, err + } + for i := range nodes { + if nodes[i].GetGlobalId() == id { + nodes[i].cluster = self + return &nodes[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SCluster) GetIHosts() ([]cloudprovider.ICloudHost, error) { + nodes, err := self.region.GetNodes(self.ClusterId, "") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudHost{} + for i := range nodes { + nodes[i].cluster = self + ret = append(ret, &nodes[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/provider/doc.go new file mode 100644 index 0000000000..145784e878 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/bingocloud/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/provider/provider.go new file mode 100644 index 0000000000..28f95d8450 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/provider/provider.go @@ -0,0 +1,162 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/bingocloud" +) + +type SBingoCloudProviderFactory struct { + cloudprovider.SPrivateCloudBaseProviderFactory +} + +func (self *SBingoCloudProviderFactory) GetId() string { + return bingocloud.CLOUD_PROVIDER_BINGO_CLOUD +} + +func (self *SBingoCloudProviderFactory) GetName() string { + return bingocloud.CLOUD_PROVIDER_BINGO_CLOUD +} + +func (self *SBingoCloudProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { + return fmt.Errorf("Changing %s bandwidth is not supported", bingocloud.CLOUD_PROVIDER_BINGO_CLOUD) +} + +func (self *SBingoCloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + if len(input.Endpoint) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "endpoint") + } + output.AccessUrl = input.Endpoint + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + return output, nil +} + +func (self *SBingoCloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func (self *SBingoCloudProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + client, err := bingocloud.NewBingoCloudClient( + bingocloud.NewBingoCloudClientConfig( + cfg.URL, cfg.Account, cfg.Secret, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SBingoCloudProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SBingoCloudProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + return map[string]string{ + "BINGO_CLOUD_ENDPOINT": info.Url, + "BINGO_CLOUD_ACCESS_KEY": info.Account, + "BINGO_CLOUD_SECRET_KEY": info.Secret, + }, nil +} + +func init() { + factory := SBingoCloudProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SBingoCloudProvider struct { + cloudprovider.SBaseProvider + client *bingocloud.SBingoCloudClient +} + +func (self *SBingoCloudProvider) GetSysInfo() (jsonutils.JSONObject, error) { + return jsonutils.NewDict(), nil +} + +func (self *SBingoCloudProvider) GetVersion() string { + return "2009-08-15" +} + +func (self *SBingoCloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SBingoCloudProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SBingoCloudProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SBingoCloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(id) +} + +func (self *SBingoCloudProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SBingoCloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return []cloudprovider.ICloudProject{}, nil +} + +func (self *SBingoCloudProvider) GetStorageClasses(regionId string) []string { + return nil +} + +func (self *SBingoCloudProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (self *SBingoCloudProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (self *SBingoCloudProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SBingoCloudProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetMetrics(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/region.go new file mode 100644 index 0000000000..af81b2ce0e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/region.go @@ -0,0 +1,175 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + multicloud.SRegion + multicloud.SRegionEipBase + multicloud.SRegionLbBase + multicloud.SRegionOssBase + multicloud.SRegionSecurityGroupBase + multicloud.SRegionVpcBase + multicloud.SRegionZoneBase + + client *SBingoCloudClient + + RegionId string + RegionName string + Hypervisor string + NetworkMode string + RegionEndpoint string +} + +func (self *SRegion) GetId() string { + return self.RegionId +} + +func (self *SRegion) GetName() string { + return self.RegionName +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_BINGO_CLOUD, self.RegionId) +} + +func (self *SRegion) GetClient() *SBingoCloudClient { + return self.client +} + +func (self *SRegion) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + return cloudprovider.SModelI18nTable{} +} + +func (self *SRegion) GetProvider() string { + return api.CLOUD_PROVIDER_BINGO_CLOUD +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) GetCloudEnv() string { + return "" +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) invoke(action string, params map[string]string) (jsonutils.JSONObject, error) { + return self.client.invoke(action, params) +} + +func (self *SBingoCloudClient) GetRegions() ([]SRegion, error) { + resp, err := self.invoke("DescribeRegions", nil) + if err != nil { + return nil, err + } + ret := []SRegion{} + err = resp.Unmarshal(&ret, "regionInfo") + if err != nil { + return nil, err + } + return ret, nil +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storages := []SStorage{} + part, nextToken, err := self.GetStorages("") + if err != nil { + return nil, err + } + storages = append(storages, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.GetStorages(nextToken) + if err != nil { + return nil, err + } + storages = append(storages, part...) + } + ret := []cloudprovider.ICloudStoragecache{} + for i := range storages { + cache := SStoragecache{ + region: self, + storageName: storages[i].StorageName, + storageId: storages[i].StorageId, + } + ret = append(ret, &cache) + } + return ret, nil +} + +func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + caches, err := self.GetIStoragecaches() + if err != nil { + return nil, err + } + for i := range caches { + if caches[i].GetGlobalId() == id { + return caches[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + zones, err := self.GetIZones() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudHost{} + for i := range zones { + hosts, err := zones[i].GetIHosts() + if err != nil { + return nil, err + } + ret = append(ret, hosts...) + } + return ret, nil +} + +func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + zones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := range zones { + hosts, err := zones[i].GetIHosts() + if err != nil { + return nil, err + } + for i := range hosts { + if hosts[i].GetGlobalId() == id { + return hosts[i], nil + } + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/secgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/secgroup.go new file mode 100644 index 0000000000..fa8aa200ef --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/secgroup.go @@ -0,0 +1,190 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSecurityGroup struct { + multicloud.SResourceBase + BingoTags + region *SRegion + + ComplexIPPermissions string `json:"complexIpPermissions"` + ComplexIPPermissionsEgress string `json:"complexIpPermissionsEgress"` + DisplayName string `json:"displayName"` + GroupDescription string `json:"groupDescription"` + GroupId string `json:"groupId"` + GroupName string `json:"groupName"` + IPPermissionType string `json:"ipPermissionType"` + IPPermissions string `json:"ipPermissions"` + IPPermissionsEgress []IPPermissionsEgress `json:"ipPermissionsEgress"` + OwnerId string `json:"ownerId"` +} + +type IPPermissionsEgress struct { + BoundType string `json:"boundType"` + Description string `json:"description"` + FromPort int `json:"fromPort"` + IPProtocol string `json:"ipProtocol"` + Groups []struct { + GroupId string + GroupName string + } `json:"groups"` + IPRanges []struct { + CIdRIP string `json:"cidrIp"` + } `json:"ipRanges"` + L2Accept string `json:"l2Accept"` + PermissionId string `json:"permissionId"` + Policy string `json:"policy"` + ToPort int `json:"toPort"` +} + +func (self *SSecurityGroup) GetId() string { + return self.GroupId +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.GetId() +} + +func (self *SSecurityGroup) GetName() string { + return self.GroupName +} + +func (self *SSecurityGroup) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SSecurityGroup) GetDescription() string { + return self.GroupDescription +} + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} + +func (self *SSecurityGroup) GetReferences() ([]cloudprovider.SecurityGroupReference, error) { + return []cloudprovider.SecurityGroupReference{}, nil +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + ret := []cloudprovider.SecurityRule{} + for _, _rule := range self.IPPermissionsEgress { + if len(_rule.Groups) > 0 { + continue + } + rule := cloudprovider.SecurityRule{} + rule.Direction = secrules.DIR_IN + rule.Priority = 1 + rule.Action = secrules.SecurityRuleAllow + rule.Protocol = secrules.PROTO_ANY + rule.Description = _rule.Description + if _rule.BoundType == "Out" { + rule.Direction = secrules.DIR_OUT + } + if _rule.Policy == "DROP" { + rule.Action = secrules.SecurityRuleDeny + } + if _rule.IPProtocol != "all" { + rule.Protocol = _rule.IPProtocol + } + if rule.Protocol == secrules.PROTO_TCP || rule.Protocol == secrules.PROTO_UDP { + rule.PortStart, rule.PortEnd = _rule.FromPort, _rule.ToPort + } + + for _, ip := range _rule.IPRanges { + if ip.CIdRIP == "::/0" { + ip.CIdRIP = "0.0.0.0/0" + } + rule.ParseCIDR(ip.CIdRIP) + err := rule.ValidateRule() + if err != nil { + return nil, err + } + ret = append(ret, rule) + } + } + return ret, nil +} + +func (self *SSecurityGroup) GetVpcId() string { + return api.NORMAL_VPC_ID +} + +func (self *SSecurityGroup) GetStatus() string { + return api.SECGROUP_STATUS_READY +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetSecurityGroups(id, name, nextToken string) ([]SSecurityGroup, string, error) { + params := map[string]string{} + if len(id) > 0 { + params["groupId"] = id + } + if len(name) > 0 { + params["groupName"] = name + } + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + resp, err := self.invoke("DescribeSecurityGroups", params) + if err != nil { + return nil, "", err + } + ret := struct { + SecurityGroupInfo []SSecurityGroup + NextToken string + }{} + resp.Unmarshal(&ret) + return ret.SecurityGroupInfo, ret.NextToken, nil +} + +func (self *SRegion) GetISecurityGroupById(id string) (cloudprovider.ICloudSecurityGroup, error) { + groups, _, err := self.GetSecurityGroups(id, "", "") + if err != nil { + return nil, err + } + for i := range groups { + if groups[i].GetGlobalId() == id { + groups[i].region = self + return &groups[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + groups, _, err := self.GetSecurityGroups("", opts.Name, "") + if err != nil { + return nil, err + } + for i := range groups { + if groups[i].GetName() == opts.Name { + groups[i].region = self + return &groups[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/storage.go new file mode 100644 index 0000000000..3281aafe89 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/storage.go @@ -0,0 +1,173 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStorage struct { + multicloud.STagBase + multicloud.SStorageBase + cluster *SCluster + + StorageId string `json:"storageId"` + Location string `json:"location"` + UsedBy string `json:"usedBy"` + SpaceUsed int64 `json:"spaceUsed"` + StorageName string `json:"storageName"` + FileFormat string `json:"fileFormat"` + Disabled string `json:"disabled"` + SpaceMax int64 `json:"spaceMax"` + StorageType string `json:"storageType"` + DrCloudId string `json:"drCloudId"` + ParameterSet []struct { + Name string + Value string + } `json:"parameterSet"` + ClusterId string `json:"clusterId"` + IsDRStorage string `json:"isDRStorage"` + ResUsage string `json:"resUsage"` + ScheduleTags string `json:"scheduleTags"` +} + +func (self *SStorage) GetName() string { + return self.StorageName +} + +func (self *SStorage) GetId() string { + return self.StorageId +} + +func (self *SStorage) GetGlobalId() string { + return self.GetId() +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStorage) DisableSync() bool { + return false +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return &SStoragecache{storageId: self.StorageId, storageName: self.StorageName, region: self.cluster.region} +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.cluster +} + +func (self *SStorage) GetStorageType() string { + return self.StorageType +} + +func (self *SStorage) GetMediumType() string { + return api.DISK_TYPE_SSD +} + +func (self *SStorage) GetCapacityMB() int64 { + return self.SpaceMax * 1024 +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return self.SpaceUsed * 1024 +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + return jsonutils.Marshal(self.ParameterSet) +} + +func (self *SStorage) GetEnabled() bool { + return self.Disabled == "false" +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} + +func (self *SRegion) GetStorages(nextToken string) ([]SStorage, string, error) { + params := map[string]string{} + if len(nextToken) > 0 { + params["nextToken"] = nextToken + } + resp, err := self.invoke("DescribeStorages", params) + if err != nil { + return nil, "", err + } + ret := struct { + NextToken string + StorageSet []SStorage + }{} + resp.Unmarshal(&ret) + return ret.StorageSet, ret.NextToken, nil +} + +func (self *SCluster) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storages, err := self.GetIStorages() + if err != nil { + return nil, err + } + for i := range storages { + if storages[i].GetGlobalId() == id { + return storages[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SCluster) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.region.getStorages() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + storages[i].cluster = self + ret = append(ret, &storages[i]) + } + return ret, nil +} + +func (self *SRegion) getStorages() ([]SStorage, error) { + storages := []SStorage{} + part, nextToken, err := self.GetStorages("") + if err != nil { + return nil, err + } + storages = append(storages, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.GetStorages(nextToken) + if err != nil { + return nil, err + } + storages = append(storages, part...) + } + return storages, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/storagecache.go new file mode 100644 index 0000000000..e0d0339612 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/storagecache.go @@ -0,0 +1,71 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStoragecache struct { + multicloud.SResourceBase + multicloud.STagBase + + region *SRegion + storageId string + storageName string +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.GetGlobalId(), self.storageId) +} + +func (self *SStoragecache) GetGlobalId() string { + return self.GetId() +} + +func (self *SStoragecache) GetName() string { + return self.storageName +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { + return "", cloudprovider.ErrNotImplemented +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/tag_base.go new file mode 100644 index 0000000000..82611ebcdc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/tag_base.go @@ -0,0 +1,44 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type BingoTags struct { + TagSet []struct { + Key string + Value string + } +} + +func (self *BingoTags) GetTags() (map[string]string, error) { + tags := map[string]string{} + for _, tag := range self.TagSet { + tags[tag.Key] = tag.Value + } + return tags, nil +} + +func (self *BingoTags) GetSysTags() map[string]string { + return nil +} + +func (self *BingoTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/vpc.go new file mode 100644 index 0000000000..c1dff8caed --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/vpc.go @@ -0,0 +1,142 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + multicloud.STagBase + + region *SRegion + + RequestId string `json:"requestId"` + VlanNum string `json:"vlanNum"` + AsGateway string `json:"asGateway"` + DhcpOptionsId string `json:"dhcpOptionsId"` + VpcName string `json:"vpcName"` + OwnerId string `json:"ownerId"` + WanCode string `json:"wanCode"` + Shared string `json:"shared"` + SubnetPolicy string `json:"subnetPolicy"` + Description string `json:"description"` + VpcId string `json:"vpcId"` + IsPublicNetwork string `json:"isPublicNetwork"` + GatewayId string `json:"gatewayId"` + IsDefault string `json:"isDefault"` + Provider string `json:"provider"` + State string `json:"state"` + CidrBlock string `json:"cidrBlock"` + InstanceTenancy string `json:"instanceTenancy"` +} + +func (self *SVpc) GetId() string { + return self.VpcId +} + +func (self *SVpc) GetGlobalId() string { + return self.VpcId +} + +func (self *SVpc) GetName() string { + return self.VpcName +} + +func (self *SVpc) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SVpc) GetCidrBlock() string { + return self.CidrBlock +} + +func (self *SVpc) GetIRouteTableById(id string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + part, nextToken, err := self.region.GetSecurityGroups("", "", "") + if err != nil { + return nil, err + } + groups := []SSecurityGroup{} + groups = append(groups, part...) + for len(nextToken) > 0 { + part, nextToken, err = self.region.GetSecurityGroups("", "", nextToken) + if err != nil { + return nil, err + } + groups = append(groups, part...) + } + ret := []cloudprovider.ICloudSecurityGroup{} + for i := range groups { + groups[i].region = self.region + ret = append(ret, &groups[i]) + } + return ret, nil +} + +func (self *SVpc) GetIsDefault() bool { + return self.IsDefault == "true" +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetStatus() string { + switch self.State { + case "available": + return api.VPC_STATUS_AVAILABLE + default: + return self.State + } +} + +func (self *SRegion) GetVpcs(id string) ([]SVpc, error) { + params := map[string]string{} + if len(id) > 0 { + params["vpcId"] = id + } + resp, err := self.invoke("DescribeVpcs", params) + if err != nil { + return nil, err + } + vpcs := []SVpc{} + return vpcs, resp.Unmarshal(&vpcs, "vpcSet") +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + vpcs, err := self.GetVpcs("") + if err != nil { + return nil, errors.Wrapf(err, "GetVpcs") + } + ret := []cloudprovider.ICloudVpc{} + for i := range vpcs { + vpcs[i].region = self + ret = append(ret, &vpcs[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/wire.go new file mode 100644 index 0000000000..68533aafdb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/wire.go @@ -0,0 +1,94 @@ +// Copyright 2019 Yunion +// +// 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 bingocloud + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.STagBase + multicloud.SResourceBase + + cluster *SCluster + vpc *SVpc +} + +func (self *SWire) GetId() string { + return fmt.Sprintf("%s/%s", self.vpc.GetGlobalId(), self.cluster.GetGlobalId()) +} + +func (self *SWire) GetGlobalId() string { + return self.GetId() +} + +func (self *SWire) GetName() string { + return fmt.Sprintf("%s-%s", self.vpc.GetName(), self.cluster.GetName()) +} + +func (self *SWire) GetBandwidth() int { + return 1000 +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) IsEmulated() bool { + return true +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return self.cluster +} + +func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { + wires, err := self.GetIWires() + if err != nil { + return nil, err + } + for i := range wires { + if wires[i].GetGlobalId() == id { + return wires[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + clusters, err := self.region.GetClusters() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudWire{} + for i := range clusters { + wire := &SWire{ + vpc: self, + cluster: &clusters[i], + } + ret = append(ret, wire) + } + return ret, nil +} diff --git a/pkg/multicloud/bingocloud/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/zone.go similarity index 100% rename from pkg/multicloud/bingocloud/zone.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/bingocloud/zone.go diff --git a/pkg/multicloud/bucket_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bucket_base.go similarity index 97% rename from pkg/multicloud/bucket_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/bucket_base.go index 1b2060cda9..039de618b6 100644 --- a/pkg/multicloud/bucket_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/bucket_base.go @@ -15,8 +15,8 @@ package multicloud import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SBaseBucket struct { diff --git a/pkg/multicloud/cloudpods/cloudpods.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/cloudpods.go similarity index 98% rename from pkg/multicloud/cloudpods/cloudpods.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/cloudpods.go index 80863bebb6..66b8fb02e3 100644 --- a/pkg/multicloud/cloudpods/cloudpods.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/cloudpods.go @@ -22,13 +22,14 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modulebase" "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) const ( diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/disk.go new file mode 100644 index 0000000000..dcc5990979 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/disk.go @@ -0,0 +1,282 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDisk struct { + multicloud.SVirtualResourceBase + multicloud.SBillingBase + CloudpodsTags + region *SRegion + + api.DiskDetails + guestDisk *api.GuestDiskDetails +} + +func (self *SDisk) GetId() string { + return self.Id +} + +func (self *SDisk) GetGlobalId() string { + return self.Id +} + +func (self *SDisk) GetName() string { + return self.Name +} + +func (self *SDisk) GetStatus() string { + return self.Status +} + +func (self *SDisk) GetIops() int { + return 0 +} + +func (self *SDisk) Refresh() error { + disk, err := self.region.GetDisk(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, disk) +} + +func (self *SDisk) GetDiskFormat() string { + return self.DiskFormat +} + +func (self *SDisk) GetDiskSizeMB() int { + return self.DiskSize +} + +func (self *SDisk) GetIsAutoDelete() bool { + return self.AutoDelete +} + +func (self *SDisk) GetTemplateId() string { + return self.TemplateId +} + +func (self *SDisk) GetDiskType() string { + return self.DiskType +} + +func (self *SDisk) GetFsFormat() string { + return self.FsFormat +} + +func (self *SDisk) GetIsNonPersistent() bool { + return self.Nonpersistent +} + +func (self *SDisk) fetchGuestDisk() error { + if self.guestDisk != nil { + return nil + } + if len(self.Guests) > 0 { + gds, err := self.region.GetGuestDisks("", self.Id) + if err != nil { + return err + } + for i := range gds { + self.guestDisk = &gds[i] + break + } + } + return nil +} + +func (self *SDisk) GetDriver() string { + self.fetchGuestDisk() + if self.guestDisk != nil { + return self.guestDisk.Driver + } + return "" +} + +func (self *SDisk) GetCacheMode() string { + self.fetchGuestDisk() + if self.guestDisk != nil { + return self.guestDisk.CacheMode + } + return "" +} + +func (self *SDisk) GetMountpoint() string { + self.fetchGuestDisk() + if self.guestDisk != nil { + return self.guestDisk.Mountpoint + } + return "" +} + +func (self *SDisk) GetAccessPath() string { + return self.AccessPath +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := self.region.GetSnapshots(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudSnapshot{} + for i := range snapshots { + snapshots[i].region = self.region + ret = append(ret, &snapshots[i]) + } + return ret, nil +} + +func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { + ret := []string{} + for _, policy := range self.Snapshotpolicies { + ret = append(ret, policy.Id) + } + return ret, nil +} + +func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { + input := api.DiskResizeInput{} + input.Size = fmt.Sprintf("%dM", sizeMb) + _, err := self.region.perform(&modules.Disks, self.Id, "resize", input) + return err +} + +func (self *SDisk) Reset(ctx context.Context, snapId string) (string, error) { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(snapId), "snapshot") + _, err := self.region.perform(&modules.Disks, self.Id, "disk-reset", params) + return self.Id, err +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SDisk) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SDisk) GetExpiredAt() time.Time { + return self.ExpiredAt +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + input := api.SnapshotCreateInput{} + input.Name = name + input.Description = desc + input.DiskId = self.Id + input.ProjectId = self.TenantId + snapshot := &SSnapshot{region: self.region} + return snapshot, self.region.create(&modules.Snapshots, input, snapshot) +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + storage, err := self.region.GetStorage(self.StorageId) + if err != nil { + return nil, err + } + return storage, nil +} + +func (self *SDisk) GetIStorageId() string { + return self.StorageId +} + +func (self *SDisk) Delete(ctx context.Context) error { + return self.region.cli.delete(&modules.Disks, self.Id) +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := self.region.GetDisks(self.Id, "") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudDisk{} + for i := range disks { + disks[i].region = self.region + ret = append(ret, &disks[i]) + } + return ret, nil +} + +func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disk, err := self.region.GetDisk(id) + if err != nil { + return nil, err + } + return disk, nil +} + +func (self *SStorage) CreateIDisk(opts *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + input := api.DiskCreateInput{ + DiskConfig: &api.DiskConfig{}, + } + input.Name = opts.Name + input.Description = opts.Desc + input.SizeMb = opts.SizeGb * 1024 + input.Storage = self.Id + input.ProjectId = opts.ProjectId + disk := &SDisk{region: self.region} + return disk, self.region.create(&modules.Disks, input, disk) +} + +func (self *SRegion) GetDisk(id string) (*SDisk, error) { + disk := &SDisk{region: self} + return disk, self.cli.get(&modules.Disks, id, nil, disk) +} + +func (self *SRegion) GetDisks(storageId, serverId string) ([]SDisk, error) { + params := map[string]interface{}{} + if len(storageId) > 0 { + params["storage_id"] = storageId + } + if len(serverId) > 0 { + params["server_id"] = serverId + } + disks := []SDisk{} + return disks, self.list(&modules.Disks, params, &disks) +} + +func (self *SRegion) GetGuestDisks(guestId string, diskId string) ([]api.GuestDiskDetails, error) { + params := map[string]interface{}{ + "scope": "system", + } + if len(guestId) > 0 { + params["server_id"] = guestId + } + if len(diskId) > 0 { + params["disk_id"] = diskId + } + ret := []api.GuestDiskDetails{} + resp, err := modules.Serverdisks.List(self.cli.s, jsonutils.Marshal(params)) + if err != nil { + return nil, err + } + return ret, jsonutils.Update(&ret, resp.Data) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/doc.go new file mode 100644 index 0000000000..63215930c4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods // import "yunion.io/x/cloudmux/pkg/multicloud/cloudpods" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/eip.go new file mode 100644 index 0000000000..bd0cb70cb8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/eip.go @@ -0,0 +1,183 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SEip struct { + multicloud.SVirtualResourceBase + multicloud.SBillingBase + CloudpodsTags + region *SRegion + + api.ElasticipDetails +} + +func (self *SEip) GetName() string { + return self.Name +} + +func (self *SEip) GetId() string { + return self.Id +} + +func (self *SEip) GetGlobalId() string { + return self.Id +} + +func (self *SEip) GetProjectId() string { + return self.TenantId +} + +func (self *SEip) GetStatus() string { + return self.Status +} + +func (self *SEip) Refresh() error { + eip, err := self.region.GetEip(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, eip) +} + +func (self *SEip) GetBillingType() string { + return self.BillingType +} + +func (self *SEip) GetIpAddr() string { + return self.IpAddr +} + +func (self *SEip) GetINetworkId() string { + return self.NetworkId +} + +func (self *SEip) GetAssociationType() string { + return self.AssociateType +} + +func (self *SEip) GetAssociationExternalId() string { + return self.AssociateId +} + +func (self *SEip) GetBandwidth() int { + return self.Bandwidth +} + +func (self *SEip) GetInternetChargeType() string { + return self.ChargeType +} + +func (self *SEip) Delete() error { + return self.region.cli.delete(&modules.Elasticips, self.Id) +} + +func (self *SEip) IsAutoRenew() bool { + return self.AutoRenew +} + +func (self *SEip) Associate(opts *cloudprovider.AssociateConfig) error { + input := api.ElasticipAssociateInput{} + input.InstanceType = opts.AssociateType + input.InstanceId = opts.InstanceId + switch opts.AssociateType { + case api.EIP_ASSOCIATE_TYPE_SERVER: + default: + return cloudprovider.ErrNotImplemented + } + _, err := self.region.perform(&modules.Elasticips, self.Id, "associate", input) + return err +} + +func (self *SEip) Dissociate() error { + _, err := self.region.perform(&modules.Elasticips, self.Id, "dissociate", nil) + return err +} + +func (self *SEip) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SEip) GetExpiredAt() time.Time { + return self.ExpiredAt +} + +func (self *SEip) GetMode() string { + return self.Mode +} + +func (self *SEip) ChangeBandwidth(bw int) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { + eip, err := self.GetEip(id) + if err != nil { + return nil, err + } + return eip, nil +} + +func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, err := self.GetEips("") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudEIP{} + for i := range eips { + eips[i].region = self + ret = append(ret, &eips[i]) + } + return ret, nil +} + +func (self *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + input := api.SElasticipCreateInput{} + input.Name = opts.Name + input.CloudregionId = self.Id + input.ChargeType = opts.ChargeType + input.BandwidthMb = opts.BandwidthMbps + input.ProjectId = opts.ProjectId + input.NetworkId = opts.NetworkExternalId + input.BgpType = opts.BGPType + input.IpAddr = opts.IP + eip := &SEip{region: self} + return eip, self.create(&modules.Elasticips, input, eip) +} + +func (self *SRegion) GetEips(associateId string) ([]SEip, error) { + eips := []SEip{} + params := map[string]interface{}{} + if len(associateId) > 0 { + params["associate_id"] = associateId + } + return eips, self.list(&modules.Elasticips, params, &eips) +} + +func (self *SRegion) GetEip(id string) (*SEip, error) { + eip := &SEip{region: self} + return eip, self.cli.get(&modules.Elasticips, id, nil, eip) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/host.go new file mode 100644 index 0000000000..6e7f49ae79 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/host.go @@ -0,0 +1,290 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/tristate" + + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone + + api.HostDetails +} + +func (self *SHost) GetGlobalId() string { + return self.Id +} + +func (self *SHost) GetId() string { + return self.Id +} + +func (self *SHost) GetName() string { + return self.Name +} + +func (self *SHost) GetStatus() string { + return self.Status +} + +func (self *SHost) GetAccessIp() string { + return self.AccessIp +} + +func (self *SHost) GetOvnVersion() string { + return self.OvnVersion +} + +func (self *SHost) Refresh() error { + host, err := self.zone.region.GetHost(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, host) +} + +func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + wires, err := self.zone.region.GetWires("", self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudWire{} + for i := range wires { + vpc, _ := self.zone.region.GetVpc(wires[i].VpcId) + wires[i].vpc = vpc + ret = append(ret, &wires[i]) + } + return ret, nil +} + +func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.zone.region.GetStorages("", self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + storages[i].region = self.zone.region + ret = append(ret, &storages[i]) + } + return ret, nil +} + +func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storage, err := self.zone.region.GetStorage(id) + if err != nil { + return nil, err + } + return storage, nil +} + +func (self *SHost) GetEnabled() bool { + return self.Enabled != nil && *self.Enabled +} + +func (self *SHost) GetHostStatus() string { + return self.HostStatus +} + +func (self *SHost) GetAccessMac() string { + return self.AccessMac +} + +func (self *SHost) GetSysInfo() jsonutils.JSONObject { + return jsonutils.Marshal(self.SysInfo) +} + +func (self *SHost) GetSN() string { + return self.SN +} + +func (self *SHost) GetCpuCount() int { + return self.CpuCount +} + +func (self *SHost) GetNodeCount() int8 { + return int8(self.NodeCount) +} + +func (self *SHost) GetCpuDesc() string { + return self.CpuDesc +} + +func (self *SHost) GetCpuMhz() int { + return self.CpuMhz +} + +func (self *SHost) GetCpuCmtbound() float32 { + return self.CpuCmtbound +} + +func (self *SHost) GetMemSizeMB() int { + return self.MemSize +} + +func (self *SHost) GetMemCmtbound() float32 { + return self.MemCmtbound +} + +func (self *SHost) GetReservedMemoryMb() int { + return self.MemReserved +} + +func (self *SHost) GetStorageSizeMB() int { + return self.StorageSize +} + +func (self *SHost) GetStorageType() string { + return self.StorageType +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_CLOUDPODS +} + +func (self *SHost) GetIsMaintenance() bool { + return self.IsMaintenance +} + +func (self *SHost) GetVersion() string { + return self.Version +} + +func (self *SHost) GetSchedtags() ([]string, error) { + ret := []string{} + for _, tag := range self.Schedtags { + ret = append(ret, tag.Name) + } + return ret, nil +} + +type SHostNic struct { + api.HostnetworkDetails +} + +func (self *SHostNic) GetDriver() string { + return "" +} + +func (self *SHostNic) GetDevice() string { + return "" +} + +func (self *SHostNic) GetMac() string { + return self.MacAddr +} + +func (self *SHostNic) GetIndex() int8 { + return int8(self.RowId) +} + +func (self *SHostNic) IsLinkUp() tristate.TriState { + return tristate.True +} + +func (self *SHostNic) GetMtu() int32 { + return 0 +} + +func (self *SHostNic) GetNicType() string { + return self.NicType +} + +func (self *SHostNic) GetBridge() string { + return "" +} + +func (self *SHostNic) GetIpAddr() string { + return self.IpAddr +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + nics := []SHostNic{} + params := map[string]interface{}{ + "scope": "system", + "details": "true", + } + resp, err := modules.Baremetalnetworks.ListDescendent(self.zone.region.cli.s, self.Id, jsonutils.Marshal(params)) + if err != nil { + return nil, err + } + err = jsonutils.Update(&nics, resp.Data) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudHostNetInterface{} + for i := range nics { + ret = append(ret, &nics[i]) + } + return ret, nil +} + +func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + hypervisor := api.HOSTTYPE_HYPERVISOR[self.HostType] + ins, err := self.zone.region.CreateInstance(self.Id, hypervisor, opts) + if err != nil { + return nil, err + } + ins.host = self + return ins, nil +} + +func (self *SRegion) GetHost(id string) (*SHost, error) { + host := &SHost{} + return host, self.cli.get(&modules.Hosts, id, nil, host) +} + +func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + host, err := self.region.GetHost(id) + if err != nil { + return nil, err + } + host.zone = self + return host, nil +} + +func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + hosts, err := self.region.GetHosts(self.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetHosts") + } + ret := []cloudprovider.ICloudHost{} + for i := range hosts { + hosts[i].zone = self + ret = append(ret, &hosts[i]) + } + return ret, nil +} + +func (self *SRegion) GetHosts(zoneId string) ([]SHost, error) { + params := map[string]interface{}{ + "baremetal": false, + } + if len(zoneId) > 0 { + params["zone_id"] = zoneId + } + ret := []SHost{} + return ret, self.list(&modules.Hosts, params, &ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/image.go new file mode 100644 index 0000000000..1629a792f8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/image.go @@ -0,0 +1,220 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "context" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/onecloud/pkg/apis/image" + "yunion.io/x/onecloud/pkg/esxi/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/onecloud/pkg/util/imagetools" + "yunion.io/x/onecloud/pkg/util/qemuimg" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SImage struct { + multicloud.SImageBase + CloudpodsTags + cache *SStoragecache + + api.ImageDetails +} + +func (self *SImage) GetProjectId() string { + return self.TenantId +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (self *SImage) GetId() string { + return self.Id +} + +func (self *SImage) GetGlobalId() string { + return self.Id +} + +func (self *SImage) GetStatus() string { + return self.Status +} + +func (self *SImage) Delete(ctx context.Context) error { + return self.cache.region.cli.delete(&modules.Images, self.Id) +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.cache +} + +func (self *SImage) GetSizeByte() int64 { + return self.Size +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + if self.IsStandard != nil && *self.IsStandard { + return cloudprovider.ImageTypeSystem + } + return cloudprovider.ImageTypeCustomized +} + +func (self *SImage) GetImageStatus() string { + return self.Status +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + osType, ok := self.Properties["os_type"] + if ok { + return cloudprovider.TOsType(osType) + } + return cloudprovider.OsTypeLinux +} + +func (self *SImage) GetOsDist() string { + osDist, ok := self.Properties["os_distribution"] + if ok { + return osDist + } + return "" +} + +func (self *SImage) GetOsVersion() string { + osVer, ok := self.Properties["os_version"] + if ok { + return osVer + } + return "" +} + +func (self *SImage) GetOsArch() string { + osArch, ok := self.Properties["os_arch"] + if ok { + return osArch + } + return "" +} + +func (self *SImage) GetOsLang() string { + osLang, ok := self.Properties["os_language"] + if ok { + return osLang + } + return "" +} + +func (self *SImage) GetBios() cloudprovider.TBiosType { + uefi, ok := self.Properties["uefi_support"] + if ok && utils.ToBool(uefi) { + return cloudprovider.UEFI + } + return cloudprovider.BIOS +} + +func (img *SImage) GetFullOsName() string { + imgInfo := imagetools.NormalizeImageInfo("", img.GetOsArch(), string(img.GetOsType()), img.GetOsDist(), img.GetOsVersion()) + return imgInfo.GetFullOsName() +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return int(self.MinDiskMB / 1024) +} + +func (self *SImage) GetMinRamSizeMb() int { + return int(self.MinRamMB) +} + +func (self *SImage) GetImageFormat() string { + return self.DiskFormat +} + +func (self *SImage) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SImage) Refresh() error { + image, err := self.cache.region.GetImage(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, image) +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + images, err := self.region.GetImages() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudImage{} + for i := range images { + images[i].cache = self + ret = append(ret, &images[i]) + } + return ret, nil +} + +func (self *SRegion) GetImages() ([]SImage, error) { + params := map[string]interface{}{ + "is_guest_image": false, + } + images := []SImage{} + return images, self.list(&modules.Images, params, &images) +} + +func (self *SRegion) GetImage(id string) (*SImage, error) { + image := &SImage{} + resp, err := modules.Images.GetById(self.cli.s, id, nil) + if err != nil { + return nil, err + } + return image, resp.Unmarshal(image) +} + +func (self *SRegion) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, opts *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + s := auth.GetAdminSession(ctx, options.Options.Region) + + meta, reader, sizeByte, err := modules.Images.Download(s, opts.ImageId, string(qemuimg.QCOW2), false) + if err != nil { + return "", err + } + log.Infof("meta data %s", meta) + + params := map[string]interface{}{ + "name": opts.ImageName, + "properties": map[string]string{ + "os_type": opts.OsType, + "os_distribution": opts.OsDistribution, + "os_arch": opts.OsArch, + "os_version": opts.OsVersion, + }, + } + + body := multicloud.NewProgress(sizeByte, 90, reader, callback) + resp, err := modules.Images.Upload(self.cli.s, jsonutils.Marshal(params), body, sizeByte) + if err != nil { + return "", err + } + return resp.GetString("id") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/instance.go new file mode 100644 index 0000000000..d76ac546ef --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/instance.go @@ -0,0 +1,566 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + "yunion.io/x/onecloud/pkg/apis" + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + "yunion.io/x/onecloud/pkg/mcclient/modules/identity" + "yunion.io/x/onecloud/pkg/mcclient/modules/logger" + "yunion.io/x/onecloud/pkg/mcclient/modules/monitor" + "yunion.io/x/onecloud/pkg/mcclient/modules/webconsole" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SInstance struct { + multicloud.SInstanceBase + CloudpodsTags + + host *SHost + api.ServerDetails +} + +func (self *SInstance) GetName() string { + return self.Name +} + +func (self *SInstance) GetHostname() string { + return self.Hostname +} + +func (self *SInstance) GetId() string { + return self.Id +} + +func (self *SInstance) GetGlobalId() string { + return self.Id +} + +func (self *SInstance) GetStatus() string { + return self.Status +} + +func (self *SInstance) Refresh() error { + ins, err := self.host.zone.region.GetInstance(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, ins) +} + +func (self *SInstance) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SInstance) GetExpiredAt() time.Time { + return self.ExpiredAt +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetIHostId() string { + return self.HostId +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := self.host.zone.region.GetDisks("", self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudDisk{} + for i := range disks { + disks[i].region = self.host.zone.region + ret = append(ret, &disks[i]) + } + return ret, nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + if len(self.Eip) > 0 { + eips, err := self.host.zone.region.GetEips(self.Id) + if err != nil { + return nil, err + } + for i := range eips { + eips[i].region = self.host.zone.region + return &eips[i], nil + } + return nil, cloudprovider.ErrNotFound + } + return nil, nil +} + +func (self *SInstance) GetVcpuCount() int { + return self.VcpuCount +} + +func (self *SInstance) GetVmemSizeMB() int { + return self.VmemSize +} + +func (self *SInstance) GetBootOrder() string { + return self.BootOrder +} + +func (self *SInstance) GetVga() string { + return self.Vga +} + +func (self *SInstance) GetVdi() string { + return self.Vdi +} + +func (self *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(self.OsType) +} + +func (self *SInstance) GetFullOsName() string { + return self.OsName +} + +func (self *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(self.Bios) +} + +func (ins *SInstance) GetOsDist() string { + val, ok := ins.Metadata["os_distribution"] + if ok { + return val + } + return "" +} + +func (ins *SInstance) GetOsVersion() string { + val, ok := ins.Metadata["os_version"] + if ok { + return val + } + return "" +} + +func (ins *SInstance) GetOsLang() string { + val, ok := ins.Metadata["os_language"] + if ok { + return val + } + return "" +} + +func (ins *SInstance) GetOsArch() string { + return ins.OsArch +} + +func (self *SInstance) GetMachine() string { + return self.Machine +} + +func (self *SInstance) GetInstanceType() string { + return self.InstanceType +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + ret := []string{} + for _, sec := range self.Secgroups { + ret = append(ret, sec.Id) + } + return ret, nil +} + +func (self *SInstance) GetProjectId() string { + return self.TenantId +} + +func (self *SInstance) AssignSecurityGroup(id string) error { + input := api.GuestAssignSecgroupInput{} + input.SecgroupId = id + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "assign-secgroup", input) + return err +} + +func (self *SInstance) SetSecurityGroups(ids []string) error { + if self.Hypervisor == api.HYPERVISOR_ESXI { + return nil + } + input := api.GuestSetSecgroupInput{} + input.SecgroupIds = ids + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "set-secgroup", input) + return err +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_CLOUDPODS +} + +func (self *SInstance) StartVM(ctx context.Context) error { + if self.Status == api.VM_RUNNING { + return nil + } + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "start", nil) + return err +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + if self.Status == api.VM_READY { + return nil + } + input := api.ServerStopInput{} + input.IsForce = opts.IsForce + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "stop", input) + return err +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + if self.DisableDelete != nil && *self.DisableDelete { + input := api.ServerUpdateInput{} + disableDelete := false + input.DisableDelete = &disableDelete + self.host.zone.region.cli.update(&modules.Servers, self.Id, input) + } + return self.host.zone.region.cli.delete(&modules.Servers, self.Id) +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + if self.Name != name { + input := api.ServerUpdateInput{} + input.Name = name + self.host.zone.region.cli.update(&modules.Servers, self.Id, input) + return cloudprovider.WaitMultiStatus(self, []string{api.VM_READY, api.VM_RUNNING}, time.Second*5, time.Minute*3) + } + return nil +} + +func (self *SInstance) UpdateUserData(userData string) error { + input := api.ServerUserDataInput{} + input.UserData = userData + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "user-data", input) + return err +} + +func (self *SInstance) RebuildRoot(ctx context.Context, opts *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + input := api.ServerRebuildRootInput{} + input.ImageId = opts.ImageId + input.Password = opts.Password + if len(opts.PublicKey) > 0 { + keypairId, err := self.host.zone.region.syncKeypair(self.Name, opts.PublicKey) + if err != nil { + return "", errors.Wrapf(err, "syncKeypair") + } + input.KeypairId = keypairId + } + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "rebuild-root", input) + if err != nil { + return "", err + } + return self.DisksInfo[0].Id, nil +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + input := api.ServerDeployInput{} + input.Password = password + if len(publicKey) > 0 { + keypairId, err := self.host.zone.region.syncKeypair(name, publicKey) + if err != nil { + return errors.Wrapf(err, "syncKeypair") + } + input.KeypairId = keypairId + } + + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "deploy", input) + if err != nil { + return errors.Wrapf(err, "deploy") + } + return cloudprovider.WaitMultiStatus(self, []string{api.VM_READY, api.VM_RUNNING}, time.Second*5, time.Minute*3) +} + +func (self *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error { + input := api.ServerChangeConfigInput{} + input.VmemSize = fmt.Sprintf("%dM", opts.MemoryMB) + input.VcpuCount = opts.Cpu + input.InstanceType = opts.InstanceType + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "change-config", input) + return err +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + s := self.host.zone.region.cli.s + resp, err := webconsole.WebConsole.DoServerConnect(s, self.Id, nil) + if err != nil { + return nil, errors.Wrapf(err, "DoServerConnect") + } + result := &cloudprovider.ServerVncOutput{ + Protocol: "cloudpods", + InstanceId: self.Id, + InstanceName: self.Name, + Hypervisor: api.HYPERVISOR_CLOUDPODS, + } + err = resp.Unmarshal(&result) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + resp, err = identity.ServicesV3.GetSpecific(s, "common", "config", nil) + if err != nil { + return nil, errors.Wrapf(err, "GetSpecific") + } + result.ApiServer, _ = resp.GetString("config", "default", "api_server") + return result, nil +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + input := api.ServerAttachDiskInput{} + input.DiskId = diskId + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "attachdisk", input) + return err +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + input := api.ServerDetachDiskInput{} + input.DiskId = diskId + input.KeepDisk = true + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "detachdisk", input) + return err +} + +func (self *SInstance) MigrateVM(hostId string) error { + input := api.GuestMigrateInput{} + input.PreferHost = hostId + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "migrate", input) + return err +} + +func (self *SInstance) LiveMigrateVM(hostId string) error { + input := api.GuestLiveMigrateInput{} + input.PreferHost = hostId + skipCpuCheck := true + input.SkipCpuCheck = &skipCpuCheck + _, err := self.host.zone.region.perform(&modules.Servers, self.Id, "live-migrate", input) + return err +} + +func (self *SInstance) GetError() error { + if utils.IsInStringArray(self.Status, []string{api.VM_DISK_FAILED, api.VM_SCHEDULE_FAILED, api.VM_NETWORK_FAILED}) { + return fmt.Errorf("vm create failed with status %s", self.Status) + } + if self.Status == api.VM_DEPLOY_FAILED { + params := map[string]interface{}{"obj_id": self.Id, "success": false} + actions := []apis.OpsLogDetails{} + self.host.zone.region.list(&logger.Actions, params, &actions) + if len(actions) > 0 { + return fmt.Errorf(actions[0].Notes) + } + return fmt.Errorf("vm create failed with status %s", self.Status) + } + return nil +} + +func (self *SInstance) CreateInstanceSnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudInstanceSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SInstance) GetInstanceSnapshot(idStr string) (cloudprovider.ICloudInstanceSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SInstance) GetInstanceSnapshots() ([]cloudprovider.ICloudInstanceSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SInstance) ResetToInstanceSnapshot(ctx context.Context, idStr string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { + return self.host.zone.region.SaveImage(self.Id, opts.Name, opts.Notes) +} + +func (self *SRegion) SaveImage(id, imageName, notes string) (*SImage, error) { + input := api.ServerSaveImageInput{} + input.GenerateName = imageName + input.Notes = notes + resp, err := self.perform(&modules.Servers, id, "save-image", input) + if err != nil { + return nil, err + } + imageId, err := resp.GetString("image_id") + if err != nil { + return nil, err + } + caches, err := self.GetStoragecaches() + if err != nil { + return nil, errors.Wrapf(err, "GetStoragecaches") + } + if len(caches) == 0 { + return nil, fmt.Errorf("no storage cache found") + } + caches[0].region = self + image, err := self.GetImage(imageId) + if err != nil { + return nil, err + } + image.cache = &caches[0] + return image, nil +} + +func (self *SInstance) AllocatePublicIpAddress() (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + servers, err := self.zone.region.GetInstances(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudVM{} + for i := range servers { + servers[i].host = self + ret = append(ret, &servers[i]) + } + return ret, nil +} + +func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + ins, err := self.zone.region.GetInstance(id) + if err != nil { + return nil, err + } + ins.host = self + return ins, nil +} + +func (self *SRegion) GetInstance(id string) (*SInstance, error) { + ins := &SInstance{} + return ins, self.cli.get(&modules.Servers, id, nil, ins) +} + +func (self *SRegion) GetInstances(hostId string) ([]SInstance, error) { + params := map[string]interface{}{} + if len(hostId) > 0 { + params["host_id"] = hostId + } + ret := []SInstance{} + return ret, self.list(&modules.Servers, params, &ret) +} + +func (self *SRegion) CreateInstance(hostId, hypervisor string, opts *cloudprovider.SManagedVMCreateConfig) (*SInstance, error) { + input := api.ServerCreateInput{ + ServerConfigs: &api.ServerConfigs{}, + } + input.Name = opts.Name + input.Hostname = opts.Hostname + input.Description = opts.Description + input.InstanceType = opts.InstanceType + input.VcpuCount = opts.Cpu + input.VmemSize = opts.MemoryMB + input.Password = opts.Password + input.PublicIpBw = opts.PublicIpBw + input.PublicIpChargeType = string(opts.PublicIpChargeType) + input.ProjectId = opts.ProjectId + input.Metadata = opts.Tags + input.UserData = opts.UserData + input.PreferHost = hostId + input.Hypervisor = hypervisor + if len(input.UserData) > 0 { + input.EnableCloudInit = true + } + input.Secgroups = opts.ExternalSecgroupIds + if opts.BillingCycle != nil { + input.Duration = opts.BillingCycle.String() + } + input.Disks = append(input.Disks, &api.DiskConfig{ + Index: 0, + ImageId: opts.ExternalImageId, + DiskType: api.DISK_TYPE_SYS, + SizeMb: opts.SysDisk.SizeGB * 1024, + Backend: opts.SysDisk.StorageType, + Storage: opts.SysDisk.StorageExternalId, + }) + for idx, disk := range opts.DataDisks { + input.Disks = append(input.Disks, &api.DiskConfig{ + Index: idx + 1, + DiskType: api.DISK_TYPE_DATA, + SizeMb: disk.SizeGB * 1024, + Backend: disk.StorageType, + Storage: disk.StorageExternalId, + }) + } + input.Networks = append(input.Networks, &api.NetworkConfig{ + Index: 0, + Network: opts.ExternalNetworkId, + Address: opts.IpAddr, + }) + ins := &SInstance{} + return ins, self.create(&modules.Servers, input, ins) +} + +type SMetricData struct { + Id string `json:"id"` + Time time.Time `json:"time"` + Value float64 `json:"value"` +} + +func (cli *SCloudpodsClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + brandArr := []string{"OneCloud", "VMware"} + metrics := []SMetricData{} + for i := 0; i < len(brandArr); i++ { + params := map[string]interface{}{ + "metric_name": opts.MetricType, + "tags": map[string]interface{}{ + "brand": brandArr[i], + }, + } + onecloudObj, err := monitor.UnifiedMonitorManager.Get(cli.s, "simple-query", jsonutils.Marshal(params)) + if err != nil { + return nil, err + } + tmp := []SMetricData{} + onecloudObj.Unmarshal(&tmp, "values") + metrics = append(metrics, tmp...) + } + + idWithMetric := map[string][]cloudprovider.MetricValue{} + for _, v := range metrics { + if _, isExist := idWithMetric[v.Id]; !isExist { + idWithMetric[v.Id] = []cloudprovider.MetricValue{{ + Timestamp: v.Time, + Value: v.Value}} + } else { + idWithMetric[v.Id] = append(idWithMetric[v.Id], cloudprovider.MetricValue{ + Timestamp: v.Time, + Value: v.Value}) + } + } + + res := []cloudprovider.MetricValues{} + for _, metric := range metrics { + res = append(res, cloudprovider.MetricValues{ + Id: metric.Id, + MetricType: opts.MetricType, + Values: idWithMetric[metric.Id], + }) + } + return res, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/instancenic.go new file mode 100644 index 0000000000..7a413b16ea --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/instancenic.go @@ -0,0 +1,102 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + api "yunion.io/x/onecloud/pkg/apis/compute" +) + +type SInstanceNic struct { + multicloud.SResourceBase + ins *SInstance + + api.GuestnetworkDetails +} + +func (self *SInstanceNic) GetId() string { + return fmt.Sprintf("%d", self.RowId) +} + +func (self *SInstanceNic) GetIP() string { + return self.IpAddr +} + +func (self *SInstanceNic) GetDriver() string { + return self.Driver +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) GetMAC() string { + return self.MacAddr +} + +func (self *SInstanceNic) GetSubAddress() ([]string, error) { + return []string{}, nil +} + +func (self *SInstanceNic) AssignNAddress(count int) ([]string, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstanceNic) UnassignAddress(IpAddrs []string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstanceNic) GetINetworkId() string { + return self.NetworkId +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics, err := self.host.zone.region.GetGuestnetworks(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNic{} + for i := range nics { + nics[i].ins = self + ret = append(ret, &nics[i]) + } + return ret, nil +} + +func (self *SRegion) GetGuestnetworks(serverId string) ([]SInstanceNic, error) { + ret := []SInstanceNic{} + params := map[string]interface{}{ + "scope": "system", + } + if len(serverId) > 0 { + params["server_id"] = serverId + } + resp, err := modules.Servernetworks.List(self.cli.s, jsonutils.Marshal(params)) + if err != nil { + return nil, err + } + return ret, jsonutils.Update(&ret, resp.Data) +} diff --git a/pkg/multicloud/cloudpods/keypair.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/keypair.go similarity index 100% rename from pkg/multicloud/cloudpods/keypair.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/keypair.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/network.go new file mode 100644 index 0000000000..15daa732e2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/network.go @@ -0,0 +1,137 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + "yunion.io/x/onecloud/pkg/util/rbacutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SNetwork struct { + multicloud.SResourceBase + CloudpodsTags + wire *SWire + + api.NetworkDetails +} + +func (self *SNetwork) GetName() string { + return self.Name +} + +func (self *SNetwork) GetId() string { + return self.Id +} + +func (self *SNetwork) GetGlobalId() string { + return self.Id +} + +func (self *SNetwork) GetStatus() string { + return self.Status +} + +func (self *SNetwork) Delete() error { + return self.wire.vpc.region.cli.delete(&modules.Networks, self.Id) +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpStart() string { + return self.GuestIpStart +} + +func (self *SNetwork) GetIpEnd() string { + return self.GuestIpEnd +} + +func (self *SNetwork) GetIpMask() int8 { + return int8(self.GuestIpMask) +} + +func (self *SNetwork) GetGateway() string { + return self.GuestGateway +} + +func (self *SNetwork) GetServerType() string { + return self.ServerType +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.TRbacScope(self.PublicScope) +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return self.AllocTimoutSeconds +} + +func (self *SNetwork) GetProjectId() string { + return self.TenantId +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + networks, err := self.vpc.region.GetNetworks(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNetwork{} + for i := range networks { + networks[i].wire = self + ret = append(ret, &networks[i]) + } + return ret, nil +} + +func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { + net, err := self.vpc.region.GetNetwork(id) + if err != nil { + return nil, errors.Wrapf(err, "GetNetwork(%s)", id) + } + net.wire = self + return net, nil +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + input := api.NetworkCreateInput{} + input.Name = opts.Name + input.Description = opts.Desc + input.GuestIpPrefix = opts.Cidr + input.WireId = self.Id + input.ProjectId = opts.ProjectId + network := &SNetwork{wire: self} + return network, self.vpc.region.create(&modules.Networks, input, network) +} + +func (self *SRegion) GetNetworks(wireId string) ([]SNetwork, error) { + networks := []SNetwork{} + params := map[string]interface{}{} + if len(wireId) > 0 { + params["wire_id"] = wireId + } + return networks, self.list(&modules.Networks, params, &networks) +} + +func (self *SRegion) GetNetwork(id string) (*SNetwork, error) { + network := &SNetwork{} + return network, self.cli.get(&modules.Networks, id, nil, network) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/project.go new file mode 100644 index 0000000000..029fc41851 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/project.go @@ -0,0 +1,71 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + api "yunion.io/x/onecloud/pkg/apis/identity" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/identity" + + "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SProject struct { + multicloud.SProjectBase + CloudpodsTags + + cli *SCloudpodsClient + + api.ProjectDetails +} + +func (self *SProject) GetName() string { + return self.Name +} + +func (self *SProject) GetId() string { + return self.Id +} + +func (self *SProject) GetGlobalId() string { + return self.Id +} + +func (self *SProject) GetStatus() string { + return compute.EXTERNAL_PROJECT_STATUS_AVAILABLE +} + +func (self *SCloudpodsClient) GetProjects() ([]SProject, error) { + ret := []SProject{} + params := map[string]interface{}{ + "scope": "system", + "limit": 1024, + } + return ret, self.list(&modules.Projects, params, &ret) +} + +func (self *SCloudpodsClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { + projects, err := self.GetProjects() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudProject{} + for i := range projects { + projects[i].cli = self + ret = append(ret, &projects[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/provider/doc.go new file mode 100644 index 0000000000..cc8110e493 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/cloudpods/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/provider/provider.go new file mode 100644 index 0000000000..632a9c529c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/provider/provider.go @@ -0,0 +1,161 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/cloudpods" +) + +type SCloudpodsProviderFactory struct { + cloudprovider.SPrivateCloudBaseProviderFactory +} + +func (self *SCloudpodsProviderFactory) GetId() string { + return cloudpods.CLOUD_PROVIDER_CLOUDPODS +} + +func (self *SCloudpodsProviderFactory) GetName() string { + return cloudpods.CLOUD_PROVIDER_CLOUDPODS +} + +func (self *SCloudpodsProviderFactory) IsNeedForceAutoCreateProject() bool { + return true +} + +func (self *SCloudpodsProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + ret := cloudprovider.SCloudaccount{} + if len(input.AuthUrl) == 0 { + return ret, httperrors.NewMissingParameterError("auth_url") + } + ret.AccessUrl = input.AuthUrl + if len(input.AccessKeyId) == 0 { + return ret, httperrors.NewMissingParameterError("access_key_id") + } + ret.Account = input.AccessKeyId + if len(input.AccessKeySecret) == 0 { + return ret, httperrors.NewMissingParameterError("access_key_secret") + } + ret.Secret = input.AccessKeySecret + return ret, nil +} + +func (self *SCloudpodsProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + ret := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return ret, httperrors.NewMissingParameterError("access_key_id") + } + ret.Account = input.AccessKeyId + if len(input.AccessKeySecret) == 0 { + return ret, httperrors.NewMissingParameterError("access_key_secret") + } + ret.Secret = input.AccessKeySecret + return ret, nil +} + +func (self *SCloudpodsProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + client, err := cloudpods.NewCloudpodsClient( + cloudpods.NewCloudpodsClientConfig( + cfg.URL, + cfg.Account, + cfg.Secret, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SCloudpodsProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SCloudpodsProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + return map[string]string{ + "CLOUDPODS_AUTH_URL": info.Url, + "CLOUDPODS_ACCESS_KEY": info.Account, + "CLOUDPODS_ACCESS_SECRET": info.Secret, + }, nil +} + +func init() { + factory := SCloudpodsProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SCloudpodsProvider struct { + cloudprovider.SBaseProvider + client *cloudpods.SCloudpodsClient +} + +func (self *SCloudpodsProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SCloudpodsProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SCloudpodsProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (self *SCloudpodsProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SCloudpodsProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SCloudpodsProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(extId) +} + +func (self *SCloudpodsProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SCloudpodsProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (self *SCloudpodsProvider) GetStorageClasses(regionId string) []string { + return nil +} + +func (self *SCloudpodsProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SCloudpodsProvider) GetSysInfo() (jsonutils.JSONObject, error) { + return jsonutils.NewDict(), nil +} + +func (self *SCloudpodsProvider) GetVersion() string { + return self.client.GetVersion() +} + +func (provider *SCloudpodsProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return provider.client.GetMetrics(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/region.go new file mode 100644 index 0000000000..abae26d509 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/region.go @@ -0,0 +1,131 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/onecloud/pkg/apis/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + multicloud.SRegion + multicloud.SRegionOssBase + multicloud.SRegionLbBase + multicloud.SRegionSecurityGroupBase + cli *SCloudpodsClient + + api.CloudregionDetails +} + +func (self *SRegion) GetClient() *SCloudpodsClient { + return self.cli +} + +func (self *SRegion) GetId() string { + return self.Id +} + +func (self *SRegion) GetName() string { + return fmt.Sprintf("%s-%s", self.cli.cpcfg.Name, self.Name) +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s/%s", CLOUD_PROVIDER_CLOUDPODS, self.cli.cpcfg.Id, self.Name) +} + +func (self *SRegion) GetStatus() string { + return self.Status +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) + return table +} + +func (self *SRegion) GetCapabilities() []string { + return self.cli.GetCapabilities() +} + +func (self *SRegion) GetCloudEnv() string { + return api.CLOUD_ENV_PRIVATE_CLOUD +} + +func (self *SRegion) GetProvider() string { + return api.CLOUD_PROVIDER_CLOUDPODS +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + return cloudprovider.SGeographicInfo{ + Latitude: self.Latitude, + Longitude: self.Longitude, + City: self.City, + CountryCode: self.CountryCode, + } +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + ins, err := self.GetInstance(id) + if err != nil { + return nil, err + } + return ins, nil +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disk, err := self.GetDisk(id) + if err != nil { + return nil, err + } + return disk, nil +} + +func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + host, err := self.GetHost(id) + if err != nil { + return nil, err + } + if host.CloudregionId != self.Id { + return nil, cloudprovider.ErrNotFound + } + zone, err := self.GetZone(host.ZoneId) + if err != nil { + return nil, err + } + host.zone = zone + return host, nil +} + +func (self *SRegion) create(manager ModelManager, params interface{}, retVal interface{}) error { + return self.cli.create(manager, params, retVal) +} + +func (self *SRegion) perform(manager ModelManager, id, action string, params interface{}) (jsonutils.JSONObject, error) { + return self.cli.perform(manager, id, action, params) +} + +func (self *SRegion) list(manager ModelManager, params map[string]interface{}, retVal interface{}) error { + if params == nil { + params = map[string]interface{}{} + } + params["cloudregion_id"] = self.Id + return self.cli.list(manager, params, retVal) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/secgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/secgroup.go new file mode 100644 index 0000000000..1b0421d770 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/secgroup.go @@ -0,0 +1,207 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "fmt" + "strings" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSecurityGroup struct { + multicloud.SResourceBase + CloudpodsTags + region *SRegion + + api.SecgroupDetails +} + +func (self *SSecurityGroup) GetName() string { + return self.Name +} + +func (self *SSecurityGroup) GetDescription() string { + return self.Description +} + +func (self *SSecurityGroup) GetId() string { + return self.Id +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.Id +} + +func (self *SSecurityGroup) GetStatus() string { + return self.Status +} + +func (self *SSecurityGroup) GetProjectId() string { + return self.TenantId +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + ret := []cloudprovider.SecurityRule{} + for _, r := range self.Rules { + if len(r.PeerSecgroupId) > 0 { + continue + } + rule := cloudprovider.SecurityRule{ExternalId: r.Id} + rule.Action = secrules.TSecurityRuleAction(r.Action) + rule.Priority = int(r.Priority) + rule.Protocol = r.Protocol + rule.Description = r.Description + rule.Direction = secrules.TSecurityRuleDirection(r.Direction) + rule.ParseCIDR(r.CIDR) + rule.ParsePorts(r.Ports) + ret = append(ret, rule) + } + return ret, nil +} + +func (self *SSecurityGroup) GetVpcId() string { + return api.NORMAL_VPC_ID +} + +func (self *SSecurityGroup) GetReferences() ([]cloudprovider.SecurityGroupReference, error) { + params := map[string]interface{}{ + "secgroup_id": self.Id, + } + servers := []SInstance{} + err := self.region.list(&modules.Servers, params, &servers) + if err != nil { + return nil, err + } + ret := []cloudprovider.SecurityGroupReference{} + for i := range servers { + ret = append(ret, cloudprovider.SecurityGroupReference{ + Id: servers[i].Id, + Name: servers[i].Name, + }) + } + return ret, nil +} + +func (self *SRegion) DeleteSecRule(id string) error { + return self.cli.delete(&modules.SecGroupRules, id) +} + +func (self *SRegion) CreateSecRule(secId string, rule cloudprovider.SecurityRule) error { + input := api.SSecgroupRuleCreateInput{} + input.SecgroupId = secId + input.Priority = &rule.Priority + input.Action = string(rule.Action) + input.Protocol = rule.Protocol + input.Direction = string(rule.Direction) + input.Description = rule.Description + if rule.IPNet != nil { + input.CIDR = rule.IPNet.String() + } + + if len(rule.Ports) > 0 { + ports := []string{} + for _, port := range rule.Ports { + ports = append(ports, fmt.Sprintf("%d", port)) + } + input.Ports = strings.Join(ports, ",") + } else if rule.PortStart > 0 && rule.PortEnd > 0 { + input.Ports = fmt.Sprintf("%d-%d", rule.PortStart, rule.PortEnd) + } + ret := struct{}{} + return self.create(&modules.SecGroupRules, input, &ret) +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + for _, r := range append(inDels, outDels...) { + err := self.region.DeleteSecRule(r.Id) + if err != nil { + return errors.Wrapf(err, "delete rule %s", r.Id) + } + } + for _, r := range append(inAdds, outAdds...) { + err := self.region.CreateSecRule(self.Id, r) + if err != nil { + return errors.Wrapf(err, "create rule %s", r) + } + } + return nil +} + +func (self *SSecurityGroup) Delete() error { + return self.region.cli.delete(&modules.SecGroups, self.Id) +} + +func (self *SRegion) GetSecurityGroups() ([]SSecurityGroup, error) { + params := map[string]interface{}{ + "cloud_env": "onpremise", + } + ret := []SSecurityGroup{} + return ret, self.cli.list(&modules.SecGroups, params, &ret) +} + +func (self *SRegion) GetSecurityGroup(id string) (*SSecurityGroup, error) { + secgroup := &SSecurityGroup{region: self} + return secgroup, self.cli.get(&modules.SecGroups, id, nil, secgroup) +} + +func (self *SRegion) CreateISecurityGroup(opts *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + params := map[string]interface{}{ + "name": opts.Name, + "description": opts.Desc, + "rules": opts.Rules, + } + if len(opts.ProjectId) > 0 { + params["project_id"] = opts.ProjectId + } + secgroup := &SSecurityGroup{region: self} + return secgroup, self.create(&modules.SecGroups, params, secgroup) +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := self.region.GetSecurityGroups() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudSecurityGroup{} + for i := range secgroups { + secgroups[i].region = self.region + ret = append(ret, &secgroups[i]) + } + return ret, nil +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + secgroup, err := self.GetSecurityGroup(secgroupId) + if err != nil { + return nil, err + } + return secgroup, nil +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroup, err := self.GetSecurityGroup(opts.Name) + if err != nil { + return nil, err + } + return secgroup, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/sku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/sku.go new file mode 100644 index 0000000000..b7d850fc5a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/sku.go @@ -0,0 +1,161 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SServerSku struct { + multicloud.SResourceBase + CloudpodsTags + region *SRegion + + api.ServerSkuDetails +} + +func (self *SServerSku) GetName() string { + return self.Name +} + +func (self *SServerSku) GetId() string { + return self.Id +} + +func (self *SServerSku) GetGlobalId() string { + return self.Id +} + +func (self *SServerSku) GetStatus() string { + return self.Status +} + +func (self *SServerSku) GetInstanceTypeFamily() string { + return self.InstanceTypeFamily +} + +func (self *SServerSku) GetInstanceTypeCategory() string { + return self.InstanceTypeCategory +} + +func (self *SServerSku) GetPrepaidStatus() string { + return self.PrepaidStatus +} + +func (self *SServerSku) GetPostpaidStatus() string { + return self.PostpaidStatus +} + +func (self *SServerSku) GetCpuArch() string { + return "x86" +} + +func (self *SServerSku) GetCpuCoreCount() int { + return self.CpuCoreCount +} + +func (self *SServerSku) GetMemorySizeMB() int { + return self.MemorySizeMB +} + +func (self *SServerSku) GetOsName() string { + return self.OsName +} + +func (self *SServerSku) GetSysDiskResizable() bool { + return self.SysDiskResizable != nil && *self.SysDiskResizable +} + +func (self *SServerSku) GetSysDiskType() string { + return self.SysDiskType +} + +func (self *SServerSku) GetSysDiskMinSizeGB() int { + return self.SysDiskMinSizeGB +} + +func (self *SServerSku) GetSysDiskMaxSizeGB() int { + return self.SysDiskMaxSizeGB +} + +func (self *SServerSku) GetAttachedDiskType() string { + return self.AttachedDiskType +} + +func (self *SServerSku) GetAttachedDiskSizeGB() int { + return self.AttachedDiskSizeGB +} + +func (self *SServerSku) GetAttachedDiskCount() int { + return self.AttachedDiskCount +} + +func (self *SServerSku) GetDataDiskTypes() string { + return self.DataDiskTypes +} + +func (self *SServerSku) GetDataDiskMaxCount() int { + return self.DataDiskMaxCount +} + +func (self *SServerSku) GetNicType() string { + return self.NicType +} + +func (self *SServerSku) GetNicMaxCount() int { + return self.NicMaxCount +} + +func (self *SServerSku) GetGpuAttachable() bool { + return self.GpuAttachable != nil && *self.GpuAttachable +} + +func (self *SServerSku) GetGpuSpec() string { + return self.GpuSpec +} + +func (self *SServerSku) GetGpuCount() int { + return self.GpuCount +} + +func (self *SServerSku) GetGpuMaxCount() int { + return self.GpuMaxCount +} + +func (self *SServerSku) Delete() error { + return self.region.cli.delete(&modules.ServerSkus, self.Id) +} + +func (self *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { + skus, err := self.GetServerSkus() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudSku{} + for i := range skus { + skus[i].region = self + ret = append(ret, &skus[i]) + } + return ret, nil +} + +func (self *SRegion) GetServerSkus() ([]SServerSku, error) { + skus := []SServerSku{} + return skus, self.list(&modules.ServerSkus, nil, &skus) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/snapshot.go new file mode 100644 index 0000000000..d574594d20 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/snapshot.go @@ -0,0 +1,112 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "yunion.io/x/jsonutils" + + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSnapshot struct { + multicloud.SVirtualResourceBase + CloudpodsTags + region *SRegion + + api.SnapshotDetails +} + +func (self *SSnapshot) GetName() string { + return self.Name +} + +func (self *SSnapshot) GetId() string { + return self.Id +} + +func (self *SSnapshot) GetGlobalId() string { + return self.Id +} + +func (self *SSnapshot) GetStatus() string { + return self.Status +} + +func (self *SSnapshot) GetProjectId() string { + return self.TenantId +} + +func (self *SSnapshot) GetSizeMb() int32 { + return int32(self.Size) +} + +func (self *SSnapshot) GetDiskId() string { + return self.DiskId +} + +func (self *SSnapshot) GetDiskType() string { + return self.DiskType +} + +func (self *SSnapshot) Delete() error { + return self.region.cli.delete(&modules.Snapshots, self.Id) +} + +func (self *SSnapshot) Refresh() error { + snapshot, err := self.region.GetSnapshot(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, snapshot) +} + +func (self *SRegion) GetSnapshots(diskId string) ([]SSnapshot, error) { + ret := []SSnapshot{} + params := map[string]interface{}{} + if len(diskId) > 0 { + params["disk_id"] = diskId + } + return ret, self.list(&modules.Snapshots, params, &ret) +} + +func (self *SRegion) GetSnapshot(id string) (*SSnapshot, error) { + snapshot := &SSnapshot{region: self} + return snapshot, self.cli.get(&modules.Snapshots, id, nil, snapshot) +} + +func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := self.GetSnapshots("") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudSnapshot{} + for i := range snapshots { + snapshots[i].region = self + ret = append(ret, &snapshots[i]) + } + return ret, nil +} + +func (self *SRegion) GetISnapshotById(id string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := self.GetSnapshot(id) + if err != nil { + return nil, err + } + return snapshot, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/storage.go new file mode 100644 index 0000000000..e3cca3c34c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/storage.go @@ -0,0 +1,140 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStorage struct { + multicloud.SStorageBase + region *SRegion + + api.StorageDetails +} + +func (self *SStorage) GetId() string { + return self.Id +} + +func (self *SStorage) GetGlobalId() string { + return self.Id +} + +func (self *SStorage) GetName() string { + return self.Name +} + +func (self *SStorage) GetStatus() string { + return self.Status +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + zone, err := self.region.GetZone(self.ZoneId) + if err != nil { + return nil + } + return zone +} + +func (self *SStorage) GetMediumType() string { + return self.MediumType +} + +func (self *SStorage) GetCapacityMB() int64 { + return self.Capacity +} + +func (self *SStorage) GetStorageType() string { + return self.StorageType +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return self.ActualCapacityUsed +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + return self.StorageConf +} + +func (self *SStorage) GetEnabled() bool { + return self.Enabled != nil && *self.Enabled +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + if len(self.StoragecacheId) == 0 { + return nil + } + cache, _ := self.region.GetStoragecache(self.StoragecacheId) + return cache +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + return self.SStorage.IsSysDiskStore != nil && *self.SStorage.IsSysDiskStore +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.region.GetStorages(self.Id, "") + if err != nil { + return nil, errors.Wrapf(err, "GetStorages") + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + storages[i].region = self.region + ret = append(ret, &storages[i]) + } + return ret, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return self.region.GetIStorageById(id) +} + +func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storage, err := self.GetStorage(id) + if err != nil { + return nil, err + } + storage.region = self + return storage, nil +} + +func (self *SRegion) GetStorage(id string) (*SStorage, error) { + storage := &SStorage{region: self} + return storage, self.cli.get(&modules.Storages, id, nil, storage) +} + +func (self *SRegion) GetStorages(zoneId, hostId string) ([]SStorage, error) { + params := map[string]interface{}{} + if len(zoneId) > 0 { + params["zone_id"] = zoneId + } + if len(hostId) > 0 { + params["host_id"] = hostId + } + storages := []SStorage{} + return storages, self.list(&modules.Storages, params, &storages) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/storagecache.go new file mode 100644 index 0000000000..d485ffbcf7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/storagecache.go @@ -0,0 +1,129 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "context" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStoragecache struct { + multicloud.SResourceBase + CloudpodsTags + region *SRegion + + api.StoragecacheDetails +} + +func (self *SStoragecache) GetName() string { + return self.Name +} + +func (self *SStoragecache) GetId() string { + return self.Id +} + +func (self *SStoragecache) GetGlobalId() string { + return self.Id +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetIImageById(id string) (cloudprovider.ICloudImage, error) { + image, err := self.region.GetImage(id) + if err != nil { + return nil, err + } + image.cache = self + return image, nil +} + +func (self *SStoragecache) GetPath() string { + return self.Path +} + +func (self *SStoragecache) CreateIImage(snapshotId, name, osType, desc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, opts *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + id, err := self.region.UploadImage(ctx, userCred, opts, callback) + if err != nil { + return "", errors.Wrapf(err, "UploadImage") + } + image, err := self.GetIImageById(id) + if err != nil { + return "", errors.Wrapf(err, "GetIImageById(%s)", id) + } + err = cloudprovider.WaitStatus(image, cloudprovider.IMAGE_STATUS_ACTIVE, time.Second*5, time.Minute*10) + if err != nil { + return "", errors.Wrapf(err, "WaitStatus") + } + if callback != nil { + callback(100) + } + return id, nil +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + caches, err := self.GetStoragecaches() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStoragecache{} + for i := range caches { + caches[i].region = self + ret = append(ret, &caches[i]) + } + return ret, nil +} + +func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + cache, err := self.GetStoragecache(id) + if err != nil { + return nil, err + } + return cache, nil +} + +func (self *SRegion) GetStoragecaches() ([]SStoragecache, error) { + caches := []SStoragecache{} + return caches, self.list(&compute.Storagecaches, nil, &caches) +} + +func (self *SRegion) GetStoragecache(id string) (*SStoragecache, error) { + cache := &SStoragecache{region: self} + return cache, self.cli.get(&compute.Storagecaches, id, nil, cache) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/tag_base.go new file mode 100644 index 0000000000..b67e8d7632 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/tag_base.go @@ -0,0 +1,46 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type CloudpodsTags struct { + Metadata map[string]string +} + +func (self *CloudpodsTags) GetTags() (map[string]string, error) { + metadatas := map[string]string{} + for k, v := range self.Metadata { + if strings.HasPrefix(k, apis.USER_TAG_PREFIX) { + metadatas[strings.TrimPrefix(k, apis.USER_TAG_PREFIX)] = v + } + } + return metadatas, nil +} + +func (self *CloudpodsTags) GetSysTags() map[string]string { + return nil +} + +func (self *CloudpodsTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/vpc.go new file mode 100644 index 0000000000..a8ade004b8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/vpc.go @@ -0,0 +1,152 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + CloudpodsTags + region *SRegion + + api.VpcDetails +} + +func (self *SVpc) GetName() string { + return self.Name +} + +func (self *SVpc) GetId() string { + return self.Id +} + +func (self *SVpc) GetGlobalId() string { + return self.Id +} + +func (self *SVpc) GetStatus() string { + return self.Status +} + +func (self *SVpc) Refresh() error { + vpc, err := self.region.GetVpc(self.Id) + if err != nil { + return errors.Wrapf(err, "GetVpc(%s)", self.Id) + } + return jsonutils.Update(self, vpc) +} + +func (self *SVpc) GetCidrBlock() string { + return self.CidrBlock +} + +func (self *SVpc) GetIRouteTableById(id string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SVpc) GetIsDefault() bool { + return self.IsDefault +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetExternalAccessMode() string { + return self.ExternalAccessMode +} + +func (self *SVpc) Delete() error { + return self.region.cli.delete(&modules.Vpcs, self.Id) +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + vpcs, err := self.GetVpcs() + if err != nil { + return nil, errors.Wrapf(err, "GetVpcs") + } + ret := []cloudprovider.ICloudVpc{} + for i := range vpcs { + vpcs[i].region = self + ret = append(ret, &vpcs[i]) + } + return ret, nil +} + +func (self *SVpc) CreateIWire(opts *cloudprovider.SWireCreateOptions) (cloudprovider.ICloudWire, error) { + wire, err := self.region.CreateWire(opts, self.Id, self.DomainId, self.PublicScope, self.IsPublic) + if err != nil { + return nil, err + } + wire.vpc = self + return wire, nil +} + +func (self *SRegion) CreateWire(opts *cloudprovider.SWireCreateOptions, vpcId, domainId, publicScope string, isPublic bool) (*SWire, error) { + input := api.WireCreateInput{} + input.GenerateName = opts.Name + input.Mtu = opts.Mtu + input.Bandwidth = opts.Bandwidth + input.VpcId = vpcId + input.DomainId = domainId + input.PublicScope = publicScope + input.IsPublic = &isPublic + input.ZoneId = opts.ZoneId + t := true + input.IsEmulated = &t + wire := &SWire{} + return wire, self.create(&modules.Wires, input, wire) +} + +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + input := api.VpcCreateInput{} + input.Name = opts.NAME + input.Description = opts.Desc + input.CidrBlock = opts.CIDR + input.CloudregionId = self.Id + vpc := &SVpc{region: self} + return vpc, self.create(&modules.Vpcs, input, vpc) +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + vpc, err := self.GetVpc(id) + if err != nil { + return nil, errors.Wrapf(err, "GetVpc(%s)", id) + } + return vpc, nil +} + +func (self *SRegion) GetVpcs() ([]SVpc, error) { + vpcs := []SVpc{} + return vpcs, self.list(&modules.Vpcs, nil, &vpcs) +} + +func (self *SRegion) GetVpc(id string) (*SVpc, error) { + vpc := &SVpc{region: self} + return vpc, self.cli.get(&modules.Vpcs, id, nil, vpc) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/wire.go new file mode 100644 index 0000000000..e3a42d2500 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/wire.go @@ -0,0 +1,121 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + CloudpodsTags + multicloud.SResourceBase + + vpc *SVpc + + api.WireDetails +} + +func (self *SWire) GetId() string { + return self.Id +} + +func (self *SWire) GetGlobalId() string { + return self.Id +} + +func (self *SWire) GetName() string { + return self.Name +} + +func (self *SWire) GetStatus() string { + return self.Status +} + +func (self *SWire) GetBandwidth() int { + return self.Bandwidth +} + +func (self *SWire) IsEmulated() bool { + return self.SWire.IsEmulated +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + if len(self.ZoneId) == 0 { + return nil + } + zone, err := self.vpc.region.GetZone(self.ZoneId) + if err != nil { + return nil + } + return zone +} + +func (self *SWire) Refresh() error { + wire, err := self.vpc.region.GetWire(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, wire) +} + +func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { + wire, err := self.region.GetWire(id) + if err != nil { + return nil, errors.Wrapf(err, "GetWire(%s)", id) + } + wire.vpc = self + return wire, nil +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + wires, err := self.region.GetWires(self.Id, "") + if err != nil { + return nil, errors.Wrapf(err, "GetWires") + } + ret := []cloudprovider.ICloudWire{} + for i := range wires { + wires[i].vpc = self + ret = append(ret, &wires[i]) + } + return ret, nil +} + +func (self *SRegion) GetWires(vpcId, hostId string) ([]SWire, error) { + wires := []SWire{} + params := map[string]interface{}{"cloud_env": ""} + if len(vpcId) > 0 { + params["vpc_id"] = vpcId + } + if len(hostId) > 0 { + params["host_id"] = hostId + } + return wires, self.list(&modules.Wires, params, &wires) +} + +func (self *SRegion) GetWire(id string) (*SWire, error) { + wire := &SWire{} + return wire, self.cli.get(&modules.Wires, id, nil, wire) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/zone.go new file mode 100644 index 0000000000..6fbe431314 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/cloudpods/zone.go @@ -0,0 +1,90 @@ +// Copyright 2019 Yunion +// +// 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 cloudpods + +import ( + "yunion.io/x/pkg/errors" + + api "yunion.io/x/onecloud/pkg/apis/compute" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SZone struct { + multicloud.SResourceBase + CloudpodsTags + region *SRegion + + api.ZoneDetails +} + +func (self *SZone) GetId() string { + return self.Id +} + +func (self *SZone) GetGlobalId() string { + return self.Id +} + +func (self *SZone) GetName() string { + return self.Name +} + +func (self *SZone) GetStatus() string { + return self.Status +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) + return table +} + +func (self *SRegion) GetZones() ([]SZone, error) { + zones := []SZone{} + return zones, self.list(&modules.Zones, nil, &zones) +} + +func (self *SRegion) GetZone(id string) (*SZone, error) { + zone := &SZone{region: self} + return zone, self.cli.get(&modules.Zones, id, nil, &zone) +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + zone, err := self.GetZone(id) + if err != nil { + return nil, err + } + return zone, nil +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + zones, err := self.GetZones() + if err != nil { + return nil, errors.Wrapf(err, "GetZones") + } + ret := []cloudprovider.ICloudZone{} + for i := range zones { + zones[i].region = self + ret = append(ret, &zones[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/clouduser.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/clouduser.go new file mode 100644 index 0000000000..2dc0fdae9c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/clouduser.go @@ -0,0 +1,36 @@ +// Copyright 2019 Yunion +// +// 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 multicloud + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SBaseClouduser struct { +} + +func (self *SBaseClouduser) CreateAccessKey(name string) (*cloudprovider.SAccessKey, error) { + return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "base CreateAccessKey") +} + +func (self *SBaseClouduser) GetAccessKeys() ([]cloudprovider.SAccessKey, error) { + return nil, errors.Wrap(cloudprovider.ErrNotImplemented, "base GetAccessKeys") +} + +func (self *SBaseClouduser) DeleteAccessKey(accesskey string) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "base DeleteAccessKey") +} diff --git a/pkg/multicloud/ctyun/crm.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/crm.go similarity index 100% rename from pkg/multicloud/ctyun/crm.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/crm.go diff --git a/pkg/multicloud/ctyun/ctyun.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/ctyun.go similarity index 99% rename from pkg/multicloud/ctyun/ctyun.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/ctyun.go index 2b7142f05e..4c583379ee 100644 --- a/pkg/multicloud/ctyun/ctyun.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/ctyun.go @@ -31,8 +31,8 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/disk.go new file mode 100644 index 0000000000..698c84c176 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/disk.go @@ -0,0 +1,599 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "context" + "fmt" + "strconv" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// http://ctyun-api-url/apiproxy/v3/ondemand/queryVolumes +type SDisk struct { + storage *SStorage + multicloud.SDisk + CtyunTags + multicloud.SBillingBase + + diskDetails *DiskDetails + + ID string `json:"id"` + Status string `json:"status"` + Name string `json:"name"` + CreatedAt int64 `json:"created_at"` + UpdatedAt string `json:"updated_at"` + Multiattach bool `json:"multiattach"` + ReplicationStatus string `json:"replication_status"` + SizeGB int64 `json:"size"` + Metadata Metadata `json:"metadata"` + VolumeType string `json:"volume_type"` + UserID string `json:"user_id"` + Shareable bool `json:"shareable"` + Encrypted bool `json:"encrypted"` + Bootable string `json:"bootable"` + AvailabilityZone string `json:"availability_zone"` + Attachments []Attachment `json:"attachments"` + MasterOrderID string `json:"masterOrderId"` + WorkOrderResourceID string `json:"workOrderResourceId"` + ExpireTime int64 `json:"expireTime"` + IsFreeze int64 `json:"isFreeze"` +} + +type Attachment struct { + VolumeID string `json:"volume_id"` + AttachmentID string `json:"attachment_id"` + AttachedAt string `json:"attached_at"` + ServerID string `json:"server_id"` + Device string `json:"device"` + ID string `json:"id"` +} + +type Metadata struct { + OrderID string `json:"orderID"` + AttachedMode string `json:"attached_mode"` + ResourceSpecCode string `json:"resourceSpecCode"` + ProductID string `json:"productID"` + Readonly string `json:"readonly"` +} + +type DiskDetails struct { + ID string `json:"id"` + ResEbsID string `json:"resEbsId"` + Size int64 `json:"size"` + Name string `json:"name"` + RegionID string `json:"regionId"` + AccountID string `json:"accountId"` + UserID string `json:"userId"` + HostID string `json:"hostId"` + OrderID string `json:"orderId"` + Status int64 `json:"status"` + Type string `json:"type"` + VolumeStatus int64 `json:"volumeStatus"` + CreateDate int64 `json:"createDate"` + DueDate int64 `json:"dueDate"` + ZoneID string `json:"zoneId"` + ZoneName string `json:"zoneName"` + IsSysVolume int64 `json:"isSysVolume"` + IsPackaged int64 `json:"isPackaged"` + WorkOrderResourceID string `json:"workOrderResourceId"` + IsFreeze int64 `json:"isFreeze"` +} + +func (self *SDisk) GetBillingType() string { + if self.ExpireTime > 0 { + return billing_api.BILLING_TYPE_PREPAID + } + + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SDisk) GetCreatedAt() time.Time { + return time.Unix(self.CreatedAt/1000, 0) +} + +func (self *SDisk) GetExpiredAt() time.Time { + if self.ExpireTime == 0 { + return time.Time{} + } + + return time.Unix(self.ExpireTime/1000, 0) +} + +func (self *SDisk) GetId() string { + return self.ID +} + +func (self *SDisk) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + + return self.ID +} + +func (self *SDisk) GetGlobalId() string { + return self.GetId() +} + +func (self *SDisk) GetStatus() string { + switch self.Status { + case "creating", "downloading": + return api.DISK_ALLOCATING + case "available", "in-use": + return api.DISK_READY + case "error": + return api.DISK_ALLOC_FAILED + case "attaching": + return api.DISK_ATTACHING + case "detaching": + return api.DISK_DETACHING + case "restoring-backup": + return api.DISK_REBUILD + case "backing-up": + return api.DISK_BACKUP_STARTALLOC + case "error_restoring": + return api.DISK_BACKUP_ALLOC_FAILED + case "uploading": + return api.DISK_SAVING + case "extending": + return api.DISK_RESIZING + case "error_extending": + return api.DISK_ALLOC_FAILED + case "deleting": + return api.DISK_DEALLOC + case "error_deleting": + return api.DISK_DEALLOC_FAILED + case "rollbacking": + return api.DISK_REBUILD + case "error_rollbacking": + return api.DISK_UNKNOWN + default: + return api.DISK_UNKNOWN + } +} + +func (self *SDisk) Refresh() error { + new, err := self.storage.zone.region.GetDisk(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SDisk) IsEmulated() bool { + return false +} + +func (self *SDisk) GetSysTags() map[string]string { + data := map[string]string{} + data["hypervisor"] = api.HYPERVISOR_CTYUN + return data +} + +func (self *SDisk) GetProjectId() string { + return "" +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +func (self *SDisk) GetIStorageId() string { + return self.storage.GetId() +} + +func (self *SDisk) GetDiskFormat() string { + return "vhd" +} + +func (self *SDisk) GetDiskSizeMB() int { + return int(self.SizeGB * 1024) +} + +func (self *SDisk) GetIsAutoDelete() bool { + if len(self.Attachments) == 0 { + return false + } + + if self.Bootable == "true" { + return true + } + + return false +} + +func (self *SDisk) GetTemplateId() string { + if len(self.Attachments) > 0 && len(self.Attachments[0].ServerID) > 0 { + server, err := self.storage.zone.region.GetVMById(self.Attachments[0].ServerID) + if err != nil { + log.Errorf("SDisk.GetTemplateId %s", err) + return "" + } + + image, err := server.GetImage() + if err != nil { + log.Errorf("SDisk.GetImage %s", err) + return "" + } + + return image.GetId() + } + + return "" +} + +func (self *SDisk) GetDiskType() string { + if self.Bootable == "true" { + return api.DISK_TYPE_SYS + } else { + return api.DISK_TYPE_DATA + } +} + +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 { + if len(self.Attachments) > 0 { + return self.Attachments[0].Device + } + + return "" +} + +func (self *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) Delete(ctx context.Context) error { + _, err := self.storage.zone.region.DeleteDisk(self.GetId()) + if err != nil { + return errors.Wrap(err, "SDisk.Delete") + } + + return nil +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +// POST http://ctyun-api-url/apiproxy/v3/ondemand/createVBS +func (self *SDisk) GetISnapshot(idStr string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotFound +} + +// no snapshot api opened +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + return []cloudprovider.ICloudSnapshot{}, nil +} + +// POST http://ctyun-api-url/apiproxy/v3/ondemand/updateDiskBackupPolicy +func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { + return []string{}, nil +} + +func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { + jobId, err := self.storage.zone.region.ResizeDisk(self.GetId(), strconv.Itoa(int(newSizeMB/1024))) + if err != nil { + return errors.Wrap(err, "Disk.Resize") + } + + err = cloudprovider.Wait(10*time.Second, 1800*time.Second, func() (b bool, err error) { + statusJson, err := self.storage.zone.region.GetVolumeJob(jobId) + // ctyun 偶尔会报客户端错误,其实job已经到后台执行了 + if err != nil { + log.Debugf("Ctyun.SDisk.Resize.GetVolumeJob %s", err) + return false, nil + } + + if status, _ := statusJson.GetString("status"); status == "SUCCESS" { + return true, nil + } else if status == "FAILED" { + return false, fmt.Errorf("Resize job %s failed", jobId) + } else { + return false, nil + } + }) + if err != nil { + return errors.Wrap(err, "Disk.Resize.Wait") + } + + return nil +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDisk) GetDiskDetails() (*DiskDetails, error) { + if self.diskDetails != nil { + return self.diskDetails, nil + } + + details, err := self.storage.zone.region.GetDiskDetailByDiskId(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "SDisk.GetDiskDetails.GetDiskDetailByDiskId") + } + + self.diskDetails = details + return self.diskDetails, nil +} + +func (self *SRegion) GetDisks() ([]SDisk, error) { + params := map[string]string{ + "regionId": self.GetId(), + } + + resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVolumes", params) + if err != nil { + return nil, errors.Wrap(err, "Region.GetDisks.DoGet") + } + + disks := make([]SDisk, 0) + err = resp.Unmarshal(&disks, "returnObj", "volumes") + if err != nil { + return nil, errors.Wrap(err, "Region.GetDisks.Unmarshal") + } + + for i := range disks { + izone, err := self.GetIZoneById(getZoneGlobalId(self, disks[i].AvailabilityZone)) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetDisk.GetIZoneById") + } + + disks[i].storage = &SStorage{ + zone: izone.(*SZone), + storageType: disks[i].VolumeType, + } + } + + return disks, nil +} + +func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { + params := map[string]string{ + "regionId": self.GetId(), + "volumeId": diskId, + } + + resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVolumes", params) + if err != nil { + return nil, errors.Wrap(err, "Region.GetDisk.DoGet") + } + + disks := make([]SDisk, 0) + err = resp.Unmarshal(&disks, "returnObj", "volumes") + if err != nil { + return nil, errors.Wrap(err, "Region.GetDisks.Unmarshal") + } + + if len(disks) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetDisk") + } else if len(disks) == 1 { + izone, err := self.GetIZoneById(getZoneGlobalId(self, disks[0].AvailabilityZone)) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetDisk.GetIZoneById") + } + + disks[0].storage = &SStorage{ + zone: izone.(*SZone), + storageType: disks[0].VolumeType, + } + + return &disks[0], nil + } else { + return nil, errors.Wrap(cloudprovider.ErrDuplicateId, "SRegion.GetDisk") + } +} + +func (self *SRegion) GetDiskDetailByDiskId(diskId string) (*DiskDetails, error) { + params := map[string]string{ + "volumeId": diskId, + "regionId": self.GetId(), + } + + resp, err := self.client.DoGet("/apiproxy/v3/queryDataDiskDetail", params) + if err != nil { + return nil, errors.Wrap(err, "Region.GetDiskDetailByDiskId.DoGet") + } + + disk := &DiskDetails{} + err = resp.Unmarshal(disk, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "Region.GetDiskDetailByDiskId.Unmarshal") + } + + return disk, nil +} + +func (self *SRegion) CreateDisk(zoneId, name, diskType, size string) (*SDisk, error) { + diskParams := jsonutils.NewDict() + diskParams.Set("regionId", jsonutils.NewString(self.GetId())) + diskParams.Set("zoneId", jsonutils.NewString(zoneId)) + diskParams.Set("name", jsonutils.NewString(name)) + diskParams.Set("type", jsonutils.NewString(diskType)) + diskParams.Set("size", jsonutils.NewString(size)) + diskParams.Set("count", jsonutils.NewString("1")) + + params := map[string]jsonutils.JSONObject{ + "createVolumeInfo": diskParams, + } + + disks, err := self.GetDisks() + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateDisk.GetDisks") + } + + diskIds := []string{} + for i := range disks { + diskIds = append(diskIds, disks[i].GetId()) + } + + _, err = self.client.DoPost("/apiproxy/v3/ondemand/createVolume", params) + if err != nil { + return nil, errors.Wrap(err, "Region.CreateDisk.DoPost") + } + + // 查询job结果一直报错,目前先用替代办法查找新硬盘ID,可能不准确。后续需要替换其它方法 + diskId := "" + cloudprovider.Wait(3*time.Second, 300*time.Second, func() (b bool, err error) { + disks, err := self.GetDisks() + if err != nil { + return false, err + } + + for i := range disks { + if !utils.IsInStringArray(disks[i].GetId(), diskIds) { + diskId = disks[i].GetId() + return true, nil + } + } + + return false, nil + }) + + return self.GetDisk(diskId) +} + +func (self *SRegion) CreateDiskBackup(name, volumeId, desc string) (string, error) { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "volumeId": jsonutils.NewString(volumeId), + "name": jsonutils.NewString(name), + "description": jsonutils.NewString(desc), + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/createVBS", params) + if err != nil { + return "", errors.Wrap(err, "Region.CreateDiskBackup.DoPost") + } + + var jobId string + err = resp.Unmarshal(&jobId, "returnObj", "data") + if err != nil { + return "", errors.Wrap(err, "Region.CreateDiskBackup.Unmarshal") + } + + return jobId, nil +} + +func (self *SRegion) DeleteDisk(volumeId string) (string, error) { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "volumeId": jsonutils.NewString(volumeId), + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/deleteVolume", params) + if err != nil { + msg, _ := resp.GetString("message") + return "", errors.Wrap(fmt.Errorf(msg), "SRegion.DeleteDisk.DoPost") + } + + var jobId string + err = resp.Unmarshal(&jobId, "returnObj", "data") + if err != nil { + return "", errors.Wrap(err, "SRegion.DeleteDisk.Unmarshal") + } + + return jobId, nil +} + +func (self *SRegion) ResizeDisk(volumeId string, newSizeGB string) (string, error) { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "volumeId": jsonutils.NewString(volumeId), + "newSize": jsonutils.NewString(newSizeGB), + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/expandVolumeSize", params) + if err != nil { + return "", errors.Wrap(err, "SRegion.ResizeDisk.DoPost") + } + + var ok bool + err = resp.Unmarshal(&ok, "returnObj", "status") + if !ok { + msg, _ := resp.GetString("message") + return "", errors.Wrap(fmt.Errorf(msg), "SRegion.ResizeDisk.JobFailed") + } + + var jobId string + err = resp.Unmarshal(&jobId, "returnObj", "data") + if err != nil { + return "", errors.Wrap(err, "SRegion.ResizeDisk.Unmarshal") + } + + return jobId, nil +} + +func (self *SRegion) RestoreDisk(volumeId, backupId string) (string, error) { + diskBackupParams := jsonutils.NewDict() + diskBackupParams.Set("regionId", jsonutils.NewString(self.GetId())) + diskBackupParams.Set("backupId", jsonutils.NewString(backupId)) + diskBackupParams.Set("volumeId", jsonutils.NewString(volumeId)) + + params := map[string]jsonutils.JSONObject{ + "diskBackup": diskBackupParams, + } + + resp, err := self.client.DoPost("/apiproxy/v3/restoreDiskBackup", params) + if err != nil { + return "", errors.Wrap(err, "SRegion.RestoreDisk.DoPost") + } + + var ok bool + err = resp.Unmarshal(&ok, "returnObj", "status") + if !ok { + msg, _ := resp.GetString("message") + return "", errors.Wrap(fmt.Errorf(msg), "SRegion.RestoreDisk.JobFailed") + } + + var jobId string + err = resp.Unmarshal(&jobId, "returnObj", "data") + if err != nil { + return "", errors.Wrap(err, "SRegion.RestoreDisk.Unmarshal") + } + + return jobId, nil +} diff --git a/pkg/multicloud/ctyun/diskbackup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/diskbackup.go similarity index 97% rename from pkg/multicloud/ctyun/diskbackup.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/diskbackup.go index a7978d5fb1..a3bd1be630 100644 --- a/pkg/multicloud/ctyun/diskbackup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/diskbackup.go @@ -21,13 +21,13 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SDiskBackup struct { multicloud.SResourceBase - multicloud.CtyunTags + CtyunTags region *SRegion Status string `json:"status"` diff --git a/pkg/multicloud/ctyun/diskbackup_policy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/diskbackup_policy.go similarity index 97% rename from pkg/multicloud/ctyun/diskbackup_policy.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/diskbackup_policy.go index e42af20bb5..dc2df602f1 100644 --- a/pkg/multicloud/ctyun/diskbackup_policy.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/diskbackup_policy.go @@ -20,14 +20,14 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SDiskBacupPolicy struct { multicloud.SResourceBase - multicloud.CtyunTags + CtyunTags region *SRegion PolicyResourceCount int64 `json:"policy_resource_count"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/doc.go new file mode 100644 index 0000000000..8c8fa608c1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 ctyun // import "yunion.io/x/cloudmux/pkg/multicloud/ctyun" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/eip.go new file mode 100644 index 0000000000..6723bde3ab --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/eip.go @@ -0,0 +1,398 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SEip struct { + region *SRegion + multicloud.SEipBase + CtyunTags + + IPVersion int64 `json:"ip_version"` + BandwidthShareType string `json:"bandwidth_share_type"` + Type string `json:"type"` + PrivateIPAddress string `json:"private_ip_address"` + EnterpriseProjectID string `json:"enterprise_project_id"` + Status string `json:"status"` + PublicIPAddress string `json:"public_ip_address"` + ID string `json:"id"` + TenantID string `json:"tenant_id"` + Profile Profile `json:"profile"` + BandwidthName string `json:"bandwidth_name"` + BandwidthID string `json:"bandwidth_id"` + PortID string `json:"port_id"` + BandwidthSize int `json:"bandwidth_size"` + CreateTime int64 `json:"create_time"` + MasterOrderID string `json:"masterOrderId"` + WorkOrderResourceID string `json:"workOrderResourceId"` + ExpireTime int64 `json:"expireTime"` + IsFreeze int64 `json:"isFreeze"` +} + +func (self *SEip) GetBillingType() string { + if len(self.MasterOrderID) > 0 { + return billing_api.BILLING_TYPE_PREPAID + } else { + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SEip) GetCreatedAt() time.Time { + return time.Unix(self.CreateTime/1000, 0) +} + +func (self *SEip) GetExpiredAt() time.Time { + if self.ExpireTime == 0 { + return time.Time{} + } + + return time.Unix(self.ExpireTime/1000, 0) +} + +func (self *SEip) GetId() string { + return self.ID +} + +func (self *SEip) GetName() string { + return self.BandwidthName +} + +func (self *SEip) GetGlobalId() string { + return self.GetId() +} + +func (self *SEip) GetStatus() string { + switch self.Status { + case "ACTIVE", "DOWN": + return api.EIP_STATUS_READY + case "ERROR": + return api.EIP_STATUS_ALLOCATE_FAIL + default: + return api.EIP_STATUS_UNKNOWN + } +} + +func (self *SEip) Refresh() error { + if self.IsEmulated() { + return nil + } + new, err := self.region.GetEip(self.ID) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SEip) IsEmulated() bool { + return false +} + +func (self *SEip) GetProjectId() string { + return "" +} + +func (self *SEip) GetIpAddr() string { + return self.PublicIPAddress +} + +func (self *SEip) GetMode() string { + return api.EIP_MODE_STANDALONE_EIP +} + +func (self *SEip) GetINetworkId() string { + return "" +} + +func (self *SEip) GetAssociationType() string { + orders, err := self.region.GetOrder(self.WorkOrderResourceID) + if err != nil { + // bugfix: 由于没有接口可以返向查询出关联的device,这里默认关联的是server? + if len(self.PortID) > 0 || len(self.PrivateIPAddress) > 0 { + return api.EIP_ASSOCIATE_TYPE_SERVER + } + + log.Errorf("SEip.GetAssociationType %s", err) + return "" + } + + for i := range orders { + order := orders[i] + if strings.Contains(order.ResourceType, "LOADBALANCER") { + return api.EIP_ASSOCIATE_TYPE_LOADBALANCER + } else { + return api.EIP_ASSOCIATE_TYPE_SERVER + } + } + + return "" +} + +// eip查询接口未返回 绑定的实例ID/网卡port id。导致不能正常找出关联的主机 +func (self *SEip) GetAssociationExternalId() string { + vms, err := self.region.GetVMs() + if err != nil { + log.Errorf("SEip.GetAssociationExternalId.GetVMs %s", err) + return "" + } + + for i := range vms { + vm := vms[i] + nics, err := self.region.GetNics(vm.GetId()) + if err != nil { + log.Errorf("SEip.GetAssociationExternalId.GetNics %s", err) + return "" + } + + for _, nic := range nics { + if nic.PortID == self.PortID { + return vm.GetGlobalId() + } + } + } + + return "" +} + +// http://ctyun-api-url/apiproxy/v3/queryNetworkDetail +func (self *SEip) GetBandwidth() int { + return self.BandwidthSize +} + +func (self *SEip) GetInternetChargeType() string { + // todo: fix me + return "" +} + +func (self *SEip) Delete() error { + return self.region.DeleteEip(self.GetId()) +} + +func (self *SEip) Associate(conf *cloudprovider.AssociateConfig) error { + nics, err := self.region.GetNics(conf.InstanceId) + if err != nil { + return errors.Wrap(err, "Eip.Associate.GetNics") + } + + if len(nics) == 0 { + return errors.Wrap(fmt.Errorf("no network card found"), "Eip.Associate.GetINics") + } + + return self.region.AssociateEip(self.GetId(), nics[0].PortID) +} + +func (self *SEip) Dissociate() error { + err := self.region.DissociateEip(self.GetId()) + if err != nil { + return err + } + + err = cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 5*time.Second, 10*time.Second, 180*time.Second) + return errors.Wrap(err, "SEip.Dissociate") +} + +func (self *SEip) ChangeBandwidth(bw int) error { + return self.region.ChangeBandwidthEip(self.GetName(), self.GetId(), strconv.Itoa(bw)) +} + +type Profile struct { + OrderID string `json:"order_id"` + RegionID string `json:"region_id"` + UserID string `json:"user_id"` + ProductID string `json:"product_id"` +} + +func (self *SRegion) GetEips() ([]SEip, error) { + params := map[string]string{ + "regionId": self.GetId(), + } + + eips := make([]SEip, 0) + resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryIps", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetEips.DoGet") + } + + err = resp.Unmarshal(&eips, "returnObj", "publicips") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetEips.Unmarshal") + } + + for i := range eips { + eips[i].region = self + } + + return eips, nil +} + +func (self *SRegion) GetEip(eipId string) (*SEip, error) { + params := map[string]string{ + "regionId": self.GetId(), + "publicIpId": eipId, + } + + eips := make([]SEip, 0) + resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryIps", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetEip.DoGet") + } + + err = resp.Unmarshal(&eips, "returnObj", "publicips") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetEip.Unmarshal") + } + + if len(eips) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetEip") + } else if len(eips) == 1 { + eips[0].region = self + return &eips[0], nil + } else { + return nil, errors.Wrap(cloudprovider.ErrDuplicateId, "SRegion.GetEip") + } +} + +func (self *SRegion) CreateEip(zoneId, name, size, shareType, chargeType string) (*SEip, error) { + eipParams := jsonutils.NewDict() + eipParams.Set("regionId", jsonutils.NewString(self.GetId())) + eipParams.Set("zoneId", jsonutils.NewString(zoneId)) + eipParams.Set("name", jsonutils.NewString(name)) + eipParams.Set("type", jsonutils.NewString("5_telcom")) + eipParams.Set("size", jsonutils.NewString(size)) + eipParams.Set("shareType", jsonutils.NewString(shareType)) + eipParams.Set("chargeMode", jsonutils.NewString(chargeType)) + + params := map[string]jsonutils.JSONObject{ + "createIpInfo": eipParams, + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/createIp", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateEip.DoPost") + } + + eipId, err := resp.GetString("returnObj", "id") + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateEip.GetEipId") + } + + return self.GetEip(eipId) +} + +func (self *SRegion) DeleteEip(publicIpId string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "publicIpId": jsonutils.NewString(publicIpId), + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/deleteIp", params) + if err != nil { + return errors.Wrap(err, "SRegion.DeleteEip.DoPost") + } + + var ok bool + err = resp.Unmarshal(&ok, "returnObj") + if !ok { + msg, _ := resp.GetString("message") + return errors.Wrap(fmt.Errorf(msg), "SRegion.DeleteEip.JobFailed") + } + + return nil +} + +// 这里networkCardId 实际指的是port id +func (self *SRegion) AssociateEip(publicIpId, networkCardId string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "publicIpId": jsonutils.NewString(publicIpId), + "networkCardId": jsonutils.NewString(networkCardId), + } + + _, err := self.client.DoPost("/apiproxy/v3/ondemand/bindIp", params) + if err != nil { + return errors.Wrap(err, "SRegion.AssociateEip.DoPost") + } + + return nil +} + +func (self *SRegion) DissociateEip(publicIpId string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "publicIpId": jsonutils.NewString(publicIpId), + } + + _, err := self.client.DoPost("/apiproxy/v3/ondemand/unbindIp", params) + if err != nil { + return errors.Wrap(err, "SRegion.DissociateEip.DoPost") + } + + return nil +} + +type SBandwidth struct { + PublicipInfo []PublicipInfo `json:"publicip_info"` + EnterpriseProjectID string `json:"enterprise_project_id"` + Name string `json:"name"` + ID string `json:"id"` + ShareType string `json:"share_type"` + Size int64 `json:"size"` + TenantID string `json:"tenant_id"` + ChargeMode string `json:"charge_mode"` + BandwidthType string `json:"bandwidth_type"` +} + +type PublicipInfo struct { + PublicipType string `json:"publicip_type"` + PublicipAddress string `json:"publicip_address"` + IPVersion int64 `json:"ip_version"` + PublicipID string `json:"publicip_id"` +} + +func (self *SRegion) ChangeBandwidthEip(name, publicIpId, sizeMb string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "publicIpId": jsonutils.NewString(publicIpId), + "name": jsonutils.NewString(name), + "size": jsonutils.NewString(sizeMb), + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/upgradeNetwork", params) + if err != nil { + return errors.Wrap(err, "SRegion.ChangeBandwidthEip.DoPost") + } + + bandwidth := SBandwidth{} + err = resp.Unmarshal(&bandwidth, "returnObj") + if err != nil { + return errors.Wrap(err, "SRegion.ChangeBandwidthEip.Unmarshal") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/host.go new file mode 100644 index 0000000000..19af38e242 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/host.go @@ -0,0 +1,288 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone + + projectId string +} + +func (self *SHost) GetId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) +} + +func (self *SHost) GetGlobalId() string { + return self.GetId() +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) Refresh() error { + return nil +} + +func (self *SHost) IsEmulated() bool { + return true +} + +// http://ctyun-api-url/apiproxy/v3/ondemand/queryVMs +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms, err := self.zone.region.GetVMs() + if err != nil { + return nil, errors.Wrap(err, "SHost.GetVMs") + } + + ivms := make([]cloudprovider.ICloudVM, len(vms)) + for i := range vms { + ivms[i] = &vms[i] + } + + return ivms, nil +} + +// http://ctyun-api-url/apiproxy/v3/ondemand/queryVMDetail +// http://ctyun-api-url/apiproxy/v3/queryVMDetail +func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + return self.zone.region.GetIVMById(id) +} + +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 api.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(api.CLOUD_PROVIDER_CTYUN), "manufacture") + return info +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetCpuCount() int { + 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 api.DISK_TYPE_HYBRID +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_CTYUN +} + +func (self *SHost) GetIsMaintenance() bool { + return false +} + +func (self *SHost) GetVersion() string { + return CTYUN_API_VERSION +} + +func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + network, err := self.zone.region.GetNetwork(desc.ExternalNetworkId) + if err != nil { + return nil, errors.Wrap(err, "Host.CreateVM.GetNetwork") + } + + // 镜像及硬盘配置 + img, err := self.zone.region.GetImage(desc.ExternalImageId) + if err != nil { + return nil, errors.Wrap(err, "SHost.CreateVM.GetImage") + } + + rootDiskSize := int(img.MinDisk) + if desc.SysDisk.SizeGB > rootDiskSize { + rootDiskSize = desc.SysDisk.SizeGB + } + + jobId, err := self.zone.region.CreateInstance(self.zone.GetId(), desc.Name, desc.ExternalImageId, desc.OsType, desc.InstanceType, network.VpcID, desc.ExternalNetworkId, desc.ExternalSecgroupId, desc.Password, desc.SysDisk.StorageType, rootDiskSize, desc.DataDisks) + if err != nil { + return nil, errors.Wrap(err, "Host.CreateVM.CreateInstance") + } + + vmId := "" + err = cloudprovider.Wait(10*time.Second, 600*time.Second, func() (b bool, err error) { + statusJson, err := self.zone.region.GetJob(jobId) + if err != nil { + if strings.Contains(err.Error(), "job fail") { + return false, err + } + + return false, nil + } + + if status, _ := statusJson.GetString("status"); status == "SUCCESS" { + jobs, err := statusJson.GetArray("entities", "sub_jobs") + if err != nil { + return false, err + } + + if len(jobs) > 0 { + vmId, err = jobs[0].GetString("entities", "server_id") + if err != nil { + return false, err + } + } else { + return false, fmt.Errorf("CreateVM empty sub jobs") + } + return true, nil + } else if status == "FAILED" { + return false, fmt.Errorf("CreateVM job %s failed", jobId) + } else { + return false, nil + } + }) + if err != nil { + return nil, errors.Wrap(err, "SHost.CreateVM.Wait") + } + + return self.zone.region.GetVMById(vmId) +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) getVMs(vmId string) ([]SInstance, error) { + params := map[string]string{ + "regionId": self.GetId(), + } + + if len(vmId) > 0 { + params["vmId"] = vmId + } + + resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVMs", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.getVMs.DoGet") + } + + ret := make([]SInstance, 0) + err = resp.Unmarshal(&ret, "returnObj", "servers") + if err != nil { + return nil, errors.Wrap(err, "SRegion.getVMs.Unmarshal") + } + + for i := range ret { + izone, err := self.GetIZoneById(getZoneGlobalId(self, ret[i].OSEXTAZAvailabilityZone)) + if err != nil { + return nil, errors.Wrap(err, "SRegion.getVMs.GetIZoneById") + } + + ret[i].host = &SHost{ + zone: izone.(*SZone), + } + } + + return ret, nil +} + +func (self *SRegion) GetVMs() ([]SInstance, error) { + return self.getVMs("") +} + +func (self *SRegion) GetVMById(vmId string) (*SInstance, error) { + if len(vmId) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetVMById.EmptyVmID") + } + + vms, err := self.getVMs(vmId) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetVMById") + } + + if len(vms) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetVMById") + } else if len(vms) == 1 { + izone, err := self.GetIZoneById(getZoneGlobalId(self, vms[0].OSEXTAZAvailabilityZone)) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetVMById.GetIZoneById") + } + + vms[0].host = &SHost{ + zone: izone.(*SZone), + } + return &vms[0], nil + } else { + return nil, errors.Wrap(cloudprovider.ErrDuplicateId, "SRegion.GetVMById") + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/image.go new file mode 100644 index 0000000000..7fd99a9ddd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/image.go @@ -0,0 +1,214 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "context" + "strconv" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +const ( + ImageOwnerPublic string = "gold" // 公共镜像:gold + ImageOwnerSelf string = "private" // 私有镜像:private + ImageOwnerShared string = "shared" // 共享镜像:shared +) + +// http://ctyun-api-url/apiproxy/v3/order/getImages +type SImage struct { + multicloud.SImageBase + CtyunTags + storageCache *SStoragecache + + // normalized image info + imgInfo *imagetools.ImageInfo + + ID string `json:"id"` + OSType string `json:"osType"` + Platform string `json:"platform"` + Name string `json:"name"` + OSBit int64 `json:"osBit"` + OSVersion string `json:"osVersion"` + MinRAM int64 `json:"minRam"` + MinDisk int64 `json:"minDisk"` + ImageType string `json:"imageType"` + Virtual bool `json:"virtual"` +} + +func (self *SImage) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SImage) GetId() string { + return self.ID +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (self *SImage) GetGlobalId() string { + return self.GetId() +} + +func (self *SImage) GetStatus() string { + return api.CACHED_IMAGE_STATUS_ACTIVE +} + +func (self *SImage) Refresh() error { + new, err := self.storageCache.region.GetImage(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SImage) IsEmulated() bool { + return false +} + +func (self *SImage) Delete(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.storageCache +} + +func (self *SImage) GetSizeByte() int64 { + return self.MinDisk * 1024 * 1024 * 1024 +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + switch self.ImageType { + case "gold": + return cloudprovider.ImageTypeSystem + case "private": + return cloudprovider.ImageTypeCustomized + case "shared": + return cloudprovider.ImageTypeShared + default: + return cloudprovider.ImageTypeCustomized + } +} + +func (self *SImage) GetImageStatus() string { + return cloudprovider.IMAGE_STATUS_ACTIVE +} + +func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if self.imgInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(self.OSVersion, strconv.Itoa(int(self.OSBit)), self.OSType, self.Platform, self.OSVersion) + self.imgInfo = &imgInfo + } + return self.imgInfo +} + +func (self *SImage) GetFullOsName() string { + return self.getNormalizedImageInfo().GetFullOsName() +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) +} + +func (self *SImage) GetOsDist() string { + return self.getNormalizedImageInfo().OsDistro +} + +func (self *SImage) GetOsVersion() string { + return self.getNormalizedImageInfo().OsVersion +} + +func (self *SImage) GetOsLang() string { + return self.getNormalizedImageInfo().OsLang +} + +func (self *SImage) GetOsArch() string { + return self.getNormalizedImageInfo().OsArch +} + +func (self *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return int(self.MinDisk) +} + +func (self *SImage) GetMinRamSizeMb() int { + return int(self.MinRAM) +} + +func (self *SImage) GetImageFormat() string { + return "" +} + +func (self *SImage) GetCreateTime() time.Time { + return time.Time{} +} + +func (self *SRegion) GetImages(imageType string) ([]SImage, error) { + params := map[string]string{ + "regionId": self.GetId(), + "imageType": imageType, + } + + resp, err := self.client.DoGet("/apiproxy/v3/order/getImages", params) + if err != nil { + return nil, errors.Wrap(err, "Region.GetImages.DoGet") + } + + images := make([]SImage, 0) + err = resp.Unmarshal(&images, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "Region.GetImages.Unmarshal") + } + + for i := range images { + images[i].storageCache = &SStoragecache{ + region: self, + } + } + + return images, nil +} + +func (self *SRegion) GetImage(imageId string) (*SImage, error) { + images, err := self.GetImages("") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetImage.GetImages") + } + + for i := range images { + if images[i].GetId() == imageId { + images[i].storageCache = &SStoragecache{ + region: self, + } + + return &images[i], nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetImage") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/instance.go new file mode 100644 index 0000000000..a3e81e1c24 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/instance.go @@ -0,0 +1,1306 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SInstance struct { + multicloud.SInstanceBase + CtyunTags + multicloud.SBillingBase + + host *SHost + image *SImage + + vmDetails *InstanceDetails + + HostID string `json:"hostId"` + ID string `json:"id"` + Name string `json:"name"` + Status string `json:"status"` + TenantID string `json:"tenant_id"` + Metadata Metadata `json:"metadata"` + Image Image `json:"image"` + Flavor FlavorObj `json:"flavor"` + Addresses map[string][]Address `json:"addresses"` + UserID string `json:"user_id"` + Created time.Time `json:"created"` + DueDate *time.Time `json:"dueDate"` + SecurityGroups []SecurityGroup `json:"security_groups"` + OSEXTAZAvailabilityZone string `json:"OS-EXT-AZ:availability_zone"` + OSExtendedVolumesVolumesAttached []Volume `json:"os-extended-volumes:volumes_attached"` + MasterOrderId string `json:"masterOrderId"` +} + +type InstanceDetails struct { + HostID string `json:"hostId"` + Name string `json:"name"` + Status string `json:"status"` + PrivateIPS []PrivateIP `json:"privateIps"` + PublicIPS []PublicIP `json:"publicIps"` + Volumes []Volume `json:"volumes"` + Created string `json:"created"` + FlavorObj FlavorObj `json:"flavorObj"` +} + +type Address struct { + Addr string `json:"addr"` + OSEXTIPSType string `json:"OS-EXT-IPS:type"` + Version int64 `json:"version"` + OSEXTIPSMACMACAddr string `json:"OS-EXT-IPS-MAC:mac_addr"` +} + +type Image struct { + Id string `json:"id"` +} + +type SecurityGroup struct { + Name string `json:"name"` +} + +type FlavorObj struct { + Name string `json:"name"` + CPUNum int `json:"cpuNum"` + MemSize int `json:"memSize"` + ID string `json:"id"` +} + +type PrivateIP struct { + ID string `json:"id"` + Address string `json:"address"` +} + +type PublicP struct { + ID string `json:"id"` + Address string `json:"address"` + Bandwidth string `json:"bandwidth"` +} + +func (self *SInstance) GetBillingType() string { + if self.DueDate != nil { + return billing_api.BILLING_TYPE_PREPAID + } else { + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SInstance) GetCreatedAt() time.Time { + return self.Created +} + +func (self *SInstance) GetExpiredAt() time.Time { + if self.DueDate == nil { + return time.Time{} + } + + return *self.DueDate +} + +func (self *SInstance) GetId() string { + return self.ID +} + +func (self *SInstance) GetName() string { + return self.Name +} + +func (self *SInstance) GetHostname() string { + return self.Name +} + +func (self *SInstance) GetGlobalId() string { + return self.GetId() +} + +func (self *SInstance) GetStatus() string { + switch self.Status { + case "RUNNING", "ACTIVE": + return api.VM_RUNNING + case "RESTARTING", "BUILD", "RESIZE", "VERIFY_RESIZE": + return api.VM_STARTING + case "STOPPING", "HARD_REBOOT": + return api.VM_STOPPING + case "STOPPED", "SHUTOFF": + return api.VM_READY + default: + return api.VM_UNKNOWN + } +} + +func (self *SInstance) Refresh() error { + new, err := self.host.zone.region.GetVMById(self.GetId()) + if err != nil { + return err + } + + new.host = self.host + if err != nil { + return err + } + + if new.Status == "DELETED" { + log.Debugf("Instance already terminated.") + return cloudprovider.ErrNotFound + } + + // update details + detail, err := self.host.zone.region.GetVMDetails(self.GetId()) + if err != nil { + return errors.Wrap(err, "SInstance.Refresh.GetDetails") + } + + self.vmDetails = detail + return jsonutils.Update(self, new) +} + +func (self *SInstance) IsEmulated() bool { + return false +} + +func (self *SInstance) GetProjectId() string { + return "" +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +// GET http://ctyun-api-url/apiproxy/v3/queryDataDiskByVMId +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + details, err := self.GetDetails() + if err != nil { + return nil, errors.Wrap(err, "SInstance.GetIDisks.GetDetails") + } + + disks := []SDisk{} + for i := range details.Volumes { + volume := details.Volumes[i] + disk, err := self.host.zone.region.GetDisk(volume.ID) + if err != nil { + return nil, errors.Wrap(err, "SInstance.GetIDisks.GetDisk") + } + + disks = append(disks, *disk) + } + + for i := 0; i < len(disks); i += 1 { + // 将系统盘放到第0个位置 + if disks[i].Bootable == "true" { + _temp := disks[0] + disks[0] = disks[i] + disks[i] = _temp + } + } + + idisks := make([]cloudprovider.ICloudDisk, len(disks)) + for i := range disks { + disk := disks[i] + idisks[i] = &disk + } + + return idisks, nil +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics, err := self.host.zone.region.GetNics(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "SInstance.GetINics") + } + + inics := make([]cloudprovider.ICloudNic, len(nics)) + for i := range nics { + inics[i] = &nics[i] + } + + return inics, nil +} + +// GET http://ctyun-api-urlapiproxy/v3/queryNetworkByVMId +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + detail, err := self.GetDetails() + if err != nil { + return nil, errors.Wrap(err, "SInstance.GetIEIP.GetDetails") + } + + if len(detail.PublicIPS) > 0 { + return self.host.zone.region.GetEip(detail.PublicIPS[0].ID) + } + + return nil, nil +} + +func (self *SInstance) GetDetails() (*InstanceDetails, error) { + if self.vmDetails != nil { + return self.vmDetails, nil + } + + detail, err := self.host.zone.region.GetVMDetails(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "SInstance.GetDetails") + } + + self.vmDetails = detail + return self.vmDetails, nil +} + +func (self *SInstance) GetVcpuCount() int { + details, err := self.GetDetails() + if err == nil { + return details.FlavorObj.CPUNum + } + + return self.Flavor.CPUNum +} + +func (self *SInstance) GetVmemSizeMB() int { + details, err := self.GetDetails() + if err == nil { + return details.FlavorObj.MemSize * 1024 + } + + return self.Flavor.MemSize * 1024 +} + +func (self *SInstance) GetBootOrder() string { + return "dcn" +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (self *SInstance) GetImage() (*SImage, error) { + if self.image != nil { + return self.image, nil + } + + image, err := self.host.zone.region.GetImage(self.Image.Id) + if err != nil { + return nil, errors.Wrap(err, "SInstance.GetImage") + } + + self.image = image + return self.image, nil +} + +func (self *SInstance) GetOsType() cloudprovider.TOsType { + image, err := self.GetImage() + if err != nil { + log.Errorf("SInstance.Image %s", err) + return cloudprovider.OsTypeLinux + } + return image.GetOsType() +} + +func (self *SInstance) GetFullOsName() string { + image, err := self.GetImage() + if err != nil { + log.Errorf("SInstance.Image %s", err) + return "" + } + return image.GetFullOsName() +} + +func (self *SInstance) GetBios() cloudprovider.TBiosType { + image, err := self.GetImage() + if err != nil { + log.Errorf("SInstance.Image %s", err) + return cloudprovider.BIOS + } + return image.GetBios() +} + +func (self *SInstance) GetOsArch() string { + image, err := self.GetImage() + if err != nil { + log.Errorf("SInstance.Image %s", err) + return "" + } + return image.GetOsArch() +} + +func (self *SInstance) GetOsDist() string { + image, err := self.GetImage() + if err != nil { + log.Errorf("SInstance.Image %s", err) + return "" + } + return image.GetOsDist() +} + +func (self *SInstance) GetOsVersion() string { + image, err := self.GetImage() + if err != nil { + log.Errorf("SInstance.Image %s", err) + return "" + } + return image.GetOsVersion() +} + +func (self *SInstance) GetOsLang() string { + image, err := self.GetImage() + if err != nil { + log.Errorf("SInstance.Image %s", err) + return "" + } + return image.GetOsLang() +} + +func (self *SInstance) GetMachine() string { + return "pc" +} + +func (self *SInstance) GetInstanceType() string { + return self.Flavor.ID +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + if len(self.SecurityGroups) == 0 { + return []string{}, nil + } + + if len(self.MasterOrderId) > 0 { + return self.getSecurityGroupIdsByMasterOrderId(self.MasterOrderId) + } + + secgroups, err := self.host.zone.region.GetSecurityGroups("") + if err != nil { + return nil, errors.Wrap(err, "SInstance.GetSecurityGroupIds.GetSecurityGroups") + } + + names := []string{} + for i := range self.SecurityGroups { + names = append(names, self.SecurityGroups[i].Name) + } + + ids := []string{} + for i := range secgroups { + // todo: bugfix 如果安全组重名比较尴尬 + if utils.IsInStringArray(secgroups[i].Name, names) { + ids = append(ids, secgroups[i].ResSecurityGroupID) + } + } + + return ids, nil +} + +func (self *SInstance) getSecurityGroupIdsByMasterOrderId(orderId string) ([]string, error) { + orders, err := self.host.zone.region.GetOrder(self.MasterOrderId) + if err != nil { + return nil, errors.Wrap(err, "SInstance.GetSecurityGroupIds.GetOrder") + } + + if len(orders) == 0 { + return nil, nil + } + + for i := range orders { + secgroups := orders[i].ResourceConfigMap.SecurityGroups + if len(secgroups) > 0 { + ids := []string{} + for j := range secgroups { + ids = append(ids, secgroups[j].ID) + } + + return ids, nil + } + } + + return nil, nil +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.host.zone.region.AssignSecurityGroup(self.GetId(), secgroupId) +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + currentIds, err := self.GetSecurityGroupIds() + if err != nil { + return errors.Wrap(err, "GetSecurityGroupIds") + } + + adds := []string{} + for i := range secgroupIds { + if !utils.IsInStringArray(secgroupIds[i], currentIds) { + adds = append(adds, secgroupIds[i]) + } + } + + for i := range adds { + err := self.host.zone.region.AssignSecurityGroup(self.GetId(), adds[i]) + if err != nil { + return errors.Wrap(err, "Instance.SetSecurityGroups") + } + } + + removes := []string{} + for i := range currentIds { + if !utils.IsInStringArray(currentIds[i], secgroupIds) { + removes = append(removes, currentIds[i]) + } + } + + for i := range removes { + err := self.host.zone.region.UnsignSecurityGroup(self.GetId(), removes[i]) + if err != nil { + return errors.Wrap(err, "Instance.SetSecurityGroups") + } + } + + return nil +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_CTYUN +} + +func (self *SInstance) StartVM(ctx context.Context) error { + err := self.host.zone.region.StartVM(self.GetId()) + if err != nil { + return errors.Wrap(err, "Instance.StartVM") + } + + err = cloudprovider.WaitStatus(self, api.VM_RUNNING, 5*time.Second, 300*time.Second) + if err != nil { + return errors.Wrap(err, "Instance.StartVM.WaitStatus") + } + return nil +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + err := self.host.zone.region.StopVM(self.GetId()) + if err != nil { + return errors.Wrap(err, "Instance.StopVM") + } + + err = cloudprovider.WaitStatus(self, api.VM_READY, 5*time.Second, 300*time.Second) + if err != nil { + return errors.Wrap(err, "Instance.StopVM.WaitStatus") + } + return nil +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + err := self.host.zone.region.DeleteVM(self.GetId()) + if err != nil { + return errors.Wrap(err, "SInstance.DeleteVM") + } + + err = cloudprovider.WaitDeleted(self, 10*time.Second, 180*time.Second) + if err != nil { + return errors.Wrap(err, "Instance.DeleteVM.WaitDeleted") + } + return nil +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + currentImage, err := self.GetImage() + if err != nil { + return "", errors.Wrap(err, "Instance.RebuildRoot") + } + + publicKeyName := "" + if len(config.PublicKey) > 0 { + publicKeyName, err = self.host.zone.region.syncKeypair(config.PublicKey) + if err != nil { + return "", errors.Wrap(err, "Instance.RebuildRoot.syncKeypair") + } + } + + jobId := "" + if currentImage.GetId() != config.ImageId { + jobId, err = self.host.zone.region.SwitchVMOs(self.GetId(), config.Password, publicKeyName, config.ImageId) + if err != nil { + return "", errors.Wrap(err, "SInstance.RebuildRoot.SwitchVMOs") + } + } else { + jobId, err = self.host.zone.region.RebuildVM(self.GetId(), config.Password, publicKeyName) + if err != nil { + return "", errors.Wrap(err, "SInstance.RebuildRoot.RebuildVM") + } + } + + err = cloudprovider.Wait(10*time.Second, 1800*time.Second, func() (b bool, err error) { + statusJson, err := self.host.zone.region.GetJob(jobId) + if err != nil { + if strings.Contains(err.Error(), "job fail") { + return false, err + } + + return false, nil + } + + if status, _ := statusJson.GetString("status"); status == "SUCCESS" { + return true, nil + } else if status == "FAILED" { + return false, fmt.Errorf("RebuildRoot job %s failed", jobId) + } else { + return false, nil + } + }) + if err != nil { + return "", errors.Wrap(err, "Instance.RebuildRoot.Wait") + } + + err = self.Refresh() + if err != nil { + return "", err + } + + idisks, err := self.GetIDisks() + if err != nil { + return "", err + } + + if len(idisks) == 0 { + return "", fmt.Errorf("server %s has no volume attached.", self.GetId()) + } + + return idisks[0].GetId(), nil +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + if len(password) == 0 { + return cloudprovider.ErrNotSupported + } + + // 只支持重置密码 + return self.host.zone.region.ResetVMPassword(self.GetId(), password) +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + jobId, err := self.host.zone.region.ChangeVMConfig(self.GetId(), config.InstanceType) + if err != nil { + return errors.Wrap(err, "Instance.ChangeConfig") + } + + err = cloudprovider.Wait(10*time.Second, 1800*time.Second, func() (b bool, err error) { + statusJson, err := self.host.zone.region.GetJob(jobId) + if err != nil { + if strings.Contains(err.Error(), "job fail") { + return false, err + } + + return false, nil + } + + if status, _ := statusJson.GetString("status"); status == "SUCCESS" { + return true, nil + } else if status == "FAILED" { + return false, fmt.Errorf("ChangeConfig job %s failed", jobId) + } else { + return false, nil + } + }) + if err != nil { + return errors.Wrap(err, "Instance.ChangeConfig.Wait") + } + + return nil +} + +// http://ctyun-api-url/apiproxy/v3/queryVncUrl +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + url, err := self.host.zone.region.GetInstanceVNCUrl(self.GetId()) + if err != nil { + return nil, err + } + ret := &cloudprovider.ServerVncOutput{ + Url: url, + Protocol: "ctyun", + InstanceId: self.GetId(), + Hypervisor: api.HYPERVISOR_CTYUN, + } + return ret, nil +} + +func (self *SInstance) NextDeviceName() (string, error) { + details, err := self.GetDetails() + if err != nil { + return "", errors.Wrap(err, "SInstance.NextDeviceName.GetDetails") + } + + disks := []*SDisk{} + for i := range details.Volumes { + disk, err := self.host.zone.region.GetDisk(details.Volumes[i].ID) + if err != nil { + return "", errors.Wrap(err, "SInstance.NextDeviceName.GetDisk") + } + + disks = append(disks, disk) + } + + prefix := "s" + if len(disks) > 0 && strings.Contains(disks[0].GetMountpoint(), "/vd") { + prefix = "v" + } + + currents := []string{} + for _, disk := range disks { + currents = append(currents, strings.ToLower(disk.GetMountpoint())) + } + + for i := 0; i < 25; i++ { + device := fmt.Sprintf("/dev/%sd%s", prefix, string([]byte{byte(98 + i)})) + if ok, _ := utils.InStringArray(device, currents); !ok { + return device, nil + } + } + + return "", fmt.Errorf("disk devicename out of index, current deivces: %s", currents) +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + device, err := self.NextDeviceName() + if err != nil { + return errors.Wrap(err, "Instance.AttachDisk.NextDeviceName") + } + + _, err = self.host.zone.region.AttachDisk(self.GetId(), diskId, device) + if err != nil { + return errors.Wrap(err, "Instance.AttachDisk") + } + + disk, err := self.host.zone.region.GetDisk(diskId) + if err != nil { + return errors.Wrap(err, "AttachDisk.GetDisk") + } + + err = cloudprovider.WaitStatusWithDelay(disk, api.DISK_READY, 10*time.Second, 5*time.Second, 180*time.Second) + if err != nil { + return errors.Wrap(err, "Instance.DetachDisk.WaitStatusWithDelay") + } + + if disk.Status != "in-use" { + return errors.Wrap(fmt.Errorf("disk status %s", disk.Status), "Instance.DetachDisk.Status") + } + + return nil +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + disk, err := self.host.zone.region.GetDisk(diskId) + if err != nil { + return errors.Wrap(err, "DetachDisk.Wait") + } + + if len(disk.Attachments) == 0 { + return errors.Wrap(err, "Instance.DetachDisk") + } + + _, err = self.host.zone.region.DetachDisk(self.GetId(), diskId, disk.Attachments[0].Device) + if err != nil { + return errors.Wrap(err, "Instance.DetachDisk") + } + + err = cloudprovider.WaitStatusWithDelay(disk, api.DISK_READY, 10*time.Second, 5*time.Second, 180*time.Second) + if err != nil { + return errors.Wrap(err, "Instance.DetachDisk.WaitStatusWithDelay") + } + + if disk.Status != "available" { + return errors.Wrap(fmt.Errorf("disk status %s", disk.Status), "Instance.DetachDisk.Status") + } + + return nil +} + +func (self *SInstance) Renew(bc billing.SBillingCycle) error { + _, err := self.host.zone.region.RenewVM(self.GetId(), &bc) + if err != nil { + return errors.Wrap(err, "Instance.Renew.RenewVM") + } + + return nil +} + +func (self *SInstance) GetError() error { + return nil +} + +type SDiskDetails struct { + HostID string `json:"hostId"` + Name string `json:"name"` + Status string `json:"status"` + PrivateIPS []PrivateIP `json:"privateIps"` + PublicIPS []PublicIP `json:"publicIps"` + Volumes []Volume `json:"volumes"` + Created string `json:"created"` + FlavorObj FlavorObj `json:"flavorObj"` +} + +type PublicIP struct { + ID string `json:"id"` + Address string `json:"address"` + Bandwidth string `json:"bandwidth"` +} + +type Volume struct { + ID string `json:"id"` + Status string `json:"status"` + Type string `json:"type"` + Size string `json:"size"` + Name string `json:"name"` + Bootable bool `json:"bootable"` +} + +func (self *SRegion) GetVMDetails(vmId string) (*InstanceDetails, error) { + params := map[string]string{ + "regionId": self.GetId(), + "vmId": vmId, + } + + resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVMDetail", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetVMDetails.DoGet") + } + + details := &InstanceDetails{} + err = resp.Unmarshal(details, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetVMDetails.Unmarshal") + } + + return details, nil +} + +type SVncInfo struct { + Type string `json:"type"` + URL string `json:"url"` +} + +func (self *SRegion) GetInstanceVNCUrl(vmId string) (string, error) { + params := map[string]string{ + "regionId": self.GetId(), + "vmId": vmId, + } + + resp, err := self.client.DoGet("/apiproxy/v3/queryVncUrl", params) + if err != nil { + return "", errors.Wrap(err, "") + } + + ret := SVncInfo{} + err = resp.Unmarshal(&ret, "returnObj", "console") + if err != nil { + return "", errors.Wrap(err, "") + } + + return ret.URL, nil +} + +/* +创建主机接口目前没有绑定密钥的参数选项,不支持绑定密码。 +但是重装系统接口支持绑定密钥 +*/ +func (self *SRegion) CreateInstance(zoneId, name, imageId, osType, flavorRef, vpcid, subnetId, secGroupId, adminPass, volumetype string, volumeSize int, dataDisks []cloudprovider.SDiskInfo) (string, error) { + rootParams := jsonutils.NewDict() + rootParams.Set("volumetype", jsonutils.NewString(volumetype)) + if volumeSize > 0 { + rootParams.Set("size", jsonutils.NewInt(int64(volumeSize))) + } + + nicParams := jsonutils.NewArray() + nicParam := jsonutils.NewDict() + nicParam.Set("subnet_id", jsonutils.NewString(subnetId)) + nicParams.Add(nicParam) + + secgroupParams := jsonutils.NewArray() + secgroupParam := jsonutils.NewDict() + secgroupParam.Set("id", jsonutils.NewString(secGroupId)) + secgroupParams.Add(secgroupParam) + + extParams := jsonutils.NewDict() + extParams.Set("regionID", jsonutils.NewString(self.GetId())) + + serverParams := jsonutils.NewDict() + serverParams.Set("availability_zone", jsonutils.NewString(zoneId)) + serverParams.Set("name", jsonutils.NewString(name)) + serverParams.Set("imageRef", jsonutils.NewString(imageId)) + serverParams.Set("root_volume", rootParams) + serverParams.Set("flavorRef", jsonutils.NewString(flavorRef)) + serverParams.Set("osType", jsonutils.NewString(osType)) + serverParams.Set("vpcid", jsonutils.NewString(vpcid)) + serverParams.Set("security_groups", secgroupParams) + serverParams.Set("nics", nicParams) + serverParams.Set("adminPass", jsonutils.NewString(adminPass)) + serverParams.Set("count", jsonutils.NewString("1")) + serverParams.Set("extendparam", extParams) + + if dataDisks != nil && len(dataDisks) > 0 { + dataDisksParams := jsonutils.NewArray() + for i := range dataDisks { + dataDiskParams := jsonutils.NewDict() + dataDiskParams.Set("volumetype", jsonutils.NewString(dataDisks[i].StorageType)) + dataDiskParams.Set("size", jsonutils.NewInt(int64(dataDisks[i].SizeGB))) + dataDisksParams.Add(dataDiskParams) + } + + serverParams.Set("data_volumes", dataDisksParams) + } + + vmParams := jsonutils.NewDict() + vmParams.Set("server", serverParams) + + params := map[string]jsonutils.JSONObject{ + "createVMInfo": vmParams, + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/createVM", params) + if err != nil { + return "", errors.Wrap(err, "SRegion.CreateInstance.DoPost") + } + + var ok bool + err = resp.Unmarshal(&ok, "returnObj", "status") + if !ok { + msg, _ := resp.GetString("returnObj", "message") + return "", errors.Wrap(fmt.Errorf(msg), "SRegion.CreateInstance.JobFailed") + } + + var jobId string + err = resp.Unmarshal(&jobId, "returnObj", "data") + if err != nil { + return "", errors.Wrap(err, "SRegion.CreateInstance.Unmarshal") + } + + return jobId, nil +} + +// vm & nic job +func (self *SRegion) GetJob(jobId string) (jsonutils.JSONObject, error) { + params := map[string]string{ + "regionId": self.GetId(), + "jobId": jobId, + } + + resp, err := self.client.DoGet("/apiproxy/v3/queryJobStatus", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetJob.DoGet") + } + + ret := jsonutils.NewDict() + err = resp.Unmarshal(&ret, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetJob.Unmarshal") + } + + return ret, nil +} + +// 查询云硬盘备份JOB状态信息 +func (self *SRegion) GetVbsJob(jobId string) (jsonutils.JSONObject, error) { + params := map[string]string{ + "regionId": self.GetId(), + "jobId": jobId, + } + + resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVbsJob", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetVbsJob.DoGet") + } + + ret := jsonutils.NewDict() + err = resp.Unmarshal(&ret, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetVbsJob.Unmarshal") + } + + return ret, nil +} + +// 查询云硬盘JOB状态信息 +func (self *SRegion) GetVolumeJob(jobId string) (jsonutils.JSONObject, error) { + params := map[string]string{ + "regionId": self.GetId(), + "jobId": jobId, + } + + resp, err := self.client.DoGet("/apiproxy/v3/queryVolumeJob", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetVolumeJob.DoGet") + } + + ret := jsonutils.NewDict() + err = resp.Unmarshal(&ret, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetVolumeJob.Unmarshal") + } + + return ret, nil +} + +// POST http://ctyun-api-url/apiproxy/v3/addSecurityGroup 绑定安全组 +func (self *SRegion) AssignSecurityGroup(vmId, securityGroupRuleId string) error { + securityParams := jsonutils.NewDict() + securityParams.Set("regionId", jsonutils.NewString(self.GetId())) + securityParams.Set("vmId", jsonutils.NewString(vmId)) + securityParams.Set("securityGroupRuleId", jsonutils.NewString(securityGroupRuleId)) + + params := map[string]jsonutils.JSONObject{ + "securityGroup": securityParams, + } + + _, err := self.client.DoPost("/apiproxy/v3/addSecurityGroup", params) + if err != nil { + return errors.Wrap(err, "SRegion.AssignSecurityGroup.DoPost") + } + + return nil +} + +// POST http://ctyun-api-url/apiproxy/v3/removeSecurityGroup 解绑安全组 +func (self *SRegion) UnsignSecurityGroup(vmId, securityGroupRuleId string) error { + securityParams := jsonutils.NewDict() + securityParams.Set("regionId", jsonutils.NewString(self.GetId())) + securityParams.Set("vmId", jsonutils.NewString(vmId)) + securityParams.Set("securityGroupRuleId", jsonutils.NewString(securityGroupRuleId)) + + params := map[string]jsonutils.JSONObject{ + "securityGroup": securityParams, + } + + _, err := self.client.DoPost("/apiproxy/v3/removeSecurityGroup", params) + if err != nil { + return errors.Wrap(err, "SRegion.UnsignSecurityGroup.DoPost") + } + + return nil +} + +func (self *SRegion) StartVM(vmId string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "vmId": jsonutils.NewString(vmId), + } + + _, err := self.client.DoPost("/apiproxy/v3/ondemand/startVM", params) + if err != nil { + return errors.Wrap(err, "SRegion.StartVm.DoPost") + } + + return nil +} + +func (self *SRegion) StopVM(vmId string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "vmId": jsonutils.NewString(vmId), + } + + _, err := self.client.DoPost("/apiproxy/v3/ondemand/stopVM", params) + if err != nil { + return errors.Wrap(err, "SRegion.StopVM.DoPost") + } + + return nil +} + +func (self *SRegion) DeleteVM(vmId string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "vmId": jsonutils.NewString(vmId), + } + + _, err := self.client.DoPost("/apiproxy/v3/ondemand/deleteVM", params) + if err != nil { + return errors.Wrap(err, "SRegion.DeleteVM.DoPost") + } + + return nil +} + +func (self *SRegion) RestartVM(vmId string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "vmId": jsonutils.NewString(vmId), + "type": jsonutils.NewString("SOFT"), + } + + _, err := self.client.DoPost("/apiproxy/v3/ondemand/restartVM", params) + if err != nil { + return errors.Wrap(err, "SRegion.RestartVM.DoPost") + } + + return nil +} + +func (self *SRegion) SwitchVMOs(vmId, adminPass, keyName, imageRef string) (string, error) { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "vmId": jsonutils.NewString(vmId), + "imageRef": jsonutils.NewString(imageRef), + } + + if len(keyName) > 0 { + params["keyName"] = jsonutils.NewString(keyName) + } else if len(adminPass) > 0 { + params["adminPass"] = jsonutils.NewString(adminPass) + } else { + return "", errors.Wrap(fmt.Errorf("require public key or password"), "SRegion.SwitchVMOs") + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/switchSys", params) + if err != nil { + return "", errors.Wrap(err, "SRegion.SwitchVMOs.DoPost") + } + + var ok bool + err = resp.Unmarshal(&ok, "returnObj", "status") + if !ok { + msg, _ := resp.GetString("returnObj", "message") + return "", errors.Wrap(fmt.Errorf(msg), "SRegion.SwitchVMOs.JobFailed") + } + + var jobId string + err = resp.Unmarshal(&jobId, "returnObj", "data") + if err != nil { + return "", errors.Wrap(err, "SRegion.SwitchVMOs.Unmarshal") + } + + return jobId, nil +} + +func (self *SRegion) RebuildVM(vmId, adminPass, keyName string) (string, error) { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "vmId": jsonutils.NewString(vmId), + } + + if len(keyName) > 0 { + params["keyName"] = jsonutils.NewString(keyName) + } else if len(adminPass) > 0 { + params["adminPass"] = jsonutils.NewString(adminPass) + } else { + return "", errors.Wrap(fmt.Errorf("require public key or password"), "SRegion.RebuildVM") + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/reInstallSys", params) + if err != nil { + return "", errors.Wrap(err, "SRegion.RebuildVM.DoPost") + } + + var ok bool + err = resp.Unmarshal(&ok, "returnObj", "status") + if !ok { + msg, _ := resp.GetString("returnObj", "message") + return "", errors.Wrap(fmt.Errorf(msg), "SRegion.RebuildVM.JobFailed") + } + + var jobId string + err = resp.Unmarshal(&jobId, "returnObj", "data") + if err != nil { + return "", errors.Wrap(err, "SRegion.RebuildVM.Unmarshal") + } + + return jobId, nil +} + +func (self *SRegion) AttachDisk(vmId, volumeId, device string) (string, error) { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "volumeId": jsonutils.NewString(volumeId), + "vmId": jsonutils.NewString(vmId), + "device": jsonutils.NewString(device), + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/attachVolume", params) + if err != nil { + return "", errors.Wrap(err, "SRegion.AttachDisk.DoPost") + } + + var ok bool + err = resp.Unmarshal(&ok, "returnObj", "status") + if !ok { + msg, _ := resp.GetString("returnObj", "message") + return "", errors.Wrap(fmt.Errorf(msg), "SRegion.AttachDisk.JobFailed") + } + + var jobId string + err = resp.Unmarshal(&jobId, "returnObj", "data") + if err != nil { + return "", errors.Wrap(err, "SRegion.AttachDisk.Unmarshal") + } + + return jobId, nil +} + +func (self *SRegion) DetachDisk(vmId, volumeId, device string) (string, error) { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "volumeId": jsonutils.NewString(volumeId), + "vmId": jsonutils.NewString(vmId), + "device": jsonutils.NewString(device), + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/uninstallVolume", params) + if err != nil { + return "", errors.Wrap(err, "SRegion.DetachDisk.DoPost") + } + + var ok bool + err = resp.Unmarshal(&ok, "returnObj", "status") + if !ok { + msg, _ := resp.GetString("returnObj", "message") + return "", errors.Wrap(fmt.Errorf(msg), "SRegion.DetachDisk.JobFailed") + } + + var jobId string + err = resp.Unmarshal(&jobId, "returnObj", "data") + if err != nil { + return "", errors.Wrap(err, "SRegion.DetachDisk.Unmarshal") + } + + return jobId, nil +} + +func (self *SRegion) ChangeVMConfig(vmId, flavorId string) (string, error) { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "vmId": jsonutils.NewString(vmId), + "flavorId": jsonutils.NewString(flavorId), + } + + resp, err := self.client.DoPost("/apiproxy/v3/ondemand/upgradeVM", params) + if err != nil { + return "", errors.Wrap(err, "SRegion.ChangeVMConfig.DoPost") + } + + var ok bool + err = resp.Unmarshal(&ok, "returnObj", "status") + if !ok { + msg, _ := resp.GetString("returnObj", "message") + return "", errors.Wrap(fmt.Errorf(msg), "SRegion.ChangeVMConfig.JobFailed") + } + + var jobId string + err = resp.Unmarshal(&jobId, "returnObj", "data") + if err != nil { + return "", errors.Wrap(err, "SRegion.ChangeVMConfig.Unmarshal") + } + + return jobId, nil +} + +// POST http://ctyun-api-url/apiproxy/v3/order/placeRenewOrder 续订 +func (self *SRegion) RenewVM(vmId string, bc *billing.SBillingCycle) ([]string, error) { + if bc == nil { + return nil, errors.Wrap(fmt.Errorf("SBillingCycle is nil"), "Region.RenewVM") + } + + resourcePackage := jsonutils.NewDict() + month := bc.GetMonths() + switch { + case month <= 11: + resourcePackage.Set("cycleCount", jsonutils.NewString(strconv.Itoa(month))) + resourcePackage.Set("cycleType", jsonutils.NewString("3")) + case month == 12: + resourcePackage.Set("cycleCount", jsonutils.NewString("1")) + resourcePackage.Set("cycleType", jsonutils.NewString("5")) + case month == 24: + resourcePackage.Set("cycleCount", jsonutils.NewString("1")) + resourcePackage.Set("cycleType", jsonutils.NewString("6")) + case month == 36: + resourcePackage.Set("cycleCount", jsonutils.NewString("1")) + resourcePackage.Set("cycleType", jsonutils.NewString("7")) + default: + return nil, errors.Wrap(fmt.Errorf("unsupported month duration %d. expected 1~11, 12, 24, 36", month), "Region.RenewVM") + } + + vmIds := jsonutils.NewArray() + vmIds.Add(jsonutils.NewString(vmId)) + resourcePackage.Set("resourceIds", vmIds) + + params := map[string]jsonutils.JSONObject{ + "resourceDetailJson": resourcePackage, + } + + resp, err := self.client.DoPost("/apiproxy/v3/order/placeRenewOrder", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.RenewVM.DoPost") + } + + var ok bool + err = resp.Unmarshal(&ok, "returnObj", "submitted") + if !ok { + msg, _ := resp.GetString("returnObj", "message") + return nil, errors.Wrap(fmt.Errorf(msg), "SRegion.RenewVM.JobFailed") + } + + type OrderPlacedEventsElement struct { + ErrorMessage string `json:"errorMessage"` + Submitted bool `json:"submitted"` + NewOrderID string `json:"newOrderId"` + NewOrderNo string `json:"newOrderNo"` + TotalPrice int64 `json:"totalPrice"` + } + + orders := []OrderPlacedEventsElement{} + err = resp.Unmarshal(&orders, "returnObj", "orderPlacedEvents") + if err != nil { + return nil, errors.Wrap(err, "SRegion.RenewVM.Unmarshal") + } + + orderIds := []string{} + for i := range orders { + orderIds = append(orderIds, orders[i].NewOrderID) + } + + return orderIds, nil +} + +func (self *SRegion) ResetVMPassword(vmId, password string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "vmId": jsonutils.NewString(vmId), + "password": jsonutils.NewString(password), + } + + _, err := self.client.DoPost("/apiproxy/v3/resetVmPassword", params) + if err != nil { + return errors.Wrap(err, "SRegion.ResetVMPassword.DoPost") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/instancenic.go new file mode 100644 index 0000000000..cee7d464bb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/instancenic.go @@ -0,0 +1,94 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + instance *SInstance + FixedIPS []FixedIP `json:"fixed_ips"` + PortState string `json:"port_state"` + PortID string `json:"port_id"` + MACAddr string `json:"mac_addr"` + NetID string `json:"net_id"` + + cloudprovider.DummyICloudNic +} + +type FixedIP struct { + IPAddress string `json:"ip_address"` + SubnetID string `json:"subnet_id"` +} + +func (self *SInstanceNic) GetIP() string { + if len(self.FixedIPS) == 0 { + return "" + } + + return self.FixedIPS[0].IPAddress +} + +func (self *SInstanceNic) GetMAC() string { + return self.MACAddr +} + +func (self *SInstanceNic) GetId() string { + return "" +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) GetINetworkId() string { + return self.NetID +} + +func (self *SRegion) GetNics(vmId string) ([]SInstanceNic, error) { + params := map[string]string{ + "regionId": self.GetId(), + "vmId": vmId, + } + + resp, err := self.client.DoGet("/apiproxy/v3/queryNetworkCards", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetNics.DoGet") + } + + ret := make([]SInstanceNic, 0) + err = resp.Unmarshal(&ret, "returnObj", "interfaceAttachments") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetNics.Unmarshal") + } + + for i := range ret { + ins, err := self.GetVMById(vmId) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetNics") + } + + ret[i].instance = ins + } + + return ret, nil +} diff --git a/pkg/multicloud/ctyun/keypair.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/keypair.go similarity index 100% rename from pkg/multicloud/ctyun/keypair.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/keypair.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/latitud_and_longitude.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/latitud_and_longitude.go new file mode 100644 index 0000000000..2fa84b3e54 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/latitud_and_longitude.go @@ -0,0 +1,62 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ + "cn-beijing1": {Latitude: 39.997743, Longitude: 116.304542, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-hz1": {Latitude: 30.274084, Longitude: 120.155067, City: api.CITY_HANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-gslz1": {Latitude: 36.0613769373, Longitude: 103.8341600069, City: api.CITY_LAN_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-sxty1": {Latitude: 37.8705857132, Longitude: 112.5506634865, City: api.CITY_TAI_YUAN, CountryCode: api.COUNTRY_CODE_CN}, + "cn-sh1": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-gz1": {Latitude: 26.6470035286, Longitude: 106.6302113880, City: api.CITY_GUI_YANG, CountryCode: api.COUNTRY_CODE_CN}, + "cn-sdqd1": {Latitude: 36.067108, Longitude: 120.382607, City: api.CITY_QING_DAO, CountryCode: api.COUNTRY_CODE_CN}, + "cn-tj1": {Latitude: 39.0850853357, Longitude: 117.1993482089, City: api.CITY_TIAN_JIN, CountryCode: api.COUNTRY_CODE_CN}, + "cn-xjcj1": {Latitude: 43.8266013700, Longitude: 87.6168405804, City: api.CITY_WU_LU_MU_QI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-cq1": {Latitude: 29.431585, Longitude: 106.912254, City: api.CITY_CHONG_QING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-gxnn1": {Latitude: 22.8167372565, Longitude: 108.3669005333, City: api.CITY_NAN_NING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-hazz1": {Latitude: 34.7533581487, Longitude: 113.6313915479, City: api.CITY_ZHENG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-ynkm1": {Latitude: 24.8796595146, Longitude: 102.8332118852, City: api.CITY_KUN_MING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-xian1": {Latitude: 34.3412614674, Longitude: 108.9398165260, City: api.CITY_XI_AN, CountryCode: api.COUNTRY_CODE_CN}, + "cn-hihk1": {Latitude: 20.0442268036, Longitude: 110.1998910288, City: api.CITY_HAI_KOU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-ahwh1": {Latitude: 31.3524675159, Longitude: 118.4331307290, City: api.CITY_WU_HU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-fz1": {Latitude: 26.0741979397, Longitude: 119.2964466153, City: api.CITY_FU_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-nmhh1": {Latitude: 40.842358, Longitude: 111.749992, City: api.CITY_HU_HE_HAO_TE, CountryCode: api.COUNTRY_CODE_CN}, + "cn-shanghai2": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-snxy1": {Latitude: 34.3412614674, Longitude: 108.9398165260, City: api.CITY_XI_AN, CountryCode: api.COUNTRY_CODE_CN}, + "cn-hbwh1": {Latitude: 30.5927599029, Longitude: 114.3052387810, City: api.CITY_WU_HAN, CountryCode: api.COUNTRY_CODE_CN}, + "cn-hncs1": {Latitude: 28.2277765095, Longitude: 112.9388453666, City: api.CITY_CHANG_SHA, CountryCode: api.COUNTRY_CODE_CN}, + "cn-guangzhou2": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-guizhou2": {Latitude: 26.6470035286, Longitude: 106.6302113880, City: api.CITY_GUI_YANG, CountryCode: api.COUNTRY_CODE_CN}, + "cn-jssz1": {Latitude: 31.2983479333, Longitude: 120.5831894861, City: api.CITY_SU_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-sccd1": {Latitude: 30.572815, Longitude: 104.066803, City: api.CITY_CHENG_DU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-guangzhou3": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-shanghai3": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-neimeng4": {Latitude: 40.842358, Longitude: 111.749992, City: api.CITY_HU_HE_HAO_TE, CountryCode: api.COUNTRY_CODE_CN}, + "cn-beijing3": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-baoding1": {Latitude: 38.8739745619, Longitude: 115.4646082830, City: api.CITY_BAO_DING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-nj2": {Latitude: 32.0584065670, Longitude: 118.7964897811, City: api.CITY_NAN_JING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-gdgz1": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-bj1": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-bj4": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-neimeng5": {Latitude: 40.842358, Longitude: 111.749992, City: api.CITY_HU_HE_HAO_TE, CountryCode: api.COUNTRY_CODE_CN}, + "cn-shanghai5": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-sh6": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-gdfs2": {Latitude: 23.0218629843, Longitude: 113.1219225896, City: api.CITY_FO_SHAN, CountryCode: api.COUNTRY_CODE_CN}, +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/network.go new file mode 100644 index 0000000000..d74c1aef2e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/network.go @@ -0,0 +1,295 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "fmt" + "strconv" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + CtyunTags + vpc *SVpc + wire *SWire + + CIDR string `json:"cidr"` + FirstDcn string `json:"firstDcn"` + Gateway string `json:"gateway"` + Name string `json:"name"` + NeutronSubnetID string `json:"neutronSubnetId"` + RegionID string `json:"regionId"` + ResVLANID string `json:"resVlanId"` + SecondDcn string `json:"secondDcn"` + VLANStatus string `json:"vlanStatus"` + VpcID string `json:"vpcId"` + ZoneID string `json:"zoneId"` + ZoneName string `json:"zoneName"` +} + +func (self *SNetwork) GetId() string { + return self.ResVLANID +} + +func (self *SNetwork) GetName() string { + return self.Name +} + +func (self *SNetwork) GetGlobalId() string { + return self.GetId() +} + +func (self *SNetwork) GetStatus() string { + switch self.VLANStatus { + case "ACTIVE", "UNKNOWN": + return api.NETWORK_STATUS_AVAILABLE + case "ERROR": + return api.NETWORK_STATUS_UNKNOWN + default: + return api.NETWORK_STATUS_UNKNOWN + } +} + +func (self *SNetwork) Refresh() error { + log.Debugf("network refresh %s", self.GetId()) + new, err := self.wire.region.GetNetwork(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SNetwork) IsEmulated() bool { + return false +} + +func (self *SNetwork) GetProjectId() string { + return "" +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + startIp = startIp.StepUp() // 2 + return startIp.String() +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + 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.CIDR) + return pref.MaskLen +} + +func (self *SNetwork) GetGateway() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String() +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetIsPublic() bool { + return true +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) Delete() error { + return self.vpc.region.DeleteNetwork(self.vpc.GetId(), self.GetId()) +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 120 +} + +func (self *SRegion) GetNetwroks(vpcId string) ([]SNetwork, error) { + querys := map[string]string{ + "regionId": self.GetId(), + } + if len(vpcId) > 0 { + querys["vpcId"] = vpcId + } + + networks := make([]SNetwork, 0) + resp, err := self.client.DoGet("/apiproxy/v3/getSubnets", querys) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetNetwroks.DoGet") + } + + err = resp.Unmarshal(&networks, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetNetwroks.Unmarshal") + } + + for i := range networks { + vpc, err := self.GetVpc(networks[i].VpcID) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetNetwork.GetVpc") + } + networks[i].vpc = vpc + + networks[i].wire = &SWire{ + region: self, + vpc: vpc, + } + + networks[i].wire.addNetwork(&networks[i]) + } + + return networks, err +} + +func (self *SRegion) getNetwork(subnetId string) (*SNetwork, error) { + querys := map[string]string{ + "subnetId": subnetId, + "regionId": self.GetId(), + } + + resp, err := self.client.DoGet("/apiproxy/v3/querySubnetDetail", querys) + if err != nil { + return nil, errors.Wrap(err, "SRegion.getNetwork.DoGet") + } + + network := &SNetwork{} + err = resp.Unmarshal(network, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "SRegion.getNetwork.Unmarshal") + } + + return network, nil +} + +func (self *SRegion) GetNetwork(subnetId string) (*SNetwork, error) { + network, err := self.getNetwork(subnetId) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetNetwork.getNetwork") + } + + vpc, err := self.GetVpc(network.VpcID) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetNetwork.GetVpc") + } + network.vpc = vpc + + network.wire = &SWire{ + region: self, + vpc: vpc, + } + + network.wire.addNetwork(network) + return network, err +} + +func (self *SRegion) CreateNetwork(vpcId, zoneId, name, cidr, dhcpEnable string) (*SNetwork, error) { + gateway, err := getDefaultGateWay(cidr) + if err != nil { + return nil, err + } + + networkParams := jsonutils.NewDict() + networkParams.Set("regionId", jsonutils.NewString(self.GetId())) + networkParams.Set("zoneId", jsonutils.NewString(zoneId)) + networkParams.Set("name", jsonutils.NewString(name)) + networkParams.Set("cidr", jsonutils.NewString(cidr)) + networkParams.Set("gatewayIp", jsonutils.NewString(gateway)) + networkParams.Set("dhcpEnable", jsonutils.NewString(dhcpEnable)) + networkParams.Set("vpcId", jsonutils.NewString(vpcId)) + // DNS地址,如果主机需要访问公网就需要填写该值,不填写就不能使用DNS解析 + // networkParams.Set("primaryDns", jsonutils.NewString(primaryDns)) + // networkParams.Set("secondaryDns", jsonutils.NewString(secondaryDns)) + + params := map[string]jsonutils.JSONObject{ + "jsonStr": networkParams, + } + + resp, err := self.client.DoPost("/apiproxy/v3/createSubnet", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateNetwork.DoPost") + } + + netId, err := resp.GetString("returnObj", "id") + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateNetwork.GetString") + } + + err = cloudprovider.WaitCreated(10*time.Second, 180*time.Second, func() bool { + network, err := self.getNetwork(netId) + if err != nil { + log.Debugf("SRegion.CreateNetwork.getNetwork") + return false + } + + if len(network.VpcID) == 0 { + return false + } else { + return true + } + }) + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateNetwork.GetVpc") + } + + return self.GetNetwork(netId) +} + +func (self *SRegion) DeleteNetwork(vpcId, subnetId string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "vpcId": jsonutils.NewString(vpcId), + "subnetId": jsonutils.NewString(subnetId), + } + + resp, err := self.client.DoPost("/apiproxy/v3/deleteSubnet", params) + if err != nil { + return errors.Wrap(err, "SRegion.DeleteNetwork.DoPost") + } + + var statusCode int + err = resp.Unmarshal(&statusCode, "statusCode") + if statusCode != 800 { + return errors.Wrap(fmt.Errorf(strconv.Itoa(statusCode)), "SRegion.DeleteNetwork.Failed") + } + + return nil +} diff --git a/pkg/multicloud/ctyun/order.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/order.go similarity index 100% rename from pkg/multicloud/ctyun/order.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/order.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/project.go new file mode 100644 index 0000000000..9e446011f9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/project.go @@ -0,0 +1,70 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "strings" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +// GET http://ctyun-api-url/apiproxy/v3/ondemand/queryProjectIds +type SProject struct { + Enabled bool `json:"enabled"` + Name string `json:"name"` + Description string `json:"description"` + ID string `json:"id"` +} + +func (self *SProject) GetRegionID() string { + return strings.Split(self.Name, "_")[1] +} + +func (self *SProject) GetHealthStatus() string { + if self.Enabled { + return api.CLOUD_PROVIDER_HEALTH_NORMAL + } + + return api.CLOUD_PROVIDER_HEALTH_SUSPENDED +} + +func (self *SCtyunClient) FetchProjects() ([]SProject, error) { + client, err := NewSCtyunClient( + NewSCtyunClientConfig( + self.accessKey, self.accessSecret, self.options, + ).Debug(self.debug), + ) + if err != nil { + return nil, errors.Wrap(err, "CtyunClient.FetchProjects") + } + projects := make([]SProject, 0) + resp, err := client.DoGet("/apiproxy/v3/ondemand/queryProjectIds", map[string]string{}) + if err != nil { + return nil, errors.Wrap(err, "CtyunClient.FetchProjects.DoGet") + } + + err = resp.Unmarshal(&projects, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "CtyunClient.FetchProjects.Unmarshal") + } + + return projects, err +} + +func (self *SRegion) FetchProjects() ([]SProject, error) { + return self.client.FetchProjects() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/provider/doc.go new file mode 100644 index 0000000000..c49d74341a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/ctyun/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/provider/provider.go new file mode 100644 index 0000000000..356dbcfce7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/provider/provider.go @@ -0,0 +1,199 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/ctyun" +) + +type SCtyunProviderFactory struct { + cloudprovider.SPublicCloudBaseProviderFactory +} + +func (self *SCtyunProviderFactory) GetId() string { + return ctyun.CLOUD_PROVIDER_CTYUN +} + +func (self *SCtyunProviderFactory) GetName() string { + return ctyun.CLOUD_PROVIDER_CTYUN_CN +} + +func (self *SCtyunProviderFactory) IsSupportPrepaidResources() bool { + return true +} + +func (self *SCtyunProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + if len(input.Environment) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "environment") + } + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + output.AccessUrl = input.Environment + return output, nil +} + +func (self *SCtyunProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func (self *SCtyunProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + segs := strings.Split(cfg.Account, "/") + projectId := "" + account := cfg.Account + if len(segs) == 2 { + projectId = segs[1] + account = segs[0] + } + + options := cloudprovider.SCtyunExtraOptions{} + if cfg.Options != nil { + err := cfg.Options.Unmarshal(&options) + if err != nil { + log.Debugf("cfg.Options.Unmarshal %s", err) + } + } + + client, err := ctyun.NewSCtyunClient( + ctyun.NewSCtyunClientConfig( + account, cfg.Secret, &options, + ).ProjectId(projectId).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SCtyunProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SCtyunProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + ret := map[string]string{ + "CTYUN_ACCESS_URL": info.Url, + "CTYUN_ACCESS_KEY": info.Account, + "CTYUN_SECRET": info.Secret, + "CTYUN_REGION": ctyun.CTYUN_DEFAULT_REGION, + } + + options := cloudprovider.SCtyunExtraOptions{} + if info.Options != nil { + err := info.Options.Unmarshal(&options) + if err != nil { + log.Debugf("info.Options.Unmarshal %s", err) + } + } + if len(options.CrmBizId) > 0 { + ret["CTYUN_CRM_BIZ_ID"] = options.CrmBizId + } + + return ret, nil +} + +func init() { + factory := SCtyunProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SCtyunProvider struct { + cloudprovider.SBaseProvider + client *ctyun.SCtyunClient +} + +func (self *SCtyunProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SCtyunProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SCtyunProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SCtyunProvider) GetSysInfo() (jsonutils.JSONObject, error) { + regions := self.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") + info.Add(jsonutils.NewString(ctyun.CTYUN_API_VERSION), "api_version") + return info, nil +} + +func (self *SCtyunProvider) GetVersion() string { + return ctyun.CTYUN_API_VERSION +} + +func (self *SCtyunProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(id) +} + +func (self *SCtyunProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SCtyunProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SCtyunProvider) GetStorageClasses(regionId string) []string { + return []string{ + "STANDARD", "WARM", "COLD", + } +} + +func (self *SCtyunProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (self *SCtyunProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (self *SCtyunProvider) GetCloudRegionExternalIdPrefix() string { + return self.client.GetCloudRegionExternalIdPrefix() +} + +func (self *SCtyunProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/region.go new file mode 100644 index 0000000000..e07bc96ded --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/region.go @@ -0,0 +1,488 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "fmt" + "strconv" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + cloudprovider.SFakeOnPremiseRegion + multicloud.SRegion + multicloud.SNoObjectStorageRegion + + client *SCtyunClient + storageCache *SStoragecache + + // + initialled bool + + RegionName string + Description string `json:"description"` + ID string `json:"id"` + ParentRegionID string `json:"parent_region_id"` + Type string `json:"type"` + + izones []cloudprovider.ICloudZone + ivpcs []cloudprovider.ICloudVpc +} + +func (self *SRegion) fetchIVpcs() error { + vpcs, err := self.GetVpcs() + if err != nil { + return errors.Wrap(err, "SRegion.fetchIVpcs") + } + + self.ivpcs = make([]cloudprovider.ICloudVpc, 0) + for i := range vpcs { + vpc := vpcs[i] + vpc.region = self + self.ivpcs = append(self.ivpcs, &vpc) + } + + return nil +} + +func (self *SRegion) fetchInfrastructure() error { + if err := self.fetchIVpcs(); err != nil { + return err + } + + for i := 0; i < len(self.ivpcs); i += 1 { + vpc := self.ivpcs[i].(*SVpc) + wire := SWire{region: self, vpc: vpc} + vpc.addWire(&wire) + + for j := 0; j < len(self.izones); j += 1 { + zone := self.izones[j].(*SZone) + zone.addWire(&wire) + } + + vpc.fetchNetworks() + } + return nil +} + +func (self *SRegion) GetVpcs() ([]SVpc, error) { + vpcs := make([]SVpc, 0) + params := map[string]string{ + "regionId": self.GetId(), + } + + resp, err := self.client.DoGet("/apiproxy/v3/getVpcs", params) + if err != nil { + return nil, err + } + + err = resp.Unmarshal(&vpcs, "returnObj") + if err != nil { + return nil, err + } + + return vpcs, nil +} + +func (self *SRegion) CreateVpc(name, cidr string) (*SVpc, error) { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "name": jsonutils.NewString(name), + "cidr": jsonutils.NewString(cidr), + } + resp, err := self.client.DoPost("/apiproxy/v3/createVPC", params) + if err != nil { + return nil, err + } + + vpc := &SVpc{} + err = resp.Unmarshal(vpc, "returnObj") + if err != nil { + return nil, err + } + + vpc.ResVpcID, _ = resp.GetString("returnObj", "id") + vpc.region = self + return vpc, nil +} + +func (self *SRegion) GetClient() *SCtyunClient { + return self.client +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return self.GetSecurityGroupDetails(secgroupId) +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + segroups, err := self.GetSecurityGroups(opts.VpcId) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetISecurityGroupByName.GetSecurityGroups") + } + + for i := range segroups { + if segroups[i].Name == opts.Name { + return &segroups[i], nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetISecurityGroupByName.GetSecurityGroups") +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + secgroup, err := self.CreateSecurityGroup(conf.VpcId, conf.Name) + if err != nil { + return nil, errors.Wrap(err, "Region.CreateISecurityGroup") + } + + return secgroup, nil +} + +func (self *SRegion) GetId() string { + return self.ID +} + +func (self *SRegion) GetName() string { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_CTYUN_CN, self.RegionName) +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_CTYUN_EN, self.RegionName) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.ID) +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) Refresh() error { + return nil +} + +func (self *SRegion) IsEmulated() bool { + return false +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + if info, ok := LatitudeAndLongitude[self.ID]; ok { + return info + } + return cloudprovider.SGeographicInfo{} +} + +// http://ctyun-api-url/apiproxy/v3/order/getZoneConfig +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if self.izones == nil || self.initialled == false { + var err error + err = self.fetchInfrastructure() + if err != nil { + return nil, err + } + + self.initialled = true + } + return self.izones, nil +} + +// http://ctyun-api-url/apiproxy/v3/getVpcs +// http://ctyun-api-url/apiproxy/v3/getVpcs +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + if self.ivpcs == nil || self.initialled == false { + err := self.fetchInfrastructure() + if err != nil { + return nil, err + } + + self.initialled = true + } + return self.ivpcs, nil +} + +// http://ctyun-api-url/apiproxy/v3/ondemand/queryIps +func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, err := self.GetEips() + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetIEips.GetEips") + } + + ieips := make([]cloudprovider.ICloudEIP, len(eips)) + for i := range eips { + ieips[i] = &eips[i] + } + + return ieips, nil +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + ivpcs, err := self.GetIVpcs() + if err != nil { + return nil, err + } + for i := 0; i < len(ivpcs); i += 1 { + if ivpcs[i].GetGlobalId() == id { + return ivpcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { + return self.GetEip(id) +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + return self.GetVMById(id) +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return self.GetDisk(id) +} + +func (self *SRegion) DeleteSecurityGroup(securityGroupId string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "securityGroupId": jsonutils.NewString(securityGroupId), + } + + resp, err := self.client.DoPost("/apiproxy/v3/deleteSecurityGroup", params) + if err != nil { + return errors.Wrap(err, "SRegion.DeleteSecurityGroup.DoPost") + } + + var statusCode int + err = resp.Unmarshal(&statusCode, "statusCode") + if statusCode != 800 { + return errors.Wrap(fmt.Errorf(strconv.Itoa(statusCode)), "SRegion.DeleteSecurityGroup.JobFailed") + } + + return nil +} + +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + return self.CreateVpc(opts.NAME, opts.CIDR) +} + +func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + zones, err := self.GetIZones() + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateEIP.GetIZones") + } + + if len(zones) == 0 { + return nil, errors.Wrap(errors.ErrNotFound, "SRegion.CreateEIP.GetIZones") + } + + return self.CreateEip(zones[0].GetId(), eip.Name, strconv.Itoa(eip.BandwidthMbps), "PER", eip.ChargeType) +} + +func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + return []cloudprovider.ICloudSnapshot{}, nil +} + +func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) CreateSnapshotPolicy(*cloudprovider.SnapshotPolicyInput) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (self *SRegion) UpdateSnapshotPolicy(*cloudprovider.SnapshotPolicyInput, string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) DeleteSnapshotPolicy(policyId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { + polices, err := self.GetDiskBackupPolices() + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetISnapshotPolicies.GetDiskBackupPolices") + } + + ipolices := make([]cloudprovider.ICloudSnapshotPolicy, len(polices)) + for i := range polices { + ipolices[i] = &polices[i] + } + + return ipolices, nil +} + +func (self *SRegion) GetISnapshotPolicyById(snapshotPolicyId string) (cloudprovider.ICloudSnapshotPolicy, error) { + return self.GetDiskBackupPolicy(snapshotPolicyId) +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + return []cloudprovider.ICloudStoragecache{storageCache}, nil +} + +func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + if storageCache.GetGlobalId() == id { + return storageCache, nil + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetProvider() string { + return api.CLOUD_PROVIDER_CTYUN +} + +func (self *SRegion) GetInstances(instanceId string) ([]SInstance, error) { + params := map[string]string{ + "regionId": self.GetId(), + } + + if len(instanceId) > 0 { + params["instanceId"] = instanceId + } + + resp, err := self.client.DoGet("/apiproxy/v3/ondemand/queryVMs", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetInstances.DoGet") + } + + ret := make([]SInstance, 0) + err = resp.Unmarshal(&ret, "returnObj", "servers") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetInstances.Unmarshal") + } + + return ret, nil +} + +func (self *SRegion) GetInstanceFlavors() ([]FlavorObj, error) { + params := map[string]string{ + "regionId": self.GetId(), + } + + resp, err := self.client.DoGet("/apiproxy/v3/order/getFlavors", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetInstanceFlavors.DoGet") + } + + ret := make([]FlavorObj, 0) + err = resp.Unmarshal(&ret, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetInstanceFlavors.Unmarshal") + } + + return ret, nil +} + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/pkg/multicloud/ctyun/secrules.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/secrules.go similarity index 100% rename from pkg/multicloud/ctyun/secrules.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/secrules.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/securitygroup.go new file mode 100644 index 0000000000..8ae88f4b1a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/securitygroup.go @@ -0,0 +1,364 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "fmt" + "net" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + apis "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSecurityGroup struct { + multicloud.SSecurityGroup + CtyunTags + region *SRegion + + ResSecurityGroupID string `json:"resSecurityGroupId"` + Name string `json:"name"` + AccountID string `json:"accountId"` + UserID string `json:"userId"` + RegionID string `json:"regionId"` + ZoneID string `json:"zoneId"` + VpcID string `json:"vpcId"` + CreateDate int64 `json:"createDate"` + Status int64 `json:"status"` +} + +func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error { + return self.DeleteSecurityGroupRule(secGrpRuleId) +} + +func (self *SRegion) AddSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error { + direction := "" + if rule.Direction == secrules.SecurityRuleIngress { + direction = "ingress" + } else { + direction = "egress" + } + + protocal := rule.Protocol + if rule.Protocol == secrules.PROTO_ANY { + protocal = "" + } + + // imcp协议默认为any + if rule.Protocol == secrules.PROTO_ICMP { + return self.addSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String()) + } + + if len(rule.Ports) > 0 { + for _, port := range rule.Ports { + portStr := fmt.Sprintf("%d", port) + err := self.addSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String()) + if err != nil { + return err + } + } + } else { + portStart := fmt.Sprintf("%d", rule.PortStart) + portEnd := fmt.Sprintf("%d", rule.PortEnd) + err := self.addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String()) + if err != nil { + return err + } + } + + return nil +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + for _, r := range append(inDels, outDels...) { + err := self.region.delSecurityGroupRule(r.ExternalId) + if err != nil { + return errors.Wrapf(err, "delSecurityGroupRule(%s)", r.ExternalId) + } + } + for _, r := range append(inAdds, outAdds...) { + err := self.region.AddSecurityGroupRules(self.ResSecurityGroupID, r) + if err != nil { + return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String()) + } + } + return nil +} + +func (self *SSecurityGroup) Delete() error { + return self.region.DeleteSecurityGroup(self.GetId()) +} + +func (self *SSecurityGroup) GetId() string { + return self.ResSecurityGroupID +} + +func (self *SSecurityGroup) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.ResSecurityGroupID +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.GetId() +} + +func (self *SSecurityGroup) GetStatus() string { + return "" +} + +func (self *SSecurityGroup) Refresh() error { + if new, err := self.region.GetSecurityGroupDetails(self.GetId()); err != nil { + return err + } else { + return jsonutils.Update(self, new) + } +} + +func (self *SSecurityGroup) IsEmulated() bool { + return false +} + +func (self *SSecurityGroup) GetDescription() string { + return "" +} + +// 判断是否兼容云端安全组规则 +func compatibleSecurityGroupRule(r SSecurityGroupRule) bool { + // 忽略了源地址是安全组的规则 + if len(r.RemoteGroupId) > 0 { + return false + } + + // 忽略IPV6 + if r.Ethertype == "IPv6" { + return false + } + + return true +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + _rules, err := self.region.GetSecurityGroupRules(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "SSecurityGroup.GetRules.GetSecurityGroupRules") + } + + rules := make([]cloudprovider.SecurityRule, 0) + for _, r := range _rules { + if !compatibleSecurityGroupRule(r) { + continue + } + + rule, err := self.GetSecurityRule(r) + if err != nil { + return rules, err + } + + rules = append(rules, rule) + } + + return rules, nil +} + +func (self *SSecurityGroup) GetSecurityRule(remoteRule SSecurityGroupRule) (cloudprovider.SecurityRule, error) { + var err error + var direction secrules.TSecurityRuleDirection + if remoteRule.Direction == "ingress" { + direction = secrules.SecurityRuleIngress + } else { + direction = secrules.SecurityRuleEgress + } + + protocol := secrules.PROTO_ANY + if remoteRule.Protocol != "" { + protocol = remoteRule.Protocol + } + + var portStart int + var portEnd int + if protocol == secrules.PROTO_ICMP { + portStart = -1 + portEnd = -1 + } else { + portStart = int(remoteRule.PortRangeMin) + portEnd = int(remoteRule.PortRangeMax) + } + + ipNet := &net.IPNet{} + if len(remoteRule.RemoteIPPrefix) > 0 { + _, ipNet, err = net.ParseCIDR(remoteRule.RemoteIPPrefix) + } else { + _, ipNet, err = net.ParseCIDR("0.0.0.0/0") + } + + if err != nil { + return cloudprovider.SecurityRule{}, err + } + + rule := cloudprovider.SecurityRule{ + ExternalId: remoteRule.ID, + SecurityRule: secrules.SecurityRule{ + Priority: 1, + Action: secrules.SecurityRuleAllow, + IPNet: ipNet, + Protocol: protocol, + Direction: direction, + PortStart: portStart, + PortEnd: portEnd, + Ports: nil, + Description: remoteRule.Description, + }, + } + + err = rule.ValidateRule() + return rule, err +} + +func (self *SSecurityGroup) GetVpcId() string { + return apis.NORMAL_VPC_ID +} + +func (self *SRegion) GetSecurityGroupDetails(groupId string) (*SSecurityGroup, error) { + params := map[string]string{ + "regionId": self.GetId(), + "securityGroupId": groupId, + } + + resp, err := self.client.DoGet("/apiproxy/v3/querySecurityGroupDetail", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetSecurityGroupDetails") + } + + ret := &SSecurityGroup{} + err = resp.Unmarshal(&ret, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetSecurityGroupDetails.Unmarshal") + } + + ret.region = self + return ret, nil +} + +func (self *SRegion) GetSecurityGroups(vpcId string) ([]SSecurityGroup, error) { + params := map[string]string{ + "regionId": self.GetId(), + } + + if len(vpcId) > 0 { + params["vpcId"] = vpcId + } + + resp, err := self.client.DoGet("/apiproxy/v3/getSecurityGroups", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetSecurityGroups") + } + + ret := make([]SSecurityGroup, 0) + err = resp.Unmarshal(&ret, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetSecurityGroups.Unmarshal") + } + + for i := range ret { + ret[i].region = self + } + + return ret, nil +} + +func (self *SRegion) CreateSecurityGroup(vpcId, name string) (*SSecurityGroup, error) { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "name": jsonutils.NewString(name), + } + + if len(vpcId) > 0 && vpcId != apis.NORMAL_VPC_ID { + params["vpcId"] = jsonutils.NewString(vpcId) + } + + resp, err := self.client.DoPost("/apiproxy/v3/createSecurityGroup", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.DoPost") + } + + secgroupId, err := resp.GetString("returnObj", "id") + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.GetSecgroupId") + } + + secgroup, err := self.GetSecurityGroupDetails(secgroupId) + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateSecurityGroup.GetISecurityGroupById") + } + + secgroup.region = self + return secgroup, nil +} + +func (self *SRegion) DeleteSecurityGroupRule(securityGroupRuleId string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "securityGroupRuleId": jsonutils.NewString(securityGroupRuleId), + } + + _, err := self.client.DoPost("/apiproxy/v3/deleteSecurityGroupRule", params) + if err != nil { + return errors.Wrap(err, "SRegion.DeleteSecurityGroupRule.DoPost") + } + + return err +} + +func (self *SRegion) addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error { + secgroupObj := jsonutils.NewDict() + secgroupObj.Add(jsonutils.NewString(self.GetId()), "regionId") + secgroupObj.Add(jsonutils.NewString(secGrpId), "securityGroupId") + secgroupObj.Add(jsonutils.NewString(direction), "direction") + secgroupObj.Add(jsonutils.NewString(ipNet), "remoteIpPrefix") + secgroupObj.Add(jsonutils.NewString("IPv4"), "ethertype") + // 端口为空或者1-65535 + if len(portStart) > 0 && portStart != "0" && portStart != "-1" { + secgroupObj.Add(jsonutils.NewString(portStart), "portRangeMin") + } + if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" { + secgroupObj.Add(jsonutils.NewString(portEnd), "portRangeMax") + } + if len(protocol) > 0 { + secgroupObj.Add(jsonutils.NewString(protocol), "protocol") + } + + params := map[string]jsonutils.JSONObject{ + "jsonStr": secgroupObj, + } + + resp, err := self.client.DoPost("/apiproxy/v3/createSecurityGroupRule", params) + if err != nil { + return errors.Wrap(err, "SRegion.DoPost") + } + + rule := SSecurityGroupRule{} + err = resp.Unmarshal(&rule, "returnObj") + if err != nil { + return errors.Wrap(err, "SRegion.Unmarshal") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/storage.go new file mode 100644 index 0000000000..7e40d9f2e9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/storage.go @@ -0,0 +1,164 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "fmt" + "strconv" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var StorageTypes = []string{ + api.STORAGE_CTYUN_SAS, + api.STORAGE_CTYUN_SATA, + api.STORAGE_CTYUN_SSD, +} + +type SStorage struct { + multicloud.SStorageBase + CtyunTags + zone *SZone + storageType string +} + +func (self *SStorage) GetId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) +} + +func (self *SStorage) GetName() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetGlobalId() string { + return self.GetId() +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) Refresh() error { + return nil +} + +func (self *SStorage) IsEmulated() bool { + return true +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.zone.region.getStoragecache() +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +// http://ctyun-api-url/apiproxy/v3/ondemand/queryVolumes +// http://ctyun-api-url/apiproxy/v3/queryDataDisks +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := self.zone.region.GetDisks() + if err != nil { + return nil, err + } + + // 按storage type 过滤出disk + filtedDisks := make([]SDisk, 0) + for i := range disks { + disk := disks[i] + if disk.VolumeType == self.storageType && disk.AvailabilityZone == self.zone.GetId() { + filtedDisks = append(filtedDisks, disk) + } + } + + idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) + for i := 0; i < len(filtedDisks); i += 1 { + filtedDisks[i].storage = self + idisks[i] = &filtedDisks[i] + } + return idisks, nil +} + +func (self *SStorage) GetStorageType() string { + return self.storageType +} + +func (self *SStorage) GetMediumType() string { + if self.storageType == api.STORAGE_CTYUN_SSD { + return api.DISK_TYPE_SSD + } else { + return api.DISK_TYPE_ROTATE + } +} + +func (self *SStorage) GetCapacityMB() int64 { + return 0 +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + disk, err := self.zone.region.CreateDisk(self.zone.GetId(), conf.Name, self.GetStorageType(), strconv.Itoa(conf.SizeGb)) + if err != nil { + return nil, errors.Wrap(err, "Storage.CreateIDisk.CreateDisk") + } + + return disk, nil +} + +func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + if len(idStr) == 0 { + log.Debugf("GetIDiskById disk id should not be empty") + return nil, cloudprovider.ErrNotFound + } + + if disk, err := self.zone.region.GetDisk(idStr); err != nil { + return nil, err + } else { + disk.storage = self + return disk, nil + } +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} + +func (self *SRegion) getStoragecache() *SStoragecache { + if self.storageCache == nil { + self.storageCache = &SStoragecache{region: self} + } + return self.storageCache +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/storagecache.go new file mode 100644 index 0000000000..94ffe6c5dd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/storagecache.go @@ -0,0 +1,105 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "context" + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStoragecache struct { + multicloud.SResourceBase + CtyunTags + region *SRegion +} + +func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, update func(progress float32)) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func GetBucketName(regionId string, imageId string) string { + return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), imageId) +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) +} + +func (self *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) +} + +func (self *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, 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) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + imagesSelf, err := self.region.GetImages(ImageOwnerSelf) + if err != nil { + return nil, errors.Wrapf(err, "GetImages") + } + ret := []cloudprovider.ICloudImage{} + for i := range imagesSelf { + imagesSelf[i].storageCache = self + ret = append(ret, &imagesSelf[i]) + } + return ret, nil +} + +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + image, err := self.region.GetImage(extId) + if err != nil { + return nil, errors.Wrap(err, "SStoragecache.GetIImageById.GetImage") + } + + image.storageCache = self + return image, err +} + +func (self *SStoragecache) GetPath() string { + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/tag_base.go new file mode 100644 index 0000000000..9ae9e7c6b3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/tag_base.go @@ -0,0 +1,36 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type CtyunTags struct { +} + +func (self *CtyunTags) GetTags() (map[string]string, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") +} + +func (self *CtyunTags) GetSysTags() map[string]string { + return nil +} + +func (self *CtyunTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/vpc.go new file mode 100644 index 0000000000..e99ad95587 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/vpc.go @@ -0,0 +1,232 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + CtyunTags + + region *SRegion + + iwires []cloudprovider.ICloudWire + secgroups []cloudprovider.ICloudSecurityGroup + + ResVpcID string `json:"resVpcId"` + Name string `json:"name"` + CIDR string `json:"cidr"` + ZoneID string `json:"zoneId"` + ZoneName string `json:"zoneName"` + VpcStatus string `json:"vpcStatus"` + RegionID string `json:"regionId"` + CreateDate int64 `json:"createDate"` +} + +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.ResVpcID +} + +func (self *SVpc) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.ResVpcID +} + +func (self *SVpc) GetGlobalId() string { + return self.GetId() +} + +func (self *SVpc) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} + +func (self *SVpc) Refresh() error { + new, err := self.region.GetVpc(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SVpc) IsEmulated() bool { + return false +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetIsDefault() bool { + return false +} + +func (self *SVpc) GetCidrBlock() string { + return self.CIDR +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + if self.iwires == nil { + err := self.fetchNetworks() + if err != nil { + return nil, err + } + } + return self.iwires, nil +} + +// http://ctyun-api-url/apiproxy/v3/getSecurityGroupRules +// http://ctyun-api-url/apiproxy/v3/getSecurityGroups +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) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + rts := []cloudprovider.ICloudRouteTable{} + return rts, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) Delete() error { + return self.region.DeleteVpc(self.GetId()) +} + +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) fetchSecurityGroups() error { + secgroups, err := self.region.GetSecurityGroups("") + if err != nil { + return err + } + + self.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) + for i := 0; i < len(secgroups); i++ { + self.secgroups[i] = &secgroups[i] + } + + return nil +} + +func (self *SVpc) getWireByRegionId(regionId string) *SWire { + if len(regionId) == 0 { + return nil + } + + for i := 0; i < len(self.iwires); i++ { + wire := self.iwires[i].(*SWire) + + if wire.region.GetId() == regionId { + return wire + } + } + + return nil +} + +func (self *SVpc) fetchNetworks() error { + networks, err := self.region.GetNetwroks(self.GetId()) + if err != nil { + return err + } + + if len(networks) == 0 { + self.iwires = []cloudprovider.ICloudWire{&SWire{region: self.region, vpc: self}} + return nil + } + + for i := 0; i < len(networks); i += 1 { + wire := self.getWireByRegionId(self.region.GetId()) + networks[i].wire = wire + wire.addNetwork(&networks[i]) + } + + return nil +} + +func (self *SRegion) GetVpc(vpcId string) (*SVpc, error) { + params := map[string]string{ + "vpcId": vpcId, + "regionId": self.GetId(), + } + + vpc := &SVpc{} + resp, err := self.client.DoGet("/apiproxy/v3/queryVPCDetail", params) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetVpc.DoGet") + } + + if id, _ := resp.GetString("returnObj", "resVpcId"); len(id) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetVpc.GetID") + } + + err = resp.Unmarshal(vpc, "returnObj") + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetVpc.Unmarshal") + } + + vpc.region = self + return vpc, nil +} + +func (self *SRegion) DeleteVpc(vpcId string) error { + params := map[string]jsonutils.JSONObject{ + "regionId": jsonutils.NewString(self.GetId()), + "vpcId": jsonutils.NewString(vpcId), + } + + _, err := self.client.DoPost("/apiproxy/v3/deleteVPC", params) + if err != nil { + return errors.Wrap(err, "SRegion.DeleteVpc.DoPost") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/wire.go new file mode 100644 index 0000000000..6adaf20bc1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/wire.go @@ -0,0 +1,141 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + CtyunTags + region *SRegion + vpc *SVpc + + inetworks []cloudprovider.ICloudNetwork +} + +func (self *SWire) GetId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) +} + +func (self *SWire) GetName() string { + return self.GetId() +} + +func (self *SWire) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SWire) Refresh() error { + return nil +} + +func (self *SWire) IsEmulated() bool { + return true +} + +// http://ctyun-api-url/apiproxy/v3/queryVPCDetail +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return nil +} + +// http://ctyun-api-url/apiproxy/v3/getSubnets +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 getDefaultGateWay(cidr string) (string, error) { + pref, err := netutils.NewIPV4Prefix(cidr) + if err != nil { + return "", errors.Wrap(err, "getDefaultGateWay.NewIPV4Prefix") + } + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String(), nil +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + var ZoneId string + if len(self.inetworks) > 0 { + ZoneId = self.inetworks[0].(*SNetwork).ZoneID + } else { + if len(self.region.izones) > 0 { + ZoneId = self.region.izones[0].GetId() + } else { + return nil, fmt.Errorf("SWire.CreateINetwork region %s zone is empty", self.region.GetName()) + } + } + network, err := self.region.CreateNetwork(self.vpc.GetId(), ZoneId, opts.Name, opts.Cidr, "true") + if err != nil { + return nil, errors.Wrap(err, "SWire.CreateINetwork.CreateNetwork") + } + + return network, 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.GetId() { + find = true + break + } + } + if !find { + self.inetworks = append(self.inetworks, network) + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/zone.go new file mode 100644 index 0000000000..2bc6149f9a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ctyun/zone.go @@ -0,0 +1,151 @@ +// Copyright 2019 Yunion +// +// 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 ctyun + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SZone struct { + multicloud.SResourceBase + CtyunTags + region *SRegion + host *SHost + + iwires []cloudprovider.ICloudWire + istorages []cloudprovider.ICloudStorage + /* 支持的磁盘种类集合 */ + storageTypes []string + + RegionID string `json:"regionId"` + ZoneID string `json:"zoneId"` + ZoneName string `json:"zoneName"` + ZoneType string `json:"zoneType"` +} + +func getZoneGlobalId(region *SRegion, zoneId string) string { + return fmt.Sprintf("%s/%s", region.GetGlobalId(), zoneId) +} + +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) GetId() string { + return self.ZoneID +} + +func (self *SZone) GetName() string { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_CTYUN_CN, self.ZoneID) +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(self.ZoneID) + return table +} + +func (self *SZone) GetGlobalId() string { + return getZoneGlobalId(self.region, self.GetId()) +} + +func (self *SZone) GetStatus() string { + return "enable" +} + +func (self *SZone) Refresh() error { + return nil +} + +func (self *SZone) IsEmulated() bool { + return false +} + +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 { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "fetchStorages") + } + } + return self.istorages, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "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) getHost() *SHost { + if self.host == nil { + self.host = &SHost{zone: self} + } + return self.host +} + +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) getStorageType() { + if len(self.storageTypes) == 0 { + self.storageTypes = StorageTypes + } +} + +func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { + return self.iwires, nil +} diff --git a/pkg/multicloud/dbinstance_account_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_account_base.go similarity index 96% rename from pkg/multicloud/dbinstance_account_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_account_base.go index dc5ad83f95..700138eccb 100644 --- a/pkg/multicloud/dbinstance_account_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_account_base.go @@ -30,8 +30,8 @@ package multicloud import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SDBInstanceAccountBase struct { diff --git a/pkg/multicloud/dbinstance_backup_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_backup_base.go similarity index 93% rename from pkg/multicloud/dbinstance_backup_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_backup_base.go index 93b942048c..b5f5b0a72f 100644 --- a/pkg/multicloud/dbinstance_backup_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_backup_base.go @@ -17,8 +17,8 @@ package multicloud import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SDBInstanceBackupBase struct { diff --git a/pkg/multicloud/dbinstance_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_base.go similarity index 98% rename from pkg/multicloud/dbinstance_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_base.go index a979572c69..7a57d85a4a 100644 --- a/pkg/multicloud/dbinstance_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_base.go @@ -19,7 +19,7 @@ import ( "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/billing" ) diff --git a/pkg/multicloud/dbinstance_database_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_database_base.go similarity index 95% rename from pkg/multicloud/dbinstance_database_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_database_base.go index a7e4852ca4..52742ec896 100644 --- a/pkg/multicloud/dbinstance_database_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/dbinstance_database_base.go @@ -17,7 +17,7 @@ package multicloud import ( "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SDBInstanceDatabaseBase struct { diff --git a/pkg/multicloud/disk_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/disk_base.go similarity index 100% rename from pkg/multicloud/disk_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/disk_base.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/doc.go new file mode 100644 index 0000000000..813eb80570 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 multicloud // import "yunion.io/x/cloudmux/pkg/multicloud" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/client.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/client.go new file mode 100644 index 0000000000..2e7a7fda2f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/client.go @@ -0,0 +1,322 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/hex" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "os" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +const ( + CLOUD_PROVIDER_ECLOUD = api.CLOUD_PROVIDER_ECLOUD + CLOUD_PROVIDER_ECLOUD_CN = "移动云" + CLOUD_PROVIDER_ECLOUD_EN = "Ecloud" + CLOUD_API_VERSION = "2016-12-05" + + ECLOUD_DEFAULT_REGION = "beijing-1" +) + +type SEcloudClientConfig struct { + cpcfg cloudprovider.ProviderConfig + signer ISigner + + debug bool +} + +func NewEcloudClientConfig(signer ISigner) *SEcloudClientConfig { + cfg := &SEcloudClientConfig{ + signer: signer, + } + return cfg +} + +func (cfg *SEcloudClientConfig) SetCloudproviderConfig(cpcfg cloudprovider.ProviderConfig) *SEcloudClientConfig { + cfg.cpcfg = cpcfg + return cfg +} + +func (cfg *SEcloudClientConfig) SetDebug(debug bool) *SEcloudClientConfig { + cfg.debug = debug + return cfg +} + +type SEcloudClient struct { + *SEcloudClientConfig + + httpClient *http.Client + iregions []cloudprovider.ICloudRegion +} + +func NewEcloudClient(cfg *SEcloudClientConfig) (*SEcloudClient, error) { + httpClient := cfg.cpcfg.AdaptiveTimeoutHttpClient() + return &SEcloudClient{ + SEcloudClientConfig: cfg, + httpClient: httpClient, + }, nil +} + +func (self *SEcloudClient) GetAccessEnv() string { + return api.CLOUD_ACCESS_ENV_ECLOUD_CHINA +} + +func (ec *SEcloudClient) fetchRegions() { + regions := make([]SRegion, 0, len(regionList)) + for id, name := range regionList { + region := SRegion{} + region.ID = id + region.Name = name + region.client = ec + regions = append(regions, region) + } + iregions := make([]cloudprovider.ICloudRegion, len(regions)) + for i := range iregions { + iregions[i] = ®ions[i] + } + ec.iregions = iregions + return +} + +func (ec *SEcloudClient) TryConnect() error { + iregions := ec.GetIRegions() + if len(iregions) == 0 { + return fmt.Errorf("no invalid region for ecloud") + } + _, err := iregions[0].GetIZones() + if err != nil { + return errors.Wrap(err, "try to connect failed") + } + return nil +} + +func (ec *SEcloudClient) GetIRegions() []cloudprovider.ICloudRegion { + if ec.iregions == nil { + ec.fetchRegions() + } + return ec.iregions +} + +func (ec *SEcloudClient) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + iregions := ec.GetIRegions() + for i := range iregions { + if iregions[i].GetGlobalId() == id { + return iregions[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (ec *SEcloudClient) GetRegionById(id string) (*SRegion, error) { + iregions := ec.GetIRegions() + for i := range iregions { + if iregions[i].GetId() == id { + return iregions[i].(*SRegion), nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (ec *SEcloudClient) GetCapabilities() []string { + caps := []string{ + cloudprovider.CLOUD_CAPABILITY_COMPUTE + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_NETWORK + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_EIP + cloudprovider.READ_ONLY_SUFFIX, + } + return caps +} + +func (ec *SEcloudClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + subAccount := cloudprovider.SSubAccount{} + subAccount.Name = ec.cpcfg.Name + subAccount.Account = ec.signer.GetAccessKeyId() + subAccount.HealthStatus = api.CLOUD_PROVIDER_HEALTH_NORMAL + return []cloudprovider.SSubAccount{subAccount}, nil +} + +func (ec *SEcloudClient) GetAccountId() string { + return ec.signer.GetAccessKeyId() +} + +func (ec *SEcloudClient) GetCloudRegionExternalIdPrefix() string { + return CLOUD_PROVIDER_ECLOUD +} + +func (ec *SEcloudClient) completeSingParams(request IRequest) (err error) { + queryParams := request.GetQueryParams() + queryParams["AccessKey"] = ec.signer.GetAccessKeyId() + queryParams["Version"] = request.GetVersion() + queryParams["Timestamp"] = request.GetTimestamp() + queryParams["SignatureMethod"] = ec.signer.GetName() + queryParams["SignatureVersion"] = ec.signer.GetVersion() + queryParams["SignatureNonce"] = ec.signer.GetNonce() + return +} + +func (ec *SEcloudClient) buildStringToSign(request IRequest) string { + signParams := request.GetQueryParams() + queryString := getUrlFormedMap(signParams) + queryString = strings.Replace(queryString, "+", "%20", -1) + queryString = strings.Replace(queryString, "*", "%2A", -1) + queryString = strings.Replace(queryString, "%7E", "~", -1) + shaString := sha256.Sum256([]byte(queryString)) + summaryQuery := hex.EncodeToString(shaString[:]) + serverPath := strings.Replace(request.GetServerPath(), "/", "%2F", -1) + return fmt.Sprintf("%s\n%s\n%s", request.GetMethod(), serverPath, summaryQuery) +} + +func (ec *SEcloudClient) doGet(ctx context.Context, r IRequest, result interface{}) error { + r.SetMethod("GET") + data, err := ec.request(ctx, r) + if err != nil { + return err + } + return data.Unmarshal(result) +} + +func (ec *SEcloudClient) doList(ctx context.Context, r IRequest, result interface{}) error { + r.SetMethod("GET") + // TODO Paging query + data, err := ec.request(ctx, r) + if err != nil { + return err + } + var ( + datas *jsonutils.JSONArray + ok bool + ) + + if datas, ok = data.(*jsonutils.JSONArray); !ok { + if !data.Contains("content") { + return ErrMissKey{ + Key: "content", + Jo: data, + } + } + content, _ := data.Get("content") + datas, ok = content.(*jsonutils.JSONArray) + if !ok { + return fmt.Errorf("The return result should be an array, but:\n%s", content) + } + } + return datas.Unmarshal(result) +} + +func (ec *SEcloudClient) request(ctx context.Context, r IRequest) (jsonutils.JSONObject, error) { + jrbody, err := ec.doRequest(ctx, r) + if err != nil { + return nil, err + } + return r.ForMateResponseBody(jrbody) +} + +func (ec *SEcloudClient) doRequest(ctx context.Context, r IRequest) (jsonutils.JSONObject, error) { + // sign + ec.completeSingParams(r) + signature := ec.signer.Sign(ec.buildStringToSign(r), "BC_SIGNATURE&") + query := r.GetQueryParams() + query["Signature"] = signature + header := r.GetHeaders() + header["Content-Type"] = "application/json" + var urlStr string + port := r.GetPort() + if len(port) > 0 { + urlStr = fmt.Sprintf("%s://%s:%s%s", r.GetScheme(), r.GetEndpoint(), port, r.GetServerPath()) + } else { + urlStr = fmt.Sprintf("%s://%s%s", r.GetScheme(), r.GetEndpoint(), r.GetServerPath()) + } + queryString := getUrlFromedMapUnescaped(r.GetQueryParams()) + if len(queryString) > 0 { + urlStr = urlStr + "?" + queryString + } + resp, err := httputils.Request( + ec.httpClient, + ctx, + httputils.THttpMethod(r.GetMethod()), + urlStr, + convertHeader(header), + r.GetBodyReader(), + ec.debug, + ) + defer httputils.CloseResponse(resp) + if err != nil { + return nil, err + } + rbody, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, errors.Wrap(err, "unable to read body of response") + } + if ec.debug { + fmt.Fprintf(os.Stderr, "Response body: %s\n", string(rbody)) + } + rbody = bytes.TrimSpace(rbody) + + var jrbody jsonutils.JSONObject + if len(rbody) > 0 && (rbody[0] == '{' || rbody[0] == '[') { + var err error + jrbody, err = jsonutils.Parse(rbody) + if err != nil { + return nil, errors.Wrapf(err, "unable to parsing json: %s", rbody) + } + } + return jrbody, nil +} + +type ErrMissKey struct { + Key string + Jo jsonutils.JSONObject +} + +func (mk ErrMissKey) Error() string { + return fmt.Sprintf("The response body should contain the %q key, but it doesn't. It is:\n%s", mk.Key, mk.Jo) +} + +func convertHeader(mh map[string]string) http.Header { + header := http.Header{} + for k, v := range mh { + header.Add(k, v) + } + return header +} + +func getUrlFromedMapUnescaped(source map[string]string) string { + kvs := make([]string, 0, len(source)) + for k, v := range source { + kvs = append(kvs, fmt.Sprintf("%s=%s", k, v)) + } + return strings.Join(kvs, "&") +} + +func getUrlFormedMap(source map[string]string) (urlEncoded string) { + urlEncoder := url.Values{} + for key, value := range source { + urlEncoder.Add(key, value) + } + urlEncoded = urlEncoder.Encode() + return +} diff --git a/pkg/multicloud/ecloud/create_time.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/create_time.go similarity index 100% rename from pkg/multicloud/ecloud/create_time.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/create_time.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/disk.go new file mode 100644 index 0000000000..d9ca17db97 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/disk.go @@ -0,0 +1,276 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "context" + "fmt" + "time" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDisk struct { + storage *SStorage + // TODO instance + + multicloud.SDisk + EcloudTags + multicloud.SBillingBase + SZoneRegionBase + SCreateTime + + ManualAttr SDiskManualAttr + + // 硬盘可挂载主机类型 + AttachServerTypes []string + AvailabilityZone string + BackupId string + Description string + ID string + IsDelete bool + IsShare bool + // 磁盘所在集群的ID + Metadata string + Name string + OperationFlag string + // 硬盘挂在主机ID列表 + ServerId []string + SizeGB int `json:"size"` + SourceVolumeId string + Status string + Type string + VolumeType string + Iscsi bool + ProductType string +} + +type SDiskManualAttr struct { + IsVirtual bool + TempalteId string + ServerId string +} + +func (d *SDisk) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (d *SDisk) GetExpiredAt() time.Time { + return time.Time{} +} + +func (d *SDisk) GetId() string { + return d.ID +} + +func (d *SDisk) GetName() string { + return d.Name +} + +func (d *SDisk) GetGlobalId() string { + return d.ID +} + +func (d *SDisk) GetCreatedAt() time.Time { + return d.SCreateTime.GetCreatedAt() +} + +func (d *SDisk) GetStatus() string { + if d.IsDelete { + // TODO + return "" + } + switch d.Status { + case "available", "in-use": + return api.DISK_READY + case "attaching": + return api.DISK_ATTACHING + case "backing_up": + return api.DISK_BACKUP_STARTALLOC + case "creating", "downloading": + return api.DISK_ALLOCATING + case "deleting": + return api.DISK_DEALLOC + case "uploading": + return api.DISK_SAVING + case "error": + return api.DISK_ALLOC_FAILED + case "error_deleting": + return api.DISK_DEALLOC_FAILED + case "restoring_backup": + return api.DISK_REBUILD + case "detaching": + return api.DISK_DETACHING + case "extending": + return api.DISK_RESIZING + case "error_extending": + return api.DISK_RESIZE_FAILED + case "error_restoring", "unrecognized": + return api.DISK_UNKNOWN + default: + return api.DISK_UNKNOWN + } +} + +func (d *SDisk) Refresh() error { + return nil +} + +func (d *SDisk) IsEmulated() bool { + return false +} + +func (s *SDisk) GetSysTags() map[string]string { + data := map[string]string{} + data["hypervisor"] = api.HYPERVISOR_ECLOUD + return data +} + +func (s *SDisk) GetProjectId() string { + return "" +} + +func (s *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return s.storage, nil +} + +func (s *SDisk) GetDiskFormat() string { + return "vhd" +} + +func (s *SDisk) GetDiskSizeMB() int { + return s.SizeGB * 1024 +} + +func (s *SDisk) GetIsAutoDelete() bool { + if s.GetDiskType() == api.DISK_TYPE_SYS { + return true + } + return false +} + +func (s *SDisk) GetTemplateId() string { + return s.ManualAttr.TempalteId +} + +func (s *SDisk) GetDiskType() string { + if s.ManualAttr.IsVirtual { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +func (s *SDisk) GetFsFormat() string { + return "" +} + +func (s *SDisk) GetIsNonPersistent() bool { + return false +} + +func (s *SDisk) GetDriver() string { + return "scsi" +} + +func (s *SDisk) GetCacheMode() string { + return "none" +} + +func (s *SDisk) GetMountpoint() string { + return "" +} + +func (s *SDisk) GetAccessPath() string { + return "" +} + +func (s *SDisk) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (s *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (s *SDisk) GetISnapshot(id string) (cloudprovider.ICloudSnapshot, error) { + parentId, isSystem := s.ID, false + if s.ManualAttr.IsVirtual { + parentId, isSystem = s.ManualAttr.ServerId, true + } + snapshots, err := s.storage.zone.region.GetSnapshots(id, parentId, isSystem) + if err != nil { + return nil, err + } + if len(snapshots) == 0 { + return nil, cloudprovider.ErrNotFound + } + return &snapshots[0], nil +} + +func (s *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + parentId, isSystem := s.ID, false + if s.ManualAttr.IsVirtual { + parentId, isSystem = s.ManualAttr.ServerId, true + } + snapshots, err := s.storage.zone.region.GetSnapshots("", parentId, isSystem) + if err != nil { + return nil, err + } + isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := range snapshots { + isnapshots[i] = &snapshots[i] + } + return isnapshots, nil +} + +func (s *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { + return []string{}, nil +} + +func (s *SDisk) Resize(ctx context.Context, newSizeMB int64) error { + return cloudprovider.ErrNotImplemented +} + +func (s *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (s *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (s *SRegion) GetDisks() ([]SDisk, error) { + request := NewNovaRequest(NewApiRequest(s.ID, "/api/v2/volume/volume/volume/list/with/server", nil, nil)) + disks := make([]SDisk, 0, 5) + err := s.client.doList(context.Background(), request, &disks) + if err != nil { + return nil, err + } + return disks, nil +} + +func (s *SRegion) GetDisk(id string) (*SDisk, error) { + // TODO + request := NewNovaRequest(NewApiRequest(s.ID, fmt.Sprintf("/api/v2/volume/volume/volumeDetail/%s", id), nil, nil)) + var disk SDisk + err := s.client.doGet(context.Background(), request, &disk) + if err != nil { + return nil, err + } + return &disk, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/doc.go new file mode 100644 index 0000000000..e67df1f572 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 ecloud // import "yunion.io/x/cloudmux/pkg/multicloud/ecloud" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/eip.go new file mode 100644 index 0000000000..2f62c8faf6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/eip.go @@ -0,0 +1,171 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "context" + "fmt" + "time" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SEip struct { + region *SRegion + multicloud.SEipBase + EcloudTags + + BandWidthMbSize int + BandWidthType string + BindType string + // 使用,未使用 + Bound bool + // bandwidthCharge, trafficCharge + ChargeModeEnum string + CreateTime time.Time + Frozen bool + // 备案状态 + IcpStatus string + Id string + IpType string + Ipv6 string + Name string //公网IPv4地址 + NicName string + PortNetworkId string + Region string + ResourceId string + RouterId string + // BINDING, UNBOUND, FROZEN + Status string +} + +func (e *SEip) GetId() string { + return e.Id +} + +func (e *SEip) GetName() string { + return e.Name +} + +func (e *SEip) GetGlobalId() string { + return e.Id +} + +func (e *SEip) GetStatus() string { + switch e.Status { + case "BINDING", "UNBOUND": + return api.EIP_STATUS_READY + default: + return api.EIP_STATUS_UNKNOWN + } +} + +func (e *SEip) Refresh() error { + return cloudprovider.ErrNotImplemented +} + +func (e *SEip) IsEmulated() bool { + return false +} + +func (e *SEip) GetIpAddr() string { + return e.Name +} + +func (e *SEip) GetMode() string { + return api.EIP_MODE_STANDALONE_EIP +} + +func (e *SEip) GetAssociationType() string { + switch e.BindType { + case "vm": + return api.EIP_ASSOCIATE_TYPE_SERVER + case "snat", "dnat": + return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY + case "elb": + return api.EIP_ASSOCIATE_TYPE_LOADBALANCER + default: + return e.BindType + } +} + +func (e *SEip) GetAssociationExternalId() string { + return e.ResourceId +} + +func (e *SEip) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (e *SEip) GetCreatedAt() time.Time { + return e.CreateTime +} + +func (e *SEip) GetExpiredAt() time.Time { + return time.Time{} +} + +func (e *SEip) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (e *SEip) GetBandwidth() int { + return e.BandWidthMbSize +} + +func (e *SEip) GetINetworkId() string { + return e.PortNetworkId +} + +func (e *SEip) GetInternetChargeType() string { + switch e.ChargeModeEnum { + // bandwidthCharge, trafficCharge + case "trafficCharge": + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + case "bandwidthCharge": + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH + default: + return "unknown" + } +} + +func (e *SEip) Associate(conf *cloudprovider.AssociateConfig) error { + return cloudprovider.ErrNotImplemented +} + +func (e *SEip) Dissociate() error { + return cloudprovider.ErrNotImplemented +} + +func (e *SEip) ChangeBandwidth(bw int) error { + return cloudprovider.ErrNotImplemented +} + +func (e *SEip) GetProjectId() string { + return "" +} + +func (r *SRegion) GetEipById(id string) (*SEip, error) { + var eip SEip + request := NewConsoleRequest(r.ID, fmt.Sprintf("/api/v2/floatingIp/getRespWithBw/%s", id), nil, nil) + err := r.client.doGet(context.Background(), request, &eip) + if err != nil { + return nil, err + } + return &eip, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/host.go new file mode 100644 index 0000000000..14b2d663cd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/host.go @@ -0,0 +1,172 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone +} + +func (h *SHost) GetId() string { + return fmt.Sprintf("%s-%s", h.zone.region.client.cpcfg.Id, h.zone.GetId()) +} + +func (h *SHost) GetName() string { + return fmt.Sprintf("%s-%s", h.zone.region.client.cpcfg.Name, h.zone.GetId()) +} + +func (h *SHost) GetGlobalId() string { + return h.GetId() +} + +func (h *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (h *SHost) Refresh() error { + return nil +} + +func (h *SHost) IsEmulated() bool { + return true +} + +func (h *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + zoneRegion := h.zone.Region + vms, err := h.zone.region.GetInstances(zoneRegion) + if err != nil { + return nil, errors.Wrap(err, "SHost.GetVMs") + } + ivms := make([]cloudprovider.ICloudVM, len(vms)) + for i := range vms { + vms[i].host = h + ivms[i] = &vms[i] + } + return ivms, nil +} + +func (h *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := h.zone.region.GetInstanceById(id) + if err != nil { + return nil, err + } + vm.host = h + return vm, nil +} + +func (h *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + return nil, nil +} + +func (h *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + return h.zone.GetIStorages() +} + +func (h *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return h.zone.GetIStorageById(id) +} + +func (h *SHost) GetEnabled() bool { + return true +} + +func (h *SHost) GetHostStatus() string { + return api.HOST_ONLINE +} + +func (h *SHost) GetAccessIp() string { + return "" +} + +func (h *SHost) GetAccessMac() string { + return "" +} + +func (h *SHost) GetSysInfo() jsonutils.JSONObject { + info := jsonutils.NewDict() + info.Add(jsonutils.NewString(api.CLOUD_PROVIDER_ECLOUD), "manufacture") + return info +} + +func (h *SHost) GetSN() string { + return "" +} + +func (h *SHost) GetCpuCount() int { + return 0 +} + +func (h *SHost) GetNodeCount() int8 { + return 0 +} + +func (h *SHost) GetCpuDesc() string { + return "" +} + +func (h *SHost) GetCpuMhz() int { + return 0 +} + +func (h *SHost) GetMemSizeMB() int { + return 0 +} + +func (h *SHost) GetStorageSizeMB() int { + return 0 +} + +func (h *SHost) GetStorageType() string { + return api.DISK_TYPE_HYBRID +} + +func (h *SHost) GetHostType() string { + return api.HOST_TYPE_ECLOUD +} + +func (h *SHost) GetIsMaintenance() bool { + return false +} + +func (h *SHost) GetVersion() string { + return CLOUD_API_VERSION +} + +func (h *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (h *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (h *SRegion) GetVMs() ([]SInstance, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (h *SRegion) GetVMById(vmId string) (*SInstance, error) { + return nil, cloudprovider.ErrNotImplemented +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/image.go new file mode 100644 index 0000000000..65aea2f47e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/image.go @@ -0,0 +1,196 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type SImage struct { + multicloud.SImageBase + EcloudTags + SZoneRegionBase + + storageCache *SStoragecache + imgInfo *imagetools.ImageInfo + + ImageId string + ServerId string + ImageAlias string + Name string + Url string + SrourceImageId string + Status string + SizeMb int `json:"size"` + IsPublic int + CreateTime time.Time + Note string + OsType string + MinDiskGB int `json:"minDisk"` + ImageType string + PublicImageType string + BackupType string + BackupWay string + SnapshotId string + OsName string +} + +func (r *SRegion) GetImage(imageId string) (*SImage, error) { + request := NewNovaRequest(NewApiRequest(r.ID, fmt.Sprintf("/api/v2/image/%s", imageId), nil, nil)) + var image SImage + err := r.client.doGet(context.Background(), request, &image) + if err != nil { + return nil, err + } + return &image, nil +} + +func (r *SRegion) GetImages(isPublic bool) ([]SImage, error) { + if isPublic { + return nil, cloudprovider.ErrNotImplemented + } + request := NewNovaRequest(NewApiRequest(r.ID, "/api/v2/image", nil, nil)) + images := make([]SImage, 0, 5) + err := r.client.doList(context.Background(), request, &images) + if err != nil { + return nil, err + } + return images, nil +} + +func (i *SImage) GetCreatedAt() time.Time { + return i.CreateTime +} + +func (i *SImage) GetId() string { + return i.ImageId +} + +func (i *SImage) GetName() string { + return i.Name +} + +func (i *SImage) GetGlobalId() string { + return i.ImageId +} + +func (i *SImage) GetStatus() string { + switch i.Status { + case "active": + return api.CACHED_IMAGE_STATUS_ACTIVE + case "queued": + return api.CACHED_IMAGE_STATUS_INIT + case "saving": + return api.CACHED_IMAGE_STATUS_SAVING + case "caching": + return api.CACHED_IMAGE_STATUS_CACHING + case "pending_delete": + return api.CACHED_IMAGE_STATUS_DELETING + default: + return api.CACHED_IMAGE_STATUS_UNKNOWN + } +} + +func (i *SImage) Refresh() error { + new, err := i.storageCache.region.GetImage(i.GetId()) + if err != nil { + return err + } + return jsonutils.Update(i, new) +} + +func (i *SImage) IsEmulated() bool { + return false +} + +func (i *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if i.imgInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(i.OsName, "", i.OsType, "", "") + i.imgInfo = &imgInfo + } + return i.imgInfo +} + +func (i *SImage) GetFullOsName() string { + return i.OsName +} + +func (i *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(i.getNormalizedImageInfo().OsType) +} + +func (i *SImage) GetOsArch() string { + return i.getNormalizedImageInfo().OsArch +} + +func (i *SImage) GetOsDist() string { + return i.getNormalizedImageInfo().OsDistro +} + +func (i *SImage) GetOsVersion() string { + return i.getNormalizedImageInfo().OsVersion +} + +func (i *SImage) GetOsLang() string { + return i.getNormalizedImageInfo().OsLang +} + +func (i *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(i.getNormalizedImageInfo().OsBios) +} + +func (i *SImage) GetMinOsDiskSizeGb() int { + return i.MinDiskGB +} + +func (i *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (i *SImage) GetImageFormat() string { + return "" +} + +func (self *SImage) Delete(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return nil +} + +func (self *SImage) GetSizeByte() int64 { + return int64(self.SizeMb) * 1024 * 1024 +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + if self.IsPublic == 1 { + return cloudprovider.ImageTypeSystem + } + return cloudprovider.ImageTypeCustomized +} + +func (self *SImage) GetImageStatus() string { + return cloudprovider.IMAGE_STATUS_ACTIVE +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/instance.go new file mode 100644 index 0000000000..1dc5bd0246 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/instance.go @@ -0,0 +1,528 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/sets" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SNovaRequest struct { + SApiRequest +} + +func NewNovaRequest(ar *SApiRequest) *SNovaRequest { + return &SNovaRequest{ + SApiRequest: *ar, + } +} + +func (nr *SNovaRequest) GetPort() string { + if nr.RegionId == "guangzhou-2" { + return "" + } + return nr.SApiRequest.GetPort() +} + +type SInstance struct { + multicloud.SInstanceBase + EcloudTags + multicloud.SBillingBase + SZoneRegionBase + SCreateTime + + nicComplete bool + host *SHost + image *SImage + + sysDisk cloudprovider.ICloudDisk + dataDisks []cloudprovider.ICloudDisk + + Id string + Name string + Vcpu int + Vmemory int + KeyName string + ImageRef string + ImageName string + ImageOsType string + FlavorRef string + SystemDiskSizeGB int `json:"vdisk"` + SystemDiskId string + ServerType string + ServerVmType string + EcStatus string + BootVolumeType string + Deleted int + Visible bool + Region string + PortDetail []SInstanceNic +} + +func (i *SInstance) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (i *SInstance) GetExpiredAt() time.Time { + return time.Time{} +} + +func (i *SInstance) GetId() string { + return i.Id +} + +func (i *SInstance) GetName() string { + return i.Name +} + +func (i *SInstance) GetHostname() string { + return i.Name +} + +func (i *SInstance) GetGlobalId() string { + return i.GetId() +} + +func (i *SInstance) GetStatus() string { + switch i.EcStatus { + case "active": + return api.VM_RUNNING + case "suspended", "paused": + return api.VM_SUSPEND + case "build", "rebuild", "resize", "verify_resize", "revert_resize", "password": + return api.VM_STARTING + case "reboot", "hard_reboot": + return api.VM_STOPPING + case "stopped", "shutoff": + return api.VM_READY + case "migrating": + return api.VM_MIGRATING + case "backuping": + return api.VM_BACKUP_CREATING + default: + return api.VM_UNKNOWN + } +} + +func (i *SInstance) Refresh() error { + // TODO + return nil +} + +func (i *SInstance) IsEmulated() bool { + return false +} + +func (self *SInstance) GetBootOrder() string { + return "dcn" +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (i *SInstance) GetImage() (*SImage, error) { + if i.image != nil { + return i.image, nil + } + image, err := i.host.zone.region.GetImage(i.ImageRef) + if err != nil { + return nil, err + } + i.image = image + return i.image, nil +} + +func (i *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(i.ImageOsType) +} + +func (i *SInstance) GetFullOsName() string { + image, err := i.GetImage() + if err != nil { + return "" + } + return image.GetFullOsName() +} + +func (i *SInstance) GetBios() cloudprovider.TBiosType { + image, err := i.GetImage() + if err != nil { + return cloudprovider.BIOS + } + return image.GetBios() +} + +func (i *SInstance) GetOsArch() string { + image, err := i.GetImage() + if err != nil { + return "" + } + return image.GetOsArch() +} + +func (i *SInstance) GetOsDist() string { + image, err := i.GetImage() + if err != nil { + return "" + } + return image.GetOsDist() +} + +func (i *SInstance) GetOsVersion() string { + image, err := i.GetImage() + if err != nil { + return "" + } + return image.GetOsVersion() +} + +func (i *SInstance) GetOsLang() string { + image, err := i.GetImage() + if err != nil { + return "" + } + return image.GetOsLang() +} + +func (i *SInstance) GetMachine() string { + return "pc" +} + +func (i *SInstance) GetInstanceType() string { + return i.FlavorRef +} + +func (in *SInstance) GetProjectId() string { + return "" +} + +func (in *SInstance) GetIHost() cloudprovider.ICloudHost { + return in.host +} + +func (in *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + if in.sysDisk == nil { + in.fetchSysDisk() + } + if in.dataDisks == nil { + err := in.fetchDataDisks() + if err != nil { + return nil, err + } + } + return append([]cloudprovider.ICloudDisk{in.sysDisk}, in.dataDisks...), nil +} + +func (in *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + if !in.nicComplete { + err := in.makeNicComplete() + if err != nil { + return nil, errors.Wrap(err, "unable to make nics complete") + } + in.nicComplete = true + } + inics := make([]cloudprovider.ICloudNic, len(in.PortDetail)) + for i := range in.PortDetail { + in.PortDetail[i].instance = in + inics[i] = &in.PortDetail[i] + } + return inics, nil +} + +func (in *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + if !in.nicComplete { + err := in.makeNicComplete() + if err != nil { + return nil, errors.Wrap(err, "unable to make nics complete") + } + in.nicComplete = true + } + var eipId string + for i := range in.PortDetail { + if len(in.PortDetail[i].IpId) > 0 { + eipId = in.PortDetail[i].IpId + break + } + } + if len(eipId) == 0 { + return nil, nil + } + return in.host.zone.region.GetEipById(eipId) +} + +func (in *SInstance) GetSecurityGroupIds() ([]string, error) { + if !in.nicComplete { + err := in.makeNicComplete() + if err != nil { + return nil, errors.Wrap(err, "unable to make nics complete") + } + in.nicComplete = true + } + ret := sets.NewString() + for i := range in.PortDetail { + for _, group := range in.PortDetail[i].SecurityGroups { + ret.Insert(group.Id) + } + } + return ret.UnsortedList(), nil +} + +func (in *SInstance) GetVcpuCount() int { + return in.Vcpu +} + +func (in *SInstance) GetVmemSizeMB() int { + return in.Vmemory +} + +func (in *SInstance) AssignSecurityGroup(id string) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) SetSecurityGroups(ids []string) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) GetHypervisor() string { + return api.HYPERVISOR_ECLOUD +} + +func (in *SInstance) StartVM(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + return errors.ErrNotImplemented +} + +func (in *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + url, err := in.host.zone.region.GetInstanceVNCUrl(in.GetId()) + if err != nil { + return nil, err + } + ret := &cloudprovider.ServerVncOutput{ + Url: url, + Protocol: "ecloud", + InstanceId: in.GetId(), + Hypervisor: api.HYPERVISOR_ECLOUD, + } + return ret, nil +} + +func (in *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) GetError() error { + return nil +} + +func (in *SInstance) fetchSysDisk() { + storage, _ := in.host.zone.getStorageByType(api.STORAGE_ECLOUD_SYSTEM) + disk := SDisk{ + storage: storage, + ManualAttr: SDiskManualAttr{ + IsVirtual: true, + TempalteId: in.ImageRef, + ServerId: in.Id, + }, + SCreateTime: in.SCreateTime, + SZoneRegionBase: in.SZoneRegionBase, + ServerId: []string{in.Id}, + IsShare: false, + IsDelete: false, + SizeGB: in.SystemDiskSizeGB, + ID: in.SystemDiskId, + Name: fmt.Sprintf("%s-root", in.Name), + Status: "in-use", + Type: api.STORAGE_ECLOUD_SYSTEM, + } + in.sysDisk = &disk + return +} + +func (in *SInstance) fetchDataDisks() error { + request := NewNovaRequest(NewApiRequest(in.host.zone.region.ID, "/api/v2/volume/volume/mount/list", + map[string]string{"serverId": in.Id}, nil)) + disks := make([]SDisk, 0, 5) + err := in.host.zone.region.client.doList(context.Background(), request, &disks) + if err != nil { + return err + } + idisks := make([]cloudprovider.ICloudDisk, len(disks)) + for i := range idisks { + storageType := disks[i].Type + storage, err := in.host.zone.getStorageByType(storageType) + if err != nil { + return errors.Wrapf(err, "unable to fetch storage with stoageType %s", storageType) + } + disks[i].storage = storage + idisks[i] = &disks[i] + } + in.dataDisks = idisks + return nil +} + +func (in *SInstance) makeNicComplete() error { + routerIds := sets.NewString() + nics := make(map[string]*SInstanceNic, len(in.PortDetail)) + for i := range in.PortDetail { + nic := &in.PortDetail[i] + routerIds.Insert(nic.RouterId) + nics[nic.PortId] = nic + } + for _, routerId := range routerIds.UnsortedList() { + request := NewConsoleRequest(in.host.zone.region.ID, fmt.Sprintf("/api/vpc/%s/nic", routerId), + map[string]string{ + "resourceId": in.Id, + }, nil, + ) + completeNics := make([]SInstanceNic, 0, len(nics)/2) + err := in.host.zone.region.client.doList(context.Background(), request, &completeNics) + if err != nil { + return errors.Wrapf(err, "unable to get nics with instance %s in vpc %s", in.Id, routerId) + } + for i := range completeNics { + id := completeNics[i].Id + nic, ok := nics[id] + if !ok { + continue + } + nic.SInstanceNicDetail = completeNics[i].SInstanceNicDetail + } + } + return nil +} + +func (r *SRegion) findHost(zoneRegion string) (*SHost, error) { + zone, err := r.FindZone(zoneRegion) + if err != nil { + return nil, err + } + return &SHost{ + zone: zone, + }, nil +} + +func (r *SRegion) GetInstancesWithHost(zoneRegion string) ([]SInstance, error) { + instances, err := r.GetInstances(zoneRegion) + if err != nil { + return nil, err + } + for i := range instances { + host, _ := r.findHost(instances[i].Region) + instances[i].host = host + } + return instances, nil +} + +func (r *SRegion) GetInstances(zoneRegion string) ([]SInstance, error) { + return r.getInstances(zoneRegion, "") +} + +func (r *SRegion) getInstances(zoneRegion string, serverId string) ([]SInstance, error) { + query := map[string]string{ + "serverTypes": "VM", + "productTypes": "NORMAL,AUTOSCALING,VO,CDN,PAAS_MASTER,PAAS_SLAVE,VCPE,EMR,LOGAUDIT", + //"productTypes": "NORMAL", + "visible": "true", + } + if len(serverId) > 0 { + query["serverId"] = serverId + } + if len(zoneRegion) > 0 { + query["region"] = zoneRegion + } + request := NewNovaRequest(NewApiRequest(r.ID, "/api/v2/server/web/with/network", query, nil)) + var instances []SInstance + err := r.client.doList(context.Background(), request, &instances) + if err != nil { + return nil, err + } + return instances, nil +} + +func (r *SRegion) GetInstanceById(id string) (*SInstance, error) { + instances, err := r.getInstances("", id) + if err != nil { + return nil, err + } + if len(instances) == 0 { + return nil, cloudprovider.ErrNotFound + } + instance := &instances[0] + host, err := r.findHost(instance.Region) + if err == nil { + instance.host = host + } + return instance, nil +} + +func (r *SRegion) GetInstanceVNCUrl(instanceId string) (string, error) { + request := NewNovaRequest(NewApiRequest(r.ID, fmt.Sprintf("/api/server/%s/vnc", instanceId), nil, nil)) + var url string + err := r.client.doGet(context.Background(), request, &url) + if err != nil { + return "", err + } + return url, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/instancenic.go new file mode 100644 index 0000000000..1d2d3569d8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/instancenic.go @@ -0,0 +1,87 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "time" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + cloudprovider.DummyICloudNic + SInstanceNicDetail + + instance *SInstance + + Id string + PrivateIp string + FipAddress string + FipBandwidthSize int + PortId string + PortName string + FixedIpDetails []SFixedIpDetail + RouterId string +} + +type SInstanceNicDetail struct { + MacAddress string + SecurityGroups []SSecurityGroupRef + Status int + ResourceId string + CreaetTime time.Time + PublicIp string + IpId string + NetworkId string +} + +type SSecurityGroupRef struct { + Id string + Name string +} + +type SFixedIpDetail struct { + IpAddress string + IpVersion string + PublicIp string + BandWidthSize int + BandWidthType string + SubnetId string + SubnetName string +} + +func (in *SInstanceNic) GetIP() string { + return in.PrivateIp +} + +func (in *SInstanceNic) GetMAC() string { + return in.MacAddress +} + +func (in *SInstanceNic) GetId() string { + return in.PortId +} + +func (in *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (in *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (in *SInstanceNic) GetINetworkId() string { + return in.NetworkId +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/latitud_and_longitude.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/latitud_and_longitude.go new file mode 100644 index 0000000000..2b18524eae --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/latitud_and_longitude.go @@ -0,0 +1,51 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ + "guangzhou-2": {Latitude: 23.129110, Longitude: 113.264381, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "beijing-1": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, + "hunan-1": {Latitude: 28.2277765095, Longitude: 112.9388453666, City: api.CITY_CHANG_SHA, CountryCode: api.COUNTRY_CODE_CN}, + "wuxi-1": {Latitude: 31.2983479333, Longitude: 120.5831894861, City: api.CITY_SU_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "dongguan-1": {Latitude: 23.129110, Longitude: 113.264381, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "yaan-1": {Latitude: 30.572815, Longitude: 104.066803, City: api.CITY_CHENG_DU, CountryCode: api.COUNTRY_CODE_CN}, + "zhengzhou-1": {Latitude: 34.7533581487, Longitude: 113.6313915479, City: api.CITY_ZHENG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "beijing-2": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, + "zhuzhou-1": {Latitude: 28.2277765095, Longitude: 112.9388453666, City: api.CITY_CHANG_SHA, CountryCode: api.COUNTRY_CODE_CN}, + "jinan-1": {Latitude: 36.64889911073425, Longitude: 117.11905617575435, City: api.CITY_JI_NAM, CountryCode: api.COUNTRY_CODE_CN}, + "xian-1": {Latitude: 34.3412614674, Longitude: 108.9398165260, City: api.CITY_XI_AN, CountryCode: api.COUNTRY_CODE_CN}, + "shanghai-1": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "chongqing-1": {Latitude: 29.431585, Longitude: 106.912254, City: api.CITY_CHONG_QING, CountryCode: api.COUNTRY_CODE_CN}, + "ningbo-1": {Latitude: 30.274084, Longitude: 120.155067, City: api.CITY_HANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "tianjin-1": {Latitude: 39.0850853357, Longitude: 117.1993482089, City: api.CITY_TIAN_JIN, CountryCode: api.COUNTRY_CODE_CN}, + "jilin-1": {Latitude: 43.87120919729674, Longitude: 125.3111129463539, City: api.CITY_CHANG_CHUN, CountryCode: api.COUNTRY_CODE_CN}, + "hubei-1": {Latitude: 32.009075721852206, Longitude: 112.13485327119795, City: api.CITY_XIANG_YANG, CountryCode: api.COUNTRY_CODE_CN}, + "jiangxi-1": {Latitude: 28.66278309381472, Longitude: 115.82816199879247, City: api.CITY_NAN_CHANG, CountryCode: api.COUNTRY_CODE_CN}, + "gansu-1": {Latitude: 36.0613769373, Longitude: 103.8341600069, City: api.CITY_LAN_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "shanxi-1": {Latitude: 37.8705857132, Longitude: 112.5506634865, City: api.CITY_TAI_YUAN, CountryCode: api.COUNTRY_CODE_CN}, + "liaoning-1": {Latitude: 41.78937667917192, Longitude: 123.43099727316815, City: api.CITY_SHEN_YANG, CountryCode: api.COUNTRY_CODE_CN}, + "yunnan-2": {Latitude: 24.8796595146, Longitude: 102.8332118852, City: api.CITY_KUN_MING, CountryCode: api.COUNTRY_CODE_CN}, + "hebei-1": {Latitude: 38.044044256466684, Longitude: 114.50225031469532, City: api.CITY_SHI_JIA_ZHUANG, CountryCode: api.COUNTRY_CODE_CN}, + "fujian-1": {Latitude: 24.478556505708365, Longitude: 118.0875755539503, City: api.CITY_XIA_MEN, CountryCode: api.COUNTRY_CODE_CN}, + "guangxi-1": {Latitude: 22.8167372565, Longitude: 108.3669005333, City: api.CITY_NAN_NING, CountryCode: api.COUNTRY_CODE_CN}, + "anhui-1": {Latitude: 32.62657438299575, Longitude: 116.99779954519057, City: api.CITY_HUAI_NAN, CountryCode: api.COUNTRY_CODE_CN}, + "huhehaote-1": {Latitude: 40.842358, Longitude: 111.749992, City: api.CITY_HU_HE_HAO_TE, CountryCode: api.COUNTRY_CODE_CN}, + "guiyang-1": {Latitude: 26.6470035286, Longitude: 106.6302113880, City: api.CITY_GUI_YANG, CountryCode: api.COUNTRY_CODE_CN}, +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/monitor.go new file mode 100644 index 0000000000..37006d7d54 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/monitor.go @@ -0,0 +1,206 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "context" + "strconv" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/timeutils" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" +) + +const ( + MONITOR_FETCH_REQUEST_ACTION = "v1.dawn.monitor.fetch" + MONITOR_PRODUCT_REQUEST_ACTION = "v1.dawn.monitor.products" + + MONITOR_FETCH_SERVER_PATH = "/api/edw/edw/api" + + REQUEST_SUCCESS_CODE = "000000" +) + +var ( + noMetricRegion = []string{"guangzhou-2", "beijing-1", "hunan-1"} + + portRegionMap = map[string][]string{ + "8443": {"wuxi-1", "dongguan-1", "yaan-1", "zhengzhou-1", "beijing-2", "zhuzhou-1", "jinan-1", + "xian-1", "shanghai-1", "chongqing-1", "ningbo-1"}, + "18080": {"tianjin-1", "jilin-1", "hubei-1", "jiangxi-1", "gansu-1", "shanxi-1", "liaoning-1", + "yunnan-2", "hebei-1", "fujian-1", "guangxi-1", "anhui-1", "huhehaote-1", "guiyang-1"}, + } +) + +type Metric struct { + Name string `json:"MetricName"` +} + +type MetricData struct { + Entitys []Entity `json:"entity"` +} + +type Entity struct { + ResourceID string `json:"resourceId"` + MetricName string `json:"metricName"` + MetricNameCN string `json:"metricNameCn"` + Unit string `json:"unit"` + MaxValue int64 `json:"maxValue"` + AvgValue int64 `json:"avgValue"` + MinValue int64 `json:"minValue"` + Granularity string `json:"granularity"` + PolymerizeType string `json:"polymerizeType"` + SelectedMetricItem interface{} `json:"selectedMetricItem"` + MetricItems interface{} `json:"metricItems"` + IsChildnode bool `json:"isChildnode"` + Datapoints []Datapoint `json:"datapoints"` +} + +type Datapoint []string + +type SMonitorRequest struct { + SApiRequest +} + +func NewMonitorRequest(regionId string, serverPath string, query map[string]string, data jsonutils.JSONObject) *SMonitorRequest { + apiRequest := NewApiRequest(regionId, serverPath, query, data) + return &SMonitorRequest{*apiRequest} +} + +func (rr *SMonitorRequest) GetPort() string { + for port, regions := range portRegionMap { + if utils.IsInStringArray(rr.GetRegionId(), regions) { + return port + } + } + return "8443" +} + +func (br *SMonitorRequest) ForMateResponseBody(jrbody jsonutils.JSONObject) (jsonutils.JSONObject, error) { + code, _ := jrbody.GetString("code") + if code != REQUEST_SUCCESS_CODE { + message, _ := jrbody.(*jsonutils.JSONDict).GetString("message") + return nil, httperrors.NewBadRequestError("rep body code is :%s, message:%s,body:%v", code, message, jrbody) + } + if jrbody == nil || !jrbody.Contains("entity") { + return nil, ErrMissKey{ + Key: "entity", + Jo: jrbody, + } + } + return jrbody, nil +} + +func (self *SEcloudClient) DescribeMetricList(regionId, productType string, metrics []Metric, resourceId string, + since time.Time, until time.Time) (MetricData, error) { + metricData := MetricData{ + Entitys: make([]Entity, 0), + } + params := map[string]string{ + "eAction": MONITOR_FETCH_REQUEST_ACTION, + } + getBody := jsonutils.NewDict() + getBody.Set("startTime", jsonutils.NewString(since.Format(timeutils.MysqlTimeFormat))) + getBody.Set("endTime", jsonutils.NewString(until.Format(timeutils.MysqlTimeFormat))) + getBody.Set("productType", jsonutils.NewString(productType)) + getBody.Set("resourceId", jsonutils.NewString(resourceId)) + getBody.Set("metrics", jsonutils.Marshal(&metrics)) + request := NewMonitorRequest(regionId, MONITOR_FETCH_SERVER_PATH, params, getBody) + err := self.doGet(context.Background(), request, &metricData) + if err != nil { + return metricData, errors.Wrap(err, "client doGet error") + } + return metricData, nil +} + +func (r *SRegion) GetProductTypes() (jsonutils.JSONObject, error) { + params := map[string]string{ + "eAction": MONITOR_PRODUCT_REQUEST_ACTION, + } + request := NewMonitorRequest(r.ID, MONITOR_FETCH_SERVER_PATH, params, nil) + rtn := jsonutils.NewDict() + err := r.client.doGet(context.Background(), request, rtn) + if err != nil { + return nil, errors.Wrap(err, "client doGet error") + } + return rtn, nil +} + +func (self *SEcloudClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) + } +} + +func (self *SEcloudClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metrics := map[string]cloudprovider.TMetricType{ + "cpu_util": cloudprovider.VM_METRIC_TYPE_CPU_USAGE, + "memory.util": cloudprovider.VM_METRIC_TYPE_MEM_USAGE, + "disk.device.read.requests.rate": cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS, + "disk.device.write.requests.rate": cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS, + "disk.device.read.bytes.rate": cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS, + "disk.device.write.bytes.rate": cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS, + "network.incoming.bytes": cloudprovider.VM_METRIC_TYPE_NET_BPS_RX, + "network.outgoing.bytes": cloudprovider.VM_METRIC_TYPE_NET_BPS_TX, + } + metricNames := []Metric{} + for metric := range metrics { + metricNames = append(metricNames, Metric{ + Name: metric, + }) + } + if utils.IsInStringArray(opts.RegionExtId, noMetricRegion) { + return []cloudprovider.MetricValues{}, nil + } + data, err := self.DescribeMetricList(opts.RegionExtId, "vm", metricNames, opts.ResourceId, opts.StartTime, opts.EndTime) + if err != nil { + return nil, errors.Wrapf(err, "DescribeMetricList") + } + ret := []cloudprovider.MetricValues{} + for _, value := range data.Entitys { + metric := cloudprovider.MetricValues{} + metric.Id = opts.ResourceId + metricType, ok := metrics[value.MetricName] + if !ok { + continue + } + metric.MetricType = metricType + for _, points := range value.Datapoints { + if len(points) != 2 { + continue + } + metricValue := cloudprovider.MetricValue{} + pointTime, err := strconv.ParseInt(points[1], 10, 64) + if err != nil { + continue + } + metricValue.Timestamp = time.Unix(pointTime, 0) + metricValue.Value, err = strconv.ParseFloat(points[0], 64) + if err != nil { + continue + } + metric.Values = append(metric.Values, metricValue) + } + ret = append(ret, metric) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/network.go new file mode 100644 index 0000000000..0daf91cb1a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/network.go @@ -0,0 +1,190 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "context" + + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + EcloudTags + SZoneRegionBase + + wire *SWire + + Id string + Name string + Shared bool + Enabled bool + EcStatus string + Subnets []SSubnet +} + +type SSubnet struct { + Id string + Name string + NetworkId string + Region string + GatewayIp string + EnableDHCP bool + Cidr string + IpVersion string +} + +func (n *SNetwork) GetId() string { + return n.Id +} + +func (n *SNetwork) GetName() string { + return n.Name +} + +func (n *SNetwork) GetGlobalId() string { + return n.Id +} + +func (n *SNetwork) GetStatus() string { + switch n.EcStatus { + case "ACTIVE": + return api.NETWORK_STATUS_AVAILABLE + case "DOWN", "BUILD", "ERROR": + return api.NETWORK_STATUS_UNAVAILABLE + case "PENDING_DELETE": + return api.NETWORK_STATUS_DELETING + case "PENDING_CREATE", "PENDING_UPDATE": + return api.NETWORK_STATUS_PENDING + default: + return api.NETWORK_STATUS_UNKNOWN + } +} + +func (n *SNetwork) Refresh() error { + return nil + // nn, err := n.wire.vpc.region.GetNetworkById(n.wire.vpc.RouterId, n.wire.zone.Region, n.GetId()) + // if err != nil { + // return err + // } + // return jsonutils.Update(n, nn) +} + +func (n *SNetwork) IsEmulated() bool { + return false +} + +func (n *SNetwork) GetProjectId() string { + return "" +} + +func (n *SNetwork) GetIWire() cloudprovider.ICloudWire { + return n.wire +} + +func (n *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(n.Cidr()) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + startIp = startIp.StepUp() // 2 + return startIp.String() +} + +func (n *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(n.Cidr()) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + return endIp.String() +} + +func (n *SNetwork) Cidr() string { + return n.Subnets[0].Cidr +} + +func (n *SNetwork) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(n.Cidr()) + return pref.MaskLen +} + +func (n *SNetwork) GetGateway() string { + return n.Subnets[0].GatewayIp +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetIsPublic() bool { + return true +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 120 +} + +func (r *SRegion) GetNetworks(routerId, zoneRegion string) ([]SNetwork, error) { + queryParams := map[string]string{ + "networkTypeEnum": "VM", + } + if len(routerId) > 0 { + queryParams["routerId"] = routerId + } + if len(zoneRegion) > 0 { + queryParams["region"] = zoneRegion + } + request := NewConsoleRequest(r.ID, "/api/v2/netcenter/network/NetworkResps", queryParams, nil) + networks := make([]SNetwork, 0) + err := r.client.doList(context.Background(), request, &networks) + if err != nil { + return nil, err + } + return networks, nil +} + +func (r *SRegion) GetNetworkById(routerId, zoneRegion, netId string) (*SNetwork, error) { + queryParams := map[string]string{ + "rangeInNetworkIds": netId, + "networkTypeEnum": "VM", + } + if len(routerId) > 0 { + queryParams["routerId"] = routerId + } + if len(zoneRegion) > 0 { + queryParams["region"] = zoneRegion + } + request := NewConsoleRequest(r.ID, "/api/v2/netcenter/network/NetworkResps", queryParams, nil) + networks := make([]SNetwork, 0, 1) + err := r.client.doList(context.Background(), request, &networks) + if err != nil { + return nil, err + } + if len(networks) == 0 { + return nil, cloudprovider.ErrNotFound + } + return &networks[0], nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/provider/doc.go new file mode 100644 index 0000000000..30bf5a4fbd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/ecloud/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/provider/provider.go new file mode 100644 index 0000000000..93225dc956 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/provider/provider.go @@ -0,0 +1,185 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/ecloud" +) + +type SEcloudProviderFactory struct { + cloudprovider.SPublicCloudBaseProviderFactory +} + +func (f *SEcloudProviderFactory) GetId() string { + return ecloud.CLOUD_PROVIDER_ECLOUD +} + +func (f *SEcloudProviderFactory) GetName() string { + return ecloud.CLOUD_PROVIDER_ECLOUD_CN +} + +func (f *SEcloudProviderFactory) IsSupportPrepaidResources() bool { + return true +} + +func (f *SEcloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + return output, nil +} + +func (f *SEcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func (f *SEcloudProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + segs := strings.Split(cfg.Account, "/") + account := cfg.Account + if len(segs) == 2 { + account = segs[0] + } + + client, err := ecloud.NewEcloudClient( + ecloud.NewEcloudClientConfig( + ecloud.NewRamRoleSigner(account, cfg.Secret), + ).SetCloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + err = client.TryConnect() + if err != nil { + return nil, err + } + return &SEcloudProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(f), + client: client, + }, nil +} + +func (f *SEcloudProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + return map[string]string{ + "ECLOUD_ACCESS_URL": info.Url, + "ECLOUD_ACCESS_KEY": info.Account, + "ECLOUD_SECRET": info.Secret, + "ECLOUD_REGION": ecloud.ECLOUD_DEFAULT_REGION, + }, nil +} + +func init() { + factory := SEcloudProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SEcloudProvider struct { + cloudprovider.SBaseProvider + client *ecloud.SEcloudClient +} + +func (p *SEcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return p.client.GetSubAccounts() +} + +func (p *SEcloudProvider) GetAccountId() string { + return p.client.GetAccountId() +} + +func (p *SEcloudProvider) GetIRegions() []cloudprovider.ICloudRegion { + return p.client.GetIRegions() +} + +func (p *SEcloudProvider) GetSysInfo() (jsonutils.JSONObject, error) { + iregions := p.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(iregions))), "region_count") + info.Add(jsonutils.NewString(ecloud.CLOUD_API_VERSION), "api_version") + return info, nil +} + +func (p *SEcloudProvider) GetVersion() string { + return ecloud.CLOUD_API_VERSION +} + +func (p *SEcloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + iregion, err := p.client.GetIRegionById(id) + if err != nil { + return nil, err + } + if iregion == nil { + return nil, cloudprovider.ErrNotFound + } + return iregion, nil +} + +func (p *SEcloudProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (p *SEcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (p *SEcloudProvider) GetStorageClasses(regionId string) []string { + // TODO + return nil +} + +func (p *SEcloudProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (p *SEcloudProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (p *SEcloudProvider) GetCloudRegionExternalIdPrefix() string { + return p.client.GetCloudRegionExternalIdPrefix() +} + +func (p *SEcloudProvider) GetCapabilities() []string { + return p.client.GetCapabilities() +} + +func (self *SEcloudProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetMetrics(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/region.go new file mode 100644 index 0000000000..16c5187673 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/region.go @@ -0,0 +1,355 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "context" + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var regionList = map[string]string{ + "guangzhou-2": "华南-广州2", + "beijing-1": "华北-北京1", + "hunan-1": "华中-长沙1", + "wuxi-1": "华东-苏州", + "dongguan-1": "华南-广州3", + "yaan-1": "西南-成都", + "zhengzhou-1": "华中-郑州", + "beijing-2": "华北-北京3", + "zhuzhou-1": "华中-长沙2", + "jinan-1": "华东-济南", + "xian-1": "西北-西安", + "shanghai-1": "华东-上海1", + "chongqing-1": "西南-重庆", + "ningbo-1": "华东-杭州", + "tianjin-1": "天津-天津", + "jilin-1": "吉林-长春", + "hubei-1": "湖北-襄阳", + "jiangxi-1": "江西-南昌", + "gansu-1": "甘肃-兰州", + "shanxi-1": "山西-太原", + "liaoning-1": "辽宁-沈阳", + "yunnan-2": "云南-昆明2", + "hebei-1": "河北-石家庄", + "fujian-1": "福建-厦门", + "guangxi-1": "广西-南宁", + "anhui-1": "安徽-淮南", + "huhehaote-1": "华北-呼和浩特", + "guiyang-1": "西南-贵阳", +} + +type SRegion struct { + cloudprovider.SFakeOnPremiseRegion + multicloud.SRegion + multicloud.SNoObjectStorageRegion + + client *SEcloudClient + storageCache *SStoragecache + + ID string `json:"id"` + Name string `json:"Name"` + + izones []cloudprovider.ICloudZone + ivpcs []cloudprovider.ICloudVpc +} + +func (r *SRegion) GetId() string { + return r.ID +} + +func (r *SRegion) GetName() string { + return r.Name +} + +func (r *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", r.client.GetAccessEnv(), r.ID) +} + +func (r *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (r *SRegion) Refresh() error { + // err := r.fetchZones() + // if err != nil { + // return err + // } + // return r.fetchVpcs() + return nil +} + +func (r *SRegion) IsEmulated() bool { + return false +} + +func (r *SRegion) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_ECLOUD_EN, r.Name) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(r.GetName()).CN(r.GetName()).EN(en) + return table +} + +// GetLatitude() float32 +// GetLongitude() float32 +func (r *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + if info, ok := LatitudeAndLongitude[r.ID]; ok { + return info + } + return cloudprovider.SGeographicInfo{} +} + +func (r *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if r.izones == nil { + err := r.fetchZones() + if err != nil { + return nil, err + } + } + return r.izones, nil +} + +func (r *SRegion) fetchZones() error { + request := NewNovaRequest(NewApiRequest(r.ID, "/api/v2/region", + map[string]string{"component": "NOVA"}, nil)) + zones := make([]SZone, 0) + err := r.client.doList(context.Background(), request, &zones) + if err != nil { + return err + } + izones := make([]cloudprovider.ICloudZone, len(zones)) + for i := range zones { + zones[i].region = r + zones[i].host = &SHost{ + zone: &zones[i], + } + izones[i] = &zones[i] + } + r.izones = izones + return nil +} + +func (r *SRegion) fetchVpcs() error { + vpcs, err := r.getVpcs() + if err != nil { + return err + } + ivpcs := make([]cloudprovider.ICloudVpc, len(vpcs)) + for i := range vpcs { + ivpcs[i] = &vpcs[i] + } + r.ivpcs = ivpcs + return nil +} + +func (r *SRegion) getVpcs() ([]SVpc, error) { + request := NewConsoleRequest(r.ID, "/api/v2/netcenter/vpc", nil, nil) + vpcs := make([]SVpc, 0) + err := r.client.doList(context.Background(), request, &vpcs) + if err != nil { + return nil, err + } + for i := range vpcs { + vpcs[i].region = r + } + return vpcs, err +} + +func (r *SRegion) getVpcById(id string) (*SVpc, error) { + request := NewConsoleRequest(r.ID, fmt.Sprintf("/api/v2/netcenter/vpc/%s", id), nil, nil) + vpc := SVpc{} + err := r.client.doGet(context.Background(), request, &vpc) + if err != nil { + return nil, err + } + vpc.region = r + return &vpc, err +} + +func (r *SRegion) getVpcByRouterId(id string) (*SVpc, error) { + request := NewConsoleRequest(r.ID, fmt.Sprintf("/api/v2/netcenter/vpc/router/%s", id), nil, nil) + vpc := SVpc{} + err := r.client.doGet(context.Background(), request, &vpc) + if err != nil { + return nil, err + } + vpc.region = r + return &vpc, err +} + +func (r *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + if r.ivpcs == nil { + err := r.fetchVpcs() + if err != nil { + return nil, err + } + } + return r.ivpcs, nil +} + +func (r *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (r *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + vpc, err := r.getVpcById(id) + if err != nil { + return nil, err + } + vpc.region = r + return vpc, nil +} + +func (r *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := r.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (r *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (r *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := r.GetInstanceById(id) + if err != nil { + return nil, err + } + zone, err := r.FindZone(vm.Region) + if err != nil { + return nil, err + } + vm.host = &SHost{ + zone: zone, + } + return vm, nil +} + +func (r *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return r.GetDisk(id) +} + +func (r *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + izones, err := r.GetIZones() + if err != nil { + return nil, err + } + iHosts := make([]cloudprovider.ICloudHost, 0, len(izones)) + for i := range izones { + hosts, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, hosts...) + } + return iHosts, nil +} + +func (r *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + hosts, err := r.GetIHosts() + if err != nil { + return nil, err + } + for i := range hosts { + if hosts[i].GetGlobalId() == id { + return hosts[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (r *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := r.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +func (r *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + istores, err := r.GetIStorages() + if err != nil { + return nil, err + } + for i := range istores { + if istores[i].GetGlobalId() == id { + return istores[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (r *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + sc := r.getStoragecache() + return []cloudprovider.ICloudStoragecache{sc}, nil +} + +func (r *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + storageCache := r.getStoragecache() + if storageCache.GetGlobalId() == id { + return storageCache, nil + } + return nil, cloudprovider.ErrNotFound +} + +func (r *SRegion) GetProvider() string { + return api.CLOUD_PROVIDER_ECLOUD +} + +func (r *SRegion) GetCapabilities() []string { + return r.client.GetCapabilities() +} + +func (r *SRegion) GetClient() *SEcloudClient { + return r.client +} + +func (r *SRegion) FindZone(zoneRegion string) (*SZone, error) { + izones, err := r.GetIZones() + if err != nil { + return nil, errors.Wrap(err, "unable to GetZones") + } + findZone := func(zoneRegion string) *SZone { + for i := range izones { + zone := izones[i].(*SZone) + if zone.Region == zoneRegion { + return zone + } + } + return nil + } + return findZone(zoneRegion), nil +} diff --git a/pkg/multicloud/ecloud/request.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/request.go similarity index 100% rename from pkg/multicloud/ecloud/request.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/request.go diff --git a/pkg/multicloud/ecloud/signer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/signer.go similarity index 100% rename from pkg/multicloud/ecloud/signer.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/signer.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/snapshot.go new file mode 100644 index 0000000000..53bda75934 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/snapshot.go @@ -0,0 +1,130 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "context" + "strings" + "time" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSnapshot struct { + multicloud.SResourceBase + EcloudTags + region *SRegion + SCreateTime + + BackupType string + CreateBy string + Description string + EcType string + Id string + Name string + Size int + VolumeId string + VolumeType string + Status string + IsSystem bool + SystemDisk string +} + +func (s *SSnapshot) GetId() string { + return s.Id +} + +func (s *SSnapshot) GetName() string { + return s.Name +} + +func (s *SSnapshot) GetStatus() string { + switch strings.ToLower(s.Status) { + case "available", "in_use", "active": + return api.SNAPSHOT_READY + case "creating", "attaching", "backing_up", "saving", "queued": + return api.SNAPSHOT_CREATING + case "deleting": + return api.SNAPSHOT_DELETING + case "error_deleting": + return api.SNAPSHOT_DELETE_FAILED + case "error": + return api.SNAPSHOT_FAILED + default: + return api.SNAPSHOT_UNKNOWN + } +} + +func (s *SSnapshot) GetSizeMb() int32 { + return int32(s.Size) +} + +func (s *SSnapshot) GetDiskId() string { + if s.IsSystem { + return s.SystemDisk + } + return s.VolumeId +} + +func (s *SSnapshot) GetCreatedAt() time.Time { + return s.SCreateTime.GetCreatedAt() +} + +func (s *SSnapshot) GetDiskType() string { + if s.IsSystem { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +func (s *SSnapshot) GetGlobalId() string { + return s.Id +} + +func (s *SSnapshot) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (s *SSnapshot) GetProjectId() string { + return "" +} + +func (s *SRegion) GetSnapshots(snapshotId string, parentId string, isSystem bool) ([]SSnapshot, error) { + var apiRequest *SApiRequest + query := map[string]string{} + if len(snapshotId) > 0 { + query["backupId"] = snapshotId + } + if isSystem { + if len(parentId) > 0 { + query["serverId"] = parentId + } + apiRequest = NewApiRequest(s.ID, "/api/v2/vmBackup", query, nil) + } else { + if len(parentId) > 0 { + query["volumeId"] = parentId + } + apiRequest = NewApiRequest(s.ID, "/api/v2/volume/volumebackup", query, nil) + } + request := NewNovaRequest(apiRequest) + snapshots := make([]SSnapshot, 0) + err := s.client.doList(context.Background(), request, &snapshots) + if err != nil { + return nil, err + } + return snapshots, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/storage.go new file mode 100644 index 0000000000..ba07068c63 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/storage.go @@ -0,0 +1,166 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var storageTypes = []string{ + api.STORAGE_ECLOUD_CAPEBS, + api.STORAGE_ECLOUD_EBS, + api.STORAGE_ECLOUD_SSD, + api.STORAGE_ECLOUD_SSDEBS, + // special storage + api.STORAGE_ECLOUD_SYSTEM, +} + +type SStorage struct { + multicloud.SStorageBase + EcloudTags + zone *SZone + storageType string +} + +func (s *SStorage) GetId() string { + return fmt.Sprintf("%s-%s-%s", s.zone.region.client.cpcfg.Id, s.zone.GetGlobalId(), s.storageType) +} + +func (s *SStorage) GetName() string { + return fmt.Sprintf("%s-%s-%s", s.zone.region.client.cpcfg.Name, s.zone.GetId(), s.storageType) +} + +func (s *SStorage) GetGlobalId() string { + return s.GetId() +} + +func (s *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (s *SStorage) Refresh() error { + return nil +} + +func (s *SStorage) IsEmulated() bool { + return true +} + +func (s *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return s.zone.region.getStoragecache() +} + +func (s *SStorage) GetIZone() cloudprovider.ICloudZone { + return s.zone +} + +func (s *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + if s.storageType == api.STORAGE_ECLOUD_SYSTEM { + return nil, nil + } + disks, err := s.zone.region.GetDisks() + if err != nil { + return nil, err + } + + // 按storage type 过滤出disk + filtedDisks := make([]SDisk, 0) + for i := range disks { + disk := disks[i] + if disk.Type == s.storageType && disk.Region == s.zone.Region { + filtedDisks = append(filtedDisks, disk) + } + } + + idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) + for i := 0; i < len(filtedDisks); i += 1 { + filtedDisks[i].storage = s + idisks[i] = &filtedDisks[i] + } + return idisks, nil +} + +func (s *SStorage) GetStorageType() string { + return s.storageType +} + +func (s *SStorage) GetMediumType() string { + if s.storageType == api.STORAGE_ECLOUD_SSD { + return api.DISK_TYPE_SSD + } else { + return api.DISK_TYPE_ROTATE + } +} + +func (s *SStorage) GetCapacityMB() int64 { + return 0 +} + +func (s *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (s *SStorage) GetStorageConf() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (s *SStorage) GetEnabled() bool { + return true +} + +func (s *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (s *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + if len(idStr) == 0 { + return nil, cloudprovider.ErrNotFound + } + + if disk, err := s.zone.region.GetDisk(idStr); err != nil { + return nil, err + } else { + disk.storage = s + return disk, nil + } +} + +func (s *SStorage) GetMountPoint() string { + return "" +} + +func (s *SStorage) IsSysDiskStore() bool { + return true +} + +func (s *SStorage) DisableSync() bool { + if s.storageType == api.STORAGE_ECLOUD_SYSTEM { + return true + } + return s.SStorageBase.DisableSync() +} + +func (s *SRegion) getStoragecache() *SStoragecache { + if s.storageCache == nil { + s.storageCache = &SStoragecache{region: s} + } + return s.storageCache +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/storagecache.go new file mode 100644 index 0000000000..d0b2db5a19 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/storagecache.go @@ -0,0 +1,100 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStoragecache struct { + multicloud.SResourceBase + EcloudTags + region *SRegion +} + +func (sc *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (sc *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (sc *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (sc *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", sc.region.client.cpcfg.Id, sc.region.GetId()) +} + +func (sc *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", sc.region.client.cpcfg.Name, sc.region.GetId()) +} + +func (sc *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", sc.region.client.cpcfg.Id, sc.region.GetGlobalId()) +} + +func (sc *SStoragecache) GetStatus() string { + return "available" +} + +func (sc *SStoragecache) Refresh() error { + return nil +} + +func (sc *SStoragecache) IsEmulated() bool { + return false +} + +func (sc *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (sc *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + imagesSelf, err := sc.region.GetImages(false) + if err != nil { + return nil, errors.Wrapf(err, "GetImages") + } + ret := []cloudprovider.ICloudImage{} + for i := range imagesSelf { + imagesSelf[i].storageCache = sc + ret = append(ret, &imagesSelf[i]) + } + return ret, nil +} + +func (sc *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + image, err := sc.region.GetImage(extId) + if err != nil { + return nil, errors.Wrap(err, "SStoragecache.GetIImageById.GetImage") + } + + image.storageCache = sc + return image, err +} + +func (sc *SStoragecache) GetPath() string { + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/tag_base.go new file mode 100644 index 0000000000..ddf812d179 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/tag_base.go @@ -0,0 +1,36 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type EcloudTags struct { +} + +func (self *EcloudTags) GetTags() (map[string]string, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") +} + +func (self *EcloudTags) GetSysTags() map[string]string { + return nil +} + +func (self *EcloudTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/vpc.go new file mode 100644 index 0000000000..1250eb1a7e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/vpc.go @@ -0,0 +1,178 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + EcloudTags + + region *SRegion + iwires []cloudprovider.ICloudWire + + // wires + // secgroups + + Id string + Name string + Region string + EcStatus string + RouterId string + Scale string + UserId string + UserName string +} + +func (v *SVpc) GetId() string { + return v.Id +} + +func (v *SVpc) GetName() string { + return v.Name +} + +func (v *SVpc) GetGlobalId() string { + return v.GetId() +} + +func (v *SVpc) GetStatus() string { + switch v.EcStatus { + case "ACTIVE": + return api.VPC_STATUS_AVAILABLE + case "DOWN", "BUILD", "ERROR": + return api.VPC_STATUS_UNAVAILABLE + case "PENDING_DELETE": + return api.VPC_STATUS_DELETING + case "PENDING_CREATE", "PENDING_UPDATE": + return api.VPC_STATUS_PENDING + default: + return api.VPC_STATUS_UNKNOWN + } +} + +func (v *SVpc) Refresh() error { + n, err := v.region.getVpcById(v.Id) + if err != nil { + return err + } + return jsonutils.Update(v, n) + // TODO? v.fetchWires() +} + +func (v *SVpc) IsEmulated() bool { + return false +} + +func (v *SVpc) GetRegion() cloudprovider.ICloudRegion { + return v.region +} + +func (v *SVpc) GetIsDefault() bool { + return false +} + +func (v *SVpc) GetCidrBlock() string { + return "" +} + +func (v *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + if v.iwires == nil { + err := v.fetchWires() + if err != nil { + return nil, err + } + } + return v.iwires, nil +} + +func (v *SVpc) fetchWires() error { + networks, err := v.region.GetNetworks(v.RouterId, "") + if err != nil { + return err + } + izones, err := v.region.GetIZones() + if err != nil { + return errors.Wrap(err, "unable to GetZones") + } + findZone := func(zoneRegion string) *SZone { + for i := range izones { + zone := izones[i].(*SZone) + if zone.Region == zoneRegion { + return zone + } + } + return nil + } + zoneRegion2Wire := map[string]*SWire{} + for i := range networks { + zoneRegion := networks[i].Region + zone := findZone(zoneRegion) + var ( + wire *SWire + ok bool + ) + if wire, ok = zoneRegion2Wire[zoneRegion]; !ok { + wire = &SWire{ + vpc: v, + zone: zone, + } + zoneRegion2Wire[zoneRegion] = wire + } + wire.inetworks = append(wire.inetworks, &networks[i]) + } + iwires := make([]cloudprovider.ICloudWire, 0, len(zoneRegion2Wire)) + for _, wire := range zoneRegion2Wire { + iwires = append(iwires, wire) + } + v.iwires = iwires + return nil +} + +func (v *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + return nil, nil +} + +func (v *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (v *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, nil +} + +func (v *SVpc) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (v *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { + iwires, err := v.GetIWires() + if err != nil { + return nil, err + } + for i := range iwires { + if iwires[i].GetGlobalId() == wireId { + return iwires[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/wire.go new file mode 100644 index 0000000000..5ba9a28643 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/wire.go @@ -0,0 +1,140 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + EcloudTags + vpc *SVpc + zone *SZone + inetworks []cloudprovider.ICloudNetwork +} + +func (w *SWire) GetId() string { + return fmt.Sprintf("%s-%s", w.vpc.GetId(), w.vpc.region.GetId()) +} + +func (w *SWire) GetName() string { + return w.GetId() +} + +func (w *SWire) GetGlobalId() string { + return fmt.Sprintf("%s-%s", w.vpc.GetGlobalId(), w.vpc.region.GetGlobalId()) +} + +func (w *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (w *SWire) Refresh() error { + return nil + // TODO? w.fetchNetworks() +} + +func (w *SWire) IsEmulated() bool { + return true +} + +func (w *SWire) GetIVpc() cloudprovider.ICloudVpc { + return w.vpc +} + +func (w *SWire) GetIZone() cloudprovider.ICloudZone { + return w.zone +} + +func (w *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + if w.inetworks == nil { + err := w.fetchNetworks() + if err != nil { + return nil, err + } + } + return w.inetworks, nil +} + +func (w *SWire) GetBandwidth() int { + return 10000 +} + +func (w *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { + n, err := w.vpc.region.GetNetworkById(w.vpc.RouterId, w.zone.Region, netid) + if err != nil { + return nil, err + } + n.wire = w + return n, nil +} + +func (w *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + return nil, nil +} + +func (w *SWire) CreateNetworks() (*SNetwork, error) { + // data := jsonutils.NewDict() + // req := jsonutils.NewDict() + // req.Set("availabilityZoneHints", jsonutils.NewString("RegionOne")) + // req.Set("networkName", jsonutils.NewString("zyone")) + // req.Set("networkTypeEnum", jsonutils.NewString("VM")) + // req.Set("region", jsonutils.NewString("RegionOne")) + // req.Set("routerId", jsonutils.NewString(w.vpc.RouterId)) + // subnet := jsonutils.NewDict() + // subnet.Set("cidr", jsonutils.NewString("192.168.46.0/24")) + // subnet.Set("ipVersion", jsonutils.NewString("4")) + // subnet.Set("subnetName", jsonutils.NewString("zyone")) + // req.Set("subnets", jsonutils.NewArray(subnet)) + // data.Set("networkCreateReq", req) + // fmt.Printf("data:\n%s", data.PrettyString()) + // request := NewConsoleRequest(w.vpc.region.ID, "/api/v2/netcenter/network", nil, req) + // request.SetMethod("POST") + // resp, err := w.vpc.region.client.request(context.Background(), request) + // if err != nil { + // return nil, err + // } + // fmt.Printf("resp:%s", resp) + // return nil, nil + return nil, cloudprovider.ErrNotImplemented +} + +func (w *SWire) GetNetworkById(netId string) (*SNetwork, error) { + n, err := w.vpc.region.GetNetworkById(w.vpc.RouterId, w.zone.Region, netId) + if err != nil { + return nil, err + } + n.wire = w + return n, nil +} + +func (w *SWire) fetchNetworks() error { + networks, err := w.vpc.region.GetNetworks(w.vpc.RouterId, w.zone.Region) + if err != nil { + return err + } + inetworks := make([]cloudprovider.ICloudNetwork, len(networks)) + for i := range networks { + networks[i].wire = w + inetworks[i] = &networks[i] + } + w.inetworks = inetworks + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/zone.go new file mode 100644 index 0000000000..8a09d213b1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ecloud/zone.go @@ -0,0 +1,148 @@ +// Copyright 2019 Yunion +// +// 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 ecloud + +import ( + "fmt" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SZone struct { + multicloud.SResourceBase + EcloudTags + region *SRegion + host *SHost + + istorages []cloudprovider.ICloudStorage + + ID string `json:"id"` + Name string `json:"name"` + Region string `json:"region"` + Deleted bool + Visible bool +} + +func (z *SZone) GetId() string { + return z.ID +} + +func (z *SZone) GetName() string { + //return fmt.Sprintf("%s %s", CLOUD_PROVIDER_ECLOUD_CN, z.Name) + return z.Name +} + +func (z *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s", z.region.GetGlobalId(), z.ID) +} + +func (z *SZone) GetStatus() string { + if z.Deleted || !z.Visible { + return "disable" + } + return "enable" +} + +func (z *SZone) Refresh() error { + return nil +} + +func (z *SZone) IsEmulated() bool { + return false +} + +func (z *SZone) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(z.GetName()).CN(z.GetName()).EN(fmt.Sprintf("%s %s", CLOUD_PROVIDER_ECLOUD_EN, z.Name)) + return table +} + +func (z *SZone) GetIRegion() cloudprovider.ICloudRegion { + return z.region +} + +func (z *SZone) getHost() cloudprovider.ICloudHost { + if z.host == nil { + z.host = &SHost{ + zone: z, + } + } + return z.host +} + +func (z *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + return []cloudprovider.ICloudHost{z.getHost()}, nil +} + +func (z *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + host := z.getHost() + if host.GetGlobalId() == id { + return host, nil + } + return nil, cloudprovider.ErrNotFound +} + +func (z *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + if z.istorages == nil { + err := z.fetchStorages() + if err != nil { + return nil, err + } + } + return z.istorages, nil +} + +func (z *SZone) fetchStorages() error { + istorages := make([]cloudprovider.ICloudStorage, len(storageTypes)) + for i := range istorages { + istorages[i] = &SStorage{ + zone: z, + storageType: storageTypes[i], + } + } + z.istorages = istorages + return nil +} + +func (z *SZone) getStorageByType(t string) (*SStorage, error) { + istorages, err := z.GetIStorages() + if err != nil { + return nil, err + } + for i := range istorages { + if istorages[i].GetStorageType() == t { + return istorages[i].(*SStorage), nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (z *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + istorages, err := z.GetIStorages() + if err != nil { + return nil, err + } + for i := range istorages { + if istorages[i].GetGlobalId() == id { + return istorages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +type SZoneRegionBase struct { + Region string +} diff --git a/pkg/multicloud/eip_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/eip_base.go similarity index 100% rename from pkg/multicloud/eip_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/eip_base.go diff --git a/pkg/multicloud/elasticcache_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/elasticcache_base.go similarity index 100% rename from pkg/multicloud/elasticcache_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/elasticcache_base.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/cluster.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/cluster.go new file mode 100644 index 0000000000..aa9b66e4db --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/cluster.go @@ -0,0 +1,110 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "context" + "fmt" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SCluster struct { + SManagedObject +} + +func NewCluster(manager *SESXiClient, cluster *mo.ClusterComputeResource, dc *SDatacenter) *SCluster { + return &SCluster{SManagedObject: newManagedObject(manager, cluster, dc)} +} + +func (cluster *SCluster) ListResourcePools() ([]mo.ResourcePool, error) { + var pools, result []mo.ResourcePool + err := cluster.manager.scanMObjects(cluster.object.Entity().Self, RESOURCEPOOL_PROPS, &pools) + if err != nil { + return nil, errors.Wrap(err, "scanMObjects") + } + for i := range pools { + if pools[i].Parent.Type == "ClusterComputeResource" { + continue + } + result = append(result, pools[i]) + } + return result, nil +} + +func (cluster *SCluster) getDefaultResourcePool() (mo.ResourcePool, error) { + pools := []mo.ResourcePool{} + err := cluster.manager.scanMObjects(cluster.object.Entity().Self, RESOURCEPOOL_PROPS, &pools) + if err != nil { + return mo.ResourcePool{}, errors.Wrap(err, "scanMObjects") + } + for i := range pools { + if pools[i].Parent.Type == "ClusterComputeResource" { + return pools[i], nil + } + } + return mo.ResourcePool{}, cloudprovider.ErrNotFound +} + +func (cluster *SCluster) CreateResourcePool(name string) (*mo.ResourcePool, error) { + if len(name) == 0 { + return nil, errors.Error("empty name str") + } + root, err := cluster.getDefaultResourcePool() + if err != nil { + return nil, errors.Wrap(err, "getDefaultResourcePool") + } + pool := object.NewResourcePool(cluster.manager.client.Client, root.Reference()) + pool.InventoryPath = fmt.Sprintf("/%s/host/%s/Resources", cluster.datacenter.GetName(), cluster.GetName()) + _, err = pool.Create(context.Background(), name, types.DefaultResourceConfigSpec()) + if err != nil { + return nil, errors.Wrap(err, "pool.Create") + } + + pools, err := cluster.ListResourcePools() + if err != nil { + return nil, errors.Wrap(err, "listResourcePools") + } + for i := range pools { + p := NewResourcePool(cluster.manager, &pools[i], cluster.datacenter) + if p.GetName() == name { + return &pools[i], nil + } + } + return nil, errors.Wrap(cloudprovider.ErrNotFound, "AfterCreate") +} + +func (cluster *SCluster) SyncResourcePool(name string) (*mo.ResourcePool, error) { + pools, err := cluster.ListResourcePools() + if err != nil { + return nil, errors.Wrap(err, "ListResourcePools") + } + for i := range pools { + if pools[i].Entity().Name == name { + return &pools[i], nil + } + } + return cluster.CreateResourcePool(name) +} + +func (cluster *SCluster) getoCluster() *mo.ClusterComputeResource { + return cluster.object.(*mo.ClusterComputeResource) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/datacenter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/datacenter.go new file mode 100644 index 0000000000..5403bef615 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/datacenter.go @@ -0,0 +1,596 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "regexp" + "strings" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/view" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/sets" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +var DATACENTER_PROPS = []string{"name", "parent", "datastore", "network"} + +type SDatacenter struct { + SManagedObject + + ihosts []cloudprovider.ICloudHost + istorages []cloudprovider.ICloudStorage + inetworks []IVMNetwork + iresoucePool []cloudprovider.ICloudProject + clusters []*SCluster + + Name string +} + +func newDatacenter(manager *SESXiClient, dc *mo.Datacenter) *SDatacenter { + obj := SDatacenter{SManagedObject: newManagedObject(manager, dc, nil)} + obj.datacenter = &obj + return &obj +} + +func (dc *SDatacenter) isDefaultDc() bool { + if dc.object == &defaultDc { + return true + } + return false +} + +func (dc *SDatacenter) getDatacenter() *mo.Datacenter { + return dc.object.(*mo.Datacenter) +} + +func (dc *SDatacenter) getObjectDatacenter() *object.Datacenter { + if dc.isDefaultDc() { + return nil + } + return object.NewDatacenter(dc.manager.client.Client, dc.object.Reference()) +} + +func (dc *SDatacenter) scanResourcePool() error { + if dc.iresoucePool == nil { + pools, err := dc.listResourcePools() + if err != nil { + return errors.Wrap(err, "listResourcePools") + } + dc.iresoucePool = []cloudprovider.ICloudProject{} + for i := 0; i < len(pools); i++ { + p := NewResourcePool(dc.manager, &pools[i], dc) + dc.iresoucePool = append(dc.iresoucePool, p) + } + } + return nil +} + +func (dc *SDatacenter) scanHosts() error { + if dc.ihosts == nil { + var hosts []mo.HostSystem + if dc.isDefaultDc() { + err := dc.manager.scanAllMObjects(HOST_SYSTEM_PROPS, &hosts) + if err != nil { + return errors.Wrap(err, "dc.manager.scanAllMObjects") + } + } else { + err := dc.manager.scanMObjects(dc.object.Entity().Self, HOST_SYSTEM_PROPS, &hosts) + if err != nil { + return errors.Wrap(err, "dc.manager.scanMObjects") + } + } + dc.ihosts = make([]cloudprovider.ICloudHost, 0) + for i := 0; i < len(hosts); i += 1 { + h := NewHost(dc.manager, &hosts[i], dc) + if h != nil { + dc.ihosts = append(dc.ihosts, h) + } + } + } + return nil +} + +func (dc *SDatacenter) GetResourcePools() ([]cloudprovider.ICloudProject, error) { + err := dc.scanResourcePool() + if err != nil { + return nil, errors.Wrap(err, "dc.scanResourcePool") + } + return dc.iresoucePool, nil +} + +func (dc *SDatacenter) listResourcePools() ([]mo.ResourcePool, error) { + var pools, result []mo.ResourcePool + err := dc.manager.scanMObjects(dc.object.Entity().Self, RESOURCEPOOL_PROPS, &pools) + if err != nil { + return nil, errors.Wrap(err, "scanMObjects") + } + for i := range pools { + if pools[i].Parent.Type == "ClusterComputeResource" { + continue + } + result = append(result, pools[i]) + } + return result, nil +} + +func (dc *SDatacenter) ListClusters() ([]*SCluster, error) { + return dc.listClusters() +} + +func (dc *SDatacenter) GetCluster(cluster string) (*SCluster, error) { + clusters, err := dc.ListClusters() + if err != nil { + return nil, errors.Wrap(err, "ListClusters") + } + for i := range clusters { + if clusters[i].GetName() == cluster { + return clusters[i], nil + } + + } + return nil, cloudprovider.ErrNotFound +} + +func (dc *SDatacenter) listClusters() ([]*SCluster, error) { + if dc.clusters != nil { + return dc.clusters, nil + } + clusters := []mo.ClusterComputeResource{} + err := dc.manager.scanMObjects(dc.object.Entity().Self, RESOURCEPOOL_PROPS, &clusters) + if err != nil { + return nil, errors.Wrap(err, "scanMObjects") + } + ret := []*SCluster{} + for i := range clusters { + c := NewCluster(dc.manager, &clusters[i], dc) + ret = append(ret, c) + } + return ret, nil +} + +func (dc *SDatacenter) GetIHosts() ([]cloudprovider.ICloudHost, error) { + err := dc.scanHosts() + if err != nil { + return nil, errors.Wrap(err, "dc.scanHosts") + } + return dc.ihosts, nil +} + +func (dc *SDatacenter) scanDatastores() error { + if dc.istorages == nil { + var stores []mo.Datastore + if dc.isDefaultDc() { + err := dc.manager.scanAllMObjects(DATASTORE_PROPS, &stores) + if err != nil { + return errors.Wrap(err, "dc.manager.scanAllMObjects") + } + } else { + dsList := dc.getDatacenter().Datastore + if dsList != nil { + err := dc.manager.references2Objects(dsList, DATASTORE_PROPS, &stores) + if err != nil { + return errors.Wrap(err, "dc.manager.references2Objects") + } + } + } + dc.istorages = make([]cloudprovider.ICloudStorage, 0) + for i := 0; i < len(stores); i += 1 { + ds := NewDatastore(dc.manager, &stores[i], dc) + dsId := ds.GetGlobalId() + if len(dsId) > 0 { + dc.istorages = append(dc.istorages, ds) + } + } + } + return nil +} + +func (dc *SDatacenter) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + err := dc.scanDatastores() + if err != nil { + return nil, errors.Wrap(err, "dc.scanDatastores") + } + return dc.istorages, nil +} + +func (dc *SDatacenter) GetIHostByMoId(idstr string) (cloudprovider.ICloudHost, error) { + ihosts, err := dc.GetIHosts() + if err != nil { + return nil, errors.Wrap(err, "dc.GetIHosts") + } + for i := 0; i < len(ihosts); i += 1 { + if ihosts[i].GetId() == idstr { + return ihosts[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (dc *SDatacenter) GetIStorageByMoId(idstr string) (cloudprovider.ICloudStorage, error) { + istorages, err := dc.GetIStorages() + if err != nil { + return nil, errors.Wrap(err, "dc.GetIStorages") + } + for i := 0; i < len(istorages); i += 1 { + if istorages[i].GetId() == idstr { + return istorages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (dc *SDatacenter) getDcObj() *object.Datacenter { + if dc.isDefaultDc() { + return nil + } + return object.NewDatacenter(dc.manager.client.Client, dc.object.Reference()) +} + +func (dc *SDatacenter) fetchMoVms(filter property.Filter, props []string) ([]mo.VirtualMachine, error) { + odc := dc.getObjectDatacenter() + root := odc.Reference() + var movms []mo.VirtualMachine + err := dc.manager.scanMObjectsWithFilter(root, props, &movms, filter) + if err != nil { + return nil, errors.Wrap(err, "scanMObjectsWithFilter") + } + return movms, nil +} + +func (dc *SDatacenter) moVms2Vm(movms []mo.VirtualMachine, all *bool) ([]*SVirtualMachine, error) { + // avoid applying new memory and copying + vms := make([]*SVirtualMachine, 0, len(movms)) + for i := range movms { + if (all != nil && *all) || !strings.HasPrefix(movms[i].Name, api.ESXI_IMAGE_CACHE_TMP_PREFIX) { + vm := NewVirtualMachine(dc.manager, &movms[i], dc) + // must + if vm == nil { + continue + } + vms = append(vms, vm) + } + } + return vms, nil +} + +func (dc *SDatacenter) fetchFakeTemplateVMs(movms []mo.VirtualMachine, regex string) ([]*SVirtualMachine, error) { + var ( + tNameRegex *regexp.Regexp + err error + ) + if len(regex) == 0 { + tNameRegex = tempalteNameRegex + } else { + tNameRegex, err = regexp.Compile(regex) + if err != nil { + return nil, errors.Wrap(err, "generate regexp") + } + } + objs := make([]types.ManagedObjectReference, 0) + for i := range movms { + name := movms[i].Name + if tNameRegex != nil && tNameRegex.MatchString(name) { + objs = append(objs, movms[i].Reference()) + } + } + if len(objs) == 0 { + return nil, nil + } + return dc.fetchVms(objs, false) +} + +func (dc *SDatacenter) fetchVmsFromCache(vmRefs []types.ManagedObjectReference) ([]*SVirtualMachine, error) { + vmRefSet := sets.NewString() + for i := range vmRefs { + vmRefSet.Insert(vmRefs[i].String()) + } + ihosts, err := dc.GetIHosts() + if err != nil { + return nil, err + } + ret := make([]*SVirtualMachine, 0, len(vmRefs)) + for i := range ihosts { + ivms, err := ihosts[i].GetIVMs() + if err != nil { + return nil, err + } + for i := range ivms { + vm := ivms[i].(*SVirtualMachine) + s := vm.getVirtualMachine().Self.String() + if vmRefSet.Has(s) { + ret = append(ret, vm) + vmRefSet.Delete(s) + } + } + } + return ret, nil +} + +func (dc *SDatacenter) fetchVms(vmRefs []types.ManagedObjectReference, all bool) ([]*SVirtualMachine, error) { + var movms []mo.VirtualMachine + if vmRefs != nil { + err := dc.manager.references2Objects(vmRefs, VIRTUAL_MACHINE_PROPS, &movms) + if err != nil { + return nil, errors.Wrap(err, "dc.manager.references2Objects") + } + } + return dc.moVms2Vm(movms, &all) +} + +func (dc *SDatacenter) fetchHosts_(vmRefs []types.ManagedObjectReference, all bool) ([]*SHost, error) { + var movms []mo.HostSystem + if vmRefs != nil { + err := dc.manager.references2Objects(vmRefs, VIRTUAL_MACHINE_PROPS, &movms) + if err != nil { + return nil, errors.Wrap(err, "dc.manager.references2Objects") + } + } + + // avoid applying new memory and copying + vms := make([]*SHost, 0, len(movms)) + for i := range movms { + if all || !strings.HasPrefix(movms[i].Entity().Name, api.ESXI_IMAGE_CACHE_TMP_PREFIX) { + vms = append(vms, NewHost(dc.manager, &movms[i], dc)) + } + } + return vms, nil +} + +func (dc *SDatacenter) FetchVMs() ([]*SVirtualMachine, error) { + return dc.fetchVMsWithFilter(property.Filter{}) +} + +func (dc *SDatacenter) FetchNoTemplateVMs() ([]*SVirtualMachine, error) { + filter := property.Filter{} + filter["config.template"] = false + return dc.fetchVMsWithFilter(filter) +} + +func (dc *SDatacenter) FetchFakeTempateVMs(regex string) ([]*SVirtualMachine, error) { + filter := property.Filter{} + filter["summary.runtime.powerState"] = types.VirtualMachinePowerStatePoweredOff + movms, err := dc.fetchMoVms(filter, []string{"name"}) + if err != nil { + return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines") + } + return dc.fetchFakeTemplateVMs(movms, regex) +} + +func (dc *SDatacenter) fetchVMsWithFilter(filter property.Filter) ([]*SVirtualMachine, error) { + movms, err := dc.fetchMoVms(filter, VIRTUAL_MACHINE_PROPS) + if err != nil { + return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines") + } + ret, err := dc.moVms2Vm(movms, nil) + if err != nil { + return nil, errors.Wrap(err, "unable to convert mo.VirtualMachine to VirtualMachine") + } + return ret, err +} + +func (dc *SDatacenter) FetchNoTemplateVMEntityReferens() ([]types.ManagedObjectReference, error) { + filter := property.Filter{} + filter["config.template"] = false + odc := dc.getObjectDatacenter() + root := odc.Reference() + m := view.NewManager(dc.manager.client.Client) + v, err := m.CreateContainerView(dc.manager.context, root, []string{"VirtualMachine"}, true) + if err != nil { + return nil, err + } + defer func() { + _ = v.Destroy(dc.manager.context) + }() + objs, err := v.Find(dc.manager.context, []string{"VirtualMachine"}, filter) + if err != nil { + return nil, err + } + return objs, nil +} + +func (dc *SDatacenter) FetchNoTemplateHostEntityReferens() ([]types.ManagedObjectReference, error) { + filter := property.Filter{} + odc := dc.getObjectDatacenter() + root := odc.Reference() + m := view.NewManager(dc.manager.client.Client) + v, err := m.CreateContainerView(dc.manager.context, root, []string{"HostSystem"}, true) + if err != nil { + return nil, err + } + defer func() { + _ = v.Destroy(dc.manager.context) + }() + objs, err := v.Find(dc.manager.context, []string{"HostSystem"}, filter) + if err != nil { + return nil, err + } + return objs, nil +} + +func (dc *SDatacenter) fetchHosts(filter property.Filter) ([]*SHost, error) { + odc := dc.getObjectDatacenter() + root := odc.Reference() + m := view.NewManager(dc.manager.client.Client) + v, err := m.CreateContainerView(dc.manager.context, root, []string{"HostSystem"}, true) + if err != nil { + return nil, err + } + defer func() { + _ = v.Destroy(dc.manager.context) + }() + objs, err := v.Find(dc.manager.context, []string{"HostSystem"}, filter) + if err != nil { + return nil, err + } + hosts, err := dc.fetchHosts_(objs, false) + return hosts, err +} + +func (dc *SDatacenter) FetchTemplateVMs() ([]*SVirtualMachine, error) { + filter := property.Filter{} + filter["config.template"] = true + return dc.fetchVMsWithFilter(filter) +} + +func (dc *SDatacenter) FetchTemplateVMById(id string) (*SVirtualMachine, error) { + filter := property.Filter{} + filter["config.template"] = true + filter["summary.config.uuid"] = id + vms, err := dc.fetchVMsWithFilter(filter) + if err != nil { + return nil, err + } + if len(vms) == 0 { + return nil, errors.ErrNotFound + } + return vms[0], nil +} + +func (dc *SDatacenter) FetchVMById(id string) (*SVirtualMachine, error) { + filter := property.Filter{} + filter["summary.config.uuid"] = id + vms, err := dc.fetchVMsWithFilter(filter) + if err != nil { + return nil, err + } + if len(vms) == 0 { + return nil, errors.ErrNotFound + } + return vms[0], nil +} + +func (dc *SDatacenter) fetchDatastores(datastoreRefs []types.ManagedObjectReference) ([]cloudprovider.ICloudStorage, error) { + var dss []mo.Datastore + if datastoreRefs != nil { + err := dc.manager.references2Objects(datastoreRefs, DATASTORE_PROPS, &dss) + if err != nil { + return nil, errors.Wrap(err, "dc.manager.references2Objects") + } + } + + retDatastores := make([]cloudprovider.ICloudStorage, 0, len(dss)) + for i := range dss { + retDatastores = append(retDatastores, NewDatastore(dc.manager, &dss[i], dc)) + } + return retDatastores, nil +} + +func (dc *SDatacenter) scanNetworks() error { + if dc.inetworks == nil { + if dc.isDefaultDc() { + return dc.scanDefaultNetworks() + } else { + return dc.scanDcNetworks() + } + } + return nil +} + +func (dc *SDatacenter) scanDefaultNetworks() error { + dc.inetworks = make([]IVMNetwork, 0) + err := dc.scanAllDvPortgroups() + if err != nil { + return errors.Wrap(err, "dc.scanAllDvPortgroups") + } + err = dc.scanAllNetworks() + if err != nil { + return errors.Wrap(err, "dc.scanAllNetworks") + } + return nil +} + +func (dc *SDatacenter) scanAllDvPortgroups() error { + var dvports []mo.DistributedVirtualPortgroup + + err := dc.manager.scanAllMObjects(DVPORTGROUP_PROPS, &dvports) + if err != nil { + return errors.Wrap(err, "dc.manager.scanAllMObjects mo.DistributedVirtualPortgroup") + } + for i := range dvports { + net := NewDistributedVirtualPortgroup(dc.manager, &dvports[i], dc) + dc.inetworks = append(dc.inetworks, net) + } + return nil +} + +func (dc *SDatacenter) scanAllNetworks() error { + var nets []mo.Network + + err := dc.manager.scanAllMObjects(NETWORK_PROPS, &nets) + if err != nil { + return errors.Wrap(err, "dc.manager.scanAllMObjects mo.Network") + } + for i := range nets { + net := NewNetwork(dc.manager, &nets[i], dc) + dc.inetworks = append(dc.inetworks, net) + } + return nil +} + +func (dc *SDatacenter) scanDcNetworks() error { + dc.inetworks = make([]IVMNetwork, 0) + + netMOBs := dc.getDatacenter().Network + for i := range netMOBs { + dvport := mo.DistributedVirtualPortgroup{} + err := dc.manager.reference2Object(netMOBs[i], DVPORTGROUP_PROPS, &dvport) + if err == nil { + net := NewDistributedVirtualPortgroup(dc.manager, &dvport, dc) + dc.inetworks = append(dc.inetworks, net) + } else { + net := mo.Network{} + err = dc.manager.reference2Object(netMOBs[i], NETWORK_PROPS, &net) + if err == nil { + vnet := NewNetwork(dc.manager, &net, dc) + dc.inetworks = append(dc.inetworks, vnet) + } else { + return errors.Wrap(err, "dc.manager.reference2Object") + } + } + } + return nil +} + +func (dc *SDatacenter) GetNetworks() ([]IVMNetwork, error) { + err := dc.scanNetworks() + if err != nil { + return nil, errors.Wrap(err, "dc.scanNetworks") + } + return dc.inetworks, nil +} + +func (dc *SDatacenter) GetTemplateVMs() ([]*SVirtualMachine, error) { + hosts, err := dc.GetIHosts() + if err != nil { + return nil, errors.Wrap(err, "SDatacenter.GetIHosts") + } + templateVms := make([]*SVirtualMachine, 5) + for _, ihost := range hosts { + host := ihost.(*SHost) + tvms, err := host.GetTemplateVMs() + if err != nil { + return nil, errors.Wrap(err, "host.GetTemplateVMs") + } + templateVms = append(templateVms, tvms...) + } + return templateVms, nil +} diff --git a/pkg/multicloud/esxi/device.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/device.go similarity index 100% rename from pkg/multicloud/esxi/device.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/device.go diff --git a/pkg/multicloud/esxi/devtools.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/devtools.go similarity index 100% rename from pkg/multicloud/esxi/devtools.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/devtools.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/doc.go new file mode 100644 index 0000000000..e687854597 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 esxi // import "yunion.io/x/cloudmux/pkg/multicloud/esxi" diff --git a/pkg/multicloud/esxi/fakeregion.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/fakeregion.go similarity index 97% rename from pkg/multicloud/esxi/fakeregion.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/fakeregion.go index ecaaca8394..50b5a2bc45 100644 --- a/pkg/multicloud/esxi/fakeregion.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/fakeregion.go @@ -18,8 +18,8 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) func (cli *SESXiClient) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { diff --git a/pkg/multicloud/esxi/guestos.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/guestos.go similarity index 100% rename from pkg/multicloud/esxi/guestos.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/guestos.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/host.go new file mode 100644 index 0000000000..f3abd76bcd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/host.go @@ -0,0 +1,1769 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "context" + "fmt" + "regexp" + "strings" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + "yunion.io/x/pkg/util/regutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var ( + hostConfigProps = []string{"config.network", "config.storageDevice"} + hostSummaryProps = []string{"summary.runtime", "summary.hardware", "summary.config.product", "summary.managementServerIp"} + hostHardWareProps = []string{"hardware.systemInfo"} +) + +var HOST_SYSTEM_PROPS []string + +func init() { + HOST_SYSTEM_PROPS = []string{"name", "parent", "vm", "datastore", "network"} + HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostConfigProps...) + HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostSummaryProps...) + HOST_SYSTEM_PROPS = append(HOST_SYSTEM_PROPS, hostHardWareProps...) +} + +type SHostStorageAdapterInfo struct { + Device string + Model string + Driver string + Pci string + Drivers []*SHostStorageDriverInfo + Enclosure int +} + +type SHostStorageDriverInfo struct { + CN string + Name string + Model string + Vendor string + Revision string + Status string + SSD bool + Dev string + Size int + Slot int +} + +type SHostStorageEnclosureInfo struct { + CN string + Name string + Model string + Vendor string + Revision string + Status string +} + +type SHostStorageInfo struct { + Adapter int + Driver string + Index int + Model string + Rotate bool + Status string + Size int +} + +type SHost struct { + multicloud.SHostBase + SManagedObject + + masterIp string + + nicInfo []SHostNicInfo + storageInfo []SHostStorageInfo + datastores []cloudprovider.ICloudStorage + storageCache *SDatastoreImageCache + vms []cloudprovider.ICloudVM + parent *mo.ComputeResource + networks []IVMNetwork + tempalteVMs []*SVirtualMachine +} + +func NewHost(manager *SESXiClient, host *mo.HostSystem, dc *SDatacenter) *SHost { + if host.Config == nil { + log.Errorf("empty host config %s", host.Name) + return nil + } + return &SHost{SManagedObject: newManagedObject(manager, host, dc)} +} + +var ( + ip4addrPattern = regexp.MustCompile(`\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}`) +) + +func formatName(name string) string { + if ip4addrPattern.MatchString(name) { + return strings.Replace(name, ".", "-", -1) + } else { + dotPos := strings.IndexByte(name, '.') + if dotPos > 0 && !regutils.MatchIP4Addr(name) { + name = name[:dotPos] + } + return name + } +} + +func (self *SHost) GetName() string { + return formatName(self.SManagedObject.GetName()) +} + +func (self *SHost) GetSchedtags() ([]string, error) { + clusters, err := self.datacenter.listClusters() + if err != nil { + return nil, err + } + cpName := self.datacenter.manager.cpcfg.Name + reference := self.GetoHostSystem().Reference() + tags := make([]string, 0, 1) + oDatacenter := self.datacenter.getDatacenter() +Loop: + for i := range clusters { + oc := clusters[i].getoCluster() + if len(oc.Host) == 0 { + continue + } + for _, h := range oc.Host { + if h == reference { + tags = append(tags, fmt.Sprintf("cluster:/%s/%s/%s", cpName, oDatacenter.Name, oc.Name)) + continue Loop + } + } + } + return tags, nil +} + +func (self *SHost) getHostSystem() *mo.HostSystem { + return self.object.(*mo.HostSystem) +} + +func (self *SHost) GetGlobalId() string { + return self.GetAccessIp() +} + +func (self *SHost) GetStatus() string { + /* + HostSystemPowerStatePoweredOn = HostSystemPowerState("poweredOn") + HostSystemPowerStatePoweredOff = HostSystemPowerState("poweredOff") + HostSystemPowerStateStandBy = HostSystemPowerState("standBy") + HostSystemPowerStateUnknown = HostSystemPowerState("unknown") + */ + switch self.getHostSystem().Summary.Runtime.PowerState { + case types.HostSystemPowerStatePoweredOn: + return api.HOST_STATUS_RUNNING + case types.HostSystemPowerStatePoweredOff: + return api.HOST_STATUS_READY + default: + return api.HOST_STATUS_UNKNOWN + } +} + +func (self *SHost) Refresh() error { + base := self.SManagedObject + var moObj mo.HostSystem + err := self.manager.reference2Object(self.object.Reference(), HOST_SYSTEM_PROPS, &moObj) + if err != nil { + return err + } + base.object = &moObj + *self = SHost{} + self.SManagedObject = base + return nil +} + +func (self *SHost) IsEmulated() bool { + return false +} + +func (self *SHost) fetchVMs(all bool) error { + if self.vms != nil { + return nil + } + + dc, err := self.GetDatacenter() + if err != nil { + return err + } + + var vms []*SVirtualMachine + hostVms := self.getHostSystem().Vm + if len(hostVms) == 0 { + // log.Errorf("host VMs are nil!!!!!") + return nil + } + + vms, err = dc.fetchVms(hostVms, all) + if err != nil { + return err + } + for _, vm := range vms { + if vm.IsTemplate() { + self.tempalteVMs = append(self.tempalteVMs, vm) + } else { + self.vms = append(self.vms, vm) + } + } + return nil +} + +func (self *SHost) GetIVMs2() ([]cloudprovider.ICloudVM, error) { + err := self.fetchVMs(true) + if err != nil { + return nil, err + } + return self.vms, nil +} + +func (self *SHost) GetTemplateVMs() ([]*SVirtualMachine, error) { + err := self.fetchVMs(false) + if err != nil { + return nil, errors.Wrap(err, "SHost.fetchVMs") + } + return self.tempalteVMs, nil +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + err := self.fetchVMs(false) + if err != nil { + return nil, err + } + return self.vms, nil +} + +func (self *SHost) GetTemplateVMById(id string) (*SVirtualMachine, error) { + id = self.manager.getPrivateId(id) + temVms, err := self.GetTemplateVMs() + if err != nil { + return nil, err + } + for i := range temVms { + if temVms[i].GetGlobalId() == id { + return temVms[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + id = self.manager.getPrivateId(id) + + vms, err := self.GetIVMs() + if err != nil { + return nil, err + } + for i := 0; i < len(vms); i += 1 { + if vms[i].GetGlobalId() == id { + return vms[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + return self.GetDataStores() +} + +func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + istorages, err := self.GetIStorages() + if err != nil { + return nil, err + } + for i := 0; i < len(istorages); i += 1 { + if istorages[i].GetGlobalId() == id { + return istorages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHost) GetEnabled() bool { + if self.getHostSystem().Summary.Runtime.InMaintenanceMode { + return false + } + return true +} + +func (self *SHost) GetHostStatus() string { + /* + HostSystemConnectionStateConnected = HostSystemConnectionState("connected") + HostSystemConnectionStateNotResponding = HostSystemConnectionState("notResponding") + HostSystemConnectionStateDisconnected = HostSystemConnectionState("disconnected") + */ + if self.getHostSystem().Summary.Runtime.InMaintenanceMode { + return api.HOST_OFFLINE + } + switch self.getHostSystem().Summary.Runtime.ConnectionState { + case types.HostSystemConnectionStateConnected: + return api.HOST_ONLINE + default: + return api.HOST_OFFLINE + } +} + +func findHostNicByMac(nicInfoList []SHostNicInfo, mac string) *SHostNicInfo { + for i := 0; i < len(nicInfoList); i += 1 { + if nicInfoList[i].Mac == mac { + return &nicInfoList[i] + } + } + return nil +} + +func (self *SHost) getAdminNic() *SHostNicInfo { + nics := self.getNicInfo(false) + for i := 0; i < len(nics); i += 1 { + if nics[i].NicType == api.NIC_TYPE_ADMIN { + return &nics[i] + } + } + for i := 0; i < len(nics); i += 1 { + if len(nics[i].IpAddr) > 0 { + return &nics[i] + } + } + return nil +} + +func (self *SHost) getNicInfo(debug bool) []SHostNicInfo { + if self.nicInfo == nil { + self.nicInfo = self.fetchNicInfo(debug) + } + return self.nicInfo +} + +func mask2len(mask string) int8 { + maskAddr, _ := netutils.NewIPV4Addr(mask) + return netutils.Mask2Len(maskAddr) +} + +func (self *SHost) isVnicAdmin(nic types.HostVirtualNic) bool { + if len(self.masterIp) > 0 { + if self.masterIp == nic.Spec.Ip.IpAddress { + return true + } else { + return false + } + } + exist, err := self.manager.IsHostIpExists(nic.Spec.Ip.IpAddress) + if err != nil { + log.Errorf("IsHostIpExists %s fail %s", nic.Spec.Ip.IpAddress, err) + return false + } + if exist { + self.masterIp = nic.Spec.Ip.IpAddress + return true + } + return false +} + +func (self *SHost) fetchNicInfo(debug bool) []SHostNicInfo { + moHost := self.getHostSystem() + + if moHost.Config == nil || moHost.Config.Network == nil { + return nil + } + + if debug { + log.Debugf("%s", jsonutils.Marshal(moHost.Config.Network).PrettyString()) + } + + nicInfoList := make([]SHostNicInfo, 0) + + for i, nic := range moHost.Config.Network.Pnic { + info := SHostNicInfo{} + info.Dev = nic.Device + info.Driver = nic.Driver + info.Mac = netutils.FormatMacAddr(nic.Mac) + info.Index = int8(i) + info.LinkUp = false + nicInfoList = append(nicInfoList, info) + } + + vnics := make([]types.HostVirtualNic, 0) + if len(moHost.Config.Network.Vnic) > 0 { + vnics = append(vnics, moHost.Config.Network.Vnic...) + } + if len(moHost.Config.Network.ConsoleVnic) > 0 { + vnics = append(vnics, moHost.Config.Network.ConsoleVnic...) + } + + for _, nic := range vnics { + mac := netutils.FormatMacAddr(nic.Spec.Mac) + pnic := findHostNicByMac(nicInfoList, mac) + if pnic != nil { + // findMaster = true + pnic.IpAddr = nic.Spec.Ip.IpAddress + pnic.IpAddrPrefixLen = mask2len(nic.Spec.Ip.SubnetMask) + if nic.Spec.Ip.IpV6Config != nil && len(nic.Spec.Ip.IpV6Config.IpV6Address) > 0 { + pnic.IpAddr6 = nic.Spec.Ip.IpV6Config.IpV6Address[0].IpAddress + pnic.IpAddr6PrefixLen = int8(nic.Spec.Ip.IpV6Config.IpV6Address[0].PrefixLength) + } + if self.isVnicAdmin(nic) { + pnic.NicType = api.NIC_TYPE_ADMIN + } + pnic.LinkUp = true + pnic.Mtu = nic.Spec.Mtu + if nic.Spec.DistributedVirtualPort != nil { + pnic.DVPortGroup = nic.Spec.DistributedVirtualPort.PortgroupKey + } + } else { + info := SHostNicInfo{} + info.Dev = nic.Device + info.Driver = "vmkernel" + info.Mac = mac + info.Index = int8(len(nicInfoList)) + info.LinkUp = true + info.IpAddr = nic.Spec.Ip.IpAddress + info.IpAddrPrefixLen = mask2len(nic.Spec.Ip.SubnetMask) + if nic.Spec.Ip.IpV6Config != nil && len(nic.Spec.Ip.IpV6Config.IpV6Address) > 0 { + info.IpAddr6 = nic.Spec.Ip.IpV6Config.IpV6Address[0].IpAddress + info.IpAddr6PrefixLen = int8(nic.Spec.Ip.IpV6Config.IpV6Address[0].PrefixLength) + } + info.Mtu = nic.Spec.Mtu + if self.isVnicAdmin(nic) { + info.NicType = api.NIC_TYPE_ADMIN + } + if nic.Spec.DistributedVirtualPort != nil { + info.DVPortGroup = nic.Spec.DistributedVirtualPort.PortgroupKey + } + nicInfoList = append(nicInfoList, info) + } + } + + return nicInfoList +} + +func (self *SHost) GetAccessIp() string { + adminNic := self.getAdminNic() + if adminNic != nil { + return adminNic.IpAddr + } + return "" +} + +func (self *SHost) GetAccessMac() string { + adminNic := self.getAdminNic() + if adminNic != nil { + return adminNic.Mac + } + return "" +} + +type SSysInfo struct { + Manufacture string + Model string + SerialNumber string +} + +func (self *SHost) GetSysInfo() jsonutils.JSONObject { + sysinfo := SSysInfo{} + host := self.getHostSystem() + sysinfo.Manufacture = host.Summary.Hardware.Vendor + sysinfo.Model = host.Summary.Hardware.Model + if host.Hardware != nil { + sysinfo.SerialNumber = host.Hardware.SystemInfo.SerialNumber + } + return jsonutils.Marshal(&sysinfo) +} + +func (self *SHost) GetSN() string { + host := self.getHostSystem() + if host.Hardware != nil { + return host.Hardware.SystemInfo.SerialNumber + } + return "" +} + +func (self *SHost) GetCpuCount() int { + return int(self.getHostSystem().Summary.Hardware.NumCpuThreads) +} + +func (self *SHost) GetNodeCount() int8 { + return int8(self.getHostSystem().Summary.Hardware.NumCpuPkgs) +} + +func (self *SHost) GetCpuDesc() string { + return self.getHostSystem().Summary.Hardware.CpuModel +} + +func (self *SHost) GetCpuMhz() int { + return int(self.getHostSystem().Summary.Hardware.CpuMhz) +} + +func (self *SHost) GetMemSizeMB() int { + return int(self.getHostSystem().Summary.Hardware.MemorySize / 1024 / 1024) +} + +func (self *SHost) GetStorageInfo() []SHostStorageInfo { + if self.storageInfo == nil { + self.storageInfo = self.getStorageInfo() + } + return self.storageInfo +} + +func (self *SHost) getStorageInfo() []SHostStorageInfo { + diskSlots := make(map[int]SHostStorageInfo) + list := self.getStorages() + for i := 0; i < len(list); i += 1 { + for j := 0; j < len(list[i].Drivers); j += 1 { + drv := list[i].Drivers[j] + info := SHostStorageInfo{ + Adapter: 0, + Driver: "Linux", + Index: drv.Slot, + Model: strings.TrimSpace(fmt.Sprintf("%s %s", drv.Vendor, drv.Model)), + Rotate: !drv.SSD, + Status: drv.Status, + Size: drv.Size, + } + diskSlots[info.Index] = info + } + } + disks := make([]SHostStorageInfo, 0) + idx := 0 + for { + if info, ok := diskSlots[idx]; ok { + disks = append(disks, info) + idx += 1 + } else { + break + } + } + return disks +} + +func (self *SHost) getStorages() []*SHostStorageAdapterInfo { + adapterList := make([]*SHostStorageAdapterInfo, 0) + adapterTable := make(map[string]*SHostStorageAdapterInfo) + driversTable := make(map[string]*SHostStorageDriverInfo, 0) + enclosuresTable := make(map[string]*SHostStorageEnclosureInfo, 0) + moHost := self.getHostSystem() + + for i := 0; i < len(moHost.Config.StorageDevice.HostBusAdapter); i += 1 { + ad := moHost.Config.StorageDevice.HostBusAdapter[i] + adinfo := ad.GetHostHostBusAdapter() + if adinfo == nil { + log.Errorf("fail to GetHostHostBusAdapter") + continue + } + info := SHostStorageAdapterInfo{} + info.Device = adinfo.Device + info.Model = strings.TrimSpace(adinfo.Model) + info.Driver = adinfo.Driver + info.Pci = adinfo.Pci + info.Drivers = make([]*SHostStorageDriverInfo, 0) + info.Enclosure = -1 + + adapterTable[adinfo.Key] = &info + adapterList = append(adapterList, &info) + } + + for i := 0; i < len(moHost.Config.StorageDevice.ScsiLun); i += 1 { + drv := moHost.Config.StorageDevice.ScsiLun[i] + lunInfo := drv.GetScsiLun() + if lunInfo == nil { + log.Errorf("fail to GetScsiLun") + continue + } + + if lunInfo.DeviceType == "disk" { + scsiDisk := drv.(*types.HostScsiDisk) + info := SHostStorageDriverInfo{} + info.CN = scsiDisk.CanonicalName + info.Name = scsiDisk.DisplayName + info.Model = strings.TrimSpace(scsiDisk.Model) + info.Vendor = strings.TrimSpace(scsiDisk.Vendor) + info.Revision = scsiDisk.Revision + info.Status = scsiDisk.OperationalState[0] + if scsiDisk.Ssd != nil && *scsiDisk.Ssd { + info.SSD = true + } + info.Dev = scsiDisk.DevicePath + info.Size = int(int64(scsiDisk.Capacity.BlockSize) * scsiDisk.Capacity.Block / 1024 / 1024) + + driversTable[scsiDisk.Key] = &info + } else if lunInfo.DeviceType == "enclosure" { + enclosuresTable[lunInfo.Key] = &SHostStorageEnclosureInfo{ + CN: lunInfo.CanonicalName, + Name: lunInfo.DisplayName, + Model: strings.TrimSpace(lunInfo.Model), + Vendor: strings.TrimSpace(lunInfo.Vendor), + Revision: lunInfo.Revision, + Status: lunInfo.OperationalState[0], + } + } + } + for i := 0; i < len(moHost.Config.StorageDevice.ScsiTopology.Adapter); i += 1 { + ad := moHost.Config.StorageDevice.ScsiTopology.Adapter[i] + adapter := adapterTable[ad.Adapter] + for j := 0; j < len(ad.Target); j += 1 { + t := ad.Target[j] + key := t.Lun[0].ScsiLun + if _, ok := enclosuresTable[key]; ok { + adapter.Enclosure = int(t.Target) + } else if _, ok := driversTable[key]; ok { + driver := driversTable[key] + driver.Slot = int(t.Target) + adapter.Drivers = append(adapter.Drivers, driver) + } + } + } + return adapterList +} + +func (self *SHost) GetStorageSizeMB() int { + storages, err := self.GetIStorages() + if err != nil { + log.Errorf("SHost.GetStorageSizeMB: SHost.GetIStorages: %s", err) + return 0 + } + var size int64 + for _, stor := range storages { + size += stor.GetCapacityMB() + } + return int(size) +} + +func (self *SHost) GetStorageType() string { + ssd := 0 + rotate := 0 + storages := self.GetStorageInfo() + for i := 0; i < len(storages); i += 1 { + if storages[i].Rotate { + rotate += 1 + } else { + ssd += 1 + } + } + if ssd == 0 && rotate > 0 { + return api.DISK_TYPE_ROTATE + } else if ssd > 0 && rotate == 0 { + return api.DISK_TYPE_SSD + } else { + return api.DISK_TYPE_HYBRID + } +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_ESXI +} + +func (self *SHost) GetIsMaintenance() bool { + moHost := self.getHostSystem() + return moHost.Summary.Runtime.InMaintenanceMode +} + +func (self *SHost) GetVersion() string { + moHost := self.getHostSystem() + about := moHost.Summary.Config.Product + return fmt.Sprintf("%s-%s", about.Version, about.Build) +} + +func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + return nil, cloudprovider.ErrNotImplemented +} + +type SCreateVMParam struct { + Name string + Uuid string + OsName string + Cpu int + Mem int + Bios string + Cdrom SCdromInfo + Disks []SDiskInfo + Nics []jsonutils.JSONObject + ResourcePool string + InstanceSnapshotInfo SEsxiInstanceSnapshotInfo +} + +type SEsxiInstanceSnapshotInfo struct { + InstanceSnapshotId string + InstanceId string +} + +type SCdromInfo struct { + ImageId string + Path string + Name string + Size string +} + +type SDiskInfo struct { + ImagePath string + Size int64 + DiskId string + Driver string + ImageInfo SEsxiImageInfo + StorageId string +} + +type SEsxiImageInfo struct { + ImageType string + ImageExternalId string + StorageCacheHostIp string +} + +func (self *SHost) CreateVM2(ctx context.Context, ds *SDatastore, params SCreateVMParam) (needDeploy bool, vm *SVirtualMachine, err error) { + needDeploy = true + var temvm *SVirtualMachine + if len(params.InstanceSnapshotInfo.InstanceSnapshotId) > 0 { + temvm, err = self.manager.SearchVM(params.InstanceSnapshotInfo.InstanceId) + if err != nil { + err = errors.Wrapf(err, "can't find vm %q, please sync status for vm or sync cloudaccount", params.InstanceSnapshotInfo.InstanceId) + } + var isp cloudprovider.ICloudInstanceSnapshot + isp, err = temvm.GetInstanceSnapshot(params.InstanceSnapshotInfo.InstanceSnapshotId) + if err != nil { + err = errors.Wrap(err, "unable to GetInstanceSnapshot") + return + } + sp := isp.(*SVirtualMachineSnapshot) + vm, err = self.CloneVM(ctx, temvm, &sp.snapshotTree.Snapshot, ds, params) + return + } + if len(params.Disks) == 0 { + err = errors.Error("empty disk config") + return + } + imageInfo := params.Disks[0].ImageInfo + if imageInfo.ImageType == string(cloudprovider.ImageTypeSystem) { + temvm, err = self.manager.SearchTemplateVM(imageInfo.ImageExternalId) + if err != nil { + err = errors.Wrapf(err, "SEsxiClient.SearchTemplateVM for image %q", imageInfo.ImageExternalId) + return + } + vm, err = self.CloneVM(ctx, temvm, nil, ds, params) + return + } + return self.DoCreateVM(ctx, ds, params) +} + +func (self *SHost) needScsi(disks []SDiskInfo) bool { + if len(disks) == 0 { + return false + } + for i := range disks { + driver := disks[i].Driver + if driver == "" || driver == "scsi" || driver == "pvscsi" { + return true + } + } + return false +} + +func (self *SHost) addDisks(ctx context.Context, dc *SDatacenter, ds *SDatastore, disks []SDiskInfo, uuid string, objectVm *object.VirtualMachine) (*SVirtualMachine, error) { + getVM := func() (*SVirtualMachine, error) { + var moVM mo.VirtualMachine + err := self.manager.reference2Object(objectVm.Reference(), VIRTUAL_MACHINE_PROPS, &moVM) + if err != nil { + return nil, errors.Wrap(err, "fail to fetch virtual machine just created") + } + + evm := NewVirtualMachine(self.manager, &moVM, self.datacenter) + if evm == nil { + return nil, errors.Error("create successfully but unable to NewVirtualMachine") + } + return evm, nil + } + + if len(disks) == 0 { + return getVM() + } + + var ( + scsiIdx = 0 + ideIdx = 0 + ide1un = 0 + ide2un = 1 + unitNumber = 0 + ctrlKey = 0 + ) + deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 1) + // add disks + var rootDiskSizeMb int64 + for i, disk := range disks { + imagePath := disk.ImagePath + var size = disk.Size + if len(imagePath) == 0 { + if size == 0 { + size = 30 * 1024 + } + } else { + var err error + imagePath, err = self.FileUrlPathToDsPath(imagePath) + if err != nil { + return nil, errors.Wrapf(err, "SHost.FileUrlPathToDsPath") + } + newImagePath := fmt.Sprintf("[%s] %s/%s.vmdk", ds.GetRelName(), uuid, uuid) + + err = self.copyVirtualDisk(imagePath, newImagePath, disk.Driver) + if err != nil { + return nil, err + } + imagePath = newImagePath + rootDiskSizeMb = size + } + uuid, driver := disk.DiskId, "scsi" + if len(disk.Driver) > 0 { + driver = disk.Driver + } + if driver == "scsi" || driver == "pvscsi" { + if self.isVersion50() { + driver = "scsi" + } + ctrlKey = 1000 + unitNumber = scsiIdx + scsiIdx += 1 + if scsiIdx == 7 { + scsiIdx++ + } + } else { + ideno := ideIdx % 2 + if ideno == 0 { + unitNumber = ideIdx/2 + ide1un + } else { + unitNumber = ideIdx/2 + ide2un + } + ctrlKey = 200 + ideno + ideIdx += 1 + } + var tds *SDatastore + var err error + if disk.StorageId != "" { + tds, err = self.FindDataStoreById(disk.StorageId) + if err != nil { + return nil, errors.Wrapf(err, "unable to find ds %s from host %s", disk.StorageId, self.masterIp) + } + } else { + tds = ds + } + log.Debugf("ds: %s, size: %d, image path: %s, uuid: %s, index: %d, ctrlKey: %d, driver: %s, key: %d.", tds.getDatastoreObj().String(), size, imagePath, uuid, unitNumber, ctrlKey, disk.Driver, 2000+i) + spec := addDevSpec(NewDiskDev(size, SDiskConfig{ + SizeMb: size, + Uuid: uuid, + ControllerKey: int32(ctrlKey), + UnitNumber: int32(unitNumber), + Key: int32(2000 + i), + ImagePath: imagePath, + IsRoot: i == 0, + Datastore: tds, + })) + if len(imagePath) == 0 { + spec.FileOperation = "create" + } + deviceChange = append(deviceChange, spec) + } + log.Infof("deviceChange: %s", jsonutils.Marshal(deviceChange)) + + configSpec := types.VirtualMachineConfigSpec{} + configSpec.DeviceChange = deviceChange + task, err := objectVm.Reconfigure(ctx, configSpec) + if err != nil { + return nil, errors.Wrap(err, "unable to reconfigure") + } + err = task.Wait(ctx) + if err != nil { + return nil, errors.Wrap(err, "task.Wait") + } + + evm, err := getVM() + if err != nil { + return nil, err + } + + // resize root disk + if rootDiskSizeMb > 0 && int64(evm.vdisks[0].GetDiskSizeMB()) != rootDiskSizeMb { + err = evm.vdisks[0].Resize(ctx, rootDiskSizeMb) + if err != nil { + return evm, errors.Wrap(err, "resize for root disk") + } + } + return evm, nil +} + +func (self *SHost) copyVirtualDisk(srcPath, dstPath, diskDriver string) error { + dm := object.NewVirtualDiskManager(self.manager.client.Client) + spec := &types.VirtualDiskSpec{ + DiskType: "thin", + } + switch diskDriver { + case "", "scsi", "pvscsi": + spec.AdapterType = "lsiLogic" + default: + spec.AdapterType = "ide" + } + task, err := dm.CopyVirtualDisk(self.manager.context, srcPath, self.datacenter.getDcObj(), dstPath, self.datacenter.getDcObj(), spec, true) + if err != nil { + return errors.Wrap(err, "unable to CopyVirtualDisk") + } + err = task.Wait(self.manager.context) + if err == nil { + return nil + } + errStr := strings.ToLower(err.Error()) + if !strings.Contains(errStr, "the requested operation is not implemented by the server") { + return errors.Wrap(err, "wait CopyVirtualDiskTask") + } + task, err = dm.CopyVirtualDisk(self.manager.context, srcPath, self.datacenter.getDcObj(), dstPath, self.datacenter.getDcObj(), nil, true) + if err != nil { + return errors.Wrap(err, "unable to CopyVirtualDisk") + } + err = task.Wait(self.manager.context) + if err != nil { + return errors.Wrap(err, "wait CopyVirtualDiskTask") + } + return nil +} + +func (self *SHost) DoCreateVM(ctx context.Context, ds *SDatastore, params SCreateVMParam) (needDeploy bool, vm *SVirtualMachine, err error) { + needDeploy = true + deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 5) + + // uuid first + name := params.Name + if len(params.Uuid) != 0 { + name = params.Uuid + } + datastorePath := fmt.Sprintf("[%s] ", ds.GetRelName()) + + firmware := "" + if len(params.Bios) != 0 { + if params.Bios == "BIOS" { + firmware = "bios" + } else if params.Bios == "UEFI" { + firmware = "efi" + } + } + + guestId := "rhel6_64Guest" + if params.OsName == "Windows" { + guestId = "windows7Server64Guest" + } + + version := "vmx-10" + if self.isVersion50() { + version = "vmx-08" + } + + spec := types.VirtualMachineConfigSpec{ + Name: name, + Version: version, + Uuid: params.Uuid, + GuestId: guestId, + NumCPUs: int32(params.Cpu), + MemoryMB: int64(params.Mem), + Firmware: firmware, + } + spec.Files = &types.VirtualMachineFileInfo{ + VmPathName: datastorePath, + } + + deviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 0))) + deviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 1))) + deviceChange = append(deviceChange, addDevSpec(NewSVGADev(500, 100))) + + if self.needScsi(params.Disks) { + driver := "pvscsi" + if self.isVersion50() { + driver = "scsi" + } + deviceChange = append(deviceChange, addDevSpec(NewSCSIDev(1000, 100, driver))) + } + cdromPath := params.Cdrom.Path + if len(cdromPath) > 0 { + needDeploy = false + cdromPath, err = self.FileUrlPathToDsPath(cdromPath) + if err != nil { + err = errors.Wrapf(err, "SHost.FileUrlPathToDsPath for cdrom path") + return + } + } + deviceChange = append(deviceChange, addDevSpec(NewCDROMDev(cdromPath, 16000, 201))) + + // add usb to support mouse + usbController := addDevSpec(NewUSBController(nil)) + deviceChange = append(deviceChange, usbController) + + nics := params.Nics + for _, nic := range nics { + index, _ := nic.Int("index") + mac, _ := nic.GetString("mac") + bridge, _ := nic.GetString("bridge") + driver := "e1000" + if nic.Contains("driver") { + driver, _ = nic.GetString("driver") + } + if self.isVersion50() { + driver = "e1000" + } + var vlanId int64 = 1 + if nic.Contains("vlan") { + vlanId, _ = nic.Int("vlan") + } + dev, err := NewVNICDev(self, mac, driver, bridge, int32(vlanId), 4000, 100, int32(index)) + if err != nil { + return needDeploy, nil, errors.Wrap(err, "NewVNICDev") + } + deviceChange = append(deviceChange, addDevSpec(dev)) + } + + spec.DeviceChange = deviceChange + dc, err := self.GetDatacenter() + if err != nil { + err = errors.Wrapf(err, "SHost.GetDatacenter for host '%s'", self.GetId()) + return + } + // get vmFloder + folders, err := dc.getObjectDatacenter().Folders(ctx) + if err != nil { + err = errors.Wrap(err, "object.DataCenter.Folders") + return + } + vmFolder := folders.VmFolder + resourcePool, err := self.SyncResourcePool(params.ResourcePool) + if err != nil { + err = errors.Wrap(err, "SyncResourcePool") + return + } + task, err := vmFolder.CreateVM(ctx, spec, resourcePool, self.GetoHostSystem()) + if err != nil { + err = errors.Wrap(err, "VmFolder.Create") + return + } + + info, err := task.WaitForResult(ctx, nil) + if err != nil { + err = errors.Wrap(err, "Task.WaitForResult") + return + } + vmRef := info.Result.(types.ManagedObjectReference) + objectVM := object.NewVirtualMachine(self.manager.client.Client, vmRef) + vm, err = self.addDisks(ctx, dc, ds, params.Disks, params.Uuid, objectVM) + return +} + +// If snapshot is not nil, params.Disks will be ignored +func (host *SHost) CloneVM(ctx context.Context, from *SVirtualMachine, snapshot *types.ManagedObjectReference, ds *SDatastore, params SCreateVMParam) (*SVirtualMachine, error) { + ovm := from.getVmObj() + + deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 3) + + addDeviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 3) + + // change nic if set + if params.Nics != nil && len(params.Nics) > 0 { + // get origin nics + originNics := make([]types.BaseVirtualDevice, 0, 1) + for _, nic := range from.vnics { + originNics = append(originNics, nic.getVirtualEthernetCard()) + } + nicIndex := 0 + nics := params.Nics + for _, nic := range nics { + index, _ := nic.Int("index") + mac, _ := nic.GetString("mac") + bridge, _ := nic.GetString("bridge") + driver := "e1000" + if nic.Contains("driver") { + driver, _ = nic.GetString("driver") + } + if host.isVersion50() { + driver = "e1000" + } + var vlanId int64 = 1 + if nic.Contains("vlan") { + vlanId, _ = nic.Int("vlan") + } + dev, err := NewVNICDev(host, mac, driver, bridge, int32(vlanId), 4000, 100, int32(index)) + if err != nil { + return nil, errors.Wrap(err, "NewVNICDev") + } + op := types.VirtualDeviceConfigSpecOperationAdd + if nicIndex < len(originNics) { + // edit + op = types.VirtualDeviceConfigSpecOperationEdit + host.changeNic(originNics[nicIndex], dev) + dev = originNics[nicIndex] + deviceChange = append(deviceChange, &types.VirtualDeviceConfigSpec{ + Operation: op, + Device: dev, + }) + } else { + addDeviceChange = append(addDeviceChange, &types.VirtualDeviceConfigSpec{ + Operation: op, + Device: dev, + }) + } + nicIndex += 1 + } + } + + if len(params.Disks) > 0 && snapshot == nil { + driver := params.Disks[0].Driver + if driver == "scsi" || driver == "pvscsi" { + scsiDevs, err := from.FindController(ctx, "scsi") + if err != nil { + return nil, errors.Wrap(err, "SVirtualMachine.FindController") + } + if len(scsiDevs) == 0 { + key := from.FindMinDiffKey(1000) + driver := "pvscsi" + if host.isVersion50() { + driver = "scsi" + } + addDeviceChange = append(deviceChange, addDevSpec(NewSCSIDev(key, 100, driver))) + } + } else { + ideDevs, err := from.FindController(ctx, "ide") + if err != nil { + return nil, errors.Wrap(err, "SVirtualMachine.FindController") + } + if len(ideDevs) == 0 { + // add ide driver + addDeviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 0))) + addDeviceChange = append(deviceChange, addDevSpec(NewIDEDev(200, 1))) + } + } + } + + dc, err := host.GetDatacenter() + if err != nil { + return nil, errors.Wrapf(err, "SHost.GetDatacenter for host '%s'", host.GetId()) + } + // get vmFloder + folders, err := dc.getObjectDatacenter().Folders(ctx) + if err != nil { + return nil, errors.Wrap(err, "object.DataCenter.Folders") + } + resourcePool, err := host.SyncResourcePool(params.ResourcePool) + if err != nil { + return nil, errors.Wrap(err, "SyncResourcePool") + } + + folderref := folders.VmFolder.Reference() + poolref := resourcePool.Reference() + hostref := host.GetoHostSystem().Reference() + dsref := ds.getDatastoreObj().Reference() + relocateSpec := types.VirtualMachineRelocateSpec{ + DeviceChange: deviceChange, + Folder: &folderref, + Pool: &poolref, + Host: &hostref, + Datastore: &dsref, + } + cloneSpec := &types.VirtualMachineCloneSpec{ + PowerOn: false, + Template: false, + Location: relocateSpec, + Snapshot: snapshot, + } + + // uuid first + name := params.Name + if len(params.Uuid) != 0 { + name = params.Uuid + } + spec := types.VirtualMachineConfigSpec{ + Name: name, + Uuid: params.Uuid, + NumCPUs: int32(params.Cpu), + MemoryMB: int64(params.Mem), + } + cloneSpec.Config = &spec + task, err := ovm.Clone(ctx, folders.VmFolder, name, *cloneSpec) + if err != nil { + return nil, errors.Wrap(err, "object.VirtualMachine.Clone") + } + info, err := task.WaitForResult(ctx, nil) + if err != nil { + return nil, errors.Wrap(err, "Task.WaitForResult") + } + + var moVM mo.VirtualMachine + err = host.manager.reference2Object(info.Result.(types.ManagedObjectReference), VIRTUAL_MACHINE_PROPS, &moVM) + if err != nil { + return nil, errors.Wrap(err, "fail to fetch virtual machine just created") + } + + vm := NewVirtualMachine(host.manager, &moVM, host.datacenter) + if vm == nil { + return nil, errors.Error("clone successfully but unable to NewVirtualMachine") + } + + if snapshot != nil { + return vm, nil + } + + deviceChange = addDeviceChange + // adjust disk + var i int + if len(params.Disks) > 0 { + // resize system disk + sysDiskSize := params.Disks[0].Size + if sysDiskSize == 0 { + sysDiskSize = 30 * 1024 + } + if int64(vm.vdisks[0].GetDiskSizeMB()) != sysDiskSize { + vdisk := vm.vdisks[0].getVirtualDisk() + originSize := vdisk.CapacityInKB + vdisk.CapacityInKB = sysDiskSize * 1024 + spec := &types.VirtualDeviceConfigSpec{} + spec.Operation = types.VirtualDeviceConfigSpecOperationEdit + spec.Device = vdisk + deviceChange = append(deviceChange, spec) + log.Infof("resize system disk: %dGB => %dGB", originSize/1024/1024, sysDiskSize/1024) + } + // resize existed disk + for i = 1; i < len(params.Disks); i++ { + if i >= len(vm.vdisks) { + break + } + wantDisk := params.Disks[i] + vdisk := vm.vdisks[i] + modisk := vdisk.getVirtualDisk() + if wantDisk.Size <= int64(vdisk.GetDiskSizeMB()) { + continue + } + originSize := modisk.CapacityInKB + modisk.CapacityInKB = wantDisk.Size * 1024 + spec := &types.VirtualDeviceConfigSpec{} + spec.Operation = types.VirtualDeviceConfigSpecOperationEdit + spec.Device = vdisk.dev + deviceChange = append(deviceChange, spec) + log.Infof("resize No.%d data disk: %dGB => %dGB", i, originSize/1024/1024, wantDisk.Size/1024) + } + // remove extra disk + for ; i < len(vm.vdisks); i++ { + vdisk := vm.vdisks[i] + spec := &types.VirtualDeviceConfigSpec{} + spec.Operation = types.VirtualDeviceConfigSpecOperationRemove + spec.Device = vdisk.dev + spec.FileOperation = types.VirtualDeviceConfigSpecFileOperationDestroy + deviceChange = append(deviceChange, spec) + log.Infof("remove No.%d data disk", i) + } + if len(deviceChange) > 0 { + spec = types.VirtualMachineConfigSpec{} + spec.DeviceChange = deviceChange + task, err = vm.getVmObj().Reconfigure(ctx, spec) + if err != nil { + return vm, errors.Wrap(err, "Reconfigure to resize disks") + } + err = task.Wait(ctx) + if err != nil { + return vm, errors.Wrap(err, "Wait task to resize disks") + } + } + } + // add data disk + for ; i < len(params.Disks); i++ { + size := params.Disks[i].Size + if size == 0 { + size = 30 * 1024 + } + uuid := params.Disks[i].DiskId + driver := params.Disks[i].Driver + opts := &cloudprovider.GuestDiskCreateOptions{ + SizeMb: int(size), + UUID: uuid, + Driver: driver, + StorageId: params.Disks[i].StorageId, + } + _, err := vm.CreateDisk(ctx, opts) + if err != nil { + log.Errorf("unable to add No.%d disk for vm %s", i, vm.GetId()) + return vm, nil + } + } + return vm, nil +} + +func (host *SHost) changeNic(device types.BaseVirtualDevice, update types.BaseVirtualDevice) { + current := device.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() + changed := update.(types.BaseVirtualEthernetCard).GetVirtualEthernetCard() + + current.Backing = changed.Backing + if changed.MacAddress != "" { + current.MacAddress = changed.MacAddress + } + if changed.AddressType != "" { + current.AddressType = changed.AddressType + } +} + +func (host *SHost) isVersion50() bool { + version := host.GetVersion() + if strings.HasPrefix(version, "5.") { + return true + } + return false +} + +func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return host.GetIHostNicsInternal(false) +} + +func (host *SHost) GetIHostNicsInternal(debug bool) ([]cloudprovider.ICloudHostNetInterface, error) { + nics := host.getNicInfo(debug) + inics := make([]cloudprovider.ICloudHostNetInterface, len(nics)) + for i := 0; i < len(nics); i += 1 { + inics[i] = &nics[i] + } + return inics, nil +} + +func (host *SHost) getLocalStorageCache() (*SDatastoreImageCache, error) { + if host.storageCache == nil { + sc, err := host.newLocalStorageCache() + if err != nil { + return nil, err + } + host.storageCache = sc + } + return host.storageCache, nil +} + +func (host *SHost) newLocalStorageCache() (*SDatastoreImageCache, error) { + ctx := context.Background() + + istorages, err := host.GetIStorages() + if err != nil { + return nil, err + } + var errmsg string + var cacheDs *SDatastore + var maxDs *SDatastore + var maxCapacity int64 + for i := 0; i < len(istorages); i += 1 { + ds := istorages[i].(*SDatastore) + if !ds.isLocalVMFS() { + continue + } + _, err := ds.CheckFile(ctx, IMAGE_CACHE_DIR_NAME) + if err != nil { + if errors.Cause(err) != cloudprovider.ErrNotFound { + // return nil, err + if len(errmsg) > 0 { + errmsg += "," + } + errmsg += err.Error() + } else if maxCapacity < ds.GetCapacityMB() { + maxCapacity = ds.GetCapacityMB() + maxDs = ds + } + } else { + cacheDs = ds + break + } + } + if cacheDs == nil { + // if no existing image cache dir found, use the one with maximal capacilty + cacheDs = maxDs + } + + if cacheDs == nil { + return nil, fmt.Errorf(errmsg) + } + + return &SDatastoreImageCache{ + datastore: cacheDs, + host: host, + }, nil +} + +func (host *SHost) GetManagementServerIp() string { + return host.getHostSystem().Summary.ManagementServerIp +} + +func (host *SHost) IsManagedByVCenter() bool { + return len(host.getHostSystem().Summary.ManagementServerIp) > 0 +} + +func (host *SHost) FindDataStoreById(id string) (*SDatastore, error) { + datastores, err := host.GetDataStores() + if err != nil { + return nil, err + } + for i := range datastores { + if datastores[i].GetGlobalId() == id { + return datastores[i].(*SDatastore), nil + } + } + return nil, fmt.Errorf("no such datastore %s", id) +} + +func (host *SHost) GetDataStores() ([]cloudprovider.ICloudStorage, error) { + err := host.fetchDatastores() + if err != nil { + return nil, err + } + return host.datastores, nil +} + +func (host *SHost) fetchDatastores() error { + if host.datastores != nil { + return nil + } + + dc, err := host.GetDatacenter() + if err != nil { + return err + } + dss := host.getHostSystem().Datastore + var datastores []mo.Datastore + err = host.manager.references2Objects(dss, DATASTORE_PROPS, &datastores) + if err != nil { + return err + } + host.datastores = make([]cloudprovider.ICloudStorage, 0) + for i := 0; i < len(datastores); i += 1 { + ds := NewDatastore(host.manager, &datastores[i], dc) + dsId := ds.GetGlobalId() + if len(dsId) > 0 { + host.datastores = append(host.datastores, ds) + } + } + return nil +} + +func (host *SHost) FileUrlPathToDsPath(path string) (string, error) { + var newPath string + dss, err := host.GetDataStores() + if err != nil { + return newPath, err + } + for _, ds := range dss { + rds := ds.(*SDatastore) + log.Debugf("rds: %s", rds.GetUrl()) + if strings.HasPrefix(path, rds.GetUrl()) { + newPath = fmt.Sprintf("[%s] %s", rds.GetRelName(), path[len(rds.GetUrl()):]) + break + } + } + if len(newPath) == 0 { + return newPath, fmt.Errorf("path '%s' don't belong any datastore of host '%s'", path, host.GetName()) + } + return newPath, nil +} + +func (host *SHost) FindNetworkByVlanID(vlanID int32) (IVMNetwork, error) { + if host.IsActiveVlanID(vlanID) { + net, err := host.findBasicNetwork(vlanID) + if err != nil { + return nil, errors.Wrap(err, "findBasicNetwork error") + } + if net != nil { + return net, nil + } + + // no found in basic network + dvpg, err := host.findVlanDVPG(vlanID) + if err != nil { + return nil, errors.Wrap(err, "findVlanDVPG") + } + return dvpg, nil + } + n, err := host.findBasicNetwork(vlanID) + if err != nil { + return nil, errors.Wrap(err, "find Basic network") + } + if n != nil { + return n, err + } + return host.findNovlanDVPG() +} + +// IsActiveVlanID will detect if vlanID is active that means vlanID in (1, 4095). +func (host *SHost) IsActiveVlanID(vlanID int32) bool { + if vlanID > 1 && vlanID < 4095 { + return true + } + return false +} + +func (host *SHost) findBasicNetwork(vlanID int32) (IVMNetwork, error) { + nets, err := host.getBasicNetworks() + if err != nil { + return nil, err + } + if len(nets) == 0 { + return nil, nil + } + if !host.IsActiveVlanID(vlanID) { + return nets[0], nil + } + for i := range nets { + if nets[i].GetVlanId() == vlanID { + return nets[i], nil + } + } + return nil, nil +} + +func (host *SHost) getBasicNetworks() ([]IVMNetwork, error) { + nets, err := host.GetNetworks() + if err != nil { + return nil, errors.Wrap(err, "GetNetworks") + } + ret := make([]IVMNetwork, 0) + for i := range nets { + if net, ok := nets[i].(*SNetwork); ok { + ret = append(ret, net) + } + } + return ret, nil +} + +func (host *SHost) GetNetworks() ([]IVMNetwork, error) { + if host.networks != nil { + return host.networks, nil + } + netMobs := host.getHostSystem().Network + netPortMobs := make([]types.ManagedObjectReference, 0) + netNetMobs := make([]types.ManagedObjectReference, 0) + + for i := range netMobs { + log.Debugf("type: %s value: %s", netMobs[i].Type, netMobs[i].Value) + if netMobs[i].Type == "DistributedVirtualPortgroup" { + netPortMobs = append(netPortMobs, netMobs[i]) + } else { + netNetMobs = append(netNetMobs, netMobs[i]) + } + } + + nets := make([]IVMNetwork, 0) + + if len(netPortMobs) > 0 { + moPorts := make([]mo.DistributedVirtualPortgroup, 0) + err := host.manager.references2Objects(netPortMobs, DVPORTGROUP_PROPS, &moPorts) + if err != nil { + return nil, errors.Wrap(err, "references2Objects") + } + for i := range moPorts { + port := NewDistributedVirtualPortgroup(host.manager, &moPorts[i], host.datacenter) + nets = append(nets, port) + } + } + if len(netNetMobs) > 0 { + moNets := make([]mo.Network, 0) + err := host.manager.references2Objects(netNetMobs, NETWORK_PROPS, &moNets) + if err != nil { + return nil, errors.Wrap(err, "references2Objects") + } + for i := range moNets { + net := NewNetwork(host.manager, &moNets[i], host.datacenter) + nets = append(nets, net) + } + } + + // network map + netMap := make(map[string]IVMNetwork) + for i := range nets { + netMap[nets[i].GetName()] = nets[i] + } + + // fetch all portgroup + portgroups := host.getHostSystem().Config.Network.Portgroup + for _, pg := range portgroups { + net, ok := netMap[pg.Spec.Name] + if !ok { + log.Infof("SNetwork corresponding to the portgroup whose name is %s could not be found", pg.Spec.Name) + continue + } + net.SetHostPortGroup(pg) + } + host.networks = nets + return host.networks, nil +} + +func (host *SHost) findNovlanDVPG() (*SDistributedVirtualPortgroup, error) { + nets, err := host.datacenter.GetNetworks() + if err != nil { + return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks") + } + for _, net := range nets { + dvpg, ok := net.(*SDistributedVirtualPortgroup) + if !ok || !dvpg.ContainHost(host) || len(dvpg.GetActivePorts()) == 0 { + continue + } + nvlan := dvpg.GetVlanId() + if !host.IsActiveVlanID(nvlan) { + return dvpg, nil + } + } + return nil, nil +} + +func (host *SHost) findDVPGById(id string) (*SDistributedVirtualPortgroup, error) { + nets, err := host.datacenter.GetNetworks() + if err != nil { + return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks") + } + for _, net := range nets { + if dvpg, ok := net.(*SDistributedVirtualPortgroup); ok && dvpg.GetId() == id { + return dvpg, nil + } + } + return nil, nil +} + +func (host *SHost) findVlanDVPG(vlanId int32) (*SDistributedVirtualPortgroup, error) { + nets, err := host.datacenter.GetNetworks() + if err != nil { + return nil, errors.Wrap(err, "SHost.datacenter.GetNetworks") + } + for _, net := range nets { + dvpg, ok := net.(*SDistributedVirtualPortgroup) + if !ok || len(dvpg.GetActivePorts()) == 0 { + continue + } + nvlan := dvpg.GetVlanId() + if nvlan == vlanId { + if dvpg.ContainHost(host) { + return dvpg, nil + } + msg := "Find dvpg with correct vlan but it didn't contain this host" + log.Debugf(msg) + // add host to dvg + // err := dvpg.AddHostToDVS(host) + // if err != nil { + // return nil, errors.Wrapf(err, "dvpg %s add host to dvs error", dvpg.GetName()) + // } + continue + } + } + return nil, nil +} + +func (host *SHost) GetoHostSystem() *object.HostSystem { + return object.NewHostSystem(host.manager.client.Client, host.getHostSystem().Reference()) +} + +func (host *SHost) GetResourcePool() (*object.ResourcePool, error) { + var err error + if host.parent == nil { + host.parent, err = host.getParent() + if err != nil { + return nil, err + } + } + return object.NewResourcePool(host.manager.client.Client, *host.parent.ResourcePool), nil +} + +func (host *SHost) getParent() (*mo.ComputeResource, error) { + var mcr *mo.ComputeResource + var parent interface{} + + moHost := host.getHostSystem() + + switch moHost.Parent.Type { + case "ComputeResource": + mcr = new(mo.ComputeResource) + parent = mcr + case "ClusterComputeResource": + mcc := new(mo.ClusterComputeResource) + mcr = &mcc.ComputeResource + parent = mcc + default: + return nil, errors.Error(fmt.Sprintf("unknown host parent type: %s", moHost.Parent.Type)) + } + + err := host.manager.reference2Object(*moHost.Parent, []string{"name", "resourcePool"}, parent) + if err != nil { + return nil, errors.Wrap(err, "SESXiClient.reference2Object") + } + return mcr, nil +} + +func (host *SHost) GetResourcePools() ([]mo.ResourcePool, error) { + cluster, err := host.GetCluster() + if err != nil { + return nil, errors.Wrap(err, "GetCluster") + } + return cluster.ListResourcePools() +} + +func (host *SHost) GetCluster() (*SCluster, error) { + cluster, err := host.getCluster() + if err != nil { + return nil, errors.Wrap(err, "getCluster") + } + return NewCluster(host.manager, cluster, host.datacenter), nil +} + +func (host *SHost) SyncResourcePool(name string) (*object.ResourcePool, error) { + cluster, err := host.GetCluster() + if err != nil { + log.Errorf("failed to get host %s cluster info: %v", host.GetName(), err) + return host.GetResourcePool() + } + pool, err := cluster.SyncResourcePool(name) + if err != nil { + log.Errorf("failed to sync resourcePool(%s) for cluster %s error: %v", name, cluster.GetName(), err) + return host.GetResourcePool() + } + return object.NewResourcePool(host.manager.client.Client, pool.Reference()), nil +} + +func (host *SHost) getCluster() (*mo.ClusterComputeResource, error) { + moHost := host.getHostSystem() + if moHost.Parent.Type != "ClusterComputeResource" { + return nil, fmt.Errorf("host %s parent is not the cluster resource", host.GetName()) + } + cluster := &mo.ClusterComputeResource{} + err := host.manager.reference2Object(*moHost.Parent, []string{"name", "resourcePool"}, cluster) + if err != nil { + return nil, errors.Wrap(err, "SESXiClient.reference2Object") + } + return cluster, nil +} + +func (host *SHost) GetSiblingHosts() ([]*SHost, error) { + rp, err := host.getParent() + if err != nil { + return nil, err + } + moHosts := make([]mo.HostSystem, 0, len(rp.Host)) + err = host.manager.references2Objects(rp.Host, HOST_SYSTEM_PROPS, &moHosts) + if err != nil { + return nil, errors.Wrap(err, "SESXiClient.references2Objects") + } + + ret := make([]*SHost, len(moHosts)) + for i := range moHosts { + ret[i] = NewHost(host.manager, &moHosts[i], host.datacenter) + } + return ret, nil +} diff --git a/pkg/multicloud/esxi/hostnic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/hostnic.go similarity index 100% rename from pkg/multicloud/esxi/hostnic.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/hostnic.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/image.go new file mode 100644 index 0000000000..4445a67c47 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/image.go @@ -0,0 +1,158 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "context" + "path" + "strings" + "time" + + "github.com/vmware/govmomi/object" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type SImage struct { + multicloud.SImageBase + multicloud.STagBase + cache *SDatastoreImageCache + filename string + size int64 + createAt time.Time + + imageInfo *imagetools.ImageInfo +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SImage) getDatacenter() *object.Datacenter { + return self.cache.datastore.datacenter.getDcObj() +} + +func (self *SImage) getFullFilename() string { + return self.cache.datastore.getPathString(self.filename) +} + +func (self *SImage) GetId() string { + idstr := path.Base(self.filename) + if strings.HasSuffix(idstr, ".vmdk") { + idstr = idstr[:len(idstr)-5] + } + return strings.ToLower(idstr) +} + +func (self *SImage) GetName() string { + return self.GetId() +} + +func (self *SImage) GetGlobalId() string { + return self.GetId() +} + +func (self *SImage) GetStatus() string { + dm := object.NewVirtualDiskManager(self.cache.datastore.manager.client.Client) + ctx := context.Background() + _, err := dm.QueryVirtualDiskInfo(ctx, self.getFullFilename(), self.getDatacenter(), true) + if err != nil { + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } + return api.CACHED_IMAGE_STATUS_ACTIVE +} + +func (self *SImage) GetImageStatus() string { + status := self.GetStatus() + if status == api.CACHED_IMAGE_STATUS_ACTIVE { + return cloudprovider.IMAGE_STATUS_ACTIVE + } + return cloudprovider.IMAGE_STATUS_DELETED +} + +func (self *SImage) Refresh() error { + return nil +} + +func (self *SImage) IsEmulated() bool { + return false +} + +func (self *SImage) Delete(ctx context.Context) error { + return self.cache.datastore.DeleteVmdk(ctx, self.filename) +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.cache +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + return cloudprovider.ImageTypeCustomized +} + +func (self *SImage) GetSizeByte() int64 { + return self.size +} + +func (img *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if img.imageInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(img.filename, "", "", "", "") + img.imageInfo = &imgInfo + } + return img.imageInfo +} + +func (img *SImage) GetFullOsName() string { + return img.filename +} + +func (img *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(img.getNormalizedImageInfo().OsType) +} + +func (img *SImage) GetOsArch() string { + return img.getNormalizedImageInfo().OsArch +} + +func (img *SImage) GetOsDist() string { + return img.getNormalizedImageInfo().OsDistro +} + +func (img *SImage) GetOsVersion() string { + return img.getNormalizedImageInfo().OsVersion +} + +func (img *SImage) GetOsLang() string { + return img.getNormalizedImageInfo().OsLang +} + +func (img *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(img.getNormalizedImageInfo().OsBios) +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return int(self.GetSizeByte() / 1024 / 1024 / 1024) +} + +func (self *SImage) GetImageFormat() string { + return "vmdk" +} + +func (self *SImage) GetCreatedAt() time.Time { + return self.createAt +} diff --git a/pkg/multicloud/esxi/ip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/ip.go similarity index 100% rename from pkg/multicloud/esxi/ip.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/ip.go diff --git a/pkg/multicloud/esxi/logger.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/logger.go similarity index 100% rename from pkg/multicloud/esxi/logger.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/logger.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/manager.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/manager.go new file mode 100644 index 0000000000..50cb15dbeb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/manager.go @@ -0,0 +1,743 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "bytes" + "context" + "fmt" + "net/http" + "net/http/httputil" + "net/url" + "reflect" + "strings" + "sync" + + xj "github.com/basgys/goxml2json" + "github.com/fatih/color" + "github.com/vmware/govmomi" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/session" + "github.com/vmware/govmomi/view" + "github.com/vmware/govmomi/vim25" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" + "moul.io/http2curl/v2" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +const ( + CLOUD_PROVIDER_VMWARE = api.CLOUD_PROVIDER_VMWARE +) + +var ( + defaultDc mo.Datacenter + + defaultDcId = "esxi-default-datacenter" +) + +func init() { + defaultDc.ManagedEntity.Name = "Datacenter" + defaultDc.ManagedEntity.ExtensibleManagedObject.Self.Type = "Datacenter" + defaultDc.ManagedEntity.ExtensibleManagedObject.Self.Value = defaultDcId +} + +type ESXiClientConfig struct { + cpcfg cloudprovider.ProviderConfig + + host string + port int + account string + password string + + managed bool + debug bool + format string +} + +func NewESXiClientConfig(host string, port int, account, password string) *ESXiClientConfig { + cfg := &ESXiClientConfig{ + host: host, + port: port, + account: account, + password: password, + } + return cfg +} + +func (cfg *ESXiClientConfig) CloudproviderConfig(cpcfg cloudprovider.ProviderConfig) *ESXiClientConfig { + cfg.cpcfg = cpcfg + return cfg +} + +func (cfg *ESXiClientConfig) Debug(debug bool) *ESXiClientConfig { + cfg.debug = debug + return cfg +} + +func (cfg *ESXiClientConfig) Format(format string) *ESXiClientConfig { + cfg.format = format + return cfg +} + +func (cfg *ESXiClientConfig) Managed(managed bool) *ESXiClientConfig { + cfg.managed = managed + return cfg +} + +type SESXiClient struct { + *ESXiClientConfig + + cloudprovider.SFakeOnPremiseRegion + multicloud.SRegion + multicloud.SNoObjectStorageRegion + + client *govmomi.Client + context context.Context + + datacenters []*SDatacenter + networkQueryMap *sync.Map +} + +func NewESXiClient(cfg *ESXiClientConfig) (*SESXiClient, error) { + cfg.Managed(true) + return NewESXiClient2(cfg) +} + +func NewESXiClient2(cfg *ESXiClientConfig) (*SESXiClient, error) { + cli := &SESXiClient{ + ESXiClientConfig: cfg, + context: context.Background(), + } + + err := cli.connect() + if err != nil { + return nil, err + } + + if !cli.IsVCenter() { + err := cli.checkHostManagedByVCenter() + if err != nil { + if cfg.managed { + cli.disconnect() + return nil, err + } else { + log.Warningf("%s", err) + } + } + } + return cli, nil +} + +func NewESXiClientFromJson(ctx context.Context, input jsonutils.JSONObject) (*SESXiClient, *vcenter.SVCenterAccessInfo, error) { + accessInfo := new(vcenter.SVCenterAccessInfo) + err := input.Unmarshal(accessInfo) + if err != nil { + return nil, nil, errors.Wrapf(err, "unmarshal SVCenterAccessInfo: %s", input) + } + c, err := NewESXiClientFromAccessInfo(ctx, accessInfo) + return c, accessInfo, err +} + +func NewESXiClientFromAccessInfo(ctx context.Context, accessInfo *vcenter.SVCenterAccessInfo) (*SESXiClient, error) { + if len(accessInfo.VcenterId) > 0 { + tmp, err := utils.DescryptAESBase64(accessInfo.VcenterId, accessInfo.Password) + if err == nil { + accessInfo.Password = tmp + } + } + client, err := NewESXiClient( + NewESXiClientConfig( + accessInfo.Host, + accessInfo.Port, + accessInfo.Account, + accessInfo.Password, + ).Managed(true), + ) + if err != nil { + return nil, err + } + if ctx == nil { + ctx = context.Background() + } + client.context = ctx + return client, nil +} + +func (cli *SESXiClient) getUrl() string { + if cli.port == 443 || cli.port == 0 { + return fmt.Sprintf("https://%s", cli.host) + } else { + return fmt.Sprintf("https://%s:%d", cli.host, cli.port) + } +} + +func (cli *SESXiClient) url() string { + return fmt.Sprintf("%s/sdk", cli.getUrl()) +} + +var ( + red = color.New(color.FgRed, color.Bold).PrintlnFunc() + green = color.New(color.FgGreen, color.Bold).PrintlnFunc() + yellow = color.New(color.FgYellow, color.Bold).PrintlnFunc() + cyan = color.New(color.FgHiCyan, color.Bold).PrintlnFunc() +) + +func (cli *SESXiClient) connect() error { + u, err := url.Parse(cli.url()) + if err != nil { + return fmt.Errorf("Illegal url %s: %s", cli.url(), err) + } + + var govmcli *govmomi.Client + { + insecure := true + soapCli := soap.NewClient(u, insecure) + httpClient := &soapCli.Client + transport := httputils.GetAdaptiveTransport(true) + transport.Proxy = cli.cpcfg.ProxyFunc + httpClient.Transport = cloudprovider.GetCheckTransport(transport, func(req *http.Request) (func(resp *http.Response), error) { + if cli.debug { + dump, _ := httputil.DumpRequestOut(req, false) + yellow(string(dump)) + // 忽略掉上传文件的请求,避免大量日志输出 + if req.Header.Get("Content-Type") != "application/octet-stream" { + curlCmd, _ := http2curl.GetCurlCommand(req) + cyan("CURL:", curlCmd, "\n") + } + } + respCheck := func(resp *http.Response) { + if cli.debug { + dump, _ := httputil.DumpResponse(resp, true) + body := string(dump) + if cli.format == "json" { + obj, err := xj.Convert(bytes.NewReader(dump)) + if err == nil { + body = string(obj.String()) + } + } + if resp.StatusCode < 300 { + green(body) + } else if resp.StatusCode < 400 { + yellow(body) + } else { + red(body) + } + } + } + return respCheck, nil + }) + vimCli, err := vim25.NewClient(cli.context, soapCli) + if err != nil { + return err + } + govmcli = &govmomi.Client{ + Client: vimCli, + SessionManager: session.NewManager(vimCli), + } + } + + userinfo := url.UserPassword(cli.account, cli.password) + + err = govmcli.Login(cli.context, userinfo) + if err != nil { + return err + } + + cli.client = govmcli + + defaultDc.ManagedEntity.Parent = &cli.client.ServiceContent.RootFolder + + return nil +} + +func (cli *SESXiClient) disconnect() error { + if cli.client != nil { + return cli.client.Logout(cli.context) + } + return nil +} + +func (cli *SESXiClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + err := cli.connect() + if err != nil { + return nil, err + } + subAccount := cloudprovider.SSubAccount{ + Account: cli.account, + Name: cli.cpcfg.Name, + HealthStatus: api.CLOUD_PROVIDER_HEALTH_NORMAL, + } + return []cloudprovider.SSubAccount{subAccount}, nil +} + +func (cli *SESXiClient) GetAccountId() string { + return fmt.Sprintf("%s@%s:%d", cli.account, cli.host, cli.port) +} + +func (cli *SESXiClient) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(cli.GetName()).CN(cli.GetName()) + return table +} + +func (cli *SESXiClient) GetVersion() string { + return cli.client.ServiceContent.About.Version +} + +func (cli *SESXiClient) About() jsonutils.JSONObject { + about := jsonutils.Marshal(&cli.client.ServiceContent.About) + aboutDict := about.(*jsonutils.JSONDict) + aboutDict.Add(jsonutils.NewString(cli.getEndpointType()), "endpoint_type") + return aboutDict +} + +func (cli *SESXiClient) getEndpointType() string { + if cli.IsVCenter() { + return "VCenter" + } else { + return "ESXi" + } +} + +func (cli *SESXiClient) GetUUID() string { + about := cli.client.ServiceContent.About + return about.InstanceUuid +} + +func (cli *SESXiClient) fetchDatacentersFromHosts() error { + var hosts []mo.HostSystem + err := cli.scanAllMObjects(HOST_SYSTEM_PROPS, &hosts) + if err != nil { + return errors.Wrap(err, "cli.scanAllMObjects host") + } + dcList := make([]*SDatacenter, 0) + for i := 0; i < len(hosts); i += 1 { + me := newManagedObject(cli, &hosts[i], nil) + dcme := me.findInParents("Datacenter") + if dcme == nil { + return cloudprovider.ErrNotFound + } + _, err := findDatacenterByMoId(dcList, dcme.Self.Value) + if err == nil { + continue + } + var moDc mo.Datacenter + err = cli.reference2Object(dcme.Self, DATACENTER_PROPS, &moDc) + if err != nil { + return errors.Wrap(err, "cli.reference2Object") + } + dc, err := cli.newDatacenterFromMo(&moDc) + if err != nil { + return errors.Wrap(err, "cli.newDatacenterFromMo") + } + dcList = append(dcList, dc) + } + cli.datacenters = dcList + return nil +} + +func (cli *SESXiClient) fetchFakeDatacenter() error { + dc, err := cli.newDatacenterFromMo(&defaultDc) + if err != nil { + return errors.Wrap(err, "newDatacenterFromMo") + } + cli.datacenters = []*SDatacenter{dc} + return nil +} + +func (cli *SESXiClient) fetchDatacenters() error { + var dcs []mo.Datacenter + err := cli.scanAllMObjects(DATACENTER_PROPS, &dcs) + if err != nil { + // log.Debugf("cli.scanAllMObjects datacenter fail %s, try cli.fetchDatacentersFromHosts", err) + // err := cli.fetchDatacentersFromHosts() + // if err != nil { + log.Debugf("cli.fetchDatacentersFromHosts fail %s, try cli.fetchFakeDatacenter", err) + return cli.fetchFakeDatacenter() + // } + } + cli.datacenters = make([]*SDatacenter, len(dcs)) + for i := 0; i < len(dcs); i += 1 { + dc, err := cli.newDatacenterFromMo(&dcs[i]) + if err != nil { + return errors.Wrap(err, "cli.newDatacenterFromMo") + } + cli.datacenters[i] = dc + } + return nil +} + +func (cli *SESXiClient) newDatacenterFromMo(mo *mo.Datacenter) (*SDatacenter, error) { + dc := newDatacenter(cli, mo) + err := dc.scanHosts() + if err != nil { + return nil, errors.Wrap(err, "dc.scanHosts") + } + // err = dc.scanDatastores() + // if err != nil { + // return nil, errors.Wrap(err, "dc.scanDatastores") + // } + return dc, nil +} + +func (cli *SESXiClient) scanAllMObjects(props []string, dst interface{}) error { + return cli.scanMObjects(cli.client.ServiceContent.RootFolder, props, dst) +} + +func (cli *SESXiClient) SearchVM(id string) (*SVirtualMachine, error) { + filter := property.Filter{} + filter["summary.config.uuid"] = id + var movms []mo.VirtualMachine + err := cli.scanMObjectsWithFilter(cli.client.ServiceContent.RootFolder, VIRTUAL_MACHINE_PROPS, &movms, filter) + if err != nil { + return nil, err + } + if len(movms) == 0 { + return nil, errors.ErrNotFound + } + vm := NewVirtualMachine(cli, &movms[0], nil) + dc, err := vm.fetchDatacenter() + if err != nil { + return nil, errors.Wrap(err, "fetchDatacenter") + } + vm.datacenter = dc + return vm, nil +} + +func (cli *SESXiClient) SearchTemplateVM(id string) (*SVirtualMachine, error) { + filter := property.Filter{} + uuid := toTemplateUuid(id) + filter["summary.config.uuid"] = uuid + var movms []mo.VirtualMachine + err := cli.scanMObjectsWithFilter(cli.client.ServiceContent.RootFolder, VIRTUAL_MACHINE_PROPS, &movms, filter) + if err != nil { + return nil, err + } + if len(movms) == 0 { + return nil, errors.ErrNotFound + } + vm := NewVirtualMachine(cli, &movms[0], nil) + if !vm.IsTemplate() { + return nil, errors.ErrNotFound + } + dc, err := vm.fetchDatacenter() + if err != nil { + return nil, errors.Wrap(err, "fetchDatacenter") + } + vm.datacenter = dc + return vm, nil +} + +func (cli *SESXiClient) scanMObjectsWithFilter(folder types.ManagedObjectReference, props []string, dst interface{}, filter property.Filter) error { + dstValue := reflect.Indirect(reflect.ValueOf(dst)) + dstType := dstValue.Type() + dstEleType := dstType.Elem() + + resType := dstEleType.Name() + m := view.NewManager(cli.client.Client) + + v, err := m.CreateContainerView(cli.context, folder, []string{resType}, true) + if err != nil { + return errors.Wrapf(err, "m.CreateContainerView %s", resType) + } + + defer v.Destroy(cli.context) + + err = v.RetrieveWithFilter(cli.context, []string{resType}, props, dst, filter) + if err != nil { + // hack + if strings.Contains(err.Error(), "object references is empty") { + return nil + } + return errors.Wrapf(err, "v.RetrieveWithFilter %s", resType) + } + + return nil +} + +func (cli *SESXiClient) scanMObjects(folder types.ManagedObjectReference, props []string, dst interface{}) error { + dstValue := reflect.Indirect(reflect.ValueOf(dst)) + dstType := dstValue.Type() + dstEleType := dstType.Elem() + + resType := dstEleType.Name() + m := view.NewManager(cli.client.Client) + + v, err := m.CreateContainerView(cli.context, folder, []string{resType}, true) + if err != nil { + return errors.Wrapf(err, "m.CreateContainerView %s", resType) + } + + defer v.Destroy(cli.context) + + err = v.Retrieve(cli.context, []string{resType}, props, dst) + if err != nil { + return errors.Wrapf(err, "v.Retrieve %s", resType) + } + + return nil +} + +func (cli *SESXiClient) references2Objects(refs []types.ManagedObjectReference, props []string, dst interface{}) error { + pc := property.DefaultCollector(cli.client.Client) + err := pc.Retrieve(cli.context, refs, props, dst) + if err != nil { + log.Errorf("pc.Retrieve fail %s", err) + return err + } + return nil +} + +func (cli *SESXiClient) reference2Object(ref types.ManagedObjectReference, props []string, dst interface{}) error { + pc := property.DefaultCollector(cli.client.Client) + err := pc.RetrieveOne(cli.context, ref, props, dst) + if err != nil { + return errors.Wrap(err, "pc.RetrieveOne") + } + return nil +} + +func (cli *SESXiClient) GetDatacenters() ([]*SDatacenter, error) { + if cli.datacenters == nil { + err := cli.fetchDatacenters() + if err != nil { + return nil, err + } + } + return cli.datacenters, nil +} + +func (cli *SESXiClient) FindDatacenterByMoId(dcId string) (*SDatacenter, error) { + dcs, err := cli.GetDatacenters() + if err != nil { + return nil, err + } + return findDatacenterByMoId(dcs, dcId) +} + +func findDatacenterByMoId(dcs []*SDatacenter, dcId string) (*SDatacenter, error) { + for i := 0; i < len(dcs); i += 1 { + if dcs[i].GetId() == dcId { + return dcs[i], nil + } + // defaultDcId means no premision to get datacenter, so return fake dc + if dcs[i].GetId() == defaultDcId { + return dcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (cli *SESXiClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { + dcs, err := cli.GetDatacenters() + if err != nil { + return nil, errors.Wrap(err, "GetDatacenters") + } + ret := []cloudprovider.ICloudProject{} + for i := 0; i < len(dcs); i++ { + iprojects, err := dcs[i].GetResourcePools() + if err != nil { + return nil, errors.Wrap(err, "GetResourcePools") + } + ret = append(ret, iprojects...) + } + return ret, nil +} + +func (cli *SESXiClient) FindHostByMoId(moId string) (cloudprovider.ICloudHost, error) { + dcs, err := cli.GetDatacenters() + if err != nil { + return nil, err + } + for i := 0; i < len(dcs); i += 1 { + ihost, err := dcs[i].GetIHostByMoId(moId) + if err == nil { + return ihost, nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (cli *SESXiClient) getPrivateId(idStr string) string { + if len(cli.cpcfg.Id) > 0 && strings.HasPrefix(idStr, cli.cpcfg.Id) { + idStr = idStr[len(cli.cpcfg.Id)+1:] + } + return idStr +} + +func (cli *SESXiClient) checkHostManagedByVCenter() error { + host, err := cli.FindHostByIp(cli.host) + if err != nil { + if errors.Cause(err) == errors.ErrNotFound { + // host might be behind a NAT + return nil + } + return errors.Wrap(err, "cli.FindHostByIp") + } + if host.IsManagedByVCenter() { + return fmt.Errorf("ESXi host is managed by vcenter %s, please connect to vcenter instead for full management functions!", host.GetManagementServerIp()) + } + return nil +} + +func (cli *SESXiClient) IsHostIpExists(hostIp string) (bool, error) { + searchIndex := object.NewSearchIndex(cli.client.Client) + + hostRef, err := searchIndex.FindByIp(cli.context, nil, cli.getPrivateId(hostIp), false) + if err != nil { + log.Errorf("searchIndex.FindByIp fail %s", err) + return false, err + } + if hostRef == nil { + return false, nil + } + return true, nil +} + +func (cli *SESXiClient) FindHostByIp(hostIp string) (*SHost, error) { + searchIndex := object.NewSearchIndex(cli.client.Client) + + hostRef, err := searchIndex.FindByIp(cli.context, nil, cli.getPrivateId(hostIp), false) + if err != nil { + log.Errorf("searchIndex.FindByIp fail %s", err) + return nil, errors.Wrap(err, "searchIndex.FindByIp") + } + + if hostRef == nil { + return nil, errors.Wrapf(errors.ErrNotFound, "cannot find %s", cli.getPrivateId(hostIp)) + } + + var host mo.HostSystem + err = cli.reference2Object(hostRef.Reference(), HOST_SYSTEM_PROPS, &host) + if err != nil { + log.Errorf("reference2Object fail %s", err) + return nil, errors.Wrap(err, "cli.reference2Object") + } + + h := NewHost(cli, &host, nil) + if h == nil { + return nil, errors.Wrap(errors.ErrInvalidStatus, "empty host mo") + } + return h, nil +} + +func (cli *SESXiClient) acquireCloneTicket() (string, error) { + manager := session.NewManager(cli.client.Client) + return manager.AcquireCloneTicket(cli.context) +} + +func (cli *SESXiClient) IsVCenter() bool { + return cli.client.Client.IsVC() +} + +func (cli *SESXiClient) IsValid() bool { + return cli.client.Client.Valid() +} + +func (cli *SESXiClient) GetCapabilities() []string { + caps := []string{ + cloudprovider.CLOUD_CAPABILITY_PROJECT, + cloudprovider.CLOUD_CAPABILITY_COMPUTE, + // cloudprovider.CLOUD_CAPABILITY_NETWORK, + // cloudprovider.CLOUD_CAPABILITY_LOADBALANCER, + // cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE, + // cloudprovider.CLOUD_CAPABILITY_RDS, + // cloudprovider.CLOUD_CAPABILITY_CACHE, + // cloudprovider.CLOUD_CAPABILITY_EVENT, + } + return caps +} + +func (cli *SESXiClient) FindVMByPrivateID(idstr string) (*SVirtualMachine, error) { + searchIndex := object.NewSearchIndex(cli.client.Client) + instanceUuid := true + vmRef, err := searchIndex.FindByUuid(cli.context, nil, idstr, true, &instanceUuid) + if err != nil { + return nil, errors.Wrap(err, "searchIndex.FindByUuid fail") + } + if vmRef == nil { + return nil, fmt.Errorf("cannot find %s", idstr) + } + var vm mo.VirtualMachine + err = cli.reference2Object(vmRef.Reference(), VIRTUAL_MACHINE_PROPS, &vm) + if err != nil { + return nil, errors.Wrap(err, "reference2Object fail") + } + + ret := NewVirtualMachine(cli, &vm, nil) + if ret == nil { + return nil, errors.Error("invalid vm") + } + return ret, nil +} + +func (cli *SESXiClient) DoExtendDiskOnline(_vm *SVirtualMachine, _disk *SVirtualDisk, newSizeMb int64) error { + disk := _disk.getVirtualDisk() + disk.CapacityInKB = newSizeMb * 1024 + devSepc := types.VirtualDeviceConfigSpec{Operation: types.VirtualDeviceConfigSpecOperationEdit, Device: disk} + spec := types.VirtualMachineConfigSpec{DeviceChange: []types.BaseVirtualDeviceConfigSpec{&devSepc}} + vm := object.NewVirtualMachine(cli.client.Client, _vm.getVirtualMachine().Reference()) + task, err := vm.Reconfigure(cli.context, spec) + if err != nil { + return errors.Wrapf(err, "vm reconfigure failed") + } + return task.Wait(cli.context) +} + +func (cli *SESXiClient) ExtendDisk(url string, newSizeMb int64) error { + param := types.ExtendVirtualDisk_Task{ + This: *cli.client.Client.ServiceContent.VirtualDiskManager, + Name: url, + NewCapacityKb: newSizeMb * 1024, + } + response, err := methods.ExtendVirtualDisk_Task(cli.context, cli.client, ¶m) + if err != nil { + return errors.Wrapf(err, "extend virtualdisk task failed") + } + log.Debugf("extend virtual disk task response: %s", response.Returnval.String()) + return nil +} + +func (cli *SESXiClient) CopyDisk(ctx context.Context, src, dst string, isForce bool) error { + dm := object.NewVirtualDiskManager(cli.client.Client) + task, err := dm.CopyVirtualDisk(ctx, src, nil, dst, nil, nil, isForce) + if err != nil { + return errors.Wrap(err, "CopyVirtualDisk") + } + return task.Wait(ctx) +} + +func (cli *SESXiClient) MoveDisk(ctx context.Context, src, dst string, isForce bool) error { + dm := object.NewVirtualDiskManager(cli.client.Client) + task, err := dm.MoveVirtualDisk(ctx, src, nil, dst, nil, isForce) + if err != nil { + return errors.Wrap(err, "MoveVirtualDisk") + } + return task.Wait(ctx) +} diff --git a/pkg/multicloud/esxi/mobase.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/mobase.go similarity index 98% rename from pkg/multicloud/esxi/mobase.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/mobase.go index 01b0cbcc45..1c48184f86 100644 --- a/pkg/multicloud/esxi/mobase.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/mobase.go @@ -21,7 +21,7 @@ import ( "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SManagedObject struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/monitor.go new file mode 100644 index 0000000000..37aa2652ec --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/monitor.go @@ -0,0 +1,292 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "fmt" + "time" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/performance" + "github.com/vmware/govmomi/view" + "github.com/vmware/govmomi/vim25/types" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + MONTYPE_HOSTSYSTEM = "HostSystem" + MONTYPE_VIRTUALMACHINE = "VirtualMachine" +) + +func (self *SESXiClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricName := "" + switch opts.MetricType { + case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: + metricName = "cpu.usage.average" + case cloudprovider.VM_METRIC_TYPE_MEM_USAGE: + metricName = "mem.usage.average" + case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: + metricName = "net.bytesRx.average" + case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: + metricName = "net.bytesTx.average" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: + metricName = "disk.read.average" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: + metricName = "disk.write.average" + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) + } + return self.getEcsMetrics(metricName, opts.MetricType, opts.StartTime, opts.EndTime) +} + +func (self *SESXiClient) getEcsMetrics(metricName string, metricType cloudprovider.TMetricType, start, end time.Time) ([]cloudprovider.MetricValues, error) { + m := view.NewManager(self.client.Client) + v, err := m.CreateContainerView(self.context, self.client.Client.ServiceContent.RootFolder, nil, true) + if err != nil { + return nil, errors.Wrapf(err, "CreateContainerView") + } + vms, err := v.Find(self.context, []string{MONTYPE_VIRTUALMACHINE}, nil) + if err != nil { + return nil, err + } + perfManager := performance.NewManager(self.client.Client) + counterInfo, err := perfManager.CounterInfoByName(self.context) + if err != nil { + return nil, errors.Wrapf(err, "CounterInfoByName") + } + + counter, ok := counterInfo[metricName] + if !ok { + return nil, fmt.Errorf("not found %s", metricName) + } + + queries := []types.PerfQuerySpec{} + for i := range vms { + query := types.PerfQuerySpec{ + Entity: vms[i].Reference(), + MetricId: []types.PerfMetricId{ + { + CounterId: counter.Key, + }, + }, + Format: "normal", + IntervalId: 20, + StartTime: &start, + EndTime: &end, + } + queries = append(queries, query) + } + + sample, err := perfManager.Query(self.context, queries) + if err != nil { + return nil, err + } + + result, err := perfManager.ToMetricSeries(self.context, sample) + if err != nil { + return nil, err + } + + ret := []cloudprovider.MetricValues{} + for _, metric := range result { + vm := object.NewVirtualMachine(self.client.Client, metric.Entity) + metricValue := cloudprovider.MetricValues{} + metricValue.MetricType = metricType + metricValue.Id = vm.UUID(self.context) + if len(metric.Value) == 0 { + continue + } + for i, v := range metric.SampleInfo { + if v.Timestamp.Second() != 0 { + continue + } + var value float64 + if len(metric.Value[0].Value) > i { + value = float64(metric.Value[0].Value[i]) + } + switch counter.UnitInfo.GetElementDescription().Key { + case "percent": + value = value / 100.0 + case "kiloBytesPerSecond": + value = value * 1024.0 + default: + log.Errorf("unknow unit: %s", counter.UnitInfo.GetElementDescription().Key) + } + metricValue.Values = append(metricValue.Values, cloudprovider.MetricValue{ + Timestamp: v.Timestamp, + Value: value, + }) + } + ret = append(ret, metricValue) + } + return ret, nil +} + +func (self *SESXiClient) GetHostMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricName := "" + switch opts.MetricType { + case cloudprovider.HOST_METRIC_TYPE_CPU_USAGE: + metricName = "cpu.usage.average" + case cloudprovider.HOST_METRIC_TYPE_MEM_USAGE: + metricName = "mem.usage.average" + case cloudprovider.HOST_METRIC_TYPE_NET_BPS_RX: + metricName = "net.received.average" + case cloudprovider.HOST_METRIC_TYPE_NET_BPS_TX: + metricName = "net.transmitted.average" + case cloudprovider.HOST_METRIC_TYPE_DISK_IO_READ_BPS: + metricName = "disk.read.average" + case cloudprovider.HOST_METRIC_TYPE_DISK_IO_WRITE_BPS: + metricName = "disk.write.average" + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) + } + return self.getHostMetrics(metricName, opts.MetricType, opts.StartTime, opts.EndTime) +} + +func (self *SESXiClient) getHostMetrics(metricName string, metricType cloudprovider.TMetricType, start, end time.Time) ([]cloudprovider.MetricValues, error) { + m := view.NewManager(self.client.Client) + v, err := m.CreateContainerView(self.context, self.client.Client.ServiceContent.RootFolder, nil, true) + if err != nil { + return nil, errors.Wrapf(err, "CreateContainerView") + } + vms, err := v.Find(self.context, []string{"HostSystem"}, nil) + if err != nil { + return nil, err + } + perfManager := performance.NewManager(self.client.Client) + counterInfo, err := perfManager.CounterInfoByName(self.context) + if err != nil { + return nil, errors.Wrapf(err, "CounterInfoByName") + } + + counter, ok := counterInfo[metricName] + if !ok { + return nil, fmt.Errorf("not found %s", metricName) + } + keys := []types.PerfMetricId{} + for _, v := range counterInfo { + keys = append(keys, types.PerfMetricId{ + CounterId: v.Key, + }) + } + + queries := []types.PerfQuerySpec{} + for i := range vms { + query := types.PerfQuerySpec{ + Entity: vms[i].Reference(), + MetricId: []types.PerfMetricId{ + { + CounterId: counter.Key, + }, + }, + Format: "normal", + IntervalId: 0, + StartTime: &start, + EndTime: &end, + } + queries = append(queries, query) + } + + sample, err := perfManager.Query(self.context, queries) + if err != nil { + return nil, err + } + + result, err := perfManager.ToMetricSeries(self.context, sample) + if err != nil { + return nil, err + } + + dcs, err := self.GetDatacenters() + if err != nil { + return nil, err + } + hostMap := map[string]string{} + for i := range dcs { + if dcs[i] == nil { + continue + } + part, err := dcs[i].GetIHosts() + if err != nil { + continue + } + for j := range part { + host := part[j].(*SHost) + hostMap[host.GetId()] = host.GetGlobalId() + } + } + + ret := []cloudprovider.MetricValues{} + for _, metric := range result { + metricValue := cloudprovider.MetricValues{} + metricValue.MetricType = metricType + hostId, ok := hostMap[metric.Entity.Value] + if !ok { + continue + } + metricValue.Id = hostId + if len(metric.Value) == 0 { + continue + } + for i, v := range metric.SampleInfo { + if v.Timestamp.Second() != 0 { + continue + } + var value float64 + if len(metric.Value[0].Value) > i { + value = float64(metric.Value[0].Value[i]) + } + switch counter.UnitInfo.GetElementDescription().Key { + case "percent": + value = value / 100.0 + case "kiloBytesPerSecond": + value = value * 1024.0 + default: + log.Errorf("unknow unit: %s", counter.UnitInfo.GetElementDescription().Key) + } + metricValue.Values = append(metricValue.Values, cloudprovider.MetricValue{ + Timestamp: v.Timestamp, + Value: value, + }) + } + ret = append(ret, metricValue) + } + return ret, nil +} + +func (self *SESXiClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_HOST: + return self.GetHostMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) + } +} + +func (self *SESXiClient) GetMetricTypes() (jsonutils.JSONObject, error) { + perfManager := performance.NewManager(self.client.Client) + counterInfo, err := perfManager.CounterInfoByName(self.context) + if err != nil { + return nil, errors.Wrapf(err, "CounterInfoByName") + } + return jsonutils.Marshal(counterInfo), nil +} diff --git a/pkg/multicloud/esxi/net_topology.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/net_topology.go similarity index 100% rename from pkg/multicloud/esxi/net_topology.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/net_topology.go diff --git a/pkg/multicloud/esxi/net_topology_pro.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/net_topology_pro.go similarity index 100% rename from pkg/multicloud/esxi/net_topology_pro.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/net_topology_pro.go diff --git a/pkg/multicloud/esxi/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/network.go similarity index 100% rename from pkg/multicloud/esxi/network.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/network.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/provider/doc.go new file mode 100644 index 0000000000..183e82c209 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/esxi/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/provider/provider.go new file mode 100644 index 0000000000..888b740815 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/provider/provider.go @@ -0,0 +1,232 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "fmt" + "net/url" + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/regutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/esxi" +) + +type SESXiProviderFactory struct { + cloudprovider.SPremiseBaseProviderFactory +} + +func (self *SESXiProviderFactory) GetId() string { + return esxi.CLOUD_PROVIDER_VMWARE +} + +func (self *SESXiProviderFactory) GetName() string { + return esxi.CLOUD_PROVIDER_VMWARE +} + +func (self *SESXiProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { + return fmt.Errorf("Changing %s bandwidth is not supported", esxi.CLOUD_PROVIDER_VMWARE) +} + +func (self *SESXiProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.Username) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "username") + } + if len(input.Password) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "password") + } + if len(input.Host) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "host") + } + if !regutils.MatchIPAddr(input.Host) && !regutils.MatchDomainName(input.Host) { + return output, errors.Wrap(httperrors.ErrInputParameter, "host should be ip or domain name") + } + output.AccessUrl = fmt.Sprintf("https://%s:%d/sdk", input.Host, input.Port) + if input.Port == 0 || input.Port == 443 { + output.AccessUrl = fmt.Sprintf("https://%s/sdk", input.Host) + } + output.Account = input.Username + output.Secret = input.Password + return output, nil +} + +func (self *SESXiProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.Username) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "username") + } + if len(input.Password) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "password") + } + output = cloudprovider.SCloudaccount{ + Account: input.Username, + Secret: input.Password, + } + return output, nil +} + +func parseHostPort(host string, defPort int) (string, int, error) { + colonPos := strings.IndexByte(host, ':') + if colonPos > 0 { + h := host[:colonPos] + p, err := strconv.Atoi(host[colonPos+1:]) + if err != nil { + log.Errorf("Invalid host %s", host) + return "", 0, err + } + if p == 0 { + p = defPort + } + return h, p, nil + } else { + return host, defPort, nil + } +} + +func (self *SESXiProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + parts, err := url.Parse(cfg.URL) + if err != nil { + return nil, err + } + host, port, err := parseHostPort(parts.Host, 443) + if err != nil { + return nil, err + } + + client, err := esxi.NewESXiClient( + esxi.NewESXiClientConfig( + host, port, cfg.Account, cfg.Secret, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SESXiProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SESXiProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + parts, err := url.Parse(info.Url) + if err != nil { + return nil, err + } + host, port, err := parseHostPort(parts.Host, 443) + if err != nil { + return nil, err + } + + return map[string]string{ + "VMWARE_HOST": host, + "VMWARE_PORT": fmt.Sprintf("%d", port), + "VMWARE_ACCOUNT": info.Account, + "VMWARE_PASSWORD": info.Secret, + }, nil +} + +func (self *SESXiProviderFactory) GetAccountIdEqualizer() func(origin, now string) bool { + return func(origin, now string) bool { + if len(now) == 0 { + return true + } + originUserName, nowUserName := origin, now + index1 := strings.Index(origin, "@") + index2 := strings.Index(now, "@") + if index1 != -1 { + originUserName = originUserName[:index1] + } + if index2 != -1 { + nowUserName = nowUserName[:index2] + } + return originUserName == nowUserName + } +} + +func init() { + factory := SESXiProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SESXiProvider struct { + cloudprovider.SBaseProvider + client *esxi.SESXiClient +} + +func (self *SESXiProvider) GetSysInfo() (jsonutils.JSONObject, error) { + return self.client.About(), nil +} + +func (self *SESXiProvider) GetVersion() string { + return self.client.GetVersion() +} + +func (self *SESXiProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SESXiProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SESXiProvider) GetIRegions() []cloudprovider.ICloudRegion { + return nil +} + +func (self *SESXiProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SESXiProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SESXiProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { + return self.client, nil +} + +func (self *SESXiProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SESXiProvider) GetStorageClasses(regionId string) []string { + return nil +} + +func (self *SESXiProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (self *SESXiProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (self *SESXiProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SESXiProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetMetrics(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/resourcepool.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/resourcepool.go new file mode 100644 index 0000000000..d692b03475 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/resourcepool.go @@ -0,0 +1,58 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "net/url" + "strings" + + "github.com/vmware/govmomi/vim25/mo" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var RESOURCEPOOL_PROPS = []string{"name", "parent", "host"} + +type SResourcePool struct { + multicloud.SProjectBase + multicloud.STagBase + SManagedObject +} + +func (pool *SResourcePool) GetGlobalId() string { + return pool.GetId() +} + +func (pool *SResourcePool) GetStatus() string { + return api.EXTERNAL_PROJECT_STATUS_AVAILABLE +} + +func (pool *SResourcePool) GetName() string { + path := pool.GetPath() + if len(path) > 5 { + path = path[5:] + } + name := []string{} + for _, _name := range path { + p, _ := url.PathUnescape(_name) + name = append([]string{p}, name...) + } + return strings.Join(name, "/") +} + +func NewResourcePool(manager *SESXiClient, rp *mo.ResourcePool, dc *SDatacenter) *SResourcePool { + return &SResourcePool{SManagedObject: newManagedObject(manager, rp, dc)} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/snapshot.go new file mode 100644 index 0000000000..8dc3c431bb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/snapshot.go @@ -0,0 +1,87 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "fmt" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/types" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVirtualMachineSnapshot struct { + multicloud.SResourceBase + multicloud.STagBase + snapshotTree types.VirtualMachineSnapshotTree + vm *SVirtualMachine +} + +func NewSnapshot(st types.VirtualMachineSnapshotTree) *SVirtualMachineSnapshot { + return &SVirtualMachineSnapshot{ + snapshotTree: st, + } +} + +func (s *SVirtualMachineSnapshot) GetId() string { + return moRefId(s.snapshotTree.Snapshot) +} + +func (s *SVirtualMachineSnapshot) GetName() string { + return s.snapshotTree.Name +} + +func (s *SVirtualMachineSnapshot) GetDescription() string { + return s.snapshotTree.Description +} + +func (s *SVirtualMachineSnapshot) GetGlobalId() string { + return fmt.Sprintf("%s-%d", s.vm.GetGlobalId(), s.snapshotTree.Id) +} + +func (s *SVirtualMachineSnapshot) GetStatus() string { + return api.INSTANCE_SNAPSHOT_READY +} + +func (s *SVirtualMachineSnapshot) Refresh() error { + return nil +} + +func (s *SVirtualMachineSnapshot) IsEmulated() bool { + return false +} + +func (s *SVirtualMachineSnapshot) GetProjectId() string { + return s.vm.GetProjectId() +} + +func (s *SVirtualMachineSnapshot) Delete() error { + cTrue := true + req := types.RemoveSnapshot_Task{ + This: s.snapshotTree.Snapshot.Reference(), + RemoveChildren: false, + Consolidate: &cTrue, + } + res, err := methods.RemoveSnapshot_Task(s.vm.manager.context, s.vm.manager.client.Client, &req) + if err != nil { + return errors.Wrap(err, "RemoveSnapshot_Task") + } + return object.NewTask(s.vm.manager.client.Client, res.Returnval).Wait(s.vm.manager.context) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storage.go new file mode 100644 index 0000000000..f2cfdd3fad --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storage.go @@ -0,0 +1,1198 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "bytes" + "context" + "encoding/binary" + "fmt" + "io" + "io/ioutil" + "math/rand" + "net/http" + "net/url" + "os" + "path" + "path/filepath" + "regexp" + "strconv" + "strings" + "text/template" + "time" + "unicode" + + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/ovf" + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/progress" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/vmdkutils" +) + +var DATASTORE_PROPS = []string{"name", "parent", "info", "summary", "host", "vm"} + +type SDatastore struct { + multicloud.SStorageBase + SManagedObject + + // vms []cloudprovider.ICloudVM + + ihosts []cloudprovider.ICloudHost + idisks []cloudprovider.ICloudDisk + + storageCache *SDatastoreImageCache +} + +func NewDatastore(manager *SESXiClient, ds *mo.Datastore, dc *SDatacenter) *SDatastore { + return &SDatastore{SManagedObject: newManagedObject(manager, ds, dc)} +} + +func (self *SDatastore) getDatastore() *mo.Datastore { + return self.object.(*mo.Datastore) +} + +func (self *SDatastore) GetGlobalId() string { + volId, err := self.getVolumeId() + if err != nil { + log.Errorf("get datastore global ID error %s", err) + } + return volId +} + +func (self *SDatastore) GetName() string { + volName, err := self.getVolumeName() + if err != nil { + log.Fatalf("datastore get name error %s", err) + } + return fmt.Sprintf("%s-%s", self.getVolumeType(), volName) +} + +func (self *SDatastore) GetRelName() string { + return self.getDatastore().Info.GetDatastoreInfo().Name +} + +func (self *SDatastore) GetCapacityMB() int64 { + moStore := self.getDatastore() + return moStore.Summary.Capacity / 1024 / 1024 +} + +func (self *SDatastore) GetCapacityUsedMB() int64 { + moStore := self.getDatastore() + return self.GetCapacityMB() - moStore.Summary.FreeSpace/1024/1024 +} + +func (self *SDatastore) GetEnabled() bool { + return true +} + +func (self *SDatastore) GetStatus() string { + if self.getDatastore().Summary.Accessible { + return api.STORAGE_ONLINE + } else { + return api.STORAGE_OFFLINE + } +} + +func (self *SDatastore) Refresh() error { + base := self.SManagedObject + var moObj mo.Datastore + err := self.manager.reference2Object(self.object.Reference(), DATASTORE_PROPS, &moObj) + if err != nil { + return err + } + base.object = &moObj + *self = SDatastore{} + self.SManagedObject = base + return nil +} + +func (self *SDatastore) IsEmulated() bool { + return false +} + +func (self *SDatastore) getVolumeId() (string, error) { + moStore := self.getDatastore() + switch fsInfo := moStore.Info.(type) { + case *types.VmfsDatastoreInfo: + if fsInfo.Vmfs.Local == nil || *fsInfo.Vmfs.Local { + host, err := self.getLocalHost() + if err == nil { + return fmt.Sprintf("%s:%s", host.GetAccessIp(), fsInfo.Vmfs.Uuid), nil + } + } + return fsInfo.Vmfs.Uuid, nil + case *types.NasDatastoreInfo: + return fmt.Sprintf("%s:%s", fsInfo.Nas.RemoteHost, fsInfo.Nas.RemotePath), nil + } + if moStore.Summary.Type == "vsan" { + vsanId := moStore.Summary.Url + vsanId = vsanId[strings.Index(vsanId, "vsan:"):] + endIdx := len(vsanId) + for ; endIdx >= 0 && vsanId[endIdx-1] == '/'; endIdx -= 1 { + } + return vsanId[:endIdx], nil + } + log.Fatalf("unsupported volume type %#v", moStore.Info) + return "", cloudprovider.ErrNotImplemented +} + +func (self *SDatastore) getVolumeType() string { + return self.getDatastore().Summary.Type +} + +func (self *SDatastore) getVolumeName() (string, error) { + moStore := self.getDatastore() + + if self.isLocalVMFS() { + host, err := self.getLocalHost() + if err != nil { + return "", err + } + return fmt.Sprintf("%s-%s", host.GetAccessIp(), moStore.Info.GetDatastoreInfo().Name), nil + } + dc, err := self.GetDatacenter() + if err != nil { + return "", nil + } + return fmt.Sprintf("%s-%s", dc.GetName(), moStore.Info.GetDatastoreInfo().Name), nil +} + +func (self *SDatastore) getAttachedHosts() ([]cloudprovider.ICloudHost, error) { + ihosts := make([]cloudprovider.ICloudHost, 0) + + moStore := self.getDatastore() + for i := 0; i < len(moStore.Host); i += 1 { + idstr := moRefId(moStore.Host[i].Key) + host, err := self.datacenter.GetIHostByMoId(idstr) + if err != nil { + return nil, err + } + ihosts = append(ihosts, host) + } + + return ihosts, nil +} + +func (self *SDatastore) getCachedAttachedHosts() ([]cloudprovider.ICloudHost, error) { + if self.ihosts == nil { + var err error + self.ihosts, err = self.getAttachedHosts() + if err != nil { + return nil, err + } + } + return self.ihosts, nil +} + +func (self *SDatastore) GetAttachedHosts() ([]cloudprovider.ICloudHost, error) { + return self.getCachedAttachedHosts() +} + +func (self *SDatastore) getLocalHost() (cloudprovider.ICloudHost, error) { + hosts, err := self.GetAttachedHosts() + if err != nil { + return nil, errors.Wrap(err, "self.GetAttachedHosts") + } + if len(hosts) == 1 { + return hosts[0], nil + } + return nil, cloudprovider.ErrInvalidStatus +} + +func (self *SDatastore) GetIStoragecache() cloudprovider.ICloudStoragecache { + if self.isLocalVMFS() { + ihost, err := self.getLocalHost() + if err != nil { + log.Errorf("GetIStoragecache getLocalHost fail %s", err) + return nil + } + host := ihost.(*SHost) + sc, err := host.getLocalStorageCache() + if err != nil { + log.Errorf("GetIStoragecache getLocalStorageCache fail %s", err) + return nil + } + return sc + } else { + return self.getStorageCache() + } +} + +func (self *SDatastore) getStorageCache() *SDatastoreImageCache { + if self.storageCache == nil { + self.storageCache = &SDatastoreImageCache{ + datastore: self, + } + } + return self.storageCache +} + +func (self *SDatastore) GetIZone() cloudprovider.ICloudZone { + return nil +} + +func (self *SDatastore) FetchNoTemplateVMs() ([]*SVirtualMachine, error) { + mods := self.getDatastore() + filter := property.Filter{} + filter["datastore"] = mods.Reference() + return self.datacenter.fetchVMsWithFilter(filter) +} + +func (self *SDatastore) FetchTemplateVMs() ([]*SVirtualMachine, error) { + mods := self.getDatastore() + filter := property.Filter{} + filter["config.template"] = true + filter["datastore"] = mods.Reference() + return self.datacenter.fetchVMsWithFilter(filter) +} + +func (self *SDatastore) FetchTemplateVMById(id string) (*SVirtualMachine, error) { + mods := self.getDatastore() + filter := property.Filter{} + uuid := toTemplateUuid(id) + filter["summary.config.uuid"] = uuid + filter["config.template"] = true + filter["datastore"] = mods.Reference() + vms, err := self.datacenter.fetchVMsWithFilter(filter) + if err != nil { + return nil, err + } + if len(vms) == 0 { + return nil, errors.ErrNotFound + } + return vms[0], nil +} + +func (self *SDatastore) FetchFakeTempateVMById(id string, regex string) (*SVirtualMachine, error) { + mods := self.getDatastore() + filter := property.Filter{} + uuid := toTemplateUuid(id) + filter["summary.config.uuid"] = uuid + filter["datastore"] = mods.Reference() + filter["summary.runtime.powerState"] = types.VirtualMachinePowerStatePoweredOff + filter["config.template"] = false + movms, err := self.datacenter.fetchMoVms(filter, []string{"name"}) + if err != nil { + return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines") + } + vms, err := self.datacenter.fetchFakeTemplateVMs(movms, regex) + if err != nil { + return nil, err + } + if len(vms) == 0 { + return nil, errors.ErrNotFound + } + return vms[0], nil +} + +func (self *SDatastore) FetchFakeTempateVMs(regex string) ([]*SVirtualMachine, error) { + mods := self.getDatastore() + filter := property.Filter{} + filter["datastore"] = mods.Reference() + filter["summary.runtime.powerState"] = types.VirtualMachinePowerStatePoweredOff + filter["config.template"] = false + movms, err := self.datacenter.fetchMoVms(filter, []string{"name"}) + if err != nil { + return nil, errors.Wrap(err, "unable to fetch mo.VirtualMachines") + } + return self.datacenter.fetchFakeTemplateVMs(movms, regex) +} + +func (self *SDatastore) getVMs() ([]cloudprovider.ICloudVM, error) { + dc, err := self.GetDatacenter() + if err != nil { + log.Errorf("SDatastore GetDatacenter fail %s", err) + return nil, err + } + vms := self.getDatastore().Vm + if len(vms) == 0 { + return nil, nil + } + svms, err := dc.fetchVmsFromCache(vms) + if err != nil { + return nil, err + } + ret := make([]cloudprovider.ICloudVM, len(svms)) + for i := range svms { + ret[i] = svms[i] + } + return ret, err +} + +func (self *SDatastore) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + vms, err := self.getVMs() + if err != nil { + log.Errorf("self.getVMs fail %s", err) + return nil, err + } + for i := 0; i < len(vms); i += 1 { + vm := vms[i].(*SVirtualMachine) + disk, err := vm.GetIDiskById(idStr) + if err == nil { + return disk, nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SDatastore) fetchDisks() error { + vms, err := self.getVMs() + if err != nil { + return err + } + allDisks := make([]cloudprovider.ICloudDisk, 0) + for i := 0; i < len(vms); i += 1 { + disks, err := vms[i].GetIDisks() + if err != nil { + return err + } + allDisks = append(allDisks, disks...) + } + self.idisks = allDisks + return nil +} + +func (self *SDatastore) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + if self.idisks != nil { + return self.idisks, nil + } + err := self.fetchDisks() + if err != nil { + return nil, err + } + return self.idisks, nil +} + +func (self *SDatastore) isLocalVMFS() bool { + moStore := self.getDatastore() + switch vmfsInfo := moStore.Info.(type) { + case *types.VmfsDatastoreInfo: + if vmfsInfo.Vmfs.Local == nil || *vmfsInfo.Vmfs.Local == true { + _, err := self.getLocalHost() + if err == nil { + return true + } + } + } + return false +} + +func (self *SDatastore) GetStorageType() string { + moStore := self.getDatastore() + t := strings.ToLower(moStore.Summary.Type) + switch t { + case "vmfs": + if self.isLocalVMFS() { + return api.STORAGE_LOCAL + } else { + return api.STORAGE_NAS + } + case "nfs", "nfs41": + return api.STORAGE_NFS + case "vsan": + return api.STORAGE_VSAN + case "cifs": + return api.STORAGE_CIFS + default: + log.Fatalf("unsupported datastore type %s", moStore.Summary.Type) + return "" + } +} + +func (self *SDatastore) GetMediumType() string { + moStore := self.getDatastore() + vmfsInfo, ok := moStore.Info.(*types.VmfsDatastoreInfo) + if ok && vmfsInfo.Vmfs.Ssd != nil && *vmfsInfo.Vmfs.Ssd { + return api.DISK_TYPE_SSD + } + return api.DISK_TYPE_ROTATE +} + +func (self *SDatastore) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + conf.Add(jsonutils.NewString(self.GetName()), "name") + conf.Add(jsonutils.NewString(self.GetGlobalId()), "id") + conf.Add(jsonutils.NewString(self.GetDatacenterPathString()), "dc_path") + volId, err := self.getVolumeId() + if err != nil { + log.Errorf("getVaolumeId fail %s", err) + } + conf.Add(jsonutils.NewString(volId), "volume_id") + + volType := self.getVolumeType() + conf.Add(jsonutils.NewString(volType), "volume_type") + + volName, err := self.getVolumeName() + if err != nil { + log.Errorf("getVaolumeName fail %s", err) + } + conf.Add(jsonutils.NewString(volName), "volume_name") + return conf +} + +const dsPrefix = "ds://" + +func (self *SDatastore) GetUrl() string { + url := self.getDatastore().Info.GetDatastoreInfo().Url + if strings.HasPrefix(url, dsPrefix) { + url = url[len(dsPrefix):] + } + return url +} + +func (self *SDatastore) GetMountPoint() string { + return self.GetUrl() +} + +func (self *SDatastore) HasFile(remotePath string) bool { + dsName := fmt.Sprintf("[%s]", self.SManagedObject.GetName()) + if strings.HasPrefix(remotePath, dsName) { + return true + } else { + return false + } +} + +func (self *SDatastore) cleanPath(remotePath string) string { + dsName := fmt.Sprintf("[%s]", self.SManagedObject.GetName()) + dsUrl := self.GetUrl() + if strings.HasPrefix(remotePath, dsName) { + remotePath = remotePath[len(dsName):] + } else if strings.HasPrefix(remotePath, dsUrl) { + remotePath = remotePath[len(dsUrl):] + } + return strings.TrimSpace(remotePath) +} + +func pathEscape(path string) string { + segs := strings.Split(path, "/") + for i := 0; i < len(segs); i += 1 { + segs[i] = url.PathEscape(segs[i]) + } + return strings.Join(segs, "/") +} + +func (self *SDatastore) GetPathUrl(remotePath string) string { + remotePath = self.cleanPath(remotePath) + if len(remotePath) == 0 || remotePath[0] != '/' { + remotePath = fmt.Sprintf("/%s", remotePath) + } + httpUrl := fmt.Sprintf("%s/folder%s", self.getManagerUri(), pathEscape(remotePath)) + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(self.SManagedObject.GetName()), "dsName") + params.Add(jsonutils.NewString(self.GetDatacenterPathString()), "dcPath") + + return fmt.Sprintf("%s?%s", httpUrl, params.QueryString()) +} + +func (self *SDatastore) getPathString(path string) string { + for len(path) > 0 && path[0] == '/' { + path = path[1:] + } + return fmt.Sprintf("[%s] %s", self.SManagedObject.GetName(), path) +} + +func (self *SDatastore) GetFullPath(remotePath string) string { + remotePath = self.cleanPath(remotePath) + return path.Join(self.GetUrl(), remotePath) +} + +func (self *SDatastore) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDatastore) FileGetContent(ctx context.Context, remotePath string) ([]byte, error) { + url := self.GetPathUrl(remotePath) + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, err + } + + var bytes []byte + + err = self.manager.client.Do(ctx, req, func(resp *http.Response) error { + if resp.StatusCode == 404 { + return cloudprovider.ErrNotFound + } + if resp.StatusCode >= 400 { + return fmt.Errorf("%s", resp.Status) + } + cont, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + bytes = cont + return nil + }) + + return bytes, err +} + +type SDatastoreFileInfo struct { + Url string + Name string + Date time.Time + FileType string + Size uint64 +} + +const ( + fileListPattern = `(?P[^<]+)<\/a>(?P[^<]+)(?P[^<]+)` + fileDateFormat = "02-Jan-2006 15:04" + fileDateFormat2 = "Mon, 2 Jan 2006 15:04:05 GMT" +) + +var ( + fileListRegexp = regexp.MustCompile(fileListPattern) +) + +func (self *SDatastore) ListDir(ctx context.Context, remotePath string) ([]SDatastoreFileInfo, error) { + listContent, err := self.FileGetContent(ctx, remotePath) + if err != nil { + return nil, err + } + ret := make([]SDatastoreFileInfo, 0) + matches := fileListRegexp.FindAllStringSubmatch(string(listContent), -1) + for r := 0; r < len(matches); r += 1 { + url := strings.TrimSpace(matches[r][1]) + name := strings.TrimSpace(matches[r][2]) + dateStr := strings.TrimSpace(matches[r][3]) + sizeStr := strings.TrimSpace(matches[r][4]) + var ftype string + var size uint64 + if sizeStr == "-" { + ftype = "dir" + size = 0 + } else { + ftype = "file" + size, _ = strconv.ParseUint(sizeStr, 10, 64) + } + date, err := time.Parse(fileDateFormat, dateStr) + if err != nil { + return nil, err + } + info := SDatastoreFileInfo{ + Url: url, + Name: name, + FileType: ftype, + Size: size, + Date: date, + } + ret = append(ret, info) + } + + return ret, nil +} + +func (self *SDatastore) listPath(b *object.HostDatastoreBrowser, path string, spec types.HostDatastoreBrowserSearchSpec) ([]types.HostDatastoreBrowserSearchResults, error) { + ctx := context.TODO() + + path = self.getDatastoreObj().Path(path) + + search := b.SearchDatastore + + task, err := search(ctx, path, &spec) + if err != nil { + return nil, err + } + + info, err := task.WaitForResult(ctx, nil) + if err != nil { + return nil, err + } + + switch r := info.Result.(type) { + case types.HostDatastoreBrowserSearchResults: + return []types.HostDatastoreBrowserSearchResults{r}, nil + case types.ArrayOfHostDatastoreBrowserSearchResults: + return r.HostDatastoreBrowserSearchResults, nil + default: + return nil, errors.Error(fmt.Sprintf("unknown result type: %T", r)) + } + +} + +func (self *SDatastore) ListPath(ctx context.Context, remotePath string) ([]types.HostDatastoreBrowserSearchResults, error) { + //types.HostDatastoreBrowserSearchResults + ds := self.getDatastoreObj() + + b, err := ds.Browser(ctx) + if err != nil { + return nil, err + } + + ret := make([]types.HostDatastoreBrowserSearchResults, 0) + + spec := types.HostDatastoreBrowserSearchSpec{ + MatchPattern: []string{"*"}, + Details: &types.FileQueryFlags{ + FileType: true, + FileSize: true, + FileOwner: types.NewBool(true), // TODO: omitempty is generated, but seems to be required + Modification: true, + }, + } + + for i := 0; ; i++ { + r, err := self.listPath(b, remotePath, spec) + if err != nil { + // Treat the argument as a match pattern if not found as directory + if i == 0 && types.IsFileNotFound(err) || isInvalid(err) { + spec.MatchPattern[0] = path.Base(remotePath) + remotePath = path.Dir(remotePath) + continue + } + if types.IsFileNotFound(err) { + return nil, errors.ErrNotFound + } + return nil, err + } + if i == 1 && len(r) == 1 && len(r[0].File) == 0 { + return nil, errors.ErrNotFound + } + for n := range r { + ret = append(ret, r[n]) + } + break + } + return ret, nil +} + +func isInvalid(err error) bool { + if f, ok := err.(types.HasFault); ok { + switch f.Fault().(type) { + case *types.InvalidArgument: + return true + } + } + + return false +} + +func (self *SDatastore) CheckFile(ctx context.Context, remotePath string) (*SDatastoreFileInfo, error) { + url := self.GetPathUrl(remotePath) + + req, err := http.NewRequest("HEAD", url, nil) + if err != nil { + return nil, err + } + + var size uint64 + var date time.Time + + err = self.manager.client.Do(ctx, req, func(resp *http.Response) error { + if resp.StatusCode >= 400 { + if resp.StatusCode == 404 { + return cloudprovider.ErrNotFound + } + return fmt.Errorf("%s", resp.Status) + } + sizeStr := resp.Header.Get("Content-Length") + size, _ = strconv.ParseUint(sizeStr, 10, 64) + + dateStr := resp.Header.Get("Date") + date, _ = time.Parse(fileDateFormat2, dateStr) + return nil + }) + + if err != nil { + return nil, err + } + return &SDatastoreFileInfo{Date: date, Size: size}, nil +} + +func (self *SDatastore) Download(ctx context.Context, remotePath string, writer io.Writer) error { + url := self.GetPathUrl(remotePath) + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return err + } + + err = self.manager.client.Do(ctx, req, func(resp *http.Response) error { + if resp.StatusCode >= 400 { + return fmt.Errorf("%s", resp.Status) + } + buffer := make([]byte, 4096) + for { + rn, re := resp.Body.Read(buffer) + if rn > 0 { + wo := 0 + for wo < rn { + wn, we := writer.Write(buffer[wo:rn]) + if we != nil { + return we + } + wo += wn + } + } + if re != nil { + if re != io.EOF { + return re + } else { + break + } + } + } + return nil + }) + + return err +} + +func (self *SDatastore) Upload(ctx context.Context, remotePath string, body io.Reader) error { + url := self.GetPathUrl(remotePath) + + req, err := http.NewRequest("PUT", url, body) + if err != nil { + return err + } + + err = self.manager.client.Do(ctx, req, func(resp *http.Response) error { + if resp.StatusCode >= 400 { + return fmt.Errorf("%s", resp.Status) + } + _, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + // log.Debugf("upload respose %s", buffer) + return nil + }) + + return err +} + +func (self *SDatastore) FilePutContent(ctx context.Context, remotePath string, content string) error { + return self.Upload(ctx, remotePath, strings.NewReader(content)) +} + +// Delete2 can delete file from this Datastore. +// isNamespace: remotePath is uuid of namespace on vsan datastore +// force: ignore nonexistent files and arguments +func (self *SDatastore) Delete2(ctx context.Context, remotePath string, isNamespace, force bool) error { + var err error + ds := self.getDatastoreObj() + dc := self.datacenter.getObjectDatacenter() + if isNamespace { + nm := object.NewDatastoreNamespaceManager(self.manager.client.Client) + err = nm.DeleteDirectory(ctx, dc, remotePath) + } else { + fm := ds.NewFileManager(dc, force) + err = fm.Delete(ctx, remotePath) + } + + if err != nil && types.IsFileNotFound(err) && force { + // Ignore error + return nil + } + return err +} + +func (self *SDatastore) Delete(ctx context.Context, remotePath string) error { + url := self.GetPathUrl(remotePath) + + req, err := http.NewRequest("DELETE", url, nil) + if err != nil { + return err + } + + err = self.manager.client.Do(ctx, req, func(resp *http.Response) error { + if resp.StatusCode >= 400 { + return fmt.Errorf("%s", resp.Status) + } + _, err := ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + // log.Debugf("delete respose %s", buffer) + return nil + }) + + return err +} + +func (self *SDatastore) DeleteVmdk(ctx context.Context, remotePath string) error { + info, err := self.CheckFile(ctx, remotePath) + if err != nil { + return err + } + if info.Size > 4096 { + return fmt.Errorf("not a valid vmdk file") + } + vmdkContent, err := self.FileGetContent(ctx, remotePath) + if err != nil { + return err + } + vmdkInfo, err := vmdkutils.Parse(string(vmdkContent)) + if err != nil { + return err + } + err = self.Delete(ctx, remotePath) + if err != nil { + return err + } + if len(vmdkInfo.ExtentFile) > 0 { + err = self.Delete(ctx, path.Join(path.Dir(remotePath), vmdkInfo.ExtentFile)) + if err != nil { + return err + } + } + return nil +} + +func (self *SDatastore) GetVmdkInfo(ctx context.Context, remotePath string) (*vmdkutils.SVMDKInfo, error) { + vmdkContent, err := self.FileGetContent(ctx, remotePath) + if err != nil { + return nil, err + } + return vmdkutils.Parse(string(vmdkContent)) +} + +func (self *SDatastore) CheckVmdk(ctx context.Context, remotePath string) error { + dm := object.NewVirtualDiskManager(self.manager.client.Client) + + dc, err := self.GetDatacenter() + if err != nil { + return err + } + + dcObj := dc.getObjectDatacenter() + + infoList, err := dm.QueryVirtualDiskInfo(ctx, self.getPathString(remotePath), dcObj, true) + if err != nil { + return err + } + + log.Debugf("%#v", infoList) + return nil +} + +func (self *SDatastore) getDatastoreObj() *object.Datastore { + od := object.NewDatastore(self.manager.client.Client, self.getDatastore().Self) + od.DatacenterPath = self.GetDatacenterPathString() + od.InventoryPath = fmt.Sprintf("%s/%s", od.DatacenterPath, self.SManagedObject.GetName()) + return od +} + +func (self *SDatastore) MakeDir(remotePath string) error { + remotePath = self.cleanPath(remotePath) + + m := object.NewFileManager(self.manager.client.Client) + path := fmt.Sprintf("[%s] %s", self.GetRelName(), remotePath) + return m.MakeDirectory(self.manager.context, path, self.datacenter.getObjectDatacenter(), true) +} + +func (self *SDatastore) RemoveDir(ctx context.Context, remotePath string) error { + dnm := object.NewDatastoreNamespaceManager(self.manager.client.Client) + + remotePath = self.GetFullPath(remotePath) + + dc, err := self.GetDatacenter() + if err != nil { + return err + } + + dcObj := dc.getObjectDatacenter() + + return dnm.DeleteDirectory(ctx, dcObj, remotePath) +} + +// CheckDirC will check that Dir 'remotePath' is exist, if not, create one. +func (self *SDatastore) CheckDirC(remotePath string) error { + _, err := self.CheckFile(self.manager.context, remotePath) + if err == nil { + return nil + } + if errors.Cause(err) != cloudprovider.ErrNotFound { + return err + } + return self.MakeDir(remotePath) + +} + +func (self *SDatastore) IsSysDiskStore() bool { + return true +} + +func (self *SDatastore) MoveVmdk(ctx context.Context, srcPath string, dstPath string) error { + dm := object.NewVirtualDiskManager(self.manager.client.Client) + defer dm.Destroy(ctx) + + srcUrl := self.GetPathUrl(srcPath) + dstUrl := self.GetPathUrl(dstPath) + task, err := dm.MoveVirtualDisk(ctx, srcUrl, nil, dstUrl, nil, true) + if err != nil { + return err + } + return task.Wait(ctx) +} + +// domainName will abandon the rune which should't disapear +func (self *SDatastore) domainName(name string) string { + var b bytes.Buffer + for _, r := range name { + if b.Len() == 0 { + if unicode.IsLetter(r) { + b.WriteRune(r) + } + } else { + if unicode.IsDigit(r) || unicode.IsLetter(r) || r == '-' { + b.WriteRune(r) + } + } + } + return strings.TrimRight(b.String(), "-") +} + +// ImportVMDK will upload local vmdk 'diskFile' to the 'remotePath' of remote datastore +func (self *SDatastore) ImportVMDK(ctx context.Context, diskFile, remotePath string, host *SHost) error { + name := fmt.Sprintf("yunioncloud.%s%d", self.domainName(remotePath)[:20], rand.Int()) + vm, err := self.ImportVM(ctx, diskFile, name, host) + if err != nil { + return errors.Wrap(err, "SDatastore.ImportVM") + } + + defer func() { + task, err := vm.Destroy(ctx) + if err != nil { + log.Errorf("vm.Destory: %s", err) + return + } + + if err = task.Wait(ctx); err != nil { + log.Errorf("task.Wait: %s", err) + } + }() + + // check if 'image_cache' is esixt + err = self.CheckDirC("image_cache") + if err != nil { + return errors.Wrap(err, "SDatastore.CheckDirC") + } + + fm := self.getDatastoreObj().NewFileManager(self.datacenter.getObjectDatacenter(), true) + + // if image_cache not exist + return fm.Move(ctx, fmt.Sprintf("[%s] %s/%s.vmdk", self.GetRelName(), name, name), fmt.Sprintf("[%s] %s", + self.GetRelName(), remotePath)) +} + +func (self *SDatastore) ImportISO(ctx context.Context, isoFile, remotePath string, host *SHost) error { + p := soap.DefaultUpload + ds := self.getDatastoreObj() + return ds.UploadFile(ctx, isoFile, remotePath, &p) +} + +var ( + ErrInvalidFormat = errors.Error("vmdk: invalid format (must be streamOptimized)") +) + +// info is used to inspect a vmdk and generate an ovf template +type info struct { + Header struct { + MagicNumber uint32 + Version uint32 + Flags uint32 + Capacity uint64 + } + + Capacity uint64 + Size int64 + Name string + ImportName string +} + +// stat looks at the vmdk header to make sure the format is streamOptimized and +// extracts the disk capacity required to properly generate the ovf descriptor. +func stat(name string) (*info, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + + var ( + di info + buf bytes.Buffer + ) + + _, err = io.CopyN(&buf, f, int64(binary.Size(di.Header))) + fi, _ := f.Stat() + _ = f.Close() + if err != nil { + return nil, err + } + + err = binary.Read(&buf, binary.LittleEndian, &di.Header) + if err != nil { + return nil, err + } + + if di.Header.MagicNumber != 0x564d444b { // SPARSE_MAGICNUMBER + return nil, ErrInvalidFormat + } + + if di.Header.Flags&(1<<16) == 0 { // SPARSEFLAG_COMPRESSED + // Needs to be converted, for example: + // vmware-vdiskmanager -r src.vmdk -t 5 dst.vmdk + // qemu-img convert -O vmdk -o subformat=streamOptimized src.vmdk dst.vmdk + return nil, ErrInvalidFormat + } + + di.Capacity = di.Header.Capacity * 512 // VMDK_SECTOR_SIZE + di.Size = fi.Size() + di.Name = filepath.Base(name) + di.ImportName = strings.TrimSuffix(di.Name, ".vmdk") + + return &di, nil +} + +// ovf returns an expanded descriptor template +func (di *info) ovf() (string, error) { + var buf bytes.Buffer + + tmpl, err := template.ParseFiles("/opt/yunion/share/vmware/ovf.xml") + if err != nil { + return "", err + } + + err = tmpl.Execute(&buf, di) + if err != nil { + return "", err + } + + return buf.String(), nil +} + +// ImportParams contains the set of optional params to the Import function. +// Note that "optional" may depend on environment, such as ESX or vCenter. +type ImportParams struct { + Path string + Logger progress.Sinker + Type types.VirtualDiskType + Force bool + Datacenter *object.Datacenter + Pool *object.ResourcePool + Folder *object.Folder + Host *object.HostSystem +} + +// ImportVM will import a vm by uploading a local vmdk +func (self *SDatastore) ImportVM(ctx context.Context, diskFile, name string, host *SHost) (*object.VirtualMachine, error) { + + var ( + c = self.manager.client.Client + datastore = self.getDatastoreObj() + ) + + m := ovf.NewManager(c) + + disk, err := stat(diskFile) + if err != nil { + return nil, errors.Wrap(err, "stat") + } + + disk.ImportName = name + + // Expand the ovf template + descriptor, err := disk.ovf() + if err != nil { + return nil, errors.Wrap(err, "disk.ovf") + } + + folders, err := self.datacenter.getObjectDatacenter().Folders(ctx) + if err != nil { + return nil, errors.Wrap(err, "Folders") + } + pool, err := host.GetResourcePool() + if err != nil { + return nil, errors.Wrap(err, "getResourcePool") + } + + kind := types.VirtualDiskTypeThin + + params := types.OvfCreateImportSpecParams{ + DiskProvisioning: string(kind), + EntityName: disk.ImportName, + } + + spec, err := m.CreateImportSpec(ctx, descriptor, pool, datastore, params) + if err != nil { + return nil, err + } + if spec.Error != nil { + return nil, errors.Error(spec.Error[0].LocalizedMessage) + } + + lease, err := pool.ImportVApp(ctx, spec.ImportSpec, folders.VmFolder, host.GetoHostSystem()) + if err != nil { + return nil, err + } + + info, err := lease.Wait(ctx, spec.FileItem) + if err != nil { + return nil, err + } + + f, err := os.Open(diskFile) + if err != nil { + return nil, err + } + + lr := newLeaseLogger("upload vmdk", 5) + + lr.Log() + defer lr.End() + + opts := soap.Upload{ + ContentLength: disk.Size, + Progress: lr, + } + + u := lease.StartUpdater(ctx, info) + defer u.Done() + + item := info.Items[0] // we only have 1 disk to upload + + err = lease.Upload(ctx, item, f, opts) + + _ = f.Close() + + if err != nil { + return nil, errors.Wrap(err, "lease.Upload") + } + + if err = lease.Complete(ctx); err != nil { + log.Debugf("lease complete error: %s, sleep 1s and try again", err) + time.Sleep(time.Second) + if err = lease.Complete(ctx); err != nil { + return nil, errors.Wrap(err, "lease.Complete") + } + } + + return object.NewVirtualMachine(c, info.Entity), nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storagecache.go new file mode 100644 index 0000000000..d750975aa7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/storagecache.go @@ -0,0 +1,292 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "context" + "fmt" + "path" + "regexp" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + IMAGE_CACHE_DIR_NAME = "image_cache" +) + +type SDatastoreImageCache struct { + multicloud.SResourceBase + multicloud.STagBase + datastore *SDatastore + host *SHost +} + +type EsxiOptions struct { + ReasonableCIDREsxi string `help:"Reasonable CIDR in esxi, such as '10.0.0.0/8'" defautl:""` + TemplateNameRegex string `help:"Regex of template name"` +} + +var tempalteNameRegex *regexp.Regexp + +func InitEsxiConfig(opt EsxiOptions) error { + var err error + if len(opt.TemplateNameRegex) != 0 { + tempalteNameRegex, err = regexp.Compile(opt.TemplateNameRegex) + if err != nil { + return errors.Wrap(err, "regexp.Compile") + } + } + return initVMIPV4Filter(opt.ReasonableCIDREsxi) +} + +func (self *SDatastoreImageCache) GetId() string { + if self.host != nil { + return self.host.GetGlobalId() + } else { + return self.datastore.GetGlobalId() + } +} + +func (self *SDatastoreImageCache) GetName() string { + if self.host != nil { + return fmt.Sprintf("storage-cache-%s", self.host.GetName()) + } else { + return fmt.Sprintf("storage-cache-%s", self.datastore.GetName()) + } +} + +func (self *SDatastoreImageCache) GetGlobalId() string { + return self.GetId() +} + +func (self *SDatastoreImageCache) GetStatus() string { + return "available" +} + +func (self *SDatastoreImageCache) Refresh() error { + return nil +} + +func (self *SDatastoreImageCache) IsEmulated() bool { + return false +} + +func (self *SDatastoreImageCache) GetPath() string { + return path.Join(self.datastore.GetMountPoint(), IMAGE_CACHE_DIR_NAME) +} + +func (self *SDatastoreImageCache) getTempalteVMs() ([]*SVirtualMachine, error) { + return self.datastore.FetchTemplateVMs() +} + +func (self *SDatastoreImageCache) getFakeTempateVMs() ([]*SVirtualMachine, error) { + if tempalteNameRegex == nil { + return nil, nil + } + return self.datastore.FetchFakeTempateVMs("") +} + +func (self *SDatastoreImageCache) GetIImageInImagecache() ([]cloudprovider.ICloudImage, error) { + ctx := context.Background() + ret := make([]cloudprovider.ICloudImage, 0, 2) + files, err := self.datastore.ListDir(ctx, IMAGE_CACHE_DIR_NAME) + if errors.Cause(err) == errors.ErrNotFound { + return ret, nil + } + if err != nil { + log.Errorf("GetIImages ListDir fail %s", err) + return ret, nil + } + + validFilenames := make(map[string]bool) + + for i := 0; i < len(files); i += 1 { + filename := path.Join(IMAGE_CACHE_DIR_NAME, files[i].Name) + if err := self.datastore.CheckVmdk(ctx, filename); err != nil { + continue + } + vmdkInfo, err := self.datastore.GetVmdkInfo(ctx, filename) + if err != nil { + continue + } + image := SImage{ + cache: self, + filename: filename, + size: vmdkInfo.Size(), + createAt: files[i].Date, + } + ret = append(ret, &image) + vmdkName := files[i].Name + vmdkExtName := fmt.Sprintf("%s-flat.vmdk", vmdkName[:len(vmdkName)-5]) + validFilenames[vmdkName] = true + validFilenames[vmdkExtName] = true + } + + log.Debugf("storage cache contains %#v", validFilenames) + // cleanup storage cache!!! + for i := 0; i < len(files); i += 1 { + if _, ok := validFilenames[files[i].Name]; !ok { + log.Debugf("delete invalid vmdk file %s!!!", files[i].Name) + self.datastore.Delete(ctx, path.Join(IMAGE_CACHE_DIR_NAME, files[i].Name)) + } + } + + return ret, nil +} + +var ErrTimeConsuming = errors.Error("time consuming") + +func (self *SDatastoreImageCache) getTemplateVMsFromCache() ([]*SVirtualMachine, error) { + ihosts, err := self.datastore.datacenter.GetIHosts() + if err != nil { + return nil, err + } + dsRef := self.datastore.getDatastore().Self + ret := make([]*SVirtualMachine, 0) + for i := range ihosts { + tvms := ihosts[i].(*SHost).tempalteVMs + if tvms == nil { + return nil, ErrTimeConsuming + } + for _, vm := range tvms { + dss := vm.getVirtualMachine().Datastore + for _, ds := range dss { + if ds == dsRef { + ret = append(ret, vm) + break + } + } + } + } + return ret, nil +} + +func (self *SDatastoreImageCache) GetIImageInTemplateVMs() ([]cloudprovider.ICloudImage, error) { + ret := make([]cloudprovider.ICloudImage, 0, 2) + log.Infof("start to GetIImages") + + datastore := self.datastore + if datastore.datacenter.ihosts != nil { + vms, err := self.getTemplateVMsFromCache() + if err == nil { + for i := range vms { + ret = append(ret, NewVMTemplate(vms[i], self)) + } + return ret, nil + } + } + realTemplates, err := self.getTempalteVMs() + if err != nil { + return nil, errors.Wrap(err, "getTemplateVMs") + } + fakeTemplates, err := self.getFakeTempateVMs() + if err != nil { + return nil, errors.Wrap(err, "getFakeTempateVMs") + } + + for i := range realTemplates { + ret = append(ret, NewVMTemplate(realTemplates[i], self)) + } + for i := range fakeTemplates { + ret = append(ret, NewVMTemplate(fakeTemplates[i], self)) + } + + log.Infof("get templates successfully") + log.Debugf("fake template name: ") + for i := range fakeTemplates { + log.Debugf("%s ", fakeTemplates[i].GetName()) + } + log.Debugf("real template name: ") + for i := range realTemplates { + log.Debugf("%s ", realTemplates[i].GetName()) + } + return ret, nil +} + +func (self *SDatastoreImageCache) GetIImageInTemplateVMsById(id string) (cloudprovider.ICloudImage, error) { + if tempalteNameRegex != nil { + vm, err := self.datastore.FetchFakeTempateVMById(id, "") + log.Infof("FetchFakeTempateVMById: %v, %v", vm, err) + if err == nil { + return NewVMTemplate(vm, self), nil + } + if errors.Cause(err) != errors.ErrNotFound { + return nil, err + } + } + vm, err := self.datastore.FetchTemplateVMById(id) + if err == nil { + return NewVMTemplate(vm, self), nil + } + return nil, err +} + +func (self *SDatastoreImageCache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDatastoreImageCache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + images1, err := self.GetIImageInTemplateVMs() + if err != nil { + return nil, err + } + return images1, nil + // images2, err := self.GetIImageInImagecache() + // if err != nil { + // return nil, err + // } + // return append(images1, images2...), nil +} + +func (self *SDatastoreImageCache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + // check templatevms + image, err := self.GetIImageInTemplateVMsById(extId) + if err == nil { + return image, nil + } + if errors.Cause(err) != errors.ErrNotFound { + return nil, err + } + log.Infof("start to GetIImageInImagecache") + images, err := self.GetIImageInImagecache() + if err != nil { + return nil, err + } + for i := 0; i < len(images); i += 1 { + if images[i].GetGlobalId() == extId { + return images[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SDatastoreImageCache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDatastoreImageCache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDatastoreImageCache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return "", cloudprovider.ErrNotImplemented +} diff --git a/pkg/multicloud/esxi/template.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/template.go similarity index 97% rename from pkg/multicloud/esxi/template.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/template.go index e904a02212..6ea4291758 100644 --- a/pkg/multicloud/esxi/template.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/template.go @@ -23,9 +23,9 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SVMTemplate struct { diff --git a/pkg/multicloud/esxi/utils.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/utils.go similarity index 100% rename from pkg/multicloud/esxi/utils.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/utils.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter/doc.go new file mode 100644 index 0000000000..0e9ec3750d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 vcenter // import "yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter" diff --git a/pkg/multicloud/esxi/vcenter/vcenter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter/vcenter.go similarity index 100% rename from pkg/multicloud/esxi/vcenter/vcenter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter/vcenter.go diff --git a/pkg/multicloud/esxi/vdisk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vdisk.go similarity index 98% rename from pkg/multicloud/esxi/vdisk.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vdisk.go index 3a3e7b4a87..00de638ed5 100644 --- a/pkg/multicloud/esxi/vdisk.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vdisk.go @@ -27,13 +27,13 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/apis/compute" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/apis/compute" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" deployapi "yunion.io/x/onecloud/pkg/hostman/hostdeployer/apis" "yunion.io/x/onecloud/pkg/hostman/hostdeployer/deployclient" - "yunion.io/x/onecloud/pkg/multicloud" - "yunion.io/x/onecloud/pkg/multicloud/esxi/vcenter" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/esxi/vcenter" ) var driverMap = map[string]string{ diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/virtualmachine.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/virtualmachine.go new file mode 100644 index 0000000000..5018a61c9a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/virtualmachine.go @@ -0,0 +1,1534 @@ +// Copyright 2019 Yunion +// +// 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 esxi + +import ( + "context" + "fmt" + "reflect" + "sort" + "strings" + "time" + + "github.com/vmware/govmomi/nfc" + "github.com/vmware/govmomi/object" + "github.com/vmware/govmomi/vim25/methods" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/soap" + "github.com/vmware/govmomi/vim25/types" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + "yunion.io/x/pkg/util/reflectutils" + "yunion.io/x/pkg/util/regutils" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" + cloudtypes "yunion.io/x/onecloud/pkg/cloudcommon/types" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/imagetools" + "yunion.io/x/onecloud/pkg/util/netutils2" + "yunion.io/x/onecloud/pkg/util/version" +) + +var ( + vmSummaryProps = []string{"summary.runtime.powerState", "summary.config.uuid", "summary.config.memorySizeMB", "summary.config.numCpu"} + // vmConfigProps = []string{"config.template", "config.alternateGuestName", "config.hardware", "config.guestId", "config.guestFullName", "config.firmware", "config.version", "config.createDate"} + vmGuestProps = []string{"guest.net", "guest.guestState", "guest.toolsStatus", "guest.toolsRunningStatus", "guest.toolsVersion"} + vmLayoutExProps = []string{"layoutEx.file"} +) + +var VIRTUAL_MACHINE_PROPS = []string{"name", "parent", "resourcePool", "snapshot", "config"} + +func init() { + VIRTUAL_MACHINE_PROPS = append(VIRTUAL_MACHINE_PROPS, vmSummaryProps...) + // VIRTUAL_MACHINE_PROPS = append(VIRTUAL_MACHINE_PROPS, vmConfigProps...) + VIRTUAL_MACHINE_PROPS = append(VIRTUAL_MACHINE_PROPS, vmGuestProps...) +} + +type SVirtualMachine struct { + multicloud.SInstanceBase + multicloud.STagBase + SManagedObject + + vnics []SVirtualNIC + vdisks []SVirtualDisk + vga SVirtualVGA + cdroms []SVirtualCdrom + devs map[int32]SVirtualDevice + ihost cloudprovider.ICloudHost + snapshots []SVirtualMachineSnapshot + + guestIps map[string]string + + osInfo *imagetools.ImageInfo +} + +type VMFetcher interface { + FetchNoTemplateVMs() ([]*SVirtualMachine, error) + FetchTemplateVMs() ([]*SVirtualMachine, error) + FetchFakeTempateVMs(string) ([]*SVirtualMachine, error) +} + +type byDiskType []SVirtualDisk + +func (d byDiskType) Len() int { return len(d) } +func (d byDiskType) Swap(i, j int) { d[i], d[j] = d[j], d[i] } +func (d byDiskType) Less(i, j int) bool { + if d[i].GetDiskType() == api.DISK_TYPE_SYS { + return true + } + return false +} + +func NewVirtualMachine(manager *SESXiClient, vm *mo.VirtualMachine, dc *SDatacenter) *SVirtualMachine { + svm := &SVirtualMachine{SManagedObject: newManagedObject(manager, vm, dc)} + err := svm.fetchHardwareInfo() + if err != nil { + log.Errorf("NewVirtualMachine: %v", err) + return nil + } + return svm +} + +func (self *SVirtualMachine) GetSecurityGroupIds() ([]string, error) { + return []string{}, cloudprovider.ErrNotSupported +} + +func (self *SVirtualMachine) GetSysTags() map[string]string { + meta := map[string]string{} + meta["datacenter"] = self.GetDatacenterPathString() + rp, _ := self.getResourcePool() + if rp != nil { + rpPath := rp.GetPath() + rpOffset := -1 + for i := range rpPath { + if rpPath[i] == "Resources" { + if i > 0 { + meta["cluster"] = rpPath[i-1] + rpOffset = i + } + } else if rpOffset >= 0 && i > rpOffset { + meta[fmt.Sprintf("pool%d", i-rpOffset-1)] = rpPath[i] + } + } + } + return meta +} + +func (self *SVirtualMachine) getVirtualMachine() *mo.VirtualMachine { + return self.object.(*mo.VirtualMachine) +} + +func (self *SVirtualMachine) GetGlobalId() string { + return self.getUuid() +} + +func (self *SVirtualMachine) GetHostname() string { + return self.GetName() +} + +func (self *SVirtualMachine) GetStatus() string { + // err := self.CheckFileInfo(context.Background()) + // if err != nil { + // return api.VM_UNKNOWN + // } + vm := object.NewVirtualMachine(self.manager.client.Client, self.getVirtualMachine().Self) + state, err := vm.PowerState(self.manager.context) + if err != nil { + return api.VM_UNKNOWN + } + switch state { + case types.VirtualMachinePowerStatePoweredOff: + return api.VM_READY + case types.VirtualMachinePowerStatePoweredOn: + return api.VM_RUNNING + case types.VirtualMachinePowerStateSuspended: + return api.VM_SUSPEND + default: + return api.VM_UNKNOWN + } +} + +func (self *SVirtualMachine) Refresh() error { + base := self.SManagedObject + var moObj mo.VirtualMachine + err := self.manager.reference2Object(self.object.Reference(), VIRTUAL_MACHINE_PROPS, &moObj) + if err != nil { + return err + } + base.object = &moObj + *self = SVirtualMachine{} + self.SManagedObject = base + self.fetchHardwareInfo() + return nil +} + +func (self *SVirtualMachine) IsEmulated() bool { + return false +} + +func (self *SVirtualMachine) GetInstanceType() string { + return "" +} + +func (self *SVirtualMachine) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SVirtualMachine) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (self *SVirtualMachine) DoRebuildRoot(ctx context.Context, imagePath string, uuid string) error { + if len(self.vdisks) == 0 { + return errors.ErrNotFound + } + return self.rebuildDisk(ctx, &self.vdisks[0], imagePath) +} + +func (self *SVirtualMachine) rebuildDisk(ctx context.Context, disk *SVirtualDisk, imagePath string) error { + uuid := disk.GetId() + sizeMb := disk.GetDiskSizeMB() + diskKey := disk.getKey() + ctlKey := disk.getControllerKey() + unitNumber := *disk.dev.GetVirtualDevice().UnitNumber + + err := self.doDetachAndDeleteDisk(ctx, disk) + if err != nil { + return err + } + return self.createDiskInternal(ctx, SDiskConfig{ + SizeMb: int64(sizeMb), + Uuid: uuid, + ControllerKey: ctlKey, + UnitNumber: unitNumber, + Key: diskKey, + ImagePath: imagePath, + IsRoot: len(imagePath) > 0, + }, false) +} + +func (self *SVirtualMachine) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotImplemented +} + +// TODO: detach disk to a separate directory, so as to keep disk independent of VM + +func (self *SVirtualMachine) DetachDisk(ctx context.Context, diskId string) error { + vdisk, err := self.GetIDiskById(diskId) + if err != nil { + return err + } + return self.doDetachDisk(ctx, vdisk.(*SVirtualDisk), false) +} + +func (self *SVirtualMachine) AttachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SVirtualMachine) getUuid() string { + return self.getVirtualMachine().Summary.Config.Uuid +} + +func (self *SVirtualMachine) GetIHost() cloudprovider.ICloudHost { + if self.ihost == nil { + self.ihost = self.getIHost() + } + return self.ihost +} + +func (self *SVirtualMachine) getIHost() cloudprovider.ICloudHost { + vm := self.getVmObj() + + hostsys, err := vm.HostSystem(self.manager.context) + if err != nil { + log.Errorf("fail to find host system for vm %s", err) + return nil + } + ihost, err := self.manager.FindHostByMoId(moRefId(hostsys.Reference())) + if err != nil { + log.Errorf("fail to find host %s for vm %s???", hostsys.Name(), self.GetName()) + return nil + } + return ihost +} + +func (self *SVirtualMachine) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + idisks := make([]cloudprovider.ICloudDisk, len(self.vdisks)) + for i := 0; i < len(self.vdisks); i += 1 { + idisks[i] = &(self.vdisks[i]) + } + return idisks, nil +} + +func (self *SVirtualMachine) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + for i := 0; i < len(self.vdisks); i += 1 { + if self.vdisks[i].MatchId(idStr) { + return &self.vdisks[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SVirtualMachine) GetINics() ([]cloudprovider.ICloudNic, error) { + inics := make([]cloudprovider.ICloudNic, len(self.vnics)) + for i := 0; i < len(self.vnics); i += 1 { + inics[i] = &(self.vnics[i]) + } + return inics, nil +} + +func (self *SVirtualMachine) GetIEIP() (cloudprovider.ICloudEIP, error) { + return nil, nil +} + +func (self *SVirtualMachine) GetVcpuCount() int { + return int(self.getVirtualMachine().Summary.Config.NumCpu) +} + +func (self *SVirtualMachine) GetVmemSizeMB() int { + return int(self.getVirtualMachine().Summary.Config.MemorySizeMB) +} + +func (self *SVirtualMachine) GetBootOrder() string { + return "cdn" +} + +func (self *SVirtualMachine) GetVga() string { + return "vga" +} + +func (self *SVirtualMachine) GetVdi() string { + return "vmrc" +} + +func (self *SVirtualMachine) GetGuestFamily() string { + moVM := self.getVirtualMachine() + return moVM.Config.AlternateGuestName +} + +func (self *SVirtualMachine) GetGuestId() string { + moVM := self.getVirtualMachine() + return moVM.Config.GuestId +} + +func (self *SVirtualMachine) GetGuestFullName() string { + moVM := self.getVirtualMachine() + return moVM.Config.GuestFullName +} + +func (self *SVirtualMachine) GetGuestState() string { + moVM := self.getVirtualMachine() + return moVM.Guest.GuestState +} + +func (self *SVirtualMachine) GetGuestToolsStatus() string { + moVM := self.getVirtualMachine() + return string(moVM.Guest.ToolsStatus) +} + +func (self *SVirtualMachine) isToolsOk() bool { + switch self.getVirtualMachine().Guest.ToolsStatus { + case types.VirtualMachineToolsStatusToolsNotInstalled: + return false + case types.VirtualMachineToolsStatusToolsNotRunning: + return false + } + return true +} + +func (self *SVirtualMachine) GetGuestToolsRunningStatus() string { + moVM := self.getVirtualMachine() + return string(moVM.Guest.ToolsRunningStatus) +} + +func (vm *SVirtualMachine) getNormalizedOsInfo() *imagetools.ImageInfo { + if vm.osInfo == nil { + if osInfo, ok := GuestOsInfo[vm.GetGuestId()]; ok { + osInfo := imagetools.NormalizeImageInfo("", string(osInfo.OsArch), string(osInfo.OsType), osInfo.OsDistribution, osInfo.OsVersion) + vm.osInfo = &osInfo + } else { + osInfo := imagetools.NormalizeImageInfo("", "", "", "", "") + vm.osInfo = &osInfo + } + } + return vm.osInfo +} + +func (vm *SVirtualMachine) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(vm.getNormalizedOsInfo().OsType) +} + +func (vm *SVirtualMachine) GetFullOsName() string { + return vm.getNormalizedOsInfo().GetFullOsName() +} + +func (vm *SVirtualMachine) GetOsDist() string { + return vm.getNormalizedOsInfo().OsDistro +} + +func (vm *SVirtualMachine) GetOsVersion() string { + return vm.getNormalizedOsInfo().OsVersion +} + +func (vm *SVirtualMachine) GetOsLang() string { + return vm.getNormalizedOsInfo().OsLang +} + +func (vm *SVirtualMachine) GetOsArch() string { + return vm.getNormalizedOsInfo().OsArch +} + +func (vm *SVirtualMachine) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(vm.getBios()) +} + +func (vm *SVirtualMachine) getBios() string { + // self.obj.config.firmware + switch vm.getVirtualMachine().Config.Firmware { + case "efi": + return "UEFI" + case "bios": + return "BIOS" + default: + return "BIOS" + } +} + +func (self *SVirtualMachine) GetMachine() string { + return "pc" +} + +func (self *SVirtualMachine) GetHypervisor() string { + return api.HYPERVISOR_ESXI +} + +func (self *SVirtualMachine) getVmObj() *object.VirtualMachine { + return object.NewVirtualMachine(self.manager.client.Client, self.getVirtualMachine().Self) +} + +// ideopotent start +func (self *SVirtualMachine) StartVM(ctx context.Context) error { + if self.GetStatus() == api.VM_RUNNING { + return nil + } + return self.startVM(ctx) +} + +func (self *SVirtualMachine) startVM(ctx context.Context) error { + ihost := self.GetIHost() + if ihost == nil { + return errors.Wrap(httperrors.ErrInvalidStatus, "no valid host") + } + + lockman.LockRawObject(ctx, "host", ihost.GetGlobalId()) + defer lockman.ReleaseRawObject(ctx, "host", ihost.GetGlobalId()) + + err := self.makeNicsStartConnected(ctx) + if err != nil { + log.Errorf("self.makeNicsStartConnected %s", err) + return err + } + + vm := self.getVmObj() + + task, err := vm.PowerOn(ctx) + if err != nil { + log.Errorf("vm.PowerOn %s", err) + return err + } + err = task.Wait(ctx) + if err != nil { + log.Errorf("task.Wait %s", err) + return err + } + return nil +} + +func (self *SVirtualMachine) makeNicsStartConnected(ctx context.Context) error { + spec := types.VirtualMachineConfigSpec{} + spec.DeviceChange = make([]types.BaseVirtualDeviceConfigSpec, len(self.vnics)) + for i := 0; i < len(self.vnics); i += 1 { + spec.DeviceChange[i] = makeNicStartConnected(&self.vnics[i]) + } + + vm := self.getVmObj() + + task, err := vm.Reconfigure(ctx, spec) + if err != nil { + return err + } + return task.Wait(ctx) +} + +func makeNicStartConnected(nic *SVirtualNIC) *types.VirtualDeviceConfigSpec { + editSpec := types.VirtualDeviceConfigSpec{} + editSpec.Operation = types.VirtualDeviceConfigSpecOperationEdit + editSpec.FileOperation = "" + editSpec.Device = nic.dev + editSpec.Device.GetVirtualDevice().Connectable.StartConnected = true + return &editSpec +} + +func (self *SVirtualMachine) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + if self.GetStatus() == api.VM_READY { + return nil + } + if !opts.IsForce && self.isToolsOk() { + return self.shutdownVM(ctx) + } else { + return self.poweroffVM(ctx) + } +} + +func (self *SVirtualMachine) SuspendVM(ctx context.Context) error { + vm := self.getVmObj() + task, err := vm.Suspend(ctx) + if err != nil { + return err + } + return task.Wait(ctx) +} + +func (self *SVirtualMachine) ResumeVM(ctx context.Context) error { + if self.GetStatus() == api.VM_RUNNING { + return nil + } + vm := self.getVmObj() + + task, err := vm.PowerOn(ctx) + if err != nil { + return errors.Wrap(err, "VM.PowerOn") + } + err = task.Wait(ctx) + if err != nil { + return errors.Wrap(err, "Task.Wait after VM.PowerOn") + } + return nil +} + +func (self *SVirtualMachine) poweroffVM(ctx context.Context) error { + vm := self.getVmObj() + + task, err := vm.PowerOff(ctx) + if err != nil { + return err + } + return task.Wait(ctx) +} + +func (self *SVirtualMachine) shutdownVM(ctx context.Context) error { + vm := self.getVmObj() + + err := vm.ShutdownGuest(ctx) + if err != nil { + return err + } + return err +} + +func (self *SVirtualMachine) doDestroy(ctx context.Context) error { + vm := self.getVmObj() + task, err := vm.Destroy(ctx) + if err != nil { + return errors.Wrap(err, "unable to destroy vm") + } + return task.Wait(ctx) +} + +func (self *SVirtualMachine) doDelete(ctx context.Context) error { + // detach all disks first + for i := range self.vdisks { + err := self.doDetachAndDeleteDisk(ctx, &self.vdisks[i]) + if err != nil { + return errors.Wrap(err, "doDetachAndDeteteDisk") + } + } + + return self.doDestroy(ctx) +} + +func (self *SVirtualMachine) doUnregister(ctx context.Context) error { + vm := self.getVmObj() + + err := vm.Unregister(ctx) + if err != nil { + log.Errorf("vm.Unregister(ctx) fail %s", err) + return err + } + return nil +} + +func (self *SVirtualMachine) DeleteVM(ctx context.Context) error { + err := self.CheckFileInfo(ctx) + if err != nil { + return self.doUnregister(ctx) + } + return self.doDestroy(ctx) +} + +func (self *SVirtualMachine) doDetachAndDeleteDisk(ctx context.Context, vdisk *SVirtualDisk) error { + return self.doDetachDisk(ctx, vdisk, true) +} + +func (self *SVirtualMachine) doDetachDisk(ctx context.Context, vdisk *SVirtualDisk, remove bool) error { + removeSpec := types.VirtualDeviceConfigSpec{} + removeSpec.Operation = types.VirtualDeviceConfigSpecOperationRemove + removeSpec.Device = vdisk.dev + + spec := types.VirtualMachineConfigSpec{} + spec.DeviceChange = []types.BaseVirtualDeviceConfigSpec{&removeSpec} + + vm := self.getVmObj() + + task, err := vm.Reconfigure(ctx, spec) + if err != nil { + log.Errorf("vm.Reconfigure fail %s", err) + return err + } + + err = task.Wait(ctx) + if err != nil { + log.Errorf("task.Wait(ctx) fail %s", err) + return err + } + + if !remove { + return nil + } + return vdisk.Delete(ctx) +} + +func (self *SVirtualMachine) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + hostVer := self.GetIHost().GetVersion() + if version.GE(hostVer, "6.5") { + info, err := self.acquireWebmksTicket("webmks") + if err == nil { + return info, nil + } + } + return self.acquireVmrcUrl() +} + +func (self *SVirtualMachine) GetVmrcInfo() (*cloudprovider.ServerVncOutput, error) { + return self.acquireVmrcUrl() +} + +func (self *SVirtualMachine) GetWebmksInfo() (*cloudprovider.ServerVncOutput, error) { + return self.acquireWebmksTicket("webmks") +} + +func (self *SVirtualMachine) acquireWebmksTicket(ticketType string) (*cloudprovider.ServerVncOutput, error) { + vm := object.NewVirtualMachine(self.manager.client.Client, self.getVirtualMachine().Self) + ticket, err := vm.AcquireTicket(self.manager.context, ticketType) + if err != nil { + return nil, err + } + + host := ticket.Host + if len(host) == 0 { + host = self.manager.host + } + port := ticket.Port + if port == 0 { + port = int32(self.manager.port) + } + if port == 0 { + port = 443 + } + ret := &cloudprovider.ServerVncOutput{ + Url: fmt.Sprintf("wss://%s:%d/ticket/%s", host, port, ticket.Ticket), + Protocol: "wmks", + Hypervisor: api.HYPERVISOR_ESXI, + } + return ret, nil +} + +func (self *SVirtualMachine) acquireVmrcUrl() (*cloudprovider.ServerVncOutput, error) { + ticket, err := self.manager.acquireCloneTicket() + if err != nil { + return nil, err + } + port := self.manager.port + if port == 0 { + port = 443 + } + ret := &cloudprovider.ServerVncOutput{ + Url: fmt.Sprintf("vmrc://clone:%s@%s:%d/?moid=%s", ticket, self.manager.host, port, self.GetId()), + Protocol: "vmrc", + } + return ret, nil +} + +func (self *SVirtualMachine) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + return self.doChangeConfig(ctx, int32(config.Cpu), int64(config.MemoryMB), "", "") +} + +func (self *SVirtualMachine) GetVersion() string { + return self.getVirtualMachine().Config.Version +} + +func (self *SVirtualMachine) doChangeConfig(ctx context.Context, ncpu int32, vmemMB int64, guestId string, version string) error { + changed := false + configSpec := types.VirtualMachineConfigSpec{} + if int(ncpu) != self.GetVcpuCount() { + configSpec.NumCPUs = ncpu + changed = true + } + if int(vmemMB) != self.GetVmemSizeMB() { + configSpec.MemoryMB = vmemMB + changed = true + } + if len(guestId) > 0 && guestId != self.GetGuestId() { + configSpec.GuestId = guestId + changed = true + } + if len(version) > 0 && version != self.GetVersion() { + configSpec.Version = version + changed = true + } + if !changed { + return nil + } + + vm := self.getVmObj() + + task, err := vm.Reconfigure(ctx, configSpec) + if err != nil { + return err + } + err = task.Wait(ctx) + if err != nil { + return err + } + return self.Refresh() +} + +func (self *SVirtualMachine) AssignSecurityGroup(secgroupId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SVirtualMachine) SetSecurityGroups(secgroupIds []string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SVirtualMachine) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SVirtualMachine) GetCreatedAt() time.Time { + moVM := self.getVirtualMachine() + ctm := moVM.Config.CreateDate + if ctm != nil { + return *ctm + } else { + return time.Time{} + } +} + +func (self *SVirtualMachine) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SVirtualMachine) UpdateUserData(userData string) error { + return nil +} + +func (self *SVirtualMachine) fetchHardwareInfo() error { + self.vnics = make([]SVirtualNIC, 0) + self.vdisks = make([]SVirtualDisk, 0) + self.cdroms = make([]SVirtualCdrom, 0) + self.devs = make(map[int32]SVirtualDevice) + + moVM := self.getVirtualMachine() + + // MAX_TRIES := 3 + // for tried := 0; tried < MAX_TRIES && (moVM == nil || moVM.Config == nil || moVM.Config.Hardware.Device == nil); tried += 1 { + // time.Sleep(time.Second) + // } + + if moVM == nil || moVM.Config == nil || moVM.Config.Hardware.Device == nil { + return fmt.Errorf("invalid vm") + } + + // sort devices via their Key + devices := moVM.Config.Hardware.Device + sort.Slice(devices, func(i, j int) bool { + return devices[i].GetVirtualDevice().Key < devices[j].GetVirtualDevice().Key + }) + for i := 0; i < len(devices); i += 1 { + dev := devices[i] + devType := reflect.Indirect(reflect.ValueOf(dev)).Type() + + etherType := reflect.TypeOf((*types.VirtualEthernetCard)(nil)).Elem() + diskType := reflect.TypeOf((*types.VirtualDisk)(nil)).Elem() + vgaType := reflect.TypeOf((*types.VirtualMachineVideoCard)(nil)).Elem() + cdromType := reflect.TypeOf((*types.VirtualCdrom)(nil)).Elem() + + if reflectutils.StructContains(devType, etherType) { + self.vnics = append(self.vnics, NewVirtualNIC(self, dev, len(self.vnics))) + } else if reflectutils.StructContains(devType, diskType) { + self.vdisks = append(self.vdisks, NewVirtualDisk(self, dev, len(self.vdisks))) + } else if reflectutils.StructContains(devType, vgaType) { + self.vga = NewVirtualVGA(self, dev, 0) + } else if reflectutils.StructContains(devType, cdromType) { + self.cdroms = append(self.cdroms, NewVirtualCdrom(self, dev, len(self.cdroms))) + } + vdev := NewVirtualDevice(self, dev, 0) + self.devs[vdev.getKey()] = vdev + } + self.rigorous() + sort.Sort(byDiskType(self.vdisks)) + return nil +} + +func (self *SVirtualMachine) rigorous() { + hasRoot := false + for i := range self.vdisks { + if self.vdisks[i].IsRoot { + hasRoot = true + break + } + } + if !hasRoot && len(self.vdisks) > 0 { + self.vdisks[0].IsRoot = true + } +} + +func (self *SVirtualMachine) getVdev(key int32) SVirtualDevice { + return self.devs[key] +} + +func (self *SVirtualMachine) fetchGuestIps() map[string]string { + guestIps := make(map[string]string) + moVM := self.getVirtualMachine() + for _, net := range moVM.Guest.Net { + mac := netutils.FormatMacAddr(net.MacAddress) + for _, ip := range net.IpAddress { + if regutils.MatchIP4Addr(ip) { + if !vmIPV4Filter.Contains(ip) { + continue + } + guestIps[mac] = ip + break + } + } + } + return guestIps +} + +func (self *SVirtualMachine) getGuestIps() map[string]string { + if self.guestIps == nil { + self.guestIps = self.fetchGuestIps() + } + return self.guestIps +} + +func (self *SVirtualMachine) GetIps() []string { + ips := make([]string, 0) + for _, ip := range self.getGuestIps() { + ips = append(ips, ip) + } + return ips +} + +func (self *SVirtualMachine) GetVGADevice() string { + return fmt.Sprintf("%s", self.vga.String()) +} + +var ( + driverTable = map[string][]string{ + "sata": {"ahci"}, + "scsi": {"parascsi", "lsilogic", "lsilogicsas", "buslogic"}, + "pvscsi": {"parascsi"}, + "ide": {"ide"}, + } +) + +func (self *SVirtualMachine) getDevsByDriver(driver string) []SVirtualDevice { + devs := make([]SVirtualDevice, 0) + for _, drv := range self.devs { + if strings.HasSuffix(drv.GetDriver(), fmt.Sprintf("%scontroller", driver)) { + devs = append(devs, drv) + } + } + return devs +} + +func minDevKey(devs []SVirtualDevice) int32 { + var minKey int32 = -1 + for i := 0; i < len(devs); i += 1 { + if minKey < 0 || minKey > devs[i].getKey() { + minKey = devs[i].getKey() + } + } + return minKey +} + +func minDiskKey(devs []SVirtualDisk) int32 { + var minKey int32 = -1 + for i := 0; i < len(devs); i += 1 { + if minKey < 0 || minKey > devs[i].getKey() { + minKey = devs[i].getKey() + } + } + return minKey +} + +func (self *SVirtualMachine) FindController(ctx context.Context, driver string) ([]SVirtualDevice, error) { + aliasDrivers, ok := driverTable[driver] + if !ok { + return nil, fmt.Errorf("Unsupported disk driver %s", driver) + } + var devs []SVirtualDevice + for _, alias := range aliasDrivers { + devs = self.getDevsByDriver(alias) + if len(devs) > 0 { + break + } + } + return devs, nil +} + +func (self *SVirtualMachine) FindDiskByDriver(drivers ...string) []SVirtualDisk { + disks := make([]SVirtualDisk, 0) + for i := range self.vdisks { + if utils.IsInStringArray(self.vdisks[i].GetDriver(), drivers) { + disks = append(disks, self.vdisks[i]) + } + } + return disks +} + +func (self *SVirtualMachine) devNumWithCtrlKey(ctrlKey int32) int { + n := 0 + for _, dev := range self.devs { + if dev.getControllerKey() == ctrlKey { + n++ + } + } + return n +} + +func (self *SVirtualMachine) getLayoutEx() *types.VirtualMachineFileLayoutEx { + vm := self.getVirtualMachine() + if vm.LayoutEx != nil { + return vm.LayoutEx + } + var nvm mo.VirtualMachine + err := self.manager.reference2Object(vm.Self, vmLayoutExProps, &nvm) + if err != nil { + log.Errorf("unable to fetch LayoutEx.File from vc: %v", err) + } + vm.LayoutEx = nvm.LayoutEx + return vm.LayoutEx +} + +func (self *SVirtualMachine) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) { + if opts.Driver == "pvscsi" { + opts.Driver = "scsi" + } + var ds *SDatastore + var err error + if opts.StorageId != "" { + ihost := self.getIHost() + if ihost == nil { + return "", fmt.Errorf("unable to get host of virtualmachine %s", self.GetName()) + } + ds, err = ihost.(*SHost).FindDataStoreById(opts.StorageId) + if err != nil { + return "", errors.Wrapf(err, "unable to find datastore %s", opts.StorageId) + } + } + devs, err := self.FindController(ctx, opts.Driver) + if err != nil { + return "", err + } + if len(devs) == 0 { + return "", self.createDriverAndDisk(ctx, ds, opts.SizeMb, opts.UUID, opts.Driver) + } + numDevBelowCtrl := make([]int, len(devs)) + for i := range numDevBelowCtrl { + numDevBelowCtrl[i] = self.devNumWithCtrlKey(devs[i].getKey()) + } + + // find the min one + ctrlKey := devs[0].getKey() + unitNumber := numDevBelowCtrl[0] + for i := 1; i < len(numDevBelowCtrl); i++ { + if numDevBelowCtrl[i] >= unitNumber { + continue + } + ctrlKey = devs[i].getKey() + unitNumber = numDevBelowCtrl[i] + } + diskKey := self.FindMinDiffKey(2000) + + // By default, the virtual SCSI controller is assigned to virtual device node (z:7), + // so that device node is unavailable for hard disks or other devices. + if unitNumber >= 7 && opts.Driver == "scsi" { + unitNumber++ + } + + return "", self.createDiskInternal(ctx, SDiskConfig{ + SizeMb: int64(opts.SizeMb), + Uuid: opts.UUID, + UnitNumber: int32(unitNumber), + ControllerKey: ctrlKey, + Key: diskKey, + Datastore: ds, + }, true) +} + +// createDriverAndDisk will create a driver and disk associated with the driver +func (self *SVirtualMachine) createDriverAndDisk(ctx context.Context, ds *SDatastore, sizeMb int, uuid string, driver string) error { + if driver != "scsi" && driver != "pvscsi" { + return fmt.Errorf("Driver %s is not supported", driver) + } + + deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 2) + + // find a suitable key for scsi or pvscsi driver + scsiKey := self.FindMinDiffKey(1000) + deviceChange = append(deviceChange, addDevSpec(NewSCSIDev(scsiKey, 100, driver))) + + // find a suitable key for disk + diskKey := self.FindMinDiffKey(2000) + + if diskKey == scsiKey { + // unarrivelable + log.Errorf("there is no suitable key between 1000 and 2000???!") + } + + return self.createDiskWithDeviceChange(ctx, deviceChange, + SDiskConfig{ + SizeMb: int64(sizeMb), + Uuid: uuid, + ControllerKey: scsiKey, + UnitNumber: 0, + Key: scsiKey, + ImagePath: "", + IsRoot: false, + Datastore: ds, + }, true) +} + +func (self *SVirtualMachine) copyRootDisk(ctx context.Context, imagePath string) (string, error) { + layoutEx := self.getLayoutEx() + if layoutEx == nil || len(layoutEx.File) == 0 { + return "", fmt.Errorf("invalid LayoutEx") + } + file := layoutEx.File[0].Name + // find stroage + host := self.GetIHost() + storages, err := host.GetIStorages() + if err != nil { + return "", errors.Wrap(err, "host.GetIStorages") + } + var datastore *SDatastore + for i := range storages { + ds := storages[i].(*SDatastore) + if ds.HasFile(file) { + datastore = ds + break + } + } + if datastore == nil { + return "", fmt.Errorf("can't find storage associated with vm %q", self.GetName()) + } + path := datastore.cleanPath(file) + vmDir := strings.Split(path, "/")[0] + // TODO find a non-conflicting path + newImagePath := datastore.getPathString(fmt.Sprintf("%s/%s.vmdk", vmDir, vmDir)) + + fm := datastore.getDatastoreObj().NewFileManager(datastore.datacenter.getObjectDatacenter(), true) + err = fm.Copy(ctx, imagePath, newImagePath) + if err != nil { + return "", errors.Wrap(err, "unable to copy system disk") + } + return newImagePath, nil +} + +func (self *SVirtualMachine) createDiskWithDeviceChange(ctx context.Context, deviceChange []types.BaseVirtualDeviceConfigSpec, config SDiskConfig, check bool) error { + var err error + // copy disk + if len(config.ImagePath) > 0 { + config.IsRoot = true + config.ImagePath, err = self.copyRootDisk(ctx, config.ImagePath) + if err != nil { + return errors.Wrap(err, "unable to copyRootDisk") + } + } + + devSpec := NewDiskDev(int64(config.SizeMb), config) + spec := addDevSpec(devSpec) + if len(config.ImagePath) == 0 { + spec.FileOperation = types.VirtualDeviceConfigSpecFileOperationCreate + } + configSpec := types.VirtualMachineConfigSpec{} + configSpec.DeviceChange = append(deviceChange, spec) + + vmObj := self.getVmObj() + + task, err := vmObj.Reconfigure(ctx, configSpec) + if err != nil { + return err + } + err = task.Wait(ctx) + if err != nil { + return err + } + if !check { + return nil + } + oldDiskCnt := len(self.vdisks) + maxTries := 60 + for tried := 0; tried < maxTries; tried += 1 { + time.Sleep(time.Second) + self.Refresh() + if len(self.vdisks) > oldDiskCnt { + return nil + } + } + return cloudprovider.ErrTimeout +} + +func (self *SVirtualMachine) createDiskInternal(ctx context.Context, config SDiskConfig, check bool) error { + + return self.createDiskWithDeviceChange(ctx, nil, config, check) +} + +func (self *SVirtualMachine) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (self *SVirtualMachine) GetProjectId() string { + pool, err := self.getResourcePool() + if err != nil { + return "" + } + if pool != nil { + return pool.GetId() + } + return "" +} + +func (self *SVirtualMachine) GetError() error { + return nil +} + +func (self *SVirtualMachine) getResourcePool() (*SResourcePool, error) { + vm := self.getVirtualMachine() + morp := mo.ResourcePool{} + if vm.ResourcePool == nil { + return nil, errors.Error("nil resource pool") + } + err := self.manager.reference2Object(*vm.ResourcePool, RESOURCEPOOL_PROPS, &morp) + if err != nil { + return nil, errors.Wrap(err, "self.manager.reference2Object") + } + rp := NewResourcePool(self.manager, &morp, self.datacenter) + return rp, nil +} + +func (self *SVirtualMachine) CheckFileInfo(ctx context.Context) error { + layoutEx := self.getLayoutEx() + if layoutEx != nil && len(layoutEx.File) > 0 { + file := layoutEx.File[0] + host := self.GetIHost() + storages, err := host.GetIStorages() + if err != nil { + return errors.Wrap(err, "host.GetIStorages") + } + for i := range storages { + ds := storages[i].(*SDatastore) + if ds.HasFile(file.Name) { + _, err := ds.CheckFile(ctx, file.Name) + if err != nil { + return errors.Wrap(err, "ds.CheckFile") + } + break + } + } + } + return nil +} + +func (self *SVirtualMachine) DoRename(ctx context.Context, name string) error { + task, err := self.getVmObj().Rename(ctx, name) + if err != nil { + return errors.Wrap(err, "object.VirtualMachine.Rename") + } + return task.Wait(ctx) +} + +func (self *SVirtualMachine) GetMoid() string { + return self.getVirtualMachine().Self.Value +} + +func (self *SVirtualMachine) GetToolsVersion() string { + return self.getVirtualMachine().Guest.ToolsVersion +} + +func (self *SVirtualMachine) DoCustomize(ctx context.Context, params jsonutils.JSONObject) error { + spec := new(types.CustomizationSpec) + + ipSettings := new(types.CustomizationGlobalIPSettings) + domain := "local" + if params.Contains("domain") { + domain, _ = params.GetString("domain") + } + ipSettings.DnsSuffixList = []string{domain} + + // deal nics + nics, _ := params.GetArray("nics") + serverNics := make([]cloudtypes.SServerNic, len(nics)) + for i := range nics { + var nicType cloudtypes.SServerNic + nics[i].Unmarshal(&nicType) + serverNics[i] = nicType + } + + // find dnsServerList + for i := range serverNics { + dnsList := netutils2.GetNicDns(&serverNics[i]) + if len(dnsList) != 0 { + ipSettings.DnsServerList = dnsList + } + } + spec.GlobalIPSettings = *ipSettings + + maps := make([]types.CustomizationAdapterMapping, 0, len(nics)) + for _, nic := range serverNics { + conf := types.CustomizationAdapterMapping{} + conf.MacAddress = nic.Mac + if len(conf.MacAddress) == 0 { + conf.MacAddress = "9e:46:27:21:a2:b2" + } + + conf.Adapter = types.CustomizationIPSettings{} + fixedIp := new(types.CustomizationFixedIp) + fixedIp.IpAddress = nic.Ip + if len(fixedIp.IpAddress) == 0 { + fixedIp.IpAddress = "10.168.26.23" + } + conf.Adapter.Ip = fixedIp + maskLen := nic.Masklen + if maskLen == 0 { + maskLen = 24 + } + mask := netutils2.Netlen2Mask(maskLen) + conf.Adapter.SubnetMask = mask + + if len(nic.Gateway) != 0 { + conf.Adapter.Gateway = []string{nic.Gateway} + } + dnsList := netutils2.GetNicDns(&nic) + if len(dnsList) != 0 { + conf.Adapter.DnsServerList = dnsList + dns := nic.Domain + if len(dns) == 0 { + dns = "local" + } + conf.Adapter.DnsDomain = dns + } + maps = append(maps, conf) + } + spec.NicSettingMap = maps + + var ( + osName string + name = "yunionhost" + ) + if params.Contains("os_name") { + osName, _ = params.GetString("os_name") + } + if params.Contains("name") { + name, _ = params.GetString("name") + } + if osName == "Linux" { + linuxPrep := types.CustomizationLinuxPrep{ + HostName: &types.CustomizationFixedName{Name: name}, + Domain: domain, + TimeZone: "Asia/Shanghai", + } + spec.Identity = &linuxPrep + } else if osName == "Windows" { + sysPrep := types.CustomizationSysprep{ + GuiUnattended: types.CustomizationGuiUnattended{ + TimeZone: 210, + AutoLogon: false, + }, + UserData: types.CustomizationUserData{ + FullName: "Administrator", + OrgName: "Yunion", + ProductId: "", + ComputerName: &types.CustomizationFixedName{ + Name: name, + }, + }, + Identification: types.CustomizationIdentification{}, + } + spec.Identity = &sysPrep + } + log.Infof("customize spec: %#v", spec) + task, err := self.getVmObj().Customize(ctx, *spec) + if err != nil { + return errors.Wrap(err, "object.VirtualMachine.Customize") + } + return task.Wait(ctx) +} + +func (self *SVirtualMachine) ExportTemplate(ctx context.Context, idx int, diskPath string) error { + lease, err := self.getVmObj().Export(ctx) + if err != nil { + return errors.Wrap(err, "esxi.SVirtualMachine.DoExportTemplate") + } + info, err := lease.Wait(ctx, nil) + if err != nil { + return errors.Wrap(err, "lease.Wait") + } + + u := lease.StartUpdater(ctx, info) + defer u.Done() + + if idx >= len(info.Items) { + return errors.Error(fmt.Sprintf("No such Device whose index is %d", idx)) + } + + lr := newLeaseLogger("download vmdk", 5) + lr.Log() + defer lr.End() + + // filter vmdk item + vmdkItems := make([]nfc.FileItem, 0, len(info.Items)/2) + for i := range info.Items { + if strings.HasSuffix(info.Items[i].Path, ".vmdk") { + vmdkItems = append(vmdkItems, info.Items[i]) + } else { + log.Infof("item.Path does not end in '.vmdk': %#v", info.Items[i]) + } + } + + log.Debugf("download to %s start...", diskPath) + err = lease.DownloadFile(ctx, diskPath, vmdkItems[idx], soap.Download{Progress: lr}) + if err != nil { + return errors.Wrap(err, "lease.DownloadFile") + } + + err = lease.Complete(ctx) + if err != nil { + return errors.Wrap(err, "lease.Complete") + } + log.Debugf("download to %s finish", diskPath) + return nil +} + +func (self *SVirtualMachine) GetSerialOutput(port int) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (self *SVirtualMachine) ConvertPublicIpToEip() error { + return cloudprovider.ErrNotSupported +} + +func (self *SVirtualMachine) IsAutoRenew() bool { + return false +} + +func (self *SVirtualMachine) SetAutoRenew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (self *SVirtualMachine) FindMinDiffKey(limit int32) int32 { + if self.devs == nil { + self.fetchHardwareInfo() + } + devKeys := make([]int32, 0, len(self.devs)) + for key := range self.devs { + devKeys = append(devKeys, key) + } + sort.Slice(devKeys, func(i int, j int) bool { + return devKeys[i] < devKeys[j] + }) + for _, key := range devKeys { + switch { + case key < limit: + case key == limit: + limit += 1 + case key > limit: + return limit + } + } + return limit +} + +func (self *SVirtualMachine) relocate(hostId string) error { + var targetHs *mo.HostSystem + if hostId == "" { + return errors.Wrap(fmt.Errorf("require hostId"), "relocate") + } + ihost, err := self.manager.GetIHostById(hostId) + if err != nil { + return errors.Wrap(err, "self.manager.GetIHostById(hostId)") + } + targetHs = ihost.(*SHost).object.(*mo.HostSystem) + if len(targetHs.Datastore) < 1 { + return errors.Wrap(fmt.Errorf("target host has no datastore"), "relocate") + } + ctx := self.manager.context + config := types.VirtualMachineRelocateSpec{} + hrs := targetHs.Reference() + config.Host = &hrs + config.Datastore = &targetHs.Datastore[0] + task, err := self.getVmObj().Relocate(ctx, config, types.VirtualMachineMovePriorityDefaultPriority) + if err != nil { + log.Errorf("vm.Migrate %s", err) + return errors.Wrap(err, "SVirtualMachine Migrate") + } + err = task.Wait(ctx) + if err != nil { + log.Errorf("task.Wait %s", err) + return errors.Wrap(err, "task.wait") + } + return nil +} + +func (self *SVirtualMachine) MigrateVM(hostId string) error { + return self.relocate(hostId) +} + +func (self *SVirtualMachine) LiveMigrateVM(hostId string) error { + return self.relocate(hostId) +} + +func (self *SVirtualMachine) GetIHostId() string { + ctx := self.manager.context + hs, err := self.getVmObj().HostSystem(ctx) + if err != nil { + log.Errorf("get HostSystem %s", err) + return "" + } + var moHost mo.HostSystem + err = self.manager.reference2Object(hs.Reference(), HOST_SYSTEM_PROPS, &moHost) + if err != nil { + log.Errorf("hostsystem reference2Object %s", err) + return "" + } + shost := NewHost(self.manager, &moHost, nil) + return shost.GetGlobalId() +} + +func (self *SVirtualMachine) IsTemplate() bool { + movm := self.getVirtualMachine() + if tempalteNameRegex != nil && tempalteNameRegex.MatchString(self.GetName()) && movm.Summary.Runtime.PowerState == types.VirtualMachinePowerStatePoweredOff { + return true + } + return movm.Config != nil && movm.Config.Template +} + +func (self *SVirtualMachine) fetchSnapshots() { + movm := self.getVirtualMachine() + if movm.Snapshot == nil { + return + } + self.snapshots = self.extractSnapshots(movm.Snapshot.RootSnapshotList, make([]SVirtualMachineSnapshot, 0, len(movm.Snapshot.RootSnapshotList))) +} + +func (self *SVirtualMachine) extractSnapshots(tree []types.VirtualMachineSnapshotTree, snapshots []SVirtualMachineSnapshot) []SVirtualMachineSnapshot { + for i := range tree { + snapshots = append(snapshots, SVirtualMachineSnapshot{ + snapshotTree: tree[i], + vm: self, + }) + snapshots = self.extractSnapshots(tree[i].ChildSnapshotList, snapshots) + } + return snapshots +} + +func (self *SVirtualMachine) GetInstanceSnapshots() ([]cloudprovider.ICloudInstanceSnapshot, error) { + if self.snapshots == nil { + self.fetchSnapshots() + } + ret := make([]cloudprovider.ICloudInstanceSnapshot, 0, len(self.snapshots)) + for i := range self.snapshots { + ret = append(ret, &self.snapshots[i]) + } + return ret, nil +} + +func (self *SVirtualMachine) GetInstanceSnapshot(idStr string) (cloudprovider.ICloudInstanceSnapshot, error) { + if self.snapshots == nil { + self.fetchSnapshots() + } + for i := range self.snapshots { + if self.snapshots[i].GetGlobalId() == idStr { + // copyone + sp := self.snapshots[i] + return &sp, nil + } + } + return nil, errors.ErrNotFound +} + +func (self *SVirtualMachine) CreateInstanceSnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudInstanceSnapshot, error) { + ovm := self.getVmObj() + task, err := ovm.CreateSnapshot(ctx, name, desc, false, false) + if err != nil { + return nil, errors.Wrap(err, "CreateSnapshot") + } + info, err := task.WaitForResult(ctx, nil) + if err != nil { + return nil, errors.Wrap(err, "task.Wait") + } + sp := info.Result.(types.ManagedObjectReference) + err = self.Refresh() + if err != nil { + return nil, errors.Wrap(err, "create successfully") + } + self.fetchSnapshots() + for i := range self.snapshots { + if self.snapshots[i].snapshotTree.Snapshot == sp { + // copyone + sp := self.snapshots[i] + return &sp, nil + } + } + return nil, errors.Wrap(errors.ErrNotFound, "create successfully") +} + +func (self *SVirtualMachine) ResetToInstanceSnapshot(ctx context.Context, idStr string) error { + cloudIsp, err := self.GetInstanceSnapshot(idStr) + if err != nil { + return errors.Wrap(err, "GetInstanceSnapshot") + } + isp := cloudIsp.(*SVirtualMachineSnapshot) + req := types.RevertToSnapshot_Task{ + This: isp.snapshotTree.Snapshot.Reference(), + } + res, err := methods.RevertToSnapshot_Task(ctx, self.manager.client.Client, &req) + if err != nil { + return errors.Wrap(err, "RevertToSnapshot_Task") + } + return object.NewTask(self.manager.client.Client, res.Returnval).Wait(ctx) +} diff --git a/pkg/multicloud/esxi/vnic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vnic.go similarity index 97% rename from pkg/multicloud/esxi/vnic.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vnic.go index 7aca0f9bb7..7c5b1c4e11 100644 --- a/pkg/multicloud/esxi/vnic.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vnic.go @@ -20,7 +20,7 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/util/netutils" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SVirtualNIC struct { diff --git a/pkg/multicloud/esxi/vswitch.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vswitch.go similarity index 100% rename from pkg/multicloud/esxi/vswitch.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/esxi/vswitch.go diff --git a/pkg/multicloud/google/bigquery.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/bigquery.go similarity index 100% rename from pkg/multicloud/google/bigquery.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/bigquery.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/bucket.go new file mode 100644 index 0000000000..0a9d76798f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/bucket.go @@ -0,0 +1,528 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "context" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "strings" + "time" + + "cloud.google.com/go/storage" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLifecycleRuleAction struct { + Type string +} + +type SLifecycleRuleCondition struct { + Age int +} + +type SLifecycleRule struct { + Action SLifecycleRuleAction + Condition SLifecycleRuleCondition +} + +type SBucketPolicyOnly struct { + Enabled bool +} + +type SUniformBucketLevelAccess struct { + Enabled bool +} + +type SIamConfiguration struct { + BucketPolicyOnly SBucketPolicyOnly + UniformBucketLevelAccess SUniformBucketLevelAccess +} + +type SLifecycle struct { + Rule []SLifecycleRule +} + +type SBucket struct { + multicloud.SBaseBucket + GoogleTags + + region *SRegion + + Kind string + SelfLink string + Name string + ProjectNumber string + Metageneration string + Location string + StorageClass string + Etag string + TimeCreated time.Time + Updated time.Time + Lifecycle SLifecycle + IamConfiguration SIamConfiguration + LocationType string +} + +func (b *SBucket) GetProjectId() string { + return b.region.GetProjectId() +} + +func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { + iam, err := b.region.GetBucketIam(b.Name) + if err != nil { + return cloudprovider.ACLUnknown + } + acl := cloudprovider.ACLPrivate + allUsers := []SBucketBinding{} + allAuthUsers := []SBucketBinding{} + for _, binding := range iam.Bindings { + if utils.IsInStringArray("allUsers", binding.Members) { + allUsers = append(allUsers, binding) + } + if utils.IsInStringArray("allAuthenticatedUsers", binding.Members) { + allAuthUsers = append(allAuthUsers, binding) + } + } + + for _, binding := range allUsers { + switch binding.Role { + case "roles/storage.admin", "roles/storage.objectAdmin": + acl = cloudprovider.ACLPublicReadWrite + case "roles/storage.objectViewer": + if acl != cloudprovider.ACLPublicReadWrite { + acl = cloudprovider.ACLPublicRead + } + } + } + + for _, binding := range allAuthUsers { + switch binding.Role { + case "roles/storage.admin", "roles/storage.objectAdmin", "roles/storage.objectViewer": + acl = cloudprovider.ACLAuthRead + } + } + return acl +} + +func (region *SRegion) SetBucketAcl(bucket string, acl cloudprovider.TBucketACLType) error { + iam, err := region.GetBucketIam(bucket) + if err != nil { + return errors.Wrap(err, "GetBucketIam") + } + bindings := []SBucketBinding{} + for _, binding := range iam.Bindings { + if !utils.IsInStringArray(string(storage.AllUsers), binding.Members) && !utils.IsInStringArray(string(storage.AllAuthenticatedUsers), binding.Members) { + bindings = append(bindings, binding) + } + } + switch acl { + case cloudprovider.ACLPrivate: + if len(bindings) == len(iam.Bindings) { + return nil + } + case cloudprovider.ACLAuthRead: + bindings = append(bindings, SBucketBinding{ + Role: "roles/storage.objectViewer", + Members: []string{"allAuthenticatedUsers"}, + }) + case cloudprovider.ACLPublicRead: + bindings = append(bindings, SBucketBinding{ + Role: "roles/storage.objectViewer", + Members: []string{"allUsers"}, + }) + case cloudprovider.ACLPublicReadWrite: + bindings = append(bindings, SBucketBinding{ + Role: "roles/storage.objectAdmin", + Members: []string{"allUsers"}, + }) + default: + return fmt.Errorf("unknown acl %s", acl) + } + iam.Bindings = bindings + _, err = region.SetBucketIam(bucket, iam) + if err != nil { + return errors.Wrap(err, "SetBucketIam") + } + return nil + +} + +func (b *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error { + return b.region.SetBucketAcl(b.Name, acl) +} + +func (b *SBucket) GetGlobalId() string { + return b.Name +} + +func (b *SBucket) GetName() string { + return b.Name +} + +func (b *SBucket) GetLocation() string { + return strings.ToLower(b.Location) +} + +func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { + return b.region +} + +func (b *SBucket) GetCreatedAt() time.Time { + return b.TimeCreated +} + +func (b *SBucket) GetStorageClass() string { + return b.StorageClass +} + +func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { + return []cloudprovider.SBucketAccessUrl{ + { + Url: fmt.Sprintf("https://www.googleapis.com/storage/v1/b/%s", b.Name), + Description: "bucket domain", + Primary: true, + }, + { + Url: fmt.Sprintf("https://www.googleapis.com/upload/storage/v1/b/%s/o", b.Name), + Description: "object upload endpoint", + }, + { + Url: fmt.Sprintf("https://www.googleapis.com/batch/storage/v1/b/%s", b.Name), + Description: "batch operation", + }, + } +} + +func (b *SBucket) GetStats() cloudprovider.SBucketStats { + stats, _ := cloudprovider.GetIBucketStats(b) + return stats +} + +func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { + resource := fmt.Sprintf("b/%s/o?uploadType=resumable&upload_id=%s", b.Name, uploadId) + return b.region.client.storageAbortUpload(resource) +} + +func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { + resource := fmt.Sprintf("b/%s/o/%s", b.Name, url.PathEscape(key)) + err := b.region.StorageGet(resource, nil) + if err != nil { + return errors.Wrapf(err, "failed to get object %s", key) + } + return nil +} + +func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + resource := fmt.Sprintf("b/%s/o/%s", srcBucket, url.PathEscape(srcKey)) + action := fmt.Sprintf("copyTo/b/%s/o/%s", b.Name, url.PathEscape(destKey)) + err := b.region.StorageDo(resource, action, nil, nil) + if err != nil { + return errors.Wrap(err, "CopyObject") + } + err = b.region.SetObjectAcl(b.Name, destKey, cannedAcl) + if err != nil { + return errors.Wrapf(err, "AddObjectAcl(%s)", cannedAcl) + } + err = b.region.SetObjectMeta(b.Name, destKey, meta) + if err != nil { + return errors.Wrap(err, "SetObjectMeta") + } + return nil +} + +func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partNumber int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (region *SRegion) DeleteObject(bucket, key string) error { + resource := fmt.Sprintf("b/%s/o/%s", bucket, url.PathEscape(key)) + return region.StorageDelete(resource) +} + +func (b *SBucket) DeleteObject(ctx context.Context, key string) error { + return b.region.DeleteObject(b.Name, key) +} + +func (region *SRegion) DownloadObjectRange(bucket, object string, start, end int64) (io.ReadCloser, error) { + resource := fmt.Sprintf("b/%s/o/%s?alt=media", bucket, url.PathEscape(object)) + header := http.Header{} + if start <= 0 { + if end > 0 { + header.Set("Range", fmt.Sprintf("bytes=0-%d", end)) + } else { + header.Set("Range", "bytes=-1") + } + } else { + if end > start { + header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end)) + } else { + header.Set("Range", fmt.Sprintf("bytes=%d-", start)) + } + } + return region.client.storageDownload(resource, header) +} + +func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { + return b.region.DownloadObjectRange(b.Name, key, rangeOpt.Start, rangeOpt.End) +} + +func (region *SRegion) SingedUrl(bucket, key string, method string, expire time.Duration) (string, error) { + if expire > time.Hour*24*7 { + return "", fmt.Errorf(`Expiration Time can\'t be longer than 604800 seconds (7 days)`) + } + opts := &storage.SignedURLOptions{ + Scheme: storage.SigningSchemeV4, + Method: method, + GoogleAccessID: region.client.clientEmail, + PrivateKey: []byte(region.client.privateKey), + Expires: time.Now().Add(expire), + } + switch method { + case "GET": + case "PUT": + opts.Headers = []string{"Content-Type:application/octet-stream"} + default: + return "", errors.Wrapf(cloudprovider.ErrNotSupported, "Not support method %s", method) + } + return storage.SignedURL(bucket, key, opts) + +} + +func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { + return b.region.SingedUrl(b.Name, key, method, expire) +} + +func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { + result := cloudprovider.SListObjectResult{} + objs, err := b.region.GetObjects(b.Name, prefix, marker, delimiter, maxCount) + if err != nil { + return result, errors.Wrap(err, "GetObjects") + } + result.NextMarker = objs.NextPageToken + log.Errorf("obj count: %d", len(objs.Items)) + result.Objects = []cloudprovider.ICloudObject{} + result.CommonPrefixes = []cloudprovider.ICloudObject{} + for i := range objs.Items { + if strings.HasSuffix(objs.Items[i].Name, "/") { + continue + } + objs.Items[i].bucket = b + result.Objects = append(result.Objects, &objs.Items[i]) + } + for i := range objs.Prefixes { + obj := &SObject{ + bucket: b, + Name: objs.Prefixes[i], + } + result.CommonPrefixes = append(result.CommonPrefixes, obj) + } + return result, nil +} + +func (region *SRegion) NewMultipartUpload(bucket, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + body := map[string]string{"name": key} + if len(storageClassStr) > 0 { + body["storageClass"] = storageClassStr + } + for k := range meta { + switch k { + case cloudprovider.META_HEADER_CONTENT_TYPE: + body["contentType"] = meta.Get(k) + case cloudprovider.META_HEADER_CONTENT_ENCODING: + body["contentEncoding"] = meta.Get(k) + case cloudprovider.META_HEADER_CONTENT_DISPOSITION: + body["contentDisposition"] = meta.Get(k) + case cloudprovider.META_HEADER_CONTENT_LANGUAGE: + body["contentLanguage"] = meta.Get(k) + case cloudprovider.META_HEADER_CACHE_CONTROL: + body["cacheControl"] = meta.Get(k) + default: + body[fmt.Sprintf("metadata.%s", k)] = meta.Get(k) + } + } + switch cannedAcl { + case cloudprovider.ACLPrivate: + case cloudprovider.ACLAuthRead: + body["predefinedAcl"] = "authenticatedRead" + case cloudprovider.ACLPublicRead: + body["predefinedAcl"] = "publicRead" + case cloudprovider.ACLPublicReadWrite: + return "", cloudprovider.ErrNotSupported + } + resource := fmt.Sprintf("b/%s/o?uploadType=resumable", bucket) + input := strings.NewReader(jsonutils.Marshal(body).String()) + header := http.Header{} + header.Set("Content-Type", "application/json; charset=UTF-8") + header.Set("Content-Length", fmt.Sprintf("%d", input.Len())) + resp, err := region.client.storageUpload(resource, header, input) + if err != nil { + return "", errors.Wrap(err, "storageUpload") + } + defer resp.Body.Close() + location := resp.Header.Get("Location") + query, err := url.ParseQuery(location) + if err != nil { + return "", errors.Wrapf(err, "url.ParseQuery(%s)", location) + } + return query.Get("upload_id"), nil +} + +func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + return b.region.NewMultipartUpload(b.Name, key, cannedAcl, storageClassStr, meta) +} + +func (region *SRegion) UploadPart(bucket, uploadId string, partIndex int, offset int64, part io.Reader, partSize int64, totalSize int64) error { + resource := fmt.Sprintf("b/%s/o?uploadType=resumable&upload_id=%s", bucket, uploadId) + header := http.Header{} + header.Set("Content-Length", fmt.Sprintf("%d", partSize)) + header.Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", offset, offset+partSize-1, totalSize)) + resp, err := region.client.storageUploadPart(resource, header, part) + if err != nil { + return errors.Wrap(err, "storageUploadPart") + } + if resp.StatusCode >= 500 { + content, _ := ioutil.ReadAll(resp.Body) + return fmt.Errorf("status code: %d %s", resp.StatusCode, content) + } + defer resp.Body.Close() + return nil +} + +func (region *SRegion) CheckUploadRange(bucket string, uploadId string) error { + resource := fmt.Sprintf("b/%s/o?uploadType=resumable&upload_id=%s", bucket, uploadId) + header := http.Header{} + header.Set("Content-Range", "bytes */*") + resp, err := region.client.storageUploadPart(resource, header, nil) + if err != nil { + return errors.Wrap(err, "storageUploadPart") + } + defer resp.Body.Close() + + content, err := ioutil.ReadAll(resp.Body) + if err != nil { + return errors.Wrap(err, "ReadAll") + } + fmt.Println("content: ", string(content)) + for k, v := range resp.Header { + fmt.Println("k: ", k, "v: ", v) + } + fmt.Println("status code: ", resp.StatusCode) + return nil +} + +func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, part io.Reader, partSize int64, offset, totalSize int64) (string, error) { + return "", b.region.UploadPart(b.Name, uploadId, partIndex, offset, part, partSize, totalSize) +} + +func (b *SBucket) PutObject(ctx context.Context, key string, body io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + return b.region.PutObject(b.Name, key, body, sizeBytes, cannedAcl, meta) +} + +func (region *SRegion) GetBucket(name string) (*SBucket, error) { + resource := "b/" + name + bucket := &SBucket{} + err := region.StorageGet(resource, bucket) + if err != nil { + return nil, errors.Wrap(err, "GetBucket") + } + return bucket, nil +} + +func (region *SRegion) GetBuckets(maxResults int, pageToken string) ([]SBucket, error) { + buckets := []SBucket{} + params := map[string]string{ + "project": region.GetProjectId(), + } + err := region.StorageList("b", params, maxResults, pageToken, &buckets) + if err != nil { + return nil, err + } + return buckets, nil +} + +func (region *SRegion) CreateBucket(name string, storageClass string, acl cloudprovider.TBucketACLType) (*SBucket, error) { + body := map[string]interface{}{ + "name": name, + "location": region.Name, + } + if len(storageClass) > 0 { + body["storageClass"] = storageClass + } + params := url.Values{} + params.Set("predefinedDefaultObjectAcl", "private") + switch acl { + case cloudprovider.ACLPrivate, cloudprovider.ACLUnknown: + params.Set("predefinedAcl", "private") + case cloudprovider.ACLAuthRead: + params.Set("predefinedAcl", "authenticatedRead") + case cloudprovider.ACLPublicRead: + params.Set("predefinedAcl", "publicRead") + case cloudprovider.ACLPublicReadWrite: + params.Set("predefinedAcl", "publicReadWrite") + } + params.Set("project", region.GetProjectId()) + bucket := &SBucket{} + resource := fmt.Sprintf("b?%s", params.Encode()) + err := region.StorageInsert(resource, jsonutils.Marshal(body), bucket) + if err != nil { + return nil, err + } + return bucket, nil +} + +func (region *SRegion) UploadObject(bucket string, params url.Values, header http.Header, input io.Reader) error { + resource := fmt.Sprintf("b/%s/o", bucket) + if len(params) > 0 { + resource = fmt.Sprintf("%s?%s", resource, params.Encode()) + } + resp, err := region.client.storageUpload(resource, header, input) + if err != nil { + return errors.Wrap(err, "storageUpload") + } + defer resp.Body.Close() + return nil +} + +func (region *SRegion) PutObject(bucket string, name string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, meta http.Header) error { + params := url.Values{} + params.Set("name", name) + params.Set("uploadType", "media") + header := http.Header{} + header.Set("Content-Length", fmt.Sprintf("%v", sizeBytes)) + err := region.UploadObject(bucket, params, header, input) + if err != nil { + return errors.Wrap(err, "UploadObject") + } + err = region.SetObjectAcl(bucket, name, cannedAcl) + if err != nil { + return errors.Wrap(err, "SetObjectAcl") + } + return region.SetObjectMeta(bucket, name, meta) +} + +func (region *SRegion) DeleteBucket(name string) error { + return region.StorageDelete("b/" + name) +} diff --git a/pkg/multicloud/google/bucketacl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/bucketacl.go similarity index 98% rename from pkg/multicloud/google/bucketacl.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/bucketacl.go index 1b3cfd1147..737c6bcc53 100644 --- a/pkg/multicloud/google/bucketacl.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/bucketacl.go @@ -23,7 +23,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type GCSAcl struct { diff --git a/pkg/multicloud/google/cloudbuild.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/cloudbuild.go similarity index 100% rename from pkg/multicloud/google/cloudbuild.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/cloudbuild.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance.go new file mode 100644 index 0000000000..259cd11b51 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance.go @@ -0,0 +1,636 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +var ( + EngineVersions = map[string]GoogleSQLVersion{ + "MYSQL_5_5": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.5"}, + "MYSQL_5_6": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.6"}, + "MYSQL_5_7": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_MYSQL, Version: "5.7"}, + "POSTGRES_9_6": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "9.6"}, + "POSTGRES_10": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "10"}, + "POSTGRES_11": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "11"}, + "POSTGRES_12": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_POSTGRESQL, Version: "12"}, + "SQLSERVER_2017_STANDARD": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Standard"}, + "SQLSERVER_2017_ENTERPRISE": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Enterprise"}, + "SQLSERVER_2017_EXPRESS": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Express"}, + "SQLSERVER_2017_WEB": GoogleSQLVersion{Engine: api.DBINSTANCE_TYPE_SQLSERVER, Version: "2017 Web"}, + } + InstanceTypes = map[string]GoogleSQLType{ + "db-f1-micro": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 614}, + "db-g1-small": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 1740}, + "D0": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 512}, + "D1": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 1024}, + "D2": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 2048}, + "D4": GoogleSQLType{VcpuCount: 1, VmemSizeMb: 5120}, + "D8": GoogleSQLType{VcpuCount: 2, VmemSizeMb: 10240}, + "D16": GoogleSQLType{VcpuCount: 4, VmemSizeMb: 10240}, + "D32": GoogleSQLType{VcpuCount: 8, VmemSizeMb: 10240}, + } +) + +type GoogleSQLType struct { + VcpuCount int + VmemSizeMb int +} + +type GoogleSQLVersion struct { + Engine string + Version string +} + +type SDBInstanceLocationPreference struct { + Zone string + Kind string +} + +type SDBInstanceMaintenanceWindow struct { + Kind string + Hour int + Day int +} + +type SDBInstanceBackupConfiguration struct { + StartTime string + Kind string + Enabled bool + BinaryLogEnabled bool +} + +type SAuthorizedNetwork struct { + Value string + Kind string + Name string +} + +type SDBInstanceSettingIpConfiguration struct { + PrivateNetwork string + AuthorizedNetworks []SAuthorizedNetwork + Ipv4Enabled bool +} + +type SDBInstanceSetting struct { + AuthorizedGaeApplications []string + Tier string + Kind string + AvailabilityType string + PricingPlan string + ReplicationType string + ActivationPolicy string + IpConfiguration SDBInstanceSettingIpConfiguration + LocationPreference SDBInstanceLocationPreference + DataDiskType string + MaintenanceWindow SDBInstanceMaintenanceWindow + BackupConfiguration SDBInstanceBackupConfiguration + SettingsVersion string + StorageAutoResizeLimit string + StorageAutoResize bool + DataDiskSizeGb int + DatabaseFlags []SDBInstanceParameter + UserLabels map[string]string +} + +type SDBInstanceIpAddress struct { + Type string + IpAddress string +} + +type SDBInstanceCaCert struct { + Kind string + CertSerialNumber string + Cert string + CommonName string + Sha1Fingerprint string + Instance string + CreateTime time.Time + ExpirationTime time.Time +} + +type SDBInstance struct { + multicloud.SDBInstanceBase + region *SRegion + + Kind string + State string + DatabaseVersion string + Settings SDBInstanceSetting + Etag string + MasterInstanceName string + IpAddresses []SDBInstanceIpAddress + ServerCaCert SDBInstanceCaCert + InstanceType string + Project string + ServiceAccountEmailAddress string + BackendType string + SelfLink string + ConnectionName string + Name string + Region string + GceZone string +} + +func (region *SRegion) GetDBInstances(maxResults int, pageToken string) ([]SDBInstance, error) { + instances := []SDBInstance{} + params := map[string]string{"filter": "region=" + region.Name} + err := region.RdsList("instances", params, maxResults, pageToken, &instances) + if err != nil { + return nil, errors.Wrap(err, "RdsList") + } + return instances, nil +} + +func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { + instance := SDBInstance{region: region} + err := region.rdsGet(instanceId, &instance) + if err != nil { + return nil, errors.Wrap(err, "RdsGet") + } + return &instance, nil +} + +func (rds *SDBInstance) GetName() string { + return rds.Name +} + +func (rds *SDBInstance) GetId() string { + return rds.SelfLink +} + +func (rds *SDBInstance) GetGlobalId() string { + return strings.TrimPrefix(rds.SelfLink, fmt.Sprintf("%s/%s/", GOOGLE_DBINSTANCE_DOMAIN, GOOGLE_DBINSTANCE_API_VERSION)) +} + +func (rds *SDBInstance) GetProjectId() string { + return rds.region.GetProjectId() +} + +func (rds *SDBInstance) IsEmulated() bool { + return false +} + +func (rds *SDBInstance) GetStatus() string { + switch rds.State { + case "RUNNABLE": + return api.DBINSTANCE_RUNNING + case "PENDING_CREATE": + return api.DBINSTANCE_DEPLOYING + case "MAINTENANCE": + return api.DBINSTANCE_MAINTENANCE + case "FAILED": + return api.DBINSTANCE_CREATE_FAILED + case "UNKNOWN_STATE", "SUSPENDED": + return api.DBINSTANCE_UNKNOWN + } + return rds.State +} + +func (rds *SDBInstance) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (rds *SDBInstance) GetCreatedAt() time.Time { + return rds.ServerCaCert.CreateTime +} + +func (rds *SDBInstance) GetExpiredAt() time.Time { + return time.Time{} +} + +func (rds *SDBInstance) GetMasterInstanceId() string { + if len(rds.MasterInstanceName) > 0 { + if master := strings.Split(rds.MasterInstanceName, ":"); len(master) == 2 { + return fmt.Sprintf("projects/%s/instances/%s", master[0], master[1]) + } + } + return "" +} + +func (rds *SDBInstance) GetSecurityGroupId() string { + return "" +} + +func (rds *SDBInstance) Refresh() error { + instance, err := rds.region.GetDBInstance(rds.SelfLink) + if err != nil { + return errors.Wrapf(err, "GetDBInstance(%s)", rds.SelfLink) + } + return jsonutils.Update(rds, instance) +} + +func (rds *SDBInstance) GetPort() int { + switch rds.GetEngine() { + case api.DBINSTANCE_TYPE_MYSQL: + return 3306 + case api.DBINSTANCE_TYPE_POSTGRESQL: + return 5432 + case api.DBINSTANCE_TYPE_SQLSERVER: + return 1433 + default: + return 0 + } +} + +func (rds *SDBInstance) GetEngine() string { + if e, ok := EngineVersions[rds.DatabaseVersion]; ok { + return e.Engine + } + return rds.DatabaseVersion +} + +func (rds *SDBInstance) GetEngineVersion() string { + if e, ok := EngineVersions[rds.DatabaseVersion]; ok { + return e.Version + } + return rds.DatabaseVersion +} + +func (rds *SDBInstance) GetInstanceType() string { + return rds.Settings.Tier +} + +func (rds *SDBInstance) GetVcpuCount() int { + if t, ok := InstanceTypes[rds.Settings.Tier]; ok { + return t.VcpuCount + } + numStr := "" + if strings.HasPrefix(rds.Settings.Tier, "db-n1-standard-") { + numStr = strings.TrimPrefix(rds.Settings.Tier, "db-n1-standard-") + } else if strings.HasPrefix(rds.Settings.Tier, "db-n1-highmem-") { + numStr = strings.TrimPrefix(rds.Settings.Tier, "db-n1-highmem-") + } else { + numStr = strings.TrimPrefix(rds.Settings.Tier, "db-custom-") + numStr = strings.Split(numStr, "-")[0] + } + cpu, _ := strconv.ParseInt(numStr, 10, 32) + return int(cpu) +} + +func (rds *SDBInstance) GetVmemSizeMB() int { + if t, ok := InstanceTypes[rds.Settings.Tier]; ok { + return t.VmemSizeMb + } + if strings.HasPrefix(rds.Settings.Tier, "db-custom-") { + info := strings.Split(rds.Settings.Tier, "-") + numStr := info[len(info)-1] + mem, _ := strconv.ParseInt(numStr, 10, 32) + return int(mem) + } else if strings.HasPrefix(rds.Settings.Tier, "db-n1-standard-") { + return rds.GetVcpuCount() * 3840 + } else if strings.HasPrefix(rds.Settings.Tier, "db-n1-highmem-") { + return rds.GetVcpuCount() * 3840 * 2 + } + return 0 +} + +func (rds *SDBInstance) GetDiskSizeGB() int { + return rds.Settings.DataDiskSizeGb +} + +func (rds *SDBInstance) GetCategory() string { + switch rds.Settings.AvailabilityType { + case "REGIONAL": + return api.GOOGLE_DBINSTANCE_CATEGORY_REGIONAL + default: + return api.GOOGLE_DBINSTANCE_CATEGORY_ZONAL + } +} + +func (rds *SDBInstance) GetStorageType() string { + return rds.Settings.DataDiskType +} + +func (rds *SDBInstance) GetMaintainTime() string { + startTime := (rds.Settings.MaintenanceWindow.Hour + 8) % 24 + startDay := (rds.Settings.MaintenanceWindow.Day + 1) % 7 + return fmt.Sprintf("%s %02d:00 - %02d:00", time.Weekday(startDay).String(), startTime, startTime+1) +} + +func (rds *SDBInstance) GetConnectionStr() string { + for _, ip := range rds.IpAddresses { + if ip.Type == "PRIMARY" { + return ip.IpAddress + } + } + return "" +} + +func (rds *SDBInstance) GetInternalConnectionStr() string { + ret := []string{rds.ConnectionName} + for _, ip := range rds.IpAddresses { + if ip.Type == "PRIVATE" { + ret = append(ret, ip.IpAddress) + } + } + return strings.Join(ret, ",") +} + +func (rds *SDBInstance) GetZone1Id() string { + zones, err := rds.region.GetIZones() + if err != nil { + log.Errorf("failed to found rds %s zone %s", rds.Name, rds.GceZone) + return "" + } + for _, zone := range zones { + if zone.GetId() == rds.GceZone { + return zone.GetGlobalId() + } + } + return "" +} + +func (rds *SDBInstance) GetZone2Id() string { + return "" +} + +func (rds *SDBInstance) GetZone3Id() string { + return "" +} + +func (rds *SDBInstance) GetIVpcId() string { + return "" +} + +func (rds *SDBInstance) GetDBNetwork() (*cloudprovider.SDBInstanceNetwork, error) { + return nil, nil +} + +func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { + ret := []cloudprovider.ICloudDBInstanceParameter{} + for i := range rds.Settings.DatabaseFlags { + rds.Settings.DatabaseFlags[i].rds = rds + ret = append(ret, &rds.Settings.DatabaseFlags[i]) + } + return ret, nil +} + +func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { + databases, err := rds.region.GetDBInstanceDatabases(rds.Name) + if err != nil { + return nil, errors.Wrap(err, "GetDBInstanceDatabases") + } + ret := []cloudprovider.ICloudDBInstanceDatabase{} + for i := range databases { + databases[i].rds = rds + ret = append(ret, &databases[i]) + } + return ret, nil +} + +func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { + accounts, err := rds.region.GetDBInstanceAccounts(rds.Name) + if err != nil { + return nil, errors.Wrap(err, "GetDBInstanceAccounts") + } + ret := []cloudprovider.ICloudDBInstanceAccount{} + for i := range accounts { + accounts[i].rds = rds + ret = append(ret, &accounts[i]) + } + return ret, nil +} + +func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + backups, err := rds.region.GetDBInstanceBackups(rds.Name) + if err != nil { + return nil, errors.Wrap(err, "GetDBInstanceBackups") + } + ret := []cloudprovider.ICloudDBInstanceBackup{} + for i := range backups { + backups[i].rds = rds + ret = append(ret, &backups[i]) + } + return ret, nil +} + +func (region *SRegion) ChangeDBInstanceConfig(instanceId string, diskSizeGb int, instanceType string) error { + rds, err := region.GetDBInstance(instanceId) + if err != nil { + return errors.Wrapf(err, "GetDBInstance(%s)", instanceId) + } + body := map[string]interface{}{} + settings := map[string]interface{}{} + if len(instanceType) > 0 && instanceType != rds.GetInstanceType() { + settings["tier"] = instanceType + } + if diskSizeGb > 0 && diskSizeGb != rds.GetDiskSizeGB() { + settings["dataDiskSizeGb"] = diskSizeGb + } + if len(settings) == 0 { + return nil + } + body["settings"] = settings + return region.rdsPatch(rds.SelfLink, jsonutils.Marshal(body)) +} + +func (rds *SDBInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedDBInstanceChangeConfig) error { + return rds.region.ChangeDBInstanceConfig(rds.SelfLink, config.DiskSizeGB, config.InstanceType) +} + +func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (region *SRegion) DBInstancePublicConnectionOperation(instanceId string, open bool) error { + ipConfiguration := map[string]interface{}{ + "ipv4Enabled": open, + } + if open { + ipConfiguration["authorizedNetworks"] = []map[string]string{ + map[string]string{ + "name": "White list", + "value": "0.0.0.0/0", + }, + } + } + body := map[string]interface{}{ + "settings": map[string]interface{}{ + "ipConfiguration": ipConfiguration, + }, + } + return region.rdsPatch(instanceId, jsonutils.Marshal(body)) +} + +func (rds *SDBInstance) OpenPublicConnection() error { + return rds.region.DBInstancePublicConnectionOperation(rds.SelfLink, true) +} + +func (rds *SDBInstance) ClosePublicConnection() error { + return rds.region.DBInstancePublicConnectionOperation(rds.SelfLink, false) +} + +func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { + return rds.region.CreateDatabase(rds.SelfLink, conf.Name, conf.CharacterSet) +} + +func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { + return rds.region.CreateDBInstanceAccount(rds.SelfLink, conf.Name, conf.Password, "%") +} + +func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { + err := rds.region.CreateDBInstanceBackup(rds.SelfLink, conf.Name, conf.Description) + if err != nil { + return "", errors.Wrap(err, "CreateIBackup") + } + return "", nil +} + +func (region *SRegion) RecoverFromBackup(instanceName, dest string, backupId string) error { + backup, err := region.GetDBInstanceBackup(backupId) + if err != nil { + return errors.Wrap(err, "GetDBInstanceBackup") + } + body := map[string]interface{}{ + "restoreBackupContext": map[string]string{ + "backupRunId": backup.Id, + "instanceId": instanceName, + "project": region.client.projectId, + }, + } + return region.rdsDo(dest, "restoreBackup", nil, jsonutils.Marshal(body)) +} + +func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { + instanceName := rds.Name + if len(conf.OriginDBInstanceExternalId) > 0 { + instance, err := rds.region.GetDBInstance(conf.OriginDBInstanceExternalId) + if err != nil { + return errors.Wrapf(err, "GetInstance(%s)", conf.OriginDBInstanceExternalId) + } + instanceName = instance.Name + } + return rds.region.RecoverFromBackup(instanceName, rds.SelfLink, conf.BackupId) +} + +func (rds *SDBInstance) Reboot() error { + return rds.region.rdsDo(rds.SelfLink, "restart", nil, nil) +} + +func (rds *SDBInstance) Delete() error { + return rds.region.DeleteDBInstance(rds.SelfLink) +} + +func (region *SRegion) DeleteDBInstance(id string) error { + return region.rdsDelete(id) +} + +func (region *SRegion) CreateRds(name, engine, databaseVersion, category, instanceType, storageType string, diskSizeGb int, vpcId, zoneId, password string) (*SDBInstance, error) { + settings := map[string]interface{}{ + "tier": instanceType, + "storageAutoResize": true, + "dataDiskType": storageType, + "dataDiskSizeGb": diskSizeGb, + } + if utils.IsInStringArray(category, []string{api.GOOGLE_DBINSTANCE_CATEGORY_REGIONAL, api.GOOGLE_DBINSTANCE_CATEGORY_ZONAL}) { + settings["availabilityType"] = strings.ToUpper(category) + backupConfiguration := map[string]interface{}{ + "enabled": true, + "startTime": "19:00", + } + if engine == api.DBINSTANCE_TYPE_MYSQL { + backupConfiguration["binaryLogEnabled"] = true + } + settings["backupConfiguration"] = backupConfiguration + } + ipConfiguration := map[string]interface{}{ + "ipv4Enabled": true, + } + ipConfiguration["authorizedNetworks"] = []map[string]string{ + map[string]string{ + "name": "White list", + "value": "0.0.0.0/0", + }, + } + settings["ipConfiguration"] = ipConfiguration + body := map[string]interface{}{ + "databaseVersion": databaseVersion, + "name": name, + "region": region.Name, + "settings": settings, + "backendType": "SECOND_GEN", + "instanceType": "CLOUD_SQL_INSTANCE", + } + if len(zoneId) > 0 { + settings["locationPreference"] = map[string]string{ + "zone": zoneId, + } + } + if len(password) > 0 { + body["rootPassword"] = password + } + rds := SDBInstance{region: region} + err := region.rdsInsert("instances", jsonutils.Marshal(body), &rds) + if err != nil { + if e, ok := errors.Cause(err).(*gError); ok && e.ErrorInfo.Code == 409 { //The instance or operation is not in an appropriate state to handle the request + return nil, fmt.Errorf("the name %s is unavailable because it was used recently", name) + } + return nil, errors.Wrap(err, "rdsInsert") + } + return &rds, nil +} + +func (region *SRegion) CreateDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (*SDBInstance, error) { + desc.EngineVersion = strings.ToUpper(desc.EngineVersion) + desc.EngineVersion = strings.Replace(desc.EngineVersion, ".", "_", -1) + desc.EngineVersion = strings.Replace(desc.EngineVersion, " ", "_", -1) + if desc.Engine == api.DBINSTANCE_TYPE_POSTGRESQL { + desc.Engine = "POSTGRES" + } + databaseVersion := fmt.Sprintf("%s_%s", strings.ToUpper(desc.Engine), desc.EngineVersion) + if _, ok := EngineVersions[databaseVersion]; !ok { + return nil, fmt.Errorf("Unsupport %s version %s", desc.Engine, desc.EngineVersion) + } + rds, err := region.CreateRds(desc.Name, desc.Engine, databaseVersion, desc.Category, desc.InstanceType, desc.StorageType, desc.DiskSizeGB, desc.VpcId, desc.ZoneId, desc.Password) + if err != nil { + return nil, errors.Wrapf(err, "CreateRds") + } + return rds, nil +} + +func (self *SDBInstance) GetTags() (map[string]string, error) { + return self.Settings.UserLabels, nil +} + +func (self *SDBInstance) GetSysTags() map[string]string { + return nil +} + +func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error { + params := map[string]interface{}{ + "settings": map[string]interface{}{ + "userLabels": tags, + }, + } + err := self.region.rdsPatch(self.GetId(), jsonutils.Marshal(params)) + return errors.Wrapf(err, "rdsPatch") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_account.go new file mode 100644 index 0000000000..79ca6accb8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_account.go @@ -0,0 +1,125 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSqlserverUserDetails struct { + ServerRoles []string +} + +type SDBInstanceAccount struct { + multicloud.SDBInstanceAccountBase + GoogleTags + rds *SDBInstance + + Kind string + Etag string + Name string + Host string + Instance string + SelfLink string + Project string + SqlserverUserDetails SSqlserverUserDetails +} + +func (region *SRegion) GetDBInstanceAccounts(instance string) ([]SDBInstanceAccount, error) { + accounts := []SDBInstanceAccount{} + params := map[string]string{} + resource := fmt.Sprintf("instances/%s/users", instance) + err := region.RdsListAll(resource, params, &accounts) + if err != nil { + return nil, errors.Wrap(err, "RdsListAll") + } + return accounts, nil +} + +func (region *SRegion) GetDBInstanceAccount(id string) (*SDBInstanceAccount, error) { + account := &SDBInstanceAccount{} + err := region.rdsGet(id, account) + if err != nil { + return nil, errors.Wrap(err, "rdsGet") + } + return account, nil +} + +func (region *SRegion) DeleteDBInstanceAccount(instanceName, user, host string) error { + resource := fmt.Sprintf("projects/%s/instances/%s/users?name=%s&host=%s", region.GetProjectId(), instanceName, url.PathEscape(user), url.PathEscape(host)) + return region.rdsDelete(resource) +} + +func (account *SDBInstanceAccount) Delete() error { + return account.rds.region.DeleteDBInstanceAccount(account.rds.Name, account.Name, account.Host) +} + +func (account *SDBInstanceAccount) GetHost() string { + return account.Host +} + +func (account *SDBInstanceAccount) GetName() string { + return account.Name +} + +func (account *SDBInstanceAccount) Refresh() error { + _account, err := account.rds.region.GetDBInstanceAccount(account.SelfLink) + if err != nil { + return errors.Wrap(err, "GetDBInstanceAccount") + } + return jsonutils.Update(account, _account) +} + +func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { + return []cloudprovider.ICloudDBInstanceAccountPrivilege{}, nil +} + +func (account *SDBInstanceAccount) ResetPassword(password string) error { + params := map[string]string{ + "host": account.Host, + "name": account.Name, + } + resource := fmt.Sprintf("instances/%s/users", account.rds.Name) + body := map[string]string{ + "password": password, + } + return account.rds.region.rdsUpdate(resource, params, jsonutils.Marshal(body)) +} + +func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { + return cloudprovider.ErrNotSupported +} + +func (account *SDBInstanceAccount) RevokePrivilege(database string) error { + return cloudprovider.ErrNotSupported +} + +func (region *SRegion) CreateDBInstanceAccount(instanceId string, name, password, host string) error { + body := map[string]interface{}{ + "name": name, + "password": password, + } + if len(host) > 0 { + body["host"] = host + } + return region.rdsDo(instanceId, "users", nil, jsonutils.Marshal(body)) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_backup.go new file mode 100644 index 0000000000..7bceb653ea --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_backup.go @@ -0,0 +1,171 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type OperationError struct { + Kind string + Code string + Message string +} + +type SDBInstanceBackup struct { + multicloud.SDBInstanceBackupBase + GoogleTags + rds *SDBInstance + + Kind string + Status string + EnqueuedTime string + Id string + StartTime time.Time + EndTime time.Time + Type string + Description string + WindowStartTime time.Time + Instance string + SelfLink string + Location string + Error OperationError +} + +func (region *SRegion) GetDBInstanceBackups(instanceId string) ([]SDBInstanceBackup, error) { + backups := []SDBInstanceBackup{} + params := map[string]string{} + resource := fmt.Sprintf("instances/%s/backupRuns", instanceId) + err := region.RdsListAll(resource, params, &backups) + if err != nil { + return nil, errors.Wrap(err, "RdsListAll") + } + return backups, nil +} + +func (region *SRegion) GetDBInstanceBackup(backupId string) (*SDBInstanceBackup, error) { + backup := SDBInstanceBackup{} + err := region.rdsGet(backupId, &backup) + if err != nil { + return nil, errors.Wrap(err, "RdsGet") + } + rds, err := region.GetDBInstance(strings.TrimSuffix(backup.SelfLink, fmt.Sprintf("/%s", backup.Id))) + if err != nil { + return nil, errors.Wrap(err, "GetDBInstance") + } + backup.rds = rds + return &backup, nil +} + +func (backup *SDBInstanceBackup) GetName() string { + return backup.Id +} + +func (backup *SDBInstanceBackup) GetId() string { + return backup.SelfLink +} + +func (backup *SDBInstanceBackup) GetGlobalId() string { + return strings.TrimPrefix(backup.SelfLink, fmt.Sprintf("%s/%s/", GOOGLE_DBINSTANCE_DOMAIN, GOOGLE_DBINSTANCE_API_VERSION)) +} + +func (backup *SDBInstanceBackup) GetProjectId() string { + return backup.rds.GetProjectId() +} + +func (backup *SDBInstanceBackup) Refresh() error { + _backup, err := backup.rds.region.GetDBInstanceBackup(backup.SelfLink) + if err != nil { + return errors.Wrap(err, "GetDBInstanceBackup") + } + return jsonutils.Update(backup, _backup) +} + +func (backup *SDBInstanceBackup) GetStatus() string { + switch backup.Status { + case "SQL_BACKUP_RUN_STATUS_UNSPECIFIED": + return api.DBINSTANCE_BACKUP_UNKNOWN + case "ENQUEUED": + return api.DBINSTANCE_BACKUP_CREATING + case "FAILED": + return api.DBINSTANCE_BACKUP_FAILED + case "SUCCESSFUL", "OVERDUE", "RUNNING", "SKIPPED", "DELETION_PENDING": + return api.DBINSTANCE_BACKUP_READY + case "DELETION_FAILED", "DELETED": + return api.DBINSTANCE_BACKUP_DELETING + } + return backup.Status +} + +func (backup *SDBInstanceBackup) IsEmulated() bool { + return false +} + +func (backup *SDBInstanceBackup) GetEngine() string { + return backup.rds.GetEngine() +} + +func (backup *SDBInstanceBackup) GetEngineVersion() string { + return backup.rds.GetEngineVersion() +} + +func (backup *SDBInstanceBackup) GetDBInstanceId() string { + return backup.rds.GetGlobalId() +} + +func (backup *SDBInstanceBackup) GetStartTime() time.Time { + return backup.StartTime +} + +func (backup *SDBInstanceBackup) GetEndTime() time.Time { + return backup.EndTime +} + +func (backup *SDBInstanceBackup) GetBackupSizeMb() int { + return 0 +} + +func (backup *SDBInstanceBackup) GetDBNames() string { + return "" +} + +func (backup *SDBInstanceBackup) GetBackupMode() string { + switch backup.Type { + case "AUTOMATED": + return api.BACKUP_MODE_AUTOMATED + default: + return api.BACKUP_MODE_MANUAL + } +} + +func (backup *SDBInstanceBackup) Delete() error { + return backup.rds.region.rdsDelete(backup.SelfLink) +} + +func (region *SRegion) CreateDBInstanceBackup(instanceId string, name, desc string) error { + body := map[string]interface{}{ + "name": name, + "description": desc, + } + return region.rdsDo(instanceId, "backupRuns", nil, jsonutils.Marshal(body)) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_database.go new file mode 100644 index 0000000000..23fd031536 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_database.go @@ -0,0 +1,105 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSqlserverDatabaseDetails struct { + CompatibilityLevel int + RecoveryModel string +} + +type SDBInstanceDatabase struct { + multicloud.SResourceBase + GoogleTags + rds *SDBInstance + Kind string + Collation string + Etag string + Name string + Instance string + SelfLink string + Charset string + Project string + SqlserverDatabaseDetails SSqlserverDatabaseDetails +} + +func (region *SRegion) GetDBInstanceDatabases(instance string) ([]SDBInstanceDatabase, error) { + databases := []SDBInstanceDatabase{} + params := map[string]string{} + resource := fmt.Sprintf("instances/%s/databases", instance) + err := region.RdsListAll(resource, params, &databases) + if err != nil { + return nil, errors.Wrap(err, "RdsListAll") + } + return databases, nil +} + +func (region *SRegion) DeleteDBInstanceDatabase(id string) error { + return region.rdsDelete(id) +} + +func (database *SDBInstanceDatabase) Delete() error { + return database.rds.region.DeleteDBInstanceDatabase(database.SelfLink) +} + +func (database *SDBInstanceDatabase) GetCharacterSet() string { + return database.Charset +} + +func (database *SDBInstanceDatabase) GetGlobalId() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetId() string { + return database.SelfLink +} + +func (database *SDBInstanceDatabase) GetName() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetStatus() string { + return api.DBINSTANCE_DATABASE_RUNNING +} + +func (database *SDBInstanceDatabase) IsEmulated() bool { + return false +} + +func (database *SDBInstanceDatabase) Refresh() error { + _database := SDBInstanceDatabase{} + err := database.rds.region.rdsGet(database.SelfLink, &_database) + if err != nil { + return errors.Wrap(err, "rdsGet") + } + return jsonutils.Update(database, _database) +} + +func (region *SRegion) CreateDatabase(instanceId string, name, charset string) error { + body := map[string]interface{}{ + "charset": charset, + "name": name, + } + return region.rdsDo(instanceId, "databases", nil, jsonutils.Marshal(body)) +} diff --git a/pkg/multicloud/google/dbinstance_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_parameter.go similarity index 100% rename from pkg/multicloud/google/dbinstance_parameter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/dbinstance_parameter.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/disk.go new file mode 100644 index 0000000000..48a4c8829d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/disk.go @@ -0,0 +1,274 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + + billing "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDisk struct { + storage *SStorage + SResourceBase + multicloud.SDisk + GoogleTags + + ProvisionedIops int + CreationTimestamp time.Time + SizeGB int + Zone string + Status string + Type string + SourceImage string + LastAttachTimestamp time.Time + LastDetachTimestamp time.Time + LabelFingerprint string + PhysicalBlockSizeBytes string + ResourcePolicies []string + Users []string + Kind string + autoDelete bool + boot bool + index int +} + +func (region *SRegion) GetDisks(zone string, storageType string, maxResults int, pageToken string) ([]SDisk, error) { + disks := []SDisk{} + if len(zone) == 0 { + return nil, fmt.Errorf("zone params can not be empty") + } + params := map[string]string{} + if len(storageType) > 0 { + params["filter"] = fmt.Sprintf(`type="%s/%s/projects/%s/zones/%s/diskTypes/%s"`, GOOGLE_COMPUTE_DOMAIN, GOOGLE_API_VERSION, region.GetProjectId(), zone, storageType) + } + return disks, region.List(fmt.Sprintf("zones/%s/disks", zone), params, maxResults, pageToken, &disks) +} + +func (region *SRegion) GetDisk(id string) (*SDisk, error) { + disk := &SDisk{} + return disk, region.Get("disks", id, disk) +} + +func (disk *SDisk) GetStatus() string { + switch disk.Status { + case "READY": + return api.DISK_READY + case "CREATING": + return api.DISK_ALLOCATING + case "RESTORING": + return api.DISK_RESET + case "FAILED": + return api.DISK_ALLOC_FAILED + case "DELETING": + return api.DISK_DEALLOC + default: + return api.DISK_UNKNOWN + } +} + +func (disk *SDisk) IsEmulated() bool { + return false +} + +func (disk *SDisk) Refresh() error { + _disk, err := disk.storage.zone.region.GetDisk(disk.Id) + if err != nil { + return err + } + return jsonutils.Update(disk, _disk) +} + +func (disk *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return disk.storage, nil +} + +func (disk *SDisk) GetIStorageId() string { + return disk.storage.GetGlobalId() +} + +func (disk *SDisk) GetDiskFormat() string { + return "raw" +} + +func (disk *SDisk) GetDiskSizeMB() int { + return disk.SizeGB * 1024 +} + +func (disk *SDisk) GetIsAutoDelete() bool { + if len(disk.Users) == 0 { + return false + } + return disk.autoDelete +} + +func (disk *SDisk) GetTemplateId() string { + return disk.SourceImage +} + +func (disk *SDisk) GetDiskType() string { + if disk.boot && len(disk.Users) > 0 { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +func (disk *SDisk) GetFsFormat() string { + return "" +} + +func (disk *SDisk) GetIsNonPersistent() bool { + return false +} + +func (disk *SDisk) GetDriver() string { + return "scsi" +} + +func (disk *SDisk) GetCacheMode() string { + return "none" +} + +func (disk *SDisk) GetMountpoint() string { + return "" +} + +func (disk *SDisk) GetAccessPath() string { + return "" +} + +func (disk *SDisk) GetIops() int { + return disk.ProvisionedIops +} + +func (disk *SDisk) Delete(ctx context.Context) error { + return disk.storage.zone.region.Delete(disk.SelfLink) +} + +func (disk *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := disk.storage.zone.region.CreateSnapshot(disk.SelfLink, name, desc) + if err != nil { + return nil, err + } + snapshot.region = disk.storage.zone.region + return snapshot, nil +} + +func (disk *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := disk.storage.zone.region.GetSnapshots(disk.SelfLink, 0, "") + if err != nil { + return nil, err + } + isnapshots := []cloudprovider.ICloudSnapshot{} + for i := range snapshots { + snapshots[i].region = disk.storage.zone.region + isnapshots = append(isnapshots, &snapshots[i]) + } + return isnapshots, nil +} + +func (disk *SDisk) GetISnapshot(id string) (cloudprovider.ICloudSnapshot, error) { + return disk.storage.zone.region.GetSnapshot(id) +} + +func (disk *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { + result := []string{} + for _, policy := range disk.ResourcePolicies { + globalId := strings.TrimPrefix(policy, fmt.Sprintf("%s/%s/", GOOGLE_COMPUTE_DOMAIN, GOOGLE_API_VERSION)) + result = append(result, globalId) + } + return result, nil +} + +func (disk *SDisk) Resize(ctx context.Context, newSizeMB int64) error { + return disk.storage.zone.region.ResizeDisk(disk.SelfLink, int(newSizeMB>>10)) +} + +func (disk *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (disk *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (disk *SDisk) GetBillingType() string { + return billing.BILLING_TYPE_POSTPAID +} + +func (disk *SDisk) GetCreatedAt() time.Time { + return disk.CreationTimestamp +} + +func (disk *SDisk) GetExpiredAt() time.Time { + return time.Time{} +} + +func (disk *SDisk) GetProjectId() string { + return disk.storage.zone.region.GetProjectId() +} + +func (region *SRegion) CreateDisk(name string, sizeGb int, zone string, storageType string, image string, desc string) (*SDisk, error) { + if !strings.HasPrefix(storageType, GOOGLE_COMPUTE_DOMAIN) { + storageType = fmt.Sprintf("projects/%s/zones/%s/diskTypes/%s", region.GetProjectId(), zone, storageType) + } + body := map[string]interface{}{ + "name": name, + "description": desc, + // https://www.googleapis.com/compute/v1/projects/my-project-15390453537169/zones/us-west2-c/diskTypes/pd-standard + // projects/my-project-15390453537169/zones/us-west2-c/diskTypes/pd-standard + "type": storageType, + } + if len(image) > 0 { + body["sourceImage"] = image + } else { + body["sizeGb"] = sizeGb + } + disk := &SDisk{} + resource := fmt.Sprintf("zones/%s/disks", zone) + err := region.Insert(resource, jsonutils.Marshal(body), disk) + if err != nil { + return nil, err + } + return disk, nil +} + +func (region *SRegion) ResizeDisk(id string, sizeGb int) error { + body := map[string]int{ + "sizeGb": sizeGb, + } + return region.Do(id, "resize", nil, jsonutils.Marshal(body)) +} + +func (self *SRegion) CreateSnapshot(diskId string, name string, desc string) (*SSnapshot, error) { + body := map[string]string{ + "name": name, + "description": desc, + } + err := self.Do(diskId, "createSnapshot", nil, jsonutils.Marshal(body)) + if err != nil { + return nil, err + } + snapshot := &SSnapshot{region: self} + return snapshot, self.GetBySelfId(fmt.Sprintf("projects/%s/global/snapshots/%s", self.GetProjectId(), name), snapshot) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/doc.go new file mode 100644 index 0000000000..e5c4de8130 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 google // import "yunion.io/x/cloudmux/pkg/multicloud/google" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/eip.go new file mode 100644 index 0000000000..a2e263eafa --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/eip.go @@ -0,0 +1,223 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SAddress struct { + region *SRegion + SResourceBase + multicloud.SEipBase + GoogleTags + instanceId string + + CreationTimestamp time.Time + Description string + Address string + Status string + Region string + Users []string + NetworkTier string + AddressType string + Kind string +} + +func (region *SRegion) GetEips(address string, maxResults int, pageToken string) ([]SAddress, error) { + eips := []SAddress{} + params := map[string]string{} + if len(address) > 0 { + params["filter"] = fmt.Sprintf(`address="%s"`, address) + } + resource := fmt.Sprintf("regions/%s/addresses", region.Name) + return eips, region.List(resource, params, maxResults, pageToken, &eips) +} + +func (region *SRegion) GetEip(id string) (*SAddress, error) { + eip := &SAddress{region: region} + return eip, region.Get("addresses", id, eip) +} + +func (addr *SAddress) GetStatus() string { + switch addr.Status { + case "RESERVING": + return api.EIP_STATUS_ASSOCIATE + case "RESERVED": + return api.EIP_STATUS_READY + case "IN_USE": + return api.EIP_STATUS_READY + default: + log.Errorf("Unknown eip status: %s", addr.Status) + return api.EIP_STATUS_UNKNOWN + } +} + +func (addr *SAddress) GetProjectId() string { + return addr.region.GetProjectId() +} + +func (addr *SAddress) IsEmulated() bool { + return len(addr.instanceId) > 0 +} + +func (addr *SAddress) GetCreatedAt() time.Time { + return addr.CreationTimestamp +} + +func (addr *SAddress) GetExpiredAt() time.Time { + return time.Time{} +} + +func (addr *SAddress) GetBillingType() string { + return billing.BILLING_TYPE_POSTPAID +} + +func (self *SAddress) Refresh() error { + if self.IsEmulated() { + return nil + } + addr, err := self.region.GetEip(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, addr) +} + +func (addr *SAddress) GetIpAddr() string { + return addr.Address +} + +func (addr *SAddress) GetMode() string { + if addr.IsEmulated() { + return api.EIP_MODE_INSTANCE_PUBLICIP + } + return api.EIP_MODE_STANDALONE_EIP +} + +func (addr *SAddress) GetINetworkId() string { + return "" +} + +func (addr *SAddress) GetAssociationType() string { + if len(addr.GetAssociationExternalId()) > 0 { + return api.EIP_ASSOCIATE_TYPE_SERVER + } + return "" +} + +func (addr *SAddress) GetAssociationExternalId() string { + if len(addr.instanceId) > 0 { + return addr.instanceId + } + if len(addr.Users) > 0 { + res := &SResourceBase{} + err := addr.region.GetBySelfId(addr.Users[0], res) + if err != nil { + return "" + } + return res.GetGlobalId() + } + return "" +} + +func (addr *SAddress) GetBandwidth() int { + return 0 +} + +func (addr *SAddress) GetInternetChargeType() string { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC +} + +func (addr *SAddress) Delete() error { + return addr.region.Delete(addr.SelfLink) +} + +func (addr *SAddress) Associate(conf *cloudprovider.AssociateConfig) error { + return addr.region.AssociateInstanceEip(conf.InstanceId, addr.Address) +} + +func (addr *SAddress) Dissociate() error { + if len(addr.Users) > 0 { + return addr.region.DissociateInstanceEip(addr.Users[0], addr.Address) + } + return nil +} + +func (addr *SAddress) ChangeBandwidth(bw int) error { + return cloudprovider.ErrNotSupported +} + +func (region *SRegion) CreateEip(name string, desc string) (*SAddress, error) { + body := map[string]string{ + "name": name, + "description": desc, + } + resource := fmt.Sprintf("regions/%s/addresses", region.Name) + addr := &SAddress{region: region} + err := region.Insert(resource, jsonutils.Marshal(body), addr) + if err != nil { + return nil, err + } + return addr, nil +} + +func (region *SRegion) AssociateInstanceEip(instanceId string, eip string) error { + instance, err := region.GetInstance(instanceId) + if err != nil { + return errors.Wrap(err, "region.GetInstance") + } + for _, networkInterface := range instance.NetworkInterfaces { + body := map[string]interface{}{ + "type": "ONE_TO_ONE_NAT", + "name": "External NAT", + "natIP": eip, + } + params := map[string]string{"networkInterface": networkInterface.Name} + return region.Do(instance.SelfLink, "addAccessConfig", params, jsonutils.Marshal(body)) + } + return fmt.Errorf("no valid networkinterface to associate") +} + +func (self *SRegion) DissociateInstanceEip(instanceId string, eip string) error { + instance := SInstance{} + err := self.GetBySelfId(instanceId, &instance) + if err != nil { + return errors.Wrap(err, "region.GetInstance") + } + for _, networkInterface := range instance.NetworkInterfaces { + for _, accessConfig := range networkInterface.AccessConfigs { + if accessConfig.NatIP == eip { + body := map[string]string{} + params := map[string]string{ + "networkInterface": networkInterface.Name, + "accessConfig": accessConfig.Name, + } + return self.Do(instance.SelfLink, "deleteAccessConfig", params, jsonutils.Marshal(body)) + } + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/globalnetwork.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/globalnetwork.go new file mode 100644 index 0000000000..5d1d622263 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/globalnetwork.go @@ -0,0 +1,135 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SGlobalNetwork struct { + GoogleTags + SResourceBase + + client *SGoogleClient + + CreationTimestamp time.Time + Description string + AutoCreateSubnetworks bool + Subnetworks []string + RoutingConfig map[string]string + Kind string +} + +func (self *SGlobalNetwork) GetStatus() string { + return api.GLOBAL_VPC_STATUS_AVAILABLE +} + +func (self *SGlobalNetwork) IsEmulated() bool { + return false +} + +func (self *SGlobalNetwork) Delete() error { + return self.client.ecsDelete(self.SelfLink, nil) +} + +func (self *SGlobalNetwork) GetCreatedAt() time.Time { + return self.CreationTimestamp +} + +func (self *SGlobalNetwork) Refresh() error { + gvpc, err := self.client.GetGlobalNetwork(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, gvpc) +} + +func (cli *SGoogleClient) GetGlobalNetwork(id string) (*SGlobalNetwork, error) { + net := &SGlobalNetwork{client: cli} + return net, cli.ecsGet("global/networks", id, net) +} + +func (self *SGoogleClient) GetICloudGlobalVpcById(id string) (cloudprovider.ICloudGlobalVpc, error) { + return self.GetGlobalNetwork(id) +} + +func (cli *SGoogleClient) GetGlobalNetworks(maxResults int, pageToken string) ([]SGlobalNetwork, error) { + networks := []SGlobalNetwork{} + params := map[string]string{} + resource := "global/networks" + if maxResults == 0 && len(pageToken) == 0 { + err := cli.ecsListAll(resource, params, &networks) + if err != nil { + return nil, errors.Wrap(err, "ecsListAll") + } + return networks, nil + } + resp, err := cli.ecsList(resource, params) + if err != nil { + return nil, errors.Wrap(err, "ecsList") + } + if resp.Contains("items") { + err = resp.Unmarshal(&networks, "items") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + } + return networks, nil +} + +func (self *SGoogleClient) CreateGlobalNetwork(name string, desc string) (*SGlobalNetwork, error) { + body := map[string]interface{}{ + "name": name, + "description": desc, + "autoCreateSubnetworks": false, + "mtu": 1460, + "routingConfig": map[string]string{ + "routingMode": "REGIONAL", + }, + } + globalnetwork := &SGlobalNetwork{client: self} + err := self.Insert("global/networks", jsonutils.Marshal(body), globalnetwork) + if err != nil { + return nil, errors.Wrap(err, "self.Insert") + } + return globalnetwork, nil +} + +func (self *SGoogleClient) CreateICloudGlobalVpc(opts *cloudprovider.GlobalVpcCreateOptions) (cloudprovider.ICloudGlobalVpc, error) { + gvpc, err := self.CreateGlobalNetwork(opts.NAME, opts.Desc) + if err != nil { + return nil, errors.Wrapf(err, "CreateICloudGlobalVpc") + } + return gvpc, nil +} + +func (self *SGoogleClient) GetICloudGlobalVpcs() ([]cloudprovider.ICloudGlobalVpc, error) { + gvpcs, err := self.GetGlobalNetworks(0, "") + if err != nil { + return nil, errors.Wrapf(err, "GetGlobalNetworks") + } + ret := []cloudprovider.ICloudGlobalVpc{} + for i := range gvpcs { + gvpcs[i].client = self + ret = append(ret, &gvpcs[i]) + } + return ret, nil +} diff --git a/pkg/multicloud/google/google.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/google.go similarity index 99% rename from pkg/multicloud/google/google.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/google.go index fb40cacbe9..4a14da9f12 100644 --- a/pkg/multicloud/google/google.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/google.go @@ -33,8 +33,8 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/host.go new file mode 100644 index 0000000000..8dad334df0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/host.go @@ -0,0 +1,189 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SHost struct { + multicloud.SHostBase + + zone *SZone +} + +func (host *SHost) GetId() string { + return host.zone.GetGlobalId() +} + +func (host *SHost) GetGlobalId() string { + return host.GetId() +} + +func (host *SHost) GetName() string { + return fmt.Sprintf("%s-%s", host.zone.region.client.cpcfg.Name, host.zone.GetName()) +} + +func (host *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + return host.zone.GetIStorages() +} + +func (host *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return host.zone.GetIStorageById(id) +} + +func (host *SHost) IsEmulated() bool { + return true +} + +func (host *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (host *SHost) Refresh() error { + return nil +} + +func (host *SHost) GetHostStatus() string { + return api.HOST_ONLINE +} + +func (host *SHost) GetEnabled() bool { + return true +} + +func (host *SHost) GetAccessIp() string { + return "" +} + +func (host *SHost) GetAccessMac() string { + return "" +} + +func (host *SHost) GetSysInfo() jsonutils.JSONObject { + info := jsonutils.NewDict() + info.Add(jsonutils.NewString(CLOUD_PROVIDER_GOOGLE), "manufacture") + return info +} + +func (host *SHost) GetSN() string { + return "" +} + +func (host *SHost) GetCpuCount() int { + return 0 +} + +func (host *SHost) GetNodeCount() int8 { + return 0 +} + +func (host *SHost) GetCpuDesc() string { + return "" +} + +func (host *SHost) GetCpuMhz() int { + return 0 +} + +func (host *SHost) GetMemSizeMB() int { + return 0 +} + +func (host *SHost) GetStorageSizeMB() int { + return 0 +} + +func (host *SHost) GetStorageType() string { + return api.DISK_TYPE_HYBRID +} + +func (host *SHost) GetHostType() string { + return api.HOST_TYPE_GOOGLE +} + +func (host *SHost) GetWire() *SWire { + vpc := &SVpc{region: host.zone.region} + return &SWire{vpc: vpc} +} + +func (host *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + ivpcs, err := host.zone.region.GetIVpcs() + if err != nil { + return nil, errors.Wrap(err, "region.GetIVpcs") + } + iwires := []cloudprovider.ICloudWire{} + for i := range ivpcs { + _iwires, err := ivpcs[i].GetIWires() + if err != nil { + return nil, errors.Wrap(err, "ivpcs[i].GetIWires") + } + iwires = append(iwires, _iwires...) + } + return iwires, nil +} + +func (host *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + instances, err := host.zone.region.GetInstances(host.zone.Name, 0, "") + if err != nil { + return nil, err + } + iVMs := []cloudprovider.ICloudVM{} + for i := range instances { + instances[i].host = host + iVMs = append(iVMs, &instances[i]) + } + return iVMs, nil +} + +func (host *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + instance, err := host.zone.region.GetInstance(id) + if err != nil { + return nil, err + } + if instance.Zone != host.zone.SelfLink { + return nil, cloudprovider.ErrNotFound + } + instance.host = host + return instance, nil +} + +func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + instance, err := host.zone.region._createVM(host.zone.Name, desc) + if err != nil { + return nil, err + } + instance.host = host + return instance, nil +} + +func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (host *SHost) GetIsMaintenance() bool { + return false +} + +func (host *SHost) GetVersion() string { + return GOOGLE_API_VERSION +} diff --git a/pkg/multicloud/google/iampolicy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/iampolicy.go similarity index 99% rename from pkg/multicloud/google/iampolicy.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/iampolicy.go index 15f8cc6b07..fadaeb2be8 100644 --- a/pkg/multicloud/google/iampolicy.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/iampolicy.go @@ -38,8 +38,8 @@ import ( "yunion.io/x/pkg/util/stringutils" "yunion.io/x/pkg/utils" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SBinding struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/image.go new file mode 100644 index 0000000000..c95f12045b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/image.go @@ -0,0 +1,270 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type GuestOsFeature struct { + Type string +} + +type SDeprecated struct { + State string + Replacement string + Deprecated bool +} + +type SImage struct { + multicloud.SImageBase + GoogleTags + storagecache *SStoragecache + SResourceBase + Name string + SelfLink string + Id string + + // normalized image info + imgInfo *imagetools.ImageInfo + + CreationTimestamp time.Time + Description string + SourceType string + RawDisk map[string]string + Deprecated SDeprecated + Status string + ArchiveSizeBytes int64 + DiskSizeGb int + Licenses []string + Family string + LabelFingerprint string + GuestOsFeatures []GuestOsFeature + LicenseCodes []string + StorageLocations []string + Kind string +} + +func (self *SImage) GetId() string { + return self.SelfLink +} + +func (self *SImage) GetGlobalId() string { + return strings.TrimPrefix(self.SelfLink, fmt.Sprintf("%s/%s/", GOOGLE_COMPUTE_DOMAIN, GOOGLE_API_VERSION)) +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (region *SRegion) SetProjectId(id string) { + region.client.projectId = id +} + +func (region *SRegion) GetAllAvailableImages() ([]SImage, error) { + images := []SImage{} + projectId := region.client.projectId + for _, project := range []string{ + "centos-cloud", + "ubuntu-os-cloud", + "windows-cloud", + "windows-sql-cloud", + "suse-cloud", + "suse-sap-cloud", + "rhel-cloud", + "rhel-sap-cloud", + "cos-cloud", + "coreos-cloud", + "debian-cloud", + projectId, + } { + _images, err := region.GetImages(project, 0, "") + if err != nil { + return nil, err + } + for _, image := range _images { + if image.Deprecated.State == "" { + images = append(images, image) + } + } + } + return images, nil +} + +func (region *SRegion) GetImages(project string, maxResults int, pageToken string) ([]SImage, error) { + images := []SImage{} + resource := "global/images" + params := map[string]string{} + if len(project) > 0 { + region.SetProjectId(project) + } + return images, region.List(resource, params, maxResults, pageToken, &images) +} + +func (region *SRegion) GetImage(id string) (*SImage, error) { + image := &SImage{} + return image, region.GetBySelfId(id, image) +} + +func (image *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (image *SImage) GetStatus() string { + switch image.Status { + case "READY": + return api.CACHED_IMAGE_STATUS_ACTIVE + case "FAILED": + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + case "PENDING": + return api.CACHED_IMAGE_STATUS_SAVING + default: + log.Errorf("Unknown image status: %s", image.Status) + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (image *SImage) GetImageStatus() string { + switch image.Status { + case "READY": + return cloudprovider.IMAGE_STATUS_ACTIVE + case "FAILED": + return cloudprovider.IMAGE_STATUS_KILLED + case "PENDING": + return cloudprovider.IMAGE_STATUS_QUEUED + default: + return cloudprovider.IMAGE_STATUS_KILLED + } +} + +func (image *SImage) Refresh() error { + _image, err := image.storagecache.region.GetImage(image.SelfLink) + if err != nil { + return err + } + return jsonutils.Update(image, _image) +} + +func (image *SImage) GetImageType() cloudprovider.TImageType { + if strings.Index(image.SelfLink, image.storagecache.region.GetProjectId()) >= 0 { + return cloudprovider.ImageTypeCustomized + } + return cloudprovider.ImageTypeSystem +} + +func (image *SImage) GetSizeByte() int64 { + return image.ArchiveSizeBytes +} + +func (image *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if image.imgInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(image.Name, "", "", "", "") + image.imgInfo = &imgInfo + } + + return image.imgInfo +} + +func (image *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(image.getNormalizedImageInfo().OsType) +} + +func (image *SImage) GetOsDist() string { + return image.getNormalizedImageInfo().OsDistro +} + +func (image *SImage) GetOsVersion() string { + return image.getNormalizedImageInfo().OsVersion +} + +func (image *SImage) GetOsLang() string { + return image.getNormalizedImageInfo().OsLang +} + +func (image *SImage) GetOsArch() string { + return image.getNormalizedImageInfo().OsArch +} + +func (image *SImage) GetFullOsName() string { + return image.Name +} + +func (image *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(image.getNormalizedImageInfo().OsBios) +} + +func (image *SImage) GetMinOsDiskSizeGb() int { + return image.DiskSizeGb +} + +func (image *SImage) GetCreatedAt() time.Time { + return image.CreationTimestamp +} + +func (image *SImage) GetImageFormat() string { + return "raw" +} + +func (image *SImage) IsEmulated() bool { + return false +} + +func (image *SImage) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (image *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return image.storagecache +} + +func (region *SRegion) CreateImage(name string, desc string, bucketName string, sourceFile string) (*SImage, error) { + body := map[string]interface{}{ + "timeout": "7200s", + "steps": []struct { + Args []string + Name string + }{ + { + Args: []string{ + fmt.Sprintf("-source_file=gs://%s/%s", bucketName, sourceFile), + "-data_disk", + "-timeout=7056s", + "-image_name=" + name, + "-no_guest_environment", + "-client_id=onecloud", + "-description=" + desc, + }, + Name: "gcr.io/compute-image-tools/gce_vm_image_import:release", + }, + }, + "tags": []string{"gce-daisy", "gce-daisy-image-import"}, + } + err := region.CloudbuildInsert(jsonutils.Marshal(body)) + if err != nil { + return nil, err + } + return region.GetImage(fmt.Sprintf("projects/%s/global/images/%s", region.GetProjectId(), name)) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/instance.go new file mode 100644 index 0000000000..40f5fcc563 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/instance.go @@ -0,0 +1,998 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/fileutils" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/cloudinit" + "yunion.io/x/onecloud/pkg/util/encode" + "yunion.io/x/onecloud/pkg/util/imagetools" + "yunion.io/x/onecloud/pkg/util/pinyinutils" +) + +const ( + METADATA_SSH_KEYS = "ssh-keys" + METADATA_STARTUP_SCRIPT = "startup-script" + METADATA_POWER_SHELL = "sysprep-specialize-script-ps1" + METADATA_STARTUP_SCRIPT_POWER_SHELL = "windows-startup-script-ps1" +) + +type AccessConfig struct { + Type string + Name string + NatIP string + NetworkTier string + Kind string +} + +type InstanceDisk struct { + Type string + Mode string + Source string + DeviceName string + Index int + Boot bool + AutoDelete bool + Licenses []string + Interface string + GuestOsFeatures []GuestOsFeature + Kind string +} + +type ServiceAccount struct { + Email string + scopes []string +} + +type SInstanceTag struct { + Items []string + Fingerprint string +} + +type SMetadataItem struct { + Key string + Value string +} + +type SMetadata struct { + Fingerprint string + Items []SMetadataItem +} + +type SInstance struct { + multicloud.SInstanceBase + GoogleTags + host *SHost + SResourceBase + + osInfo *imagetools.ImageInfo + + CreationTimestamp time.Time + Description string + Tags SInstanceTag + MachineType string + Status string + Zone string + CanIpForward bool + NetworkInterfaces []SNetworkInterface + Disks []InstanceDisk + Metadata SMetadata + ServiceAccounts []ServiceAccount + Scheduling map[string]interface{} + CpuPlatform string + LabelFingerprint string + StartRestricted bool + DeletionProtection bool + Kind string + + guestCpus int + memoryMb int + machineType string +} + +func (region *SRegion) GetInstances(zone string, maxResults int, pageToken string) ([]SInstance, error) { + instances := []SInstance{} + params := map[string]string{} + if len(zone) == 0 { + return nil, fmt.Errorf("zone params can not be empty") + } + resource := fmt.Sprintf("zones/%s/instances", zone) + return instances, region.List(resource, params, maxResults, pageToken, &instances) +} + +func (region *SRegion) GetInstance(id string) (*SInstance, error) { + instance := &SInstance{} + return instance, region.Get("instances", id, instance) +} + +func (instance *SInstance) GetHostname() string { + return instance.GetName() +} + +func (instance *SInstance) fetchMachineType() error { + if instance.guestCpus > 0 || instance.memoryMb > 0 || len(instance.machineType) > 0 { + return nil + } + machinetype := SMachineType{} + err := instance.host.zone.region.GetBySelfId(instance.MachineType, &machinetype) + if err != nil { + return err + } + instance.guestCpus = machinetype.GuestCpus + instance.memoryMb = machinetype.MemoryMb + instance.machineType = machinetype.Name + return nil +} + +func (self *SInstance) Refresh() error { + instance, err := self.host.zone.region.GetInstance(self.Id) + if err != nil { + return err + } + err = jsonutils.Update(self, instance) + if err != nil { + return err + } + instance.Labels = self.Labels + return nil +} + +//PROVISIONING, STAGING, RUNNING, STOPPING, STOPPED, SUSPENDING, SUSPENDED, and TERMINATED. +func (instance *SInstance) GetStatus() string { + switch instance.Status { + case "PROVISIONING": + return api.VM_DEPLOYING + case "STAGING": + return api.VM_STARTING + case "RUNNING": + return api.VM_RUNNING + case "STOPPING": + return api.VM_STOPPING + case "STOPPED": + return api.VM_READY + case "SUSPENDING": + return api.VM_SUSPENDING + case "SUSPENDED": + return api.VM_SUSPEND + case "TERMINATED": + return api.VM_READY + default: + return api.VM_UNKNOWN + } +} + +func (instance *SInstance) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (instance *SInstance) GetCreatedAt() time.Time { + return instance.CreationTimestamp +} + +func (instance *SInstance) GetExpiredAt() time.Time { + return time.Time{} +} + +func (instance *SInstance) GetProjectId() string { + return instance.host.zone.region.GetProjectId() +} + +func (instance *SInstance) GetIHost() cloudprovider.ICloudHost { + return instance.host +} + +func (instance *SInstance) GetIHostId() string { + return instance.host.GetGlobalId() +} + +func (instance *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + idisks := []cloudprovider.ICloudDisk{} + for _, disk := range instance.Disks { + _disk := &SDisk{} + err := instance.host.zone.region.GetBySelfId(disk.Source, _disk) + if err != nil { + return nil, errors.Wrap(err, "GetDisk") + } + storage, err := instance.host.zone.region.GetStorage(_disk.Type) + if err != nil { + return nil, errors.Wrap(err, "GetStorage") + } + storage.zone = instance.host.zone + _disk.storage = storage + _disk.autoDelete = disk.AutoDelete + _disk.boot = disk.Boot + _disk.index = disk.Index + idisks = append(idisks, _disk) + } + return idisks, nil +} + +func (instance *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics := []cloudprovider.ICloudNic{} + for i := range instance.NetworkInterfaces { + instance.NetworkInterfaces[i].instance = instance + nics = append(nics, &instance.NetworkInterfaces[i]) + } + return nics, nil +} + +func (instance *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + for _, networkinterface := range instance.NetworkInterfaces { + for _, conf := range networkinterface.AccessConfigs { + if len(conf.NatIP) > 0 { + eips, err := instance.host.zone.region.GetEips(conf.NatIP, 0, "") + if err != nil { + return nil, errors.Wrapf(err, "region.GetEip(%s)", conf.NatIP) + } + if len(eips) == 1 { + eips[0].region = instance.host.zone.region + return &eips[0], nil + } + eip := &SAddress{ + region: instance.host.zone.region, + Status: "IN_USE", + Address: conf.NatIP, + instanceId: instance.Id, + } + eip.Id = instance.Id + eip.SelfLink = instance.SelfLink + return eip, nil + } + } + } + return nil, nil +} + +func (instance *SInstance) GetVcpuCount() int { + instance.fetchMachineType() + return instance.guestCpus +} + +func (instance *SInstance) GetVmemSizeMB() int { + instance.fetchMachineType() + return instance.memoryMb +} + +func (instance *SInstance) GetBootOrder() string { + return "cdn" +} + +func (instance *SInstance) GetVga() string { + return "std" +} + +func (instance *SInstance) GetVdi() string { + return "vnc" +} + +func (instance *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(instance.getNormalizedOsInfo().OsType) +} + +func (instance *SInstance) getValidLicense() string { + for _, disk := range instance.Disks { + if disk.Index == 0 { + for _, license := range disk.Licenses { + if len(license) > 0 { + return license + } + } + } + } + return "" +} + +func (instance *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { + if instance.osInfo != nil { + return instance.osInfo + } + osinfo := imagetools.NormalizeImageInfo(instance.getValidLicense(), "", "", "", "") + instance.osInfo = &osinfo + return instance.osInfo +} + +func (instance *SInstance) GetFullOsName() string { + return instance.getValidLicense() +} + +func (instance *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(instance.getNormalizedOsInfo().OsBios) +} + +func (instance *SInstance) GetOsArch() string { + return instance.getNormalizedOsInfo().OsArch +} + +func (instance *SInstance) GetOsDist() string { + return instance.getNormalizedOsInfo().OsDistro +} + +func (instance *SInstance) GetOsVersion() string { + return instance.getNormalizedOsInfo().OsVersion +} + +func (instance *SInstance) GetOsLang() string { + return instance.getNormalizedOsInfo().OsLang +} + +func (instance *SInstance) GetMachine() string { + return "pc" +} + +func (instance *SInstance) GetInstanceType() string { + instance.fetchMachineType() + return instance.machineType +} + +func (instance *SInstance) AssignSecurityGroup(id string) error { + for _, secgrpType := range []string{SECGROUP_TYPE_TAG, SECGROUP_TYPE_SERVICE_ACCOUNT} { + if strings.Contains(id, fmt.Sprintf("/%s/", secgrpType)) { + idx := strings.LastIndex(id, "/") + 1 + if idx <= 0 { + return fmt.Errorf("invalid secgroup %s with id %s", secgrpType, id) + } + secgroup := id[idx:] + switch secgrpType { + case SECGROUP_TYPE_TAG: + tag := strings.ToLower(secgroup) + if !utils.IsInStringArray(tag, instance.Tags.Items) { + instance.Tags.Items = append(instance.Tags.Items, tag) + return instance.host.zone.region.SetResourceTags(instance.SelfLink, instance.Tags) + } + case SECGROUP_TYPE_SERVICE_ACCOUNT: + if len(instance.ServiceAccounts) > 0 { + return fmt.Errorf("instance %s has already set serviceAccount %s", instance.Name, instance.ServiceAccounts[0].Email) + } + return instance.host.zone.region.SetServiceAccount(instance.SelfLink, secgroup) + } + } + } + return fmt.Errorf("unknown secgroup type %s", id) +} + +func (instance *SInstance) GetSecurityGroupIds() ([]string, error) { + secgroupIds := []string{} + isecgroups := []cloudprovider.ICloudSecurityGroup{} + for _, networkinterface := range instance.NetworkInterfaces { + vpc := SVpc{region: instance.host.zone.region} + err := instance.host.zone.region.GetBySelfId(networkinterface.Subnetwork, &vpc) + if err != nil { + return nil, errors.Wrap(err, "GetGlobalNetwork") + } + _isecgroups, err := vpc.GetISecurityGroups() + if err != nil { + return nil, errors.Wrap(err, "vpc.GetISecurityGroups") + } + isecgroups = append(isecgroups, _isecgroups...) + for _, isecgroup := range _isecgroups { + if len(instance.ServiceAccounts) > 0 && isecgroup.GetName() == instance.ServiceAccounts[0].Email { + secgroupIds = append(secgroupIds, isecgroup.GetGlobalId()) + } + gvpcInfo := strings.Split(vpc.Network, "/") + gvpcName := gvpcInfo[len(gvpcInfo)-1] + if isecgroup.GetName() == gvpcName && !strings.Contains(isecgroup.GetGlobalId(), fmt.Sprintf("/%s/", SECGROUP_TYPE_TAG)) { + secgroupIds = append(secgroupIds, isecgroup.GetGlobalId()) + } + } + } + if len(instance.NetworkInterfaces) == 1 { + for _, secgroup := range isecgroups { + if utils.IsInStringArray(secgroup.GetName(), instance.Tags.Items) && strings.Contains(secgroup.GetGlobalId(), fmt.Sprintf("/%s/", SECGROUP_TYPE_TAG)) { + secgroupIds = append(secgroupIds, secgroup.GetGlobalId()) + } + } + } + return secgroupIds, nil +} + +func (instance *SInstance) SetSecurityGroups(ids []string) error { + secgroups := map[string][]string{} + for _, id := range ids { + for _, secgrpType := range []string{SECGROUP_TYPE_TAG, SECGROUP_TYPE_SERVICE_ACCOUNT} { + if strings.Contains(id, fmt.Sprintf("/%s/", secgrpType)) { + idx := strings.LastIndex(id, "/") + 1 + if idx <= 0 { + return fmt.Errorf("invalid secgroup %s with id %s", secgrpType, id) + } + secgroup := id[idx:] + if len(secgroup) == 0 { + return fmt.Errorf("invalid secgroup %s with id %s", secgrpType, id) + } + if _, ok := secgroups[secgrpType]; !ok { + secgroups[secgrpType] = []string{} + } + if !utils.IsInStringArray(secgroup, secgroups[secgrpType]) { + secgroups[secgrpType] = append(secgroups[secgrpType], secgroup) + } + } + } + } + if tags, ok := secgroups[SECGROUP_TYPE_TAG]; ok && len(tags) > 0 { + for _, tag := range tags { + tag = strings.ToLower(tag) + if !utils.IsInStringArray(tag, instance.Tags.Items) { + instance.Tags.Items = append(instance.Tags.Items, tag) + } + } + err := instance.host.zone.region.SetResourceTags(instance.SelfLink, instance.Tags) + if err != nil { + return errors.Wrap(err, "SetTags") + } + } + if serviceAccounts, ok := secgroups[SECGROUP_TYPE_SERVICE_ACCOUNT]; ok && len(serviceAccounts) > 0 { + if len(serviceAccounts) > 1 { + return fmt.Errorf("can not set multi service account for google instance") + } + return instance.host.zone.region.SetServiceAccount(instance.SelfLink, serviceAccounts[0]) + } + return nil +} + +func (instance *SInstance) GetHypervisor() string { + return api.HYPERVISOR_GOOGLE +} + +func (instance *SInstance) StartVM(ctx context.Context) error { + return instance.host.zone.region.StartInstance(instance.SelfLink) +} + +func (instance *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + return instance.host.zone.region.StopInstance(instance.SelfLink) +} + +func (instance *SInstance) DeleteVM(ctx context.Context) error { + return instance.host.zone.region.Delete(instance.SelfLink) +} + +func (instance *SInstance) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotSupported +} + +func (instance *SInstance) UpdateUserData(userData string) error { + items := []SMetadataItem{} + for _, item := range instance.Metadata.Items { + if item.Key != METADATA_STARTUP_SCRIPT && item.Key != METADATA_POWER_SHELL && item.Key != METADATA_STARTUP_SCRIPT_POWER_SHELL { + items = append(items, item) + } + } + if len(userData) > 0 { + items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT, Value: userData}) + items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT_POWER_SHELL, Value: userData}) + items = append(items, SMetadataItem{Key: METADATA_POWER_SHELL, Value: userData}) + } + instance.Metadata.Items = items + return instance.host.zone.region.SetMetadata(instance.SelfLink, instance.Metadata) +} + +func (instance *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + diskId, err := instance.host.zone.region.RebuildRoot(instance.Id, desc.ImageId, desc.SysSizeGB) + if err != nil { + return "", errors.Wrap(err, "region.RebuildRoot") + } + return diskId, instance.DeployVM(ctx, "", desc.Account, desc.Password, desc.PublicKey, false, "") +} + +func (instance *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + conf := cloudinit.SCloudConfig{} + user := cloudinit.NewUser(username) + if len(password) > 0 { + user.Password(password) + } + if len(publicKey) > 0 { + user.SshKey(publicKey) + } + if len(password) > 0 || len(publicKey) > 0 { + conf.MergeUser(user) + items := []SMetadataItem{} + instance.Refresh() + for _, item := range instance.Metadata.Items { + if item.Key != METADATA_STARTUP_SCRIPT_POWER_SHELL && item.Key != METADATA_STARTUP_SCRIPT { + items = append(items, item) + } + } + items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT_POWER_SHELL, Value: conf.UserDataPowerShell()}) + items = append(items, SMetadataItem{Key: METADATA_STARTUP_SCRIPT, Value: conf.UserDataScript()}) + instance.Metadata.Items = items + return instance.host.zone.region.SetMetadata(instance.SelfLink, instance.Metadata) + } + return nil +} + +func (instance *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + return instance.host.zone.region.ChangeInstanceConfig(instance.SelfLink, instance.host.zone.Name, config.InstanceType, config.Cpu, config.MemoryMB) +} + +func (instance *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (instance *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return instance.host.zone.region.AttachDisk(instance.SelfLink, diskId, false) +} + +func (instance *SInstance) DetachDisk(ctx context.Context, diskId string) error { + _disk, err := instance.host.zone.region.GetDisk(diskId) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return errors.Wrapf(err, "GetDisk(%s)", diskId) + } + for _, disk := range instance.Disks { + if disk.Source == _disk.SelfLink { + return instance.host.zone.region.DetachDisk(instance.SelfLink, disk.DeviceName) + } + } + return nil +} + +func (instance *SInstance) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (instance *SInstance) GetError() error { + return nil +} + +func getDiskInfo(disk string) (cloudprovider.SDiskInfo, error) { + result := cloudprovider.SDiskInfo{} + diskInfo := strings.Split(disk, ":") + for _, d := range diskInfo { + if utils.IsInStringArray(d, []string{api.STORAGE_GOOGLE_PD_STANDARD, api.STORAGE_GOOGLE_PD_SSD, api.STORAGE_GOOGLE_LOCAL_SSD, api.STORAGE_GOOGLE_PD_BALANCED}) { + result.StorageType = d + } else if memSize, err := fileutils.GetSizeMb(d, 'M', 1024); err == nil { + result.SizeGB = memSize >> 10 + } else { + result.Name = d + } + } + if len(result.StorageType) == 0 { + result.StorageType = api.STORAGE_GOOGLE_PD_STANDARD + } + + if result.SizeGB == 0 { + return result, fmt.Errorf("Missing disk size") + } + return result, nil +} + +func (region *SRegion) CreateInstance(zone, name, desc, instanceType string, cpu, memoryMb int, networkId string, ipAddr, imageId string, disks []string) (*SInstance, error) { + if len(instanceType) == 0 && (cpu == 0 || memoryMb == 0) { + return nil, fmt.Errorf("Missing instanceType or cpu &memory info") + } + if len(disks) == 0 { + return nil, fmt.Errorf("Missing disk info") + } + sysDisk, err := getDiskInfo(disks[0]) + if err != nil { + return nil, errors.Wrap(err, "getDiskInfo.sys") + } + dataDisks := []cloudprovider.SDiskInfo{} + for _, d := range disks[1:] { + dataDisk, err := getDiskInfo(d) + if err != nil { + return nil, errors.Wrapf(err, "getDiskInfo(%s)", d) + } + dataDisks = append(dataDisks, dataDisk) + } + conf := &cloudprovider.SManagedVMCreateConfig{ + Name: name, + Description: desc, + ExternalImageId: imageId, + Cpu: cpu, + MemoryMB: memoryMb, + ExternalNetworkId: networkId, + IpAddr: ipAddr, + SysDisk: sysDisk, + DataDisks: dataDisks, + } + return region._createVM(zone, conf) +} + +func (region *SRegion) getSecgroupByIds(ids []string) (map[string][]string, error) { + secgroups := map[string][]string{} + for _, id := range ids { + for _, secgrpType := range []string{SECGROUP_TYPE_TAG, SECGROUP_TYPE_SERVICE_ACCOUNT} { + if strings.Contains(id, fmt.Sprintf("/%s/", secgrpType)) { + idx := strings.LastIndex(id, "/") + 1 + if idx <= 0 { + return nil, fmt.Errorf("invalid secgroup %s for %s", id, secgrpType) + } + secgroup := id[idx:] + if len(secgroup) == 0 { + return nil, fmt.Errorf("invalid secgroup %s for %s", id, secgrpType) + } + if _, ok := secgroups[secgrpType]; !ok { + secgroups[secgrpType] = []string{} + } + if !utils.IsInStringArray(secgroup, secgroups[secgrpType]) { + secgroups[secgrpType] = append(secgroups[secgrpType], secgroup) + } + } + } + } + return secgroups, nil +} + +func (region *SRegion) _createVM(zone string, desc *cloudprovider.SManagedVMCreateConfig) (*SInstance, error) { + vpc, err := region.GetVpc(desc.ExternalNetworkId) + if err != nil { + return nil, errors.Wrap(err, "region.GetNetwork") + } + secgroups, err := region.getSecgroupByIds(desc.ExternalSecgroupIds) + if err != nil { + return nil, errors.Wrap(err, "getSecgroupByIds") + } + serviceAccounts, ok := secgroups[SECGROUP_TYPE_SERVICE_ACCOUNT] + if ok && len(serviceAccounts) > 1 { + return nil, fmt.Errorf("Security groups are distributed across multiple service accounts") + } + if len(desc.InstanceType) == 0 { + desc.InstanceType = fmt.Sprintf("custom-%d-%d", desc.Cpu, desc.MemoryMB) + } + disks := []map[string]interface{}{} + if len(desc.SysDisk.Name) == 0 { + desc.SysDisk.Name = fmt.Sprintf("vdisk-%s-%d", desc.Name, time.Now().UnixNano()) + } + nameConv := func(name string) string { + name = strings.Replace(name, "_", "-", -1) + name = pinyinutils.Text2Pinyin(name) + return strings.ToLower(name) + } + disks = append(disks, map[string]interface{}{ + "boot": true, + "initializeParams": map[string]interface{}{ + "diskName": nameConv(desc.SysDisk.Name), + "sourceImage": desc.ExternalImageId, + "diskSizeGb": desc.SysDisk.SizeGB, + "diskType": fmt.Sprintf("zones/%s/diskTypes/%s", zone, desc.SysDisk.StorageType), + }, + "autoDelete": true, + }) + for _, disk := range desc.DataDisks { + if len(disk.Name) == 0 { + disk.Name = fmt.Sprintf("vdisk-%s-%d", desc.Name, time.Now().UnixNano()) + } + disks = append(disks, map[string]interface{}{ + "boot": false, + "initializeParams": map[string]interface{}{ + "diskName": nameConv(disk.Name), + "diskSizeGb": disk.SizeGB, + "diskType": fmt.Sprintf("zones/%s/diskTypes/%s", zone, disk.StorageType), + }, + "autoDelete": true, + }) + } + networkInterface := map[string]string{ + "network": vpc.Network, + "subnetwork": vpc.SelfLink, + } + if len(desc.IpAddr) > 0 { + networkInterface["networkIp"] = desc.IpAddr + } + params := map[string]interface{}{ + "name": desc.NameEn, + "description": desc.Description, + "machineType": fmt.Sprintf("zones/%s/machineTypes/%s", zone, desc.InstanceType), + "networkInterfaces": []map[string]string{ + networkInterface, + }, + "disks": disks, + } + + labels := map[string]string{} + for k, v := range desc.Tags { + labels[encode.EncodeGoogleLabel(k)] = encode.EncodeGoogleLabel(v) + } + + if len(labels) > 0 { + params["labels"] = labels + } + + if tags, ok := secgroups[SECGROUP_TYPE_TAG]; ok && len(tags) > 0 { + for i := range tags { + tags[i] = strings.ToLower(tags[i]) + } + params["tags"] = map[string][]string{ + "items": tags, + } + } + if len(desc.UserData) > 0 { + params["metadata"] = map[string]interface{}{ + "items": []struct { + Key string + Value string + }{ + { + Key: METADATA_STARTUP_SCRIPT, + Value: desc.UserData, + }, + { + Key: METADATA_POWER_SHELL, + Value: desc.UserData, + }, + }, + } + } + if len(serviceAccounts) > 0 { + params["serviceAccounts"] = []struct { + Email string + Scopes []string + }{ + { + Email: serviceAccounts[0], + Scopes: []string{ + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + "https://www.googleapis.com/auth/servicecontrol", + "https://www.googleapis.com/auth/service.management.readonly", + "https://www.googleapis.com/auth/trace.append", + }, + }, + } + } + log.Debugf("create google instance params: %s", jsonutils.Marshal(params).String()) + instance := &SInstance{} + resource := fmt.Sprintf("zones/%s/instances", zone) + err = region.Insert(resource, jsonutils.Marshal(params), instance) + if err != nil { + return nil, err + } + return instance, nil +} + +func (region *SRegion) StartInstance(id string) error { + params := map[string]string{} + return region.Do(id, "start", nil, jsonutils.Marshal(params)) +} + +func (region *SRegion) StopInstance(id string) error { + params := map[string]string{} + return region.Do(id, "stop", nil, jsonutils.Marshal(params)) +} + +func (region *SRegion) ResetInstance(id string) error { + params := map[string]string{} + return region.Do(id, "reset", nil, jsonutils.Marshal(params)) +} + +func (region *SRegion) DetachDisk(instanceId, deviceName string) error { + body := map[string]string{} + params := map[string]string{"deviceName": deviceName} + return region.Do(instanceId, "detachDisk", params, jsonutils.Marshal(body)) +} + +func (instance *SInstance) GetSerialOutput(port int) (string, error) { + return instance.host.zone.region.GetSerialPortOutput(instance.SelfLink, port) +} + +func (region *SRegion) GetSerialPortOutput(id string, port int) (string, error) { + _content, content, next := "", "", 0 + var err error = nil + for { + _content, next, err = region.getSerialPortOutput(id, port, next) + if err != nil { + return content, err + } + content += _content + if len(_content) == 0 { + break + } + } + return content, nil +} + +func (region *SRegion) getSerialPortOutput(id string, port int, start int) (string, int, error) { + resource := fmt.Sprintf("%s/serialPort?port=%d&start=%d", id, port, start) + result := struct { + Contents string + Start int + Next int + }{} + err := region.GetBySelfId(resource, &result) + if err != nil { + return "", result.Next, errors.Wrap(err, "") + } + return result.Contents, result.Next, nil +} + +func (self *SRegion) AttachDisk(instanceId, diskId string, boot bool) error { + disk, err := self.GetDisk(diskId) + if err != nil { + return errors.Wrapf(err, "GetDisk(%s)", diskId) + } + body := map[string]interface{}{ + "source": disk.SelfLink, + "boot": boot, + } + if boot { + body["autoDelete"] = true + } + params := map[string]string{} + return self.Do(instanceId, "attachDisk", params, jsonutils.Marshal(body)) +} + +func (region *SRegion) ChangeInstanceConfig(id string, zone string, instanceType string, cpu int, memoryMb int) error { + if len(instanceType) == 0 { + instanceType = fmt.Sprintf("custom-%d-%d", cpu, memoryMb) + } + params := map[string]string{ + "machineType": fmt.Sprintf("zones/%s/machineTypes/%s", zone, instanceType), + } + return region.Do(id, "setMachineType", nil, jsonutils.Marshal(params)) +} + +func (region *SRegion) SetMetadata(id string, metadata SMetadata) error { + return region.Do(id, "setMetadata", nil, jsonutils.Marshal(metadata)) +} + +func (region *SRegion) SetResourceTags(id string, tags SInstanceTag) error { + return region.Do(id, "setTags", nil, jsonutils.Marshal(tags)) +} + +func (region *SRegion) SetServiceAccount(id string, email string) error { + body := map[string]interface{}{ + "email": email, + "scopes": []string{ + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + "https://www.googleapis.com/auth/servicecontrol", + "https://www.googleapis.com/auth/service.management.readonly", + "https://www.googleapis.com/auth/trace.append", + }, + } + return region.Do(id, "setsetServiceAccount", nil, jsonutils.Marshal(body)) +} + +func (region *SRegion) RebuildRoot(instanceId string, imageId string, sysDiskSizeGb int) (string, error) { + oldDisk, diskType, deviceName := "", api.STORAGE_GOOGLE_PD_STANDARD, "" + instance, err := region.GetInstance(instanceId) + if err != nil { + return "", errors.Wrap(err, "region.GetInstance") + } + for _, disk := range instance.Disks { + if disk.Boot { + oldDisk = disk.Source + deviceName = disk.DeviceName + break + } + } + + if len(oldDisk) > 0 { + disk := &SDisk{} + err := region.GetBySelfId(oldDisk, disk) + if err != nil { + return "", errors.Wrap(err, "region.GetDisk") + } + diskType = disk.Type + if sysDiskSizeGb == 0 { + sysDiskSizeGb = disk.SizeGB + } + } + + zone, err := region.GetZone(instance.Zone) + if err != nil { + return "", errors.Wrap(err, "region.GetZone") + } + + diskName := fmt.Sprintf("vdisk-%s-%d", instance.Name, time.Now().UnixNano()) + disk, err := region.CreateDisk(diskName, sysDiskSizeGb, zone.Name, diskType, imageId, "create for replace instance system disk") + if err != nil { + return "", errors.Wrap(err, "region.CreateDisk.systemDisk") + } + + if len(deviceName) > 0 { + err = region.DetachDisk(instance.SelfLink, deviceName) + if err != nil { + defer region.Delete(disk.SelfLink) + return "", errors.Wrap(err, "region.DetachDisk") + } + } + + err = region.AttachDisk(instance.SelfLink, disk.Id, true) + if err != nil { + if len(oldDisk) > 0 { + defer region.AttachDisk(instance.SelfLink, oldDisk, true) + } + defer region.Delete(disk.SelfLink) + return "", errors.Wrap(err, "region.AttachDisk.newSystemDisk") + } + + if len(oldDisk) > 0 { + defer region.Delete(oldDisk) + } + return disk.GetGlobalId(), nil +} + +func (self *SRegion) SaveImage(diskId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { + params := map[string]interface{}{ + "name": opts.Name, + "description": opts.Notes, + "sourceDisk": diskId, + } + image := &SImage{} + err := self.Insert("global/images", jsonutils.Marshal(params), image) + if err != nil { + return nil, errors.Wrapf(err, "Insert") + } + image.storagecache = self.getStoragecache() + return image, nil +} + +func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { + for i := range self.Disks { + if self.Disks[0].Index == 0 { + image, err := self.host.zone.region.SaveImage(self.Disks[i].Source, opts) + if err != nil { + return nil, errors.Wrapf(err, "SaveImage") + } + return image, nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "no valid system disk found") +} + +func (region *SRegion) SetLabels(id string, _labels map[string]string, labelFingerprint string) error { + labels := map[string]string{} + for k, v := range _labels { + labels[encode.EncodeGoogleLabel(k)] = encode.EncodeGoogleLabel(v) + } + params := map[string]interface{}{ + "labels": labels, + "labelFingerprint": labelFingerprint, + } + err := region.Do(id, "setLabels", nil, jsonutils.Marshal(params)) + if err != nil { + return errors.Wrapf(err, `region.Do(%s, "setLabels", nil, %s)`, id, jsonutils.Marshal(params).String()) + } + return nil +} + +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { + if !replace { + oldTags, _ := self.GetTags() + for k, v := range oldTags { + if _, ok := tags[k]; !ok { + tags[k] = v + } + } + } + err := self.Refresh() + if err != nil { + return errors.Wrap(err, "self.Refresh()") + } + err = self.host.zone.region.SetLabels(self.SelfLink, tags, self.LabelFingerprint) + if err != nil { + return errors.Wrapf(err, ` self.host.zone.region.SsetLabels()`) + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/instancenic.go new file mode 100644 index 0000000000..5b435ace82 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/instancenic.go @@ -0,0 +1,65 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "yunion.io/x/pkg/util/netutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SNetworkInterface struct { + instance *SInstance + + Network string + Subnetwork string + NetworkIP string + Name string + AccessConfigs []AccessConfig + Fingerprint string + Kind string + + cloudprovider.DummyICloudNic +} + +func (nic *SNetworkInterface) GetId() string { + return "" +} + +func (nic *SNetworkInterface) GetIP() string { + return nic.NetworkIP +} + +func (nic *SNetworkInterface) GetMAC() string { + ip, _ := netutils.NewIPV4Addr(nic.NetworkIP) + return ip.ToMac("42:01:") +} + +func (nic *SNetworkInterface) GetDriver() string { + return "virtio" +} + +func (nic *SNetworkInterface) InClassicNetwork() bool { + return false +} + +func (nic *SNetworkInterface) GetINetworkId() string { + vpc := &SVpc{region: nic.instance.host.zone.region} + err := nic.instance.host.zone.region.GetBySelfId(nic.Subnetwork, vpc) + if err != nil { + return "" + } + return vpc.Id +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/latitude_and_longitude.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/latitude_and_longitude.go new file mode 100644 index 0000000000..00de2a6e30 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/latitude_and_longitude.go @@ -0,0 +1,97 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ + "asia-east1": api.RegionTaiwan, + "asia-east2": api.RegionHongkong, + "asia-northeast1": api.RegionTokyo, + "asia-northeast2": api.RegionOsaka, + "asia-northeast3": api.RegionSeoul, + "asia-south1": api.RegionMumbai, + "asia-south2": api.RegionDelhi, + "asia-southeast1": api.RegionSingapore, + "asia-southeast2": api.RegionJakarta, + "australia-southeast1": api.RegionSydney, + "australia-southeast2": api.RegionMelbourne, + + "europe-north1": api.RegionFinland, + "europe-west1": api.RegionBelgium, + "europe-west2": api.RegionLondon, + "europe-west3": api.RegionFrankfurt, + "europe-west4": api.RegionHolland, + "europe-west6": api.RegionZurich, + "europe-central2": api.RegionWarsaw, + + "northamerica-northeast1": api.RegionMontreal, + "northamerica-northeast2": api.RegionToronto, + "southamerica-east1": api.RegionSaoPaulo, + "us-central1": api.RegionIowa, + "us-east1": api.RegionCarolina, + "us-east4": api.RegionNothVirginia, + "us-west1": api.RegionOregon, + "us-west2": api.RegionLosAngeles, + "us-west3": api.RegionSaltLakeCity, + "us-west4": api.RegionLasVegas, + "southamerica-west1": api.RegionSantiago, +} + +var RegionNames = map[string]string{ + "asia-east1": "台湾", + "asia-east2": "香港", + "asia-northeast1": "东京", + "asia-northeast2": "大阪", + "asia-northeast3": "首尔", + "asia-south1": "孟买", + "asia-south2": "德里", + "asia-southeast1": "新加坡", + "asia-southeast2": "雅加达", + "australia-southeast1": "悉尼", + "australia-southeast2": "墨尔本", + + "europe-north1": "芬兰", + "europe-west1": "比利时", + "europe-west2": "伦敦", + "europe-west3": "法兰克福", + "europe-west4": "荷兰", + "europe-west6": "苏黎世", + "europe-central2": "华沙", + + "northamerica-northeast1": "蒙特利尔", + "northamerica-northeast2": "多伦多", + "southamerica-east1": "圣保罗", + "southamerica-west1": "圣地亚哥", + "us-central1": "爱荷华", + "us-east1": "南卡罗来纳州", + "us-east4": "北弗吉尼亚", + "us-west1": "俄勒冈州", + "us-west2": "洛杉矶", + "us-west3": "盐湖城", + "us-west4": "拉斯维加斯", + + // Multi-region + "us": "美国的多区域", + "eu": "欧盟的多区域", + "asia": "亚洲的多区域", + + // Dual-region + "nam4": "爱荷华和南卡罗来纳", + "eur4": "荷兰和芬兰", +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer.go new file mode 100644 index 0000000000..0484582a00 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer.go @@ -0,0 +1,480 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +// 全球负载均衡 https://cloud.google.com/compute/docs/reference/rest/v1/globalAddresses/list +// 区域负载均衡 https://cloud.google.com/compute/docs/reference/rest/v1/addresses +// https://cloud.google.com/compute/docs/reference/rest/v1/targetHttpProxies/get +// https://cloud.google.com/compute/docs/reference/rest/v1/targetGrpcProxies/get +// https://cloud.google.com/compute/docs/reference/rest/v1/targetHttpsProxies/get +// https://cloud.google.com/compute/docs/reference/rest/v1/targetSslProxies/get +// https://cloud.google.com/compute/docs/reference/rest/v1/targetTcpProxies/get + +type SLoadbalancer struct { + SResourceBase + region *SRegion + urlMap *SUrlMap // http & https LB + backendServices []SBackendServices // tcp & udp LB. 或者 http & https 后端 + instanceGroups []SInstanceGroup + healthChecks []HealthChecks + + forwardRules []SForwardingRule // 服务IP地址 + isHttpLb bool // 标记是否为http/https lb +} + +func (self *SLoadbalancer) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancer) Refresh() error { + lb, err := self.region.GetLoadbalancer(self.GetGlobalId()) + if err != nil { + return errors.Wrap(err, "GetLoadbalancer") + } + + err = jsonutils.Update(self, &lb) + if err != nil { + return errors.Wrap(err, "Refresh.Update") + } + + self.healthChecks = nil + self.instanceGroups = nil + self.forwardRules = nil + if self.isHttpLb { + bss, err := self.GetBackendServices() + if err != nil { + return errors.Wrap(err, "GetForwardingRules") + } + self.backendServices = bss + } + return nil +} + +func (self *SLoadbalancer) IsEmulated() bool { + return true +} + +func (self *SLoadbalancer) GetSysTags() map[string]string { + frs, err := self.GetForwardingRules() + if err != nil { + return nil + } + + ips := []string{} + for i := range frs { + if len(frs[i].IPAddress) > 0 { + ips = append(ips, frs[i].IPAddress) + } + } + data := map[string]string{} + data["FrontendIPs"] = strings.Join(ips, ",") + return data +} + +func (self *SLoadbalancer) GetTags() (map[string]string, error) { + return map[string]string{}, nil +} + +func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SLoadbalancer) GetProjectId() string { + return self.region.GetProjectId() +} + +/* +对应forwardingRules地址,存在多个前端IP的情况下,只展示按拉丁字母排序最前的一个地址。其他地址需要到详情中查看 +External +Internal +InternalManaged +InternalSelfManaged +Invalid +UndefinedLoadBalancingScheme +*/ +func (self *SLoadbalancer) GetAddress() string { + frs, err := self.GetForwardingRules() + if err != nil { + log.Errorf("GetAddress.GetForwardingRules %s", err) + } + + for i := range frs { + sche := strings.ToLower(frs[i].LoadBalancingScheme) + if !utils.IsInStringArray(sche, []string{"invalid", "undefinedloadbalancingscheme"}) { + return frs[i].IPAddress + } + } + + return "" +} + +func (self *SLoadbalancer) GetAddressType() string { + frs, err := self.GetForwardingRules() + if err != nil { + return api.LB_ADDR_TYPE_INTRANET + } + + for i := range frs { + sche := strings.ToLower(frs[i].LoadBalancingScheme) + if !utils.IsInStringArray(sche, []string{"invalid", "undefinedloadbalancingscheme"}) { + if sche == "external" { + return api.LB_ADDR_TYPE_INTERNET + } else { + return api.LB_ADDR_TYPE_INTRANET + } + } + } + + return api.LB_ADDR_TYPE_INTERNET +} + +func (self *SLoadbalancer) GetNetworkType() string { + return api.LB_NETWORK_TYPE_VPC +} + +func (self *SLoadbalancer) GetNetworkIds() []string { + igs, err := self.GetInstanceGroups() + if err != nil { + log.Errorf("GetInstanceGroups %s", err) + return nil + } + + selfLinks := make([]string, 0) + networkIds := make([]string, 0) + for i := range igs { + if utils.IsInStringArray(igs[i].Subnetwork, selfLinks) { + selfLinks = append(selfLinks, igs[i].Subnetwork) + network := SResourceBase{ + Name: "", + SelfLink: igs[i].Network, + } + networkIds = append(networkIds, network.GetGlobalId()) + } + } + + return networkIds +} + +func (self *SLoadbalancer) GetVpcId() string { + networkIds := self.GetNetworkIds() + if len(networkIds) == 0 { + return "" + } + if len(networkIds) >= 1 { + vpc, err := self.region.GetVpc(networkIds[0]) + if err == nil && vpc != nil { + return vpc.GetGlobalId() + } + } + return "" +} + +func (self *SLoadbalancer) GetZoneId() string { + igs, err := self.GetInstanceGroups() + if err != nil { + log.Errorf("GetInstanceGroups %s", err) + return "" + } + + for i := range igs { + if len(igs[i].Zone) > 0 { + zone := SResourceBase{ + Name: "", + SelfLink: igs[i].Zone, + } + + return zone.GetGlobalId() + } + } + + return "" +} + +func (self *SLoadbalancer) GetZone1Id() string { + return "" +} + +func (self *SLoadbalancer) GetLoadbalancerSpec() string { + if self.isHttpLb { + return "regional_http_lb" + } + + return fmt.Sprintf("regional_%s", strings.ToLower(self.backendServices[0].Protocol)) +} + +func (self *SLoadbalancer) GetChargeType() string { + return api.LB_CHARGE_TYPE_BY_TRAFFIC +} + +func (self *SLoadbalancer) GetEgressMbps() int { + return 0 +} + +func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { + frs, err := self.GetForwardingRules() + if err != nil { + log.Errorf("GetAddress.GetForwardingRules %s", err) + } + + for i := range frs { + if strings.ToLower(frs[i].LoadBalancingScheme) == "external" { + eips, err := self.region.GetEips(frs[i].IPAddress, 0, "") + if err != nil { + log.Errorf("GetEips %s", err) + } + + if len(eips) > 0 { + return &eips[0], nil + } + } + } + + return nil, nil +} + +func (self *SLoadbalancer) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SLoadbalancer) Start() error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) Stop() error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + lbls, err := self.GetLoadbalancerListeners() + if err != nil { + return nil, errors.Wrap(err, "GetLoadbalancerListeners") + } + + ilbls := make([]cloudprovider.ICloudLoadbalancerListener, len(lbls)) + for i := range lbls { + ilbls[i] = &lbls[i] + } + + return ilbls, nil +} + +func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + lbbgs, err := self.GetLoadbalancerBackendGroups() + if err != nil { + return nil, errors.Wrap(err, "GetLoadbalancerBackendGroups") + } + + ilbbgs := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(lbbgs)) + for i := range lbbgs { + ilbbgs[i] = &lbbgs[i] + } + + return ilbbgs, nil +} + +func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + lbbgs, err := self.GetLoadbalancerBackendGroups() + if err != nil { + return nil, errors.Wrap(err, "GetLoadbalancerBackendGroups") + } + + for i := range lbbgs { + if lbbgs[i].GetGlobalId() == groupId { + return &lbbgs[i], nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { + lbls, err := self.GetLoadbalancerListeners() + if err != nil { + return nil, errors.Wrap(err, "GetLoadbalancerBackendGroups") + } + + for i := range lbls { + if lbls[i].GetGlobalId() == listenerId { + return &lbls[i], nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +// GET https://compute.googleapis.com/compute/v1/projects/{project}/aggregated/targetHttpProxies 前端监听 +// tcp lb backend type: backend service +func (self *SRegion) GetRegionalTcpLoadbalancers() ([]SLoadbalancer, error) { + bss, err := self.GetRegionalBackendServices("protocol eq TCP") + if err != nil { + return nil, errors.Wrap(err, "GetRegionalBackendServices") + } + + lbs := make([]SLoadbalancer, len(bss)) + for i := range bss { + lbs[i] = SLoadbalancer{ + region: self, + SResourceBase: SResourceBase{ + Name: bss[i].Name, + SelfLink: bss[i].SelfLink, + }, + urlMap: nil, + backendServices: []SBackendServices{bss[i]}, + forwardRules: nil, + } + } + + return lbs, nil +} + +// udp lb backend type: backend service +func (self *SRegion) GetRegionalUdpLoadbalancers() ([]SLoadbalancer, error) { + bss, err := self.GetRegionalBackendServices("protocol eq UDP") + if err != nil { + return nil, errors.Wrap(err, "GetRegionalBackendServices") + } + + lbs := make([]SLoadbalancer, len(bss)) + for i := range bss { + lbs[i] = SLoadbalancer{ + region: self, + SResourceBase: SResourceBase{ + Name: bss[i].Name, + SelfLink: bss[i].SelfLink, + }, + urlMap: nil, + backendServices: []SBackendServices{bss[i]}, + forwardRules: nil, + } + } + + return lbs, nil +} + +// http&https lb: urlmaps +func (self *SRegion) GetRegionalHTTPLoadbalancers() ([]SLoadbalancer, error) { + ums, err := self.GetRegionalUrlMaps("") + if err != nil { + return nil, errors.Wrap(err, "GetRegionalUrlMaps") + } + + lbs := make([]SLoadbalancer, len(ums)) + for i := range ums { + lbs[i] = SLoadbalancer{ + region: self, + SResourceBase: SResourceBase{ + Name: ums[i].Name, + SelfLink: ums[i].SelfLink, + }, + urlMap: &ums[i], + backendServices: nil, + forwardRules: nil, + isHttpLb: true, + } + } + + return lbs, nil +} + +func (self *SRegion) GetRegionalLoadbalancers() ([]SLoadbalancer, error) { + lbs := make([]SLoadbalancer, 0) + funcs := []func() ([]SLoadbalancer, error){self.GetRegionalHTTPLoadbalancers, self.GetRegionalTcpLoadbalancers, self.GetRegionalUdpLoadbalancers} + for i := range funcs { + _lbs, err := funcs[i]() + if err != nil { + return nil, errors.Wrap(err, "GetRegionalLoadbalancers") + } + lbs = append(lbs, _lbs...) + } + + return lbs, nil +} + +func (self *SRegion) GetLoadbalancer(resourceId string) (SLoadbalancer, error) { + lb := SLoadbalancer{} + var err error + if strings.Contains(resourceId, "/urlMaps/") { + ret := SUrlMap{} + err = self.GetBySelfId(resourceId, &ret) + lb.isHttpLb = true + lb.urlMap = &ret + lb.SResourceBase = SResourceBase{ + Name: ret.Name, + SelfLink: ret.SelfLink, + } + } else { + ret := SBackendServices{} + err = self.GetBySelfId(resourceId, &ret) + lb.backendServices = []SBackendServices{ret} + lb.SResourceBase = SResourceBase{ + Name: ret.Name, + SelfLink: ret.SelfLink, + } + } + + if err != nil { + return lb, errors.Wrapf(err, "get") + } + + lb.region = self + return lb, nil +} + +func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + lbs, err := self.GetRegionalLoadbalancers() + if err != nil { + return nil, errors.Wrap(err, "GetRegionalLoadbalancers") + } + ilbs := []cloudprovider.ICloudLoadbalancer{} + for i := range lbs { + ilbs = append(ilbs, &lbs[i]) + } + return ilbs, nil +} + +func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { + lb, err := self.GetLoadbalancer(loadbalancerId) + if err != nil { + return nil, errors.Wrap(err, "GetLoadbalancer") + } + return &lb, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_backend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_backend.go new file mode 100644 index 0000000000..d192be8d81 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_backend.go @@ -0,0 +1,205 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SLoadbalancerBackend struct { + lbbg *SLoadBalancerBackendGroup + + backendService SBackendServices // + instanceGroup SInstanceGroup // 实例组 + Backend SInstanceGroupInstance // backend + + Port int `json:"port"` +} + +func (self *SLoadbalancerBackend) GetId() string { + return fmt.Sprintf("%s::%s::%s::%d", self.lbbg.GetGlobalId(), self.instanceGroup.GetGlobalId(), self.GetBackendId(), self.Port) +} + +func (self *SLoadbalancerBackend) GetName() string { + segs := strings.Split(self.Backend.Instance, "/") + name := "" + if len(segs) > 0 { + name = segs[len(segs)-1] + } + return fmt.Sprintf("%s::%s::%d", self.instanceGroup.GetName(), name, self.Port) +} + +func (self *SLoadbalancerBackend) GetGlobalId() string { + return self.GetId() +} + +func (self *SLoadbalancerBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancerBackend) Refresh() error { + return nil +} + +func (self *SLoadbalancerBackend) IsEmulated() bool { + return true +} + +func (self *SLoadbalancerBackend) GetSysTags() map[string]string { + return nil +} + +func (self *SLoadbalancerBackend) GetTags() (map[string]string, error) { + return nil, nil +} + +func (self *SLoadbalancerBackend) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancerBackend) GetProjectId() string { + return self.lbbg.GetProjectId() +} + +func (self *SLoadbalancerBackend) GetWeight() int { + return 0 +} + +func (self *SLoadbalancerBackend) GetPort() int { + return self.Port +} + +func (self *SLoadbalancerBackend) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SLoadbalancerBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (self *SLoadbalancerBackend) GetBackendRole() string { + return api.LB_BACKEND_ROLE_DEFAULT +} + +func (self *SLoadbalancerBackend) GetBackendId() string { + r := SResourceBase{ + Name: "", + SelfLink: self.Backend.Instance, + } + return r.GetGlobalId() +} + +func (self *SLoadbalancerBackend) GetIpAddress() string { + return "" +} + +func (self *SLoadbalancerBackend) SyncConf(ctx context.Context, port, weight int) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadBalancerBackendGroup) GetLoadbalancerBackends() ([]SLoadbalancerBackend, error) { + if self.backends != nil { + return self.backends, nil + } + + _igs, err := self.lb.GetInstanceGroupsMap() + if err != nil { + return nil, errors.Wrap(err, "GetInstanceGroupsMap") + } + + igs := make([]SInstanceGroup, 0) + for i := range self.backendService.Backends { + backend := self.backendService.Backends[i] + if v, ok := _igs[backend.Group]; ok { + igs = append(igs, v) + } + } + + ret := make([]SLoadbalancerBackend, 0) + for i := range igs { + ig := igs[i] + // http lb + if self.lb.isHttpLb { + for j := range ig.NamedPorts { + np := ig.NamedPorts[j] + if np.Name != self.backendService.PortName { + continue + } + + bs, err := ig.GetInstances() + if err != nil { + return nil, errors.Wrap(err, "GetInstances") + } + + for n := range bs { + backend := SLoadbalancerBackend{ + lbbg: self, + backendService: self.backendService, + instanceGroup: ig, + Backend: bs[n], + Port: int(np.Port), + } + + ret = append(ret, backend) + } + } + } else { + // tcp & udp lb + bs, err := ig.GetInstances() + if err != nil { + return nil, errors.Wrap(err, "GetInstances") + } + + frs, err := self.lb.GetForwardingRules() + if err != nil { + return nil, errors.Wrap(err, "GetForwardingRules") + } + + for m := range frs { + fr := frs[m] + for p := range fr.Ports { + port, _ := strconv.Atoi(fr.Ports[p]) + if port <= 0 { + continue + } + + for n := range bs { + backend := SLoadbalancerBackend{ + lbbg: self, + backendService: self.backendService, + instanceGroup: ig, + Backend: bs[n], + Port: port, + } + + ret = append(ret, backend) + } + } + } + } + } + + self.backends = ret + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_backendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_backendgroup.go new file mode 100644 index 0000000000..9a9e1ee0e5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_backendgroup.go @@ -0,0 +1,173 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "context" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SLoadBalancerBackendGroup struct { + lb *SLoadbalancer + backends []SLoadbalancerBackend + + backendService SBackendServices // + + Id string `json:"id"` + Name string `json:"name"` +} + +func (self *SLoadBalancerBackendGroup) GetId() string { + return self.Id +} + +func (self *SLoadBalancerBackendGroup) GetName() string { + return self.Name +} + +func (self *SLoadBalancerBackendGroup) GetGlobalId() string { + return self.backendService.GetGlobalId() +} + +func (self *SLoadBalancerBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadBalancerBackendGroup) Refresh() error { + return nil +} + +func (self *SLoadBalancerBackendGroup) IsEmulated() bool { + return true +} + +func (self *SLoadBalancerBackendGroup) GetSysTags() map[string]string { + return nil +} + +func (self *SLoadBalancerBackendGroup) GetTags() (map[string]string, error) { + return nil, nil +} + +func (self *SLoadBalancerBackendGroup) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadBalancerBackendGroup) GetProjectId() string { + return self.lb.GetProjectId() +} + +func (self *SLoadBalancerBackendGroup) IsDefault() bool { + return false +} + +func (self *SLoadBalancerBackendGroup) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SLoadBalancerBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_NORMAL +} + +func (self *SLoadBalancerBackendGroup) GetLoadbalancerId() string { + return self.lb.GetGlobalId() +} + +func (self *SLoadBalancerBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := self.GetLoadbalancerBackends() + if err != nil { + return nil, errors.Wrap(err, "GetLoadbalancerBackends") + } + + ibackends := make([]cloudprovider.ICloudLoadbalancerBackend, len(backends)) + for i := range backends { + ibackends[i] = &backends[i] + } + + return ibackends, nil +} + +func (self *SLoadBalancerBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := self.GetLoadbalancerBackends() + if err != nil { + return nil, errors.Wrap(err, "GetLoadbalancerBackends") + } + + for i := range backends { + if backends[i].GetGlobalId() == backendId { + return &backends[i], nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SLoadBalancerBackendGroup) GetProtocolType() string { + return "" +} + +func (self *SLoadBalancerBackendGroup) GetScheduler() string { + return "" +} + +func (self *SLoadBalancerBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + return nil, nil +} + +func (self *SLoadBalancerBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + return nil, nil +} + +func (self *SLoadBalancerBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SLoadBalancerBackendGroup) RemoveBackendServer(serverId string, weight int, port int) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadBalancerBackendGroup) Delete(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadBalancerBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetLoadbalancerBackendGroups() ([]SLoadBalancerBackendGroup, error) { + bss, err := self.GetBackendServices() + if err != nil { + return nil, errors.Wrap(err, "GetBackendServices") + } + + ret := make([]SLoadBalancerBackendGroup, 0) + for i := range bss { + group := SLoadBalancerBackendGroup{ + lb: self, + backendService: bss[i], + Id: bss[i].GetId(), + Name: bss[i].GetName(), + } + + ret = append(ret, group) + } + + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_cert.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_cert.go new file mode 100644 index 0000000000..65965a71a4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_cert.go @@ -0,0 +1,172 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "crypto/sha256" + "crypto/x509" + "encoding/hex" + "encoding/pem" + "strings" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SLoadbalancerCertificate struct { + region *SRegion + SResourceBase + cert *x509.Certificate + + ID string `json:"id"` + CreationTimestamp string `json:"creationTimestamp"` + Certificate string `json:"certificate"` + SelfManaged SelfManaged `json:"selfManaged"` + Type string `json:"type"` + ExpireTime time.Time `json:"expireTime"` + Region string `json:"region"` + Kind string `json:"kind"` +} + +type SelfManaged struct { + Certificate string `json:"certificate"` +} + +func (self *SLoadbalancerCertificate) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancerCertificate) Refresh() error { + return nil +} + +func (self *SLoadbalancerCertificate) IsEmulated() bool { + return false +} + +func (self *SLoadbalancerCertificate) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SLoadbalancerCertificate) GetSysTags() map[string]string { + return nil +} + +func (self *SLoadbalancerCertificate) GetTags() (map[string]string, error) { + return nil, nil +} + +func (self *SLoadbalancerCertificate) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancerCertificate) GetProjectId() string { + return self.region.GetProjectId() +} + +func (self *SLoadbalancerCertificate) Sync(name, privateKey, publickKey string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancerCertificate) Delete() error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancerCertificate) GetCommonName() string { + c := self.getCert() + if c == nil { + return "" + } + return c.Subject.CommonName +} + +func (self *SLoadbalancerCertificate) GetSubjectAlternativeNames() string { + c := self.getCert() + if c == nil { + return "" + } + + names := []string{} + for i := range c.Extensions { + names = append(names, string(c.Extensions[i].Value)) + } + + return strings.Join(names, ",") +} + +func (self *SLoadbalancerCertificate) getCert() *x509.Certificate { + if self.cert != nil { + return self.cert + } + + p, _ := pem.Decode([]byte(self.Certificate)) + c, err := x509.ParseCertificate(p.Bytes) + if err != nil { + log.Errorf("get certificate %s(%s): %s", self.Name, self.GetId(), err) + return nil + } + + self.cert = c + return c +} + +func (self *SLoadbalancerCertificate) GetFingerprint() string { + c := self.getCert() + if c == nil { + return "" + } + d := sha256.Sum256(c.Raw) + return api.LB_TLS_CERT_FINGERPRINT_ALGO_SHA256 + ":" + hex.EncodeToString(d[:]) +} + +func (self *SLoadbalancerCertificate) GetExpireTime() time.Time { + return self.ExpireTime +} + +func (self *SLoadbalancerCertificate) GetPublickKey() string { + return "" +} + +func (self *SLoadbalancerCertificate) GetPrivateKey() string { + return "" +} + +func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + certs, err := self.GetRegionalSslCertificates("") + if err != nil { + return nil, errors.Wrap(err, "GetRegionalSslCertificates") + } + + icerts := make([]cloudprovider.ICloudLoadbalancerCertificate, len(certs)) + for i := range certs { + icerts[i] = &certs[i] + } + + return icerts, nil +} + +func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + ret := SLoadbalancerCertificate{} + err := self.GetBySelfId(certId, &ret) + if err != nil { + return nil, errors.Wrap(err, "Get") + } + ret.region = self + return &ret, nil +} diff --git a/pkg/multicloud/google/loadbalancer_components.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_components.go similarity index 99% rename from pkg/multicloud/google/loadbalancer_components.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_components.go index f5bcc88401..b028f2e413 100644 --- a/pkg/multicloud/google/loadbalancer_components.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_components.go @@ -21,7 +21,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SUrlMap struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_listener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_listener.go new file mode 100644 index 0000000000..05a20234d9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_listener.go @@ -0,0 +1,596 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SLoadbalancerListener struct { + lb *SLoadbalancer + rules []SLoadbalancerListenerRule + forwardRule SForwardingRule // 服务IP地址 + backendService SBackendServices // + httpProxy *STargetHttpProxy // http + httpsProxy *STargetHttpsProxy // https + healthChecks []HealthChecks + + ForwardRuleName string `json:"forward_rule_name"` + BackendServiceName string `json:"backend_service_name"` + Protocol string `json:"protocol"` + Port string `json:"port"` // 监听端口 +} + +func (self *SLoadbalancerListener) GetId() string { + return fmt.Sprintf("%s::%s::%s", self.forwardRule.GetGlobalId(), self.backendService.GetGlobalId(), self.Port) +} + +func (self *SLoadbalancerListener) GetName() string { + return fmt.Sprintf("%s::%s::%s", self.forwardRule.GetName(), self.backendService.GetName(), self.Port) +} + +func (self *SLoadbalancerListener) GetGlobalId() string { + return self.GetId() +} + +func (self *SLoadbalancerListener) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancerListener) Refresh() error { + return nil +} + +func (self *SLoadbalancerListener) IsEmulated() bool { + return true +} + +func (self *SLoadbalancerListener) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SLoadbalancerListener) GetSysTags() map[string]string { + return nil +} + +func (self *SLoadbalancerListener) GetTags() (map[string]string, error) { + if len(self.forwardRule.IPAddress) > 0 { + return map[string]string{"FrontendIP": self.forwardRule.IPAddress}, nil + } + + return map[string]string{}, nil +} + +func (self *SLoadbalancerListener) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancerListener) GetProjectId() string { + return self.lb.GetProjectId() +} + +func (self *SLoadbalancerListener) GetListenerType() string { + return self.Protocol +} + +func (self *SLoadbalancerListener) GetListenerPort() int { + port, err := strconv.Atoi(self.Port) + if err != nil { + log.Errorf("GetListenerPort %s", err) + return 0 + } + + return port +} + +/* +在本地范围内使用的负载均衡算法。可能的值为: + +ROUND_ROBIN:这是一个简单的策略,其中按循环顺序选择每个健康的后端。这是默认设置。 +LEAST_REQUEST:一种 O(1) 算法,它选择两个随机的健康主机并选择具有较少活动请求的主机。 +RING_HASH:环/模散列负载均衡器对后端实现一致的散列。该算法的特性是从一组 N 个主机中添加/删除一个主机只会影响 1/N 的请求。 +RANDOM:负载均衡器随机选择一个健康的主机。 +ORIGINAL_DESTINATION:根据客户端连接元数据选择后端主机,即在连接被重定向到负载均衡器之前,连接被打开到与传入连接的目标地址相同的地址。 +MAGLEV:用作环形哈希负载均衡器的替代品。Maglev 不如环哈希稳定,但具有更快的表查找构建时间和主机选择时间。有关磁悬浮的更多信息,请参阅https://ai.google/research/pubs/pub44824 +此字段适用于: + +service_protocol 设置为 HTTP、HTTPS 或 HTTP2,并且 load_balancing_scheme 设置为 INTERNAL_MANAGED 的区域后端服务。 +load_balancing_scheme 设置为 INTERNAL_SELF_MANAGED 的全局后端服务。 +如果 sessionAffinity 不为 NONE,并且该字段未设置为 MAGLEV 或 RING_HASH,则会话亲缘性设置不会生效。 + +当后端服务被绑定到目标 gRPC 代理且 validateForProxyless 字段设置为 true 的 URL 映射引用时,仅支持默认的 ROUND_ROBIN 策略。 +*/ +// todo: fix me ??? +func (self *SLoadbalancerListener) GetScheduler() string { + switch self.backendService.LocalityLBPolicy { + case "ROUND_ROBIN": + return api.LB_SCHEDULER_RR + case "LEAST_REQUEST": + return api.LB_SCHEDULER_WLC + case "RING_HASH": + return api.LB_SCHEDULER_QCH + case "ORIGINAL_DESTINATION": + return api.LB_SCHEDULER_SCH + case "MAGLEV": + return api.LB_SCHEDULER_MH + default: + return "" + } +} + +func (self *SLoadbalancerListener) GetAclStatus() string { + return api.LB_BOOL_OFF +} + +func (self *SLoadbalancerListener) GetAclType() string { + return "" +} + +func (self *SLoadbalancerListener) GetAclId() string { + return "" +} + +func (self *SLoadbalancerListener) GetEgressMbps() int { + return 0 +} + +func (self *SLoadbalancerListener) GetBackendGroupId() string { + return self.backendService.GetGlobalId() +} + +func (self *SLoadbalancerListener) GetBackendServerPort() int { + igs, err := self.GetInstanceGroups() + if err != nil { + log.Errorf("GetInstanceGroups %s", err) + return 0 + } + + for i := range igs { + for j := range igs[i].NamedPorts { + if igs[i].NamedPorts[j].Name == self.backendService.PortName { + return int(igs[i].NamedPorts[j].Port) + } + } + } + + return 0 +} + +func (self *SLoadbalancerListener) GetClientIdleTimeout() int { + return int(self.backendService.ConnectionDraining.DrainingTimeoutSEC) +} + +func (self *SLoadbalancerListener) GetBackendConnectTimeout() int { + return int(self.backendService.TimeoutSEC) +} + +func (self *SLoadbalancerListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SLoadbalancerListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + rules, err := self.GetLoadbalancerListenerRules() + if err != nil { + return nil, errors.Wrap(err, "GetLoadbalancerListenerRules") + } + + for i := range rules { + if rules[i].GetGlobalId() == ruleId { + return &rules[i], nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SLoadbalancerListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + rules, err := self.GetLoadbalancerListenerRules() + if err != nil { + return nil, errors.Wrap(err, "GetLoadbalancerListenerRules") + } + + irules := make([]cloudprovider.ICloudLoadbalancerListenerRule, len(rules)) + for i := range rules { + irules[i] = &rules[i] + } + + return irules, nil +} + +func (self *SLoadbalancerListener) GetStickySession() string { + if self.backendService.SessionAffinity == "NONE" { + return api.LB_BOOL_OFF + } else { + return api.LB_BOOL_ON + } +} + +/* +https://cloud.google.com/load-balancing/docs/backend-service#sessionAffinity +区域级外部 HTTP(S) 负载均衡器: + 无 (NONE) + 客户端 IP (CLIENT_IP) + 生成的 Cookie (GENERATED_COOKIE) + 标头字段 (HEADER_FIELD) + HTTP Cookie (HTTP_COOKIE) +*/ +func (self *SLoadbalancerListener) GetStickySessionType() string { + switch self.backendService.SessionAffinity { + case "HTTP_COOKIE": + return api.LB_STICKY_SESSION_TYPE_SERVER + case "GENERATED_COOKIE": + return api.LB_STICKY_SESSION_TYPE_INSERT + } + return self.backendService.SessionAffinity +} + +func (self *SLoadbalancerListener) GetStickySessionCookie() string { + return self.backendService.ConsistentHash.HTTPCookie.Name +} + +func (self *SLoadbalancerListener) GetStickySessionCookieTimeout() int { + if len(self.backendService.ConsistentHash.HTTPCookie.TTL.Seconds) == 0 { + return 0 + } + + sec, err := strconv.Atoi(self.backendService.ConsistentHash.HTTPCookie.TTL.Seconds) + if err != nil { + log.Debugf("GetStickySessionCookieTimeout %s", err) + return 0 + } + + return sec +} + +// https://cloud.google.com/load-balancing/docs/https +func (self *SLoadbalancerListener) XForwardedForEnabled() bool { + return true +} + +// https://cloud.google.com/load-balancing/docs/https/troubleshooting-ext-https-lbs +func (self *SLoadbalancerListener) GzipEnabled() bool { + return false +} + +func (self *SLoadbalancerListener) GetCertificateId() string { + if self.httpsProxy != nil && len(self.httpsProxy.SSLCertificates) > 0 { + cert := SResourceBase{ + Name: "", + SelfLink: self.httpsProxy.SSLCertificates[0], + } + return cert.GetGlobalId() + } + + return "" +} + +func (self *SLoadbalancerListener) GetTLSCipherPolicy() string { + return "" +} + +// https://cloud.google.com/load-balancing/docs/https/troubleshooting-ext-https-lbs +func (self *SLoadbalancerListener) HTTP2Enabled() bool { + return true +} + +// todo: fix me route +// 高级配置才有重定向,具体怎么解析? +func (self *SLoadbalancerListener) GetRedirect() string { + //self.lb.urlMap.PathMatchers[0].RouteRules[0].URLRedirect + return "" +} + +func (self *SLoadbalancerListener) GetRedirectCode() int64 { + return 0 +} + +func (self *SLoadbalancerListener) GetRedirectScheme() string { + return "" +} + +func (self *SLoadbalancerListener) GetRedirectHost() string { + return "" +} + +func (self *SLoadbalancerListener) GetRedirectPath() string { + return "" +} + +func (self *SLoadbalancerListener) GetHealthCheck() string { + if len(self.backendService.HealthChecks) > 0 { + return api.LB_BOOL_ON + } else { + return api.LB_BOOL_OFF + } +} + +func (self *SLoadbalancerListener) GetHealthChecks() []HealthChecks { + if self.healthChecks != nil { + return self.healthChecks + } + + hcm, err := self.lb.GetHealthCheckMaps() + if err != nil { + log.Errorf("GetHealthCheckMaps %s", err) + return nil + } + ret := make([]HealthChecks, 0) + for i := range self.backendService.HealthChecks { + hc := self.backendService.HealthChecks[i] + if _, ok := hcm[hc]; ok { + ret = append(ret, hcm[hc]) + } + } + + self.healthChecks = ret + return ret +} + +func (self *SLoadbalancerListener) GetHealthCheckType() string { + hcs := self.GetHealthChecks() + if hcs == nil { + return "" + } + + switch strings.ToLower(hcs[0].Type) { + case "tcp": + return api.LB_HEALTH_CHECK_TCP + case "udp": + return api.LB_HEALTH_CHECK_UDP + case "http", "http2": + return api.LB_HEALTH_CHECK_HTTP + case "https", "ssl": + return api.LB_HEALTH_CHECK_HTTPS + default: + return "" + } +} + +func (self *SLoadbalancerListener) GetHealthCheckTimeout() int { + hcs := self.GetHealthChecks() + if hcs == nil { + return 0 + } + + return int(hcs[0].TimeoutSEC) +} + +func (self *SLoadbalancerListener) GetHealthCheckInterval() int { + hcs := self.GetHealthChecks() + if hcs == nil { + return 0 + } + + return int(hcs[0].CheckIntervalSEC) +} + +func (self *SLoadbalancerListener) GetHealthCheckRise() int { + hcs := self.GetHealthChecks() + if hcs == nil { + return 0 + } + + return int(hcs[0].HealthyThreshold) +} + +func (self *SLoadbalancerListener) GetHealthCheckFail() int { + hcs := self.GetHealthChecks() + if hcs == nil { + return 0 + } + + return int(hcs[0].UnhealthyThreshold) +} + +func (self *SLoadbalancerListener) GetHealthCheckReq() string { + return "" +} + +func (self *SLoadbalancerListener) GetHealthCheckExp() string { + return "" +} + +func (self *SLoadbalancerListener) GetHealthCheckDomain() string { + hcs := self.GetHealthChecks() + if hcs == nil { + return "" + } + switch hcs[0].Type { + case "HTTPS": + return hcs[0].HTTPSHealthCheck.Host + case "HTTP2": + return hcs[0].Http2HealthCheck.Host + case "HTTP": + return hcs[0].HTTPHealthCheck.Host + default: + return "" + } +} + +func (self *SLoadbalancerListener) GetHealthCheckURI() string { + hcs := self.GetHealthChecks() + if hcs == nil { + return "" + } + switch hcs[0].Type { + case "HTTPS": + return hcs[0].HTTPSHealthCheck.RequestPath + case "HTTP2": + return hcs[0].Http2HealthCheck.RequestPath + case "HTTP": + return hcs[0].HTTPHealthCheck.RequestPath + default: + return "" + } +} + +func (self *SLoadbalancerListener) GetHealthCheckCode() string { + return "" +} + +func (self *SLoadbalancerListener) Start() error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancerListener) Stop() error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancerListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancerListener) Delete(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancerListener) GetInstanceGroups() ([]SInstanceGroup, error) { + igs, err := self.lb.GetInstanceGroupsMap() + if err != nil { + return nil, errors.Wrap(err, "GetInstanceGroups") + } + + ret := make([]SInstanceGroup, 0) + for i := range self.backendService.Backends { + b := self.backendService.Backends[i] + if ig, ok := igs[b.Group]; ok { + ret = append(ret, ig) + } + } + + return ret, nil +} + +func (self *SLoadbalancer) GetLoadbalancerListeners() ([]SLoadbalancerListener, error) { + if self.urlMap != nil { + return self.GetHTTPLoadbalancerListeners() + } else { + return self.GetNetworkLoadbalancerListeners() + } +} + +func (self *SLoadbalancer) GetHTTPLoadbalancerListeners() ([]SLoadbalancerListener, error) { + frs, err := self.GetForwardingRules() + if err != nil { + return nil, errors.Wrap(err, "GetForwardingRules") + } + + _hps, err := self.GetTargetHttpProxies() + if err != nil { + return nil, errors.Wrap(err, "GetTargetHttpProxies") + } + + hps := make(map[string]STargetHttpProxy, 0) + for i := range _hps { + hps[_hps[i].SelfLink] = _hps[i] + } + + _hsps, err := self.GetTargetHttpsProxies() + if err != nil { + return nil, errors.Wrap(err, "GetTargetHttpsProxies") + } + + hsps := make(map[string]STargetHttpsProxy, 0) + for i := range _hsps { + hsps[_hsps[i].SelfLink] = _hsps[i] + } + + bss, err := self.GetBackendServices() + if err != nil { + return nil, errors.Wrap(err, "GetBackendServices") + } + + lbls := make([]SLoadbalancerListener, 0) + for i := range frs { + fr := frs[i] + for j := range bss { + bs := bss[j] + port := "80" + protocol := "http" + var hp STargetHttpProxy + var hsp STargetHttpsProxy + if fr.PortRange == "443-443" { + port = "443" + hsp = hsps[fr.Target] + protocol = "https" + } else if fr.PortRange == "8080-8080" { + port = "8080" + hp = hps[fr.Target] + } else { + hp = hps[fr.Target] + } + + lbl := SLoadbalancerListener{ + lb: self, + forwardRule: fr, + backendService: bs, + httpProxy: &hp, + httpsProxy: &hsp, + ForwardRuleName: fr.GetName(), + BackendServiceName: bs.GetName(), + Protocol: protocol, + Port: port, + } + lbls = append(lbls, lbl) + } + } + + return lbls, nil +} + +func (self *SLoadbalancer) GetNetworkLoadbalancerListeners() ([]SLoadbalancerListener, error) { + frs, err := self.GetForwardingRules() + if err != nil { + return nil, errors.Wrap(err, "GetForwardingRules") + } + + bss, err := self.GetBackendServices() + if err != nil { + return nil, errors.Wrap(err, "GetBackendServices") + } + + lbls := make([]SLoadbalancerListener, 0) + for i := range frs { + fr := frs[i] + for j := range bss { + bs := bss[j] + for n := range fr.Ports { + lbl := SLoadbalancerListener{ + lb: self, + forwardRule: fr, + backendService: bs, + ForwardRuleName: fr.GetName(), + BackendServiceName: bs.GetName(), + Protocol: strings.ToLower(fr.IPProtocol), + Port: fr.Ports[n], + } + + lbls = append(lbls, lbl) + } + } + } + + return lbls, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_listenerrule.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_listenerrule.go new file mode 100644 index 0000000000..c3ece7d926 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/loadbalancer_listenerrule.go @@ -0,0 +1,182 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "context" + "fmt" + "strings" + "time" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SLoadbalancerListenerRule struct { + lbl *SLoadbalancerListener + pathMatcher PathMatcher + pathRule PathRule + backendService SBackendServices + + ListenerName string `json:"listener_name"` + BackendServiceName string `json:"backend_service_name"` + Domain string `json:"domain"` + Path string `json:"path"` + Port string `json:"Port"` +} + +func (self *SLoadbalancerListenerRule) GetId() string { + return fmt.Sprintf("%s::%s::%s", self.lbl.GetGlobalId(), self.Domain, strings.Join(self.pathRule.Paths, ",")) +} + +func (self *SLoadbalancerListenerRule) GetName() string { + return fmt.Sprintf("%s::%s::%s", self.lbl.GetName(), self.Domain, strings.Join(self.pathRule.Paths, ",")) +} + +func (self *SLoadbalancerListenerRule) GetGlobalId() string { + return self.GetId() +} + +func (self *SLoadbalancerListenerRule) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancerListenerRule) Refresh() error { + return nil +} + +func (self *SLoadbalancerListenerRule) IsEmulated() bool { + return true +} + +func (self *SLoadbalancerListenerRule) GetCreatedAt() time.Time { + return time.Time{} +} + +func (self *SLoadbalancerListenerRule) GetSysTags() map[string]string { + return nil +} + +func (self *SLoadbalancerListenerRule) GetTags() (map[string]string, error) { + return nil, nil +} + +func (self *SLoadbalancerListenerRule) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancerListenerRule) GetProjectId() string { + return self.lbl.GetProjectId() +} + +func (self *SLoadbalancerListenerRule) GetRedirect() string { + return "" +} + +func (self *SLoadbalancerListenerRule) GetRedirectCode() int64 { + return 0 +} + +func (self *SLoadbalancerListenerRule) GetRedirectScheme() string { + return "" +} + +func (self *SLoadbalancerListenerRule) GetRedirectHost() string { + return "" +} + +func (self *SLoadbalancerListenerRule) GetRedirectPath() string { + return "" +} + +func (self *SLoadbalancerListenerRule) IsDefault() bool { + return false +} + +func (self *SLoadbalancerListenerRule) GetDomain() string { + return self.Domain +} + +func (self *SLoadbalancerListenerRule) GetPath() string { + return self.Path +} + +func (self *SLoadbalancerListenerRule) GetCondition() string { + return "" +} + +func (self *SLoadbalancerListenerRule) GetBackendGroupId() string { + return self.backendService.GetGlobalId() +} + +func (self *SLoadbalancerListenerRule) Delete(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancerListener) GetLoadbalancerListenerRules() ([]SLoadbalancerListenerRule, error) { + if !self.lb.isHttpLb { + return nil, nil + } + + if self.rules != nil { + return self.rules, nil + } + + hostRules := self.lb.urlMap.HostRules + pathMatchers := self.lb.urlMap.PathMatchers + + pmm := make(map[string]PathMatcher, 0) + for i := range pathMatchers { + name := pathMatchers[i].Name + pmm[name] = pathMatchers[i] + } + + ret := make([]SLoadbalancerListenerRule, 0) + for _, rule := range hostRules { + pm, ok := pmm[rule.PathMatcher] + if !ok { + continue + } + + for i := range rule.Hosts { + host := rule.Hosts[i] + for j := range pm.PathRules { + pr := pm.PathRules[j] + + if pr.Service != self.backendService.GetId() { + continue + } + + r := SLoadbalancerListenerRule{ + lbl: self, + backendService: self.backendService, + BackendServiceName: self.backendService.GetName(), + pathMatcher: pm, + pathRule: pr, + + ListenerName: self.GetName(), + Domain: host, + Path: strings.Join(pr.Paths, ","), + Port: self.Port, + } + + ret = append(ret, r) + } + } + } + + self.rules = ret + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/machinetype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/machinetype.go new file mode 100644 index 0000000000..9ec5ed43de --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/machinetype.go @@ -0,0 +1,57 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "time" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SMachineType struct { + Id string + CreationTimestamp time.Time + Name string + Description string + GuestCpus int + MemoryMb int + ImageSpaceGb int + MaximumPersistentDisks int + MaximumPersistentDisksSizeGb int + Zone string + SelfLink string + IsSharedCpu bool + Kind string +} + +func (region *SRegion) GetMachineTypes(zone string, maxResults int, pageToken string) ([]SMachineType, error) { + machines := []SMachineType{} + params := map[string]string{} + if len(zone) == 0 { + return nil, cloudprovider.ErrNotFound + } + resource := fmt.Sprintf("zones/%s/machineTypes", zone) + return machines, region.List(resource, params, maxResults, pageToken, &machines) +} + +func (region *SRegion) GetMachineType(id string) (*SMachineType, error) { + machine := &SMachineType{} + err := region.client.ecsGet("machineTypes", id, machine) + if err != nil { + return nil, err + } + return machine, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/monitor.go new file mode 100644 index 0000000000..7ed8cf98fa --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/monitor.go @@ -0,0 +1,119 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type MetricDataValue struct { + DoubleValue float64 + Int64Value float64 +} + +func (self *MetricDataValue) GetValue() float64 { + return self.DoubleValue + self.Int64Value +} + +type MetricData struct { + Resource struct { + Labels struct { + InstanceId string + } + } + MetricKind string + ValueType string + Points []struct { + Interval struct { + StartTime time.Time + EndTime time.Time + } + Value MetricDataValue + } +} + +func (self *SGoogleClient) GetMonitorData(metricName string, since time.Time, until time.Time) (*jsonutils.JSONArray, error) { + params := map[string]string{ + "filter": fmt.Sprintf(`metric.type="%s"`, metricName), + "interval.startTime": since.Format(time.RFC3339), + "interval.endTime": until.Format(time.RFC3339), + } + resource := fmt.Sprintf("%s/%s/%s", "projects", self.projectId, "timeSeries") + timeSeries, err := self.monitorListAll(resource, params) + if err != nil { + return nil, err + } + return timeSeries, nil +} + +func (self *SGoogleClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) + } +} + +func (self *SGoogleClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metricName := "" + switch opts.MetricType { + case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: + metricName = "compute.googleapis.com/instance/cpu/utilization" + case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: + metricName = "compute.googleapis.com/instance/network/received_bytes_count" + case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: + metricName = "compute.googleapis.com/instance/network/sent_bytes_count" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: + metricName = "compute.googleapis.com/instance/disk/read_bytes_count" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: + metricName = "compute.googleapis.com/instance/disk/write_bytes_count" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: + metricName = "compute.googleapis.com/instance/disk/read_ops_count" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: + metricName = "compute.googleapis.com/instance/disk/write_ops_count" + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) + } + metrics, err := self.GetMonitorData(metricName, opts.StartTime, opts.EndTime) + if err != nil { + return nil, errors.Wrapf(err, "GetMonitorData") + } + data := []MetricData{} + err = metrics.Unmarshal(&data) + if err != nil { + return nil, errors.Wrapf(err, "metrics.Unmarshal") + } + ret := []cloudprovider.MetricValues{} + for i := range data { + value := cloudprovider.MetricValues{} + value.Id = data[i].Resource.Labels.InstanceId + value.MetricType = opts.MetricType + for j := range data[i].Points { + metricValue := cloudprovider.MetricValue{} + metricValue.Timestamp = data[i].Points[j].Interval.StartTime + metricValue.Value = data[i].Points[j].Value.GetValue() + value.Values = append(value.Values, metricValue) + } + ret = append(ret, value) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/network.go new file mode 100644 index 0000000000..cf8c03366f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/network.go @@ -0,0 +1,109 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "time" + + "yunion.io/x/onecloud/pkg/util/rbacutils" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SNetwork struct { + GoogleTags + wire *SWire +} + +func (network *SNetwork) GetProjectId() string { + return network.wire.vpc.region.GetProjectId() +} + +func (self *SNetwork) GetName() string { + return self.wire.vpc.GetName() +} + +func (self *SNetwork) GetId() string { + return self.wire.vpc.GetId() +} + +func (self *SNetwork) GetGlobalId() string { + return self.wire.vpc.GetGlobalId() +} + +func (self *SNetwork) Refresh() error { + return self.wire.vpc.Refresh() +} + +func (network *SNetwork) IsEmulated() bool { + return false +} + +func (network *SNetwork) GetStatus() string { + return api.NETWORK_INTERFACE_STATUS_AVAILABLE +} + +func (network *SNetwork) GetCreatedAt() time.Time { + return time.Time{} +} + +func (network *SNetwork) Delete() error { + return network.wire.vpc.Delete() +} + +func (network *SNetwork) GetAllocTimeoutSeconds() int { + return 300 +} + +func (network *SNetwork) GetIWire() cloudprovider.ICloudWire { + return network.wire +} + +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.wire.vpc.IpCidrRange) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String() +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.wire.vpc.IpCidrRange) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + return endIp.String() +} + +func (self *SNetwork) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(self.wire.vpc.IpCidrRange) + return pref.MaskLen +} + +func (self *SNetwork) GetGateway() string { + return self.wire.vpc.GatewayAddress +} + +func (network *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (network *SNetwork) GetIsPublic() bool { + return true +} + +func (network *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} diff --git a/pkg/multicloud/google/operation.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/operation.go similarity index 98% rename from pkg/multicloud/google/operation.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/operation.go index 6e6cec0978..2027d82206 100644 --- a/pkg/multicloud/google/operation.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/operation.go @@ -19,7 +19,7 @@ import ( "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) const ( diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/project.go new file mode 100644 index 0000000000..da9bce1593 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/project.go @@ -0,0 +1,99 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SProject struct { + multicloud.SProjectBase + GoogleTags + Name string + CreateTime time.Time + LifecycleState string + ProjectId string + ProjectNumber string +} + +func (cli *SGoogleClient) GetProject(id string) (*SProject, error) { + project := &SProject{} + resp, err := cli.managerGet(id) + if err != nil { + return nil, errors.Wrap(err, "managerGet") + } + err = resp.Unmarshal(project) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return project, nil +} + +func (cli *SGoogleClient) GetProjects() ([]SProject, error) { + nextPageToken := "" + params := map[string]string{} + result := []SProject{} + for { + if len(nextPageToken) > 0 { + params["pageToken"] = nextPageToken + } + resp, err := cli.managerList("projects", params) + if err != nil { + return nil, errors.Wrap(err, "managerList") + } + _result := []SProject{} + if resp.Contains("projects") { + err = resp.Unmarshal(&_result, "projects") + if err != nil { + return nil, errors.Wrap(err, "data.Unmarshal") + } + } + result = append(result, _result...) + nextPageToken, _ = resp.GetString("nextPageToken") + if len(nextPageToken) == 0 || len(_result) == 0 { + break + } + } + return result, nil +} + +func (p *SProject) GetName() string { + return p.Name +} + +func (p *SProject) GetId() string { + return p.ProjectId +} + +func (p *SProject) GetGlobalId() string { + return p.ProjectId +} + +func (p *SProject) GetStatus() string { + return api.EXTERNAL_PROJECT_STATUS_AVAILABLE +} + +func (p *SProject) Refresh() error { + return nil +} + +func (p *SProject) IsEmulated() bool { + return false +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/provider/doc.go new file mode 100644 index 0000000000..8ef58fb3bb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/google/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/provider/provider.go new file mode 100644 index 0000000000..51bd836ade --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/provider/provider.go @@ -0,0 +1,315 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/google" +) + +type SGoogleProviderFactory struct { + cloudprovider.SPublicCloudBaseProviderFactory +} + +func (self *SGoogleProviderFactory) GetId() string { + return google.CLOUD_PROVIDER_GOOGLE +} + +func (self *SGoogleProviderFactory) GetName() string { + return google.CLOUD_PROVIDER_GOOGLE_CN +} + +func (self *SGoogleProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { + return nil +} + +func (self *SGoogleProviderFactory) IsSupportPrepaidResources() bool { + return false +} + +func (self *SGoogleProviderFactory) IsClouduserSupportPassword() bool { + return false +} + +func (factory *SGoogleProviderFactory) IsCloudpolicyWithSubscription() bool { + return true +} + +func (factory *SGoogleProviderFactory) IsClouduserpolicyWithSubscription() bool { + return true +} + +func (factory *SGoogleProviderFactory) IsSupportCloudIdService() bool { + return true +} + +func (factory *SGoogleProviderFactory) IsClouduserNeedInitPolicy() bool { + return true +} + +func (factory *SGoogleProviderFactory) IsSupportResetClouduserPassword() bool { + return false +} + +func (factory *SGoogleProviderFactory) GetClouduserMinPolicyCount() int { + return 1 +} + +func (self *SGoogleProviderFactory) IsClouduserBelongCloudprovider() bool { + return true +} + +func (self *SGoogleProviderFactory) NeedSyncSkuFromCloud() bool { + return false +} + +func (self *SGoogleProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + for key, value := range map[string]string{ + "client_email": input.GCPClientEmail, + "project_id": input.GCPProjectId, + "private_key_id": input.GCPPrivateKeyId, + "private_key": input.GCPPrivateKey, + } { + if len(value) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, key) + } + } + output.Account = fmt.Sprintf("%s/%s", input.GCPProjectId, input.GCPClientEmail) + output.Secret = fmt.Sprintf("%s/%s", input.GCPPrivateKeyId, input.GCPPrivateKey) + return output, nil +} + +func (self *SGoogleProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + projectID, clientEmail := "", "" + accountInfo := strings.Split(cloudaccount, "/") + if len(accountInfo) == 2 { + projectID, clientEmail = accountInfo[0], accountInfo[1] + } + + for key, value := range map[string]string{ + "private_key_id": input.GCPPrivateKeyId, + "private_key": input.GCPPrivateKey, + } { + if len(value) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, key) + } + } + if len(input.GCPClientEmail) == 0 { + input.GCPClientEmail = clientEmail + } + + if len(input.GCPProjectId) == 0 { + input.GCPProjectId = projectID + } + + output = cloudprovider.SCloudaccount{ + Account: fmt.Sprintf("%s/%s", input.GCPProjectId, input.GCPClientEmail), + Secret: fmt.Sprintf("%s/%s", input.GCPPrivateKeyId, input.GCPPrivateKey), + } + return output, nil +} + +func (self *SGoogleProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + privateKeyID, privateKey := "", "" + privateKeyInfo := strings.Split(cfg.Secret, "/") + if len(privateKeyInfo) < 2 { + return nil, fmt.Errorf("Missing privateKeyID or privateKey for google cloud") + } + privateKeyID = privateKeyInfo[0] + privateKey = strings.Join(privateKeyInfo[1:], "/") + projectID, clientEmail := "", "" + accountInfo := strings.Split(cfg.Account, "/") + if len(accountInfo) < 2 { + return nil, fmt.Errorf("Invalid projectID or client email for google cloud %s", cfg.Account) + } + projectID, clientEmail = accountInfo[0], accountInfo[1] + + client, err := google.NewGoogleClient( + google.NewGoogleClientConfig( + projectID, clientEmail, privateKeyID, privateKey, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SGoogleProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func parseAccount(account, secret string) (projectId string, clientEmail string, privateKey string, privateKeyId string) { + accountInfo := strings.Split(account, "/") + if len(accountInfo) == 2 { + projectId, clientEmail = accountInfo[0], accountInfo[1] + } + secretInfo := strings.Split(secret, "/") + if len(secretInfo) >= 2 { + privateKeyId, privateKey = secretInfo[0], strings.Join(secretInfo[1:], "/") + } + return +} + +func (self *SGoogleProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + projectId, clientEmail, privateKey, privateKeyId := parseAccount(info.Account, info.Secret) + return map[string]string{ + "GOOGLE_CLIENT_EMAIL": clientEmail, + "GOOGLE_PROJECT_ID": projectId, + "GOOGLE_PRIVATE_KEY_ID": privateKeyId, + "GOOGLE_PRIVATE_KEY": privateKey, + }, nil +} + +func init() { + factory := SGoogleProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SGoogleProvider struct { + cloudprovider.SBaseProvider + client *google.SGoogleClient +} + +func (self *SGoogleProvider) GetSysInfo() (jsonutils.JSONObject, error) { + regions := self.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") + info.Add(jsonutils.NewString(google.GOOGLE_API_VERSION), "api_version") + return info, nil +} + +func (self *SGoogleProvider) GetVersion() string { + return google.GOOGLE_API_VERSION +} + +func (self *SGoogleProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SGoogleProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SGoogleProvider) GetIamLoginUrl() string { + return "https://console.cloud.google.com" +} + +func (self *SGoogleProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SGoogleProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(extId) +} + +func (self *SGoogleProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SGoogleProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SGoogleProvider) GetStorageClasses(regionId string) []string { + return []string{ + "STANDARD", "NEARLINE", "COLDLINE", "ARCHIVE", + } +} + +func (self *SGoogleProvider) GetBucketCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLAuthRead), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SGoogleProvider) GetObjectCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLAuthRead), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SGoogleProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SGoogleProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { + return self.client.GetICloudusers() +} + +func (self *SGoogleProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + return []cloudprovider.ICloudgroup{}, nil +} + +func (self *SGoogleProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SGoogleProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetISystemCloudpolicies() +} + +func (self *SGoogleProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetICustomCloudpolicies() +} + +func (self *SGoogleProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + return self.client.CreateIClouduser(conf) +} + +func (self *SGoogleProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.client.GetIClouduserByName(name) +} + +func (self *SGoogleProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { + return self.client.CreateICloudpolicy(opts) +} + +func (self *SGoogleProvider) GetSamlEntityId() string { + return cloudprovider.SAML_ENTITY_ID_GOOGLE +} + +func (self *SGoogleProvider) GetICloudGlobalVpcs() ([]cloudprovider.ICloudGlobalVpc, error) { + return self.client.GetICloudGlobalVpcs() +} + +func (self *SGoogleProvider) GetICloudGlobalVpcById(id string) (cloudprovider.ICloudGlobalVpc, error) { + return self.client.GetICloudGlobalVpcById(id) +} + +func (self *SGoogleProvider) CreateICloudGlobalVpc(opts *cloudprovider.GlobalVpcCreateOptions) (cloudprovider.ICloudGlobalVpc, error) { + return self.client.CreateICloudGlobalVpc(opts) +} + +func (self *SGoogleProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetMetrics(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/quota.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/quota.go new file mode 100644 index 0000000000..0acae3aa95 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/quota.go @@ -0,0 +1,60 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "strings" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SQuota struct { + Metric string + Limit int + Usage int + Owner string +} + +func (q *SQuota) GetGlobalId() string { + return strings.ToLower(q.Metric) +} + +func (q *SQuota) GetName() string { + return q.Metric +} + +func (q *SQuota) GetDesc() string { + return q.Metric +} + +func (q *SQuota) GetQuotaType() string { + return q.Metric +} + +func (q *SQuota) GetMaxQuotaCount() int { + return q.Limit +} + +func (q *SQuota) GetCurrentQuotaUsedCount() int { + return q.Usage +} + +func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { + ret := []cloudprovider.ICloudQuota{} + for i := range region.Quotas { + ret = append(ret, ®ion.Quotas[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/region.go new file mode 100644 index 0000000000..1a78484fe4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/region.go @@ -0,0 +1,833 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + cloudprovider.SFakeOnPremiseRegion + multicloud.SRegion + client *SGoogleClient + + capabilities []string + Quotas []SQuota + + Description string + ID string + Kind string + Name string + Status string + SelfLink string + CreationTimestamp time.Time +} + +func (region *SRegion) GetClient() *SGoogleClient { + return region.client +} + +func (region *SRegion) GetName() string { + if name, ok := RegionNames[region.Name]; ok { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_GOOGLE_CN, name) + } + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_GOOGLE_CN, region.Name) +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_GOOGLE, self.Name) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (region *SRegion) GetId() string { + return region.Name +} + +func (region *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_GOOGLE, region.Name) +} + +func (region *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + if geoInfo, ok := LatitudeAndLongitude[region.Name]; ok { + return geoInfo + } + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetCreatedAt() time.Time { + return self.CreationTimestamp +} + +func (region *SRegion) GetProvider() string { + return CLOUD_PROVIDER_GOOGLE +} + +func (region *SRegion) GetStatus() string { + if region.Status == "UP" || utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return api.CLOUD_REGION_STATUS_INSERVER + } + return api.CLOUD_REGION_STATUS_OUTOFSERVICE +} + +func (region *SRegion) CreateIBucket(name string, storageClassStr string, acl string) error { + _, err := region.CreateBucket(name, storageClassStr, cloudprovider.TBucketACLType(acl)) + return err +} + +func (region *SRegion) DeleteIBucket(name string) error { + return region.DeleteBucket(name) +} + +func (region *SRegion) IBucketExist(name string) (bool, error) { + //{"error":{"code":403,"details":"200420163731-compute@developer.gserviceaccount.com does not have storage.buckets.get access to test."}} + //{"error":{"code":404,"details":"Not Found"}} + _, err := region.GetBucket(name) + if err == nil { + return true, nil + } + if errors.Cause(err) == cloudprovider.ErrNotFound || strings.Contains(err.Error(), "storage.buckets.get access") { + return false, nil + } + return false, err +} + +func (region *SRegion) GetIBucketById(id string) (cloudprovider.ICloudBucket, error) { + return cloudprovider.GetIBucketById(region, id) +} + +func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { + return region.GetIBucketById(name) +} + +func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + iBuckets, err := region.client.getIBuckets() + if err != nil { + return nil, errors.Wrap(err, "getIBuckets") + } + ret := []cloudprovider.ICloudBucket{} + for i := range iBuckets { + if iBuckets[i].GetLocation() != region.GetId() { + continue + } + ret = append(ret, iBuckets[i]) + } + return ret, nil +} + +func (region *SRegion) IsEmulated() bool { + return false +} + +func (region *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return []cloudprovider.ICloudZone{}, nil + } + zones, err := region.GetZones(region.Name, 0, "") + if err != nil { + return nil, err + } + izones := []cloudprovider.ICloudZone{} + for i := 0; i < len(zones); i++ { + zones[i].region = region + izones = append(izones, &zones[i]) + } + return izones, nil +} + +func (region *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotFound + } + + zones, err := region.GetIZones() + if err != nil { + return nil, err + } + for i := range zones { + if zones[i].GetGlobalId() == id { + return zones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + if utils.IsInStringArray(self.Name, MultiRegions) || utils.IsInStringArray(self.Name, DualRegions) { + return []cloudprovider.ICloudVpc{}, nil + } + vpcs, err := self.GetVpcs() + if err != nil { + return nil, errors.Wrapf(err, "GetVpcs") + } + ret := []cloudprovider.ICloudVpc{} + for i := range vpcs { + vpcs[i].region = self + ret = append(ret, &vpcs[i]) + } + return ret, nil +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + vpc, err := self.GetVpc(id) + if err != nil { + return nil, errors.Wrapf(err, "GetVpc") + } + return vpc, nil +} + +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + if utils.IsInStringArray(self.Name, MultiRegions) || utils.IsInStringArray(self.Name, DualRegions) { + return nil, cloudprovider.ErrNotSupported + } + gvpc, err := self.client.GetGlobalNetwork(opts.GlobalVpcExternalId) + if err != nil { + return nil, errors.Wrapf(err, "GetGlobalNetwork") + } + return self.CreateVpc(opts.NAME, gvpc.SelfLink, opts.CIDR, opts.Desc) +} + +func (region *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotFound + } + + storage, err := region.GetStorage(id) + if err != nil { + return nil, err + } + zone, err := region.GetZone(storage.Zone) + if err != nil { + return nil, errors.Wrapf(err, "region.GetZone(%s)", storage.Zone) + } + zone.region = region + storage.zone = zone + return storage, nil +} + +func (region *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotFound + } + + izones, err := region.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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetProjectId() string { + return region.client.projectId +} + +func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return []cloudprovider.ICloudEIP{}, nil + } + + eips, err := region.GetEips("", 0, "") + if err != nil { + return nil, err + } + ieips := []cloudprovider.ICloudEIP{} + for i := range eips { + eips[i].region = region + ieips = append(ieips, &eips[i]) + } + return ieips, nil +} + +func (region *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotFound + } + + ivm, err := region.GetInstance(id) + if err != nil { + return nil, err + } + zone, err := region.GetZone(ivm.Zone) + if err != nil { + return nil, errors.Wrapf(err, "GetZone(%s)", ivm.Zone) + } + ivm.host = &SHost{zone: zone} + return ivm, nil +} + +func (region *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotFound + } + + disk, err := region.GetDisk(id) + if err != nil { + return nil, err + } + return disk, nil +} + +func (region *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotFound + } + + eip, err := region.GetEip(id) + if err != nil { + return nil, err + } + return eip, nil +} + +func (region *SRegion) fetchSnapshots() error { + if len(region.client.snapshots) > 0 { + return nil + } + region.client.snapshots = map[string][]SSnapshot{} + snapshots, err := region.GetSnapshots("", 0, "") + if err != nil { + return err + } + regionNames := []string{} + for _, region := range region.client.iregions { + regionNames = append(regionNames, region.GetId()) + } + for _, snapshot := range snapshots { + for _, location := range snapshot.StorageLocations { + _regionName := "" + if utils.IsInStringArray(location, regionNames) { + _regionName = location + } else { + for _, regionName := range regionNames { + if strings.HasPrefix(regionName, location) { + _regionName = regionName + break + } + } + } + if len(_regionName) > 0 { + if _, ok := region.client.snapshots[_regionName]; !ok { + region.client.snapshots[_regionName] = []SSnapshot{} + } + region.client.snapshots[_regionName] = append(region.client.snapshots[_regionName], snapshot) + break + } + + } + } + return nil +} + +func (region *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return []cloudprovider.ICloudSnapshot{}, nil + } + + region.fetchSnapshots() + isnapshots := []cloudprovider.ICloudSnapshot{} + if snapshots, ok := region.client.snapshots[region.Name]; ok { + for i := range snapshots { + snapshots[i].region = region + isnapshots = append(isnapshots, &snapshots[i]) + } + } + return isnapshots, nil +} + +func (region *SRegion) GetISnapshotById(id string) (cloudprovider.ICloudSnapshot, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotFound + } + + snapshot, err := region.GetSnapshot(id) + if err != nil { + return nil, err + } + return snapshot, nil +} + +func (region *SRegion) rdsDelete(id string) error { + operation := &SOperation{} + err := region.client.rdsDelete(id, operation) + if err != nil { + return errors.Wrap(err, "client.rdsDelete") + } + _, err = region.WaitRdsOperation(operation.SelfLink, id, "delete") + if err != nil { + return errors.Wrapf(err, "region.WaitRdsOperation(%s)", operation.SelfLink) + } + return nil +} + +func (region *SRegion) rdsDo(id string, action string, params map[string]string, body jsonutils.JSONObject) error { + opId, err := region.client.rdsDo(id, action, params, body) + if err != nil { + return err + } + if strings.Index(opId, "/operations/") > 0 { + _, err = region.WaitRdsOperation(opId, id, action) + return err + } + return nil +} + +func (region *SRegion) rdsPatch(id string, body jsonutils.JSONObject) error { + opId, err := region.client.rdsPatch(id, body) + if err != nil { + return err + } + if strings.Index(opId, "/operations/") > 0 { + _, err = region.WaitRdsOperation(opId, id, "update") + return err + } + return nil +} + +func (region *SRegion) rdsUpdate(id string, params map[string]string, body jsonutils.JSONObject) error { + opId, err := region.client.rdsUpdate(id, params, body) + if err != nil { + return err + } + if strings.Index(opId, "/operations/") > 0 { + _, err = region.WaitRdsOperation(opId, id, "update") + return err + } + return nil +} + +func (region *SRegion) rdsGet(resource string, retval interface{}) error { + return region.client.rdsGet(resource, retval) +} + +func (region *SRegion) rdsInsert(resource string, body jsonutils.JSONObject, retval interface{}) error { + operation := SOperation{} + err := region.client.rdsInsert(resource, body, &operation) + if err != nil { + return errors.Wrap(err, "rdsInsert") + } + resourceId, err := region.WaitRdsOperation(operation.SelfLink, resource, "insert") + if err != nil { + return errors.Wrapf(err, "region.WaitRdsOperation(%s)", operation.SelfLink) + } + return region.rdsGet(resourceId, retval) +} + +func (region *SRegion) RdsListAll(resource string, params map[string]string, retval interface{}) error { + return region.client.rdsListAll(resource, params, retval) +} + +func (region *SRegion) RdsList(resource string, params map[string]string, maxResults int, pageToken string, retval interface{}) error { + if maxResults == 0 && len(pageToken) == 0 { + return region.RdsListAll(resource, params, retval) + } + if params == nil { + params = map[string]string{} + } + params["maxResults"] = fmt.Sprintf("%d", maxResults) + params["pageToken"] = pageToken + resp, err := region.client.rdsList(resource, params) + if err != nil { + return errors.Wrap(err, "billingList") + } + if resp.Contains("items") && retval != nil { + err = resp.Unmarshal(retval, "items") + if err != nil { + return errors.Wrap(err, "resp.Unmarshal") + } + } + return nil +} + +func (region *SRegion) BillingList(resource string, params map[string]string, pageSize int, pageToken string, retval interface{}) error { + if pageSize == 0 && len(pageToken) == 0 { + return region.BillingListAll(resource, params, retval) + } + if params == nil { + params = map[string]string{} + } + params["pageSize"] = fmt.Sprintf("%d", pageSize) + params["pageToken"] = pageToken + resp, err := region.client.billingList(resource, params) + if err != nil { + return errors.Wrap(err, "billingList") + } + if resp.Contains("skus") && retval != nil { + err = resp.Unmarshal(retval, "skus") + if err != nil { + return errors.Wrap(err, "resp.Unmarshal") + } + } + return nil +} + +func (region *SRegion) BillingListAll(resource string, params map[string]string, retval interface{}) error { + return region.client.billingListAll(resource, params, retval) +} + +func (region *SRegion) ListAll(resource string, params map[string]string, retval interface{}) error { + return region.listAll("GET", resource, params, retval) +} + +func (region *SRegion) listAll(method string, resource string, params map[string]string, retval interface{}) error { + return region.client._ecsListAll(method, resource, params, retval) +} + +func (region *SRegion) List(resource string, params map[string]string, maxResults int, pageToken string, retval interface{}) error { + if maxResults == 0 && len(pageToken) == 0 { + return region.ListAll(resource, params, retval) + } + if params == nil { + params = map[string]string{} + } + params["maxResults"] = fmt.Sprintf("%d", maxResults) + params["pageToken"] = pageToken + resp, err := region.client.ecsList(resource, params) + if err != nil { + return errors.Wrap(err, "ecsList") + } + if resp.Contains("items") && retval != nil { + err = resp.Unmarshal(retval, "items") + if err != nil { + return errors.Wrap(err, "resp.Unmarshal") + } + } + return nil +} + +func (region *SRegion) Get(resourceType, id string, retval interface{}) error { + return region.client.ecsGet(resourceType, id, retval) +} + +func (self *SGoogleClient) GetBySelfId(id string, retval interface{}) error { + resp, err := jsonRequest(self.client, "GET", GOOGLE_COMPUTE_DOMAIN, GOOGLE_API_VERSION, id, nil, nil, self.debug) + if err != nil { + return err + } + if retval != nil { + return resp.Unmarshal(retval) + } + return nil +} + +func (self *SRegion) GetBySelfId(id string, retval interface{}) error { + return self.client.GetBySelfId(id, retval) +} + +func (region *SRegion) StorageListAll(resource string, params map[string]string, retval interface{}) error { + return region.client.storageListAll(resource, params, retval) +} + +func (region *SRegion) StorageList(resource string, params map[string]string, maxResults int, pageToken string, retval interface{}) error { + if maxResults == 0 && len(pageToken) == 0 { + return region.client.storageListAll(resource, params, retval) + } + if params == nil { + params = map[string]string{} + } + params["maxResults"] = fmt.Sprintf("%d", maxResults) + params["pageToken"] = pageToken + resp, err := region.client.storageList(resource, params) + if err != nil { + return errors.Wrap(err, "storageList") + } + if resp.Contains("items") && retval != nil { + err = resp.Unmarshal(retval, "items") + if err != nil { + return errors.Wrap(err, "resp.Unmarshal") + } + } + return nil +} + +func (region *SRegion) StorageGet(id string, retval interface{}) error { + return region.client.storageGet(id, retval) +} + +func (region *SRegion) StoragePut(id string, body jsonutils.JSONObject, retval interface{}) error { + return region.client.storagePut(id, body, retval) +} + +func (region *SRegion) StorageDo(id string, action string, params map[string]string, body jsonutils.JSONObject) error { + opId, err := region.client.storageDo(id, action, params, body) + if err != nil { + return err + } + if strings.Index(opId, "/operations/") > 0 { + _, err = region.client.WaitOperation(opId, id, action) + return err + } + return nil +} + +func (region *SRegion) Do(id string, action string, params map[string]string, body jsonutils.JSONObject) error { + opId, err := region.client.ecsDo(id, action, params, body) + if err != nil { + return err + } + if strings.Index(opId, "/operations/") > 0 { + _, err = region.client.WaitOperation(opId, id, action) + return err + } + return nil +} + +func (region *SRegion) Patch(id string, action string, params map[string]string, body jsonutils.JSONObject) error { + opId, err := region.client.ecsPatch(id, action, params, body) + if err != nil { + return err + } + if strings.Index(opId, "/operations/") > 0 { + _, err = region.client.WaitOperation(opId, id, action) + return err + } + return nil +} + +func (region *SRegion) StorageDelete(id string) error { + return region.client.storageDelete(id, nil) +} + +func (region *SRegion) Delete(id string) error { + operation := &SOperation{} + err := region.client.ecsDelete(id, operation) + if err != nil { + return errors.Wrap(err, "client.ecsDelete") + } + _, err = region.client.WaitOperation(operation.SelfLink, id, "delete") + if err != nil { + return errors.Wrapf(err, "region.WaitOperation(%s)", operation.SelfLink) + } + return nil +} + +func (region *SRegion) StorageInsert(resource string, body jsonutils.JSONObject, retval interface{}) error { + return region.client.storageInsert(resource, body, retval) +} + +func (region *SRegion) CloudbuildInsert(body jsonutils.JSONObject) error { + result := &struct { + Name string + }{} + resource := fmt.Sprintf("projects/%s/builds", region.GetProjectId()) + err := region.client.cloudbuildInsert(resource, body, result) + if err != nil { + return errors.Wrap(err, "insert") + } + err = cloudprovider.Wait(time.Second*10, time.Minute*40, func() (bool, error) { + operation, err := region.GetCloudbuildOperation(result.Name) + if err != nil { + return false, errors.Wrapf(err, "region.GetCloudbuildOperation(%s)", result.Name) + } + status := operation.Metadata.Build.Status + log.Debugf("cloudbuild %s status: %s", result.Name, status) + if status == "FAILURE" { + return false, fmt.Errorf("cloudbuild failed error log: %s", operation.Metadata.Build.LogUrl) + } + if status == "SUCCESS" { + return true, nil + } + return false, nil + }) + if err != nil { + return errors.Wrap(err, "cloudprovider.Wait") + } + return nil +} + +func (region *SRegion) cloudbuildGet(id string, retval interface{}) error { + return region.client.cloudbuildGet(id, retval) +} + +func (self *SGoogleClient) Insert(resource string, body jsonutils.JSONObject, retval interface{}) error { + operation := &SOperation{} + err := self.ecsInsert(resource, body, operation) + if err != nil { + return err + } + resourceId, err := self.WaitOperation(operation.SelfLink, resource, "insert") + if err != nil { + return errors.Wrapf(err, "region.WaitOperation(%s)", operation.SelfLink) + } + return self.GetBySelfId(resourceId, retval) +} + +func (self *SRegion) Insert(resource string, body jsonutils.JSONObject, retval interface{}) error { + return self.client.Insert(resource, body, retval) +} + +func (region *SRegion) fetchResourcePolicies() ([]SResourcePolicy, error) { + if len(region.client.resourcepolices) > 0 { + return region.client.resourcepolices, nil + } + policies, err := region.GetResourcePolicies(0, "") + if err != nil { + return nil, err + } + region.client.resourcepolices = policies + return policies, nil +} + +func (region *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return []cloudprovider.ICloudSnapshotPolicy{}, nil + } + + policies, err := region.fetchResourcePolicies() + if err != nil { + return nil, err + } + ipolicies := []cloudprovider.ICloudSnapshotPolicy{} + for i := range policies { + policies[i].region = region + if utils.IsInStringArray(region.Name, policies[i].SnapshotSchedulePolicy.SnapshotProperties.StorageLocations) { + ipolicies = append(ipolicies, &policies[i]) + } + } + return ipolicies, nil +} + +func (region *SRegion) GetISnapshotPolicyById(id string) (cloudprovider.ICloudSnapshotPolicy, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotFound + } + + policy, err := region.GetResourcePolicy(id) + if err != nil { + return nil, err + } + if !strings.Contains(region.Name, policy.SnapshotSchedulePolicy.SnapshotProperties.StorageLocations[0]) { + return nil, cloudprovider.ErrNotFound + } + return policy, nil +} + +func (region *SRegion) CreateEIP(args *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotSupported + } + + eip, err := region.CreateEip(args.Name, "") + if err != nil { + return nil, err + } + return eip, nil +} + +func (region *SRegion) GetCapabilities() []string { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return []string{cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE} + } + if region.capabilities == nil { + return region.client.GetCapabilities() + } + return region.capabilities +} + +func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return []cloudprovider.ICloudDBInstance{}, nil + } + + instances, err := region.GetDBInstances(0, "") + if err != nil { + return nil, errors.Wrap(err, "GetDBInstances") + } + ret := []cloudprovider.ICloudDBInstance{} + for i := range instances { + instances[i].region = region + ret = append(ret, &instances[i]) + } + return ret, nil +} + +func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotFound + } + + instance, err := region.GetDBInstance(instanceId) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstance(%s)", instanceId) + } + return instance, nil +} + +func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return []cloudprovider.ICloudDBInstanceBackup{}, nil + } + + instances, err := region.GetDBInstances(0, "") + if err != nil { + return nil, errors.Wrap(err, "GetDBInstances") + } + ret := []cloudprovider.ICloudDBInstanceBackup{} + for i := range instances { + instances[i].region = region + backups, err := region.GetDBInstanceBackups(instances[i].Name) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceBackups(%s)", instances[i].Name) + } + for j := range backups { + backups[j].rds = &instances[i] + ret = append(ret, &backups[j]) + } + } + return ret, nil +} + +func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotFound + } + + backup, err := region.GetDBInstanceBackup(backupId) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceBackup(%s)", backupId) + } + return backup, nil +} + +func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + if utils.IsInStringArray(region.Name, MultiRegions) || utils.IsInStringArray(region.Name, DualRegions) { + return nil, cloudprovider.ErrNotSupported + } + + rds, err := region.CreateDBInstance(desc) + if err != nil { + return nil, errors.Wrap(err, "CreateDBInstance") + } + return rds, nil +} diff --git a/pkg/multicloud/google/regiondisk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/regiondisk.go similarity index 100% rename from pkg/multicloud/google/regiondisk.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/regiondisk.go diff --git a/pkg/multicloud/google/regionstorage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/regionstorage.go similarity index 100% rename from pkg/multicloud/google/regionstorage.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/regionstorage.go diff --git a/pkg/multicloud/google/resourcebase.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/resourcebase.go similarity index 100% rename from pkg/multicloud/google/resourcebase.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/resourcebase.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/resourcepolicy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/resourcepolicy.go new file mode 100644 index 0000000000..28ed77b475 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/resourcepolicy.go @@ -0,0 +1,163 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +type SDailySchedule struct { + DaysInCycle int + StartTime string + Duration string +} + +type SDayOfWeek struct { + Day string + StartTime string + Duration string +} + +type SHourlySchedule struct { + HoursInCycle int + StartTime string + Duration string +} + +type SWeeklySchedule struct { + DayOfWeeks []SDayOfWeek +} + +type SSchedule struct { + WeeklySchedule SWeeklySchedule + DailySchedule SDailySchedule + HourlySchedule SHourlySchedule +} + +type SRetentionPolicy struct { + MaxRetentionDays int + OnSourceDiskDelete string +} + +type SSnapshotProperties struct { + StorageLocations []string + GuestFlush bool +} + +type SSnapshotSchedulePolicy struct { + Schedule SSchedule + RetentionPolicy SRetentionPolicy + SnapshotProperties SSnapshotProperties +} + +type SResourcePolicy struct { + region *SRegion + SResourceBase + GoogleTags + + CreationTimestamp time.Time + Region string + Status string + Kind string + SnapshotSchedulePolicy SSnapshotSchedulePolicy `json:"snapshotSchedulePolicy"` +} + +func (region *SRegion) GetResourcePolicies(maxResults int, pageToken string) ([]SResourcePolicy, error) { + policies := []SResourcePolicy{} + resource := fmt.Sprintf("regions/%s/resourcePolicies", region.Name) + params := map[string]string{} + return policies, region.List(resource, params, maxResults, pageToken, &policies) +} + +func (region *SRegion) GetResourcePolicy(id string) (*SResourcePolicy, error) { + policy := &SResourcePolicy{region: region} + return policy, region.Get("resourcePolicies", id, policy) +} + +func (policy *SResourcePolicy) GetStatus() string { + switch policy.Status { + case "READY": + return api.SNAPSHOT_POLICY_READY + default: + log.Errorf("unknown policy status %s", policy.Status) + return api.SNAPSHOT_POLICY_UNKNOWN + } +} + +func (policy *SResourcePolicy) GetCreatedAt() time.Time { + return policy.CreationTimestamp +} + +func (policy *SResourcePolicy) Refresh() error { + _policy, err := policy.region.GetResourcePolicy(policy.Id) + if err != nil { + return err + } + return jsonutils.Update(policy, _policy) +} + +func (policy *SResourcePolicy) IsEmulated() bool { + return false +} + +func (policy *SResourcePolicy) GetProjectId() string { + return policy.region.GetProjectId() +} + +func (policy *SResourcePolicy) GetRetentionDays() int { + return policy.SnapshotSchedulePolicy.RetentionPolicy.MaxRetentionDays +} + +func (policy *SResourcePolicy) GetRepeatWeekdays() ([]int, error) { + result := []int{1, 2, 3, 4, 5, 6, 7} + if len(policy.SnapshotSchedulePolicy.Schedule.WeeklySchedule.DayOfWeeks) > 0 { + return nil, fmt.Errorf("current not support dayOfWeeks") + } + if policy.SnapshotSchedulePolicy.Schedule.HourlySchedule.HoursInCycle != 0 { + return nil, fmt.Errorf("current not support hourlySchedule") + } + return result, nil +} + +func (policy *SResourcePolicy) GetTimePoints() ([]int, error) { + result := []int{} + if len(policy.SnapshotSchedulePolicy.Schedule.DailySchedule.StartTime) == 0 { + return nil, fmt.Errorf("current only support dailySchedule") + } + if startInfo := strings.Split(policy.SnapshotSchedulePolicy.Schedule.DailySchedule.StartTime, ":"); len(startInfo) >= 2 { + point, err := strconv.Atoi(startInfo[0]) + if err != nil { + return nil, errors.Wrapf(err, "convert %s", policy.SnapshotSchedulePolicy.Schedule.DailySchedule.StartTime) + } + result = append(result, point) + if startInfo[1] != "00" { + result = append(result, point+1) + } + } + return result, nil +} + +func (policy *SResourcePolicy) IsActivated() bool { + return true +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/s3object.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/s3object.go new file mode 100644 index 0000000000..96b7c31b6d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/s3object.go @@ -0,0 +1,207 @@ +// Copyright 2019 Yunion +// +// 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. + +// Copyright 2019 Yunion + +// +// 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 google + +import ( + "context" + "fmt" + "net/http" + "net/url" + "strings" + "time" + + "cloud.google.com/go/storage" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SBucketObjects struct { + Prefixes []string + Items []SObject + NextPageToken string +} + +type SObject struct { + bucket *SBucket + + Id string + Name string + SelfLink string + MediaLink string + Bucket string + Generation string + Metageneration string + ContentType string + ContentEncoding string + ContentDisposition string + ContentLanguage string + CacheControl string + StorageClass string + Size int64 + Md5Hash string + Metadata map[string]string + Crc32c string + Etag string + TimeCreated time.Time + Updated time.Time + TimeStorageClassUpdated time.Time +} + +func (region *SRegion) GetObjects(bucket string, prefix string, nextPageToken string, delimiter string, maxCount int) (*SBucketObjects, error) { + if maxCount <= 0 { + maxCount = 20 + } + resource := fmt.Sprintf("b/%s/o", bucket) + params := map[string]string{"maxResults": fmt.Sprintf("%d", maxCount)} + if len(prefix) > 0 { + params["prefix"] = prefix + } + if len(delimiter) > 0 { + params["delimiter"] = delimiter + } + if len(nextPageToken) > 0 { + params["pageToken"] = nextPageToken + } + objs := SBucketObjects{} + resp, err := region.client.storageList(resource, params) + if err != nil { + return nil, errors.Wrap(err, "storageList") + } + err = resp.Unmarshal(&objs) + if err != nil { + return nil, errors.Wrap(err, "Unmarshal") + } + return &objs, nil +} + +func (region *SRegion) ConvertAcl(acls []GCSAcl) cloudprovider.TBucketACLType { + ret := cloudprovider.ACLPrivate + for _, acl := range acls { + if acl.Entity == string(storage.AllUsers) { + if acl.Role == string(storage.RoleOwner) || acl.Role == string(storage.RoleWriter) { + ret = cloudprovider.ACLPublicReadWrite + } + if acl.Role == string(storage.RoleReader) && ret != cloudprovider.ACLPublicReadWrite { + ret = cloudprovider.ACLPublicRead + } + } + if !(ret == cloudprovider.ACLPublicRead || ret == cloudprovider.ACLPublicReadWrite) && acl.Entity == string(storage.AllAuthenticatedUsers) { + ret = cloudprovider.ACLAuthRead + } + } + return ret +} + +func (o *SObject) GetAcl() cloudprovider.TBucketACLType { + if strings.HasSuffix(o.Name, "/") { + return cloudprovider.ACLPrivate + } + acls, err := o.bucket.region.GetObjectAcl(o.bucket.Name, o.Name) + if err != nil { + log.Errorf("failed to get object %s acls error: %v", o.Name, err) + return cloudprovider.ACLUnknown + } + return o.bucket.region.ConvertAcl(acls) +} + +func (o *SObject) SetAcl(acl cloudprovider.TBucketACLType) error { + return o.bucket.region.SetObjectAcl(o.bucket.Name, o.Name, acl) +} + +func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { + return o.bucket +} + +func (o *SObject) GetKey() string { + return o.Name +} + +func (o *SObject) GetSizeBytes() int64 { + return o.Size +} + +func (o *SObject) GetLastModified() time.Time { + return o.Updated +} + +func (o *SObject) GetStorageClass() string { + return o.StorageClass +} + +func (o *SObject) GetETag() string { + return o.Etag +} + +func (o *SObject) GetMeta() http.Header { + meta := http.Header{} + for k, v := range o.Metadata { + meta.Set(k, v) + } + for k, v := range map[string]string{ + cloudprovider.META_HEADER_CONTENT_TYPE: o.ContentType, + cloudprovider.META_HEADER_CONTENT_ENCODING: o.ContentEncoding, + cloudprovider.META_HEADER_CONTENT_DISPOSITION: o.ContentDisposition, + cloudprovider.META_HEADER_CONTENT_LANGUAGE: o.ContentLanguage, + cloudprovider.META_HEADER_CACHE_CONTROL: o.CacheControl, + } { + meta.Set(k, v) + } + return meta +} + +func (region *SRegion) SetObjectMeta(bucket, object string, meta http.Header) error { + body := map[string]string{} + for k := range meta { + switch k { + case cloudprovider.META_HEADER_CONTENT_TYPE: + body["contentType"] = meta.Get(k) + case cloudprovider.META_HEADER_CONTENT_ENCODING: + body["contentEncoding"] = meta.Get(k) + case cloudprovider.META_HEADER_CONTENT_DISPOSITION: + body["contentDisposition"] = meta.Get(k) + case cloudprovider.META_HEADER_CONTENT_LANGUAGE: + body["contentLanguage"] = meta.Get(k) + case cloudprovider.META_HEADER_CACHE_CONTROL: + body["cacheControl"] = meta.Get(k) + default: + body[fmt.Sprintf("metadata.%s", k)] = meta.Get(k) + } + } + resource := fmt.Sprintf("b/%s/o/%s", bucket, url.PathEscape(object)) + return region.StoragePut(resource, jsonutils.Marshal(body), nil) +} + +func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { + return o.bucket.region.SetObjectMeta(o.bucket.Name, o.Name, meta) +} diff --git a/pkg/multicloud/google/saml.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/saml.go similarity index 100% rename from pkg/multicloud/google/saml.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/google/saml.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/securitygroup.go new file mode 100644 index 0000000000..d9a36f2cd9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/securitygroup.go @@ -0,0 +1,429 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + SECGROUP_TYPE_SERVICE_ACCOUNT = "serviceAccount" + SECGROUP_TYPE_TAG = "tag" +) + +type SFirewallAction struct { + IPProtocol string + Ports []string +} + +type SFirewall struct { + Id string + CreationTimestamp time.Time + Name string + Description string + Network string + Priority int + SourceRanges []string + DestinationRanges []string + TargetServiceAccounts []string + TargetTags []string + Allowed []SFirewallAction + Denied []SFirewallAction + Direction string + Disabled bool + SelfLink string + Kind string +} + +type SSecurityGroup struct { + multicloud.SSecurityGroup + GoogleTags + gvpc *SGlobalNetwork + + ServiceAccount string + Tag string +} + +func (self *SGoogleClient) GetFirewalls(network string, maxResults int, pageToken string) ([]SFirewall, error) { + firewalls := []SFirewall{} + params := map[string]string{"filter": "disabled = false"} + resource := "global/firewalls" + if len(network) > 0 { + params["filter"] = fmt.Sprintf(`(disabled = false) AND (network="%s")`, network) + } + return firewalls, self._ecsListAll("GET", resource, params, &firewalls) +} + +func (self *SGoogleClient) GetFirewall(id string) (*SFirewall, error) { + firewall := &SFirewall{} + return firewall, self.ecsGet("global/firewalls", id, firewall) +} + +func (firewall *SFirewall) _toRules(action secrules.TSecurityRuleAction) ([]cloudprovider.SecurityRule, error) { + rules := []cloudprovider.SecurityRule{} + list := firewall.Allowed + if action == secrules.SecurityRuleDeny { + list = firewall.Denied + } + for _, allow := range list { + rule := cloudprovider.SecurityRule{ + ExternalId: firewall.SelfLink, + SecurityRule: secrules.SecurityRule{ + Action: action, + Direction: secrules.DIR_IN, + Priority: firewall.Priority, + }, + } + if firewall.Direction == "EGRESS" { + rule.Direction = secrules.DIR_OUT + } + switch allow.IPProtocol { + case "tcp", "udp", "icmp": + rule.Protocol = allow.IPProtocol + case "all": + rule.Protocol = secrules.PROTO_ANY + default: + return nil, fmt.Errorf("unsupport protocol %s", allow.IPProtocol) + } + ipRanges := firewall.SourceRanges + if rule.Direction == secrules.DIR_OUT { + ipRanges = firewall.DestinationRanges + } + for _, ipRange := range ipRanges { + rule.ParseCIDR(ipRange) + ports := []int{} + for _, port := range allow.Ports { + if strings.Index(port, "-") > 0 { + port = strings.Replace(port, "0-", "1-", 1) + err := rule.ParsePorts(port) + if err != nil { + return nil, errors.Wrapf(err, "Parse port %s", port) + } + rules = append(rules, rule) + } else { + _port, err := strconv.Atoi(port) + if err != nil { + return nil, errors.Wrapf(err, "Atio port %s", port) + } + ports = append(ports, _port) + } + } + if len(ports) > 0 { + rule.Ports = ports + rule.PortStart = -1 + rule.PortEnd = -1 + rules = append(rules, rule) + } + if len(allow.Ports) == 0 { + rule.Ports = []int{} + rule.PortStart = -1 + rule.PortEnd = -1 + rules = append(rules, rule) + } + } + } + return rules, nil +} + +func (firewall *SFirewall) toRules() ([]cloudprovider.SecurityRule, error) { + rules := []cloudprovider.SecurityRule{} + _rules, err := firewall._toRules(secrules.SecurityRuleAllow) + if err != nil { + return nil, err + } + rules = append(rules, _rules...) + _rules, err = firewall._toRules(secrules.SecurityRuleDeny) + if err != nil { + return nil, err + } + rules = append(rules, _rules...) + return rules, nil +} + +func (secgroup *SSecurityGroup) GetId() string { + return secgroup.gvpc.GetGlobalId() +} + +func (secgroup *SSecurityGroup) GetGlobalId() string { + if len(secgroup.Tag) > 0 { + return fmt.Sprintf("%s/%s/%s", secgroup.GetId(), SECGROUP_TYPE_TAG, secgroup.Tag) + } + if len(secgroup.ServiceAccount) > 0 { + return fmt.Sprintf("%s/%s/%s", secgroup.GetId(), SECGROUP_TYPE_SERVICE_ACCOUNT, secgroup.ServiceAccount) + } + return secgroup.GetId() +} + +func (secgroup *SSecurityGroup) GetDescription() string { + return "" +} + +func (secgroup *SSecurityGroup) GetName() string { + if len(secgroup.Tag) > 0 { + return secgroup.Tag + } + if len(secgroup.ServiceAccount) > 0 { + return secgroup.ServiceAccount + } + return secgroup.gvpc.Name +} + +func (secgroup *SSecurityGroup) GetStatus() string { + return "" +} + +func (secgroup *SSecurityGroup) IsEmulated() bool { + return false +} + +func (secgroup *SSecurityGroup) Refresh() error { + return nil +} + +func (secgroup *SSecurityGroup) Delete() error { + rules, err := secgroup.GetRules() + if err != nil { + return errors.Wrap(err, "GetRules") + } + for _, rule := range rules { + err = secgroup.gvpc.client.DeleteSecgroupRule(rule) + if err != nil { + return errors.Wrapf(err, "DeleteSecgroupRule(%s)", rule.Description) + } + } + return nil +} + +func (secgroup *SSecurityGroup) GetProjectId() string { + return "" +} + +func (secgroup *SSecurityGroup) GetVpcId() string { + return secgroup.gvpc.GetGlobalId() +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + _firewalls, err := self.gvpc.client.GetFirewalls(self.gvpc.SelfLink, 0, "") + if err != nil { + return nil, err + } + firewalls := []SFirewall{} + for _, firewall := range _firewalls { + if len(self.Tag) > 0 && utils.IsInStringArray(self.Tag, firewall.TargetTags) { + firewalls = append(firewalls, firewall) + } else if len(self.ServiceAccount) > 0 && utils.IsInStringArray(self.ServiceAccount, firewall.TargetServiceAccounts) { + firewalls = append(firewalls, firewall) + } else { + if len(self.Tag) == 0 && len(self.ServiceAccount) == 0 && len(firewall.TargetServiceAccounts) == 0 && len(firewall.TargetTags) == 0 { + firewalls = append(firewalls, firewall) + } + } + } + rules := []cloudprovider.SecurityRule{} + for _, firewall := range firewalls { + if firewall.Priority == 65535 { // skip 65535 rule, because it not work + continue + } + _rules, err := firewall.toRules() + if err != nil { + return nil, err + } + rules = append(rules, _rules...) + } + return rules, nil +} + +func (self *SGoogleClient) DeleteSecgroupRule(rule cloudprovider.SecurityRule) error { + firwall, err := self.GetFirewall(rule.ExternalId) + if err != nil { + return errors.Wrap(err, "region.GetFirewall") + } + currentRule, err := firwall.toRules() + if err != nil { + return errors.Wrap(err, "firwall.toRules") + } + if len(currentRule) > 1 { + for _, _rule := range currentRule { + if _rule.String() != rule.String() { + for _, tag := range firwall.TargetTags { + err = self.CreateSecurityGroupRule(_rule, firwall.Network, tag, "") + if err != nil { + return errors.Wrap(err, "region.CreateSecurityGroupRule") + } + } + for _, serviceAccount := range firwall.TargetServiceAccounts { + err = self.CreateSecurityGroupRule(_rule, firwall.Network, "", serviceAccount) + if err != nil { + return errors.Wrap(err, "region.CreateSecurityGroupRule") + } + } + if len(firwall.TargetTags)+len(firwall.TargetServiceAccounts) == 0 { + err = self.CreateSecurityGroupRule(_rule, firwall.Network, "", "") + if err != nil { + return errors.Wrap(err, "region.CreateSecurityGroupRule") + } + } + } + } + } + return self.ecsDelete(firwall.SelfLink, nil) +} + +func (secgroup *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + for _, r := range append(inDels, outDels...) { + err := secgroup.gvpc.client.DeleteSecgroupRule(r) + if err != nil { + return errors.Wrap(err, "DeleteSecgroupRule") + } + } + for _, r := range append(inAdds, outAdds...) { + err := secgroup.gvpc.client.CreateSecurityGroupRule(r, secgroup.gvpc.SelfLink, secgroup.Tag, secgroup.ServiceAccount) + if err != nil { + return errors.Wrapf(err, "CreateSecurityGroupRule(%s)", r.String()) + } + } + return nil +} + +func (region *SRegion) GetISecurityGroupById(id string) (cloudprovider.ICloudSecurityGroup, error) { + vpcs, err := region.GetIVpcs() + if err != nil { + return nil, errors.Wrap(err, "GetIVpcs") + } + + for _, vpc := range vpcs { + secgroups, err := vpc.GetISecurityGroups() + if err != nil { + return nil, errors.Wrap(err, "GetISecurityGroups") + } + for _, secgroup := range secgroups { + if secgroup.GetGlobalId() == id { + return secgroup, nil + } + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + ivpc, err := region.GetIVpcById(opts.VpcId) + if err != nil { + return nil, err + } + secgroups, err := ivpc.GetISecurityGroups() + if err != nil { + return nil, errors.Wrap(err, "ivpc.GetISecurityGroups") + } + for _, secgroup := range secgroups { + if strings.ToLower(secgroup.GetName()) == strings.ToLower(opts.Name) { + return secgroup, nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SGoogleClient) CreateSecurityGroupRule(rule cloudprovider.SecurityRule, vpcId string, tag string, serviceAccount string) error { + name := fmt.Sprintf("%s-%d", rule.String(), rule.Priority) + if len(tag) > 0 { + name = fmt.Sprintf("%s-%s", tag, name) + } + if len(serviceAccount) > 0 { + name = fmt.Sprintf("%s-%s", serviceAccount, name) + } + + body := map[string]interface{}{ + "name": strings.ToLower(name), + "priority": rule.Priority, + "network": vpcId, + "direction": "INGRESS", + } + if len(tag) > 0 { + body["targetTags"] = []string{strings.ToLower(tag)} + } + if len(serviceAccount) > 0 { + body["targetServiceAccounts"] = []string{serviceAccount} + } + if rule.Direction == secrules.DIR_OUT { + body["direction"] = "EGRESS" + } else { + body["sourceRanges"] = []string{rule.IPNet.String()} + } + + protocol := strings.ToLower(rule.Protocol) + if protocol == secrules.PROTO_ANY { + protocol = "all" + } + + ports := []string{} + if len(rule.Ports) > 0 { + for _, port := range rule.Ports { + ports = append(ports, fmt.Sprintf("%d", port)) + } + } else if rule.PortStart > 0 && rule.PortEnd > 0 { + if rule.PortStart == rule.PortEnd { + ports = append(ports, fmt.Sprintf("%d", rule.PortStart)) + } else { + ports = append(ports, fmt.Sprintf("%d-%d", rule.PortStart, rule.PortEnd)) + } + } + + actionInfo := []struct { + IPProtocol string + Ports []string + }{ + { + IPProtocol: protocol, + Ports: ports, + }, + } + + if rule.Action == secrules.SecurityRuleDeny { + body["denied"] = actionInfo + } else { + body["allowed"] = actionInfo + } + + firwall := &SFirewall{} + err := self.Insert("global/firewalls", jsonutils.Marshal(body), firwall) + if err != nil { + if strings.Index(err.Error(), "already exists") >= 0 { + return nil + } + return errors.Wrap(err, "region.Insert") + } + return nil +} + +func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + gvpc, err := region.client.GetGlobalNetwork(conf.VpcId) + if err != nil { + return nil, errors.Wrapf(err, "region.GetIVpcById(%s)", conf.VpcId) + } + + secgroup := &SSecurityGroup{gvpc: gvpc, Tag: strings.ToLower(conf.Name)} + return secgroup, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/sku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/sku.go new file mode 100644 index 0000000000..69b02c4f30 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/sku.go @@ -0,0 +1,352 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +type SkuBillingCatetory struct { + ServiceDisplayName string + ResourceFamily string + ResourceGroup string + UsageType string +} + +type SkuPricingInfo struct { + Summary string + PricingExpression SPricingExpression + currencyConversionRate int + EffectiveTime time.Time +} + +type SPricingExpression struct { + UsageUnit string + UsageUnitDescription string + BaseUnit string + BaseUnitDescription string + BaseUnitConversionFactor string + DisplayQuantity int + TieredRates []STieredRate +} + +type STieredRate struct { + StartUsageAmount int + UnitPrice SUnitPrice +} + +type SUnitPrice struct { + CurrencyCode string + Units string + Nanos int +} + +type SSkuBilling struct { + Name string + SkuId string + Description string + Category SkuBillingCatetory + ServiceRegions []string + PricingInfo []SkuPricingInfo + ServiceProviderName string +} + +func (region *SRegion) ListSkuBilling(pageSize int, pageToken string) ([]SSkuBilling, error) { + skus := []SSkuBilling{} + params := map[string]string{} + err := region.BillingList("services/6F81-5844-456A/skus", params, pageSize, pageToken, &skus) + if err != nil { + return nil, err + } + return skus, nil +} + +type SRateInfo struct { + // region: europe-north1 + // family: Compute, Storage, Network + // resource: CPU, Ram, Gpu, N1Standard + // category: custome, predefine, optimized + // startUsageAmount: + // map[region]map[family]map[resource]map[category]map[startUsageAmount][money] + + Info map[string]map[string]map[string]map[string]map[string]float64 +} + +func (region *SRegion) GetSkuRateInfo(skus []SSkuBilling) SRateInfo { + result := SRateInfo{ + Info: map[string]map[string]map[string]map[string]map[string]float64{}, + } + for _, sku := range skus { + if sku.ServiceProviderName == "Google" && + sku.Category.ServiceDisplayName == "Compute Engine" && + utils.IsInStringArray(sku.Category.ResourceFamily, []string{"Compute", "Storage"}) && + sku.Category.UsageType == "OnDemand" { + for _, region := range sku.ServiceRegions { + if _, ok := result.Info[region]; !ok { + result.Info[region] = map[string]map[string]map[string]map[string]float64{} + } + if _, ok := result.Info[region][sku.Category.ResourceFamily]; !ok { + result.Info[region][sku.Category.ResourceFamily] = map[string]map[string]map[string]float64{} + } + if sku.Category.ResourceGroup == "N1Standard" { + if strings.Index(sku.Description, "Core") > 0 { + sku.Category.ResourceGroup = "CPU" + } else if strings.Index(sku.Description, "Ram") > 0 { + sku.Category.ResourceGroup = "RAM" + } + } + if !utils.IsInStringArray(sku.Category.ResourceGroup, []string{"F1Micro", "G1Small", "CPU", "RAM", "PDStandard", "SSD", "LocalSSD", "f1-micro", "g1-small"}) { + continue + } + if utils.IsInStringArray(sku.Category.ResourceGroup, []string{"PDStandard", "SSD"}) && strings.Index(sku.Description, "Regional") >= 0 { + continue + } + convers := map[string]string{ + "PDStandard": api.STORAGE_GOOGLE_PD_STANDARD, + "SSD": api.STORAGE_GOOGLE_PD_SSD, + "LocalSSD": api.STORAGE_GOOGLE_LOCAL_SSD, + "F1Micro": "f1-micro", + "G1Small": "g1-small", + } + if group, ok := convers[sku.Category.ResourceGroup]; ok { + sku.Category.ResourceGroup = group + } + + if _, ok := result.Info[region][sku.Category.ResourceFamily][sku.Category.ResourceGroup]; !ok { + result.Info[region][sku.Category.ResourceFamily][sku.Category.ResourceGroup] = map[string]map[string]float64{} + } + description := strings.ToLower(sku.Description) + if strings.Contains("sole", description) { //单租户 + continue + } + category := "" + keys := []string{"memory optimized", "memory-optimized", "compute optimized", "n1 predefined", "n2 instance", "n2 custom extended", "custom extended", "n2 custom", "custom instance"} + categories := map[string]string{ + "memory optimized": "ultramem", + "memory-optimized": "memory-optimized", + "compute optimized": "compute-optimized", + + "n1 predefined": "n1-predefined", + "n2 instance": "n2-instance", + + "n2 custom extended": "n2-custom-extended", + "custom extended": "custom-extended", + + "n2 custom": "n2-custom", //cpu ram + "custom instance": "custom-instance", //cpu + } + for _, key := range keys { + _category := categories[key] + if strings.Contains(description, key) { + category = _category + break + } + } + if utils.IsInStringArray(sku.Category.ResourceGroup, []string{api.STORAGE_GOOGLE_PD_STANDARD, api.STORAGE_GOOGLE_PD_SSD, api.STORAGE_GOOGLE_LOCAL_SSD, "f1-micro", "g1-small"}) { + category = sku.Category.ResourceGroup + } + if len(category) == 0 { + continue + } + if _, ok := result.Info[region][sku.Category.ResourceFamily][sku.Category.ResourceGroup][category]; !ok { + result.Info[region][sku.Category.ResourceFamily][sku.Category.ResourceGroup][category] = map[string]float64{} + } + for _, priceInfo := range sku.PricingInfo { + for _, price := range priceInfo.PricingExpression.TieredRates { + result.Info[region][sku.Category.ResourceFamily][sku.Category.ResourceGroup][category][fmt.Sprintf("%d", price.StartUsageAmount)] = float64(price.UnitPrice.Nanos) / 1000000000 + } + } + } + } + } + return result +} + +func (rate *SRateInfo) GetDiscount(sku string) []float64 { + if strings.Index(sku, "custom") < 0 && strings.HasPrefix(sku, "c") || strings.Index(sku, "n2") >= 0 { + return []float64{0, 0.15, 0.25, 0.4} + } + return []float64{0, 0.2, 0.4, 0.6} +} + +func (rate *SRateInfo) GetSkuType(sku string) (string, error) { + if strings.Index(sku, "custom") >= 0 { + cpuType := "custom-instance" + if strings.HasPrefix(sku, "n2") { + cpuType = "n2-custom" + } + return cpuType, nil + } + if strings.HasPrefix(sku, "n1") { + return "n1-predefined", nil + } + if strings.HasPrefix(sku, "n2") { + return "n2-instance", nil + } + if strings.HasPrefix(sku, "c") { + return "compute-optimized", nil + } + if strings.HasPrefix(sku, "m") { + return "memory-optimized", nil + } + return "", fmt.Errorf("failed to found sku %s type", sku) +} + +func (rate *SRateInfo) GetCpuPrice(regionId, cpuType string) (float64, error) { + computePrice, err := rate.GetComputePrice(regionId) + if err != nil { + return 0, errors.Wrap(err, "GetComputePrice") + } + + _cpuPrice, ok := computePrice["CPU"] + if !ok { + return 0, fmt.Errorf("failed to found region %s compute cpu price info", regionId) + } + + cpuPrice, ok := _cpuPrice[cpuType] + if !ok { + return 0, fmt.Errorf("failed to found region %s compute %s cpu price info", regionId, cpuType) + } + return cpuPrice["0"], nil +} + +func (rate *SRateInfo) GetExtendMemoryGb(sku string, cpu int, memoryMb int) float64 { + maxMemoryGb := 0.0 + if strings.Index(sku, "custom") >= 0 { + maxMemoryGb = float64(cpu) * 6.5 + if strings.Index(sku, "n2") >= 0 { + maxMemoryGb = float64(cpu) * 8 + } + } + if float64(memoryMb)/1024 > maxMemoryGb { + return float64(memoryMb)/1024 - maxMemoryGb + } + return 0.0 +} + +func (rate *SRateInfo) GetMemoryPrice(regionId string, memoryType string) (float64, error) { + computePrice, err := rate.GetComputePrice(regionId) + if err != nil { + return 0, errors.Wrap(err, "GetComputePrice") + } + + _memoryPrice, ok := computePrice["RAM"] + if !ok { + return 0, fmt.Errorf("failed to found region %s compute memory price info", regionId) + } + + memoryPrice, ok := _memoryPrice[memoryType] + if !ok { + return 0, fmt.Errorf("failed to found region %s compute %s memory price info", regionId, memoryType) + } + return memoryPrice["0"], nil +} + +func (rate *SRateInfo) GetComputePrice(regionId string) (map[string]map[string]map[string]float64, error) { + regionPrice, ok := rate.Info[regionId] + if !ok { + return nil, fmt.Errorf("failed to found region %s price info", regionId) + } + computePrice, ok := regionPrice["Compute"] + if !ok { + return nil, fmt.Errorf("failed to found region %s compute price info", regionId) + } + return computePrice, nil +} + +func (rate *SRateInfo) GetSharedSkuPrice(regionId string, sku string) (float64, error) { + computePrice, err := rate.GetComputePrice(regionId) + if err != nil { + return 0.0, errors.Wrap(err, "GetComputePrice") + } + if _sharedSku, ok := computePrice[sku]; ok { + if sharedSku, ok := _sharedSku[sku]; ok { + return sharedSku["0"], nil + } + } + return 0.0, fmt.Errorf("sku is not shared sku") +} + +func (rate *SRateInfo) GetSkuPrice(regionId string, sku string, cpu, memoryMb int) (struct { + Hour float64 + Month float64 + Year float64 +}, error) { + result := struct { + Hour float64 + Month float64 + Year float64 + }{} + + discount := rate.GetDiscount(sku) + + price, err := rate.GetSharedSkuPrice(regionId, sku) + if err != nil { + skuType, err := rate.GetSkuType(sku) + if err != nil { + return result, errors.Wrap(err, "GetSkuType") + } + + cpuPrice, err := rate.GetCpuPrice(regionId, skuType) + if err != nil { + return result, errors.Wrap(err, "price.GetCpuPrice") + } + + price += float64(cpu) * cpuPrice + log.Debugf("cpu price: %f", cpuPrice) + + extendMemoryGb := rate.GetExtendMemoryGb(sku, cpu, memoryMb) + memoryMb = int(float64(memoryMb) - 1024*extendMemoryGb) + + memoryPrice, err := rate.GetMemoryPrice(regionId, skuType) + if err != nil { + return result, errors.Wrap(err, "GetMemoryPrice") + } + + price += memoryPrice * float64(memoryMb/1024) + log.Debugf("ramPrice: %f", memoryPrice) + + if extendMemoryGb > 0 { + memoryType := "custom-extended" + if strings.HasPrefix(sku, "n2") { + memoryType = "n2-custom-extended" + } + extendPrice, err := rate.GetMemoryPrice(regionId, memoryType) + if err != nil { + return result, errors.Wrap(err, "GetMemoryPrice.Extend") + } + price += extendPrice * float64(extendMemoryGb) + log.Debugf("extendPrice: %f", extendPrice) + } + } + + log.Debugf("totalPrice: %f", price) + + result.Month = 182.5 * price + result.Month += 182.5 * (1 - discount[1]) * price + result.Month += 182.5 * (1 - discount[2]) * price + result.Month += 172.49999999999997 * (1 - discount[3]) * price + result.Hour = result.Month / 30 / 24 + result.Year = result.Month * 12 + return result, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/snapshot.go new file mode 100644 index 0000000000..e739b3ae2b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/snapshot.go @@ -0,0 +1,113 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +type SSnapshot struct { + region *SRegion + SResourceBase + GoogleTags + + CreationTimestamp time.Time + Status string + SourceDisk string + SourceDiskId string + DiskSizeGb int32 + StorageBytes int + StorageBytesStatus string + Licenses []string + LabelFingerprint string + LicenseCodes []string + StorageLocations []string + Kind string +} + +func (region *SRegion) GetSnapshots(disk string, maxResults int, pageToken string) ([]SSnapshot, error) { + snapshots := []SSnapshot{} + params := map[string]string{} + if len(disk) > 0 { + params["filter"] = fmt.Sprintf(`sourceDisk="%s"`, disk) + } + resource := "global/snapshots" + return snapshots, region.List(resource, params, maxResults, pageToken, &snapshots) +} + +func (region *SRegion) GetSnapshot(id string) (*SSnapshot, error) { + snapshot := &SSnapshot{region: region} + return snapshot, region.Get("global/snapshots", id, snapshot) +} + +// CREATING, DELETING, FAILED, READY, or UPLOADING +func (snapshot *SSnapshot) GetStatus() string { + switch snapshot.Status { + case "CREATING": + return api.SNAPSHOT_CREATING + case "DELETING": + return api.SNAPSHOT_DELETING + case "FAILED": + return api.SNAPSHOT_UNKNOWN + case "READY", "UPLOADING": + return api.SNAPSHOT_READY + default: + return api.SNAPSHOT_UNKNOWN + } +} + +func (snapshot *SSnapshot) IsEmulated() bool { + return false +} + +func (self *SSnapshot) GetCreatedAt() time.Time { + return self.CreationTimestamp +} + +func (snapshot *SSnapshot) Refresh() error { + _snapshot, err := snapshot.region.GetSnapshot(snapshot.Id) + if err != nil { + return err + } + return jsonutils.Update(snapshot, _snapshot) +} + +func (snapshot *SSnapshot) GetSizeMb() int32 { + return snapshot.DiskSizeGb * 1024 +} + +func (snapshot *SSnapshot) GetDiskId() string { + return snapshot.SourceDisk +} + +func (snapshot *SSnapshot) GetDiskType() string { + if len(snapshot.Licenses) > 0 { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +func (snapshot *SSnapshot) Delete() error { + return snapshot.region.Delete(snapshot.SelfLink) +} + +func (snapshot *SSnapshot) GetProjectId() string { + return snapshot.region.GetProjectId() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/storage.go new file mode 100644 index 0000000000..3082b8e427 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/storage.go @@ -0,0 +1,155 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SStorage struct { + zone *SZone + SResourceBase + GoogleTags + + CreationTimestamp time.Time + Description string + ValidDiskSize string + Zone string + DefaultDiskSizeGb string + Kind string +} + +func (region *SRegion) GetStorages(zone string, maxResults int, pageToken string) ([]SStorage, error) { + storages := []SStorage{} + if len(zone) == 0 { + return nil, fmt.Errorf("zone params can not be empty") + } + resource := fmt.Sprintf("zones/%s/diskTypes", zone) + params := map[string]string{} + return storages, region.List(resource, params, maxResults, pageToken, &storages) +} + +func (region *SRegion) GetStorage(id string) (*SStorage, error) { + storage := &SStorage{} + return storage, region.GetBySelfId(id, storage) +} + +func (storage *SStorage) GetName() string { + return storage.Description +} + +func (storage *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (storage *SStorage) IsEmulated() bool { + return true +} + +func (self *SStorage) GetCreatedAt() time.Time { + return time.Time{} +} + +func (storage *SStorage) Refresh() error { + _storage, err := storage.zone.region.GetStorage(storage.SelfLink) + if err != nil { + return err + } + return jsonutils.Update(storage, _storage) +} + +func (storage *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return storage.zone.region.getStoragecache() +} + +func (storage *SStorage) GetIZone() cloudprovider.ICloudZone { + return storage.zone +} + +func (storage *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := storage.zone.region.GetDisks(storage.zone.Name, storage.Name, 0, "") + if err != nil { + return nil, err + } + idisks := []cloudprovider.ICloudDisk{} + for i := range disks { + disks[i].storage = storage + idisks = append(idisks, &disks[i]) + } + return idisks, nil +} + +func (storage *SStorage) GetStorageType() string { + return storage.Name +} + +func (storage *SStorage) GetMediumType() string { + return api.DISK_TYPE_SSD +} + +func (storage *SStorage) GetCapacityMB() int64 { + return 0 +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (storage *SStorage) GetStorageConf() jsonutils.JSONObject { + return jsonutils.Marshal(map[string]string{ + "ValidDiskSize": storage.ValidDiskSize, + "DefaultDiskSizeGb": storage.DefaultDiskSizeGb, + }) +} + +func (storage *SStorage) GetEnabled() bool { + return true +} + +func (storage *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disk, err := storage.zone.region.GetDisk(id) + if err != nil { + return nil, err + } + disk.storage = storage + return disk, nil +} + +func (storage *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + disk, err := storage.zone.region.CreateDisk(conf.Name, conf.SizeGb, storage.zone.Name, storage.Name, "", conf.Desc) + if err != nil { + return nil, err + } + disk.storage = storage + return disk, nil +} + +func (storage *SStorage) GetMountPoint() string { + return "" +} + +func (storage *SStorage) IsSysDiskStore() bool { + return storage.Name != api.STORAGE_GOOGLE_LOCAL_SSD +} + +func (storage *SStorage) DisableSync() bool { + return false +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/storagecache.go new file mode 100644 index 0000000000..98bdf939cd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/storagecache.go @@ -0,0 +1,210 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "context" + "fmt" + "strings" + "unicode" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/image/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +type SStoragecache struct { + multicloud.SResourceBase + GoogleTags + region *SRegion + + iimages []cloudprovider.ICloudImage +} + +func (cache *SStoragecache) GetId() string { + return cache.region.client.cpcfg.Id +} + +func (cache *SStoragecache) GetName() string { + return cache.region.client.cpcfg.Name +} + +func (cache *SStoragecache) GetStatus() string { + return "available" +} + +func (cache *SStoragecache) Refresh() error { + return nil +} + +func (cache *SStoragecache) GetGlobalId() string { + return cache.region.client.cpcfg.Id +} + +func (cache *SStoragecache) IsEmulated() bool { + return true +} + +func (cache *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (cache *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + images, err := cache.region.GetImages(cache.region.client.projectId, 1000, "") + if err != nil { + return nil, errors.Wrapf(err, "GetImages") + } + ret := []cloudprovider.ICloudImage{} + for i := range images { + images[i].storagecache = cache + ret = append(ret, &images[i]) + } + return ret, nil +} + +func (cache *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + image, err := cache.region.GetImage(extId) + if err != nil { + return nil, err + } + return image, nil +} + +func (cache *SStoragecache) GetPath() string { + return "" +} + +func (cache *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return cache.uploadImage(ctx, userCred, image, callback) +} + +func (region *SRegion) checkAndCreateBucket(bucketName string) (*SBucket, error) { + bucket, err := region.GetBucket(bucketName) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + bucket, err = region.CreateBucket(bucketName, "", cloudprovider.ACLPrivate) + if err != nil { + return nil, errors.Wrapf(err, "region.CreateBucket(%s)", bucketName) + } + } else { + return nil, errors.Wrapf(err, "region.StorageGet(%s)", bucketName) + } + } + return bucket, nil +} + +func (cache *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + s := auth.GetAdminSession(ctx, options.Options.Region) + + meta, reader, sizeBytes, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false) + if err != nil { + return "", err + } + log.Infof("meta data %s", meta) + + info := struct { + Id string + Name string + Size int64 + Description string + }{} + meta.Unmarshal(&info) + + bucketName := fmt.Sprintf("imagecache-%s", info.Id) + bucket, err := cache.region.checkAndCreateBucket(bucketName) + if err != nil { + return "", errors.Wrapf(err, "checkAndCreateBucket(%s)", bucketName) + } + + defer cache.region.DeleteBucket(bucket.Name) + + log.Debugf("To upload image to bucket %s ...", bucketName) + body := multicloud.NewProgress(sizeBytes, 80, reader, callback) + err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeBytes, "", "", nil, false) + if err != nil { + return "", errors.Wrap(err, "UploadObjectWithProgress") + } + + images, err := cache.region.GetImages(cache.region.GetProjectId(), 0, "") + if err != nil { + return "", errors.Wrap(err, "region.GetImages") + } + imageNames := []string{} + for _, image := range images { + imageNames = append(imageNames, image.Name) + } + + imageName := "img-" + for _, s := range strings.ToLower(info.Name) { + if unicode.IsDigit(s) || unicode.IsLetter(s) || s == '-' { + imageName = fmt.Sprintf("%s%c", imageName, s) + } else { + imageName = fmt.Sprintf("%s-", imageName) + } + } + + baseName := imageName + for i := 0; i < 30; i++ { + if !utils.IsInStringArray(imageName, imageNames) { + break + } + imageName = fmt.Sprintf("%s-%d", baseName, i) + } + + _image, err := cache.region.CreateImage(imageName, info.Description, bucketName, info.Name) + if err != nil { + return "", errors.Wrap(err, "region.CreateImage") + } + + if callback != nil { + callback(100) + } + + return _image.GetGlobalId(), nil +} + +func (cache *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (cache *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + cache := &SStoragecache{region: region} + return []cloudprovider.ICloudStoragecache{cache}, nil +} + +func (region *SRegion) getStoragecache() *SStoragecache { + return &SStoragecache{region: region} +} + +func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + cache := region.getStoragecache() + if id == cache.GetGlobalId() { + return cache, nil + } + return nil, cloudprovider.ErrNotFound +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/tag_base.go new file mode 100644 index 0000000000..838c8b6c04 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/tag_base.go @@ -0,0 +1,53 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/util/encode" +) + +type GoogleTags struct { + Labels map[string]string +} + +func (self *GoogleTags) GetTags() (map[string]string, error) { + ret := map[string]string{} + for k, v := range self.Labels { + if strings.HasPrefix(k, "goog-") { + continue + } + ret[encode.DecodeGoogleLable(k)] = encode.DecodeGoogleLable(v) + } + return ret, nil +} + +func (self *GoogleTags) GetSysTags() map[string]string { + ret := map[string]string{} + for k, v := range self.Labels { + if strings.HasPrefix(k, "goog-") { + ret[k] = v + } + } + return ret +} + +func (self *GoogleTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/vpc.go new file mode 100644 index 0000000000..c5381a66d4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/vpc.go @@ -0,0 +1,170 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + GoogleTags + SResourceBase + + region *SRegion + + CreationTimestamp time.Time + Network string + IpCidrRange string + Region string + GatewayAddress string + Status string + AvailableCpuPlatforms []string + PrivateIpGoogleAccess bool + Fingerprint string + Purpose string + Kind string +} + +func (self *SVpc) GetGlobalVpcId() string { + gvpc := &SGlobalNetwork{} + err := self.region.GetBySelfId(self.Network, gvpc) + if err != nil { + return "" + } + return gvpc.Id +} + +func (self *SVpc) Refresh() error { + vpc, err := self.region.GetVpc(self.Id) + if err != nil { + return errors.Wrapf(err, "GetVpc") + } + return jsonutils.Update(self, vpc) +} + +func (self *SRegion) GetVpc(id string) (*SVpc, error) { + vpc := &SVpc{region: self} + return vpc, self.Get("subnetworks", id, vpc) +} + +func (vpc *SVpc) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} + +func (vpc *SVpc) Delete() error { + return vpc.region.Delete(vpc.SelfLink) +} + +func (vpc *SVpc) GetCidrBlock() string { + return vpc.IpCidrRange +} + +func (vpc *SVpc) IsEmulated() bool { + return false +} + +func (vpc *SVpc) GetIsDefault() bool { + return false +} + +func (vpc *SVpc) GetRegion() cloudprovider.ICloudRegion { + return vpc.region +} + +func (vpc *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (vpc *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + firewalls, err := vpc.region.client.GetFirewalls(vpc.Network, 0, "") + if err != nil { + return nil, errors.Wrap(err, "GetFirewalls") + } + gvpc := &SGlobalNetwork{client: vpc.region.client} + err = vpc.region.GetBySelfId(vpc.Network, gvpc) + if err != nil { + return nil, errors.Wrapf(err, "GetGlobalNetwork") + } + isecgroups := []cloudprovider.ICloudSecurityGroup{} + allInstance := false + tags := []string{} + for _, firewall := range firewalls { + if len(firewall.TargetServiceAccounts) > 0 { + secgroup := &SSecurityGroup{gvpc: gvpc, ServiceAccount: firewall.TargetServiceAccounts[0]} + isecgroups = append(isecgroups, secgroup) + } else if len(firewall.TargetTags) > 0 && !utils.IsInStringArray(firewall.TargetTags[0], tags) { + secgroup := &SSecurityGroup{gvpc: gvpc, Tag: firewall.TargetTags[0]} + tags = append(tags, firewall.TargetTags[0]) + isecgroups = append(isecgroups, secgroup) + } else if !allInstance { + secgroup := &SSecurityGroup{gvpc: gvpc} + isecgroups = append(isecgroups, secgroup) + allInstance = true + } + } + return isecgroups, nil +} + +func (vpc *SVpc) getWire() *SWire { + return &SWire{vpc: vpc} +} + +func (vpc *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + wire := vpc.getWire() + return []cloudprovider.ICloudWire{wire}, nil +} + +func (vpc *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { + if id != vpc.getWire().GetGlobalId() { + return nil, cloudprovider.ErrNotFound + } + return &SWire{vpc: vpc}, nil +} + +func (self *SRegion) CreateVpc(name string, gvpcId string, cidr string, desc string) (*SVpc, error) { + body := map[string]interface{}{ + "name": name, + "description": desc, + "network": gvpcId, + "ipCidrRange": cidr, + } + resource := fmt.Sprintf("regions/%s/subnetworks", self.Name) + vpc := &SVpc{region: self} + err := self.Insert(resource, jsonutils.Marshal(body), vpc) + if err != nil { + return nil, err + } + return vpc, nil +} + +func (self *SRegion) GetVpcs() ([]SVpc, error) { + vpcs := []SVpc{} + resource := fmt.Sprintf("regions/%s/subnetworks", self.Name) + return vpcs, self.List(resource, nil, 0, "", &vpcs) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/wire.go new file mode 100644 index 0000000000..0dd57f7abb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/wire.go @@ -0,0 +1,94 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + GoogleTags + vpc *SVpc +} + +func (wire *SWire) GetId() string { + return wire.vpc.GetGlobalId() +} + +func (wire *SWire) GetGlobalId() string { + return fmt.Sprintf("%s-%s", wire.GetId(), wire.vpc.region.Name) +} + +func (wire *SWire) GetName() string { + return wire.vpc.GetName() +} + +func (wire *SWire) GetCreatedAt() time.Time { + return time.Time{} +} + +func (wire *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (wire *SWire) GetIVpc() cloudprovider.ICloudVpc { + return wire.vpc +} + +func (wire *SWire) GetIZone() cloudprovider.ICloudZone { + return nil +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + network := SNetwork{wire: self} + return []cloudprovider.ICloudNetwork{&network}, nil +} + +func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { + networks, err := self.GetINetworks() + if err != nil { + return nil, errors.Wrapf(err, "GetINetwork") + } + for i := range networks { + if networks[i].GetGlobalId() == id { + return networks[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (wire *SWire) GetBandwidth() int { + return 0 +} + +func (wire *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (wire *SWire) IsEmulated() bool { + return true +} + +func (wire *SWire) Refresh() error { + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/zone.go new file mode 100644 index 0000000000..f82d915446 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/google/zone.go @@ -0,0 +1,128 @@ +// Copyright 2019 Yunion +// +// 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 google + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SZone struct { + multicloud.SResourceBase + GoogleTags + region *SRegion + + Description string + ID string + Kind string + Name string + Region string + SelfLink string + AvailableCpuPlatforms []string + Status string +} + +func (region *SRegion) GetZone(id string) (*SZone, error) { + zone := &SZone{region: region} + return zone, region.GetBySelfId(id, zone) +} + +func (region *SRegion) GetZones(regionId string, maxResults int, pageToken string) ([]SZone, error) { + zones := []SZone{} + params := map[string]string{} + if len(regionId) > 0 { + params["filter"] = fmt.Sprintf(`region="%s/%s/projects/%s/regions/%s"`, GOOGLE_COMPUTE_DOMAIN, GOOGLE_API_VERSION, region.GetProjectId(), regionId) + } + resource := "zones" + return zones, region.List(resource, params, maxResults, pageToken, &zones) +} + +func (zone *SZone) GetName() string { + return zone.Name +} + +func (zone *SZone) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(zone.GetName()).CN(zone.GetName()) + return table +} + +func (zone *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s", zone.region.GetGlobalId(), zone.Name) +} + +func (zone *SZone) GetId() string { + return zone.Name +} + +func (zone *SZone) GetIHostById(hostId string) (cloudprovider.ICloudHost, error) { + if hostId != zone.getHost().GetGlobalId() { + return nil, cloudprovider.ErrNotFound + } + return &SHost{zone: zone}, nil +} + +func (zone *SZone) getHost() *SHost { + return &SHost{zone: zone} +} + +func (zone *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + host := zone.getHost() + return []cloudprovider.ICloudHost{host}, nil +} + +func (zone *SZone) GetIRegion() cloudprovider.ICloudRegion { + return zone.region +} + +func (zone *SZone) GetIStorageById(storageId string) (cloudprovider.ICloudStorage, error) { + storage, err := zone.region.GetStorage(storageId) + if err != nil { + return nil, err + } + storage.zone = zone + return storage, nil +} + +func (zone *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := zone.region.GetStorages(zone.Name, 0, "") + if err != nil { + return nil, err + } + istorages := []cloudprovider.ICloudStorage{} + for i := range storages { + storages[i].zone = zone + istorages = append(istorages, &storages[i]) + } + return istorages, nil +} + +func (zone *SZone) IsEmulated() bool { + return false +} + +func (zone *SZone) Refresh() error { + return nil +} + +func (zone *SZone) GetStatus() string { + if zone.Status == "UP" { + return api.ZONE_ENABLE + } + return api.ZONE_SOLDOUT +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/bucket.go new file mode 100644 index 0000000000..5cb6c0c719 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/bucket.go @@ -0,0 +1,804 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" + + "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + "yunion.io/x/s3cli" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SBucket struct { + multicloud.SBaseBucket + huawei.HuaweiTags + + region *SRegion + + Name string + Location string + CreationDate time.Time +} + +func (b *SBucket) GetProjectId() string { + resp, err := b.region.HeadBucket(b.Name) + if err != nil { + return "" + } + epid, _ := resp.ResponseHeaders["epid"] + if len(epid) > 0 { + return epid[0] + } + return "" +} + +func (b *SBucket) GetGlobalId() string { + return b.Name +} + +func (b *SBucket) GetName() string { + return b.Name +} + +func (b *SBucket) GetLocation() string { + return b.Location +} + +func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { + return b.region +} + +func (b *SBucket) GetCreateAt() time.Time { + return b.CreationDate +} + +func (b *SBucket) GetStorageClass() string { + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("b.region.getOBSClient error %s", err) + return "" + } + output, err := obscli.GetBucketStoragePolicy(b.Name) + if err != nil { + log.Errorf("obscli.GetBucketStoragePolicy error %s", err) + return "" + } + return output.StorageClass +} + +func obsAcl2CannedAcl(acls []obs.Grant) cloudprovider.TBucketACLType { + switch { + case len(acls) == 1: + if acls[0].Grantee.URI == "" && acls[0].Permission == s3cli.PERMISSION_FULL_CONTROL { + return cloudprovider.ACLPrivate + } + case len(acls) == 2: + for _, g := range acls { + if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_AUTH_USERS && g.Permission == s3cli.PERMISSION_READ { + return cloudprovider.ACLAuthRead + } + if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_READ { + return cloudprovider.ACLPublicRead + } + } + case len(acls) == 3: + for _, g := range acls { + if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_WRITE { + return cloudprovider.ACLPublicReadWrite + } + } + } + return cloudprovider.ACLUnknown +} + +func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("b.region.getOBSClient error %s", err) + return acl + } + output, err := obscli.GetBucketAcl(b.Name) + if err != nil { + log.Errorf("obscli.GetBucketAcl error %s", err) + return acl + } + acl = obsAcl2CannedAcl(output.Grants) + return acl +} + +func (b *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "b.region.getOBSClient") + } + input := &obs.SetBucketAclInput{} + input.Bucket = b.Name + input.ACL = obs.AclType(string(acl)) + _, err = obscli.SetBucketAcl(input) + if err != nil { + return errors.Wrap(err, "obscli.SetBucketAcl") + } + return nil +} + +func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { + return []cloudprovider.SBucketAccessUrl{ + { + Url: fmt.Sprintf("https://%s.%s", b.Name, b.region.getOBSEndpoint()), + Description: "bucket url", + Primary: true, + }, + { + Url: fmt.Sprintf("https://%s/%s", b.region.getOBSEndpoint(), b.Name), + Description: "obs url", + }, + } +} + +func (b *SBucket) GetStats() cloudprovider.SBucketStats { + stats := cloudprovider.SBucketStats{} + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("b.region.getOBSClient error %s", err) + stats.SizeBytes = -1 + stats.ObjectCount = -1 + return stats + } + output, err := obscli.GetBucketStorageInfo(b.Name) + if err != nil { + log.Errorf("obscli.GetBucketStorageInfo error %s", err) + stats.SizeBytes = -1 + stats.ObjectCount = -1 + return stats + } + stats.SizeBytes = output.Size + stats.ObjectCount = output.ObjectNumber + return stats +} + +func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { + result := cloudprovider.SListObjectResult{} + obscli, err := b.region.getOBSClient() + if err != nil { + return result, errors.Wrap(err, "GetOBSClient") + } + input := &obs.ListObjectsInput{} + input.Bucket = b.Name + if len(prefix) > 0 { + input.Prefix = prefix + } + if len(marker) > 0 { + input.Marker = marker + } + if len(delimiter) > 0 { + input.Delimiter = delimiter + } + if maxCount > 0 { + input.MaxKeys = maxCount + } + oResult, err := obscli.ListObjects(input) + if err != nil { + return result, errors.Wrap(err, "ListObjects") + } + result.Objects = make([]cloudprovider.ICloudObject, 0) + for _, object := range oResult.Contents { + obj := &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + StorageClass: string(object.StorageClass), + Key: object.Key, + SizeBytes: object.Size, + ETag: object.ETag, + LastModified: object.LastModified, + }, + } + result.Objects = append(result.Objects, obj) + } + if oResult.CommonPrefixes != nil { + result.CommonPrefixes = make([]cloudprovider.ICloudObject, 0) + for _, commonPrefix := range oResult.CommonPrefixes { + obj := &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + Key: commonPrefix, + }, + } + result.CommonPrefixes = append(result.CommonPrefixes, obj) + } + } + result.IsTruncated = oResult.IsTruncated + result.NextMarker = oResult.NextMarker + return result, nil +} + +func (b *SBucket) PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.PutObjectInput{} + input.Bucket = b.Name + input.Key = key + input.Body = reader + + if sizeBytes > 0 { + input.ContentLength = sizeBytes + } + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return err + } + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.ACL = obs.AclType(string(cannedAcl)) + if meta != nil { + val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) + if len(val) > 0 { + input.ContentType = val + } + val = meta.Get(cloudprovider.META_HEADER_CONTENT_MD5) + if len(val) > 0 { + input.ContentMD5 = val + } + extraMeta := make(map[string]string) + for k, v := range meta { + if utils.IsInStringArray(k, []string{ + cloudprovider.META_HEADER_CONTENT_TYPE, + cloudprovider.META_HEADER_CONTENT_MD5, + }) { + continue + } + if len(v[0]) > 0 { + extraMeta[k] = v[0] + } + } + input.Metadata = extraMeta + } + _, err = obscli.PutObject(input) + if err != nil { + return errors.Wrap(err, "PutObject") + } + return nil +} + +func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + + input := &obs.InitiateMultipartUploadInput{} + input.Bucket = b.Name + input.Key = key + if meta != nil { + val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) + if len(val) > 0 { + input.ContentType = val + } + extraMeta := make(map[string]string) + for k, v := range meta { + if utils.IsInStringArray(k, []string{ + cloudprovider.META_HEADER_CONTENT_TYPE, + }) { + continue + } + if len(v[0]) > 0 { + extraMeta[k] = v[0] + } + } + input.Metadata = extraMeta + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.ACL = obs.AclType(string(cannedAcl)) + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return "", errors.Wrap(err, "str2StorageClass") + } + } + output, err := obscli.InitiateMultipartUpload(input) + if err != nil { + return "", errors.Wrap(err, "InitiateMultipartUpload") + } + + return output.UploadId, nil +} + +func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, part io.Reader, partSize int64, offset, totalSize int64) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + + input := &obs.UploadPartInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + input.PartNumber = partIndex + input.PartSize = partSize + input.Body = part + output, err := obscli.UploadPart(input) + if err != nil { + return "", errors.Wrap(err, "UploadPart") + } + + return output.ETag, nil +} + +func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.CompleteMultipartUploadInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + parts := make([]obs.Part, len(partEtags)) + for i := range partEtags { + parts[i] = obs.Part{ + PartNumber: i + 1, + ETag: partEtags[i], + } + } + input.Parts = parts + _, err = obscli.CompleteMultipartUpload(input) + if err != nil { + return errors.Wrap(err, "CompleteMultipartUpload") + } + + return nil +} + +func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + input := &obs.AbortMultipartUploadInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + + _, err = obscli.AbortMultipartUpload(input) + if err != nil { + return errors.Wrap(err, "AbortMultipartUpload") + } + + return nil +} + +func (b *SBucket) DeleteObject(ctx context.Context, key string) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.DeleteObjectInput{} + input.Bucket = b.Name + input.Key = key + _, err = obscli.DeleteObject(input) + if err != nil { + return errors.Wrap(err, "DeleteObject") + } + return nil +} + +func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + input := obs.CreateSignedUrlInput{} + input.Bucket = b.Name + input.Key = key + input.Expires = int(expire / time.Second) + switch method { + case "GET": + input.Method = obs.HttpMethodGet + case "PUT": + input.Method = obs.HttpMethodPut + case "DELETE": + input.Method = obs.HttpMethodDelete + default: + return "", errors.Error("unsupported method") + } + output, err := obscli.CreateSignedUrl(&input) + return output.SignedUrl, nil +} + +func (b *SBucket) LimitSupport() cloudprovider.SBucketStats { + return cloudprovider.SBucketStats{ + SizeBytes: 1, + ObjectCount: -1, + } +} + +func (b *SBucket) GetLimit() cloudprovider.SBucketStats { + stats := cloudprovider.SBucketStats{} + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("getOBSClient error %s", err) + return stats + } + output, err := obscli.GetBucketQuota(b.Name) + if err != nil { + return stats + } + stats.SizeBytes = output.Quota + return stats +} + +func (b *SBucket) SetLimit(limit cloudprovider.SBucketStats) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "getOBSClient") + } + input := &obs.SetBucketQuotaInput{} + input.Bucket = b.Name + input.Quota = limit.SizeBytes + _, err = obscli.SetBucketQuota(input) + if err != nil { + return errors.Wrap(err, "SetBucketQuota") + } + return nil +} + +func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.CopyObjectInput{} + input.Bucket = b.Name + input.Key = destKey + input.CopySourceBucket = srcBucket + input.CopySourceKey = srcKey + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return err + } + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.ACL = obs.AclType(string(cannedAcl)) + if meta != nil { + val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) + if len(val) > 0 { + input.ContentType = val + } + extraMeta := make(map[string]string) + for k, v := range meta { + if utils.IsInStringArray(k, []string{ + cloudprovider.META_HEADER_CONTENT_TYPE, + }) { + continue + } + if len(v[0]) > 0 { + extraMeta[k] = v[0] + } + } + input.Metadata = extraMeta + input.MetadataDirective = obs.ReplaceMetadata + } else { + input.MetadataDirective = obs.CopyMetadata + } + _, err = obscli.CopyObject(input) + if err != nil { + return errors.Wrap(err, "obscli.CopyObject") + } + return nil +} + +func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + input := &obs.GetObjectInput{} + input.Bucket = b.Name + input.Key = key + if rangeOpt != nil { + input.RangeStart = rangeOpt.Start + input.RangeEnd = rangeOpt.End + } + output, err := obscli.GetObject(input) + if err != nil { + return nil, errors.Wrap(err, "obscli.GetObject") + } + return output.Body, nil +} + +func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + input := &obs.CopyPartInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + input.PartNumber = partIndex + input.CopySourceBucket = srcBucket + input.CopySourceKey = srcKey + input.CopySourceRangeStart = srcOffset + input.CopySourceRangeEnd = srcOffset + srcLength - 1 + output, err := obscli.CopyPart(input) + if err != nil { + return "", errors.Wrap(err, "CopyPart") + } + return output.ETag, nil +} + +func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + obsWebConf := obs.SetBucketWebsiteConfigurationInput{} + obsWebConf.Bucket = b.Name + obsWebConf.BucketWebsiteConfiguration = obs.BucketWebsiteConfiguration{ + IndexDocument: obs.IndexDocument{Suffix: websitConf.Index}, + ErrorDocument: obs.ErrorDocument{Key: websitConf.ErrorDocument}, + } + _, err = obscli.SetBucketWebsiteConfiguration(&obsWebConf) + if err != nil { + return errors.Wrap(err, "obscli.SetBucketWebsiteConfiguration(&obsWebConf)") + } + return nil +} + +func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { + result := cloudprovider.SBucketWebsiteConf{} + obscli, err := b.region.getOBSClient() + if err != nil { + return result, errors.Wrap(err, "GetOBSClient") + } + out, err := obscli.GetBucketWebsiteConfiguration(b.Name) + if out == nil { + return result, nil + } + result.Index = out.IndexDocument.Suffix + result.ErrorDocument = out.ErrorDocument.Key + result.Url = fmt.Sprintf("https://%s.obs-website.%s.myhuaweicloud.com", b.Name, b.region.GetId()) + return result, nil +} + +func (b *SBucket) DeleteWebSiteConf() error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + _, err = obscli.DeleteBucketWebsiteConfiguration(b.Name) + if err != nil { + return errors.Wrapf(err, "obscli.DeleteBucketWebsiteConfiguration(%s)", b.Name) + } + return nil +} + +func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + opts := []obs.CorsRule{} + for i := range rules { + opts = append(opts, obs.CorsRule{ + AllowedOrigin: rules[i].AllowedOrigins, + AllowedMethod: rules[i].AllowedMethods, + AllowedHeader: rules[i].AllowedHeaders, + MaxAgeSeconds: rules[i].MaxAgeSeconds, + ExposeHeader: rules[i].ExposeHeaders, + }) + } + + input := obs.SetBucketCorsInput{} + input.Bucket = b.Name + input.BucketCors.CorsRules = opts + _, err = obscli.SetBucketCors(&input) + if err != nil { + return errors.Wrapf(err, "obscli.SetBucketCors(%s)", jsonutils.Marshal(input).String()) + } + return nil +} + +func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + conf, err := obscli.GetBucketCors(b.Name) + if err != nil { + if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") { + return nil, errors.Wrapf(err, "obscli.GetBucketCors(%s)", b.Name) + } + } + if conf == nil { + return nil, nil + } + result := []cloudprovider.SBucketCORSRule{} + for i := range conf.CorsRules { + result = append(result, cloudprovider.SBucketCORSRule{ + AllowedOrigins: conf.CorsRules[i].AllowedOrigin, + AllowedMethods: conf.CorsRules[i].AllowedMethod, + AllowedHeaders: conf.CorsRules[i].AllowedHeader, + MaxAgeSeconds: conf.CorsRules[i].MaxAgeSeconds, + ExposeHeaders: conf.CorsRules[i].ExposeHeader, + Id: strconv.Itoa(i), + }) + } + return result, nil +} + +func (b *SBucket) DeleteCORS() error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + _, err = obscli.DeleteBucketCors(b.Name) + if err != nil { + return errors.Wrapf(err, "obscli.DeleteBucketCors(%s)", b.Name) + } + return nil +} + +func (b *SBucket) GetTags() (map[string]string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + tagresult, err := obscli.GetBucketTagging(b.Name) + if err != nil { + if strings.Contains(err.Error(), "404") { + return nil, nil + } + return nil, errors.Wrapf(err, "osscli.GetBucketTagging(%s)", b.Name) + } + result := map[string]string{} + for i := range tagresult.Tags { + result[tagresult.Tags[i].Key] = tagresult.Tags[i].Value + } + return result, nil +} + +func (b *SBucket) SetTags(tags map[string]string, replace bool) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + _, err = obscli.DeleteBucketTagging(b.Name) + if err != nil { + return errors.Wrapf(err, "DeleteBucketTagging") + } + + if len(tags) == 0 { + return nil + } + + input := obs.SetBucketTaggingInput{BucketTagging: obs.BucketTagging{}} + input.Bucket = b.Name + for k, v := range tags { + input.BucketTagging.Tags = append(input.BucketTagging.Tags, obs.Tag{Key: k, Value: v}) + } + + _, err = obscli.SetBucketTagging(&input) + if err != nil { + return errors.Wrapf(err, "obscli.SetBucketTagging(%s)", jsonutils.Marshal(input).String()) + } + return nil +} + +func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + result := []cloudprovider.SBucketMultipartUploads{} + + input := obs.ListMultipartUploadsInput{Bucket: b.Name} + keyMarker := "" + uploadIDMarker := "" + for { + if len(keyMarker) > 0 { + input.KeyMarker = keyMarker + } + if len(uploadIDMarker) > 0 { + input.UploadIdMarker = uploadIDMarker + } + + output, err := obscli.ListMultipartUploads(&input) + if err != nil { + return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") + } + for i := range output.Uploads { + temp := cloudprovider.SBucketMultipartUploads{ + ObjectName: output.Uploads[i].Key, + UploadID: output.Uploads[i].UploadId, + Initiator: output.Uploads[i].Initiator.DisplayName, + Initiated: output.Uploads[i].Initiated, + } + result = append(result, temp) + } + keyMarker = output.NextKeyMarker + uploadIDMarker = output.NextUploadIdMarker + if !output.IsTruncated { + break + } + } + + return result, nil +} + +func (self *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { + return self.CreateBucket(name, storageClassStr, aclStr) +} + +func (self *SRegion) CreateBucket(name string, storageClassStr string, aclStr string) error { + obsClient, err := self.getOBSClient() + if err != nil { + return errors.Wrap(err, "self.getOBSClient") + } + input := &obs.CreateBucketInput{} + input.Bucket = name + input.Location = self.GetId() + if len(aclStr) > 0 { + if strings.EqualFold(aclStr, string(obs.AclPrivate)) { + input.ACL = obs.AclPrivate + } else if strings.EqualFold(aclStr, string(obs.AclPublicRead)) { + input.ACL = obs.AclPublicRead + } else if strings.EqualFold(aclStr, string(obs.AclPublicReadWrite)) { + input.ACL = obs.AclPublicReadWrite + } else { + return errors.Error("unsupported acl") + } + } + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return err + } + } + _, err = obsClient.CreateBucket(input) + if err != nil { + return errors.Wrap(err, "obsClient.CreateBucket") + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance.go new file mode 100644 index 0000000000..bc8f1a0603 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance.go @@ -0,0 +1,707 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type SBackupStrategy struct { + KeepDays int + StartTime string +} + +type SDatastore struct { + Type string + Version string +} + +type SHa struct { + ReplicationMode string +} + +type SNonde struct { + AvailabilityZone string + Id string + Name string + Role string + Staus string +} + +type SVolume struct { + Size int + Type string +} + +type SRelatedInstance struct { + Id string + Type string +} + +type SDBInstance struct { + multicloud.SDBInstanceBase + huawei.HuaweiTags + region *SRegion + + flavorCache []SDBInstanceFlavor + + BackupStrategy SBackupStrategy + Created string //time.Time + Datastore SDatastore + DbUserName string + DIskEncryptionId string + FlavorRef string + Ha SHa + Id string + MaintenanceWindow string + Name string + Nodes []SNonde + Port int + PrivateIps []string + PublicIps []string + Region string + RelatedInstance []SRelatedInstance + SecurityGroupId string + Status string + SubnetId string + SwitchStrategy string + TimeZone string + Type string + Updated string //time.Time + Volume SVolume + VpcId string + EnterpriseProjectId string +} + +func (region *SRegion) GetDBInstances() ([]SDBInstance, error) { + dbinstances := []SDBInstance{} + err := region.rdsList("instances", nil, nil) + return dbinstances, err +} + +func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { + if len(instanceId) == 0 { + return nil, cloudprovider.ErrNotFound + } + instance := SDBInstance{region: region} + res := &SDBInstance{} + err := region.rdsGet(fmt.Sprintf("instance/%s", instanceId), res) + return &instance, err +} + +func (rds *SDBInstance) GetName() string { + return rds.Name +} + +func (rds *SDBInstance) GetId() string { + return rds.Id +} + +func (rds *SDBInstance) GetGlobalId() string { + return rds.GetId() +} + +// 值为“BUILD”,表示实例正在创建。 +// 值为“ACTIVE”,表示实例正常。 +// 值为“FAILED”,表示实例异常。 +// 值为“FROZEN”,表示实例冻结。 +// 值为“MODIFYING”,表示实例正在扩容。 +// 值为“REBOOTING”,表示实例正在重启。 +// 值为“RESTORING”,表示实例正在恢复。 +// 值为“MODIFYING INSTANCE TYPE”,表示实例正在转主备。 +// 值为“SWITCHOVER”,表示实例正在主备切换。 +// 值为“MIGRATING”,表示实例正在迁移。 +// 值为“BACKING UP”,表示实例正在进行备份。 +// 值为“MODIFYING DATABASE PORT”,表示实例正在修改数据库端口。 +// 值为“STORAGE FULL”,表示实例磁盘空间满。 + +func (rds *SDBInstance) GetStatus() string { + switch rds.Status { + case "BUILD", "MODIFYING", "MODIFYING INSTANCE TYPE", "SWITCHOVER", "MODIFYING DATABASE PORT": + return api.DBINSTANCE_DEPLOYING + case "ACTIVE": + return api.DBINSTANCE_RUNNING + case "FAILED", "FROZEN", "STORAGE FULL": + return api.DBINSTANCE_UNKNOWN + case "REBOOTING": + return api.DBINSTANCE_REBOOTING + case "RESTORING": + return api.DBINSTANCE_RESTORING + case "MIGRATING": + return api.DBINSTANCE_MIGRATING + case "BACKING UP": + return api.DBINSTANCE_BACKING_UP + } + return rds.Status +} + +func (rds *SDBInstance) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (rds *SDBInstance) GetSecurityGroupIds() ([]string, error) { + return []string{rds.SecurityGroupId}, nil +} + +func (rds *SDBInstance) fetchFlavor() error { + if len(rds.flavorCache) > 0 { + return nil + } + flavors, err := rds.region.GetDBInstanceFlavors(rds.Datastore.Type, rds.Datastore.Version) + if err != nil { + return err + } + rds.flavorCache = flavors + return nil +} + +func (rds *SDBInstance) GetExpiredAt() time.Time { + return time.Time{} +} + +func (rds *SDBInstance) GetStorageType() string { + return rds.Volume.Type +} + +func (rds *SDBInstance) GetCreatedAt() time.Time { + t, err := time.Parse("2006-01-02T15:04:05Z0700", rds.Created) + if err != nil { + return time.Time{} + } + return t +} + +func (rds *SDBInstance) GetEngine() string { + return rds.Datastore.Type +} + +func (rds *SDBInstance) GetEngineVersion() string { + return rds.Datastore.Version +} + +func (rds *SDBInstance) GetInstanceType() string { + return rds.FlavorRef +} + +func (rds *SDBInstance) GetCategory() string { + switch rds.Type { + case "Single": + return api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE + case "Ha": + return api.HUAWEI_DBINSTANCE_CATEGORY_HA + case "Replica": + return api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA + } + return rds.Type +} + +func (rds *SDBInstance) GetVcpuCount() int { + err := rds.fetchFlavor() + if err != nil { + log.Errorf("failed to fetch flavors: %v", err) + return 0 + } + for _, flavor := range rds.flavorCache { + if flavor.SpecCode == rds.FlavorRef { + return flavor.Vcpus + } + } + return 0 +} + +func (rds *SDBInstance) GetVmemSizeMB() int { + err := rds.fetchFlavor() + if err != nil { + log.Errorf("failed to fetch flavors: %v", err) + return 0 + } + for _, flavor := range rds.flavorCache { + if flavor.SpecCode == rds.FlavorRef { + return flavor.Ram * 1024 + } + } + return 0 +} + +func (rds *SDBInstance) GetDiskSizeGB() int { + return rds.Volume.Size +} + +func (rds *SDBInstance) GetPort() int { + return rds.Port +} + +func (rds *SDBInstance) GetMaintainTime() string { + return rds.MaintenanceWindow +} + +func (rds *SDBInstance) GetIVpcId() string { + return rds.VpcId +} + +func (rds *SDBInstance) GetProjectId() string { + return rds.EnterpriseProjectId +} + +func (rds *SDBInstance) Refresh() error { + instance, err := rds.region.GetDBInstance(rds.Id) + if err != nil { + return err + } + return jsonutils.Update(rds, instance) +} + +func (rds *SDBInstance) GetZone1Id() string { + return rds.GetZoneIdByRole("master") +} + +func (rds *SDBInstance) GetZoneIdByRole(role string) string { + // for _, node := range rds.Nodes { + // if node.Role == role { + // zone, err := rds.region.getZoneById(node.AvailabilityZone) + // if err != nil { + // log.Errorf("failed to found zone %s for rds %s error: %v", node.AvailabilityZone, rds.Name, err) + // return "" + // } + // return zone.GetGlobalId() + // } + // } + return "" +} + +func (rds *SDBInstance) GetZone2Id() string { + return rds.GetZoneIdByRole("slave") +} + +func (rds *SDBInstance) GetZone3Id() string { + return "" +} + +type SRdsNetwork struct { + SubnetId string + IP string +} + +func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { + ret := []cloudprovider.SDBInstanceNetwork{} + for _, ip := range rds.PrivateIps { + network := cloudprovider.SDBInstanceNetwork{ + IP: ip, + NetworkId: rds.SubnetId, + } + ret = append(ret, network) + } + return ret, nil +} + +func (rds *SDBInstance) GetInternalConnectionStr() string { + for _, ip := range rds.PrivateIps { + return ip + } + return "" +} + +func (rds *SDBInstance) GetConnectionStr() string { + for _, ip := range rds.PublicIps { + return ip + } + return "" +} + +func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { + dbinstance, err := region.GetDBInstance(instanceId) + if err != nil { + log.Errorf("failed to get dbinstance by id %s error: %v", instanceId, err) + } + return dbinstance, err +} + +func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { + instances, err := region.GetDBInstances() + if err != nil { + return nil, errors.Wrapf(err, "region.GetDBInstances()") + } + idbinstances := []cloudprovider.ICloudDBInstance{} + for i := 0; i < len(instances); i++ { + instances[i].region = region + idbinstances = append(idbinstances, &instances[i]) + } + return idbinstances, nil +} + +func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { + parameters, err := rds.region.GetDBInstanceParameters(rds.Id) + if err != nil { + return nil, err + } + iparameters := []cloudprovider.ICloudDBInstanceParameter{} + for i := 0; i < len(parameters); i++ { + iparameters = append(iparameters, ¶meters[i]) + } + return iparameters, nil +} + +func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { + databases, err := rds.region.GetDBInstanceDatabases(rds.Id) + if err != nil { + return nil, errors.Wrap(err, "rds.region.GetDBInstanceDatabases(rds.Id)") + } + + idatabase := []cloudprovider.ICloudDBInstanceDatabase{} + for i := 0; i < len(databases); i++ { + databases[i].instance = rds + idatabase = append(idatabase, &databases[i]) + } + return idatabase, nil +} + +func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { + accounts, err := rds.region.GetDBInstanceAccounts(rds.Id) + if err != nil { + return nil, errors.Wrap(err, "rds.region.GetDBInstanceAccounts(rds.Id)") + } + + user := "root" + if rds.GetEngine() == api.DBINSTANCE_TYPE_SQLSERVER { + user = "rduser" + } + + accounts = append(accounts, SDBInstanceAccount{ + Name: user, + instance: rds, + }) + + iaccounts := []cloudprovider.ICloudDBInstanceAccount{} + for i := 0; i < len(accounts); i++ { + accounts[i].instance = rds + iaccounts = append(iaccounts, &accounts[i]) + } + return iaccounts, nil +} + +func (rds *SDBInstance) Delete() error { + return rds.region.DeleteDBInstance(rds.Id) +} + +func (region *SRegion) DeleteDBInstance(instanceId string) error { + err := region.client.rdsDelete(region.Id, instanceId) + return err +} + +func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + zoneIds := []string{} + zones, err := region.GetIZones() + if err != nil { + return nil, err + } + for _, zone := range zones { + zoneIds = append(zoneIds, zone.GetId()) + } + + if len(desc.SecgroupIds) == 0 { + return nil, fmt.Errorf("Missing secgroupId") + } + + params := map[string]interface{}{ + "region": region.Id, + "name": desc.Name, + "datastore": map[string]string{ + "type": desc.Engine, + "version": desc.EngineVersion, + }, + "password": desc.Password, + "volume": map[string]interface{}{ + "type": desc.StorageType, + "size": desc.DiskSizeGB, + }, + "vpc_id": desc.VpcId, + "subnet_id": desc.NetworkId, + "security_group_id": desc.SecgroupIds[0], + } + + if len(desc.ProjectId) > 0 { + params["enterprise_project_id"] = desc.ProjectId + } + + if len(desc.MasterInstanceId) > 0 { + params["replica_of_id"] = desc.MasterInstanceId + delete(params, "security_group_id") + } + + if len(desc.RdsId) > 0 && len(desc.BackupId) > 0 { + params["restore_point"] = map[string]interface{}{ + "backup_id": desc.BackupId, + "instance_id": desc.RdsId, + "type": "backup", + } + } + + switch desc.Category { + case api.HUAWEI_DBINSTANCE_CATEGORY_HA: + switch desc.Engine { + case api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL: + params["ha"] = map[string]string{ + "mode": "Ha", + "replication_mode": "async", + } + case api.DBINSTANCE_TYPE_SQLSERVER: + params["ha"] = map[string]string{ + "mode": "Ha", + "replication_mode": "sync", + } + } + case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE: + case api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA: + } + + if desc.BillingCycle != nil { + periodType := "month" + periodNum := desc.BillingCycle.GetMonths() + if desc.BillingCycle.GetYears() > 0 { + periodType = "year" + periodNum = desc.BillingCycle.GetYears() + } + params["charge_info"] = map[string]interface{}{ + "charge_mode": "prePaid", + "period_type": periodType, + "period_num": periodNum, + "is_auto_renew": false, + } + } + params["flavor_ref"] = desc.InstanceType + params["availability_zone"] = desc.ZoneId + resp, err := region.client.request(httputils.POST, region.client._url("instance", "v3", region.Id, "instance"), nil, params) + if err != nil { + return nil, errors.Wrapf(err, "Create") + } + + instance := &SDBInstance{region: region} + err = resp.Unmarshal(instance, "instance") + if err != nil { + return nil, errors.Wrap(err, `resp.Unmarshal(&instance, "instance")`) + } + if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { + err = cloudprovider.Wait(10*time.Second, 20*time.Minute, func() (bool, error) { + + job, err := region.client.request(httputils.POST, region.client._url(fmt.Sprintf("instance/%s", jobId), "v3", region.Id, "instance"), nil, params) + if err != nil { + return false, nil + } + status, _ := job.GetString("status") + process, _ := job.GetString("process") + log.Debugf("create dbinstance job %s status: %s process: %s", jobId, status, process) + if status == "Completed" { + return true, nil + } + if status == "Failed" { + return false, fmt.Errorf("create failed") + } + return false, nil + }) + } + return instance, err +} + +func (rds *SDBInstance) Reboot() error { + // return rds.region.RebootDBInstance(rds.Id) + return nil +} + +func (rds *SDBInstance) OpenPublicConnection() error { + return fmt.Errorf("Huawei current not support this operation") + //return rds.region.PublicConnectionAction(rds.Id, "openRC") +} + +func (rds *SDBInstance) ClosePublicConnection() error { + return fmt.Errorf("Huawei current not support this operation") + //return rds.region.PublicConnectionAction(rds.Id, "closeRC") +} + +func (region *SRegion) PublicConnectionAction(instanceId string, action string) error { + return cloudprovider.ErrNotImplemented + /*resp, err := region.ecsClient.DBInstance.PerformAction2(action, instanceId, nil, "") + if err != nil { + return errors.Wrapf(err, "rds.%s", action) + } + + if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { + err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { + job := struct { + Status string + Process string + }{} + query := url.Values{} + query.Add("id", jobId) + err := region.rdsJobGet("jobs", query, job) + if err != nil { + log.Errorf("failed to get job %s info error: %v", jobId, err) + return false + } + if job.Status == "Completed" { + return true + } + log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, job.Status, job.Process) + return false + }) + } + + return nil + */ +} + +func (region *SRegion) RebootDBInstance(instanceId string) error { + return cloudprovider.ErrNotImplemented + /*params := jsonutils.Marshal(map[string]interface{}{ + "restart": map[string]string{}, + }) + resp, err := region.ecsClient.DBInstance.PerformAction2("action", instanceId, params, "") + if err != nil { + return err + } + if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { + err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { + job := struct { + Status string + Process string + }{} + query := url.Values{} + query.Add("id", jobId) + err := region.rdsJobGet("jobs", query, job) + if err != nil { + log.Errorf("failed to get job %s info error: %v", jobId, err) + return false + } + if job.Status == "Completed" { + return true + } + log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, job.Status, job.Process) + return false + }) + } + return err*/ +} + +func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { + return rds.region.CreateDBInstanceAccount(rds.Id, conf.Name, conf.Password) +} + +func (region *SRegion) CreateDBInstanceAccount(instanceId, account, password string) error { + params := map[string]interface{}{ + "name": account, + "password": password, + } + + err := region.rdsCreate(fmt.Sprintf("instances/%s/db_user", instanceId), params, nil) + return err +} + +func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { + return rds.region.CreateDBInstanceDatabase(rds.Id, conf.Name, conf.CharacterSet) +} + +func (region *SRegion) CreateDBInstanceDatabase(instanceId, database, characterSet string) error { + params := map[string]interface{}{ + "name": database, + "character_set": characterSet, + } + err := region.rdsCreate(fmt.Sprintf("instances/%s/database", instanceId), params, nil) + return err +} + +func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { + return rds.region.ChangeDBInstanceConfig(rds.Id, desc.InstanceType, desc.DiskSizeGB) +} + +func (region *SRegion) ChangeDBInstanceConfig(instanceId string, instanceType string, diskSizeGb int) error { + instance, err := region.GetIDBInstanceById(instanceId) + if err != nil { + return errors.Wrapf(err, "region.GetIDBInstanceById(%s)", instanceId) + } + + if len(instanceType) > 0 { + params := map[string]interface{}{ + "resize_flavor": map[string]string{ + "spec_code": instanceType, + }, + } + err := region.rdsPerform(fmt.Sprintf("instances/%s", instanceId), "action", params, nil) + if err != nil { + return errors.Wrap(err, "resize_flavor") + } + cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) + } + if diskSizeGb > 0 { + params := map[string]interface{}{ + "enlarge_volume": map[string]int{ + "size": diskSizeGb, + }, + } + err := region.rdsPerform(fmt.Sprintf("instances/%s", instanceId), "action", params, nil) + if err != nil { + return errors.Wrap(err, "enlarge_volume") + } + cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) + } + return nil +} + +func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { + if len(conf.OriginDBInstanceExternalId) == 0 { + conf.OriginDBInstanceExternalId = rds.Id + } + return rds.region.RecoveryDBInstanceFromBackup(rds.Id, conf.OriginDBInstanceExternalId, conf.BackupId, conf.Databases) +} + +func (region *SRegion) RecoveryDBInstanceFromBackup(target, origin string, backupId string, databases map[string]string) error { + source := map[string]interface{}{ + "type": "backup", + "backup_id": backupId, + } + if len(origin) > 0 { + source["instance_id"] = origin + } + if len(databases) > 0 { + source["database_name"] = databases + } + params := map[string]interface{}{ + "source": source, + "target": map[string]string{ + "instance_id": target, + }, + } + err := region.rdsPerform("instance", "recovery", params, nil) + if err != nil { + return errors.Wrap(err, "dbinstance.recovery") + } + return nil +} + +func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_account.go new file mode 100644 index 0000000000..9c3274b348 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_account.go @@ -0,0 +1,126 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SDBInstanceAccount struct { + multicloud.SDBInstanceAccountBase + huawei.HuaweiTags + instance *SDBInstance + Name string +} + +func (account *SDBInstanceAccount) GetName() string { + return account.Name +} + +func (account *SDBInstanceAccount) Delete() error { + return account.instance.region.rdsDelete(fmt.Sprintf("%s/db_user/%s", account.instance.Id, account.Name)) +} + +func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { + privileges, err := account.instance.region.GetDBInstancePrivileges(account.instance.Id, account.Name) + if err != nil { + return nil, err + } + iprivileves := []cloudprovider.ICloudDBInstanceAccountPrivilege{} + for i := 0; i < len(privileges); i++ { + privileges[i].account = account + iprivileves = append(iprivileves, &privileges[i]) + } + return iprivileves, nil +} + +func (region *SRegion) GetDBInstanceAccounts(instanceId string) ([]SDBInstanceAccount, error) { + accounts := []SDBInstanceAccount{} + err := region.rdsList(fmt.Sprintf("instances/%s/db_user/detail", instanceId), nil, accounts) + if err != nil { + return nil, err + } + return accounts, nil +} + +func (region *SRegion) GetDBInstancePrivileges(instanceId string, username string) ([]SDatabasePrivilege, error) { + query := url.Values{} + query.Add("iser-name", username) + privileges := []SDatabasePrivilege{} + err := region.rdsList(fmt.Sprintf("instances/%s/db_user/database", instanceId), query, privileges) + if err != nil { + return nil, err + } + return privileges, nil +} + +func (account *SDBInstanceAccount) RevokePrivilege(database string) error { + return account.instance.region.RevokeDBInstancePrivilege(account.instance.Id, account.Name, database) +} + +func (region *SRegion) RevokeDBInstancePrivilege(instanceId string, account, database string) error { + params := map[string]interface{}{ + "db_name": database, + "users": []map[string]interface{}{ + map[string]interface{}{ + "name": account, + }, + }, + } + return region.rdsDBPrivilegesDelete(fmt.Sprintf("instances/%s/db_privilege", instanceId), params) +} + +func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { + return account.instance.region.GrantDBInstancePrivilege(account.instance.Id, account.Name, database, privilege) +} + +func (region *SRegion) GrantDBInstancePrivilege(instanceId string, account, database string, privilege string) error { + readonly := false + switch privilege { + case api.DATABASE_PRIVILEGE_R: + readonly = true + case api.DATABASE_PRIVILEGE_RW: + default: + return fmt.Errorf("Unknown privilege %s", privilege) + } + params := map[string]interface{}{ + "db_name": database, + "users": []map[string]interface{}{ + map[string]interface{}{ + "name": account, + "readonly": readonly, + }, + }, + } + resp := &struct { + Resp string + }{} + err := region.rdsDBPrivilegesGrant(fmt.Sprintf("instances/%s/db_privilege", instanceId), params, resp) + return err +} + +func (account *SDBInstanceAccount) ResetPassword(password string) error { + return account.instance.region.ResetDBInstanceAccountPassword(account.instance.Id, account.Name, password) +} + +func (region *SRegion) ResetDBInstanceAccountPassword(instanceId, account, password string) error { + return fmt.Errorf("The API does not exist or has not been published in the environment") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_backup.go new file mode 100644 index 0000000000..f0f89c697d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_backup.go @@ -0,0 +1,239 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SDBInstanceBackup struct { + multicloud.SDBInstanceBackupBase + huawei.HuaweiTags + region *SRegion + + BeginTime string + Datastore SDatastore + EndTime string + Id string + InstanceId string + Name string + Size int + Status string + Type string +} + +func (backup *SDBInstanceBackup) GetId() string { + return backup.Id +} + +func (backup *SDBInstanceBackup) GetGlobalId() string { + return backup.Id +} + +func (backup *SDBInstanceBackup) GetName() string { + return backup.Name +} + +func (backup *SDBInstanceBackup) GetEngine() string { + return backup.Datastore.Type +} + +func (backup *SDBInstanceBackup) GetEngineVersion() string { + return backup.Datastore.Version +} + +func (backup *SDBInstanceBackup) GetStartTime() time.Time { + //2019-08-05T08:00:02+0000 + t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.BeginTime) + if err != nil { + return time.Time{} + } + return t +} + +func (backup *SDBInstanceBackup) GetEndTime() time.Time { + t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.EndTime) + if err != nil { + return time.Time{} + } + return t +} + +func (backup *SDBInstanceBackup) GetBackupMode() string { + switch backup.Type { + case "manual": + return api.BACKUP_MODE_MANUAL + default: + return api.BACKUP_MODE_AUTOMATED + } +} + +func (backup *SDBInstanceBackup) GetStatus() string { + switch backup.Status { + case "COMPLETED": + return api.DBINSTANCE_BACKUP_READY + case "FAILED": + return api.DBINSTANCE_BACKUP_FAILED + case "BUILDING": + return api.DBINSTANCE_BACKUP_CREATING + case "DELETING": + return api.DBINSTANCE_BACKUP_DELETING + default: + return api.DBINSTANCE_BACKUP_UNKNOWN + } +} + +func (backup *SDBInstanceBackup) GetBackupSizeMb() int { + return backup.Size / 1024 +} + +func (backup *SDBInstanceBackup) GetDBNames() string { + return "" +} + +func (backup *SDBInstanceBackup) Delete() error { + return backup.region.DeleteDBInstanceBackup(backup.Id) +} + +func (region *SRegion) DeleteDBInstanceBackup(backupId string) error { + err := region.rdsDelete(fmt.Sprintf("backups/%s", backupId)) + return err +} + +func (backup *SDBInstanceBackup) GetDBInstanceId() string { + return backup.InstanceId +} + +func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string) ([]SDBInstanceBackup, error) { + query := url.Values{} + query.Add("instance_id", instanceId) + if len(backupId) > 0 { + query.Add("backup_id", backupId) + } + backups := []SDBInstanceBackup{} + err := region.rdsList("offsite-backups", query, backups) + if err != nil { + return nil, err + } + return backups, nil +} + +func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + dbinstnaces, err := region.GetIDBInstances() + if err != nil { + return nil, err + } + ibackups := []cloudprovider.ICloudDBInstanceBackup{} + for i := 0; i < len(dbinstnaces); i++ { + _dbinstance := dbinstnaces[i].(*SDBInstance) + _ibackup, err := _dbinstance.GetIDBInstanceBackups() + if err != nil { + return nil, errors.Wrapf(err, "_dbinstance(%v).GetIDBInstanceBackups", _dbinstance) + } + ibackups = append(ibackups, _ibackup...) + } + return ibackups, nil +} + +func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { + backups, err := region.GetIDBInstanceBackups() + if err != nil { + return nil, errors.Wrap(err, "region.GetIDBInstanceBackups") + } + for _, backup := range backups { + if backup.GetGlobalId() == backupId { + return backup, nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + backups, err := rds.region.GetDBInstanceBackups(rds.Id, "") + if err != nil { + return nil, err + } + + ibackups := []cloudprovider.ICloudDBInstanceBackup{} + for i := 0; i < len(backups); i++ { + backups[i].region = rds.region + ibackups = append(ibackups, &backups[i]) + } + return ibackups, nil +} + +func (backup *SDBInstanceBackup) Refresh() error { + backups, err := backup.region.GetDBInstanceBackups(backup.InstanceId, backup.Id) + if err != nil { + return err + } + if len(backups) == 0 { + return cloudprovider.ErrNotFound + } + return jsonutils.Update(backup, backups[0]) +} + +func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { + backupId, err := rds.region.CreateDBInstanceBackup(rds.Id, conf.Name, conf.Description, conf.Databases) + if err != nil { + return "", err + } + backup, err := rds.region.GetIDBInstanceBackupById(backupId) + if err != nil { + return "", errors.Wrap(err, "region.GetIDBInstanceBackupById") + } + cloudprovider.WaitStatus(backup, api.DBINSTANCE_BACKUP_READY, time.Second*3, time.Minute*30) + return backupId, nil +} + +func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, descrition string, databases []string) (string, error) { + params := map[string]interface{}{ + "instance_id": instanceId, + "name": name, + "description": descrition, + } + if len(databases) > 0 { + dbs := []map[string]string{} + for _, database := range databases { + dbs = append(dbs, map[string]string{"name": database}) + } + params["databases"] = dbs + } + backup := SDBInstanceBackup{} + err := region.rdsCreate("backups", params, backup) + if err != nil { + return "", errors.Wrap(err, "DBInstanceBackup.Create") + } + backupId := backup.Id + if err != nil { + return "", errors.Wrap(err, "resp.GetBackupId") + } + return backupId, nil +} + +func (self *SDBInstanceBackup) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + opts.BackupId = self.Id + return self.region.CreateIDBInstance(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_database.go new file mode 100644 index 0000000000..1e981ef58b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_database.go @@ -0,0 +1,73 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SDBInstanceDatabase struct { + instance *SDBInstance + multicloud.SDBInstanceDatabaseBase + huawei.HuaweiTags + + Name string + CharacterSet string +} + +func (database *SDBInstanceDatabase) GetId() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetGlobalId() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetName() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetStatus() string { + return api.DBINSTANCE_DATABASE_RUNNING +} + +func (database *SDBInstanceDatabase) GetCharacterSet() string { + return database.CharacterSet +} + +func (database *SDBInstanceDatabase) Delete() error { + return database.instance.region.DeleteDBInstanceDatabase(database.instance.Id, database.Name) +} + +func (region *SRegion) DeleteDBInstanceDatabase(instanceId, database string) error { + resource := fmt.Sprintf("instances/%s/database/%s", instanceId, database) + err := region.rdsDelete(resource) + return err +} + +// rds查询数据库列表 +func (region *SRegion) GetDBInstanceDatabases(instanceId string) ([]SDBInstanceDatabase, error) { + resource := fmt.Sprintf("%s/database/detail", instanceId) + databases := []SDBInstanceDatabase{} + err := region.rdsList(resource, nil, databases) + if err != nil { + return nil, err + } + return databases, nil +} diff --git a/pkg/multicloud/hcs/dbinstance_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_parameter.go similarity index 100% rename from pkg/multicloud/hcs/dbinstance_parameter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_parameter.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_privilege.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_privilege.go new file mode 100644 index 0000000000..1b8143b10b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_privilege.go @@ -0,0 +1,43 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +type SDatabasePrivilege struct { + account *SDBInstanceAccount + + Name string + Readonly bool +} + +func (privilege *SDatabasePrivilege) GetGlobalId() string { + return fmt.Sprintf("%s/%s", privilege.account.Name, privilege.Name) +} + +func (privilege *SDatabasePrivilege) GetPrivilege() string { + if privilege.Readonly { + return api.DATABASE_PRIVILEGE_R + } + return api.DATABASE_PRIVILEGE_RW +} + +func (privilege *SDatabasePrivilege) GetDBName() string { + return privilege.Name +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_skus.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_skus.go new file mode 100644 index 0000000000..fa540c0443 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/dbinstance_skus.go @@ -0,0 +1,273 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SDBInstanceSku struct { + Vcpus int + Ram int //单位GB + SpecCode string + InstanceMode string //实例模型 + + StorageType string + Az1 string + Az2 string + Engine string + EngineVersion string +} + +func (self *SDBInstanceSku) GetName() string { + return self.SpecCode +} + +func (self *SDBInstanceSku) GetGlobalId() string { + return fmt.Sprintf("%s-%s-%s-%s-%s-%s", self.Engine, self.EngineVersion, self.InstanceMode, self.SpecCode, self.StorageType, self.GetZoneId()) +} + +func (self *SDBInstanceSku) GetCategory() string { + return self.InstanceMode +} + +func (self *SDBInstanceSku) GetDiskSizeStep() int { + return 10 +} + +func (self *SDBInstanceSku) GetIOPS() int { + return 0 +} + +func (self *SDBInstanceSku) GetTPS() int { + return 0 +} + +func (self *SDBInstanceSku) GetZone1Id() string { + return self.Az1 +} + +func (self *SDBInstanceSku) GetZone2Id() string { + return self.Az2 +} + +func (self *SDBInstanceSku) GetZone3Id() string { + return "" +} + +func (self *SDBInstanceSku) GetZoneId() string { + zones := []string{} + for _, zone := range []string{self.Az1, self.Az2} { + if len(zone) > 0 { + zones = append(zones, zone) + } + } + return strings.Join(zones, ",") +} + +func (self *SDBInstanceSku) GetMaxConnections() int { + return 0 +} + +func (self *SDBInstanceSku) GetMaxDiskSizeGb() int { + return 4000 +} + +func (self *SDBInstanceSku) GetMinDiskSizeGb() int { + return 40 +} + +func (self *SDBInstanceSku) GetVcpuCount() int { + return self.Vcpus +} + +func (self *SDBInstanceSku) GetVmemSizeMb() int { + return self.Ram * 1024 +} + +func (self *SDBInstanceSku) GetStorageType() string { + return self.StorageType +} + +func (sku *SDBInstanceSku) GetEngine() string { + return sku.Engine +} + +func (sku *SDBInstanceSku) GetEngineVersion() string { + return sku.EngineVersion +} + +func (self *SDBInstanceSku) GetStatus() string { + return api.DBINSTANCE_SKU_AVAILABLE +} + +func (sku *SDBInstanceSku) GetQPS() int { + return 0 +} + +type SDBInstanceFlavor struct { + Vcpus int + Ram int //单位GB + SpecCode string + InstanceMode string //实例模型 + + StorageType string + AzStatus map[string]string + Engine string + EngineVersion string +} + +func (self *SDBInstanceFlavor) GetISkus() []cloudprovider.ICloudDBInstanceSku { + ret := []cloudprovider.ICloudDBInstanceSku{} + switch self.InstanceMode { + case api.HUAWEI_DBINSTANCE_CATEGORY_HA: + for az1, status1 := range self.AzStatus { + if status1 != "normal" { + continue + } + for az2, status2 := range self.AzStatus { + if status2 != "normal" { + continue + } + sku := &SDBInstanceSku{ + Vcpus: self.Vcpus, + Ram: self.Ram, + SpecCode: self.SpecCode, + InstanceMode: self.InstanceMode, + StorageType: self.StorageType, + Az1: az1, + Az2: az2, + Engine: self.Engine, + EngineVersion: self.EngineVersion, + } + ret = append(ret, sku) + } + } + case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE: + for az, status := range self.AzStatus { + if status != "normal" { + continue + } + sku := &SDBInstanceSku{ + Vcpus: self.Vcpus, + Ram: self.Ram, + SpecCode: self.SpecCode, + InstanceMode: self.InstanceMode, + StorageType: self.StorageType, + Az1: az, + Engine: self.Engine, + EngineVersion: self.EngineVersion, + } + ret = append(ret, sku) + } + } + return ret +} + +func (self *SRegion) GetIDBInstanceSkus() ([]cloudprovider.ICloudDBInstanceSku, error) { + skus, err := self.GetDBInstanceSkus() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudDBInstanceSku{} + for i := range skus { + ret = append(ret, skus[i].GetISkus()...) + } + return ret, nil +} + +type SDBInstanceDatastore struct { + Id string + Name string +} + +func (self *SRegion) GetDBInstanceSkus() ([]SDBInstanceFlavor, error) { + skus := []SDBInstanceFlavor{} + for _, engine := range []string{api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL, api.DBINSTANCE_TYPE_SQLSERVER} { + stores, err := self.GetDBInstanceDatastores(engine) + if err != nil { + return nil, err + } + for _, version := range stores { + storages, err := self.GetDBInstanceStorages(engine, version.Name) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceStorages(%s,%s)", engine, version.Name) + } + flavors, err := self.GetDBInstanceFlavors(engine, version.Name) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceFlavors(%s, %s)", engine, version.Name) + } + for i := range flavors { + flavors[i].Engine = engine + flavors[i].EngineVersion = version.Name + for j := range storages { + flavors[i].StorageType = storages[j].Name + flavors[i].AzStatus = storages[j].AzStatus + skus = append(skus, flavors[i]) + } + } + } + } + return skus, nil +} + +// rds规格信息 +func (region *SRegion) GetDBInstanceFlavors(engine string, version string) ([]SDBInstanceFlavor, error) { + flavors := []SDBInstanceFlavor{} + query := url.Values{} + query.Add("version_name", version) + resource := fmt.Sprintf("%s/%s", "flavor", engine) + err := region.rdsList(resource, query, flavors) + if err != nil { + return nil, err + } + return flavors, nil +} + +// rds数据库引擎版本信息 +func (region *SRegion) GetDBInstanceDatastores(engine string) ([]SDBInstanceDatastore, error) { + stores := []SDBInstanceDatastore{} + resource := fmt.Sprintf("%s/%s", "datastores", engine) + err := region.rdsList(resource, nil, stores) + if err != nil { + return nil, err + } + return stores, nil +} + +type SDBInstanceStorage struct { + Name string + AzStatus map[string]string +} + +// rds数据库磁盘类型 +func (region *SRegion) GetDBInstanceStorages(engine, engineVersion string) ([]SDBInstanceStorage, error) { + storages := []SDBInstanceStorage{} + resource := fmt.Sprintf("%s/%s", "storage-type", engine) + query := url.Values{} + query.Add("version_name", engineVersion) + err := region.rdsList(resource, query, storages) + if err != nil { + return nil, err + } + return storages, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/disk.go new file mode 100644 index 0000000000..740ba16271 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/disk.go @@ -0,0 +1,439 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +/* +华为云云硬盘 +======创建========== +1.磁盘只能挂载到同一可用区的云服务器内,创建后不支持更换可用区 +2.计费模式 包年包月/按需计费 +3.*支持自动备份 + + +共享盘 和 普通盘:https://support.huaweicloud.com/productdesc-evs/zh-cn_topic_0032860759.html +根据是否支持挂载至多台云服务器可以将云硬盘分为非共享云硬盘和共享云硬盘。 +一个非共享云硬盘只能挂载至一台云服务器,而一个共享云硬盘可以同时挂载至多台云服务器。 +单个共享云硬盘最多可同时挂载给16个云服务器。目前,共享云硬盘只适用于数据盘,不支持系统盘。 +*/ + +type Attachment struct { + ServerId string `json:"server_id"` + AttachmentId string `json:"attachment_id"` + AttachedAt string `json:"attached_at"` + HostName string `json:"host_name"` + VolumeId string `json:"volume_id"` + Device string `json:"device"` + Id string `json:"id"` +} + +type DiskMeta struct { + ResourceSpecCode string `json:"resourceSpecCode"` + Billing string `json:"billing"` + ResourceType string `json:"resourceType"` + AttachedMode string `json:"attached_mode"` + Readonly string `json:"readonly"` +} + +type VolumeImageMetadata struct { + QuickStart string `json:"__quick_start"` + ContainerFormat string `json:"container_format"` + MinRAM string `json:"min_ram"` + ImageName string `json:"image_name"` + ImageId string `json:"image_id"` + OSType string `json:"__os_type"` + OSFeatureList string `json:"__os_feature_list"` + MinDisk string `json:"min_disk"` + SupportKVM string `json:"__support_kvm"` + VirtualEnvType string `json:"virtual_env_type"` + SizeGB string `json:"size"` + OSVersion string `json:"__os_version"` + OSBit string `json:"__os_bit"` + SupportKVMHi1822Hiovs string `json:"__support_kvm_hi1822_hiovs"` + SupportXen string `json:"__support_xen"` + Description string `json:"__description"` + Imagetype string `json:"__imagetype"` + DiskFormat string `json:"disk_format"` + ImageSourceType string `json:"__image_source_type"` + Checksum string `json:"checksum"` + Isregistered string `json:"__isregistered"` + HwVifMultiqueueEnabled string `json:"hw_vif_multiqueue_enabled"` + Platform string `json:"__platform"` +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0124881427.html +type SDisk struct { + multicloud.SDisk + huawei.HuaweiDiskTags + //details *SResourceDetail + + region *SRegion + + Id string `json:"id"` + Name string `json:"name"` + Status string `json:"status"` + Attachments []Attachment `json:"attachments"` + Description string `json:"description"` + SizeGB int `json:"size"` + Metadata DiskMeta `json:"metadata"` + Encrypted bool `json:"encrypted"` + Bootable string `json:"bootable"` + Multiattach bool `json:"multiattach"` + AvailabilityZone string `json:"availability_zone"` + SourceVolid string `json:"source_volid"` + SnapshotId string `json:"snapshot_id"` + CreatedAt time.Time `json:"created_at"` + VolumeType string `json:"volume_type"` + VolumeImageMetadata VolumeImageMetadata `json:"volume_image_metadata"` + ReplicationStatus string `json:"replication_status"` + UserId string `json:"user_id"` + ConsistencygroupId string `json:"consistencygroup_id"` + UpdatedAt string `json:"updated_at"` + EnterpriseProjectId string + + ExpiredTime time.Time +} + +func (self *SDisk) GetId() string { + return self.Id +} + +func (self *SDisk) GetName() string { + if len(self.Name) == 0 { + return self.Id + } + + return self.Name +} + +func (self *SDisk) GetGlobalId() string { + return self.Id +} + +func (self *SDisk) GetStatus() string { + // https://support.huaweicloud.com/api-evs/zh-cn_topic_0051803385.html + switch self.Status { + case "creating", "downloading": + return api.DISK_ALLOCATING + case "available", "in-use": + return api.DISK_READY + case "error": + return api.DISK_ALLOC_FAILED + case "attaching": + return api.DISK_ATTACHING + case "detaching": + return api.DISK_DETACHING + case "restoring-backup": + return api.DISK_REBUILD + case "backing-up": + return api.DISK_BACKUP_STARTALLOC // ? + case "error_restoring": + return api.DISK_BACKUP_ALLOC_FAILED + case "uploading": + return api.DISK_SAVING //? + case "extending": + return api.DISK_RESIZING + case "error_extending": + return api.DISK_ALLOC_FAILED // ? + case "deleting": + return api.DISK_DEALLOC //? + case "error_deleting": + return api.DISK_DEALLOC_FAILED // ? + case "rollbacking": + return api.DISK_REBUILD + case "error_rollbacking": + return api.DISK_UNKNOWN + default: + return api.DISK_UNKNOWN + } +} + +func (self *SDisk) Refresh() error { + ret, err := self.region.GetDisk(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, ret) +} + +func (self *SDisk) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SDisk) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return nil, cloudprovider.ErrNotImplemented + // return self.storage, nil +} + +func (self *SDisk) GetDiskFormat() string { + return "vhd" +} + +func (self *SDisk) GetDiskSizeMB() int { + return int(self.SizeGB * 1024) +} + +func (self *SDisk) GetIsAutoDelete() bool { + return false +} + +func (self *SDisk) GetTemplateId() string { + return self.VolumeImageMetadata.ImageId +} + +// Bootable 表示硬盘是否为启动盘。 +// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) +func (self *SDisk) GetDiskType() string { + if self.Bootable == "true" { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +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 { + if len(self.Attachments) > 0 { + return self.Attachments[0].Device + } + return "" +} + +func (self *SDisk) GetMountServerId() string { + if len(self.Attachments) > 0 { + return self.Attachments[0].ServerId + } + return "" +} + +func (self *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) Delete(ctx context.Context) error { + return self.region.DeleteDisk(self.Id) +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + snap, err := self.region.CreateSnapshot(self.Id, name, desc) + if err != nil { + return nil, err + } + return snap, nil +} + +func (self *SDisk) GetISnapshot(id string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := self.region.GetSnapshot(id) + if err != nil { + return nil, err + } + return snapshot, nil +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := self.region.GetSnapshots(self.Id, "") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudSnapshot{} + for i := 0; i < len(snapshots); i++ { + snapshots[i].region = self.region + ret = append(ret, &snapshots[i]) + } + return ret, nil +} + +func (self *SDisk) Resize(ctx context.Context, sizeMB int64) error { + return self.region.ResizeDisk(self.GetId(), sizeMB/1024) +} + +func (self *SDisk) Detach() error { + return self.region.DetachDisk(self.GetMountServerId(), self.GetId()) +} + +func (self *SDisk) Attach(device string) error { + return self.region.AttachDisk(self.GetMountServerId(), self.GetId(), device) +} + +// 在线卸载磁盘 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0036046828.html +// 对于挂载在系统盘盘位(也就是“/dev/sda”或“/dev/vda”挂载点)上的磁盘,当前仅支持离线卸载 +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + mountpoint := self.GetMountpoint() + if len(mountpoint) > 0 { + err := self.Detach() + if err != nil { + return "", err + } + } + + err := self.region.ResetDisk(self.Id, snapshotId) + if err != nil { + return self.Id, err + } + err = cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 300*time.Second) + if err != nil { + return "", err + } + if len(mountpoint) > 0 { + err := self.Attach(mountpoint) + if err != nil { + return "", err + } + } + return self.Id, nil +} + +// 华为云不支持重置 +func (self *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetDisk(id string) (*SDisk, error) { + ret := &SDisk{region: self} + res := fmt.Sprintf("volumes/%s", id) + return ret, self.evsGet(res, ret) +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762430.html +func (self *SRegion) GetDisks(zoneId string) ([]SDisk, error) { + params := url.Values{} + if len(zoneId) > 0 { + params.Set("availability_zone", zoneId) + } + disks := []SDisk{} + return disks, self.evsList("volumes/detail", params, &disks) +} + +func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, snapshotId string, desc string, projectId string) (*SDisk, error) { + volume := map[string]interface{}{ + "name": name, + "availability_zone": zoneId, + "description": desc, + "volume_type": category, + "size": sizeGb, + } + if len(snapshotId) > 0 { + volume["snapshot_id"] = snapshotId + } + if len(projectId) > 0 { + volume["enterprise_project_id"] = projectId + } + params := map[string]interface{}{ + "volume": volume, + } + ret := &SDisk{region: self} + return ret, self.evsCreate("volumes", params, ret) +} + +func (self *SRegion) DeleteDisk(id string) error { + res := fmt.Sprintf("volumes/%s", id) + return self.evsDelete(res) +} + +func (self *SRegion) ResizeDisk(id string, sizeGb int64) error { + params := map[string]interface{}{ + "os_extend": map[string]interface{}{ + "new_size": sizeGb, + }, + } + res := fmt.Sprintf("volumes/%s", id) + return self.evsPerform(res, "action", params) +} + +func (self *SRegion) ResetDisk(diskId, snapshotId string) error { + params := map[string]interface{}{ + "volume_id": diskId, + } + res := fmt.Sprintf("os-vendor-snapshots/%s", snapshotId) + return self.evsPerform(res, "rollback", params) +} + +func (self *SDisk) GetProjectId() string { + return self.EnterpriseProjectId +} + +func (self *SRegion) DetachDisk(instanceId string, diskId string) error { + res := fmt.Sprintf("servers/%s/os-volume_attachments/%s", instanceId, diskId) + return self.delete("ecs", "v2", res) +} + +func (self *SRegion) AttachDisk(instanceId string, diskId string, device string) error { + params := map[string]interface{}{ + "volumeAttachment": map[string]interface{}{ + "volumeId": instanceId, + "device": device, + }, + } + res := fmt.Sprintf("servers/%s/os-volume_attachments", instanceId) + return self.perform("ecs", "v2", res, "action", params, nil) +} + +type SDiskType struct { + ExtraSpecs ExtraSpecs `json:"extra_specs"` + Name string `json:"name"` + QosSpecsId string `json:"qos_specs_id"` + Id string `json:"id"` + IsPublic bool `json:"is_public"` +} + +func (self *SDiskType) IsAvaliableInZone(zoneId string) bool { + if strings.Contains(self.ExtraSpecs.HwAvailabilityZone, zoneId) { + return true + } + return false +} + +type ExtraSpecs struct { + VolumeBackendName string `json:"volume_backend_name"` + HwAvailabilityZone string `json:"HW:availability-zone"` +} + +func (self *SRegion) GetDiskTypes() ([]SDiskType, error) { + ret := []SDiskType{} + return ret, self.get("evs", "v3", "types", &ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/doc.go new file mode 100644 index 0000000000..432a7c00a7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/doc.go @@ -0,0 +1 @@ +package hcs // import "yunion.io/x/cloudmux/pkg/multicloud/hcs" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/eip.go new file mode 100644 index 0000000000..018b0a584a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/eip.go @@ -0,0 +1,434 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type TInternetChargeType string + +const ( + InternetChargeByTraffic = TInternetChargeType("traffic") + InternetChargeByBandwidth = TInternetChargeType("bandwidth") +) + +type Bandwidth struct { + Id string `json:"id"` + Name string `json:"name"` + Size int64 `json:"size"` + ShareType string `json:"share_type"` + PublicipInfo []PublicipInfo `json:"publicip_info"` + TenantId string `json:"tenant_id"` + BandwidthType string `json:"bandwidth_type"` + ChargeMode string `json:"charge_mode"` + BillingInfo string `json:"billing_info"` + EnterpriseProjectId string `json:"enterprise_project_id"` +} + +type PublicipInfo struct { + PublicipId string `json:"publicip_id"` + PublicipAddress string `json:"publicip_address"` + PublicipType string `json:"publicip_type"` + IPVersion int64 `json:"ip_version"` +} + +type SProfile struct { + UserId string `json:"user_id"` + ProductId string `json:"product_id"` + RegionId string `json:"region_id"` + OrderId string `json:"order_id"` +} + +type SEip struct { + multicloud.SEipBase + HcsTags + + region *SRegion + port *Port + + Alias string + Id string `json:"id"` + Status string `json:"status"` + Profile *SProfile `json:"profile,omitempty"` + Type string `json:"type"` + PublicIPAddress string `json:"public_ip_address"` + PrivateIPAddress string `json:"private_ip_address"` + TenantId string `json:"tenant_id"` + CreateTime time.Time `json:"create_time"` + BandwidthId string `json:"bandwidth_id"` + BandwidthShareType string `json:"bandwidth_share_type"` + BandwidthSize int64 `json:"bandwidth_size"` + BandwidthName string `json:"bandwidth_name"` + EnterpriseProjectId string `json:"enterprise_project_id"` + IPVersion int64 `json:"ip_version"` + PortId string `json:"port_id"` +} + +func (self *SEip) GetId() string { + return self.Id +} + +func (self *SEip) GetName() string { + if len(self.Alias) > 0 { + return self.Alias + } + return self.PublicIPAddress +} + +func (self *SEip) GetGlobalId() string { + return self.Id +} + +func (self *SEip) GetStatus() string { + // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html + switch self.Status { + case "ACTIVE", "DOWN", "ELB": + return api.EIP_STATUS_READY + case "PENDING_CREATE", "NOTIFYING": + return api.EIP_STATUS_ALLOCATE + case "BINDING": + return api.EIP_STATUS_ALLOCATE + case "BIND_ERROR": + return api.EIP_STATUS_ALLOCATE_FAIL + case "PENDING_DELETE", "NOTIFY_DELETE": + return api.EIP_STATUS_DEALLOCATE + default: + return api.EIP_STATUS_UNKNOWN + } +} + +func (self *SEip) Refresh() error { + if self.IsEmulated() { + return nil + } + new, err := self.region.GetEip(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SEip) IsEmulated() bool { + return false +} + +func (self *SEip) GetIpAddr() string { + return self.PublicIPAddress +} + +func (self *SEip) GetMode() string { + return api.EIP_MODE_STANDALONE_EIP +} + +func (self *SEip) GetPort() *Port { + if len(self.PortId) == 0 { + return nil + } + + if self.port != nil { + return self.port + } + + port, err := self.region.GetPort(self.PortId) + if err != nil { + return nil + } + self.port = port + return self.port +} + +func (self *SEip) GetAssociationType() string { + if len(self.PortId) == 0 { + return "" + } + port, err := self.region.GetPort(self.PortId) + if err != nil { + log.Errorf("Get eip %s port %s error: %v", self.Id, self.PortId, err) + return "" + } + + if strings.HasPrefix(port.DeviceOwner, "compute") { + return api.EIP_ASSOCIATE_TYPE_SERVER + } + + switch port.DeviceOwner { + case "neutron:LOADBALANCER", "neutron:LOADBALANCERV2": + return api.EIP_ASSOCIATE_TYPE_LOADBALANCER + case "network:nat_gateway": + return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY + default: + return port.DeviceOwner + } +} + +func (self *SEip) GetAssociationExternalId() string { + // network/0273a359d61847fc83405926c958c746/ext-floatingips?tenantId=0273a359d61847fc83405926c958c746&limit=2000 + // 只能通过 port id 反查device id. + if len(self.PortId) > 0 { + port, _ := self.region.GetPort(self.PortId) + return port.DeviceId + } + return "" +} + +func (self *SEip) GetBandwidth() int { + return int(self.BandwidthSize) // Mb +} + +func (self *SEip) GetINetworkId() string { + return "" +} + +func (self *SEip) GetInternetChargeType() string { + // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090603.html + bandwidth, err := self.region.GetEipBandwidth(self.BandwidthId) + if err != nil { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + } + if bandwidth.ChargeMode == "traffic" { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + } + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH +} + +func (self *SEip) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SEip) GetCreatedAt() time.Time { + return self.CreateTime +} + +func (self *SEip) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SEip) Delete() error { + return self.region.DeallocateEIP(self.Id) +} + +func (self *SEip) Associate(conf *cloudprovider.AssociateConfig) error { + portId, err := self.region.GetInstancePortId(conf.InstanceId) + if err != nil { + return err + } + + if len(self.PortId) > 0 { + if self.PortId == portId { + return nil + } + + return fmt.Errorf("eip %s aready associate with port %s", self.GetId(), self.PortId) + } + + err = self.region.AssociateEipWithPortId(self.Id, portId) + if err != nil { + return err + } + + err = cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 10*time.Second, 10*time.Second, 180*time.Second) + return err +} + +func (self *SEip) Dissociate() error { + err := self.region.DissociateEip(self.Id) + if err != nil { + return err + } + return cloudprovider.WaitStatus(self, api.EIP_STATUS_READY, 10*time.Second, 180*time.Second) +} + +func (self *SEip) ChangeBandwidth(bw int) error { + return self.region.UpdateEipBandwidth(self.BandwidthId, bw) +} + +func (self *SRegion) GetInstancePortId(instanceId string) (string, error) { + // 目前只绑定一个网卡 + // todo: 还需要按照ports状态进行过滤 + ports, err := self.GetPorts(instanceId) + if err != nil { + return "", err + } + + if len(ports) == 0 { + return "", fmt.Errorf("AssociateEip instance %s port is empty", instanceId) + } + + return ports[0].Id, nil +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html +func (self *SRegion) AllocateEIP(name string, bwMbps int, chargeType TInternetChargeType, bgpType string, projectId string) (*SEip, error) { + params := map[string]interface{}{ + "bandwidth": map[string]interface{}{ + "name": name, + "size": bwMbps, + "share_type": "PER", + "charge_mode": chargeType, + }, + "publicip": map[string]interface{}{ + "type": bgpType, + "ip_version": 4, + "alias": name, + }, + } + if len(projectId) > 0 { + params["enterprise_project_id"] = projectId + } + eip := &SEip{region: self} + return eip, self.vpcCreate("publicips", params, eip) +} + +func (self *SRegion) GetEip(eipId string) (*SEip, error) { + eip := &SEip{region: self} + return eip, self.vpcGet("publicips/"+eipId, eip) +} + +func (self *SRegion) DeallocateEIP(eipId string) error { + return self.vpcDelete("publicips/" + eipId) +} + +func (self *SRegion) AssociateEip(eipId string, instanceId string) error { + portId, err := self.GetInstancePortId(instanceId) + if err != nil { + return err + } + return self.AssociateEipWithPortId(eipId, portId) +} + +func (self *SRegion) AssociateEipWithPortId(eipId string, portId string) error { + params := map[string]interface{}{ + "publicip": map[string]interface{}{ + "port_id": portId, + }, + } + return self.vpcUpdate("publicips/"+eipId, params) +} + +func (self *SRegion) DissociateEip(eipId string) error { + return self.AssociateEipWithPortId(eipId, "") +} + +func (self *SRegion) UpdateEipBandwidth(bandwidthId string, bw int) error { + params := map[string]interface{}{ + "bandwidth": map[string]interface{}{ + "size": bw, + }, + } + return self.vpcUpdate("bandwidths/"+bandwidthId, params) +} + +func (self *SRegion) GetEipBandwidth(id string) (*Bandwidth, error) { + ret := &Bandwidth{} + return ret, self.vpcGet("bandwidths/"+id, ret) +} + +func (self *SEip) GetProjectId() string { + return self.EnterpriseProjectId +} + +func (self *SRegion) GetEips(portId string, addrs []string) ([]SEip, error) { + query := url.Values{} + for _, addr := range addrs { + query.Add("public_ip_address", addr) + } + if len(portId) > 0 { + query.Set("port_id", portId) + } + eips := []SEip{} + return eips, self.vpcList("publicips", query, &eips) +} + +type SEipType struct { + Id string + Type string + Name string + Group string +} + +func (self *SRegion) GetEipTypes() ([]SEipType, error) { + query := url.Values{} + ret := []SEipType{} + return ret, self.vpcList("publicip_types", query, &ret) +} + +func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, err := self.GetEips("", nil) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudEIP{} + for i := 0; i < len(eips); i += 1 { + eips[i].region = self + ret = append(ret, &eips[i]) + } + return ret, nil +} + +func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { + eip, err := self.GetEip(id) + if err != nil { + return nil, err + } + return eip, nil +} + +func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + var ctype TInternetChargeType + switch eip.ChargeType { + case api.EIP_CHARGE_TYPE_BY_TRAFFIC: + ctype = InternetChargeByTraffic + case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: + ctype = InternetChargeByBandwidth + } + + // todo: 如何避免hardcode。集成到cloudmeta服务中? + if len(eip.BGPType) == 0 { + types, err := self.GetEipTypes() + if err != nil { + return nil, errors.Wrapf(err, "GetEipTypes") + } + if len(types) > 0 { + eip.BGPType = types[0].Type + } + } + + // 华为云EIP名字最大长度64 + if len(eip.Name) > 64 { + eip.Name = eip.Name[:64] + } + + ieip, err := self.AllocateEIP(eip.Name, eip.BandwidthMbps, ctype, eip.BGPType, eip.ProjectId) + ieip.region = self + if err != nil { + return nil, err + } + + err = cloudprovider.WaitStatus(ieip, api.EIP_STATUS_READY, 5*time.Second, 60*time.Second) + return ieip, err +} diff --git a/pkg/multicloud/hcs/hcs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/hcs.go similarity index 99% rename from pkg/multicloud/hcs/hcs.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/hcs.go index 5c167f5f52..1d758f42d8 100644 --- a/pkg/multicloud/hcs/hcs.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/hcs.go @@ -31,9 +31,9 @@ import ( "yunion.io/x/pkg/gotypes" "yunion.io/x/pkg/utils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/auth" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/host.go new file mode 100644 index 0000000000..4dcb7404c3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/host.go @@ -0,0 +1,254 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone +} + +func (self *SHost) GetId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) +} + +func (self *SHost) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) IsEmulated() bool { + return true +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms, err := self.zone.region.GetInstances("") + if err != nil { + return nil, err + } + + ret := []cloudprovider.ICloudVM{} + for i := range vms { + if vms[i].OSEXTAZAvailabilityZone == self.zone.GetId() { + vms[i].host = self + ret = append(ret, &vms[i]) + } + } + return ret, nil +} + +func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := self.zone.region.GetInstance(id) + if err != nil { + return nil, err + } + vm.host = self + return vm, 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 api.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_HCS), "manufacture") + return info +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetCpuCount() int { + 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 api.DISK_TYPE_HYBRID +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_HCS +} + +func (self *SHost) GetIsMaintenance() bool { + return false +} + +func (self *SHost) GetVersion() string { + return HCS_API_VERSION +} + +func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + vm, err := self._createVM( + desc.Name, desc.ExternalImageId, desc.SysDisk, + desc.Cpu, desc.MemoryMB, desc.InstanceType, + desc.ExternalNetworkId, desc.IpAddr, + desc.Description, desc.Account, + desc.Password, desc.DataDisks, + desc.PublicKey, desc.ExternalSecgroupId, + desc.UserData, desc.BillingCycle, desc.ProjectId, desc.Tags) + if err != nil { + return nil, err + } + return vm, err +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, + networkId string, ipAddr string, desc string, account string, passwd string, + diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string, + userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (*SInstance, error) { + net, err := self.zone.region.GetNetwork(networkId) + if err != nil { + return nil, errors.Wrapf(err, "GetNetwork(%s)", networkId) + } + + keypair := "" + if len(publicKey) > 0 { + keypair, err = self.zone.region.syncKeypair(publicKey) + if err != nil { + return nil, err + } + } + + // 镜像及硬盘配置 + img, err := self.zone.region.GetImage(imgId) + if err != nil { + return nil, errors.Wrapf(err, "GetImage(%s)", imgId) + } + // passwd, windows机型直接使用密码比较方便 + if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(passwd) > 0 { + keypair = "" + } + + if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) { + if u, err := updateWindowsUserData(userData, img.OSVersion, account, passwd); err == nil { + userData = u + } else { + return nil, errors.Wrap(err, "SHost.CreateVM.updateWindowsUserData") + } + } + + if sysDisk.SizeGB > 0 && sysDisk.SizeGB < img.SizeGB { + sysDisk.SizeGB = img.SizeGB + } + + // 创建实例 + if len(instanceType) > 0 { + log.Debugf("Try instancetype : %s", instanceType) + vm, err := self.zone.region.CreateInstance(name, imgId, instanceType, networkId, secgroupId, + net.VpcId, self.zone.GetId(), desc, sysDisk, diskSizes, ipAddr, keypair, + passwd, userData, bc, projectId, tags) + if err != nil { + return nil, fmt.Errorf("create %s failed:%v", instanceType, err) + } + return vm, nil + } + + // 匹配实例类型 + instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, self.zone.GetId()) + if err != nil { + return nil, err + } + if len(instanceTypes) == 0 { + return nil, fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB) + } + + var vm *SInstance + for _, instType := range instanceTypes { + instanceTypeId := instType.Name + log.Debugf("Try instancetype : %s", instanceTypeId) + vm, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupId, + net.VpcId, self.zone.GetId(), desc, sysDisk, diskSizes, ipAddr, keypair, + passwd, userData, bc, projectId, tags) + if err != nil { + log.Errorf("Failed for %s: %s", instanceTypeId, err) + } else { + return vm, nil + } + } + + return nil, fmt.Errorf("create failed: %v", err) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/image.go new file mode 100644 index 0000000000..0834e2c3eb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/image.go @@ -0,0 +1,469 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/apis" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type TImageOwnerType string + +const ( + ImageOwnerPublic TImageOwnerType = "gold" // 公共镜像:gold + ImageOwnerSelf TImageOwnerType = "private" // 私有镜像:private + ImageOwnerShared TImageOwnerType = "shared" // 共享镜像:shared + + EnvFusionCompute = "FusionCompute" + EnvIronic = "Ironic" +) + +const ( + ImageStatusQueued = "queued" // queued:表示镜像元数据已经创建成功,等待上传镜像文件。 + ImageStatusSaving = "saving" // saving:表示镜像正在上传文件到后端存储。 + ImageStatusDeleted = "deleted" // deleted:表示镜像已经删除。 + ImageStatusKilled = "killed" // killed:表示镜像上传错误。 + ImageStatusActive = "active" // active:表示镜像可以正常使用 +) + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091565.html +type SImage struct { + multicloud.SImageBase + huawei.HuaweiTags + cache *SStoragecache + + // normalized image info + imgInfo *imagetools.ImageInfo + + Schema string `json:"schema"` + MinDiskGB int64 `json:"min_disk"` + CreatedAt time.Time `json:"created_at"` + ImageSourceType string `json:"__image_source_type"` + ContainerFormat string `json:"container_format"` + File string `json:"file"` + UpdatedAt time.Time `json:"updated_at"` + Protected bool `json:"protected"` + Checksum string `json:"checksum"` + Id string `json:"id"` + Isregistered string `json:"__isregistered"` + MinRamMB int `json:"min_ram"` + Lazyloading string `json:"__lazyloading"` + Owner string `json:"owner"` + OSType string `json:"__os_type"` + Imagetype string `json:"__imagetype"` + Visibility string `json:"visibility"` + VirtualEnvType string `json:"virtual_env_type"` + Platform string `json:"__platform"` + SizeGB int `json:"size"` + ImageSize int64 `json:"__image_size"` + OSBit string `json:"__os_bit"` + OSVersion string `json:"__os_version"` + Architecture string + Name string `json:"name"` + Self string `json:"self"` + DiskFormat string `json:"disk_format"` + Status string `json:"status"` + SupportKVMFPGAType string `json:"__support_kvm_fpga_type"` + SupportKVMNVMEHIGHIO string `json:"__support_nvme_highio"` + SupportLargeMemory string `json:"__support_largememory"` + SupportDiskIntensive string `json:"__support_diskintensive"` + SupportHighPerformance string `json:"__support_highperformance"` + SupportXENGPUType string `json:"__support_xen_gpu_type"` + SupportKVMGPUType string `json:"__support_kvm_gpu_type"` + SupportGPUT4 string `json:"__support_gpu_t4"` + SupportKVMAscend310 string `json:"__support_kvm_ascend_310"` + SupportArm string `json:"__support_arm"` +} + +func (self *SImage) GetMinRamSizeMb() int { + return self.MinRamMB +} + +func (self *SImage) GetId() string { + return self.Id +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (self *SImage) GetGlobalId() string { + return self.Id +} + +func (self *SImage) GetStatus() string { + switch self.Status { + case ImageStatusQueued: + return api.CACHED_IMAGE_STATUS_CACHING + case ImageStatusActive: + return api.CACHED_IMAGE_STATUS_ACTIVE + case ImageStatusKilled: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + default: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (self *SImage) GetImageStatus() string { + switch self.Status { + case ImageStatusQueued: + return cloudprovider.IMAGE_STATUS_QUEUED + case ImageStatusActive: + return cloudprovider.IMAGE_STATUS_ACTIVE + case ImageStatusKilled: + return cloudprovider.IMAGE_STATUS_KILLED + default: + return cloudprovider.IMAGE_STATUS_KILLED + } +} + +func (self *SImage) Refresh() error { + ret, err := self.cache.region.GetImage(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, ret) +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + switch self.Imagetype { + case "gold": + return cloudprovider.ImageTypeSystem + case "private": + return cloudprovider.ImageTypeCustomized + case "shared": + return cloudprovider.ImageTypeShared + default: + return cloudprovider.ImageTypeCustomized + } +} + +func (self *SImage) GetSizeByte() int64 { + return int64(self.MinDiskGB) * 1024 * 1024 * 1024 +} + +func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if self.imgInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(self.ImageSourceType, self.Architecture, self.OSType, self.Platform, "") + self.imgInfo = &imgInfo + } + + return self.imgInfo +} + +func (self *SImage) GetFullOsName() string { + return self.ImageSourceType +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) +} + +func (self *SImage) GetOsDist() string { + return self.getNormalizedImageInfo().OsDistro +} + +func (self *SImage) GetOsVersion() string { + return self.getNormalizedImageInfo().OsVersion +} + +func (self *SImage) GetOsLang() string { + return self.getNormalizedImageInfo().OsLang +} + +func (self *SImage) GetOsArch() string { + return self.getNormalizedImageInfo().OsArch +} + +func (self *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return int(self.MinDiskGB) +} + +func (self *SImage) GetImageFormat() string { + return self.DiskFormat +} + +func (self *SImage) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SImage) IsEmulated() bool { + return false +} + +func (self *SImage) Delete(ctx context.Context) error { + return self.cache.region.DeleteImage(self.GetId()) +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.cache +} + +func (self *SRegion) GetImage(imageId string) (*SImage, error) { + image := &SImage{cache: self.getStoragecache()} + res := fmt.Sprintf("images/%s", imageId) + return image, self.imsGet(res, image) +} + +func excludeImage(image SImage) bool { + if image.VirtualEnvType == "Ironic" { + return true + } + + if len(image.SupportDiskIntensive) > 0 { + return true + } + + if len(image.SupportKVMFPGAType) > 0 || len(image.SupportKVMAscend310) > 0 { + return true + } + + if len(image.SupportKVMGPUType) > 0 { + return true + } + + if len(image.SupportKVMNVMEHIGHIO) > 0 { + return true + } + + if len(image.SupportGPUT4) > 0 { + return true + } + + if len(image.SupportXENGPUType) > 0 { + return true + } + + if len(image.SupportHighPerformance) > 0 { + return true + } + + if len(image.SupportArm) > 0 { + return true + } + + return false +} + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0060804959.html +func (self *SRegion) GetImages(status string, imagetype TImageOwnerType, name string, envType string) ([]SImage, error) { + params := url.Values{} + if len(status) > 0 { + params.Set("status", status) + } + + if len(imagetype) > 0 { + params.Set("__imagetype", string(imagetype)) + if imagetype == ImageOwnerPublic { + params.Set("protected", "True") + } + } + if len(envType) > 0 { + params.Set("virtual_env_type", envType) + } + + if len(name) > 0 { + params.Set("name", name) + } + + images := []SImage{} + err := self.imsList("images", params, &images) + if err != nil { + return nil, err + } + + // 排除掉需要特定镜像才能创建的实例类型 + // https://support.huaweicloud.com/eu-west-0-api-ims/zh-cn_topic_0031617666.html#ZH-CN_TOPIC_0031617666__table48545918250 + // https://support.huaweicloud.com/productdesc-ecs/zh-cn_topic_0088142947.html + filtedImages := make([]SImage, 0) + for i := range images { + if !excludeImage(images[i]) { + filtedImages = append(filtedImages, images[i]) + } + } + return filtedImages, err +} + +func (self *SRegion) DeleteImage(imageId string) error { + res := fmt.Sprintf("images/%s", imageId) + return self.imsDelete(res) +} + +func (self *SRegion) GetImageByName(name string) (*SImage, error) { + if len(name) == 0 { + return nil, fmt.Errorf("image name should not be empty") + } + images, err := self.GetImages("", TImageOwnerType(""), name, "") + if err != nil { + return nil, err + } + if len(images) == 0 { + return nil, cloudprovider.ErrNotFound + } + log.Debugf("%d image found match name %s", len(images), name) + return &images[0], nil +} + +/* +https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html + + os version 取值范围: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html + 用于创建私有镜像的源云服务器系统盘大小大于等于40GB且不超过1024GB。 + 目前支持vhd,zvhd、raw,qcow2 + todo: 考虑使用镜像快速导入。 https://support.huaweicloud.com/api-ims/zh-cn_topic_0133188204.html + 使用OBS文件创建镜像 + + * openstack原生接口支持的格式:https://support.huaweicloud.com/api-ims/zh-cn_topic_0031615566.html +*/ +func (self *SRegion) ImportImageJob(name string, osDist string, osVersion string, osArch string, bucket string, key string, minDiskGB int64) error { + os_version, err := stdVersion(osDist, osVersion, osArch) + log.Debugf("%s %s %s: %s.min_disk %d GB", osDist, osVersion, osArch, os_version, minDiskGB) + if err != nil { + log.Debugln(err) + } + + image_url := fmt.Sprintf("%s:%s", bucket, key) + params := map[string]interface{}{ + "name": name, + "image_url": image_url, + "os_version": os_version, + "is_config_init": true, + "is_config": true, + "min_disk": minDiskGB, + } + return self.imsPerform("cloudimage", "action", params, nil) +} + +func formatVersion(osDist string, osVersion string) (string, error) { + err := fmt.Errorf("unsupport version %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osVersion) + dist := strings.ToLower(osDist) + if dist == "ubuntu" || dist == "redhat" || dist == "centos" || dist == "oracle" || dist == "euleros" { + parts := strings.Split(osVersion, ".") + if len(parts) < 2 { + return "", err + } + + return parts[0] + "." + parts[1], nil + } + + if dist == "debian" { + parts := strings.Split(osVersion, ".") + if len(parts) < 3 { + return "", err + } + + return parts[0] + "." + parts[1] + "." + parts[2], nil + } + + if dist == "fedora" || dist == "windows" || dist == "suse" { + parts := strings.Split(osVersion, ".") + if len(parts) < 1 { + return "", err + } + + return parts[0], nil + } + + if dist == "opensuse" { + parts := strings.Split(osVersion, ".") + if len(parts) == 0 { + return "", err + } + + if len(parts) == 1 { + return parts[0], nil + } + + if len(parts) >= 2 { + return parts[0] + "." + parts[1], nil + } + } + + return "", err +} + +// todo: 如何保持同步更新 +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html +func stdVersion(osDist string, osVersion string, osArch string) (string, error) { + // 架构 + arch := "" + switch osArch { + case "64", apis.OS_ARCH_X86_64: + arch = "64bit" + case "32", apis.OS_ARCH_X86_32: + arch = "32bit" + default: + return "", fmt.Errorf("unsupported arch %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osArch) + } + + _dist := strings.Split(strings.TrimSpace(osDist), " ")[0] + _dist = strings.ToLower(_dist) + // 版本 + ver, err := formatVersion(_dist, osVersion) + if err != nil { + return "", err + } + + // 操作系统 + dist := "" + + switch _dist { + case "ubuntu": + return fmt.Sprintf("Ubuntu %s server %s", ver, arch), nil + case "redhat": + dist = "Redhat Linux Enterprise" + case "centos": + dist = "CentOS" + case "fedora": + dist = "Fedora" + case "debian": + dist = "Debian GNU/Linux" + case "windows": + dist = "Windows Server" + case "oracle": + dist = "Oracle Linux Server release" + case "suse": + dist = "SUSE Linux Enterprise Server" + case "opensuse": + dist = "OpenSUSE" + case "euleros": + dist = "EulerOS" + default: + return "", fmt.Errorf("unsupported os %s. reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", dist) + } + + return fmt.Sprintf("%s %s %s", dist, ver, arch), nil +} + +func (self *SImage) UEFI() bool { + return false +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instance.go new file mode 100644 index 0000000000..c3a1e2ca98 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instance.go @@ -0,0 +1,1115 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + "encoding/base64" + "fmt" + "net/url" + "sort" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/cloudinit" + "yunion.io/x/onecloud/pkg/util/imagetools" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/apis" + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +const ( + InstanceStatusRunning = "ACTIVE" + InstanceStatusTerminated = "DELETED" + InstanceStatusStopped = "SHUTOFF" +) + +type IpAddress struct { + Version string `json:"version"` + Addr string `json:"addr"` + OSEXTIPSMACMACAddr string `json:"OS-EXT-IPS-MAC:mac_addr"` + OSEXTIPSPortId string `json:"OS-EXT-IPS:port_id"` + OSEXTIPSType string `json:"OS-EXT-IPS:type"` +} + +type Flavor struct { + Disk string `json:"disk"` + Vcpus string `json:"vcpus"` + RAM string `json:"ram"` + Id string `json:"id"` + Name string `json:"name"` +} + +type Image struct { + Id string `json:"id"` +} + +type VMMetadata struct { + MeteringImageId string `json:"metering.image_id"` + MeteringImagetype string `json:"metering.imagetype"` + MeteringOrderId string `json:"metering.order_id"` + MeteringResourcespeccode string `json:"metering.resourcespeccode"` + ImageName string `json:"image_name"` + OSBit string `json:"os_bit"` + VpcId string `json:"vpc_id"` + MeteringResourcetype string `json:"metering.resourcetype"` + CascadedInstanceExtrainfo string `json:"cascaded.instance_extrainfo"` + OSType string `json:"os_type"` + ChargingMode string `json:"charging_mode"` +} + +type OSExtendedVolumesVolumesAttached struct { + Device string `json:"device"` + BootIndex string `json:"bootIndex"` + Id string `json:"id"` + DeleteOnTermination string `json:"delete_on_termination"` +} + +type OSSchedulerHints struct { +} + +type SecurityGroup struct { + Name string `json:"name"` +} + +type SysTag struct { + Key string `json:"key"` + Value string `json:"value"` +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html +// https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0100166287.html v1.1 支持创建包年/包月的弹性云服务器 +type SInstance struct { + multicloud.SInstanceBase + huawei.HuaweiTags + + host *SHost + + osInfo *imagetools.ImageInfo + + Id string `json:"id"` + Name string `json:"name"` + Addresses map[string][]IpAddress `json:"addresses"` + Flavor Flavor `json:"flavor"` + AccessIPv4 string `json:"accessIPv4"` + AccessIPv6 string `json:"accessIPv6"` + Status string `json:"status"` + Progress string `json:"progress"` + HostId string `json:"hostId"` + Image Image `json:"image"` + Updated string `json:"updated"` + Created time.Time `json:"created"` + Metadata VMMetadata `json:"metadata"` + Description string `json:"description"` + Locked bool `json:"locked"` + ConfigDrive string `json:"config_drive"` + TenantId string `json:"tenant_id"` + UserId string `json:"user_id"` + KeyName string `json:"key_name"` + + OSExtendedVolumesVolumesAttached []OSExtendedVolumesVolumesAttached `json:"os-extended-volumes:volumes_attached"` + OSEXTSTSTaskState string `json:"OS-EXT-STS:task_state"` + OSEXTSTSPowerState int64 `json:"OS-EXT-STS:power_state"` + OSEXTSTSVMState string `json:"OS-EXT-STS:vm_state"` + OSEXTSRVATTRHost string `json:"OS-EXT-SRV-ATTR:host"` + OSEXTSRVATTRInstanceName string `json:"OS-EXT-SRV-ATTR:instance_name"` + OSEXTSRVATTRHypervisorHostname string `json:"OS-EXT-SRV-ATTR:hypervisor_hostname"` + OSDCFDiskConfig string `json:"OS-DCF:diskConfig"` + OSEXTAZAvailabilityZone string `json:"OS-EXT-AZ:availability_zone"` + OSSchedulerHints OSSchedulerHints `json:"os:scheduler_hints"` + OSEXTSRVATTRRootDeviceName string `json:"OS-EXT-SRV-ATTR:root_device_name"` + OSEXTSRVATTRRamdiskId string `json:"OS-EXT-SRV-ATTR:ramdisk_id"` + EnterpriseProjectId string `json:"enterprise_project_id"` + OSEXTSRVATTRUserData string `json:"OS-EXT-SRV-ATTR:user_data"` + OSSRVUSGLaunchedAt time.Time `json:"OS-SRV-USG:launched_at"` + OSEXTSRVATTRKernelId string `json:"OS-EXT-SRV-ATTR:kernel_id"` + OSEXTSRVATTRLaunchIndex int64 `json:"OS-EXT-SRV-ATTR:launch_index"` + HostStatus string `json:"host_status"` + OSEXTSRVATTRReservationId string `json:"OS-EXT-SRV-ATTR:reservation_id"` + OSEXTSRVATTRHostname string `json:"OS-EXT-SRV-ATTR:hostname"` + OSSRVUSGTerminatedAt time.Time `json:"OS-SRV-USG:terminated_at"` + SysTags []SysTag `json:"sys_tags"` + SecurityGroups []SecurityGroup `json:"security_groups"` +} + +func compareSet(currentSet []string, newSet []string) (add []string, remove []string, keep []string) { + sort.Strings(currentSet) + sort.Strings(newSet) + + i, j := 0, 0 + for i < len(currentSet) || j < len(newSet) { + if i < len(currentSet) && j < len(newSet) { + if currentSet[i] == newSet[j] { + keep = append(keep, currentSet[i]) + i += 1 + j += 1 + } else if currentSet[i] < newSet[j] { + remove = append(remove, currentSet[i]) + i += 1 + } else { + add = append(add, newSet[j]) + j += 1 + } + } else if i >= len(currentSet) { + add = append(add, newSet[j]) + j += 1 + } else if j >= len(newSet) { + remove = append(remove, currentSet[i]) + i += 1 + } + } + + return add, remove, keep +} + +// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) +func isBootDisk(server *SInstance, disk *SDisk) bool { + if disk.GetDiskType() != api.DISK_TYPE_SYS { + return false + } + + for _, attachment := range disk.Attachments { + if attachment.ServerId == server.GetId() && attachment.Device == server.OSEXTSRVATTRRootDeviceName { + return true + } + } + + return false +} + +func (self *SInstance) GetId() string { + return self.Id +} + +func (self *SInstance) GetHostname() string { + return self.OSEXTSRVATTRHostname +} + +func (self *SInstance) GetName() string { + return self.Name +} + +func (self *SInstance) GetGlobalId() string { + return self.Id +} + +func (self *SInstance) GetStatus() string { + switch self.Status { + case "ACTIVE": + return api.VM_RUNNING + case "MIGRATING", "REBUILD", "BUILD", "RESIZE", "VERIFY_RESIZE": // todo: pending ? + return api.VM_STARTING + case "REBOOT", "HARD_REBOOT": + return api.VM_STOPPING + case "SHUTOFF": + return api.VM_READY + default: + return api.VM_UNKNOWN + } +} + +func (self *SInstance) Refresh() error { + ret, err := self.host.zone.region.GetInstance(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, ret) +} + +func (self *SInstance) GetInstanceType() string { + return self.Flavor.Id +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + secgroups, err := self.host.zone.region.GetInstanceSecrityGroups(self.Id) + if err != nil { + return nil, err + } + ret := []string{} + for i := range secgroups { + ret = append(ret, secgroups[i].Id) + } + return ret, nil +} + +// https://support.huaweicloud.com/api-ecs/ecs_02_1002.html +// key 相同时value不会替换 +func (self *SRegion) CreateServerTags(instanceId string, tags map[string]string) error { + params := map[string]interface{}{ + "action": "create", + } + + tagsObj := []map[string]string{} + for k, v := range tags { + tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) + } + params["tags"] = tagsObj + + res := fmt.Sprintf("cloudservers/%s", instanceId) + return self.perform("ecs", "v1", res, "tags/action", params, nil) +} + +// https://support.huaweicloud.com/api-ecs/ecs_02_1003.html +func (self *SRegion) DeleteServerTags(instanceId string, tagsKey []string) error { + params := map[string]interface{}{ + "action": "delete", + } + tagsObj := []map[string]string{} + for _, k := range tagsKey { + tagsObj = append(tagsObj, map[string]string{"key": k}) + } + params["tags"] = tagsObj + res := fmt.Sprintf("cloudservers/%s", instanceId) + return self.perform("ecs", "v1", res, "tags/action", params, nil) +} + +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { + existedTags, err := self.GetTags() + if err != nil { + return errors.Wrap(err, "self.GetTags()") + } + deleteTagsKey := []string{} + for k := range existedTags { + if replace { + deleteTagsKey = append(deleteTagsKey, k) + } else { + if _, ok := tags[k]; ok { + deleteTagsKey = append(deleteTagsKey, k) + } + } + } + if len(deleteTagsKey) > 0 { + err := self.host.zone.region.DeleteServerTags(self.GetId(), deleteTagsKey) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.DeleteServerTags(%s,%s)", self.GetId(), deleteTagsKey) + } + } + if len(tags) > 0 { + err := self.host.zone.region.CreateServerTags(self.GetId(), tags) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.CreateServerTags(%s,%s)", self.GetId(), jsonutils.Marshal(tags).String()) + } + } + return nil +} + +func (self *SInstance) GetBillingType() string { + // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html + // charging_mode “0”:按需计费 “1”:按包年包月计费 + if self.Metadata.ChargingMode == "1" { + return billing_api.BILLING_TYPE_PREPAID + } + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SInstance) GetCreatedAt() time.Time { + return self.Created +} + +// charging_mode “0”:按需计费 “1”:按包年包月计费 +func (self *SInstance) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + attached := self.OSExtendedVolumesVolumesAttached + disks := make([]SDisk, 0) + for _, vol := range attached { + disk, err := self.host.zone.region.GetDisk(vol.Id) + if err != nil { + return nil, err + } + + disks = append(disks, *disk) + } + + ret := []cloudprovider.ICloudDisk{} + for i := 0; i < len(disks); i += 1 { + disks[i].region = self.host.zone.region + if isBootDisk(self, &disks[i]) { + ret = append([]cloudprovider.ICloudDisk{&disks[i]}, ret...) + } else { + ret = append(ret, &disks[i]) + } + } + return ret, nil +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics := make([]cloudprovider.ICloudNic, 0) + for _, ipAddresses := range self.Addresses { + for _, ipAddress := range ipAddresses { + if ipAddress.OSEXTIPSType == "fixed" { + nic := SInstanceNic{ + instance: self, + ipAddr: ipAddress.Addr, + macAddr: ipAddress.OSEXTIPSMACMACAddr, + } + nics = append(nics, &nic) + } + } + } + return nics, nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + ips := make([]string, 0) + for _, addresses := range self.Addresses { + for _, address := range addresses { + if address.OSEXTIPSType != "fixed" && !strings.HasPrefix(address.Addr, "100.") { + ips = append(ips, address.Addr) + } + } + } + + if len(ips) == 0 { + return nil, nil + } + + eips, err := self.host.zone.region.GetEips("", ips) + if err != nil { + return nil, err + } + if len(eips) > 0 { + eips[0].region = self.host.zone.region + return &eips[0], nil + } + return nil, nil +} + +func (self *SInstance) GetVcpuCount() int { + cpu, _ := strconv.Atoi(self.Flavor.Vcpus) + return cpu +} + +func (self *SInstance) GetVmemSizeMB() int { + mem, _ := strconv.Atoi(self.Flavor.RAM) + return int(mem) +} + +func (self *SInstance) GetBootOrder() string { + return "dcn" +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (self *SInstance) GetOSArch() string { + if len(self.Image.Id) > 0 { + image, err := self.host.zone.region.GetImage(self.Image.Id) + if err == nil { + return image.GetOsArch() + } + + log.Debugf("GetOSArch.GetImage %s: %s", self.Image.Id, err) + } + + t := self.GetInstanceType() + if len(t) > 0 { + if strings.HasPrefix(t, "k") { + return apis.OS_ARCH_AARCH64 + } + } + + return apis.OS_ARCH_X86 +} + +func (self *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(osprofile.NormalizeOSType(self.Metadata.OSType)) +} + +func (self *SInstance) GetOSName() string { + return self.Metadata.ImageName +} + +func (i *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { + if i.osInfo == nil { + osInfo := imagetools.NormalizeImageInfo(i.Metadata.ImageName, "", i.Metadata.OSType, "", "") + i.osInfo = &osInfo + } + return i.osInfo +} + +func (self *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.BIOS +} + +func (i *SInstance) GetOsDist() string { + return i.getNormalizedOsInfo().OsDistro +} + +func (i *SInstance) GetOsVersion() string { + return i.getNormalizedOsInfo().OsVersion +} + +func (i *SInstance) GetOsLang() string { + return i.getNormalizedOsInfo().OsLang +} + +func (self *SInstance) GetFullOsName() string { + return self.Metadata.ImageName +} + +func (self *SInstance) GetMachine() string { + return "pc" +} + +func (self *SInstance) GetOsArch() string { + if flavor, err := self.host.zone.region.GetICloudSku(self.Flavor.Id); err == nil { + return flavor.GetCpuArch() + } else { + log.Debugf("GetOSArch.GetICloudSku %s: %s", self.Flavor.Id, err) + } + + t := self.GetInstanceType() + if len(t) > 0 { + if strings.HasPrefix(t, "k") { + return apis.OS_ARCH_AARCH64 + } + } + + return apis.OS_ARCH_X86 +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.SetSecurityGroups([]string{secgroupId}) +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + currentSecgroups, err := self.GetSecurityGroupIds() + if err != nil { + return err + } + + add, remove, _ := compareSet(currentSecgroups, secgroupIds) + err = self.host.zone.region.AssignSecurityGroups(add, self.GetId()) + if err != nil { + return err + } + return self.host.zone.region.UnassignSecurityGroups(remove, self.GetId()) +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_HCS +} + +func (self *SInstance) StartVM(ctx context.Context) error { + if self.Status == InstanceStatusRunning { + return nil + } + + 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 + } + + if self.GetStatus() == api.VM_RUNNING { + return nil + } else if self.GetStatus() == api.VM_READY { + err := self.host.zone.region.StartVM(self.GetId()) + if err != nil { + return err + } + } + time.Sleep(interval) + } + return cloudprovider.ErrTimeout +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + if self.Status == InstanceStatusStopped { + return nil + } + + if self.Status == InstanceStatusTerminated { + log.Debugf("Instance already terminated.") + return nil + } + + err := self.host.zone.region.StopVM(self.GetId(), opts.IsForce) + if err != nil { + return err + } + return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + return self.host.zone.region.DeleteVM(self.GetId()) +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return self.host.zone.region.UpdateVM(self.GetId(), name) +} + +// https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0032380449.html +// 创建云服务器过程中注入用户数据。支持注入文本、文本文件或gzip文件。 +// 注入内容,需要进行base64格式编码。注入内容(编码之前的内容)最大长度32KB。 +// 对于Linux弹性云服务器,adminPass参数传入时,user_data参数不生效。 +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html 使用原镜像重装 +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html 更换系统盘操作系统 +// 不支持调整系统盘大小 +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + publicKeyName := "" + var err error + if len(desc.PublicKey) > 0 { + publicKeyName, err = self.host.zone.region.syncKeypair(desc.PublicKey) + if err != nil { + return "", err + } + } + + image, err := self.host.zone.region.GetImage(desc.ImageId) + if err != nil { + return "", errors.Wrap(err, "SInstance.RebuildRoot.GetImage") + } + + // Password存在的情况下,windows 系统直接使用密码 + if strings.ToLower(image.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(desc.Password) > 0 { + publicKeyName = "" + } + + userData, err := updateUserData(self.OSEXTSRVATTRUserData, image.OSVersion, desc.Account, desc.Password, desc.PublicKey) + if err != nil { + return "", errors.Wrap(err, "SInstance.RebuildRoot.updateUserData") + } + + if self.Metadata.MeteringImageId == desc.ImageId { + err = self.host.zone.region.RebuildRoot(ctx, self.UserId, self.GetId(), desc.Password, publicKeyName, userData) + if err != nil { + return "", err + } + } else { + err = self.host.zone.region.ChangeRoot(ctx, self.UserId, self.GetId(), desc.ImageId, desc.Password, publicKeyName, userData) + if err != nil { + return "", err + } + } + + idisks, err := self.GetIDisks() + if err != nil { + return "", err + } + + if len(idisks) == 0 { + return "", fmt.Errorf("server %s has no volume attached.", self.GetId()) + } + + return idisks[0].GetId(), nil +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return self.host.zone.region.DeployVM(self.GetId(), name, password, publicKey, deleteKeypair, description) +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + instanceTypes := []string{} + if len(config.InstanceType) > 0 { + instanceTypes = []string{config.InstanceType} + } else { + flavors, err := self.host.zone.region.GetMatchInstanceTypes(config.Cpu, config.MemoryMB, self.OSEXTAZAvailabilityZone) + if err != nil { + return errors.Wrapf(err, "GetMatchInstanceTypes") + } + for _, flavor := range flavors { + instanceTypes = append(instanceTypes, flavor.Id) + } + } + var err error + for _, instanceType := range instanceTypes { + err = self.host.zone.region.ChangeVMConfig(self.GetId(), instanceType) + if err != nil { + log.Warningf("ChangeVMConfig %s for %s error: %v", self.GetId(), instanceType, err) + } else { + return cloudprovider.WaitStatusWithDelay(self, api.VM_READY, 15*time.Second, 15*time.Second, 180*time.Second) + } + } + if err != nil { + return errors.Wrapf(err, "ChangeVMConfig") + } + return fmt.Errorf("Failed to change vm config, specification not supported") +} + +// todo:// 返回jsonobject感觉很诡异。不能直接知道内部细节 +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return self.host.zone.region.GetInstanceVNCUrl(self.GetId()) +} + +func (self *SInstance) NextDeviceName() (string, error) { + prefix := "s" + if strings.Contains(self.OSEXTSRVATTRRootDeviceName, "/vd") { + prefix = "v" + } + + currents := []string{} + for _, item := range self.OSExtendedVolumesVolumesAttached { + currents = append(currents, strings.ToLower(item.Device)) + } + + for i := 0; i < 25; i++ { + device := fmt.Sprintf("/dev/%sd%s", prefix, string([]byte{byte(98 + i)})) + if ok, _ := utils.InStringArray(device, currents); !ok { + return device, nil + } + } + + return "", fmt.Errorf("disk devicename out of index, current deivces: %s", currents) +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + device, err := self.NextDeviceName() + if err != nil { + return errors.Wrap(err, "Instance.AttachDisk.NextDeviceName") + } + + err = self.host.zone.region.AttachDisk(self.GetId(), diskId, device) + if err != nil { + return errors.Wrap(err, "Instance.AttachDisk.AttachDisk") + } + + return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { + disk, err := self.host.zone.region.GetDisk(diskId) + if err != nil { + log.Debugf("Instance.AttachDisk.GetDisk %s", err) + return false, nil + } + + if disk.Status == "in-use" { + return true, nil + } + + return false, nil + }) +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + err := self.host.zone.region.DetachDisk(self.GetId(), diskId) + if err != nil { + return errors.Wrap(err, "Instance.DetachDisk") + } + + return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { + disk, err := self.host.zone.region.GetDisk(diskId) + if err != nil { + log.Debugf("Instance.DetachDisk.GetDisk %s", err) + return false, nil + } + + if disk.Status == "available" { + return true, nil + } + + return false, nil + }) +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148850.html +func (self *SRegion) GetInstances(ip string) ([]SInstance, error) { + params := url.Values{} + if len(ip) > 0 { + params.Set("ip", ip) + } + params.Set("offset", "1") + ret := []SInstance{} + return ret, self.list("ecs", "v1", "cloudservers/detail", params, &ret) +} + +func (self *SRegion) GetInstance(id string) (*SInstance, error) { + ret := &SInstance{} + res := fmt.Sprintf("cloudservers/%s", id) + return ret, self.get("ecs", "v1", res, ret) +} +func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, subnetId string, + securityGroupId string, vpcId string, zoneId string, desc string, sysDisk cloudprovider.SDiskInfo, dataDisks []cloudprovider.SDiskInfo, ipAddr string, + keypair string, passwd string, userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (*SInstance, error) { + diskParams := []map[string]interface{}{} + for _, disk := range dataDisks { + diskParams = append(diskParams, map[string]interface{}{ + "volumetype": disk.StorageType, + "size": disk.SizeGB, + }) + } + params := map[string]interface{}{ + "availability_zone": zoneId, + "name": name, + "flavorRef": instanceType, + "imageRef": imageId, + "description": desc, + "count": 1, + "tenancy": "0", + "region_id": self.Id, + "operate_type": "apply", + "service_type": "ecs", + "tenantId": self.client.projectId, + "project_id": self.client.projectId, + "nics": []map[string]interface{}{ + { + "subnet_id": subnetId, + "ip_address": ipAddr, + "binding:profile": map[string]interface{}{ + "disable_security_groups": false, + }, + }, + }, + "security_groups": []map[string]interface{}{ + { + "id": securityGroupId, + }, + }, + "vpcid": vpcId, + "metadata": map[string]string{}, + "root_volume": map[string]interface{}{ + "volumetype": sysDisk.StorageType, + "size": sysDisk.SizeGB, + }, + "data_volumes": diskParams, + "extendparam": map[string]interface{}{ + "enterprise_project_id": projectId, + "regionID": self.Id, + }, + } + + if len(keypair) > 0 { + params["key_name"] = keypair + } else { + params["adminPass"] = passwd + } + + if len(userData) > 0 { + params["user_data"] = userData + } + tagParams := []map[string]interface{}{} + for k, v := range tags { + tagParams = append(tagParams, map[string]interface{}{ + "key": k, + "value": v, + }) + } + params["server_tags"] = tagParams + body := map[string]interface{}{ + "server": params, + } + job := &SJob{} + err := self.client.create("ecs", "v1.1", self.Id, "cloudservers", body, job) + if err != nil { + return nil, err + } + for _, sub := range job.Entities.SubJobs { + if len(sub.Entities.ServerId) > 0 { + return self.GetInstance(sub.Entities.ServerId) + } + } + return nil, fmt.Errorf("no server id returned with job %s", jsonutils.Marshal(job)) +} + +func (self *SRegion) AssignSecurityGroups(secgroupIds []string, instanceId string) error { + return cloudprovider.ErrNotImplemented +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067161717.html +func (self *SRegion) UnassignSecurityGroups(secgroupIds []string, instanceId string) error { + return cloudprovider.ErrNotImplemented +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212207.html +func (self *SRegion) StartVM(id string) error { + params := map[string]interface{}{ + "os-start": map[string]string{}, + } + res := fmt.Sprintf("servers/%s", id) + return self.ecsPerform(res, "action", params, nil) +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212651.html +func (self *SRegion) StopVM(id string, isForce bool) error { + params := map[string]interface{}{ + "os-stop": map[string]string{}, + } + res := fmt.Sprintf("servers/%s", id) + return self.ecsPerform(res, "action", params, nil) +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212679.html +// 只删除主机。弹性IP和数据盘需要单独删除 +func (self *SRegion) DeleteVM(id string) error { + params := map[string]interface{}{ + "delete_publicip": false, + "delete_volume": false, + "servers": []struct { + Id string + }{ + {Id: id}, + }, + } + return self.perform("ecs", "v1", "cloudservers", "delete", params, nil) +} + +func (self *SRegion) UpdateVM(instanceId, name string) error { + params := map[string]interface{}{ + "server": map[string]string{ + "name": name, + }, + } + return self.update("ecs", "v2.1", "servers/"+instanceId, params) +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html +// 返回job id +func (self *SRegion) RebuildRoot(ctx context.Context, userId, instanceId, passwd, publicKeyName, userData string) error { + reInstall := map[string]interface{}{} + if len(publicKeyName) > 0 { + reInstall["keyname"] = publicKeyName + } else if len(passwd) > 0 { + reInstall["adminpass"] = passwd + } else { + return fmt.Errorf("both password and publicKey are empty.") + } + if len(userId) > 0 { + reInstall["userid"] = userId + } + metadata := map[string]interface{}{} + if len(userData) > 0 { + metadata["user_data"] = userData + } + reInstall["metadata"] = metadata + + params := map[string]interface{}{ + "os-reinstall": reInstall, + } + return self.ecsPerform("cloudservers/"+instanceId, "reinstallos", params, nil) +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html +// 返回job id +func (self *SRegion) ChangeRoot(ctx context.Context, userId, instanceId, imageId, passwd, publicKeyName, userData string) error { + osChange := map[string]interface{}{} + if len(publicKeyName) > 0 { + osChange["keyname"] = publicKeyName + } else if len(passwd) > 0 { + osChange["adminpass"] = passwd + } else { + return fmt.Errorf("both password and publicKey are empty.") + } + if len(userId) > 0 { + osChange["userid"] = userId + } + metadata := map[string]interface{}{} + if len(userData) > 0 { + metadata["user_data"] = userData + } + osChange["metadata"] = metadata + osChange["imageid"] = imageId + params := map[string]interface{}{ + "os-change": osChange, + } + return self.ecsPerform("cloudservers/"+instanceId, "changeos", params, nil) +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212692.html +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0110109377.html +// 一键式重置密码 需要安装安装一键式重置密码插件 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0068095385.html +// 目前不支持直接重置密钥 +func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { + if len(name) > 0 { + err := self.UpdateVM(instanceId, name) + if err != nil { + return err + } + } + + if len(password) > 0 { + params := map[string]interface{}{ + "reset-password": map[string]interface{}{ + "new_password": password, + }, + } + return self.perform("ecs", "v1", "cloudservers/"+instanceId, "os-reset-password", params, nil) + } + return nil +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212653.html +func (self *SRegion) ChangeVMConfig(instanceId string, instanceType string) error { + params := map[string]interface{}{ + "resize": map[string]interface{}{ + "flavorRef": instanceType, + }, + } + return self.perform("ecs", "v1.1", "cloudservers/"+instanceId, "resize", params, nil) +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0142763126.html 微版本2.6及以上? +// https://support.huaweicloud.com/api-ecs/ecs_02_0208.html +func (self *SRegion) GetInstanceVNCUrl(instanceId string) (*cloudprovider.ServerVncOutput, error) { + params := map[string]interface{}{ + "remote_console": map[string]interface{}{ + "type": "novnc", + "protocol": "vnc", + }, + } + ret := &cloudprovider.ServerVncOutput{} + err := self.perform("ecs", "v1", "cloudservers/"+instanceId, "remote_console", params, ret) + if err != nil { + return nil, err + } + ret.Hypervisor = api.HYPERVISOR_HUAWEI + ret.Protocol = "huawei" + return ret, nil +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817702.html +func (self *SRegion) GetInstanceSecrityGroups(instanceId string) ([]SSecurityGroup, error) { + ret := []SSecurityGroup{} + return ret, self.get("ecs", "v2.1", "servers/"+instanceId+"/os-security-groups", &ret) +} + +func (self *SInstance) GetProjectId() string { + return self.EnterpriseProjectId +} + +func (self *SInstance) GetError() error { + return nil +} + +func updateUserData(userData, osVersion, username, password, publicKey string) (string, error) { + winOS := strings.ToLower(osprofile.OS_TYPE_WINDOWS) + osVersion = strings.ToLower(osVersion) + config := &cloudinit.SCloudConfig{} + if len(userData) > 0 { + if strings.Contains(osVersion, winOS) { + if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { + config = _config + } else { + log.Debugf("updateWindowsUserData invalid userdata %s", userData) + } + } else { + if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { + config = _config + } else { + return "", fmt.Errorf("updateLinuxUserData invalid userdata %s", userData) + } + } + } + + user := cloudinit.NewUser(username) + config.RemoveUser(user) + config.DisableRoot = 0 + if len(password) > 0 { + config.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON + user.Password(password) + config.MergeUser(user) + } + + if len(publicKey) > 0 { + user.SshKey(publicKey) + config.MergeUser(user) + } + + if strings.Contains(osVersion, winOS) { + userData, err := updateWindowsUserData(config.UserDataPowerShell(), osVersion, username, password) + if err != nil { + return "", errors.Wrap(err, "updateUserData.updateWindowsUserData") + } + return userData, nil + } else { + return config.UserDataBase64(), nil + } +} + +func updateWindowsUserData(userData string, osVersion string, username, password string) (string, error) { + // Windows Server 2003, Windows Vista, Windows Server 2008, Windows Server 2003 R2, Windows Server 2000, Windows Server 2012, Windows Server 2003 with SP1, Windows 8 + oldVersions := []string{"2000", "2003", "2008", "2012", "Vista"} + isOldVersion := false + for i := range oldVersions { + if strings.Contains(osVersion, oldVersions[i]) { + isOldVersion = true + } + } + + shells := "" + if isOldVersion { + shells += fmt.Sprintf("rem cmd\n") + if username == "Administrator" { + shells += fmt.Sprintf("net user %s %s\n", username, password) + } else { + shells += fmt.Sprintf("net user %s %s /add\n", username, password) + shells += fmt.Sprintf("net localgroup administrators %s /add\n", username) + } + + shells += fmt.Sprintf("net user %s /active:yes", username) + } else { + if !strings.HasPrefix(userData, "#ps1") { + shells = fmt.Sprintf("#ps1\n%s", userData) + } + } + + return base64.StdEncoding.EncodeToString([]byte(shells)), nil +} + +func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { + params := map[string]interface{}{ + "name": opts.Name, + "instance_id": instanceId, + } + if len(opts.Notes) > 0 { + params["description"] = func() string { + opts.Notes = strings.ReplaceAll(opts.Notes, "<", "") + opts.Notes = strings.ReplaceAll(opts.Notes, ">", "") + opts.Notes = strings.ReplaceAll(opts.Notes, "\n", "") + if len(opts.Notes) > 1024 { + opts.Notes = opts.Notes[:1024] + } + return opts.Notes + }() + } + ret := &SImage{cache: &SStoragecache{region: self}} + return ret, self.perform("ims", "v2", "cloudimages", "action", params, ret) +} + +func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { + image, err := self.host.zone.region.SaveImage(self.Id, opts) + if err != nil { + return nil, errors.Wrapf(err, "SaveImage") + } + return image, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instancenic.go new file mode 100644 index 0000000000..00af3a40ed --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instancenic.go @@ -0,0 +1,86 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +// =========================================== +type Interface struct { + PortState string `json:"port_state"` + FixedIPS []FixedIP `json:"fixed_ips"` + NetId string `json:"net_id"` // 网络Id. 与 SNetwork里的Id对应。统一使用这个Id + PortId string `json:"port_id"` + MACAddr string `json:"mac_addr"` +} + +type FixedIP struct { + SubnetId string `json:"subnet_id"` // 子网Id, 与SNetwork中的 neutron_subnet_id对应. 注意!!! 并不是SNetwork Id。 + IPAddress string `json:"ip_address"` +} + +type SInstanceNic struct { + instance *SInstance + ipAddr string + macAddr string + + cloudprovider.DummyICloudNic +} + +func (self *SInstanceNic) GetId() string { + return "" +} + +func (self *SInstanceNic) GetIP() string { + return self.ipAddr +} + +func (self *SInstanceNic) GetMAC() string { + return self.macAddr +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) GetINetworkId() string { + instanceId := self.instance.GetId() + subnets, _ := self.instance.host.zone.region.GetInstanceInterfaces(instanceId) + for i := range subnets { + return subnets[i].NetId + } + return "" +} + +type SInstanceInterface struct { + NetId string + PortId string + MacAddr string + PortState string + FixedIps []struct { + SubnetId string + IpAddress string + } +} + +func (self *SRegion) GetInstanceInterfaces(instanceId string) ([]SInstanceInterface, error) { + ret := []SInstanceInterface{} + return ret, self.get("ecs", "v2.1", "servers/"+instanceId+"/os-interface", &ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instancetype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instancetype.go new file mode 100644 index 0000000000..a76f034496 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/instancetype.go @@ -0,0 +1,223 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212656.html +type SInstanceType struct { + multicloud.SResourceBase + HcsTags + + Id string `json:"id"` + Name string `json:"name"` + Vcpus int `json:"vcpus"` + RamMB int `json:"ram"` // 内存大小 + OSExtraSpecs OSExtraSpecs `json:"os_extra_specs"` // 扩展规格 +} + +type OSExtraSpecs struct { + EcsPerformancetype string `json:"ecs:performancetype"` + EcsGeneration string `json:"ecs:generation"` + EcsInstanceArchitecture string `json:"ecs:instance_architecture"` +} + +func (self *SInstanceType) GetId() string { + return self.Id +} + +func (self *SInstanceType) GetName() string { + return self.Id +} + +func (self *SInstanceType) GetGlobalId() string { + return self.Id +} + +func (self *SInstanceType) GetInstanceTypeFamily() string { + if len(self.OSExtraSpecs.EcsGeneration) > 0 { + return self.OSExtraSpecs.EcsGeneration + } + return strings.Split(self.Name, ".")[0] +} + +func (self *SInstanceType) GetStatus() string { + return "" +} + +func (self *SInstanceType) GetInstanceTypeCategory() string { + return self.OSExtraSpecs.EcsPerformancetype +} + +func (self *SInstanceType) GetPrepaidStatus() string { + return api.SkuStatusSoldout +} + +func (self *SInstanceType) GetPostpaidStatus() string { + return api.SkuStatusAvailable +} + +func (self *SInstanceType) GetCpuArch() string { + if len(self.OSExtraSpecs.EcsInstanceArchitecture) > 0 { + if strings.HasPrefix(self.OSExtraSpecs.EcsInstanceArchitecture, "arm") { + return apis.OS_ARCH_AARCH64 + } + return apis.OS_ARCH_X86 + } + return "" +} + +func (self *SInstanceType) GetCpuCoreCount() int { + return self.Vcpus +} + +func (self *SInstanceType) GetMemorySizeMB() int { + return self.RamMB +} + +func (self *SInstanceType) GetOsName() string { + return "" +} + +func (self *SInstanceType) GetSysDiskResizable() bool { + return false +} + +func (self *SInstanceType) GetSysDiskType() string { + return "" +} + +func (self *SInstanceType) GetSysDiskMinSizeGB() int { + return 0 +} + +func (self *SInstanceType) GetSysDiskMaxSizeGB() int { + return 0 +} + +func (self *SInstanceType) GetAttachedDiskType() string { + return "" +} + +func (self *SInstanceType) GetAttachedDiskSizeGB() int { + return 0 +} + +func (self *SInstanceType) GetAttachedDiskCount() int { + return 0 +} + +func (self *SInstanceType) GetDataDiskTypes() string { + return "" +} + +func (self *SInstanceType) GetDataDiskMaxCount() int { + return 0 +} + +func (self *SInstanceType) GetNicType() string { + return "" +} + +func (self *SInstanceType) GetNicMaxCount() int { + return 0 +} + +func (self *SInstanceType) GetGpuAttachable() bool { + return self.OSExtraSpecs.EcsPerformancetype == "gpu" +} + +func (self *SInstanceType) GetGpuSpec() string { + if self.OSExtraSpecs.EcsPerformancetype == "gpu" { + return self.OSExtraSpecs.EcsGeneration + } + + return "" +} + +func (self *SInstanceType) GetGpuCount() int { + if self.OSExtraSpecs.EcsPerformancetype == "gpu" { + return 1 + } + + return 0 +} + +func (self *SInstanceType) GetGpuMaxCount() int { + if self.OSExtraSpecs.EcsPerformancetype == "gpu" { + return 1 + } + + return 0 +} + +func (self *SInstanceType) Delete() error { + return nil +} + +func (self *SRegion) GetchInstanceTypes(zoneId string) ([]SInstanceType, error) { + query := url.Values{} + if len(zoneId) > 0 { + query.Set("availability_zone", zoneId) + } + ret := []SInstanceType{} + return ret, self.list("ecs", "v1", "cloudservers/flavors", query, &ret) +} + +func (self *SRegion) GetchInstanceType(id string) (*SInstanceType, error) { + ret := &SInstanceType{} + res := fmt.Sprintf("flavors/%s", id) + return ret, self.get("ecs", "v2", res, &ret) +} + +func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, zoneId string) ([]SInstanceType, error) { + instanceTypes, err := self.GetchInstanceTypes(zoneId) + if err != nil { + return nil, err + } + + ret := make([]SInstanceType, 0) + for _, t := range instanceTypes { + // cpu & mem & disk都匹配才行 + if t.Vcpus == cpu && t.RamMB == memMB { + ret = append(ret, t) + } + } + + return ret, nil +} + +func (self *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { + flavors, err := self.GetchInstanceTypes("") + if err != nil { + return nil, errors.Wrap(err, "fetchInstanceTypes") + } + ret := []cloudprovider.ICloudSku{} + for i := range flavors { + ret = append(ret, &flavors[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/job.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/job.go new file mode 100644 index 0000000000..224b8fcc56 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/job.go @@ -0,0 +1,105 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + TASK_SUCCESS = "SUCCESS" + TASK_FAIL = "FAIL" +) + +type SJob struct { + Status string `json:"status"` + Entities struct { + SubJobsJotal int + ImageId string + ServerId string + SubJobs []SJob + } `json:"entities"` + JobId string `json:"job_id"` + JobType string `json:"job_type"` + BeginTime string `json:"begin_time"` + EndTime string `json:"end_time"` + ErrorCode string `json:"error_code"` + FailReason string `json:"fail_reason"` +} + +func (self *SJob) GetIds() []string { + ret := []string{} + if len(self.Entities.ImageId) > 0 { + ret = append(ret, self.Entities.ImageId) + } + if len(self.Entities.ServerId) > 0 { + ret = append(ret, self.Entities.ServerId) + } + for _, sub := range self.Entities.SubJobs { + if len(sub.Entities.ServerId) > 0 { + ret = append(ret, sub.Entities.ServerId) + } + } + return ret +} + +func (self *SHcsClient) waitJobSuccess(serviceType, regionId string, jobId string, interval time.Duration, timeout time.Duration) (*SJob, error) { + start := time.Now() + var job *SJob + var err error + for time.Now().Sub(start) < timeout { + job, err = self.GetJob(serviceType, regionId, jobId) + if err != nil { + return nil, err + } + log.Infof("wait %s job %s(%s) status: %s", serviceType, job.JobId, job.JobType, job.Status) + if job.Status == TASK_SUCCESS { + return job, nil + } + reason := []string{job.FailReason} + for _, subJob := range job.Entities.SubJobs { + if len(subJob.FailReason) > 0 { + reason = append(reason, subJob.FailReason) + } + } + if job.Status == TASK_FAIL { + return nil, fmt.Errorf("job %s failed reason %s", jobId, strings.Join(reason, ";")) + } + time.Sleep(interval) + } + return nil, errors.Wrapf(cloudprovider.ErrTimeout, "wait job %s", jsonutils.Marshal(job)) +} + +func (self *SHcsClient) GetJob(service, regionId string, jobId string) (*SJob, error) { + resp, err := self._getJob(service, regionId, jobId) + if err != nil { + return nil, err + } + ret := &SJob{} + return ret, resp.Unmarshal(ret) + +} + +func (self *SRegion) GetJob(service string, jobId string) (*SJob, error) { + return self.client.GetJob(service, self.Id, jobId) +} diff --git a/pkg/multicloud/hcs/keypair.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/keypair.go similarity index 100% rename from pkg/multicloud/hcs/keypair.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/keypair.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer.go new file mode 100644 index 0000000000..de11e0236a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer.go @@ -0,0 +1,602 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + "fmt" + "net/url" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +var LB_ALGORITHM_MAP = map[string]string{ + api.LB_SCHEDULER_WRR: "ROUND_ROBIN", + api.LB_SCHEDULER_WLC: "LEAST_CONNECTIONS", + api.LB_SCHEDULER_SCH: "SOURCE_IP", +} + +var LB_PROTOCOL_MAP = map[string]string{ + api.LB_LISTENER_TYPE_HTTP: "HTTP", + api.LB_LISTENER_TYPE_HTTPS: "TERMINATED_HTTPS", + api.LB_LISTENER_TYPE_UDP: "UDP", + api.LB_LISTENER_TYPE_TCP: "TCP", +} + +var LBBG_PROTOCOL_MAP = map[string]string{ + api.LB_LISTENER_TYPE_HTTP: "HTTP", + api.LB_LISTENER_TYPE_HTTPS: "HTTP", + api.LB_LISTENER_TYPE_UDP: "UDP", + api.LB_LISTENER_TYPE_TCP: "TCP", +} + +var LB_STICKY_SESSION_MAP = map[string]string{ + api.LB_STICKY_SESSION_TYPE_INSERT: "HTTP_COOKIE", + api.LB_STICKY_SESSION_TYPE_SERVER: "APP_COOKIE", +} + +var LB_HEALTHCHECK_TYPE_MAP = map[string]string{ + api.LB_HEALTH_CHECK_HTTP: "HTTP", + api.LB_HEALTH_CHECK_TCP: "TCP", + api.LB_HEALTH_CHECK_UDP: "UDP_CONNECT", +} + +type SLoadbalancer struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + subnet *SNetwork + eip *SEip + + Description string `json:"description"` + ProvisioningStatus string `json:"provisioning_status"` + TenantId string `json:"tenant_id"` + ProjectId string `json:"project_id"` + AdminStateUp bool `json:"admin_state_up"` + Provider string `json:"provider"` + Pools []Pool `json:"pools"` + Listeners []Listener `json:"listeners"` + VipPortId string `json:"vip_port_id"` + OperatingStatus string `json:"operating_status"` + VipAddress string `json:"vip_address"` + VipSubnetId string `json:"vip_subnet_id"` + Id string `json:"id"` + Name string `json:"name"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +type Listener struct { + Id string `json:"id"` +} + +type Pool struct { + Id string `json:"id"` +} + +func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { + if self.GetEip() == nil { + return nil, nil + } + + return self.eip, nil +} + +func (self *SLoadbalancer) GetId() string { + return self.Id +} + +func (self *SLoadbalancer) GetName() string { + return self.Name +} + +func (self *SLoadbalancer) GetGlobalId() string { + return self.Id +} + +func (self *SLoadbalancer) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancer) Refresh() error { + lb, err := self.region.GetLoadbalancer(self.GetId()) + if err != nil { + return err + } + + return jsonutils.Update(self, lb) +} + +func (self *SLoadbalancer) IsEmulated() bool { + return false +} + +func (self *SLoadbalancer) GetProjectId() string { + return self.ProjectId +} + +func (self *SLoadbalancer) GetAddress() string { + return self.VipAddress +} + +// todo: api.LB_ADDR_TYPE_INTERNET? +func (self *SLoadbalancer) GetAddressType() string { + return api.LB_ADDR_TYPE_INTRANET +} + +func (self *SLoadbalancer) GetNetworkType() string { + return api.LB_NETWORK_TYPE_VPC +} + +func (self *SLoadbalancer) GetNetworkIds() []string { + net := self.GetNetwork() + if net != nil { + return []string{net.GetId()} + } + + return []string{} +} + +func (self *SLoadbalancer) GetNetwork() *SNetwork { + if self.subnet == nil { + port, err := self.region.GetPort(self.VipPortId) + if err == nil { + net, err := self.region.GetNetwork(port.NetworkId) + if err == nil { + self.subnet = net + } else { + log.Debugf("huawei.SLoadbalancer.getNetwork %s", err) + } + } else { + log.Debugf("huawei.SLoadbalancer.GetPort %s", err) + } + } + + return self.subnet +} + +func (self *SLoadbalancer) GetEip() *SEip { + if self.eip == nil { + eips, _ := self.region.GetEips(self.VipPortId, nil) + for i := range eips { + self.eip = &eips[i] + } + } + return self.eip +} + +func (self *SLoadbalancer) GetVpcId() string { + net := self.GetNetwork() + if net != nil { + return net.VpcId + } + + return "" +} + +func (self *SLoadbalancer) GetZoneId() string { + net := self.GetNetwork() + if net != nil { + z, err := self.region.GetZoneById(net.AvailabilityZone) + if err != nil { + log.Infof("getZoneById %s %s", net.AvailabilityZone, err) + return "" + } + + return z.GetGlobalId() + } + + return "" +} + +func (self *SLoadbalancer) GetZone1Id() string { + return "" +} + +func (self *SLoadbalancer) GetLoadbalancerSpec() string { + return "" +} + +func (self *SLoadbalancer) GetChargeType() string { + eip := self.GetEip() + if eip != nil { + return eip.GetInternetChargeType() + } + + return api.EIP_CHARGE_TYPE_BY_TRAFFIC +} + +func (self *SLoadbalancer) GetEgressMbps() int { + eip := self.GetEip() + if eip != nil { + return eip.GetBandwidth() + } + + return 0 +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0141008275.html +func (self *SLoadbalancer) Delete(ctx context.Context) error { + return self.region.DeleteLoadBalancer(self.GetId()) +} + +func (self *SLoadbalancer) Start() error { + return nil +} + +func (self *SLoadbalancer) Stop() error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + ret, err := self.region.GetLoadBalancerListeners(self.GetId()) + if err != nil { + return nil, err + } + + iret := make([]cloudprovider.ICloudLoadbalancerListener, 0) + for i := range ret { + listener := ret[i] + listener.lb = self + iret = append(iret, &listener) + } + + return iret, nil +} + +func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + ret, err := self.region.GetLoadBalancerBackendGroups(self.GetId()) + if err != nil { + return nil, err + } + + iret := make([]cloudprovider.ICloudLoadbalancerBackendGroup, 0) + for i := range ret { + bg := ret[i] + bg.lb = self + bg.region = self.region + iret = append(iret, &bg) + } + + return iret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561549.html +func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + ret, err := self.region.CreateLoadBalancerBackendGroup(group) + ret.lb = self + return &ret, err +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561563.html +func (self *SLoadbalancer) CreateHealthCheck(backendGroupId string, healthcheck *cloudprovider.SLoadbalancerHealthCheck) error { + _, err := self.region.CreateLoadBalancerHealthCheck(backendGroupId, healthcheck) + return err +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561548.html +func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + ret := &SElbBackendGroup{lb: self, region: self.region} + return ret, self.region.lbGet("lbaas/pools/"+groupId, ret) +} + +func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + ret, err := self.region.CreateLoadBalancerListener(listener) + if err != nil { + return nil, err + } + + ret.lb = self + return &ret, nil +} + +func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { + ret := &SElbListener{lb: self} + return ret, self.region.lbGet("lbaas/listeners/"+listenerId, ret) +} + +func (self *SRegion) GetLoadbalancer(id string) (*SLoadbalancer, error) { + ret := &SLoadbalancer{region: self} + return ret, self.lbGet("lbaas/loadbalancers/"+id, ret) +} + +func (self *SRegion) DeleteLoadBalancer(elbId string) error { + resource := fmt.Sprintf("lbaas/loadbalancers/%s", elbId) + return self.lbDelete(resource) +} + +func (self *SRegion) GetLoadBalancerListeners(lbId string) ([]SElbListener, error) { + ret := []SElbListener{} + params := url.Values{} + if len(lbId) > 0 { + params.Set("loadbalancer_id", lbId) + } + return ret, self.lbList("lbaas/listeners", params, &ret) +} + +func (self *SRegion) CreateLoadBalancerListener(listener *cloudprovider.SLoadbalancerListener) (SElbListener, error) { + params := map[string]interface{}{ + "name": listener.Name, + "description": listener.Description, + "protocol": LB_PROTOCOL_MAP[listener.ListenerType], + "protocol_port": listener.ListenerPort, + "loadbalancer_id": listener.LoadbalancerID, + "http2_enable": listener.EnableHTTP2, + } + if len(listener.BackendGroupID) > 0 { + params["default_pool_id"] = listener.BackendGroupID + } + + if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { + params["default_tls_container_ref"] = listener.CertificateID + } + + if listener.XForwardedFor { + params["insert_headers"] = map[string]interface{}{ + "X-Forwarded-ELB-IP": listener.XForwardedFor, + } + } + + ret := SElbListener{} + err := self.lbCreate("lbaas/listeners", map[string]interface{}{"listener": params}, &ret) + if err != nil { + return ret, err + } + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html +func (self *SRegion) GetLoadBalancerBackendGroups(elbId string) ([]SElbBackendGroup, error) { + query := url.Values{} + if len(elbId) > 0 { + query.Set("loadbalancer_id", elbId) + } + + ret := []SElbBackendGroup{} + return ret, self.lbList("lbaas/pools", query, &ret) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html +func (self *SRegion) CreateLoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (SElbBackendGroup, error) { + ret := SElbBackendGroup{region: self} + var protocol, scheduler string + if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { + return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) + } else { + scheduler = s + } + + if t, ok := LBBG_PROTOCOL_MAP[group.ListenType]; !ok { + return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported listener type %s", group.ListenType) + } else { + protocol = t + } + + params := map[string]interface{}{ + "project_id": self.client.projectId, + "name": group.Name, + "protocol": protocol, + "lb_algorithm": scheduler, + } + + if len(group.ListenerID) > 0 { + params["listener_id"] = group.ListenerID + } else if len(group.LoadbalancerID) > 0 { + params["loadbalancer_id"] = group.LoadbalancerID + } else { + return ret, fmt.Errorf("CreateLoadBalancerBackendGroup one of listener id / loadbalancer id must be specified") + } + + if group.StickySession != nil { + s := map[string]interface{}{} + timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) + if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { + s["type"] = "SOURCE_IP" + if timeout > 0 { + s["persistence_timeout"] = timeout + } + } else { + s["type"] = LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType] + if len(group.StickySession.StickySessionCookie) > 0 { + s["cookie_name"] = group.StickySession.StickySessionCookie + } else { + if timeout > 0 { + s["persistence_timeout"] = timeout + } + } + } + params["session_persistence"] = s + } + err := self.lbCreate("lbaas/pools", map[string]interface{}{"pool": params}, &ret) + if err != nil { + return ret, err + } + + if group.HealthCheck != nil { + _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) + if err != nil { + return ret, err + } + } + + return ret, nil +} + +func (self *SRegion) CreateLoadBalancerHealthCheck(backendGroupId string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { + params := map[string]interface{}{ + "delay": healthCheck.HealthCheckInterval, + "max_retries": healthCheck.HealthCheckRise, + "pool_id": backendGroupId, + "timeout": healthCheck.HealthCheckTimeout, + "type": LB_HEALTHCHECK_TYPE_MAP[healthCheck.HealthCheckType], + } + if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { + if len(healthCheck.HealthCheckDomain) > 0 { + params["domain_name"] = healthCheck.HealthCheckDomain + } + + if len(healthCheck.HealthCheckURI) > 0 { + params["url_path"] = healthCheck.HealthCheckURI + } + + if len(healthCheck.HealthCheckHttpCode) > 0 { + params["expected_codes"] = ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode) + } + } + + ret := SElbHealthCheck{region: self} + err := self.lbCreate("lbaas/healthmonitors", map[string]interface{}{"healthmonitor": params}, &ret) + if err != nil { + return ret, err + } + + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561564.html +func (self *SRegion) UpdateLoadBalancerHealthCheck(healthCheckId string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { + params := map[string]interface{}{ + "delay": healthCheck.HealthCheckInterval, + "max_retries": healthCheck.HealthCheckRise, + "timeout": healthCheck.HealthCheckTimeout, + } + if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { + if len(healthCheck.HealthCheckDomain) > 0 { + params["domain_name"] = healthCheck.HealthCheckDomain + } + + if len(healthCheck.HealthCheckURI) > 0 { + params["url_path"] = healthCheck.HealthCheckURI + } + + if len(healthCheck.HealthCheckHttpCode) > 0 { + params["expected_codes"] = ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode) + } + } + + ret := SElbHealthCheck{region: self} + res := "lbaas/healthmonitors/" + healthCheckId + err := self.lbUpdate(res, map[string]interface{}{"healthmonitor": params}) + if err != nil { + return ret, err + } + return ret, self.lbGet(res, &ret) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561565.html +func (self *SRegion) DeleteLoadbalancerHealthCheck(healthCheckId string) error { + return self.lbDelete("lbaas/healthmonitors/" + healthCheckId) +} + +func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) lbGet(resource string, retVal interface{}) error { + return self.client.get("vpc", "v2.0", self.Id, resource, retVal) +} + +func (self *SRegion) lbList(resource string, params url.Values, retVal interface{}) error { + return self.list("vpc", "v2.0", resource, params, retVal) +} + +func (self *SRegion) lbDelete(resource string) error { + return self.delete("vpc", "v2.0", resource) +} + +func (self *SRegion) lbCreate(resource string, params map[string]interface{}, retVal interface{}) error { + return self.create("vpc", "v2.0", resource, params, retVal) +} + +func (self *SRegion) lbUpdate(resource string, params map[string]interface{}) error { + return self.update("vpc", "v2.0", resource, params) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561535.html +func (self *SRegion) CreateLoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (*SLoadbalancer, error) { + subnet, err := self.GetNetwork(loadbalancer.NetworkIDs[0]) + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateLoadBalancer.getNetwork") + } + + params := map[string]interface{}{ + "name": loadbalancer.Name, + "vip_subnet_id": subnet.NeutronSubnetId, + "tenant_id": self.client.projectId, + } + if len(loadbalancer.Address) > 0 { + params["vip_address"] = loadbalancer.Address + } + ret := &SLoadbalancer{region: self} + err = self.lbCreate("lbaas/loadbalancers", map[string]interface{}{"loadbalancer": params}, ret) + if err != nil { + return nil, err + } + + // 创建公网类型ELB + if len(loadbalancer.EipID) > 0 { + err := self.AssociateEipWithPortId(loadbalancer.EipID, ret.VipPortId) + if err != nil { + return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.AssociateEipWithPortId") + } + } + return ret, nil +} + +func (self *SRegion) GetLoadBalancers() ([]SLoadbalancer, error) { + lbs := []SLoadbalancer{} + params := url.Values{} + return lbs, self.lbList("lbaas/loadbalancers", params, &lbs) +} + +func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + elbs, err := self.GetLoadBalancers() + if err != nil { + return nil, err + } + + ret := []cloudprovider.ICloudLoadbalancer{} + for i := range elbs { + elbs[i].region = self + ret = append(ret, &elbs[i]) + } + + return ret, nil +} + +func (self *SRegion) GetILoadBalancerById(id string) (cloudprovider.ICloudLoadbalancer, error) { + elb, err := self.GetLoadbalancer(id) + if err != nil { + return nil, err + } + return elb, nil +} + +func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + ret, err := self.CreateLoadBalancer(loadbalancer) + if err != nil { + return nil, err + } + + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_acl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_acl.go new file mode 100644 index 0000000000..9cd3ff5e8a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_acl.go @@ -0,0 +1,156 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "net/url" + "strings" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SElbACL struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + + Id string `json:"id"` + ListenerId string `json:"listener_id"` + TenantId string `json:"tenant_id"` + EnableWhitelist bool `json:"enable_whitelist"` + Whitelist string `json:"whitelist"` +} + +func (self *SElbACL) GetAclListenerID() string { + return self.ListenerId +} + +func (self *SElbACL) GetId() string { + return self.Id +} + +func (self *SElbACL) GetName() string { + return self.Id +} + +func (self *SElbACL) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbACL) GetStatus() string { + if self.EnableWhitelist { + return api.LB_BOOL_ON + } + + return api.LB_BOOL_OFF +} + +func (self *SElbACL) Refresh() error { + acl, err := self.region.GetLoadBalancerAcl(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, acl) +} + +func (self *SElbACL) IsEmulated() bool { + return false +} + +func (self *SElbACL) GetProjectId() string { + return "" +} + +func (self *SElbACL) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { + ret := []cloudprovider.SLoadbalancerAccessControlListEntry{} + for _, cidr := range strings.Split(self.Whitelist, ",") { + ret = append(ret, cloudprovider.SLoadbalancerAccessControlListEntry{CIDR: cidr}) + } + + return ret +} + +func (self *SElbACL) Sync(acl *cloudprovider.SLoadbalancerAccessControlList) error { + whiteList := "" + cidrs := []string{} + for _, entry := range acl.Entrys { + cidrs = append(cidrs, entry.CIDR) + } + whiteList = strings.Join(cidrs, ",") + params := map[string]interface{}{ + "whitelist": whiteList, + "enable_whitelist": acl.AccessControlEnable, + } + return self.region.lbUpdate("lbaas/whitelists/"+self.GetId(), map[string]interface{}{"whitelist": params}) +} + +func (self *SElbACL) Delete() error { + return self.region.lbDelete("lbaas/whitelists/" + self.GetId()) +} + +func (self *SRegion) GetLoadBalancerAcl(aclId string) (*SElbACL, error) { + ret := &SElbACL{region: self} + return ret, self.lbGet("lbaas/whitelists/"+aclId, ret) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561582.html +func (self *SRegion) GetLoadBalancerAcls(listenerId string) ([]SElbACL, error) { + query := url.Values{} + if len(listenerId) > 0 { + query.Set("listener_id", listenerId) + } + ret := []SElbACL{} + return ret, self.lbList("lbaas/whitelists", query, &ret) +} + +func (self *SRegion) CreateLoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (*SElbACL, error) { + params := map[string]interface{}{ + "listener_id": acl.ListenerId, + } + if len(acl.Entrys) > 0 { + whitelist := []string{} + for i := range acl.Entrys { + whitelist = append(whitelist, acl.Entrys[i].CIDR) + } + params["enable_whitelist"] = acl.AccessControlEnable + params["whitelist"] = strings.Join(whitelist, ",") + } else { + params["enable_whitelist"] = false + } + ret := &SElbACL{region: self} + return ret, self.lbCreate("lbaas/whitelists", map[string]interface{}{"whitelist": params}, ret) +} + +func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + ret, err := self.CreateLoadBalancerAcl(acl) + if err != nil { + return nil, err + } + + return ret, nil +} + +func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { + acl, err := self.GetLoadBalancerAcl(aclId) + if err != nil { + return nil, err + } + return acl, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_backend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_backend.go new file mode 100644 index 0000000000..6539ddbe8e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_backend.go @@ -0,0 +1,142 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SElbBackend struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + lb *SLoadbalancer + backendGroup *SElbBackendGroup + + Name string `json:"name"` + Weight int `json:"weight"` + AdminStateUp bool `json:"admin_state_up"` + SubnetId string `json:"subnet_id"` + TenantId string `json:"tenant_id"` + ProjectId string `json:"project_id"` + Address string `json:"address"` + ProtocolPort int `json:"protocol_port"` + OperatingStatus string `json:"operating_status"` + Id string `json:"id"` +} + +func (self *SElbBackend) GetId() string { + return self.Id +} + +func (self *SElbBackend) GetName() string { + return self.Name +} + +func (self *SElbBackend) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbBackend) Refresh() error { + backend, err := self.region.GetElbBackend(self.backendGroup.GetId(), self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, backend) +} + +func (self *SElbBackend) IsEmulated() bool { + return false +} + +func (self *SElbBackend) GetProjectId() string { + return "" +} + +func (self *SElbBackend) GetWeight() int { + return self.Weight +} + +func (self *SElbBackend) GetPort() int { + return self.ProtocolPort +} + +func (self *SElbBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (self *SElbBackend) GetBackendRole() string { + return api.LB_BACKEND_ROLE_DEFAULT +} + +func (self *SElbBackend) GetBackendId() string { + i, err := self.lb.region.getInstanceByIP(self.Address) + if err != nil { + log.Errorf("ElbBackend GetBackendId %s", err) + } + + if i != nil { + return i.GetId() + } + + return "" +} + +func (self *SElbBackend) GetIpAddress() string { + return "" +} + +func (self *SElbBackend) SyncConf(ctx context.Context, port, weight int) error { + if port > 0 { + log.Warningf("Elb backend SyncConf unsupport modify port") + } + + params := map[string]interface{}{ + "weight": weight, + } + res := fmt.Sprintf("lbaas/pools/%s/members/%s", self.backendGroup.GetId(), self.Id) + return self.region.lbUpdate(res, map[string]interface{}{"member": params}) +} + +func (self *SRegion) getInstanceByIP(ip string) (*SInstance, error) { + instances, err := self.GetInstances(ip) + if err != nil { + return nil, errors.Wrapf(err, "GetInstance(%s)", ip) + } + for i := range instances { + return &instances[i], nil + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetElbBackend(pool, id string) (*SElbBackend, error) { + res := fmt.Sprintf("lbaas/pools/%s/members/%s", pool, id) + ret := &SElbBackend{region: self} + return ret, self.lbGet(res, ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_backendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_backendgroup.go new file mode 100644 index 0000000000..b2d1dab839 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_backendgroup.go @@ -0,0 +1,491 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SElbBackendGroup struct { + multicloud.SResourceBase + huawei.HuaweiTags + lb *SLoadbalancer + region *SRegion + + LBAlgorithm string `json:"lb_algorithm"` + Protocol string `json:"protocol"` + Description string `json:"description"` + AdminStateUp bool `json:"admin_state_up"` + Loadbalancers []Listener `json:"loadbalancers"` + TenantId string `json:"tenant_id"` + ProjectId string `json:"project_id"` + Listeners []Listener `json:"listeners"` + Id string `json:"id"` + Name string `json:"name"` + HealthMonitorId string `json:"healthmonitor_id"` + SessionPersistence StickySession `json:"session_persistence"` +} + +func (self *SElbBackendGroup) GetLoadbalancerId() string { + return self.lb.GetId() +} + +func (self *SElbBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { + return self.lb +} + +type StickySession struct { + Type string `json:"type"` + CookieName string `json:"cookie_name"` + PersistenceTimeout int `json:"persistence_timeout"` +} + +func (self *SElbBackendGroup) GetProtocolType() string { + switch self.Protocol { + case "TCP": + return api.LB_LISTENER_TYPE_TCP + case "UDP": + return api.LB_LISTENER_TYPE_UDP + case "HTTP": + return api.LB_LISTENER_TYPE_HTTP + default: + return "" + } +} + +func (self *SElbBackendGroup) GetScheduler() string { + switch self.LBAlgorithm { + case "ROUND_ROBIN": + return api.LB_SCHEDULER_WRR + case "LEAST_CONNECTIONS": + return api.LB_SCHEDULER_WLC + case "SOURCE_IP": + return api.LB_SCHEDULER_SCH + default: + return "" + } +} + +func ToHuaweiHealthCheckHttpCode(c string) string { + c = strings.TrimSpace(c) + segs := strings.Split(c, ",") + ret := []string{} + for _, seg := range segs { + seg = strings.TrimLeft(seg, "http_") + seg = strings.TrimSpace(seg) + seg = strings.Replace(seg, "xx", "00", -1) + ret = append(ret, seg) + } + + return strings.Join(ret, ",") +} + +func ToOnecloudHealthCheckHttpCode(c string) string { + c = strings.TrimSpace(c) + segs := strings.Split(c, ",") + ret := []string{} + for _, seg := range segs { + seg = strings.TrimSpace(seg) + seg = strings.Replace(seg, "00", "xx", -1) + seg = "http_" + seg + ret = append(ret, seg) + } + + return strings.Join(ret, ",") +} + +func (self *SElbBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + if len(self.HealthMonitorId) == 0 { + return nil, nil + } + + health, err := self.region.GetLoadBalancerHealthCheck(self.HealthMonitorId) + if err != nil { + return nil, err + } + + var healthCheckType string + switch health.Type { + case "TCP": + healthCheckType = api.LB_HEALTH_CHECK_TCP + case "UDP_CONNECT": + healthCheckType = api.LB_HEALTH_CHECK_UDP + case "HTTP": + healthCheckType = api.LB_HEALTH_CHECK_HTTP + default: + healthCheckType = "" + } + + ret := cloudprovider.SLoadbalancerHealthCheck{ + HealthCheckType: healthCheckType, + HealthCheckTimeout: health.Timeout, + HealthCheckDomain: health.DomainName, + HealthCheckURI: health.URLPath, + HealthCheckInterval: health.Delay, + HealthCheckRise: health.MaxRetries, + HealthCheckHttpCode: ToOnecloudHealthCheckHttpCode(health.ExpectedCodes), + } + + return &ret, nil +} + +func (self *SElbBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + if len(self.SessionPersistence.Type) == 0 { + return nil, nil + } + + var stickySessionType string + switch self.SessionPersistence.Type { + case "SOURCE_IP": + stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT + case "HTTP_COOKIE": + stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT + case "APP_COOKIE": + stickySessionType = api.LB_STICKY_SESSION_TYPE_SERVER + } + + ret := cloudprovider.SLoadbalancerStickySession{ + StickySession: api.LB_BOOL_ON, + StickySessionCookie: self.SessionPersistence.CookieName, + StickySessionType: stickySessionType, + StickySessionCookieTimeout: self.SessionPersistence.PersistenceTimeout * 60, + } + + return &ret, nil +} + +func (self *SElbBackendGroup) GetId() string { + return self.Id +} + +func (self *SElbBackendGroup) GetName() string { + return self.Name +} + +func (self *SElbBackendGroup) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbBackendGroup) Refresh() error { + ret, err := self.lb.region.GetLoadBalancerBackendGroupId(self.GetId()) + if err != nil { + return err + } + ret.lb = self.lb + + err = jsonutils.Update(self, ret) + if err != nil { + return err + } + + return nil +} + +func (self *SElbBackendGroup) IsEmulated() bool { + return false +} + +func (self *SElbBackendGroup) GetProjectId() string { + return self.ProjectId +} + +func (self *SElbBackendGroup) IsDefault() bool { + return false +} + +func (self *SElbBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_NORMAL +} + +func (self *SElbBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + ret, err := self.region.GetLoadBalancerBackends(self.GetId()) + if err != nil { + return nil, err + } + + iret := []cloudprovider.ICloudLoadbalancerBackend{} + for i := range ret { + backend := ret[i] + backend.lb = self.lb + backend.backendGroup = self + + iret = append(iret, &backend) + } + + return iret, nil +} + +func (self *SElbBackendGroup) GetILoadbalancerBackendById(serverId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + backend, err := self.region.GetElbBackend(self.GetId(), serverId) + if err != nil { + return nil, err + } + backend.lb = self.lb + backend.backendGroup = self + return backend, nil +} + +func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + instance, err := self.lb.region.GetInstance(serverId) + if err != nil { + return nil, err + } + + nics, err := instance.GetINics() + if err != nil { + return nil, err + } else if len(nics) == 0 { + return nil, fmt.Errorf("AddBackendServer %s no network interface found", serverId) + } + + subnets, err := self.lb.region.GetInstanceInterfaces(instance.GetId()) + if err != nil { + return nil, err + } else if len(subnets) == 0 { + return nil, fmt.Errorf("AddBackendServer %s no subnet found", serverId) + } + + net, err := self.lb.region.GetNetwork(subnets[0].NetId) + if err != nil { + return nil, err + } + + backend, err := self.region.AddLoadBalancerBackend(self.GetId(), net.NeutronSubnetId, nics[0].GetIP(), port, weight) + if err != nil { + return nil, err + } + + backend.lb = self.lb + backend.backendGroup = self + return backend, nil +} + +func (self *SElbBackendGroup) RemoveBackendServer(backendId string, weight int, port int) error { + ibackend, err := self.GetILoadbalancerBackendById(backendId) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + + return errors.Wrap(err, "ElbBackendGroup.GetILoadbalancerBackendById") + } + + err = self.region.RemoveLoadBalancerBackend(self.GetId(), backendId) + if err != nil { + return errors.Wrap(err, "ElbBackendGroup.RemoveBackendServer") + } + + return cloudprovider.WaitDeleted(ibackend, 2*time.Second, 30*time.Second) +} + +func (self *SElbBackendGroup) Delete(ctx context.Context) error { + if len(self.HealthMonitorId) > 0 { + err := self.region.DeleteLoadbalancerHealthCheck(self.HealthMonitorId) + if err != nil { + return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadbalancerHealthCheck") + } + } + + // 删除后端服务器组的同时,删除掉无效的后端服务器数据 + { + backends, err := self.region.getLoadBalancerAdminStateDownBackends(self.GetId()) + if err != nil { + return errors.Wrap(err, "SElbBackendGroup.Delete.getLoadBalancerAdminStateDownBackends") + } + + for i := range backends { + backend := backends[i] + err := self.RemoveBackendServer(backend.GetId(), backend.GetPort(), backend.GetWeight()) + if err != nil { + return errors.Wrap(err, "SElbBackendGroup.Delete.RemoveBackendServer") + } + } + } + + err := self.region.DeleteLoadBalancerBackendGroup(self.GetId()) + if err != nil { + return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadBalancerBackendGroup") + } + + return cloudprovider.WaitDeleted(self, 2*time.Second, 30*time.Second) +} + +func (self *SElbBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + if group == nil { + return nil + } + + _, err := self.region.UpdateLoadBalancerBackendGroup(self.GetId(), group) + return err +} + +func (self *SRegion) GetLoadBalancerBackendGroupId(backendGroupId string) (*SElbBackendGroup, error) { + ret := &SElbBackendGroup{region: self} + res := fmt.Sprintf("lbaas/pools/" + backendGroupId) + return ret, self.lbGet(res, ret) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561550.html +func (self *SRegion) UpdateLoadBalancerBackendGroup(backendGroupId string, group *cloudprovider.SLoadbalancerBackendGroup) (*SElbBackendGroup, error) { + params := map[string]interface{}{ + "name": group.Name, + } + var scheduler string + if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { + return nil, fmt.Errorf("UpdateLoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) + } else { + scheduler = s + } + params["lb_algorithm"] = scheduler + + if group.StickySession == nil || group.StickySession.StickySession == api.LB_BOOL_OFF { + params["session_persistence"] = jsonutils.JSONNull + } else { + s := map[string]interface{}{} + timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) + if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { + s["type"] = "SOURCE_IP" + if timeout > 0 { + s["persistence_timeout"] = timeout + } + } else { + s["type"] = LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType] + if len(group.StickySession.StickySessionCookie) > 0 { + s["cookie_name"] = group.StickySession.StickySessionCookie + } else { + if timeout > 0 { + s["persistence_timeout"] = timeout + } + } + } + params["session_persistence"] = s + } + err := self.lbUpdate("lbaas/pools/"+backendGroupId, map[string]interface{}{"pool": params}) + if err != nil { + return nil, err + } + + ret, err := self.GetLoadBalancerBackendGroupId(backendGroupId) + if err != nil { + return nil, err + } + + if group.HealthCheck == nil && len(ret.HealthMonitorId) > 0 { + err := self.DeleteLoadbalancerHealthCheck(ret.HealthMonitorId) + if err != nil { + return ret, errors.Wrap(err, "DeleteLoadbalancerHealthCheck") + } + } + + if group.HealthCheck != nil { + if len(ret.HealthMonitorId) == 0 { + _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) + if err != nil { + return ret, errors.Wrap(err, "CreateLoadBalancerHealthCheck") + } + } else { + _, err := self.UpdateLoadBalancerHealthCheck(ret.HealthMonitorId, group.HealthCheck) + if err != nil { + return ret, errors.Wrap(err, "UpdateLoadBalancerHealthCheck") + } + } + } + + ret.region = self + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561551.html +func (self *SRegion) DeleteLoadBalancerBackendGroup(id string) error { + return self.lbDelete("lbaas/pools/" + id) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561556.html +func (self *SRegion) AddLoadBalancerBackend(backendGroupId, subnetId, ipaddr string, port, weight int) (*SElbBackend, error) { + params := map[string]interface{}{ + "address": ipaddr, + "protocol_port": port, + "subnet_id": subnetId, + "weight": weight, + } + ret := &SElbBackend{} + return ret, self.lbCreate(fmt.Sprintf("lbaas/pools/%s/members", backendGroupId), map[string]interface{}{"member": params}, ret) +} + +func (self *SRegion) RemoveLoadBalancerBackend(lbbgId string, backendId string) error { + return self.lbDelete(fmt.Sprintf("lbaas/pools/%s/members/%s", lbbgId, backendId)) +} + +func (self *SRegion) getLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { + res := fmt.Sprintf("lbaas/pools/%s/members", backendGroupId) + ret := []SElbBackend{} + return ret, self.lbList(res, url.Values{}, &ret) +} + +func (self *SRegion) GetLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { + ret, err := self.getLoadBalancerBackends(backendGroupId) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetLoadBalancerBackends.getLoadBalancerBackends") + } + + // 过滤掉服务器已经被删除的backend。原因是运管平台查询不到已删除的服务器记录,导致同步出错。产生肮数据。 + filtedRet := []SElbBackend{} + for i := range ret { + if ret[i].AdminStateUp { + backend := ret[i] + filtedRet = append(filtedRet, backend) + } + } + + return filtedRet, nil +} + +func (self *SRegion) getLoadBalancerAdminStateDownBackends(backendGroupId string) ([]SElbBackend, error) { + ret, err := self.getLoadBalancerBackends(backendGroupId) + if err != nil { + return nil, errors.Wrap(err, "SRegion.getLoadBalancerAdminStateDownBackends.getLoadBalancerBackends") + } + + filtedRet := []SElbBackend{} + for i := range ret { + if !ret[i].AdminStateUp { + backend := ret[i] + filtedRet = append(filtedRet, backend) + } + } + + return filtedRet, nil +} + +func (self *SRegion) GetLoadBalancerHealthCheck(healthCheckId string) (*SElbHealthCheck, error) { + ret := &SElbHealthCheck{region: self} + return ret, self.lbGet("lbaas/healthmonitors/"+healthCheckId, ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_cert.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_cert.go new file mode 100644 index 0000000000..c322fbf590 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_cert.go @@ -0,0 +1,182 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "crypto/sha1" + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElbCert struct { + multicloud.SResourceBase + HcsTags + region *SRegion + + Certificate string `json:"certificate"` + CreateTime time.Time `json:"create_time"` + ExpireTime time.Time `json:"expire_time"` + Description string `json:"description"` + Domain string `json:"domain"` + ID string `json:"id"` + AdminStateUp bool `json:"admin_state_up"` + TenantID string `json:"tenant_id"` + Name string `json:"name"` + PrivateKey string `json:"private_key"` + Type string `json:"type"` + UpdateTime time.Time `json:"update_time"` +} + +func (self *SElbCert) GetPublickKey() string { + return self.Certificate +} + +func (self *SElbCert) GetPrivateKey() string { + return self.PrivateKey +} + +func (self *SElbCert) GetId() string { + return self.ID +} + +func (self *SElbCert) GetName() string { + return self.Name +} + +func (self *SElbCert) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbCert) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbCert) Refresh() error { + cert, err := self.region.GetLoadBalancerCertificate(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, cert) +} + +func (self *SElbCert) IsEmulated() bool { + return false +} + +func (self *SElbCert) GetProjectId() string { + return "" +} + +func (self *SElbCert) Sync(name, privateKey, publickKey string) error { + params := map[string]interface{}{ + "name": name, + "private_key": privateKey, + "certificate": publickKey, + } + return self.region.lbUpdate("lbaas/certificates/"+self.GetId(), params) +} + +func (self *SElbCert) Delete() error { + return self.region.lbDelete("lbaas/certificates/" + self.GetId()) +} + +func (self *SElbCert) GetCommonName() string { + return self.Domain +} + +func (self *SElbCert) GetSubjectAlternativeNames() string { + return self.Domain +} + +func (self *SElbCert) GetFingerprint() string { + _fp := sha1.Sum([]byte(self.Certificate)) + fp := fmt.Sprintf("sha1:% x", _fp) + return strings.Replace(fp, " ", ":", -1) +} + +func (self *SElbCert) GetExpireTime() time.Time { + return self.ExpireTime +} + +func (self *SRegion) GetLoadBalancerCertificate(id string) (*SElbCert, error) { + ret := &SElbCert{region: self} + err := self.lbGet("lbaas/certificates/"+id, ret) + if err != nil { + return nil, err + } + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/elb_qy_zs_0001.html +func (self *SRegion) CreateLoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (*SElbCert, error) { + params := map[string]interface{}{ + "name": cert.Name, + "private_key": cert.PrivateKey, + "certificate": cert.Certificate, + } + ret := &SElbCert{region: self} + err := self.lbCreate("lbaas/certificates", params, ret) + if err != nil { + return nil, err + } + return ret, nil +} + +func (self *SRegion) GetLoadBalancerCertificates() ([]SElbCert, error) { + ret := []SElbCert{} + err := self.lbList("lbaas/certificates", url.Values{}, &ret) + if err != nil { + return nil, err + } + return ret, nil +} + +func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + ret, err := self.GetLoadBalancerCertificates() + if err != nil { + return nil, err + } + + iret := make([]cloudprovider.ICloudLoadbalancerCertificate, len(ret)) + for i := range ret { + ret[i].region = self + iret[i] = &ret[i] + } + return iret, nil +} + +func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + ret, err := self.CreateLoadBalancerCertificate(cert) + if err != nil { + return nil, err + } + return ret, nil +} + +func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + cert, err := self.GetLoadBalancerCertificate(certId) + if err != nil { + return nil, err + } + return cert, nil +} diff --git a/pkg/multicloud/hcs/loadbalancer_healthcheck.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_healthcheck.go similarity index 100% rename from pkg/multicloud/hcs/loadbalancer_healthcheck.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_healthcheck.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_listener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_listener.go new file mode 100644 index 0000000000..a44d2868a8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_listener.go @@ -0,0 +1,644 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + "fmt" + "net/url" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type InsertHeaders struct { + XForwardedELBIP bool `json:"X-Forwarded-ELB-IP"` +} + +type Loadbalancer struct { + Id string `json:"id"` +} + +type SElbListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + huawei.HuaweiTags + lb *SLoadbalancer + acl *SElbACL + backendgroup *SElbBackendGroup + + ProtocolPort int `json:"protocol_port"` + Protocol string `json:"protocol"` + Description string `json:"description"` + AdminStateUp bool `json:"admin_state_up"` + Http2Enable bool `json:"http2_enable"` + Loadbalancers []Loadbalancer `json:"loadbalancers"` + TenantId string `json:"tenant_id"` + ProjectId string `json:"project_id"` + ConnectionLimit int `json:"connection_limit"` + DefaultPoolId string `json:"default_pool_id"` + Id string `json:"id"` + Name string `json:"name"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + InsertHeaders InsertHeaders `json:"insert_headers"` + DefaultTlsContainerRef string `json:"default_tls_container_ref"` +} + +func (self *SElbListener) GetId() string { + return self.Id +} + +func (self *SElbListener) GetName() string { + return self.Name +} + +func (self *SElbListener) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbListener) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbListener) Refresh() error { + ilistener, err := self.lb.GetILoadBalancerListenerById(self.GetId()) + if err != nil { + return err + } + + listener := ilistener.(*SElbListener) + listener.lb = self.lb + err = jsonutils.Update(self, listener) + if err != nil { + return err + } + + return nil +} + +func (self *SElbListener) IsEmulated() bool { + return false +} + +func (self *SElbListener) GetProjectId() string { + return self.ProjectId +} + +func (self *SElbListener) GetListenerType() string { + switch self.Protocol { + case "TCP": + return api.LB_LISTENER_TYPE_TCP + case "UDP": + return api.LB_LISTENER_TYPE_UDP + case "HTTP": + return api.LB_LISTENER_TYPE_HTTP + case "TERMINATED_HTTPS": + return api.LB_LISTENER_TYPE_HTTPS + case "HTTPS": + return api.LB_LISTENER_TYPE_HTTPS + default: + return "" + } +} + +func (self *SElbListener) GetListenerPort() int { + return self.ProtocolPort +} + +func (self *SElbListener) GetBackendGroup() (*SElbBackendGroup, error) { + if self.backendgroup == nil { + lbbgId := self.GetBackendGroupId() + if len(lbbgId) > 0 { + lbbg, err := self.lb.GetILoadBalancerBackendGroupById(lbbgId) + if err != nil { + return nil, err + } + + self.backendgroup = lbbg.(*SElbBackendGroup) + } + } + + return self.backendgroup, nil +} + +func (self *SElbListener) GetScheduler() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetScheduler %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + return lbbg.GetScheduler() +} + +func (self *SElbListener) GetAcl() (*SElbACL, error) { + if self.acl != nil { + return self.acl, nil + } + + acls, err := self.lb.region.GetLoadBalancerAcls(self.GetId()) + if err != nil { + return nil, err + } + + if len(acls) == 0 { + return nil, nil + } else { + self.acl = &acls[0] + return &acls[0], nil + } +} + +func (self *SElbListener) GetAclStatus() string { + acl, err := self.GetAcl() + if err != nil { + log.Debugf("GetAclStatus %s", err) + return "" + } + + if acl != nil && acl.EnableWhitelist { + return api.LB_BOOL_ON + } + + return api.LB_BOOL_OFF +} + +func (self *SElbListener) GetAclType() string { + return api.LB_ACL_TYPE_WHITE +} + +func (self *SElbListener) GetAclId() string { + acl, err := self.GetAcl() + if err != nil { + log.Debugf("GetAclStatus %s", err) + return "" + } + + if acl == nil { + return "" + } + + return acl.GetId() +} + +func (self *SElbListener) GetEgressMbps() int { + return 0 +} + +func (self *SElbListener) GetHealthCheck() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheck %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheck %s", err.Error()) + } + + if health != nil { + return api.LB_BOOL_ON + } else { + return api.LB_BOOL_OFF + } +} + +func (self *SElbListener) GetHealthCheckType() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) + } + + if health != nil { + return health.HealthCheckType + } + + return "" +} + +func (self *SElbListener) GetHealthCheckTimeout() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) + } + + if health != nil { + return health.HealthCheckTimeout + } + + return 0 +} + +func (self *SElbListener) GetHealthCheckInterval() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) + } + + if health != nil { + return health.HealthCheckInterval + } + + return 0 +} + +func (self *SElbListener) GetHealthCheckRise() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) + } + + if health != nil { + return health.HealthCheckRise + } else { + return 0 + } +} + +func (self *SElbListener) GetHealthCheckFail() int { + return 0 +} + +func (self *SElbListener) GetHealthCheckReq() string { + return "" +} + +func (self *SElbListener) GetHealthCheckExp() string { + return "" +} + +func (self *SElbListener) GetBackendGroupId() string { + return self.DefaultPoolId +} + +func (self *SElbListener) GetBackendServerPort() int { + return 0 +} + +func (self *SElbListener) GetHealthCheckDomain() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) + } + + if health != nil { + return health.HealthCheckDomain + } + + return "" +} + +func (self *SElbListener) GetHealthCheckURI() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) + } + + if health != nil { + return health.HealthCheckURI + } + + return "" +} + +func (self *SElbListener) GetHealthCheckCode() string { + return "" +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html +func (self *SElbListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + l7policy, err := self.lb.region.CreateLoadBalancerPolicy(self.GetId(), rule) + if err != nil { + return nil, err + } + + l7policy.region = self.lb.region + l7policy.lb = self.lb + l7policy.listener = self + return l7policy, nil +} + +func (self *SElbListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + ret := &SElbListenerPolicy{region: self.lb.region, lb: self.lb, listener: self} + return ret, self.lb.region.lbGet("lbaas/l7policies/"+ruleId, ret) +} + +func (self *SElbListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + ret, err := self.lb.region.GetLoadBalancerPolicies(self.GetId()) + if err != nil { + return nil, err + } + + iret := []cloudprovider.ICloudLoadbalancerListenerRule{} + for i := range ret { + rule := ret[i] + rule.listener = self + rule.lb = self.lb + rule.region = self.lb.region + iret = append(iret, &rule) + } + + return iret, nil +} + +func (self *SElbListener) GetStickySession() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySession %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySession %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySession + } + + return "" +} + +func (self *SElbListener) GetStickySessionType() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySessionType %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySessionType %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySessionType + } + + return "" +} + +func (self *SElbListener) GetStickySessionCookie() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySessionCookie + } + + return "" +} + +func (self *SElbListener) GetStickySessionCookieTimeout() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySessionCookieTimeout + } + + return 0 +} + +func (self *SElbListener) XForwardedForEnabled() bool { + return self.InsertHeaders.XForwardedELBIP +} + +func (self *SElbListener) GzipEnabled() bool { + return false +} + +func (self *SElbListener) GetCertificateId() string { + return self.DefaultTlsContainerRef +} + +func (self *SElbListener) GetTLSCipherPolicy() string { + return "" +} + +func (self *SElbListener) HTTP2Enabled() bool { + return self.Http2Enable +} + +func (self *SElbListener) Start() error { + return nil +} + +func (self *SElbListener) Stop() error { + return cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561544.html +/* +default_pool_id有如下限制: +不能更新为其他监听器的default_pool。 +不能更新为其他监听器的关联的转发策略所使用的pool。 +default_pool_id对应的后端云服务器组的protocol和监听器的protocol有如下关系: +监听器的protocol为TCP时,后端云服务器组的protocol必须为TCP。 +监听器的protocol为UDP时,后端云服务器组的protocol必须为UDP。 +监听器的protocol为HTTP或TERMINATED_HTTPS时,后端云服务器组的protocol必须为HTTP。 +*/ +func (self *SElbListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { + return self.lb.region.UpdateLoadBalancerListener(self.GetId(), listener) +} + +func (self *SElbListener) Delete(ctx context.Context) error { + return self.lb.region.lbDelete("lbaas/listeners/" + self.GetId()) +} + +func (self *SRegion) UpdateLoadBalancerListener(listenerId string, listener *cloudprovider.SLoadbalancerListener) error { + params := map[string]interface{}{ + "name": listener.Name, + "description": listener.Description, + "http2_enable": listener.EnableHTTP2, + "default_pool_id": jsonutils.JSONNull, + } + if len(listener.BackendGroupID) > 0 { + params["default_pool_id"] = listener.BackendGroupID + } + + if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { + params["default_tls_container_ref"] = listener.CertificateID + } + + if listener.XForwardedFor { + params["insert_headers"] = map[string]interface{}{ + "X-Forwarded-ELB-IP": listener.XForwardedFor, + } + } + return self.lbUpdate("elb/listeners/"+listenerId, map[string]interface{}{"listener": params}) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295315.html +func (self *SRegion) GetLoadBalancerPolicies(listenerId string) ([]SElbListenerPolicy, error) { + query := url.Values{} + if len(listenerId) > 0 { + query.Set("listener_id", listenerId) + } + + ret := []SElbListenerPolicy{} + return ret, self.lbList("lbaas/l7policies", query, &ret) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0116649234.html +func (self *SRegion) GetLoadBalancerPolicyRules(policyId string) ([]SElbListenerPolicyRule, error) { + ret := []SElbListenerPolicyRule{} + return ret, self.lbList(fmt.Sprintf("lbaas/l7policies/%s/rules", policyId), url.Values{}, &ret) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html +func (self *SRegion) CreateLoadBalancerPolicy(listenerId string, rule *cloudprovider.SLoadbalancerListenerRule) (*SElbListenerPolicy, error) { + ret := &SElbListenerPolicy{} + params := map[string]interface{}{ + "name": rule.Name, + "listener_id": listenerId, + "action": "REDIRECT_TO_POOL", + "redirect_pool_id": rule.BackendGroupID, + } + err := self.lbCreate("lbaas/l7policies", map[string]interface{}{"l7policy": params}, ret) + if err != nil { + return nil, err + } + if len(rule.Domain) > 0 { + params := map[string]interface{}{ + "type": "HOST_NAME", + "value": rule.Domain, + "compare_type": "EQUAL_TO", + } + err := self.lbCreate(fmt.Sprintf("lbaas/l7policies/%s/rules", ret.GetId()), map[string]interface{}{"rule": params}, nil) + if err != nil { + return ret, err + } + } + + if len(rule.Path) > 0 { + params := map[string]interface{}{ + "type": "PATH", + "value": rule.Path, + "compare_type": "EQUAL_TO", + } + err := self.lbCreate(fmt.Sprintf("lbaas/l7policies/%s/rules", ret.GetId()), map[string]interface{}{"rule": params}, nil) + if err != nil { + return ret, err + } + } + + return ret, nil +} + +func (self *SElbListener) GetClientIdleTimeout() int { + return 0 +} + +func (self *SElbListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_listener_rule.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_listener_rule.go new file mode 100644 index 0000000000..b63549d825 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/loadbalancer_listener_rule.go @@ -0,0 +1,169 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SElbListenerPolicy struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + huawei.HuaweiTags + region *SRegion + lb *SLoadbalancer + listener *SElbListener + + RedirectPoolId string `json:"redirect_pool_id"` + RedirectListenerId *string `json:"redirect_listener_id"` + Description string `json:"description"` + AdminStateUp bool `json:"admin_state_up"` + Rules []Rule `json:"rules"` + TenantId string `json:"tenant_id"` + ProjectId string `json:"project_id"` + ListenerId string `json:"listener_id"` + RedirectURL *string `json:"redirect_url"` + ProvisioningStatus string `json:"provisioning_status"` + Action string `json:"action"` + Position int64 `json:"position"` + Id string `json:"id"` + Name string `json:"name"` +} + +type Rule struct { + Id string `json:"id"` +} + +type SElbListenerPolicyRule struct { + region *SRegion + policy *SElbListenerPolicy + + CompareType string `json:"compare_type"` + ProvisioningStatus string `json:"provisioning_status"` + AdminStateUp bool `json:"admin_state_up"` + TenantId string `json:"tenant_id"` + ProjectId string `json:"project_id"` + Invert bool `json:"invert"` + Value string `json:"value"` + Key interface{} `json:"key"` + Type string `json:"type"` + Id string `json:"id"` +} + +func (self *SElbListenerPolicy) GetId() string { + return self.Id +} + +func (self *SElbListenerPolicy) GetName() string { + return self.Name +} + +func (self *SElbListenerPolicy) GetGlobalId() string { + return self.GetId() +} + +// 负载均衡没有启用禁用操作 +func (self *SElbListenerPolicy) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbListenerPolicy) Refresh() error { + res := "lbaas/l7policies/" + self.Id + ret := &SElbListenerPolicy{} + err := self.lb.region.lbGet(res, ret) + if err != nil { + return err + } + return jsonutils.Update(self, ret) +} + +func (self *SElbListenerPolicy) IsDefault() bool { + return false +} + +func (self *SElbListenerPolicy) IsEmulated() bool { + return false +} + +func (self *SElbListenerPolicy) GetProjectId() string { + return "" +} + +func (self *SElbListenerPolicy) GetRules() ([]SElbListenerPolicyRule, error) { + ret, err := self.region.GetLoadBalancerPolicyRules(self.GetId()) + if err != nil { + return nil, err + } + + for i := range ret { + ret[i].region = self.lb.region + ret[i].policy = self + } + + return ret, nil +} + +func (self *SElbListenerPolicy) GetDomain() string { + rules, err := self.GetRules() + if err != nil { + log.Errorf("loadbalancer rule GetDomain %s", err) + } + + for i := range rules { + if rules[i].Type == "HOST_NAME" { + return rules[i].Value + } + } + + return "" +} + +func (self *SElbListenerPolicy) GetCondition() string { + return "" +} + +func (self *SElbListenerPolicy) GetPath() string { + rules, err := self.GetRules() + if err != nil { + log.Errorf("loadbalancer rule GetPath %s", err) + } + + for i := range rules { + if rules[i].Type == "PATH" { + return rules[i].Value + } + } + + return "" +} + +func (self *SElbListenerPolicy) GetBackendGroupId() string { + return self.RedirectPoolId +} + +func (self *SElbListenerPolicy) Delete(ctx context.Context) error { + return self.region.DeleteLoadBalancerPolicy(self.GetId()) +} + +func (self *SRegion) DeleteLoadBalancerPolicy(policyId string) error { + return self.lbDelete("lbaas/l7policies/" + policyId) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/monitor.go new file mode 100644 index 0000000000..06131282e4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/monitor.go @@ -0,0 +1,494 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type MetricData struct { + Namespace string + MetricName string + Dimensions []struct { + Name string + Value string + } + Datapoints []struct { + Average float64 + Timestamp int64 + } + Unit string +} + +func (self *SHcsClient) monitorPost(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + url := self._url("ces", "V1.0", self.defaultRegion, resource) + return self.request(httputils.POST, url, nil, params) +} + +func (self *SHcsClient) getServerMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + params := map[string]interface{}{ + "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), + "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), + "period": "1", + "filter": "average", + } + metrics := []interface{}{} + namespace, dimesionName, metricNames := "SYS.ECS", "instance_id", []string{ + "cpu_util", + "network_incoming_bytes_aggregate_rate", + "network_outgoing_bytes_aggregate_rate", + "disk_read_bytes_rate", + "disk_write_bytes_rate", + "disk_read_requests_rate", + "disk_write_requests_rate", + } + for _, metricName := range metricNames { + metrics = append(metrics, map[string]interface{}{ + "namespace": namespace, + "metric_name": metricName, + "dimensions": []map[string]string{ + { + "name": dimesionName, + "value": opts.ResourceId, + }, + }, + }) + } + params["metrics"] = metrics + resp, err := self.monitorPost("batch-query-metric-data", params) + if err != nil { + return nil, err + } + metricData := []MetricData{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].MetricName { + case "cpu_util": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_CPU_USAGE + case "network_incoming_bytes_aggregate_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_RX + tags = map[string]string{"net_type": "internet"} + case "network_outgoing_bytes_aggregate_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_TX + tags = map[string]string{"net_type": "internet"} + case "disk_read_bytes_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS + case "disk_write_bytes_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS + case "disk_read_requests_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS + case "disk_write_requests_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + metricValue := cloudprovider.MetricValue{ + Value: value.Average, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHcsClient) getRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + params := map[string]interface{}{ + "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), + "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), + "period": "1", + "filter": "average", + } + metrics := []interface{}{} + namespace, dimesionName, metricNames := "SYS.DCS", "dcs_instance_id", []string{ + "cpu_usage", + "memory_usage", + "instantaneous_input_kbps", + "instantaneous_output_kbps", + "connected_clients", + "instantaneous_ops", + "keys", + "expires", + "used_memory_dataset", + } + for _, metricName := range metricNames { + metrics = append(metrics, map[string]interface{}{ + "namespace": namespace, + "metric_name": metricName, + "dimensions": []map[string]string{ + { + "name": dimesionName, + "value": opts.ResourceId, + }, + }, + }) + } + params["metrics"] = metrics + resp, err := self.monitorPost("batch-query-metric-data", params) + if err != nil { + return nil, err + } + metricData := []MetricData{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].MetricName { + case "cpu_usage": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE + case "memory_usage": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE + case "instantaneous_input_kbps": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX + case "instantaneous_output_kbps": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX + case "connected_clients": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_USED_CONN + case "instantaneous_ops": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_OPT_SES + case "keys": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS + case "expires": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS + case "used_memory_dataset": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + metricValue := cloudprovider.MetricValue{ + Value: value.Average, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHcsClient) getRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + params := map[string]interface{}{ + "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), + "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), + "period": "1", + "filter": "average", + } + metrics := []interface{}{} + namespace, dimesionName, metricNames := "SYS.RDS", "rds_cluster_id", []string{ + "rds001_cpu_util", + "rds002_mem_util", + "rds004_bytes_in", + "rds004_bytes_in", + "rds005_bytes_out", + "rds039_disk_util", + "rds049_disk_read_throughput", + "rds050_disk_write_throughput", + "rds006_conn_count", + "rds008_qps", + "rds009_tps", + "rds013_innodb_reads", + "rds014_innodb_writes", + } + switch opts.Engine { + case api.DBINSTANCE_TYPE_POSTGRESQL: + dimesionName = "postgresql_cluster_id" + case api.DBINSTANCE_TYPE_SQLSERVER: + dimesionName = "rds_cluster_sqlserver_id" + } + + for _, metricName := range metricNames { + metrics = append(metrics, map[string]interface{}{ + "namespace": namespace, + "metric_name": metricName, + "dimensions": []map[string]string{ + { + "name": dimesionName, + "value": opts.ResourceId, + }, + }, + }) + } + params["metrics"] = metrics + resp, err := self.monitorPost("batch-query-metric-data", params) + if err != nil { + return nil, err + } + metricData := []MetricData{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].MetricName { + case "rds001_cpu_util": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_CPU_USAGE + case "rds002_mem_util": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_MEM_USAGE + case "rds004_bytes_in": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX + case "rds005_bytes_out": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX + case "rds039_disk_util": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_USAGE + case "rds049_disk_read_throughput": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_READ_BPS + case "rds050_disk_write_throughput": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_WRITE_BPS + case "rds006_conn_count": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_CONN_COUNT + case "rds008_qps": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_QPS + case "rds009_tps": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_TPS + case "rds013_innodb_reads": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_INNODB_READ_BPS + case "rds014_innodb_writes": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_INNODB_WRITE_BPS + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + metricValue := cloudprovider.MetricValue{ + Value: value.Average, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHcsClient) getBucketMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + params := map[string]interface{}{ + "from": opts.StartTime.UnixMilli(), + "to": opts.EndTime.UnixMilli(), + "period": "1", + "filter": "average", + } + metrics := []interface{}{} + namespace, dimesionName, metricNames := "SYS.OBS", "bucket_name", []string{ + "download_bytes", + "upload_bytes", + "first_byte_latency", + "get_request_count", + "request_count_4xx", + "request_count_5xx", + } + + for _, metricName := range metricNames { + metrics = append(metrics, map[string]interface{}{ + "namespace": namespace, + "metric_name": metricName, + "dimensions": []map[string]string{ + { + "name": dimesionName, + "value": opts.ResourceId, + }, + }, + }) + } + params["metrics"] = metrics + resp, err := self.monitorPost("batch-query-metric-data", params) + if err != nil { + return nil, err + } + metricData := []MetricData{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].MetricName { + case "download_bytes": + ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_TX + case "upload_bytes": + ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_RX + case "first_byte_latency": + ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_LATECY + tags = map[string]string{"request": "get"} + case "get_request_count": + ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT + tags = map[string]string{"request": "get"} + case "request_count_4xx": + ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT + tags = map[string]string{"request": "4xx"} + case "request_count_5xx": + ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT + tags = map[string]string{"request": "5xx"} + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + metricValue := cloudprovider.MetricValue{ + Value: value.Average, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHcsClient) getLoadbalancerMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + params := map[string]interface{}{ + "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), + "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), + "period": "1", + "filter": "average", + } + metrics := []interface{}{} + namespace, dimesionName, metricNames := "SYS.ELB", "lb_instance_id", []string{ + "m7_in_Bps", + "m8_out_Bps", + "mc_l7_http_2xx", + "md_l7_http_3xx", + "me_l7_http_4xx", + "mf_l7_http_5xx", + } + + for _, metricName := range metricNames { + metrics = append(metrics, map[string]interface{}{ + "namespace": namespace, + "metric_name": metricName, + "dimensions": []map[string]string{ + { + "name": dimesionName, + "value": opts.ResourceId, + }, + }, + }) + } + params["metrics"] = metrics + resp, err := self.monitorPost("batch-query-metric-data", params) + if err != nil { + return nil, err + } + metricData := []MetricData{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].MetricName { + case "m7_in_Bps": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_NET_BPS_RX + case "m8_out_Bps": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_NET_BPS_TX + case "mc_l7_http_2xx": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT + tags = map[string]string{"request": "2xx"} + case "md_l7_http_3xx": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT + tags = map[string]string{"request": "3xx"} + case "md_l7_http_4xx": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT + tags = map[string]string{"request": "4xx"} + case "md_l7_http_5xx": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT + tags = map[string]string{"request": "5xx"} + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + metricValue := cloudprovider.MetricValue{ + Value: value.Average, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHcsClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.getServerMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: + return self.getRedisMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_RDS: + return self.getRdsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_BUCKET: + return self.getBucketMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_LB: + return self.getLoadbalancerMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) + } +} diff --git a/pkg/multicloud/hcs/nat_sku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/nat_sku.go similarity index 95% rename from pkg/multicloud/hcs/nat_sku.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/nat_sku.go index cf40e235e5..0ce818b016 100644 --- a/pkg/multicloud/hcs/nat_sku.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/nat_sku.go @@ -15,8 +15,8 @@ package hcs import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) const ( diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natdtable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natdtable.go new file mode 100644 index 0000000000..9993a3cf81 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natdtable.go @@ -0,0 +1,149 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SNatDEntry struct { + multicloud.SResourceBase + HcsTags + gateway *SNatGateway + + Id string `json:"id"` + NatGatewayId string `json:"nat_gateway_id"` + Protocol string `json:"protocol"` + Status string `json:"status"` + ExternalIP string `json:"floating_ip_address"` + ExternalPort int `json:"external_service_port"` + InternalIP string `json:"private_ip"` + InternalPort int `json:"internal_service_port"` + PortId string `json:"port_id"` + AdminStateUp bool `json:"admin_state_up"` +} + +func (nat *SNatDEntry) GetId() string { + return nat.Id +} + +func (nat *SNatDEntry) GetName() string { + // No name so return id + return nat.GetId() +} + +func (nat *SNatDEntry) GetGlobalId() string { + return nat.GetId() +} + +func (nat *SNatDEntry) GetStatus() string { + return NatResouceStatusTransfer(nat.Status) +} + +func (nat *SNatDEntry) GetIpProtocol() string { + return nat.Protocol +} + +func (nat *SNatDEntry) GetExternalIp() string { + return nat.ExternalIP +} + +func (nat *SNatDEntry) GetExternalPort() int { + return nat.ExternalPort +} + +func (nat *SNatDEntry) GetInternalIp() string { + return nat.InternalIP +} + +func (nat *SNatDEntry) GetInternalPort() int { + return nat.InternalPort +} + +func (nat *SNatDEntry) Delete() error { + return nat.gateway.region.DeleteNatDEntry(nat.GetId()) +} + +// getNatSTable return all snat rules of gateway +func (gateway *SNatGateway) getNatDTable() ([]SNatDEntry, error) { + ret, err := gateway.region.GetNatDTable(gateway.GetId()) + if err != nil { + return nil, err + } + for i := range ret { + ret[i].gateway = gateway + } + return ret, nil +} + +func (self *SRegion) GetNatDTable(natGatewayId string) ([]SNatDEntry, error) { + query := url.Values{} + query.Set("nat_gateway_id", natGatewayId) + ret := []SNatDEntry{} + err := self.list("nat", "v2.0", "dnat_rules", query, &ret) + if err != nil { + return nil, err + } + for i := range ret { + nat := &ret[i] + if len(nat.InternalIP) == 0 { + port, err := self.GetPort(nat.PortId) + if err != nil { + return nil, errors.Wrapf(err, `get port info for transfer to ip of port_id %q error`, nat.PortId) + } + nat.InternalIP = port.FixedIps[0].IpAddress + } + } + return ret, nil +} + +func (self *SRegion) DeleteNatDEntry(entryId string) error { + return self.delete("nat", "v2.0", "dnat_rules/"+entryId) +} + +func (nat *SNatDEntry) Refresh() error { + ret, err := nat.gateway.region.GetNatDEntry(nat.Id) + if err != nil { + return err + } + return jsonutils.Update(nat, ret) +} + +func (self *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayId string) (*SNatDEntry, error) { + params := make(map[string]interface{}) + params["nat_gateway_id"] = gatewayId + params["private_ip"] = rule.InternalIP + params["internal_service_port"] = rule.InternalPort + params["floating_ip_id"] = rule.ExternalIPID + params["external_service_port"] = rule.ExternalPort + params["protocol"] = rule.Protocol + + packParams := map[string]interface{}{ + "dnat_rule": params, + } + ret := &SNatDEntry{} + return ret, self.create("nat", "v2.0", "dnat_rules", packParams, ret) +} + +func (self *SRegion) GetNatDEntry(id string) (*SNatDEntry, error) { + ret := &SNatDEntry{} + return ret, self.get("nat", "v2.0", "dnat_rules/"+id, ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natgateway.go new file mode 100644 index 0000000000..730491cfad --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natgateway.go @@ -0,0 +1,265 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SNatGateway struct { + multicloud.SNatGatewayBase + HcsTags + region *SRegion + + Id string + Name string + Description string + Spec string + Status string + InternalNetworkId string + CreatedTime string `json:"created_at"` +} + +func (gateway *SNatGateway) GetId() string { + return gateway.Id +} + +func (gateway *SNatGateway) GetName() string { + return gateway.Name +} + +func (gateway *SNatGateway) GetGlobalId() string { + return gateway.GetId() +} + +func (gateway *SNatGateway) GetStatus() string { + return NatResouceStatusTransfer(gateway.Status) +} + +func (self *SNatGateway) Delete() error { + return self.region.DeleteNatGateway(self.Id) +} + +func (self *SNatGateway) Refresh() error { + nat, err := self.region.GetNatGateway(self.Id) + if err != nil { + return errors.Wrapf(err, "GetNatGateway(%s)", self.Id) + } + return jsonutils.Update(self, nat) +} + +func (self *SNatGateway) GetINetworkId() string { + return self.InternalNetworkId +} + +func (gateway *SNatGateway) GetNatSpec() string { + switch gateway.Spec { + case "1": + return api.NAT_SPEC_SMALL + case "2": + return api.NAT_SPEC_MIDDLE + case "3": + return api.NAT_SPEC_LARGE + case "4": + return api.NAT_SPEC_XLARGE + } + return gateway.Spec +} + +func (gateway *SNatGateway) GetDescription() string { + return gateway.Description +} + +func (gateway *SNatGateway) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (gateway *SNatGateway) GetCreatedAt() time.Time { + t, _ := time.Parse("2006-01-02 15:04:05.000000", gateway.CreatedTime) + return t +} + +func (gateway *SNatGateway) GetExpiredAt() time.Time { + return time.Time{} +} + +func (gateway *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { + IEips, err := gateway.region.GetIEips() + if err != nil { + return nil, errors.Wrapf(err, `get all Eips of region %q error`, gateway.region.GetId()) + } + dNatTables, err := gateway.GetINatDTable() + if err != nil { + return nil, errors.Wrapf(err, `get all DNatTable of gateway %q error`, gateway.GetId()) + } + sNatTables, err := gateway.GetINatSTable() + if err != nil { + return nil, errors.Wrapf(err, `get all SNatTable of gateway %q error`, gateway.GetId()) + } + + // Get natIPSet of nat rules + natIPSet := make(map[string]struct{}) + for _, snat := range sNatTables { + natIPSet[snat.GetIP()] = struct{}{} + } + for _, dnat := range dNatTables { + natIPSet[dnat.GetExternalIp()] = struct{}{} + } + + // Add Eip whose GetIpAddr() in natIPSet to ret + ret := make([]cloudprovider.ICloudEIP, 0, 2) + for i := range IEips { + if _, ok := natIPSet[IEips[i].GetIpAddr()]; ok { + ret = append(ret, IEips[i]) + } + } + return ret, nil +} + +func (gateway *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { + dNatTable, err := gateway.getNatDTable() + if err != nil { + return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) + } + ret := make([]cloudprovider.ICloudNatDEntry, len(dNatTable)) + for i := range dNatTable { + ret[i] = &dNatTable[i] + } + return ret, nil +} + +func (gateway *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { + sNatTable, err := gateway.getNatSTable() + if err != nil { + return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) + } + ret := make([]cloudprovider.ICloudNatSEntry, len(sNatTable)) + for i := range sNatTable { + ret[i] = &sNatTable[i] + } + return ret, nil +} + +func (gateway *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { + dnat, err := gateway.region.CreateNatDEntry(rule, gateway.GetId()) + if err != nil { + return nil, err + } + dnat.gateway = gateway + return dnat, nil +} + +func (gateway *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { + snat, err := gateway.region.CreateNatSEntry(rule, gateway.GetId()) + if err != nil { + return nil, err + } + snat.gateway = gateway + return snat, nil +} + +func (gateway *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { + dnat, err := gateway.region.GetNatDEntry(id) + if err != nil { + return nil, err + } + dnat.gateway = gateway + return dnat, nil +} + +func (gateway *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { + snat, err := gateway.region.GetNatSEntry(id) + if err != nil { + return nil, err + } + snat.gateway = gateway + return snat, nil +} + +func (self *SRegion) GetNatGateways(vpcId string) ([]SNatGateway, error) { + query := url.Values{} + if len(vpcId) > 0 { + query.Set("router_id", vpcId) + } + ret := []SNatGateway{} + return ret, self.list("nat", "v2.0", "nat_gateways", query, &ret) +} + +func NatResouceStatusTransfer(status string) string { + // In Huawei Cloud, there are isx resource status of Nat, "ACTIVE", "PENDING_CREATE", + // "PENDING_UPDATE", "PENDING_DELETE", "EIP_FREEZED", "INACTIVE". + switch status { + case "ACTIVE": + return api.NAT_STAUTS_AVAILABLE + case "PENDING_CREATE": + return api.NAT_STATUS_ALLOCATE + case "PENDING_UPDATE", "PENDING_DELETE": + return api.NAT_STATUS_DEPLOYING + default: + return api.NAT_STATUS_UNKNOWN + } +} + +func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) { + ret := &SNatGateway{region: self} + return ret, self.get("nat", "v2.0", "nat_gateways/"+id, ret) +} + +func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { + nat, err := self.region.CreateNatGateway(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateNatGateway") + } + return nat, nil +} + +func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGateway, error) { + spec := "" + switch strings.ToLower(opts.NatSpec) { + case api.NAT_SPEC_SMALL: + spec = "1" + case api.NAT_SPEC_MIDDLE: + spec = "2" + case api.NAT_SPEC_LARGE: + spec = "3" + case api.NAT_SPEC_XLARGE: + spec = "4" + } + params := map[string]interface{}{ + "nat_gateway": map[string]interface{}{ + "name": opts.Name, + "description": opts.Desc, + "router_id": opts.VpcId, + "internal_network_id": opts.NetworkId, + "spec": spec, + }, + } + ret := SNatGateway{region: self} + return &ret, self.create("nat", "v2.0", "nat_gateways", params, &ret) +} + +func (self *SRegion) DeleteNatGateway(id string) error { + return self.delete("nat", "v2.0", "nat_gateways/"+id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natstable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natstable.go new file mode 100644 index 0000000000..2d5a01162b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/natstable.go @@ -0,0 +1,143 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SNatSEntry struct { + multicloud.SResourceBase + huawei.HuaweiTags + gateway *SNatGateway + + Id string `json:"id"` + NatGatewayId string `json:"nat_gateway_id"` + NetworkId string `json:"network_id"` + SourceCIDR string `json:"cidr"` + Status string `json:"status"` + SNatIP string `json:"floating_ip_address"` + AdminStateUp bool `json:"admin_state_up"` +} + +func (nat *SNatSEntry) GetId() string { + return nat.Id +} + +func (nat *SNatSEntry) GetName() string { + // Snat rule has no name in Huawei Cloud, so return Id + return nat.GetId() +} + +func (nat *SNatSEntry) GetGlobalId() string { + return nat.GetId() +} + +func (nat *SNatSEntry) GetStatus() string { + return NatResouceStatusTransfer(nat.Status) +} + +func (nat *SNatSEntry) GetIP() string { + return nat.SNatIP +} + +func (nat *SNatSEntry) GetSourceCIDR() string { + return nat.SourceCIDR +} + +func (nat *SNatSEntry) GetNetworkId() string { + return nat.NetworkId +} + +func (nat *SNatSEntry) Delete() error { + return nat.gateway.region.DeleteNatSEntry(nat.GetId()) +} + +// getNatSTable return all snat rules of gateway +func (gateway *SNatGateway) getNatSTable() ([]SNatSEntry, error) { + ret, err := gateway.region.GetNatSTable(gateway.GetId()) + if err != nil { + return nil, err + } + for i := range ret { + ret[i].gateway = gateway + } + return ret, nil +} + +func (self *SRegion) GetNatSTable(natGatewayId string) ([]SNatSEntry, error) { + query := url.Values{} + query.Set("nat_gateway_id", natGatewayId) + ret := []SNatSEntry{} + err := self.list("nat", "v2.0", "snat_rules", query, &ret) + if err != nil { + return nil, err + } + for i := range ret { + nat := &ret[i] + if len(nat.SourceCIDR) != 0 { + continue + } + net, err := self.GetNetwork(nat.NetworkId) + if err != nil { + return nil, errors.Wrapf(err, "GetNetwork(%s)", nat.NetworkId) + } + nat.SourceCIDR = net.CIDR + } + return ret, nil +} + +func (self *SRegion) DeleteNatSEntry(entryId string) error { + return self.delete("nat", "v2.0", "snat_rules/"+entryId) +} + +func (nat *SNatSEntry) Refresh() error { + ret, err := nat.gateway.region.GetNatSEntry(nat.Id) + if err != nil { + return err + } + return jsonutils.Update(nat, ret) +} + +func (self *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayId string) (*SNatSEntry, error) { + params := make(map[string]interface{}) + params["nat_gateway_id"] = gatewayId + if len(rule.NetworkID) != 0 { + params["network_id"] = rule.NetworkID + } + if len(rule.SourceCIDR) != 0 { + params["cidr"] = rule.SourceCIDR + } + params["floating_ip_id"] = rule.ExternalIPID + + packParams := map[string]interface{}{ + "snat_rule": params, + } + + ret := &SNatSEntry{} + return ret, self.create("nat", "v2.0", "snat_rules", packParams, ret) +} + +func (self *SRegion) GetNatSEntry(id string) (*SNatSEntry, error) { + ret := &SNatSEntry{} + return ret, self.get("nat", "v2.0", "snat_rules/"+id, ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/network.go new file mode 100644 index 0000000000..f3178882ae --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/network.go @@ -0,0 +1,167 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +/* +Subnets +*/ + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html +type SNetwork struct { + multicloud.SResourceBase + HcsTags + wire *SWire + + AvailabilityZone string `json:"availability_zone"` + CIDR string `json:"cidr"` + DHCPEnable bool `json:"dhcp_enable"` + DNSList []string `json:"dnsList"` + GatewayIP string `json:"gateway_ip"` + Id string `json:"id"` + Ipv6Enable bool `json:"ipv6_enable"` + Name string `json:"name"` + NeutronNetworkId string `json:"neutron_network_id"` + NeutronSubnetId string `json:"neutron_subnet_id"` + PrimaryDNS string `json:"primary_dns"` + SecondaryDNS string `json:"secondary_dns"` + Status string `json:"status"` + VpcId string `json:"vpc_id"` +} + +func (self *SNetwork) GetId() string { + return self.Id +} + +func (self *SNetwork) GetName() string { + if len(self.Name) == 0 { + return self.Id + } + return self.Name +} + +func (self *SNetwork) GetGlobalId() string { + return self.Id +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090591.html +func (self *SNetwork) GetStatus() string { + switch self.Status { + case "ACTIVE", "UNKNOWN": + return api.NETWORK_STATUS_AVAILABLE // ? todo: // UNKNOWN + case "ERROR": + return api.NETWORK_STATUS_UNKNOWN + default: + return api.NETWORK_STATUS_UNKNOWN + } +} + +func (self *SNetwork) Refresh() error { + ret, err := self.wire.region.GetNetwork(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, ret) +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + startIp = startIp.StepUp() // 2 + return startIp.String() +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + 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.CIDR) + return pref.MaskLen +} + +func (self *SNetwork) GetGateway() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String() +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetIsPublic() bool { + return true +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) Delete() error { + return self.wire.region.DeleteNetwork(self.Id) +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (self *SRegion) GetNetwork(id string) (*SNetwork, error) { + ret := &SNetwork{} + res := fmt.Sprintf("subnets/%s", id) + return ret, self.vpcGet(res, ret) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090592.html +func (self *SRegion) GetNetwroks(vpcId string) ([]SNetwork, error) { + params := url.Values{} + if len(vpcId) > 0 { + params.Set("vpc_id", vpcId) + } + ret := []SNetwork{} + return ret, self.vpcList("subnets", params, &ret) +} + +func (self *SRegion) DeleteNetwork(id string) error { + res := fmt.Sprintf("subnets/%s", id) + return self.vpcDelete(res) +} + +func (self *SNetwork) GetProjectId() string { + return self.wire.vpc.EnterpriseProjectId +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/object.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/object.go new file mode 100644 index 0000000000..670048b0d8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/object.go @@ -0,0 +1,104 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + "net/http" + + "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SObject struct { + bucket *SBucket + + cloudprovider.SBaseCloudObject +} + +func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { + return o.bucket +} + +func (o *SObject) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + obscli, err := o.bucket.region.getOBSClient() + if err != nil { + log.Errorf("o.bucket.region.GetOssClient error %s", err) + return acl + } + input := &obs.GetObjectAclInput{} + input.Bucket = o.bucket.Name + input.Key = o.Key + output, err := obscli.GetObjectAcl(input) + if err != nil { + log.Errorf("GetObjectAcl error: %v", err) + return acl + } + acl = obsAcl2CannedAcl(output.Grants) + return acl +} + +func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { + obscli, err := o.bucket.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "o.bucket.region.getOBSClient") + } + input := &obs.SetObjectAclInput{} + input.Bucket = o.bucket.Name + input.Key = o.Key + input.ACL = obs.AclType(string(aclStr)) + _, err = obscli.SetObjectAcl(input) + if err != nil { + return errors.Wrap(err, "obscli.SetObjectAcl") + } + return nil +} + +func (o *SObject) GetMeta() http.Header { + if o.Meta != nil { + return o.Meta + } + obscli, err := o.bucket.region.getOBSClient() + if err != nil { + log.Errorf("getOBSClient fail %s", err) + return nil + } + input := &obs.GetObjectMetadataInput{} + input.Bucket = o.bucket.Name + input.Key = o.Key + output, err := obscli.GetObjectMetadata(input) + if err != nil { + log.Errorf("obscli.GetObjectMetadata fail %s", err) + return nil + } + meta := http.Header{} + for k, v := range output.Metadata { + meta.Add(k, v) + } + if len(output.ContentType) > 0 { + meta.Add(cloudprovider.META_HEADER_CONTENT_TYPE, output.ContentType) + } + o.Meta = meta + return meta +} + +func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { + return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/port.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/port.go new file mode 100644 index 0000000000..e6cd402d6b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/port.go @@ -0,0 +1,162 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SFixedIP struct { + IpAddress string + SubnetId string + NetworkId string +} + +func (fixip *SFixedIP) GetGlobalId() string { + return fixip.IpAddress +} + +func (fixip *SFixedIP) GetIP() string { + return fixip.IpAddress +} + +func (fixip *SFixedIP) GetINetworkId() string { + return fixip.NetworkId +} + +func (fixip *SFixedIP) IsPrimary() bool { + return true +} + +type Port struct { + multicloud.SNetworkInterfaceBase + huawei.HuaweiTags + region *SRegion + Id string `json:"id"` + Name string `json:"name"` + Status string `json:"status"` + AdminStateUp string `json:"admin_state_up"` + DNSName string `json:"dns_name"` + MACAddress string `json:"mac_address"` + NetworkId string `json:"network_id"` + TenantId string `json:"tenant_id"` + DeviceId string `json:"device_id"` + DeviceOwner string `json:"device_owner"` + BindingVnicType string `json:"binding:vnic_type"` + FixedIps []SFixedIP +} + +func (port *Port) GetName() string { + if len(port.Name) > 0 { + return port.Name + } + return port.Id +} + +func (port *Port) GetId() string { + return port.Id +} + +func (port *Port) GetGlobalId() string { + return port.Id +} + +func (port *Port) GetMacAddress() string { + return port.MACAddress +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html +func (port *Port) GetAssociateType() string { + switch port.DeviceOwner { + case "compute:nova": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER + case "network:router_gateway", "network:router_interface", "network:router_interface_distributed": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_RESERVED + case "network:dhcp": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_DHCP + case "neutron:LOADBALANCERV2": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_LOADBALANCER + case "neutron:VIP_PORT": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_VIP + default: + if strings.HasPrefix(port.DeviceOwner, "compute:") { + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER + } + } + return port.DeviceOwner +} + +func (port *Port) GetAssociateId() string { + return port.DeviceId +} + +func (port *Port) GetStatus() string { + switch port.Status { + case "ACTIVE", "DOWN": + return api.NETWORK_INTERFACE_STATUS_AVAILABLE + case "BUILD": + return api.NETWORK_INTERFACE_STATUS_CREATING + } + return port.Status +} + +func (port *Port) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { + address := []cloudprovider.ICloudInterfaceAddress{} + for i := 0; i < len(port.FixedIps); i++ { + port.FixedIps[i].NetworkId = port.NetworkId + address = append(address, &port.FixedIps[i]) + } + return address, nil +} + +func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { + ports, err := region.GetPorts("") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNetworkInterface{} + for i := 0; i < len(ports); i++ { + if len(ports[i].DeviceId) == 0 || !utils.IsInStringArray(ports[i].DeviceOwner, []string{"compute:CCI", "compute:nova", "neutron:LOADBALANCERV2"}) { + ports[i].region = region + ret = append(ret, &ports[i]) + } + } + return ret, nil +} + +func (self *SRegion) GetPort(id string) (*Port, error) { + port := &Port{} + res := fmt.Sprintf("ports/%s", id) + return port, self.vpcGet(res, port) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html +func (self *SRegion) GetPorts(instanceId string) ([]Port, error) { + ports := []Port{} + params := url.Values{} + if len(instanceId) > 0 { + params.Set("device_id", instanceId) + } + return ports, self.vpcList("ports", params, &ports) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/project.go new file mode 100644 index 0000000000..38e1bfb266 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/project.go @@ -0,0 +1,98 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "strings" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SProject struct { + Id string + Name string + DomainId string + Description bool + Enabled bool + ParentId string + IsDomain bool +} + +func (self *SProject) GetHealthStatus() string { + if self.Enabled { + return api.CLOUD_PROVIDER_HEALTH_NORMAL + } + return api.CLOUD_PROVIDER_HEALTH_SUSPENDED +} + +func (self *SHcsClient) GetProjects() ([]SProject, error) { + if len(self.projects) > 0 { + return self.projects, nil + } + resp, err := self.iamGet("v3/projects", nil) + if err != nil { + return nil, err + } + self.projects = []SProject{} + return self.projects, resp.Unmarshal(&self.projects, "projects") +} + +func (self *SHcsClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + projects, err := self.GetProjects() + if err != nil { + return nil, err + } + + ret := make([]cloudprovider.SSubAccount, 0) + for i := range projects { + project := projects[i] + // name 为MOS的project是华为云内部的一个特殊project。不需要同步到本地 + if strings.ToLower(project.Name) == "mos" { + continue + } + s := cloudprovider.SSubAccount{ + Name: fmt.Sprintf("%s-%s", self.cpcfg.Name, project.Name), + Account: fmt.Sprintf("%s/%s", self.accessKey, project.Id), + HealthStatus: project.GetHealthStatus(), + DefaultProjectId: "0", + } + for j := range self.regions { + region := self.regions[j] + if strings.Contains(project.Name, region.Id) { + s.Desc = region.Locales.ZhCN + break + } + } + ret = append(ret, s) + } + return ret, nil +} + +func (self *SHcsClient) GetProjectById(id string) (*SProject, error) { + projects, err := self.GetProjects() + if err != nil { + return nil, err + } + for i := range projects { + if projects[i].Id == id { + return &projects[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/provider/doc.go new file mode 100644 index 0000000000..a87ff6f3c6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/provider/doc.go @@ -0,0 +1 @@ +package provider // import "yunion.io/x/cloudmux/pkg/multicloud/hcs/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/provider/provider.go new file mode 100644 index 0000000000..5a3fa84232 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/provider/provider.go @@ -0,0 +1,217 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/hcs" +) + +type SHcsProviderFactory struct { + cloudprovider.SPrivateCloudBaseProviderFactory +} + +func (self *SHcsProviderFactory) GetId() string { + return hcs.CLOUD_PROVIDER_HCS +} + +func (self *SHcsProviderFactory) GetName() string { + return hcs.CLOUD_PROVIDER_HCS_CN +} + +func (self *SHcsProviderFactory) IsCloudeventRegional() bool { + return true +} + +func (self *SHcsProviderFactory) GetMaxCloudEventSyncDays() int { + return 7 +} + +func (self *SHcsProviderFactory) GetMaxCloudEventKeepDays() int { + return 7 +} + +func (factory *SHcsProviderFactory) IsSupportModifyRouteTable() bool { + return true +} + +func (factory *SHcsProviderFactory) IsSupportSAMLAuth() bool { + return false +} + +func (self *SHcsProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + if len(input.AuthUrl) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "auth_url") + } + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + output.AccessUrl = input.AuthUrl + return output, nil +} + +func (self *SHcsProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func parseAccount(account string) (accessKey string, projectId string) { + segs := strings.Split(account, "/") + if len(segs) == 2 { + accessKey = segs[0] + projectId = segs[1] + } else { + accessKey = account + projectId = "" + } + return +} + +func (self *SHcsProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + accessKey, projectId := parseAccount(cfg.Account) + client, err := hcs.NewHcsClient( + hcs.NewHcsConfig( + accessKey, cfg.Secret, projectId, cfg.URL, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SHcsProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SHcsProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + accessKey, projectId := parseAccount(info.Account) + return map[string]string{ + "HCS_AUTH_URL": info.Url, + "HCS_ACCESS_KEY": accessKey, + "HCS_SECRET": info.Secret, + "HCS_PROJECT_ID": projectId, + }, nil +} + +func init() { + factory := SHcsProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SHcsProvider struct { + cloudprovider.SBaseProvider + client *hcs.SHcsClient +} + +func (self *SHcsProvider) GetVersion() string { + return "" +} + +func (self *SHcsProvider) GetSysInfo() (jsonutils.JSONObject, error) { + regions := self.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") + info.Add(jsonutils.NewString(hcs.HCS_API_VERSION), "api_version") + return info, nil +} + +func (self *SHcsProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SHcsProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + region, err := self.client.GetRegion(id) + if err != nil { + return nil, err + } + return region, nil +} + +func (self *SHcsProvider) GetBalance() (float64, string, error) { + return 0, api.CLOUD_PROVIDER_HEALTH_NORMAL, nil +} + +func (self *SHcsProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SHcsProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SHcsProvider) GetCloudRegionExternalIdPrefix() string { + return self.client.GetCloudRegionExternalIdPrefix() +} + +func (self *SHcsProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return []cloudprovider.ICloudProject{}, nil +} + +func (self *SHcsProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SHcsProvider) GetStorageClasses(regionId string) []string { + return []string{ + "STANDARD", "WARM", "COLD", + } +} + +func (self *SHcsProvider) GetBucketCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLAuthRead), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SHcsProvider) GetObjectCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLAuthRead), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SHcsProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis.go new file mode 100644 index 0000000000..17e64af76d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis.go @@ -0,0 +1,608 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html +type SElasticcache struct { + multicloud.SElasticcacheBase + HcsTags + + region *SRegion + + Name string `json:"name"` + Engine string `json:"engine"` + CapacityGB int `json:"capacity"` + IP string `json:"ip"` + DomainName string `json:"domainName"` + Port int `json:"port"` + Status string `json:"status"` + Libos bool `json:"libos"` + Description string `json:"description"` + Task string `json:"task"` + MaxMemoryMB int `json:"max_memory"` + UsedMemoryMB int `json:"used_memory"` + InstanceId string `json:"instance_id"` + ResourceSpecCode string `json:"resource_spec_code"` + EngineVersion string `json:"engine_version"` + InternalVersion string `json:"internal_version"` + ChargingMode int `json:"charging_mode"` + CapacityMinor string `json:"capacity_minor"` + VpcId string `json:"vpc_id"` + VpcName string `json:"vpc_name"` + TaskStatus string `json:"task_status"` + CreatedAt string `json:"created_at"` + ErrorCode string `json:"error_code"` + UserId string `json:"user_id"` + UserName string `json:"user_name"` + MaintainBegin string `json:"maintain_begin"` + MaintainEnd string `json:"maintain_end"` + NoPasswordAccess string `json:"no_password_access"` + AccessUser string `json:"access_user"` + EnablePublicip bool `json:"enable_publicip"` + PublicipId string `json:"publicip_id"` + PublicipAddress string `json:"publicip_address"` + EnableSSL bool `json:"enable_ssl"` + ServiceUpgrade bool `json:"service_upgrade"` + ServiceTaskId string `json:"service_task_id"` + IsFree string `json:"is_free"` + EnterpriseProjectId string `json:"enterprise_project_id"` + AvailableZones []string `json:"available_zones"` + SubnetId string `json:"subnet_id"` + SecurityGroupId string `json:"security_group_id"` + BackendAddrs []string `json:"backend_addrs"` + ProductId string `json:"product_id"` + SecurityGroupName string `json:"security_group_name"` + SubnetName string `json:"subnet_name"` + OrderId string `json:"order_id"` + SubnetCIdR string `json:"subnet_cidr"` + InstanceBackupPolicy string `json:"instance_backup_policy"` + EnterpriseProjectName string `json:"enterprise_project_name"` +} + +func (self *SElasticcache) GetId() string { + return self.InstanceId +} + +func (self *SElasticcache) GetName() string { + return self.Name +} + +func (self *SElasticcache) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcache) GetProjectId() string { + return self.EnterpriseProjectId +} + +func (self *SElasticcache) Refresh() error { + cache, err := self.region.GetElasticCache(self.GetId()) + if err != nil { + return errors.Wrap(err, "Elasticcache.Refresh.GetElasticCache") + } + + err = jsonutils.Update(self, cache) + if err != nil { + return errors.Wrap(err, "Elasticcache.Refresh.Update") + } + + return nil +} + +func (self *SElasticcache) GetStatus() string { + switch self.Status { + case "RUNNING": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "CREATING": + return api.ELASTIC_CACHE_STATUS_DEPLOYING + case "CREATEFAILED": + return api.ELASTIC_CACHE_STATUS_CREATE_FAILED + case "ERROR": + return api.ELASTIC_CACHE_STATUS_ERROR + case "RESTARTING": + return api.ELASTIC_CACHE_STATUS_RESTARTING + case "FROZEN": + return api.ELASTIC_CACHE_STATUS_UNAVAILABLE + case "EXTENDING": + return api.ELASTIC_CACHE_STATUS_CHANGING + case "RESTORING": + return api.ELASTIC_CACHE_STATUS_TRANSFORMING // ? + case "FLUSHING": + return api.ELASTIC_CACHE_STATUS_FLUSHING + } + + return "" +} + +func (self *SElasticcache) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SElasticcache) GetCreatedAt() time.Time { + var createtime time.Time + if len(self.CreatedAt) > 0 { + createtime, _ = time.Parse("2006-01-02T15:04:05.000Z", self.CreatedAt) + } + + return createtime +} + +func (self *SElasticcache) GetInstanceType() string { + return self.ResourceSpecCode +} + +func (self *SElasticcache) GetCapacityMB() int { + return self.CapacityGB * 1024 +} + +func (self *SElasticcache) GetArchType() string { + if strings.Contains(self.ResourceSpecCode, "single") { + return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE + } + if strings.Contains(self.ResourceSpecCode, "ha") { + return api.ELASTIC_CACHE_ARCH_TYPE_MASTER + } + if strings.Contains(self.ResourceSpecCode, "cluster") { + return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER + } + if strings.Contains(self.ResourceSpecCode, "proxy") { + return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER + } + return "" +} + +func (self *SElasticcache) GetNodeType() string { + // single(单副本) | double(双副本) + if strings.Contains(self.ResourceSpecCode, "single") { + return "single" + } + return "double" +} + +func (self *SElasticcache) GetEngine() string { + return self.Engine +} + +func (self *SElasticcache) GetEngineVersion() string { + return self.EngineVersion +} + +func (self *SElasticcache) GetVpcId() string { + return self.VpcId +} + +func (self *SElasticcache) GetZoneId() string { + if len(self.AvailableZones) > 0 { + zone, err := self.region.GetZoneById(self.AvailableZones[0]) + if err != nil { + log.Errorf("elasticcache.GetZoneId %s", err) + return "" + } + return zone.GetGlobalId() + } + return "" +} + +func (self *SElasticcache) GetNetworkType() string { + return api.LB_NETWORK_TYPE_VPC +} + +func (self *SElasticcache) GetNetworkId() string { + return self.SubnetId +} + +func (self *SElasticcache) GetPrivateDNS() string { + return self.DomainName +} + +func (self *SElasticcache) GetPrivateIpAddr() string { + return self.IP +} + +func (self *SElasticcache) GetPrivateConnectPort() int { + return self.Port +} + +func (self *SElasticcache) GetPublicDNS() string { + return self.PublicipAddress +} + +func (self *SElasticcache) GetPublicIpAddr() string { + return self.PublicipAddress +} + +func (self *SElasticcache) GetPublicConnectPort() int { + return self.Port +} + +func (self *SElasticcache) GetMaintainStartTime() string { + return self.MaintainBegin +} + +func (self *SElasticcache) GetMaintainEndTime() string { + return self.MaintainEnd +} + +func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { + iaccounts := []cloudprovider.ICloudElasticcacheAccount{} + iaccount := &SElasticcacheAccount{cacheDB: self} + iaccounts = append(iaccounts, iaccount) + return iaccounts, nil +} + +func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { + // 华为云使用安全组做访问控制。目前未支持 + return []cloudprovider.ICloudElasticcacheAcl{}, nil +} + +func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { + start := self.GetCreatedAt().Format("20060102150405") + end := time.Now().Format("20060102150405") + backups, err := self.region.GetElasticCacheBackups(self.GetId(), start, end) + if err != nil { + return nil, err + } + + ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) + for i := range backups { + backups[i].cacheDB = self + ibackups[i] = &backups[i] + } + + return ibackups, nil +} + +func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { + parameters, err := self.region.GetElasticCacheParameters(self.GetId()) + if err != nil { + return nil, err + } + + iparameters := make([]cloudprovider.ICloudElasticcacheParameter, len(parameters)) + for i := range parameters { + parameters[i].cacheDB = self + iparameters[i] = ¶meters[i] + } + + return iparameters, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html +func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) { + params := url.Values{} + params.Set("beginTime", startTime) + params.Set("endTime", endTime) + res := fmt.Sprintf("instances/%s/backups", instanceId) + ret := []SElasticcacheBackup{} + return ret, self.redisList(res, params, &ret) +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html +func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { + params := url.Values{} + res := fmt.Sprintf("instances/%s/configs", instanceId) + ret := []SElasticcacheParameter{} + return ret, self.redisList(res, params, &ret) +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423044.html +func (self *SRegion) GetElasticCaches() ([]SElasticcache, error) { + params := url.Values{} + ret := []SElasticcache{} + return ret, self.redisList("instances", params, &ret) +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html +func (self *SRegion) GetElasticCache(instanceId string) (*SElasticcache, error) { + cache := &SElasticcache{region: self} + res := fmt.Sprintf("instances/%s", instanceId) + return cache, self.redisGet(res, cache) +} + +func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { + ec, err := self.GetElasticCache(id) + if err != nil { + return nil, errors.Wrapf(err, "GetElasticCache(%s)", id) + } + return ec, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423047.html +func (self *SRegion) zoneNameToDcsZoneIds(zoneIds []string) ([]string, error) { + type Z struct { + Id string `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Port string `json:"port"` + ResourceAvailability string `json:"resource_availability"` + } + + rs := []Z{} + err := self.redisList("availableZones", url.Values{}, &rs) + if err != nil { + return nil, errors.Wrapf(err, "availableZones") + } + zoneMap := map[string]string{} + for i := range rs { + if rs[i].ResourceAvailability == "true" { + zoneMap[rs[i].Code] = rs[i].Id + } + } + + ret := []string{} + for _, zone := range zoneIds { + if id, ok := zoneMap[zone]; ok { + ret = append(ret, id) + } else { + return nil, errors.Wrap(fmt.Errorf("zone %s not found or not available", zone), "region.zoneNameToDcsZoneIds") + } + } + + return ret, nil +} + +func (self *SRegion) CreateElasticcache(opts *cloudprovider.SCloudElasticCacheInput) (*SElasticcache, error) { + params := map[string]interface{}{ + "name": opts.InstanceName, + "engine": opts.Engine, + "engine_version": opts.EngineVersion, + "capacity": opts.CapacityGB, + "vpc_id": opts.VpcId, + "subnet_id": opts.NetworkId, + "product_id": opts.InstanceType, + "spec_code": opts.InstanceType, + "available_zones": opts.ZoneIds, + "no_password_access": true, + "enable_publicip": false, + } + if len(opts.SecurityGroupIds) > 0 { + params["security_group_id"] = opts.SecurityGroupIds[0] + } + + if len(opts.ProjectId) > 0 { + params["enterprise_project_id"] = opts.ProjectId + } + + if len(opts.Password) > 0 { + params["no_password_access"] = false + params["password"] = opts.Password + if opts.Engine == "Memcache" { + params["access_user"] = opts.UserName + } + } + + if len(opts.EipId) > 0 { + params["enable_publicip"] = true + params["publicip_id"] = opts.EipId + } + + if len(opts.PrivateIpAddress) > 0 { + params["private_ip"] = opts.PrivateIpAddress + } + + if len(opts.MaintainBegin) > 0 { + params["maintain_begin"] = opts.MaintainBegin + params["maintain_end"] = opts.MaintainEnd + } + + ret := struct { + InstanceId string + }{} + err := self.redisCreate("instances", params, &ret) + if err != nil { + return nil, errors.Wrap(err, "redisCreate") + } + return self.GetElasticCache(ret.InstanceId) +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423019.html +func (self *SRegion) CreateIElasticcaches(opts *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { + cache, err := self.CreateElasticcache(opts) + if err != nil { + return nil, err + } + return cache, nil +} + +func (self *SElasticcache) Restart() error { + return nil +} + +func (self *SElasticcache) Delete() error { + return self.region.DeleteElasticcache(self.InstanceId) +} + +func (self *SRegion) DeleteElasticcache(id string) error { + res := fmt.Sprintf("instances/%s", id) + return self.redisDelete(res) +} + +func (self *SElasticcache) ChangeInstanceSpec(spec string) error { + return cloudprovider.ErrNotImplemented +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html +func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { + return cloudprovider.ErrNotImplemented +} + +// https://support.huaweicloud.com/usermanual-dcs/dcs-zh-ug-180314001.html +// 目前只有Redis3.0版本密码模式的实例支持通过公网访问Redis实例,其他版本暂不支持公网访问。 +// todo: 目前没找到api +func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +// todo: 目前没找到api +func (self *SElasticcache) ReleasePublicConnection() error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { + return nil, cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html + +func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423029.html +func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { + return cloudprovider.ErrNotImplemented +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423033.html +func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func backupPeriodTrans(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) *jsonutils.JSONArray { + segs := strings.Split(config.PreferredBackupPeriod, ",") + ret := jsonutils.NewArray() + for _, seg := range segs { + switch seg { + case "Monday": + ret.Add(jsonutils.NewString("1")) + case "Tuesday": + ret.Add(jsonutils.NewString("2")) + case "Wednesday": + ret.Add(jsonutils.NewString("3")) + case "Thursday": + ret.Add(jsonutils.NewString("4")) + case "Friday": + ret.Add(jsonutils.NewString("5")) + case "Saturday": + ret.Add(jsonutils.NewString("6")) + case "Sunday": + ret.Add(jsonutils.NewString("7")) + } + } + + return ret +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html +func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html +// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 +func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { + return nil +} + +// SElasticcacheAccount => ResetPassword +func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool, password string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetAuthMode() string { + switch self.NoPasswordAccess { + case "true": + return "off" + default: + return "on" + } +} + +func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { + accounts, err := self.GetICloudElasticcacheAccounts() + if err != nil { + return nil, errors.Wrap(err, "Elasticcache.GetICloudElasticcacheAccount.Accounts") + } + + for i := range accounts { + account := accounts[i] + if account.GetGlobalId() == accountId { + return account, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { + backups, err := self.GetICloudElasticcacheBackups() + if err != nil { + return nil, err + } + + for _, backup := range backups { + if backup.GetId() == backupId { + return backup, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (instance *SElasticcache) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { + return errors.Wrap(cloudprovider.ErrNotSupported, "UpdateSecurityGroups") +} + +func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) SetAutoRenew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { + caches, err := self.GetElasticCaches() + if err != nil { + return nil, err + } + + ret := []cloudprovider.ICloudElasticcache{} + for i := range caches { + caches[i].region = self + ret = append(ret, &caches[i]) + } + + return ret, nil +} diff --git a/pkg/multicloud/hcs/redis_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_account.go similarity index 92% rename from pkg/multicloud/hcs/redis_account.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_account.go index f5cc8a9032..ae546c2fcc 100644 --- a/pkg/multicloud/hcs/redis_account.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_account.go @@ -17,14 +17,15 @@ package hcs import ( "fmt" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" ) type SElasticcacheAccount struct { multicloud.SElasticcacheAccountBase - multicloud.HuaweiTags + huawei.HuaweiTags cacheDB *SElasticcache } diff --git a/pkg/multicloud/hcs/redis_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_backup.go similarity index 94% rename from pkg/multicloud/hcs/redis_backup.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_backup.go index d45c30eec3..f6bed0219d 100644 --- a/pkg/multicloud/hcs/redis_backup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_backup.go @@ -20,15 +20,16 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" ) // https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html type SElasticcacheBackup struct { multicloud.SElasticcacheBackupBase - multicloud.HuaweiTags + huawei.HuaweiTags cacheDB *SElasticcache diff --git a/pkg/multicloud/hcs/redis_instancetype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_instancetype.go similarity index 98% rename from pkg/multicloud/hcs/redis_instancetype.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_instancetype.go index 394d85bad2..99cebde122 100644 --- a/pkg/multicloud/hcs/redis_instancetype.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_instancetype.go @@ -21,9 +21,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - "yunion.io/x/onecloud/pkg/apis" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/apis" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SRedisSkuDetails struct { diff --git a/pkg/multicloud/hcs/redis_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_parameter.go similarity index 93% rename from pkg/multicloud/hcs/redis_parameter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_parameter.go index a19009116f..730ded7704 100644 --- a/pkg/multicloud/hcs/redis_parameter.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/redis_parameter.go @@ -17,14 +17,15 @@ package hcs import ( "fmt" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" ) // https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html type SElasticcacheParameter struct { multicloud.SElasticcacheParameterBase - multicloud.HuaweiTags + huawei.HuaweiTags cacheDB *SElasticcache diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/region.go new file mode 100644 index 0000000000..6bda0fe5bd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/region.go @@ -0,0 +1,332 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + "strings" + + "github.com/huaweicloud/huaweicloud-sdk-go-obs/obs" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + HcsTags + multicloud.SRegion + multicloud.SRegionEipBase + multicloud.SRegionOssBase + multicloud.SRegionLbBase + multicloud.SRegionVpcBase + multicloud.SRegionZoneBase + multicloud.SRegionSecurityGroupBase + + obsClient *obs.ObsClient // 对象存储client.请勿直接引用。 + + client *SHcsClient + + Id string + CloudInfras []string + Description string + Locales struct { + EnUS string `json:"en-us"` + ZhCN string `json:"zh-cn"` + } + ParentRegionId string +} + +func (self *SRegion) GetClient() *SHcsClient { + return self.client +} + +func (self *SRegion) GetId() string { + return self.Id +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_HCS, self.Id) +} + +func (self *SRegion) GetName() string { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HCS_CN, self.Locales.ZhCN) +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HCS_EN, self.Locales.EnUS) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SRegion) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SRegion) GetCloudEnv() string { + return "" +} + +func (self *SRegion) GetProvider() string { + return CLOUD_PROVIDER_HCS +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) ecsList(resource string, query url.Values, retVal interface{}) error { + return self.client.ecsList(self.Id, resource, query, retVal) +} + +func (self *SRegion) ecsGet(resource string, retVal interface{}) error { + return self.client.ecsGet(self.Id, resource, retVal) +} + +func (self *SRegion) ecsDelete(resource string) error { + return self.client.ecsDelete(self.Id, resource) +} + +func (self *SRegion) ecsCreate(resource string, body map[string]interface{}, retVal interface{}) error { + return self.client.ecsCreate(self.Id, resource, body, retVal) +} + +func (self *SRegion) ecsPerform(resource, action string, params map[string]interface{}, retVal interface{}) error { + return self.client.ecsPerform(self.Id, resource, action, params, retVal) +} + +func (region *SRegion) rdsList(resource string, query url.Values, retVal interface{}) error { + return region.client.rdsList(region.Id, resource, query, retVal) +} + +func (region *SRegion) rdsGet(resource string, retVal interface{}) error { + return region.client.rdsGet(region.Id, resource, retVal) +} + +func (region *SRegion) rdsDelete(resource string) error { + return region.client.rdsDelete(region.Id, resource) +} + +func (region *SRegion) rdsCreate(resource string, body map[string]interface{}, retVal interface{}) error { + return region.client.rdsCreate(region.Id, resource, body, retVal) +} + +func (self *SRegion) rdsPerform(resource, action string, params map[string]interface{}, retVal interface{}) error { + return self.client.rdsPerform(self.Id, resource, action, params, retVal) +} + +func (region *SRegion) rdsJobGet(resource string, query url.Values, retVal interface{}) error { + return region.client.rdsJobGet(region.Id, resource, query, retVal) +} + +func (region *SRegion) rdsDBPrivilegesDelete(resource string, params map[string]interface{}) error { + return region.client.rdsDBPrivvilegesDelete(region.Id, resource, params) +} + +func (region *SRegion) rdsDBPrivilegesGrant(resource string, params map[string]interface{}, retVal interface{}) error { + return region.client.rdsDBPrivilegesGrant(region.Id, resource, params, retVal) +} + +func (self *SRegion) perform(product, version, resource, action string, params map[string]interface{}, retVal interface{}) error { + return self.client.perform(product, version, self.Id, resource, action, params, retVal) +} + +func (self *SRegion) create(product, version, resource string, body map[string]interface{}, retVal interface{}) error { + return self.client.create(product, version, self.Id, resource, body, retVal) +} + +func (self *SRegion) delete(product, version, resource string) error { + return self.client.delete(product, version, self.Id, resource) +} + +func (self *SRegion) list(product, version, resource string, query url.Values, retVal interface{}) error { + return self.client.list(product, version, self.Id, resource, query, retVal) +} + +func (self *SRegion) get(product, version, resource string, retVal interface{}) error { + return self.client.get(product, version, self.Id, resource, retVal) +} +func (self *SRegion) update(product, version, resource string, params map[string]interface{}) error { + return self.client.update(product, version, self.Id, resource, params) +} + +func (self *SRegion) evsList(resource string, query url.Values, retVal interface{}) error { + return self.client.evsList(self.Id, resource, query, retVal) +} + +func (self *SRegion) evsGet(resource string, retVal interface{}) error { + return self.client.evsGet(self.Id, resource, retVal) +} + +func (self *SRegion) evsDelete(resource string) error { + return self.client.evsDelete(self.Id, resource) +} + +func (self *SRegion) evsPerform(resource, action string, params map[string]interface{}) error { + return self.client.evsPerform(self.Id, resource, action, params) +} + +func (self *SRegion) evsCreate(resource string, body map[string]interface{}, retVal interface{}) error { + return self.client.evsCreate(self.Id, resource, body, retVal) +} + +func (self *SRegion) vpcList(resource string, query url.Values, retVal interface{}) error { + return self.client.vpcList(self.Id, resource, query, retVal) +} + +func (self *SRegion) vpcCreate(resource string, body map[string]interface{}, retVal interface{}) error { + return self.client.vpcCreate(self.Id, resource, body, retVal) +} + +func (self *SRegion) vpcGet(resource string, retVal interface{}) error { + return self.client.vpcGet(self.Id, resource, retVal) +} + +func (self *SRegion) vpcUpdate(resource string, params map[string]interface{}) error { + return self.client.vpcUpdate(self.Id, resource, params) +} + +func (self *SRegion) vpcDelete(resource string) error { + return self.client.vpcDelete(self.Id, resource) +} + +func (self *SRegion) imsList(resource string, query url.Values, retVal interface{}) error { + return self.client.imsList(self.Id, resource, query, retVal) +} + +func (self *SRegion) imsCreate(resource string, body map[string]interface{}, retVal interface{}) error { + return self.client.imsCreate(self.Id, resource, body, retVal) +} + +func (self *SRegion) imsGet(resource string, retVal interface{}) error { + return self.client.imsGet(self.Id, resource, retVal) +} + +func (self *SRegion) imsUpdate(resource string, params map[string]interface{}) error { + return self.client.imsUpdate(self.Id, resource, params) +} + +func (self *SRegion) imsDelete(resource string) error { + return self.client.imsDelete(self.Id, resource) +} + +func (self *SRegion) imsPerform(resource, action string, params map[string]interface{}, retVal interface{}) error { + return self.client.imsPerform(self.Id, resource, action, params, retVal) +} + +func (self *SRegion) redisList(resource string, query url.Values, retVal interface{}) error { + return self.client.dcsList(self.Id, resource, query, retVal) +} + +func (self *SRegion) redisCreate(resource string, body map[string]interface{}, retVal interface{}) error { + return self.client.dcsCreate(self.Id, resource, body, retVal) +} + +func (self *SRegion) redisGet(resource string, retVal interface{}) error { + return self.client.dcsGet(self.Id, resource, retVal) +} + +func (self *SRegion) redisUpdate(resource string, params map[string]interface{}) error { + return self.client.dcsUpdate(self.Id, resource, params) +} + +func (self *SRegion) redisDelete(resource string) error { + return self.client.dcsDelete(self.Id, resource) +} + +func (self *SRegion) redisPerform(resource, action string, params map[string]interface{}, retVal interface{}) error { + return self.client.dcsPerform(self.Id, resource, action, params, retVal) +} + +func (self *SRegion) GetICloudSku(skuId string) (cloudprovider.ICloudSku, error) { + sku, err := self.GetchInstanceType(skuId) + if err != nil { + return nil, err + } + return sku, nil +} + +func (self *SRegion) getOBSClient() (*obs.ObsClient, error) { + if self.obsClient == nil { + obsClient, err := self.client.getOBSClient(self.GetId()) + if err != nil { + return nil, err + } + self.obsClient = obsClient + } + return self.obsClient, nil +} + +func (self *SRegion) HeadBucket(name string) (*obs.BaseModel, error) { + obsClient, err := self.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "region.getOBSClient") + } + return obsClient.HeadBucket(name) +} + +func (self *SRegion) getOBSEndpoint() string { + return self.client.getOBSEndpoint(self.GetId()) +} + +func str2StorageClass(storageClassStr string) (obs.StorageClassType, error) { + if strings.EqualFold(storageClassStr, string(obs.StorageClassStandard)) { + return obs.StorageClassStandard, nil + } else if strings.EqualFold(storageClassStr, string(obs.StorageClassWarm)) { + return obs.StorageClassWarm, nil + } else if strings.EqualFold(storageClassStr, string(obs.StorageClassCold)) { + return obs.StorageClassCold, nil + } else { + return obs.StorageClassStandard, errors.Error("unsupported storageClass") + } +} + +func (self *SRegion) GetBuckets() ([]SBucket, error) { + buckets, err := self.client.GetBuckets() + if err != nil { + return nil, err + } + ret := []SBucket{} + for i := range buckets { + if buckets[i].region.GetGlobalId() == self.GetGlobalId() { + ret = append(ret, buckets[i]) + } + } + return ret, nil +} + +func (self *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + buckets, err := self.GetBuckets() + if err != nil { + return nil, errors.Wrap(err, "GetBuckets") + } + ret := make([]cloudprovider.ICloudBucket, 0) + for i := range buckets { + ret = append(ret, &buckets[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/routetables.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/routetables.go new file mode 100644 index 0000000000..1a3373aa84 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/routetables.go @@ -0,0 +1,215 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +var hoptypes = map[string]string{ + api.NEXT_HOP_TYPE_VPCPEERING: "peering", + api.NEXT_HOP_TYPE_INSTANCE: "ecs", + api.NEXT_HOP_TYPE_NAT: "nat", + api.NEXT_HOP_TYPE_HAVIP: "vip", + api.NEXT_HOP_TYPE_NETWORK: "eni", + api.NEXT_HOP_TYPE_INTERVPCNETWORK: "cc", +} + +type SRoute struct { + multicloud.SResourceBase + huawei.HuaweiTags + + Type string `json:"type"` + Destination string `json:"destination"` + Nexthop string `json:"nexthop"` + Description string `json:"description,omitempty"` +} + +func (self *SRoute) GetCidr() string { + return self.Destination +} + +func (self *SRoute) GetGlobalId() string { + return self.GetId() +} + +func (self *SRoute) GetId() string { + return fmt.Sprintf("%s:%s:%s", self.Type, self.Nexthop, self.Destination) +} + +func (self *SRoute) GetName() string { + return "" +} + +func (route *SRoute) GetStatus() string { + return api.ROUTE_ENTRY_STATUS_AVAILIABLE +} + +func (route *SRoute) GetType() string { + if route.Type != "local" { + return api.ROUTE_ENTRY_TYPE_CUSTOM + } + return api.ROUTE_ENTRY_TYPE_SYSTEM +} + +func (self *SRoute) GetNextHopType() string { + for k, v := range hoptypes { + if v == self.Type { + return k + } + } + return self.Type +} + +type Subnet struct { + Id string `json:"id"` +} + +type SRouteTable struct { + multicloud.SResourceBase + huawei.HuaweiTags + vpc *SVpc + + Id string `json:"id"` + Name string `json:"name"` + Routes []SRoute `json:"routes"` + Subnets []Subnet `json:"subnets"` + VpcId string `json:"vpc_id"` + Default bool `json:"default"` + TenantId string `json:"tenant_id"` +} + +func (self *SRouteTable) GetDescription() string { + return "" +} + +func (self *SRouteTable) GetGlobalId() string { + return self.Id +} + +func (self *SRouteTable) GetId() string { + return self.Id +} + +func (self *SRouteTable) GetName() string { + return self.Name +} + +func (self *SRouteTable) GetRegionId() string { + return self.vpc.region.GetId() +} + +func (self *SRouteTable) GetVpcId() string { + return self.VpcId +} + +func (self *SRouteTable) GetType() cloudprovider.RouteTableType { + return cloudprovider.RouteTableTypeSystem +} + +func (self *SRouteTable) GetStatus() string { + return api.ROUTE_TABLE_AVAILABLE +} + +func (self *SRouteTable) Refresh() error { + rtb, err := self.vpc.region.GetRouteTable(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, rtb) +} + +func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { + if len(self.Routes) == 0 { + err := self.Refresh() + if err != nil { + return nil, err + } + } + ret := []cloudprovider.ICloudRoute{} + for i := range self.Routes { + ret = append(ret, &self.Routes[i]) + } + return ret, nil +} + +func (self *SRoute) GetNextHop() string { + return self.Nexthop +} + +func (self *SRegion) GetRouteTables(vpcId string) ([]SRouteTable, error) { + params := url.Values{} + if len(vpcId) > 0 { + params.Set("vpc_id", vpcId) + } + rtbs := []SRouteTable{} + return rtbs, self.list("vpc", "v2.0", "vpc/routes", params, &rtbs) +} + +func (self *SRegion) GetRouteTable(id string) (*SRouteTable, error) { + tb := &SRouteTable{} + return tb, self.get("vpc", "v2.0", "vpc/routes/"+id, tb) +} + +func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { + routeType, ok := hoptypes[route.NextHopType] + if !ok { + return errors.Wrapf(cloudprovider.ErrNotSupported, route.NextHopType) + } + params := map[string]interface{}{ + "routes": map[string]interface{}{ + "add": []map[string]interface{}{ + { + "type": routeType, + "destination": route.Destination, + "nexthop": route.NextHop, + }, + }, + }, + } + return self.vpc.region.create("vpc", "v2.0", "vpc/routes", params, nil) +} + +func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { + if len(route.RouteId) > 0 { + return self.vpc.region.delete("vpc", "v2.0", "vpc/routes/"+route.RouteId) + } + return fmt.Errorf("missing route id") +} + +func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { + err := self.RemoveRoute(route) + if err != nil { + return errors.Wrap(err, "self.RemoveRoute(route)") + } + err = self.CreateRoute(route) + if err != nil { + return errors.Wrap(err, "self.CreateRoute(route)") + } + return nil +} + +func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { + return []cloudprovider.RouteTableAssociation{} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/securitygroup.go new file mode 100644 index 0000000000..b617e8a7e6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/securitygroup.go @@ -0,0 +1,340 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SecurityGroupRule struct { + Direction string `json:"direction"` + Ethertype string `json:"ethertype"` + Id string `json:"id"` + Description string `json:"description"` + SecurityGroupId string `json:"security_group_id"` + RemoteGroupId string `json:"remote_group_id"` +} + +type SecurityGroupRuleDetail struct { + Direction string `json:"direction"` + Ethertype string `json:"ethertype"` + Id string `json:"id"` + Description string `json:"description"` + PortRangeMax int64 `json:"port_range_max"` + PortRangeMin int64 `json:"port_range_min"` + Protocol string `json:"protocol"` + RemoteGroupId string `json:"remote_group_id"` + RemoteIPPrefix string `json:"remote_ip_prefix"` + SecurityGroupId string `json:"security_group_id"` + TenantId string `json:"tenant_id"` +} + +type SSecurityGroup struct { + multicloud.SSecurityGroup + HcsTags + region *SRegion + + Id string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + VpcId string `json:"vpc_id"` + EnterpriseProjectId string `json:"enterprise_project_id "` + SecurityGroupRules []SecurityGroupRule `json:"security_group_rules"` +} + +// 判断是否兼容云端安全组规则 +func compatibleSecurityGroupRule(r SecurityGroupRule) bool { + // 忽略了源地址是安全组的规则 + if len(r.RemoteGroupId) > 0 { + return false + } + + // 忽略IPV6 + if r.Ethertype == "IPv6" { + return false + } + + return true +} + +func (self *SSecurityGroup) GetId() string { + return self.Id +} + +func (self *SSecurityGroup) GetVpcId() string { + return self.VpcId +} + +func (self *SSecurityGroup) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.Id +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.Id +} + +func (self *SSecurityGroup) GetStatus() string { + return "" +} + +func (self *SSecurityGroup) Refresh() error { + if new, err := self.region.GetSecurityGroupDetails(self.GetId()); err != nil { + return err + } else { + return jsonutils.Update(self, new) + } +} + +func (self *SSecurityGroup) IsEmulated() bool { + return false +} + +func (self *SSecurityGroup) GetDescription() string { + if self.Description == self.VpcId { + return "" + } + return self.Description +} + +// todo: 这里需要优化查询太多了 +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + rules := make([]cloudprovider.SecurityRule, 0) + for _, r := range self.SecurityGroupRules { + if !compatibleSecurityGroupRule(r) { + continue + } + + rule, err := self.GetSecurityRule(r.Id) + if err != nil { + return rules, err + } + + rules = append(rules, rule) + } + + return rules, nil +} + +func (self *SSecurityGroup) GetSecurityRule(ruleId string) (cloudprovider.SecurityRule, error) { + remoteRule := SecurityGroupRuleDetail{} + err := self.region.vpcGet("security-group-rules/"+ruleId, &remoteRule) + if err != nil { + return cloudprovider.SecurityRule{}, err + } + + var direction secrules.TSecurityRuleDirection + if remoteRule.Direction == "ingress" { + direction = secrules.SecurityRuleIngress + } else { + direction = secrules.SecurityRuleEgress + } + + protocol := secrules.PROTO_ANY + if remoteRule.Protocol != "" { + protocol = remoteRule.Protocol + } + + var portStart int + var portEnd int + if protocol == secrules.PROTO_ICMP { + portStart = -1 + portEnd = -1 + } else { + portStart = int(remoteRule.PortRangeMin) + portEnd = int(remoteRule.PortRangeMax) + } + + ipNet := &net.IPNet{} + if len(remoteRule.RemoteIPPrefix) > 0 { + _, ipNet, err = net.ParseCIDR(remoteRule.RemoteIPPrefix) + } else { + _, ipNet, err = net.ParseCIDR("0.0.0.0/0") + } + + if err != nil { + return cloudprovider.SecurityRule{}, err + } + + rule := cloudprovider.SecurityRule{ + ExternalId: ruleId, + SecurityRule: secrules.SecurityRule{ + Priority: 1, + Action: secrules.SecurityRuleAllow, + IPNet: ipNet, + Protocol: protocol, + Direction: direction, + PortStart: portStart, + PortEnd: portEnd, + Ports: nil, + Description: remoteRule.Description, + }, + } + + err = rule.ValidateRule() + return rule, err +} + +func (self *SRegion) GetSecurityGroupDetails(id string) (*SSecurityGroup, error) { + ret := &SSecurityGroup{region: self} + return ret, self.vpcGet("security-groups/"+id, ret) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090617.html +func (self *SRegion) GetSecurityGroups(vpcId string) ([]SSecurityGroup, error) { + query := url.Values{} + if len(vpcId) > 0 && !utils.IsInStringArray(vpcId, []string{"default", api.NORMAL_VPC_ID}) { // vpc_id = default or normal 时报错 '{"code":"VPC.0601","message":"Query security groups error vpcId is invalid."}' + query.Set("vpc_id", vpcId) + } + ret := []SSecurityGroup{} + return ret, self.vpcList("security-groups", query, &ret) +} + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} + +func (self *SSecurityGroup) Delete() error { + return self.region.DeleteSecurityGroup(self.Id) +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + for _, r := range append(inDels, outDels...) { + err := self.region.DeleteSecurityGroupRule(r.ExternalId) + if err != nil { + return errors.Wrapf(err, "delSecurityGroupRule(%s %s)", r.ExternalId, r.String()) + } + } + for _, r := range append(inAdds, outAdds...) { + err := self.region.CreateSecurityGroupRule(self.Id, r) + if err != nil { + return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String()) + } + } + return nil +} + +func (self *SRegion) DeleteSecurityGroup(id string) error { + return self.vpcDelete("security-groups/" + id) +} + +func (self *SRegion) DeleteSecurityGroupRule(ruleId string) error { + return self.vpcDelete("security-group-rules/" + ruleId) +} + +func (self *SRegion) CreateSecurityGroupRule(secGrpId string, rule cloudprovider.SecurityRule) error { + direction := "" + if rule.Direction == secrules.SecurityRuleIngress { + direction = "ingress" + } else { + direction = "egress" + } + + protocal := rule.Protocol + if rule.Protocol == secrules.PROTO_ANY { + protocal = "" + } + + // imcp协议默认为any + if rule.Protocol == secrules.PROTO_ICMP { + return self.AddSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String()) + } + + if len(rule.Ports) > 0 { + for _, port := range rule.Ports { + portStr := fmt.Sprintf("%d", port) + err := self.AddSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String()) + if err != nil { + return err + } + } + } else { + portStart := fmt.Sprintf("%d", rule.PortStart) + portEnd := fmt.Sprintf("%d", rule.PortEnd) + err := self.AddSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String()) + if err != nil { + return err + } + } + return nil +} + +func (self *SRegion) AddSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error { + rule := map[string]interface{}{ + "security_group_id": secGrpId, + "direction": direction, + "remote_ip_prefix": ipNet, + "ethertype": "IPV4", + } + if len(portStart) > 0 && portStart != "0" && portStart != "-1" { + rule["port_range_min"] = portStart + } + if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" { + rule["port_range_max"] = portEnd + } + if len(protocol) > 0 { + rule["protocol"] = protocol + } + params := map[string]interface{}{ + "security_group_rule": rule, + } + return self.vpcCreate("security-group-rules", params, nil) +} + +func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (*SSecurityGroup, error) { + params := map[string]interface{}{ + "security_group": map[string]interface{}{ + "name": name, + "vpc_id": vpcId, + }, + } + ret := &SSecurityGroup{region: self} + return ret, self.vpcCreate("security-groups", params, ret) +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return self.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return self.GetSecurityGroupDetails(secgroupId) +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := self.GetSecurityGroups(opts.VpcId) + if err != nil { + return nil, err + } + for i := range secgroups { + if secgroups[i].GetName() == opts.Name { + secgroups[i].region = self + return &secgroups[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "vpc:%s, name:%s", opts.VpcId, opts.Name) +} diff --git a/pkg/multicloud/hcs/signer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/signer.go similarity index 100% rename from pkg/multicloud/hcs/signer.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/signer.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/snapshot.go new file mode 100644 index 0000000000..a27a209fac --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/snapshot.go @@ -0,0 +1,192 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +/* +限制: +https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html +1. 从快照创建云硬盘时,volume_type字段必须和快照源云硬盘保持一致。 +2. 当指定的云硬盘类型在avaliability_zone内不存在时,则创建云硬盘失败。 +*/ + +type SnapshotStatusType string + +const ( + SnapshotStatusCreating SnapshotStatusType = "creating" + SnapshotStatusAvailable SnapshotStatusType = "available" // 云硬盘快照创建成功,可以使用。 + SnapshotStatusError SnapshotStatusType = "error" // 云硬盘快照在创建过程中出现错误。 + SnapshotStatusDeleting SnapshotStatusType = "deleting" // 云硬盘快照处于正在删除的过程中。 + SnapshotStatusErrorDeleting SnapshotStatusType = "error_deleting" // 云硬盘快照在删除过程中出现错误 + SnapshotStatusRollbacking SnapshotStatusType = "rollbacking" // 云硬盘快照处于正在回滚数据的过程中。 + SnapshotStatusBackingUp SnapshotStatusType = "backing-up" // 通过快照创建备份,快照状态就会变为backing-up +) + +type Metadata struct { + SystemEnableActive string `json:"__system__enableActive"` // 如果为true。则表明是系统盘快照 +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html +type SSnapshot struct { + multicloud.SResourceBase + HcsTags + region *SRegion + + Metadata Metadata `json:"metadata"` + CreatedAt string `json:"created_at"` + Description string `json:"description"` + Id string `json:"id"` + Name string `json:"name"` + OSExtendedSnapshotAttributesProgress string `json:"os-extended-snapshot-attributes:progress"` + OSExtendedSnapshotAttributesProjectId string `json:"os-extended-snapshot-attributes:project_id"` + Size int32 `json:"size"` // GB + Status string `json:"status"` + UpdatedAt string `json:"updated_at"` + VolumeId string `json:"volume_id"` +} + +func (self *SSnapshot) GetId() string { + return self.Id +} + +func (self *SSnapshot) GetName() string { + return self.Name +} + +func (self *SSnapshot) GetGlobalId() string { + return self.Id +} + +func (self *SSnapshot) GetStatus() string { + switch SnapshotStatusType(self.Status) { + case SnapshotStatusAvailable: + return api.SNAPSHOT_READY + case SnapshotStatusCreating: + return api.SNAPSHOT_CREATING + case SnapshotStatusDeleting: + return api.SNAPSHOT_DELETING + case SnapshotStatusErrorDeleting, SnapshotStatusError: + return api.SNAPSHOT_FAILED + case SnapshotStatusRollbacking: + return api.SNAPSHOT_ROLLBACKING + default: + return api.SNAPSHOT_UNKNOWN + } +} + +func (self *SSnapshot) Refresh() error { + ret, err := self.region.GetSnapshot(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, ret) +} + +func (self *SSnapshot) GetSizeMb() int32 { + return self.Size * 1024 +} + +func (self *SSnapshot) GetDiskId() string { + return self.VolumeId +} + +func (self *SSnapshot) GetDiskType() string { + if self.Metadata.SystemEnableActive == "true" { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +func (self *SSnapshot) Delete() error { + return self.region.DeleteSnapshot(self.Id) +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408627.html +func (self *SRegion) GetSnapshots(diskId string, name string) ([]SSnapshot, error) { + params := url.Values{} + if len(diskId) > 0 { + params.Set("volume_id", diskId) + } + + if len(name) > 0 { + params.Set("name", name) + } + ret := []SSnapshot{} + return ret, self.evsList("snapshots", params, &ret) +} + +func (self *SRegion) GetSnapshot(id string) (*SSnapshot, error) { + ret := &SSnapshot{region: self} + res := fmt.Sprintf("snapshots/%s", id) + return ret, self.evsGet(res, ret) +} + +// 不能删除以autobk_snapshot_为前缀的快照。 +// 当快照状态为available、error状态时,才可以删除。 +func (self *SRegion) DeleteSnapshot(id string) error { + res := fmt.Sprintf("snapshots/%s", id) + return self.evsDelete(res) +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html +// 目前已设置force字段。云硬盘处于挂载状态时,能强制创建快照。 +func (self *SRegion) CreateSnapshot(diskId, name, desc string) (*SSnapshot, error) { + params := map[string]interface{}{ + "snapshot": map[string]interface{}{ + "name": name, + "description": desc, + "volume_id": diskId, + "force": true, + }, + } + ret := &SSnapshot{region: self} + return ret, self.evsCreate("snapshots", params, ret) +} + +func (self *SSnapshot) GetProjectId() string { + return "" +} + +func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := self.GetSnapshots("", "") + if err != nil { + return nil, errors.Wrapf(err, "GetSnapshots") + } + ret := []cloudprovider.ICloudSnapshot{} + for i := 0; i < len(snapshots); i += 1 { + snapshots[i].region = self + ret = append(ret, &snapshots[i]) + } + return ret, nil +} + +func (self *SRegion) GetISnapshotById(id string) (cloudprovider.ICloudSnapshot, error) { + ret, err := self.GetSnapshot(id) + if err != nil { + return nil, err + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/storage.go new file mode 100644 index 0000000000..fd4da2e332 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/storage.go @@ -0,0 +1,135 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SStorage struct { + multicloud.SStorageBase + huawei.HuaweiTags + + zone *SZone + storageType string // volume_type 目前支持“SSD”,“SAS”和“SATA”三种 +} + +func (self *SStorage) GetId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetName() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetGlobalId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + cache := &SStoragecache{region: self.zone.region} + return cache +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := self.zone.region.GetDisks(self.zone.GetId()) + if err != nil { + return nil, err + } + + // 按storage type 过滤出disk + filtedDisks := make([]SDisk, 0) + for i := range disks { + disk := disks[i] + if disk.VolumeType == self.storageType { + filtedDisks = append(filtedDisks, disk) + } + } + + idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) + for i := 0; i < len(filtedDisks); i += 1 { + filtedDisks[i].region = self.zone.region + idisks[i] = &filtedDisks[i] + } + return idisks, nil +} + +func (self *SStorage) GetStorageType() string { + return self.storageType +} + +func (self *SStorage) GetMediumType() string { + if self.storageType == api.STORAGE_HUAWEI_SSD { + return api.DISK_TYPE_SSD + } + return api.DISK_TYPE_ROTATE +} + +func (self *SStorage) GetCapacityMB() int64 { + return 0 // unlimited +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + return conf +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + disk, err := self.zone.region.CreateDisk(self.zone.GetId(), self.storageType, conf.Name, conf.SizeGb, "", conf.Desc, conf.ProjectId) + if err != nil { + return nil, errors.Wrapf(err, "CreateDisk") + } + return disk, nil +} + +func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disk, err := self.zone.region.GetDisk(id) + if err != nil { + return nil, err + } + return disk, nil +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/storagecache.go new file mode 100644 index 0000000000..34e13b255b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/storagecache.go @@ -0,0 +1,255 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "context" + "fmt" + "math" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/onecloud/pkg/util/qemuimg" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SStoragecache struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion +} + +func GetBucketName(regionId string, imageId string) string { + return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), imageId) +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) +} + +func (self *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) +} + +func (self *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetGlobalId()) +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + imagesSelf, err := self.region.GetImages("", ImageOwnerSelf, "", EnvFusionCompute) + if err != nil { + return nil, errors.Wrapf(err, "GetImages") + } + + ret := []cloudprovider.ICloudImage{} + for i := range imagesSelf { + imagesSelf[i].cache = self + ret = append(ret, &imagesSelf[i]) + } + return ret, nil +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + image, err := self.region.GetImage(extId) + if err != nil { + return nil, errors.Wrap(err, "self.region.GetImage") + } + image.cache = self + return image, nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +// 目前支持使用vhd、zvhd、vmdk、qcow2、raw、zvhd2、vhdx、qcow、vdi或qed格式镜像文件创建私有镜像。 +// 快速通道功能可快速完成镜像制作,但镜像文件需转换为raw或zvhd2格式并完成镜像优化。 +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0083905788.html +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.cache = self + iimage := make([]cloudprovider.ICloudImage, 1) + iimage[0] = image + 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) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return self.uploadImage(ctx, userCred, image, callback) +} + +func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + bucketName := GetBucketName(self.region.GetId(), image.ImageId) + + exist, _ := self.region.IBucketExist(bucketName) + if !exist { + err := self.region.CreateIBucket(bucketName, "", "") + if err != nil { + return "", errors.Wrap(err, "CreateIBucket") + } + } + defer self.region.DeleteIBucket(bucketName) + + // upload to huawei cloud + s := auth.GetAdminSession(ctx, options.Options.Region) + meta, reader, sizeByte, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) + if err != nil { + return "", errors.Wrap(err, "Images.Download") + } + log.Debugf("Images meta data %s", meta) + + minDiskMB, _ := meta.Int("min_disk") + minDiskGB := int64(math.Ceil(float64(minDiskMB) / 1024)) + // 在使用OBS桶的外部镜像文件制作镜像时生效且为必选字段。取值为40~1024GB。 + if minDiskGB < 40 { + minDiskGB = 40 + } else if minDiskGB > 1024 { + minDiskGB = 1024 + } + + bucket, err := self.region.GetIBucketByName(bucketName) + if err != nil { + return "", errors.Wrapf(err, "GetIBucketByName %s", bucketName) + } + + body := multicloud.NewProgress(sizeByte, 95, reader, callback) + err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeByte, "", "", nil, false) + if err != nil { + return "", errors.Wrap(err, "cloudprovider.UploadObject") + } + + defer bucket.DeleteObject(context.Background(), image.ImageId) + + // check image name, avoid name conflict + imageBaseName := image.ImageId + if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { + imageBaseName = fmt.Sprintf("img%s", image.ImageId) + } + imageName := imageBaseName + nameIdx := 1 + + for { + _, err = self.region.GetImageByName(imageName) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + break + } else { + return "", err + } + } + + imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) + nameIdx += 1 + log.Debugf("uploadImage Match remote name %s", imageName) + } + + err = self.region.ImportImageJob(imageName, image.OsDistribution, image.OsVersion, image.OsArch, bucketName, image.ImageId, int64(minDiskGB)) + if err != nil { + return "", errors.Wrapf(err, "ImportImageJob") + } + + if callback != nil { + callback(100) + } + return "", cloudprovider.ErrNotImplemented +} + +func (self *SRegion) getStoragecache() *SStoragecache { + return &SStoragecache{region: self} +} + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html +func (self *SRegion) createIImage(snapshotId, imageName, imageDesc string) (string, error) { + snapshot, err := self.GetSnapshot(snapshotId) + if err != nil { + return "", err + } + + disk, err := self.GetDisk(snapshot.VolumeId) + if err != nil { + return "", err + } + + if disk.GetDiskType() != api.DISK_TYPE_SYS { + return "", fmt.Errorf("disk type err, expected disk type %s", api.DISK_TYPE_SYS) + } + + if len(disk.Attachments) == 0 { + return "", fmt.Errorf("disk is not attached.") + } + + params := map[string]interface{}{ + "name": imageName, + "description": imageDesc, + "instance_id": disk.Attachments[0].ServerId, + } + + ret := struct { + ImageId string + }{} + err = self.imsPerform("cloudimages", "action", params, &ret) + if err != nil { + return "", err + } + return ret.ImageId, nil +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + return []cloudprovider.ICloudStoragecache{storageCache}, nil +} + +func (self *SRegion) GetIStoragecacheById(idstr string) (cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + if storageCache.GetGlobalId() == idstr { + return storageCache, nil + } + return nil, cloudprovider.ErrNotFound +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/tag_base.go new file mode 100644 index 0000000000..6b64dfa252 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/tag_base.go @@ -0,0 +1,46 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type HcsTags struct { + Tags []string +} + +func (self *HcsTags) GetTags() (map[string]string, error) { + tags := map[string]string{} + for _, kv := range self.Tags { + splited := strings.Split(kv, "=") + if len(splited) == 2 { + tags[splited[0]] = splited[1] + } + } + return tags, nil +} + +func (self *HcsTags) GetSysTags() map[string]string { + return nil +} + +func (self *HcsTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/vpc.go new file mode 100644 index 0000000000..4a684d8606 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/vpc.go @@ -0,0 +1,312 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + HcsTags + + region *SRegion + + Id string + Name string + CIDR string + Status string + EnterpriseProjectId string +} + +func (self *SRegion) GetVpcs() ([]SVpc, error) { + ret := []SVpc{} + return ret, self.vpcList("vpcs", nil, &ret) +} + +func (self *SVpc) GetId() string { + return self.Id +} + +func (self *SVpc) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.Id +} + +func (self *SVpc) GetGlobalId() string { + return self.Id +} + +func (self *SVpc) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} + +func (self *SVpc) Refresh() error { + ret, err := self.region.GetVpc(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, ret) +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetIsDefault() bool { + return false +} + +func (self *SVpc) GetCidrBlock() string { + return self.CIDR +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + wire := &SWire{region: self.region, vpc: self} + return []cloudprovider.ICloudWire{wire}, nil +} + +func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { + wires, err := self.GetIWires() + if err != nil { + return nil, err + } + for i := range wires { + if wires[i].GetGlobalId() == id { + return wires[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := self.region.GetSecurityGroups(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudSecurityGroup{} + for i := range secgroups { + secgroups[i].region = self.region + ret = append(ret, &secgroups[i]) + } + return ret, nil +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + rtbs, err := self.region.GetRouteTables(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudRouteTable{} + for i := range rtbs { + rtbs[i].vpc = self + ret = append(ret, &rtbs[i]) + } + return ret, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + rtb, err := self.region.GetRouteTable(routeTableId) + if err != nil { + return nil, err + } + rtb.vpc = self + return rtb, nil +} + +func (self *SVpc) Delete() error { + return self.region.DeleteVpc(self.GetId()) +} + +func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { + nats, err := self.region.GetNatGateways(self.GetId()) + if err != nil { + return nil, err + } + ret := make([]cloudprovider.ICloudNatGateway, len(nats)) + for i := 0; i < len(nats); i++ { + nats[i].region = self.region + ret[i] = &nats[i] + } + return ret, nil +} + +func (self *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPCs, err := self.getVpcPeeringConnections() + if err != nil { + return nil, errors.Wrap(err, "self.getVpcPeeringConnections()") + } + ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} + for i := range svpcPCs { + ivpcPCs = append(ivpcPCs, &svpcPCs[i]) + } + return ivpcPCs, nil +} + +func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPCs, err := self.getAccepterVpcPeeringConnections() + if err != nil { + return nil, errors.Wrap(err, "self.getAccepterVpcPeeringConnections()") + } + ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} + for i := range svpcPCs { + ivpcPCs = append(ivpcPCs, &svpcPCs[i]) + } + return ivpcPCs, nil +} + +func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPC, err := self.getVpcPeeringConnectionById(id) + if err != nil { + return nil, errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) + } + return svpcPC, nil +} + +func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPC, err := self.region.CreateVpcPeering(self.GetId(), opts) + if err != nil { + return nil, errors.Wrapf(err, "self.region.CreateVpcPeering(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) + } + svpcPC.vpc = self + return svpcPC, nil +} + +func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { + vpcPC, err := self.getVpcPeeringConnectionById(id) + if err != nil { + return errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) + } + if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_ACTIVE { + return nil + } + if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN { + return errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcPC: %s", jsonutils.Marshal(vpcPC).String()) + } + err = self.region.AcceptVpcPeering(id) + if err != nil { + return errors.Wrapf(err, "self.region.AcceptVpcPeering(%s)", id) + } + return nil +} + +func (self *SVpc) GetAuthorityOwnerId() string { + return self.region.client.projectId +} + +func (self *SRegion) GetVpc(id string) (*SVpc, error) { + vpc := &SVpc{region: self} + res := fmt.Sprintf("vpcs/%s", id) + return vpc, self.vpcGet(res, vpc) +} + +func (self *SRegion) DeleteVpc(id string) error { + if id != "default" { + secgroups, err := self.GetSecurityGroups(id) + if err != nil { + return errors.Wrap(err, "GetSecurityGroups") + } + for _, secgroup := range secgroups { + err = self.DeleteSecurityGroup(secgroup.Id) + if err != nil { + return errors.Wrapf(err, "DeleteSecurityGroup(%s)", secgroup.Id) + } + } + } + res := fmt.Sprintf("vpcs/%s", id) + return self.vpcDelete(res) +} + +func (self *SRegion) CreateVpc(name, cidr, desc string) (*SVpc, error) { + params := map[string]interface{}{ + "vpc": map[string]string{ + "name": name, + "cidr": cidr, + "description": desc, + }, + } + vpc := &SVpc{region: self} + return vpc, self.vpcCreate("vpcs", params, vpc) +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + vpcs, err := self.GetVpcs() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudVpc{} + for i := range vpcs { + vpcs[i].region = self + ret = append(ret, &vpcs[i]) + } + return ret, nil +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + vpc, err := self.GetVpc(id) + if err != nil { + return nil, err + } + vpc.region = self + return vpc, nil +} + +func (self *SVpc) getVpcPeeringConnections() ([]SVpcPeering, error) { + svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) + } + vpcPCs := []SVpcPeering{} + for i := range svpcPeerings { + if svpcPeerings[i].GetVpcId() == self.GetId() { + svpcPeerings[i].vpc = self + vpcPCs = append(vpcPCs, svpcPeerings[i]) + } + } + return vpcPCs, nil +} + +func (self *SVpc) getAccepterVpcPeeringConnections() ([]SVpcPeering, error) { + svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) + } + vpcPCs := []SVpcPeering{} + for i := range svpcPeerings { + if svpcPeerings[i].GetPeerVpcId() == self.GetId() { + svpcPeerings[i].vpc = self + vpcPCs = append(vpcPCs, svpcPeerings[i]) + } + } + return vpcPCs, nil +} + +func (self *SVpc) getVpcPeeringConnectionById(id string) (*SVpcPeering, error) { + svpcPC, err := self.region.GetVpcPeering(id) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetVpcPeering(%s)", id) + } + svpcPC.vpc = self + return svpcPC, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/vpc_peering.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/vpc_peering.go new file mode 100644 index 0000000000..25c7f850a1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/vpc_peering.go @@ -0,0 +1,144 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type RequestVpcInfo struct { + VpcId string `json:"vpc_id"` + TenantId string `json:"tenant_id"` +} + +type AcceptVpcInfo struct { + VpcId string `json:"vpc_id"` + TenantId string `json:"tenant_id"` +} + +type SVpcPeering struct { + multicloud.SResourceBase + huawei.HuaweiTags + vpc *SVpc + + RequestVpcInfo RequestVpcInfo `json:"request_vpc_info"` + AcceptVpcInfo AcceptVpcInfo `json:"accept_vpc_info"` + Name string `json:"name"` + Id string `json:"id"` + Status string `json:"status"` +} + +func (self *SRegion) GetVpcPeerings(vpcId string) ([]SVpcPeering, error) { + params := url.Values{} + if len(vpcId) > 0 { + params.Set("vpc_id", vpcId) + } + ret := []SVpcPeering{} + return ret, self.list("vpc", "v2.0", "vpc/peerings", params, &ret) +} + +func (self *SRegion) GetVpcPeering(id string) (*SVpcPeering, error) { + ret := SVpcPeering{} + resource := fmt.Sprintf("vpc/peerings/%s", id) + return &ret, self.get("vpc", "v2.0", resource, &ret) +} + +func (self *SRegion) CreateVpcPeering(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPeering, error) { + params := map[string]interface{}{ + "peering": map[string]interface{}{ + "name": opts.Name, + "request_vpc_info": map[string]interface{}{ + "vpc_id": vpcId, + "tenant_id": self.client.projectId, + }, + "accept_vpc_info": map[string]interface{}{ + "vpc_id": opts.PeerVpcId, + "tenant_id": opts.PeerAccountId, + }, + }, + } + ret := &SVpcPeering{} + return ret, self.create("vpc", "v2.0", "vpc/peerings", params, ret) +} + +func (self *SRegion) AcceptVpcPeering(id string) error { + res := fmt.Sprintf("vpc/peerings/%s/accept", id) + return self.update("vpc", "v2.0", res, nil) +} + +func (self *SRegion) DeleteVpcPeering(id string) error { + res := fmt.Sprintf("vpc/peerings/%s", id) + return self.delete("vpc", "v2.0", res) +} + +func (self *SVpcPeering) GetId() string { + return self.Id +} + +func (self *SVpcPeering) GetName() string { + return self.Name +} + +func (self *SVpcPeering) GetGlobalId() string { + return self.GetId() +} + +func (self *SVpcPeering) GetStatus() string { + switch self.Status { + case "PENDING_ACCEPTANCE": + return api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT + case "ACTIVE": + return api.VPC_PEERING_CONNECTION_STATUS_ACTIVE + default: + return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN + } +} + +func (self *SVpcPeering) Refresh() error { + peer, err := self.vpc.region.GetVpcPeering(self.Id) + if err != nil { + return errors.Wrapf(err, "self.region.GetVpcPeering(%s)", self.Id) + } + return jsonutils.Update(self, peer) +} + +func (self *SVpcPeering) GetVpcId() string { + return self.RequestVpcInfo.VpcId +} + +func (self *SVpcPeering) GetPeerVpcId() string { + return self.AcceptVpcInfo.VpcId +} + +func (self *SVpcPeering) GetPeerAccountId() string { + return self.AcceptVpcInfo.TenantId +} + +func (self *SVpcPeering) GetEnabled() bool { + return true +} + +func (self *SVpcPeering) Delete() error { + return self.vpc.region.DeleteVpcPeering(self.Id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/wire.go new file mode 100644 index 0000000000..b7ffe327ca --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/wire.go @@ -0,0 +1,127 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// 华为云的子网有点特殊。子网在整个region可用。 +type SWire struct { + multicloud.SResourceBase + HcsTags + region *SRegion + vpc *SVpc +} + +func (self *SWire) GetId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) +} + +func (self *SWire) GetName() string { + return self.GetId() +} + +func (self *SWire) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return nil +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + nets, err := self.region.GetNetwroks(self.vpc.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNetwork{} + for i := range nets { + nets[i].wire = self + ret = append(ret, &nets[i]) + } + return ret, nil +} + +func (self *SWire) GetBandwidth() int { + return 10000 +} + +func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { + net, err := self.region.GetNetwork(id) + if err != nil { + return nil, err + } + net.wire = self + return net, nil +} + +/* +华为云子网可用区,类似一个zone标签。即使指定了zone子网在整个region依然是可用。 +通过华为web控制台创建子网需要指定可用区。这里是不指定的。 +*/ +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + net, err := self.region.CreateNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc) + if err != nil { + return nil, errors.Wrapf(err, "CreateNetwork") + } + net.wire = self + return net, nil +} + +func getDefaultGateWay(cidr string) (string, error) { + pref, err := netutils.NewIPV4Prefix(cidr) + if err != nil { + return "", errors.Wrap(err, "getDefaultGateWay.NewIPV4Prefix") + } + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String(), nil +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html +// cidr 掩码长度不能大于28 +func (self *SRegion) CreateNetwork(vpcId string, name string, cidr string, desc string) (*SNetwork, error) { + gateway, err := getDefaultGateWay(cidr) + if err != nil { + return nil, err + } + + params := map[string]interface{}{ + "subnet": map[string]interface{}{ + "name": name, + "vpc_id": vpcId, + "cidr": cidr, + "gateway_ip": gateway, + }, + } + ret := &SNetwork{} + return ret, self.vpcCreate("subnets", params, ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/zone.go new file mode 100644 index 0000000000..a04c4c0700 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcs/zone.go @@ -0,0 +1,230 @@ +// Copyright 2019 Yunion +// +// 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 hcs + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SZone struct { + multicloud.SResourceBase + HcsTags + + region *SRegion + ZoneName string + ZoneState struct { + Available bool + } +} + +func (self *SRegion) GetZones() ([]SZone, error) { + zones := []SZone{} + return zones, self.ecsList("os-availability-zone", nil, &zones) +} + +func (self *SZone) getStorageType() ([]string, error) { + return self.region.GetZoneSupportedDiskTypes(self.GetId()) +} + +func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) { + dts, err := self.GetDiskTypes() + if err != nil { + return nil, errors.Wrap(err, "GetDiskTypes") + } + + ret := []string{} + for i := range dts { + if dts[i].IsAvaliableInZone(zoneId) { + ret = append(ret, dts[i].Name) + } + } + return ret, nil +} + +func (self *SZone) GetId() string { + return self.ZoneName +} + +func (self *SZone) GetName() string { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HCS_CN, self.ZoneName) +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HCS_EN, self.ZoneName) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneName) +} + +func (self *SZone) GetStatus() string { + return api.ZONE_ENABLE +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + host := &SHost{zone: self} + return []cloudprovider.ICloudHost{host}, nil +} + +func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + host := &SHost{zone: self} + if host.GetGlobalId() == id { + return host, nil + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.getStorageType() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + ret = append(ret, &SStorage{zone: self, storageType: storages[i]}) + } + return ret, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storages, err := self.GetIStorages() + if err != nil { + return nil, err + } + for i := 0; i < len(storages); i += 1 { + if storages[i].GetGlobalId() == id { + return storages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { + vpcs, err := self.region.GetVpcs() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudWire{} + for i := range vpcs { + wire := &SWire{region: self.region, vpc: &vpcs[i]} + ret = append(ret, wire) + } + return ret, nil +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + zones, err := self.GetZones() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudZone{} + for i := 0; i < len(zones); i++ { + zones[i].region = self + ret = append(ret, &zones[i]) + } + if len(zones) == 0 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "no availabe zone found") + } + return ret, nil +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + if izones[i].GetGlobalId() == id { + return izones[i], 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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetZoneById(id string) (*SZone, error) { + zones, err := self.GetZones() + if err != nil { + return nil, err + } + for i := 0; i < len(zones); i += 1 { + zones[i].region = self + if zones[i].GetId() == id || zones[i].GetGlobalId() == id { + return &zones[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/bucket.go new file mode 100644 index 0000000000..93e6495f9d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/bucket.go @@ -0,0 +1,775 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + "yunion.io/x/s3cli" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" +) + +type SBucket struct { + multicloud.SBaseBucket + huawei.HuaweiTags + + region *SRegion + + Name string + Location string + CreationDate time.Time +} + +func (b *SBucket) GetProjectId() string { + resp, err := b.region.HeadBucket(b.Name) + if err != nil { + return "" + } + epid, _ := resp.ResponseHeaders["epid"] + if len(epid) > 0 { + return epid[0] + } + return "" +} + +func (b *SBucket) GetGlobalId() string { + return b.Name +} + +func (b *SBucket) GetName() string { + return b.Name +} + +func (b *SBucket) GetLocation() string { + return b.Location +} + +func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { + return b.region +} + +func (b *SBucket) GetCreatedAt() time.Time { + return b.CreationDate +} + +/* + service returned error: Status=405 Method Not Allowed, Code=MethodNotAllowed, + Message=The specified method is not allowed against this resource., + RequestId=00000175B0E9D138440B9EF092DF8A7A + +https://support.huaweicloud.com/productdesc-modelarts/modelarts_01_0017.html +*/ +func (b *SBucket) GetStorageClass() string { + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("b.region.getOBSClient error %s", err) + return "" + } + output, err := obscli.GetBucketStoragePolicy(b.Name) + if err != nil { + log.Errorf("obscli.GetBucketStoragePolicy error %s", err) + return "" + } + return output.StorageClass +} + +func obsAcl2CannedAcl(acls []obs.Grant) cloudprovider.TBucketACLType { + switch { + case len(acls) == 1: + if acls[0].Grantee.URI == "" && acls[0].Permission == s3cli.PERMISSION_FULL_CONTROL { + return cloudprovider.ACLPrivate + } + case len(acls) == 2: + for _, g := range acls { + if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_AUTH_USERS && g.Permission == s3cli.PERMISSION_READ { + return cloudprovider.ACLAuthRead + } + if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_READ { + return cloudprovider.ACLPublicRead + } + } + case len(acls) == 3: + for _, g := range acls { + if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_WRITE { + return cloudprovider.ACLPublicReadWrite + } + } + } + return cloudprovider.ACLUnknown +} + +func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("b.region.getOBSClient error %s", err) + return acl + } + output, err := obscli.GetBucketAcl(b.Name) + if err != nil { + log.Errorf("obscli.GetBucketAcl error %s", err) + return acl + } + acl = obsAcl2CannedAcl(output.Grants) + return acl +} + +func (b *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "b.region.getOBSClient") + } + input := &obs.SetBucketAclInput{} + input.Bucket = b.Name + input.ACL = obs.AclType(string(acl)) + _, err = obscli.SetBucketAcl(input) + if err != nil { + return errors.Wrap(err, "obscli.SetBucketAcl") + } + return nil +} + +func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { + return []cloudprovider.SBucketAccessUrl{ + { + Url: fmt.Sprintf("https://%s.%s", b.Name, b.region.getOBSEndpoint()), + Description: "bucket url", + Primary: true, + }, + { + Url: fmt.Sprintf("https://%s/%s", b.region.getOBSEndpoint(), b.Name), + Description: "obs url", + }, + } +} + +func (b *SBucket) GetStats() cloudprovider.SBucketStats { + stats := cloudprovider.SBucketStats{} + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("b.region.getOBSClient error %s", err) + stats.SizeBytes = -1 + stats.ObjectCount = -1 + return stats + } + output, err := obscli.GetBucketStorageInfo(b.Name) + if err != nil { + log.Errorf("obscli.GetBucketStorageInfo error %s", err) + stats.SizeBytes = -1 + stats.ObjectCount = -1 + return stats + } + stats.SizeBytes = output.Size + stats.ObjectCount = output.ObjectNumber + return stats +} + +func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { + result := cloudprovider.SListObjectResult{} + obscli, err := b.region.getOBSClient() + if err != nil { + return result, errors.Wrap(err, "GetOBSClient") + } + input := &obs.ListObjectsInput{} + input.Bucket = b.Name + if len(prefix) > 0 { + input.Prefix = prefix + } + if len(marker) > 0 { + input.Marker = marker + } + if len(delimiter) > 0 { + input.Delimiter = delimiter + } + if maxCount > 0 { + input.MaxKeys = maxCount + } + oResult, err := obscli.ListObjects(input) + if err != nil { + return result, errors.Wrap(err, "ListObjects") + } + result.Objects = make([]cloudprovider.ICloudObject, 0) + for _, object := range oResult.Contents { + obj := &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + StorageClass: string(object.StorageClass), + Key: object.Key, + SizeBytes: object.Size, + ETag: object.ETag, + LastModified: object.LastModified, + }, + } + result.Objects = append(result.Objects, obj) + } + if oResult.CommonPrefixes != nil { + result.CommonPrefixes = make([]cloudprovider.ICloudObject, 0) + for _, commonPrefix := range oResult.CommonPrefixes { + obj := &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + Key: commonPrefix, + }, + } + result.CommonPrefixes = append(result.CommonPrefixes, obj) + } + } + result.IsTruncated = oResult.IsTruncated + result.NextMarker = oResult.NextMarker + return result, nil +} + +func (b *SBucket) PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.PutObjectInput{} + input.Bucket = b.Name + input.Key = key + input.Body = reader + + if sizeBytes > 0 { + input.ContentLength = sizeBytes + } + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return err + } + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.ACL = obs.AclType(string(cannedAcl)) + if meta != nil { + val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) + if len(val) > 0 { + input.ContentType = val + } + val = meta.Get(cloudprovider.META_HEADER_CONTENT_MD5) + if len(val) > 0 { + input.ContentMD5 = val + } + extraMeta := make(map[string]string) + for k, v := range meta { + if utils.IsInStringArray(k, []string{ + cloudprovider.META_HEADER_CONTENT_TYPE, + cloudprovider.META_HEADER_CONTENT_MD5, + }) { + continue + } + if len(v[0]) > 0 { + extraMeta[k] = v[0] + } + } + input.Metadata = extraMeta + } + _, err = obscli.PutObject(input) + if err != nil { + return errors.Wrap(err, "PutObject") + } + return nil +} + +func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + + input := &obs.InitiateMultipartUploadInput{} + input.Bucket = b.Name + input.Key = key + if meta != nil { + val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) + if len(val) > 0 { + input.ContentType = val + } + extraMeta := make(map[string]string) + for k, v := range meta { + if utils.IsInStringArray(k, []string{ + cloudprovider.META_HEADER_CONTENT_TYPE, + }) { + continue + } + if len(v[0]) > 0 { + extraMeta[k] = v[0] + } + } + input.Metadata = extraMeta + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.ACL = obs.AclType(string(cannedAcl)) + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return "", errors.Wrap(err, "str2StorageClass") + } + } + output, err := obscli.InitiateMultipartUpload(input) + if err != nil { + return "", errors.Wrap(err, "InitiateMultipartUpload") + } + + return output.UploadId, nil +} + +func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, part io.Reader, partSize int64, offset, totalSize int64) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + + input := &obs.UploadPartInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + input.PartNumber = partIndex + input.PartSize = partSize + input.Body = part + output, err := obscli.UploadPart(input) + if err != nil { + return "", errors.Wrap(err, "UploadPart") + } + + return output.ETag, nil +} + +func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.CompleteMultipartUploadInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + parts := make([]obs.Part, len(partEtags)) + for i := range partEtags { + parts[i] = obs.Part{ + PartNumber: i + 1, + ETag: partEtags[i], + } + } + input.Parts = parts + _, err = obscli.CompleteMultipartUpload(input) + if err != nil { + return errors.Wrap(err, "CompleteMultipartUpload") + } + + return nil +} + +func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + input := &obs.AbortMultipartUploadInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + + _, err = obscli.AbortMultipartUpload(input) + if err != nil { + return errors.Wrap(err, "AbortMultipartUpload") + } + + return nil +} + +func (b *SBucket) DeleteObject(ctx context.Context, key string) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.DeleteObjectInput{} + input.Bucket = b.Name + input.Key = key + _, err = obscli.DeleteObject(input) + if err != nil { + return errors.Wrap(err, "DeleteObject") + } + return nil +} + +func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + input := obs.CreateSignedUrlInput{} + input.Bucket = b.Name + input.Key = key + input.Expires = int(expire / time.Second) + switch method { + case "GET": + input.Method = obs.HttpMethodGet + case "PUT": + input.Method = obs.HttpMethodPut + case "DELETE": + input.Method = obs.HttpMethodDelete + default: + return "", errors.Error("unsupported method") + } + output, err := obscli.CreateSignedUrl(&input) + return output.SignedUrl, nil +} + +func (b *SBucket) LimitSupport() cloudprovider.SBucketStats { + return cloudprovider.SBucketStats{ + SizeBytes: 1, + ObjectCount: -1, + } +} + +func (b *SBucket) GetLimit() cloudprovider.SBucketStats { + stats := cloudprovider.SBucketStats{} + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("getOBSClient error %s", err) + return stats + } + output, err := obscli.GetBucketQuota(b.Name) + if err != nil { + return stats + } + stats.SizeBytes = output.Quota + return stats +} + +func (b *SBucket) SetLimit(limit cloudprovider.SBucketStats) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "getOBSClient") + } + input := &obs.SetBucketQuotaInput{} + input.Bucket = b.Name + input.Quota = limit.SizeBytes + _, err = obscli.SetBucketQuota(input) + if err != nil { + return errors.Wrap(err, "SetBucketQuota") + } + return nil +} + +func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.CopyObjectInput{} + input.Bucket = b.Name + input.Key = destKey + input.CopySourceBucket = srcBucket + input.CopySourceKey = srcKey + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return err + } + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.ACL = obs.AclType(string(cannedAcl)) + if meta != nil { + val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) + if len(val) > 0 { + input.ContentType = val + } + extraMeta := make(map[string]string) + for k, v := range meta { + if utils.IsInStringArray(k, []string{ + cloudprovider.META_HEADER_CONTENT_TYPE, + }) { + continue + } + if len(v[0]) > 0 { + extraMeta[k] = v[0] + } + } + input.Metadata = extraMeta + input.MetadataDirective = obs.ReplaceMetadata + } else { + input.MetadataDirective = obs.CopyMetadata + } + _, err = obscli.CopyObject(input) + if err != nil { + return errors.Wrap(err, "obscli.CopyObject") + } + return nil +} + +func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + input := &obs.GetObjectInput{} + input.Bucket = b.Name + input.Key = key + if rangeOpt != nil { + input.RangeStart = rangeOpt.Start + input.RangeEnd = rangeOpt.End + } + output, err := obscli.GetObject(input) + if err != nil { + return nil, errors.Wrap(err, "obscli.GetObject") + } + return output.Body, nil +} + +func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + input := &obs.CopyPartInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + input.PartNumber = partIndex + input.CopySourceBucket = srcBucket + input.CopySourceKey = srcKey + input.CopySourceRangeStart = srcOffset + input.CopySourceRangeEnd = srcOffset + srcLength - 1 + output, err := obscli.CopyPart(input) + if err != nil { + return "", errors.Wrap(err, "CopyPart") + } + return output.ETag, nil +} + +func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + obsWebConf := obs.SetBucketWebsiteConfigurationInput{} + obsWebConf.Bucket = b.Name + obsWebConf.BucketWebsiteConfiguration = obs.BucketWebsiteConfiguration{ + IndexDocument: obs.IndexDocument{Suffix: websitConf.Index}, + ErrorDocument: obs.ErrorDocument{Key: websitConf.ErrorDocument}, + } + _, err = obscli.SetBucketWebsiteConfiguration(&obsWebConf) + if err != nil { + return errors.Wrap(err, "obscli.SetBucketWebsiteConfiguration(&obsWebConf)") + } + return nil +} + +func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { + result := cloudprovider.SBucketWebsiteConf{} + obscli, err := b.region.getOBSClient() + if err != nil { + return result, errors.Wrap(err, "GetOBSClient") + } + out, err := obscli.GetBucketWebsiteConfiguration(b.Name) + if out == nil { + return result, nil + } + result.Index = out.IndexDocument.Suffix + result.ErrorDocument = out.ErrorDocument.Key + endpoint := b.region.client.endpoints.GetEndpoint(b.region.client.cpcfg.DefaultRegion, "obs-website", b.region.GetId()) + result.Url = fmt.Sprintf("https://%s.%s", b.Name, endpoint) + return result, nil +} + +func (b *SBucket) DeleteWebSiteConf() error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + _, err = obscli.DeleteBucketWebsiteConfiguration(b.Name) + if err != nil { + return errors.Wrapf(err, "obscli.DeleteBucketWebsiteConfiguration(%s)", b.Name) + } + return nil +} + +func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + opts := []obs.CorsRule{} + for i := range rules { + opts = append(opts, obs.CorsRule{ + AllowedOrigin: rules[i].AllowedOrigins, + AllowedMethod: rules[i].AllowedMethods, + AllowedHeader: rules[i].AllowedHeaders, + MaxAgeSeconds: rules[i].MaxAgeSeconds, + ExposeHeader: rules[i].ExposeHeaders, + }) + } + + input := obs.SetBucketCorsInput{} + input.Bucket = b.Name + input.BucketCors.CorsRules = opts + _, err = obscli.SetBucketCors(&input) + if err != nil { + return errors.Wrapf(err, "obscli.SetBucketCors(%s)", jsonutils.Marshal(input).String()) + } + return nil +} + +func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + conf, err := obscli.GetBucketCors(b.Name) + if err != nil { + if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") { + return nil, errors.Wrapf(err, "obscli.GetBucketCors(%s)", b.Name) + } + } + if conf == nil { + return nil, nil + } + result := []cloudprovider.SBucketCORSRule{} + for i := range conf.CorsRules { + result = append(result, cloudprovider.SBucketCORSRule{ + AllowedOrigins: conf.CorsRules[i].AllowedOrigin, + AllowedMethods: conf.CorsRules[i].AllowedMethod, + AllowedHeaders: conf.CorsRules[i].AllowedHeader, + MaxAgeSeconds: conf.CorsRules[i].MaxAgeSeconds, + ExposeHeaders: conf.CorsRules[i].ExposeHeader, + Id: strconv.Itoa(i), + }) + } + return result, nil +} + +func (b *SBucket) DeleteCORS() error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + _, err = obscli.DeleteBucketCors(b.Name) + if err != nil { + return errors.Wrapf(err, "obscli.DeleteBucketCors(%s)", b.Name) + } + return nil +} + +func (b *SBucket) GetTags() (map[string]string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + tagresult, err := obscli.GetBucketTagging(b.Name) + if err != nil { + if strings.Contains(err.Error(), "404") { + return nil, nil + } + return nil, errors.Wrapf(err, "osscli.GetBucketTagging(%s)", b.Name) + } + result := map[string]string{} + for i := range tagresult.Tags { + result[tagresult.Tags[i].Key] = tagresult.Tags[i].Value + } + return result, nil +} + +func (b *SBucket) SetTags(tags map[string]string, replace bool) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + _, err = obscli.DeleteBucketTagging(b.Name) + if err != nil { + return errors.Wrapf(err, "DeleteBucketTagging") + } + + if len(tags) == 0 { + return nil + } + + input := obs.SetBucketTaggingInput{BucketTagging: obs.BucketTagging{}} + input.Bucket = b.Name + for k, v := range tags { + input.BucketTagging.Tags = append(input.BucketTagging.Tags, obs.Tag{Key: k, Value: v}) + } + + _, err = obscli.SetBucketTagging(&input) + if err != nil { + return errors.Wrapf(err, "obscli.SetBucketTagging(%s)", jsonutils.Marshal(input).String()) + } + return nil +} + +func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + result := []cloudprovider.SBucketMultipartUploads{} + + input := obs.ListMultipartUploadsInput{Bucket: b.Name} + keyMarker := "" + uploadIDMarker := "" + for { + if len(keyMarker) > 0 { + input.KeyMarker = keyMarker + } + if len(uploadIDMarker) > 0 { + input.UploadIdMarker = uploadIDMarker + } + + output, err := obscli.ListMultipartUploads(&input) + if err != nil { + return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") + } + for i := range output.Uploads { + temp := cloudprovider.SBucketMultipartUploads{ + ObjectName: output.Uploads[i].Key, + UploadID: output.Uploads[i].UploadId, + Initiator: output.Uploads[i].Initiator.DisplayName, + Initiated: output.Uploads[i].Initiated, + } + result = append(result, temp) + } + keyMarker = output.NextKeyMarker + uploadIDMarker = output.NextUploadIdMarker + if !output.IsTruncated { + break + } + } + + return result, nil +} diff --git a/pkg/multicloud/hcso/client/auth/credential.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credential.go similarity index 100% rename from pkg/multicloud/hcso/client/auth/credential.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credential.go diff --git a/pkg/multicloud/hcso/client/auth/credentials/access_key_credential.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials/access_key_credential.go similarity index 100% rename from pkg/multicloud/hcso/client/auth/credentials/access_key_credential.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials/access_key_credential.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials/doc.go new file mode 100644 index 0000000000..5febbeba20 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 credentials // import "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/doc.go new file mode 100644 index 0000000000..1dc9a5656e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 auth // import "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signer.go new file mode 100644 index 0000000000..1e66b0c2f3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signer.go @@ -0,0 +1,214 @@ +// Copyright 2019 Yunion +// +// 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 auth + +import ( + "crypto/md5" + "crypto/sha256" + "encoding/hex" + "fmt" + "io/ioutil" + "sort" + "strings" + "time" + + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signers" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests" +) + +type Signer interface { + GetName() string // 签名算法名称 + GetAccessKeyId() (accessKeyId string, err error) // 签名access key + GetSecretKey() (secretKey string, err error) // access secret + Sign(stringToSign, secretSuffix string) string // 生成签名结果 +} + +func NewSignerWithCredential(credential Credential) (signer Signer, err error) { + switch instance := credential.(type) { + case *credentials.AccessKeyCredential: + return signers.NewAccessKeySigner(instance), nil + default: + return nil, fmt.Errorf("unsupported credential error") + } +} + +// 对request进行签名 +func Sign(request requests.IRequest, signer Signer) (err error) { + return signRequest(request, signer) +} + +func signRequest(request requests.IRequest, signer Signer) error { + // https://support.huaweicloud.com/api-dis/dis_02_0508.html + // requestTime + reqTime := time.Now() + // 添加 必须的Headers + fillRequiredHeaders(request, reqTime) + // 计算CanonicalRequest + canonicalRequest := canonicalRequest(request) + // stringToSign + credentialScope := strings.Join([]string{ + formattedSignTime(reqTime, "Date"), + request.GetRegionId(), + request.GetProduct(), + "sdk_request", + }, "/") + stringToSign := strings.Join([]string{"SDK-HMAC-SHA256", + formattedSignTime(reqTime, "DateTime"), + credentialScope, + hashSha256([]byte(canonicalRequest)), + }, "\n") + // 计算SigningKey + secret, _ := signer.GetSecretKey() + signKey := getSigningKey(secret, formattedSignTime(reqTime, "Date"), + request.GetRegionId(), request.GetProduct()) + // 计算Signature + signature := signer.Sign(stringToSign, signKey) + accesskey, _ := signer.GetAccessKeyId() + addAuthorizationHeader(request, accesskey, credentialScope, signature) + return nil +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0132456728.html +// X-Project-Id 如果是专属云场景采用AK/SK 认证方式的接口请求或者多project场景采用AK/SK认证的接口请求则该字段必选。 +func fillRequiredHeaders(request requests.IRequest, t time.Time) { + request.AddHeaderParam("HOST", request.GetHost()) + request.AddHeaderParam("X-Sdk-Date", formattedSignTime(t, "DateTime")) + if len(request.GetProjectId()) > 0 { + request.AddHeaderParam("X-Project-Id", request.GetProjectId()) + } + return +} + +func buildRequestStringToSign(request requests.IRequest) string { + return "" +} + +func formattedSignTime(t time.Time, format string) string { + switch format { + case "Date": + return t.UTC().Format("20060102") + case "DateTime": + return t.UTC().Format("20060102T150405Z") + default: + return t.UTC().Format("20060102T150405Z") + } +} + +func contentSha256(request requests.IRequest) string { + method := strings.ToUpper(request.GetMethod()) + content := []byte{} + body := request.GetBodyReader() + content, _ = ioutil.ReadAll(body) + if method == "POST" { + if len(content) == 0 { + // other http method use query as content + content = []byte(request.BuildQueries()) + } + } + + return hashSha256(content) +} + +func hashSha256(msg []byte) string { + sh256 := sha256.New() + sh256.Write(msg) + + return hex.EncodeToString(sh256.Sum(nil)) +} + +func canonicalRequest(request requests.IRequest) string { + sha256 := contentSha256(request) + uri := request.GetURI() + if !strings.HasSuffix(uri, "/") { + uri = uri + "/" + } + + return strings.Join([]string{ + request.GetMethod(), + uri, + canonicalQueryString(request), + canonicalHeaders(request), + canonicalHeaderNames(request), + sha256, + }, "\n") +} + +func sortedHeaderNames(request requests.IRequest) []string { + headers := request.GetHeaders() + keys := make([]string, 0) + for k := range headers { + keys = append(keys, k) + } + + sort.Slice(keys, func(i, j int) bool { + return strings.ToLower(keys[i]) < strings.ToLower(keys[j]) + }) + + return keys +} + +func canonicalQueryString(request requests.IRequest) string { + if strings.ToUpper(request.GetMethod()) != "POST" { + return request.BuildQueries() + } + + return "" +} + +func canonicalHeaders(request requests.IRequest) string { + keys := sortedHeaderNames(request) + headers := request.GetHeaders() + ret := []string{} + for _, k := range keys { + ret = append(ret, strings.ToLower(k)+":"+strings.TrimSpace(headers[k])) + } + + return strings.Join(ret, "\n") + "\n" +} + +func canonicalHeaderNames(request requests.IRequest) string { + keys := sortedHeaderNames(request) + ret := strings.Join(keys, ";") + return strings.ToLower(ret) +} + +var SigningKeyCache = map[string][]byte{} + +func getSigningKey(secretKey, date, regionId, service string) string { + joinedKey := strings.Join([]string{secretKey, date, regionId, service}, "") + cacheKey := fmt.Sprintf("%x", md5.Sum([]byte(joinedKey))) + if v, ok := SigningKeyCache[cacheKey]; ok { + return string(v) + } + + ret := []byte("SDK" + secretKey) + for _, k := range []string{date, regionId, service, "sdk_request"} { + ret = signers.HmacSha256(k, ret) + } + + SigningKeyCache[cacheKey] = ret + return string(ret) +} + +func addAuthorizationHeader(request requests.IRequest, accessKey, credentialScope, signature string) { + auth := "SDK-HMAC-SHA256" + " " + strings.Join([]string{ + "Credential=" + accessKey + "/" + credentialScope, + "SignedHeaders=" + canonicalHeaderNames(request), + "Signature=" + signature, + }, ", ") + + request.AddHeaderParam("Authorization", auth) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signers/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signers/doc.go new file mode 100644 index 0000000000..357add8d51 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signers/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 signers // import "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signers" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signers/signer_access_key.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signers/signer_access_key.go new file mode 100644 index 0000000000..f4cd406252 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/signers/signer_access_key.go @@ -0,0 +1,55 @@ +// Copyright 2019 Yunion +// +// 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 signers + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials" +) + +type AccessKeySigner struct { + credential *credentials.AccessKeyCredential +} + +func (signer *AccessKeySigner) GetName() string { + return "HmacSha256" +} + +func (signer *AccessKeySigner) GetAccessKeyId() (accessKeyId string, err error) { + return signer.credential.AccessKeyId, nil +} + +func (signer *AccessKeySigner) GetSecretKey() (secretKey string, err error) { + return signer.credential.AccessKeySecret, nil +} + +func (signer *AccessKeySigner) Sign(stringToSign, secretSuffix string) string { + return hex.EncodeToString(HmacSha256(stringToSign, []byte(secretSuffix))) +} + +func HmacSha256(data string, key []byte) []byte { + mac := hmac.New(sha256.New, key) + mac.Write([]byte(data)) + return mac.Sum(nil) +} + +func NewAccessKeySigner(credential *credentials.AccessKeyCredential) *AccessKeySigner { + return &AccessKeySigner{ + credential: credential, + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/client.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/client.go new file mode 100644 index 0000000000..da8333ea8c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/client.go @@ -0,0 +1,286 @@ +// Copyright 2019 Yunion +// +// 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 client + +import ( + "net/http" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules" +) + +type Client struct { + cfg *SClientConfig + // 标记初始化状态 + init bool + + Bandwidths *modules.SBandwidthManager + Credentials *modules.SCredentialManager + Disks *modules.SDiskManager + Domains *modules.SDomainManager + Eips *modules.SEipManager + Endpoints *modules.SEndpointManager + Services *modules.SServiceManager + Elasticcache *modules.SElasticcacheManager + DcsAvailableZone *modules.SDcsAvailableZoneManager + Flavors *modules.SFlavorManager + Images *modules.SImageManager + OpenStackImages *modules.SImageManager + Interface *modules.SInterfaceManager + Jobs *modules.SJobManager + Keypairs *modules.SKeypairManager + Elb *modules.SLoadbalancerManager + ElbBackend *modules.SElbBackendManager + ElbBackendGroup *modules.SElbBackendGroupManager + ElbListeners *modules.SElbListenersManager + ElbCertificates *modules.SElbCertificatesManager + ElbHealthCheck *modules.SElbHealthCheckManager + ElbL7policies *modules.SElbL7policiesManager + ElbPolicies *modules.SElbPoliciesManager + ElbWhitelist *modules.SElbWhitelistManager + Port *modules.SPortManager + Projects *modules.SProjectManager + Regions *modules.SRegionManager + SecurityGroupRules *modules.SSecgroupRuleManager + SecurityGroups *modules.SSecurityGroupManager + NovaSecurityGroups *modules.SSecurityGroupManager + Servers *modules.SServerManager + ServersV2 *modules.SServerManager + NovaServers *modules.SServerManager + Snapshots *modules.SSnapshotManager + OsSnapshots *modules.SSnapshotManager + Subnets *modules.SSubnetManager + Users *modules.SUserManager + Vpcs *modules.SVpcManager + Zones *modules.SZoneManager + VpcRoutes *modules.SVpcRouteManager + SNatRules *modules.SNatSRuleManager + DNatRules *modules.SNatDRuleManager + NatGateways *modules.SNatGatewayManager + VpcPeerings *modules.SVpcPeeringManager + DBInstance *modules.SDBInstanceManager + DBInstanceBackup *modules.SDBInstanceBackupManager + DBInstanceFlavor *modules.SDBInstanceFlavorManager + DBInstanceDatastore *modules.SDBInstanceDatastoreManager + DBInstanceStorage *modules.SDBInstanceStorageManager + DBInstanceJob *modules.SDBInstanceJobManager + Traces *modules.STraceManager + CloudEye *modules.SCloudEyeManager + Quotas *modules.SQuotaManager + EnterpriseProjects *modules.SEnterpriseProjectManager + Roles *modules.SRoleManager + Groups *modules.SGroupManager + SAMLProviders *modules.SAMLProviderManager + SAMLProviderMappings *modules.SAMLProviderMappingManager + SfsTurbos *modules.SfsTurboManager +} + +type SClientConfig struct { + signer auth.Signer + endpoints *cloudprovider.SHCSOEndpoints + regionId string + domainId string + projectId string + defaultRegion string + + debug bool +} + +func (self *SClientConfig) GetSigner() auth.Signer { + return self.signer +} + +func (self *SClientConfig) GetEndpoints() *cloudprovider.SHCSOEndpoints { + return self.endpoints +} + +func (self *SClientConfig) GetDefaultRegion() string { + return self.defaultRegion +} + +func (self *SClientConfig) GetRegionId() string { + return self.regionId +} + +func (self *SClientConfig) GetDomainId() string { + return self.domainId +} + +func (self *SClientConfig) GetProjectId() string { + return self.projectId +} + +func (self *SClientConfig) GetDebug() bool { + return self.debug +} + +func (self *Client) SetHttpClient(httpClient *http.Client) { + self.Credentials.SetHttpClient(httpClient) + self.Servers.SetHttpClient(httpClient) + self.ServersV2.SetHttpClient(httpClient) + self.NovaServers.SetHttpClient(httpClient) + self.Snapshots.SetHttpClient(httpClient) + self.OsSnapshots.SetHttpClient(httpClient) + self.Images.SetHttpClient(httpClient) + self.OpenStackImages.SetHttpClient(httpClient) + self.Projects.SetHttpClient(httpClient) + self.Regions.SetHttpClient(httpClient) + self.Zones.SetHttpClient(httpClient) + self.Vpcs.SetHttpClient(httpClient) + self.Eips.SetHttpClient(httpClient) + self.Elasticcache.SetHttpClient(httpClient) + self.DcsAvailableZone.SetHttpClient(httpClient) + self.Disks.SetHttpClient(httpClient) + self.Domains.SetHttpClient(httpClient) + self.Keypairs.SetHttpClient(httpClient) + self.Elb.SetHttpClient(httpClient) + self.ElbBackend.SetHttpClient(httpClient) + self.ElbBackendGroup.SetHttpClient(httpClient) + self.ElbListeners.SetHttpClient(httpClient) + self.ElbCertificates.SetHttpClient(httpClient) + self.ElbHealthCheck.SetHttpClient(httpClient) + self.ElbL7policies.SetHttpClient(httpClient) + self.ElbPolicies.SetHttpClient(httpClient) + self.ElbWhitelist.SetHttpClient(httpClient) + self.SecurityGroupRules.SetHttpClient(httpClient) + self.SecurityGroups.SetHttpClient(httpClient) + self.NovaSecurityGroups.SetHttpClient(httpClient) + self.Subnets.SetHttpClient(httpClient) + self.Users.SetHttpClient(httpClient) + self.Interface.SetHttpClient(httpClient) + self.Jobs.SetHttpClient(httpClient) + self.Bandwidths.SetHttpClient(httpClient) + self.Port.SetHttpClient(httpClient) + self.Flavors.SetHttpClient(httpClient) + self.VpcRoutes.SetHttpClient(httpClient) + self.SNatRules.SetHttpClient(httpClient) + self.DNatRules.SetHttpClient(httpClient) + self.NatGateways.SetHttpClient(httpClient) + self.DBInstance.SetHttpClient(httpClient) + self.DBInstanceBackup.SetHttpClient(httpClient) + self.DBInstanceFlavor.SetHttpClient(httpClient) + self.DBInstanceJob.SetHttpClient(httpClient) + self.Traces.SetHttpClient(httpClient) + self.CloudEye.SetHttpClient(httpClient) + self.EnterpriseProjects.SetHttpClient(httpClient) + self.Roles.SetHttpClient(httpClient) + self.Groups.SetHttpClient(httpClient) + self.SAMLProviders.SetHttpClient(httpClient) + self.SAMLProviderMappings.SetHttpClient(httpClient) + self.SfsTurbos.SetHttpClient(httpClient) + self.Endpoints.SetHttpClient(httpClient) + self.Services.SetHttpClient(httpClient) +} + +func (self *Client) InitWithAccessKey(regionId, domainId, projectId, accessKey, secretKey string, debug bool, defaultRegion string, endpoints *cloudprovider.SHCSOEndpoints) error { + // accessKey signer + credential := &credentials.AccessKeyCredential{ + AccessKeyId: accessKey, + AccessKeySecret: secretKey, + } + + // 从signer中初始化 + signer, err := auth.NewSignerWithCredential(credential) + if err != nil { + return err + } + self.cfg = &SClientConfig{ + signer: signer, + endpoints: endpoints, + regionId: regionId, + defaultRegion: defaultRegion, + domainId: domainId, + projectId: projectId, + debug: debug, + } + + // 初始化 resource manager + self.initManagers() + return err +} + +func (self *Client) initManagers() { + if !self.init { + self.Servers = modules.NewServerManager(self.cfg) + self.ServersV2 = modules.NewServerV2Manager(self.cfg) + self.NovaServers = modules.NewNovaServerManager(self.cfg) + self.Snapshots = modules.NewSnapshotManager(self.cfg) + self.OsSnapshots = modules.NewOsSnapshotManager(self.cfg) + self.Images = modules.NewImageManager(self.cfg) + self.OpenStackImages = modules.NewOpenstackImageManager(self.cfg) + self.Projects = modules.NewProjectManager(self.cfg) + self.Regions = modules.NewRegionManager(self.cfg) + self.Zones = modules.NewZoneManager(self.cfg) + self.Vpcs = modules.NewVpcManager(self.cfg) + self.Eips = modules.NewEipManager(self.cfg) + self.Elasticcache = modules.NewElasticcacheManager(self.cfg) + self.DcsAvailableZone = modules.NewDcsAvailableZoneManager(self.cfg) + self.Disks = modules.NewDiskManager(self.cfg) + self.Domains = modules.NewDomainManager(self.cfg) + self.Keypairs = modules.NewKeypairManager(self.cfg) + self.Elb = modules.NewLoadbalancerManager(self.cfg) + self.ElbBackend = modules.NewElbBackendManager(self.cfg) + self.ElbBackendGroup = modules.NewElbBackendGroupManager(self.cfg) + self.ElbListeners = modules.NewElbListenersManager(self.cfg) + self.ElbCertificates = modules.NewElbCertificatesManager(self.cfg) + self.ElbHealthCheck = modules.NewElbHealthCheckManager(self.cfg) + self.ElbL7policies = modules.NewElbL7policiesManager(self.cfg) + self.ElbPolicies = modules.NewElbPoliciesManager(self.cfg) + self.ElbWhitelist = modules.NewElbWhitelistManager(self.cfg) + self.SecurityGroupRules = modules.NewSecgroupRuleManager(self.cfg) + self.SecurityGroups = modules.NewSecurityGroupManager(self.cfg) + self.NovaSecurityGroups = modules.NewNovaSecurityGroupManager(self.cfg) + self.Subnets = modules.NewSubnetManager(self.cfg) + self.Users = modules.NewUserManager(self.cfg) + self.Interface = modules.NewInterfaceManager(self.cfg) + self.Jobs = modules.NewJobManager(self.cfg) + self.Bandwidths = modules.NewBandwidthManager(self.cfg) + self.Credentials = modules.NewCredentialManager(self.cfg) + self.Port = modules.NewPortManager(self.cfg) + self.Flavors = modules.NewFlavorManager(self.cfg) + self.VpcRoutes = modules.NewVpcRouteManager(self.cfg) + self.SNatRules = modules.NewNatSManager(self.cfg) + self.DNatRules = modules.NewNatDManager(self.cfg) + self.NatGateways = modules.NewNatGatewayManager(self.cfg) + self.VpcPeerings = modules.NewVpcPeeringManager(self.cfg) + self.DBInstance = modules.NewDBInstanceManager(self.cfg) + self.DBInstanceBackup = modules.NewDBInstanceBackupManager(self.cfg) + self.DBInstanceFlavor = modules.NewDBInstanceFlavorManager(self.cfg) + self.DBInstanceStorage = modules.NewDBInstanceStorageManager(self.cfg) + self.DBInstanceDatastore = modules.NewDBInstanceDatastoreManager(self.cfg) + self.DBInstanceJob = modules.NewDBInstanceJobManager(self.cfg) + self.Traces = modules.NewTraceManager(self.cfg) + self.CloudEye = modules.NewCloudEyeManager(self.cfg) + self.Quotas = modules.NewQuotaManager(self.cfg) + self.EnterpriseProjects = modules.NewEnterpriseProjectManager(self.cfg) + self.Roles = modules.NewRoleManager(self.cfg) + self.Groups = modules.NewGroupManager(self.cfg) + self.SAMLProviders = modules.NewSAMLProviderManager(self.cfg) + self.SAMLProviderMappings = modules.NewSAMLProviderMappingManager(self.cfg) + self.SfsTurbos = modules.NewSfsTurboManager(self.cfg) + self.Endpoints = modules.NewEndpointManager(self.cfg) + self.Services = modules.NewServiceManager(self.cfg) + } + + self.init = true +} + +func NewClientWithAccessKey(regionId, domainId, projectId, accessKey, secretKey string, debug bool, defaultRegion string, endpoints *cloudprovider.SHCSOEndpoints) (*Client, error) { + c := &Client{} + err := c.InitWithAccessKey(regionId, domainId, projectId, accessKey, secretKey, debug, defaultRegion, endpoints) + return c, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/doc.go new file mode 100644 index 0000000000..31a3eb6533 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 client // import "yunion.io/x/cloudmux/pkg/multicloud/hcso/client" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager/doc.go new file mode 100644 index 0000000000..ecba46dd83 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 manager // import "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager/manager.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager/manager.go new file mode 100644 index 0000000000..27e3c7038b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager/manager.go @@ -0,0 +1,84 @@ +// Copyright 2019 Yunion +// +// 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 manager + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type IManagerContext interface { + GetPath() string +} + +type IBaseManager interface { + Version() string + KeyString() string + ServiceType() string + GetColumns() []string +} + +type IManager interface { + IBaseManager + // 获取资源列表 GET /cloudservers/? + List(queries map[string]string) (*responses.ListResult, error) + // 根据上文获取资源列表 GET /cloudservers//nics? + ListInContext(ctx IManagerContext, queries map[string]string) (*responses.ListResult, error) + ListInContextWithSpec(ctx IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error) + + // 查询单个资源 GET /cloudservers/? + Get(id string, queries map[string]string) (jsonutils.JSONObject, error) + // 根据上文获取资源查询单个资源 GET /cloudservers//nics/? + GetInContext(ctx IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error) + + // 创建单个资源 POST /cloudservers + Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 根据上文创建单个资源 POST /cloudservers//nics/ + CreateInContext(ctx IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 异步任务创建 POST /cloudservers. 返回异步任务 job_id。 todo:// 后续考虑返回一个task对象 + AsyncCreate(params jsonutils.JSONObject) (string, error) + + // 更新单个资源 PUT /cloudservers/ + Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 根据上文更新单个资源 PUT /cloudservers//nics/ + UpdateInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 根据上文和spec更新单个资源 PUT /v2.1/{project_id}/servers/{server_id}/os-reset-password + UpdateInContextWithSpec(ctx IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) + + // 删除单个资源 DELETE /cloudservers/ + Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 根据上文删除单个资源 DELETE /cloudservers//nics/ + DeleteInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 根据上文和spec删除单个资源 + DeleteInContextWithSpec(ctx IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) + // 批量执行操作 POST /cloudservers/ + // BatchPerformAction(action string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 执行操作 POST /cloudservers// + PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) +} + +type IManagerConfig interface { + GetSigner() auth.Signer + GetEndpoints() *cloudprovider.SHCSOEndpoints + GetRegionId() string + GetDomainId() string + GetProjectId() string + GetDebug() bool + + GetDefaultRegion() string +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/doc.go new file mode 100644 index 0000000000..f592b09ffc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 modules // import "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/manager_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/manager_base.go new file mode 100644 index 0000000000..915a95a20f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/manager_base.go @@ -0,0 +1,268 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "context" + "fmt" + "net/http" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type IRequestHook interface { + Process(r requests.IRequest) +} + +type SBaseManager struct { + cfg manager.IManagerConfig + httpClient *http.Client + requestHook IRequestHook // 用于对request做特殊处理。非必要请不要使用!!!。目前只有port接口用到。 + + columns []string + debug bool +} + +type sThrottlingThreshold struct { + locked bool + lockTime time.Time +} + +func (t *sThrottlingThreshold) CheckingLock() { + if !t.locked { + return + } + + for { + if t.lockTime.Sub(time.Now()).Seconds() < 0 { + return + } + log.Debugf("throttling threshold has been reached. release at %s", t.lockTime) + time.Sleep(5 * time.Second) + } +} + +func (t *sThrottlingThreshold) Lock() { + // 锁定至少15秒 + t.locked = true + t.lockTime = time.Now().Add(15 * time.Second) +} + +var ThrottlingLock = sThrottlingThreshold{locked: false, lockTime: time.Time{}} + +func NewBaseManager2(cfg manager.IManagerConfig, requesthk IRequestHook) SBaseManager { + return SBaseManager{ + cfg: cfg, + httpClient: httputils.GetDefaultClient(), + debug: cfg.GetDebug(), + requestHook: requesthk, + } +} + +func NewBaseManager(cfg manager.IManagerConfig) SBaseManager { + return NewBaseManager2(cfg, nil) +} + +func (self *SBaseManager) GetColumns() []string { + return self.columns +} + +func (self *SBaseManager) SetHttpClient(httpClient *http.Client) { + self.httpClient = httpClient +} + +func (self *SBaseManager) _list(request requests.IRequest, responseKey string) (*responses.ListResult, error) { + _, body, err := self.jsonRequest(request) + if err != nil { + return nil, err + } + if body == nil { + log.Warningf("empty response") + return &responses.ListResult{}, nil + } + + rets, err := body.GetArray(responseKey) + if err != nil { + return nil, err + } + total, _ := body.Int("count") + // if err != nil { + // total = int64(len(rets)) + //} + + //if total == 0 { + // total = int64(len(rets)) + //} + + limit := 0 + if v, exists := request.GetQueryParams()["limit"]; exists { + limit, _ = strconv.Atoi(v) + } + + offset := 0 + if v, exists := request.GetQueryParams()["offset"]; exists { + offset, _ = strconv.Atoi(v) + } + + return &responses.ListResult{ + Data: rets, + Total: int(total), + Limit: limit, + Offset: offset, + }, nil +} + +func (self *SBaseManager) _do(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) { + _, resp, e := self.jsonRequest(request) + if e != nil { + return nil, e + } + + if resp == nil { // no reslt + return jsonutils.NewDict(), nil + } + + if len(responseKey) == 0 { + return resp, nil + } + + ret, e := resp.Get(responseKey) + if e != nil { + return nil, e + } + + return ret, nil +} + +func (self *SBaseManager) _get(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) { + return self._do(request, responseKey) +} + +type HuaweiClientError struct { + Code int + Errorcode []string + err error + Details string + ErrorCode string +} + +func (ce *HuaweiClientError) Error() string { + return jsonutils.Marshal(ce).String() +} + +func (ce *HuaweiClientError) ParseErrorFromJsonResponse(statusCode int, body jsonutils.JSONObject) error { + if body != nil { + body.Unmarshal(ce) + } + if ce.Code == 0 { + ce.Code = statusCode + } + if len(ce.Details) == 0 && body != nil { + ce.Details = body.String() + } + return ce +} + +func (self *SBaseManager) jsonRequest(request requests.IRequest) (http.Header, jsonutils.JSONObject, error) { + ThrottlingLock.CheckingLock() + ctx := context.Background() + // hook request + if self.requestHook != nil { + self.requestHook.Process(request) + } + // 拼接、编译、签名 requests here。 + err := self.buildRequestWithSigner(request, self.cfg.GetSigner()) + if err != nil { + return nil, nil, err + } + header := http.Header{} + for k, v := range request.GetHeaders() { + header.Set(k, v) + } + + var jsonBody jsonutils.JSONObject + content := request.GetContent() + if len(content) > 0 { + jsonBody, err = jsonutils.Parse(content) + if err != nil { + return nil, nil, fmt.Errorf("not a json body") + } + } + + client := httputils.NewJsonClient(self.httpClient) + req := httputils.NewJsonRequest(httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), jsonBody) + req.SetHeader(header) + resp := &HuaweiClientError{} + const MAX_RETRY = 3 + retry := MAX_RETRY + for { + h, b, e := client.Send(ctx, req, resp, self.debug) + if e == nil { + return h, b, nil + } + + log.Errorf("[%s] %s body: %v error: %v", req.GetHttpMethod(), req.GetUrl(), jsonBody, e) + + switch err := e.(type) { + case *HuaweiClientError: + if err.ErrorCode == "APIGW.0301" { + return h, b, errors.Wrapf(httperrors.ErrInvalidAccessKey, e.Error()) + } else if err.Code == 499 && retry > 0 && request.GetMethod() == "GET" { + retry -= 1 + time.Sleep(3 * time.Second * time.Duration(MAX_RETRY-retry)) + } else if (err.Code == 404 || strings.Contains(err.Details, "could not be found") || + strings.Contains(err.Error(), "Not Found") || + strings.Contains(err.Details, "does not exist")) && request.GetMethod() != "POST" { + return h, b, errors.Wrap(cloudprovider.ErrNotFound, err.Error()) + } else if err.Code == 429 && retry > 0 { + // 当前请求过多。 + ThrottlingLock.Lock() + retry -= 1 + time.Sleep(15 * time.Second) + } else { + return h, b, e + } + default: + return h, b, e + } + } +} + +func (self *SBaseManager) rawRequest(request requests.IRequest) (*http.Response, error) { + ctx := context.Background() + // 拼接、编译requests here。 + header := http.Header{} + for k, v := range request.GetHeaders() { + header.Set(k, v) + } + return httputils.Request(self.httpClient, ctx, httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), header, request.GetBodyReader(), self.debug) +} + +func (self *SBaseManager) buildRequestWithSigner(request requests.IRequest, signer auth.Signer) error { + return auth.Sign(request, signer) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/manager_resource.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/manager_resource.go new file mode 100644 index 0000000000..e90efd0508 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/manager_resource.go @@ -0,0 +1,298 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type ServiceNameType string + +const ( + ServiceNameECS ServiceNameType = "ecs" // 弹性云服务 + ServiceNameCCE ServiceNameType = "cce" // 云容器服务 + ServiceNameAS ServiceNameType = "as" // 弹性伸缩服务 + ServiceNameIAM ServiceNameType = "iam" // 统一身份认证服务 + ServiceNameIMS ServiceNameType = "ims" // 镜像服务 + ServiceNameCSBS ServiceNameType = "csbs" // 云服务器备份服务 + ServiceNameCCI ServiceNameType = "cci" // 云容器实例 CCI + ServiceNameBMS ServiceNameType = "bms" // 裸金属服务器 + ServiceNameEVS ServiceNameType = "evs" // 云硬盘 EVS + ServiceNameVBS ServiceNameType = "vbs" // 云硬盘备份 VBS + ServiceNameOBS ServiceNameType = "obs" // 对象存储服务 OBS + ServiceNameVPC ServiceNameType = "vpc" // 虚拟私有云 VPC + ServiceNameELB ServiceNameType = "elb" // 弹性负载均衡 ELB + ServiceNameBSS ServiceNameType = "bss" // 合作伙伴运营能力 + ServiceNameNAT ServiceNameType = "nat" // Nat网关 NAT + ServiceNameDCS ServiceNameType = "dcs" // 分布式缓存服务 + ServiceNameRDS ServiceNameType = "rds" // 关系型数据库 RDS + ServiceNameCTS ServiceNameType = "cts" // 云审计服务 + ServiceNameCES ServiceNameType = "ces" // 监控服务 CloudEye + ServiceNameEPS ServiceNameType = "eps" // 企业项目 + + ServiceNameSFSTurbo ServiceNameType = "sfs-turbo" // 文件系统 +) + +type SManagerContext struct { + InstanceManager manager.IManager + InstanceId string +} + +func (self *SManagerContext) GetPath() string { + path := self.InstanceManager.KeyString() + if len(self.InstanceId) > 0 { + path += fmt.Sprintf("/%s", url.PathEscape(self.InstanceId)) + } + + return path +} + +type SResourceManager struct { + SBaseManager + ctx manager.IManagerContext + ServiceName ServiceNameType // 服务名称: ecs + Region string // 区域: cn-north-1 + DomainId string + ProjectId string // 项目ID: uuid + version string // api 版本号 + Keyword string // 资源名称单数。构建URL时使用 + KeywordPlural string // 资源名称复数形式。构建URL时使用 + + ResourceKeyword string // 资源名称。url中使用 +} + +func getContent(params jsonutils.JSONObject) string { + if params == nil { + return "" + } + + return params.String() +} + +func (self *SResourceManager) Version() string { + return self.version +} + +func (self *SResourceManager) KeyString() string { + return self.ResourceKeyword +} + +func (self *SResourceManager) ServiceType() string { + return string(self.ServiceName) +} + +func (self *SResourceManager) GetEndpoint() string { + return self.cfg.GetEndpoints().GetEndpoint(self.cfg.GetDefaultRegion(), self.ServiceType(), self.Region) +} + +func (self *SResourceManager) GetColumns() []string { + return []string{} +} + +func (self *SResourceManager) SetDomainId(domainId string) { + self.DomainId = domainId +} + +func (self *SResourceManager) getReourcePath(ctx manager.IManagerContext, rid string, spec string) string { + segs := []string{} + if ctx != nil { + segs = append(segs, ctx.GetPath()) + } + + segs = append(segs, self.KeyString()) + + if len(rid) > 0 { + segs = append(segs, url.PathEscape(rid)) + } + + if len(spec) > 0 { + specSegs := strings.Split(spec, "/") + for _, specSeg := range specSegs { + segs = append(segs, url.PathEscape(specSeg)) + } + } + + return strings.Join(segs, "/") +} + +func (self *SResourceManager) newRequest(method, rid, spec string, ctx manager.IManagerContext) *requests.SRequest { + resourcePath := self.getReourcePath(ctx, rid, spec) + return requests.NewResourceRequest(self.GetEndpoint(), method, string(self.ServiceName), self.version, self.Region, self.ProjectId, resourcePath) +} + +func (self *SResourceManager) List(queries map[string]string) (*responses.ListResult, error) { + return self.ListInContext(self.ctx, queries) +} + +func (self *SResourceManager) ListInContext(ctx manager.IManagerContext, queries map[string]string) (*responses.ListResult, error) { + return self.ListInContextWithSpec(ctx, "", queries, self.KeywordPlural) +} + +func (self *SResourceManager) ListInContextWithSpec(ctx manager.IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error) { + request := self.newRequest("GET", "", spec, ctx) + for k, v := range queries { + request.AddQueryParam(k, v) + } + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._list(request, responseKey) +} + +func (self *SResourceManager) Get(id string, queries map[string]string) (jsonutils.JSONObject, error) { + return self.GetInContext(self.ctx, id, queries) +} + +func (self *SResourceManager) GetInContext(ctx manager.IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error) { + return self.GetInContextWithSpec(ctx, id, "", queries, self.Keyword) +} + +func (self *SResourceManager) GetInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("GET", id, spec, ctx) + for k, v := range queries { + request.AddQueryParam(k, v) + } + + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._get(request, responseKey) +} + +func (self *SResourceManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.CreateInContext(self.ctx, params) +} + +func (self *SResourceManager) CreateInContext(ctx manager.IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.CreateInContextWithSpec(ctx, "", params, self.Keyword) +} + +func (self *SResourceManager) CreateInContextWithSpec(ctx manager.IManagerContext, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("POST", "", spec, ctx) + request.SetContent([]byte(params.String())) + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._do(request, responseKey) +} + +func (self *SResourceManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { + return "", fmt.Errorf("not supported") +} + +func (self *SResourceManager) Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.UpdateInContext(self.ctx, id, params) +} + +func (self *SResourceManager) UpdateInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.UpdateInContextWithSpec(ctx, id, "", params, self.Keyword) +} + +func (self *SResourceManager) UpdateInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("PUT", id, spec, ctx) + content := getContent(params) + if len(content) > 0 { + request.SetContent([]byte(content)) + } + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._do(request, responseKey) +} + +func (self *SResourceManager) Patch(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.PatchInContext(self.ctx, id, params) +} + +func (self *SResourceManager) PatchInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.PatchInContextWithSpec(ctx, id, "", params, self.Keyword) +} + +func (self *SResourceManager) PatchInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("PATCH", id, spec, ctx) + content := getContent(params) + if len(content) > 0 { + request.SetContent([]byte(content)) + } + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._do(request, responseKey) +} + +func (self *SResourceManager) Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.DeleteInContext(self.ctx, id, params) +} + +func (self *SResourceManager) DeleteInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.DeleteInContextWithSpec(ctx, id, "", nil, params, "") +} + +func (self *SResourceManager) DeleteInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("DELETE", id, spec, ctx) + for k, v := range queries { + request.AddQueryParam(k, v) + } + + content := getContent(params) + if len(content) > 0 { + request.SetContent([]byte(content)) + } + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._do(request, responseKey) +} + +func (self *SResourceManager) PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.PerformAction2(action, id, params, self.Keyword) +} + +func (self *SResourceManager) PerformAction2(action string, id string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("POST", id, action, nil) + request.SetContent([]byte(getContent(params))) + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._do(request, responseKey) +} + +func (self *SResourceManager) SetVersion(v string) { + self.version = v +} + +func (self *SResourceManager) versionedURL(path string) string { + return "" +} + +// todo: Init a manager with environment variables +func (self *SResourceManager) Init() error { + return nil +} diff --git a/pkg/multicloud/hcso/client/modules/mod_bandwidths.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_bandwidths.go similarity index 94% rename from pkg/multicloud/hcso/client/modules/mod_bandwidths.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_bandwidths.go index 068804e681..c1ad870eb8 100644 --- a/pkg/multicloud/hcso/client/modules/mod_bandwidths.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_bandwidths.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SBandwidthManager struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_ces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_ces.go new file mode 100644 index 0000000000..a741185656 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_ces.go @@ -0,0 +1,120 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests" + hw_mod "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" +) + +type SCloudEyeManager struct { + SResourceManager +} + +func NewCloudEyeManager(cfg manager.IManagerConfig) *SCloudEyeManager { + return &SCloudEyeManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameCES, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "V1.0", + Keyword: "", + KeywordPlural: "metrics", + ResourceKeyword: "metrics", + }} +} + +func (ces *SCloudEyeManager) ListMetrics() ([]hw_mod.SMetricMeta, error) { + metrics := make([]hw_mod.SMetricMeta, 0) + next := "" + for { + marker, data, err := ces.listMetricsInternal(next) + if err != nil { + return nil, errors.Wrap(err, "ces.listMetricsInternal") + } + if len(data) == 0 { + break + } + metrics = append(metrics, data...) + next = marker + } + return metrics, nil +} + +func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []hw_mod.SMetricMeta, error) { + request := requests.NewResourceRequest(ces.GetEndpoint(), "GET", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, ces.ResourceKeyword) + request.AddQueryParam("limit", "1000") + if len(start) > 0 { + request.AddQueryParam("start", start) + } + _, resp, err := ces.jsonRequest(request) + if err != nil { + return "", nil, errors.Wrap(err, "ces.jsonRequest") + } + marker, _ := resp.GetString("meta_data", "marker") + metrics := make([]hw_mod.SMetricMeta, 0) + err = resp.Unmarshal(&metrics, "metrics") + if err != nil { + return "", nil, errors.Wrap(err, "resp.Unmarshal metrics") + } + return marker, metrics, nil +} + +type SBatchQueryMetricDataInput struct { + Metrics []hw_mod.SMetric `json:"metrics"` + + From int64 `json:"from"` + To int64 `json:"to"` + Period string `json:"period"` + Filter string `json:"filter"` +} + +func (ces *SCloudEyeManager) GetMetricsData(metrics []hw_mod.SMetricMeta, since time.Time, until time.Time) ([]hw_mod.SMetricData, error) { + if len(metrics) > 10 { + return nil, errors.Wrap(httperrors.ErrTooLarge, "request more than 10 metrics") + } + metricReq := make([]hw_mod.SMetric, len(metrics)) + for i := range metrics { + metricReq[i] = metrics[i].SMetric + } + request := requests.NewResourceRequest(ces.GetEndpoint(), "POST", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, "batch-query-metric-data") + input := SBatchQueryMetricDataInput{ + Metrics: metricReq, + From: since.Unix() * 1000, + To: until.Unix() * 1000, + Period: "1", + Filter: "average", + } + body := jsonutils.Marshal(&input).String() + request.SetContent([]byte(body)) + _, resp, err := ces.jsonRequest(request) + if err != nil { + return nil, errors.Wrap(err, "ces.jsonRequest") + } + //log.Debugf("%s", resp) + result := make([]hw_mod.SMetricData, 0) + err = resp.Unmarshal(&result, "metrics") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return result, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_credential.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_credential.go new file mode 100644 index 0000000000..11dfcd382f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_credential.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SCredentialManager struct { + SResourceManager +} + +func NewCredentialManager(cfg manager.IManagerConfig) *SCredentialManager { + return &SCredentialManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v3.0", + Keyword: "credential", + KeywordPlural: "credentials", + + ResourceKeyword: "OS-CREDENTIAL/credentials", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance.go new file mode 100644 index 0000000000..e7016010d9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance.go @@ -0,0 +1,103 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type SDBInstanceManager struct { + SResourceManager +} + +func NewDBInstanceManager(cfg manager.IManagerConfig) *SDBInstanceManager { + return &SDBInstanceManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameRDS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v3", + Keyword: "", + KeywordPlural: "instances", + + ResourceKeyword: "instances", + }} +} + +func (self *SDBInstanceManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { + if len(id) == 0 { + return nil, cloudprovider.ErrNotFound + } + resp, err := self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "") + if err != nil { + return nil, err + } + instances, err := resp.GetArray("instances") + if err != nil { + return nil, err + } + if len(instances) == 0 { + return nil, cloudprovider.ErrNotFound + } else if len(instances) == 1 { + return instances[0], nil + } + return nil, cloudprovider.ErrDuplicateId +} + +func (self *SDBInstanceManager) ListParameters(queries map[string]string) (*responses.ListResult, error) { + id, _ := queries["instance_id"] + if len(id) == 0 { + return nil, fmt.Errorf("SDBInstanceManager.ListParameters missing parameter instance_id") + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/configurations", id), queries, "configuration_parameters") +} + +func (self *SDBInstanceManager) ListDatabases(queries map[string]string) (*responses.ListResult, error) { + id, _ := queries["instance_id"] + if len(id) == 0 { + return nil, fmt.Errorf("SDBInstanceManager.ListDatabases missing parameter instance_id") + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/database/detail", id), queries, "databases") +} + +func (self *SDBInstanceManager) ListAccounts(queries map[string]string) (*responses.ListResult, error) { + id, _ := queries["instance_id"] + if len(id) == 0 { + return nil, fmt.Errorf("SDBInstanceManager.ListAccounts missing parameter instance_id") + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/detail", id), queries, "users") +} + +func (self *SDBInstanceManager) ListPrivileges(queries map[string]string) (*responses.ListResult, error) { + id, _ := queries["instance_id"] + if len(id) == 0 { + return nil, fmt.Errorf("SDBInstanceManager.ListPrivileges missing parameter instance_id") + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/database", id), queries, "databases") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_backup.go new file mode 100644 index 0000000000..e39b050df2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_backup.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SDBInstanceBackupManager struct { + SResourceManager +} + +func NewDBInstanceBackupManager(cfg manager.IManagerConfig) *SDBInstanceBackupManager { + return &SDBInstanceBackupManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameRDS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v3", + Keyword: "backup", + KeywordPlural: "backups", + + ResourceKeyword: "backups", + }} +} diff --git a/pkg/multicloud/hcso/client/modules/mod_dbinstance_datastore.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_datastore.go similarity index 94% rename from pkg/multicloud/hcso/client/modules/mod_dbinstance_datastore.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_datastore.go index 28e1deac85..ec639fad60 100644 --- a/pkg/multicloud/hcso/client/modules/mod_dbinstance_datastore.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_datastore.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SDBInstanceDatastoreManager struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_flavor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_flavor.go new file mode 100644 index 0000000000..cd148f95a5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_flavor.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SDBInstanceFlavorManager struct { + SResourceManager +} + +func NewDBInstanceFlavorManager(cfg manager.IManagerConfig) *SDBInstanceFlavorManager { + return &SDBInstanceFlavorManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameRDS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v3", + Keyword: "flavor", + KeywordPlural: "flavor", + + ResourceKeyword: "flavors", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_job.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_job.go new file mode 100644 index 0000000000..49985fa874 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_job.go @@ -0,0 +1,43 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SDBInstanceJobManager struct { + SResourceManager +} + +func NewDBInstanceJobManager(cfg manager.IManagerConfig) *SDBInstanceJobManager { + return &SDBInstanceJobManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameRDS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v3", + Keyword: "", + KeywordPlural: "", + + ResourceKeyword: "jobs", + }} +} + +func (self *SDBInstanceJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { + return self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "job") +} diff --git a/pkg/multicloud/hcso/client/modules/mod_dbinstance_storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_storage.go similarity index 94% rename from pkg/multicloud/hcso/client/modules/mod_dbinstance_storage.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_storage.go index e6519c79c7..10396729a7 100644 --- a/pkg/multicloud/hcso/client/modules/mod_dbinstance_storage.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dbinstance_storage.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SDBInstanceStorageManager struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_disks.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_disks.go new file mode 100644 index 0000000000..8e2808420c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_disks.go @@ -0,0 +1,76 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type SDiskManager struct { + SResourceManager +} + +func NewDiskManager(cfg manager.IManagerConfig) *SDiskManager { + return &SDiskManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameEVS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "volume", + KeywordPlural: "volumes", + + ResourceKeyword: "cloudvolumes", + }} +} + +func (self *SDiskManager) List(querys map[string]string) (*responses.ListResult, error) { + return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) +} + +// https://support.huaweicloud.com/api-evs/evs_04_2003.html +func (self *SDiskManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { + origin_version := self.version + self.version = "v2.1" + defer func() { self.version = origin_version }() + + ret, err := self.CreateInContextWithSpec(nil, "", params, "") + if err != nil { + log.Debugf("AsyncCreate %s", err) + return "", err + } + + log.Debugf("AsyncCreate result %s", ret.String()) + // 按需机器 + jobId, err := ret.GetString("job_id") + if err == nil { + return jobId, nil + } + + // 包年包月机器 + return ret.GetString("order_id") +} + +// https://support.huaweicloud.com/api-evs/evs_04_2003.html +func (self *SDiskManager) GetDiskTypes() (*responses.ListResult, error) { + originKeyword := self.ResourceKeyword + self.ResourceKeyword = "" + defer func() { self.ResourceKeyword = originKeyword }() + return self.ListInContextWithSpec(self.ctx, "types", nil, "volume_types") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dnat_rules.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dnat_rules.go new file mode 100644 index 0000000000..a079463f8e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_dnat_rules.go @@ -0,0 +1,41 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SNatDRuleManager struct { + SResourceManager +} + +func NewNatDManager(cfg manager.IManagerConfig) *SNatDRuleManager { + man := &SNatDRuleManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameNAT, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2.0", + Keyword: "dnat_rule", + KeywordPlural: "dnat_rules", + + ResourceKeyword: "dnat_rules", + }} + if len(cfg.GetProjectId()) > 0 { + man.requestHook = &sProjectHook{cfg.GetProjectId()} + } + return man +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_domains.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_domains.go new file mode 100644 index 0000000000..d1eac0b8e2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_domains.go @@ -0,0 +1,95 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type SDomainManager struct { + SResourceManager +} + +func NewDomainManager(cfg manager.IManagerConfig) *SDomainManager { + m := &SDomainManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v3/auth", + Keyword: "domain", + KeywordPlural: "domains", + + ResourceKeyword: "domains", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} + +func (manager *SDomainManager) DeleteRole(domainId string, groupId, roleId string) error { + if len(domainId) == 0 { + return fmt.Errorf("missing domainId") + } + if len(groupId) == 0 { + return fmt.Errorf("missing groupId") + } + if len(roleId) == 0 { + return fmt.Errorf("missing roleId") + } + manager.SetVersion("v3") + defer manager.SetVersion("v3/auth") + res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) + _, err := manager.DeleteInContextWithSpec(nil, domainId, res, nil, nil, "") + if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return err +} + +func (manager *SDomainManager) ListRoles(domainId string, groupId string) (*responses.ListResult, error) { + if len(domainId) == 0 { + return nil, fmt.Errorf("missing domainId") + } + if len(groupId) == 0 { + return nil, fmt.Errorf("missing groupId") + } + manager.SetVersion("v3") + defer manager.SetVersion("v3/auth") + res := fmt.Sprintf("%s/groups/%s/roles", domainId, groupId) + return manager.ListInContextWithSpec(nil, res, nil, "roles") +} + +func (manager *SDomainManager) AddRole(domainId string, groupId, roleId string) error { + if len(domainId) == 0 { + return fmt.Errorf("missing domainId") + } + if len(groupId) == 0 { + return fmt.Errorf("missing groupId") + } + if len(roleId) == 0 { + return fmt.Errorf("missing roleId") + } + manager.SetVersion("v3") + defer manager.SetVersion("v3/auth") + res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) + _, err := manager.UpdateInContextWithSpec(nil, domainId, res, nil, "") + return err +} diff --git a/pkg/multicloud/hcso/client/modules/mod_eips.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_eips.go similarity index 95% rename from pkg/multicloud/hcso/client/modules/mod_eips.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_eips.go index 489ec813f8..4d3481211b 100644 --- a/pkg/multicloud/hcso/client/modules/mod_eips.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_eips.go @@ -17,7 +17,7 @@ package modules import ( "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SEipManager struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_elasticcache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_elasticcache.go new file mode 100644 index 0000000000..8b13b85342 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_elasticcache.go @@ -0,0 +1,118 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type SElasticcacheManager struct { + SResourceManager +} + +type SDcsAvailableZoneManager struct { + SResourceManager +} + +func NewElasticcacheManager(cfg manager.IManagerConfig) *SElasticcacheManager { + return &SElasticcacheManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameDCS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1.0", + Keyword: "", + KeywordPlural: "instances", + + ResourceKeyword: "instances", + }} +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html +func (self *SElasticcacheManager) ListBackups(queries map[string]string) (*responses.ListResult, error) { + var spec string + if id, _ := queries["instance_id"]; len(id) == 0 { + return nil, fmt.Errorf("SElasticcacheManager.ListBackups missing parameter instance_id") + } else { + spec = fmt.Sprintf("%s/backups", id) + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, spec, queries, "backup_record_response") +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html +func (self *SElasticcacheManager) ListParameters(queries map[string]string) (*responses.ListResult, error) { + var spec string + if id, _ := queries["instance_id"]; len(id) == 0 { + return nil, fmt.Errorf("SElasticcacheManager.ListParameters missing parameter instance_id") + } else { + spec = fmt.Sprintf("%s/configs", id) + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, spec, queries, "redis_config") +} + +func (self *SElasticcacheManager) Restart(instanceId string) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") + params.Add(jsonutils.NewString("restart"), "action") + return self.UpdateInContextWithSpec(nil, "", "status", params, "") +} + +// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 +func (self *SElasticcacheManager) Flush(instanceId string) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") + params.Add(jsonutils.NewString("flush"), "action") + return self.UpdateInContextWithSpec(nil, "", "status", params, "") +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html +func (self *SElasticcacheManager) RestoreInstance(instanceId string, backupId string) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Add(jsonutils.NewArray(jsonutils.NewString(backupId)), "backup_id") + + return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/restores", instanceId), params, "") +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html +func (self *SElasticcacheManager) ChangeInstanceSpec(instanceId string, specCode string, newCapacity int64) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Set("new_capacity", jsonutils.NewInt(newCapacity)) + params.Set("spec_code", jsonutils.NewString(specCode)) + + return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/extend", instanceId), params, "") +} + +func NewDcsAvailableZoneManager(cfg manager.IManagerConfig) *SDcsAvailableZoneManager { + return &SDcsAvailableZoneManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameDCS, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v1.0", + Keyword: "available_zone", + KeywordPlural: "available_zones", + + ResourceKeyword: "availableZones", + }} +} diff --git a/pkg/multicloud/hcso/client/modules/mod_endpoints.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_endpoints.go similarity index 94% rename from pkg/multicloud/hcso/client/modules/mod_endpoints.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_endpoints.go index 0351fe36c2..cbd0286811 100644 --- a/pkg/multicloud/hcso/client/modules/mod_endpoints.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_endpoints.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SEndpointManager struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_enterpriceprojects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_enterpriceprojects.go new file mode 100644 index 0000000000..dcf4268f10 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_enterpriceprojects.go @@ -0,0 +1,39 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SEnterpriseProjectManager struct { + SResourceManager +} + +func NewEnterpriseProjectManager(cfg manager.IManagerConfig) *SEnterpriseProjectManager { + m := &SEnterpriseProjectManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameEPS, + Region: "", + ProjectId: "", + version: "v1.0", + Keyword: "enterprise_project", + KeywordPlural: "enterprise_projects", + + ResourceKeyword: "enterprise-projects", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_flavors.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_flavors.go new file mode 100644 index 0000000000..387efe8fe7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_flavors.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SFlavorManager struct { + SResourceManager +} + +func NewFlavorManager(cfg manager.IManagerConfig) *SFlavorManager { + return &SFlavorManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "flavor", + KeywordPlural: "flavors", + + ResourceKeyword: "cloudservers/flavors", // 这个接口有点特殊,实际只用到了list一个方法。为了简便直接把cloudservers附上。 + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_groups.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_groups.go new file mode 100644 index 0000000000..c0f5de1da9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_groups.go @@ -0,0 +1,39 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SGroupManager struct { + SResourceManager +} + +func NewGroupManager(cfg manager.IManagerConfig) *SGroupManager { + m := &SGroupManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v3", + Keyword: "group", + KeywordPlural: "groups", + + ResourceKeyword: "groups", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_images.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_images.go new file mode 100644 index 0000000000..a12f34a0ee --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_images.go @@ -0,0 +1,101 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests" +) + +type SImageManager struct { + SResourceManager +} + +type imageProject struct { + projectId string +} + +// image创建接口若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊) +// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID +func (self *imageProject) Process(request requests.IRequest) { + request.AddHeaderParam("X-Project-Id", self.projectId) +} + +func NewImageManager(cfg manager.IManagerConfig) *SImageManager { + var requestHook imageProject + if len(cfg.GetProjectId()) > 0 { + requestHook = imageProject{projectId: cfg.GetProjectId()} + } + + return &SImageManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager2(cfg, &requestHook), + ServiceName: ServiceNameIMS, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2", + Keyword: "image", + KeywordPlural: "images", + + ResourceKeyword: "cloudimages", + }} +} + +//https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091566.html +func (self *SImageManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { + if querys == nil { + querys = make(map[string]string, 0) + } + + querys["id"] = id + // 这里默认使用private + // if t, exists := querys["__imagetype"]; !exists || len(t) == 0 { + // querys["__imagetype"] = "private" + // } + + ret, err := self.ListInContext(nil, querys) + if err != nil { + return nil, err + } + + if ret.Data == nil || len(ret.Data) == 0 { + return nil, httperrors.NewNotFoundError("image %s not found", id) + } + + return ret.Data[0], nil +} + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092108.html +// 删除image只能用这个manager +func NewOpenstackImageManager(cfg manager.IManagerConfig) *SImageManager { + var requestHook imageProject + if len(cfg.GetProjectId()) > 0 { + requestHook = imageProject{projectId: cfg.GetProjectId()} + } + + return &SImageManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager2(cfg, &requestHook), + ServiceName: ServiceNameIMS, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2", + Keyword: "image", + KeywordPlural: "images", + + ResourceKeyword: "images", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_interface.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_interface.go new file mode 100644 index 0000000000..3a1650e2be --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_interface.go @@ -0,0 +1,38 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SInterfaceManager struct { + SResourceManager +} + +// 不建议使用 +func NewInterfaceManager(cfg manager.IManagerConfig) *SInterfaceManager { + return &SInterfaceManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "interfaceAttachment", + KeywordPlural: "interfaceAttachments", + + ResourceKeyword: "os-interface", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_jobs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_jobs.go new file mode 100644 index 0000000000..398cb7bddc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_jobs.go @@ -0,0 +1,71 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type SJobManager struct { + SResourceManager +} + +func NewJobManager(cfg manager.IManagerConfig) *SJobManager { + return &SJobManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: "", + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "", + KeywordPlural: "", + + ResourceKeyword: "jobs", + }} +} + +func (self *SJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { + processedQuery, err := self.processQueryParam(querys) + if err != nil { + return nil, err + } + + return self.GetInContext(nil, id, processedQuery) +} + +func (self *SJobManager) List(querys map[string]string) (*responses.ListResult, error) { + processedQuery, err := self.processQueryParam(querys) + if err != nil { + return nil, err + } + return self.ListInContext(nil, processedQuery) +} + +// 兼容查询不同ServiceName服务的Job做的特殊处理。 +func (self *SJobManager) processQueryParam(querys map[string]string) (map[string]string, error) { + service_type, exists := querys["service_type"] + if !exists { + return querys, fmt.Errorf("must specific query parameter `service_type`. e.g. ecs|ims|iam") + } + + self.ServiceName = ServiceNameType(service_type) + delete(querys, "service_type") + return querys, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_keypairs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_keypairs.go new file mode 100644 index 0000000000..aa1624f0b4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_keypairs.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SKeypairManager struct { + SResourceManager +} + +func NewKeypairManager(cfg manager.IManagerConfig) *SKeypairManager { + return &SKeypairManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "keypair", + KeywordPlural: "keypairs", + + ResourceKeyword: "os-keypairs", + }} +} diff --git a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend.go similarity index 96% rename from pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend.go index 6ed5848d7e..aa93c3c4e3 100644 --- a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend.go @@ -17,7 +17,7 @@ package modules import ( "fmt" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SElbBackendManager struct { diff --git a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend_group.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend_group.go similarity index 95% rename from pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend_group.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend_group.go index d3d9dec2e2..9dc493072c 100644 --- a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend_group.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_backend_group.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SElbBackendGroupManager struct { diff --git a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_certificates.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_certificates.go similarity index 95% rename from pkg/multicloud/hcso/client/modules/mod_loadbalancer_certificates.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_certificates.go index fe3b5710cb..1f18b081ea 100644 --- a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_certificates.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_certificates.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SElbCertificatesManager struct { diff --git a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_healthcheck.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_healthcheck.go similarity index 96% rename from pkg/multicloud/hcso/client/modules/mod_loadbalancer_healthcheck.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_healthcheck.go index acd22a1c19..a5961ce652 100644 --- a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_healthcheck.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_healthcheck.go @@ -17,7 +17,7 @@ package modules import ( "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SElbHealthCheckManager struct { diff --git a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_listeners.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_listeners.go similarity index 95% rename from pkg/multicloud/hcso/client/modules/mod_loadbalancer_listeners.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_listeners.go index 6998878873..2df12ff24d 100644 --- a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_listeners.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_listeners.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SElbListenersManager struct { diff --git a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_policies.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_policies.go similarity index 95% rename from pkg/multicloud/hcso/client/modules/mod_loadbalancer_policies.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_policies.go index 491f39772d..119497102a 100644 --- a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_policies.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_policies.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SElbL7policiesManager struct { diff --git a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_rules.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_rules.go similarity index 96% rename from pkg/multicloud/hcso/client/modules/mod_loadbalancer_rules.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_rules.go index 6d4ad51d68..1a93590e5d 100644 --- a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_rules.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_rules.go @@ -17,7 +17,7 @@ package modules import ( "fmt" - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SElbPoliciesManager struct { diff --git a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_whitelists.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_whitelists.go similarity index 95% rename from pkg/multicloud/hcso/client/modules/mod_loadbalancer_whitelists.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_whitelists.go index 5bcc8046ef..c96e2dc491 100644 --- a/pkg/multicloud/hcso/client/modules/mod_loadbalancer_whitelists.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancer_whitelists.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SElbWhitelistManager struct { diff --git a/pkg/multicloud/hcso/client/modules/mod_loadbalancers.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancers.go similarity index 95% rename from pkg/multicloud/hcso/client/modules/mod_loadbalancers.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancers.go index cb8d9d31a0..b77a3f6329 100644 --- a/pkg/multicloud/hcso/client/modules/mod_loadbalancers.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_loadbalancers.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SLoadbalancerManager struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_mapping.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_mapping.go new file mode 100644 index 0000000000..37a7c9fa69 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_mapping.go @@ -0,0 +1,39 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SAMLProviderMappingManager struct { + SResourceManager +} + +func NewSAMLProviderMappingManager(cfg manager.IManagerConfig) *SAMLProviderMappingManager { + m := &SAMLProviderMappingManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v3/OS-FEDERATION", + Keyword: "mapping", + KeywordPlural: "mappings", + + ResourceKeyword: "mappings", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_natgateway.go new file mode 100644 index 0000000000..0ecbc3c3a7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_natgateway.go @@ -0,0 +1,50 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests" +) + +type SNatGatewayManager struct { + SResourceManager +} + +type sProjectHook struct { + projectId string +} + +func (self *sProjectHook) Process(request requests.IRequest) { + request.AddHeaderParam("X-Project-Id", self.projectId) +} + +func NewNatGatewayManager(cfg manager.IManagerConfig) *SNatGatewayManager { + man := &SNatGatewayManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameNAT, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2.0", + Keyword: "nat_gateway", + KeywordPlural: "nat_gateways", + + ResourceKeyword: "nat_gateways", + }} + if len(cfg.GetProjectId()) > 0 { + man.requestHook = &sProjectHook{cfg.GetProjectId()} + } + return man +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_port.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_port.go new file mode 100644 index 0000000000..68ae7ba41e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_port.go @@ -0,0 +1,53 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests" +) + +type SPortManager struct { + SResourceManager +} + +type portProject struct { + projectId string +} + +// port接口查询时若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊) +// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID +func (self *portProject) Process(request requests.IRequest) { + request.AddHeaderParam("X-Project-Id", self.projectId) +} + +func NewPortManager(cfg manager.IManagerConfig) *SPortManager { + var requestHook portProject + if len(cfg.GetProjectId()) > 0 { + requestHook = portProject{projectId: cfg.GetProjectId()} + } + + return &SPortManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager2(cfg, &requestHook), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "port", + KeywordPlural: "ports", + + ResourceKeyword: "ports", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_projects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_projects.go new file mode 100644 index 0000000000..c0d3a05ba3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_projects.go @@ -0,0 +1,89 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type SProjectManager struct { + SResourceManager +} + +func NewProjectManager(cfg manager.IManagerConfig) *SProjectManager { + m := &SProjectManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v3", + Keyword: "project", + KeywordPlural: "projects", + + ResourceKeyword: "projects", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} + +func (manager *SProjectManager) ListRoles(projectId, groupId string) (*responses.ListResult, error) { + if len(projectId) == 0 { + return nil, fmt.Errorf("missing projectId") + } + if len(groupId) == 0 { + return nil, fmt.Errorf("missing groupId") + } + res := fmt.Sprintf("%s/groups/%s/roles", projectId, groupId) + return manager.ListInContextWithSpec(nil, res, nil, "roles") +} + +func (manager *SProjectManager) DeleteProjectRole(projectId, groupId, roleId string) error { + if len(projectId) == 0 { + return fmt.Errorf("missing projectId") + } + if len(groupId) == 0 { + return fmt.Errorf("missing groupId") + } + if len(roleId) == 0 { + return fmt.Errorf("missing roleId") + } + res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) + _, err := manager.DeleteInContextWithSpec(nil, projectId, res, nil, nil, "") + if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return err +} + +func (manager *SProjectManager) AddProjectRole(projectId string, groupId, roleId string) error { + if len(projectId) == 0 { + return fmt.Errorf("missing projectId") + } + if len(groupId) == 0 { + return fmt.Errorf("missing groupId") + } + if len(roleId) == 0 { + return fmt.Errorf("missing roleId") + } + res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) + _, err := manager.UpdateInContextWithSpec(nil, projectId, res, nil, "") + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_quotas.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_quotas.go new file mode 100644 index 0000000000..83961df88c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_quotas.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SQuotaManager struct { + SResourceManager +} + +func NewQuotaManager(cfg manager.IManagerConfig) *SQuotaManager { + return &SQuotaManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameEVS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "quotas", + KeywordPlural: "quotas", + + ResourceKeyword: "quotas", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_regions.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_regions.go new file mode 100644 index 0000000000..9835fb15a9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_regions.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SRegionManager struct { + SResourceManager +} + +func NewRegionManager(cfg manager.IManagerConfig) *SRegionManager { + return &SRegionManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v3", + Keyword: "region", + KeywordPlural: "regions", + + ResourceKeyword: "regions", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_roles.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_roles.go new file mode 100644 index 0000000000..e04549ea3d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_roles.go @@ -0,0 +1,39 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SRoleManager struct { + SResourceManager +} + +func NewRoleManager(cfg manager.IManagerConfig) *SRoleManager { + m := &SRoleManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v3", + Keyword: "role", + KeywordPlural: "roles", + + ResourceKeyword: "roles", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_saml_provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_saml_provider.go new file mode 100644 index 0000000000..ed0ff7f4a0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_saml_provider.go @@ -0,0 +1,39 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SAMLProviderManager struct { + SResourceManager +} + +func NewSAMLProviderManager(cfg manager.IManagerConfig) *SAMLProviderManager { + m := &SAMLProviderManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v3/OS-FEDERATION", + Keyword: "identity_provider", + KeywordPlural: "identity_providers", + + ResourceKeyword: "identity_providers", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_secgroup_rules.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_secgroup_rules.go new file mode 100644 index 0000000000..3d2c8206d3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_secgroup_rules.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SSecgroupRuleManager struct { + SResourceManager +} + +func NewSecgroupRuleManager(cfg manager.IManagerConfig) *SSecgroupRuleManager { + return &SSecgroupRuleManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "security_group_rule", + KeywordPlural: "security_group_rules", + + ResourceKeyword: "security-group-rules", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_secgroups.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_secgroups.go new file mode 100644 index 0000000000..d6e7d9b19e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_secgroups.go @@ -0,0 +1,51 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SSecurityGroupManager struct { + SResourceManager +} + +func NewSecurityGroupManager(cfg manager.IManagerConfig) *SSecurityGroupManager { + return &SSecurityGroupManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "security_group", + KeywordPlural: "security_groups", + + ResourceKeyword: "security-groups", + }} +} + +func NewNovaSecurityGroupManager(cfg manager.IManagerConfig) *SSecurityGroupManager { + return &SSecurityGroupManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2.1", + Keyword: "security_group", + KeywordPlural: "security_groups", + + ResourceKeyword: "os-security-groups", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_servers.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_servers.go new file mode 100644 index 0000000000..cd75879180 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_servers.go @@ -0,0 +1,124 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + "strconv" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type SServerManager struct { + SResourceManager +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212668.html +// v.1.1 新增支持创建包年/包月的弹性云服务器。!!但是不支持查询等调用 https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html +func NewServerManager(cfg manager.IManagerConfig) *SServerManager { + return &SServerManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "server", + KeywordPlural: "servers", + + ResourceKeyword: "cloudservers", + }} +} + +func (self *SServerManager) List(querys map[string]string) (*responses.ListResult, error) { + if offset, exists := querys["offset"]; !exists { + // 华为云分页参数各式各样。cloudserver offset从1开始。部分其他接口从0开始。 + // 另外部分接口使用pager分页 或者 maker分页 + querys["offset"] = "1" + } else { + n, err := strconv.Atoi(offset) + if err != nil { + return nil, fmt.Errorf("offset is invalid: %s", offset) + } + querys["offset"] = strconv.Itoa(n + 1) + } + return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) +} + +/* +返回job id 或者 order id + +https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html +创建按需的弹性云服务 ——> job_id 任务ID (返回数据uuid举例:"70a599e0-31e7-49b7-b260-868f441e862b") +包年包月机器 --> order_id (返回数据举例: "CS1711152257C60TL") +*/ +func (self *SServerManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { + origin_version := self.version + self.version = "v1.1" + defer func() { self.version = origin_version }() + + ret, err := self.CreateInContextWithSpec(nil, "", params, "") + if err != nil { + log.Debugf("AsyncCreate %s", err) + return "", err + } + + log.Debugf("AsyncCreate result %s", ret.String()) + // 按需机器 + jobId, err := ret.GetString("job_id") + if err == nil { + return jobId, nil + } + + // 包年包月机器 + return ret.GetString("order_id") +} + +func (self *SServerManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return nil, fmt.Errorf("not supported.please use AsyncCreate") +} + +// 不推荐使用这个manager +func NewNovaServerManager(cfg manager.IManagerConfig) *SServerManager { + return &SServerManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2.1", + Keyword: "server", + KeywordPlural: "servers", + + ResourceKeyword: "servers", + }} +} + +// 重装弹性云服务器操作系统(安装Cloud-init),请用这个manager +func NewServerV2Manager(cfg manager.IManagerConfig) *SServerManager { + return &SServerManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "server", + KeywordPlural: "servers", + + ResourceKeyword: "cloudservers", + }} +} diff --git a/pkg/multicloud/hcso/client/modules/mod_services.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_services.go similarity index 94% rename from pkg/multicloud/hcso/client/modules/mod_services.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_services.go index b0f736dfcb..d520ca61bc 100644 --- a/pkg/multicloud/hcso/client/modules/mod_services.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_services.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" ) type SServiceManager struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_sfs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_sfs.go new file mode 100644 index 0000000000..61fc1f890f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_sfs.go @@ -0,0 +1,48 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type SfsTurboManager struct { + SResourceManager +} + +func NewSfsTurboManager(cfg manager.IManagerConfig) *SfsTurboManager { + return &SfsTurboManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameSFSTurbo, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "", + KeywordPlural: "shares", + + ResourceKeyword: "sfs-turbo/shares", + }} +} + +func (self *SfsTurboManager) List(querys map[string]string) (*responses.ListResult, error) { + return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) +} + +func (self *SfsTurboManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.CreateInContextWithSpec(self.ctx, "", params, "") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_snapshots.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_snapshots.go new file mode 100644 index 0000000000..0e70579c97 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_snapshots.go @@ -0,0 +1,59 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type SSnapshotManager struct { + SResourceManager +} + +func NewSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager { + return &SSnapshotManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameEVS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "snapshot", + KeywordPlural: "snapshots", + + ResourceKeyword: "snapshots", + }} +} + +func (self *SSnapshotManager) List(querys map[string]string) (*responses.ListResult, error) { + return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html +// 回滚快照只能用这个manger。其他情况请不要使用 +// 另外,香港-亚太还支持另外一个接口。https://support.huaweicloud.com/api-evs/zh-cn_topic_0142374138.html +func NewOsSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager { + return &SSnapshotManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameEVS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "snapshot", + KeywordPlural: "snapshots", + + ResourceKeyword: "os-vendor-snapshots", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_snat_rules.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_snat_rules.go new file mode 100644 index 0000000000..81f86351d6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_snat_rules.go @@ -0,0 +1,41 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SNatSRuleManager struct { + SResourceManager +} + +func NewNatSManager(cfg manager.IManagerConfig) *SNatSRuleManager { + man := &SNatSRuleManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameNAT, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2.0", + Keyword: "snat_rule", + KeywordPlural: "snat_rules", + + ResourceKeyword: "snat_rules", + }} + if len(cfg.GetProjectId()) > 0 { + man.requestHook = &sProjectHook{cfg.GetProjectId()} + } + return man +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_subnets.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_subnets.go new file mode 100644 index 0000000000..2d282d3417 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_subnets.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SSubnetManager struct { + SResourceManager +} + +func NewSubnetManager(cfg manager.IManagerConfig) *SSubnetManager { + return &SSubnetManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "subnet", + KeywordPlural: "subnets", + + ResourceKeyword: "subnets", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_traces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_traces.go new file mode 100644 index 0000000000..8c8886b541 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_traces.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type STraceManager struct { + SResourceManager +} + +func NewTraceManager(cfg manager.IManagerConfig) *STraceManager { + return &STraceManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameCTS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2.0", + Keyword: "trace", + KeywordPlural: "traces", + + ResourceKeyword: "system/trace", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_users.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_users.go new file mode 100644 index 0000000000..bce76f62aa --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_users.go @@ -0,0 +1,69 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +type SUserManager struct { + SResourceManager +} + +func NewUserManager(cfg manager.IManagerConfig) *SUserManager { + user := &SUserManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v3.0/OS-USER", + Keyword: "user", + KeywordPlural: "users", + + ResourceKeyword: "users", + }} + user.SetDomainId(cfg.GetDomainId()) + return user +} + +func (self *SUserManager) List(querys map[string]string) (*responses.ListResult, error) { + self.SetVersion("v3") + return self.SResourceManager.List(querys) +} + +func (self *SUserManager) Delete(id string) (jsonutils.JSONObject, error) { + self.SetVersion("v3") + return self.SResourceManager.Delete(id, nil) +} + +func (self *SUserManager) ResetPassword(id, password string) error { + params := map[string]interface{}{ + "user": map[string]string{ + "password": password, + }, + } + _, err := self.SResourceManager.Update(id, jsonutils.Marshal(params)) + return err +} + +func (self *SUserManager) ListGroups(userId string) (*responses.ListResult, error) { + self.SetVersion("v3") + return self.SResourceManager.ListInContextWithSpec(nil, fmt.Sprintf("%s/groups", userId), nil, "groups") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpc_peerings.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpc_peerings.go new file mode 100644 index 0000000000..7ac2f50062 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpc_peerings.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SVpcPeeringManager struct { + SResourceManager +} + +func NewVpcPeeringManager(cfg manager.IManagerConfig) *SVpcPeeringManager { + return &SVpcPeeringManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2.0", + Keyword: "peering", + KeywordPlural: "peerings", + + ResourceKeyword: "vpc/peerings", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpc_routes.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpc_routes.go new file mode 100644 index 0000000000..c453d43367 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpc_routes.go @@ -0,0 +1,38 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SVpcRouteManager struct { + SResourceManager +} + +func NewVpcRouteManager(cfg manager.IManagerConfig) *SVpcRouteManager { + return &SVpcRouteManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + // the url should not include the field "projectid" in huawei cloud api v2.0 + ProjectId: "", + version: "v2.0", + Keyword: "route", + KeywordPlural: "routes", + + ResourceKeyword: "vpc/routes", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpcs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpcs.go new file mode 100644 index 0000000000..37c47d3ea4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_vpcs.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SVpcManager struct { + SResourceManager +} + +func NewVpcManager(cfg manager.IManagerConfig) *SVpcManager { + return &SVpcManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "vpc", + KeywordPlural: "vpcs", + + ResourceKeyword: "vpcs", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_zones.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_zones.go new file mode 100644 index 0000000000..1f2f7c0dd3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules/mod_zones.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" +) + +type SZoneManager struct { + SResourceManager +} + +func NewZoneManager(cfg manager.IManagerConfig) *SZoneManager { + return &SZoneManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "availabilityZoneInfo", + KeywordPlural: "availabilityZoneInfo", + + ResourceKeyword: "os-availability-zone", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests/doc.go new file mode 100644 index 0000000000..8d8a11de76 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 requests // import "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests" diff --git a/pkg/multicloud/hcso/client/requests/requests.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests/requests.go similarity index 100% rename from pkg/multicloud/hcso/client/requests/requests.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/requests/requests.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses/doc.go new file mode 100644 index 0000000000..eb120ee314 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 responses // import "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" diff --git a/pkg/multicloud/hcso/client/responses/responses.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses/responses.go similarity index 100% rename from pkg/multicloud/hcso/client/responses/responses.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses/responses.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/cloudgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/cloudgroup.go new file mode 100644 index 0000000000..13f9ad96e9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/cloudgroup.go @@ -0,0 +1,446 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SCloudgroup struct { + client *SHuaweiClient + Name string + Description string + Id string + CreateTime string +} + +func (group *SCloudgroup) GetName() string { + return group.Name +} + +func (group *SCloudgroup) GetDescription() string { + return group.Description +} + +func (group *SCloudgroup) GetGlobalId() string { + return group.Id +} + +func (group *SCloudgroup) Delete() error { + return group.client.DeleteGroup(group.Id) +} + +func (group *SCloudgroup) AddUser(name string) error { + user, err := group.client.GetIClouduserByName(name) + if err != nil { + return errors.Wrap(err, "GetIClouduserByName") + } + return group.client.AddUserToGroup(group.Id, user.GetGlobalId()) +} + +func (group *SCloudgroup) RemoveUser(name string) error { + user, err := group.client.GetIClouduserByName(name) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return errors.Wrapf(err, "GetIClouduserByName(%s)", name) + } + return group.client.RemoveUserFromGroup(group.Id, user.GetGlobalId()) +} + +func (group *SCloudgroup) DetachSystemPolicy(roleId string) error { + return group.client.DetachGroupRole(group.Id, roleId) +} + +func (group *SCloudgroup) DetachCustomPolicy(roleId string) error { + return group.client.DetachGroupCustomRole(group.Id, roleId) +} + +func (group *SCloudgroup) AttachSystemPolicy(roleId string) error { + return group.client.AttachGroupRole(group.Id, roleId) +} + +func (group *SCloudgroup) AttachCustomPolicy(roleId string) error { + return group.client.AttachGroupCustomRole(group.Id, roleId) +} + +func (group *SCloudgroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + roles, err := group.client.GetGroupRoles(group.Id) + if err != nil { + return nil, errors.Wrap(err, "GetGroupRoles") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range roles { + _, err := group.client.GetRole(roles[i].GetName()) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + continue + } + return nil, errors.Wrapf(err, "GetRole(%s)", roles[i].GetName()) + } + ret = append(ret, &roles[i]) + } + return ret, nil +} + +func (group *SCloudgroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + roles, err := group.client.GetGroupRoles(group.Id) + if err != nil { + return nil, errors.Wrap(err, "GetGroupRoles") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range roles { + _, err := group.client.GetCustomRole(roles[i].GetName()) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + continue + } + return nil, errors.Wrapf(err, "GetRole(%s)", roles[i].GetName()) + } + ret = append(ret, &roles[i]) + } + return ret, nil +} + +func (group *SCloudgroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { + users, err := group.client.GetGroupUsers(group.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.IClouduser{} + for i := range users { + users[i].client = group.client + ret = append(ret, &users[i]) + } + return ret, nil +} + +func (self *SHuaweiClient) GetGroups(domainId, name string) ([]SCloudgroup, error) { + params := map[string]string{} + if len(domainId) > 0 { + params["domain_id"] = self.ownerId + } + if len(name) > 0 { + params["name"] = name + } + + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + + groups := []SCloudgroup{} + err = doListAllWithNextLink(client.Groups.List, params, &groups) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithOffset") + } + return groups, nil +} + +func (self *SHuaweiClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + groups, err := self.GetGroups("", "") + if err != nil { + return nil, errors.Wrap(err, "GetGroup") + } + ret := []cloudprovider.ICloudgroup{} + for i := range groups { + if groups[i].Name != "admin" { + groups[i].client = self + ret = append(ret, &groups[i]) + } + } + return ret, nil +} + +func (self *SHuaweiClient) GetGroupUsers(groupId string) ([]SClouduser, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + + resp, err := client.Groups.ListInContextWithSpec(nil, fmt.Sprintf("%s/users", groupId), nil, "users") + if err != nil { + return nil, errors.Wrap(err, "") + } + users := []SClouduser{} + err = jsonutils.Update(&users, resp.Data) + if err != nil { + return nil, errors.Wrap(err, "jsonutils.Update") + } + return users, nil +} + +func (self *SHuaweiClient) GetGroupRoles(groupId string) ([]SRole, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + resp, err := client.Domains.ListRoles(self.ownerId, groupId) + if err != nil { + return nil, errors.Wrap(err, "ListRoles") + } + roles := []SRole{} + err = jsonutils.Update(&roles, resp.Data) + if err != nil { + return nil, errors.Wrap(err, "jsonutils.Update") + } + return roles, nil +} + +func (self *SHuaweiClient) CreateGroup(name, desc string) (*SCloudgroup, error) { + params := map[string]string{ + "name": name, + } + if len(desc) > 0 { + params["description"] = desc + } + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + + group := SCloudgroup{client: self} + err = DoCreate(client.Groups.Create, jsonutils.Marshal(map[string]interface{}{"group": params}), &group) + if err != nil { + return nil, errors.Wrap(err, "DoCreate") + } + return &group, nil +} + +func (self *SHuaweiClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + group, err := self.CreateGroup(name, desc) + if err != nil { + return nil, errors.Wrap(err, "CreateGroup") + } + return group, nil +} + +func (self *SHuaweiClient) DeleteGroup(id string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + return DoDeleteWithSpec(client.Groups.DeleteInContextWithSpec, nil, id, "", nil, nil) +} + +func (self *SHuaweiClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + groups, err := self.GetGroups(self.ownerId, name) + if err != nil { + return nil, errors.Wrap(err, "GetGroups") + } + if len(groups) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(groups) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + groups[0].client = self + return &groups[0], nil +} + +func (self *SHuaweiClient) AddUserToGroup(groupId, userId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + _, err = client.Groups.UpdateInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, "") + return err +} + +func (self *SHuaweiClient) RemoveUserFromGroup(groupId, userId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + _, err = client.Groups.DeleteInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, nil, "") + return err +} + +func (self *SHuaweiClient) DetachGroupRole(groupId, roleId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + role, err := self.GetRole(roleId) + if err != nil { + return errors.Wrapf(err, "GetRole(%s)", roleId) + } + if role.Type == "AX" || role.Type == "AA" { + err = client.Domains.DeleteRole(self.ownerId, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "DeleteRole") + } + if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { + err = client.Projects.DeleteProjectRole(self.GetMosProjectId(), groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "DeleteProjectRole") + } + } + } + if role.Type == "XA" || role.Type == "AA" { + projects, err := self.GetProjects() + if err != nil { + return errors.Wrapf(err, "GetProjects") + } + for _, project := range projects { + err = client.Projects.DeleteProjectRole(project.ID, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "DeleteProjectRole") + } + } + } + return nil +} + +func (self *SHuaweiClient) DetachGroupCustomRole(groupId, roleId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + role, err := self.GetCustomRole(roleId) + if err != nil { + return errors.Wrapf(err, "GetCustomRole(%s)", roleId) + } + if role.Type == "AX" || role.Type == "AA" { + err = client.Domains.DeleteRole(self.ownerId, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "DeleteRole") + } + if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { + err = client.Projects.DeleteProjectRole(self.GetMosProjectId(), groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "DeleteProjectRole") + } + } + } + if role.Type == "XA" || role.Type == "AA" { + projects, err := self.GetProjects() + if err != nil { + return errors.Wrapf(err, "GetProjects") + } + for _, project := range projects { + err = client.Projects.DeleteProjectRole(project.ID, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "DeleteProjectRole") + } + } + } + return nil +} + +func (self *SHuaweiClient) GetCustomRole(name string) (*SRole, error) { + roles, err := self.GetCustomRoles() + if err != nil { + return nil, errors.Wrapf(err, "GetCustomRoles(%s)", name) + } + for i := range roles { + if roles[i].DisplayName == name { + return &roles[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) +} + +func (self *SHuaweiClient) GetRole(name string) (*SRole, error) { + roles, err := self.GetRoles("", "") + if err != nil { + return nil, errors.Wrapf(err, "GetRoles(%s)", name) + } + for i := range roles { + if roles[i].DisplayName == name { + return &roles[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) +} + +func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + role, err := self.GetRole(roleId) + if err != nil { + return errors.Wrapf(err, "GetRole(%s)", roleId) + } + if role.Type == "AX" || role.Type == "AA" { + err = client.Domains.AddRole(self.ownerId, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddRole") + } + if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { + err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddProjectRole") + } + } + } + if role.Type == "XA" || role.Type == "AA" { + projects, err := self.GetProjects() + if err != nil { + return errors.Wrapf(err, "GetProjects") + } + for _, project := range projects { + err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddProjectRole") + } + } + } + return nil +} + +func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + role, err := self.GetCustomRole(roleId) + if err != nil { + return errors.Wrapf(err, "GetRole(%s)", roleId) + } + if role.Type == "AX" || role.Type == "AA" { + err = client.Domains.AddRole(self.ownerId, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddRole") + } + if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { + err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddProjectRole") + } + } + } + if role.Type == "XA" || role.Type == "AA" { + projects, err := self.GetProjects() + if err != nil { + return errors.Wrapf(err, "GetProjects") + } + for _, project := range projects { + err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddProjectRole") + } + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/clouduser.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/clouduser.go new file mode 100644 index 0000000000..4ba00f1026 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/clouduser.go @@ -0,0 +1,293 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules" +) + +type SLink struct { + Next string + Previous string + Self string +} + +type SClouduser struct { + client *SHuaweiClient + + Description string + DomainId string + Enabled bool + ForceResetPwd bool + Id string + LastProjectId string + Links SLink + Name string + PasswordExpiresAt string + PwdStatus bool +} + +func (user *SClouduser) GetGlobalId() string { + return user.Id +} + +func (user *SClouduser) GetName() string { + return user.Name +} + +func (user *SClouduser) GetEmailAddr() string { + return "" +} + +func (user *SClouduser) GetInviteUrl() string { + return "" +} + +func (user *SClouduser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return []cloudprovider.ICloudpolicy{}, nil +} + +func (user *SClouduser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return []cloudprovider.ICloudpolicy{}, nil +} + +func (user *SClouduser) AttachSystemPolicy(policyType string) error { + return cloudprovider.ErrNotSupported +} + +func (user *SClouduser) AttachCustomPolicy(policyType string) error { + return cloudprovider.ErrNotSupported +} + +func (user *SClouduser) DetachSystemPolicy(policyId string) error { + return cloudprovider.ErrNotSupported +} + +func (user *SClouduser) DetachCustomPolicy(policyId string) error { + return cloudprovider.ErrNotSupported +} + +func (user *SClouduser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + groups, err := user.client.ListUserGroups(user.Id) + if err != nil { + return nil, errors.Wrap(err, "Users.ListGroups") + } + ret := []cloudprovider.ICloudgroup{} + for i := range groups { + groups[i].client = user.client + ret = append(ret, &groups[i]) + } + return ret, nil +} + +func (user *SClouduser) Delete() error { + return user.client.DeleteClouduser(user.Id) +} + +func (user *SClouduser) IsConsoleLogin() bool { + return user.Enabled == true +} + +func (user *SClouduser) ResetPassword(password string) error { + return user.client.ResetClouduserPassword(user.Id, password) +} + +func (self *SHuaweiClient) DeleteClouduser(id string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + _, err = client.Users.Delete(id) + return err +} + +func (self *SHuaweiClient) ListUserGroups(userId string) ([]SCloudgroup, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + result, err := client.Users.ListGroups(userId) + if err != nil { + return nil, errors.Wrap(err, "Users.ListGroups") + } + groups := []SCloudgroup{} + err = jsonutils.Update(&groups, result.Data) + if err != nil { + return nil, errors.Wrap(err, "jsonutils.Update") + } + return groups, nil +} + +func (self *SHuaweiClient) GetCloudusers(name string) ([]SClouduser, error) { + params := map[string]string{} + if len(name) > 0 { + params["name"] = name + } + users := []SClouduser{} + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + err = doListAllWithOffset(client.Users.List, params, &users) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithOffset") + } + return users, nil +} + +func (self *SHuaweiClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { + users, err := self.GetCloudusers("") + if err != nil { + return nil, errors.Wrap(err, "GetCloudusers") + } + iUsers := []cloudprovider.IClouduser{} + for i := range users { + if users[i].Name != self.ownerName { + users[i].client = self + iUsers = append(iUsers, &users[i]) + } + } + return iUsers, nil +} + +func (self *SHuaweiClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + users, err := self.GetCloudusers(name) + if err != nil { + return nil, errors.Wrapf(err, "GetCloudusers(%s)", name) + } + if len(users) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(users) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + users[0].client = self + return &users[0], nil +} + +func (self *SHuaweiClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + return self.CreateClouduser(conf.Name, conf.Password, conf.Desc) +} + +func (self *SHuaweiClient) CreateClouduser(name, password, desc string) (*SClouduser, error) { + params := map[string]string{ + "name": name, + "domain_id": self.ownerId, + } + if len(password) > 0 { + params["password"] = password + } + if len(desc) > 0 { + params["description"] = desc + } + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + user := SClouduser{client: self} + err = DoCreate(client.Users.Create, jsonutils.Marshal(map[string]interface{}{"user": params}), &user) + if err != nil { + ce, ok := err.(*modules.HuaweiClientError) + if ok && len(ce.Errorcode) > 0 && ce.Errorcode[0] == "1101" { + return nil, errors.Wrap(err, `IAM user name. The length is between 5 and 32. The first digit is not a number. Special characters can only contain the '_' '-' or ' '`) //https://support.huaweicloud.com/api-iam/iam_08_0015.html + } + return nil, errors.Wrap(err, "DoCreate") + } + return &user, nil +} + +func (self *SHuaweiClient) ResetClouduserPassword(id, password string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + return client.Users.ResetPassword(id, password) +} + +type SAccessKey struct { + client *SHuaweiClient + + AccessKey string `json:"access"` + Secret string `json:"secret"` + Description string `json:"description"` + Status string `json:"status"` + CreatedAt time.Time `json:"create_time"` +} + +func (self *SHuaweiClient) GetAKSK(id string) ([]cloudprovider.SAccessKey, error) { + obj, err := self.getAKSKList(id) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.getAKSKList") + } + aks := make([]SAccessKey, 0) + obj.Unmarshal(&aks, "credentials") + res := make([]cloudprovider.SAccessKey, len(aks)) + for i := 0; i < len(aks); i++ { + res[i].Name = aks[i].Description + res[i].AccessKey = aks[i].AccessKey + res[i].Secret = aks[i].Secret + res[i].Status = aks[i].Status + res[i].CreatedAt = aks[i].CreatedAt + } + return res, nil +} + +func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKey, error) { + params := map[string]interface{}{ + "credential": map[string]interface{}{ + "user_id": id, + "description": name, + }, + } + obj, err := self.createAKSK(params) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.createAKSK") + } + ak := SAccessKey{} + obj.Unmarshal(&ak, "credential") + res := cloudprovider.SAccessKey{ + Name: ak.Description, + AccessKey: ak.AccessKey, + Secret: ak.Secret, + } + return &res, nil +} + +func (self *SHuaweiClient) DeleteAKSK(accessKey string) error { + _, err := self.deleteAKSK(accessKey) + return err +} + +func (user *SClouduser) DeleteAccessKey(accessKey string) error { + err := user.client.DeleteAKSK(accessKey) + if err != nil { + return errors.Wrap(err, "SHuaweiClient.deleteAKSK") + } + return nil +} + +func (user *SClouduser) CreateAccessKey(name string) (*cloudprovider.SAccessKey, error) { + return user.client.CreateAKSK(user.Id, name) +} + +func (user *SClouduser) GetAccessKeys() ([]cloudprovider.SAccessKey, error) { + return user.client.GetAKSK(user.Id) +} diff --git a/pkg/multicloud/hcso/consts.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/consts.go similarity index 100% rename from pkg/multicloud/hcso/consts.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/consts.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance.go new file mode 100644 index 0000000000..91ef5f860a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance.go @@ -0,0 +1,694 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + "fmt" + "time" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SBackupStrategy struct { + KeepDays int + StartTime string +} + +type SDatastore struct { + Type string + Version string +} + +type SHa struct { + ReplicationMode string +} + +type SNonde struct { + AvailabilityZone string + Id string + Name string + Role string + Staus string +} + +type SVolume struct { + Size int + Type string +} + +type SRelatedInstance struct { + Id string + Type string +} + +type SDBInstance struct { + multicloud.SDBInstanceBase + huawei.HuaweiTags + region *SRegion + + flavorCache []SDBInstanceFlavor + + BackupStrategy SBackupStrategy + Created string //time.Time + Datastore SDatastore + DbUserName string + DIskEncryptionId string + FlavorRef string + Ha SHa + Id string + MaintenanceWindow string + Name string + Nodes []SNonde + Port int + PrivateIps []string + PublicIps []string + Region string + RelatedInstance []SRelatedInstance + SecurityGroupId string + Status string + SubnetId string + SwitchStrategy string + TimeZone string + Type string + Updated string //time.Time + Volume SVolume + VpcId string + EnterpriseProjectId string +} + +func (region *SRegion) GetDBInstances() ([]SDBInstance, error) { + params := map[string]string{} + dbinstances := []SDBInstance{} + err := doListAllWithOffset(region.ecsClient.DBInstance.List, params, &dbinstances) + return dbinstances, err +} + +func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { + if len(instanceId) == 0 { + return nil, cloudprovider.ErrNotFound + } + instance := SDBInstance{region: region} + err := DoGet(region.ecsClient.DBInstance.Get, instanceId, nil, &instance) + return &instance, err +} + +func (rds *SDBInstance) GetName() string { + return rds.Name +} + +func (rds *SDBInstance) GetId() string { + return rds.Id +} + +func (rds *SDBInstance) GetGlobalId() string { + return rds.GetId() +} + +// 值为“BUILD”,表示实例正在创建。 +// 值为“ACTIVE”,表示实例正常。 +// 值为“FAILED”,表示实例异常。 +// 值为“FROZEN”,表示实例冻结。 +// 值为“MODIFYING”,表示实例正在扩容。 +// 值为“REBOOTING”,表示实例正在重启。 +// 值为“RESTORING”,表示实例正在恢复。 +// 值为“MODIFYING INSTANCE TYPE”,表示实例正在转主备。 +// 值为“SWITCHOVER”,表示实例正在主备切换。 +// 值为“MIGRATING”,表示实例正在迁移。 +// 值为“BACKING UP”,表示实例正在进行备份。 +// 值为“MODIFYING DATABASE PORT”,表示实例正在修改数据库端口。 +// 值为“STORAGE FULL”,表示实例磁盘空间满。 + +func (rds *SDBInstance) GetStatus() string { + switch rds.Status { + case "BUILD", "MODIFYING", "MODIFYING INSTANCE TYPE", "SWITCHOVER", "MODIFYING DATABASE PORT": + return api.DBINSTANCE_DEPLOYING + case "ACTIVE": + return api.DBINSTANCE_RUNNING + case "FAILED", "FROZEN", "STORAGE FULL": + return api.DBINSTANCE_UNKNOWN + case "REBOOTING": + return api.DBINSTANCE_REBOOTING + case "RESTORING": + return api.DBINSTANCE_RESTORING + case "MIGRATING": + return api.DBINSTANCE_MIGRATING + case "BACKING UP": + return api.DBINSTANCE_BACKING_UP + } + return rds.Status +} + +func (rds *SDBInstance) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (rds *SDBInstance) GetSecurityGroupIds() ([]string, error) { + return []string{rds.SecurityGroupId}, nil +} + +func (rds *SDBInstance) fetchFlavor() error { + if len(rds.flavorCache) > 0 { + return nil + } + flavors, err := rds.region.GetDBInstanceFlavors(rds.Datastore.Type, rds.Datastore.Version) + if err != nil { + return err + } + rds.flavorCache = flavors + return nil +} + +func (rds *SDBInstance) GetExpiredAt() time.Time { + return time.Time{} +} + +func (rds *SDBInstance) GetStorageType() string { + return rds.Volume.Type +} + +func (rds *SDBInstance) GetCreatedAt() time.Time { + t, err := time.Parse("2006-01-02T15:04:05Z0700", rds.Created) + if err != nil { + return time.Time{} + } + return t +} + +func (rds *SDBInstance) GetEngine() string { + return rds.Datastore.Type +} + +func (rds *SDBInstance) GetEngineVersion() string { + return rds.Datastore.Version +} + +func (rds *SDBInstance) GetInstanceType() string { + return rds.FlavorRef +} + +func (rds *SDBInstance) GetCategory() string { + switch rds.Type { + case "Single": + return api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE + case "Ha": + return api.HUAWEI_DBINSTANCE_CATEGORY_HA + case "Replica": + return api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA + } + return rds.Type +} + +func (rds *SDBInstance) GetVcpuCount() int { + err := rds.fetchFlavor() + if err != nil { + log.Errorf("failed to fetch flavors: %v", err) + return 0 + } + for _, flavor := range rds.flavorCache { + if flavor.SpecCode == rds.FlavorRef { + return flavor.Vcpus + } + } + return 0 +} + +func (rds *SDBInstance) GetVmemSizeMB() int { + err := rds.fetchFlavor() + if err != nil { + log.Errorf("failed to fetch flavors: %v", err) + return 0 + } + for _, flavor := range rds.flavorCache { + if flavor.SpecCode == rds.FlavorRef { + return flavor.Ram * 1024 + } + } + return 0 +} + +func (rds *SDBInstance) GetDiskSizeGB() int { + return rds.Volume.Size +} + +func (rds *SDBInstance) GetPort() int { + return rds.Port +} + +func (rds *SDBInstance) GetMaintainTime() string { + return rds.MaintenanceWindow +} + +func (rds *SDBInstance) GetIVpcId() string { + return rds.VpcId +} + +func (rds *SDBInstance) GetProjectId() string { + return rds.EnterpriseProjectId +} + +func (rds *SDBInstance) Refresh() error { + instance, err := rds.region.GetDBInstance(rds.Id) + if err != nil { + return err + } + return jsonutils.Update(rds, instance) +} + +func (rds *SDBInstance) GetZone1Id() string { + return rds.GetZoneIdByRole("master") +} + +func (rds *SDBInstance) GetZoneIdByRole(role string) string { + for _, node := range rds.Nodes { + if node.Role == role { + zone, err := rds.region.getZoneById(node.AvailabilityZone) + if err != nil { + log.Errorf("failed to found zone %s for rds %s error: %v", node.AvailabilityZone, rds.Name, err) + return "" + } + return zone.GetGlobalId() + } + } + return "" +} + +func (rds *SDBInstance) GetZone2Id() string { + return rds.GetZoneIdByRole("slave") +} + +func (rds *SDBInstance) GetZone3Id() string { + return "" +} + +type SRdsNetwork struct { + SubnetId string + IP string +} + +func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { + ret := []cloudprovider.SDBInstanceNetwork{} + for _, ip := range rds.PrivateIps { + network := cloudprovider.SDBInstanceNetwork{ + IP: ip, + NetworkId: rds.SubnetId, + } + ret = append(ret, network) + } + return ret, nil +} + +func (rds *SDBInstance) GetInternalConnectionStr() string { + for _, ip := range rds.PrivateIps { + return ip + } + return "" +} + +func (rds *SDBInstance) GetConnectionStr() string { + for _, ip := range rds.PublicIps { + return ip + } + return "" +} + +func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { + dbinstance, err := region.GetDBInstance(instanceId) + if err != nil { + log.Errorf("failed to get dbinstance by id %s error: %v", instanceId, err) + } + return dbinstance, err +} + +func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { + instances, err := region.GetDBInstances() + if err != nil { + return nil, errors.Wrapf(err, "region.GetDBInstances()") + } + idbinstances := []cloudprovider.ICloudDBInstance{} + for i := 0; i < len(instances); i++ { + instances[i].region = region + idbinstances = append(idbinstances, &instances[i]) + } + return idbinstances, nil +} + +func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { + parameters, err := rds.region.GetDBInstanceParameters(rds.Id) + if err != nil { + return nil, err + } + iparameters := []cloudprovider.ICloudDBInstanceParameter{} + for i := 0; i < len(parameters); i++ { + iparameters = append(iparameters, ¶meters[i]) + } + return iparameters, nil +} + +func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { + databases, err := rds.region.GetDBInstanceDatabases(rds.Id) + if err != nil { + return nil, errors.Wrap(err, "rds.region.GetDBInstanceDatabases(rds.Id)") + } + + idatabase := []cloudprovider.ICloudDBInstanceDatabase{} + for i := 0; i < len(databases); i++ { + databases[i].instance = rds + idatabase = append(idatabase, &databases[i]) + } + return idatabase, nil +} + +func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { + accounts, err := rds.region.GetDBInstanceAccounts(rds.Id) + if err != nil { + return nil, errors.Wrap(err, "rds.region.GetDBInstanceAccounts(rds.Id)") + } + + user := "root" + if rds.GetEngine() == api.DBINSTANCE_TYPE_SQLSERVER { + user = "rduser" + } + + accounts = append(accounts, SDBInstanceAccount{ + Name: user, + instance: rds, + }) + + iaccounts := []cloudprovider.ICloudDBInstanceAccount{} + for i := 0; i < len(accounts); i++ { + accounts[i].instance = rds + iaccounts = append(iaccounts, &accounts[i]) + } + return iaccounts, nil +} + +func (rds *SDBInstance) Delete() error { + return rds.region.DeleteDBInstance(rds.Id) +} + +func (region *SRegion) DeleteDBInstance(instanceId string) error { + _, err := region.ecsClient.DBInstance.Delete(instanceId, nil) + return err +} + +func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + zoneIds := []string{} + zones, err := region.GetIZones() + if err != nil { + return nil, err + } + for _, zone := range zones { + zoneIds = append(zoneIds, zone.GetId()) + } + + if len(desc.SecgroupIds) == 0 { + return nil, fmt.Errorf("Missing secgroupId") + } + + params := map[string]interface{}{ + "region": region.ID, + "name": desc.Name, + "datastore": map[string]string{ + "type": desc.Engine, + "version": desc.EngineVersion, + }, + "password": desc.Password, + "volume": map[string]interface{}{ + "type": desc.StorageType, + "size": desc.DiskSizeGB, + }, + "vpc_id": desc.VpcId, + "subnet_id": desc.NetworkId, + "security_group_id": desc.SecgroupIds[0], + } + + if len(desc.ProjectId) > 0 { + params["enterprise_project_id"] = desc.ProjectId + } + + if len(desc.MasterInstanceId) > 0 { + params["replica_of_id"] = desc.MasterInstanceId + delete(params, "security_group_id") + } + + if len(desc.RdsId) > 0 && len(desc.BackupId) > 0 { + params["restore_point"] = map[string]interface{}{ + "backup_id": desc.BackupId, + "instance_id": desc.RdsId, + "type": "backup", + } + } + + switch desc.Category { + case api.HUAWEI_DBINSTANCE_CATEGORY_HA: + switch desc.Engine { + case api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL: + params["ha"] = map[string]string{ + "mode": "Ha", + "replication_mode": "async", + } + case api.DBINSTANCE_TYPE_SQLSERVER: + params["ha"] = map[string]string{ + "mode": "Ha", + "replication_mode": "sync", + } + } + case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE: + case api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA: + } + + if desc.BillingCycle != nil { + periodType := "month" + periodNum := desc.BillingCycle.GetMonths() + if desc.BillingCycle.GetYears() > 0 { + periodType = "year" + periodNum = desc.BillingCycle.GetYears() + } + params["charge_info"] = map[string]interface{}{ + "charge_mode": "prePaid", + "period_type": periodType, + "period_num": periodNum, + "is_auto_renew": false, + } + } + params["flavor_ref"] = desc.InstanceType + params["availability_zone"] = desc.ZoneId + resp, err := region.ecsClient.DBInstance.Create(jsonutils.Marshal(params)) + if err != nil { + return nil, errors.Wrapf(err, "Create") + } + + instance := &SDBInstance{region: region} + err = resp.Unmarshal(instance, "instance") + if err != nil { + return nil, errors.Wrap(err, `resp.Unmarshal(&instance, "instance")`) + } + if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { + err = cloudprovider.Wait(10*time.Second, 20*time.Minute, func() (bool, error) { + job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) + if err != nil { + return false, nil + } + status, _ := job.GetString("status") + process, _ := job.GetString("process") + log.Debugf("create dbinstance job %s status: %s process: %s", jobId, status, process) + if status == "Completed" { + return true, nil + } + if status == "Failed" { + return false, fmt.Errorf("create failed") + } + return false, nil + }) + } + return instance, err +} + +func (rds *SDBInstance) Reboot() error { + return rds.region.RebootDBInstance(rds.Id) +} + +func (rds *SDBInstance) OpenPublicConnection() error { + return fmt.Errorf("Huawei current not support this operation") + //return rds.region.PublicConnectionAction(rds.Id, "openRC") +} + +func (rds *SDBInstance) ClosePublicConnection() error { + return fmt.Errorf("Huawei current not support this operation") + //return rds.region.PublicConnectionAction(rds.Id, "closeRC") +} + +func (region *SRegion) PublicConnectionAction(instanceId string, action string) error { + resp, err := region.ecsClient.DBInstance.PerformAction2(action, instanceId, nil, "") + if err != nil { + return errors.Wrapf(err, "rds.%s", action) + } + + if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { + err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { + job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) + if err != nil { + log.Errorf("failed to get job %s info error: %v", jobId, err) + return false + } + status, _ := job.GetString("status") + process, _ := job.GetString("process") + if status == "Completed" { + return true + } + log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, status, process) + return false + }) + } + + return nil + +} + +func (region *SRegion) RebootDBInstance(instanceId string) error { + params := jsonutils.Marshal(map[string]interface{}{ + "restart": map[string]string{}, + }) + resp, err := region.ecsClient.DBInstance.PerformAction2("action", instanceId, params, "") + if err != nil { + return err + } + if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { + err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { + job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) + if err != nil { + log.Errorf("failed to get job %s info error: %v", jobId, err) + return false + } + status, _ := job.GetString("status") + process, _ := job.GetString("process") + if status == "Completed" { + return true + } + log.Debugf("reboot dbinstance job %s status: %s process: %s", jobId, status, process) + return false + }) + } + return err +} + +func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { + return rds.region.CreateDBInstanceAccount(rds.Id, conf.Name, conf.Password) +} + +func (region *SRegion) CreateDBInstanceAccount(instanceId, account, password string) error { + params := map[string]string{ + "name": account, + "password": password, + } + _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/db_user", instanceId), jsonutils.Marshal(params), "") + return err +} + +func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { + return rds.region.CreateDBInstanceDatabase(rds.Id, conf.Name, conf.CharacterSet) +} + +func (region *SRegion) CreateDBInstanceDatabase(instanceId, database, characterSet string) error { + params := map[string]string{ + "name": database, + "character_set": characterSet, + } + _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/database", instanceId), jsonutils.Marshal(params), "") + return err +} + +func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { + return rds.region.ChangeDBInstanceConfig(rds.Id, desc.InstanceType, desc.DiskSizeGB) +} + +func (region *SRegion) ChangeDBInstanceConfig(instanceId string, instanceType string, diskSizeGb int) error { + instance, err := region.GetIDBInstanceById(instanceId) + if err != nil { + return errors.Wrapf(err, "region.GetIDBInstanceById(%s)", instanceId) + } + + if len(instanceType) > 0 { + params := map[string]map[string]string{ + "resize_flavor": map[string]string{ + "spec_code": instanceType, + }, + } + _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) + if err != nil { + return errors.Wrap(err, "resize_flavor") + } + cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) + } + if diskSizeGb > 0 { + params := map[string]map[string]int{ + "enlarge_volume": map[string]int{ + "size": diskSizeGb, + }, + } + _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) + if err != nil { + return errors.Wrap(err, "enlarge_volume") + } + cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) + } + return nil +} + +func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { + if len(conf.OriginDBInstanceExternalId) == 0 { + conf.OriginDBInstanceExternalId = rds.Id + } + return rds.region.RecoveryDBInstanceFromBackup(rds.Id, conf.OriginDBInstanceExternalId, conf.BackupId, conf.Databases) +} + +func (region *SRegion) RecoveryDBInstanceFromBackup(target, origin string, backupId string, databases map[string]string) error { + source := map[string]interface{}{ + "type": "backup", + "backup_id": backupId, + } + if len(origin) > 0 { + source["instance_id"] = origin + } + if len(databases) > 0 { + source["database_name"] = databases + } + params := map[string]interface{}{ + "source": source, + "target": map[string]string{ + "instance_id": target, + }, + } + _, err := region.ecsClient.DBInstance.PerformAction("", "recovery", jsonutils.Marshal(params)) + if err != nil { + return errors.Wrap(err, "dbinstance.recovery") + } + return nil +} + +func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_account.go new file mode 100644 index 0000000000..2cdf07ee69 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_account.go @@ -0,0 +1,133 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SDBInstanceAccount struct { + multicloud.SDBInstanceAccountBase + huawei.HuaweiTags + instance *SDBInstance + Name string +} + +func (account *SDBInstanceAccount) GetName() string { + return account.Name +} + +func (account *SDBInstanceAccount) Delete() error { + return account.instance.region.DeleteDBInstanceAccount(account.instance.Id, account.Name) +} + +func (region *SRegion) DeleteDBInstanceAccount(instanceId string, account string) error { + return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, fmt.Sprintf("db_user/%s", account), nil, nil) +} + +func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { + privileges, err := account.instance.region.GetDBInstancePrivvileges(account.instance.Id, account.Name) + if err != nil { + return nil, err + } + iprivileves := []cloudprovider.ICloudDBInstanceAccountPrivilege{} + for i := 0; i < len(privileges); i++ { + privileges[i].account = account + iprivileves = append(iprivileves, &privileges[i]) + } + return iprivileves, nil +} + +func (region *SRegion) GetDBInstanceAccounts(instanceId string) ([]SDBInstanceAccount, error) { + params := map[string]string{ + "instance_id": instanceId, + } + accounts := []SDBInstanceAccount{} + err := doListAllWithPage(region.ecsClient.DBInstance.ListAccounts, params, &accounts) + if err != nil { + return nil, err + } + return accounts, nil +} + +func (region *SRegion) GetDBInstancePrivvileges(instanceId string, username string) ([]SDatabasePrivilege, error) { + params := map[string]string{ + "instance_id": instanceId, + "user-name": username, + } + privileges := []SDatabasePrivilege{} + err := doListAllWithPage(region.ecsClient.DBInstance.ListPrivileges, params, &privileges) + if err != nil { + return nil, err + } + return privileges, nil +} + +func (account *SDBInstanceAccount) RevokePrivilege(database string) error { + return account.instance.region.RevokeDBInstancePrivilege(account.instance.Id, account.Name, database) +} + +func (region *SRegion) RevokeDBInstancePrivilege(instanceId string, account, database string) error { + params := map[string]interface{}{ + "db_name": database, + "users": []map[string]interface{}{ + map[string]interface{}{ + "name": account, + }, + }, + } + return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, "db_privilege", nil, jsonutils.Marshal(params)) +} + +func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { + return account.instance.region.GrantDBInstancePrivilege(account.instance.Id, account.Name, database, privilege) +} + +func (region *SRegion) GrantDBInstancePrivilege(instanceId string, account, database string, privilege string) error { + readonly := false + switch privilege { + case api.DATABASE_PRIVILEGE_R: + readonly = true + case api.DATABASE_PRIVILEGE_RW: + default: + return fmt.Errorf("Unknown privilege %s", privilege) + } + params := map[string]interface{}{ + "db_name": database, + "users": []map[string]interface{}{ + map[string]interface{}{ + "name": account, + "readonly": readonly, + }, + }, + } + _, err := region.ecsClient.DBInstance.PerformAction("db_privilege", instanceId, jsonutils.Marshal(params)) + return err +} + +func (account *SDBInstanceAccount) ResetPassword(password string) error { + return account.instance.region.ResetDBInstanceAccountPassword(account.instance.Id, account.Name, password) +} + +func (region *SRegion) ResetDBInstanceAccountPassword(instanceId, account, password string) error { + return fmt.Errorf("The API does not exist or has not been published in the environment") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_backup.go new file mode 100644 index 0000000000..a82a15a9d8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_backup.go @@ -0,0 +1,237 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SDBInstanceBackup struct { + multicloud.SDBInstanceBackupBase + huawei.HuaweiTags + region *SRegion + + BeginTime string + Datastore SDatastore + EndTime string + Id string + InstanceId string + Name string + Size int + Status string + Type string +} + +func (backup *SDBInstanceBackup) GetId() string { + return backup.Id +} + +func (backup *SDBInstanceBackup) GetGlobalId() string { + return backup.Id +} + +func (backup *SDBInstanceBackup) GetName() string { + return backup.Name +} + +func (backup *SDBInstanceBackup) GetEngine() string { + return backup.Datastore.Type +} + +func (backup *SDBInstanceBackup) GetEngineVersion() string { + return backup.Datastore.Version +} + +func (backup *SDBInstanceBackup) GetStartTime() time.Time { + //2019-08-05T08:00:02+0000 + t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.BeginTime) + if err != nil { + return time.Time{} + } + return t +} + +func (backup *SDBInstanceBackup) GetEndTime() time.Time { + t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.EndTime) + if err != nil { + return time.Time{} + } + return t +} + +func (backup *SDBInstanceBackup) GetBackupMode() string { + switch backup.Type { + case "manual": + return api.BACKUP_MODE_MANUAL + default: + return api.BACKUP_MODE_AUTOMATED + } +} + +func (backup *SDBInstanceBackup) GetStatus() string { + switch backup.Status { + case "COMPLETED": + return api.DBINSTANCE_BACKUP_READY + case "FAILED": + return api.DBINSTANCE_BACKUP_FAILED + case "BUILDING": + return api.DBINSTANCE_BACKUP_CREATING + case "DELETING": + return api.DBINSTANCE_BACKUP_DELETING + default: + return api.DBINSTANCE_BACKUP_UNKNOWN + } +} + +func (backup *SDBInstanceBackup) GetBackupSizeMb() int { + return backup.Size / 1024 +} + +func (backup *SDBInstanceBackup) GetDBNames() string { + return "" +} + +func (backup *SDBInstanceBackup) Delete() error { + return backup.region.DeleteDBInstanceBackup(backup.Id) +} + +func (region *SRegion) DeleteDBInstanceBackup(backupId string) error { + _, err := region.ecsClient.DBInstanceBackup.Delete(backupId, nil) + return err +} + +func (backup *SDBInstanceBackup) GetDBInstanceId() string { + return backup.InstanceId +} + +func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string) ([]SDBInstanceBackup, error) { + params := map[string]string{ + "instance_id": instanceId, + } + if len(backupId) > 0 { + params["backup_id"] = backupId + } + backups := []SDBInstanceBackup{} + err := doListAllWithOffset(region.ecsClient.DBInstanceBackup.List, params, &backups) + if err != nil { + return nil, err + } + return backups, nil +} + +func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + dbinstnaces, err := region.GetIDBInstances() + if err != nil { + return nil, err + } + ibackups := []cloudprovider.ICloudDBInstanceBackup{} + for i := 0; i < len(dbinstnaces); i++ { + _dbinstance := dbinstnaces[i].(*SDBInstance) + _ibackup, err := _dbinstance.GetIDBInstanceBackups() + if err != nil { + return nil, errors.Wrapf(err, "_dbinstance(%v).GetIDBInstanceBackups", _dbinstance) + } + ibackups = append(ibackups, _ibackup...) + } + return ibackups, nil +} + +func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { + backups, err := region.GetIDBInstanceBackups() + if err != nil { + return nil, errors.Wrap(err, "region.GetIDBInstanceBackups") + } + for _, backup := range backups { + if backup.GetGlobalId() == backupId { + return backup, nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + backups, err := rds.region.GetDBInstanceBackups(rds.Id, "") + if err != nil { + return nil, err + } + + ibackups := []cloudprovider.ICloudDBInstanceBackup{} + for i := 0; i < len(backups); i++ { + backups[i].region = rds.region + ibackups = append(ibackups, &backups[i]) + } + return ibackups, nil +} + +func (backup *SDBInstanceBackup) Refresh() error { + backups, err := backup.region.GetDBInstanceBackups(backup.InstanceId, backup.Id) + if err != nil { + return err + } + if len(backups) == 0 { + return cloudprovider.ErrNotFound + } + return jsonutils.Update(backup, backups[0]) +} + +func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { + backupId, err := rds.region.CreateDBInstanceBackup(rds.Id, conf.Name, conf.Description, conf.Databases) + if err != nil { + return "", err + } + backup, err := rds.region.GetIDBInstanceBackupById(backupId) + if err != nil { + return "", errors.Wrap(err, "region.GetIDBInstanceBackupById") + } + cloudprovider.WaitStatus(backup, api.DBINSTANCE_BACKUP_READY, time.Second*3, time.Minute*30) + return backupId, nil +} + +func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, descrition string, databases []string) (string, error) { + params := map[string]interface{}{ + "instance_id": instanceId, + "name": name, + "description": descrition, + } + if len(databases) > 0 { + dbs := []map[string]string{} + for _, database := range databases { + dbs = append(dbs, map[string]string{"name": database}) + } + params["databases"] = dbs + } + resp, err := region.ecsClient.DBInstanceBackup.Create(jsonutils.Marshal(params)) + if err != nil { + return "", errors.Wrap(err, "DBInstanceBackup.Create") + } + backupId, err := resp.GetString("id") + if err != nil { + return "", errors.Wrap(err, "resp.GetBackupId") + } + return backupId, nil +} + +func (self *SDBInstanceBackup) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + opts.BackupId = self.Id + return self.region.CreateIDBInstance(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_database.go new file mode 100644 index 0000000000..ad4f67a60c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_database.go @@ -0,0 +1,73 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SDBInstanceDatabase struct { + instance *SDBInstance + multicloud.SDBInstanceDatabaseBase + huawei.HuaweiTags + + Name string + CharacterSet string +} + +func (database *SDBInstanceDatabase) GetId() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetGlobalId() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetName() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetStatus() string { + return api.DBINSTANCE_DATABASE_RUNNING +} + +func (database *SDBInstanceDatabase) GetCharacterSet() string { + return database.CharacterSet +} + +func (database *SDBInstanceDatabase) Delete() error { + return database.instance.region.DeleteDBInstanceDatabase(database.instance.Id, database.Name) +} + +func (region *SRegion) DeleteDBInstanceDatabase(instanceId, database string) error { + _, err := region.ecsClient.DBInstance.DeleteInContextWithSpec(nil, instanceId, fmt.Sprintf("database/%s", database), nil, nil, "") + return err +} + +func (region *SRegion) GetDBInstanceDatabases(instanceId string) ([]SDBInstanceDatabase, error) { + params := map[string]string{ + "instance_id": instanceId, + } + databases := []SDBInstanceDatabase{} + err := doListAllWithPage(region.ecsClient.DBInstance.ListDatabases, params, &databases) + if err != nil { + return nil, err + } + return databases, nil +} diff --git a/pkg/multicloud/hcso/dbinstance_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_parameter.go similarity index 100% rename from pkg/multicloud/hcso/dbinstance_parameter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_parameter.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_privilege.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_privilege.go new file mode 100644 index 0000000000..bb35c66bb3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_privilege.go @@ -0,0 +1,43 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +type SDatabasePrivilege struct { + account *SDBInstanceAccount + + Name string + Readonly bool +} + +func (privilege *SDatabasePrivilege) GetGlobalId() string { + return fmt.Sprintf("%s/%s", privilege.account.Name, privilege.Name) +} + +func (privilege *SDatabasePrivilege) GetPrivilege() string { + if privilege.Readonly { + return api.DATABASE_PRIVILEGE_R + } + return api.DATABASE_PRIVILEGE_RW +} + +func (privilege *SDatabasePrivilege) GetDBName() string { + return privilege.Name +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_skus.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_skus.go new file mode 100644 index 0000000000..6696b87106 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/dbinstance_skus.go @@ -0,0 +1,263 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SDBInstanceSku struct { + Vcpus int + Ram int //单位GB + SpecCode string + InstanceMode string //实例模型 + + StorageType string + Az1 string + Az2 string + Engine string + EngineVersion string +} + +func (self *SDBInstanceSku) GetName() string { + return self.SpecCode +} + +func (self *SDBInstanceSku) GetGlobalId() string { + return fmt.Sprintf("%s-%s-%s-%s-%s-%s", self.Engine, self.EngineVersion, self.InstanceMode, self.SpecCode, self.StorageType, self.GetZoneId()) +} + +func (self *SDBInstanceSku) GetCategory() string { + return self.InstanceMode +} + +func (self *SDBInstanceSku) GetDiskSizeStep() int { + return 10 +} + +func (self *SDBInstanceSku) GetIOPS() int { + return 0 +} + +func (self *SDBInstanceSku) GetTPS() int { + return 0 +} + +func (self *SDBInstanceSku) GetZone1Id() string { + return self.Az1 +} + +func (self *SDBInstanceSku) GetZone2Id() string { + return self.Az2 +} + +func (self *SDBInstanceSku) GetZone3Id() string { + return "" +} + +func (self *SDBInstanceSku) GetZoneId() string { + zones := []string{} + for _, zone := range []string{self.Az1, self.Az2} { + if len(zone) > 0 { + zones = append(zones, zone) + } + } + return strings.Join(zones, ",") +} + +func (self *SDBInstanceSku) GetMaxConnections() int { + return 0 +} + +func (self *SDBInstanceSku) GetMaxDiskSizeGb() int { + return 4000 +} + +func (self *SDBInstanceSku) GetMinDiskSizeGb() int { + return 40 +} + +func (self *SDBInstanceSku) GetVcpuCount() int { + return self.Vcpus +} + +func (self *SDBInstanceSku) GetVmemSizeMb() int { + return self.Ram * 1024 +} + +func (self *SDBInstanceSku) GetStorageType() string { + return self.StorageType +} + +func (sku *SDBInstanceSku) GetEngine() string { + return sku.Engine +} + +func (sku *SDBInstanceSku) GetEngineVersion() string { + return sku.EngineVersion +} + +func (self *SDBInstanceSku) GetStatus() string { + return api.DBINSTANCE_SKU_AVAILABLE +} + +func (sku *SDBInstanceSku) GetQPS() int { + return 0 +} + +type SDBInstanceFlavor struct { + Vcpus int + Ram int //单位GB + SpecCode string + InstanceMode string //实例模型 + + StorageType string + AzStatus map[string]string + Engine string + EngineVersion string +} + +func (self *SDBInstanceFlavor) GetISkus() []cloudprovider.ICloudDBInstanceSku { + ret := []cloudprovider.ICloudDBInstanceSku{} + switch self.InstanceMode { + case api.HUAWEI_DBINSTANCE_CATEGORY_HA: + for az1, status1 := range self.AzStatus { + if status1 != "normal" { + continue + } + for az2, status2 := range self.AzStatus { + if status2 != "normal" { + continue + } + sku := &SDBInstanceSku{ + Vcpus: self.Vcpus, + Ram: self.Ram, + SpecCode: self.SpecCode, + InstanceMode: self.InstanceMode, + StorageType: self.StorageType, + Az1: az1, + Az2: az2, + Engine: self.Engine, + EngineVersion: self.EngineVersion, + } + ret = append(ret, sku) + } + } + case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE: + for az, status := range self.AzStatus { + if status != "normal" { + continue + } + sku := &SDBInstanceSku{ + Vcpus: self.Vcpus, + Ram: self.Ram, + SpecCode: self.SpecCode, + InstanceMode: self.InstanceMode, + StorageType: self.StorageType, + Az1: az, + Engine: self.Engine, + EngineVersion: self.EngineVersion, + } + ret = append(ret, sku) + } + } + return ret +} + +func (self *SRegion) GetIDBInstanceSkus() ([]cloudprovider.ICloudDBInstanceSku, error) { + skus, err := self.GetDBInstanceSkus() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudDBInstanceSku{} + for i := range skus { + ret = append(ret, skus[i].GetISkus()...) + } + return ret, nil +} + +type SDBInstanceDatastore struct { + Id string + Name string +} + +func (self *SRegion) GetDBInstanceSkus() ([]SDBInstanceFlavor, error) { + skus := []SDBInstanceFlavor{} + for _, engine := range []string{api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL, api.DBINSTANCE_TYPE_SQLSERVER} { + stores, err := self.GetDBInstanceDatastores(engine) + if err != nil { + return nil, err + } + for _, version := range stores { + storages, err := self.GetDBInstanceStorages(engine, version.Name) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceStorages(%s,%s)", engine, version.Name) + } + flavors, err := self.GetDBInstanceFlavors(engine, version.Name) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstanceFlavors(%s, %s)", engine, version.Name) + } + for i := range flavors { + flavors[i].Engine = engine + flavors[i].EngineVersion = version.Name + for j := range storages { + flavors[i].StorageType = storages[j].Name + flavors[i].AzStatus = storages[j].AzStatus + skus = append(skus, flavors[i]) + } + } + } + } + return skus, nil +} + +func (region *SRegion) GetDBInstanceFlavors(engine string, version string) ([]SDBInstanceFlavor, error) { + flavors := []SDBInstanceFlavor{} + resp, err := region.ecsClient.DBInstanceFlavor.ListInContextWithSpec(nil, engine, map[string]string{"version_name": version}, "flavors") + if err != nil { + return nil, err + } + return flavors, jsonutils.Update(&flavors, resp.Data) +} + +func (region *SRegion) GetDBInstanceDatastores(engine string) ([]SDBInstanceDatastore, error) { + stores := []SDBInstanceDatastore{} + resp, err := region.ecsClient.DBInstanceDatastore.ListInContextWithSpec(nil, engine, nil, region.ecsClient.DBInstanceDatastore.KeywordPlural) + if err != nil { + return nil, err + } + return stores, jsonutils.Update(&stores, resp.Data) +} + +type SDBInstanceStorage struct { + Name string + AzStatus map[string]string +} + +func (region *SRegion) GetDBInstanceStorages(engine, engineVersion string) ([]SDBInstanceStorage, error) { + storages := []SDBInstanceStorage{} + resp, err := region.ecsClient.DBInstanceStorage.ListInContextWithSpec(nil, engine, map[string]string{"version_name": engineVersion}, region.ecsClient.DBInstanceStorage.KeywordPlural) + if err != nil { + return nil, err + } + return storages, jsonutils.Update(&storages, resp.Data) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/disk.go new file mode 100644 index 0000000000..8c88d15482 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/disk.go @@ -0,0 +1,534 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +/* +华为云云硬盘 +======创建========== +1.磁盘只能挂载到同一可用区的云服务器内,创建后不支持更换可用区 +2.计费模式 包年包月/按需计费 +3.*支持自动备份 + + +共享盘 和 普通盘:https://support.huaweicloud.com/productdesc-evs/zh-cn_topic_0032860759.html +根据是否支持挂载至多台云服务器可以将云硬盘分为非共享云硬盘和共享云硬盘。 +一个非共享云硬盘只能挂载至一台云服务器,而一个共享云硬盘可以同时挂载至多台云服务器。 +单个共享云硬盘最多可同时挂载给16个云服务器。目前,共享云硬盘只适用于数据盘,不支持系统盘。 +*/ + +type Attachment struct { + ServerID string `json:"server_id"` + AttachmentID string `json:"attachment_id"` + AttachedAt string `json:"attached_at"` + HostName string `json:"host_name"` + VolumeID string `json:"volume_id"` + Device string `json:"device"` + ID string `json:"id"` +} + +type DiskMeta struct { + ResourceSpecCode string `json:"resourceSpecCode"` + Billing string `json:"billing"` + ResourceType string `json:"resourceType"` + AttachedMode string `json:"attached_mode"` + Readonly string `json:"readonly"` +} + +type VolumeImageMetadata struct { + QuickStart string `json:"__quick_start"` + ContainerFormat string `json:"container_format"` + MinRAM string `json:"min_ram"` + ImageName string `json:"image_name"` + ImageID string `json:"image_id"` + OSType string `json:"__os_type"` + OSFeatureList string `json:"__os_feature_list"` + MinDisk string `json:"min_disk"` + SupportKVM string `json:"__support_kvm"` + VirtualEnvType string `json:"virtual_env_type"` + SizeGB string `json:"size"` + OSVersion string `json:"__os_version"` + OSBit string `json:"__os_bit"` + SupportKVMHi1822Hiovs string `json:"__support_kvm_hi1822_hiovs"` + SupportXen string `json:"__support_xen"` + Description string `json:"__description"` + Imagetype string `json:"__imagetype"` + DiskFormat string `json:"disk_format"` + ImageSourceType string `json:"__image_source_type"` + Checksum string `json:"checksum"` + Isregistered string `json:"__isregistered"` + HwVifMultiqueueEnabled string `json:"hw_vif_multiqueue_enabled"` + Platform string `json:"__platform"` +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0124881427.html +type SDisk struct { + storage *SStorage + multicloud.SDisk + huawei.HuaweiDiskTags + details *SResourceDetail + + ID string `json:"id"` + Name string `json:"name"` + Status string `json:"status"` + Attachments []Attachment `json:"attachments"` + Description string `json:"description"` + SizeGB int `json:"size"` + Metadata DiskMeta `json:"metadata"` + Encrypted bool `json:"encrypted"` + Bootable string `json:"bootable"` + Multiattach bool `json:"multiattach"` + AvailabilityZone string `json:"availability_zone"` + SourceVolid string `json:"source_volid"` + SnapshotID string `json:"snapshot_id"` + CreatedAt time.Time `json:"created_at"` + VolumeType string `json:"volume_type"` + VolumeImageMetadata VolumeImageMetadata `json:"volume_image_metadata"` + ReplicationStatus string `json:"replication_status"` + UserID string `json:"user_id"` + ConsistencygroupID string `json:"consistencygroup_id"` + UpdatedAt string `json:"updated_at"` + EnterpriseProjectId string + + ExpiredTime time.Time +} + +func (self *SDisk) GetId() string { + return self.ID +} + +func (self *SDisk) GetName() string { + if len(self.Name) == 0 { + return self.ID + } + + return self.Name +} + +func (self *SDisk) GetGlobalId() string { + return self.ID +} + +func (self *SDisk) GetStatus() string { + // https://support.huaweicloud.com/api-evs/zh-cn_topic_0051803385.html + switch self.Status { + case "creating", "downloading": + return api.DISK_ALLOCATING + case "available", "in-use": + return api.DISK_READY + case "error": + return api.DISK_ALLOC_FAILED + case "attaching": + return api.DISK_ATTACHING + case "detaching": + return api.DISK_DETACHING + case "restoring-backup": + return api.DISK_REBUILD + case "backing-up": + return api.DISK_BACKUP_STARTALLOC // ? + case "error_restoring": + return api.DISK_BACKUP_ALLOC_FAILED + case "uploading": + return api.DISK_SAVING //? + case "extending": + return api.DISK_RESIZING + case "error_extending": + return api.DISK_ALLOC_FAILED // ? + case "deleting": + return api.DISK_DEALLOC //? + case "error_deleting": + return api.DISK_DEALLOC_FAILED // ? + case "rollbacking": + return api.DISK_REBUILD + case "error_rollbacking": + return api.DISK_UNKNOWN + default: + return api.DISK_UNKNOWN + } +} + +func (self *SDisk) Refresh() error { + new, err := self.storage.zone.region.GetDisk(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SDisk) IsEmulated() bool { + return false +} + +func (self *SDisk) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SDisk) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SDisk) GetExpiredAt() time.Time { + var expiredTime time.Time + return expiredTime +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +func (self *SDisk) GetDiskFormat() string { + // self.volume_type ? + return "vhd" +} + +func (self *SDisk) GetDiskSizeMB() int { + return int(self.SizeGB * 1024) +} + +func (self *SDisk) checkAutoDelete(attachments []Attachment) bool { + autodelete := false + for _, attach := range attachments { + if len(attach.ServerID) > 0 { + // todo : 忽略错误?? + vm, err := self.storage.zone.region.GetInstanceByID(attach.ServerID) + if err != nil { + volumes := vm.OSExtendedVolumesVolumesAttached + for _, vol := range volumes { + if vol.ID == self.ID && strings.ToLower(vol.DeleteOnTermination) == "true" { + autodelete = true + } + } + } + + break + } + } + + return autodelete +} + +func (self *SDisk) GetIsAutoDelete() bool { + if len(self.Attachments) > 0 { + return self.checkAutoDelete(self.Attachments) + } + + return false +} + +func (self *SDisk) GetTemplateId() string { + return self.VolumeImageMetadata.ImageID +} + +// Bootable 表示硬盘是否为启动盘。 +// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) +func (self *SDisk) GetDiskType() string { + if self.Bootable == "true" { + return api.DISK_TYPE_SYS + } else { + return api.DISK_TYPE_DATA + } +} + +func (self *SDisk) GetFsFormat() string { + return "" +} + +func (self *SDisk) GetIsNonPersistent() bool { + return false +} + +func (self *SDisk) GetDriver() string { + // https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762431.html + // scsi or vbd? + // todo: implement me + return "scsi" +} + +func (self *SDisk) GetCacheMode() string { + return "none" +} + +func (self *SDisk) GetMountpoint() string { + if len(self.Attachments) > 0 { + return self.Attachments[0].Device + } + + return "" +} + +func (self *SDisk) GetMountServerId() string { + if len(self.Attachments) > 0 { + return self.Attachments[0].ServerID + } + + return "" +} + +func (self *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) Delete(ctx context.Context) error { + disk, err := self.storage.zone.region.GetDisk(self.GetId()) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return err + } + if disk.Status != "deleting" { + // 等待硬盘ready + cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 60*time.Second) + err := self.storage.zone.region.DeleteDisk(self.GetId()) + if err != nil { + return err + } + } + + return cloudprovider.WaitDeleted(self, 10*time.Second, 120*time.Second) +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + if snapshotId, err := self.storage.zone.region.CreateSnapshot(self.GetId(), 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, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil { + return nil, err + } + return snapshot, nil + } +} + +func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) { + snapshot, err := self.storage.zone.region.GetSnapshotById(snapshotId) + return &snapshot, err +} + +func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := self.getSnapshot(snapshotId) + return snapshot, err +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := self.storage.zone.region.GetSnapshots(self.ID, "") + if err != nil { + return nil, err + } + + isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := 0; i < len(snapshots); i++ { + isnapshots[i] = &snapshots[i] + } + return isnapshots, nil +} + +func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { + err := cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 60*time.Second) + if err != nil { + return err + } + + sizeGb := newSizeMB / 1024 + err = self.storage.zone.region.resizeDisk(self.GetId(), sizeGb) + if err != nil { + return err + } + + return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 15*time.Second, 5*time.Second, 60*time.Second) +} + +func (self *SDisk) Detach() error { + err := self.storage.zone.region.DetachDisk(self.GetMountServerId(), self.GetId()) + if err != nil { + log.Debugf("detach server %s disk %s failed: %s", self.GetMountServerId(), self.GetId(), err) + return err + } + + return cloudprovider.WaitCreated(5*time.Second, 60*time.Second, func() bool { + err := self.Refresh() + if err != nil { + log.Debugln(err) + return false + } + + if self.Status == "available" { + return true + } + + return false + }) +} + +func (self *SDisk) Attach(device string) error { + err := self.storage.zone.region.AttachDisk(self.GetMountServerId(), self.GetId(), device) + if err != nil { + log.Debugf("attach server %s disk %s failed: %s", self.GetMountServerId(), self.GetId(), err) + return err + } + + return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 10*time.Second, 5*time.Second, 60*time.Second) +} + +// 在线卸载磁盘 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0036046828.html +// 对于挂载在系统盘盘位(也就是“/dev/sda”或“/dev/vda”挂载点)上的磁盘,当前仅支持离线卸载 +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + mountpoint := self.GetMountpoint() + if len(mountpoint) > 0 { + err := self.Detach() + if err != nil { + return "", err + } + } + + diskId, err := self.storage.zone.region.resetDisk(self.GetId(), snapshotId) + if err != nil { + return diskId, err + } + + err = cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 300*time.Second) + if err != nil { + return "", err + } + + if len(mountpoint) > 0 { + err := self.Attach(mountpoint) + if err != nil { + return "", err + } + } + + return diskId, nil +} + +// 华为云不支持重置 +func (self *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { + if len(diskId) == 0 { + return nil, cloudprovider.ErrNotFound + } + var disk SDisk + err := DoGet(self.ecsClient.Disks.Get, diskId, nil, &disk) + return &disk, err +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762430.html +func (self *SRegion) GetDisks(zoneId string) ([]SDisk, error) { + queries := map[string]string{} + if len(zoneId) > 0 { + queries["availability_zone"] = zoneId + } + + disks := make([]SDisk, 0) + err := doListAllWithOffset(self.ecsClient.Disks.List, queries, &disks) + return disks, err +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html +func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, snapshotId string, desc string, projectId string) (string, error) { + params := jsonutils.NewDict() + volumeObj := jsonutils.NewDict() + volumeObj.Add(jsonutils.NewString(name), "name") + volumeObj.Add(jsonutils.NewString(zoneId), "availability_zone") + volumeObj.Add(jsonutils.NewString(desc), "description") + volumeObj.Add(jsonutils.NewString(category), "volume_type") + volumeObj.Add(jsonutils.NewInt(int64(sizeGb)), "size") + if len(snapshotId) > 0 { + volumeObj.Add(jsonutils.NewString(snapshotId), "snapshot_id") + } + if len(projectId) > 0 { + volumeObj.Add(jsonutils.NewString(projectId), "enterprise_project_id") + } + + params.Add(volumeObj, "volume") + // 目前只支持创建按需资源,返回job id。 如果创建包年包月资源则返回order id + _id, err := self.ecsClient.Disks.AsyncCreate(params) + if err != nil { + log.Debugf("AsyncCreate with params: %s", params) + return "", errors.Wrap(err, "AsyncCreate") + } + + // 按需计费 + volumeId, err := self.GetTaskEntityID(self.ecsClient.Disks.ServiceType(), _id, "volume_id") + if err != nil { + return "", errors.Wrap(err, "GetAllSubTaskEntityIDs") + } + + if len(volumeId) == 0 { + return "", errors.Errorf("CreateInstance job %s result is emtpy", _id) + } else { + return volumeId, nil + } +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762428.html +// 默认删除云硬盘关联的所有快照 +func (self *SRegion) DeleteDisk(diskId string) error { + return DoDeleteWithSpec(self.ecsClient.Disks.DeleteInContextWithSpec, nil, diskId, "", nil, nil) +} + +/* +扩容状态为available的云硬盘时,没有约束限制。 +扩容状态为in-use的云硬盘时,有以下约束: +不支持共享云硬盘,即multiattach参数值必须为false。 +云硬盘所挂载的云服务器状态必须为ACTIVE、PAUSED、SUSPENDED、SHUTOFF才支持扩容 +*/ +func (self *SRegion) resizeDisk(diskId string, sizeGB int64) error { + params := jsonutils.NewDict() + osExtendObj := jsonutils.NewDict() + osExtendObj.Add(jsonutils.NewInt(sizeGB), "new_size") // GB + params.Add(osExtendObj, "os-extend") + _, err := self.ecsClient.Disks.PerformAction2("action", diskId, params, "") + return err +} + +/* +https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html +只支持快照回滚到源云硬盘,不支持快照回滚到其它指定云硬盘。 +只有云硬盘状态处于“available”或“error_rollbacking”状态才允许快照回滚到源云硬盘。 +*/ +func (self *SRegion) resetDisk(diskId, snapshotId string) (string, error) { + params := jsonutils.NewDict() + rollbackObj := jsonutils.NewDict() + rollbackObj.Add(jsonutils.NewString(diskId), "volume_id") + params.Add(rollbackObj, "rollback") + _, err := self.ecsClient.OsSnapshots.PerformAction2("rollback", snapshotId, params, "") + return diskId, err +} + +func (self *SDisk) GetProjectId() string { + return self.EnterpriseProjectId +} diff --git a/pkg/multicloud/hcso/disktype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/disktype.go similarity index 100% rename from pkg/multicloud/hcso/disktype.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/disktype.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/doc.go new file mode 100644 index 0000000000..aaaba680c2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 hcso // import huawei "yunion.io/x/cloudmux/pkg/multicloud/hcso" diff --git a/pkg/multicloud/hcso/domain.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/domain.go similarity index 100% rename from pkg/multicloud/hcso/domain.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/domain.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/eip.go new file mode 100644 index 0000000000..344aa9d45f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/eip.go @@ -0,0 +1,402 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type TInternetChargeType string + +const ( + InternetChargeByTraffic = TInternetChargeType("traffic") + InternetChargeByBandwidth = TInternetChargeType("bandwidth") +) + +type Bandwidth struct { + ID string `json:"id"` + Name string `json:"name"` + Size int64 `json:"size"` + ShareType string `json:"share_type"` + PublicipInfo []PublicipInfo `json:"publicip_info"` + TenantID string `json:"tenant_id"` + BandwidthType string `json:"bandwidth_type"` + ChargeMode string `json:"charge_mode"` + BillingInfo string `json:"billing_info"` + EnterpriseProjectID string `json:"enterprise_project_id"` +} + +type PublicipInfo struct { + PublicipID string `json:"publicip_id"` + PublicipAddress string `json:"publicip_address"` + PublicipType string `json:"publicip_type"` + IPVersion int64 `json:"ip_version"` +} + +type SProfile struct { + UserID string `json:"user_id"` + ProductID string `json:"product_id"` + RegionID string `json:"region_id"` + OrderID string `json:"order_id"` +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html +type SEipAddress struct { + region *SRegion + port *Port + multicloud.SEipBase + huawei.HuaweiTags + + ID string `json:"id"` + Status string `json:"status"` + Profile *SProfile `json:"profile,omitempty"` + Type string `json:"type"` + PublicIPAddress string `json:"public_ip_address"` + PrivateIPAddress string `json:"private_ip_address"` + TenantID string `json:"tenant_id"` + CreateTime time.Time `json:"create_time"` + BandwidthID string `json:"bandwidth_id"` + BandwidthShareType string `json:"bandwidth_share_type"` + BandwidthSize int64 `json:"bandwidth_size"` + BandwidthName string `json:"bandwidth_name"` + EnterpriseProjectID string `json:"enterprise_project_id"` + IPVersion int64 `json:"ip_version"` + PortId string `json:"port_id"` + EnterpriseProjectId string +} + +func (self *SEipAddress) GetId() string { + return self.ID +} + +func (self *SEipAddress) GetName() string { + if len(self.BandwidthName) == 0 { + return self.BandwidthName + } + + return self.PublicIPAddress +} + +func (self *SEipAddress) GetGlobalId() string { + return self.ID +} + +func (self *SEipAddress) GetStatus() string { + // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html + switch self.Status { + case "ACTIVE", "DOWN", "ELB": + return api.EIP_STATUS_READY + case "PENDING_CREATE", "NOTIFYING": + return api.EIP_STATUS_ALLOCATE + case "BINDING": + return api.EIP_STATUS_ALLOCATE + case "BIND_ERROR": + return api.EIP_STATUS_ALLOCATE_FAIL + case "PENDING_DELETE", "NOTIFY_DELETE": + return api.EIP_STATUS_DEALLOCATE + default: + return api.EIP_STATUS_UNKNOWN + } +} + +func (self *SEipAddress) Refresh() error { + if self.IsEmulated() { + return nil + } + new, err := self.region.GetEip(self.ID) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SEipAddress) IsEmulated() bool { + return false +} + +func (self *SEipAddress) GetIpAddr() string { + return self.PublicIPAddress +} + +func (self *SEipAddress) GetMode() string { + return api.EIP_MODE_STANDALONE_EIP +} + +func (self *SEipAddress) GetPort() *Port { + if len(self.PortId) == 0 { + return nil + } + + if self.port != nil { + return self.port + } + + port, err := self.region.GetPort(self.PortId) + if err != nil { + return nil + } else { + self.port = &port + } + + return self.port +} + +func (self *SEipAddress) GetAssociationType() string { + if len(self.PortId) == 0 { + return "" + } + port, err := self.region.GetPort(self.PortId) + if err != nil { + log.Errorf("Get eip %s port %s error: %v", self.ID, self.PortId, err) + return "" + } + + switch port.DeviceOwner { + case "neutron:LOADBALANCER", "neutron:LOADBALANCERV2": + return api.EIP_ASSOCIATE_TYPE_LOADBALANCER + case "network:nat_gateway": + return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY + default: + return port.DeviceOwner + } +} + +func (self *SEipAddress) GetAssociationExternalId() string { + // network/0273a359d61847fc83405926c958c746/ext-floatingips?tenantId=0273a359d61847fc83405926c958c746&limit=2000 + // 只能通过 port id 反查device id. + if len(self.PortId) > 0 { + port, _ := self.region.GetPort(self.PortId) + return port.DeviceID + } + return "" +} + +func (self *SEipAddress) GetBandwidth() int { + return int(self.BandwidthSize) // Mb +} + +func (self *SEipAddress) GetINetworkId() string { + return "" +} + +func (self *SEipAddress) GetInternetChargeType() string { + // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090603.html + bandwidth, err := self.region.GetEipBandwidth(self.BandwidthID) + if err != nil { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + } + + if bandwidth.ChargeMode != "traffic" { + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH + } else { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + } +} + +func (self *SEipAddress) GetBillingType() string { + if self.Profile == nil { + return billing_api.BILLING_TYPE_POSTPAID + } else { + return billing_api.BILLING_TYPE_PREPAID + } +} + +func (self *SEipAddress) GetCreatedAt() time.Time { + return self.CreateTime +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SEipAddress) Delete() error { + return self.region.DeallocateEIP(self.ID) +} + +func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { + portId, err := self.region.GetInstancePortId(conf.InstanceId) + if err != nil { + return err + } + + if len(self.PortId) > 0 { + if self.PortId == portId { + return nil + } + + return fmt.Errorf("eip %s aready associate with port %s", self.GetId(), self.PortId) + } + + err = self.region.AssociateEipWithPortId(self.ID, portId) + if err != nil { + return err + } + + err = cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 10*time.Second, 10*time.Second, 180*time.Second) + return err +} + +func (self *SEipAddress) Dissociate() error { + if len(self.PortId) == 0 { + return nil + } + port, err := self.region.GetPort(self.PortId) + if err != nil { + return errors.Wrapf(err, "GetPort(%s)", self.PortId) + } + + err = self.region.DissociateEip(self.ID, port.DeviceID) + if err != nil { + return errors.Wrapf(err, "DissociateEip") + } + err = cloudprovider.WaitStatus(self, api.EIP_STATUS_READY, 10*time.Second, 180*time.Second) + return err +} + +func (self *SEipAddress) ChangeBandwidth(bw int) error { + return self.region.UpdateEipBandwidth(self.BandwidthID, bw) +} + +func (self *SRegion) GetInstancePortId(instanceId string) (string, error) { + // 目前只绑定一个网卡 + // todo: 还需要按照ports状态进行过滤 + ports, err := self.GetPorts(instanceId) + if err != nil { + return "", err + } + + if len(ports) == 0 { + return "", fmt.Errorf("AssociateEip instance %s port is empty", instanceId) + } + + return ports[0].ID, nil +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html +func (self *SRegion) AllocateEIP(name string, bwMbps int, chargeType TInternetChargeType, bgpType string, projectId string) (*SEipAddress, error) { + paramsStr := ` +{ + "publicip": { + "type": "%s", + "ip_version": 4 + }, + "bandwidth": { + "name": "%s", + "size": %d, + "share_type": "PER", + "charge_mode": "%s" + } +} +` + if len(bgpType) == 0 { + return nil, fmt.Errorf("AllocateEIP bgp type should not be empty") + } + paramsStr = fmt.Sprintf(paramsStr, bgpType, name, bwMbps, chargeType) + _params, _ := jsonutils.ParseString(paramsStr) + params := _params.(*jsonutils.JSONDict) + if len(projectId) > 0 { + params.Set("enterprise_project_id", jsonutils.NewString(projectId)) + } + eip := SEipAddress{} + err := DoCreate(self.ecsClient.Eips.Create, params, &eip) + return &eip, err +} + +func (self *SRegion) GetEip(eipId string) (*SEipAddress, error) { + var eip SEipAddress + err := DoGet(self.ecsClient.Eips.Get, eipId, nil, &eip) + eip.region = self + return &eip, err +} + +func (self *SRegion) DeallocateEIP(eipId string) error { + _, err := self.ecsClient.Eips.Delete(eipId, nil) + return err +} + +func (self *SRegion) AssociateEip(eipId string, instanceId string) error { + portId, err := self.GetInstancePortId(instanceId) + if err != nil { + return err + } + return self.AssociateEipWithPortId(eipId, portId) +} + +func (self *SRegion) AssociateEipWithPortId(eipId string, portId string) error { + params := jsonutils.NewDict() + publicIPObj := jsonutils.NewDict() + publicIPObj.Add(jsonutils.NewString(portId), "port_id") + params.Add(publicIPObj, "publicip") + + _, err := self.ecsClient.Eips.Update(eipId, params) + return err +} + +func (self *SRegion) DissociateEip(eipId string, instanceId string) error { + eip, err := self.GetEip(eipId) + if err != nil { + return err + } + + // 已经是解绑状态 + if eip.Status == "DOWN" { + return nil + } + + remoteInstanceId := eip.GetAssociationExternalId() + if remoteInstanceId != instanceId { + return fmt.Errorf("eip %s associate with another instance %s", eipId, remoteInstanceId) + } + + paramsStr := `{"publicip":{"port_id":null}}` + params, _ := jsonutils.ParseString(paramsStr) + _, err = self.ecsClient.Eips.Update(eipId, params) + return err +} + +func (self *SRegion) UpdateEipBandwidth(bandwidthId string, bw int) error { + paramStr := `{ + "bandwidth": + { + "size": %d + } + }` + + paramStr = fmt.Sprintf(paramStr, bw) + params, _ := jsonutils.ParseString(paramStr) + _, err := self.ecsClient.Bandwidths.Update(bandwidthId, params) + return err +} + +func (self *SRegion) GetEipBandwidth(bandwidthId string) (Bandwidth, error) { + bandwidth := Bandwidth{} + err := DoGet(self.ecsClient.Bandwidths.Get, bandwidthId, nil, &bandwidth) + return bandwidth, err +} + +func (self *SEipAddress) GetProjectId() string { + return self.EnterpriseProjectId +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_account.go new file mode 100644 index 0000000000..c9bb3aa852 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_account.go @@ -0,0 +1,109 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SElasticcacheAccount struct { + multicloud.SElasticcacheAccountBase + huawei.HuaweiTags + + cacheDB *SElasticcache +} + +func (self *SElasticcacheAccount) GetId() string { + return fmt.Sprintf("%s/root", self.cacheDB.InstanceID) +} + +func (self *SElasticcacheAccount) GetName() string { + if len(self.cacheDB.AccessUser) > 0 { + return self.cacheDB.AccessUser + } + + return "root" +} + +func (self *SElasticcacheAccount) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheAccount) GetStatus() string { + return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE +} + +func (self *SElasticcacheAccount) GetAccountType() string { + return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN +} + +func (self *SElasticcacheAccount) GetAccountPrivilege() string { + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html +// 未找到关闭密码的开放api, 不支持开启/关闭密码访问 +// https://console.huaweicloud.com/dcs/rest/v2/41f6bfe48d7f4455b7754f7c1b11ae34/instances/26db46e2-c7d8-4b5e-bd36-b5278d2fe17c/password/reset +// new_password: "26db46e2!" +// no_password_access: false +func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { + if input.OldPassword == nil { + return fmt.Errorf("elasticcacheAccount.ResetPassword.input OldPassword should not be empty") + } + + type ResetPasswordResult struct { + Result string `json:"result"` + Message string `json:"message"` + } + + result := ResetPasswordResult{} + params := jsonutils.NewDict() + params.Set("old_password", jsonutils.NewString(*input.OldPassword)) + params.Set("new_password", jsonutils.NewString(input.NewPassword)) + err := DoUpdateWithSpec2(self.cacheDB.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.cacheDB.GetId(), "password", params, &result) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.ResetPassword") + } + + if result.Result != "success" { + return errors.Wrap(fmt.Errorf(result.Message), "elasticcacheAccount.ResetPassword") + } + + return nil +} + +func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { + if input.Password != nil { + inputPassword := cloudprovider.SCloudElasticCacheAccountResetPasswordInput{} + inputPassword.NewPassword = *input.Password + inputPassword.OldPassword = input.OldPassword + inputPassword.NoPasswordAccess = input.NoPasswordAccess + return self.ResetPassword(inputPassword) + } + + return nil +} + +func (self *SElasticcacheAccount) Delete() error { + return cloudprovider.ErrNotSupported +} diff --git a/pkg/multicloud/hcso/elasticcache_acl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_acl.go similarity index 100% rename from pkg/multicloud/hcso/elasticcache_acl.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_acl.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_backup.go new file mode 100644 index 0000000000..2709c87d0c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_backup.go @@ -0,0 +1,139 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html +type SElasticcacheBackup struct { + multicloud.SElasticcacheBackupBase + huawei.HuaweiTags + + cacheDB *SElasticcache + + Status string `json:"status"` + Remark string `json:"remark"` + Period string `json:"period"` + Progress string `json:"progress"` + SizeByte int64 `json:"size"` + InstanceID string `json:"instance_id"` + BackupID string `json:"backup_id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + ExecutionAt time.Time `json:"execution_at"` + BackupType string `json:"backup_type"` + BackupName string `json:"backup_name"` + ErrorCode string `json:"error_code"` + IsSupportRestore string `json:"is_support_restore"` +} + +func (self *SElasticcacheBackup) GetId() string { + return self.BackupID +} + +func (self *SElasticcacheBackup) GetName() string { + return self.BackupName +} + +func (self *SElasticcacheBackup) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheBackup) Refresh() error { + cache, err := self.cacheDB.GetICloudElasticcacheBackup(self.GetId()) + if err != nil { + return errors.Wrap(err, "ElasticcacheBackup.Refresh.GetICloudElasticcacheBackup") + } + + err = jsonutils.Update(self, cache) + if err != nil { + return errors.Wrap(err, "ElasticcacheBackup.Refresh.Update") + } + + return nil +} + +func (self *SElasticcacheBackup) GetStatus() string { + switch self.Status { + case "waiting", "backuping": + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATING + case "succeed": + return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS + case "failed": + return api.ELASTIC_CACHE_BACKUP_STATUS_FAILED + case "expired": + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_EXPIRED + case "deleted": + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_DELETED + default: + return self.Status + } +} + +func (self *SElasticcacheBackup) GetBackupSizeMb() int { + return int(self.SizeByte / 1024 / 1024) +} + +func (self *SElasticcacheBackup) GetBackupType() string { + switch self.BackupType { + case "manual": + return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL + case "auto": + return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED + default: + return self.BackupType + } + +} + +func (self *SElasticcacheBackup) GetBackupMode() string { + return "" +} + +func (self *SElasticcacheBackup) GetDownloadURL() string { + return "" +} + +func (self *SElasticcacheBackup) GetStartTime() time.Time { + return self.CreatedAt +} + +func (self *SElasticcacheBackup) GetEndTime() time.Time { + return self.UpdatedAt +} + +func (self *SElasticcacheBackup) Delete() error { + return cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html +func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { + _, err := self.cacheDB.region.ecsClient.Elasticcache.RestoreInstance(instanceId, self.GetId()) + if err != nil { + return nil + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_instance.go new file mode 100644 index 0000000000..b11db075cf --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_instance.go @@ -0,0 +1,752 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" + "yunion.io/x/onecloud/pkg/util/billing" +) + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html +type SElasticcache struct { + multicloud.SElasticcacheBase + huawei.HuaweiTags + + region *SRegion + + Name string `json:"name"` + Engine string `json:"engine"` + CapacityGB int `json:"capacity"` + IP string `json:"ip"` + DomainName string `json:"domainName"` + Port int `json:"port"` + Status string `json:"status"` + Libos bool `json:"libos"` + Description string `json:"description"` + Task string `json:"task"` + MaxMemoryMB int `json:"max_memory"` + UsedMemoryMB int `json:"used_memory"` + InstanceID string `json:"instance_id"` + ResourceSpecCode string `json:"resource_spec_code"` + EngineVersion string `json:"engine_version"` + InternalVersion string `json:"internal_version"` + ChargingMode int `json:"charging_mode"` + CapacityMinor string `json:"capacity_minor"` + VpcID string `json:"vpc_id"` + VpcName string `json:"vpc_name"` + TaskStatus string `json:"task_status"` + CreatedAt string `json:"created_at"` + ErrorCode string `json:"error_code"` + UserID string `json:"user_id"` + UserName string `json:"user_name"` + MaintainBegin string `json:"maintain_begin"` + MaintainEnd string `json:"maintain_end"` + NoPasswordAccess string `json:"no_password_access"` + AccessUser string `json:"access_user"` + EnablePublicip bool `json:"enable_publicip"` + PublicipID string `json:"publicip_id"` + PublicipAddress string `json:"publicip_address"` + EnableSSL bool `json:"enable_ssl"` + ServiceUpgrade bool `json:"service_upgrade"` + ServiceTaskID string `json:"service_task_id"` + IsFree string `json:"is_free"` + EnterpriseProjectID string `json:"enterprise_project_id"` + AvailableZones []string `json:"available_zones"` + SubnetID string `json:"subnet_id"` + SecurityGroupID string `json:"security_group_id"` + BackendAddrs []string `json:"backend_addrs"` + ProductID string `json:"product_id"` + SecurityGroupName string `json:"security_group_name"` + SubnetName string `json:"subnet_name"` + OrderID string `json:"order_id"` + SubnetCIDR string `json:"subnet_cidr"` + InstanceBackupPolicy string `json:"instance_backup_policy"` + EnterpriseProjectName string `json:"enterprise_project_name"` +} + +func (self *SElasticcache) GetId() string { + return self.InstanceID +} + +func (self *SElasticcache) GetName() string { + return self.Name +} + +func (self *SElasticcache) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcache) GetProjectId() string { + return self.EnterpriseProjectID +} + +func (self *SElasticcache) Refresh() error { + cache, err := self.region.GetElasticCache(self.GetId()) + if err != nil { + return errors.Wrap(err, "Elasticcache.Refresh.GetElasticCache") + } + + err = jsonutils.Update(self, cache) + if err != nil { + return errors.Wrap(err, "Elasticcache.Refresh.Update") + } + + return nil +} + +func (self *SElasticcache) GetStatus() string { + switch self.Status { + case "RUNNING": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "CREATING": + return api.ELASTIC_CACHE_STATUS_DEPLOYING + case "CREATEFAILED": + return api.ELASTIC_CACHE_STATUS_CREATE_FAILED + case "ERROR": + return api.ELASTIC_CACHE_STATUS_ERROR + case "RESTARTING": + return api.ELASTIC_CACHE_STATUS_RESTARTING + case "FROZEN": + return api.ELASTIC_CACHE_STATUS_UNAVAILABLE + case "EXTENDING": + return api.ELASTIC_CACHE_STATUS_CHANGING + case "RESTORING": + return api.ELASTIC_CACHE_STATUS_TRANSFORMING // ? + case "FLUSHING": + return api.ELASTIC_CACHE_STATUS_FLUSHING + } + + return "" +} + +func (self *SElasticcache) GetBillingType() string { + // charging_mode “0”:按需计费 “1”:按包年包月计费 + if self.ChargingMode == 1 { + return billing_api.BILLING_TYPE_PREPAID + } else { + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SElasticcache) GetCreatedAt() time.Time { + var createtime time.Time + if len(self.CreatedAt) > 0 { + createtime, _ = time.Parse("2006-01-02T15:04:05.000Z", self.CreatedAt) + } + + return createtime +} + +func (self *SElasticcache) GetExpiredAt() time.Time { + var expiredTime time.Time + return expiredTime +} + +func (self *SElasticcache) GetInstanceType() string { + // todo: ?? + return self.ResourceSpecCode +} + +func (self *SElasticcache) GetCapacityMB() int { + return self.CapacityGB * 1024 +} + +func (self *SElasticcache) GetArchType() string { + /* + 资源规格标识。 + + dcs.single_node:表示实例类型为单机 + dcs.master_standby:表示实例类型为主备 + dcs.cluster:表示实例类型为集群 + */ + if strings.Contains(self.ResourceSpecCode, "single") { + return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE + } else if strings.Contains(self.ResourceSpecCode, "ha") { + return api.ELASTIC_CACHE_ARCH_TYPE_MASTER + } else if strings.Contains(self.ResourceSpecCode, "cluster") { + return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER + } else if strings.Contains(self.ResourceSpecCode, "proxy") { + return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER + } + + return "" +} + +func (self *SElasticcache) GetNodeType() string { + // single(单副本) | double(双副本) + if strings.Contains(self.ResourceSpecCode, "single") { + return "single" + } else { + return "double" + } +} + +func (self *SElasticcache) GetEngine() string { + return self.Engine +} + +func (self *SElasticcache) GetEngineVersion() string { + return self.EngineVersion +} + +func (self *SElasticcache) GetVpcId() string { + return self.VpcID +} + +func (self *SElasticcache) GetZoneId() string { + if len(self.AvailableZones) > 0 { + zone, err := self.region.getZoneById(self.AvailableZones[0]) + if err != nil { + log.Errorf("elasticcache.GetZoneId %s", err) + return "" + } + + return zone.GetGlobalId() + } + + return "" +} + +func (self *SElasticcache) GetNetworkType() string { + return api.LB_NETWORK_TYPE_VPC +} + +func (self *SElasticcache) GetNetworkId() string { + return self.SubnetID +} + +func (self *SElasticcache) GetPrivateDNS() string { + return self.DomainName +} + +func (self *SElasticcache) GetPrivateIpAddr() string { + return self.IP +} + +func (self *SElasticcache) GetPrivateConnectPort() int { + return self.Port +} + +func (self *SElasticcache) GetPublicDNS() string { + return self.PublicipAddress +} + +func (self *SElasticcache) GetPublicIpAddr() string { + return self.PublicipAddress +} + +func (self *SElasticcache) GetPublicConnectPort() int { + return self.Port +} + +func (self *SElasticcache) GetMaintainStartTime() string { + return self.MaintainBegin +} + +func (self *SElasticcache) GetMaintainEndTime() string { + return self.MaintainEnd +} + +func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { + iaccounts := []cloudprovider.ICloudElasticcacheAccount{} + iaccount := &SElasticcacheAccount{cacheDB: self} + iaccounts = append(iaccounts, iaccount) + return iaccounts, nil +} + +func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { + // 华为云使用安全组做访问控制。目前未支持 + return []cloudprovider.ICloudElasticcacheAcl{}, nil +} + +func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { + start := self.GetCreatedAt().Format("20060102150405") + end := time.Now().Format("20060102150405") + backups, err := self.region.GetElasticCacheBackups(self.GetId(), start, end) + if err != nil { + return nil, err + } + + ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) + for i := range backups { + backups[i].cacheDB = self + ibackups[i] = &backups[i] + } + + return ibackups, nil +} + +func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { + parameters, err := self.region.GetElasticCacheParameters(self.GetId()) + if err != nil { + return nil, err + } + + iparameters := make([]cloudprovider.ICloudElasticcacheParameter, len(parameters)) + for i := range parameters { + parameters[i].cacheDB = self + iparameters[i] = ¶meters[i] + } + + return iparameters, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html +func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) { + params := make(map[string]string) + params["instance_id"] = instanceId + params["beginTime"] = startTime + params["endTime"] = endTime + + backups := make([]SElasticcacheBackup, 0) + err := doListAll(self.ecsClient.Elasticcache.ListBackups, params, &backups) + if err != nil { + return nil, err + } + + return backups, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html +func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { + params := make(map[string]string) + params["instance_id"] = instanceId + + parameters := make([]SElasticcacheParameter, 0) + err := doListAll(self.ecsClient.Elasticcache.ListParameters, params, ¶meters) + if err != nil { + return nil, err + } + + return parameters, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423044.html +func (self *SRegion) GetElasticCaches() ([]SElasticcache, error) { + params := make(map[string]string) + caches := make([]SElasticcache, 0) + err := doListAll(self.ecsClient.Elasticcache.List, params, &caches) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCaches") + } + + for i := range caches { + cache, err := self.GetElasticCache(caches[i].GetId()) + if err != nil { + return nil, err + } else { + caches[i] = *cache + } + + caches[i].region = self + } + + return caches, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html +func (self *SRegion) GetElasticCache(instanceId string) (*SElasticcache, error) { + cache := SElasticcache{} + err := DoGet(self.ecsClient.Elasticcache.Get, instanceId, nil, &cache) + if err != nil { + return nil, errors.Wrapf(err, "region.GetElasticCache %s", instanceId) + } + + cache.region = self + return &cache, nil +} + +func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { + ec, err := self.GetElasticCache(id) + if err != nil { + return nil, errors.Wrap(err, "region.GetIElasticCacheById.GetElasticCache") + } + + return ec, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423047.html +func (self *SRegion) zoneNameToDcsZoneIds(zoneIds []string) ([]string, error) { + type Z struct { + ID string `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Port string `json:"port"` + ResourceAvailability string `json:"resource_availability"` + } + + rs := []Z{} + err := doListAll(self.ecsClient.DcsAvailableZone.List, nil, &rs) + if err != nil { + return nil, errors.Wrap(err, "region.zoneNameToDcsZoneIds") + } + + zoneMap := map[string]string{} + for i := range rs { + if rs[i].ResourceAvailability == "true" { + zoneMap[rs[i].Code] = rs[i].ID + } + } + + ret := []string{} + for _, zone := range zoneIds { + if id, ok := zoneMap[zone]; ok { + ret = append(ret, id) + } else { + return nil, errors.Wrap(fmt.Errorf("zone %s not found or not available", zone), "region.zoneNameToDcsZoneIds") + } + } + + return ret, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423019.html +func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { + params := jsonutils.NewDict() + params.Set("name", jsonutils.NewString(ec.InstanceName)) + params.Set("engine", jsonutils.NewString(ec.Engine)) + params.Set("engine_version", jsonutils.NewString(ec.EngineVersion)) + params.Set("capacity", jsonutils.NewInt(ec.CapacityGB)) + params.Set("vpc_id", jsonutils.NewString(ec.VpcId)) + if len(ec.SecurityGroupIds) > 0 { + params.Set("security_group_id", jsonutils.NewString(ec.SecurityGroupIds[0])) + } + params.Set("subnet_id", jsonutils.NewString(ec.NetworkId)) + params.Set("product_id", jsonutils.NewString(ec.InstanceType)) + zones, err := self.zoneNameToDcsZoneIds(ec.ZoneIds) + if err != nil { + return nil, err + } + params.Set("available_zones", jsonutils.NewStringArray(zones)) + + if len(ec.ProjectId) > 0 { + params.Set("enterprise_project_id", jsonutils.NewString(ec.ProjectId)) + } + + if len(ec.Password) > 0 { + params.Set("no_password_access", jsonutils.NewString("false")) + params.Set("password", jsonutils.NewString(ec.Password)) + + // todo: 这里换成常量 + if ec.Engine == "Memcache" { + params.Set("access_user", jsonutils.NewString(ec.UserName)) + } + } else { + params.Set("no_password_access", jsonutils.NewString("true")) + } + + if len(ec.EipId) > 0 { + params.Set("enable_publicip", jsonutils.NewString("true")) + params.Set("publicip_id", jsonutils.NewString(ec.EipId)) + // enable_ssl + } else { + params.Set("enable_publicip", jsonutils.NewString("false")) + } + + if len(ec.PrivateIpAddress) > 0 { + params.Set("private_ip", jsonutils.NewString(ec.PrivateIpAddress)) + } + + if len(ec.MaintainBegin) > 0 { + params.Set("maintain_begin", jsonutils.NewString(ec.MaintainBegin)) + params.Set("maintain_end", jsonutils.NewString(ec.MaintainEnd)) + } + + if strings.ToLower(ec.ChargeType) == billing_api.BILLING_TYPE_PREPAID && ec.BillingCycle != nil { + bssParam := jsonutils.NewDict() + bssParam.Set("charging_mode", jsonutils.NewString("prePaid")) + bssParam.Set("is_auto_pay", jsonutils.NewString("true")) + bssParam.Set("is_auto_renew", jsonutils.NewString(fmt.Sprintf("%v", ec.BillingCycle.AutoRenew))) + if ec.BillingCycle.GetMonths() >= 1 && ec.BillingCycle.GetMonths() >= 9 { + bssParam.Set("period_type", jsonutils.NewString("month")) + bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetMonths()))) + } else if ec.BillingCycle.GetYears() >= 1 && ec.BillingCycle.GetYears() <= 3 { + bssParam.Set("period_type", jsonutils.NewString("year")) + bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetYears()))) + } else { + return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") + } + + params.Set("bss_param", bssParam) + } + + ret := &SElasticcache{} + err = DoCreate(self.ecsClient.Elasticcache.Create, params, ret) + if err != nil { + return nil, errors.Wrap(err, "region.CreateIElasticcaches") + } + + ret.region = self + return ret, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html +func (self *SElasticcache) Restart() error { + resp, err := self.region.ecsClient.Elasticcache.Restart(self.GetId()) + if err != nil { + return errors.Wrap(err, "elasticcache.Restart") + } + + rets, err := resp.GetArray("results") + if err != nil { + return errors.Wrap(err, "elasticcache.results") + } + + for _, r := range rets { + if ret, _ := r.GetString("result"); ret != "success" { + return fmt.Errorf("elasticcache.Restart failed") + } + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423022.html +func (self *SElasticcache) Delete() error { + err := DoDelete(self.region.ecsClient.Elasticcache.Delete, self.GetId(), nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.Delete") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html +func (self *SElasticcache) ChangeInstanceSpec(spec string) error { + segs := strings.Split(spec, ":") + if len(segs) < 2 { + return fmt.Errorf("elasticcache.ChangeInstanceSpec invalid sku %s", spec) + } + + if !strings.HasPrefix(segs[1], "m") || !strings.HasSuffix(segs[1], "g") { + return fmt.Errorf("elasticcache.ChangeInstanceSpec sku %s memeory size is invalid.", spec) + } + + newCapacity := segs[1][1 : len(segs[1])-1] + capacity, err := strconv.Atoi(newCapacity) + if err != nil { + return errors.Wrap(fmt.Errorf("invalid sku capacity %s", spec), "Elasticcache.ChangeInstanceSpec") + } + + _, err = self.region.ecsClient.Elasticcache.ChangeInstanceSpec(self.GetId(), segs[0], int64(capacity)) + if err != nil { + return errors.Wrap(err, "elasticcache.ChangeInstanceSpec") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html +func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { + params := jsonutils.NewDict() + params.Set("maintain_begin", jsonutils.NewString(maintainStartTime)) + params.Set("maintain_end", jsonutils.NewString(maintainEndTime)) + err := DoUpdate(self.region.ecsClient.Elasticcache.Update, self.GetId(), params, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.SetMaintainTime") + } + + return nil +} + +// https://support.huaweicloud.com/usermanual-dcs/dcs-zh-ug-180314001.html +// 目前只有Redis3.0版本密码模式的实例支持通过公网访问Redis实例,其他版本暂不支持公网访问。 +// todo: 目前没找到api +func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +// todo: 目前没找到api +func (self *SElasticcache) ReleasePublicConnection() error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { + return nil, cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html + +func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423029.html +func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { + params := jsonutils.NewDict() + params.Set("redis_config", config) + err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423033.html +func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func backupPeriodTrans(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) *jsonutils.JSONArray { + segs := strings.Split(config.PreferredBackupPeriod, ",") + ret := jsonutils.NewArray() + for _, seg := range segs { + switch seg { + case "Monday": + ret.Add(jsonutils.NewString("1")) + case "Tuesday": + ret.Add(jsonutils.NewString("2")) + case "Wednesday": + ret.Add(jsonutils.NewString("3")) + case "Thursday": + ret.Add(jsonutils.NewString("4")) + case "Friday": + ret.Add(jsonutils.NewString("5")) + case "Saturday": + ret.Add(jsonutils.NewString("6")) + case "Sunday": + ret.Add(jsonutils.NewString("7")) + } + } + + return ret +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html +func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { + params := jsonutils.NewDict() + policy := jsonutils.NewDict() + policy.Set("save_days", jsonutils.NewInt(int64(config.BackupReservedDays))) + policy.Set("backup_type", jsonutils.NewString(config.BackupType)) + plan := jsonutils.NewDict() + backTime := strings.ReplaceAll(config.PreferredBackupTime, "Z", "") + backupPeriod := backupPeriodTrans(config) + plan.Set("begin_at", jsonutils.NewString(backTime)) + plan.Set("period_type", jsonutils.NewString("weekly")) + plan.Set("backup_at", backupPeriod) + policy.Set("periodical_backup_plan", plan) + params.Set("instance_backup_policy", policy) + err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html +// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 +func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { + resp, err := self.region.ecsClient.Elasticcache.Flush(self.GetId()) + if err != nil { + return errors.Wrap(err, "elasticcache.FlushInstance") + } + + rets, err := resp.GetArray("results") + if err != nil { + return errors.Wrap(err, "elasticcache.FlushInstance") + } + + for _, r := range rets { + if ret, _ := r.GetString("result"); ret != "success" { + return fmt.Errorf("elasticcache.FlushInstance failed") + } + } + + return nil +} + +// SElasticcacheAccount => ResetPassword +func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool, password string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetAuthMode() string { + switch self.NoPasswordAccess { + case "true": + return "off" + default: + return "on" + } +} + +func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { + accounts, err := self.GetICloudElasticcacheAccounts() + if err != nil { + return nil, errors.Wrap(err, "Elasticcache.GetICloudElasticcacheAccount.Accounts") + } + + for i := range accounts { + account := accounts[i] + if account.GetGlobalId() == accountId { + return account, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { + backups, err := self.GetICloudElasticcacheBackups() + if err != nil { + return nil, err + } + + for _, backup := range backups { + if backup.GetId() == backupId { + return backup, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (instance *SElasticcache) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { + return errors.Wrap(cloudprovider.ErrNotSupported, "UpdateSecurityGroups") +} + +func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) SetAutoRenew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_parameter.go new file mode 100644 index 0000000000..d63e718b55 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/elasticcache_parameter.go @@ -0,0 +1,79 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html +type SElasticcacheParameter struct { + multicloud.SElasticcacheParameterBase + huawei.HuaweiTags + + cacheDB *SElasticcache + + Description string `json:"description"` + ParamID int64 `json:"param_id"` + ParamName string `json:"param_name"` + ParamValue string `json:"param_value"` + DefaultValue string `json:"default_value"` + ValueType string `json:"value_type"` + ValueRange string `json:"value_range"` +} + +func (self *SElasticcacheParameter) GetId() string { + return fmt.Sprintf("%d", self.ParamID) +} + +func (self *SElasticcacheParameter) GetName() string { + return self.ParamName +} + +func (self *SElasticcacheParameter) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.cacheDB.InstanceID, self.GetId()) +} + +func (self *SElasticcacheParameter) GetStatus() string { + return api.ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE +} + +func (self *SElasticcacheParameter) GetParameterKey() string { + return self.ParamName +} + +func (self *SElasticcacheParameter) GetParameterValue() string { + return self.ParamValue +} + +func (self *SElasticcacheParameter) GetParameterValueRange() string { + return self.Description +} + +func (self *SElasticcacheParameter) GetDescription() string { + return self.ValueRange +} + +func (self *SElasticcacheParameter) GetModifiable() bool { + return true +} + +func (self *SElasticcacheParameter) GetForceRestart() bool { + return false +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/enterpriceprojects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/enterpriceprojects.go new file mode 100644 index 0000000000..a7171fe95a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/enterpriceprojects.go @@ -0,0 +1,115 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +// https://support.huaweicloud.com/api-em/zh-cn_topic_0121230880.html +type SEnterpriseProject struct { + multicloud.SProjectBase + huawei.HuaweiTags + + Id string + Name string + Description string + Status int + CreatedAt time.Time + UpdatedAt time.Time +} + +func (self *SHuaweiClient) GetEnterpriseProjects() ([]SEnterpriseProject, error) { + projects := []SEnterpriseProject{} + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + err = doListAllWithOffset(client.EnterpriseProjects.List, map[string]string{}, &projects) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithOffset") + } + return projects, nil +} + +func (ep *SEnterpriseProject) GetId() string { + return ep.Id +} + +func (ep *SEnterpriseProject) GetGlobalId() string { + return ep.Id +} + +func (ep *SEnterpriseProject) GetStatus() string { + if ep.Status == 1 { + return api.EXTERNAL_PROJECT_STATUS_AVAILABLE + } + return api.EXTERNAL_PROJECT_STATUS_UNAVAILABLE +} + +func (ep *SEnterpriseProject) GetName() string { + return ep.Name +} + +func (self *SHuaweiClient) CreateExterpriseProject(name, desc string) (*SEnterpriseProject, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + params := map[string]string{ + "name": name, + } + if len(desc) > 0 { + params["description"] = desc + } + resp, err := client.EnterpriseProjects.Create(jsonutils.Marshal(params)) + if err != nil { + if strings.Contains(err.Error(), "EPS.0004") { + return nil, cloudprovider.ErrNotSupported + } + return nil, errors.Wrap(err, "EnterpriseProjects.Create") + } + project := &SEnterpriseProject{} + err = resp.Unmarshal(&project) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return project, nil +} + +func (self *SHuaweiClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return self.CreateExterpriseProject(name, "") +} + +func (self *SHuaweiClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { + projects, err := self.GetEnterpriseProjects() + if err != nil { + return nil, errors.Wrap(err, "GetProjects") + } + ret := []cloudprovider.ICloudProject{} + for i := range projects { + ret = append(ret, &projects[i]) + } + return ret, nil +} diff --git a/pkg/multicloud/hcso/hcso.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/hcso.go similarity index 99% rename from pkg/multicloud/hcso/hcso.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/hcso.go index 161764ca45..b200bb0518 100644 --- a/pkg/multicloud/hcso/hcso.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/hcso.go @@ -28,7 +28,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/gotypes" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/host.go new file mode 100644 index 0000000000..a43f96a592 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/host.go @@ -0,0 +1,349 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone + vms []SInstance + + // 华为私有云没有直接列出host的接口,所有账号下的host都是通过VM反向解析出来的 + // 当账号下没有虚拟机时,如果没有host,会导致调度找不到可用的HOST。 + // 因此,为了避免上述情况始终会在每个zone下返回一台虚拟的host + IsFake bool + projectId string + Id string + Name string +} + +func (self *SHost) GetId() string { + return self.Id +} + +func (self *SHost) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + + return self.Id +} + +func (self *SHost) GetGlobalId() string { + return self.Id +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) Refresh() error { + _, err := self.getVMs() + return errors.Wrap(err, "getVMs") +} + +func (self *SHost) IsEmulated() bool { + return self.IsFake +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + var vms []SInstance + var err error + if self.vms != nil { + vms = self.vms + } else { + vms, err = self.getVMs() + if err != nil { + return nil, err + } + } + + ret := make([]cloudprovider.ICloudVM, len(vms)) + for i := range vms { + vm := vms[i] + vm.host = self + ret[i] = &vm + } + + return ret, nil +} + +func (self *SHost) getVMs() ([]SInstance, error) { + vms, err := self.zone.region.GetInstances() + if err != nil { + return nil, errors.Wrap(err, "GetInstances") + } + + ret := []SInstance{} + for i := range vms { + vm := vms[i] + if vm.OSEXTAZAvailabilityZone == self.GetId() && vm.HostID == self.GetId() { + vm.host = self + ret = append(ret, vm) + } + } + + self.vms = ret + return ret, nil +} + +func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := self.zone.region.GetInstanceByID(id) + if vm.HostID != self.GetId() { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetInstanceByID") + } + + vm.host = self + return &vm, err +} + +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 api.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_HUAWEI), "manufacture") + info.Add(jsonutils.NewString(self.GetId()), "id") + info.Add(jsonutils.NewString(self.GetName()), "name") + return info +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetCpuCount() int { + 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 api.DISK_TYPE_HYBRID +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_HCSO +} + +func (self *SHost) GetIsMaintenance() bool { + return false +} + +func (self *SHost) GetVersion() string { + return HUAWEI_API_VERSION +} + +func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) { + instance, err := self.zone.region.GetInstanceByID(instanceId) + if err != nil { + return nil, err + } + + if instance.HostID != self.GetId() { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetInstanceByID") + } + + instance.host = self + return &instance, nil +} + +func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + vmId, err := self._createVM( + desc.Name, desc.ExternalImageId, desc.SysDisk, + desc.Cpu, desc.MemoryMB, desc.InstanceType, + desc.ExternalNetworkId, desc.IpAddr, + desc.Description, desc.Account, + desc.Password, desc.DataDisks, + desc.PublicKey, desc.ExternalSecgroupId, + desc.UserData, desc.BillingCycle, desc.ProjectId, desc.Tags) + if err != nil { + return nil, err + } + + // VM实际调度到的host, 可能不是当前host.因此需要改写host信息 + vm, err := self.zone.region.GetIVMById(vmId) + if err != nil { + return nil, err + } + + return vm, err +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, + networkId string, ipAddr string, desc string, account string, passwd string, + diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string, + userData string, bc *billing.SBillingCycle, projectId string, tags map[string]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") + } + + // 同步keypair + var err error + keypair := "" + if len(publicKey) > 0 { + 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 %s fail %s", imgId, err) + return "", err + } + if img.Status != ImageStatusActive { + log.Errorf("image %s status %s", imgId, img.Status) + return "", fmt.Errorf("image not ready") + } + // passwd, windows机型直接使用密码比较方便 + if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(passwd) > 0 { + keypair = "" + } + + if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) { + if u, err := updateWindowsUserData(userData, img.OSVersion, account, passwd); err == nil { + userData = u + } else { + return "", errors.Wrap(err, "SHost.CreateVM.updateWindowsUserData") + } + } + + disks := make([]SDisk, len(diskSizes)+1) + disks[0].SizeGB = img.SizeGB + if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.SizeGB { + disks[0].SizeGB = sysDisk.SizeGB + } + disks[0].VolumeType = sysDisk.StorageType + + for i, dataDisk := range diskSizes { + disks[i+1].SizeGB = dataDisk.SizeGB + disks[i+1].VolumeType = dataDisk.StorageType + } + + _, err = self.zone.region.GetSecurityGroupDetails(secgroupId) + if err != nil { + return "", errors.Wrap(err, "SHost.CreateVM.GetSecurityGroupDetails") + } + + // 创建实例 + if len(instanceType) > 0 { + log.Debugf("Try instancetype : %s", instanceType) + vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) + if err != nil { + log.Errorf("Failed for %s: %s", instanceType, err) + return "", fmt.Errorf("create %s failed:%s", instanceType, ErrMessage(err)) + } else { + return vmId, nil + } + } + + // 匹配实例类型 + instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, self.zone.GetId()) + if err != nil { + return "", err + } + if len(instanceTypes) == 0 { + return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB) + } + + var vmId string + for _, instType := range instanceTypes { + instanceTypeId := instType.Name + log.Debugf("Try instancetype : %s", instanceTypeId) + vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) + if err != nil { + log.Errorf("Failed for %s: %s", instanceTypeId, err) + } else { + return vmId, nil + } + } + + return "", fmt.Errorf("create failed: %s", ErrMessage(err)) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/huawei.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/huawei.go new file mode 100644 index 0000000000..e47f1ac57d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/huawei.go @@ -0,0 +1,554 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "net/http" + "strings" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/timeutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/auth/credentials" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" +) + +/* +待解决问题: +2.VM密码登录不成功(ubuntu不行,centos可以) +3.实例绑定eip 查不出来eip? +*/ + +const ( + CLOUD_PROVIDER_HUAWEI = api.CLOUD_PROVIDER_HCSO + CLOUD_PROVIDER_HUAWEI_CN = "华为云Stack" + CLOUD_PROVIDER_HUAWEI_EN = "HCSO" + + HUAWEI_API_VERSION = "" +) + +var HUAWEI_REGION_CACHES = map[string]userRegionsCache{} + +type userRegionsCache struct { + UserId string + ExpireAt time.Time + Regions []SRegion +} + +type HuaweiClientConfig struct { + cpcfg cloudprovider.ProviderConfig + endpoints *cloudprovider.SHCSOEndpoints + + projectId string // 华为云项目ID. + accessKey string + accessSecret string + + debug bool +} + +func NewHuaweiClientConfig(accessKey, accessSecret, projectId string, endpoints *cloudprovider.SHCSOEndpoints) *HuaweiClientConfig { + cfg := &HuaweiClientConfig{ + projectId: projectId, + accessKey: accessKey, + accessSecret: accessSecret, + endpoints: endpoints, + } + + return cfg +} + +func (cfg *HuaweiClientConfig) CloudproviderConfig(cpcfg cloudprovider.ProviderConfig) *HuaweiClientConfig { + cfg.cpcfg = cpcfg + return cfg +} + +func (cfg *HuaweiClientConfig) Debug(debug bool) *HuaweiClientConfig { + cfg.debug = debug + return cfg +} + +type SHuaweiClient struct { + *HuaweiClientConfig + + signer auth.Signer + + isMainProject bool // whether the project is the main project in the region + + ownerId string + ownerName string + ownerCreateTime time.Time + + iregions []cloudprovider.ICloudRegion + iBuckets []cloudprovider.ICloudBucket + + projects []SProject + regions []SRegion + + httpClient *http.Client +} + +// 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成,通过"/"分割。 +// 初次导入Subaccount时,参数account对应cloudaccounts表中的account字段,即accesskey。此时projectID为空, +// 只能进行同步子账号、查询region列表等projectId无关的操作。 +func NewHuaweiClient(cfg *HuaweiClientConfig) (*SHuaweiClient, error) { + client := SHuaweiClient{ + HuaweiClientConfig: cfg, + } + + err := client.init() + if err != nil { + return nil, err + } + return &client, nil +} + +func (self *SHuaweiClient) init() error { + err := self.fetchRegions() + if err != nil { + return err + } + err = self.initSigner() + if err != nil { + return errors.Wrap(err, "initSigner") + } + err = self.initOwner() + if err != nil { + return errors.Wrap(err, "fetchOwner") + } + if self.debug { + log.Debugf("OwnerId: %s name: %s", self.ownerId, self.ownerName) + } + return nil +} + +func (self *SHuaweiClient) initSigner() error { + var err error + cred := credentials.NewAccessKeyCredential(self.accessKey, self.accessKey) + self.signer, err = auth.NewSignerWithCredential(cred) + if err != nil { + return err + } + return nil +} + +func (self *SHuaweiClient) newRegionAPIClient(regionId string) (*client.Client, error) { + cli, err := client.NewClientWithAccessKey(regionId, self.ownerId, self.projectId, self.accessKey, self.accessSecret, self.debug, self.cpcfg.DefaultRegion, self.endpoints) + if err != nil { + return nil, err + } + + httpClient := self.cpcfg.AdaptiveTimeoutHttpClient() + ts, _ := httpClient.Transport.(*http.Transport) + httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { + if self.cpcfg.ReadOnly { + if req.Method == "GET" { + return nil, nil + } + return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) + } + return nil, nil + }) + cli.SetHttpClient(httpClient) + + return cli, nil +} + +func (self *SHuaweiClient) newGeneralAPIClient() (*client.Client, error) { + cli, err := client.NewClientWithAccessKey(self.cpcfg.DefaultRegion, self.ownerId, "", self.accessKey, self.accessSecret, self.debug, self.cpcfg.DefaultRegion, self.endpoints) + if err != nil { + return nil, err + } + + httpClient := self.cpcfg.AdaptiveTimeoutHttpClient() + ts, _ := httpClient.Transport.(*http.Transport) + httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { + if self.cpcfg.ReadOnly { + if req.Method == "GET" { + return nil, nil + } + return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) + } + return nil, nil + }) + cli.SetHttpClient(httpClient) + + return cli, nil +} + +func (self *SHuaweiClient) fetchRegions() error { + huawei, _ := self.newGeneralAPIClient() + if self.regions == nil { + userId, err := self.GetUserId() + if err != nil { + return errors.Wrap(err, "GetUserId") + } + + if regionsCache, ok := HUAWEI_REGION_CACHES[userId]; !ok || regionsCache.ExpireAt.Sub(time.Now()).Seconds() > 0 { + regions := make([]SRegion, 0) + err := doListAll(huawei.Regions.List, nil, ®ions) + if err != nil { + return errors.Wrap(err, "Regions.List") + } + + HUAWEI_REGION_CACHES[userId] = userRegionsCache{ExpireAt: time.Now().Add(24 * time.Hour), UserId: userId, Regions: regions} + } + + self.regions = HUAWEI_REGION_CACHES[userId].Regions + } + + filtedRegions := make([]SRegion, 0) + if len(self.projectId) > 0 { + project, err := self.GetProjectById(self.projectId) + if err != nil { + return err + } + + regionId := strings.Split(project.Name, "_")[0] + for _, region := range self.regions { + if region.ID == regionId { + filtedRegions = append(filtedRegions, region) + } + } + if regionId == project.Name { + self.isMainProject = true + } + } else { + filtedRegions = self.regions + } + + self.iregions = make([]cloudprovider.ICloudRegion, len(filtedRegions)) + for i := 0; i < len(filtedRegions); i += 1 { + filtedRegions[i].client = self + _, err := filtedRegions[i].getECSClient() + if err != nil { + return err + } + self.iregions[i] = &filtedRegions[i] + } + return nil +} + +func (self *SHuaweiClient) invalidateIBuckets() { + self.iBuckets = nil +} + +func (self *SHuaweiClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) { + if self.iBuckets == nil { + err := self.fetchBuckets() + if err != nil { + return nil, errors.Wrap(err, "fetchBuckets") + } + } + return self.iBuckets, nil +} + +func getOBSEndpoint(regionId string) string { + return fmt.Sprintf("obs.%s.myhuaweicloud.com", regionId) +} + +func (client *SHuaweiClient) getOBSClient(regionId string) (*obs.ObsClient, error) { + endpoint := client.endpoints.GetEndpoint(client.cpcfg.DefaultRegion, "obs", regionId) + return obs.New(client.accessKey, client.accessSecret, endpoint) +} + +func (self *SHuaweiClient) fetchBuckets() error { + obscli, err := self.getOBSClient(self.cpcfg.DefaultRegion) + if err != nil { + return errors.Wrap(err, "getOBSClient") + } + input := &obs.ListBucketsInput{QueryLocation: true} + output, err := obscli.ListBuckets(input) + if err != nil { + return errors.Wrap(err, "obscli.ListBuckets") + } + self.ownerId = output.Owner.ID + + ret := make([]cloudprovider.ICloudBucket, 0) + for i := range output.Buckets { + bInfo := output.Buckets[i] + region, err := self.getIRegionByRegionId(bInfo.Location) + if err != nil { + log.Errorf("fail to find region %s", bInfo.Location) + continue + } + b := SBucket{ + region: region.(*SRegion), + + Name: bInfo.Name, + Location: bInfo.Location, + CreationDate: bInfo.CreationDate, + } + ret = append(ret, &b) + } + self.iBuckets = ret + return nil +} + +func (self *SHuaweiClient) GetCloudRegionExternalIdPrefix() string { + if len(self.projectId) > 0 { + return self.iregions[0].GetGlobalId() + } else { + return CLOUD_PROVIDER_HUAWEI + } +} + +func (self *SHuaweiClient) UpdateAccount(accessKey, secret string) error { + if self.accessKey != accessKey || self.accessSecret != secret { + self.accessKey = accessKey + self.accessSecret = secret + return self.fetchRegions() + } else { + return nil + } +} + +func (self *SHuaweiClient) 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 *SHuaweiClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + projects, err := self.fetchProjects() + if err != nil { + return nil, err + } + + // https://support.huaweicloud.com/api-iam/zh-cn_topic_0074171149.html + subAccounts := make([]cloudprovider.SSubAccount, 0) + for i := range projects { + project := projects[i] + // name 为MOS的project是华为云内部的一个特殊project。不需要同步到本地 + if strings.ToLower(project.Name) == "mos" { + continue + } + + s := cloudprovider.SSubAccount{ + Name: fmt.Sprintf("%s-%s", self.cpcfg.Name, project.Name), + Account: fmt.Sprintf("%s/%s", self.accessKey, project.ID), + HealthStatus: project.GetHealthStatus(), + } + + subAccounts = append(subAccounts, s) + } + + return subAccounts, nil +} + +func (client *SHuaweiClient) GetAccountId() string { + return client.ownerId +} + +func (client *SHuaweiClient) GetIamLoginUrl() string { + return fmt.Sprintf("https://auth.huaweicloud.com/authui/login.html?account=%s#/login", client.ownerName) +} + +func (self *SHuaweiClient) GetIRegions() []cloudprovider.ICloudRegion { + return self.iregions +} + +func (self *SHuaweiClient) getIRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) { + for i := 0; i < len(self.iregions); i += 1 { + log.Debugf("%d ID: %s", i, self.iregions[i].GetId()) + if self.iregions[i].GetId() == id { + return self.iregions[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHuaweiClient) 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 *SHuaweiClient) GetRegion(regionId string) *SRegion { + if len(regionId) == 0 { + regionId = self.cpcfg.DefaultRegion + } + + for i := 0; i < len(self.iregions); i += 1 { + if self.iregions[i].GetId() == regionId { + return self.iregions[i].(*SRegion) + } + } + return nil +} + +func (self *SHuaweiClient) 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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHuaweiClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + for i := 0; i < len(self.iregions); i += 1 { + ivpc, err := self.iregions[i].GetIVpcById(id) + if err == nil { + return ivpc, nil + } else if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHuaweiClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + for i := 0; i < len(self.iregions); i += 1 { + istorage, err := self.iregions[i].GetIStorageById(id) + if err == nil { + return istorage, nil + } else if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +// 总账户余额 +type SAccountBalance struct { + AvailableAmount float64 + CreditAmount float64 + DesignatedAmount float64 +} + +// 账户余额 +// https://support.huaweicloud.com/api-oce/zh-cn_topic_0109685133.html +type SBalance struct { + Amount float64 `json:"amount"` + Currency string `json:"currency"` + AccountID string `json:"account_id"` + AccountType int64 `json:"account_type"` + DesignatedAmount float64 `json:"designated_amount,omitempty"` + CreditAmount float64 `json:"credit_amount,omitempty"` + MeasureUnit int64 `json:"measure_unit"` +} + +func (self *SHuaweiClient) GetVersion() string { + return HUAWEI_API_VERSION +} + +func (self *SHuaweiClient) GetAccessEnv() string { + return "" +} + +func (self *SHuaweiClient) GetCapabilities() []string { + caps := []string{ + cloudprovider.CLOUD_CAPABILITY_PROJECT, + cloudprovider.CLOUD_CAPABILITY_COMPUTE, + cloudprovider.CLOUD_CAPABILITY_NETWORK, + cloudprovider.CLOUD_CAPABILITY_EIP, + cloudprovider.CLOUD_CAPABILITY_LOADBALANCER, + // cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE, + cloudprovider.CLOUD_CAPABILITY_QUOTA + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_RDS, + cloudprovider.CLOUD_CAPABILITY_CACHE, + cloudprovider.CLOUD_CAPABILITY_EVENT, + cloudprovider.CLOUD_CAPABILITY_CLOUDID, + cloudprovider.CLOUD_CAPABILITY_SAML_AUTH, + cloudprovider.CLOUD_CAPABILITY_NAT, + cloudprovider.CLOUD_CAPABILITY_NAS, + cloudprovider.CLOUD_CAPABILITY_MODELARTES, + } + // huawei objectstore is shared across projects(subscriptions) + // to avoid multiple project access the same bucket + // only main project is allow to access objectstore bucket + if self.isMainProject { + caps = append(caps, cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE) + } + return caps +} + +func (self *SHuaweiClient) GetUserId() (string, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return "", errors.Wrap(err, "SHuaweiClient.GetUserId.newGeneralAPIClient") + } + + type cred struct { + UserId string `json:"user_id"` + } + + ret := &cred{} + err = DoGet(client.Credentials.Get, self.accessKey, nil, ret) + if err != nil { + return "", errors.Wrap(err, "SHuaweiClient.GetUserId.DoGet") + } + + return ret.UserId, nil +} + +// owner id == domain_id == account id +func (self *SHuaweiClient) GetOwnerId() (string, error) { + userId, err := self.GetUserId() + if err != nil { + return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.GetUserId") + } + + client, err := self.newGeneralAPIClient() + if err != nil { + return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.newGeneralAPIClient") + } + + type user struct { + DomainId string `json:"domain_id"` + Name string `json:"name"` + CreateTime string + } + + ret := &user{} + err = DoGet(client.Users.Get, userId, nil, ret) + if err != nil { + return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.DoGet") + } + self.ownerName = ret.Name + // 2021-02-02 02:43:28.0 + self.ownerCreateTime, _ = timeutils.ParseTimeStr(strings.TrimSuffix(ret.CreateTime, ".0")) + return ret.DomainId, nil +} + +func (self *SHuaweiClient) GetSamlEntityId() string { + return fmt.Sprintf("auth.%s", self.endpoints.EndpointDomain) +} + +func (self *SHuaweiClient) initOwner() error { + ownerId, err := self.GetOwnerId() + if err != nil { + return errors.Wrap(err, "SHuaweiClient.initOwner") + } + + self.ownerId = ownerId + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/image.go new file mode 100644 index 0000000000..507ca4c194 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/image.go @@ -0,0 +1,472 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type TImageOwnerType string + +const ( + ImageOwnerPublic TImageOwnerType = "gold" // 公共镜像:gold + ImageOwnerSelf TImageOwnerType = "private" // 私有镜像:private + ImageOwnerShared TImageOwnerType = "shared" // 共享镜像:shared + + EnvFusionCompute = "FusionCompute" + EnvIronic = "Ironic" +) + +const ( + ImageStatusQueued = "queued" // queued:表示镜像元数据已经创建成功,等待上传镜像文件。 + ImageStatusSaving = "saving" // saving:表示镜像正在上传文件到后端存储。 + ImageStatusDeleted = "deleted" // deleted:表示镜像已经删除。 + ImageStatusKilled = "killed" // killed:表示镜像上传错误。 + ImageStatusActive = "active" // active:表示镜像可以正常使用 +) + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091565.html +type SImage struct { + multicloud.SImageBase + huawei.HuaweiTags + storageCache *SStoragecache + + // normalized image info + imgInfo *imagetools.ImageInfo + + Schema string `json:"schema"` + MinDiskGB int64 `json:"min_disk"` + CreatedAt time.Time `json:"created_at"` + ImageSourceType string `json:"__image_source_type"` + ContainerFormat string `json:"container_format"` + File string `json:"file"` + UpdatedAt time.Time `json:"updated_at"` + Protected bool `json:"protected"` + Checksum string `json:"checksum"` + ID string `json:"id"` + Isregistered string `json:"__isregistered"` + MinRamMB int `json:"min_ram"` + Lazyloading string `json:"__lazyloading"` + Owner string `json:"owner"` + OSType string `json:"__os_type"` + Imagetype string `json:"__imagetype"` + Visibility string `json:"visibility"` + VirtualEnvType string `json:"virtual_env_type"` + Platform string `json:"__platform"` + SizeGB int `json:"size"` + ImageSize int64 `json:"__image_size"` + OSBit string `json:"__os_bit"` + OSVersion string `json:"__os_version"` + Name string `json:"name"` + Self string `json:"self"` + DiskFormat string `json:"disk_format"` + Status string `json:"status"` + SupportKVMFPGAType string `json:"__support_kvm_fpga_type"` + SupportKVMNVMEHIGHIO string `json:"__support_nvme_highio"` + SupportLargeMemory string `json:"__support_largememory"` + SupportDiskIntensive string `json:"__support_diskintensive"` + SupportHighPerformance string `json:"__support_highperformance"` + SupportXENGPUType string `json:"__support_xen_gpu_type"` + SupportKVMGPUType string `json:"__support_kvm_gpu_type"` + SupportGPUT4 string `json:"__support_gpu_t4"` + SupportKVMAscend310 string `json:"__support_kvm_ascend_310"` + SupportArm string `json:"__support_arm"` +} + +func (self *SImage) GetMinRamSizeMb() int { + return self.MinRamMB +} + +func (self *SImage) GetId() string { + return self.ID +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (self *SImage) GetGlobalId() string { + return self.ID +} + +func (self *SImage) GetStatus() string { + switch self.Status { + case ImageStatusQueued: + return api.CACHED_IMAGE_STATUS_CACHING + case ImageStatusActive: + return api.CACHED_IMAGE_STATUS_ACTIVE + case ImageStatusKilled: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + default: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (self *SImage) GetImageStatus() string { + switch self.Status { + case ImageStatusQueued: + return cloudprovider.IMAGE_STATUS_QUEUED + case ImageStatusActive: + return cloudprovider.IMAGE_STATUS_ACTIVE + case ImageStatusKilled: + return cloudprovider.IMAGE_STATUS_KILLED + default: + return cloudprovider.IMAGE_STATUS_KILLED + } +} + +func (self *SImage) Refresh() error { + new, err := self.storageCache.region.GetImage(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + switch self.Imagetype { + case "gold": + return cloudprovider.ImageTypeSystem + case "private": + return cloudprovider.ImageTypeCustomized + case "shared": + return cloudprovider.ImageTypeShared + default: + return cloudprovider.ImageTypeCustomized + } +} + +func (self *SImage) GetSizeByte() int64 { + return int64(self.MinDiskGB) * 1024 * 1024 * 1024 +} + +func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if self.imgInfo == nil { + arch := "x86" + if strings.ToLower(self.SupportArm) == "true" { + arch = "arm" + } + imgInfo := imagetools.NormalizeImageInfo(self.ImageSourceType, arch, self.OSType, self.Platform, "") + self.imgInfo = &imgInfo + } + + return self.imgInfo +} + +func (self *SImage) GetFullOsName() string { + return self.ImageSourceType +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) +} + +func (self *SImage) GetOsDist() string { + return self.getNormalizedImageInfo().OsDistro +} + +func (self *SImage) GetOsVersion() string { + return self.getNormalizedImageInfo().OsVersion +} + +func (self *SImage) GetOsLang() string { + return self.getNormalizedImageInfo().OsLang +} + +func (self *SImage) GetOsArch() string { + return self.getNormalizedImageInfo().OsArch +} + +func (i *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(i.getNormalizedImageInfo().OsBios) +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return int(self.MinDiskGB) +} + +func (self *SImage) GetImageFormat() string { + return self.DiskFormat +} + +func (self *SImage) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SImage) IsEmulated() bool { + return false +} + +func (self *SImage) Delete(ctx context.Context) error { + return self.storageCache.region.DeleteImage(self.GetId()) +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.storageCache +} + +func (self *SRegion) GetImage(imageId string) (*SImage, error) { + image := &SImage{} + err := DoGet(self.ecsClient.Images.Get, imageId, nil, image) + if err != nil { + return nil, errors.Wrap(err, "DoGet") + } + return image, nil +} + +func excludeImage(image SImage) bool { + if image.VirtualEnvType == "Ironic" { + return true + } + + if len(image.SupportDiskIntensive) > 0 { + return true + } + + if len(image.SupportKVMFPGAType) > 0 || len(image.SupportKVMAscend310) > 0 { + return true + } + + if len(image.SupportKVMGPUType) > 0 { + return true + } + + if len(image.SupportKVMNVMEHIGHIO) > 0 { + return true + } + + if len(image.SupportGPUT4) > 0 { + return true + } + + if len(image.SupportXENGPUType) > 0 { + return true + } + + if len(image.SupportHighPerformance) > 0 { + return true + } + + return false +} + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0060804959.html +func (self *SRegion) GetImages(status string, imagetype TImageOwnerType, name string, envType string) ([]SImage, error) { + queries := map[string]string{} + if len(status) > 0 { + queries["status"] = status + } + + if len(imagetype) > 0 { + queries["__imagetype"] = string(imagetype) + if imagetype == ImageOwnerPublic { + queries["protected"] = "True" + } + } + if len(envType) > 0 { + queries["virtual_env_type"] = envType + } + + if len(name) > 0 { + queries["name"] = name + } + + images := make([]SImage, 0) + err := doListAllWithMarker(self.ecsClient.Images.List, queries, &images) + + // 排除掉需要特定镜像才能创建的实例类型 + // https://support.huaweicloud.com/eu-west-0-api-ims/zh-cn_topic_0031617666.html#ZH-CN_TOPIC_0031617666__table48545918250 + // https://support.huaweicloud.com/productdesc-ecs/zh-cn_topic_0088142947.html + filtedImages := make([]SImage, 0) + for i := range images { + if !excludeImage(images[i]) { + filtedImages = append(filtedImages, images[i]) + } + } + + return filtedImages, err +} + +func (self *SRegion) DeleteImage(imageId string) error { + return DoDelete(self.ecsClient.OpenStackImages.Delete, imageId, nil, nil) +} + +func (self *SRegion) GetImageByName(name string) (*SImage, error) { + if len(name) == 0 { + return nil, fmt.Errorf("image name should not be empty") + } + + images, err := self.GetImages("", TImageOwnerType(""), name, "") + if err != nil { + return nil, err + } + if len(images) == 0 { + return nil, cloudprovider.ErrNotFound + } + + log.Debugf("%d image found match name %s", len(images), name) + return &images[0], nil +} + +/* +https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html + + os version 取值范围: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html + 用于创建私有镜像的源云服务器系统盘大小大于等于40GB且不超过1024GB。 + 目前支持vhd,zvhd、raw,qcow2 + todo: 考虑使用镜像快速导入。 https://support.huaweicloud.com/api-ims/zh-cn_topic_0133188204.html + 使用OBS文件创建镜像 + + * openstack原生接口支持的格式:https://support.huaweicloud.com/api-ims/zh-cn_topic_0031615566.html +*/ +func (self *SRegion) ImportImageJob(name string, osDist string, osVersion string, osArch string, bucket string, key string, minDiskGB int64) (string, error) { + os_version, err := stdVersion(osDist, osVersion, osArch) + log.Debugf("%s %s %s: %s.min_disk %d GB", osDist, osVersion, osArch, os_version, minDiskGB) + if err != nil { + log.Debugln(err) + } + + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(name), "name") + image_url := fmt.Sprintf("%s:%s", bucket, key) + params.Add(jsonutils.NewString(image_url), "image_url") + if len(os_version) > 0 { + params.Add(jsonutils.NewString(os_version), "os_version") + } + params.Add(jsonutils.NewBool(true), "is_config_init") + params.Add(jsonutils.NewBool(true), "is_config") + params.Add(jsonutils.NewInt(minDiskGB), "min_disk") + + ret, err := self.ecsClient.Images.PerformAction2("action", "", params, "") + if err != nil { + return "", err + } + + return ret.GetString("job_id") +} + +func formatVersion(osDist string, osVersion string) (string, error) { + err := fmt.Errorf("unsupport version %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osVersion) + dist := strings.ToLower(osDist) + if dist == "ubuntu" || dist == "redhat" || dist == "centos" || dist == "oracle" || dist == "euleros" { + parts := strings.Split(osVersion, ".") + if len(parts) < 2 { + return "", err + } + + return parts[0] + "." + parts[1], nil + } + + if dist == "debian" { + parts := strings.Split(osVersion, ".") + if len(parts) < 3 { + return "", err + } + + return parts[0] + "." + parts[1] + "." + parts[2], nil + } + + if dist == "fedora" || dist == "windows" || dist == "suse" { + parts := strings.Split(osVersion, ".") + if len(parts) < 1 { + return "", err + } + + return parts[0], nil + } + + if dist == "opensuse" { + parts := strings.Split(osVersion, ".") + if len(parts) == 0 { + return "", err + } + + if len(parts) == 1 { + return parts[0], nil + } + + if len(parts) >= 2 { + return parts[0] + "." + parts[1], nil + } + } + + return "", err +} + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html +func stdVersion(osDist string, osVersion string, osArch string) (string, error) { + // 架构 + arch := "" + switch osArch { + case "64", apis.OS_ARCH_X86_64, apis.OS_ARCH_AARCH64, apis.OS_ARCH_ARM: + arch = "64bit" + case "32", apis.OS_ARCH_X86_32, apis.OS_ARCH_AARCH32: + arch = "32bit" + default: + return "", fmt.Errorf("unsupported arch %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osArch) + } + + _dist := strings.Split(strings.TrimSpace(osDist), " ")[0] + _dist = strings.ToLower(_dist) + // 版本 + ver, err := formatVersion(_dist, osVersion) + if err != nil { + return "", err + } + + // 操作系统 + dist := "" + + switch _dist { + case "ubuntu": + return fmt.Sprintf("Ubuntu %s server %s", ver, arch), nil + case "redhat": + dist = "Redhat Linux Enterprise" + case "centos": + dist = "CentOS" + case "fedora": + dist = "Fedora" + case "debian": + dist = "Debian GNU/Linux" + case "windows": + dist = "Windows Server" + case "oracle": + dist = "Oracle Linux Server release" + case "suse": + dist = "SUSE Linux Enterprise Server" + case "opensuse": + dist = "OpenSUSE" + case "euleros": + dist = "EulerOS" + default: + return "", fmt.Errorf("unsupported os %s. reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", dist) + } + + return fmt.Sprintf("%s %s %s", dist, ver, arch), nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instance.go new file mode 100644 index 0000000000..9d21b50589 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instance.go @@ -0,0 +1,1467 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + "encoding/base64" + "fmt" + "sort" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/apis" + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/cloudinit" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +const ( + InstanceStatusRunning = "ACTIVE" + InstanceStatusTerminated = "DELETED" + InstanceStatusStopped = "SHUTOFF" +) + +type IpAddress struct { + Version string `json:"version"` + Addr string `json:"addr"` + OSEXTIPSMACMACAddr string `json:"OS-EXT-IPS-MAC:mac_addr"` + OSEXTIPSPortID string `json:"OS-EXT-IPS:port_id"` + OSEXTIPSType string `json:"OS-EXT-IPS:type"` +} + +type Flavor struct { + Disk string `json:"disk"` + Vcpus string `json:"vcpus"` + RAM string `json:"ram"` + ID string `json:"id"` + Name string `json:"name"` +} + +type Image struct { + ID string `json:"id"` +} + +type VMMetadata struct { + MeteringImageID string `json:"metering.image_id"` + MeteringImagetype string `json:"metering.imagetype"` + MeteringResourcespeccode string `json:"metering.resourcespeccode"` + ImageName string `json:"image_name"` + OSBit string `json:"os_bit"` + VpcID string `json:"vpc_id"` + MeteringResourcetype string `json:"metering.resourcetype"` + CascadedInstanceExtrainfo string `json:"cascaded.instance_extrainfo"` + OSType string `json:"os_type"` + ChargingMode string `json:"charging_mode"` +} + +type OSExtendedVolumesVolumesAttached struct { + Device string `json:"device"` + BootIndex string `json:"bootIndex"` + ID string `json:"id"` + DeleteOnTermination string `json:"delete_on_termination"` +} + +type OSSchedulerHints struct { +} + +type SecurityGroup struct { + Name string `json:"name"` +} + +type SysTag struct { + Key string `json:"key"` + Value string `json:"value"` +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html +// https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0100166287.html v1.1 支持创建包年/包月的弹性云服务器 +type SInstance struct { + multicloud.SInstanceBase + huawei.HuaweiTags + + host *SHost + + osInfo *imagetools.ImageInfo + + ID string `json:"id"` + Name string `json:"name"` + Addresses map[string][]IpAddress `json:"addresses"` + Flavor Flavor `json:"flavor"` + AccessIPv4 string `json:"accessIPv4"` + AccessIPv6 string `json:"accessIPv6"` + Status string `json:"status"` + Progress string `json:"progress"` + HostID string `json:"hostId"` + Updated string `json:"updated"` + Created time.Time `json:"created"` + Metadata VMMetadata `json:"metadata"` + Description string `json:"description"` + Locked bool `json:"locked"` + ConfigDrive string `json:"config_drive"` + TenantID string `json:"tenant_id"` + UserID string `json:"user_id"` + KeyName string `json:"key_name"` + + OSExtendedVolumesVolumesAttached []OSExtendedVolumesVolumesAttached `json:"os-extended-volumes:volumes_attached"` + OSEXTSTSTaskState string `json:"OS-EXT-STS:task_state"` + OSEXTSTSPowerState int64 `json:"OS-EXT-STS:power_state"` + OSEXTSTSVMState string `json:"OS-EXT-STS:vm_state"` + OSEXTSRVATTRHost string `json:"OS-EXT-SRV-ATTR:host"` + OSEXTSRVATTRInstanceName string `json:"OS-EXT-SRV-ATTR:instance_name"` + OSEXTSRVATTRHypervisorHostname string `json:"OS-EXT-SRV-ATTR:hypervisor_hostname"` + OSDCFDiskConfig string `json:"OS-DCF:diskConfig"` + OSEXTAZAvailabilityZone string `json:"OS-EXT-AZ:availability_zone"` + OSSchedulerHints OSSchedulerHints `json:"os:scheduler_hints"` + OSEXTSRVATTRRootDeviceName string `json:"OS-EXT-SRV-ATTR:root_device_name"` + OSEXTSRVATTRRamdiskID string `json:"OS-EXT-SRV-ATTR:ramdisk_id"` + EnterpriseProjectID string `json:"enterprise_project_id"` + OSEXTSRVATTRUserData string `json:"OS-EXT-SRV-ATTR:user_data"` + OSSRVUSGLaunchedAt time.Time `json:"OS-SRV-USG:launched_at"` + OSEXTSRVATTRKernelID string `json:"OS-EXT-SRV-ATTR:kernel_id"` + OSEXTSRVATTRLaunchIndex int64 `json:"OS-EXT-SRV-ATTR:launch_index"` + HostStatus string `json:"host_status"` + OSEXTSRVATTRReservationID string `json:"OS-EXT-SRV-ATTR:reservation_id"` + OSEXTSRVATTRHostname string `json:"OS-EXT-SRV-ATTR:hostname"` + OSSRVUSGTerminatedAt time.Time `json:"OS-SRV-USG:terminated_at"` + SysTags []SysTag `json:"sys_tags"` + SecurityGroups []SecurityGroup `json:"security_groups"` + EnterpriseProjectId string +} + +func compareSet(currentSet []string, newSet []string) (add []string, remove []string, keep []string) { + sort.Strings(currentSet) + sort.Strings(newSet) + + i, j := 0, 0 + for i < len(currentSet) || j < len(newSet) { + if i < len(currentSet) && j < len(newSet) { + if currentSet[i] == newSet[j] { + keep = append(keep, currentSet[i]) + i += 1 + j += 1 + } else if currentSet[i] < newSet[j] { + remove = append(remove, currentSet[i]) + i += 1 + } else { + add = append(add, newSet[j]) + j += 1 + } + } else if i >= len(currentSet) { + add = append(add, newSet[j]) + j += 1 + } else if j >= len(newSet) { + remove = append(remove, currentSet[i]) + i += 1 + } + } + + return add, remove, keep +} + +// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) +func isBootDisk(server *SInstance, disk *SDisk) bool { + if disk.GetDiskType() != api.DISK_TYPE_SYS { + return false + } + + for _, attachment := range disk.Attachments { + if attachment.ServerID == server.GetId() && attachment.Device == server.OSEXTSRVATTRRootDeviceName { + return true + } + } + + return false +} + +func (self *SInstance) GetId() string { + return self.ID +} + +func (self *SInstance) GetName() string { + return self.Name +} + +func (self *SInstance) GetHostname() string { + return self.OSEXTSRVATTRHostname +} + +func (self *SInstance) GetGlobalId() string { + return self.ID +} + +func (self *SInstance) GetStatus() string { + switch self.Status { + case "ACTIVE": + return api.VM_RUNNING + case "MIGRATING", "REBUILD", "BUILD", "RESIZE", "VERIFY_RESIZE": // todo: pending ? + return api.VM_STARTING + case "REBOOT", "HARD_REBOOT": + return api.VM_STOPPING + case "SHUTOFF": + return api.VM_READY + default: + return api.VM_UNKNOWN + } +} + +func (self *SInstance) Refresh() error { + new, err := self.host.zone.region.GetInstanceByID(self.GetId()) + new.host = self.host + if err != nil { + return err + } + + if new.Status == InstanceStatusTerminated { + log.Debugf("Instance already terminated.") + return cloudprovider.ErrNotFound + } + + err = jsonutils.Update(self, new) + if err != nil { + return err + } + return nil +} + +func (self *SInstance) IsEmulated() bool { + return false +} + +func (self *SInstance) GetInstanceType() string { + return self.Flavor.ID +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + return self.host.zone.region.GetInstanceSecrityGroupIds(self.GetId()) +} + +// https://support.huaweicloud.com/api-ecs/ecs_02_1002.html +// key 相同时value不会替换 +func (self *SRegion) CreateServerTags(instanceId string, tags map[string]string) error { + params := map[string]interface{}{ + "action": "create", + } + + tagsObj := []map[string]string{} + for k, v := range tags { + tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) + } + params["tags"] = tagsObj + + _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + return err +} + +// https://support.huaweicloud.com/api-ecs/ecs_02_1003.html +func (self *SRegion) DeleteServerTags(instanceId string, tagsKey []string) error { + params := map[string]interface{}{ + "action": "delete", + } + tagsObj := []map[string]string{} + for _, k := range tagsKey { + tagsObj = append(tagsObj, map[string]string{"key": k}) + } + params["tags"] = tagsObj + + _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + return err +} + +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { + existedTags, err := self.GetTags() + if err != nil { + return errors.Wrap(err, "self.GetTags()") + } + deleteTagsKey := []string{} + for k := range existedTags { + if replace { + deleteTagsKey = append(deleteTagsKey, k) + } else { + if _, ok := tags[k]; ok { + deleteTagsKey = append(deleteTagsKey, k) + } + } + } + if len(deleteTagsKey) > 0 { + err := self.host.zone.region.DeleteServerTags(self.GetId(), deleteTagsKey) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.DeleteServerTags(%s,%s)", self.GetId(), deleteTagsKey) + } + } + if len(tags) > 0 { + err := self.host.zone.region.CreateServerTags(self.GetId(), tags) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.CreateServerTags(%s,%s)", self.GetId(), jsonutils.Marshal(tags).String()) + } + } + return nil +} + +func (self *SInstance) GetBillingType() string { + // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html + // charging_mode “0”:按需计费 “1”:按包年包月计费 + if self.Metadata.ChargingMode == "1" { + return billing_api.BILLING_TYPE_PREPAID + } else { + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SInstance) GetCreatedAt() time.Time { + return self.Created +} + +// charging_mode “0”:按需计费 “1”:按包年包月计费 +func (self *SInstance) GetExpiredAt() time.Time { + var expiredTime time.Time + return expiredTime +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetIHostId() string { + return self.host.GetGlobalId() +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + err := self.Refresh() + if err != nil { + return nil, err + } + + attached := self.OSExtendedVolumesVolumesAttached + disks := make([]SDisk, 0) + for _, vol := range attached { + disk, err := self.host.zone.region.GetDisk(vol.ID) + if err != nil { + return nil, err + } + + disks = append(disks, *disk) + } + + idisks := make([]cloudprovider.ICloudDisk, len(disks)) + for i := 0; i < len(disks); i += 1 { + storage, err := self.host.zone.getStorageByCategory(disks[i].VolumeType) + if err != nil { + return nil, err + } + disks[i].storage = storage + idisks[i] = &disks[i] + // 将系统盘放到第0个位置 + if isBootDisk(self, &disks[i]) { + _temp := idisks[0] + idisks[0] = &disks[i] + idisks[i] = _temp + } + } + return idisks, nil +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics := make([]cloudprovider.ICloudNic, 0) + + // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html + // OS-EXT-IPS.type + // todo: 这里没有区分是IPv4 还是 IPv6。统一当IPv4处理了.可能会引发错误 + for _, ipAddresses := range self.Addresses { + for _, ipAddress := range ipAddresses { + if ipAddress.OSEXTIPSType == "fixed" { + nic := SInstanceNic{ + instance: self, + ipAddr: ipAddress.Addr, + macAddr: ipAddress.OSEXTIPSMACMACAddr, + } + nics = append(nics, &nic) + } + } + } + return nics, nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + ips := make([]string, 0) + for _, addresses := range self.Addresses { + for _, address := range addresses { + if address.OSEXTIPSType != "fixed" && !strings.HasPrefix(address.Addr, "100.") { + ips = append(ips, address.Addr) + } + } + } + + if len(ips) == 0 { + return nil, nil + } + + eips, err := self.host.zone.region.GetEips() + if err != nil { + return nil, err + } + + for _, eip := range eips { + if eip.PublicIPAddress == ips[0] { + return &eip, nil + } + } + + return nil, nil +} + +func (self *SInstance) GetVcpuCount() int { + cpu, _ := strconv.Atoi(self.Flavor.Vcpus) + return cpu +} + +func (self *SInstance) GetVmemSizeMB() int { + mem, _ := strconv.Atoi(self.Flavor.RAM) + return int(mem) +} + +func (self *SInstance) GetBootOrder() string { + return "dcn" +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (self *SInstance) GetOsArch() string { + if flavor, err := self.host.zone.region.GetICloudSku(self.Flavor.ID); err == nil { + return flavor.GetCpuArch() + } else { + log.Debugf("GetOSArch.GetICloudSku %s: %s", self.Flavor.ID, err) + } + + t := self.GetInstanceType() + if len(t) > 0 { + if strings.HasPrefix(t, "k") { + return apis.OS_ARCH_AARCH64 + } + } + + return apis.OS_ARCH_X86 +} + +func (self *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(osprofile.NormalizeOSType(self.Metadata.OSType)) +} + +func (self *SInstance) GetFullOsName() string { + return self.Metadata.ImageName +} + +func (i *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { + if i.osInfo == nil { + osInfo := imagetools.NormalizeImageInfo(i.Metadata.ImageName, "", i.Metadata.OSType, "", "") + i.osInfo = &osInfo + } + return i.osInfo +} + +func (i *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(i.getNormalizedOsInfo().OsBios) +} + +func (i *SInstance) GetOsDist() string { + return i.getNormalizedOsInfo().OsDistro +} + +func (i *SInstance) GetOsVersion() string { + return i.getNormalizedOsInfo().OsVersion +} + +func (i *SInstance) GetOsLang() string { + return i.getNormalizedOsInfo().OsLang +} + +func (self *SInstance) GetMachine() string { + return "pc" +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.SetSecurityGroups([]string{secgroupId}) +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + currentSecgroups, err := self.host.zone.region.GetInstanceSecrityGroupIds(self.GetId()) + if err != nil { + return err + } + + add, remove, _ := compareSet(currentSecgroups, secgroupIds) + err = self.host.zone.region.assignSecurityGroups(add, self.GetId()) + if err != nil { + return err + } + + return self.host.zone.region.unassignSecurityGroups(remove, self.GetId()) +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_HCSO +} + +func (self *SInstance) StartVM(ctx context.Context) error { + if self.Status == InstanceStatusRunning { + return nil + } + + 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 + } + + if self.GetStatus() == api.VM_RUNNING { + return nil + } else if self.GetStatus() == api.VM_READY { + err := self.host.zone.region.StartVM(self.GetId()) + if err != nil { + return err + } + } + time.Sleep(interval) + } + return cloudprovider.ErrTimeout +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + if self.Status == InstanceStatusStopped { + return nil + } + + if self.Status == InstanceStatusTerminated { + log.Debugf("Instance already terminated.") + return nil + } + + err := self.host.zone.region.StopVM(self.GetId(), opts.IsForce) + if err != nil { + return err + } + return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + if self.Status == InstanceStatusTerminated { + return nil + } + + for { + err := self.host.zone.region.DeleteVM(self.GetId()) + if err != nil && self.Status != InstanceStatusTerminated { + log.Errorf("DeleteVM fail: %s", err) + return err + } else { + break + } + } + + return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return self.host.zone.region.UpdateVM(self.GetId(), name) +} + +// https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0032380449.html +// 创建云服务器过程中注入用户数据。支持注入文本、文本文件或gzip文件。 +// 注入内容,需要进行base64格式编码。注入内容(编码之前的内容)最大长度32KB。 +// 对于Linux弹性云服务器,adminPass参数传入时,user_data参数不生效。 +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html 使用原镜像重装 +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html 更换系统盘操作系统 +// 不支持调整系统盘大小 +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + var err error + var jobId string + + publicKeyName := "" + if len(desc.PublicKey) > 0 { + publicKeyName, err = self.host.zone.region.syncKeypair(desc.PublicKey) + if err != nil { + return "", err + } + } + + image, err := self.host.zone.region.GetImage(desc.ImageId) + if err != nil { + return "", errors.Wrap(err, "SInstance.RebuildRoot.GetImage") + } + + // Password存在的情况下,windows 系统直接使用密码 + if strings.ToLower(image.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(desc.Password) > 0 { + publicKeyName = "" + } + + userData, err := updateUserData(self.OSEXTSRVATTRUserData, image.OSVersion, desc.Account, desc.Password, desc.PublicKey) + if err != nil { + return "", errors.Wrap(err, "SInstance.RebuildRoot.updateUserData") + } + + if self.Metadata.MeteringImageID == desc.ImageId { + jobId, err = self.host.zone.region.RebuildRoot(ctx, self.UserID, self.GetId(), desc.Password, publicKeyName, userData) + if err != nil { + return "", err + } + } else { + jobId, err = self.host.zone.region.ChangeRoot(ctx, self.UserID, self.GetId(), desc.ImageId, desc.Password, publicKeyName, userData) + if err != nil { + return "", err + } + } + + err = self.host.zone.region.waitTaskStatus(self.host.zone.region.ecsClient.Servers.ServiceType(), jobId, TASK_SUCCESS, 15*time.Second, 900*time.Second) + if err != nil { + log.Errorf("RebuildRoot task error %s", err) + return "", err + } + + err = self.Refresh() + if err != nil { + return "", err + } + + idisks, err := self.GetIDisks() + if err != nil { + return "", err + } + + if len(idisks) == 0 { + return "", fmt.Errorf("server %s has no volume attached.", self.GetId()) + } + + return idisks[0].GetId(), nil +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return self.host.zone.region.DeployVM(self.GetId(), name, password, publicKey, deleteKeypair, description) +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + instanceTypes := []string{} + if len(config.InstanceType) > 0 { + instanceTypes = []string{config.InstanceType} + } else { + flavors, err := self.host.zone.region.GetMatchInstanceTypes(config.Cpu, config.MemoryMB, self.OSEXTAZAvailabilityZone) + if err != nil { + return errors.Wrapf(err, "GetMatchInstanceTypes") + } + for _, flavor := range flavors { + instanceTypes = append(instanceTypes, flavor.ID) + } + } + var err error + for _, instanceType := range instanceTypes { + err = self.host.zone.region.ChangeVMConfig(self.GetId(), instanceType) + if err != nil { + log.Warningf("ChangeVMConfig %s for %s error: %v", self.GetId(), instanceType, err) + } else { + return cloudprovider.WaitStatusWithDelay(self, api.VM_READY, 15*time.Second, 15*time.Second, 180*time.Second) + } + } + if err != nil { + return errors.Wrapf(err, "ChangeVMConfig") + } + return fmt.Errorf("Failed to change vm config, specification not supported") +} + +// todo:// 返回jsonobject感觉很诡异。不能直接知道内部细节 +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return self.host.zone.region.GetInstanceVNCUrl(self.GetId()) +} + +func (self *SInstance) NextDeviceName() (string, error) { + prefix := "s" + if strings.Contains(self.OSEXTSRVATTRRootDeviceName, "/vd") { + prefix = "v" + } + + currents := []string{} + for _, item := range self.OSExtendedVolumesVolumesAttached { + currents = append(currents, strings.ToLower(item.Device)) + } + + for i := 0; i < 25; i++ { + device := fmt.Sprintf("/dev/%sd%s", prefix, string([]byte{byte(98 + i)})) + if ok, _ := utils.InStringArray(device, currents); !ok { + return device, nil + } + } + + return "", fmt.Errorf("disk devicename out of index, current deivces: %s", currents) +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + device, err := self.NextDeviceName() + if err != nil { + return errors.Wrap(err, "Instance.AttachDisk.NextDeviceName") + } + + err = self.host.zone.region.AttachDisk(self.GetId(), diskId, device) + if err != nil { + return errors.Wrap(err, "Instance.AttachDisk.AttachDisk") + } + + return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { + disk, err := self.host.zone.region.GetDisk(diskId) + if err != nil { + log.Debugf("Instance.AttachDisk.GetDisk %s", err) + return false, nil + } + + if disk.Status == "in-use" { + return true, nil + } + + return false, nil + }) +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + err := self.host.zone.region.DetachDisk(self.GetId(), diskId) + if err != nil { + return errors.Wrap(err, "Instance.DetachDisk") + } + + return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { + disk, err := self.host.zone.region.GetDisk(diskId) + if err != nil { + log.Debugf("Instance.DetachDisk.GetDisk %s", err) + return false, nil + } + + if disk.Status == "available" { + return true, nil + } + + return false, nil + }) +} + +func (self *SInstance) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148850.html +func (self *SRegion) GetInstances() ([]SInstance, error) { + queries := make(map[string]string) + + if len(self.client.projectId) > 0 { + queries["project_id"] = self.client.projectId + } + + instances := make([]SInstance, 0) + err := doListAllWithPagerOffset(self.ecsClient.Servers.List, queries, &instances) + return instances, err +} + +func (self *SRegion) GetInstanceByID(instanceId string) (SInstance, error) { + instance := SInstance{} + err := DoGet(self.ecsClient.Servers.Get, instanceId, nil, &instance) + if instance.Status == "DELETED" { + return instance, errors.Wrap(cloudprovider.ErrNotFound, "GetInstanceByID") + } + return instance, err +} + +func (self *SRegion) GetInstanceByIds(ids []string) ([]SInstance, int, error) { + instances := make([]SInstance, 0) + for _, instanceId := range ids { + instance, err := self.GetInstanceByID(instanceId) + if err != nil { + return nil, 0, err + } + instances = append(instances, instance) + } + + return instances, len(instances), nil +} + +/* +系统盘大小取值范围:1-1024 GB,且必须不小于镜像min_disk. +*/ +type SServerCreate struct { + AvailabilityZone string `json:"availability_zone"` + Name string `json:"name"` + ImageRef string `json:"imageRef"` + RootVolume RootVolume `json:"root_volume"` + DataVolumes []DataVolume `json:"data_volumes"` + FlavorRef string `json:"flavorRef"` + UserData string `json:"user_data"` + Vpcid string `json:"vpcid"` + SecurityGroups []SecGroup `json:"security_groups"` + Nics []NIC `json:"nics"` + KeyName string `json:"key_name"` + AdminPass string `json:"adminPass"` + Count int64 `json:"count"` + Extendparam ServerExtendparam `json:"extendparam"` + ServerTags []ServerTag `json:"server_tags"` + Description string `json:"description"` +} + +type DataVolume struct { + Volumetype string `json:"volumetype"` + SizeGB int `json:"size"` + Extendparam *DataVolumeExtendparam `json:"extendparam,omitempty"` + Multiattach *bool `json:"multiattach,omitempty"` + HwPassthrough *string `json:"hw:passthrough,omitempty"` +} + +type DataVolumeExtendparam struct { + SnapshotID string `json:"snapshotId"` +} + +type ServerExtendparam struct { + ChargingMode string `json:"chargingMode"` // 计费模式 prePaid|postPaid + PeriodType string `json:"periodType"` // 周期类型:month|year + PeriodNum string `json:"periodNum"` // 订购周期数:periodType=month(周期类型为月)时,取值为[1,9]。periodType=year(周期类型为年)时,取值为1。 + IsAutoRenew string `json:"isAutoRenew"` // 是否自动续订 true|false + IsAutoPay string `json:"isAutoPay"` // 是否自动从客户的账户中支付 true|false + RegionID string `json:"regionID"` + EnterpriseProjectId string `json:"enterprise_project_id,omitempty"` +} + +type NIC struct { + SubnetID string `json:"subnet_id"` // 网络ID. 与 SNetwork里的ID对应。统一使用这个ID + IpAddress string `json:"ip_address"` +} + +type RootVolume struct { + Volumetype string `json:"volumetype"` + SizeGB int `json:"size"` +} + +type SecGroup struct { + ID string `json:"id"` +} + +type ServerTag struct { + Key string `json:"key"` + Value string `json:"value"` +} + +/* +包月机器退订规则: https://support.huaweicloud.com/usermanual-billing/zh-cn_topic_0083138805.html +5天无理由全额退订:新购资源(不包含续费资源)在开通的五天内且退订次数不超过10次(每账号每年10次)的符合5天无理由全额退订。 +非5天无理由退订:不符合5天无理由全额退订条件的退订,都属于非5天无理由退订。非5天无理由退订,不限制退订次数,但需要收取退订手续费。 + +退订资源的方法: https://support.huaweicloud.com/usermanual-billing/zh-cn_topic_0072297197.html +*/ +func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, SubnetId string, + securityGroupId string, vpcId string, zoneId string, desc string, disks []SDisk, ipAddr string, + keypair string, publicKey string, passwd string, userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (string, error) { + params := SServerCreate{} + params.AvailabilityZone = zoneId + params.Name = name + params.FlavorRef = instanceType + params.ImageRef = imageId + params.Description = desc + params.Count = 1 + params.Nics = []NIC{{SubnetID: SubnetId, IpAddress: ipAddr}} + params.SecurityGroups = []SecGroup{{ID: securityGroupId}} + params.Vpcid = vpcId + + for i, disk := range disks { + if i == 0 { + params.RootVolume.Volumetype = disk.VolumeType + params.RootVolume.SizeGB = disk.SizeGB + } else { + dataVolume := DataVolume{} + dataVolume.Volumetype = disk.VolumeType + dataVolume.SizeGB = disk.SizeGB + params.DataVolumes = append(params.DataVolumes, dataVolume) + } + } + + if len(projectId) > 0 { + params.Extendparam.EnterpriseProjectId = projectId + } + + // billing type + if bc != nil { + params.Extendparam.ChargingMode = PRE_PAID + if bc.GetMonths() <= 9 { + params.Extendparam.PeriodNum = strconv.Itoa(bc.GetMonths()) + params.Extendparam.PeriodType = "month" + } else { + params.Extendparam.PeriodNum = strconv.Itoa(bc.GetYears()) + params.Extendparam.PeriodType = "year" + } + + params.Extendparam.RegionID = self.GetId() + if bc.AutoRenew { + params.Extendparam.IsAutoRenew = "true" + } else { + params.Extendparam.IsAutoRenew = "false" + } + params.Extendparam.IsAutoPay = "true" + } else { + params.Extendparam.ChargingMode = POST_PAID + } + + // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212668.html#ZH-CN_TOPIC_0020212668__table761103195216 + if len(keypair) > 0 { + params.KeyName = keypair + } else { + params.AdminPass = passwd + } + + if len(userData) > 0 { + params.UserData = userData + } + + if len(tags) > 0 { + serverTags := []ServerTag{} + for k, v := range tags { + serverTags = append(serverTags, ServerTag{Key: k, Value: v}) + } + params.ServerTags = serverTags + } + + serverObj := jsonutils.Marshal(params) + createParams := jsonutils.NewDict() + createParams.Add(serverObj, "server") + _id, err := self.ecsClient.Servers.AsyncCreate(createParams) + if err != nil { + return "", err + } + + var ids []string + if params.Extendparam.ChargingMode == POST_PAID { + // 按需计费 + ids, err = self.GetAllSubTaskEntityIDs(self.ecsClient.Servers.ServiceType(), _id, "server_id") + } else { + // 包年包月 + return "", errors.Wrap(cloudprovider.ErrNotSupported, "CreateInstance") + } + + if err != nil { + return "", err + } else if len(ids) == 0 { + return "", fmt.Errorf("CreateInstance job %s result is emtpy", _id) + } else if len(ids) == 1 { + return ids[0], nil + } else { + return "", fmt.Errorf("CreateInstance job %s mutliple instance id returned. %s", _id, ids) + } +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067161469.html +// 添加多个安全组时,建议最多为弹性云服务器添加5个安全组。 +// todo: 确认是否需要先删除,再进行添加操作 +func (self *SRegion) assignSecurityGroups(secgroupIds []string, instanceId string) error { + _, err := self.GetInstanceByID(instanceId) + if err != nil { + return err + } + + for i := range secgroupIds { + secId := secgroupIds[i] + params := jsonutils.NewDict() + secgroupObj := jsonutils.NewDict() + secgroupObj.Add(jsonutils.NewString(secId), "name") + params.Add(secgroupObj, "addSecurityGroup") + + _, err := self.ecsClient.NovaServers.PerformAction("action", instanceId, params) + if err != nil { + return err + } + } + return nil +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067161717.html +func (self *SRegion) unassignSecurityGroups(secgroupIds []string, instanceId string) error { + for i := range secgroupIds { + secId := secgroupIds[i] + params := jsonutils.NewDict() + secgroupObj := jsonutils.NewDict() + secgroupObj.Add(jsonutils.NewString(secId), "name") + params.Add(secgroupObj, "removeSecurityGroup") + + _, err := self.ecsClient.NovaServers.PerformAction("action", instanceId, params) + if err != nil { + return err + } + } + return nil +} + +func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) { + instance, err := self.GetInstanceByID(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: %s", err) + return err + } + if status != remoteStatus { + log.Errorf("instanceStatusChecking: vm status is %s expect %s", remoteStatus, status) + return cloudprovider.ErrInvalidStatus + } + + return nil +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212207.html +func (self *SRegion) StartVM(instanceId string) error { + rstatus, err := self.GetInstanceStatus(instanceId) + if err != nil { + return err + } + + if rstatus == InstanceStatusRunning { + return nil + } + + if rstatus != InstanceStatusStopped { + log.Errorf("instanceStatusChecking: vm status is %s expect %s", rstatus, InstanceStatusStopped) + return cloudprovider.ErrInvalidStatus + } + + params := jsonutils.NewDict() + startObj := jsonutils.NewDict() + serversObj := jsonutils.NewArray() + serverObj := jsonutils.NewDict() + serverObj.Add(jsonutils.NewString(instanceId), "id") + serversObj.Add(serverObj) + startObj.Add(serversObj, "servers") + params.Add(startObj, "os-start") + _, err = self.ecsClient.Servers.PerformAction2("action", "", params, "") + return err +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212651.html +func (self *SRegion) StopVM(instanceId string, isForce bool) error { + rstatus, err := self.GetInstanceStatus(instanceId) + if err != nil { + return err + } + + if rstatus == InstanceStatusStopped { + return nil + } + + if rstatus != InstanceStatusRunning { + log.Errorf("instanceStatusChecking: vm status is %s expect %s", rstatus, InstanceStatusRunning) + return cloudprovider.ErrInvalidStatus + } + + params := jsonutils.NewDict() + stopObj := jsonutils.NewDict() + serversObj := jsonutils.NewArray() + serverObj := jsonutils.NewDict() + serverObj.Add(jsonutils.NewString(instanceId), "id") + serversObj.Add(serverObj) + stopObj.Add(serversObj, "servers") + if isForce { + stopObj.Add(jsonutils.NewString("HARD"), "type") + } else { + stopObj.Add(jsonutils.NewString("SOFT"), "type") + } + params.Add(stopObj, "os-stop") + _, err = self.ecsClient.Servers.PerformAction2("action", "", params, "") + return err +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212679.html +// 只删除主机。弹性IP和数据盘需要单独删除 +func (self *SRegion) DeleteVM(instanceId string) error { + remoteStatus, err := self.GetInstanceStatus(instanceId) + if err != nil { + return err + } + + if remoteStatus != InstanceStatusStopped { + log.Errorf("DeleteVM vm status is %s expect %s", remoteStatus, InstanceStatusStopped) + return cloudprovider.ErrInvalidStatus + } + + params := jsonutils.NewDict() + serversObj := jsonutils.NewArray() + serverObj := jsonutils.NewDict() + serverObj.Add(jsonutils.NewString(instanceId), "id") + serversObj.Add(serverObj) + params.Add(serversObj, "servers") + params.Add(jsonutils.NewBool(false), "delete_publicip") + params.Add(jsonutils.NewBool(false), "delete_volume") + + _, err = self.ecsClient.Servers.PerformAction2("delete", "", params, "") + return err +} + +func (self *SRegion) UpdateVM(instanceId, name string) error { + params := jsonutils.NewDict() + serverObj := jsonutils.NewDict() + serverObj.Add(jsonutils.NewString(name), "name") + params.Add(serverObj, "server") + + _, err := self.ecsClient.Servers.Update(instanceId, params) + return err +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html +// 返回job id +func (self *SRegion) RebuildRoot(ctx context.Context, userId, instanceId, passwd, publicKeyName, userData string) (string, error) { + params := jsonutils.NewDict() + reinstallObj := jsonutils.NewDict() + + if len(publicKeyName) > 0 { + reinstallObj.Add(jsonutils.NewString(publicKeyName), "keyname") + } else if len(passwd) > 0 { + reinstallObj.Add(jsonutils.NewString(passwd), "adminpass") + } else { + return "", fmt.Errorf("both password and publicKey are empty.") + } + + if len(userData) > 0 { + meta := jsonutils.NewDict() + meta.Add(jsonutils.NewString(userData), "user_data") + reinstallObj.Add(meta, "metadata") + } + + if len(userId) > 0 { + reinstallObj.Add(jsonutils.NewString(userId), "userid") + } + + params.Add(reinstallObj, "os-reinstall") + ret, err := self.ecsClient.ServersV2.PerformAction2("reinstallos", instanceId, params, "") + if err != nil { + return "", err + } + + return ret.GetString("job_id") +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html +// 返回job id +func (self *SRegion) ChangeRoot(ctx context.Context, userId, instanceId, imageId, passwd, publicKeyName, userData string) (string, error) { + params := jsonutils.NewDict() + changeOsObj := jsonutils.NewDict() + + if len(publicKeyName) > 0 { + changeOsObj.Add(jsonutils.NewString(publicKeyName), "keyname") + } else if len(passwd) > 0 { + changeOsObj.Add(jsonutils.NewString(passwd), "adminpass") + } else { + return "", fmt.Errorf("both password and publicKey are empty.") + } + + if len(userData) > 0 { + meta := jsonutils.NewDict() + meta.Add(jsonutils.NewString(userData), "user_data") + changeOsObj.Add(meta, "metadata") + } + + if len(userId) > 0 { + changeOsObj.Add(jsonutils.NewString(userId), "userid") + } + + changeOsObj.Add(jsonutils.NewString(imageId), "imageid") + params.Add(changeOsObj, "os-change") + + ret, err := self.ecsClient.ServersV2.PerformAction2("changeos", instanceId, params, "") + if err != nil { + return "", err + } + + return ret.GetString("job_id") +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212692.html +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0110109377.html +// 一键式重置密码 需要安装安装一键式重置密码插件 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0068095385.html +// 目前不支持直接重置密钥 +func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { + serverObj := jsonutils.NewDict() + if len(name) > 0 { + serverObj.Add(jsonutils.NewString(name), "name") + } + + // if len(description) > 0 { + // serverObj.Add(jsonutils.NewString(description), "description") + // } + + if serverObj.Size() > 0 { + params := jsonutils.NewDict() + params.Add(serverObj, "server") + // 这里华为返回的image字段是字符串。和SInstance的定义的image是字典结构不一致。 + err := DoUpdate(self.ecsClient.NovaServers.Update, instanceId, params, nil) + if err != nil { + return err + } + } + + if len(password) > 0 { + params := jsonutils.NewDict() + passwdObj := jsonutils.NewDict() + passwdObj.Add(jsonutils.NewString(password), "new_password") + params.Add(passwdObj, "reset-password") + + err := DoUpdateWithSpec(self.ecsClient.NovaServers.UpdateInContextWithSpec, instanceId, "os-reset-password", params) + if err != nil { + return err + } + } + + return nil +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212653.html +func (self *SRegion) ChangeVMConfig(instanceId string, instanceType string) error { + self.ecsClient.Servers.SetVersion("v1.1") + defer self.ecsClient.Servers.SetVersion("v1") + + params := jsonutils.NewDict() + resizeObj := jsonutils.NewDict() + resizeObj.Add(jsonutils.NewString(instanceType), "flavorRef") + params.Add(resizeObj, "resize") + _, err := self.ecsClient.Servers.PerformAction2("resize", instanceId, params, "") + return errors.Wrapf(err, "PerformAction2(resize)") +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0142763126.html 微版本2.6及以上? +// https://support.huaweicloud.com/api-ecs/ecs_02_0208.html +func (self *SRegion) GetInstanceVNCUrl(instanceId string) (*cloudprovider.ServerVncOutput, error) { + params := jsonutils.NewDict() + vncObj := jsonutils.NewDict() + vncObj.Add(jsonutils.NewString("novnc"), "type") + vncObj.Add(jsonutils.NewString("vnc"), "protocol") + params.Add(vncObj, "remote_console") + + resp, err := self.ecsClient.Servers.PerformAction2("remote_console", instanceId, params, "remote_console") + if err != nil { + return nil, err + } + + ret := &cloudprovider.ServerVncOutput{ + Hypervisor: api.HYPERVISOR_HCSO, + } + resp.Unmarshal(ret) + ret.Protocol = "huawei" + return ret, nil +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022472987.html +// XEN平台虚拟机device为必选参数。 +func (self *SRegion) AttachDisk(instanceId string, diskId string, device string) error { + params := jsonutils.NewDict() + volumeObj := jsonutils.NewDict() + volumeObj.Add(jsonutils.NewString(diskId), "volumeId") + if len(device) > 0 { + volumeObj.Add(jsonutils.NewString(device), "device") + } + + params.Add(volumeObj, "volumeAttachment") + + _, err := self.ecsClient.Servers.PerformAction2("attachvolume", instanceId, params, "") + return err +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022472988.html +// 默认非强制卸载。delete_flag=0 +func (self *SRegion) DetachDisk(instanceId string, diskId string) error { + path := fmt.Sprintf("detachvolume/%s", diskId) + err := DoDeleteWithSpec(self.ecsClient.Servers.DeleteInContextWithSpec, nil, instanceId, path, nil, nil) + //volume a2091934-2669-4fca-8eb4-a950c1836b3c is not in server 49b053d2-f798-432f-af55-76eb6ef2c769 attach volume list => 磁盘已经被卸载了 + if err != nil && strings.Contains(err.Error(), fmt.Sprintf("is not in server")) && strings.Contains(err.Error(), fmt.Sprintf("attach volume list")) { + return nil + } + return err +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817702.html +func (self *SRegion) GetInstanceSecrityGroupIds(instanceId string) ([]string, error) { + if len(instanceId) == 0 { + return nil, fmt.Errorf("GetInstanceSecrityGroups instanceId is empty") + } + + securitygroups := make([]SSecurityGroup, 0) + ctx := &modules.SManagerContext{InstanceManager: self.ecsClient.NovaServers, InstanceId: instanceId} + err := DoListInContext(self.ecsClient.NovaSecurityGroups.ListInContext, ctx, nil, &securitygroups) + if err != nil { + return nil, err + } + + securitygroupIds := []string{} + for _, secgroup := range securitygroups { + securitygroupIds = append(securitygroupIds, secgroup.GetId()) + } + + return securitygroupIds, nil +} + +func (self *SInstance) GetProjectId() string { + return self.EnterpriseProjectId +} + +func (self *SInstance) GetError() error { + return nil +} + +func updateUserData(userData, osVersion, username, password, publicKey string) (string, error) { + winOS := strings.ToLower(osprofile.OS_TYPE_WINDOWS) + osVersion = strings.ToLower(osVersion) + config := &cloudinit.SCloudConfig{} + if strings.Contains(osVersion, winOS) { + if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { + config = _config + } else { + log.Debugf("updateWindowsUserData invalid userdata %s", userData) + } + } else { + if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { + config = _config + } else { + return "", fmt.Errorf("updateLinuxUserData invalid userdata %s", userData) + } + } + + user := cloudinit.NewUser(username) + config.RemoveUser(user) + config.DisableRoot = 0 + if len(password) > 0 { + config.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON + user.Password(password) + config.MergeUser(user) + } + + if len(publicKey) > 0 { + user.SshKey(publicKey) + config.MergeUser(user) + } + + if strings.Contains(osVersion, winOS) { + userData, err := updateWindowsUserData(config.UserDataPowerShell(), osVersion, username, password) + if err != nil { + return "", errors.Wrap(err, "updateUserData.updateWindowsUserData") + } + return userData, nil + } else { + return config.UserDataBase64(), nil + } +} + +func updateWindowsUserData(userData string, osVersion string, username, password string) (string, error) { + // Windows Server 2003, Windows Vista, Windows Server 2008, Windows Server 2003 R2, Windows Server 2000, Windows Server 2012, Windows Server 2003 with SP1, Windows 8 + oldVersions := []string{"2000", "2003", "2008", "2012", "Vista"} + isOldVersion := false + for i := range oldVersions { + if strings.Contains(osVersion, oldVersions[i]) { + isOldVersion = true + } + } + + shells := "" + if isOldVersion { + shells += fmt.Sprintf("rem cmd\n") + if username == "Administrator" { + shells += fmt.Sprintf("net user %s %s\n", username, password) + } else { + shells += fmt.Sprintf("net user %s %s /add\n", username, password) + shells += fmt.Sprintf("net localgroup administrators %s /add\n", username) + } + + shells += fmt.Sprintf("net user %s /active:yes", username) + } else { + if !strings.HasPrefix(userData, "#ps1") { + shells = fmt.Sprintf("#ps1\n%s", userData) + } + } + + return base64.StdEncoding.EncodeToString([]byte(shells)), nil +} + +func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { + params := map[string]string{ + "name": opts.Name, + "instance_id": instanceId, + } + if len(opts.Notes) > 0 { + params["description"] = func() string { + opts.Notes = strings.ReplaceAll(opts.Notes, "<", "") + opts.Notes = strings.ReplaceAll(opts.Notes, ">", "") + opts.Notes = strings.ReplaceAll(opts.Notes, "\n", "") + if len(opts.Notes) > 1024 { + opts.Notes = opts.Notes[:1024] + } + return opts.Notes + }() + } + resp, err := self.ecsClient.Images.CreateInContextWithSpec(nil, "action", jsonutils.Marshal(params), "") + if err != nil { + return nil, errors.Wrapf(err, "Images.Create") + } + jobId, err := resp.GetString("job_id") + if err != nil { + return nil, errors.Wrapf(err, "resp.GetString(job_id)") + } + err = self.waitTaskStatus(self.ecsClient.Images.ServiceType(), jobId, TASK_SUCCESS, 15*time.Second, 10*time.Minute) + if err != nil { + return nil, errors.Wrapf(err, "waitTaskStatus") + } + imageId, err := self.GetTaskEntityID(self.ecsClient.Images.ServiceType(), jobId, "image_id") + if err != nil { + return nil, errors.Wrapf(err, "GetTaskEntityID") + } + image, err := self.GetImage(imageId) + if err != nil { + return nil, errors.Wrapf(err, "GetImage(%s)", imageId) + } + image.storageCache = self.getStoragecache() + return image, nil +} + +func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { + image, err := self.host.zone.region.SaveImage(self.ID, opts) + if err != nil { + return nil, errors.Wrapf(err, "SaveImage") + } + return image, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instancenic.go new file mode 100644 index 0000000000..8e4638eb61 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instancenic.go @@ -0,0 +1,110 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules" +) + +// =========================================== +type Interface struct { + PortState string `json:"port_state"` + FixedIPS []FixedIP `json:"fixed_ips"` + NetID string `json:"net_id"` // 网络ID. 与 SNetwork里的ID对应。统一使用这个ID + PortID string `json:"port_id"` + MACAddr string `json:"mac_addr"` +} + +/* +subnet: {id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233", name: "subnet-149c", cidr: "192.168.0.0/24",…} +availability_zone: "cn-north-1b" +cidr: "192.168.0.0/24" +dhcp_enable: true +dnsList: ["100.125.1.250", "100.125.21.250"] +gateway_ip: "192.168.0.1" +id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233" +ipv6_enable: false +name: "subnet-149c" +neutron_network_id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233" +neutron_subnet_id: "81fcfaa0-8e73-4472-9eba-3b2b7736d3a7" +primary_dns: "100.125.1.250" +secondary_dns: "100.125.21.250" +status: "ACTIVE" +tags: [] +vpc_id: "877f1feb-3dc8-4c2d-92e9-0d94fd7d79dd"} +*/ +type FixedIP struct { + SubnetID string `json:"subnet_id"` // 子网ID, 与SNetwork中的 neutron_subnet_id对应. 注意!!! 并不是SNetwork ID。 + IPAddress string `json:"ip_address"` +} + +// =========================================== + +type SInstanceNic struct { + instance *SInstance + ipAddr string + macAddr string + + cloudprovider.DummyICloudNic +} + +func (self *SInstanceNic) GetId() string { + return "" +} + +func (self *SInstanceNic) GetIP() string { + return self.ipAddr +} + +func (self *SInstanceNic) GetMAC() string { + return self.macAddr +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) GetINetworkId() string { + instanceId := self.instance.GetId() + subnets, err := self.instance.host.zone.region.getSubnetIdsByInstanceId(instanceId) + if err != nil || len(subnets) == 0 { + log.Errorf("getSubnetIdsByInstanceId error: %s", err.Error()) + return "" + } + return subnets[0] +} + +func (self *SRegion) getSubnetIdsByInstanceId(instanceId string) ([]string, error) { + ctx := &modules.SManagerContext{InstanceManager: self.ecsClient.NovaServers, InstanceId: instanceId} + interfaces := make([]Interface, 0) + err := DoListInContext(self.ecsClient.Interface.ListInContext, ctx, nil, &interfaces) + if err != nil { + return nil, err + } + + subnets := make([]string, 0) + for _, i := range interfaces { + subnets = append(subnets, i.NetID) + } + + return subnets, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instancetype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instancetype.go new file mode 100644 index 0000000000..f584c0779d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/instancetype.go @@ -0,0 +1,314 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "strconv" + "strings" + + "yunion.io/x/cloudmux/pkg/apis" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212656.html +type SInstanceType struct { + multicloud.SResourceBase + ID string `json:"id"` + Name string `json:"name"` + Vcpus string `json:"vcpus"` + RamMB int `json:"ram"` // 内存大小 + Disk string `json:"disk"` + Swap string `json:"swap"` + OSFLVEXTDATAEphemeral int64 `json:"OS-FLV-EXT-DATA:ephemeral"` + RxtxFactor int64 `json:"rxtx_factor"` + OSFLVDISABLEDDisabled bool `json:"OS-FLV-DISABLED:disabled"` + OSFlavorAccessIsPublic bool `json:"os-flavor-access:is_public"` + OSExtraSpecs OSExtraSpecs `json:"os_extra_specs"` // 扩展规格 +} + +type OSExtraSpecs struct { + EcsPerformancetype string `json:"ecs:performancetype"` + EcsGeneration string `json:"ecs:generation"` + EcsInstanceArchitecture string `json:"ecs:instance_architecture"` +} + +var FLAVOR_FAMILY_CATEGORY_MAP = map[string]string{ + "s1": "通用型I代", + "s2": "通用型II代", + "s3": "通用型S3", + "sn3": "通用型", + "s6": "通用型S6", + "p1": "GPU P1型", + "pi1": "GPU Pi1型", + "p2v": "GPU P2v型", + "t6": "通用型T6", + "m1": "内存优化型I代", + "m2": "内存优化型II代", + "m3": "内存优化型", + "m3ne": "内存优化M3ne型", + "h1": "高性能计算型I代", + "h2": "高性能计算型II代", + "h3": "高性能计算型", + "hc2": "高性能计算HC2型", + "hi3": "超高性能计算型", + "d1": "密集存储型I代", + "d2": "密集存储型II代", + "d3": "磁盘增强型", + "g1": "GPU加速型I代", + "g2": "GPU加速型II代", + "g3": "GPU加速型III代", + "f1": "FPGA高性能型", + "f2": "FPGA通用型", + "fp1": "FPGA FP1型", + "fp1c": "FPGA FP1C型", + "ai1": "人工智能Ai1型", + "c1": "通用计算增强C1型", + "c2": "通用计算增强C2型", + "c3": "通用计算增强C3型", + "c3ne": "通用计算增强C3ne型", + "c6": "通用计算增强C6型", + "e1": "大内存E1型", + "e2": "大内存E2型", + "et2": "大内存ET2型", + "e3": "大内存E3型", + "i3": "超高I/O型", + "kc1": "鲲鹏通用计算增强型", + "km1": "鲲鹏内存优化型", + "ki1": "鲲鹏超高I/O型", + "kai1s": "鲲鹏AI推理加速型", +} + +func getFlavorCategory(family string) string { + ret, ok := FLAVOR_FAMILY_CATEGORY_MAP[family] + if ok { + return ret + } + + return family +} + +func getFlavorLocalCategory(family string) string { + switch family { + case "s1", "s2", "s3", "sn3", "s6", "t6": + return "general-purpose" + case "c1", "c2", "c3", "c3ne", "c6", "h1", "h2", "h3", "hc2", "hi3", "kc1": + return "compute-optimized" + case "m1", "m2", "m3", "m3ne", "e1", "e2", "et2", "e3", "km1": + return "memory-optimized" + case "d1", "d2", "d3": + return "storage-optimized" + case "p1", "pi1", "p2v", "g1", "g2", "g3": + return "gpu-compute" + default: + return "others" + } +} + +func (self *SInstanceType) GetId() string { + return self.ID +} + +func (self *SInstanceType) GetName() string { + return self.ID +} + +func (self *SInstanceType) GetGlobalId() string { + return self.ID +} + +func (self *SInstanceType) GetStatus() string { + return "" +} + +func (self *SInstanceType) Refresh() error { + return nil +} + +func (self *SInstanceType) IsEmulated() bool { + return false +} + +func (self *SInstanceType) GetSysTags() map[string]string { + return nil +} + +func (self *SInstanceType) GetTags() (map[string]string, error) { + return nil, nil +} + +func (self *SInstanceType) SetTags(tags map[string]string, replace bool) error { + return nil +} + +func (self *SInstanceType) GetInstanceTypeFamily() string { + if len(self.OSExtraSpecs.EcsGeneration) > 0 { + return self.OSExtraSpecs.EcsGeneration + } else { + return strings.Split(self.ID, ".")[0] + } +} + +func (self *SInstanceType) GetInstanceTypeCategory() string { + return getFlavorCategory(self.GetInstanceTypeFamily()) +} + +func (self *SInstanceType) GetPrepaidStatus() string { + return "available" +} + +func (self *SInstanceType) GetPostpaidStatus() string { + return "available" +} + +// https://support.huaweicloud.com/productdesc-ecs/ecs_01_0066.html +// https://support.huaweicloud.com/ecs_faq/ecs_faq_0105.html +func (self *SInstanceType) GetCpuArch() string { + if len(self.OSExtraSpecs.EcsInstanceArchitecture) > 0 { + if strings.ToLower(self.OSExtraSpecs.EcsInstanceArchitecture) == "arm64" { + return apis.OS_ARCH_AARCH64 + } + + if strings.HasPrefix(self.OSExtraSpecs.EcsInstanceArchitecture, "arm") { + return apis.OS_ARCH_AARCH64 + } + } + + if strings.HasPrefix(self.ID, "k") { + return apis.OS_ARCH_AARCH64 + } + + return apis.OS_ARCH_X86 +} + +func (self *SInstanceType) GetCpuCoreCount() int { + count, err := strconv.Atoi(self.Vcpus) + if err == nil { + return count + } + return 0 +} + +func (self *SInstanceType) GetMemorySizeMB() int { + return self.RamMB +} + +func (self *SInstanceType) GetOsName() string { + return "" +} + +func (self *SInstanceType) GetSysDiskResizable() bool { + return false +} + +func (self *SInstanceType) GetSysDiskType() string { + return "" +} + +func (self *SInstanceType) GetSysDiskMinSizeGB() int { + return 0 +} + +func (self *SInstanceType) GetSysDiskMaxSizeGB() int { + return 0 +} + +func (self *SInstanceType) GetAttachedDiskType() string { + return "" +} + +func (self *SInstanceType) GetAttachedDiskSizeGB() int { + return 0 +} + +func (self *SInstanceType) GetAttachedDiskCount() int { + return 0 +} + +func (self *SInstanceType) GetDataDiskTypes() string { + return "" +} + +func (self *SInstanceType) GetDataDiskMaxCount() int { + return 0 +} + +func (self *SInstanceType) GetNicType() string { + return "" +} + +func (self *SInstanceType) GetNicMaxCount() int { + return 0 +} + +func (self *SInstanceType) GetGpuAttachable() bool { + return self.OSExtraSpecs.EcsPerformancetype == "gpu" +} + +func (self *SInstanceType) GetGpuSpec() string { + if self.OSExtraSpecs.EcsPerformancetype == "gpu" { + return self.OSExtraSpecs.EcsGeneration + } + + return "" +} + +func (self *SInstanceType) GetGpuCount() int { + if self.OSExtraSpecs.EcsPerformancetype == "gpu" { + return 1 + } + + return 0 +} + +func (self *SInstanceType) GetGpuMaxCount() int { + if self.OSExtraSpecs.EcsPerformancetype == "gpu" { + return 1 + } + + return 0 +} + +func (self *SInstanceType) Delete() error { + return nil +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212656.html +func (self *SRegion) fetchInstanceTypes(zoneId string) ([]SInstanceType, error) { + querys := map[string]string{} + if len(zoneId) > 0 { + querys["availability_zone"] = zoneId + } + + instanceTypes := make([]SInstanceType, 0) + err := doListAll(self.ecsClient.Flavors.List, querys, &instanceTypes) + return instanceTypes, err +} + +func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, zoneId string) ([]SInstanceType, error) { + instanceTypes, err := self.fetchInstanceTypes(zoneId) + if err != nil { + return nil, err + } + + ret := make([]SInstanceType, 0) + for _, t := range instanceTypes { + // cpu & mem & disk都匹配才行 + if t.Vcpus == strconv.Itoa(cpu) && t.RamMB == memMB { + ret = append(ret, t) + } + } + + return ret, nil +} diff --git a/pkg/multicloud/hcso/keypair.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/keypair.go similarity index 100% rename from pkg/multicloud/hcso/keypair.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/keypair.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/latitud_and_longitude.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/latitud_and_longitude.go new file mode 100644 index 0000000000..632454e298 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/latitud_and_longitude.go @@ -0,0 +1,44 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +// China: https://developer.huaweicloud.com/endpoint +// International: https://developer-intl.huaweicloud.com/endpoint +// ref: https://countrycode.org +var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ + "cn-east-2": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-east-3": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-north-1": {Latitude: 39.997743, Longitude: 116.304542, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-north-4": {Latitude: 39.997743, Longitude: 116.304542, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-south-1": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-south-2": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "ap-southeast-1": {Latitude: 22.396428, Longitude: 114.109497, City: api.CITY_HONG_KONG, CountryCode: api.COUNTRY_CODE_CN}, + "ap-southeast-2": {Latitude: 13.7563309, Longitude: 100.5017651, City: api.CITY_BANGKOK, CountryCode: api.COUNTRY_CODE_TH}, + "ap-southeast-3": {Latitude: 1.360386, Longitude: 103.821195, City: api.CITY_SINGAPORE, CountryCode: api.COUNTRY_CODE_SG}, + "eu-west-0": {Latitude: 48.856614, Longitude: 2.3522219, City: api.CITY_PARIS, CountryCode: api.COUNTRY_CODE_FR}, + "cn-northeast-1": {Latitude: 38.91400300000001, Longitude: 121.614682, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-southwest-2": {Latitude: 26.6470035286, Longitude: 106.6302113880, City: api.CITY_GUI_YANG, CountryCode: api.COUNTRY_CODE_CN}, + "af-south-1": {Latitude: -26.1714537, Longitude: 27.8999389, City: api.CITY_JOHANNESBURG, CountryCode: api.COUNTRY_CODE_ZA}, + "sa-brazil-1": {Latitude: -23.5505199, Longitude: -46.6333094, City: api.CITY_SAO_PAULO, CountryCode: api.COUNTRY_CODE_BR}, + "na-mexico-1": {Latitude: 55.1182908, Longitude: 141.0377645, City: api.CITY_MEXICO, CountryCode: api.COUNTRY_CODE_MX}, + "la-south-2": {Latitude: -33.45206, Longitude: -70.676031, City: api.CITY_SANTIAGO, CountryCode: api.COUNTRY_CODE_CL}, + "cn-north-9": {Latitude: 41.0178713, Longitude: 113.094978, City: api.CITY_NEI_MENG_GU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-north-219": {Latitude: 39.997743, Longitude: 116.304542, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer.go new file mode 100644 index 0000000000..7c656bc7b0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer.go @@ -0,0 +1,554 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +var LB_ALGORITHM_MAP = map[string]string{ + api.LB_SCHEDULER_WRR: "ROUND_ROBIN", + api.LB_SCHEDULER_WLC: "LEAST_CONNECTIONS", + api.LB_SCHEDULER_SCH: "SOURCE_IP", +} + +var LB_PROTOCOL_MAP = map[string]string{ + api.LB_LISTENER_TYPE_HTTP: "HTTP", + api.LB_LISTENER_TYPE_HTTPS: "TERMINATED_HTTPS", + api.LB_LISTENER_TYPE_UDP: "UDP", + api.LB_LISTENER_TYPE_TCP: "TCP", +} + +var LBBG_PROTOCOL_MAP = map[string]string{ + api.LB_LISTENER_TYPE_HTTP: "HTTP", + api.LB_LISTENER_TYPE_HTTPS: "HTTP", + api.LB_LISTENER_TYPE_UDP: "UDP", + api.LB_LISTENER_TYPE_TCP: "TCP", +} + +var LB_STICKY_SESSION_MAP = map[string]string{ + api.LB_STICKY_SESSION_TYPE_INSERT: "HTTP_COOKIE", + api.LB_STICKY_SESSION_TYPE_SERVER: "APP_COOKIE", +} + +var LB_HEALTHCHECK_TYPE_MAP = map[string]string{ + api.LB_HEALTH_CHECK_HTTP: "HTTP", + api.LB_HEALTH_CHECK_TCP: "TCP", + api.LB_HEALTH_CHECK_UDP: "UDP_CONNECT", +} + +type SLoadbalancer struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + subnet *SNetwork + eip *SEipAddress + + Description string `json:"description"` + ProvisioningStatus string `json:"provisioning_status"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + AdminStateUp bool `json:"admin_state_up"` + Provider string `json:"provider"` + Pools []Pool `json:"pools"` + Listeners []Listener `json:"listeners"` + VipPortID string `json:"vip_port_id"` + OperatingStatus string `json:"operating_status"` + VipAddress string `json:"vip_address"` + VipSubnetID string `json:"vip_subnet_id"` + ID string `json:"id"` + Name string `json:"name"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +type Listener struct { + ID string `json:"id"` +} + +type Pool struct { + ID string `json:"id"` +} + +func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { + if self.GetEip() == nil { + return nil, nil + } + + return self.eip, nil +} + +func (self *SLoadbalancer) GetId() string { + return self.ID +} + +func (self *SLoadbalancer) GetName() string { + return self.Name +} + +func (self *SLoadbalancer) GetGlobalId() string { + return self.ID +} + +func (self *SLoadbalancer) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancer) Refresh() error { + lb, err := self.region.GetLoadbalancer(self.GetId()) + if err != nil { + return err + } + + return jsonutils.Update(self, lb) +} + +func (self *SLoadbalancer) IsEmulated() bool { + return false +} + +func (self *SLoadbalancer) GetProjectId() string { + return self.ProjectID +} + +func (self *SLoadbalancer) GetAddress() string { + return self.VipAddress +} + +// todo: api.LB_ADDR_TYPE_INTERNET? +func (self *SLoadbalancer) GetAddressType() string { + return api.LB_ADDR_TYPE_INTRANET +} + +func (self *SLoadbalancer) GetNetworkType() string { + return api.LB_NETWORK_TYPE_VPC +} + +func (self *SLoadbalancer) GetNetworkIds() []string { + net := self.GetNetwork() + if net != nil { + return []string{net.GetId()} + } + + return []string{} +} + +func (self *SLoadbalancer) GetNetwork() *SNetwork { + if self.subnet == nil { + port, err := self.region.GetPort(self.VipPortID) + if err == nil { + net, err := self.region.getNetwork(port.NetworkID) + if err == nil { + self.subnet = net + } else { + log.Debugf("huawei.SLoadbalancer.getNetwork %s", err) + } + } else { + log.Debugf("huawei.SLoadbalancer.GetPort %s", err) + } + } + + return self.subnet +} + +func (self *SLoadbalancer) GetEip() *SEipAddress { + if self.eip == nil { + eips, _ := self.region.GetEips() + for i := range eips { + eip := &eips[i] + if eip.PortId == self.VipPortID { + self.eip = eip + } + } + } + + return self.eip +} + +func (self *SLoadbalancer) GetVpcId() string { + net := self.GetNetwork() + if net != nil { + return net.VpcID + } + + return "" +} + +func (self *SLoadbalancer) GetZoneId() string { + net := self.GetNetwork() + if net != nil { + z, err := self.region.getZoneById(net.AvailabilityZone) + if err != nil { + log.Infof("getZoneById %s %s", net.AvailabilityZone, err) + return "" + } + + return z.GetGlobalId() + } + + return "" +} + +func (self *SLoadbalancer) GetZone1Id() string { + return "" +} + +func (self *SLoadbalancer) GetLoadbalancerSpec() string { + return "" +} + +func (self *SLoadbalancer) GetChargeType() string { + eip := self.GetEip() + if eip != nil { + return eip.GetInternetChargeType() + } + + return api.EIP_CHARGE_TYPE_BY_TRAFFIC +} + +func (self *SLoadbalancer) GetEgressMbps() int { + eip := self.GetEip() + if eip != nil { + return eip.GetBandwidth() + } + + return 0 +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0141008275.html +func (self *SLoadbalancer) Delete(ctx context.Context) error { + return self.region.DeleteLoadBalancer(self.GetId()) +} + +func (self *SLoadbalancer) Start() error { + return nil +} + +func (self *SLoadbalancer) Stop() error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + ret, err := self.region.GetLoadBalancerListeners(self.GetId()) + if err != nil { + return nil, err + } + + iret := make([]cloudprovider.ICloudLoadbalancerListener, 0) + for i := range ret { + listener := ret[i] + listener.lb = self + iret = append(iret, &listener) + } + + return iret, nil +} + +func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + ret, err := self.region.GetLoadBalancerBackendGroups(self.GetId()) + if err != nil { + return nil, err + } + + iret := make([]cloudprovider.ICloudLoadbalancerBackendGroup, 0) + for i := range ret { + bg := ret[i] + bg.lb = self + iret = append(iret, &bg) + } + + return iret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561549.html +func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + ret, err := self.region.CreateLoadBalancerBackendGroup(group) + ret.lb = self + return &ret, err +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561563.html +func (self *SLoadbalancer) CreateHealthCheck(backendGroupId string, healthcheck *cloudprovider.SLoadbalancerHealthCheck) error { + _, err := self.region.CreateLoadBalancerHealthCheck(backendGroupId, healthcheck) + return err +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561548.html +func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + ret := &SElbBackendGroup{} + err := DoGet(self.region.ecsClient.ElbBackendGroup.Get, groupId, nil, ret) + if err != nil { + return nil, err + } + + ret.lb = self + ret.region = self.region + return ret, nil +} + +func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + ret, err := self.region.CreateLoadBalancerListener(listener) + if err != nil { + return nil, err + } + + ret.lb = self + return &ret, nil +} + +func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { + ret := &SElbListener{} + err := DoGet(self.region.ecsClient.ElbListeners.Get, listenerId, nil, ret) + if err != nil { + return nil, err + } + + ret.lb = self + return ret, nil +} + +func (self *SRegion) GetLoadbalancer(lgId string) (SLoadbalancer, error) { + elb := SLoadbalancer{} + err := DoGet(self.ecsClient.Elb.Get, lgId, nil, &elb) + if err != nil { + return elb, err + } + + return elb, nil +} + +func (self *SRegion) DeleteLoadBalancer(elbId string) error { + return DoDelete(self.ecsClient.Elb.Delete, elbId, nil, nil) +} + +func (self *SRegion) GetLoadBalancerListeners(lbId string) ([]SElbListener, error) { + params := map[string]string{} + if len(lbId) > 0 { + params["loadbalancer_id"] = lbId + } + + ret := make([]SElbListener, 0) + err := doListAll(self.ecsClient.ElbListeners.List, params, &ret) + if err != nil { + return nil, err + } + + return ret, nil +} + +func (self *SRegion) CreateLoadBalancerListener(listener *cloudprovider.SLoadbalancerListener) (SElbListener, error) { + params := jsonutils.NewDict() + listenerObj := jsonutils.NewDict() + listenerObj.Set("name", jsonutils.NewString(listener.Name)) + listenerObj.Set("description", jsonutils.NewString(listener.Description)) + listenerObj.Set("protocol", jsonutils.NewString(LB_PROTOCOL_MAP[listener.ListenerType])) + listenerObj.Set("protocol_port", jsonutils.NewInt(int64(listener.ListenerPort))) + listenerObj.Set("loadbalancer_id", jsonutils.NewString(listener.LoadbalancerID)) + listenerObj.Set("http2_enable", jsonutils.NewBool(listener.EnableHTTP2)) + if len(listener.BackendGroupID) > 0 { + listenerObj.Set("default_pool_id", jsonutils.NewString(listener.BackendGroupID)) + } + + if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { + listenerObj.Set("default_tls_container_ref", jsonutils.NewString(listener.CertificateID)) + } + + if listener.XForwardedFor { + insertObj := jsonutils.NewDict() + insertObj.Set("X-Forwarded-ELB-IP", jsonutils.NewBool(listener.XForwardedFor)) + listenerObj.Set("insert_headers", insertObj) + } + params.Set("listener", listenerObj) + ret := SElbListener{} + err := DoCreate(self.ecsClient.ElbListeners.Create, params, &ret) + if err != nil { + return ret, err + } + + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html +func (self *SRegion) GetLoadBalancerBackendGroups(elbId string) ([]SElbBackendGroup, error) { + params := map[string]string{} + if len(elbId) > 0 { + params["loadbalancer_id"] = elbId + } + + ret := make([]SElbBackendGroup, 0) + err := doListAll(self.ecsClient.ElbBackendGroup.List, params, &ret) + if err != nil { + return nil, err + } + + for i := range ret { + ret[i].region = self + } + + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html +func (self *SRegion) CreateLoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (SElbBackendGroup, error) { + ret := SElbBackendGroup{} + var protocol, scheduler string + if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { + return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) + } else { + scheduler = s + } + + if t, ok := LBBG_PROTOCOL_MAP[group.ListenType]; !ok { + return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported listener type %s", group.ListenType) + } else { + protocol = t + } + + params := jsonutils.NewDict() + poolObj := jsonutils.NewDict() + poolObj.Set("project_id", jsonutils.NewString(self.client.projectId)) + poolObj.Set("name", jsonutils.NewString(group.Name)) + poolObj.Set("protocol", jsonutils.NewString(protocol)) + poolObj.Set("lb_algorithm", jsonutils.NewString(scheduler)) + + if len(group.ListenerID) > 0 { + poolObj.Set("listener_id", jsonutils.NewString(group.ListenerID)) + } else if len(group.LoadbalancerID) > 0 { + poolObj.Set("loadbalancer_id", jsonutils.NewString(group.LoadbalancerID)) + } else { + return ret, fmt.Errorf("CreateLoadBalancerBackendGroup one of listener id / loadbalancer id must be specified") + } + + if group.StickySession != nil { + s := jsonutils.NewDict() + timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) + if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { + s.Set("type", jsonutils.NewString("SOURCE_IP")) + if timeout > 0 { + s.Set("persistence_timeout", jsonutils.NewInt(timeout)) + } + } else { + s.Set("type", jsonutils.NewString(LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType])) + if len(group.StickySession.StickySessionCookie) > 0 { + s.Set("cookie_name", jsonutils.NewString(group.StickySession.StickySessionCookie)) + } else { + if timeout > 0 { + s.Set("persistence_timeout", jsonutils.NewInt(timeout)) + } + } + } + + poolObj.Set("session_persistence", s) + } + params.Set("pool", poolObj) + err := DoCreate(self.ecsClient.ElbBackendGroup.Create, params, &ret) + if err != nil { + return ret, err + } + + if group.HealthCheck != nil { + _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) + if err != nil { + return ret, err + } + } + + ret.region = self + return ret, nil +} + +func (self *SRegion) CreateLoadBalancerHealthCheck(backendGroupID string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { + params := jsonutils.NewDict() + healthObj := jsonutils.NewDict() + healthObj.Set("delay", jsonutils.NewInt(int64(healthCheck.HealthCheckInterval))) + healthObj.Set("max_retries", jsonutils.NewInt(int64(healthCheck.HealthCheckRise))) + healthObj.Set("pool_id", jsonutils.NewString(backendGroupID)) + healthObj.Set("timeout", jsonutils.NewInt(int64(healthCheck.HealthCheckTimeout))) + healthObj.Set("type", jsonutils.NewString(LB_HEALTHCHECK_TYPE_MAP[healthCheck.HealthCheckType])) + if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { + if len(healthCheck.HealthCheckDomain) > 0 { + healthObj.Set("domain_name", jsonutils.NewString(healthCheck.HealthCheckDomain)) + } + + if len(healthCheck.HealthCheckURI) > 0 { + healthObj.Set("url_path", jsonutils.NewString(healthCheck.HealthCheckURI)) + } + + if len(healthCheck.HealthCheckHttpCode) > 0 { + healthObj.Set("expected_codes", jsonutils.NewString(ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode))) + } + } + params.Set("healthmonitor", healthObj) + + ret := SElbHealthCheck{} + err := DoCreate(self.ecsClient.ElbHealthCheck.Create, params, &ret) + if err != nil { + return ret, err + } + + ret.region = self + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561564.html +func (self *SRegion) UpdateLoadBalancerHealthCheck(healthCheckID string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { + params := jsonutils.NewDict() + healthObj := jsonutils.NewDict() + healthObj.Set("delay", jsonutils.NewInt(int64(healthCheck.HealthCheckInterval))) + healthObj.Set("max_retries", jsonutils.NewInt(int64(healthCheck.HealthCheckRise))) + healthObj.Set("timeout", jsonutils.NewInt(int64(healthCheck.HealthCheckTimeout))) + if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { + if len(healthCheck.HealthCheckDomain) > 0 { + healthObj.Set("domain_name", jsonutils.NewString(healthCheck.HealthCheckDomain)) + } + + if len(healthCheck.HealthCheckURI) > 0 { + healthObj.Set("url_path", jsonutils.NewString(healthCheck.HealthCheckURI)) + } + + if len(healthCheck.HealthCheckHttpCode) > 0 { + healthObj.Set("expected_codes", jsonutils.NewString(ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode))) + } + } + params.Set("healthmonitor", healthObj) + + ret := SElbHealthCheck{} + err := DoUpdate(self.ecsClient.ElbHealthCheck.Update, healthCheckID, params, &ret) + if err != nil { + return ret, err + } + + ret.region = self + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561565.html +func (self *SRegion) DeleteLoadbalancerHealthCheck(healthCheckID string) error { + return DoDelete(self.ecsClient.ElbHealthCheck.Delete, healthCheckID, nil, nil) +} + +func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_acl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_acl.go new file mode 100644 index 0000000000..c9f78076eb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_acl.go @@ -0,0 +1,114 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "strings" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SElbACL struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + + ID string `json:"id"` + ListenerID string `json:"listener_id"` + TenantID string `json:"tenant_id"` + EnableWhitelist bool `json:"enable_whitelist"` + Whitelist string `json:"whitelist"` +} + +func (self *SElbACL) GetAclListenerID() string { + return self.ListenerID +} + +func (self *SElbACL) GetId() string { + return self.ID +} + +func (self *SElbACL) GetName() string { + return self.ID +} + +func (self *SElbACL) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbACL) GetStatus() string { + if self.EnableWhitelist { + return api.LB_BOOL_ON + } + + return api.LB_BOOL_OFF +} + +func (self *SElbACL) Refresh() error { + acl, err := self.region.GetLoadBalancerAclById(self.GetId()) + if err != nil { + return err + } + + err = jsonutils.Update(self, acl) + if err != nil { + return err + } + + return nil +} + +func (self *SElbACL) IsEmulated() bool { + return false +} + +func (self *SElbACL) GetProjectId() string { + return "" +} + +func (self *SElbACL) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { + ret := []cloudprovider.SLoadbalancerAccessControlListEntry{} + for _, cidr := range strings.Split(self.Whitelist, ",") { + ret = append(ret, cloudprovider.SLoadbalancerAccessControlListEntry{CIDR: cidr}) + } + + return ret +} + +func (self *SElbACL) Sync(acl *cloudprovider.SLoadbalancerAccessControlList) error { + whiteList := "" + cidrs := []string{} + for _, entry := range acl.Entrys { + cidrs = append(cidrs, entry.CIDR) + } + + whiteList = strings.Join(cidrs, ",") + + params := jsonutils.NewDict() + whiteListObj := jsonutils.NewDict() + whiteListObj.Set("whitelist", jsonutils.NewString(whiteList)) + whiteListObj.Set("enable_whitelist", jsonutils.NewBool(acl.AccessControlEnable)) + params.Set("whitelist", whiteListObj) + return DoUpdate(self.region.ecsClient.ElbWhitelist.Update, self.GetId(), params, nil) +} + +func (self *SElbACL) Delete() error { + return DoDelete(self.region.ecsClient.ElbWhitelist.Delete, self.GetId(), nil, nil) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_backend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_backend.go new file mode 100644 index 0000000000..3d004a6a56 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_backend.go @@ -0,0 +1,169 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SElbBackend struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + lb *SLoadbalancer + backendGroup *SElbBackendGroup + + Name string `json:"name"` + Weight int `json:"weight"` + AdminStateUp bool `json:"admin_state_up"` + SubnetID string `json:"subnet_id"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + Address string `json:"address"` + ProtocolPort int `json:"protocol_port"` + OperatingStatus string `json:"operating_status"` + ID string `json:"id"` +} + +func (self *SElbBackend) GetId() string { + return self.ID +} + +func (self *SElbBackend) GetName() string { + return self.Name +} + +func (self *SElbBackend) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbBackend) Refresh() error { + m := self.lb.region.ecsClient.ElbBackend + err := m.SetBackendGroupId(self.backendGroup.GetId()) + if err != nil { + return err + } + + backend := SElbBackend{} + err = DoGet(m.Get, self.GetId(), nil, &backend) + if err != nil { + return err + } + + backend.lb = self.lb + backend.backendGroup = self.backendGroup + err = jsonutils.Update(self, backend) + if err != nil { + return err + } + + return nil +} + +func (self *SElbBackend) IsEmulated() bool { + return false +} + +func (self *SElbBackend) GetProjectId() string { + return "" +} + +func (self *SElbBackend) GetWeight() int { + return self.Weight +} + +func (self *SElbBackend) GetPort() int { + return self.ProtocolPort +} + +func (self *SElbBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (self *SElbBackend) GetBackendRole() string { + return api.LB_BACKEND_ROLE_DEFAULT +} + +func (self *SElbBackend) GetBackendId() string { + i, err := self.lb.region.getInstanceByIP(self.Address) + if err != nil { + log.Errorf("ElbBackend GetBackendId %s", err) + } + + if i != nil { + return i.GetId() + } + + return "" +} + +func (self *SElbBackend) GetIpAddress() string { + return "" +} + +func (self *SElbBackend) SyncConf(ctx context.Context, port, weight int) error { + if port > 0 { + log.Warningf("Elb backend SyncConf unsupport modify port") + } + + params := jsonutils.NewDict() + memberObj := jsonutils.NewDict() + memberObj.Set("weight", jsonutils.NewInt(int64(weight))) + params.Set("member", memberObj) + err := self.lb.region.ecsClient.ElbBackend.SetBackendGroupId(self.backendGroup.GetId()) + if err != nil { + return err + } + return DoUpdate(self.lb.region.ecsClient.ElbBackend.Update, self.GetId(), params, nil) +} + +func (self *SRegion) getInstanceByIP(privateIP string) (*SInstance, error) { + queries := make(map[string]string) + + if len(self.client.projectId) > 0 { + queries["project_id"] = self.client.projectId + } + + if len(privateIP) > 0 { + queries["ip"] = privateIP + } + + instances := make([]SInstance, 0) + err := doListAllWithOffset(self.ecsClient.Servers.List, queries, &instances) + if err != nil { + return nil, err + } + + if len(instances) == 1 { + return &instances[0], nil + } else if len(instances) > 1 { + log.Warningf("SRegion.getInstanceByIP %s result: multiple server find", privateIP) + return &instances[0], nil + } + + return nil, cloudprovider.ErrNotFound +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_backendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_backendgroup.go new file mode 100644 index 0000000000..b575cb58ae --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_backendgroup.go @@ -0,0 +1,542 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SElbBackendGroup struct { + multicloud.SResourceBase + huawei.HuaweiTags + lb *SLoadbalancer + region *SRegion + + LBAlgorithm string `json:"lb_algorithm"` + Protocol string `json:"protocol"` + Description string `json:"description"` + AdminStateUp bool `json:"admin_state_up"` + Loadbalancers []Listener `json:"loadbalancers"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + Listeners []Listener `json:"listeners"` + ID string `json:"id"` + Name string `json:"name"` + HealthMonitorID string `json:"healthmonitor_id"` + SessionPersistence StickySession `json:"session_persistence"` +} + +func (self *SElbBackendGroup) GetLoadbalancerId() string { + return self.lb.GetId() +} + +func (self *SElbBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { + return self.lb +} + +type StickySession struct { + Type string `json:"type"` + CookieName string `json:"cookie_name"` + PersistenceTimeout int `json:"persistence_timeout"` +} + +func (self *SElbBackendGroup) GetProtocolType() string { + switch self.Protocol { + case "TCP": + return api.LB_LISTENER_TYPE_TCP + case "UDP": + return api.LB_LISTENER_TYPE_UDP + case "HTTP": + return api.LB_LISTENER_TYPE_HTTP + default: + return "" + } +} + +func (self *SElbBackendGroup) GetScheduler() string { + switch self.LBAlgorithm { + case "ROUND_ROBIN": + return api.LB_SCHEDULER_WRR + case "LEAST_CONNECTIONS": + return api.LB_SCHEDULER_WLC + case "SOURCE_IP": + return api.LB_SCHEDULER_SCH + default: + return "" + } +} + +func ToHuaweiHealthCheckHttpCode(c string) string { + c = strings.TrimSpace(c) + segs := strings.Split(c, ",") + ret := []string{} + for _, seg := range segs { + seg = strings.TrimLeft(seg, "http_") + seg = strings.TrimSpace(seg) + seg = strings.Replace(seg, "xx", "00", -1) + ret = append(ret, seg) + } + + return strings.Join(ret, ",") +} + +func ToOnecloudHealthCheckHttpCode(c string) string { + c = strings.TrimSpace(c) + segs := strings.Split(c, ",") + ret := []string{} + for _, seg := range segs { + seg = strings.TrimSpace(seg) + seg = strings.Replace(seg, "00", "xx", -1) + seg = "http_" + seg + ret = append(ret, seg) + } + + return strings.Join(ret, ",") +} + +func (self *SElbBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + if len(self.HealthMonitorID) == 0 { + return nil, nil + } + + health, err := self.region.GetLoadBalancerHealthCheck(self.HealthMonitorID) + if err != nil { + return nil, err + } + + var healthCheckType string + switch health.Type { + case "TCP": + healthCheckType = api.LB_HEALTH_CHECK_TCP + case "UDP_CONNECT": + healthCheckType = api.LB_HEALTH_CHECK_UDP + case "HTTP": + healthCheckType = api.LB_HEALTH_CHECK_HTTP + default: + healthCheckType = "" + } + + ret := cloudprovider.SLoadbalancerHealthCheck{ + HealthCheckType: healthCheckType, + HealthCheckTimeout: health.Timeout, + HealthCheckDomain: health.DomainName, + HealthCheckURI: health.URLPath, + HealthCheckInterval: health.Delay, + HealthCheckRise: health.MaxRetries, + HealthCheckHttpCode: ToOnecloudHealthCheckHttpCode(health.ExpectedCodes), + } + + return &ret, nil +} + +func (self *SElbBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + if len(self.SessionPersistence.Type) == 0 { + return nil, nil + } + + var stickySessionType string + switch self.SessionPersistence.Type { + case "SOURCE_IP": + stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT + case "HTTP_COOKIE": + stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT + case "APP_COOKIE": + stickySessionType = api.LB_STICKY_SESSION_TYPE_SERVER + } + + ret := cloudprovider.SLoadbalancerStickySession{ + StickySession: api.LB_BOOL_ON, + StickySessionCookie: self.SessionPersistence.CookieName, + StickySessionType: stickySessionType, + StickySessionCookieTimeout: self.SessionPersistence.PersistenceTimeout * 60, + } + + return &ret, nil +} + +func (self *SElbBackendGroup) GetId() string { + return self.ID +} + +func (self *SElbBackendGroup) GetName() string { + return self.Name +} + +func (self *SElbBackendGroup) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbBackendGroup) Refresh() error { + ret, err := self.lb.region.GetLoadBalancerBackendGroupId(self.GetId()) + if err != nil { + return err + } + ret.lb = self.lb + + err = jsonutils.Update(self, ret) + if err != nil { + return err + } + + return nil +} + +func (self *SElbBackendGroup) IsEmulated() bool { + return false +} + +func (self *SElbBackendGroup) GetProjectId() string { + return self.ProjectID +} + +func (self *SElbBackendGroup) IsDefault() bool { + return false +} + +func (self *SElbBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_NORMAL +} + +func (self *SElbBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + ret, err := self.region.GetLoadBalancerBackends(self.GetId()) + if err != nil { + return nil, err + } + + iret := []cloudprovider.ICloudLoadbalancerBackend{} + for i := range ret { + backend := ret[i] + backend.lb = self.lb + backend.backendGroup = self + + iret = append(iret, &backend) + } + + return iret, nil +} + +func (self *SElbBackendGroup) GetILoadbalancerBackendById(serverId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + m := self.lb.region.ecsClient.ElbBackend + err := m.SetBackendGroupId(self.GetId()) + if err != nil { + return nil, err + } + + backend := SElbBackend{} + err = DoGet(m.Get, serverId, nil, &backend) + if err != nil { + return nil, err + } + + backend.lb = self.lb + backend.backendGroup = self + return &backend, nil +} + +func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + instance, err := self.lb.region.GetInstanceByID(serverId) + if err != nil { + return nil, err + } + + nics, err := instance.GetINics() + if err != nil { + return nil, err + } else if len(nics) == 0 { + return nil, fmt.Errorf("AddBackendServer %s no network interface found", serverId) + } + + subnets, err := self.lb.region.getSubnetIdsByInstanceId(instance.GetId()) + if err != nil { + return nil, err + } else if len(subnets) == 0 { + return nil, fmt.Errorf("AddBackendServer %s no subnet found", serverId) + } + + net, err := self.lb.region.getNetwork(subnets[0]) + if err != nil { + return nil, err + } + + backend, err := self.region.AddLoadBalancerBackend(self.GetId(), net.NeutronSubnetID, nics[0].GetIP(), port, weight) + if err != nil { + return nil, err + } + + backend.lb = self.lb + backend.backendGroup = self + return &backend, nil +} + +func (self *SElbBackendGroup) RemoveBackendServer(backendId string, weight int, port int) error { + ibackend, err := self.GetILoadbalancerBackendById(backendId) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + + return errors.Wrap(err, "ElbBackendGroup.GetILoadbalancerBackendById") + } + + err = self.region.RemoveLoadBalancerBackend(self.GetId(), backendId) + if err != nil { + return errors.Wrap(err, "ElbBackendGroup.RemoveBackendServer") + } + + return cloudprovider.WaitDeleted(ibackend, 2*time.Second, 30*time.Second) +} + +func (self *SElbBackendGroup) Delete(ctx context.Context) error { + if len(self.HealthMonitorID) > 0 { + err := self.region.DeleteLoadbalancerHealthCheck(self.HealthMonitorID) + if err != nil { + return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadbalancerHealthCheck") + } + } + + // 删除后端服务器组的同时,删除掉无效的后端服务器数据 + { + backends, err := self.region.getLoadBalancerAdminStateDownBackends(self.GetId()) + if err != nil { + return errors.Wrap(err, "SElbBackendGroup.Delete.getLoadBalancerAdminStateDownBackends") + } + + for i := range backends { + backend := backends[i] + err := self.RemoveBackendServer(backend.GetId(), backend.GetPort(), backend.GetWeight()) + if err != nil { + return errors.Wrap(err, "SElbBackendGroup.Delete.RemoveBackendServer") + } + } + } + + err := self.region.DeleteLoadBalancerBackendGroup(self.GetId()) + if err != nil { + return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadBalancerBackendGroup") + } + + return cloudprovider.WaitDeleted(self, 2*time.Second, 30*time.Second) +} + +func (self *SElbBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + if group == nil { + return nil + } + + _, err := self.region.UpdateLoadBalancerBackendGroup(self.GetId(), group) + return err +} + +func (self *SRegion) GetLoadBalancerBackendGroupId(backendGroupId string) (SElbBackendGroup, error) { + ret := SElbBackendGroup{} + err := DoGet(self.ecsClient.ElbBackendGroup.Get, backendGroupId, nil, &ret) + if err != nil { + return ret, err + } + + ret.region = self + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561550.html +func (self *SRegion) UpdateLoadBalancerBackendGroup(backendGroupID string, group *cloudprovider.SLoadbalancerBackendGroup) (SElbBackendGroup, error) { + params := jsonutils.NewDict() + poolObj := jsonutils.NewDict() + poolObj.Set("name", jsonutils.NewString(group.Name)) + var scheduler string + if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { + return SElbBackendGroup{}, fmt.Errorf("UpdateLoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) + } else { + scheduler = s + } + poolObj.Set("lb_algorithm", jsonutils.NewString(scheduler)) + + if group.StickySession == nil || group.StickySession.StickySession == api.LB_BOOL_OFF { + poolObj.Set("session_persistence", jsonutils.JSONNull) + } else { + s := jsonutils.NewDict() + timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) + if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { + s.Set("type", jsonutils.NewString("SOURCE_IP")) + if timeout > 0 { + s.Set("persistence_timeout", jsonutils.NewInt(timeout)) + } + } else { + s.Set("type", jsonutils.NewString(LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType])) + if len(group.StickySession.StickySessionCookie) > 0 { + s.Set("cookie_name", jsonutils.NewString(group.StickySession.StickySessionCookie)) + } else { + if timeout > 0 { + s.Set("persistence_timeout", jsonutils.NewInt(timeout)) + } + } + } + + poolObj.Set("session_persistence", s) + } + params.Set("pool", poolObj) + + ret := SElbBackendGroup{} + err := DoUpdate(self.ecsClient.ElbBackendGroup.Update, backendGroupID, params, &ret) + if err != nil { + return ret, errors.Wrap(err, "ElbBackendGroup.Update") + } + + if group.HealthCheck == nil && len(ret.HealthMonitorID) > 0 { + err := self.DeleteLoadbalancerHealthCheck(ret.HealthMonitorID) + if err != nil { + return ret, errors.Wrap(err, "DeleteLoadbalancerHealthCheck") + } + } + + if group.HealthCheck != nil { + if len(ret.HealthMonitorID) == 0 { + _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) + if err != nil { + return ret, errors.Wrap(err, "CreateLoadBalancerHealthCheck") + } + } else { + _, err := self.UpdateLoadBalancerHealthCheck(ret.HealthMonitorID, group.HealthCheck) + if err != nil { + return ret, errors.Wrap(err, "UpdateLoadBalancerHealthCheck") + } + } + } + + ret.region = self + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561551.html +func (self *SRegion) DeleteLoadBalancerBackendGroup(backendGroupID string) error { + return DoDelete(self.ecsClient.ElbBackendGroup.Delete, backendGroupID, nil, nil) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561556.html +func (self *SRegion) AddLoadBalancerBackend(backendGroupId, subnetId, ipaddr string, port, weight int) (SElbBackend, error) { + backend := SElbBackend{} + params := jsonutils.NewDict() + memberObj := jsonutils.NewDict() + memberObj.Set("address", jsonutils.NewString(ipaddr)) + memberObj.Set("protocol_port", jsonutils.NewInt(int64(port))) + memberObj.Set("subnet_id", jsonutils.NewString(subnetId)) + memberObj.Set("weight", jsonutils.NewInt(int64(weight))) + params.Set("member", memberObj) + + m := self.ecsClient.ElbBackend + err := m.SetBackendGroupId(backendGroupId) + if err != nil { + return backend, err + } + + err = DoCreate(m.Create, params, &backend) + if err != nil { + return backend, err + } + + return backend, nil +} + +func (self *SRegion) RemoveLoadBalancerBackend(lbbgId string, backendId string) error { + m := self.ecsClient.ElbBackend + err := m.SetBackendGroupId(lbbgId) + if err != nil { + return err + } + + return DoDelete(m.Delete, backendId, nil, nil) +} + +func (self *SRegion) getLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { + m := self.ecsClient.ElbBackend + err := m.SetBackendGroupId(backendGroupId) + if err != nil { + return nil, err + } + + ret := []SElbBackend{} + err = doListAll(m.List, nil, &ret) + if err != nil { + return nil, err + } + + for i := range ret { + backend := ret[i] + backend.region = self + } + + return ret, nil +} + +func (self *SRegion) GetLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { + ret, err := self.getLoadBalancerBackends(backendGroupId) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetLoadBalancerBackends.getLoadBalancerBackends") + } + + // 过滤掉服务器已经被删除的backend。原因是运管平台查询不到已删除的服务器记录,导致同步出错。产生肮数据。 + filtedRet := []SElbBackend{} + for i := range ret { + if ret[i].AdminStateUp { + backend := ret[i] + filtedRet = append(filtedRet, backend) + } + } + + return filtedRet, nil +} + +func (self *SRegion) getLoadBalancerAdminStateDownBackends(backendGroupId string) ([]SElbBackend, error) { + ret, err := self.getLoadBalancerBackends(backendGroupId) + if err != nil { + return nil, errors.Wrap(err, "SRegion.getLoadBalancerAdminStateDownBackends.getLoadBalancerBackends") + } + + filtedRet := []SElbBackend{} + for i := range ret { + if !ret[i].AdminStateUp { + backend := ret[i] + filtedRet = append(filtedRet, backend) + } + } + + return filtedRet, nil +} + +func (self *SRegion) GetLoadBalancerHealthCheck(healthCheckId string) (SElbHealthCheck, error) { + ret := SElbHealthCheck{} + err := DoGet(self.ecsClient.ElbHealthCheck.Get, healthCheckId, nil, &ret) + if err != nil { + return ret, err + } + + ret.region = self + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_cert.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_cert.go new file mode 100644 index 0000000000..d1ce4e6f55 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_cert.go @@ -0,0 +1,124 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "crypto/sha1" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SElbCert struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + + Certificate string `json:"certificate"` + CreateTime time.Time `json:"create_time"` + ExpireTime time.Time `json:"expire_time"` + Description string `json:"description"` + Domain string `json:"domain"` + ID string `json:"id"` + AdminStateUp bool `json:"admin_state_up"` + TenantID string `json:"tenant_id"` + Name string `json:"name"` + PrivateKey string `json:"private_key"` + Type string `json:"type"` + UpdateTime time.Time `json:"update_time"` +} + +func (self *SElbCert) GetPublickKey() string { + return self.Certificate +} + +func (self *SElbCert) GetPrivateKey() string { + return self.PrivateKey +} + +func (self *SElbCert) GetId() string { + return self.ID +} + +func (self *SElbCert) GetName() string { + return self.Name +} + +func (self *SElbCert) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbCert) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbCert) Refresh() error { + cert, err := self.region.GetLoadBalancerCertificateById(self.GetId()) + if err != nil { + return err + } + + cert.region = self.region + err = jsonutils.Update(self, cert) + if err != nil { + return err + } + + return nil +} + +func (self *SElbCert) IsEmulated() bool { + return false +} + +func (self *SElbCert) GetProjectId() string { + return "" +} + +func (self *SElbCert) Sync(name, privateKey, publickKey string) error { + params := jsonutils.NewDict() + params.Set("name", jsonutils.NewString(name)) + params.Set("private_key", jsonutils.NewString(privateKey)) + params.Set("certificate", jsonutils.NewString(publickKey)) + return DoUpdate(self.region.ecsClient.ElbCertificates.Update, self.GetId(), params, nil) +} + +func (self *SElbCert) Delete() error { + return DoDelete(self.region.ecsClient.ElbCertificates.Delete, self.GetId(), nil, nil) +} + +func (self *SElbCert) GetCommonName() string { + return self.Domain +} + +func (self *SElbCert) GetSubjectAlternativeNames() string { + return self.Domain +} + +func (self *SElbCert) GetFingerprint() string { + _fp := sha1.Sum([]byte(self.Certificate)) + fp := fmt.Sprintf("sha1:% x", _fp) + return strings.Replace(fp, " ", ":", -1) +} + +func (self *SElbCert) GetExpireTime() time.Time { + return self.ExpireTime +} diff --git a/pkg/multicloud/hcso/loadbalancer_healthcheck.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_healthcheck.go similarity index 100% rename from pkg/multicloud/hcso/loadbalancer_healthcheck.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_healthcheck.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_listener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_listener.go new file mode 100644 index 0000000000..6b26baa79e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_listener.go @@ -0,0 +1,695 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type InsertHeaders struct { + XForwardedELBIP bool `json:"X-Forwarded-ELB-IP"` +} + +type Loadbalancer struct { + ID string `json:"id"` +} + +type SElbListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + huawei.HuaweiTags + lb *SLoadbalancer + acl *SElbACL + backendgroup *SElbBackendGroup + + ProtocolPort int `json:"protocol_port"` + Protocol string `json:"protocol"` + Description string `json:"description"` + AdminStateUp bool `json:"admin_state_up"` + Http2Enable bool `json:"http2_enable"` + Loadbalancers []Loadbalancer `json:"loadbalancers"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + ConnectionLimit int `json:"connection_limit"` + DefaultPoolID string `json:"default_pool_id"` + ID string `json:"id"` + Name string `json:"name"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + InsertHeaders InsertHeaders `json:"insert_headers"` + DefaultTlsContainerRef string `json:"default_tls_container_ref"` +} + +func (self *SElbListener) GetId() string { + return self.ID +} + +func (self *SElbListener) GetName() string { + return self.Name +} + +func (self *SElbListener) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbListener) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbListener) Refresh() error { + ilistener, err := self.lb.GetILoadBalancerListenerById(self.GetId()) + if err != nil { + return err + } + + listener := ilistener.(*SElbListener) + listener.lb = self.lb + err = jsonutils.Update(self, listener) + if err != nil { + return err + } + + return nil +} + +func (self *SElbListener) IsEmulated() bool { + return false +} + +func (self *SElbListener) GetProjectId() string { + return self.ProjectID +} + +func (self *SElbListener) GetListenerType() string { + switch self.Protocol { + case "TCP": + return api.LB_LISTENER_TYPE_TCP + case "UDP": + return api.LB_LISTENER_TYPE_UDP + case "HTTP": + return api.LB_LISTENER_TYPE_HTTP + case "TERMINATED_HTTPS": + return api.LB_LISTENER_TYPE_HTTPS + case "HTTPS": + return api.LB_LISTENER_TYPE_HTTPS + default: + return "" + } +} + +func (self *SElbListener) GetListenerPort() int { + return self.ProtocolPort +} + +func (self *SElbListener) GetBackendGroup() (*SElbBackendGroup, error) { + if self.backendgroup == nil { + lbbgId := self.GetBackendGroupId() + if len(lbbgId) > 0 { + lbbg, err := self.lb.GetILoadBalancerBackendGroupById(lbbgId) + if err != nil { + return nil, err + } + + self.backendgroup = lbbg.(*SElbBackendGroup) + } + } + + return self.backendgroup, nil +} + +func (self *SElbListener) GetScheduler() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetScheduler %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + return lbbg.GetScheduler() +} + +func (self *SElbListener) GetAcl() (*SElbACL, error) { + if self.acl != nil { + return self.acl, nil + } + + acls, err := self.lb.region.GetLoadBalancerAcls(self.GetId()) + if err != nil { + return nil, err + } + + if len(acls) == 0 { + return nil, nil + } else { + self.acl = &acls[0] + return &acls[0], nil + } +} + +func (self *SElbListener) GetAclStatus() string { + acl, err := self.GetAcl() + if err != nil { + log.Debugf("GetAclStatus %s", err) + return "" + } + + if acl != nil && acl.EnableWhitelist { + return api.LB_BOOL_ON + } + + return api.LB_BOOL_OFF +} + +func (self *SElbListener) GetAclType() string { + return api.LB_ACL_TYPE_WHITE +} + +func (self *SElbListener) GetAclId() string { + acl, err := self.GetAcl() + if err != nil { + log.Debugf("GetAclStatus %s", err) + return "" + } + + if acl == nil { + return "" + } + + return acl.GetId() +} + +func (self *SElbListener) GetEgressMbps() int { + return 0 +} + +func (self *SElbListener) GetHealthCheck() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheck %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheck %s", err.Error()) + } + + if health != nil { + return api.LB_BOOL_ON + } else { + return api.LB_BOOL_OFF + } +} + +func (self *SElbListener) GetHealthCheckType() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) + } + + if health != nil { + return health.HealthCheckType + } + + return "" +} + +func (self *SElbListener) GetHealthCheckTimeout() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) + } + + if health != nil { + return health.HealthCheckTimeout + } + + return 0 +} + +func (self *SElbListener) GetHealthCheckInterval() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) + } + + if health != nil { + return health.HealthCheckInterval + } + + return 0 +} + +func (self *SElbListener) GetHealthCheckRise() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) + } + + if health != nil { + return health.HealthCheckRise + } else { + return 0 + } +} + +func (self *SElbListener) GetHealthCheckFail() int { + return 0 +} + +func (self *SElbListener) GetHealthCheckReq() string { + return "" +} + +func (self *SElbListener) GetHealthCheckExp() string { + return "" +} + +func (self *SElbListener) GetBackendGroupId() string { + return self.DefaultPoolID +} + +func (self *SElbListener) GetBackendServerPort() int { + return 0 +} + +func (self *SElbListener) GetHealthCheckDomain() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) + } + + if health != nil { + return health.HealthCheckDomain + } + + return "" +} + +func (self *SElbListener) GetHealthCheckURI() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) + } + + if health != nil { + return health.HealthCheckURI + } + + return "" +} + +func (self *SElbListener) GetHealthCheckCode() string { + return "" +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html +func (self *SElbListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + l7policy, err := self.lb.region.CreateLoadBalancerPolicy(self.GetId(), rule) + if err != nil { + return nil, err + } + + l7policy.region = self.lb.region + l7policy.lb = self.lb + l7policy.listener = self + return &l7policy, nil +} + +func (self *SElbListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + ret := &SElbListenerPolicy{} + err := DoGet(self.lb.region.ecsClient.ElbL7policies.Get, ruleId, nil, ret) + if err != nil { + return nil, err + } + + ret.region = self.lb.region + ret.lb = self.lb + ret.listener = self + return ret, nil +} + +func (self *SElbListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + ret, err := self.lb.region.GetLoadBalancerPolicies(self.GetId()) + if err != nil { + return nil, err + } + + iret := []cloudprovider.ICloudLoadbalancerListenerRule{} + for i := range ret { + rule := ret[i] + rule.listener = self + rule.lb = self.lb + iret = append(iret, &rule) + } + + return iret, nil +} + +func (self *SElbListener) GetStickySession() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySession %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySession %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySession + } + + return "" +} + +func (self *SElbListener) GetStickySessionType() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySessionType %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySessionType %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySessionType + } + + return "" +} + +func (self *SElbListener) GetStickySessionCookie() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySessionCookie + } + + return "" +} + +func (self *SElbListener) GetStickySessionCookieTimeout() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySessionCookieTimeout + } + + return 0 +} + +func (self *SElbListener) XForwardedForEnabled() bool { + return self.InsertHeaders.XForwardedELBIP +} + +func (self *SElbListener) GzipEnabled() bool { + return false +} + +func (self *SElbListener) GetCertificateId() string { + return self.DefaultTlsContainerRef +} + +func (self *SElbListener) GetTLSCipherPolicy() string { + return "" +} + +func (self *SElbListener) HTTP2Enabled() bool { + return self.Http2Enable +} + +func (self *SElbListener) Start() error { + return nil +} + +func (self *SElbListener) Stop() error { + return cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561544.html +/* +default_pool_id有如下限制: +不能更新为其他监听器的default_pool。 +不能更新为其他监听器的关联的转发策略所使用的pool。 +default_pool_id对应的后端云服务器组的protocol和监听器的protocol有如下关系: +监听器的protocol为TCP时,后端云服务器组的protocol必须为TCP。 +监听器的protocol为UDP时,后端云服务器组的protocol必须为UDP。 +监听器的protocol为HTTP或TERMINATED_HTTPS时,后端云服务器组的protocol必须为HTTP。 +*/ +func (self *SElbListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { + return self.lb.region.UpdateLoadBalancerListener(self.GetId(), listener) +} + +func (self *SElbListener) Delete(ctx context.Context) error { + err := DoDelete(self.lb.region.ecsClient.ElbListeners.Delete, self.GetId(), nil, nil) + if err != nil { + return err + } + + return nil +} + +func (self *SRegion) UpdateLoadBalancerListener(listenerId string, listener *cloudprovider.SLoadbalancerListener) error { + params := jsonutils.NewDict() + listenerObj := jsonutils.NewDict() + listenerObj.Set("name", jsonutils.NewString(listener.Name)) + listenerObj.Set("description", jsonutils.NewString(listener.Description)) + listenerObj.Set("http2_enable", jsonutils.NewBool(listener.EnableHTTP2)) + if len(listener.BackendGroupID) > 0 { + listenerObj.Set("default_pool_id", jsonutils.NewString(listener.BackendGroupID)) + } else { + listenerObj.Set("default_pool_id", jsonutils.JSONNull) + } + + if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { + listenerObj.Set("default_tls_container_ref", jsonutils.NewString(listener.CertificateID)) + } + + if listener.XForwardedFor { + insertObj := jsonutils.NewDict() + insertObj.Set("X-Forwarded-ELB-IP", jsonutils.NewBool(listener.XForwardedFor)) + listenerObj.Set("insert_headers", insertObj) + } + + params.Set("listener", listenerObj) + err := DoUpdate(self.ecsClient.ElbListeners.Update, listenerId, params, nil) + if err != nil { + return err + } + return nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295315.html +func (self *SRegion) GetLoadBalancerPolicies(listenerId string) ([]SElbListenerPolicy, error) { + params := map[string]string{} + if len(listenerId) > 0 { + params["listener_id"] = listenerId + } + + ret := []SElbListenerPolicy{} + err := doListAll(self.ecsClient.ElbL7policies.List, params, &ret) + if err != nil { + return nil, err + } + + for i := range ret { + ret[i].region = self + } + + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0116649234.html +func (self *SRegion) GetLoadBalancerPolicyRules(policyId string) ([]SElbListenerPolicyRule, error) { + m := self.ecsClient.ElbPolicies + err := m.SetL7policyId(policyId) + if err != nil { + return nil, err + } + + ret := []SElbListenerPolicyRule{} + err = doListAll(m.List, nil, &ret) + if err != nil { + return nil, err + } + + for i := range ret { + ret[i].region = self + } + + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html +func (self *SRegion) CreateLoadBalancerPolicy(listenerID string, rule *cloudprovider.SLoadbalancerListenerRule) ( + SElbListenerPolicy, error) { + l7policy := SElbListenerPolicy{} + params := jsonutils.NewDict() + policyObj := jsonutils.NewDict() + policyObj.Set("name", jsonutils.NewString(rule.Name)) + policyObj.Set("listener_id", jsonutils.NewString(listenerID)) + // todo: REDIRECT_TO_LISTENER? + policyObj.Set("action", jsonutils.NewString("REDIRECT_TO_POOL")) + policyObj.Set("redirect_pool_id", jsonutils.NewString(rule.BackendGroupID)) + params.Set("l7policy", policyObj) + + err := DoCreate(self.ecsClient.ElbL7policies.Create, params, &l7policy) + if err != nil { + return l7policy, err + } + + m := self.ecsClient.ElbPolicies + m.SetL7policyId(l7policy.GetId()) + if len(rule.Domain) > 0 { + p := jsonutils.NewDict() + p.Set("type", jsonutils.NewString("HOST_NAME")) + p.Set("value", jsonutils.NewString(rule.Domain)) + // todo: support more compare_type + p.Set("compare_type", jsonutils.NewString("EQUAL_TO")) + rule := jsonutils.NewDict() + rule.Set("rule", p) + err := DoCreate(m.Create, rule, nil) + if err != nil { + return l7policy, err + } + } + + if len(rule.Path) > 0 { + p := jsonutils.NewDict() + p.Set("type", jsonutils.NewString("PATH")) + p.Set("value", jsonutils.NewString(rule.Path)) + p.Set("compare_type", jsonutils.NewString("EQUAL_TO")) + rule := jsonutils.NewDict() + rule.Set("rule", p) + err := DoCreate(m.Create, rule, nil) + if err != nil { + return l7policy, err + } + } + + return l7policy, nil +} + +func (self *SElbListener) GetClientIdleTimeout() int { + return 0 +} + +func (self *SElbListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_listener_rule.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_listener_rule.go new file mode 100644 index 0000000000..9f4f1a0a0a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/loadbalancer_listener_rule.go @@ -0,0 +1,173 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SElbListenerPolicy struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + huawei.HuaweiTags + region *SRegion + lb *SLoadbalancer + listener *SElbListener + + RedirectPoolID string `json:"redirect_pool_id"` + RedirectListenerID *string `json:"redirect_listener_id"` + Description string `json:"description"` + AdminStateUp bool `json:"admin_state_up"` + Rules []Rule `json:"rules"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + ListenerID string `json:"listener_id"` + RedirectURL *string `json:"redirect_url"` + ProvisioningStatus string `json:"provisioning_status"` + Action string `json:"action"` + Position int64 `json:"position"` + ID string `json:"id"` + Name string `json:"name"` +} + +type Rule struct { + ID string `json:"id"` +} + +type SElbListenerPolicyRule struct { + region *SRegion + policy *SElbListenerPolicy + + CompareType string `json:"compare_type"` + ProvisioningStatus string `json:"provisioning_status"` + AdminStateUp bool `json:"admin_state_up"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + Invert bool `json:"invert"` + Value string `json:"value"` + Key interface{} `json:"key"` + Type string `json:"type"` + ID string `json:"id"` +} + +func (self *SElbListenerPolicy) GetId() string { + return self.ID +} + +func (self *SElbListenerPolicy) GetName() string { + return self.Name +} + +func (self *SElbListenerPolicy) GetGlobalId() string { + return self.GetId() +} + +// 负载均衡没有启用禁用操作 +func (self *SElbListenerPolicy) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbListenerPolicy) Refresh() error { + ret := &SElbListenerPolicy{} + err := DoGet(self.lb.region.ecsClient.ElbL7policies.Get, self.GetId(), nil, ret) + if err != nil { + return err + } + + err = jsonutils.Update(self, ret) + if err != nil { + return err + } + + return nil +} + +func (self *SElbListenerPolicy) IsDefault() bool { + return false +} + +func (self *SElbListenerPolicy) IsEmulated() bool { + return false +} + +func (self *SElbListenerPolicy) GetProjectId() string { + return "" +} + +func (self *SElbListenerPolicy) GetRules() ([]SElbListenerPolicyRule, error) { + ret, err := self.region.GetLoadBalancerPolicyRules(self.GetId()) + if err != nil { + return nil, err + } + + for i := range ret { + ret[i].policy = self + } + + return ret, nil +} + +func (self *SElbListenerPolicy) GetDomain() string { + rules, err := self.GetRules() + if err != nil { + log.Errorf("loadbalancer rule GetDomain %s", err) + } + + for i := range rules { + if rules[i].Type == "HOST_NAME" { + return rules[i].Value + } + } + + return "" +} + +func (self *SElbListenerPolicy) GetCondition() string { + return "" +} + +func (self *SElbListenerPolicy) GetPath() string { + rules, err := self.GetRules() + if err != nil { + log.Errorf("loadbalancer rule GetPath %s", err) + } + + for i := range rules { + if rules[i].Type == "PATH" { + return rules[i].Value + } + } + + return "" +} + +func (self *SElbListenerPolicy) GetBackendGroupId() string { + return self.RedirectPoolID +} + +func (self *SElbListenerPolicy) Delete(ctx context.Context) error { + return self.region.DeleteLoadBalancerPolicy(self.GetId()) +} + +func (self *SRegion) DeleteLoadBalancerPolicy(policyId string) error { + return DoDelete(self.ecsClient.ElbL7policies.Delete, policyId, nil, nil) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts.go new file mode 100644 index 0000000000..ec0cbedfc4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts.go @@ -0,0 +1,394 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SModelartsPool struct { + region *SRegion + multicloud.SResourceBase + + Metadata SModelartsPoolMetadata `json:"metadata"` + Spec SModelartsPoolSpec `json:"spec"` + Status SModelartsPoolStatus `json:"status"` + InstanceType string + WorkType string +} + +type SModelartsPoolMetadata struct { + Name string `json:"name"` + CreationTimestamp string `json:"creationTimestamp"` + Labels SModelartsPoolMeatadataLabel + Annotations SModelartsPoolMetadataAnnotations `json:"annotations"` +} + +type SModelartsPoolMeatadataLabel struct { + WorkspaceId string `json:"os.modelarts/workspace.id"` + Name string `json:"os.modelarts/name"` + ResourceId string `json:"os.modelarts/resource.id"` +} + +type SModelartsPoolMetadataAnnotations struct { + Describe string `json:"os.modelarts/description"` + BillingType string `json:"os.modelarts/billing.mode"` + BillingCycle string `json:"os.modelarts/period.num"` + BillingPeriodType string `json:"os.modelarts/period.type"` + BillingMod string `json:"os.modelarts/charging.mode"` + BillingRenew string `json:"os.modelarts/auto.renew"` + OrderId string `json:"os.modelarts/order.id"` +} + +type SModelartsPoolSpec struct { + Type string `json:"type"` + Scope []string `json:"scope"` + Resource []SModelartsPoolResource `json:"resources"` +} + +type SModelartsPoolResource struct { + Flavor string `json:"flavor"` + Count int `json:"count"` + cloudprovider.Azs +} + +type SNodeStatus struct { + Creating []SNodeFlavor `json:"creating"` + Available []SNodeFlavor `json:"available"` + Abnormal []SNodeFlavor `json:"abnormal"` + Deleting []SNodeFlavor `json:"deleting"` +} + +type SNodeFlavor struct { + Flavor string `json:"flavor"` + Count int `json:"count"` +} + +type SModelartsPoolStatus struct { + Phase string `json:"phase"` + Message string `json:"message"` + Resource SNodeStatus `json:"resources"` +} + +type SModelartsPoolNetwork struct { + Metadata SModelartsPoolNetworkMetadata `json:"metadata"` +} + +type SModelartsPoolNetworkMetadata struct { + Name string `json:"name"` + CreationTimestamp string `json:"creationTimestamp"` +} + +func (self *SRegion) GetIModelartsPools() ([]cloudprovider.ICloudModelartsPool, error) { + pools := make([]SModelartsPool, 0) + resObj, err := self.client.modelartsPoolList(nil) + if err != nil { + return nil, errors.Wrap(err, "region.GetPools") + } + err = resObj.Unmarshal(&pools, "items") + if err != nil { + return nil, errors.Wrap(err, "resObj unmarshal") + } + res := make([]cloudprovider.ICloudModelartsPool, len(pools)) + for i := 0; i < len(pools); i++ { + pools[i].region = self + res[i] = &pools[i] + } + + return res, nil +} + +func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreateOption) (cloudprovider.ICloudModelartsPool, error) { + netObj, err := self.client.modelartsPoolNetworkList(nil) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.GetPools") + } + netRes := make([]SModelartsPoolNetwork, 0) + netObj.Unmarshal(&netRes, "items") + netId := "" + if len(netRes) != 0 { + netId = netRes[0].Metadata.Name + } else { + createNetObj, err := self.client.CreatePoolNetworks() + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.CreatePoolNetworks") + } + netId, _ = createNetObj.GetString("metadata", "name") + } + + scopeArr := strings.Split(args.WorkType, ",") + params := map[string]interface{}{ + "apiVersion": "v2", + "kind": "Pool", + "metadata": map[string]interface{}{ + "labels": map[string]interface{}{ + "os.modelarts/name": args.Name, + "os.modelarts/workspace.id": "0", + }, + }, + "spec": map[string]interface{}{ + "type": "Dedicate", + "scope": scopeArr, + "network": map[string]interface{}{ + "name": netId, + }, + + "resources": []map[string]interface{}{ + { + "flavor": args.InstanceType, + "count": args.NodeCount, + }, + }, + }, + } + obj, err := self.client.modelartsPoolCreate(params) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.CreatePools") + } + pool := &SModelartsPool{} + obj.Unmarshal(&pool) + res := []cloudprovider.ICloudModelartsPool{} + for i := 0; i < 1; i++ { + pool.region = self + res = append(res, pool) + } + + return res[0], nil +} + +func (self *SRegion) DeletePool(poolName string) (jsonutils.JSONObject, error) { + return self.client.modelartsPoolDelete(poolName, nil) +} + +func (self *SRegion) GetIModelartsPoolById(poolId string) (cloudprovider.ICloudModelartsPool, error) { + obj, err := self.client.modelartsPoolById(poolId) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "") + } + return nil, errors.Wrap(err, "region.modelartsPoolByName") + } + pool := &SModelartsPool{} + obj.Unmarshal(&pool) + res := []cloudprovider.ICloudModelartsPool{} + for i := 0; i < 1; i++ { + pool.region = self + res = append(res, pool) + } + return res[0], nil +} + +func (self *SRegion) MonitorPool(poolId string) (*SModelartsMetrics, error) { + resObj, err := self.client.modelartsPoolMonitor(poolId, nil) + if err != nil { + return nil, errors.Wrapf(err, "send request error") + } + metrics := SModelartsMetrics{} + err = resObj.Unmarshal(&metrics) + if err != nil { + return nil, errors.Wrapf(err, "unmarsh error") + } + return &metrics, nil +} + +type SModelartsMetrics struct { + Metrics []SModelartsMetric `json:"metrics"` +} + +type SModelartsMetric struct { + Metric SModelartsMetricInfo `json:"metric"` + Datapoints []SModelartsDataPoints `json:"dataPoints"` +} + +type SModelartsMetricInfo struct { + Dimensions []SModelartsDimensions `json:"dimensions"` + MetricName string + Namespace string +} + +type SModelartsDimensions struct { + Name string + Value string +} + +type SModelartsDataPoints struct { + Timestamp int64 + Unit string + Statistics []ModelartsStatistics +} + +type ModelartsStatistics struct { + Statistic string + Value float64 +} + +func (self *SHuaweiClient) GetPoolNetworks(poolName string) (jsonutils.JSONObject, error) { + return self.modelartsPoolNetworkList(nil) +} + +func (self *SHuaweiClient) CreatePoolNetworks() (jsonutils.JSONObject, error) { + params := map[string]interface{}{ + "apiVersion": "v1", + "kind": "Network", + "metadata": map[string]interface{}{ + "labels": map[string]interface{}{ + "os.modelarts/name": "test", + "os.modelarts/workspace.id": "0", + }, + }, + "spec": map[string]interface{}{ + "cidr": "192.168.20.0/24", + }, + } + return self.modelartsPoolNetworkCreate(params) +} + +func (self *SModelartsPool) GetCreatedAt() time.Time { + ret, _ := time.Parse("2006-01-02T15:04:05CST", self.Metadata.CreationTimestamp) + if !ret.IsZero() { + ret = ret.Add(time.Hour * 8) + } + return ret +} + +func (self *SModelartsPool) GetGlobalId() string { + return self.Metadata.Name +} + +func (self *SModelartsPool) GetId() string { + return self.Metadata.Name +} + +func (self *SModelartsPool) GetName() string { + return self.Metadata.Labels.Name +} + +func (self *SModelartsPool) GetStatus() string { + res := strings.ToLower(self.Status.Phase) + switch { + case res == compute.MODELARTS_POOL_STATUS_RUNNING && len(self.Status.Resource.Creating) != 0: + res = compute.MODELARTS_POOL_STATUS_CREATING + } + return res +} + +func (self *SModelartsPool) GetSysTags() map[string]string { + return nil +} + +func (self *SModelartsPool) GetTags() (map[string]string, error) { + return nil, nil +} + +func (self *SModelartsPool) IsEmulated() bool { + return false +} + +func (self *SModelartsPool) GetBillingType() string { + if self.Metadata.Annotations.BillingType == "1" { + return billing_api.BILLING_TYPE_PREPAID + } else { + return billing_api.BILLING_TYPE_POSTPAID + } +} + +// 获取资源归属项目Id +func (self *SModelartsPool) GetProjectId() string { + return self.Metadata.Name +} + +func (self *SModelartsPool) GetExpiredAt() time.Time { + ret, _ := time.Parse("2006-01-02T15:04:05CST", self.Metadata.CreationTimestamp) + if !ret.IsZero() { + ret = ret.Add(time.Hour * 8) + } + return ret +} + +func (self *SModelartsPool) IsAutoRenew() bool { + return false +} + +func (self *SModelartsPool) Renew(bc billing.SBillingCycle) error { + return nil +} + +func (self *SModelartsPool) SetAutoRenew(bc billing.SBillingCycle) error { + return nil +} + +func (self *SModelartsPool) Refresh() error { + pool, err := self.region.client.modelartsPoolById(self.GetId()) + if err != nil { + return errors.Wrapf(err, "GetModelartsPool(%s)", self.GetId()) + } + return jsonutils.Update(self, pool) +} + +func (self *SModelartsPool) SetTags(tags map[string]string, replace bool) error { + return nil +} + +func (self *SModelartsPool) Delete() error { + _, err := self.region.DeletePool(self.GetId()) + if err != nil { + return err + } + return nil +} + +func (self *SModelartsPool) GetInstanceType() string { + return self.Spec.Resource[0].Flavor + +} + +func (self *SModelartsPool) GetWorkType() string { + return strings.Join(self.Spec.Scope, ",") +} + +func (self *SModelartsPool) GetNodeCount() int { + if len(self.Spec.Resource) < 1 { + return 0 + } + return self.Spec.Resource[0].Count +} + +func (self *SModelartsPool) ChangeConfig(opts *cloudprovider.ModelartsPoolChangeConfigOptions) error { + //{"spec":{"resources":[{"flavor":"modelarts.kat1.8xlarge","count":2}]}} + res := []map[string]interface{}{} + for _, re := range self.Spec.Resource { + res = append(res, map[string]interface{}{ + "flavor": re.Flavor, + "count": opts.NodeCount, + }) + } + params := map[string]interface{}{ + "spec": map[string]interface{}{ + "resources": res, + }, + } + _, err := self.region.client.modelartsPoolUpdate(self.Metadata.Name, params) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts_sku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts_sku.go new file mode 100644 index 0000000000..5cda651842 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/modelarts_sku.go @@ -0,0 +1,131 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "strconv" + "time" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SModelartsPoolSku struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + + Kind string `json:"kind"` + Spec SModelartsResourceflavorsSpec `json:"spec"` + Status SModelartsResourceflavorsStatus `json:"status"` +} + +type SModelartsResourceflavorsSpec struct { + BillingCode string `json:"billingCode"` + BillingModes []int `json:"billingMods"` + Cpu int `json:"cpu"` + CpuArch string `json:"cpuArch"` + Gpu SModelartsResourceflavorsGpuSpec `json:"gpu"` + Npu SModelartsResourceflavorsGpuSpec `json:"npu"` + Memory string `json:"memory"` + Type string `json:"type"` +} + +type SModelartsResourceflavorsGpuSpec struct { + Size int `json:"size"` + Type string `json:"type"` +} + +type SModelartsResourceflavorsStatus struct { + Phase map[string]interface{} `json:"phase"` +} + +func (self *SRegion) GetIModelartsPoolSku() ([]cloudprovider.ICloudModelartsPoolSku, error) { + params := make(map[string]interface{}) + resourceflavors := make([]SModelartsPoolSku, 0) + obj, err := self.client.modelartsResourceflavors(params) + if err != nil { + return nil, errors.Wrap(err, "region.modelartsResourceflavors") + } + obj.Unmarshal(&resourceflavors, "items") + res := make([]cloudprovider.ICloudModelartsPoolSku, len(resourceflavors)) + for i := 0; i < len(resourceflavors); i++ { + res[i] = &resourceflavors[i] + } + return res, nil +} + +func (self *SModelartsPoolSku) GetCreatedAt() time.Time { + createdAt, _ := time.Parse("2006-01-02T15:04:05CST", time.Now().Format("2006-01-02T15:04:05CST")) + return createdAt +} + +func (self *SModelartsPoolSku) GetGlobalId() string { + return self.Spec.BillingCode +} + +func (self *SModelartsPoolSku) GetId() string { + return self.Spec.BillingCode +} + +func (self *SModelartsPoolSku) GetName() string { + return self.Spec.BillingCode +} + +func (self *SModelartsPoolSku) GetCpuArch() string { + return self.Spec.CpuArch +} + +func (self *SModelartsPoolSku) GetCpuCoreCount() int { + return self.Spec.Cpu +} + +func (self *SModelartsPoolSku) GetMemorySizeMB() int { + size, _ := strconv.Atoi(self.Spec.Memory[:len(self.Spec.Memory)-2]) + return size * 1024 +} + +func (self *SModelartsPoolSku) GetStatus() string { + for _, v := range self.Status.Phase { + if v == "normal" { + return compute.MODELARTS_POOL_SKU_AVAILABLE + } + } + return compute.MODELARTS_POOL_SKU_SOLDOUT +} + +func (self *SModelartsPoolSku) GetGpuSize() int { + return self.Spec.Gpu.Size +} + +func (self *SModelartsPoolSku) GetGpuType() string { + return self.Spec.Gpu.Type +} + +func (self *SModelartsPoolSku) GetNpuSize() int { + return self.Spec.Npu.Size +} + +func (self *SModelartsPoolSku) GetNpuType() string { + return self.Spec.Npu.Type +} + +func (self *SModelartsPoolSku) GetPoolType() string { + return self.Spec.Type +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/monitor.go new file mode 100644 index 0000000000..a9d2212d79 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/monitor.go @@ -0,0 +1,107 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" +) + +func (r *SRegion) GetMetrics() ([]modules.SMetricMeta, error) { + return r.ecsClient.CloudEye.ListMetrics() +} + +func (r *SRegion) GetMetricsData(metrics []modules.SMetricMeta, since time.Time, until time.Time) ([]modules.SMetricData, error) { + return r.ecsClient.CloudEye.GetMetricsData(metrics, since, until) +} + +func (self *SHuaweiClient) getModelartsPoolMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + resp, err := self.modelartsPoolMonitor(opts.ResourceId, nil) + if err != nil { + return nil, err + } + metricData := []SModelartsMetric{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + isMB := false + if metricData[i].Datapoints[0].Unit == "Megabytes" { + isMB = true + metricData[i].Datapoints[0].Unit = "Bytes" + } + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Datapoints[0].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].Metric.MetricName { + case "cpuUsage": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_CPU_USAGE + case "memUsedRate": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_MEM_USAGE + case "gpuUtil": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_GPU_UTIL + case "gpuMemUsage": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_GPU_MEM_USAGE + case "npuUtil": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_NPU_UTIL + case "npuMemUsage": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_NPU_MEM_USAGE + case "diskAvailableCapacity": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_AVAILABLE_CAPACITY + case "diskCapacity": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_CAPACITY + case "diskUsedRate": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_USAGE + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].Metric.MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + if isMB { + value.Statistics[0].Value *= 1024 + } + if value.Statistics[0].Value == -1 { + value.Statistics[0].Value = 0 + } + metricValue := cloudprovider.MetricValue{ + Value: value.Statistics[0].Value, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHuaweiClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_MODELARTS_POOL: + return self.getModelartsPoolMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/nat_skus.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/nat_skus.go new file mode 100644 index 0000000000..378ae9dec7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/nat_skus.go @@ -0,0 +1,97 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + HUAWEI_NAT_SKU_SMALL = "Small" + HUAWEI_NAT_SKU_MIDDLE = "Middle" + HUAWEI_NAT_SKU_LARGE = "Large" + HUAWEI_NAT_SKU_XLARGE = "XLarge" +) + +type SNatSku struct { + spec string +} + +func (self *SNatSku) GetName() string { + return self.spec +} + +func (self *SNatSku) GetPps() int { + return 1000000 +} + +func (self *SNatSku) GetConns() int { + switch self.spec { + case HUAWEI_NAT_SKU_SMALL: + return 10000 + case HUAWEI_NAT_SKU_MIDDLE: + return 50000 + case HUAWEI_NAT_SKU_LARGE: + return 200000 + case HUAWEI_NAT_SKU_XLARGE: + return 1000000 + } + return 0 +} + +func (self *SNatSku) GetThroughput() int { + return 10 +} + +func (self *SNatSku) GetDesc() string { + switch self.spec { + case HUAWEI_NAT_SKU_SMALL: + return "小型" + case HUAWEI_NAT_SKU_MIDDLE: + return "中型" + case HUAWEI_NAT_SKU_LARGE: + return "大型" + case HUAWEI_NAT_SKU_XLARGE: + return "超大型" + } + return "" +} + +func (self *SNatSku) GetPostpaidStatus() string { + return api.NAT_SKU_AVAILABLE +} + +func (self *SNatSku) GetPrepaidStatus() string { + return api.NAT_SKU_SOLDOUT +} + +func (self *SNatSku) GetGlobalId() string { + return self.spec +} + +func (self *SRegion) GetICloudNatSkus() ([]cloudprovider.ICloudNatSku, error) { + ret := []cloudprovider.ICloudNatSku{} + for _, spec := range []string{ + HUAWEI_NAT_SKU_SMALL, + HUAWEI_NAT_SKU_MIDDLE, + HUAWEI_NAT_SKU_LARGE, + HUAWEI_NAT_SKU_XLARGE, + } { + sku := &SNatSku{spec: spec} + ret = append(ret, sku) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natdtable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natdtable.go new file mode 100644 index 0000000000..44f92182fc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natdtable.go @@ -0,0 +1,132 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SNatDEntry struct { + multicloud.SResourceBase + huawei.HuaweiTags + gateway *SNatGateway + + ID string `json:"id"` + NatGatewayID string `json:"nat_gateway_id"` + Protocol string `json:"protocol"` + Status string `json:"status"` + ExternalIP string `json:"floating_ip_address"` + ExternalPort int `json:"external_service_port"` + InternalIP string `json:"private_ip"` + InternalPort int `json:"internal_service_port"` + PortID string `json:"port_id"` + AdminStateUp bool `json:"admin_state_up"` +} + +func (nat *SNatDEntry) GetId() string { + return nat.ID +} + +func (nat *SNatDEntry) GetName() string { + // No name so return id + return nat.GetId() +} + +func (nat *SNatDEntry) GetGlobalId() string { + return nat.GetId() +} + +func (nat *SNatDEntry) GetStatus() string { + return NatResouceStatusTransfer(nat.Status) +} + +func (nat *SNatDEntry) GetIpProtocol() string { + return nat.Protocol +} + +func (nat *SNatDEntry) GetExternalIp() string { + return nat.ExternalIP +} + +func (nat *SNatDEntry) GetExternalPort() int { + return nat.ExternalPort +} + +func (nat *SNatDEntry) GetInternalIp() string { + return nat.InternalIP +} + +func (nat *SNatDEntry) GetInternalPort() int { + return nat.InternalPort +} + +func (nat *SNatDEntry) Delete() error { + return nat.gateway.region.DeleteNatDEntry(nat.GetId()) +} + +// getNatSTable return all snat rules of gateway +func (gateway *SNatGateway) getNatDTable() ([]SNatDEntry, error) { + ret, err := gateway.region.GetNatDTable(gateway.GetId()) + if err != nil { + return nil, err + } + for i := range ret { + ret[i].gateway = gateway + } + return ret, nil +} + +func (region *SRegion) GetNatDTable(natGatewayID string) ([]SNatDEntry, error) { + queuies := map[string]string{ + "nat_gateway_id": natGatewayID, + } + dNatSTableEntries := make([]SNatDEntry, 0, 2) + // can't make true that restapi support marker para in Huawei Cloud + err := doListAllWithMarker(region.ecsClient.DNatRules.List, queuies, &dNatSTableEntries) + if err != nil { + return nil, errors.Wrapf(err, `get dnat rule of gateway %q`, natGatewayID) + } + for i := range dNatSTableEntries { + nat := &dNatSTableEntries[i] + if len(nat.InternalIP) == 0 { + port, err := region.GetPort(nat.PortID) + if err != nil { + return nil, errors.Wrapf(err, `get port info for transfer to ip of port_id %q error`, nat.PortID) + } + nat.InternalIP = port.FixedIps[0].IpAddress + } + } + return dNatSTableEntries, nil +} + +func (region *SRegion) DeleteNatDEntry(entryID string) error { + _, err := region.ecsClient.DNatRules.Delete(entryID, nil) + if err != nil { + return errors.Wrapf(err, `delete dnat rule %q failed`, entryID) + } + return nil +} + +func (nat *SNatDEntry) Refresh() error { + new, err := nat.gateway.region.GetNatDEntryByID(nat.ID) + if err != nil { + return err + } + return jsonutils.Update(nat, new) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natgateway.go new file mode 100644 index 0000000000..d46b04e35f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natgateway.go @@ -0,0 +1,354 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SNatGateway struct { + multicloud.SNatGatewayBase + huawei.HuaweiTags + region *SRegion + + ID string + Name string + Description string + Spec string + Status string + InternalNetworkId string + CreatedTime string `json:"created_at"` +} + +func (gateway *SNatGateway) GetId() string { + return gateway.ID +} + +func (gateway *SNatGateway) GetName() string { + return gateway.Name +} + +func (gateway *SNatGateway) GetGlobalId() string { + return gateway.GetId() +} + +func (gateway *SNatGateway) GetStatus() string { + return NatResouceStatusTransfer(gateway.Status) +} + +func (self *SNatGateway) Delete() error { + return self.region.DeleteNatGateway(self.ID) +} + +func (self *SNatGateway) Refresh() error { + nat, err := self.region.GetNatGateway(self.ID) + if err != nil { + return errors.Wrapf(err, "GetNatGateway(%s)", self.ID) + } + return jsonutils.Update(self, nat) +} + +func (self *SNatGateway) GetINetworkId() string { + return self.InternalNetworkId +} + +func (gateway *SNatGateway) GetNatSpec() string { + switch gateway.Spec { + case "1": + return api.NAT_SPEC_SMALL + case "2": + return api.NAT_SPEC_MIDDLE + case "3": + return api.NAT_SPEC_LARGE + case "4": + return api.NAT_SPEC_XLARGE + } + return gateway.Spec +} + +func (gateway *SNatGateway) GetDescription() string { + return gateway.Description +} + +func (gateway *SNatGateway) GetBillingType() string { + // Up to 2019.07.17, only support post pay + return billing_api.BILLING_TYPE_POSTPAID +} + +func (gateway *SNatGateway) GetCreatedAt() time.Time { + t, _ := time.Parse("2006-01-02 15:04:05.000000", gateway.CreatedTime) + return t +} + +func (gateway *SNatGateway) GetExpiredAt() time.Time { + // no support for expired time + return time.Time{} +} + +func (gateway *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { + IEips, err := gateway.region.GetIEips() + if err != nil { + return nil, errors.Wrapf(err, `get all Eips of region %q error`, gateway.region.GetId()) + } + dNatTables, err := gateway.GetINatDTable() + if err != nil { + return nil, errors.Wrapf(err, `get all DNatTable of gateway %q error`, gateway.GetId()) + } + sNatTables, err := gateway.GetINatSTable() + if err != nil { + return nil, errors.Wrapf(err, `get all SNatTable of gateway %q error`, gateway.GetId()) + } + + // Get natIPSet of nat rules + natIPSet := make(map[string]struct{}) + for _, snat := range sNatTables { + natIPSet[snat.GetIP()] = struct{}{} + } + for _, dnat := range dNatTables { + natIPSet[dnat.GetExternalIp()] = struct{}{} + } + + // Add Eip whose GetIpAddr() in natIPSet to ret + ret := make([]cloudprovider.ICloudEIP, 0, 2) + for i := range IEips { + if _, ok := natIPSet[IEips[i].GetIpAddr()]; ok { + ret = append(ret, IEips[i]) + } + } + return ret, nil +} + +func (gateway *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { + dNatTable, err := gateway.getNatDTable() + if err != nil { + return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) + } + ret := make([]cloudprovider.ICloudNatDEntry, len(dNatTable)) + for i := range dNatTable { + ret[i] = &dNatTable[i] + } + return ret, nil +} + +func (gateway *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { + sNatTable, err := gateway.getNatSTable() + if err != nil { + return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) + } + ret := make([]cloudprovider.ICloudNatSEntry, len(sNatTable)) + for i := range sNatTable { + ret[i] = &sNatTable[i] + } + return ret, nil +} + +func (gateway *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { + dnat, err := gateway.region.CreateNatDEntry(rule, gateway.GetId()) + if err != nil { + return nil, err + } + dnat.gateway = gateway + return &dnat, nil +} + +func (gateway *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { + snat, err := gateway.region.CreateNatSEntry(rule, gateway.GetId()) + if err != nil { + return nil, err + } + snat.gateway = gateway + return &snat, nil +} + +func (gateway *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { + dnat, err := gateway.region.GetNatDEntryByID(id) + if err != nil { + return nil, err + } + dnat.gateway = gateway + return &dnat, nil +} + +func (gateway *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { + snat, err := gateway.region.GetNatSEntryByID(id) + if err != nil { + return nil, err + } + snat.gateway = gateway + return &snat, nil +} + +func (region *SRegion) GetNatGateways(vpcID, natGatewayID string) ([]SNatGateway, error) { + queues := make(map[string]string) + if len(natGatewayID) != 0 { + queues["id"] = natGatewayID + } + if len(vpcID) != 0 { + queues["router_id"] = vpcID + } + natGateways := make([]SNatGateway, 0, 2) + err := doListAllWithMarker(region.ecsClient.NatGateways.List, queues, &natGateways) + if err != nil { + return nil, errors.Wrapf(err, "get nat gateways error by natgatewayid") + } + for i := range natGateways { + natGateways[i].region = region + } + return natGateways, nil +} + +func (region *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayID string) (SNatDEntry, error) { + params := make(map[string]interface{}) + params["nat_gateway_id"] = gatewayID + params["private_ip"] = rule.InternalIP + params["internal_service_port"] = rule.InternalPort + params["floating_ip_id"] = rule.ExternalIPID + params["external_service_port"] = rule.ExternalPort + params["protocol"] = rule.Protocol + + packParams := map[string]map[string]interface{}{ + "dnat_rule": params, + } + + ret := SNatDEntry{} + err := DoCreate(region.ecsClient.DNatRules.Create, jsonutils.Marshal(packParams), &ret) + if err != nil { + return SNatDEntry{}, errors.Wrapf(err, `create dnat rule of nat gateway %q failed`, gatewayID) + } + return ret, nil +} + +func (region *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayID string) (SNatSEntry, error) { + params := make(map[string]interface{}) + params["nat_gateway_id"] = gatewayID + if len(rule.NetworkID) != 0 { + params["network_id"] = rule.NetworkID + } + if len(rule.SourceCIDR) != 0 { + params["cidr"] = rule.SourceCIDR + } + params["floating_ip_id"] = rule.ExternalIPID + + packParams := map[string]map[string]interface{}{ + "snat_rule": params, + } + + ret := SNatSEntry{} + err := DoCreate(region.ecsClient.SNatRules.Create, jsonutils.Marshal(packParams), &ret) + if err != nil { + return SNatSEntry{}, errors.Wrapf(err, `create snat rule of nat gateway %q failed`, gatewayID) + } + return ret, nil +} + +func (region *SRegion) GetNatDEntryByID(id string) (SNatDEntry, error) { + dnat := SNatDEntry{} + err := DoGet(region.ecsClient.DNatRules.Get, id, map[string]string{}, &dnat) + + if err != nil { + return SNatDEntry{}, err + } + return dnat, nil +} + +func (region *SRegion) GetNatSEntryByID(id string) (SNatSEntry, error) { + snat := SNatSEntry{} + err := DoGet(region.ecsClient.SNatRules.Get, id, map[string]string{}, &snat) + if err != nil { + return SNatSEntry{}, cloudprovider.ErrNotFound + } + return snat, nil +} + +func NatResouceStatusTransfer(status string) string { + // In Huawei Cloud, there are isx resource status of Nat, "ACTIVE", "PENDING_CREATE", + // "PENDING_UPDATE", "PENDING_DELETE", "EIP_FREEZED", "INACTIVE". + switch status { + case "ACTIVE": + return api.NAT_STAUTS_AVAILABLE + case "PENDING_CREATE": + return api.NAT_STATUS_ALLOCATE + case "PENDING_UPDATE", "PENDING_DELETE": + return api.NAT_STATUS_DEPLOYING + default: + return api.NAT_STATUS_UNKNOWN + } +} + +func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) { + resp, err := self.ecsClient.NatGateways.Get(id, nil) + if err != nil { + return nil, errors.Wrapf(err, "NatGateways.Get(%s)", id) + } + nat := &SNatGateway{region: self} + err = resp.Unmarshal(nat) + return nat, errors.Wrap(err, "resp.Unmarshal") +} + +func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { + nat, err := self.region.CreateNatGateway(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateNatGateway") + } + return nat, nil +} + +func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGateway, error) { + spec := "" + switch strings.ToLower(opts.NatSpec) { + case api.NAT_SPEC_SMALL: + spec = "1" + case api.NAT_SPEC_MIDDLE: + spec = "2" + case api.NAT_SPEC_LARGE: + spec = "3" + case api.NAT_SPEC_XLARGE: + spec = "4" + } + params := jsonutils.Marshal(map[string]map[string]interface{}{ + "nat_gateway": map[string]interface{}{ + "name": opts.Name, + "description": opts.Desc, + "router_id": opts.VpcId, + "internal_network_id": opts.NetworkId, + "spec": spec, + }, + }) + resp, err := self.ecsClient.NatGateways.Create(params) + if err != nil { + return nil, errors.Wrap(err, "AsyncCreate") + } + nat := &SNatGateway{region: self} + err = resp.Unmarshal(nat) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return nat, nil +} + +func (self *SRegion) DeleteNatGateway(id string) error { + _, err := self.ecsClient.NatGateways.Delete(id, nil) + return errors.Wrapf(err, "NatGateways.Delete(%s)", id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natstable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natstable.go new file mode 100644 index 0000000000..fc1bdb2934 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/natstable.go @@ -0,0 +1,122 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SNatSEntry struct { + multicloud.SResourceBase + huawei.HuaweiTags + gateway *SNatGateway + + ID string `json:"id"` + NatGatewayID string `json:"nat_gateway_id"` + NetworkID string `json:"network_id"` + SourceCIDR string `json:"cidr"` + Status string `json:"status"` + SNatIP string `json:"floating_ip_address"` + AdminStateUp bool `json:"admin_state_up"` +} + +func (nat *SNatSEntry) GetId() string { + return nat.ID +} + +func (nat *SNatSEntry) GetName() string { + // Snat rule has no name in Huawei Cloud, so return ID + return nat.GetId() +} + +func (nat *SNatSEntry) GetGlobalId() string { + return nat.GetId() +} + +func (nat *SNatSEntry) GetStatus() string { + return NatResouceStatusTransfer(nat.Status) +} + +func (nat *SNatSEntry) GetIP() string { + return nat.SNatIP +} + +func (nat *SNatSEntry) GetSourceCIDR() string { + return nat.SourceCIDR +} + +func (nat *SNatSEntry) GetNetworkId() string { + return nat.NetworkID +} + +func (nat *SNatSEntry) Delete() error { + return nat.gateway.region.DeleteNatSEntry(nat.GetId()) +} + +// getNatSTable return all snat rules of gateway +func (gateway *SNatGateway) getNatSTable() ([]SNatSEntry, error) { + ret, err := gateway.region.GetNatSTable(gateway.GetId()) + if err != nil { + return nil, err + } + for i := range ret { + ret[i].gateway = gateway + } + return ret, nil +} + +func (region *SRegion) GetNatSTable(natGatewayID string) ([]SNatSEntry, error) { + queuies := map[string]string{ + "nat_gateway_id": natGatewayID, + } + sNatSTableEntris := make([]SNatSEntry, 0, 2) + err := doListAllWithMarker(region.ecsClient.SNatRules.List, queuies, &sNatSTableEntris) + if err != nil { + return nil, errors.Wrapf(err, `get snat rule of gateway %q`, natGatewayID) + } + for i := range sNatSTableEntris { + nat := &sNatSTableEntris[i] + if len(nat.SourceCIDR) != 0 { + continue + } + subnet := SNetwork{} + err := DoGet(region.ecsClient.Subnets.Get, nat.NetworkID, map[string]string{}, &subnet) + if err != nil { + return nil, errors.Wrapf(err, `get cidr of subnet %q`, nat.NetworkID) + } + nat.SourceCIDR = subnet.CIDR + } + return sNatSTableEntris, nil +} + +func (region *SRegion) DeleteNatSEntry(entryID string) error { + _, err := region.ecsClient.SNatRules.Delete(entryID, nil) + if err != nil { + return errors.Wrapf(err, `delete snat rule %q failed`, entryID) + } + return nil +} + +func (nat *SNatSEntry) Refresh() error { + new, err := nat.gateway.region.GetNatSEntryByID(nat.ID) + if err != nil { + return err + } + return jsonutils.Update(nat, new) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/network.go new file mode 100644 index 0000000000..43870401ba --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/network.go @@ -0,0 +1,175 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +/* +Subnets +*/ + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html +type SNetwork struct { + multicloud.SResourceBase + huawei.HuaweiTags + wire *SWire + + AvailabilityZone string `json:"availability_zone"` + CIDR string `json:"cidr"` + DHCPEnable bool `json:"dhcp_enable"` + DNSList []string `json:"dnsList"` + GatewayIP string `json:"gateway_ip"` + ID string `json:"id"` + Ipv6Enable bool `json:"ipv6_enable"` + Name string `json:"name"` + NeutronNetworkID string `json:"neutron_network_id"` + NeutronSubnetID string `json:"neutron_subnet_id"` + PrimaryDNS string `json:"primary_dns"` + SecondaryDNS string `json:"secondary_dns"` + Status string `json:"status"` + VpcID string `json:"vpc_id"` +} + +func (self *SNetwork) GetId() string { + return self.ID +} + +func (self *SNetwork) GetName() string { + if len(self.Name) == 0 { + return self.ID + } + + return self.Name +} + +func (self *SNetwork) GetGlobalId() string { + return self.ID +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090591.html +func (self *SNetwork) GetStatus() string { + switch self.Status { + case "ACTIVE", "UNKNOWN": + return api.NETWORK_STATUS_AVAILABLE // ? todo: // UNKNOWN + case "ERROR": + return api.NETWORK_STATUS_UNKNOWN + default: + return api.NETWORK_STATUS_UNKNOWN + } +} + +func (self *SNetwork) Refresh() error { + log.Debugf("network refresh %s", self.GetId()) + new, err := self.wire.region.getNetwork(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SNetwork) IsEmulated() bool { + return false +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + startIp = startIp.StepUp() // 2 + return startIp.String() +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + 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.CIDR) + return pref.MaskLen +} + +func (self *SNetwork) GetGateway() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String() +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetIsPublic() bool { + return true +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) Delete() error { + return self.wire.region.deleteNetwork(self.VpcID, self.GetId()) +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) { + network := SNetwork{} + err := DoGet(self.ecsClient.Subnets.Get, networkId, nil, &network) + return &network, err +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090592.html +func (self *SRegion) GetNetwroks(vpcId string) ([]SNetwork, error) { + querys := map[string]string{} + if len(vpcId) > 0 { + querys["vpc_id"] = vpcId + } + + networks := make([]SNetwork, 0) + err := doListAllWithMarker(self.ecsClient.Subnets.List, querys, &networks) + return networks, err +} + +func (self *SRegion) deleteNetwork(vpcId string, networkId string) error { + ctx := &modules.SManagerContext{InstanceId: vpcId, InstanceManager: self.ecsClient.Vpcs} + return DoDeleteWithSpec(self.ecsClient.Subnets.DeleteInContextWithSpec, ctx, networkId, "", nil, nil) +} + +func (self *SNetwork) GetProjectId() string { + return self.wire.vpc.EnterpriseProjectID +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/object.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/object.go new file mode 100644 index 0000000000..fdc5e10f8b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/object.go @@ -0,0 +1,103 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + "net/http" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" +) + +type SObject struct { + bucket *SBucket + + cloudprovider.SBaseCloudObject +} + +func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { + return o.bucket +} + +func (o *SObject) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + obscli, err := o.bucket.region.getOBSClient() + if err != nil { + log.Errorf("o.bucket.region.GetOssClient error %s", err) + return acl + } + input := &obs.GetObjectAclInput{} + input.Bucket = o.bucket.Name + input.Key = o.Key + output, err := obscli.GetObjectAcl(input) + if err != nil { + log.Errorf("GetObjectAcl error: %v", err) + return acl + } + acl = obsAcl2CannedAcl(output.Grants) + return acl +} + +func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { + obscli, err := o.bucket.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "o.bucket.region.getOBSClient") + } + input := &obs.SetObjectAclInput{} + input.Bucket = o.bucket.Name + input.Key = o.Key + input.ACL = obs.AclType(string(aclStr)) + _, err = obscli.SetObjectAcl(input) + if err != nil { + return errors.Wrap(err, "obscli.SetObjectAcl") + } + return nil +} + +func (o *SObject) GetMeta() http.Header { + if o.Meta != nil { + return o.Meta + } + obscli, err := o.bucket.region.getOBSClient() + if err != nil { + log.Errorf("getOBSClient fail %s", err) + return nil + } + input := &obs.GetObjectMetadataInput{} + input.Bucket = o.bucket.Name + input.Key = o.Key + output, err := obscli.GetObjectMetadata(input) + if err != nil { + log.Errorf("obscli.GetObjectMetadata fail %s", err) + return nil + } + meta := http.Header{} + for k, v := range output.Metadata { + meta.Add(k, v) + } + if len(output.ContentType) > 0 { + meta.Add(cloudprovider.META_HEADER_CONTENT_TYPE, output.ContentType) + } + o.Meta = meta + return meta +} + +func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { + return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) +} diff --git a/pkg/multicloud/hcso/order.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/order.go similarity index 100% rename from pkg/multicloud/hcso/order.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/order.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/port.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/port.go new file mode 100644 index 0000000000..3ef2e4293a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/port.go @@ -0,0 +1,162 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "strings" + + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SFixedIP struct { + IpAddress string + SubnetID string + NetworkId string +} + +func (fixip *SFixedIP) GetGlobalId() string { + return fixip.IpAddress +} + +func (fixip *SFixedIP) GetIP() string { + return fixip.IpAddress +} + +func (fixip *SFixedIP) GetINetworkId() string { + return fixip.NetworkId +} + +func (fixip *SFixedIP) IsPrimary() bool { + return true +} + +type Port struct { + multicloud.SNetworkInterfaceBase + huawei.HuaweiTags + region *SRegion + ID string `json:"id"` + Name string `json:"name"` + Status string `json:"status"` + AdminStateUp string `json:"admin_state_up"` + DNSName string `json:"dns_name"` + MACAddress string `json:"mac_address"` + NetworkID string `json:"network_id"` + TenantID string `json:"tenant_id"` + DeviceID string `json:"device_id"` + DeviceOwner string `json:"device_owner"` + BindingVnicType string `json:"binding:vnic_type"` + FixedIps []SFixedIP +} + +func (port *Port) GetName() string { + if len(port.Name) > 0 { + return port.Name + } + return port.ID +} + +func (port *Port) GetId() string { + return port.ID +} + +func (port *Port) GetGlobalId() string { + return port.ID +} + +func (port *Port) GetMacAddress() string { + return port.MACAddress +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html +func (port *Port) GetAssociateType() string { + switch port.DeviceOwner { + case "compute:nova": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER + case "network:router_gateway", "network:router_interface", "network:router_interface_distributed": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_RESERVED + case "network:dhcp": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_DHCP + case "neutron:LOADBALANCERV2": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_LOADBALANCER + case "neutron:VIP_PORT": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_VIP + default: + if strings.HasPrefix(port.DeviceOwner, "compute:") { + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER + } + } + return port.DeviceOwner +} + +func (port *Port) GetAssociateId() string { + return port.DeviceID +} + +func (port *Port) GetStatus() string { + switch port.Status { + case "ACTIVE", "DOWN": + return api.NETWORK_INTERFACE_STATUS_AVAILABLE + case "BUILD": + return api.NETWORK_INTERFACE_STATUS_CREATING + } + return port.Status +} + +func (port *Port) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { + address := []cloudprovider.ICloudInterfaceAddress{} + for i := 0; i < len(port.FixedIps); i++ { + port.FixedIps[i].NetworkId = port.NetworkID + address = append(address, &port.FixedIps[i]) + } + return address, nil +} + +func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { + ports, err := region.GetPorts("") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNetworkInterface{} + for i := 0; i < len(ports); i++ { + if len(ports[i].DeviceID) == 0 || !utils.IsInStringArray(ports[i].DeviceOwner, []string{"compute:CCI", "compute:nova", "neutron:LOADBALANCERV2"}) { + ports[i].region = region + ret = append(ret, &ports[i]) + } + } + return ret, nil +} + +func (self *SRegion) GetPort(portId string) (Port, error) { + port := Port{} + err := DoGet(self.ecsClient.Port.Get, portId, nil, &port) + return port, err +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html +func (self *SRegion) GetPorts(instanceId string) ([]Port, error) { + ports := make([]Port, 0) + querys := map[string]string{} + if len(instanceId) > 0 { + querys["device_id"] = instanceId + } + + err := doListAllWithMarker(self.ecsClient.Port.List, querys, &ports) + return ports, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/project.go new file mode 100644 index 0000000000..bc16d50759 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/project.go @@ -0,0 +1,106 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +// https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845625.html +type SProject struct { + client *SHuaweiClient + + IsDomain bool `json:"is_domain"` + Description string `json:"description"` + Enabled bool `json:"enabled"` + ID string `json:"id"` + ParentID string `json:"parent_id"` + DomainID string `json:"domain_id"` + Name string `json:"name"` +} + +func (self *SProject) GetRegionID() string { + return strings.Split(self.Name, "_")[0] +} + +func (self *SProject) GetHealthStatus() string { + if self.Enabled { + return api.CLOUD_PROVIDER_HEALTH_NORMAL + } + + return api.CLOUD_PROVIDER_HEALTH_SUSPENDED +} + +func (self *SHuaweiClient) fetchProjects() ([]SProject, error) { + if self.projects != nil { + return self.projects, nil + } + + huawei, _ := self.newGeneralAPIClient() + projects := make([]SProject, 0) + err := doListAll(huawei.Projects.List, nil, &projects) + if err == nil { + self.projects = projects + } + + return projects, err +} + +// obs 权限必须赋予到mos project之上 +func (self *SHuaweiClient) GetMosProjectId() string { + projects, err := self.GetProjects() + if err != nil { + return "" + } + for i := range projects { + if strings.ToLower(projects[i].Name) == "mos" { + return projects[i].ID + } + } + return "" +} + +func (self *SHuaweiClient) GetMosRoles(groupId string) ([]SRole, error) { + client, _ := self.newGeneralAPIClient() + resp, err := client.Projects.ListRoles(self.GetMosProjectId(), groupId) + if err != nil { + return nil, err + } + ret := []SRole{} + return ret, jsonutils.Update(&ret, resp.Data) +} + +func (self *SHuaweiClient) GetProjectById(projectId string) (SProject, error) { + projects, err := self.fetchProjects() + if err != nil { + return SProject{}, err + } + + for _, project := range projects { + if project.ID == projectId { + return project, nil + } + } + return SProject{}, fmt.Errorf("project %s not found", projectId) +} + +func (self *SHuaweiClient) GetProjects() ([]SProject, error) { + return self.fetchProjects() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/provider/doc.go new file mode 100644 index 0000000000..4689a626e0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/hcso/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/provider/provider.go new file mode 100644 index 0000000000..4e5fa529e4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/provider/provider.go @@ -0,0 +1,336 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + huawei "yunion.io/x/cloudmux/pkg/multicloud/hcso" +) + +type SHCSOProviderFactory struct { + cloudprovider.SPrivateCloudBaseProviderFactory +} + +func (self *SHCSOProviderFactory) GetId() string { + return huawei.CLOUD_PROVIDER_HUAWEI +} + +func (self *SHCSOProviderFactory) GetName() string { + return huawei.CLOUD_PROVIDER_HUAWEI_CN +} + +func (self *SHCSOProviderFactory) IsCloudeventRegional() bool { + return true +} + +func (self *SHCSOProviderFactory) GetMaxCloudEventSyncDays() int { + return 7 +} + +func (self *SHCSOProviderFactory) GetMaxCloudEventKeepDays() int { + return 7 +} + +func (self *SHCSOProviderFactory) IsSupportCloudIdService() bool { + return true +} + +func (self *SHCSOProviderFactory) IsSupportClouduserPolicy() bool { + return false +} + +func (self *SHCSOProviderFactory) IsSupportCreateCloudgroup() bool { + return true +} + +func (factory *SHCSOProviderFactory) IsSupportCrossCloudEnvVpcPeering() bool { + return false +} + +func (factory *SHCSOProviderFactory) IsSupportCrossRegionVpcPeering() bool { + return false +} + +func (factory *SHCSOProviderFactory) IsSupportVpcPeeringVpcCidrOverlap() bool { + return true +} + +func (factory *SHCSOProviderFactory) IsSupportModifyRouteTable() bool { + return true +} + +func (factory *SHCSOProviderFactory) IsSupportSAMLAuth() bool { + return true +} + +func (self *SHCSOProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + + if input.SHCSOEndpoints == nil { + return output, errors.Wrap(httperrors.ErrMissingParameter, "cloud_stack_endpoints") + } + + if len(input.DefaultRegion) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "default_region") + } + + if len(input.SHCSOEndpoints.EndpointDomain) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "endpoint_domain") + } + + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + return output, nil +} + +func (self *SHCSOProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + + if input.SHCSOEndpoints != nil { + if len(input.DefaultRegion) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "default_region") + } + + if len(input.SHCSOEndpoints.EndpointDomain) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "endpoint_domain") + } + } + + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func parseAccount(account string) (accessKey string, projectId string) { + segs := strings.Split(account, "/") + if len(segs) == 2 { + accessKey = segs[0] + projectId = segs[1] + } else { + accessKey = account + projectId = "" + } + + return +} + +func (self *SHCSOProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + hscsoEndpoints := cloudprovider.SHCSOEndpoints{} + if cfg.Options != nil { + cfg.Options.Unmarshal(&hscsoEndpoints) + } + accessKey, project_id := parseAccount(cfg.Account) + client, err := huawei.NewHuaweiClient( + huawei.NewHuaweiClientConfig( + accessKey, cfg.Secret, project_id, &hscsoEndpoints, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SHCSOProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SHCSOProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + accessKey, projectId := parseAccount(info.Account) + region := "" + data := strings.Split(info.Name, "-") + if len(data) >= 3 { + region = strings.Join(data[2:], "-") + } + return map[string]string{ + "HUAWEI_CLOUD_ENV": info.Url, + "HUAWEI_ACCESS_KEY": accessKey, + "HUAWEI_SECRET": info.Secret, + "HUAWEI_REGION": region, + "HUAWEI_PROJECT": projectId, + }, nil +} + +func (self *SHCSOProviderFactory) IsMultiTenant() bool { + return true +} + +func init() { + factory := SHCSOProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SHCSOProvider struct { + cloudprovider.SBaseProvider + client *huawei.SHuaweiClient +} + +func (self *SHCSOProvider) GetVersion() string { + return self.client.GetVersion() +} + +func (self *SHCSOProvider) GetSysInfo() (jsonutils.JSONObject, error) { + regions := self.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") + info.Add(jsonutils.NewString(huawei.HUAWEI_API_VERSION), "api_version") + return info, nil +} + +func (self *SHCSOProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SHCSOProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(extId) +} + +func (self *SHCSOProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, nil +} + +func (self *SHCSOProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SHCSOProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SHCSOProvider) GetIamLoginUrl() string { + return self.client.GetIamLoginUrl() +} + +func (self *SHCSOProvider) GetCloudRegionExternalIdPrefix() string { + return self.client.GetCloudRegionExternalIdPrefix() +} + +func (self *SHCSOProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SHCSOProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return self.client.CreateIProject(name) +} + +func (self *SHCSOProvider) GetStorageClasses(regionId string) []string { + return []string{ + "STANDARD", "WARM", "COLD", + } +} + +func (self *SHCSOProvider) GetBucketCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLAuthRead), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SHCSOProvider) GetObjectCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLAuthRead), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SHCSOProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SHCSOProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + return self.client.CreateIClouduser(conf) +} + +func (self *SHCSOProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { + return self.client.GetICloudusers() +} + +func (self *SHCSOProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroups() +} + +func (self *SHCSOProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroupByName(name) +} + +func (self *SHCSOProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + return self.client.CreateICloudgroup(name, desc) +} + +func (self *SHCSOProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetISystemCloudpolicies() +} + +func (self *SHCSOProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetICustomCloudpolicies() +} + +func (self *SHCSOProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { + return self.client.CreateICloudpolicy(opts) +} + +func (self *SHCSOProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.client.GetIClouduserByName(name) +} + +func (self *SHCSOProvider) GetSamlEntityId() string { + return self.client.GetSamlEntityId() +} + +func (self *SHCSOProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { + return self.client.GetICloudSAMLProviders() +} + +func (self *SHCSOProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { + sp, err := self.client.CreateSAMLProvider(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateSAMLProvider") + } + return sp, nil +} + +func (self *SHCSOProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metrics, err := self.client.GetMetrics(opts) + if err != nil { + return nil, errors.Wrapf(err, "GetMetrics") + } + return metrics, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/quota.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/quota.go new file mode 100644 index 0000000000..9c01ff5d8c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/quota.go @@ -0,0 +1,80 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SQuota struct { + Min int + Quota int + Type string + Used int +} + +func (q *SQuota) GetGlobalId() string { + return q.Type +} + +func (q *SQuota) GetQuotaType() string { + return q.Type +} + +func (q *SQuota) GetName() string { + return q.Type +} + +func (q *SQuota) GetDesc() string { + return "" +} + +func (q *SQuota) GetMaxQuotaCount() int { + return q.Quota +} + +func (q *SQuota) GetCurrentQuotaUsedCount() int { + return q.Used +} + +func (self *SRegion) GetQuotas() ([]SQuota, error) { + quotas := []SQuota{} + params := map[string]string{} + result, err := self.ecsClient.Quotas.Get("", params) + if err != nil { + return nil, errors.Wrap(err, "Quotas.List") + } + + err = result.Unmarshal("as, "resources") + if err != nil { + return nil, errors.Wrap(err, "result.Unmarshal") + } + + return quotas, nil +} + +func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { + quotas, err := region.GetQuotas() + if err != nil { + return nil, errors.Wrap(err, "GetQuotas") + } + ret := []cloudprovider.ICloudQuota{} + for i := range quotas { + ret = append(ret, "as[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/region.go new file mode 100644 index 0000000000..afae1cfd0a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/region.go @@ -0,0 +1,1114 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "net/http" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" +) + +type Locales struct { + EnUs string `json:"en-us"` + ZhCN string `json:"zh-cn"` +} + +// https://support.huaweicloud.com/api-iam/zh-cn_topic_0067148043.html +type SRegion struct { + multicloud.SRegion + + client *SHuaweiClient + ecsClient *client.Client + obsClient *obs.ObsClient // 对象存储client.请勿直接引用。 + + Description string `json:"description"` + ID string `json:"id"` + Locales Locales `json:"locales"` + ParentRegionID string `json:"parent_region_id"` + Type string `json:"type"` + + izones []cloudprovider.ICloudZone + ivpcs []cloudprovider.ICloudVpc + iskus []cloudprovider.ICloudSku + + storageCache *SStoragecache +} + +func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetClient() *SHuaweiClient { + return self.client +} + +func (self *SRegion) getECSClient() (*client.Client, error) { + var err error + + if len(self.client.projectId) > 0 { + project, err := self.client.GetProjectById(self.client.projectId) + if err != nil { + return nil, err + } + + regionId := strings.Split(project.Name, "_")[0] + if regionId != self.ID { + // log.Debugf("project %s not in region %s", self.client.ProjectId, self.ID) + return nil, errors.Error("region and project mismatch") + } + } + + if self.ecsClient == nil { + self.ecsClient, err = self.client.newRegionAPIClient(self.ID) + if err != nil { + return nil, err + } + } + + return self.ecsClient, err +} + +func (self *SRegion) getOBSEndpoint() string { + return getOBSEndpoint(self.GetId()) +} + +func (self *SRegion) getOBSClient() (*obs.ObsClient, error) { + if self.obsClient == nil { + obsClient, err := self.client.getOBSClient(self.GetId()) + if err != nil { + return nil, err + } + + client := obsClient.GetClient() + ts, _ := client.Transport.(*http.Transport) + client.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { + if self.client.cpcfg.ReadOnly { + if req.Method == "GET" || req.Method == "HEAD" { + return nil, nil + } + return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) + } + return nil, nil + }) + + self.obsClient = obsClient + } + + return self.obsClient, nil +} + +func (self *SRegion) fetchZones() error { + zones := make([]SZone, 0) + err := doListAll(self.ecsClient.Zones.List, nil, &zones) + if err != nil { + return err + } + + self.izones = make([]cloudprovider.ICloudZone, 0) + for i := range zones { + zone := zones[i] + zone.region = self + self.izones = append(self.izones, &zone) + } + return nil +} + +func (self *SRegion) fetchIVpcs() error { + // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html + vpcs := make([]SVpc, 0) + querys := map[string]string{ + "limit": "2048", + } + err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs) + if err != nil { + return err + } + + self.ivpcs = make([]cloudprovider.ICloudVpc, 0) + for i := range vpcs { + vpc := vpcs[i] + vpc.region = self + self.ivpcs = append(self.ivpcs, &vpc) + } + return nil +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + if len(id) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetIVMById") + } + + instance, err := self.GetInstanceByID(id) + if err != nil { + return nil, err + } + + zone, err := self.getZoneById(instance.OSEXTAZAvailabilityZone) + if err != nil { + return nil, errors.Wrap(err, "getZoneById") + } + instance.host = &SHost{ + zone: zone, + vms: nil, + projectId: self.client.projectId, + Id: instance.HostID, + Name: instance.OSEXTSRVATTRHost, + } + return &instance, err +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return self.GetDisk(id) +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + if info, ok := LatitudeAndLongitude[self.ID]; ok { + return info + } + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + elbs, err := self.GetLoadBalancers() + if err != nil { + return nil, err + } + + ielbs := make([]cloudprovider.ICloudLoadbalancer, len(elbs)) + for i := range elbs { + ielbs[i] = &elbs[i] + } + + return ielbs, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561531.html +func (self *SRegion) GetLoadBalancers() ([]SLoadbalancer, error) { + params := map[string]string{} + if len(self.client.projectId) > 0 { + params["project_id"] = self.client.projectId + } + + ret := []SLoadbalancer{} + err := doListAll(self.ecsClient.Elb.List, params, &ret) + if err != nil { + return nil, err + } + + for i := range ret { + ret[i].region = self + } + + return ret, nil +} + +func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { + elb, err := self.GetLoadBalancerById(loadbalancerId) + if err != nil { + return nil, err + } + + return &elb, nil +} + +func (self *SRegion) GetLoadBalancerById(loadbalancerId string) (SLoadbalancer, error) { + elb := SLoadbalancer{} + err := DoGet(self.ecsClient.Elb.Get, loadbalancerId, nil, &elb) + if err != nil { + return elb, err + } + + elb.region = self + return elb, nil +} + +func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { + acl, err := self.GetLoadBalancerAclById(aclId) + if err != nil { + return nil, err + } + + return &acl, nil +} + +func (self *SRegion) GetLoadBalancerAclById(aclId string) (SElbACL, error) { + acl := SElbACL{} + err := DoGet(self.ecsClient.ElbWhitelist.Get, aclId, nil, &acl) + if err != nil { + return acl, err + } + + acl.region = self + return acl, nil +} + +func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + cert, err := self.GetLoadBalancerCertificateById(certId) + if err != nil { + return nil, err + } + + return &cert, nil +} + +func (self *SRegion) GetLoadBalancerCertificateById(certId string) (SElbCert, error) { + ret := SElbCert{} + err := DoGet(self.ecsClient.ElbCertificates.Get, certId, nil, &ret) + if err != nil { + return ret, err + } + + ret.region = self + return ret, nil +} + +func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + ret, err := self.CreateLoadBalancerCertificate(cert) + if err != nil { + return nil, err + } + + return &ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561584.html +func (self *SRegion) CreateLoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (SElbCert, error) { + params := jsonutils.NewDict() + params.Set("name", jsonutils.NewString(cert.Name)) + params.Set("private_key", jsonutils.NewString(cert.PrivateKey)) + params.Set("certificate", jsonutils.NewString(cert.Certificate)) + + ret := SElbCert{} + err := DoCreate(self.ecsClient.ElbCertificates.Create, params, &ret) + if err != nil { + return ret, err + } + + ret.region = self + return ret, nil +} + +func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { + ret, err := self.GetLoadBalancerAcls("") + if err != nil { + return nil, err + } + + iret := make([]cloudprovider.ICloudLoadbalancerAcl, len(ret)) + for i := range ret { + iret[i] = &ret[i] + } + return iret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561582.html +func (self *SRegion) GetLoadBalancerAcls(listenerId string) ([]SElbACL, error) { + params := map[string]string{} + if len(listenerId) > 0 { + params["listener_id"] = listenerId + } + + ret := []SElbACL{} + err := doListAll(self.ecsClient.ElbWhitelist.List, params, &ret) + if err != nil { + return nil, err + } + + for i := range ret { + ret[i].region = self + } + + return ret, nil +} + +func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + ret, err := self.GetLoadBalancerCertificates() + if err != nil { + return nil, err + } + + iret := make([]cloudprovider.ICloudLoadbalancerCertificate, len(ret)) + for i := range ret { + iret[i] = &ret[i] + } + return iret, nil +} + +func (self *SRegion) GetLoadBalancerCertificates() ([]SElbCert, error) { + ret := []SElbCert{} + err := doListAll(self.ecsClient.ElbCertificates.List, nil, &ret) + if err != nil { + return nil, err + } + + for i := range ret { + ret[i].region = self + } + + return ret, nil +} + +// https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845622.html +func (self *SRegion) GetId() string { + return self.ID +} + +func (self *SRegion) GetName() string { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.Locales.ZhCN) +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.Locales.EnUs) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", api.CLOUD_PROVIDER_HCSO, self.ID) +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) Refresh() error { + return nil +} + +func (self *SRegion) IsEmulated() bool { + return false +} + +func (self *SRegion) GetLatitude() float32 { + if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok { + return locationInfo.Latitude + } + return 0.0 +} + +func (self *SRegion) GetLongitude() float32 { + if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok { + return locationInfo.Longitude + } + return 0.0 +} + +func (self *SRegion) fetchInfrastructure() error { + _, err := self.getECSClient() + if 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 { + vpc := self.ivpcs[i].(*SVpc) + wire := SWire{region: self, vpc: vpc} + vpc.addWire(&wire) + + for j := 0; j < len(self.izones); j += 1 { + zone := self.izones[j].(*SZone) + zone.addWire(&wire) + } + } + return nil +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if self.izones == nil { + var err error + err = self.fetchInfrastructure() + if 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) GetEipById(eipId string) (SEipAddress, error) { + var eip SEipAddress + err := DoGet(self.ecsClient.Eips.Get, eipId, nil, &eip) + eip.region = self + return eip, err +} + +// 返回参数分别为eip 列表、列表长度、error。 +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html +func (self *SRegion) GetEips() ([]SEipAddress, error) { + querys := make(map[string]string) + + eips := make([]SEipAddress, 0) + err := doListAllWithMarker(self.ecsClient.Eips.List, querys, &eips) + for i := range eips { + eips[i].region = self + } + return eips, err +} + +func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + _, err := self.getECSClient() + if err != nil { + return nil, err + } + + eips, err := self.GetEips() + if err != nil { + return nil, err + } + + ret := make([]cloudprovider.ICloudEIP, len(eips)) + for i := 0; i < len(eips); i += 1 { + eips[i].region = self + ret[i] = &eips[i] + } + return ret, nil +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + ivpcs, err := self.GetIVpcs() + if err != nil { + return nil, err + } + for i := 0; i < len(ivpcs); i += 1 { + if ivpcs[i].GetGlobalId() == id { + return ivpcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { + eip, err := self.GetEipById(eipId) + return &eip, err +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0060595555.html +func (self *SRegion) DeleteSecurityGroup(secgroupId string) error { + return DoDelete(self.ecsClient.SecurityGroups.Delete, secgroupId, nil, nil) +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return self.GetSecurityGroupDetails(secgroupId) +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := self.GetSecurityGroups(opts.VpcId, opts.Name) + if err != nil { + return nil, err + } + if len(secgroups) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(secgroups) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + secgroups[0].region = self + return &secgroups[0], nil +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return self.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090608.html +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + return self.CreateVpc(opts.NAME, opts.CIDR, opts.Desc) +} + +func (self *SRegion) CreateVpc(name, cidr, desc string) (*SVpc, error) { + params := map[string]interface{}{ + "vpc": map[string]string{ + "name": name, + "cidr": cidr, + "description": desc, + }, + } + vpc := &SVpc{region: self} + return vpc, DoCreate(self.ecsClient.Vpcs.Create, jsonutils.Marshal(params), vpc) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html +// size: 1Mbit/s~2000Mbit/s +// bgpType: 5_telcom,5_union,5_bgp,5_sbgp. +// 东北-大连:5_telcom、5_union +// 华南-广州:5_sbgp +// 华东-上海二:5_sbgp +// 华北-北京一:5_bgp、5_sbgp +// 亚太-香港:5_bgp +func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + var ctype TInternetChargeType + switch eip.ChargeType { + case api.EIP_CHARGE_TYPE_BY_TRAFFIC: + ctype = InternetChargeByTraffic + case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: + ctype = InternetChargeByBandwidth + } + + if len(eip.BGPType) == 0 { + eip.BGPType = "5_bgp" + } + + // 华为云EIP名字最大长度64 + if len(eip.Name) > 64 { + eip.Name = eip.Name[:64] + } + + ieip, err := self.AllocateEIP(eip.Name, eip.BandwidthMbps, ctype, eip.BGPType, eip.ProjectId) + ieip.region = self + if err != nil { + return nil, err + } + + err = cloudprovider.WaitStatus(ieip, api.EIP_STATUS_READY, 5*time.Second, 60*time.Second) + return ieip, err +} + +func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := self.GetSnapshots("", "") + if err != nil { + log.Errorf("self.GetSnapshots fail %s", err) + return nil, err + } + + ret := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := 0; i < len(snapshots); i += 1 { + snapshots[i].region = self + ret[i] = &snapshots[i] + } + return ret, nil +} + +func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := self.GetSnapshotById(snapshotId) + return &snapshot, err +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetProvider() string { + return CLOUD_PROVIDER_HUAWEI +} + +func (self *SRegion) GetCloudEnv() string { + return "" +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html +// 目前desc字段并没有用到 +func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (*SSecurityGroup, error) { + // 华为不允许创建名称为default的安全组 + if strings.ToLower(name) == "default" { + name = fmt.Sprintf("%s-%s", vpcId, name) + } + + params := jsonutils.NewDict() + secgroupObj := jsonutils.NewDict() + secgroupObj.Add(jsonutils.NewString(name), "name") + if len(vpcId) > 0 && vpcId != api.NORMAL_VPC_ID { + secgroupObj.Add(jsonutils.NewString(vpcId), "vpc_id") + } + params.Add(secgroupObj, "security_group") + + secgroup := SSecurityGroup{region: self} + err := DoCreate(self.ecsClient.SecurityGroups.Create, params, &secgroup) + return &secgroup, err +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087467071.html +func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error { + _, err := self.ecsClient.SecurityGroupRules.DeleteInContextWithSpec(nil, secGrpRuleId, "", nil, nil, "") + return err +} + +func (self *SRegion) DeleteSecurityGroupRule(ruleId string) error { + return self.delSecurityGroupRule(ruleId) +} + +func (self *SRegion) CreateSecurityGroupRule(secgroupId string, rule cloudprovider.SecurityRule) error { + return self.addSecurityGroupRules(secgroupId, rule) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087451723.html +// icmp port对应关系:https://support.huaweicloud.com/api-vpc/zh-cn_topic_0024109590.html +func (self *SRegion) addSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error { + direction := "" + if rule.Direction == secrules.SecurityRuleIngress { + direction = "ingress" + } else { + direction = "egress" + } + + protocal := rule.Protocol + if rule.Protocol == secrules.PROTO_ANY { + protocal = "" + } + + // imcp协议默认为any + if rule.Protocol == secrules.PROTO_ICMP { + return self.addSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String()) + } + + if len(rule.Ports) > 0 { + for _, port := range rule.Ports { + portStr := fmt.Sprintf("%d", port) + err := self.addSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String()) + if err != nil { + return err + } + } + } else { + portStart := fmt.Sprintf("%d", rule.PortStart) + portEnd := fmt.Sprintf("%d", rule.PortEnd) + err := self.addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String()) + if err != nil { + return err + } + } + + return nil +} + +func (self *SRegion) addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error { + params := jsonutils.NewDict() + secgroupObj := jsonutils.NewDict() + secgroupObj.Add(jsonutils.NewString(secGrpId), "security_group_id") + secgroupObj.Add(jsonutils.NewString(direction), "direction") + secgroupObj.Add(jsonutils.NewString(ipNet), "remote_ip_prefix") + secgroupObj.Add(jsonutils.NewString("IPV4"), "ethertype") + // 端口为空或者1-65535 + if len(portStart) > 0 && portStart != "0" && portStart != "-1" { + secgroupObj.Add(jsonutils.NewString(portStart), "port_range_min") + } + if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" { + secgroupObj.Add(jsonutils.NewString(portEnd), "port_range_max") + } + if len(protocol) > 0 { + secgroupObj.Add(jsonutils.NewString(protocol), "protocol") + } + params.Add(secgroupObj, "security_group_rule") + + rule := SecurityGroupRule{} + return DoCreate(self.ecsClient.SecurityGroupRules.Create, params, &rule) +} + +func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + ret, err := self.CreateLoadBalancer(loadbalancer) + if err != nil { + return nil, err + } + + return &ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561535.html +func (self *SRegion) CreateLoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (SLoadbalancer, error) { + ret := SLoadbalancer{} + subnet, err := self.getNetwork(loadbalancer.NetworkIDs[0]) + if err != nil { + return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.getNetwork") + } + + params := jsonutils.NewDict() + elbObj := jsonutils.NewDict() + elbObj.Set("name", jsonutils.NewString(loadbalancer.Name)) + elbObj.Set("vip_subnet_id", jsonutils.NewString(subnet.NeutronSubnetID)) + if len(loadbalancer.Address) > 0 { + elbObj.Set("vip_address", jsonutils.NewString(loadbalancer.Address)) + } + elbObj.Set("tenant_id", jsonutils.NewString(self.client.projectId)) + params.Set("loadbalancer", elbObj) + + err = DoCreate(self.ecsClient.Elb.Create, params, &ret) + if err != nil { + return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.DoCreate") + } + + ret.region = self + + // 创建公网类型ELB + if len(loadbalancer.EipID) > 0 { + err := self.AssociateEipWithPortId(loadbalancer.EipID, ret.VipPortID) + if err != nil { + return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.AssociateEipWithPortId") + } + } + return ret, nil +} + +func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + ret, err := self.CreateLoadBalancerAcl(acl) + if err != nil { + return nil, err + } + + return &ret, nil +} + +func (self *SRegion) CreateLoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (SElbACL, error) { + params := jsonutils.NewDict() + aclObj := jsonutils.NewDict() + aclObj.Set("listener_id", jsonutils.NewString(acl.ListenerId)) + if len(acl.Entrys) > 0 { + whitelist := []string{} + for i := range acl.Entrys { + whitelist = append(whitelist, acl.Entrys[i].CIDR) + } + + aclObj.Set("enable_whitelist", jsonutils.NewBool(acl.AccessControlEnable)) + aclObj.Set("whitelist", jsonutils.NewString(strings.Join(whitelist, ","))) + } else { + aclObj.Set("enable_whitelist", jsonutils.NewBool(false)) + } + params.Set("whitelist", aclObj) + + ret := SElbACL{} + err := DoCreate(self.ecsClient.ElbWhitelist.Create, params, &ret) + if err != nil { + return ret, err + } + + ret.region = self + return ret, nil +} + +func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + iBuckets, err := region.client.getIBuckets() + if err != nil { + return nil, errors.Wrap(err, "getIBuckets") + } + ret := make([]cloudprovider.ICloudBucket, 0) + for i := range iBuckets { + // huawei OBS is shared across projects + if iBuckets[i].GetLocation() == region.GetId() { + ret = append(ret, iBuckets[i]) + } + } + return ret, nil +} + +func str2StorageClass(storageClassStr string) (obs.StorageClassType, error) { + if strings.EqualFold(storageClassStr, string(obs.StorageClassStandard)) { + return obs.StorageClassStandard, nil + } else if strings.EqualFold(storageClassStr, string(obs.StorageClassWarm)) { + return obs.StorageClassWarm, nil + } else if strings.EqualFold(storageClassStr, string(obs.StorageClassCold)) { + return obs.StorageClassCold, nil + } else { + return obs.StorageClassStandard, errors.Error("unsupported storageClass") + } +} + +func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { + obsClient, err := region.getOBSClient() + if err != nil { + return errors.Wrap(err, "region.getOBSClient") + } + input := &obs.CreateBucketInput{} + input.Bucket = name + input.Location = region.GetId() + if len(aclStr) > 0 { + if strings.EqualFold(aclStr, string(obs.AclPrivate)) { + input.ACL = obs.AclPrivate + } else if strings.EqualFold(aclStr, string(obs.AclPublicRead)) { + input.ACL = obs.AclPublicRead + } else if strings.EqualFold(aclStr, string(obs.AclPublicReadWrite)) { + input.ACL = obs.AclPublicReadWrite + } else { + return errors.Error("unsupported acl") + } + } + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return err + } + } + _, err = obsClient.CreateBucket(input) + if err != nil { + return errors.Wrap(err, "obsClient.CreateBucket") + } + region.client.invalidateIBuckets() + return nil +} + +func obsHttpCode(err error) int { + switch httpErr := err.(type) { + case obs.ObsError: + return httpErr.StatusCode + case *obs.ObsError: + return httpErr.StatusCode + } + return -1 +} + +func (region *SRegion) DeleteIBucket(name string) error { + obsClient, err := region.getOBSClient() + if err != nil { + return errors.Wrap(err, "region.getOBSClient") + } + _, err = obsClient.DeleteBucket(name) + if err != nil { + if obsHttpCode(err) == 404 { + return nil + } + log.Debugf("%#v %s", err, err) + return errors.Wrap(err, "DeleteBucket") + } + region.client.invalidateIBuckets() + return nil +} + +func (region *SRegion) HeadBucket(name string) (*obs.BaseModel, error) { + obsClient, err := region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "region.getOBSClient") + } + return obsClient.HeadBucket(name) +} + +func (region *SRegion) IBucketExist(name string) (bool, error) { + _, err := region.HeadBucket(name) + if err != nil { + if obsHttpCode(err) == 404 { + return false, nil + } else { + return false, errors.Wrap(err, "HeadBucket") + } + } + return true, nil +} + +func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { + return cloudprovider.GetIBucketById(region, name) +} + +func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { + return region.GetIBucketById(name) +} + +func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) { + if self.iskus != nil { + return self.iskus, nil + } + + ret := make([]cloudprovider.ICloudSku, 0) + flavors, err := self.fetchInstanceTypes(zoneId) + if err != nil { + return nil, errors.Wrap(err, "fetchInstanceTypes") + } + + for i := range flavors { + ret = append(ret, &flavors[i]) + } + + self.iskus = ret + return ret, nil +} + +func (self *SRegion) GetICloudSku(skuId string) (cloudprovider.ICloudSku, error) { + skus, err := self.GetSkus("") + if err != nil { + return nil, err + } + + for i := range skus { + if skus[i].GetId() == skuId { + return skus[i], nil + } + } + + return nil, errors.Wrap(cloudprovider.ErrNotFound, "GetICloudSku") +} + +func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { + caches, err := self.GetElasticCaches() + if err != nil { + return nil, err + } + + icaches := make([]cloudprovider.ICloudElasticcache, len(caches)) + for i := range caches { + caches[i].region = self + icaches[i] = &caches[i] + } + + return icaches, nil +} + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} + +func (self *SRegion) GetDiskTypes() ([]SDiskType, error) { + ret, err := self.ecsClient.Disks.GetDiskTypes() + if err != nil { + return nil, errors.Wrap(err, "GetDiskTypes") + } + + dts := []SDiskType{} + _ret := jsonutils.NewArray(ret.Data...) + err = _ret.Unmarshal(&dts) + if err != nil { + return nil, errors.Wrap(err, "Unmarshal") + } + + return dts, nil +} + +func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) { + dts, err := self.GetDiskTypes() + if err != nil { + return nil, errors.Wrap(err, "GetDiskTypes") + } + + ret := []string{} + for i := range dts { + if dts[i].IsAvaliableInZone(zoneId) { + ret = append(ret, dts[i].Name) + } + } + + return ret, nil +} + +func (self *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { + return self.GetSkus("") +} + +func (self *SRegion) GetEndpoints() ([]jsonutils.JSONObject, error) { + endpoints := make([]jsonutils.JSONObject, 0) + err := doListAll(self.ecsClient.Endpoints.List, nil, &endpoints) + if err != nil { + return nil, err + } + + return endpoints, nil +} + +func (self *SRegion) GetServices() ([]jsonutils.JSONObject, error) { + services := make([]jsonutils.JSONObject, 0) + err := doListAll(self.ecsClient.Services.List, nil, &services) + if err != nil { + return nil, err + } + + return services, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/roles.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/roles.go new file mode 100644 index 0000000000..9b7e1fd0bb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/roles.go @@ -0,0 +1,164 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/cloudid" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SRole struct { + DomainId string + Flag string + DescriptionCn string + Catelog string + Description string + Id string + DisplayName string + Type string + UpdatedTime string + CreatedTime string + Links SLink + Policy jsonutils.JSONDict + roleType string +} + +func (role *SRole) GetName() string { + return role.DisplayName +} + +func (role *SRole) GetDescription() string { + return role.DescriptionCn +} + +func (role *SRole) GetPolicyType() string { + return role.roleType +} + +func (role *SRole) GetGlobalId() string { + return role.DisplayName +} + +func (role *SRole) UpdateDocument(document *jsonutils.JSONDict) error { + return cloudprovider.ErrNotImplemented +} + +func (role *SRole) GetDocument() (*jsonutils.JSONDict, error) { + return &role.Policy, nil +} + +func (role *SRole) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SHuaweiClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + roles, err := self.GetRoles("", "") + if err != nil { + return nil, errors.Wrap(err, "GetRoles") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range roles { + roles[i].roleType = api.CLOUD_POLICY_TYPE_SYSTEM + ret = append(ret, &roles[i]) + } + return ret, nil +} + +func (self *SHuaweiClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + roles, err := self.GetCustomRoles() + if err != nil { + return nil, errors.Wrap(err, "GetCustomRoles") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range roles { + roles[i].roleType = api.CLOUD_POLICY_TYPE_CUSTOM + ret = append(ret, &roles[i]) + } + return ret, nil +} + +func (self *SHuaweiClient) GetCustomRoles() ([]SRole, error) { + params := map[string]string{} + + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + + client.Roles.SetVersion("v3.0/OS-ROLE") + defer client.Roles.SetVersion("v3.0") + + roles := []SRole{} + err = doListAllWithNextLink(client.Roles.List, params, &roles) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithOffset") + } + return roles, nil +} + +func (self *SHuaweiClient) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + + client.Roles.SetVersion("v3.0/OS-ROLE") + defer client.Roles.SetVersion("v3.0") + + params := map[string]interface{}{ + "role": map[string]interface{}{ + "display_name": opts.Name, + "type": "XA", + "description": opts.Desc, + "policy": opts.Document, + }, + } + + resp, err := client.Roles.Create(jsonutils.Marshal(params)) + if err != nil { + return nil, err + } + role := &SRole{roleType: api.CLOUD_POLICY_TYPE_CUSTOM} + err = resp.Unmarshal(role) + if err != nil { + return nil, err + } + return role, nil +} + +func (self *SHuaweiClient) GetRoles(domainId, name string) ([]SRole, error) { + params := map[string]string{} + if len(domainId) > 0 { + params["domain_id"] = self.ownerId + } + if len(name) > 0 { + params["display_name"] = name + } + + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + + roles := []SRole{} + err = doListAllWithNextLink(client.Roles.List, params, &roles) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithOffset") + } + return roles, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/routetable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/routetable.go new file mode 100644 index 0000000000..995876f003 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/routetable.go @@ -0,0 +1,357 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +// date: 2019.07.15 +// In Huawei cloud, there are only two routing tables in a vpc, which are +// self-defined routing tables and peer-to-peer routing tables. +// The routing in these two tables is different, one's NextHop is a IP address and +// the other one's NextHop address is a instance ID of peer-to-peer connection. +// The former has no id and it's Type is ROUTE_TYPR_IP, and the latter's Type is ROUTE_TYPE_PEER. + +const ( + ROUTE_TYPR_IP = "IP" + ROUTE_TYPE_PEER = "peering" +) + +type SRouteEntry struct { + multicloud.SResourceBase + huawei.HuaweiTags + routeTable *SRouteTable + + ID string // route ID + Type string // route type + Destination string // route destination + NextHop string // route next hop (ip or id) +} + +func (route *SRouteEntry) GetId() string { + if len(route.ID) == 0 { + return route.Destination + ":" + route.NextHop + } + return route.ID +} + +func (route *SRouteEntry) GetName() string { + return "" +} + +func (route *SRouteEntry) GetGlobalId() string { + return route.GetId() +} + +func (route *SRouteEntry) GetStatus() string { + return api.ROUTE_ENTRY_STATUS_AVAILIABLE +} + +func (route *SRouteEntry) Refresh() error { + return nil +} + +func (route *SRouteEntry) IsEmulated() bool { + return false +} + +func (route *SRouteEntry) GetType() string { + if route.Type == ROUTE_TYPE_PEER { + return api.ROUTE_ENTRY_TYPE_CUSTOM + } + return api.ROUTE_ENTRY_TYPE_SYSTEM +} + +func (route *SRouteEntry) GetCidr() string { + return route.Destination +} + +func (route *SRouteEntry) GetNextHopType() string { + // In Huawei Cloud, NextHopType is same with itself + switch route.Type { + case ROUTE_TYPE_PEER: + return api.NEXT_HOP_TYPE_VPCPEERING + default: + return "" + } +} + +func (route *SRouteEntry) GetNextHop() string { + return route.NextHop +} + +// SRouteTable has no ID and Name because there is no id or name of route table in huawei cloud. +// And some method such as GetId and GetName of ICloudRouteTable has no practical meaning +type SRouteTable struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + vpc *SVpc + + VpcId string + Description string + Type string + Routes []*SRouteEntry +} + +func NewSRouteTable(vpc *SVpc, Type string) SRouteTable { + return SRouteTable{ + region: vpc.region, + vpc: vpc, + Type: Type, + VpcId: vpc.GetId(), + } + +} + +func (self *SRouteTable) GetId() string { + return self.GetGlobalId() +} + +func (self *SRouteTable) GetName() string { + return "" +} + +func (self *SRouteTable) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.GetVpcId(), self.GetType()) +} + +func (self *SRouteTable) GetStatus() string { + return api.ROUTE_TABLE_AVAILABLE +} + +func (self *SRouteTable) Refresh() error { + return nil +} + +func (self *SRouteTable) IsEmulated() bool { + return false +} + +func (self *SRouteTable) GetDescription() string { + return self.Description +} + +func (self *SRouteTable) GetRegionId() string { + return self.region.GetId() +} + +func (self *SRouteTable) GetVpcId() string { + return self.VpcId +} + +func (self *SRouteTable) GetType() cloudprovider.RouteTableType { + return cloudprovider.RouteTableTypeSystem +} + +func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { + if self.Routes == nil { + err := self.fetchRoutes() + if err != nil { + return nil, err + } + } + ret := []cloudprovider.ICloudRoute{} + for i := range self.Routes { + ret = append(ret, self.Routes[i]) + } + return ret, nil +} + +// fetchRoutes fetch Routes +func (self *SRouteTable) fetchRoutes() error { + if self.Type == ROUTE_TYPR_IP { + return self.fetchRoutesForIP() + } + return self.fetchRoutesForPeer() +} + +// fetchRoutesForIP fetch the Routes which Type is ROUTE_TYPR_IP through vpc's get api +func (self *SRouteTable) fetchRoutesForIP() error { + ret, err := self.region.ecsClient.Vpcs.Get(self.GetVpcId(), map[string]string{}) + if err != nil { + return errors.Wrap(err, "get vpc info error") + } + routeArray, err := ret.GetArray("routes") + routes := make([]*SRouteEntry, 0, len(routeArray)) + for i := range routeArray { + destination, err := routeArray[i].GetString("destination") + if err != nil { + return errors.Wrap(err, "get destination of route error") + } + nextHop, err := routeArray[i].GetString("nexthop") + if err != nil { + return errors.Wrap(err, "get nexthop of route error") + } + routes = append(routes, &SRouteEntry{ + routeTable: self, + ID: "", + Type: ROUTE_TYPR_IP, + Destination: destination, + NextHop: nextHop, + }) + } + self.Routes = routes + return nil +} + +// fetchRoutesForPeer fetch the routes which Type is ROUTE_TYPE_PEER through vpcRoute's list api +func (self *SRouteTable) fetchRoutesForPeer() error { + retPeer, err := self.region.ecsClient.VpcRoutes.List(map[string]string{"vpc_id": self.GetVpcId()}) + if err != nil { + return errors.Wrap(err, "get peer route error") + } + routesPeer := make([]*SRouteEntry, 0, retPeer.Total) + for i := range retPeer.Data { + route := retPeer.Data[i] + id, err := route.GetString("id") + if err != nil { + return errors.Wrap(err, "get id of peer route error") + } + destination, err := route.GetString("destination") + if err != nil { + return errors.Wrap(err, "get destination of peer route error") + } + nextHop, err := route.GetString("nexthop") + if err != nil { + return errors.Wrap(err, "get nexthop of peer route error") + } + routesPeer = append(routesPeer, &SRouteEntry{ + routeTable: self, + ID: id, + Type: ROUTE_TYPE_PEER, + Destination: destination, + NextHop: nextHop, + }) + } + self.Routes = routesPeer + return nil +} + +func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { + result := []cloudprovider.RouteTableAssociation{} + return result +} + +func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { + if route.NextHopType != api.NEXT_HOP_TYPE_VPCPEERING { + return cloudprovider.ErrNotSupported + } + err := self.region.CreatePeeringRoute(self.vpc.GetId(), route.Destination, route.NextHop) + if err != nil { + return errors.Wrapf(err, " self.region.CreatePeeringRoute(%s,%s,%s)", self.vpc.GetId(), route.Destination, route.NextHop) + } + return nil +} + +func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { + err := self.RemoveRoute(route) + if err != nil { + return errors.Wrap(err, "self.RemoveRoute(route)") + } + err = self.CreateRoute(route) + if err != nil { + return errors.Wrap(err, "self.CreateRoute(route)") + } + return nil +} + +func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { + err := self.region.DeletePeeringRoute(route.RouteId) + if err != nil { + return errors.Wrapf(err, "self.region.DeletePeeringRoute(%s)", route.RouteId) + } + return nil +} + +// GetRouteTables return []SRouteTable of self +func (self *SVpc) getRouteTables() ([]SRouteTable, error) { + // every Vpc has two route table in Huawei Cloud + routeTableIp := NewSRouteTable(self, ROUTE_TYPR_IP) + routeTablePeer := NewSRouteTable(self, ROUTE_TYPE_PEER) + if err := routeTableIp.fetchRoutesForIP(); err != nil { + return nil, errors.Wrap(err, `get route table whilc type is "ip" error`) + } + if err := routeTablePeer.fetchRoutesForPeer(); err != nil { + return nil, errors.Wrap(err, `get route table whilc type is "peering" error`) + } + ret := make([]SRouteTable, 0, 2) + if len(routeTableIp.Routes) != 0 { + ret = append(ret, routeTableIp) + } + if len(routeTablePeer.Routes) != 0 { + ret = append(ret, routeTablePeer) + } + return ret, nil +} + +// GetRouteTables return []SRouteTable of vpc which id is vpcId if vpcId is no-nil, +// otherwise return []SRouteTable of all vpc in this SRegion +func (self *SRegion) GetRouteTables(vpcId string) ([]SRouteTable, error) { + vpcs, err := self.GetVpcs() + if err != nil { + return nil, errors.Wrap(err, "Get Vpcs error") + } + if vpcId != "" { + for i := range vpcs { + if vpcs[i].GetId() == vpcId { + vpcs = vpcs[i : i+1] + break + } + } + } + ret := make([]SRouteTable, 0, 2*len(vpcs)) + for _, vpc := range vpcs { + routetables, err := vpc.getRouteTables() + if err != nil { + return nil, errors.Wrapf(err, "get vpc's route tables whilch id is %s error", vpc.GetId()) + } + ret = append(ret, routetables...) + + } + return ret, nil +} + +func (self *SRegion) CreatePeeringRoute(vpcId, destinationCidr, target string) error { + params := jsonutils.NewDict() + routeObj := jsonutils.NewDict() + routeObj.Set("type", jsonutils.NewString("peering")) + routeObj.Set("nexthop", jsonutils.NewString(target)) + routeObj.Set("destination", jsonutils.NewString(destinationCidr)) + routeObj.Set("vpc_id", jsonutils.NewString(vpcId)) + params.Set("route", routeObj) + err := DoCreate(self.ecsClient.VpcRoutes.Create, params, nil) + if err != nil { + return errors.Wrapf(err, "DoCreate(self.ecsClient.VpcRoutes.Create, %s, &ret)", jsonutils.Marshal(params).String()) + } + return nil +} + +func (self *SRegion) DeletePeeringRoute(routeId string) error { + err := DoDelete(self.ecsClient.VpcRoutes.Delete, routeId, nil, nil) + if err != nil { + return errors.Wrapf(err, "DoDelete(self.ecsClient.VpcRoutes.Delete,%s,nil)", routeId) + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/saml_provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/saml_provider.go new file mode 100644 index 0000000000..4efbba45de --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/saml_provider.go @@ -0,0 +1,350 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "time" + "unicode" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/stringutils" + + api "yunion.io/x/cloudmux/pkg/apis/cloudid" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/modules" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" + "yunion.io/x/onecloud/pkg/util/samlutils" +) + +type SAMLProviderLinks struct { + Self string + Protocols string +} + +type SAMLProvider struct { + multicloud.SResourceBase + huawei.HuaweiTags + client *SHuaweiClient + + Id string + Links SAMLProviderLinks + Description string +} + +func (self *SAMLProvider) GetId() string { + return self.Id +} + +func (self *SAMLProvider) GetGlobalId() string { + return self.Id +} + +func (self *SAMLProvider) GetName() string { + return self.Id +} + +func (self *SAMLProvider) GetStatus() string { + mapping, _ := self.client.findMapping() + if mapping != nil { + return api.SAML_PROVIDER_STATUS_AVAILABLE + } + return api.SAML_PROVIDER_STATUS_UNVALIABLE +} + +func (self *SAMLProvider) GetAuthUrl() string { + return fmt.Sprintf("https://auth.%s/authui/federation/websso?domain_id=%s&idp=%s&protocol=saml", self.client.endpoints.EndpointDomain, self.client.ownerId, self.Id) +} + +func (self *SAMLProvider) Delete() error { + return self.client.DeleteSAMLProvider(self.Id) +} + +func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { + info, err := self.client.GetSAMLProviderMetadata(self.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetSAMLProviderMetadata(%s)", self.Id) + } + metadata, err := samlutils.ParseMetadata([]byte(info.Data)) + if err != nil { + return nil, errors.Wrapf(err, "ParseMetadata") + } + return &metadata, nil +} + +func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { + return self.client.UpdateSAMLProviderMetadata(self.Id, metadata.String()) +} + +func (self *SHuaweiClient) ListSAMLProviders() ([]SAMLProvider, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrapf(err, "newGeneralAPIClient") + } + samls := []SAMLProvider{} + err = doListAllWithNextLink(client.SAMLProviders.List, nil, &samls) + if err != nil { + return nil, errors.Wrapf(err, "doListAll") + } + return samls, nil +} + +type SAMLProviderProtocol struct { + MappingId string + Id string +} + +func (self *SHuaweiClient) GetSAMLProviderProtocols(id string) ([]SAMLProviderProtocol, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + resp, err := client.SAMLProviders.ListInContextWithSpec(nil, fmt.Sprintf("%s/protocols", id), nil, "protocols") + if err != nil { + return nil, errors.Wrapf(err, "ListInContextWithSpec") + } + protocols := []SAMLProviderProtocol{} + return protocols, jsonutils.Update(&protocols, resp.Data) +} + +func (self *SHuaweiClient) DeleteSAMLProviderProtocol(spId, id string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + _, err = client.SAMLProviders.DeleteInContextWithSpec(nil, spId, fmt.Sprintf("protocols/%s", id), nil, nil, "") + return err +} + +type SAMLProviderMetadata struct { + DomainId string + UpdateTime time.Time + Data string + IdpId string + ProtocolId string + Id string + EntityId string + XaccountType string +} + +func (self *SHuaweiClient) GetSAMLProviderMetadata(id string) (*SAMLProviderMetadata, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION") + resp, err := client.SAMLProviders.GetInContextWithSpec(nil, id, fmt.Sprintf("protocols/saml/metadata"), nil, "") + if err != nil { + return nil, err + } + + metadata := &SAMLProviderMetadata{} + err = resp.Unmarshal(metadata) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return metadata, nil +} + +func (self *SHuaweiClient) UpdateSAMLProviderMetadata(id, metadata string) error { + params := map[string]string{ + "domain_id": self.ownerId, + "xaccount_type": "", + "metadata": metadata, + } + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION") + _, err = client.SAMLProviders.PerformAction2("protocols/saml/metadata", id, jsonutils.Marshal(params), "") + if err != nil { + return errors.Wrapf(err, "SAMLProvider.PerformAction") + } + return nil +} + +func (self *SHuaweiClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { + samls, err := self.ListSAMLProviders() + if err != nil { + return nil, errors.Wrapf(err, "ListSAMLProviders") + } + ret := []cloudprovider.ICloudSAMLProvider{} + for i := range samls { + samls[i].client = self + ret = append(ret, &samls[i]) + } + return ret, nil +} + +func (self *SHuaweiClient) DeleteSAMLProvider(id string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + _, err = client.SAMLProviders.Delete(id, nil) + return err +} + +func (self *SHuaweiClient) CreateSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (*SAMLProvider, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + params := jsonutils.Marshal(map[string]interface{}{ + "identity_provider": map[string]interface{}{ + "description": opts.Name, + "enabled": true, + }, + }) + opts.Name = fmt.Sprintf("%s-%s", self.ownerName, opts.Name) + name := []byte{} + for _, c := range opts.Name { + if unicode.IsLetter(c) || unicode.IsNumber(c) || c == '-' || c == '_' { + name = append(name, byte(c)) + } else { + name = append(name, '-') + } + } + opts.Name = string(name) + _, err = client.SAMLProviders.Update(opts.Name, params) + if err != nil { + if he, ok := err.(*modules.HuaweiClientError); ok && he.Code != 409 { + return nil, errors.Wrapf(err, "SAMLProviders.Update") + } + } + ret := SAMLProvider{client: self, Id: opts.Name} + err = self.UpdateSAMLProviderMetadata(opts.Name, opts.Metadata.String()) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + err = self.InitSAMLProviderMapping(opts.Name) + if err != nil { + return nil, errors.Wrapf(err, "InitSAMLProviderMapping") + } + return &ret, nil +} + +type SAMLProviderMapping struct { + Id string + Rules jsonutils.JSONObject +} + +var ( + onecloudMappingRules = jsonutils.Marshal(map[string]interface{}{ + "rules": []map[string]interface{}{ + { + "remote": []map[string]interface{}{ + { + "type": "User", + }, + { + "type": "Groups", + }, + }, + "local": []map[string]interface{}{ + { + "groups": "{1}", + "user": map[string]string{"name": "{0}"}, + }, + }, + }, + }, + }) +) + +func (self *SHuaweiClient) ListSAMLProviderMappings() ([]SAMLProviderMapping, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + mappings := []SAMLProviderMapping{} + err = doListAllWithNextLink(client.SAMLProviderMappings.List, nil, &mappings) + if err != nil { + return nil, err + } + return mappings, nil +} + +func (self *SHuaweiClient) findMapping() (*SAMLProviderMapping, error) { + mappings, err := self.ListSAMLProviderMappings() + if err != nil { + return nil, errors.Wrapf(err, "ListSAMLProviderMappings") + } + for i := range mappings { + if jsonutils.Marshal(map[string]interface{}{"rules": mappings[i].Rules}).Equals(jsonutils.Marshal(onecloudMappingRules)) { + return &mappings[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHuaweiClient) InitSAMLProviderMapping(spId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + + mapping, err := self.findMapping() + if err != nil { + if errors.Cause(err) != cloudprovider.ErrNotFound { + return errors.Wrapf(err, "findMapping") + } + mappingId := stringutils.UUID4() + params := map[string]interface{}{ + "mapping": onecloudMappingRules, + } + _, err = client.SAMLProviderMappings.Update(mappingId, jsonutils.Marshal(params)) + if err != nil { + return errors.Wrapf(err, "create mapping") + } + mapping = &SAMLProviderMapping{ + Id: mappingId, + Rules: onecloudMappingRules, + } + } + protocols, err := self.GetSAMLProviderProtocols(spId) + if err != nil { + return errors.Wrapf(err, "GetSAMLProviderProtocols") + } + params := map[string]interface{}{ + "protocol": map[string]string{ + "mapping_id": mapping.Id, + }, + } + for i := range protocols { + if protocols[i].Id == "saml" { + if protocols[i].MappingId == mapping.Id { + return nil + } + _, err = client.SAMLProviders.PatchInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "") + return err + } + } + _, err = client.SAMLProviders.UpdateInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "") + return err +} + +func (self *SHuaweiClient) DeleteSAMLProviderMapping(id string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + + _, err = client.SAMLProviderMappings.Delete(id, nil) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/securitygroup.go new file mode 100644 index 0000000000..77dd73782c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/securitygroup.go @@ -0,0 +1,276 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +/* +https://support.huaweicloud.com/usermanual-vpc/zh-cn_topic_0073379079.html +安全组的限制 +默认情况下,一个用户可以创建100个安全组。 +默认情况下,一个安全组最多只允许拥有50条安全组规则。 +默认情况下,一个弹性云服务器或辅助网卡最多只能被添加到5个安全组中。 +在创建私网弹性负载均衡时,需要选择弹性负载均衡所在的安全组。请勿删除默认规则或者确保满足以下规则: +出方向:允许发往同一个安全组的报文可以通过,或者允许对端负载均衡器报文通过。 +入方向:允许来自同一个安全组的报文可以通过,或者允许对端负载均衡器报文通过。 +*/ + +import ( + "net" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SecurityGroupRule struct { + Direction string `json:"direction"` + Ethertype string `json:"ethertype"` + ID string `json:"id"` + Description string `json:"description"` + SecurityGroupID string `json:"security_group_id"` + RemoteGroupID string `json:"remote_group_id"` +} + +type SecurityGroupRuleDetail struct { + Direction string `json:"direction"` + Ethertype string `json:"ethertype"` + ID string `json:"id"` + Description string `json:"description"` + PortRangeMax int64 `json:"port_range_max"` + PortRangeMin int64 `json:"port_range_min"` + Protocol string `json:"protocol"` + RemoteGroupID string `json:"remote_group_id"` + RemoteIPPrefix string `json:"remote_ip_prefix"` + SecurityGroupID string `json:"security_group_id"` + TenantID string `json:"tenant_id"` +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html +type SSecurityGroup struct { + multicloud.SSecurityGroup + huawei.HuaweiTags + region *SRegion + + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + VpcID string `json:"vpc_id"` + EnterpriseProjectID string `json:"enterprise_project_id "` + SecurityGroupRules []SecurityGroupRule `json:"security_group_rules"` +} + +// 判断是否兼容云端安全组规则 +func compatibleSecurityGroupRule(r SecurityGroupRule) bool { + // 忽略了源地址是安全组的规则 + if len(r.RemoteGroupID) > 0 { + return false + } + + // 忽略IPV6 + if r.Ethertype == "IPv6" { + return false + } + + return true +} + +func (self *SSecurityGroup) GetId() string { + return self.ID +} + +func (self *SSecurityGroup) GetVpcId() string { + return api.NORMAL_VPC_ID +} + +func (self *SSecurityGroup) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.ID +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.ID +} + +func (self *SSecurityGroup) GetStatus() string { + return "" +} + +func (self *SSecurityGroup) Refresh() error { + if new, err := self.region.GetSecurityGroupDetails(self.GetId()); err != nil { + return err + } else { + return jsonutils.Update(self, new) + } +} + +func (self *SSecurityGroup) IsEmulated() bool { + return false +} + +func (self *SSecurityGroup) GetDescription() string { + if self.Description == self.VpcID { + return "" + } + return self.Description +} + +// todo: 这里需要优化查询太多了 +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + rules := make([]cloudprovider.SecurityRule, 0) + for _, r := range self.SecurityGroupRules { + if !compatibleSecurityGroupRule(r) { + continue + } + + rule, err := self.GetSecurityRule(r.ID) + if err != nil { + return rules, err + } + + rules = append(rules, rule) + } + + return rules, nil +} + +func (self *SSecurityGroup) GetSecurityRule(ruleId string) (cloudprovider.SecurityRule, error) { + remoteRule := SecurityGroupRuleDetail{} + err := DoGet(self.region.ecsClient.SecurityGroupRules.Get, ruleId, nil, &remoteRule) + if err != nil { + return cloudprovider.SecurityRule{}, err + } + + var direction secrules.TSecurityRuleDirection + if remoteRule.Direction == "ingress" { + direction = secrules.SecurityRuleIngress + } else { + direction = secrules.SecurityRuleEgress + } + + protocol := secrules.PROTO_ANY + if remoteRule.Protocol != "" { + protocol = remoteRule.Protocol + } + + var portStart int + var portEnd int + if protocol == secrules.PROTO_ICMP { + portStart = -1 + portEnd = -1 + } else { + portStart = int(remoteRule.PortRangeMin) + portEnd = int(remoteRule.PortRangeMax) + } + + ipNet := &net.IPNet{} + if len(remoteRule.RemoteIPPrefix) > 0 { + _, ipNet, err = net.ParseCIDR(remoteRule.RemoteIPPrefix) + } else { + _, ipNet, err = net.ParseCIDR("0.0.0.0/0") + } + + if err != nil { + return cloudprovider.SecurityRule{}, err + } + + rule := cloudprovider.SecurityRule{ + ExternalId: ruleId, + SecurityRule: secrules.SecurityRule{ + Priority: 1, + Action: secrules.SecurityRuleAllow, + IPNet: ipNet, + Protocol: protocol, + Direction: direction, + PortStart: portStart, + PortEnd: portEnd, + Ports: nil, + Description: remoteRule.Description, + }, + } + + err = rule.ValidateRule() + return rule, err +} + +func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) { + securitygroup := SSecurityGroup{} + err := DoGet(self.ecsClient.SecurityGroups.Get, secGroupId, nil, &securitygroup) + if err != nil { + return nil, err + } + + securitygroup.region = self + return &securitygroup, err +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090617.html +func (self *SRegion) GetSecurityGroups(vpcId string, name string) ([]SSecurityGroup, error) { + querys := map[string]string{} + if len(vpcId) > 0 && !utils.IsInStringArray(vpcId, []string{"default", api.NORMAL_VPC_ID}) { // vpc_id = default or normal 时报错 '{"code":"VPC.0601","message":"Query security groups error vpcId is invalid."}' + querys["vpc_id"] = vpcId + } + + securitygroups := make([]SSecurityGroup, 0) + err := doListAllWithMarker(self.ecsClient.SecurityGroups.List, querys, &securitygroups) + if err != nil { + return nil, err + } + + // security 中的vpc字段只是一个标识,实际可以跨vpc使用 + for i := range securitygroups { + securitygroup := &securitygroups[i] + securitygroup.region = self + } + + result := []SSecurityGroup{} + for _, secgroup := range securitygroups { + if len(name) == 0 || secgroup.Name == name { + result = append(result, secgroup) + } + } + + return result, nil +} + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} + +func (self *SSecurityGroup) Delete() error { + return self.region.DeleteSecurityGroup(self.ID) +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + for _, r := range append(inDels, outDels...) { + err := self.region.delSecurityGroupRule(r.ExternalId) + if err != nil { + return errors.Wrapf(err, "delSecurityGroupRule(%s %s)", r.ExternalId, r.String()) + } + } + for _, r := range append(inAdds, outAdds...) { + err := self.region.addSecurityGroupRules(self.ID, r) + if err != nil { + return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String()) + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/sfs-turbo.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/sfs-turbo.go new file mode 100644 index 0000000000..d90b5fc809 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/sfs-turbo.go @@ -0,0 +1,299 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SfsTurbo struct { + multicloud.SNasBase + huawei.HuaweiTags + region *SRegion + + EnterpriseProjectId string + Actions []string + AvailCapacity float64 + AvailabilityZone string + AzName string + CreatedAt time.Time + CryptKeyId string + ExpandType string + ExportLocation string + Id string + Name string + PayModel string + Region string + SecurityGroupId string + ShareProto string + ShareType string + Size float64 + Status string + SubStatus string + SubnetId string + VpcId string + Description string +} + +func (self *SfsTurbo) GetName() string { + return self.Name +} + +func (self *SfsTurbo) GetId() string { + return self.Id +} + +func (self *SfsTurbo) GetGlobalId() string { + return self.Id +} + +func (self *SfsTurbo) GetFileSystemType() string { + return "SFS Turbo" +} + +func (self *SfsTurbo) Refresh() error { + sf, err := self.region.GetSfsTurbo(self.Id) + if err != nil { + return errors.Wrapf(err, "GetSfsTurbo") + } + return jsonutils.Update(self, sf) +} + +func (self *SfsTurbo) GetBillingType() string { + if self.PayModel == "0" { + return billing_api.BILLING_TYPE_POSTPAID + } + return billing_api.BILLING_TYPE_PREPAID +} + +func (self *SfsTurbo) GetStorageType() string { + if len(self.ExpandType) == 0 { + return strings.ToLower(self.ShareType) + } + return strings.ToLower(self.ShareType) + ".enhanced" +} + +func (self *SfsTurbo) GetProtocol() string { + return self.ShareProto +} + +func (self *SfsTurbo) GetStatus() string { + switch self.Status { + case "100": + return api.NAS_STATUS_CREATING + case "200": + return api.NAS_STATUS_AVAILABLE + case "300": + return api.NAS_STATUS_UNKNOWN + case "303": + return api.NAS_STATUS_CREATE_FAILED + case "400": + return api.NAS_STATUS_DELETING + case "800": + return api.NAS_STATUS_UNAVAILABLE + default: + return self.Status + } +} + +func (self *SfsTurbo) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SfsTurbo) GetCapacityGb() int64 { + return int64(self.Size) +} + +func (self *SfsTurbo) GetUsedCapacityGb() int64 { + return int64(self.Size - self.AvailCapacity) +} + +func (self *SfsTurbo) GetMountTargetCountLimit() int { + return 1 +} + +func (self *SfsTurbo) GetZoneId() string { + return self.AvailabilityZone +} + +func (self *SfsTurbo) GetMountTargets() ([]cloudprovider.ICloudMountTarget, error) { + mt := &sMoutTarget{sfs: self} + return []cloudprovider.ICloudMountTarget{mt}, nil +} + +func (self *SfsTurbo) CreateMountTarget(opts *cloudprovider.SMountTargetCreateOptions) (cloudprovider.ICloudMountTarget, error) { + return nil, errors.Wrap(cloudprovider.ErrNotSupported, "CreateMountTarget") +} + +func (self *SfsTurbo) Delete() error { + return self.region.DeleteSfsTurbo(self.Id) +} + +func (self *SRegion) GetICloudFileSystems() ([]cloudprovider.ICloudFileSystem, error) { + sfs, err := self.GetSfsTurbos() + if err != nil { + return nil, errors.Wrapf(err, "self.GetSfsTurbos") + } + ret := []cloudprovider.ICloudFileSystem{} + for i := range sfs { + sfs[i].region = self + ret = append(ret, &sfs[i]) + } + return ret, nil +} + +func (self *SRegion) GetICloudFileSystemById(id string) (cloudprovider.ICloudFileSystem, error) { + sf, err := self.GetSfsTurbo(id) + if err != nil { + return nil, errors.Wrapf(err, "GetSfsTurbo(%s)", id) + } + return sf, nil +} + +func (self *SRegion) GetSfsTurbos() ([]SfsTurbo, error) { + queues := make(map[string]string) + sfs := make([]SfsTurbo, 0, 2) + err := doListAllWithOffset(self.ecsClient.SfsTurbos.List, queues, &sfs) + if err != nil { + return nil, errors.Wrapf(err, "doListAllWithOffset") + } + return sfs, nil +} + +func (self *SRegion) GetSfsTurbo(id string) (*SfsTurbo, error) { + sf := &SfsTurbo{region: self} + err := DoGet(self.ecsClient.SfsTurbos.Get, id, nil, &sf) + return sf, errors.Wrapf(err, "self.ecsClient.SfsTurbos.Get") +} + +func (self *SRegion) DeleteSfsTurbo(id string) error { + return DoDelete(self.ecsClient.SfsTurbos.Delete, id, nil, nil) +} + +func (self *SRegion) GetSysDefaultSecgroupId() (string, error) { + secs, err := self.GetSecurityGroups("default", "") + if err != nil { + return "", errors.Wrapf(err, "GetSecurityGroups") + } + if len(secs) > 0 { + return secs[0].ID, nil + } + return "", fmt.Errorf("not found default security group") +} + +func (self *SRegion) CreateICloudFileSystem(opts *cloudprovider.FileSystemCraeteOptions) (cloudprovider.ICloudFileSystem, error) { + fs, err := self.CreateSfsTurbo(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateSfsTurbo") + } + return fs, nil +} + +func (self *SRegion) CreateSfsTurbo(opts *cloudprovider.FileSystemCraeteOptions) (*SfsTurbo, error) { + secId, err := self.GetSysDefaultSecgroupId() + if err != nil { + return nil, errors.Wrapf(err, "GetSysDefaultSecgroupId") + } + metadata := map[string]string{} + if strings.HasSuffix(opts.StorageType, ".enhanced") { + metadata["expand_type"] = "bandwidth" + } + params := map[string]interface{}{ + "share": map[string]interface{}{ + "name": opts.Name, + "share_proto": strings.ToUpper(opts.Protocol), + "share_type": strings.ToUpper(strings.TrimSuffix(opts.StorageType, ".enhanced")), + "size": opts.Capacity, + "availability_zone": opts.ZoneId, + "vpc_id": opts.VpcId, + "subnet_id": opts.NetworkId, + "security_group_id": secId, + "description": opts.Desc, + "metadata": metadata, + }, + } + resp, err := self.ecsClient.SfsTurbos.Create(jsonutils.Marshal(params)) + if err != nil { + return nil, errors.Wrapf(err, "Create") + } + id, err := resp.GetString("id") + if err != nil { + return nil, errors.Wrapf(err, "resp.GetString(id)") + } + return self.GetSfsTurbo(id) +} + +func (self *SRegion) GetICloudAccessGroups() ([]cloudprovider.ICloudAccessGroup, error) { + return []cloudprovider.ICloudAccessGroup{}, nil +} + +func (self *SRegion) CreateICloudAccessGroup(opts *cloudprovider.SAccessGroup) (cloudprovider.ICloudAccessGroup, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "CreateICloudAccessGroup") +} + +func (self *SRegion) GetICloudAccessGroupById(id string) (cloudprovider.ICloudAccessGroup, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetICloudAccessGroupById(%s)", id) +} + +type sMoutTarget struct { + sfs *SfsTurbo +} + +func (self *sMoutTarget) GetName() string { + return self.sfs.Name +} + +func (self *sMoutTarget) GetGlobalId() string { + return self.sfs.GetGlobalId() +} + +func (self *sMoutTarget) GetAccessGroupId() string { + return "" +} + +func (self *sMoutTarget) GetDomainName() string { + return self.sfs.ExportLocation +} + +func (self *sMoutTarget) GetNetworkType() string { + return api.NETWORK_TYPE_VPC +} + +func (self *sMoutTarget) GetNetworkId() string { + return self.sfs.SubnetId +} + +func (self *sMoutTarget) GetVpcId() string { + return self.sfs.VpcId +} + +func (self *sMoutTarget) GetStatus() string { + return api.MOUNT_TARGET_STATUS_AVAILABLE +} + +func (self *sMoutTarget) Delete() error { + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/snapshot.go new file mode 100644 index 0000000000..c67e604792 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/snapshot.go @@ -0,0 +1,190 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +/* +限制: +https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html +1. 从快照创建云硬盘时,volume_type字段必须和快照源云硬盘保持一致。 +2. 当指定的云硬盘类型在avaliability_zone内不存在时,则创建云硬盘失败。 +*/ + +type SnapshotStatusType string + +const ( + SnapshotStatusCreating SnapshotStatusType = "creating" + SnapshotStatusAvailable SnapshotStatusType = "available" // 云硬盘快照创建成功,可以使用。 + SnapshotStatusError SnapshotStatusType = "error" // 云硬盘快照在创建过程中出现错误。 + SnapshotStatusDeleting SnapshotStatusType = "deleting" // 云硬盘快照处于正在删除的过程中。 + SnapshotStatusErrorDeleting SnapshotStatusType = "error_deleting" // 云硬盘快照在删除过程中出现错误 + SnapshotStatusRollbacking SnapshotStatusType = "rollbacking" // 云硬盘快照处于正在回滚数据的过程中。 + SnapshotStatusBackingUp SnapshotStatusType = "backing-up" // 通过快照创建备份,快照状态就会变为backing-up +) + +type Metadata struct { + SystemEnableActive string `json:"__system__enableActive"` // 如果为true。则表明是系统盘快照 +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html +type SSnapshot struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + + Metadata Metadata `json:"metadata"` + CreatedAt string `json:"created_at"` + Description string `json:"description"` + ID string `json:"id"` + Name string `json:"name"` + OSExtendedSnapshotAttributesProgress string `json:"os-extended-snapshot-attributes:progress"` + OSExtendedSnapshotAttributesProjectID string `json:"os-extended-snapshot-attributes:project_id"` + Size int32 `json:"size"` // GB + Status string `json:"status"` + UpdatedAt string `json:"updated_at"` + VolumeID string `json:"volume_id"` +} + +func (self *SSnapshot) GetId() string { + return self.ID +} + +func (self *SSnapshot) GetName() string { + return self.Name +} + +func (self *SSnapshot) GetGlobalId() string { + return self.ID +} + +func (self *SSnapshot) GetStatus() string { + switch SnapshotStatusType(self.Status) { + case SnapshotStatusAvailable: + return api.SNAPSHOT_READY + case SnapshotStatusCreating: + return api.SNAPSHOT_CREATING + case SnapshotStatusDeleting: + return api.SNAPSHOT_DELETING + case SnapshotStatusErrorDeleting, SnapshotStatusError: + return api.SNAPSHOT_FAILED + case SnapshotStatusRollbacking: + return api.SNAPSHOT_ROLLBACKING + default: + return api.SNAPSHOT_UNKNOWN + } +} + +func (self *SSnapshot) Refresh() error { + snapshot, err := self.region.GetSnapshotById(self.GetId()) + if err != nil { + return err + } + + if err := jsonutils.Update(self, snapshot); err != nil { + return err + } + + return nil +} + +func (self *SSnapshot) IsEmulated() bool { + return false +} + +func (self *SSnapshot) GetSizeMb() int32 { + return self.Size * 1024 +} + +func (self *SSnapshot) GetDiskId() string { + return self.VolumeID +} + +func (self *SSnapshot) GetDiskType() string { + if self.Metadata.SystemEnableActive == "true" { + return api.DISK_TYPE_SYS + } else { + return api.DISK_TYPE_DATA + } +} + +func (self *SSnapshot) Delete() error { + if self.region == nil { + return fmt.Errorf("not init region for snapshot %s", self.GetId()) + } + return self.region.DeleteSnapshot(self.GetId()) +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408627.html +func (self *SRegion) GetSnapshots(diskId string, snapshotName string) ([]SSnapshot, error) { + params := make(map[string]string) + + if len(diskId) > 0 { + params["volume_id"] = diskId + } + + if len(snapshotName) > 0 { + params["name"] = snapshotName + } + + snapshots := make([]SSnapshot, 0) + err := doListAllWithOffset(self.ecsClient.Snapshots.List, params, &snapshots) + for i := range snapshots { + snapshots[i].region = self + } + + return snapshots, err +} + +func (self *SRegion) GetSnapshotById(snapshotId string) (SSnapshot, error) { + var snapshot SSnapshot + err := DoGet(self.ecsClient.Snapshots.Get, snapshotId, nil, &snapshot) + snapshot.region = self + return snapshot, err +} + +// 不能删除以autobk_snapshot_为前缀的快照。 +// 当快照状态为available、error状态时,才可以删除。 +func (self *SRegion) DeleteSnapshot(snapshotId string) error { + return DoDelete(self.ecsClient.Snapshots.Delete, snapshotId, nil, nil) +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html +// 目前已设置force字段。云硬盘处于挂载状态时,能强制创建快照。 +func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { + params := jsonutils.NewDict() + snapshotObj := jsonutils.NewDict() + snapshotObj.Add(jsonutils.NewString(name), "name") + snapshotObj.Add(jsonutils.NewString(desc), "description") + snapshotObj.Add(jsonutils.NewString(diskId), "volume_id") + snapshotObj.Add(jsonutils.JSONTrue, "force") + params.Add(snapshotObj, "snapshot") + + snapshot := SSnapshot{} + err := DoCreate(self.ecsClient.Snapshots.Create, params, &snapshot) + return snapshot.ID, err +} + +func (self *SSnapshot) GetProjectId() string { + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/storage.go new file mode 100644 index 0000000000..6a6b60caae --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/storage.go @@ -0,0 +1,162 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SStorage struct { + zone *SZone + multicloud.SStorageBase + huawei.HuaweiTags + storageType string // volume_type 目前支持“SSD”,“SAS”和“SATA”三种 +} + +func (self *SStorage) GetId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetName() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetGlobalId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) Refresh() error { + return nil +} + +func (self *SStorage) IsEmulated() bool { + return true +} + +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, err := self.zone.region.GetDisks(self.zone.GetId()) + if err != nil { + return nil, err + } + + // 按storage type 过滤出disk + filtedDisks := make([]SDisk, 0) + for i := range disks { + disk := disks[i] + if disk.VolumeType == self.storageType { + filtedDisks = append(filtedDisks, disk) + } + } + + idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) + for i := 0; i < len(filtedDisks); i += 1 { + filtedDisks[i].storage = self + idisks[i] = &filtedDisks[i] + } + return idisks, nil +} + +func (self *SStorage) GetStorageType() string { + return self.storageType +} + +func (self *SStorage) GetMediumType() string { + if self.storageType == api.STORAGE_HUAWEI_SSD { + return api.DISK_TYPE_SSD + } else { + return api.DISK_TYPE_ROTATE + } +} + +func (self *SStorage) GetCapacityMB() int64 { + return 0 // unlimited +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + return conf +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + diskId, err := self.zone.region.CreateDisk(self.zone.GetId(), self.storageType, conf.Name, conf.SizeGb, "", conf.Desc, conf.ProjectId) + 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 + + err = cloudprovider.WaitStatus(disk, api.DISK_READY, 5*time.Second, 120*time.Second) + if err != nil { + return nil, err + } + + return disk, nil +} + +func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + if len(idStr) == 0 { + log.Debugf("GetIDiskById disk id should not be empty") + return nil, cloudprovider.ErrNotFound + } + + if disk, err := self.zone.region.GetDisk(idStr); err != nil { + return nil, err + } else { + disk.storage = self + return disk, nil + } +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/storagecache.go new file mode 100644 index 0000000000..c6c98e3540 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/storagecache.go @@ -0,0 +1,325 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "context" + "fmt" + "math" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +type SStoragecache struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + iimages []cloudprovider.ICloudImage +} + +func GetBucketName(regionId string, imageId string) string { + return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), imageId) +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) +} + +func (self *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) +} + +func (self *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, 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) fetchImages() error { + imagesGold, err := self.region.GetImages("", ImageOwnerPublic, "", EnvFusionCompute) + if err != nil { + return err + } + + imagesSelf, err := self.region.GetImages("", ImageOwnerSelf, "", EnvFusionCompute) + if err != nil { + return err + } + + self.iimages = make([]cloudprovider.ICloudImage, len(imagesGold)+len(imagesSelf)) + for i := range imagesGold { + imagesGold[i].storageCache = self + self.iimages[i] = &imagesGold[i] + } + + l := len(imagesGold) + for i := range imagesSelf { + imagesSelf[i].storageCache = self + self.iimages[i+l] = &imagesSelf[i] + } + return nil +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + if self.iimages == nil { + err := self.fetchImages() + if err != nil { + return nil, err + } + } + return self.iimages, nil +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + image, err := self.region.GetImage(extId) + if err != nil { + return nil, errors.Wrap(err, "self.region.GetImage") + } + image.storageCache = self + return image, nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +// 目前支持使用vhd、zvhd、vmdk、qcow2、raw、zvhd2、vhdx、qcow、vdi或qed格式镜像文件创建私有镜像。 +// 快速通道功能可快速完成镜像制作,但镜像文件需转换为raw或zvhd2格式并完成镜像优化。 +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0083905788.html +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 + 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) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return self.uploadImage(ctx, userCred, image, callback) +} + +func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + bucketName := GetBucketName(self.region.GetId(), image.ImageId) + + exist, _ := self.region.IBucketExist(bucketName) + if !exist { + err := self.region.CreateIBucket(bucketName, "", "") + if err != nil { + return "", errors.Wrap(err, "CreateIBucket") + } + } + defer self.region.DeleteIBucket(bucketName) + + // upload to huawei cloud + s := auth.GetAdminSession(ctx, options.Options.Region) + meta, reader, sizeByte, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) + if err != nil { + return "", errors.Wrap(err, "Images.Download") + } + log.Debugf("Images meta data %s", meta) + + minDiskMB, _ := meta.Int("min_disk") + minDiskGB := int64(math.Ceil(float64(minDiskMB) / 1024)) + // 在使用OBS桶的外部镜像文件制作镜像时生效且为必选字段。取值为40~1024GB。 + if minDiskGB < 40 { + minDiskGB = 40 + } else if minDiskGB > 1024 { + minDiskGB = 1024 + } + + bucket, err := self.region.GetIBucketByName(bucketName) + if err != nil { + return "", errors.Wrapf(err, "GetIBucketByName %s", bucketName) + } + + body := multicloud.NewProgress(sizeByte, 80, reader, callback) + err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeByte, "", "", nil, false) + if err != nil { + return "", errors.Wrap(err, "cloudprovider.UploadObject") + } + + defer bucket.DeleteObject(context.Background(), image.ImageId) + + // check image name, avoid name conflict + imageBaseName := image.ImageId + if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { + imageBaseName = fmt.Sprintf("img%s", image.ImageId) + } + imageName := imageBaseName + nameIdx := 1 + + for { + _, err = self.region.GetImageByName(imageName) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + break + } else { + return "", err + } + } + + imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) + nameIdx += 1 + log.Debugf("uploadImage Match remote name %s", imageName) + } + + jobId, err := self.region.ImportImageJob(imageName, image.OsDistribution, image.OsVersion, image.OsArch, bucketName, image.ImageId, int64(minDiskGB)) + + if err != nil { + log.Errorf("ImportImage error %s %s %s %s", jobId, image.ImageId, bucketName, err) + return "", err + } + + // timeout: 1hour = 3600 seconds + serviceType := self.region.ecsClient.Images.ServiceType() + err = self.region.waitTaskStatus(serviceType, jobId, TASK_SUCCESS, 15*time.Second, 3600*time.Second) + if err != nil { + log.Errorf("waitTaskStatus %s", err) + return "", err + } + + if callback != nil { + callback(100) + } + + // https://support.huaweicloud.com/api-ims/zh-cn_topic_0022473688.html + return self.region.GetTaskEntityID(serviceType, jobId, "image_id") +} + +func (self *SRegion) getStoragecache() *SStoragecache { + if self.storageCache == nil { + self.storageCache = &SStoragecache{region: self} + } + return self.storageCache +} + +type SJob struct { + Status string `json:"status"` + Entities map[string]string `json:"entities"` + JobID string `json:"job_id"` + JobType string `json:"job_type"` + BeginTime string `json:"begin_time"` + EndTime string `json:"end_time"` + ErrorCode string `json:"error_code"` + FailReason string `json:"fail_reason"` +} + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html +func (self *SRegion) createIImage(snapshotId, imageName, imageDesc string) (string, error) { + snapshot, err := self.GetSnapshotById(snapshotId) + if err != nil { + return "", err + } + + disk, err := self.GetDisk(snapshot.VolumeID) + if err != nil { + return "", err + } + + if disk.GetDiskType() != api.DISK_TYPE_SYS { + return "", fmt.Errorf("disk type err, expected disk type %s", api.DISK_TYPE_SYS) + } + + if len(disk.Attachments) == 0 { + return "", fmt.Errorf("disk is not attached.") + } + + imageObj := jsonutils.NewDict() + imageObj.Add(jsonutils.NewString(disk.Attachments[0].ServerID), "instance_id") + imageObj.Add(jsonutils.NewString(imageName), "name") + imageObj.Add(jsonutils.NewString(imageDesc), "description") + + ret, err := self.ecsClient.Images.PerformAction2("action", "", imageObj, "") + if err != nil { + return "", err + } + + job := SJob{} + jobId, err := ret.GetString("job_id") + querys := map[string]string{"service_type": self.ecsClient.Images.ServiceType()} + err = DoGet(self.ecsClient.Jobs.Get, jobId, querys, &job) + if err != nil { + return "", err + } + + if job.Status == "SUCCESS" { + imageId, exists := job.Entities["image_id"] + if exists { + return imageId, nil + } else { + return "", fmt.Errorf("image id not found in create image job %s", job.JobID) + } + } else { + return "", fmt.Errorf("create image failed, %s", job.FailReason) + } + +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + return []cloudprovider.ICloudStoragecache{storageCache}, nil +} + +func (self *SRegion) GetIStoragecacheById(idstr string) (cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + if storageCache.GetGlobalId() == idstr { + return storageCache, nil + } + return nil, cloudprovider.ErrNotFound +} diff --git a/pkg/multicloud/hcso/task.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/task.go similarity index 100% rename from pkg/multicloud/hcso/task.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/task.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/traces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/traces.go new file mode 100644 index 0000000000..c5cade4916 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/traces.go @@ -0,0 +1,131 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "strconv" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SUser struct { + Domain map[string]string + Name string + Id string +} + +type SEvent struct { + TraceId string + Code string + TraceName string + ResourceType string + ApiVersion string + SourceIp string + TraceType string + ServiceType string + EventType string + ProjectId string + Request string + Response string + TrackerName string + TraceStatus string + Time int64 + ResourceId string + ResourceName string + User SUser + RecordTime int64 +} + +func (event *SEvent) GetName() string { + if len(event.ResourceName) > 0 { + return event.ResourceName + } + if len(event.ResourceId) > 0 { + return event.ResourceId + } + return event.TraceName +} + +func (event *SEvent) GetService() string { + return event.ServiceType +} + +func (event *SEvent) GetAction() string { + return event.TraceName +} + +func (event *SEvent) GetResourceType() string { + return event.ResourceType +} + +func (event *SEvent) GetRequestId() string { + return event.TraceId +} + +func (event *SEvent) GetRequest() jsonutils.JSONObject { + return jsonutils.Marshal(event) +} + +func (event *SEvent) GetAccount() string { + return event.User.Name +} + +func (event *SEvent) IsSuccess() bool { + code, _ := strconv.Atoi(event.Code) + return code < 400 +} + +func (event *SEvent) GetCreatedAt() time.Time { + return time.Unix(event.Time/1000, event.Time%1000) +} + +func (self *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { + if !self.client.isMainProject { + return nil, cloudprovider.ErrNotSupported + } + events, err := self.GetEvents(start, end) + if err != nil { + return nil, err + } + iEvents := []cloudprovider.ICloudEvent{} + for i := range events { + iEvents = append(iEvents, &events[i]) + } + return iEvents, nil +} + +func (self *SRegion) GetEvents(start time.Time, end time.Time) ([]SEvent, error) { + events := []SEvent{} + params := map[string]string{} + if start.IsZero() { + start = time.Now().AddDate(0, 0, -7) + } + if end.IsZero() { + end = time.Now() + } + params["from"] = fmt.Sprintf("%d000", start.Unix()) + params["to"] = fmt.Sprintf("%d000", end.Unix()) + + err := doListAllWithMarker(self.ecsClient.Traces.List, params, &events) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithMarker") + } + return events, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/utils.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/utils.go new file mode 100644 index 0000000000..5174adcfe8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/utils.go @@ -0,0 +1,271 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "reflect" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + "yunion.io/x/onecloud/pkg/util/httputils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/hcso/client/responses" +) + +// 常用的方法 +type listFunc func(querys map[string]string) (*responses.ListResult, error) +type getFunc func(id string, querys map[string]string) (jsonutils.JSONObject, error) +type createFunc func(params jsonutils.JSONObject) (jsonutils.JSONObject, error) +type updateFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) +type updateFunc2 func(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) +type deleteFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) +type deleteFunc2 func(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) +type listInCtxFunc func(ctx manager.IManagerContext, querys map[string]string) (*responses.ListResult, error) +type listInCtxWithSpecFunc func(ctx manager.IManagerContext, spec string, querys map[string]string, responseKey string) (*responses.ListResult, error) + +func unmarshalResult(resp jsonutils.JSONObject, respErr error, result interface{}, method string) error { + if respErr != nil { + switch e := respErr.(type) { + case *httputils.JSONClientError: + if (e.Code == 404 || utils.IsInStringArray(e.Class, NOT_FOUND_CODES)) && method != "POST" { + return cloudprovider.ErrNotFound + } + return e + default: + return e + } + } + + if result == nil { + return nil + } + + err := resp.Unmarshal(result) + if err != nil { + log.Errorf("unmarshal json error %s", err) + } + + return err +} + +var pageLimit = 100 + +// offset 表示的是页码 +func doListAllWithPagerOffset(doList listFunc, queries map[string]string, result interface{}) error { + startIndex := 0 + resultValue := reflect.Indirect(reflect.ValueOf(result)) + queries["limit"] = fmt.Sprintf("%d", pageLimit) + queries["offset"] = fmt.Sprintf("%d", startIndex) + for { + total, part, err := doListPart(doList, queries, result) + if err != nil { + return err + } + if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { + break + } + + startIndex++ + queries["offset"] = fmt.Sprintf("%d", startIndex) + } + return nil +} + +func doListAllWithNextLink(doList listFunc, querys map[string]string, result interface{}) error { + values := []jsonutils.JSONObject{} + for { + ret, err := doList(querys) + if err != nil { + return errors.Wrap(err, "doList") + } + values = append(values, ret.Data...) + if len(ret.NextLink) == 0 || ret.NextLink == "null" { + break + } + } + if result != nil { + return jsonutils.Update(result, values) + } + return nil +} + +func doListAllWithOffset(doList listFunc, queries map[string]string, result interface{}) error { + startIndex := 0 + resultValue := reflect.Indirect(reflect.ValueOf(result)) + queries["limit"] = fmt.Sprintf("%d", pageLimit) + queries["offset"] = fmt.Sprintf("%d", startIndex) + for { + total, part, err := doListPart(doList, queries, result) + if err != nil { + return err + } + if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { + break + } + queries["offset"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) + } + return nil +} + +func doListAllWithPage(doList listFunc, queries map[string]string, result interface{}) error { + startIndex := 1 + resultValue := reflect.Indirect(reflect.ValueOf(result)) + queries["limit"] = fmt.Sprintf("%d", pageLimit) + queries["page"] = fmt.Sprintf("%d", startIndex) + for { + total, part, err := doListPart(doList, queries, result) + if err != nil { + return err + } + if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { + break + } + queries["page"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) + } + return nil +} + +func doListAllWithMarker(doList listFunc, queries map[string]string, result interface{}) error { + resultValue := reflect.Indirect(reflect.ValueOf(result)) + queries["limit"] = fmt.Sprintf("%d", pageLimit) + for { + total, part, err := doListPart(doList, queries, result) + if err != nil { + return err + } + if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { + break + } + lastValue := resultValue.Index(resultValue.Len() - 1) + markerValue := lastValue.FieldByNameFunc(func(key string) bool { + if strings.ToLower(key) == "id" { + return true + } + return false + }) + queries["marker"] = markerValue.String() + } + return nil +} + +func doListAll(doList listFunc, queries map[string]string, result interface{}) error { + total, _, err := doListPart(doList, queries, result) + if err != nil { + return err + } + resultValue := reflect.Indirect(reflect.ValueOf(result)) + if total > 0 && resultValue.Len() < total { + log.Warningf("INCOMPLETE QUERY, total %d queried %d", total, resultValue.Len()) + } + return nil +} + +func doListPart(doList listFunc, queries map[string]string, result interface{}) (int, int, error) { + ret, err := doList(queries) + if err != nil { + return 0, 0, err + } + resultValue := reflect.Indirect(reflect.ValueOf(result)) + elemType := resultValue.Type().Elem() + for i := range ret.Data { + elemPtr := reflect.New(elemType) + err = ret.Data[i].Unmarshal(elemPtr.Interface()) + if err != nil { + return 0, 0, err + } + resultValue.Set(reflect.Append(resultValue, elemPtr.Elem())) + } + return ret.Total, len(ret.Data), nil +} + +func DoGet(doGet getFunc, id string, queries map[string]string, result interface{}) error { + if len(id) == 0 { + resultType := reflect.Indirect(reflect.ValueOf(result)).Type() + return errors.Wrap(cloudprovider.ErrNotFound, fmt.Sprintf(" Get %s id should not be empty", resultType.Name())) + } + + ret, err := doGet(id, queries) + return unmarshalResult(ret, err, result, "GET") +} + +func DoListInContext(listFunc listInCtxFunc, ctx manager.IManagerContext, querys map[string]string, result interface{}) error { + ret, err := listFunc(ctx, querys) + if err != nil { + return err + } + + obj := responses.ListResult2JSON(ret) + err = obj.Unmarshal(result, "data") + if err != nil { + log.Errorf("unmarshal json error %s", err) + return err + } + + return nil +} + +func DoCreate(createFunc createFunc, params jsonutils.JSONObject, result interface{}) error { + ret, err := createFunc(params) + return unmarshalResult(ret, err, result, "POST") +} + +func DoUpdate(updateFunc updateFunc, id string, params jsonutils.JSONObject, result interface{}) error { + ret, err := updateFunc(id, params) + return unmarshalResult(ret, err, result, "PUT") +} + +func DoUpdateWithSpec(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject) error { + _, err := updateFunc(nil, id, spec, params, "") + return err +} + +func DoUpdateWithSpec2(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject, result interface{}) error { + ret, err := updateFunc(nil, id, spec, params, "") + return unmarshalResult(ret, err, result, "PUT") +} + +func DoDelete(deleteFunc deleteFunc, id string, params jsonutils.JSONObject, result interface{}) error { + if len(id) == 0 { + return fmt.Errorf(" id should not be empty") + } + + ret, err := deleteFunc(id, params) + return unmarshalResult(ret, err, result, "DELETE") +} + +func DoDeleteWithSpec(deleteFunc deleteFunc2, ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject) error { + if len(id) == 0 { + return fmt.Errorf(" id should not be empty") + } + + _, err := deleteFunc(ctx, id, spec, queries, params, "") + return err +} + +func ErrMessage(err error) string { + switch v := err.(type) { + case *httputils.JSONClientError: + return fmt.Sprintf("%d(%s):%s", v.Code, v.Class, v.Details) + default: + return err.Error() + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/vpc.go new file mode 100644 index 0000000000..4ec7a158c4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/vpc.go @@ -0,0 +1,369 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html +type SVpc struct { + multicloud.SVpc + huawei.HuaweiTags + + region *SRegion + + iwires []cloudprovider.ICloudWire + secgroups []cloudprovider.ICloudSecurityGroup + routeTables []cloudprovider.ICloudRouteTable + + ID string `json:"id"` + Name string `json:"name"` + CIDR string `json:"cidr"` + Status string `json:"status"` + EnterpriseProjectID string `json:"enterprise_project_id"` +} + +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) getWireByRegionId(regionId string) *SWire { + if len(regionId) == 0 { + return nil + } + + for i := 0; i < len(self.iwires); i++ { + wire := self.iwires[i].(*SWire) + + if wire.region.GetId() == regionId { + return wire + } + } + + return nil +} + +func (self *SVpc) fetchNetworks() error { + networks, err := self.region.GetNetwroks(self.ID) + if err != nil { + return err + } + + // ??????? + if len(networks) == 0 { + self.iwires = append(self.iwires, &SWire{region: self.region, vpc: self}) + return nil + } + + for i := 0; i < len(networks); i += 1 { + wire := self.getWireByRegionId(self.region.GetId()) + networks[i].wire = wire + wire.addNetwork(&networks[i]) + } + return nil +} + +// 华为云安全组可以被同region的VPC使用 +func (self *SVpc) fetchSecurityGroups() error { + secgroups, err := self.region.GetSecurityGroups("", "") + if err != nil { + return err + } + + self.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) + for i := 0; i < len(secgroups); i++ { + self.secgroups[i] = &secgroups[i] + } + return nil +} + +func (self *SVpc) GetId() string { + return self.ID +} + +func (self *SVpc) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.ID +} + +func (self *SVpc) GetGlobalId() string { + return self.ID +} + +func (self *SVpc) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} + +func (self *SVpc) Refresh() error { + new, err := self.region.getVpc(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SVpc) IsEmulated() bool { + return false +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetIsDefault() bool { + // 华为云没有default vpc. + return false +} + +func (self *SVpc) GetCidrBlock() string { + return self.CIDR +} + +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) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + if self.routeTables == nil { + routeTables, err := self.getRouteTables() + if err != nil { + return nil, errors.Wrap(err, "get route table error") + } + defaultRouteTable := NewSRouteTable(self, string(cloudprovider.RouteTableTypeSystem)) + for i := range routeTables { + defaultRouteTable.Routes = append(defaultRouteTable.Routes, routeTables[i].Routes...) + } + self.routeTables = []cloudprovider.ICloudRouteTable{&defaultRouteTable} + } + return self.routeTables, nil +} + +// 华为云 路由表资源方法 api 暂未支持,只能直接对vpc对象增加,删除 路由 +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + routeTables, err := self.getRouteTables() + if err != nil { + return nil, errors.Wrap(err, "get route table error") + } + defaultRouteTable := NewSRouteTable(self, string(cloudprovider.RouteTableTypeSystem)) + for i := range routeTables { + defaultRouteTable.Routes = append(defaultRouteTable.Routes, routeTables[i].Routes...) + } + return &defaultRouteTable, nil +} + +func (self *SVpc) Delete() error { + // todo: 确定删除VPC的逻辑 + return self.region.DeleteVpc(self.GetId()) +} + +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) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { + nats, err := self.region.GetNatGateways(self.GetId(), "") + if err != nil { + return nil, err + } + ret := make([]cloudprovider.ICloudNatGateway, len(nats)) + for i := 0; i < len(nats); i++ { + ret[i] = &nats[i] + } + return ret, nil +} + +func (self *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPCs, err := self.getVpcPeeringConnections() + if err != nil { + return nil, errors.Wrap(err, "self.getVpcPeeringConnections()") + } + ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} + for i := range svpcPCs { + ivpcPCs = append(ivpcPCs, &svpcPCs[i]) + } + return ivpcPCs, nil +} + +func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPCs, err := self.getAccepterVpcPeeringConnections() + if err != nil { + return nil, errors.Wrap(err, "self.getAccepterVpcPeeringConnections()") + } + ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} + for i := range svpcPCs { + ivpcPCs = append(ivpcPCs, &svpcPCs[i]) + } + return ivpcPCs, nil +} + +func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPC, err := self.getVpcPeeringConnectionById(id) + if err != nil { + return nil, errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) + } + return svpcPC, nil +} + +func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPC, err := self.region.CreateVpcPeering(self.GetId(), opts) + if err != nil { + return nil, errors.Wrapf(err, "self.region.CreateVpcPeering(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) + } + svpcPC.vpc = self + return svpcPC, nil +} +func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { + vpcPC, err := self.getVpcPeeringConnectionById(id) + if err != nil { + return errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) + } + if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_ACTIVE { + return nil + } + if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN { + return errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcPC: %s", jsonutils.Marshal(vpcPC).String()) + } + err = self.region.AcceptVpcPeering(id) + if err != nil { + return errors.Wrapf(err, "self.region.AcceptVpcPeering(%s)", id) + } + return nil +} + +func (self *SVpc) GetAuthorityOwnerId() string { + return self.region.client.projectId +} + +func (self *SVpc) getVpcPeeringConnections() ([]SVpcPeering, error) { + svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) + } + vpcPCs := []SVpcPeering{} + for i := range svpcPeerings { + if svpcPeerings[i].GetVpcId() == self.GetId() { + svpcPeerings[i].vpc = self + vpcPCs = append(vpcPCs, svpcPeerings[i]) + } + } + return vpcPCs, nil +} + +func (self *SVpc) getAccepterVpcPeeringConnections() ([]SVpcPeering, error) { + svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) + } + vpcPCs := []SVpcPeering{} + for i := range svpcPeerings { + if svpcPeerings[i].GetPeerVpcId() == self.GetId() { + svpcPeerings[i].vpc = self + vpcPCs = append(vpcPCs, svpcPeerings[i]) + } + } + return vpcPCs, nil +} + +func (self *SVpc) getVpcPeeringConnectionById(id string) (*SVpcPeering, error) { + svpcPC, err := self.region.GetVpcPeering(id) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetVpcPeering(%s)", id) + } + svpcPC.vpc = self + return svpcPC, nil +} + +func (self *SRegion) getVpc(vpcId string) (*SVpc, error) { + vpc := SVpc{} + err := DoGet(self.ecsClient.Vpcs.Get, vpcId, nil, &vpc) + if err != nil && strings.Contains(err.Error(), "RouterNotFound") { + return nil, cloudprovider.ErrNotFound + } + vpc.region = self + return &vpc, err +} + +func (self *SRegion) DeleteVpc(vpcId string) error { + if vpcId != "default" { + secgroups, err := self.GetSecurityGroups(vpcId, "") + if err != nil { + return errors.Wrap(err, "GetSecurityGroups") + } + for _, secgroup := range secgroups { + err = self.DeleteSecurityGroup(secgroup.ID) + if err != nil { + return errors.Wrapf(err, "DeleteSecurityGroup(%s)", secgroup.ID) + } + } + } + return DoDelete(self.ecsClient.Vpcs.Delete, vpcId, nil, nil) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html +func (self *SRegion) GetVpcs() ([]SVpc, error) { + querys := make(map[string]string) + + vpcs := make([]SVpc, 0) + err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs) + if err != nil { + return nil, err + } + + for i := range vpcs { + vpcs[i].region = self + } + return vpcs, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/vpc_peering.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/vpc_peering.go new file mode 100644 index 0000000000..649f18cf93 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/vpc_peering.go @@ -0,0 +1,160 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type RequestVpcInfo struct { + VpcID string `json:"vpc_id"` + TenantID string `json:"tenant_id"` +} +type AcceptVpcInfo struct { + VpcID string `json:"vpc_id"` + TenantID string `json:"tenant_id"` +} +type SVpcPeering struct { + multicloud.SResourceBase + huawei.HuaweiTags + vpc *SVpc + + RequestVpcInfo RequestVpcInfo `json:"request_vpc_info"` + AcceptVpcInfo AcceptVpcInfo `json:"accept_vpc_info"` + Name string `json:"name"` + ID string `json:"id"` + Status string `json:"status"` +} + +func (self *SRegion) GetVpcPeerings(vpcId string) ([]SVpcPeering, error) { + querys := make(map[string]string) + querys["vpc_id"] = vpcId + vpcPeerings := make([]SVpcPeering, 0) + err := doListAllWithMarker(self.ecsClient.VpcPeerings.List, querys, &vpcPeerings) + if err != nil { + return nil, errors.Wrapf(err, "oListAllWithMarker(self.ecsClient.VpcPeerings.List, %s, &vpcPeerings)", jsonutils.Marshal(querys).String()) + } + return vpcPeerings, nil +} + +func (self *SRegion) GetVpcPeering(vpcPeeringId string) (*SVpcPeering, error) { + if len(vpcPeeringId) == 0 { + return nil, cloudprovider.ErrNotFound + } + vpcPeering := SVpcPeering{} + err := DoGet(self.ecsClient.VpcPeerings.Get, vpcPeeringId, nil, &vpcPeering) + if err != nil { + return nil, errors.Wrapf(err, "DoGet(self.ecsClient.VpcPeerings.Get, %s, nil, &vpcPeering)", vpcPeeringId) + } + return &vpcPeering, nil +} + +func (self *SRegion) CreateVpcPeering(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPeering, error) { + params := jsonutils.NewDict() + vpcPeeringObj := jsonutils.NewDict() + requestVpcObj := jsonutils.NewDict() + acceptVpcObj := jsonutils.NewDict() + vpcPeeringObj.Set("name", jsonutils.NewString(opts.Name)) + requestVpcObj.Set("vpc_id", jsonutils.NewString(vpcId)) + requestVpcObj.Set("tenant_id", jsonutils.NewString(self.client.projectId)) + vpcPeeringObj.Set("request_vpc_info", requestVpcObj) + acceptVpcObj.Set("vpc_id", jsonutils.NewString(opts.PeerVpcId)) + acceptVpcObj.Set("tenant_id", jsonutils.NewString(opts.PeerAccountId)) + vpcPeeringObj.Set("accept_vpc_info", acceptVpcObj) + params.Set("peering", vpcPeeringObj) + ret := SVpcPeering{} + err := DoCreate(self.ecsClient.VpcPeerings.Create, params, &ret) + if err != nil { + return nil, errors.Wrapf(err, "DoCreate(self.ecsClient.VpcPeerings.Create, %s, &ret)", jsonutils.Marshal(params).String()) + } + return &ret, nil +} + +func (self *SRegion) AcceptVpcPeering(vpcPeeringId string) error { + err := DoUpdateWithSpec(self.ecsClient.VpcPeerings.UpdateInContextWithSpec, vpcPeeringId, "accept", nil) + if err != nil { + return errors.Wrapf(err, "DoUpdateWithSpec(self.ecsClient.VpcPeerings.UpdateInContextWithSpec, %s, accept, nil)", vpcPeeringId) + } + return nil +} + +func (self *SRegion) DeleteVpcPeering(vpcPeeringId string) error { + err := DoDelete(self.ecsClient.VpcPeerings.Delete, vpcPeeringId, nil, nil) + if err != nil { + return errors.Wrapf(err, "DoDelete(self.ecsClient.VpcPeerings.Delete,%s,nil)", vpcPeeringId) + } + return nil +} + +func (self *SVpcPeering) GetId() string { + return self.ID +} + +func (self *SVpcPeering) GetName() string { + return self.Name +} + +func (self *SVpcPeering) GetGlobalId() string { + return self.GetId() +} + +func (self *SVpcPeering) GetStatus() string { + switch self.Status { + case "PENDING_ACCEPTANCE": + return api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT + case "ACTIVE": + return api.VPC_PEERING_CONNECTION_STATUS_ACTIVE + default: + return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN + } +} + +func (self *SVpcPeering) Refresh() error { + peer, err := self.vpc.region.GetVpcPeering(self.ID) + if err != nil { + return errors.Wrapf(err, "self.region.GetVpcPeering(%s)", self.ID) + } + return jsonutils.Update(self, peer) +} + +func (self *SVpcPeering) GetVpcId() string { + return self.RequestVpcInfo.VpcID +} + +func (self *SVpcPeering) GetPeerVpcId() string { + return self.AcceptVpcInfo.VpcID +} + +func (self *SVpcPeering) GetPeerAccountId() string { + return self.AcceptVpcInfo.TenantID +} + +func (self *SVpcPeering) GetEnabled() bool { + return true +} + +func (self *SVpcPeering) Delete() error { + err := self.vpc.region.DeleteVpcPeering(self.ID) + if err != nil { + return errors.Wrapf(err, "self.region.DeleteVpcPeering(%s)", self.ID) + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/wire.go new file mode 100644 index 0000000000..09ebd8c983 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/wire.go @@ -0,0 +1,207 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +// 华为云的子网有点特殊。子网在整个region可用。 +type SWire struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + vpc *SVpc + + inetworks []cloudprovider.ICloudNetwork +} + +func (self *SWire) GetId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) +} + +func (self *SWire) GetName() string { + return self.GetId() +} + +func (self *SWire) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SWire) Refresh() error { + return nil +} + +func (self *SWire) IsEmulated() bool { + return true +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return nil +} + +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 +} + +/* +华为云子网可用区,类似一个zone标签。即使指定了zone子网在整个region依然是可用。 +通过华为web控制台创建子网需要指定可用区。这里是不指定的。 +*/ +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + networkId, err := self.region.createNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc) + if err != nil { + log.Errorf("createNetwork error %s", err) + return nil, err + } + + var network *SNetwork + err = cloudprovider.WaitCreated(5*time.Second, 60*time.Second, func() bool { + self.inetworks = nil + network = self.getNetworkById(networkId) + if network == nil { + return false + } else { + return true + } + }) + + if err != nil { + log.Errorf("cannot find network after create????") + return nil, err + } + + network.wire = self + return network, 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.ID { + find = true + break + } + } + if !find { + self.inetworks = append(self.inetworks, network) + } +} + +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 getDefaultGateWay(cidr string) (string, error) { + pref, err := netutils.NewIPV4Prefix(cidr) + if err != nil { + return "", errors.Wrap(err, "getDefaultGateWay.NewIPV4Prefix") + } + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String(), nil +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html +// cidr 掩码长度不能大于28 +func (self *SRegion) createNetwork(vpcId string, name string, cidr string, desc string) (string, error) { + gateway, err := getDefaultGateWay(cidr) + if err != nil { + return "", err + } + + params := jsonutils.NewDict() + subnetObj := jsonutils.NewDict() + subnetObj.Add(jsonutils.NewString(name), "name") + subnetObj.Add(jsonutils.NewString(vpcId), "vpc_id") + subnetObj.Add(jsonutils.NewString(cidr), "cidr") + subnetObj.Add(jsonutils.NewString(gateway), "gateway_ip") + // hard code for hcso + // https://support.huaweicloud.com/dns_faq/dns_faq_002.html + // https://support.huaweicloud.com/api-dns/dns_api_69001.html + if self.client != nil && len(self.client.endpoints.DefaultSubnetDns) > 0 { + dns := strings.Split(self.client.endpoints.DefaultSubnetDns, ",") + if len(dns) > 0 && len(dns[0]) > 0 { + subnetObj.Add(jsonutils.NewString(dns[0]), "primary_dns") + } + + if len(dns) > 1 && len(dns[1]) > 0 { + subnetObj.Add(jsonutils.NewString(dns[1]), "secondary_dns") + } + } + params.Add(subnetObj, "subnet") + + subnet := SNetwork{} + err = DoCreate(self.ecsClient.Subnets.Create, params, &subnet) + return subnet.ID, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/zone.go new file mode 100644 index 0000000000..7d64502aa5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/hcso/zone.go @@ -0,0 +1,263 @@ +// Copyright 2019 Yunion +// +// 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 hcso + +import ( + "fmt" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +var StorageTypes = []string{ + api.STORAGE_HUAWEI_SAS, + api.STORAGE_HUAWEI_SATA, + api.STORAGE_HUAWEI_SSD, +} + +type ZoneState struct { + Available bool `json:"available"` +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817728.html +type SZone struct { + multicloud.SResourceBase + huawei.HuaweiTags + region *SRegion + ihosts []cloudprovider.ICloudHost + + iwires []cloudprovider.ICloudWire + istorages []cloudprovider.ICloudStorage + + ZoneState ZoneState `json:"zoneState"` + ZoneName string `json:"zoneName"` + + /* 支持的磁盘种类集合 */ + 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) getStorageType() { + if len(self.storageTypes) == 0 { + if sts, err := self.region.GetZoneSupportedDiskTypes(self.GetId()); err == nil { + self.storageTypes = sts + } else { + log.Errorf("GetZoneSupportedDiskTypes %s %s", self.GetId(), err) + 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 +} + +// 华为私有云没有直接列出host的接口,所有账号下的host都是通过VM反向解析出来的 +// 当账号下没有虚拟机时,如果没有host,会导致调度找不到可用的HOST。 +// 因此,为了避免上述情况始终会在每个zone下返回一台虚拟的host +func (self *SZone) getEmulatedHost() SHost { + return SHost{ + zone: self, + vms: nil, + IsFake: true, + projectId: self.region.client.projectId, + Id: fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.GetId()), + Name: fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.GetId()), + } +} + +func (self *SZone) getHosts() ([]cloudprovider.ICloudHost, error) { + if self.ihosts != nil { + return self.ihosts, nil + } + + vms, err := self.region.GetInstances() + if err != nil { + return nil, errors.Wrap(err, "GetInstances") + } + + hosts := map[string]string{} + hostVms := map[string][]SInstance{} + for i := range vms { + vm := vms[i] + if vm.OSEXTAZAvailabilityZone == self.GetId() { + hosts[vm.HostID] = vm.OSEXTSRVATTRHost + if _, ok := hostVms[vm.HostID]; ok { + hostVms[vm.HostID] = append(hostVms[vm.HostID], vm) + } else { + hostVms[vm.HostID] = []SInstance{vm} + } + } + } + + fakeHost := self.getEmulatedHost() + ihosts := []cloudprovider.ICloudHost{&fakeHost} + for k, _ := range hosts { + h := SHost{ + zone: self, + projectId: self.region.client.projectId, + Id: k, + Name: hosts[k], + } + for i := range hostVms[k] { + hostVms[k][i].host = &h + } + + h.vms = hostVms[k] + ihosts = append(ihosts, &h) + } + + return ihosts, nil +} + +func (self *SZone) GetId() string { + return self.ZoneName +} + +func (self *SZone) GetName() string { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.ZoneName) +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.ZoneName) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneName) +} + +func (self *SZone) GetStatus() string { + return "enable" +} + +func (self *SZone) Refresh() error { + return nil +} + +func (self *SZone) IsEmulated() bool { + return false +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + return self.getHosts() +} + +func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + ihosts, err := self.getHosts() + if err != nil { + return nil, errors.Wrap(err, "getHosts") + } + + for i := range ihosts { + if ihosts[i].GetGlobalId() == id { + return ihosts[i], nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "fetchStorages") + } + } + return self.istorages, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "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) GetIWires() ([]cloudprovider.ICloudWire, error) { + return self.iwires, nil +} + +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.GetId() == id { + return zone, nil + } + } + return nil, fmt.Errorf("no such zone %s", id) +} + +func (self *SZone) getNetworkById(networkId string) *SNetwork { + for i := 0; i < len(self.iwires); i += 1 { + wire := self.iwires[i].(*SWire) + net := wire.getNetworkById(networkId) + if net != nil { + return net + } + } + return nil +} diff --git a/pkg/multicloud/host_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/host_base.go similarity index 100% rename from pkg/multicloud/host_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/host_base.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/bucket.go new file mode 100644 index 0000000000..b56868f17b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/bucket.go @@ -0,0 +1,766 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + "yunion.io/x/s3cli" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" +) + +type SBucket struct { + multicloud.SBaseBucket + HuaweiTags + + region *SRegion + + Name string + Location string + CreationDate time.Time +} + +func (b *SBucket) GetProjectId() string { + resp, err := b.region.HeadBucket(b.Name) + if err != nil { + return "" + } + epid, _ := resp.ResponseHeaders["epid"] + if len(epid) > 0 { + return epid[0] + } + return "" +} + +func (b *SBucket) GetGlobalId() string { + return b.Name +} + +func (b *SBucket) GetName() string { + return b.Name +} + +func (b *SBucket) GetLocation() string { + return b.Location +} + +func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { + return b.region +} + +func (b *SBucket) GetCreatedAt() time.Time { + return b.CreationDate +} + +func (b *SBucket) GetStorageClass() string { + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("b.region.getOBSClient error %s", err) + return "" + } + output, err := obscli.GetBucketStoragePolicy(b.Name) + if err != nil { + log.Errorf("obscli.GetBucketStoragePolicy error %s", err) + return "" + } + return output.StorageClass +} + +func obsAcl2CannedAcl(acls []obs.Grant) cloudprovider.TBucketACLType { + switch { + case len(acls) == 1: + if acls[0].Grantee.URI == "" && acls[0].Permission == s3cli.PERMISSION_FULL_CONTROL { + return cloudprovider.ACLPrivate + } + case len(acls) == 2: + for _, g := range acls { + if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_AUTH_USERS && g.Permission == s3cli.PERMISSION_READ { + return cloudprovider.ACLAuthRead + } + if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_READ { + return cloudprovider.ACLPublicRead + } + } + case len(acls) == 3: + for _, g := range acls { + if g.Grantee.URI == s3cli.GRANTEE_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_WRITE { + return cloudprovider.ACLPublicReadWrite + } + } + } + return cloudprovider.ACLUnknown +} + +func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("b.region.getOBSClient error %s", err) + return acl + } + output, err := obscli.GetBucketAcl(b.Name) + if err != nil { + log.Errorf("obscli.GetBucketAcl error %s", err) + return acl + } + acl = obsAcl2CannedAcl(output.Grants) + return acl +} + +func (b *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "b.region.getOBSClient") + } + input := &obs.SetBucketAclInput{} + input.Bucket = b.Name + input.ACL = obs.AclType(string(acl)) + _, err = obscli.SetBucketAcl(input) + if err != nil { + return errors.Wrap(err, "obscli.SetBucketAcl") + } + return nil +} + +func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { + return []cloudprovider.SBucketAccessUrl{ + { + Url: fmt.Sprintf("https://%s.%s", b.Name, b.region.getOBSEndpoint()), + Description: "bucket url", + Primary: true, + }, + { + Url: fmt.Sprintf("https://%s/%s", b.region.getOBSEndpoint(), b.Name), + Description: "obs url", + }, + } +} + +func (b *SBucket) GetStats() cloudprovider.SBucketStats { + stats := cloudprovider.SBucketStats{} + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("b.region.getOBSClient error %s", err) + stats.SizeBytes = -1 + stats.ObjectCount = -1 + return stats + } + output, err := obscli.GetBucketStorageInfo(b.Name) + if err != nil { + log.Errorf("obscli.GetBucketStorageInfo error %s", err) + stats.SizeBytes = -1 + stats.ObjectCount = -1 + return stats + } + stats.SizeBytes = output.Size + stats.ObjectCount = output.ObjectNumber + return stats +} + +func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { + result := cloudprovider.SListObjectResult{} + obscli, err := b.region.getOBSClient() + if err != nil { + return result, errors.Wrap(err, "GetOBSClient") + } + input := &obs.ListObjectsInput{} + input.Bucket = b.Name + if len(prefix) > 0 { + input.Prefix = prefix + } + if len(marker) > 0 { + input.Marker = marker + } + if len(delimiter) > 0 { + input.Delimiter = delimiter + } + if maxCount > 0 { + input.MaxKeys = maxCount + } + oResult, err := obscli.ListObjects(input) + if err != nil { + return result, errors.Wrap(err, "ListObjects") + } + result.Objects = make([]cloudprovider.ICloudObject, 0) + for _, object := range oResult.Contents { + obj := &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + StorageClass: string(object.StorageClass), + Key: object.Key, + SizeBytes: object.Size, + ETag: object.ETag, + LastModified: object.LastModified, + }, + } + result.Objects = append(result.Objects, obj) + } + if oResult.CommonPrefixes != nil { + result.CommonPrefixes = make([]cloudprovider.ICloudObject, 0) + for _, commonPrefix := range oResult.CommonPrefixes { + obj := &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + Key: commonPrefix, + }, + } + result.CommonPrefixes = append(result.CommonPrefixes, obj) + } + } + result.IsTruncated = oResult.IsTruncated + result.NextMarker = oResult.NextMarker + return result, nil +} + +func (b *SBucket) PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.PutObjectInput{} + input.Bucket = b.Name + input.Key = key + input.Body = reader + + if sizeBytes > 0 { + input.ContentLength = sizeBytes + } + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return err + } + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.ACL = obs.AclType(string(cannedAcl)) + if meta != nil { + val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) + if len(val) > 0 { + input.ContentType = val + } + val = meta.Get(cloudprovider.META_HEADER_CONTENT_MD5) + if len(val) > 0 { + input.ContentMD5 = val + } + extraMeta := make(map[string]string) + for k, v := range meta { + if utils.IsInStringArray(k, []string{ + cloudprovider.META_HEADER_CONTENT_TYPE, + cloudprovider.META_HEADER_CONTENT_MD5, + }) { + continue + } + if len(v[0]) > 0 { + extraMeta[k] = v[0] + } + } + input.Metadata = extraMeta + } + _, err = obscli.PutObject(input) + if err != nil { + return errors.Wrap(err, "PutObject") + } + return nil +} + +func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + + input := &obs.InitiateMultipartUploadInput{} + input.Bucket = b.Name + input.Key = key + if meta != nil { + val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) + if len(val) > 0 { + input.ContentType = val + } + extraMeta := make(map[string]string) + for k, v := range meta { + if utils.IsInStringArray(k, []string{ + cloudprovider.META_HEADER_CONTENT_TYPE, + }) { + continue + } + if len(v[0]) > 0 { + extraMeta[k] = v[0] + } + } + input.Metadata = extraMeta + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.ACL = obs.AclType(string(cannedAcl)) + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return "", errors.Wrap(err, "str2StorageClass") + } + } + output, err := obscli.InitiateMultipartUpload(input) + if err != nil { + return "", errors.Wrap(err, "InitiateMultipartUpload") + } + + return output.UploadId, nil +} + +func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, part io.Reader, partSize int64, offset, totalSize int64) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + + input := &obs.UploadPartInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + input.PartNumber = partIndex + input.PartSize = partSize + input.Body = part + output, err := obscli.UploadPart(input) + if err != nil { + return "", errors.Wrap(err, "UploadPart") + } + + return output.ETag, nil +} + +func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.CompleteMultipartUploadInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + parts := make([]obs.Part, len(partEtags)) + for i := range partEtags { + parts[i] = obs.Part{ + PartNumber: i + 1, + ETag: partEtags[i], + } + } + input.Parts = parts + _, err = obscli.CompleteMultipartUpload(input) + if err != nil { + return errors.Wrap(err, "CompleteMultipartUpload") + } + + return nil +} + +func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + input := &obs.AbortMultipartUploadInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + + _, err = obscli.AbortMultipartUpload(input) + if err != nil { + return errors.Wrap(err, "AbortMultipartUpload") + } + + return nil +} + +func (b *SBucket) DeleteObject(ctx context.Context, key string) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.DeleteObjectInput{} + input.Bucket = b.Name + input.Key = key + _, err = obscli.DeleteObject(input) + if err != nil { + return errors.Wrap(err, "DeleteObject") + } + return nil +} + +func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + input := obs.CreateSignedUrlInput{} + input.Bucket = b.Name + input.Key = key + input.Expires = int(expire / time.Second) + switch method { + case "GET": + input.Method = obs.HttpMethodGet + case "PUT": + input.Method = obs.HttpMethodPut + case "DELETE": + input.Method = obs.HttpMethodDelete + default: + return "", errors.Error("unsupported method") + } + output, err := obscli.CreateSignedUrl(&input) + return output.SignedUrl, nil +} + +func (b *SBucket) LimitSupport() cloudprovider.SBucketStats { + return cloudprovider.SBucketStats{ + SizeBytes: 1, + ObjectCount: -1, + } +} + +func (b *SBucket) GetLimit() cloudprovider.SBucketStats { + stats := cloudprovider.SBucketStats{} + obscli, err := b.region.getOBSClient() + if err != nil { + log.Errorf("getOBSClient error %s", err) + return stats + } + output, err := obscli.GetBucketQuota(b.Name) + if err != nil { + return stats + } + stats.SizeBytes = output.Quota + return stats +} + +func (b *SBucket) SetLimit(limit cloudprovider.SBucketStats) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "getOBSClient") + } + input := &obs.SetBucketQuotaInput{} + input.Bucket = b.Name + input.Quota = limit.SizeBytes + _, err = obscli.SetBucketQuota(input) + if err != nil { + return errors.Wrap(err, "SetBucketQuota") + } + return nil +} + +func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + input := &obs.CopyObjectInput{} + input.Bucket = b.Name + input.Key = destKey + input.CopySourceBucket = srcBucket + input.CopySourceKey = srcKey + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return err + } + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + input.ACL = obs.AclType(string(cannedAcl)) + if meta != nil { + val := meta.Get(cloudprovider.META_HEADER_CONTENT_TYPE) + if len(val) > 0 { + input.ContentType = val + } + extraMeta := make(map[string]string) + for k, v := range meta { + if utils.IsInStringArray(k, []string{ + cloudprovider.META_HEADER_CONTENT_TYPE, + }) { + continue + } + if len(v[0]) > 0 { + extraMeta[k] = v[0] + } + } + input.Metadata = extraMeta + input.MetadataDirective = obs.ReplaceMetadata + } else { + input.MetadataDirective = obs.CopyMetadata + } + _, err = obscli.CopyObject(input) + if err != nil { + return errors.Wrap(err, "obscli.CopyObject") + } + return nil +} + +func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + input := &obs.GetObjectInput{} + input.Bucket = b.Name + input.Key = key + if rangeOpt != nil { + input.RangeStart = rangeOpt.Start + input.RangeEnd = rangeOpt.End + } + output, err := obscli.GetObject(input) + if err != nil { + return nil, errors.Wrap(err, "obscli.GetObject") + } + return output.Body, nil +} + +func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucket string, srcKey string, srcOffset int64, srcLength int64) (string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return "", errors.Wrap(err, "GetOBSClient") + } + input := &obs.CopyPartInput{} + input.Bucket = b.Name + input.Key = key + input.UploadId = uploadId + input.PartNumber = partIndex + input.CopySourceBucket = srcBucket + input.CopySourceKey = srcKey + input.CopySourceRangeStart = srcOffset + input.CopySourceRangeEnd = srcOffset + srcLength - 1 + output, err := obscli.CopyPart(input) + if err != nil { + return "", errors.Wrap(err, "CopyPart") + } + return output.ETag, nil +} + +func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + obsWebConf := obs.SetBucketWebsiteConfigurationInput{} + obsWebConf.Bucket = b.Name + obsWebConf.BucketWebsiteConfiguration = obs.BucketWebsiteConfiguration{ + IndexDocument: obs.IndexDocument{Suffix: websitConf.Index}, + ErrorDocument: obs.ErrorDocument{Key: websitConf.ErrorDocument}, + } + _, err = obscli.SetBucketWebsiteConfiguration(&obsWebConf) + if err != nil { + return errors.Wrap(err, "obscli.SetBucketWebsiteConfiguration(&obsWebConf)") + } + return nil +} + +func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { + result := cloudprovider.SBucketWebsiteConf{} + obscli, err := b.region.getOBSClient() + if err != nil { + return result, errors.Wrap(err, "GetOBSClient") + } + out, err := obscli.GetBucketWebsiteConfiguration(b.Name) + if out == nil { + return result, nil + } + result.Index = out.IndexDocument.Suffix + result.ErrorDocument = out.ErrorDocument.Key + result.Url = fmt.Sprintf("https://%s.obs-website.%s.myhuaweicloud.com", b.Name, b.region.GetId()) + return result, nil +} + +func (b *SBucket) DeleteWebSiteConf() error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + _, err = obscli.DeleteBucketWebsiteConfiguration(b.Name) + if err != nil { + return errors.Wrapf(err, "obscli.DeleteBucketWebsiteConfiguration(%s)", b.Name) + } + return nil +} + +func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + opts := []obs.CorsRule{} + for i := range rules { + opts = append(opts, obs.CorsRule{ + AllowedOrigin: rules[i].AllowedOrigins, + AllowedMethod: rules[i].AllowedMethods, + AllowedHeader: rules[i].AllowedHeaders, + MaxAgeSeconds: rules[i].MaxAgeSeconds, + ExposeHeader: rules[i].ExposeHeaders, + }) + } + + input := obs.SetBucketCorsInput{} + input.Bucket = b.Name + input.BucketCors.CorsRules = opts + _, err = obscli.SetBucketCors(&input) + if err != nil { + return errors.Wrapf(err, "obscli.SetBucketCors(%s)", jsonutils.Marshal(input).String()) + } + return nil +} + +func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + conf, err := obscli.GetBucketCors(b.Name) + if err != nil { + if !strings.Contains(err.Error(), "NoSuchCORSConfiguration") { + return nil, errors.Wrapf(err, "obscli.GetBucketCors(%s)", b.Name) + } + } + if conf == nil { + return nil, nil + } + result := []cloudprovider.SBucketCORSRule{} + for i := range conf.CorsRules { + result = append(result, cloudprovider.SBucketCORSRule{ + AllowedOrigins: conf.CorsRules[i].AllowedOrigin, + AllowedMethods: conf.CorsRules[i].AllowedMethod, + AllowedHeaders: conf.CorsRules[i].AllowedHeader, + MaxAgeSeconds: conf.CorsRules[i].MaxAgeSeconds, + ExposeHeaders: conf.CorsRules[i].ExposeHeader, + Id: strconv.Itoa(i), + }) + } + return result, nil +} + +func (b *SBucket) DeleteCORS() error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + _, err = obscli.DeleteBucketCors(b.Name) + if err != nil { + return errors.Wrapf(err, "obscli.DeleteBucketCors(%s)", b.Name) + } + return nil +} + +func (b *SBucket) GetTags() (map[string]string, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + tagresult, err := obscli.GetBucketTagging(b.Name) + if err != nil { + if strings.Contains(err.Error(), "404") { + return nil, nil + } + return nil, errors.Wrapf(err, "osscli.GetBucketTagging(%s)", b.Name) + } + result := map[string]string{} + for i := range tagresult.Tags { + result[tagresult.Tags[i].Key] = tagresult.Tags[i].Value + } + return result, nil +} + +func (b *SBucket) SetTags(tags map[string]string, replace bool) error { + obscli, err := b.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "GetOBSClient") + } + + _, err = obscli.DeleteBucketTagging(b.Name) + if err != nil { + return errors.Wrapf(err, "DeleteBucketTagging") + } + + if len(tags) == 0 { + return nil + } + + input := obs.SetBucketTaggingInput{BucketTagging: obs.BucketTagging{}} + input.Bucket = b.Name + for k, v := range tags { + input.BucketTagging.Tags = append(input.BucketTagging.Tags, obs.Tag{Key: k, Value: v}) + } + + _, err = obscli.SetBucketTagging(&input) + if err != nil { + return errors.Wrapf(err, "obscli.SetBucketTagging(%s)", jsonutils.Marshal(input).String()) + } + return nil +} + +func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { + obscli, err := b.region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "GetOBSClient") + } + result := []cloudprovider.SBucketMultipartUploads{} + + input := obs.ListMultipartUploadsInput{Bucket: b.Name} + keyMarker := "" + uploadIDMarker := "" + for { + if len(keyMarker) > 0 { + input.KeyMarker = keyMarker + } + if len(uploadIDMarker) > 0 { + input.UploadIdMarker = uploadIDMarker + } + + output, err := obscli.ListMultipartUploads(&input) + if err != nil { + return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") + } + for i := range output.Uploads { + temp := cloudprovider.SBucketMultipartUploads{ + ObjectName: output.Uploads[i].Key, + UploadID: output.Uploads[i].UploadId, + Initiator: output.Uploads[i].Initiator.DisplayName, + Initiated: output.Uploads[i].Initiated, + } + result = append(result, temp) + } + keyMarker = output.NextKeyMarker + uploadIDMarker = output.NextUploadIdMarker + if !output.IsTruncated { + break + } + } + + return result, nil +} diff --git a/pkg/multicloud/huawei/client/auth/credential.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credential.go similarity index 100% rename from pkg/multicloud/huawei/client/auth/credential.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credential.go diff --git a/pkg/multicloud/huawei/client/auth/credentials/access_key_credential.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/access_key_credential.go similarity index 100% rename from pkg/multicloud/huawei/client/auth/credentials/access_key_credential.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/access_key_credential.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/doc.go new file mode 100644 index 0000000000..dd5b1f282b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 credentials // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/doc.go new file mode 100644 index 0000000000..3cb37b7add --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 auth // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signer.go new file mode 100644 index 0000000000..c2bf12f0e7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signer.go @@ -0,0 +1,215 @@ +// Copyright 2019 Yunion +// +// 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 auth + +import ( + "crypto/md5" + "crypto/sha256" + "encoding/hex" + "fmt" + "io/ioutil" + "sort" + "strings" + "sync" + "time" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" +) + +type Signer interface { + GetName() string // 签名算法名称 + GetAccessKeyId() (accessKeyId string, err error) // 签名access key + GetSecretKey() (secretKey string, err error) // access secret + Sign(stringToSign, secretSuffix string) string // 生成签名结果 +} + +func NewSignerWithCredential(credential Credential) (signer Signer, err error) { + switch instance := credential.(type) { + case *credentials.AccessKeyCredential: + return signers.NewAccessKeySigner(instance), nil + default: + return nil, fmt.Errorf("unsupported credential error") + } +} + +// 对request进行签名 +func Sign(request requests.IRequest, signer Signer) (err error) { + return signRequest(request, signer) +} + +func signRequest(request requests.IRequest, signer Signer) error { + // https://support.huaweicloud.com/api-dis/dis_02_0508.html + // requestTime + reqTime := time.Now() + // 添加 必须的Headers + fillRequiredHeaders(request, reqTime) + // 计算CanonicalRequest + canonicalRequest := canonicalRequest(request) + // stringToSign + credentialScope := strings.Join([]string{ + formattedSignTime(reqTime, "Date"), + request.GetRegionId(), + request.GetProduct(), + "sdk_request", + }, "/") + stringToSign := strings.Join([]string{"SDK-HMAC-SHA256", + formattedSignTime(reqTime, "DateTime"), + credentialScope, + hashSha256([]byte(canonicalRequest)), + }, "\n") + // 计算SigningKey + secret, _ := signer.GetSecretKey() + signKey := getSigningKey(secret, formattedSignTime(reqTime, "Date"), + request.GetRegionId(), request.GetProduct()) + // 计算Signature + signature := signer.Sign(stringToSign, signKey) + accesskey, _ := signer.GetAccessKeyId() + addAuthorizationHeader(request, accesskey, credentialScope, signature) + return nil +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0132456728.html +// X-Project-Id 如果是专属云场景采用AK/SK 认证方式的接口请求或者多project场景采用AK/SK认证的接口请求则该字段必选。 +func fillRequiredHeaders(request requests.IRequest, t time.Time) { + request.AddHeaderParam("HOST", request.GetHost()) + request.AddHeaderParam("X-Sdk-Date", formattedSignTime(t, "DateTime")) + if len(request.GetProjectId()) > 0 { + request.AddHeaderParam("X-Project-Id", request.GetProjectId()) + } + return +} + +func buildRequestStringToSign(request requests.IRequest) string { + return "" +} + +func formattedSignTime(t time.Time, format string) string { + switch format { + case "Date": + return t.UTC().Format("20060102") + case "DateTime": + return t.UTC().Format("20060102T150405Z") + default: + return t.UTC().Format("20060102T150405Z") + } +} + +func contentSha256(request requests.IRequest) string { + method := strings.ToUpper(request.GetMethod()) + content := []byte{} + body := request.GetBodyReader() + content, _ = ioutil.ReadAll(body) + if method == "POST" { + if len(content) == 0 { + // other http method use query as content + content = []byte(request.BuildQueries()) + } + } + + return hashSha256(content) +} + +func hashSha256(msg []byte) string { + sh256 := sha256.New() + sh256.Write(msg) + + return hex.EncodeToString(sh256.Sum(nil)) +} + +func canonicalRequest(request requests.IRequest) string { + sha256 := contentSha256(request) + uri := request.GetURI() + if !strings.HasSuffix(uri, "/") { + uri = uri + "/" + } + + return strings.Join([]string{ + request.GetMethod(), + uri, + canonicalQueryString(request), + canonicalHeaders(request), + canonicalHeaderNames(request), + sha256, + }, "\n") +} + +func sortedHeaderNames(request requests.IRequest) []string { + headers := request.GetHeaders() + keys := make([]string, 0) + for k := range headers { + keys = append(keys, k) + } + + sort.Slice(keys, func(i, j int) bool { + return strings.ToLower(keys[i]) < strings.ToLower(keys[j]) + }) + + return keys +} + +func canonicalQueryString(request requests.IRequest) string { + if strings.ToUpper(request.GetMethod()) != "POST" { + return request.BuildQueries() + } + + return "" +} + +func canonicalHeaders(request requests.IRequest) string { + keys := sortedHeaderNames(request) + headers := request.GetHeaders() + ret := []string{} + for _, k := range keys { + ret = append(ret, strings.ToLower(k)+":"+strings.TrimSpace(headers[k])) + } + + return strings.Join(ret, "\n") + "\n" +} + +func canonicalHeaderNames(request requests.IRequest) string { + keys := sortedHeaderNames(request) + ret := strings.Join(keys, ";") + return strings.ToLower(ret) +} + +var SigningKeyCache sync.Map // map[string][]byte{} + +func getSigningKey(secretKey, date, regionId, service string) string { + joinedKey := strings.Join([]string{secretKey, date, regionId, service}, "") + cacheKey := fmt.Sprintf("%x", md5.Sum([]byte(joinedKey))) + if v, ok := SigningKeyCache.Load(cacheKey); ok { + return v.(string) + } + + ret := []byte("SDK" + secretKey) + for _, k := range []string{date, regionId, service, "sdk_request"} { + ret = signers.HmacSha256(k, ret) + } + + SigningKeyCache.Store(cacheKey, string(ret)) + return string(ret) +} + +func addAuthorizationHeader(request requests.IRequest, accessKey, credentialScope, signature string) { + auth := "SDK-HMAC-SHA256" + " " + strings.Join([]string{ + "Credential=" + accessKey + "/" + credentialScope, + "SignedHeaders=" + canonicalHeaderNames(request), + "Signature=" + signature, + }, ", ") + + request.AddHeaderParam("Authorization", auth) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/doc.go new file mode 100644 index 0000000000..40021b4369 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 signers // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/signer_access_key.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/signer_access_key.go new file mode 100644 index 0000000000..8920307491 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/signers/signer_access_key.go @@ -0,0 +1,55 @@ +// Copyright 2019 Yunion +// +// 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 signers + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials" +) + +type AccessKeySigner struct { + credential *credentials.AccessKeyCredential +} + +func (signer *AccessKeySigner) GetName() string { + return "HmacSha256" +} + +func (signer *AccessKeySigner) GetAccessKeyId() (accessKeyId string, err error) { + return signer.credential.AccessKeyId, nil +} + +func (signer *AccessKeySigner) GetSecretKey() (secretKey string, err error) { + return signer.credential.AccessKeySecret, nil +} + +func (signer *AccessKeySigner) Sign(stringToSign, secretSuffix string) string { + return hex.EncodeToString(HmacSha256(stringToSign, []byte(secretSuffix))) +} + +func HmacSha256(data string, key []byte) []byte { + mac := hmac.New(sha256.New, key) + mac.Write([]byte(data)) + return mac.Sum(nil) +} + +func NewAccessKeySigner(credential *credentials.AccessKeyCredential) *AccessKeySigner { + return &AccessKeySigner{ + credential: credential, + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/client.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/client.go new file mode 100644 index 0000000000..ca90f292cb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/client.go @@ -0,0 +1,249 @@ +// Copyright 2019 Yunion +// +// 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 client + +import ( + "net/http" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" +) + +type Client struct { + cfg *SClientConfig + // 标记初始化状态 + init bool + + Balances *modules.SBalanceManager + Credentials *modules.SCredentialManager + Disks *modules.SDiskManager + Domains *modules.SDomainManager + Elasticcache *modules.SElasticcacheManager + DcsAvailableZone *modules.SDcsAvailableZoneManager + Flavors *modules.SFlavorManager + Images *modules.SImageManager + OpenStackImages *modules.SImageManager + Interface *modules.SInterfaceManager + Jobs *modules.SJobManager + Keypairs *modules.SKeypairManager + Orders *modules.SOrderManager + Port *modules.SPortManager + Projects *modules.SProjectManager + Regions *modules.SRegionManager + SecurityGroupRules *modules.SSecgroupRuleManager + SecurityGroups *modules.SSecurityGroupManager + NovaSecurityGroups *modules.SSecurityGroupManager + Servers *modules.SServerManager + ServersV2 *modules.SServerManager + NovaServers *modules.SServerManager + Snapshots *modules.SSnapshotManager + OsSnapshots *modules.SSnapshotManager + Subnets *modules.SSubnetManager + Users *modules.SUserManager + Vpcs *modules.SVpcManager + Zones *modules.SZoneManager + VpcRoutes *modules.SVpcRouteManager + SNatRules *modules.SNatSRuleManager + DNatRules *modules.SNatDRuleManager + NatGateways *modules.SNatGatewayManager + VpcPeerings *modules.SVpcPeeringManager + DBInstance *modules.SDBInstanceManager + DBInstanceBackup *modules.SDBInstanceBackupManager + DBInstanceFlavor *modules.SDBInstanceFlavorManager + DBInstanceJob *modules.SDBInstanceJobManager + Traces *modules.STraceManager + CloudEye *modules.SCloudEyeManager + Quotas *modules.SQuotaManager + EnterpriseProjects *modules.SEnterpriseProjectManager + Roles *modules.SRoleManager + Groups *modules.SGroupManager + SAMLProviders *modules.SAMLProviderManager + SAMLProviderMappings *modules.SAMLProviderMappingManager + SfsTurbos *modules.SfsTurboManager + RouteTables *modules.SRouteTableManager +} + +type SClientConfig struct { + signer auth.Signer + endpoint string // myhuaweicloud.com + regionId string + domainId string + projectId string + + debug bool +} + +func (self *SClientConfig) GetSigner() auth.Signer { + return self.signer +} + +func (self *SClientConfig) GetEndpoint() string { + return self.endpoint +} + +func (self *SClientConfig) GetRegionId() string { + return self.regionId +} + +func (self *SClientConfig) GetDomainId() string { + return self.domainId +} + +func (self *SClientConfig) GetProjectId() string { + return self.projectId +} + +func (self *SClientConfig) GetDebug() bool { + return self.debug +} + +func (self *Client) SetHttpClient(httpClient *http.Client) { + self.Credentials.SetHttpClient(httpClient) + self.Servers.SetHttpClient(httpClient) + self.ServersV2.SetHttpClient(httpClient) + self.NovaServers.SetHttpClient(httpClient) + self.Snapshots.SetHttpClient(httpClient) + self.OsSnapshots.SetHttpClient(httpClient) + self.Images.SetHttpClient(httpClient) + self.OpenStackImages.SetHttpClient(httpClient) + self.Projects.SetHttpClient(httpClient) + self.Regions.SetHttpClient(httpClient) + self.Zones.SetHttpClient(httpClient) + self.Vpcs.SetHttpClient(httpClient) + self.Elasticcache.SetHttpClient(httpClient) + self.DcsAvailableZone.SetHttpClient(httpClient) + self.Disks.SetHttpClient(httpClient) + self.Domains.SetHttpClient(httpClient) + self.Keypairs.SetHttpClient(httpClient) + self.Orders.SetHttpClient(httpClient) + self.SecurityGroupRules.SetHttpClient(httpClient) + self.SecurityGroups.SetHttpClient(httpClient) + self.NovaSecurityGroups.SetHttpClient(httpClient) + self.Subnets.SetHttpClient(httpClient) + self.Users.SetHttpClient(httpClient) + self.Interface.SetHttpClient(httpClient) + self.Jobs.SetHttpClient(httpClient) + self.Balances.SetHttpClient(httpClient) + self.Port.SetHttpClient(httpClient) + self.Flavors.SetHttpClient(httpClient) + self.VpcRoutes.SetHttpClient(httpClient) + self.SNatRules.SetHttpClient(httpClient) + self.DNatRules.SetHttpClient(httpClient) + self.NatGateways.SetHttpClient(httpClient) + self.DBInstance.SetHttpClient(httpClient) + self.DBInstanceBackup.SetHttpClient(httpClient) + self.DBInstanceFlavor.SetHttpClient(httpClient) + self.DBInstanceJob.SetHttpClient(httpClient) + self.Traces.SetHttpClient(httpClient) + self.CloudEye.SetHttpClient(httpClient) + self.EnterpriseProjects.SetHttpClient(httpClient) + self.Roles.SetHttpClient(httpClient) + self.Groups.SetHttpClient(httpClient) + self.SAMLProviders.SetHttpClient(httpClient) + self.SAMLProviderMappings.SetHttpClient(httpClient) + self.SfsTurbos.SetHttpClient(httpClient) + self.RouteTables.SetHttpClient(httpClient) +} + +func (self *Client) InitWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey string, debug bool) error { + // accessKey signer + credential := &credentials.AccessKeyCredential{ + AccessKeyId: accessKey, + AccessKeySecret: secretKey, + } + + // 从signer中初始化 + signer, err := auth.NewSignerWithCredential(credential) + if err != nil { + return err + } + self.cfg = &SClientConfig{ + signer: signer, + endpoint: endpoint, + regionId: regionId, + domainId: domainId, + projectId: projectId, + debug: debug, + } + + // 初始化 resource manager + self.initManagers() + return err +} + +func (self *Client) initManagers() { + if !self.init { + self.Servers = modules.NewServerManager(self.cfg) + self.ServersV2 = modules.NewServerV2Manager(self.cfg) + self.NovaServers = modules.NewNovaServerManager(self.cfg) + self.Snapshots = modules.NewSnapshotManager(self.cfg) + self.OsSnapshots = modules.NewOsSnapshotManager(self.cfg) + self.Images = modules.NewImageManager(self.cfg) + self.OpenStackImages = modules.NewOpenstackImageManager(self.cfg) + self.Projects = modules.NewProjectManager(self.cfg) + self.Regions = modules.NewRegionManager(self.cfg) + self.Zones = modules.NewZoneManager(self.cfg) + self.Vpcs = modules.NewVpcManager(self.cfg) + self.Elasticcache = modules.NewElasticcacheManager(self.cfg) + self.DcsAvailableZone = modules.NewDcsAvailableZoneManager(self.cfg) + self.Disks = modules.NewDiskManager(self.cfg) + self.Domains = modules.NewDomainManager(self.cfg) + self.Keypairs = modules.NewKeypairManager(self.cfg) + self.Orders = modules.NewOrderManager(self.cfg) + self.SecurityGroupRules = modules.NewSecgroupRuleManager(self.cfg) + self.SecurityGroups = modules.NewSecurityGroupManager(self.cfg) + self.NovaSecurityGroups = modules.NewNovaSecurityGroupManager(self.cfg) + self.Subnets = modules.NewSubnetManager(self.cfg) + self.Users = modules.NewUserManager(self.cfg) + self.Interface = modules.NewInterfaceManager(self.cfg) + self.Jobs = modules.NewJobManager(self.cfg) + self.Balances = modules.NewBalanceManager(self.cfg) + self.Credentials = modules.NewCredentialManager(self.cfg) + self.Port = modules.NewPortManager(self.cfg) + self.Flavors = modules.NewFlavorManager(self.cfg) + self.VpcRoutes = modules.NewVpcRouteManager(self.cfg) + self.SNatRules = modules.NewNatSManager(self.cfg) + self.DNatRules = modules.NewNatDManager(self.cfg) + self.NatGateways = modules.NewNatGatewayManager(self.cfg) + self.VpcPeerings = modules.NewVpcPeeringManager(self.cfg) + self.DBInstance = modules.NewDBInstanceManager(self.cfg) + self.DBInstanceBackup = modules.NewDBInstanceBackupManager(self.cfg) + self.DBInstanceFlavor = modules.NewDBInstanceFlavorManager(self.cfg) + self.DBInstanceJob = modules.NewDBInstanceJobManager(self.cfg) + self.Traces = modules.NewTraceManager(self.cfg) + self.CloudEye = modules.NewCloudEyeManager(self.cfg) + self.Quotas = modules.NewQuotaManager(self.cfg) + self.EnterpriseProjects = modules.NewEnterpriseProjectManager(self.cfg) + self.Roles = modules.NewRoleManager(self.cfg) + self.Groups = modules.NewGroupManager(self.cfg) + self.SAMLProviders = modules.NewSAMLProviderManager(self.cfg) + self.SAMLProviderMappings = modules.NewSAMLProviderMappingManager(self.cfg) + self.SfsTurbos = modules.NewSfsTurboManager(self.cfg) + self.RouteTables = modules.NewRouteTableManager(self.cfg) + } + + self.init = true +} + +func NewClientWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey string, debug bool) (*Client, error) { + c := &Client{} + err := c.InitWithAccessKey(endpoint, regionId, domainId, projectId, accessKey, secretKey, debug) + return c, err +} + +func NewPublicCloudClientWithAccessKey(regionId, domainId, projectId, accessKey, secretKey string, debug bool) (*Client, error) { + return NewClientWithAccessKey("myhuaweicloud.com", regionId, domainId, projectId, accessKey, secretKey, debug) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/doc.go new file mode 100644 index 0000000000..b50b2e2b90 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 client // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/doc.go new file mode 100644 index 0000000000..fd4bfdd238 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 manager // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/manager.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/manager.go new file mode 100644 index 0000000000..ceaa387cbf --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager/manager.go @@ -0,0 +1,81 @@ +// Copyright 2019 Yunion +// +// 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 manager + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type IManagerContext interface { + GetPath() string +} + +type IBaseManager interface { + Version() string + KeyString() string + ServiceType() string + GetColumns() []string +} + +type IManager interface { + IBaseManager + // 获取资源列表 GET /cloudservers/? + List(queries map[string]string) (*responses.ListResult, error) + // 根据上文获取资源列表 GET /cloudservers//nics? + ListInContext(ctx IManagerContext, queries map[string]string) (*responses.ListResult, error) + ListInContextWithSpec(ctx IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error) + + // 查询单个资源 GET /cloudservers/? + Get(id string, queries map[string]string) (jsonutils.JSONObject, error) + // 根据上文获取资源查询单个资源 GET /cloudservers//nics/? + GetInContext(ctx IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error) + + // 创建单个资源 POST /cloudservers + Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 根据上文创建单个资源 POST /cloudservers//nics/ + CreateInContext(ctx IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 异步任务创建 POST /cloudservers. 返回异步任务 job_id。 todo:// 后续考虑返回一个task对象 + AsyncCreate(params jsonutils.JSONObject) (string, error) + + // 更新单个资源 PUT /cloudservers/ + Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 根据上文更新单个资源 PUT /cloudservers//nics/ + UpdateInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 根据上文和spec更新单个资源 PUT /v2.1/{project_id}/servers/{server_id}/os-reset-password + UpdateInContextWithSpec(ctx IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) + + // 删除单个资源 DELETE /cloudservers/ + Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 根据上文删除单个资源 DELETE /cloudservers//nics/ + DeleteInContext(ctx IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 根据上文和spec删除单个资源 + DeleteInContextWithSpec(ctx IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) + // 批量执行操作 POST /cloudservers/ + // BatchPerformAction(action string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) + // 执行操作 POST /cloudservers// + PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) +} + +type IManagerConfig interface { + GetSigner() auth.Signer + GetEndpoint() string + GetRegionId() string + GetDomainId() string + GetProjectId() string + GetDebug() bool +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/doc.go new file mode 100644 index 0000000000..10bf5c141d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 modules // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_base.go new file mode 100644 index 0000000000..629884429a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_base.go @@ -0,0 +1,272 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "context" + "fmt" + "net/http" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type IRequestHook interface { + Process(r requests.IRequest) +} + +type SBaseManager struct { + cfg manager.IManagerConfig + httpClient *http.Client + requestHook IRequestHook // 用于对request做特殊处理。非必要请不要使用!!!。目前只有port接口用到。 + + columns []string + debug bool +} + +type sThrottlingThreshold struct { + locked bool + lockTime time.Time +} + +func (t *sThrottlingThreshold) CheckingLock() { + if !t.locked { + return + } + + for { + if t.lockTime.Sub(time.Now()).Seconds() < 0 { + return + } + log.Debugf("throttling threshold has been reached. release at %s", t.lockTime) + time.Sleep(5 * time.Second) + } +} + +func (t *sThrottlingThreshold) Lock() { + // 锁定至少15秒 + t.locked = true + t.lockTime = time.Now().Add(15 * time.Second) +} + +var ThrottlingLock = sThrottlingThreshold{locked: false, lockTime: time.Time{}} + +func NewBaseManager2(cfg manager.IManagerConfig, requesthk IRequestHook) SBaseManager { + return SBaseManager{ + cfg: cfg, + httpClient: httputils.GetDefaultClient(), + debug: cfg.GetDebug(), + requestHook: requesthk, + } +} + +func NewBaseManager(cfg manager.IManagerConfig) SBaseManager { + return NewBaseManager2(cfg, nil) +} + +func (self *SBaseManager) GetEndpoint() string { + return self.cfg.GetEndpoint() +} + +func (self *SBaseManager) GetColumns() []string { + return self.columns +} + +func (self *SBaseManager) SetHttpClient(httpClient *http.Client) { + self.httpClient = httpClient +} + +func (self *SBaseManager) _list(request requests.IRequest, responseKey string) (*responses.ListResult, error) { + _, body, err := self.jsonRequest(request) + if err != nil { + return nil, err + } + if body == nil { + log.Warningf("empty response") + return &responses.ListResult{}, nil + } + + rets, err := body.GetArray(responseKey) + if err != nil { + return nil, errors.Wrapf(err, "body.GetArray %s", responseKey) + } + total, _ := body.Int("count") + // if err != nil { + // total = int64(len(rets)) + //} + + //if total == 0 { + // total = int64(len(rets)) + //} + + limit := 0 + if v, exists := request.GetQueryParams()["limit"]; exists { + limit, _ = strconv.Atoi(v) + } + + offset := 0 + if v, exists := request.GetQueryParams()["offset"]; exists { + offset, _ = strconv.Atoi(v) + } + + return &responses.ListResult{ + Data: rets, + Total: int(total), + Limit: limit, + Offset: offset, + }, nil +} + +func (self *SBaseManager) _do(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) { + _, resp, e := self.jsonRequest(request) + if e != nil { + return nil, e + } + + if resp == nil { // no reslt + return jsonutils.NewDict(), nil + } + + if len(responseKey) == 0 { + return resp, nil + } + + ret, e := resp.Get(responseKey) + if e != nil { + return nil, e + } + + return ret, nil +} + +func (self *SBaseManager) _get(request requests.IRequest, responseKey string) (jsonutils.JSONObject, error) { + return self._do(request, responseKey) +} + +type HuaweiClientError struct { + Code int + Errorcode []string + err error + Details string + ErrorCode string +} + +func (ce *HuaweiClientError) Error() string { + return jsonutils.Marshal(ce).String() +} + +func (ce *HuaweiClientError) ParseErrorFromJsonResponse(statusCode int, body jsonutils.JSONObject) error { + if body != nil { + body.Unmarshal(ce) + } + if ce.Code == 0 { + ce.Code = statusCode + } + if len(ce.Details) == 0 && body != nil { + ce.Details = body.String() + } + return ce +} + +func (self *SBaseManager) jsonRequest(request requests.IRequest) (http.Header, jsonutils.JSONObject, error) { + ThrottlingLock.CheckingLock() + ctx := context.Background() + // hook request + if self.requestHook != nil { + self.requestHook.Process(request) + } + // 拼接、编译、签名 requests here。 + err := self.buildRequestWithSigner(request, self.cfg.GetSigner()) + if err != nil { + return nil, nil, err + } + header := http.Header{} + for k, v := range request.GetHeaders() { + header.Set(k, v) + } + + var jsonBody jsonutils.JSONObject + content := request.GetContent() + if len(content) > 0 { + jsonBody, err = jsonutils.Parse(content) + if err != nil { + return nil, nil, fmt.Errorf("not a json body") + } + } + + client := httputils.NewJsonClient(self.httpClient) + req := httputils.NewJsonRequest(httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), jsonBody) + req.SetHeader(header) + resp := &HuaweiClientError{} + const MAX_RETRY = 3 + retry := MAX_RETRY + for { + h, b, e := client.Send(ctx, req, resp, self.debug) + if e == nil { + return h, b, nil + } + + log.Errorf("[%s] %s body: %v error: %v", req.GetHttpMethod(), req.GetUrl(), jsonBody, e) + + switch err := e.(type) { + case *HuaweiClientError: + if err.ErrorCode == "APIGW.0301" { + return h, b, errors.Wrapf(httperrors.ErrInvalidAccessKey, e.Error()) + } else if err.Code == 499 && retry > 0 && request.GetMethod() == "GET" { + retry -= 1 + time.Sleep(3 * time.Second * time.Duration(MAX_RETRY-retry)) + } else if (err.Code == 404 || strings.Contains(err.Details, "could not be found") || + strings.Contains(err.Error(), "Not Found") || + strings.Contains(err.Details, "does not exist")) && request.GetMethod() != "POST" { + return h, b, errors.Wrap(cloudprovider.ErrNotFound, err.Error()) + } else if err.Code == 429 && retry > 0 { + // 当前请求过多。 + ThrottlingLock.Lock() + retry -= 1 + time.Sleep(15 * time.Second) + } else { + return h, b, e + } + default: + return h, b, e + } + } +} + +func (self *SBaseManager) rawRequest(request requests.IRequest) (*http.Response, error) { + ctx := context.Background() + // 拼接、编译requests here。 + header := http.Header{} + for k, v := range request.GetHeaders() { + header.Set(k, v) + } + return httputils.Request(self.httpClient, ctx, httputils.THttpMethod(request.GetMethod()), request.BuildUrl(), header, request.GetBodyReader(), self.debug) +} + +func (self *SBaseManager) buildRequestWithSigner(request requests.IRequest, signer auth.Signer) error { + return auth.Sign(request, signer) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_resource.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_resource.go new file mode 100644 index 0000000000..91fa296c38 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/manager_resource.go @@ -0,0 +1,298 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type ServiceNameType string + +const HuaWeiDefaultDomain = "myhuaweicloud.com" + +const ( + ServiceNameECS ServiceNameType = "ecs" // 弹性云服务 + ServiceNameCCE ServiceNameType = "cce" // 云容器服务 + ServiceNameAS ServiceNameType = "as" // 弹性伸缩服务 + ServiceNameIAM ServiceNameType = "iam" // 统一身份认证服务 + ServiceNameIMS ServiceNameType = "ims" // 镜像服务 + ServiceNameCSBS ServiceNameType = "csbs" // 云服务器备份服务 + ServiceNameCCI ServiceNameType = "cci" // 云容器实例 CCI + ServiceNameBMS ServiceNameType = "bms" // 裸金属服务器 + ServiceNameEVS ServiceNameType = "evs" // 云硬盘 EVS + ServiceNameVBS ServiceNameType = "vbs" // 云硬盘备份 VBS + ServiceNameOBS ServiceNameType = "obs" // 对象存储服务 OBS + ServiceNameVPC ServiceNameType = "vpc" // 虚拟私有云 VPC + ServiceNameELB ServiceNameType = "elb" // 弹性负载均衡 ELB + ServiceNameBSS ServiceNameType = "bss" // 合作伙伴运营能力 + ServiceNameNAT ServiceNameType = "nat" // Nat网关 NAT + ServiceNameDCS ServiceNameType = "dcs" // 分布式缓存服务 + ServiceNameRDS ServiceNameType = "rds" // 关系型数据库 RDS + ServiceNameCTS ServiceNameType = "cts" // 云审计服务 + ServiceNameCES ServiceNameType = "ces" // 监控服务 CloudEye + ServiceNameEPS ServiceNameType = "eps" // 企业项目 + + ServiceNameModelarts ServiceNameType = "modelarts" // AI ModelArts + + ServiceNameSFSTurbo ServiceNameType = "sfs-turbo" // 文件系统 +) + +type SManagerContext struct { + InstanceManager manager.IManager + InstanceId string +} + +func (self *SManagerContext) GetPath() string { + path := self.InstanceManager.KeyString() + if len(self.InstanceId) > 0 { + path += fmt.Sprintf("/%s", url.PathEscape(self.InstanceId)) + } + + return path +} + +type SResourceManager struct { + SBaseManager + ctx manager.IManagerContext + ServiceName ServiceNameType // 服务名称: ecs + Region string // 区域: cn-north-1 + DomainId string + ProjectId string // 项目ID: uuid + version string // api 版本号 + Keyword string // 资源名称单数。构建URL时使用 + KeywordPlural string // 资源名称复数形式。构建URL时使用 + + ResourceKeyword string // 资源名称。url中使用 +} + +func getContent(params jsonutils.JSONObject) string { + if params == nil { + return "" + } + + return params.String() +} + +func (self *SResourceManager) Version() string { + return self.version +} + +func (self *SResourceManager) KeyString() string { + return self.ResourceKeyword +} + +func (self *SResourceManager) ServiceType() string { + return string(self.ServiceName) +} + +func (self *SResourceManager) GetColumns() []string { + return []string{} +} + +func (self *SResourceManager) SetDomainId(domainId string) { + self.DomainId = domainId +} + +func (self *SResourceManager) getReourcePath(ctx manager.IManagerContext, rid string, spec string) string { + segs := []string{} + if ctx != nil { + segs = append(segs, ctx.GetPath()) + } + + segs = append(segs, self.KeyString()) + + if len(rid) > 0 { + segs = append(segs, url.PathEscape(rid)) + } + + if len(spec) > 0 { + specSegs := strings.Split(spec, "/") + for _, specSeg := range specSegs { + segs = append(segs, url.PathEscape(specSeg)) + } + } + + return strings.Join(segs, "/") +} + +func (self *SResourceManager) newRequest(method, rid, spec string, ctx manager.IManagerContext) *requests.SRequest { + resourcePath := self.getReourcePath(ctx, rid, spec) + return requests.NewResourceRequest(self.GetEndpoint(), method, string(self.ServiceName), self.version, self.Region, self.ProjectId, resourcePath) +} + +func (self *SResourceManager) List(queries map[string]string) (*responses.ListResult, error) { + return self.ListInContext(self.ctx, queries) +} + +func (self *SResourceManager) ListInContext(ctx manager.IManagerContext, queries map[string]string) (*responses.ListResult, error) { + return self.ListInContextWithSpec(ctx, "", queries, self.KeywordPlural) +} + +func (self *SResourceManager) ListInContextWithSpec(ctx manager.IManagerContext, spec string, queries map[string]string, responseKey string) (*responses.ListResult, error) { + request := self.newRequest("GET", "", spec, ctx) + for k, v := range queries { + request.AddQueryParam(k, v) + } + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._list(request, responseKey) +} + +func (self *SResourceManager) Get(id string, queries map[string]string) (jsonutils.JSONObject, error) { + return self.GetInContext(self.ctx, id, queries) +} + +func (self *SResourceManager) GetInContext(ctx manager.IManagerContext, id string, queries map[string]string) (jsonutils.JSONObject, error) { + return self.GetInContextWithSpec(ctx, id, "", queries, self.Keyword) +} + +func (self *SResourceManager) GetInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("GET", id, spec, ctx) + for k, v := range queries { + request.AddQueryParam(k, v) + } + + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._get(request, responseKey) +} + +func (self *SResourceManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.CreateInContext(self.ctx, params) +} + +func (self *SResourceManager) CreateInContext(ctx manager.IManagerContext, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.CreateInContextWithSpec(ctx, "", params, self.Keyword) +} + +func (self *SResourceManager) CreateInContextWithSpec(ctx manager.IManagerContext, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("POST", "", spec, ctx) + request.SetContent([]byte(params.String())) + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._do(request, responseKey) +} + +func (self *SResourceManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { + return "", fmt.Errorf("not supported") +} + +func (self *SResourceManager) Update(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.UpdateInContext(self.ctx, id, params) +} + +func (self *SResourceManager) UpdateInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.UpdateInContextWithSpec(ctx, id, "", params, self.Keyword) +} + +func (self *SResourceManager) UpdateInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("PUT", id, spec, ctx) + content := getContent(params) + if len(content) > 0 { + request.SetContent([]byte(content)) + } + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._do(request, responseKey) +} + +func (self *SResourceManager) Patch(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.PatchInContext(self.ctx, id, params) +} + +func (self *SResourceManager) PatchInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.PatchInContextWithSpec(ctx, id, "", params, self.Keyword) +} + +func (self *SResourceManager) PatchInContextWithSpec(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("PATCH", id, spec, ctx) + content := getContent(params) + if len(content) > 0 { + request.SetContent([]byte(content)) + } + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._do(request, responseKey) +} + +func (self *SResourceManager) Delete(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.DeleteInContext(self.ctx, id, params) +} + +func (self *SResourceManager) DeleteInContext(ctx manager.IManagerContext, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.DeleteInContextWithSpec(ctx, id, "", nil, params, "") +} + +func (self *SResourceManager) DeleteInContextWithSpec(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("DELETE", id, spec, ctx) + for k, v := range queries { + request.AddQueryParam(k, v) + } + + content := getContent(params) + if len(content) > 0 { + request.SetContent([]byte(content)) + } + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._do(request, responseKey) +} + +func (self *SResourceManager) PerformAction(action string, id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.PerformAction2(action, id, params, self.Keyword) +} + +func (self *SResourceManager) PerformAction2(action string, id string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) { + request := self.newRequest("POST", id, action, nil) + request.SetContent([]byte(getContent(params))) + if len(self.DomainId) > 0 { + request.AddHeaderParam("X-Domain-Id", self.DomainId) + } + + return self._do(request, responseKey) +} + +func (self *SResourceManager) SetVersion(v string) { + self.version = v +} + +func (self *SResourceManager) versionedURL(path string) string { + return "" +} + +// todo: Init a manager with environment variables +func (self *SResourceManager) Init() error { + return nil +} diff --git a/pkg/multicloud/huawei/client/modules/mod_balances.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_balances.go similarity index 94% rename from pkg/multicloud/huawei/client/modules/mod_balances.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_balances.go index d3b1290cb8..1a68f95706 100644 --- a/pkg/multicloud/huawei/client/modules/mod_balances.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_balances.go @@ -17,8 +17,8 @@ package modules import ( "fmt" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" ) /* diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_ces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_ces.go new file mode 100644 index 0000000000..853b52757a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_ces.go @@ -0,0 +1,152 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" +) + +type SCloudEyeManager struct { + SResourceManager +} + +func NewCloudEyeManager(cfg manager.IManagerConfig) *SCloudEyeManager { + return &SCloudEyeManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameCES, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "V1.0", + Keyword: "", + KeywordPlural: "metrics", + ResourceKeyword: "metrics", + }} +} + +type SMetricDimension struct { + Name string `json:"name"` + Value string `json:"value"` +} + +type SDatapoint struct { + Timestamp int64 `json:"timestamp"` + Max float64 `json:"max,omitzero"` + Min float64 `json:"min,omitzero"` + Average float64 `json:"average,omitzero"` + Sum float64 `json:"sum,omitzero"` + Variance float64 `json:"variance,omitzero"` +} + +type SMetricData struct { + SMetricMeta + + Datapoints []SDatapoint +} + +type SMetricMeta struct { + SMetric + + Unit string `json:"unit"` +} + +type SMetric struct { + MetricName string `json:"metric_name"` + Namespace string `json:"namespace"` + + Dimensions []SMetricDimension `json:"dimensions"` +} + +func (ces *SCloudEyeManager) ListMetrics() ([]SMetricMeta, error) { + metrics := make([]SMetricMeta, 0) + next := "" + for { + marker, data, err := ces.listMetricsInternal(next) + if err != nil { + return nil, errors.Wrap(err, "ces.listMetricsInternal") + } + if len(data) == 0 { + break + } + metrics = append(metrics, data...) + next = marker + } + return metrics, nil +} + +func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []SMetricMeta, error) { + request := requests.NewResourceRequest(ces.GetEndpoint(), "GET", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, ces.ResourceKeyword) + request.AddQueryParam("limit", "1000") + if len(start) > 0 { + request.AddQueryParam("start", start) + } + _, resp, err := ces.jsonRequest(request) + if err != nil { + return "", nil, errors.Wrap(err, "ces.jsonRequest") + } + marker, _ := resp.GetString("meta_data", "marker") + metrics := make([]SMetricMeta, 0) + err = resp.Unmarshal(&metrics, "metrics") + if err != nil { + return "", nil, errors.Wrap(err, "resp.Unmarshal metrics") + } + return marker, metrics, nil +} + +type SBatchQueryMetricDataInput struct { + Metrics []SMetric `json:"metrics"` + + From int64 `json:"from"` + To int64 `json:"to"` + Period string `json:"period"` + Filter string `json:"filter"` +} + +func (ces *SCloudEyeManager) GetMetricsData(metrics []SMetricMeta, since time.Time, until time.Time) ([]SMetricData, error) { + if len(metrics) > 10 { + return nil, errors.Wrap(httperrors.ErrTooLarge, "request more than 10 metrics") + } + metricReq := make([]SMetric, len(metrics)) + for i := range metrics { + metricReq[i] = metrics[i].SMetric + } + request := requests.NewResourceRequest(ces.GetEndpoint(), "POST", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, "batch-query-metric-data") + input := SBatchQueryMetricDataInput{ + Metrics: metricReq, + From: since.Unix() * 1000, + To: until.Unix() * 1000, + Period: "1", + Filter: "average", + } + body := jsonutils.Marshal(&input).String() + request.SetContent([]byte(body)) + _, resp, err := ces.jsonRequest(request) + if err != nil { + return nil, errors.Wrap(err, "ces.jsonRequest") + } + //log.Debugf("%s", resp) + result := make([]SMetricData, 0) + err = resp.Unmarshal(&result, "metrics") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return result, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_credential.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_credential.go new file mode 100644 index 0000000000..171e1788d5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_credential.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SCredentialManager struct { + SResourceManager +} + +func NewCredentialManager(cfg manager.IManagerConfig) *SCredentialManager { + return &SCredentialManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: "", + ProjectId: "", + version: "v3.0", + Keyword: "credential", + KeywordPlural: "credentials", + + ResourceKeyword: "OS-CREDENTIAL/credentials", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance.go new file mode 100644 index 0000000000..663e6fd465 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance.go @@ -0,0 +1,103 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type SDBInstanceManager struct { + SResourceManager +} + +func NewDBInstanceManager(cfg manager.IManagerConfig) *SDBInstanceManager { + return &SDBInstanceManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameRDS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v3", + Keyword: "", + KeywordPlural: "instances", + + ResourceKeyword: "instances", + }} +} + +func (self *SDBInstanceManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { + if len(id) == 0 { + return nil, cloudprovider.ErrNotFound + } + resp, err := self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "") + if err != nil { + return nil, err + } + instances, err := resp.GetArray("instances") + if err != nil { + return nil, err + } + if len(instances) == 0 { + return nil, cloudprovider.ErrNotFound + } else if len(instances) == 1 { + return instances[0], nil + } + return nil, cloudprovider.ErrDuplicateId +} + +func (self *SDBInstanceManager) ListParameters(queries map[string]string) (*responses.ListResult, error) { + id, _ := queries["instance_id"] + if len(id) == 0 { + return nil, fmt.Errorf("SDBInstanceManager.ListParameters missing parameter instance_id") + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/configurations", id), queries, "configuration_parameters") +} + +func (self *SDBInstanceManager) ListDatabases(queries map[string]string) (*responses.ListResult, error) { + id, _ := queries["instance_id"] + if len(id) == 0 { + return nil, fmt.Errorf("SDBInstanceManager.ListDatabases missing parameter instance_id") + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/database/detail", id), queries, "databases") +} + +func (self *SDBInstanceManager) ListAccounts(queries map[string]string) (*responses.ListResult, error) { + id, _ := queries["instance_id"] + if len(id) == 0 { + return nil, fmt.Errorf("SDBInstanceManager.ListAccounts missing parameter instance_id") + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/detail", id), queries, "users") +} + +func (self *SDBInstanceManager) ListPrivileges(queries map[string]string) (*responses.ListResult, error) { + id, _ := queries["instance_id"] + if len(id) == 0 { + return nil, fmt.Errorf("SDBInstanceManager.ListPrivileges missing parameter instance_id") + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, fmt.Sprintf("%s/db_user/database", id), queries, "databases") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go new file mode 100644 index 0000000000..6062aa256f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_backup.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SDBInstanceBackupManager struct { + SResourceManager +} + +func NewDBInstanceBackupManager(cfg manager.IManagerConfig) *SDBInstanceBackupManager { + return &SDBInstanceBackupManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameRDS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v3", + Keyword: "backup", + KeywordPlural: "backups", + + ResourceKeyword: "backups", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go new file mode 100644 index 0000000000..9f937891b1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_flavor.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SDBInstanceFlavorManager struct { + SResourceManager +} + +func NewDBInstanceFlavorManager(cfg manager.IManagerConfig) *SDBInstanceFlavorManager { + return &SDBInstanceFlavorManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameRDS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v3", + Keyword: "flavor", + KeywordPlural: "flavor", + + ResourceKeyword: "flavors", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go new file mode 100644 index 0000000000..53777a6bc9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dbinstance_job.go @@ -0,0 +1,43 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SDBInstanceJobManager struct { + SResourceManager +} + +func NewDBInstanceJobManager(cfg manager.IManagerConfig) *SDBInstanceJobManager { + return &SDBInstanceJobManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameRDS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v3", + Keyword: "", + KeywordPlural: "", + + ResourceKeyword: "jobs", + }} +} + +func (self *SDBInstanceJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { + return self.GetInContextWithSpec(nil, "", "", map[string]string{"id": id}, "job") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_disks.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_disks.go new file mode 100644 index 0000000000..0aa79990cd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_disks.go @@ -0,0 +1,76 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type SDiskManager struct { + SResourceManager +} + +func NewDiskManager(cfg manager.IManagerConfig) *SDiskManager { + return &SDiskManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameEVS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "volume", + KeywordPlural: "volumes", + + ResourceKeyword: "cloudvolumes", + }} +} + +func (self *SDiskManager) List(querys map[string]string) (*responses.ListResult, error) { + return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) +} + +// https://support.huaweicloud.com/api-evs/evs_04_2003.html +func (self *SDiskManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { + origin_version := self.version + self.version = "v2.1" + defer func() { self.version = origin_version }() + + ret, err := self.CreateInContextWithSpec(nil, "", params, "") + if err != nil { + log.Debugf("AsyncCreate %s", err) + return "", err + } + + log.Debugf("AsyncCreate result %s", ret.String()) + // 按需机器 + jobId, err := ret.GetString("job_id") + if err == nil { + return jobId, nil + } + + // 包年包月机器 + return ret.GetString("order_id") +} + +// https://support.huaweicloud.com/api-evs/evs_04_2003.html +func (self *SDiskManager) GetDiskTypes() (*responses.ListResult, error) { + originKeyword := self.ResourceKeyword + self.ResourceKeyword = "" + defer func() { self.ResourceKeyword = originKeyword }() + return self.ListInContextWithSpec(self.ctx, "types", nil, "volume_types") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dnat_rules.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dnat_rules.go new file mode 100644 index 0000000000..70ba9f3868 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_dnat_rules.go @@ -0,0 +1,41 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SNatDRuleManager struct { + SResourceManager +} + +func NewNatDManager(cfg manager.IManagerConfig) *SNatDRuleManager { + man := &SNatDRuleManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameNAT, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2.0", + Keyword: "dnat_rule", + KeywordPlural: "dnat_rules", + + ResourceKeyword: "dnat_rules", + }} + if len(cfg.GetProjectId()) > 0 { + man.requestHook = &sProjectHook{cfg.GetProjectId()} + } + return man +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_domains.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_domains.go new file mode 100644 index 0000000000..f2ced5b04c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_domains.go @@ -0,0 +1,95 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type SDomainManager struct { + SResourceManager +} + +func NewDomainManager(cfg manager.IManagerConfig) *SDomainManager { + m := &SDomainManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: "", + ProjectId: "", + version: "v3/auth", + Keyword: "domain", + KeywordPlural: "domains", + + ResourceKeyword: "domains", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} + +func (manager *SDomainManager) DeleteRole(domainId string, groupId, roleId string) error { + if len(domainId) == 0 { + return fmt.Errorf("missing domainId") + } + if len(groupId) == 0 { + return fmt.Errorf("missing groupId") + } + if len(roleId) == 0 { + return fmt.Errorf("missing roleId") + } + manager.SetVersion("v3") + defer manager.SetVersion("v3/auth") + res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) + _, err := manager.DeleteInContextWithSpec(nil, domainId, res, nil, nil, "") + if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return err +} + +func (manager *SDomainManager) ListRoles(domainId string, groupId string) (*responses.ListResult, error) { + if len(domainId) == 0 { + return nil, fmt.Errorf("missing domainId") + } + if len(groupId) == 0 { + return nil, fmt.Errorf("missing groupId") + } + manager.SetVersion("v3") + defer manager.SetVersion("v3/auth") + res := fmt.Sprintf("%s/groups/%s/roles", domainId, groupId) + return manager.ListInContextWithSpec(nil, res, nil, "roles") +} + +func (manager *SDomainManager) AddRole(domainId string, groupId, roleId string) error { + if len(domainId) == 0 { + return fmt.Errorf("missing domainId") + } + if len(groupId) == 0 { + return fmt.Errorf("missing groupId") + } + if len(roleId) == 0 { + return fmt.Errorf("missing roleId") + } + manager.SetVersion("v3") + defer manager.SetVersion("v3/auth") + res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) + _, err := manager.UpdateInContextWithSpec(nil, domainId, res, nil, "") + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_elasticcache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_elasticcache.go new file mode 100644 index 0000000000..0ec087ae94 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_elasticcache.go @@ -0,0 +1,118 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type SElasticcacheManager struct { + SResourceManager +} + +type SDcsAvailableZoneManager struct { + SResourceManager +} + +func NewElasticcacheManager(cfg manager.IManagerConfig) *SElasticcacheManager { + return &SElasticcacheManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameDCS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1.0", + Keyword: "", + KeywordPlural: "instances", + + ResourceKeyword: "instances", + }} +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html +func (self *SElasticcacheManager) ListBackups(queries map[string]string) (*responses.ListResult, error) { + var spec string + if id, _ := queries["instance_id"]; len(id) == 0 { + return nil, fmt.Errorf("SElasticcacheManager.ListBackups missing parameter instance_id") + } else { + spec = fmt.Sprintf("%s/backups", id) + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, spec, queries, "backup_record_response") +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html +func (self *SElasticcacheManager) ListParameters(queries map[string]string) (*responses.ListResult, error) { + var spec string + if id, _ := queries["instance_id"]; len(id) == 0 { + return nil, fmt.Errorf("SElasticcacheManager.ListParameters missing parameter instance_id") + } else { + spec = fmt.Sprintf("%s/configs", id) + } + + delete(queries, "instance_id") + return self.ListInContextWithSpec(nil, spec, queries, "redis_config") +} + +func (self *SElasticcacheManager) Restart(instanceId string) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") + params.Add(jsonutils.NewString("restart"), "action") + return self.UpdateInContextWithSpec(nil, "", "status", params, "") +} + +// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 +func (self *SElasticcacheManager) Flush(instanceId string) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Add(jsonutils.NewArray(jsonutils.NewString(instanceId)), "instances") + params.Add(jsonutils.NewString("flush"), "action") + return self.UpdateInContextWithSpec(nil, "", "status", params, "") +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html +func (self *SElasticcacheManager) RestoreInstance(instanceId string, backupId string) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Add(jsonutils.NewArray(jsonutils.NewString(backupId)), "backup_id") + + return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/restores", instanceId), params, "") +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html +func (self *SElasticcacheManager) ChangeInstanceSpec(instanceId string, specCode string, newCapacity int64) (jsonutils.JSONObject, error) { + params := jsonutils.NewDict() + params.Set("new_capacity", jsonutils.NewInt(newCapacity)) + params.Set("spec_code", jsonutils.NewString(specCode)) + + return self.CreateInContextWithSpec(nil, fmt.Sprintf("%s/extend", instanceId), params, "") +} + +func NewDcsAvailableZoneManager(cfg manager.IManagerConfig) *SDcsAvailableZoneManager { + return &SDcsAvailableZoneManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameDCS, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v1.0", + Keyword: "available_zone", + KeywordPlural: "available_zones", + + ResourceKeyword: "availableZones", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go new file mode 100644 index 0000000000..33bfd3b1bd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_enterpriceprojects.go @@ -0,0 +1,39 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SEnterpriseProjectManager struct { + SResourceManager +} + +func NewEnterpriseProjectManager(cfg manager.IManagerConfig) *SEnterpriseProjectManager { + m := &SEnterpriseProjectManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameEPS, + Region: "", + ProjectId: "", + version: "v1.0", + Keyword: "enterprise_project", + KeywordPlural: "enterprise_projects", + + ResourceKeyword: "enterprise-projects", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_flavors.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_flavors.go new file mode 100644 index 0000000000..596a20e68e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_flavors.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SFlavorManager struct { + SResourceManager +} + +func NewFlavorManager(cfg manager.IManagerConfig) *SFlavorManager { + return &SFlavorManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "flavor", + KeywordPlural: "flavors", + + ResourceKeyword: "cloudservers/flavors", // 这个接口有点特殊,实际只用到了list一个方法。为了简便直接把cloudservers附上。 + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_groups.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_groups.go new file mode 100644 index 0000000000..d7c13e487b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_groups.go @@ -0,0 +1,39 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SGroupManager struct { + SResourceManager +} + +func NewGroupManager(cfg manager.IManagerConfig) *SGroupManager { + m := &SGroupManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: "", + ProjectId: "", + version: "v3", + Keyword: "group", + KeywordPlural: "groups", + + ResourceKeyword: "groups", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_images.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_images.go new file mode 100644 index 0000000000..accc748714 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_images.go @@ -0,0 +1,101 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" +) + +type SImageManager struct { + SResourceManager +} + +type imageProject struct { + projectId string +} + +// image创建接口若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊) +// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID +func (self *imageProject) Process(request requests.IRequest) { + request.AddHeaderParam("X-Project-Id", self.projectId) +} + +func NewImageManager(cfg manager.IManagerConfig) *SImageManager { + var requestHook imageProject + if len(cfg.GetProjectId()) > 0 { + requestHook = imageProject{projectId: cfg.GetProjectId()} + } + + return &SImageManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager2(cfg, &requestHook), + ServiceName: ServiceNameIMS, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2", + Keyword: "image", + KeywordPlural: "images", + + ResourceKeyword: "cloudimages", + }} +} + +//https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091566.html +func (self *SImageManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { + if querys == nil { + querys = make(map[string]string, 0) + } + + querys["id"] = id + // 这里默认使用private + // if t, exists := querys["__imagetype"]; !exists || len(t) == 0 { + // querys["__imagetype"] = "private" + // } + + ret, err := self.ListInContext(nil, querys) + if err != nil { + return nil, err + } + + if ret.Data == nil || len(ret.Data) == 0 { + return nil, httperrors.NewNotFoundError("image %s not found", id) + } + + return ret.Data[0], nil +} + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092108.html +// 删除image只能用这个manager +func NewOpenstackImageManager(cfg manager.IManagerConfig) *SImageManager { + var requestHook imageProject + if len(cfg.GetProjectId()) > 0 { + requestHook = imageProject{projectId: cfg.GetProjectId()} + } + + return &SImageManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager2(cfg, &requestHook), + ServiceName: ServiceNameIMS, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2", + Keyword: "image", + KeywordPlural: "images", + + ResourceKeyword: "images", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_interface.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_interface.go new file mode 100644 index 0000000000..a6c8cf5ae6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_interface.go @@ -0,0 +1,38 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SInterfaceManager struct { + SResourceManager +} + +// 不建议使用 +func NewInterfaceManager(cfg manager.IManagerConfig) *SInterfaceManager { + return &SInterfaceManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "interfaceAttachment", + KeywordPlural: "interfaceAttachments", + + ResourceKeyword: "os-interface", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_jobs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_jobs.go new file mode 100644 index 0000000000..dbf18df310 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_jobs.go @@ -0,0 +1,71 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type SJobManager struct { + SResourceManager +} + +func NewJobManager(cfg manager.IManagerConfig) *SJobManager { + return &SJobManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: "", + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "", + KeywordPlural: "", + + ResourceKeyword: "jobs", + }} +} + +func (self *SJobManager) Get(id string, querys map[string]string) (jsonutils.JSONObject, error) { + processedQuery, err := self.processQueryParam(querys) + if err != nil { + return nil, err + } + + return self.GetInContext(nil, id, processedQuery) +} + +func (self *SJobManager) List(querys map[string]string) (*responses.ListResult, error) { + processedQuery, err := self.processQueryParam(querys) + if err != nil { + return nil, err + } + return self.ListInContext(nil, processedQuery) +} + +// 兼容查询不同ServiceName服务的Job做的特殊处理。 +func (self *SJobManager) processQueryParam(querys map[string]string) (map[string]string, error) { + service_type, exists := querys["service_type"] + if !exists { + return querys, fmt.Errorf("must specific query parameter `service_type`. e.g. ecs|ims|iam") + } + + self.ServiceName = ServiceNameType(service_type) + delete(querys, "service_type") + return querys, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_keypairs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_keypairs.go new file mode 100644 index 0000000000..b25b4e33c8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_keypairs.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SKeypairManager struct { + SResourceManager +} + +func NewKeypairManager(cfg manager.IManagerConfig) *SKeypairManager { + return &SKeypairManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "keypair", + KeywordPlural: "keypairs", + + ResourceKeyword: "os-keypairs", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_mapping.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_mapping.go new file mode 100644 index 0000000000..deb59aea3f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_mapping.go @@ -0,0 +1,39 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SAMLProviderMappingManager struct { + SResourceManager +} + +func NewSAMLProviderMappingManager(cfg manager.IManagerConfig) *SAMLProviderMappingManager { + m := &SAMLProviderMappingManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: "", + ProjectId: "", + version: "v3/OS-FEDERATION", + Keyword: "mapping", + KeywordPlural: "mappings", + + ResourceKeyword: "mappings", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_natgateway.go new file mode 100644 index 0000000000..2b586cfd2b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_natgateway.go @@ -0,0 +1,50 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" +) + +type SNatGatewayManager struct { + SResourceManager +} + +type sProjectHook struct { + projectId string +} + +func (self *sProjectHook) Process(request requests.IRequest) { + request.AddHeaderParam("X-Project-Id", self.projectId) +} + +func NewNatGatewayManager(cfg manager.IManagerConfig) *SNatGatewayManager { + man := &SNatGatewayManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameNAT, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2.0", + Keyword: "nat_gateway", + KeywordPlural: "nat_gateways", + + ResourceKeyword: "nat_gateways", + }} + if len(cfg.GetProjectId()) > 0 { + man.requestHook = &sProjectHook{cfg.GetProjectId()} + } + return man +} diff --git a/pkg/multicloud/huawei/client/modules/mod_orders.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_orders.go similarity index 96% rename from pkg/multicloud/huawei/client/modules/mod_orders.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_orders.go index ef83fcb8cf..405b4880d1 100644 --- a/pkg/multicloud/huawei/client/modules/mod_orders.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_orders.go @@ -19,8 +19,8 @@ import ( "yunion.io/x/jsonutils" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/responses" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" ) // domian 客户账号ID https://support.huaweicloud.com/oce_faq/zh-cn_topic_0113714840.html diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_port.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_port.go new file mode 100644 index 0000000000..37b3feecb2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_port.go @@ -0,0 +1,53 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" +) + +type SPortManager struct { + SResourceManager +} + +type portProject struct { + projectId string +} + +// port接口查询时若非默认project,需要在header中指定X-Project-ID。url中未携带project信息(与其他接口相比有一点特殊) +// 绕过了ResourceManager中的projectid。直接在发送json请求前注入X-Project-ID +func (self *portProject) Process(request requests.IRequest) { + request.AddHeaderParam("X-Project-Id", self.projectId) +} + +func NewPortManager(cfg manager.IManagerConfig) *SPortManager { + var requestHook portProject + if len(cfg.GetProjectId()) > 0 { + requestHook = portProject{projectId: cfg.GetProjectId()} + } + + return &SPortManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager2(cfg, &requestHook), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "port", + KeywordPlural: "ports", + + ResourceKeyword: "ports", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_projects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_projects.go new file mode 100644 index 0000000000..2544b7ef24 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_projects.go @@ -0,0 +1,89 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type SProjectManager struct { + SResourceManager +} + +func NewProjectManager(cfg manager.IManagerConfig) *SProjectManager { + m := &SProjectManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: "", + ProjectId: "", + version: "v3", + Keyword: "project", + KeywordPlural: "projects", + + ResourceKeyword: "projects", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} + +func (manager *SProjectManager) ListRoles(projectId, groupId string) (*responses.ListResult, error) { + if len(projectId) == 0 { + return nil, fmt.Errorf("missing projectId") + } + if len(groupId) == 0 { + return nil, fmt.Errorf("missing groupId") + } + res := fmt.Sprintf("%s/groups/%s/roles", projectId, groupId) + return manager.ListInContextWithSpec(nil, res, nil, "roles") +} + +func (manager *SProjectManager) DeleteProjectRole(projectId, groupId, roleId string) error { + if len(projectId) == 0 { + return fmt.Errorf("missing projectId") + } + if len(groupId) == 0 { + return fmt.Errorf("missing groupId") + } + if len(roleId) == 0 { + return fmt.Errorf("missing roleId") + } + res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) + _, err := manager.DeleteInContextWithSpec(nil, projectId, res, nil, nil, "") + if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return err +} + +func (manager *SProjectManager) AddProjectRole(projectId string, groupId, roleId string) error { + if len(projectId) == 0 { + return fmt.Errorf("missing projectId") + } + if len(groupId) == 0 { + return fmt.Errorf("missing groupId") + } + if len(roleId) == 0 { + return fmt.Errorf("missing roleId") + } + res := fmt.Sprintf("groups/%s/roles/%s", groupId, roleId) + _, err := manager.UpdateInContextWithSpec(nil, projectId, res, nil, "") + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_quotas.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_quotas.go new file mode 100644 index 0000000000..e7a488a828 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_quotas.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SQuotaManager struct { + SResourceManager +} + +func NewQuotaManager(cfg manager.IManagerConfig) *SQuotaManager { + return &SQuotaManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameEVS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "quotas", + KeywordPlural: "quotas", + + ResourceKeyword: "quotas", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_regions.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_regions.go new file mode 100644 index 0000000000..a3a75dc369 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_regions.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SRegionManager struct { + SResourceManager +} + +func NewRegionManager(cfg manager.IManagerConfig) *SRegionManager { + return &SRegionManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: "", + ProjectId: "", + version: "v3", + Keyword: "region", + KeywordPlural: "regions", + + ResourceKeyword: "regions", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_roles.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_roles.go new file mode 100644 index 0000000000..75b375edf9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_roles.go @@ -0,0 +1,39 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SRoleManager struct { + SResourceManager +} + +func NewRoleManager(cfg manager.IManagerConfig) *SRoleManager { + m := &SRoleManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: "", + ProjectId: "", + version: "v3", + Keyword: "role", + KeywordPlural: "roles", + + ResourceKeyword: "roles", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} diff --git a/pkg/multicloud/huawei/client/modules/mod_routetables.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_routetables.go similarity index 94% rename from pkg/multicloud/huawei/client/modules/mod_routetables.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_routetables.go index 248f62680f..ebfd1ce5a9 100644 --- a/pkg/multicloud/huawei/client/modules/mod_routetables.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_routetables.go @@ -15,7 +15,7 @@ package modules import ( - "yunion.io/x/onecloud/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" ) type SRouteTableManager struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_saml_provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_saml_provider.go new file mode 100644 index 0000000000..9e24b35048 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_saml_provider.go @@ -0,0 +1,39 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SAMLProviderManager struct { + SResourceManager +} + +func NewSAMLProviderManager(cfg manager.IManagerConfig) *SAMLProviderManager { + m := &SAMLProviderManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: "", + ProjectId: "", + version: "v3/OS-FEDERATION", + Keyword: "identity_provider", + KeywordPlural: "identity_providers", + + ResourceKeyword: "identity_providers", + }} + m.SetDomainId(cfg.GetDomainId()) + return m +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_secgroup_rules.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_secgroup_rules.go new file mode 100644 index 0000000000..5e4223f29e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_secgroup_rules.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SSecgroupRuleManager struct { + SResourceManager +} + +func NewSecgroupRuleManager(cfg manager.IManagerConfig) *SSecgroupRuleManager { + return &SSecgroupRuleManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "security_group_rule", + KeywordPlural: "security_group_rules", + + ResourceKeyword: "security-group-rules", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_secgroups.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_secgroups.go new file mode 100644 index 0000000000..477f0ac64b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_secgroups.go @@ -0,0 +1,51 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SSecurityGroupManager struct { + SResourceManager +} + +func NewSecurityGroupManager(cfg manager.IManagerConfig) *SSecurityGroupManager { + return &SSecurityGroupManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "security_group", + KeywordPlural: "security_groups", + + ResourceKeyword: "security-groups", + }} +} + +func NewNovaSecurityGroupManager(cfg manager.IManagerConfig) *SSecurityGroupManager { + return &SSecurityGroupManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2.1", + Keyword: "security_group", + KeywordPlural: "security_groups", + + ResourceKeyword: "os-security-groups", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_servers.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_servers.go new file mode 100644 index 0000000000..fd33dc8805 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_servers.go @@ -0,0 +1,124 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + "strconv" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type SServerManager struct { + SResourceManager +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212668.html +// v.1.1 新增支持创建包年/包月的弹性云服务器。!!但是不支持查询等调用 https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html +func NewServerManager(cfg manager.IManagerConfig) *SServerManager { + return &SServerManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "server", + KeywordPlural: "servers", + + ResourceKeyword: "cloudservers", + }} +} + +func (self *SServerManager) List(querys map[string]string) (*responses.ListResult, error) { + if offset, exists := querys["offset"]; !exists { + // 华为云分页参数各式各样。cloudserver offset从1开始。部分其他接口从0开始。 + // 另外部分接口使用pager分页 或者 maker分页 + querys["offset"] = "1" + } else { + n, err := strconv.Atoi(offset) + if err != nil { + return nil, fmt.Errorf("offset is invalid: %s", offset) + } + querys["offset"] = strconv.Itoa(n + 1) + } + return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) +} + +/* +返回job id 或者 order id + +https://support.huaweicloud.com/api-ecs/zh-cn_topic_0093055772.html +创建按需的弹性云服务 ——> job_id 任务ID (返回数据uuid举例:"70a599e0-31e7-49b7-b260-868f441e862b") +包年包月机器 --> order_id (返回数据举例: "CS1711152257C60TL") +*/ +func (self *SServerManager) AsyncCreate(params jsonutils.JSONObject) (string, error) { + origin_version := self.version + self.version = "v1.1" + defer func() { self.version = origin_version }() + + ret, err := self.CreateInContextWithSpec(nil, "", params, "") + if err != nil { + log.Debugf("AsyncCreate %s", err) + return "", err + } + + log.Debugf("AsyncCreate result %s", ret.String()) + // 按需机器 + jobId, err := ret.GetString("job_id") + if err == nil { + return jobId, nil + } + + // 包年包月机器 + return ret.GetString("order_id") +} + +func (self *SServerManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return nil, fmt.Errorf("not supported.please use AsyncCreate") +} + +// 不推荐使用这个manager +func NewNovaServerManager(cfg manager.IManagerConfig) *SServerManager { + return &SServerManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2.1", + Keyword: "server", + KeywordPlural: "servers", + + ResourceKeyword: "servers", + }} +} + +// 重装弹性云服务器操作系统(安装Cloud-init),请用这个manager +func NewServerV2Manager(cfg manager.IManagerConfig) *SServerManager { + return &SServerManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "server", + KeywordPlural: "servers", + + ResourceKeyword: "cloudservers", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_sfs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_sfs.go new file mode 100644 index 0000000000..e56161ebd1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_sfs.go @@ -0,0 +1,48 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type SfsTurboManager struct { + SResourceManager +} + +func NewSfsTurboManager(cfg manager.IManagerConfig) *SfsTurboManager { + return &SfsTurboManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameSFSTurbo, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "", + KeywordPlural: "shares", + + ResourceKeyword: "sfs-turbo/shares", + }} +} + +func (self *SfsTurboManager) List(querys map[string]string) (*responses.ListResult, error) { + return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) +} + +func (self *SfsTurboManager) Create(params jsonutils.JSONObject) (jsonutils.JSONObject, error) { + return self.CreateInContextWithSpec(self.ctx, "", params, "") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snapshots.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snapshots.go new file mode 100644 index 0000000000..24f801448c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snapshots.go @@ -0,0 +1,59 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type SSnapshotManager struct { + SResourceManager +} + +func NewSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager { + return &SSnapshotManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameEVS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "snapshot", + KeywordPlural: "snapshots", + + ResourceKeyword: "snapshots", + }} +} + +func (self *SSnapshotManager) List(querys map[string]string) (*responses.ListResult, error) { + return self.ListInContextWithSpec(nil, "detail", querys, self.KeywordPlural) +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html +// 回滚快照只能用这个manger。其他情况请不要使用 +// 另外,香港-亚太还支持另外一个接口。https://support.huaweicloud.com/api-evs/zh-cn_topic_0142374138.html +func NewOsSnapshotManager(cfg manager.IManagerConfig) *SSnapshotManager { + return &SSnapshotManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameEVS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "snapshot", + KeywordPlural: "snapshots", + + ResourceKeyword: "os-vendor-snapshots", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snat_rules.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snat_rules.go new file mode 100644 index 0000000000..82f818ea14 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_snat_rules.go @@ -0,0 +1,41 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SNatSRuleManager struct { + SResourceManager +} + +func NewNatSManager(cfg manager.IManagerConfig) *SNatSRuleManager { + man := &SNatSRuleManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameNAT, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2.0", + Keyword: "snat_rule", + KeywordPlural: "snat_rules", + + ResourceKeyword: "snat_rules", + }} + if len(cfg.GetProjectId()) > 0 { + man.requestHook = &sProjectHook{cfg.GetProjectId()} + } + return man +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_subnets.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_subnets.go new file mode 100644 index 0000000000..99bef6ab13 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_subnets.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SSubnetManager struct { + SResourceManager +} + +func NewSubnetManager(cfg manager.IManagerConfig) *SSubnetManager { + return &SSubnetManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "subnet", + KeywordPlural: "subnets", + + ResourceKeyword: "subnets", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_traces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_traces.go new file mode 100644 index 0000000000..d46d15b47e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_traces.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type STraceManager struct { + SResourceManager +} + +func NewTraceManager(cfg manager.IManagerConfig) *STraceManager { + return &STraceManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameCTS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2.0", + Keyword: "trace", + KeywordPlural: "traces", + + ResourceKeyword: "system/trace", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_users.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_users.go new file mode 100644 index 0000000000..e7bb96bae0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_users.go @@ -0,0 +1,69 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" +) + +type SUserManager struct { + SResourceManager +} + +func NewUserManager(cfg manager.IManagerConfig) *SUserManager { + user := &SUserManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameIAM, + Region: "", + ProjectId: "", + version: "v3.0/OS-USER", + Keyword: "user", + KeywordPlural: "users", + + ResourceKeyword: "users", + }} + user.SetDomainId(cfg.GetDomainId()) + return user +} + +func (self *SUserManager) List(querys map[string]string) (*responses.ListResult, error) { + self.SetVersion("v3") + return self.SResourceManager.List(querys) +} + +func (self *SUserManager) Delete(id string) (jsonutils.JSONObject, error) { + self.SetVersion("v3") + return self.SResourceManager.Delete(id, nil) +} + +func (self *SUserManager) ResetPassword(id, password string) error { + params := map[string]interface{}{ + "user": map[string]string{ + "password": password, + }, + } + _, err := self.SResourceManager.Update(id, jsonutils.Marshal(params)) + return err +} + +func (self *SUserManager) ListGroups(userId string) (*responses.ListResult, error) { + self.SetVersion("v3") + return self.SResourceManager.ListInContextWithSpec(nil, fmt.Sprintf("%s/groups", userId), nil, "groups") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go new file mode 100644 index 0000000000..35b5b78d3b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_peerings.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SVpcPeeringManager struct { + SResourceManager +} + +func NewVpcPeeringManager(cfg manager.IManagerConfig) *SVpcPeeringManager { + return &SVpcPeeringManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: "", + version: "v2.0", + Keyword: "peering", + KeywordPlural: "peerings", + + ResourceKeyword: "vpc/peerings", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_routes.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_routes.go new file mode 100644 index 0000000000..493c934edd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpc_routes.go @@ -0,0 +1,38 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SVpcRouteManager struct { + SResourceManager +} + +func NewVpcRouteManager(cfg manager.IManagerConfig) *SVpcRouteManager { + return &SVpcRouteManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + // the url should not include the field "projectid" in huawei cloud api v2.0 + ProjectId: "", + version: "v2.0", + Keyword: "route", + KeywordPlural: "routes", + + ResourceKeyword: "vpc/routes", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpcs.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpcs.go new file mode 100644 index 0000000000..11b218cefb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_vpcs.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SVpcManager struct { + SResourceManager +} + +func NewVpcManager(cfg manager.IManagerConfig) *SVpcManager { + return &SVpcManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameVPC, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v1", + Keyword: "vpc", + KeywordPlural: "vpcs", + + ResourceKeyword: "vpcs", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_zones.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_zones.go new file mode 100644 index 0000000000..25f783ae26 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules/mod_zones.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 modules + +import ( + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" +) + +type SZoneManager struct { + SResourceManager +} + +func NewZoneManager(cfg manager.IManagerConfig) *SZoneManager { + return &SZoneManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(cfg), + ServiceName: ServiceNameECS, + Region: cfg.GetRegionId(), + ProjectId: cfg.GetProjectId(), + version: "v2", + Keyword: "availabilityZoneInfo", + KeywordPlural: "availabilityZoneInfo", + + ResourceKeyword: "os-availability-zone", + }} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/doc.go new file mode 100644 index 0000000000..1efcc36222 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 requests // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests" diff --git a/pkg/multicloud/huawei/client/requests/requests.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/requests.go similarity index 100% rename from pkg/multicloud/huawei/client/requests/requests.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/requests/requests.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/doc.go new file mode 100644 index 0000000000..64028392cf --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 responses // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" diff --git a/pkg/multicloud/huawei/client/responses/responses.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/responses.go similarity index 100% rename from pkg/multicloud/huawei/client/responses/responses.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses/responses.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/cloudgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/cloudgroup.go new file mode 100644 index 0000000000..ed0363eee4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/cloudgroup.go @@ -0,0 +1,465 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SCloudgroup struct { + client *SHuaweiClient + Name string + Description string + Id string + CreateTime string +} + +func (group *SCloudgroup) GetName() string { + return group.Name +} + +func (group *SCloudgroup) GetDescription() string { + return group.Description +} + +func (group *SCloudgroup) GetGlobalId() string { + return group.Id +} + +func (group *SCloudgroup) Delete() error { + return group.client.DeleteGroup(group.Id) +} + +func (group *SCloudgroup) AddUser(name string) error { + user, err := group.client.GetIClouduserByName(name) + if err != nil { + return errors.Wrap(err, "GetIClouduserByName") + } + return group.client.AddUserToGroup(group.Id, user.GetGlobalId()) +} + +func (group *SCloudgroup) RemoveUser(name string) error { + user, err := group.client.GetIClouduserByName(name) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return errors.Wrapf(err, "GetIClouduserByName(%s)", name) + } + return group.client.RemoveUserFromGroup(group.Id, user.GetGlobalId()) +} + +func (group *SCloudgroup) DetachSystemPolicy(roleId string) error { + return group.client.DetachGroupRole(group.Id, roleId) +} + +func (group *SCloudgroup) DetachCustomPolicy(roleId string) error { + return group.client.DetachGroupCustomRole(group.Id, roleId) +} + +func (group *SCloudgroup) AttachSystemPolicy(roleId string) error { + return group.client.AttachGroupRole(group.Id, roleId) +} + +func (group *SCloudgroup) AttachCustomPolicy(roleId string) error { + return group.client.AttachGroupCustomRole(group.Id, roleId) +} + +func (group *SCloudgroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + roles, err := group.client.GetGroupRoles(group.Id) + if err != nil { + return nil, errors.Wrap(err, "GetGroupRoles") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range roles { + _, err := group.client.GetRole(roles[i].GetName()) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + continue + } + return nil, errors.Wrapf(err, "GetRole(%s)", roles[i].GetName()) + } + ret = append(ret, &roles[i]) + } + return ret, nil +} + +func (group *SCloudgroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + roles, err := group.client.GetGroupRoles(group.Id) + if err != nil { + return nil, errors.Wrap(err, "GetGroupRoles") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range roles { + _, err := group.client.GetCustomRole(roles[i].GetName()) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + continue + } + return nil, errors.Wrapf(err, "GetRole(%s)", roles[i].GetName()) + } + ret = append(ret, &roles[i]) + } + return ret, nil +} + +func (group *SCloudgroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { + users, err := group.client.GetGroupUsers(group.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.IClouduser{} + for i := range users { + users[i].client = group.client + ret = append(ret, &users[i]) + } + return ret, nil +} + +func (self *SHuaweiClient) GetGroups(domainId, name string) ([]SCloudgroup, error) { + params := map[string]string{} + if len(domainId) > 0 { + params["domain_id"] = self.ownerId + } + if len(name) > 0 { + params["name"] = name + } + + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + + groups := []SCloudgroup{} + err = doListAllWithNextLink(client.Groups.List, params, &groups) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithOffset") + } + return groups, nil +} + +func (self *SHuaweiClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + groups, err := self.GetGroups("", "") + if err != nil { + return nil, errors.Wrap(err, "GetGroup") + } + ret := []cloudprovider.ICloudgroup{} + for i := range groups { + if groups[i].Name != "admin" { + groups[i].client = self + ret = append(ret, &groups[i]) + } + } + return ret, nil +} + +func (self *SHuaweiClient) GetGroupUsers(groupId string) ([]SClouduser, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + + resp, err := client.Groups.ListInContextWithSpec(nil, fmt.Sprintf("%s/users", groupId), nil, "users") + if err != nil { + return nil, errors.Wrap(err, "") + } + users := []SClouduser{} + err = jsonutils.Update(&users, resp.Data) + if err != nil { + return nil, errors.Wrap(err, "jsonutils.Update") + } + return users, nil +} + +func (self *SHuaweiClient) GetGroupRoles(groupId string) ([]SRole, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + resp, err := client.Domains.ListRoles(self.ownerId, groupId) + if err != nil { + return nil, errors.Wrap(err, "ListRoles") + } + roles := []SRole{} + err = jsonutils.Update(&roles, resp.Data) + if err != nil { + return nil, errors.Wrap(err, "jsonutils.Update") + } + return roles, nil +} + +func (self *SHuaweiClient) CreateGroup(name, desc string) (*SCloudgroup, error) { + params := map[string]string{ + "name": name, + } + if len(desc) > 0 { + params["description"] = desc + } + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + + group := SCloudgroup{client: self} + err = DoCreate(client.Groups.Create, jsonutils.Marshal(map[string]interface{}{"group": params}), &group) + if err != nil { + return nil, errors.Wrap(err, "DoCreate") + } + return &group, nil +} + +func (self *SHuaweiClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + group, err := self.CreateGroup(name, desc) + if err != nil { + return nil, errors.Wrap(err, "CreateGroup") + } + return group, nil +} + +func (self *SHuaweiClient) DeleteGroup(id string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + return DoDeleteWithSpec(client.Groups.DeleteInContextWithSpec, nil, id, "", nil, nil) +} + +func (self *SHuaweiClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + groups, err := self.GetGroups(self.ownerId, name) + if err != nil { + return nil, errors.Wrap(err, "GetGroups") + } + if len(groups) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(groups) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + groups[0].client = self + return &groups[0], nil +} + +func (self *SHuaweiClient) AddUserToGroup(groupId, userId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + _, err = client.Groups.UpdateInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, "") + return err +} + +func (self *SHuaweiClient) RemoveUserFromGroup(groupId, userId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + _, err = client.Groups.DeleteInContextWithSpec(nil, groupId, fmt.Sprintf("users/%s", userId), nil, nil, "") + return err +} + +func (self *SHuaweiClient) GetCustomRoles() ([]SRole, error) { + params := map[string]string{} + + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + + client.Roles.SetVersion("v3.0/OS-ROLE") + defer client.Roles.SetVersion("v3.0") + + roles := []SRole{} + err = doListAllWithNextLink(client.Roles.List, params, &roles) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithOffset") + } + return roles, nil +} + +func (self *SHuaweiClient) GetCustomRole(name string) (*SRole, error) { + roles, err := self.GetCustomRoles() + if err != nil { + return nil, errors.Wrapf(err, "GetCustomRoles(%s)", name) + } + for i := range roles { + if roles[i].DisplayName == name { + return &roles[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) +} + +func (self *SHuaweiClient) GetRole(name string) (*SRole, error) { + roles, err := self.GetRoles("", "") + if err != nil { + return nil, errors.Wrapf(err, "GetRoles(%s)", name) + } + for i := range roles { + if roles[i].DisplayName == name { + return &roles[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) +} + +func (self *SHuaweiClient) DetachGroupRole(groupId, roleId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + role, err := self.GetRole(roleId) + if err != nil { + return errors.Wrapf(err, "GetRole(%s)", roleId) + } + if role.Type == "AX" || role.Type == "AA" { + err = client.Domains.AddRole(self.ownerId, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddRole") + } + if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { + err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddProjectRole") + } + } + } + if role.Type == "XA" || role.Type == "AA" { + projects, err := self.GetProjects() + if err != nil { + return errors.Wrapf(err, "GetProjects") + } + for _, project := range projects { + err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddProjectRole") + } + } + } + return nil +} + +func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + role, err := self.GetRole(roleId) + if err != nil { + return errors.Wrapf(err, "GetRole(%s)", roleId) + } + if role.Type == "AX" || role.Type == "AA" { + err = client.Domains.AddRole(self.ownerId, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddRole") + } + if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { + err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddProjectRole") + } + } + } + if role.Type == "XA" || role.Type == "AA" { + projects, err := self.GetProjects() + if err != nil { + return errors.Wrapf(err, "GetProjects") + } + for _, project := range projects { + err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddProjectRole") + } + } + } + return nil +} + +func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + role, err := self.GetCustomRole(roleId) + if err != nil { + return errors.Wrapf(err, "GetRole(%s)", roleId) + } + if role.Type == "AX" || role.Type == "AA" { + err = client.Domains.AddRole(self.ownerId, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddRole") + } + if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { + err = client.Projects.AddProjectRole(self.GetMosProjectId(), groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddProjectRole") + } + } + } + if role.Type == "XA" || role.Type == "AA" { + projects, err := self.GetProjects() + if err != nil { + return errors.Wrapf(err, "GetProjects") + } + for _, project := range projects { + err = client.Projects.AddProjectRole(project.ID, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "AddProjectRole") + } + } + } + return nil +} + +func (self *SHuaweiClient) DetachGroupCustomRole(groupId, roleId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + role, err := self.GetCustomRole(roleId) + if err != nil { + return errors.Wrapf(err, "GetCustomRole(%s)", roleId) + } + if role.Type == "AX" || role.Type == "AA" { + err = client.Domains.DeleteRole(self.ownerId, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "DeleteRole") + } + if strings.Contains(strings.ToLower(role.Policy.String()), "obs") { + err = client.Projects.DeleteProjectRole(self.GetMosProjectId(), groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "DeleteProjectRole") + } + } + } + if role.Type == "XA" || role.Type == "AA" { + projects, err := self.GetProjects() + if err != nil { + return errors.Wrapf(err, "GetProjects") + } + for _, project := range projects { + err = client.Projects.DeleteProjectRole(project.ID, groupId, role.Id) + if err != nil { + return errors.Wrapf(err, "DeleteProjectRole") + } + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/clouduser.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/clouduser.go new file mode 100644 index 0000000000..ece27cd320 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/clouduser.go @@ -0,0 +1,289 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" +) + +type SLink struct { + Next string + Previous string + Self string +} + +type SClouduser struct { + client *SHuaweiClient + + Description string + DomainId string + Enabled bool + ForceResetPwd bool + Id string + LastProjectId string + Links SLink + Name string + PasswordExpiresAt string + PwdStatus bool +} + +func (user *SClouduser) GetGlobalId() string { + return user.Id +} + +func (user *SClouduser) GetName() string { + return user.Name +} + +func (user *SClouduser) GetEmailAddr() string { + return "" +} + +func (user *SClouduser) GetInviteUrl() string { + return "" +} + +func (user *SClouduser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return []cloudprovider.ICloudpolicy{}, nil +} + +func (user *SClouduser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return []cloudprovider.ICloudpolicy{}, nil +} + +func (user *SClouduser) AttachSystemPolicy(policyType string) error { + return cloudprovider.ErrNotSupported +} + +func (user *SClouduser) AttachCustomPolicy(policyType string) error { + return cloudprovider.ErrNotSupported +} + +func (user *SClouduser) DetachSystemPolicy(policyId string) error { + return cloudprovider.ErrNotSupported +} + +func (user *SClouduser) DetachCustomPolicy(policyId string) error { + return cloudprovider.ErrNotSupported +} + +func (user *SClouduser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + groups, err := user.client.ListUserGroups(user.Id) + if err != nil { + return nil, errors.Wrap(err, "Users.ListGroups") + } + ret := []cloudprovider.ICloudgroup{} + for i := range groups { + groups[i].client = user.client + ret = append(ret, &groups[i]) + } + return ret, nil +} + +func (user *SClouduser) Delete() error { + return user.client.DeleteClouduser(user.Id) +} + +func (user *SClouduser) IsConsoleLogin() bool { + return user.Enabled == true +} + +func (user *SClouduser) ResetPassword(password string) error { + return user.client.ResetClouduserPassword(user.Id, password) +} + +func (self *SHuaweiClient) DeleteClouduser(id string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + _, err = client.Users.Delete(id) + return err +} + +func (self *SHuaweiClient) ListUserGroups(userId string) ([]SCloudgroup, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + result, err := client.Users.ListGroups(userId) + if err != nil { + return nil, errors.Wrap(err, "Users.ListGroups") + } + groups := []SCloudgroup{} + err = jsonutils.Update(&groups, result.Data) + if err != nil { + return nil, errors.Wrap(err, "jsonutils.Update") + } + return groups, nil +} + +func (self *SHuaweiClient) GetCloudusers(name string) ([]SClouduser, error) { + params := map[string]string{} + if len(name) > 0 { + params["name"] = name + } + users := []SClouduser{} + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + err = doListAllWithOffset(client.Users.List, params, &users) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithOffset") + } + return users, nil +} + +func (self *SHuaweiClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { + users, err := self.GetCloudusers("") + if err != nil { + return nil, errors.Wrap(err, "GetCloudusers") + } + iUsers := []cloudprovider.IClouduser{} + for i := range users { + if users[i].Name != self.ownerName { + users[i].client = self + iUsers = append(iUsers, &users[i]) + } + } + return iUsers, nil +} + +func (self *SHuaweiClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + users, err := self.GetCloudusers(name) + if err != nil { + return nil, errors.Wrapf(err, "GetCloudusers(%s)", name) + } + if len(users) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(users) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + users[0].client = self + return &users[0], nil +} + +func (self *SHuaweiClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + return self.CreateClouduser(conf.Name, conf.Password, conf.Desc) +} + +func (self *SHuaweiClient) CreateClouduser(name, password, desc string) (*SClouduser, error) { + params := map[string]string{ + "name": name, + "domain_id": self.ownerId, + } + if len(password) > 0 { + params["password"] = password + } + if len(desc) > 0 { + params["description"] = desc + } + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + user := SClouduser{client: self} + err = DoCreate(client.Users.Create, jsonutils.Marshal(map[string]interface{}{"user": params}), &user) + if err != nil { + ce, ok := err.(*modules.HuaweiClientError) + if ok && len(ce.Errorcode) > 0 && ce.Errorcode[0] == "1101" { + return nil, errors.Wrap(err, `IAM user name. The length is between 5 and 32. The first digit is not a number. Special characters can only contain the '_' '-' or ' '`) //https://support.huaweicloud.com/api-iam/iam_08_0015.html + } + return nil, errors.Wrap(err, "DoCreate") + } + return &user, nil +} + +func (self *SHuaweiClient) ResetClouduserPassword(id, password string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + return client.Users.ResetPassword(id, password) +} + +type SAccessKey struct { + client *SHuaweiClient + + AccessKey string `json:"access"` + Secret string `json:"secret"` + Description string `json:"description"` + Status string `json:"status"` + CreatedAt time.Time `json:"create_time"` +} + +func (self *SHuaweiClient) GetAKSK(id string) ([]cloudprovider.SAccessKey, error) { + obj, err := self.getAKSKList(id) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.getAKSKList") + } + aks := make([]SAccessKey, 0) + obj.Unmarshal(&aks, "credentials") + res := make([]cloudprovider.SAccessKey, len(aks)) + for i := 0; i < len(aks); i++ { + res[i].Name = aks[i].Description + res[i].AccessKey = aks[i].AccessKey + res[i].Secret = aks[i].Secret + res[i].Status = aks[i].Status + res[i].CreatedAt = aks[i].CreatedAt + } + return res, nil +} + +func (self *SHuaweiClient) CreateAKSK(id, name string) (*cloudprovider.SAccessKey, error) { + params := map[string]interface{}{ + "credential": map[string]interface{}{ + "user_id": id, + "description": name, + }, + } + obj, err := self.createAKSK(params) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.createAKSK") + } + ak := SAccessKey{} + obj.Unmarshal(&ak, "credential") + res := cloudprovider.SAccessKey{ + Name: ak.Description, + AccessKey: ak.AccessKey, + Secret: ak.Secret, + } + return &res, nil +} + +func (self *SHuaweiClient) DeleteAKSK(accessKey string) error { + _, err := self.deleteAKSK(accessKey) + return err +} + +func (user *SClouduser) DeleteAccessKey(accessKey string) error { + return user.client.DeleteAKSK(accessKey) +} + +func (user *SClouduser) CreateAccessKey(name string) (*cloudprovider.SAccessKey, error) { + return user.client.CreateAKSK(user.Id, name) +} + +func (user *SClouduser) GetAccessKeys() ([]cloudprovider.SAccessKey, error) { + return user.client.GetAKSK(user.Id) +} diff --git a/pkg/multicloud/huawei/consts.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/consts.go similarity index 100% rename from pkg/multicloud/huawei/consts.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/consts.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance.go new file mode 100644 index 0000000000..cfa00f7459 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance.go @@ -0,0 +1,780 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "fmt" + "time" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SBackupStrategy struct { + KeepDays int + StartTime string +} + +type SDatastore struct { + Type string + Version string +} + +type SHa struct { + ReplicationMode string +} + +type SNonde struct { + AvailabilityZone string + Id string + Name string + Role string + Staus string +} + +type SVolume struct { + Size int + Type string +} + +type SRelatedInstance struct { + Id string + Type string +} + +type SDBInstance struct { + multicloud.SDBInstanceBase + HuaweiTags + region *SRegion + + flavorCache []SDBInstanceFlavor + BackupStrategy SBackupStrategy + Created string //time.Time + Datastore SDatastore + DbUserName string + DIskEncryptionId string + FlavorRef string + Ha SHa + Id string + MaintenanceWindow string + MaxIops int + Name string + Nodes []SNonde + Port int + PrivateIps []string + PublicIps []string + Region string + RelatedInstance []SRelatedInstance + SecurityGroupId string + Status string + SubnetId string + SwitchStrategy string + TimeZone string + Type string + Updated string //time.Time + Volume SVolume + VpcId string + EnterpriseProjectId string +} + +func (region *SRegion) GetDBInstances() ([]SDBInstance, error) { + params := map[string]string{} + dbinstances := []SDBInstance{} + err := doListAllWithOffset(region.ecsClient.DBInstance.List, params, &dbinstances) + return dbinstances, err +} + +func (region *SRegion) GetDBInstance(instanceId string) (*SDBInstance, error) { + if len(instanceId) == 0 { + return nil, cloudprovider.ErrNotFound + } + instance := SDBInstance{region: region} + err := DoGet(region.ecsClient.DBInstance.Get, instanceId, nil, &instance) + return &instance, err +} + +func (rds *SDBInstance) GetName() string { + return rds.Name +} + +func (rds *SDBInstance) GetId() string { + return rds.Id +} + +func (rds *SDBInstance) GetGlobalId() string { + return rds.GetId() +} + +// 值为“BUILD”,表示实例正在创建。 +// 值为“ACTIVE”,表示实例正常。 +// 值为“FAILED”,表示实例异常。 +// 值为“FROZEN”,表示实例冻结。 +// 值为“MODIFYING”,表示实例正在扩容。 +// 值为“REBOOTING”,表示实例正在重启。 +// 值为“RESTORING”,表示实例正在恢复。 +// 值为“MODIFYING INSTANCE TYPE”,表示实例正在转主备。 +// 值为“SWITCHOVER”,表示实例正在主备切换。 +// 值为“MIGRATING”,表示实例正在迁移。 +// 值为“BACKING UP”,表示实例正在进行备份。 +// 值为“MODIFYING DATABASE PORT”,表示实例正在修改数据库端口。 +// 值为“STORAGE FULL”,表示实例磁盘空间满。 + +func (rds *SDBInstance) GetStatus() string { + switch rds.Status { + case "BUILD", "MODIFYING", "MODIFYING INSTANCE TYPE", "SWITCHOVER", "MODIFYING DATABASE PORT": + return api.DBINSTANCE_DEPLOYING + case "ACTIVE": + return api.DBINSTANCE_RUNNING + case "FAILED", "FROZEN", "STORAGE FULL": + return api.DBINSTANCE_UNKNOWN + case "REBOOTING": + return api.DBINSTANCE_REBOOTING + case "RESTORING": + return api.DBINSTANCE_RESTORING + case "MIGRATING": + return api.DBINSTANCE_MIGRATING + case "BACKING UP": + return api.DBINSTANCE_BACKING_UP + } + return rds.Status +} + +func (rds *SDBInstance) GetBillingType() string { + _, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id)) + if err != nil { + return billing_api.BILLING_TYPE_POSTPAID + } + return billing_api.BILLING_TYPE_PREPAID +} + +func (rds *SDBInstance) GetSecurityGroupIds() ([]string, error) { + return []string{rds.SecurityGroupId}, nil +} + +func (rds *SDBInstance) fetchFlavor() error { + if len(rds.flavorCache) > 0 { + return nil + } + flavors, err := rds.region.GetDBInstanceFlavors(rds.Datastore.Type, rds.Datastore.Version) + if err != nil { + return err + } + rds.flavorCache = flavors + return nil +} + +func (rds *SDBInstance) GetExpiredAt() time.Time { + order, err := rds.region.GetOrderResourceDetail(fmt.Sprintf("%s.vm", rds.Id)) + if err != nil { + return time.Time{} + } + return order.ExpireTime +} + +func (rds *SDBInstance) GetStorageType() string { + return rds.Volume.Type +} + +func (rds *SDBInstance) GetCreatedAt() time.Time { + t, err := time.Parse("2006-01-02T15:04:05Z0700", rds.Created) + if err != nil { + return time.Time{} + } + return t +} + +func (rds *SDBInstance) GetEngine() string { + return rds.Datastore.Type +} + +func (rds *SDBInstance) GetEngineVersion() string { + return rds.Datastore.Version +} + +func (rds *SDBInstance) GetInstanceType() string { + return rds.FlavorRef +} + +func (rds *SDBInstance) GetCategory() string { + switch rds.Type { + case "Single": + return api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE + case "Ha": + return api.HUAWEI_DBINSTANCE_CATEGORY_HA + case "Replica": + return api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA + } + return rds.Type +} + +func (rds *SDBInstance) GetVcpuCount() int { + err := rds.fetchFlavor() + if err != nil { + log.Errorf("failed to fetch flavors: %v", err) + return 0 + } + for _, flavor := range rds.flavorCache { + if flavor.SpecCode == rds.FlavorRef { + return flavor.Vcpus + } + } + return 0 +} + +func (rds *SDBInstance) GetVmemSizeMB() int { + err := rds.fetchFlavor() + if err != nil { + log.Errorf("failed to fetch flavors: %v", err) + return 0 + } + for _, flavor := range rds.flavorCache { + if flavor.SpecCode == rds.FlavorRef { + return flavor.Ram * 1024 + } + } + return 0 +} + +func (rds *SDBInstance) GetDiskSizeGB() int { + return rds.Volume.Size +} + +func (rds *SDBInstance) GetPort() int { + return rds.Port +} + +func (rds *SDBInstance) GetMaintainTime() string { + return rds.MaintenanceWindow +} + +func (rds *SDBInstance) GetIVpcId() string { + return rds.VpcId +} + +func (rds *SDBInstance) GetProjectId() string { + return rds.EnterpriseProjectId +} + +func (rds *SDBInstance) Refresh() error { + instance, err := rds.region.GetDBInstance(rds.Id) + if err != nil { + return err + } + return jsonutils.Update(rds, instance) +} + +func (rds *SDBInstance) GetZone1Id() string { + return rds.GetZoneIdByRole("master") +} + +func (rds *SDBInstance) GetZoneIdByRole(role string) string { + for _, node := range rds.Nodes { + if node.Role == role { + zone, err := rds.region.getZoneById(node.AvailabilityZone) + if err != nil { + log.Errorf("failed to found zone %s for rds %s error: %v", node.AvailabilityZone, rds.Name, err) + return "" + } + return zone.GetGlobalId() + } + } + return "" +} + +func (rds *SDBInstance) GetZone2Id() string { + return rds.GetZoneIdByRole("slave") +} + +func (rds *SDBInstance) GetZone3Id() string { + return "" +} + +func (rds *SDBInstance) GetIops() int { + return rds.MaxIops +} + +type SRdsNetwork struct { + SubnetId string + IP string +} + +func (rds *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { + ret := []cloudprovider.SDBInstanceNetwork{} + for _, ip := range rds.PrivateIps { + network := cloudprovider.SDBInstanceNetwork{ + IP: ip, + NetworkId: rds.SubnetId, + } + ret = append(ret, network) + } + return ret, nil +} + +func (rds *SDBInstance) GetInternalConnectionStr() string { + for _, ip := range rds.PrivateIps { + return ip + } + return "" +} + +func (rds *SDBInstance) GetConnectionStr() string { + for _, ip := range rds.PublicIps { + return ip + } + return "" +} + +func (region *SRegion) GetIDBInstanceById(instanceId string) (cloudprovider.ICloudDBInstance, error) { + dbinstance, err := region.GetDBInstance(instanceId) + if err != nil { + log.Errorf("failed to get dbinstance by id %s error: %v", instanceId, err) + } + return dbinstance, err +} + +func (region *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { + instances, err := region.GetDBInstances() + if err != nil { + return nil, errors.Wrapf(err, "region.GetDBInstances()") + } + idbinstances := []cloudprovider.ICloudDBInstance{} + for i := 0; i < len(instances); i++ { + instances[i].region = region + idbinstances = append(idbinstances, &instances[i]) + } + return idbinstances, nil +} + +func (rds *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { + parameters, err := rds.region.GetDBInstanceParameters(rds.Id) + if err != nil { + return nil, err + } + iparameters := []cloudprovider.ICloudDBInstanceParameter{} + for i := 0; i < len(parameters); i++ { + iparameters = append(iparameters, ¶meters[i]) + } + return iparameters, nil +} + +func (rds *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { + databases, err := rds.region.GetDBInstanceDatabases(rds.Id) + if err != nil { + return nil, errors.Wrap(err, "rds.region.GetDBInstanceDatabases(rds.Id)") + } + + idatabase := []cloudprovider.ICloudDBInstanceDatabase{} + for i := 0; i < len(databases); i++ { + databases[i].instance = rds + idatabase = append(idatabase, &databases[i]) + } + return idatabase, nil +} + +func (rds *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { + accounts, err := rds.region.GetDBInstanceAccounts(rds.Id) + if err != nil { + return nil, errors.Wrap(err, "rds.region.GetDBInstanceAccounts(rds.Id)") + } + + user := "root" + if rds.GetEngine() == api.DBINSTANCE_TYPE_SQLSERVER { + user = "rduser" + } + + accounts = append(accounts, SDBInstanceAccount{ + Name: user, + instance: rds, + }) + + iaccounts := []cloudprovider.ICloudDBInstanceAccount{} + for i := 0; i < len(accounts); i++ { + accounts[i].instance = rds + iaccounts = append(iaccounts, &accounts[i]) + } + return iaccounts, nil +} + +func (rds *SDBInstance) Delete() error { + return rds.region.DeleteDBInstance(rds.Id) +} + +func (region *SRegion) DeleteDBInstance(instanceId string) error { + _, err := region.ecsClient.DBInstance.Delete(instanceId, nil) + return err +} + +func (region *SRegion) CreateIDBInstance(desc *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + zoneIds := []string{} + zones, err := region.GetIZones() + if err != nil { + return nil, err + } + for _, zone := range zones { + zoneIds = append(zoneIds, zone.GetId()) + } + + if len(desc.SecgroupIds) == 0 { + return nil, fmt.Errorf("Missing secgroupId") + } + + params := map[string]interface{}{ + "region": region.ID, + "name": desc.Name, + "datastore": map[string]string{ + "type": desc.Engine, + "version": desc.EngineVersion, + }, + "password": desc.Password, + "volume": map[string]interface{}{ + "type": desc.StorageType, + "size": desc.DiskSizeGB, + }, + "vpc_id": desc.VpcId, + "subnet_id": desc.NetworkId, + "security_group_id": desc.SecgroupIds[0], + } + + if len(desc.ProjectId) > 0 { + params["enterprise_project_id"] = desc.ProjectId + } + + if len(desc.MasterInstanceId) > 0 { + params["replica_of_id"] = desc.MasterInstanceId + delete(params, "security_group_id") + } + + if len(desc.RdsId) > 0 && len(desc.BackupId) > 0 { + params["restore_point"] = map[string]interface{}{ + "backup_id": desc.BackupId, + "instance_id": desc.RdsId, + "type": "backup", + } + } + + switch desc.Category { + case api.HUAWEI_DBINSTANCE_CATEGORY_HA: + switch desc.Engine { + case api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_POSTGRESQL: + params["ha"] = map[string]string{ + "mode": "Ha", + "replication_mode": "async", + } + case api.DBINSTANCE_TYPE_SQLSERVER: + params["ha"] = map[string]string{ + "mode": "Ha", + "replication_mode": "sync", + } + } + case api.HUAWEI_DBINSTANCE_CATEGORY_SINGLE: + case api.HUAWEI_DBINSTANCE_CATEGORY_REPLICA: + } + + if desc.BillingCycle != nil { + periodType := "month" + periodNum := desc.BillingCycle.GetMonths() + if desc.BillingCycle.GetYears() > 0 { + periodType = "year" + periodNum = desc.BillingCycle.GetYears() + } + params["charge_info"] = map[string]interface{}{ + "charge_mode": "prePaid", + "period_type": periodType, + "period_num": periodNum, + "is_auto_renew": false, + } + } + params["flavor_ref"] = desc.InstanceType + params["availability_zone"] = desc.ZoneId + resp, err := region.ecsClient.DBInstance.Create(jsonutils.Marshal(params)) + if err != nil { + return nil, errors.Wrapf(err, "Create") + } + + instance := &SDBInstance{region: region} + err = resp.Unmarshal(instance, "instance") + if err != nil { + return nil, errors.Wrap(err, `resp.Unmarshal(&instance, "instance")`) + } + if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { + err = cloudprovider.Wait(10*time.Second, 20*time.Minute, func() (bool, error) { + job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) + if err != nil { + return false, nil + } + status, _ := job.GetString("status") + process, _ := job.GetString("process") + log.Debugf("create dbinstance job %s status: %s process: %s", jobId, status, process) + if status == "Completed" { + return true, nil + } + if status == "Failed" { + return false, fmt.Errorf("create failed") + } + return false, nil + }) + } + return instance, err +} + +func (rds *SDBInstance) Reboot() error { + return rds.region.RebootDBInstance(rds.Id) +} + +func (rds *SDBInstance) OpenPublicConnection() error { + return fmt.Errorf("Huawei current not support this operation") + //return rds.region.PublicConnectionAction(rds.Id, "openRC") +} + +func (rds *SDBInstance) ClosePublicConnection() error { + return fmt.Errorf("Huawei current not support this operation") + //return rds.region.PublicConnectionAction(rds.Id, "closeRC") +} + +func (region *SRegion) PublicConnectionAction(instanceId string, action string) error { + resp, err := region.ecsClient.DBInstance.PerformAction2(action, instanceId, nil, "") + if err != nil { + return errors.Wrapf(err, "rds.%s", action) + } + + if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { + err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { + job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) + if err != nil { + log.Errorf("failed to get job %s info error: %v", jobId, err) + return false + } + status, _ := job.GetString("status") + process, _ := job.GetString("process") + if status == "Completed" { + return true + } + log.Debugf("%s dbinstance job %s status: %s process: %s", action, jobId, status, process) + return false + }) + } + + return nil + +} + +func (region *SRegion) RebootDBInstance(instanceId string) error { + params := jsonutils.Marshal(map[string]interface{}{ + "restart": map[string]string{}, + }) + resp, err := region.ecsClient.DBInstance.PerformAction2("action", instanceId, params, "") + if err != nil { + return err + } + if jobId, _ := resp.GetString("job_id"); len(jobId) > 0 { + err = cloudprovider.WaitCreated(10*time.Second, 20*time.Minute, func() bool { + job, err := region.ecsClient.DBInstanceJob.Get(jobId, map[string]string{"id": jobId}) + if err != nil { + log.Errorf("failed to get job %s info error: %v", jobId, err) + return false + } + status, _ := job.GetString("status") + process, _ := job.GetString("process") + if status == "Completed" { + return true + } + log.Debugf("reboot dbinstance job %s status: %s process: %s", jobId, status, process) + return false + }) + } + return err +} + +type SDBInstanceFlavor struct { + Vcpus int + Ram int //单位GB + SpecCode string + InstanceMode string //实例模型 +} + +func (region *SRegion) GetDBInstanceFlavors(engine string, version string) ([]SDBInstanceFlavor, error) { + flavors := []SDBInstanceFlavor{} + resp, err := region.ecsClient.DBInstanceFlavor.ListInContextWithSpec(nil, engine, map[string]string{"version_name": version}, "flavors") + if err != nil { + return nil, err + } + return flavors, jsonutils.Update(&flavors, resp.Data) +} + +func (rds *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { + return rds.region.CreateDBInstanceAccount(rds.Id, conf.Name, conf.Password) +} + +func (region *SRegion) CreateDBInstanceAccount(instanceId, account, password string) error { + params := map[string]string{ + "name": account, + "password": password, + } + _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/db_user", instanceId), jsonutils.Marshal(params), "") + return err +} + +func (rds *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { + return rds.region.CreateDBInstanceDatabase(rds.Id, conf.Name, conf.CharacterSet) +} + +func (region *SRegion) CreateDBInstanceDatabase(instanceId, database, characterSet string) error { + params := map[string]string{ + "name": database, + "character_set": characterSet, + } + _, err := region.ecsClient.DBInstance.CreateInContextWithSpec(nil, fmt.Sprintf("%s/database", instanceId), jsonutils.Marshal(params), "") + return err +} + +func (rds *SDBInstance) ChangeConfig(cxt context.Context, desc *cloudprovider.SManagedDBInstanceChangeConfig) error { + return rds.region.ChangeDBInstanceConfig(rds.Id, desc.InstanceType, desc.DiskSizeGB) +} + +func (region *SRegion) ChangeDBInstanceConfig(instanceId string, instanceType string, diskSizeGb int) error { + instance, err := region.GetIDBInstanceById(instanceId) + if err != nil { + return errors.Wrapf(err, "region.GetIDBInstanceById(%s)", instanceId) + } + + if len(instanceType) > 0 { + params := map[string]map[string]string{ + "resize_flavor": map[string]string{ + "spec_code": instanceType, + }, + } + _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) + if err != nil { + return errors.Wrap(err, "resize_flavor") + } + cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) + } + if diskSizeGb > 0 { + params := map[string]map[string]int{ + "enlarge_volume": map[string]int{ + "size": diskSizeGb, + }, + } + _, err := region.ecsClient.DBInstance.PerformAction("action", instanceId, jsonutils.Marshal(params)) + if err != nil { + return errors.Wrap(err, "enlarge_volume") + } + cloudprovider.WaitStatus(instance, api.DBINSTANCE_RUNNING, time.Second*5, time.Minute*30) + } + return nil +} + +func (self *SDBInstance) SetTags(tags map[string]string, replace bool) error { + existedTags, err := self.GetTags() + if err != nil { + return errors.Wrap(err, "self.GetTags()") + } + deleteTagsKey := []string{} + for k := range existedTags { + if replace { + deleteTagsKey = append(deleteTagsKey, k) + } else { + if _, ok := tags[k]; ok { + deleteTagsKey = append(deleteTagsKey, k) + } + } + } + if len(deleteTagsKey) > 0 { + err := self.region.DeleteRdsTags(self.GetId(), deleteTagsKey) + if err != nil { + return errors.Wrapf(err, "DeleteRdsTags") + } + } + if len(tags) > 0 { + err := self.region.CreateRdsTags(self.GetId(), tags) + if err != nil { + return errors.Wrapf(err, "CreateRdsTags") + } + } + return nil +} + +func (self *SRegion) DeleteRdsTags(instanceId string, tagsKey []string) error { + params := map[string]interface{}{ + "action": "delete", + } + tagsObj := []map[string]string{} + for _, k := range tagsKey { + tagsObj = append(tagsObj, map[string]string{"key": k}) + } + params["tags"] = tagsObj + + _, err := self.ecsClient.DBInstance.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + return err +} + +func (self *SRegion) CreateRdsTags(instanceId string, tags map[string]string) error { + params := map[string]interface{}{ + "action": "create", + } + + tagsObj := []map[string]string{} + for k, v := range tags { + tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) + } + params["tags"] = tagsObj + + _, err := self.ecsClient.DBInstance.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + return err +} + +func (rds *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { + if len(conf.OriginDBInstanceExternalId) == 0 { + conf.OriginDBInstanceExternalId = rds.Id + } + return rds.region.RecoveryDBInstanceFromBackup(rds.Id, conf.OriginDBInstanceExternalId, conf.BackupId, conf.Databases) +} + +func (region *SRegion) RecoveryDBInstanceFromBackup(target, origin string, backupId string, databases map[string]string) error { + source := map[string]interface{}{ + "type": "backup", + "backup_id": backupId, + } + if len(origin) > 0 { + source["instance_id"] = origin + } + if len(databases) > 0 { + source["database_name"] = databases + } + params := map[string]interface{}{ + "source": source, + "target": map[string]string{ + "instance_id": target, + }, + } + _, err := region.ecsClient.DBInstance.PerformAction("", "recovery", jsonutils.Marshal(params)) + if err != nil { + return errors.Wrap(err, "dbinstance.recovery") + } + return nil +} + +func (rds *SDBInstance) Renew(bc billing.SBillingCycle) error { + return rds.region.RenewInstance(rds.Id, bc) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_account.go new file mode 100644 index 0000000000..83008d5e6a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_account.go @@ -0,0 +1,132 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceAccount struct { + multicloud.SDBInstanceAccountBase + HuaweiTags + instance *SDBInstance + Name string +} + +func (account *SDBInstanceAccount) GetName() string { + return account.Name +} + +func (account *SDBInstanceAccount) Delete() error { + return account.instance.region.DeleteDBInstanceAccount(account.instance.Id, account.Name) +} + +func (region *SRegion) DeleteDBInstanceAccount(instanceId string, account string) error { + return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, fmt.Sprintf("db_user/%s", account), nil, nil) +} + +func (account *SDBInstanceAccount) GetIDBInstanceAccountPrivileges() ([]cloudprovider.ICloudDBInstanceAccountPrivilege, error) { + privileges, err := account.instance.region.GetDBInstancePrivvileges(account.instance.Id, account.Name) + if err != nil { + return nil, err + } + iprivileves := []cloudprovider.ICloudDBInstanceAccountPrivilege{} + for i := 0; i < len(privileges); i++ { + privileges[i].account = account + iprivileves = append(iprivileves, &privileges[i]) + } + return iprivileves, nil +} + +func (region *SRegion) GetDBInstanceAccounts(instanceId string) ([]SDBInstanceAccount, error) { + params := map[string]string{ + "instance_id": instanceId, + } + accounts := []SDBInstanceAccount{} + err := doListAllWithPage(region.ecsClient.DBInstance.ListAccounts, params, &accounts) + if err != nil { + return nil, err + } + return accounts, nil +} + +func (region *SRegion) GetDBInstancePrivvileges(instanceId string, username string) ([]SDatabasePrivilege, error) { + params := map[string]string{ + "instance_id": instanceId, + "user-name": username, + } + privileges := []SDatabasePrivilege{} + err := doListAllWithPage(region.ecsClient.DBInstance.ListPrivileges, params, &privileges) + if err != nil { + return nil, err + } + return privileges, nil +} + +func (account *SDBInstanceAccount) RevokePrivilege(database string) error { + return account.instance.region.RevokeDBInstancePrivilege(account.instance.Id, account.Name, database) +} + +func (region *SRegion) RevokeDBInstancePrivilege(instanceId string, account, database string) error { + params := map[string]interface{}{ + "db_name": database, + "users": []map[string]interface{}{ + map[string]interface{}{ + "name": account, + }, + }, + } + return DoDeleteWithSpec(region.ecsClient.DBInstance.DeleteInContextWithSpec, nil, instanceId, "db_privilege", nil, jsonutils.Marshal(params)) +} + +func (account *SDBInstanceAccount) GrantPrivilege(database, privilege string) error { + return account.instance.region.GrantDBInstancePrivilege(account.instance.Id, account.Name, database, privilege) +} + +func (region *SRegion) GrantDBInstancePrivilege(instanceId string, account, database string, privilege string) error { + readonly := false + switch privilege { + case api.DATABASE_PRIVILEGE_R: + readonly = true + case api.DATABASE_PRIVILEGE_RW: + default: + return fmt.Errorf("Unknown privilege %s", privilege) + } + params := map[string]interface{}{ + "db_name": database, + "users": []map[string]interface{}{ + map[string]interface{}{ + "name": account, + "readonly": readonly, + }, + }, + } + _, err := region.ecsClient.DBInstance.PerformAction("db_privilege", instanceId, jsonutils.Marshal(params)) + return err +} + +func (account *SDBInstanceAccount) ResetPassword(password string) error { + return account.instance.region.ResetDBInstanceAccountPassword(account.instance.Id, account.Name, password) +} + +func (region *SRegion) ResetDBInstanceAccountPassword(instanceId, account, password string) error { + return fmt.Errorf("The API does not exist or has not been published in the environment") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_backup.go new file mode 100644 index 0000000000..95117ac7fc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_backup.go @@ -0,0 +1,236 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceBackup struct { + multicloud.SDBInstanceBackupBase + HuaweiTags + region *SRegion + + BeginTime string + Datastore SDatastore + EndTime string + Id string + InstanceId string + Name string + Size int + Status string + Type string +} + +func (backup *SDBInstanceBackup) GetId() string { + return backup.Id +} + +func (backup *SDBInstanceBackup) GetGlobalId() string { + return backup.Id +} + +func (backup *SDBInstanceBackup) GetName() string { + return backup.Name +} + +func (backup *SDBInstanceBackup) GetEngine() string { + return backup.Datastore.Type +} + +func (backup *SDBInstanceBackup) GetEngineVersion() string { + return backup.Datastore.Version +} + +func (backup *SDBInstanceBackup) GetStartTime() time.Time { + //2019-08-05T08:00:02+0000 + t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.BeginTime) + if err != nil { + return time.Time{} + } + return t +} + +func (backup *SDBInstanceBackup) GetEndTime() time.Time { + t, err := time.Parse("2006-01-02T15:04:05Z0700", backup.EndTime) + if err != nil { + return time.Time{} + } + return t +} + +func (backup *SDBInstanceBackup) GetBackupMode() string { + switch backup.Type { + case "manual": + return api.BACKUP_MODE_MANUAL + default: + return api.BACKUP_MODE_AUTOMATED + } +} + +func (backup *SDBInstanceBackup) GetStatus() string { + switch backup.Status { + case "COMPLETED": + return api.DBINSTANCE_BACKUP_READY + case "FAILED": + return api.DBINSTANCE_BACKUP_FAILED + case "BUILDING": + return api.DBINSTANCE_BACKUP_CREATING + case "DELETING": + return api.DBINSTANCE_BACKUP_DELETING + default: + return api.DBINSTANCE_BACKUP_UNKNOWN + } +} + +func (backup *SDBInstanceBackup) GetBackupSizeMb() int { + return backup.Size / 1024 +} + +func (backup *SDBInstanceBackup) GetDBNames() string { + return "" +} + +func (backup *SDBInstanceBackup) Delete() error { + return backup.region.DeleteDBInstanceBackup(backup.Id) +} + +func (region *SRegion) DeleteDBInstanceBackup(backupId string) error { + _, err := region.ecsClient.DBInstanceBackup.Delete(backupId, nil) + return err +} + +func (backup *SDBInstanceBackup) GetDBInstanceId() string { + return backup.InstanceId +} + +func (region *SRegion) GetDBInstanceBackups(instanceId, backupId string) ([]SDBInstanceBackup, error) { + params := map[string]string{ + "instance_id": instanceId, + } + if len(backupId) > 0 { + params["backup_id"] = backupId + } + backups := []SDBInstanceBackup{} + err := doListAllWithOffset(region.ecsClient.DBInstanceBackup.List, params, &backups) + if err != nil { + return nil, err + } + return backups, nil +} + +func (region *SRegion) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + dbinstnaces, err := region.GetIDBInstances() + if err != nil { + return nil, err + } + ibackups := []cloudprovider.ICloudDBInstanceBackup{} + for i := 0; i < len(dbinstnaces); i++ { + _dbinstance := dbinstnaces[i].(*SDBInstance) + _ibackup, err := _dbinstance.GetIDBInstanceBackups() + if err != nil { + return nil, errors.Wrapf(err, "_dbinstance(%v).GetIDBInstanceBackups", _dbinstance) + } + ibackups = append(ibackups, _ibackup...) + } + return ibackups, nil +} + +func (region *SRegion) GetIDBInstanceBackupById(backupId string) (cloudprovider.ICloudDBInstanceBackup, error) { + backups, err := region.GetIDBInstanceBackups() + if err != nil { + return nil, errors.Wrap(err, "region.GetIDBInstanceBackups") + } + for _, backup := range backups { + if backup.GetGlobalId() == backupId { + return backup, nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (rds *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + backups, err := rds.region.GetDBInstanceBackups(rds.Id, "") + if err != nil { + return nil, err + } + + ibackups := []cloudprovider.ICloudDBInstanceBackup{} + for i := 0; i < len(backups); i++ { + backups[i].region = rds.region + ibackups = append(ibackups, &backups[i]) + } + return ibackups, nil +} + +func (backup *SDBInstanceBackup) Refresh() error { + backups, err := backup.region.GetDBInstanceBackups(backup.InstanceId, backup.Id) + if err != nil { + return err + } + if len(backups) == 0 { + return cloudprovider.ErrNotFound + } + return jsonutils.Update(backup, backups[0]) +} + +func (rds *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { + backupId, err := rds.region.CreateDBInstanceBackup(rds.Id, conf.Name, conf.Description, conf.Databases) + if err != nil { + return "", err + } + backup, err := rds.region.GetIDBInstanceBackupById(backupId) + if err != nil { + return "", errors.Wrap(err, "region.GetIDBInstanceBackupById") + } + cloudprovider.WaitStatus(backup, api.DBINSTANCE_BACKUP_READY, time.Second*3, time.Minute*30) + return backupId, nil +} + +func (region *SRegion) CreateDBInstanceBackup(instanceId string, name string, descrition string, databases []string) (string, error) { + params := map[string]interface{}{ + "instance_id": instanceId, + "name": name, + "description": descrition, + } + if len(databases) > 0 { + dbs := []map[string]string{} + for _, database := range databases { + dbs = append(dbs, map[string]string{"name": database}) + } + params["databases"] = dbs + } + resp, err := region.ecsClient.DBInstanceBackup.Create(jsonutils.Marshal(params)) + if err != nil { + return "", errors.Wrap(err, "DBInstanceBackup.Create") + } + backupId, err := resp.GetString("id") + if err != nil { + return "", errors.Wrap(err, "resp.GetBackupId") + } + return backupId, nil +} + +func (self *SDBInstanceBackup) CreateICloudDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + opts.BackupId = self.Id + return self.region.CreateIDBInstance(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_database.go new file mode 100644 index 0000000000..d641e1739d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_database.go @@ -0,0 +1,72 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstanceDatabase struct { + instance *SDBInstance + multicloud.SDBInstanceDatabaseBase + HuaweiTags + + Name string + CharacterSet string +} + +func (database *SDBInstanceDatabase) GetId() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetGlobalId() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetName() string { + return database.Name +} + +func (database *SDBInstanceDatabase) GetStatus() string { + return api.DBINSTANCE_DATABASE_RUNNING +} + +func (database *SDBInstanceDatabase) GetCharacterSet() string { + return database.CharacterSet +} + +func (database *SDBInstanceDatabase) Delete() error { + return database.instance.region.DeleteDBInstanceDatabase(database.instance.Id, database.Name) +} + +func (region *SRegion) DeleteDBInstanceDatabase(instanceId, database string) error { + _, err := region.ecsClient.DBInstance.DeleteInContextWithSpec(nil, instanceId, fmt.Sprintf("database/%s", database), nil, nil, "") + return err +} + +func (region *SRegion) GetDBInstanceDatabases(instanceId string) ([]SDBInstanceDatabase, error) { + params := map[string]string{ + "instance_id": instanceId, + } + databases := []SDBInstanceDatabase{} + err := doListAllWithPage(region.ecsClient.DBInstance.ListDatabases, params, &databases) + if err != nil { + return nil, err + } + return databases, nil +} diff --git a/pkg/multicloud/huawei/dbinstance_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_parameter.go similarity index 100% rename from pkg/multicloud/huawei/dbinstance_parameter.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_parameter.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_privilege.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_privilege.go new file mode 100644 index 0000000000..e76b77253b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/dbinstance_privilege.go @@ -0,0 +1,43 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +type SDatabasePrivilege struct { + account *SDBInstanceAccount + + Name string + Readonly bool +} + +func (privilege *SDatabasePrivilege) GetGlobalId() string { + return fmt.Sprintf("%s/%s", privilege.account.Name, privilege.Name) +} + +func (privilege *SDatabasePrivilege) GetPrivilege() string { + if privilege.Readonly { + return api.DATABASE_PRIVILEGE_R + } + return api.DATABASE_PRIVILEGE_RW +} + +func (privilege *SDatabasePrivilege) GetDBName() string { + return privilege.Name +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/disk.go new file mode 100644 index 0000000000..e8268e1cac --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/disk.go @@ -0,0 +1,558 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +/* +华为云云硬盘 +======创建========== +1.磁盘只能挂载到同一可用区的云服务器内,创建后不支持更换可用区 +2.计费模式 包年包月/按需计费 +3.*支持自动备份 + + +共享盘 和 普通盘:https://support.huaweicloud.com/productdesc-evs/zh-cn_topic_0032860759.html +根据是否支持挂载至多台云服务器可以将云硬盘分为非共享云硬盘和共享云硬盘。 +一个非共享云硬盘只能挂载至一台云服务器,而一个共享云硬盘可以同时挂载至多台云服务器。 +单个共享云硬盘最多可同时挂载给16个云服务器。目前,共享云硬盘只适用于数据盘,不支持系统盘。 +*/ + +type Attachment struct { + ServerID string `json:"server_id"` + AttachmentID string `json:"attachment_id"` + AttachedAt string `json:"attached_at"` + HostName string `json:"host_name"` + VolumeID string `json:"volume_id"` + Device string `json:"device"` + ID string `json:"id"` +} + +type DiskMeta struct { + ResourceSpecCode string `json:"resourceSpecCode"` + Billing string `json:"billing"` + ResourceType string `json:"resourceType"` + AttachedMode string `json:"attached_mode"` + Readonly string `json:"readonly"` +} + +type VolumeImageMetadata struct { + QuickStart string `json:"__quick_start"` + ContainerFormat string `json:"container_format"` + MinRAM string `json:"min_ram"` + ImageName string `json:"image_name"` + ImageID string `json:"image_id"` + OSType string `json:"__os_type"` + OSFeatureList string `json:"__os_feature_list"` + MinDisk string `json:"min_disk"` + SupportKVM string `json:"__support_kvm"` + VirtualEnvType string `json:"virtual_env_type"` + SizeGB string `json:"size"` + OSVersion string `json:"__os_version"` + OSBit string `json:"__os_bit"` + SupportKVMHi1822Hiovs string `json:"__support_kvm_hi1822_hiovs"` + SupportXen string `json:"__support_xen"` + Description string `json:"__description"` + Imagetype string `json:"__imagetype"` + DiskFormat string `json:"disk_format"` + ImageSourceType string `json:"__image_source_type"` + Checksum string `json:"checksum"` + Isregistered string `json:"__isregistered"` + HwVifMultiqueueEnabled string `json:"hw_vif_multiqueue_enabled"` + Platform string `json:"__platform"` +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0124881427.html +type SDisk struct { + storage *SStorage + multicloud.SDisk + HuaweiDiskTags + details *SResourceDetail + + ID string `json:"id"` + Name string `json:"name"` + Status string `json:"status"` + Attachments []Attachment `json:"attachments"` + Description string `json:"description"` + SizeGB int `json:"size"` + Metadata DiskMeta `json:"metadata"` + Encrypted bool `json:"encrypted"` + Bootable string `json:"bootable"` + Multiattach bool `json:"multiattach"` + AvailabilityZone string `json:"availability_zone"` + SourceVolid string `json:"source_volid"` + SnapshotID string `json:"snapshot_id"` + CreatedAt time.Time `json:"created_at"` + VolumeType string `json:"volume_type"` + VolumeImageMetadata VolumeImageMetadata `json:"volume_image_metadata"` + ReplicationStatus string `json:"replication_status"` + UserID string `json:"user_id"` + ConsistencygroupID string `json:"consistencygroup_id"` + UpdatedAt string `json:"updated_at"` + EnterpriseProjectId string + + ExpiredTime time.Time +} + +func (self *SDisk) GetId() string { + return self.ID +} + +func (self *SDisk) GetName() string { + if len(self.Name) == 0 { + return self.ID + } + + return self.Name +} + +func (self *SDisk) GetGlobalId() string { + return self.ID +} + +func (self *SDisk) GetStatus() string { + // https://support.huaweicloud.com/api-evs/zh-cn_topic_0051803385.html + switch self.Status { + case "creating", "downloading": + return api.DISK_ALLOCATING + case "available", "in-use": + return api.DISK_READY + case "error": + return api.DISK_ALLOC_FAILED + case "attaching": + return api.DISK_ATTACHING + case "detaching": + return api.DISK_DETACHING + case "restoring-backup": + return api.DISK_REBUILD + case "backing-up": + return api.DISK_BACKUP_STARTALLOC // ? + case "error_restoring": + return api.DISK_BACKUP_ALLOC_FAILED + case "uploading": + return api.DISK_SAVING //? + case "extending": + return api.DISK_RESIZING + case "error_extending": + return api.DISK_ALLOC_FAILED // ? + case "deleting": + return api.DISK_DEALLOC //? + case "error_deleting": + return api.DISK_DEALLOC_FAILED // ? + case "rollbacking": + return api.DISK_REBUILD + case "error_rollbacking": + return api.DISK_UNKNOWN + default: + return api.DISK_UNKNOWN + } +} + +func (self *SDisk) Refresh() error { + new, err := self.storage.zone.region.GetDisk(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SDisk) IsEmulated() bool { + return false +} + +func (self *SDisk) getResourceDetails() *SResourceDetail { + if self.details != nil { + return self.details + } + + res, err := self.storage.zone.region.GetOrderResourceDetail(self.GetId()) + if err != nil { + log.Debugln(err) + return nil + } + + self.details = &res + return self.details +} + +func (self *SDisk) GetBillingType() string { + details := self.getResourceDetails() + if details == nil { + return billing_api.BILLING_TYPE_POSTPAID + } else { + return billing_api.BILLING_TYPE_PREPAID + } +} + +func (self *SDisk) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SDisk) GetExpiredAt() time.Time { + var expiredTime time.Time + details := self.getResourceDetails() + if details != nil { + expiredTime = details.ExpireTime + } + + return expiredTime +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +func (self *SDisk) GetDiskFormat() string { + // self.volume_type ? + return "vhd" +} + +func (self *SDisk) GetDiskSizeMB() int { + return int(self.SizeGB * 1024) +} + +func (self *SDisk) checkAutoDelete(attachments []Attachment) bool { + autodelete := false + for _, attach := range attachments { + if len(attach.ServerID) > 0 { + // todo : 忽略错误?? + vm, err := self.storage.zone.region.GetInstanceByID(attach.ServerID) + if err != nil { + volumes := vm.OSExtendedVolumesVolumesAttached + for _, vol := range volumes { + if vol.ID == self.ID && strings.ToLower(vol.DeleteOnTermination) == "true" { + autodelete = true + } + } + } + + break + } + } + + return autodelete +} + +func (self *SDisk) GetIsAutoDelete() bool { + if len(self.Attachments) > 0 { + return self.checkAutoDelete(self.Attachments) + } + + return false +} + +func (self *SDisk) GetTemplateId() string { + return self.VolumeImageMetadata.ImageID +} + +// Bootable 表示硬盘是否为启动盘。 +// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) +func (self *SDisk) GetDiskType() string { + if self.Bootable == "true" { + return api.DISK_TYPE_SYS + } else { + return api.DISK_TYPE_DATA + } +} + +func (self *SDisk) GetFsFormat() string { + return "" +} + +func (self *SDisk) GetIsNonPersistent() bool { + return false +} + +func (self *SDisk) GetDriver() string { + // https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762431.html + // scsi or vbd? + // todo: implement me + return "scsi" +} + +func (self *SDisk) GetCacheMode() string { + return "none" +} + +func (self *SDisk) GetMountpoint() string { + if len(self.Attachments) > 0 { + return self.Attachments[0].Device + } + + return "" +} + +func (self *SDisk) GetMountServerId() string { + if len(self.Attachments) > 0 { + return self.Attachments[0].ServerID + } + + return "" +} + +func (self *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) Delete(ctx context.Context) error { + disk, err := self.storage.zone.region.GetDisk(self.GetId()) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return err + } + if disk.Status != "deleting" { + // 等待硬盘ready + cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 60*time.Second) + err := self.storage.zone.region.DeleteDisk(self.GetId()) + if err != nil { + return err + } + } + + return cloudprovider.WaitDeleted(self, 10*time.Second, 120*time.Second) +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + if snapshotId, err := self.storage.zone.region.CreateSnapshot(self.GetId(), 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, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second); err != nil { + return nil, err + } + return snapshot, nil + } +} + +func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) { + snapshot, err := self.storage.zone.region.GetSnapshotById(snapshotId) + return &snapshot, err +} + +func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := self.getSnapshot(snapshotId) + return snapshot, err +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := self.storage.zone.region.GetSnapshots(self.ID, "") + if err != nil { + return nil, err + } + + isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := 0; i < len(snapshots); i++ { + isnapshots[i] = &snapshots[i] + } + return isnapshots, nil +} + +func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { + err := cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 60*time.Second) + if err != nil { + return err + } + + sizeGb := newSizeMB / 1024 + err = self.storage.zone.region.resizeDisk(self.GetId(), sizeGb) + if err != nil { + return err + } + + return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 15*time.Second, 5*time.Second, 60*time.Second) +} + +func (self *SDisk) Detach() error { + err := self.storage.zone.region.DetachDisk(self.GetMountServerId(), self.GetId()) + if err != nil { + log.Debugf("detach server %s disk %s failed: %s", self.GetMountServerId(), self.GetId(), err) + return err + } + + return cloudprovider.WaitCreated(5*time.Second, 60*time.Second, func() bool { + err := self.Refresh() + if err != nil { + log.Debugln(err) + return false + } + + if self.Status == "available" { + return true + } + + return false + }) +} + +func (self *SDisk) Attach(device string) error { + err := self.storage.zone.region.AttachDisk(self.GetMountServerId(), self.GetId(), device) + if err != nil { + log.Debugf("attach server %s disk %s failed: %s", self.GetMountServerId(), self.GetId(), err) + return err + } + + return cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 10*time.Second, 5*time.Second, 60*time.Second) +} + +// 在线卸载磁盘 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0036046828.html +// 对于挂载在系统盘盘位(也就是“/dev/sda”或“/dev/vda”挂载点)上的磁盘,当前仅支持离线卸载 +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + mountpoint := self.GetMountpoint() + if len(mountpoint) > 0 { + err := self.Detach() + if err != nil { + return "", err + } + } + + diskId, err := self.storage.zone.region.resetDisk(self.GetId(), snapshotId) + if err != nil { + return diskId, err + } + + err = cloudprovider.WaitStatus(self, api.DISK_READY, 5*time.Second, 300*time.Second) + if err != nil { + return "", err + } + + if len(mountpoint) > 0 { + err := self.Attach(mountpoint) + if err != nil { + return "", err + } + } + + return diskId, nil +} + +// 华为云不支持重置 +func (self *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { + if len(diskId) == 0 { + return nil, cloudprovider.ErrNotFound + } + var disk SDisk + err := DoGet(self.ecsClient.Disks.Get, diskId, nil, &disk) + return &disk, err +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762430.html +func (self *SRegion) GetDisks(zoneId string) ([]SDisk, error) { + queries := map[string]string{} + if len(zoneId) > 0 { + queries["availability_zone"] = zoneId + } + + disks := make([]SDisk, 0) + err := doListAllWithOffset(self.ecsClient.Disks.List, queries, &disks) + return disks, err +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html +func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, snapshotId string, desc string, projectId string) (string, error) { + params := jsonutils.NewDict() + volumeObj := jsonutils.NewDict() + volumeObj.Add(jsonutils.NewString(name), "name") + volumeObj.Add(jsonutils.NewString(zoneId), "availability_zone") + volumeObj.Add(jsonutils.NewString(desc), "description") + volumeObj.Add(jsonutils.NewString(category), "volume_type") + volumeObj.Add(jsonutils.NewInt(int64(sizeGb)), "size") + if len(snapshotId) > 0 { + volumeObj.Add(jsonutils.NewString(snapshotId), "snapshot_id") + } + if len(projectId) > 0 { + volumeObj.Add(jsonutils.NewString(projectId), "enterprise_project_id") + } + + params.Add(volumeObj, "volume") + // 目前只支持创建按需资源,返回job id。 如果创建包年包月资源则返回order id + _id, err := self.ecsClient.Disks.AsyncCreate(params) + if err != nil { + log.Debugf("AsyncCreate with params: %s", params) + return "", errors.Wrap(err, "AsyncCreate") + } + + // 按需计费 + volumeId, err := self.GetTaskEntityID(self.ecsClient.Disks.ServiceType(), _id, "volume_id") + if err != nil { + return "", errors.Wrap(err, "GetAllSubTaskEntityIDs") + } + + if len(volumeId) == 0 { + return "", errors.Errorf("CreateInstance job %s result is emtpy", _id) + } else { + return volumeId, nil + } +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762428.html +// 默认删除云硬盘关联的所有快照 +func (self *SRegion) DeleteDisk(diskId string) error { + return DoDeleteWithSpec(self.ecsClient.Disks.DeleteInContextWithSpec, nil, diskId, "", nil, nil) +} + +/* +扩容状态为available的云硬盘时,没有约束限制。 +扩容状态为in-use的云硬盘时,有以下约束: +不支持共享云硬盘,即multiattach参数值必须为false。 +云硬盘所挂载的云服务器状态必须为ACTIVE、PAUSED、SUSPENDED、SHUTOFF才支持扩容 +*/ +func (self *SRegion) resizeDisk(diskId string, sizeGB int64) error { + params := jsonutils.NewDict() + osExtendObj := jsonutils.NewDict() + osExtendObj.Add(jsonutils.NewInt(sizeGB), "new_size") // GB + params.Add(osExtendObj, "os-extend") + _, err := self.ecsClient.Disks.PerformAction2("action", diskId, params, "") + return err +} + +/* +https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408629.html +只支持快照回滚到源云硬盘,不支持快照回滚到其它指定云硬盘。 +只有云硬盘状态处于“available”或“error_rollbacking”状态才允许快照回滚到源云硬盘。 +*/ +func (self *SRegion) resetDisk(diskId, snapshotId string) (string, error) { + params := jsonutils.NewDict() + rollbackObj := jsonutils.NewDict() + rollbackObj.Add(jsonutils.NewString(diskId), "volume_id") + params.Add(rollbackObj, "rollback") + _, err := self.ecsClient.OsSnapshots.PerformAction2("rollback", snapshotId, params, "") + return diskId, err +} + +func (self *SDisk) GetProjectId() string { + return self.EnterpriseProjectId +} diff --git a/pkg/multicloud/huawei/disktype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/disktype.go similarity index 100% rename from pkg/multicloud/huawei/disktype.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/disktype.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/doc.go new file mode 100644 index 0000000000..c9c72fe03b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 huawei // import "yunion.io/x/cloudmux/pkg/multicloud/huawei" diff --git a/pkg/multicloud/huawei/domain.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/domain.go similarity index 100% rename from pkg/multicloud/huawei/domain.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/domain.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/eip.go new file mode 100644 index 0000000000..57654c8f5c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/eip.go @@ -0,0 +1,396 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type TInternetChargeType string + +const ( + InternetChargeByTraffic = TInternetChargeType("traffic") + InternetChargeByBandwidth = TInternetChargeType("bandwidth") +) + +type Bandwidth struct { + ID string `json:"id"` + Name string `json:"name"` + Size int64 `json:"size"` + ShareType string `json:"share_type"` + PublicipInfo []PublicipInfo `json:"publicip_info"` + TenantID string `json:"tenant_id"` + BandwidthType string `json:"bandwidth_type"` + ChargeMode string `json:"charge_mode"` + BillingInfo string `json:"billing_info"` + EnterpriseProjectID string `json:"enterprise_project_id"` +} + +type PublicipInfo struct { + PublicipID string `json:"publicip_id"` + PublicipAddress string `json:"publicip_address"` + PublicipType string `json:"publicip_type"` + IPVersion int64 `json:"ip_version"` +} + +type SProfile struct { + UserID string `json:"user_id"` + ProductID string `json:"product_id"` + RegionID string `json:"region_id"` + OrderID string `json:"order_id"` +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html +type SEipAddress struct { + region *SRegion + port *Port + multicloud.SEipBase + HuaweiTags + + Alias string + ID string `json:"id"` + Status string `json:"status"` + Profile *SProfile `json:"profile,omitempty"` + Type string `json:"type"` + PublicIPAddress string `json:"public_ip_address"` + PrivateIPAddress string `json:"private_ip_address"` + TenantID string `json:"tenant_id"` + CreateTime time.Time `json:"create_time"` + BandwidthID string `json:"bandwidth_id"` + BandwidthShareType string `json:"bandwidth_share_type"` + BandwidthSize int64 `json:"bandwidth_size"` + BandwidthName string `json:"bandwidth_name"` + EnterpriseProjectID string `json:"enterprise_project_id"` + IPVersion int64 `json:"ip_version"` + PortId string `json:"port_id"` + EnterpriseProjectId string +} + +func (self *SEipAddress) GetId() string { + return self.ID +} + +func (self *SEipAddress) GetName() string { + if len(self.Alias) > 0 { + return self.Alias + } + return self.PublicIPAddress +} + +func (self *SEipAddress) GetGlobalId() string { + return self.ID +} + +func (self *SEipAddress) GetStatus() string { + // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090598.html + switch self.Status { + case "ACTIVE", "DOWN", "ELB": + return api.EIP_STATUS_READY + case "PENDING_CREATE", "NOTIFYING": + return api.EIP_STATUS_ALLOCATE + case "BINDING": + return api.EIP_STATUS_ALLOCATE + case "BIND_ERROR": + return api.EIP_STATUS_ALLOCATE_FAIL + case "PENDING_DELETE", "NOTIFY_DELETE": + return api.EIP_STATUS_DEALLOCATE + default: + return api.EIP_STATUS_UNKNOWN + } +} + +func (self *SEipAddress) Refresh() error { + if self.IsEmulated() { + return nil + } + new, err := self.region.GetEip(self.ID) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SEipAddress) IsEmulated() bool { + return false +} + +func (self *SEipAddress) GetIpAddr() string { + return self.PublicIPAddress +} + +func (self *SEipAddress) GetMode() string { + return api.EIP_MODE_STANDALONE_EIP +} + +func (self *SEipAddress) GetPort() *Port { + if len(self.PortId) == 0 { + return nil + } + + if self.port != nil { + return self.port + } + + port, err := self.region.GetPort(self.PortId) + if err != nil { + return nil + } else { + self.port = &port + } + + return self.port +} + +func (self *SEipAddress) GetAssociationType() string { + if len(self.PortId) == 0 { + return "" + } + port, err := self.region.GetPort(self.PortId) + if err != nil { + log.Errorf("Get eip %s port %s error: %v", self.ID, self.PortId, err) + return "" + } + + if strings.HasPrefix(port.DeviceOwner, "compute") { + return api.EIP_ASSOCIATE_TYPE_SERVER + } + + switch port.DeviceOwner { + case "neutron:LOADBALANCER", "neutron:LOADBALANCERV2": + return api.EIP_ASSOCIATE_TYPE_LOADBALANCER + case "network:nat_gateway": + return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY + default: + return port.DeviceOwner + } +} + +func (self *SEipAddress) GetAssociationExternalId() string { + // network/0273a359d61847fc83405926c958c746/ext-floatingips?tenantId=0273a359d61847fc83405926c958c746&limit=2000 + // 只能通过 port id 反查device id. + if len(self.PortId) > 0 { + port, _ := self.region.GetPort(self.PortId) + return port.DeviceID + } + return "" +} + +func (self *SEipAddress) GetBandwidth() int { + return int(self.BandwidthSize) // Mb +} + +func (self *SEipAddress) GetINetworkId() string { + return "" +} + +func (self *SEipAddress) GetInternetChargeType() string { + // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090603.html + bandwidth, err := self.region.GetEipBandwidth(self.BandwidthID) + if err != nil { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + } + if bandwidth.ChargeMode == "traffic" { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + } + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH +} + +func (self *SEipAddress) GetBillingType() string { + if self.Profile == nil { + return billing_api.BILLING_TYPE_POSTPAID + } + return billing_api.BILLING_TYPE_PREPAID +} + +func (self *SEipAddress) GetCreatedAt() time.Time { + return self.CreateTime +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SEipAddress) Delete() error { + return self.region.DeallocateEIP(self.ID) +} + +func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { + portId, err := self.region.GetInstancePortId(conf.InstanceId) + if err != nil { + return err + } + + if len(self.PortId) > 0 { + if self.PortId == portId { + return nil + } + + return fmt.Errorf("eip %s aready associate with port %s", self.GetId(), self.PortId) + } + + err = self.region.AssociateEipWithPortId(self.ID, portId) + if err != nil { + return err + } + + err = cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 10*time.Second, 10*time.Second, 180*time.Second) + return err +} + +func (self *SEipAddress) Dissociate() error { + err := self.region.DissociateEip(self.ID) + if err != nil { + return err + } + return cloudprovider.WaitStatus(self, api.EIP_STATUS_READY, 10*time.Second, 180*time.Second) +} + +func (self *SEipAddress) ChangeBandwidth(bw int) error { + return self.region.UpdateEipBandwidth(self.BandwidthID, bw) +} + +func (self *SRegion) GetInstancePortId(instanceId string) (string, error) { + // 目前只绑定一个网卡 + // todo: 还需要按照ports状态进行过滤 + ports, err := self.GetPorts(instanceId) + if err != nil { + return "", err + } + + if len(ports) == 0 { + return "", fmt.Errorf("AssociateEip instance %s port is empty", instanceId) + } + + return ports[0].ID, nil +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html +func (self *SRegion) AllocateEIP(name string, bwMbps int, chargeType TInternetChargeType, bgpType string, projectId string) (*SEipAddress, error) { + params := map[string]interface{}{ + "bandwidth": map[string]interface{}{ + "name": name, + "size": bwMbps, + "share_type": "PER", + "charge_mode": chargeType, + }, + "publicip": map[string]interface{}{ + "type": bgpType, + "ip_version": 4, + "alias": name, + }, + } + if len(projectId) > 0 { + params["enterprise_project_id"] = projectId + } + resp, err := self.vpcCreate("publicips", params) + if err != nil { + return nil, err + } + eip := &SEipAddress{region: self} + return eip, resp.Unmarshal(eip, "publicip") +} + +func (self *SRegion) GetEip(eipId string) (*SEipAddress, error) { + resp, err := self.vpcGet("publicips/" + eipId) + if err != nil { + return nil, err + } + eip := &SEipAddress{region: self} + return eip, resp.Unmarshal(eip, "publicip") +} + +func (self *SRegion) DeallocateEIP(eipId string) error { + _, err := self.vpcDelete("publicips/" + eipId) + return err +} + +func (self *SRegion) AssociateEip(eipId string, instanceId string) error { + portId, err := self.GetInstancePortId(instanceId) + if err != nil { + return err + } + return self.AssociateEipWithPortId(eipId, portId) +} + +func (self *SRegion) AssociateEipWithPortId(eipId string, portId string) error { + params := map[string]interface{}{ + "publicip": map[string]interface{}{ + "port_id": portId, + }, + } + _, err := self.vpcUpdate("publicips/"+eipId, params) + return err +} + +func (self *SRegion) DissociateEip(eipId string) error { + return self.AssociateEipWithPortId(eipId, "") +} + +func (self *SRegion) UpdateEipBandwidth(bandwidthId string, bw int) error { + params := map[string]interface{}{ + "bandwidth": map[string]interface{}{ + "size": bw, + }, + } + _, err := self.vpcUpdate("bandwidths/"+bandwidthId, params) + return err +} + +func (self *SRegion) GetEipBandwidth(id string) (*Bandwidth, error) { + resp, err := self.vpcGet("bandwidths/" + id) + if err != nil { + return nil, err + } + ret := &Bandwidth{} + return ret, resp.Unmarshal(ret, "bandwidth") +} + +func (self *SEipAddress) GetProjectId() string { + return self.EnterpriseProjectId +} + +func (self *SRegion) GetEips(portId string, addrs []string) ([]SEipAddress, error) { + query := url.Values{} + for _, addr := range addrs { + query.Add("public_ip_address", addr) + } + if len(portId) > 0 { + query.Set("port_id", portId) + } + resp, err := self.vpcList("publicips", query) + if err != nil { + return nil, err + } + eips := []SEipAddress{} + err = resp.Unmarshal(&eips, "publicips") + if err != nil { + return nil, err + } + for i := range eips { + eips[i].region = self + } + return eips, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_account.go new file mode 100644 index 0000000000..0da5601978 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_account.go @@ -0,0 +1,108 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElasticcacheAccount struct { + multicloud.SElasticcacheAccountBase + HuaweiTags + + cacheDB *SElasticcache +} + +func (self *SElasticcacheAccount) GetId() string { + return fmt.Sprintf("%s/root", self.cacheDB.InstanceID) +} + +func (self *SElasticcacheAccount) GetName() string { + if len(self.cacheDB.AccessUser) > 0 { + return self.cacheDB.AccessUser + } + + return "root" +} + +func (self *SElasticcacheAccount) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheAccount) GetStatus() string { + return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE +} + +func (self *SElasticcacheAccount) GetAccountType() string { + return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN +} + +func (self *SElasticcacheAccount) GetAccountPrivilege() string { + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html +// 未找到关闭密码的开放api, 不支持开启/关闭密码访问 +// https://console.huaweicloud.com/dcs/rest/v2/41f6bfe48d7f4455b7754f7c1b11ae34/instances/26db46e2-c7d8-4b5e-bd36-b5278d2fe17c/password/reset +// new_password: "26db46e2!" +// no_password_access: false +func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { + if input.OldPassword == nil { + return fmt.Errorf("elasticcacheAccount.ResetPassword.input OldPassword should not be empty") + } + + type ResetPasswordResult struct { + Result string `json:"result"` + Message string `json:"message"` + } + + result := ResetPasswordResult{} + params := jsonutils.NewDict() + params.Set("old_password", jsonutils.NewString(*input.OldPassword)) + params.Set("new_password", jsonutils.NewString(input.NewPassword)) + err := DoUpdateWithSpec2(self.cacheDB.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.cacheDB.GetId(), "password", params, &result) + if err != nil { + return errors.Wrap(err, "elasticcacheAccount.ResetPassword") + } + + if result.Result != "success" { + return errors.Wrap(fmt.Errorf(result.Message), "elasticcacheAccount.ResetPassword") + } + + return nil +} + +func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { + if input.Password != nil { + inputPassword := cloudprovider.SCloudElasticCacheAccountResetPasswordInput{} + inputPassword.NewPassword = *input.Password + inputPassword.OldPassword = input.OldPassword + inputPassword.NoPasswordAccess = input.NoPasswordAccess + return self.ResetPassword(inputPassword) + } + + return nil +} + +func (self *SElasticcacheAccount) Delete() error { + return cloudprovider.ErrNotSupported +} diff --git a/pkg/multicloud/huawei/elasticcache_acl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_acl.go similarity index 100% rename from pkg/multicloud/huawei/elasticcache_acl.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_acl.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_backup.go new file mode 100644 index 0000000000..a5b8d7ae87 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_backup.go @@ -0,0 +1,138 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html +type SElasticcacheBackup struct { + multicloud.SElasticcacheBackupBase + HuaweiTags + + cacheDB *SElasticcache + + Status string `json:"status"` + Remark string `json:"remark"` + Period string `json:"period"` + Progress string `json:"progress"` + SizeByte int64 `json:"size"` + InstanceID string `json:"instance_id"` + BackupID string `json:"backup_id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + ExecutionAt time.Time `json:"execution_at"` + BackupType string `json:"backup_type"` + BackupName string `json:"backup_name"` + ErrorCode string `json:"error_code"` + IsSupportRestore string `json:"is_support_restore"` +} + +func (self *SElasticcacheBackup) GetId() string { + return self.BackupID +} + +func (self *SElasticcacheBackup) GetName() string { + return self.BackupName +} + +func (self *SElasticcacheBackup) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheBackup) Refresh() error { + cache, err := self.cacheDB.GetICloudElasticcacheBackup(self.GetId()) + if err != nil { + return errors.Wrap(err, "ElasticcacheBackup.Refresh.GetICloudElasticcacheBackup") + } + + err = jsonutils.Update(self, cache) + if err != nil { + return errors.Wrap(err, "ElasticcacheBackup.Refresh.Update") + } + + return nil +} + +func (self *SElasticcacheBackup) GetStatus() string { + switch self.Status { + case "waiting", "backuping": + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATING + case "succeed": + return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS + case "failed": + return api.ELASTIC_CACHE_BACKUP_STATUS_FAILED + case "expired": + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_EXPIRED + case "deleted": + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_DELETED + default: + return self.Status + } +} + +func (self *SElasticcacheBackup) GetBackupSizeMb() int { + return int(self.SizeByte / 1024 / 1024) +} + +func (self *SElasticcacheBackup) GetBackupType() string { + switch self.BackupType { + case "manual": + return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL + case "auto": + return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED + default: + return self.BackupType + } + +} + +func (self *SElasticcacheBackup) GetBackupMode() string { + return "" +} + +func (self *SElasticcacheBackup) GetDownloadURL() string { + return "" +} + +func (self *SElasticcacheBackup) GetStartTime() time.Time { + return self.CreatedAt +} + +func (self *SElasticcacheBackup) GetEndTime() time.Time { + return self.UpdatedAt +} + +func (self *SElasticcacheBackup) Delete() error { + return cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423034.html +func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { + _, err := self.cacheDB.region.ecsClient.Elasticcache.RestoreInstance(instanceId, self.GetId()) + if err != nil { + return nil + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_instance.go new file mode 100644 index 0000000000..b049e02bbf --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_instance.go @@ -0,0 +1,760 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html +type SElasticcache struct { + multicloud.SElasticcacheBase + HuaweiTags + + region *SRegion + + Name string `json:"name"` + Engine string `json:"engine"` + CapacityGB int `json:"capacity"` + IP string `json:"ip"` + DomainName string `json:"domainName"` + Port int `json:"port"` + Status string `json:"status"` + Libos bool `json:"libos"` + Description string `json:"description"` + Task string `json:"task"` + MaxMemoryMB int `json:"max_memory"` + UsedMemoryMB int `json:"used_memory"` + InstanceID string `json:"instance_id"` + ResourceSpecCode string `json:"resource_spec_code"` + EngineVersion string `json:"engine_version"` + InternalVersion string `json:"internal_version"` + ChargingMode int `json:"charging_mode"` + CapacityMinor string `json:"capacity_minor"` + VpcID string `json:"vpc_id"` + VpcName string `json:"vpc_name"` + TaskStatus string `json:"task_status"` + CreatedAt string `json:"created_at"` + ErrorCode string `json:"error_code"` + UserID string `json:"user_id"` + UserName string `json:"user_name"` + MaintainBegin string `json:"maintain_begin"` + MaintainEnd string `json:"maintain_end"` + NoPasswordAccess string `json:"no_password_access"` + AccessUser string `json:"access_user"` + EnablePublicip bool `json:"enable_publicip"` + PublicipID string `json:"publicip_id"` + PublicipAddress string `json:"publicip_address"` + EnableSSL bool `json:"enable_ssl"` + ServiceUpgrade bool `json:"service_upgrade"` + ServiceTaskID string `json:"service_task_id"` + IsFree string `json:"is_free"` + EnterpriseProjectID string `json:"enterprise_project_id"` + AvailableZones []string `json:"available_zones"` + SubnetID string `json:"subnet_id"` + SecurityGroupID string `json:"security_group_id"` + BackendAddrs []string `json:"backend_addrs"` + ProductID string `json:"product_id"` + SecurityGroupName string `json:"security_group_name"` + SubnetName string `json:"subnet_name"` + OrderID string `json:"order_id"` + SubnetCIDR string `json:"subnet_cidr"` + InstanceBackupPolicy string `json:"instance_backup_policy"` + EnterpriseProjectName string `json:"enterprise_project_name"` +} + +func (self *SElasticcache) GetId() string { + return self.InstanceID +} + +func (self *SElasticcache) GetName() string { + return self.Name +} + +func (self *SElasticcache) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcache) GetProjectId() string { + return self.EnterpriseProjectID +} + +func (self *SElasticcache) Refresh() error { + cache, err := self.region.GetElasticCache(self.GetId()) + if err != nil { + return errors.Wrap(err, "Elasticcache.Refresh.GetElasticCache") + } + + err = jsonutils.Update(self, cache) + if err != nil { + return errors.Wrap(err, "Elasticcache.Refresh.Update") + } + + return nil +} + +func (self *SElasticcache) GetStatus() string { + switch self.Status { + case "RUNNING": + return api.ELASTIC_CACHE_STATUS_RUNNING + case "CREATING": + return api.ELASTIC_CACHE_STATUS_DEPLOYING + case "CREATEFAILED": + return api.ELASTIC_CACHE_STATUS_CREATE_FAILED + case "ERROR": + return api.ELASTIC_CACHE_STATUS_ERROR + case "RESTARTING": + return api.ELASTIC_CACHE_STATUS_RESTARTING + case "FROZEN": + return api.ELASTIC_CACHE_STATUS_UNAVAILABLE + case "EXTENDING": + return api.ELASTIC_CACHE_STATUS_CHANGING + case "RESTORING": + return api.ELASTIC_CACHE_STATUS_TRANSFORMING // ? + case "FLUSHING": + return api.ELASTIC_CACHE_STATUS_FLUSHING + } + + return "" +} + +func (self *SElasticcache) GetBillingType() string { + // charging_mode “0”:按需计费 “1”:按包年包月计费 + if self.ChargingMode == 1 { + return billing_api.BILLING_TYPE_PREPAID + } else { + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SElasticcache) GetCreatedAt() time.Time { + var createtime time.Time + if len(self.CreatedAt) > 0 { + createtime, _ = time.Parse("2006-01-02T15:04:05.000Z", self.CreatedAt) + } + + return createtime +} + +func (self *SElasticcache) GetExpiredAt() time.Time { + var expiredTime time.Time + if self.ChargingMode == 1 { + res, err := self.region.GetOrderResourceDetail(self.GetId()) + if err != nil { + log.Debugln(err) + } + + expiredTime = res.ExpireTime + } + + return expiredTime +} + +func (self *SElasticcache) GetInstanceType() string { + // todo: ?? + return self.ResourceSpecCode +} + +func (self *SElasticcache) GetCapacityMB() int { + return self.CapacityGB * 1024 +} + +func (self *SElasticcache) GetArchType() string { + /* + 资源规格标识。 + + dcs.single_node:表示实例类型为单机 + dcs.master_standby:表示实例类型为主备 + dcs.cluster:表示实例类型为集群 + */ + if strings.Contains(self.ResourceSpecCode, "single") { + return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE + } else if strings.Contains(self.ResourceSpecCode, "ha") { + return api.ELASTIC_CACHE_ARCH_TYPE_MASTER + } else if strings.Contains(self.ResourceSpecCode, "cluster") { + return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER + } else if strings.Contains(self.ResourceSpecCode, "proxy") { + return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER + } + + return "" +} + +func (self *SElasticcache) GetNodeType() string { + // single(单副本) | double(双副本) + if strings.Contains(self.ResourceSpecCode, "single") { + return "single" + } else { + return "double" + } +} + +func (self *SElasticcache) GetEngine() string { + return self.Engine +} + +func (self *SElasticcache) GetEngineVersion() string { + return self.EngineVersion +} + +func (self *SElasticcache) GetVpcId() string { + return self.VpcID +} + +func (self *SElasticcache) GetZoneId() string { + if len(self.AvailableZones) > 0 { + zone, err := self.region.getZoneById(self.AvailableZones[0]) + if err != nil { + log.Errorf("elasticcache.GetZoneId %s", err) + return "" + } + + return zone.GetGlobalId() + } + + return "" +} + +func (self *SElasticcache) GetNetworkType() string { + return api.LB_NETWORK_TYPE_VPC +} + +func (self *SElasticcache) GetNetworkId() string { + return self.SubnetID +} + +func (self *SElasticcache) GetPrivateDNS() string { + return self.DomainName +} + +func (self *SElasticcache) GetPrivateIpAddr() string { + return self.IP +} + +func (self *SElasticcache) GetPrivateConnectPort() int { + return self.Port +} + +func (self *SElasticcache) GetPublicDNS() string { + return self.PublicipAddress +} + +func (self *SElasticcache) GetPublicIpAddr() string { + return self.PublicipAddress +} + +func (self *SElasticcache) GetPublicConnectPort() int { + return self.Port +} + +func (self *SElasticcache) GetMaintainStartTime() string { + return self.MaintainBegin +} + +func (self *SElasticcache) GetMaintainEndTime() string { + return self.MaintainEnd +} + +func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { + iaccounts := []cloudprovider.ICloudElasticcacheAccount{} + iaccount := &SElasticcacheAccount{cacheDB: self} + iaccounts = append(iaccounts, iaccount) + return iaccounts, nil +} + +func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { + // 华为云使用安全组做访问控制。目前未支持 + return []cloudprovider.ICloudElasticcacheAcl{}, nil +} + +func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { + start := self.GetCreatedAt().Format("20060102150405") + end := time.Now().Format("20060102150405") + backups, err := self.region.GetElasticCacheBackups(self.GetId(), start, end) + if err != nil { + return nil, err + } + + ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) + for i := range backups { + backups[i].cacheDB = self + ibackups[i] = &backups[i] + } + + return ibackups, nil +} + +func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { + parameters, err := self.region.GetElasticCacheParameters(self.GetId()) + if err != nil { + return nil, err + } + + iparameters := make([]cloudprovider.ICloudElasticcacheParameter, len(parameters)) + for i := range parameters { + parameters[i].cacheDB = self + iparameters[i] = ¶meters[i] + } + + return iparameters, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423035.html +func (self *SRegion) GetElasticCacheBackups(instanceId, startTime, endTime string) ([]SElasticcacheBackup, error) { + params := make(map[string]string) + params["instance_id"] = instanceId + params["beginTime"] = startTime + params["endTime"] = endTime + + backups := make([]SElasticcacheBackup, 0) + err := doListAll(self.ecsClient.Elasticcache.ListBackups, params, &backups) + if err != nil { + return nil, err + } + + return backups, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html +func (self *SRegion) GetElasticCacheParameters(instanceId string) ([]SElasticcacheParameter, error) { + params := make(map[string]string) + params["instance_id"] = instanceId + + parameters := make([]SElasticcacheParameter, 0) + err := doListAll(self.ecsClient.Elasticcache.ListParameters, params, ¶meters) + if err != nil { + return nil, err + } + + return parameters, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423044.html +func (self *SRegion) GetElasticCaches() ([]SElasticcache, error) { + params := make(map[string]string) + caches := make([]SElasticcache, 0) + err := doListAll(self.ecsClient.Elasticcache.List, params, &caches) + if err != nil { + return nil, errors.Wrap(err, "region.GetElasticCaches") + } + + for i := range caches { + cache, err := self.GetElasticCache(caches[i].GetId()) + if err != nil { + return nil, err + } else { + caches[i] = *cache + } + + caches[i].region = self + } + + return caches, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423020.html +func (self *SRegion) GetElasticCache(instanceId string) (*SElasticcache, error) { + cache := SElasticcache{} + err := DoGet(self.ecsClient.Elasticcache.Get, instanceId, nil, &cache) + if err != nil { + return nil, errors.Wrapf(err, "region.GetElasticCache %s", instanceId) + } + + cache.region = self + return &cache, nil +} + +func (self *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { + ec, err := self.GetElasticCache(id) + if err != nil { + return nil, errors.Wrap(err, "region.GetIElasticCacheById.GetElasticCache") + } + + return ec, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423047.html +func (self *SRegion) zoneNameToDcsZoneIds(zoneIds []string) ([]string, error) { + type Z struct { + ID string `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + Port string `json:"port"` + ResourceAvailability string `json:"resource_availability"` + } + + rs := []Z{} + err := doListAll(self.ecsClient.DcsAvailableZone.List, nil, &rs) + if err != nil { + return nil, errors.Wrap(err, "region.zoneNameToDcsZoneIds") + } + + zoneMap := map[string]string{} + for i := range rs { + if rs[i].ResourceAvailability == "true" { + zoneMap[rs[i].Code] = rs[i].ID + } + } + + ret := []string{} + for _, zone := range zoneIds { + if id, ok := zoneMap[zone]; ok { + ret = append(ret, id) + } else { + return nil, errors.Wrap(fmt.Errorf("zone %s not found or not available", zone), "region.zoneNameToDcsZoneIds") + } + } + + return ret, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423019.html +func (self *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { + params := jsonutils.NewDict() + params.Set("name", jsonutils.NewString(ec.InstanceName)) + params.Set("engine", jsonutils.NewString(ec.Engine)) + params.Set("engine_version", jsonutils.NewString(ec.EngineVersion)) + params.Set("capacity", jsonutils.NewInt(ec.CapacityGB)) + params.Set("vpc_id", jsonutils.NewString(ec.VpcId)) + if len(ec.SecurityGroupIds) > 0 { + params.Set("security_group_id", jsonutils.NewString(ec.SecurityGroupIds[0])) + } + params.Set("subnet_id", jsonutils.NewString(ec.NetworkId)) + params.Set("product_id", jsonutils.NewString(ec.InstanceType)) + zones, err := self.zoneNameToDcsZoneIds(ec.ZoneIds) + if err != nil { + return nil, err + } + params.Set("available_zones", jsonutils.NewStringArray(zones)) + + if len(ec.ProjectId) > 0 { + params.Set("enterprise_project_id", jsonutils.NewString(ec.ProjectId)) + } + + if len(ec.Password) > 0 { + params.Set("no_password_access", jsonutils.NewString("false")) + params.Set("password", jsonutils.NewString(ec.Password)) + + // todo: 这里换成常量 + if ec.Engine == "Memcache" { + params.Set("access_user", jsonutils.NewString(ec.UserName)) + } + } else { + params.Set("no_password_access", jsonutils.NewString("true")) + } + + if len(ec.EipId) > 0 { + params.Set("enable_publicip", jsonutils.NewString("true")) + params.Set("publicip_id", jsonutils.NewString(ec.EipId)) + // enable_ssl + } else { + params.Set("enable_publicip", jsonutils.NewString("false")) + } + + if len(ec.PrivateIpAddress) > 0 { + params.Set("private_ip", jsonutils.NewString(ec.PrivateIpAddress)) + } + + if len(ec.MaintainBegin) > 0 { + params.Set("maintain_begin", jsonutils.NewString(ec.MaintainBegin)) + params.Set("maintain_end", jsonutils.NewString(ec.MaintainEnd)) + } + + if ec.BillingCycle != nil { + bssParam := jsonutils.NewDict() + bssParam.Set("charging_mode", jsonutils.NewString("prePaid")) + bssParam.Set("is_auto_pay", jsonutils.NewString("true")) + bssParam.Set("is_auto_renew", jsonutils.NewString(fmt.Sprintf("%v", ec.BillingCycle.AutoRenew))) + if ec.BillingCycle.GetMonths() >= 1 && ec.BillingCycle.GetMonths() >= 9 { + bssParam.Set("period_type", jsonutils.NewString("month")) + bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetMonths()))) + } else if ec.BillingCycle.GetYears() >= 1 && ec.BillingCycle.GetYears() <= 3 { + bssParam.Set("period_type", jsonutils.NewString("year")) + bssParam.Set("period_num", jsonutils.NewInt(int64(ec.BillingCycle.GetYears()))) + } else { + return nil, fmt.Errorf("region.CreateIElasticcaches invalid billing cycle.reqired month (1~9) or year(1~3)") + } + + params.Set("bss_param", bssParam) + } + + ret := &SElasticcache{} + err = DoCreate(self.ecsClient.Elasticcache.Create, params, ret) + if err != nil { + return nil, errors.Wrap(err, "region.CreateIElasticcaches") + } + + ret.region = self + return ret, nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html +func (self *SElasticcache) Restart() error { + resp, err := self.region.ecsClient.Elasticcache.Restart(self.GetId()) + if err != nil { + return errors.Wrap(err, "elasticcache.Restart") + } + + rets, err := resp.GetArray("results") + if err != nil { + return errors.Wrap(err, "elasticcache.results") + } + + for _, r := range rets { + if ret, _ := r.GetString("result"); ret != "success" { + return fmt.Errorf("elasticcache.Restart failed") + } + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423022.html +func (self *SElasticcache) Delete() error { + err := DoDelete(self.region.ecsClient.Elasticcache.Delete, self.GetId(), nil, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.Delete") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423024.html +func (self *SElasticcache) ChangeInstanceSpec(spec string) error { + segs := strings.Split(spec, ":") + if len(segs) < 2 { + return fmt.Errorf("elasticcache.ChangeInstanceSpec invalid sku %s", spec) + } + + if !strings.HasPrefix(segs[1], "m") || !strings.HasSuffix(segs[1], "g") { + return fmt.Errorf("elasticcache.ChangeInstanceSpec sku %s memeory size is invalid.", spec) + } + + newCapacity := segs[1][1 : len(segs[1])-1] + capacity, err := strconv.Atoi(newCapacity) + if err != nil { + return errors.Wrap(fmt.Errorf("invalid sku capacity %s", spec), "Elasticcache.ChangeInstanceSpec") + } + + _, err = self.region.ecsClient.Elasticcache.ChangeInstanceSpec(self.GetId(), segs[0], int64(capacity)) + if err != nil { + return errors.Wrap(err, "elasticcache.ChangeInstanceSpec") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html +func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { + params := jsonutils.NewDict() + params.Set("maintain_begin", jsonutils.NewString(maintainStartTime)) + params.Set("maintain_end", jsonutils.NewString(maintainEndTime)) + err := DoUpdate(self.region.ecsClient.Elasticcache.Update, self.GetId(), params, nil) + if err != nil { + return errors.Wrap(err, "elasticcache.SetMaintainTime") + } + + return nil +} + +// https://support.huaweicloud.com/usermanual-dcs/dcs-zh-ug-180314001.html +// 目前只有Redis3.0版本密码模式的实例支持通过公网访问Redis实例,其他版本暂不支持公网访问。 +// todo: 目前没找到api +func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +// todo: 目前没找到api +func (self *SElasticcache) ReleasePublicConnection() error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { + return nil, cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423031.html + +func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423029.html +func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { + params := jsonutils.NewDict() + params.Set("redis_config", config) + err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423033.html +func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func backupPeriodTrans(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) *jsonutils.JSONArray { + segs := strings.Split(config.PreferredBackupPeriod, ",") + ret := jsonutils.NewArray() + for _, seg := range segs { + switch seg { + case "Monday": + ret.Add(jsonutils.NewString("1")) + case "Tuesday": + ret.Add(jsonutils.NewString("2")) + case "Wednesday": + ret.Add(jsonutils.NewString("3")) + case "Thursday": + ret.Add(jsonutils.NewString("4")) + case "Friday": + ret.Add(jsonutils.NewString("5")) + case "Saturday": + ret.Add(jsonutils.NewString("6")) + case "Sunday": + ret.Add(jsonutils.NewString("7")) + } + } + + return ret +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423021.html +func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { + params := jsonutils.NewDict() + policy := jsonutils.NewDict() + policy.Set("save_days", jsonutils.NewInt(int64(config.BackupReservedDays))) + policy.Set("backup_type", jsonutils.NewString(config.BackupType)) + plan := jsonutils.NewDict() + backTime := strings.ReplaceAll(config.PreferredBackupTime, "Z", "") + backupPeriod := backupPeriodTrans(config) + plan.Set("begin_at", jsonutils.NewString(backTime)) + plan.Set("period_type", jsonutils.NewString("weekly")) + plan.Set("backup_at", backupPeriod) + policy.Set("periodical_backup_plan", plan) + params.Set("instance_backup_policy", policy) + err := DoUpdateWithSpec(self.region.ecsClient.Elasticcache.UpdateInContextWithSpec, self.GetId(), "configs", params) + if err != nil { + return errors.Wrap(err, "elasticcache.UpdateInstanceParameters") + } + + return nil +} + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423030.html +// 当前版本,只有DCS2.0实例支持清空数据功能,即flush操作。 +func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { + resp, err := self.region.ecsClient.Elasticcache.Flush(self.GetId()) + if err != nil { + return errors.Wrap(err, "elasticcache.FlushInstance") + } + + rets, err := resp.GetArray("results") + if err != nil { + return errors.Wrap(err, "elasticcache.FlushInstance") + } + + for _, r := range rets { + if ret, _ := r.GetString("result"); ret != "success" { + return fmt.Errorf("elasticcache.FlushInstance failed") + } + } + + return nil +} + +// SElasticcacheAccount => ResetPassword +func (self *SElasticcache) UpdateAuthMode(noPwdAccess bool, password string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetAuthMode() string { + switch self.NoPasswordAccess { + case "true": + return "off" + default: + return "on" + } +} + +func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { + accounts, err := self.GetICloudElasticcacheAccounts() + if err != nil { + return nil, errors.Wrap(err, "Elasticcache.GetICloudElasticcacheAccount.Accounts") + } + + for i := range accounts { + account := accounts[i] + if account.GetGlobalId() == accountId { + return account, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { + backups, err := self.GetICloudElasticcacheBackups() + if err != nil { + return nil, err + } + + for _, backup := range backups { + if backup.GetId() == backupId { + return backup, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (instance *SElasticcache) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { + return errors.Wrap(cloudprovider.ErrNotSupported, "UpdateSecurityGroups") +} + +func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) SetAutoRenew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_parameter.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_parameter.go new file mode 100644 index 0000000000..0aaabbc0a3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/elasticcache_parameter.go @@ -0,0 +1,78 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://support.huaweicloud.com/api-dcs/dcs-zh-api-180423027.html +type SElasticcacheParameter struct { + multicloud.SElasticcacheParameterBase + HuaweiTags + + cacheDB *SElasticcache + + Description string `json:"description"` + ParamID int64 `json:"param_id"` + ParamName string `json:"param_name"` + ParamValue string `json:"param_value"` + DefaultValue string `json:"default_value"` + ValueType string `json:"value_type"` + ValueRange string `json:"value_range"` +} + +func (self *SElasticcacheParameter) GetId() string { + return fmt.Sprintf("%d", self.ParamID) +} + +func (self *SElasticcacheParameter) GetName() string { + return self.ParamName +} + +func (self *SElasticcacheParameter) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.cacheDB.InstanceID, self.GetId()) +} + +func (self *SElasticcacheParameter) GetStatus() string { + return api.ELASTIC_CACHE_PARAMETER_STATUS_AVAILABLE +} + +func (self *SElasticcacheParameter) GetParameterKey() string { + return self.ParamName +} + +func (self *SElasticcacheParameter) GetParameterValue() string { + return self.ParamValue +} + +func (self *SElasticcacheParameter) GetParameterValueRange() string { + return self.Description +} + +func (self *SElasticcacheParameter) GetDescription() string { + return self.ValueRange +} + +func (self *SElasticcacheParameter) GetModifiable() bool { + return true +} + +func (self *SElasticcacheParameter) GetForceRestart() bool { + return false +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/enterpriceprojects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/enterpriceprojects.go new file mode 100644 index 0000000000..1472f9614b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/enterpriceprojects.go @@ -0,0 +1,114 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://support.huaweicloud.com/api-em/zh-cn_topic_0121230880.html +type SEnterpriseProject struct { + multicloud.SProjectBase + HuaweiTags + + Id string + Name string + Description string + Status int + CreatedAt time.Time + UpdatedAt time.Time +} + +func (self *SHuaweiClient) GetEnterpriseProjects() ([]SEnterpriseProject, error) { + projects := []SEnterpriseProject{} + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + err = doListAllWithOffset(client.EnterpriseProjects.List, map[string]string{}, &projects) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithOffset") + } + return projects, nil +} + +func (ep *SEnterpriseProject) GetId() string { + return ep.Id +} + +func (ep *SEnterpriseProject) GetGlobalId() string { + return ep.Id +} + +func (ep *SEnterpriseProject) GetStatus() string { + if ep.Status == 1 { + return api.EXTERNAL_PROJECT_STATUS_AVAILABLE + } + return api.EXTERNAL_PROJECT_STATUS_UNAVAILABLE +} + +func (ep *SEnterpriseProject) GetName() string { + return ep.Name +} + +func (self *SHuaweiClient) CreateExterpriseProject(name, desc string) (*SEnterpriseProject, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + params := map[string]string{ + "name": name, + } + if len(desc) > 0 { + params["description"] = desc + } + resp, err := client.EnterpriseProjects.Create(jsonutils.Marshal(params)) + if err != nil { + if strings.Contains(err.Error(), "EPS.0004") { + return nil, cloudprovider.ErrNotSupported + } + return nil, errors.Wrap(err, "EnterpriseProjects.Create") + } + project := &SEnterpriseProject{} + err = resp.Unmarshal(&project) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return project, nil +} + +func (self *SHuaweiClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return self.CreateExterpriseProject(name, "") +} + +func (self *SHuaweiClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { + projects, err := self.GetEnterpriseProjects() + if err != nil { + return nil, errors.Wrap(err, "GetProjects") + } + ret := []cloudprovider.ICloudProject{} + for i := range projects { + ret = append(ret, &projects[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/host.go new file mode 100644 index 0000000000..6060787799 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/host.go @@ -0,0 +1,306 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone + + projectId string +} + +func (self *SHost) GetId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) +} + +func (self *SHost) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) Refresh() error { + return nil +} + +func (self *SHost) IsEmulated() bool { + return true +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms, err := self.zone.region.GetInstances() + if err != nil { + return nil, err + } + + filtedVms := make([]SInstance, 0) + for i := range vms { + if vms[i].OSEXTAZAvailabilityZone == self.zone.GetId() { + filtedVms = append(filtedVms, vms[i]) + } + } + + ivms := make([]cloudprovider.ICloudVM, len(filtedVms)) + for i := 0; i < len(filtedVms); i += 1 { + filtedVms[i].host = self + ivms[i] = &filtedVms[i] + } + return ivms, nil +} + +func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := self.zone.region.GetInstanceByID(id) + vm.host = self + return &vm, err +} + +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 api.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_HUAWEI), "manufacture") + return info +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetCpuCount() int { + 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 api.DISK_TYPE_HYBRID +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_HUAWEI +} + +func (self *SHost) GetIsMaintenance() bool { + return false +} + +func (self *SHost) GetVersion() string { + return HUAWEI_API_VERSION +} + +func (self *SHost) GetInstanceById(instanceId string) (*SInstance, error) { + instance, err := self.zone.region.GetInstanceByID(instanceId) + if err != nil { + return nil, err + } + + instance.host = self + return &instance, nil +} + +func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + vmId, err := self._createVM( + desc.Name, desc.ExternalImageId, desc.SysDisk, + desc.Cpu, desc.MemoryMB, desc.InstanceType, + desc.ExternalNetworkId, desc.IpAddr, + desc.Description, desc.Account, + desc.Password, desc.DataDisks, + desc.PublicKey, desc.ExternalSecgroupId, + desc.UserData, desc.BillingCycle, desc.ProjectId, desc.Tags) + if err != nil { + return nil, err + } + + vm, err := self.GetInstanceById(vmId) + if err != nil { + return nil, err + } + + return vm, err +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SHost) _createVM(name string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, + networkId string, ipAddr string, desc string, account string, passwd string, + diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string, + userData string, bc *billing.SBillingCycle, projectId string, tags map[string]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") + } + + // 同步keypair + var err error + keypair := "" + if len(publicKey) > 0 { + 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 %s fail %s", imgId, err) + return "", err + } + if img.Status != ImageStatusActive { + log.Errorf("image %s status %s", imgId, img.Status) + return "", fmt.Errorf("image not ready") + } + // passwd, windows机型直接使用密码比较方便 + if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(passwd) > 0 { + keypair = "" + } + + if strings.ToLower(img.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) { + if u, err := updateWindowsUserData(userData, img.OSVersion, account, passwd); err == nil { + userData = u + } else { + return "", errors.Wrap(err, "SHost.CreateVM.updateWindowsUserData") + } + } + + disks := make([]SDisk, len(diskSizes)+1) + disks[0].SizeGB = img.SizeGB + if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.SizeGB { + disks[0].SizeGB = sysDisk.SizeGB + } + disks[0].VolumeType = sysDisk.StorageType + + for i, dataDisk := range diskSizes { + disks[i+1].SizeGB = dataDisk.SizeGB + disks[i+1].VolumeType = dataDisk.StorageType + } + + _, err = self.zone.region.GetSecurityGroupDetails(secgroupId) + if err != nil { + return "", errors.Wrap(err, "SHost.CreateVM.GetSecurityGroupDetails") + } + + // 创建实例 + if len(instanceType) > 0 { + log.Debugf("Try instancetype : %s", instanceType) + vmId, err := self.zone.region.CreateInstance(name, imgId, instanceType, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) + if err != nil { + log.Errorf("Failed for %s: %s", instanceType, err) + return "", fmt.Errorf("create %s failed:%s", instanceType, ErrMessage(err)) + } else { + return vmId, nil + } + } + + // 匹配实例类型 + instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, self.zone.GetId()) + if err != nil { + return "", err + } + if len(instanceTypes) == 0 { + return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB) + } + + var vmId string + for _, instType := range instanceTypes { + instanceTypeId := instType.Name + log.Debugf("Try instancetype : %s", instanceTypeId) + vmId, err = self.zone.region.CreateInstance(name, imgId, instanceTypeId, networkId, secgroupId, net.VpcID, self.zone.GetId(), desc, disks, ipAddr, keypair, publicKey, passwd, userData, bc, projectId, tags) + if err != nil { + log.Errorf("Failed for %s: %s", instanceTypeId, err) + } else { + return vmId, nil + } + } + + return "", fmt.Errorf("create failed: %s", ErrMessage(err)) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/huawei.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/huawei.go new file mode 100644 index 0000000000..8ea40142c9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/huawei.go @@ -0,0 +1,863 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + "sync" + "time" + + "github.com/huaweicloud/huaweicloud-sdk-go/auth/aksk" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/gotypes" + "yunion.io/x/pkg/util/timeutils" + + "yunion.io/x/onecloud/pkg/util/httputils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/auth/credentials" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" +) + +/* +待解决问题: +1.同步的子账户中有一条空记录.需要查原因 +2.安全组同步需要进一步确认 +3.实例接口需要进一步确认 +4.BGP type 目前是hard code在代码中。需要考虑从cloudmeta服务中查询 +*/ + +const ( + CLOUD_PROVIDER_HUAWEI = api.CLOUD_PROVIDER_HUAWEI + CLOUD_PROVIDER_HUAWEI_CN = "华为云" + CLOUD_PROVIDER_HUAWEI_EN = "Huawei" + + HUAWEI_INTERNATIONAL_CLOUDENV = "InternationalCloud" + HUAWEI_CHINA_CLOUDENV = "ChinaCloud" + + HUAWEI_DEFAULT_REGION = "cn-north-1" + HUAWEI_API_VERSION = "2018-12-25" +) + +var HUAWEI_REGION_CACHES sync.Map + +type userRegionsCache struct { + UserId string + ExpireAt time.Time + Regions []SRegion +} + +type HuaweiClientConfig struct { + cpcfg cloudprovider.ProviderConfig + + projectId string // 华为云项目ID. + cloudEnv string // 服务区域 ChinaCloud | InternationalCloud + accessKey string + accessSecret string + + debug bool +} + +func NewHuaweiClientConfig(cloudEnv, accessKey, accessSecret, projectId string) *HuaweiClientConfig { + cfg := &HuaweiClientConfig{ + projectId: projectId, + cloudEnv: cloudEnv, + accessKey: accessKey, + accessSecret: accessSecret, + } + return cfg +} + +func (cfg *HuaweiClientConfig) CloudproviderConfig(cpcfg cloudprovider.ProviderConfig) *HuaweiClientConfig { + cfg.cpcfg = cpcfg + return cfg +} + +func (cfg *HuaweiClientConfig) Debug(debug bool) *HuaweiClientConfig { + cfg.debug = debug + return cfg +} + +type SHuaweiClient struct { + *HuaweiClientConfig + + signer auth.Signer + + isMainProject bool // whether the project is the main project in the region + clientRegion string + + ownerId string + ownerName string + ownerCreateTime time.Time + + iregions []cloudprovider.ICloudRegion + iBuckets []cloudprovider.ICloudBucket + + projects []SProject + regions []SRegion + + httpClient *http.Client +} + +// 进行资源操作时参数account 对应数据库cloudprovider表中的account字段,由accessKey和projectID两部分组成,通过"/"分割。 +// 初次导入Subaccount时,参数account对应cloudaccounts表中的account字段,即accesskey。此时projectID为空, +// 只能进行同步子账号、查询region列表等projectId无关的操作。 +// todo: 通过accessurl支持国际站。目前暂时未支持国际站 +func NewHuaweiClient(cfg *HuaweiClientConfig) (*SHuaweiClient, error) { + client := SHuaweiClient{ + HuaweiClientConfig: cfg, + } + err := client.init() + if err != nil { + return nil, err + } + return &client, nil +} + +func (self *SHuaweiClient) init() error { + err := self.fetchRegions() + if err != nil { + return err + } + err = self.initSigner() + if err != nil { + return errors.Wrap(err, "initSigner") + } + err = self.initOwner() + if err != nil { + return errors.Wrap(err, "fetchOwner") + } + if self.debug { + log.Debugf("OwnerId: %s name: %s", self.ownerId, self.ownerName) + } + return nil +} + +func (self *SHuaweiClient) initSigner() error { + var err error + cred := credentials.NewAccessKeyCredential(self.accessKey, self.accessKey) + self.signer, err = auth.NewSignerWithCredential(cred) + if err != nil { + return err + } + return nil +} + +func (self *SHuaweiClient) getDefaultClient() *http.Client { + if self.httpClient != nil { + return self.httpClient + } + self.httpClient = self.cpcfg.AdaptiveTimeoutHttpClient() + ts, _ := self.httpClient.Transport.(*http.Transport) + self.httpClient.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { + service, method, path := strings.Split(req.URL.Host, ".")[0], req.Method, req.URL.Path + respCheck := func(resp *http.Response) { + if resp.StatusCode == 403 { + if self.cpcfg.UpdatePermission != nil { + self.cpcfg.UpdatePermission(service, fmt.Sprintf("%s %s", method, path)) + } + } + } + if self.cpcfg.ReadOnly { + if req.Method == "GET" { + return respCheck, nil + } + return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) + } + return respCheck, nil + }) + return self.httpClient +} + +func (self *SHuaweiClient) newRegionAPIClient(regionId string) (*client.Client, error) { + projectId := self.projectId + if len(regionId) == 0 { + projectId = "" + } + cli, err := client.NewPublicCloudClientWithAccessKey(regionId, self.ownerId, projectId, self.accessKey, self.accessSecret, self.debug) + if err != nil { + return nil, err + } + + httpClient := self.getDefaultClient() + cli.SetHttpClient(httpClient) + + return cli, nil +} + +type sPageInfo struct { + NextMarker string +} + +func (self *SHuaweiClient) newGeneralAPIClient() (*client.Client, error) { + return self.newRegionAPIClient("") +} + +func (self *SHuaweiClient) lbList(regionId, resource string, query url.Values) (jsonutils.JSONObject, error) { + url := fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) + return self.request(httputils.GET, url, query, nil) +} + +func (self *SHuaweiClient) monitorList(resource string, query url.Values) (jsonutils.JSONObject, error) { + url := fmt.Sprintf("https://ces.%s.myhuaweicloud.com/v1.0/%s/%s", self.clientRegion, self.projectId, resource) + return self.request(httputils.GET, url, query, nil) +} + +func (self *SHuaweiClient) monitorPost(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + url := fmt.Sprintf("https://ces.%s.myhuaweicloud.com/V1.0/%s/%s", self.clientRegion, self.projectId, resource) + return self.request(httputils.POST, url, nil, params) +} + +func (self *SHuaweiClient) modelartsPoolNetworkList(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/networks", self.clientRegion, self.projectId) + return self.request(httputils.GET, uri, url.Values{}, params) +} + +func (self *SHuaweiClient) modelartsPoolNetworkCreate(params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/networks", self.clientRegion, self.projectId) + return self.request(httputils.POST, uri, url.Values{}, params) +} + +func (self *SHuaweiClient) modelartsPoolById(poolName string) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/pools/%s", self.clientRegion, self.projectId, poolName) + return self.request(httputils.GET, uri, url.Values{}, nil) +} + +func (self *SHuaweiClient) modelartsPoolList(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/%s", self.clientRegion, self.projectId, resource) + return self.request(httputils.GET, uri, url.Values{}, params) +} + +func (self *SHuaweiClient) modelartsPoolCreate(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/%s", self.clientRegion, self.projectId, resource) + return self.request(httputils.POST, uri, url.Values{}, params) +} + +func (self *SHuaweiClient) modelartsPoolDelete(resource, poolName string, params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/pools/%s", self.clientRegion, self.projectId, poolName) + return self.request(httputils.DELETE, uri, url.Values{}, params) +} + +func (self *SHuaweiClient) modelartsPoolUpdate(poolName string, params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/pools/%s", self.clientRegion, self.projectId, poolName) + urlValue := url.Values{} + urlValue.Add("time_range", "") + urlValue.Add("statistics", "") + urlValue.Add("period", "") + return self.patchRequest(httputils.PATCH, uri, urlValue, params) +} + +func (self *SHuaweiClient) modelartsPoolMonitor(poolName string, params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v2/%s/pools/%s/monitor", self.clientRegion, self.projectId, poolName) + return self.request(httputils.GET, uri, url.Values{}, params) +} + +func (self *SHuaweiClient) modelartsResourceflavors(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://modelarts.%s.myhuaweicloud.com/v1/%s/%s", self.clientRegion, self.projectId, resource) + return self.request(httputils.GET, uri, url.Values{}, params) +} + +func (self *SHuaweiClient) getAKSKList(userId string) (jsonutils.JSONObject, error) { + params := url.Values{} + params.Set("user_id", userId) + uri := fmt.Sprintf("https://iam.cn-north-4.myhuaweicloud.com/v3.0/OS-CREDENTIAL/credentials") + return self.request(httputils.GET, uri, params, nil) +} + +func (self *SHuaweiClient) deleteAKSK(accesskey string) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://iam.cn-north-4.myhuaweicloud.com/v3.0/OS-CREDENTIAL/credentials/%s", accesskey) + return self.request(httputils.DELETE, uri, url.Values{}, nil) +} + +func (self *SHuaweiClient) createAKSK(params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://iam.cn-north-4.myhuaweicloud.com/v3.0/OS-CREDENTIAL/credentials") + return self.request(httputils.POST, uri, url.Values{}, params) +} + +func (self *SHuaweiClient) lbGet(regionId, resource string) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) + return self.request(httputils.GET, uri, url.Values{}, nil) +} + +func (self *SHuaweiClient) lbCreate(regionId, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) + return self.request(httputils.POST, uri, url.Values{}, params) +} + +func (self *SHuaweiClient) lbUpdate(regionId, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) + return self.request(httputils.PUT, uri, url.Values{}, params) +} + +func (self *SHuaweiClient) lbDelete(regionId, resource string) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://elb.%s.myhuaweicloud.com/v2/%s/%s", regionId, self.projectId, resource) + return self.request(httputils.DELETE, uri, url.Values{}, nil) +} + +func (self *SHuaweiClient) vpcList(regionId, resource string, query url.Values) (jsonutils.JSONObject, error) { + url := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) + return self.request(httputils.GET, url, query, nil) +} + +func (self *SHuaweiClient) vpcCreate(regionId, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) + return self.request(httputils.POST, uri, url.Values{}, params) +} + +func (self *SHuaweiClient) vpcGet(regionId, resource string) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) + return self.request(httputils.GET, uri, url.Values{}, nil) +} + +func (self *SHuaweiClient) vpcDelete(regionId, resource string) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) + return self.request(httputils.DELETE, uri, url.Values{}, nil) +} + +func (self *SHuaweiClient) vpcUpdate(regionId, resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + uri := fmt.Sprintf("https://vpc.%s.myhuaweicloud.com/v1/%s/%s", regionId, self.projectId, resource) + return self.request(httputils.PUT, uri, url.Values{}, params) +} + +type akClient struct { + client *http.Client + aksk aksk.SignOptions +} + +func (self *akClient) Do(req *http.Request) (*http.Response, error) { + req.Header.Del("Accept") + if req.Method == string(httputils.GET) || req.Method == string(httputils.DELETE) || req.Method == string(httputils.PATCH) { + req.Header.Del("Content-Length") + } + aksk.Sign(req, self.aksk) + return self.client.Do(req) +} + +func (self *SHuaweiClient) getAkClient() *akClient { + return &akClient{ + client: self.getDefaultClient(), + aksk: aksk.SignOptions{ + AccessKey: self.accessKey, + SecretKey: self.accessSecret, + }, + } +} + +func (self *SHuaweiClient) request(method httputils.THttpMethod, url string, query url.Values, params map[string]interface{}) (jsonutils.JSONObject, error) { + client := self.getAkClient() + if len(query) > 0 { + url = fmt.Sprintf("%s?%s", url, query.Encode()) + } + var body jsonutils.JSONObject = nil + if len(params) > 0 { + body = jsonutils.Marshal(params) + } + header := http.Header{} + if len(self.projectId) > 0 { + header.Set("X-Project-Id", self.projectId) + } + if strings.Contains(url, "/OS-CREDENTIAL/credentials") && len(self.ownerId) > 0 { + header.Set("X-Domain-Id", self.ownerId) + } + _, resp, err := httputils.JSONRequest(client, context.Background(), method, url, header, body, self.debug) + if err != nil { + if e, ok := err.(*httputils.JSONClientError); ok && e.Code == 404 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, err.Error()) + } + return nil, err + } + return resp, err +} + +func (self *SHuaweiClient) fetchRegions() error { + huawei, _ := self.newGeneralAPIClient() + if self.regions == nil { + userId, err := self.GetUserId() + if err != nil { + return errors.Wrap(err, "GetUserId") + } + + if regionsCache, ok := HUAWEI_REGION_CACHES.Load(userId); !ok || regionsCache.(*userRegionsCache).ExpireAt.Sub(time.Now()).Seconds() > 0 { + regions := make([]SRegion, 0) + err := doListAll(huawei.Regions.List, nil, ®ions) + if err != nil { + return errors.Wrap(err, "Regions.List") + } + + HUAWEI_REGION_CACHES.Store(userId, &userRegionsCache{ExpireAt: time.Now().Add(24 * time.Hour), UserId: userId, Regions: regions}) + } + + if regionsCache, ok := HUAWEI_REGION_CACHES.Load(userId); ok { + self.regions = regionsCache.(*userRegionsCache).Regions + } + } + + filtedRegions := make([]SRegion, 0) + if len(self.projectId) > 0 { + project, err := self.GetProjectById(self.projectId) + if err != nil { + return err + } + + for _, region := range self.regions { + if strings.Count(project.Name, region.ID) >= 1 { + self.clientRegion = region.ID + filtedRegions = append(filtedRegions, region) + } + if project.Name == region.ID { + self.isMainProject = true + } + } + } else { + filtedRegions = self.regions + } + + if len(filtedRegions) == 0 { + return errors.Wrapf(cloudprovider.ErrNotFound, "empty regions") + } + + self.iregions = make([]cloudprovider.ICloudRegion, len(filtedRegions)) + for i := 0; i < len(filtedRegions); i += 1 { + filtedRegions[i].client = self + _, err := filtedRegions[i].getECSClient() + if err != nil { + return err + } + self.iregions[i] = &filtedRegions[i] + } + return nil +} + +func (self *SHuaweiClient) invalidateIBuckets() { + self.iBuckets = nil +} + +func (self *SHuaweiClient) getIBuckets() ([]cloudprovider.ICloudBucket, error) { + if self.iBuckets == nil { + err := self.fetchBuckets() + if err != nil { + return nil, errors.Wrap(err, "fetchBuckets") + } + } + return self.iBuckets, nil +} + +func getOBSEndpoint(regionId string) string { + return fmt.Sprintf("obs.%s.myhuaweicloud.com", regionId) +} + +func (self *SHuaweiClient) getOBSClient(regionId string) (*obs.ObsClient, error) { + endpoint := getOBSEndpoint(regionId) + cli, err := obs.New(self.accessKey, self.accessSecret, endpoint) + if err != nil { + return nil, err + } + client := cli.GetClient() + ts, _ := client.Transport.(*http.Transport) + client.Transport = cloudprovider.GetCheckTransport(ts, func(req *http.Request) (func(resp *http.Response), error) { + method, path := req.Method, req.URL.Path + respCheck := func(resp *http.Response) { + if resp.StatusCode == 403 { + if self.cpcfg.UpdatePermission != nil { + self.cpcfg.UpdatePermission("obs", fmt.Sprintf("%s %s", method, path)) + } + } + } + if self.cpcfg.ReadOnly { + if req.Method == "GET" || req.Method == "HEAD" { + return respCheck, nil + } + return nil, errors.Wrapf(cloudprovider.ErrAccountReadOnly, "%s %s", req.Method, req.URL.Path) + } + return respCheck, nil + }) + + return cli, nil +} + +func (self *SHuaweiClient) fetchBuckets() error { + obscli, err := self.getOBSClient(HUAWEI_DEFAULT_REGION) + if err != nil { + return errors.Wrap(err, "getOBSClient") + } + input := &obs.ListBucketsInput{QueryLocation: true} + output, err := obscli.ListBuckets(input) + if err != nil { + return errors.Wrap(err, "obscli.ListBuckets") + } + self.ownerId = output.Owner.ID + + ret := make([]cloudprovider.ICloudBucket, 0) + for i := range output.Buckets { + bInfo := output.Buckets[i] + region, err := self.getIRegionByRegionId(bInfo.Location) + if err != nil { + log.Errorf("fail to find region %s", bInfo.Location) + continue + } + b := SBucket{ + region: region.(*SRegion), + + Name: bInfo.Name, + Location: bInfo.Location, + CreationDate: bInfo.CreationDate, + } + ret = append(ret, &b) + } + self.iBuckets = ret + return nil +} + +func (self *SHuaweiClient) GetCloudRegionExternalIdPrefix() string { + if len(self.projectId) > 0 { + return self.iregions[0].GetGlobalId() + } else { + return CLOUD_PROVIDER_HUAWEI + } +} + +func (self *SHuaweiClient) UpdateAccount(accessKey, secret string) error { + if self.accessKey != accessKey || self.accessSecret != secret { + self.accessKey = accessKey + self.accessSecret = secret + return self.fetchRegions() + } else { + return nil + } +} + +func (self *SHuaweiClient) 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 *SHuaweiClient) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + projects, err := self.fetchProjects() + if err != nil { + return nil, err + } + + // https://support.huaweicloud.com/api-iam/zh-cn_topic_0074171149.html + subAccounts := make([]cloudprovider.SSubAccount, 0) + for i := range projects { + project := projects[i] + // name 为MOS的project是华为云内部的一个特殊project。不需要同步到本地 + if strings.ToLower(project.Name) == "mos" { + continue + } + // https://www.huaweicloud.com/notice/2018/20190618171312411.html + // expiredAt, _ := timeutils.ParseTimeStr("2020-09-16 00:00:00") + // if !self.ownerCreateTime.IsZero() && self.ownerCreateTime.After(expiredAt) && strings.ToLower(project.Name) == "cn-north-1" { + // continue + // } + s := cloudprovider.SSubAccount{ + Name: fmt.Sprintf("%s-%s", self.cpcfg.Name, project.Name), + Account: fmt.Sprintf("%s/%s", self.accessKey, project.ID), + HealthStatus: project.GetHealthStatus(), + DefaultProjectId: "0", + } + for j := range self.iregions { + region := self.iregions[j].(*SRegion) + if strings.Contains(project.Name, region.ID) { + s.Desc = region.Locales.ZhCN + break + } + } + + subAccounts = append(subAccounts, s) + } + + return subAccounts, nil +} + +func (client *SHuaweiClient) GetAccountId() string { + return client.ownerId +} + +func (client *SHuaweiClient) GetIamLoginUrl() string { + return fmt.Sprintf("https://auth.huaweicloud.com/authui/login.html?account=%s#/login", client.ownerName) +} + +func (self *SHuaweiClient) GetIRegions() []cloudprovider.ICloudRegion { + return self.iregions +} + +func (self *SHuaweiClient) getIRegionByRegionId(id string) (cloudprovider.ICloudRegion, error) { + for i := 0; i < len(self.iregions); i += 1 { + log.Debugf("%d ID: %s", i, self.iregions[i].GetId()) + if self.iregions[i].GetId() == id { + return self.iregions[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHuaweiClient) 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 *SHuaweiClient) GetRegion(regionId string) *SRegion { + if len(regionId) == 0 { + regionId = HUAWEI_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 *SHuaweiClient) 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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHuaweiClient) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + for i := 0; i < len(self.iregions); i += 1 { + ivpc, err := self.iregions[i].GetIVpcById(id) + if err == nil { + return ivpc, nil + } else if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHuaweiClient) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + for i := 0; i < len(self.iregions); i += 1 { + istorage, err := self.iregions[i].GetIStorageById(id) + if err == nil { + return istorage, nil + } else if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +// 总账户余额 +type SAccountBalance struct { + AvailableAmount float64 + CreditAmount float64 + DesignatedAmount float64 +} + +// 账户余额 +// https://support.huaweicloud.com/api-oce/zh-cn_topic_0109685133.html +type SBalance struct { + Amount float64 `json:"amount"` + Currency string `json:"currency"` + AccountID string `json:"account_id"` + AccountType int64 `json:"account_type"` + DesignatedAmount float64 `json:"designated_amount,omitempty"` + CreditAmount float64 `json:"credit_amount,omitempty"` + MeasureUnit int64 `json:"measure_unit"` +} + +// 这里的余额指的是所有租户的总余额 +func (self *SHuaweiClient) QueryAccountBalance() (*SAccountBalance, error) { + domains, err := self.getEnabledDomains() + if err != nil { + return nil, err + } + + result := &SAccountBalance{} + for _, domain := range domains { + balances, err := self.queryDomainBalances(domain.ID) + if err != nil { + return nil, err + } + for _, balance := range balances { + result.AvailableAmount += balance.Amount + result.CreditAmount += balance.CreditAmount + result.DesignatedAmount += balance.DesignatedAmount + } + } + + return result, nil +} + +// https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0075213309.html +func (self *SHuaweiClient) queryDomainBalances(domainId string) ([]SBalance, error) { + huawei, _ := self.newGeneralAPIClient() + huawei.Balances.SetDomainId(domainId) + balances := make([]SBalance, 0) + err := doListAll(huawei.Balances.List, nil, &balances) + if err != nil { + return nil, err + } + + return balances, nil +} + +func (self *SHuaweiClient) GetVersion() string { + return HUAWEI_API_VERSION +} + +func (self *SHuaweiClient) GetAccessEnv() string { + switch self.cloudEnv { + case HUAWEI_INTERNATIONAL_CLOUDENV: + return api.CLOUD_ACCESS_ENV_HUAWEI_GLOBAL + case HUAWEI_CHINA_CLOUDENV: + return api.CLOUD_ACCESS_ENV_HUAWEI_CHINA + default: + return api.CLOUD_ACCESS_ENV_HUAWEI_GLOBAL + } +} + +func (self *SHuaweiClient) GetCapabilities() []string { + caps := []string{ + cloudprovider.CLOUD_CAPABILITY_PROJECT, + cloudprovider.CLOUD_CAPABILITY_COMPUTE, + cloudprovider.CLOUD_CAPABILITY_NETWORK, + cloudprovider.CLOUD_CAPABILITY_EIP, + cloudprovider.CLOUD_CAPABILITY_LOADBALANCER, + // cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE, + cloudprovider.CLOUD_CAPABILITY_RDS, + cloudprovider.CLOUD_CAPABILITY_CACHE, + cloudprovider.CLOUD_CAPABILITY_EVENT, + cloudprovider.CLOUD_CAPABILITY_CLOUDID, + cloudprovider.CLOUD_CAPABILITY_SAML_AUTH, + cloudprovider.CLOUD_CAPABILITY_NAT, + cloudprovider.CLOUD_CAPABILITY_NAS, + cloudprovider.CLOUD_CAPABILITY_QUOTA + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_MODELARTES, + } + // huawei objectstore is shared across projects(subscriptions) + // to avoid multiple project access the same bucket + // only main project is allow to access objectstore bucket + if self.isMainProject { + caps = append(caps, cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE) + } + return caps +} + +func (self *SHuaweiClient) GetUserId() (string, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return "", errors.Wrap(err, "SHuaweiClient.GetUserId.newGeneralAPIClient") + } + + type cred struct { + UserId string `json:"user_id"` + } + + ret := &cred{} + err = DoGet(client.Credentials.Get, self.accessKey, nil, ret) + if err != nil { + return "", errors.Wrap(err, "SHuaweiClient.GetUserId.DoGet") + } + + return ret.UserId, nil +} + +// owner id == domain_id == account id +func (self *SHuaweiClient) GetOwnerId() (string, error) { + userId, err := self.GetUserId() + if err != nil { + return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.GetUserId") + } + + client, err := self.newGeneralAPIClient() + if err != nil { + return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.newGeneralAPIClient") + } + + type user struct { + DomainId string `json:"domain_id"` + Name string `json:"name"` + CreateTime string + } + + ret := &user{} + err = DoGet(client.Users.Get, userId, nil, ret) + if err != nil { + return "", errors.Wrap(err, "SHuaweiClient.GetOwnerId.DoGet") + } + self.ownerName = ret.Name + // 2021-02-02 02:43:28.0 + self.ownerCreateTime, _ = timeutils.ParseTimeStr(strings.TrimSuffix(ret.CreateTime, ".0")) + return ret.DomainId, nil +} + +func (self *SHuaweiClient) initOwner() error { + ownerId, err := self.GetOwnerId() + if err != nil { + return errors.Wrap(err, "SHuaweiClient.initOwner") + } + + self.ownerId = ownerId + return nil +} + +func (self *SHuaweiClient) patchRequest(method httputils.THttpMethod, url string, query url.Values, params map[string]interface{}) (jsonutils.JSONObject, error) { + client := self.getAkClient() + if len(query) > 0 { + url = fmt.Sprintf("%s?%s", url, query.Encode()) + } + var body jsonutils.JSONObject = nil + if len(params) > 0 { + body = jsonutils.Marshal(params) + } + header := http.Header{} + if len(self.projectId) > 0 { + header.Set("X-Project-Id", self.projectId) + } + var bodystr string + if !gotypes.IsNil(body) { + bodystr = body.String() + } + jbody := strings.NewReader(bodystr) + header.Set("Content-Length", strconv.FormatInt(int64(len(bodystr)), 10)) + header.Set("Content-Type", "application/merge-patch+json") + resp, err := httputils.Request(client, context.Background(), method, url, header, jbody, self.debug) + _, respValue, err := httputils.ParseJSONResponse(bodystr, resp, err, self.debug) + if err != nil { + if e, ok := err.(*httputils.JSONClientError); ok && e.Code == 404 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, err.Error()) + } + return nil, err + } + return respValue, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/image.go new file mode 100644 index 0000000000..ce523eaac7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/image.go @@ -0,0 +1,474 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type TImageOwnerType string + +const ( + ImageOwnerPublic TImageOwnerType = "gold" // 公共镜像:gold + ImageOwnerSelf TImageOwnerType = "private" // 私有镜像:private + ImageOwnerShared TImageOwnerType = "shared" // 共享镜像:shared + + EnvFusionCompute = "FusionCompute" + EnvIronic = "Ironic" +) + +const ( + ImageStatusQueued = "queued" // queued:表示镜像元数据已经创建成功,等待上传镜像文件。 + ImageStatusSaving = "saving" // saving:表示镜像正在上传文件到后端存储。 + ImageStatusDeleted = "deleted" // deleted:表示镜像已经删除。 + ImageStatusKilled = "killed" // killed:表示镜像上传错误。 + ImageStatusActive = "active" // active:表示镜像可以正常使用 +) + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020091565.html +type SImage struct { + multicloud.SImageBase + HuaweiTags + storageCache *SStoragecache + + // normalized image info + imgInfo *imagetools.ImageInfo + + Schema string `json:"schema"` + MinDiskGB int64 `json:"min_disk"` + CreatedAt time.Time `json:"created_at"` + ImageSourceType string `json:"__image_source_type"` + ContainerFormat string `json:"container_format"` + File string `json:"file"` + UpdatedAt time.Time `json:"updated_at"` + Protected bool `json:"protected"` + Checksum string `json:"checksum"` + ID string `json:"id"` + Isregistered string `json:"__isregistered"` + MinRamMB int `json:"min_ram"` + Lazyloading string `json:"__lazyloading"` + Owner string `json:"owner"` + OSType string `json:"__os_type"` + Imagetype string `json:"__imagetype"` + Visibility string `json:"visibility"` + VirtualEnvType string `json:"virtual_env_type"` + Platform string `json:"__platform"` + SizeGB int `json:"size"` + ImageSize int64 `json:"__image_size"` + OSBit string `json:"__os_bit"` + OSVersion string `json:"__os_version"` + Name string `json:"name"` + Self string `json:"self"` + DiskFormat string `json:"disk_format"` + Status string `json:"status"` + SupportKVMFPGAType string `json:"__support_kvm_fpga_type"` + SupportKVMNVMEHIGHIO string `json:"__support_nvme_highio"` + SupportLargeMemory string `json:"__support_largememory"` + SupportDiskIntensive string `json:"__support_diskintensive"` + SupportHighPerformance string `json:"__support_highperformance"` + SupportXENGPUType string `json:"__support_xen_gpu_type"` + SupportKVMGPUType string `json:"__support_kvm_gpu_type"` + SupportGPUT4 string `json:"__support_gpu_t4"` + SupportKVMAscend310 string `json:"__support_kvm_ascend_310"` + SupportArm string `json:"__support_arm"` +} + +func (self *SImage) GetMinRamSizeMb() int { + return self.MinRamMB +} + +func (self *SImage) GetId() string { + return self.ID +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (self *SImage) GetGlobalId() string { + return self.ID +} + +func (self *SImage) GetStatus() string { + switch self.Status { + case ImageStatusQueued: + return api.CACHED_IMAGE_STATUS_CACHING + case ImageStatusActive: + return api.CACHED_IMAGE_STATUS_ACTIVE + case ImageStatusKilled: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + default: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (self *SImage) GetImageStatus() string { + switch self.Status { + case ImageStatusQueued: + return cloudprovider.IMAGE_STATUS_QUEUED + case ImageStatusActive: + return cloudprovider.IMAGE_STATUS_ACTIVE + case ImageStatusKilled: + return cloudprovider.IMAGE_STATUS_KILLED + default: + return cloudprovider.IMAGE_STATUS_KILLED + } +} + +func (self *SImage) Refresh() error { + new, err := self.storageCache.region.GetImage(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + switch self.Imagetype { + case "gold": + return cloudprovider.ImageTypeSystem + case "private": + return cloudprovider.ImageTypeCustomized + case "shared": + return cloudprovider.ImageTypeShared + default: + return cloudprovider.ImageTypeCustomized + } +} + +func (self *SImage) GetSizeByte() int64 { + return int64(self.MinDiskGB) * 1024 * 1024 * 1024 +} + +func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if self.imgInfo == nil { + arch := "x86" + if strings.ToLower(self.SupportArm) == "true" { + arch = "arm" + } + imgInfo := imagetools.NormalizeImageInfo(self.ImageSourceType, arch, self.OSType, self.Platform, "") + self.imgInfo = &imgInfo + } + + return self.imgInfo +} + +func (self *SImage) GetFullOsName() string { + return self.ImageSourceType +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) +} + +func (self *SImage) GetOsDist() string { + return self.getNormalizedImageInfo().OsDistro +} + +func (self *SImage) GetOsVersion() string { + return self.getNormalizedImageInfo().OsVersion +} + +func (self *SImage) GetOsLang() string { + return self.getNormalizedImageInfo().OsLang +} + +func (self *SImage) GetOsArch() string { + return self.getNormalizedImageInfo().OsArch +} + +func (self *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(self.getNormalizedImageInfo().OsBios) +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return int(self.MinDiskGB) +} + +func (self *SImage) GetImageFormat() string { + return self.DiskFormat +} + +func (self *SImage) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SImage) IsEmulated() bool { + return false +} + +func (self *SImage) Delete(ctx context.Context) error { + return self.storageCache.region.DeleteImage(self.GetId()) +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.storageCache +} + +func (self *SRegion) GetImage(imageId string) (*SImage, error) { + image := &SImage{} + err := DoGet(self.ecsClient.Images.Get, imageId, nil, image) + if err != nil { + return nil, errors.Wrap(err, "DoGet") + } + return image, nil +} + +func excludeImage(image SImage) bool { + if image.VirtualEnvType == "Ironic" { + return true + } + + if len(image.SupportDiskIntensive) > 0 { + return true + } + + if len(image.SupportKVMFPGAType) > 0 || len(image.SupportKVMAscend310) > 0 { + return true + } + + if len(image.SupportKVMGPUType) > 0 { + return true + } + + if len(image.SupportKVMNVMEHIGHIO) > 0 { + return true + } + + if len(image.SupportGPUT4) > 0 { + return true + } + + if len(image.SupportXENGPUType) > 0 { + return true + } + + if len(image.SupportHighPerformance) > 0 { + return true + } + + if len(image.SupportArm) > 0 { + return true + } + + return false +} + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0060804959.html +func (self *SRegion) GetImages(status string, imagetype TImageOwnerType, name string, envType string) ([]SImage, error) { + queries := map[string]string{} + if len(status) > 0 { + queries["status"] = status + } + + if len(imagetype) > 0 { + queries["__imagetype"] = string(imagetype) + if imagetype == ImageOwnerPublic { + queries["protected"] = "True" + } + } + if len(envType) > 0 { + queries["virtual_env_type"] = envType + } + + if len(name) > 0 { + queries["name"] = name + } + + images := make([]SImage, 0) + err := doListAllWithMarker(self.ecsClient.Images.List, queries, &images) + + // 排除掉需要特定镜像才能创建的实例类型 + // https://support.huaweicloud.com/eu-west-0-api-ims/zh-cn_topic_0031617666.html#ZH-CN_TOPIC_0031617666__table48545918250 + // https://support.huaweicloud.com/productdesc-ecs/zh-cn_topic_0088142947.html + filtedImages := make([]SImage, 0) + for i := range images { + if !excludeImage(images[i]) { + filtedImages = append(filtedImages, images[i]) + } + } + + return filtedImages, err +} + +func (self *SRegion) DeleteImage(imageId string) error { + return DoDelete(self.ecsClient.OpenStackImages.Delete, imageId, nil, nil) +} + +func (self *SRegion) GetImageByName(name string) (*SImage, error) { + if len(name) == 0 { + return nil, fmt.Errorf("image name should not be empty") + } + + images, err := self.GetImages("", TImageOwnerType(""), name, "") + if err != nil { + return nil, err + } + if len(images) == 0 { + return nil, cloudprovider.ErrNotFound + } + + log.Debugf("%d image found match name %s", len(images), name) + return &images[0], nil +} + +/* https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html + os version 取值范围: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html + 用于创建私有镜像的源云服务器系统盘大小大于等于40GB且不超过1024GB。 + 目前支持vhd,zvhd、raw,qcow2 + todo: 考虑使用镜像快速导入。 https://support.huaweicloud.com/api-ims/zh-cn_topic_0133188204.html + 使用OBS文件创建镜像 + + * openstack原生接口支持的格式:https://support.huaweicloud.com/api-ims/zh-cn_topic_0031615566.html +*/ +func (self *SRegion) ImportImageJob(name string, osDist string, osVersion string, osArch string, bucket string, key string, minDiskGB int64) (string, error) { + os_version, err := stdVersion(osDist, osVersion, osArch) + log.Debugf("%s %s %s: %s.min_disk %d GB", osDist, osVersion, osArch, os_version, minDiskGB) + if err != nil { + log.Debugln(err) + } + + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(name), "name") + image_url := fmt.Sprintf("%s:%s", bucket, key) + params.Add(jsonutils.NewString(image_url), "image_url") + if len(os_version) > 0 { + params.Add(jsonutils.NewString(os_version), "os_version") + } + params.Add(jsonutils.NewBool(true), "is_config_init") + params.Add(jsonutils.NewBool(true), "is_config") + params.Add(jsonutils.NewInt(minDiskGB), "min_disk") + + ret, err := self.ecsClient.Images.PerformAction2("action", "", params, "") + if err != nil { + return "", err + } + + return ret.GetString("job_id") +} + +func formatVersion(osDist string, osVersion string) (string, error) { + err := fmt.Errorf("unsupport version %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osVersion) + dist := strings.ToLower(osDist) + if dist == "ubuntu" || dist == "redhat" || dist == "centos" || dist == "oracle" || dist == "euleros" { + parts := strings.Split(osVersion, ".") + if len(parts) < 2 { + return "", err + } + + return parts[0] + "." + parts[1], nil + } + + if dist == "debian" { + parts := strings.Split(osVersion, ".") + if len(parts) < 3 { + return "", err + } + + return parts[0] + "." + parts[1] + "." + parts[2], nil + } + + if dist == "fedora" || dist == "windows" || dist == "suse" { + parts := strings.Split(osVersion, ".") + if len(parts) < 1 { + return "", err + } + + return parts[0], nil + } + + if dist == "opensuse" { + parts := strings.Split(osVersion, ".") + if len(parts) == 0 { + return "", err + } + + if len(parts) == 1 { + return parts[0], nil + } + + if len(parts) >= 2 { + return parts[0] + "." + parts[1], nil + } + } + + return "", err +} + +// todo: 如何保持同步更新 +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html +func stdVersion(osDist string, osVersion string, osArch string) (string, error) { + // 架构 + arch := "" + switch osArch { + case "64", apis.OS_ARCH_X86_64: + arch = "64bit" + case "32", apis.OS_ARCH_X86_32: + arch = "32bit" + default: + return "", fmt.Errorf("unsupported arch %s.reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", osArch) + } + + _dist := strings.Split(strings.TrimSpace(osDist), " ")[0] + _dist = strings.ToLower(_dist) + // 版本 + ver, err := formatVersion(_dist, osVersion) + if err != nil { + return "", err + } + + // 操作系统 + dist := "" + + switch _dist { + case "ubuntu": + return fmt.Sprintf("Ubuntu %s server %s", ver, arch), nil + case "redhat": + dist = "Redhat Linux Enterprise" + case "centos": + dist = "CentOS" + case "fedora": + dist = "Fedora" + case "debian": + dist = "Debian GNU/Linux" + case "windows": + dist = "Windows Server" + case "oracle": + dist = "Oracle Linux Server release" + case "suse": + dist = "SUSE Linux Enterprise Server" + case "opensuse": + dist = "OpenSUSE" + case "euleros": + dist = "EulerOS" + default: + return "", fmt.Errorf("unsupported os %s. reference: https://support.huaweicloud.com/api-ims/zh-cn_topic_0031617666.html", dist) + } + + return fmt.Sprintf("%s %s %s", dist, ver, arch), nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instance.go new file mode 100644 index 0000000000..238cbcb298 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instance.go @@ -0,0 +1,1538 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "encoding/base64" + "fmt" + "sort" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/apis" + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/cloudinit" +) + +const ( + InstanceStatusRunning = "ACTIVE" + InstanceStatusTerminated = "DELETED" + InstanceStatusStopped = "SHUTOFF" +) + +type IpAddress struct { + Version string `json:"version"` + Addr string `json:"addr"` + OSEXTIPSMACMACAddr string `json:"OS-EXT-IPS-MAC:mac_addr"` + OSEXTIPSPortID string `json:"OS-EXT-IPS:port_id"` + OSEXTIPSType string `json:"OS-EXT-IPS:type"` +} + +type Flavor struct { + Disk string `json:"disk"` + Vcpus string `json:"vcpus"` + RAM string `json:"ram"` + ID string `json:"id"` + Name string `json:"name"` +} + +type Image struct { + ID string `json:"id"` +} + +type VMMetadata struct { + MeteringImageID string `json:"metering.image_id"` + MeteringImagetype string `json:"metering.imagetype"` + MeteringOrderId string `json:"metering.order_id"` + MeteringResourcespeccode string `json:"metering.resourcespeccode"` + ImageName string `json:"image_name"` + OSBit string `json:"os_bit"` + VpcID string `json:"vpc_id"` + MeteringResourcetype string `json:"metering.resourcetype"` + CascadedInstanceExtrainfo string `json:"cascaded.instance_extrainfo"` + OSType string `json:"os_type"` + ChargingMode string `json:"charging_mode"` +} + +type OSExtendedVolumesVolumesAttached struct { + Device string `json:"device"` + BootIndex string `json:"bootIndex"` + ID string `json:"id"` + DeleteOnTermination string `json:"delete_on_termination"` +} + +type OSSchedulerHints struct { +} + +type SecurityGroup struct { + Name string `json:"name"` +} + +type SysTag struct { + Key string `json:"key"` + Value string `json:"value"` +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html +// https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0100166287.html v1.1 支持创建包年/包月的弹性云服务器 +type SInstance struct { + multicloud.SInstanceBase + HuaweiTags + + host *SHost + + image *SImage + + ID string `json:"id"` + Name string `json:"name"` + Addresses map[string][]IpAddress `json:"addresses"` + Flavor Flavor `json:"flavor"` + AccessIPv4 string `json:"accessIPv4"` + AccessIPv6 string `json:"accessIPv6"` + Status string `json:"status"` + Progress string `json:"progress"` + HostID string `json:"hostId"` + Image Image `json:"image"` + Updated string `json:"updated"` + Created time.Time `json:"created"` + Metadata VMMetadata `json:"metadata"` + Description string `json:"description"` + Locked bool `json:"locked"` + ConfigDrive string `json:"config_drive"` + TenantID string `json:"tenant_id"` + UserID string `json:"user_id"` + KeyName string `json:"key_name"` + + OSExtendedVolumesVolumesAttached []OSExtendedVolumesVolumesAttached `json:"os-extended-volumes:volumes_attached"` + OSEXTSTSTaskState string `json:"OS-EXT-STS:task_state"` + OSEXTSTSPowerState int64 `json:"OS-EXT-STS:power_state"` + OSEXTSTSVMState string `json:"OS-EXT-STS:vm_state"` + OSEXTSRVATTRHost string `json:"OS-EXT-SRV-ATTR:host"` + OSEXTSRVATTRInstanceName string `json:"OS-EXT-SRV-ATTR:instance_name"` + OSEXTSRVATTRHypervisorHostname string `json:"OS-EXT-SRV-ATTR:hypervisor_hostname"` + OSDCFDiskConfig string `json:"OS-DCF:diskConfig"` + OSEXTAZAvailabilityZone string `json:"OS-EXT-AZ:availability_zone"` + OSSchedulerHints OSSchedulerHints `json:"os:scheduler_hints"` + OSEXTSRVATTRRootDeviceName string `json:"OS-EXT-SRV-ATTR:root_device_name"` + OSEXTSRVATTRRamdiskID string `json:"OS-EXT-SRV-ATTR:ramdisk_id"` + EnterpriseProjectID string `json:"enterprise_project_id"` + OSEXTSRVATTRUserData string `json:"OS-EXT-SRV-ATTR:user_data"` + OSSRVUSGLaunchedAt time.Time `json:"OS-SRV-USG:launched_at"` + OSEXTSRVATTRKernelID string `json:"OS-EXT-SRV-ATTR:kernel_id"` + OSEXTSRVATTRLaunchIndex int64 `json:"OS-EXT-SRV-ATTR:launch_index"` + HostStatus string `json:"host_status"` + OSEXTSRVATTRReservationID string `json:"OS-EXT-SRV-ATTR:reservation_id"` + OSEXTSRVATTRHostname string `json:"OS-EXT-SRV-ATTR:hostname"` + OSSRVUSGTerminatedAt time.Time `json:"OS-SRV-USG:terminated_at"` + SysTags []SysTag `json:"sys_tags"` + SecurityGroups []SecurityGroup `json:"security_groups"` + EnterpriseProjectId string +} + +func compareSet(currentSet []string, newSet []string) (add []string, remove []string, keep []string) { + sort.Strings(currentSet) + sort.Strings(newSet) + + i, j := 0, 0 + for i < len(currentSet) || j < len(newSet) { + if i < len(currentSet) && j < len(newSet) { + if currentSet[i] == newSet[j] { + keep = append(keep, currentSet[i]) + i += 1 + j += 1 + } else if currentSet[i] < newSet[j] { + remove = append(remove, currentSet[i]) + i += 1 + } else { + add = append(add, newSet[j]) + j += 1 + } + } else if i >= len(currentSet) { + add = append(add, newSet[j]) + j += 1 + } else if j >= len(newSet) { + remove = append(remove, currentSet[i]) + i += 1 + } + } + + return add, remove, keep +} + +// 启动盘 != 系统盘(必须是启动盘且挂载在root device上) +func isBootDisk(server *SInstance, disk *SDisk) bool { + if disk.GetDiskType() != api.DISK_TYPE_SYS { + return false + } + + for _, attachment := range disk.Attachments { + if attachment.ServerID == server.GetId() && attachment.Device == server.OSEXTSRVATTRRootDeviceName { + return true + } + } + + return false +} + +func (self *SInstance) GetId() string { + return self.ID +} + +func (self *SInstance) GetHostname() string { + return self.OSEXTSRVATTRHostname +} + +func (self *SInstance) GetName() string { + return self.Name +} + +func (self *SInstance) GetGlobalId() string { + return self.ID +} + +func (self *SInstance) GetStatus() string { + switch self.Status { + case "ACTIVE": + return api.VM_RUNNING + case "MIGRATING", "REBUILD", "BUILD", "RESIZE", "VERIFY_RESIZE": // todo: pending ? + return api.VM_STARTING + case "REBOOT", "HARD_REBOOT": + return api.VM_STOPPING + case "SHUTOFF": + return api.VM_READY + default: + return api.VM_UNKNOWN + } +} + +func (self *SInstance) Refresh() error { + new, err := self.host.zone.region.GetInstanceByID(self.GetId()) + new.host = self.host + if err != nil { + return err + } + + if new.Status == InstanceStatusTerminated { + log.Debugf("Instance already terminated.") + return cloudprovider.ErrNotFound + } + + err = jsonutils.Update(self, new) + if err != nil { + return err + } + return nil +} + +func (self *SInstance) IsEmulated() bool { + return false +} + +func (self *SInstance) GetInstanceType() string { + return self.Flavor.ID +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + return self.host.zone.region.GetInstanceSecrityGroupIds(self.GetId()) +} + +// https://support.huaweicloud.com/api-ecs/ecs_02_1002.html +// key 相同时value不会替换 +func (self *SRegion) CreateServerTags(instanceId string, tags map[string]string) error { + params := map[string]interface{}{ + "action": "create", + } + + tagsObj := []map[string]string{} + for k, v := range tags { + tagsObj = append(tagsObj, map[string]string{"key": k, "value": v}) + } + params["tags"] = tagsObj + + _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + return err +} + +// https://support.huaweicloud.com/api-ecs/ecs_02_1003.html +func (self *SRegion) DeleteServerTags(instanceId string, tagsKey []string) error { + params := map[string]interface{}{ + "action": "delete", + } + tagsObj := []map[string]string{} + for _, k := range tagsKey { + tagsObj = append(tagsObj, map[string]string{"key": k}) + } + params["tags"] = tagsObj + + _, err := self.ecsClient.Servers.PerformAction2("tags/action", instanceId, jsonutils.Marshal(params), "") + return err +} + +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { + existedTags, err := self.GetTags() + if err != nil { + return errors.Wrap(err, "self.GetTags()") + } + deleteTagsKey := []string{} + for k := range existedTags { + if replace { + deleteTagsKey = append(deleteTagsKey, k) + } else { + if _, ok := tags[k]; ok { + deleteTagsKey = append(deleteTagsKey, k) + } + } + } + if len(deleteTagsKey) > 0 { + err := self.host.zone.region.DeleteServerTags(self.GetId(), deleteTagsKey) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.DeleteServerTags(%s,%s)", self.GetId(), deleteTagsKey) + } + } + if len(tags) > 0 { + err := self.host.zone.region.CreateServerTags(self.GetId(), tags) + if err != nil { + return errors.Wrapf(err, "self.host.zone.region.CreateServerTags(%s,%s)", self.GetId(), jsonutils.Marshal(tags).String()) + } + } + return nil +} + +func (self *SInstance) GetBillingType() string { + // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html + // charging_mode “0”:按需计费 “1”:按包年包月计费 + if self.Metadata.ChargingMode == "1" { + return billing_api.BILLING_TYPE_PREPAID + } else { + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SInstance) GetCreatedAt() time.Time { + return self.Created +} + +// charging_mode “0”:按需计费 “1”:按包年包月计费 +func (self *SInstance) GetExpiredAt() time.Time { + if len(self.Metadata.MeteringOrderId) > 0 { + res, _ := self.host.zone.region.GetOrderResources(self.Metadata.MeteringOrderId, []string{self.ID}, true) + for i := range res { + return res[i].ExpireTime + } + } + var expiredTime time.Time + if self.Metadata.ChargingMode == "1" { + res, err := self.host.zone.region.GetOrderResourceDetail(self.GetId()) + if err != nil { + log.Debugln(err) + } + + expiredTime = res.ExpireTime + } + + return expiredTime +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + err := self.Refresh() + if err != nil { + return nil, err + } + + attached := self.OSExtendedVolumesVolumesAttached + disks := make([]SDisk, 0) + for _, vol := range attached { + disk, err := self.host.zone.region.GetDisk(vol.ID) + if err != nil { + return nil, err + } + + disks = append(disks, *disk) + } + + idisks := make([]cloudprovider.ICloudDisk, len(disks)) + for i := 0; i < len(disks); i += 1 { + storage, err := self.host.zone.getStorageByCategory(disks[i].VolumeType) + if err != nil { + return nil, err + } + disks[i].storage = storage + idisks[i] = &disks[i] + // 将系统盘放到第0个位置 + if isBootDisk(self, &disks[i]) { + _temp := idisks[0] + idisks[0] = &disks[i] + idisks[i] = _temp + } + } + return idisks, nil +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics := make([]cloudprovider.ICloudNic, 0) + + // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148849.html + // OS-EXT-IPS.type + // todo: 这里没有区分是IPv4 还是 IPv6。统一当IPv4处理了.可能会引发错误 + for _, ipAddresses := range self.Addresses { + for _, ipAddress := range ipAddresses { + if ipAddress.OSEXTIPSType == "fixed" { + nic := SInstanceNic{ + instance: self, + ipAddr: ipAddress.Addr, + macAddr: ipAddress.OSEXTIPSMACMACAddr, + } + nics = append(nics, &nic) + } + } + } + return nics, nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + ips := make([]string, 0) + for _, addresses := range self.Addresses { + for _, address := range addresses { + if address.OSEXTIPSType != "fixed" && !strings.HasPrefix(address.Addr, "100.") { + ips = append(ips, address.Addr) + } + } + } + + if len(ips) == 0 { + return nil, nil + } + + eips, err := self.host.zone.region.GetEips("", ips) + if err != nil { + return nil, err + } + if len(eips) > 0 { + return &eips[0], nil + } + return nil, nil +} + +func (self *SInstance) GetVcpuCount() int { + cpu, _ := strconv.Atoi(self.Flavor.Vcpus) + return cpu +} + +func (self *SInstance) GetVmemSizeMB() int { + mem, _ := strconv.Atoi(self.Flavor.RAM) + return int(mem) +} + +func (self *SInstance) GetBootOrder() string { + return "dcn" +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (i *SInstance) getImage() *SImage { + if i.image == nil && len(i.Image.ID) > 0 { + image, err := i.host.zone.region.GetImage(i.Image.ID) + if err == nil { + i.image = image + } else { + log.Debugf("GetOSArch.GetImage %s: %s", i.Image.ID, err) + } + } + return i.image +} + +func (self *SInstance) GetOsArch() string { + img := self.getImage() + if img != nil { + return img.GetOsArch() + } + + t := self.GetInstanceType() + if len(t) > 0 { + if strings.HasPrefix(t, "k") { + return apis.OS_ARCH_AARCH64 + } + } + + return apis.OS_ARCH_X86 +} + +func (self *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(osprofile.NormalizeOSType(self.Metadata.OSType)) +} + +func (self *SInstance) GetFullOsName() string { + return self.Metadata.ImageName +} + +func (self *SInstance) GetBios() cloudprovider.TBiosType { + img := self.getImage() + if img != nil { + return img.GetBios() + } + return cloudprovider.BIOS +} + +func (self *SInstance) GetOsDist() string { + img := self.getImage() + if img != nil { + return img.GetOsDist() + } + return "" +} + +func (self *SInstance) GetOsVersion() string { + img := self.getImage() + if img != nil { + return img.GetOsVersion() + } + return "" +} + +func (self *SInstance) GetOsLang() string { + img := self.getImage() + if img != nil { + return img.GetOsLang() + } + return "" +} + +func (self *SInstance) GetMachine() string { + return "pc" +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.SetSecurityGroups([]string{secgroupId}) +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + currentSecgroups, err := self.host.zone.region.GetInstanceSecrityGroupIds(self.GetId()) + if err != nil { + return err + } + + add, remove, _ := compareSet(currentSecgroups, secgroupIds) + err = self.host.zone.region.assignSecurityGroups(add, self.GetId()) + if err != nil { + return err + } + + return self.host.zone.region.unassignSecurityGroups(remove, self.GetId()) +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_HUAWEI +} + +func (self *SInstance) StartVM(ctx context.Context) error { + if self.Status == InstanceStatusRunning { + return nil + } + + 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 + } + + if self.GetStatus() == api.VM_RUNNING { + return nil + } else if self.GetStatus() == api.VM_READY { + err := self.host.zone.region.StartVM(self.GetId()) + if err != nil { + return err + } + } + time.Sleep(interval) + } + return cloudprovider.ErrTimeout +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + if self.Status == InstanceStatusStopped { + return nil + } + + if self.Status == InstanceStatusTerminated { + log.Debugf("Instance already terminated.") + return nil + } + + err := self.host.zone.region.StopVM(self.GetId(), opts.IsForce) + if err != nil { + return err + } + return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) // 5mintues +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + if self.Status == InstanceStatusTerminated { + return nil + } + + for { + err := self.host.zone.region.DeleteVM(self.GetId()) + if err != nil && self.Status != InstanceStatusTerminated { + log.Errorf("DeleteVM fail: %s", err) + return err + } else { + break + } + } + + return cloudprovider.WaitDeleted(self, 10*time.Second, 300*time.Second) // 5minutes +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return self.host.zone.region.UpdateVM(self.GetId(), name) +} + +// https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0032380449.html +// 创建云服务器过程中注入用户数据。支持注入文本、文本文件或gzip文件。 +// 注入内容,需要进行base64格式编码。注入内容(编码之前的内容)最大长度32KB。 +// 对于Linux弹性云服务器,adminPass参数传入时,user_data参数不生效。 +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html 使用原镜像重装 +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html 更换系统盘操作系统 +// 不支持调整系统盘大小 +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + var err error + var jobId string + + publicKeyName := "" + if len(desc.PublicKey) > 0 { + publicKeyName, err = self.host.zone.region.syncKeypair(desc.PublicKey) + if err != nil { + return "", err + } + } + + image, err := self.host.zone.region.GetImage(desc.ImageId) + if err != nil { + return "", errors.Wrap(err, "SInstance.RebuildRoot.GetImage") + } + + // Password存在的情况下,windows 系统直接使用密码 + if strings.ToLower(image.Platform) == strings.ToLower(osprofile.OS_TYPE_WINDOWS) && len(desc.Password) > 0 { + publicKeyName = "" + } + + userData, err := updateUserData(self.OSEXTSRVATTRUserData, image.OSVersion, desc.Account, desc.Password, desc.PublicKey) + if err != nil { + return "", errors.Wrap(err, "SInstance.RebuildRoot.updateUserData") + } + + if self.Metadata.MeteringImageID == desc.ImageId { + jobId, err = self.host.zone.region.RebuildRoot(ctx, self.UserID, self.GetId(), desc.Password, publicKeyName, userData) + if err != nil { + return "", err + } + } else { + jobId, err = self.host.zone.region.ChangeRoot(ctx, self.UserID, self.GetId(), desc.ImageId, desc.Password, publicKeyName, userData) + if err != nil { + return "", err + } + } + + err = self.host.zone.region.waitTaskStatus(self.host.zone.region.ecsClient.Servers.ServiceType(), jobId, TASK_SUCCESS, 15*time.Second, 900*time.Second) + if err != nil { + log.Errorf("RebuildRoot task error %s", err) + return "", err + } + + err = self.Refresh() + if err != nil { + return "", err + } + + idisks, err := self.GetIDisks() + if err != nil { + return "", err + } + + if len(idisks) == 0 { + return "", fmt.Errorf("server %s has no volume attached.", self.GetId()) + } + + return idisks[0].GetId(), nil +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return self.host.zone.region.DeployVM(self.GetId(), name, password, publicKey, deleteKeypair, description) +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + instanceTypes := []string{} + if len(config.InstanceType) > 0 { + instanceTypes = []string{config.InstanceType} + } else { + flavors, err := self.host.zone.region.GetMatchInstanceTypes(config.Cpu, config.MemoryMB, self.OSEXTAZAvailabilityZone) + if err != nil { + return errors.Wrapf(err, "GetMatchInstanceTypes") + } + for _, flavor := range flavors { + instanceTypes = append(instanceTypes, flavor.ID) + } + } + var err error + for _, instanceType := range instanceTypes { + err = self.host.zone.region.ChangeVMConfig(self.GetId(), instanceType) + if err != nil { + log.Warningf("ChangeVMConfig %s for %s error: %v", self.GetId(), instanceType, err) + } else { + return cloudprovider.WaitStatusWithDelay(self, api.VM_READY, 15*time.Second, 15*time.Second, 180*time.Second) + } + } + if err != nil { + return errors.Wrapf(err, "ChangeVMConfig") + } + return fmt.Errorf("Failed to change vm config, specification not supported") +} + +// todo:// 返回jsonobject感觉很诡异。不能直接知道内部细节 +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return self.host.zone.region.GetInstanceVNCUrl(self.GetId()) +} + +func (self *SInstance) NextDeviceName() (string, error) { + prefix := "s" + if strings.Contains(self.OSEXTSRVATTRRootDeviceName, "/vd") { + prefix = "v" + } + + currents := []string{} + for _, item := range self.OSExtendedVolumesVolumesAttached { + currents = append(currents, strings.ToLower(item.Device)) + } + + for i := 0; i < 25; i++ { + device := fmt.Sprintf("/dev/%sd%s", prefix, string([]byte{byte(98 + i)})) + if ok, _ := utils.InStringArray(device, currents); !ok { + return device, nil + } + } + + return "", fmt.Errorf("disk devicename out of index, current deivces: %s", currents) +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + device, err := self.NextDeviceName() + if err != nil { + return errors.Wrap(err, "Instance.AttachDisk.NextDeviceName") + } + + err = self.host.zone.region.AttachDisk(self.GetId(), diskId, device) + if err != nil { + return errors.Wrap(err, "Instance.AttachDisk.AttachDisk") + } + + return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { + disk, err := self.host.zone.region.GetDisk(diskId) + if err != nil { + log.Debugf("Instance.AttachDisk.GetDisk %s", err) + return false, nil + } + + if disk.Status == "in-use" { + return true, nil + } + + return false, nil + }) +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + err := self.host.zone.region.DetachDisk(self.GetId(), diskId) + if err != nil { + return errors.Wrap(err, "Instance.DetachDisk") + } + + return cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { + disk, err := self.host.zone.region.GetDisk(diskId) + if err != nil { + log.Debugf("Instance.DetachDisk.GetDisk %s", err) + return false, nil + } + + if disk.Status == "available" { + return true, nil + } + + return false, nil + }) +} + +func (self *SInstance) Renew(bc billing.SBillingCycle) error { + return self.host.zone.region.RenewInstance(self.GetId(), bc) +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0094148850.html +func (self *SRegion) GetInstances() ([]SInstance, error) { + queries := make(map[string]string) + + if len(self.client.projectId) > 0 { + queries["project_id"] = self.client.projectId + } + + instances := make([]SInstance, 0) + err := doListAllWithPagerOffset(self.ecsClient.Servers.List, queries, &instances) + return instances, err +} + +func (self *SRegion) GetInstanceByID(instanceId string) (SInstance, error) { + instance := SInstance{} + err := DoGet(self.ecsClient.Servers.Get, instanceId, nil, &instance) + return instance, err +} + +func (self *SRegion) GetInstanceByIds(ids []string) ([]SInstance, int, error) { + instances := make([]SInstance, 0) + for _, instanceId := range ids { + instance, err := self.GetInstanceByID(instanceId) + if err != nil { + return nil, 0, err + } + instances = append(instances, instance) + } + + return instances, len(instances), nil +} + +/* +系统盘大小取值范围:1-1024 GB,且必须不小于镜像min_disk. +*/ +type SServerCreate struct { + AvailabilityZone string `json:"availability_zone"` + Name string `json:"name"` + ImageRef string `json:"imageRef"` + RootVolume RootVolume `json:"root_volume"` + DataVolumes []DataVolume `json:"data_volumes"` + FlavorRef string `json:"flavorRef"` + UserData string `json:"user_data"` + Vpcid string `json:"vpcid"` + SecurityGroups []SecGroup `json:"security_groups"` + Nics []NIC `json:"nics"` + KeyName string `json:"key_name"` + AdminPass string `json:"adminPass"` + Count int64 `json:"count"` + Extendparam ServerExtendparam `json:"extendparam"` + ServerTags []ServerTag `json:"server_tags"` + Description string `json:"description"` + Metadata map[string]string `json:"metadata"` +} + +type DataVolume struct { + Volumetype string `json:"volumetype"` + SizeGB int `json:"size"` + Extendparam *DataVolumeExtendparam `json:"extendparam,omitempty"` + Multiattach *bool `json:"multiattach,omitempty"` + HwPassthrough *string `json:"hw:passthrough,omitempty"` +} + +type DataVolumeExtendparam struct { + SnapshotID string `json:"snapshotId"` +} + +type ServerExtendparam struct { + ChargingMode string `json:"chargingMode"` // 计费模式 prePaid|postPaid + PeriodType string `json:"periodType"` // 周期类型:month|year + PeriodNum string `json:"periodNum"` // 订购周期数:periodType=month(周期类型为月)时,取值为[1,9]。periodType=year(周期类型为年)时,取值为1。 + IsAutoRenew string `json:"isAutoRenew"` // 是否自动续订 true|false + IsAutoPay string `json:"isAutoPay"` // 是否自动从客户的账户中支付 true|false + RegionID string `json:"regionID"` + EnterpriseProjectId string `json:"enterprise_project_id,omitempty"` +} + +type NIC struct { + SubnetID string `json:"subnet_id"` // 网络ID. 与 SNetwork里的ID对应。统一使用这个ID + IpAddress string `json:"ip_address"` +} + +type RootVolume struct { + Volumetype string `json:"volumetype"` + SizeGB int `json:"size"` +} + +type SecGroup struct { + ID string `json:"id"` +} + +type ServerTag struct { + Key string `json:"key"` + Value string `json:"value"` +} + +/* +包月机器退订规则: https://support.huaweicloud.com/usermanual-billing/zh-cn_topic_0083138805.html +5天无理由全额退订:新购资源(不包含续费资源)在开通的五天内且退订次数不超过10次(每账号每年10次)的符合5天无理由全额退订。 +非5天无理由退订:不符合5天无理由全额退订条件的退订,都属于非5天无理由退订。非5天无理由退订,不限制退订次数,但需要收取退订手续费。 + +退订资源的方法: https://support.huaweicloud.com/usermanual-billing/zh-cn_topic_0072297197.html +*/ +func (self *SRegion) CreateInstance(name string, imageId string, instanceType string, SubnetId string, + securityGroupId string, vpcId string, zoneId string, desc string, disks []SDisk, ipAddr string, + keypair string, publicKey string, passwd string, userData string, bc *billing.SBillingCycle, projectId string, tags map[string]string) (string, error) { + params := SServerCreate{} + params.AvailabilityZone = zoneId + params.Name = name + params.FlavorRef = instanceType + params.ImageRef = imageId + params.Description = desc + params.Count = 1 + params.Nics = []NIC{{SubnetID: SubnetId, IpAddress: ipAddr}} + params.SecurityGroups = []SecGroup{{ID: securityGroupId}} + params.Vpcid = vpcId + params.Metadata = map[string]string{} + + for i, disk := range disks { + if i == 0 { + params.RootVolume.Volumetype = disk.VolumeType + params.RootVolume.SizeGB = disk.SizeGB + } else { + dataVolume := DataVolume{} + dataVolume.Volumetype = disk.VolumeType + dataVolume.SizeGB = disk.SizeGB + params.DataVolumes = append(params.DataVolumes, dataVolume) + } + } + + if len(projectId) > 0 { + params.Extendparam.EnterpriseProjectId = projectId + } + + // billing type + if bc != nil { + params.Extendparam.ChargingMode = PRE_PAID + if bc.GetMonths() <= 9 { + params.Extendparam.PeriodNum = strconv.Itoa(bc.GetMonths()) + params.Extendparam.PeriodType = "month" + } else { + params.Extendparam.PeriodNum = strconv.Itoa(bc.GetYears()) + params.Extendparam.PeriodType = "year" + } + + params.Extendparam.RegionID = self.GetId() + if bc.AutoRenew { + params.Extendparam.IsAutoRenew = "true" + } else { + params.Extendparam.IsAutoRenew = "false" + } + params.Extendparam.IsAutoPay = "true" + params.Metadata["op_svc_userid"] = self.client.ownerId + } else { + params.Extendparam.ChargingMode = POST_PAID + } + + // https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212668.html#ZH-CN_TOPIC_0020212668__table761103195216 + if len(keypair) > 0 { + params.KeyName = keypair + } else { + params.AdminPass = passwd + } + + if len(userData) > 0 { + params.UserData = userData + } + + if len(tags) > 0 { + serverTags := []ServerTag{} + for k, v := range tags { + serverTags = append(serverTags, ServerTag{Key: k, Value: v}) + } + params.ServerTags = serverTags + } + + serverObj := jsonutils.Marshal(params) + createParams := jsonutils.NewDict() + createParams.Add(serverObj, "server") + _id, err := self.ecsClient.Servers.AsyncCreate(createParams) + if err != nil { + return "", err + } + + ids, err := self.GetAllSubTaskEntityIDs(self.ecsClient.Servers.ServiceType(), _id, "server_id") + if err != nil { + return "", errors.Wrapf(err, "GetAllSubTaskEntityIDs(%s)", _id) + } + + if len(ids) == 0 { + return "", fmt.Errorf("CreateInstance job %s result is emtpy", _id) + } + if len(ids) == 1 { + return ids[0], nil + } + return "", fmt.Errorf("CreateInstance job %s mutliple instance id returned. %s", _id, ids) +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067161469.html +// 添加多个安全组时,建议最多为弹性云服务器添加5个安全组。 +// todo: 确认是否需要先删除,再进行添加操作 +func (self *SRegion) assignSecurityGroups(secgroupIds []string, instanceId string) error { + _, err := self.GetInstanceByID(instanceId) + if err != nil { + return err + } + + for i := range secgroupIds { + secId := secgroupIds[i] + params := jsonutils.NewDict() + secgroupObj := jsonutils.NewDict() + secgroupObj.Add(jsonutils.NewString(secId), "name") + params.Add(secgroupObj, "addSecurityGroup") + + _, err := self.ecsClient.NovaServers.PerformAction("action", instanceId, params) + if err != nil { + return err + } + } + return nil +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067161717.html +func (self *SRegion) unassignSecurityGroups(secgroupIds []string, instanceId string) error { + for i := range secgroupIds { + secId := secgroupIds[i] + params := jsonutils.NewDict() + secgroupObj := jsonutils.NewDict() + secgroupObj.Add(jsonutils.NewString(secId), "name") + params.Add(secgroupObj, "removeSecurityGroup") + + _, err := self.ecsClient.NovaServers.PerformAction("action", instanceId, params) + if err != nil { + return err + } + } + return nil +} + +func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) { + instance, err := self.GetInstanceByID(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: %s", err) + return err + } + if status != remoteStatus { + log.Errorf("instanceStatusChecking: vm status is %s expect %s", remoteStatus, status) + return cloudprovider.ErrInvalidStatus + } + + return nil +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212207.html +func (self *SRegion) StartVM(instanceId string) error { + rstatus, err := self.GetInstanceStatus(instanceId) + if err != nil { + return err + } + + if rstatus == InstanceStatusRunning { + return nil + } + + if rstatus != InstanceStatusStopped { + log.Errorf("instanceStatusChecking: vm status is %s expect %s", rstatus, InstanceStatusStopped) + return cloudprovider.ErrInvalidStatus + } + + params := jsonutils.NewDict() + startObj := jsonutils.NewDict() + serversObj := jsonutils.NewArray() + serverObj := jsonutils.NewDict() + serverObj.Add(jsonutils.NewString(instanceId), "id") + serversObj.Add(serverObj) + startObj.Add(serversObj, "servers") + params.Add(startObj, "os-start") + _, err = self.ecsClient.Servers.PerformAction2("action", "", params, "") + return err +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212651.html +func (self *SRegion) StopVM(instanceId string, isForce bool) error { + rstatus, err := self.GetInstanceStatus(instanceId) + if err != nil { + return err + } + + if rstatus == InstanceStatusStopped { + return nil + } + + if rstatus != InstanceStatusRunning { + log.Errorf("instanceStatusChecking: vm status is %s expect %s", rstatus, InstanceStatusRunning) + return cloudprovider.ErrInvalidStatus + } + + params := jsonutils.NewDict() + stopObj := jsonutils.NewDict() + serversObj := jsonutils.NewArray() + serverObj := jsonutils.NewDict() + serverObj.Add(jsonutils.NewString(instanceId), "id") + serversObj.Add(serverObj) + stopObj.Add(serversObj, "servers") + if isForce { + stopObj.Add(jsonutils.NewString("HARD"), "type") + } else { + stopObj.Add(jsonutils.NewString("SOFT"), "type") + } + params.Add(stopObj, "os-stop") + _, err = self.ecsClient.Servers.PerformAction2("action", "", params, "") + return err +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212679.html +// 只删除主机。弹性IP和数据盘需要单独删除 +func (self *SRegion) DeleteVM(instanceId string) error { + remoteStatus, err := self.GetInstanceStatus(instanceId) + if err != nil { + return err + } + + if remoteStatus != InstanceStatusStopped { + log.Errorf("DeleteVM vm status is %s expect %s", remoteStatus, InstanceStatusStopped) + return cloudprovider.ErrInvalidStatus + } + + params := jsonutils.NewDict() + serversObj := jsonutils.NewArray() + serverObj := jsonutils.NewDict() + serverObj.Add(jsonutils.NewString(instanceId), "id") + serversObj.Add(serverObj) + params.Add(serversObj, "servers") + params.Add(jsonutils.NewBool(false), "delete_publicip") + params.Add(jsonutils.NewBool(false), "delete_volume") + + _, err = self.ecsClient.Servers.PerformAction2("delete", "", params, "") + return err +} + +func (self *SRegion) UpdateVM(instanceId, name string) error { + params := jsonutils.NewDict() + serverObj := jsonutils.NewDict() + serverObj.Add(jsonutils.NewString(name), "name") + params.Add(serverObj, "server") + + _, err := self.ecsClient.Servers.Update(instanceId, params) + return err +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876349.html +// 返回job id +func (self *SRegion) RebuildRoot(ctx context.Context, userId, instanceId, passwd, publicKeyName, userData string) (string, error) { + params := jsonutils.NewDict() + reinstallObj := jsonutils.NewDict() + + if len(publicKeyName) > 0 { + reinstallObj.Add(jsonutils.NewString(publicKeyName), "keyname") + } else if len(passwd) > 0 { + reinstallObj.Add(jsonutils.NewString(passwd), "adminpass") + } else { + return "", fmt.Errorf("both password and publicKey are empty.") + } + + if len(userData) > 0 { + meta := jsonutils.NewDict() + meta.Add(jsonutils.NewString(userData), "user_data") + reinstallObj.Add(meta, "metadata") + } + + if len(userId) > 0 { + reinstallObj.Add(jsonutils.NewString(userId), "userid") + } + + params.Add(reinstallObj, "os-reinstall") + ret, err := self.ecsClient.ServersV2.PerformAction2("reinstallos", instanceId, params, "") + if err != nil { + return "", err + } + + return ret.GetString("job_id") +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0067876971.html +// 返回job id +func (self *SRegion) ChangeRoot(ctx context.Context, userId, instanceId, imageId, passwd, publicKeyName, userData string) (string, error) { + params := jsonutils.NewDict() + changeOsObj := jsonutils.NewDict() + + if len(publicKeyName) > 0 { + changeOsObj.Add(jsonutils.NewString(publicKeyName), "keyname") + } else if len(passwd) > 0 { + changeOsObj.Add(jsonutils.NewString(passwd), "adminpass") + } else { + return "", fmt.Errorf("both password and publicKey are empty.") + } + + if len(userData) > 0 { + meta := jsonutils.NewDict() + meta.Add(jsonutils.NewString(userData), "user_data") + changeOsObj.Add(meta, "metadata") + } + + if len(userId) > 0 { + changeOsObj.Add(jsonutils.NewString(userId), "userid") + } + + changeOsObj.Add(jsonutils.NewString(imageId), "imageid") + params.Add(changeOsObj, "os-change") + + ret, err := self.ecsClient.ServersV2.PerformAction2("changeos", instanceId, params, "") + if err != nil { + return "", err + } + + return ret.GetString("job_id") +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212692.html +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0110109377.html +// 一键式重置密码 需要安装安装一键式重置密码插件 https://support.huaweicloud.com/usermanual-ecs/zh-cn_topic_0068095385.html +// 目前不支持直接重置密钥 +func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { + serverObj := jsonutils.NewDict() + if len(name) > 0 { + serverObj.Add(jsonutils.NewString(name), "name") + } + + // if len(description) > 0 { + // serverObj.Add(jsonutils.NewString(description), "description") + // } + + if serverObj.Size() > 0 { + params := jsonutils.NewDict() + params.Add(serverObj, "server") + // 这里华为返回的image字段是字符串。和SInstance的定义的image是字典结构不一致。 + err := DoUpdate(self.ecsClient.NovaServers.Update, instanceId, params, nil) + if err != nil { + return err + } + } + + if len(password) > 0 { + params := jsonutils.NewDict() + passwdObj := jsonutils.NewDict() + passwdObj.Add(jsonutils.NewString(password), "new_password") + params.Add(passwdObj, "reset-password") + + err := DoUpdateWithSpec(self.ecsClient.NovaServers.UpdateInContextWithSpec, instanceId, "os-reset-password", params) + if err != nil { + return err + } + } + + return nil +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0020212653.html +func (self *SRegion) ChangeVMConfig(instanceId string, instanceType string) error { + self.ecsClient.Servers.SetVersion("v1.1") + defer self.ecsClient.Servers.SetVersion("v1") + + params := jsonutils.NewDict() + resizeObj := jsonutils.NewDict() + resizeObj.Add(jsonutils.NewString(instanceType), "flavorRef") + params.Add(resizeObj, "resize") + _, err := self.ecsClient.Servers.PerformAction2("resize", instanceId, params, "") + return errors.Wrapf(err, "PerformAction2(resize)") +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0142763126.html 微版本2.6及以上? +// https://support.huaweicloud.com/api-ecs/ecs_02_0208.html +func (self *SRegion) GetInstanceVNCUrl(instanceId string) (*cloudprovider.ServerVncOutput, error) { + params := jsonutils.NewDict() + vncObj := jsonutils.NewDict() + vncObj.Add(jsonutils.NewString("novnc"), "type") + vncObj.Add(jsonutils.NewString("vnc"), "protocol") + params.Add(vncObj, "remote_console") + + ret, err := self.ecsClient.Servers.PerformAction2("remote_console", instanceId, params, "remote_console") + if err != nil { + return nil, err + } + + result := &cloudprovider.ServerVncOutput{ + Hypervisor: api.HYPERVISOR_HUAWEI, + } + ret.Unmarshal(result) + result.Protocol = "huawei" + return result, nil +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022472987.html +// XEN平台虚拟机device为必选参数。 +func (self *SRegion) AttachDisk(instanceId string, diskId string, device string) error { + params := jsonutils.NewDict() + volumeObj := jsonutils.NewDict() + volumeObj.Add(jsonutils.NewString(diskId), "volumeId") + if len(device) > 0 { + volumeObj.Add(jsonutils.NewString(device), "device") + } + + params.Add(volumeObj, "volumeAttachment") + + _, err := self.ecsClient.Servers.PerformAction2("attachvolume", instanceId, params, "") + return err +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0022472988.html +// 默认非强制卸载。delete_flag=0 +func (self *SRegion) DetachDisk(instanceId string, diskId string) error { + path := fmt.Sprintf("detachvolume/%s", diskId) + err := DoDeleteWithSpec(self.ecsClient.Servers.DeleteInContextWithSpec, nil, instanceId, path, nil, nil) + //volume a2091934-2669-4fca-8eb4-a950c1836b3c is not in server 49b053d2-f798-432f-af55-76eb6ef2c769 attach volume list => 磁盘已经被卸载了 + if err != nil && strings.Contains(err.Error(), fmt.Sprintf("is not in server")) && strings.Contains(err.Error(), fmt.Sprintf("attach volume list")) { + return nil + } + return err +} + +// // https://support.huaweicloud.com/api-bpconsole/zh-cn_topic_0082522029.html +// 只支持传入主资源ID, 根据“查询客户包周期资源列表”接口响应参数中的“is_main_resource”来标识。 +// expire_mode 0:进入宽限期 1:转按需 2:自动退订 3:自动续订(当前只支持ECS、EVS和VPC) +func (self *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle) error { + params := jsonutils.NewDict() + res := jsonutils.NewArray() + res.Add(jsonutils.NewString(instanceId)) + params.Add(res, "resource_ids") + params.Add(jsonutils.NewInt(EXPIRE_MODE_AUTO_UNSUBSCRIBE), "expire_mode") // 自动退订 + params.Add(jsonutils.NewInt(AUTO_PAY_TRUE), "isAutoPay") // 自动支付 + month := int64(bc.GetMonths()) + year := int64(bc.GetYears()) + + if month >= 1 && month <= 11 { + params.Add(jsonutils.NewInt(PERIOD_TYPE_MONTH), "period_type") + params.Add(jsonutils.NewInt(month), "period_num") + } else if year >= 1 && year <= 3 { + params.Add(jsonutils.NewInt(PERIOD_TYPE_YEAR), "period_type") + params.Add(jsonutils.NewInt(year), "period_num") + } else { + return fmt.Errorf("invalid renew period %d month,must be 1~11 month or 1~3 year", month) + } + + domainId, err := self.getDomianId() + if err != nil { + return err + } + + err = self.ecsClient.Orders.SetDomainId(domainId) + if err != nil { + return err + } + + _, err = self.ecsClient.Orders.RenewPeriodResource(params) + return err +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817702.html +func (self *SRegion) GetInstanceSecrityGroupIds(instanceId string) ([]string, error) { + if len(instanceId) == 0 { + return nil, fmt.Errorf("GetInstanceSecrityGroups instanceId is empty") + } + + securitygroups := make([]SSecurityGroup, 0) + ctx := &modules.SManagerContext{InstanceManager: self.ecsClient.NovaServers, InstanceId: instanceId} + err := DoListInContext(self.ecsClient.NovaSecurityGroups.ListInContext, ctx, nil, &securitygroups) + if err != nil { + return nil, err + } + + securitygroupIds := []string{} + for _, secgroup := range securitygroups { + securitygroupIds = append(securitygroupIds, secgroup.GetId()) + } + + return securitygroupIds, nil +} + +// https://support.huaweicloud.com/api-oce/zh-cn_topic_0082522030.html +func (self *SRegion) UnsubscribeInstance(instanceId string, domianId string) (jsonutils.JSONObject, error) { + unsubObj := jsonutils.NewDict() + unsubObj.Add(jsonutils.NewInt(1), "unSubType") + unsubObj.Add(jsonutils.NewInt(5), "unsubscribeReasonType") + unsubObj.Add(jsonutils.NewString("no reason"), "unsubscribeReason") + resList := jsonutils.NewArray() + resList.Add(jsonutils.NewString(instanceId)) + unsubObj.Add(resList, "resourceIds") + + self.ecsClient.Orders.SetDomainId(domianId) + return self.ecsClient.Orders.PerformAction("resources/delete", "", unsubObj) +} + +func (self *SInstance) GetProjectId() string { + return self.EnterpriseProjectId +} + +func (self *SInstance) GetError() error { + return nil +} + +func updateUserData(userData, osVersion, username, password, publicKey string) (string, error) { + winOS := strings.ToLower(osprofile.OS_TYPE_WINDOWS) + osVersion = strings.ToLower(osVersion) + config := &cloudinit.SCloudConfig{} + if strings.Contains(osVersion, winOS) { + if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { + config = _config + } else { + log.Debugf("updateWindowsUserData invalid userdata %s", userData) + } + } else { + if _config, err := cloudinit.ParseUserDataBase64(userData); err == nil { + config = _config + } else { + return "", fmt.Errorf("updateLinuxUserData invalid userdata %s", userData) + } + } + + user := cloudinit.NewUser(username) + config.RemoveUser(user) + config.DisableRoot = 0 + if len(password) > 0 { + config.SshPwauth = cloudinit.SSH_PASSWORD_AUTH_ON + user.Password(password) + config.MergeUser(user) + } + + if len(publicKey) > 0 { + user.SshKey(publicKey) + config.MergeUser(user) + } + + if strings.Contains(osVersion, winOS) { + userData, err := updateWindowsUserData(config.UserDataPowerShell(), osVersion, username, password) + if err != nil { + return "", errors.Wrap(err, "updateUserData.updateWindowsUserData") + } + return userData, nil + } else { + return config.UserDataBase64(), nil + } +} + +func updateWindowsUserData(userData string, osVersion string, username, password string) (string, error) { + // Windows Server 2003, Windows Vista, Windows Server 2008, Windows Server 2003 R2, Windows Server 2000, Windows Server 2012, Windows Server 2003 with SP1, Windows 8 + oldVersions := []string{"2000", "2003", "2008", "2012", "Vista"} + isOldVersion := false + for i := range oldVersions { + if strings.Contains(osVersion, oldVersions[i]) { + isOldVersion = true + } + } + + shells := "" + if isOldVersion { + shells += fmt.Sprintf("rem cmd\n") + if username == "Administrator" { + shells += fmt.Sprintf("net user %s %s\n", username, password) + } else { + shells += fmt.Sprintf("net user %s %s /add\n", username, password) + shells += fmt.Sprintf("net localgroup administrators %s /add\n", username) + } + + shells += fmt.Sprintf("net user %s /active:yes", username) + } else { + if !strings.HasPrefix(userData, "#ps1") { + shells = fmt.Sprintf("#ps1\n%s", userData) + } + } + + return base64.StdEncoding.EncodeToString([]byte(shells)), nil +} + +func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { + params := map[string]string{ + "name": opts.Name, + "instance_id": instanceId, + } + if len(opts.Notes) > 0 { + params["description"] = func() string { + opts.Notes = strings.ReplaceAll(opts.Notes, "<", "") + opts.Notes = strings.ReplaceAll(opts.Notes, ">", "") + opts.Notes = strings.ReplaceAll(opts.Notes, "\n", "") + if len(opts.Notes) > 1024 { + opts.Notes = opts.Notes[:1024] + } + return opts.Notes + }() + } + resp, err := self.ecsClient.Images.CreateInContextWithSpec(nil, "action", jsonutils.Marshal(params), "") + if err != nil { + return nil, errors.Wrapf(err, "Images.Create") + } + jobId, err := resp.GetString("job_id") + if err != nil { + return nil, errors.Wrapf(err, "resp.GetString(job_id)") + } + err = self.waitTaskStatus(self.ecsClient.Images.ServiceType(), jobId, TASK_SUCCESS, 15*time.Second, 10*time.Minute) + if err != nil { + return nil, errors.Wrapf(err, "waitTaskStatus") + } + imageId, err := self.GetTaskEntityID(self.ecsClient.Images.ServiceType(), jobId, "image_id") + if err != nil { + return nil, errors.Wrapf(err, "GetTaskEntityID") + } + image, err := self.GetImage(imageId) + if err != nil { + return nil, errors.Wrapf(err, "GetImage(%s)", imageId) + } + image.storageCache = self.getStoragecache() + return image, nil +} + +func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { + image, err := self.host.zone.region.SaveImage(self.ID, opts) + if err != nil { + return nil, errors.Wrapf(err, "SaveImage") + } + return image, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancenic.go new file mode 100644 index 0000000000..3aecdb2ec4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancenic.go @@ -0,0 +1,111 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" +) + +// =========================================== +type Interface struct { + PortState string `json:"port_state"` + FixedIPS []FixedIP `json:"fixed_ips"` + NetID string `json:"net_id"` // 网络ID. 与 SNetwork里的ID对应。统一使用这个ID + PortID string `json:"port_id"` + MACAddr string `json:"mac_addr"` +} + +/* +subnet: {id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233", name: "subnet-149c", cidr: "192.168.0.0/24",…} +availability_zone: "cn-north-1b" +cidr: "192.168.0.0/24" +dhcp_enable: true +dnsList: ["100.125.1.250", "100.125.21.250"] +gateway_ip: "192.168.0.1" +id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233" +ipv6_enable: false +name: "subnet-149c" +neutron_network_id: "b09877fc-90d4-4fc8-b343-e6e00cb2b233" +neutron_subnet_id: "81fcfaa0-8e73-4472-9eba-3b2b7736d3a7" +primary_dns: "100.125.1.250" +secondary_dns: "100.125.21.250" +status: "ACTIVE" +tags: [] +vpc_id: "877f1feb-3dc8-4c2d-92e9-0d94fd7d79dd"} +*/ +type FixedIP struct { + SubnetID string `json:"subnet_id"` // 子网ID, 与SNetwork中的 neutron_subnet_id对应. 注意!!! 并不是SNetwork ID。 + IPAddress string `json:"ip_address"` +} + +// =========================================== + +type SInstanceNic struct { + instance *SInstance + ipAddr string + macAddr string + + cloudprovider.DummyICloudNic +} + +func (self *SInstanceNic) GetId() string { + return "" +} + +func (self *SInstanceNic) GetIP() string { + return self.ipAddr +} + +func (self *SInstanceNic) GetMAC() string { + return self.macAddr +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) GetINetworkId() string { + instanceId := self.instance.GetId() + subnets, err := self.instance.host.zone.region.getSubnetIdsByInstanceId(instanceId) + if err != nil || len(subnets) == 0 { + log.Errorf("getSubnetIdsByInstanceId error: %s", err.Error()) + return "" + } + + return subnets[0] +} + +func (self *SRegion) getSubnetIdsByInstanceId(instanceId string) ([]string, error) { + ctx := &modules.SManagerContext{InstanceManager: self.ecsClient.NovaServers, InstanceId: instanceId} + interfaces := make([]Interface, 0) + err := DoListInContext(self.ecsClient.Interface.ListInContext, ctx, nil, &interfaces) + if err != nil { + return nil, err + } + + subnets := make([]string, 0) + for _, i := range interfaces { + subnets = append(subnets, i.NetID) + } + + return subnets, nil +} diff --git a/pkg/multicloud/huawei/instancetype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancetype.go similarity index 100% rename from pkg/multicloud/huawei/instancetype.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/instancetype.go diff --git a/pkg/multicloud/huawei/keypair.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/keypair.go similarity index 100% rename from pkg/multicloud/huawei/keypair.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/keypair.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/latitud_and_longitude.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/latitud_and_longitude.go new file mode 100644 index 0000000000..b8169c7c20 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/latitud_and_longitude.go @@ -0,0 +1,44 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +// China: https://developer.huaweicloud.com/endpoint +// International: https://developer-intl.huaweicloud.com/endpoint +// ref: https://countrycode.org +var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ + "cn-east-2": api.RegionShanghai, + "cn-east-3": api.RegionShanghai, + "cn-north-1": api.RegionBeijing, + "cn-north-4": api.RegionBeijing, + "cn-south-1": api.RegionGuangzhou, + "cn-south-2": api.RegionGuangzhou, + "ap-southeast-1": api.RegionHongkong, + "ap-southeast-2": api.RegionBangkok, + "ap-southeast-3": api.RegionSingapore, + "eu-west-0": api.RegionParis, + "cn-northeast-1": api.RegionDalian, + "cn-southwest-2": api.RegionGuiyang, + "af-south-1": api.RegionJohannesburg, + "sa-brazil-1": api.RegionSaoPaulo, + "na-mexico-1": api.RegionMexico, + "la-south-2": api.RegionSantiago, + "cn-north-9": api.RegionNeimenggu, + "cn-north-219": api.RegionBeijing, +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer.go new file mode 100644 index 0000000000..18538c52ae --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer.go @@ -0,0 +1,625 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "fmt" + "net/url" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var LB_ALGORITHM_MAP = map[string]string{ + api.LB_SCHEDULER_WRR: "ROUND_ROBIN", + api.LB_SCHEDULER_WLC: "LEAST_CONNECTIONS", + api.LB_SCHEDULER_SCH: "SOURCE_IP", +} + +var LB_PROTOCOL_MAP = map[string]string{ + api.LB_LISTENER_TYPE_HTTP: "HTTP", + api.LB_LISTENER_TYPE_HTTPS: "TERMINATED_HTTPS", + api.LB_LISTENER_TYPE_UDP: "UDP", + api.LB_LISTENER_TYPE_TCP: "TCP", +} + +var LBBG_PROTOCOL_MAP = map[string]string{ + api.LB_LISTENER_TYPE_HTTP: "HTTP", + api.LB_LISTENER_TYPE_HTTPS: "HTTP", + api.LB_LISTENER_TYPE_UDP: "UDP", + api.LB_LISTENER_TYPE_TCP: "TCP", +} + +var LB_STICKY_SESSION_MAP = map[string]string{ + api.LB_STICKY_SESSION_TYPE_INSERT: "HTTP_COOKIE", + api.LB_STICKY_SESSION_TYPE_SERVER: "APP_COOKIE", +} + +var LB_HEALTHCHECK_TYPE_MAP = map[string]string{ + api.LB_HEALTH_CHECK_HTTP: "HTTP", + api.LB_HEALTH_CHECK_TCP: "TCP", + api.LB_HEALTH_CHECK_UDP: "UDP_CONNECT", +} + +type SLoadbalancer struct { + multicloud.SResourceBase + HuaweiTags + region *SRegion + subnet *SNetwork + eip *SEipAddress + + Description string `json:"description"` + ProvisioningStatus string `json:"provisioning_status"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + AdminStateUp bool `json:"admin_state_up"` + Provider string `json:"provider"` + Pools []Pool `json:"pools"` + Listeners []Listener `json:"listeners"` + VipPortID string `json:"vip_port_id"` + OperatingStatus string `json:"operating_status"` + VipAddress string `json:"vip_address"` + VipSubnetID string `json:"vip_subnet_id"` + ID string `json:"id"` + Name string `json:"name"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +type Listener struct { + ID string `json:"id"` +} + +type Pool struct { + ID string `json:"id"` +} + +func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { + if self.GetEip() == nil { + return nil, nil + } + + return self.eip, nil +} + +func (self *SLoadbalancer) GetId() string { + return self.ID +} + +func (self *SLoadbalancer) GetName() string { + return self.Name +} + +func (self *SLoadbalancer) GetGlobalId() string { + return self.ID +} + +func (self *SLoadbalancer) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLoadbalancer) Refresh() error { + lb, err := self.region.GetLoadbalancer(self.GetId()) + if err != nil { + return err + } + + return jsonutils.Update(self, lb) +} + +func (self *SLoadbalancer) IsEmulated() bool { + return false +} + +func (self *SLoadbalancer) GetProjectId() string { + return self.ProjectID +} + +func (self *SLoadbalancer) GetAddress() string { + return self.VipAddress +} + +// todo: api.LB_ADDR_TYPE_INTERNET? +func (self *SLoadbalancer) GetAddressType() string { + return api.LB_ADDR_TYPE_INTRANET +} + +func (self *SLoadbalancer) GetNetworkType() string { + return api.LB_NETWORK_TYPE_VPC +} + +func (self *SLoadbalancer) GetNetworkIds() []string { + net := self.GetNetwork() + if net != nil { + return []string{net.GetId()} + } + + return []string{} +} + +func (self *SLoadbalancer) GetNetwork() *SNetwork { + if self.subnet == nil { + port, err := self.region.GetPort(self.VipPortID) + if err == nil { + net, err := self.region.getNetwork(port.NetworkID) + if err == nil { + self.subnet = net + } else { + log.Debugf("huawei.SLoadbalancer.getNetwork %s", err) + } + } else { + log.Debugf("huawei.SLoadbalancer.GetPort %s", err) + } + } + + return self.subnet +} + +func (self *SLoadbalancer) GetEip() *SEipAddress { + if self.eip == nil { + eips, _ := self.region.GetEips(self.VipPortID, nil) + for i := range eips { + self.eip = &eips[i] + } + } + return self.eip +} + +func (self *SLoadbalancer) GetVpcId() string { + net := self.GetNetwork() + if net != nil { + return net.VpcID + } + + return "" +} + +func (self *SLoadbalancer) GetZoneId() string { + net := self.GetNetwork() + if net != nil { + z, err := self.region.getZoneById(net.AvailabilityZone) + if err != nil { + log.Infof("getZoneById %s %s", net.AvailabilityZone, err) + return "" + } + + return z.GetGlobalId() + } + + return "" +} + +func (self *SLoadbalancer) GetZone1Id() string { + return "" +} + +func (self *SLoadbalancer) GetLoadbalancerSpec() string { + return "" +} + +func (self *SLoadbalancer) GetChargeType() string { + eip := self.GetEip() + if eip != nil { + return eip.GetInternetChargeType() + } + + return api.EIP_CHARGE_TYPE_BY_TRAFFIC +} + +func (self *SLoadbalancer) GetEgressMbps() int { + eip := self.GetEip() + if eip != nil { + return eip.GetBandwidth() + } + + return 0 +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0141008275.html +func (self *SLoadbalancer) Delete(ctx context.Context) error { + return self.region.DeleteLoadBalancer(self.GetId()) +} + +func (self *SLoadbalancer) Start() error { + return nil +} + +func (self *SLoadbalancer) Stop() error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + ret, err := self.region.GetLoadBalancerListeners(self.GetId()) + if err != nil { + return nil, err + } + + iret := make([]cloudprovider.ICloudLoadbalancerListener, 0) + for i := range ret { + listener := ret[i] + listener.lb = self + iret = append(iret, &listener) + } + + return iret, nil +} + +func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + ret, err := self.region.GetLoadBalancerBackendGroups(self.GetId()) + if err != nil { + return nil, err + } + + iret := make([]cloudprovider.ICloudLoadbalancerBackendGroup, 0) + for i := range ret { + bg := ret[i] + bg.lb = self + bg.region = self.region + iret = append(iret, &bg) + } + + return iret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561549.html +func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + ret, err := self.region.CreateLoadBalancerBackendGroup(group) + ret.lb = self + return &ret, err +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561563.html +func (self *SLoadbalancer) CreateHealthCheck(backendGroupId string, healthcheck *cloudprovider.SLoadbalancerHealthCheck) error { + _, err := self.region.CreateLoadBalancerHealthCheck(backendGroupId, healthcheck) + return err +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561548.html +func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + ret := &SElbBackendGroup{lb: self, region: self.region} + resp, err := self.region.lbGet("elb/pools/" + groupId) + if err != nil { + return nil, err + } + return ret, resp.Unmarshal(ret, "pool") +} + +func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + ret, err := self.region.CreateLoadBalancerListener(listener) + if err != nil { + return nil, err + } + + ret.lb = self + return &ret, nil +} + +func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { + ret := &SElbListener{lb: self} + resp, err := self.region.lbGet("elb/listeners/" + listenerId) + if err != nil { + return nil, err + } + return ret, resp.Unmarshal(ret, "listener") +} + +func (self *SRegion) GetLoadbalancer(id string) (*SLoadbalancer, error) { + resp, err := self.lbGet("elb/loadbalancers/" + id) + if err != nil { + return nil, err + } + ret := &SLoadbalancer{region: self} + return ret, resp.Unmarshal(ret, "loadbalancer") +} + +func (self *SRegion) DeleteLoadBalancer(elbId string) error { + resource := fmt.Sprintf("elb/loadbalancers/%s", elbId) + _, err := self.lbDelete(resource) + return err +} + +func (self *SRegion) GetLoadBalancerListeners(lbId string) ([]SElbListener, error) { + ret := []SElbListener{} + params := url.Values{} + if len(lbId) > 0 { + params.Set("loadbalancer_id", lbId) + } + return ret, self.lbListAll("elb/listeners", params, "listeners", &ret) +} + +func (self *SRegion) CreateLoadBalancerListener(listener *cloudprovider.SLoadbalancerListener) (SElbListener, error) { + params := map[string]interface{}{ + "name": listener.Name, + "description": listener.Description, + "protocol": LB_PROTOCOL_MAP[listener.ListenerType], + "protocol_port": listener.ListenerPort, + "loadbalancer_id": listener.LoadbalancerID, + "http2_enable": listener.EnableHTTP2, + } + if len(listener.BackendGroupID) > 0 { + params["default_pool_id"] = listener.BackendGroupID + } + + if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { + params["default_tls_container_ref"] = listener.CertificateID + } + + if listener.XForwardedFor { + params["insert_headers"] = map[string]interface{}{ + "X-Forwarded-ELB-IP": listener.XForwardedFor, + } + } + + ret := SElbListener{} + resp, err := self.lbCreate("lb/listeners", map[string]interface{}{"listener": params}) + if err != nil { + return ret, err + } + return ret, resp.Unmarshal(&ret, "listener") +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html +func (self *SRegion) GetLoadBalancerBackendGroups(elbId string) ([]SElbBackendGroup, error) { + query := url.Values{} + if len(elbId) > 0 { + query.Set("loadbalancer_id", elbId) + } + + ret := []SElbBackendGroup{} + return ret, self.lbListAll("elb/pools", query, "pools", &ret) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561547.html +func (self *SRegion) CreateLoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (SElbBackendGroup, error) { + ret := SElbBackendGroup{region: self} + var protocol, scheduler string + if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { + return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) + } else { + scheduler = s + } + + if t, ok := LBBG_PROTOCOL_MAP[group.ListenType]; !ok { + return ret, fmt.Errorf("CreateILoadBalancerBackendGroup unsupported listener type %s", group.ListenType) + } else { + protocol = t + } + + params := map[string]interface{}{ + "project_id": self.client.projectId, + "name": group.Name, + "protocol": protocol, + "lb_algorithm": scheduler, + } + + if len(group.ListenerID) > 0 { + params["listener_id"] = group.ListenerID + } else if len(group.LoadbalancerID) > 0 { + params["loadbalancer_id"] = group.LoadbalancerID + } else { + return ret, fmt.Errorf("CreateLoadBalancerBackendGroup one of listener id / loadbalancer id must be specified") + } + + if group.StickySession != nil { + s := map[string]interface{}{} + timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) + if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { + s["type"] = "SOURCE_IP" + if timeout > 0 { + s["persistence_timeout"] = timeout + } + } else { + s["type"] = LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType] + if len(group.StickySession.StickySessionCookie) > 0 { + s["cookie_name"] = group.StickySession.StickySessionCookie + } else { + if timeout > 0 { + s["persistence_timeout"] = timeout + } + } + } + params["session_persistence"] = s + } + resp, err := self.lbCreate("elb/pools", map[string]interface{}{"pool": params}) + if err != nil { + return ret, err + } + err = resp.Unmarshal(&ret, "pool") + if err != nil { + return ret, err + } + + if group.HealthCheck != nil { + _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) + if err != nil { + return ret, err + } + } + + return ret, nil +} + +func (self *SRegion) CreateLoadBalancerHealthCheck(backendGroupID string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { + params := map[string]interface{}{ + "delay": healthCheck.HealthCheckInterval, + "max_retries": healthCheck.HealthCheckRise, + "pool_id": backendGroupID, + "timeout": healthCheck.HealthCheckTimeout, + "type": LB_HEALTHCHECK_TYPE_MAP[healthCheck.HealthCheckType], + } + if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { + if len(healthCheck.HealthCheckDomain) > 0 { + params["domain_name"] = healthCheck.HealthCheckDomain + } + + if len(healthCheck.HealthCheckURI) > 0 { + params["url_path"] = healthCheck.HealthCheckURI + } + + if len(healthCheck.HealthCheckHttpCode) > 0 { + params["expected_codes"] = ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode) + } + } + + ret := SElbHealthCheck{region: self} + resp, err := self.lbCreate("elb/healthmonitors", map[string]interface{}{"healthmonitor": params}) + if err != nil { + return ret, err + } + + return ret, resp.Unmarshal(&ret, "healthmonitor") +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561564.html +func (self *SRegion) UpdateLoadBalancerHealthCheck(healthCheckID string, healthCheck *cloudprovider.SLoadbalancerHealthCheck) (SElbHealthCheck, error) { + params := map[string]interface{}{ + "delay": healthCheck.HealthCheckInterval, + "max_retries": healthCheck.HealthCheckRise, + "timeout": healthCheck.HealthCheckTimeout, + } + if healthCheck.HealthCheckType == api.LB_HEALTH_CHECK_HTTP { + if len(healthCheck.HealthCheckDomain) > 0 { + params["domain_name"] = healthCheck.HealthCheckDomain + } + + if len(healthCheck.HealthCheckURI) > 0 { + params["url_path"] = healthCheck.HealthCheckURI + } + + if len(healthCheck.HealthCheckHttpCode) > 0 { + params["expected_codes"] = ToHuaweiHealthCheckHttpCode(healthCheck.HealthCheckHttpCode) + } + } + + ret := SElbHealthCheck{region: self} + resp, err := self.lbUpdate("elb/healthmonitors/"+healthCheckID, map[string]interface{}{"healthmonitor": params}) + if err != nil { + return ret, err + } + return ret, resp.Unmarshal(&ret, "healthmonitor") +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561565.html +func (self *SRegion) DeleteLoadbalancerHealthCheck(healthCheckID string) error { + _, err := self.lbDelete("elb/healthmonitors/" + healthCheckID) + return err +} + +func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) lbList(resource string, query url.Values) (jsonutils.JSONObject, error) { + return self.client.lbList(self.ID, resource, query) +} + +func (self *SRegion) vpcList(resource string, query url.Values) (jsonutils.JSONObject, error) { + return self.client.vpcList(self.ID, resource, query) +} + +func (self *SRegion) vpcCreate(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + return self.client.vpcCreate(self.ID, resource, params) +} + +func (self *SRegion) vpcGet(resource string) (jsonutils.JSONObject, error) { + return self.client.vpcGet(self.ID, resource) +} + +func (self *SRegion) vpcDelete(resource string) (jsonutils.JSONObject, error) { + return self.client.vpcDelete(self.ID, resource) +} + +func (self *SRegion) vpcUpdate(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + return self.client.vpcUpdate(self.ID, resource, params) +} + +func (self *SRegion) lbListAll(resource string, query url.Values, respKey string, retVal interface{}) error { + ret := jsonutils.NewArray() + for { + resp, err := self.lbList(resource, query) + if err != nil { + return err + } + arr, err := resp.GetArray(respKey) + if err != nil { + return errors.Wrapf(err, "get %s", respKey) + } + ret.Add(arr...) + marker, _ := resp.GetString("page_info", "next_marker") + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return ret.Unmarshal(retVal) +} + +func (self *SRegion) lbGet(resource string) (jsonutils.JSONObject, error) { + return self.client.lbGet(self.ID, resource) +} + +func (self *SRegion) lbDelete(resource string) (jsonutils.JSONObject, error) { + return self.client.lbDelete(self.ID, resource) +} + +func (self *SRegion) lbCreate(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + return self.client.lbCreate(self.ID, resource, params) +} + +func (self *SRegion) lbUpdate(resource string, params map[string]interface{}) (jsonutils.JSONObject, error) { + return self.client.lbUpdate(self.ID, resource, params) +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561535.html +func (self *SRegion) CreateLoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (*SLoadbalancer, error) { + subnet, err := self.getNetwork(loadbalancer.NetworkIDs[0]) + if err != nil { + return nil, errors.Wrap(err, "SRegion.CreateLoadBalancer.getNetwork") + } + + params := map[string]interface{}{ + "name": loadbalancer.Name, + "vip_subnet_id": subnet.NeutronSubnetID, + "tenant_id": self.client.projectId, + } + if len(loadbalancer.Address) > 0 { + params["vip_address"] = loadbalancer.Address + } + resp, err := self.lbCreate("elb/loadbalancers", map[string]interface{}{"loadbalancer": params}) + if err != nil { + return nil, err + } + ret := &SLoadbalancer{region: self} + err = resp.Unmarshal(ret, "loadbalancer") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + + // 创建公网类型ELB + if len(loadbalancer.EipID) > 0 { + err := self.AssociateEipWithPortId(loadbalancer.EipID, ret.VipPortID) + if err != nil { + return ret, errors.Wrap(err, "SRegion.CreateLoadBalancer.AssociateEipWithPortId") + } + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_acl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_acl.go new file mode 100644 index 0000000000..de94f24e75 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_acl.go @@ -0,0 +1,152 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "net/url" + "strings" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElbACL struct { + multicloud.SResourceBase + HuaweiTags + region *SRegion + + ID string `json:"id"` + ListenerID string `json:"listener_id"` + TenantID string `json:"tenant_id"` + EnableWhitelist bool `json:"enable_whitelist"` + Whitelist string `json:"whitelist"` +} + +func (self *SElbACL) GetAclListenerID() string { + return self.ListenerID +} + +func (self *SElbACL) GetId() string { + return self.ID +} + +func (self *SElbACL) GetName() string { + return self.ID +} + +func (self *SElbACL) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbACL) GetStatus() string { + if self.EnableWhitelist { + return api.LB_BOOL_ON + } + + return api.LB_BOOL_OFF +} + +func (self *SElbACL) Refresh() error { + acl, err := self.region.GetLoadBalancerAcl(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, acl) +} + +func (self *SElbACL) IsEmulated() bool { + return false +} + +func (self *SElbACL) GetProjectId() string { + return "" +} + +func (self *SElbACL) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { + ret := []cloudprovider.SLoadbalancerAccessControlListEntry{} + for _, cidr := range strings.Split(self.Whitelist, ",") { + ret = append(ret, cloudprovider.SLoadbalancerAccessControlListEntry{CIDR: cidr}) + } + + return ret +} + +func (self *SElbACL) Sync(acl *cloudprovider.SLoadbalancerAccessControlList) error { + whiteList := "" + cidrs := []string{} + for _, entry := range acl.Entrys { + cidrs = append(cidrs, entry.CIDR) + } + whiteList = strings.Join(cidrs, ",") + params := map[string]interface{}{ + "whitelist": whiteList, + "enable_whitelist": acl.AccessControlEnable, + } + _, err := self.region.lbUpdate("elb/whitelists/"+self.GetId(), map[string]interface{}{"whitelist": params}) + return err +} + +func (self *SElbACL) Delete() error { + _, err := self.region.lbDelete("elb/whitelists/" + self.GetId()) + return err +} + +func (self *SRegion) GetLoadBalancerAcl(aclId string) (*SElbACL, error) { + resp, err := self.lbGet("elb/whitelists/" + aclId) + if err != nil { + return nil, err + } + ret := &SElbACL{region: self} + return ret, resp.Unmarshal(ret, "whitelist") +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561582.html +func (self *SRegion) GetLoadBalancerAcls(listenerId string) ([]SElbACL, error) { + query := url.Values{} + if len(listenerId) > 0 { + query.Set("listener_id", listenerId) + } + resp, err := self.lbList("elb/whitelists", query) + if err != nil { + return nil, err + } + ret := []SElbACL{} + return ret, resp.Unmarshal(&ret, "whitelists") +} + +func (self *SRegion) CreateLoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (*SElbACL, error) { + params := map[string]interface{}{ + "listener_id": acl.ListenerId, + } + if len(acl.Entrys) > 0 { + whitelist := []string{} + for i := range acl.Entrys { + whitelist = append(whitelist, acl.Entrys[i].CIDR) + } + params["enable_whitelist"] = acl.AccessControlEnable + params["whitelist"] = strings.Join(whitelist, ",") + } else { + params["enable_whitelist"] = false + } + resp, err := self.lbCreate("elb/whitelists", map[string]interface{}{"whitelist": params}) + if err != nil { + return nil, err + } + ret := &SElbACL{region: self} + return ret, resp.Unmarshal(ret, "whitelist") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backend.go new file mode 100644 index 0000000000..14f7828fec --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backend.go @@ -0,0 +1,161 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElbBackend struct { + multicloud.SResourceBase + HuaweiTags + region *SRegion + lb *SLoadbalancer + backendGroup *SElbBackendGroup + + Name string `json:"name"` + Weight int `json:"weight"` + AdminStateUp bool `json:"admin_state_up"` + SubnetID string `json:"subnet_id"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + Address string `json:"address"` + ProtocolPort int `json:"protocol_port"` + OperatingStatus string `json:"operating_status"` + ID string `json:"id"` +} + +func (self *SElbBackend) GetId() string { + return self.ID +} + +func (self *SElbBackend) GetName() string { + return self.Name +} + +func (self *SElbBackend) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbBackend) Refresh() error { + backend, err := self.region.GetElbBackend(self.backendGroup.GetId(), self.ID) + if err != nil { + return err + } + return jsonutils.Update(self, backend) +} + +func (self *SElbBackend) IsEmulated() bool { + return false +} + +func (self *SElbBackend) GetProjectId() string { + return "" +} + +func (self *SElbBackend) GetWeight() int { + return self.Weight +} + +func (self *SElbBackend) GetPort() int { + return self.ProtocolPort +} + +func (self *SElbBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (self *SElbBackend) GetBackendRole() string { + return api.LB_BACKEND_ROLE_DEFAULT +} + +func (self *SElbBackend) GetBackendId() string { + i, err := self.lb.region.getInstanceByIP(self.Address) + if err != nil { + log.Errorf("ElbBackend GetBackendId %s", err) + } + + if i != nil { + return i.GetId() + } + + return "" +} + +func (self *SElbBackend) GetIpAddress() string { + return "" +} + +func (self *SElbBackend) SyncConf(ctx context.Context, port, weight int) error { + if port > 0 { + log.Warningf("Elb backend SyncConf unsupport modify port") + } + + params := map[string]interface{}{ + "weight": weight, + } + res := fmt.Sprintf("elb/pools/%s/members/%s", self.backendGroup.GetId(), self.ID) + _, err := self.region.lbUpdate(res, map[string]interface{}{"member": params}) + return err +} + +func (self *SRegion) getInstanceByIP(privateIP string) (*SInstance, error) { + queries := make(map[string]string) + + if len(self.client.projectId) > 0 { + queries["project_id"] = self.client.projectId + } + + if len(privateIP) > 0 { + queries["ip"] = privateIP + } + + instances := make([]SInstance, 0) + err := doListAllWithOffset(self.ecsClient.Servers.List, queries, &instances) + if err != nil { + return nil, err + } + + if len(instances) == 1 { + return &instances[0], nil + } else if len(instances) > 1 { + log.Warningf("SRegion.getInstanceByIP %s result: multiple server find", privateIP) + return &instances[0], nil + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetElbBackend(pool, id string) (*SElbBackend, error) { + res := fmt.Sprintf("elb/pools/%s/members/%s", pool, id) + resp, err := self.lbGet(res) + if err != nil { + return nil, err + } + ret := &SElbBackend{region: self} + return ret, resp.Unmarshal(ret, "member") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backendgroup.go new file mode 100644 index 0000000000..e0ee3db3ae --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_backendgroup.go @@ -0,0 +1,509 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElbBackendGroup struct { + multicloud.SResourceBase + HuaweiTags + lb *SLoadbalancer + region *SRegion + + LBAlgorithm string `json:"lb_algorithm"` + Protocol string `json:"protocol"` + Description string `json:"description"` + AdminStateUp bool `json:"admin_state_up"` + Loadbalancers []Listener `json:"loadbalancers"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + Listeners []Listener `json:"listeners"` + ID string `json:"id"` + Name string `json:"name"` + HealthMonitorID string `json:"healthmonitor_id"` + SessionPersistence StickySession `json:"session_persistence"` +} + +func (self *SElbBackendGroup) GetLoadbalancerId() string { + return self.lb.GetId() +} + +func (self *SElbBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { + return self.lb +} + +type StickySession struct { + Type string `json:"type"` + CookieName string `json:"cookie_name"` + PersistenceTimeout int `json:"persistence_timeout"` +} + +func (self *SElbBackendGroup) GetProtocolType() string { + switch self.Protocol { + case "TCP": + return api.LB_LISTENER_TYPE_TCP + case "UDP": + return api.LB_LISTENER_TYPE_UDP + case "HTTP": + return api.LB_LISTENER_TYPE_HTTP + default: + return "" + } +} + +func (self *SElbBackendGroup) GetScheduler() string { + switch self.LBAlgorithm { + case "ROUND_ROBIN": + return api.LB_SCHEDULER_WRR + case "LEAST_CONNECTIONS": + return api.LB_SCHEDULER_WLC + case "SOURCE_IP": + return api.LB_SCHEDULER_SCH + default: + return "" + } +} + +func ToHuaweiHealthCheckHttpCode(c string) string { + c = strings.TrimSpace(c) + segs := strings.Split(c, ",") + ret := []string{} + for _, seg := range segs { + seg = strings.TrimLeft(seg, "http_") + seg = strings.TrimSpace(seg) + seg = strings.Replace(seg, "xx", "00", -1) + ret = append(ret, seg) + } + + return strings.Join(ret, ",") +} + +func ToOnecloudHealthCheckHttpCode(c string) string { + c = strings.TrimSpace(c) + segs := strings.Split(c, ",") + ret := []string{} + for _, seg := range segs { + seg = strings.TrimSpace(seg) + seg = strings.Replace(seg, "00", "xx", -1) + seg = "http_" + seg + ret = append(ret, seg) + } + + return strings.Join(ret, ",") +} + +func (self *SElbBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + if len(self.HealthMonitorID) == 0 { + return nil, nil + } + + health, err := self.region.GetLoadBalancerHealthCheck(self.HealthMonitorID) + if err != nil { + return nil, err + } + + var healthCheckType string + switch health.Type { + case "TCP": + healthCheckType = api.LB_HEALTH_CHECK_TCP + case "UDP_CONNECT": + healthCheckType = api.LB_HEALTH_CHECK_UDP + case "HTTP": + healthCheckType = api.LB_HEALTH_CHECK_HTTP + default: + healthCheckType = "" + } + + ret := cloudprovider.SLoadbalancerHealthCheck{ + HealthCheckType: healthCheckType, + HealthCheckTimeout: health.Timeout, + HealthCheckDomain: health.DomainName, + HealthCheckURI: health.URLPath, + HealthCheckInterval: health.Delay, + HealthCheckRise: health.MaxRetries, + HealthCheckHttpCode: ToOnecloudHealthCheckHttpCode(health.ExpectedCodes), + } + + return &ret, nil +} + +func (self *SElbBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + if len(self.SessionPersistence.Type) == 0 { + return nil, nil + } + + var stickySessionType string + switch self.SessionPersistence.Type { + case "SOURCE_IP": + stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT + case "HTTP_COOKIE": + stickySessionType = api.LB_STICKY_SESSION_TYPE_INSERT + case "APP_COOKIE": + stickySessionType = api.LB_STICKY_SESSION_TYPE_SERVER + } + + ret := cloudprovider.SLoadbalancerStickySession{ + StickySession: api.LB_BOOL_ON, + StickySessionCookie: self.SessionPersistence.CookieName, + StickySessionType: stickySessionType, + StickySessionCookieTimeout: self.SessionPersistence.PersistenceTimeout * 60, + } + + return &ret, nil +} + +func (self *SElbBackendGroup) GetId() string { + return self.ID +} + +func (self *SElbBackendGroup) GetName() string { + return self.Name +} + +func (self *SElbBackendGroup) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbBackendGroup) Refresh() error { + ret, err := self.lb.region.GetLoadBalancerBackendGroupId(self.GetId()) + if err != nil { + return err + } + ret.lb = self.lb + + err = jsonutils.Update(self, ret) + if err != nil { + return err + } + + return nil +} + +func (self *SElbBackendGroup) IsEmulated() bool { + return false +} + +func (self *SElbBackendGroup) GetProjectId() string { + return self.ProjectID +} + +func (self *SElbBackendGroup) IsDefault() bool { + return false +} + +func (self *SElbBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_NORMAL +} + +func (self *SElbBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + ret, err := self.region.GetLoadBalancerBackends(self.GetId()) + if err != nil { + return nil, err + } + + iret := []cloudprovider.ICloudLoadbalancerBackend{} + for i := range ret { + backend := ret[i] + backend.lb = self.lb + backend.backendGroup = self + + iret = append(iret, &backend) + } + + return iret, nil +} + +func (self *SElbBackendGroup) GetILoadbalancerBackendById(serverId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + backend, err := self.region.GetElbBackend(self.GetId(), serverId) + if err != nil { + return nil, err + } + backend.lb = self.lb + backend.backendGroup = self + return backend, nil +} + +func (self *SElbBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + instance, err := self.lb.region.GetInstanceByID(serverId) + if err != nil { + return nil, err + } + + nics, err := instance.GetINics() + if err != nil { + return nil, err + } else if len(nics) == 0 { + return nil, fmt.Errorf("AddBackendServer %s no network interface found", serverId) + } + + subnets, err := self.lb.region.getSubnetIdsByInstanceId(instance.GetId()) + if err != nil { + return nil, err + } else if len(subnets) == 0 { + return nil, fmt.Errorf("AddBackendServer %s no subnet found", serverId) + } + + net, err := self.lb.region.getNetwork(subnets[0]) + if err != nil { + return nil, err + } + + backend, err := self.region.AddLoadBalancerBackend(self.GetId(), net.NeutronSubnetID, nics[0].GetIP(), port, weight) + if err != nil { + return nil, err + } + + backend.lb = self.lb + backend.backendGroup = self + return backend, nil +} + +func (self *SElbBackendGroup) RemoveBackendServer(backendId string, weight int, port int) error { + ibackend, err := self.GetILoadbalancerBackendById(backendId) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + + return errors.Wrap(err, "ElbBackendGroup.GetILoadbalancerBackendById") + } + + err = self.region.RemoveLoadBalancerBackend(self.GetId(), backendId) + if err != nil { + return errors.Wrap(err, "ElbBackendGroup.RemoveBackendServer") + } + + return cloudprovider.WaitDeleted(ibackend, 2*time.Second, 30*time.Second) +} + +func (self *SElbBackendGroup) Delete(ctx context.Context) error { + if len(self.HealthMonitorID) > 0 { + err := self.region.DeleteLoadbalancerHealthCheck(self.HealthMonitorID) + if err != nil { + return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadbalancerHealthCheck") + } + } + + // 删除后端服务器组的同时,删除掉无效的后端服务器数据 + { + backends, err := self.region.getLoadBalancerAdminStateDownBackends(self.GetId()) + if err != nil { + return errors.Wrap(err, "SElbBackendGroup.Delete.getLoadBalancerAdminStateDownBackends") + } + + for i := range backends { + backend := backends[i] + err := self.RemoveBackendServer(backend.GetId(), backend.GetPort(), backend.GetWeight()) + if err != nil { + return errors.Wrap(err, "SElbBackendGroup.Delete.RemoveBackendServer") + } + } + } + + err := self.region.DeleteLoadBalancerBackendGroup(self.GetId()) + if err != nil { + return errors.Wrap(err, "ElbBackendGroup.Delete.DeleteLoadBalancerBackendGroup") + } + + return cloudprovider.WaitDeleted(self, 2*time.Second, 30*time.Second) +} + +func (self *SElbBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + if group == nil { + return nil + } + + _, err := self.region.UpdateLoadBalancerBackendGroup(self.GetId(), group) + return err +} + +func (self *SRegion) GetLoadBalancerBackendGroupId(backendGroupId string) (*SElbBackendGroup, error) { + ret := &SElbBackendGroup{region: self} + res := fmt.Sprintf("elb/pools/" + backendGroupId) + resp, err := self.lbGet(res) + if err != nil { + return nil, err + } + return ret, resp.Unmarshal(ret, "pool") +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561550.html +func (self *SRegion) UpdateLoadBalancerBackendGroup(backendGroupID string, group *cloudprovider.SLoadbalancerBackendGroup) (*SElbBackendGroup, error) { + params := map[string]interface{}{ + "name": group.Name, + } + var scheduler string + if s, ok := LB_ALGORITHM_MAP[group.Scheduler]; !ok { + return nil, fmt.Errorf("UpdateLoadBalancerBackendGroup unsupported scheduler %s", group.Scheduler) + } else { + scheduler = s + } + params["lb_algorithm"] = scheduler + + if group.StickySession == nil || group.StickySession.StickySession == api.LB_BOOL_OFF { + params["session_persistence"] = jsonutils.JSONNull + } else { + s := map[string]interface{}{} + timeout := int64(group.StickySession.StickySessionCookieTimeout / 60) + if group.ListenType == api.LB_LISTENER_TYPE_UDP || group.ListenType == api.LB_LISTENER_TYPE_TCP { + s["type"] = "SOURCE_IP" + if timeout > 0 { + s["persistence_timeout"] = timeout + } + } else { + s["type"] = LB_STICKY_SESSION_MAP[group.StickySession.StickySessionType] + if len(group.StickySession.StickySessionCookie) > 0 { + s["cookie_name"] = group.StickySession.StickySessionCookie + } else { + if timeout > 0 { + s["persistence_timeout"] = timeout + } + } + } + params["session_persistence"] = s + } + resp, err := self.lbUpdate("elb/pools/"+backendGroupID, map[string]interface{}{"pool": params}) + if err != nil { + return nil, err + } + + ret := &SElbBackendGroup{} + err = resp.Unmarshal(ret, "pool") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + + if group.HealthCheck == nil && len(ret.HealthMonitorID) > 0 { + err := self.DeleteLoadbalancerHealthCheck(ret.HealthMonitorID) + if err != nil { + return ret, errors.Wrap(err, "DeleteLoadbalancerHealthCheck") + } + } + + if group.HealthCheck != nil { + if len(ret.HealthMonitorID) == 0 { + _, err := self.CreateLoadBalancerHealthCheck(ret.GetId(), group.HealthCheck) + if err != nil { + return ret, errors.Wrap(err, "CreateLoadBalancerHealthCheck") + } + } else { + _, err := self.UpdateLoadBalancerHealthCheck(ret.HealthMonitorID, group.HealthCheck) + if err != nil { + return ret, errors.Wrap(err, "UpdateLoadBalancerHealthCheck") + } + } + } + + ret.region = self + return ret, nil +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561551.html +func (self *SRegion) DeleteLoadBalancerBackendGroup(id string) error { + _, err := self.lbDelete("elb/pools/" + id) + return err +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561556.html +func (self *SRegion) AddLoadBalancerBackend(backendGroupId, subnetId, ipaddr string, port, weight int) (*SElbBackend, error) { + params := map[string]interface{}{ + "address": ipaddr, + "protocol_port": port, + "subnet_id": subnetId, + "weight": weight, + } + ret := &SElbBackend{} + resp, err := self.lbCreate(fmt.Sprintf("elb/pools/%s/members", backendGroupId), map[string]interface{}{"member": params}) + if err != nil { + return nil, err + } + return ret, resp.Unmarshal(ret, "member") +} + +func (self *SRegion) RemoveLoadBalancerBackend(lbbgId string, backendId string) error { + _, err := self.lbDelete(fmt.Sprintf("elb/pools/%s/members/%s", lbbgId, backendId)) + return err +} + +func (self *SRegion) getLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { + res := fmt.Sprintf("elb/pools/%s/members", backendGroupId) + resp, err := self.lbList(res, url.Values{}) + if err != nil { + return nil, err + } + ret := []SElbBackend{} + return ret, resp.Unmarshal(&ret, "members") +} + +func (self *SRegion) GetLoadBalancerBackends(backendGroupId string) ([]SElbBackend, error) { + ret, err := self.getLoadBalancerBackends(backendGroupId) + if err != nil { + return nil, errors.Wrap(err, "SRegion.GetLoadBalancerBackends.getLoadBalancerBackends") + } + + // 过滤掉服务器已经被删除的backend。原因是运管平台查询不到已删除的服务器记录,导致同步出错。产生肮数据。 + filtedRet := []SElbBackend{} + for i := range ret { + if ret[i].AdminStateUp { + backend := ret[i] + filtedRet = append(filtedRet, backend) + } + } + + return filtedRet, nil +} + +func (self *SRegion) getLoadBalancerAdminStateDownBackends(backendGroupId string) ([]SElbBackend, error) { + ret, err := self.getLoadBalancerBackends(backendGroupId) + if err != nil { + return nil, errors.Wrap(err, "SRegion.getLoadBalancerAdminStateDownBackends.getLoadBalancerBackends") + } + + filtedRet := []SElbBackend{} + for i := range ret { + if !ret[i].AdminStateUp { + backend := ret[i] + filtedRet = append(filtedRet, backend) + } + } + + return filtedRet, nil +} + +func (self *SRegion) GetLoadBalancerHealthCheck(healthCheckId string) (*SElbHealthCheck, error) { + resp, err := self.lbGet("elb/healthmonitors/" + healthCheckId) + if err != nil { + return nil, err + } + ret := &SElbHealthCheck{region: self} + return ret, resp.Unmarshal(ret, "healthmonitor") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_cert.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_cert.go new file mode 100644 index 0000000000..bc6e43a49f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_cert.go @@ -0,0 +1,154 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "crypto/sha1" + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElbCert struct { + multicloud.SResourceBase + HuaweiTags + region *SRegion + + Certificate string `json:"certificate"` + CreateTime time.Time `json:"create_time"` + ExpireTime time.Time `json:"expire_time"` + Description string `json:"description"` + Domain string `json:"domain"` + ID string `json:"id"` + AdminStateUp bool `json:"admin_state_up"` + TenantID string `json:"tenant_id"` + Name string `json:"name"` + PrivateKey string `json:"private_key"` + Type string `json:"type"` + UpdateTime time.Time `json:"update_time"` +} + +func (self *SElbCert) GetPublickKey() string { + return self.Certificate +} + +func (self *SElbCert) GetPrivateKey() string { + return self.PrivateKey +} + +func (self *SElbCert) GetId() string { + return self.ID +} + +func (self *SElbCert) GetName() string { + return self.Name +} + +func (self *SElbCert) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbCert) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbCert) Refresh() error { + cert, err := self.region.GetLoadBalancerCertificate(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, cert) +} + +func (self *SElbCert) IsEmulated() bool { + return false +} + +func (self *SElbCert) GetProjectId() string { + return "" +} + +func (self *SElbCert) Sync(name, privateKey, publickKey string) error { + params := map[string]interface{}{ + "name": name, + "private_key": privateKey, + "certificate": publickKey, + } + _, err := self.region.lbUpdate("elb/certificates/"+self.GetId(), params) + return err +} + +func (self *SElbCert) Delete() error { + _, err := self.region.lbDelete("elb/certificates/" + self.GetId()) + return err +} + +func (self *SElbCert) GetCommonName() string { + return self.Domain +} + +func (self *SElbCert) GetSubjectAlternativeNames() string { + return self.Domain +} + +func (self *SElbCert) GetFingerprint() string { + _fp := sha1.Sum([]byte(self.Certificate)) + fp := fmt.Sprintf("sha1:% x", _fp) + return strings.Replace(fp, " ", ":", -1) +} + +func (self *SElbCert) GetExpireTime() time.Time { + return self.ExpireTime +} + +func (self *SRegion) GetLoadBalancerCertificate(id string) (*SElbCert, error) { + resp, err := self.lbGet("elb/certificates/" + id) + if err != nil { + return nil, err + } + ret := &SElbCert{region: self} + return ret, resp.Unmarshal(ret) +} + +// https://support.huaweicloud.com/api-elb/elb_qy_zs_0001.html +func (self *SRegion) CreateLoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (*SElbCert, error) { + params := map[string]interface{}{ + "name": cert.Name, + "private_key": cert.PrivateKey, + "certificate": cert.Certificate, + } + resp, err := self.lbCreate("elb/certificates", params) + if err != nil { + return nil, err + } + ret := &SElbCert{region: self} + return ret, resp.Unmarshal(ret) +} + +func (self *SRegion) GetLoadBalancerCertificates() ([]SElbCert, error) { + resp, err := self.lbList("elb/certificates", url.Values{}) + if err != nil { + return nil, err + } + ret := []SElbCert{} + return ret, resp.Unmarshal(&ret, "certificates") +} diff --git a/pkg/multicloud/huawei/loadbalancer_healthcheck.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_healthcheck.go similarity index 100% rename from pkg/multicloud/huawei/loadbalancer_healthcheck.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_healthcheck.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_listener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_listener.go new file mode 100644 index 0000000000..c0279efe90 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_listener.go @@ -0,0 +1,663 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "fmt" + "net/url" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type InsertHeaders struct { + XForwardedELBIP bool `json:"X-Forwarded-ELB-IP"` +} + +type Loadbalancer struct { + ID string `json:"id"` +} + +type SElbListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + HuaweiTags + lb *SLoadbalancer + acl *SElbACL + backendgroup *SElbBackendGroup + + ProtocolPort int `json:"protocol_port"` + Protocol string `json:"protocol"` + Description string `json:"description"` + AdminStateUp bool `json:"admin_state_up"` + Http2Enable bool `json:"http2_enable"` + Loadbalancers []Loadbalancer `json:"loadbalancers"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + ConnectionLimit int `json:"connection_limit"` + DefaultPoolID string `json:"default_pool_id"` + ID string `json:"id"` + Name string `json:"name"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + InsertHeaders InsertHeaders `json:"insert_headers"` + DefaultTlsContainerRef string `json:"default_tls_container_ref"` +} + +func (self *SElbListener) GetId() string { + return self.ID +} + +func (self *SElbListener) GetName() string { + return self.Name +} + +func (self *SElbListener) GetGlobalId() string { + return self.GetId() +} + +func (self *SElbListener) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbListener) Refresh() error { + ilistener, err := self.lb.GetILoadBalancerListenerById(self.GetId()) + if err != nil { + return err + } + + listener := ilistener.(*SElbListener) + listener.lb = self.lb + err = jsonutils.Update(self, listener) + if err != nil { + return err + } + + return nil +} + +func (self *SElbListener) IsEmulated() bool { + return false +} + +func (self *SElbListener) GetProjectId() string { + return self.ProjectID +} + +func (self *SElbListener) GetListenerType() string { + switch self.Protocol { + case "TCP": + return api.LB_LISTENER_TYPE_TCP + case "UDP": + return api.LB_LISTENER_TYPE_UDP + case "HTTP": + return api.LB_LISTENER_TYPE_HTTP + case "TERMINATED_HTTPS": + return api.LB_LISTENER_TYPE_HTTPS + case "HTTPS": + return api.LB_LISTENER_TYPE_HTTPS + default: + return "" + } +} + +func (self *SElbListener) GetListenerPort() int { + return self.ProtocolPort +} + +func (self *SElbListener) GetBackendGroup() (*SElbBackendGroup, error) { + if self.backendgroup == nil { + lbbgId := self.GetBackendGroupId() + if len(lbbgId) > 0 { + lbbg, err := self.lb.GetILoadBalancerBackendGroupById(lbbgId) + if err != nil { + return nil, err + } + + self.backendgroup = lbbg.(*SElbBackendGroup) + } + } + + return self.backendgroup, nil +} + +func (self *SElbListener) GetScheduler() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetScheduler %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + return lbbg.GetScheduler() +} + +func (self *SElbListener) GetAcl() (*SElbACL, error) { + if self.acl != nil { + return self.acl, nil + } + + acls, err := self.lb.region.GetLoadBalancerAcls(self.GetId()) + if err != nil { + return nil, err + } + + if len(acls) == 0 { + return nil, nil + } else { + self.acl = &acls[0] + return &acls[0], nil + } +} + +func (self *SElbListener) GetAclStatus() string { + acl, err := self.GetAcl() + if err != nil { + log.Debugf("GetAclStatus %s", err) + return "" + } + + if acl != nil && acl.EnableWhitelist { + return api.LB_BOOL_ON + } + + return api.LB_BOOL_OFF +} + +func (self *SElbListener) GetAclType() string { + return api.LB_ACL_TYPE_WHITE +} + +func (self *SElbListener) GetAclId() string { + acl, err := self.GetAcl() + if err != nil { + log.Debugf("GetAclStatus %s", err) + return "" + } + + if acl == nil { + return "" + } + + return acl.GetId() +} + +func (self *SElbListener) GetEgressMbps() int { + return 0 +} + +func (self *SElbListener) GetHealthCheck() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheck %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheck %s", err.Error()) + } + + if health != nil { + return api.LB_BOOL_ON + } else { + return api.LB_BOOL_OFF + } +} + +func (self *SElbListener) GetHealthCheckType() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckType %s", err.Error()) + } + + if health != nil { + return health.HealthCheckType + } + + return "" +} + +func (self *SElbListener) GetHealthCheckTimeout() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckTimeout %s", err.Error()) + } + + if health != nil { + return health.HealthCheckTimeout + } + + return 0 +} + +func (self *SElbListener) GetHealthCheckInterval() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckInterval %s", err.Error()) + } + + if health != nil { + return health.HealthCheckInterval + } + + return 0 +} + +func (self *SElbListener) GetHealthCheckRise() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckRise %s", err.Error()) + } + + if health != nil { + return health.HealthCheckRise + } else { + return 0 + } +} + +func (self *SElbListener) GetHealthCheckFail() int { + return 0 +} + +func (self *SElbListener) GetHealthCheckReq() string { + return "" +} + +func (self *SElbListener) GetHealthCheckExp() string { + return "" +} + +func (self *SElbListener) GetBackendGroupId() string { + return self.DefaultPoolID +} + +func (self *SElbListener) GetBackendServerPort() int { + return 0 +} + +func (self *SElbListener) GetHealthCheckDomain() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckDomain %s", err.Error()) + } + + if health != nil { + return health.HealthCheckDomain + } + + return "" +} + +func (self *SElbListener) GetHealthCheckURI() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + health, err := lbbg.GetHealthCheck() + if err != nil { + log.Errorf("ElbListener GetHealthCheckURI %s", err.Error()) + } + + if health != nil { + return health.HealthCheckURI + } + + return "" +} + +func (self *SElbListener) GetHealthCheckCode() string { + return "" +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html +func (self *SElbListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + l7policy, err := self.lb.region.CreateLoadBalancerPolicy(self.GetId(), rule) + if err != nil { + return nil, err + } + + l7policy.region = self.lb.region + l7policy.lb = self.lb + l7policy.listener = self + return l7policy, nil +} + +func (self *SElbListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + ret := &SElbListenerPolicy{region: self.lb.region, lb: self.lb, listener: self} + resp, err := self.lb.region.lbGet("elb/l7policies/" + ruleId) + if err != nil { + return nil, err + } + return ret, resp.Unmarshal(ret, "l7policy") +} + +func (self *SElbListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + ret, err := self.lb.region.GetLoadBalancerPolicies(self.GetId()) + if err != nil { + return nil, err + } + + iret := []cloudprovider.ICloudLoadbalancerListenerRule{} + for i := range ret { + rule := ret[i] + rule.listener = self + rule.lb = self.lb + rule.region = self.lb.region + iret = append(iret, &rule) + } + + return iret, nil +} + +func (self *SElbListener) GetStickySession() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySession %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySession %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySession + } + + return "" +} + +func (self *SElbListener) GetStickySessionType() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySessionType %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySessionType %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySessionType + } + + return "" +} + +func (self *SElbListener) GetStickySessionCookie() string { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) + } + + if lbbg == nil { + return "" + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookie %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySessionCookie + } + + return "" +} + +func (self *SElbListener) GetStickySessionCookieTimeout() int { + lbbg, err := self.GetBackendGroup() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) + } + + if lbbg == nil { + return 0 + } + + stickySession, err := lbbg.GetStickySession() + if err != nil { + log.Errorf("ElbListener GetStickySessionCookieTimeout %s", err.Error()) + } + + if stickySession != nil { + return stickySession.StickySessionCookieTimeout + } + + return 0 +} + +func (self *SElbListener) XForwardedForEnabled() bool { + return self.InsertHeaders.XForwardedELBIP +} + +func (self *SElbListener) GzipEnabled() bool { + return false +} + +func (self *SElbListener) GetCertificateId() string { + return self.DefaultTlsContainerRef +} + +func (self *SElbListener) GetTLSCipherPolicy() string { + return "" +} + +func (self *SElbListener) HTTP2Enabled() bool { + return self.Http2Enable +} + +func (self *SElbListener) Start() error { + return nil +} + +func (self *SElbListener) Stop() error { + return cloudprovider.ErrNotSupported +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0096561544.html +/* +default_pool_id有如下限制: +不能更新为其他监听器的default_pool。 +不能更新为其他监听器的关联的转发策略所使用的pool。 +default_pool_id对应的后端云服务器组的protocol和监听器的protocol有如下关系: +监听器的protocol为TCP时,后端云服务器组的protocol必须为TCP。 +监听器的protocol为UDP时,后端云服务器组的protocol必须为UDP。 +监听器的protocol为HTTP或TERMINATED_HTTPS时,后端云服务器组的protocol必须为HTTP。 +*/ +func (self *SElbListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { + return self.lb.region.UpdateLoadBalancerListener(self.GetId(), listener) +} + +func (self *SElbListener) Delete(ctx context.Context) error { + _, err := self.lb.region.lbDelete("elb/listeners/" + self.GetId()) + return err +} + +func (self *SRegion) UpdateLoadBalancerListener(listenerId string, listener *cloudprovider.SLoadbalancerListener) error { + params := map[string]interface{}{ + "name": listener.Name, + "description": listener.Description, + "http2_enable": listener.EnableHTTP2, + "default_pool_id": jsonutils.JSONNull, + } + if len(listener.BackendGroupID) > 0 { + params["default_pool_id"] = listener.BackendGroupID + } + + if listener.ListenerType == api.LB_LISTENER_TYPE_HTTPS { + params["default_tls_container_ref"] = listener.CertificateID + } + + if listener.XForwardedFor { + params["insert_headers"] = map[string]interface{}{ + "X-Forwarded-ELB-IP": listener.XForwardedFor, + } + } + _, err := self.lbUpdate("elb/listeners/"+listenerId, map[string]interface{}{"listener": params}) + return err +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295315.html +func (self *SRegion) GetLoadBalancerPolicies(listenerId string) ([]SElbListenerPolicy, error) { + query := url.Values{} + if len(listenerId) > 0 { + query.Set("listener_id", listenerId) + } + + resp, err := self.lbList("elb/l7policies", query) + if err != nil { + return nil, err + } + + ret := []SElbListenerPolicy{} + return ret, resp.Unmarshal(&ret, "l7policies") +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0116649234.html +func (self *SRegion) GetLoadBalancerPolicyRules(policyId string) ([]SElbListenerPolicyRule, error) { + resp, err := self.lbList(fmt.Sprintf("elb/l7policies/%s/rules", policyId), url.Values{}) + if err != nil { + return nil, err + } + + ret := []SElbListenerPolicyRule{} + return ret, resp.Unmarshal(&ret, "rules") +} + +// https://support.huaweicloud.com/api-elb/zh-cn_topic_0136295317.html +func (self *SRegion) CreateLoadBalancerPolicy(listenerID string, rule *cloudprovider.SLoadbalancerListenerRule) (*SElbListenerPolicy, error) { + ret := &SElbListenerPolicy{} + params := map[string]interface{}{ + "name": rule.Name, + "listener_id": listenerID, + "action": "REDIRECT_TO_POOL", + "redirect_pool_id": rule.BackendGroupID, + } + resp, err := self.lbCreate("elb/l7policies", map[string]interface{}{"l7policy": params}) + if err != nil { + return nil, err + } + err = resp.Unmarshal(ret, "l7policy") + if err != nil { + return nil, err + } + if len(rule.Domain) > 0 { + params := map[string]interface{}{ + "type": "HOST_NAME", + "value": rule.Domain, + "compare_type": "EQUAL_TO", + } + _, err := self.lbCreate(fmt.Sprintf("elb/l7policies/%s/rules", ret.GetId()), map[string]interface{}{"rule": params}) + if err != nil { + return ret, err + } + } + + if len(rule.Path) > 0 { + params := map[string]interface{}{ + "type": "PATH", + "value": rule.Path, + "compare_type": "EQUAL_TO", + } + _, err := self.lbCreate(fmt.Sprintf("elb/l7policies/%s/rules", ret.GetId()), map[string]interface{}{"rule": params}) + if err != nil { + return ret, err + } + } + + return ret, nil +} + +func (self *SElbListener) GetClientIdleTimeout() int { + return 0 +} + +func (self *SElbListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_listener_rule.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_listener_rule.go new file mode 100644 index 0000000000..89394efe26 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/loadbalancer_listener_rule.go @@ -0,0 +1,166 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElbListenerPolicy struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + HuaweiTags + region *SRegion + lb *SLoadbalancer + listener *SElbListener + + RedirectPoolID string `json:"redirect_pool_id"` + RedirectListenerID *string `json:"redirect_listener_id"` + Description string `json:"description"` + AdminStateUp bool `json:"admin_state_up"` + Rules []Rule `json:"rules"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + ListenerID string `json:"listener_id"` + RedirectURL *string `json:"redirect_url"` + ProvisioningStatus string `json:"provisioning_status"` + Action string `json:"action"` + Position int64 `json:"position"` + ID string `json:"id"` + Name string `json:"name"` +} + +type Rule struct { + ID string `json:"id"` +} + +type SElbListenerPolicyRule struct { + region *SRegion + policy *SElbListenerPolicy + + CompareType string `json:"compare_type"` + ProvisioningStatus string `json:"provisioning_status"` + AdminStateUp bool `json:"admin_state_up"` + TenantID string `json:"tenant_id"` + ProjectID string `json:"project_id"` + Invert bool `json:"invert"` + Value string `json:"value"` + Key interface{} `json:"key"` + Type string `json:"type"` + ID string `json:"id"` +} + +func (self *SElbListenerPolicy) GetId() string { + return self.ID +} + +func (self *SElbListenerPolicy) GetName() string { + return self.Name +} + +func (self *SElbListenerPolicy) GetGlobalId() string { + return self.GetId() +} + +// 负载均衡没有启用禁用操作 +func (self *SElbListenerPolicy) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SElbListenerPolicy) Refresh() error { + resp, err := self.lb.region.lbGet("") + if err != nil { + return err + } + return resp.Unmarshal(self, "l7policy") +} + +func (self *SElbListenerPolicy) IsDefault() bool { + return false +} + +func (self *SElbListenerPolicy) IsEmulated() bool { + return false +} + +func (self *SElbListenerPolicy) GetProjectId() string { + return "" +} + +func (self *SElbListenerPolicy) GetRules() ([]SElbListenerPolicyRule, error) { + ret, err := self.region.GetLoadBalancerPolicyRules(self.GetId()) + if err != nil { + return nil, err + } + + for i := range ret { + ret[i].region = self.lb.region + ret[i].policy = self + } + + return ret, nil +} + +func (self *SElbListenerPolicy) GetDomain() string { + rules, err := self.GetRules() + if err != nil { + log.Errorf("loadbalancer rule GetDomain %s", err) + } + + for i := range rules { + if rules[i].Type == "HOST_NAME" { + return rules[i].Value + } + } + + return "" +} + +func (self *SElbListenerPolicy) GetCondition() string { + return "" +} + +func (self *SElbListenerPolicy) GetPath() string { + rules, err := self.GetRules() + if err != nil { + log.Errorf("loadbalancer rule GetPath %s", err) + } + + for i := range rules { + if rules[i].Type == "PATH" { + return rules[i].Value + } + } + + return "" +} + +func (self *SElbListenerPolicy) GetBackendGroupId() string { + return self.RedirectPoolID +} + +func (self *SElbListenerPolicy) Delete(ctx context.Context) error { + return self.region.DeleteLoadBalancerPolicy(self.GetId()) +} + +func (self *SRegion) DeleteLoadBalancerPolicy(policyId string) error { + _, err := self.lbDelete("elb/l7policies/" + policyId) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go new file mode 100644 index 0000000000..05387b26c8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool.go @@ -0,0 +1,393 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SModelartsPool struct { + region *SRegion + multicloud.SResourceBase + + Metadata SModelartsPoolMetadata `json:"metadata"` + Spec SModelartsPoolSpec `json:"spec"` + Status SModelartsPoolStatus `json:"status"` + InstanceType string + WorkType string +} + +type SModelartsPoolMetadata struct { + Name string `json:"name"` + CreationTimestamp string `json:"creationTimestamp"` + Labels SModelartsPoolMeatadataLabel + Annotations SModelartsPoolMetadataAnnotations `json:"annotations"` +} + +type SModelartsPoolMeatadataLabel struct { + WorkspaceId string `json:"os.modelarts/workspace.id"` + Name string `json:"os.modelarts/name"` + ResourceId string `json:"os.modelarts/resource.id"` +} + +type SModelartsPoolMetadataAnnotations struct { + Describe string `json:"os.modelarts/description"` + BillingType string `json:"os.modelarts/billing.mode"` + BillingCycle string `json:"os.modelarts/period.num"` + BillingPeriodType string `json:"os.modelarts/period.type"` + BillingMod string `json:"os.modelarts/charging.mode"` + BillingRenew string `json:"os.modelarts/auto.renew"` + OrderId string `json:"os.modelarts/order.id"` +} + +type SModelartsPoolSpec struct { + Type string `json:"type"` + Scope []string `json:"scope"` + Resource []SModelartsPoolResource `json:"resources"` +} + +type SModelartsPoolResource struct { + Flavor string `json:"flavor"` + Count int `json:"count"` + cloudprovider.Azs +} + +type SNodeStatus struct { + Creating []SNodeFlavor `json:"creating"` + Available []SNodeFlavor `json:"available"` + Abnormal []SNodeFlavor `json:"abnormal"` + Deleting []SNodeFlavor `json:"deleting"` +} +type SNodeFlavor struct { + Flavor string `json:"flavor"` + Count int `json:"count"` +} + +type SModelartsPoolStatus struct { + Phase string `json:"phase"` + Message string `json:"message"` + Resource SNodeStatus `json:"resources"` +} + +type SModelartsPoolNetwork struct { + Metadata SModelartsPoolNetworkMetadata `json:"metadata"` +} + +type SModelartsPoolNetworkMetadata struct { + Name string `json:"name"` + CreationTimestamp string `json:"creationTimestamp"` +} + +func (self *SRegion) GetIModelartsPools() ([]cloudprovider.ICloudModelartsPool, error) { + pools := make([]SModelartsPool, 0) + resObj, err := self.client.modelartsPoolList("pools", nil) + if err != nil { + return nil, errors.Wrap(err, "region.GetPools") + } + err = resObj.Unmarshal(&pools, "items") + if err != nil { + return nil, errors.Wrap(err, "resObj unmarshal") + } + res := make([]cloudprovider.ICloudModelartsPool, len(pools)) + for i := 0; i < len(pools); i++ { + pools[i].region = self + res[i] = &pools[i] + } + + return res, nil +} + +func (self *SRegion) CreateIModelartsPool(args *cloudprovider.ModelartsPoolCreateOption) (cloudprovider.ICloudModelartsPool, error) { + netObj, err := self.client.modelartsPoolNetworkList("network", nil) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.GetPools") + } + netRes := make([]SModelartsPoolNetwork, 0) + netObj.Unmarshal(&netRes, "items") + netId := "" + if len(netRes) != 0 { + netId = netRes[0].Metadata.Name + } else { + createNetObj, err := self.client.CreatePoolNetworks() + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.CreatePoolNetworks") + } + netId, _ = createNetObj.GetString("metadata", "name") + } + + scopeArr := strings.Split(args.WorkType, ",") + params := map[string]interface{}{ + "apiVersion": "v2", + "kind": "Pool", + "metadata": map[string]interface{}{ + "labels": map[string]interface{}{ + "os.modelarts/name": args.Name, + "os.modelarts/workspace.id": "0", + }, + }, + "spec": map[string]interface{}{ + "type": "Dedicate", + "scope": scopeArr, + "network": map[string]interface{}{ + "name": netId, + }, + + "resources": []map[string]interface{}{ + { + "flavor": args.InstanceType, + "count": args.NodeCount, + }, + }, + }, + } + obj, err := self.client.modelartsPoolCreate("pools", params) + if err != nil { + return nil, errors.Wrap(err, "SHuaweiClient.CreatePools") + } + pool := &SModelartsPool{} + obj.Unmarshal(&pool) + res := []cloudprovider.ICloudModelartsPool{} + for i := 0; i < 1; i++ { + pool.region = self + res = append(res, pool) + } + + return res[0], nil +} + +func (self *SRegion) DeletePool(poolName string) (jsonutils.JSONObject, error) { + return self.client.modelartsPoolDelete("pools", poolName, nil) +} + +func (self *SRegion) GetIModelartsPoolById(poolId string) (cloudprovider.ICloudModelartsPool, error) { + obj, err := self.client.modelartsPoolById(poolId) + if err != nil { + if strings.Contains(err.Error(), "not found") { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "") + } + return nil, errors.Wrap(err, "region.modelartsPoolByName") + } + pool := &SModelartsPool{} + obj.Unmarshal(&pool) + res := []cloudprovider.ICloudModelartsPool{} + for i := 0; i < 1; i++ { + pool.region = self + res = append(res, pool) + } + return res[0], nil +} + +func (self *SRegion) MonitorPool(poolId string) (*SModelartsMetrics, error) { + resObj, err := self.client.modelartsPoolMonitor(poolId, nil) + if err != nil { + return nil, errors.Wrapf(err, "send request error") + } + metrics := SModelartsMetrics{} + err = resObj.Unmarshal(&metrics) + if err != nil { + return nil, errors.Wrapf(err, "unmarsh error") + } + return &metrics, nil +} + +type SModelartsMetrics struct { + Metrics []SModelartsMetric `json:"metrics"` +} + +type SModelartsMetric struct { + Metric SModelartsMetricInfo `json:"metric"` + Datapoints []SModelartsDataPoints `json:"dataPoints"` +} + +type SModelartsMetricInfo struct { + Dimensions []SModelartsDimensions `json:"dimensions"` + MetricName string + Namespace string +} + +type SModelartsDimensions struct { + Name string + Value string +} + +type SModelartsDataPoints struct { + Timestamp int64 + Unit string + Statistics []ModelartsStatistics +} + +type ModelartsStatistics struct { + Statistic string + Value float64 +} + +func (self *SHuaweiClient) GetPoolNetworks(poolName string) (jsonutils.JSONObject, error) { + return self.modelartsPoolNetworkList(poolName, nil) +} + +func (self *SHuaweiClient) CreatePoolNetworks() (jsonutils.JSONObject, error) { + params := map[string]interface{}{ + "apiVersion": "v1", + "kind": "Network", + "metadata": map[string]interface{}{ + "labels": map[string]interface{}{ + "os.modelarts/name": "test", + "os.modelarts/workspace.id": "0", + }, + }, + "spec": map[string]interface{}{ + "cidr": "192.168.20.0/24", + }, + } + return self.modelartsPoolNetworkCreate(params) +} + +func (self *SModelartsPool) GetCreatedAt() time.Time { + ret, _ := time.Parse("2006-01-02T15:04:05CST", self.Metadata.CreationTimestamp) + if !ret.IsZero() { + ret = ret.Add(time.Hour * 8) + } + return ret +} + +func (self *SModelartsPool) GetGlobalId() string { + return self.Metadata.Name +} + +func (self *SModelartsPool) GetId() string { + return self.Metadata.Name +} + +func (self *SModelartsPool) GetName() string { + return self.Metadata.Labels.Name +} + +func (self *SModelartsPool) GetStatus() string { + res := strings.ToLower(self.Status.Phase) + switch { + case res == compute.MODELARTS_POOL_STATUS_RUNNING && len(self.Status.Resource.Creating) != 0: + res = compute.MODELARTS_POOL_STATUS_CREATING + } + return res +} + +func (self *SModelartsPool) GetSysTags() map[string]string { + return nil +} + +func (self *SModelartsPool) GetTags() (map[string]string, error) { + return nil, nil +} + +func (self *SModelartsPool) IsEmulated() bool { + return false +} + +func (self *SModelartsPool) GetBillingType() string { + if self.Metadata.Annotations.BillingType == "1" { + return billing_api.BILLING_TYPE_PREPAID + } else { + return billing_api.BILLING_TYPE_POSTPAID + } +} + +// 获取资源归属项目Id +func (self *SModelartsPool) GetProjectId() string { + return self.Metadata.Name +} + +func (self *SModelartsPool) GetExpiredAt() time.Time { + ret, _ := time.Parse("2006-01-02T15:04:05CST", self.Metadata.CreationTimestamp) + if !ret.IsZero() { + ret = ret.Add(time.Hour * 8) + } + return ret +} + +func (self *SModelartsPool) IsAutoRenew() bool { + return false +} + +func (self *SModelartsPool) Renew(bc billing.SBillingCycle) error { + return nil +} + +func (self *SModelartsPool) SetAutoRenew(bc billing.SBillingCycle) error { + return nil +} + +func (self *SModelartsPool) Refresh() error { + pool, err := self.region.client.modelartsPoolById(self.GetId()) + if err != nil { + return errors.Wrapf(err, "GetModelartsPool(%s)", self.GetId()) + } + return jsonutils.Update(self, pool) +} + +func (self *SModelartsPool) SetTags(tags map[string]string, replace bool) error { + return nil +} + +func (self *SModelartsPool) Delete() error { + _, err := self.region.DeletePool(self.GetId()) + if err != nil { + return err + } + return nil +} + +func (self *SModelartsPool) GetInstanceType() string { + return self.Spec.Resource[0].Flavor + +} + +func (self *SModelartsPool) GetWorkType() string { + return strings.Join(self.Spec.Scope, ",") +} + +func (self *SModelartsPool) GetNodeCount() int { + if len(self.Spec.Resource) < 1 { + return 0 + } + return self.Spec.Resource[0].Count +} + +func (self *SModelartsPool) ChangeConfig(opts *cloudprovider.ModelartsPoolChangeConfigOptions) error { + //{"spec":{"resources":[{"flavor":"modelarts.kat1.8xlarge","count":2}]}} + res := []map[string]interface{}{} + for _, re := range self.Spec.Resource { + res = append(res, map[string]interface{}{ + "flavor": re.Flavor, + "count": opts.NodeCount, + }) + } + params := map[string]interface{}{ + "spec": map[string]interface{}{ + "resources": res, + }, + } + _, err := self.region.client.modelartsPoolUpdate(self.Metadata.Name, params) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool_sku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool_sku.go new file mode 100644 index 0000000000..5ab9a99bd2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/modelarts_pool_sku.go @@ -0,0 +1,130 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "strconv" + "time" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SModelartsPoolSku struct { + multicloud.SResourceBase + HuaweiTags + region *SRegion + + Kind string `json:"kind"` + Spec SModelartsResourceflavorsSpec `json:"spec"` + Status SModelartsResourceflavorsStatus `json:"status"` +} + +type SModelartsResourceflavorsSpec struct { + BillingCode string `json:"billingCode"` + BillingModes []int `json:"billingMods"` + Cpu int `json:"cpu"` + CpuArch string `json:"cpuArch"` + Gpu SModelartsResourceflavorsGpuSpec `json:"gpu"` + Npu SModelartsResourceflavorsGpuSpec `json:"npu"` + Memory string `json:"memory"` + Type string `json:"type"` +} + +type SModelartsResourceflavorsGpuSpec struct { + Size int `json:"size"` + Type string `json:"type"` +} + +type SModelartsResourceflavorsStatus struct { + Phase map[string]interface{} `json:"phase"` +} + +func (self *SRegion) GetIModelartsPoolSku() ([]cloudprovider.ICloudModelartsPoolSku, error) { + params := make(map[string]interface{}) + resourceflavors := make([]SModelartsPoolSku, 0) + obj, err := self.client.modelartsResourceflavors("resourceflavors", params) + if err != nil { + return nil, errors.Wrap(err, "region.modelartsResourceflavors") + } + obj.Unmarshal(&resourceflavors, "items") + res := make([]cloudprovider.ICloudModelartsPoolSku, len(resourceflavors)) + for i := 0; i < len(resourceflavors); i++ { + res[i] = &resourceflavors[i] + } + return res, nil +} + +func (self *SModelartsPoolSku) GetCreatedAt() time.Time { + createdAt, _ := time.Parse("2006-01-02T15:04:05CST", time.Now().Format("2006-01-02T15:04:05CST")) + return createdAt +} + +func (self *SModelartsPoolSku) GetGlobalId() string { + return self.Spec.BillingCode +} + +func (self *SModelartsPoolSku) GetId() string { + return self.Spec.BillingCode +} + +func (self *SModelartsPoolSku) GetName() string { + return self.Spec.BillingCode +} + +func (self *SModelartsPoolSku) GetCpuArch() string { + return self.Spec.CpuArch +} + +func (self *SModelartsPoolSku) GetCpuCoreCount() int { + return self.Spec.Cpu +} + +func (self *SModelartsPoolSku) GetMemorySizeMB() int { + size, _ := strconv.Atoi(self.Spec.Memory[:len(self.Spec.Memory)-2]) + return size * 1024 +} + +func (self *SModelartsPoolSku) GetStatus() string { + for _, v := range self.Status.Phase { + if v == "normal" { + return compute.MODELARTS_POOL_SKU_AVAILABLE + } + } + return compute.MODELARTS_POOL_SKU_SOLDOUT +} + +func (self *SModelartsPoolSku) GetGpuSize() int { + return self.Spec.Gpu.Size +} + +func (self *SModelartsPoolSku) GetGpuType() string { + return self.Spec.Gpu.Type +} + +func (self *SModelartsPoolSku) GetNpuSize() int { + return self.Spec.Npu.Size +} + +func (self *SModelartsPoolSku) GetNpuType() string { + return self.Spec.Npu.Type +} + +func (self *SModelartsPoolSku) GetPoolType() string { + return self.Spec.Type +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/monitor.go new file mode 100644 index 0000000000..c3e8adfd5c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/monitor.go @@ -0,0 +1,563 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" +) + +func (r *SRegion) GetMetrics() ([]modules.SMetricMeta, error) { + return r.ecsClient.CloudEye.ListMetrics() +} + +func (r *SRegion) GetMetricsData(metrics []modules.SMetricMeta, since time.Time, until time.Time) ([]modules.SMetricData, error) { + return r.ecsClient.CloudEye.GetMetricsData(metrics, since, until) +} + +type MetricData struct { + Namespace string + MetricName string + Dimensions []struct { + Name string + Value string + } + Datapoints []struct { + Average float64 + Timestamp int64 + } + Unit string +} + +func (self *SHuaweiClient) getServerMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + params := map[string]interface{}{ + "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), + "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), + "period": "1", + "filter": "average", + } + metrics := []interface{}{} + namespace, dimesionName, metricNames := "SYS.ECS", "instance_id", []string{ + "cpu_util", + "network_incoming_bytes_aggregate_rate", + "network_outgoing_bytes_aggregate_rate", + "disk_read_bytes_rate", + "disk_write_bytes_rate", + "disk_read_requests_rate", + "disk_write_requests_rate", + } + for _, metricName := range metricNames { + metrics = append(metrics, map[string]interface{}{ + "namespace": namespace, + "metric_name": metricName, + "dimensions": []map[string]string{ + { + "name": dimesionName, + "value": opts.ResourceId, + }, + }, + }) + } + params["metrics"] = metrics + resp, err := self.monitorPost("batch-query-metric-data", params) + if err != nil { + return nil, err + } + metricData := []MetricData{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].MetricName { + case "cpu_util": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_CPU_USAGE + case "network_incoming_bytes_aggregate_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_RX + tags = map[string]string{"net_type": "internet"} + case "network_outgoing_bytes_aggregate_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_NET_BPS_TX + tags = map[string]string{"net_type": "internet"} + case "disk_read_bytes_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS + case "disk_write_bytes_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS + case "disk_read_requests_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS + case "disk_write_requests_rate": + ret.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + metricValue := cloudprovider.MetricValue{ + Value: value.Average, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHuaweiClient) getRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + params := map[string]interface{}{ + "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), + "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), + "period": "1", + "filter": "average", + } + metrics := []interface{}{} + namespace, dimesionName, metricNames := "SYS.DCS", "dcs_instance_id", []string{ + "cpu_usage", + "memory_usage", + "instantaneous_input_kbps", + "instantaneous_output_kbps", + "connected_clients", + "instantaneous_ops", + "keys", + "expires", + "used_memory_dataset", + } + for _, metricName := range metricNames { + metrics = append(metrics, map[string]interface{}{ + "namespace": namespace, + "metric_name": metricName, + "dimensions": []map[string]string{ + { + "name": dimesionName, + "value": opts.ResourceId, + }, + }, + }) + } + params["metrics"] = metrics + resp, err := self.monitorPost("batch-query-metric-data", params) + if err != nil { + return nil, err + } + metricData := []MetricData{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].MetricName { + case "cpu_usage": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE + case "memory_usage": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE + case "instantaneous_input_kbps": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX + case "instantaneous_output_kbps": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX + case "connected_clients": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_USED_CONN + case "instantaneous_ops": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_OPT_SES + case "keys": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS + case "expires": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS + case "used_memory_dataset": + ret.MetricType = cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + metricValue := cloudprovider.MetricValue{ + Value: value.Average, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHuaweiClient) getRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + params := map[string]interface{}{ + "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), + "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), + "period": "1", + "filter": "average", + } + metrics := []interface{}{} + namespace, dimesionName, metricNames := "SYS.RDS", "rds_cluster_id", []string{ + "rds001_cpu_util", + "rds002_mem_util", + "rds004_bytes_in", + "rds004_bytes_in", + "rds005_bytes_out", + "rds039_disk_util", + "rds049_disk_read_throughput", + "rds050_disk_write_throughput", + "rds006_conn_count", + "rds008_qps", + "rds009_tps", + "rds013_innodb_reads", + "rds014_innodb_writes", + } + switch opts.Engine { + case api.DBINSTANCE_TYPE_POSTGRESQL: + dimesionName = "postgresql_cluster_id" + case api.DBINSTANCE_TYPE_SQLSERVER: + dimesionName = "rds_cluster_sqlserver_id" + } + + for _, metricName := range metricNames { + metrics = append(metrics, map[string]interface{}{ + "namespace": namespace, + "metric_name": metricName, + "dimensions": []map[string]string{ + { + "name": dimesionName, + "value": opts.ResourceId, + }, + }, + }) + } + params["metrics"] = metrics + resp, err := self.monitorPost("batch-query-metric-data", params) + if err != nil { + return nil, err + } + metricData := []MetricData{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].MetricName { + case "rds001_cpu_util": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_CPU_USAGE + case "rds002_mem_util": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_MEM_USAGE + case "rds004_bytes_in": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX + case "rds005_bytes_out": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX + case "rds039_disk_util": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_USAGE + case "rds049_disk_read_throughput": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_READ_BPS + case "rds050_disk_write_throughput": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_DISK_WRITE_BPS + case "rds006_conn_count": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_CONN_COUNT + case "rds008_qps": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_QPS + case "rds009_tps": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_TPS + case "rds013_innodb_reads": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_INNODB_READ_BPS + case "rds014_innodb_writes": + ret.MetricType = cloudprovider.RDS_METRIC_TYPE_INNODB_WRITE_BPS + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + metricValue := cloudprovider.MetricValue{ + Value: value.Average, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHuaweiClient) getBucketMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + params := map[string]interface{}{ + "from": opts.StartTime.UnixMilli(), + "to": opts.EndTime.UnixMilli(), + "period": "1", + "filter": "average", + } + metrics := []interface{}{} + namespace, dimesionName, metricNames := "SYS.OBS", "bucket_name", []string{ + "download_bytes", + "upload_bytes", + "first_byte_latency", + "get_request_count", + "request_count_4xx", + "request_count_5xx", + } + + for _, metricName := range metricNames { + metrics = append(metrics, map[string]interface{}{ + "namespace": namespace, + "metric_name": metricName, + "dimensions": []map[string]string{ + { + "name": dimesionName, + "value": opts.ResourceId, + }, + }, + }) + } + params["metrics"] = metrics + resp, err := self.monitorPost("batch-query-metric-data", params) + if err != nil { + return nil, err + } + metricData := []MetricData{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].MetricName { + case "download_bytes": + ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_TX + case "upload_bytes": + ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_NET_BPS_RX + case "first_byte_latency": + ret.MetricType = cloudprovider.BUCKET_METRIC_TYPE_LATECY + tags = map[string]string{"request": "get"} + case "get_request_count": + ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT + tags = map[string]string{"request": "get"} + case "request_count_4xx": + ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT + tags = map[string]string{"request": "4xx"} + case "request_count_5xx": + ret.MetricType = cloudprovider.BUCKET_METRYC_TYPE_REQ_COUNT + tags = map[string]string{"request": "5xx"} + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + metricValue := cloudprovider.MetricValue{ + Value: value.Average, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHuaweiClient) getLoadbalancerMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + params := map[string]interface{}{ + "from": fmt.Sprintf("%d", opts.StartTime.UnixMilli()), + "to": fmt.Sprintf("%d", opts.EndTime.UnixMilli()), + "period": "1", + "filter": "average", + } + metrics := []interface{}{} + namespace, dimesionName, metricNames := "SYS.ELB", "lb_instance_id", []string{ + "m7_in_Bps", + "m8_out_Bps", + "mc_l7_http_2xx", + "md_l7_http_3xx", + "me_l7_http_4xx", + "mf_l7_http_5xx", + } + + for _, metricName := range metricNames { + metrics = append(metrics, map[string]interface{}{ + "namespace": namespace, + "metric_name": metricName, + "dimensions": []map[string]string{ + { + "name": dimesionName, + "value": opts.ResourceId, + }, + }, + }) + } + params["metrics"] = metrics + resp, err := self.monitorPost("batch-query-metric-data", params) + if err != nil { + return nil, err + } + metricData := []MetricData{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].MetricName { + case "m7_in_Bps": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_NET_BPS_RX + case "m8_out_Bps": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_NET_BPS_TX + case "mc_l7_http_2xx": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT + tags = map[string]string{"request": "2xx"} + case "md_l7_http_3xx": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT + tags = map[string]string{"request": "3xx"} + case "md_l7_http_4xx": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT + tags = map[string]string{"request": "4xx"} + case "md_l7_http_5xx": + ret.MetricType = cloudprovider.LB_METRIC_TYPE_HRSP_COUNT + tags = map[string]string{"request": "5xx"} + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + metricValue := cloudprovider.MetricValue{ + Value: value.Average, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHuaweiClient) getModelartsPoolMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + resp, err := self.modelartsPoolMonitor(opts.ResourceId, nil) + if err != nil { + return nil, err + } + metricData := []SModelartsMetric{} + err = resp.Unmarshal(&metricData, "metrics") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + result := []cloudprovider.MetricValues{} + for i := range metricData { + isMB := false + if metricData[i].Datapoints[0].Unit == "Megabytes" { + isMB = true + metricData[i].Datapoints[0].Unit = "Bytes" + } + ret := cloudprovider.MetricValues{ + Id: opts.ResourceId, + Unit: metricData[i].Datapoints[0].Unit, + Values: []cloudprovider.MetricValue{}, + } + tags := map[string]string{} + switch metricData[i].Metric.MetricName { + case "cpuUsage": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_CPU_USAGE + case "memUsedRate": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_MEM_USAGE + case "gpuUtil": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_GPU_UTIL + case "gpuMemUsage": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_GPU_MEM_USAGE + case "npuUtil": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_NPU_UTIL + case "npuMemUsage": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_NPU_MEM_USAGE + case "diskAvailableCapacity": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_AVAILABLE_CAPACITY + case "diskCapacity": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_CAPACITY + case "diskUsedRate": + ret.MetricType = cloudprovider.MODELARTS_POOL_METRIC_TYPE_DISK_USAGE + default: + log.Warningf("invalid metricName %s for %s %s", metricData[i].Metric.MetricName, opts.ResourceType, opts.ResourceId) + continue + } + for _, value := range metricData[i].Datapoints { + if isMB { + value.Statistics[0].Value *= 1024 + } + if value.Statistics[0].Value == -1 { + value.Statistics[0].Value = 0 + } + metricValue := cloudprovider.MetricValue{ + Value: value.Statistics[0].Value, + Timestamp: time.UnixMilli(value.Timestamp), + Tags: tags, + } + ret.Values = append(ret.Values, metricValue) + } + result = append(result, ret) + } + return result, nil +} + +func (self *SHuaweiClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.getServerMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: + return self.getRedisMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_RDS: + return self.getRdsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_BUCKET: + return self.getBucketMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_LB: + return self.getLoadbalancerMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_MODELARTS_POOL: + return self.getModelartsPoolMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.ResourceType) + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natdtable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natdtable.go new file mode 100644 index 0000000000..6fabc7e407 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natdtable.go @@ -0,0 +1,131 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SNatDEntry struct { + multicloud.SResourceBase + HuaweiTags + gateway *SNatGateway + + ID string `json:"id"` + NatGatewayID string `json:"nat_gateway_id"` + Protocol string `json:"protocol"` + Status string `json:"status"` + ExternalIP string `json:"floating_ip_address"` + ExternalPort int `json:"external_service_port"` + InternalIP string `json:"private_ip"` + InternalPort int `json:"internal_service_port"` + PortID string `json:"port_id"` + AdminStateUp bool `json:"admin_state_up"` +} + +func (nat *SNatDEntry) GetId() string { + return nat.ID +} + +func (nat *SNatDEntry) GetName() string { + // No name so return id + return nat.GetId() +} + +func (nat *SNatDEntry) GetGlobalId() string { + return nat.GetId() +} + +func (nat *SNatDEntry) GetStatus() string { + return NatResouceStatusTransfer(nat.Status) +} + +func (nat *SNatDEntry) GetIpProtocol() string { + return nat.Protocol +} + +func (nat *SNatDEntry) GetExternalIp() string { + return nat.ExternalIP +} + +func (nat *SNatDEntry) GetExternalPort() int { + return nat.ExternalPort +} + +func (nat *SNatDEntry) GetInternalIp() string { + return nat.InternalIP +} + +func (nat *SNatDEntry) GetInternalPort() int { + return nat.InternalPort +} + +func (nat *SNatDEntry) Delete() error { + return nat.gateway.region.DeleteNatDEntry(nat.GetId()) +} + +// getNatSTable return all snat rules of gateway +func (gateway *SNatGateway) getNatDTable() ([]SNatDEntry, error) { + ret, err := gateway.region.GetNatDTable(gateway.GetId()) + if err != nil { + return nil, err + } + for i := range ret { + ret[i].gateway = gateway + } + return ret, nil +} + +func (region *SRegion) GetNatDTable(natGatewayID string) ([]SNatDEntry, error) { + queuies := map[string]string{ + "nat_gateway_id": natGatewayID, + } + dNatSTableEntries := make([]SNatDEntry, 0, 2) + // can't make true that restapi support marker para in Huawei Cloud + err := doListAllWithMarker(region.ecsClient.DNatRules.List, queuies, &dNatSTableEntries) + if err != nil { + return nil, errors.Wrapf(err, `get dnat rule of gateway %q`, natGatewayID) + } + for i := range dNatSTableEntries { + nat := &dNatSTableEntries[i] + if len(nat.InternalIP) == 0 { + port, err := region.GetPort(nat.PortID) + if err != nil { + return nil, errors.Wrapf(err, `get port info for transfer to ip of port_id %q error`, nat.PortID) + } + nat.InternalIP = port.FixedIps[0].IpAddress + } + } + return dNatSTableEntries, nil +} + +func (region *SRegion) DeleteNatDEntry(entryID string) error { + _, err := region.ecsClient.DNatRules.Delete(entryID, nil) + if err != nil { + return errors.Wrapf(err, `delete dnat rule %q failed`, entryID) + } + return nil +} + +func (nat *SNatDEntry) Refresh() error { + new, err := nat.gateway.region.GetNatDEntryByID(nat.ID) + if err != nil { + return err + } + return jsonutils.Update(nat, new) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natgateway.go new file mode 100644 index 0000000000..62a54e8df4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natgateway.go @@ -0,0 +1,353 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SNatGateway struct { + multicloud.SNatGatewayBase + HuaweiTags + region *SRegion + + ID string + Name string + Description string + Spec string + Status string + InternalNetworkId string + CreatedTime string `json:"created_at"` +} + +func (gateway *SNatGateway) GetId() string { + return gateway.ID +} + +func (gateway *SNatGateway) GetName() string { + return gateway.Name +} + +func (gateway *SNatGateway) GetGlobalId() string { + return gateway.GetId() +} + +func (gateway *SNatGateway) GetStatus() string { + return NatResouceStatusTransfer(gateway.Status) +} + +func (self *SNatGateway) Delete() error { + return self.region.DeleteNatGateway(self.ID) +} + +func (self *SNatGateway) Refresh() error { + nat, err := self.region.GetNatGateway(self.ID) + if err != nil { + return errors.Wrapf(err, "GetNatGateway(%s)", self.ID) + } + return jsonutils.Update(self, nat) +} + +func (self *SNatGateway) GetINetworkId() string { + return self.InternalNetworkId +} + +func (gateway *SNatGateway) GetNatSpec() string { + switch gateway.Spec { + case "1": + return api.NAT_SPEC_SMALL + case "2": + return api.NAT_SPEC_MIDDLE + case "3": + return api.NAT_SPEC_LARGE + case "4": + return api.NAT_SPEC_XLARGE + } + return gateway.Spec +} + +func (gateway *SNatGateway) GetDescription() string { + return gateway.Description +} + +func (gateway *SNatGateway) GetBillingType() string { + // Up to 2019.07.17, only support post pay + return billing_api.BILLING_TYPE_POSTPAID +} + +func (gateway *SNatGateway) GetCreatedAt() time.Time { + t, _ := time.Parse("2006-01-02 15:04:05.000000", gateway.CreatedTime) + return t +} + +func (gateway *SNatGateway) GetExpiredAt() time.Time { + // no support for expired time + return time.Time{} +} + +func (gateway *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { + IEips, err := gateway.region.GetIEips() + if err != nil { + return nil, errors.Wrapf(err, `get all Eips of region %q error`, gateway.region.GetId()) + } + dNatTables, err := gateway.GetINatDTable() + if err != nil { + return nil, errors.Wrapf(err, `get all DNatTable of gateway %q error`, gateway.GetId()) + } + sNatTables, err := gateway.GetINatSTable() + if err != nil { + return nil, errors.Wrapf(err, `get all SNatTable of gateway %q error`, gateway.GetId()) + } + + // Get natIPSet of nat rules + natIPSet := make(map[string]struct{}) + for _, snat := range sNatTables { + natIPSet[snat.GetIP()] = struct{}{} + } + for _, dnat := range dNatTables { + natIPSet[dnat.GetExternalIp()] = struct{}{} + } + + // Add Eip whose GetIpAddr() in natIPSet to ret + ret := make([]cloudprovider.ICloudEIP, 0, 2) + for i := range IEips { + if _, ok := natIPSet[IEips[i].GetIpAddr()]; ok { + ret = append(ret, IEips[i]) + } + } + return ret, nil +} + +func (gateway *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { + dNatTable, err := gateway.getNatDTable() + if err != nil { + return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) + } + ret := make([]cloudprovider.ICloudNatDEntry, len(dNatTable)) + for i := range dNatTable { + ret[i] = &dNatTable[i] + } + return ret, nil +} + +func (gateway *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { + sNatTable, err := gateway.getNatSTable() + if err != nil { + return nil, errors.Wrapf(err, `get dnat table of nat gateway %q`, gateway.GetId()) + } + ret := make([]cloudprovider.ICloudNatSEntry, len(sNatTable)) + for i := range sNatTable { + ret[i] = &sNatTable[i] + } + return ret, nil +} + +func (gateway *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { + dnat, err := gateway.region.CreateNatDEntry(rule, gateway.GetId()) + if err != nil { + return nil, err + } + dnat.gateway = gateway + return &dnat, nil +} + +func (gateway *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { + snat, err := gateway.region.CreateNatSEntry(rule, gateway.GetId()) + if err != nil { + return nil, err + } + snat.gateway = gateway + return &snat, nil +} + +func (gateway *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { + dnat, err := gateway.region.GetNatDEntryByID(id) + if err != nil { + return nil, err + } + dnat.gateway = gateway + return &dnat, nil +} + +func (gateway *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { + snat, err := gateway.region.GetNatSEntryByID(id) + if err != nil { + return nil, err + } + snat.gateway = gateway + return &snat, nil +} + +func (region *SRegion) GetNatGateways(vpcID, natGatewayID string) ([]SNatGateway, error) { + queues := make(map[string]string) + if len(natGatewayID) != 0 { + queues["id"] = natGatewayID + } + if len(vpcID) != 0 { + queues["router_id"] = vpcID + } + natGateways := make([]SNatGateway, 0, 2) + err := doListAllWithMarker(region.ecsClient.NatGateways.List, queues, &natGateways) + if err != nil { + return nil, errors.Wrapf(err, "get nat gateways error by natgatewayid") + } + for i := range natGateways { + natGateways[i].region = region + } + return natGateways, nil +} + +func (region *SRegion) CreateNatDEntry(rule cloudprovider.SNatDRule, gatewayID string) (SNatDEntry, error) { + params := make(map[string]interface{}) + params["nat_gateway_id"] = gatewayID + params["private_ip"] = rule.InternalIP + params["internal_service_port"] = rule.InternalPort + params["floating_ip_id"] = rule.ExternalIPID + params["external_service_port"] = rule.ExternalPort + params["protocol"] = rule.Protocol + + packParams := map[string]map[string]interface{}{ + "dnat_rule": params, + } + + ret := SNatDEntry{} + err := DoCreate(region.ecsClient.DNatRules.Create, jsonutils.Marshal(packParams), &ret) + if err != nil { + return SNatDEntry{}, errors.Wrapf(err, `create dnat rule of nat gateway %q failed`, gatewayID) + } + return ret, nil +} + +func (region *SRegion) CreateNatSEntry(rule cloudprovider.SNatSRule, gatewayID string) (SNatSEntry, error) { + params := make(map[string]interface{}) + params["nat_gateway_id"] = gatewayID + if len(rule.NetworkID) != 0 { + params["network_id"] = rule.NetworkID + } + if len(rule.SourceCIDR) != 0 { + params["cidr"] = rule.SourceCIDR + } + params["floating_ip_id"] = rule.ExternalIPID + + packParams := map[string]map[string]interface{}{ + "snat_rule": params, + } + + ret := SNatSEntry{} + err := DoCreate(region.ecsClient.SNatRules.Create, jsonutils.Marshal(packParams), &ret) + if err != nil { + return SNatSEntry{}, errors.Wrapf(err, `create snat rule of nat gateway %q failed`, gatewayID) + } + return ret, nil +} + +func (region *SRegion) GetNatDEntryByID(id string) (SNatDEntry, error) { + dnat := SNatDEntry{} + err := DoGet(region.ecsClient.DNatRules.Get, id, map[string]string{}, &dnat) + + if err != nil { + return SNatDEntry{}, err + } + return dnat, nil +} + +func (region *SRegion) GetNatSEntryByID(id string) (SNatSEntry, error) { + snat := SNatSEntry{} + err := DoGet(region.ecsClient.SNatRules.Get, id, map[string]string{}, &snat) + if err != nil { + return SNatSEntry{}, cloudprovider.ErrNotFound + } + return snat, nil +} + +func NatResouceStatusTransfer(status string) string { + // In Huawei Cloud, there are isx resource status of Nat, "ACTIVE", "PENDING_CREATE", + // "PENDING_UPDATE", "PENDING_DELETE", "EIP_FREEZED", "INACTIVE". + switch status { + case "ACTIVE": + return api.NAT_STAUTS_AVAILABLE + case "PENDING_CREATE": + return api.NAT_STATUS_ALLOCATE + case "PENDING_UPDATE", "PENDING_DELETE": + return api.NAT_STATUS_DEPLOYING + default: + return api.NAT_STATUS_UNKNOWN + } +} + +func (self *SRegion) GetNatGateway(id string) (*SNatGateway, error) { + resp, err := self.ecsClient.NatGateways.Get(id, nil) + if err != nil { + return nil, errors.Wrapf(err, "NatGateways.Get(%s)", id) + } + nat := &SNatGateway{region: self} + err = resp.Unmarshal(nat) + return nat, errors.Wrap(err, "resp.Unmarshal") +} + +func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { + nat, err := self.region.CreateNatGateway(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateNatGateway") + } + return nat, nil +} + +func (self *SRegion) CreateNatGateway(opts *cloudprovider.NatGatewayCreateOptions) (*SNatGateway, error) { + spec := "" + switch strings.ToLower(opts.NatSpec) { + case api.NAT_SPEC_SMALL: + spec = "1" + case api.NAT_SPEC_MIDDLE: + spec = "2" + case api.NAT_SPEC_LARGE: + spec = "3" + case api.NAT_SPEC_XLARGE: + spec = "4" + } + params := jsonutils.Marshal(map[string]map[string]interface{}{ + "nat_gateway": map[string]interface{}{ + "name": opts.Name, + "description": opts.Desc, + "router_id": opts.VpcId, + "internal_network_id": opts.NetworkId, + "spec": spec, + }, + }) + resp, err := self.ecsClient.NatGateways.Create(params) + if err != nil { + return nil, errors.Wrap(err, "AsyncCreate") + } + nat := &SNatGateway{region: self} + err = resp.Unmarshal(nat) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return nat, nil +} + +func (self *SRegion) DeleteNatGateway(id string) error { + _, err := self.ecsClient.NatGateways.Delete(id, nil) + return errors.Wrapf(err, "NatGateways.Delete(%s)", id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natstable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natstable.go new file mode 100644 index 0000000000..3659eee4fa --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/natstable.go @@ -0,0 +1,121 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SNatSEntry struct { + multicloud.SResourceBase + HuaweiTags + gateway *SNatGateway + + ID string `json:"id"` + NatGatewayID string `json:"nat_gateway_id"` + NetworkID string `json:"network_id"` + SourceCIDR string `json:"cidr"` + Status string `json:"status"` + SNatIP string `json:"floating_ip_address"` + AdminStateUp bool `json:"admin_state_up"` +} + +func (nat *SNatSEntry) GetId() string { + return nat.ID +} + +func (nat *SNatSEntry) GetName() string { + // Snat rule has no name in Huawei Cloud, so return ID + return nat.GetId() +} + +func (nat *SNatSEntry) GetGlobalId() string { + return nat.GetId() +} + +func (nat *SNatSEntry) GetStatus() string { + return NatResouceStatusTransfer(nat.Status) +} + +func (nat *SNatSEntry) GetIP() string { + return nat.SNatIP +} + +func (nat *SNatSEntry) GetSourceCIDR() string { + return nat.SourceCIDR +} + +func (nat *SNatSEntry) GetNetworkId() string { + return nat.NetworkID +} + +func (nat *SNatSEntry) Delete() error { + return nat.gateway.region.DeleteNatSEntry(nat.GetId()) +} + +// getNatSTable return all snat rules of gateway +func (gateway *SNatGateway) getNatSTable() ([]SNatSEntry, error) { + ret, err := gateway.region.GetNatSTable(gateway.GetId()) + if err != nil { + return nil, err + } + for i := range ret { + ret[i].gateway = gateway + } + return ret, nil +} + +func (region *SRegion) GetNatSTable(natGatewayID string) ([]SNatSEntry, error) { + queuies := map[string]string{ + "nat_gateway_id": natGatewayID, + } + sNatSTableEntris := make([]SNatSEntry, 0, 2) + err := doListAllWithMarker(region.ecsClient.SNatRules.List, queuies, &sNatSTableEntris) + if err != nil { + return nil, errors.Wrapf(err, `get snat rule of gateway %q`, natGatewayID) + } + for i := range sNatSTableEntris { + nat := &sNatSTableEntris[i] + if len(nat.SourceCIDR) != 0 { + continue + } + subnet := SNetwork{} + err := DoGet(region.ecsClient.Subnets.Get, nat.NetworkID, map[string]string{}, &subnet) + if err != nil { + return nil, errors.Wrapf(err, `get cidr of subnet %q`, nat.NetworkID) + } + nat.SourceCIDR = subnet.CIDR + } + return sNatSTableEntris, nil +} + +func (region *SRegion) DeleteNatSEntry(entryID string) error { + _, err := region.ecsClient.SNatRules.Delete(entryID, nil) + if err != nil { + return errors.Wrapf(err, `delete snat rule %q failed`, entryID) + } + return nil +} + +func (nat *SNatSEntry) Refresh() error { + new, err := nat.gateway.region.GetNatSEntryByID(nat.ID) + if err != nil { + return err + } + return jsonutils.Update(nat, new) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/network.go new file mode 100644 index 0000000000..fe79636429 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/network.go @@ -0,0 +1,174 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +/* +Subnets +*/ + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html +type SNetwork struct { + multicloud.SResourceBase + HuaweiTags + wire *SWire + + AvailabilityZone string `json:"availability_zone"` + CIDR string `json:"cidr"` + DHCPEnable bool `json:"dhcp_enable"` + DNSList []string `json:"dnsList"` + GatewayIP string `json:"gateway_ip"` + ID string `json:"id"` + Ipv6Enable bool `json:"ipv6_enable"` + Name string `json:"name"` + NeutronNetworkID string `json:"neutron_network_id"` + NeutronSubnetID string `json:"neutron_subnet_id"` + PrimaryDNS string `json:"primary_dns"` + SecondaryDNS string `json:"secondary_dns"` + Status string `json:"status"` + VpcID string `json:"vpc_id"` +} + +func (self *SNetwork) GetId() string { + return self.ID +} + +func (self *SNetwork) GetName() string { + if len(self.Name) == 0 { + return self.ID + } + + return self.Name +} + +func (self *SNetwork) GetGlobalId() string { + return self.ID +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090591.html +func (self *SNetwork) GetStatus() string { + switch self.Status { + case "ACTIVE", "UNKNOWN": + return api.NETWORK_STATUS_AVAILABLE // ? todo: // UNKNOWN + case "ERROR": + return api.NETWORK_STATUS_UNKNOWN + default: + return api.NETWORK_STATUS_UNKNOWN + } +} + +func (self *SNetwork) Refresh() error { + log.Debugf("network refresh %s", self.GetId()) + new, err := self.wire.region.getNetwork(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SNetwork) IsEmulated() bool { + return false +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + startIp = startIp.StepUp() // 2 + return startIp.String() +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + 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.CIDR) + return pref.MaskLen +} + +func (self *SNetwork) GetGateway() string { + pref, _ := netutils.NewIPV4Prefix(self.CIDR) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String() +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetIsPublic() bool { + return true +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) Delete() error { + return self.wire.region.deleteNetwork(self.VpcID, self.GetId()) +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) { + network := SNetwork{} + err := DoGet(self.ecsClient.Subnets.Get, networkId, nil, &network) + return &network, err +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090592.html +func (self *SRegion) GetNetwroks(vpcId string) ([]SNetwork, error) { + querys := map[string]string{} + if len(vpcId) > 0 { + querys["vpc_id"] = vpcId + } + + networks := make([]SNetwork, 0) + err := doListAllWithMarker(self.ecsClient.Subnets.List, querys, &networks) + return networks, err +} + +func (self *SRegion) deleteNetwork(vpcId string, networkId string) error { + ctx := &modules.SManagerContext{InstanceId: vpcId, InstanceManager: self.ecsClient.Vpcs} + return DoDeleteWithSpec(self.ecsClient.Subnets.DeleteInContextWithSpec, ctx, networkId, "", nil, nil) +} + +func (self *SNetwork) GetProjectId() string { + return self.wire.vpc.EnterpriseProjectID +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/object.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/object.go new file mode 100644 index 0000000000..b647e18e7e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/object.go @@ -0,0 +1,103 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "net/http" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" +) + +type SObject struct { + bucket *SBucket + + cloudprovider.SBaseCloudObject +} + +func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { + return o.bucket +} + +func (o *SObject) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + obscli, err := o.bucket.region.getOBSClient() + if err != nil { + log.Errorf("o.bucket.region.GetOssClient error %s", err) + return acl + } + input := &obs.GetObjectAclInput{} + input.Bucket = o.bucket.Name + input.Key = o.Key + output, err := obscli.GetObjectAcl(input) + if err != nil { + log.Errorf("GetObjectAcl error: %v", err) + return acl + } + acl = obsAcl2CannedAcl(output.Grants) + return acl +} + +func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { + obscli, err := o.bucket.region.getOBSClient() + if err != nil { + return errors.Wrap(err, "o.bucket.region.getOBSClient") + } + input := &obs.SetObjectAclInput{} + input.Bucket = o.bucket.Name + input.Key = o.Key + input.ACL = obs.AclType(string(aclStr)) + _, err = obscli.SetObjectAcl(input) + if err != nil { + return errors.Wrap(err, "obscli.SetObjectAcl") + } + return nil +} + +func (o *SObject) GetMeta() http.Header { + if o.Meta != nil { + return o.Meta + } + obscli, err := o.bucket.region.getOBSClient() + if err != nil { + log.Errorf("getOBSClient fail %s", err) + return nil + } + input := &obs.GetObjectMetadataInput{} + input.Bucket = o.bucket.Name + input.Key = o.Key + output, err := obscli.GetObjectMetadata(input) + if err != nil { + log.Errorf("obscli.GetObjectMetadata fail %s", err) + return nil + } + meta := http.Header{} + for k, v := range output.Metadata { + meta.Add(k, v) + } + if len(output.ContentType) > 0 { + meta.Add(cloudprovider.META_HEADER_CONTENT_TYPE, output.ContentType) + } + o.Meta = meta + return meta +} + +func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { + return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) +} diff --git a/pkg/multicloud/huawei/obs/auth.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/auth.go similarity index 100% rename from pkg/multicloud/huawei/obs/auth.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/auth.go diff --git a/pkg/multicloud/huawei/obs/client.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/client.go similarity index 100% rename from pkg/multicloud/huawei/obs/client.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/client.go diff --git a/pkg/multicloud/huawei/obs/conf.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/conf.go similarity index 100% rename from pkg/multicloud/huawei/obs/conf.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/conf.go diff --git a/pkg/multicloud/huawei/obs/const.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/const.go similarity index 100% rename from pkg/multicloud/huawei/obs/const.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/const.go diff --git a/pkg/multicloud/huawei/obs/convert.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/convert.go similarity index 100% rename from pkg/multicloud/huawei/obs/convert.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/convert.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/doc.go new file mode 100644 index 0000000000..c2bb6f11c0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 obs // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" diff --git a/pkg/multicloud/huawei/obs/error.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/error.go similarity index 100% rename from pkg/multicloud/huawei/obs/error.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/error.go diff --git a/pkg/multicloud/huawei/obs/http.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/http.go similarity index 100% rename from pkg/multicloud/huawei/obs/http.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/http.go diff --git a/pkg/multicloud/huawei/obs/log.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/log.go similarity index 100% rename from pkg/multicloud/huawei/obs/log.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/log.go diff --git a/pkg/multicloud/huawei/obs/model.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/model.go similarity index 100% rename from pkg/multicloud/huawei/obs/model.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/model.go diff --git a/pkg/multicloud/huawei/obs/temporary.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/temporary.go similarity index 100% rename from pkg/multicloud/huawei/obs/temporary.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/temporary.go diff --git a/pkg/multicloud/huawei/obs/trait.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/trait.go similarity index 100% rename from pkg/multicloud/huawei/obs/trait.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/trait.go diff --git a/pkg/multicloud/huawei/obs/util.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/util.go similarity index 100% rename from pkg/multicloud/huawei/obs/util.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/obs/util.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/order.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/order.go new file mode 100644 index 0000000000..5c024b4678 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/order.go @@ -0,0 +1,193 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SOrder struct { + ErrorCode *string `json:"error_code"` // 只有失败时才返回此参数 + ErrorMsg *string `json:"error_msg"` //只有失败时才返回此参数 + TotalSize int `json:"totalSize"` // 只有成功时才返回此参数 + Resources []SResource `json:"resources"` +} + +type SResource struct { + ResourceID string `json:"resourceId"` + CloudServiceType string `json:"cloudServiceType"` + RegionCode string `json:"regionCode"` + ResourceType string `json:"resourceType"` + ResourceSpecCode string `json:"resourceSpecCode"` + Status int64 `json:"status"` +} + +type SResourceDetail struct { + ID string `json:"id"` + Status int64 `json:"status"` + ResourceID string `json:"resource_id"` + ResourceName string `json:"resource_name"` + RegionCode string `json:"region_code"` + CloudServiceTypeCode string `json:"cloud_service_type_code"` + ResourceTypeCode string `json:"resource_type_code"` + ResourceSpecCode string `json:"resource_spec_code"` + ProjectCode string `json:"project_code"` + ProductID string `json:"product_id"` + MainResourceID string `json:"main_resource_id"` + IsMainResource int64 `json:"is_main_resource"` + ValidTime time.Time `json:"valid_time"` + ExpireTime time.Time `json:"expire_time"` + NextOperationPolicy string `json:"next_operation_policy"` +} + +func (self *SRegion) getDomianId() (string, error) { + domains, err := self.client.getEnabledDomains() + if err != nil { + return "", err + } + + if domains == nil || len(domains) == 0 { + return "", fmt.Errorf("GetAllResByOrderId domain is empty") + } else if len(domains) > 1 { + // not supported?? + return "", fmt.Errorf("GetAllResByOrderId mutliple domain(%d) found", len(domains)) + } + + return domains[0].ID, nil +} + +/* +获取订单信息 https://support.huaweicloud.com/api-oce/api_order_00001.html +*/ +func (self *SRegion) GetOrder(orderId string) (SOrder, error) { + var order SOrder + domain, err := self.getDomianId() + if err != nil { + return order, err + } + + err = self.ecsClient.Orders.SetDomainId(domain) + if err != nil { + return order, err + } + + err = DoGet(self.ecsClient.Orders.Get, orderId, nil, &order) + return order, err +} + +/* +获取订单资源详情列表 https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html +*/ +func (self *SRegion) GetOrderResources(orderId string, resource_ids []string, only_main_resource bool) ([]SResourceDetail, error) { + domain, err := self.getDomianId() + if err != nil { + return nil, err + } + + err = self.ecsClient.Orders.SetDomainId(domain) + if err != nil { + return nil, err + } + + resources := make([]SResourceDetail, 0) + queries := map[string]string{"customer_id": domain} + if len(orderId) > 0 { + queries["order_id"] = orderId + } + + if len(resource_ids) > 0 { + queries["resource_ids"] = strings.Join(resource_ids, ",") + } + + if only_main_resource { + queries["only_main_resource"] = "1" + } + + err = doListAll(self.ecsClient.Orders.GetPeriodResourceList, queries, &resources) + return resources, err +} + +/* +获取资源详情 https://support.huaweicloud.com/api-oce/zh-cn_topic_0084961226.html +*/ +func (self *SRegion) GetOrderResourceDetail(resourceId string) (SResourceDetail, error) { + var res SResourceDetail + if len(resourceId) == 0 { + return res, fmt.Errorf("GetOrderResourceDetail resource id should not be empty") + } + + resources, err := self.GetOrderResources("", []string{resourceId}, false) + if err != nil { + return res, err + } + + switch len(resources) { + case 0: + return res, cloudprovider.ErrNotFound + case 1: + return resources[0], nil + default: + return res, fmt.Errorf("%d resources with id %s found, Expect 1", len(resources), resourceId) + } +} + +func (self *SRegion) GetAllResByOrderId(orderId string) ([]SResource, error) { + order, err := self.GetOrder(orderId) + if err != nil { + return nil, err + } + + log.Debugf("GetAllResByOrderId %#v", order.Resources) + return order.Resources, nil +} + +func (self *SRegion) getAllResByType(orderId string, resourceType string) ([]SResource, error) { + res, err := self.GetAllResByOrderId(orderId) + if err != nil { + return nil, err + } + + ret := make([]SResource, 0) + for i := range res { + r := res[i] + if r.ResourceType == resourceType { + ret = append(ret, r) + } + } + + return ret, nil +} + +func (self *SRegion) getAllResIdsByType(orderId string, resourceType string) ([]string, error) { + res, err := self.getAllResByType(orderId, resourceType) + if err != nil { + return nil, err + } + + ids := make([]string, 0) + for _, r := range res { + if len(r.ResourceID) > 0 { + ids = append(ids, r.ResourceID) + } + } + + return ids, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/port.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/port.go new file mode 100644 index 0000000000..6bbcd96970 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/port.go @@ -0,0 +1,161 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "strings" + + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SFixedIP struct { + IpAddress string + SubnetID string + NetworkId string +} + +func (fixip *SFixedIP) GetGlobalId() string { + return fixip.IpAddress +} + +func (fixip *SFixedIP) GetIP() string { + return fixip.IpAddress +} + +func (fixip *SFixedIP) GetINetworkId() string { + return fixip.NetworkId +} + +func (fixip *SFixedIP) IsPrimary() bool { + return true +} + +type Port struct { + multicloud.SNetworkInterfaceBase + HuaweiTags + region *SRegion + ID string `json:"id"` + Name string `json:"name"` + Status string `json:"status"` + AdminStateUp string `json:"admin_state_up"` + DNSName string `json:"dns_name"` + MACAddress string `json:"mac_address"` + NetworkID string `json:"network_id"` + TenantID string `json:"tenant_id"` + DeviceID string `json:"device_id"` + DeviceOwner string `json:"device_owner"` + BindingVnicType string `json:"binding:vnic_type"` + FixedIps []SFixedIP +} + +func (port *Port) GetName() string { + if len(port.Name) > 0 { + return port.Name + } + return port.ID +} + +func (port *Port) GetId() string { + return port.ID +} + +func (port *Port) GetGlobalId() string { + return port.ID +} + +func (port *Port) GetMacAddress() string { + return port.MACAddress +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html +func (port *Port) GetAssociateType() string { + switch port.DeviceOwner { + case "compute:nova": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER + case "network:router_gateway", "network:router_interface", "network:router_interface_distributed": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_RESERVED + case "network:dhcp": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_DHCP + case "neutron:LOADBALANCERV2": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_LOADBALANCER + case "neutron:VIP_PORT": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_VIP + default: + if strings.HasPrefix(port.DeviceOwner, "compute:") { + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER + } + } + return port.DeviceOwner +} + +func (port *Port) GetAssociateId() string { + return port.DeviceID +} + +func (port *Port) GetStatus() string { + switch port.Status { + case "ACTIVE", "DOWN": + return api.NETWORK_INTERFACE_STATUS_AVAILABLE + case "BUILD": + return api.NETWORK_INTERFACE_STATUS_CREATING + } + return port.Status +} + +func (port *Port) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { + address := []cloudprovider.ICloudInterfaceAddress{} + for i := 0; i < len(port.FixedIps); i++ { + port.FixedIps[i].NetworkId = port.NetworkID + address = append(address, &port.FixedIps[i]) + } + return address, nil +} + +func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { + ports, err := region.GetPorts("") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNetworkInterface{} + for i := 0; i < len(ports); i++ { + if len(ports[i].DeviceID) == 0 || !utils.IsInStringArray(ports[i].DeviceOwner, []string{"compute:CCI", "compute:nova", "neutron:LOADBALANCERV2"}) { + ports[i].region = region + ret = append(ret, &ports[i]) + } + } + return ret, nil +} + +func (self *SRegion) GetPort(portId string) (Port, error) { + port := Port{} + err := DoGet(self.ecsClient.Port.Get, portId, nil, &port) + return port, err +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0133195888.html +func (self *SRegion) GetPorts(instanceId string) ([]Port, error) { + ports := make([]Port, 0) + querys := map[string]string{} + if len(instanceId) > 0 { + querys["device_id"] = instanceId + } + + err := doListAllWithMarker(self.ecsClient.Port.List, querys, &ports) + return ports, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/project.go new file mode 100644 index 0000000000..9a23856921 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/project.go @@ -0,0 +1,94 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "strings" + + api "yunion.io/x/cloudmux/pkg/apis/compute" +) + +// https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845625.html +type SProject struct { + client *SHuaweiClient + + IsDomain bool `json:"is_domain"` + Description string `json:"description"` + Enabled bool `json:"enabled"` + ID string `json:"id"` + ParentID string `json:"parent_id"` + DomainID string `json:"domain_id"` + Name string `json:"name"` +} + +func (self *SProject) GetRegionID() string { + return strings.Split(self.Name, "_")[0] +} + +func (self *SProject) GetHealthStatus() string { + if self.Enabled { + return api.CLOUD_PROVIDER_HEALTH_NORMAL + } + + return api.CLOUD_PROVIDER_HEALTH_SUSPENDED +} + +func (self *SHuaweiClient) fetchProjects() ([]SProject, error) { + if self.projects != nil { + return self.projects, nil + } + + huawei, _ := self.newGeneralAPIClient() + projects := make([]SProject, 0) + err := doListAll(huawei.Projects.List, nil, &projects) + if err == nil { + self.projects = projects + } + + return projects, err +} + +// obs 权限必须赋予到mos project之上 +func (self *SHuaweiClient) GetMosProjectId() string { + projects, err := self.GetProjects() + if err != nil { + return "" + } + for i := range projects { + if strings.ToLower(projects[i].Name) == "mos" { + return projects[i].ID + } + } + return "" +} + +func (self *SHuaweiClient) GetProjectById(projectId string) (SProject, error) { + projects, err := self.fetchProjects() + if err != nil { + return SProject{}, err + } + + for _, project := range projects { + if project.ID == projectId { + return project, nil + } + } + return SProject{}, fmt.Errorf("project %s not found", projectId) +} + +func (self *SHuaweiClient) GetProjects() ([]SProject, error) { + return self.fetchProjects() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/doc.go new file mode 100644 index 0000000000..5f753232f5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/huawei/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/provider.go new file mode 100644 index 0000000000..5cd77a92c8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/provider/provider.go @@ -0,0 +1,314 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/huawei" +) + +type SHuaweiProviderFactory struct { + cloudprovider.SPublicCloudBaseProviderFactory +} + +func (self *SHuaweiProviderFactory) GetId() string { + return huawei.CLOUD_PROVIDER_HUAWEI +} + +func (self *SHuaweiProviderFactory) GetName() string { + return huawei.CLOUD_PROVIDER_HUAWEI_CN +} + +func (self *SHuaweiProviderFactory) IsCloudeventRegional() bool { + return true +} + +func (self *SHuaweiProviderFactory) GetMaxCloudEventSyncDays() int { + return 7 +} + +func (self *SHuaweiProviderFactory) GetMaxCloudEventKeepDays() int { + return 7 +} + +func (self *SHuaweiProviderFactory) IsSupportCloudIdService() bool { + return true +} + +func (self *SHuaweiProviderFactory) IsSupportClouduserPolicy() bool { + return false +} + +func (self *SHuaweiProviderFactory) IsSupportCreateCloudgroup() bool { + return true +} + +func (factory *SHuaweiProviderFactory) IsSupportCrossCloudEnvVpcPeering() bool { + return false +} + +func (factory *SHuaweiProviderFactory) IsSupportCrossRegionVpcPeering() bool { + return false +} + +func (factory *SHuaweiProviderFactory) IsSupportVpcPeeringVpcCidrOverlap() bool { + return true +} + +func (factory *SHuaweiProviderFactory) IsSupportModifyRouteTable() bool { + return true +} + +func (factory *SHuaweiProviderFactory) IsSupportSAMLAuth() bool { + return true +} + +func (self *SHuaweiProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + if len(input.Environment) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "environment") + } + + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + output.AccessUrl = input.Environment + + return output, nil +} + +func (self *SHuaweiProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func parseAccount(account string) (accessKey string, projectId string) { + segs := strings.Split(account, "/") + if len(segs) == 2 { + accessKey = segs[0] + projectId = segs[1] + } else { + accessKey = account + projectId = "" + } + + return +} + +func (self *SHuaweiProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + accessKey, projectId := parseAccount(cfg.Account) + client, err := huawei.NewHuaweiClient( + huawei.NewHuaweiClientConfig( + cfg.URL, accessKey, cfg.Secret, projectId, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SHuaweiProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SHuaweiProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + accessKey, projectId := parseAccount(info.Account) + region := huawei.HUAWEI_DEFAULT_REGION + data := strings.Split(info.Name, "-") + if len(data) >= 3 { + region = strings.Join(data[len(data)-3:], "-") + } + return map[string]string{ + "HUAWEI_CLOUD_ENV": info.Url, + "HUAWEI_ACCESS_KEY": accessKey, + "HUAWEI_SECRET": info.Secret, + "HUAWEI_REGION": region, + "HUAWEI_PROJECT": projectId, + }, nil +} + +func init() { + factory := SHuaweiProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SHuaweiProvider struct { + cloudprovider.SBaseProvider + client *huawei.SHuaweiClient +} + +func (self *SHuaweiProvider) GetVersion() string { + return self.client.GetVersion() +} + +func (self *SHuaweiProvider) GetSysInfo() (jsonutils.JSONObject, error) { + regions := self.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") + info.Add(jsonutils.NewString(huawei.HUAWEI_API_VERSION), "api_version") + return info, nil +} + +func (self *SHuaweiProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SHuaweiProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(extId) +} + +func (self *SHuaweiProvider) GetBalance() (float64, string, error) { + balance, err := self.client.QueryAccountBalance() + if err != nil { + return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, err + } + status := api.CLOUD_PROVIDER_HEALTH_NORMAL + if balance.AvailableAmount < 0.0 && balance.CreditAmount < 0.0 { + status = api.CLOUD_PROVIDER_HEALTH_ARREARS + } + return balance.AvailableAmount, status, nil +} + +func (self *SHuaweiProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SHuaweiProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SHuaweiProvider) GetIamLoginUrl() string { + return self.client.GetIamLoginUrl() +} + +func (self *SHuaweiProvider) GetCloudRegionExternalIdPrefix() string { + return self.client.GetCloudRegionExternalIdPrefix() +} + +func (self *SHuaweiProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SHuaweiProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return self.client.CreateIProject(name) +} + +func (self *SHuaweiProvider) GetStorageClasses(regionId string) []string { + return []string{ + "STANDARD", "WARM", "COLD", + } +} + +func (self *SHuaweiProvider) GetBucketCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLAuthRead), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SHuaweiProvider) GetObjectCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLAuthRead), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + } +} + +func (self *SHuaweiProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SHuaweiProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + return self.client.CreateIClouduser(conf) +} + +func (self *SHuaweiProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { + return self.client.GetICloudusers() +} + +func (self *SHuaweiProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroups() +} + +func (self *SHuaweiProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroupByName(name) +} + +func (self *SHuaweiProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + return self.client.CreateICloudgroup(name, desc) +} + +func (self *SHuaweiProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetISystemCloudpolicies() +} + +func (self *SHuaweiProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return []cloudprovider.ICloudpolicy{}, nil +} + +func (self *SHuaweiProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.client.GetIClouduserByName(name) +} + +func (self *SHuaweiProvider) GetSamlEntityId() string { + return cloudprovider.SAML_ENTITY_ID_HUAWEI_CLOUD +} + +func (self *SHuaweiProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { + return self.client.GetICloudSAMLProviders() +} + +func (self *SHuaweiProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { + sp, err := self.client.CreateSAMLProvider(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateSAMLProvider") + } + return sp, nil +} + +func (self *SHuaweiProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metrics, err := self.client.GetMetrics(opts) + if err != nil { + return nil, errors.Wrapf(err, "GetMetrics") + } + return metrics, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/quota.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/quota.go new file mode 100644 index 0000000000..a26fc137b7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/quota.go @@ -0,0 +1,80 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SQuota struct { + Min int + Quota int + Type string + Used int +} + +func (q *SQuota) GetGlobalId() string { + return q.Type +} + +func (q *SQuota) GetQuotaType() string { + return q.Type +} + +func (q *SQuota) GetName() string { + return q.Type +} + +func (q *SQuota) GetDesc() string { + return "" +} + +func (q *SQuota) GetMaxQuotaCount() int { + return q.Quota +} + +func (q *SQuota) GetCurrentQuotaUsedCount() int { + return q.Used +} + +func (self *SRegion) GetQuotas() ([]SQuota, error) { + quotas := []SQuota{} + params := map[string]string{} + result, err := self.ecsClient.Quotas.Get("", params) + if err != nil { + return nil, errors.Wrap(err, "Quotas.List") + } + + err = result.Unmarshal("as, "resources") + if err != nil { + return nil, errors.Wrap(err, "result.Unmarshal") + } + + return quotas, nil +} + +func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { + quotas, err := region.GetQuotas() + if err != nil { + return nil, errors.Wrap(err, "GetQuotas") + } + ret := []cloudprovider.ICloudQuota{} + for i := range quotas { + ret = append(ret, "as[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/region.go new file mode 100644 index 0000000000..f6ca9cfddf --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/region.go @@ -0,0 +1,862 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/obs" +) + +type Locales struct { + EnUs string `json:"en-us"` + ZhCN string `json:"zh-cn"` +} + +// https://support.huaweicloud.com/api-iam/zh-cn_topic_0067148043.html +type SRegion struct { + multicloud.SRegion + + client *SHuaweiClient + ecsClient *client.Client + obsClient *obs.ObsClient // 对象存储client.请勿直接引用。 + + Description string `json:"description"` + ID string `json:"id"` + Locales Locales `json:"locales"` + ParentRegionID string `json:"parent_region_id"` + Type string `json:"type"` + + izones []cloudprovider.ICloudZone + ivpcs []cloudprovider.ICloudVpc + + storageCache *SStoragecache +} + +func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetClient() *SHuaweiClient { + return self.client +} + +func (self *SRegion) getECSClient() (*client.Client, error) { + var err error + + if len(self.client.projectId) > 0 { + project, err := self.client.GetProjectById(self.client.projectId) + if err != nil { + return nil, err + } + + if !strings.Contains(project.Name, self.ID) { + return nil, errors.Errorf("region %s and project %s mismatch", self.ID, project.Name) + } + } + + if self.ecsClient == nil { + self.ecsClient, err = self.client.newRegionAPIClient(self.ID) + if err != nil { + return nil, err + } + } + + return self.ecsClient, err +} + +func (self *SRegion) getOBSEndpoint() string { + return getOBSEndpoint(self.GetId()) +} + +func (self *SRegion) getOBSClient() (*obs.ObsClient, error) { + if self.obsClient == nil { + obsClient, err := self.client.getOBSClient(self.GetId()) + if err != nil { + return nil, err + } + + self.obsClient = obsClient + } + + return self.obsClient, nil +} + +func (self *SRegion) fetchZones() error { + zones := make([]SZone, 0) + err := doListAll(self.ecsClient.Zones.List, nil, &zones) + if err != nil { + return err + } + + self.izones = make([]cloudprovider.ICloudZone, 0) + for i := range zones { + zone := zones[i] + zone.region = self + self.izones = append(self.izones, &zone) + } + return nil +} + +func (self *SRegion) fetchIVpcs() error { + // https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html + vpcs := make([]SVpc, 0) + querys := map[string]string{ + "limit": "2048", + } + err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs) + if err != nil { + return err + } + + self.ivpcs = make([]cloudprovider.ICloudVpc, 0) + for i := range vpcs { + vpc := vpcs[i] + vpc.region = self + self.ivpcs = append(self.ivpcs, &vpc) + } + return nil +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + if len(id) == 0 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "SRegion.GetIVMById") + } + + instance, err := self.GetInstanceByID(id) + if err != nil { + return nil, err + } + return &instance, err +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return self.GetDisk(id) +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + if info, ok := LatitudeAndLongitude[self.ID]; ok { + return info + } + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + elbs, err := self.GetLoadBalancers() + if err != nil { + return nil, err + } + + ielbs := make([]cloudprovider.ICloudLoadbalancer, len(elbs)) + for i := range elbs { + elbs[i].region = self + ielbs[i] = &elbs[i] + } + + return ielbs, nil +} + +func (self *SRegion) GetLoadBalancers() ([]SLoadbalancer, error) { + lbs := []SLoadbalancer{} + params := url.Values{} + return lbs, self.lbListAll("elb/loadbalancers", params, "loadbalancers", &lbs) +} + +func (self *SRegion) GetILoadBalancerById(id string) (cloudprovider.ICloudLoadbalancer, error) { + elb, err := self.GetLoadbalancer(id) + if err != nil { + return nil, err + } + return elb, nil +} + +func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { + acl, err := self.GetLoadBalancerAcl(aclId) + if err != nil { + return nil, err + } + return acl, nil +} + +func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + cert, err := self.GetLoadBalancerCertificate(certId) + if err != nil { + return nil, err + } + return cert, nil +} + +func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + ret, err := self.CreateLoadBalancerCertificate(cert) + if err != nil { + return nil, err + } + return ret, nil +} + +func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { + ret, err := self.GetLoadBalancerAcls("") + if err != nil { + return nil, err + } + + iret := make([]cloudprovider.ICloudLoadbalancerAcl, len(ret)) + for i := range ret { + ret[i].region = self + iret[i] = &ret[i] + } + return iret, nil +} + +func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + ret, err := self.GetLoadBalancerCertificates() + if err != nil { + return nil, err + } + + iret := make([]cloudprovider.ICloudLoadbalancerCertificate, len(ret)) + for i := range ret { + ret[i].region = self + iret[i] = &ret[i] + } + return iret, nil +} + +// https://support.huaweicloud.com/api-iam/zh-cn_topic_0057845622.html +func (self *SRegion) GetId() string { + return self.ID +} + +func (self *SRegion) GetName() string { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.Locales.ZhCN) +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.Locales.EnUs) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.client.GetAccessEnv(), self.ID) +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) Refresh() error { + return nil +} + +func (self *SRegion) IsEmulated() bool { + return false +} + +func (self *SRegion) GetLatitude() float32 { + if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok { + return locationInfo.Latitude + } + return 0.0 +} + +func (self *SRegion) GetLongitude() float32 { + if locationInfo, ok := LatitudeAndLongitude[self.ID]; ok { + return locationInfo.Longitude + } + return 0.0 +} + +func (self *SRegion) fetchInfrastructure() error { + _, err := self.getECSClient() + if 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 { + vpc := self.ivpcs[i].(*SVpc) + wire := SWire{region: self, vpc: vpc} + vpc.addWire(&wire) + + for j := 0; j < len(self.izones); j += 1 { + zone := self.izones[j].(*SZone) + zone.addWire(&wire) + } + } + return nil +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if self.izones == nil { + var err error + err = self.fetchInfrastructure() + if 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) { + eips, err := self.GetEips("", nil) + if err != nil { + return nil, err + } + + ret := []cloudprovider.ICloudEIP{} + for i := 0; i < len(eips); i += 1 { + eips[i].region = self + ret = append(ret, &eips[i]) + } + return ret, nil +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + ivpcs, err := self.GetIVpcs() + if err != nil { + return nil, err + } + for i := 0; i < len(ivpcs); i += 1 { + if ivpcs[i].GetGlobalId() == id { + return ivpcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { + eip, err := self.GetEip(eipId) + if err != nil { + return nil, err + } + return eip, nil +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0060595555.html +func (self *SRegion) DeleteSecurityGroup(secgroupId string) error { + return DoDelete(self.ecsClient.SecurityGroups.Delete, secgroupId, nil, nil) +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return self.GetSecurityGroupDetails(secgroupId) +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := self.GetSecurityGroups(opts.VpcId, opts.Name) + if err != nil { + return nil, err + } + if len(secgroups) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(secgroups) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + secgroups[0].region = self + return &secgroups[0], nil +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return self.CreateSecurityGroup(conf.VpcId, conf.Name, conf.Desc) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090608.html +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + return self.CreateVpc(opts.NAME, opts.CIDR, opts.Desc) +} + +func (self *SRegion) CreateVpc(name, cidr, desc string) (*SVpc, error) { + params := map[string]interface{}{ + "vpc": map[string]string{ + "name": name, + "cidr": cidr, + "description": desc, + }, + } + vpc := &SVpc{region: self} + return vpc, DoCreate(self.ecsClient.Vpcs.Create, jsonutils.Marshal(params), vpc) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090596.html +// size: 1Mbit/s~2000Mbit/s +// bgpType: 5_telcom,5_union,5_bgp,5_sbgp. +// 东北-大连:5_telcom、5_union +// 华南-广州:5_sbgp +// 华东-上海二:5_sbgp +// 华北-北京一:5_bgp、5_sbgp +// 亚太-香港:5_bgp +func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + var ctype TInternetChargeType + switch eip.ChargeType { + case api.EIP_CHARGE_TYPE_BY_TRAFFIC: + ctype = InternetChargeByTraffic + case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: + ctype = InternetChargeByBandwidth + } + + // todo: 如何避免hardcode。集成到cloudmeta服务中? + if len(eip.BGPType) == 0 { + switch self.GetId() { + case "cn-north-1", "cn-east-2", "cn-south-1": + eip.BGPType = "5_sbgp" + case "cn-northeast-1": + eip.BGPType = "5_telcom" + case "cn-north-4", "ap-southeast-1", "ap-southeast-2", "eu-west-0": + eip.BGPType = "5_bgp" + case "cn-southwest-2": + eip.BGPType = "5_sbgp" + default: + eip.BGPType = "5_bgp" + } + } + + // 华为云EIP名字最大长度64 + if len(eip.Name) > 64 { + eip.Name = eip.Name[:64] + } + + ieip, err := self.AllocateEIP(eip.Name, eip.BandwidthMbps, ctype, eip.BGPType, eip.ProjectId) + ieip.region = self + if err != nil { + return nil, err + } + + err = cloudprovider.WaitStatus(ieip, api.EIP_STATUS_READY, 5*time.Second, 60*time.Second) + return ieip, err +} + +func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := self.GetSnapshots("", "") + if err != nil { + log.Errorf("self.GetSnapshots fail %s", err) + return nil, err + } + + ret := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := 0; i < len(snapshots); i += 1 { + snapshots[i].region = self + ret[i] = &snapshots[i] + } + return ret, nil +} + +func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := self.GetSnapshotById(snapshotId) + return &snapshot, err +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetProvider() string { + return CLOUD_PROVIDER_HUAWEI +} + +func (self *SRegion) GetCloudEnv() string { + return self.client.cloudEnv +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html +// 目前desc字段并没有用到 +func (self *SRegion) CreateSecurityGroup(vpcId string, name string, desc string) (*SSecurityGroup, error) { + // 华为不允许创建名称为default的安全组 + if strings.ToLower(name) == "default" { + name = fmt.Sprintf("%s-%s", vpcId, name) + } + + params := jsonutils.NewDict() + secgroupObj := jsonutils.NewDict() + secgroupObj.Add(jsonutils.NewString(name), "name") + if len(vpcId) > 0 && vpcId != api.NORMAL_VPC_ID { + secgroupObj.Add(jsonutils.NewString(vpcId), "vpc_id") + } + params.Add(secgroupObj, "security_group") + + secgroup := SSecurityGroup{region: self} + err := DoCreate(self.ecsClient.SecurityGroups.Create, params, &secgroup) + return &secgroup, err +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087467071.html +func (self *SRegion) delSecurityGroupRule(secGrpRuleId string) error { + _, err := self.ecsClient.SecurityGroupRules.DeleteInContextWithSpec(nil, secGrpRuleId, "", nil, nil, "") + return err +} + +func (self *SRegion) DeleteSecurityGroupRule(ruleId string) error { + return self.delSecurityGroupRule(ruleId) +} + +func (self *SRegion) CreateSecurityGroupRule(secgroupId string, rule cloudprovider.SecurityRule) error { + return self.addSecurityGroupRules(secgroupId, rule) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0087451723.html +// icmp port对应关系:https://support.huaweicloud.com/api-vpc/zh-cn_topic_0024109590.html +func (self *SRegion) addSecurityGroupRules(secGrpId string, rule cloudprovider.SecurityRule) error { + direction := "" + if rule.Direction == secrules.SecurityRuleIngress { + direction = "ingress" + } else { + direction = "egress" + } + + protocal := rule.Protocol + if rule.Protocol == secrules.PROTO_ANY { + protocal = "" + } + + // imcp协议默认为any + if rule.Protocol == secrules.PROTO_ICMP { + return self.addSecurityGroupRule(secGrpId, direction, "-1", "-1", protocal, rule.IPNet.String()) + } + + if len(rule.Ports) > 0 { + for _, port := range rule.Ports { + portStr := fmt.Sprintf("%d", port) + err := self.addSecurityGroupRule(secGrpId, direction, portStr, portStr, protocal, rule.IPNet.String()) + if err != nil { + return err + } + } + } else { + portStart := fmt.Sprintf("%d", rule.PortStart) + portEnd := fmt.Sprintf("%d", rule.PortEnd) + err := self.addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocal, rule.IPNet.String()) + if err != nil { + return err + } + } + + return nil +} + +func (self *SRegion) addSecurityGroupRule(secGrpId, direction, portStart, portEnd, protocol, ipNet string) error { + params := jsonutils.NewDict() + secgroupObj := jsonutils.NewDict() + secgroupObj.Add(jsonutils.NewString(secGrpId), "security_group_id") + secgroupObj.Add(jsonutils.NewString(direction), "direction") + secgroupObj.Add(jsonutils.NewString(ipNet), "remote_ip_prefix") + secgroupObj.Add(jsonutils.NewString("IPV4"), "ethertype") + // 端口为空或者1-65535 + if len(portStart) > 0 && portStart != "0" && portStart != "-1" { + secgroupObj.Add(jsonutils.NewString(portStart), "port_range_min") + } + if len(portEnd) > 0 && portEnd != "0" && portEnd != "-1" { + secgroupObj.Add(jsonutils.NewString(portEnd), "port_range_max") + } + if len(protocol) > 0 { + secgroupObj.Add(jsonutils.NewString(protocol), "protocol") + } + params.Add(secgroupObj, "security_group_rule") + + rule := SecurityGroupRule{} + return DoCreate(self.ecsClient.SecurityGroupRules.Create, params, &rule) +} + +func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + ret, err := self.CreateLoadBalancer(loadbalancer) + if err != nil { + return nil, err + } + + return ret, nil +} + +func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + ret, err := self.CreateLoadBalancerAcl(acl) + if err != nil { + return nil, err + } + + return ret, nil +} + +func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + iBuckets, err := region.client.getIBuckets() + if err != nil { + return nil, errors.Wrap(err, "getIBuckets") + } + ret := make([]cloudprovider.ICloudBucket, 0) + for i := range iBuckets { + // huawei OBS is shared across projects + if iBuckets[i].GetLocation() == region.GetId() { + ret = append(ret, iBuckets[i]) + } + } + return ret, nil +} + +func str2StorageClass(storageClassStr string) (obs.StorageClassType, error) { + if strings.EqualFold(storageClassStr, string(obs.StorageClassStandard)) { + return obs.StorageClassStandard, nil + } else if strings.EqualFold(storageClassStr, string(obs.StorageClassWarm)) { + return obs.StorageClassWarm, nil + } else if strings.EqualFold(storageClassStr, string(obs.StorageClassCold)) { + return obs.StorageClassCold, nil + } else { + return obs.StorageClassStandard, errors.Error("unsupported storageClass") + } +} + +func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { + obsClient, err := region.getOBSClient() + if err != nil { + return errors.Wrap(err, "region.getOBSClient") + } + input := &obs.CreateBucketInput{} + input.Bucket = name + input.Location = region.GetId() + if len(aclStr) > 0 { + if strings.EqualFold(aclStr, string(obs.AclPrivate)) { + input.ACL = obs.AclPrivate + } else if strings.EqualFold(aclStr, string(obs.AclPublicRead)) { + input.ACL = obs.AclPublicRead + } else if strings.EqualFold(aclStr, string(obs.AclPublicReadWrite)) { + input.ACL = obs.AclPublicReadWrite + } else { + return errors.Error("unsupported acl") + } + } + if len(storageClassStr) > 0 { + input.StorageClass, err = str2StorageClass(storageClassStr) + if err != nil { + return err + } + } + _, err = obsClient.CreateBucket(input) + if err != nil { + return errors.Wrap(err, "obsClient.CreateBucket") + } + region.client.invalidateIBuckets() + return nil +} + +func obsHttpCode(err error) int { + switch httpErr := err.(type) { + case obs.ObsError: + return httpErr.StatusCode + case *obs.ObsError: + return httpErr.StatusCode + } + return -1 +} + +func (region *SRegion) DeleteIBucket(name string) error { + obsClient, err := region.getOBSClient() + if err != nil { + return errors.Wrap(err, "region.getOBSClient") + } + _, err = obsClient.DeleteBucket(name) + if err != nil { + if obsHttpCode(err) == 404 { + return nil + } + log.Debugf("%#v %s", err, err) + return errors.Wrap(err, "DeleteBucket") + } + region.client.invalidateIBuckets() + return nil +} + +func (region *SRegion) HeadBucket(name string) (*obs.BaseModel, error) { + obsClient, err := region.getOBSClient() + if err != nil { + return nil, errors.Wrap(err, "region.getOBSClient") + } + return obsClient.HeadBucket(name) +} + +func (region *SRegion) IBucketExist(name string) (bool, error) { + _, err := region.HeadBucket(name) + if err != nil { + if obsHttpCode(err) == 404 { + return false, nil + } else { + return false, errors.Wrap(err, "HeadBucket") + } + } + return true, nil +} + +func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { + return cloudprovider.GetIBucketById(region, name) +} + +func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { + return region.GetIBucketById(name) +} + +func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { + caches, err := self.GetElasticCaches() + if err != nil { + return nil, err + } + + icaches := make([]cloudprovider.ICloudElasticcache, len(caches)) + for i := range caches { + caches[i].region = self + icaches[i] = &caches[i] + } + + return icaches, nil +} + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} + +func (self *SRegion) GetDiskTypes() ([]SDiskType, error) { + ret, err := self.ecsClient.Disks.GetDiskTypes() + if err != nil { + return nil, errors.Wrap(err, "GetDiskTypes") + } + + dts := []SDiskType{} + _ret := jsonutils.NewArray(ret.Data...) + err = _ret.Unmarshal(&dts) + if err != nil { + return nil, errors.Wrap(err, "Unmarshal") + } + + return dts, nil +} + +func (self *SRegion) GetZoneSupportedDiskTypes(zoneId string) ([]string, error) { + dts, err := self.GetDiskTypes() + if err != nil { + return nil, errors.Wrap(err, "GetDiskTypes") + } + + ret := []string{} + for i := range dts { + if dts[i].IsAvaliableInZone(zoneId) { + ret = append(ret, dts[i].Name) + } + } + + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/roles.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/roles.go new file mode 100644 index 0000000000..783f2c1fd1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/roles.go @@ -0,0 +1,99 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SRole struct { + DomainId string + Flag string + DescriptionCn string + Catelog string + Description string + Id string + DisplayName string + Type string + UpdatedTime string + CreatedTime string + Links SLink + Policy jsonutils.JSONDict +} + +func (role *SRole) GetName() string { + return role.DisplayName +} + +func (role *SRole) GetDescription() string { + return role.DescriptionCn +} + +func (role *SRole) GetPolicyType() string { + return "System" +} + +func (role *SRole) GetGlobalId() string { + return role.Id +} + +func (role *SRole) UpdateDocument(document *jsonutils.JSONDict) error { + return cloudprovider.ErrNotImplemented +} + +func (role *SRole) GetDocument() (*jsonutils.JSONDict, error) { + return &role.Policy, nil +} + +func (role *SRole) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (self *SHuaweiClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + roles, err := self.GetRoles("", "") + if err != nil { + return nil, errors.Wrap(err, "GetRoles") + } + ret := []cloudprovider.ICloudpolicy{} + for i := range roles { + ret = append(ret, &roles[i]) + } + return ret, nil +} + +func (self *SHuaweiClient) GetRoles(domainId, name string) ([]SRole, error) { + params := map[string]string{} + if len(domainId) > 0 { + params["domain_id"] = self.ownerId + } + if len(name) > 0 { + params["name"] = name + } + + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + + roles := []SRole{} + err = doListAllWithNextLink(client.Roles.List, params, &roles) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithOffset") + } + return roles, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/routetables.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/routetables.go new file mode 100644 index 0000000000..ade73920be --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/routetables.go @@ -0,0 +1,232 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var hoptypes = map[string]string{ + api.NEXT_HOP_TYPE_VPCPEERING: "peering", + api.NEXT_HOP_TYPE_INSTANCE: "ecs", + api.NEXT_HOP_TYPE_NAT: "nat", + api.NEXT_HOP_TYPE_HAVIP: "vip", + api.NEXT_HOP_TYPE_NETWORK: "eni", + api.NEXT_HOP_TYPE_INTERVPCNETWORK: "cc", +} + +type SRoute struct { + multicloud.SResourceBase + HuaweiTags + + Type string `json:"type"` + Destination string `json:"destination"` + Nexthop string `json:"nexthop"` + Description string `json:"description,omitempty"` +} + +func (self *SRoute) GetCidr() string { + return self.Destination +} + +func (self *SRoute) GetGlobalId() string { + return self.GetId() +} + +func (self *SRoute) GetId() string { + return fmt.Sprintf("%s:%s:%s", self.Type, self.Nexthop, self.Destination) +} + +func (self *SRoute) GetName() string { + return "" +} + +func (route *SRoute) GetStatus() string { + return api.ROUTE_ENTRY_STATUS_AVAILIABLE +} + +func (route *SRoute) GetType() string { + if route.Type != "local" { + return api.ROUTE_ENTRY_TYPE_CUSTOM + } + return api.ROUTE_ENTRY_TYPE_SYSTEM +} + +func (self *SRoute) GetNextHopType() string { + for k, v := range hoptypes { + if v == self.Type { + return k + } + } + return self.Type +} + +type Subnet struct { + Id string `json:"id"` +} + +type SRouteTable struct { + multicloud.SResourceBase + HuaweiTags + vpc *SVpc + + Id string `json:"id"` + Name string `json:"name"` + Routes []SRoute `json:"routes"` + Subnets []Subnet `json:"subnets"` + VpcId string `json:"vpc_id"` + Default bool `json:"default"` + TenantId string `json:"tenant_id"` +} + +func (self *SRouteTable) GetDescription() string { + return "" +} + +func (self *SRouteTable) GetGlobalId() string { + return self.Id +} + +func (self *SRouteTable) GetId() string { + return self.Id +} + +func (self *SRouteTable) GetName() string { + return self.Name +} + +func (self *SRouteTable) GetRegionId() string { + return self.vpc.region.GetId() +} + +func (self *SRouteTable) GetVpcId() string { + return self.VpcId +} + +func (self *SRouteTable) GetType() cloudprovider.RouteTableType { + return cloudprovider.RouteTableTypeSystem +} + +func (self *SRouteTable) GetStatus() string { + return api.ROUTE_TABLE_AVAILABLE +} + +func (self *SRouteTable) Refresh() error { + rtb, err := self.vpc.region.GetRouteTable(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, rtb) +} + +func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { + if len(self.Routes) == 0 { + err := self.Refresh() + if err != nil { + return nil, err + } + } + ret := []cloudprovider.ICloudRoute{} + for i := range self.Routes { + ret = append(ret, &self.Routes[i]) + } + return ret, nil +} + +func (self *SRoute) GetNextHop() string { + return self.Nexthop +} + +func (self *SRegion) GetRouteTables(vpcId string) ([]SRouteTable, error) { + params := map[string]string{} + if len(vpcId) > 0 { + params["vpc_id"] = vpcId + } + rtbs := make([]SRouteTable, 0) + err := doListAllWithMarker(self.ecsClient.RouteTables.List, params, &rtbs) + return rtbs, err +} + +func (self *SRegion) GetRouteTable(id string) (*SRouteTable, error) { + resp, err := self.ecsClient.RouteTables.Get(id, nil) + if err != nil { + return nil, err + } + tb := &SRouteTable{} + return tb, resp.Unmarshal(tb) +} + +func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { + routeType, ok := hoptypes[route.NextHopType] + if !ok { + return errors.Wrapf(cloudprovider.ErrNotSupported, route.NextHopType) + } + params := map[string]interface{}{ + "routes": map[string]interface{}{ + "add": []map[string]interface{}{ + { + "type": routeType, + "destination": route.Destination, + "nexthop": route.NextHop, + }, + }, + }, + } + _, err := self.vpc.region.ecsClient.VpcRoutes.Update(self.Id, jsonutils.Marshal(params)) + return err +} + +func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { + routeType, ok := hoptypes[route.NextHopType] + if !ok { + return errors.Wrapf(cloudprovider.ErrNotSupported, route.NextHopType) + } + params := map[string]interface{}{ + "routes": map[string]interface{}{ + "mod": []map[string]interface{}{ + { + "type": routeType, + "destination": route.Destination, + "nexthop": route.NextHop, + }, + }, + }, + } + _, err := self.vpc.region.ecsClient.VpcRoutes.Update(self.Id, jsonutils.Marshal(params)) + return err +} + +func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { + err := self.RemoveRoute(route) + if err != nil { + return errors.Wrap(err, "self.RemoveRoute(route)") + } + err = self.CreateRoute(route) + if err != nil { + return errors.Wrap(err, "self.CreateRoute(route)") + } + return nil +} + +func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { + return []cloudprovider.RouteTableAssociation{} +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/saml_provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/saml_provider.go new file mode 100644 index 0000000000..b66114755c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/saml_provider.go @@ -0,0 +1,367 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "time" + "unicode" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/stringutils" + + api "yunion.io/x/cloudmux/pkg/apis/cloudid" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/modules" + "yunion.io/x/onecloud/pkg/util/samlutils" +) + +type SAMLProviderLinks struct { + Self string + Protocols string +} + +type SAMLProvider struct { + multicloud.SResourceBase + HuaweiTags + client *SHuaweiClient + + Id string + Links SAMLProviderLinks + Description string +} + +func (self *SAMLProvider) GetId() string { + return self.Id +} + +func (self *SAMLProvider) GetGlobalId() string { + return self.Id +} + +func (self *SAMLProvider) GetName() string { + return self.Id +} + +func (self *SAMLProvider) GetStatus() string { + mapping, _ := self.client.findMapping() + if mapping != nil { + return api.SAML_PROVIDER_STATUS_AVAILABLE + } + return api.SAML_PROVIDER_STATUS_UNVALIABLE +} + +func (self *SAMLProvider) GetAuthUrl() string { + return fmt.Sprintf("https://auth.huaweicloud.com/authui/federation/websso?domain_id=%s&idp=%s&protocol=saml", self.client.ownerId, self.Id) +} + +func (self *SAMLProvider) Delete() error { + return self.client.DeleteSAMLProvider(self.Id) +} + +func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { + info, err := self.client.GetSAMLProviderMetadata(self.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetSAMLProviderMetadata(%s)", self.Id) + } + metadata, err := samlutils.ParseMetadata([]byte(info.Data)) + if err != nil { + return nil, errors.Wrapf(err, "ParseMetadata") + } + return &metadata, nil +} + +func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { + return self.client.UpdateSAMLProviderMetadata(self.Id, metadata.String()) +} + +func (self *SHuaweiClient) ListSAMLProviders() ([]SAMLProvider, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrapf(err, "newGeneralAPIClient") + } + samls := []SAMLProvider{} + err = doListAllWithNextLink(client.SAMLProviders.List, nil, &samls) + if err != nil { + return nil, errors.Wrapf(err, "doListAll") + } + return samls, nil +} + +type SAMLProviderProtocol struct { + MappingId string + Id string +} + +func (self *SHuaweiClient) GetSAMLProviderProtocols(id string) ([]SAMLProviderProtocol, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + resp, err := client.SAMLProviders.ListInContextWithSpec(nil, fmt.Sprintf("%s/protocols", id), nil, "protocols") + if err != nil { + return nil, errors.Wrapf(err, "ListInContextWithSpec") + } + protocols := []SAMLProviderProtocol{} + return protocols, jsonutils.Update(&protocols, resp.Data) +} + +func (self *SHuaweiClient) DeleteSAMLProviderProtocol(spId, id string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + _, err = client.SAMLProviders.DeleteInContextWithSpec(nil, spId, fmt.Sprintf("protocols/%s", id), nil, nil, "") + return err +} + +type SAMLProviderMetadata struct { + DomainId string + UpdateTime time.Time + Data string + IdpId string + ProtocolId string + Id string + EntityId string + XaccountType string +} + +func (self *SHuaweiClient) GetSAMLProviderMetadata(id string) (*SAMLProviderMetadata, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION") + resp, err := client.SAMLProviders.GetInContextWithSpec(nil, id, fmt.Sprintf("protocols/saml/metadata"), nil, "") + if err != nil { + return nil, err + } + + metadata := &SAMLProviderMetadata{} + err = resp.Unmarshal(metadata) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return metadata, nil +} + +func (self *SHuaweiClient) UpdateSAMLProviderMetadata(id, metadata string) error { + params := map[string]string{ + "domain_id": self.ownerId, + "xaccount_type": "", + "metadata": metadata, + } + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + client.SAMLProviders.SetVersion("v3-ext/OS-FEDERATION") + _, err = client.SAMLProviders.PerformAction2("protocols/saml/metadata", id, jsonutils.Marshal(params), "") + if err != nil { + return errors.Wrapf(err, "SAMLProvider.PerformAction") + } + return nil +} + +func (self *SHuaweiClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { + samls, err := self.ListSAMLProviders() + if err != nil { + return nil, errors.Wrapf(err, "ListSAMLProviders") + } + ret := []cloudprovider.ICloudSAMLProvider{} + for i := range samls { + samls[i].client = self + ret = append(ret, &samls[i]) + } + return ret, nil +} + +func (self *SHuaweiClient) DeleteSAMLProvider(id string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + _, err = client.SAMLProviders.Delete(id, nil) + return err +} + +func (self *SHuaweiClient) CreateSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (*SAMLProvider, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + params := jsonutils.Marshal(map[string]interface{}{ + "identity_provider": map[string]interface{}{ + "description": opts.Name, + "enabled": true, + }, + }) + name := []byte{} + for _, c := range opts.Name { + if unicode.IsLetter(c) || unicode.IsNumber(c) || c == '-' || c == '_' { + name = append(name, byte(c)) + } else { + name = append(name, '-') + } + } + samlName := string(name) + err = func() error { + idx := 1 + for { + _, err = client.SAMLProviders.Update(samlName, params) + if err == nil { + return nil + } + he, ok := err.(*modules.HuaweiClientError) + if !ok { + return errors.Wrapf(err, "SAMLProviders.Update") + } + if he.Code != 409 { + return errors.Wrapf(err, "SAMLProviders.Update") + } + samlName = fmt.Sprintf("%s-%d", string(name), idx) + idx++ + if idx >= 40 { + break + } + } + return err + }() + if err != nil { + return nil, errors.Wrapf(err, "saml provider create") + } + ret := SAMLProvider{client: self, Id: samlName} + err = self.UpdateSAMLProviderMetadata(samlName, opts.Metadata.String()) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + err = self.InitSAMLProviderMapping(samlName) + if err != nil { + return nil, errors.Wrapf(err, "InitSAMLProviderMapping") + } + return &ret, nil +} + +type SAMLProviderMapping struct { + Id string + Rules jsonutils.JSONObject +} + +var ( + onecloudMappingRules = jsonutils.Marshal(map[string]interface{}{ + "rules": []map[string]interface{}{ + { + "remote": []map[string]interface{}{ + { + "type": "User", + }, + { + "type": "Groups", + }, + }, + "local": []map[string]interface{}{ + { + "groups": "{1}", + "user": map[string]string{"name": "{0}"}, + }, + }, + }, + }, + }) +) + +func (self *SHuaweiClient) ListSAMLProviderMappings() ([]SAMLProviderMapping, error) { + client, err := self.newGeneralAPIClient() + if err != nil { + return nil, errors.Wrap(err, "newGeneralAPIClient") + } + mappings := []SAMLProviderMapping{} + err = doListAllWithNextLink(client.SAMLProviderMappings.List, nil, &mappings) + if err != nil { + return nil, err + } + return mappings, nil +} + +func (self *SHuaweiClient) findMapping() (*SAMLProviderMapping, error) { + mappings, err := self.ListSAMLProviderMappings() + if err != nil { + return nil, errors.Wrapf(err, "ListSAMLProviderMappings") + } + for i := range mappings { + if jsonutils.Marshal(map[string]interface{}{"rules": mappings[i].Rules}).Equals(jsonutils.Marshal(onecloudMappingRules)) { + return &mappings[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHuaweiClient) InitSAMLProviderMapping(spId string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + + mapping, err := self.findMapping() + if err != nil { + if errors.Cause(err) != cloudprovider.ErrNotFound { + return errors.Wrapf(err, "findMapping") + } + mappingId := stringutils.UUID4() + params := map[string]interface{}{ + "mapping": onecloudMappingRules, + } + _, err = client.SAMLProviderMappings.Update(mappingId, jsonutils.Marshal(params)) + if err != nil { + return errors.Wrapf(err, "create mapping") + } + mapping = &SAMLProviderMapping{ + Id: mappingId, + Rules: onecloudMappingRules, + } + } + protocols, err := self.GetSAMLProviderProtocols(spId) + if err != nil { + return errors.Wrapf(err, "GetSAMLProviderProtocols") + } + params := map[string]interface{}{ + "protocol": map[string]string{ + "mapping_id": mapping.Id, + }, + } + for i := range protocols { + if protocols[i].Id == "saml" { + if protocols[i].MappingId == mapping.Id { + return nil + } + _, err = client.SAMLProviders.PatchInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "") + return err + } + } + _, err = client.SAMLProviders.UpdateInContextWithSpec(nil, spId, "protocols/saml", jsonutils.Marshal(params), "") + return err +} + +func (self *SHuaweiClient) DeleteSAMLProviderMapping(id string) error { + client, err := self.newGeneralAPIClient() + if err != nil { + return errors.Wrap(err, "newGeneralAPIClient") + } + + _, err = client.SAMLProviderMappings.Delete(id, nil) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/securitygroup.go new file mode 100644 index 0000000000..869e5537d8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/securitygroup.go @@ -0,0 +1,275 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +/* +https://support.huaweicloud.com/usermanual-vpc/zh-cn_topic_0073379079.html +安全组的限制 +默认情况下,一个用户可以创建100个安全组。 +默认情况下,一个安全组最多只允许拥有50条安全组规则。 +默认情况下,一个弹性云服务器或辅助网卡最多只能被添加到5个安全组中。 +在创建私网弹性负载均衡时,需要选择弹性负载均衡所在的安全组。请勿删除默认规则或者确保满足以下规则: +出方向:允许发往同一个安全组的报文可以通过,或者允许对端负载均衡器报文通过。 +入方向:允许来自同一个安全组的报文可以通过,或者允许对端负载均衡器报文通过。 +*/ + +import ( + "net" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SecurityGroupRule struct { + Direction string `json:"direction"` + Ethertype string `json:"ethertype"` + ID string `json:"id"` + Description string `json:"description"` + SecurityGroupID string `json:"security_group_id"` + RemoteGroupID string `json:"remote_group_id"` +} + +type SecurityGroupRuleDetail struct { + Direction string `json:"direction"` + Ethertype string `json:"ethertype"` + ID string `json:"id"` + Description string `json:"description"` + PortRangeMax int64 `json:"port_range_max"` + PortRangeMin int64 `json:"port_range_min"` + Protocol string `json:"protocol"` + RemoteGroupID string `json:"remote_group_id"` + RemoteIPPrefix string `json:"remote_ip_prefix"` + SecurityGroupID string `json:"security_group_id"` + TenantID string `json:"tenant_id"` +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090615.html +type SSecurityGroup struct { + multicloud.SSecurityGroup + HuaweiTags + region *SRegion + + ID string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + VpcID string `json:"vpc_id"` + EnterpriseProjectID string `json:"enterprise_project_id "` + SecurityGroupRules []SecurityGroupRule `json:"security_group_rules"` +} + +// 判断是否兼容云端安全组规则 +func compatibleSecurityGroupRule(r SecurityGroupRule) bool { + // 忽略了源地址是安全组的规则 + if len(r.RemoteGroupID) > 0 { + return false + } + + // 忽略IPV6 + if r.Ethertype == "IPv6" { + return false + } + + return true +} + +func (self *SSecurityGroup) GetId() string { + return self.ID +} + +func (self *SSecurityGroup) GetVpcId() string { + return api.NORMAL_VPC_ID +} + +func (self *SSecurityGroup) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.ID +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.ID +} + +func (self *SSecurityGroup) GetStatus() string { + return "" +} + +func (self *SSecurityGroup) Refresh() error { + if new, err := self.region.GetSecurityGroupDetails(self.GetId()); err != nil { + return err + } else { + return jsonutils.Update(self, new) + } +} + +func (self *SSecurityGroup) IsEmulated() bool { + return false +} + +func (self *SSecurityGroup) GetDescription() string { + if self.Description == self.VpcID { + return "" + } + return self.Description +} + +// todo: 这里需要优化查询太多了 +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + rules := make([]cloudprovider.SecurityRule, 0) + for _, r := range self.SecurityGroupRules { + if !compatibleSecurityGroupRule(r) { + continue + } + + rule, err := self.GetSecurityRule(r.ID) + if err != nil { + return rules, err + } + + rules = append(rules, rule) + } + + return rules, nil +} + +func (self *SSecurityGroup) GetSecurityRule(ruleId string) (cloudprovider.SecurityRule, error) { + remoteRule := SecurityGroupRuleDetail{} + err := DoGet(self.region.ecsClient.SecurityGroupRules.Get, ruleId, nil, &remoteRule) + if err != nil { + return cloudprovider.SecurityRule{}, err + } + + var direction secrules.TSecurityRuleDirection + if remoteRule.Direction == "ingress" { + direction = secrules.SecurityRuleIngress + } else { + direction = secrules.SecurityRuleEgress + } + + protocol := secrules.PROTO_ANY + if remoteRule.Protocol != "" { + protocol = remoteRule.Protocol + } + + var portStart int + var portEnd int + if protocol == secrules.PROTO_ICMP { + portStart = -1 + portEnd = -1 + } else { + portStart = int(remoteRule.PortRangeMin) + portEnd = int(remoteRule.PortRangeMax) + } + + ipNet := &net.IPNet{} + if len(remoteRule.RemoteIPPrefix) > 0 { + _, ipNet, err = net.ParseCIDR(remoteRule.RemoteIPPrefix) + } else { + _, ipNet, err = net.ParseCIDR("0.0.0.0/0") + } + + if err != nil { + return cloudprovider.SecurityRule{}, err + } + + rule := cloudprovider.SecurityRule{ + ExternalId: ruleId, + SecurityRule: secrules.SecurityRule{ + Priority: 1, + Action: secrules.SecurityRuleAllow, + IPNet: ipNet, + Protocol: protocol, + Direction: direction, + PortStart: portStart, + PortEnd: portEnd, + Ports: nil, + Description: remoteRule.Description, + }, + } + + err = rule.ValidateRule() + return rule, err +} + +func (self *SRegion) GetSecurityGroupDetails(secGroupId string) (*SSecurityGroup, error) { + securitygroup := SSecurityGroup{} + err := DoGet(self.ecsClient.SecurityGroups.Get, secGroupId, nil, &securitygroup) + if err != nil { + return nil, err + } + + securitygroup.region = self + return &securitygroup, err +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090617.html +func (self *SRegion) GetSecurityGroups(vpcId string, name string) ([]SSecurityGroup, error) { + querys := map[string]string{} + if len(vpcId) > 0 && !utils.IsInStringArray(vpcId, []string{"default", api.NORMAL_VPC_ID}) { // vpc_id = default or normal 时报错 '{"code":"VPC.0601","message":"Query security groups error vpcId is invalid."}' + querys["vpc_id"] = vpcId + } + + securitygroups := make([]SSecurityGroup, 0) + err := doListAllWithMarker(self.ecsClient.SecurityGroups.List, querys, &securitygroups) + if err != nil { + return nil, err + } + + // security 中的vpc字段只是一个标识,实际可以跨vpc使用 + for i := range securitygroups { + securitygroup := &securitygroups[i] + securitygroup.region = self + } + + result := []SSecurityGroup{} + for _, secgroup := range securitygroups { + if len(name) == 0 || secgroup.Name == name { + result = append(result, secgroup) + } + } + + return result, nil +} + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} + +func (self *SSecurityGroup) Delete() error { + return self.region.DeleteSecurityGroup(self.ID) +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + for _, r := range append(inDels, outDels...) { + err := self.region.delSecurityGroupRule(r.ExternalId) + if err != nil { + return errors.Wrapf(err, "delSecurityGroupRule(%s %s)", r.ExternalId, r.String()) + } + } + for _, r := range append(inAdds, outAdds...) { + err := self.region.addSecurityGroupRules(self.ID, r) + if err != nil { + return errors.Wrapf(err, "addSecurityGroupRule(%d %s)", r.Priority, r.String()) + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/sfs-turbo.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/sfs-turbo.go new file mode 100644 index 0000000000..023997b2d7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/sfs-turbo.go @@ -0,0 +1,298 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SfsTurbo struct { + multicloud.SNasBase + HuaweiTags + region *SRegion + + EnterpriseProjectId string + Actions []string + AvailCapacity float64 + AvailabilityZone string + AzName string + CreatedAt time.Time + CryptKeyId string + ExpandType string + ExportLocation string + Id string + Name string + PayModel string + Region string + SecurityGroupId string + ShareProto string + ShareType string + Size float64 + Status string + SubStatus string + SubnetId string + VpcId string + Description string +} + +func (self *SfsTurbo) GetName() string { + return self.Name +} + +func (self *SfsTurbo) GetId() string { + return self.Id +} + +func (self *SfsTurbo) GetGlobalId() string { + return self.Id +} + +func (self *SfsTurbo) GetFileSystemType() string { + return "SFS Turbo" +} + +func (self *SfsTurbo) Refresh() error { + sf, err := self.region.GetSfsTurbo(self.Id) + if err != nil { + return errors.Wrapf(err, "GetSfsTurbo") + } + return jsonutils.Update(self, sf) +} + +func (self *SfsTurbo) GetBillingType() string { + if self.PayModel == "0" { + return billing_api.BILLING_TYPE_POSTPAID + } + return billing_api.BILLING_TYPE_PREPAID +} + +func (self *SfsTurbo) GetStorageType() string { + if len(self.ExpandType) == 0 { + return strings.ToLower(self.ShareType) + } + return strings.ToLower(self.ShareType) + ".enhanced" +} + +func (self *SfsTurbo) GetProtocol() string { + return self.ShareProto +} + +func (self *SfsTurbo) GetStatus() string { + switch self.Status { + case "100": + return api.NAS_STATUS_CREATING + case "200": + return api.NAS_STATUS_AVAILABLE + case "300": + return api.NAS_STATUS_UNKNOWN + case "303": + return api.NAS_STATUS_CREATE_FAILED + case "400": + return api.NAS_STATUS_DELETING + case "800": + return api.NAS_STATUS_UNAVAILABLE + default: + return self.Status + } +} + +func (self *SfsTurbo) GetCreatedAt() time.Time { + return self.CreatedAt +} + +func (self *SfsTurbo) GetCapacityGb() int64 { + return int64(self.Size) +} + +func (self *SfsTurbo) GetUsedCapacityGb() int64 { + return int64(self.Size - self.AvailCapacity) +} + +func (self *SfsTurbo) GetMountTargetCountLimit() int { + return 1 +} + +func (self *SfsTurbo) GetZoneId() string { + return self.AvailabilityZone +} + +func (self *SfsTurbo) GetMountTargets() ([]cloudprovider.ICloudMountTarget, error) { + mt := &sMoutTarget{sfs: self} + return []cloudprovider.ICloudMountTarget{mt}, nil +} + +func (self *SfsTurbo) CreateMountTarget(opts *cloudprovider.SMountTargetCreateOptions) (cloudprovider.ICloudMountTarget, error) { + return nil, errors.Wrap(cloudprovider.ErrNotSupported, "CreateMountTarget") +} + +func (self *SfsTurbo) Delete() error { + return self.region.DeleteSfsTurbo(self.Id) +} + +func (self *SRegion) GetICloudFileSystems() ([]cloudprovider.ICloudFileSystem, error) { + sfs, err := self.GetSfsTurbos() + if err != nil { + return nil, errors.Wrapf(err, "self.GetSfsTurbos") + } + ret := []cloudprovider.ICloudFileSystem{} + for i := range sfs { + sfs[i].region = self + ret = append(ret, &sfs[i]) + } + return ret, nil +} + +func (self *SRegion) GetICloudFileSystemById(id string) (cloudprovider.ICloudFileSystem, error) { + sf, err := self.GetSfsTurbo(id) + if err != nil { + return nil, errors.Wrapf(err, "GetSfsTurbo(%s)", id) + } + return sf, nil +} + +func (self *SRegion) GetSfsTurbos() ([]SfsTurbo, error) { + queues := make(map[string]string) + sfs := make([]SfsTurbo, 0, 2) + err := doListAllWithOffset(self.ecsClient.SfsTurbos.List, queues, &sfs) + if err != nil { + return nil, errors.Wrapf(err, "doListAllWithOffset") + } + return sfs, nil +} + +func (self *SRegion) GetSfsTurbo(id string) (*SfsTurbo, error) { + sf := &SfsTurbo{region: self} + err := DoGet(self.ecsClient.SfsTurbos.Get, id, nil, &sf) + return sf, errors.Wrapf(err, "self.ecsClient.SfsTurbos.Get") +} + +func (self *SRegion) DeleteSfsTurbo(id string) error { + return DoDelete(self.ecsClient.SfsTurbos.Delete, id, nil, nil) +} + +func (self *SRegion) GetSysDefaultSecgroupId() (string, error) { + secs, err := self.GetSecurityGroups("default", "") + if err != nil { + return "", errors.Wrapf(err, "GetSecurityGroups") + } + if len(secs) > 0 { + return secs[0].ID, nil + } + return "", fmt.Errorf("not found default security group") +} + +func (self *SRegion) CreateICloudFileSystem(opts *cloudprovider.FileSystemCraeteOptions) (cloudprovider.ICloudFileSystem, error) { + fs, err := self.CreateSfsTurbo(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateSfsTurbo") + } + return fs, nil +} + +func (self *SRegion) CreateSfsTurbo(opts *cloudprovider.FileSystemCraeteOptions) (*SfsTurbo, error) { + secId, err := self.GetSysDefaultSecgroupId() + if err != nil { + return nil, errors.Wrapf(err, "GetSysDefaultSecgroupId") + } + metadata := map[string]string{} + if strings.HasSuffix(opts.StorageType, ".enhanced") { + metadata["expand_type"] = "bandwidth" + } + params := map[string]interface{}{ + "share": map[string]interface{}{ + "name": opts.Name, + "share_proto": strings.ToUpper(opts.Protocol), + "share_type": strings.ToUpper(strings.TrimSuffix(opts.StorageType, ".enhanced")), + "size": opts.Capacity, + "availability_zone": opts.ZoneId, + "vpc_id": opts.VpcId, + "subnet_id": opts.NetworkId, + "security_group_id": secId, + "description": opts.Desc, + "metadata": metadata, + }, + } + resp, err := self.ecsClient.SfsTurbos.Create(jsonutils.Marshal(params)) + if err != nil { + return nil, errors.Wrapf(err, "Create") + } + id, err := resp.GetString("id") + if err != nil { + return nil, errors.Wrapf(err, "resp.GetString(id)") + } + return self.GetSfsTurbo(id) +} + +func (self *SRegion) GetICloudAccessGroups() ([]cloudprovider.ICloudAccessGroup, error) { + return []cloudprovider.ICloudAccessGroup{}, nil +} + +func (self *SRegion) CreateICloudAccessGroup(opts *cloudprovider.SAccessGroup) (cloudprovider.ICloudAccessGroup, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "CreateICloudAccessGroup") +} + +func (self *SRegion) GetICloudAccessGroupById(id string) (cloudprovider.ICloudAccessGroup, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetICloudAccessGroupById(%s)", id) +} + +type sMoutTarget struct { + sfs *SfsTurbo +} + +func (self *sMoutTarget) GetName() string { + return self.sfs.Name +} + +func (self *sMoutTarget) GetGlobalId() string { + return self.sfs.GetGlobalId() +} + +func (self *sMoutTarget) GetAccessGroupId() string { + return "" +} + +func (self *sMoutTarget) GetDomainName() string { + return self.sfs.ExportLocation +} + +func (self *sMoutTarget) GetNetworkType() string { + return api.NETWORK_TYPE_VPC +} + +func (self *sMoutTarget) GetNetworkId() string { + return self.sfs.SubnetId +} + +func (self *sMoutTarget) GetVpcId() string { + return self.sfs.VpcId +} + +func (self *sMoutTarget) GetStatus() string { + return api.MOUNT_TARGET_STATUS_AVAILABLE +} + +func (self *sMoutTarget) Delete() error { + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/snapshot.go new file mode 100644 index 0000000000..566851157e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/snapshot.go @@ -0,0 +1,189 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +/* +限制: +https://support.huaweicloud.com/api-evs/zh-cn_topic_0058762427.html +1. 从快照创建云硬盘时,volume_type字段必须和快照源云硬盘保持一致。 +2. 当指定的云硬盘类型在avaliability_zone内不存在时,则创建云硬盘失败。 +*/ + +type SnapshotStatusType string + +const ( + SnapshotStatusCreating SnapshotStatusType = "creating" + SnapshotStatusAvailable SnapshotStatusType = "available" // 云硬盘快照创建成功,可以使用。 + SnapshotStatusError SnapshotStatusType = "error" // 云硬盘快照在创建过程中出现错误。 + SnapshotStatusDeleting SnapshotStatusType = "deleting" // 云硬盘快照处于正在删除的过程中。 + SnapshotStatusErrorDeleting SnapshotStatusType = "error_deleting" // 云硬盘快照在删除过程中出现错误 + SnapshotStatusRollbacking SnapshotStatusType = "rollbacking" // 云硬盘快照处于正在回滚数据的过程中。 + SnapshotStatusBackingUp SnapshotStatusType = "backing-up" // 通过快照创建备份,快照状态就会变为backing-up +) + +type Metadata struct { + SystemEnableActive string `json:"__system__enableActive"` // 如果为true。则表明是系统盘快照 +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html +type SSnapshot struct { + multicloud.SResourceBase + HuaweiTags + region *SRegion + + Metadata Metadata `json:"metadata"` + CreatedAt string `json:"created_at"` + Description string `json:"description"` + ID string `json:"id"` + Name string `json:"name"` + OSExtendedSnapshotAttributesProgress string `json:"os-extended-snapshot-attributes:progress"` + OSExtendedSnapshotAttributesProjectID string `json:"os-extended-snapshot-attributes:project_id"` + Size int32 `json:"size"` // GB + Status string `json:"status"` + UpdatedAt string `json:"updated_at"` + VolumeID string `json:"volume_id"` +} + +func (self *SSnapshot) GetId() string { + return self.ID +} + +func (self *SSnapshot) GetName() string { + return self.Name +} + +func (self *SSnapshot) GetGlobalId() string { + return self.ID +} + +func (self *SSnapshot) GetStatus() string { + switch SnapshotStatusType(self.Status) { + case SnapshotStatusAvailable: + return api.SNAPSHOT_READY + case SnapshotStatusCreating: + return api.SNAPSHOT_CREATING + case SnapshotStatusDeleting: + return api.SNAPSHOT_DELETING + case SnapshotStatusErrorDeleting, SnapshotStatusError: + return api.SNAPSHOT_FAILED + case SnapshotStatusRollbacking: + return api.SNAPSHOT_ROLLBACKING + default: + return api.SNAPSHOT_UNKNOWN + } +} + +func (self *SSnapshot) Refresh() error { + snapshot, err := self.region.GetSnapshotById(self.GetId()) + if err != nil { + return err + } + + if err := jsonutils.Update(self, snapshot); err != nil { + return err + } + + return nil +} + +func (self *SSnapshot) IsEmulated() bool { + return false +} + +func (self *SSnapshot) GetSizeMb() int32 { + return self.Size * 1024 +} + +func (self *SSnapshot) GetDiskId() string { + return self.VolumeID +} + +func (self *SSnapshot) GetDiskType() string { + if self.Metadata.SystemEnableActive == "true" { + return api.DISK_TYPE_SYS + } else { + return api.DISK_TYPE_DATA + } +} + +func (self *SSnapshot) Delete() error { + if self.region == nil { + return fmt.Errorf("not init region for snapshot %s", self.GetId()) + } + return self.region.DeleteSnapshot(self.GetId()) +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408627.html +func (self *SRegion) GetSnapshots(diskId string, snapshotName string) ([]SSnapshot, error) { + params := make(map[string]string) + + if len(diskId) > 0 { + params["volume_id"] = diskId + } + + if len(snapshotName) > 0 { + params["name"] = snapshotName + } + + snapshots := make([]SSnapshot, 0) + err := doListAllWithOffset(self.ecsClient.Snapshots.List, params, &snapshots) + for i := range snapshots { + snapshots[i].region = self + } + + return snapshots, err +} + +func (self *SRegion) GetSnapshotById(snapshotId string) (SSnapshot, error) { + var snapshot SSnapshot + err := DoGet(self.ecsClient.Snapshots.Get, snapshotId, nil, &snapshot) + snapshot.region = self + return snapshot, err +} + +// 不能删除以autobk_snapshot_为前缀的快照。 +// 当快照状态为available、error状态时,才可以删除。 +func (self *SRegion) DeleteSnapshot(snapshotId string) error { + return DoDelete(self.ecsClient.Snapshots.Delete, snapshotId, nil, nil) +} + +// https://support.huaweicloud.com/api-evs/zh-cn_topic_0051408624.html +// 目前已设置force字段。云硬盘处于挂载状态时,能强制创建快照。 +func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { + params := jsonutils.NewDict() + snapshotObj := jsonutils.NewDict() + snapshotObj.Add(jsonutils.NewString(name), "name") + snapshotObj.Add(jsonutils.NewString(desc), "description") + snapshotObj.Add(jsonutils.NewString(diskId), "volume_id") + snapshotObj.Add(jsonutils.JSONTrue, "force") + params.Add(snapshotObj, "snapshot") + + snapshot := SSnapshot{} + err := DoCreate(self.ecsClient.Snapshots.Create, params, &snapshot) + return snapshot.ID, err +} + +func (self *SSnapshot) GetProjectId() string { + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storage.go new file mode 100644 index 0000000000..40770f94a4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storage.go @@ -0,0 +1,161 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStorage struct { + zone *SZone + multicloud.SStorageBase + HuaweiTags + storageType string // volume_type 目前支持“SSD”,“SAS”和“SATA”三种 +} + +func (self *SStorage) GetId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetName() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetGlobalId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) Refresh() error { + return nil +} + +func (self *SStorage) IsEmulated() bool { + return true +} + +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, err := self.zone.region.GetDisks(self.zone.GetId()) + if err != nil { + return nil, err + } + + // 按storage type 过滤出disk + filtedDisks := make([]SDisk, 0) + for i := range disks { + disk := disks[i] + if disk.VolumeType == self.storageType { + filtedDisks = append(filtedDisks, disk) + } + } + + idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) + for i := 0; i < len(filtedDisks); i += 1 { + filtedDisks[i].storage = self + idisks[i] = &filtedDisks[i] + } + return idisks, nil +} + +func (self *SStorage) GetStorageType() string { + return self.storageType +} + +func (self *SStorage) GetMediumType() string { + if self.storageType == api.STORAGE_HUAWEI_SSD { + return api.DISK_TYPE_SSD + } else { + return api.DISK_TYPE_ROTATE + } +} + +func (self *SStorage) GetCapacityMB() int64 { + return 0 // unlimited +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + return conf +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + diskId, err := self.zone.region.CreateDisk(self.zone.GetId(), self.storageType, conf.Name, conf.SizeGb, "", conf.Desc, conf.ProjectId) + 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 + + err = cloudprovider.WaitStatus(disk, api.DISK_READY, 5*time.Second, 120*time.Second) + if err != nil { + return nil, err + } + + return disk, nil +} + +func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + if len(idStr) == 0 { + log.Debugf("GetIDiskById disk id should not be empty") + return nil, cloudprovider.ErrNotFound + } + + if disk, err := self.zone.region.GetDisk(idStr); err != nil { + return nil, err + } else { + disk.storage = self + return disk, nil + } +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storagecache.go new file mode 100644 index 0000000000..2ac7e087f2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/storagecache.go @@ -0,0 +1,302 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "context" + "fmt" + "math" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +type SStoragecache struct { + multicloud.SResourceBase + HuaweiTags + region *SRegion +} + +func GetBucketName(regionId string, imageId string) string { + return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), imageId) +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) +} + +func (self *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) +} + +func (self *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, 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) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + imagesSelf, err := self.region.GetImages("", ImageOwnerSelf, "", EnvFusionCompute) + if err != nil { + return nil, errors.Wrapf(err, "GetImages") + } + + ret := []cloudprovider.ICloudImage{} + for i := range imagesSelf { + imagesSelf[i].storageCache = self + ret = append(ret, &imagesSelf[i]) + } + return ret, nil +} + +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + image, err := self.region.GetImage(extId) + if err != nil { + return nil, errors.Wrap(err, "self.region.GetImage") + } + image.storageCache = self + return image, nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +// 目前支持使用vhd、zvhd、vmdk、qcow2、raw、zvhd2、vhdx、qcow、vdi或qed格式镜像文件创建私有镜像。 +// 快速通道功能可快速完成镜像制作,但镜像文件需转换为raw或zvhd2格式并完成镜像优化。 +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0083905788.html +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 + 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) downloadImage(userCred mcclient.TokenCredential, imageId string, extId string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return self.uploadImage(ctx, userCred, image, callback) +} + +func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + bucketName := GetBucketName(self.region.GetId(), image.ImageId) + + exist, _ := self.region.IBucketExist(bucketName) + if !exist { + err := self.region.CreateIBucket(bucketName, "", "") + if err != nil { + return "", errors.Wrap(err, "CreateIBucket") + } + } + defer self.region.DeleteIBucket(bucketName) + + // upload to huawei cloud + s := auth.GetAdminSession(ctx, options.Options.Region) + meta, reader, sizeByte, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) + if err != nil { + return "", errors.Wrap(err, "Images.Download") + } + log.Debugf("Images meta data %s", meta) + + minDiskMB, _ := meta.Int("min_disk") + minDiskGB := int64(math.Ceil(float64(minDiskMB) / 1024)) + // 在使用OBS桶的外部镜像文件制作镜像时生效且为必选字段。取值为40~1024GB。 + if minDiskGB < 40 { + minDiskGB = 40 + } else if minDiskGB > 1024 { + minDiskGB = 1024 + } + + bucket, err := self.region.GetIBucketByName(bucketName) + if err != nil { + return "", errors.Wrapf(err, "GetIBucketByName %s", bucketName) + } + + body := multicloud.NewProgress(sizeByte, 95, reader, callback) + err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeByte, "", "", nil, false) + if err != nil { + return "", errors.Wrap(err, "cloudprovider.UploadObject") + } + + defer bucket.DeleteObject(context.Background(), image.ImageId) + + // check image name, avoid name conflict + imageBaseName := image.ImageId + if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { + imageBaseName = fmt.Sprintf("img%s", image.ImageId) + } + imageName := imageBaseName + nameIdx := 1 + + for { + _, err = self.region.GetImageByName(imageName) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + break + } else { + return "", err + } + } + + imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) + nameIdx += 1 + log.Debugf("uploadImage Match remote name %s", imageName) + } + + jobId, err := self.region.ImportImageJob(imageName, image.OsDistribution, image.OsVersion, image.OsArch, bucketName, image.ImageId, int64(minDiskGB)) + + if err != nil { + log.Errorf("ImportImage error %s %s %s %s", jobId, image.ImageId, bucketName, err) + return "", err + } + + // timeout: 1hour = 3600 seconds + serviceType := self.region.ecsClient.Images.ServiceType() + err = self.region.waitTaskStatus(serviceType, jobId, TASK_SUCCESS, 15*time.Second, 3600*time.Second) + if err != nil { + log.Errorf("waitTaskStatus %s", err) + return "", err + } + + if callback != nil { + callback(100) + } + + // https://support.huaweicloud.com/api-ims/zh-cn_topic_0022473688.html + return self.region.GetTaskEntityID(serviceType, jobId, "image_id") +} + +func (self *SRegion) getStoragecache() *SStoragecache { + if self.storageCache == nil { + self.storageCache = &SStoragecache{region: self} + } + return self.storageCache +} + +type SJob struct { + Status string `json:"status"` + Entities map[string]string `json:"entities"` + JobID string `json:"job_id"` + JobType string `json:"job_type"` + BeginTime string `json:"begin_time"` + EndTime string `json:"end_time"` + ErrorCode string `json:"error_code"` + FailReason string `json:"fail_reason"` +} + +// https://support.huaweicloud.com/api-ims/zh-cn_topic_0020092109.html +func (self *SRegion) createIImage(snapshotId, imageName, imageDesc string) (string, error) { + snapshot, err := self.GetSnapshotById(snapshotId) + if err != nil { + return "", err + } + + disk, err := self.GetDisk(snapshot.VolumeID) + if err != nil { + return "", err + } + + if disk.GetDiskType() != api.DISK_TYPE_SYS { + return "", fmt.Errorf("disk type err, expected disk type %s", api.DISK_TYPE_SYS) + } + + if len(disk.Attachments) == 0 { + return "", fmt.Errorf("disk is not attached.") + } + + imageObj := jsonutils.NewDict() + imageObj.Add(jsonutils.NewString(disk.Attachments[0].ServerID), "instance_id") + imageObj.Add(jsonutils.NewString(imageName), "name") + imageObj.Add(jsonutils.NewString(imageDesc), "description") + + ret, err := self.ecsClient.Images.PerformAction2("action", "", imageObj, "") + if err != nil { + return "", err + } + + job := SJob{} + jobId, err := ret.GetString("job_id") + querys := map[string]string{"service_type": self.ecsClient.Images.ServiceType()} + err = DoGet(self.ecsClient.Jobs.Get, jobId, querys, &job) + if err != nil { + return "", err + } + + if job.Status == "SUCCESS" { + imageId, exists := job.Entities["image_id"] + if exists { + return imageId, nil + } else { + return "", fmt.Errorf("image id not found in create image job %s", job.JobID) + } + } else { + return "", fmt.Errorf("create image failed, %s", job.FailReason) + } + +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + return []cloudprovider.ICloudStoragecache{storageCache}, nil +} + +func (self *SRegion) GetIStoragecacheById(idstr string) (cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + if storageCache.GetGlobalId() == idstr { + return storageCache, nil + } + return nil, cloudprovider.ErrNotFound +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/tag_base.go new file mode 100644 index 0000000000..c5a469ac71 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/tag_base.go @@ -0,0 +1,62 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type HuaweiTags struct { + Tags []string +} + +func (self *HuaweiTags) GetTags() (map[string]string, error) { + tags := map[string]string{} + for _, kv := range self.Tags { + splited := strings.Split(kv, "=") + if len(splited) == 2 { + tags[splited[0]] = splited[1] + } + } + return tags, nil +} + +func (self *HuaweiTags) GetSysTags() map[string]string { + return nil +} + +func (self *HuaweiTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} + +type HuaweiDiskTags struct { + Tags map[string]string +} + +func (self *HuaweiDiskTags) GetTags() (map[string]string, error) { + return self.Tags, nil +} + +func (self *HuaweiDiskTags) GetSysTags() map[string]string { + return nil +} + +func (self *HuaweiDiskTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/pkg/multicloud/huawei/task.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/task.go similarity index 100% rename from pkg/multicloud/huawei/task.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/task.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/traces.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/traces.go new file mode 100644 index 0000000000..4b6f549072 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/traces.go @@ -0,0 +1,131 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "strconv" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SUser struct { + Domain map[string]string + Name string + Id string +} + +type SEvent struct { + TraceId string + Code string + TraceName string + ResourceType string + ApiVersion string + SourceIp string + TraceType string + ServiceType string + EventType string + ProjectId string + Request string + Response string + TrackerName string + TraceStatus string + Time int64 + ResourceId string + ResourceName string + User SUser + RecordTime int64 +} + +func (event *SEvent) GetName() string { + if len(event.ResourceName) > 0 { + return event.ResourceName + } + if len(event.ResourceId) > 0 { + return event.ResourceId + } + return event.TraceName +} + +func (event *SEvent) GetService() string { + return event.ServiceType +} + +func (event *SEvent) GetAction() string { + return event.TraceName +} + +func (event *SEvent) GetResourceType() string { + return event.ResourceType +} + +func (event *SEvent) GetRequestId() string { + return event.TraceId +} + +func (event *SEvent) GetRequest() jsonutils.JSONObject { + return jsonutils.Marshal(event) +} + +func (event *SEvent) GetAccount() string { + return event.User.Name +} + +func (event *SEvent) IsSuccess() bool { + code, _ := strconv.Atoi(event.Code) + return code < 400 +} + +func (event *SEvent) GetCreatedAt() time.Time { + return time.Unix(event.Time/1000, event.Time%1000) +} + +func (self *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { + if !self.client.isMainProject { + return nil, cloudprovider.ErrNotSupported + } + events, err := self.GetEvents(start, end) + if err != nil { + return nil, err + } + iEvents := []cloudprovider.ICloudEvent{} + for i := range events { + iEvents = append(iEvents, &events[i]) + } + return iEvents, nil +} + +func (self *SRegion) GetEvents(start time.Time, end time.Time) ([]SEvent, error) { + events := []SEvent{} + params := map[string]string{} + if start.IsZero() { + start = time.Now().AddDate(0, 0, -7) + } + if end.IsZero() { + end = time.Now() + } + params["from"] = fmt.Sprintf("%d000", start.Unix()) + params["to"] = fmt.Sprintf("%d000", end.Unix()) + + err := doListAllWithMarker(self.ecsClient.Traces.List, params, &events) + if err != nil { + return nil, errors.Wrap(err, "doListAllWithMarker") + } + return events, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/utils.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/utils.go new file mode 100644 index 0000000000..fe14e19afd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/utils.go @@ -0,0 +1,270 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "reflect" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/manager" + "yunion.io/x/cloudmux/pkg/multicloud/huawei/client/responses" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +// 常用的方法 +type listFunc func(querys map[string]string) (*responses.ListResult, error) +type getFunc func(id string, querys map[string]string) (jsonutils.JSONObject, error) +type createFunc func(params jsonutils.JSONObject) (jsonutils.JSONObject, error) +type updateFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) +type updateFunc2 func(ctx manager.IManagerContext, id string, spec string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) +type deleteFunc func(id string, params jsonutils.JSONObject) (jsonutils.JSONObject, error) +type deleteFunc2 func(ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject, responseKey string) (jsonutils.JSONObject, error) +type listInCtxFunc func(ctx manager.IManagerContext, querys map[string]string) (*responses.ListResult, error) +type listInCtxWithSpecFunc func(ctx manager.IManagerContext, spec string, querys map[string]string, responseKey string) (*responses.ListResult, error) + +func unmarshalResult(resp jsonutils.JSONObject, respErr error, result interface{}, method string) error { + if respErr != nil { + switch e := respErr.(type) { + case *httputils.JSONClientError: + if (e.Code == 404 || utils.IsInStringArray(e.Class, NOT_FOUND_CODES)) && method != "POST" { + return cloudprovider.ErrNotFound + } + return e + default: + return e + } + } + + if result == nil { + return nil + } + + err := resp.Unmarshal(result) + if err != nil { + log.Errorf("unmarshal json error %s", err) + } + + return err +} + +var pageLimit = 100 + +// offset 表示的是页码 +func doListAllWithPagerOffset(doList listFunc, queries map[string]string, result interface{}) error { + startIndex := 0 + resultValue := reflect.Indirect(reflect.ValueOf(result)) + queries["limit"] = fmt.Sprintf("%d", pageLimit) + queries["offset"] = fmt.Sprintf("%d", startIndex) + for { + total, part, err := doListPart(doList, queries, result) + if err != nil { + return err + } + if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { + break + } + + startIndex++ + queries["offset"] = fmt.Sprintf("%d", startIndex) + } + return nil +} + +func doListAllWithNextLink(doList listFunc, querys map[string]string, result interface{}) error { + values := []jsonutils.JSONObject{} + for { + ret, err := doList(querys) + if err != nil { + return errors.Wrap(err, "doList") + } + values = append(values, ret.Data...) + if len(ret.NextLink) == 0 || ret.NextLink == "null" { + break + } + } + if result != nil { + return jsonutils.Update(result, values) + } + return nil +} + +func doListAllWithOffset(doList listFunc, queries map[string]string, result interface{}) error { + startIndex := 0 + resultValue := reflect.Indirect(reflect.ValueOf(result)) + queries["limit"] = fmt.Sprintf("%d", pageLimit) + queries["offset"] = fmt.Sprintf("%d", startIndex) + for { + total, part, err := doListPart(doList, queries, result) + if err != nil { + return err + } + if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { + break + } + queries["offset"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) + } + return nil +} + +func doListAllWithPage(doList listFunc, queries map[string]string, result interface{}) error { + startIndex := 1 + resultValue := reflect.Indirect(reflect.ValueOf(result)) + queries["limit"] = fmt.Sprintf("%d", pageLimit) + queries["page"] = fmt.Sprintf("%d", startIndex) + for { + total, part, err := doListPart(doList, queries, result) + if err != nil { + return err + } + if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { + break + } + queries["page"] = fmt.Sprintf("%d", startIndex+resultValue.Len()) + } + return nil +} + +func doListAllWithMarker(doList listFunc, queries map[string]string, result interface{}) error { + resultValue := reflect.Indirect(reflect.ValueOf(result)) + queries["limit"] = fmt.Sprintf("%d", pageLimit) + for { + total, part, err := doListPart(doList, queries, result) + if err != nil { + return err + } + if (total > 0 && resultValue.Len() >= total) || (total == 0 && pageLimit > part) { + break + } + lastValue := resultValue.Index(resultValue.Len() - 1) + markerValue := lastValue.FieldByNameFunc(func(key string) bool { + if strings.ToLower(key) == "id" { + return true + } + return false + }) + queries["marker"] = markerValue.String() + } + return nil +} + +func doListAll(doList listFunc, queries map[string]string, result interface{}) error { + total, _, err := doListPart(doList, queries, result) + if err != nil { + return err + } + resultValue := reflect.Indirect(reflect.ValueOf(result)) + if total > 0 && resultValue.Len() < total { + log.Warningf("INCOMPLETE QUERY, total %d queried %d", total, resultValue.Len()) + } + return nil +} + +func doListPart(doList listFunc, queries map[string]string, result interface{}) (int, int, error) { + ret, err := doList(queries) + if err != nil { + return 0, 0, err + } + resultValue := reflect.Indirect(reflect.ValueOf(result)) + elemType := resultValue.Type().Elem() + for i := range ret.Data { + elemPtr := reflect.New(elemType) + err = ret.Data[i].Unmarshal(elemPtr.Interface()) + if err != nil { + return 0, 0, err + } + resultValue.Set(reflect.Append(resultValue, elemPtr.Elem())) + } + return ret.Total, len(ret.Data), nil +} + +func DoGet(doGet getFunc, id string, queries map[string]string, result interface{}) error { + if len(id) == 0 { + resultType := reflect.Indirect(reflect.ValueOf(result)).Type() + return errors.Wrap(cloudprovider.ErrNotFound, fmt.Sprintf(" Get %s id should not be empty", resultType.Name())) + } + + ret, err := doGet(id, queries) + return unmarshalResult(ret, err, result, "GET") +} + +func DoListInContext(listFunc listInCtxFunc, ctx manager.IManagerContext, querys map[string]string, result interface{}) error { + ret, err := listFunc(ctx, querys) + if err != nil { + return err + } + + obj := responses.ListResult2JSON(ret) + err = obj.Unmarshal(result, "data") + if err != nil { + log.Errorf("unmarshal json error %s", err) + return err + } + + return nil +} + +func DoCreate(createFunc createFunc, params jsonutils.JSONObject, result interface{}) error { + ret, err := createFunc(params) + return unmarshalResult(ret, err, result, "POST") +} + +func DoUpdate(updateFunc updateFunc, id string, params jsonutils.JSONObject, result interface{}) error { + ret, err := updateFunc(id, params) + return unmarshalResult(ret, err, result, "PUT") +} + +func DoUpdateWithSpec(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject) error { + _, err := updateFunc(nil, id, spec, params, "") + return err +} + +func DoUpdateWithSpec2(updateFunc updateFunc2, id string, spec string, params jsonutils.JSONObject, result interface{}) error { + ret, err := updateFunc(nil, id, spec, params, "") + return unmarshalResult(ret, err, result, "PUT") +} + +func DoDelete(deleteFunc deleteFunc, id string, params jsonutils.JSONObject, result interface{}) error { + if len(id) == 0 { + return fmt.Errorf(" id should not be empty") + } + + ret, err := deleteFunc(id, params) + return unmarshalResult(ret, err, result, "DELETE") +} + +func DoDeleteWithSpec(deleteFunc deleteFunc2, ctx manager.IManagerContext, id string, spec string, queries map[string]string, params jsonutils.JSONObject) error { + if len(id) == 0 { + return fmt.Errorf(" id should not be empty") + } + + _, err := deleteFunc(ctx, id, spec, queries, params, "") + return err +} + +func ErrMessage(err error) string { + switch v := err.(type) { + case *httputils.JSONClientError: + return fmt.Sprintf("%d(%s):%s", v.Code, v.Class, v.Details) + default: + return err.Error() + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc.go new file mode 100644 index 0000000000..ffc43f3360 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc.go @@ -0,0 +1,361 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html +type SVpc struct { + multicloud.SVpc + HuaweiTags + + region *SRegion + + iwires []cloudprovider.ICloudWire + secgroups []cloudprovider.ICloudSecurityGroup + + ID string `json:"id"` + Name string `json:"name"` + CIDR string `json:"cidr"` + Status string `json:"status"` + EnterpriseProjectID string `json:"enterprise_project_id"` +} + +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) getWireByRegionId(regionId string) *SWire { + if len(regionId) == 0 { + return nil + } + + for i := 0; i < len(self.iwires); i++ { + wire := self.iwires[i].(*SWire) + + if wire.region.GetId() == regionId { + return wire + } + } + + return nil +} + +func (self *SVpc) fetchNetworks() error { + networks, err := self.region.GetNetwroks(self.ID) + if err != nil { + return err + } + + // ??????? + if len(networks) == 0 { + self.iwires = append(self.iwires, &SWire{region: self.region, vpc: self}) + return nil + } + + for i := 0; i < len(networks); i += 1 { + wire := self.getWireByRegionId(self.region.GetId()) + networks[i].wire = wire + wire.addNetwork(&networks[i]) + } + return nil +} + +// 华为云安全组可以被同region的VPC使用 +func (self *SVpc) fetchSecurityGroups() error { + secgroups, err := self.region.GetSecurityGroups("", "") + if err != nil { + return err + } + + self.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) + for i := 0; i < len(secgroups); i++ { + self.secgroups[i] = &secgroups[i] + } + return nil +} + +func (self *SVpc) GetId() string { + return self.ID +} + +func (self *SVpc) GetName() string { + if len(self.Name) > 0 { + return self.Name + } + return self.ID +} + +func (self *SVpc) GetGlobalId() string { + return self.ID +} + +func (self *SVpc) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} + +func (self *SVpc) Refresh() error { + new, err := self.region.getVpc(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SVpc) IsEmulated() bool { + return false +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetIsDefault() bool { + // 华为云没有default vpc. + return false +} + +func (self *SVpc) GetCidrBlock() string { + return self.CIDR +} + +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) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + rtbs, err := self.region.GetRouteTables(self.ID) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudRouteTable{} + for i := range rtbs { + rtbs[i].vpc = self + ret = append(ret, &rtbs[i]) + } + return ret, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + rtb, err := self.region.GetRouteTable(routeTableId) + if err != nil { + return nil, err + } + rtb.vpc = self + return rtb, nil +} + +func (self *SVpc) Delete() error { + // todo: 确定删除VPC的逻辑 + return self.region.DeleteVpc(self.GetId()) +} + +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) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { + nats, err := self.region.GetNatGateways(self.GetId(), "") + if err != nil { + return nil, err + } + ret := make([]cloudprovider.ICloudNatGateway, len(nats)) + for i := 0; i < len(nats); i++ { + ret[i] = &nats[i] + } + return ret, nil +} + +func (self *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPCs, err := self.getVpcPeeringConnections() + if err != nil { + return nil, errors.Wrap(err, "self.getVpcPeeringConnections()") + } + ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} + for i := range svpcPCs { + ivpcPCs = append(ivpcPCs, &svpcPCs[i]) + } + return ivpcPCs, nil +} + +func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPCs, err := self.getAccepterVpcPeeringConnections() + if err != nil { + return nil, errors.Wrap(err, "self.getAccepterVpcPeeringConnections()") + } + ivpcPCs := []cloudprovider.ICloudVpcPeeringConnection{} + for i := range svpcPCs { + ivpcPCs = append(ivpcPCs, &svpcPCs[i]) + } + return ivpcPCs, nil +} + +func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPC, err := self.getVpcPeeringConnectionById(id) + if err != nil { + return nil, errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) + } + return svpcPC, nil +} + +func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPC, err := self.region.CreateVpcPeering(self.GetId(), opts) + if err != nil { + return nil, errors.Wrapf(err, "self.region.CreateVpcPeering(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) + } + svpcPC.vpc = self + return svpcPC, nil +} +func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { + vpcPC, err := self.getVpcPeeringConnectionById(id) + if err != nil { + return errors.Wrapf(err, "self.getVpcPeeringConnectionById(%s)", id) + } + if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_ACTIVE { + return nil + } + if vpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN { + return errors.Wrapf(cloudprovider.ErrInvalidStatus, "vpcPC: %s", jsonutils.Marshal(vpcPC).String()) + } + err = self.region.AcceptVpcPeering(id) + if err != nil { + return errors.Wrapf(err, "self.region.AcceptVpcPeering(%s)", id) + } + return nil +} + +func (self *SVpc) GetAuthorityOwnerId() string { + return self.region.client.projectId +} + +func (self *SVpc) getVpcPeeringConnections() ([]SVpcPeering, error) { + svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) + } + vpcPCs := []SVpcPeering{} + for i := range svpcPeerings { + if svpcPeerings[i].GetVpcId() == self.GetId() { + svpcPeerings[i].vpc = self + vpcPCs = append(vpcPCs, svpcPeerings[i]) + } + } + return vpcPCs, nil +} + +func (self *SVpc) getAccepterVpcPeeringConnections() ([]SVpcPeering, error) { + svpcPeerings, err := self.region.GetVpcPeerings(self.GetId()) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetVpcPeerings(%s)", self.GetId()) + } + vpcPCs := []SVpcPeering{} + for i := range svpcPeerings { + if svpcPeerings[i].GetPeerVpcId() == self.GetId() { + svpcPeerings[i].vpc = self + vpcPCs = append(vpcPCs, svpcPeerings[i]) + } + } + return vpcPCs, nil +} + +func (self *SVpc) getVpcPeeringConnectionById(id string) (*SVpcPeering, error) { + svpcPC, err := self.region.GetVpcPeering(id) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetVpcPeering(%s)", id) + } + svpcPC.vpc = self + return svpcPC, nil +} + +func (self *SRegion) getVpc(vpcId string) (*SVpc, error) { + vpc := SVpc{} + err := DoGet(self.ecsClient.Vpcs.Get, vpcId, nil, &vpc) + if err != nil && strings.Contains(err.Error(), "RouterNotFound") { + return nil, cloudprovider.ErrNotFound + } + vpc.region = self + return &vpc, err +} + +func (self *SRegion) DeleteVpc(vpcId string) error { + if vpcId != "default" { + secgroups, err := self.GetSecurityGroups(vpcId, "") + if err != nil { + return errors.Wrap(err, "GetSecurityGroups") + } + for _, secgroup := range secgroups { + err = self.DeleteSecurityGroup(secgroup.ID) + if err != nil { + return errors.Wrapf(err, "DeleteSecurityGroup(%s)", secgroup.ID) + } + } + } + return DoDelete(self.ecsClient.Vpcs.Delete, vpcId, nil, nil) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html +func (self *SRegion) GetVpcs() ([]SVpc, error) { + querys := make(map[string]string) + + vpcs := make([]SVpc, 0) + err := doListAllWithMarker(self.ecsClient.Vpcs.List, querys, &vpcs) + if err != nil { + return nil, err + } + + for i := range vpcs { + vpcs[i].region = self + } + return vpcs, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc_peering.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc_peering.go new file mode 100644 index 0000000000..841c385b2a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/vpc_peering.go @@ -0,0 +1,159 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type RequestVpcInfo struct { + VpcID string `json:"vpc_id"` + TenantID string `json:"tenant_id"` +} +type AcceptVpcInfo struct { + VpcID string `json:"vpc_id"` + TenantID string `json:"tenant_id"` +} +type SVpcPeering struct { + multicloud.SResourceBase + HuaweiTags + vpc *SVpc + + RequestVpcInfo RequestVpcInfo `json:"request_vpc_info"` + AcceptVpcInfo AcceptVpcInfo `json:"accept_vpc_info"` + Name string `json:"name"` + ID string `json:"id"` + Status string `json:"status"` +} + +func (self *SRegion) GetVpcPeerings(vpcId string) ([]SVpcPeering, error) { + querys := make(map[string]string) + querys["vpc_id"] = vpcId + vpcPeerings := make([]SVpcPeering, 0) + err := doListAllWithMarker(self.ecsClient.VpcPeerings.List, querys, &vpcPeerings) + if err != nil { + return nil, errors.Wrapf(err, "oListAllWithMarker(self.ecsClient.VpcPeerings.List, %s, &vpcPeerings)", jsonutils.Marshal(querys).String()) + } + return vpcPeerings, nil +} + +func (self *SRegion) GetVpcPeering(vpcPeeringId string) (*SVpcPeering, error) { + if len(vpcPeeringId) == 0 { + return nil, cloudprovider.ErrNotFound + } + vpcPeering := SVpcPeering{} + err := DoGet(self.ecsClient.VpcPeerings.Get, vpcPeeringId, nil, &vpcPeering) + if err != nil { + return nil, errors.Wrapf(err, "DoGet(self.ecsClient.VpcPeerings.Get, %s, nil, &vpcPeering)", vpcPeeringId) + } + return &vpcPeering, nil +} + +func (self *SRegion) CreateVpcPeering(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPeering, error) { + params := jsonutils.NewDict() + vpcPeeringObj := jsonutils.NewDict() + requestVpcObj := jsonutils.NewDict() + acceptVpcObj := jsonutils.NewDict() + vpcPeeringObj.Set("name", jsonutils.NewString(opts.Name)) + requestVpcObj.Set("vpc_id", jsonutils.NewString(vpcId)) + requestVpcObj.Set("tenant_id", jsonutils.NewString(self.client.projectId)) + vpcPeeringObj.Set("request_vpc_info", requestVpcObj) + acceptVpcObj.Set("vpc_id", jsonutils.NewString(opts.PeerVpcId)) + acceptVpcObj.Set("tenant_id", jsonutils.NewString(opts.PeerAccountId)) + vpcPeeringObj.Set("accept_vpc_info", acceptVpcObj) + params.Set("peering", vpcPeeringObj) + ret := SVpcPeering{} + err := DoCreate(self.ecsClient.VpcPeerings.Create, params, &ret) + if err != nil { + return nil, errors.Wrapf(err, "DoCreate(self.ecsClient.VpcPeerings.Create, %s, &ret)", jsonutils.Marshal(params).String()) + } + return &ret, nil +} + +func (self *SRegion) AcceptVpcPeering(vpcPeeringId string) error { + err := DoUpdateWithSpec(self.ecsClient.VpcPeerings.UpdateInContextWithSpec, vpcPeeringId, "accept", nil) + if err != nil { + return errors.Wrapf(err, "DoUpdateWithSpec(self.ecsClient.VpcPeerings.UpdateInContextWithSpec, %s, accept, nil)", vpcPeeringId) + } + return nil +} + +func (self *SRegion) DeleteVpcPeering(vpcPeeringId string) error { + err := DoDelete(self.ecsClient.VpcPeerings.Delete, vpcPeeringId, nil, nil) + if err != nil { + return errors.Wrapf(err, "DoDelete(self.ecsClient.VpcPeerings.Delete,%s,nil)", vpcPeeringId) + } + return nil +} + +func (self *SVpcPeering) GetId() string { + return self.ID +} + +func (self *SVpcPeering) GetName() string { + return self.Name +} + +func (self *SVpcPeering) GetGlobalId() string { + return self.GetId() +} + +func (self *SVpcPeering) GetStatus() string { + switch self.Status { + case "PENDING_ACCEPTANCE": + return api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT + case "ACTIVE": + return api.VPC_PEERING_CONNECTION_STATUS_ACTIVE + default: + return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN + } +} + +func (self *SVpcPeering) Refresh() error { + peer, err := self.vpc.region.GetVpcPeering(self.ID) + if err != nil { + return errors.Wrapf(err, "self.region.GetVpcPeering(%s)", self.ID) + } + return jsonutils.Update(self, peer) +} + +func (self *SVpcPeering) GetVpcId() string { + return self.RequestVpcInfo.VpcID +} + +func (self *SVpcPeering) GetPeerVpcId() string { + return self.AcceptVpcInfo.VpcID +} + +func (self *SVpcPeering) GetPeerAccountId() string { + return self.AcceptVpcInfo.TenantID +} + +func (self *SVpcPeering) GetEnabled() bool { + return true +} + +func (self *SVpcPeering) Delete() error { + err := self.vpc.region.DeleteVpcPeering(self.ID) + if err != nil { + return errors.Wrapf(err, "self.region.DeleteVpcPeering(%s)", self.ID) + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/wire.go new file mode 100644 index 0000000000..e2fa7b02bd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/wire.go @@ -0,0 +1,192 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// 华为云的子网有点特殊。子网在整个region可用。 +type SWire struct { + multicloud.SResourceBase + HuaweiTags + region *SRegion + vpc *SVpc + + inetworks []cloudprovider.ICloudNetwork +} + +func (self *SWire) GetId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) +} + +func (self *SWire) GetName() string { + return self.GetId() +} + +func (self *SWire) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SWire) Refresh() error { + return nil +} + +func (self *SWire) IsEmulated() bool { + return true +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return nil +} + +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 +} + +/* +华为云子网可用区,类似一个zone标签。即使指定了zone子网在整个region依然是可用。 +通过华为web控制台创建子网需要指定可用区。这里是不指定的。 +*/ +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + networkId, err := self.region.createNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc) + if err != nil { + log.Errorf("createNetwork error %s", err) + return nil, err + } + + var network *SNetwork + err = cloudprovider.WaitCreated(5*time.Second, 60*time.Second, func() bool { + self.inetworks = nil + network = self.getNetworkById(networkId) + if network == nil { + return false + } else { + return true + } + }) + + if err != nil { + log.Errorf("cannot find network after create????") + return nil, err + } + + network.wire = self + return network, 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.ID { + find = true + break + } + } + if !find { + self.inetworks = append(self.inetworks, network) + } +} + +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 getDefaultGateWay(cidr string) (string, error) { + pref, err := netutils.NewIPV4Prefix(cidr) + if err != nil { + return "", errors.Wrap(err, "getDefaultGateWay.NewIPV4Prefix") + } + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + return startIp.String(), nil +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090590.html +// cidr 掩码长度不能大于28 +func (self *SRegion) createNetwork(vpcId string, name string, cidr string, desc string) (string, error) { + gateway, err := getDefaultGateWay(cidr) + if err != nil { + return "", err + } + + params := jsonutils.NewDict() + subnetObj := jsonutils.NewDict() + subnetObj.Add(jsonutils.NewString(name), "name") + subnetObj.Add(jsonutils.NewString(vpcId), "vpc_id") + subnetObj.Add(jsonutils.NewString(cidr), "cidr") + subnetObj.Add(jsonutils.NewString(gateway), "gateway_ip") + params.Add(subnetObj, "subnet") + + subnet := SNetwork{} + err = DoCreate(self.ecsClient.Subnets.Create, params, &subnet) + return subnet.ID, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/zone.go new file mode 100644 index 0000000000..e9ccd74d46 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/huawei/zone.go @@ -0,0 +1,204 @@ +// Copyright 2019 Yunion +// +// 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 huawei + +import ( + "fmt" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var StorageTypes = []string{ + api.STORAGE_HUAWEI_SAS, + api.STORAGE_HUAWEI_SATA, + api.STORAGE_HUAWEI_SSD, +} + +type ZoneState struct { + Available bool `json:"available"` +} + +// https://support.huaweicloud.com/api-ecs/zh-cn_topic_0065817728.html +type SZone struct { + multicloud.SResourceBase + HuaweiTags + region *SRegion + host *SHost + + iwires []cloudprovider.ICloudWire + istorages []cloudprovider.ICloudStorage + + ZoneState ZoneState `json:"zoneState"` + ZoneName string `json:"zoneName"` + + /* 支持的磁盘种类集合 */ + 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) getStorageType() { + if len(self.storageTypes) == 0 { + if sts, err := self.region.GetZoneSupportedDiskTypes(self.GetId()); err == nil { + self.storageTypes = sts + } else { + log.Errorf("GetZoneSupportedDiskTypes %s %s", self.GetId(), err) + 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) getHost() *SHost { + if self.host == nil { + self.host = &SHost{zone: self, projectId: self.region.client.projectId} + } + return self.host +} + +func (self *SZone) GetId() string { + return self.ZoneName +} + +func (self *SZone) GetName() string { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_CN, self.ZoneName) +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_HUAWEI_EN, self.ZoneName) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.ZoneName) +} + +func (self *SZone) GetStatus() string { + return "enable" +} + +func (self *SZone) Refresh() error { + return nil +} + +func (self *SZone) IsEmulated() bool { + return false +} + +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 { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "fetchStorages") + } + } + return self.istorages, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "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) GetIWires() ([]cloudprovider.ICloudWire, error) { + return self.iwires, nil +} + +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.GetId() == id { + return zone, nil + } + } + return nil, fmt.Errorf("no such zone %s", id) +} + +func (self *SZone) getNetworkById(networkId string) *SNetwork { + for i := 0; i < len(self.iwires); i += 1 { + wire := self.iwires[i].(*SWire) + net := wire.getNetworkById(networkId) + if net != nil { + return net + } + } + return nil +} diff --git a/pkg/multicloud/image_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/image_base.go similarity index 95% rename from pkg/multicloud/image_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/image_base.go index 67042038a6..046781d765 100644 --- a/pkg/multicloud/image_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/image_base.go @@ -15,7 +15,7 @@ package multicloud import ( - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/rbacutils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/disk.go new file mode 100644 index 0000000000..7f5e3af7e1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/disk.go @@ -0,0 +1,246 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "context" + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type RelatedVms struct { + Id string `json:"id"` + Text string `json:"text"` + IconCls string `json:"iconCls"` + State string `json:"state"` + Children string `json:"children"` + Object string `json:"object"` + Name string `json:"name"` + ViewId string `json:"viewId"` + TargetType string `json:"targetType"` + InnerName string `json:"innerName"` + ServiceType string `json:"serviceType"` + StorageType string `json:"storageType"` + HciType string `json:"hciType"` + VMType string `json:"vmType"` + HostId string `json:"hostId"` + ParentId string `json:"parentId"` + DatastoreRole string `json:"datastoreRole"` + Vlan string `json:"vlan"` + DhcpEnabled bool `json:"dhcpEnabled"` + ConnectMode string `json:"connectMode"` + DataStoreType string `json:"dataStoreType"` + Hypervisor string `json:"hypervisor"` +} + +type SDisk struct { + multicloud.SDisk + InCloudSphereTags + + region *SRegion + + Id string `json:"id"` + UUID string `json:"uuid"` + Size float64 `json:"size"` + RealSize float64 `json:"realSize"` + Name string `json:"name"` + FileName string `json:"fileName"` + Offset int `json:"offset"` + Shared bool `json:"shared"` + DeleteModel string `json:"deleteModel"` + VolumePolicy string `json:"volumePolicy"` + Format string `json:"format"` + BlockDeviceId string `json:"blockDeviceId"` + DiskType string `json:"diskType"` + DataStoreId string `json:"dataStoreId"` + DataStoreName string `json:"dataStoreName"` + DataStoreSize float64 `json:"dataStoreSize"` + FreeStorage float64 `json:"freeStorage"` + DataStoreType string `json:"dataStoreType"` + DataStoreReplicate int `json:"dataStoreReplicate"` + VMName string `json:"vmName"` + VMStatus string `json:"vmStatus"` + Type string `json:"type"` + Description string `json:"description"` + Bootable bool `json:"bootable"` + VolumeStatus string `json:"volumeStatus"` + MountedHostIds string `json:"mountedHostIds"` + Md5 string `json:"md5"` + DataSize int `json:"dataSize"` + OpenStackId string `json:"openStackId"` + VvSourceDto string `json:"vvSourceDto"` + FormatDisk bool `json:"formatDisk"` + ToBeConverted bool `json:"toBeConverted"` + RelatedVms []RelatedVms `json:"relatedVms"` + XactiveDataStoreId string `json:"xactiveDataStoreId"` + ClusterSize int `json:"clusterSize"` + ScsiId string `json:"scsiId"` + SecondaryUUId string `json:"secondaryUuid"` + SecondaryVolumes string `json:"secondaryVolumes"` +} + +func (self *SDisk) GetName() string { + return self.Name +} + +func (self *SDisk) GetId() string { + return self.Id +} + +func (self *SDisk) GetGlobalId() string { + return self.GetId() +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SDisk) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SDisk) GetCacheMode() string { + return "none" +} + +func (self *SDisk) GetFsFormat() string { + return "" +} + +func (self *SDisk) GetIsNonPersistent() bool { + return false +} + +func (self *SDisk) GetDriver() string { + return "scsi" +} + +func (self *SDisk) GetDiskType() string { + if strings.HasSuffix(self.Name, "1") || strings.HasSuffix(self.Name, "0") { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +func (self *SDisk) GetDiskFormat() string { + return strings.ToLower(self.Format) +} + +func (self *SDisk) GetDiskSizeMB() int { + return int(self.Size * 1024) +} + +func (self *SDisk) GetIsAutoDelete() bool { + return true +} + +func (self *SDisk) GetMountpoint() string { + return "" +} + +func (self *SDisk) GetStatus() string { + return api.DISK_READY +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { + return self.region.ResizeDisk(self.Id, int(sizeMb/1024)) +} + +func (self *SDisk) GetTemplateId() string { + return "" +} + +func (self *SDisk) GetAccessPath() string { + return self.FileName +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.region.GetStorage(self.DataStoreId) +} + +func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + return []cloudprovider.ICloudSnapshot{}, nil +} + +func (self *SRegion) GetDisks(storageId string) ([]SDisk, error) { + ret := []SDisk{} + res := fmt.Sprintf("/storages/%s/volumes", storageId) + return ret, self.list(res, url.Values{}, &ret) +} + +func (self *SRegion) GetDisk(id string) (*SDisk, error) { + ret := &SDisk{region: self} + res := fmt.Sprintf("/volumes/%s", id) + return ret, self.get(res, nil, ret) +} + +func (self *SRegion) ResizeDisk(id string, sizeGb int) error { + disk, err := self.GetDisk(id) + if err != nil { + return errors.Wrapf(err, "GetDisk(%s)", id) + } + body := map[string]interface{}{ + "size": sizeGb, + "name": disk.Name, + "bootable": disk.Bootable, + "volumePolicy": disk.VolumePolicy, + "dataStoreType": disk.DataStoreType, + } + return self.put("/volumes/"+disk.Id, nil, jsonutils.Marshal(body), nil) +} + +func (self *SRegion) CreateDisk(name, storageId string, sizeGb int) (*SDisk, error) { + body := map[string]interface{}{ + "dataStoreId": storageId, + "format": "RAW", + "name": name, + "replicate": 1, + "size": sizeGb, + "volumePolicy": "THIN", + } + resp, err := self.client.post("/volumes", jsonutils.Marshal(body)) + if err != nil { + return nil, err + } + taskId, err := resp.GetString("taskId") + if err != nil { + return nil, err + } + diskId, err := self.client.waitTask(taskId) + if err != nil { + return nil, errors.Wrapf(err, "waitTask(%s)", taskId) + } + return self.GetDisk(diskId) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/doc.go new file mode 100644 index 0000000000..878bda80d0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere // import "yunion.io/x/cloudmux/pkg/multicloud/incloudsphere" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/host.go new file mode 100644 index 0000000000..9d3dfaf08c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/host.go @@ -0,0 +1,452 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "fmt" + "net" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SHost struct { + multicloud.SHostBase + InCloudSphereTags + zone *SZone + + Id string `json:"id"` + IP string `json:"ip"` + SwitchUplinkPortDto string `json:"switchUplinkPortDto"` + UplinkTopoDto string `json:"uplinkTopoDto"` + Pnics string `json:"pnics"` + Disks string `json:"disks"` + Name string `json:"name"` + HostName string `json:"hostName"` + NodeVersion string `json:"nodeVersion"` + Password string `json:"password"` + DataCenterId string `json:"dataCenterId"` + DataCenterName string `json:"dataCenterName"` + ClusterName string `json:"clusterName"` + ClusterId string `json:"clusterId"` + Status string `json:"status"` + CPUSocket int64 `json:"cpuSocket"` + CPUCorePerSocket int64 `json:"cpuCorePerSocket"` + CPUThreadPerCore int64 `json:"cpuThreadPerCore"` + LogicCPUNum int64 `json:"logicCpuNum"` + LogicalProcessor int64 `json:"logicalProcessor"` + CPUFrequency float64 `json:"cpuFrequency"` + CPUUsage float64 `json:"cpuUsage"` + CPUTotalHz int64 `json:"cpuTotalHz"` + FreeCPU int64 `json:"freeCpu"` + UsedCPU int64 `json:"usedCpu"` + TotalMem float64 `json:"totalMem"` + LogicTotalMem int64 `json:"logicTotalMem"` + MemoryUsage float64 `json:"memoryUsage"` + FreeMemory int64 `json:"freeMemory"` + UsedMemory int64 `json:"usedMemory"` + LogicUsedMemory int64 `json:"logicUsedMemory"` + LogicFreeMemory int64 `json:"logicFreeMemory"` + PnicNum int64 `json:"pnicNum"` + NormalRunTime int64 `json:"normalRunTime"` + Model string `json:"model"` + CPUType string `json:"cpuType"` + VTDegree int64 `json:"vtDegree"` + Powerstate string `json:"powerstate"` + HostBmcDto string `json:"hostBmcDto"` + MountPath string `json:"mountPath"` + MonMountState string `json:"monMountState"` + CPUModel string `json:"cpuModel"` + NetworkDtos string `json:"networkDtos"` + PortIP string `json:"portIp"` + Monstatus bool `json:"monstatus"` + HostIqn string `json:"hostIqn"` + VxlanPortDto string `json:"vxlanPortDto"` + SDNUpLinks string `json:"sdnUpLinks"` + AllPNicsCount int64 `json:"allPNicsCount"` + AvailablePNicsCount int64 `json:"availablePNicsCount"` + CfsDomainStatus string `json:"cfsDomainStatus"` + SerialNumber string `json:"serialNumber"` + Manufacturer string `json:"manufacturer"` + IndicatorStatus string `json:"indicatorStatus"` + EntryTemperature string `json:"entryTemperature"` + MulticastEnabled bool `json:"multicastEnabled"` + BroadcastLimitEnabled bool `json:"broadcastLimitEnabled"` + Pcies string `json:"pcies"` + VgpuEnable bool `json:"vgpuEnable"` + SSHEnable bool `json:"sshEnable"` + SpecialFailover bool `json:"specialFailover"` + VswitchDtos string `json:"vswitchDtos"` + HotfixVersion string `json:"hotfixVersion"` + VMMigBandWidth string `json:"vmMigBandWidth"` + VMMigBandWidthFlag bool `json:"vmMigBandWidthFlag"` + DpdkEnabled bool `json:"dpdkEnabled"` + HugePageTotal int64 `json:"hugePageTotal"` + HugePageUsed int64 `json:"hugePageUsed"` + HugePageFree int64 `json:"hugePageFree"` + StorageUsage int64 `json:"storageUsage"` + NodeForm string `json:"nodeForm"` + CPUArchType string `json:"cpuArchType"` + LogPartitionSize int64 `json:"logPartitionSize"` + RootPartitionSize int64 `json:"rootPartitionSize"` + Cpuflags string `json:"cpuflags"` +} + +func (self *SHost) GetId() string { + return self.Id +} + +func (self *SHost) GetGlobalId() string { + return self.Id +} + +func (self *SHost) GetName() string { + return self.HostName +} + +func (self *SHost) GetEnabled() bool { + return true +} + +func (self *SHost) GetHostStatus() string { + return api.HOST_ONLINE +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) GetAccessIp() string { + return self.Name +} + +func (self *SHost) GetAccessMac() string { + return "" +} + +func (self *SHost) GetSysInfo() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (self *SHost) GetSN() string { + return self.SerialNumber +} + +func (self *SHost) GetCpuCount() int { + return int(self.CPUCorePerSocket) +} + +func (self *SHost) GetNodeCount() int8 { + return int8(self.CPUSocket) +} + +func (self *SHost) GetCpuDesc() string { + return self.CPUType +} + +func (self *SHost) GetCpuMhz() int { + return int(self.CPUFrequency * 1024) +} + +func (self *SHost) GetCpuCmtbound() float32 { + return 1 +} + +func (self *SHost) GetMemSizeMB() int { + return int(self.TotalMem) +} + +func (self *SHost) GetMemCmtbound() float32 { + return 1 +} + +func (self *SHost) GetReservedMemoryMb() int { + return 0 +} + +func (self *SHost) GetStorageSizeMB() int { + return 0 +} + +func (self *SHost) GetStorageType() string { + return api.STORAGE_LOCAL +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_INCLOUD_SPHERE +} + +func (self *SHost) GetIsMaintenance() bool { + return false +} + +func (self *SHost) GetVersion() string { + return self.NodeVersion +} + +func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + storages, err := self.zone.region.GetImageStorages(self.zone.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetImageStorages") + } + var image *SImage = nil + storageCache := &SStoragecache{zone: self.zone} + for i := range storages { + images, err := self.zone.region.GetImageList(storages[i].Id) + if err != nil { + return nil, err + } + for j := range images { + images[j].cache = storageCache + if images[j].GetGlobalId() == opts.ExternalImageId { + image = &images[j] + break + } + } + } + if image == nil { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, opts.ExternalImageId) + } + format := "RAW" + if strings.HasSuffix(opts.ExternalImageId, "qcow2") { + format = "QCOW2" + } + sizeGb := float64((image.GetSizeByte() + 1024/2) / 1024 / 1024 / 1024) + disks := []Disks{} + disks = append(disks, Disks{ + BusModel: "IDE", + ReadWriteModel: "NONE", + QueueNum: 1, + Volume: Volume{ + Bootable: true, + DataStoreId: opts.SysDisk.StorageExternalId, + Format: format, + Size: sizeGb, + VolumePolicy: "THIN", + VvSourceDto: VvSourceDto{ + FilePath: fmt.Sprintf("%s/%s", image.Path, image.Name), + SourceType: "IMAGE_STORAGE", + FtpServerHost: FtpServerHost{ + Id: image.ServerID, + Ip: image.FTPServer, + }, + }, + }, + }) + for i := range opts.DataDisks { + disks = append(disks, Disks{ + BusModel: "IDE", + ReadWriteModel: "NONE", + QueueNum: 1, + Volume: Volume{ + Bootable: false, + DataStoreId: opts.DataDisks[i].StorageExternalId, + Format: "RAW", + Size: float64(opts.DataDisks[i].SizeGB), + VolumePolicy: "THIN", + }, + }) + } + imageTree, err := self.zone.region.GetImageTrees() + if err != nil { + return nil, errors.Wrapf(err, "GetImageTrees") + } + guestLabel, guestosType := "CentOS 7.9(2009) 64bit", "CentOS" + for i := range imageTree { + images := imageTree[i].ToList() + for j := range images { + if images[j].IsEquals(image.Name) { + guestLabel = images[j].Model + guestosType = images[j].OsDist + break + } + } + } + nic := SInstanceNic{ + AutoGenerated: true, + DeviceId: opts.ExternalNetworkId, + DeviceType: "NETWORK", + Model: "E1000", + Queues: 1, + } + network, err := self.zone.region.GetNetwork(opts.ExternalNetworkId) + if err != nil { + return nil, errors.Wrapf(err, "GetNetwork") + } + if network.DhcpEnabled { + nic.Dhcp = true + nic.DhcpEnabled = true + nic.DhcpIP = opts.IpAddr + } else if len(opts.IpAddr) > 0 { + nic.IP = opts.IpAddr + mask := net.CIDRMask(int(network.GetIpMask()), 32) + nic.Netmask = fmt.Sprintf("%d.%d.%d.%d", mask[0], mask[1], mask[2], mask[3]) + nic.Gateway = network.GetGateway() + if len(nic.Gateway) == 0 { + info := strings.Split(opts.IpAddr, ".") + if len(info) == 4 { + info[3] = "1" + nic.Gateway = strings.Join(info, ".") + } + } + } + body := map[string]interface{}{ + "boot": "HD", + "bootMode": "BIOS", + "clockModel": "LOCALTIME", + "cpuBindType": "NOBIND", + "cpuCore": opts.Cpu, + "cpuHotplugEnabled": false, + "cpuLimit": -1, + "cpuModelType": "SELF_ADAPTING", + "cpuNum": opts.Cpu, + "cpuReservation": 0, + "cpuShares": 1024, + "cpuSocket": 1, + "dataCenterId": self.zone.Id, + "dataStoreId": opts.SysDisk.StorageExternalId, + "deacription": opts.Description, + "disks": disks, + "enableHugeMemPage": false, + "enableReplicate": false, + "graphicsCardMemory": 16384, + "graphicsCardModel": "VGA", + "guestosLabel": guestLabel, + "guestosType": guestosType, + "hostBinded": false, + "hostId": self.Id, + "maxCpuNum": 128, + "maxMemory": 4194304, + "memory": opts.MemoryMB, + "memoryShow": 4, + "memoryUnit": "GB", + "name": opts.Name, + "nics": []SInstanceNic{ + nic, + }, + "panickPolicy": "NO_ACTION", + "replicate": 1, + "socketLimit": 24, + "startPriority": "DEFAULT", + "supportCpuHotPlug": true, + "supportMemHotPlug": true, + "supportUefiBootMode": true, + "vcpuPin": "all", + "version": "V2", + } + resp, err := self.zone.region.post("/vms", jsonutils.Marshal(body)) + if err != nil { + return nil, err + } + taskId, err := resp.GetString("taskId") + if err != nil { + return nil, errors.Wrapf(err, "taskId") + } + vmId, err := self.zone.region.client.waitTask(taskId) + if err != nil { + return nil, err + } + vm, err := self.zone.region.GetInstance(vmId) + if err != nil { + return nil, err + } + vm.host = self + return vm, nil +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms, err := self.zone.region.GetInstances(self.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetInstances") + } + ret := []cloudprovider.ICloudVM{} + for i := range vms { + vms[i].host = self + ret = append(ret, &vms[i]) + } + return ret, nil +} + +func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := self.zone.region.GetInstance(id) + if err != nil { + return nil, err + } + if vm.HostId != self.Id { + return nil, cloudprovider.ErrNotFound + } + vm.host = self + return vm, nil +} + +func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + wires, err := self.zone.region.GetWiresByDs(self.DataCenterId) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudWire{} + for i := range wires { + wires[i].region = self.zone.region + ret = append(ret, &wires[i]) + } + return ret, nil +} + +func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.zone.region.GetStoragesByHost(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + storages[i].zone = self.zone + ret = append(ret, &storages[i]) + } + return ret, nil +} + +func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storage, err := self.zone.region.GetStorage(id) + if err != nil { + return nil, err + } + storage.zone = self.zone + if storage.HostId != self.Id { + return nil, cloudprovider.ErrNotFound + } + return storage, nil +} + +func (self *SRegion) GetHosts(dcId string) ([]SHost, error) { + hosts := []SHost{} + res := fmt.Sprintf("/datacenters/%s/hosts", dcId) + return hosts, self.list(res, url.Values{}, &hosts) +} + +func (self *SRegion) GetHost(id string) (*SHost, error) { + ret := &SHost{} + res := fmt.Sprintf("/hosts/%s", id) + return ret, self.get(res, url.Values{}, ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/image.go new file mode 100644 index 0000000000..dd075ca832 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/image.go @@ -0,0 +1,183 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "context" + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type SImage struct { + multicloud.SImageBase + InCloudSphereTags + cache *SStoragecache + + imageInfo *imagetools.ImageInfo + + Name string `json:"name"` + FileSize int64 `json:"fileSize"` + RealSize int64 `json:"realSize"` + SourceType string `json:"sourceType"` + Format string `json:"format"` + FileType string `json:"fileType"` + Size int64 `json:"size"` + Date string `json:"date"` + Path string `json:"path"` + FTPServer string `json:"ftpServer"` + DataStoreID string `json:"dataStoreId"` + DataStoreName string `json:"dataStoreName"` + ServerID string `json:"serverId"` + Md5 string `json:"md5"` +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SImage) GetId() string { + return fmt.Sprintf("%s/%s/%s", self.cache.zone.Id, self.Path, self.Name) +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (self *SImage) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SImage) GetGlobalId() string { + return self.GetId() +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.cache +} + +func (self *SImage) GetStatus() string { + return api.CACHED_IMAGE_STATUS_ACTIVE +} + +func (self *SImage) GetImageStatus() string { + return cloudprovider.IMAGE_STATUS_ACTIVE +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + return cloudprovider.ImageTypeSystem +} + +func (self *SImage) GetSizeByte() int64 { + return self.FileSize +} + +func (i *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(i.getNormalizedImageInfo().OsType) +} + +func (i *SImage) GetOsDist() string { + return i.getNormalizedImageInfo().OsDistro +} + +func (i *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if i.imageInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(i.Name, "", "", "", "") + i.imageInfo = &imgInfo + } + return i.imageInfo +} + +func (i *SImage) GetFullOsName() string { + return i.Name +} + +func (i *SImage) GetOsVersion() string { + return i.getNormalizedImageInfo().OsVersion +} + +func (i *SImage) GetOsArch() string { + return i.getNormalizedImageInfo().OsArch +} + +func (i *SImage) GetOsLang() string { + return i.getNormalizedImageInfo().OsLang +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + if self.GetOsType() == "windows" { + return 40 + } + return 30 +} + +func (self *SImage) GetImageFormat() string { + return self.Format +} + +func (i *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(i.getNormalizedImageInfo().OsBios) +} + +type SImageInfo struct { + OsType string + OsDist string + Model string + SocketLimit int + SupportCpuHotPlug bool + SupportMemHotPlug bool + SupportDiskHotPlug bool + SupportUefiBootMode bool +} + +func (self *SImageInfo) IsEquals(name string) bool { + model := imagetools.NormalizeImageInfo(self.Model, "", "", "", "") + image := imagetools.NormalizeImageInfo(name, "", "", "", "") + return model.OsDistro == image.OsDistro && model.OsVersion == image.OsVersion +} + +type SImageTree struct { + Id string + Name string + Children []struct { + Id string + Name string + Children []struct { + Id string + Name string + Object SImageInfo + } + } +} + +func (self *SImageTree) ToList() []SImageInfo { + ret := []SImageInfo{} + for i := range self.Children { + for j := range self.Children[i].Children { + self.Children[i].Children[j].Object.OsType = self.Name + self.Children[i].Children[j].Object.OsDist = self.Children[i].Name + ret = append(ret, self.Children[i].Children[j].Object) + } + } + return ret +} + +func (self *SRegion) GetImageTrees() ([]SImageTree, error) { + ret := []SImageTree{} + return ret, self.get("/vms/ostrees", nil, &ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/instance.go new file mode 100644 index 0000000000..04b12cc8b0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/instance.go @@ -0,0 +1,613 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "context" + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type Cdrom struct { + Path string `json:"path"` + Type string `json:"type"` + Connected bool `json:"connected"` + StartConnected bool `json:"startConnected"` + CifsDto string `json:"cifsDto"` + DataStore struct { + Id string `json:"id"` + Name string `json:"name"` + } `json:"dataStore"` +} + +type Floppy struct { + Path string `json:"path"` + DataStore string `json:"dataStore"` + VfdType string `json:"vfdType"` +} + +type FtpServerHost struct { + Id string `json:"id"` + Ip string `json:"ip"` +} + +type VvSourceDto struct { + SourceType string `json:"sourceType"` + FilePath string `json:"filePath"` + Name string `json:"name"` + FtpServerHost FtpServerHost `json:"ftpServerHost"` +} + +type Volume struct { + Id string `json:"id"` + UUID string `json:"uuid"` + Size float64 `json:"size"` + RealSize float64 `json:"realSize"` + Name string `json:"name"` + FileName string `json:"fileName"` + Offset int `json:"offset"` + Shared bool `json:"shared"` + DeleteModel string `json:"deleteModel"` + VolumePolicy string `json:"volumePolicy"` + Format string `json:"format"` + BlockDeviceId string `json:"blockDeviceId"` + DiskType string `json:"diskType"` + DataStoreId string `json:"dataStoreId"` + DataStoreName string `json:"dataStoreName"` + DataStoreSize float64 `json:"dataStoreSize"` + FreeStorage float64 `json:"freeStorage"` + DataStoreType string `json:"dataStoreType"` + DataStoreReplicate int `json:"dataStoreReplicate"` + VMName string `json:"vmName"` + VMStatus string `json:"vmStatus"` + Type string `json:"type"` + Description string `json:"description"` + Bootable bool `json:"bootable"` + VolumeStatus string `json:"volumeStatus"` + MountedHostIds string `json:"mountedHostIds"` + Md5 string `json:"md5"` + DataSize int `json:"dataSize"` + OpenStackId string `json:"openStackId"` + VvSourceDto VvSourceDto `json:"vvSourceDto"` + FormatDisk bool `json:"formatDisk"` + ToBeConverted bool `json:"toBeConverted"` + RelatedVms string `json:"relatedVms"` + XactiveDataStoreId string `json:"xactiveDataStoreId"` + ClusterSize int `json:"clusterSize"` + ScsiId string `json:"scsiId"` + SecondaryUUID string `json:"secondaryUuid"` + SecondaryVolumes []struct{} `json:"secondaryVolumes"` +} + +type Disks struct { + Id string `json:"id"` + Label string `json:"label"` + ScsiId string `json:"scsiId"` + Enabled bool `json:"enabled"` + WriteBps int `json:"writeBps"` + ReadBps int `json:"readBps"` + TotalBps int `json:"totalBps"` + TotalIops int `json:"totalIops"` + WriteIops int `json:"writeIops"` + ReadIops int `json:"readIops"` + Volume Volume `json:"volume"` + BusModel string `json:"busModel"` + Usage float64 `json:"usage"` + MonReadIops float64 `json:"monReadIops"` + MonWriteIops float64 `json:"monWriteIops"` + ReadThroughput float64 `json:"readThroughput"` + WriteThroughput float64 `json:"writeThroughput"` + ReadWriteModel string `json:"readWriteModel"` + EnableNativeIO bool `json:"enableNativeIO"` + EnableKernelIO bool `json:"enableKernelIO"` + L2CacheSize int `json:"l2CacheSize"` + QueueNum int `json:"queueNum"` +} + +type CdpInfo struct { + CdpBackupDatastoreId string `json:"cdpBackupDatastoreId"` + BackupDataStoreName string `json:"backupDataStoreName"` + StartTime string `json:"startTime"` + EndTime string `json:"endTime"` + EnableCDP bool `json:"enableCDP"` + CdpAvgWriteMBps int `json:"cdpAvgWriteMBps"` + CdpRemainTimes int `json:"cdpRemainTimes"` + CdpLogSpaceSize int `json:"cdpLogSpaceSize"` + IntervalTime int `json:"intervalTime"` +} + +type GuestOSAuthInfo struct { + UserName string `json:"userName"` + UserPwd string `json:"userPwd"` +} + +type SInstance struct { + multicloud.SInstanceBase + InCloudSphereTags + + host *SHost + + osInfo *imagetools.ImageInfo + + Id string `json:"id"` + CustomVMId string `json:"customVmId"` + Name string `json:"name"` + State string `json:"state"` + Status string `json:"status"` + HostId string `json:"hostId"` + HostName string `json:"hostName"` + HostIP string `json:"hostIp"` + HostStatus string `json:"hostStatus"` + HostMemory int64 `json:"hostMemory"` + DataCenterId string `json:"dataCenterId"` + HaEnabled bool `json:"haEnabled"` + RouterFlag bool `json:"routerFlag"` + Migratable bool `json:"migratable"` + HostBinded bool `json:"hostBinded"` + ToolsInstalled bool `json:"toolsInstalled"` + ToolsVersion string `json:"toolsVersion"` + ToolsType string `json:"toolsType"` + ToolsVersionStatus string `json:"toolsVersionStatus"` + ToolsRunningStatus string `json:"toolsRunningStatus"` + ToolsNeedUpdate bool `json:"toolsNeedUpdate"` + Description string `json:"description"` + HaMaxLimit int64 `json:"haMaxLimit"` + Template bool `json:"template"` + Initialized bool `json:"initialized"` + GuestosLabel string `json:"guestosLabel"` + GuestosType string `json:"guestosType"` + GuestOSInfo struct { + Model string `json:"model"` + SocketLimit int `json:"socketLimit"` + SupportCpuHotPlug bool `json:"supportCpuHotPlug"` + SupportDiskHotPlug bool `json:"supportDiskHotPlug"` + SupportMemHotPlug bool `json:"supportMemHotPlug"` + SupportUefiBootMode bool `json:"supportUefiBootMode"` + } `json:"guestOsInfo"` + InnerName string `json:"innerName"` + UUId string `json:"uuid"` + MaxMemory int64 `json:"maxMemory"` + Memory int `json:"memory"` + MemoryUsage int64 `json:"memoryUsage"` + MemHotplugEnabled bool `json:"memHotplugEnabled"` + EnableHugeMemPage bool `json:"enableHugeMemPage"` + CPUNum int `json:"cpuNum"` + CPUSocket int `json:"cpuSocket"` + CPUCore int64 `json:"cpuCore"` + CPUUsage int64 `json:"cpuUsage"` + MaxCPUNum int64 `json:"maxCpuNum"` + CPUHotplugEnabled bool `json:"cpuHotplugEnabled"` + CPUModelType string `json:"cpuModelType"` + CPUModelEnabled bool `json:"cpuModelEnabled"` + RunningTime int64 `json:"runningTime"` + Boot string `json:"boot"` + BootMode string `json:"bootMode"` + SplashTime int64 `json:"splashTime"` + StoragePriority int64 `json:"storagePriority"` + USB string `json:"usb"` + + //Usbs []interface{} `json:"usbs"` + Cdrom Cdrom `json:"cdrom"` + Floppy Floppy `json:"floppy"` + Disks []Disks `json:"disks"` + Nics []SInstanceNic `json:"nics"` + + //Gpus []interface{} `json:"gpus"` + //VMPcis []interface{} `json:"vmPcis"` + ConfigLocation string `json:"configLocation"` + HotplugEnabled bool `json:"hotplugEnabled"` + VNCPort int64 `json:"vncPort"` + VNCPasswd string `json:"vncPasswd"` + VNCSharePolicy string `json:"vncSharePolicy"` + CPUBindType string `json:"cpuBindType"` + VcpuPin string `json:"vcpuPin"` + VcpuPins []string `json:"vcpuPins"` + CPUShares int64 `json:"cpuShares"` + PanickPolicy string `json:"panickPolicy"` + DataStoreId string `json:"dataStoreId"` + SdsdomainId string `json:"sdsdomainId"` + ClockModel string `json:"clockModel"` + CPULimit int64 `json:"cpuLimit"` + MemShares int64 `json:"memShares"` + CPUReservation int64 `json:"cpuReservation"` + MemReservation int64 `json:"memReservation"` + LastBackup string `json:"lastBackup"` + VMType string `json:"vmType"` + SystemVMType string `json:"systemVmType"` + MemBalloonEnabled bool `json:"memBalloonEnabled"` + Completed bool `json:"completed"` + GraphicsCardModel string `json:"graphicsCardModel"` + GraphicsCardMemory int64 `json:"graphicsCardMemory"` + GraphicsCards string `json:"graphicsCards"` + VMHostName string `json:"vmHostName"` + DiskTotalSize int64 `json:"diskTotalSize"` + DiskUsedSize float64 `json:"diskUsedSize"` + DiskUsage float64 `json:"diskUsage"` + StartPriority string `json:"startPriority"` + OwnerName string `json:"ownerName"` + Version string `json:"version"` + EnableReplicate bool `json:"enableReplicate"` + ReplicationDatastoreId string `json:"replicationDatastoreId"` + ReplicationDatastoreName string `json:"replicationDatastoreName"` + RecoveryFlag bool `json:"recoveryFlag"` + SpiceUSBNum int64 `json:"spiceUsbNum"` + CDPInfo CdpInfo `json:"cdpInfo"` + GuestOSAuthInfo GuestOSAuthInfo `json:"guestOSAuthInfo"` + AwareNUMAEnabled bool `json:"awareNumaEnabled"` + DrxEnabled bool `json:"drxEnabled"` + SecretLevel string `json:"secretLevel"` + //VmfpgaDevs []interface{} `json:"vmfpgaDevs"` +} + +func (self *SInstance) GetName() string { + return self.Name +} + +func (self *SInstance) GetId() string { + return self.Id +} + +func (self *SInstance) GetGlobalId() string { + return self.GetId() +} + +func (self *SInstance) Refresh() error { + ins, err := self.host.zone.region.GetInstance(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, ins) +} + +func (self *SInstance) AssignSecurityGroup(id string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return self.host.zone.region.AttachDisk(self.Id, diskId) +} + +func (self *SInstance) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error { + return self.host.zone.region.ChangeConfig(self.Id, opts.Cpu, opts.MemoryMB) +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + return self.host.zone.region.DeleteVM(self.Id) +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return self.host.zone.region.ResetVmPassword(self.Id, username, password) +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return self.host.zone.region.DetachDisk(self.Id, diskId) +} + +func (self *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(self.BootMode) +} + +func (self *SInstance) GetBootOrder() string { + return strings.ToLower(self.Boot) +} + +func (self *SInstance) GetError() error { + return nil +} + +func (self *SInstance) GetHostname() string { + return self.HostName +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_INCLOUD_SPHERE +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + ret := []cloudprovider.ICloudDisk{} + for i := range self.Disks { + disk, err := self.host.zone.region.GetDisk(self.Disks[i].Volume.Id) + if err != nil { + return nil, err + } + ret = append(ret, disk) + } + return ret, nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + ret := []cloudprovider.ICloudNic{} + for i := range self.Nics { + self.Nics[i].ins = self + ret = append(ret, &self.Nics[i]) + } + return ret, nil +} + +func (self *SInstance) GetInstanceType() string { + return fmt.Sprintf("ecs.g1.c%dm%d", self.GetVcpuCount(), self.GetVmemSizeMB()/1024) +} + +func (self *SInstance) GetMachine() string { + return "" +} + +/* +PENDING 开启准备中 +STARTING 开启或恢复中 +STARTED 开启的 +PAUSING 暂停中 +PAUSED 暂停的 +RESTARTING 重启中 +STOPPING 关机中 +STOPPED 关闭的 +HOT_SAVING 开机快照中 +COLD_SAVING 关机快照中 +PRE_MIGRATE 迁移准备中 +HOT_MIGRATING 热迁移中 +COLD_MIGRATING 冷迁移中 +REVERTING 恢复快照中 +EXPORTING 导出中 +IMPORTING 导入中 +COLD_BACKUPING 关机备份中 +HOT_BACKUPING 开机备份中 +COLD_MODIFYING 冷配置中 +HOT_MODIFYING 热配置中 +COLD_COPING 关机复制中 +*/ + +func (self *SInstance) GetStatus() string { + switch strings.ToUpper(self.Status) { + case "COLD_COPING", "COLD_BACKUPING", "COLD_SAVING", "STOPPED": + return api.VM_READY + case "PENDING", "STARTING": + return api.VM_START_START + case "STARTED", "HOT_SAVING", "HOT_BACKUPING": + return api.VM_RUNNING + case "PAUSING", "RESTARTING", "STOPPING": + return api.VM_START_STOP + case "REVERTING", "EXPORTING", "IMPORTING", "COLD_MODIFYING", "HOT_MODIFYING": + return api.VM_RESUMING + case "PRE_MIGRATE", "HOT_MIGRATING", "COLD_MIGRATING": + return api.VM_MIGRATING + } + return strings.ToLower(self.Status) +} + +func (i *SInstance) GetFullOsName() string { + return i.GuestOSInfo.Model +} + +func (i *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(i.GuestosType) +} + +func (i *SInstance) GetOsArch() string { + return i.GetIHost().GetCpuArchitecture() +} + +func (i *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { + if i.osInfo == nil { + osInfo := imagetools.NormalizeImageInfo(i.GuestOSInfo.Model, "", "", "", "") + i.osInfo = &osInfo + } + return i.osInfo +} + +func (i *SInstance) GetOsDist() string { + return i.getNormalizedOsInfo().OsDistro +} + +func (i *SInstance) GetOsVersion() string { + return i.getNormalizedOsInfo().OsVersion +} + +func (i *SInstance) GetOsLang() string { + return i.getNormalizedOsInfo().OsLang +} + +func (self *SInstance) GetProjectId() string { + return "" +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + ret := &cloudprovider.ServerVncOutput{ + Protocol: "vnc", + Host: self.host.Name, + Port: self.VNCPort, + Id: self.Id, + Password: "1q@W3e$R", + } + return ret, nil +} + +func (self *SInstance) GetVcpuCount() int { + return int(self.CPUNum) +} + +func (self *SInstance) GetVmemSizeMB() int { + return int(self.Memory) +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + return []string{}, nil +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) StartVM(ctx context.Context) error { + return self.host.zone.region.StartVm(self.Id, "", "") +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + if self.GetStatus() == api.VM_READY { + return nil + } + return self.host.zone.region.StopVm(self.Id) +} + +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetInstances(hostId string) ([]SInstance, error) { + ret := []SInstance{} + res := fmt.Sprintf("/hosts/%s/vms", hostId) + return ret, self.list(res, url.Values{}, &ret) +} + +func (self *SRegion) GetInstance(id string) (*SInstance, error) { + ret := &SInstance{} + res := fmt.Sprintf("/vms/%s", id) + return ret, self.get(res, nil, ret) +} + +func (self *SRegion) StartVm(id string, password, publicKey string) error { + res := fmt.Sprintf("/vms/%s", id) + params := url.Values{} + params.Set("action", "poweron") + if len(password) > 0 { + params.Set("os-passwd", password) + } + if len(publicKey) > 0 { + params.Set("publicKey", publicKey) + } + return self.put(res, params, nil, nil) +} + +func (self *SRegion) StopVm(id string) error { + res := fmt.Sprintf("/vms/%s", id) + params := url.Values{} + params.Set("action", "poweroff") + return self.put(res, params, nil, nil) +} + +func (self *SRegion) AttachDisk(vmId, diskId string) error { + disk, err := self.GetDisk(diskId) + if err != nil { + return errors.Wrapf(err, "GetDisk(%s)", diskId) + } + vm, err := self.GetInstance(vmId) + if err != nil { + return errors.Wrapf(err, "GetInstance(%s)", vmId) + } + vm.VNCPasswd = "" + diskInfo := Disks{ + BusModel: "VIRTIO", + ReadWriteModel: "NONE", + QueueNum: 1, + Volume: Volume{ + Id: disk.Id, + Size: disk.Size, + }, + } + vm.Disks = append(vm.Disks, diskInfo) + return self.put("/vms/"+vm.Id, nil, jsonutils.Marshal(vm), nil) +} + +func (self *SRegion) DetachDisk(vmId, diskId string) error { + vm, err := self.GetInstance(vmId) + if err != nil { + return errors.Wrapf(err, "GetInstance(%s)", vmId) + } + vm.VNCPasswd = "" + disks := []Disks{} + for i := 0; i < len(vm.Disks); i++ { + if vm.Disks[i].Volume.Id == diskId { + continue + } + disks = append(disks, vm.Disks[i]) + } + vm.Disks = disks + return self.put("/vms/"+vm.Id, nil, jsonutils.Marshal(vm), nil) +} + +func (self *SRegion) ChangeConfig(vmId string, cpu int, memMb int) error { + vm, err := self.GetInstance(vmId) + if err != nil { + return errors.Wrapf(err, "GetInstance(%s)", vmId) + } + vm.VNCPasswd = "" + changed := false + if cpu > 0 { + vm.CPUCore = 1 + vm.CPUNum = cpu + vm.CPUSocket = cpu + changed = true + } + if memMb > 0 { + vm.Memory = memMb + changed = true + } + if !changed { + return nil + } + return self.put("/vms/"+vm.Id, nil, jsonutils.Marshal(vm), nil) +} + +func (self *SRegion) ResetVmPassword(vmId string, username, password string) error { + params := url.Values{} + params.Set("action", "updateOsAuth") + body := map[string]interface{}{ + "userName": username, + "userPwd": password, + } + return self.put("/vms/"+vmId, params, jsonutils.Marshal(body), nil) +} + +func (self *SRegion) DeleteVM(vmId string) error { + params := url.Values{} + params.Set("type", "force") + return self.del("/vms/"+vmId, params, nil) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/network.go new file mode 100644 index 0000000000..f56e3e7573 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/network.go @@ -0,0 +1,184 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + InCloudSphereTags + + wire *SWire + + Id string `json:"id"` + Name string `json:"name"` + ResourceId string `json:"resourceId"` + Vlan int `json:"vlan"` + VlanFlag bool `json:"vlanFlag"` + Mtu string `json:"mtu"` + Type string `json:"type"` + VswitchDto SWire `json:"vswitchDto"` + //PortDtos []string `json:"portDtos"` + VMDtos string `json:"vmDtos"` + VnicDtos string `json:"vnicDtos"` + Vmcount int `json:"vmcount"` + Vniccount int `json:"vniccount"` + ConnectMode string `json:"connectMode"` + // 约定未开启dhcp时,描述信息里面放置/ + Description string `json:"description"` + UplinkRate int `json:"uplinkRate"` + UplinkBurst int `json:"uplinkBurst"` + DownlinkRate int `json:"downlinkRate"` + DownlinkBurst int `json:"downlinkBurst"` + QosEnabled bool `json:"qosEnabled"` + DataServiceType string `json:"dataServiceType"` + UserVlan string `json:"userVlan"` + TpidType string `json:"tpidType"` + PermitDel bool `json:"permitDel"` + Cidr string `json:"cidr"` + Gateway string `json:"gateway"` + DhcpEnabled bool `json:"dhcpEnabled"` + DNS string `json:"dns"` + DataCenterDto SZone `json:"dataCenterDto"` + NetworkTopoly bool `json:"networkTopoly"` +} + +func (self *SNetwork) GetCidr() string { + if len(self.Cidr) > 0 { + return self.Cidr + } + _, err := netutils.NewIPV4Prefix(self.Description) + if err == nil { + return self.Description + } + return "0.0.0.0/0" +} + +func (self *SNetwork) GetName() string { + return self.Name +} + +func (self *SNetwork) GetId() string { + return self.Id +} + +func (self *SNetwork) GetGlobalId() string { + return self.GetId() +} + +func (self *SNetwork) Refresh() error { + ret, err := self.wire.region.GetNetwork(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, ret) +} + +func (self *SNetwork) Delete() error { + return cloudprovider.ErrNotFound +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (self *SNetwork) GetGateway() string { + if len(self.Gateway) > 0 { + return self.Gateway + } + if len(self.Description) > 0 && strings.Contains(self.Description, "/") { + info := strings.Split(self.Description, "/") + ip, err := netutils.NewIPV4Addr(info[0]) + if err == nil { + return ip.String() + } + } + return self.Gateway +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpStart() string { + _range, err := netutils.NewIPV4Prefix(self.GetCidr()) + if err != nil { + return "" + } + return _range.ToIPRange().StartIp().StepUp().String() +} + +func (self *SNetwork) GetIpEnd() string { + _range, err := netutils.NewIPV4Prefix(self.GetCidr()) + if err != nil { + return "" + } + return _range.ToIPRange().EndIp().StepDown().String() +} + +func (self *SNetwork) Contains(_ip string) bool { + start, _ := netutils.NewIPV4Addr(self.GetIpStart()) + end, _ := netutils.NewIPV4Addr(self.GetIpEnd()) + ip, _ := netutils.NewIPV4Addr(_ip) + return netutils.NewIPV4AddrRange(start, end).Contains(ip) +} + +func (self *SNetwork) GetIpMask() int8 { + pref, err := netutils.NewIPV4Prefix(self.GetCidr()) + if err != nil { + return 0 + } + return pref.MaskLen +} + +func (self *SNetwork) GetProjectId() string { + return "" +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetStatus() string { + return api.NETWORK_STATUS_AVAILABLE +} + +func (self *SRegion) GetNetworks(vsId string) ([]SNetwork, error) { + ret := []SNetwork{} + res := fmt.Sprintf("/vswitchs/%s/networks", vsId) + return ret, self.list(res, url.Values{}, &ret) +} + +func (self *SRegion) GetNetwork(id string) (*SNetwork, error) { + ret := &SNetwork{} + res := fmt.Sprintf("/networks/%s", id) + return ret, self.get(res, url.Values{}, ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/nic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/nic.go new file mode 100644 index 0000000000..2fc474293f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/nic.go @@ -0,0 +1,129 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "strings" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + cloudprovider.DummyICloudNic + ins *SInstance + + Id string `json:"id"` + AutoGenerated bool `json:"autoGenerated"` + Name string `json:"name"` + NolocalName string `json:"nolocalName"` + InnerName string `json:"innerName"` + DevName string `json:"devName"` + IP string `json:"ip"` + Netmask string `json:"netmask"` + Gateway string `json:"gateway"` + Mac string `json:"mac"` + Model string `json:"model"` + DeviceId string `json:"deviceId"` + DeviceName string `json:"deviceName"` + DeviceType string `json:"deviceType"` + SwitchType string `json:"switchType"` + VswitchId string `json:"vswitchId"` + UplinkRate int `json:"uplinkRate"` + UplinkBurst int `json:"uplinkBurst"` + DownlinkRate int `json:"downlinkRate"` + DownlinkBurst int `json:"downlinkBurst"` + DownlinkQueue string `json:"downlinkQueue"` + Enable bool `json:"enable"` + Status string `json:"status"` + InboundRate float64 `json:"inboundRate"` + OutboundRate float64 `json:"outboundRate"` + ConnectStatus bool `json:"connectStatus"` + VMName string `json:"vmName"` + VMId string `json:"vmId"` + VMStatus string `json:"vmStatus"` + VMTemplate bool `json:"vmTemplate"` + NetworkName string `json:"networkName"` + NetworkVlan string `json:"networkVlan"` + VlanRange string `json:"vlanRange"` + NetworkId string `json:"networkId"` + NetworkType string `json:"networkType"` + HostIP string `json:"hostIp"` + HostStatus string `json:"hostStatus"` + HostId string `json:"hostId"` + DirectObjName string `json:"directObjName"` + TotalOctets float64 `json:"totalOctets"` + TotalDropped float64 `json:"totalDropped"` + TotalPackets float64 `json:"totalPackets"` + TotalBytes float64 `json:"totalBytes"` + TotalErrors float64 `json:"totalErrors"` + WriteOctets float64 `json:"writeOctets"` + WriteDropped float64 `json:"writeDropped"` + WritePackets float64 `json:"writePackets"` + WriteBytes float64 `json:"writeBytes"` + WriteErrors float64 `json:"writeErrors"` + ReadOctets float64 `json:"readOctets"` + ReadDropped float64 `json:"readDropped"` + ReadPackets float64 `json:"readPackets"` + ReadBytes float64 `json:"readBytes"` + ReadErrors float64 `json:"readErrors"` + SecurityGroups string `json:"securityGroups"` + AdvancedNetIP string `json:"advancedNetIp"` + PortId string `json:"portId"` + SdnVFId string `json:"sdnVFId"` + OpenstackId string `json:"openstackId"` + BindIPEnable bool `json:"bindIpEnable"` + BindIP string `json:"bindIp"` + PriorityEnabled bool `json:"priorityEnabled"` + NetPriority string `json:"netPriority"` + VMType string `json:"vmType"` + SystemVMType string `json:"systemVmType"` + Dhcp bool `json:"dhcp"` + DhcpIP string `json:"dhcpIp"` + DhcpEnabled bool `json:"dhcpEnabled"` + UsedDpdk bool `json:"usedDpdk"` + Queues int `json:"queues"` +} + +func (self *SInstanceNic) GetId() string { + return self.Id +} + +func (self *SInstanceNic) GetIP() string { + return self.IP +} + +func (self *SInstanceNic) GetMAC() string { + return self.Mac +} + +func (self *SInstanceNic) GetDriver() string { + return strings.ToLower(self.Model) +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return true +} + +func (self *SInstanceNic) GetSubAddress() ([]string, error) { + return []string{}, nil +} + +func (self *SInstanceNic) GetINetworkId() string { + return self.NetworkId +} + +func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/provider/doc.go new file mode 100644 index 0000000000..1a34d12fdd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/provider/provider.go new file mode 100644 index 0000000000..5399b9d39c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/provider/provider.go @@ -0,0 +1,171 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/regutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/incloudsphere" +) + +type SInCloudSphereProviderFactory struct { + cloudprovider.SPrivateCloudBaseProviderFactory +} + +func (self *SInCloudSphereProviderFactory) GetId() string { + return incloudsphere.CLOUD_PROVIDER_INCLOUD_SPHERE +} + +func (self *SInCloudSphereProviderFactory) GetName() string { + return incloudsphere.CLOUD_PROVIDER_INCLOUD_SPHERE +} + +func (self *SInCloudSphereProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { + return fmt.Errorf("Changing %s bandwidth is not supported", incloudsphere.CLOUD_PROVIDER_INCLOUD_SPHERE) +} + +func (self *SInCloudSphereProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + if len(input.Host) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "host") + } + input.Host = strings.TrimPrefix(input.Host, "https://") + input.Host = strings.TrimPrefix(input.Host, "http://") + if !regutils.MatchIPAddr(input.Host) && !regutils.MatchDomainName(input.Host) { + return output, errors.Wrap(httperrors.ErrInputParameter, "host should be ip or domain name") + } + output.AccessUrl = input.Host + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + return output, nil +} + +func (self *SInCloudSphereProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func (self *SInCloudSphereProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + client, err := incloudsphere.NewSphereClient( + incloudsphere.NewSphereClientConfig( + cfg.URL, cfg.Account, cfg.Secret, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SInCloudSphereProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SInCloudSphereProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + return map[string]string{ + "INCLOUD_SPHERE_HOST": info.Url, + "INCLOUD_SPHERE_ACCESS_KEY_ID": info.Account, + "INCLOUD_SPHERE_ACCESS_KEY_SECRET": info.Secret, + }, nil +} + +func init() { + factory := SInCloudSphereProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SInCloudSphereProvider struct { + cloudprovider.SBaseProvider + client *incloudsphere.SphereClient +} + +func (self *SInCloudSphereProvider) GetSysInfo() (jsonutils.JSONObject, error) { + return jsonutils.NewDict(), nil +} + +func (self *SInCloudSphereProvider) GetVersion() string { + return "5.8" +} + +func (self *SInCloudSphereProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SInCloudSphereProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SInCloudSphereProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SInCloudSphereProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + regions := self.GetIRegions() + for i := range regions { + if regions[i].GetGlobalId() == id { + return regions[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SInCloudSphereProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SInCloudSphereProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return []cloudprovider.ICloudProject{}, nil +} + +func (self *SInCloudSphereProvider) GetStorageClasses(regionId string) []string { + return nil +} + +func (self *SInCloudSphereProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (self *SInCloudSphereProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (self *SInCloudSphereProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/region.go new file mode 100644 index 0000000000..4067b34a43 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/region.go @@ -0,0 +1,212 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "fmt" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + multicloud.SRegion + multicloud.SRegionEipBase + multicloud.SNoObjectStorageRegion + multicloud.SRegionLbBase + + client *SphereClient +} + +func (self *SRegion) GetClient() *SphereClient { + return self.client +} + +func (self *SRegion) GetName() string { + return self.client.cpcfg.Name +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) + return table +} + +func (self *SRegion) GetId() string { + return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_INCLOUD_SPHERE, self.client.cpcfg.Id) +} + +func (self *SRegion) GetGlobalId() string { + return self.GetId() +} + +func (self *SRegion) GetProvider() string { + return CLOUD_PROVIDER_INCLOUD_SPHERE +} + +func (self *SRegion) GetCloudEnv() string { + return "" +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) Refresh() error { + return nil +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) CreateIVpc(conf *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SRegion) getVpc() *SVpc { + return &SVpc{region: self} +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + vpc := self.getVpc() + return []cloudprovider.ICloudVpc{vpc}, nil +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + vpcs, err := self.GetIVpcs() + if err != nil { + return nil, err + } + for i := range vpcs { + if vpcs[i].GetGlobalId() == id { + return vpcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + zone, err := self.GetZone(id) + if err != nil { + return nil, errors.Wrapf(err, "GetZone(%s)", id) + } + return zone, nil +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + zones, err := self.GetZones() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudZone{} + for i := range zones { + zones[i].region = self + ret = append(ret, &zones[i]) + } + return ret, nil +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := self.GetInstance(id) + if err != nil { + return nil, err + } + return vm, nil +} + +func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + host, err := self.GetHost(id) + if err != nil { + return nil, err + } + zone, err := self.GetZone(host.DataCenterId) + if err != nil { + return nil, err + } + host.zone = zone + return host, nil +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + zones, err := self.GetZones() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStoragecache{} + for i := range zones { + cache := &SStoragecache{zone: &zones[i]} + ret = append(ret, cache) + } + return ret, nil +} + +func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + caches, err := self.GetIStoragecaches() + if err != nil { + return nil, err + } + for i := range caches { + if caches[i].GetGlobalId() == id { + return caches[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) _list(res string, params url.Values) (jsonutils.JSONObject, error) { + return self.client._list(res, params) +} + +func (self *SRegion) list(res string, params url.Values, retVal interface{}) error { + return self.client.list(res, params, retVal) +} + +func (self *SRegion) get(res string, params url.Values, retVal interface{}) error { + return self.client.get(res, params, retVal) +} + +func (self *SRegion) post(res string, params interface{}) (jsonutils.JSONObject, error) { + return self.client.post(res, params) +} + +func (self *SRegion) put(res string, params url.Values, body jsonutils.JSONObject, retVal interface{}) error { + return self.client.put(res, params, body, retVal) +} + +func (self *SRegion) del(res string, params url.Values, retVal interface{}) error { + return self.client.del(res, params, retVal) +} diff --git a/pkg/multicloud/incloudsphere/sphere.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/sphere.go similarity index 98% rename from pkg/multicloud/incloudsphere/sphere.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/sphere.go index 59ab69541b..a07e2227d1 100644 --- a/pkg/multicloud/incloudsphere/sphere.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/sphere.go @@ -25,8 +25,8 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/storage.go new file mode 100644 index 0000000000..6339c447ba --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/storage.go @@ -0,0 +1,224 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type DataCenterOrHostDto struct { + DataCenterOrHost string `json:"dataCenterOrHost"` + DataCenterName string `json:"dataCenterName"` + HostName string `json:"hostName"` + Status string `json:"status"` +} + +type BlockDeviceDto struct { + ID string `json:"id"` + Name string `json:"name"` + PartitionFlag bool `json:"partitionFlag"` + PartitionNumber string `json:"partitionNumber"` + Capacity int `json:"capacity"` + DisplayCapacity string `json:"displayCapacity"` + DiskType string `json:"diskType"` + AbsolutePath string `json:"absolutePath"` + Transport string `json:"transport"` + Used string `json:"used"` + IsUsed bool `json:"isUsed"` +} + +type SStorage struct { + multicloud.SStorageBase + InCloudSphereTags + + zone *SZone + + Id string `json:"id"` + Name string `json:"name"` + MountPath string `json:"mountPath"` + DataStoreType string `json:"dataStoreType"` + Capacity float64 `json:"capacity"` + UsedCapacity float64 `json:"usedCapacity"` + AvailCapacity float64 `json:"availCapacity"` + DataCenterId string `json:"dataCenterId"` + HostId string `json:"hostId"` + MountStatus string `json:"mountStatus"` + HostIP string `json:"hostIp"` + UUID string `json:"uuid"` + AbsolutePath string `json:"absolutePath"` + DataCenterName string `json:"dataCenterName"` + DataCenterOrHostDto DataCenterOrHostDto `json:"dataCenterOrHostDto"` + BlockDeviceDto BlockDeviceDto `json:"blockDeviceDto"` + XactiveStoreName string `json:"xactiveStoreName"` + XactiveStoreId string `json:"xactiveStoreId"` + DataCenterDto string `json:"dataCenterDto"` + HostNumbers int `json:"hostNumbers"` + VMNumbers int `json:"vmNumbers"` + VolumesNumbers int `json:"volumesNumbers"` + VMTemplateNumbers int `json:"vmTemplateNumbers"` + Tags string `json:"tags"` + MaxSlots int `json:"maxSlots"` + Creating bool `json:"creating"` + StorageBackUp bool `json:"storageBackUp"` + ExtensionType string `json:"extensionType"` + CanBeImageStorage bool `json:"canBeImageStorage"` + MultiplexRatio float64 `json:"multiplexRatio"` + Oplimit bool `json:"oplimit"` + Maxop int `json:"maxop"` + MountStateCount string `json:"mountStateCount"` + DatastoreRole string `json:"datastoreRole"` + CanCreateXactive bool `json:"canCreateXactive"` + BlockDeviceUUId string `json:"blockDeviceUuid"` + OpHostIP string `json:"opHostIp"` + IsMount string `json:"isMount"` + HostDto string `json:"hostDto"` + ScvmOn bool `json:"scvmOn"` +} + +func (self *SStorage) GetName() string { + return self.Name +} + +func (self *SStorage) GetId() string { + return self.Id +} + +func (self *SStorage) GetGlobalId() string { + return self.GetId() +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := self.zone.region.GetDisks(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudDisk{} + for i := range disks { + disks[i].region = self.zone.region + ret = append(ret, &disks[i]) + } + return ret, nil +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + disk, err := self.zone.region.CreateDisk(conf.Name, self.Id, conf.SizeGb) + if err != nil { + return nil, err + } + return disk, nil +} + +func (self *SStorage) GetCapacityMB() int64 { + return int64(self.Capacity) * 1024 +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return int64(self.UsedCapacity) * 1024 +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disk, err := self.zone.region.GetDisk(id) + if err != nil { + return nil, err + } + if disk.DataStoreId != self.Id { + return nil, cloudprovider.ErrNotFound + } + return disk, nil +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + cache := &SStoragecache{zone: self.zone} + return cache +} + +func (self *SStorage) GetMediumType() string { + return api.DISK_TYPE_SSD +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) Refresh() error { + ret, err := self.zone.region.GetStorage(self.GetGlobalId()) + if err != nil { + return err + } + return jsonutils.Update(self, ret) +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (self *SStorage) GetStorageType() string { + return strings.ToLower(self.DataStoreType) +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} + +func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storage, err := self.GetStorage(id) + if err != nil { + return nil, err + } + zone, err := self.GetZone(storage.DataCenterId) + if err != nil { + return nil, err + } + storage.zone = zone + return storage, nil +} + +func (self *SRegion) GetStoragesByDc(dcId string) ([]SStorage, error) { + storages := []SStorage{} + res := fmt.Sprintf("/datacenters/%s/storages", dcId) + return storages, self.list(res, url.Values{}, &storages) +} + +func (self *SRegion) GetStoragesByHost(hostId string) ([]SStorage, error) { + storages := []SStorage{} + res := fmt.Sprintf("/hosts/%s/storages", hostId) + return storages, self.list(res, url.Values{}, &storages) +} + +func (self *SRegion) GetStorage(id string) (*SStorage, error) { + ret := &SStorage{} + res := fmt.Sprintf("/storages/%s", id) + return ret, self.get(res, url.Values{}, ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/storagecache.go new file mode 100644 index 0000000000..e395032c15 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/storagecache.go @@ -0,0 +1,126 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "context" + "fmt" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStoragecache struct { + multicloud.SResourceBase + InCloudSphereTags + + zone *SZone +} + +func (self *SStoragecache) GetGlobalId() string { + return self.zone.GetGlobalId() +} + +func (self *SStoragecache) GetId() string { + return self.zone.GetId() +} + +func (self *SStoragecache) GetName() string { + return self.zone.GetName() +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + ret := []cloudprovider.ICloudImage{} + iss, err := self.zone.region.GetImageStorages(self.zone.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetImageStorages") + } + for i := range iss { + images, err := self.zone.region.GetImageList(iss[i].Id) + if err != nil { + return nil, err + } + for j := range images { + if utils.IsInStringArray(images[j].GetImageFormat(), []string{"iso", "ova"}) { + continue + } + images[j].cache = self + ret = append(ret, &images[j]) + } + } + return ret, nil +} + +func (seflf *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SStoragecache) GetIImageById(id string) (cloudprovider.ICloudImage, error) { + images, err := self.GetICloudImages() + if err != nil { + return nil, err + } + for i := range images { + if images[i].GetGlobalId() == id { + return images[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +func (self *SStoragecache) CreateIImage(snpId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +type SImageStorage struct { + Id string + Name string +} + +func (self *SRegion) GetImageStorages(dsId string) ([]SImageStorage, error) { + params := url.Values{} + params.Set("type", "imagestorage") + res := fmt.Sprintf("/datacenters/%s/storages", dsId) + ret := []SImageStorage{} + return ret, self.get(res, params, &ret) +} + +func (self *SRegion) GetImageList(storageId string) ([]SImage, error) { + res := fmt.Sprintf("/storages/%s/files", storageId) + ret := []SImage{} + return ret, self.list(res, url.Values{}, &ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/tag_base.go new file mode 100644 index 0000000000..6ab92b692d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/tag_base.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type InCloudSphereTags struct { +} + +func (self *InCloudSphereTags) GetTags() (map[string]string, error) { + tags := map[string]string{} + return tags, nil +} + +func (self *InCloudSphereTags) GetSysTags() map[string]string { + return nil +} + +func (self *InCloudSphereTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/task.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/task.go new file mode 100644 index 0000000000..6051d53da0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/task.go @@ -0,0 +1,58 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "fmt" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type STask struct { + Id string + Name string + Detail string + Error string + State string + CreatedResourceId string +} + +func (self *SphereClient) waitTask(id string) (string, error) { + resId := "" + return resId, cloudprovider.Wait(time.Second*10, time.Minute*10, func() (bool, error) { + task := &STask{} + err := self.get("/tasks/"+id, nil, task) + if err != nil { + return false, errors.Wrapf(err, "get task %s", id) + } + switch task.State { + case "WAITING", "READY", "RUNNING": + log.Debugf("task %s with %s state: %s", task.Id, task.Detail, task.State) + return false, nil + case "FINISHED": + resId = task.CreatedResourceId + return true, nil + case "ERROR": + return false, fmt.Errorf("%s: %s", task.Detail, task.Error) + default: + log.Debugf("task %s with %s state: %s", task.Id, task.Detail, task.State) + return false, fmt.Errorf("%s: %s invalid state: %v", task.Detail, task.Error, task.State) + } + }) +} diff --git a/pkg/multicloud/incloudsphere/version.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/version.go similarity index 100% rename from pkg/multicloud/incloudsphere/version.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/version.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/vpc.go new file mode 100644 index 0000000000..c09c83422e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/vpc.go @@ -0,0 +1,98 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + InCloudSphereTags + + region *SRegion +} + +func (self *SVpc) GetName() string { + return "Default" +} + +func (self *SVpc) GetId() string { + return self.region.GetId() +} + +func (self *SVpc) GetGlobalId() string { + return self.GetId() +} + +func (self *SVpc) Delete() error { + return cloudprovider.ErrNotSupported +} + +func (self *SVpc) IsEmulated() bool { + return true +} + +func (self *SVpc) GetCidrBlock() string { + return "0.0.0.0/0" +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + return []cloudprovider.ICloudRouteTable{}, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + return []cloudprovider.ICloudSecurityGroup{}, nil +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + wires, err := self.region.GetWires() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudWire{} + for i := range wires { + wires[i].region = self.region + ret = append(ret, &wires[i]) + } + return ret, nil +} + +func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { + wire, err := self.region.GetWire(id) + if err != nil { + return nil, err + } + wire.region = self.region + return wire, nil +} + +func (self *SVpc) GetIsDefault() bool { + return true +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/wire.go new file mode 100644 index 0000000000..13d110ec18 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/wire.go @@ -0,0 +1,146 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "fmt" + "net/url" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + InCloudSphereTags + + region *SRegion + + Id string `json:"id"` + Name string `json:"name"` + ResourceId string `json:"resourceId"` + ControllerIP string `json:"controllerIP"` + DataCenterDto SZone `json:"dataCenterDto"` + HostDtos []SHost `json:"hostDtos"` + SwitchType string `json:"switchType"` + AppType string `json:"appType"` + Description string `json:"description"` + NetworkDtos string `json:"networkDtos"` + SdnNetworkDtos string `json:"sdnNetworkDtos"` + VMDtos string `json:"vmDtos"` + HostNum int `json:"hostNum"` + PnicNum int `json:"pnicNum"` + NetworkNum int `json:"networkNum"` + VMNum int `json:"vmNum"` + Maxvfs int `json:"maxvfs"` + ThirdPartySDN bool `json:"thirdPartySDN"` + Hierarchy bool `json:"hierarchy"` + ConnectStorage bool `json:"connectStorage"` + ConnectManage bool `json:"connectManage"` + ConnectSwitches string `json:"connectSwitches"` + DhcpProtection bool `json:"dhcpProtection"` + NeutronName string `json:"neutronName"` + NeutronPassword string `json:"neutronPassword"` + ConnectScvm bool `json:"connectScvm"` + SwitchUplinkType string `json:"switchUplinkType"` + ComputerNetNum int `json:"computerNetNum"` + DataNetNum int `json:"dataNetNum"` + MigrateNetNum int `json:"migrateNetNum"` + VMMigBandWidth string `json:"vmMigBandWidth"` + EnableDpdk bool `json:"enableDpdk"` + SflowStatus bool `json:"sflowStatus"` + NetflowStatus bool `json:"netflowStatus"` + MulticastStatus bool `json:"multicastStatus"` + MirrorStatus bool `json:"mirrorStatus"` + BrLimitStatus bool `json:"brLimitStatus"` + Hidden bool `json:"hidden"` + NetworkTopoly bool `json:"networkTopoly"` +} + +func (self *SWire) GetName() string { + return self.Name +} + +func (self *SWire) GetId() string { + return self.Id +} + +func (self *SWire) GetGlobalId() string { + return self.GetId() +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SWire) GetBandwidth() int { + return 10000 +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + nets, err := self.region.GetNetworks(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNetwork{} + for i := range nets { + nets[i].wire = self + ret = append(ret, &nets[i]) + } + return ret, nil +} + +func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { + net, err := self.region.GetNetwork(id) + if err != nil { + return nil, err + } + net.wire = self + if net.VswitchDto.Id != self.Id { + return nil, cloudprovider.ErrNotFound + } + return net, nil +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.region.getVpc() +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + zone, _ := self.region.GetZone(self.DataCenterDto.Id) + return zone +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SRegion) GetWires() ([]SWire, error) { + ret := []SWire{} + return ret, self.list("/vswitchs", url.Values{}, &ret) +} + +func (self *SRegion) GetWiresByDs(dsId string) ([]SWire, error) { + ret := []SWire{} + res := fmt.Sprintf("/datacenters/%s/vswitchs", dsId) + return ret, self.list(res, url.Values{}, &ret) +} + +func (self *SRegion) GetWire(id string) (*SWire, error) { + ret := &SWire{region: self} + res := fmt.Sprintf("/vswitchs/%s", id) + return ret, self.get(res, url.Values{}, ret) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/zone.go new file mode 100644 index 0000000000..ab8c0d7a46 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/zone.go @@ -0,0 +1,156 @@ +// Copyright 2019 Yunion +// +// 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 incloudsphere + +import ( + "fmt" + "net/url" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SZone struct { + multicloud.SResourceBase + InCloudSphereTags + + region *SRegion + + Id string `json:"id"` + Name string `json:"name"` + NFSPath string `json:"nfsPath"` + Type string `json:"type"` + Description string `json:"description"` + HostNum int64 `json:"hostNum"` + VMNum int64 `json:"vmNum"` + ClusterNum int64 `json:"clusterNum"` + CfsDomainNum int64 `json:"cfsDomainNum"` + StorageNum int64 `json:"storageNum"` + ImageISONum int64 `json:"imageIsoNum"` + NetNum int64 `json:"netNum"` + NeutronNetNum int64 `json:"neutronNetNum"` + CPUCapacity string `json:"cpuCapacity"` + CPUAvailable string `json:"cpuAvailable"` + CPUUsed string `json:"cpuUsed"` + CPUUtilization string `json:"cpuUtilization"` + MemoryCapacity string `json:"memoryCapacity"` + MemoryAvailable string `json:"memoryAvailable"` + MemoryUsed string `json:"memoryUsed"` + MemoryUtilization string `json:"memoryUtilization"` + StorageCapacity string `json:"storageCapacity"` + StorageAvailable string `json:"storageAvailable"` + StorageUsed string `json:"storageUsed"` + StorageUtilization string `json:"storageUtilization"` + DatastoreNum int64 `json:"datastoreNum"` + LocalstoreNum int64 `json:"localstoreNum"` + CfsstoreNum int64 `json:"cfsstoreNum"` + RawstoreNum int64 `json:"rawstoreNum"` + NfsstoreNum int64 `json:"nfsstoreNum"` + XactivestoreNum int64 `json:"xactivestoreNum"` + NetworkType string `json:"networkType"` + VswitchDtos string `json:"vswitchDtos"` + //SDNNetworkDtos []interface{} `json:"sdnNetworkDtos"` + SDNInit bool `json:"sdnInit"` + SDNSpeedUp bool `json:"sdnSpeedUp"` + SDNConfigDto string `json:"sdnConfigDto"` +} + +func (self *SZone) GetId() string { + return self.Id +} + +func (self *SZone) GetGlobalId() string { + return self.Id +} + +func (self *SZone) GetName() string { + return self.Name +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) GetStatus() string { + return api.ZONE_ENABLE +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) + return table +} + +func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + host, err := self.region.GetHost(id) + if err != nil { + return nil, err + } + host.zone = self + if host.DataCenterId != self.Id { + return nil, cloudprovider.ErrNotFound + } + return host, nil +} + +func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + hosts, err := self.region.GetHosts(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudHost{} + for i := range hosts { + hosts[i].zone = self + ret = append(ret, &hosts[i]) + } + return ret, nil +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.region.GetStoragesByDc(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + storages[i].zone = self + ret = append(ret, &storages[i]) + } + return ret, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storage, err := self.region.GetStorage(id) + if err != nil { + return nil, err + } + if storage.DataCenterId != self.Id { + return nil, cloudprovider.ErrNotFound + } + storage.zone = self + return storage, nil +} + +func (self *SRegion) GetZones() ([]SZone, error) { + ret := []SZone{} + return ret, self.list("/datacenters", url.Values{}, &ret) +} + +func (self *SRegion) GetZone(id string) (*SZone, error) { + ret := &SZone{region: self} + res := fmt.Sprintf("/datacenters/%s", id) + return ret, self.get(res, url.Values{}, ret) +} diff --git a/pkg/multicloud/instance_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/instance_base.go similarity index 98% rename from pkg/multicloud/instance_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/instance_base.go index 7dc928304a..755a835732 100644 --- a/pkg/multicloud/instance_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/instance_base.go @@ -19,7 +19,7 @@ import ( "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SInstanceBase struct { diff --git a/pkg/multicloud/jdcloud/balance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/balance.go similarity index 100% rename from pkg/multicloud/jdcloud/balance.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/balance.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/disk.go new file mode 100644 index 0000000000..f4df78587f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/disk.go @@ -0,0 +1,285 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "context" + "fmt" + "time" + + commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" + "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/apis" + "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/client" + "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/models" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDisk struct { + storage *SStorage + + multicloud.SDisk + JdcloudTags + multicloud.SBillingBase + + models.Disk + + ImageId string + IsSystemDisk bool +} + +func (d *SDisk) GetBillingType() string { + return billingType(&d.Charge) +} + +func (d *SDisk) GetExpiredAt() time.Time { + return expireAt(&d.Charge) +} + +func (d *SDisk) GetId() string { + return d.DiskId +} + +func (d *SDisk) GetName() string { + return d.Name +} + +func (d *SDisk) GetGlobalId() string { + return d.GetId() +} + +func (d *SDisk) GetIops() int { + return d.Iops +} + +func (d *SDisk) GetStatus() string { + switch d.Status { + case "available", "in-use": + return api.DISK_READY + case "creating": + return api.DISK_ALLOCATING + case "extending": + return api.DISK_RESIZING + case "restoring": + return api.DISK_RESET + case "deleting": + return api.DISK_DEALLOC + case "error_create": + return api.DISK_ALLOC_FAILED + case "error_delete": + return api.DISK_DEALLOC_FAILED + case "error_restore": + return api.DISK_RESET_FAILED + case "error_extend": + return api.DISK_RESIZE_FAILED + default: + return api.DISK_UNKNOWN + } +} + +func (d *SDisk) Refresh() error { + return nil +} + +func (d *SDisk) IsEmulated() bool { + return false +} + +func (d *SDisk) GetSysTags() map[string]string { + return map[string]string{ + "hypervisor": api.HYPERVISOR_JDCLOUD, + } +} + +func (d *SDisk) GetProjectId() string { + return "" +} + +func (d *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return d.storage, nil +} + +func (d *SDisk) GetDiskFormat() string { + return "vhd" +} + +func (d *SDisk) GetDiskSizeMB() int { + return d.DiskSizeGB * 1024 +} + +func (d *SDisk) GetIsAutoDelete() bool { + if len(d.Attachments) == 0 { + return false + } + return true +} + +func (d *SDisk) GetTemplateId() string { + // TODO 通过快照创建的盘应该如何 + return d.ImageId +} + +func (d *SDisk) GetDiskType() string { + if d.IsSystemDisk { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +func (d *SDisk) GetFsFormat() string { + return "" +} + +func (d *SDisk) GetIsNonPersistent() bool { + return false +} + +func (d *SDisk) GetDriver() string { + return "scsi" +} + +func (d *SDisk) GetCacheMode() string { + return "none" +} + +func (d *SDisk) GetMountpoint() string { + return "" +} + +func (d *SDisk) GetAccessPath() string { + return "" +} + +func (d *SDisk) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (d *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (d *SDisk) GetISnapshot(id string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := d.storage.zone.region.GetSnapshotById(id) + if err != nil { + return nil, err + } + snapshot.disk = d + return snapshot, nil +} + +func (s *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots := make([]SSnapshot, 0) + n := 1 + for { + parts, total, err := s.storage.zone.region.GetSnapshots(s.DiskId, n, 100) + if err != nil { + return nil, err + } + snapshots = append(snapshots, parts...) + if len(snapshots) >= total { + break + } + n++ + } + isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := range snapshots { + snapshots[i].disk = s + isnapshots[i] = &snapshots[i] + } + return isnapshots, nil +} + +func (s *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { + return []string{}, nil +} + +func (s *SDisk) Resize(ctx context.Context, newSizeMB int64) error { + return cloudprovider.ErrNotImplemented +} + +func (s *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (s *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (r *SRegion) GetDisks(instanceId, zoneId, diskType string, diskIds []string, pageNumber, pageSize int) ([]SDisk, int, error) { + filters := []commodels.Filter{} + if instanceId != "" { + filters = append(filters, commodels.Filter{ + Name: "instanceId", + Values: []string{instanceId}, + }, commodels.Filter{ + Name: "instanceType", + Values: []string{"vm"}, + }) + } + if zoneId != "" { + filters = append(filters, commodels.Filter{ + Name: "az", + Values: []string{zoneId}, + }) + } + if len(diskIds) > 0 { + filters = append(filters, commodels.Filter{ + Name: "diskId", + Values: diskIds, + }) + } + if diskType != "" { + filters = append(filters, commodels.Filter{ + Name: "diskType", + Values: []string{diskType}, + }) + } + req := apis.NewDescribeDisksRequestWithAllParams(r.ID, &pageNumber, &pageSize, nil, filters) + client := client.NewDiskClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeDisks(req) + if err != nil { + return nil, 0, err + } + if resp.Error.Code >= 400 { + return nil, 0, fmt.Errorf(resp.Error.Message) + } + total := resp.Result.TotalCount + disks := make([]SDisk, 0, len(resp.Result.Disks)) + for i := range resp.Result.Disks { + disks = append(disks, SDisk{ + Disk: resp.Result.Disks[i], + }) + } + return disks, total, nil +} + +func (r *SRegion) GetDiskById(id string) (*SDisk, error) { + req := apis.NewDescribeDiskRequest(r.ID, id) + client := client.NewDiskClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeDisk(req) + if err != nil { + return nil, err + } + if resp.Error.Code >= 400 { + return nil, fmt.Errorf(resp.Error.Message) + } + return &SDisk{ + Disk: resp.Result.Disk, + }, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/doc.go new file mode 100644 index 0000000000..d20eae1e15 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud // import "yunion.io/x/cloudmux/pkg/multicloud/jdcloud" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/eip.go new file mode 100644 index 0000000000..8461f0ebbc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/eip.go @@ -0,0 +1,151 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + "time" + + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/apis" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/client" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/models" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SEip struct { + region *SRegion + multicloud.SEipBase + JdcloudTags + + models.ElasticIp +} + +func (e *SEip) GetId() string { + return e.ElasticIpId +} + +func (e *SEip) GetName() string { + return e.ElasticIpAddress +} + +func (e *SEip) GetGlobalId() string { + return e.GetId() +} + +func (e *SEip) GetStatus() string { + return api.EIP_STATUS_READY +} + +func (e *SEip) Refresh() error { + return nil +} + +func (e *SEip) IsEmulated() bool { + return false +} + +func (e *SEip) GetIpAddr() string { + return e.ElasticIpAddress +} + +func (e *SEip) GetMode() string { + return api.EIP_MODE_STANDALONE_EIP +} + +func (e *SEip) GetAssociationType() string { + switch e.InstanceType { + case "compute": + return api.EIP_ASSOCIATE_TYPE_SERVER + case "lb": + return api.EIP_ASSOCIATE_TYPE_LOADBALANCER + default: + return e.InstanceType + } +} + +func (e *SEip) GetAssociationExternalId() string { + return e.InstanceId +} + +func (e *SEip) GetBillingType() string { + return billingType(&e.Charge) +} + +func (e *SEip) GetCreatedAt() time.Time { + return parseTime(e.CreatedTime) +} + +func (e *SEip) GetExpiredAt() time.Time { + return expireAt(&e.Charge) +} + +func (e *SEip) Delete() error { + return nil +} + +func (e *SEip) GetBandwidth() int { + return e.BandwidthMbps +} + +func (e *SEip) GetINetworkId() string { + return "" +} + +func (e *SEip) GetInternetChargeType() string { + switch e.Charge.ChargeMode { + case "postpaid_by_usage": + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + case "postpaid_by_duration": + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH + default: + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + } +} + +func (e *SEip) Associate(conf *cloudprovider.AssociateConfig) error { + return nil +} + +func (e *SEip) Dissociate() error { + return nil +} + +func (e *SEip) ChangeBandwidth(bw int) error { + return nil +} + +func (e *SEip) GetProjectId() string { + return "" +} + +func (r *SRegion) GetEIPById(id string) (*SEip, error) { + req := apis.NewDescribeElasticIpRequest(r.ID, id) + client := client.NewVpcClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeElasticIp(req) + if err != nil { + return nil, err + } + if resp.Error.Code >= 400 { + return nil, fmt.Errorf(resp.Error.Message) + } + return &SEip{ + region: r, + ElasticIp: resp.Result.ElasticIp, + }, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/host.go new file mode 100644 index 0000000000..3916e87589 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/host.go @@ -0,0 +1,187 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/sets" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone +} + +func (h *SHost) GetId() string { + return fmt.Sprintf("%s-%s", h.zone.region.cpcfg.Id, h.zone.GetGlobalId()) +} + +func (h *SHost) GetName() string { + return fmt.Sprintf("%s-%s", h.zone.region.cpcfg.Name, h.zone.GetName()) +} + +func (h *SHost) GetGlobalId() string { + return h.GetId() +} + +func (h *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (h *SHost) Refresh() error { + return nil +} + +func (h *SHost) IsEmulated() bool { + return true +} + +func (h *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms := make([]SInstance, 0) + n := 1 + for { + parts, total, err := h.zone.region.GetInstances(h.zone.ID, nil, n, 100) + if err != nil { + return nil, err + } + vms = append(vms, parts...) + if len(vms) >= total { + break + } + n++ + } + // fill instanceType + instanceTypes := sets.NewString() + for i := range vms { + instanceTypes.Insert(vms[i].InstanceType) + } + its, err := h.zone.region.InstanceTypes(instanceTypes.UnsortedList()...) + if err != nil { + return nil, errors.Wrap(err, "unable to fetch instanceTypes") + } + itMap := make(map[string]*SInstanceType, len(its)) + for i := range its { + itMap[its[i].InstanceType.InstanceType] = &its[i] + } + ivms := make([]cloudprovider.ICloudVM, len(vms)) + for i := range vms { + vms[i].host = h + vms[i].instanceType = itMap[vms[i].InstanceType] + ivms[i] = &vms[i] + } + return ivms, nil +} + +func (h *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + in, err := h.zone.region.GetInstanceById(id) + if err != nil { + return nil, err + } + in.host = h + return in, nil +} + +func (h *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + return nil, nil +} + +func (h *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + return h.zone.GetIStorages() +} + +func (h *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return h.zone.GetIStorageById(id) +} + +func (h *SHost) GetEnabled() bool { + return true +} + +func (h *SHost) GetHostStatus() string { + return api.HOST_ONLINE +} + +func (h *SHost) GetAccessIp() string { + return "" +} + +func (h *SHost) GetAccessMac() string { + return "" +} + +func (h *SHost) GetSysInfo() jsonutils.JSONObject { + info := jsonutils.NewDict() + info.Add(jsonutils.NewString(api.CLOUD_PROVIDER_JDCLOUD), "manufacture") + return info +} + +func (h *SHost) GetSN() string { + return "" +} + +func (h *SHost) GetCpuCount() int { + return 0 +} + +func (h *SHost) GetNodeCount() int8 { + return 0 +} + +func (h *SHost) GetCpuDesc() string { + return "" +} + +func (h *SHost) GetCpuMhz() int { + return 0 +} + +func (h *SHost) GetMemSizeMB() int { + return 0 +} + +func (h *SHost) GetStorageSizeMB() int { + return 0 +} + +func (h *SHost) GetStorageType() string { + return api.DISK_TYPE_HYBRID +} + +func (h *SHost) GetHostType() string { + return api.HOST_TYPE_JDCLOUD +} + +func (h *SHost) GetIsMaintenance() bool { + return false +} + +func (h *SHost) GetVersion() string { + return "" +} + +func (h *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (h *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/image.go new file mode 100644 index 0000000000..ae67b673fe --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/image.go @@ -0,0 +1,215 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/apis" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/client" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/models" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type SImage struct { + multicloud.SImageBase + JdcloudTags + + storageCache *SStoragecache + + imageInfo *imagetools.ImageInfo + + models.Image +} + +func (i *SImage) GetCreatedAt() time.Time { + return parseTime(i.CreateTime) +} + +func (i *SImage) GetId() string { + return i.ImageId +} + +func (i *SImage) GetName() string { + return i.Name +} + +func (i *SImage) GetDescription() string { + return i.Desc +} + +func (i *SImage) GetGlobalId() string { + return i.GetId() +} + +func (i *SImage) GetStatus() string { + switch i.Status { + case "pending": + return api.CACHED_IMAGE_STATUS_SAVING + case "ready": + return api.CACHED_IMAGE_STATUS_ACTIVE + case "deleting": + return api.CACHED_IMAGE_STATUS_DELETING + case "error": + return api.CACHED_IMAGE_STATUS_UNKNOWN + default: + return api.CACHED_IMAGE_STATUS_UNKNOWN + } +} + +func (i *SImage) Refresh() error { + return nil +} + +func (i *SImage) IsEmulated() bool { + return false +} + +func (i *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if i.imageInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(i.Name, i.Architecture, i.OsType, i.Platform, i.OsVersion) + i.imageInfo = &imgInfo + } + return i.imageInfo +} + +func (i *SImage) GetFullOsName() string { + return i.Name +} + +func (i *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(i.getNormalizedImageInfo().OsType) +} + +func (i *SImage) GetOsDist() string { + return i.getNormalizedImageInfo().OsDistro +} + +func (i *SImage) GetOsVersion() string { + return i.getNormalizedImageInfo().OsVersion +} + +func (i *SImage) GetOsLang() string { + return i.getNormalizedImageInfo().OsLang +} + +func (i *SImage) GetOsArch() string { + return i.getNormalizedImageInfo().OsArch +} + +func (i *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(i.getNormalizedImageInfo().OsBios) +} + +func (i *SImage) GetMinOsDiskSizeGb() int { + return i.SystemDiskSizeGB +} + +func (i *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (i *SImage) GetImageFormat() string { + return "" +} + +func (i *SImage) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (i *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return nil +} + +func (i *SImage) GetSizeByte() int64 { + return int64(i.SizeMB) * 1024 * 1024 +} + +func (i *SImage) GetImageType() cloudprovider.TImageType { + switch i.ImageSource { + case "jcloud": + return cloudprovider.ImageTypeSystem + case "marketplace": + return cloudprovider.ImageTypeMarket + case "self": + return cloudprovider.ImageTypeCustomized + case "shared": + return cloudprovider.ImageTypeShared + default: + return cloudprovider.TImageType("") + } +} + +func (i *SImage) GetImageStatus() string { + switch i.Status { + case "pending": + return cloudprovider.IMAGE_STATUS_QUEUED + default: + return cloudprovider.IMAGE_STATUS_ACTIVE + } +} + +func (r *SRegion) GetImage(imageId string) (*SImage, error) { + req := apis.NewDescribeImageRequest(r.ID, imageId) + client := client.NewVmClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeImage(req) + if err != nil { + return nil, err + } + if resp.Error.Code >= 400 { + err = fmt.Errorf(resp.Error.Message) + return nil, err + } + return &SImage{ + Image: resp.Result.Image, + }, nil +} + +func (r *SRegion) GetImages(imageIds []string, imageSource string, pageNumber, pageSize int) ([]SImage, int, error) { + req := apis.NewDescribeImagesRequestWithAllParams(r.ID, &imageSource, nil, nil, nil, imageIds, nil, nil, nil, nil, &pageNumber, &pageSize) + client := client.NewVmClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeImages(req) + if err != nil { + log.Errorf("err: %v", err) + return nil, 0, err + } + if resp.Error.Code >= 400 { + if strings.Contains(resp.Error.Message, "secret key is nul") || strings.Contains(resp.Error.Message, "sign result is not same") { + return nil, 0, errors.Wrapf(httperrors.ErrInvalidAccessKey, resp.Error.Message) + } + err = fmt.Errorf(resp.Error.Message) + return nil, 0, err + } + images := make([]SImage, len(resp.Result.Images)) + for i := range resp.Result.Images { + images[i] = SImage{ + Image: resp.Result.Images[i], + } + } + return images, resp.Result.TotalCount, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/instance.go new file mode 100644 index 0000000000..f866a6304b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/instance.go @@ -0,0 +1,443 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "context" + "fmt" + "time" + + commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/apis" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/client" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/models" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/sets" + + napis "yunion.io/x/cloudmux/pkg/apis" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SInstance struct { + multicloud.SInstanceBase + multicloud.SBillingBase + JdcloudTags + + host *SHost + image *SImage + + models.Instance + + instanceType *SInstanceType +} + +func (i *SInstance) GetBillingType() string { + return billingType(&i.Charge) +} + +func (i *SInstance) GetExpiredAt() time.Time { + return expireAt(&i.Charge) +} + +func (i *SInstance) GetId() string { + return i.InstanceId +} + +func (i *SInstance) GetName() string { + return i.InstanceName +} + +func (i *SInstance) GetHostname() string { + return i.Hostname +} + +func (i *SInstance) GetGlobalId() string { + return i.GetId() +} + +func (i *SInstance) GetStatus() string { + switch i.Status { + case "pending": + return api.VM_DEPLOYING + case "starting": + return api.VM_STARTING + case "running": + return api.VM_RUNNING + case "stopping": + return api.VM_STOPPING + case "stopped": + return api.VM_READY + case "reboot": + return api.VM_STARTING + case "rebuilding": + return api.VM_REBUILD_ROOT + case "resizing": + return api.VM_CHANGE_FLAVOR + case "deleting": + return api.VM_DELETING + default: + return api.VM_UNKNOWN + } +} + +func (i *SInstance) Refresh() error { + return nil +} + +func (i *SInstance) IsEmulated() bool { + return false +} + +func (i *SInstance) GetBootOrder() string { + return "dcn" +} + +func (i *SInstance) GetVga() string { + return "std" +} + +func (i *SInstance) GetVdi() string { + return "vnc" +} + +func (i *SInstance) GetImage() (*SImage, error) { + if i.image != nil { + return i.image, nil + } + image, err := i.host.zone.region.GetImage(i.ImageId) + if err != nil { + return nil, err + } + i.image = image + return i.image, nil +} + +func (i *SInstance) GetOsType() cloudprovider.TOsType { + image, err := i.GetImage() + if err != nil { + return cloudprovider.OsTypeLinux + } + return image.GetOsType() +} + +func (i *SInstance) GetFullOsName() string { + image, err := i.GetImage() + if err != nil { + return "" + } + return image.GetFullOsName() +} + +func (i *SInstance) GetBios() cloudprovider.TBiosType { + image, err := i.GetImage() + if err != nil { + return cloudprovider.BIOS + } + return image.GetBios() +} + +func (i *SInstance) GetOsArch() string { + image, err := i.GetImage() + if err != nil { + return napis.OS_ARCH_X86_64 + } + return image.GetOsArch() +} + +func (i *SInstance) GetOsDist() string { + image, err := i.GetImage() + if err != nil { + return "" + } + return image.GetOsDist() +} + +func (i *SInstance) GetOsVersion() string { + image, err := i.GetImage() + if err != nil { + return "" + } + return image.GetOsVersion() +} + +func (i *SInstance) GetOsLang() string { + image, err := i.GetImage() + if err != nil { + return "" + } + return image.GetOsLang() +} + +func (i *SInstance) GetMachine() string { + return "pc" +} + +func (i *SInstance) GetInstanceType() string { + return i.InstanceType +} + +func (in *SInstance) GetProjectId() string { + return "" +} + +func (in *SInstance) GetIHost() cloudprovider.ICloudHost { + return in.host +} + +func (in *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks := make([]cloudprovider.ICloudDisk, 0, len(in.DataDisks)+1) + if in.SystemDisk.DiskCategory != "local" { + disk := &SDisk{ + Disk: in.SystemDisk.CloudDisk, + ImageId: in.ImageId, + IsSystemDisk: true, + } + stroage, err := in.host.zone.getStorageByType(disk.DiskType) + if err != nil { + return nil, errors.Wrapf(err, "unable to find storage with type %s", disk.DiskType) + } + disk.storage = stroage + disks = append(disks, disk) + } + for i := range in.DataDisks { + disk := &SDisk{ + Disk: in.DataDisks[i].CloudDisk, + } + stroage, err := in.host.zone.getStorageByType(disk.DiskType) + if err != nil { + return nil, errors.Wrapf(err, "unable to find storage with type %s", disk.DiskType) + } + disk.storage = stroage + disks = append(disks, disk) + } + return disks, nil +} + +func (in *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nis := make([]cloudprovider.ICloudNic, 0, len(in.SecondaryNetworkInterfaces)+1) + nis = append(nis, &SInstanceNic{ + instance: in, + InstanceNetworkInterface: in.PrimaryNetworkInterface.NetworkInterface, + }) + for i := range in.SecondaryNetworkInterfaces { + nis = append(nis, &SInstanceNic{ + instance: in, + InstanceNetworkInterface: in.SecondaryNetworkInterfaces[i].NetworkInterface, + }) + } + return nis, nil +} + +func (in *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + eip, err := in.host.zone.region.GetEIPById(in.ElasticIpId) + if err != nil { + return nil, err + } + return eip, nil +} + +func (in *SInstance) GetSecurityGroupIds() ([]string, error) { + ids := sets.NewString() + for _, sg := range in.PrimaryNetworkInterface.NetworkInterface.SecurityGroups { + ids.Insert(sg.GroupId) + } + for i := range in.SecondaryNetworkInterfaces { + for _, sg := range in.SecondaryNetworkInterfaces[i].NetworkInterface.SecurityGroups { + ids.Insert(sg.GroupId) + } + } + return ids.UnsortedList(), nil +} + +func (in *SInstance) fetchInstanceType() error { + its, err := in.host.zone.region.InstanceTypes(in.InstanceType) + if err != nil { + return err + } + if len(its) == 0 { + return cloudprovider.ErrNotFound + } + for i := range its { + if its[i].InstanceType.InstanceType == in.InstanceType { + in.instanceType = &its[i] + return nil + } + } + return cloudprovider.ErrNotFound +} + +func (in *SInstance) GetVcpuCount() int { + if in.instanceType == nil { + err := in.fetchInstanceType() + if err != nil { + log.Errorf("unable to get instance type %s: %v", in.InstanceType, err) + return 0 + } + } + return in.instanceType.GetCpu() +} + +func (in *SInstance) GetVmemSizeMB() int { + if in.instanceType == nil { + err := in.fetchInstanceType() + if err != nil { + log.Errorf("unable to get instance type %s", in.InstanceType) + return 0 + } + } + return in.instanceType.GetMemoryMB() +} + +func (in *SInstance) AssignSecurityGroup(id string) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) SetSecurityGroups(ids []string) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) GetHypervisor() string { + return api.HYPERVISOR_JDCLOUD +} + +func (in *SInstance) StartVM(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) DeleteVM(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotSupported +} + +func (in *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + return "", cloudprovider.ErrNotImplemented +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + region := in.host.zone.region + req := apis.NewDescribeInstanceVncUrlRequest(region.ID, in.InstanceId) + client := client.NewVmClient(region.getCredential()) + client.Logger = Logger{debug: region.client.debug} + resp, err := client.DescribeInstanceVncUrl(req) + if err != nil { + return nil, err + } + + ret := &cloudprovider.ServerVncOutput{ + Url: resp.Result.VncUrl, + Protocol: "jdcloud", + InstanceId: in.GetId(), + Hypervisor: api.HYPERVISOR_JDCLOUD, + } + return ret, nil +} + +func (in *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (in *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) GetError() error { + return nil +} + +func (r *SRegion) GetInstances(zoneId string, ids []string, pangeNumber, pageSize int) ([]SInstance, int, error) { + filters := []commodels.Filter{} + if zoneId != "" { + filters = append(filters, commodels.Filter{ + Name: "az", + Values: []string{zoneId}, + }) + } + if len(ids) > 0 { + filters = append(filters, commodels.Filter{ + Name: "instanceId", + Values: ids, + }) + } + req := apis.NewDescribeInstancesRequestWithAllParams(r.ID, &pangeNumber, &pageSize, filters) + client := client.NewVmClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeInstances(req) + if err != nil { + return nil, 0, err + } + if resp.Error.Code >= 400 { + return nil, 0, fmt.Errorf(resp.Error.Message) + } + ins := make([]SInstance, len(resp.Result.Instances)) + for i := range ins { + ins[i] = SInstance{ + Instance: resp.Result.Instances[i], + } + } + return ins, resp.Result.TotalCount, nil +} + +func (r *SRegion) GetInstanceById(id string) (*SInstance, error) { + req := apis.NewDescribeInstanceRequest(r.ID, id) + client := client.NewVmClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeInstance(req) + if err != nil { + return nil, err + } + return &SInstance{ + Instance: resp.Result.Instance, + }, nil +} + +func (r *SRegion) FillHost(instance *SInstance) { + izone, err := r.getIZoneByRealId(instance.Az) + if err != nil { + log.Errorf("unable to find zone %s: %v", instance.Az, err) + return + } + zone := izone.(*SZone) + instance.host = &SHost{ + zone: zone, + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/instancenic.go new file mode 100644 index 0000000000..34d32d2921 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/instancenic.go @@ -0,0 +1,52 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "github.com/jdcloud-api/jdcloud-sdk-go/services/vm/models" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + instance *SInstance + cloudprovider.DummyICloudNic + + models.InstanceNetworkInterface +} + +func (in *SInstanceNic) GetIP() string { + return in.PrimaryIp.PrivateIpAddress +} + +func (in *SInstanceNic) GetMAC() string { + return in.MacAddress +} + +func (in *SInstanceNic) GetId() string { + return in.NetworkInterfaceId +} + +func (in *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (in *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (in *SInstanceNic) GetINetworkId() string { + return in.SubnetId +} diff --git a/pkg/multicloud/jdcloud/instancetype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/instancetype.go similarity index 100% rename from pkg/multicloud/jdcloud/instancetype.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/instancetype.go diff --git a/pkg/multicloud/jdcloud/jdcloud.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/jdcloud.go similarity index 96% rename from pkg/multicloud/jdcloud/jdcloud.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/jdcloud.go index c6a936bfb3..7175e38744 100644 --- a/pkg/multicloud/jdcloud/jdcloud.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/jdcloud.go @@ -17,8 +17,8 @@ package jdcloud import ( "github.com/jdcloud-api/jdcloud-sdk-go/core" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SJDCloudClient struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/latitud_and_longitude.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/latitud_and_longitude.go new file mode 100644 index 0000000000..38a608aa2f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/latitud_and_longitude.go @@ -0,0 +1,27 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ + "cn-south-1": {Latitude: 23.129110, Longitude: 113.264381, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "cn-north-1": {Latitude: 39.904202, Longitude: 116.407394, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-east-2": {Latitude: 31.210344, Longitude: 121.455364, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-east-1": {Latitude: 33.939763, Longitude: 118.267582, City: api.CITY_SU_QIAN, CountryCode: api.COUNTRY_CODE_CN}, +} diff --git a/pkg/multicloud/jdcloud/log.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/log.go similarity index 100% rename from pkg/multicloud/jdcloud/log.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/log.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/monitor.go new file mode 100644 index 0000000000..abd08bd216 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/monitor.go @@ -0,0 +1,155 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + "strconv" + "time" + + jc_apis "github.com/jdcloud-api/jdcloud-sdk-go/services/monitor/apis" + client "github.com/jdcloud-api/jdcloud-sdk-go/services/monitor/client" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/timeutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +func (self *SJDCloudClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_RDS: + return self.GetRdsMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) + } +} + +func (self *SJDCloudClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + for metricType, metricName := range map[cloudprovider.TMetricType]string{ + cloudprovider.VM_METRIC_TYPE_CPU_USAGE: "cpu_util", + cloudprovider.VM_METRIC_TYPE_MEM_USAGE: "memory.usage", + cloudprovider.VM_METRIC_TYPE_DISK_USAGE: "vm.disk.dev.used", + cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: "vm.network.dev.bytes.in", + cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: "vm.network.dev.bytes.out", + cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: "vm.disk.dev.bytes.read", + cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: "vm.disk.dev.bytes.write", + cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: "vm.disk.dev.io.read", + cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: "vm.disk.dev.io.write", + } { + + aggrType, downSampleType, serviceCode := "avg", "avg", "vm" + startTime, endTime := opts.StartTime.Format(timeutils.FullIsoTimeFormat), opts.EndTime.Format(timeutils.FullIsoTimeFormat) + request := jc_apis.NewDescribeMetricDataRequestWithAllParams(opts.RegionExtId, metricName, &aggrType, &downSampleType, &startTime, &endTime, nil, nil, nil, nil, &serviceCode, nil, opts.ResourceId) + monitorClient := client.NewMonitorClient(self.getCredential()) + monitorClient.Logger = Logger{debug: self.debug} + response, err := monitorClient.DescribeMetricData(request) + if err != nil { + return nil, err + } + metric := cloudprovider.MetricValues{} + metric.Id = opts.ResourceId + metric.MetricType = metricType + for _, data := range response.Result.MetricDatas { + for _, value := range data.Data { + metricValue := cloudprovider.MetricValue{} + metricValue.Timestamp = time.Unix(value.Timestamp/1000, 0) + if value.Value == nil { + continue + } + metricValue.Value, err = strconv.ParseFloat(fmt.Sprintf("%s", value.Value), 64) + if err != nil { + log.Errorf("parse value %v error: %v", value.Value, nil) + continue + } + metric.Values = append(metric.Values, metricValue) + } + } + ret = append(ret, metric) + } + return ret, nil +} + +func (self *SJDCloudClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + metrics := map[cloudprovider.TMetricType]string{} + switch opts.Engine { + case api.DBINSTANCE_TYPE_MYSQL, api.DBINSTANCE_TYPE_SQLSERVER, api.DBINSTANCE_TYPE_PERCONA, api.DBINSTANCE_TYPE_MARIADB: + metrics = map[cloudprovider.TMetricType]string{ + cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: "database.docker.cpu.util", + cloudprovider.RDS_METRIC_TYPE_MEM_USAGE: "database.docker.memory.pused", + cloudprovider.RDS_METRIC_TYPE_DISK_USAGE: "database.docker.disk1.used", + cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: "database.docker.network.incoming", + cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: "database.docker.network.outgoing", + } + case api.DBINSTANCE_TYPE_POSTGRESQL: + metrics = map[cloudprovider.TMetricType]string{ + cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: "database.docker.cpu.util", + cloudprovider.RDS_METRIC_TYPE_MEM_USAGE: "database.docker.memory.pused", + cloudprovider.RDS_METRIC_TYPE_DISK_USAGE: "database.docker.disk1.used", + cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: "database.docker.network.incoming", + cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: "database.docker.network.outgoing", + } + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.Engine) + } + ret := []cloudprovider.MetricValues{} + aggrType, downSampleType := "avg", "avg" + startTime, endTime := opts.StartTime.Format(timeutils.FullIsoTimeFormat), opts.EndTime.Format(timeutils.FullIsoTimeFormat) + serviceCode := map[string]string{ + api.DBINSTANCE_TYPE_SQLSERVER: "sqlserver", + api.DBINSTANCE_TYPE_MYSQL: "database", + api.DBINSTANCE_TYPE_PERCONA: "percona", + api.DBINSTANCE_TYPE_MARIADB: "mariadb", + api.DBINSTANCE_TYPE_POSTGRESQL: "pag", + }[opts.Engine] + for metricType, metricName := range metrics { + request := jc_apis.NewDescribeMetricDataRequestWithAllParams(opts.RegionExtId, metricName, &aggrType, &downSampleType, &startTime, &endTime, nil, nil, nil, nil, &serviceCode, nil, opts.ResourceId) + monitorClient := client.NewMonitorClient(self.getCredential()) + monitorClient.Logger = Logger{} + response, err := monitorClient.DescribeMetricData(request) + if err != nil { + return nil, err + } + metric := cloudprovider.MetricValues{} + metric.Id = opts.ResourceId + metric.MetricType = metricType + for _, data := range response.Result.MetricDatas { + for _, value := range data.Data { + metricValue := cloudprovider.MetricValue{} + metricValue.Timestamp = time.Unix(value.Timestamp/1000, 0) + if value.Value == nil { + continue + } + metricValue.Value, err = strconv.ParseFloat(fmt.Sprintf("%s", value.Value), 64) + if err != nil { + log.Errorf("parse value %v error: %v", value.Value, nil) + continue + } + // kbps -> byte + if opts.Engine != api.DBINSTANCE_TYPE_POSTGRESQL && (metricType == cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX || metricType == cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX) { + metricValue.Value = metricValue.Value / 1024.0 + } + metric.Values = append(metric.Values, metricValue) + } + } + ret = append(ret, metric) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/network.go new file mode 100644 index 0000000000..4be97fd83c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/network.go @@ -0,0 +1,156 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + + commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/apis" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/client" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/models" + + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + JdcloudTags + + wire *SWire + + models.Subnet +} + +func (n *SNetwork) GetId() string { + return n.SubnetId +} + +func (n *SNetwork) GetName() string { + return n.SubnetName +} + +func (n *SNetwork) GetGlobalId() string { + return n.GetId() +} + +func (n *SNetwork) GetStatus() string { + return api.NETWORK_STATUS_AVAILABLE +} + +func (n *SNetwork) Refresh() error { + return nil +} + +func (n *SNetwork) IsEmulated() bool { + return false +} + +func (n *SNetwork) GetProjectId() string { + return "" +} + +func (n *SNetwork) GetIWire() cloudprovider.ICloudWire { + return n.wire +} + +func (n *SNetwork) GetIpStart() string { + return n.StartIp +} + +func (n *SNetwork) GetIpEnd() string { + return n.EndIp +} + +func (n *SNetwork) Cidr() string { + return n.AddressPrefix +} + +func (n *SNetwork) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(n.Cidr()) + return pref.MaskLen +} + +func (n *SNetwork) GetGateway() string { + return "" +} + +func (n *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (n *SNetwork) GetIsPublic() bool { + return true +} + +func (n *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (n *SNetwork) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (n *SNetwork) GetAllocTimeoutSeconds() int { + return 120 +} + +func (r *SRegion) GetNetworks(vpcId string, pageNumber int, pageSize int) ([]SNetwork, int, error) { + filters := []commodels.Filter{} + if vpcId != "" { + filters = append(filters, commodels.Filter{ + Name: "vpcId", + Values: []string{vpcId}, + }) + } + req := apis.NewDescribeSubnetsRequestWithAllParams(r.ID, &pageNumber, &pageSize, filters) + client := client.NewVpcClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeSubnets(req) + if err != nil { + return nil, 0, err + } + if resp.Error.Code >= 400 { + return nil, 0, fmt.Errorf(resp.Error.Message) + } + nets := make([]SNetwork, len(resp.Result.Subnets)) + for i := range nets { + nets[i] = SNetwork{ + Subnet: resp.Result.Subnets[i], + } + } + return nets, resp.Result.TotalCount, nil +} + +func (r *SRegion) GetNetworkById(id string) (*SNetwork, error) { + req := apis.NewDescribeSubnetRequest(r.ID, id) + client := client.NewVpcClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeSubnet(req) + if err != nil { + return nil, err + } + if resp.Error.Code >= 400 { + return nil, fmt.Errorf(resp.Error.Message) + } + return &SNetwork{ + Subnet: resp.Result.Subnet, + }, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/networkinterface.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/networkinterface.go new file mode 100644 index 0000000000..12c87f0157 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/networkinterface.go @@ -0,0 +1,107 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/models" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SNetworkInterface struct { + multicloud.SNetworkInterfaceBase + JdcloudTags + region *SRegion + + models.NetworkInterface +} + +func (nic *SNetworkInterface) GetId() string { + return nic.NetworkInterfaceId +} + +func (nic *SNetworkInterface) GetName() string { + return nic.NetworkInterfaceName +} + +func (nic *SNetworkInterface) GetGlobalId() string { + return nic.GetId() +} + +func (nic *SNetworkInterface) GetAssociateId() string { + return nic.InstanceId +} + +func (nic *SNetworkInterface) GetAssociateType() string { + if nic.InstanceType == "vm" { + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER + } + return "" +} + +func (nic *SNetworkInterface) GetMacAddress() string { + return nic.MacAddress +} + +func (nic *SNetworkInterface) GetStatus() string { + switch nic.NetworkInterfaceStatus { + case "enabled": + return api.NETWORK_INTERFACE_STATUS_AVAILABLE + case "disabled": + return api.NETWORK_INTERFACE_STATUS_DISABLED + } + return api.NETWORK_INTERFACE_STATUS_UNKNOWN +} + +type SNetworkInterfacePrivateIp struct { + subnetId string + isPrimary bool + models.NetworkInterfacePrivateIp +} + +func (ip *SNetworkInterfacePrivateIp) GetGlobalId() string { + return ip.PrivateIpAddress +} + +func (ip *SNetworkInterfacePrivateIp) GetINetworkId() string { + return ip.subnetId +} + +func (ip *SNetworkInterfacePrivateIp) GetIP() string { + return ip.PrivateIpAddress +} + +func (ip *SNetworkInterfacePrivateIp) IsPrimary() bool { + return ip.isPrimary +} + +func (nic *SNetworkInterface) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { + address := make([]cloudprovider.ICloudInterfaceAddress, 0, len(nic.SecondaryIps)+1) + address = append(address, &SNetworkInterfacePrivateIp{ + subnetId: nic.SubnetId, + isPrimary: true, + NetworkInterfacePrivateIp: nic.PrimaryIp, + }) + for i := range nic.SecondaryIps { + address = append(address, &SNetworkInterfacePrivateIp{ + subnetId: nic.SubnetId, + isPrimary: false, + NetworkInterfacePrivateIp: nic.SecondaryIps[i], + }) + } + return address, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider/doc.go new file mode 100644 index 0000000000..42305726e1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider/provider.go new file mode 100644 index 0000000000..8b0315bd23 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider/provider.go @@ -0,0 +1,200 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/jdcloud" +) + +type SJdcloudProviderFactory struct { + cloudprovider.SPublicCloudBaseProviderFactory +} + +func (f *SJdcloudProviderFactory) GetId() string { + return jdcloud.CLOUD_PROVIDER_JDCLOUD +} + +func (f *SJdcloudProviderFactory) GetName() string { + return jdcloud.CLOUD_PROVIDER_JDCLOUD_CN +} + +func (f *SJdcloudProviderFactory) IsSupportPrepaidResources() bool { + return true +} + +func (f *SJdcloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + return output, nil +} + +func (f *SJdcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func (f *SJdcloudProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + segs := strings.Split(cfg.Account, "/") + account := cfg.Account + if len(segs) == 2 { + account = segs[0] + } + client, err := jdcloud.NewJDCloudClient( + jdcloud.NewJDCloudClientConfig( + account, + cfg.Secret, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + + return &SJdcloudProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(f), + client: client, + }, nil +} + +func (f *SJdcloudProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + return map[string]string{ + "JDCLOUD_ACCESS_KEY": info.Account, + "JDCLOUD_SECRET": info.Secret, + "JDCLOUD_REGION": jdcloud.JDCLOUD_DEFAULT_REGION, + }, nil +} + +func init() { + factory := SJdcloudProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SJdcloudProvider struct { + cloudprovider.SBaseProvider + + client *jdcloud.SJDCloudClient +} + +func (p *SJdcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return p.client.GetSubAccounts() +} + +func (p *SJdcloudProvider) GetAccountId() string { + return p.client.GetAccountId() +} + +func (p *SJdcloudProvider) GetIRegions() []cloudprovider.ICloudRegion { + return p.client.GetIRegions() +} + +func (p *SJdcloudProvider) GetSysInfo() (jsonutils.JSONObject, error) { + iregions := p.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(iregions))), "region_count") + return info, nil +} + +func (p *SJdcloudProvider) GetVersion() string { + return "" +} + +func (p *SJdcloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + iregions := p.GetIRegions() + for i := range iregions { + if iregions[i].GetGlobalId() == id { + return iregions[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (p *SJdcloudProvider) GetBalance() (float64, string, error) { + balance, err := p.client.DescribeAccountAmount() + if err != nil { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NO_PERMISSION, errors.Wrap(err, "DescribeAccountAmount") + } + amount, _ := jsonutils.Marshal(balance).Float("totalAmount") + if amount < 0 { + return amount, api.CLOUD_PROVIDER_HEALTH_ARREARS, nil + } else if amount < 50 { + return amount, api.CLOUD_PROVIDER_HEALTH_INSUFFICIENT, nil + } + return amount, api.CLOUD_PROVIDER_HEALTH_NORMAL, nil +} + +func (p *SJdcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (p *SJdcloudProvider) GetStorageClasses(regionId string) []string { + // TODO + return nil +} + +func (p *SJdcloudProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (p *SJdcloudProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (p *SJdcloudProvider) GetCloudRegionExternalIdPrefix() string { + return api.CLOUD_PROVIDER_JDCLOUD +} + +func (p *SJdcloudProvider) GetCapabilities() []string { + iRegions := p.GetIRegions() + if len(iRegions) > 0 { + return iRegions[0].GetCapabilities() + } + caps := []string{ + cloudprovider.CLOUD_CAPABILITY_COMPUTE + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_NETWORK + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_EIP + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_RDS + cloudprovider.READ_ONLY_SUFFIX, + } + return caps +} + +func (self *SJdcloudProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetMetrics(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds.go new file mode 100644 index 0000000000..e7214dc1a7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds.go @@ -0,0 +1,266 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + "strconv" + "strings" + "time" + + commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" + "github.com/jdcloud-api/jdcloud-sdk-go/services/rds/apis" + "github.com/jdcloud-api/jdcloud-sdk-go/services/rds/client" + "github.com/jdcloud-api/jdcloud-sdk-go/services/rds/models" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDBInstance struct { + multicloud.SDBInstanceBase + JdcloudTags + region *SRegion + + models.DBInstance +} + +func (self *SDBInstance) GetName() string { + return self.InstanceName +} + +func (self *SDBInstance) GetInstanceType() string { + return self.InstanceClass +} + +func (self *SDBInstance) GetCategory() string { + return self.InstanceType +} + +func (self *SDBInstance) GetDiskSizeGB() int { + return self.InstanceStorageGB +} + +func (self *SDBInstance) GetEngine() string { + return self.Engine +} + +func (self *SDBInstance) GetEngineVersion() string { + return self.EngineVersion +} + +func (self *SDBInstance) GetGlobalId() string { + return self.InstanceId +} + +func (self *SDBInstance) GetId() string { + return self.InstanceId +} + +func (self *SDBInstance) GetIVpcId() string { + return self.VpcId +} + +func (self *SDBInstance) Refresh() error { + rds, err := self.region.GetDBInstance(self.InstanceId) + if err != nil { + return err + } + return jsonutils.Update(self, rds) +} + +func (self *SDBInstance) GetMaintainTime() string { + return "" +} + +func (self *SDBInstance) GetMasterInstanceId() string { + return self.SourceInstanceId +} + +func (self *SDBInstance) GetPort() int { + if len(self.InstancePort) == 0 { + self.Refresh() + } + port, _ := strconv.Atoi(self.InstancePort) + return int(port) +} + +func (self *SDBInstance) GetCreatedAt() time.Time { + return parseTime(self.CreateTime) +} + +func (self *SDBInstance) GetExpiredAt() time.Time { + return expireAt(&self.Charge) +} + +func (self *SDBInstance) GetStatus() string { + switch self.InstanceStatus { + case "BUILDING", "DDLING", "PARAMETERGROUP_MODIFYING", "AUDIT_OPENING", "AUDIT_CLOSING", "SECURITY_OPENING", "SECURITY_CLOSING", "SSL_OPENING", "SSL_CLOSING": + return api.DBINSTANCE_DEPLOYING + case "RUNNING": + return api.DBINSTANCE_RUNNING + case "DELETING": + return api.DBINSTANCE_DELETING + case "FAILOVER", "AZ_MIGRATING": + return api.DBINSTANCE_MIGRATING + case "RESTORING", "DB_RESTORING": + return api.DBINSTANCE_RESTORING + case "MODIFYING": + return api.DBINSTANCE_CHANGE_CONFIG + case "BUILD_READONLY": + return api.DBINSTANCE_DEPLOYING + case "REBOOTING": + return api.DBINSTANCE_REBOOTING + case "MAINTENANCE": + return api.DBINSTANCE_MAINTENANCE + default: + return self.InstanceStatus + } +} + +func (self *SDBInstance) GetStorageType() string { + return self.InstanceStorageType +} + +func (self *SDBInstance) GetVcpuCount() int { + return self.InstanceCPU +} + +func (self *SDBInstance) GetVmemSizeMB() int { + return self.InstanceMemoryMB +} + +func (self *SDBInstance) GetZone1Id() string { + if len(self.AzId) > 0 { + return self.AzId[0] + } + return "" +} + +func (self *SDBInstance) GetZone2Id() string { + if len(self.AzId) > 1 { + return self.AzId[1] + } + return "" +} + +func (self *SDBInstance) GetZone3Id() string { + if len(self.AzId) > 2 { + return self.AzId[2] + } + return "" +} + +func (self *SDBInstance) GetConnectionStr() string { + return self.PublicDomainName +} + +func (self *SDBInstance) GetInternalConnectionStr() string { + return self.InternalDomainName +} + +func (self *SDBInstance) Delete() error { + return self.region.DeleteDBInstance(self.InstanceId) +} + +func (self *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { + rds := []SDBInstance{} + n := 1 + for { + part, total, err := self.GetDBInstances(n, 100) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstances") + } + rds = append(rds, part...) + if len(rds) >= total { + break + } + n++ + } + ret := []cloudprovider.ICloudDBInstance{} + for i := range rds { + ret = append(ret, &rds[i]) + } + return ret, nil +} + +func (self *SRegion) GetIDBInstanceById(id string) (cloudprovider.ICloudDBInstance, error) { + rds, err := self.GetDBInstance(id) + if err != nil { + return nil, errors.Wrapf(err, "GetDBInstance(%s)", id) + } + return rds, nil +} + +func (self *SRegion) GetDBInstance(id string) (*SDBInstance, error) { + req := apis.NewDescribeInstanceAttributesRequest(self.ID, id) + client := client.NewRdsClient(self.getCredential()) + client.Logger = Logger{debug: self.client.debug} + resp, err := client.DescribeInstanceAttributes(req) + if err != nil { + return nil, errors.Wrapf(err, "DescribeInstanceAttributes") + } + if resp.Error.Code == 404 || strings.Contains(resp.Error.Status, "NotFound") { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, jsonutils.Marshal(resp.Error).String()) + } else if resp.Error.Code != 0 { + return nil, errors.Error(jsonutils.Marshal(resp.Error).String()) + } + ret := SDBInstance{ + region: self, + } + jsonutils.Update(&ret.DBInstance, resp.Result.DbInstanceAttributes) + return &ret, nil +} + +func (self *SRegion) DeleteDBInstance(id string) error { + req := apis.NewDeleteInstanceRequest(self.ID, id) + client := client.NewRdsClient(self.getCredential()) + client.Logger = Logger{} + resp, err := client.DeleteInstance(req) + if err != nil { + return err + } + if resp.Error.Code == 404 { + return nil + } + return nil +} + +func (self *SRegion) GetDBInstances(pageNumber int, pageSize int) ([]SDBInstance, int, error) { + req := apis.NewDescribeInstancesRequestWithAllParams(self.ID, &pageNumber, &pageSize, []commodels.Filter{}, []commodels.TagFilter{}) + client := client.NewRdsClient(self.getCredential()) + client.Logger = Logger{debug: self.client.debug} + resp, err := client.DescribeInstances(req) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeInstances") + } + if resp.Error.Code >= 400 { + err = fmt.Errorf(resp.Error.Message) + return nil, 0, err + } + total := resp.Result.TotalCount + ret := []SDBInstance{} + for i := range resp.Result.DbInstances { + ret = append(ret, SDBInstance{ + region: self, + DBInstance: resp.Result.DbInstances[i], + }) + } + return ret, total, nil +} diff --git a/pkg/multicloud/jdcloud/rds_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds_account.go similarity index 95% rename from pkg/multicloud/jdcloud/rds_account.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds_account.go index f462953973..61fba3cccb 100644 --- a/pkg/multicloud/jdcloud/rds_account.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds_account.go @@ -23,14 +23,14 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SDBInstanceAccount struct { multicloud.SDBInstanceAccountBase - multicloud.JdcloudTags + JdcloudTags rds *SDBInstance models.Account diff --git a/pkg/multicloud/jdcloud/rds_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds_backup.go similarity index 96% rename from pkg/multicloud/jdcloud/rds_backup.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds_backup.go index e010cf76a0..d8b676bd04 100644 --- a/pkg/multicloud/jdcloud/rds_backup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds_backup.go @@ -24,14 +24,14 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SDBInstanceBackup struct { multicloud.SDBInstanceBackupBase - multicloud.JdcloudTags + JdcloudTags rds *SDBInstance models.Backup diff --git a/pkg/multicloud/jdcloud/rds_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds_database.go similarity index 94% rename from pkg/multicloud/jdcloud/rds_database.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds_database.go index 9ba7a41c36..64509511bc 100644 --- a/pkg/multicloud/jdcloud/rds_database.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds_database.go @@ -23,14 +23,14 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SDBInstanceDatabase struct { multicloud.SDBInstanceDatabaseBase - multicloud.JdcloudTags + JdcloudTags rds *SDBInstance models.Database diff --git a/pkg/multicloud/jdcloud/rds_privilege.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds_privilege.go similarity index 100% rename from pkg/multicloud/jdcloud/rds_privilege.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/rds_privilege.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/region.go new file mode 100644 index 0000000000..9309f2dde4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/region.go @@ -0,0 +1,312 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + + "github.com/jdcloud-api/jdcloud-sdk-go/core" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + CLOUD_PROVIDER_JDCLOUD = api.CLOUD_PROVIDER_JDCLOUD + CLOUD_PROVIDER_JDCLOUD_CN = "京东云" + CLOUD_PROVIDER_JDCLOUD_EN = "JDcloud" + + JDCLOUD_DEFAULT_REGION = "cn-north-1" +) + +var regionList = map[string]string{ + "cn-north-1": "华北-北京", + "cn-east-1": "华东-宿迁", + "cn-east-2": "华东-上海", + "cn-south-1": "华南-广州", +} + +type SRegion struct { + cloudprovider.SFakeOnPremiseRegion + multicloud.SRegion + multicloud.SNoObjectStorageRegion + + client *SJDCloudClient + + cpcfg cloudprovider.ProviderConfig + storageCache *SStoragecache + + ID string `json:"id"` + Name string `json:"Name"` + + izones []cloudprovider.ICloudZone + ivpcs []cloudprovider.ICloudVpc +} + +func (self *SRegion) GetClient() *SJDCloudClient { + return self.client +} + +func (self *SRegion) getCredential() *core.Credential { + return self.client.getCredential() +} + +func (r *SRegion) GetId() string { + return r.ID +} + +func (r *SRegion) GetName() string { + return r.Name +} + +func (r *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", api.CLOUD_ACCESS_ENV_JDCLOUD_CHINA, r.GetId()) +} + +func (r *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (r *SRegion) Refresh() error { + return nil +} + +func (r *SRegion) IsEmulated() bool { + return false +} + +func (r *SRegion) GetI18n() cloudprovider.SModelI18nTable { + en := fmt.Sprintf("%s %s", CLOUD_PROVIDER_JDCLOUD_EN, r.Name) + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(r.GetName()).CN(r.GetName()).EN(en) + return table +} + +func (r *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + if info, ok := LatitudeAndLongitude[r.ID]; ok { + return info + } + return cloudprovider.SGeographicInfo{} +} + +func (r *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if r.izones == nil { + err := r.fetchZones() + if err != nil { + return nil, err + } + } + return r.izones, nil +} + +func (r *SRegion) fetchZones() error { + zoneIdens := ZonesInRegion[r.ID] + r.izones = make([]cloudprovider.ICloudZone, 0, len(zoneIdens)) + for _, iden := range zoneIdens { + zone := SZone{ + region: r, + ID: iden.Id, + Name: iden.Name, + } + r.izones = append(r.izones, &zone) + } + return nil +} + +func (r *SRegion) fetchVpcs() error { + vpcs := make([]SVpc, 0) + n := 1 + for { + part, total, err := r.GetVpcs(n, 100) + if err != nil { + return err + } + vpcs = append(vpcs, part...) + if len(vpcs) >= total { + break + } + n++ + } + r.ivpcs = make([]cloudprovider.ICloudVpc, len(vpcs)) + for i := 0; i < len(vpcs); i++ { + r.ivpcs[i] = &vpcs[i] + } + return nil +} + +func (r *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + if r.ivpcs == nil { + err := r.fetchVpcs() + if err != nil { + return nil, err + } + } + return r.ivpcs, nil +} + +func (r *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + return nil, nil +} + +func (r *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + vpc, err := r.GetVpcById(id) + if err != nil { + return nil, err + } + return vpc, nil +} + +func (r *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := r.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (r *SRegion) getIZoneByRealId(id string) (cloudprovider.ICloudZone, error) { + izones, err := r.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + if izones[i].GetId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (r *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (r *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := r.GetInstanceById(id) + if err != nil { + return nil, err + } + izone, err := r.getIZoneByRealId(vm.Az) + if err != nil { + return nil, err + } + zone := izone.(*SZone) + vm.host = &SHost{ + zone: zone, + } + return vm, nil +} + +func (r *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return r.GetDiskById(id) +} + +func (r *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + izones, err := r.GetIZones() + if err != nil { + return nil, err + } + iHosts := make([]cloudprovider.ICloudHost, 0, len(izones)) + for i := range izones { + hosts, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, hosts...) + } + return iHosts, nil +} + +func (r *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + hosts, err := r.GetIHosts() + if err != nil { + return nil, err + } + for i := range hosts { + if hosts[i].GetGlobalId() == id { + return hosts[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (r *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := r.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +func (r *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + istores, err := r.GetIStorages() + if err != nil { + return nil, err + } + for i := range istores { + if istores[i].GetGlobalId() == id { + return istores[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (r *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + sc := r.getStoragecache() + return []cloudprovider.ICloudStoragecache{sc}, nil +} + +func (s *SRegion) getStoragecache() *SStoragecache { + if s.storageCache == nil { + s.storageCache = &SStoragecache{region: s} + } + return s.storageCache +} + +func (r *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + storageCache := r.getStoragecache() + if storageCache.GetGlobalId() == id { + return storageCache, nil + } + return nil, cloudprovider.ErrNotFound +} + +func (r *SRegion) GetProvider() string { + return api.CLOUD_PROVIDER_JDCLOUD +} + +func (r *SRegion) GetCapabilities() []string { + return []string{ + cloudprovider.CLOUD_CAPABILITY_COMPUTE + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_NETWORK + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_EIP + cloudprovider.READ_ONLY_SUFFIX, + cloudprovider.CLOUD_CAPABILITY_RDS + cloudprovider.READ_ONLY_SUFFIX, + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/securitygroup.go new file mode 100644 index 0000000000..c8f6725f15 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/securitygroup.go @@ -0,0 +1,162 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + "net" + + commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/apis" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/client" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/models" + + "yunion.io/x/pkg/util/secrules" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSecurityGroup struct { + multicloud.SSecurityGroup + JdcloudTags + + vpc *SVpc + models.NetworkSecurityGroup +} + +func (sg *SSecurityGroup) GetVpcId() string { + return sg.VpcId +} + +func (sg *SSecurityGroup) GetId() string { + return sg.NetworkSecurityGroupId +} + +func (sg *SSecurityGroup) GetGlobalId() string { + return sg.GetId() +} + +func (sg *SSecurityGroup) GetName() string { + return sg.NetworkSecurityGroupName +} + +func (sg *SSecurityGroup) GetDescription() string { + return sg.Description +} + +func (sg *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + rules := sg.SecurityGroupRules + srs := make([]cloudprovider.SecurityRule, 0, len(rules)) + for i := range rules { + rule := secrules.SecurityRule{ + Priority: 1, + } + + if rules[i].Direction == 0 { + rule.Direction = secrules.SecurityRuleIngress + } else { + rule.Direction = secrules.SecurityRuleEgress + } + + switch rules[i].Protocol { + case 6: + rule.Protocol = secrules.PROTO_TCP + case 17: + rule.Protocol = secrules.PROTO_UDP + case 1: + rule.Protocol = secrules.PROTO_ICMP + case 300: + rule.Protocol = secrules.PROTO_ANY + } + + _, rule.IPNet, _ = net.ParseCIDR(rules[i].AddressPrefix) + rule.Description = rules[i].Description + rule.PortStart = rules[i].FromPort + rule.PortEnd = rules[i].ToPort + rule.Action = secrules.SecurityRuleAllow + + if rules[i].RuleType == "default" && rules[i].FromPort == 0 && rules[i].ToPort == 0 { + rule.Action = secrules.SecurityRuleDeny + } + + sr := cloudprovider.SecurityRule{ + Id: rules[i].RuleId, + ExternalId: rules[i].RuleId, + SecurityRule: rule, + } + srs = append(srs, sr) + } + return srs, nil +} + +func (sg *SSecurityGroup) GetStatus() string { + return "" +} + +func (sg *SSecurityGroup) IsEmulated() bool { + return false +} + +func (sg *SSecurityGroup) Refresh() error { + return nil +} + +func (sg *SSecurityGroup) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (sg *SSecurityGroup) GetProjectId() string { + return "" +} + +func (sg *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + return nil +} + +func (r *SRegion) GetSecurityGroups(vpcId string, securityGroupIds []string, pageNumber int, pageSize int) ([]SSecurityGroup, int, error) { + filters := []commodels.Filter{} + if vpcId != "" { + filters = append(filters, commodels.Filter{ + Name: "vpcId", + Values: []string{vpcId}, + }) + } + if len(securityGroupIds) > 0 { + filters = append(filters, commodels.Filter{ + Name: "networkSecurityGroupIds", + Values: securityGroupIds, + }) + } + req := apis.NewDescribeNetworkSecurityGroupsRequestWithAllParams(r.ID, &pageNumber, &pageSize, filters) + client := client.NewVpcClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeNetworkSecurityGroups(req) + if err != nil { + return nil, 0, err + } + if resp.Error.Code >= 400 { + err = fmt.Errorf(resp.Error.Message) + return nil, 0, err + } + total := resp.Result.TotalCount + sgs := make([]SSecurityGroup, 0, len(resp.Result.NetworkSecurityGroups)) + for i := range resp.Result.NetworkSecurityGroups { + sgs = append(sgs, SSecurityGroup{ + NetworkSecurityGroup: resp.Result.NetworkSecurityGroups[i], + }) + } + return sgs, total, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/snapshot.go new file mode 100644 index 0000000000..42694c6a94 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/snapshot.go @@ -0,0 +1,159 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + + commodels "github.com/jdcloud-api/jdcloud-sdk-go/services/common/models" + "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/apis" + "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/client" + "github.com/jdcloud-api/jdcloud-sdk-go/services/disk/models" + + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSnapshot struct { + multicloud.SResourceBase + JdcloudTags + region *SRegion + + models.Snapshot + disk *SDisk +} + +func (s *SSnapshot) GetId() string { + return s.SnapshotId +} + +func (s *SSnapshot) GetName() string { + return s.Name +} + +func (s *SSnapshot) GetStatus() string { + switch s.Status { + case "creating": + return api.SNAPSHOT_CREATING + case "available", "in-use": + return api.SNAPSHOT_READY + case "deleting": + return api.SNAPSHOT_DELETING + case "error_create": + return api.SNAPSHOT_FAILED + case "error_delete": + return api.SNAPSHOT_DELETE_FAILED + default: + return api.SNAPSHOT_UNKNOWN + } +} + +func (s *SSnapshot) GetSizeMb() int32 { + return int32(s.SnapshotSizeGB) * 1024 +} + +func (s *SSnapshot) GetDiskId() string { + return s.DiskId +} + +func (s *SSnapshot) getDisk() (*SDisk, error) { + if s.disk != nil { + return s.disk, nil + } + disk, err := s.region.GetDiskById(s.DiskId) + if err != nil { + return disk, err + } + s.disk = disk + return s.disk, nil +} + +func (s *SSnapshot) GetDiskType() string { + disk, err := s.getDisk() + if err != nil { + log.Errorf("unable to get disk %s", s.DiskId) + return "" + } + return disk.GetDiskType() +} + +func (s *SSnapshot) Refresh() error { + return nil +} + +func (s *SSnapshot) GetGlobalId() string { + return s.GetId() +} + +func (s *SSnapshot) IsEmulated() bool { + return false +} + +func (s *SSnapshot) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (s *SSnapshot) GetProjectId() string { + return "" +} + +func (r *SRegion) GetSnapshots(diskId string, pageNumber, pageSize int) ([]SSnapshot, int, error) { + filters := []commodels.Filter{} + if diskId != "" { + filters = append(filters, commodels.Filter{ + Name: "diskId", + Values: []string{diskId}, + }) + } + req := apis.NewDescribeSnapshotsRequestWithAllParams(r.ID, &pageNumber, &pageSize, nil, filters) + client := client.NewDiskClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeSnapshots(req) + if err != nil { + return nil, 0, err + } + if resp.Error.Code >= 400 { + return nil, 0, fmt.Errorf(resp.Error.Message) + } + snapshots := make([]SSnapshot, len(resp.Result.Snapshots)) + for i := range resp.Result.Snapshots { + snapshots = append(snapshots, SSnapshot{ + region: r, + Snapshot: resp.Result.Snapshots[i], + }) + } + return snapshots, resp.Result.TotalCount, nil +} + +func (r *SRegion) GetSnapshotById(id string) (*SSnapshot, error) { + req := apis.NewDescribeSnapshotRequest(r.ID, id) + client := client.NewDiskClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeSnapshot(req) + if err != nil { + return nil, err + } + if resp.Error.Code >= 400 { + return nil, fmt.Errorf(resp.Error.Message) + } + snapshot := SSnapshot{ + region: r, + Snapshot: resp.Result.Snapshot, + } + return &snapshot, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/storage.go new file mode 100644 index 0000000000..585040f933 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/storage.go @@ -0,0 +1,148 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var storageTypes = []string{ + api.STORAGE_JDCLOUD_STD, + api.STORAGE_JDCLOUD_GP1, + api.STORAGE_JDCLOUD_IO1, + api.STORAGE_JDCLOUD_SSD, + api.STORAGE_JDCLOUD_PHD, +} + +type SStorage struct { + multicloud.SStorageBase + JdcloudTags + zone *SZone + storageType string +} + +func (s *SStorage) GetId() string { + return fmt.Sprintf("%s-%s-%s", s.zone.region.cpcfg.Id, s.zone.GetGlobalId(), s.storageType) +} + +func (s *SStorage) GetName() string { + return fmt.Sprintf("%s-%s-%s", s.zone.region.cpcfg.Name, s.zone.GetName(), s.storageType) +} + +func (s *SStorage) GetGlobalId() string { + return s.GetId() +} + +func (s *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (s *SStorage) Refresh() error { + return nil +} + +func (s *SStorage) IsEmulated() bool { + return true +} + +func (s *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return s.zone.region.getStoragecache() +} + +var ss cloudprovider.ICloudStorage = &SStorage{} + +func (s *SStorage) GetIZone() cloudprovider.ICloudZone { + return s.zone +} + +func (s *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks := make([]SDisk, 0) + n := 1 + for { + parts, total, err := s.zone.region.GetDisks("", s.zone.GetId(), s.storageType, []string{}, n, 100) + if err != nil { + return nil, err + } + disks = append(disks, parts...) + if len(disks) >= total { + break + } + n++ + } + idisk := make([]cloudprovider.ICloudDisk, len(disks)) + for i := range disks { + disks[i].storage = s + idisk[i] = &disks[i] + } + return idisk, nil +} + +func (s *SStorage) GetStorageType() string { + return s.storageType +} + +func (s *SStorage) GetMediumType() string { + if s.storageType == api.STORAGE_JDCLOUD_STD { + return api.DISK_TYPE_ROTATE + } else { + return api.DISK_TYPE_SSD + } +} + +func (s *SStorage) GetCapacityMB() int64 { + return 0 +} + +func (s *SStorage) GetStorageConf() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (s *SStorage) GetEnabled() bool { + return true +} + +func (s *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (s *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + disk, err := s.zone.region.GetDiskById(idStr) + if err != nil { + return nil, err + } + disk.storage = s + return disk, nil +} + +func (s *SStorage) GetMountPoint() string { + return "" +} + +func (s *SStorage) IsSysDiskStore() bool { + return true +} +func (s *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (s *SStorage) DisableSync() bool { + return false +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/storagecache.go new file mode 100644 index 0000000000..d86f763463 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/storagecache.go @@ -0,0 +1,107 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStoragecache struct { + multicloud.SResourceBase + JdcloudTags + region *SRegion +} + +func (sc *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", sc.region.cpcfg.Id, sc.region.GetId()) +} + +func (sc *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", sc.region.cpcfg.Name, sc.region.GetName()) +} + +func (sc *SStoragecache) GetStatus() string { + return "available" +} + +func (sc *SStoragecache) Refresh() error { + return nil +} + +func (sc *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", sc.region.cpcfg.Id, sc.region.GetGlobalId()) +} + +func (sc *SStoragecache) IsEmulated() bool { + return false +} + +func (sc *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (sc *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + images := make([]SImage, 0) + n := 1 + for { + parts, total, err := sc.region.GetImages([]string{}, "private", n, 100) + if err != nil { + return nil, err + } + images = append(images, parts...) + if len(images) >= total { + break + } + n++ + } + ret := make([]cloudprovider.ICloudImage, len(images)) + for i := range ret { + images[i].storageCache = sc + ret[i] = &images[i] + } + return ret, nil +} + +func (sc *SStoragecache) GetIImageById(exId string) (cloudprovider.ICloudImage, error) { + img, err := sc.region.GetImage(exId) + if err != nil { + return nil, err + } + img.storageCache = sc + return img, nil +} + +func (sc *SStoragecache) GetPath() string { + return "" +} + +func (sc *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (sc *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (sc *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return "", cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/tag_base.go new file mode 100644 index 0000000000..85bc623382 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/tag_base.go @@ -0,0 +1,36 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type JdcloudTags struct { +} + +func (jt *JdcloudTags) GetTags() (map[string]string, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") +} + +func (self *JdcloudTags) GetSysTags() map[string]string { + return nil +} + +func (self *JdcloudTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/utils.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/utils.go new file mode 100644 index 0000000000..b7221fde1b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/utils.go @@ -0,0 +1,46 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "time" + + "github.com/jdcloud-api/jdcloud-sdk-go/services/charge/models" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" +) + +func parseTime(ts string) time.Time { + t, _ := time.Parse("2006-01-02T15:04:05Z", ts) + return t +} + +func billingType(charge *models.Charge) string { + switch charge.ChargeMode { + case "prepaid_by_duration": + return billing_api.BILLING_TYPE_PREPAID + case "postpaid_by_usage", "postpaid_by_duration": + return billing_api.BILLING_TYPE_POSTPAID + default: + return "" + } +} + +func expireAt(charge *models.Charge) time.Time { + if billingType(charge) == billing_api.BILLING_TYPE_POSTPAID { + return time.Time{} + } + return parseTime(charge.ChargeExpiredTime) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/vpc.go new file mode 100644 index 0000000000..8e513a41a2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/vpc.go @@ -0,0 +1,190 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/apis" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/client" + "github.com/jdcloud-api/jdcloud-sdk-go/services/vpc/models" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + JdcloudTags + models.Vpc + + secgroups []cloudprovider.ICloudSecurityGroup + iwires []cloudprovider.ICloudWire + + region *SRegion +} + +func (v *SVpc) GetId() string { + return v.VpcId +} + +func (v *SVpc) GetName() string { + return v.VpcName +} + +func (v *SVpc) GetGlobalId() string { + return v.GetId() +} + +func (v *SVpc) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} + +func (v *SVpc) Refresh() error { + return nil +} + +func (v *SVpc) IsEmulated() bool { + return false +} + +func (v *SVpc) GetRegion() cloudprovider.ICloudRegion { + return v.region +} + +func (v *SVpc) GetIsDefault() bool { + return false +} + +func (v *SVpc) GetCidrBlock() string { + return "" +} + +func (v *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + if v.iwires != nil { + return v.iwires, nil + } + wire := SWire{ + vpc: v, + } + v.iwires = []cloudprovider.ICloudWire{&wire} + return v.iwires, nil +} + +func (v *SVpc) GetWire() *SWire { + return &SWire{ + vpc: v, + } +} + +func (v *SVpc) fetchSecurityGroups() error { + secgroups := make([]SSecurityGroup, 0) + n := 1 + for { + parts, total, err := v.region.GetSecurityGroups(v.GetId(), []string{}, n, 100) + if err != nil { + return err + } + secgroups = append(secgroups, parts...) + if len(secgroups) >= total { + break + } + n++ + } + v.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) + for i := 0; i < len(secgroups); i++ { + secgroups[i].vpc = v + v.secgroups[i] = &secgroups[i] + } + return nil +} + +func (v *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + if v.secgroups == nil { + err := v.fetchSecurityGroups() + if err != nil { + return nil, err + } + } + return v.secgroups, nil +} + +func (v *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (v *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, nil +} + +func (v *SVpc) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (v *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { + iwires, err := v.GetIWires() + if err != nil { + return nil, err + } + for i := range iwires { + if iwires[i].GetGlobalId() == wireId { + return iwires[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (r *SRegion) GetVpcs(pageNumber, pageSize int) (vpcs []SVpc, total int, err error) { + req := apis.NewDescribeVpcsRequestWithAllParams(r.ID, &pageNumber, &pageSize, nil) + client := client.NewVpcClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeVpcs(req) + if err != nil { + return + } + if resp.Error.Code >= 400 { + err = errors.Error(resp.Error.Message) + return + } + total = resp.Result.TotalCount + vpcs = make([]SVpc, 0, len(resp.Result.Vpcs)) + for i := range resp.Result.Vpcs { + vpcs = append(vpcs, SVpc{ + Vpc: resp.Result.Vpcs[i], + region: r, + }) + } + return +} + +func (r *SRegion) GetVpcById(id string) (*SVpc, error) { + req := apis.NewDescribeVpcRequest(r.ID, id) + client := client.NewVpcClient(r.getCredential()) + client.Logger = Logger{debug: r.client.debug} + resp, err := client.DescribeVpc(req) + if err != nil { + return nil, err + } + if resp.Error.Code >= 400 { + return nil, fmt.Errorf(resp.Error.Message) + } + return &SVpc{ + region: r, + Vpc: resp.Result.Vpc, + }, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/wire.go new file mode 100644 index 0000000000..efcfd349ba --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/wire.go @@ -0,0 +1,120 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + JdcloudTags + + vpc *SVpc + inetworks []cloudprovider.ICloudNetwork +} + +func (w *SWire) GetId() string { + return fmt.Sprintf("%s-%s", w.vpc.GetId(), w.vpc.region.GetId()) +} + +func (w *SWire) GetName() string { + return w.GetId() +} + +func (w *SWire) GetGlobalId() string { + return fmt.Sprintf("%s-%s", w.vpc.GetGlobalId(), w.vpc.region.GetGlobalId()) +} + +func (w *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (w *SWire) Refresh() error { + return nil +} + +func (w *SWire) IsEmulated() bool { + return true +} + +func (w *SWire) GetIVpc() cloudprovider.ICloudVpc { + return w.vpc +} + +func (w *SWire) GetIZone() cloudprovider.ICloudZone { + return nil +} + +func (w *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + if w.inetworks == nil { + nets, err := w.networks() + if err != nil { + return nil, err + } + w.inetworks = make([]cloudprovider.ICloudNetwork, 0, len(nets)) + for i := range nets { + nets[i].wire = w + w.inetworks = append(w.inetworks, &nets[i]) + } + } + return w.inetworks, nil +} + +func (w *SWire) networks() ([]SNetwork, error) { + nets := make([]SNetwork, 0) + n := 1 + for { + parts, total, err := w.vpc.region.GetNetworks(w.vpc.VpcId, n, 100) + if err != nil { + return nil, err + } + nets = append(nets, parts...) + if len(nets) >= total { + break + } + n++ + } + return nets, nil +} + +func (w *SWire) GetBandwidth() int { + return 10000 +} + +func (w *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { + networks, err := w.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 (w *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (w *SWire) CreateNetworks() (*SNetwork, error) { + return nil, cloudprovider.ErrNotImplemented +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/zone.go new file mode 100644 index 0000000000..10b04b9dcd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/jdcloud/zone.go @@ -0,0 +1,195 @@ +// Copyright 2019 Yunion +// +// 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 jdcloud + +import ( + "fmt" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type sZoneIden struct { + Id string + Name string +} + +var ZonesInRegion = map[string][]sZoneIden{ + "cn-north-1": { + { + Id: "cn-north-1a", + Name: "可用区A", + }, + { + Id: "cn-north-1b", + Name: "可用区B", + }, + { + Id: "cn-north-1c", + Name: "可用区C", + }, + }, + "cn-east-1": { + { + Id: "cn-east-1a", + Name: "可用区A", + }, + }, + "cn-east-2": { + { + Id: "cn-east-2a", + Name: "可用区A", + }, + { + Id: "cn-east-2b", + Name: "可用区B", + }, + { + Id: "cn-east-2c", + Name: "可用区C", + }, + }, + "cn-south-1": { + { + Id: "cn-south-1a", + Name: "可用区A", + }, + { + Id: "cn-south-1b", + Name: "可用区B", + }, + { + Id: "cn-south-1c", + Name: "可用区C", + }, + }, +} + +type SZone struct { + multicloud.SResourceBase + JdcloudTags + region *SRegion + + ihost cloudprovider.ICloudHost + istorages []cloudprovider.ICloudStorage + + ID string + Name string +} + +func (z *SZone) GetId() string { + return z.ID +} + +func (z *SZone) GetName() string { + return z.Name +} + +func (z *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s", z.region.GetGlobalId(), z.ID) +} + +func (z *SZone) GetStatus() string { + return "enable" +} + +func (z *SZone) Refresh() error { + return nil +} + +func (z *SZone) IsEmulated() bool { + return false +} + +func (z *SZone) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(z.GetName()).CN(z.GetName()).EN(fmt.Sprintf("%s %s", CLOUD_PROVIDER_JDCLOUD_EN, z.Name)) + return table +} + +func (z *SZone) GetIRegion() cloudprovider.ICloudRegion { + return z.region +} + +func (z *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + if z.ihost != nil { + return []cloudprovider.ICloudHost{z.ihost}, nil + } + z.ihost = &SHost{ + zone: z, + } + return []cloudprovider.ICloudHost{z.ihost}, nil +} + +func (z *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + ihosts, err := z.GetIHosts() + if err != nil { + return nil, err + } + for i := range ihosts { + if ihosts[i].GetGlobalId() == id { + return ihosts[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (z *SZone) fetchStorages() error { + istorages := make([]cloudprovider.ICloudStorage, len(storageTypes)) + for i := range istorages { + istorages[i] = &SStorage{ + zone: z, + storageType: storageTypes[i], + } + } + z.istorages = istorages + return nil +} + +func (z *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + if z.istorages == nil { + err := z.fetchStorages() + if err != nil { + return nil, err + } + } + return z.istorages, nil +} + +func (z *SZone) getStorageByType(t string) (*SStorage, error) { + istorages, err := z.GetIStorages() + if err != nil { + return nil, err + } + for i := range istorages { + if istorages[i].GetStorageType() == t { + return istorages[i].(*SStorage), nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (z *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + istorages, err := z.GetIStorages() + if err != nil { + return nil, err + } + for i := range istorages { + if istorages[i].GetGlobalId() == id { + return istorages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} diff --git a/pkg/multicloud/lbredirect_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/lbredirect_base.go similarity index 100% rename from pkg/multicloud/lbredirect_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/lbredirect_base.go diff --git a/pkg/multicloud/loadbalancer_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/loadbalancer_base.go similarity index 94% rename from pkg/multicloud/loadbalancer_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/loadbalancer_base.go index c152055c3d..4ba60ab558 100644 --- a/pkg/multicloud/loadbalancer_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/loadbalancer_base.go @@ -15,7 +15,7 @@ package multicloud import ( - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SLoadbalancerBase struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/loader/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/loader/doc.go new file mode 100644 index 0000000000..19ccc5eba2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/loader/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 loader // import "yunion.io/x/cloudmux/pkg/multicloud/loader" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/loader/loader.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/loader/loader.go new file mode 100644 index 0000000000..da4f28343b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/loader/loader.go @@ -0,0 +1,49 @@ +// Copyright 2019 Yunion +// +// 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 loader + +import ( + "yunion.io/x/log" // on-premise virtualization technologies + + _ "yunion.io/x/cloudmux/pkg/multicloud/aliyun/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/apsara/provider" // aliyun apsara stack + _ "yunion.io/x/cloudmux/pkg/multicloud/aws/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/azure/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/bingocloud/provider" // private clouds + _ "yunion.io/x/cloudmux/pkg/multicloud/cloudpods/provider" // private clouds + _ "yunion.io/x/cloudmux/pkg/multicloud/ctyun/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/ecloud/provider" // public clouds + _ "yunion.io/x/cloudmux/pkg/multicloud/esxi/provider" // private clouds + _ "yunion.io/x/cloudmux/pkg/multicloud/google/provider" // public clouds + _ "yunion.io/x/cloudmux/pkg/multicloud/hcs/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/hcso/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/huawei/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/incloudsphere/provider" // private clouds + _ "yunion.io/x/cloudmux/pkg/multicloud/jdcloud/provider" // public clouds + _ "yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider" // private clouds + _ "yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/openstack/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/proxmox/provider" // private clouds + _ "yunion.io/x/cloudmux/pkg/multicloud/qcloud/provider" + _ "yunion.io/x/cloudmux/pkg/multicloud/remotefile/provider" // private clouds + _ "yunion.io/x/cloudmux/pkg/multicloud/ucloud/provider" // object storages + _ "yunion.io/x/cloudmux/pkg/multicloud/zstack/provider" // private clouds +) + +func init() { + log.Infof("Loading cloud providers ...") +} diff --git a/pkg/multicloud/mongodb_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/mongodb_base.go similarity index 100% rename from pkg/multicloud/mongodb_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/mongodb_base.go diff --git a/pkg/multicloud/nas_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nas_base.go similarity index 100% rename from pkg/multicloud/nas_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/nas_base.go diff --git a/pkg/multicloud/natgateway_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/natgateway_base.go similarity index 97% rename from pkg/multicloud/natgateway_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/natgateway_base.go index 2f15df82bc..ff96619624 100644 --- a/pkg/multicloud/natgateway_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/natgateway_base.go @@ -17,7 +17,7 @@ package multicloud import ( "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SNatGatewayBase struct { diff --git a/pkg/multicloud/networkinterface_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/networkinterface_base.go similarity index 100% rename from pkg/multicloud/networkinterface_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/networkinterface_base.go diff --git a/pkg/multicloud/no_lb_region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/no_lb_region.go similarity index 97% rename from pkg/multicloud/no_lb_region.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/no_lb_region.go index f735e1eb94..2062b56a10 100644 --- a/pkg/multicloud/no_lb_region.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/no_lb_region.go @@ -14,7 +14,7 @@ package multicloud -import "yunion.io/x/onecloud/pkg/cloudprovider" +import "yunion.io/x/cloudmux/pkg/cloudprovider" type SNoLbRegion struct{} diff --git a/pkg/multicloud/no_storage_region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/no_storage_region.go similarity index 96% rename from pkg/multicloud/no_storage_region.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/no_storage_region.go index 2cce5c59c3..ce490647bf 100644 --- a/pkg/multicloud/no_storage_region.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/no_storage_region.go @@ -14,7 +14,7 @@ package multicloud -import "yunion.io/x/onecloud/pkg/cloudprovider" +import "yunion.io/x/cloudmux/pkg/cloudprovider" type SNoObjectStorageRegion struct{} diff --git a/pkg/multicloud/nutanix/cluster.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/cluster.go similarity index 100% rename from pkg/multicloud/nutanix/cluster.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/cluster.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/disk.go new file mode 100644 index 0000000000..18bceafb99 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/disk.go @@ -0,0 +1,355 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "context" + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type DiskStats struct { + HypervisorAvgIoLatencyUsecs string `json:"hypervisor_avg_io_latency_usecs"` + HypervisorWriteIoBandwidthKBps string `json:"hypervisor_write_io_bandwidth_kBps"` + ControllerRandomOpsPpm string `json:"controller.random_ops_ppm"` + ControllerStorageTierSsdUsageBytes string `json:"controller.storage_tier.ssd.usage_bytes"` + ReadIoPpm string `json:"read_io_ppm"` + ControllerFrontendReadLatencyHistogram1000Us string `json:"controller.frontend_read_latency_histogram_1000us"` + ControllerNumIops string `json:"controller_num_iops"` + ControllerFrontendWriteOps string `json:"controller.frontend_write_ops"` + ControllerFrontendWriteLatencyHistogram10000Us string `json:"controller.frontend_write_latency_histogram_10000us"` + ControllerReadSizeHistogram1024KB string `json:"controller.read_size_histogram_1024kB"` + TotalReadIoTimeUsecs string `json:"total_read_io_time_usecs"` + ControllerTotalReadIoTimeUsecs string `json:"controller_total_read_io_time_usecs"` + ControllerWss3600SWriteMB string `json:"controller.wss_3600s_write_MB"` + ControllerFrontendReadLatencyHistogram50000Us string `json:"controller.frontend_read_latency_histogram_50000us"` + ControllerFrontendReadLatencyHistogram2000Us string `json:"controller.frontend_read_latency_histogram_2000us"` + ControllerNumWriteIo string `json:"controller_num_write_io"` + ControllerReadSourceCacheSsdBytes string `json:"controller.read_source_cache_ssd_bytes"` + ControllerReadSourceOplogBytes string `json:"controller.read_source_oplog_bytes"` + ControllerReadSourceCacheDramBytes string `json:"controller.read_source_cache_dram_bytes"` + ControllerRandomReadOps string `json:"controller.random_read_ops"` + ControllerTotalIoTimeUsecs string `json:"controller_total_io_time_usecs"` + ControllerNumSeqIo string `json:"controller_num_seq_io"` + ControllerTotalIoSizeKbytes string `json:"controller_total_io_size_kbytes"` + ControllerWss120SWriteMB string `json:"controller.wss_120s_write_MB"` + ControllerReadSourceBlockStoreBytes string `json:"controller.read_source_block_store_bytes"` + ControllerNumIo string `json:"controller_num_io"` + ControllerReadSourceEstoreZeroBytes string `json:"controller.read_source_estore_zero_bytes"` + ControllerNumRandomIo string `json:"controller_num_random_io"` + HypervisorNumReadIo string `json:"hypervisor_num_read_io"` + HypervisorTotalReadIoTimeUsecs string `json:"hypervisor_total_read_io_time_usecs"` + NumIo string `json:"num_io"` + HypervisorNumWriteIo string `json:"hypervisor_num_write_io"` + ControllerWriteSizeHistogram32KB string `json:"controller.write_size_histogram_32kB"` + ControllerFrontendReadLatencyHistogram20000Us string `json:"controller.frontend_read_latency_histogram_20000us"` + ControllerReadSizeHistogram32KB string `json:"controller.read_size_histogram_32kB"` + HypervisorNumWriteIops string `json:"hypervisor_num_write_iops"` + AvgIoLatencyUsecs string `json:"avg_io_latency_usecs"` + ControllerWriteIoPpm string `json:"controller_write_io_ppm"` + ControllerReadSourceEstoreSsdBytes string `json:"controller.read_source_estore_ssd_bytes"` + HypervisorTotalReadIoSizeKbytes string `json:"hypervisor_total_read_io_size_kbytes"` + ControllerNumWriteIops string `json:"controller_num_write_iops"` + TotalIoTimeUsecs string `json:"total_io_time_usecs"` + ControllerWss3600SReadMB string `json:"controller.wss_3600s_read_MB"` + ControllerSummaryReadSourceSsdBytesPerSec string `json:"controller.summary_read_source_ssd_bytes_per_sec"` + ControllerWriteSizeHistogram16KB string `json:"controller.write_size_histogram_16kB"` + TotalTransformedUsageBytes string `json:"total_transformed_usage_bytes"` + AvgWriteIoLatencyUsecs string `json:"avg_write_io_latency_usecs"` + ControllerCseTarget90PercentWriteMB string `json:"controller.cse_target_90_percent_write_MB"` + NumReadIo string `json:"num_read_io"` + HypervisorReadIoBandwidthKBps string `json:"hypervisor_read_io_bandwidth_kBps"` + HypervisorTotalIoTimeUsecs string `json:"hypervisor_total_io_time_usecs"` + NumRandomIo string `json:"num_random_io"` + ControllerWriteDestEstoreBytes string `json:"controller.write_dest_estore_bytes"` + ControllerFrontendWriteLatencyHistogram5000Us string `json:"controller.frontend_write_latency_histogram_5000us"` + ControllerStorageTierDasSataPinnedUsageBytes string `json:"controller.storage_tier.das-sata.pinned_usage_bytes"` + NumWriteIo string `json:"num_write_io"` + ControllerFrontendWriteLatencyHistogram2000Us string `json:"controller.frontend_write_latency_histogram_2000us"` + ControllerRandomWriteOpsPerSec string `json:"controller.random_write_ops_per_sec"` + ControllerFrontendWriteLatencyHistogram20000Us string `json:"controller.frontend_write_latency_histogram_20000us"` + IoBandwidthKBps string `json:"io_bandwidth_kBps"` + ControllerWriteSizeHistogram512KB string `json:"controller.write_size_histogram_512kB"` + ControllerReadSizeHistogram16KB string `json:"controller.read_size_histogram_16kB"` + WriteIoPpm string `json:"write_io_ppm"` + ControllerAvgWriteIoLatencyUsecs string `json:"controller_avg_write_io_latency_usecs"` + ControllerFrontendReadLatencyHistogram100000Us string `json:"controller.frontend_read_latency_histogram_100000us"` + NumReadIops string `json:"num_read_iops"` + ControllerSummaryReadSourceHddBytesPerSec string `json:"controller.summary_read_source_hdd_bytes_per_sec"` + ControllerReadSourceExtentCacheBytes string `json:"controller.read_source_extent_cache_bytes"` + TimespanUsecs string `json:"timespan_usecs"` + ControllerNumReadIops string `json:"controller_num_read_iops"` + ControllerFrontendReadLatencyHistogram10000Us string `json:"controller.frontend_read_latency_histogram_10000us"` + ControllerWriteSizeHistogram64KB string `json:"controller.write_size_histogram_64kB"` + ControllerFrontendWriteLatencyHistogram0Us string `json:"controller.frontend_write_latency_histogram_0us"` + ControllerFrontendWriteLatencyHistogram100000Us string `json:"controller.frontend_write_latency_histogram_100000us"` + HypervisorNumIo string `json:"hypervisor_num_io"` + ControllerTotalTransformedUsageBytes string `json:"controller_total_transformed_usage_bytes"` + AvgReadIoLatencyUsecs string `json:"avg_read_io_latency_usecs"` + ControllerTotalReadIoSizeKbytes string `json:"controller_total_read_io_size_kbytes"` + ControllerReadIoPpm string `json:"controller_read_io_ppm"` + ControllerFrontendOps string `json:"controller.frontend_ops"` + ControllerWss120SReadMB string `json:"controller.wss_120s_read_MB"` + ControllerReadSizeHistogram512KB string `json:"controller.read_size_histogram_512kB"` + HypervisorAvgReadIoLatencyUsecs string `json:"hypervisor_avg_read_io_latency_usecs"` + ControllerWriteSizeHistogram1024KB string `json:"controller.write_size_histogram_1024kB"` + ControllerWriteDestBlockStoreBytes string `json:"controller.write_dest_block_store_bytes"` + ControllerReadSizeHistogram4KB string `json:"controller.read_size_histogram_4kB"` + NumWriteIops string `json:"num_write_iops"` + ControllerRandomOpsPerSec string `json:"controller.random_ops_per_sec"` + NumIops string `json:"num_iops"` + ControllerStorageTierCloudPinnedUsageBytes string `json:"controller.storage_tier.cloud.pinned_usage_bytes"` + ControllerAvgIoLatencyUsecs string `json:"controller_avg_io_latency_usecs"` + ControllerReadSizeHistogram8KB string `json:"controller.read_size_histogram_8kB"` + ControllerNumReadIo string `json:"controller_num_read_io"` + ControllerSeqIoPpm string `json:"controller_seq_io_ppm"` + ControllerReadIoBandwidthKBps string `json:"controller_read_io_bandwidth_kBps"` + ControllerIoBandwidthKBps string `json:"controller_io_bandwidth_kBps"` + ControllerReadSizeHistogram0KB string `json:"controller.read_size_histogram_0kB"` + ControllerRandomOps string `json:"controller.random_ops"` + HypervisorTimespanUsecs string `json:"hypervisor_timespan_usecs"` + TotalReadIoSizeKbytes string `json:"total_read_io_size_kbytes"` + HypervisorTotalIoSizeKbytes string `json:"hypervisor_total_io_size_kbytes"` + ControllerFrontendOpsPerSec string `json:"controller.frontend_ops_per_sec"` + ControllerWriteDestOplogBytes string `json:"controller.write_dest_oplog_bytes"` + ControllerFrontendWriteLatencyHistogram1000Us string `json:"controller.frontend_write_latency_histogram_1000us"` + HypervisorNumReadIops string `json:"hypervisor_num_read_iops"` + ControllerSummaryReadSourceCacheBytesPerSec string `json:"controller.summary_read_source_cache_bytes_per_sec"` + ControllerWriteIoBandwidthKBps string `json:"controller_write_io_bandwidth_kBps"` + ControllerUserBytes string `json:"controller_user_bytes"` + HypervisorAvgWriteIoLatencyUsecs string `json:"hypervisor_avg_write_io_latency_usecs"` + ControllerStorageTierSsdPinnedUsageBytes string `json:"controller.storage_tier.ssd.pinned_usage_bytes"` + ReadIoBandwidthKBps string `json:"read_io_bandwidth_kBps"` + ControllerFrontendReadOps string `json:"controller.frontend_read_ops"` + HypervisorNumIops string `json:"hypervisor_num_iops"` + HypervisorIoBandwidthKBps string `json:"hypervisor_io_bandwidth_kBps"` + ControllerWss120SUnionMB string `json:"controller.wss_120s_union_MB"` + ControllerReadSourceEstoreHddBytes string `json:"controller.read_source_estore_hdd_bytes"` + ControllerRandomIoPpm string `json:"controller_random_io_ppm"` + ControllerCseTarget90PercentReadMB string `json:"controller.cse_target_90_percent_read_MB"` + ControllerStorageTierDasSataUsageBytes string `json:"controller.storage_tier.das-sata.usage_bytes"` + ControllerFrontendReadLatencyHistogram5000Us string `json:"controller.frontend_read_latency_histogram_5000us"` + ControllerAvgReadIoSizeKbytes string `json:"controller_avg_read_io_size_kbytes"` + WriteIoBandwidthKBps string `json:"write_io_bandwidth_kBps"` + ControllerRandomReadOpsPerSec string `json:"controller.random_read_ops_per_sec"` + ControllerReadSizeHistogram64KB string `json:"controller.read_size_histogram_64kB"` + ControllerWss3600SUnionMB string `json:"controller.wss_3600s_union_MB"` + RandomIoPpm string `json:"random_io_ppm"` + TotalUntransformedUsageBytes string `json:"total_untransformed_usage_bytes"` + ControllerFrontendReadLatencyHistogram0Us string `json:"controller.frontend_read_latency_histogram_0us"` + ControllerRandomWriteOps string `json:"controller.random_write_ops"` + ControllerAvgWriteIoSizeKbytes string `json:"controller_avg_write_io_size_kbytes"` + ControllerAvgReadIoLatencyUsecs string `json:"controller_avg_read_io_latency_usecs"` + TotalIoSizeKbytes string `json:"total_io_size_kbytes"` + ControllerStorageTierCloudUsageBytes string `json:"controller.storage_tier.cloud.usage_bytes"` + ControllerFrontendWriteLatencyHistogram50000Us string `json:"controller.frontend_write_latency_histogram_50000us"` + ControllerWriteSizeHistogram8KB string `json:"controller.write_size_histogram_8kB"` + ControllerTimespanUsecs string `json:"controller_timespan_usecs"` + NumSeqIo string `json:"num_seq_io"` + ControllerWriteSizeHistogram4KB string `json:"controller.write_size_histogram_4kB"` + SeqIoPpm string `json:"seq_io_ppm"` + ControllerWriteSizeHistogram0KB string `json:"controller.write_size_histogram_0kB"` +} + +type SDisk struct { + multicloud.STagBase + multicloud.SDisk + + storage *SStorage + + VirtualDiskID string `json:"virtual_disk_id"` + UUID string `json:"uuid"` + DeviceUUID string `json:"device_uuid"` + NutanixNfsfilePath string `json:"nutanix_nfsfile_path"` + DiskAddress string `json:"disk_address"` + AttachedVMID string `json:"attached_vm_id"` + AttachedVMUUID string `json:"attached_vm_uuid"` + AttachedVmname string `json:"attached_vmname"` + AttachedVolumeGroupID string `json:"attached_volume_group_id"` + DiskCapacityInBytes int64 `json:"disk_capacity_in_bytes"` + ClusterUUID string `json:"cluster_uuid"` + StorageContainerID string `json:"storage_container_id"` + StorageContainerUUID string `json:"storage_container_uuid"` + FlashModeEnabled string `json:"flash_mode_enabled"` + DataSourceURL string `json:"data_source_url"` + Stats DiskStats `json:"stats"` + + isSys bool +} + +func (self *SDisk) GetName() string { + return self.DiskAddress +} + +func (self *SDisk) GetId() string { + return self.UUID +} + +func (self *SDisk) GetGlobalId() string { + return self.UUID +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SDisk) Delete(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDisk) GetAccessPath() string { + return self.NutanixNfsfilePath +} + +func (self *SDisk) GetCacheMode() string { + return "none" +} + +func (self *SDisk) GetFsFormat() string { + return "" +} + +func (self *SDisk) GetIsNonPersistent() bool { + return false +} + +func (self *SDisk) GetDriver() string { + if info := strings.Split(self.DiskAddress, "."); len(info) > 0 { + return info[0] + } + return "scsi" +} + +func (self *SDisk) GetDiskType() string { + if self.isSys { + return api.DISK_TYPE_SYS + } + ins, err := self.storage.zone.region.GetInstance(self.AttachedVMUUID) + if err != nil { + return api.DISK_TYPE_DATA + } + for _, disk := range ins.VMDiskInfo { + if disk.IsCdrom { + continue + } + if disk.DiskAddress.VmdiskUUID == self.UUID { + return api.DISK_TYPE_SYS + } else { + return api.DISK_TYPE_DATA + } + } + return api.DISK_TYPE_DATA +} + +func (self *SDisk) GetDiskFormat() string { + return "raw" +} + +func (self *SDisk) GetDiskSizeMB() int { + return int(self.DiskCapacityInBytes / 1024 / 1024) +} + +func (self *SDisk) GetIsAutoDelete() bool { + return true +} + +func (self *SDisk) GetMountpoint() string { + return "" +} + +func (self *SDisk) GetStatus() string { + return api.DISK_READY +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { + ins, err := self.storage.zone.region.GetInstance(self.AttachedVMUUID) + if err != nil { + return errors.Wrapf(err, "GetInstance(%s)", self.AttachedVMUUID) + } + for _, disk := range ins.VMDiskInfo { + if disk.DiskAddress.VmdiskUUID == self.UUID { + params := map[string]interface{}{ + "vm_disks": []map[string]interface{}{ + { + "disk_address": disk.DiskAddress, + "flash_mode_enabled": disk.FlashModeEnabled, + "is_cdrom": disk.IsCdrom, + "is_empty": disk.IsEmpty, + "vm_disk_create": map[string]interface{}{ + "storage_container_uuid": disk.StorageContainerUUID, + "size": sizeMb * 1024 * 1024, + }, + }, + }, + } + return self.storage.zone.region.update("vms", fmt.Sprintf("%s/disks/update", self.AttachedVMUUID), jsonutils.Marshal(params), nil) + } + } + return cloudprovider.ErrNotSupported +} + +func (self *SDisk) GetTemplateId() string { + return "" +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetDisks(storageId, vmId string) ([]SDisk, error) { + disks := []SDisk{} + params := url.Values{} + filter := []string{} + if len(storageId) > 0 { + filter = append(filter, "container_uuid=="+storageId) + } + if len(vmId) > 0 { + filter = append(filter, "vm_uuid=="+vmId) + filter = append(filter, "attach_vm_id=="+vmId) + } + if len(filter) > 0 { + params.Set("filter_criteria", strings.Join(filter, ",")) + } + return disks, self.listAll("virtual_disks", params, &disks) +} + +func (self *SRegion) GetDisk(id string) (*SDisk, error) { + disk := &SDisk{} + return disk, self.get("virtual_disks", id, url.Values{}, disk) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/doc.go new file mode 100644 index 0000000000..9c9f53633e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 nutanix // import "yunion.io/x/cloudmux/pkg/multicloud/nutanix" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/host.go new file mode 100644 index 0000000000..3fb09b57ce --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/host.go @@ -0,0 +1,512 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "strconv" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SHost struct { + multicloud.STagBase + multicloud.SHostBase + firstHost bool + + zone *SZone + + ServiceVmid string `json:"service_vmid"` + UUID string `json:"uuid"` + DiskHardwareConfigs DiskHardwareConfigs `json:"disk_hardware_configs"` + Name string `json:"name"` + ServiceVmexternalIP string `json:"service_vmexternal_ip"` + ServiceVmnatIP string `json:"service_vmnat_ip"` + ServiceVmnatPort string `json:"service_vmnat_port"` + OplogDiskPct float64 `json:"oplog_disk_pct"` + OplogDiskSize int64 `json:"oplog_disk_size"` + HypervisorKey string `json:"hypervisor_key"` + HypervisorAddress string `json:"hypervisor_address"` + HypervisorUsername string `json:"hypervisor_username"` + HypervisorPassword string `json:"hypervisor_password"` + BackplaneIP string `json:"backplane_ip"` + ControllerVMBackplaneIP string `json:"controller_vm_backplane_ip"` + RdmaBackplaneIps string `json:"rdma_backplane_ips"` + ManagementServerName string `json:"management_server_name"` + IpmiAddress string `json:"ipmi_address"` + IpmiUsername string `json:"ipmi_username"` + IpmiPassword string `json:"ipmi_password"` + Monitored bool `json:"monitored"` + Position Position `json:"position"` + Serial string `json:"serial"` + BlockSerial string `json:"block_serial"` + BlockModel string `json:"block_model"` + BlockModelName string `json:"block_model_name"` + BlockLocation string `json:"block_location"` + HostMaintenanceModeReason string `json:"host_maintenance_mode_reason"` + HypervisorState string `json:"hypervisor_state"` + AcropolisConnectionState string `json:"acropolis_connection_state"` + MetadataStoreStatus string `json:"metadata_store_status"` + MetadataStoreStatusMessage string `json:"metadata_store_status_message"` + State string `json:"state"` + DynamicRingChangingNode string `json:"dynamic_ring_changing_node"` + RemovalStatus []string `json:"removal_status"` + VzoneName string `json:"vzone_name"` + CPUModel string `json:"cpu_model"` + NumCPUCores int `json:"num_cpu_cores"` + NumCPUThreads int `json:"num_cpu_threads"` + NumCPUSockets int `json:"num_cpu_sockets"` + CPUFrequencyInHz int64 `json:"cpu_frequency_in_hz"` + CPUCapacityInHz int64 `json:"cpu_capacity_in_hz"` + MemoryCapacityInBytes int64 `json:"memory_capacity_in_bytes"` + HypervisorFullName string `json:"hypervisor_full_name"` + HypervisorType string `json:"hypervisor_type"` + NumVms int `json:"num_vms"` + BootTimeInUsecs int64 `json:"boot_time_in_usecs"` + IsDegraded bool `json:"is_degraded"` + IsSecureBooted bool `json:"is_secure_booted"` + IsHardwareVirtualized bool `json:"is_hardware_virtualized"` + FailoverClusterFqdn string `json:"failover_cluster_fqdn"` + FailoverClusterNodeState string `json:"failover_cluster_node_state"` + RebootPending bool `json:"reboot_pending"` + DefaultVMLocation string `json:"default_vm_location"` + DefaultVMStorageContainerID string `json:"default_vm_storage_container_id"` + DefaultVMStorageContainerUUID string `json:"default_vm_storage_container_uuid"` + DefaultVhdLocation string `json:"default_vhd_location"` + DefaultVhdStorageContainerID string `json:"default_vhd_storage_container_id"` + DefaultVhdStorageContainerUUID string `json:"default_vhd_storage_container_uuid"` + BiosVersion string `json:"bios_version"` + BiosModel string `json:"bios_model"` + BmcVersion string `json:"bmc_version"` + BmcModel string `json:"bmc_model"` + HbaFirmwaresList string `json:"hba_firmwares_list"` + ClusterUUID string `json:"cluster_uuid"` + Stats Stats `json:"stats"` + UsageStats UsageStats `json:"usage_stats"` + HasCsr bool `json:"has_csr"` + HostNicIds []string `json:"host_nic_ids"` + HostGpus string `json:"host_gpus"` + GpuDriverVersion string `json:"gpu_driver_version"` + HostType string `json:"host_type"` + KeyManagementDeviceToCertificateStatus KeyManagementDeviceToCertificateStatus `json:"key_management_device_to_certificate_status"` + HostInMaintenanceMode string `json:"host_in_maintenance_mode"` +} + +type Num1 struct { + SerialNumber string `json:"serial_number"` + DiskID string `json:"disk_id"` + DiskUUID string `json:"disk_uuid"` + Location int `json:"location"` + Bad bool `json:"bad"` + Mounted bool `json:"mounted"` + MountPath string `json:"mount_path"` + Model string `json:"model"` + Vendor string `json:"vendor"` + BootDisk bool `json:"boot_disk"` + OnlyBootDisk bool `json:"only_boot_disk"` + UnderDiagnosis bool `json:"under_diagnosis"` + BackgroundOperation string `json:"background_operation"` + CurrentFirmwareVersion string `json:"current_firmware_version"` + TargetFirmwareVersion string `json:"target_firmware_version"` + CanAddAsNewDisk bool `json:"can_add_as_new_disk"` + CanAddAsOldDisk bool `json:"can_add_as_old_disk"` +} +type Num2 struct { + SerialNumber string `json:"serial_number"` + DiskID string `json:"disk_id"` + DiskUUID string `json:"disk_uuid"` + Location int `json:"location"` + Bad bool `json:"bad"` + Mounted bool `json:"mounted"` + MountPath string `json:"mount_path"` + Model string `json:"model"` + Vendor string `json:"vendor"` + BootDisk bool `json:"boot_disk"` + OnlyBootDisk bool `json:"only_boot_disk"` + UnderDiagnosis bool `json:"under_diagnosis"` + BackgroundOperation string `json:"background_operation"` + CurrentFirmwareVersion string `json:"current_firmware_version"` + TargetFirmwareVersion string `json:"target_firmware_version"` + CanAddAsNewDisk bool `json:"can_add_as_new_disk"` + CanAddAsOldDisk bool `json:"can_add_as_old_disk"` +} +type DiskHardwareConfigs struct { + Num1 Num1 `json:"1"` + Num2 Num2 `json:"2"` +} +type Position struct { + Ordinal int `json:"ordinal"` + Name string `json:"name"` + PhysicalPosition string `json:"physical_position"` +} +type Stats struct { + HypervisorAvgIoLatencyUsecs string `json:"hypervisor_avg_io_latency_usecs"` + NumReadIops string `json:"num_read_iops"` + HypervisorWriteIoBandwidthKBps string `json:"hypervisor_write_io_bandwidth_kBps"` + TimespanUsecs string `json:"timespan_usecs"` + ControllerNumReadIops string `json:"controller_num_read_iops"` + ReadIoPpm string `json:"read_io_ppm"` + ControllerNumIops string `json:"controller_num_iops"` + TotalReadIoTimeUsecs string `json:"total_read_io_time_usecs"` + ControllerTotalReadIoTimeUsecs string `json:"controller_total_read_io_time_usecs"` + HypervisorNumIo string `json:"hypervisor_num_io"` + ControllerTotalTransformedUsageBytes string `json:"controller_total_transformed_usage_bytes"` + HypervisorCPUUsagePpm string `json:"hypervisor_cpu_usage_ppm"` + ControllerNumWriteIo string `json:"controller_num_write_io"` + AvgReadIoLatencyUsecs string `json:"avg_read_io_latency_usecs"` + ContentCacheLogicalSsdUsageBytes string `json:"content_cache_logical_ssd_usage_bytes"` + ControllerTotalIoTimeUsecs string `json:"controller_total_io_time_usecs"` + ControllerTotalReadIoSizeKbytes string `json:"controller_total_read_io_size_kbytes"` + ControllerNumSeqIo string `json:"controller_num_seq_io"` + ControllerReadIoPpm string `json:"controller_read_io_ppm"` + ContentCacheNumLookups string `json:"content_cache_num_lookups"` + ControllerTotalIoSizeKbytes string `json:"controller_total_io_size_kbytes"` + ContentCacheHitPpm string `json:"content_cache_hit_ppm"` + ControllerNumIo string `json:"controller_num_io"` + HypervisorAvgReadIoLatencyUsecs string `json:"hypervisor_avg_read_io_latency_usecs"` + ContentCacheNumDedupRefCountPph string `json:"content_cache_num_dedup_ref_count_pph"` + NumWriteIops string `json:"num_write_iops"` + ControllerNumRandomIo string `json:"controller_num_random_io"` + NumIops string `json:"num_iops"` + HypervisorNumReadIo string `json:"hypervisor_num_read_io"` + HypervisorTotalReadIoTimeUsecs string `json:"hypervisor_total_read_io_time_usecs"` + ControllerAvgIoLatencyUsecs string `json:"controller_avg_io_latency_usecs"` + NumIo string `json:"num_io"` + ControllerNumReadIo string `json:"controller_num_read_io"` + HypervisorNumWriteIo string `json:"hypervisor_num_write_io"` + ControllerSeqIoPpm string `json:"controller_seq_io_ppm"` + ControllerReadIoBandwidthKBps string `json:"controller_read_io_bandwidth_kBps"` + ControllerIoBandwidthKBps string `json:"controller_io_bandwidth_kBps"` + HypervisorNumReceivedBytes string `json:"hypervisor_num_received_bytes"` + HypervisorTimespanUsecs string `json:"hypervisor_timespan_usecs"` + HypervisorNumWriteIops string `json:"hypervisor_num_write_iops"` + TotalReadIoSizeKbytes string `json:"total_read_io_size_kbytes"` + HypervisorTotalIoSizeKbytes string `json:"hypervisor_total_io_size_kbytes"` + AvgIoLatencyUsecs string `json:"avg_io_latency_usecs"` + HypervisorNumReadIops string `json:"hypervisor_num_read_iops"` + ContentCacheSavedSsdUsageBytes string `json:"content_cache_saved_ssd_usage_bytes"` + ControllerWriteIoBandwidthKBps string `json:"controller_write_io_bandwidth_kBps"` + ControllerWriteIoPpm string `json:"controller_write_io_ppm"` + HypervisorAvgWriteIoLatencyUsecs string `json:"hypervisor_avg_write_io_latency_usecs"` + HypervisorNumTransmittedBytes string `json:"hypervisor_num_transmitted_bytes"` + HypervisorTotalReadIoSizeKbytes string `json:"hypervisor_total_read_io_size_kbytes"` + ReadIoBandwidthKBps string `json:"read_io_bandwidth_kBps"` + HypervisorMemoryUsagePpm string `json:"hypervisor_memory_usage_ppm"` + HypervisorNumIops string `json:"hypervisor_num_iops"` + HypervisorIoBandwidthKBps string `json:"hypervisor_io_bandwidth_kBps"` + ControllerNumWriteIops string `json:"controller_num_write_iops"` + TotalIoTimeUsecs string `json:"total_io_time_usecs"` + ContentCachePhysicalSsdUsageBytes string `json:"content_cache_physical_ssd_usage_bytes"` + ControllerRandomIoPpm string `json:"controller_random_io_ppm"` + ControllerAvgReadIoSizeKbytes string `json:"controller_avg_read_io_size_kbytes"` + TotalTransformedUsageBytes string `json:"total_transformed_usage_bytes"` + AvgWriteIoLatencyUsecs string `json:"avg_write_io_latency_usecs"` + NumReadIo string `json:"num_read_io"` + WriteIoBandwidthKBps string `json:"write_io_bandwidth_kBps"` + HypervisorReadIoBandwidthKBps string `json:"hypervisor_read_io_bandwidth_kBps"` + RandomIoPpm string `json:"random_io_ppm"` + TotalUntransformedUsageBytes string `json:"total_untransformed_usage_bytes"` + HypervisorTotalIoTimeUsecs string `json:"hypervisor_total_io_time_usecs"` + NumRandomIo string `json:"num_random_io"` + ControllerAvgWriteIoSizeKbytes string `json:"controller_avg_write_io_size_kbytes"` + ControllerAvgReadIoLatencyUsecs string `json:"controller_avg_read_io_latency_usecs"` + NumWriteIo string `json:"num_write_io"` + TotalIoSizeKbytes string `json:"total_io_size_kbytes"` + IoBandwidthKBps string `json:"io_bandwidth_kBps"` + ContentCachePhysicalMemoryUsageBytes string `json:"content_cache_physical_memory_usage_bytes"` + ControllerTimespanUsecs string `json:"controller_timespan_usecs"` + NumSeqIo string `json:"num_seq_io"` + ContentCacheSavedMemoryUsageBytes string `json:"content_cache_saved_memory_usage_bytes"` + SeqIoPpm string `json:"seq_io_ppm"` + WriteIoPpm string `json:"write_io_ppm"` + ControllerAvgWriteIoLatencyUsecs string `json:"controller_avg_write_io_latency_usecs"` + ContentCacheLogicalMemoryUsageBytes string `json:"content_cache_logical_memory_usage_bytes"` +} +type UsageStats struct { + StorageTierDasSataUsageBytes string `json:"storage_tier.das-sata.usage_bytes"` + StorageCapacityBytes string `json:"storage.capacity_bytes"` + StorageLogicalUsageBytes string `json:"storage.logical_usage_bytes"` + StorageTierDasSataCapacityBytes string `json:"storage_tier.das-sata.capacity_bytes"` + StorageFreeBytes string `json:"storage.free_bytes"` + StorageTierSsdUsageBytes string `json:"storage_tier.ssd.usage_bytes"` + StorageTierSsdCapacityBytes string `json:"storage_tier.ssd.capacity_bytes"` + StorageTierDasSataFreeBytes string `json:"storage_tier.das-sata.free_bytes"` + StorageUsageBytes string `json:"storage.usage_bytes"` + StorageTierSsdFreeBytes string `json:"storage_tier.ssd.free_bytes"` +} +type KeyManagementDeviceToCertificateStatus struct { +} + +func (self *SRegion) GetHosts() ([]SHost, error) { + hosts := []SHost{} + return hosts, self.listAll("hosts", nil, &hosts) +} + +func (self *SRegion) GetHost(id string) (*SHost, error) { + host := &SHost{} + return host, self.cli.get("hosts", id, nil, host) +} + +func (self *SHost) GetName() string { + return self.Name +} + +func (self *SHost) GetId() string { + return self.UUID +} + +func (self *SHost) GetGlobalId() string { + return self.UUID +} + +func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + image, err := self.zone.region.GetImage(opts.ExternalImageId) + if err != nil { + return nil, errors.Wrapf(err, "GetImage") + } + disks := []map[string]interface{}{ + { + "disk_address": map[string]interface{}{ + "device_bus": "ide", + "device_index": 0, + }, + "is_cdrom": true, + "is_empty": true, + }, + { + "disk_address": map[string]interface{}{ + "device_bus": "scsi", + "device_index": 0, + }, + "is_cdrom": false, + "vm_disk_clone": map[string]interface{}{ + "disk_address": map[string]string{ + "vmdisk_uuid": image.VMDiskID, + }, + "minimum_size": opts.SysDisk.SizeGB * 1024 * 1024 * 1024, + }, + }, + } + for i, disk := range opts.DataDisks { + disks = append(disks, map[string]interface{}{ + "disk_address": map[string]interface{}{ + "device_bus": "scsi", + "device_index": i + 1, + }, + "is_cdrom": false, + "vm_disk_create": map[string]interface{}{ + "size": disk.SizeGB * 1024 * 1024 * 1024, + "storage_container_uuid": disk.StorageExternalId, + }, + }) + } + nic := map[string]interface{}{ + "network_uuid": opts.ExternalVpcId, + } + if len(opts.IpAddr) > 0 { + nic["requested_ip_address"] = opts.IpAddr + } + params := map[string]interface{}{ + "boot": map[string]interface{}{ + "boot_device_order": []string{"CDROM", "DISK", "NIC"}, + "uefi_boot": false, + }, + "description": opts.Description, + "hypervisor_type": "ACROPOLIS", + "memory_mb": opts.MemoryMB, + "name": opts.Name, + "num_cores_per_vcpu": 1, + "num_vcpus": opts.Cpu, + "timezone": "UTC", + "vm_customization_config": map[string]interface{}{ + "files_to_inject_list": []string{}, + "userdata": opts.UserData, + }, + "vm_disks": disks, + "vm_features": map[string]interface{}{ + "AGENT_VM": false, + }, + "vm_nics": []map[string]interface{}{ + nic, + }, + } + ret := struct { + TaskUUID string + }{} + err = self.zone.region.post("vms", jsonutils.Marshal(params), &ret) + if err != nil { + return nil, err + } + resId, err := self.zone.region.cli.wait(ret.TaskUUID) + if err != nil { + return nil, err + } + vm, err := self.zone.region.GetInstance(resId) + if err != nil { + return nil, err + } + vm.host = self + return vm, nil +} + +func (self *SHost) GetAccessIp() string { + return self.HypervisorAddress +} + +func (self *SHost) GetAccessMac() string { + return "" +} + +func (self *SHost) GetCpuCmtbound() float32 { + return 16.0 +} + +func (self *SHost) GetMemCmtbound() float32 { + return 1.5 +} + +func (self *SHost) GetCpuCount() int { + return self.NumCPUCores * self.NumCPUSockets +} + +func (self *SHost) GetNodeCount() int8 { + return int8(self.NumCPUSockets) +} + +func (self *SHost) GetEnabled() bool { + return true +} + +func (self *SHost) GetCpuDesc() string { + return self.CPUModel +} + +func (self *SHost) GetCpuMhz() int { + return int(self.CPUCapacityInHz / 1000 / 1000) +} + +func (self *SHost) GetMemSizeMB() int { + return int(self.MemoryCapacityInBytes / 1024 / 1024) +} + +func (self *SHost) GetStorageSizeMB() int { + sizeBytes, _ := strconv.Atoi(self.UsageStats.StorageCapacityBytes) + return sizeBytes / 1024 / 1024 +} + +func (self *SHost) GetStorageType() string { + return api.DISK_TYPE_HYBRID +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_NUTANIX +} + +func (self *SHost) GetHostStatus() string { + return api.HOST_ONLINE +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return []cloudprovider.ICloudHostNetInterface{}, nil +} + +func (self *SHost) GetIsMaintenance() bool { + return false +} + +func (self *SHost) GetVersion() string { + return "" +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetSysInfo() jsonutils.JSONObject { + info := jsonutils.NewDict() + info.Add(jsonutils.NewString(CLOUD_PROVIDER_NUTANIX), "manufacture") + return info +} + +func (self *SHost) IsEmulated() bool { + return false +} + +func (self *SHost) Refresh() error { + host, err := self.zone.region.GetHost(self.UUID) + if err != nil { + return err + } + return jsonutils.Update(self, host) +} + +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) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms, err := self.zone.region.GetInstances() + if err != nil { + return nil, errors.Wrapf(err, "GetInstances") + } + ret := []cloudprovider.ICloudVM{} + for i := range vms { + if vms[i].HostUUID == self.UUID || (self.firstHost && len(vms[i].HostUUID) == 0) { + vms[i].host = self + ret = append(ret, &vms[i]) + } + } + return ret, nil +} + +func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := self.zone.region.GetInstance(id) + if err != nil { + return nil, errors.Wrapf(err, "GetInstance") + } + if len(vm.HostUUID) > 0 && vm.HostUUID != self.UUID { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "vm not locate host %s, it locate host %s", self.Name, vm.HostUUID) + } + vm.host = self + return vm, nil +} + +func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + vpcs, err := self.zone.region.GetIVpcs() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudWire{} + for i := range vpcs { + wires, err := vpcs[i].GetIWires() + if err != nil { + return nil, errors.Wrapf(err, "GetIWires") + } + ret = append(ret, wires...) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/image.go new file mode 100644 index 0000000000..e63420686f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/image.go @@ -0,0 +1,249 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type SImage struct { + multicloud.STagBase + multicloud.SImageBase + + cache *SStoragecache + + imageInfo *imagetools.ImageInfo + + UUID string `json:"uuid"` + Name string `json:"name"` + Deleted bool `json:"deleted"` + StorageContainerID int `json:"storage_container_id"` + StorageContainerUUID string `json:"storage_container_uuid"` + LogicalTimestamp int `json:"logical_timestamp"` + ImageType string `json:"image_type"` + VMDiskID string `json:"vm_disk_id"` + ImageState string `json:"image_state"` + CreatedTimeInUsecs int64 `json:"created_time_in_usecs"` + UpdatedTimeInUsecs int64 `json:"updated_time_in_usecs"` + VMDiskSize int64 `json:"vm_disk_size"` +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (self *SImage) GetId() string { + return self.UUID +} + +func (self *SImage) GetGlobalId() string { + return self.UUID +} + +func (self *SImage) Refresh() error { + image, err := self.cache.region.GetImage(self.GetGlobalId()) + if err != nil { + return err + } + return jsonutils.Update(self, image) +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.cache +} + +func (self *SImage) GetImageFormat() string { + if self.ImageType == "ISO_IMAGE" { + return "iso" + } + return "raw" +} + +func (self *SImage) GetStatus() string { + switch self.ImageState { + case "ACTIVE": + return api.CACHED_IMAGE_STATUS_ACTIVE + case "INACTIVE": + return api.CACHED_IMAGE_STATUS_SAVING + } + return self.ImageState +} + +func (self *SImage) GetImageStatus() string { + switch self.ImageState { + case "ACTIVE": + return cloudprovider.IMAGE_STATUS_ACTIVE + case "INACTIVE": + return cloudprovider.IMAGE_STATUS_QUEUED + } + return cloudprovider.IMAGE_STATUS_KILLED +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + return cloudprovider.ImageTypeSystem +} + +func (self *SImage) GetCreatedAt() time.Time { + return time.Unix(self.CreatedTimeInUsecs/1000, self.CreatedTimeInUsecs%1000) +} + +func (self *SImage) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return int(self.VMDiskSize / 1024 / 1024 / 1024) +} + +func (self *SImage) GetSizeByte() int64 { + return self.VMDiskSize +} + +func (img *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if img.imageInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(img.Name, "", "", "", "") + img.imageInfo = &imgInfo + } + return img.imageInfo +} + +func (img *SImage) GetFullOsName() string { + return img.Name +} + +func (ins *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(ins.getNormalizedImageInfo().OsType) +} + +func (ins *SImage) GetOsDist() string { + return ins.getNormalizedImageInfo().OsDistro +} + +func (ins *SImage) GetOsVersion() string { + return ins.getNormalizedImageInfo().OsVersion +} + +func (ins *SImage) GetOsLang() string { + return ins.getNormalizedImageInfo().OsLang +} + +func (ins *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(ins.getNormalizedImageInfo().OsBios) +} + +func (ins *SImage) GetOsArch() string { + return ins.getNormalizedImageInfo().OsArch +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SRegion) GetImages() ([]SImage, error) { + images := []SImage{} + params := url.Values{} + params.Set("include_vm_disk_sizes", "true") + params.Set("include_vm_disk_paths", "true") + return images, self.listAll("images", nil, &images) +} + +func (self *SRegion) GetImage(id string) (*SImage, error) { + image := &SImage{} + params := url.Values{} + params.Set("include_vm_disk_sizes", "true") + params.Set("include_vm_disk_paths", "true") + return image, self.get("images", id, params, image) +} + +func (self *SRegion) CreateImage(storageId string, opts *cloudprovider.SImageCreateOption, sizeBytes int64, body io.Reader, callback func(float32)) (*SImage, error) { + params := map[string]interface{}{ + "image_type": "DISK_IMAGE", + "name": opts.ImageName, + "annotation": opts.OsDistribution, + } + ret := struct { + TaskUUID string + }{} + err := self.post("images", jsonutils.Marshal(params), &ret) + if err != nil { + return nil, errors.Wrapf(err, "create image") + } + imageId := "" + err = cloudprovider.Wait(time.Second*5, time.Minute*3, func() (bool, error) { + task, err := self.GetTask(ret.TaskUUID) + if err != nil { + return false, err + } + for _, entity := range task.EntityList { + imageId = entity.EntityID + } + log.Debugf("task %s %s status: %s", task.OperationType, task.UUID, task.ProgressStatus) + if task.ProgressStatus == "Succeeded" { + for _, entity := range task.EntityList { + imageId = entity.EntityID + } + return true, nil + } + return false, nil + }) + if err != nil { + return nil, err + } + header := http.Header{} + header.Set("X-Nutanix-Destination-Container", storageId) + header.Set("Content-Type", "application/octet-stream") + header.Set("Content-Length", fmt.Sprintf("%d", sizeBytes)) + reader := multicloud.NewProgress(sizeBytes, 90, body, callback) + resp, err := self.upload("images", fmt.Sprintf("%s/upload", imageId), header, reader) + if err != nil { + return nil, errors.Wrapf(err, "upload") + } + resp.Unmarshal(&ret) + err = cloudprovider.Wait(time.Second*10, time.Hour*2, func() (bool, error) { + task, err := self.GetTask(ret.TaskUUID) + if err != nil { + return false, err + } + if callback != nil { + callback(90 + float32(task.PercentageComplete)*0.1) + } + log.Debugf("task %s %s status: %s", task.OperationType, task.UUID, task.ProgressStatus) + if task.ProgressStatus == "Succeeded" { + for _, entity := range task.EntityList { + imageId = entity.EntityID + } + return true, nil + } + return false, nil + }) + if err != nil { + return nil, errors.Wrapf(err, "wait image ready") + } + return self.GetImage(imageId) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/instance.go new file mode 100644 index 0000000000..743dcbb2e8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/instance.go @@ -0,0 +1,422 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "context" + "fmt" + "net/url" + "sort" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/apis" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type Boot struct { + UefiBoot bool `json:"uefi_boot"` +} + +type VMFeatures struct { + VGACONSOLE bool `json:"VGA_CONSOLE"` + AGENTVM bool `json:"AGENT_VM"` +} + +type DiskAddress struct { + DeviceBus string `json:"device_bus"` + DeviceIndex int `json:"device_index"` + DiskLabel string `json:"disk_label"` + NdfsFilepath string `json:"ndfs_filepath"` + VmdiskUUID string `json:"vmdisk_uuid"` + DeviceUUID string `json:"device_uuid"` +} + +type VMDiskInfo struct { + IsCdrom bool `json:"is_cdrom"` + IsEmpty bool `json:"is_empty"` + FlashModeEnabled bool `json:"flash_mode_enabled"` + IsScsiPassthrough bool `json:"is_scsi_passthrough"` + IsHotRemoveEnabled bool `json:"is_hot_remove_enabled"` + IsThinProvisioned bool `json:"is_thin_provisioned"` + Shared bool `json:"shared"` + SourceDiskAddress SourceDiskAddress `json:"source_disk_address,omitempty"` + StorageContainerUUID string `json:"storage_container_uuid,omitempty"` + Size int64 `json:"size,omitempty"` + DataSourceURL string `json:"data_source_url"` + DiskAddress DiskAddress `json:"disk_address,omitempty"` +} + +type SourceDiskAddress struct { + VmdiskUUID string `json:"vmdisk_uuid"` +} + +type VMNics struct { + MacAddress string `json:"mac_address"` + NetworkUUID string `json:"network_uuid"` + NicUUID string `json:"nic_uuid"` + Model string `json:"model"` + VlanMode string `json:"vlan_mode"` + IsConnected bool `json:"is_connected"` +} + +type SInstance struct { + multicloud.STagBase + multicloud.SInstanceBase + + host *SHost + + AllowLiveMigrate bool `json:"allow_live_migrate"` + GpusAssigned bool `json:"gpus_assigned"` + Boot Boot `json:"boot"` + HaPriority int `json:"ha_priority"` + HostUUID string `json:"host_uuid"` + MemoryMb int `json:"memory_mb"` + Name string `json:"name"` + NumCoresPerVcpu int `json:"num_cores_per_vcpu"` + NumVcpus int `json:"num_vcpus"` + PowerState string `json:"power_state"` + Timezone string `json:"timezone"` + UUID string `json:"uuid"` + VMFeatures VMFeatures `json:"vm_features"` + VMLogicalTimestamp int `json:"vm_logical_timestamp"` + MachineType string `json:"machine_type"` + + VMDiskInfo []VMDiskInfo `json:"vm_disk_info"` + VMNics []VMNics `json:"vm_nics"` +} + +func (self *SRegion) GetInstances() ([]SInstance, error) { + vms := []SInstance{} + params := url.Values{} + params.Set("include_vm_disk_config", "true") + params.Set("include_vm_nic_config", "true") + return vms, self.listAll("vms", params, &vms) +} + +func (self *SRegion) GetInstance(id string) (*SInstance, error) { + vm := &SInstance{} + params := url.Values{} + params.Set("include_vm_disk_config", "true") + params.Set("include_vm_nic_config", "true") + return vm, self.get("vms", id, params, vm) +} + +func (self *SInstance) GetName() string { + return self.Name +} + +func (self *SInstance) GetId() string { + return self.UUID +} + +func (self *SInstance) GetGlobalId() string { + return self.UUID +} + +func (self *SInstance) Refresh() error { + ins, err := self.host.zone.region.GetInstance(self.UUID) + if err != nil { + return err + } + return jsonutils.Update(self, ins) +} + +func (self *SInstance) AssignSecurityGroup(id string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) { + driver := opts.Driver + if !utils.IsInStringArray(driver, []string{"ide", "scsi", "pci", "sata"}) { + driver = "scsi" + } + idx, ids := -1, []int{} + for _, disk := range self.VMDiskInfo { + if disk.DiskAddress.DeviceBus == driver { + ids = append(ids, disk.DiskAddress.DeviceIndex) + } + } + sort.Ints(ids) + for _, id := range ids { + if id == idx+1 { + idx = id + } + } + params := map[string]interface{}{ + "vm_disks": []map[string]interface{}{ + { + "is_cdrom": false, + "disk_address": map[string]interface{}{ + "device_bus": driver, + "device_index": idx + 1, + }, + "vm_disk_create": map[string]interface{}{ + "storage_container_uuid": opts.StorageId, + "size": opts.SizeMb * 1024 * 1024, + }, + }, + }, + } + ret := struct { + TaskUUID string + }{} + res := fmt.Sprintf("vms/%s/disks/attach", self.UUID) + err := self.host.zone.region.post(res, jsonutils.Marshal(params), &ret) + if err != nil { + return "", err + } + return self.host.zone.region.cli.wait(ret.TaskUUID) +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error { + params := map[string]interface{}{ + "memory_mb": opts.MemoryMB, + "num_cores_per_vcpu": self.NumCoresPerVcpu, + "num_vcpus": opts.Cpu / self.NumCoresPerVcpu, + } + return self.host.zone.region.update("vms", self.UUID, jsonutils.Marshal(params), nil) +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + return self.host.zone.region.DeleteVM(self.UUID) +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) GetBios() cloudprovider.TBiosType { + if self.Boot.UefiBoot { + return cloudprovider.UEFI + } + return cloudprovider.BIOS +} + +func (self *SInstance) GetBootOrder() string { + return "dcn" +} + +func (self *SInstance) GetError() error { + return nil +} + +func (self *SInstance) GetHostname() string { + return self.Name +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_NUTANIX +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := self.host.zone.region.GetDisks("", self.GetGlobalId()) + if err != nil { + return nil, errors.Wrapf(err, "GetInstanceDisks") + } + cdroms := []string{} + for _, disk := range self.VMDiskInfo { + if disk.IsCdrom && len(disk.DiskAddress.VmdiskUUID) > 0 { + cdroms = append(cdroms, disk.DiskAddress.VmdiskUUID) + } + } + isSys := true + ret := []cloudprovider.ICloudDisk{} + for i := range disks { + if utils.IsInStringArray(disks[i].UUID, cdroms) { // skip cdrom disk + continue + } + storage, err := self.host.zone.GetIStorageById(disks[i].StorageContainerUUID) + if err != nil { + log.Errorf("can not found disk %s storage %s", disks[i].DiskAddress, disks[i].StorageContainerUUID) + continue + } + disks[i].isSys = isSys + disks[i].storage = storage.(*SStorage) + isSys = false + ret = append(ret, &disks[i]) + } + return ret, nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics, err := self.host.zone.region.GetInstanceNics(self.GetGlobalId()) + if err != nil { + return nil, errors.Wrapf(err, "GetInstanceNics") + } + ret := []cloudprovider.ICloudNic{} + for i := range nics { + nics[i].ins = self + ret = append(ret, &nics[i]) + } + return ret, nil +} + +func (self *SInstance) GetInstanceType() string { + return fmt.Sprintf("ecs.g1.c%dm%d", self.GetVcpuCount(), self.GetVmemSizeMB()/1024) +} + +func (self *SInstance) GetMachine() string { + return self.MachineType +} + +// "UNKNOWN", "OFF", "POWERING_ON", "ON", "SHUTTING_DOWN", "POWERING_OFF", "PAUSING", "PAUSED", "SUSPENDING", "SUSPENDED", "RESUMING", "RESETTING", "MIGRATING" +func (self *SInstance) GetStatus() string { + switch strings.ToUpper(self.PowerState) { + case "OFF": + return api.VM_READY + case "POWERING_ON": + return api.VM_START_START + case "ON": + return api.VM_RUNNING + case "SHUTTING_DOWN": + return api.VM_START_STOP + case "POWERING_OFF": + return api.VM_START_STOP + case "PAUSING", "PAUSED": + return api.VM_READY + case "SUSPENDING", "SUSPENDED": + return api.VM_SUSPEND + case "RESUMING": + return api.VM_RESUMING + case "RESETTING": + return api.VM_RUNNING + case "MIGRATING": + return api.VM_MIGRATING + } + return api.VM_UNKNOWN +} + +func (self *SInstance) GetFullOsName() string { + return "" +} + +func (self *SInstance) GetOsType() cloudprovider.TOsType { + if strings.Contains(strings.ToLower(self.Name), "win") { + return cloudprovider.OsTypeWindows + } + return cloudprovider.OsTypeLinux +} + +func (ins *SInstance) GetOsDist() string { + return "" +} + +func (ins *SInstance) GetOsVersion() string { + return "" +} + +func (ins *SInstance) GetOsLang() string { + return "" +} + +func (ins *SInstance) GetOsArch() string { + return apis.OS_ARCH_X86_64 +} + +func (self *SInstance) GetProjectId() string { + return "" +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + return []string{}, nil +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SInstance) GetVcpuCount() int { + return self.NumCoresPerVcpu * self.NumVcpus +} + +func (self *SInstance) GetVmemSizeMB() int { + return self.MemoryMb +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) StartVM(ctx context.Context) error { + return self.host.zone.region.SetInstancePowerState(self.UUID, "on") +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + act := "acpi_shutdown" + if opts.IsForce { + act = "off" + } + return self.host.zone.region.SetInstancePowerState(self.UUID, act) +} + +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) SetInstancePowerState(id string, state string) error { + res := fmt.Sprintf("vms/%s/set_power_state", id) + ret := struct { + TaskUUID string + }{} + err := self.post(res, jsonutils.Marshal(map[string]string{"transition": state}), &ret) + if err != nil { + return err + } + _, err = self.cli.wait(ret.TaskUUID) + return err +} + +func (self *SRegion) DeleteVM(id string) error { + return self.delete("vms", id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/instancenic.go new file mode 100644 index 0000000000..db3408ea51 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/instancenic.go @@ -0,0 +1,106 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "fmt" + "net/url" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + cloudprovider.DummyICloudNic + ins *SInstance + + MacAddress string `json:"mac_address"` + NetworkUUID string `json:"network_uuid"` + NicUUID string `json:"nic_uuid"` + Model string `json:"model"` + IPAddress string `json:"ip_address"` + IPAddresses []string `json:"ip_addresses"` + VlanMode string `json:"vlan_mode"` + IsConnected bool `json:"is_connected"` +} + +func (self *SInstanceNic) GetId() string { + return self.NicUUID +} + +func (self *SInstanceNic) GetIP() string { + return self.IPAddress +} + +func (self *SInstanceNic) GetMAC() string { + return self.MacAddress +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) GetSubAddress() ([]string, error) { + ret := []string{} + for _, addr := range self.IPAddresses { + if addr != self.IPAddress { + ret = append(ret, addr) + } + } + return ret, nil +} + +func (self *SInstanceNic) GetINetworkId() string { + if len(self.IPAddress) == 0 { + return self.NetworkUUID + } + vpc, err := self.ins.host.zone.region.GetVpc(self.NetworkUUID) + if err != nil { + return self.NetworkUUID + } + wires, err := vpc.GetIWires() + if err != nil { + return self.NetworkUUID + } + for i := range wires { + networks, err := wires[i].GetINetworks() + if err != nil { + continue + } + for j := range networks { + network := networks[j].(*SNetwork) + if network.Contains(self.IPAddress) { + return network.GetGlobalId() + } + } + } + return self.NetworkUUID +} + +func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetInstanceNics(id string) ([]SInstanceNic, error) { + nics := []SInstanceNic{} + res := fmt.Sprintf("vms/%s/nics", id) + params := url.Values{} + params.Set("include_address_assignments", "true") + _, err := self.list(res, params, &nics) + return nics, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/network.go new file mode 100644 index 0000000000..2ecdc52656 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/network.go @@ -0,0 +1,183 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + multicloud.STagBase + wire *SWire + + Range string +} + +func (self *SNetwork) GetName() string { + if len(self.Range) > 0 { + return self.Range + } + return self.wire.GetName() +} + +func (self *SNetwork) GetId() string { + if len(self.Range) > 0 { + return self.Range + } + return self.wire.GetId() +} + +func (self *SNetwork) GetGlobalId() string { + if len(self.Range) > 0 { + return self.Range + } + return self.wire.GetGlobalId() +} + +func (self *SNetwork) IsEmulated() bool { + return len(self.Range) == 0 +} + +func (self *SNetwork) Refresh() error { + vpc, err := self.wire.vpc.region.GetVpc(self.wire.vpc.GetGlobalId()) + if err != nil { + return err + } + for _, pool := range vpc.IPConfig.Pool { + if pool.Range == self.Range { + return nil + } + } + return cloudprovider.ErrNotFound +} + +func (self *SNetwork) Delete() error { + if len(self.Range) == 0 { + return nil + } + return self.wire.vpc.region.DeleteNetwork(self.wire.vpc.UUID, self.Range) +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (self *SNetwork) GetGateway() string { + return self.wire.vpc.IPConfig.DefaultGateway +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpStart() string { + if info := strings.Split(self.Range, " "); len(info) == 2 { + return info[0] + } + cidr := self.wire.vpc.GetCidrBlock() + if len(cidr) == 0 { + cidr = "0.0.0.0/0" + } + _range, _ := netutils.NewIPV4Prefix(cidr) + return _range.ToIPRange().StartIp().StepUp().String() +} + +func (self *SNetwork) GetIpEnd() string { + if info := strings.Split(self.Range, " "); len(info) == 2 { + return info[1] + } + cidr := self.wire.vpc.GetCidrBlock() + if len(cidr) == 0 { + cidr = "0.0.0.0/0" + } + _range, _ := netutils.NewIPV4Prefix(cidr) + return _range.ToIPRange().EndIp().StepDown().String() +} + +func (self *SNetwork) Contains(_ip string) bool { + start, _ := netutils.NewIPV4Addr(self.GetIpStart()) + end, _ := netutils.NewIPV4Addr(self.GetIpEnd()) + ip, _ := netutils.NewIPV4Addr(_ip) + return netutils.NewIPV4AddrRange(start, end).Contains(ip) +} + +func (self *SNetwork) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(self.wire.vpc.GetCidrBlock()) + return pref.MaskLen +} + +func (self *SNetwork) GetProjectId() string { + return "" +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetStatus() string { + return api.NETWORK_STATUS_AVAILABLE +} + +func (self *SRegion) CreateNetwork(vpcId string, opts *cloudprovider.SNetworkCreateOptions) (*SNetwork, error) { + vpc, err := self.GetVpc(vpcId) + if err != nil { + return nil, errors.Wrapf(err, "GetVpc") + } + cidr, _ := netutils.NewIPV4Prefix(opts.Cidr) + _range := fmt.Sprintf("%s %s", cidr.ToIPRange().StartIp().StepUp(), cidr.ToIPRange().EndIp().StepDown()) + pool := SPool{Range: _range} + vpc.IPConfig.Pool = append(vpc.IPConfig.Pool, pool) + err = self.update("networks", vpcId, jsonutils.Marshal(vpc), nil) + if err != nil { + return nil, err + } + wire := vpc.getWire() + return &SNetwork{wire: wire, Range: _range}, nil +} + +func (self *SRegion) DeleteNetwork(vpcId string, _range string) error { + vpc, err := self.GetVpc(vpcId) + if err != nil { + return err + } + pools, find := []SPool{}, false + for i := range vpc.IPConfig.Pool { + if vpc.IPConfig.Pool[i].Range == _range { + find = true + continue + } + pools = append(pools, vpc.IPConfig.Pool[i]) + } + if !find { + return nil + } + vpc.IPConfig.Pool = pools + return self.update("networks", vpcId, jsonutils.Marshal(vpc), nil) +} diff --git a/pkg/multicloud/nutanix/nutanix.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/nutanix.go similarity index 99% rename from pkg/multicloud/nutanix/nutanix.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/nutanix.go index 2dc1b24b27..c6a99a0a59 100644 --- a/pkg/multicloud/nutanix/nutanix.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/nutanix.go @@ -26,8 +26,8 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider/doc.go new file mode 100644 index 0000000000..e2c1e02d7d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider/provider.go new file mode 100644 index 0000000000..512aed8371 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/provider/provider.go @@ -0,0 +1,201 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "fmt" + "net/url" + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/regutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/nutanix" +) + +type SNutanixProviderFactory struct { + cloudprovider.SPrivateCloudBaseProviderFactory +} + +func (self *SNutanixProviderFactory) GetId() string { + return nutanix.CLOUD_PROVIDER_NUTANIX +} + +func (self *SNutanixProviderFactory) GetName() string { + return nutanix.CLOUD_PROVIDER_NUTANIX +} + +func (self *SNutanixProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { + return fmt.Errorf("Changing %s bandwidth is not supported", nutanix.CLOUD_PROVIDER_NUTANIX) +} + +func (self *SNutanixProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.Username) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "username") + } + if len(input.Password) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "password") + } + if len(input.Host) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "host") + } + if !regutils.MatchIPAddr(input.Host) && !regutils.MatchDomainName(input.Host) { + return output, errors.Wrap(httperrors.ErrInputParameter, "host should be ip or domain name") + } + if input.Port == 0 { + input.Port = 9440 + } + output.AccessUrl = fmt.Sprintf("https://%s:%d", input.Host, input.Port) + output.Account = input.Username + output.Secret = input.Password + return output, nil +} + +func (self *SNutanixProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.Username) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "username") + } + if len(input.Password) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "password") + } + output = cloudprovider.SCloudaccount{ + Account: input.Username, + Secret: input.Password, + } + return output, nil +} + +func parseHostPort(_url string) (string, int, error) { + urlParse, err := url.Parse(_url) + if err != nil { + return "", 0, errors.Wrapf(err, "parse %s", _url) + } + port := func() int { + if len(urlParse.Port()) > 0 { + _port, _ := strconv.Atoi(urlParse.Port()) + return _port + } + return 9440 + }() + return strings.TrimSuffix(urlParse.Host, fmt.Sprintf(":%d", port)), port, nil +} + +func (self *SNutanixProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + host, port, err := parseHostPort(cfg.URL) + if err != nil { + return nil, errors.Wrapf(err, "parseHostPort") + } + + client, err := nutanix.NewNutanixClient( + nutanix.NewNutanixClientConfig( + host, cfg.Account, cfg.Secret, port, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SNutanixProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SNutanixProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + host, port, err := parseHostPort(info.Url) + if err != nil { + return nil, err + } + + return map[string]string{ + "NUTANIX_HOST": host, + "NUTANIX_PORT": fmt.Sprintf("%d", port), + "NUTANIX_USERNAME": info.Account, + "NUTANIX_PASSWORD": info.Secret, + }, nil +} + +func init() { + factory := SNutanixProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SNutanixProvider struct { + cloudprovider.SBaseProvider + client *nutanix.SNutanixClient +} + +func (self *SNutanixProvider) GetSysInfo() (jsonutils.JSONObject, error) { + return jsonutils.NewDict(), nil +} + +func (self *SNutanixProvider) GetVersion() string { + return nutanix.NUTANIX_VERSION_V2 +} + +func (self *SNutanixProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SNutanixProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SNutanixProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SNutanixProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + regions := self.GetIRegions() + for i := range regions { + if regions[i].GetGlobalId() == id { + return regions[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SNutanixProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SNutanixProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return []cloudprovider.ICloudProject{}, nil + //return self.client.GetIProjects() +} + +func (self *SNutanixProvider) GetStorageClasses(regionId string) []string { + return nil +} + +func (self *SNutanixProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (self *SNutanixProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (self *SNutanixProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/region.go new file mode 100644 index 0000000000..65cb9f5b9b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/region.go @@ -0,0 +1,222 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "fmt" + "io" + "net/http" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + multicloud.SRegion + multicloud.SNoObjectStorageRegion + multicloud.SNoLbRegion + + cli *SNutanixClient +} + +func (self *SRegion) GetId() string { + return self.cli.cpcfg.Id +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", api.CLOUD_PROVIDER_NUTANIX, self.cli.cpcfg.Id) +} + +func (self *SRegion) GetName() string { + return self.cli.cpcfg.Name +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) + return table +} + +func (self *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + return self.CreateVpc(opts) +} + +func (self *SRegion) GetCapabilities() []string { + return self.cli.GetCapabilities() +} + +func (self *SRegion) GetCloudEnv() string { + return "" +} + +func (self *SRegion) GetProvider() string { + return api.CLOUD_PROVIDER_NUTANIX +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + return []cloudprovider.ICloudEIP{}, nil +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + vpc, err := self.GetVpc(id) + if err != nil { + return nil, errors.Wrapf(err, "GetVpc(%s)", id) + } + return vpc, nil +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + vpcs, err := self.GetVpcs() + if err != nil { + return nil, errors.Wrapf(err, "GetVpcs") + } + ret := []cloudprovider.ICloudVpc{} + for i := range vpcs { + vpcs[i].region = self + ret = append(ret, &vpcs[i]) + } + return ret, nil +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + clusters, err := self.GetClusters() + if err != nil { + return nil, errors.Wrapf(err, "GetClusters") + } + ret := []cloudprovider.ICloudZone{} + for i := range clusters { + ret = append(ret, &SZone{ + SCluster: clusters[i], + region: self, + }) + } + return ret, nil +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + zones, err := self.GetIZones() + if err != nil { + return nil, errors.Wrapf(err, "GetIZones") + } + for i := range zones { + if zones[i].GetGlobalId() == id { + return zones[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + zones, err := self.GetIZones() + if err != nil { + return nil, errors.Wrapf(err, "GetIZones") + } + ret := []cloudprovider.ICloudHost{} + for i := range zones { + part, err := zones[i].GetIHosts() + if err != nil { + return nil, errors.Wrapf(err, "GetIHost") + } + ret = append(ret, part...) + } + return ret, nil +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := self.GetInstance(id) + if err != nil { + return nil, err + } + return vm, nil +} + +func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + hosts, err := self.GetIHosts() + if err != nil { + return nil, errors.Wrapf(err, "GetIHosts") + } + for i := range hosts { + if hosts[i].GetGlobalId() == id { + return hosts[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) list(res string, params url.Values, retVal interface{}) (int, error) { + return self.cli.list(res, params, retVal) +} + +func (self *SRegion) get(res, id string, params url.Values, retVal interface{}) error { + return self.cli.get(res, id, params, retVal) +} + +func (self *SRegion) listAll(res string, params url.Values, retVal interface{}) error { + return self.cli.listAll(res, params, retVal) +} + +func (self *SRegion) post(res string, body jsonutils.JSONObject, retVal interface{}) error { + return self.cli.post(res, body, retVal) +} + +func (self *SRegion) delete(res string, id string) error { + return self.cli.delete(res, id) +} + +func (self *SRegion) update(res string, id string, body jsonutils.JSONObject, retVal interface{}) error { + return self.cli.update(res, id, body, retVal) +} + +func (self *SRegion) upload(res string, id string, header http.Header, body io.Reader) (jsonutils.JSONObject, error) { + return self.cli.upload(res, id, header, body) +} + +func (self *SRegion) getTask(id string) (*STask, error) { + task := &STask{} + return task, self.get("tasks", id, nil, task) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/storage.go new file mode 100644 index 0000000000..7b5527265d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/storage.go @@ -0,0 +1,332 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type DownMigrateTimesInSecs struct { + SSDSATA int `json:"SSD-SATA"` + SSDPCIe int `json:"SSD-PCIe"` + DASSATA int `json:"DAS-SATA"` +} + +type MappedRemoteContainers struct { +} + +type StorageStats struct { + HypervisorAvgIoLatencyUsecs string `json:"hypervisor_avg_io_latency_usecs"` + NumReadIops string `json:"num_read_iops"` + HypervisorWriteIoBandwidthKBps string `json:"hypervisor_write_io_bandwidth_kBps"` + TimespanUsecs string `json:"timespan_usecs"` + ControllerNumReadIops string `json:"controller_num_read_iops"` + ReadIoPpm string `json:"read_io_ppm"` + ControllerNumIops string `json:"controller_num_iops"` + TotalReadIoTimeUsecs string `json:"total_read_io_time_usecs"` + ControllerTotalReadIoTimeUsecs string `json:"controller_total_read_io_time_usecs"` + HypervisorNumIo string `json:"hypervisor_num_io"` + ControllerTotalTransformedUsageBytes string `json:"controller_total_transformed_usage_bytes"` + ControllerNumWriteIo string `json:"controller_num_write_io"` + AvgReadIoLatencyUsecs string `json:"avg_read_io_latency_usecs"` + ControllerTotalIoTimeUsecs string `json:"controller_total_io_time_usecs"` + ControllerTotalReadIoSizeKbytes string `json:"controller_total_read_io_size_kbytes"` + ControllerNumSeqIo string `json:"controller_num_seq_io"` + ControllerReadIoPpm string `json:"controller_read_io_ppm"` + ControllerTotalIoSizeKbytes string `json:"controller_total_io_size_kbytes"` + ControllerNumIo string `json:"controller_num_io"` + HypervisorAvgReadIoLatencyUsecs string `json:"hypervisor_avg_read_io_latency_usecs"` + NumWriteIops string `json:"num_write_iops"` + ControllerNumRandomIo string `json:"controller_num_random_io"` + NumIops string `json:"num_iops"` + HypervisorNumReadIo string `json:"hypervisor_num_read_io"` + HypervisorTotalReadIoTimeUsecs string `json:"hypervisor_total_read_io_time_usecs"` + ControllerAvgIoLatencyUsecs string `json:"controller_avg_io_latency_usecs"` + NumIo string `json:"num_io"` + ControllerNumReadIo string `json:"controller_num_read_io"` + HypervisorNumWriteIo string `json:"hypervisor_num_write_io"` + ControllerSeqIoPpm string `json:"controller_seq_io_ppm"` + ControllerReadIoBandwidthKBps string `json:"controller_read_io_bandwidth_kBps"` + ControllerIoBandwidthKBps string `json:"controller_io_bandwidth_kBps"` + HypervisorTimespanUsecs string `json:"hypervisor_timespan_usecs"` + HypervisorNumWriteIops string `json:"hypervisor_num_write_iops"` + TotalReadIoSizeKbytes string `json:"total_read_io_size_kbytes"` + HypervisorTotalIoSizeKbytes string `json:"hypervisor_total_io_size_kbytes"` + AvgIoLatencyUsecs string `json:"avg_io_latency_usecs"` + HypervisorNumReadIops string `json:"hypervisor_num_read_iops"` + ControllerWriteIoBandwidthKBps string `json:"controller_write_io_bandwidth_kBps"` + ControllerWriteIoPpm string `json:"controller_write_io_ppm"` + HypervisorAvgWriteIoLatencyUsecs string `json:"hypervisor_avg_write_io_latency_usecs"` + HypervisorTotalReadIoSizeKbytes string `json:"hypervisor_total_read_io_size_kbytes"` + ReadIoBandwidthKBps string `json:"read_io_bandwidth_kBps"` + HypervisorNumIops string `json:"hypervisor_num_iops"` + HypervisorIoBandwidthKBps string `json:"hypervisor_io_bandwidth_kBps"` + ControllerNumWriteIops string `json:"controller_num_write_iops"` + TotalIoTimeUsecs string `json:"total_io_time_usecs"` + ControllerRandomIoPpm string `json:"controller_random_io_ppm"` + ControllerAvgReadIoSizeKbytes string `json:"controller_avg_read_io_size_kbytes"` + TotalTransformedUsageBytes string `json:"total_transformed_usage_bytes"` + AvgWriteIoLatencyUsecs string `json:"avg_write_io_latency_usecs"` + NumReadIo string `json:"num_read_io"` + WriteIoBandwidthKBps string `json:"write_io_bandwidth_kBps"` + HypervisorReadIoBandwidthKBps string `json:"hypervisor_read_io_bandwidth_kBps"` + RandomIoPpm string `json:"random_io_ppm"` + TotalUntransformedUsageBytes string `json:"total_untransformed_usage_bytes"` + HypervisorTotalIoTimeUsecs string `json:"hypervisor_total_io_time_usecs"` + NumRandomIo string `json:"num_random_io"` + ControllerAvgWriteIoSizeKbytes string `json:"controller_avg_write_io_size_kbytes"` + ControllerAvgReadIoLatencyUsecs string `json:"controller_avg_read_io_latency_usecs"` + NumWriteIo string `json:"num_write_io"` + TotalIoSizeKbytes string `json:"total_io_size_kbytes"` + IoBandwidthKBps string `json:"io_bandwidth_kBps"` + ControllerTimespanUsecs string `json:"controller_timespan_usecs"` + NumSeqIo string `json:"num_seq_io"` + SeqIoPpm string `json:"seq_io_ppm"` + WriteIoPpm string `json:"write_io_ppm"` + ControllerAvgWriteIoLatencyUsecs string `json:"controller_avg_write_io_latency_usecs"` +} +type StorageUsageStats struct { + StorageUserUnreservedOwnUsageBytes string `json:"storage.user_unreserved_own_usage_bytes"` + StorageReservedFreeBytes string `json:"storage.reserved_free_bytes"` + DataReductionOverallSavingRatioPpm string `json:"data_reduction.overall.saving_ratio_ppm"` + DataReductionUserSavedBytes string `json:"data_reduction.user_saved_bytes"` + StorageTierDasSataUsageBytes string `json:"storage_tier.das-sata.usage_bytes"` + DataReductionErasureCodingPostReductionBytes string `json:"data_reduction.erasure_coding.post_reduction_bytes"` + StorageReservedUsageBytes string `json:"storage.reserved_usage_bytes"` + StorageUserUnreservedSharedUsageBytes string `json:"storage.user_unreserved_shared_usage_bytes"` + StorageUserUnreservedUsageBytes int64 `json:"storage.user_unreserved_usage_bytes"` + StorageUsageBytes string `json:"storage.usage_bytes"` + DataReductionCompressionUserSavedBytes string `json:"data_reduction.compression.user_saved_bytes"` + DataReductionErasureCodingUserPreReductionBytes string `json:"data_reduction.erasure_coding.user_pre_reduction_bytes"` + StorageUserUnreservedCapacityBytes string `json:"storage.user_unreserved_capacity_bytes"` + StorageUserCapacityBytes int64 `json:"storage.user_capacity_bytes"` + StorageUserStoragePoolCapacityBytes string `json:"storage.user_storage_pool_capacity_bytes"` + DataReductionPreReductionBytes string `json:"data_reduction.pre_reduction_bytes"` + DataReductionUserPreReductionBytes string `json:"data_reduction.user_pre_reduction_bytes"` + StorageUserOtherContainersReservedCapacityBytes string `json:"storage.user_other_containers_reserved_capacity_bytes"` + DataReductionErasureCodingPreReductionBytes string `json:"data_reduction.erasure_coding.pre_reduction_bytes"` + StorageCapacityBytes int64 `json:"storage.capacity_bytes"` + StorageUserUnreservedFreeBytes string `json:"storage.user_unreserved_free_bytes"` + DataReductionCloneUserSavedBytes string `json:"data_reduction.clone.user_saved_bytes"` + DataReductionDedupPostReductionBytes string `json:"data_reduction.dedup.post_reduction_bytes"` + DataReductionCloneSavingRatioPpm string `json:"data_reduction.clone.saving_ratio_ppm"` + StorageLogicalUsageBytes string `json:"storage.logical_usage_bytes"` + DataReductionSavedBytes string `json:"data_reduction.saved_bytes"` + StorageUserDiskPhysicalUsageBytes string `json:"storage.user_disk_physical_usage_bytes"` + StorageFreeBytes string `json:"storage.free_bytes"` + DataReductionCompressionPostReductionBytes string `json:"data_reduction.compression.post_reduction_bytes"` + DataReductionCompressionUserPostReductionBytes string `json:"data_reduction.compression.user_post_reduction_bytes"` + StorageUserFreeBytes string `json:"storage.user_free_bytes"` + StorageUnreservedFreeBytes string `json:"storage.unreserved_free_bytes"` + StorageUserContainerOwnUsageBytes string `json:"storage.user_container_own_usage_bytes"` + DataReductionCompressionSavingRatioPpm string `json:"data_reduction.compression.saving_ratio_ppm"` + StorageUserUsageBytes int64 `json:"storage.user_usage_bytes"` + DataReductionErasureCodingUserSavedBytes string `json:"data_reduction.erasure_coding.user_saved_bytes"` + DataReductionDedupSavingRatioPpm string `json:"data_reduction.dedup.saving_ratio_ppm"` + StorageUnreservedCapacityBytes string `json:"storage.unreserved_capacity_bytes"` + StorageUserReservedUsageBytes string `json:"storage.user_reserved_usage_bytes"` + DataReductionCompressionUserPreReductionBytes string `json:"data_reduction.compression.user_pre_reduction_bytes"` + DataReductionUserPostReductionBytes string `json:"data_reduction.user_post_reduction_bytes"` + DataReductionOverallUserSavedBytes string `json:"data_reduction.overall.user_saved_bytes"` + DataReductionErasureCodingParityBytes string `json:"data_reduction.erasure_coding.parity_bytes"` + DataReductionSavingRatioPpm string `json:"data_reduction.saving_ratio_ppm"` + StorageUnreservedOwnUsageBytes string `json:"storage.unreserved_own_usage_bytes"` + DataReductionErasureCodingSavingRatioPpm string `json:"data_reduction.erasure_coding.saving_ratio_ppm"` + StorageUserReservedCapacityBytes string `json:"storage.user_reserved_capacity_bytes"` + DataReductionThinProvisionUserSavedBytes string `json:"data_reduction.thin_provision.user_saved_bytes"` + StorageDiskPhysicalUsageBytes string `json:"storage.disk_physical_usage_bytes"` + DataReductionErasureCodingUserPostReductionBytes string `json:"data_reduction.erasure_coding.user_post_reduction_bytes"` + DataReductionCompressionPreReductionBytes string `json:"data_reduction.compression.pre_reduction_bytes"` + DataReductionDedupPreReductionBytes string `json:"data_reduction.dedup.pre_reduction_bytes"` + DataReductionDedupUserSavedBytes string `json:"data_reduction.dedup.user_saved_bytes"` + StorageUnreservedUsageBytes string `json:"storage.unreserved_usage_bytes"` + StorageTierSsdUsageBytes string `json:"storage_tier.ssd.usage_bytes"` + DataReductionPostReductionBytes string `json:"data_reduction.post_reduction_bytes"` + DataReductionThinProvisionSavingRatioPpm string `json:"data_reduction.thin_provision.saving_ratio_ppm"` + StorageReservedCapacityBytes string `json:"storage.reserved_capacity_bytes"` + StorageUserReservedFreeBytes string `json:"storage.user_reserved_free_bytes"` +} + +type SStorage struct { + multicloud.SStorageBase + multicloud.STagBase + + zone *SZone + + StorageContainerUUID string `json:"storage_container_uuid"` + Name string `json:"name"` + ClusterUUID string `json:"cluster_uuid"` + MarkedForRemoval bool `json:"marked_for_removal"` + MaxCapacity int64 `json:"max_capacity"` + TotalExplicitReservedCapacity int `json:"total_explicit_reserved_capacity"` + TotalImplicitReservedCapacity int `json:"total_implicit_reserved_capacity"` + AdvertisedCapacity interface{} `json:"advertised_capacity"` + ReplicationFactor int `json:"replication_factor"` + OplogReplicationFactor int `json:"oplog_replication_factor"` + NfsWhitelist []interface{} `json:"nfs_whitelist"` + NfsWhitelistInherited bool `json:"nfs_whitelist_inherited"` + RandomIoPreference []string `json:"random_io_preference"` + SeqIoPreference []string `json:"seq_io_preference"` + IlmPolicy interface{} `json:"ilm_policy"` + DownMigrateTimesInSecs DownMigrateTimesInSecs `json:"down_migrate_times_in_secs"` + ErasureCode string `json:"erasure_code"` + InlineEcEnabled interface{} `json:"inline_ec_enabled"` + PreferHigherEcfaultDomain interface{} `json:"prefer_higher_ecfault_domain"` + ErasureCodeDelaySecs interface{} `json:"erasure_code_delay_secs"` + FingerPrintOnWrite string `json:"finger_print_on_write"` + OnDiskDedup string `json:"on_disk_dedup"` + CompressionEnabled bool `json:"compression_enabled"` + CompressionDelayInSecs int `json:"compression_delay_in_secs"` + IsNutanixManaged interface{} `json:"is_nutanix_managed"` + EnableSoftwareEncryption bool `json:"enable_software_encryption"` + VstoreNameList []string `json:"vstore_name_list"` + MappedRemoteContainers MappedRemoteContainers `json:"mapped_remote_containers"` + Stats StorageStats `json:"stats"` + UsageStats StorageUsageStats `json:"usage_stats"` + Encrypted interface{} `json:"encrypted"` +} + +func (self *SStorage) GetName() string { + return self.Name +} + +func (self *SStorage) GetId() string { + return self.StorageContainerUUID +} + +func (self *SStorage) GetGlobalId() string { + return self.StorageContainerUUID +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := self.zone.region.GetDisks(self.GetGlobalId(), "") + if err != nil { + return nil, errors.Wrapf(err, "GetDisks") + } + ret := []cloudprovider.ICloudDisk{} + for i := range disks { + disks[i].storage = self + ret = append(ret, &disks[i]) + } + return ret, nil +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStorage) GetCapacityMB() int64 { + return self.UsageStats.StorageUserCapacityBytes / 1024 / 1024 +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return self.UsageStats.StorageUserUsageBytes / 1024 / 1024 +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disk, err := self.zone.region.GetDisk(id) + if err != nil { + return nil, err + } + if disk.StorageContainerUUID != self.GetGlobalId() { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) + } + disk.storage = self + return disk, nil +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return &SStoragecache{storage: self, region: self.zone.region} +} + +func (self *SRegion) GetStorages() ([]SStorage, error) { + storages := []SStorage{} + err := self.listAll("storage_containers", nil, &storages) + if err != nil { + return nil, err + } + ret := []SStorage{} + for i := range storages { + if storages[i].Name == "NutanixManagementShare" { // https://portal.nutanix.com/page/documents/details?targetId=Web-Console-Guide-Prism-v5_15-ZH:wc-container-create-wc-t.html + continue + } + ret = append(ret, storages[i]) + } + return ret, nil +} + +func (self *SRegion) GetStorage(id string) (*SStorage, error) { + storage := &SStorage{} + return storage, self.get("storage_containers", id, nil, storage) +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SStorage) GetMediumType() string { + return api.DISK_TYPE_SSD +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) Refresh() error { + storage, err := self.zone.region.GetStorage(self.GetGlobalId()) + if err != nil { + return err + } + return jsonutils.Update(self, storage) +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (self *SStorage) GetStorageType() string { + return api.STORAGE_LOCAL +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} + +func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + zones, err := self.GetIZones() + if err != nil { + return nil, errors.Wrapf(err, "GetIZones") + } + for i := range zones { + storage, err := zones[i].GetIStorageById(id) + if err == nil && storage != nil { + return storage, nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/storagecache.go new file mode 100644 index 0000000000..83aabff59b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/storagecache.go @@ -0,0 +1,136 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/esxi/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +type SStoragecache struct { + multicloud.SResourceBase + multicloud.STagBase + + storage *SStorage + region *SRegion +} + +func (self *SStoragecache) GetName() string { + return self.storage.GetName() +} + +func (self *SStoragecache) GetId() string { + return self.storage.GetId() +} + +func (self *SStoragecache) GetGlobalId() string { + return self.storage.GetGlobalId() +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + images, err := self.region.GetImages() + if err != nil { + return nil, errors.Wrapf(err, "GetImages") + } + ret := []cloudprovider.ICloudImage{} + for i := range images { + if images[i].StorageContainerUUID != self.storage.GetGlobalId() { + continue + } + images[i].cache = self + ret = append(ret, &images[i]) + } + return ret, nil +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SStoragecache) GetIImageById(id string) (cloudprovider.ICloudImage, error) { + image, err := self.region.GetImage(id) + if err != nil { + return nil, err + } + image.cache = self + return image, nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, opts *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { + s := auth.GetAdminSession(ctx, options.Options.Region) + + meta, reader, size, err := modules.Images.Download(s, opts.ImageId, string(qemuimg.QCOW2), false) + if err != nil { + return "", err + } + log.Infof("meta data %s", meta) + image, err := self.region.CreateImage(self.storage.StorageContainerUUID, opts, size, reader, callback) + if err != nil { + return "", err + } + if callback != nil { + callback(100.0) + } + image.cache = self + return image.GetGlobalId(), nil +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storages, err := self.GetStorages() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStoragecache{} + for i := range storages { + cache := &SStoragecache{storage: &storages[i], region: self} + ret = append(ret, cache) + } + return ret, nil +} + +func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + storage, err := self.GetStorage(id) + if err != nil { + return nil, errors.Wrapf(err, "GetStorage") + } + return &SStoragecache{region: self, storage: storage}, nil +} diff --git a/pkg/multicloud/nutanix/task.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/task.go similarity index 100% rename from pkg/multicloud/nutanix/task.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/task.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/vpc.go new file mode 100644 index 0000000000..2e26fe0eef --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/vpc.go @@ -0,0 +1,182 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "fmt" + "net/url" + "sort" + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type DhcpOptions struct { +} + +type SPool struct { + Range string `json:"range"` +} + +type IPConfig struct { + NetworkAddress string `json:"network_address"` + PrefixLength int `json:"prefix_length"` + DefaultGateway string `json:"default_gateway"` + DhcpOptions DhcpOptions `json:"dhcp_options"` + Pool []SPool `json:"pool"` + DhcpServerAddress string `json:"dhcp_server_address"` +} + +type SVpc struct { + multicloud.SVpc + multicloud.STagBase + + region *SRegion + + LogicalTimestamp int `json:"logical_timestamp"` + VlanID int `json:"vlan_id"` + UUID string `json:"uuid"` + Name string `json:"name"` + IPConfig IPConfig `json:"ip_config,omitempty"` +} + +func (self *SVpc) GetName() string { + return self.Name +} + +func (self *SVpc) GetId() string { + return self.UUID +} + +func (self *SVpc) GetGlobalId() string { + return self.UUID +} + +func (self *SVpc) Delete() error { + return self.region.DeleteVpc(self.UUID) +} + +func (self *SVpc) GetCidrBlock() string { + if len(self.IPConfig.NetworkAddress) > 0 { + return fmt.Sprintf("%s/%d", self.IPConfig.NetworkAddress, self.IPConfig.PrefixLength) + } + return "" +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + return []cloudprovider.ICloudRouteTable{}, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + return []cloudprovider.ICloudSecurityGroup{}, nil +} + +func (self *SRegion) GetVpcs() ([]SVpc, error) { + vpcs := []SVpc{} + _, err := self.list("networks", url.Values{}, &vpcs) + return vpcs, err +} + +func (self *SVpc) getWire() *SWire { + return &SWire{vpc: self} +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + wire := self.getWire() + return []cloudprovider.ICloudWire{wire}, nil +} + +func (self *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { + wires, err := self.GetIWires() + if err != nil { + return nil, err + } + for i := range wires { + if wires[i].GetGlobalId() == wireId { + return wires[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SVpc) GetIsDefault() bool { + return len(self.GetCidrBlock()) > 0 +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} + +func (self *SRegion) GetVpc(id string) (*SVpc, error) { + vpc := &SVpc{region: self} + return vpc, self.get("networks", id, url.Values{}, vpc) +} + +func (self *SRegion) CreateVpc(opts *cloudprovider.VpcCreateOptions) (*SVpc, error) { + ipConfig := map[string]interface{}{} + if len(opts.CIDR) > 0 { + if addrs := strings.Split(opts.CIDR, "/"); len(addrs) == 2 { + ipConfig["network_address"] = addrs[0] + ipConfig["prefix_length"], _ = strconv.Atoi(addrs[1]) + } + + } + vpcs, err := self.GetVpcs() + if err != nil { + return nil, errors.Wrapf(err, "GetVpcs") + } + vlanId, vlanIds := -1, []int{} + for i := range vpcs { + vlanIds = append(vlanIds, vpcs[i].VlanID) + } + sort.Ints(vlanIds) + for _, vlan := range vlanIds { + if vlan == vlanId+1 { + vlanId = vlan + } + } + params := map[string]interface{}{ + "name": opts.NAME, + "annotation": opts.Desc, + "ip_config": ipConfig, + "vlan_id": vlanId + 1, + } + ret := struct { + NetworkUUID string + }{} + err = self.post("networks", jsonutils.Marshal(params), &ret) + if err != nil { + return nil, err + } + return self.GetVpc(ret.NetworkUUID) +} + +func (self *SRegion) DeleteVpc(id string) error { + return self.delete("networks", id) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/wire.go new file mode 100644 index 0000000000..896da6ad37 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/wire.go @@ -0,0 +1,103 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + multicloud.STagBase + + vpc *SVpc +} + +func (self *SWire) GetName() string { + return self.vpc.GetName() +} + +func (self *SWire) GetId() string { + return self.vpc.GetId() +} + +func (self *SWire) GetGlobalId() string { + return self.vpc.GetGlobalId() +} + +func (self *SWire) IsEmulated() bool { + return true +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + network, err := self.vpc.region.CreateNetwork(self.vpc.UUID, opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateNetwork") + } + return network, nil +} + +func (self *SWire) GetBandwidth() int { + return 10000 +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + ret := []cloudprovider.ICloudNetwork{} + if len(self.vpc.IPConfig.Pool) == 0 { + network := &SNetwork{wire: self} + ret = append(ret, network) + } + for _, pool := range self.vpc.IPConfig.Pool { + network := &SNetwork{wire: self} + network.Range = pool.Range + ret = append(ret, network) + } + return ret, nil +} + +func (self *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { + networks, err := self.GetINetworks() + if err != nil { + return nil, err + } + + for i := range networks { + if networks[i].GetGlobalId() == netid { + return networks[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + cluster := SCluster{} + err := self.vpc.region.get("cluster", "", nil, &cluster) + if err != nil { + return nil + } + return &SZone{SCluster: cluster, region: self.vpc.region} +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/zone.go new file mode 100644 index 0000000000..c371675b6a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/nutanix/zone.go @@ -0,0 +1,118 @@ +// Copyright 2019 Yunion +// +// 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 nutanix + +import ( + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SZone struct { + multicloud.STagBase + multicloud.SResourceBase + + SCluster + region *SRegion +} + +func (self *SZone) GetName() string { + return self.Name +} + +func (self *SZone) GetId() string { + return self.UUID +} + +func (self *SZone) GetGlobalId() string { + return self.UUID +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) + return table +} + +func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + hosts, err := self.region.GetHosts() + if err != nil { + return nil, errors.Wrapf(err, "GetIHosts") + } + firstHost := true + ret := []cloudprovider.ICloudHost{} + for i := range hosts { + if hosts[i].ClusterUUID != self.UUID { + continue + } + hosts[i].zone = self + hosts[i].firstHost = firstHost + ret = append(ret, &hosts[i]) + if firstHost { + firstHost = false + } + } + return ret, nil +} + +func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + host, err := self.region.GetHost(id) + if err != nil { + return nil, errors.Wrapf(err, "GetIHostById(%s)", id) + } + if host.ClusterUUID != self.UUID { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) + } + host.zone = self + return host, nil +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) GetStatus() string { + return api.ZONE_ENABLE +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.region.GetStorages() + if err != nil { + return nil, errors.Wrapf(err, "GetStorages") + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + if storages[i].ClusterUUID != self.UUID { + continue + } + storages[i].zone = self + ret = append(ret, &storages[i]) + } + return ret, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storage, err := self.region.GetStorage(id) + if err != nil { + return nil, errors.Wrapf(err, "GetStorage %s", id) + } + if storage.ClusterUUID != self.UUID { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) + } + storage.zone = self + return storage, nil +} diff --git a/pkg/multicloud/objectstore/buckets.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/buckets.go similarity index 98% rename from pkg/multicloud/objectstore/buckets.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/buckets.go index b3f176d1b0..fc8175cb9d 100644 --- a/pkg/multicloud/objectstore/buckets.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/buckets.go @@ -26,9 +26,9 @@ import ( "yunion.io/x/pkg/utils" "yunion.io/x/s3cli" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SBucket struct { diff --git a/pkg/multicloud/objectstore/ceph/adminapi.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/adminapi.go similarity index 100% rename from pkg/multicloud/objectstore/ceph/adminapi.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/adminapi.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/bucket.go new file mode 100644 index 0000000000..3ab74524ec --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/bucket.go @@ -0,0 +1,67 @@ +// Copyright 2019 Yunion +// +// 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 ceph + +import ( + "context" + "strconv" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud/objectstore" +) + +type SCephRadosBucket struct { + *objectstore.SBucket +} + +func (b *SCephRadosBucket) GetStats() cloudprovider.SBucketStats { + _, hdr, _ := b.GetIBucketProvider().S3Client().BucketExists(b.Name) + if hdr != nil { + sizeBytesStr := hdr.Get("X-Rgw-Bytes-Used") + sizeBytes, _ := strconv.ParseInt(sizeBytesStr, 10, 64) + objCntStr := hdr.Get("X-Rgw-Object-Count") + objCnt, _ := strconv.ParseInt(objCntStr, 10, 64) + return cloudprovider.SBucketStats{ + SizeBytes: sizeBytes, + ObjectCount: int(objCnt), + } + } + return b.SBucket.GetStats() +} + +func (b *SCephRadosBucket) GetLimit() cloudprovider.SBucketStats { + if cephCli, ok := b.GetIBucketProvider().(*SCephRadosClient); ok { + quota, err := cephCli.adminApi.GetBucketQuota(context.Background(), cephCli.GetAccountId(), b.Name) + if err == nil { + limit := cloudprovider.SBucketStats{} + if quota.Enabled.IsTrue() { + limit.SizeBytes = quota.MaxSize + limit.ObjectCount = quota.MaxObjects + } + return limit + } + } + return b.SBucket.GetLimit() +} + +func (b *SCephRadosBucket) SetLimit(limit cloudprovider.SBucketStats) error { + /*if cephCli, ok := b.GetIBucketProvider().(*SCephRadosClient); ok { + err := cephCli.adminApi.SetBucketQuota(context.Background(), cephCli.GetAccountId(), b.Name, limit.SizeBytes, limit.ObjectCount) + return errors.Wrap(err, "cephCli.adminApi.SetBucketQuota") + } + return b.SBucket.SetLimit(limit)*/ + return httperrors.ErrNotSupported +} diff --git a/pkg/multicloud/objectstore/ceph/ceph.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/ceph.go similarity index 95% rename from pkg/multicloud/objectstore/ceph/ceph.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/ceph.go index ff4a5ee20d..7889ab53f0 100644 --- a/pkg/multicloud/objectstore/ceph/ceph.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/ceph.go @@ -22,10 +22,10 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/s3cli" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" + "yunion.io/x/cloudmux/pkg/multicloud/objectstore" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/doc.go new file mode 100644 index 0000000000..2fcd44ed2b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 ceph // import "yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider/doc.go new file mode 100644 index 0000000000..317c0d3b26 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider/provider.go new file mode 100644 index 0000000000..4fca07df1a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph/provider/provider.go @@ -0,0 +1,65 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/objectstore" + "yunion.io/x/cloudmux/pkg/multicloud/objectstore/ceph" + s3provider "yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider" +) + +type SCephRadosProviderFactory struct { + s3provider.SObjectStoreProviderFactory +} + +func (self *SCephRadosProviderFactory) GetId() string { + return api.CLOUD_PROVIDER_CEPH +} + +func (self *SCephRadosProviderFactory) GetName() string { + return api.CLOUD_PROVIDER_CEPH +} + +func (self *SCephRadosProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + client, err := ceph.NewCephRados( + objectstore.NewObjectStoreClientConfig( + cfg.URL, cfg.Account, cfg.Secret, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return s3provider.NewObjectStoreProvider(self, client, []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + }), nil +} + +func (self *SCephRadosProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + return map[string]string{ + "S3_ACCESS_KEY": info.Account, + "S3_SECRET": info.Secret, + "S3_ACCESS_URL": info.Url, + "S3_BACKEND": api.CLOUD_PROVIDER_CEPH, + }, nil +} + +func init() { + factory := SCephRadosProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/doc.go new file mode 100644 index 0000000000..2eca452cc5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 objectstore // import "yunion.io/x/cloudmux/pkg/multicloud/objectstore" diff --git a/pkg/multicloud/objectstore/interface.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/interface.go similarity index 96% rename from pkg/multicloud/objectstore/interface.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/interface.go index d1814aec15..f00665fe54 100644 --- a/pkg/multicloud/objectstore/interface.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/interface.go @@ -18,7 +18,7 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/s3cli" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type IBucketProvider interface { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/object.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/object.go new file mode 100644 index 0000000000..e73b4a4ebb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/object.go @@ -0,0 +1,92 @@ +// Copyright 2019 Yunion +// +// 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 objectstore + +import ( + "context" + "net/http" + "strings" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/s3cli" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + META_HEADER = "X-Amz-Meta-" +) + +type SObject struct { + bucket *SBucket + + cloudprovider.SBaseCloudObject +} + +func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { + return o.bucket +} + +func (o *SObject) GetAcl() cloudprovider.TBucketACLType { + acl, err := o.bucket.client.GetObjectAcl(o.bucket.Name, o.Key) + if err != nil { + if e, ok := errors.Cause(err).(s3cli.ErrorResponse); ok { + if e.Code == "NoSuchKey" || e.Message == "The specified key does not exist." { + objects, _ := o.bucket.ListObjects(o.Key, "", "", 1) + if len(objects.Objects) > 0 { + return cloudprovider.ACLPrivate + } + } + } + log.Errorf("o.bucket.client.GetObjectAcl error %s", err) + return cloudprovider.ACLPrivate + } + return acl +} + +func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { + err := o.bucket.client.SetObjectAcl(o.bucket.Name, o.Key, aclStr) + if err != nil { + if strings.Contains(err.Error(), "not implemented") || strings.Contains(err.Error(), "Please use AWS4-HMAC-SHA256") { + // ignore not implemented error + return nil // cloudprovider.ErrNotImplemented + } else { + return errors.Wrap(err, "o.bucket.client.SetObjectAcl") + } + } + return nil +} + +func (o *SObject) GetMeta() http.Header { + if o.Meta != nil { + return o.Meta + } + cli := o.bucket.client.S3Client() + objInfo, err := cli.StatObject(o.bucket.Name, o.Key, s3cli.StatObjectOptions{}) + if err != nil { + log.Errorf("cli.statObject fail %s", err) + return nil + } + if len(objInfo.ContentType) > 0 { + objInfo.Metadata.Set(cloudprovider.META_HEADER_CONTENT_TYPE, objInfo.ContentType) + } + o.Meta = cloudprovider.FetchMetaFromHttpHeader(META_HEADER, objInfo.Metadata) + return o.Meta +} + +func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { + return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) +} diff --git a/pkg/multicloud/objectstore/objectstore.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/objectstore.go similarity index 99% rename from pkg/multicloud/objectstore/objectstore.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/objectstore.go index 6439c29631..d935dc5b3f 100644 --- a/pkg/multicloud/objectstore/objectstore.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/objectstore.go @@ -25,10 +25,10 @@ import ( "yunion.io/x/pkg/util/secrules" "yunion.io/x/s3cli" - api "yunion.io/x/onecloud/pkg/apis/compute" + api "yunion.io/x/cloudmux/pkg/apis/compute" "yunion.io/x/onecloud/pkg/cloudcommon/object" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider/doc.go new file mode 100644 index 0000000000..6502f640cc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider/provider.go new file mode 100644 index 0000000000..0b0a6b3961 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider/provider.go @@ -0,0 +1,166 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/objectstore" +) + +type SObjectStoreProviderFactory struct { + cloudprovider.SPremiseBaseProviderFactory +} + +func (self *SObjectStoreProviderFactory) GetId() string { + return api.CLOUD_PROVIDER_GENERICS3 +} + +func (self *SObjectStoreProviderFactory) GetName() string { + return api.CLOUD_PROVIDER_GENERICS3 +} + +func (self *SObjectStoreProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + if len(input.Endpoint) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "endpoint") + } + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + output.AccessUrl = input.Endpoint + return output, nil +} + +func (self *SObjectStoreProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func (self *SObjectStoreProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + client, err := objectstore.NewObjectStoreClient( + objectstore.NewObjectStoreClientConfig( + cfg.URL, cfg.Account, cfg.Secret, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return NewObjectStoreProvider(self, client, []string{ + string(cloudprovider.ACLPrivate), + }), nil +} + +func (self *SObjectStoreProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + return map[string]string{ + "S3_ACCESS_KEY": info.Account, + "S3_SECRET": info.Secret, + "S3_ACCESS_URL": info.Url, + "S3_BACKEND": api.CLOUD_PROVIDER_GENERICS3, + }, nil +} + +func init() { + factory := SObjectStoreProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SObjectStoreProvider struct { + cloudprovider.SBaseProvider + client objectstore.IBucketProvider + supportedAcls []string +} + +func NewObjectStoreProvider(factory cloudprovider.ICloudProviderFactory, client objectstore.IBucketProvider, acls []string) *SObjectStoreProvider { + return &SObjectStoreProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(factory), + client: client, + supportedAcls: acls, + } +} + +func (self *SObjectStoreProvider) GetIRegions() []cloudprovider.ICloudRegion { + return nil +} + +func (self *SObjectStoreProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SObjectStoreProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SObjectStoreProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { + return self.client, nil +} + +func (self *SObjectStoreProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SObjectStoreProvider) GetSysInfo() (jsonutils.JSONObject, error) { + return self.client.About(), nil +} + +func (self *SObjectStoreProvider) GetVersion() string { + return self.client.GetVersion() +} + +func (self *SObjectStoreProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SObjectStoreProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SObjectStoreProvider) GetStorageClasses(regionId string) []string { + return []string{} +} + +func (self *SObjectStoreProvider) GetBucketCannedAcls(regionId string) []string { + return self.supportedAcls +} + +func (self *SObjectStoreProvider) GetObjectCannedAcls(regionId string) []string { + return self.supportedAcls +} + +func (self *SObjectStoreProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} diff --git a/pkg/multicloud/objectstore/shell.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/shell.go similarity index 99% rename from pkg/multicloud/objectstore/shell.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/shell.go index 1236e64f92..df6e11111d 100644 --- a/pkg/multicloud/objectstore/shell.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/shell.go @@ -27,7 +27,7 @@ import ( "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/fileutils2" "yunion.io/x/onecloud/pkg/util/printutils" "yunion.io/x/onecloud/pkg/util/shellutils" diff --git a/pkg/multicloud/objectstore/xsky/adminapi.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/adminapi.go similarity index 99% rename from pkg/multicloud/objectstore/xsky/adminapi.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/adminapi.go index 00bffa2cd3..db8f395aa0 100644 --- a/pkg/multicloud/objectstore/xsky/adminapi.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/adminapi.go @@ -27,9 +27,10 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/util/httputils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SXskyAdminApi struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/bucket.go new file mode 100644 index 0000000000..10287d206f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/bucket.go @@ -0,0 +1,89 @@ +// Copyright 2019 Yunion +// +// 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 xsky + +import ( + "context" + "strconv" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/objectstore" +) + +type SXskyBucket struct { + *objectstore.SBucket + + client *SXskyClient +} + +func (b *SXskyBucket) GetStats() cloudprovider.SBucketStats { + _, hdr, _ := b.GetIBucketProvider().S3Client().BucketExists(b.Name) + if hdr != nil { + sizeBytesStr := hdr.Get("X-Rgw-Bytes-Used") + sizeBytes, _ := strconv.ParseInt(sizeBytesStr, 10, 64) + objCntStr := hdr.Get("X-Rgw-Object-Count") + objCnt, _ := strconv.ParseInt(objCntStr, 10, 64) + return cloudprovider.SBucketStats{ + SizeBytes: sizeBytes, + ObjectCount: int(objCnt), + } + } + return b.SBucket.GetStats() +} + +func (b *SXskyBucket) LimitSupport() cloudprovider.SBucketStats { + return cloudprovider.SBucketStats{ + SizeBytes: 1, + ObjectCount: 1, + } +} + +func (b *SXskyBucket) GetLimit() cloudprovider.SBucketStats { + limit := cloudprovider.SBucketStats{} + bucket, err := b.client.adminApi.getBucketByName(context.Background(), b.Name) + if err != nil { + log.Errorf("b.client.adminApi.getBucketByName error %s", err) + } else { + limit.SizeBytes = bucket.QuotaMaxSize + limit.ObjectCount = bucket.QuotaMaxObjects + } + return limit +} + +func (b *SXskyBucket) SetLimit(limit cloudprovider.SBucketStats) error { + bucket, err := b.client.adminApi.getBucketByName(context.Background(), b.Name) + if err != nil { + return errors.Wrap(err, "b.client.adminApi.getBucketByName") + } + input := sBucketQuotaInput{} + input.OsBucket.QuotaMaxObjects = limit.ObjectCount + input.OsBucket.QuotaMaxSize = limit.SizeBytes + err = b.client.adminApi.setBucketQuota(context.Background(), bucket.Id, input) + if err != nil { + return errors.Wrap(err, "b.client.adminApi.setBucketQuota") + } + cloudprovider.Wait(time.Second, 30*time.Second, func() (bool, error) { + target := b.GetLimit() + if target.SizeBytes == limit.SizeBytes && target.ObjectCount == limit.ObjectCount { + return true, nil + } + return false, nil + }) + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/doc.go new file mode 100644 index 0000000000..7795ceb167 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 xsky // import "yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/provider/doc.go new file mode 100644 index 0000000000..893c8e7c5c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/provider/provider.go new file mode 100644 index 0000000000..00cdc38c02 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/provider/provider.go @@ -0,0 +1,68 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/objectstore" + s3provider "yunion.io/x/cloudmux/pkg/multicloud/objectstore/provider" + "yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky" +) + +type SXskyProviderFactory struct { + s3provider.SObjectStoreProviderFactory +} + +func (self *SXskyProviderFactory) GetId() string { + return api.CLOUD_PROVIDER_XSKY +} + +func (self *SXskyProviderFactory) GetName() string { + return api.CLOUD_PROVIDER_XSKY +} + +func (self *SXskyProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + client, err := xsky.NewXskyClient( + objectstore.NewObjectStoreClientConfig( + cfg.URL, cfg.Account, cfg.Secret, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return s3provider.NewObjectStoreProvider(self, client, []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLPublicRead), + string(cloudprovider.ACLPublicReadWrite), + }), nil +} + +func (self *SXskyProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + client, err := xsky.NewXskyClient( + objectstore.NewObjectStoreClientConfig( + info.Url, info.Account, info.Secret, + ), + ) + if err != nil { + return nil, err + } + return client.GetClientRC(), nil +} + +func init() { + factory := SXskyProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} diff --git a/pkg/multicloud/objectstore/xsky/xsky.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/xsky.go similarity index 96% rename from pkg/multicloud/objectstore/xsky/xsky.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/xsky.go index 67146e38ab..23dbf9f9b9 100644 --- a/pkg/multicloud/objectstore/xsky/xsky.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/objectstore/xsky/xsky.go @@ -23,9 +23,9 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/s3cli" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud/objectstore" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud/objectstore" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/disk.go new file mode 100644 index 0000000000..3a8d424b6d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/disk.go @@ -0,0 +1,448 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/version" +) + +const ( + DISK_STATUS_CREATING = "creating" // The volume is being created. + + DISK_STATUS_ATTACHING = "attaching" // The volume is attaching to an instance. + DISK_STATUS_DETACHING = "detaching" // The volume is detaching from an instance. + DISK_STATUS_EXTENDING = "extending" // The volume is being extended. + DISK_STATUS_DELETING = "deleting" // The volume is being deleted. + + DISK_STATUS_RETYPING = "retyping" // The volume is changing type to another volume type. + DISK_STATUS_AVAILABLE = "available" // The volume is ready to attach to an instance. + DISK_STATUS_RESERVED = "reserved" // The volume is reserved for attaching or shelved. + DISK_STATUS_IN_USE = "in-use" // The volume is attached to an instance. + DISK_STATUS_MAINTENANCE = "maintenance" // The volume is locked and being migrated. + DISK_STATUS_AWAITING_TRANSFER = "awaiting-transfer" // The volume is awaiting for transfer. + DISK_STATUS_BACKING_UP = "backing-up" // The volume is being backed up. + DISK_STATUS_RESTORING_BACKUP = "restoring-backup" // A backup is being restored to the volume. + DISK_STATUS_DOWNLOADING = "downloading" // The volume is downloading an image. + DISK_STATUS_UPLOADING = "uploading" // The volume is being uploaded to an image. + + DISK_STATUS_ERROR = "error" // A volume creation error occurred. + DISK_STATUS_ERROR_DELETING = "error_deleting" // A volume deletion error occurred. + DISK_STATUS_ERROR_BACKING_UP = "error_backing-up" // A backup error occurred. + DISK_STATUS_ERROR_RESTORING = "error_restoring" // A backup restoration error occurred. + DISK_STATUS_ERROR_EXTENDING = "error_extending" // An error occurred while attempting to extend a volume. + +) + +type Attachment struct { + ServerId string + AttachmentId string + HostName string + VolumeId string + Device string + Id string +} + +type Link struct { + Href string + Rel string +} + +type VolumeImageMetadata struct { + Checksum string + MinRAM int + DiskFormat string + ImageName string + ImageId string + ContainerFormat string + MinDisk int + Size int +} + +type SDisk struct { + storage *SStorage + multicloud.SDisk + OpenStackTags + + Id string + Name string + + MigrationStatus string + Attachments []Attachment + Links []Link + + AvailabilityZone string + Host string `json:"os-vol-host-attr:host"` + Encrypted bool + ReplicationStatus string + SnapshotId string + Size int + UserId string + TenantId string `json:"os-vol-tenant-attr:tenant_id"` + Migstat string `json:"os-vol-mig-status-attr:migstat"` + + Status string + Description string + Multiattach string + SourceVolid string + ConsistencygroupId string + VolumeImageMetadata VolumeImageMetadata + NameId string `json:"os-vol-mig-status-attr:name_id"` + Bootable bool + CreatedAt time.Time + VolumeType string +} + +func (region *SRegion) GetDisks() ([]SDisk, error) { + disks := []SDisk{} + resource := "/volumes/detail" + query := url.Values{} + query.Set("all_tenants", "true") + for { + resp, err := region.bsList(resource, query) + if err != nil { + return nil, errors.Wrap(err, "bsList") + } + part := struct { + Volumes []SDisk + VolumesLinks SNextLinks + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + disks = append(disks, part.Volumes...) + marker := part.VolumesLinks.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return disks, nil +} + +func (disk *SDisk) GetId() string { + return disk.Id +} + +func (disk *SDisk) Delete(ctx context.Context) error { + err := disk.storage.zone.region.DeleteDisk(disk.Id) + if err != nil { + return err + } + return cloudprovider.WaitDeleted(disk, 10*time.Second, 8*time.Minute) +} + +func (disk *SDisk) attachInstances(attachments []Attachment) error { + for _, attachment := range attachments { + startTime := time.Now() + for time.Now().Sub(startTime) < 5*time.Minute { + if err := disk.storage.zone.region.AttachDisk(attachment.ServerId, disk.Id); err != nil { + if strings.Contains(err.Error(), "status must be available or downloading") { + time.Sleep(time.Second * 10) + continue + } + log.Errorf("recover attach disk %s => instance %s error: %v", disk.Id, attachment.ServerId, err) + return err + } else { + return nil + } + } + } + return nil +} + +func (disk *SDisk) Resize(ctx context.Context, sizeMb int64) error { + maxVersion := "" + for _, service := range []string{OPENSTACK_SERVICE_VOLUMEV3, OPENSTACK_SERVICE_VOLUMEV2, OPENSTACK_SERVICE_VOLUME} { + maxVersion, _ = disk.storage.zone.region.GetMaxVersion(service) + if len(maxVersion) > 0 { + break + } + } + if version.GE(maxVersion, "3.42") { + return disk.storage.zone.region.ResizeDisk(disk.Id, sizeMb) + } + instanceIds := []string{} + for _, attachement := range disk.Attachments { + if err := disk.storage.zone.region.DetachDisk(attachement.ServerId, disk.Id); err != nil { + return err + } + instanceIds = append(instanceIds, attachement.ServerId) + } + err := disk.storage.zone.region.ResizeDisk(disk.Id, sizeMb) + if err != nil { + disk.attachInstances(disk.Attachments) + return err + } + return disk.attachInstances(disk.Attachments) +} + +func (disk *SDisk) GetName() string { + if len(disk.Name) > 0 { + return disk.Name + } + return disk.Id +} + +func (disk *SDisk) GetGlobalId() string { + return disk.Id +} + +func (disk *SDisk) IsEmulated() bool { + return false +} + +func (disk *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return disk.storage, nil +} + +func (disk *SDisk) GetStatus() string { + switch disk.Status { + case DISK_STATUS_CREATING, DISK_STATUS_DOWNLOADING: + return api.DISK_ALLOCATING + case DISK_STATUS_ATTACHING: + return api.DISK_ATTACHING + case DISK_STATUS_DETACHING: + return api.DISK_DETACHING + case DISK_STATUS_EXTENDING: + return api.DISK_RESIZING + case DISK_STATUS_RETYPING, DISK_STATUS_AVAILABLE, DISK_STATUS_RESERVED, DISK_STATUS_IN_USE, DISK_STATUS_MAINTENANCE, DISK_STATUS_AWAITING_TRANSFER, DISK_STATUS_BACKING_UP, DISK_STATUS_RESTORING_BACKUP, DISK_STATUS_UPLOADING: + return api.DISK_READY + case DISK_STATUS_DELETING: + return api.DISK_DEALLOC + case DISK_STATUS_ERROR: + return api.DISK_ALLOC_FAILED + default: + return api.DISK_UNKNOWN + } +} + +func (disk *SDisk) Refresh() error { + _disk, err := disk.storage.zone.region.GetDisk(disk.Id) + if err != nil { + return err + } + return jsonutils.Update(disk, _disk) +} + +func (disk *SDisk) ResizeDisk(sizeMb int64) error { + return disk.storage.zone.region.ResizeDisk(disk.Id, sizeMb) +} + +func (disk *SDisk) GetDiskFormat() string { + return "lvm" +} + +func (disk *SDisk) GetDiskSizeMB() int { + return disk.Size * 1024 +} + +func (disk *SDisk) GetIsAutoDelete() bool { + return false +} + +func (disk *SDisk) GetTemplateId() string { + return disk.VolumeImageMetadata.ImageId +} + +func (disk *SDisk) GetDiskType() string { + if disk.Bootable { + return api.DISK_TYPE_SYS + } + return api.DISK_TYPE_DATA +} + +func (disk *SDisk) GetFsFormat() string { + return "" +} + +func (disk *SDisk) GetIsNonPersistent() bool { + return false +} + +func (disk *SDisk) GetDriver() string { + return "scsi" +} + +func (disk *SDisk) GetCacheMode() string { + return "none" +} + +func (disk *SDisk) GetMountpoint() string { + return "" +} + +func (region *SRegion) CreateDisk(imageRef string, volumeType string, name string, sizeGb int, desc string, projectId string) (*SDisk, error) { + params := map[string]map[string]interface{}{ + "volume": { + "size": sizeGb, + "volume_type": volumeType, + "name": name, + "description": desc, + }, + } + if len(imageRef) > 0 { + params["volume"]["imageRef"] = imageRef + } + resp, err := region.bsCreate(projectId, "/volumes", params) + if err != nil { + return nil, errors.Wrap(err, "bsCreate") + } + + disk := &SDisk{} + err = resp.Unmarshal(disk, "volume") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + //这里由于不好初始化disk的storage就手动循环了,如果是通过镜像创建,有个下载过程,比较慢,等待时间较长 + startTime := time.Now() + timeout := time.Minute * 10 + //若是通过镜像创建,需要先下载镜像,需要的时间更长 + if len(imageRef) > 0 { + timeout = time.Minute * 30 + } + for time.Now().Sub(startTime) < timeout { + disk, err = region.GetDisk(disk.GetGlobalId()) + if err != nil { + return nil, errors.Wrapf(err, "GetDisk(%s)", disk.GetGlobalId()) + } + log.Debugf("disk status %s expect %s", disk.GetStatus(), api.DISK_READY) + status := disk.GetStatus() + if status == api.DISK_READY { + break + } + if status == api.DISK_ALLOC_FAILED { + messages, _ := region.GetMessages(disk.Id) + if len(messages) > 0 { + return nil, fmt.Errorf("allocate disk %s failed, status is %s message: %s", disk.Name, disk.Status, messages[0].UserMessage) + } + return nil, fmt.Errorf("allocate disk %s failed, status is %s", disk.Name, disk.Status) + } + time.Sleep(time.Second * 10) + } + if disk.GetStatus() != api.DISK_READY { + return nil, fmt.Errorf("timeout for waitting disk ready, current status: %s", disk.Status) + } + return disk, nil +} + +func (region *SRegion) GetDisk(diskId string) (*SDisk, error) { + resource := fmt.Sprintf("/volumes/%s", diskId) + resp, err := region.bsGet(resource) + if err != nil { + return nil, errors.Wrap(err, "bsGet") + } + disk := &SDisk{} + err = resp.Unmarshal(disk, "volume") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return disk, nil +} + +func (region *SRegion) DeleteDisk(diskId string) error { + resource := fmt.Sprintf("/volumes/%s", diskId) + _, err := region.bsDelete(resource) + return err +} + +func (region *SRegion) ResizeDisk(diskId string, sizeMb int64) error { + params := map[string]map[string]interface{}{ + "os-extend": { + "new_size": sizeMb / 1024, + }, + } + resource := fmt.Sprintf("/volumes/%s/action", diskId) + _, err := region.bsPost(resource, params) + return err +} + +func (region *SRegion) ResetDisk(diskId, snapshotId string) error { + params := map[string]map[string]interface{}{ + "revert": { + "snapshot_id": snapshotId, + }, + } + resource := fmt.Sprintf("/volumes/%s/action", diskId) + _, err := region.bsPost(resource, params) + return err +} + +func (disk *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := disk.storage.zone.region.CreateSnapshot(disk.Id, name, desc) + if err != nil { + return nil, err + } + return snapshot, cloudprovider.WaitStatus(snapshot, api.SNAPSHOT_READY, time.Second*5, time.Minute*5) +} + +func (disk *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + return disk.storage.zone.region.GetISnapshotById(snapshotId) +} + +func (disk *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := disk.storage.zone.region.GetSnapshots(disk.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetSnapshots(%s)", disk.Id) + } + isnapshots := []cloudprovider.ICloudSnapshot{} + for i := range snapshots { + snapshots[i].region = disk.storage.zone.region + isnapshots = append(isnapshots, &snapshots[i]) + } + return isnapshots, nil +} + +func (disk *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return disk.Id, disk.storage.zone.region.ResetDisk(disk.Id, snapshotId) +} + +func (disk *SDisk) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (disk *SDisk) GetCreatedAt() time.Time { + return disk.CreatedAt +} + +func (disk *SDisk) GetExpiredAt() time.Time { + return time.Time{} +} + +func (disk *SDisk) GetAccessPath() string { + return "" +} + +func (disk *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (disk *SDisk) GetProjectId() string { + return disk.TenantId +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/doc.go new file mode 100644 index 0000000000..85696d927f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 openstack // import "yunion.io/x/cloudmux/pkg/multicloud/openstack" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/eip.go new file mode 100644 index 0000000000..11f7dbfbf9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/eip.go @@ -0,0 +1,335 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + "net/url" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SPortDetail struct { + Status string `json:"status"` + Name string `json:"name"` + AdminStateUp bool `json:"admin_state_up"` + NetworkId string `json:"network_id"` + DeviceOwner string `json:"device_owner"` + MacAddress string `json:"mac_address"` + DeviceId string `json:"device_id"` +} + +type SEipAddress struct { + region *SRegion + multicloud.SEipBase + OpenStackTags + + RouterId string `json:"router_id"` + Status string `json:"status"` + Description string `json:"description"` + Tags []string `json:"tags"` + TenantId string `json:"tenant_id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + FloatingNetworkId string `json:"floating_network_id"` + PortDetails SPortDetail `json:"port_details"` + FixedIPAddress string `json:"fixed_ip_address"` + FloatingIPAddress string `json:"floating_ip_address"` + RevisionNumber int `json:"revision_number"` + ProjectId string `json:"project_id"` + PortId string `json:"port_id"` + Id string `json:"id"` + QosPolicyId string `json:"qos_policy_id"` +} + +func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { + resource := fmt.Sprintf("/v2.0/floatingips/%s", eipId) + resp, err := region.vpcGet(resource) + if err != nil { + return nil, err + } + eip := &SEipAddress{region: region} + err = resp.Unmarshal(eip, "floatingip") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return eip, nil +} + +func (region *SRegion) GetEipByIp(ip string) (*SEipAddress, error) { + eips, err := region.GetEips(ip) + if err != nil { + return nil, errors.Wrap(err, "GetEips") + } + if len(eips) == 1 { + eips[0].region = region + return &eips[0], nil + } + if len(eips) == 0 { + return nil, cloudprovider.ErrNotFound + } + return nil, cloudprovider.ErrDuplicateId +} + +func (region *SRegion) GetEips(ip string) ([]SEipAddress, error) { + resource := "/v2.0/floatingips" + eips := []SEipAddress{} + query := url.Values{} + if len(ip) > 0 { + query.Set("floating_ip_address", ip) + } + for { + part := struct { + Floatingips []SEipAddress + FloatingipsLinks SNextLinks + }{} + resp, err := region.vpcList(resource, query) + if err != nil { + return nil, errors.Wrap(err, "vpcList") + } + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + eips = append(eips, part.Floatingips...) + marker := part.FloatingipsLinks.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return eips, nil +} + +func (eip *SEipAddress) GetId() string { + return eip.Id +} + +func (eip *SEipAddress) GetName() string { + return eip.FloatingIPAddress +} + +func (eip *SEipAddress) GetGlobalId() string { + return eip.Id +} + +func (eip *SEipAddress) GetStatus() string { + switch eip.Status { + case "ACTIVE": + return api.EIP_STATUS_READY + case "DOWN": //实际是未绑定在机器上 + return api.EIP_STATUS_READY + case "ERROR": + return api.EIP_STATUS_UNKNOWN + default: + log.Errorf("Unknown eip %s status %s", eip.Id, eip.Status) + return api.EIP_STATUS_UNKNOWN + } +} + +func (eip *SEipAddress) Refresh() error { + _eip, err := eip.region.GetEip(eip.Id) + if err != nil { + return err + } + return jsonutils.Update(eip, _eip) +} + +func (eip *SEipAddress) IsEmulated() bool { + return false +} + +func (eip *SEipAddress) GetIpAddr() string { + return eip.FloatingIPAddress +} + +func (eip *SEipAddress) GetMode() string { + return api.EIP_MODE_STANDALONE_EIP +} + +func (eip *SEipAddress) GetAssociationType() string { + if len(eip.GetAssociationExternalId()) > 0 { + return api.EIP_ASSOCIATE_TYPE_SERVER + } + return "" +} + +func (eip *SEipAddress) GetAssociationExternalId() string { + if len(eip.PortDetails.DeviceId) > 0 { + return eip.PortDetails.DeviceId + } + if len(eip.PortId) > 0 { + port, err := eip.region.GetPort(eip.PortId) + if err != nil { + log.Errorf("failed to get eip port %s info", eip.PortId) + return "" + } + return port.DeviceID + } + return "" +} + +func (eip *SEipAddress) GetBillingType() string { + return "" +} + +func (eip *SEipAddress) GetCreatedAt() time.Time { + return eip.CreatedAt +} + +func (eip *SEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} + +func (eip *SEipAddress) Delete() error { + return eip.region.DeleteEip(eip.Id) +} + +func (eip *SEipAddress) GetBandwidth() int { + return 0 +} + +func (eip *SEipAddress) GetINetworkId() string { + networks, err := eip.region.GetNetworks(eip.FloatingNetworkId) + if err != nil { + log.Errorf("failed to find vpc id for eip %s(%s), error: %v", eip.FloatingIPAddress, eip.FloatingNetworkId, err) + return "" + } + for _, network := range networks { + for _, pool := range network.AllocationPools { + if pool.Contains(eip.FloatingIPAddress) { + network.AllocationPools = []AllocationPool{pool} + return network.GetGlobalId() + } + } + } + log.Errorf("failed to find eip %s(%s) networkId", eip.FloatingIPAddress, eip.FloatingNetworkId) + return "" +} + +func (eip *SEipAddress) GetInternetChargeType() string { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC +} + +func (eip *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { + return eip.region.AssociateEip(conf.InstanceId, eip.Id) +} + +func (eip *SEipAddress) Dissociate() error { + return eip.region.DisassociateEip(eip.Id) +} + +func (eip *SEipAddress) ChangeBandwidth(bw int) error { + return cloudprovider.ErrNotSupported +} + +func (eip *SEipAddress) GetProjectId() string { + return eip.ProjectId +} + +func (region *SRegion) CreateEip(vpcId, networkId, ip string, projectId string) (*SEipAddress, error) { + _, networkId = getNetworkId(networkId) + params := map[string]map[string]string{ + "floatingip": map[string]string{ + "floating_network_id": vpcId, + "subnet_id": networkId, + }, + } + if len(projectId) > 0 { + params["floatingip"]["tenant_id"] = projectId + } + if len(ip) > 0 { + params["floatingip"]["floating_ip_address"] = ip + } + resource := "/v2.0/floatingips" + resp, err := region.vpcPost(resource, params) + if err != nil { + return nil, errors.Wrap(err, "vpcPost") + } + eip := &SEipAddress{region: region} + err = resp.Unmarshal(eip, "floatingip") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return eip, nil +} + +func (region *SRegion) AssociateEip(instanceId, eipId string) error { + instance, err := region.GetInstance(instanceId) + if err != nil { + return err + } + for networkName, address := range instance.Addresses { + for i := 0; i < len(address); i++ { + if instance.Addresses[networkName][i].Type == "fixed" { + ports, err := region.GetPorts(instance.Addresses[networkName][i].MacAddr, "") + if err != nil { + return err + } + + if len(ports) == 1 { + params := map[string]map[string]string{ + "floatingip": { + "port_id": ports[0].ID, + }, + } + resource := "/v2.0/floatingips/" + eipId + _, err = region.vpcUpdate(resource, params) + return err + } + + if len(ports) == 0 { + log.Errorf("failed to found port for instance nic %s(%s)", instance.Addresses[networkName][i].Addr, instance.Addresses[networkName][i].MacAddr) + return cloudprovider.ErrNotFound + } + return cloudprovider.ErrDuplicateId + } + } + } + return fmt.Errorf("failed to found instnace %s nics for binding eip", instanceId) +} + +func (region *SRegion) AssociateEipWithPortId(portid, eipId string) error { + params := map[string]map[string]string{ + "floatingip": { + "port_id": portid, + }, + } + _, err := region.vpcUpdate("/v2.0/floatingips/"+eipId, jsonutils.Marshal(params)) + return err +} + +func (region *SRegion) DisassociateEip(eipId string) error { + params, _ := jsonutils.Parse([]byte(`{ + "floatingip": { + "port_id": null, + }, + }`)) + _, err := region.vpcUpdate("/v2.0/floatingips/"+eipId, params) + return err +} + +func (region *SRegion) DeleteEip(eipId string) error { + resource := "/v2.0/floatingips/" + eipId + _, err := region.vpcDelete(resource) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/flavor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/flavor.go new file mode 100644 index 0000000000..f11b36e543 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/flavor.go @@ -0,0 +1,285 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + "net/url" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SFlavor struct { + multicloud.SServerSku + OpenStackTags + region *SRegion + + Id string + Disk int + Ephemeral int + ExtraSpecs ExtraSpecs + OriginalName string + Name string + RAM int + Swap string + Vcpus int +} + +func (region *SRegion) GetFlavors() ([]SFlavor, error) { + resource := "/flavors/detail" + flavors := []SFlavor{} + query := url.Values{} + for { + resp, err := region.ecsList(resource, query) + if err != nil { + return nil, errors.Wrap(err, "ecsList") + } + part := struct { + Flavors []SFlavor + FlavorsLinks SNextLinks + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + flavors = append(flavors, part.Flavors...) + + marker := part.FlavorsLinks.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return flavors, nil +} + +func (region *SRegion) GetFlavor(flavorId string) (*SFlavor, error) { + resource := fmt.Sprintf("/flavors/%s", flavorId) + resp, err := region.ecsGet(resource) + if err != nil { + return nil, errors.Wrap(err, "ecsGet") + } + flavor := &SFlavor{region: region} + err = resp.Unmarshal(flavor, "flavor") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return flavor, nil +} + +func (region *SRegion) SyncFlavor(name string, cpu, memoryMb, diskGB int) (string, error) { + flavor, err := region.syncFlavor(name, cpu, memoryMb, diskGB) + if err != nil { + return "", errors.Wrapf(err, "syncFlavor") + } + return flavor.Id, nil +} + +func (region *SRegion) syncFlavor(name string, cpu, memoryMb, diskGB int) (*SFlavor, error) { + flavors, err := region.GetFlavors() + if err != nil { + return nil, errors.Wrapf(err, "GetFlavors") + } + + if cpu == 0 && memoryMb == 0 { + return nil, fmt.Errorf("failed to find instance type %s", name) + } + + for i := range flavors { + flavor := flavors[i] + flavorName := flavor.GetName() + if (len(name) == 0 || flavorName == name || flavorName == fmt.Sprintf("%s-%d", name, diskGB)) && + flavor.GetCpuCoreCount() == cpu && + flavor.GetMemorySizeMB() == memoryMb && + diskGB <= flavor.GetSysDiskMaxSizeGB() { + return &flavor, nil + } + } + if len(name) == 0 { + name = fmt.Sprintf("ecs.g1.c%dm%d", cpu, memoryMb/1024) + } + name = fmt.Sprintf("%s-%d", name, diskGB) + flavor, err := region.CreateFlavor(name, cpu, memoryMb, diskGB) + if err != nil { + return nil, errors.Wrap(err, "CreateFlavor") + } + return flavor, nil +} + +func (region *SRegion) CreateISku(opts *cloudprovider.SServerSkuCreateOption) (cloudprovider.ICloudSku, error) { + flavor, err := region.CreateFlavor(opts.Name, opts.CpuCount, opts.VmemSizeMb, opts.SysDiskMaxSizeGb) + if err != nil { + return nil, errors.Wrapf(err, "CreateFlavor") + } + return flavor, nil +} + +func (region *SRegion) CreateFlavor(name string, cpu int, memoryMb int, diskGB int) (*SFlavor, error) { + if diskGB <= 0 { + diskGB = 30 + } + params := map[string]map[string]interface{}{ + "flavor": { + "name": name, + "ram": memoryMb, + "vcpus": cpu, + "disk": diskGB, + }, + } + resp, err := region.ecsPost("/flavors", params) + if err != nil { + return nil, errors.Wrap(err, "ecsPost") + } + flavor := &SFlavor{region: region} + err = resp.Unmarshal(flavor, "flavor") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return flavor, nil +} + +func (region *SRegion) DeleteFlavor(flavorId string) error { + _, err := region.ecsDelete("/flavors/" + flavorId) + return err +} + +func (flavor *SFlavor) Delete() error { + return flavor.region.DeleteFlavor(flavor.Id) +} + +func (flavor *SFlavor) IsEmulated() bool { + return false +} + +func (flavor *SFlavor) Refresh() error { + _flavor, err := flavor.region.GetFlavor(flavor.Id) + if err != nil { + return err + } + return jsonutils.Update(flavor, _flavor) +} + +func (flavor *SFlavor) GetName() string { + if len(flavor.OriginalName) > 0 { + return flavor.OriginalName + } + return flavor.Name +} + +func (flavor *SFlavor) GetId() string { + return flavor.Id +} + +func (flavor *SFlavor) GetGlobalId() string { + return flavor.Id +} + +func (flavor *SFlavor) GetInstanceTypeFamily() string { + return api.InstanceFamilies[api.SkuCategoryGeneralPurpose] +} + +func (flavor *SFlavor) GetInstanceTypeCategory() string { + return api.SkuCategoryGeneralPurpose +} + +func (flavor *SFlavor) GetPrepaidStatus() string { + return api.SkuStatusSoldout +} + +func (flavor *SFlavor) GetPostpaidStatus() string { + return api.SkuStatusAvailable +} + +func (flavor *SFlavor) GetCpuArch() string { + return "" +} + +func (flavor *SFlavor) GetCpuCoreCount() int { + return int(flavor.Vcpus) +} + +func (flavor *SFlavor) GetMemorySizeMB() int { + return flavor.RAM +} + +func (flavor *SFlavor) GetOsName() string { + return "Any" +} + +func (flavor *SFlavor) GetSysDiskResizable() bool { + return true +} + +func (flavor *SFlavor) GetSysDiskType() string { + return "" +} + +func (flavor *SFlavor) GetSysDiskMinSizeGB() int { + return 0 +} + +func (flavor *SFlavor) GetSysDiskMaxSizeGB() int { + return flavor.Disk +} + +func (flavor *SFlavor) GetAttachedDiskType() string { + return "iscsi" +} + +func (flavor *SFlavor) GetAttachedDiskSizeGB() int { + return 0 +} + +func (flavor *SFlavor) GetAttachedDiskCount() int { + return 0 +} + +func (flavor *SFlavor) GetDataDiskTypes() string { + return "" +} + +func (flavor *SFlavor) GetDataDiskMaxCount() int { + return 6 +} + +func (flavor *SFlavor) GetNicType() string { + return "vpc" +} + +func (flavor *SFlavor) GetNicMaxCount() int { + return 1 +} + +func (flavor *SFlavor) GetGpuAttachable() bool { + return false +} + +func (flavor *SFlavor) GetGpuSpec() string { + return "" +} + +func (flavor *SFlavor) GetGpuCount() int { + return 0 +} + +func (flavor *SFlavor) GetGpuMaxCount() int { + return 0 +} diff --git a/pkg/multicloud/openstack/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/host.go similarity index 100% rename from pkg/multicloud/openstack/host.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/host.go diff --git a/pkg/multicloud/openstack/hypervisor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/hypervisor.go similarity index 98% rename from pkg/multicloud/openstack/hypervisor.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/hypervisor.go index b06ddad0f9..70569aed30 100644 --- a/pkg/multicloud/openstack/hypervisor.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/hypervisor.go @@ -23,9 +23,9 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type CpuInfo struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/image.go new file mode 100644 index 0000000000..1af3cb80b3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/image.go @@ -0,0 +1,335 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "context" + "fmt" + "io" + "net/url" + "strings" + "time" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" + "yunion.io/x/onecloud/pkg/util/qemuimg" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +const ( + QUEUED = "queued" // The Image service reserved an image ID for the image in the catalog but did not yet upload any image data. + SAVING = "saving" // The Image service is in the process of saving the raw data for the image into the backing store. + ACTIVE = "active" // The image is active and ready for consumption in the Image service. + KILLED = "killed" // An image data upload error occurred. + DELETED = "deleted" // The Image service retains information about the image but the image is no longer available for use. + PENDING_DELETE = "pending_delete" // Similar to the deleted status. An image in this state is not recoverable. + DEACTIVATED = "deactivated" // The image data is not available for use. + UPLOADING = "uploading" // Data has been staged as part of the interoperable image import process. It is not yet available for use. (Since Image API 2.6) + IMPORTING = "importing" // The image data is being processed as part of the interoperable image import process, but is not yet available for use. (Since Image API 2.6) +) + +type SImage struct { + multicloud.SImageBase + storageCache *SStoragecache + OpenStackTags + + // normalized image info + imgInfo *imagetools.ImageInfo + + Status string + Name string + Tags []string + ContainerFormat string + CreatedAt time.Time + DiskFormat string + UpdatedAt time.Time + Visibility string + Self string + MinDisk int + Protected bool + Id string + File string + Checksum string + OsHashAlgo string + OsHashValue string + OsHidden bool + OsDistro string + OsType string + Owner string + Size int + MinRAM int + Schema string + VirtualSize int + visibility string +} + +func (image *SImage) GetMinRamSizeMb() int { + return image.MinRAM +} + +func (region *SRegion) GetImages(name string, status string, imageId string) ([]SImage, error) { + query := url.Values{} + if len(status) > 0 { + query.Set("status", status) + } + if len(name) > 0 { + query.Set("name", name) + } + if len(imageId) > 0 { + query.Set("id", imageId) + } + images := []SImage{} + resource := "/v2/images" + marker := "" + for { + if len(marker) > 0 { + query.Set("marker", marker) + } + resp, err := region.imageList(resource, query) + if err != nil { + return nil, errors.Wrap(err, "imageList") + } + part := struct { + Images []SImage + Next string + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + images = append(images, part.Images...) + if len(part.Next) == 0 { + break + } + if len(part.Next) > 0 { + href, err := url.Parse(part.Next) + if err != nil { + marker = "" + } else { + marker = href.Query().Get("marker") + } + } + if len(marker) == 0 { + break + } + } + return images, nil +} + +func (image *SImage) GetId() string { + return image.Id +} + +func (image *SImage) GetName() string { + return image.Name +} + +func (image *SImage) IsEmulated() bool { + return false +} + +func (image *SImage) GetGlobalId() string { + return image.Id +} + +func (image *SImage) Delete(ctx context.Context) error { + return image.storageCache.region.DeleteImage(image.Id) +} + +func (image *SImage) GetStatus() string { + switch image.Status { + case QUEUED, SAVING, UPLOADING, IMPORTING: + return api.CACHED_IMAGE_STATUS_CACHING + case ACTIVE: + return api.CACHED_IMAGE_STATUS_ACTIVE + case DELETED, DEACTIVATED, PENDING_DELETE, KILLED: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + default: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (image *SImage) GetImageStatus() string { + switch image.Status { + case QUEUED, SAVING, UPLOADING, IMPORTING: + return cloudprovider.IMAGE_STATUS_SAVING + case ACTIVE: + return cloudprovider.IMAGE_STATUS_ACTIVE + case DELETED, DEACTIVATED, PENDING_DELETE: + return cloudprovider.IMAGE_STATUS_DELETED + case KILLED: + return cloudprovider.IMAGE_STATUS_KILLED + default: + return cloudprovider.IMAGE_STATUS_DELETED + } +} + +func (image *SImage) Refresh() error { + _image, err := image.storageCache.region.GetImage(image.Id) + if err != nil { + return errors.Wrap(err, "GetImage") + } + return jsonutils.Update(image, _image) +} + +func (image *SImage) GetImageType() cloudprovider.TImageType { + return cloudprovider.ImageTypeSystem +} + +func (image *SImage) GetPublicScope() rbacutils.TRbacScope { + switch image.Visibility { + case "private": + return rbacutils.ScopeNone + default: + return rbacutils.ScopeSystem + } +} + +func (image *SImage) GetProjectId() string { + return image.Owner +} + +func (image *SImage) GetSizeByte() int64 { + return int64(image.Size) +} + +func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if self.imgInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(self.Name, "", self.OsType, "", "") + self.imgInfo = &imgInfo + } + + return self.imgInfo +} + +func (image *SImage) GetFullOsName() string { + return image.Name +} + +func (image *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(image.getNormalizedImageInfo().OsType) +} + +func (image *SImage) GetOsDist() string { + return image.getNormalizedImageInfo().OsDistro +} + +func (image *SImage) GetOsVersion() string { + return image.getNormalizedImageInfo().OsVersion +} + +func (image *SImage) GetOsArch() string { + return image.getNormalizedImageInfo().OsArch +} + +func (image *SImage) GetOsLang() string { + return image.getNormalizedImageInfo().OsLang +} + +func (image *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(image.getNormalizedImageInfo().OsBios) +} + +func (image *SImage) GetMinOsDiskSizeGb() int { + if image.MinDisk > 0 { + return image.MinDisk + } + return 30 +} + +func (image *SImage) GetImageFormat() string { + return image.DiskFormat +} + +func (image *SImage) GetCreatedAt() time.Time { + return image.CreatedAt +} + +func (region *SRegion) GetImage(imageId string) (*SImage, error) { + resource := "/v2/images/" + imageId + resp, err := region.imageGet(resource) + if err != nil { + return nil, errors.Wrapf(err, "imageGet(%s)", resource) + } + image := &SImage{} + err = resp.Unmarshal(image) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return image, nil +} + +func (image *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return image.storageCache +} + +func (region *SRegion) DeleteImage(imageId string) error { + _, err := region.imageDelete("/v2/images/" + imageId) + return err +} + +func (region *SRegion) GetImageStatus(imageId string) (string, error) { + image, err := region.GetImage(imageId) + if err != nil { + return "", err + } + return image.Status, nil +} + +func (region *SRegion) GetImageByName(name string) (*SImage, error) { + images, err := region.GetImages(name, "", "") + if err != nil { + return nil, err + } + if len(images) == 0 { + return nil, cloudprovider.ErrNotFound + } + return &images[0], nil +} + +func (region *SRegion) CreateImage(imageName string, osType string, osDist string, minDiskGb int, minRam int, size int64, body io.Reader, callback func(progress float32)) (*SImage, error) { + params := map[string]interface{}{ + "container_format": "bare", + "disk_format": string(qemuimg.QCOW2), + "name": imageName, + "min_disk": minDiskGb, + "min_ram": minRam, + "os_type": strings.ToLower(osType), + "os_distro": osDist, + "hw_qemu_guest_agent": "yes", + } + + resp, err := region.imagePost("/v2/images", params) + if err != nil { + return nil, errors.Wrap(err, "imagePost") + } + image := &SImage{} + err = resp.Unmarshal(image) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + url := fmt.Sprintf("/v2/images/%s/file", image.Id) + err = region.imageUpload(url, size, body, callback) + if err != nil { + return nil, errors.Wrap(err, "imageUpload") + } + return image, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/instance.go new file mode 100644 index 0000000000..4c88090608 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/instance.go @@ -0,0 +1,1167 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "context" + "fmt" + "net/url" + "time" + + "gopkg.in/fatih/set.v0" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +const ( + INSTANCE_STATUS_ACTIVE = "ACTIVE" //The server is active. + INSTANCE_STATUS_BUILD = "BUILD" //The server has not finished the original build process. + INSTANCE_STATUS_DELETED = "DELETED" //The server is permanently deleted. + INSTANCE_STATUS_ERROR = "ERROR" //The server is in error. + INSTANCE_STATUS_HARD_REBOOT = "HARD_REBOOT" //The server is hard rebooting. This is equivalent to pulling the power plug on a physical server, plugging it back in, and rebooting it. + INSTANCE_STATUS_MIGRATING = "MIGRATING" //The server is being migrated to a new host. + INSTANCE_STATUS_PASSWORD = "PASSWORD" //The password is being reset on the server. + INSTANCE_STATUS_PAUSED = "PAUSED" //In a paused state, the state of the server is stored in RAM.A paused server continues to run in frozen state. + INSTANCE_STATUS_REBOOT = "REBOOT" //The server is in a soft reboot state. A reboot command was passed to the operating system. + INSTANCE_STATUS_REBUILD = "REBUILD" //The server is currently being rebuilt from an image. + INSTANCE_STATUS_RESCUE = "RESCUE" //The server is in rescue mode. A rescue image is running with the original server image attached. + INSTANCE_STATUS_RESIZE = "RESIZE" //Server is performing the differential copy of data that changed during its initial copy. Server is down for this stage. + INSTANCE_STATUS_REVERT_RESIZE = "REVERT_RESIZE" //The resize or migration of a server failed for some reason. The destination server is being cleaned up and the original source server is restarting. + INSTANCE_STATUS_SHELVED = "SHELVED" // The server is in shelved state. Depending on the shelve offload time, the server will be automatically shelved offloaded. + INSTANCE_STATUS_SHELVED_OFFLOADED = "SHELVED_OFFLOADED" // The shelved server is offloaded (removed from the compute host) and it needs unshelved action to be used again. + INSTANCE_STATUS_SHUTOFF = "SHUTOFF" //The server is powered off and the disk image still persists. + INSTANCE_STATUS_SOFT_DELETED = "SOFT_DELETED" //The server is marked as deleted but the disk images are still available to restore. + INSTANCE_STATUS_SUSPENDED = "SUSPENDED" //The server is suspended, either by request or necessity. This status appears for only the XenServer/XCP, KVM, and ESXi hypervisors. Administrative users can suspend an instance if it is infrequently used or to perform system maintenance. When you suspend an instance, its VM state is stored on disk, all memory is written to disk, and the virtual machine is stopped. Suspending an instance is similar to placing a device in hibernation; memory and vCPUs become available to create other instances. + INSTANCE_STATUS_UNKNOWN = "UNKNOWN" //The state of the server is unknown. Contact your cloud provider. + INSTANCE_STATUS_VERIFY_RESIZE = "VERIFY_RESIZE" //System is awaiting confirmation that the server is operational after a move or resize. +) + +type SPrivate struct { + MacAddr string `json:"OS-EXT-IPS-MAC:mac_addr,omitempty"` + Addr string `json:"OS-EXT-IPS:type,omitempty"` + Version int +} + +type SecurityGroup struct { + Id string + Name string + Description string +} + +type ExtraSpecs struct { + CpuPolicy string `json:"hw:cpu_policy,omitempty"` + MemPageSize string `json:"hw:mem_page_size,omitempty"` +} + +type Resource struct { + Id string + Links []Link +} + +type VolumesAttached struct { + Id string + DeleteOnTermination bool +} + +type SFault struct { + Message string + Code int + Details string +} + +type SInstance struct { + multicloud.SInstanceBase + OpenStackTags + host *SHypervisor + + imageObj *SImage + + DiskConfig string `json:"OS-DCF:diskConfig,omitempty"` + AvailabilityZone string `json:"OS-EXT-AZ:availability_zone,omitempty"` + Host string `json:"OS-EXT-SRV-ATTR:host,omitempty"` + Hostname string `json:"OS-EXT-SRV-ATTR:hostname,omitempty"` + HypervisorHostname string `json:"OS-EXT-SRV-ATTR:hypervisor_hostname,omitempty"` + InstanceName string `json:"OS-EXT-SRV-ATTR:instance_name,omitempty"` + KernelId string `json:"OS-EXT-SRV-ATTR:kernel_id,omitempty"` + LaunchIndex int `json:"OS-EXT-SRV-ATTR:launch_index,omitempty"` + RamdiskId string `json:"OS-EXT-SRV-ATTR:ramdisk_id,omitempty"` + ReservationId string `json:"OS-EXT-SRV-ATTR:reservation_id,omitempty"` + RootDeviceName string `json:"OS-EXT-SRV-ATTR:root_device_name,omitempty"` + UserData string `json:"OS-EXT-SRV-ATTR:user_data,omitempty"` + PowerState int `json:"OS-EXT-STS:power_state,omitempty"` + TaskState string `json:"OS-EXT-STS:task_state,omitempty"` + VmState string `json:"OS-EXT-STS:vm_state,omitempty"` + LaunchedAt time.Time `json:"OS-SRV-USG:launched_at,omitempty"` + TerminatedAt string `json:"OS-SRV-USG:terminated_at,omitempty"` + + AccessIPv4 string + AccessIPv6 string + Addresses map[string][]SInstanceNic + ConfigDrive string + Created time.Time + Description string + Flavor SFlavor + HostId string + HostStatus string + Id string + Image jsonutils.JSONObject `json:"image"` //有可能是字符串 + KeyName string + Links []Link + Locked bool + Name string + VolumesAttached []VolumesAttached `json:"os-extended-volumes:volumes_attached,omitempty"` + Progress int + SecurityGroups []SecurityGroup + Status string + Tags []string + TenantId string + TrustedImageCertificates []string + Updated time.Time + UserId string + Fault SFault +} + +func (region *SRegion) GetSecurityGroupsByInstance(instanceId string) ([]SecurityGroup, error) { + resource := fmt.Sprintf("/servers/%s/os-security-groups", instanceId) + resp, err := region.ecsGet(resource) + if err != nil { + return nil, errors.Wrap(err, "ecsGet") + } + secgroups := []SecurityGroup{} + err = resp.Unmarshal(&secgroups, "security_groups") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return secgroups, nil +} + +func (region *SRegion) GetInstances(host string) ([]SInstance, error) { + instances := []SInstance{} + resource := "/servers/detail" + query := url.Values{} + query.Set("all_tenants", "True") + for { + resp, err := region.ecsList(resource, query) + if err != nil { + return nil, errors.Wrap(err, "ecsList") + } + part := struct { + Servers []SInstance + ServersLinks SNextLinks + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + for i := range part.Servers { + if len(host) == 0 || part.Servers[i].Host == host || part.Servers[i].HypervisorHostname == host { + instances = append(instances, part.Servers[i]) + } + } + marker := part.ServersLinks.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return instances, nil +} + +func (region *SRegion) GetInstance(instanceId string) (*SInstance, error) { + resource := "/servers/" + instanceId + resp, err := region.ecsGet(resource) + if err != nil { + return nil, errors.Wrap(err, "ecsGet") + } + instance := &SInstance{} + err = resp.Unmarshal(instance, "server") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarsha") + } + return instance, nil +} + +func (instance *SInstance) GetSecurityGroupIds() ([]string, error) { + secgroupIds := []string{} + secgroups, err := instance.host.zone.region.GetSecurityGroupsByInstance(instance.Id) + if err != nil { + return nil, err + } + for _, secgroup := range secgroups { + secgroupIds = append(secgroupIds, secgroup.Id) + } + return secgroupIds, nil +} + +func (instance *SInstance) GetIHost() cloudprovider.ICloudHost { + return instance.host +} + +func (instance *SInstance) GetId() string { + return instance.Id +} + +func (instance *SInstance) GetName() string { + return instance.Name +} + +func (instance *SInstance) GetHostname() string { + return instance.Hostname +} + +func (instance *SInstance) GetGlobalId() string { + return instance.Id +} + +func (instance *SInstance) IsEmulated() bool { + return false +} + +func (instance *SInstance) fetchFlavor() error { + if len(instance.Flavor.Id) > 0 && instance.Flavor.Vcpus == 0 { + flavor, err := instance.host.zone.region.GetFlavor(instance.Flavor.Id) + if err != nil { + return err + } + instance.Flavor = *flavor + } + return nil +} + +func (instance *SInstance) GetInstanceType() string { + err := instance.fetchFlavor() + if err != nil { + return "" + } + return instance.Flavor.GetName() +} + +func (instance *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks := []SDisk{} + hasSysDisk := false + for i := 0; i < len(instance.VolumesAttached); i++ { + disk, err := instance.host.zone.region.GetDisk(instance.VolumesAttached[i].Id) + if err != nil { + return nil, errors.Wrapf(err, "GetDisk(%s)", instance.VolumesAttached[i].Id) + } + disks = append(disks, *disk) + if disk.GetDiskType() == api.DISK_TYPE_SYS { + hasSysDisk = true + } + } + idisks := []cloudprovider.ICloudDisk{} + for i := 0; i < len(disks); i++ { + store, err := instance.host.zone.getStorageByCategory(disks[i].VolumeType, disks[i].Host) + if err != nil { + return nil, errors.Wrapf(err, "getStorageByCategory(%s.%s)", disks[i].Id, disks[i].VolumeType) + } + disks[i].storage = store + idisks = append(idisks, &disks[i]) + } + + if !hasSysDisk { + store := &SNovaStorage{zone: instance.host.zone, host: instance.host} + disk := &SNovaDisk{storage: store, instanceId: instance.Id, region: instance.host.zone.region} + idisks = append([]cloudprovider.ICloudDisk{disk}, idisks...) + } + + return idisks, nil +} + +func (instance *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics, err := instance.host.zone.region.GetInstancePorts(instance.Id) + if err != nil { + return nil, errors.Wrap(err, "GetInstancePorts") + } + inics := []cloudprovider.ICloudNic{} + for i := range nics { + nics[i].region = instance.host.zone.region + inics = append(inics, &nics[i]) + } + return inics, nil +} + +func (instance *SInstance) GetVcpuCount() int { + err := instance.fetchFlavor() + if err != nil { + return 0 + } + return instance.Flavor.Vcpus +} + +func (instance *SInstance) GetVmemSizeMB() int { + err := instance.fetchFlavor() + if err != nil { + return 0 + } + return instance.Flavor.RAM +} + +func (instance *SInstance) GetBootOrder() string { + return "dcn" +} + +func (instance *SInstance) GetVga() string { + return "std" +} + +func (instance *SInstance) GetVdi() string { + return "vnc" +} + +func (instance *SInstance) getImage() *SImage { + if instance.imageObj == nil && instance.Image != nil { + imageId, _ := instance.Image.GetString("id") + if len(imageId) == 0 { + imageId, _ = instance.Image.GetString() + } + if len(imageId) > 0 { + image, _ := instance.host.zone.region.GetImage(imageId) + if image != nil { + instance.imageObj = image + } + } + } + return instance.imageObj +} + +func (instance *SInstance) GetOsType() cloudprovider.TOsType { + img := instance.getImage() + if img != nil { + return img.GetOsType() + } + return cloudprovider.OsTypeLinux +} + +func (instance *SInstance) GetFullOsName() string { + img := instance.getImage() + if img != nil { + return img.GetFullOsName() + } + return "" +} + +func (instance *SInstance) GetBios() cloudprovider.TBiosType { + img := instance.getImage() + if img != nil { + return img.GetBios() + } + return "BIOS" +} + +func (instance *SInstance) GetOsDist() string { + img := instance.getImage() + if img != nil { + return img.GetOsDist() + } + return "" +} + +func (instance *SInstance) GetOsVersion() string { + img := instance.getImage() + if img != nil { + return img.GetOsVersion() + } + return "" +} + +func (instance *SInstance) GetOsLang() string { + img := instance.getImage() + if img != nil { + return img.GetOsLang() + } + return "" +} + +func (instance *SInstance) GetOsArch() string { + img := instance.getImage() + if img != nil { + return img.GetOsArch() + } + return "" +} + +func (instance *SInstance) GetMachine() string { + return "pc" +} + +func (instance *SInstance) GetStatus() string { + switch instance.Status { + case INSTANCE_STATUS_ACTIVE, INSTANCE_STATUS_RESCUE: + return api.VM_RUNNING + case INSTANCE_STATUS_BUILD, INSTANCE_STATUS_PASSWORD: + return api.VM_DEPLOYING + case INSTANCE_STATUS_DELETED: + return api.VM_DELETING + case INSTANCE_STATUS_HARD_REBOOT, INSTANCE_STATUS_REBOOT: + return api.VM_STARTING + case INSTANCE_STATUS_MIGRATING: + return api.VM_MIGRATING + case INSTANCE_STATUS_PAUSED, INSTANCE_STATUS_SUSPENDED: + return api.VM_SUSPEND + case INSTANCE_STATUS_RESIZE: + return api.VM_CHANGE_FLAVOR + case INSTANCE_STATUS_VERIFY_RESIZE: + // API请求更改配置后,状态先回变更到 INSTANCE_STATUS_RESIZE 等待一会变成此状态 + // 到达此状态后需要再次发送确认请求,变更才会生效 + // 此状态不能和INSTANCE_STATUS_RESIZE返回一样,避免在INSTANCE_STATUS_RESIZE状态下发送确认请求,导致更改配置失败 + return api.VM_SYNC_CONFIG + case INSTANCE_STATUS_SHELVED, INSTANCE_STATUS_SHELVED_OFFLOADED, INSTANCE_STATUS_SHUTOFF, INSTANCE_STATUS_SOFT_DELETED: + return api.VM_READY + default: + return api.VM_UNKNOWN + } +} + +func (instance *SInstance) Refresh() error { + _instance, err := instance.host.zone.region.GetInstance(instance.Id) + if err != nil { + return err + } + return jsonutils.Update(instance, _instance) +} + +func (instance *SInstance) UpdateVM(ctx context.Context, name string) error { + if instance.Name != name { + params := map[string]map[string]string{ + "server": { + "name": name, + }, + } + resource := "/servers/" + instance.Id + _, err := instance.host.zone.region.ecsUpdate(resource, params) + return err + } + return nil +} + +func (instance *SInstance) GetHypervisor() string { + return api.HYPERVISOR_OPENSTACK +} + +func (instance *SInstance) StartVM(ctx context.Context) error { + err := instance.host.zone.region.StartVM(instance.Id) + if err != nil { + return errors.Wrapf(err, "StartVM(%s)", instance.Id) + } + return cloudprovider.WaitStatus(instance, api.VM_RUNNING, 10*time.Second, 8*time.Minute) +} + +func (instance *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + err := instance.host.zone.region.StopVM(instance.Id, opts.IsForce) + if err != nil { + return errors.Wrapf(err, "StopVM(%s)", instance.Id) + } + return cloudprovider.WaitStatus(instance, api.VM_READY, 10*time.Second, 8*time.Minute) +} + +func (region *SRegion) GetInstanceVNCUrl(instanceId string, origin bool) (*cloudprovider.ServerVncOutput, error) { + params := map[string]map[string]string{ + "remote_console": { + "protocol": "vnc", + "type": "novnc", + }, + } + resource := fmt.Sprintf("/servers/%s/remote-consoles", instanceId) + resp, err := region.ecsPost(resource, params) + if err != nil { + return nil, errors.Wrap(err, "ecsPost") + } + ret := &cloudprovider.ServerVncOutput{ + Protocol: "openstack", + InstanceId: instanceId, + Hypervisor: api.HYPERVISOR_OPENSTACK, + } + + ret.Url, err = resp.GetString("remote_console", "url") + if err != nil { + return nil, errors.Wrapf(err, "remote_console") + } + + if origin { + return ret, nil + } + + token := string([]byte(ret.Url)[len(ret.Url)-36:]) + vncUrl, _ := url.Parse(ret.Url) + ret.Url = fmt.Sprintf("ws://%s?token=%s", vncUrl.Host, token) + ret.Protocol = "vnc" + return ret, nil +} + +func (region *SRegion) GetInstanceVNC(instanceId string, origin bool) (*cloudprovider.ServerVncOutput, error) { + params := map[string]map[string]string{ + "os-getVNCConsole": { + "type": "novnc", + }, + } + resource := fmt.Sprintf("/servers/%s/action", instanceId) + resp, err := region.ecsPost(resource, params) + if err != nil { + return nil, errors.Wrap(err, "ecsPost") + } + ret := &cloudprovider.ServerVncOutput{ + Protocol: "openstack", + InstanceId: instanceId, + Hypervisor: api.HYPERVISOR_OPENSTACK, + } + + ret.Url, err = resp.GetString("console", "url") + if err != nil { + return nil, errors.Wrapf(err, "remote_console") + } + + if origin { + return ret, nil + } + + token := string([]byte(ret.Url)[len(ret.Url)-36:]) + vncUrl, _ := url.Parse(ret.Url) + ret.Url = fmt.Sprintf("ws://%s?token=%s", vncUrl.Host, token) + ret.Protocol = "vnc" + return ret, nil +} + +func (instance *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + origin := false + if input != nil { + origin = input.Origin + } + ret, err := instance.host.zone.region.GetInstanceVNCUrl(instance.Id, origin) + if err == nil { + return ret, nil + } + return instance.host.zone.region.GetInstanceVNC(instance.Id, origin) +} + +func (instance *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return instance.host.zone.region.DeployVM(instance.Id, name, password, publicKey, deleteKeypair, description) +} + +func (instance *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + return instance.Id, instance.host.zone.region.ReplaceSystemDisk(instance.Id, desc.ImageId, desc.Password, desc.PublicKey, desc.SysSizeGB) +} + +func (instance *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + if (len(config.InstanceType) > 0 && instance.GetInstanceType() != config.InstanceType) || instance.GetVcpuCount() != config.Cpu || instance.GetVmemSizeMB() != config.MemoryMB { + flavor, err := instance.host.zone.region.syncFlavor(config.InstanceType, config.Cpu, config.MemoryMB, 40) + if err != nil { + return errors.Wrapf(err, "syncFlavor(%s)", config.InstanceType) + } + // When resizing, instances must change flavor! + if flavor.Name == instance.Flavor.OriginalName { + return nil + } + return instance.host.zone.region.ChangeConfig(instance, flavor.Id) + } + return nil +} + +func (region *SRegion) ChangeConfig(instance *SInstance, flavorId string) error { + params := map[string]map[string]string{ + "resize": { + "flavorRef": flavorId, + }, + } + resource := fmt.Sprintf("/servers/%s/action", instance.Id) + _, err := region.ecsPost(resource, params) + if err != nil { + return errors.Wrap(err, "ecsPost") + } + err = cloudprovider.WaitStatus(instance, api.VM_SYNC_CONFIG, time.Second*3, time.Minute*4) + if err != nil { + return errors.Wrap(err, "WaitStatsAfterChangeConfig") + } + return region.instanceOperation(instance.Id, "confirmResize") +} + +func (instance *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return instance.host.zone.region.AttachDisk(instance.Id, diskId) +} + +func (instance *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return instance.host.zone.region.DetachDisk(instance.Id, diskId) +} + +func (region *SRegion) instanceOperation(instanceId, operate string) error { + params := map[string]string{operate: ""} + resource := fmt.Sprintf("/servers/%s/action", instanceId) + _, err := region.ecsPost(resource, params) + return err +} + +func (region *SRegion) doStopVM(instanceId string, isForce bool) error { + return region.instanceOperation(instanceId, "os-stop") +} + +func (region *SRegion) doDeleteVM(instanceId string) error { + return region.instanceOperation(instanceId, "forceDelete") +} + +func (region *SRegion) StartVM(instanceId string) error { + return region.instanceOperation(instanceId, "os-start") +} + +func (region *SRegion) StopVM(instanceId string, isForce bool) error { + return region.doStopVM(instanceId, isForce) +} + +func (region *SRegion) DeleteVM(instanceId string) error { + instance, err := region.GetInstance(instanceId) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return errors.Wrapf(err, "GetInstance(%s)", instanceId) + } + status := instance.GetStatus() + log.Debugf("Instance status on delete is %s", status) + if status != api.VM_READY { + log.Warningf("DeleteVM: vm status is %s expect %s", status, api.VM_READY) + } + return region.doDeleteVM(instanceId) +} + +func (region *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { + if len(password) > 0 { + params := map[string]map[string]string{ + "changePassword": { + "adminPass": password, + }, + } + resource := fmt.Sprintf("/servers/%s/action", instanceId) + _, err := region.ecsPost(resource, params) + return err + } + return nil +} + +func (instance *SInstance) DeleteVM(ctx context.Context) error { + err := instance.host.zone.region.DeleteVM(instance.Id) + if err != nil { + return errors.Wrapf(err, "instance.host.zone.region.DeleteVM(%s)", instance.Id) + } + return cloudprovider.WaitDeleted(instance, time.Second*5, time.Minute*10) +} + +func (region *SRegion) ReplaceSystemDisk(instanceId string, imageId string, passwd string, publicKey string, sysDiskSizeGB int) error { + params := map[string]map[string]string{ + "rebuild": { + "imageRef": imageId, + }, + } + + if len(publicKey) > 0 { + keypairName, err := region.syncKeypair(instanceId, publicKey) + if err != nil { + return err + } + params["rebuild"]["key_name"] = keypairName + } + + if len(passwd) > 0 { + params["rebuild"]["adminPass"] = passwd + } + resource := fmt.Sprintf("/servers/%s/action", instanceId) + _, err := region.ecsPost(resource, params) + return err +} + +func (region *SRegion) DetachDisk(instanceId string, diskId string) error { + resource := fmt.Sprintf("/servers/%s/os-volume_attachments/%s", instanceId, diskId) + _, err := region.ecsDelete(resource) + if err != nil { + return errors.Wrap(err, "ecsDelete") + } + status := "" + startTime := time.Now() + for time.Now().Sub(startTime) < time.Minute*10 { + disk, err := region.GetDisk(diskId) + if err != nil { + return errors.Wrapf(err, "GetDisk(%s)", diskId) + } + status = disk.Status + log.Debugf("status %s expect %s", status, DISK_STATUS_AVAILABLE) + if status == DISK_STATUS_AVAILABLE { + return nil + } + time.Sleep(time.Second * 15) + } + return fmt.Errorf("timeout for waitting detach disk, current status: %s", status) +} + +func (region *SRegion) AttachDisk(instanceId string, diskId string) error { + params := map[string]map[string]string{ + "volumeAttachment": { + "volumeId": diskId, + }, + } + resource := fmt.Sprintf("/servers/%s/os-volume_attachments", instanceId) + _, err := region.ecsPost(resource, params) + if err != nil { + return errors.Wrap(err, "ecsPost") + } + status := "" + startTime := time.Now() + for time.Now().Sub(startTime) < time.Minute*10 { + disk, err := region.GetDisk(diskId) + if err != nil { + return errors.Wrapf(err, "GetDisk(%s)", diskId) + } + status = disk.Status + log.Debugf("status %s expect %s", status, DISK_STATUS_IN_USE) + if status == DISK_STATUS_IN_USE { + return nil + } + time.Sleep(time.Second * 15) + } + return fmt.Errorf("timeout for waitting attach disk, current status: %s", status) +} + +func (region *SRegion) MigrateVM(instanceId string, hostName string) error { + params := jsonutils.NewDict() + migrate := jsonutils.NewDict() + migrate.Add(jsonutils.JSONNull, "host") + if hostName != "" { + migrate.Add(jsonutils.NewString(hostName), "host") + } + params.Add(migrate, "migrate") + resource := fmt.Sprintf("/servers/%s/action", instanceId) + _, err := region.ecsPost(resource, params) + if err != nil { + return errors.Wrapf(err, "On Requst Migrate instance:%s", instanceId) + } + return nil +} + +func (region *SRegion) LiveMigrateVM(instanceId string, hostName string) error { + params := jsonutils.NewDict() + osMigrateLive := jsonutils.NewDict() + osMigrateLive.Add(jsonutils.NewString("auto"), "block_migration") + osMigrateLive.Add(jsonutils.JSONNull, "host") + if hostName != "" { + osMigrateLive.Add(jsonutils.NewString(hostName), "host") + } + params.Add(osMigrateLive, "os-migrateLive") + resource := fmt.Sprintf("/servers/%s/action", instanceId) + _, err := region.ecsPost(resource, params) + if err != nil { + return errors.Wrapf(err, "On Requst LiveMigrate instance:%s", instanceId) + } + return nil +} + +//仅live-migration +func (region *SRegion) ListServerMigration(instanceId string) error { + resource := fmt.Sprintf("/servers/%s/migrations", instanceId) + _, err := region.ecsGet(resource) + if err != nil { + return errors.Wrapf(err, "ListServerMigration") + } + return nil +} + +//仅live-migration +func (region *SRegion) DeleteMigration(instanceId string, migrationId string) error { + resource := fmt.Sprintf("/servers/%s/migrations/%s", instanceId, migrationId) + _, err := region.ecsDelete(resource) + if err != nil { + return errors.Wrapf(err, "On Requst delete LiveMigrate:%s", migrationId) + } + return nil +} + +//仅live-migration +func (region *SRegion) ForceCompleteMigration(instanceId string, migrationId string) error { + params := jsonutils.NewDict() + params.Add(jsonutils.JSONNull, "force_complete") + resource := fmt.Sprintf("/servers/%s/migrations/%s/action", instanceId, migrationId) + _, err := region.ecsPost(resource, params) + if err != nil { + return errors.Wrapf(err, "On Requst delete LiveMigrate:%s", migrationId) + } + return nil +} + +func (region *SRegion) GetMigrations(instanceId string, migrationType string) (jsonutils.JSONObject, error) { + query := url.Values{} + query.Set("instance_uuid", instanceId) + query.Set("migration_type", migrationType) + resource := "/os-migrations" + migrations, err := region.ecsList(resource, query) + if err != nil { + return nil, errors.Wrapf(err, "On Get instance :%s Migration,migration_type:%s", instanceId, migrationType) + } + return migrations, nil +} + +func (instance *SInstance) AssignSecurityGroup(secgroupId string) error { + if secgroupId == SECGROUP_NOT_SUPPORT { + return fmt.Errorf("Security groups are not supported. Security group components are not installed") + } + secgroup, err := instance.host.zone.region.GetSecurityGroup(secgroupId) + if err != nil { + return errors.Wrapf(err, "GetSecurityGroup(%s)", secgroupId) + } + params := map[string]map[string]string{ + "addSecurityGroup": { + "name": secgroup.Name, + }, + } + resource := fmt.Sprintf("/servers/%s/action", instance.Id) + _, err = instance.host.zone.region.ecsDo(instance.GetProjectId(), resource, params) + return err +} + +func (instance *SInstance) RevokeSecurityGroup(secgroupId string) error { + // 若OpenStack不支持安全组,则忽略解绑安全组 + if secgroupId == SECGROUP_NOT_SUPPORT { + return nil + } + secgroup, err := instance.host.zone.region.GetSecurityGroup(secgroupId) + if err != nil { + return errors.Wrapf(err, "GetSecurityGroup(%s)", secgroupId) + } + params := map[string]map[string]string{ + "removeSecurityGroup": { + "name": secgroup.Name, + }, + } + resource := fmt.Sprintf("/servers/%s/action", instance.Id) + _, err = instance.host.zone.region.ecsDo(instance.GetProjectId(), resource, params) + return err +} + +func (instance *SInstance) SetSecurityGroups(secgroupIds []string) error { + secgroups, err := instance.host.zone.region.GetSecurityGroupsByInstance(instance.Id) + if err != nil { + return errors.Wrapf(err, "GetSecurityGroupsByInstance(%s)", instance.Id) + } + local := set.New(set.ThreadSafe) + for _, secgroup := range secgroups { + local.Add(secgroup.Id) + } + newG := set.New(set.ThreadSafe) + for _, secgroupId := range secgroupIds { + newG.Add(secgroupId) + } + for _, del := range set.Difference(local, newG).List() { + secgroupId := del.(string) + err := instance.RevokeSecurityGroup(secgroupId) + if err != nil { + return errors.Wrapf(err, "RevokeSecurityGroup(%s)", secgroupId) + } + } + for _, add := range set.Difference(newG, local).List() { + secgroupId := add.(string) + err := instance.AssignSecurityGroup(secgroupId) + if err != nil { + return errors.Wrapf(err, "AssignSecurityGroup(%s)", secgroupId) + } + } + return nil +} + +func (instance *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + for networkName, address := range instance.Addresses { + for i := 0; i < len(address); i++ { + if instance.Addresses[networkName][i].Type == "floating" { + return instance.host.zone.region.GetEipByIp(instance.Addresses[networkName][i].Addr) + } + } + } + return nil, nil +} + +func (instance *SInstance) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (instance *SInstance) GetCreatedAt() time.Time { + return instance.Created +} + +func (instance *SInstance) GetExpiredAt() time.Time { + return time.Time{} +} + +func (instance *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +func (instance *SInstance) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (region *SRegion) RenewInstances(instanceId []string, bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (instance *SInstance) GetProjectId() string { + return instance.TenantId +} + +func (self *SInstance) GetError() error { + if self.Status == INSTANCE_STATUS_ERROR && len(self.Fault.Message) > 0 { + return errors.Error(self.Fault.Message) + } + return nil +} + +func (instance *SInstance) MigrateVM(hostId string) error { + hostName := "" + if hostId != "" { + iHost, err := instance.host.zone.region.GetIHostById(hostId) + if err != nil { + return errors.Wrapf(err, "GetIHostById(%s)", hostId) + } + hostName = iHost.GetName() + } + + previousHostName := instance.Host + err := instance.host.zone.region.MigrateVM(instance.Id, hostName) + if err != nil { + return errors.Wrap(err, "MigrateVm") + } + err = cloudprovider.WaitMultiStatus(instance, []string{api.VM_SYNC_CONFIG, api.VM_READY, api.VM_UNKNOWN}, time.Second*10, time.Hour*3) + if err != nil { + return errors.Wrap(err, "WaitMultiStatus") + } + if instance.GetStatus() == api.VM_UNKNOWN { + return errors.Wrap(errors.ErrInvalidStatus, "GetStatus") + } + if instance.GetStatus() == api.VM_READY { + if instance.Host == previousHostName { + return errors.Wrap(fmt.Errorf("instance not migrated"), "Check host after migration") + } + return nil + } + return instance.host.zone.region.instanceOperation(instance.Id, "confirmResize") +} + +func (instance *SInstance) LiveMigrateVM(hostId string) error { + hostName := "" + if hostId != "" { + iHost, err := instance.host.zone.region.GetIHostById(hostId) + if err != nil { + return errors.Wrapf(err, "GetIHostById(%s)", hostId) + } + hostName = iHost.GetName() + } + previousHostName := instance.Host + err := instance.host.zone.region.LiveMigrateVM(instance.Id, hostName) + if err != nil { + return errors.Wrap(err, "LiveMIgrateVm") + } + err = cloudprovider.WaitMultiStatus(instance, []string{api.VM_SYNC_CONFIG, api.VM_RUNNING, api.VM_UNKNOWN}, time.Second*10, time.Hour*3) + if err != nil { + return errors.Wrap(err, "WaitMultiStatus") + } + if instance.GetStatus() == api.VM_UNKNOWN { + return errors.Wrap(errors.ErrInvalidStatus, "GetStatus") + } + if instance.GetStatus() == api.VM_RUNNING { + if instance.Host == previousHostName { + return errors.Wrap(fmt.Errorf("instance not migrated"), "Check host after migration") + } + return nil + } + return instance.host.zone.region.instanceOperation(instance.Id, "confirmResize") +} +func (instance *SInstance) GetIHostId() string { + err := instance.host.zone.fetchHosts() + if err != nil { + return "" + } + for _, host := range instance.host.zone.hosts { + if instance.HypervisorHostname == host.HypervisorHostname { + return host.GetGlobalId() + } + } + return "" +} + +func (region *SRegion) GetInstanceMetadata(instanceId string) (map[string]string, error) { + resource := fmt.Sprintf("/servers/%s/metadata", instanceId) + resp, err := region.ecsList(resource, nil) + if err != nil { + return nil, errors.Wrap(err, "ecsList") + } + result := struct { + Metadata map[string]string + }{} + err = resp.Unmarshal(&result) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return result.Metadata, nil +} + +func (zone *SZone) CreateVM(hypervisor string, opts *cloudprovider.SManagedVMCreateConfig) (*SInstance, error) { + region := zone.region + network, err := region.GetNetwork(opts.ExternalNetworkId) + if err != nil { + return nil, err + } + + secgroups := []map[string]string{} + for _, secgroupId := range opts.ExternalSecgroupIds { + if secgroupId != SECGROUP_NOT_SUPPORT { + secgroups = append(secgroups, map[string]string{"name": secgroupId}) + } + } + + image, err := region.GetImage(opts.ExternalImageId) + if err != nil { + return nil, errors.Wrapf(err, "GetImage(%s)", opts.ExternalImageId) + } + + sysDiskSizeGB := image.Size / 1024 / 1024 / 1024 + if opts.SysDisk.SizeGB < sysDiskSizeGB { + opts.SysDisk.SizeGB = sysDiskSizeGB + } + + if opts.SysDisk.SizeGB < image.GetMinOsDiskSizeGb() { + opts.SysDisk.SizeGB = image.GetMinOsDiskSizeGb() + } + + BlockDeviceMappingV2 := []map[string]interface{}{} + + diskIds := []string{} + + defer func() { + for _, diskId := range diskIds { + err = region.DeleteDisk(diskId) + if err != nil { + log.Errorf("clean disk %s error: %v", diskId, err) + } + } + }() + + if opts.SysDisk.StorageType != api.STORAGE_OPENSTACK_NOVA { //新建volume + istorage, err := zone.GetIStorageById(opts.SysDisk.StorageExternalId) + if err != nil { + return nil, errors.Wrapf(err, "GetIStorageById(%s)", opts.SysDisk.StorageExternalId) + } + + _sysDisk, err := region.CreateDisk(opts.ExternalImageId, istorage.GetName(), "", opts.SysDisk.SizeGB, opts.SysDisk.Name, opts.ProjectId) + if err != nil { + return nil, errors.Wrapf(err, "CreateDisk %s", opts.SysDisk.Name) + } + + diskIds = append(diskIds, _sysDisk.GetGlobalId()) + + BlockDeviceMappingV2 = append(BlockDeviceMappingV2, map[string]interface{}{ + "boot_index": 0, + "uuid": _sysDisk.GetGlobalId(), + "source_type": "volume", + "destination_type": "volume", + "delete_on_termination": true, + }) + } else { + BlockDeviceMappingV2 = append(BlockDeviceMappingV2, map[string]interface{}{ + "boot_index": 0, + "uuid": image.Id, + "source_type": "image", + "destination_type": "local", + "delete_on_termination": true, + }) + } + + var _disk *SDisk + for index, disk := range opts.DataDisks { + istorage, err := zone.GetIStorageById(disk.StorageExternalId) + if err != nil { + return nil, errors.Wrapf(err, "GetIStorageById(%s)", disk.StorageExternalId) + } + _disk, err = region.CreateDisk("", istorage.GetName(), "", disk.SizeGB, disk.Name, opts.ProjectId) + if err != nil { + return nil, errors.Wrapf(err, "CreateDisk %s", disk.Name) + } + diskIds = append(diskIds, _disk.Id) + + mapping := map[string]interface{}{ + "source_type": "volume", + "destination_type": "volume", + "delete_on_termination": true, + "boot_index": index + 1, + "uuid": _disk.Id, + } + + BlockDeviceMappingV2 = append(BlockDeviceMappingV2, mapping) + } + + az := zone.ZoneName + if len(hypervisor) > 0 { + az = fmt.Sprintf("%s:%s", zone.ZoneName, hypervisor) + } + + net := map[string]string{ + "uuid": network.NetworkId, + } + if len(opts.IpAddr) > 0 { + net["fixed_ip"] = opts.IpAddr + } + + params := map[string]map[string]interface{}{ + "server": { + "name": opts.Name, + "adminPass": opts.Password, + "availability_zone": az, + "networks": []map[string]string{net}, + "security_groups": secgroups, + "user_data": opts.UserData, + "imageRef": opts.ExternalImageId, + "block_device_mapping_v2": BlockDeviceMappingV2, + }, + } + if len(opts.IpAddr) > 0 { + params["server"]["accessIPv4"] = opts.IpAddr + } + + flavor, err := region.syncFlavor(opts.InstanceType, opts.Cpu, opts.MemoryMB, opts.SysDisk.SizeGB) + if err != nil { + return nil, err + } + params["server"]["flavorRef"] = flavor.Id + + if len(opts.PublicKey) > 0 { + keypairName, err := region.syncKeypair(opts.Name, opts.PublicKey) + if err != nil { + return nil, err + } + params["server"]["key_name"] = keypairName + } + + resp, err := region.ecsCreate(opts.ProjectId, "/servers", params) + if err != nil { + return nil, errors.Wrap(err, "ecsCreate") + } + diskIds = []string{} + instance := &SInstance{} + err = resp.Unmarshal(instance, "server") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return instance, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/instancenic.go new file mode 100644 index 0000000000..efc47958a6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/instancenic.go @@ -0,0 +1,99 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/regutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + MacAddr string `json:"OS-EXT-IPS-MAC:mac_addr"` + Version int `json:"version"` + Addr string `json:"addr"` + Type string `json:"OS-EXT-IPS:type"` +} + +type SFixedIp struct { + IpAddress string + SubnetId string +} + +type SInstancePort struct { + region *SRegion + FixedIps []SFixedIp + MacAddr string + NetId string + PortId string + PortState string + + cloudprovider.DummyICloudNic +} + +func (region *SRegion) GetInstancePorts(instanceId string) ([]SInstancePort, error) { + resource := fmt.Sprintf("/servers/%s/os-interface", instanceId) + resp, err := region.ecsList(resource, nil) + if err != nil { + return nil, errors.Wrap(err, "ecsList") + } + ports := []SInstancePort{} + err = resp.Unmarshal(&ports, "interfaceAttachments") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return ports, nil +} + +func (nic *SInstancePort) GetId() string { + return "" +} + +func (nic *SInstancePort) GetIP() string { + for i := range nic.FixedIps { + if regutils.MatchIPAddr(nic.FixedIps[i].IpAddress) { + return nic.FixedIps[i].IpAddress + } + } + return "" +} + +func (nic *SInstancePort) GetMAC() string { + return nic.MacAddr +} + +func (nic *SInstancePort) GetDriver() string { + return "virtio" +} + +func (nic *SInstancePort) InClassicNetwork() bool { + return false +} + +func (nic *SInstancePort) GetINetworkId() string { + for i := range nic.FixedIps { + if regutils.MatchIPAddr(nic.FixedIps[i].IpAddress) { + network, err := nic.region.GetNetwork(nic.FixedIps[i].SubnetId) + if err != nil { + return nic.FixedIps[i].SubnetId + } + return network.GetGlobalId() + } + } + return "" +} diff --git a/pkg/multicloud/openstack/keypaire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/keypaire.go similarity index 98% rename from pkg/multicloud/openstack/keypaire.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/keypaire.go index 05f0790eeb..e6669e6a4a 100644 --- a/pkg/multicloud/openstack/keypaire.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/keypaire.go @@ -20,7 +20,7 @@ import ( "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/rand" ) diff --git a/pkg/multicloud/openstack/loadbalabcerpool.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalabcerpool.go similarity index 99% rename from pkg/multicloud/openstack/loadbalabcerpool.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalabcerpool.go index a223b3ec3a..3015da1829 100644 --- a/pkg/multicloud/openstack/loadbalabcerpool.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalabcerpool.go @@ -24,9 +24,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SLoadbalancerPoolCreateParams struct { @@ -69,7 +69,7 @@ type SSessionPersistence struct { type SLoadbalancerPool struct { multicloud.SResourceBase - multicloud.OpenStackTags + OpenStackTags region *SRegion members []SLoadbalancerMember healthmonitor *SLoadbalancerHealthmonitor diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalanceracl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalanceracl.go new file mode 100644 index 0000000000..99c8afbf99 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalanceracl.go @@ -0,0 +1,187 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + "time" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type AclEntrys struct { + AclEntry []AclEntry +} + +type AclEntry struct { + AclEntryComment string + AclEntryIP string +} + +type SLoadbalancerAcl struct { + multicloud.SResourceBase + OpenStackTags + listener *SLoadbalancerListener +} + +func (acl *SLoadbalancerAcl) GetAclListenerID() string { + return acl.listener.ID +} + +func (acl *SLoadbalancerAcl) GetName() string { + return acl.listener.Name + "AllowedCidrs" +} + +func (acl *SLoadbalancerAcl) GetId() string { + return acl.listener.ID +} + +func (acl *SLoadbalancerAcl) GetGlobalId() string { + return acl.listener.ID +} + +func (acl *SLoadbalancerAcl) GetStatus() string { + return "" +} + +func (acl *SLoadbalancerAcl) IsEmulated() bool { + return false +} + +func (acl *SLoadbalancerAcl) Refresh() error { + return acl.listener.Refresh() +} + +func (acl *SLoadbalancerAcl) GetAclEntries() []cloudprovider.SLoadbalancerAccessControlListEntry { + aclEntrys := []cloudprovider.SLoadbalancerAccessControlListEntry{} + for i := 0; i < len(acl.listener.AllowedCidrs); i++ { + aclEntry := cloudprovider.SLoadbalancerAccessControlListEntry{} + aclEntry.CIDR = acl.listener.AllowedCidrs[i] + aclEntry.Comment = "AllowedCidr" + aclEntrys = append(aclEntrys, aclEntry) + } + return aclEntrys +} + +func (region *SRegion) UpdateLoadbalancerListenerAllowedCidrs(listenerId string, cidrs []string) error { + params := jsonutils.NewDict() + listenerParam := jsonutils.NewDict() + listenerParam.Add(jsonutils.NewStringArray(cidrs), "allowed_cidrs") + params.Add(listenerParam, "listener") + _, err := region.lbUpdate(fmt.Sprintf("/v2/lbaas/listeners/%s", listenerId), params) + if err != nil { + return errors.Wrapf(err, `region.lbUpdate(/v2/lbaas/listeners/%s, params)`, listenerId) + } + return nil +} + +func (acl *SLoadbalancerAcl) Delete() error { + // ensure listener status + err := waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute) + if err != nil { + return errors.Wrap(err, `waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute)`) + } + err = acl.listener.region.UpdateLoadbalancerListenerAllowedCidrs(acl.listener.ID, []string{}) + if err != nil { + return errors.Wrap(err, `acl.listener.region.UpdateLoadbalancerListenerAllowedCidrs(acl.listener.ID, []string{})`) + } + err = waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute) + if err != nil { + return errors.Wrap(err, `waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute)`) + } + return nil +} + +func (region *SRegion) GetLoadbalancerAclDetail(aclId string) (*SLoadbalancerAcl, error) { + listener, err := region.GetLoadbalancerListenerbyId(aclId) + if err != nil { + return nil, errors.Wrapf(err, "region.GetLoadbalancerListenerbyId(%s)", aclId) + } + acl := SLoadbalancerAcl{} + acl.listener = listener + return &acl, nil +} + +func (region *SRegion) GetLoadBalancerAcls() ([]SLoadbalancerAcl, error) { + listeners, err := region.GetLoadbalancerListeners() + if err != nil { + return nil, errors.Wrap(err, "region.GetLoadbalancerListeners()") + } + acls := []SLoadbalancerAcl{} + for i := 0; i < len(listeners); i++ { + if len(listeners[i].AllowedCidrs) < 1 { + continue + } + acl := new(SLoadbalancerAcl) + acl.listener = &listeners[i] + acls = append(acls, *acl) + + } + return acls, nil +} + +func (region *SRegion) CreateLoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (*SLoadbalancerAcl, error) { + if !acl.AccessControlEnable { + return nil, errors.Wrap(fmt.Errorf("only support allowed cidrs"), "CreateLoadBalancerAcl") + } + if len(acl.ListenerId) < 1 { + return nil, errors.Wrap(fmt.Errorf("loadbalanceracl must band to a loadbalancerlistener"), "CreateLoadBalancerAcl") + } + cidrs := []string{} + for i := 0; i < len(acl.Entrys); i++ { + cidrs = append(cidrs, acl.Entrys[i].CIDR) + } + sacl, err := region.GetLoadbalancerAclDetail(acl.ListenerId) + if err != nil { + return nil, errors.Wrapf(err, "region.GetLoadbalancerAclDetail(%s)", acl.ListenerId) + } + // ensure listener status + err = waitLbResStatus(sacl.listener, 10*time.Second, 8*time.Minute) + if err != nil { + return nil, errors.Wrap(err, `waitLbResStatus(sacl.listener, 10*time.Second, 8*time.Minute)`) + } + return sacl, region.UpdateLoadbalancerListenerAllowedCidrs(acl.ListenerId, cidrs) +} + +func (acl *SLoadbalancerAcl) Sync(_acl *cloudprovider.SLoadbalancerAccessControlList) error { + // ensure listener status + err := waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute) + if err != nil { + return errors.Wrap(err, "waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute)") + } + + cidrs := []string{} + for i := 0; i < len(_acl.Entrys); i++ { + cidrs = append(cidrs, _acl.Entrys[i].CIDR) + } + err = acl.listener.region.UpdateLoadbalancerListenerAllowedCidrs(acl.listener.ID, cidrs) + if err != nil { + return errors.Wrapf(err, "UpdateLoadbalancerListenerAllowedCidrs(%s, cidrs)", acl.listener.ID) + } + err = waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute) + if err != nil { + return errors.Wrap(err, "waitLbResStatus(acl.listener, 10*time.Second, 8*time.Minute)") + } + return nil +} + +func (acl *SLoadbalancerAcl) GetProjectId() string { + return acl.listener.ProjectID +} diff --git a/pkg/multicloud/openstack/loadbalancerl7policy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancerl7policy.go similarity index 97% rename from pkg/multicloud/openstack/loadbalancerl7policy.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancerl7policy.go index 4b06c53957..c8b846fc5f 100644 --- a/pkg/multicloud/openstack/loadbalancerl7policy.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancerl7policy.go @@ -20,9 +20,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SLoadbalancerL7PolicyCreateParams struct { @@ -41,7 +41,7 @@ type SLoadbalancerL7PolicyCreateParams struct { type SLoadbalancerL7Policy struct { multicloud.SResourceBase - multicloud.OpenStackTags + OpenStackTags region *SRegion l7rules []SLoadbalancerL7Rule ListenerID string `json:"listener_id"` diff --git a/pkg/multicloud/openstack/loadbalancerl7rule.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancerl7rule.go similarity index 97% rename from pkg/multicloud/openstack/loadbalancerl7rule.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancerl7rule.go index 73f84cca93..420e9f30be 100644 --- a/pkg/multicloud/openstack/loadbalancerl7rule.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancerl7rule.go @@ -22,9 +22,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SLoadbalancerL7RuleCreateParams struct { @@ -39,7 +39,7 @@ type SLoadbalancerL7RuleCreateParams struct { type SLoadbalancerL7Rule struct { multicloud.SResourceBase multicloud.SLoadbalancerRedirectBase - multicloud.OpenStackTags + OpenStackTags policy *SLoadbalancerL7Policy CreatedAt string `json:"created_at"` CompareType string `json:"compare_type"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancerlistener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancerlistener.go new file mode 100644 index 0000000000..90fdf88786 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancerlistener.go @@ -0,0 +1,774 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "context" + "fmt" + "net/url" + "strconv" + "time" + + "github.com/coredns/coredns/plugin/pkg/log" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLoadbalancerListenerCreateParams struct { + Protocol string `json:"protocol,omitempty"` + Description string `json:"description,omitempty"` + AdminStateUp bool `json:"admin_state_up,omitempty"` + ConnectionLimit *int `json:"connection_limit,omitempty"` + ProtocolPort string `json:"protocol_port,omitempty"` + LoadbalancerID string `json:"loadbalancer_id,omitempty"` + DefaultPoolId string `json:"default_pool_id,omitempty"` + Name string `json:"name,omitempty"` + InsertHeaders SInsertHeaders `json:"insert_headers,omitempty"` + DefaultTLSContainerRef string `json:"default_tls_container_ref,omitempty"` + SniContainerRefs []string `json:"sni_container_refs,omitempty"` + TimeoutClientData *int `json:"timeout_client_data,omitempty"` + TimeoutMemberConnect *int `json:"timeout_member_connect,omitempty"` + TimeoutMemberData *int `json:"timeout_member_data,omitempty"` + TimeoutTCPInspect *int `json:"timeout_tcp_inspect,omitempty"` + Tags []string `json:"tags,omitempty"` + ClientCaTLSContainerRef string `json:"client_ca_tls_container_ref,omitempty"` + ClientAuthentication string `json:"client_authentication,omitempty"` + ClientCrlContainerRef string `json:"client_crl_container_ref,omitempty"` + AllowedCidrs []string `json:"allowed_cidrs,omitempty"` + TLSCiphers string `json:"tls_ciphers,omitempty"` + TLSVersions []string `json:"tls_versions,omitempty"` +} + +type SLoadbalancerListenerUpdateParams struct { + Description string `json:"description,omitempty"` + AdminStateUp bool `json:"admin_state_up,omitempty"` + ConnectionLimit *int `json:"connection_limit,omitempty"` + DefaultPoolId string `json:"default_pool_id,omitempty"` + Name string `json:"name,omitempty"` + InsertHeaders SInsertHeaders `json:"insert_headers,omitempty"` + DefaultTLSContainerRef string `json:"default_tls_container_ref,omitempty"` + SniContainerRefs []string `json:"sni_container_refs,omitempty"` + TimeoutClientData *int `json:"timeout_client_data,omitempty"` + TimeoutMemberConnect *int `json:"timeout_member_connect,omitempty"` + TimeoutMemberData *int `json:"timeout_member_data,omitempty"` + TimeoutTCPInspect *int `json:"timeout_tcp_inspect,omitempty"` + Tags []string `json:"tags,omitempty"` + ClientCaTLSContainerRef string `json:"client_ca_tls_container_ref,omitempty"` + ClientAuthentication string `json:"client_authentication,omitempty"` + ClientCrlContainerRef string `json:"client_crl_container_ref,omitempty"` + AllowedCidrs []string `json:"allowed_cidrs,omitempty"` + TLSCiphers string `json:"tls_ciphers,omitempty"` + TLSVersions []string `json:"tls_versions,omitempty"` +} + +type SInsertHeaders struct { + XForwardedPort string `json:"X-Forwarded-Port"` + XForwardedFor string `json:"X-Forwarded-For"` +} + +type SLoadbalancerListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + OpenStackTags + region *SRegion + l7policies []SLoadbalancerL7Policy + pools []SLoadbalancerPool + Description string `json:"description"` + AdminStateUp bool `json:"admin_state_up"` + ProjectID string `json:"project_id"` + Protocol string `json:"protocol"` + ProtocolPort int `json:"protocol_port"` + ProvisioningStatus string `json:"provisioning_status"` + DefaultTLSContainerRef string `json:"default_tls_container_ref"` + LoadbalancerIds []SLoadbalancerID `json:"loadbalancers"` + InsertHeaders SInsertHeaders `json:"insert_headers"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + ID string `json:"id"` + OperatingStatus string `json:"operating_status"` + DefaultPoolID string `json:"default_pool_id"` + SniContainerRefs []string `json:"sni_container_refs"` + L7PolicieIds []SL7PolicieID `json:"l7policies"` + Name string `json:"name"` + TimeoutClientData int `json:"timeout_client_data"` + TimeoutMemberConnect int `json:"timeout_member_connect"` + TimeoutMemberData int `json:"timeout_member_data"` + TimeoutTCPInspect int `json:"timeout_tcp_inspect"` + Tags []string `json:"tags"` + ClientCaTLSContainerRef string `json:"client_ca_tls_container_ref"` + ClientAuthentication string `json:"client_authentication"` + ClientCrlContainerRef string `json:"client_crl_container_ref"` + AllowedCidrs []string `json:"allowed_cidrs"` + TLSCiphers string `json:"tls_ciphers"` + TLSVersions []string `json:"tls_versions"` +} + +func (listener *SLoadbalancerListener) GetName() string { + if len(listener.Name) == 0 { + listener.Refresh() + } + if len(listener.Name) > 0 { + return listener.Name + } + return fmt.Sprintf("HTTP:%d", listener.ProtocolPort) +} + +func (listener *SLoadbalancerListener) GetId() string { + return listener.ID +} + +func (listener *SLoadbalancerListener) GetGlobalId() string { + return listener.GetId() +} + +func (listener *SLoadbalancerListener) GetStatus() string { + switch listener.ProvisioningStatus { + case "ACTIVE": + return api.LB_STATUS_ENABLED + case "PENDING_CREATE": + return api.LB_CREATING + case "PENDING_UPDATE": + return api.LB_SYNC_CONF + case "PENDING_DELETE": + return api.LB_STATUS_DELETING + case "DELETED": + return api.LB_STATUS_DELETED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (listener *SLoadbalancerListener) IsEmulated() bool { + return false +} + +func (listener *SLoadbalancerListener) GetEgressMbps() int { + + return 0 +} + +func (region *SRegion) GetLoadbalancerListeners() ([]SLoadbalancerListener, error) { + listeners := []SLoadbalancerListener{} + resource := "/v2/lbaas/listeners" + query := url.Values{} + for { + resp, err := region.lbList(resource, query) + if err != nil { + return nil, errors.Wrap(err, "lbList") + } + part := struct { + Listeners []SLoadbalancerListener + ListenersLinks SNextLinks + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + listeners = append(listeners, part.Listeners...) + marker := part.ListenersLinks.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + + for i := 0; i < len(listeners); i++ { + listeners[i].region = region + } + for i := 0; i < len(listeners); i++ { + err := listeners[i].fetchLoadbalancerListenerL7Policies() + if err != nil { + return nil, errors.Wrap(err, "listener.fetchLoadbalancerListenerL7Policies()") + } + } + + for i := 0; i < len(listeners); i++ { + err := listeners[i].fetchLoadbalancerPools() + if err != nil { + return nil, errors.Wrap(err, "listeners[i].fetchLoadbalancerPools()") + } + } + + return listeners, nil +} + +func (region *SRegion) GetLoadbalancerListenerbyId(listenerId string) (*SLoadbalancerListener, error) { + resp, err := region.lbGet(fmt.Sprintf("/v2/lbaas/listeners/%s", listenerId)) + if err != nil { + return nil, errors.Wrapf(err, "region.Get(/v2/lbaas/listeners/%s)", listenerId) + } + listener := SLoadbalancerListener{} + err = resp.Unmarshal(&listener, "listener") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal(&listener, listener)") + } + listener.region = region + err = listener.fetchLoadbalancerListenerL7Policies() + if err != nil { + return nil, errors.Wrap(err, "listener.fetchLoadbalancerListenerL7Policies()") + } + + err = listener.fetchLoadbalancerPools() + if err != nil { + return nil, errors.Wrap(err, "listeners[i].fetchLoadbalancerPools()") + + } + return &listener, nil +} + +func (region *SRegion) CreateLoadbalancerListener(loadbalancerId string, listenerParams *cloudprovider.SLoadbalancerListener) (*SLoadbalancerListener, error) { + type CreateParams struct { + Listener SLoadbalancerListenerCreateParams `json:"listener"` + } + params := CreateParams{} + params.Listener.AdminStateUp = true + params.Listener.LoadbalancerID = loadbalancerId + params.Listener.DefaultPoolId = listenerParams.BackendGroupID + params.Listener.Protocol = LB_PROTOCOL_MAP[listenerParams.ListenerType] + params.Listener.ProtocolPort = strconv.Itoa(listenerParams.ListenerPort) + if listenerParams.ClientIdleTimeout != 0 { + // 毫秒单位 + msClientIdleTimeout := listenerParams.ClientIdleTimeout * 1000 + params.Listener.TimeoutClientData = &msClientIdleTimeout + } + if listenerParams.BackendConnectTimeout != 0 { + msBackendConnectTimeout := listenerParams.BackendConnectTimeout * 1000 + params.Listener.TimeoutMemberConnect = &msBackendConnectTimeout + } + if listenerParams.BackendIdleTimeout != 0 { + msBackendIdleTimeout := listenerParams.BackendIdleTimeout * 1000 + params.Listener.TimeoutMemberData = &msBackendIdleTimeout + } + + params.Listener.Name = listenerParams.Name + if listenerParams.XForwardedFor { + params.Listener.InsertHeaders.XForwardedFor = "true" + } + body, err := region.lbPost("/v2/lbaas/listeners", jsonutils.Marshal(params)) + if err != nil { + return nil, errors.Wrap(err, "region.Post(/v2/lbaas/listeners)") + } + slistener := SLoadbalancerListener{} + slistener.region = region + return &slistener, body.Unmarshal(&slistener, "listener") +} + +func (listener *SLoadbalancerListener) Refresh() error { + newlistener, err := listener.region.GetLoadbalancerListenerbyId(listener.ID) + if err != nil { + return errors.Wrapf(err, "listener.region.GetLoadbalancerListenerbyId(%s)", listener.ID) + } + return jsonutils.Update(listener, newlistener) +} + +func (listener *SLoadbalancerListener) GetListenerType() string { + switch listener.Protocol { + case "HTTP": + return api.LB_LISTENER_TYPE_HTTP + case "HTTPS": + return api.LB_LISTENER_TYPE_HTTPS + case "TERMINATED_HTTPS": + return api.LB_LISTENER_TYPE_TERMINATED_HTTPS + case "TCP": + return api.LB_LISTENER_TYPE_TCP + case "UDP": + return api.LB_LISTENER_TYPE_UDP + default: + return "" + } +} + +func (listener *SLoadbalancerListener) GetListenerPort() int { + return listener.ProtocolPort +} + +func (listener *SLoadbalancerListener) GetBackendGroupId() string { + return listener.DefaultPoolID +} + +func (listener *SLoadbalancerListener) GetBackendServerPort() int { + return listener.ProtocolPort +} + +func (listener *SLoadbalancerListener) GetScheduler() string { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetScheduler():listener.fetchFeaturePool():%s", err) + return "" + } + switch pool.LbAlgorithm { + case "ROUND_ROBIN": + return api.LB_SCHEDULER_WRR + case "LEAST_CONNECTIONS": + return api.LB_SCHEDULER_WLC + case "SOURCE_IP": + return api.LB_SCHEDULER_SCH + case "SOURCE_IP_PORT": + return api.LB_SCHEDULER_TCH + default: + return "" + } +} + +func (listener *SLoadbalancerListener) GetAclStatus() string { + if len(listener.AllowedCidrs) > 0 { + return api.LB_BOOL_ON + } + return api.LB_BOOL_OFF +} + +func (listener *SLoadbalancerListener) GetAclType() string { + return api.LB_ACL_TYPE_WHITE +} + +func (listener *SLoadbalancerListener) GetAclId() string { + return "" +} + +func (listener *SLoadbalancerListener) GetHealthCheck() string { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetHealthCheck():listener.fetchFeaturePool():%s", err) + return "" + } + if pool.healthmonitor != nil { + return api.LB_BOOL_ON + } + return api.LB_BOOL_OFF + +} + +func (listener *SLoadbalancerListener) GetHealthCheckType() string { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetHealthCheckType():listener.fetchFeaturePool():%s", err) + return "" + } + if pool.healthmonitor == nil { + return "" + } + switch pool.healthmonitor.Type { + case "HTTP": + return api.LB_HEALTH_CHECK_HTTP + case "HTTPS": + return api.LB_HEALTH_CHECK_HTTPS + case "TCP": + return api.LB_HEALTH_CHECK_TCP + case "UDP-CONNECT": + return api.LB_HEALTH_CHECK_UDP + default: + return "" + } +} + +func (listener *SLoadbalancerListener) GetHealthCheckDomain() string { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetHealthCheckDomain():listener.fetchFeaturePool():%s", err) + return "" + } + if pool.healthmonitor == nil { + return "" + } + return pool.healthmonitor.DomainName +} + +func (listener *SLoadbalancerListener) GetHealthCheckURI() string { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetHealthCheckURI():listener.fetchFeaturePool():%s", err) + return "" + } + if pool.healthmonitor == nil { + return "" + } + return pool.healthmonitor.URLPath +} + +func (listener *SLoadbalancerListener) GetHealthCheckCode() string { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetHealthCheckCode():listener.fetchFeaturePool():%s", err) + return "" + } + if pool.healthmonitor == nil { + return "" + } + return pool.healthmonitor.ExpectedCodes +} + +func (listener *SLoadbalancerListener) GetHealthCheckRise() int { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetHealthCheckRise():listener.fetchFeaturePool():%s", err) + return 0 + } + if pool.healthmonitor == nil { + return 0 + } + return pool.healthmonitor.MaxRetries +} + +func (listener *SLoadbalancerListener) GetHealthCheckFail() int { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetHealthCheckFail():listener.fetchFeaturePool():%s", err) + return 0 + } + if pool.healthmonitor == nil { + return 0 + } + return pool.healthmonitor.MaxRetriesDown +} + +func (listener *SLoadbalancerListener) GetHealthCheckTimeout() int { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetHealthCheckTimeout():listener.fetchFeaturePool():%s", err) + return 0 + } + if pool.healthmonitor == nil { + return 0 + } + return pool.healthmonitor.Timeout +} + +func (listener *SLoadbalancerListener) GetHealthCheckInterval() int { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetHealthCheckInterval():listener.fetchFeaturePool():%s", err) + return 0 + } + if pool.healthmonitor == nil { + return 0 + } + return pool.healthmonitor.Delay +} + +func (listener *SLoadbalancerListener) GetHealthCheckReq() string { + return "" +} + +func (listener *SLoadbalancerListener) GetHealthCheckExp() string { + return "" +} + +func (listener *SLoadbalancerListener) GetStickySession() string { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) + return api.LB_BOOL_OFF + } + stickySession, err := pool.GetStickySession() + if err != nil { + log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) + return api.LB_BOOL_OFF + } + if stickySession == nil { + return "" + } + return stickySession.StickySession +} + +func (listener *SLoadbalancerListener) GetStickySessionType() string { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) + return "" + } + stickySession, err := pool.GetStickySession() + if err != nil { + log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) + return "" + } + if stickySession == nil { + return "" + } + return stickySession.StickySessionType +} + +func (listener *SLoadbalancerListener) GetStickySessionCookie() string { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) + return "" + } + stickySession, err := pool.GetStickySession() + if err != nil { + log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) + return "" + } + if stickySession == nil { + return "" + } + return stickySession.StickySessionCookie +} + +func (listener *SLoadbalancerListener) GetStickySessionCookieTimeout() int { + pool, err := listener.fetchFeaturePool() + if err != nil { + log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) + return 0 + } + stickySession, err := pool.GetStickySession() + if err != nil { + log.Errorf("GetStickySession():listener.fetchFeaturePool():%s", err) + return 0 + } + if stickySession == nil { + return 0 + } + return stickySession.StickySessionCookieTimeout +} + +func (listener *SLoadbalancerListener) XForwardedForEnabled() bool { + if listener.InsertHeaders.XForwardedFor == "true" { + return true + } + return false +} + +func (listener *SLoadbalancerListener) GzipEnabled() bool { + return false +} + +func (listener *SLoadbalancerListener) GetCertificateId() string { + return "" +} + +func (listener *SLoadbalancerListener) GetTLSCipherPolicy() string { + return listener.TLSCiphers +} + +func (listener *SLoadbalancerListener) HTTP2Enabled() bool { + return false +} + +func (listener *SLoadbalancerListener) fetchLoadbalancerListenerL7Policies() error { + l7policies := []SLoadbalancerL7Policy{} + for i := 0; i < len(listener.L7PolicieIds); i++ { + l7policy, err := listener.region.GetLoadbalancerL7PolicybyId(listener.L7PolicieIds[i].ID) + if err != nil { + return errors.Wrapf(err, "listener.region.GetLoadbalancerL7PolicybyId(%s)", listener.L7PolicieIds[i].ID) + } + l7policies = append(l7policies, *l7policy) + } + listener.l7policies = l7policies + return nil +} + +func (listener *SLoadbalancerListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} + for i := 0; i < len(listener.l7policies); i++ { + for j := 0; j < len(listener.l7policies[i].l7rules); j++ { + iRules = append(iRules, &listener.l7policies[i].l7rules[j]) + } + } + return iRules, nil +} + +func (region *SRegion) DeleteLoadbalancerListener(listenerId string) error { + _, err := region.lbDelete(fmt.Sprintf("/v2/lbaas/listeners/%s", listenerId)) + if err != nil { + return errors.Wrapf(err, `region.lbDelete("/v2/lbaas/listeners/%s")`, listenerId) + } + return nil +} + +func (listener *SLoadbalancerListener) Delete(ctx context.Context) error { + waitLbResStatus(listener, 10*time.Second, 1*time.Minute) + return listener.region.DeleteLoadbalancerListener(listener.ID) +} + +func (listener *SLoadbalancerListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + l7policy, err := listener.region.CreateLoadbalancerL7Policy(listener.ID, rule) + if err != nil { + return nil, errors.Wrapf(err, `listener.region.CreateLoadbalancerL7Policy(%s, rule)`, listener.ID) + } + // async wait + err = waitLbResStatus(l7policy, 10*time.Second, 8*time.Minute) + if err != nil { + return nil, errors.Wrap(err, `waitLbResStatus(l7policy, 10*time.Second, 8*time.Minute)`) + } + + l7rule, err := listener.region.CreateLoadbalancerL7Rule(l7policy.ID, rule) + if err != nil { + return nil, errors.Wrapf(err, `listener.region.CreateLoadbalancerL7Rule(%s, rule)`, l7policy.ID) + } + l7rule.policy = l7policy + // async wait + err = waitLbResStatus(l7rule, 10*time.Second, 8*time.Minute) + if err != nil { + return nil, errors.Wrap(err, `waitLbResStatus(l7rule, 10*time.Second, 8*time.Minute)`) + } + return l7rule, nil +} + +func (listener *SLoadbalancerListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + for i := 0; i < len(listener.l7policies); i++ { + for j := 0; j < len(listener.l7policies[i].l7rules); j++ { + if listener.l7policies[i].l7rules[j].GetId() == ruleId { + return &listener.l7policies[i].l7rules[j], nil + } + } + } + return nil, nil +} + +func (listener *SLoadbalancerListener) fetchLoadbalancerPools() error { + pools := []SLoadbalancerPool{} + if len(listener.DefaultPoolID) > 0 { + defaultPool, err := listener.region.GetLoadbalancerPoolById(listener.DefaultPoolID) + if err != nil { + return errors.Wrapf(err, "listener.region.GetLoadbalancerPoolById(%s)", listener.DefaultPoolID) + } + pools = append(pools, *defaultPool) + } + for i := 0; i < len(listener.l7policies); i++ { + if len(listener.l7policies[i].RedirectPoolID) > 0 { + policyPool, err := listener.region.GetLoadbalancerPoolById(listener.l7policies[i].RedirectPoolID) + if err != nil { + return errors.Wrapf(err, "listener.region.GetLoadbalancerPoolById(%s)", listener.l7policies[i].RedirectPoolID) + } + pools = append(pools, *policyPool) + } + } + listener.pools = pools + return nil +} + +func (listener *SLoadbalancerListener) fetchFeaturePool() (*SLoadbalancerPool, error) { + if len(listener.pools) < 1 { + return nil, fmt.Errorf("can't find pool with healthmonitor") + } + for i := 0; i < len(listener.pools); i++ { + if listener.pools[i].healthmonitor != nil { + return &listener.pools[i], nil + } + } + return &listener.pools[0], nil +} + +func (region *SRegion) UpdateLoadBalancerListenerAdminStateUp(AdminStateUp bool, loadbalancerListenerId string) error { + params := jsonutils.NewDict() + poolParam := jsonutils.NewDict() + poolParam.Add(jsonutils.NewBool(AdminStateUp), "admin_state_up") + params.Add(poolParam, "listener") + _, err := region.lbUpdate(fmt.Sprintf("/v2/lbaas/listeners/%s", loadbalancerListenerId), params) + if err != nil { + return errors.Wrapf(err, `region.lbUpdate(/v2/lbaas/listeners/%s, params)`, loadbalancerListenerId) + } + return nil +} + +func (region *SRegion) UpdateLoadBalancerListener(loadbalancerListenerId string, lblis *cloudprovider.SLoadbalancerListener) error { + type UpdateParams struct { + Listener SLoadbalancerListenerUpdateParams `json:"listener"` + } + params := UpdateParams{} + params.Listener.AdminStateUp = true + params.Listener.DefaultPoolId = lblis.BackendGroupID + + if lblis.ClientIdleTimeout != 0 { + // 毫秒单位 + msClientIdleTimeout := lblis.ClientIdleTimeout * 1000 + params.Listener.TimeoutClientData = &msClientIdleTimeout + } + if lblis.BackendConnectTimeout != 0 { + msBackendConnectTimeout := lblis.BackendConnectTimeout * 1000 + params.Listener.TimeoutMemberConnect = &msBackendConnectTimeout + } + if lblis.BackendIdleTimeout != 0 { + msBackendIdleTimeout := lblis.BackendIdleTimeout * 1000 + params.Listener.TimeoutMemberData = &msBackendIdleTimeout + } + params.Listener.Name = lblis.Name + if lblis.XForwardedFor { + params.Listener.InsertHeaders.XForwardedFor = "true" + } + _, err := region.lbUpdate(fmt.Sprintf("/v2/lbaas/listeners/%s", loadbalancerListenerId), jsonutils.Marshal(params)) + if err != nil { + return errors.Wrapf(err, `region.lbUpdate(/v2/lbaas/listeners/%s, jsonutils.Marshal(params))`, loadbalancerListenerId) + } + return nil +} + +func (listener *SLoadbalancerListener) Start() error { + // ensure listener status + err := waitLbResStatus(listener, 10*time.Second, 8*time.Minute) + if err != nil { + return errors.Wrap(err, ` waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) + } + err = listener.region.UpdateLoadBalancerListenerAdminStateUp(true, listener.ID) + if err != nil { + return errors.Wrapf(err, `listener.region.UpdateLoadBalancerListenerAdminStateUp(true, %s)`, listener.ID) + } + err = waitLbResStatus(listener, 10*time.Second, 8*time.Minute) + if err != nil { + return errors.Wrap(err, `waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) + } + return nil +} + +func (listener *SLoadbalancerListener) Stop() error { + // ensure listener status + err := waitLbResStatus(listener, 10*time.Second, 8*time.Minute) + if err != nil { + return errors.Wrap(err, ` waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) + } + err = listener.region.UpdateLoadBalancerListenerAdminStateUp(false, listener.ID) + if err != nil { + return errors.Wrapf(err, `listener.region.UpdateLoadBalancerListenerAdminStateUp(false,%s)`, listener.ID) + } + err = waitLbResStatus(listener, 10*time.Second, 8*time.Minute) + if err != nil { + return errors.Wrap(err, `waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) + } + return nil +} + +func (listener *SLoadbalancerListener) Sync(ctx context.Context, lblis *cloudprovider.SLoadbalancerListener) error { + // ensure listener status + err := waitLbResStatus(listener, 10*time.Second, 8*time.Minute) + if err != nil { + return errors.Wrap(err, ` waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) + } + err = listener.region.UpdateLoadBalancerListener(listener.ID, lblis) + if err != nil { + return errors.Wrapf(err, `listener.region.UpdateLoadBalancerListener(%s, lblis)`, listener.ID) + } + err = waitLbResStatus(listener, 10*time.Second, 8*time.Minute) + if err != nil { + return errors.Wrap(err, `waitLbResStatus(listener, 10*time.Second, 8*time.Minute)`) + } + return nil +} + +func (listener *SLoadbalancerListener) GetProjectId() string { + return listener.ProjectID +} + +func (listener *SLoadbalancerListener) GetClientIdleTimeout() int { + return 0 +} + +func (listener *SLoadbalancerListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/pkg/multicloud/openstack/loadbalancermember.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancermember.go similarity index 98% rename from pkg/multicloud/openstack/loadbalancermember.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancermember.go index 0c00927841..e77ae4a6ac 100644 --- a/pkg/multicloud/openstack/loadbalancermember.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalancermember.go @@ -24,8 +24,8 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SLoadbalancerMemberCreateParams struct { @@ -42,7 +42,7 @@ type SLoadbalancerMemberCreateParams struct { type SLoadbalancerMember struct { multicloud.SResourceBase - multicloud.OpenStackTags + OpenStackTags poolID string region *SRegion MonitorPort int `json:"monitor_port"` diff --git a/pkg/multicloud/openstack/loadbalbacer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalbacer.go similarity index 99% rename from pkg/multicloud/openstack/loadbalbacer.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalbacer.go index f8abf44783..3f6c09c7ff 100644 --- a/pkg/multicloud/openstack/loadbalbacer.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalbacer.go @@ -39,9 +39,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) var LB_ALGORITHM_MAP = map[string]string{ @@ -112,7 +112,7 @@ type SL7RuleID struct { type SLoadbalancer struct { multicloud.SLoadbalancerBase - multicloud.OpenStackTags + OpenStackTags region *SRegion Description string `json:"description"` diff --git a/pkg/multicloud/openstack/loadbalbancerhealthmonitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalbancerhealthmonitor.go similarity index 98% rename from pkg/multicloud/openstack/loadbalbancerhealthmonitor.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalbancerhealthmonitor.go index ef9ec90b6e..094014b153 100644 --- a/pkg/multicloud/openstack/loadbalbancerhealthmonitor.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/loadbalbancerhealthmonitor.go @@ -20,9 +20,9 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SLoadbalancerHealthmonitorCreateParams struct { @@ -59,7 +59,7 @@ type SLoadbalancerHealthmonitorUpdateParams struct { type SLoadbalancerHealthmonitor struct { multicloud.SResourceBase - multicloud.OpenStackTags + OpenStackTags region *SRegion ProjectID string `json:"project_id"` Name string `json:"name"` diff --git a/pkg/multicloud/openstack/message.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/message.go similarity index 100% rename from pkg/multicloud/openstack/message.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/message.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/network.go new file mode 100644 index 0000000000..de215a3aeb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/network.go @@ -0,0 +1,347 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + "net/url" + "strings" + "time" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type AllocationPool struct { + Start string `json:"start"` + End string `json:"end"` +} + +func (p AllocationPool) IsValid() bool { + for _, ip := range []string{p.Start, p.End} { + _, err := netutils.NewIPV4Addr(ip) + if err != nil { + return false + } + } + return true +} + +func (p AllocationPool) Equals(s AllocationPool) bool { + return p.Start == s.Start && p.End == s.End +} + +func (p AllocationPool) Contains(ip string) bool { + start, err := netutils.NewIPV4Addr(p.Start) + if err != nil { + return false + } + end, err := netutils.NewIPV4Addr(p.End) + if err != nil { + return false + } + addr, err := netutils.NewIPV4Addr(ip) + if err != nil { + return false + } + return netutils.NewIPV4AddrRange(start, end).Contains(addr) +} + +type SNextLinks []SNextLink + +func (links SNextLinks) GetNextMark() string { + for _, link := range links { + if link.Rel == "next" && len(link.Href) > 0 { + href, err := url.Parse(link.Href) + if err != nil { + log.Errorf("failed parse next link %s error: %v", link.Href, err) + continue + } + marker := href.Query().Get("marker") + if len(marker) > 0 { + return marker + } + } + } + return "" +} + +type SNextLink struct { + Href string + Rel string +} + +type SNetwork struct { + multicloud.SResourceBase + OpenStackTags + wire *SWire + + Name string + EnableDhcp bool + NetworkId string + SegmentId string + ProjectId string + TenantId string + DnsNameservers []string + AllocationPools []AllocationPool + HostRoutes []string + IpVersion int + GatewayIP string + CIDR string + Id string + CreatedAt time.Time + Description string + Ipv6AddressMode string + Ipv6RaMode string + RevisionNumber int + ServiceTypes []string + SubnetpoolId string + Tags []string + UpdatedAt time.Time +} + +func (network *SNetwork) GetId() string { + return network.Id +} + +func (network *SNetwork) GetName() string { + if len(network.Name) > 0 { + return network.Name + } + return network.Id +} + +func (network *SNetwork) GetGlobalId() string { + if len(network.AllocationPools) > 0 { + return fmt.Sprintf("%s|%s-%s", network.Id, network.AllocationPools[0].Start, network.AllocationPools[0].End) + } + return network.Id +} + +func (network *SNetwork) IsEmulated() bool { + return false +} + +func (network *SNetwork) GetStatus() string { + return api.NETWORK_STATUS_AVAILABLE +} + +func (network *SNetwork) Delete() error { + nw, err := network.wire.vpc.region.GetNetwork(network.Id) + if err != nil { + return errors.Wrapf(err, "GetNetwork(%s)", network.Id) + } + if len(nw.AllocationPools) <= 1 || len(network.AllocationPools) == 0 { + return network.wire.vpc.region.DeleteNetwork(network.Id) + } + pools := []AllocationPool{} + for i := range nw.AllocationPools { + if nw.AllocationPools[i].Equals(network.AllocationPools[0]) { + continue + } + pools = append(pools, nw.AllocationPools[i]) + } + + params := map[string]interface{}{ + "subnet": map[string]interface{}{ + "allocation_pools": pools, + }, + } + resource := fmt.Sprintf("/v2.0/subnets/%s", network.Id) + _, err = network.wire.vpc.region.vpcUpdate(resource, jsonutils.Marshal(params)) + return err +} + +func (region *SRegion) DeleteNetwork(networkId string) error { + resource := fmt.Sprintf("/v2.0/subnets/%s", networkId) + _, err := region.vpcDelete(resource) + return err +} + +func (network *SNetwork) GetIWire() cloudprovider.ICloudWire { + return network.wire +} + +func (network *SNetwork) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (network *SNetwork) GetGateway() string { + return network.GatewayIP +} + +func (network *SNetwork) GetIpStart() string { + if len(network.AllocationPools) >= 1 { + return network.AllocationPools[0].Start + } + return "" +} + +func (network *SNetwork) GetIpEnd() string { + if len(network.AllocationPools) >= 1 { + return network.AllocationPools[0].End + } + return "" +} + +func (network *SNetwork) GetIPRange() netutils.IPV4AddrRange { + start, _ := netutils.NewIPV4Addr(network.GetIpStart()) + end, _ := netutils.NewIPV4Addr(network.GetIpEnd()) + return netutils.NewIPV4AddrRange(start, end) +} + +func (network *SNetwork) Contains(ipAddr string) bool { + for _, pool := range network.AllocationPools { + if pool.Contains(ipAddr) { + return true + } + } + return false +} + +func (network *SNetwork) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(network.CIDR) + return pref.MaskLen +} + +func (network *SNetwork) GetIsPublic() bool { + return network.wire.vpc.Shared +} + +func (network *SNetwork) GetPublicScope() rbacutils.TRbacScope { + if network.wire.vpc.Shared { + return rbacutils.ScopeSystem + } + return rbacutils.ScopeNone +} + +func (network *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func getNetworkId(networkId string) (AllocationPool, string) { + pool := AllocationPool{} + if !strings.Contains(networkId, "|") { + return pool, networkId + } + info := strings.Split(networkId, "|") + networkId = info[0] + ipInfo := strings.Split(info[1], "-") + pool.Start, pool.End = ipInfo[0], ipInfo[1] + return pool, networkId +} + +func (region *SRegion) GetNetwork(networkId string) (*SNetwork, error) { + var pool AllocationPool + pool, networkId = getNetworkId(networkId) + resource := fmt.Sprintf("/v2.0/subnets/%s", networkId) + resp, err := region.vpcGet(resource) + if err != nil { + return nil, err + } + network := &SNetwork{} + err = resp.Unmarshal(network, "subnet") + if err != nil { + return nil, err + } + if len(pool.Start) == 0 && len(pool.End) == 0 { + return network, nil + } + for _, _pool := range network.AllocationPools { + if _pool.Equals(pool) { + network.AllocationPools = []AllocationPool{pool} + return network, nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "%s", networkId) +} + +func (region *SRegion) GetNetworks(vpcId string) ([]SNetwork, error) { + resource := "/v2.0/subnets" + networks := []SNetwork{} + query := url.Values{} + if len(vpcId) > 0 { + query.Set("network_id", vpcId) + } + for { + resp, err := region.vpcList(resource, query) + if err != nil { + return nil, errors.Wrap(err, "vpcList") + } + + part := struct { + Subnets []SNetwork + SubnetsLinks SNextLinks + }{} + + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + + networks = append(networks, part.Subnets...) + marker := part.SubnetsLinks.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return networks, nil +} + +func (network *SNetwork) Refresh() error { + _network, err := network.wire.vpc.region.GetNetwork(network.Id) + if err != nil { + return err + } + return jsonutils.Update(network, _network) +} + +func (region *SRegion) CreateNetwork(vpcId string, projectId, name string, cidr string, desc string) (*SNetwork, error) { + params := map[string]map[string]interface{}{ + "subnet": { + "name": name, + "network_id": vpcId, + "cidr": cidr, + "description": desc, + "ip_version": 4, + }, + } + if len(projectId) > 0 { + params["subnet"]["project_id"] = projectId + } + resp, err := region.vpcPost("/v2.0/subnets", params) + if err != nil { + return nil, errors.Wrap(err, "vpcPost") + } + network := &SNetwork{} + err = resp.Unmarshal(network, "subnet") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return network, nil +} + +func (network *SNetwork) GetProjectId() string { + return network.TenantId +} diff --git a/pkg/multicloud/openstack/nova_disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/nova_disk.go similarity index 94% rename from pkg/multicloud/openstack/nova_disk.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/nova_disk.go index eecc12e701..3104e99abc 100644 --- a/pkg/multicloud/openstack/nova_disk.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/nova_disk.go @@ -19,15 +19,15 @@ import ( "fmt" "time" - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SNovaDisk struct { multicloud.SDisk - multicloud.OpenStackTags + OpenStackTags storage *SNovaStorage region *SRegion diff --git a/pkg/multicloud/openstack/novastorage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/novastorage.go similarity index 94% rename from pkg/multicloud/openstack/novastorage.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/novastorage.go index eb4a094d95..287f1c3903 100644 --- a/pkg/multicloud/openstack/novastorage.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/novastorage.go @@ -19,14 +19,14 @@ import ( "yunion.io/x/jsonutils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SNovaStorage struct { multicloud.SStorageBase - multicloud.OpenStackTags + OpenStackTags host *SHypervisor zone *SZone } diff --git a/pkg/multicloud/openstack/openstack.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/openstack.go similarity index 99% rename from pkg/multicloud/openstack/openstack.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/openstack.go index c75e75795d..a5b599d8b1 100644 --- a/pkg/multicloud/openstack/openstack.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/openstack.go @@ -27,11 +27,11 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/multicloud" "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/version" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/port.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/port.go new file mode 100644 index 0000000000..cc3136f63e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/port.go @@ -0,0 +1,219 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "net/url" + "strings" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type DnsAssignment struct { + Hostname string + IpAddress string + Fqdn string +} + +type ExtraDhcpOpt struct { + OptValue string + IpVersion int + OptName string +} + +type SFixedIP struct { + port *SPort + + IpAddress string + SubnetID string +} + +func (fixip *SFixedIP) GetGlobalId() string { + return fixip.IpAddress +} + +func (fixip *SFixedIP) GetIP() string { + return fixip.IpAddress +} + +func (fixip *SFixedIP) GetINetworkId() string { + network, err := fixip.port.region.GetNetwork(fixip.SubnetID) + if err != nil { + return "" + } + for _, pool := range network.AllocationPools { + if pool.Contains(fixip.IpAddress) { + network.AllocationPools = []AllocationPool{pool} + return network.GetGlobalId() + } + } + return "" +} + +func (fixip *SFixedIP) IsPrimary() bool { + return true +} + +type SPort struct { + multicloud.SNetworkInterfaceBase + OpenStackTags + region *SRegion + AdminStateUp bool + AllowedAddressPairs []string + CreatedAt time.Time + DataPlaneStatus string + Description string + DeviceID string + DeviceOwner string + DnsAssignment []DnsAssignment + DnsDomain string + DnsName string + ExtraDhcpOpts []ExtraDhcpOpt + FixedIps []SFixedIP + ID string + IpAllocation string + MacAddress string + Name string + NetworkID string + ProjectID string + RevisionNumber int + SecurityGroups []string + Status string + Tags []string + TenantID string + UpdatedAt time.Time + QosPolicyID string + PortSecurityEnabled bool + UplinkStatusPropagation bool +} + +func (port *SPort) GetName() string { + if len(port.Name) > 0 { + return port.Name + } + return port.ID +} + +func (port *SPort) GetId() string { + return port.ID +} + +func (port *SPort) GetGlobalId() string { + return port.ID +} + +func (port *SPort) GetMacAddress() string { + return port.MacAddress +} + +func (port *SPort) GetAssociateType() string { + switch port.DeviceOwner { + case "compute:nova": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER + case "network:router_gateway", "network:dhcp", "network:router_interface": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_RESERVED + } + return port.DeviceOwner +} + +func (port *SPort) GetAssociateId() string { + return port.DeviceID +} + +func (port *SPort) GetStatus() string { + switch port.Status { + case "ACTIVE", "DOWN": + return api.NETWORK_INTERFACE_STATUS_AVAILABLE + case "BUILD": + return api.NETWORK_INTERFACE_STATUS_CREATING + } + return port.Status +} + +func (port *SPort) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { + address := []cloudprovider.ICloudInterfaceAddress{} + for i := 0; i < len(port.FixedIps); i++ { + port.FixedIps[i].port = port + address = append(address, &port.FixedIps[i]) + } + return address, nil +} + +func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { + ports, err := region.GetPorts("", "") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNetworkInterface{} + for i := 0; i < len(ports); i++ { + if strings.HasPrefix(ports[i].DeviceOwner, "compute:") || ports[i].DeviceOwner == "network:floatingip" { + continue + } + ports[i].region = region + ret = append(ret, &ports[i]) + } + return ret, nil +} + +func (region *SRegion) GetPort(portId string) (*SPort, error) { + resource := "/v2.0/ports/" + portId + resp, err := region.vpcGet(resource) + if err != nil { + return nil, err + } + port := &SPort{} + err = resp.Unmarshal(port, "port") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return port, nil +} + +func (region *SRegion) GetPorts(macAddress, deviceId string) ([]SPort, error) { + resource, ports := "/v2.0/ports", []SPort{} + query := url.Values{} + if len(macAddress) > 0 { + query.Set("mac_address", macAddress) + } + if len(deviceId) > 0 { + query.Set("device_id", deviceId) + } + for { + resp, err := region.vpcList(resource, query) + if err != nil { + return nil, errors.Wrap(err, "vpcList") + } + part := struct { + Ports []SPort + PortsLinks SNextLinks + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + ports = append(ports, part.Ports...) + marker := part.PortsLinks.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return ports, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/project.go new file mode 100644 index 0000000000..842ac072b4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/project.go @@ -0,0 +1,125 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + "net/url" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type SProject struct { + multicloud.SProjectBase + OpenStackTags + client *SOpenStackClient + Description string + Enabled bool + Id string + Name string +} + +func (p *SProject) GetId() string { + return p.Id +} + +func (p *SProject) GetGlobalId() string { + return p.GetId() +} + +func (p *SProject) GetName() string { + return p.Name +} + +func (p *SProject) GetStatus() string { + if !p.Enabled { + return api.EXTERNAL_PROJECT_STATUS_UNKNOWN + } + _, err := p.getToken() + if err != nil { + log.Errorf("get project %s token error: %v %T", p.Name, err, err) + return api.EXTERNAL_PROJECT_STATUS_UNKNOWN + } + return api.EXTERNAL_PROJECT_STATUS_AVAILABLE +} + +func (p *SProject) getToken() (mcclient.TokenCredential, error) { + return p.client.getProjectToken(p.Id, p.Name) +} + +func (p *SProject) IsEmulated() bool { + return false +} + +func (p *SProject) Refresh() error { + return nil +} + +type SProjectLinks struct { + Next string + Previous string + Self string +} + +func (link SProjectLinks) GetNextMark() string { + if len(link.Next) == 0 || link.Next == "null" { + return "" + } + next, err := url.Parse(link.Next) + if err != nil { + log.Errorf("parse next link %s error: %v", link.Next, err) + return "" + } + return next.Query().Get("marker") +} + +func (cli *SOpenStackClient) GetProjects() ([]SProject, error) { + resource := "/v3/projects" + projects := []SProject{} + query := url.Values{} + for { + resp, err := cli.iamRequest("", httputils.GET, resource, query, nil) + if err != nil { + return nil, errors.Wrap(err, "iamRequest") + } + part := struct { + Projects []SProject + Links SProjectLinks + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "iamRequest") + } + projects = append(projects, part.Projects...) + marker := part.Links.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return projects, nil +} + +func (cli *SOpenStackClient) DeleteProject(projectId string) error { + resource := fmt.Sprintf("/v3/projects/%s", projectId) + _, err := cli.iamRequest(cli.getDefaultRegionName(), httputils.DELETE, resource, nil, nil) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/provider/doc.go new file mode 100644 index 0000000000..e6c015c51a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/openstack/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/provider/provider.go new file mode 100644 index 0000000000..e9aac37d10 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/provider/provider.go @@ -0,0 +1,225 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/openstack" +) + +type SOpenStackProviderFactory struct { + cloudprovider.SPrivateCloudBaseProviderFactory +} + +var EndpointTypes = []string{"admin", "internal", "public"} + +func (self *SOpenStackProviderFactory) GetId() string { + return openstack.CLOUD_PROVIDER_OPENSTACK +} + +func (self *SOpenStackProviderFactory) GetName() string { + return openstack.CLOUD_PROVIDER_OPENSTACK +} + +func (self *SOpenStackProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.ProjectName) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "project_name") + } + if len(input.Username) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "username") + } + if len(input.Password) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "password") + } + if len(input.AuthUrl) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "auth_url") + } + + output.Account = fmt.Sprintf("%s/%s", input.ProjectName, input.Username) + if len(input.DomainName) > 0 { + output.Account = fmt.Sprintf("%s/%s", output.Account, input.DomainName) + } + + output.Secret = input.Password + output.AccessUrl = input.AuthUrl + return output, nil +} + +func (self *SOpenStackProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.ProjectName) == 0 { + accountInfo := strings.Split(cloudaccount, "/") + if len(accountInfo) < 2 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "project_name") + } + input.ProjectName = accountInfo[0] + } + if len(input.Username) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "username") + } + if len(input.Password) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "password") + } + + _account := fmt.Sprintf("%s/%s", input.ProjectName, input.Username) + if len(input.DomainName) == 0 { + if accountInfo := strings.Split(cloudaccount, "/"); len(accountInfo) == 3 { + input.DomainName = accountInfo[2] + } + } + + if len(input.DomainName) > 0 { + _account = fmt.Sprintf("%s/%s", _account, input.DomainName) + } + + output = cloudprovider.SCloudaccount{ + Account: _account, + Secret: input.Password, + } + return output, nil +} + +func (self *SOpenStackProviderFactory) IsNeedForceAutoCreateProject() bool { + return true +} + +func (self *SOpenStackProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + accountInfo := strings.Split(cfg.Account, "/") + if len(accountInfo) < 2 { + return nil, fmt.Errorf("Missing username or project name %s", cfg.Account) + } + project, username, endpointType, domainName, projectDomainName := accountInfo[0], accountInfo[1], "internal", "Default", "Default" + if len(accountInfo) == 3 { + domainName, projectDomainName = accountInfo[2], accountInfo[2] + } + client, err := openstack.NewOpenStackClient( + openstack.NewOpenstackClientConfig( + cfg.URL, + username, + cfg.Secret, + project, + projectDomainName, + ). + DomainName(domainName). + EndpointType(endpointType). + CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SOpenStackProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SOpenStackProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + accountInfo := strings.Split(info.Account, "/") + if len(accountInfo) < 2 { + return nil, fmt.Errorf("Missing username or project name %s", info.Account) + } + project, username, endpointType, domainName, projectDomainName := accountInfo[0], accountInfo[1], "internal", "Default", "Default" + if len(accountInfo) == 3 { + domainName, projectDomainName = accountInfo[2], accountInfo[2] + } + + return map[string]string{ + "OPENSTACK_AUTH_URL": info.Url, + "OPENSTACK_USERNAME": username, + "OPENSTACK_PASSWORD": info.Secret, + "OPENSTACK_PROJECT": project, + "OPENSTACK_ENDPOINT_TYPE": endpointType, + "OPENSTACK_DOMAIN_NAME": domainName, + "OPENSTACK_PROJECT_DOMAIN": projectDomainName, + "OPENSTACK_REGION_ID": openstack.OPENSTACK_DEFAULT_REGION, + }, nil +} + +func init() { + factory := SOpenStackProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SOpenStackProvider struct { + cloudprovider.SBaseProvider + client *openstack.SOpenStackClient +} + +func (self *SOpenStackProvider) GetVersion() string { + return "" +} + +func (self *SOpenStackProvider) GetSysInfo() (jsonutils.JSONObject, error) { + return jsonutils.NewDict(), nil +} + +func (self *SOpenStackProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SOpenStackProvider) GetAccountId() string { + return "" +} + +func (self *SOpenStackProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SOpenStackProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(extId) +} + +func (self *SOpenStackProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, cloudprovider.ErrNotSupported +} + +func (self *SOpenStackProvider) GetCloudRegionExternalIdPrefix() string { + return self.client.GetCloudRegionExternalIdPrefix() +} + +func (self *SOpenStackProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SOpenStackProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return self.client.CreateIProject(name) +} + +func (self *SOpenStackProvider) GetStorageClasses(regionId string) []string { + return nil +} + +func (self *SOpenStackProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (self *SOpenStackProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (self *SOpenStackProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/quota.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/quota.go new file mode 100644 index 0000000000..7d26364de8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/quota.go @@ -0,0 +1,165 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type QuotaDetail struct { + Reserved int + Limit int + InUse int +} + +type QuotaSet struct { + InjectedFileContentBytes QuotaDetail + MetadataItems QuotaDetail + ServerGroupMembers QuotaDetail + ServerGroups QuotaDetail + Ram QuotaDetail + FloatingIps QuotaDetail + KeyPairs QuotaDetail + Id string + Instances QuotaDetail + SecurityGroupRules QuotaDetail + InjectedFiles QuotaDetail + Cores QuotaDetail + FixedIps QuotaDetail + InjectedFilePathBytes QuotaDetail + SecurityGroups QuotaDetail +} + +type SQuota struct { + Cores int + Instances int + KeyPairs int + FixedIps int + MetadataItems int + Ram int + ServerGroups int + ServerGroupMembers int + InjectedFileContentBytes int + InjectedFilePathBytes int + InjectedFiles int + Floatingips int + Networks int + Port int + RbacPolicy int + Router int + SecurityGroups int + SecurityGroupRules int +} + +func (region *SRegion) GetQuota() (*QuotaSet, error) { + resource := fmt.Sprintf("/os-quota-sets/%s/detail", region.client.tokenCredential.GetTenantId()) + resp, err := region.ecsGet(resource) + if err != nil { + return nil, errors.Wrap(err, "ecsGet") + } + quota := &QuotaSet{} + return quota, resp.Unmarshal(quota, "quota_set") +} + +func (region *SRegion) SetQuota(quota *SQuota) error { + params := map[string]map[string]interface{}{ + "quota_set": { + "force": "True", + }, + } + + if quota.Floatingips > 0 { + params["quota_set"]["floating_ips"] = quota.Floatingips + } + + if quota.SecurityGroups > 0 { + params["quota_set"]["security_group"] = quota.SecurityGroups + } + + if quota.SecurityGroupRules > 0 { + params["quota_set"]["security_group_rules"] = quota.SecurityGroupRules + } + + if quota.FixedIps > 0 { + params["quota_set"]["fixed_ips"] = quota.FixedIps + } + + if quota.Networks > 0 { + params["quota_set"]["networks"] = quota.Networks + } + + resource := "/os-quota-sets/" + region.client.tokenCredential.GetTenantId() + _, err := region.ecsUpdate(resource, params) + return err +} + +type IQuota struct { + Name string + Limit int + InUse int +} + +func (iq *IQuota) GetGlobalId() string { + return iq.Name +} + +func (iq *IQuota) GetName() string { + return iq.Name +} + +func (iq *IQuota) GetDesc() string { + return "" +} + +func (iq *IQuota) GetQuotaType() string { + return iq.Name +} + +func (iq *IQuota) GetMaxQuotaCount() int { + return iq.Limit +} + +func (iq *IQuota) GetCurrentQuotaUsedCount() int { + return iq.InUse +} + +func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { + quota, err := region.GetQuota() + if err != nil { + return nil, errors.Wrap(err, "GetQuota") + } + + ret := []cloudprovider.ICloudQuota{} + + ret = append(ret, &IQuota{Name: "injected_file_content_bytes", Limit: quota.InjectedFileContentBytes.Limit, InUse: quota.InjectedFileContentBytes.InUse}) + ret = append(ret, &IQuota{Name: "metadata_items", Limit: quota.MetadataItems.Limit, InUse: quota.MetadataItems.InUse}) + ret = append(ret, &IQuota{Name: "server_group_members", Limit: quota.ServerGroupMembers.Limit, InUse: quota.ServerGroupMembers.InUse}) + ret = append(ret, &IQuota{Name: "server_groups", Limit: quota.ServerGroups.Limit, InUse: quota.ServerGroups.InUse}) + ret = append(ret, &IQuota{Name: "ram", Limit: quota.Ram.Limit, InUse: quota.Ram.InUse}) + ret = append(ret, &IQuota{Name: "floating_ips", Limit: quota.FloatingIps.Limit, InUse: quota.FloatingIps.InUse}) + ret = append(ret, &IQuota{Name: "key_pairs", Limit: quota.KeyPairs.Limit, InUse: quota.KeyPairs.InUse}) + ret = append(ret, &IQuota{Name: "instances", Limit: quota.Instances.Limit, InUse: quota.Instances.InUse}) + ret = append(ret, &IQuota{Name: "security_group_rules", Limit: quota.SecurityGroupRules.Limit, InUse: quota.SecurityGroupRules.InUse}) + ret = append(ret, &IQuota{Name: "injected_files", Limit: quota.InjectedFiles.Limit, InUse: quota.InjectedFiles.InUse}) + ret = append(ret, &IQuota{Name: "cores", Limit: quota.Cores.Limit, InUse: quota.Cores.InUse}) + ret = append(ret, &IQuota{Name: "fixed_ips", Limit: quota.FixedIps.Limit, InUse: quota.FixedIps.InUse}) + ret = append(ret, &IQuota{Name: "injected_file_path_bytes", Limit: quota.InjectedFilePathBytes.Limit, InUse: quota.InjectedFilePathBytes.InUse}) + ret = append(ret, &IQuota{Name: "security_groups", Limit: quota.SecurityGroups.Limit, InUse: quota.SecurityGroups.InUse}) + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/region.go new file mode 100644 index 0000000000..d0578bf4dc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/region.go @@ -0,0 +1,620 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + "io" + "net/url" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type SRegion struct { + multicloud.SRegion + + client *SOpenStackClient + + Name string + + vpcs []SVpc + + storageCache *SStoragecache + routers []SRouter +} + +func (region *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + backendGroups := []cloudprovider.ICloudLoadbalancerBackendGroup{} + pools, err := region.GetLoadbalancerPools() + if err != nil { + return backendGroups, errors.Wrap(err, "region.GetLoadbalancerPools()") + } + for i := 0; i < len(pools); i++ { + backendGroups = append(backendGroups, &pools[i]) + } + return backendGroups, nil +} + +func (region *SRegion) GetClient() *SOpenStackClient { + return region.client +} + +func (region *SRegion) GetId() string { + return region.Name +} + +func (region *SRegion) GetName() string { + return fmt.Sprintf("%s-%s", region.client.cpcfg.Name, region.Name) +} + +func (region *SRegion) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(region.GetName()).CN(region.GetName()) + return table +} + +func (region *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s/%s", CLOUD_PROVIDER_OPENSTACK, region.client.cpcfg.Id, region.Name) +} + +func (region *SRegion) IsEmulated() bool { + return false +} + +func (region *SRegion) GetProvider() string { + return CLOUD_PROVIDER_OPENSTACK +} + +func (region *SRegion) GetCloudEnv() string { + return "" +} + +func (region *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + return cloudprovider.SGeographicInfo{} +} + +func (region *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (region *SRegion) Refresh() error { + // do nothing + return nil +} + +func (region *SRegion) GetMaxVersion(service string) (string, error) { + return region.client.GetMaxVersion(region.Name, service) +} + +func (region *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + vpc, err := region.CreateVpc(opts.NAME, opts.Desc) + if err != nil { + return nil, errors.Wrap(err, "CreateVp") + } + return vpc, nil +} + +func (region *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + izones, err := region.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i++ { + ihost, err := izones[i].GetIHostById(id) + if err == nil { + return ihost, nil + } else if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + izones, err := region.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i++ { + istore, err := izones[i].GetIStorageById(id) + if err == nil { + return istore, nil + } else if errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := []cloudprovider.ICloudHost{} + izones, err := region.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i++ { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +func (region *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + izones, err := region.GetIZones() + if err != nil { + return nil, err + } + iStorages := []cloudprovider.ICloudStorage{} + for i := 0; i < len(izones); i++ { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStorages = append(iStorages, iZoneStores...) + } + return iStorages, nil +} + +func (region *SRegion) getStoragecache() *SStoragecache { + if region.storageCache == nil { + region.storageCache = &SStoragecache{region: region} + } + return region.storageCache +} + +func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + storageCache := region.getStoragecache() + if storageCache.GetGlobalId() == id { + return region.storageCache, nil + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storageCache := region.getStoragecache() + return []cloudprovider.ICloudStoragecache{storageCache}, nil +} + +func (region *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + instance, err := region.GetInstance(id) + if err != nil { + return nil, errors.Wrapf(err, "GetInstance(%s)", id) + } + hosts, err := region.GetIHosts() + if err != nil { + return nil, err + } + for i := range hosts { + host := hosts[i].(*SHypervisor) + if instance.HypervisorHostname == host.HypervisorHostname { + instance.host = host + } + } + return instance, nil +} + +func (region *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disk, err := region.GetDisk(id) + if err != nil { + _, err := region.GetInstance(id) + if err == nil { + return &SNovaDisk{region: region, instanceId: id}, nil + } + return nil, errors.Wrapf(err, "GetDisk(%s)", id) + } + return disk, nil +} + +func (region *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + vpc, err := region.GetVpc(id) + if err != nil { + return nil, errors.Wrapf(err, "GetVpc(%s)", id) + } + return vpc, nil +} + +func (region *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := region.GetIZones() + if err != nil { + return nil, errors.Wrap(err, "GetIZones") + } + for i := 0; i < len(izones); i++ { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetZones() ([]SZone, error) { + zones, err := region.getZones() + if err != nil { + return nil, errors.Wrap(err, "getZones") + } + ret := []SZone{} + for i := 0; i < len(zones); i++ { + if zones[i].ZoneName == "internal" { + continue + } + zones[i].region = region + ret = append(ret, zones[i]) + } + return ret, nil +} + +func (region *SRegion) fetchVpcs() error { + if len(region.vpcs) > 0 { + return nil + } + var err error + region.vpcs, err = region.GetVpcs("") + if err != nil { + return errors.Wrap(err, "GetVpcs") + } + return nil +} + +func (region *SRegion) ecsList(resource string, query url.Values) (jsonutils.JSONObject, error) { + return region.client.ecsRequest(region.Name, httputils.GET, resource, query, nil) +} + +func (region *SRegion) ecsGet(resource string) (jsonutils.JSONObject, error) { + return region.client.ecsRequest(region.Name, httputils.GET, resource, nil, nil) +} + +func (region *SRegion) ecsUpdate(resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.ecsRequest(region.Name, httputils.PUT, resource, nil, params) +} + +func (region *SRegion) ecsPost(resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.ecsRequest(region.Name, httputils.POST, resource, nil, params) +} + +func (region *SRegion) ecsDo(projectId, resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.ecsDo(projectId, region.Name, resource, params) +} + +func (region *SRegion) ecsDelete(resource string) (jsonutils.JSONObject, error) { + return region.client.ecsRequest(region.Name, httputils.DELETE, resource, nil, nil) +} + +func (region *SRegion) ecsCreate(projectId, resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.ecsCreate(projectId, region.Name, resource, params) +} + +func (region *SRegion) vpcList(resource string, query url.Values) (jsonutils.JSONObject, error) { + return region.client.vpcRequest(region.Name, httputils.GET, resource, query, nil) +} + +func (region *SRegion) vpcGet(resource string) (jsonutils.JSONObject, error) { + return region.client.vpcRequest(region.Name, httputils.GET, resource, nil, nil) +} + +func (region *SRegion) vpcUpdate(resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.vpcRequest(region.Name, httputils.PUT, resource, nil, params) +} + +func (region *SRegion) vpcPost(resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.vpcRequest(region.Name, httputils.POST, resource, nil, params) +} + +func (region *SRegion) vpcDelete(resource string) (jsonutils.JSONObject, error) { + return region.client.vpcRequest(region.Name, httputils.DELETE, resource, nil, nil) +} + +func (region *SRegion) imageList(resource string, query url.Values) (jsonutils.JSONObject, error) { + return region.client.imageRequest(region.Name, httputils.GET, resource, query, nil) +} + +func (region *SRegion) imageGet(resource string) (jsonutils.JSONObject, error) { + return region.client.imageRequest(region.Name, httputils.GET, resource, nil, nil) +} + +func (region *SRegion) imagePost(resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.imageRequest(region.Name, httputils.POST, resource, nil, params) +} + +func (region *SRegion) imageDelete(resource string) (jsonutils.JSONObject, error) { + return region.client.imageRequest(region.Name, httputils.DELETE, resource, nil, nil) +} + +func (region *SRegion) imageUpload(url string, size int64, body io.Reader, callback func(progress float32)) error { + resp, err := region.client.imageUpload(region.Name, url, size, body, callback) + _, _, err = httputils.ParseResponse("", resp, err, region.client.debug) + return err +} + +// Block Storage +func (region *SRegion) bsList(resource string, query url.Values) (jsonutils.JSONObject, error) { + return region.client.bsRequest(region.Name, httputils.GET, resource, query, nil) +} + +func (region *SRegion) bsGet(resource string) (jsonutils.JSONObject, error) { + return region.client.bsRequest(region.Name, httputils.GET, resource, nil, nil) +} + +func (region *SRegion) bsUpdate(resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.bsRequest(region.Name, httputils.PUT, resource, nil, params) +} + +func (region *SRegion) bsPost(resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.bsRequest(region.Name, httputils.POST, resource, nil, params) +} + +func (region *SRegion) bsDelete(resource string) (jsonutils.JSONObject, error) { + return region.client.bsRequest(region.Name, httputils.DELETE, resource, nil, nil) +} + +func (region *SRegion) bsCreate(projectId, resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.bsCreate(projectId, region.Name, resource, params) +} + +//loadbalancer + +func (region *SRegion) lbList(resource string, query url.Values) (jsonutils.JSONObject, error) { + return region.client.lbRequest(region.Name, httputils.GET, resource, query, nil) +} + +func (region *SRegion) lbGet(resource string) (jsonutils.JSONObject, error) { + return region.client.lbRequest(region.Name, httputils.GET, resource, nil, nil) +} + +func (region *SRegion) lbUpdate(resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.lbRequest(region.Name, httputils.PUT, resource, nil, params) +} + +func (region *SRegion) lbPost(resource string, params interface{}) (jsonutils.JSONObject, error) { + return region.client.lbRequest(region.Name, httputils.POST, resource, nil, params) +} + +func (region *SRegion) lbDelete(resource string) (jsonutils.JSONObject, error) { + return region.client.lbRequest(region.Name, httputils.DELETE, resource, nil, nil) +} + +func (region *SRegion) ProjectId() string { + return region.client.tokenCredential.GetProjectId() +} + +func (region *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + zones, err := region.GetZones() + if err != nil { + return nil, errors.Wrapf(err, "GetZones") + } + ret := []cloudprovider.ICloudZone{} + for i := range zones { + ret = append(ret, &zones[i]) + } + return ret, nil +} + +func (region *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + err := region.fetchVpcs() + if err != nil { + return nil, errors.Wrap(err, "fetchVpcs") + } + ivpcs := []cloudprovider.ICloudVpc{} + for i := range region.vpcs { + region.vpcs[i].region = region + ivpcs = append(ivpcs, ®ion.vpcs[i]) + } + return ivpcs, nil +} + +func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, err := region.GetEips("") + if err != nil { + return nil, err + } + ieips := []cloudprovider.ICloudEIP{} + for i := 0; i < len(eips); i++ { + eips[i].region = region + ieips = append(ieips, &eips[i]) + } + return ieips, nil +} + +func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + network, err := region.GetNetwork(eip.NetworkExternalId) + if err != nil { + return nil, errors.Wrapf(err, "GetNetwork(%s)", eip.NetworkExternalId) + } + ieip, err := region.CreateEip(network.NetworkId, eip.NetworkExternalId, eip.IP, eip.ProjectId) + if err != nil { + return nil, errors.Wrap(err, "CreateEip") + } + return ieip, nil +} + +func (region *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { + return region.GetEip(eipId) +} + +func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + loadbalancers := []cloudprovider.ICloudLoadbalancer{} + sloadbalancers, err := region.GetLoadbalancers() + if err != nil { + return nil, errors.Wrap(err, "region.GetLoadbalancers()") + } + for i := 0; i < len(sloadbalancers); i++ { + loadbalancers = append(loadbalancers, &sloadbalancers[i]) + } + return loadbalancers, nil +} + +func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { + sloadbalancer, err := region.GetLoadbalancerbyId(loadbalancerId) + if err != nil { + return nil, errors.Wrapf(err, "region.GetLoadbalancerbyId(%s)", loadbalancerId) + } + return sloadbalancer, nil +} + +func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { + return region.GetLoadbalancerAclDetail(aclId) +} + +func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { + iloadbalancerAcls := []cloudprovider.ICloudLoadbalancerAcl{} + acls, err := region.GetLoadBalancerAcls() + if err != nil { + return nil, errors.Wrap(err, "region.GetLoadBalancerAcls") + } + for i := 0; i < len(acls); i++ { + iloadbalancerAcls = append(iloadbalancerAcls, &acls[i]) + } + return iloadbalancerAcls, nil +} + +func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + sloadbalancer, err := region.CreateLoadBalancer(loadbalancer) + if err != nil { + return nil, errors.Wrap(err, "region.CreateLoadBalancer") + } + return sloadbalancer, nil +} + +func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + sacl, err := region.CreateLoadBalancerAcl(acl) + if err != nil { + return nil, errors.Wrap(err, "region.CreateLoadBalancerAcl(acl)") + } + err = cloudprovider.WaitMultiStatus(sacl.listener, []string{api.LB_STATUS_ENABLED, api.LB_STATUS_UNKNOWN}, 10*time.Second, 8*time.Minute) + if err != nil { + return nil, errors.Wrap(err, "cloudprovider.WaitMultiStatus") + } + if sacl.listener.GetStatus() == api.LB_STATUS_UNKNOWN { + return nil, errors.Wrap(fmt.Errorf("status error"), "check status") + } + return sacl, nil +} + +func (region *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { + flavors, err := region.GetFlavors() + if err != nil { + return nil, err + } + iskus := make([]cloudprovider.ICloudSku, len(flavors)) + for i := 0; i < len(flavors); i++ { + flavors[i].region = region + iskus[i] = &flavors[i] + } + return iskus, nil +} + +func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) CreateIBucket(name string, storageClassStr string, acl string) error { + return cloudprovider.ErrNotImplemented +} + +func (region *SRegion) DeleteIBucket(name string) error { + return cloudprovider.ErrNotImplemented +} + +func (region *SRegion) IBucketExist(name string) (bool, error) { + return false, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return region.GetSecurityGroup(secgroupId) +} + +func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := region.GetSecurityGroups(opts.ProjectId, opts.Name) + if err != nil { + return nil, err + } + if len(secgroups) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(secgroups) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + secgroups[0].region = region + return &secgroups[0], nil +} + +func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return region.CreateSecurityGroup(conf.ProjectId, conf.Name, conf.Desc) +} + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} + +func (region *SRegion) GetRouters() ([]SRouter, error) { + resource := "/v2.0/routers" + resp, err := region.vpcList(resource, nil) + if err != nil { + return nil, errors.Wrap(err, "vpcList.routes") + } + routers := []SRouter{} + err = resp.Unmarshal(&routers, "routers") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + for i := 0; i < len(routers); i++ { + ports, err := region.GetPorts("", routers[i].Id) + if err != nil { + return nil, errors.Wrap(err, "vpc.region.GetPortsByDeviceId") + } + routers[i].ports = ports + } + return routers, nil +} + +func (region *SRegion) fetchrouters() error { + if len(region.routers) > 0 { + return nil + } + routers, err := region.GetRouters() + if err != nil { + return errors.Wrap(err, "region.GetRouters()") + } + region.routers = routers + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/roles.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/roles.go new file mode 100644 index 0000000000..fc84f65bee --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/roles.go @@ -0,0 +1,67 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + "net/url" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type SRole struct { + Id string + Name string +} + +func (cli *SOpenStackClient) GetRoles(name string) ([]SRole, error) { + resource := "/v3/roles" + query := url.Values{} + if len(name) > 0 { + query.Set("name", name) + } + resp, err := cli.iamRequest(cli.getDefaultRegionName(), httputils.GET, resource, query, nil) + if err != nil { + return nil, errors.Wrap(err, "iamRequest") + } + roles := []SRole{} + err = resp.Unmarshal(&roles, "roles") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return roles, nil +} + +func (cli *SOpenStackClient) AssignRoleToUserOnProject(userId, projectId, roleName string) error { + if len(roleName) == 0 { + return errors.Error("empty role name") + } + roles, err := cli.GetRoles(roleName) + if err != nil { + return errors.Wrapf(err, "GetRoles(%s)", roleName) + } + if len(roles) == 0 { + return errors.Wrapf(cloudprovider.ErrNotFound, "role %s", roleName) + } + if len(roles) > 1 { + return errors.Wrapf(cloudprovider.ErrDuplicateId, "roles %d for %s", len(roles), roleName) + } + resource := fmt.Sprintf("/v3/projects/%s/users/%s/roles/%s", projectId, userId, roles[0].Id) + _, err = cli.iamRequest(cli.getDefaultRegionName(), httputils.PUT, resource, nil, map[string]string{}) + return err +} diff --git a/pkg/multicloud/openstack/router.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/router.go similarity index 100% rename from pkg/multicloud/openstack/router.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/router.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/routetable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/routetable.go new file mode 100644 index 0000000000..3777af6e66 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/routetable.go @@ -0,0 +1,139 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRouteEntry struct { + multicloud.SResourceBase + OpenStackTags + Destination string `json:"destination"` + Nexthop string `json:"nexthop"` +} + +func (route *SRouteEntry) GetId() string { + return route.Destination + ":" + route.Nexthop +} +func (route *SRouteEntry) GetName() string { + return "" +} +func (route *SRouteEntry) GetGlobalId() string { + return route.GetId() +} + +func (route *SRouteEntry) GetStatus() string { + return "" +} + +func (route *SRouteEntry) Refresh() error { + return nil +} + +func (route *SRouteEntry) IsEmulated() bool { + return false +} + +func (route *SRouteEntry) GetType() string { + return api.ROUTE_ENTRY_TYPE_CUSTOM +} + +func (route *SRouteEntry) GetCidr() string { + return route.Destination +} + +func (route *SRouteEntry) GetNextHopType() string { + return route.Nexthop +} + +func (route *SRouteEntry) GetNextHop() string { + return route.Nexthop +} + +type SRouteTable struct { + multicloud.SResourceBase + OpenStackTags + vpc *SVpc + entries []SRouteEntry + router *SRouter +} + +func (self *SRouteTable) GetDescription() string { + return "" +} + +func (self *SRouteTable) GetId() string { + return self.GetGlobalId() +} + +func (self *SRouteTable) GetGlobalId() string { + return self.router.Id +} + +func (self *SRouteTable) GetName() string { + return self.router.Name +} + +func (self *SRouteTable) GetRegionId() string { + return self.vpc.region.GetId() +} + +func (self *SRouteTable) GetType() cloudprovider.RouteTableType { + return cloudprovider.RouteTableTypeSystem +} + +func (self *SRouteTable) GetVpcId() string { + return self.vpc.GetId() +} + +func (self *SRouteTable) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { + ret := []cloudprovider.ICloudRoute{} + for index := range self.entries { + ret = append(ret, &self.entries[index]) + } + return ret, nil +} + +func (self *SRouteTable) GetStatus() string { + return self.router.Status +} + +func (self *SRouteTable) IsEmulated() bool { + return false +} + +func (self *SRouteTable) Refresh() error { + return nil +} + +func (self *SRouteTable) GetAssociations() []cloudprovider.RouteTableAssociation { + result := []cloudprovider.RouteTableAssociation{} + return result +} + +func (self *SRouteTable) CreateRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteTable) UpdateRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteTable) RemoveRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/securitygroup.go new file mode 100644 index 0000000000..116b19c35a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/securitygroup.go @@ -0,0 +1,324 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + "net/url" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +const ( + SECGROUP_NOT_SUPPORT = "openstack_skip_security_group" +) + +type SSecurityGroupRule struct { + Direction string + Ethertype string + Id string + PortRangeMax int + PortRangeMin int + Protocol string + RemoteGroupId string + RemoteIpPrefix string + SecurityGroupId string + ProjectId string + RevisionNumber int + Tags []string + TenantId string + CreatedAt time.Time + UpdatedAt time.Time + Description string +} + +type SSecurityGroup struct { + multicloud.SSecurityGroup + OpenStackTags + region *SRegion + + Description string + Id string + Name string + SecurityGroupRules []SSecurityGroupRule + ProjectId string + RevisionNumber int + CreatedAt time.Time + UpdatedAt time.Time + Tags []string + TenantId string +} + +func (region *SRegion) GetSecurityGroup(secgroupId string) (*SSecurityGroup, error) { + resource := "/v2.0/security-groups/" + secgroupId + resp, err := region.vpcGet(resource) + if err != nil { + return nil, errors.Wrap(err, "vpcGet") + } + secgroup := &SSecurityGroup{region: region} + err = resp.Unmarshal(secgroup, "security_group") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return secgroup, nil +} + +func (region *SRegion) GetSecurityGroups(projectId, name string) ([]SSecurityGroup, error) { + secgroups := []SSecurityGroup{} + resource := "/v2.0/security-groups" + query := url.Values{} + if len(name) > 0 { + query.Set("name", name) + } + if len(projectId) > 0 { + query.Set("project_id", projectId) + } + for { + resp, err := region.vpcList(resource, query) + if err != nil { + return nil, errors.Wrap(err, "vpcList") + } + part := struct { + SecurityGroups []SSecurityGroup + SecurityGroupsLinks SNextLinks + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + secgroups = append(secgroups, part.SecurityGroups...) + marker := part.SecurityGroupsLinks.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return secgroups, nil +} + +func (secgroup *SSecurityGroup) GetVpcId() string { + return "normal" +} + +func (secgroup *SSecurityGroup) GetId() string { + return secgroup.Id +} + +func (secgroup *SSecurityGroup) GetGlobalId() string { + return secgroup.Id +} + +func (secgroup *SSecurityGroup) GetDescription() string { + return secgroup.Description +} + +func (secgroup *SSecurityGroup) GetName() string { + if len(secgroup.Name) > 0 { + return secgroup.Name + } + return secgroup.Id +} + +func (secgrouprule *SSecurityGroupRule) toRules() ([]cloudprovider.SecurityRule, error) { + rules := []cloudprovider.SecurityRule{} + // 暂时忽略IPv6安全组规则,忽略远端也是安全组的规则 + if secgrouprule.Ethertype != "IPv4" || len(secgrouprule.RemoteGroupId) > 0 { + return rules, fmt.Errorf("ethertype: %s remoteGroupId: %s", secgrouprule.Ethertype, secgrouprule.RemoteGroupId) + } + rule := cloudprovider.SecurityRule{ + ExternalId: secgrouprule.Id, + SecurityRule: secrules.SecurityRule{ + Direction: secrules.DIR_IN, + Action: secrules.SecurityRuleAllow, + Description: secgrouprule.Description, + }, + } + if utils.IsInStringArray(secgrouprule.Protocol, []string{"any", "-1", ""}) { + rule.Protocol = secrules.PROTO_ANY + } else if utils.IsInStringArray(secgrouprule.Protocol, []string{"6", "tcp"}) { + rule.Protocol = secrules.PROTO_TCP + } else if utils.IsInStringArray(secgrouprule.Protocol, []string{"17", "udp"}) { + rule.Protocol = secrules.PROTO_UDP + } else if utils.IsInStringArray(secgrouprule.Protocol, []string{"1", "icmp"}) { + rule.Protocol = secrules.PROTO_ICMP + } else { + return rules, errors.Wrap(httperrors.ErrUnsupportedProtocol, secgrouprule.Protocol) + } + if secgrouprule.Direction == "egress" { + rule.Direction = secrules.DIR_OUT + } + if len(secgrouprule.RemoteIpPrefix) == 0 { + secgrouprule.RemoteIpPrefix = "0.0.0.0/0" + } + + rule.ParseCIDR(secgrouprule.RemoteIpPrefix) + if secgrouprule.PortRangeMax > 0 && secgrouprule.PortRangeMin > 0 { + if secgrouprule.PortRangeMax == secgrouprule.PortRangeMin { + rule.Ports = []int{secgrouprule.PortRangeMax} + } else { + rule.PortStart = secgrouprule.PortRangeMin + rule.PortEnd = secgrouprule.PortRangeMax + } + } + err := rule.ValidateRule() + if err != nil && err != secrules.ErrInvalidPriority { + return rules, errors.Wrap(err, "rule.ValidateRule") + } + return []cloudprovider.SecurityRule{rule}, nil +} + +func (secgroup *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + rules := []cloudprovider.SecurityRule{} + for _, rule := range secgroup.SecurityGroupRules { + subRules, err := rule.toRules() + if err != nil { + log.Errorf("failed to convert rule %s for secgroup %s(%s) error: %v", rule.Id, secgroup.Name, secgroup.Id, err) + continue + } + rules = append(rules, subRules...) + } + return rules, nil +} + +func (secgroup *SSecurityGroup) GetStatus() string { + return "" +} + +func (secgroup *SSecurityGroup) IsEmulated() bool { + return false +} + +func (secgroup *SSecurityGroup) Refresh() error { + new, err := secgroup.region.GetSecurityGroup(secgroup.Id) + if err != nil { + return err + } + return jsonutils.Update(secgroup, new) +} + +func (region *SRegion) delSecurityGroupRule(ruleId string) error { + resource := "/v2.0/security-group-rules/" + ruleId + _, err := region.vpcDelete(resource) + return err +} + +func (region *SRegion) addSecurityGroupRules(secgroupId string, rule cloudprovider.SecurityRule) error { + direction := "ingress" + if rule.Direction == secrules.SecurityRuleEgress { + direction = "egress" + } + + if rule.Protocol == secrules.PROTO_ANY { + rule.Protocol = "" + } + + ruleInfo := map[string]interface{}{ + "direction": direction, + "security_group_id": secgroupId, + "remote_ip_prefix": rule.IPNet.String(), + } + if len(rule.Protocol) > 0 { + ruleInfo["protocol"] = rule.Protocol + } + + params := map[string]map[string]interface{}{ + "security_group_rule": ruleInfo, + } + if len(rule.Ports) > 0 { + for _, port := range rule.Ports { + params["security_group_rule"]["port_range_max"] = port + params["security_group_rule"]["port_range_min"] = port + resource := "/v2.0/security-group-rules" + _, err := region.vpcPost(resource, params) + if err != nil { + return errors.Wrap(err, "vpcPost") + } + } + return nil + } + if rule.PortEnd > 0 && rule.PortStart > 0 { + params["security_group_rule"]["port_range_min"] = rule.PortStart + params["security_group_rule"]["port_range_max"] = rule.PortEnd + } + _, err := region.vpcPost("/v2.0/security-group-rules", params) + return err +} + +func (region *SRegion) DeleteSecurityGroup(secGroupId string) error { + resource := "/v2.0/security-groups/" + secGroupId + _, err := region.vpcDelete(resource) + return err +} + +func (secgroup *SSecurityGroup) Delete() error { + return secgroup.region.DeleteSecurityGroup(secgroup.Id) +} + +func (region *SRegion) CreateSecurityGroup(projectId, name, description string) (*SSecurityGroup, error) { + params := map[string]map[string]interface{}{ + "security_group": { + "name": name, + "description": description, + }, + } + if len(projectId) > 0 { + params["security_group"]["project_id"] = projectId + } + resp, err := region.vpcPost("/v2.0/security-groups", params) + if err != nil { + return nil, errors.Wrap(err, "vpcPost") + } + secgroup := &SSecurityGroup{region: region} + err = resp.Unmarshal(secgroup, "security_group") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return secgroup, nil +} + +func (secgroup *SSecurityGroup) GetProjectId() string { + return secgroup.TenantId +} + +func (secgroup *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + for _, r := range append(inDels, outDels...) { + err := secgroup.region.delSecurityGroupRule(r.ExternalId) + if err != nil { + return errors.Wrapf(err, "delSecurityGroupRule(%s)", r.ExternalId) + } + } + for _, r := range append(inAdds, outAdds...) { + err := secgroup.region.addSecurityGroupRules(secgroup.Id, r) + if err != nil { + if jsonError, ok := err.(*httputils.JSONClientError); ok { + if jsonError.Class == "SecurityGroupRuleExists" { + continue + } + } + return errors.Wrapf(err, "addSecgroupRules(%s)", r.String()) + } + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/snapshot.go new file mode 100644 index 0000000000..490c9e3186 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/snapshot.go @@ -0,0 +1,216 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + SNAPSHOT_STATUS_CREATING = "creating" //The snapshot is being created. + SNAPSHOT_STATUS_AVAILABLE = "available" //The snapshot is ready to use. + SNAPSHOT_STATUS_BACKING_UP = "backing-up" //The snapshot is being backed up. + SNAPSHOT_STATUS_DELETING = "deleting" //The snapshot is being deleted. + SNAPSHOT_STATUS_ERROR = "error" //A snapshot creation error occurred. + SNAPSHOT_STATUS_DELETED = "deleted" //The snapshot has been deleted. + SNAPSHOT_STATUS_UNMANAGING = "unmanaging" //The snapshot is being unmanaged. + SNAPSHOT_STATUS_RESTORING = "restoring" //The snapshot is being restored to a volume. + SNAPSHOT_STATUS_ERROR_DELETING = "error_deleting" //A snapshot deletion error occurred. +) + +type SSnapshot struct { + multicloud.SResourceBase + OpenStackTags + region *SRegion + + Id string + VolumeId string + + Status string + + Progress string `json:"os-extended-snapshot-attributes:progress"` + Name string + UserId string + ProjectId string `json:"os-extended-snapshot-attributes:project_id"` + //CreatedAt time.Time + Size int32 + + Description string + //UpdatedAt time.Time +} + +func (region *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + resource := "/snapshots/" + snapshotId + resp, err := region.bsGet(resource) + if err != nil { + return nil, errors.Wrap(err, "bsGet") + } + snapshot := SSnapshot{region: region} + err = resp.Unmarshal(&snapshot, "snapshot") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return &snapshot, nil +} + +func (snapshot *SSnapshot) GetStatus() string { + switch snapshot.Status { + case SNAPSHOT_STATUS_CREATING: + return api.SNAPSHOT_CREATING + case SNAPSHOT_STATUS_AVAILABLE: + return api.SNAPSHOT_READY + case SNAPSHOT_STATUS_BACKING_UP: + return api.SNAPSHOT_ROLLBACKING + case SNAPSHOT_STATUS_DELETED, SNAPSHOT_STATUS_DELETING: + return api.SNAPSHOT_DELETING + default: + return api.SNAPSHOT_UNKNOWN + } +} + +func (snapshot *SSnapshot) IsEmulated() bool { + return false +} + +func (snapshot *SSnapshot) Refresh() error { + _snapshot, err := snapshot.region.GetISnapshotById(snapshot.Id) + if err != nil { + return err + } + return jsonutils.Update(snapshot, _snapshot) +} + +func (region *SRegion) GetSnapshots(diskId string) ([]SSnapshot, error) { + resource := "/snapshots/detail" + query := url.Values{} + query.Set("all_tenants", "true") + if len(diskId) > 0 { + query.Set("volume_id", diskId) + } + snapshots := []SSnapshot{} + for { + resp, err := region.bsList(resource, query) + if err != nil { + return nil, errors.Wrap(err, "bsList") + } + part := struct { + Snapshots []SSnapshot + SnapshotsLinks SNextLinks + }{} + + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + snapshots = append(snapshots, part.Snapshots...) + marker := part.SnapshotsLinks.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return snapshots, nil +} + +func (region *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := region.GetSnapshots("") + if err != nil { + return nil, err + } + isnapshots := []cloudprovider.ICloudSnapshot{} + for i := range snapshots { + snapshots[i].region = region + isnapshots = append(isnapshots, &snapshots[i]) + } + return isnapshots, nil +} + +func (snapshot *SSnapshot) GetSizeMb() int32 { + return snapshot.Size * 1024 +} + +func (snapshot *SSnapshot) GetDiskId() string { + return snapshot.VolumeId +} + +func (snapshot *SSnapshot) GetId() string { + return snapshot.Id +} + +func (snapshot *SSnapshot) GetGlobalId() string { + return snapshot.Id +} + +func (snapshot *SSnapshot) GetName() string { + if len(snapshot.Name) == 0 { + return snapshot.Id + } + return snapshot.Name +} + +func (snapshot *SSnapshot) Delete() error { + return snapshot.region.DeleteSnapshot(snapshot.Id) +} + +func (snapshot *SSnapshot) GetDiskType() string { + if len(snapshot.VolumeId) > 0 { + disk, err := snapshot.region.GetDisk(snapshot.VolumeId) + if err != nil { + log.Errorf("failed to get snapshot %s disk %s error: %v", snapshot.Name, snapshot.VolumeId, err) + return api.DISK_TYPE_DATA + } + return disk.GetDiskType() + } + return api.DISK_TYPE_DATA +} + +func (region *SRegion) DeleteSnapshot(snapshotId string) error { + resource := "/snapshots/" + snapshotId + _, err := region.bsDelete(resource) + return err +} + +func (region *SRegion) CreateSnapshot(diskId, name, desc string) (*SSnapshot, error) { + params := map[string]map[string]interface{}{ + "snapshot": { + "volume_id": diskId, + "name": name, + "description": desc, + "force": true, + }, + } + resp, err := region.bsPost("/snapshots", params) + if err != nil { + return nil, errors.Wrap(err, "bsPost") + } + snapshot := &SSnapshot{region: region} + err = resp.Unmarshal(snapshot, "snapshot") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return snapshot, nil +} + +func (self *SSnapshot) GetProjectId() string { + return self.ProjectId +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/storage.go new file mode 100644 index 0000000000..0ea20af6ad --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/storage.go @@ -0,0 +1,257 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + DEFAULT_STORAGE_TYPE = "scheduler" +) + +type SExtraSpecs struct { + VolumeBackendName string +} + +type SStorage struct { + multicloud.SStorageBase + zone *SZone + Name string + ExtraSpecs SExtraSpecs + ID string +} + +func (storage *SStorage) GetId() string { + return storage.ID +} + +func (storage *SStorage) GetName() string { + return storage.Name +} + +func (storage *SStorage) GetGlobalId() string { + return fmt.Sprintf("%s-%s", storage.zone.GetGlobalId(), storage.ID) +} + +func (storage *SStorage) IsEmulated() bool { + return false +} + +func (storage *SStorage) GetIZone() cloudprovider.ICloudZone { + return storage.zone +} + +func (storage *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := storage.zone.region.GetDisks() + if err != nil { + return nil, err + } + idisks := []cloudprovider.ICloudDisk{} + for i := 0; i < len(disks); i++ { + if disks[i].AvailabilityZone == storage.zone.ZoneName && (disks[i].VolumeType == storage.Name || strings.HasSuffix(disks[i].Host, "#"+storage.ExtraSpecs.VolumeBackendName)) { + disks[i].storage = storage + idisks = append(idisks, &disks[i]) + } + } + return idisks, nil +} + +func (storage *SStorage) GetStorageType() string { + if len(storage.ExtraSpecs.VolumeBackendName) == 0 { + return DEFAULT_STORAGE_TYPE + } + return storage.ExtraSpecs.VolumeBackendName +} + +func (storage *SStorage) GetMediumType() string { + if strings.Contains(storage.Name, "SSD") { + return api.DISK_TYPE_SSD + } + return api.DISK_TYPE_ROTATE +} + +func (storage *SStorage) GetCapacityMB() int64 { + return 0 // unlimited +} + +func (storage *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (storage *SStorage) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + return conf +} + +func (storage *SStorage) GetStatus() string { + ok, err := storage.zone.region.IsStorageAvailable(storage.GetStorageType()) + if err != nil || !ok { + return api.STORAGE_OFFLINE + } + return api.STORAGE_ONLINE +} + +func (storage *SStorage) Refresh() error { + // do nothing + return nil +} + +func (storage *SStorage) GetEnabled() bool { + return true +} + +func (storage *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return storage.zone.region.getStoragecache() +} + +func (storage *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + disk, err := storage.zone.region.CreateDisk("", storage.Name, conf.Name, conf.SizeGb, conf.Desc, conf.ProjectId) + if err != nil { + log.Errorf("createDisk fail %v", err) + return nil, err + } + disk.storage = storage + return disk, cloudprovider.WaitStatus(disk, api.DISK_READY, time.Second*5, time.Minute*5) +} + +func (storage *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + disk, err := storage.zone.region.GetDisk(idStr) + if err != nil { + return nil, err + } + if disk.AvailabilityZone != storage.zone.ZoneName { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "disk %s not in zone %s", disk.Name, storage.zone.ZoneName) + } + disk.storage = storage + return disk, nil +} + +func (storage *SStorage) GetMountPoint() string { + return "" +} + +func (storage *SStorage) IsSysDiskStore() bool { + return true +} + +func (region *SRegion) GetStorageTypes() ([]SStorage, error) { + resource := "/types" + storages := []SStorage{} + query := url.Values{} + for { + resp, err := region.bsList(resource, query) + if err != nil { + return nil, errors.Wrap(err, "bsReqest") + } + part := struct { + VolumeTypes []SStorage + VolumeTypeLinks SNextLinks + }{} + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + storages = append(storages, part.VolumeTypes...) + marker := part.VolumeTypeLinks.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return storages, nil +} + +type SCinderService struct { + ActiveBackendId string + // cinder-volume + Binary string + DisabledReason string + Frozen string + Host string + ReplicationStatus string + State string + Status string + UpdatedAt time.Time + Zone string +} + +func (region *SRegion) GetCinderServices() ([]SCinderService, error) { + resp, err := region.bsList("/os-services", nil) + if err != nil { + return nil, errors.Wrap(err, "bsList") + } + services := []SCinderService{} + err = resp.Unmarshal(&services, "services") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return services, nil +} + +func (region *SRegion) IsStorageAvailable(storageType string) (bool, error) { + if utils.IsInStringArray(storageType, []string{DEFAULT_STORAGE_TYPE, api.STORAGE_OPENSTACK_NOVA}) { + return true, nil + } + services, err := region.GetCinderServices() + if err != nil { + return false, errors.Wrap(err, "GetCinderServices") + } + for _, service := range services { + if service.Binary == "cinder-volume" && strings.Contains(service.Host, "@") { + hostInfo := strings.Split(service.Host, "@") + if hostInfo[len(hostInfo)-1] == storageType { + if service.State == "up" && service.Status == "enabled" { + return true, nil + } + } + } + } + log.Errorf("storage %s offline", storageType) + return false, nil +} + +type SCapabilities struct { +} + +type SPool struct { + Name string + Capabilities SCapabilities +} + +func (region *SRegion) GetSchedulerStatsPool() ([]SPool, error) { + resp, err := region.bsList("/scheduler-stats/get_pools", nil) + if err != nil { + return nil, errors.Wrap(err, "bsList") + } + pools := []SPool{} + err = resp.Unmarshal(&pools, "pools") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return pools, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/storagecache.go new file mode 100644 index 0000000000..a89df2e0a9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/storagecache.go @@ -0,0 +1,160 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +type SStoragecache struct { + multicloud.SResourceBase + OpenStackTags + region *SRegion +} + +func (cache *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", cache.region.client.cpcfg.Id, cache.region.GetId()) +} + +func (cache *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", cache.region.client.cpcfg.Name, cache.region.GetId()) +} + +func (cache *SStoragecache) GetStatus() string { + return "available" +} + +func (cache *SStoragecache) Refresh() error { + return nil +} + +func (cache *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", cache.region.client.cpcfg.Id, cache.region.GetGlobalId()) +} + +func (cache *SStoragecache) IsEmulated() bool { + return false +} + +func (cache *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + images, err := cache.region.GetImages("", ACTIVE, "") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudImage{} + for i := 0; i < len(images); i++ { + images[i].storageCache = cache + ret = append(ret, &images[i]) + } + return ret, nil +} + +func (cache *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (cache *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + image, err := cache.region.GetImage(extId) + if err != nil { + return nil, err + } + image.storageCache = cache + return image, nil +} + +func (cache *SStoragecache) GetPath() string { + return "" +} + +func (cache *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return cache.uploadImage(ctx, userCred, image, callback) +} + +func (cache *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + s := auth.GetAdminSession(ctx, options.Options.Region) + + meta, reader, size, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false) + if err != nil { + return "", err + } + log.Infof("meta data %s", meta) + + imageBaseName := image.ImageName + imageName := imageBaseName + nameIdx := 1 + + for { + _, err = cache.region.GetImageByName(imageName) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + break + } else { + return "", err + } + } + imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) + nameIdx++ + } + + minDiskSizeMb, _ := meta.Int("min_disk") + minRamMb, _ := meta.Int("min_ram") + osType, _ := meta.GetString("properties", "os_type") + osDist, _ := meta.GetString("properties", "os_distribution") + minDiskSizeGB := minDiskSizeMb / 1024 + if minDiskSizeMb%1024 > 0 { + minDiskSizeGB += 1 + } + + img, err := cache.region.CreateImage(imageName, osType, osDist, int(minDiskSizeGB), int(minRamMb), size, reader, callback) + if err != nil { + return "", err + } + + img.storageCache = cache + + err = cloudprovider.WaitStatus(img, api.CACHED_IMAGE_STATUS_ACTIVE, 15*time.Second, 3600*time.Second) + if err != nil { + return "", errors.Wrapf(err, "WaitStatus") + } + + if callback != nil { + callback(100) + } + + return img.Id, nil +} + +func (cache *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (cache *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/tag_base.go new file mode 100644 index 0000000000..7b0450fa7a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/tag_base.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type OpenStackTags struct { + Metadata map[string]string +} + +func (self *OpenStackTags) GetTags() (map[string]string, error) { + return self.Metadata, nil +} + +func (self *OpenStackTags) GetSysTags() map[string]string { + return nil +} + +func (self *OpenStackTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/vpc.go new file mode 100644 index 0000000000..6ad9be2778 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/vpc.go @@ -0,0 +1,268 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + "net/url" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + VPC_STATUS_ACTIVE = "ACTIVE" + VPC_STATUS_DOWN = "DOWN" + VPC_STATUS_BUILD = "BUILD" + VPC_STATUS_ERROR = "ERROR" +) + +type SVpc struct { + multicloud.SVpc + OpenStackTags + region *SRegion + + AdminStateUp bool + AvailabilityZoneHints []string + AvailabilityZones []string + CreatedAt time.Time + DnsDomain string + Id string + Ipv4AddressScope string + Ipv6AddressScope string + L2Adjacency bool + Mtu int + Name string + PortSecurityEnabled bool + ProjectID string + QosPolicyID string + RevisionNumber int + External bool `json:"router:external"` + Shared bool + Status string + Subnets []string + TenantID string + UpdatedAt time.Time + VlanTransparent bool + Fescription string + IsDefault bool + NetworkType string `json:"provider:network_type"` // flat, vlan, vxlan, or gre ... + PhysicalNetwork string `json:"provider:physical_network"` + SegmentationId string `json:"provider:segmentation_id"` +} + +func (vpc *SVpc) GetId() string { + return vpc.Id +} + +func (vpc *SVpc) GetName() string { + if len(vpc.Name) > 0 { + return vpc.Name + } + return vpc.Id +} + +func (vpc *SVpc) GetGlobalId() string { + return vpc.Id +} + +func (vpc *SVpc) IsEmulated() bool { + return false +} + +func (vpc *SVpc) GetIsDefault() bool { + return vpc.IsDefault +} + +func (vpc *SVpc) GetCidrBlock() string { + return "" +} + +func (vpc *SVpc) GetStatus() string { + switch vpc.Status { + case VPC_STATUS_ACTIVE: + return api.VPC_STATUS_AVAILABLE + case VPC_STATUS_BUILD, VPC_STATUS_DOWN: + return api.VPC_STATUS_PENDING + case VPC_STATUS_ERROR: + return api.VPC_STATUS_FAILED + default: + return api.VPC_STATUS_UNKNOWN + } +} + +func (vpc *SVpc) Delete() error { + return vpc.region.DeleteVpc(vpc.Id) +} + +func (region *SRegion) DeleteVpc(vpcId string) error { + resource := fmt.Sprintf("/v2.0/networks/%s", vpcId) + _, err := region.vpcDelete(resource) + return err +} + +func (vpc *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + err := vpc.region.client.fetchProjects() + if err != nil { + return nil, errors.Wrap(err, "fetchProjects") + } + iSecgroups := []cloudprovider.ICloudSecurityGroup{} + for _, project := range vpc.region.client.projects { + secgroups, err := vpc.region.GetSecurityGroups(project.Id, "") + if err != nil { + return nil, errors.Wrapf(err, "GetSecurityGroups(%s)", project.Id) + } + for i := 0; i < len(secgroups); i++ { + secgroups[i].region = vpc.region + iSecgroups = append(iSecgroups, &secgroups[i]) + } + } + return iSecgroups, nil +} + +func (vpc *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + if vpc.PhysicalNetwork == "public" { + return []cloudprovider.ICloudRouteTable{}, nil + } + err := vpc.region.fetchrouters() + if err != nil { + return nil, errors.Wrap(err, "vpc.region.fetchrouters()") + } + routeTables := []SRouteTable{} + for index, router := range vpc.region.routers { + if len(router.Routes) < 1 { + continue + } + for _, port := range router.ports { + if port.NetworkID == vpc.GetId() { + routeTable := SRouteTable{} + routeTable.entries = router.Routes + routeTable.router = &vpc.region.routers[index] + routeTable.vpc = vpc + routeTables = append(routeTables, routeTable) + break + } + } + } + ret := []cloudprovider.ICloudRouteTable{} + for i := range routeTables { + ret = append(ret, &routeTables[i]) + } + return ret, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (vpc *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { + iwires, err := vpc.GetIWires() + if err != nil { + return nil, errors.Wrap(err, "GetIWires") + } + for i := range iwires { + if iwires[i].GetGlobalId() == wireId { + return iwires[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (vpc *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + return []cloudprovider.ICloudWire{&SWire{vpc: vpc}}, nil +} + +func (vpc *SVpc) GetRegion() cloudprovider.ICloudRegion { + return vpc.region +} + +func (region *SRegion) GetVpc(vpcId string) (*SVpc, error) { + vpc := &SVpc{region: region} + resource := fmt.Sprintf("/v2.0/networks/%s", vpcId) + resp, err := region.vpcGet(resource) + if err != nil { + return nil, errors.Wrapf(err, "vpcGet(%s)", resource) + } + err = resp.Unmarshal(vpc, "network") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return vpc, nil +} + +func (region *SRegion) GetVpcs(projectId string) ([]SVpc, error) { + vpcs := []SVpc{} + resource := "/v2.0/networks" + query := url.Values{} + if len(projectId) > 0 { + query.Set("tenant_id", projectId) + } + for { + resp, err := region.vpcList(resource, query) + if err != nil { + return nil, errors.Wrapf(err, "vpcList.%s", resource) + } + + part := struct { + Networks []SVpc + NetworksLinks SNextLinks + }{} + + err = resp.Unmarshal(&part) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + vpcs = append(vpcs, part.Networks...) + marker := part.NetworksLinks.GetNextMark() + if len(marker) == 0 { + break + } + query.Set("marker", marker) + } + return vpcs, nil +} + +func (vpc *SVpc) Refresh() error { + _vpc, err := vpc.region.GetVpc(vpc.Id) + if err != nil { + return errors.Wrapf(err, "GetVpc(%s)", vpc.Id) + } + return jsonutils.Update(vpc, _vpc) +} + +func (region *SRegion) CreateVpc(name, desc string) (*SVpc, error) { + params := map[string]map[string]string{ + "network": { + "name": name, + "description": desc, + }, + } + resource := "/v2.0/networks" + resp, err := region.vpcPost(resource, params) + if err != nil { + return nil, errors.Wrap(err, "vpcPost") + } + vpc := &SVpc{region: region} + err = resp.Unmarshal(vpc, "network") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return vpc, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/wire.go new file mode 100644 index 0000000000..f8de67b61f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/wire.go @@ -0,0 +1,112 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + OpenStackTags + + vpc *SVpc +} + +func (wire *SWire) GetId() string { + return wire.vpc.GetId() +} + +func (wire *SWire) GetName() string { + return wire.GetId() +} + +func (wire *SWire) IsEmulated() bool { + return true +} + +func (wire *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (wire *SWire) Refresh() error { + return nil +} + +func (wire *SWire) GetGlobalId() string { + return wire.vpc.GetGlobalId() +} + +func (wire *SWire) GetIVpc() cloudprovider.ICloudVpc { + return wire.vpc +} + +func (wire *SWire) GetIZone() cloudprovider.ICloudZone { + return nil +} + +func (wire *SWire) GetBandwidth() int { + return 10000 +} + +func (wire *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + network, err := wire.vpc.region.CreateNetwork(wire.vpc.Id, opts.ProjectId, opts.Name, opts.Cidr, opts.Desc) + if err != nil { + return nil, errors.Wrap(err, "CreateNetwork") + } + network.wire = wire + return network, nil +} + +func (wire *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { + networks, err := wire.GetINetworks() + if err != nil { + return nil, err + } + for i := 0; i < len(networks); i++ { + if networks[i].GetGlobalId() == netid { + return networks[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, netid) +} + +func (wire *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + _networks, err := wire.vpc.region.GetNetworks(wire.vpc.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetNetworks(%s)", wire.vpc.Id) + } + networks := []SNetwork{} + for i := range _networks { + pools := _networks[i].AllocationPools + for j := range pools { + if !pools[j].IsValid() { + continue + } + _networks[i].AllocationPools = []AllocationPool{pools[j]} + networks = append(networks, _networks[i]) + } + } + inetworks := []cloudprovider.ICloudNetwork{} + for i := range networks { + networks[i].wire = wire + inetworks = append(inetworks, &networks[i]) + } + return inetworks, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/zone.go new file mode 100644 index 0000000000..8005dc04a3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/openstack/zone.go @@ -0,0 +1,210 @@ +// Copyright 2019 Yunion +// +// 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 openstack + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type ZoneState struct { + Available bool +} + +type HostState struct { + Available bool + Active bool + UpdatedAt time.Time +} + +type SZone struct { + multicloud.SResourceBase + OpenStackTags + region *SRegion + + ZoneName string + ZoneState ZoneState + + Hosts map[string]jsonutils.JSONObject + + hosts []SHypervisor +} + +func (zone *SZone) GetId() string { + return zone.ZoneName +} + +func (zone *SZone) GetName() string { + return zone.ZoneName +} + +func (zone *SZone) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(zone.GetName()).CN(zone.GetName()) + return table +} + +func (zone *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s/%s", CLOUD_PROVIDER_OPENSTACK, zone.region.Name, zone.ZoneName) +} + +func (zone *SZone) IsEmulated() bool { + return false +} + +func (zone *SZone) GetStatus() string { + if zone.ZoneState.Available { + return api.ZONE_ENABLE + } + return api.ZONE_DISABLE +} + +func (zone *SZone) Refresh() error { + // do nothing + return nil +} + +func (zone *SZone) GetIRegion() cloudprovider.ICloudRegion { + return zone.region +} + +func (zone *SZone) getStorageByCategory(category, host string) (*SStorage, error) { + storages, err := zone.region.GetStorageTypes() + if err != nil { + return nil, errors.Wrap(err, "GetStorageTypes") + } + for i := range storages { + if storages[i].Name == category || storages[i].ExtraSpecs.VolumeBackendName == category { + storages[i].zone = zone + return &storages[i], nil + } + } + for i := range storages { + if strings.HasSuffix(host, "#"+storages[i].Name) || strings.HasSuffix(host, "#"+storages[i].ExtraSpecs.VolumeBackendName) { + storages[i].zone = zone + return &storages[i], nil + } + } + return nil, fmt.Errorf("No such storage [%s]", category) +} + +func (zone *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := zone.region.GetStorageTypes() + if err != nil && errors.Cause(err) != ErrNoEndpoint { + return nil, errors.Wrap(err, "GetStorageTypes") + } + istorages := []cloudprovider.ICloudStorage{} + for i := range storages { + storages[i].zone = zone + istorages = append(istorages, &storages[i]) + } + err = zone.fetchHosts() + if err != nil { + return nil, errors.Wrap(err, "fetchHosts") + } + for i := range zone.hosts { + nova := &SNovaStorage{host: &zone.hosts[i], zone: zone} + istorages = append(istorages, nova) + } + return istorages, nil +} + +func (zone *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + istorages, err := zone.GetIStorages() + if err != nil { + return nil, errors.Wrap(err, "GetIStorages") + } + for i := 0; i < len(istorages); i++ { + if istorages[i].GetGlobalId() == id { + return istorages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (zone *SZone) fetchHosts() error { + if len(zone.hosts) > 0 { + return nil + } + + zone.hosts = []SHypervisor{} + hypervisors, err := zone.region.GetHypervisors() + if err != nil { + return errors.Wrap(err, "GetHypervisors") + } + for i := range hypervisors { + hypervisor := strings.ToLower(hypervisors[i].HypervisorType) + // 过滤vmware的机器 + if strings.Index(hypervisor, "vmware") != -1 { + continue + } + + _, ok1 := zone.Hosts[hypervisors[i].HypervisorHostname] + _, ok2 := zone.Hosts[hypervisors[i].Service.Host] + if !ok1 && !ok2 { + continue + } + zone.hosts = append(zone.hosts, hypervisors[i]) + } + return nil + +} + +func (zone *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + err := zone.fetchHosts() + if err != nil { + return nil, errors.Wrap(err, "fetchHosts") + } + ihosts := []cloudprovider.ICloudHost{} + for i := range zone.hosts { + zone.hosts[i].zone = zone + ihosts = append(ihosts, &zone.hosts[i]) + } + return ihosts, nil +} + +func (zone *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + ihosts, err := zone.GetIHosts() + if err != nil { + return nil, errors.Wrap(err, "GetIHosts") + } + for i := range ihosts { + if ihosts[i].GetGlobalId() == id { + return ihosts[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) getZones() ([]SZone, error) { + zones := []SZone{} + resp, err := region.ecsList("os-availability-zone/detail", nil) + if err != nil { + return nil, errors.Wrap(err, "ecsList.os-availability-zone") + } + err = resp.Unmarshal(&zones, "availabilityZoneInfo") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return zones, nil +} diff --git a/pkg/multicloud/progress.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/progress.go similarity index 100% rename from pkg/multicloud/progress.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/progress.go diff --git a/pkg/multicloud/project_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/project_base.go similarity index 100% rename from pkg/multicloud/project_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/project_base.go diff --git a/pkg/multicloud/proxmox/cluster.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/cluster.go similarity index 100% rename from pkg/multicloud/proxmox/cluster.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/cluster.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/disk.go new file mode 100644 index 0000000000..28209e1936 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/disk.go @@ -0,0 +1,236 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "context" + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDisk struct { + multicloud.SDisk + ProxmoxTags + + region *SRegion + + Storage string + Node string + DiskDriver string + DriverIdx int + VmId int + CacheMode string + + Format string `json:"format"` + Size int64 `json:"size"` + VolId string `json:"volid"` + Name string `json:"name"` + Parent string `json:"parent"` + Content string `json:"content"` +} + +func (self *SDisk) GetName() string { + return self.Name +} + +func (self *SDisk) GetId() string { + return self.VolId +} + +func (self *SDisk) GetGlobalId() string { + return self.GetId() +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SDisk) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SDisk) GetCacheMode() string { + return self.CacheMode +} + +func (self *SDisk) GetFsFormat() string { + return "" +} + +func (self *SDisk) GetIsNonPersistent() bool { + return false +} + +func (self *SDisk) GetDriver() string { + return self.DiskDriver +} + +func (self *SDisk) GetDiskType() string { + return api.DISK_TYPE_DATA +} + +func (self *SDisk) GetDiskFormat() string { + return strings.ToLower(self.Format) +} + +func (self *SDisk) GetDiskSizeMB() int { + return int(self.Size / 1024 / 1024) +} + +func (self *SDisk) GetIsAutoDelete() bool { + return true +} + +func (self *SDisk) GetMountpoint() string { + return "" +} + +func (self *SDisk) GetStatus() string { + return api.DISK_READY +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { + return self.region.ResizeDisk(self.VolId, int(sizeMb/1024)) +} + +func (self *SDisk) GetTemplateId() string { + return "" +} + +func (self *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + DataStoreId := fmt.Sprintf("storage/%s/%s", self.Node, self.Storage) + return self.region.GetStorage(DataStoreId) +} + +func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + return []cloudprovider.ICloudSnapshot{}, nil +} + +func (self *SRegion) GetDisks(storageId string) ([]SDisk, error) { + vols := []SDisk{} + disks := []SDisk{} + + splited := strings.Split(storageId, "/") + nodeName := "" + storageName := "" + + if len(splited) == 3 { + nodeName, storageName = splited[1], splited[2] + } + + res := fmt.Sprintf("/nodes/%s/storage/%s/content", nodeName, storageName) + err := self.get(res, url.Values{}, &vols) + if err != nil { + return nil, err + } + for i := range vols { + _, diskName := ParseSubConf(vols[i].VolId, ":") + if err != nil { + continue + } + vols[i].Storage = storageName + vols[i].Node = nodeName + vols[i].Name = diskName.(string) + + disks = append(disks, vols[i]) + } + + return disks, nil +} + +func (self *SRegion) GetDisk(Id string) (*SDisk, error) { + + vols := []SDisk{} + nodeName := "" + storageName, diskName := ParseSubConf(Id, ":") + resources, err := self.GetClusterStoragesResources() + if err != nil { + return nil, err + } + + if res, ok := resources[storageName]; !ok { + return nil, errors.Errorf("self.GetDisk") + } else { + nodeName = res.Node + } + + res := fmt.Sprintf("/nodes/%s/storage/%s/content", nodeName, storageName) + err = self.get(res, url.Values{}, &vols) + if err != nil { + return nil, errors.Wrapf(err, "self.GetDisk") + } + + for _, vol := range vols { + if vol.VolId == Id { + ret := &SDisk{ + region: self, + Storage: storageName, + Node: nodeName, + Format: vol.Format, + Size: vol.Size, + VolId: vol.VolId, + Name: diskName.(string), + Parent: vol.Parent, + VmId: vol.VmId, + Content: vol.Content, + } + return ret, nil + } + } + + return nil, errors.Errorf("self.GetDisk failed to get disk by %s", Id) +} + +func (self *SRegion) ResizeDisk(id string, sizeGb int) error { + disk, err := self.GetDisk(id) + if err != nil { + return errors.Wrapf(err, "GetDisk(%s)", id) + } + // not support unmount disk + if disk.VmId < 1 { + return nil + } + body := map[string]interface{}{ + "disk": fmt.Sprintf("%s%d", disk.DiskDriver, disk.DriverIdx), + "size": sizeGb, + } + + res := fmt.Sprintf("/nodes/%s/qemu/%d/resize", disk.Node, disk.VmId) + return self.put(res, nil, jsonutils.Marshal(body), nil) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/doc.go new file mode 100644 index 0000000000..aaa086e75a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 proxmox // import "yunion.io/x/cloudmux/pkg/multicloud/proxmox" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/host.go new file mode 100644 index 0000000000..82150f648b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/host.go @@ -0,0 +1,335 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "fmt" + "net/url" + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SHost struct { + multicloud.SHostBase + ProxmoxTags + zone *SZone + + Id string + Node string + + Uptime int `json:"uptime"` + Wait int `json:"wait"` + Idle int `json:"idle"` + Kversion string `json:"kversion"` + Pveversion string `json:"pveversion"` + CPU int `json:"cpu"` + Loadavg []string `json:"loadavg"` + Rootfs Rootfs `json:"rootfs"` + Swap Swap `json:"swap"` + Memory Memory `json:"memory"` + Cpuinfo Cpuinfo `json:"cpuinfo"` + Ksm Ksm `json:"ksm"` +} + +type Rootfs struct { + Used int64 `json:"used"` + Total int64 `json:"total"` + Avail int64 `json:"avail"` + Free int64 `json:"free"` +} + +type Swap struct { + Free int64 `json:"free"` + Used int64 `json:"used"` + Total int64 `json:"total"` +} + +type Memory struct { + Free int64 `json:"free"` + Used int64 `json:"used"` + Total int64 `json:"total"` +} + +type Cpuinfo struct { + Flags string `json:"flags"` + Hvm string `json:"hvm"` + Cores int `json:"cores"` + Model string `json:"model"` + Mhz float64 `json:"mhz"` + Cpus int `json:"cpus"` + UserHz int `json:"user_hz"` + Sockets int `json:"sockets"` +} + +type Ksm struct { + Shared int `json:"shared"` +} + +func (self *SHost) GetId() string { + return self.Id +} + +func (self *SHost) GetGlobalId() string { + return self.Id +} + +func (self *SHost) GetName() string { + return self.Node +} + +func (self *SHost) GetEnabled() bool { + return true +} + +func (self *SHost) GetHostStatus() string { + return api.HOST_ONLINE +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) GetAccessIp() string { + return "" +} + +func (self *SHost) GetAccessMac() string { + return "" +} + +func (self *SHost) GetSysInfo() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetCpuCount() int { + return int(self.Cpuinfo.Cores) +} + +func (self *SHost) GetNodeCount() int8 { + return int8(self.Cpuinfo.Sockets) +} + +func (self *SHost) GetCpuDesc() string { + return self.Cpuinfo.Model +} + +func (self *SHost) GetCpuMhz() int { + return int(self.Cpuinfo.Mhz) +} + +func (self *SHost) GetCpuCmtbound() float32 { + return 1 +} + +func (self *SHost) GetMemSizeMB() int { + return int(self.Memory.Total / 1024 / 1024) +} + +func (self *SHost) GetMemCmtbound() float32 { + return 1 +} + +func (self *SHost) GetReservedMemoryMb() int { + return 0 +} + +func (self *SHost) GetStorageSizeMB() int { + return int(self.Rootfs.Total / 1024 / 1024) +} + +func (self *SHost) GetStorageType() string { + return api.STORAGE_LOCAL +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_PROXMOX +} + +func (self *SHost) GetIsMaintenance() bool { + return false +} + +func (self *SHost) GetVersion() string { + return self.Pveversion +} + +func (self *SHost) CreateVM(opts *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + + vmId := self.zone.region.GetClusterVmMaxId() + if vmId == -1 { + return nil, errors.Errorf("failed to get vm number by %d", vmId) + } else { + vmId++ + } + + splited := strings.Split(opts.SysDisk.StorageExternalId, "/") + storage := splited[2] + + body := map[string]interface{}{ + "vmid": vmId, + "name": opts.Name, + "ostype": "other", + "sockets": 1, + "cores": opts.Cpu, + "cpu": "host", + "kvm": 1, + "hotplug": "network,disk,usb", + "memory": opts.MemoryMB, + "description": opts.OsDistribution, + "scsihw": "virtio-scsi-pci", + "scsi0": fmt.Sprintf("%s:%d", storage, opts.SysDisk.SizeGB), + } + + res := fmt.Sprintf("/nodes/%s/qemu", self.Node) + _, err := self.zone.region.post(res, jsonutils.Marshal(body)) + if err != nil { + return nil, err + } + + vmIdRet := strconv.Itoa(vmId) + vm, err := self.zone.region.GetInstance(vmIdRet) + if err != nil { + return nil, err + } + + for k, _ := range vm.QemuDisks { + _, diskName := ParseSubConf(k, ":") + opts.SysDisk.Name = diskName.(string) + break + } + + vm.host = self + return vm, nil +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms, err := self.zone.region.GetInstances(self.Id) + if err != nil { + return nil, errors.Wrapf(err, "GetInstances") + } + ret := []cloudprovider.ICloudVM{} + for i := range vms { + vms[i].host = self + ret = append(ret, &vms[i]) + } + return ret, nil +} + +func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := self.zone.region.GetInstance(id) + if err != nil { + return nil, err + } + hostId := fmt.Sprintf("node/%s", vm.Node) + if hostId != self.Id { + return nil, cloudprovider.ErrNotFound + } + vm.host = self + return vm, nil +} + +func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + wires, err := self.zone.region.GetWires() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudWire{} + for i := range wires { + wires[i].region = self.zone.region + ret = append(ret, &wires[i]) + } + return ret, nil +} + +func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.zone.region.GetStoragesByHost(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + storages[i].zone = self.zone + ret = append(ret, &storages[i]) + } + return ret, nil +} + +func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storage, err := self.zone.region.GetStorage(id) + if err != nil { + return nil, err + } + storage.zone = self.zone + + return storage, nil +} + +func (self *SRegion) GetHosts() ([]SHost, error) { + hosts := []SHost{} + resources, err := self.GetClusterNodeResources() + if err != nil { + return nil, err + } + + for _, res := range resources { + host := &SHost{} + status := fmt.Sprintf("nodes/%s/status", res.Node) + err := self.get(status, url.Values{}, host) + if err != nil { + return nil, err + } + host.Id = res.Id + host.Node = res.Node + hosts = append(hosts, *host) + } + + return hosts, nil +} + +func (self *SRegion) GetHost(id string) (*SHost, error) { + ret := &SHost{} + nodeName := "" + + //"id": "node/nodeNAME", + splited := strings.Split(id, "/") + if len(splited) == 2 { + nodeName = splited[1] + } + + res := fmt.Sprintf("nodes/%s/status", nodeName) + err := self.get(res, url.Values{}, ret) + if err != nil { + return nil, err + } + ret.Id = id + ret.Node = nodeName + + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/image.go new file mode 100644 index 0000000000..74cd68c40b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/image.go @@ -0,0 +1,249 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "context" + "fmt" + "net/url" + "regexp" + "strconv" + "strings" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type SImage struct { + multicloud.SImageBase + ProxmoxTags + cache *SStoragecache + + imageInfo *imagetools.ImageInfo + + VmId int + Node string + Name string + Format string + SizeGB float64 +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SImage) GetId() string { + return fmt.Sprintf("%d", self.VmId) +} + +func (self *SImage) GetName() string { + return self.Name +} + +func (self *SImage) Delete(ctx context.Context) error { + return cloudprovider.ErrNotImplemented +} + +func (self *SImage) GetGlobalId() string { + return self.GetId() +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.cache +} + +func (self *SImage) GetStatus() string { + return api.CACHED_IMAGE_STATUS_ACTIVE +} + +func (self *SImage) GetImageStatus() string { + return cloudprovider.IMAGE_STATUS_ACTIVE +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + return cloudprovider.ImageTypeSystem +} + +func (self *SImage) GetSizeByte() int64 { + return int64(self.SizeGB * 1024 * 1024) +} + +func (img *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if img.imageInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(img.Name, "", "", "", "") + img.imageInfo = &imgInfo + } + return img.imageInfo +} + +func (img *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(img.getNormalizedImageInfo().OsType) +} + +func (img *SImage) GetOsDist() string { + return img.getNormalizedImageInfo().OsDistro +} + +func (img *SImage) GetOsVersion() string { + return img.getNormalizedImageInfo().OsVersion +} + +func (img *SImage) GetOsArch() string { + return img.getNormalizedImageInfo().OsArch +} + +func (img *SImage) GetOsLang() string { + return img.getNormalizedImageInfo().OsLang +} + +func (img *SImage) GetFullOsName() string { + return img.Name +} + +func (img *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.BIOS +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + if self.GetOsType() == "windows" { + return 40 + } + return 30 +} + +func (self *SImage) GetImageFormat() string { + return "raw" +} + +func (self *SRegion) GetImageList() ([]SImage, error) { + ret := []SImage{} + resources, err := self.GetClusterVmResources() + if err != nil { + return nil, err + } + for _, vm := range resources { + if vm.Template == true { + image := SImage{ + VmId: vm.VmId, + Name: vm.Name, + Node: vm.Node, + } + + res := fmt.Sprintf("/nodes/%s/qemu/%d/config", image.Node, image.VmId) + vmConfig := map[string]interface{}{} + err := self.get(res, url.Values{}, &vmConfig) + if err != nil { + return nil, err + } + + diskNames := []string{} + for k := range vmConfig { + if diskName := regexp.MustCompile(`(virtio|scsi|sata)\d+`).FindStringSubmatch(k); len(diskName) > 0 { + diskNames = append(diskNames, diskName[0]) + } + } + + for _, diskName := range diskNames { + diskConfStr := vmConfig[diskName].(string) + diskConfMap := ParsePMConf(diskConfStr, "volume") + + if diskConfMap["volume"].(string) == "none" { + continue + } + if diskConfMap["media"] != nil { + continue + } + + storageName, fileName := ParseSubConf(diskConfMap["volume"].(string), ":") + diskConfMap["storage"] = storageName + diskConfMap["file"] = fileName + + // cloud-init disks not always have the size sent by the API, which results in a crash + if diskConfMap["size"] == nil && strings.Contains(fileName.(string), "cloudinit") { + diskConfMap["size"] = "4M" // default cloud-init disk size + } + + image.SizeGB += DiskSizeGB(diskConfMap["size"]) + + } + ret = append(ret, image) + } + } + + return ret, nil +} + +func (self *SRegion) GetImage(id string) (*SImage, error) { + image := &SImage{} + vmId, err := strconv.Atoi(id) + if err != nil { + return nil, err + } + resources, err := self.GetClusterVmResources() + if err != nil { + return nil, err + } + if resources[vmId].Template == false { + return nil, errors.Errorf("self.GetDisk") + } + image.VmId = resources[vmId].VmId + image.Name = resources[vmId].Name + image.Node = resources[vmId].Node + res := fmt.Sprintf("/nodes/%s/qemu/%d/config", image.Node, image.VmId) + vmConfig := map[string]interface{}{} + err = self.get(res, url.Values{}, &vmConfig) + if err != nil { + return nil, err + } + + diskNames := []string{} + for k := range vmConfig { + if diskName := regexp.MustCompile(`(virtio|scsi|sata)\d+`).FindStringSubmatch(k); len(diskName) > 0 { + diskNames = append(diskNames, diskName[0]) + } + } + + for _, diskName := range diskNames { + diskConfStr := vmConfig[diskName].(string) + diskConfMap := ParsePMConf(diskConfStr, "volume") + + if diskConfMap["volume"].(string) == "none" || diskConfMap["media"].(string) == "cdrom" { + continue + } + + storageName, fileName := ParseSubConf(diskConfMap["volume"].(string), ":") + diskConfMap["storage"] = storageName + diskConfMap["file"] = fileName + + // cloud-init disks not always have the size sent by the API, which results in a crash + if diskConfMap["size"] == nil && strings.Contains(fileName.(string), "cloudinit") { + diskConfMap["size"] = "4M" // default cloud-init disk size + } + + var sizeInTerabytes = regexp.MustCompile(`[0-9]+T`) + // Convert to gigabytes if disk size was received in terabytes + matched := sizeInTerabytes.MatchString(diskConfMap["size"].(string)) + if matched { + image.SizeGB += DiskSizeGB(diskConfMap["size"]) + } + + } + + return image, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/instance.go new file mode 100644 index 0000000000..05fdc28418 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/instance.go @@ -0,0 +1,1019 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "regexp" + "sort" + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/osprofile" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var ( + rxIso = regexp.MustCompile(`(.*?),media`) + rxDeviceID = regexp.MustCompile(`\d+`) + rxDiskName = regexp.MustCompile(`(virtio|scsi|sata|ide)\d+`) + rxDiskType = regexp.MustCompile(`\D+`) + rxUnusedDiskName = regexp.MustCompile(`^(unused)\d+`) + rxNicName = regexp.MustCompile(`net\d+`) + rxSerialName = regexp.MustCompile(`serial\d+`) + rxUsbName = regexp.MustCompile(`usb\d+`) +) + +type ( + QemuDevices map[string]map[string]interface{} + QemuDevice map[string]interface{} + QemuDeviceParam []string +) + +type Intermediate struct { + HardwareAddress string `json:"hardware-address"` + IPAddresses []struct { + IPAddress string `json:"ip-address"` + IPAddressType string `json:"ip-address-type"` + Prefix int `json:"prefix"` + } `json:"ip-addresses"` + Name string `json:"name"` + Statistics map[string]int64 `json:"statistics"` +} + +type VmBase struct { + Name string `json:"name"` + Description string `json:"Description"` + Tags string `json:"tags"` + Args string `json:"args"` + Bios string `json:"bios"` + OnBoot int `json:"onboot"` + Startup string `json:"startup"` + Tablet int `json:"tablet"` + Ostype string `json:"ostype"` + Memory int64 `json:"memory"` + Balloon int64 `json:"balloon"` + Cores int64 `json:"cores"` + Vcpus int64 `json:"vcpus"` + Sockets int64 `json:"sockets"` + Cpu string `json:"cpu"` + Numa int `json:"numa"` + Hotplug string `json:"hotplug"` + Boot string `json:"boot"` + Bootdisk string `json:"bootdisk"` + Kvm int `json:"kvm"` + Scsihw string `json:"scsihw"` + Hookscript string `json:"hookscript"` + Machine string `json:"machine"` + Ide2 string `json:"ide2,omitempty"` + Ciuser string `json:"ciuser"` + Cipassword string `json:"cipassword"` + Cicustom string `json:"cicustom"` + Searchdomain string `json:"searchdomain"` + Nameserver string `json:"nameserver"` + Sshkeys string `json:"sshkeys"` +} + +type SInstance struct { + multicloud.SInstanceBase + ProxmoxTags + + host *SHost + + QemuNetworks []SInstanceNic + PowerState string + Node string + + VmID int `json:"vmid"` + Name string `json:"name"` + Description string `json:"desc"` + Pool string `json:"pool,omitempty"` + Bios string `json:"bios"` + EFIDisk QemuDevice `json:"efidisk,omitempty"` + Machine string `json:"machine,omitempty"` + Onboot bool `json:"onboot"` + Startup string `json:"startup,omitempty"` + Tablet bool `json:"tablet"` + Agent int `json:"agent"` + Memory int `json:"memory"` + Balloon int `json:"balloon"` + QemuOs string `json:"ostype"` + QemuCores int `json:"cores"` + QemuSockets int `json:"sockets"` + QemuVcpus int `json:"vcpus"` + QemuCpu string `json:"cpu"` + QemuNuma bool `json:"numa"` + QemuKVM bool `json:"kvm"` + Hotplug string `json:"hotplug"` + QemuIso string `json:"iso"` + QemuPxe bool `json:"pxe"` + FullClone *int `json:"fullclone"` + Boot string `json:"boot"` + BootDisk string `json:"bootdisk,omitempty"` + Scsihw string `json:"scsihw,omitempty"` + QemuDisks QemuDevices `json:"disk"` + QemuUnusedDisks QemuDevices `json:"unused_disk"` + QemuVga QemuDevice `json:"vga,omitempty"` + QemuSerials QemuDevices `json:"serial,omitempty"` + QemuUsbs QemuDevices `json:"usb,omitempty"` + Hookscript string `json:"hookscript,omitempty"` + Tags string `json:"tags"` + Args string `json:"args"` + + // Deprecated single disk. + DiskSize float64 `json:"diskGB"` + Storage string `json:"storage"` + StorageType string `json:"storageType"` // virtio|scsi (cloud-init defaults to scsi) + + // Deprecated single nic. + QemuNicModel string `json:"nic"` + QemuBridge string `json:"bridge"` + QemuVlanTag int `json:"vlan"` + QemuMacAddr string `json:"mac"` + + // cloud-init options + CIuser string `json:"ciuser"` + CIpassword string `json:"cipassword"` + CIcustom string `json:"cicustom"` + + Searchdomain string `json:"searchdomain"` + Nameserver string `json:"nameserver"` + Sshkeys string `json:"sshkeys"` +} + +func (self *SInstance) GetName() string { + return self.Name +} + +func (self *SInstance) GetId() string { + return strconv.Itoa(self.VmID) +} + +func (self *SInstance) GetGlobalId() string { + return self.GetId() +} + +func (self *SInstance) Refresh() error { + id := strconv.Itoa(int(self.VmID)) + ins, err := self.host.zone.region.GetInstance(id) + if err != nil { + return err + } + return jsonutils.Update(self, ins) +} + +func (self *SInstance) AssignSecurityGroup(id string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return self.host.zone.region.AttachDisk(self.VmID, diskId) +} + +func (self *SInstance) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedVMChangeConfig) error { + return self.host.zone.region.ChangeConfig(self.VmID, opts.Cpu, opts.MemoryMB) +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + return self.host.zone.region.DeleteVM(self.VmID) +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return self.host.zone.region.ResetVmPassword(self.VmID, username, password) +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return self.host.zone.region.DetachDisk(self.VmID, diskId) +} + +func (self *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(self.Bios) +} + +func (self *SInstance) GetBootOrder() string { + return strings.ToLower(self.Boot) +} + +func (self *SInstance) GetError() error { + return nil +} + +func (self *SInstance) GetHostname() string { + return self.GetName() +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_PROXMOX +} + +func (self *SInstance) VMIdExists(vmId int) (bool, error) { + resources, err := self.host.zone.region.GetClusterVmResources() + if err != nil { + return false, err + } + + _, res := resources[vmId] + return res, nil +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + ret := []cloudprovider.ICloudDisk{} + id := self.VmID + + exist, err := self.VMIdExists(self.VmID) + if err != nil { + return nil, err + } + + if exist == false { + return nil, nil + } + + for k, v := range self.QemuDisks { + disk, err := self.host.zone.region.GetDisk(k) + if err != nil { + continue + } + disk.VmId = id + disk.DiskDriver = v["type"].(string) + disk.DriverIdx = v["slot"].(int) + if cache, ok := v["cache"].(string); ok { + disk.CacheMode = cache + } + ret = append(ret, disk) + } + + // for k, v := range self.QemuUnusedDisks { + // disk, err := self.host.zone.region.GetDisk(k) + // if err != nil { + // continue + // } + // disk.VmId = self.VmID + // disk.DriverIdx = v["slot"].(int) + // ret = append(ret, disk) + // } + + return ret, nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + ret := []cloudprovider.ICloudNic{} + for i := range self.QemuNetworks { + self.QemuNetworks[i].ins = self + ret = append(ret, &self.QemuNetworks[i]) + } + return ret, nil +} + +func (self *SInstance) GetInstanceType() string { + return fmt.Sprintf("ecs.g1.c%dm%d", self.GetVcpuCount(), self.GetVmemSizeMB()/1024) +} + +func (self *SInstance) GetMachine() string { + return self.Machine +} + +func (self *SInstance) GetStatus() string { + switch strings.ToLower(self.PowerState) { + case "running": + return api.VM_RUNNING + case "stopped": + return api.VM_READY + case "paused": + return api.VM_SUSPEND + } + return api.VM_UNKNOWN +} + +func (self *SInstance) GetFullOsName() string { + return "" +} + +func (self *SInstance) GetOsType() cloudprovider.TOsType { + isWin, _ := regexp.MatchString("(wxp|w2k|w2k3|w2k8|wvista|win7|win8|win10|win11)", self.QemuOs) + if isWin == true { + return cloudprovider.TOsType(osprofile.OS_TYPE_WINDOWS) + } else { + return cloudprovider.TOsType(osprofile.OS_TYPE_LINUX) + } +} + +func (ins *SInstance) GetOsArch() string { + return "x86_64" +} + +func (ins *SInstance) GetOsDist() string { + return "" +} + +func (ins *SInstance) GetOsVersion() string { + return "" +} + +func (ins *SInstance) GetOsLang() string { + return "" +} + +func (self *SInstance) GetProjectId() string { + return "" +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetVcpuCount() int { + return int(self.QemuCores * self.QemuSockets) +} + +func (self *SInstance) GetVmemSizeMB() int { + return int(self.Memory) +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + return []string{}, nil +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) StartVM(ctx context.Context) error { + return self.host.zone.region.StartVm(self.VmID) +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + if self.GetStatus() == api.VM_READY { + return nil + } + return self.host.zone.region.StopVm(self.VmID) +} + +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotSupported +} + +// readDeviceConfig - get standard sub-conf strings where `key=value` and update conf map. +func (confMap QemuDevice) readDeviceConfig(confList []string) error { + // Add device config. + for _, conf := range confList { + key, value := ParseSubConf(conf, "=") + confMap[key] = value + } + return nil +} + +func (self *SRegion) GetVmAgentNetworkInterfaces(node string, VmId int) (map[string]string, error) { + intermediates := []Intermediate{} + ipMap := map[string]string{} + res := fmt.Sprintf("/nodes/%s/qemu/%d/agent/network-get-interfaces", node, VmId) + err := self.getAgent(res, url.Values{}, &intermediates) + if err != nil { + return nil, errors.Wrap(err, "GetVmAgentNetworkInterfaces") + } + + for _, intermediate := range intermediates { + ipMap[intermediate.HardwareAddress] = intermediate.IPAddresses[0].IPAddress + } + + return ipMap, nil +} + +func (self *SRegion) GetVmPowerStatus(node string, VmId int) string { + current := map[string]string{} + res := fmt.Sprintf("/nodes/%s/qemu/%d/status/current", node, VmId) + err := self.get(res, url.Values{}, ¤t) + if err != nil { + return "unkown" + } + + power := "unkown" + if _, ok := current["qmpstatus"]; ok { + power = current["qmpstatus"] + } + + return power +} + +func (self *SRegion) GetQemuConfig(node string, VmId int) (*SInstance, error) { + //ret := &SInstance{} + res := fmt.Sprintf("/nodes/%s/qemu/%d/config", node, VmId) + vmConfig := map[string]interface{}{} + vmBase := &VmBase{ + Bios: "seabios", + OnBoot: 1, + Tablet: 1, + Ostype: "other", + Memory: 0, + Balloon: 0, + Cores: 0, + Vcpus: 0, + Sockets: 0, + Cpu: "host", + Numa: 0, + Hotplug: "network,disk,usb", + Boot: "cdn", + Kvm: 1, + Scsihw: "lsi", + Machine: "i440fx", + } + err := self.get(res, url.Values{}, &vmConfig) + if err != nil { + return nil, err + } + byteArr, err := json.Marshal(&vmConfig) + if err != nil { + return nil, err + } + err = json.Unmarshal(byteArr, &vmBase) + if err != nil { + return nil, err + } + + config := SInstance{ + VmID: int(VmId), + Name: vmBase.Name, + Description: strings.TrimSpace(vmBase.Description), + Tags: strings.TrimSpace(vmBase.Tags), + Args: strings.TrimSpace(vmBase.Args), + Bios: vmBase.Bios, + EFIDisk: QemuDevice{}, + Machine: vmBase.Machine, + Onboot: Itob(vmBase.OnBoot), + Startup: vmBase.Startup, + Tablet: Itob(vmBase.Tablet), + QemuOs: vmBase.Ostype, + Memory: int(vmBase.Memory), + QemuCores: int(vmBase.Cores), + QemuSockets: int(vmBase.Sockets), + QemuCpu: vmBase.Cpu, + QemuNuma: Itob(vmBase.Numa), + QemuKVM: Itob(vmBase.Kvm), + Hotplug: vmBase.Hotplug, + QemuVlanTag: -1, + Boot: vmBase.Boot, + BootDisk: vmBase.Bootdisk, + Scsihw: vmBase.Scsihw, + Hookscript: vmBase.Hookscript, + QemuDisks: QemuDevices{}, + QemuUnusedDisks: QemuDevices{}, + QemuVga: QemuDevice{}, + QemuNetworks: []SInstanceNic{}, + QemuSerials: QemuDevices{}, + QemuUsbs: QemuDevices{}, + Node: node, + CIuser: vmBase.Ciuser, + CIpassword: vmBase.Cipassword, + Searchdomain: vmBase.Searchdomain, + Nameserver: vmBase.Nameserver, + } + + // vmConfig Sample: map[ cpu:host + // net0:virtio=62:DF:XX:XX:XX:XX,bridge=vmbr0 + // ide2:local:iso/xxx-xx.iso,media=cdrom memory:2048 + // smbios1:uuid=8b3bf833-aad8-4545-xxx-xxxxxxx digest:aa6ce5xxxxx1b9ce33e4aaeff564d4 sockets:1 + // name:terraform-ubuntu1404-template bootdisk:virtio0 + // virtio0:ProxmoxxxxISCSI:vm-1014-disk-2,size=4G + // description:Base image + // cores:2 ostype:l26 + if vmConfig["ide2"] != nil { + isoMatch := rxIso.FindStringSubmatch(vmConfig["ide2"].(string)) + config.QemuIso = isoMatch[1] + } + + if _, ok := vmConfig["sshkeys"]; ok { + config.Sshkeys, _ = url.PathUnescape(vmConfig["sshkeys"].(string)) + } + + agent := 0 + if _, ok := vmConfig["agent"]; ok { + switch vmConfig["agent"].(type) { + case int64: + agent = int(vmConfig["agent"].(int64)) + case string: + agentConfList := strings.Split(vmConfig["agent"].(string), ",") + agent, _ = strconv.Atoi(agentConfList[0]) + } + + } + config.Agent = agent + + config.PowerState = self.GetVmPowerStatus(node, VmId) + + // Add disks. + diskNames := []string{} + for k := range vmConfig { + if diskName := rxDiskName.FindStringSubmatch(k); len(diskName) > 0 { + diskNames = append(diskNames, diskName[0]) + } + } + + for _, diskName := range diskNames { + diskConfStr := vmConfig[diskName].(string) + + id := rxDeviceID.FindStringSubmatch(diskName) + diskID, _ := strconv.Atoi(id[0]) + diskType := rxDiskType.FindStringSubmatch(diskName)[0] + + diskConfMap := ParsePMConf(diskConfStr, "volume") + + if diskConfMap["volume"].(string) == "none" { + continue + } + + diskConfMap["slot"] = diskID + diskConfMap["type"] = diskType + + storageName, fileName := ParseSubConf(diskConfMap["volume"].(string), ":") + diskConfMap["storage"] = storageName + diskConfMap["file"] = fileName + + volId := diskConfMap["volume"].(string) + + // cloud-init disks not always have the size sent by the API, which results in a crash + if diskConfMap["size"] == nil && strings.Contains(fileName.(string), "cloudinit") { + diskConfMap["size"] = "4M" // default cloud-init disk size + } + + var sizeInTerabytes = regexp.MustCompile(`[0-9]+T`) + // Convert to gigabytes if disk size was received in terabytes + matched := sizeInTerabytes.MatchString(diskConfMap["size"].(string)) + if matched { + diskConfMap["size"] = fmt.Sprintf("%.0fG", DiskSizeGB(diskConfMap["size"])) + } + + // And device config to disks map. + if len(diskConfMap) > 0 { + config.QemuDisks[volId] = diskConfMap + } + } + + // Add unused disks + // unused0:local:100/vm-100-disk-1.qcow2 + unusedDiskNames := []string{} + for k := range vmConfig { + // look for entries from the config in the format "unusedX:" where X is an integer + if unusedDiskName := rxUnusedDiskName.FindStringSubmatch(k); len(unusedDiskName) > 0 { + unusedDiskNames = append(unusedDiskNames, unusedDiskName[0]) + } + } + if len(unusedDiskNames) > 0 { + log.Debugf("[DEBUG] unusedDiskNames: %v", unusedDiskNames) + } + + for _, unusedDiskName := range unusedDiskNames { + unusedDiskConfStr := vmConfig[unusedDiskName].(string) + finalDiskConfMap := QemuDevice{} + + // parse "unused0" to get the id '0' as an int + id := rxDeviceID.FindStringSubmatch(unusedDiskName) + slotID, err := strconv.Atoi(id[0]) + if err != nil { + return nil, errors.Errorf("Unable to parse unused disk id from input string '%s' .", unusedDiskName) + } + finalDiskConfMap["slot"] = slotID + + // parse the attributes from the unused disk + // extract the storage and file path from the unused disk entry + parsedUnusedDiskMap := ParsePMConf(unusedDiskConfStr, "storage+file") + storageName, fileName := ParseSubConf(parsedUnusedDiskMap["storage+file"].(string), ":") + finalDiskConfMap["storage"] = storageName + finalDiskConfMap["file"] = fileName + volId := parsedUnusedDiskMap["storage+file"].(string) + + config.QemuUnusedDisks[volId] = finalDiskConfMap + } + + //Display + if vga, ok := vmConfig["vga"]; ok { + vgaList := strings.Split(vga.(string), ",") + vgaMap := QemuDevice{} + + // TODO: keep going if error? + err = vgaMap.readDeviceConfig(vgaList) + if err != nil { + log.Debugf("[ERROR] %q", err) + } + if len(vgaMap) > 0 { + config.QemuVga = vgaMap + } + } + + // Add networks. + nicNames := []string{} + ipMap := make(map[string]string) + if config.PowerState == "running" && config.Agent == 1 { + ipMap, _ = self.GetVmAgentNetworkInterfaces(node, VmId) + } + + for k := range vmConfig { + if nicName := rxNicName.FindStringSubmatch(k); len(nicName) > 0 { + nicNames = append(nicNames, nicName[0]) + } + } + + for _, nicName := range nicNames { + nicConfStr := vmConfig[nicName] + nicConfList := strings.Split(nicConfStr.(string), ",") + + //id := rxDeviceID.FindStringSubmatch(nicName) + model, macaddr := ParseSubConf(nicConfList[0], "=") + _, network := ParseSubConf(nicConfList[1], "=") + //nicID := fmt.Sprintf("%d:%s", VmId, nicName) + + // Add model and MAC address. + nicConf := SInstanceNic{ + NicId: network.(string), + Model: model, + MacAddr: strings.ToLower(macaddr.(string)), + NetworkId: fmt.Sprintf("network/%s/%s", node, network), + } + + if ip, ok := ipMap[nicConf.MacAddr]; ok { + nicConf.IpAddr = ip + } + + // And device config to networks. + config.QemuNetworks = append(config.QemuNetworks, nicConf) + } + + // Add serials + serialNames := []string{} + + for k := range vmConfig { + if serialName := rxSerialName.FindStringSubmatch(k); len(serialName) > 0 { + serialNames = append(serialNames, serialName[0]) + } + } + + for _, serialName := range serialNames { + id := rxDeviceID.FindStringSubmatch(serialName) + serialID, _ := strconv.Atoi(id[0]) + + serialConfMap := QemuDevice{ + "id": serialID, + "type": vmConfig[serialName], + } + + // And device config to serials map. + if len(serialConfMap) > 0 { + config.QemuSerials[serialName] = serialConfMap + } + } + + // Add usbs + usbNames := []string{} + + for k := range vmConfig { + if usbName := rxUsbName.FindStringSubmatch(k); len(usbName) > 0 { + usbNames = append(usbNames, usbName[0]) + } + } + + for _, usbName := range usbNames { + usbConfStr := vmConfig[usbName] + usbConfList := strings.Split(usbConfStr.(string), ",") + id := rxDeviceID.FindStringSubmatch(usbName) + usbID, _ := strconv.Atoi(id[0]) + _, host := ParseSubConf(usbConfList[0], "=") + + usbConfMap := QemuDevice{ + "id": usbID, + "host": host, + } + + err = usbConfMap.readDeviceConfig(usbConfList[1:]) + if err != nil { + log.Debugf("[ERROR] %q", err) + } + if usbConfMap["usb3"] == 1 { + usbConfMap["usb3"] = true + } + + // And device config to usbs map. + if len(usbConfMap) > 0 { + config.QemuUsbs[usbName] = usbConfMap + } + } + + return &config, nil + +} + +func (self *SRegion) GetInstances(hostId string) ([]SInstance, error) { + ret := []SInstance{} + resources, err := self.GetClusterVmResources() + if err != nil { + return nil, err + } + + for _, res := range resources { + if res.NodeId == hostId { + instance, err := self.GetQemuConfig(res.Node, res.VmId) + if err == nil { + ret = append(ret, *instance) + } + + } + } + + return ret, nil +} + +func (self *SRegion) GetInstance(id string) (*SInstance, error) { + resources, err := self.GetClusterVmResources() + if err != nil { + return nil, err + } + + nodeName := "" + vmId, _ := strconv.Atoi(id) + if resource, ok := resources[vmId]; !ok { + return nil, errors.Errorf("failed get Instance id %s", id) + } else { + nodeName = resource.Node + } + + return self.GetQemuConfig(nodeName, vmId) +} + +func (self *SRegion) StartVm(vmId int) error { + resources, err := self.GetClusterVmResources() + if err != nil { + return err + } + + nodeName := "" + if resource, ok := resources[vmId]; !ok { + return errors.Errorf("start VM id %d", vmId) + } else { + nodeName = resource.Node + } + + res := fmt.Sprintf("/nodes/%s/qemu/%d/status/start", nodeName, vmId) + params := url.Values{} + + _, err = self.post(res, params) + return err + +} + +func (self *SRegion) StopVm(vmId int) error { + resources, err := self.GetClusterVmResources() + if err != nil { + return err + } + + nodeName := "" + if resource, ok := resources[vmId]; !ok { + return errors.Errorf("start VM id %d", vmId) + } else { + nodeName = resource.Node + } + + res := fmt.Sprintf("/nodes/%s/qemu/%d/status/stop", nodeName, vmId) + params := url.Values{} + + _, err = self.post(res, params) + return err +} + +func (self *SRegion) AttachDisk(vmId int, diskId string) error { + id := strconv.Itoa(int(vmId)) + vm1, err := self.GetInstance(id) + if err != nil { + return errors.Wrapf(err, "GetInstance(%d)", vmId) + } + if _, ok := vm1.QemuUnusedDisks[diskId]; !ok { + return nil + } + + slotsArr := []int{} + for _, v := range vm1.QemuDisks { + if v["type"] == "scsi" { + slotIdx := v["slot"].(int) + slotsArr = append(slotsArr, slotIdx) + } + } + sort.Ints(slotsArr) + minSlot := slotsArr[0] + for idx, _ := range slotsArr { + if slotsArr[idx] == minSlot { + minSlot++ + } else { + break + } + + } + + body := map[string]string{} + params := url.Values{} + diskName := fmt.Sprintf("scsi%d", minSlot) + body[diskName] = diskId + res := fmt.Sprintf("/nodes/%s/qemu/%d/config", vm1.Node, vm1.VmID) + err = self.put(res, params, jsonutils.Marshal(body), nil) + if err != nil { + return errors.Wrapf(err, "GetInstance(%d) self.put", vmId) + } + //clear + vm1.QemuDisks = make(map[string]map[string]interface{}) + vm1.QemuUnusedDisks = make(map[string]map[string]interface{}) + + vm2, err := self.GetInstance(id) + if err != nil { + return errors.Wrapf(err, "GetInstance(%d) vm2", vmId) + } + vm1.QemuDisks = vm2.QemuDisks + vm1.QemuUnusedDisks = vm2.QemuUnusedDisks + + return nil + +} + +func (self *SRegion) DetachDisk(vmId int, diskId string) error { + id := strconv.Itoa(int(vmId)) + vm1, err := self.GetInstance(id) + if err != nil { + return errors.Wrapf(err, "GetInstance(%d)", vmId) + } + if v, ok := vm1.QemuDisks[diskId]; !ok { + return nil + } else { + diskName := fmt.Sprintf("%s%d", v["type"].(string), v["slot"].(int)) + body := map[string]string{} + params := url.Values{} + body["delete"] = diskName + res := fmt.Sprintf("/nodes/%s/qemu/%d/config", vm1.Node, vm1.VmID) + err := self.put(res, params, jsonutils.Marshal(body), nil) + if err != nil { + return errors.Wrapf(err, "GetInstance(%d) self.put", vmId) + } + //clear + vm1.QemuDisks = make(map[string]map[string]interface{}) + vm1.QemuUnusedDisks = make(map[string]map[string]interface{}) + + vm2, err := self.GetInstance(id) + if err != nil { + return errors.Wrapf(err, "GetInstance(%d) vm2", vmId) + } + vm1.QemuDisks = vm2.QemuDisks + vm1.QemuUnusedDisks = vm2.QemuUnusedDisks + + return nil + } + +} + +func (self *SRegion) ChangeConfig(vmId int, cpu int, memMb int) error { + vm, err := self.GetInstance(strconv.Itoa(int(vmId))) + body := map[string]interface{}{} + if err != nil { + return errors.Wrapf(err, "ChangeConfig(%d)", vmId) + } + + changed := false + if cpu > 0 { + vm.QemuCores = 1 + vm.QemuSockets = cpu + vm.QemuVcpus = cpu + changed = true + body["cores"] = 1 + body["sockets"] = cpu + body["vcpus"] = cpu + } + if memMb > 0 { + vm.Memory = memMb + body["memory"] = memMb + changed = true + } + if !changed { + return nil + } + + params := url.Values{} + res := fmt.Sprintf("/nodes/%s/qemu/%d/config", vm.Node, vmId) + return self.put(res, params, jsonutils.Marshal(body), nil) +} + +func (self *SRegion) ResetVmPassword(vmId int, username, password string) error { + resources, err := self.GetClusterVmResources() + if err != nil { + return err + } + + nodeName := "" + if resource, ok := resources[vmId]; !ok { + return errors.Errorf("failed to ResetVmPassword VM id %d", vmId) + } else { + nodeName = resource.Node + } + + params := url.Values{} + body := map[string]interface{}{ + "username": username, + "password": password, + } + + res := fmt.Sprintf("/nodes/%s/qemu/%d/agent/set-user-password", nodeName, vmId) + return self.put(res, params, jsonutils.Marshal(body), nil) + +} + +func (self *SRegion) DeleteVM(vmId int) error { + id := strconv.Itoa(int(vmId)) + vm1, err := self.GetInstance(id) + if err != nil { + return errors.Wrapf(err, "GetInstance(%d)", vmId) + } + params := url.Values{} + params.Set("purge", "1") + + res := fmt.Sprintf("/nodes/%s/qemu/%d", vm1.Node, vmId) + return self.del(res, params, nil) +} +func (self *SRegion) GenVM(name, node string, cores, memMB int) (*SInstance, error) { + + vmId := self.GetClusterVmMaxId() + if vmId == -1 { + return nil, errors.Errorf("failed to get vm number by %d", vmId) + } else { + vmId++ + } + + body := map[string]interface{}{ + "vmid": vmId, + "name": name, + "ostype": "other", + "sockets": 1, + "cores": cores, + "cpu": "host", + "kvm": 1, + "hotplug": "network,disk,usb", + "memory": memMB, + "description": "", + "scsihw": "virtio-scsi-pci", + } + + res := fmt.Sprintf("/nodes/%s/qemu", node) + _, err := self.post(res, jsonutils.Marshal(body)) + if err != nil { + return nil, err + } + + vmIdRet := strconv.Itoa(vmId) + vm, err := self.GetInstance(vmIdRet) + if err != nil { + return nil, err + } + + return vm, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/network.go new file mode 100644 index 0000000000..5640be6e51 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/network.go @@ -0,0 +1,187 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + ProxmoxTags + + wire *SWire + + Id string + + Priority int `json:"priority"` + Families []string `json:"families"` + Method string `json:"method"` + Autostart int `json:"autostart,omitempty"` + Iface string `json:"iface"` + BridgeFd string `json:"bridge_fd,omitempty"` + Method6 string `json:"method6"` + BridgePorts string `json:"bridge_ports,omitempty"` + Type string `json:"type"` + Active int `json:"active"` + BridgeStp string `json:"bridge_stp,omitempty"` + BridgeVids string `json:"bridge_vids,omitempty"` + Netmask string `json:"netmask,omitempty"` + Address string `json:"address,omitempty"` + BridgeVlanAware int `json:"bridge_vlan_aware,omitempty"` + Gateway string `json:"gateway,omitempty"` + Cidr string `json:"cidr,omitempty"` + Exists int `json:"exists,omitempty"` + Options []string `json:"options,omitempty"` +} + +func (self *SNetwork) GetName() string { + return self.Iface +} + +func (self *SNetwork) GetId() string { + return self.Id +} + +func (self *SNetwork) GetGlobalId() string { + return self.GetId() +} + +func (self *SNetwork) Refresh() error { + ret, err := self.wire.region.GetNetwork(self.Id) + if err != nil { + return err + } + return jsonutils.Update(self, ret) +} + +func (self *SNetwork) Delete() error { + return cloudprovider.ErrNotFound +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (self *SNetwork) GetGateway() string { + return self.Gateway +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.Cidr) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + startIp = startIp.StepUp() // 2 + return startIp.String() +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.Cidr) + 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) Contains(_ip string) bool { + start, _ := netutils.NewIPV4Addr(self.GetIpStart()) + end, _ := netutils.NewIPV4Addr(self.GetIpEnd()) + ip, _ := netutils.NewIPV4Addr(_ip) + return netutils.NewIPV4AddrRange(start, end).Contains(ip) +} + +func (self *SNetwork) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(self.Cidr) + return pref.MaskLen +} + +func (self *SNetwork) GetProjectId() string { + return "" +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetStatus() string { + return api.NETWORK_STATUS_AVAILABLE +} + +func (self *SRegion) GetNetworks() ([]SNetwork, error) { + ret := []SNetwork{} + + resources, err := self.GetClusterNodeResources() + if err != nil { + return nil, err + } + + for _, res := range resources { + networks := []SNetwork{} + urlNetwork := fmt.Sprintf("/nodes/%s/network", res.Node) + self.get(urlNetwork, url.Values{}, &networks) + + for _, iface := range networks { + id := fmt.Sprintf("network/%s/%s", res.Node, iface.Iface) + iface.Id = id + + ret = append(ret, iface) + } + + } + + return ret, nil +} + +func (self *SRegion) GetNetwork(id string) (*SNetwork, error) { + ret := &SNetwork{} + + //"id": "network/nodeNAME/iface", + splited := strings.Split(id, "/") + nodeName := "" + networkName := "" + + if len(splited) == 3 { + nodeName = splited[1] + networkName = splited[2] + } else { + return nil, errors.Errorf("failed to get network by %s", id) + } + + res := fmt.Sprintf("/nodes/%s/network/%s", nodeName, networkName) + err := self.get(res, url.Values{}, ret) + ret.Id = id + + return ret, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/nic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/nic.go new file mode 100644 index 0000000000..a60d01304a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/nic.go @@ -0,0 +1,65 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "fmt" + "strings" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + cloudprovider.DummyICloudNic + ins *SInstance + + MacAddr string + IpAddr string + NicId string + Model string + NetworkId string +} + +func (self *SInstanceNic) GetId() string { + return fmt.Sprintf("%d/%s", self.ins.VmID, self.NicId) +} + +func (self *SInstanceNic) GetIP() string { + return self.IpAddr +} + +func (self *SInstanceNic) GetMAC() string { + return self.MacAddr +} + +func (self *SInstanceNic) GetDriver() string { + return strings.ToLower(self.Model) +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return true +} + +func (self *SInstanceNic) GetSubAddress() ([]string, error) { + return []string{}, nil +} + +func (self *SInstanceNic) GetINetworkId() string { + return self.NetworkId +} + +func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/provider/doc.go new file mode 100644 index 0000000000..0381caeea5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/provider/doc.go @@ -0,0 +1 @@ +package provider // import "yunion.io/x/cloudmux/pkg/multicloud/proxmox/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/provider/provider.go new file mode 100644 index 0000000000..d867c919f7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/provider/provider.go @@ -0,0 +1,200 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "fmt" + "net/url" + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/regutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/proxmox" +) + +type SProxmoxProviderFactory struct { + cloudprovider.SPrivateCloudBaseProviderFactory +} + +func (self *SProxmoxProviderFactory) GetId() string { + return proxmox.CLOUD_PROVIDER_PROXMOX +} + +func (self *SProxmoxProviderFactory) GetName() string { + return proxmox.CLOUD_PROVIDER_PROXMOX +} + +func (self *SProxmoxProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { + return fmt.Errorf("Changing %s bandwidth is not supported", proxmox.CLOUD_PROVIDER_PROXMOX) +} + +func (self *SProxmoxProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.Username) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "username") + } + if len(input.Password) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "password") + } + if len(input.Host) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "host") + } + if !regutils.MatchIPAddr(input.Host) && !regutils.MatchDomainName(input.Host) { + return output, errors.Wrap(httperrors.ErrInputParameter, "host should be ip or domain name") + } + if input.Port == 0 { + input.Port = 8006 + } + output.AccessUrl = fmt.Sprintf("https://%s:%d", input.Host, input.Port) + output.Account = input.Username + output.Secret = input.Password + return output, nil +} + +func (self *SProxmoxProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.Username) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "username") + } + if len(input.Password) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "password") + } + output = cloudprovider.SCloudaccount{ + Account: input.Username, + Secret: input.Password, + } + return output, nil +} + +func parseHostPort(_url string) (string, int, error) { + urlParse, err := url.Parse(_url) + if err != nil { + return "", 0, errors.Wrapf(err, "parse %s", _url) + } + port := func() int { + if len(urlParse.Port()) > 0 { + _port, _ := strconv.Atoi(urlParse.Port()) + return _port + } + return 8006 + }() + return strings.TrimSuffix(urlParse.Host, fmt.Sprintf(":%d", port)), port, nil +} + +func (self *SProxmoxProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + host, port, err := parseHostPort(cfg.URL) + if err != nil { + return nil, errors.Wrapf(err, "parseHostPort") + } + + client, err := proxmox.NewProxmoxClient( + proxmox.NewProxmoxClientConfig( + cfg.Account, cfg.Secret, host, port, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SProxmoxProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SProxmoxProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + host, port, err := parseHostPort(info.Url) + if err != nil { + return nil, err + } + + return map[string]string{ + "PROXMOX_HOST": host, + "PROXMOX_PORT": fmt.Sprintf("%d", port), + "PROXMOX_USERNAME": info.Account, + "PROXMOX_PASSWORD": info.Secret, + }, nil +} + +func init() { + factory := SProxmoxProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SProxmoxProvider struct { + cloudprovider.SBaseProvider + client *proxmox.SProxmoxClient +} + +func (self *SProxmoxProvider) GetSysInfo() (jsonutils.JSONObject, error) { + return jsonutils.NewDict(), nil +} + +func (self *SProxmoxProvider) GetVersion() string { + return "1.0" +} + +func (self *SProxmoxProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SProxmoxProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SProxmoxProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SProxmoxProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + regions := self.GetIRegions() + for i := range regions { + if regions[i].GetGlobalId() == id { + return regions[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SProxmoxProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SProxmoxProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return []cloudprovider.ICloudProject{}, nil +} + +func (self *SProxmoxProvider) GetStorageClasses(regionId string) []string { + return nil +} + +func (self *SProxmoxProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (self *SProxmoxProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (self *SProxmoxProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} diff --git a/pkg/multicloud/proxmox/proxmox.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/proxmox.go similarity index 98% rename from pkg/multicloud/proxmox/proxmox.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/proxmox.go index 574d029c09..07c6514d4b 100644 --- a/pkg/multicloud/proxmox/proxmox.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/proxmox.go @@ -26,8 +26,8 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/region.go new file mode 100644 index 0000000000..2d9be0df76 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/region.go @@ -0,0 +1,204 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "fmt" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + multicloud.SRegion + multicloud.SRegionEipBase + multicloud.SNoObjectStorageRegion + multicloud.SRegionLbBase + + client *SProxmoxClient +} + +func (self *SRegion) GetClient() *SProxmoxClient { + return self.client +} + +func (self *SRegion) GetName() string { + return self.client.cpcfg.Name +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) + return table +} + +func (self *SRegion) GetId() string { + return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_PROXMOX, self.client.cpcfg.Id) +} + +func (self *SRegion) GetGlobalId() string { + return self.GetId() +} + +func (self *SRegion) GetProvider() string { + return CLOUD_PROVIDER_PROXMOX +} + +func (self *SRegion) GetCloudEnv() string { + return "" +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) Refresh() error { + return nil +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) CreateIVpc(conf *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SRegion) getVpc() *SVpc { + return &SVpc{region: self} +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + vpc := self.getVpc() + return []cloudprovider.ICloudVpc{vpc}, nil +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + vpcs, err := self.GetIVpcs() + if err != nil { + return nil, err + } + for i := range vpcs { + if vpcs[i].GetGlobalId() == id { + return vpcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + zone, err := self.GetZone() + if err != nil { + return nil, errors.Wrapf(err, "GetZone()") + } + return zone, nil +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + zone, err := self.GetZone() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudZone{} + zone.region = self + ret = append(ret, zone) + return ret, nil +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := self.GetInstance(id) + if err != nil { + return nil, err + } + return vm, nil +} + +func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + host, err := self.GetHost(id) + if err != nil { + return nil, err + } + zone, err := self.GetZone() + if err != nil { + return nil, err + } + host.zone = zone + return host, nil +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + zone, err := self.GetZone() + if err != nil { + return nil, cloudprovider.ErrNotSupported + } + ret := []cloudprovider.ICloudStoragecache{} + cache := &SStoragecache{zone: zone} + ret = append(ret, cache) + return ret, nil +} + +func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + caches, err := self.GetIStoragecaches() + if err != nil { + return nil, cloudprovider.ErrNotSupported + } + for i := range caches { + if caches[i].GetGlobalId() == id { + return caches[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) get(res string, params url.Values, retVal interface{}) error { + return self.client.get(res, params, retVal) +} + +func (self *SRegion) getAgent(res string, params url.Values, retVal interface{}) error { + return self.client.getAgent(res, params, retVal) +} + +func (self *SRegion) post(res string, params interface{}) (jsonutils.JSONObject, error) { + return self.client.post(res, params) +} + +func (self *SRegion) put(res string, params url.Values, body jsonutils.JSONObject, retVal interface{}) error { + return self.client.put(res, params, body, retVal) +} + +func (self *SRegion) del(res string, params url.Values, retVal interface{}) error { + return self.client.del(res, params, retVal) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/storage.go new file mode 100644 index 0000000000..37cef91ae1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/storage.go @@ -0,0 +1,230 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStorage struct { + multicloud.SStorageBase + ProxmoxTags + + zone *SZone + + Id string + Node string + + Total int64 `json:"total"` + Storage string `json:"storage"` + Shared int `json:"shared"` + Used int64 `json:"used"` + Content string `json:"content"` + Active int `json:"active"` + UsedFraction float64 `json:"used_fraction"` + Avail int64 `json:"avail"` + Enabled int `json:"enabled"` + Type string `json:"type"` +} + +func (self *SStorage) GetName() string { + return self.Storage +} + +func (self *SStorage) GetId() string { + return self.Id +} + +func (self *SStorage) GetGlobalId() string { + return self.GetId() +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := self.zone.region.GetDisks(self.Id) + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudDisk{} + for i := range disks { + disks[i].region = self.zone.region + ret = append(ret, &disks[i]) + } + return ret, nil +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SStorage) GetCapacityMB() int64 { + return int64(self.Total / 1024 / 1024) +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return int64(self.Used / 1024 / 1024) +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disk, err := self.zone.region.GetDisk(id) + if err != nil { + return nil, cloudprovider.ErrNotFound + } + + return disk, nil +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + cache := &SStoragecache{zone: self.zone} + return cache +} + +func (self *SStorage) GetMediumType() string { + return api.DISK_TYPE_SSD +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) Refresh() error { + ret, err := self.zone.region.GetStorage(self.GetGlobalId()) + if err != nil { + return err + } + return jsonutils.Update(self, ret) +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (self *SStorage) GetStorageType() string { + return strings.ToLower(self.Type) +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} + +func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storage, err := self.GetStorage(id) + if err != nil { + return nil, err + } + zone, err := self.GetZone() + if err != nil { + return nil, err + } + storage.zone = zone + return storage, nil +} + +func (self *SRegion) GetStorages() ([]SStorage, error) { + storages := []SStorage{} + resources, err := self.GetClusterStoragesResources() + if err != nil { + return nil, err + } + + for _, res := range resources { + storage := &SStorage{} + status := fmt.Sprintf("%s/status", res.Path) + err := self.get(status, url.Values{}, storage) + if err != nil { + return nil, err + } + + storage.Id = res.Id + storage.Node = res.Node + // not support storageCache, so chanege the type name. + if storage.Type == "rbd" { + storage.Type = "cephrbd" + } + if storage.Storage == "" { + storage.Storage = res.Name + } + + storages = append(storages, *storage) + } + + return storages, nil +} + +func (self *SRegion) GetStoragesByHost(hostId string) ([]SStorage, error) { + storages := []SStorage{} + nodeName := "" + splited := strings.Split(hostId, "/") + nodeName = splited[1] + + res := fmt.Sprintf("/nodes/%s/storage", nodeName) + err := self.get(res, url.Values{}, &storages) + if err != nil { + return nil, err + } + + for i := range storages { + id := fmt.Sprintf("storage/%s/%s", nodeName, storages[i].Storage) + storages[i].Node = nodeName + storages[i].Id = id + if storages[i].Type == "rbd" { + storages[i].Type = "cephrbd" + } + } + + return storages, nil +} + +func (self *SRegion) GetStorage(id string) (*SStorage, error) { + ret := &SStorage{} + + //"id": "storage/nodeNAME/strogeNAME", + splited := strings.Split(id, "/") + nodeName := "" + storageName := "" + + if len(splited) == 3 { + nodeName, storageName = splited[1], splited[2] + } + + status := fmt.Sprintf("/nodes/%s/storage/%s/status", nodeName, storageName) + err := self.get(status, url.Values{}, ret) + ret.Id = id + ret.Node = nodeName + if ret.Type == "rbd" { + ret.Type = "cephrbd" + } + + return ret, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/storagecache.go new file mode 100644 index 0000000000..3ac36744e9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/storagecache.go @@ -0,0 +1,95 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "context" + + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStoragecache struct { + multicloud.SResourceBase + ProxmoxTags + + zone *SZone +} + +func (self *SStoragecache) GetGlobalId() string { + return self.zone.GetGlobalId() +} + +func (self *SStoragecache) GetId() string { + return self.zone.GetId() +} + +func (self *SStoragecache) GetName() string { + return self.zone.GetName() +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + ret := []cloudprovider.ICloudImage{} + images, err := self.zone.region.GetImageList() + if err != nil { + return nil, err + } + for i := range images { + images[i].cache = self + ret = append(ret, &images[i]) + } + + return ret, nil +} + +func (seflf *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SStoragecache) GetIImageById(id string) (cloudprovider.ICloudImage, error) { + images, err := self.GetICloudImages() + if err != nil { + return nil, err + } + for i := range images { + if images[i].GetGlobalId() == id { + return images[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +func (self *SStoragecache) CreateIImage(snpId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(float32)) (string, error) { + return "", cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/tag_base.go new file mode 100644 index 0000000000..c95ee96793 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/tag_base.go @@ -0,0 +1,37 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type ProxmoxTags struct { +} + +func (self *ProxmoxTags) GetTags() (map[string]string, error) { + tags := map[string]string{} + return tags, nil +} + +func (self *ProxmoxTags) GetSysTags() map[string]string { + return nil +} + +func (self *ProxmoxTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/task.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/task.go new file mode 100644 index 0000000000..195256bed9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/task.go @@ -0,0 +1,86 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "encoding/json" + "fmt" + "strings" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type STask struct { + User string `json:"user"` + Type string `json:"type"` + Saved string `json:"saved"` + Status string `json:"status"` + Starttime int `json:"starttime"` + Node string `json:"node"` + ID string `json:"id"` + Endtime int `json:"endtime"` + Upid string `json:"upid"` +} + +func (c *SProxmoxClient) getTaskId(taskResponse map[string]interface{}) string { + if taskResponse["errors"] != nil { + errJSON, _ := json.MarshalIndent(taskResponse["errors"], "", " ") + return string(errJSON) + } + if taskResponse["data"] == nil { + return "" + } + + taskUpid := taskResponse["data"].(string) + return taskUpid +} + +func (self *SProxmoxClient) waitTask(id string) (string, error) { + resId := "" + return resId, cloudprovider.Wait(time.Second*10, time.Minute*10, func() (bool, error) { + tasks := []STask{} + err := self.get("/cluster/tasks", nil, &tasks) + if err != nil { + return false, errors.Wrapf(err, "get task %s", id) + } + + for _, task := range tasks { + if task.Upid == id { + switch strings.ToLower(task.Status) { + case "running": + log.Debugf("task %s state: %s", task.Upid, task.Status) + return false, nil + case "ok": + log.Debugf("task %s state: %s", task.Upid, task.Status) + resId = task.Upid + return true, nil + case "": + log.Debugf("task %s not finish", task.Upid) + return false, nil + default: + log.Debugf("task %s state: %s", task.Upid, task.Status) + return false, fmt.Errorf("task %s state: %s", task.Upid, task.Status) + } + + } + } + + return false, fmt.Errorf("not find task %s ", id) + }) +} diff --git a/pkg/multicloud/proxmox/util.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/util.go similarity index 100% rename from pkg/multicloud/proxmox/util.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/util.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/vpc.go new file mode 100644 index 0000000000..380ddd2e30 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/vpc.go @@ -0,0 +1,98 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + ProxmoxTags + + region *SRegion +} + +func (self *SVpc) GetName() string { + return "Default" +} + +func (self *SVpc) GetId() string { + return self.region.GetId() +} + +func (self *SVpc) GetGlobalId() string { + return self.GetId() +} + +func (self *SVpc) Delete() error { + return cloudprovider.ErrNotSupported +} + +func (self *SVpc) IsEmulated() bool { + return true +} + +func (self *SVpc) GetCidrBlock() string { + return "0.0.0.0/0" +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + return []cloudprovider.ICloudRouteTable{}, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + return []cloudprovider.ICloudSecurityGroup{}, nil +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + wires, err := self.region.GetWires() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudWire{} + for i := range wires { + wires[i].region = self.region + ret = append(ret, &wires[i]) + } + return ret, nil +} + +func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { + wire, err := self.region.GetWire() + if err != nil { + return nil, err + } + wire.region = self.region + return wire, nil +} + +func (self *SVpc) GetIsDefault() bool { + return true +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVpc) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/wire.go new file mode 100644 index 0000000000..b4df4cf519 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/wire.go @@ -0,0 +1,95 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + ProxmoxTags + + region *SRegion +} + +func (self *SWire) GetId() string { + return self.region.GetId() +} + +func (self *SWire) GetName() string { + return "Default" +} + +func (self *SWire) GetGlobalId() string { + return self.GetId() +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SWire) GetBandwidth() int { + return 10000 +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + nets, err := self.region.GetNetworks() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNetwork{} + for i := range nets { + nets[i].wire = self + ret = append(ret, &nets[i]) + } + return ret, nil +} + +func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { + net, err := self.region.GetNetwork(id) + if err != nil { + return nil, err + } + net.wire = self + return net, nil +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.region.getVpc() +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + zone, _ := self.region.GetZone() + return zone +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SRegion) GetWires() ([]SWire, error) { + ret := []SWire{} + wire := &SWire{region: self} + ret = append(ret, *wire) + return ret, nil +} + +func (self *SRegion) GetWire() (*SWire, error) { + ret := &SWire{region: self} + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/zone.go new file mode 100644 index 0000000000..924a07553d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/proxmox/zone.go @@ -0,0 +1,157 @@ +// Copyright 2019 Yunion +// +// 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 proxmox + +import ( + "net/url" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SZone struct { + multicloud.SResourceBase + ProxmoxTags + + region *SRegion + + Name string + Nodes int + Quorate int + Version int +} + +type ClusterStatus struct { + Nodes int `json:"nodes,omitempty"` + Quorate int `json:"quorate,omitempty"` + Version int `json:"version,omitempty"` + Type string `json:"type"` + ID string `json:"id"` + Name string `json:"name"` + Online int `json:"online,omitempty"` + Level string `json:"level,omitempty"` + Nodeid int `json:"nodeid,omitempty"` + Local int `json:"local,omitempty"` + IP string `json:"ip,omitempty"` +} + +func (self *SZone) GetId() string { + return self.Name +} + +func (self *SZone) GetGlobalId() string { + return self.Name +} + +func (self *SZone) GetName() string { + return self.Name +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) GetStatus() string { + return api.ZONE_ENABLE +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()) + return table +} + +func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + host, err := self.region.GetHost(id) + if err != nil { + return nil, err + } + host.zone = self + + return host, nil +} + +func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + hosts, err := self.region.GetHosts() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudHost{} + for i := range hosts { + hosts[i].zone = self + ret = append(ret, &hosts[i]) + } + return ret, nil +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.region.GetStorages() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + storages[i].zone = self + ret = append(ret, &storages[i]) + } + return ret, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storage, err := self.region.GetStorage(id) + if err != nil { + return nil, errors.Wrapf(err, "GetStorage %s", id) + } + + storage.zone = self + return storage, nil +} + +func (self *SRegion) GetZone() (*SZone, error) { + ret := &SZone{region: self} + css := []ClusterStatus{} + + noneClusterMsg := true + nodeNum := 0 + + err := self.get("/cluster/status", url.Values{}, &css) + if err != nil { + return nil, err + } + + for _, cs := range css { + if cs.Type == "cluster" { + ret.Name = cs.Name + ret.Nodes = cs.Nodes + ret.Quorate = cs.Quorate + ret.Version = cs.Version + noneClusterMsg = false + break + } else { + nodeNum++ + } + + } + + if noneClusterMsg == true { + ret.Name = "cluster" + ret.Nodes = nodeNum + } + + return ret, nil +} diff --git a/pkg/multicloud/qcloud/bandwidthpackage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/bandwidthpackage.go similarity index 100% rename from pkg/multicloud/qcloud/bandwidthpackage.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/bandwidthpackage.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/bucket.go new file mode 100644 index 0000000000..925b9db878 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/bucket.go @@ -0,0 +1,1169 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" + + "github.com/tencentyun/cos-go-sdk-v5" + "gopkg.in/fatih/set.v0" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/timeutils" + "yunion.io/x/s3cli" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + COS_META_HEADER = "X-Cos-Meta-" +) + +type SBucket struct { + multicloud.SBaseBucket + QcloudTags + + appId string + + region *SRegion + zone *SZone + + Name string + Location string + CreateDate time.Time +} + +func (b *SBucket) GetProjectId() string { + return "" +} + +func (b *SBucket) GetGlobalId() string { + if b.getAppId() == b.region.client.appId { + return b.Name + } else { + return b.getFullName() + } +} + +func (b *SBucket) GetName() string { + return b.GetGlobalId() +} + +func (b *SBucket) GetLocation() string { + return b.Location +} + +func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { + return b.region +} + +func (b *SBucket) GetCreatedAt() time.Time { + return b.CreateDate +} + +func (b *SBucket) GetStorageClass() string { + return "" +} + +const ( + ACL_GROUP_URI_ALL_USERS = "http://cam.qcloud.com/groups/global/AllUsers" + ACL_GROUP_URI_AUTH_USERS = "http://cam.qcloud.com/groups/global/AuthenticatedUsers" +) + +func cosAcl2CannedAcl(acls []cos.ACLGrant) cloudprovider.TBucketACLType { + switch { + case len(acls) == 1: + if acls[0].Grantee.URI == "" && acls[0].Permission == s3cli.PERMISSION_FULL_CONTROL { + return cloudprovider.ACLPrivate + } + case len(acls) == 2: + for _, g := range acls { + if g.Grantee.URI == ACL_GROUP_URI_AUTH_USERS && g.Permission == s3cli.PERMISSION_READ { + return cloudprovider.ACLAuthRead + } + if g.Grantee.URI == ACL_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_READ { + return cloudprovider.ACLPublicRead + } + } + case len(acls) == 3: + for _, g := range acls { + if g.Grantee.URI == ACL_GROUP_URI_ALL_USERS && g.Permission == s3cli.PERMISSION_WRITE { + return cloudprovider.ACLPublicReadWrite + } + } + } + return cloudprovider.ACLUnknown +} + +func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + coscli, err := b.region.GetCosClient(b) + if err != nil { + log.Errorf("GetCosClient fail %s", err) + return acl + } + result, _, err := coscli.Bucket.GetACL(context.Background()) + if err != nil { + log.Errorf("coscli.Bucket.GetACL fail %s", err) + return acl + } + return cosAcl2CannedAcl(result.AccessControlList) +} + +func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrap(err, "b.region.GetCosClient") + } + opts := &cos.BucketPutACLOptions{} + opts.Header = &cos.ACLHeaderOptions{} + opts.Header.XCosACL = string(aclStr) + _, err = coscli.Bucket.PutACL(context.Background(), opts) + if err != nil { + return errors.Wrap(err, "PutACL") + } + return nil +} + +func (b *SBucket) getAppId() string { + if len(b.appId) > 0 { + return b.appId + } + if b.zone != nil { + return b.zone.region.client.appId + } + return b.region.client.appId +} + +func (b *SBucket) getFullName() string { + return fmt.Sprintf("%s-%s", b.Name, b.getAppId()) +} + +func (b *SBucket) getBucketUrlHost() string { + if b.zone != nil { + return fmt.Sprintf("%s.%s", b.getFullName(), b.zone.getCosEndpoint()) + } else { + return fmt.Sprintf("%s.%s", b.getFullName(), b.region.getCosEndpoint()) + } +} + +func (b *SBucket) getBucketUrl() string { + return fmt.Sprintf("https://%s", b.getBucketUrlHost()) +} + +func (b *SBucket) getBucketWebsiteUrlHost() string { + if b.zone != nil { + return fmt.Sprintf("%s.%s", b.getFullName(), b.zone.getCosWebsiteEndpoint()) + } else { + return fmt.Sprintf("%s.%s", b.getFullName(), b.region.getCosWebsiteEndpoint()) + } +} + +func (b *SBucket) getWebsiteUrl() string { + return fmt.Sprintf("https://%s", b.getBucketWebsiteUrlHost()) +} + +func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { + return []cloudprovider.SBucketAccessUrl{ + { + Url: b.getBucketUrl(), + Description: "bucket domain", + Primary: true, + }, + { + Url: fmt.Sprintf("https://%s/%s", b.region.getCosEndpoint(), b.getFullName()), + Description: "cos domain", + }, + } +} + +func (b *SBucket) GetStats() cloudprovider.SBucketStats { + stats, _ := cloudprovider.GetIBucketStats(b) + return stats +} + +func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { + result := cloudprovider.SListObjectResult{} + coscli, err := b.region.GetCosClient(b) + if err != nil { + return result, errors.Wrap(err, "GetCosClient") + } + opts := &cos.BucketGetOptions{} + if len(prefix) > 0 { + opts.Prefix = prefix + } + if len(marker) > 0 { + opts.Marker = marker + } + if len(delimiter) > 0 { + opts.Delimiter = delimiter + } + if maxCount > 0 { + opts.MaxKeys = maxCount + } + oResult, _, err := coscli.Bucket.Get(context.Background(), opts) + if err != nil { + return result, errors.Wrap(err, "coscli.Bucket.Get") + } + result.Objects = make([]cloudprovider.ICloudObject, 0) + for _, object := range oResult.Contents { + lastModified, _ := timeutils.ParseTimeStr(object.LastModified) + obj := &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + StorageClass: string(object.StorageClass), + Key: object.Key, + SizeBytes: int64(object.Size), + ETag: object.ETag, + LastModified: lastModified, + }, + } + result.Objects = append(result.Objects, obj) + } + if oResult.CommonPrefixes != nil { + result.CommonPrefixes = make([]cloudprovider.ICloudObject, 0) + for _, commPrefix := range oResult.CommonPrefixes { + obj := &SObject{ + bucket: b, + SBaseCloudObject: cloudprovider.SBaseCloudObject{ + Key: commPrefix, + }, + } + result.CommonPrefixes = append(result.CommonPrefixes, obj) + } + } + result.IsTruncated = oResult.IsTruncated + result.NextMarker = oResult.NextMarker + return result, nil +} + +func (b *SBucket) PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrap(err, "GetCosClient") + } + opts := &cos.ObjectPutOptions{ + ACLHeaderOptions: &cos.ACLHeaderOptions{}, + ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{}, + } + if sizeBytes > 0 { + opts.ContentLength = sizeBytes + } + if meta != nil { + extraHdr := http.Header{} + for k, v := range meta { + if len(v) == 0 || len(v[0]) == 0 { + continue + } + switch http.CanonicalHeaderKey(k) { + case cloudprovider.META_HEADER_CACHE_CONTROL: + opts.CacheControl = v[0] + case cloudprovider.META_HEADER_CONTENT_TYPE: + opts.ContentType = v[0] + case cloudprovider.META_HEADER_CONTENT_MD5: + opts.ContentMD5 = v[0] + case cloudprovider.META_HEADER_CONTENT_ENCODING: + opts.ContentEncoding = v[0] + case cloudprovider.META_HEADER_CONTENT_DISPOSITION: + opts.ContentDisposition = v[0] + default: + extraHdr.Add(fmt.Sprintf("%s%s", COS_META_HEADER, k), v[0]) + } + } + if len(extraHdr) > 0 { + opts.XCosMetaXXX = &extraHdr + } + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + opts.XCosACL = string(cannedAcl) + if len(storageClassStr) > 0 { + opts.XCosStorageClass = storageClassStr + } + _, err = coscli.Object.Put(ctx, key, reader, opts) + if err != nil { + return errors.Wrap(err, "coscli.Object.Put") + } + return nil +} + +func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return "", errors.Wrap(err, "GetCosClient") + } + opts := &cos.InitiateMultipartUploadOptions{ + ACLHeaderOptions: &cos.ACLHeaderOptions{}, + ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{}, + } + if meta != nil { + extraHdr := http.Header{} + for k, v := range meta { + if len(v) == 0 || len(v[0]) == 0 { + continue + } + switch http.CanonicalHeaderKey(k) { + case cloudprovider.META_HEADER_CACHE_CONTROL: + opts.CacheControl = v[0] + case cloudprovider.META_HEADER_CONTENT_TYPE: + opts.ContentType = v[0] + case cloudprovider.META_HEADER_CONTENT_MD5: + opts.ContentMD5 = v[0] + case cloudprovider.META_HEADER_CONTENT_ENCODING: + opts.ContentEncoding = v[0] + case cloudprovider.META_HEADER_CONTENT_DISPOSITION: + opts.ContentDisposition = v[0] + default: + extraHdr.Add(fmt.Sprintf("%s%s", COS_META_HEADER, k), v[0]) + } + } + if len(extraHdr) > 0 { + opts.XCosMetaXXX = &extraHdr + } + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + opts.XCosACL = string(cannedAcl) + if len(storageClassStr) > 0 { + opts.XCosStorageClass = storageClassStr + } + result, _, err := coscli.Object.InitiateMultipartUpload(ctx, key, opts) + if err != nil { + return "", errors.Wrap(err, "InitiateMultipartUpload") + } + + return result.UploadID, nil +} + +func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return "", errors.Wrap(err, "GetCosClient") + } + opts := &cos.ObjectUploadPartOptions{} + opts.ContentLength = partSize + resp, err := coscli.Object.UploadPart(ctx, key, uploadId, partIndex, input, opts) + if err != nil { + return "", errors.Wrap(err, "UploadPart") + } + + return resp.Header.Get("Etag"), nil +} + +func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrap(err, "GetCosClient") + } + opts := &cos.CompleteMultipartUploadOptions{} + parts := make([]cos.Object, len(partEtags)) + for i := range partEtags { + parts[i] = cos.Object{ + PartNumber: i + 1, + ETag: partEtags[i], + } + } + opts.Parts = parts + _, _, err = coscli.Object.CompleteMultipartUpload(ctx, key, uploadId, opts) + + if err != nil { + return errors.Wrap(err, "CompleteMultipartUpload") + } + + return nil +} + +func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrap(err, "GetCosClient") + } + + _, err = coscli.Object.AbortMultipartUpload(ctx, key, uploadId) + if err != nil { + return errors.Wrap(err, "AbortMultipartUpload") + } + + return nil +} + +func (b *SBucket) DeleteObject(ctx context.Context, key string) error { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrap(err, "GetCosClient") + } + _, err = coscli.Object.Delete(ctx, key) + if err != nil { + return errors.Wrap(err, "coscli.Object.Delete") + } + return nil +} + +func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { + if method != "GET" && method != "PUT" && method != "DELETE" { + return "", errors.Error("unsupported method") + } + coscli, err := b.region.GetCosClient(b) + if err != nil { + return "", errors.Wrap(err, "GetCosClient") + } + url, err := coscli.Object.GetPresignedURL(context.Background(), method, key, + b.region.client.secretId, + b.region.client.secretKey, + expire, nil) + if err != nil { + return "", errors.Wrap(err, "coscli.Object.GetPresignedURL") + } + return url.String(), nil +} + +func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucketName, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrap(err, "GetCosClient") + } + opts := &cos.ObjectCopyOptions{ + ObjectCopyHeaderOptions: &cos.ObjectCopyHeaderOptions{}, + ACLHeaderOptions: &cos.ACLHeaderOptions{}, + } + if len(cannedAcl) == 0 { + cannedAcl = b.GetAcl() + } + opts.XCosACL = string(cannedAcl) + if len(storageClassStr) > 0 { + opts.XCosStorageClass = storageClassStr + } + if meta != nil { + opts.XCosMetadataDirective = "Replaced" + extraHdr := http.Header{} + for k, v := range meta { + if len(v) == 0 || len(v[0]) == 0 { + continue + } + switch http.CanonicalHeaderKey(k) { + case cloudprovider.META_HEADER_CACHE_CONTROL: + opts.CacheControl = v[0] + case cloudprovider.META_HEADER_CONTENT_TYPE: + opts.ContentType = v[0] + case cloudprovider.META_HEADER_CONTENT_ENCODING: + opts.ContentEncoding = v[0] + case cloudprovider.META_HEADER_CONTENT_DISPOSITION: + opts.ContentDisposition = v[0] + default: + extraHdr.Add(fmt.Sprintf("%s%s", COS_META_HEADER, k), v[0]) + } + } + if len(extraHdr) > 0 { + opts.XCosMetaXXX = &extraHdr + } + } else { + opts.XCosMetadataDirective = "Copy" + } + srcBucket := SBucket{ + region: b.region, + Name: srcBucketName, + } + srcUrl := fmt.Sprintf("%s/%s", srcBucket.getBucketUrlHost(), srcKey) + _, _, err = coscli.Object.Copy(ctx, destKey, srcUrl, opts) + if err != nil { + return errors.Wrap(err, "coscli.Object.Copy") + } + return nil +} + +func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return nil, errors.Wrap(err, "GetCosClient") + } + opts := &cos.ObjectGetOptions{} + if rangeOpt != nil { + opts.Range = rangeOpt.String() + } + resp, err := coscli.Object.Get(ctx, key, opts) + if err != nil { + return nil, errors.Wrap(err, "coscli.Object.Get") + } + return resp.Body, nil +} + +func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucketName string, srcKey string, srcOffset int64, srcLength int64) (string, error) { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return "", errors.Wrap(err, "GetCosClient") + } + srcBucket := SBucket{ + region: b.region, + Name: srcBucketName, + } + opts := cos.ObjectCopyPartOptions{} + srcUrl := fmt.Sprintf("%s/%s", srcBucket.getBucketUrlHost(), srcKey) + opts.XCosCopySourceRange = fmt.Sprintf("bytes=%d-%d", srcOffset, srcOffset+srcLength-1) + result, _, err := coscli.Object.CopyPart(ctx, key, uploadId, partIndex, srcUrl, &opts) + if err != nil { + return "", errors.Wrap(err, "coscli.Object.CopyPart") + } + return result.ETag, nil +} + +func (b *SBucket) SetWebsite(websitConf cloudprovider.SBucketWebsiteConf) error { + if len(websitConf.Index) == 0 { + return errors.Wrap(cloudprovider.ErrNotSupported, "missing Index") + } + if len(websitConf.ErrorDocument) == 0 { + return errors.Wrap(cloudprovider.ErrNotSupported, "missing ErrorDocument") + } + if websitConf.Protocol != "http" && websitConf.Protocol != "https" { + return errors.Wrap(cloudprovider.ErrNotSupported, "missing Protocol") + } + + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrap(err, "b.region.GetCosClient") + } + + rulesOpts := []cos.WebsiteRoutingRule{} + for i := range websitConf.Rules { + rulesOpts = append(rulesOpts, cos.WebsiteRoutingRule{ + ConditionErrorCode: websitConf.Rules[i].ConditionErrorCode, + ConditionPrefix: websitConf.Rules[i].ConditionPrefix, + + RedirectProtocol: websitConf.Rules[i].RedirectProtocol, + RedirectReplaceKey: websitConf.Rules[i].RedirectReplaceKey, + RedirectReplaceKeyPrefix: websitConf.Rules[i].ConditionPrefix, + }) + } + opts := &cos.BucketPutWebsiteOptions{ + Index: websitConf.Index, + Error: &cos.ErrorDocument{Key: websitConf.ErrorDocument}, + RedirectProtocol: &cos.RedirectRequestsProtocol{Protocol: websitConf.Protocol}, + } + if len(rulesOpts) > 0 { + opts.RoutingRules = &cos.WebsiteRoutingRules{Rules: rulesOpts} + } + + _, err = coscli.Bucket.PutWebsite(context.Background(), opts) + if err != nil { + return errors.Wrap(err, "PutWebsite") + } + return nil +} + +func (b *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return cloudprovider.SBucketWebsiteConf{}, errors.Wrap(err, "b.region.GetCosClient") + } + websiteResult, _, err := coscli.Bucket.GetWebsite(context.Background()) + if err != nil { + if strings.Contains(err.Error(), "NoSuchWebsiteConfiguration") { + return cloudprovider.SBucketWebsiteConf{}, nil + } + return cloudprovider.SBucketWebsiteConf{}, errors.Wrap(err, "coscli.Bucket.GetWebsite") + } + + result := cloudprovider.SBucketWebsiteConf{ + Index: websiteResult.Index, + } + if websiteResult.Error != nil { + result.ErrorDocument = websiteResult.Error.Key + } + if websiteResult.RedirectProtocol != nil { + result.Protocol = websiteResult.RedirectProtocol.Protocol + } + routingRules := []cloudprovider.SBucketWebsiteRoutingRule{} + if websiteResult.RoutingRules != nil { + for i := range websiteResult.RoutingRules.Rules { + routingRules = append(routingRules, cloudprovider.SBucketWebsiteRoutingRule{ + ConditionErrorCode: websiteResult.RoutingRules.Rules[i].ConditionErrorCode, + ConditionPrefix: websiteResult.RoutingRules.Rules[i].ConditionPrefix, + + RedirectProtocol: websiteResult.RoutingRules.Rules[i].RedirectProtocol, + RedirectReplaceKey: websiteResult.RoutingRules.Rules[i].RedirectReplaceKey, + RedirectReplaceKeyPrefix: websiteResult.RoutingRules.Rules[i].RedirectReplaceKeyPrefix, + }) + } + } + result.Rules = routingRules + result.Url = b.getWebsiteUrl() + return result, nil +} + +func (b *SBucket) DeleteWebSiteConf() error { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrap(err, "b.region.GetCosClient") + } + _, err = coscli.Bucket.DeleteWebsite(context.Background()) + if err != nil { + return errors.Wrap(err, "coscli.Bucket.DeleteWebsite") + } + return nil +} + +func (b *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { + if len(rules) == 0 { + return nil + } + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrap(err, "b.region.GetCosClient") + } + input := cos.BucketPutCORSOptions{} + for i := range rules { + input.Rules = append(input.Rules, cos.BucketCORSRule{ + AllowedOrigins: rules[i].AllowedOrigins, + AllowedMethods: rules[i].AllowedMethods, + AllowedHeaders: rules[i].AllowedHeaders, + MaxAgeSeconds: rules[i].MaxAgeSeconds, + ExposeHeaders: rules[i].ExposeHeaders, + ID: rules[i].Id, + }) + } + + _, err = coscli.Bucket.PutCORS(context.Background(), &input) + if err != nil { + return errors.Wrap(err, "coscli.Bucket.PutCORS") + } + return nil +} + +func (b *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return nil, errors.Wrap(err, "b.region.GetCosClient") + } + conf, _, err := coscli.Bucket.GetCORS(context.Background()) + if err != nil { + if strings.Contains(err.Error(), "NoSuchCORSConfiguration") { + return nil, nil + } + return nil, errors.Wrap(err, "b.region.GetCORS") + } + result := []cloudprovider.SBucketCORSRule{} + for i := range conf.Rules { + result = append(result, cloudprovider.SBucketCORSRule{ + AllowedOrigins: conf.Rules[i].AllowedOrigins, + AllowedMethods: conf.Rules[i].AllowedMethods, + AllowedHeaders: conf.Rules[i].AllowedHeaders, + MaxAgeSeconds: conf.Rules[i].MaxAgeSeconds, + ExposeHeaders: conf.Rules[i].ExposeHeaders, + Id: strconv.Itoa(i), + }) + } + return result, nil +} + +func (b *SBucket) DeleteCORS() error { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrap(err, "b.region.GetCosClient") + } + _, err = coscli.Bucket.DeleteCORS(context.Background()) + if err != nil { + return errors.Wrap(err, "coscli.Bucket.DeleteCORS") + } + return nil +} + +func (b *SBucket) SetReferer(conf cloudprovider.SBucketRefererConf) error { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrap(err, "b.region.GetCosClient") + } + + if !conf.Enabled { + _, err = coscli.Bucket.PutReferer(context.Background(), nil) + return errors.Wrap(err, "Disable Refer") + } + + opts := cos.BucketPutRefererOptions{ + Status: "Enabled", + EmptyReferConfiguration: "Deny", + RefererType: conf.RefererType, + DomainList: conf.DomainList, + } + + if conf.AllowEmptyRefer { + opts.EmptyReferConfiguration = "Allow" + } + + _, err = coscli.Bucket.PutReferer(context.Background(), &opts) + if err != nil { + return errors.Wrap(err, "coscli.Bucket.PutReferer") + } + return nil +} +func (b *SBucket) GetReferer() (cloudprovider.SBucketRefererConf, error) { + result := cloudprovider.SBucketRefererConf{} + coscli, err := b.region.GetCosClient(b) + if err != nil { + return result, errors.Wrap(err, "b.region.GetCosClient") + } + + referResult, _, err := coscli.Bucket.GetReferer(context.Background()) + if err != nil { + return result, errors.Wrap(err, " coscli.Bucket.GetReferer") + } + + result.AllowEmptyRefer = (referResult.EmptyReferConfiguration == "Allow") + result.Enabled = (referResult.Status == "Enabled") + result.RefererType = referResult.RefererType + result.DomainList = referResult.DomainList + + return result, nil +} + +func toAPICdnArea(area string) string { + switch area { + case "mainland": + return api.CDN_DOMAIN_AREA_MAINLAND + case "overseas": + return api.CDN_DOMAIN_AREA_OVERSEAS + case "global": + return api.CDN_DOMAIN_AREA_GLOBAL + default: + return "" + } +} +func toAPICdnStatus(status string) string { + switch status { + case "online": + return api.CDN_DOMAIN_STATUS_ONLINE + case "offline": + return api.CDN_DOMAIN_STATUS_OFFLINE + case "processing": + return api.CDN_DOMAIN_STATUS_PROCESSING + case "rejected": + return api.CDN_DOMAIN_STATUS_REJECTED + default: + return "" + } +} + +func (b *SBucket) GetCdnDomains() ([]cloudprovider.SCdnDomain, error) { + result := []cloudprovider.SCdnDomain{} + bucketHost := b.getBucketUrlHost() + bucketWebsiteHost := b.getBucketWebsiteUrlHost() + + bucketCdnDomains, err := b.region.client.DescribeAllCdnDomains(nil, []string{bucketHost}, "cos") + if err != nil { + return nil, errors.Wrapf(err, `b.region.client.DescribeAllCdnDomains(nil, []string{%s}, "cos")`, bucketHost) + } + + for i := range bucketCdnDomains { + result = append(result, cloudprovider.SCdnDomain{ + Domain: bucketCdnDomains[i].Domain, + Status: toAPICdnStatus(bucketCdnDomains[i].Status), + Cname: bucketCdnDomains[i].Cname, + Area: toAPICdnArea(bucketCdnDomains[i].Area), + Origin: bucketHost, + OriginType: api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET, + }) + } + + bucketWebsiteCdnDomains, err := b.region.client.DescribeAllCdnDomains(nil, []string{bucketWebsiteHost}, "cos") + if err != nil { + return nil, errors.Wrapf(err, `b.region.client.DescribeAllCdnDomains(nil, []string{%s}, "cos")`, bucketWebsiteHost) + } + + for i := range bucketWebsiteCdnDomains { + result = append(result, cloudprovider.SCdnDomain{ + Domain: bucketWebsiteCdnDomains[i].Domain, + Status: toAPICdnStatus(bucketWebsiteCdnDomains[i].Status), + Cname: bucketWebsiteCdnDomains[i].Cname, + Area: toAPICdnArea(bucketWebsiteCdnDomains[i].Area), + Origin: bucketWebsiteHost, + OriginType: api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET, + }) + } + return result, nil +} + +func getQcsResourcePath(resource []string) []string { + path := []string{} + for i := range resource { + strs := strings.Split(resource[i], ":") + path = append(path, strs[len(strs)-1]) + } + return path +} + +func getQcsUserId(principal []string) []string { + ids := []string{} + for i := range principal { + // qcs::cam::uin/100008182714:uin/100008182714 + // qcs::cam::uin/100008182714:service/cdn + // qcs::cam::anyone:anyone + + strs := strings.Split(principal[i], "::") + ids = append(ids, strings.Replace(strs[len(strs)-1], "uin/", "", 2)) + } + + return ids +} + +var cannedReadActions = [...]string{ + "name/cos:GetBucket", + "name/cos:GetBucketObjectVersions", + "name/cos:HeadBucket", + "name/cos:ListMultipartUploads", + "name/cos:ListParts", + "name/cos:GetObject", + "name/cos:HeadObject", + "name/cos:OptionsObject", +} + +var cannedReadWriteActions = [...]string{ + "name/cos:GetBucket", + "name/cos:GetBucketObjectVersions", + "name/cos:HeadBucket", + "name/cos:ListMultipartUploads", + "name/cos:ListParts", + "name/cos:GetObject", + "name/cos:HeadObject", + "name/cos:OptionsObject", + + "name/cos:PutObject", + "name/cos:PostObject", + "name/cos:DeleteObject", + "name/cos:InitiateMultipartUpload", + "name/cos:UploadPart", + "name/cos:CompleteMultipartUpload", + "name/cos:AbortMultipartUpload", +} + +func getCannedAction(action []string) string { + cannedAction := "" + + actionSet := set.New(set.NonThreadSafe) + for i := range action { + actionSet.Add(action[i]) + } + if actionSet.Has("name/cos:*") { + return "FullControl" + } + + readSet := set.New(set.NonThreadSafe) + for i := range cannedReadActions { + readSet.Add(cannedReadActions[i]) + } + if set.Difference(readSet, actionSet).Size() == 0 { + cannedAction = "Read" + } + + readWriteSet := set.New(set.NonThreadSafe) + for i := range cannedReadWriteActions { + readWriteSet.Add(cannedReadWriteActions[i]) + } + if set.Difference(readWriteSet, actionSet).Size() == 0 { + cannedAction = "ReadWrite" + } + return cannedAction +} + +func (b *SBucket) GetPolicy() ([]cloudprovider.SBucketPolicyStatement, error) { + policyOptions := []cloudprovider.SBucketPolicyStatement{} + coscli, err := b.region.GetCosClient(b) + if err != nil { + return nil, errors.Wrap(err, "GetCosClient") + } + result, _, err := coscli.Bucket.GetPolicy(context.Background()) + if err != nil { + if strings.Contains(err.Error(), "404") { + return nil, nil + } + return nil, errors.Wrap(err, "GetPolicy") + } + + users, err := b.region.client.GetICloudusers() + if err != nil { + return nil, errors.Wrapf(err, "GetICloudusers") + } + + userMaps := map[string]string{} + for i := range users { + userMaps[fmt.Sprintf("%s:%s", b.region.client.ownerName, users[i].GetGlobalId())] = users[i].GetName() + } + + for i := range result.Statement { + policyOption := cloudprovider.SBucketPolicyStatement{ + Principal: result.Statement[i].Principal, + Action: result.Statement[i].Action, + Effect: result.Statement[i].Effect, + Resource: result.Statement[i].Resource, + Condition: result.Statement[i].Condition, + + PrincipalId: getQcsUserId(result.Statement[i].Principal["qcs"]), + CannedAction: getCannedAction(result.Statement[i].Action), + ResourcePath: getQcsResourcePath(result.Statement[i].Resource), + Id: strconv.Itoa(i), + } + policyOption.PrincipalNames = func() map[string]string { + ret := map[string]string{} + for _, id := range policyOption.PrincipalId { + ret[id], _ = userMaps[id] + } + return ret + }() + policyOptions = append(policyOptions, policyOption) + } + return policyOptions, nil +} + +func (b *SBucket) SetPolicy(policy cloudprovider.SBucketPolicyStatementInput) error { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrapf(err, "GetCosClient") + } + opts := cos.BucketPutPolicyOptions{} + opts.Version = "2.0" + oldOpts, _, err := coscli.Bucket.GetPolicy(context.Background()) + if err != nil { + if !strings.Contains(err.Error(), "404") { + return errors.Wrap(err, "GetPolicy") + } + } + if len(oldOpts.Statement) > 0 { + opts.Statement = oldOpts.Statement + } + newStatement := cos.BucketStatement{} + ids := []string{} + for i := range policy.PrincipalId { + id := strings.Split(policy.PrincipalId[i], ":") + if len(id) == 1 { + ids = append(ids, fmt.Sprintf("qcs::cam::uin/%s:uin/%s", id[0], id[0])) + } + if len(id) == 2 { + // 没有主账号id,设为owner id + if len(id[0]) == 0 { + s, _, err := coscli.Service.Get(context.Background()) + if err != nil { + return errors.Wrap(err, "coscli.Service.Get") + } + id[0] = s.Owner.DisplayName + } + // 没有子账号,默认和主账号相同 + if len(id[1]) == 0 { + id[1] = id[0] + } + ids = append(ids, fmt.Sprintf("qcs::cam::uin/%s:uin/%s", id[0], id[1])) + } + if len(id) > 2 { + return errors.Wrap(cloudprovider.ErrNotSupported, "Invalida PrincipalId Input") + } + } + principal := map[string][]string{} + principal["qcs"] = ids + newStatement.Principal = principal + newStatement.Effect = policy.Effect + resources := []string{} + for i := range policy.ResourcePath { + resources = append(resources, fmt.Sprintf("qcs::cos:%s:uid/%s:%s%s", b.GetIRegion().GetId(), b.appId, b.getFullName(), policy.ResourcePath[i])) + } + newStatement.Resource = resources + ipEqual := []string{} + ipNotEqual := []string{} + for i := range policy.IpEquals { + ipEqual = append(ipEqual, policy.IpEquals[i]) + } + for i := range policy.IpNotEquals { + ipNotEqual = append(ipNotEqual, policy.IpNotEquals[i]) + } + condition := map[string]map[string]interface{}{} + newStatement.Condition = condition + if len(ipEqual) > 0 { + newStatement.Condition["ip_equal"] = map[string]interface{}{"qcs:ip": ipEqual} + } + if len(ipNotEqual) > 0 { + newStatement.Condition["ip_not_equal"] = map[string]interface{}{"qcs:ip": ipNotEqual} + } + + if policy.CannedAction == "FullControl" { + newStatement.Action = []string{"name/cos:*"} + } + if policy.CannedAction == "Read" { + newStatement.Action = cannedReadActions[:] + } + if policy.CannedAction == "ReadWrite" { + newStatement.Action = cannedReadWriteActions[:] + } + opts.Statement = append([]cos.BucketStatement{newStatement}, opts.Statement...) + + _, err = coscli.Bucket.PutPolicy(context.Background(), &opts) + if err != nil { + log.Errorf("coscli.Bucket.GetACL fail %s", err) + return errors.Wrapf(err, " coscli.Bucket.PutPolicy(context.Background(), %s)", jsonutils.Marshal(opts).String()) + } + return nil +} + +func (b *SBucket) DeletePolicy(id []string) ([]cloudprovider.SBucketPolicyStatement, error) { + deletedPolicy := []cloudprovider.SBucketPolicyStatement{} + coscli, err := b.region.GetCosClient(b) + if err != nil { + log.Errorf("GetCosClient fail %s", err) + return nil, errors.Wrap(err, "b.region.GetCosClient(b)") + } + result, _, err := coscli.Bucket.GetPolicy(context.Background()) + if err != nil { + if strings.Contains(err.Error(), "404") { + return nil, nil + } + log.Errorf("coscli.Bucket.GetACL fail %s", err) + return nil, errors.Wrap(err, "coscli.Bucket.GetPolicy(context.Background())") + } + newOpts := cos.BucketPutPolicyOptions{} + newOpts.Version = result.Version + newOpts.Principal = result.Principal + excludeMap := map[int]bool{} + for i := range id { + index, err := strconv.Atoi(id[i]) + if err == nil { + excludeMap[index] = true + } + } + for i := range result.Statement { + if _, ok := excludeMap[i]; !ok { + newOpts.Statement = append(newOpts.Statement, result.Statement[i]) + } else { + deletedPolicy = append(deletedPolicy, cloudprovider.SBucketPolicyStatement{ + Principal: result.Statement[i].Principal, + Action: result.Statement[i].Action, + Effect: result.Statement[i].Effect, + Resource: result.Statement[i].Resource, + Condition: result.Statement[i].Condition, + + PrincipalId: getQcsUserId(result.Statement[i].Principal["qcs"]), + CannedAction: getCannedAction(result.Statement[i].Action), + ResourcePath: getQcsResourcePath(result.Statement[i].Resource), + }) + } + } + + if len(newOpts.Statement) == 0 { + _, err := coscli.Bucket.DeletePolicy(context.Background()) + if err != nil { + log.Errorf("coscli.Bucket.DeletePolicy fail %s", err) + return nil, errors.Wrap(err, "coscli.Bucket.DeletePolicy(context.Background())") + } + return deletedPolicy, nil + } + + _, err = coscli.Bucket.PutPolicy(context.Background(), &newOpts) + if err != nil { + log.Errorf("coscli.Bucket.GetACL fail %s", err) + return nil, errors.Wrapf(err, "coscli.Bucket.PutPolicy(context.Background(), %s)", jsonutils.Marshal(newOpts).String()) + } + return deletedPolicy, nil +} + +func (b *SBucket) GetTags() (map[string]string, error) { + coscli, err := b.region.GetCosClient(b) + if err != nil { + return nil, errors.Wrap(err, "GetCosClient") + } + + tagresult, _, err := coscli.Bucket.GetTagging(context.Background()) + if err != nil { + if strings.Contains(err.Error(), "404") { + return nil, nil + } + return nil, errors.Wrap(err, "GetTagging") + } + result := map[string]string{} + for i := range tagresult.TagSet { + result[tagresult.TagSet[i].Key] = tagresult.TagSet[i].Value + } + return result, nil +} + +func (b *SBucket) SetTags(tags map[string]string, replace bool) error { + if !replace { + return cloudprovider.ErrNotSupported + } + coscli, err := b.region.GetCosClient(b) + if err != nil { + return errors.Wrapf(err, "b.region.GetCosClient(%s)", b.Name) + } + + _, err = coscli.Bucket.DeleteTagging(context.Background()) + if err != nil { + return errors.Wrapf(err, "DeleteTagging") + } + + if len(tags) == 0 { + return nil + } + + input := cos.BucketPutTaggingOptions{} + for k, v := range tags { + input.TagSet = append(input.TagSet, cos.BucketTaggingTag{Key: k, Value: v}) + } + + _, err = coscli.Bucket.PutTagging(context.Background(), &input) + if err != nil { + return errors.Wrapf(err, "coscli.Bucket.PutTagging(%s)", jsonutils.Marshal(input)) + } + return nil +} + +func (b *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { + coscli, err := b.region.GetCosClient(b) + if err != nil { + log.Errorf("GetCosClient fail %s", err) + return nil, errors.Wrap(err, "b.region.GetCosClient(b)") + } + result := []cloudprovider.SBucketMultipartUploads{} + input := cos.ListMultipartUploadsOptions{} + keyMarker := "" + uploadIDMarker := "" + for { + input.KeyMarker = keyMarker + input.UploadIDMarker = uploadIDMarker + output, _, err := coscli.Bucket.ListMultipartUploads(context.Background(), &input) + if err != nil { + return nil, errors.Wrap(err, " coscli.Bucket.ListMultipartUploads(context.Background(), &input)") + } + for i := range output.Uploads { + temp := cloudprovider.SBucketMultipartUploads{ + ObjectName: output.Uploads[i].Key, + UploadID: output.Uploads[i].UploadID, + Initiator: output.Uploads[i].Initiator.DisplayName, + } + temp.Initiated, _ = timeutils.ParseTimeStr(output.Uploads[i].Initiated) + result = append(result, temp) + } + keyMarker = output.NextKeyMarker + uploadIDMarker = output.NextUploadIDMarker + if !output.IsTruncated { + break + } + } + + return result, nil +} diff --git a/pkg/multicloud/qcloud/cam_collaborator.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_collaborator.go similarity index 100% rename from pkg/multicloud/qcloud/cam_collaborator.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_collaborator.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_group.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_group.go new file mode 100644 index 0000000000..d188781d29 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_group.go @@ -0,0 +1,385 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "time" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SGroup struct { + client *SQcloudClient + + GroupId int + GroupName string + CreateTime time.Time +} + +func (self *SGroup) GetName() string { + return self.GroupName +} + +func (self *SGroup) GetGlobalId() string { + return self.GroupName +} + +func (self *SGroup) GetDescription() string { + return "" +} + +func (self *SGroup) GetICloudusers() ([]cloudprovider.IClouduser, error) { + users := []SUser{} + offset := 1 + for { + part, total, err := self.client.ListGroupUsers(self.GroupId, offset, 100) + if err != nil { + return nil, errors.Wrapf(err, "ListGroupUsers") + } + users = append(users, part...) + if len(users) >= total { + break + } + offset += 1 + } + ret := []cloudprovider.IClouduser{} + for i := range users { + users[i].client = self.client + ret = append(ret, &users[i]) + } + return ret, nil +} + +func (self *SGroup) AddUser(name string) error { + user, err := self.client.GetUser(name) + if err != nil { + return errors.Wrapf(err, "GetUser(%s)", name) + } + return self.client.AddUserToGroup(self.GroupId, int(user.Uid)) +} + +func (self *SGroup) RemoveUser(name string) error { + user, err := self.client.GetUser(name) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return errors.Wrapf(err, "GetUser(%s)", name) + } + return self.client.RemoveUserFromGroup(self.GroupId, int(user.Uid)) +} + +func (self *SGroup) AttachSystemPolicy(policyId string) error { + return self.client.AttachGroupPolicy(self.GroupId, policyId) +} + +func (self *SGroup) AttachCustomPolicy(policyId string) error { + return self.client.AttachGroupPolicy(self.GroupId, policyId) +} + +func (self *SGroup) DetachSystemPolicy(policyId string) error { + return self.client.DetachGroupPolicy(self.GroupId, policyId) +} + +func (self *SGroup) DetachCustomPolicy(policyId string) error { + return self.client.DetachGroupPolicy(self.GroupId, policyId) +} + +func (self *SGroup) ListGroupPolicies() ([]SPolicy, error) { + policies := []SPolicy{} + offset := 1 + for { + part, total, err := self.client.ListAttachedGroupPolicies(self.GroupId, offset, 200) + if err != nil { + return nil, errors.Wrapf(err, "ListAttachedGroupPolicies") + } + policies = append(policies, part...) + if len(policies) >= total { + break + } + offset += 1 + } + return policies, nil +} + +func (self *SGroup) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := self.ListGroupPolicies() + if err != nil { + return nil, errors.Wrapf(err, "ListGroupPolicies") + } + ret := []cloudprovider.ICloudpolicy{} + customPolicyMaps, err := self.client.GetCustomPolicyMaps() + if err != nil { + return nil, errors.Wrap(err, "GetCustomPolicyIds") + } + for i := range policies { + _, ok := customPolicyMaps[policies[i].PolicyName] + if ok { + policies[i].client = self.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (self *SQcloudClient) GetCustomPolicyMaps() (map[string]int64, error) { + policyMaps := map[string]int64{} + offset := 1 + for { + part, total, err := self.ListPolicies("", "Local", offset, 50) + if err != nil { + return nil, errors.Wrap(err, "ListPolicies") + } + for _, policy := range part { + policyMaps[policy.PolicyName] = policy.PolicyId + } + if len(policyMaps) >= total { + break + } + offset += 1 + } + return policyMaps, nil +} + +func (self *SGroup) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies, err := self.ListGroupPolicies() + if err != nil { + return nil, errors.Wrapf(err, "ListGroupPolicies") + } + ret := []cloudprovider.ICloudpolicy{} + customPolicyMaps, err := self.client.GetCustomPolicyMaps() + if err != nil { + return nil, errors.Wrap(err, "GetCustomPolicyIds") + } + for i := range policies { + _, ok := customPolicyMaps[policies[i].PolicyName] + if !ok { + policies[i].client = self.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (self *SGroup) Delete() error { + return self.client.DeleteGroup(self.GroupId) +} + +func (self *SQcloudClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + ret := []cloudprovider.ICloudgroup{} + offset := 1 + for { + part, total, err := self.ListGroups("", offset, 50) + if err != nil { + return nil, errors.Wrapf(err, "DescribeRoleList") + } + for i := range part { + part[i].client = self + ret = append(ret, &part[i]) + } + if total >= len(ret) { + break + } + offset += 1 + } + return ret, nil +} + +func (self *SQcloudClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + group, err := self.CreateGroup(name, desc) + if err != nil { + return nil, errors.Wrapf(err, "CreateGroup") + } + return group, nil +} + +func (self *SQcloudClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + groups := []SGroup{} + offset := 1 + for { + part, total, err := self.ListGroups(name, offset, 50) + if err != nil { + return nil, errors.Wrapf(err, "ListGroups") + } + groups = append(groups, part...) + if len(groups) >= total { + break + } + offset += 1 + } + for i := range groups { + if groups[i].GroupName == name { + groups[i].client = self + return &groups[i], nil + } + } + return nil, errors.Wrap(cloudprovider.ErrNotFound, name) +} + +func (self *SQcloudClient) ListGroups(keyword string, offset int, limit int) ([]SGroup, int, error) { + if offset < 1 { + offset = 1 + } + if limit <= 0 || limit > 50 { + limit = 50 + } + params := map[string]string{ + "Page": fmt.Sprintf("%d", offset), + "Rp": fmt.Sprintf("%d", limit), + } + if len(keyword) > 0 { + params["Keyword"] = keyword + } + + resp, err := self.camRequest("ListGroups", params) + if err != nil { + return nil, 0, errors.Wrap(err, "camRequest.ListGroups") + } + groups := []SGroup{} + err = resp.Unmarshal(&groups, "GroupInfo") + if err != nil { + return nil, 0, errors.Wrap(err, "resp.Unmarshal") + } + total, _ := resp.Float("TotalNum") + return groups, int(total), nil +} + +func (self *SQcloudClient) CreateGroup(name string, remark string) (*SGroup, error) { + params := map[string]string{ + "GroupName": name, + } + if len(remark) > 0 { + params["Remark"] = remark + } + resp, err := self.camRequest("CreateGroup", params) + if err != nil { + return nil, errors.Wrap(err, "camRequest.CreateGroup") + } + groupId, _ := resp.Float("GroupId") + return self.GetGroup(int(groupId)) +} + +func (self *SQcloudClient) GetGroup(groupId int) (*SGroup, error) { + params := map[string]string{ + "GroupId": fmt.Sprintf("%d", groupId), + } + resp, err := self.camRequest("GetGroup", params) + if err != nil { + return nil, errors.Wrap(err, "camRequest.GetGroup") + } + group := &SGroup{client: self} + err = resp.Unmarshal(group) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return group, nil +} + +func (self *SQcloudClient) DeleteGroup(id int) error { + params := map[string]string{ + "GroupId": fmt.Sprintf("%d", id), + } + _, err := self.camRequest("DeleteGroup", params) + return err +} + +func (self *SQcloudClient) ListAttachedGroupPolicies(groupId int, offset int, limit int) ([]SPolicy, int, error) { + if offset < 1 { + offset = 1 + } + if limit <= 0 || limit > 50 { + limit = 50 + } + params := map[string]string{ + "TargetGroupId": fmt.Sprintf("%d", groupId), + "Page": fmt.Sprintf("%d", offset), + "Rp": fmt.Sprintf("%d", limit), + } + resp, err := self.camRequest("ListAttachedGroupPolicies", params) + if err != nil { + return nil, 0, errors.Wrap(err, "iamRequest.ListAttachedGroupPolicies") + } + policies := []SPolicy{} + err = resp.Unmarshal(&policies, "List") + if err != nil { + return nil, 0, errors.Wrap(err, "resp.Unmarshal") + } + total, _ := resp.Float("TotalNum") + return policies, int(total), nil +} + +func (self *SQcloudClient) ListGroupUsers(groupId int, offset int, limit int) ([]SUser, int, error) { + if offset < 1 { + offset = 1 + } + if limit <= 0 || limit > 50 { + limit = 50 + } + params := map[string]string{ + "GroupId": fmt.Sprintf("%d", groupId), + "Page": fmt.Sprintf("%d", offset), + "Rp": fmt.Sprintf("%d", limit), + } + resp, err := self.camRequest("ListUsersForGroup", params) + if err != nil { + return nil, 0, errors.Wrap(err, "iamRequest.ListUserForGroup") + } + users := []SUser{} + err = resp.Unmarshal(&users, "UserInfo") + if err != nil { + return nil, 0, errors.Wrap(err, "resp.Unmarshal") + } + total, _ := resp.Float("TotalNum") + return users, int(total), nil +} + +func (self *SQcloudClient) RemoveUserFromGroup(groupId, userId int) error { + params := map[string]string{ + "Info.0.Uid": fmt.Sprintf("%d", userId), + "Info.0.GroupId": fmt.Sprintf("%d", groupId), + } + _, err := self.camRequest("RemoveUserFromGroup", params) + return err +} + +func (self *SQcloudClient) AddUserToGroup(groupId, userId int) error { + params := map[string]string{ + "Info.0.Uid": fmt.Sprintf("%d", userId), + "Info.0.GroupId": fmt.Sprintf("%d", groupId), + } + _, err := self.camRequest("AddUserToGroup", params) + return err +} + +func (self *SQcloudClient) AttachGroupPolicy(groupId int, policyId string) error { + params := map[string]string{ + "PolicyId": policyId, + "AttachGroupId": fmt.Sprintf("%d", groupId), + } + _, err := self.camRequest("AttachGroupPolicy", params) + return err +} + +func (self *SQcloudClient) DetachGroupPolicy(groupId int, policyId string) error { + params := map[string]string{ + "PolicyId": policyId, + "DetachGroupId": fmt.Sprintf("%d", groupId), + } + _, err := self.camRequest("DetachGroupPolicy", params) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_policy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_policy.go new file mode 100644 index 0000000000..0cf60e855c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_policy.go @@ -0,0 +1,285 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SPolicy struct { + client *SQcloudClient + + PolicyId int64 + PolicyName string + AddTime time.Time + CreateMode string + PolicyType string + Description string + PolicyDocument string +} + +func (self *SPolicy) GetGlobalId() string { + return fmt.Sprintf("%d", self.PolicyId) +} + +func (self *SPolicy) GetName() string { + return self.PolicyName +} + +func (self *SPolicy) UpdateDocument(document *jsonutils.JSONDict) error { + return self.client.UpdatePolicy(int(self.PolicyId), document.String(), "") +} + +func (self *SPolicy) GetDocument() (*jsonutils.JSONDict, error) { + if len(self.PolicyDocument) == 0 { + err := self.Refresh() + if err != nil { + return nil, errors.Wrapf(err, "Refesh") + } + } + jsonObj, err := jsonutils.Parse([]byte(self.PolicyDocument)) + if err != nil { + return nil, errors.Wrapf(err, "jsonutils.Parse") + } + return jsonObj.(*jsonutils.JSONDict), nil +} + +func (self *SPolicy) Delete() error { + return self.client.DeletePolicy([]int{int(self.PolicyId)}) +} + +func (self *SPolicy) Refresh() error { + p, err := self.client.GetPolicy(self.GetGlobalId()) + if err != nil { + return errors.Wrapf(err, "GetPolicy(%s)", self.GetGlobalId()) + } + // p.PolicyId一般为0,若jsonutils.Update会有问题 + self.Description = p.Description + self.PolicyDocument = p.PolicyDocument + return nil +} + +func (self *SPolicy) GetDescription() string { + if len(self.Description) == 0 { + err := self.Refresh() + if err != nil { + return "" + } + } + return self.Description +} + +func (self *SQcloudClient) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + ret := []cloudprovider.ICloudpolicy{} + offset := 1 + for { + part, total, err := self.ListPolicies("", "QCS", offset, 50) + if err != nil { + return nil, errors.Wrap(err, "ListPolicies") + } + for i := range part { + part[i].client = self + ret = append(ret, &part[i]) + } + if len(ret) >= total { + break + } + offset += 1 + } + return ret, nil +} + +func (self *SQcloudClient) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + ret := []cloudprovider.ICloudpolicy{} + offset := 1 + for { + part, total, err := self.ListPolicies("", "Local", offset, 50) + if err != nil { + return nil, errors.Wrap(err, "ListPolicies") + } + for i := range part { + part[i].client = self + ret = append(ret, &part[i]) + } + if len(ret) >= total { + break + } + offset += 1 + } + return ret, nil +} + +func (self *SQcloudClient) ListAttachedUserPolicies(uin string, offset int, limit int) ([]SPolicy, int, error) { + if offset < 1 { + offset = 1 + } + if limit <= 0 || limit > 50 { + limit = 50 + } + params := map[string]string{ + "TargetUin": uin, + "Page": fmt.Sprintf("%d", offset), + "Rp": fmt.Sprintf("%d", limit), + } + resp, err := self.camRequest("ListAttachedUserPolicies", params) + if err != nil { + return nil, 0, errors.Wrap(err, "camRequest.ListAttachedUserPolicies") + } + policies := []SPolicy{} + err = resp.Unmarshal(&policies, "List") + if err != nil { + return nil, 0, errors.Wrap(err, "resp.Unmarshal") + } + total, _ := resp.Float("TotalNum") + return policies, int(total), nil +} + +func (self *SQcloudClient) AttachUserPolicy(uin, policyId string) error { + params := map[string]string{ + "AttachUin": uin, + "PolicyId": policyId, + } + _, err := self.camRequest("AttachUserPolicy", params) + return err +} + +func (self *SQcloudClient) DetachUserPolicy(uin, policyId string) error { + params := map[string]string{ + "DetachUin": uin, + "PolicyId": policyId, + } + _, err := self.camRequest("DetachUserPolicy", params) + return err +} + +// https://cloud.tencent.com/document/api/598/34570 +func (self *SQcloudClient) ListPolicies(keyword, scope string, offset int, limit int) ([]SPolicy, int, error) { + if offset < 1 { + offset = 1 + } + if limit <= 0 || limit > 50 { + limit = 50 + } + params := map[string]string{ + "Page": fmt.Sprintf("%d", offset), + "Rp": fmt.Sprintf("%d", limit), + } + if len(scope) > 0 { + params["Scope"] = scope + } + if len(keyword) > 0 { + params["Keyword"] = keyword + } + resp, err := self.camRequest("ListPolicies", params) + if err != nil { + return nil, 0, errors.Wrap(err, "camRequest.ListPolicies") + } + policies := []SPolicy{} + err = resp.Unmarshal(&policies, "List") + if err != nil { + return nil, 0, errors.Wrap(err, "resp.Unmarshal") + } + total, _ := resp.Float("TotalNum") + return policies, int(total), nil +} + +func (self *SQcloudClient) GetPolicy(policyId string) (*SPolicy, error) { + params := map[string]string{ + "PolicyId": policyId, + } + resp, err := self.camRequest("GetPolicy", params) + if err != nil { + return nil, errors.Wrap(err, "GetPolicy") + } + policy := SPolicy{} + err = resp.Unmarshal(&policy) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return &policy, nil +} + +func (self *SQcloudClient) DeletePolicy(policyIds []int) error { + params := map[string]string{} + for i, policyId := range policyIds { + params[fmt.Sprintf("PolicyId.%d", i)] = fmt.Sprintf("%d", policyId) + } + _, err := self.camRequest("DeletePolicy", params) + return err +} + +func (self *SQcloudClient) GetPolicyByName(name string) (*SPolicy, error) { + policies := []SPolicy{} + offset := 1 + for { + part, total, err := self.ListPolicies(name, "", offset, 50) + if err != nil { + return nil, errors.Wrapf(err, "ListPolicies") + } + policies = append(policies, part...) + if len(policies) >= total { + break + } + offset += 1 + } + for i := range policies { + if policies[i].PolicyName == name { + policies[i].client = self + return &policies[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetPolicyByName(%s)", name) +} + +func (self *SQcloudClient) CreatePolicy(name, document, desc string) (*SPolicy, error) { + params := map[string]string{ + "PolicyName": name, + "PolicyDocument": document, + "Description": desc, + } + _, err := self.camRequest("CreatePolicy", params) + if err != nil { + return nil, errors.Wrapf(err, "CreatePolicy") + } + return self.GetPolicyByName(name) +} + +func (self *SQcloudClient) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { + policy, err := self.CreatePolicy(opts.Name, opts.Document.String(), opts.Desc) + if err != nil { + return nil, errors.Wrapf(err, "CreatePolicy") + } + return policy, nil +} + +func (self *SQcloudClient) UpdatePolicy(policyId int, document, desc string) error { + params := map[string]string{ + "PolicyId": fmt.Sprintf("%d", policyId), + } + if len(document) > 0 { + params["PolicyDocument"] = document + } + if len(desc) > 0 { + params["Description"] = desc + } + _, err := self.camRequest("UpdatePolicy", params) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_role.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_role.go new file mode 100644 index 0000000000..739437a5cd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_role.go @@ -0,0 +1,275 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + DEFAULT_ROLE_DOCUMENT = `{"version":"2.0","statement":[{"action":"name/sts:AssumeRole","effect":"allow","principal":{"service":["cvm.qcloud.com"]}}]}` +) + +/* +"AddTime": "2020-08-11 17:03:30", +"ConsoleLogin": 0.000000, +"Description": "hello", +"PolicyDocument": "{\"version\":\"2.0\",\"statement\":[{\"action\":\"name/sts:AssumeRole\",\"effect\":\"allow\",\"principal\":{\"service\":[\"cdb.qcloud.com\",\"blueking.cloud.tencent.com\"]}}]}", +"RoleId": "4611686018428392276", +"RoleName": "test-role", +"RoleType": "user", +"SessionDuration": 0.000000, +"UpdateTime": "2020-08-11 17:03:30" +*/ + +type SPrincipal struct { + Federated []string +} + +type Statement struct { + Action string + Effect string + Principal SPrincipal +} + +type SRole struct { + multicloud.SResourceBase + client *SQcloudClient + + AddTime time.Time + ConsoleLogin float32 + Description string + PolicyDocument string + RoleId string + RoleName string + RoleType string + SessionDuration float32 + UpdateTime time.Time +} + +func (self *SRole) GetGlobalId() string { + return self.RoleName +} + +func (self *SRole) GetName() string { + return self.RoleName +} + +func (self *SRole) GetDocument() *jsonutils.JSONDict { + if len(self.PolicyDocument) > 0 { + document, err := jsonutils.Parse([]byte(self.PolicyDocument)) + if err != nil { + return nil + } + return document.(*jsonutils.JSONDict) + } + return nil +} + +func (self *SRole) GetSAMLProvider() string { + document := self.GetDocument() + if document != nil { + statements := []Statement{} + document.Unmarshal(&statements, "statement") + for i := range statements { + if statements[i].Action == "name/sts:AssumeRoleWithSAML" { + for _, federated := range statements[i].Principal.Federated { + if strings.Contains(federated, ":saml-provider/") { + info := strings.Split(federated, "/") + return info[len(info)-1] + } + } + } + } + } + return "" +} + +func (self *SRole) Delete() error { + return self.client.DeleteRole(self.RoleName) +} + +func (self *SRole) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + ret := []cloudprovider.ICloudpolicy{} + for { + part, total, err := self.client.ListAttachedRolePolicies(self.RoleName, "", len(ret), 50) + if err != nil { + return nil, errors.Wrapf(err, "ListAttachedRolePolicies") + } + for i := range part { + part[i].client = self.client + ret = append(ret, &part[i]) + } + if len(ret) >= total { + break + } + } + return ret, nil +} + +func (self *SRole) AttachPolicy(id string) error { + return self.client.AttachRolePolicy(self.RoleName, id) +} + +func (self *SRole) DetachPolicy(id string) error { + return self.client.DetachRolePolicy(self.RoleName, id) +} + +func (self *SQcloudClient) GetICloudroles() ([]cloudprovider.ICloudrole, error) { + ret := []cloudprovider.ICloudrole{} + for { + part, total, err := self.DescribeRoleList(len(ret), 200) + if err != nil { + return nil, errors.Wrapf(err, "DescribeRoleList") + } + for i := range part { + part[i].client = self + ret = append(ret, &part[i]) + } + if len(ret) >= total { + break + } + } + return ret, nil +} + +func (self *SQcloudClient) DescribeRoleList(offset int, limit int) ([]SRole, int, error) { + if limit < 1 || limit > 200 { + limit = 200 + } + if offset < 1 { + offset = 1 + } + params := map[string]string{ + "Page": fmt.Sprintf("%d", offset), + "Rp": fmt.Sprintf("%d", limit), + } + roles := []SRole{} + resp, err := self.camRequest("DescribeRoleList", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeRoleList") + } + err = resp.Unmarshal(&roles, "List") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + total, _ := resp.Float("TotalNum") + return roles, int(total), nil +} + +func (self *SQcloudClient) CreateRole(name, document, desc string) (*SRole, error) { + if len(document) == 0 { + document = DEFAULT_ROLE_DOCUMENT + } + params := map[string]string{ + "RoleName": name, + "PolicyDocument": document, + "ConsoleLogin": "1", + "SessionDuration": "43200", + "Description": desc, + } + _, err := self.camRequest("CreateRole", params) + if err != nil { + return nil, errors.Wrap(err, "CreateRole") + } + return self.GetRole(name) +} + +func (self *SQcloudClient) GetRole(name string) (*SRole, error) { + params := map[string]string{ + "RoleName": name, + } + resp, err := self.camRequest("GetRole", params) + if err != nil { + return nil, errors.Wrapf(err, "GetRole(%s)", name) + } + role := &SRole{client: self} + err = resp.Unmarshal(role, "RoleInfo") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return role, nil +} + +func (self *SQcloudClient) ListAttachedRolePolicies(roleName, policyType string, offset, limit int) ([]SPolicy, int, error) { + if limit < 1 || limit > 200 { + limit = 200 + } + if offset < 1 { + offset = 1 + } + params := map[string]string{ + "Page": fmt.Sprintf("%d", offset), + "Rp": fmt.Sprintf("%d", limit), + "RoleName": roleName, + } + if len(policyType) > 0 { + params["PolicyType"] = policyType + } + resp, err := self.camRequest("ListAttachedRolePolicies", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "ListAttachedRolePolicies") + } + policies := []SPolicy{} + err = resp.Unmarshal(&policies, "List") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + total, _ := resp.Float("TotalNum") + return policies, int(total), nil +} + +func (self *SQcloudClient) DeleteRole(name string) error { + params := map[string]string{ + "RoleName": name, + } + _, err := self.camRequest("DeleteRole", params) + return err +} + +func (self *SQcloudClient) AttachRolePolicy(roleName string, policyId string) error { + params := map[string]string{ + "AttachRoleName": roleName, + } + if _id, _ := strconv.Atoi(policyId); _id > 0 { + params["PolicyId"] = policyId + } else { + params["PolicyName"] = policyId + } + _, err := self.camRequest("AttachRolePolicy", params) + return err +} + +func (self *SQcloudClient) DetachRolePolicy(roleName string, policyId string) error { + params := map[string]string{ + "DetachRoleName": roleName, + } + if _id, _ := strconv.Atoi(policyId); _id > 0 { + params["PolicyId"] = policyId + } else { + params["PolicyName"] = policyId + } + _, err := self.camRequest("DetachRolePolicy", params) + return err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_user.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_user.go new file mode 100644 index 0000000000..1af3b1e3ff --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cam_user.go @@ -0,0 +1,297 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SUser struct { + multicloud.SBaseClouduser + client *SQcloudClient + + Uin int64 + Name string + Uid int64 + Remark string + ConsoleLogin int + CountryCode string + Email string +} + +func (user *SUser) GetGlobalId() string { + return fmt.Sprintf("%d", user.Uin) +} + +func (self *SUser) GetEmailAddr() string { + return self.Email +} + +func (self *SUser) GetInviteUrl() string { + return "" +} + +func (user *SUser) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies := []SPolicy{} + offset := 1 + for { + part, total, err := user.client.ListAttachedUserPolicies(user.GetGlobalId(), offset, 50) + if err != nil { + return nil, errors.Wrap(err, "GetClouduserPolicy") + } + policies = append(policies, part...) + if len(policies) >= total { + break + } + offset += 1 + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].PolicyType == "QCS" || policies[i].PolicyType == "" { + policies[i].client = user.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (user *SUser) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + policies := []SPolicy{} + offset := 1 + for { + part, total, err := user.client.ListAttachedUserPolicies(user.GetGlobalId(), offset, 50) + if err != nil { + return nil, errors.Wrap(err, "GetClouduserPolicy") + } + policies = append(policies, part...) + if len(policies) >= total { + break + } + offset += 1 + } + ret := []cloudprovider.ICloudpolicy{} + for i := range policies { + if policies[i].PolicyType == "User" { + policies[i].client = user.client + ret = append(ret, &policies[i]) + } + } + return ret, nil +} + +func (user *SUser) AttachSystemPolicy(policyId string) error { + return user.client.AttachUserPolicy(user.GetGlobalId(), policyId) +} + +func (user *SUser) AttachCustomPolicy(policyId string) error { + return user.client.AttachUserPolicy(user.GetGlobalId(), policyId) +} + +func (user *SUser) DetachSystemPolicy(policyId string) error { + return user.client.DetachUserPolicy(user.GetGlobalId(), policyId) +} + +func (user *SUser) DetachCustomPolicy(policyId string) error { + return user.client.DetachUserPolicy(user.GetGlobalId(), policyId) +} + +func (user *SUser) IsConsoleLogin() bool { + return user.ConsoleLogin == 1 +} + +func (user *SUser) Delete() error { + return user.client.DeleteUser(user.Name) +} + +func (user *SUser) ResetPassword(password string) error { + return user.client.UpdateUser(user.Name, password) +} + +func (user *SUser) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + ret := []cloudprovider.ICloudgroup{} + offset := 1 + for { + part, total, err := user.client.ListGroupsForUser(int(user.Uin), offset, 100) + if err != nil { + return nil, errors.Wrapf(err, "ListGroupsForUser") + } + for i := range part { + part[i].client = user.client + ret = append(ret, &part[i]) + } + if len(ret) >= total { + break + } + offset += 1 + } + return ret, nil +} + +func (user *SUser) GetName() string { + return user.Name +} + +func (self *SQcloudClient) DeleteUser(name string) error { + params := map[string]string{ + "Name": name, + "Force": "1", + } + _, err := self.camRequest("DeleteUser", params) + return err +} + +func (self *SQcloudClient) ListUsers() ([]SUser, error) { + resp, err := self.camRequest("ListUsers", nil) + if err != nil { + return nil, errors.Wrap(err, "camRequest.ListUsers") + } + users := []SUser{} + err = resp.Unmarshal(&users, "Data") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return users, nil +} + +func (self *SQcloudClient) ListGroupsForUser(uin int, offset, limit int) ([]SGroup, int, error) { + if offset < 1 { + offset = 1 + } + if limit <= 0 || limit > 50 { + limit = 50 + } + params := map[string]string{ + "SubUin": fmt.Sprintf("%d", uin), + "Page": fmt.Sprintf("%d", offset), + "Rp": fmt.Sprintf("%d", limit), + } + resp, err := self.camRequest("ListGroupsForUser", params) + if err != nil { + return nil, 0, errors.Wrap(err, "camRequest.ListGroupsForUser") + } + groups := []SGroup{} + err = resp.Unmarshal(&groups, "GroupInfo") + if err != nil { + return nil, 0, errors.Wrap(err, "resp.Unmarshal") + } + total, _ := resp.Float("TotalNum") + return groups, int(total), nil +} + +func (self *SQcloudClient) GetICloudusers() ([]cloudprovider.IClouduser, error) { + users, err := self.ListUsers() + if err != nil { + return nil, errors.Wrap(err, "ListUsers") + } + + ret := []cloudprovider.IClouduser{} + for i := range users { + users[i].client = self + ret = append(ret, &users[i]) + } + collaborators := []SUser{} + for { + part, total, err := self.ListCollaborators(len(collaborators), 50) + if err != nil { + return nil, errors.Wrapf(err, "ListCollaborators") + } + collaborators = append(collaborators, part...) + if len(collaborators) >= total { + break + } + } + for i := range collaborators { + collaborators[i].client = self + ret = append(ret, &collaborators[i]) + } + return ret, nil +} + +func (self *SQcloudClient) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.GetUser(name) +} + +func (self *SQcloudClient) GetUser(name string) (*SUser, error) { + params := map[string]string{ + "Name": name, + } + resp, err := self.camRequest("GetUser", params) + if err != nil { + return nil, errors.Wrap(err, "camRequest.GetUser") + } + user := &SUser{client: self} + err = resp.Unmarshal(user) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return user, nil +} + +func (self *SQcloudClient) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + user, err := self.AddUser(conf.Name, conf.Password, conf.Desc, conf.IsConsoleLogin) + if err != nil { + return nil, errors.Wrap(err, "CreateClouduser") + } + for _, policyId := range conf.ExternalPolicyIds { + err = user.client.AttachUserPolicy(fmt.Sprintf("%d", user.Uin), policyId) + if err != nil { + log.Errorf("attach policy %s for user %s error: %v", policyId, conf.Name, err) + } + } + return user, nil +} + +func (self *SQcloudClient) AddUser(name, password, desc string, consoleLogin bool) (*SUser, error) { + params := map[string]string{ + "Name": name, + "Remark": desc, + "ConsoleLogin": "0", + } + if len(password) > 0 { + params["Password"] = password + } + if consoleLogin { + params["ConsoleLogin"] = "1" + } + resp, err := self.camRequest("AddUser", params) + if err != nil { + return nil, errors.Wrap(err, "camRequest.AddUser") + } + user := &SUser{client: self} + err = resp.Unmarshal(user) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return user, nil +} + +func (self *SQcloudClient) UpdateUser(name, password string) error { + params := map[string]string{ + "Name": name, + "ConsoleLogin": "1", + "Password": password, + } + _, err := self.camRequest("UpdateUser", params) + if err != nil { + return errors.Wrap(err, "UpdateUser") + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cdn.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cdn.go new file mode 100644 index 0000000000..5094876884 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cdn.go @@ -0,0 +1,321 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strconv" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SCdnOrigin struct { + Origins []string `json:"Origins"` + OriginType string `json:"OriginType"` + ServerName string `json:"ServerName"` + CosPrivateAccess string `json:"CosPrivateAccess"` + OriginPullProtocol string `json:"OriginPullProtocol"` + BackupOrigins []string `json:"BackupOrigins"` + BackupOriginType string `json:"BackupOriginType"` + BackupServerName string `json:"BackupServerName"` +} + +type SCdnDomain struct { + multicloud.SResourceBase + QcloudTags + + client *SQcloudClient + + Area string `json:"Area"` + Cname string `json:"Cname"` + CreateTime string `json:"CreateTime"` + Disable string `json:"Disable"` + Domain string `json:"Domain"` + Origin SCdnOrigin `json:"Origin"` + ProjectID int `json:"ProjectId"` + Readonly string `json:"Readonly"` + ResourceID string `json:"ResourceId"` + ServiceType string `json:"ServiceType"` + Status string `json:"Status"` + UpdateTime string `json:"UpdateTime"` +} + +func (self *SCdnDomain) GetName() string { + return self.Domain +} + +func (self *SCdnDomain) GetGlobalId() string { + return self.Domain +} + +func (self *SCdnDomain) GetId() string { + return self.Domain +} + +func (self *SCdnDomain) GetStatus() string { + return self.Status +} + +func (self *SCdnDomain) GetEnabled() bool { + return self.Disable == "normal" +} + +func (self *SCdnDomain) GetCname() string { + return self.Cname +} + +func (self *SCdnDomain) GetOrigins() *cloudprovider.SCdnOrigins { + ret := cloudprovider.SCdnOrigins{} + if self.Origin.OriginType == "cos" { + self.Origin.OriginType = api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET + } + for _, org := range self.Origin.Origins { + ret = append(ret, cloudprovider.SCdnOrigin{ + Type: self.Origin.OriginType, + ServerName: self.Origin.ServerName, + Protocol: self.Origin.OriginPullProtocol, + Origin: org, + }) + } + for _, org := range self.Origin.BackupOrigins { + ret = append(ret, cloudprovider.SCdnOrigin{ + Type: self.Origin.BackupOriginType, + ServerName: self.Origin.BackupServerName, + Origin: org, + }) + } + return &ret +} + +func (self *SCdnDomain) GetArea() string { + return self.Area +} + +func (self *SCdnDomain) GetServiceType() string { + return self.ServiceType +} + +func (self *SQcloudClient) GetCdnDomain(domain string) (*SCdnDomain, error) { + domains, _, err := self.DescribeCdnDomains([]string{domain}, nil, "", 0, 100) + if err != nil { + return nil, errors.Wrapf(err, "DescribeCdnDomains") + } + for i := range domains { + if domains[i].Domain == domain { + domains[i].client = self + return &domains[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, domain) +} + +func (self *SCdnDomain) Refresh() error { + domain, err := self.client.GetCdnDomain(self.Domain) + if err != nil { + return err + } + return jsonutils.Update(self, domain) +} + +func (self *SCdnDomain) Delete() error { + err := self.client.StopCdnDomain(self.Domain) + if err != nil { + return errors.Wrapf(err, "StopCdnDomain") + } + return self.client.DeleteCdnDomain(self.Domain) +} + +func (self *SCdnDomain) SetTags(tags map[string]string, replace bool) error { + region, err := self.client.getDefaultRegion() + if err != nil { + return errors.Wrapf(err, "getDefaultRegion") + } + return region.SetResourceTags("cdn", "domain", []string{self.Domain}, tags, replace) +} + +func (self *SQcloudClient) StopCdnDomain(domain string) error { + params := map[string]string{ + "Domain": domain, + } + _, err := self.cdnRequest("StopCdnDomain", params) + return errors.Wrapf(err, "StopCdnDomain") +} + +func (self *SQcloudClient) StartCdnDomain(domain string) error { + params := map[string]string{ + "Domain": domain, + } + _, err := self.cdnRequest("StartCdnDomain", params) + return errors.Wrapf(err, "StartCdnDomain") +} + +func (self *SQcloudClient) DeleteCdnDomain(domain string) error { + params := map[string]string{ + "Domain": domain, + } + _, err := self.cdnRequest("DeleteCdnDomain", params) + return errors.Wrapf(err, "DeleteCdnDomain") +} + +type SDomains struct { + RequestID string `json:"RequestId"` + Domains []SCdnDomain `json:"Domains"` + TotalNumber int `json:"TotalNumber"` +} + +func (self *SQcloudClient) GetICloudCDNDomains() ([]cloudprovider.ICloudCDNDomain, error) { + cdns, err := self.DescribeAllCdnDomains(nil, nil, "") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudCDNDomain{} + for i := range cdns { + cdns[i].client = self + ret = append(ret, &cdns[i]) + } + return ret, nil +} + +func (self *SQcloudClient) GetICloudCDNDomainByName(name string) (cloudprovider.ICloudCDNDomain, error) { + domains, _, err := self.DescribeCdnDomains([]string{name}, nil, "", 0, 1) + if err != nil { + return nil, errors.Wrapf(err, "DescribeCdnDomains") + } + for i := range domains { + if domains[i].Domain == name { + domains[i].client = self + return &domains[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, name) +} + +func (client *SQcloudClient) AddCdnDomain(domain string, originType string, origins []string, cosPrivateAccess string) error { + params := map[string]string{} + params["Domain"] = domain + params["ServiceType"] = "web" + for i := range origins { + params[fmt.Sprintf("Origin.Origins.%d", i)] = origins[i] + } + params["Origin.OriginType"] = originType + params["Origin.CosPrivateAccess"] = cosPrivateAccess + _, err := client.cdnRequest("AddCdnDomain", params) + if err != nil { + return errors.Wrapf(err, `AddCdnDomain %s`, params) + } + return nil +} + +func (client *SQcloudClient) DescribeCdnDomains(domains, origins []string, domainType string, offset int, limit int) ([]SCdnDomain, int, error) { + params := map[string]string{} + params["Offset"] = strconv.Itoa(offset) + params["Limit"] = strconv.Itoa(limit) + filterIndex := 0 + if len(domains) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filterIndex)] = "domain" + for i := range domains { + params[fmt.Sprintf("Filters.%d.Value.%d", filterIndex, i)] = domains[i] + } + filterIndex++ + } + if len(origins) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filterIndex)] = "origin" + for i := range origins { + params[fmt.Sprintf("Filters.%d.Value.%d", filterIndex, i)] = origins[i] + } + filterIndex++ + } + + if len(domainType) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filterIndex)] = "domainType" + params[fmt.Sprintf("Filters.%d.Value.0", filterIndex)] = domainType + filterIndex++ + } + + resp, err := client.cdnRequest("DescribeDomainsConfig", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeDomainsConfig %s", params) + } + cdnDomains := []SCdnDomain{} + err = resp.Unmarshal(&cdnDomains, "Domains") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + totalcount, _ := resp.Float("TotalNumber") + return cdnDomains, int(totalcount), nil +} + +func (client *SQcloudClient) DescribeAllCdnDomains(domains, origins []string, domainType string) ([]SCdnDomain, error) { + cdnDomains := make([]SCdnDomain, 0) + for { + part, total, err := client.DescribeCdnDomains(domains, origins, domainType, len(cdnDomains), 50) + if err != nil { + return nil, errors.Wrap(err, "DescribeCdnDomains") + } + cdnDomains = append(cdnDomains, part...) + if len(cdnDomains) >= total { + break + } + } + return cdnDomains, nil +} + +func (self *SQcloudClient) CreateCDNDomain(opts *cloudprovider.CdnCreateOptions) (*SCdnDomain, error) { + params := map[string]string{ + "Domain": opts.Domain, + "ServiceType": opts.ServiceType, + } + if len(opts.Area) > 0 { + params["Area"] = opts.Area + } + originTypes := map[string][]string{} + for _, origin := range opts.Origins { + _, ok := originTypes[origin.Type] + if !ok { + originTypes[origin.Type] = []string{} + } + originTypes[origin.Type] = append(originTypes[origin.Type], origin.Origin) + } + for _, origin := range opts.Origins { + params["Origin.OriginType"] = origin.Type + if origin.Type == api.CDN_DOMAIN_ORIGIN_TYPE_BUCKET { + params["Origin.OriginType"] = "cos" + } + if len(origin.ServerName) > 0 { + params["Origin.ServerName"] = origin.ServerName + } else { + params["Origin.ServerName"] = origin.Origin + } + if len(origin.Protocol) > 0 { + params["Origin.OriginPullProtocol"] = origin.Protocol + } + origins, ok := originTypes[origin.Type] + if ok { + for i, origin := range origins { + params[fmt.Sprintf("Origin.Origins.%d", i)] = origin + } + } + } + _, err := self.cdnRequest("AddCdnDomain", params) + if err != nil { + return nil, errors.Wrapf(err, "AddCdnDomain") + } + return self.GetCdnDomain(opts.Domain) +} diff --git a/pkg/multicloud/qcloud/certificate.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/certificate.go similarity index 98% rename from pkg/multicloud/qcloud/certificate.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/certificate.go index fe2d4898ba..2aeba430ad 100644 --- a/pkg/multicloud/qcloud/certificate.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/certificate.go @@ -24,8 +24,8 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type projectInfo struct { @@ -40,7 +40,7 @@ type projectInfo struct { // https://cloud.tencent.com/document/api/400/13675 type SCertificate struct { multicloud.SResourceBase - multicloud.QcloudTags + QcloudTags region *SRegion CertificateID string `json:"CertificateId"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cloud_connect_network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cloud_connect_network.go new file mode 100644 index 0000000000..09aff1cbe7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cloud_connect_network.go @@ -0,0 +1,400 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strconv" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SCcn struct { + multicloud.SResourceBase + QcloudTags + region *SRegion + + CcnID string `json:"CcnId"` + CcnName string `json:"CcnName"` + CcnDescription string `json:"CcnDescription"` + InstanceCount int `json:"InstanceCount"` + CreateTime string `json:"CreateTime"` + State string `json:"State"` + AttachedInstances []SCcnInstance +} + +type SCcnInstance struct { + CcnID string `json:"CcnId"` + InstanceType string `json:"InstanceType"` + InstanceID string `json:"InstanceId"` + InstanceName string `json:"InstanceName"` + InstanceRegion string `json:"InstanceRegion"` + InstanceUin string `json:"InstanceUin"` + CidrBlock []string `json:"CidrBlock"` + State string `json:"State"` +} + +type SCcnAttachInstanceInput struct { + InstanceType string + InstanceId string + InstanceRegion string +} + +func (self *SRegion) DescribeCcns(ccnIds []string, offset int, limit int) ([]SCcn, int, error) { + params := map[string]string{} + params["Offset"] = strconv.Itoa(offset) + params["Limit"] = strconv.Itoa(limit) + if ccnIds != nil && len(ccnIds) > 0 { + for index, ccnId := range ccnIds { + params[fmt.Sprintf("CcnIds.%d", index)] = ccnId + } + } + resp, err := self.vpcRequest("DescribeCcns", params) + if err != nil { + return nil, 0, errors.Wrapf(err, `self.vpcRequest("DescribeCcns", %s)`, jsonutils.Marshal(params).String()) + } + ccns := []SCcn{} + err = resp.Unmarshal(&ccns, "CcnSet") + if err != nil { + return nil, 0, errors.Wrapf(err, `(%s).Unmarshal(&ccns,"CcnSet")`, jsonutils.Marshal(resp).String()) + } + total, _ := resp.Float("TotalCount") + return ccns, int(total), nil +} + +func (self *SRegion) GetAllCcns() ([]SCcn, error) { + ccns := []SCcn{} + for { + part, total, err := self.DescribeCcns(nil, len(ccns), 50) + if err != nil { + return nil, errors.Wrapf(err, "self.DescribeCcns(nil, %d, 50)", len(ccns)) + } + ccns = append(ccns, part...) + if len(ccns) >= total { + break + } + } + for i := range ccns { + ccns[i].region = self + } + return ccns, nil +} + +func (self *SRegion) GetCcnById(ccnId string) (*SCcn, error) { + ccns, _, err := self.DescribeCcns([]string{ccnId}, 0, 50) + if err != nil { + return nil, errors.Wrapf(err, "self.DescribeCcns(%s, 0, 50)", ccnId) + } + if len(ccns) < 1 { + return nil, errors.Wrap(cloudprovider.ErrNotFound, "DescribeCcns") + } + if len(ccns) > 1 { + return nil, errors.Wrap(cloudprovider.ErrDuplicateId, "DescribeCcns") + } + ccns[0].region = self + return &ccns[0], nil +} + +func (self *SRegion) DescribeCcnAttachedInstances(ccnId string, offset int, limit int) ([]SCcnInstance, int, error) { + params := map[string]string{} + params["Offset"] = strconv.Itoa(offset) + params["Limit"] = strconv.Itoa(limit) + params["Filters.0.Name"] = "ccn-id" + params["Filters.0.Values.0"] = ccnId + resp, err := self.vpcRequest("DescribeCcnAttachedInstances", params) + if err != nil { + return nil, 0, errors.Wrapf(err, `self.vpcRequest("DescribeCcnAttachedInstances", %s)`, jsonutils.Marshal(params).String()) + } + instances := []SCcnInstance{} + err = resp.Unmarshal(&instances, "InstanceSet") + if err != nil { + return nil, 0, errors.Wrapf(err, `(%s).Unmarshal(&instances, "InstanceSet")`, jsonutils.Marshal(resp).String()) + } + total, _ := resp.Float("TotalCount") + return instances, int(total), nil +} + +func (self *SRegion) GetAllCcnAttachedInstances(ccnId string) ([]SCcnInstance, error) { + ccnInstances := []SCcnInstance{} + for { + part, total, err := self.DescribeCcnAttachedInstances(ccnId, len(ccnInstances), 50) + if err != nil { + return nil, errors.Wrapf(err, "self.DescribeCcns(nil, %d, 50)", len(ccnInstances)) + } + ccnInstances = append(ccnInstances, part...) + if len(ccnInstances) >= total { + break + } + } + return ccnInstances, nil +} + +func (self *SRegion) CreateCcn(opts *cloudprovider.SInterVpcNetworkCreateOptions) (string, error) { + params := make(map[string]string) + params["CcnName"] = opts.Name + params["CcnDescription"] = opts.Desc + // 默认的后付费不能被支持 + params["InstanceChargeType"] = "PREPAID" + // 预付费仅支持地域间限速 + params["BandwidthLimitType"] = "INTER_REGION_LIMIT" + resp, err := self.vpcRequest("CreateCcn", params) + if err != nil { + return "", errors.Wrapf(err, `self.vpcRequest("CreateCcn", %s)`, jsonutils.Marshal(params).String()) + } + ccn := &SCcn{} + err = resp.Unmarshal(ccn, "Ccn") + if err != nil { + return "", errors.Wrapf(err, `(%s).Unmarshal(ccn, "Ccn")`, jsonutils.Marshal(resp).String()) + } + return ccn.CcnID, nil +} + +func (self *SRegion) AcceptAttachCcnInstances(ccnId string, instances []SCcnAttachInstanceInput) error { + params := make(map[string]string) + params["CcnId"] = ccnId + for i := range instances { + params[fmt.Sprintf("Instances.%d.InstanceType", i)] = instances[i].InstanceType + params[fmt.Sprintf("Instances.%d.InstanceId", i)] = instances[i].InstanceId + params[fmt.Sprintf("Instances.%d.InstanceRegion", i)] = instances[i].InstanceRegion + } + _, err := self.vpcRequest("AcceptAttachCcnInstances", params) + if err != nil { + return errors.Wrapf(err, `self.vpcRequest("AcceptAttachCcnInstances", %s)`, jsonutils.Marshal(params).String()) + } + return nil +} + +func (self *SRegion) DeleteCcn(ccnId string) error { + params := make(map[string]string) + params["CcnId"] = ccnId + _, err := self.vpcRequest("DeleteCcn", params) + if err != nil { + return errors.Wrapf(err, ` self.vpcRequest("DeleteCcn", %s)`, jsonutils.Marshal(params).String()) + } + return nil +} + +func (self *SRegion) AttachCcnInstances(ccnId string, ccnUin string, instances []SCcnAttachInstanceInput) error { + params := make(map[string]string) + params["CcnId"] = ccnId + if len(ccnUin) > 0 { + params["CcnUin"] = ccnUin + } + for i := range instances { + params[fmt.Sprintf("Instances.%d.InstanceType", i)] = instances[i].InstanceType + params[fmt.Sprintf("Instances.%d.InstanceId", i)] = instances[i].InstanceId + params[fmt.Sprintf("Instances.%d.InstanceRegion", i)] = instances[i].InstanceRegion + } + + _, err := self.vpcRequest("AttachCcnInstances", params) + if err != nil { + return errors.Wrapf(err, ` self.vpcRequest("AttachCcnInstances", %s)`, jsonutils.Marshal(params).String()) + } + return nil +} + +func (self *SRegion) DetachCcnInstances(ccnId string, instances []SCcnAttachInstanceInput) error { + params := make(map[string]string) + params["CcnId"] = ccnId + + for i := range instances { + params[fmt.Sprintf("Instances.%d.InstanceType", i)] = instances[i].InstanceType + params[fmt.Sprintf("Instances.%d.InstanceId", i)] = instances[i].InstanceId + params[fmt.Sprintf("Instances.%d.InstanceRegion", i)] = instances[i].InstanceRegion + } + + _, err := self.vpcRequest("DetachCcnInstances", params) + if err != nil { + return errors.Wrapf(err, ` self.vpcRequest("DetachCcnInstances", %s)`, jsonutils.Marshal(params).String()) + } + return nil +} + +func (self *SCcn) GetId() string { + return self.CcnID +} + +func (self *SCcn) GetName() string { + return self.CcnName +} + +func (self *SCcn) GetGlobalId() string { + return self.GetId() +} + +func (self *SCcn) GetStatus() string { + switch self.State { + case "AVAILABLE": + return api.INTER_VPC_NETWORK_STATUS_AVAILABLE + case "ISOLATED": + return api.INTER_VPC_NETWORK_STATUS_UNKNOWN + default: + return api.INTER_VPC_NETWORK_STATUS_UNKNOWN + } +} + +func (self *SCcn) Refresh() error { + ccn, err := self.region.GetCcnById(self.GetId()) + if err != nil { + return errors.Wrapf(err, "self.region.GetCcnById(%s)", self.GetId()) + } + return jsonutils.Update(self, ccn) +} + +func (self *SCcn) GetAuthorityOwnerId() string { + return self.region.client.ownerName +} + +func (self *SCcn) fetchAttachedInstances() error { + if self.AttachedInstances != nil { + return nil + } + + instances, err := self.region.GetAllCcnAttachedInstances(self.GetId()) + if err != nil { + return errors.Wrapf(err, "self.region.GetAllCcnAttachedInstances(%s)", self.GetId()) + } + self.AttachedInstances = instances + return nil +} + +func (self *SCcn) GetICloudVpcIds() ([]string, error) { + err := self.fetchAttachedInstances() + if err != nil { + return nil, errors.Wrap(err, "self.fetchAttachedInstances()") + } + result := []string{} + for i := range self.AttachedInstances { + if self.AttachedInstances[i].InstanceType == "VPC" { + result = append(result, self.AttachedInstances[i].InstanceID) + } + } + return result, nil +} + +func (self *SCcn) AttachVpc(opts *cloudprovider.SInterVpcNetworkAttachVpcOption) error { + if self.GetAuthorityOwnerId() == opts.VpcAuthorityOwnerId { + return nil + } + instance := SCcnAttachInstanceInput{ + InstanceType: "VPC", + InstanceId: opts.VpcId, + InstanceRegion: opts.VpcRegionId, + } + err := self.region.AcceptAttachCcnInstances(self.GetId(), []SCcnAttachInstanceInput{instance}) + if err != nil { + return errors.Wrapf(err, "self.region.AcceptAttachCcnInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) + } + return nil +} + +func (self *SCcn) DetachVpc(opts *cloudprovider.SInterVpcNetworkDetachVpcOption) error { + instance := SCcnAttachInstanceInput{ + InstanceType: "VPC", + InstanceId: opts.VpcId, + InstanceRegion: opts.VpcRegionId, + } + err := self.region.DetachCcnInstances(self.GetId(), []SCcnAttachInstanceInput{instance}) + if err != nil { + return errors.Wrapf(err, "self.client.DetachCcnInstance(%s,%s)", self.GetId(), jsonutils.Marshal(opts).String()) + } + return nil +} + +func (self *SCcn) Delete() error { + err := self.region.DeleteCcn(self.GetId()) + if err != nil { + return errors.Wrapf(err, "self.region.DeleteCcn(%s)", self.GetId()) + } + return nil +} + +func (self *SCcn) GetIRoutes() ([]cloudprovider.ICloudInterVpcNetworkRoute, error) { + routes, err := self.region.GetAllCcnRouteSets(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, " self.region.GetAllCcnRouteSets(self.GetId())") + } + result := []cloudprovider.ICloudInterVpcNetworkRoute{} + for i := range routes { + result = append(result, &routes[i]) + } + return result, nil +} + +func (self *SCcn) EnableRouteEntry(routeId string) error { + err := self.region.EnableCcnRoutes(self.GetId(), []string{routeId}) + if err != nil { + return errors.Wrap(err, "self.region.EnableCcnRoutes") + } + return nil +} + +func (self *SCcn) DisableRouteEntry(routeId string) error { + err := self.region.DisableCcnRoutes(self.GetId(), []string{routeId}) + if err != nil { + return errors.Wrap(err, "self.region.DisableCcnRoutes") + } + return nil +} + +func (client *SQcloudClient) GetICloudInterVpcNetworks() ([]cloudprovider.ICloudInterVpcNetwork, error) { + region, err := client.getDefaultRegion() + if err != nil { + return nil, errors.Wrap(err, "getDefaultRegion") + } + sccns, err := region.GetAllCcns() + if err != nil { + return nil, errors.Wrap(err, " region.GetAllCcns()") + } + result := []cloudprovider.ICloudInterVpcNetwork{} + for i := range sccns { + result = append(result, &sccns[i]) + } + return result, nil +} + +func (client *SQcloudClient) GetICloudInterVpcNetworkById(id string) (cloudprovider.ICloudInterVpcNetwork, error) { + region, err := client.getDefaultRegion() + if err != nil { + return nil, errors.Wrap(err, "getDefaultRegion") + } + ccn, err := region.GetCcnById(id) + if err != nil { + return nil, errors.Wrapf(err, "region.GetCcnById(%s)", id) + } + return ccn, nil +} + +func (client *SQcloudClient) CreateICloudInterVpcNetwork(opts *cloudprovider.SInterVpcNetworkCreateOptions) (cloudprovider.ICloudInterVpcNetwork, error) { + region, err := client.getDefaultRegion() + if err != nil { + return nil, errors.Wrap(err, "getDefaultRegion") + } + + ccnId, err := region.CreateCcn(opts) + if err != nil { + return nil, errors.Wrapf(err, "region.CreateCcn(%s)", jsonutils.Marshal(opts).String()) + } + iNetwork, err := client.GetICloudInterVpcNetworkById(ccnId) + if err != nil { + return nil, errors.Wrapf(err, "client.GetICloudInterVpcNetworkById(%s)", ccnId) + } + return iNetwork, nil +} diff --git a/pkg/multicloud/qcloud/cloud_connect_network_route.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cloud_connect_network_route.go similarity index 97% rename from pkg/multicloud/qcloud/cloud_connect_network_route.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cloud_connect_network_route.go index 2d0bb3d34f..7cd7b36ed1 100644 --- a/pkg/multicloud/qcloud/cloud_connect_network_route.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/cloud_connect_network_route.go @@ -21,13 +21,13 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SCcnRouteSet struct { multicloud.SResourceBase - multicloud.QcloudTags + QcloudTags RouteID string `json:"RouteId"` DestinationCidrBlock string `json:"DestinationCidrBlock"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/dbinstance.go new file mode 100644 index 0000000000..9bb8d71dd2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/dbinstance.go @@ -0,0 +1,63 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "strings" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +func (self *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { + ret := []cloudprovider.ICloudDBInstance{} + mysqls, err := self.GetIMySQLs() + if err != nil { + return nil, errors.Wrapf(err, "GetIMySQLs") + } + ret = append(ret, mysqls...) + tdsqls, err := self.GetITDSQLs() + if err != nil { + return nil, errors.Wrapf(err, "GetITDSQLs") + } + ret = append(ret, tdsqls...) + return ret, nil +} + +func (self *SRegion) GetIDBInstanceById(id string) (cloudprovider.ICloudDBInstance, error) { + if strings.HasPrefix(id, "cdb") { + return self.GetMySQLInstanceById(id) + } else if strings.HasPrefix(id, "tdsqlshard") { + return self.GetTDSQL(id) + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) CreateIDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (cloudprovider.ICloudDBInstance, error) { + if opts.Category == api.QCLOUD_DBINSTANCE_CATEGORY_TDSQL { + return nil, cloudprovider.ErrNotImplemented + } + switch opts.Engine { + case api.DBINSTANCE_TYPE_MYSQL: + rds, err := self.CreateMySQLDBInstance(opts) + if err != nil { + return nil, errors.Wrapf(err, "CreateMySQLDBInstance") + } + return rds, nil + } + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "For %s", opts.Engine) +} diff --git a/pkg/multicloud/qcloud/deal.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/deal.go similarity index 97% rename from pkg/multicloud/qcloud/deal.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/deal.go index 5fab94c377..d1da830fbd 100644 --- a/pkg/multicloud/qcloud/deal.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/deal.go @@ -18,7 +18,7 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SElasticcacheDeal struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/disk.go new file mode 100644 index 0000000000..5de94c0d08 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/disk.go @@ -0,0 +1,415 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + "sort" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type Placement struct { + ProjectId int + Zone string +} + +type SDisk struct { + storage *SStorage + multicloud.SDisk + QcloudTags + + Attached bool + AutoRenewFlagError bool + CreateTime time.Time + DeadlineError bool + DeadlineTime time.Time + DifferDaysOfDeadline int + DiskChargeType string + DiskId string + DiskName string + DiskSize int + DiskState string + DiskType string + DiskUsage string + Encrypt bool + InstanceId string + IsReturnable bool + Placement Placement + Portable bool + RenewFlag string + ReturnFailCode int + RollbackPercent int + Rollbacking bool + SnapshotAbility bool + DeleteWithInstance bool +} + +type SDiskSet []SDisk + +func (v SDiskSet) Len() int { + return len(v) +} + +func (v SDiskSet) Swap(i, j int) { + v[i], v[j] = v[j], v[i] +} + +func (v SDiskSet) Less(i, j int) bool { + if v[i].DiskUsage == "SYSTEM_DISK" || v[j].DiskUsage == "DATA_DISK" { + return true + } + return false +} + +func (self *SRegion) GetDisks(instanceId string, zoneId string, category string, diskIds []string, offset int, limit int) ([]SDisk, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + filter := 0 + + if len(zoneId) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "zone" + params[fmt.Sprintf("Filters.%d.Values.0", filter)] = zoneId + filter++ + } + + if len(instanceId) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "instance-id" + params[fmt.Sprintf("Filters.%d.Values.0", filter)] = instanceId + filter++ + } + + if len(category) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "disk-type" + params[fmt.Sprintf("Filters.%d.Values.0", filter)] = category + filter++ + } + if diskIds != nil && len(diskIds) > 0 { + for index, diskId := range diskIds { + params[fmt.Sprintf("DiskIds.%d", index)] = diskId + } + } + + body, err := self.cbsRequest("DescribeDisks", params) + if err != nil { + log.Errorf("GetDisks fail %s", err) + return nil, 0, err + } + + disks := make([]SDisk, 0) + err = body.Unmarshal(&disks, "DiskSet") + if err != nil { + log.Errorf("Unmarshal disk details fail %s", err) + return nil, 0, err + } + total, _ := body.Float("TotalCount") + sort.Sort(SDiskSet(disks)) + return disks, int(total), 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 *SDisk) GetId() string { + return self.DiskId +} + +func (self *SRegion) DeleteDisk(diskId string) error { + params := make(map[string]string) + params["Region"] = self.Region + params["DiskIds.0"] = diskId + + _, err := self.cbsRequest("TerminateDisks", params) + return err +} + +func (self *SDisk) Delete(ctx context.Context) error { + return self.storage.zone.region.DeleteDisk(self.DiskId) +} + +func (self *SRegion) ResizeDisk(ctx context.Context, diskId string, sizeGb int64) error { + params := make(map[string]string) + params["DiskId"] = diskId + params["DiskSize"] = fmt.Sprintf("%d", sizeGb) + startTime := time.Now() + for { + _, err := self.cbsRequest("ResizeDisk", params) + if err != nil { + if strings.Index(err.Error(), "Code=InvalidDisk.Busy") > 0 { + log.Infof("The disk is busy, try later ...") + time.Sleep(10 * time.Second) + if time.Now().Sub(startTime) > time.Minute*20 { + return cloudprovider.ErrTimeout + } + continue + } + } + return err + } +} + +func (self *SDisk) Resize(ctx context.Context, sizeMb int64) error { + return self.storage.zone.region.ResizeDisk(ctx, self.DiskId, sizeMb/1024) +} + +func (self *SDisk) GetName() string { + if len(self.DiskName) > 0 && self.DiskName != "未命名" { + return self.DiskName + } + return self.DiskId +} + +func (self *SDisk) GetGlobalId() string { + return self.DiskId +} + +func (self *SDisk) IsEmulated() bool { + return false +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +func (self *SDisk) GetStatus() string { + switch self.DiskState { + case "ATTACHING", "DETACHING", "EXPANDING", "ROLLBACKING": + return api.DISK_ALLOCATING + default: + return api.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) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { + snapshotId, err := self.storage.zone.region.CreateSnapshot(self.DiskId, name, desc) + if err != nil { + log.Errorf("createSnapshot fail %s", err) + return nil, err + } + snapshots, total, err := self.storage.zone.region.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) + if err != nil { + return nil, err + } + if total == 1 { + snapshot := &snapshots[0] + err := cloudprovider.WaitStatus(snapshot, api.SNAPSHOT_READY, 15*time.Second, 3600*time.Second) + if err != nil { + return nil, err + } + return snapshot, nil + } + return nil, nil +} + +func (self *SDisk) GetDiskType() string { + switch self.DiskUsage { + case "SYSTEM_DISK": + return api.DISK_TYPE_SYS + case "DATA_DISK": + return api.DISK_TYPE_DATA + default: + return api.DISK_TYPE_DATA + } +} + +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) GetBillingType() string { + switch self.DiskChargeType { + case "PREPAID": + return billing_api.BILLING_TYPE_PREPAID + case "POSTPAID_BY_HOUR": + return billing_api.BILLING_TYPE_POSTPAID + default: + return billing_api.BILLING_TYPE_PREPAID + } +} + +func (self *SDisk) GetDiskFormat() string { + return "vhd" +} + +func (self *SDisk) GetDiskSizeMB() int { + return self.DiskSize * 1024 +} + +func (self *SDisk) GetIsAutoDelete() bool { + return self.DeleteWithInstance +} + +func (self *SDisk) GetCreatedAt() time.Time { + // 2019-12-25 09:00:43 #非UTC时间 + return self.CreateTime.Add(time.Hour * -8) +} + +func (self *SDisk) GetExpiredAt() time.Time { + if self.DeadlineTime.IsZero() { + return time.Time{} + } + return self.DeadlineTime.Add(time.Hour * -8) +} + +func (self *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + snapshots, total, err := self.storage.zone.region.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) + if err != nil { + return nil, err + } + if total == 1 { + return &snapshots[0], nil + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots := make([]SSnapshot, 0) + for { + parts, total, err := self.storage.zone.region.GetSnapshots("", self.DiskId, "", []string{}, 0, 20) + if err != nil { + log.Errorf("GetDisks fail %s", err) + return nil, err + } + 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) GetExtSnapshotPolicyIds() ([]string, error) { + return self.storage.zone.region.GetSnapshotIdByDiskId(self.GetId()) +} + +func (self *SDisk) GetTemplateId() string { + //return self.ImageId + return "" +} + +func (self *SRegion) ResetDisk(diskId, snapshotId string) error { + params := make(map[string]string) + params["Region"] = self.Region + params["DiskId"] = diskId + params["SnapshotId"] = snapshotId + _, err := self.cbsRequest("ApplySnapshot", params) + if err != nil { + log.Errorf("ResetDisk %s to snapshot %s fail %s", diskId, snapshotId, err) + return err + } + return nil +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", self.storage.zone.region.ResetDisk(self.DiskId, snapshotId) +} + +func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int, desc string, projectId string) (string, error) { + params := make(map[string]string) + params["Region"] = self.Region + params["DiskType"] = category + params["DiskChargeType"] = "POSTPAID_BY_HOUR" + // [TencentCloudSDKError] Code=InvalidParameter, Message=DiskName: vdisk_stress-testvm-qcloud-1_1560117118026502729, length is 48, out of range [0,20] (e11d6c4007e4), RequestId=a8409994-0357-42e9-b028-e11d6c4007e4 + if len(name) > 20 { + name = name[:20] + } + params["DiskName"] = name + params["Placement.Zone"] = zoneId + if len(projectId) > 0 { + params["Placement.ProjectId"] = projectId + } + //params["Encrypted"] = "false" + params["DiskSize"] = fmt.Sprintf("%d", sizeGb) + params["ClientToken"] = utils.GenRequestId(20) + + body, err := self.cbsRequest("CreateDisks", params) + if err != nil { + return "", err + } + diskIDSet := []string{} + err = body.Unmarshal(&diskIDSet, "DiskIdSet") + if err != nil { + return "", err + } + if len(diskIDSet) < 1 { + return "", fmt.Errorf("Create Disk error") + } + return diskIDSet[0], nil +} + +func (disk *SDisk) GetAccessPath() string { + return "" +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + // TODO + return cloudprovider.ErrNotSupported +} + +func (self *SDisk) GetProjectId() string { + return strconv.Itoa(self.Placement.ProjectId) +} diff --git a/pkg/multicloud/qcloud/dnspod_domain.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/dnspod_domain.go similarity index 98% rename from pkg/multicloud/qcloud/dnspod_domain.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/dnspod_domain.go index 57e0c0533e..d4049975db 100644 --- a/pkg/multicloud/qcloud/dnspod_domain.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/dnspod_domain.go @@ -22,14 +22,14 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SDomian struct { multicloud.SResourceBase - multicloud.QcloudTags + QcloudTags client *SQcloudClient CNAMESpeedup string `json:"CNAMESpeedup"` diff --git a/pkg/multicloud/qcloud/dnspod_record.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/dnspod_record.go similarity index 98% rename from pkg/multicloud/qcloud/dnspod_record.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/dnspod_record.go index 0c121f0c3e..b27dbabd77 100644 --- a/pkg/multicloud/qcloud/dnspod_record.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/dnspod_record.go @@ -22,8 +22,8 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SRecordCreateRet struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/doc.go new file mode 100644 index 0000000000..e152d3d721 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/doc.go @@ -0,0 +1,113 @@ +// Copyright 2019 Yunion +// +// 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 qcloud // import "yunion.io/x/cloudmux/pkg/multicloud/qcloud" + +/* +Network Pre Conditions + +若是不开放公网,则需要开放以下域名的443和80端口, 避免部分资源同步异常或创建资源失败 + +cvm.tencentcloudapi.com +cvm.ap-shanghai-fsi.tencentcloudapi.com +cvm.ap-shenzhen-fsi.tencentcloudapi.com + +vpc.tencentcloudapi.com +vpc.ap-shanghai-fsi.tencentcloudapi.com +vpc.ap-shenzhen-fsi.tencentcloudapi.com + +cloudaudit.tencentcloudapi.com +cloudaudit.ap-shanghai-fsi.tencentcloudapi.com +cloudaudit.ap-shenzhen-fsi.tencentcloudapi.com + +cbs.tencentcloudapi.com +cbs.ap-shanghai-fsi.tencentcloudapi.com +cbs.ap-shenzhen-fsi.tencentcloudapi.com + +account.api.qcloud.com + +clb.tencentcloudapi.com +clb.ap-shanghai-fsi.tencentcloudapi.com +clb.ap-shenzhen-fsi.tencentcloudapi.com + +cdb.tencentcloudapi.com +cdb.ap-shanghai-fsi.tencentcloudapi.com +cdb.ap-shenzhen-fsi.tencentcloudapi.com + +mariadb.tencentcloudapi.com +mariadb.ap-shanghai-fsi.tencentcloudapi.com +mariadb.ap-shenzhen-fsi.tencentcloudapi.com + +postgres.tencentcloudapi.com +postgres.ap-shanghai-fsi.tencentcloudapi.com +postgres.ap-shenzhen-fsi.tencentcloudapi.com + +sqlserver.tencentcloudapi.com +sqlserver.ap-shanghai-fsi.tencentcloudapi.com +sqlserver.ap-shenzhen-fsi.tencentcloudapi.com + +lb.api.qcloud.com +wss.api.qcloud.com +cns.api.qcloud.com +vpc.api.qcloud.com +billing.tencentcloudapi.com +cam.tencentcloudapi.com +monitor.tencentcloudapi.com + +cos.ap-beijing.myqcloud.com +service.cos.myqcloud.com +cos.ap-bangkok.myqcloud.com. +bj.file.myqcloud.com. +tj.file.myqcloud.com. +cd.file.myqcloud.com. +cq.file.myqcloud.com. +gz.file.myqcloud.com. +hk.file.myqcloud.com. +cos.ap-mumbai.myqcloud.com. +cos.ap-nanjing.myqcloud.com. +cos.ap-seoul.myqcloud.com. +sh.file.myqcloud.com. +cos.ap-shanghai-fsi.myqcloud.com. +cos.ap-shenzhen-fsi.myqcloud.com. +sgp.file.myqcloud.com. +cos.ap-tokyo.myqcloud.com. +ger.file.myqcloud.com. +cos.eu-moscow.myqcloud.com. +cos.na-ashburn.myqcloud.com. +cos.na-siliconvalley.myqcloud.com. +ca.file.myqcloud.com. +3jytr9q1.dayugslb.com. +60icvusw.dayugslb.com. +5ekm872f.dayugslb.com. +r5mfqoyl.dayugslb.com. + +Permission Pre Conditions +若仅需要同步资源, 则需要赋予账号以下权限 +QCloudFinanceFullAccess +QcloudCVMReadOnlyAccess +QcloudCamReadOnlyAccess +QcloudCOSReadOnlyAccess +QcloudAuditReadOnlyAccess +QcloudMonitorReadOnlyAccess + +若需要资源读写,需要赋予账号以下权限 +QCloudFinanceFullAccess +QcloudCVMFullAccess +QcloudCamFullAccess +QcloudCBSFullAccess +QcloudEIPFullAccess +QcloudCOSFullAccess +QcloudAuditFullAccess +QcloudMonitorFullAccess +*/ diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/eip.go new file mode 100644 index 0000000000..b05afff345 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/eip.go @@ -0,0 +1,424 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + EIP_STATUS_CREATING = "CREATING" + EIP_STATUS_BINDING = "BINDING" + EIP_STATUS_BIND = "BIND" + EIP_STATUS_UNBINDING = "UNBINDING" + EIP_STATUS_UNBIND = "UNBIND" + EIP_STATUS_OFFLINING = "OFFLINING" + EIP_STATUS_BIND_ENI = "BIND_ENI" + EIP_STATUS_CREATE_FAILED = "CREATE_FAILED" + + EIP_TYPE_CALCIP = "CalcIP" //表示设备ip + EIP_TYPE_WANIP = "WanIP" //普通公网ip + EIP_TYPE_EIP = "EIP" //弹性公网ip + EIP_TYPE_ANYCASTEIP = "AnycastEIP" //加速EIP +) + +type SEipAddress struct { + region *SRegion + multicloud.SEipBase + QcloudTags + + AddressId string // EIP的ID,是EIP的唯一标识。 + AddressName string // EIP名称。 + AddressStatus string // EIP状态。 + AddressIp string // 外网IP地址 + InstanceId string // 绑定的资源实例ID。可能是一个CVM,NAT。 + CreatedTime time.Time // 创建时间。按照ISO8601标准表示,并且使用UTC时间。格式为:YYYY-MM-DDThh:mm:ssZ。 + NetworkInterfaceId string // 绑定的弹性网卡ID + PrivateAddressIp string // 绑定的资源内网ip + IsArrears bool // 资源隔离状态。true表示eip处于隔离状态,false表示资源处于未隔离装填 + IsBlocked bool // 资源封堵状态。true表示eip处于封堵状态,false表示eip处于未封堵状态 + IsEipDirectConnection bool // eip是否支持直通模式。true表示eip支持直通模式,false表示资源不支持直通模式 + AddressType string // eip资源类型,包括"CalcIP","WanIP","EIP","AnycastEIP"。其中"CalcIP"表示设备ip,“WanIP”表示普通公网ip,“EIP”表示弹性公网ip,“AnycastEip”表示加速EIP + CascadeRelease bool // eip是否在解绑后自动释放。true表示eip将会在解绑后自动释放,false表示eip在解绑后不会自动释放 + Bandwidth int + InternetChargeType string +} + +func (self *SEipAddress) GetId() string { + return self.AddressId +} + +func (self *SEipAddress) GetName() string { + if len(self.AddressName) > 0 && self.AddressName != "未命名" { + return self.AddressName + } + return self.AddressId +} + +func (self *SEipAddress) GetGlobalId() string { + return self.AddressId +} + +func (self *SEipAddress) GetStatus() string { + switch self.AddressStatus { + case EIP_STATUS_CREATING: + return api.EIP_STATUS_ALLOCATE + case EIP_STATUS_BINDING: + return api.EIP_STATUS_ASSOCIATE + case EIP_STATUS_UNBINDING: + return api.EIP_STATUS_DISSOCIATE + case EIP_STATUS_UNBIND, EIP_STATUS_BIND, EIP_STATUS_OFFLINING, EIP_STATUS_BIND_ENI: + return api.EIP_STATUS_READY + case EIP_STATUS_CREATE_FAILED: + return api.EIP_STATUS_ALLOCATE_FAIL + default: + return api.EIP_STATUS_UNKNOWN + } +} + +func (self *SEipAddress) Refresh() error { + if self.IsEmulated() { + return nil + } + new, err := self.region.GetEip(self.AddressId) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SEipAddress) IsEmulated() bool { + if self.AddressId == self.InstanceId { + // fixed Public IP + return true + } else { + return false + } +} + +func (self *SEipAddress) GetIpAddr() string { + return self.AddressIp +} + +func (self *SEipAddress) GetMode() string { + if self.InstanceId == self.AddressId { + return api.EIP_MODE_INSTANCE_PUBLICIP + } + return api.EIP_MODE_STANDALONE_EIP +} + +func (self *SEipAddress) GetAssociationType() string { + if len(self.InstanceId) > 0 { + for prefix, instanceType := range map[string]string{ + "nat-": api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY, + "ins-": api.EIP_ASSOCIATE_TYPE_SERVER, + "lb-": api.EIP_ASSOCIATE_TYPE_LOADBALANCER, + "lbl-": api.EIP_ASSOCIATE_TYPE_LOADBALANCER, + } { + if strings.HasPrefix(self.InstanceId, prefix) { + return instanceType + } + } + if info := strings.Split(self.InstanceId, "-"); len(info) > 0 { + return info[0] + } + return self.InstanceId + } + return "" +} + +func (self *SEipAddress) GetAssociationExternalId() string { + return self.InstanceId +} + +func (self *SEipAddress) Delete() error { + return self.region.DeallocateEIP(self.AddressId) +} + +func (self *SEipAddress) GetBandwidth() int { + if self.Bandwidth > 0 { + return self.Bandwidth + } + if len(self.InstanceId) > 0 { + if strings.HasPrefix(self.InstanceId, "ins-") { + if instance, err := self.region.GetInstance(self.InstanceId); err == nil { + return instance.InternetAccessible.InternetMaxBandwidthOut + } + } + } + return 0 +} + +func (self *SEipAddress) GetINetworkId() string { + return "" +} + +func (self *SEipAddress) GetBillingType() string { + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SEipAddress) GetCreatedAt() time.Time { + return self.CreatedTime +} + +func (self *SEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SEipAddress) GetInternetChargeType() string { + switch self.InternetChargeType { + case "TRAFFIC_POSTPAID_BY_HOUR": + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + case "BANDWIDTH_PACKAGE", "BANDWIDTH_POSTPAID_BY_HOUR", "BANDWIDTH_PREPAID_BY_MONTH": + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH + } + if len(self.InstanceId) > 0 { + if strings.HasPrefix(self.InstanceId, "ins-") { + if instance, err := self.region.GetInstance(self.InstanceId); err == nil { + switch instance.InternetAccessible.InternetChargeType { + case InternetChargeTypeTrafficPostpaidByHour: + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + default: + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH + } + } + } + } + return "" +} + +func (self *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { + err := self.region.AssociateEip(self.AddressId, conf.InstanceId) + if err != nil { + return err + } + if conf.Bandwidth > 0 && self.Bandwidth == 0 { + err = self.region.UpdateInstanceBandwidth(conf.InstanceId, conf.Bandwidth, conf.ChargeType) + if err != nil { + log.Warningf("failed to change instance %s bandwidth -> %d error: %v", conf.InstanceId, conf.Bandwidth, err) + } + } + return cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 5*time.Second, 10*time.Second, 180*time.Second) +} + +func (self *SEipAddress) Dissociate() error { + err := self.region.DissociateEip(self.AddressId) + if err != nil { + return err + } + return cloudprovider.WaitStatusWithDelay(self, api.EIP_STATUS_READY, 5*time.Second, 10*time.Second, 180*time.Second) +} + +func (self *SEipAddress) ChangeBandwidth(bw int) error { + if len(self.InstanceId) > 0 && self.Bandwidth == 0 && self.GetAssociationType() == api.EIP_ASSOCIATE_TYPE_SERVER { + return self.region.UpdateInstanceBandwidth(self.InstanceId, bw, "") + } + if len(self.InternetChargeType) > 0 { + return self.region.ChangeEipBindWidth(self.AddressId, bw, self.InternetChargeType) + } + return nil +} + +func (region *SRegion) GetEips(eipId string, instanceId string, offset int, limit int) ([]SEipAddress, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + + params := make(map[string]string) + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + + if len(eipId) > 0 { + params["AddressIds.0"] = eipId + } + + if len(instanceId) > 0 { + params["Filters.0.Name"] = "instance-id" + params["Filters.0.Values.0"] = instanceId + } + + body, err := region.vpcRequest("DescribeAddresses", params) + if err != nil { + log.Errorf("DescribeEipAddresses fail %s", err) + return nil, 0, err + } + + eips := make([]SEipAddress, 0) + err = body.Unmarshal(&eips, "AddressSet") + if err != nil { + log.Errorf("Unmarshal EipAddress details fail %s", err) + return nil, 0, err + } + total, _ := body.Float("TotalCount") + for i := 0; i < len(eips); i++ { + eips[i].region = region + } + return eips, int(total), nil +} + +func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { + eips, total, err := region.GetEips(eipId, "", 0, 1) + if err != nil { + return nil, err + } + if total != 1 { + return nil, cloudprovider.ErrNotFound + } + return &eips[0], nil +} + +func (region *SRegion) AllocateEIP(name string, bwMbps int, chargeType string) (*SEipAddress, error) { + params := make(map[string]string) + params["AddressName"] = name + if len(name) > 20 { + params["AddressName"] = name[:20] + } + if bwMbps > 0 { + params["InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bwMbps) + } + + _, totalCount, err := region.GetBandwidthPackages([]string{}, 0, 50) + if err != nil { + return nil, errors.Wrapf(err, "GetBandwidthPackages") + } + if totalCount == 0 { + switch chargeType { + case api.EIP_CHARGE_TYPE_BY_TRAFFIC: + params["InternetChargeType"] = "TRAFFIC_POSTPAID_BY_HOUR" + case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: + params["InternetChargeType"] = "BANDWIDTH_POSTPAID_BY_HOUR" + } + } + + addRessSet := []string{} + body, err := region.vpcRequest("AllocateAddresses", params) + if err != nil { + return nil, errors.Wrapf(err, "AllocateAddresses") + } + err = body.Unmarshal(&addRessSet, "AddressSet") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return region.GetEip(addRessSet[0]) +} + +// https://cloud.tencent.com/document/api/215/16699 +// 腾讯云eip不支持指定项目 +func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + return region.AllocateEIP(eip.Name, eip.BandwidthMbps, eip.ChargeType) +} + +func (region *SRegion) DeallocateEIP(eipId string) error { + params := make(map[string]string) + params["Region"] = region.Region + params["AddressIds.0"] = eipId + + _, err := region.vpcRequest("ReleaseAddresses", params) + return errors.Wrapf(err, "ReleaseAddresses") +} + +func (region *SRegion) AssociateEip(eipId string, instanceId string) error { + params := make(map[string]string) + params["AddressId"] = eipId + params["InstanceId"] = instanceId + + _, err := region.vpcRequest("AssociateAddress", params) + return errors.Wrapf(err, "AssociateAddress") +} + +func (region *SRegion) DissociateEip(eipId string) error { + params := make(map[string]string) + params["Region"] = region.Region + params["AddressId"] = eipId + + _, err := region.vpcRequest("DisassociateAddress", params) + return errors.Wrapf(err, "DisassociateAddress") +} + +func (self *SRegion) UpdateInstanceBandwidth(instanceId string, bw int, chargeType string) error { + params := make(map[string]string) + params["Region"] = self.Region + params["InternetAccessible.InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bw) + + _, totalCount, err := self.GetBandwidthPackages([]string{}, 0, 50) + if err != nil { + return errors.Wrapf(err, "GetBandwidthPackages") + } + if totalCount > 0 { + params["InstanceIds.0"] = instanceId + _, err = self.cvmRequest("ResetInstancesInternetMaxBandwidth", params, true) + return errors.Wrapf(err, "ResetInstancesInternetMaxBandwidth") + } + internetChargeType := "TRAFFIC_POSTPAID_BY_HOUR" + if chargeType == api.EIP_CHARGE_TYPE_BY_BANDWIDTH { + internetChargeType = "BANDWIDTH_POSTPAID_BY_HOUR" + } + params["InternetAccessible.InternetChargeType"] = internetChargeType + action := "ResetInstancesInternetMaxBandwidth" + + instance, err := self.GetInstance(instanceId) + if err != nil { + return errors.Wrapf(err, "GetInstance(%s)", instanceId) + } + if instance.InternetAccessible.InternetChargeType != internetChargeType { //避免 Code=InvalidParameterValue, Message=参数`InternetChargeType`中`TRAFFIC_POSTPAID_BY_HOUR`没有更改, RequestId=6be2f9bc-a967-41db-9f0d-aff789c703ca + params["InstanceId"] = instanceId + action = "ModifyInstanceInternetChargeType" + } else { + params["InstanceIds.0"] = instanceId + } + err = cloudprovider.Wait(time.Second*5, time.Minute*3, func() (bool, error) { + instance, err := self.GetInstance(instanceId) + if err != nil { + return false, errors.Wrapf(err, "GetInstance(%s)", instanceId) + } + _bw := instance.InternetAccessible.InternetMaxBandwidthOut + log.Infof("%s bandwidth from %d -> %d expect %d", action, _bw, bw, bw) + if _bw == bw { + return true, nil + } + if _, err := self.cvmRequest(action, params, true); err != nil { + log.Errorf("%s %v", action, err) + return false, nil + } + return false, nil + }) + return errors.Wrapf(err, "cloudprovider.Wait bandwidth changed") +} + +func (self *SRegion) ChangeEipBindWidth(eipId string, bw int, chargeType string) error { + params := map[string]string{ + "Region": self.Region, + "InternetMaxBandwidthOut": fmt.Sprintf("%d", bw), + "InternetChargeType": chargeType, + "AddressId": eipId, + } + _, err := self.vpcRequest("ModifyAddressInternetChargeType", params) + return errors.Wrapf(err, "ModifyAddressInternetChargeType") +} + +func (self *SEipAddress) GetProjectId() string { + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elastic_search.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elastic_search.go new file mode 100644 index 0000000000..79d63b0964 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elastic_search.go @@ -0,0 +1,351 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElasticSearch struct { + multicloud.SVirtualResourceBase + multicloud.SBillingBase + QcloudTags + region *SRegion + + InstanceId string + InstanceName string + Region string + Zone string + AppId int + Uin string + VpcUid string + SubnetUid string + Status int + ChargeType string + ChargePeriod int + RenewFlag string + NodeType string + NodeNum int + CpuNum int + MemSize int + DiskType string + DiskSize int + EsDomain string + EsVip string + EsPort int + KibanaUrl string + EsVersion string + EsConfig string + EsAcl struct { + BlackIpList []string + WhiteIpList []string + } + CreateTime time.Time + UpdateTime time.Time + Deadline string + InstanceType int + IkConfig struct { + MainDict []struct { + Key string + Name string + Size int + } + Stopwords []struct { + Key string + Name string + Size int + } + QQDict []struct { + Key string + Name string + Size int + } + Synonym []struct { + Key string + Name string + Size int + } + UpdateType string + } + MasterNodeInfo struct { + EnableDedicatedMaster bool + MasterNodeType string + MasterNodeNum int + MasterNodeCpuNum int + MasterNodeMemSize int + MasterNodeDiskSize int + MasterNodeDiskType string + } + CosBackup struct { + IsAutoBackup bool + BackupTime string + } + AllowCosBackup bool + LicenseType string + EnableHotWarmMode bool + WarmNodeType string + WarmNodeNum int + WarmCpuNum int + WarmMemSize int + WarmDiskType string + WarmDiskSize int + NodeInfoList []struct { + NodeNum int + NodeType string + Type string + DiskType string + DiskSize int + LocalDiskInfo struct { + LocalDiskType string + LocalDiskSize int + LocalDiskCount int + } + DiskCount int + DiskEncrypt int + } + EsPublicUrl string + MultiZoneInfo []struct { + Zone string + SubnetId string + } + DeployMode int + PublicAccess string + EsPublicAcl struct { + BlackIpList []string + WhiteIpList []string + } + KibanaPrivateUrl string + KibanaPublicAccess string + KibanaPrivateAccess string + SecurityType int + SceneType int + KibanaConfig string + KibanaNodeInfo struct { + KibanaNodeType string + KibanaNodeNum int + KibanaNodeCpuNum int + KibanaNodeMemSize int + KibanaNodeDiskType string + KibanaNodeDiskSize int + } +} + +func (self *SElasticSearch) GetId() string { + return self.InstanceId +} + +func (self *SElasticSearch) GetGlobalId() string { + return self.InstanceId +} + +func (self *SElasticSearch) GetName() string { + if len(self.InstanceName) > 0 { + return self.InstanceName + } + return self.InstanceId +} + +func (self *SElasticSearch) GetVersion() string { + return self.EsVersion +} + +func (self *SElasticSearch) Refresh() error { + es, err := self.region.GetElasticSearch(self.InstanceId) + if err != nil { + return err + } + return jsonutils.Update(self, es) +} + +func (self *SElasticSearch) GetDiskSizeGb() int { + return self.DiskSize +} + +func (self *SElasticSearch) GetStorageType() string { + return self.DiskType +} + +func (self *SElasticSearch) GetCategory() string { + return self.LicenseType +} + +func (self *SElasticSearch) GetCreatedAt() time.Time { + return self.CreateTime +} + +func (self *SElasticSearch) GetVpcId() string { + return self.VpcUid +} + +func (self *SElasticSearch) GetNetworkId() string { + for _, zone := range self.MultiZoneInfo { + if len(zone.SubnetId) > 0 { + return zone.SubnetId + } + } + return self.SubnetUid +} + +func (self *SElasticSearch) GetInstanceType() string { + return self.NodeType +} + +func (self *SElasticSearch) GetVcpuCount() int { + return self.CpuNum +} + +func (self *SElasticSearch) GetVmemSizeGb() int { + return self.MemSize +} + +func (self *SElasticSearch) GetZoneId() string { + for _, zone := range self.MultiZoneInfo { + if len(zone.Zone) > 0 { + return zone.Zone + } + } + return self.Zone +} + +func (self *SElasticSearch) IsMultiAz() bool { + return len(self.MultiZoneInfo) > 1 +} + +func (self *SElasticSearch) GetBillingType() string { + switch self.ChargeType { + case "PREPAID", "CDHPAID": + return billing_api.BILLING_TYPE_PREPAID + case "POSTPAID_BY_HOUR": + return billing_api.BILLING_TYPE_POSTPAID + } + return billing_api.BILLING_TYPE_POSTPAID +} + +func (self *SElasticSearch) GetStatus() string { + switch self.Status { + case 0: + return api.ELASITC_SEARCH_STATUS_CREATING + case 1: + return api.ELASTIC_SEARCH_STATUS_AVAILABLE + case -1: + return api.ELASTIC_SEARCH_STATUS_UNAVAILABLE + case -2, -3: + return api.ELASTIC_SEARCH_STATUS_DELETING + } + return fmt.Sprintf("%d", self.Status) +} + +func (self *SElasticSearch) IsAutoRenew() bool { + return self.RenewFlag == "NOTIFY_AND_AUTO_RENEW" +} + +func (self *SElasticSearch) Delete() error { + return self.region.DeleteElasticSearch(self.InstanceId) +} + +func (self *SElasticSearch) GetAccessInfo() (*cloudprovider.ElasticSearchAccessInfo, error) { + return &cloudprovider.ElasticSearchAccessInfo{ + Port: self.EsPort, + Vip: self.EsVip, + Domain: self.EsPublicUrl, + PrivateDomain: self.EsDomain, + KibanaUrl: self.KibanaUrl, + KibanaPrivateUrl: self.KibanaPrivateUrl, + }, nil +} + +func (self *SRegion) GetIElasticSearchs() ([]cloudprovider.ICloudElasticSearch, error) { + ess := []SElasticSearch{} + for { + part, total, err := self.GetElasticSearchs(nil, 100, len(ess)) + if err != nil { + return nil, errors.Wrapf(err, "GetElasticSearchs") + } + ess = append(ess, part...) + if len(ess) >= total { + break + } + } + ret := []cloudprovider.ICloudElasticSearch{} + for i := range ess { + ess[i].region = self + ret = append(ret, &ess[i]) + } + return ret, nil +} + +func (self *SRegion) GetIElasticSearchById(id string) (cloudprovider.ICloudElasticSearch, error) { + es, err := self.GetElasticSearch(id) + if err != nil { + return nil, errors.Wrapf(err, "GetElasitcSearch") + } + return es, nil +} + +func (self *SRegion) GetElasticSearch(id string) (*SElasticSearch, error) { + if len(id) == 0 { + return nil, cloudprovider.ErrNotFound + } + ret, _, err := self.GetElasticSearchs([]string{id}, 1, 0) + if err != nil { + return nil, errors.Wrapf(err, "GetElasticSearchs") + } + for i := range ret { + ret[i].region = self + return &ret[i], nil + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetElasticSearchs(ids []string, limit, offset int) ([]SElasticSearch, int, error) { + if limit < 1 || limit > 100 { + limit = 100 + } + params := map[string]string{ + "Limit": fmt.Sprintf("%d", limit), + "Offset": fmt.Sprintf("%d", offset), + } + for i, id := range ids { + params[fmt.Sprintf("InstanceIds.%d", i)] = id + } + resp, err := self.esRequest("DescribeInstances", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeInstances") + } + ret := []SElasticSearch{} + err = resp.Unmarshal(&ret, "InstanceList") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + totalCount, _ := resp.Float("TotalCount") + return ret, int(totalCount), nil +} + +func (self *SRegion) DeleteElasticSearch(id string) error { + params := map[string]string{ + "InstanceId": id, + } + _, err := self.esRequest("DeleteInstance", params) + return errors.Wrapf(err, "DeleteDBInstance") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_account.go new file mode 100644 index 0000000000..0ea8527449 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_account.go @@ -0,0 +1,172 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElasticcacheAccount struct { + multicloud.SElasticcacheAccountBase + QcloudTags + + cacheDB *SElasticcache + + InstanceID string `json:"InstanceId"` + AccountName string `json:"AccountName"` + Remark string `json:"Remark"` + Privilege string `json:"Privilege"` + ReadonlyPolicy []string `json:"ReadonlyPolicy"` + Status int `json:"Status"` + IsEmulate bool `json:"is_emulate"` +} + +func (self *SElasticcacheAccount) GetId() string { + return fmt.Sprintf("%s/%s", self.InstanceID, self.AccountName) +} + +func (self *SElasticcacheAccount) GetName() string { + return self.AccountName +} + +func (self *SElasticcacheAccount) IsEmulated() bool { + return self.IsEmulate +} + +func (self *SElasticcacheAccount) GetGlobalId() string { + return self.GetId() +} + +func (self *SElasticcacheAccount) GetStatus() string { + switch self.Status { + case 1: + return api.ELASTIC_CACHE_ACCOUNT_STATUS_CREATING + case 2: + return api.ELASTIC_CACHE_ACCOUNT_STATUS_AVAILABLE + case 4: + return api.ELASTIC_CACHE_ACCOUNT_STATUS_DELETED + default: + return api.ELASTIC_CACHE_ACCOUNT_STATUS_UNAVAILABLE + } +} + +func (self *SElasticcacheAccount) GetAccountType() string { + if strings.ToLower(self.AccountName) == "root" { + return api.ELASTIC_CACHE_ACCOUNT_TYPE_ADMIN + } else { + return api.ELASTIC_CACHE_ACCOUNT_TYPE_NORMAL + } +} + +func (self *SElasticcacheAccount) GetAccountPrivilege() string { + switch self.Privilege { + case "r": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_READ + case "w": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE + case "rw": + return api.ELASTIC_CACHE_ACCOUNT_PRIVILEGE_WRITE + default: + return self.Privilege + } +} + +func (self *SElasticcacheAccount) Refresh() error { + account, err := self.cacheDB.GetICloudElasticcacheAccount(self.GetGlobalId()) + if err != nil { + return errors.Wrap(err, "GetICloudElasticcacheAccount") + } + + err = jsonutils.Update(self, account) + if err != nil { + return errors.Wrap(err, "Update") + } + + return nil +} + +// https://cloud.tencent.com/document/product/239/38925 +func (self *SElasticcacheAccount) Delete() error { + params := map[string]string{} + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.AccountName + _, err := self.cacheDB.region.redisRequest("DeleteInstanceAccount", params) + if err != nil { + return errors.Wrap(err, "DeleteInstanceAccount") + } + + return nil +} + +// https://cloud.tencent.com/document/product/239/20014 +func (self *SElasticcacheAccount) ResetPassword(input cloudprovider.SCloudElasticCacheAccountResetPasswordInput) error { + params := map[string]string{} + params["InstanceId"] = self.cacheDB.GetId() + if input.NoPasswordAccess != nil && *input.NoPasswordAccess { + params["NoAuth"] = "true" + } else { + if len(input.NewPassword) > 0 { + params["Password"] = input.NewPassword + } else { + return nil + } + } + + _, err := self.cacheDB.region.redisRequest("ResetPassword", params) + if err != nil { + return errors.Wrap(err, "ResetPassword") + } + + return nil +} + +// https://cloud.tencent.com/document/product/239/38923 +func (self *SElasticcacheAccount) UpdateAccount(input cloudprovider.SCloudElasticCacheAccountUpdateInput) error { + params := map[string]string{} + params["InstanceId"] = self.cacheDB.GetId() + params["AccountName"] = self.AccountName + if input.NoPasswordAccess != nil && *input.NoPasswordAccess { + params["NoAuth"] = "true" + } else { + if input.Password != nil && len(*input.Password) > 0 { + params["AccountPassword"] = *input.Password + } + } + + if input.Description != nil && len(*input.Description) > 0 { + params["Remark"] = *input.Description + } + + if input.AccountPrivilege != nil && len(*input.AccountPrivilege) > 0 { + params["Privilege"] = *input.AccountPrivilege + params["ReadonlyPolicy.0"] = "master" + } + + _, err := self.cacheDB.region.redisRequest("ModifyInstanceAccount", params) + if err != nil { + return errors.Wrap(err, "ModifyInstanceAccount") + } + + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_backup.go new file mode 100644 index 0000000000..aeff1078c4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_backup.go @@ -0,0 +1,185 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "strconv" + "strings" + "time" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SElasticcacheBackup struct { + multicloud.SElasticcacheBackupBase + QcloudTags + + cacheDB *SElasticcache + + StartTime time.Time `json:"StartTime"` + BackupID string `json:"BackupId"` + BackupType string `json:"BackupType"` + Status int `json:"Status"` + Remark string `json:"Remark"` + Locked int64 `json:"Locked"` +} + +func (self *SElasticcacheBackup) GetId() string { + return self.BackupID +} + +func (self *SElasticcacheBackup) GetName() string { + if len(self.Remark) > 0 { + segs := strings.Split(self.Remark, "@") + return segs[0] + } + + return self.GetId() +} + +func (self *SElasticcacheBackup) GetGlobalId() string { + return self.GetId() +} + +/* + ELASTIC_CACHE_BACKUP_STATUS_CREATING = "creating" // 备份中 + ELASTIC_CACHE_BACKUP_STATUS_CREATE_EXPIRED = "expired" //(备份文件已过期) + ELASTIC_CACHE_BACKUP_STATUS_CREATE_DELETED = "deleted" //(备份文件已删除) + ELASTIC_CACHE_BACKUP_STATUS_DELETING = "deleting" // 删除中 + ELASTIC_CACHE_BACKUP_STATUS_SUCCESS = "success" // 备份成功 + ELASTIC_CACHE_BACKUP_STATUS_FAILED = "failed" // 备份失败 +*/ +func (self *SElasticcacheBackup) GetStatus() string { + switch self.Status { + case 1: + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATING + case 2: + return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS + case -1: + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_EXPIRED + case -2: + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATE_DELETED + case 3: + return api.ELASTIC_CACHE_BACKUP_STATUS_CREATING + case 4: + return api.ELASTIC_CACHE_BACKUP_STATUS_SUCCESS + default: + return strconv.Itoa(self.Status) + } +} + +func (self *SElasticcacheBackup) Refresh() error { + backup, err := self.cacheDB.GetICloudElasticcacheBackup(self.GetGlobalId()) + if err != nil { + return errors.Wrap(err, "GetICloudElasticcacheBackup") + } + + err = jsonutils.Update(self, backup) + if err != nil { + return errors.Wrap(err, "Update") + } + + return nil +} + +func (self *SElasticcacheBackup) GetBackupSizeMb() int { + return 0 +} + +func (self *SElasticcacheBackup) GetBackupType() string { + return api.ELASTIC_CACHE_BACKUP_TYPE_INCREMENTAL +} + +func (self *SElasticcacheBackup) GetBackupMode() string { + switch self.BackupType { + case "1", "systemBackupInstance": + return api.ELASTIC_CACHE_BACKUP_MODE_AUTOMATED + case "0", "manualBackupInstance": + return api.ELASTIC_CACHE_BACKUP_MODE_MANUAL + default: + return self.BackupType + } +} + +// https://cloud.tencent.com/document/api/239/34443 +func (self *SElasticcacheBackup) GetDownloadURL() string { + url, err := self.GetBackupDownloadURL() + if err != nil { + log.Debugf("GetBackupDownloadURL %s", err) + return "" + } + + return url +} + +func (self *SElasticcacheBackup) GetStartTime() time.Time { + return self.StartTime +} + +func (self *SElasticcacheBackup) GetEndTime() time.Time { + return time.Time{} +} + +func (self *SElasticcacheBackup) Delete() error { + return errors.Wrap(cloudprovider.ErrNotSupported, "Delete") +} + +// https://cloud.tencent.com/document/product/239/34435 +// todo: password +func (self *SElasticcacheBackup) RestoreInstance(instanceId string) error { + params := map[string]string{} + params["InstanceId"] = instanceId + params["BackupId"] = self.GetId() + //if len(Password) > 0 { + // params["Password"] = Password + //} + + _, err := self.cacheDB.region.redisRequest("RestoreInstance", params) + if err != nil { + return errors.Wrap(err, "RestoreInstance") + } + + return nil +} + +func (self *SElasticcacheBackup) GetBackupDownloadURL() (string, error) { + params := map[string]string{} + params["InstanceId"] = self.cacheDB.GetId() + params["BackupId"] = self.GetId() + client := self.cacheDB.region.client + resp, err := client.redisRequest("DescribeBackupUrl", params) + if err != nil { + return "", errors.Wrap(err, "DescribeBackupUrl") + } + + urls := []string{} + err = resp.Unmarshal(&urls, "DownloadUrl") + if err != nil { + return "", errors.Wrap(err, "Unmarshal.DownloadUrl") + } + + if len(urls) > 0 { + return urls[0], nil + } + + return "", nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_instance.go new file mode 100644 index 0000000000..cc0e067ef5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_instance.go @@ -0,0 +1,1229 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strconv" + "strings" + "time" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SElasticcache struct { + multicloud.SElasticcacheBase + QcloudTags + region *SRegion + + ClientLimit int + ClientLimitMax int + ClientLimitMin int + MaintenanceTime *MaintenanceTime `json:"maintenance_time"` + NoAuth *bool `json:"no_auth"` + NodeSet []NodeSet `json:"NodeSet"` + Appid int64 `json:"Appid"` + AutoRenewFlag int64 `json:"AutoRenewFlag"` + BillingMode int64 `json:"BillingMode"` + CloseTime string `json:"CloseTime"` + Createtime time.Time `json:"Createtime"` + DeadlineTime string `json:"DeadlineTime"` + Engine string `json:"Engine"` + InstanceID string `json:"InstanceId"` + InstanceName string `json:"InstanceName"` + InstanceNode []interface{} `json:"InstanceNode"` + InstanceTitle string `json:"InstanceTitle"` + OfflineTime string `json:"OfflineTime"` + Port int `json:"Port"` + PriceID int64 `json:"PriceId"` + ProductType string `json:"ProductType"` + ProjectID int `json:"ProjectId"` + RedisReplicasNum int `json:"RedisReplicasNum"` + RedisShardNum int64 `json:"RedisShardNum"` + RedisShardSize int64 `json:"RedisShardSize"` // MB + DiskSize int64 `json:"disk_size"` + RegionID int64 `json:"RegionId"` + Size int `json:"Size"` + SizeUsed int64 `json:"SizeUsed"` + SlaveReadWeight int64 `json:"SlaveReadWeight"` + Status int `json:"Status"` + SubStatus int64 `json:"SubStatus"` + SubnetID int64 `json:"SubnetId"` + Type int `json:"Type"` + UniqSubnetID string `json:"UniqSubnetId"` + UniqVpcID string `json:"UniqVpcId"` + VpcID int64 `json:"VpcId"` + WANIP string `json:"WanIp"` + ZoneID int `json:"ZoneId"` +} + +func (self *SElasticcache) SetTags(tags map[string]string, replace bool) error { + return self.region.SetResourceTags("redis", "instance", []string{self.InstanceID}, tags, replace) +} + +type MaintenanceTime struct { + StartTime string `json:"start_time"` + EndTime string `json:"end_time"` +} + +type NodeSet struct { + NodeID int64 `json:"NodeId"` + NodeType int64 `json:"NodeType"` + ZoneID int64 `json:"ZoneId"` +} + +var zoneMaps = map[int]string{ + 100001: "ap-guangzhou-1", + 100002: "ap-guangzhou-2", + 100003: "ap-guangzhou-3", + 100004: "ap-guangzhou-4", + 100006: "ap-guangzhou-6", + 110001: "ap-shenzhen-fsi-1", + 110002: "ap-shenzhen-fsi-2", + 110003: "ap-shenzhen-fsi-3", + 200001: "ap-shanghai-1", + 200002: "ap-shanghai-2", + 200003: "ap-shanghai-3", + 200004: "ap-shanghai-4", + 200005: "ap-shanghai-5", + 200006: "ap-shanghai-6", + 200007: "ap-shanghai-7", + 700001: "ap-shanghai-fsi-1", + 700002: "ap-shanghai-fsi-2", + 700003: "ap-shanghai-fsi-3", + 330001: "ap-nanjing-1", + 330002: "ap-nanjing-2", + 330003: "ap-nanjing-3", + 800001: "ap-beijing-1", + 800002: "ap-beijing-2", + 800003: "ap-beijing-3", + 800004: "ap-beijing-4", + 800005: "ap-beijing-5", + 800006: "ap-beijing-6", + 800007: "ap-beijing-7", + 460001: "ap-beijing-fsi-1", + 360001: "ap-tianjin-1", + 360002: "ap-tianjin-2", + 160001: "ap-chengdu-1", + 160002: "ap-chengdu-2", + 190001: "ap-chongqing-1", + 300001: "ap-hongkong-1", + 300002: "ap-hongkong-2", + 300003: "ap-hongkong-3", + 390001: "ap-taipei-1", + 900001: "ap-singapore-1", + 230001: "ap-bangkok-1", + 210001: "ap-mumbai-1", + 210002: "ap-mumbai-2", + 180001: "ap-seoul-1", + 180002: "ap-seoul-2", + 250001: "ap-tokyo-1", + 150001: "na-siliconvalley-1", + 150002: "na-siliconvalley-2", + 220001: "na-ashburn-1", + 220002: "na-ashburn-2", + 400001: "na-toronto-1", + 170001: "eu-frankfurt-1", + 240001: "eu-moscow-1", +} + +var zoneIdMaps = map[string]int{ + "ap-guangzhou-1": 100001, + "ap-guangzhou-2": 100002, + "ap-guangzhou-3": 100003, + "ap-guangzhou-4": 100004, + "ap-guangzhou-6": 100006, + "ap-shenzhen-fsi-1": 110001, + "ap-shenzhen-fsi-2": 110002, + "ap-shenzhen-fsi-3": 110003, + "ap-shanghai-1": 200001, + "ap-shanghai-2": 200002, + "ap-shanghai-3": 200003, + "ap-shanghai-4": 200004, + "ap-shanghai-5": 200005, + "ap-shanghai-6": 200006, + "ap-shanghai-7": 200007, + "ap-shanghai-fsi-1": 700001, + "ap-shanghai-fsi-2": 700002, + "ap-shanghai-fsi-3": 700003, + "ap-nanjing-1": 330001, + "ap-nanjing-2": 330002, + "ap-nanjing-3": 330003, + "ap-beijing-1": 800001, + "ap-beijing-2": 800002, + "ap-beijing-3": 800003, + "ap-beijing-4": 800004, + "ap-beijing-5": 800005, + "ap-beijing-6": 800006, + "ap-beijing-7": 800007, + "ap-beijing-fsi-1": 460001, + "ap-tianjin-1": 360001, + "ap-tianjin-2": 360002, + "ap-chengdu-1": 160001, + "ap-chengdu-2": 160002, + "ap-chongqing-1": 190001, + "ap-hongkong-1": 300001, + "ap-hongkong-2": 300002, + "ap-hongkong-3": 300003, + "ap-taipei-1": 390001, + "ap-singapore-1": 900001, + "ap-bangkok-1": 230001, + "ap-mumbai-1": 210001, + "ap-mumbai-2": 210002, + "ap-seoul-1": 180001, + "ap-seoul-2": 180002, + "ap-tokyo-1": 250001, + "na-siliconvalley-1": 150001, + "na-siliconvalley-2": 150002, + "na-ashburn-1": 220001, + "na-ashburn-2": 220002, + "na-toronto-1": 400001, + "eu-frankfurt-1": 170001, + "eu-moscow-1": 240001, +} + +func (self *SElasticcache) GetId() string { + return self.InstanceID +} + +func (self *SElasticcache) GetName() string { + return self.InstanceName +} + +func (self *SElasticcache) GetGlobalId() string { + return self.GetId() +} + +// https://cloud.tencent.com/document/api/239/20022#InstanceSet +// 实例当前状态,0:待初始化;1:实例在流程中;2:实例运行中;-2:实例已隔离;-3:实例待删除 +func (self *SElasticcache) GetStatus() string { + switch self.Status { + case 2: + return api.ELASTIC_CACHE_STATUS_RUNNING + case 0: + return api.ELASTIC_CACHE_STATUS_DEPLOYING + case -3: + return api.ELASTIC_CACHE_STATUS_RELEASING + case -2: + return api.ELASTIC_CACHE_STATUS_UNAVAILABLE + case 1: + return api.ELASTIC_CACHE_STATUS_CHANGING + } + + return "" +} + +func (self *SElasticcache) GetConnections() int { + return self.ClientLimit +} + +func (self *SElasticcache) Refresh() error { + cache, err := self.region.GetIElasticcacheById(self.GetId()) + if err != nil { + return errors.Wrap(err, "Elasticcache.Refresh.GetElasticCache") + } + + err = jsonutils.Update(self, cache) + if err != nil { + return errors.Wrap(err, "Elasticcache.Refresh.Update") + } + + return nil +} + +func (self *SElasticcache) IsEmulated() bool { + return false +} + +func (self *SElasticcache) GetProjectId() string { + return strconv.Itoa(self.ProjectID) +} + +func (self *SElasticcache) GetBillingType() string { + // 计费模式:0-按量计费,1-包年包月 + if self.BillingMode == 1 { + return billing_api.BILLING_TYPE_PREPAID + } else { + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SElasticcache) GetCreatedAt() time.Time { + return self.Createtime +} + +func (self *SElasticcache) GetExpiredAt() time.Time { + if self.DeadlineTime == "0000-00-00 00:00:00" || len(self.DeadlineTime) == 0 { + return time.Time{} + } + + t, err := time.Parse("2006-01-02 15:04:05", self.DeadlineTime) + if err != nil { + log.Debugf("GetExpiredAt.Parse %s", err) + return time.Time{} + } + + return t +} + +// https://cloud.tencent.com/document/product/239/31785 +func (self *SElasticcache) SetAutoRenew(bc billing.SBillingCycle) error { + params := map[string]string{} + params["Operation"] = "modifyAutoRenew" + params["InstanceIds.0"] = self.GetId() + if bc.AutoRenew { + params["AutoRenews.0"] = "1" + } else { + params["AutoRenews.0"] = "0" + } + + _, err := self.region.redisRequest("ModifyInstance", params) + if err != nil { + return errors.Wrap(err, "ModifyInstance") + } + + return nil +} + +func (self *SElasticcache) IsAutoRenew() bool { + // 实例是否设置自动续费标识,1:设置自动续费;0:未设置自动续费 + return self.AutoRenewFlag == 1 +} + +// redis:master:s1:r5:m1g:v4.0 +// 实例类型:2 – Redis2.8内存版(标准架构),3 – CKV 3.2内存版(标准架构),4 – CKV 3.2内存版(集群架构) +// ,6 – Redis4.0内存版(标准架构),7 – Redis4.0内存版(集群架构), +// 8 – Redis5.0内存版(标准架构),9 – Redis5.0内存版(集群架构) +func (self *SElasticcache) GetInstanceType() string { + segs := make([]string, 6) + segs[0] = "redis" + switch self.Type { + case 2, 3, 6, 8: + segs[1] = "master" + case 4, 7, 9, 10: + segs[1] = "cluster" + case 5: + segs[1] = "single" + default: + segs[1] = strconv.Itoa(self.Type) + } + + segs[2] = fmt.Sprintf("s%d", self.RedisShardNum) + segs[3] = fmt.Sprintf("r%d", self.RedisReplicasNum) + if self.DiskSize > 0 { + segs[4] = fmt.Sprintf("m%dg-d%dg", self.Size/1024, self.DiskSize) + } else { + segs[4] = fmt.Sprintf("m%dg", self.Size/1024) + } + segs[5] = fmt.Sprintf("v%s", self.GetEngineVersion()) + + return strings.Join(segs, ":") +} + +func (self *SElasticcache) GetCapacityMB() int { + return self.Size +} + +func (self *SElasticcache) GetArchType() string { + // 产品类型:standalone – 标准版,cluster – 集群版 + switch self.ProductType { + case "standalone": + return api.ELASTIC_CACHE_ARCH_TYPE_MASTER + case "cluster": + return api.ELASTIC_CACHE_ARCH_TYPE_CLUSTER + } + + return "" +} + +func (self *SElasticcache) GetNodeType() string { + // single(单副本) | double(双副本) + switch self.RedisReplicasNum { + case 1: + return "single" + case 2: + return "double" + case 3: + return "three" + case 4: + return "four" + case 5: + return "five" + case 6: + return "six" + } + + return strconv.Itoa(self.RedisReplicasNum) +} + +func (self *SElasticcache) GetEngine() string { + return api.ELASTIC_CACHE_ENGINE_REDIS +} + +func (self *SElasticcache) GetEngineVersion() string { + switch self.Type { + case 1, 2, 5: + return "2.8" + case 3, 4: + return "3.2" + case 6, 7, 10: + return "4.0" + case 8, 9: + return "5.0" + } + + return "unknown" +} + +func (self *SElasticcache) GetVpcId() string { + return self.UniqVpcID +} + +// https://cloud.tencent.com/document/product/239/4106 +func (self *SElasticcache) GetZoneId() string { + zone := zoneMaps[self.ZoneID] + if len(zone) == 0 { + net, err := self.region.GetNetwork(self.UniqSubnetID) + if err != nil { + log.Warningf("zone %d not found. zone map needed update.", self.ZoneID) + log.Debugf("GetNetwork %s %s", self.UniqSubnetID, err) + return "" + } + + zone = net.Zone + } + + z, err := self.region.getZoneById(zone) + if err != nil { + log.Debugf("getZoneById %s", err) + return "" + } + + return z.GetGlobalId() +} + +func (self *SElasticcache) GetNetworkType() string { + if len(self.UniqVpcID) > 0 { + return api.LB_NETWORK_TYPE_VPC + } else { + return api.LB_NETWORK_TYPE_CLASSIC + } +} + +func (self *SElasticcache) GetNetworkId() string { + return self.UniqSubnetID +} + +func (self *SElasticcache) GetPrivateDNS() string { + return self.WANIP +} + +func (self *SElasticcache) GetPrivateIpAddr() string { + return self.WANIP +} + +func (self *SElasticcache) GetPrivateConnectPort() int { + return self.Port +} + +func (self *SElasticcache) GetPublicDNS() string { + return "" +} + +func (self *SElasticcache) GetPublicIpAddr() string { + return "" +} + +func (self *SElasticcache) GetPublicConnectPort() int { + return self.Port +} + +// https://cloud.tencent.com/document/api/239/46336 +func (self *SElasticcache) getMaintenanceTime() error { + params := map[string]string{} + params["InstanceId"] = self.GetId() + params["Region"] = self.region.GetId() + resp, err := self.region.client.redisRequest("DescribeMaintenanceWindow", params) + if err != nil { + return errors.Wrap(err, "DescribeMaintenanceWindow") + } + + self.MaintenanceTime = &MaintenanceTime{} + err = resp.Unmarshal(self.MaintenanceTime) + if err != nil { + return errors.Wrap(err, "err.MaintenanceTime") + } + + return nil +} + +func (self *SElasticcache) GetMaintainStartTime() string { + if self.MaintenanceTime == nil { + if err := self.getMaintenanceTime(); err != nil { + log.Debugf("getMaintenanceTime %s", err) + return "" + } + } + + return self.MaintenanceTime.StartTime +} + +func (self *SElasticcache) GetMaintainEndTime() string { + if self.MaintenanceTime == nil { + if err := self.getMaintenanceTime(); err != nil { + log.Debugf("getMaintenanceTime %s", err) + return "" + } + } + + return self.MaintenanceTime.EndTime +} + +func (self *SElasticcache) GetAuthMode() string { + if self.NoAuth != nil && *self.NoAuth == false { + return "on" + } + + return "off" +} + +func (self *SElasticcache) GetSecurityGroupIds() ([]string, error) { + ss, err := self.region.GetCloudElasticcacheSecurityGroups(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "GetCloudElasticcacheSecurityGroups") + } + + ret := make([]string, len(ss)) + for i := range ss { + ret[i] = ss[i].SecurityGroupID + } + + return ret, nil +} + +func (self *SElasticcache) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { + accounts, err := self.getCloudElasticcacheAccounts() + if err != nil { + return nil, errors.Wrap(err, "GetCloudElasticcacheAccounts") + } + + iaccounts := make([]cloudprovider.ICloudElasticcacheAccount, len(accounts)) + for i := range accounts { + account := accounts[i] + account.cacheDB = self + iaccounts[i] = &account + } + + return iaccounts, nil +} + +func (self *SElasticcache) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { + backups, err := self.region.GetCloudElasticcacheBackups(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "GetCloudElasticcacheBackups") + } + + ibackups := make([]cloudprovider.ICloudElasticcacheBackup, len(backups)) + for i := range backups { + backup := backups[i] + backup.cacheDB = self + ibackups[i] = &backup + } + + return ibackups, nil +} + +func (self *SElasticcache) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { + parameters, err := self.region.GetCloudElasticcacheParameters(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "GetCloudElasticcacheParameters") + } + + ret := []cloudprovider.ICloudElasticcacheParameter{} + for i := range parameters { + parameter := parameters[i] + parameter.cacheDB = self + ret = append(ret, ¶meter) + } + + return ret, nil +} + +func (self *SElasticcache) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { + accounts, err := self.getCloudElasticcacheAccounts() + if err != nil { + return nil, errors.Wrap(err, "GetCloudElasticcacheAccounts") + } + + for i := range accounts { + account := accounts[i] + if account.GetGlobalId() == accountId { + account.cacheDB = self + return &account, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SElasticcache) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SElasticcache) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { + backups, err := self.region.GetCloudElasticcacheBackups(self.InstanceID) + if err != nil { + return nil, errors.Wrap(err, "GetCloudElasticcacheBackups") + } + + for i := range backups { + backup := backups[i] + if backup.GetGlobalId() == backupId { + backup.cacheDB = self + return &backup, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SElasticcache) GetICloudElasticcacheBackupByReadmark(readmark string) (cloudprovider.ICloudElasticcacheBackup, error) { + backups, err := self.region.GetCloudElasticcacheBackups(self.InstanceID) + if err != nil { + return nil, errors.Wrap(err, "GetCloudElasticcacheBackups") + } + + for i := range backups { + backup := backups[i] + if backup.Remark == readmark { + backup.cacheDB = self + return &backup, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SElasticcache) Restart() error { + return errors.Wrap(cloudprovider.ErrNotSupported, "Restart") +} + +// https://cloud.tencent.com/document/product/239/34440 +func (self *SElasticcache) Delete() error { + requiredStatus := "" + if self.GetBillingType() == billing_api.BILLING_TYPE_POSTPAID { + if err := self.DestroyPostpaidInstance(); err != nil { + return errors.Wrap(err, "DestroyPostpaidInstance") + } + + requiredStatus = api.ELASTIC_CACHE_STATUS_RELEASING + } else { + if err := self.DestroyPrepaidInstance(); err != nil { + return errors.Wrap(err, "DestroyPrepaidInstance") + } + + requiredStatus = api.ELASTIC_CACHE_STATUS_UNAVAILABLE + } + + err := cloudprovider.WaitStatus(self, requiredStatus, 5*time.Second, 300*time.Second) + if err != nil { + return errors.Wrap(err, fmt.Sprintf("WaitStatus.%s", requiredStatus)) + } + + err = self.CleanupInstance() + if err != nil { + return errors.Wrap(err, "CleanupInstance") + } + + return nil +} + +// https://cloud.tencent.com/document/product/239/34439 +func (self *SElasticcache) DestroyPrepaidInstance() error { + if self.GetStatus() == api.ELASTIC_CACHE_STATUS_UNAVAILABLE { + return nil + } + + params := map[string]string{} + params["InstanceId"] = self.GetId() + _, err := self.region.redisRequest("DestroyPrepaidInstance", params) + if err != nil { + return errors.Wrap(err, "DestroyPrepaidInstance") + } + + return nil +} + +// https://cloud.tencent.com/document/product/239/34439 +func (self *SElasticcache) DestroyPostpaidInstance() error { + if self.GetStatus() == api.ELASTIC_CACHE_STATUS_RELEASING { + return nil + } + + params := map[string]string{} + params["InstanceId"] = self.GetId() + _, err := self.region.redisRequest("DestroyPostpaidInstance", params) + if err != nil { + return errors.Wrap(err, "DestroyPostpaidInstance") + } + + return nil +} + +// https://cloud.tencent.com/document/product/239/34442 +func (self *SElasticcache) CleanupInstance() error { + params := map[string]string{} + params["InstanceId"] = self.GetId() + _, err := self.region.redisRequest("CleanUpInstance", params) + if err != nil { + return errors.Wrap(err, "CleanUpInstance") + } + + return nil +} + +// https://cloud.tencent.com/document/product/239/20013 +func (self *SElasticcache) ChangeInstanceSpec(spec string) error { + s, err := parseLocalInstanceSpec(spec) + if err != nil { + return errors.Wrap(err, "parseLocalInstanceSpec") + } + + params := map[string]string{} + params["InstanceId"] = self.GetId() + params["MemSize"] = fmt.Sprintf("%d", s.MemSizeMB) + params["RedisShardNum"] = s.RedisShardNum + params["RedisReplicasNum"] = s.RedisReplicasNum + _, err = self.region.redisRequest("UpgradeInstance", params) + if err != nil { + return errors.Wrap(err, "UpgradeInstance") + } + + return nil +} + +// https://cloud.tencent.com/document/product/239/46335 +func (self *SElasticcache) SetMaintainTime(maintainStartTime, maintainEndTime string) error { + params := map[string]string{} + params["InstanceId"] = self.GetId() + params["StartTime"] = maintainStartTime + params["EndTime"] = maintainEndTime + _, err := self.region.redisRequest("ModifyMaintenanceWindow", params) + if err != nil { + return errors.Wrap(err, "ModifyMaintenanceWindow") + } + + return nil +} + +func (self *SElasticcache) AllocatePublicConnection(port int) (string, error) { + return "", errors.Wrap(cloudprovider.ErrNotSupported, "AllocatePublicConnection") +} + +func (self *SElasticcache) ReleasePublicConnection() error { + return errors.Wrap(cloudprovider.ErrNotSupported, "ReleasePublicConnection") +} + +// https://cloud.tencent.com/document/product/239/38926 +func (self *SElasticcache) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { + params := map[string]string{} + params["InstanceId"] = self.GetId() + params["AccountName"] = account.AccountName + params["AccountPassword"] = account.AccountPassword + params["Privilege"] = account.AccountPrivilege + params["ReadonlyPolicy.0"] = "master" + if len(account.Description) > 0 { + params["Remark"] = account.Description + } + + _, err := self.region.redisRequest("CreateInstanceAccount", params) + if err != nil { + return nil, errors.Wrap(err, "CreateInstanceAccount") + } + + accountId := "" + cloudprovider.Wait(5*time.Second, 60*time.Second, func() (bool, error) { + accounts, err := self.GetICloudElasticcacheAccounts() + if err != nil { + log.Debugf("GetICloudElasticcacheAccounts %s", err) + return false, nil + } + + for i := range accounts { + if accounts[i].GetName() == account.AccountName { + accountId = accounts[i].GetGlobalId() + return true, nil + } + } + + return false, nil + }) + + return self.GetICloudElasticcacheAccount(accountId) +} + +func (self *SElasticcache) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, errors.Wrap(cloudprovider.ErrNotSupported, "CreateAcl") +} + +// https://cloud.tencent.com/document/product/239/20010 +func (self *SElasticcache) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { + readmark := strings.Join([]string{desc, fmt.Sprintf("%d", time.Now().Unix())}, "@") + params := map[string]string{} + params["InstanceId"] = self.GetId() + params["Remark"] = readmark + resp, err := self.region.redisRequest("ManualBackupInstance", params) + if err != nil { + return nil, errors.Wrap(err, "ManualBackupInstance") + } + + taskId := 0 + err = resp.Unmarshal(&taskId, "TaskId") + if err != nil { + return nil, errors.Wrap(err, "Unmarshal") + } + + var task *SElasticcacheTask + err = cloudprovider.Wait(5*time.Second, 900*time.Second, func() (bool, error) { + task, err = self.region.DescribeTaskInfo(fmt.Sprintf("%d", taskId)) + if err != nil { + return false, nil + } + + if task != nil { + if task.Status == "failed" || task.Status == "error" { + return false, fmt.Errorf("CreateBackup failed %#v", task) + } + + if task.Status == "succeed" { + return true, nil + } + } + + return false, nil + }) + if err != nil { + return nil, errors.Wrap(err, "Wait.DescribeTaskInfo") + } + + if task == nil { + return nil, fmt.Errorf("CreateBackup failed task is empty") + } + + return self.GetICloudElasticcacheBackupByReadmark(readmark) +} + +// https://cloud.tencent.com/document/product/239/20021 +func (self *SElasticcache) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { + params := map[string]string{} + params["InstanceId"] = self.GetId() + if self.NoAuth != nil && *self.NoAuth == false { + if len(input.Password) > 0 { + params["Password"] = input.Password + } else { + return fmt.Errorf("password required on auth mode while flush elastich cache instance") + } + } + _, err := self.region.redisRequest("ClearInstance", params) + if err != nil { + return errors.Wrap(err, "ClearInstance") + } + + return nil +} + +// https://cloud.tencent.com/document/product/239/38923 +// https://cloud.tencent.com/document/product/239/20014 +// true表示将主账号切换为免密账号,这里只适用于主账号,子账号不可免密 +func (self *SElasticcache) UpdateAuthMode(noPasswordAccess bool, password string) error { + params := map[string]string{} + params["InstanceId"] = self.GetId() + if noPasswordAccess { + params["NoAuth"] = "true" + } else { + params["NoAuth"] = "false" + params["Password"] = password + } + + _, err := self.region.redisRequest("ResetPassword", params) + if err != nil { + return errors.Wrap(err, "ResetPassword") + } + + return nil +} + +// https://cloud.tencent.com/document/product/239/34445 +// todo: finish me +func (self *SElasticcache) UpdateInstanceParameters(config jsonutils.JSONObject) error { + params := map[string]string{} + params["InstanceId"] = self.GetId() + params["InstanceParams.0"] = config.String() + _, err := self.region.redisRequest("ModifyInstanceParams", params) + if err != nil { + return errors.Wrap(err, "ModifyInstanceParams") + } + + return nil +} + +func (self *SElasticcache) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { + panic("implement me") +} + +func (self *SElasticcache) getCloudElasticcacheAccounts() ([]SElasticcacheAccount, error) { + if self.GetEngineVersion() == "2.8" || (self.NodeSet != nil && len(self.NodeSet) > 0) { + account := SElasticcacheAccount{} + account.cacheDB = self + account.AccountName = "root" + account.InstanceID = self.GetId() + account.Privilege = "rw" + account.Status = 2 + account.IsEmulate = true + + return []SElasticcacheAccount{account}, nil + } + + accounts, err := self.region.GetCloudElasticcacheAccounts(self.GetId()) + if err != nil { + return nil, errors.Wrap(err, "GetCloudElasticcacheAccounts") + } + + for i := range accounts { + accounts[i].cacheDB = self + } + + return accounts, nil +} + +// https://cloud.tencent.com/document/api/239/38924 +func (self *SElasticcache) getCloudElasticcacheAccount(accountName string) (*SElasticcacheAccount, error) { + accounts, err := self.getCloudElasticcacheAccounts() + if err != nil { + return nil, errors.Wrap(err, "GetCloudElasticcacheAccounts") + } + + for i := range accounts { + if accounts[i].AccountName == accountName { + accounts[i].cacheDB = self + return &accounts[i], nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +// https://cloud.tencent.com/document/api/239/41256 +func (self *SElasticcache) UpdateSecurityGroups(secgroupIds []string) error { + params := map[string]string{} + params["InstanceId"] = self.GetId() + params["Product"] = "redis" + for i := range secgroupIds { + params[fmt.Sprintf("SecurityGroupIds.%d", i)] = secgroupIds[i] + } + + _, err := self.region.redisRequest("ModifyDBInstanceSecurityGroups", params) + if err != nil { + return errors.Wrap(err, "ModifyDBInstanceSecurityGroups") + } + + return nil +} + +func (self *SElasticcache) Renew(bc billing.SBillingCycle) error { + month := bc.GetMonths() + if month <= 0 { + return errors.Wrap(fmt.Errorf("month should great than 0"), "GetMonths") + } + + params := map[string]string{} + params["InstanceId"] = self.GetId() + params["Period"] = fmt.Sprintf("%d", month) + _, err := self.region.redisRequest("RenewInstance", params) + if err != nil { + return errors.Wrap(err, "RenewInstance") + } + + return nil +} + +// https://cloud.tencent.com/document/api/239/38924 +func (self *SRegion) GetCloudElasticcacheAccounts(instanceId string) ([]SElasticcacheAccount, error) { + params := map[string]string{} + params["Region"] = self.GetId() + params["InstanceId"] = instanceId + params["Limit"] = "20" + params["Offset"] = "0" + + ret := []SElasticcacheAccount{} + offset := 0 + for { + resp, err := self.client.redisRequest("DescribeInstanceAccount", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeInstanceAccount") + } + + _ret := []SElasticcacheAccount{} + err = resp.Unmarshal(&_ret, "Accounts") + if err != nil { + return nil, errors.Wrap(err, "Unmarshal") + } else { + ret = append(ret, _ret...) + } + + if len(_ret) < 20 { + break + } else { + offset += 20 + params["Offset"] = strconv.Itoa(offset) + } + } + + return ret, nil +} + +// https://cloud.tencent.com/document/api/239/20011 +func (self *SRegion) GetCloudElasticcacheBackups(instanceId string) ([]SElasticcacheBackup, error) { + params := map[string]string{} + params["Region"] = self.GetId() + params["InstanceId"] = instanceId + params["Limit"] = "20" + params["Offset"] = "0" + + ret := []SElasticcacheBackup{} + offset := 0 + for { + resp, err := self.client.redisRequest("DescribeInstanceBackups", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeInstanceBackups") + } + + _ret := []SElasticcacheBackup{} + err = resp.Unmarshal(&_ret, "BackupSet") + if err != nil { + return nil, errors.Wrap(err, "Unmarshal") + } else { + ret = append(ret, _ret...) + } + + if len(_ret) < 20 { + break + } else { + offset += 20 + params["Offset"] = strconv.Itoa(offset) + } + } + + return ret, nil +} + +// https://cloud.tencent.com/document/api/239/41259 +func (self *SRegion) GetCloudElasticcacheSecurityGroups(instanceId string) ([]SElasticcacheSecgroup, error) { + params := map[string]string{} + params["Region"] = self.GetId() + params["InstanceId"] = instanceId + params["Product"] = "redis" + resp, err := self.client.redisRequest("DescribeDBSecurityGroups", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeDBSecurityGroups") + } + + ret := []SElasticcacheSecgroup{} + err = resp.Unmarshal(&ret, "Groups") + if err != nil { + return nil, errors.Wrap(err, "Unmarshal") + } + + return ret, nil +} + +// https://cloud.tencent.com/document/api/239/34448 +func (self *SRegion) GetCloudElasticcacheParameters(instanceId string) ([]SElasticcacheParameter, error) { + params := map[string]string{} + params["Region"] = self.GetId() + params["InstanceId"] = instanceId + resp, err := self.client.redisRequest("DescribeInstanceParams", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeInstanceParams") + } + + ret1 := []SElasticcacheParameter{} + err = resp.Unmarshal(&ret1, "InstanceEnumParam") + if err != nil { + return nil, errors.Wrap(err, "InstanceEnumParam") + } + + ret2 := []SElasticcacheParameter{} + err = resp.Unmarshal(&ret2, "InstanceIntegerParam") + if err != nil { + return nil, errors.Wrap(err, "InstanceIntegerParam") + } + + ret3 := []SElasticcacheParameter{} + err = resp.Unmarshal(&ret3, "InstanceMultiParam") + if err != nil { + return nil, errors.Wrap(err, "InstanceMultiParam") + } + + ret4 := []SElasticcacheParameter{} + err = resp.Unmarshal(&ret4, "InstanceTextParam") + if err != nil { + return nil, errors.Wrap(err, "InstanceTextParam") + } + + ret := []SElasticcacheParameter{} + ret = append(ret, ret1...) + ret = append(ret, ret2...) + ret = append(ret, ret3...) + ret = append(ret, ret4...) + return ret, nil +} + +// https://cloud.tencent.com/document/api/239/20018 +func (self *SRegion) GetCloudElasticcaches(instanceId string) ([]SElasticcache, error) { + params := map[string]string{} + params["Region"] = self.GetId() + params["Limit"] = "20" + params["Offset"] = "0" + + if len(instanceId) > 0 { + params["InstanceId"] = instanceId + } + + ret := []SElasticcache{} + offset := 0 + for { + resp, err := self.client.redisRequest("DescribeInstances", params) + if err != nil { + return nil, errors.Wrap(err, "DescribeInstances") + } + + _ret := []SElasticcache{} + err = resp.Unmarshal(&_ret, "InstanceSet") + if err != nil { + return nil, errors.Wrap(err, "Unmarshal") + } else { + ret = append(ret, _ret...) + } + + if len(_ret) < 20 { + break + } else { + offset += 20 + params["Offset"] = strconv.Itoa(offset) + } + } + + return ret, nil +} + +type elasticcachInstanceSpec struct { + TypeId string `json:"type_id"` + MemSizeMB int `json:"mem_size_mb"` + DiskSizeGB int `json:"disk_size_gb"` + RedisShardNum string `json:"redis_shard_num"` + RedisReplicasNum string `json:"redis_replicas_num"` +} + +// redis:master:s1:r5:m1g:v4.0 +func parseLocalInstanceSpec(s string) (elasticcachInstanceSpec, error) { + ret := elasticcachInstanceSpec{} + segs := strings.Split(s, ":") + if len(segs) != 6 { + return ret, fmt.Errorf("invalid instance spec %s", s) + } + if segs[1] == "master" { + switch segs[5] { + case "v2.8": + ret.TypeId = "2" + case "v3.2": + ret.TypeId = "3" + case "v4.0": + ret.TypeId = "6" + case "v5.0": + ret.TypeId = "8" + default: + return ret, fmt.Errorf("unknown master elastic cache version %s", segs[1]) + } + } else if segs[1] == "cluster" { + switch segs[5] { + case "v3.0": + ret.TypeId = "4" + case "v4.0": + ret.TypeId = "7" + case "v5.0": + if strings.Contains(segs[4], "-d") { + ret.TypeId = "10" + } else { + ret.TypeId = "9" + } + + default: + return ret, fmt.Errorf("unknown cluster elastic cache version %s", segs[1]) + } + } else if segs[1] == "single" { + switch segs[5] { + case "v2.8": + ret.TypeId = "5" + default: + return ret, fmt.Errorf("unknown single elastic cache version %s", segs[1]) + } + } else { + return ret, fmt.Errorf("unknown elastic cache type %s", segs[1]) + } + + // + sizes := strings.Split(segs[4], "-") + if len(sizes) == 2 { + ms, err := strconv.Atoi(strings.Trim(sizes[1], "dg")) + if err != nil { + return ret, errors.Wrap(err, "Atoi") + } + + ret.DiskSizeGB = ms + } + + sn, err := strconv.Atoi(strings.Trim(segs[2], "s")) + if err != nil { + return ret, errors.Wrap(err, "RedisShardNum") + } + + ms, err := strconv.Atoi(strings.Trim(sizes[0], "mdg")) + if err != nil { + return ret, errors.Wrap(err, "Atoi") + } + if strings.HasSuffix(sizes[0], "g") { + ret.MemSizeMB = ms * 1024 / sn + } else if strings.HasSuffix(sizes[0], "m") { + ret.MemSizeMB = ms / sn + } + + ret.RedisShardNum = strings.Trim(segs[2], "s") + ret.RedisReplicasNum = strings.Trim(segs[3], "r") + return ret, nil +} diff --git a/pkg/multicloud/qcloud/elasticcache_parameters.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_parameters.go similarity index 95% rename from pkg/multicloud/qcloud/elasticcache_parameters.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_parameters.go index 357f988a84..703321af45 100644 --- a/pkg/multicloud/qcloud/elasticcache_parameters.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_parameters.go @@ -17,13 +17,13 @@ package qcloud import ( "fmt" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SElasticcacheParameters struct { multicloud.SElasticcacheParameterBase - multicloud.QcloudTags + QcloudTags cacheDB *SElasticcache @@ -36,7 +36,7 @@ type SElasticcacheParameters struct { type SElasticcacheParameter struct { multicloud.SElasticcacheParameterBase - multicloud.QcloudTags + QcloudTags cacheDB *SElasticcache diff --git a/pkg/multicloud/qcloud/elasticcache_secgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_secgroup.go similarity index 96% rename from pkg/multicloud/qcloud/elasticcache_secgroup.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_secgroup.go index f332b00f97..996429edca 100644 --- a/pkg/multicloud/qcloud/elasticcache_secgroup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_secgroup.go @@ -14,7 +14,7 @@ package qcloud -import "yunion.io/x/onecloud/pkg/multicloud" +import "yunion.io/x/cloudmux/pkg/multicloud" type SElasticcacheSecgroup struct { multicloud.SElasticcacheBackupBase diff --git a/pkg/multicloud/qcloud/elasticcache_task.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_task.go similarity index 100% rename from pkg/multicloud/qcloud/elasticcache_task.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/elasticcache_task.go diff --git a/pkg/multicloud/qcloud/errors.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/errors.go similarity index 100% rename from pkg/multicloud/qcloud/errors.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/errors.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/events.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/events.go new file mode 100644 index 0000000000..c149e0c1f9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/events.go @@ -0,0 +1,158 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SEvent struct { + region *SRegion + AccountID int64 + CloudAuditEvent string + ErrorCode int + EventId string + EventName string + EventNameCn string + EventRegion string + EventSource string + EventTime int64 + RequestID string + ResourceRegion string + ResourceTypeCn string + Resources map[string]string + SecretId string + SourceIPAddress string + Username string +} + +func (event *SEvent) GetName() string { + if resourceName, ok := event.Resources["ResourceName"]; ok && len(resourceName) > 0 { + return resourceName + } + return event.EventName +} + +func (event *SEvent) GetService() string { + return event.ResourceTypeCn +} + +func (event *SEvent) GetAction() string { + return event.EventName +} + +func (event *SEvent) GetResourceType() string { + if resourceType, ok := event.Resources["ResourceType"]; ok { + return resourceType + } + return "" +} + +func (event *SEvent) GetRequest() jsonutils.JSONObject { + return jsonutils.Marshal(event) +} + +func (event *SEvent) GetRequestId() string { + return event.RequestID +} + +func (event *SEvent) GetAccount() string { + if len(event.SecretId) > 0 { + return event.SecretId + } + return event.Username +} + +func (event *SEvent) IsSuccess() bool { + return event.ErrorCode == 0 +} + +func (event *SEvent) GetCreatedAt() time.Time { + return time.Unix(event.EventTime, 0) +} + +func (region *SRegion) GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]cloudprovider.ICloudEvent, error) { + events, err := region.GetEvents(start, end) + if err != nil { + return nil, err + } + iEvents := []cloudprovider.ICloudEvent{} + for i := range events { + if withReadEvent || !strings.Contains(events[i].CloudAuditEvent, `"Read"`) { + iEvents = append(iEvents, &events[i]) + } + } + return iEvents, nil +} + +func (region *SRegion) GetEvents(start time.Time, end time.Time) ([]SEvent, error) { + var ( + events []SEvent + nextToken string + err error + _events []SEvent + ) + for { + _events, nextToken, err = region.getEvents(start, end, nextToken) + if err != nil { + return nil, err + } + if len(nextToken) == 0 { + break + } + events = append(events, _events...) + } + return events, nil +} + +func (region *SRegion) getEvents(start time.Time, end time.Time, nextToken string) ([]SEvent, string, error) { + params := map[string]string{} + if start.IsZero() { + start = time.Now().AddDate(0, 0, -7) + } + if end.IsZero() { + end = time.Now() + } + params["StartTime"] = fmt.Sprintf("%d", start.Unix()) + params["EndTime"] = fmt.Sprintf("%d", end.Unix()) + params["MaxResults"] = "50" + if len(nextToken) > 0 { + params["NextToken"] = nextToken + } + + body, err := region.auditRequest("LookUpEvents", params) + if err != nil { + return nil, "", err + } + + events := []SEvent{} + + err = body.Unmarshal(&events, "Events") + if err != nil { + return nil, "", errors.Wrap(err, "body.Unmarshal") + } + nextToken, _ = body.GetString("NextToken") + if over, _ := body.Bool("ListOver"); over { + nextToken = "" + } + return events, nextToken, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/host.go new file mode 100644 index 0000000000..221dfe8cb3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/host.go @@ -0,0 +1,289 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone +} + +func (self *SHost) GetId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) +} + +func (self *SHost) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +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(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + vmId, err := self._createVM(desc.Name, desc.Hostname, desc.ExternalImageId, + desc.SysDisk, desc.Cpu, desc.MemoryMB, + desc.InstanceType, desc.ExternalNetworkId, + desc.IpAddr, desc.Description, desc.Password, + desc.DataDisks, desc.PublicKey, desc.ExternalSecgroupId, + desc.UserData, desc.BillingCycle, desc.ProjectId, desc.PublicIpBw, desc.PublicIpChargeType, desc.Tags, desc.OsType) + 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, hostname string, imgId string, sysDisk cloudprovider.SDiskInfo, cpu int, memMB int, instanceType string, + networkId string, ipAddr string, desc string, passwd string, + diskSizes []cloudprovider.SDiskInfo, publicKey string, secgroupId string, userData string, bc *billing.SBillingCycle, projectId string, + publicIpBw int, publicIpChargeType cloudprovider.TElasticipChargeType, + tags map[string]string, osType string, +) (string, error) { + net := self.zone.getNetworkById(networkId) + if net == nil { + return "", fmt.Errorf("invalid network ID %s", networkId) + } + + var err error + + keypair := "" + if len(publicKey) > 0 { + keypair, err = self.zone.region.syncKeypair(publicKey) + if err != nil { + return "", err + } + } + + img, err := self.zone.region.GetImage(imgId) + if err != nil { + return "", errors.Wrapf(err, "GetImage(%s)", imgId) + } + if img.ImageState != ImageStatusNormal && img.ImageState != ImageStatusUsing { + return "", fmt.Errorf("image %s not ready status is %s", imgId, img.ImageState) + } + + err = self.zone.validateStorageType(sysDisk.StorageType) + if err != nil { + return "", fmt.Errorf("Storage %s not avaiable: %s", sysDisk.StorageType, err) + } + + disks := make([]SDisk, len(diskSizes)+1) + disks[0].DiskSize = img.ImageSize + if sysDisk.SizeGB > 0 && sysDisk.SizeGB > img.ImageSize { + disks[0].DiskSize = sysDisk.SizeGB + } + if disks[0].DiskSize < 50 { + disks[0].DiskSize = 50 + } + disks[0].DiskType = strings.ToUpper(sysDisk.StorageType) + + for i, dataDisk := range diskSizes { + disks[i+1].DiskSize = dataDisk.SizeGB + err = self.zone.validateStorageType(dataDisk.StorageType) + if err != nil { + return "", fmt.Errorf("Storage %s not avaiable: %s", dataDisk.StorageType, err) + } + disks[i+1].DiskType = strings.ToUpper(dataDisk.StorageType) + } + + if len(instanceType) > 0 { + log.Debugf("Try instancetype : %s", instanceType) + vmId, err := self.zone.region.CreateInstance(name, hostname, imgId, instanceType, secgroupId, self.zone.Zone, desc, passwd, disks, networkId, ipAddr, keypair, userData, bc, projectId, publicIpBw, publicIpChargeType, tags, osType) + if err != nil { + return "", errors.Wrapf(err, "Failed to create specification %s", instanceType) + } + return vmId, nil + } + + instanceTypes, err := self.zone.region.GetMatchInstanceTypes(cpu, memMB, 0, self.zone.Zone) + if err != nil { + return "", err + } + if len(instanceTypes) == 0 { + return "", fmt.Errorf("instance type %dC%dMB not avaiable", cpu, memMB) + } + + var vmId string + for _, instType := range instanceTypes { + instanceTypeId := instType.InstanceType + log.Debugf("Try instancetype : %s", instanceTypeId) + vmId, err = self.zone.region.CreateInstance(name, hostname, imgId, instanceTypeId, secgroupId, self.zone.Zone, desc, passwd, disks, networkId, ipAddr, keypair, userData, bc, projectId, publicIpBw, publicIpChargeType, tags, osType) + if err != nil { + log.Errorf("Failed for %s: %s", instanceTypeId, err) + } else { + return vmId, nil + } + } + + return "", fmt.Errorf("Failed to create, %s", err.Error()) +} + +func (self *SHost) Refresh() error { + return nil +} + +func (self *SHost) GetAccessIp() string { + return "" +} + +func (self *SHost) GetAccessMac() string { + return "" +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetCpuCount() int { + 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) GetEnabled() bool { + return true +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) GetHostStatus() string { + return api.HOST_ONLINE +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_QCLOUD +} + +func (self *SHost) GetStorageType() string { + return api.DISK_TYPE_HYBRID +} + +func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return self.zone.GetIStorageById(id) +} + +func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + return self.zone.GetIStorages() +} + +func (self *SHost) GetIVMById(gid string) (cloudprovider.ICloudVM, error) { + if len(gid) == 0 { + return nil, cloudprovider.ErrNotFound + } + parts, _, err := self.zone.region.GetInstances(self.zone.Zone, []string{gid}, 0, 1) + if err != nil { + return nil, err + } + if len(parts) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(parts) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + parts[0].host = self + return &parts[0], nil +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms := make([]SInstance, 0) + for { + parts, total, err := self.zone.region.GetInstances(self.zone.Zone, nil, len(vms), 50) + if err != nil { + return nil, err + } + vms = append(vms, parts...) + if len(vms) >= total { + break + } + } + ivms := make([]cloudprovider.ICloudVM, len(vms)) + for i := 0; i < len(vms); i++ { + vms[i].host = self + ivms[i] = &vms[i] + } + return ivms, nil +} + +func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + return self.zone.GetIWires() +} + +func (self *SHost) GetSysInfo() jsonutils.JSONObject { + info := jsonutils.NewDict() + info.Add(jsonutils.NewString(CLOUD_PROVIDER_QCLOUD), "manufacture") + return info +} + +func (self *SHost) IsEmulated() bool { + return true +} + +func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (host *SHost) GetIsMaintenance() bool { + return false +} + +func (host *SHost) GetVersion() string { + return QCLOUD_API_VERSION +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/image.go new file mode 100644 index 0000000000..7a68da9205 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/image.go @@ -0,0 +1,383 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/apis" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type ImageStatusType string + +const ( + ImageStatusCreating ImageStatusType = "CREATING" + ImageStatusNormal ImageStatusType = "NORMAL" + ImageStatusSycing ImageStatusType = "SYNCING" + ImageStatusImporting ImageStatusType = "IMPORTING" + ImageStatusUsing ImageStatusType = "USING" + ImageStatusDeleting ImageStatusType = "DELETING" +) + +type SImage struct { + multicloud.SImageBase + QcloudTags + storageCache *SStoragecache + + // normalized image info + imgInfo *imagetools.ImageInfo + + ImageId string // 镜像ID + OsName string // 镜像操作系统 + ImageType string // 镜像类型 + CreatedTime time.Time // 镜像创建时间 + ImageName string // 镜像名称 + ImageDescription string // 镜像描述 + ImageSize int // 镜像大小 + Architecture string // 镜像架构 + ImageState ImageStatusType // 镜像状态 + Platform string // 镜像来源平台 + ImageCreator string // 镜像创建者 + ImageSource string // 镜像来源 + SyncPercent int // 同步百分比 + IsSupportCloudinit bool // 镜像是否支持cloud-init +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SRegion) GetImages(status string, owner string, imageIds []string, name string, offset int, limit int) ([]SImage, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + + for index, imageId := range imageIds { + params[fmt.Sprintf("ImageIds.%d", index)] = imageId + } + + if len(imageIds) == 0 { // imageIds 不能和Filter同时查询 + filter := 0 + if len(status) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "image-state" + params[fmt.Sprintf("Filters.%d.Values.0", filter)] = status + filter++ + } + + if len(owner) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "image-type" + params[fmt.Sprintf("Filters.%d.Values.0", filter)] = owner + filter++ + } + + if len(name) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "image-name" + params[fmt.Sprintf("Filters.%d.Values.0", filter)] = name + filter++ + } + } + + images := make([]SImage, 0) + body, err := self.cvmRequest("DescribeImages", params, true) + if err != nil { + return nil, 0, err + } + err = body.Unmarshal(&images, "ImageSet") + if err != nil { + return nil, 0, err + } + for i := 0; i < len(images); i++ { + images[i].storageCache = self.getStoragecache() + } + total, _ := body.Float("TotalCount") + return images, int(total), nil +} + +func (self *SImage) GetId() string { + return self.ImageId +} + +func (self *SImage) GetName() string { + return self.ImageName +} + +func (self *SImage) IsEmulated() bool { + return false +} + +func (self *SImage) GetGlobalId() string { + return self.ImageId +} + +func (self *SImage) Delete(ctx context.Context) error { + return self.storageCache.region.DeleteImage(self.ImageId) +} + +func (self *SImage) GetStatus() string { + switch self.ImageState { + case ImageStatusCreating, ImageStatusSycing, ImageStatusImporting: + return api.CACHED_IMAGE_STATUS_CACHING + case ImageStatusNormal, ImageStatusUsing: + return api.CACHED_IMAGE_STATUS_ACTIVE + default: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (self *SImage) GetImageStatus() string { + switch self.ImageState { + case ImageStatusCreating, ImageStatusSycing, ImageStatusImporting: + return cloudprovider.IMAGE_STATUS_SAVING + case ImageStatusNormal, ImageStatusUsing: + return cloudprovider.IMAGE_STATUS_ACTIVE + case ImageStatusDeleting: + return cloudprovider.IMAGE_STATUS_DELETED + default: + return cloudprovider.IMAGE_STATUS_DELETED + } +} + +func (self *SImage) Refresh() error { + new, err := self.storageCache.region.GetImage(self.ImageId) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SImage) GetImageType() cloudprovider.TImageType { + switch self.ImageType { + case "PUBLIC_IMAGE": + return cloudprovider.ImageTypeSystem + case "PRIVATE_IMAGE": + return cloudprovider.ImageTypeCustomized + default: + return cloudprovider.ImageTypeCustomized + } +} + +func (self *SImage) GetSizeByte() int64 { + return int64(self.ImageSize) * 1024 * 1024 * 1024 +} + +func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if self.imgInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(self.OsName, self.Architecture, self.Platform, self.Platform, "") + self.imgInfo = &imgInfo + } + + return self.imgInfo +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) +} + +func (self *SImage) GetOsDist() string { + return self.getNormalizedImageInfo().OsDistro +} + +func (self *SImage) GetOsVersion() string { + return self.getNormalizedImageInfo().OsVersion +} + +func (self *SImage) GetOsArch() string { + return self.getNormalizedImageInfo().OsArch +} + +func (img *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(img.getNormalizedImageInfo().OsBios) +} + +func (img *SImage) GetFullOsName() string { + return img.OsName +} + +func (img *SImage) GetOsLang() string { + return img.getNormalizedImageInfo().OsLang +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return 50 +} + +func (self *SImage) GetImageFormat() string { + return "qcow2" +} + +func (self *SImage) GetCreatedAt() time.Time { + return self.CreatedTime +} + +func (self *SRegion) GetImage(imageId string) (*SImage, error) { + images, _, err := self.GetImages("", "", []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 *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.storageCache +} + +func (self *SRegion) DeleteImage(imageId string) error { + params := make(map[string]string) + params["ImageIds.0"] = imageId + + _, err := self.cvmRequest("DeleteImages", params, true) + return err +} + +func (self *SRegion) GetImageStatus(imageId string) (ImageStatusType, error) { + image, err := self.GetImage(imageId) + if err != nil { + return "", err + } + return image.ImageState, nil +} + +func (self *SRegion) GetImageByName(name string) (*SImage, error) { + images, _, err := self.GetImages("", "", nil, name, 0, 1) + if err != nil { + return nil, err + } + if len(images) == 0 { + return nil, cloudprovider.ErrNotFound + } + return &images[0], nil +} + +type ImportImageOsListSupported struct { + Linux []string //"CentOS|Ubuntu|Debian|OpenSUSE|SUSE|CoreOS|FreeBSD|Other Linux" + Windows []string //"Windows Server 2008|Windows Server 2012|Windows Server 2016" +} + +type ImportImageOsVersionSet struct { + Architecture []string + OsName string //"CentOS|Ubuntu|Debian|OpenSUSE|SUSE|CoreOS|FreeBSD|Other Linux|Windows Server 2008|Windows Server 2012|Windows Server 2016" + OsVersions []string +} + +type SupportImageSet struct { + ImportImageOsListSupported ImportImageOsListSupported + ImportImageOsVersionSet []ImportImageOsVersionSet +} + +func (self *SRegion) GetSupportImageSet() (*SupportImageSet, error) { + body, err := self.cvmRequest("DescribeImportImageOs", map[string]string{}, true) + if err != nil { + return nil, err + } + imageSet := SupportImageSet{} + return &imageSet, body.Unmarshal(&imageSet) +} + +func (self *SRegion) GetImportImageParams(name string, osArch, osDist, osVersion string, imageUrl string) (map[string]string, error) { + params := map[string]string{} + imageSet, err := self.GetSupportImageSet() + if err != nil { + return nil, err + } + osType := "" + for _, _imageSet := range imageSet.ImportImageOsVersionSet { + if strings.ToLower(osDist) == strings.ToLower(_imageSet.OsName) { //Linux一般可正常匹配 + osType = _imageSet.OsName + } else if strings.Contains(strings.ToLower(_imageSet.OsName), "windows") && strings.Contains(strings.ToLower(osDist), "windows") { + info := strings.Split(_imageSet.OsName, " ") + _osVersion := "2008" + for _, version := range info { + if _, err := strconv.Atoi(version); err == nil { + _osVersion = version + break + } + } + if strings.Contains(osDist+osVersion, _osVersion) { + osType = _imageSet.OsName + } + } + if len(osType) == 0 { + continue + } + if !utils.IsInStringArray(osArch, _imageSet.Architecture) { + osArch = apis.OS_ARCH_X86_64 + } + for _, _osVersion := range _imageSet.OsVersions { + if strings.HasPrefix(osVersion, _osVersion) { + osVersion = _osVersion + break + } + } + if !utils.IsInStringArray(osVersion, _imageSet.OsVersions) { + osVersion = "-" + if len(_imageSet.OsVersions) > 0 { + osVersion = _imageSet.OsVersions[0] + } + } + break + } + if len(osType) == 0 { + osType = "Other Linux" + osArch = apis.OS_ARCH_X86_64 + osVersion = "-" + } + + params["ImageName"] = name + params["OsType"] = osType + params["OsVersion"] = osVersion + params["Architecture"] = osArch // "x86_64|i386" + params["ImageUrl"] = imageUrl + params["Force"] = "true" + return params, nil +} + +func (self *SRegion) ImportImage(name string, osArch, osDist, osVersion string, imageUrl string) (*SImage, error) { + params, err := self.GetImportImageParams(name, osArch, osDist, osVersion, imageUrl) + if err != nil { + return nil, err + } + + log.Debugf("Upload image with params %#v", params) + + if _, err := self.cvmRequest("ImportImage", params, true); err != nil { + return nil, err + } + for i := 0; i < 8; i++ { + image, err := self.GetImageByName(name) + if err == nil { + return image, nil + } + time.Sleep(time.Minute * time.Duration(i)) + } + return nil, cloudprovider.ErrNotFound +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/instance.go new file mode 100644 index 0000000000..5c5ec7897e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/instance.go @@ -0,0 +1,1072 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + sdkerrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +const ( + // PENDING:表示创建中 + // LAUNCH_FAILED:表示创建失败 + // RUNNING:表示运行中 + // STOPPED:表示关机 + // STARTING:表示开机中 + // STOPPING:表示关机中 + // REBOOTING:表示重启中 + // SHUTDOWN:表示停止待销毁 + // TERMINATING:表示销毁中。 + + InstanceStatusStopped = "STOPPED" + InstanceStatusRunning = "RUNNING" + InstanceStatusStopping = "STOPPING" + InstanceStatusStarting = "STARTING" +) + +const ( + InternetChargeTypeBandwidthPrepaid = "BANDWIDTH_PREPAID" + InternetChargeTypeTrafficPostpaidByHour = "TRAFFIC_POSTPAID_BY_HOUR" + InternetChargeTypeBandwidthPostpaidByHour = "BANDWIDTH_POSTPAID_BY_HOUR" + InternetChargeTypeBandwidthPackage = "BANDWIDTH_PACKAGE" +) + +type SystemDisk struct { + DiskType string //系统盘类型。系统盘类型限制详见CVM实例配置。取值范围:LOCAL_BASIC:本地硬盘 LOCAL_SSD:本地SSD硬盘 CLOUD_BASIC:普通云硬盘 CLOUD_SSD:SSD云硬盘 CLOUD_PREMIUM:高性能云硬盘 默认取值:CLOUD_BASIC。 + DiskId string // 系统盘ID。LOCAL_BASIC 和 LOCAL_SSD 类型没有ID。暂时不支持该参数。 + DiskSize float32 //系统盘大小,单位:GB。默认值为 50 +} + +type DataDisk struct { + DiskSize float32 // 数据盘大小,单位:GB。最小调整步长为10G,不同数据盘类型取值范围不同,具体限制详见:CVM实例配置。默认值为0,表示不购买数据盘。更多限制详见产品文档。 + DiskType string // 数据盘类型。数据盘类型限制详见CVM实例配置。取值范围:LOCAL_BASIC:本地硬盘 LOCAL_SSD:本地SSD硬盘 CLOUD_BASIC:普通云硬盘 CLOUD_PREMIUM:高性能云硬盘 CLOUD_SSD:SSD云硬盘 默认取值:LOCAL_BASIC。 该参数对ResizeInstanceDisk接口无效。 + DiskId string // 数据盘ID。LOCAL_BASIC 和 LOCAL_SSD 类型没有ID。暂时不支持该参数。 + DeleteWithInstance bool // 数据盘是否随子机销毁。取值范围:TRUE:子机销毁时,销毁数据盘 FALSE:子机销毁时,保留数据盘 默认取值:TRUE 该参数目前仅用于 RunInstances 接口。 +} + +type InternetAccessible struct { + InternetChargeType string //网络计费类型。取值范围:BANDWIDTH_PREPAID:预付费按带宽结算 TRAFFIC_POSTPAID_BY_HOUR:流量按小时后付费 BANDWIDTH_POSTPAID_BY_HOUR:带宽按小时后付费 BANDWIDTH_PACKAGE:带宽包用户 默认取值:非带宽包用户默认与子机付费类型保持一致。 + InternetMaxBandwidthOut int // 公网出带宽上限,单位:Mbps。默认值:0Mbps。不同机型带宽上限范围不一致,具体限制详见购买网络带宽。 + PublicIpAssigned bool // 是否分配公网IP。取值范围: TRUE:表示分配公网IP FALSE:表示不分配公网IP 当公网带宽大于0Mbps时,可自由选择开通与否,默认开通公网IP;当公网带宽为0,则不允许分配公网IP。 +} + +type VirtualPrivateCloud struct { + VpcId string // 私有网络ID,形如vpc-xxx。有效的VpcId可通过登录控制台查询;也可以调用接口 DescribeVpcEx ,从接口返回中的unVpcId字段获取。 + SubnetId string // 私有网络子网ID,形如subnet-xxx。有效的私有网络子网ID可通过登录控制台查询;也可以调用接口 DescribeSubnets ,从接口返回中的unSubnetId字段获取。 + AsVpcGateway bool // 是否用作公网网关。公网网关只有在实例拥有公网IP以及处于私有网络下时才能正常使用。取值范围:TRUE:表示用作公网网关 FALSE:表示不用作公网网关 默认取值:FALSE。 + PrivateIpAddresses []string // 私有网络子网 IP 数组,在创建实例、修改实例vpc属性操作中可使用此参数。当前仅批量创建多台实例时支持传入相同子网的多个 IP。 +} + +type LoginSettings struct { + Password string //实例登录密码。不同操作系统类型密码复杂度限制不一样,具体如下:Linux实例密码必须8到16位,至少包括两项[a-z,A-Z]、[0-9] 和 [( ) ~ ! @ # $ % ^ & * - + = | { } [ ] : ; ' , . ? / ]中的特殊符号。
  • Windows实例密码必须12到16位,至少包括三项[a-z],[A-Z],[0-9] 和 [( ) ~ ! @ # $ % ^ & * - + = { } [ ] : ; ' , . ? /]中的特殊符号。 若不指定该参数,则由系统随机生成密码,并通过站内信方式通知到用户。 + KeyIds []string // 密钥ID列表。关联密钥后,就可以通过对应的私钥来访问实例;KeyId可通过接口DescribeKeyPairs获取,密钥与密码不能同时指定,同时Windows操作系统不支持指定密钥。当前仅支持购买的时候指定一个密钥。 + KeepImageLogin string // 保持镜像的原始设置。该参数与Password或KeyIds.N不能同时指定。只有使用自定义镜像、共享镜像或外部导入镜像创建实例时才能指定该参数为TRUE。取值范围: TRUE:表示保持镜像的登录设置 FALSE:表示不保持镜像的登录设置 默认取值:FALSE。 +} + +type Tag struct { + Key string + Value string +} + +type SInstance struct { + multicloud.SInstanceBase + QcloudTags + + host *SHost + + // normalized image info + osInfo *imagetools.ImageInfo + + image *SImage + idisks []cloudprovider.ICloudDisk + + Placement Placement + InstanceId string + InstanceType string + CPU int + Memory int + RestrictState string //NORMAL EXPIRED PROTECTIVELY_ISOLATED + InstanceName string + InstanceChargeType InstanceChargeType //PREPAID:表示预付费,即包年包月 POSTPAID_BY_HOUR:表示后付费,即按量计费 CDHPAID:CDH付费,即只对CDH计费,不对CDH上的实例计费。 + SystemDisk SystemDisk //实例系统盘信息。 + DataDisks []DataDisk //实例数据盘信息。只包含随实例购买的数据盘。 + PrivateIpAddresses []string //实例主网卡的内网IP列表。 + PublicIpAddresses []string //实例主网卡的公网IP列表。 + InternetAccessible InternetAccessible //实例带宽信息。 + VirtualPrivateCloud VirtualPrivateCloud //实例所属虚拟私有网络信息。 + ImageId string // 生产实例所使用的镜像ID。 + RenewFlag string // 自动续费标识。取值范围:NOTIFY_AND_MANUAL_RENEW:表示通知即将过期,但不自动续费 NOTIFY_AND_AUTO_RENEW:表示通知即将过期,而且自动续费 DISABLE_NOTIFY_AND_MANUAL_RENEW:表示不通知即将过期,也不自动续费。 + CreatedTime time.Time // 创建时间。按照ISO8601标准表示,并且使用UTC时间。格式为:YYYY-MM-DDThh:mm:ssZ。 + ExpiredTime time.Time // 到期时间。按照ISO8601标准表示,并且使用UTC时间。格式为:YYYY-MM-DDThh:mm:ssZ。 + OsName string // 操作系统名称。 + SecurityGroupIds []string // 实例所属安全组。该参数可以通过调用 DescribeSecurityGroups 的返回值中的sgId字段来获取。 + LoginSettings LoginSettings //实例登录设置。目前只返回实例所关联的密钥。 + InstanceState string // 实例状态。取值范围:PENDING:表示创建中 LAUNCH_FAILED:表示创建失败 RUNNING:表示运行中 STOPPED:表示关机 STARTING:表示开机中 STOPPING:表示关机中 REBOOTING:表示重启中 SHUTDOWN:表示停止待销毁 TERMINATING:表示销毁中。 + Tags []Tag +} + +func (self *SRegion) GetInstances(zoneId string, ids []string, offset int, limit int) ([]SInstance, int, error) { + params := make(map[string]string) + if limit < 1 || limit > 50 { + limit = 50 + } + + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + instances := make([]SInstance, 0) + if ids != nil && len(ids) > 0 { + for index, id := range ids { + params[fmt.Sprintf("InstanceIds.%d", index)] = id + } + } else { + if len(zoneId) > 0 { + params["Filters.0.Name"] = "zone" + params["Filters.0.Values.0"] = zoneId + } + } + body, err := self.cvmRequest("DescribeInstances", params, true) + if err != nil { + return nil, 0, err + } + err = body.Unmarshal(&instances, "InstanceSet") + if err != nil { + return nil, 0, err + } + total, _ := body.Float("TotalCount") + return instances, int(total), nil +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + return self.SecurityGroupIds, nil +} + +func (self *SInstance) getCloudMetadata() (map[string]string, error) { + mtags, err := self.host.zone.region.FetchResourceTags("cvm", "instance", []string{self.InstanceId}) + if err != nil { + return nil, errors.Wrap(err, "FetchResourceTags") + } + if tags, ok := mtags[self.InstanceId]; ok { + return *tags, nil + } else { + return nil, nil + } +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetId() string { + return self.InstanceId +} + +func (self *SInstance) GetName() string { + if len(self.InstanceName) > 0 && self.InstanceName != "未命名" { + return self.InstanceName + } + return self.InstanceId +} + +func (self *SInstance) GetHostname() string { + return self.GetName() +} + +func (self *SInstance) GetGlobalId() string { + return self.InstanceId +} + +func (self *SInstance) IsEmulated() bool { + return false +} + +func (self *SInstance) GetInstanceType() string { + return self.InstanceType +} + +func (self *SInstance) getVpc() (*SVpc, error) { + return self.host.zone.region.getVpc(self.VirtualPrivateCloud.VpcId) +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + idisks := make([]cloudprovider.ICloudDisk, 0) + + if utils.IsInStringArray(strings.ToUpper(self.SystemDisk.DiskType), QCLOUD_LOCAL_STORAGE_TYPES) { + storage := SLocalStorage{zone: self.host.zone, storageType: self.SystemDisk.DiskType} + disk := SLocalDisk{ + storage: &storage, + DiskId: self.SystemDisk.DiskId, + DiskSize: self.SystemDisk.DiskSize, + DisktType: self.SystemDisk.DiskType, + DiskUsage: "SYSTEM_DISK", + imageId: self.ImageId, + } + idisks = append(idisks, &disk) + } + + for i := 0; i < len(self.DataDisks); i++ { + if utils.IsInStringArray(strings.ToUpper(self.DataDisks[i].DiskType), QCLOUD_LOCAL_STORAGE_TYPES) { + storage := SLocalStorage{zone: self.host.zone, storageType: self.DataDisks[i].DiskType} + disk := SLocalDisk{ + storage: &storage, + DiskId: self.DataDisks[i].DiskId, + DiskSize: self.DataDisks[i].DiskSize, + DisktType: self.DataDisks[i].DiskType, + DiskUsage: "DATA_DISK", + } + idisks = append(idisks, &disk) + } + } + + disks := make([]SDisk, 0) + totalDisk := -1 + for totalDisk < 0 || len(disks) < totalDisk { + parts, total, err := self.host.zone.region.GetDisks(self.InstanceId, "", "", nil, len(disks), 50) + if err != nil { + log.Errorf("fetchDisks fail %s", err) + return nil, err + } + if len(parts) > 0 { + disks = append(disks, parts...) + } + totalDisk = total + } + + for i := 0; i < len(disks); i += 1 { + store, err := self.host.zone.getStorageByCategory(disks[i].DiskType) + if err != nil { + return nil, err + } + disks[i].storage = store + idisks = append(idisks, &disks[i]) + } + + return idisks, nil +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + classic := self.VirtualPrivateCloud.VpcId == "" + region := self.host.zone.region + ret := []cloudprovider.ICloudNic{} + if classic { + for _, ipAddr := range self.PrivateIpAddresses { + nic := SInstanceNic{ + instance: self, + ipAddr: ipAddr, + classic: true, + } + ret = append(ret, &nic) + } + } + nics, _, err := region.GetNetworkInterfaces(nil, self.InstanceId, "", 0, 10) + if err != nil { + return nil, errors.Wrapf(err, "GetNetworkInterfaces") + } + for _, networkInterface := range nics { + nic := &SInstanceNic{ + instance: self, + id: String(&networkInterface.NetworkInterfaceId), + macAddr: strings.ToLower(networkInterface.MacAddress), + classic: classic, + } + for _, addr := range networkInterface.PrivateIpAddressSet { + if addr.Primary { + nic.ipAddr = addr.PrivateIpAddress + } + } + ret = append(ret, nic) + } + return ret, nil +} + +func (self *SInstance) GetVcpuCount() int { + return self.CPU +} + +func (self *SInstance) GetVmemSizeMB() int { + return self.Memory * 1024 +} + +func (self *SInstance) GetBootOrder() string { + return "dcn" +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (ins *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { + if ins.osInfo == nil { + osInfo := imagetools.NormalizeImageInfo(ins.OsName, "", "", "", "") + ins.osInfo = &osInfo + } + return ins.osInfo +} + +func (ins *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(ins.getNormalizedOsInfo().OsType) +} + +func (ins *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(ins.getNormalizedOsInfo().OsBios) +} + +func (ins *SInstance) GetFullOsName() string { + return ins.OsName +} + +func (ins *SInstance) GetOsLang() string { + return ins.getNormalizedOsInfo().OsLang +} + +func (ins *SInstance) GetOsArch() string { + return ins.getNormalizedOsInfo().OsArch +} + +func (ins *SInstance) GetOsDist() string { + return ins.getNormalizedOsInfo().OsDistro +} + +func (ins *SInstance) GetOsVersion() string { + return ins.getNormalizedOsInfo().OsVersion +} + +func (self *SInstance) GetMachine() string { + return "pc" +} + +func (self *SInstance) GetStatus() string { + switch self.InstanceState { + case "PENDING": + return api.VM_DEPLOYING + case "LAUNCH_FAILED": + return api.VM_DEPLOY_FAILED + case "RUNNING": + return api.VM_RUNNING + case "STOPPED": + return api.VM_READY + case "STARTING", "REBOOTING": + return api.VM_STARTING + case "STOPPING": + return api.VM_STOPPING + case "SHUTDOWN": + return api.VM_DEALLOCATED + case "TERMINATING": + return api.VM_DELETING + default: + return api.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) GetHypervisor() string { + return api.HYPERVISOR_QCLOUD +} + +func (self *SInstance) StartVM(ctx context.Context) error { + err := cloudprovider.Wait(time.Second*15, time.Minute*5, func() (bool, error) { + err := self.Refresh() + if err != nil { + return true, errors.Wrapf(err, "Refresh") + } + log.Debugf("status %s expect %s", self.GetStatus(), api.VM_RUNNING) + if self.GetStatus() == api.VM_RUNNING { + return true, nil + } + if self.GetStatus() == api.VM_STARTING { + return false, nil + } + if self.GetStatus() == api.VM_READY { + err := self.host.zone.region.StartVM(self.InstanceId) + if err != nil { + if e, ok := errors.Cause(err).(*sdkerrors.TencentCloudSDKError); ok { + if e.Code == "UnsupportedOperation.InstanceStateRunning" { + return true, nil + } + } + return true, err + } + } + return false, nil + }) + return errors.Wrapf(err, "Wait") +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + err := self.host.zone.region.StopVM(self.InstanceId, opts) + if err != nil { + return err + } + return cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 8*time.Minute) // 8 mintues, 腾讯云有时关机比较慢 +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + url, err := self.host.zone.region.GetInstanceVNCUrl(self.InstanceId) + if err != nil { + return nil, err + } + ret := &cloudprovider.ServerVncOutput{ + Url: url, + Protocol: "qcloud", + InstanceId: self.InstanceId, + Hypervisor: api.HYPERVISOR_QCLOUD, + } + return ret, nil +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return self.host.zone.region.UpdateVM(self.InstanceId, name) +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + var keypairName string + if len(publicKey) > 0 { + var err error + keypairName, err = self.host.zone.region.syncKeypair(publicKey) + if err != nil { + return err + } + } + + return self.host.zone.region.DeployVM(self.InstanceId, name, password, keypairName, deleteKeypair, description) +} + +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + keypair := "" + if len(desc.PublicKey) > 0 { + var err error + keypair, err = self.host.zone.region.syncKeypair(desc.PublicKey) + if err != nil { + return "", err + } + } + err := self.host.zone.region.ReplaceSystemDisk(self.InstanceId, desc.ImageId, desc.Password, keypair, desc.SysSizeGB) + if err != nil { + return "", err + } + opts := &cloudprovider.ServerStopOptions{ + IsForce: true, + } + self.StopVM(ctx, opts) + instance, err := self.host.zone.region.GetInstance(self.InstanceId) + if err != nil { + return "", err + } + return instance.SystemDisk.DiskId, nil +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + instanceTypes := []string{} + if len(config.InstanceType) > 0 { + instanceTypes = []string{config.InstanceType} + } else { + specs, err := self.host.zone.region.GetMatchInstanceTypes(config.Cpu, config.MemoryMB, 0, self.Placement.Zone) + if err != nil { + return errors.Wrapf(err, "GetMatchInstanceTypes") + } + for _, spec := range specs { + instanceTypes = append(instanceTypes, spec.InstanceType) + } + } + + var err error + for _, instanceType := range instanceTypes { + err = self.host.zone.region.ChangeVMConfig(self.InstanceId, instanceType) + if err != nil { + log.Errorf("ChangeConfig for %s with %s error: %v", self.InstanceId, instanceType, err) + continue + } + return nil + } + if err != nil { + return err + } + + return fmt.Errorf("Failed to change vm config, specification not supported") +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return self.host.zone.region.AttachDisk(self.InstanceId, diskId) +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return self.host.zone.region.DetachDisk(self.InstanceId, diskId) +} + +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 + } + if len(instances) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + if instances[0].InstanceState == "LAUNCH_FAILED" { + return nil, cloudprovider.ErrNotFound + } + return &instances[0], nil +} + +func (self *SRegion) CreateInstance(name, hostname string, imageId string, instanceType string, securityGroupId string, + zoneId string, desc string, passwd string, disks []SDisk, networkId string, ipAddr string, + keypair string, userData string, bc *billing.SBillingCycle, projectId string, + publicIpBw int, publicIpChargeType cloudprovider.TElasticipChargeType, + tags map[string]string, osType string, +) (string, error) { + params := make(map[string]string) + params["Region"] = self.Region + params["ImageId"] = imageId + params["InstanceType"] = instanceType + params["SecurityGroupIds.0"] = securityGroupId + params["Placement.Zone"] = zoneId + if len(projectId) > 0 { + params["Placement.ProjectId"] = projectId + } + params["InstanceName"] = name + if len(hostname) > 0 { + params["HostName"] = hostname + } + + bandwidth := publicIpBw + if publicIpBw == 0 { + bandwidth = 100 + if bc != nil { + bandwidth = 200 + } + } + + internetChargeType := "TRAFFIC_POSTPAID_BY_HOUR" + if publicIpChargeType == cloudprovider.ElasticipChargeTypeByBandwidth { + internetChargeType = "BANDWIDTH_POSTPAID_BY_HOUR" + } + pkgs, _, err := self.GetBandwidthPackages([]string{}, 0, 50) + if err != nil { + return "", errors.Wrapf(err, "GetBandwidthPackages") + } + if len(pkgs) > 0 { + bandwidth = 65535 // unlimited bandwidth + if publicIpBw > 0 { // 若用户指定带宽则限制带宽大小 + bandwidth = publicIpBw + } + internetChargeType = "BANDWIDTH_PACKAGE" + pkgId := pkgs[0].BandwidthPackageId + for _, pkg := range pkgs { + if len(pkg.ResourceSet) < 100 { + pkgId = pkg.BandwidthPackageId + break + } + } + params["InternetAccessible.BandwidthPackageId"] = pkgId + } + + params["InternetAccessible.InternetChargeType"] = internetChargeType + params["InternetAccessible.InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bandwidth) + params["InternetAccessible.PublicIpAssigned"] = "TRUE" + if publicIpBw == 0 { + params["InternetAccessible.PublicIpAssigned"] = "FALSE" + } + if len(keypair) > 0 { + params["LoginSettings.KeyIds.0"] = keypair + } else if len(passwd) > 0 { + params["LoginSettings.Password"] = passwd + } else { + params["LoginSettings.KeepImageLogin"] = "TRUE" + } + if len(userData) > 0 { + params["UserData"] = userData + } + + if bc != nil { + params["InstanceChargeType"] = "PREPAID" + params["InstanceChargePrepaid.Period"] = fmt.Sprintf("%d", bc.GetMonths()) + if bc.AutoRenew { + params["InstanceChargePrepaid.RenewFlag"] = "NOTIFY_AND_AUTO_RENEW" + } else { + params["InstanceChargePrepaid.RenewFlag"] = "NOTIFY_AND_MANUAL_RENEW" + } + } else { + params["InstanceChargeType"] = "POSTPAID_BY_HOUR" + } + + // tags + if len(tags) > 0 { + params["TagSpecification.0.ResourceType"] = "instance" + tagIdx := 0 + for k, v := range tags { + params[fmt.Sprintf("TagSpecification.0.Tags.%d.Key", tagIdx)] = k + params[fmt.Sprintf("TagSpecification.0.Tags.%d.Value", tagIdx)] = v + tagIdx += 1 + } + } + + //params["IoOptimized"] = "optimized" + for i, d := range disks { + if i == 0 { + params["SystemDisk.DiskType"] = d.DiskType + params["SystemDisk.DiskSize"] = fmt.Sprintf("%d", d.DiskSize) + } else { + params[fmt.Sprintf("DataDisks.%d.DiskSize", i-1)] = fmt.Sprintf("%d", d.DiskSize) + params[fmt.Sprintf("DataDisks.%d.DiskType", i-1)] = d.DiskType + } + } + network, err := self.GetNetwork(networkId) + if err != nil { + return "", errors.Wrapf(err, "GetNetwork(%s)", networkId) + } + params["VirtualPrivateCloud.SubnetId"] = networkId + params["VirtualPrivateCloud.VpcId"] = network.VpcId + if len(ipAddr) > 0 { + params["VirtualPrivateCloud.PrivateIpAddresses.0"] = ipAddr + } + + var body jsonutils.JSONObject + instanceIdSet := []string{} + err = cloudprovider.Wait(time.Second*10, time.Minute, func() (bool, error) { + params["ClientToken"] = utils.GenRequestId(20) + body, err = self.cvmRequest("RunInstances", params, true) + if err != nil { + if strings.Contains(err.Error(), "Code=InvalidPermission") { // 带宽上移用户未指定公网ip时不能设置带宽 + delete(params, "InternetAccessible.InternetChargeType") + delete(params, "InternetAccessible.InternetMaxBandwidthOut") + return false, nil + } + if strings.Contains(err.Error(), "UnsupportedOperation.BandwidthPackageIdNotSupported") || + (strings.Contains(err.Error(), "Code=InvalidParameterCombination") && strings.Contains(err.Error(), "InternetAccessible.BandwidthPackageId")) { + delete(params, "InternetAccessible.BandwidthPackageId") + return false, nil + } + return false, errors.Wrapf(err, "RunInstances") + } + return true, nil + }) + if err != nil { + return "", errors.Wrap(err, "RunInstances") + } + err = body.Unmarshal(&instanceIdSet, "InstanceIdSet") + if err == nil && len(instanceIdSet) > 0 { + return instanceIdSet[0], nil + } + return "", fmt.Errorf("Failed to create instance") +} + +func (self *SRegion) doStartVM(instanceId string) error { + return self.instanceOperation(instanceId, "StartInstances", nil, true) +} + +func (self *SRegion) doStopVM(instanceId string, opts *cloudprovider.ServerStopOptions) error { + params := make(map[string]string) + if opts.IsForce { + // params["ForceStop"] = "FALSE" + params["StopType"] = "HARD" + } else { + // params["ForceStop"] = "FALSE" + params["StopType"] = "SOFT" + } + if opts.StopCharging { + params["StoppedMode"] = "STOP_CHARGING" + } + return self.instanceOperation(instanceId, "StopInstances", params, true) +} + +func (self *SRegion) doDeleteVM(instanceId string) error { + params := make(map[string]string) + err := self.instanceOperation(instanceId, "TerminateInstances", params, true) + if err != nil && cloudprovider.IsError(err, []string{"InvalidInstanceId.NotFound"}) { + return nil + } + return err +} + +func (self *SRegion) StartVM(instanceId string) error { + status, err := self.GetInstanceStatus(instanceId) + if err != nil { + log.Errorf("Fail to get instance status on StartVM: %s", err) + return err + } + if status != InstanceStatusStopped { + log.Errorf("StartVM: vm status is %s expect %s", status, InstanceStatusStopped) + return cloudprovider.ErrInvalidStatus + } + return self.doStartVM(instanceId) +} + +func (self *SRegion) StopVM(instanceId string, opts *cloudprovider.ServerStopOptions) error { + status, err := self.GetInstanceStatus(instanceId) + if err != nil { + log.Errorf("Fail to get instance status on StopVM: %s", err) + return err + } + if status == InstanceStatusStopped { + return nil + } + return self.doStopVM(instanceId, opts) +} + +func (self *SRegion) DeleteVM(instanceId string) error { + status, err := self.GetInstanceStatus(instanceId) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + return errors.Wrapf(err, "self.GetInstanceStatus") + } + log.Debugf("Instance status on delete is %s", status) + if status != InstanceStatusStopped { + log.Warningf("DeleteVM: vm status is %s expect %s", status, InstanceStatusStopped) + } + return self.doDeleteVM(instanceId) +} + +func (self *SRegion) DeployVM(instanceId string, name string, password string, keypairName string, deleteKeypair bool, description string) error { + instance, err := self.GetInstance(instanceId) + if err != nil { + return err + } + + // 修改密钥时直接返回 + if deleteKeypair { + for i := 0; i < len(instance.LoginSettings.KeyIds); i++ { + err = self.DetachKeyPair(instanceId, instance.LoginSettings.KeyIds[i]) + if err != nil { + return err + } + } + } + + if len(keypairName) > 0 { + err = self.AttachKeypair(instanceId, keypairName) + if err != nil { + return err + } + } + + params := make(map[string]string) + + if len(name) > 0 && instance.InstanceName != name { + params["InstanceName"] = name + } + + if len(params) > 0 { + err := self.modifyInstanceAttribute(instanceId, params) + if err != nil { + return err + } + } + if len(password) > 0 { + return self.instanceOperation(instanceId, "ResetInstancesPassword", map[string]string{"Password": password}, true) + } + return nil +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + err := self.host.zone.region.DeleteVM(self.InstanceId) + if err != nil { + return errors.Wrapf(err, "region.DeleteVM(%s)", self.InstanceId) + } + if self.GetBillingType() == billing_api.BILLING_TYPE_PREPAID { // 预付费的需要删除两次 + cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) { + err = self.Refresh() + if err != nil { + log.Warningf("refresh instance %s(%s) error: %v", self.InstanceName, self.InstanceId, err) + return false, nil + } + // 需要等待第一次删除后,状态变为SHUTDOWN,才可以进行第二次删除,否则会报: + // Code=OperationDenied.InstanceOperationInProgress, Message=该实例`['ins-mxqturgj']` + if self.InstanceState == "SHUTDOWN" { + return true, nil + } + log.Debugf("wait %s(%s) status be SHUTDOWN, current is %s", self.InstanceName, self.InstanceId, self.InstanceState) + return false, nil + }) + err := self.host.zone.region.DeleteVM(self.InstanceId) + if err != nil { + return errors.Wrapf(err, "region.DeleteVM(%s)", self.InstanceId) + } + } + return cloudprovider.WaitDeleted(self, 10*time.Second, 5*time.Minute) // 5minutes +} + +func (self *SRegion) UpdateVM(instanceId string, name string) error { + params := make(map[string]string) + params["InstanceName"] = name + return self.modifyInstanceAttribute(instanceId, params) +} + +func (self *SRegion) modifyInstanceAttribute(instanceId string, params map[string]string) error { + return self.instanceOperation(instanceId, "ModifyInstancesAttribute", params, true) +} + +func (self *SRegion) ReplaceSystemDisk(instanceId string, imageId string, passwd string, keypairName string, sysDiskSizeGB int) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["ImageId"] = imageId + params["EnhancedService.SecurityService.Enabled"] = "TRUE" + params["EnhancedService.MonitorService.Enabled"] = "TRUE" + + // 秘钥和密码及保留镜像设置只能选其一 + if len(keypairName) > 0 { + params["LoginSettings.KeyIds.0"] = keypairName + } else if len(passwd) > 0 { + params["LoginSettings.Password"] = passwd + } else { + params["LoginSettings.KeepImageLogin"] = "TRUE" + } + + if sysDiskSizeGB > 0 { + params["SystemDisk.DiskSize"] = fmt.Sprintf("%d", sysDiskSizeGB) + } + _, err := self.cvmRequest("ResetInstance", params, true) + return err +} + +func (self *SRegion) ChangeVMConfig(instanceId string, instanceType string) error { + params := make(map[string]string) + params["InstanceType"] = instanceType + + err := self.instanceOperation(instanceId, "ResetInstancesType", params, true) + return errors.Wrapf(err, "ResetInstancesType %s", instanceType) +} + +func (self *SRegion) DetachDisk(instanceId string, diskId string) error { + params := make(map[string]string) + params["DiskIds.0"] = diskId + log.Infof("Detach instance %s disk %s", instanceId, diskId) + _, err := self.cbsRequest("DetachDisks", params) + if err != nil { + // 可重复卸载,无报错,若磁盘被删除会有以下错误 + //[TencentCloudSDKError] Code=InvalidDisk.NotSupported, Message=disk(disk-4g5s7zhl) deleted (39a711ce2d17), RequestId=508d7fe3-e64e-4bb8-8ad7-39a711ce2d17 + if strings.Contains(err.Error(), fmt.Sprintf("disk(%s) deleted", diskId)) { + return nil + } + return errors.Wrap(err, "DetachDisks") + } + + return nil +} + +func (self *SRegion) AttachDisk(instanceId string, diskId string) error { + params := make(map[string]string) + params["InstanceId"] = instanceId + params["DiskIds.0"] = diskId + _, err := self.cbsRequest("AttachDisks", params) + if err != nil { + log.Errorf("AttachDisks %s to %s fail %s", diskId, instanceId, err) + return err + } + return nil +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + params := map[string]string{"SecurityGroups.0": secgroupId} + return self.host.zone.region.instanceOperation(self.InstanceId, "ModifyInstancesAttribute", params, true) +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + params := map[string]string{} + for i := 0; i < len(secgroupIds); i++ { + params[fmt.Sprintf("SecurityGroups.%d", i)] = secgroupIds[i] + } + return self.host.zone.region.instanceOperation(self.InstanceId, "ModifyInstancesAttribute", params, true) +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + eip, total, err := self.host.zone.region.GetEips("", self.InstanceId, 0, 1) + if err != nil { + return nil, err + } + if total == 1 { + return &eip[0], nil + } + self.Refresh() + for _, address := range self.PublicIpAddresses { + eip := SEipAddress{region: self.host.zone.region} + eip.AddressIp = address + eip.InstanceId = self.InstanceId + eip.AddressId = self.InstanceId + eip.AddressName = address + eip.AddressType = EIP_TYPE_WANIP + eip.AddressStatus = EIP_STATUS_BIND + eip.Bandwidth = self.InternetAccessible.InternetMaxBandwidthOut + return &eip, nil + } + return nil, nil +} + +func (self *SInstance) GetBillingType() string { + switch self.InstanceChargeType { + case PrePaidInstanceChargeType: + return billing_api.BILLING_TYPE_PREPAID + case PostPaidInstanceChargeType: + return billing_api.BILLING_TYPE_POSTPAID + default: + return billing_api.BILLING_TYPE_PREPAID + } +} + +func (self *SInstance) GetCreatedAt() time.Time { + return self.CreatedTime +} + +func (self *SInstance) GetExpiredAt() time.Time { + return self.ExpiredTime +} + +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) Renew(bc billing.SBillingCycle) error { + return self.host.zone.region.RenewInstances([]string{self.InstanceId}, bc) +} + +func (region *SRegion) RenewInstances(instanceId []string, bc billing.SBillingCycle) error { + params := make(map[string]string) + for i := 0; i < len(instanceId); i += 1 { + params[fmt.Sprintf("InstanceIds.%d", i)] = instanceId[i] + } + params["InstanceChargePrepaid.Period"] = fmt.Sprintf("%d", bc.GetMonths()) + params["InstanceChargePrepaid.RenewFlag"] = "NOTIFY_AND_MANUAL_RENEW" + params["RenewPortableDataDisk"] = "TRUE" + _, err := region.cvmRequest("RenewInstances", params, true) + if err != nil { + log.Errorf("RenewInstance fail %s", err) + return err + } + return nil +} + +func (self *SInstance) GetProjectId() string { + return strconv.Itoa(self.Placement.ProjectId) +} + +func (self *SInstance) GetError() error { + return nil +} + +func (region *SRegion) ConvertPublicIpToEip(instanceId string) error { + params := map[string]string{ + "InstanceId": instanceId, + "Region": region.Region, + } + _, err := region.vpcRequest("TransformAddress", params) + if err != nil { + log.Errorf("TransformAddress fail %s", err) + return err + } + return nil +} + +func (self *SInstance) ConvertPublicIpToEip() error { + return self.host.zone.region.ConvertPublicIpToEip(self.InstanceId) +} + +func (self *SInstance) IsAutoRenew() bool { + return self.RenewFlag == "NOTIFY_AND_AUTO_RENEW" +} + +// https://cloud.tencent.com/document/api/213/15752 +func (region *SRegion) SetInstanceAutoRenew(instanceId string, autoRenew bool) error { + params := map[string]string{ + "InstanceIds.0": instanceId, + "Region": region.Region, + "RenewFlag": "NOTIFY_AND_MANUAL_RENEW", + } + if autoRenew { + params["RenewFlag"] = "NOTIFY_AND_AUTO_RENEW" + } + _, err := region.cvmRequest("ModifyInstancesRenewFlag", params, true) + return err +} + +func (self *SInstance) SetAutoRenew(bc billing.SBillingCycle) error { + return self.host.zone.region.SetInstanceAutoRenew(self.InstanceId, bc.AutoRenew) +} + +func (self *SInstance) SetTags(tags map[string]string, replace bool) error { + return self.host.zone.region.SetResourceTags("cvm", "instance", []string{self.InstanceId}, tags, replace) +} + +func (self *SRegion) SaveImage(instanceId string, opts *cloudprovider.SaveImageOptions) (*SImage, error) { + params := map[string]string{ + "ImageName": opts.Name, + "InstanceId": instanceId, + } + if len(opts.Notes) > 0 { + params["ImageDescription"] = opts.Notes + } + resp, err := self.cvmRequest("CreateImage", params, true) + if err != nil { + return nil, errors.Wrapf(err, "CreateImage") + } + ret := struct{ ImageId string }{} + err = resp.Unmarshal(&ret) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + imageIds := []string{} + if len(ret.ImageId) > 0 { + imageIds = append(imageIds, ret.ImageId) + } + + images, _, err := self.GetImages("", "PRIVATE_IMAGE", imageIds, opts.Name, 0, 1) + if err != nil { + return nil, errors.Wrapf(err, "GetImage(%s,%s)", opts.Name, ret.ImageId) + } + for i := range images { + if images[i].ImageId == ret.ImageId || images[i].ImageName == opts.Name { + images[i].storageCache = self.getStoragecache() + return &images[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "after save image %s", opts.Name) +} + +func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { + image, err := self.host.zone.region.SaveImage(self.InstanceId, opts) + if err != nil { + return nil, errors.Wrapf(err, "SaveImage") + } + return image, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/instancenic.go new file mode 100644 index 0000000000..c41a8218e6 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/instancenic.go @@ -0,0 +1,54 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + instance *SInstance + + id string + ipAddr string + macAddr string + classic bool + + cloudprovider.DummyICloudNic +} + +func (self *SInstanceNic) GetId() string { + return self.id +} + +func (self *SInstanceNic) GetIP() string { + return self.ipAddr +} + +func (self *SInstanceNic) GetMAC() string { + return self.macAddr +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return self.classic +} + +func (self *SInstanceNic) GetINetworkId() string { + return self.instance.VirtualPrivateCloud.SubnetId +} diff --git a/pkg/multicloud/qcloud/instancetype.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/instancetype.go similarity index 100% rename from pkg/multicloud/qcloud/instancetype.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/instancetype.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kafka.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kafka.go new file mode 100644 index 0000000000..3fde143221 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kafka.go @@ -0,0 +1,250 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SKafka struct { + multicloud.SVirtualResourceBase + multicloud.SBillingBase + QcloudTags + region *SRegion + + InstanceId string + InstanceName string + Vip string + Vport string + VipList []struct { + Vip string + Vport string + } + Status int + Bandwidth int + DiskSize int + ZoneId int + VpcId string + SubnetId string + RenewFlag int + Healthy int + HealthyMessage string + CreateTime int + ExpireTime int + IsInternal int + TopicNum int + Version string + ZoneIds []int + Cvm int + InstanceType string + DiskType string + MaxTopicNumber int + MaxPartitionNubmer int + RebalanceTime string + MsgRetentionTime int +} + +func (self *SKafka) GetName() string { + if len(self.InstanceName) > 0 { + return self.InstanceName + } + return self.InstanceId +} + +func (self *SKafka) GetId() string { + return self.InstanceId +} + +func (self *SKafka) GetGlobalId() string { + return self.InstanceId +} + +func (self *SKafka) GetVpcId() string { + return self.VpcId +} + +func (self *SKafka) GetNetworkId() string { + return self.SubnetId +} + +func (self *SKafka) IsAutoRenew() bool { + return self.RenewFlag == 1 +} + +func (self *SKafka) GetBillingType() string { + return billing_api.BILLING_TYPE_PREPAID +} + +func (self *SKafka) GetCreatedAt() time.Time { + return time.Unix(int64(self.CreateTime), 0) +} + +func (self *SKafka) GetExpiredAt() time.Time { + return time.Unix(int64(self.ExpireTime), 0) +} + +func (self *SKafka) GetInstanceType() string { + return self.InstanceType +} + +func (self *SKafka) GetDiskSizeGb() int { + return self.DiskSize +} + +func (self *SKafka) GetVersion() string { + return self.Version +} + +func (self *SKafka) IsMultiAz() bool { + return len(self.ZoneIds) > 1 +} + +func (self *SKafka) GetBandwidthMb() int { + return self.Bandwidth / 8 +} + +func (self *SKafka) GetStorageType() string { + return self.DiskType +} + +func (self *SKafka) GetEndpoint() string { + endpoints := []string{} + var add = func(vip, vport string) { + endpoint := fmt.Sprintf("%s:%s", vip, vport) + if len(vip) > 0 && len(vport) > 0 && !utils.IsInStringArray(endpoint, endpoints) { + endpoints = append(endpoints, endpoint) + } + } + for _, ed := range self.VipList { + add(ed.Vip, ed.Vport) + } + add(self.Vip, self.Vport) + return strings.Join(endpoints, ",") +} + +func (self *SKafka) GetStatus() string { + switch self.Status { + case 0: + return api.KAFKA_STATUS_CREATING + case 1: + return api.KAFKA_STATUS_AVAILABLE + case 2: + return api.KAFKA_STATUS_DELETING + default: + return fmt.Sprintf("%d", self.Status) + } +} + +func (self *SKafka) GetMsgRetentionMinute() int { + if self.MsgRetentionTime == 0 { + self.Refresh() + } + return self.MsgRetentionTime +} + +func (self *SKafka) GetZoneId() string { + return fmt.Sprintf("%s-%d", self.region.Region, self.ZoneId) +} + +func (self *SKafka) Refresh() error { + kafka, err := self.region.GetKafka(self.InstanceId) + if err != nil { + return err + } + return jsonutils.Update(self, kafka) +} + +func (self *SKafka) Delete() error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetICloudKafkaById(id string) (cloudprovider.ICloudKafka, error) { + kafka, err := self.GetKafka(id) + if err != nil { + return nil, errors.Wrapf(err, "GetKafka(%s)", id) + } + return kafka, nil +} + +func (self *SRegion) GetICloudKafkas() ([]cloudprovider.ICloudKafka, error) { + kafkas := []SKafka{} + for { + part, total, err := self.GetKafkas("", 20, len(kafkas)) + if err != nil { + return nil, errors.Wrapf(err, "GetKafkas") + } + kafkas = append(kafkas, part...) + if len(kafkas) >= total { + break + } + } + ret := []cloudprovider.ICloudKafka{} + for i := range kafkas { + kafkas[i].region = self + ret = append(ret, &kafkas[i]) + } + return ret, nil +} + +func (self *SRegion) GetKafka(id string) (*SKafka, error) { + params := map[string]string{ + "InstanceId": id, + } + resp, err := self.kafkaRequest("DescribeInstanceAttributes", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeInstanceAttributes") + } + ret := SKafka{region: self} + err = resp.Unmarshal(&ret, "Result") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return &ret, nil +} + +func (self *SRegion) GetKafkas(id string, limit, offset int) ([]SKafka, int, error) { + if limit < 1 || limit > 20 { + limit = 20 + } + params := map[string]string{ + "Limit": fmt.Sprintf("%d", limit), + "Offset": fmt.Sprintf("%d", offset), + } + if len(id) > 0 { + params["InstanceId"] = id + } + resp, err := self.kafkaRequest("DescribeInstancesDetail", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeInstancesDetail") + } + ret := []SKafka{} + err = resp.Unmarshal(&ret, "Result", "InstanceList") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + totalCount, _ := resp.Int("Result", "TotalCount") + return ret, int(totalCount), nil +} diff --git a/pkg/multicloud/qcloud/kafka_topic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kafka_topic.go similarity index 97% rename from pkg/multicloud/qcloud/kafka_topic.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kafka_topic.go index a3ebeb48ca..ca205399c5 100644 --- a/pkg/multicloud/qcloud/kafka_topic.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kafka_topic.go @@ -19,7 +19,7 @@ import ( "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) func (self *SKafka) GetTopics() ([]cloudprovider.SKafkaTopic, error) { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/keypair.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/keypair.go new file mode 100644 index 0000000000..6d7c8a288b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/keypair.go @@ -0,0 +1,193 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strconv" + "time" + + "github.com/aokoli/goutils" + "golang.org/x/crypto/ssh" + + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SKeypair struct { + AssociatedInstanceIds []string + CreateTime time.Time + Description string + KeyId string + KeyName string + PublicKey string +} + +func (self *SRegion) GetKeypairs(name string, keyIds []string, offset int, limit int) ([]SKeypair, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := map[string]string{} + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + + if len(keyIds) > 0 { + for i := 0; i < len(keyIds); i++ { + params[fmt.Sprintf("KeyIds.%d", i)] = keyIds[i] + } + } else { + if len(name) > 0 { + params["Filters.0.Name"] = "key-name" + params["Filters.0.Values.0"] = name + } + } + + body, err := self.cvmRequest("DescribeKeyPairs", params, true) + if err != nil { + log.Errorf("GetKeypairs fail %s", err) + return nil, 0, err + } + + keypairs := []SKeypair{} + err = body.Unmarshal(&keypairs, "KeyPairSet") + if err != nil { + log.Errorf("Unmarshal keypair fail %s", err) + return nil, 0, err + } + total, _ := body.Float("TotalCount") + return keypairs, int(total), nil +} + +func (self *SRegion) ImportKeypair(name string, pubKey string) (*SKeypair, error) { + params := map[string]string{} + params["PublicKey"] = pubKey + params["ProjectId"] = "0" + params["KeyName"] = name + + body, err := self.cvmRequest("ImportKeyPair", params, true) + if err != nil { + log.Errorf("ImportKeypair fail %s", err) + return nil, err + } + + keypairID, err := body.GetString("KeyId") + if err != nil { + return nil, err + } + keypairs, total, err := self.GetKeypairs("", []string{keypairID}, 0, 1) + if err != nil { + return nil, err + } + if total != 1 { + return nil, cloudprovider.ErrNotFound + } + return &keypairs[0], nil +} + +func (self *SRegion) AttachKeypair(instanceId string, keypairId string) error { + params := map[string]string{} + params["InstanceIds.0"] = instanceId + params["KeyIds.0"] = keypairId + _, err := self.cvmRequest("AssociateInstancesKeyPairs", params, true) + return err +} + +func (self *SRegion) DetachKeyPair(instanceId string, keypairId string) error { + params := make(map[string]string) + params["InstanceIds.0"] = instanceId + params["KeyIds.0"] = keypairId + _, err := self.cvmRequest("DisassociateInstancesKeyPairs", params, true) + return err +} + +func (self *SRegion) CreateKeyPair(name string) (*SKeypair, error) { + params := make(map[string]string) + params["KeyName"] = name + params["ProjectId"] = "0" + body, err := self.cvmRequest("CreateKeyPair", params, true) + keypair := SKeypair{} + err = body.Unmarshal(&keypair, "KeyPair") + if err != nil { + return nil, err + } + return &keypair, err +} + +func (self *SRegion) getKeypairs() ([]SKeypair, error) { + keypairs := []SKeypair{} + for { + parts, total, err := self.GetKeypairs("", []string{}, 0, 50) + if err != nil { + log.Errorf("Get keypairs fail %v", err) + return nil, err + } + keypairs = append(keypairs, parts...) + if len(keypairs) >= total { + break + } + } + return keypairs, nil +} + +func (self *SRegion) getFingerprint(publicKey string) (string, error) { + pk, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKey)) + if err != nil { + return "", fmt.Errorf("publicKey error %s", err) + } + return ssh.FingerprintLegacyMD5(pk), nil +} + +func (self *SRegion) lookUpQcloudKeypair(publicKey string) (string, error) { + keypairs, err := self.getKeypairs() + if err != nil { + return "", err + } + + localFiger, err := self.getFingerprint(publicKey) + if err != nil { + return "", err + } + + for i := 0; i < len(keypairs); i++ { + finger, err := self.getFingerprint(keypairs[i].PublicKey) + if err != nil { + continue + } + if finger == localFiger { + return keypairs[i].KeyId, nil + } + } + return "", cloudprovider.ErrNotFound +} + +func (self *SRegion) syncKeypair(publicKey string) (string, error) { + keypairId, err := self.lookUpQcloudKeypair(publicKey) + if err == nil { + return keypairId, nil + } + + prefix, e := goutils.RandomAlphabetic(6) + if e != nil { + return "", fmt.Errorf("publicKey error %s", e) + } + + name := prefix + strconv.FormatInt(time.Now().Unix(), 10) + keypair, err := self.ImportKeypair(name, publicKey) + if err != nil { + return "", err + } + return keypair.KeyId, nil +} diff --git a/pkg/multicloud/qcloud/kube_clusters.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kube_clusters.go similarity index 98% rename from pkg/multicloud/qcloud/kube_clusters.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kube_clusters.go index b26efefefc..05556602a9 100644 --- a/pkg/multicloud/qcloud/kube_clusters.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kube_clusters.go @@ -21,13 +21,13 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SKubeCluster struct { multicloud.SResourceBase - multicloud.QcloudTags + QcloudTags region *SRegion ClusterId string diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kube_node_pools.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kube_node_pools.go new file mode 100644 index 0000000000..ffcf3a422a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kube_node_pools.go @@ -0,0 +1,113 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SKubeNodePool struct { + multicloud.SResourceBase + QcloudTags + + cluster *SKubeCluster + + NodePoolId string + Name string + ClusterInstanceId string + LifeState string + LaunchConfigurationId string + AutoscalingGroupId string + Labels []struct { + Name string + Value string + } + Taints []struct { + Kye string + Value string + Effect string + } + NodeCountSummary struct { + ManuallyAdded struct { + Joining int + Initializing int + Normal int + Total int + } + AutoscalingAdded struct { + Joining int + Initializing int + Normal int + Total int + } + } + AutoscalingGroupStatus string + MaxNodesNum int + MinNodesNum int + DesiredNodesNum int + NodePoolOs string + OsCustomizeType string + ImageId string + DesiredPodNum int + UserScript string +} + +func (self *SKubeNodePool) GetId() string { + return self.NodePoolId +} + +func (self *SKubeNodePool) GetGlobalId() string { + return self.NodePoolId +} + +func (self *SKubeNodePool) GetName() string { + return self.Name +} + +func (self *SKubeNodePool) GetStatus() string { + return self.LifeState +} + +func (self *SKubeCluster) GetIKubeNodePools() ([]cloudprovider.ICloudKubeNodePool, error) { + pools, err := self.region.GetKubeNodePools(self.ClusterId) + if err != nil { + return nil, errors.Wrapf(err, "GetKubeNodePools") + } + ret := []cloudprovider.ICloudKubeNodePool{} + for i := range pools { + pools[i].cluster = self + ret = append(ret, &pools[i]) + } + return ret, nil +} + +func (self *SRegion) GetKubeNodePools(clusterId string) ([]SKubeNodePool, error) { + params := map[string]string{ + "ClusterId": clusterId, + } + resp, err := self.tkeRequest("DescribeClusterNodePools", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeClusterNodePools") + } + pools := []SKubeNodePool{} + err = resp.Unmarshal(&pools, "NodePoolSet") + if err != nil { + return nil, errors.Wrapf(err, "NodePoolSet") + } + return pools, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kube_nodes.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kube_nodes.go new file mode 100644 index 0000000000..7ae1055a0a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/kube_nodes.go @@ -0,0 +1,126 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SKubeNode struct { + multicloud.SResourceBase + QcloudTags + + cluster *SKubeCluster + + InstanceId string + InstanceRole string + FailedReason string + InstanceState string + DrainStatus string + InstanceAdvancedSettings struct { + MountTarget string + DockerGraphPath string + UserScript string + Unschedulable int + DesiredPodNumber int + PreStartUserScript string + Labels []struct { + Name string + Value string + } + DataDisks []struct { + DiskType string + FileSystem string + DiskSize int + AutoFormatAndMount bool + MountTarget string + DiskPartition string + } + ExtraArgs struct { + Kubelet []string + } + } + CreatedTime string + LanIP string + NodePoolId string + AutoscalingGroupId string +} + +func (self *SKubeNode) GetId() string { + return self.InstanceId +} + +func (self *SKubeNode) GetGlobalId() string { + return self.InstanceId +} + +func (self *SKubeNode) GetName() string { + return self.InstanceId +} + +func (self *SKubeNode) GetStatus() string { + return self.DrainStatus +} + +func (self *SKubeNode) GetINodePoolId() string { + return self.NodePoolId +} + +func (self *SKubeCluster) GetIKubeNodes() ([]cloudprovider.ICloudKubeNode, error) { + nodes := []SKubeNode{} + for { + part, total, err := self.region.GetKubeNodes(self.ClusterId, 100, len(nodes)/100) + if err != nil { + return nil, errors.Wrapf(err, "GetIKubeNodes") + } + nodes = append(nodes, part...) + if len(nodes) >= total || len(part) == 0 { + break + } + } + ret := []cloudprovider.ICloudKubeNode{} + for i := range nodes { + nodes[i].cluster = self + ret = append(ret, &nodes[i]) + } + return ret, nil +} + +func (self *SRegion) GetKubeNodes(clusterId string, limit, offset int) ([]SKubeNode, int, error) { + if limit < 1 || limit > 100 { + limit = 100 + } + params := map[string]string{ + "Limit": fmt.Sprintf("%d", limit), + "Offset": fmt.Sprintf("%d", offset), + "ClusterId": clusterId, + } + resp, err := self.tkeRequest("DescribeClusterInstances", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeClusterInstances") + } + nodes := []SKubeNode{} + err = resp.Unmarshal(&nodes, "InstanceSet") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + totalCount, _ := resp.Float("TotalCount") + return nodes, int(totalCount), nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/latitud_and_longitude.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/latitud_and_longitude.go new file mode 100644 index 0000000000..d2a4c0a348 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/latitud_and_longitude.go @@ -0,0 +1,43 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ + "ap-bangkok": api.RegionBangkok, // 腾讯云 亚太地区(曼谷) + "ap-beijing": api.RegionBeijing, // 腾讯云 华北地区(北京) + "ap-chengdu": api.RegionChengdu, // 腾讯云 西南地区(成都) + "ap-chongqing": api.RegionChongqing, // 腾讯云 西南地区(重庆) + "ap-guangzhou": api.RegionGuangzhou, // 腾讯云 华南地区(广州) + "ap-guangzhou-open": api.RegionGuangzhou, // 腾讯云 华南地区(广州Open) + "ap-hongkong": api.RegionHongkong, // 腾讯云 东南亚地区(香港) + "ap-mumbai": api.RegionMumbai, // 腾讯云 亚太地区(孟买) + "ap-seoul": api.RegionSeoul, // 腾讯云 东南亚地区(首尔) + "ap-shanghai": api.RegionShanghai, // 腾讯云 华东地区(上海) + "ap-shanghai-fsi": api.RegionShanghai, // 腾讯云 华东地区(上海金融) + "ap-shenzhen-fsi": api.RegionShenzhen, // 腾讯云 华南地区(深圳金融) + "ap-singapore": api.RegionSingapore, // 腾讯云 东南亚地区(新加坡) + "ap-tokyo": api.RegionTokyo, // 腾讯云 亚太地区(东京) + "eu-frankfurt": api.RegionFrankfurt, // 腾讯云 欧洲地区(德国) + "eu-moscow": api.RegionMoscow, // 腾讯云 欧洲地区(莫斯科) + "na-ashburn": api.RegionVirginia, // 腾讯云 美国东部(弗吉尼亚) + "na-siliconvalley": api.RegionSiliconValley, // 腾讯云 美国西部(硅谷) + "na-toronto": api.RegionToronto, // 腾讯云 北美地区(多伦多) + "ap-nanjing": api.RegionNanjing, +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer.go new file mode 100644 index 0000000000..cbeb124557 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer.go @@ -0,0 +1,715 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + LB_ADDR_TYPE_INTERNAL = "INTERNAL" + LB_ADDR_TYPE_OPEN = "OPEN" +) + +type LB_TYPE int64 + +const ( + LB_TYPE_CLASSIC = LB_TYPE(0) + LB_TYPE_APPLICATION = LB_TYPE(1) +) + +/* +todo: +1.统一LB 证书fingerprint算法.另外缺少一个回写指纹算法到数据库的方法。 +2.需要同步腾讯云LB 所在的project +*/ + +// https://cloud.tencent.com/document/api/214/30694#LoadBalancer +type SLoadbalancer struct { + multicloud.SLoadbalancerBase + QcloudTags + region *SRegion + + Status int64 `json:"Status"` // 0:创建中,1:正常运行 + Domain string `json:"Domain"` + VpcID string `json:"VpcId"` + Log string `json:"Log"` + ProjectID int64 `json:"ProjectId"` + Snat bool `json:"Snat"` + LoadBalancerID string `json:"LoadBalancerId"` + LoadBalancerVips []string `json:"LoadBalancerVips"` + LoadBalancerType string `json:"LoadBalancerType"` // 负载均衡实例的网络类型: OPEN:公网属性, INTERNAL:内网属性。 + LoadBalancerName string `json:"LoadBalancerName"` + Forward LB_TYPE `json:"Forward"` // 应用型负载均衡标识,1:应用型负载均衡,0:传统型的负载均衡。 + StatusTime time.Time `json:"StatusTime"` + OpenBGP int64 `json:"OpenBgp"` // 高防 LB 的标识,1:高防负载均衡 0:非高防负载均衡。 + CreateTime time.Time `json:"CreateTime"` + Isolation int64 `json:"Isolation"` // 0:表示未被隔离,1:表示被隔离。 + SubnetId string `json:"SubnetId"` + BackupZoneSet []ZoneSet `json:"BackupZoneSet"` + MasterZone ZoneSet `json:"MasterZone"` + NetworkAttributes struct { + InternetChargeType string + InternetMaxBandwidthOut int + } +} + +type ZoneSet struct { + Zone string `json:"Zone"` + ZoneID int64 `json:"ZoneId"` + ZoneName string `json:"ZoneName"` +} + +func (self *SLoadbalancer) GetLoadbalancerSpec() string { + return "" +} + +func (self *SLoadbalancer) GetChargeType() string { + if len(self.NetworkAttributes.InternetChargeType) > 0 && self.NetworkAttributes.InternetChargeType != "TRAFFIC_POSTPAID_BY_HOUR" { + return api.LB_CHARGE_TYPE_BY_BANDWIDTH + } + return api.LB_CHARGE_TYPE_BY_TRAFFIC +} + +func (self *SLoadbalancer) GetEgressMbps() int { + return self.NetworkAttributes.InternetMaxBandwidthOut +} + +// https://cloud.tencent.com/document/product/214/30689 +func (self *SLoadbalancer) Delete(ctx context.Context) error { + lockman.LockRawObject(ctx, "qcloud.SLoadbalancer.Delete", self.region.client.ownerId) + defer lockman.ReleaseRawObject(ctx, "qcloud.SLoadbalancer.Delete", self.region.client.ownerId) + + if self.Forward == LB_TYPE_APPLICATION { + _, err := self.region.DeleteLoadbalancer(self.GetId()) + if err != nil { + return err + } + } else { + _, err := self.region.DeleteClassicLoadbalancer(self.GetId()) + if err != nil { + return err + } + } + + return cloudprovider.WaitDeleted(self, 5*time.Second, 60*time.Second) +} + +// 腾讯云loadbalance不支持启用/禁用 +func (self *SLoadbalancer) Start() error { + return nil +} + +func (self *SLoadbalancer) Stop() error { + return cloudprovider.ErrNotSupported +} + +// 腾讯云无后端服务器组 +// todo: 是否返回一个fake的后端服务器组 +func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + groups, err := self.GetILoadBalancerBackendGroups() + if err != nil { + return nil, err + } + + for _, group := range groups { + if group.GetId() == groupId { + return group, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func onecloudHealthCodeToQcloud(codes string) int { + qcode := 0 + for i, code := range HTTP_CODES { + if strings.Contains(codes, code) { + // 按位或然后再赋值qcode + qcode |= 1 << uint(i) + } + } + + return qcode +} + +// https://cloud.tencent.com/document/product/214/30693 +// todo: 1.限制比较多必须加参数校验 2.Onecloud 不支持双向证书可能存在兼容性问题 +// 应用型负载均衡 传统型不支持设置SNI +func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + lockman.LockRawObject(ctx, "qcloud.SLoadbalancer.CreateILoadBalancerListener", self.region.client.ownerId) + defer lockman.ReleaseRawObject(ctx, "qcloud.SLoadbalancer.CreateILoadBalancerListener", self.region.client.ownerId) + + sniSwitch := 0 + hc := getHealthCheck(listener) + cert := getCertificate(listener) + + var listenId string + var err error + if self.Forward == LB_TYPE_APPLICATION { + listenId, err = self.region.CreateLoadbalancerListener(self.GetId(), + listener.Name, + getProtocol(listener), + listener.ListenerPort, + getScheduler(listener), + &listener.StickySessionCookieTimeout, + &sniSwitch, + hc, + cert) + } else { + // 传统型内网属性负载均衡不支持指定scheduler + var scheduler *string + if self.LoadBalancerType == "OPEN" { + scheduler = getScheduler(listener) + } + + listenId, err = self.region.CreateClassicLoadbalancerListener(self.GetId(), + listener.Name, + getClassicLBProtocol(listener), + listener.ListenerPort, + listener.BackendServerPort, + scheduler, + &listener.StickySessionCookieTimeout, + &sniSwitch, + hc, + cert) + } + if err != nil { + return nil, err + } + + var lblis cloudprovider.ICloudLoadbalancerListener + err = cloudprovider.Wait(3*time.Second, 30*time.Second, func() (bool, error) { + lblis, err = self.GetILoadBalancerListenerById(listenId) + if err != nil { + if errors.Cause(err) != cloudprovider.ErrNotFound { + return false, err + } else { + return false, nil + } + } + + return true, nil + }) + if err != nil { + return nil, errors.Wrap(err, "GetILoadBalancerListenerById.Wait") + } + + return lblis, nil +} + +func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { + listeners, err := self.GetLoadbalancerListeners("") + if err != nil { + return nil, err + } + + for _, listener := range listeners { + if listener.GetId() == listenerId { + return &listener, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SLoadbalancer) GetId() string { + return self.LoadBalancerID +} + +func (self *SLoadbalancer) GetName() string { + return self.LoadBalancerName +} + +// add region? +func (self *SLoadbalancer) GetGlobalId() string { + return self.LoadBalancerID +} + +func (self *SLoadbalancer) GetStatus() string { + switch self.Status { + case 0: + return api.LB_STATUS_INIT + case 1: + return api.LB_STATUS_ENABLED + default: + return api.LB_STATUS_UNKNOWN + } +} + +func (self *SLoadbalancer) Refresh() error { + lb, err := self.region.GetLoadbalancer(self.GetId()) + if err != nil { + return err + } + + return jsonutils.Update(self, lb) +} + +func (self *SLoadbalancer) IsEmulated() bool { + return false +} + +func (self *SLoadbalancer) GetSysTags() map[string]string { + meta := map[string]string{} + meta["Forward"] = strconv.FormatInt(int64(self.Forward), 10) + meta["OpenBGP"] = strconv.FormatInt(self.OpenBGP, 10) + meta["Domain"] = self.Domain + meta["ProjectID"] = strconv.FormatInt(self.ProjectID, 10) + return meta +} + +// 腾讯云当前不支持一个LB绑定多个ip,每个LB只支持绑定一个ip +func (self *SLoadbalancer) GetAddress() string { + return self.LoadBalancerVips[0] +} + +func (self *SLoadbalancer) GetAddressType() string { + switch self.LoadBalancerType { + case LB_ADDR_TYPE_INTERNAL: + return api.LB_ADDR_TYPE_INTRANET + case LB_ADDR_TYPE_OPEN: + return api.LB_ADDR_TYPE_INTERNET + default: + return "" + } +} + +func (self *SLoadbalancer) GetNetworkType() string { + if len(self.VpcID) > 0 { + return api.LB_NETWORK_TYPE_VPC + } else { + return api.LB_NETWORK_TYPE_CLASSIC + } +} + +func (self *SLoadbalancer) GetNetworkIds() []string { + if len(self.SubnetId) == 0 { + return []string{} + } + + return []string{self.SubnetId} +} + +func (self *SLoadbalancer) GetVpcId() string { + return self.VpcID +} + +func (self *SLoadbalancer) GetZoneId() string { + zoneId := "" + if len(self.MasterZone.Zone) > 0 { + zoneId = self.MasterZone.Zone + } else if len(self.SubnetId) > 0 { + net, err := self.region.GetNetwork(self.SubnetId) + if err != nil { + log.Warningf("GetNetwork %s %s", self.SubnetId, err) + return "" + } + + zoneId = net.Zone + } + + if len(zoneId) > 0 { + z, err := self.region.getZoneById(zoneId) + if err != nil { + log.Warningf("getZoneById %s %s", zoneId, err) + return "" + } + + return z.GetGlobalId() + } + + return "" +} + +func (self *SLoadbalancer) GetZone1Id() string { + if self.BackupZoneSet == nil { + return "" + } + + if len(self.BackupZoneSet) > 0 { + z, err := self.region.getZoneById(self.BackupZoneSet[0].Zone) + if err != nil { + log.Warningf("getZoneById %s %s", self.BackupZoneSet[0].Zone, err) + return "" + } + + return z.GetGlobalId() + } + + return "" +} + +func (self *SLoadbalancer) GetLoadbalancerListeners(protocal string) ([]SLBListener, error) { + listeners, err := self.region.GetLoadbalancerListeners(self.GetId(), self.Forward, protocal) + if err != nil { + return nil, err + } + + for i := range listeners { + listeners[i].lb = self + } + + return listeners, nil +} + +func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + listeners, err := self.GetLoadbalancerListeners("") + if err != nil { + return nil, err + } + + ilisteners := make([]cloudprovider.ICloudLoadbalancerListener, len(listeners)) + for i := range listeners { + l := listeners[i] + ilisteners[i] = &l + } + + return ilisteners, nil +} + +func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + if self.Forward == LB_TYPE_CLASSIC { + bg := SLBBackendGroup{lb: self} + return []cloudprovider.ICloudLoadbalancerBackendGroup{&bg}, nil + } + + listeners, err := self.GetLoadbalancerListeners("") + if err != nil { + return nil, err + } + + bgs := []cloudprovider.ICloudLoadbalancerBackendGroup{} + for i := range listeners { + listener := listeners[i] + t := listener.GetListenerType() + if t == api.LB_LISTENER_TYPE_HTTP || t == api.LB_LISTENER_TYPE_HTTPS { + rules := listener.Rules + for i := range rules { + rule := rules[i] + rule.listener = &listener + bg := rule.GetBackendGroup() + bgs = append(bgs, bg) + } + } else { + bg := listener.GetBackendGroup() + bgs = append(bgs, bg) + } + } + + ibgs := make([]cloudprovider.ICloudLoadbalancerBackendGroup, len(bgs)) + for i := range bgs { + ibgs[i] = bgs[i] + } + + return ibgs, nil +} + +func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { + if self.LoadBalancerType == "OPEN" && len(self.LoadBalancerVips) > 0 { + return &SEipAddress{ + region: self.region, + AddressId: self.LoadBalancerID, + AddressIp: self.LoadBalancerVips[0], + AddressType: EIP_STATUS_BIND, + InstanceId: self.LoadBalancerID, + CreatedTime: self.CreateTime, + }, nil + } + return nil, nil +} + +func (self *SRegion) GetLoadbalancers(ids []string) ([]SLoadbalancer, error) { + params := map[string]string{} + for i, id := range ids { + params[fmt.Sprintf("LoadBalancerIds.%d", i)] = id + } + + offset := 0 + limit := 100 + lbs := make([]SLoadbalancer, 0) + for { + params["Limit"] = strconv.Itoa(limit) + params["Offset"] = strconv.Itoa(offset) + + resp, err := self.clbRequest("DescribeLoadBalancers", params) + if err != nil { + return nil, err + } + + parts := make([]SLoadbalancer, 0) + err = resp.Unmarshal(&parts, "LoadBalancerSet") + if err != nil { + return nil, err + } + + _total, err := resp.Float("TotalCount") + if err != nil { + return nil, err + } + + total := int(_total) + if err != nil { + return nil, err + } + + lbs = append(lbs, parts...) + offset += len(parts) + if offset >= total { + for i := range lbs { + lbs[i].region = self + } + + return lbs, err + } + } +} + +func (self *SRegion) GetLoadbalancer(id string) (*SLoadbalancer, error) { + if len(id) == 0 { + return nil, fmt.Errorf("GetILoadbalancer id should not empty") + } + + lbs, err := self.GetLoadbalancers([]string{id}) + if err != nil { + return nil, err + } + + switch len(lbs) { + case 0: + return nil, cloudprovider.ErrNotFound + case 1: + return &lbs[0], nil + default: + return nil, fmt.Errorf("GetILoadbalancer %s found %d", id, len(lbs)) + } +} + +/* +返回requstid 用于异步任务查询 +https://cloud.tencent.com/document/product/214/30689 +*/ +func (self *SRegion) DeleteLoadbalancer(lbid string) (string, error) { + if len(lbid) == 0 { + return "", fmt.Errorf("loadbalancer id should not be empty") + } + + params := map[string]string{"LoadBalancerIds.0": lbid} + resp, err := self.clbRequest("DeleteLoadBalancer", params) + if err != nil { + return "", err + } + + return resp.GetString("RequestId") +} + +/* +返回requstid 用于异步任务查询 +https://cloud.tencent.com/document/product/214/30689 +*/ +func (self *SRegion) DeleteClassicLoadbalancer(lbid string) (string, error) { + if len(lbid) == 0 { + return "", fmt.Errorf("loadbalancer id should not be empty") + } + + params := map[string]string{"loadBalancerIds.n": lbid} + resp, err := self.lbRequest("DeleteLoadBalancers", params) + if err != nil { + return "", err + } + + return resp.GetString("requestId") +} + +/* +https://cloud.tencent.com/document/product/214/30693 +SNI 特性是什么?? +*/ +func (self *SRegion) CreateLoadbalancerListener(lbid, name, protocol string, port int, scheduler *string, sessionExpireTime, sniSwitch *int, healthCheck *healthCheck, cert *certificate) (string, error) { + if len(lbid) == 0 { + return "", fmt.Errorf("loadbalancer id should not be empty") + } + + params := map[string]string{ + "LoadBalancerId": lbid, + "Ports.0": strconv.Itoa(port), + "Protocol": protocol, + } + + if len(name) > 0 { + params["ListenerNames.0"] = name + } + + if utils.IsInStringArray(protocol, []string{PROTOCOL_TCP, PROTOCOL_UDP, PROTOCOL_TCP_SSL}) { + params = healthCheckParams(LB_TYPE_APPLICATION, params, healthCheck, "HealthCheck.") + + if scheduler != nil && len(*scheduler) > 0 { + params["Scheduler"] = *scheduler + } + + if sessionExpireTime != nil { + params["SessionExpireTime"] = strconv.Itoa(*sessionExpireTime) + } + } else { + if protocol == PROTOCOL_HTTPS && sniSwitch != nil { + params["SniSwitch"] = strconv.Itoa(*sniSwitch) + } + } + + params = certificateParams(LB_TYPE_APPLICATION, params, cert, "Certificate.") + + resp, err := self.clbRequest("CreateListener", params) + if err != nil { + return "", err + } + + listeners, err := resp.GetArray("ListenerIds") + if err != nil { + return "", err + } + + if len(listeners) == 0 { + return "", fmt.Errorf("CreateLoadbalancerListener no listener id returned: %s", resp.String()) + } else if len(listeners) == 1 { + return listeners[0].GetString() + } else { + return "", fmt.Errorf("CreateLoadbalancerListener mutliple listener id returned: %s", resp.String()) + } +} + +// https://cloud.tencent.com/document/api/214/1255 +// 不支持sniSwitch +// todo: 待测试 +func (self *SRegion) CreateClassicLoadbalancerListener(lbid, name string, protocol, port, backendServerPort int, scheduler *string, sessionExpireTime, sniSwitch *int, healthCheck *healthCheck, cert *certificate) (string, error) { + if len(lbid) == 0 { + return "", fmt.Errorf("loadbalancer id should not be empty") + } + + // 负载均衡实例监听器协议类型 1:HTTP,2:TCP,3:UDP,4:HTTPS。 + // todo: 待测试 。 这里没有判断是否为公网负载均衡,可能存在问题.内网传统型负载均衡监听协议只支持TCP、UDP,并且不能指定调度算法 + params := map[string]string{ + "loadBalancerId": lbid, + "listeners.0.loadBalancerPort": strconv.Itoa(port), + "listeners.0.instancePort": strconv.Itoa(backendServerPort), + "listeners.0.protocol": strconv.Itoa(protocol), + } + + if len(name) > 0 { + params["listeners.0.listenerName"] = name + } + + if sessionExpireTime != nil { + params["listeners.0.sessionExpire"] = strconv.Itoa(*sessionExpireTime) + } + + if scheduler != nil && len(*scheduler) > 0 && (protocol == 2 || protocol == 3) { + params["listeners.0.scheduler"] = strings.ToLower(*scheduler) + } + + if scheduler != nil && len(*scheduler) > 0 && (protocol == 1 || protocol == 4) { + params["listeners.0.httpHash"] = strings.ToLower(*scheduler) + } + + params = healthCheckParams(LB_TYPE_CLASSIC, params, healthCheck, "listeners.0.") + params = certificateParams(LB_TYPE_CLASSIC, params, cert, "listeners.0.") + + resp, err := self.lbRequest("CreateLoadBalancerListeners", params) + if err != nil { + return "", err + } + + listeners, err := resp.GetArray("listenerIds") + if err != nil { + return "", err + } + + if len(listeners) == 0 { + return "", fmt.Errorf("CreateLoadbalancerListener no listener id returned: %s", resp.String()) + } else if len(listeners) == 1 { + return listeners[0].GetString() + } else { + return "", fmt.Errorf("CreateLoadbalancerListener mutliple listener id returned: %s", resp.String()) + } +} + +// https://cloud.tencent.com/document/product/214/30683 +// 任务的当前状态。 0:成功,1:失败,2:进行中 +func (self *SRegion) GetLBTaskStatus(requestId string) (string, error) { + if len(requestId) == 0 { + return "", fmt.Errorf("WaitTaskSuccess requestId should not be emtpy") + } + + params := map[string]string{"TaskId": requestId} + resp, err := self.clbRequest("DescribeTaskStatus", params) + if err != nil { + return "", err + } + + status, err := resp.Get("Status") + if err != nil { + log.Debugf("WaitTaskSuccess failed %s: %s", err, resp.String()) + return "", err + } + + _status, err := status.Float() + return fmt.Sprintf("%1.f", _status), err +} + +func (self *SRegion) WaitLBTaskSuccess(requestId string, interval time.Duration, timeout time.Duration) error { + startTime := time.Now() + for time.Now().Sub(startTime) < timeout { + status, err := self.GetLBTaskStatus(requestId) + if err != nil { + return err + } + if status == "0" { + return nil + } + + if status == "1" { + return fmt.Errorf("Task %s failed.", requestId) + } + + time.Sleep(interval) + } + + return cloudprovider.ErrTimeout +} + +func (self *SLoadbalancer) GetProjectId() string { + return strconv.Itoa(int(self.ProjectID)) +} + +func (self *SLoadbalancer) SetTags(tags map[string]string, replace bool) error { + return self.region.SetResourceTags("clb", "clb", []string{self.LoadBalancerID}, tags, replace) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_acl.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_acl.go new file mode 100644 index 0000000000..58e3d098da --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_acl.go @@ -0,0 +1,73 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// 腾讯云没有LB ACL +type SLBACL struct { + multicloud.SResourceBase + QcloudTags +} + +func (self *SLBACL) GetAclListenerID() string { + return "" +} + +func (self *SLBACL) Sync(acl *cloudprovider.SLoadbalancerAccessControlList) error { + return nil +} + +func (self *SLBACL) Delete() error { + return nil +} + +func (self *SLBACL) GetId() string { + return "" +} + +func (self *SLBACL) GetName() string { + return "" +} + +func (self *SLBACL) GetGlobalId() string { + return "" +} + +func (self *SLBACL) GetStatus() string { + return api.LB_BOOL_OFF +} + +func (self *SLBACL) Refresh() error { + return nil +} + +func (self *SLBACL) IsEmulated() bool { + return false +} + +func (self *SLBACL) GetAclEntries() *jsonutils.JSONArray { + return nil +} + +func (self *SLBACL) GetProjectId() string { + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_backend.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_backend.go new file mode 100644 index 0000000000..954e91c916 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_backend.go @@ -0,0 +1,209 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLBBackend struct { + multicloud.SResourceBase + QcloudTags + group *SLBBackendGroup + + PublicIPAddresses []string `json:"PublicIpAddresses"` + Weight int `json:"Weight"` + InstanceID string `json:"InstanceId"` + InstanceName string `json:"InstanceName"` + PrivateIPAddresses []string `json:"PrivateIpAddresses"` + RegisteredTime string `json:"RegisteredTime"` + Type string `json:"Type"` + Port int `json:"Port"` +} + +// ========================================================== +type SListenerBackend struct { + Rules []rule `json:"Rules"` + Targets []SLBBackend `json:"Targets"` + Protocol string `json:"Protocol"` + ListenerID string `json:"ListenerId"` + Port int64 `json:"Port"` +} + +type rule struct { + URL string `json:"Url"` + Domain string `json:"Domain"` + LocationID string `json:"LocationId"` + Targets []SLBBackend `json:"Targets"` +} + +// ========================================================== + +// backend InstanceID + protocol +Port + ip + rip全局唯一 +func (self *SLBBackend) GetId() string { + return fmt.Sprintf("%s/%s-%d", self.group.GetId(), self.InstanceID, self.Port) +} + +func (self *SLBBackend) GetName() string { + return self.GetId() +} + +func (self *SLBBackend) GetGlobalId() string { + return self.GetId() +} + +func (self *SLBBackend) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLBBackend) Refresh() error { + backends, err := self.group.GetBackends() + if err != nil { + return err + } + + for _, backend := range backends { + if backend.GetId() == self.GetId() { + return jsonutils.Update(self, backend) + } + } + + return cloudprovider.ErrNotFound +} + +func (self *SLBBackend) IsEmulated() bool { + return false +} + +func (self *SLBBackend) GetWeight() int { + return self.Weight +} + +func (self *SLBBackend) GetPort() int { + return self.Port +} + +func (self *SLBBackend) GetBackendType() string { + return api.LB_BACKEND_GUEST +} + +func (self *SLBBackend) GetBackendRole() string { + return api.LB_BACKEND_ROLE_DEFAULT +} + +func (self *SLBBackend) GetBackendId() string { + return self.InstanceID +} + +func (self *SLBBackend) GetIpAddress() string { + return "" +} + +// 传统型: https://cloud.tencent.com/document/product/214/31790 +func (self *SRegion) getClassicBackends(lbId, listenerId string) ([]SLBBackend, error) { + params := map[string]string{"LoadBalancerId": lbId} + + resp, err := self.clbRequest("DescribeClassicalLBTargets", params) + if err != nil { + return nil, err + } + + backends := []SLBBackend{} + err = resp.Unmarshal(&backends, "Targets") + if err != nil { + return nil, err + } + return backends, nil +} + +// 应用型: https://cloud.tencent.com/document/product/214/30684 +func (self *SRegion) getBackends(lbId, listenerId, ruleId string) ([]SLBBackend, error) { + params := map[string]string{"LoadBalancerId": lbId} + + if len(listenerId) > 0 { + params["ListenerIds.0"] = listenerId + } + + resp, err := self.clbRequest("DescribeTargets", params) + if err != nil { + return nil, err + } + + lbackends := []SListenerBackend{} + err = resp.Unmarshal(&lbackends, "Listeners") + if err != nil { + return nil, err + } + + for _, entry := range lbackends { + if (entry.Protocol == "HTTP" || entry.Protocol == "HTTPS") && len(ruleId) == 0 { + return nil, fmt.Errorf("GetBackends for http/https listener %s must specific rule id", listenerId) + } + + if len(ruleId) > 0 { + for _, r := range entry.Rules { + if r.LocationID == ruleId { + return r.Targets, nil + } + } + } else { + return entry.Targets, nil + } + } + + // todo: 这里是返回空列表还是404? + return []SLBBackend{}, nil +} + +// 注意http、https监听器必须指定ruleId +func (self *SRegion) GetLBBackends(t LB_TYPE, lbId, listenerId, ruleId string) ([]SLBBackend, error) { + if len(lbId) == 0 { + return nil, fmt.Errorf("GetLBBackends loadbalancer id should not be empty") + } + + if t == LB_TYPE_APPLICATION { + return self.getBackends(lbId, listenerId, ruleId) + } else if t == LB_TYPE_CLASSIC { + return self.getClassicBackends(lbId, listenerId) + } else { + return nil, fmt.Errorf("GetLBBackends unsupported loadbalancer type %d", t) + } +} + +func (self *SLBBackend) GetProjectId() string { + return self.group.GetProjectId() +} + +func (self *SLBBackend) SyncConf(ctx context.Context, port, weight int) error { + lockman.LockRawObject(ctx, "qcloud.SLBBackend.SyncConf", self.group.lb.region.client.ownerId) + defer lockman.ReleaseRawObject(ctx, "qcloud.SLBBackend.SyncConf", self.group.lb.region.client.ownerId) + + err := self.group.UpdateBackendServer(self.InstanceID, self.Weight, self.Port, weight, port) + if err != nil { + return err + } + + self.Port = port + self.Weight = weight + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_backendgroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_backendgroup.go new file mode 100644 index 0000000000..b9827696f7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_backendgroup.go @@ -0,0 +1,422 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLBBackendGroup struct { + multicloud.SResourceBase + QcloudTags + lb *SLoadbalancer // 必须不能为nil + listener *SLBListener // 可能为nil + rule *SLBListenerRule // tcp、udp、tcp_ssl监听rule 为nil +} + +func (self *SLBBackendGroup) GetLoadbalancerId() string { + return self.lb.GetId() +} + +func (self *SLBBackendGroup) GetILoadbalancer() cloudprovider.ICloudLoadbalancer { + return self.lb +} + +func (self *SLBBackendGroup) GetProtocolType() string { + return "" +} + +func (self *SLBBackendGroup) GetScheduler() string { + return "" +} + +func (self *SLBBackendGroup) GetHealthCheck() (*cloudprovider.SLoadbalancerHealthCheck, error) { + return nil, nil +} + +func (self *SLBBackendGroup) GetStickySession() (*cloudprovider.SLoadbalancerStickySession, error) { + return nil, nil +} + +func (self *SLBBackendGroup) GetListenerId() string { + if self.listener != nil { + return self.listener.GetId() + } + + return "" +} + +// 返回requestid +func (self *SLBBackendGroup) appLBBackendServer(action string, serverId string, weight int, port int) (string, error) { + if len(serverId) == 0 { + return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") + } + + params := map[string]string{ + "LoadBalancerId": self.lb.GetId(), + "ListenerId": self.GetListenerId(), + "Targets.0.InstanceId": serverId, + "Targets.0.Port": strconv.Itoa(port), + "Targets.0.Weight": strconv.Itoa(weight), + } + + if self.rule != nil { + params["LocationId"] = self.rule.GetId() + } + + resp, err := self.lb.region.clbRequest(action, params) + if err != nil { + return "", err + } + + return resp.GetString("RequestId") +} + +// deprecated +func (self *SLBBackendGroup) appLBSeventhBackendServer(action string, serverId string, weight int, port int) (string, error) { + if len(serverId) == 0 { + return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") + } + + params := map[string]string{ + "loadBalancerId": self.lb.GetId(), + "listenerId": self.GetListenerId(), + "backends.0.InstanceId": serverId, + "backends.0.Port": strconv.Itoa(port), + "backends.0.Weight": strconv.Itoa(weight), + } + + if self.rule != nil { + params["LocationId"] = self.rule.GetId() + } + + resp, err := self.lb.region.clbRequest(action, params) + if err != nil { + return "", err + } + + return resp.GetString("RequestId") +} + +// https://cloud.tencent.com/document/product/214/30677 +func (self *SLBBackendGroup) updateBackendServerWeight(action string, serverId string, weight int, port int) (string, error) { + if len(serverId) == 0 { + return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") + } + + params := map[string]string{ + "LoadBalancerId": self.lb.GetId(), + "ListenerId": self.GetListenerId(), + "Targets.0.InstanceId": serverId, + "Targets.0.Port": strconv.Itoa(port), + "Targets.0.Weight": strconv.Itoa(weight), + } + + if self.rule != nil { + params["LocationId"] = self.rule.GetId() + } + + resp, err := self.lb.region.clbRequest(action, params) + if err != nil { + return "", err + } + + return resp.GetString("RequestId") +} + +// https://cloud.tencent.com/document/product/214/30678 +func (self *SLBBackendGroup) updateBackendServerPort(action string, serverId string, oldPort int, newPort int) (string, error) { + if len(serverId) == 0 { + return "", fmt.Errorf("loadbalancer backend instance id should not be empty.") + } + + params := map[string]string{ + "LoadBalancerId": self.lb.GetId(), + "ListenerId": self.GetListenerId(), + "Targets.0.InstanceId": serverId, + "Targets.0.Port": strconv.Itoa(oldPort), + "NewPort": strconv.Itoa(newPort), + } + + if self.rule != nil { + params["LocationId"] = self.rule.GetId() + } + + resp, err := self.lb.region.clbRequest(action, params) + if err != nil { + return "", err + } + + return resp.GetString("RequestId") +} + +// 返回requestid +// https://cloud.tencent.com/document/api/214/1264 +func (self *SLBBackendGroup) classicLBBackendServer(action string, serverId string, weight int, port int) (string, error) { + // 传统型负载均衡忽略了port参数 + params := map[string]string{ + "LoadBalancerId": self.lb.GetId(), + "Targets.0.InstanceId": serverId, + "Targets.0.Weight": strconv.Itoa(weight), + } + + resp, err := self.lb.region.clbRequest(action, params) + if err != nil { + return "", err + } + + return resp.GetString("RequestId") +} + +// https://cloud.tencent.com/document/product/214/30676 +// https://cloud.tencent.com/document/product/214/31789 +func (self *SLBBackendGroup) AddBackendServer(serverId string, weight int, port int) (cloudprovider.ICloudLoadbalancerBackend, error) { + var requestId string + var err error + if self.lb.Forward == LB_TYPE_APPLICATION { + requestId, err = self.appLBBackendServer("RegisterTargets", serverId, weight, port) + } else { + requestId, err = self.classicLBBackendServer("RegisterTargetsWithClassicalLB", serverId, weight, port) + } + + if err != nil { + return nil, err + } + + err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) + if err != nil { + return nil, err + } + + err = self.Refresh() + if err != nil { + return nil, err + } + + backends, err := self.GetBackends() + if err != nil { + return nil, err + } + + for _, backend := range backends { + if strings.HasSuffix(backend.GetId(), fmt.Sprintf("%s-%d", serverId, port)) { + return &backend, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +// https://cloud.tencent.com/document/product/214/30687 +// https://cloud.tencent.com/document/product/214/31794 +func (self *SLBBackendGroup) RemoveBackendServer(serverId string, weight int, port int) error { + _, err := self.lb.region.GetInstance(serverId) + if err != nil && errors.Cause(err) == cloudprovider.ErrNotFound { + return nil + } + + var requestId string + if self.lb.Forward == LB_TYPE_APPLICATION { + requestId, err = self.appLBBackendServer("DeregisterTargets", serverId, weight, port) + } else { + requestId, err = self.classicLBBackendServer("DeregisterTargetsFromClassicalLB", serverId, weight, port) + } + + if err != nil { + if strings.Contains(err.Error(), "not registered") { + return nil + } + return err + } + + return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) +} + +func (self *SLBBackendGroup) UpdateBackendServer(serverId string, oldWeight, oldPort, weight, newPort int) error { + var requestId string + var err error + // if self.lb.Forward == LB_TYPE_APPLICATION { + // // https://cloud.tencent.com/document/product/214/30678 + // // https://cloud.tencent.com/document/product/214/30677 + // if self.listener.Protocol == api.LB_LISTENER_TYPE_HTTPS || self.listener.Protocol == api.LB_LISTENER_TYPE_HTTP { + // requestId, err = self.appLBSeventhBackendServer("ModifyForwardSeventhBackends", serverId, weight, port) + // } else { + // requestId, err = self.appLBBackendServer("ModifyForwardFourthBackendsWeight", serverId, weight, port) + // } + // } else { + // requestId, err = self.classicLBBackendServer("ModifyLoadBalancerBackends", serverId, weight, port) + // } + if oldWeight != weight { + requestId, err = self.updateBackendServerWeight("ModifyTargetWeight", serverId, weight, oldPort) + if err != nil { + if strings.Contains(err.Error(), "not registered") { + return nil + } + return errors.Wrap(err, "LBBackendGroup.updateBackendServerWeight") + } + + err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) + if err != nil { + return errors.Wrap(err, "LBBackendGroup.updateBackendServerWeight.WaitLBTaskSuccess") + } + } + + if oldPort != newPort { + requestId, err = self.updateBackendServerPort("ModifyTargetPort", serverId, oldPort, newPort) + if err != nil { + if strings.Contains(err.Error(), "not registered") { + return nil + } + return errors.Wrap(err, "LBBackendGroup.updateBackendServerPort") + } + + err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) + if err != nil { + return errors.Wrap(err, "LBBackendGroup.updateBackendServerPort.WaitLBTaskSuccess") + } + } + + return nil +} + +// 腾讯云无后端服务器组。 +func (self *SLBBackendGroup) Delete(ctx context.Context) error { + return fmt.Errorf("Please remove related listener/rule frist") +} + +// 腾讯云无后端服务器组 +func (self *SLBBackendGroup) Sync(ctx context.Context, group *cloudprovider.SLoadbalancerBackendGroup) error { + return nil +} + +func backendGroupIdGen(lbid string, secondId string) string { + if len(secondId) > 0 { + return fmt.Sprintf("%s", secondId) + } else { + return lbid + } +} + +func (self *SLBBackendGroup) GetId() string { + t := "" + if self.listener != nil { + t = self.listener.GetListenerType() + } + + if t == api.LB_LISTENER_TYPE_HTTP || t == api.LB_LISTENER_TYPE_HTTPS { + // http https 后端服务器只与规则绑定 + return backendGroupIdGen(self.lb.GetId(), self.rule.GetId()) + } else if self.lb.Forward == LB_TYPE_APPLICATION { + return backendGroupIdGen(self.lb.GetId(), self.GetListenerId()) + } else { + // 传统型lb 所有监听共用一个后端服务器组 + return backendGroupIdGen(self.lb.GetId(), "") + } +} + +func (self *SLBBackendGroup) GetName() string { + return self.GetId() +} + +func (self *SLBBackendGroup) GetGlobalId() string { + return self.GetId() +} + +func (self *SLBBackendGroup) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLBBackendGroup) Refresh() error { + return nil +} + +// note: model没有更新这个字段? +func (self *SLBBackendGroup) IsEmulated() bool { + return true +} + +func (self *SLBBackendGroup) IsDefault() bool { + return false +} + +func (self *SLBBackendGroup) GetType() string { + return api.LB_BACKENDGROUP_TYPE_NORMAL +} + +func (self *SLBBackendGroup) GetILoadbalancerBackends() ([]cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := self.GetBackends() + if err != nil { + return nil, err + } + + ibackends := make([]cloudprovider.ICloudLoadbalancerBackend, len(backends)) + for i := range backends { + backends[i].group = self + ibackends[i] = &backends[i] + } + + return ibackends, nil +} + +func (self *SLBBackendGroup) GetILoadbalancerBackendById(backendId string) (cloudprovider.ICloudLoadbalancerBackend, error) { + backends, err := self.GetILoadbalancerBackends() + if err != nil { + return nil, err + } + for i := 0; i < len(backends); i++ { + if backends[i].GetGlobalId() == backendId { + return backends[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SLBBackendGroup) GetBackends() ([]SLBBackend, error) { + backends := []SLBBackend{} + var err error + if self.rule != nil { + // http、https监听 + backends, err = self.lb.region.GetLBBackends(self.lb.Forward, self.lb.GetId(), self.GetListenerId(), self.rule.GetId()) + if err != nil { + return nil, err + } + } else { + // tcp,udp,tcp_ssl监听 + backends, err = self.lb.region.GetLBBackends(self.lb.Forward, self.lb.GetId(), self.GetListenerId(), "") + if err != nil { + return nil, err + } + } + + for i := range backends { + backends[i].group = self + } + + return backends, nil +} + +func (self *SLBBackendGroup) GetProjectId() string { + return self.lb.GetProjectId() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_listener.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_listener.go new file mode 100644 index 0000000000..0ab633683c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_listener.go @@ -0,0 +1,884 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +var HTTP_CODES = []string{ + api.LB_HEALTH_CHECK_HTTP_CODE_1xx, + api.LB_HEALTH_CHECK_HTTP_CODE_2xx, + api.LB_HEALTH_CHECK_HTTP_CODE_3xx, + api.LB_HEALTH_CHECK_HTTP_CODE_4xx, + api.LB_HEALTH_CHECK_HTTP_CODE_5xx, +} + +const ( + PROTOCOL_TCP = "TCP" + PROTOCOL_UDP = "UDP" + PROTOCOL_TCP_SSL = "TCP_SSL" + PROTOCOL_HTTP = "HTTP" + PROTOCOL_HTTPS = "HTTPS" +) + +type certificate struct { + SSLMode string `json:"SSLMode"` + CERTCAID string `json:"CertCaId"` + CERTID string `json:"CertId"` +} + +/* +健康检查状态码(仅适用于HTTP/HTTPS转发规则)。可选值:1~31,默认 31。 +1 表示探测后返回值 1xx 表示健康,2 表示返回 2xx 表示健康,4 表示返回 3xx 表示健康,8 表示返回 4xx 表示健康,16 表示返回 5xx 表示健康。 +若希望多种码都表示健康,则将相应的值相加。 +*/ +type healthCheck struct { + HTTPCheckDomain string `json:"HttpCheckDomain"` + HealthSwitch int `json:"HealthSwitch"` + HTTPCheckPath string `json:"HttpCheckPath"` + HTTPCheckMethod string `json:"HttpCheckMethod"` + UnHealthNum int `json:"UnHealthNum"` + IntervalTime int `json:"IntervalTime"` + HTTPCode int `json:"HttpCode"` // 健康检查状态码(仅适用于HTTP/HTTPS转发规则)。可选值:1~31,默认 31。 + HealthNum int `json:"HealthNum"` + TimeOut int `json:"TimeOut"` +} + +type SLBListener struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + QcloudTags + lb *SLoadbalancer + + Protocol string `json:"Protocol"` // 监听器协议类型,取值 TCP | UDP | HTTP | HTTPS | TCP_SSL + Certificate certificate `json:"Certificate"` + SniSwitch int64 `json:"SniSwitch"` // 是否开启SNI特性(本参数仅对于HTTPS监听器有意义) + HealthCheck healthCheck `json:"HealthCheck"` // 仅适用于TCP/UDP/TCP_SSL监听器 + ListenerID string `json:"ListenerId"` + ListenerName string `json:"ListenerName"` + Rules []SLBListenerRule `json:"Rules"` // 监听器下的全部转发规则(本参数仅对于HTTP/HTTPS监听器有意义) + Scheduler string `json:"Scheduler"` + SessionExpireTime int `json:"SessionExpireTime"` // 会话保持时间,单位:秒。可选值:30~3600,默认 0,表示不开启。此参数仅适用于TCP/UDP监听器。 + Port int `json:"Port"` + ClassicListener bool // 这个字段是在qcloud返回字段基础上,额外增加的字段。用于区分listener 是否是classic。 +} + +// 腾讯云后端端口不是与listener绑定的 +func (self *SLBListener) GetBackendServerPort() int { + return 0 +} + +// https://cloud.tencent.com/document/product/214/30691 +func (self *SLBListener) CreateILoadBalancerListenerRule(rule *cloudprovider.SLoadbalancerListenerRule) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + hc := getListenerRuleHealthCheck(rule) + requestId, err := self.lb.region.CreateLoadbalancerListenerRule(self.lb.GetId(), + self.GetId(), + rule.Domain, + rule.Path, + rule.Scheduler, + rule.StickySessionCookieTimeout, + hc) + if err != nil { + return nil, err + } + + err = self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) + if err != nil { + return nil, err + } + + err = self.Refresh() + if err != nil { + return nil, err + } + + for _, r := range self.Rules { + if r.GetPath() == rule.Path { + r.listener = self + return &r, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SLBListener) GetILoadBalancerListenerRuleById(ruleId string) (cloudprovider.ICloudLoadbalancerListenerRule, error) { + rules, err := self.GetILoadbalancerListenerRules() + if err != nil { + return nil, err + } + + for _, rule := range rules { + if rule.GetId() == ruleId { + return rule, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SLBListener) Start() error { + return nil +} + +func (self *SLBListener) Stop() error { + return cloudprovider.ErrNotSupported +} + +// https://cloud.tencent.com/document/product/214/30677 +func (self *SLBListener) Sync(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) error { + lockman.LockRawObject(ctx, "qcloud.SLBListener.Sync", self.lb.region.client.ownerId) + defer lockman.ReleaseRawObject(ctx, "qcloud.SLBListener.Sync", self.lb.region.client.ownerId) + + hc := getHealthCheck(listener) + cert := getCertificate(listener) + requestId, err := self.lb.region.UpdateLoadbalancerListener( + self.lb.Forward, + self.lb.GetId(), + self.GetId(), + &listener.Name, + getScheduler(listener), + &listener.StickySessionCookieTimeout, + hc, + cert) + if err != nil { + return err + } + + return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) +} + +func (self *SLBListener) Delete(ctx context.Context) error { + lockman.LockRawObject(ctx, "qcloud.SLBListener.Delete", self.lb.region.client.ownerId) + defer lockman.ReleaseRawObject(ctx, "qcloud.SLBListener.Delete", self.lb.region.client.ownerId) + + requestId, err := self.lb.region.DeleteLoadbalancerListener(self.lb.Forward, self.lb.GetId(), self.GetId()) + if err != nil { + return err + } + + return self.lb.region.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) +} + +// https://cloud.tencent.com/document/api/214/30694#ClassicalListener +type SLBClassicListener struct { + InstancePort int64 `json:"InstancePort"` + CERTCAID string `json:"CertCaId"` + Status int64 `json:"Status"` + CERTID string `json:"CertId"` + Protocol string `json:"Protocol"` + TimeOut int `json:"TimeOut"` + HTTPHash string `json:"HttpHash"` // 公网固定IP型的 HTTP、HTTPS 协议监听器的轮询方法。wrr 表示按权重轮询,ip_hash 表示根据访问的源 IP 进行一致性哈希方式来分发 + UnhealthNum int `json:"UnhealthNum"` + IntervalTime int `json:"IntervalTime"` + ListenerID string `json:"ListenerId"` + ListenerPort int `json:"ListenerPort"` + HTTPCheckPath string `json:"HttpCheckPath"` + HealthNum int `json:"HealthNum"` + ListenerName string `json:"ListenerName"` + HealthSwitch int `json:"HealthSwitch"` + SSLMode string `json:"SSLMode"` + SessionExpire int `json:"SessionExpire"` + HTTPCode int `json:"HttpCode"` +} + +func (self *SLBClassicListener) ToLBListener() SLBListener { + // 转换之后丢弃了 InstancePort、Status、HttpHash + return SLBListener{ + Protocol: self.Protocol, + Certificate: certificate{ + SSLMode: self.SSLMode, + CERTCAID: self.CERTCAID, + CERTID: self.CERTID, + }, + HealthCheck: healthCheck{ + HTTPCheckDomain: "", + HealthSwitch: self.HealthSwitch, + HTTPCheckPath: self.HTTPCheckPath, + HTTPCheckMethod: "", + UnHealthNum: self.UnhealthNum, + IntervalTime: self.IntervalTime, + HTTPCode: self.HTTPCode, + HealthNum: self.HealthNum, + TimeOut: self.TimeOut, + }, + ListenerID: self.ListenerID, + ListenerName: self.ListenerName, + Rules: nil, + Scheduler: self.HTTPHash, + SessionExpireTime: self.SessionExpire, + Port: self.ListenerPort, + ClassicListener: true, + } +} + +func (self *SLBListener) GetId() string { + return self.ListenerID +} + +func (self *SLBListener) GetName() string { + return self.ListenerName +} + +func (self *SLBListener) GetGlobalId() string { + return self.ListenerID +} + +// 腾讯云负载均衡没有启用禁用操作 +func (self *SLBListener) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLBListener) Refresh() error { + listeners, err := self.lb.region.GetLoadbalancerListeners(self.lb.GetId(), self.lb.Forward, "") + if err != nil { + return err + } + + for _, listener := range listeners { + if listener.GetId() == self.GetId() { + listener.lb = self.lb + err := jsonutils.Update(self, listener) + if err != nil { + return err + } + + return nil + } + } + + return cloudprovider.ErrNotFound +} + +func (self *SLBListener) IsEmulated() bool { + return false +} + +func (self *SLBListener) GetEgressMbps() int { + return 0 +} + +func (self *SLBListener) GetListenerType() string { + switch self.Protocol { + case PROTOCOL_TCP: + return api.LB_LISTENER_TYPE_TCP + case PROTOCOL_UDP: + return api.LB_LISTENER_TYPE_UDP + case PROTOCOL_HTTP: + return api.LB_LISTENER_TYPE_HTTP + case PROTOCOL_HTTPS: + return api.LB_LISTENER_TYPE_HTTPS + case PROTOCOL_TCP_SSL: + return api.LB_LISTENER_TYPE_TCP + default: + return "" + } +} + +func (self *SLBListener) GetListenerPort() int { + return self.Port +} + +func (self *SLBListener) GetScheduler() string { + switch strings.ToLower(self.Scheduler) { + case "wrr": + return api.LB_SCHEDULER_WRR + case "ip_hash": + return api.LB_SCHEDULER_SCH + case "least_conn": + return api.LB_SCHEDULER_WLC + default: + return "" + } +} + +func (self *SLBListener) GetAclStatus() string { + return api.LB_BOOL_OFF +} + +func (self *SLBListener) GetAclType() string { + return "" +} + +func (self *SLBListener) GetAclId() string { + return "" +} + +func (self *SLBListener) GetHealthCheck() string { + if self.HealthCheck.HealthSwitch == 0 { + return api.LB_BOOL_OFF + } else { + return api.LB_BOOL_ON + } +} + +func (self *SLBListener) GetHealthCheckType() string { + if len(self.HealthCheck.HTTPCheckMethod) > 0 { + return api.LB_HEALTH_CHECK_HTTP + } else { + return api.LB_HEALTH_CHECK_TCP + } +} + +func (self *SLBListener) GetHealthCheckTimeout() int { + return self.HealthCheck.TimeOut +} + +func (self *SLBListener) GetHealthCheckInterval() int { + return self.HealthCheck.IntervalTime +} + +func (self *SLBListener) GetHealthCheckRise() int { + return self.HealthCheck.HealthNum +} + +func (self *SLBListener) GetHealthCheckFail() int { + return self.HealthCheck.UnHealthNum +} + +func (self *SLBListener) GetHealthCheckReq() string { + return "" +} + +func (self *SLBListener) GetHealthCheckExp() string { + return "" +} + +func (self *SLBListener) GetBackendGroup() *SLBBackendGroup { + t := self.GetListenerType() + // http、https类型的监听不能直接绑定服务器 + if t == api.LB_LISTENER_TYPE_HTTP || t == api.LB_LISTENER_TYPE_HTTPS { + return nil + } else { + return &SLBBackendGroup{lb: self.lb, listener: self} + } +} + +func (self *SLBListener) GetBackendGroupId() string { + bg := self.GetBackendGroup() + if bg == nil { + return "" + } + + return bg.GetId() +} + +func (self *SLBListener) GetHealthCheckDomain() string { + return self.HealthCheck.HTTPCheckDomain +} + +func (self *SLBListener) GetHealthCheckURI() string { + return self.HealthCheck.HTTPCheckPath +} + +func (self *SLBListener) GetHealthCheckCode() string { + codes := []string{} + for i := uint8(0); i < 5; i++ { + n := 1 << i + if (self.HealthCheck.HTTPCode & n) == n { + codes = append(codes, HTTP_CODES[i]) + } + } + + return strings.Join(codes, ",") +} + +// 仅http、https类型监听包含rules +func (self *SLBListener) GetILoadbalancerListenerRules() ([]cloudprovider.ICloudLoadbalancerListenerRule, error) { + rules := self.Rules + iRules := []cloudprovider.ICloudLoadbalancerListenerRule{} + for i := 0; i < len(rules); i++ { + rules[i].listener = self + iRules = append(iRules, &rules[i]) + } + return iRules, nil +} + +func (self *SLBListener) GetStickySession() string { + if self.SessionExpireTime == 0 { + return api.LB_BOOL_OFF + } else { + return api.LB_BOOL_ON + } +} + +// 支持基于 cookie 插入的会话保持能力 https://cloud.tencent.com/document/product/214/6154 +func (self *SLBListener) GetStickySessionType() string { + return api.LB_STICKY_SESSION_TYPE_INSERT +} + +// https://cloud.tencent.com/document/product/214/2736 +// 经测试应用型负载均衡返回都是 tgw_l7_route。 +func (self *SLBListener) GetStickySessionCookie() string { + if self.GetListenerType() == api.LB_LISTENER_TYPE_HTTPS { + return "tgw_l7_route" + } + + return "" +} + +func (self *SLBListener) GetStickySessionCookieTimeout() int { + return self.SessionExpireTime +} + +/* +7层负载均衡系统提供 X-Forwarded-For 的方式获取访问者真实 IP,LB 侧默认开启 + +https://cloud.tencent.com/document/product/214/6151 +七层转发获取来访真实IP的方法 https://cloud.tencent.com/document/product/214/3728 +*/ +func (self *SLBListener) XForwardedForEnabled() bool { + switch self.GetListenerType() { + case api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS: + return true + default: + return false + } +} + +// HTTP/HTTPS协议默认支持用户开启gzip压缩功能 +// 负载均衡开启Gzip配置及检测方法说明 https://cloud.tencent.com/document/product/214/5404 +func (self *SLBListener) GzipEnabled() bool { + switch self.GetListenerType() { + case api.LB_LISTENER_TYPE_HTTP, api.LB_LISTENER_TYPE_HTTPS: + return true + default: + return false + } +} + +func (self *SLBListener) GetCertificateId() string { + return self.Certificate.CERTID +} + +// https://cloud.tencent.com/document/product/214/5412#2.-https.E6.94.AF.E6.8C.81.E5.93.AA.E4.BA.9B.E7.89.88.E6.9C.AC.E7.9A.84ssl.2Ftls.E5.AE.89.E5.85.A8.E5.8D.8F.E8.AE.AE.EF.BC.9F +func (self *SLBListener) GetTLSCipherPolicy() string { + return "" +} + +// 负载均衡能力说明 https://cloud.tencent.com/document/product/214/6534 +func (self *SLBListener) HTTP2Enabled() bool { + return true +} + +func (self *SRegion) GetLoadbalancerListeners(lbid string, t LB_TYPE, protocol string) ([]SLBListener, error) { + params := map[string]string{"LoadBalancerId": lbid} + if len(protocol) > 0 { + params["Protocol"] = protocol + } + + listeners := []SLBListener{} + if t == LB_TYPE_CLASSIC { + resp, err := self.clbRequest("DescribeClassicalLBListeners", params) + if err != nil { + return nil, err + } + + clisteners := []SLBClassicListener{} + err = resp.Unmarshal(&clisteners, "Listeners") + if err != nil { + return nil, err + } + + for _, l := range clisteners { + listeners = append(listeners, l.ToLBListener()) + } + + return listeners, nil + } + + resp, err := self.clbRequest("DescribeListeners", params) + if err != nil { + return nil, err + } + + err = resp.Unmarshal(&listeners, "Listeners") + if err != nil { + return nil, err + } + + return listeners, nil +} + +// 返回requestID +func (self *SRegion) CreateLoadbalancerListenerRule(lbid string, listenerId string, domain string, url string, scheduler string, sessionExpireTime int, hc *healthCheck) (string, error) { + if len(lbid) == 0 { + return "", fmt.Errorf("loadbalancer id should not be empty") + } + + params := map[string]string{ + "LoadBalancerId": lbid, + "ListenerId": listenerId, + "Rules.0.Domain": domain, + "Rules.0.Url": url, + } + + params["Rules.0.Scheduler"] = scheduler + params["Rules.0.SessionExpireTime"] = strconv.Itoa(sessionExpireTime) + + // health check + params["Rules.0.HealthCheck.HealthSwitch"] = strconv.Itoa(hc.HealthSwitch) + params["Rules.0.HealthCheck.IntervalTime"] = strconv.Itoa(hc.IntervalTime) + params["Rules.0.HealthCheck.HealthNum"] = strconv.Itoa(hc.HealthNum) + params["Rules.0.HealthCheck.UnHealthNum"] = strconv.Itoa(hc.UnHealthNum) + if hc.HTTPCode > 0 { + params["Rules.0.HealthCheck.HttpCode"] = strconv.Itoa(hc.HTTPCode) + params["Rules.0.HealthCheck.HttpCheckPath"] = hc.HTTPCheckPath + params["Rules.0.HealthCheck.HttpCheckDomain"] = hc.HTTPCheckDomain + params["Rules.0.HealthCheck.HttpCheckMethod"] = hc.HTTPCheckMethod + } + + resp, err := self.clbRequest("CreateRule", params) + if err != nil { + return "", err + } + + return resp.GetString("RequestId") +} + +// 返回requestID +func (self *SRegion) deleteLoadbalancerListener(lbid string, listenerId string) (string, error) { + if len(lbid) == 0 { + return "", fmt.Errorf("loadbalancer id should not be empty") + } + + params := map[string]string{ + "LoadBalancerId": lbid, + "ListenerId": listenerId, + } + + resp, err := self.clbRequest("DeleteListener", params) + if err != nil { + return "", err + } + + return resp.GetString("RequestId") +} + +// 返回requestID +func (self *SRegion) deleteClassicLoadbalancerListener(lbid string, listenerId string) (string, error) { + if len(lbid) == 0 { + return "", fmt.Errorf("classic loadbalancer id should not be empty") + } + + params := map[string]string{ + "loadBalancerId": lbid, + "listenerIds.0": listenerId, + } + + resp, err := self.lbRequest("DeleteLoadBalancerListeners", params) + if err != nil { + return "", err + } + + _requestId, err := resp.Float("requestId") + if err != nil { + return "", err + } + + return fmt.Sprintf("%.f", _requestId), nil +} + +// 返回requestID +func (self *SRegion) DeleteLoadbalancerListener(t LB_TYPE, lbid string, listenerId string) (string, error) { + ctx := context.Background() + lockman.LockRawObject(ctx, "qcloud.SRegion.DeleteLoadbalancerListener", self.client.ownerId) + defer lockman.ReleaseRawObject(ctx, "qcloud.SRegion.DeleteLoadbalancerListener", self.client.ownerId) + + if len(lbid) == 0 { + return "", fmt.Errorf("loadbalancer id should not be empty") + } + + if t == LB_TYPE_APPLICATION { + return self.deleteLoadbalancerListener(lbid, listenerId) + } else { + return self.deleteClassicLoadbalancerListener(lbid, listenerId) + } +} + +// https://cloud.tencent.com/document/product/214/30681 +func (self *SRegion) updateLoadbalancerListener(lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) { + params := map[string]string{ + "LoadBalancerId": lbid, + "ListenerId": listenerId, + } + + if listenerName != nil && len(*listenerName) > 0 { + params["ListenerName"] = *listenerName + } + + if scheduler != nil && len(*scheduler) > 0 { + params["Scheduler"] = *scheduler + } + + if sessionExpireTime != nil { + params["SessionExpireTime"] = strconv.Itoa(*sessionExpireTime) + } + + params = healthCheckParams(LB_TYPE_APPLICATION, params, healthCheck, "HealthCheck.") + params = certificateParams(LB_TYPE_APPLICATION, params, cert, "Certificate.") + + resp, err := self.clbRequest("ModifyListener", params) + if err != nil { + return "", err + } + + return resp.GetString("RequestId") +} + +// https://cloud.tencent.com/document/api/214/3601 +func (self *SRegion) updateClassicLoadbalancerListener(lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) { + params := map[string]string{ + "loadBalancerId": lbid, + "listenerId": listenerId, + } + + if listenerName != nil && len(*listenerName) > 0 { + params["listenerName"] = *listenerName + } + + if scheduler != nil && len(*scheduler) > 0 { + params["scheduler"] = strings.ToLower(*scheduler) + } + + if sessionExpireTime != nil { + params["sessionExpire"] = strconv.Itoa(*sessionExpireTime) + } + + params = healthCheckParams(LB_TYPE_APPLICATION, params, healthCheck, "listeners.0.") + params = certificateParams(LB_TYPE_APPLICATION, params, cert, "listeners.0.") + + resp, err := self.lbRequest("ModifyLoadBalancerListener", params) + if err != nil { + return "", err + } + + return resp.GetString("RequestId") +} + +func (self *SRegion) UpdateLoadbalancerListener(t LB_TYPE, lbid string, listenerId string, listenerName *string, scheduler *string, sessionExpireTime *int, healthCheck *healthCheck, cert *certificate) (string, error) { + if len(lbid) == 0 { + return "", fmt.Errorf("loadbalancer id should not be empty") + } + + if len(listenerId) == 0 { + return "", fmt.Errorf("loadbalancer listener id should not be empty") + } + + if t == LB_TYPE_APPLICATION { + return self.updateLoadbalancerListener(lbid, listenerId, listenerName, scheduler, sessionExpireTime, healthCheck, cert) + } else { + return self.updateClassicLoadbalancerListener(lbid, listenerId, listenerName, scheduler, sessionExpireTime, healthCheck, cert) + } +} + +func getHealthCheck(listener *cloudprovider.SLoadbalancerListener) *healthCheck { + var hc *healthCheck + if listener.HealthCheck == api.LB_BOOL_ON { + hc = &healthCheck{ + HealthSwitch: 1, + UnHealthNum: listener.HealthCheckFail, + IntervalTime: listener.HealthCheckInterval, + HealthNum: listener.HealthCheckRise, + TimeOut: listener.HealthCheckTimeout, + } + + httpCode := onecloudHealthCodeToQcloud(listener.HealthCheckHttpCode) + if httpCode > 0 { + hc.HTTPCode = httpCode + hc.HTTPCheckMethod = "HEAD" // todo: add column HttpCheckMethod in model + hc.HTTPCheckDomain = listener.HealthCheckDomain + hc.HTTPCheckPath = listener.HealthCheckURI + } + } else { + hc = &healthCheck{ + HealthSwitch: 0, + UnHealthNum: 3, + IntervalTime: 5, + HealthNum: 3, + TimeOut: 2, + } + } + + return hc +} + +func getListenerRuleHealthCheck(rule *cloudprovider.SLoadbalancerListenerRule) *healthCheck { + var hc *healthCheck + if rule.HealthCheck == api.LB_BOOL_ON { + hc = &healthCheck{ + HealthSwitch: 1, + UnHealthNum: rule.HealthCheckFail, + IntervalTime: rule.HealthCheckInterval, + HealthNum: rule.HealthCheckRise, + TimeOut: rule.HealthCheckTimeout, + } + + httpCode := onecloudHealthCodeToQcloud(rule.HealthCheckHttpCode) + if httpCode > 0 { + hc.HTTPCode = httpCode + hc.HTTPCheckMethod = "HEAD" // todo: add column HttpCheckMethod in model + hc.HTTPCheckDomain = rule.HealthCheckDomain + hc.HTTPCheckPath = rule.HealthCheckURI + } + } else { + hc = &healthCheck{ + HealthSwitch: 0, + UnHealthNum: 3, + IntervalTime: 5, + HealthNum: 3, + TimeOut: 2, + } + } + + return hc +} + +func getCertificate(listener *cloudprovider.SLoadbalancerListener) *certificate { + var cert *certificate + if len(listener.CertificateID) > 0 { + cert = &certificate{ + SSLMode: "UNIDIRECTIONAL", + CERTCAID: "", + CERTID: listener.CertificateID, + } + } + + return cert +} + +func getProtocol(listener *cloudprovider.SLoadbalancerListener) string { + switch listener.ListenerType { + case api.LB_LISTENER_TYPE_HTTPS: + return PROTOCOL_HTTPS + case api.LB_LISTENER_TYPE_HTTP: + return PROTOCOL_HTTP + case api.LB_LISTENER_TYPE_TCP: + return PROTOCOL_TCP + case api.LB_LISTENER_TYPE_UDP: + return PROTOCOL_UDP + case "tcp_ssl": + return PROTOCOL_TCP_SSL + default: + return "" + } +} + +func getClassicLBProtocol(listener *cloudprovider.SLoadbalancerListener) int { + switch listener.ListenerType { + case api.LB_LISTENER_TYPE_HTTP: + return 1 + case api.LB_LISTENER_TYPE_HTTPS: + return 4 + case api.LB_LISTENER_TYPE_TCP: + return 2 + case api.LB_LISTENER_TYPE_UDP: + return 3 + default: + return 0 // 非法值 + } +} + +func getScheduler(listener *cloudprovider.SLoadbalancerListener) *string { + var sch string + switch listener.Scheduler { + case api.LB_SCHEDULER_WRR: + sch = "WRR" + case api.LB_SCHEDULER_WLC: + sch = "LEAST_CONN" + case api.LB_SCHEDULER_SCH: + sch = "IP_HASH" + default: + return nil + } + + return &sch +} + +func healthCheckParams(t LB_TYPE, params map[string]string, hc *healthCheck, paramPrefix string) map[string]string { + if hc == nil { + return params + } + + if t == LB_TYPE_APPLICATION { + params[paramPrefix+"HealthSwitch"] = strconv.Itoa(hc.HealthSwitch) + params[paramPrefix+"TimeOut"] = strconv.Itoa(hc.TimeOut) + params[paramPrefix+"IntervalTime"] = strconv.Itoa(hc.IntervalTime) + params[paramPrefix+"HealthNum"] = strconv.Itoa(hc.HealthNum) + params[paramPrefix+"UnHealthNum"] = strconv.Itoa(hc.UnHealthNum) + if hc.HTTPCode > 0 { + params[paramPrefix+"HttpCode"] = strconv.Itoa(hc.HTTPCode) + params[paramPrefix+"HttpCheckPath"] = hc.HTTPCheckPath + params[paramPrefix+"HttpCheckDomain"] = hc.HTTPCheckDomain + params[paramPrefix+"HttpCheckMethod"] = hc.HTTPCheckMethod + } + } else { + params[paramPrefix+"healthSwitch"] = strconv.Itoa(hc.HealthSwitch) + params[paramPrefix+"timeOut"] = strconv.Itoa(hc.TimeOut) + params[paramPrefix+"intervalTime"] = strconv.Itoa(hc.IntervalTime) + params[paramPrefix+"healthNum"] = strconv.Itoa(hc.HealthNum) + params[paramPrefix+"unHealthNum"] = strconv.Itoa(hc.UnHealthNum) + if hc.HTTPCode > 0 { + params[paramPrefix+"httpCode"] = strconv.Itoa(hc.HTTPCode) + params[paramPrefix+"httpCheckPath"] = hc.HTTPCheckPath + } + } + return params +} + +func certificateParams(t LB_TYPE, params map[string]string, cert *certificate, paramPrefix string) map[string]string { + if cert == nil { + return params + } + + if t == LB_TYPE_APPLICATION { + params[paramPrefix+"SSLMode"] = cert.SSLMode + params[paramPrefix+"CertId"] = cert.CERTID + if len(cert.CERTCAID) > 0 { + params[paramPrefix+"CertCaId"] = cert.CERTCAID + } + } else { + params[paramPrefix+"SSLMode"] = strings.ToLower(cert.SSLMode) + params[paramPrefix+"certId"] = cert.CERTID + if len(cert.CERTCAID) > 0 { + params[paramPrefix+"certCaId"] = cert.CERTCAID + } + } + return params +} + +func (self *SLBListener) GetProjectId() string { + return self.lb.GetProjectId() +} + +func (self *SLBListener) GetClientIdleTimeout() int { + return 0 +} + +func (self *SLBListener) GetBackendConnectTimeout() int { + return 0 +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_listenerrule.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_listenerrule.go new file mode 100644 index 0000000000..42510f5fad --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/loadbalancer_listenerrule.go @@ -0,0 +1,170 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SLBListenerRule struct { + multicloud.SResourceBase + multicloud.SLoadbalancerRedirectBase + QcloudTags + listener *SLBListener + + Domain string `json:"Domain"` + Certificate certificate `json:"Certificate"` + URL string `json:"Url"` + HealthCheck healthCheck `json:"HealthCheck"` + LocationID string `json:"LocationId"` + Scheduler string `json:"Scheduler"` + SessionExpireTime int64 `json:"SessionExpireTime"` +} + +// https://cloud.tencent.com/document/api/214/30688 +func (self *SLBListenerRule) Delete(ctx context.Context) error { + lockman.LockRawObject(ctx, "qcloud.SLBListenerRule.Delete", self.listener.lb.region.client.ownerId) + defer lockman.ReleaseRawObject(ctx, "qcloud.SLBListenerRule.Delete", self.listener.lb.region.client.ownerId) + + _, err := self.listener.lb.region.DeleteLBListenerRule(self.listener.lb.GetId(), self.listener.GetId(), self.GetId()) + if err != nil { + return err + } + + return cloudprovider.WaitDeleted(self, 5*time.Second, 60*time.Second) +} + +func (self *SLBListenerRule) GetId() string { + return self.LocationID +} + +func (self *SLBListenerRule) GetName() string { + return self.LocationID +} + +func (self *SLBListenerRule) GetGlobalId() string { + return self.LocationID +} + +func (self *SLBListenerRule) GetStatus() string { + return api.LB_STATUS_ENABLED +} + +func (self *SLBListenerRule) Refresh() error { + err := self.listener.Refresh() + if err != nil { + return err + } + + for _, rule := range self.listener.Rules { + if rule.GetId() == self.GetId() { + rule.listener = self.listener + return jsonutils.Update(self, rule) + } + } + + return cloudprovider.ErrNotFound +} + +func (self *SLBListenerRule) IsDefault() bool { + return false +} + +func (self *SLBListenerRule) IsEmulated() bool { + return false +} + +func (self *SLBListenerRule) GetDomain() string { + return self.Domain +} + +func (self *SLBListenerRule) GetCondition() string { + return "" +} + +func (self *SLBListenerRule) GetPath() string { + return self.URL +} + +func (self *SLBListenerRule) GetProjectId() string { + return self.listener.GetProjectId() +} + +func (self *SLBListenerRule) GetBackendGroup() *SLBBackendGroup { + t := self.listener.GetListenerType() + if t == api.LB_LISTENER_TYPE_HTTP || t == api.LB_LISTENER_TYPE_HTTPS { + return &SLBBackendGroup{ + lb: self.listener.lb, + listener: self.listener, + rule: self, + } + } + + return nil +} + +// 只有http、https协议监听规则有backendgroupid +func (self *SLBListenerRule) GetBackendGroupId() string { + bg := self.GetBackendGroup() + if bg == nil { + return "" + } + + return bg.GetId() +} + +// https://cloud.tencent.com/document/api/214/30688 +// 返回requestId及error +func (self *SRegion) DeleteLBListenerRule(lbid, listenerId, ruleId string) (string, error) { + if len(ruleId) == 0 { + return "", fmt.Errorf("DeleteLBListenerRule rule id should not be empty") + } + return self.DeleteLBListenerRules(lbid, listenerId, []string{ruleId}) +} + +func (self *SRegion) DeleteLBListenerRules(lbid, listenerId string, ruleIds []string) (string, error) { + if len(lbid) == 0 { + return "", fmt.Errorf("DeleteLBListenerRules loadbalancer id should not be empty") + } + + if len(listenerId) == 0 { + return "", fmt.Errorf("DeleteLBListenerRules listener id should not be empty") + } + + if len(ruleIds) == 0 { + return "", fmt.Errorf("DeleteLBListenerRules rule id should not be empty") + } + + params := map[string]string{"LoadBalancerId": lbid, "ListenerId": listenerId} + for i, ruleId := range ruleIds { + params[fmt.Sprintf("LocationIds.%d", i)] = ruleId + } + + resp, err := self.clbRequest("DeleteRule", params) + if err != nil { + return "", err + } + + return resp.GetString("RequestId") +} diff --git a/pkg/multicloud/qcloud/localdisk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/localdisk.go similarity index 95% rename from pkg/multicloud/qcloud/localdisk.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/localdisk.go index 79d8f06717..f0f966c5f1 100644 --- a/pkg/multicloud/qcloud/localdisk.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/localdisk.go @@ -18,14 +18,14 @@ import ( "context" "time" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SLocalDisk struct { multicloud.SDisk - multicloud.QcloudTags + QcloudTags storage *SLocalStorage DiskId string diff --git a/pkg/multicloud/qcloud/localstorage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/localstorage.go similarity index 96% rename from pkg/multicloud/qcloud/localstorage.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/localstorage.go index 48832f8be1..d51ab1d47d 100644 --- a/pkg/multicloud/qcloud/localstorage.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/localstorage.go @@ -20,9 +20,9 @@ import ( "yunion.io/x/jsonutils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) var QCLOUD_LOCAL_STORAGE_TYPES = []string{ diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/memcached.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/memcached.go new file mode 100644 index 0000000000..d9f486bdea --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/memcached.go @@ -0,0 +1,314 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strconv" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SMemcached struct { + multicloud.SElasticcacheBase + QcloudTags + region *SRegion + + InstanceId string `json:"InstanceId"` + InstanceName string `json:"InstanceName"` + AppId int `json:"AppId"` + ProjectId int `json:"ProjectId"` + InstanceDesc string `json:"InstanceDesc"` + Vip string `json:"Vip"` + Vport int `json:"Vport"` + Status int `json:"Status"` + AutoRenewFlag int `json:"AutoRenewFlag"` + VpcId int `json:"VpcId"` + SubnetId int `json:"SubnetId"` + PayMode int `json:"PayMode"` + ZoneId int `json:"ZoneId"` + Expire int `json:"Expire"` + RegionId int `json:"RegionId"` + AddTimeStamp time.Time `json:"AddTimeStamp"` + ModtimeStamp time.Time `json:"ModTimeStamp"` + IsolateTimesSamp time.Time `json:"IsolateTimeStamp"` + UniqVpcId string `json:"UniqVpcId"` + UniqSubnetId string `json:"UniqSubnetId"` + DeadlineTimeStamp string `json:"DeadlineTimeStamp"` + SetId int `json:"SetId"` + CmemId int `json:"CmemId"` +} + +func (self *SMemcached) GetId() string { + return self.InstanceId +} + +func (self *SMemcached) GetName() string { + return self.InstanceName +} + +func (self *SMemcached) GetGlobalId() string { + return self.GetId() +} + +func (self *SMemcached) GetStatus() string { + switch self.Status { + case 0: + return api.ELASTIC_CACHE_STATUS_DEPLOYING + case 1: + return api.ELASTIC_CACHE_STATUS_RUNNING + case 2: + return api.ELASTIC_CACHE_STATUS_CREATE_FAILED + case 4, 5, 6, 7: + return api.ELASTIC_CACHE_STATUS_RELEASING + default: + return fmt.Sprintf("%d", self.Status) + } +} + +func (self *SMemcached) GetProjectId() string { + return strconv.Itoa(self.ProjectId) +} + +func (self *SMemcached) GetBillingType() string { + // 计费模式:0-按量计费,1-包年包月 + if self.PayMode == 1 { + return billing_api.BILLING_TYPE_PREPAID + } else { + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SMemcached) GetCreatedAt() time.Time { + return self.AddTimeStamp +} + +func (self *SMemcached) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SMemcached) SetAutoRenew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (self *SMemcached) IsAutoRenew() bool { + return self.AutoRenewFlag == 1 +} + +func (self *SMemcached) GetInstanceType() string { + return "" +} + +func (self *SMemcached) GetCapacityMB() int { + return 0 +} + +func (self *SMemcached) GetArchType() string { + return api.ELASTIC_CACHE_NODE_TYPE_SINGLE +} + +func (self *SMemcached) GetNodeType() string { + return api.ELASTIC_CACHE_ARCH_TYPE_SINGLE +} + +func (self *SMemcached) GetEngine() string { + return api.ELASTIC_CACHE_ENGINE_MEMCACHED +} + +func (self *SMemcached) GetEngineVersion() string { + return "latest" +} + +func (self *SMemcached) GetVpcId() string { + return self.UniqVpcId +} + +func (self *SMemcached) GetZoneId() string { + return fmt.Sprintf("%s/%s-%d", self.region.GetGlobalId(), self.region.Region, self.ZoneId%10) +} + +func (self *SMemcached) GetNetworkType() string { + if len(self.UniqSubnetId) > 0 { + return api.LB_NETWORK_TYPE_VPC + } + return api.LB_NETWORK_TYPE_CLASSIC +} + +func (self *SMemcached) GetNetworkId() string { + return self.UniqSubnetId +} + +func (self *SMemcached) GetPrivateDNS() string { + return "" +} + +func (self *SMemcached) GetPrivateIpAddr() string { + return self.Vip +} + +func (self *SMemcached) GetPrivateConnectPort() int { + return self.Vport +} + +func (self *SMemcached) GetPublicDNS() string { + return "" +} + +func (self *SMemcached) GetPublicIpAddr() string { + return "" +} + +func (self *SMemcached) GetPublicConnectPort() int { + return 0 +} + +func (self *SMemcached) GetMaintainStartTime() string { + return "" +} + +func (self *SMemcached) GetMaintainEndTime() string { + return "" +} + +func (self *SMemcached) GetAuthMode() string { + return "off" +} + +func (self *SMemcached) GetSecurityGroupIds() ([]string, error) { + return []string{}, nil +} + +func (self *SMemcached) GetICloudElasticcacheAccounts() ([]cloudprovider.ICloudElasticcacheAccount, error) { + return []cloudprovider.ICloudElasticcacheAccount{}, nil +} + +func (self *SMemcached) GetICloudElasticcacheAcls() ([]cloudprovider.ICloudElasticcacheAcl, error) { + return []cloudprovider.ICloudElasticcacheAcl{}, nil +} + +func (self *SMemcached) GetICloudElasticcacheBackups() ([]cloudprovider.ICloudElasticcacheBackup, error) { + return []cloudprovider.ICloudElasticcacheBackup{}, nil +} + +func (self *SMemcached) GetICloudElasticcacheParameters() ([]cloudprovider.ICloudElasticcacheParameter, error) { + return []cloudprovider.ICloudElasticcacheParameter{}, nil +} + +func (self *SMemcached) GetICloudElasticcacheAccount(accountId string) (cloudprovider.ICloudElasticcacheAccount, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SMemcached) GetICloudElasticcacheAcl(aclId string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SMemcached) GetICloudElasticcacheBackup(backupId string) (cloudprovider.ICloudElasticcacheBackup, error) { + return nil, cloudprovider.ErrNotFound +} + +func (self *SMemcached) Restart() error { + return errors.Wrap(cloudprovider.ErrNotSupported, "Restart") +} + +func (self *SMemcached) Delete() error { + return cloudprovider.ErrNotSupported +} + +func (self *SMemcached) CleanupInstance() error { + return cloudprovider.ErrNotSupported +} + +func (self *SMemcached) ChangeInstanceSpec(spec string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SMemcached) SetMaintainTime(maintainStartTime, maintainEndTime string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SMemcached) AllocatePublicConnection(port int) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SMemcached) ReleasePublicConnection() error { + return errors.Wrap(cloudprovider.ErrNotSupported, "ReleasePublicConnection") +} + +func (self *SMemcached) CreateAccount(account cloudprovider.SCloudElasticCacheAccountInput) (cloudprovider.ICloudElasticcacheAccount, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SMemcached) CreateAcl(aclName, securityIps string) (cloudprovider.ICloudElasticcacheAcl, error) { + return nil, errors.Wrap(cloudprovider.ErrNotSupported, "CreateAcl") +} + +func (self *SMemcached) CreateBackup(desc string) (cloudprovider.ICloudElasticcacheBackup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SMemcached) FlushInstance(input cloudprovider.SCloudElasticCacheFlushInstanceInput) error { + return cloudprovider.ErrNotSupported +} + +func (self *SMemcached) UpdateAuthMode(noPasswordAccess bool, password string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SMemcached) UpdateInstanceParameters(config jsonutils.JSONObject) error { + return cloudprovider.ErrNotSupported +} + +func (self *SMemcached) UpdateBackupPolicy(config cloudprovider.SCloudElasticCacheBackupPolicyUpdateInput) error { + return cloudprovider.ErrNotSupported +} + +func (self *SMemcached) UpdateSecurityGroups(secgroupIds []string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SMemcached) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetMemcaches(ids []string, limit, offset int) ([]SMemcached, int, error) { + params := map[string]string{} + if limit <= 0 { + limit = 100 + } + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + for i, id := range ids { + params[fmt.Sprintf("InstanceIds.%d", i)] = id + } + resp, err := self.memcachedRequest("DescribeInstances", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeInstances") + } + ret := []SMemcached{} + err = resp.Unmarshal(&ret, "InstanceList") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal InstanceList") + } + total, _ := resp.Float("TotalCount") + return ret, int(total), nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/mongodb.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/mongodb.go new file mode 100644 index 0000000000..86dda50aea --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/mongodb.go @@ -0,0 +1,406 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + "time" + + sdkerrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SMongoDB struct { + QcloudTags + multicloud.SVirtualResourceBase + multicloud.SBillingBase + multicloud.SMongodbBase + + region *SRegion + + IOPS int + NetworkAddress string + AutoRenewFlag int `json:"AutoRenewFlag"` + CloneInstances []interface{} `json:"CloneInstances"` + ClusterType int `json:"ClusterType"` + ClusterVer int `json:"ClusterVer"` + ConfigServerCpuNum int `json:"ConfigServerCpuNum"` + ConfigServerMemory int `json:"ConfigServerMemory"` + ConfigServerNodeNum int `json:"ConfigServerNodeNum"` + ConfigServerVolume int `json:"ConfigServerVolume"` + CpuNum int `json:"CpuNum"` + CreateTime time.Time `json:"CreateTime"` + DeadLine string `json:"DeadLine"` + InstanceId string `json:"InstanceId"` + InstanceName string `json:"InstanceName"` + InstanceStatusDesc string `json:"InstanceStatusDesc"` + InstanceTaskDesc string `json:"InstanceTaskDesc"` + InstanceTaskId int `json:"InstanceTaskId"` + InstanceType int `json:"InstanceType"` + InstanceVer int `json:"InstanceVer"` + MachineType string `json:"MachineType"` + MaintenanceEnd string `json:"MaintenanceEnd"` + MaintenanceStart string `json:"MaintenanceStart"` + Memory int `json:"Memory"` + MongoVersion string `json:"MongoVersion"` + MongosCpuNum int `json:"MongosCpuNum"` + MongosMemory int `json:"MongosMemory"` + MongosNodeNum int `json:"MongosNodeNum"` + NetType int `json:"NetType"` + PayMode int `json:"PayMode"` + ProjectId int `json:"ProjectId"` + Protocol int `json:"Protocol"` + Readonlyinstances []interface{} `json:"ReadonlyInstances"` + RealInstanceId string `json:"RealInstanceId"` + Region string `json:"Region"` + Relatedinstance struct { + InstanceId string `json:"InstanceId"` + Region string `json:"Region"` + } `json:"RelatedInstance"` + Replicasets []struct { + Memory int `json:"Memory"` + OplogSize int `json:"OplogSize"` + RealReplicasetId string `json:"RealReplicaSetId"` + ReplicaSetId string `json:"ReplicaSetId"` + ReplicaSetName string `json:"ReplicaSetName"` + SecondaryNum int `json:"SecondaryNum"` + UsedVolume int `json:"UsedVolume"` + Volume int `json:"Volume"` + } `json:"ReplicaSets"` + ReplicationSetNum int `json:"ReplicationSetNum"` + SecondaryNum int `json:"SecondaryNum"` + StandbyInstances []interface{} `json:"StandbyInstances"` + Status int `json:"Status"` + SubnetId string `json:"SubnetId"` + UsedVolume int `json:"UsedVolume"` + Vip string `json:"Vip"` + Volume int `json:"Volume"` + VpcId string `json:"VpcId"` + Vport int `json:"Vport"` + Zone string `json:"Zone"` +} + +func (self *SMongoDB) GetGlobalId() string { + return self.InstanceId +} + +func (self *SMongoDB) GetId() string { + return self.InstanceId +} + +func (self *SMongoDB) GetName() string { + return self.InstanceName +} + +func (self *SMongoDB) GetStatus() string { + switch self.Status { + case 0, 1: + return api.MONGO_DB_STATUS_CREATING + case 2: + return api.MONGO_DB_STATUS_RUNNING + case -2, -3: + return api.MONGO_DB_STATUS_DELETING + } + return fmt.Sprintf("%d", self.Status) +} + +func (self *SMongoDB) Refresh() error { + ins, err := self.region.GetMongoDB(self.InstanceId) + if err != nil { + return errors.Wrapf(err, "GetMongoDB") + } + return jsonutils.Update(self, ins) +} + +func (self *SMongoDB) GetProjectId() string { + return fmt.Sprintf("%d", self.ProjectId) +} + +func (self *SMongoDB) GetVpcId() string { + return self.VpcId +} + +func (self *SMongoDB) GetNetworkId() string { + return self.SubnetId +} + +func (self *SMongoDB) GetCreatedAt() time.Time { + return self.CreateTime.Add(time.Hour * -8) +} + +func (self *SMongoDB) GetExpiredAt() time.Time { + return time.Time{} +} + +func (self *SMongoDB) GetIpAddr() string { + return self.Vip +} + +func (self *SMongoDB) GetVcpuCount() int { + return self.CpuNum +} + +func (self *SMongoDB) GetVmemSizeMb() int { + return self.Memory +} + +func (self *SMongoDB) GetReplicationNum() int { + switch self.GetCategory() { + case api.MONGO_DB_CATEGORY_SHARDING: + return self.ReplicationSetNum + case api.MONGO_DB_CATEGORY_REPLICATE: + return 3 + } + return self.ReplicationSetNum +} + +func (self *SMongoDB) GetDiskSizeMb() int { + return self.Volume +} + +func (self *SMongoDB) GetZoneId() string { + return self.Zone +} + +func (self *SMongoDB) GetBillingType() string { + // 计费模式:0-按量计费,1-包年包月 + if self.PayMode == 1 { + return billing_api.BILLING_TYPE_PREPAID + } else { + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SMongoDB) IsAutoRenew() bool { + return self.AutoRenewFlag == 1 +} + +func (self *SMongoDB) GetCategory() string { + switch self.ClusterType { + case 0: + return api.MONGO_DB_CATEGORY_REPLICATE + case 1: + return api.MONGO_DB_CATEGORY_SHARDING + default: + return fmt.Sprintf("%d", self.ClusterType) + } +} + +func (self *SMongoDB) GetEngine() string { + if utils.IsInStringArray("WT", strings.Split(self.MongoVersion, "_")) { + return api.MONGO_DB_ENGINE_WIRED_TIGER + } + return api.MONGO_DB_ENGINE_ROCKS +} + +func (self *SMongoDB) GetEngineVersion() string { + vers := strings.Split(self.MongoVersion, "_") + if len(vers) > 1 { + return strings.Join(strings.Split(vers[1], ""), ".") + } + return "" +} + +func (self *SMongoDB) GetInstanceType() string { + return self.MachineType +} + +func (self *SMongoDB) GetMaintainTime() string { + return fmt.Sprintf("%s-%s", self.MaintenanceStart, self.MaintenanceEnd) +} + +func (self *SMongoDB) GetPort() int { + return self.Vport +} + +func (self *SMongoDB) Delete() error { + return self.region.DeleteMongoDB(self.InstanceId) +} + +func (self *SRegion) DeleteMongoDB(id string) error { + err := self.IsolateMongoDB(id) + if err != nil { + return errors.Wrapf(err, "IsolateDBInstance") + } + return cloudprovider.Wait(time.Second*10, time.Minute*3, func() (bool, error) { + err = self.OfflineIsolatedMongoDB(id) + if err == nil { + return true, nil + } + if e, ok := errors.Cause(err).(*sdkerrors.TencentCloudSDKError); ok && e.Code == "InvalidParameterValue.LockFailed" { + return false, nil + } + return true, err + }) +} + +func (self *SMongoDB) SetTags(tags map[string]string, replace bool) error { + return self.region.SetResourceTags("mongodb", "instance", []string{self.InstanceId}, tags, replace) +} + +func (self *SMongoDB) GetIBackups() ([]cloudprovider.SMongoDBBackup, error) { + return self.region.GetMongoDBBackups(self.InstanceId) +} + +func (self *SRegion) IsolateMongoDB(id string) error { + params := map[string]string{ + "InstanceId": id, + } + _, err := self.mongodbRequest("IsolateDBInstance", params) + return errors.Wrapf(err, "IsolateDBInstance") +} + +func (self *SRegion) OfflineIsolatedMongoDB(id string) error { + params := map[string]string{ + "InstanceId": id, + } + _, err := self.mongodbRequest("OfflineIsolatedDBInstance", params) + return errors.Wrapf(err, "OfflineIsolatedDBInstance") +} + +func (self *SRegion) GetMongoDBs(ids []string, limit, offset int) ([]SMongoDB, int, error) { + if limit < 1 || limit > 100 { + limit = 100 + } + params := map[string]string{ + "Limit": fmt.Sprintf("%d", limit), + "Offset": fmt.Sprintf("%d", offset), + } + for i, id := range ids { + params[fmt.Sprintf("InstanceIds.%d", i)] = id + } + resp, err := self.mongodbRequest("DescribeDBInstances", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeDBInstances") + } + dbs := []SMongoDB{} + err = resp.Unmarshal(&dbs, "InstanceDetails") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + totalCount, _ := resp.Float("TotalCount") + return dbs, int(totalCount), nil +} + +func (self *SMongoDB) GetIops() int { + return self.IOPS +} + +func (self *SMongoDB) GetNetworkAddress() string { + return self.NetworkAddress +} + +func (self *SRegion) GetICloudMongoDBs() ([]cloudprovider.ICloudMongoDB, error) { + dbs := []SMongoDB{} + for { + part, total, err := self.GetMongoDBs(nil, 100, len(dbs)) + if err != nil { + return nil, errors.Wrapf(err, "GetMongoDBs") + } + dbs = append(dbs, part...) + if len(dbs) >= total { + break + } + } + ret := []cloudprovider.ICloudMongoDB{} + for i := range dbs { + dbs[i].region = self + ret = append(ret, &dbs[i]) + } + return ret, nil +} + +func (self *SRegion) GetMongoDBBackups(id string) ([]cloudprovider.SMongoDBBackup, error) { + params := map[string]string{ + "BackupMethod": "2", + "InstanceId": id, + } + resp, err := self.mongodbRequest("DescribeDBBackups", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeDBBackups") + } + backups := []struct { + InstanceId string + BackupType int + BackupName string + BackupDesc string + BackupSize int + StartTime time.Time + EndTime time.Time + Status int + BackupMethod int + }{} + err = resp.Unmarshal(&backups, "BackupList") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + ret := []cloudprovider.SMongoDBBackup{} + for _, backup := range backups { + b := cloudprovider.SMongoDBBackup{ + Name: backup.BackupName, + Description: backup.BackupDesc, + BackupSizeKb: backup.BackupSize, + } + b.StartTime = backup.StartTime.Add(time.Hour * -8) + b.EndTime = backup.EndTime.Add(time.Hour * -8) + switch backup.Status { + case 1: + b.Status = cloudprovider.MongoDBBackupStatusCreating + case 2: + b.Status = cloudprovider.MongoDBBackupStatusAvailable + default: + b.Status = cloudprovider.MongoDBBackupStatusUnknown + } + b.BackupMethod = cloudprovider.MongoDBBackupMethodLogical + if backup.BackupMethod == 0 { + b.BackupMethod = cloudprovider.MongoDBBackupMethodPhysical + } + b.BackupType = cloudprovider.MongoDBBackupTypeAuto + if backup.BackupType == 1 { + b.BackupType = cloudprovider.MongoDBBackupTypeManual + } + ret = append(ret, b) + } + return ret, nil +} + +func (self *SRegion) GetMongoDB(id string) (*SMongoDB, error) { + dbs, _, err := self.GetMongoDBs([]string{id}, 1, 0) + if err != nil { + return nil, errors.Wrapf(err, "GetMongoDB(%s)", id) + } + for i := range dbs { + dbs[i].region = self + return &dbs[i], nil + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SRegion) GetICloudMongoDBById(id string) (cloudprovider.ICloudMongoDB, error) { + db, err := self.GetMongoDB(id) + if err != nil { + return nil, errors.Wrapf(err, "GetMongoDB") + } + return db, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/monitor.go new file mode 100644 index 0000000000..08d3526e93 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/monitor.go @@ -0,0 +1,372 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/timeutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +const ( + QCLOUD_API_VERSION_METRICS = "2018-07-24" +) + +type SQcMetricDimension struct { + Name string `json:"Name"` + Value string `json:"Value"` +} + +type SQcMetricConditionDimension struct { + Key string `json:"Key"` + Value string `json:"Value"` + Operator string `json:"Operator"` +} + +type SQcInstanceMetricDimension struct { + Dimensions []SQcMetricDimension +} + +type SDataPoint struct { + Dimensions []SQcMetricDimension `json:"Dimensions"` + Timestamps []float64 `json:"Timestamps"` + Values []float64 `json:"Values"` +} + +type SK8SDataPoint struct { + MetricName string `json:"MetricName"` + Points []SK8sPoint `json:"Points"` +} + +type SK8sPoint struct { + Dimensions []SQcMetricDimension `json:"Dimensions"` + Values []SK8sPointValue `json:"Values"` +} + +type SK8sPointValue struct { + Timestamp float64 `json:"Timestamp"` + Value float64 `json:"Value"` +} + +type SBatchQueryMetricDataInput struct { + MetricName string `json:"MetricName"` + Namespace string `json:"Namespace"` + Metrics []SQcMetricDimension `json:"Metrics"` + StartTime int64 `json:"StartTime"` + EndTime int64 `json:"EndTime"` + Period string `json:"Period"` +} + +func (self *SQcloudClient) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { + cli, err := self.getDefaultClient(params) + if err != nil { + return nil, err + } + return monitorRequest(cli, action, params, self.cpcfg.UpdatePermission, self.debug) +} + +func (self *SQcloudClient) GetMonitorData(ns string, name string, since time.Time, until time.Time, regionId string, dimensionName string, resIds []string) ([]SDataPoint, error) { + params := make(map[string]string) + params["Region"] = regionId + params["MetricName"] = name + params["Namespace"] = ns + params["StartTime"] = since.Format(timeutils.IsoTimeFormat) + params["EndTime"] = until.Format(timeutils.IsoTimeFormat) + for idx, resId := range resIds { + params[fmt.Sprintf("Instances.%d.Dimensions.0.Name", idx)] = dimensionName + params[fmt.Sprintf("Instances.%d.Dimensions.0.Value", idx)] = resId + } + body, err := self.metricsRequest("GetMonitorData", params) + if err != nil { + return nil, errors.Wrapf(err, "MetricRequest for %s", resIds) + } + ret := []SDataPoint{} + err = body.Unmarshal(&ret, "DataPoints") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return ret, nil +} + +func (self *SQcloudClient) GetK8sMonitorData(ns, name, resourceId string, since time.Time, until time.Time, regionId string) ([]SK8SDataPoint, error) { + params := make(map[string]string) + params["Module"] = "monitor" + params["Region"] = regionId + params["MetricNames.0"] = name + params["Namespace"] = ns + params["Period"] = "60" + params["StartTime"] = since.Format(timeutils.IsoTimeFormat) + params["EndTime"] = until.Format(timeutils.IsoTimeFormat) + params["Conditions.0.Key"] = "tke_cluster_instance_id" + params["Conditions.0.Operator"] = "in" + params["Conditions.0.Value.0"] = resourceId + body, err := self.metricsRequest("DescribeStatisticData", params) + if err != nil { + return nil, errors.Wrap(err, "region.MetricRequest") + } + ret := []SK8SDataPoint{} + return ret, body.Unmarshal(&ret, "Data") +} + +func (self *SQcloudClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_REDIS: + return self.GetRedisMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_RDS: + return self.GetRdsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_K8S: + return self.GetK8sMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) + } +} + +func (self *SQcloudClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ + cloudprovider.VM_METRIC_TYPE_CPU_USAGE: { + "CPUUsage": "", + }, + cloudprovider.VM_METRIC_TYPE_MEM_USAGE: { + "MemUsage": "", + }, + cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: { + "lanOuttraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + "WanOuttraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, + }, + cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: { + "lanIntraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + "WanIntraffic": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTERNET, + }, + } { + for metricName, tag := range metricNames { + metrics, err := self.GetMonitorData("QCE/CVM", metricName, opts.StartTime, opts.EndTime, opts.RegionExtId, "InstanceId", opts.ResourceIds) + if err != nil { + log.Errorf("GetMonitorData error: %v", err) + continue + } + for i := range metrics { + metric := cloudprovider.MetricValues{} + if len(metrics[i].Dimensions) < 1 || metrics[i].Dimensions[0].Name != "InstanceId" { + continue + } + metric.Id = metrics[i].Dimensions[0].Value + metric.MetricType = metricType + metricValue := cloudprovider.MetricValue{} + metricValue.Tags = map[string]string{} + idx := strings.Index(tag, ":") + if idx > 0 { + metricValue.Tags[tag[:idx]] = tag[idx+1:] + } + if len(metrics[i].Timestamps) == 0 { + continue + } + for j := range metrics[i].Timestamps { + metricValue.Value = metrics[i].Values[j] + if strings.Contains(metricName, "traffic") { //Mbps + metricValue.Value *= 1024 * 1024 + } + metricValue.Timestamp = time.Unix(int64(metrics[i].Timestamps[j]), 0) + metric.Values = append(metric.Values, metricValue) + } + ret = append(ret, metric) + } + } + } + return ret, nil +} + +func (self *SQcloudClient) GetRedisMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ + cloudprovider.REDIS_METRIC_TYPE_CPU_USAGE: { + "CpuUsMin": "", + }, + cloudprovider.REDIS_METRIC_TYPE_MEM_USAGE: { + "StorageUsMin": "", + }, + cloudprovider.REDIS_METRIC_TYPE_NET_BPS_RX: { + "InFlowMin": "", + }, + cloudprovider.REDIS_METRIC_TYPE_NET_BPS_TX: { + "OutFlowMin": "", + }, + cloudprovider.REDIS_METRIC_TYPE_USED_CONN: { + "ConnectionsMin": "", + }, + cloudprovider.REDIS_METRIC_TYPE_OPT_SES: { + "QpsMin": "", + }, + cloudprovider.REDIS_METRIC_TYPE_CACHE_KEYS: { + "KeysMin": "", + }, + cloudprovider.REDIS_METRIC_TYPE_CACHE_EXP_KEYS: { + "ExpiredKeysMin": "", + }, + cloudprovider.REDIS_METRIC_TYPE_DATA_MEM_USAGE: { + "StorageMin": "", + }, + } { + for metricName, tag := range metricNames { + metrics, err := self.GetMonitorData("QCE/REDIS", metricName, opts.StartTime, opts.EndTime, opts.RegionExtId, "instanceid", opts.ResourceIds) + if err != nil { + log.Errorf("GetMonitorData error: %v", err) + continue + } + for i := range metrics { + metric := cloudprovider.MetricValues{} + if len(metrics[i].Dimensions) < 1 || metrics[i].Dimensions[0].Name != "instanceid" { + continue + } + metric.Id = metrics[i].Dimensions[0].Value + metric.MetricType = metricType + metricValue := cloudprovider.MetricValue{} + metricValue.Tags = map[string]string{} + idx := strings.Index(tag, ":") + if idx > 0 { + metricValue.Tags[tag[:idx]] = tag[idx+1:] + } + if len(metrics[i].Timestamps) == 0 { + continue + } + for j := range metrics[i].Timestamps { + metricValue.Value = metrics[i].Values[j] + metricValue.Timestamp = time.Unix(int64(metrics[i].Timestamps[j]), 0) + metric.Values = append(metric.Values, metricValue) + } + ret = append(ret, metric) + } + } + } + return ret, nil +} + +func (self *SQcloudClient) GetRdsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + for metricType, metricNames := range map[cloudprovider.TMetricType]map[string]string{ + cloudprovider.RDS_METRIC_TYPE_CPU_USAGE: { + "CPUUseRate": "", + }, + cloudprovider.RDS_METRIC_TYPE_MEM_USAGE: { + "MemoryUseRate": "", + }, + cloudprovider.RDS_METRIC_TYPE_NET_BPS_TX: { + "BytesSent": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + }, + cloudprovider.RDS_METRIC_TYPE_NET_BPS_RX: { + "BytesReceived": cloudprovider.METRIC_TAG_NET_TYPE + ":" + cloudprovider.METRIC_TAG_NET_TYPE_INTRANET, + }, + cloudprovider.RDS_METRIC_TYPE_DISK_USAGE: { + "VolumeRate": "", + }, + cloudprovider.RDS_METRIC_TYPE_CONN_COUNT: { + "ThreadsConnected": "", + }, + cloudprovider.RDS_METRIC_TYPE_CONN_USAGE: { + "ConnectionUseRate": "", + }, + cloudprovider.RDS_METRIC_TYPE_QPS: { + "QPS": "", + }, + cloudprovider.RDS_METRIC_TYPE_TPS: { + "TPS": "", + }, + cloudprovider.RDS_METRIC_TYPE_INNODB_READ_BPS: { + "InnodbDataRead": "", + }, + cloudprovider.RDS_METRIC_TYPE_INNODB_WRITE_BPS: { + "InnodbDataWritten": "", + }, + } { + for metricName, tag := range metricNames { + metrics, err := self.GetMonitorData("QCE/CDB", metricName, opts.StartTime, opts.EndTime, opts.RegionExtId, "InstanceId", opts.ResourceIds) + if err != nil { + log.Errorf("GetMonitorData error: %v", err) + continue + } + for i := range metrics { + metric := cloudprovider.MetricValues{} + if len(metrics[i].Dimensions) < 1 || metrics[i].Dimensions[0].Name != "InstanceId" { + continue + } + metric.Id = metrics[i].Dimensions[0].Value + metric.MetricType = metricType + metricValue := cloudprovider.MetricValue{} + metricValue.Tags = map[string]string{} + idx := strings.Index(tag, ":") + if idx > 0 { + metricValue.Tags[tag[:idx]] = tag[idx+1:] + } + if len(metrics[i].Timestamps) == 0 { + continue + } + for j := range metrics[i].Timestamps { + metricValue.Value = metrics[i].Values[j] + metricValue.Timestamp = time.Unix(int64(metrics[i].Timestamps[j]), 0) + metric.Values = append(metric.Values, metricValue) + } + ret = append(ret, metric) + } + } + } + return ret, nil +} + +func (self *SQcloudClient) GetK8sMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ret := []cloudprovider.MetricValues{} + for metricType, metricName := range map[cloudprovider.TMetricType]string{ + cloudprovider.K8S_NODE_METRIC_TYPE_CPU_USAGE: "K8sNodeCpuUsage", + cloudprovider.K8S_NODE_METRIC_TYPE_MEM_USAGE: "K8sNodeMemUsage", + } { + metrics, err := self.GetK8sMonitorData("QCE/TKE2", metricName, opts.ResourceId, opts.StartTime, opts.EndTime, opts.RegionExtId) + if err != nil { + log.Errorf("GetMonitorData error: %v", err) + continue + } + for i := range metrics { + for _, point := range metrics[i].Points { + tags := map[string]string{} + for _, dim := range point.Dimensions { + if dim.Name == "node" { + tags[cloudprovider.METRIC_TAG_NODE] = dim.Value + } + } + metric := cloudprovider.MetricValues{} + metric.Id = opts.ResourceId + metric.MetricType = metricType + for _, value := range point.Values { + metric.Values = append(metric.Values, cloudprovider.MetricValue{ + Value: value.Value, + Timestamp: time.Unix(int64(value.Timestamp), 0), + Tags: tags, + }) + } + if len(metric.Values) > 0 { + ret = append(ret, metric) + } + } + } + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/natdtable.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/natdtable.go new file mode 100644 index 0000000000..1cff38ac58 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/natdtable.go @@ -0,0 +1,104 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "time" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDTable struct { + multicloud.SResourceBase + QcloudTags + nat *SNatGateway + + Eip string + NatId string + Description string + UniqVpcId string + Proto string + Pport int + Eport int + Owner string + VpcId int + PipType int + Pip string + UniqNatId string + CreateTime time.Time +} + +func (table *SDTable) GetName() string { + if len(table.Description) > 0 { + return table.Description + } + return fmt.Sprintf("%s/%s/%d", table.Eip, table.Proto, table.Eport) +} + +func (table *SDTable) GetId() string { + return fmt.Sprintf("%s/%s/%d", table.NatId, table.Eip, table.Eport) +} + +func (table *SDTable) GetGlobalId() string { + return table.GetId() +} + +func (table *SDTable) GetStatus() string { + return api.NAT_STAUTS_AVAILABLE +} + +func (table *SDTable) GetExternalIp() string { + return table.Eip +} + +func (table *SDTable) GetExternalPort() int { + return table.Eport +} + +func (table *SDTable) GetInternalIp() string { + return table.Pip +} + +func (table *SDTable) GetInternalPort() int { + return table.Pport +} + +func (table *SDTable) GetIpProtocol() string { + return table.Proto +} + +func (table *SDTable) Delete() error { + return cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetDTables(natId, vpcId string) ([]SDTable, error) { + param := map[string]string{} + param["vpcId"] = vpcId + param["natId"] = natId + + body, err := region.vpc2017Request("GetDnaptRule", param) + if err != nil { + return nil, err + } + tables := []SDTable{} + err = body.Unmarshal(&tables, "data", "detail") + if err != nil { + return nil, err + } + return tables, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/natgateway.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/natgateway.go new file mode 100644 index 0000000000..9d93cb3bbd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/natgateway.go @@ -0,0 +1,164 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "time" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SNatGateway struct { + multicloud.SNatGatewayBase + QcloudTags + vpc *SVpc + + NatId string `json:"natId"` + NatName string `json:"natName"` + ProductionStatus float32 `json:"productionStatus"` + State float32 `json:"state"` + UnVpcId string `json:"unVpcId"` + VpcId float32 `json:"vpcId"` + VpcName string `json:"vpcName"` + Zone string `json:"zone"` + + Bandwidth float32 `json:"bandwidth"` + CreateTime time.Time `json:"createTime"` + EipCount float32 `json:"eipCount"` + MaxConcurrent float32 `json:"maxConcurrent"` +} + +func (nat *SNatGateway) GetName() string { + if len(nat.NatName) > 0 { + return nat.NatName + } + return nat.NatId +} + +func (nat *SNatGateway) GetId() string { + return nat.NatId +} + +func (nat *SNatGateway) GetGlobalId() string { + return nat.NatId +} + +func (self *SNatGateway) GetINetworkId() string { + return "" +} + +func (nat *SNatGateway) GetStatus() string { + // NAT网关状态,0:运行中, 1:不可用, 2:欠费停服 + switch int(nat.State) { + case 0: + return api.NAT_STAUTS_AVAILABLE + case 1, 2: + return api.NAT_STATUS_UNKNOWN + default: + return api.NAT_STATUS_UNKNOWN + } +} + +func (nat *SNatGateway) GetNatSpec() string { + switch int(nat.MaxConcurrent) { + case 100 * 10000: + return api.QCLOUD_NAT_SPEC_SMALL + case 300 * 10000: + return api.QCLOUD_NAT_SPEC_MIDDLE + case 1000 * 10000: + return api.QCLOUD_NAT_SPEC_LARGE + } + return "" +} + +func (nat *SNatGateway) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips := []SEipAddress{} + for { + part, total, err := nat.vpc.region.GetEips("", nat.NatId, len(eips), 50) + if err != nil { + return nil, err + } + eips = append(eips, part...) + if len(eips) >= total { + break + } + } + ieips := []cloudprovider.ICloudEIP{} + for i := 0; i < len(eips); i++ { + eips[i].region = nat.vpc.region + ieips = append(ieips, &eips[i]) + } + return ieips, nil +} + +func (nat *SNatGateway) GetINatSTable() ([]cloudprovider.ICloudNatSEntry, error) { + return []cloudprovider.ICloudNatSEntry{}, nil +} + +func (nat *SNatGateway) GetINatDTable() ([]cloudprovider.ICloudNatDEntry, error) { + tables, err := nat.vpc.region.GetDTables(nat.NatId, nat.vpc.VpcId) + if err != nil { + return nil, err + } + itables := []cloudprovider.ICloudNatDEntry{} + for i := 0; i < len(tables); i++ { + tables[i].nat = nat + itables = append(itables, &tables[i]) + } + return itables, nil +} + +func (nat *SNatGateway) GetINatDEntryByID(id string) (cloudprovider.ICloudNatDEntry, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (nat *SNatGateway) GetINatSEntryByID(id string) (cloudprovider.ICloudNatSEntry, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (nat *SNatGateway) CreateINatDEntry(rule cloudprovider.SNatDRule) (cloudprovider.ICloudNatDEntry, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (nat *SNatGateway) CreateINatSEntry(rule cloudprovider.SNatSRule) (cloudprovider.ICloudNatSEntry, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetNatGateways(vpcId string, offset int, limit int) ([]SNatGateway, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + + params := make(map[string]string) + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + if len(vpcId) > 0 { + params["vpcId"] = vpcId + } + body, err := region.vpc2017Request("DescribeNatGateway", params) + if err != nil { + return nil, 0, err + } + nats := []SNatGateway{} + err = body.Unmarshal(&nats, "data") + if err != nil { + return nil, 0, err + } + total, _ := body.Float("totalCount") + return nats, int(total), nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/network.go new file mode 100644 index 0000000000..66f43fa05c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/network.go @@ -0,0 +1,183 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "time" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + QcloudTags + wire *SWire + + CidrBlock string + Zone string + SubnetId string + VpcId string + SubnetName string + AvailableIpAddressCount int + CreatedTime time.Time + EnableBroadcast bool + IsDefault bool + RouteTableId string +} + +func (self *SNetwork) GetId() string { + return self.SubnetId +} + +func (self *SNetwork) GetName() string { + if len(self.SubnetName) > 0 { + return self.SubnetName + } + return self.SubnetId +} + +func (self *SNetwork) GetGlobalId() string { + return self.SubnetId +} + +func (self *SNetwork) IsEmulated() bool { + return false +} + +func (self *SNetwork) GetStatus() string { + return api.NETWORK_STATUS_AVAILABLE +} + +func (self *SNetwork) Delete() error { + return self.wire.zone.region.DeleteNetwork(self.SubnetId) +} + +func (self *SRegion) DeleteNetwork(networkId string) error { + params := make(map[string]string) + params["SubnetId"] = networkId + + interfaces := []SNetworkInterface{} + for { + _interfaces, total, err := self.GetNetworkInterfaces([]string{}, "", networkId, len(interfaces), 50) + if err != nil { + return errors.Wrapf(err, "DeleteNetwork.GetNetworkInterfaces") + } + interfaces = append(interfaces, _interfaces...) + if len(interfaces) >= total { + break + } + } + + for _, nic := range interfaces { + err := self.DeleteNetworkInterface(nic.NetworkInterfaceId) + if err != nil { + return errors.Wrapf(err, "DeleteNetwork.DeleteNetworkInterface") + } + } + + _, err := self.vpcRequest("DeleteSubnet", params) + if err != nil { + return errors.Wrapf(err, "vpcRequest.DeleteSubnet") + } + return nil +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (self *SNetwork) SetTags(tags map[string]string, replace bool) error { + return self.wire.vpc.region.SetResourceTags("vpc", "subnet", []string{self.SubnetId}, tags, replace) +} + +func (self *SNetwork) GetGateway() string { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + return endIp.String() +} + +//https://cloud.tencent.com/document/product/215/20046 +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 + startIp = startIp.StepUp() // 2 + return startIp.String() +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + return endIp.String() +} + +func (self *SNetwork) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(self.CidrBlock) + return pref.MaskLen +} + +func (self *SNetwork) GetIsPublic() bool { + // return self.IsDefault + return true +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) Refresh() error { + log.Debugf("network refresh %s", self.SubnetId) + new, err := self.wire.zone.region.GetNetwork(self.SubnetId) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SRegion) CreateNetwork(zoneId string, vpcId string, name string, cidr string, desc string) (string, error) { + params := make(map[string]string) + params["Zone"] = zoneId + params["VpcId"] = vpcId + params["CidrBlock"] = cidr + params["SubnetName"] = name + body, err := self.vpcRequest("CreateSubnet", params) + if err != nil { + return "", err + } + return body.GetString("Subnet", "SubnetId") +} + +func (self *SNetwork) GetProjectId() string { + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/networkinterface.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/networkinterface.go new file mode 100644 index 0000000000..1b3ce92e1a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/networkinterface.go @@ -0,0 +1,199 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + "time" + + "github.com/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SPrivateIpAddress struct { + nic *SNetworkInterface + Description string + Primary bool + PrivateIpAddress string + PublicIpAddress string + IsWanIpBlocked bool + State string +} + +func (ip *SPrivateIpAddress) GetGlobalId() string { + return ip.PrivateIpAddress +} + +func (ip *SPrivateIpAddress) GetIP() string { + return ip.PrivateIpAddress +} + +func (ip *SPrivateIpAddress) GetINetworkId() string { + return ip.nic.SubnetId +} + +func (ip *SPrivateIpAddress) IsPrimary() bool { + return ip.Primary +} + +type SNetworkInterfaceAttachment struct { + InstanceId string + DeviceIndex int + InstanceAccountId string + AttachTime string +} + +type SNetworkInterface struct { + multicloud.SNetworkInterfaceBase + QcloudTags + region *SRegion + VpcId string + SubnetId string + NetworkInterfaceId string + NetworkInterfaceName string + NetworkInterfaceDescription string + GroupSet []string + Primary bool + MacAddress string + State string + CreatedTime time.Time + Attachment SNetworkInterfaceAttachment + Zone string + PrivateIpAddressSet []SPrivateIpAddress +} + +func (nic *SNetworkInterface) GetName() string { + return nic.NetworkInterfaceName +} + +func (nic *SNetworkInterface) GetId() string { + return nic.NetworkInterfaceId +} + +func (nic *SNetworkInterface) GetGlobalId() string { + return nic.NetworkInterfaceId +} + +func (nic *SNetworkInterface) GetMacAddress() string { + return nic.MacAddress +} + +func (nic *SNetworkInterface) GetAssociateType() string { + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_SERVER +} + +func (nic *SNetworkInterface) GetAssociateId() string { + return nic.Attachment.InstanceId +} + +func (nic *SNetworkInterface) GetStatus() string { + switch nic.State { + case "PENDING": + return api.NETWORK_INTERFACE_STATUS_CREATING + case "AVAILABLE": + return api.NETWORK_INTERFACE_STATUS_AVAILABLE + case "ATTACHING": + return api.NETWORK_INTERFACE_STATUS_ATTACHING + case "DETACHING": + return api.NETWORK_INTERFACE_STATUS_DETACHING + case "DELETING": + return api.NETWORK_INTERFACE_STATUS_DELETING + } + return nic.State +} + +func (nic *SNetworkInterface) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { + address := []cloudprovider.ICloudInterfaceAddress{} + for i := 0; i < len(nic.PrivateIpAddressSet); i++ { + nic.PrivateIpAddressSet[i].nic = nic + address = append(address, &nic.PrivateIpAddressSet[i]) + } + return address, nil +} + +func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { + interfaces := []SNetworkInterface{} + for { + parts, total, err := region.GetNetworkInterfaces([]string{}, "", "", len(interfaces), 50) + if err != nil { + return nil, err + } + interfaces = append(interfaces, parts...) + if len(interfaces) >= total { + break + } + } + ret := []cloudprovider.ICloudNetworkInterface{} + for i := 0; i < len(interfaces); i++ { + if !strings.HasPrefix(interfaces[i].Attachment.InstanceId, "ins-") { //弹性网卡有可能已绑定资源,若绑定资源则由资源进行同步 + interfaces[i].region = region + ret = append(ret, &interfaces[i]) + } + } + return ret, nil +} + +func (region *SRegion) GetNetworkInterfaces(nicIds []string, instanceId, subnetId string, offset int, limit int) ([]SNetworkInterface, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := map[string]string{} + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + + for idx, interfaceId := range nicIds { + params[fmt.Sprintf("NetworkInterfaceIds.%d", idx)] = interfaceId + } + + idx := 0 + if len(subnetId) > 0 { + params[fmt.Sprintf("Filters.%d.Name", idx)] = "subnet-id" + params[fmt.Sprintf("Filters.%d.Values.0", idx)] = subnetId + idx++ + } + if len(instanceId) > 0 { + params[fmt.Sprintf("Filters.%d.Name", idx)] = "attachment.instance-id" + params[fmt.Sprintf("Filters.%d.Values.0", idx)] = instanceId + idx++ + } + body, err := region.vpcRequest("DescribeNetworkInterfaces", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeNetworkInterfaces") + } + + interfaces := []SNetworkInterface{} + err = body.Unmarshal(&interfaces, "NetworkInterfaceSet") + if err != nil { + return nil, 0, errors.Wrapf(err, "Unmarshal.NetworkInterfaceSet") + } + total, _ := body.Float("TotalCount") + return interfaces, int(total), nil +} + +func (region *SRegion) DeleteNetworkInterface(interfaceId string) error { + params := map[string]string{} + params["Region"] = region.Region + params["NetworkInterfaceId"] = interfaceId + + _, err := region.vpcRequest("DeleteNetworkInterface", params) + if err != nil { + return errors.Wrapf(err, "vpcRequest.DeleteNetworkInterface") + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/object.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/object.go new file mode 100644 index 0000000000..a1f03dd44f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/object.go @@ -0,0 +1,90 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "net/http" + + "github.com/tencentyun/cos-go-sdk-v5" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SObject struct { + bucket *SBucket + + cloudprovider.SBaseCloudObject +} + +func (o *SObject) GetIBucket() cloudprovider.ICloudBucket { + return o.bucket +} + +func (o *SObject) GetAcl() cloudprovider.TBucketACLType { + acl := cloudprovider.ACLPrivate + coscli, err := o.bucket.region.GetCosClient(o.bucket) + if err != nil { + log.Errorf("o.bucket.region.GetOssClient error %s", err) + return acl + } + result, _, err := coscli.Object.GetACL(context.Background(), o.Key) + if err != nil { + log.Errorf("coscli.Object.GetACL error %s", err) + return acl + } + return cosAcl2CannedAcl(result.AccessControlList) +} + +func (o *SObject) SetAcl(aclStr cloudprovider.TBucketACLType) error { + coscli, err := o.bucket.region.GetCosClient(o.bucket) + if err != nil { + return errors.Wrap(err, "o.bucket.region.GetCosClient") + } + opts := &cos.ObjectPutACLOptions{ + Header: &cos.ACLHeaderOptions{}, + } + opts.Header.XCosACL = string(aclStr) + _, err = coscli.Object.PutACL(context.Background(), o.Key, opts) + if err != nil { + return errors.Wrap(err, "coscli.Object.PutACL") + } + return nil +} + +func (o *SObject) GetMeta() http.Header { + if o.Meta != nil { + return o.Meta + } + coscli, err := o.bucket.region.GetCosClient(o.bucket) + if err != nil { + log.Errorf("o.bucket.region.GetCosClient fail %s", err) + return nil + } + resp, err := coscli.Object.Head(context.Background(), o.Key, nil) + if err != nil { + log.Errorf("coscli.Object.Head fail %s", err) + return nil + } + o.Meta = cloudprovider.FetchMetaFromHttpHeader(COS_META_HEADER, resp.Header) + return o.Meta +} + +func (o *SObject) SetMeta(ctx context.Context, meta http.Header) error { + return cloudprovider.ObjectSetMeta(ctx, o.bucket, o, meta) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/project.go new file mode 100644 index 0000000000..4438af97b4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/project.go @@ -0,0 +1,115 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SProject struct { + multicloud.SProjectBase + QcloudTags + client *SQcloudClient + + ProjectName string `json:"projectName"` + ProjectId string `json:"projectId"` + CreateTime time.Time `json:"createTime"` + CreateorUin int `json:"creatorUin"` + ProjectInfo string `json:"projectInfo"` +} + +func (p *SProject) GetId() string { + var pId string + pos := strings.Index(p.ProjectId, ".") + if pos >= 0 { + pId = p.ProjectId[:pos] + } else { + pId = p.ProjectId + } + return pId +} + +func (p *SProject) GetGlobalId() string { + return p.GetId() +} + +func (p *SProject) GetName() string { + return p.ProjectName +} + +func (p *SProject) GetStatus() string { + return api.EXTERNAL_PROJECT_STATUS_AVAILABLE +} + +func (p *SProject) IsEmulated() bool { + return false +} + +func (p *SProject) Refresh() error { + return nil +} + +func (client *SQcloudClient) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return client.CreateProject(name, "") +} + +func (client *SQcloudClient) GetProjects() ([]SProject, error) { + projects := []SProject{} + params := map[string]string{"allList": "1"} + resp, err := client.accountRequestRequest("DescribeProject", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeProject") + } + err = resp.Unmarshal(&projects) + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return projects, nil +} + +func (client *SQcloudClient) CreateProject(name, desc string) (*SProject, error) { + params := map[string]string{ + "projectName": name, + } + if len(desc) > 0 { + params["projectDesc"] = desc + } + body, err := client.accountRequestRequest("AddProject", params) + if err != nil { + return nil, errors.Wrap(err, "AddProject") + } + projectId, _ := body.GetString("projectId") + if len(projectId) == 0 { + return nil, fmt.Errorf("empty project reture") + } + projects, err := client.GetProjects() + if err != nil { + return nil, errors.Wrap(err, "GetProjects") + } + for i := range projects { + if projects[i].GetId() == projectId { + return &projects[i], nil + } + } + return nil, fmt.Errorf("failedd to found created project") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/provider/doc.go new file mode 100644 index 0000000000..1022631927 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/qcloud/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/provider/provider.go new file mode 100644 index 0000000000..fc9b9eb0b2 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/provider/provider.go @@ -0,0 +1,463 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "fmt" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/qcloud" +) + +type SQcloudProviderFactory struct { + cloudprovider.SPublicCloudBaseProviderFactory +} + +func (self *SQcloudProviderFactory) GetId() string { + return qcloud.CLOUD_PROVIDER_QCLOUD +} + +func (self *SQcloudProviderFactory) GetName() string { + return qcloud.CLOUD_PROVIDER_QCLOUD_CN +} + +func (self *SQcloudProviderFactory) IsCloudeventRegional() bool { + return true +} + +func (self *SQcloudProviderFactory) GetMaxCloudEventSyncDays() int { + return 7 +} + +func (self *SQcloudProviderFactory) GetMaxCloudEventKeepDays() int { + return 30 +} + +func (self *SQcloudProviderFactory) IsSupportCloudIdService() bool { + return true +} + +func (self *SQcloudProviderFactory) IsSupportCreateCloudgroup() bool { + return true +} + +func (self *SQcloudProviderFactory) IsSupportSAMLAuth() bool { + return true +} + +func (self *SQcloudProviderFactory) IsSupportCrossCloudEnvVpcPeering() bool { + return false +} + +func (self *SQcloudProviderFactory) IsSupportCrossRegionVpcPeering() bool { + return true +} + +func (self *SQcloudProviderFactory) IsSupportVpcPeeringVpcCidrOverlap() bool { + return false +} + +func (self *SQcloudProviderFactory) ValidateCrossRegionVpcPeeringBandWidth(bandwidth int) error { + validatedBandwidths := []int{10, 20, 50, 100, 200, 500, 1000} + ok, _ := utils.InArray(bandwidth, validatedBandwidths) + if ok { + return nil + } + return httperrors.NewInputParameterError("require validated qcloud cross region vpcPeering bandwidth values:[10, 20, 50, 100, 200, 500, 1000],unit Mbps") +} + +func (self *SQcloudProviderFactory) GetSupportedDnsZoneTypes() []cloudprovider.TDnsZoneType { + return []cloudprovider.TDnsZoneType{ + cloudprovider.PublicZone, + } +} + +func (self *SQcloudProviderFactory) GetSupportedDnsTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType { + return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsType{ + cloudprovider.PublicZone: []cloudprovider.TDnsType{ + cloudprovider.DnsTypeA, + cloudprovider.DnsTypeAAAA, + cloudprovider.DnsTypeCNAME, + cloudprovider.DnsTypeMX, + cloudprovider.DnsTypeNS, + cloudprovider.DnsTypeSRV, + cloudprovider.DnsTypeTXT, + cloudprovider.DnsTypePTR, + }, + } +} + +func (self *SQcloudProviderFactory) GetSupportedDnsPolicyTypes() map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType { + return map[cloudprovider.TDnsZoneType][]cloudprovider.TDnsPolicyType{ + cloudprovider.PublicZone: []cloudprovider.TDnsPolicyType{ + cloudprovider.DnsPolicyTypeSimple, + cloudprovider.DnsPolicyTypeByCarrier, + cloudprovider.DnsPolicyTypeByGeoLocation, + cloudprovider.DnsPolicyTypeBySearchEngine, + cloudprovider.DnsPolicyTypeWeighted, + }, + } +} + +func (self *SQcloudProviderFactory) GetSupportedDnsPolicyValues() map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue { + return map[cloudprovider.TDnsPolicyType][]cloudprovider.TDnsPolicyValue{ + cloudprovider.DnsPolicyTypeByCarrier: []cloudprovider.TDnsPolicyValue{ + cloudprovider.DnsPolicyValueUnicom, + cloudprovider.DnsPolicyValueTelecom, + cloudprovider.DnsPolicyValueChinaMobile, + cloudprovider.DnsPolicyValueCernet, + }, + cloudprovider.DnsPolicyTypeByGeoLocation: []cloudprovider.TDnsPolicyValue{ + cloudprovider.DnsPolicyValueOversea, + cloudprovider.DnsPolicyValueMainland, + }, + cloudprovider.DnsPolicyTypeBySearchEngine: []cloudprovider.TDnsPolicyValue{ + cloudprovider.DnsPolicyValueBaidu, + cloudprovider.DnsPolicyValueBing, + cloudprovider.DnsPolicyValueGoogle, + cloudprovider.DnsPolicyValueYoudao, + cloudprovider.DnsPolicyValueSousou, + cloudprovider.DnsPolicyValueSougou, + cloudprovider.DnsPolicyValueQihu360, + }, + } +} + +// https://buy.cloud.tencent.com/cns?from=gobuy&domain=example4.com +func (self *SQcloudProviderFactory) GetTTLRange(zoneType cloudprovider.TDnsZoneType, productType cloudprovider.TDnsProductType) cloudprovider.TTlRange { + if len(productType) > 0 { + switch productType { + case cloudprovider.DnsProductEnterpriseUltimate: + return cloudprovider.TtlRangeQcloudEnterpriseUltimate + case cloudprovider.DnsProductEnterpriseStandard: + return cloudprovider.TtlRangeQcloudEnterpriseStandard + case cloudprovider.DnsProductEnterpriseBasic: + return cloudprovider.TtlRangeQcloudEnterpriseBasic + case cloudprovider.DnsProductPersonalProfessional: + return cloudprovider.TtlRangeQcloudPersonalProfessional + case cloudprovider.DnsProductFree: + return cloudprovider.TtlRangeQcloudFree + default: + return cloudprovider.TtlRangeQcloudFree + } + } + return cloudprovider.TtlRangeQcloudFree +} + +func (self *SQcloudProviderFactory) ValidateChangeBandwidth(instanceId string, bandwidth int64) error { + if len(instanceId) == 0 { + return fmt.Errorf("Only changes to the binding machine's EIP bandwidth are supported") + } + return nil +} + +func (self *SQcloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AppId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "app_id") + } + if len(input.SecretId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_id") + } + if len(input.SecretKey) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_key") + } + output.Account = fmt.Sprintf("%s/%s", input.SecretId, input.AppId) + output.Secret = input.SecretKey + return output, nil +} + +func (self *SQcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AppId) == 0 { + accountInfo := strings.Split(cloudaccount, "/") + if len(accountInfo) < 2 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "app_id") + } + input.AppId = accountInfo[1] + } + if len(input.SecretId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_id") + } + if len(input.SecretKey) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "secret_key") + } + output = cloudprovider.SCloudaccount{ + Account: fmt.Sprintf("%s/%s", input.SecretId, input.AppId), + Secret: input.SecretKey, + } + return output, nil +} + +func (self *SQcloudProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + secretId := cfg.Account + appId := "" + if tmp := strings.Split(cfg.Account, "/"); len(tmp) == 2 { + secretId = tmp[0] + appId = tmp[1] + } + client, err := qcloud.NewQcloudClient( + qcloud.NewQcloudClientConfig( + secretId, cfg.Secret, + ).AppId(appId).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SQcloudProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SQcloudProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + secretId := info.Account + appId := "" + if tmp := strings.Split(info.Account, "/"); len(tmp) == 2 { + secretId = tmp[0] + appId = tmp[1] + } + return map[string]string{ + "QCLOUD_APPID": appId, + "QCLOUD_SECRET_ID": secretId, + "QCLOUD_SECRET_KEY": info.Secret, + "QCLOUD_REGION": qcloud.QCLOUD_DEFAULT_REGION, + }, nil +} + +func init() { + factory := SQcloudProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SQcloudProvider struct { + cloudprovider.SBaseProvider + client *qcloud.SQcloudClient +} + +func (self *SQcloudProvider) GetSysInfo() (jsonutils.JSONObject, error) { + regions := self.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") + info.Add(jsonutils.NewString(qcloud.QCLOUD_API_VERSION), "api_version") + return info, nil +} + +func (self *SQcloudProvider) GetVersion() string { + return qcloud.QCLOUD_API_VERSION +} + +func (self *SQcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SQcloudProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SQcloudProvider) GetIamLoginUrl() string { + return self.client.GetIamLoginUrl() +} + +func (self *SQcloudProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SQcloudProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(id) +} + +func (self *SQcloudProvider) GetBalance() (float64, string, error) { + balance, err := self.client.QueryAccountBalance() + if err != nil { + return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, err + } + status := api.CLOUD_PROVIDER_HEALTH_NORMAL + if balance.AvailableAmount < 0.0 { + status = api.CLOUD_PROVIDER_HEALTH_ARREARS + } + return balance.AvailableAmount, status, nil +} + +func (self *SQcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SQcloudProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return self.client.CreateIProject(name) +} + +func (self *SQcloudProvider) GetStorageClasses(regionId string) []string { + return []string{ + "STANDARD", "STANDARD_IA", "ARCHIVE", + } +} + +func (self *SQcloudProvider) GetBucketCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLAuthRead), + string(cloudprovider.ACLPublicRead), + } +} + +func (self *SQcloudProvider) GetObjectCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLAuthRead), + string(cloudprovider.ACLPublicRead), + } +} + +func (self *SQcloudProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SQcloudProvider) CreateIClouduser(conf *cloudprovider.SClouduserCreateConfig) (cloudprovider.IClouduser, error) { + return self.client.CreateIClouduser(conf) +} + +func (self *SQcloudProvider) GetICloudusers() ([]cloudprovider.IClouduser, error) { + return self.client.GetICloudusers() +} + +func (self *SQcloudProvider) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroups() +} + +func (self *SQcloudProvider) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) { + return self.client.GetICloudgroupByName(name) +} + +func (self *SQcloudProvider) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) { + return self.client.CreateICloudgroup(name, desc) +} + +func (self *SQcloudProvider) GetISystemCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetISystemCloudpolicies() +} + +func (self *SQcloudProvider) GetICustomCloudpolicies() ([]cloudprovider.ICloudpolicy, error) { + return self.client.GetICustomCloudpolicies() +} + +func (self *SQcloudProvider) GetIClouduserByName(name string) (cloudprovider.IClouduser, error) { + return self.client.GetIClouduserByName(name) +} + +func (self *SQcloudProvider) CreateICloudpolicy(opts *cloudprovider.SCloudpolicyCreateOptions) (cloudprovider.ICloudpolicy, error) { + return self.client.CreateICloudpolicy(opts) +} + +func (self *SQcloudProvider) GetSamlEntityId() string { + return cloudprovider.SAML_ENTITY_ID_QCLOUD +} + +func (self *SQcloudProvider) GetICloudDnsZones() ([]cloudprovider.ICloudDnsZone, error) { + return self.client.GetICloudDnsZones() +} + +func (self *SQcloudProvider) GetICloudDnsZoneById(id string) (cloudprovider.ICloudDnsZone, error) { + domain, err := self.client.GetDomain(id) + if err != nil { + return nil, err + } + return domain, nil +} + +func (self *SQcloudProvider) CreateICloudDnsZone(opts *cloudprovider.SDnsZoneCreateOptions) (cloudprovider.ICloudDnsZone, error) { + return self.client.CreateICloudDnsZone(opts) +} + +func (self *SQcloudProvider) CreateICloudSAMLProvider(opts *cloudprovider.SAMLProviderCreateOptions) (cloudprovider.ICloudSAMLProvider, error) { + saml, err := self.client.CreateSAMLProvider(opts.Name, opts.Metadata.String(), "") + if err != nil { + return nil, errors.Wrap(err, "CreateSAMLProvider") + } + return saml, nil +} + +func (self *SQcloudProvider) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { + return self.client.GetICloudSAMLProviders() +} + +func (self *SQcloudProvider) CreateICloudrole(opts *cloudprovider.SRoleCreateOptions) (cloudprovider.ICloudrole, error) { + if len(opts.SAMLProvider) > 0 { + document := fmt.Sprintf(`{"version":"2.0","statement":[{"action":"name/sts:AssumeRoleWithSAML","effect":"allow","principal":{"federated":["qcs::cam::uin/%s:saml-provider/%s"]},"condition":{}}]}`, self.client.GetAccountId(), opts.SAMLProvider) + role, err := self.client.CreateRole(opts.Name, document, opts.Desc) + if err != nil { + return nil, errors.Wrapf(err, "CreateRole") + } + return role, nil + } + role, err := self.client.CreateRole(opts.Name, "", opts.Desc) + if err != nil { + return nil, errors.Wrapf(err, "") + } + return role, nil +} + +func (self *SQcloudProvider) GetICloudroles() ([]cloudprovider.ICloudrole, error) { + return self.client.GetICloudroles() +} + +func (self *SQcloudProvider) GetICloudroleByName(name string) (cloudprovider.ICloudrole, error) { + role, err := self.client.GetRole(name) + if err != nil { + return nil, errors.Wrapf(err, "GetRole(%s)", name) + } + return role, nil +} + +func (self *SQcloudProvider) GetICloudroleById(id string) (cloudprovider.ICloudrole, error) { + return self.GetICloudroleByName(id) +} + +func (self *SQcloudProvider) GetICloudInterVpcNetworks() ([]cloudprovider.ICloudInterVpcNetwork, error) { + return self.client.GetICloudInterVpcNetworks() +} + +func (self *SQcloudProvider) GetICloudInterVpcNetworkById(id string) (cloudprovider.ICloudInterVpcNetwork, error) { + return self.client.GetICloudInterVpcNetworkById(id) +} + +func (self *SQcloudProvider) CreateICloudInterVpcNetwork(opts *cloudprovider.SInterVpcNetworkCreateOptions) (cloudprovider.ICloudInterVpcNetwork, error) { + return self.client.CreateICloudInterVpcNetwork(opts) +} + +func (self *SQcloudProvider) GetICloudCDNDomains() ([]cloudprovider.ICloudCDNDomain, error) { + return self.client.GetICloudCDNDomains() +} + +func (self *SQcloudProvider) GetICloudCDNDomainByName(name string) (cloudprovider.ICloudCDNDomain, error) { + return self.client.GetICloudCDNDomainByName(name) +} + +func (self *SQcloudProvider) CreateICloudCDNDomain(opts *cloudprovider.CdnCreateOptions) (cloudprovider.ICloudCDNDomain, error) { + return self.client.CreateCDNDomain(opts) +} + +func (self *SQcloudProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetMetrics(opts) +} diff --git a/pkg/multicloud/qcloud/qcloud.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/qcloud.go similarity index 99% rename from pkg/multicloud/qcloud/qcloud.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/qcloud.go index 58b106e611..0b5eaba3bd 100644 --- a/pkg/multicloud/qcloud/qcloud.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/qcloud.go @@ -39,8 +39,8 @@ import ( "yunion.io/x/pkg/util/timeutils" "yunion.io/x/pkg/utils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/quota.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/quota.go new file mode 100644 index 0000000000..ec23ebc64b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/quota.go @@ -0,0 +1,131 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "strings" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type ImageQuota struct { + region *SRegion + ImageNumQuota int +} + +func (iq *ImageQuota) GetGlobalId() string { + return "ImageNumQuota" +} + +func (iq *ImageQuota) GetName() string { + return "ImageNumQuota" +} + +func (iq *ImageQuota) GetDesc() string { + return "" +} + +func (iq *ImageQuota) GetQuotaType() string { + return "ImageNumQuota" +} + +func (iq *ImageQuota) GetMaxQuotaCount() int { + return iq.ImageNumQuota +} + +func (iq *ImageQuota) GetCurrentQuotaUsedCount() int { + _, count, err := iq.region.GetImages("", "PRIVATE_IMAGE", nil, "", 0, iq.ImageNumQuota) + if err != nil { + log.Errorf("get private image error: %v", err) + return -1 + } + return count +} + +func (region *SRegion) GetImageQuota() (*ImageQuota, error) { + params := map[string]string{} + resp, err := region.cvmRequest("DescribeImageQuota", params, true) + if err != nil { + return nil, errors.Wrap(err, "DescribeImageQuota") + } + imageQuota := &ImageQuota{region: region} + return imageQuota, resp.Unmarshal(imageQuota) +} + +type QuotaSet struct { + QuotaId string + QuotaCurrent int + QuotaLimit int +} + +func (qs *QuotaSet) GetGlobalId() string { + return strings.ToLower(qs.QuotaId) +} + +func (qs *QuotaSet) GetName() string { + return qs.QuotaId +} + +func (qs *QuotaSet) GetDesc() string { + return "" +} + +func (qs *QuotaSet) GetQuotaType() string { + return qs.QuotaId +} + +func (qs *QuotaSet) GetMaxQuotaCount() int { + return qs.QuotaLimit +} + +func (qs *QuotaSet) GetCurrentQuotaUsedCount() int { + return qs.QuotaCurrent +} + +func (region *SRegion) GetQuota(action string) ([]QuotaSet, error) { + params := map[string]string{} + resp, err := region.vpcRequest(action, params) + if err != nil { + return nil, errors.Wrap(err, action) + } + quotas := []QuotaSet{} + err = resp.Unmarshal("as, "QuotaSet") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return quotas, nil +} + +func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { + ret := []cloudprovider.ICloudQuota{} + imageQ, err := region.GetImageQuota() + if err != nil { + return nil, errors.Wrap(err, "GetImageQuota") + } + ret = append(ret, imageQ) + for _, action := range []string{"DescribeAddressQuota", "DescribeBandwidthPackageQuota"} { + quotas, err := region.GetQuota(action) + if err != nil { + return nil, errors.Wrapf(err, "GetQuota(%s)", action) + } + for i := range quotas { + ret = append(ret, "as[i]) + } + } + return ret, nil +} diff --git a/pkg/multicloud/qcloud/rds_mariadb_sku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mariadb_sku.go similarity index 98% rename from pkg/multicloud/qcloud/rds_mariadb_sku.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mariadb_sku.go index 525082121d..8ec3b8cc30 100644 --- a/pkg/multicloud/qcloud/rds_mariadb_sku.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mariadb_sku.go @@ -17,7 +17,7 @@ package qcloud import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" + api "yunion.io/x/cloudmux/pkg/apis/compute" ) var ( diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql.go new file mode 100644 index 0000000000..bdae0a6e4d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql.go @@ -0,0 +1,923 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + "regexp" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/timeutils" + "yunion.io/x/pkg/utils" + + billingapi "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SlaveInstanceInfo struct { + Region string + Vip string + VpcId int + Vport int + Zone string +} + +type SlaveInfo struct { + First SlaveInstanceInfo + Second SlaveInstanceInfo +} + +type SDrInfo struct { + Status int + Zone string + InstanceId string + Region string + SyncStatus string + InstanceName string + InstanceType string +} + +type SMasterInfo struct { + Region string + RegionId int + ZoneId int + Zone string + InstanceId string + ResourceId string + Status int + InstanceName string + InstanceType int + TaskStatus int + Memory int + Volume int + DeviceType string + Qps int + VpcId int + SubnetId int + ExClusterId string + ExClusterName string +} + +type SRoGroup struct { + RoGroupMode string + RoGroupId string + RoGroupName string + RoOfflineDelay int + RoMaxDelayTime int + MinRoInGroup int + WeightMode string + Weight int + // RoInstances + Vip string + Vport int + UniqVpcId string + UniqSubnetId string + RoGroupRegion string + RoGroupZone string +} + +type SRoVipInfo struct { + RoVipStatus int + RoSubnetId int + RoVpcId int + RoVport int + RoVip string +} + +type SMySQLInstance struct { + region *SRegion + multicloud.SDBInstanceBase + QcloudTags + + AutoRenew int + CdbError int + Cpu int + CreateTime time.Time + DeadlineTime string + DeployGroupId string + DeployMode int + DeviceClass string + DeviceType string + DrInfo []SDrInfo + EngineVersion string + ExClusterId string + HourFeeStatus int + InitFlag int + InstanceId string + InstanceName string + InstanceType int + IsolateTime string + MasterInfo SMasterInfo + Memory int + OfflineTime string + PayType int + PhysicalId string + ProjectId int + ProtectMode string + Qps int + Region string + RegionId string + ResourceId string + RoGroups []SRoGroup + RoVipInfo SRoVipInfo + SecurityGroupIds []string + SlaveInfo SlaveInfo + Status int + SubnetId int + //TagList": null, + TaskStatus int + UniqSubnetId string + UniqVpcId string + Vip string + Volume int + VpcId int + Vport int + WanDomain string + WanPort int + WanStatus int + Zone string + ZoneId int + ZoneName string +} + +func (self *SMySQLInstance) GetId() string { + return self.InstanceId +} + +func (self *SMySQLInstance) GetGlobalId() string { + return self.InstanceId +} + +func (self *SMySQLInstance) GetName() string { + if len(self.InstanceName) > 0 { + return self.InstanceName + } + return self.InstanceId +} + +func (self *SMySQLInstance) GetDiskSizeGB() int { + return self.Volume +} + +func (self *SMySQLInstance) GetEngine() string { + return api.DBINSTANCE_TYPE_MYSQL +} + +func (self *SMySQLInstance) GetEngineVersion() string { + return self.EngineVersion +} + +func (self *SMySQLInstance) GetIVpcId() string { + return self.UniqVpcId +} + +func (self *SMySQLInstance) Refresh() error { + rds, err := self.region.GetMySQLInstanceById(self.InstanceId) + if err != nil { + return errors.Wrapf(err, "GetMySQLInstanceById(%s)", self.InstanceId) + } + return jsonutils.Update(self, rds) +} + +func (self *SMySQLInstance) GetInstanceType() string { + return fmt.Sprintf("%d核%dMB", self.Cpu, self.Memory) +} + +func (self *SMySQLInstance) GetMaintainTime() string { + timeWindow, err := self.region.DescribeMySQLTimeWindow(self.InstanceId) + if err != nil { + log.Errorf("DescribeMySQLTimeWindow %s error: %v", self.InstanceId, err) + return "" + } + return timeWindow.String() +} + +func (self *SMySQLInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { + return []cloudprovider.SDBInstanceNetwork{ + cloudprovider.SDBInstanceNetwork{NetworkId: self.UniqSubnetId, IP: self.Vip}, + }, nil +} + +func (self *SMySQLInstance) GetConnectionStr() string { + if self.WanStatus == 1 { + return fmt.Sprintf("%s:%d", self.WanDomain, self.WanPort) + } + return "" +} + +func (self *SMySQLInstance) GetInternalConnectionStr() string { + return fmt.Sprintf("%s:%d", self.Vip, self.Vport) +} + +func (self *SMySQLInstance) Reboot() error { + return self.region.RebootMySQLInstance(self.InstanceId) +} + +func (self *SMySQLInstance) ChangeConfig(ctx context.Context, opts *cloudprovider.SManagedDBInstanceChangeConfig) error { + mb := self.GetVmemSizeMB() + if len(opts.InstanceType) > 0 { + re := regexp.MustCompile(`(\d{1,4})核(\d{1,20})MB$`) + params := re.FindStringSubmatch(opts.InstanceType) + if len(params) != 3 { + return fmt.Errorf("invalid rds instance type %s", opts.InstanceType) + } + _mb, _ := strconv.Atoi(params[2]) + mb = int(_mb) + } + if opts.DiskSizeGB == 0 { + opts.DiskSizeGB = self.GetDiskSizeGB() + } + return self.region.UpgradeMySQLDBInstance(self.InstanceId, mb, opts.DiskSizeGB) +} + +func (self *SMySQLInstance) GetMasterInstanceId() string { + return self.MasterInfo.InstanceId +} + +func (self *SMySQLInstance) GetSecurityGroupIds() ([]string, error) { + if len(self.SecurityGroupIds) > 0 { + return self.SecurityGroupIds, nil + } + if self.DeviceType == "BASIC" { + return []string{}, nil + } + secgroups, err := self.region.DescribeMySQLDBSecurityGroups(self.InstanceId) + if err != nil { + return []string{}, errors.Wrapf(err, "DescribeMySQLDBSecurityGroups") + } + ids := []string{} + for i := range secgroups { + ids = append(ids, secgroups[i].SecurityGroupId) + } + return ids, nil +} + +func (self *SMySQLInstance) SetSecurityGroups(ids []string) error { + return self.region.ModifyMySQLInstanceSecurityGroups(self.InstanceId, ids) +} + +func (self *SRegion) ModifyMySQLInstanceSecurityGroups(rdsId string, secIds []string) error { + params := map[string]string{ + "InstanceId": rdsId, + } + for idx, id := range secIds { + params[fmt.Sprintf("SecurityGroupIds.%d", idx)] = id + } + _, err := self.cdbRequest("ModifyDBInstanceSecurityGroups", params) + return err +} + +func (self *SMySQLInstance) Renew(bc billing.SBillingCycle) error { + month := bc.GetMonths() + return self.region.RenewMySQLDBInstance(self.InstanceId, month) +} + +func (self *SMySQLInstance) OpenPublicConnection() error { + if self.WanStatus == 0 { + return self.region.OpenMySQLWanService(self.InstanceId) + } + return nil +} + +func (self *SMySQLInstance) ClosePublicConnection() error { + if self.WanStatus == 1 { + return self.region.CloseMySQLWanService(self.InstanceId) + } + return nil +} + +func (self *SMySQLInstance) GetPort() int { + return self.Vport +} + +func (self *SMySQLInstance) GetStatus() string { + if self.InitFlag == 0 { + return api.DBINSTANCE_INIT + } + switch self.Status { + case 4: + return api.DBINSTANCE_ISOLATING + case 5: + return api.DBINSTANCE_ISOLATE + } + switch self.TaskStatus { + case 0: + switch self.Status { + case 0: + return api.DBINSTANCE_DEPLOYING + case 1: + return api.DBINSTANCE_RUNNING + } + case 1: + return api.DBINSTANCE_UPGRADING + case 2: //数据导入中 + return api.DBINSTANCE_IMPORTING + case 3, 4: //开放关闭外网地址 + return api.DBINSTANCE_DEPLOYING + case 10: + return api.DBINSTANCE_REBOOTING + case 12: + return api.DBINSTANCE_MIGRATING + default: + return api.DBINSTANCE_DEPLOYING + } + return api.DBINSTANCE_UNKNOWN +} + +func (self *SMySQLInstance) GetCategory() string { + category := strings.ToLower(self.DeviceType) + if category == "universal" { + category = "ha" + } + return category +} + +func (self *SMySQLInstance) GetStorageType() string { + switch self.DeviceType { + case "BASIC": + return api.QCLOUD_DBINSTANCE_STORAGE_TYPE_CLOUD_SSD + default: + return api.QCLOUD_DBINSTANCE_STORAGE_TYPE_LOCAL_SSD + } +} + +func (self *SMySQLInstance) GetCreatedAt() time.Time { + // 2019-12-25 09:00:43 #非UTC时间 + return self.CreateTime.Add(time.Hour * -8) +} + +func (self *SMySQLInstance) GetBillingType() string { + if self.PayType == 0 { + return billingapi.BILLING_TYPE_PREPAID + } + return billingapi.BILLING_TYPE_POSTPAID +} + +func (self *SMySQLInstance) SetAutoRenew(bc billing.SBillingCycle) error { + return self.region.ModifyMySQLAutoRenewFlag([]string{self.InstanceId}, bc.AutoRenew) +} + +func (self *SMySQLInstance) IsAutoRenew() bool { + return self.AutoRenew == 1 +} + +func (self *SMySQLInstance) GetExpiredAt() time.Time { + offline, _ := timeutils.ParseTimeStr(self.OfflineTime) + if !offline.IsZero() { + return offline.Add(time.Hour * -8) + } + deadline, _ := timeutils.ParseTimeStr(self.DeadlineTime) + if !deadline.IsZero() { + return deadline.Add(time.Hour * -8) + } + return time.Time{} +} + +func (self *SMySQLInstance) GetVcpuCount() int { + return self.Cpu +} + +func (self *SMySQLInstance) GetVmemSizeMB() int { + return self.Memory +} + +func (self *SMySQLInstance) GetZone1Id() string { + return self.Zone +} + +func (self *SMySQLInstance) GetZone2Id() string { + return self.SlaveInfo.First.Zone +} + +func (self *SMySQLInstance) GetZone3Id() string { + return self.SlaveInfo.Second.Zone +} + +func (self *SMySQLInstance) GetProjectId() string { + return fmt.Sprintf("%d", self.ProjectId) +} + +func (self *SMySQLInstance) Delete() error { + err := self.region.IsolateMySQLDBInstance(self.InstanceId) + if err != nil { + return errors.Wrapf(err, "IsolateMySQLDBInstance") + } + return self.region.OfflineIsolatedMySQLInstances([]string{self.InstanceId}) +} + +func (self *SRegion) ListMySQLInstances(ids []string, offset, limit int) ([]SMySQLInstance, int, error) { + if limit < 1 || limit > 50 { + limit = 50 + } + params := map[string]string{ + "Offset": fmt.Sprintf("%d", offset), + "Limit": fmt.Sprintf("%d", limit), + } + for idx, id := range ids { + params[fmt.Sprintf("InstanceIds.%d", idx)] = id + } + resp, err := self.cdbRequest("DescribeDBInstances", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeDBInstances") + } + items := []SMySQLInstance{} + err = resp.Unmarshal(&items, "Items") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + total, _ := resp.Float("TotalCount") + return items, int(total), nil +} + +type SAsyncRequestResult struct { + Info string + Status string +} + +func (self *SRegion) DescribeMySQLAsyncRequestInfo(id string) (*SAsyncRequestResult, error) { + resp, err := self.cdbRequest("DescribeAsyncRequestInfo", map[string]string{"AsyncRequestId": id}) + if err != nil { + return nil, errors.Wrapf(err, "DescribeAsyncRequestInfo") + } + result := SAsyncRequestResult{} + err = resp.Unmarshal(&result) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return &result, nil +} + +func (self *SRegion) waitAsyncAction(action string, resId, asyncRequestId string) error { + if len(asyncRequestId) == 0 { + return errors.Error("Missing AsyncRequestId") + } + return cloudprovider.Wait(time.Second*10, time.Minute*20, func() (bool, error) { + result, err := self.DescribeMySQLAsyncRequestInfo(asyncRequestId) + if err != nil { + return false, errors.Wrapf(err, action) + } + log.Debugf("task %s(%s) for mysql instance %s status: %s", action, asyncRequestId, resId, result.Status) + switch result.Status { + case "FAILED", "KILLED", "REMOVED", "PAUSED": + return true, errors.Errorf(result.Info) + case "SUCCESS": + return true, nil + default: + return false, nil + } + }) +} + +func (self *SRegion) RebootMySQLInstance(id string) error { + resp, err := self.cdbRequest("RestartDBInstances", map[string]string{"InstanceIds.0": id}) + if err != nil { + return errors.Wrapf(err, "RestartDBInstances") + } + asyncRequestId, _ := resp.GetString("AsyncRequestId") + return self.waitAsyncAction("RestartDBInstances", id, asyncRequestId) +} + +func (self *SRegion) DescribeMySQLDBInstanceInfo(id string) (*SMySQLInstance, error) { + resp, err := self.cdbRequest("DescribeDBInstanceInfo", map[string]string{"InstanceId": id}) + if err != nil { + return nil, errors.Wrapf(err, "DescribeDBInstanceInfo") + } + result := SMySQLInstance{region: self} + err = resp.Unmarshal(&result) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return &result, nil +} + +func (self *SRegion) RenewMySQLDBInstance(id string, month int) error { + params := map[string]string{ + "InstanceId": id, + "TimeSpan": fmt.Sprintf("%d", month), + } + _, err := self.cdbRequest("RenewDBInstance", params) + if err != nil { + return errors.Wrapf(err, "RenewDBInstance") + } + return nil +} + +func (self *SRegion) OfflineIsolatedMySQLInstances(ids []string) error { + params := map[string]string{} + for idx, id := range ids { + params[fmt.Sprintf("InstanceIds.%d", idx)] = id + } + _, err := self.cdbRequest("OfflineIsolatedInstances", params) + if err != nil { + return errors.Wrapf(err, "OfflineIsolatedInstances") + } + return nil +} + +func (self *SRegion) ReleaseIsolatedMySQLDBInstances(ids []string) error { + params := map[string]string{} + for idx, id := range ids { + params[fmt.Sprintf("InstanceIds.%d", idx)] = id + } + resp, err := self.cdbRequest("ReleaseIsolatedDBInstances", params) + if err != nil { + return errors.Wrapf(err, "ReleaseIsolatedDBInstances") + } + result := []struct { + InstanceId string + Code int + Message string + }{} + err = resp.Unmarshal(&result, "Items") + if err != nil { + return errors.Wrapf(err, "resp.Unmarshal") + } + msg := []string{} + for i := range result { + if result[i].Code != 0 { + msg = append(msg, fmt.Sprintf("instance %s release isolate error: %s", result[i].InstanceId, result[i].Message)) + } + } + if len(msg) > 0 { + return errors.Error(strings.Join(msg, " ")) + } + return cloudprovider.Wait(time.Second, time.Minute*10, func() (bool, error) { + instances, _, err := self.ListMySQLInstances(ids, 0, len(ids)) + if err != nil { + return false, errors.Wrapf(err, "ListMySQLInstances") + } + for i := range instances { + if instances[i].Status == 4 || instances[i].Status == 5 { + log.Debugf("mysql instance %s(%s) current be isolate", instances[i].InstanceName, instances[i].InstanceId) + return false, nil + } + } + return true, nil + }) +} + +func (self *SRegion) IsolateMySQLDBInstance(id string) error { + params := map[string]string{"InstanceId": id} + resp, err := self.cdbRequest("IsolateDBInstance", params) + if err != nil { + return errors.Wrapf(err, "IsolateDBInstance") + } + asyncRequestId, _ := resp.GetString("AsyncRequestId") + if len(asyncRequestId) > 0 { + return self.waitAsyncAction("IsolateDBInstance", id, asyncRequestId) + } + return cloudprovider.Wait(time.Second*10, time.Minute*5, func() (bool, error) { + instances, _, err := self.ListMySQLInstances([]string{id}, 0, 1) + if err != nil { + return false, errors.Wrapf(err, "ListMySQLInstances(%s)", id) + } + statusMap := map[int]string{0: "创建中", 1: "运行中", 4: "隔离中", 5: "已隔离"} + for _, rds := range instances { + status, _ := statusMap[rds.Status] + log.Debugf("instance %s(%s) status %d(%s)", rds.InstanceName, rds.InstanceId, rds.Status, status) + if rds.Status != 5 { + return false, nil + } + } + return true, nil + }) +} + +func (self *SRegion) CloseMySQLWanService(id string) error { + params := map[string]string{"InstanceId": id} + resp, err := self.cdbRequest("CloseWanService", params) + if err != nil { + return errors.Wrapf(err, "CloseWanService") + } + asyncRequestId, _ := resp.GetString("AsyncRequestId") + return self.waitAsyncAction("CloseWanService", id, asyncRequestId) +} + +func (self *SRegion) OpenMySQLWanService(id string) error { + params := map[string]string{"InstanceId": id} + resp, err := self.cdbRequest("OpenWanService", params) + if err != nil { + return errors.Wrapf(err, "OpenWanService") + } + asyncRequestId, _ := resp.GetString("AsyncRequestId") + return self.waitAsyncAction("OpenWanService", id, asyncRequestId) +} + +func (self *SRegion) InitMySQLDBInstances(ids []string, password string, parameters map[string]string, vport int) error { + params := map[string]string{"NewPassword": password} + for idx, id := range ids { + params[fmt.Sprintf("InstanceIds.%d", idx)] = id + } + i := 0 + for k, v := range parameters { + params[fmt.Sprintf("Parameters.%d.name", i)] = k + params[fmt.Sprintf("Parameters.%d.value", i)] = v + i++ + } + if vport >= 1024 && vport <= 65535 { + params["Vport"] = fmt.Sprintf("%d", vport) + } + resp, err := self.cdbRequest("InitDBInstances", params) + if err != nil { + return errors.Wrapf(err, "InitDBInstances") + } + asyncRequestIds := []string{} + err = resp.Unmarshal(&asyncRequestIds, "AsyncRequestIds") + if err != nil { + return errors.Wrapf(err, "resp.Unmarshal") + } + for idx, requestId := range asyncRequestIds { + err = self.waitAsyncAction("InitDBInstances", fmt.Sprintf("%d", idx), requestId) + if err != nil { + return err + } + } + return nil +} + +func (self *SRegion) UpgradeMySQLDBInstance(id string, memoryMb int, volumeGb int) error { + params := map[string]string{ + "InstanceId": id, + "Memory": fmt.Sprintf("%d", memoryMb), + "Volume": fmt.Sprintf("%d", volumeGb), + } + resp, err := self.cdbRequest("UpgradeDBInstance", params) + if err != nil { + return errors.Wrapf(err, "UpgradeDBInstance") + } + asyncRequestId, _ := resp.GetString("AsyncRequestId") + return self.waitAsyncAction("UpgradeDBInstance", id, asyncRequestId) +} + +func (self *SRegion) ModifyMySQLAutoRenewFlag(ids []string, autoRenew bool) error { + params := map[string]string{} + for idx, id := range ids { + params[fmt.Sprintf("InstanceIds.%d", idx)] = id + } + params["AutoRenew"] = "0" + if autoRenew { + params["AutoRenew"] = "1" + } + _, err := self.cdbRequest("ModifyAutoRenewFlag", params) + return err +} + +type SMaintenanceTime struct { + Monday []string + Tuesday []string + Wednesday []string + Thursday []string + Friday []string + Saturday []string + Sunday []string +} + +func (w SMaintenanceTime) String() string { + windows := []string{} + for k, v := range map[string][]string{ + "Monday": w.Monday, + "Tuesday": w.Tuesday, + "Wednesday": w.Wednesday, + "Thursday": w.Thursday, + "Friday": w.Friday, + "Saturday": w.Saturday, + "Sunday": w.Sunday, + } { + if len(v) > 0 { + windows = append(windows, fmt.Sprintf("%s: %s", k, strings.Join(v, " "))) + } + } + return strings.Join(windows, "\n") +} + +func (self *SRegion) DescribeMySQLTimeWindow(id string) (*SMaintenanceTime, error) { + params := map[string]string{"InstanceId": id} + resp, err := self.cdbRequest("DescribeTimeWindow", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeTimeWindow") + } + timeWindow := &SMaintenanceTime{} + err = resp.Unmarshal(timeWindow) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return timeWindow, nil +} + +type SDBSecgroup struct { + ProjectId int + CreateTime time.Time + SecurityGroupId string + SecurityGroupName string + SecurityGroupRemark string +} + +func (self *SRegion) DescribeMySQLDBSecurityGroups(instanceId string) ([]SDBSecgroup, error) { + params := map[string]string{ + "InstanceId": instanceId, + } + resp, err := self.cdbRequest("DescribeDBSecurityGroups", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeDBSecurityGroups") + } + result := []SDBSecgroup{} + err = resp.Unmarshal(&result, "Groups") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return result, nil +} + +func (self *SRegion) CreateMySQLDBInstance(opts *cloudprovider.SManagedDBInstanceCreateConfig) (*SMySQLInstance, error) { + params := map[string]string{ + "InstanceName": opts.Name, + "GoodsNum": "1", + "Memory": fmt.Sprintf("%d", opts.VmemSizeMb), + "Volume": fmt.Sprintf("%d", opts.DiskSizeGB), + "EngineVersion": opts.EngineVersion, + } + if len(opts.VpcId) > 0 { + params["UniqVpcId"] = opts.VpcId + } + if len(opts.NetworkId) > 0 { + params["UniqSubnetId"] = opts.NetworkId + } + if len(opts.ProjectId) > 0 { + params["ProjectId"] = opts.ProjectId + } + if opts.Port > 1024 && opts.Port < 65535 { + params["Port"] = fmt.Sprintf("%d", opts.Port) + } + if len(opts.Password) > 0 { + params["Password"] = opts.Password + } + for i, secId := range opts.SecgroupIds { + params[fmt.Sprintf("SecurityGroup.%d", i)] = secId + } + action := "CreateDBInstanceHour" + if opts.BillingCycle != nil { + params["Period"] = fmt.Sprintf("%d", opts.BillingCycle.GetMonths()) + params["AutoRenewFlag"] = "0" + if opts.BillingCycle.AutoRenew { + params["AutoRenewFlag"] = "1" + } + action = "CreateDBInstance" + } + if len(opts.Zone1) > 0 { + params["Zone"] = opts.Zone1 + } + params["DeployMode"] = "0" + switch opts.Category { + case api.QCLOUD_DBINSTANCE_CATEGORY_BASIC: + params["DeviceType"] = strings.ToUpper(opts.Category) + case api.QCLOUD_DBINSTANCE_CATEGORY_HA: + params["DeviceType"] = strings.ToUpper(opts.Category) + if len(opts.Zone2) > 0 { + params["SlaveZone"] = opts.Zone2 + } + case api.QCLOUD_DBINSTANCE_CATEGORY_FINANCE: + params["DeviceType"] = "HA" + params["ProtectMode"] = "2" + if len(opts.Zone2) > 0 { + params["SlaveZone"] = opts.Zone2 + } + if len(opts.Zone3) > 0 { + params["BackupZone"] = opts.Zone3 + } + } + if len(opts.Zone1) > 0 && len(opts.Zone2) > 0 && opts.Zone1 != opts.Zone2 { + params["DeployMode"] = "1" + } + params["ClientToken"] = utils.GenRequestId(20) + + i := 0 + for k, v := range opts.Tags { + params[fmt.Sprintf("ResourceTags.%d.TagKey", i)] = k + params[fmt.Sprintf("ResourceTags.%d.TagValue", i)] = v + i++ + } + + var create = func(action string, params map[string]string) (jsonutils.JSONObject, error) { + startTime := time.Now() + var resp jsonutils.JSONObject + var err error + for time.Now().Sub(startTime) < time.Minute*10 { + resp, err = self.cdbRequest(action, params) + if err != nil { + if strings.Contains(err.Error(), "OperationDenied.OtherOderInProcess") || strings.Contains(err.Error(), "Message=请求已经在处理中") { + time.Sleep(time.Second * 20) + continue + } + return nil, errors.Wrapf(err, "cdbRequest") + } + return resp, nil + } + return resp, err + } + + resp, err := create(action, params) + if err != nil { + return nil, errors.Wrapf(err, "cdbRequest") + } + instanceIds := []string{} + err = resp.Unmarshal(&instanceIds, "InstanceIds") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + if len(instanceIds) == 0 { + return nil, fmt.Errorf("%s not return InstanceIds", action) + } + err = cloudprovider.Wait(time.Second*10, time.Minute*20, func() (bool, error) { + instances, _, err := self.ListMySQLInstances(instanceIds, 0, 1) + if err != nil { + return false, errors.Wrapf(err, "ListMySQLInstances(%s)", instanceIds) + } + for _, rds := range instances { + log.Debugf("instance %s(%s) task status: %d", rds.InstanceName, rds.InstanceId, rds.TaskStatus) + if rds.TaskStatus == 1 { + return false, nil + } + } + return true, nil + }) + if err != nil { + return nil, errors.Wrapf(err, "cloudprovider.Wait After create") + } + return self.GetMySQLInstanceById(instanceIds[0]) +} + +func (self *SRegion) GetMySQLInstanceById(id string) (*SMySQLInstance, error) { + part, total, err := self.ListMySQLInstances([]string{id}, 0, 20) + if err != nil { + return nil, errors.Wrapf(err, "ListMySQLInstances") + } + if total > 1 { + return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "id: [%s]", id) + } + if total < 1 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) + } + part[0].region = self + return &part[0], nil +} + +func (self *SMySQLInstance) CreateDatabase(opts *cloudprovider.SDBInstanceDatabaseCreateConfig) error { + return cloudprovider.ErrNotSupported +} + +func (self *SMySQLInstance) CreateAccount(opts *cloudprovider.SDBInstanceAccountCreateConfig) error { + return self.region.CreateMySQLAccount(self.InstanceId, opts) +} + +func (self *SMySQLInstance) CreateIBackup(opts *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { + tables := map[string]string{} + for _, d := range opts.Databases { + tables[d] = "" + } + return self.region.CreateMySQLBackup(self.InstanceId, tables) +} + +func (self *SMySQLInstance) SetTags(tags map[string]string, replace bool) error { + return self.region.SetResourceTags("cdb", "instanceId", []string{self.InstanceId}, tags, replace) +} + +func (self *SRegion) GetIMySQLs() ([]cloudprovider.ICloudDBInstance, error) { + ret := []cloudprovider.ICloudDBInstance{} + mysql := []SMySQLInstance{} + for { + part, total, err := self.ListMySQLInstances([]string{}, len(mysql), 50) + if err != nil { + return nil, errors.Wrapf(err, "ListMySQLInstances") + } + mysql = append(mysql, part...) + if len(mysql) >= total { + break + } + } + for i := range mysql { + mysql[i].region = self + ret = append(ret, &mysql[i]) + } + return ret, nil +} diff --git a/pkg/multicloud/qcloud/rds_mysql_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_account.go similarity index 98% rename from pkg/multicloud/qcloud/rds_mysql_account.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_account.go index 98852f8968..e1230e4d0d 100644 --- a/pkg/multicloud/qcloud/rds_mysql_account.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_account.go @@ -23,14 +23,14 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SMySQLInstanceAccount struct { multicloud.SDBInstanceAccountBase - multicloud.QcloudTags + QcloudTags rds *SMySQLInstance Notes string diff --git a/pkg/multicloud/qcloud/rds_mysql_backup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_backup.go similarity index 97% rename from pkg/multicloud/qcloud/rds_mysql_backup.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_backup.go index 6aeb164ef8..25a7ad3f2d 100644 --- a/pkg/multicloud/qcloud/rds_mysql_backup.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_backup.go @@ -23,14 +23,14 @@ import ( "yunion.io/x/pkg/util/timeutils" "yunion.io/x/pkg/utils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SMySQLInstanceBackup struct { multicloud.SDBInstanceBackupBase - multicloud.QcloudTags + QcloudTags rds *SMySQLInstance Name string diff --git a/pkg/multicloud/qcloud/rds_mysql_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_database.go similarity index 94% rename from pkg/multicloud/qcloud/rds_mysql_database.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_database.go index 2393bbfb86..e449ffb2e6 100644 --- a/pkg/multicloud/qcloud/rds_mysql_database.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_database.go @@ -19,15 +19,15 @@ import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SMySQLInstanceDatabase struct { rds *SMySQLInstance multicloud.SResourceBase - multicloud.QcloudTags + QcloudTags CharacterSet string DatabaseName string diff --git a/pkg/multicloud/qcloud/rds_mysql_sku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_sku.go similarity index 99% rename from pkg/multicloud/qcloud/rds_mysql_sku.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_sku.go index d5ebef2ef7..2fa1c1aefe 100644 --- a/pkg/multicloud/qcloud/rds_mysql_sku.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_mysql_sku.go @@ -19,7 +19,7 @@ import ( "yunion.io/x/pkg/errors" "yunion.io/x/pkg/utils" - api "yunion.io/x/onecloud/pkg/apis/compute" + api "yunion.io/x/cloudmux/pkg/apis/compute" ) type SellTypeConfig struct { diff --git a/pkg/multicloud/qcloud/rds_postgre_sku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_postgre_sku.go similarity index 97% rename from pkg/multicloud/qcloud/rds_postgre_sku.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_postgre_sku.go index 02dcb4454f..db77c9d086 100644 --- a/pkg/multicloud/qcloud/rds_postgre_sku.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_postgre_sku.go @@ -17,7 +17,7 @@ package qcloud import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" + api "yunion.io/x/cloudmux/pkg/apis/compute" ) type SpecItemInfoList struct { diff --git a/pkg/multicloud/qcloud/rds_sqlserver_sku.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_sqlserver_sku.go similarity index 97% rename from pkg/multicloud/qcloud/rds_sqlserver_sku.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_sqlserver_sku.go index a3392704a2..06d1de9445 100644 --- a/pkg/multicloud/qcloud/rds_sqlserver_sku.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_sqlserver_sku.go @@ -17,7 +17,7 @@ package qcloud import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" + api "yunion.io/x/cloudmux/pkg/apis/compute" ) type SqlServerSpecInfoList struct { diff --git a/pkg/multicloud/qcloud/rds_tdsql.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_tdsql.go similarity index 98% rename from pkg/multicloud/qcloud/rds_tdsql.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_tdsql.go index f0e4b33ceb..7b3ab77766 100644 --- a/pkg/multicloud/qcloud/rds_tdsql.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/rds_tdsql.go @@ -22,16 +22,16 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/pkg/errors" - billing_api "yunion.io/x/onecloud/pkg/apis/billing" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type STDSQL struct { multicloud.SDBInstanceBase // multicloud.SBillingBase - multicloud.QcloudTags + QcloudTags region *SRegion AppId int `json:"AppId"` diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/region.go new file mode 100644 index 0000000000..76ab76a22e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/region.go @@ -0,0 +1,1244 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + sdkerrors "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" + "github.com/tencentyun/cos-go-sdk-v5" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + multicloud.SRegion + + client *SQcloudClient + + izones []cloudprovider.ICloudZone + ivpcs []cloudprovider.ICloudVpc + + storageCache *SStoragecache + + instanceTypes []SInstanceType + + Region string + RegionName string + RegionState string + + Latitude float64 + Longitude float64 + fetchLocation bool +} + +func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + lbs, err := self.GetLoadbalancers(nil) + if err != nil { + return nil, err + } + + ilbs := make([]cloudprovider.ICloudLoadbalancer, len(lbs)) + for i := range lbs { + lbs[i].region = self + ilbs[i] = &lbs[i] + } + + return ilbs, nil +} + +// 腾讯云不支持acl +func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { + return []cloudprovider.ICloudLoadbalancerAcl{}, nil +} + +func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + certs, err := self.GetCertificates("", "", "") + if err != nil { + return nil, errors.Wrap(err, "GetCertificates") + } + + icerts := make([]cloudprovider.ICloudLoadbalancerCertificate, len(certs)) + for i := range certs { + icerts[i] = &certs[i] + } + + return icerts, nil +} + +func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + cert, err := self.GetCertificate(certId) + if err != nil { + return nil, errors.Wrap(err, "GetCertificate") + } + + return cert, nil +} + +func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { + lbs, err := self.GetLoadbalancers([]string{loadbalancerId}) + if err != nil { + return nil, err + } + + if len(lbs) == 1 { + lbs[0].region = self + return &lbs[0], nil + } else if len(lbs) == 0 { + return nil, cloudprovider.ErrNotFound + } else { + log.Debugf("GetILoadBalancerById %s %d loadbalancer found", loadbalancerId, len(lbs)) + return nil, cloudprovider.ErrNotFound + } +} + +func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, nil +} + +// https://cloud.tencent.com/document/api/214/30692 +// todo: 1. 支持跨地域绑定负载均衡 及 https://cloud.tencent.com/document/product/214/12014 +// todo: 2. 支持指定Project。 ProjectId可以通过 DescribeProject 接口获取。不填则属于默认项目。 +func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + params := map[string]string{ + "LoadBalancerName": loadbalancer.Name, + "VpcId": loadbalancer.VpcID, + } + + LoadBalancerType := "INTERNAL" + if loadbalancer.AddressType == api.LB_ADDR_TYPE_INTERNET { + LoadBalancerType = "OPEN" + switch loadbalancer.ChargeType { + case api.LB_CHARGE_TYPE_BY_BANDWIDTH: + pkgs, _, err := self.GetBandwidthPackages([]string{}, 0, 50) + if err != nil { + return nil, errors.Wrapf(err, "GetBandwidthPackages") + } + bps := loadbalancer.EgressMbps + if bps == 0 { + bps = 200 + } + if len(pkgs) > 0 { + pkgId := pkgs[0].BandwidthPackageId + for _, pkg := range pkgs { + if len(pkg.ResourceSet) < 100 { + pkgId = pkg.BandwidthPackageId + break + } + } + params["BandwidthPackageId"] = pkgId + params["InternetAccessible.InternetChargeType"] = "BANDWIDTH_PACKAGE" + params["InternetAccessible.InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bps) + } else { + params["InternetAccessible.InternetChargeType"] = "BANDWIDTH_POSTPAID_BY_HOUR" + params["InternetAccessible.InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bps) + } + default: + bps := loadbalancer.EgressMbps + if bps == 0 { + bps = 200 + } + params["InternetAccessible.InternetChargeType"] = "TRAFFIC_POSTPAID_BY_HOUR" + params["InternetAccessible.InternetMaxBandwidthOut"] = fmt.Sprintf("%d", bps) + + } + } + + params["LoadBalancerType"] = LoadBalancerType + + if len(loadbalancer.ProjectId) > 0 { + params["ProjectId"] = loadbalancer.ProjectId + } + + if loadbalancer.AddressType != api.LB_ADDR_TYPE_INTERNET { + params["SubnetId"] = loadbalancer.NetworkIDs[0] + } else { + // 公网类型ELB可支持多可用区 + if len(loadbalancer.ZoneID) > 0 { + if len(loadbalancer.SlaveZoneID) > 0 { + params["MasterZoneId"] = loadbalancer.ZoneID + } else { + params["ZoneId"] = loadbalancer.ZoneID + } + } + } + i := 0 + for k, v := range loadbalancer.Tags { + params[fmt.Sprintf("Tags.%d.TagKey", i)] = k + params[fmt.Sprintf("Tags.%d.TagValue", i)] = v + i++ + } + + resp, err := func() (jsonutils.JSONObject, error) { + _resp, err := self.clbRequest("CreateLoadBalancer", params) + if err != nil { + // 兼容不支持指定zone的账号 + if e, ok := err.(*sdkerrors.TencentCloudSDKError); ok && e.Code == "InvalidParameterValue" { + delete(params, "ZoneId") + delete(params, "MasterZoneId") + return self.clbRequest("CreateLoadBalancer", params) + } + } + return _resp, err + }() + if err != nil { + return nil, err + } + + requestId, err := resp.GetString("RequestId") + if err != nil { + return nil, err + } + + lbs, err := resp.GetArray("LoadBalancerIds") + if err != nil || len(lbs) != 1 { + log.Debugf("CreateILoadBalancer %s", resp.String()) + return nil, err + } + + err = self.WaitLBTaskSuccess(requestId, 5*time.Second, 60*time.Second) + if err != nil { + return nil, err + } + + lbId, err := lbs[0].GetString() + if err != nil { + return nil, err + } + + return self.GetLoadbalancer(lbId) +} + +func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +// todo:目前onecloud端只能指定服务器端证书。需要兼容客户端证书? +// todo:支持指定Project。 +// todo: 已过期的证书不能上传也不能关联资源 +func (self *SRegion) CreateILoadBalancerCertificate(input *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + certId, err := self.CreateCertificate("", input.Certificate, input.PrivateKey, "SVR", input.Name) + if err != nil { + return nil, err + } + + cert, err := self.GetCertificate(certId) + if err != nil { + log.Debugf("GetCertificate %s failed", certId) + return nil, err + } + + return cert, nil +} + +func (self *SRegion) GetId() string { + return self.Region +} + +func (self *SRegion) GetName() string { + return self.RegionName +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + en := self.RegionName + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_QCLOUD, self.Region) +} + +func (self *SRegion) IsEmulated() bool { + return false +} + +func (self *SRegion) GetProvider() string { + return CLOUD_PROVIDER_QCLOUD +} + +func (self *SRegion) GetCloudEnv() string { + return "" +} + +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + params := make(map[string]string) + if len(opts.CIDR) > 0 { + params["CidrBlock"] = opts.CIDR + } + if len(opts.NAME) > 0 { + params["VpcName"] = opts.NAME + } + body, err := self.vpcRequest("CreateVpc", params) + if err != nil { + return nil, err + } + vpcId, err := body.GetString("Vpc", "VpcId") + if err != nil { + return nil, err + } + err = self.fetchInfrastructure() + if err != nil { + return nil, err + } + return self.GetIVpcById(vpcId) +} + +func (self *SRegion) GetCosClient(bucket *SBucket) (*cos.Client, error) { + return self.client.getCosClient(bucket) +} + +func (self *SRegion) GetClient() *SQcloudClient { + return self.client +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + return self.GetInstance(id) +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return self.GetDisk(id) +} + +func (self *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { + if len(eipId) == 0 { + return nil, cloudprovider.ErrNotFound + } + eips, total, err := self.GetEips(eipId, "", 0, 1) + 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) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, total, err := self.GetEips("", "", 0, 50) + if err != nil { + return nil, err + } + for len(eips) < total { + var parts []SEipAddress + parts, total, err = self.GetEips("", "", len(eips), 50) + if err != nil { + return nil, err + } + eips = append(eips, parts...) + } + ret := make([]cloudprovider.ICloudEIP, len(eips)) + for i := 0; i < len(eips); i++ { + ret[i] = &eips[i] + } + return ret, nil +} + +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 errors.Cause(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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + if storageCache.GetGlobalId() == id { + return self.storageCache, nil + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + return []cloudprovider.ICloudStoragecache{storageCache}, nil +} + +func (self *SRegion) updateInstance(instId string, name, desc, passwd, hostname string) error { + params := make(map[string]string) + params["InstanceId"] = instId + if len(name) > 0 { + params["InstanceName"] = name + } + if len(desc) > 0 { + params["Description"] = desc + } + if len(passwd) > 0 { + params["Password"] = passwd + } + if len(hostname) > 0 { + params["HostName"] = hostname + } + _, err := self.cvmRequest("ModifyInstanceAttribute", params, true) + return err +} + +func (self *SRegion) UpdateInstancePassword(instId string, passwd string) error { + return self.updateInstance(instId, "", "", passwd, "") +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + ivpcs, err := self.GetIVpcs() + if err != nil { + return nil, err + } + for i := 0; i < len(ivpcs); i++ { + if ivpcs[i].GetGlobalId() == id { + return ivpcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +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.Zone == id { + return zone, nil + } + } + return nil, fmt.Errorf("no such zone %s", id) +} + +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) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if self.izones == nil { + var err error + err = self.fetchInfrastructure() + if err != nil { + return nil, err + } + } + return self.izones, nil +} + +func (self *SRegion) _fetchZones() error { + params := make(map[string]string) + zones := make([]SZone, 0) + body, err := self.cvmRequest("DescribeZones", params, true) + if err != nil { + return err + } + err = body.Unmarshal(&zones, "ZoneSet") + if err != nil { + return err + } + self.izones = make([]cloudprovider.ICloudZone, len(zones)) + for i := 0; i < len(zones); i++ { + zones[i].region = self + self.izones[i] = &zones[i] + } + return nil +} + +func (self *SRegion) fetchInfrastructure() error { + err := self._fetchZones() + if err != nil { + return err + } + err = self.fetchIVpcs() + if 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) DeleteVpc(vpcId string) error { + params := make(map[string]string) + params["VpcId"] = vpcId + + _, err := self.vpcRequest("DeleteVpc", params) + return err +} + +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.ErrDuplicateId + } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } + vpcs[0].region = self + return &vpcs[0], nil +} + +func (self *SRegion) fetchIVpcs() error { + vpcs := make([]SVpc, 0) + for { + part, total, err := self.GetVpcs(nil, len(vpcs), 50) + if err != nil { + return err + } + vpcs = append(vpcs, part...) + if len(vpcs) >= total { + break + } + } + self.ivpcs = make([]cloudprovider.ICloudVpc, len(vpcs)) + for i := 0; i < len(vpcs); i += 1 { + vpcs[i].region = self + self.ivpcs[i] = &vpcs[i] + } + return nil +} + +func (self *SRegion) GetVpcs(vpcIds []string, offset int, limit int) ([]SVpc, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + if vpcIds != nil && len(vpcIds) > 0 { + for index, vpcId := range vpcIds { + params[fmt.Sprintf("VpcIds.%d", index)] = vpcId + } + } + body, err := self.vpcRequest("DescribeVpcs", params) + if err != nil { + return nil, 0, err + } + vpcs := make([]SVpc, 0) + err = body.Unmarshal(&vpcs, "VpcSet") + if err != nil { + log.Errorf("Unmarshal vpc fail %s", err) + return nil, 0, err + } + total, _ := body.Float("TotalCount") + return vpcs, int(total), nil +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + if info, ok := LatitudeAndLongitude[self.Region]; ok { + return info + } + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetStatus() string { + if self.RegionState == "AVAILABLE" { + return api.CLOUD_REGION_STATUS_INSERVER + } + return api.CLOUD_REGION_STATUS_OUTOFSERVICE +} + +func (self *SRegion) Refresh() error { + // do nothing + return nil +} + +// 容器 +func (self *SRegion) tkeRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.tkeRequest(apiName, params) +} + +func (self *SRegion) vpcRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.vpcRequest(apiName, params) +} + +func (self *SRegion) auditRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.auditRequest(apiName, params) +} + +func (self *SRegion) vpc2017Request(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.vpc2017Request(apiName, params) +} + +func (self *SRegion) cvmRequest(apiName string, params map[string]string, retry bool) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.jsonRequest(apiName, params, retry) +} + +func (self *SRegion) accountRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + return self.client.accountRequestRequest(apiName, params) +} + +func (self *SRegion) cbsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.cbsRequest(apiName, params) +} + +func (self *SRegion) clbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.clbRequest(apiName, params) +} + +func (self *SRegion) lbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.lbRequest(apiName, params) +} + +func (self *SRegion) cdbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.cdbRequest(apiName, params) +} + +func (self *SRegion) mariadbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.mariadbRequest(apiName, params) +} + +func (self *SRegion) postgresRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.postgresRequest(apiName, params) +} + +func (self *SRegion) sqlserverRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.sqlserverRequest(apiName, params) +} + +// deprecated +func (self *SRegion) wssRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + return self.client.wssRequest(apiName, params) +} + +func (self *SRegion) sslRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + return self.client.sslRequest(apiName, params) +} + +func (self *SRegion) kafkaRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.kafkaRequest(apiName, params) +} + +func (self *SRegion) redisRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.redisRequest(apiName, params) +} + +func (self *SRegion) dcdbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.dcdbRequest(apiName, params) +} + +func (self *SRegion) mongodbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.mongodbRequest(apiName, params) +} + +// Elasticsearch +func (self *SRegion) esRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.esRequest(apiName, params) +} + +func (self *SRegion) memcachedRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + params["Region"] = self.Region + return self.client.memcachedRequest(apiName, params) +} + +func (self *SRegion) GetNetworks(ids []string, vpcId string, offset int, limit int) ([]SNetwork, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + base := 0 + if ids != nil && len(ids) > 0 { + for index, networkId := range ids { + params[fmt.Sprintf("SubnetIds.%d", index)] = networkId + } + base += len(ids) + } + if len(vpcId) > 0 { + params["Filters.0.Name"] = "vpc-id" + params["Filters.0.Values.0"] = vpcId + } + + body, err := self.vpcRequest("DescribeSubnets", params) + if err != nil { + log.Errorf("DescribeSubnets fail %s", err) + return nil, 0, err + } + + networks := make([]SNetwork, 0) + err = body.Unmarshal(&networks, "SubnetSet") + if err != nil { + log.Errorf("Unmarshal network fail %s", err) + return nil, 0, err + } + total, _ := body.Float("TotalCount") + return networks, int(total), nil +} + +func (self *SRegion) GetNetwork(networkId string) (*SNetwork, error) { + networks, total, err := self.GetNetworks([]string{networkId}, "", 0, 1) + if err != nil { + return nil, err + } + if total > 1 { + return nil, cloudprovider.ErrDuplicateId + } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } + return &networks[0], nil +} + +func (self *SRegion) getStoragecache() *SStoragecache { + if self.storageCache == nil { + self.storageCache = &SStoragecache{region: self} + } + return self.storageCache +} + +func (self *SRegion) GetMatchInstanceTypes(cpu int, memMB int, gpu int, zoneId string) ([]SInstanceType, error) { + if self.instanceTypes == nil { + types, err := self.GetInstanceTypes() + if err != nil { + log.Errorf("GetInstanceTypes %s", err) + return nil, err + } + self.instanceTypes = types + } + + var available []string + if len(zoneId) > 0 { + zone, err := self.getZoneById(zoneId) + if err != nil { + return nil, err + } + available = zone.getAvaliableInstanceTypes() + } + ret := make([]SInstanceType, 0) + for _, t := range self.instanceTypes { + if t.CPU == cpu && memMB == t.memoryMB() && gpu == t.GPU { + if available == nil || utils.IsInStringArray(t.InstanceType, available) { + ret = append(ret, t) + } + } + } + return ret, nil +} + +func (self *SRegion) CreateInstanceSimple(name string, imgId string, cpu int, memGB int, storageType string, dataDiskSizesGB []int, networkId string, passwd string, publicKey string, secgroup string, tags map[string]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.Zone) + net := z.getNetworkById(networkId) + if net != nil { + desc := &cloudprovider.SManagedVMCreateConfig{ + Name: name, + ExternalImageId: imgId, + SysDisk: cloudprovider.SDiskInfo{SizeGB: 0, StorageType: storageType}, + Cpu: cpu, + MemoryMB: memGB * 1024, + ExternalNetworkId: networkId, + Password: passwd, + DataDisks: []cloudprovider.SDiskInfo{}, + PublicKey: publicKey, + + Tags: tags, + + ExternalSecgroupId: secgroup, + } + for _, sizeGB := range dataDiskSizesGB { + desc.DataDisks = append(desc.DataDisks, cloudprovider.SDiskInfo{SizeGB: sizeGB, StorageType: storageType}) + } + inst, err := z.getHost().CreateVM(desc) + if err != nil { + return nil, err + } + return inst.(*SInstance), nil + } + } + return nil, fmt.Errorf("cannot find network %s", networkId) +} + +func (self *SRegion) instanceOperation(instanceId string, opname string, extra map[string]string, retry bool) error { + params := make(map[string]string) + params["InstanceIds.0"] = instanceId + if extra != nil && len(extra) > 0 { + for k, v := range extra { + params[k] = v + } + } + _, err := self.cvmRequest(opname, params, retry) + return err +} + +func (self *SRegion) GetInstanceVNCUrl(instanceId string) (string, error) { + params := make(map[string]string) + params["InstanceId"] = instanceId + body, err := self.cvmRequest("DescribeInstanceVncUrl", params, true) + if err != nil { + return "", err + } + return body.GetString("InstanceVncUrl") +} + +func (self *SRegion) GetInstanceStatus(instanceId string) (string, error) { + instance, err := self.GetInstance(instanceId) + if err != nil { + return "", err + } + return instance.InstanceState, nil +} + +func (self *SRegion) QueryAccountBalance() (*SAccountBalance, error) { + return self.client.QueryAccountBalance() +} + +func (self *SRegion) getCosEndpoint() string { + return fmt.Sprintf("cos.%s.myqcloud.com", self.GetId()) +} + +func (self *SRegion) getCosWebsiteEndpoint() string { + return fmt.Sprintf("cos-website.%s.myqcloud.com", self.GetId()) +} + +func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + iBuckets, err := region.client.getIBuckets() + if err != nil { + return nil, err + } + ret := make([]cloudprovider.ICloudBucket, 0) + for i := range iBuckets { + bucket := iBuckets[i].(*SBucket) + if bucket.region.GetId() != region.GetId() { + continue + } + ret = append(ret, iBuckets[i]) + } + return ret, nil +} + +func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { + bucket := &SBucket{ + region: region, + Name: name, + } + coscli, err := region.GetCosClient(bucket) + if err != nil { + return errors.Wrap(err, "GetCosClient") + } + opts := &cos.BucketPutOptions{} + if len(aclStr) > 0 { + if utils.IsInStringArray(aclStr, []string{ + "private", "public-read", "public-read-write", "authenticated-read", + }) { + opts.XCosACL = aclStr + } else { + return errors.Error("invalid acl") + } + } + _, err = coscli.Bucket.Put(context.Background(), opts) + if err != nil { + return errors.Wrap(err, "coscli.Bucket.Put") + } + region.client.invalidateIBuckets() + return nil +} + +func cosHttpCode(err error) int { + if httpErr, ok := err.(*cos.ErrorResponse); ok { + return httpErr.Response.StatusCode + } + return -1 +} + +func (region *SRegion) DeleteIBucket(name string) error { + bucket := &SBucket{ + region: region, + Name: name, + } + coscli, err := region.GetCosClient(bucket) + if err != nil { + return errors.Wrap(err, "GetCosClient") + } + _, err = coscli.Bucket.Delete(context.Background()) + if err != nil { + if cosHttpCode(err) == 404 { + return nil + } + return errors.Wrap(err, "DeleteBucket") + } + return nil +} + +func (region *SRegion) IBucketExist(name string) (bool, error) { + bucket := &SBucket{ + region: region, + Name: name, + } + coscli, err := region.GetCosClient(bucket) + if err != nil { + return false, errors.Wrap(err, "GetCosClient") + } + _, err = coscli.Bucket.Head(context.Background()) + if err != nil { + if cosHttpCode(err) == 404 { + return false, nil + } + return false, errors.Wrap(err, "BucketExists") + } + return true, nil +} + +func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { + return cloudprovider.GetIBucketById(region, name) +} + +func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { + return region.GetIBucketById(name) +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, total, err := self.GetSecurityGroups([]string{secgroupId}, "", "", 0, 1) + if err != nil { + return nil, errors.Wrapf(err, "GetSecurityGroups(%s)", secgroupId) + } + if total < 1 { + return nil, cloudprovider.ErrNotFound + } + secgroups[0].region = self + return &secgroups[0], nil +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, total, err := self.GetSecurityGroups([]string{}, opts.VpcId, opts.Name, 0, 0) + if err != nil { + return nil, err + } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } + if total > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return &secgroups[0], nil +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return self.CreateSecurityGroup(conf.Name, conf.ProjectId, conf.Desc) +} + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} + +func (region *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { + caches, err := region.GetCloudElasticcaches("") + if err != nil { + return nil, errors.Wrap(err, "GetCloudElasticcaches") + } + + ret := []cloudprovider.ICloudElasticcache{} + for i := range caches { + cache := caches[i] + cache.region = region + ret = append(ret, &cache) + } + + mems := []SMemcached{} + offset := 0 + for { + part, total, err := region.GetMemcaches(nil, 100, offset) + if err != nil { + return nil, errors.Wrapf(err, "GetMemcaches") + } + mems = append(mems, part...) + if len(mems) >= total { + break + } + offset += len(part) + } + for i := range mems { + mems[i].region = region + ret = append(ret, &mems[i]) + } + + return ret, nil +} + +func (region *SRegion) GetIElasticcacheById(id string) (cloudprovider.ICloudElasticcache, error) { + if strings.HasPrefix(id, "cmem-") { + memcacheds, _, err := region.GetMemcaches([]string{id}, 1, 0) + if err != nil { + return nil, errors.Wrapf(err, "GetMemcaches") + } + for i := range memcacheds { + if memcacheds[i].GetGlobalId() == id { + memcacheds[i].region = region + return &memcacheds[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) + } + caches, err := region.GetCloudElasticcaches(id) + if err != nil { + return nil, errors.Wrap(err, "GetCloudElasticcaches") + } + + for i := range caches { + if caches[i].GetGlobalId() == id { + caches[i].region = region + return &caches[i], nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +// DescribeProductInfo 可以查询在售可用区信息 +// https://cloud.tencent.com/document/product/239/20026 +func (r *SRegion) CreateIElasticcaches(ec *cloudprovider.SCloudElasticCacheInput) (cloudprovider.ICloudElasticcache, error) { + params := map[string]string{} + if len(ec.ZoneIds) == 0 { + return nil, fmt.Errorf("CreateIElasticcaches zone id should not be empty.") + } + + zoneId, ok := zoneIdMaps[ec.ZoneIds[0]] + if !ok { + return nil, fmt.Errorf("can't convert zone %s to integer id", ec.ZoneIds[0]) + } + + if len(ec.ZoneIds) > 1 { + for i := range ec.ZoneIds { + if i == 0 { + params[fmt.Sprintf("NodeSet.%d.NodeType", i)] = "0" + params[fmt.Sprintf("NodeSet.%d.ZoneId", i)] = fmt.Sprintf("%d", zoneId) + } else { + _z, ok := zoneIdMaps[ec.ZoneIds[i]] + if !ok { + return nil, fmt.Errorf("can't convert zone %s to integer id", ec.ZoneIds[i]) + } + params[fmt.Sprintf("NodeSet.%d.NodeType", i)] = "1" + params[fmt.Sprintf("NodeSet.%d.ZoneId", i)] = fmt.Sprintf("%d", _z) + } + } + } + + spec, err := parseLocalInstanceSpec(ec.InstanceType) + if err != nil { + return nil, errors.Wrap(err, "parseLocalInstanceSpec") + } + + params["InstanceName"] = ec.InstanceName + if len(ec.ProjectId) > 0 { + params["ProjectId"] = ec.ProjectId + } + params["ZoneId"] = fmt.Sprintf("%d", zoneId) + params["TypeId"] = spec.TypeId + params["MemSize"] = strconv.Itoa(spec.MemSizeMB) + params["RedisShardNum"] = spec.RedisShardNum + params["RedisReplicasNum"] = spec.RedisReplicasNum + params["GoodsNum"] = "1" + if ec.NetworkType == api.LB_NETWORK_TYPE_VPC { + params["VpcId"] = ec.VpcId + params["SubnetId"] = ec.NetworkId + + for i := range ec.SecurityGroupIds { + params[fmt.Sprintf("SecurityGroupIdList.%d", i)] = ec.SecurityGroupIds[i] + } + } + params["Period"] = "1" + params["BillingMode"] = "0" + if ec.BillingCycle != nil && ec.BillingCycle.GetMonths() >= 1 { + params["Period"] = strconv.Itoa(ec.BillingCycle.GetMonths()) + params["BillingMode"] = "1" + // 自动续费 + if ec.BillingCycle.AutoRenew { + params["AutoRenew"] = "1" + } + } + + if len(ec.Password) > 0 { + params["NoAuth"] = "false" + params["Password"] = ec.Password + } else { + params["NoAuth"] = "true" + } + + resp, err := r.redisRequest("CreateInstances", params) + if err != nil { + return nil, errors.Wrap(err, "CreateInstances") + } + + instanceId := "" + if resp.Contains("InstanceIds") { + ids := []string{} + if err := resp.Unmarshal(&ids, "InstanceIds"); err != nil { + log.Debugf("Unmarshal.InstanceIds %s", resp) + } else { + if len(ids) > 0 { + instanceId = ids[0] + } + } + } + + // try to fetch instance id from deal id + if len(instanceId) == 0 { + dealId, err := resp.GetString("DealId") + if err != nil { + return nil, errors.Wrap(err, "dealId") + } + + // maybe is a dealId not a instance ID. + if strings.HasPrefix(dealId, "crs-") { + instanceId = dealId + } else { + err = cloudprovider.Wait(5*time.Second, 900*time.Second, func() (bool, error) { + _realInstanceId, err := r.GetElasticcacheIdByDeal(dealId) + if err != nil { + return false, nil + } + + instanceId = _realInstanceId + return true, nil + }) + if err != nil { + return nil, errors.Wrap(err, "Wait.GetElasticcacheIdByDeal") + } + } + } + + err = r.SetResourceTags("redis", "instance", []string{instanceId}, ec.Tags, false) + if err != nil { + log.Errorf("SetResourceTags(redis:%s,error:%s)", instanceId, err) + } + return r.GetIElasticcacheById(instanceId) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/route_table.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/route_table.go new file mode 100644 index 0000000000..4d0168a137 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/route_table.go @@ -0,0 +1,245 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRouteSet struct { + multicloud.SResourceBase + QcloudTags + RouteID int `json:"RouteId"` + RouteItemID string `json:"RouteItemId"` + DestinationIpv6CidrBlock string `json:"DestinationIpv6CidrBlock,omitempty"` + GatewayType string `json:"GatewayType"` + GatewayID string `json:"GatewayId"` + RouteDescription string `json:"RouteDescription"` + DestinationCidrBlock string `json:"DestinationCidrBlock,omitempty"` + RouteType string `json:"RouteType"` +} +type SRouteTableSet struct { + multicloud.SResourceBase + QcloudTags + vpc *SVpc + VpcID string `json:"VpcId"` + RouteTableID string `json:"RouteTableId"` + RouteTableName string `json:"RouteTableName"` + AssociationSet []RouteTableAssociationSet `json:"AssociationSet"` + RouteSet []SRouteSet `json:"RouteSet"` + Main bool `json:"Main"` + CreatedTime string `json:"CreatedTime"` +} + +type RouteTableAssociationSet struct { + SubnetId string + RouteTableId string +} + +func (self *SRegion) DescribeRouteTables(vpcId string, routetables []string, offset int, limit int) ([]SRouteTableSet, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + + for i := range routetables { + params[fmt.Sprintf("RouteTableIds.%d", i)] = routetables[i] + } + + if len(vpcId) > 0 { + params["Filters.0.Name"] = "vpc-id" + params["Filters.0.Values.0"] = vpcId + } + body, err := self.vpcRequest("DescribeRouteTables", params) + if err != nil { + return nil, 0, errors.Wrapf(err, ` self.vpcRequest("DescribeRouteTables", %s)`, jsonutils.Marshal(params)) + } + routeTables := make([]SRouteTableSet, 0) + err = body.Unmarshal(&routeTables, "RouteTableSet") + if err != nil { + return nil, 0, errors.Wrapf(err, "body.Unmarshal(RouteTableSet)[%s]", body.String()) + } + total, _ := body.Float("TotalCount") + return routeTables, int(total), nil +} + +func (self *SRegion) GetAllRouteTables(vpcId string, routetables []string) ([]SRouteTableSet, error) { + routeTables := make([]SRouteTableSet, 0) + for { + part, total, err := self.DescribeRouteTables(vpcId, routetables, len(routeTables), 50) + if err != nil { + return nil, errors.Wrap(err, "self.DescribeRouteTables(vpcId, routetables, offset, limit)") + } + routeTables = append(routeTables, part...) + if len(routeTables) >= total { + break + } + } + return routeTables, nil +} + +func (self *SRouteTableSet) GetId() string { + return self.RouteTableID +} + +func (self *SRouteTableSet) GetName() string { + return self.RouteTableName +} + +func (self *SRouteTableSet) GetGlobalId() string { + return self.RouteTableID +} + +func (self *SRouteTableSet) GetStatus() string { + return api.ROUTE_TABLE_AVAILABLE +} + +func (self *SRouteTableSet) Refresh() error { + return nil +} + +func (self *SRouteTableSet) IsEmulated() bool { + return false +} + +func (self *SRouteTableSet) GetAssociations() []cloudprovider.RouteTableAssociation { + result := []cloudprovider.RouteTableAssociation{} + for i := range self.AssociationSet { + association := cloudprovider.RouteTableAssociation{ + AssociationType: cloudprovider.RouteTableAssociaToSubnet, + AssociatedResourceId: self.AssociationSet[i].SubnetId, + } + result = append(result, association) + } + return result +} + +func (self *SRouteTableSet) GetDescription() string { + return "" +} + +func (self *SRouteTableSet) GetRegionId() string { + return self.vpc.GetRegion().GetId() +} + +func (self *SRouteTableSet) GetVpcId() string { + return self.vpc.GetId() +} + +func (self *SRouteTableSet) GetType() cloudprovider.RouteTableType { + if self.Main { + return cloudprovider.RouteTableTypeSystem + } + return cloudprovider.RouteTableTypeCustom +} + +func (self *SRouteTableSet) GetIRoutes() ([]cloudprovider.ICloudRoute, error) { + result := []cloudprovider.ICloudRoute{} + for i := range self.RouteSet { + result = append(result, &self.RouteSet[i]) + } + return result, nil +} + +func (self *SRouteTableSet) CreateRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteTableSet) UpdateRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteTableSet) RemoveRoute(route cloudprovider.RouteSet) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRouteSet) GetId() string { + return self.RouteItemID +} + +func (self *SRouteSet) GetName() string { + return "" +} + +func (self *SRouteSet) GetGlobalId() string { + return self.RouteItemID +} + +func (self *SRouteSet) GetStatus() string { + return api.ROUTE_ENTRY_STATUS_AVAILIABLE +} + +func (self *SRouteSet) Refresh() error { + return nil +} + +func (self *SRouteSet) IsEmulated() bool { + return false +} + +func (self *SRouteSet) GetType() string { + switch self.RouteType { + case "USER": + return api.ROUTE_ENTRY_TYPE_CUSTOM + case "NETD": + return api.ROUTE_ENTRY_TYPE_SYSTEM + case "CCN": + return api.ROUTE_ENTRY_TYPE_PROPAGATE + default: + return api.ROUTE_ENTRY_TYPE_SYSTEM + } +} + +func (self *SRouteSet) GetCidr() string { + return self.DestinationCidrBlock +} + +func (self *SRouteSet) GetNextHopType() string { + switch self.GatewayType { + case "CVM": + return api.NEXT_HOP_TYPE_INSTANCE + case "VPN": + return api.NEXT_HOP_TYPE_VPN + case "DIRECTCONNECT": + return api.NEXT_HOP_TYPE_DIRECTCONNECTION + case "PEERCONNECTION": + return api.NEXT_HOP_TYPE_VPCPEERING + case "SSLVPN": + return api.NEXT_HOP_TYPE_VPN + case "NAT": + return api.NEXT_HOP_TYPE_NAT + case "NORMAL_CVM": + return api.NEXT_HOP_TYPE_INSTANCE + case "EIP": + return api.NEXT_HOP_TYPE_EIP + case "CCN": + return api.NEXT_HOP_TYPE_INTERVPCNETWORK + default: + return "" + } +} + +func (self *SRouteSet) GetNextHop() string { + return self.GatewayID +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/saml_provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/saml_provider.go new file mode 100644 index 0000000000..16ab9e6b11 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/saml_provider.go @@ -0,0 +1,184 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "encoding/base64" + "fmt" + "time" + "unicode" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/cloudid" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/samlutils" +) + +type SAMLProvider struct { + multicloud.SResourceBase + QcloudTags + client *SQcloudClient + + Name string + Description string + CreateTime time.Time + ModifyTime time.Time + SAMLMetadata string +} + +func (self *SAMLProvider) GetId() string { + return self.Name +} + +func (self *SAMLProvider) GetGlobalId() string { + return self.Name +} + +func (self *SAMLProvider) GetName() string { + return self.Name +} + +func (self *SAMLProvider) GetStatus() string { + return api.SAML_PROVIDER_STATUS_AVAILABLE +} + +func (self *SAMLProvider) Delete() error { + return self.client.DeleteSAMLProvider(self.Name) +} + +func (self *SAMLProvider) GetAuthUrl() string { + return fmt.Sprintf("https://cloud.tencent.com/login/forwardIdp/%s/%s", self.client.ownerName, self.Name) +} + +func (self *SAMLProvider) GetMetadataDocument() (*samlutils.EntityDescriptor, error) { + provider, err := self.client.GetSAMLProvider(self.Name) + if err != nil { + return nil, errors.Wrapf(err, "GetSAMLProvider(%s)", self.Name) + } + metadata, err := base64.StdEncoding.DecodeString(provider.SAMLMetadata) + if err != nil { + return nil, errors.Wrapf(err, "decode metadata") + } + ret, err := samlutils.ParseMetadata(metadata) + if err != nil { + return nil, errors.Wrapf(err, "ParseMetadata") + } + return &ret, nil +} + +func (self *SAMLProvider) UpdateMetadata(metadata samlutils.EntityDescriptor) error { + return self.client.UpdateSAMLProvider(self.Name, metadata.String(), "") +} + +func (self *SQcloudClient) ListSAMLProviders() ([]SAMLProvider, error) { + resp, err := self.camRequest("ListSAMLProviders", nil) + if err != nil { + return nil, errors.Wrapf(err, "ListSAMLProviders") + } + result := []SAMLProvider{} + err = resp.Unmarshal(&result, "SAMLProviderSet") + if err != nil { + return nil, errors.Wrapf(err, "Unmarshal") + } + return result, nil +} + +func (self *SQcloudClient) CreateSAMLProvider(name, metadata, desc string) (*SAMLProvider, error) { + if len(desc) == 0 { + desc = "For CloudId Service" + } + //支持3-128个数字、大小写字母、和+=,.@_- + name = func() string { + ret := "" + for _, c := range name { + if unicode.IsLetter(c) || unicode.IsNumber(c) || + c == '+' || c == '=' || c == ',' || c == '.' || c == '@' || c == '_' || c == '-' { + ret += string(c) + } else { + ret += "-" + } + } + return ret + }() + if len(name) > 128 { + name = name[:128] + } + params := map[string]string{ + "Name": name, + "Description": desc, + "SAMLMetadataDocument": base64.StdEncoding.EncodeToString([]byte(metadata)), + } + _, err := self.camRequest("CreateSAMLProvider", params) + if err != nil { + return nil, errors.Wrapf(err, "CreateSAMLProvider") + } + return self.GetSAMLProvider(name) +} + +func (self *SQcloudClient) GetSAMLProvider(name string) (*SAMLProvider, error) { + params := map[string]string{ + "Name": name, + } + resp, err := self.camRequest("GetSAMLProvider", params) + if err != nil { + return nil, errors.Wrapf(err, "GetSAMLProvider") + } + result := &SAMLProvider{client: self} + err = resp.Unmarshal(result) + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return result, nil +} + +func (self *SQcloudClient) DeleteSAMLProvider(name string) error { + params := map[string]string{ + "Name": name, + } + _, err := self.camRequest("DeleteSAMLProvider", params) + return err +} + +func (self *SQcloudClient) UpdateSAMLProvider(name, metadata, desc string) error { + params := map[string]string{ + "Name": name, + } + if len(desc) > 0 { + params["Description"] = desc + } + if len(metadata) > 0 { + params["SAMLMetadataDocument"] = base64.StdEncoding.EncodeToString([]byte(metadata)) + } + _, err := self.camRequest("UpdateSAMLProvider", params) + if err != nil { + return errors.Wrap(err, "UpdateSAMLProvider") + } + return nil +} + +func (self *SQcloudClient) GetICloudSAMLProviders() ([]cloudprovider.ICloudSAMLProvider, error) { + providers, err := self.ListSAMLProviders() + if err != nil { + return nil, errors.Wrapf(err, "ListSAMLProviders") + } + ret := []cloudprovider.ICloudSAMLProvider{} + for i := range providers { + providers[i].client = self + ret = append(ret, &providers[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/securitygroup.go new file mode 100644 index 0000000000..5527f00e87 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/securitygroup.go @@ -0,0 +1,570 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "sort" + "strconv" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SecurityGroupPolicy struct { + region *SRegion + PolicyIndex int // 安全组规则索引号。 + Protocol string // 协议, 取值: TCP,UDP, ICMP。 + Port string // 端口(all, 离散port, range)。 + ServiceTemplate ServiceTemplateSpecification // 协议端口ID或者协议端口组ID。ServiceTemplate和Protocol+Port互斥。 + CidrBlock string // 网段或IP(互斥)。 + SecurityGroupId string // 已绑定安全组的网段或IP。 + AddressTemplate AddressTemplateSpecification // IP地址ID或者ID地址组ID。 + Action string // ACCEPT 或 DROP。 + PolicyDescription string // 安全组规则描述。 + direction string +} + +type ServiceTemplateSpecification struct { + ServiceId string // 协议端口ID,例如:ppm-f5n1f8da。 + ServiceGroupId string // 协议端口组ID,例如:ppmg-f5n1f8da。 +} + +type AddressTemplateSpecification struct { + AddressId string // IP地址ID,例如:ipm-2uw6ujo6。 + AddressGroupId string // IP地址组ID,例如:ipmg-2uw6ujo6。 +} + +type SecurityGroupPolicySet struct { + Version string + Egress []SecurityGroupPolicy // 出站规则。 + Ingress []SecurityGroupPolicy // 入站规则。 +} + +type SSecurityGroup struct { + multicloud.SSecurityGroup + QcloudTags + region *SRegion + SecurityGroupId string // 安全组实例ID,例如:sg-ohuuioma。 + SecurityGroupName string // 安全组名称,可任意命名,但不得超过60个字符。 + SecurityGroupDesc string // 安全组备注,最多100个字符。 + ProjectId string // 项目id,默认0。可在qcloud控制台项目管理页面查询到。 + IsDefault bool // 是否是默认安全组,默认安全组不支持删除。 + CreatedTime time.Time // 安全组创建时间。 + SecurityGroupPolicySet SecurityGroupPolicySet +} + +func (self *SRegion) GetSecurityGroups(ids []string, vpcId string, name string, offset int, limit int) ([]SSecurityGroup, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + + if len(name) > 0 { + params["Filters.0.Name"] = "security-group-name" + params["Filters.0.Values.0"] = name + } + + for idx, id := range ids { + params[fmt.Sprintf("SecurityGroupIds.%d", idx)] = id + } + + resp, err := self.vpcRequest("DescribeSecurityGroups", params) + if err != nil { + return nil, 0, errors.Wrapf(err, "DescribeSecurityGroups") + } + + secgrps := make([]SSecurityGroup, 0) + err = resp.Unmarshal(&secgrps, "SecurityGroupSet") + if err != nil { + return nil, 0, errors.Wrapf(err, "resp.Unmarshal") + } + total, _ := resp.Float("TotalCount") + return secgrps, int(total), nil +} + +func (self *SSecurityGroup) GetVpcId() string { + //腾讯云安全组未与vpc关联,统一使用normal + return "normal" +} + +func (self *SSecurityGroup) GetId() string { + return self.SecurityGroupId +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.SecurityGroupId +} + +func (self *SSecurityGroup) GetDescription() string { + return self.SecurityGroupDesc +} + +func (self *SSecurityGroup) GetName() string { + if len(self.SecurityGroupName) > 0 { + return self.SecurityGroupName + } + return self.SecurityGroupId +} + +func (self *SecurityGroupPolicy) String() string { + rules := self.toRules() + result := []string{} + for _, rule := range rules { + result = append(result, rule.String()) + } + return strings.Join(result, ";") +} + +type ReferredSecurityGroup struct { + SecurityGroupId string + ReferredSecurityGroupIds []string +} + +func (self *SSecurityGroup) GetReferences() ([]cloudprovider.SecurityGroupReference, error) { + references, err := self.region.DescribeSecurityGroupReferences(self.SecurityGroupId) + if err != nil { + return nil, errors.Wrapf(err, "DescribeSecurityGroupReferences") + } + ret := []cloudprovider.SecurityGroupReference{} + for _, refer := range references { + if refer.SecurityGroupId == self.SecurityGroupId { + for _, id := range refer.ReferredSecurityGroupIds { + ret = append(ret, cloudprovider.SecurityGroupReference{ + Id: id, + }) + } + } + } + return ret, nil +} + +func (self *SRegion) DescribeSecurityGroupReferences(id string) ([]ReferredSecurityGroup, error) { + params := map[string]string{ + "Region": self.Region, + "SecurityGroupIds.0": id, + } + resp, err := self.vpcRequest("DescribeSecurityGroupReferences", params) + if err != nil { + return nil, errors.Wrapf(err, "DescribeSecurityGroupReferences") + } + ret := []ReferredSecurityGroup{} + err = resp.Unmarshal(&ret, "ReferredSecurityGroupSet") + if err != nil { + return nil, errors.Wrapf(err, "resp.Unmarshal") + } + return ret, nil +} + +func (self *SecurityGroupPolicy) toRules() []cloudprovider.SecurityRule { + result := []cloudprovider.SecurityRule{} + rule := cloudprovider.SecurityRule{ + ExternalId: fmt.Sprintf("%d", self.PolicyIndex), + SecurityRule: secrules.SecurityRule{ + Action: secrules.SecurityRuleAllow, + Protocol: secrules.PROTO_ANY, + Direction: secrules.TSecurityRuleDirection(self.direction), + Priority: self.PolicyIndex, + Ports: []int{}, + PortStart: -1, + PortEnd: -1, + }, + } + if len(self.SecurityGroupId) != 0 { + rule.ParseCIDR("0.0.0.0/0") + rule.PeerSecgroupId = self.SecurityGroupId + } + if strings.ToLower(self.Action) == "drop" { + rule.Action = secrules.SecurityRuleDeny + } + if utils.IsInStringArray(strings.ToLower(self.Protocol), []string{"tcp", "udp", "icmp"}) { + rule.Protocol = strings.ToLower(self.Protocol) + } + if strings.Index(self.Port, ",") > 0 { + for _, _port := range strings.Split(self.Port, ",") { + port, err := strconv.Atoi(_port) + if err != nil { + log.Errorf("parse secgroup port %s %s error %v", self.Port, _port, err) + continue + } + rule.Ports = append(rule.Ports, port) + } + } else if strings.Index(self.Port, "-") > 0 { + ports := strings.Split(self.Port, "-") + if len(ports) == 2 { + portStart, err := strconv.Atoi(ports[0]) + if err != nil { + return nil + } + portEnd, err := strconv.Atoi(ports[1]) + if err != nil { + return nil + } + rule.PortStart, rule.PortEnd = portStart, portEnd + } + } else if strings.ToLower(self.Port) != "all" { + port, err := strconv.Atoi(self.Port) + if err != nil { + return nil + } + rule.PortStart, rule.PortEnd = port, port + } + + if len(self.AddressTemplate.AddressGroupId) > 0 { + addressGroup, total, err := self.region.AddressGroupList(self.AddressTemplate.AddressGroupId, "", 0, 1) + if err != nil { + log.Errorf("Get AddressList %s failed %v", self.AddressTemplate.AddressId, err) + return nil + } + if total != 1 { + return nil + } + for i := 0; i < len(addressGroup[0].AddressTemplateIdSet); i++ { + rules, err := self.getAddressRules(rule, addressGroup[0].AddressTemplateIdSet[i]) + if err != nil { + return nil + } + result = append(result, rules...) + } + } else if len(self.AddressTemplate.AddressId) > 0 { + rules, err := self.getAddressRules(rule, self.AddressTemplate.AddressId) + if err != nil { + return nil + } + result = append(result, rules...) + } else if len(self.SecurityGroupId) > 0 { + rule.PeerSecgroupId = self.SecurityGroupId + result = append(result, rule) + } else if len(self.CidrBlock) > 0 { + rule.ParseCIDR(self.CidrBlock) + result = append(result, rule) + } + return result +} + +func (self *SecurityGroupPolicy) getAddressRules(rule cloudprovider.SecurityRule, addressId string) ([]cloudprovider.SecurityRule, error) { + result := []cloudprovider.SecurityRule{} + address, total, err := self.region.AddressList(addressId, "", 0, 1) + if err != nil { + log.Errorf("Get AddressList %s failed %v", self.AddressTemplate.AddressId, err) + return nil, err + } + if total != 1 { + return nil, fmt.Errorf("failed to find address %s", addressId) + } + for _, ip := range address[0].AddressSet { + rule.ParseCIDR(ip) + result = append(result, rule) + } + return result, nil +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + policySet, err := self.region.DescribeSecurityGroupPolicies(self.SecurityGroupId) + if err != nil { + return nil, err + } + for i := 0; i < len(policySet.Egress); i++ { + policySet.Egress[i].direction = "out" + } + for i := 0; i < len(policySet.Ingress); i++ { + policySet.Ingress[i].direction = "in" + } + originRules := []SecurityGroupPolicy{} + originRules = append(originRules, policySet.Egress...) + originRules = append(originRules, policySet.Ingress...) + for i := 0; i < len(originRules); i++ { + originRules[i].region = self.region + } + rules := []cloudprovider.SecurityRule{} + for _, rule := range originRules { + subRules := rule.toRules() + rules = append(rules, subRules...) + } + return rules, nil +} + +func (self *SSecurityGroup) GetStatus() string { + return "" +} + +func (self *SSecurityGroup) IsEmulated() bool { + return false +} + +func (self *SSecurityGroup) Refresh() error { + groups, total, err := self.region.GetSecurityGroups([]string{self.SecurityGroupId}, "", "", 0, 0) + if err != nil { + return err + } + if total < 1 { + return cloudprovider.ErrNotFound + } + return jsonutils.Update(self, groups[0]) +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + rules := append(common, append(inAdds, outAdds...)...) + sort.Sort(cloudprovider.SecurityRuleSet(rules)) + return self.region.syncSecgroupRules(self.SecurityGroupId, rules) +} + +func (self *SRegion) syncSecgroupRules(secgroupId string, rules []cloudprovider.SecurityRule) error { + params := map[string]string{ + "SecurityGroupId": secgroupId, + "SortPolicys": "True", + } + egressIndex, ingressIndex := 0, 0 + for _, rule := range rules { + switch rule.Direction { + case secrules.DIR_IN: + params = convertSecgroupRule(ingressIndex, rule, params) + ingressIndex++ + case secrules.DIR_OUT: + params = convertSecgroupRule(egressIndex, rule, params) + egressIndex++ + } + } + _, err := self.vpcRequest("ModifySecurityGroupPolicies", params) + if err != nil { + return errors.Wrapf(err, "ModifySecurityGroupPolicies") + } + if egressIndex == 0 || ingressIndex == 0 { + ruleSet, err := self.DescribeSecurityGroupPolicies(secgroupId) + if err != nil { + return errors.Wrapf(err, "DescribeSecurityGroupPolicies") + } + params = map[string]string{ + "SecurityGroupId": secgroupId, + } + if egressIndex == 0 && len(ruleSet.Egress) > 0 { + for idx, rule := range ruleSet.Egress { + params[fmt.Sprintf("SecurityGroupPolicySet.Egress.%d.PolicyIndex", idx)] = fmt.Sprintf("%d", rule.PolicyIndex) + } + } + if ingressIndex == 0 && len(ruleSet.Ingress) > 0 { + for idx, rule := range ruleSet.Ingress { + params[fmt.Sprintf("SecurityGroupPolicySet.Ingress.%d.PolicyIndex", idx)] = fmt.Sprintf("%d", rule.PolicyIndex) + } + } + if len(params) > 1 { + _, err = self.vpcRequest("DeleteSecurityGroupPolicies", params) + if err != nil { + return errors.Wrapf(err, "DeleteSecurityGroupPolicies") + } + } + } + return nil +} + +func convertSecgroupRule(policyIndex int, rule cloudprovider.SecurityRule, params map[string]string) map[string]string { + direction := "Egress" + action := "accept" + if rule.Action == secrules.SecurityRuleDeny { + action = "drop" + } + protocol := "ALL" + if rule.Protocol != secrules.PROTO_ANY { + protocol = rule.Protocol + } + if rule.Direction == secrules.DIR_IN { + direction = "Ingress" + } + params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.Action", direction, policyIndex)] = action + params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.PolicyDescription", direction, policyIndex)] = rule.Description + params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.Protocol", direction, policyIndex)] = protocol + if len(rule.PeerSecgroupId) > 0 { + params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.SecurityGroupId", direction, policyIndex)] = rule.PeerSecgroupId + } else { + params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.CidrBlock", direction, policyIndex)] = rule.IPNet.String() + } + if rule.Protocol == secrules.PROTO_TCP || rule.Protocol == secrules.PROTO_UDP { + port := "ALL" + if rule.PortEnd > 0 && rule.PortStart > 0 { + if rule.PortStart == rule.PortEnd { + port = fmt.Sprintf("%d", rule.PortStart) + } else { + port = fmt.Sprintf("%d-%d", rule.PortStart, rule.PortEnd) + } + } else if len(rule.Ports) > 0 { + ports := []string{} + for _, _port := range rule.Ports { + ports = append(ports, fmt.Sprintf("%d", _port)) + } + port = strings.Join(ports, ",") + } + params[fmt.Sprintf("SecurityGroupPolicySet.%s.%d.Port", direction, policyIndex)] = port + } + return params +} + +func (self *SRegion) DescribeSecurityGroupPolicies(secGroupId string) (*SecurityGroupPolicySet, error) { + params := make(map[string]string) + params["Region"] = self.Region + params["SecurityGroupId"] = secGroupId + + body, err := self.vpcRequest("DescribeSecurityGroupPolicies", params) + if err != nil { + log.Errorf("DescribeSecurityGroupAttribute fail %s", err) + return nil, err + } + + policies := SecurityGroupPolicySet{} + err = body.Unmarshal(&policies, "SecurityGroupPolicySet") + if err != nil { + return nil, errors.Wrapf(err, "body.Unmarshal") + } + return &policies, nil +} + +func (self *SRegion) DeleteSecurityGroup(secGroupId string) error { + params := make(map[string]string) + params["Region"] = self.Region + params["SecurityGroupId"] = secGroupId + _, err := self.vpcRequest("DeleteSecurityGroup", params) + return err +} + +type AddressTemplate struct { + AddressSet []string + AddressTemplateId string + AddressTemplateName string + CreatedTime time.Time +} + +func (self *SRegion) AddressList(addressId, addressName string, offset, limit int) ([]AddressTemplate, int, error) { + params := map[string]string{} + filter := 0 + if len(addressId) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "address-template-id" + params[fmt.Sprintf("Filters.%d.Values.0", filter)] = addressId + filter++ + } + if len(addressName) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "address-template-name" + params[fmt.Sprintf("Filters.%d.Values.0", filter)] = addressName + filter++ + } + params["Offset"] = fmt.Sprintf("%d", offset) + if limit == 0 { + limit = 20 + } + params["Limit"] = fmt.Sprintf("%d", limit) + body, err := self.vpcRequest("DescribeAddressTemplates", params) + if err != nil { + return nil, 0, err + } + addressTemplates := []AddressTemplate{} + err = body.Unmarshal(&addressTemplates, "AddressTemplateSet") + if err != nil { + return nil, 0, err + } + total, _ := body.Float("TotalCount") + return addressTemplates, int(total), nil +} + +type AddressTemplateGroup struct { + AddressTemplateIdSet []string + AddressTemplateGroupName string + AddressTemplateGroupId string + CreatedTime time.Time +} + +func (self *SRegion) AddressGroupList(groupId, groupName string, offset, limit int) ([]AddressTemplateGroup, int, error) { + params := map[string]string{} + filter := 0 + if len(groupId) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "address-template-group-id" + params[fmt.Sprintf("Filters.%d.Values.0", filter)] = groupId + filter++ + } + if len(groupName) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "address-template-group-name" + params[fmt.Sprintf("Filters.%d.Values.0", filter)] = groupName + filter++ + } + params["Offset"] = fmt.Sprintf("%d", offset) + if limit == 0 { + limit = 20 + } + params["Limit"] = fmt.Sprintf("%d", limit) + body, err := self.vpcRequest("DescribeAddressTemplateGroups", params) + if err != nil { + return nil, 0, err + } + addressTemplateGroups := []AddressTemplateGroup{} + err = body.Unmarshal(&addressTemplateGroups, "AddressTemplateGroupSet") + if err != nil { + return nil, 0, err + } + total, _ := body.Float("TotalCount") + return addressTemplateGroups, int(total), nil +} + +func (self *SRegion) DeleteSecgroupRule(secId string, direction string, index int) error { + params := map[string]string{ + "SecurityGroupId": secId, + } + switch direction { + case secrules.DIR_IN: + params["SecurityGroupPolicySet.Ingress.0.PolicyIndex"] = fmt.Sprintf("%d", index) + case secrules.DIR_OUT: + params["SecurityGroupPolicySet.Egress.0.PolicyIndex"] = fmt.Sprintf("%d", index) + } + _, err := self.vpcRequest("DeleteSecurityGroupPolicies", params) + return errors.Wrapf(err, "DeleteSecurityGroupPolicies") +} + +func (self *SRegion) CreateSecurityGroup(name, projectId, description string) (*SSecurityGroup, error) { + params := make(map[string]string) + params["Region"] = self.Region + params["GroupName"] = name + params["GroupDescription"] = description + if len(projectId) > 0 { + params["ProjectId"] = projectId + } + + if len(description) == 0 { + params["GroupDescription"] = "Customize Create" + } + secgroup := SSecurityGroup{region: self} + body, err := self.vpcRequest("CreateSecurityGroup", params) + if err != nil { + return nil, errors.Wrap(err, "CreateSecurityGroup") + } + err = body.Unmarshal(&secgroup, "SecurityGroup") + if err != nil { + return nil, errors.Wrap(err, "body.Unmarshal") + } + return &secgroup, nil +} + +func (self *SSecurityGroup) GetProjectId() string { + return self.ProjectId +} + +func (self *SSecurityGroup) Delete() error { + return self.region.DeleteSecurityGroup(self.SecurityGroupId) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/snapshot.go new file mode 100644 index 0000000000..f0909d88b4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/snapshot.go @@ -0,0 +1,233 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strconv" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SnapshotStatusType string + +const ( + SnapshotStatusAccomplished SnapshotStatusType = "NORMAL" + SnapshotStatusProgress SnapshotStatusType = "CREATING" + SnapshotStatusFailed SnapshotStatusType = "failed" +) + +type SSnapshot struct { + multicloud.SResourceBase + QcloudTags + region *SRegion + + SnapshotId string // 快照ID。 + Placement Placement // 快照所在的位置。 + DiskUsage string // 创建此快照的云硬盘类型。取值范围:SYSTEM_DISK:系统盘 DATA_DISK:数据盘。 + DiskId string // 创建此快照的云硬盘ID。 + DiskSize int32 // 创建此快照的云硬盘大小,单位GB。 + SnapshotState SnapshotStatusType // 快照的状态。取值范围: NORMAL:正常 CREATING:创建中 ROLLBACKING:回滚中 COPYING_FROM_REMOTE:跨地域复制快照拷贝中。 + SnapshotName string // 快照名称,用户自定义的快照别名。调用ModifySnapshotAttribute可修改此字段。 + Percent int // 快照创建进度百分比,快照创建成功后此字段恒为100。 + CreateTime time.Time // 快照的创建时间。 + DeadlineTime time.Time // 快照到期时间。如果快照为永久保留,此字段为空。 + Encrypt bool // 是否为加密盘创建的快照。取值范围:true:该快照为加密盘创建的 false:非加密盘创建的快照。 + IsPermanent bool // 是否为永久快照。取值范围: true:永久快照 false:非永久快照。 + CopyingToRegions []string // 快照正在跨地域复制的目的地域,默认取值为[]。 + CopyFromRemote bool // 是否为跨地域复制的快照。取值范围:true:表示为跨地域复制的快照。 false:本地域的快照。 +} + +func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + snapshots, total, err := self.GetSnapshots("", "", "", []string{snapshotId}, 0, 1) + if err != nil { + return nil, err + } + if total > 1 { + return nil, cloudprovider.ErrDuplicateId + } + if total == 0 { + return nil, cloudprovider.ErrNotFound + } + return &snapshots[0], nil +} + +func (self *SSnapshot) GetStatus() string { + // NORMAL:正常 + // CREATING:创建中 + // ROLLBACKING:回滚中 + // COPYING_FROM_REMOTE:跨地域复制快照拷贝中。 + switch self.SnapshotState { + case "NORMAL", "COPYING_FROM_REMOTE": + return api.SNAPSHOT_READY + case "CREATING": + return api.SNAPSHOT_CREATING + case "ROLLBACKING": + return api.SNAPSHOT_ROLLBACKING + } + return api.SNAPSHOT_UNKNOWN +} + +func (self *SSnapshot) IsEmulated() bool { + return false +} + +func (self *SSnapshot) Refresh() error { + snapshots, total, err := self.region.GetSnapshots("", "", "", []string{self.SnapshotId}, 0, 1) + if err != nil { + return err + } + if total > 1 { + return cloudprovider.ErrDuplicateId + } + + if total == 0 { + return cloudprovider.ErrNotFound + } + return jsonutils.Update(self, snapshots[0]) +} + +func (self *SRegion) GetSnapshots(instanceId string, diskId string, snapshotName string, snapshotIds []string, offset int, limit int) ([]SSnapshot, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["Limit"] = fmt.Sprintf("%d", limit) + params["Offset"] = fmt.Sprintf("%d", offset) + + filter := 0 + if len(instanceId) > 0 { + } + if len(diskId) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "disk-id" + params[fmt.Sprintf("Filters.%d.Values.0", filter)] = diskId + filter++ + } + if len(snapshotName) > 0 { + params[fmt.Sprintf("Filters.%d.Name", filter)] = "snapshot-name" + params[fmt.Sprintf("Filters.%d.Values", filter)] = snapshotName + filter++ + } + if snapshotIds != nil && len(snapshotIds) > 0 { + for index, snapshotId := range snapshotIds { + params[fmt.Sprintf("SnapshotIds.%d", index)] = snapshotId + } + } + snapshots := []SSnapshot{} + body, err := self.cbsRequest("DescribeSnapshots", params) + if err != nil { + log.Errorf("GetSnapshots fail %s", err) + return nil, 0, err + } + body.Unmarshal(&snapshots, "SnapshotSet") + if err != nil { + return nil, 0, err + } + total, _ := body.Float("TotalCount") + for i := 0; i < len(snapshots); i++ { + snapshots[i].region = self + } + return snapshots, int(total), nil +} + +func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, total, err := self.GetSnapshots("", "", "", []string{}, 0, 50) + if err != nil { + return nil, err + } + for len(snapshots) < total { + var parts []SSnapshot + parts, total, err = self.GetSnapshots("", "", "", []string{}, len(snapshots), 50) + if err != nil { + return nil, err + } + snapshots = append(snapshots, parts...) + } + ret := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := 0; i < len(snapshots); i++ { + ret[i] = &snapshots[i] + } + return ret, nil +} + +func (self *SSnapshot) GetRegionId() string { + return self.region.GetId() +} + +func (self *SSnapshot) GetSizeMb() int32 { + return self.DiskSize * 1024 +} + +func (self *SSnapshot) GetDiskId() string { + return self.DiskId +} + +func (self *SSnapshot) GetId() string { + return self.SnapshotId +} + +func (self *SSnapshot) GetGlobalId() string { + return fmt.Sprintf("%s", self.SnapshotId) +} + +func (self *SSnapshot) GetName() string { + return self.SnapshotName +} + +func (self *SSnapshot) Delete() error { + if self.region == nil { + return fmt.Errorf("not init region for snapshot %s", self.SnapshotId) + } + return self.region.DeleteSnapshot(self.SnapshotId) +} + +func (self *SSnapshot) GetDiskType() string { + switch self.DiskUsage { + case "SYSTEM_DISK": + return api.DISK_TYPE_SYS + case "DATA_DISK": + return api.DISK_TYPE_DATA + } + return api.DISK_TYPE_DATA +} + +func (self *SRegion) DeleteSnapshot(snapshotId string) error { + params := map[string]string{"SnapshotIds.0": snapshotId} + _, err := self.cbsRequest("DeleteSnapshots", params) + return err +} + +func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { + params := make(map[string]string) + params["DiskId"] = diskId + params["SnapshotName"] = name + + body, err := self.cbsRequest("CreateSnapshot", params) + if err != nil { + log.Errorf("CreateSnapshot fail %s", err) + return "", err + } + return body.GetString("SnapshotId") +} + +func (self *SSnapshot) GetProjectId() string { + return strconv.Itoa(self.Placement.ProjectId) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/snapshot_policy.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/snapshot_policy.go new file mode 100644 index 0000000000..a5e20646dd --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/snapshot_policy.go @@ -0,0 +1,275 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strconv" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + NORMAL = "NORMAL" + UNKOWN = "ISOLATED" +) + +type SSnapshotDatePolicy struct { + DayOfWeek []int + Hour []int +} + +type SSnapshotPolicy struct { + multicloud.SResourceBase + QcloudTags + region *SRegion + + AutoSnapshotPolicyName string + AutoSnapshotPolicyId string + AutoSnapshotPolicyState string + RetentionDays int + Policy []SSnapshotDatePolicy + Activated bool `json:"IsActivated"` + IsPermanent bool +} + +func (self *SSnapshotPolicy) GetId() string { + return self.AutoSnapshotPolicyId +} + +func (self *SSnapshotPolicy) GetName() string { + return self.AutoSnapshotPolicyName +} + +func (self *SSnapshotPolicy) GetGlobalId() string { + return self.GetId() +} + +func (self *SSnapshotPolicy) GetStatus() string { + if self.AutoSnapshotPolicyState == NORMAL { + return api.SNAPSHOT_POLICY_READY + } + return api.SNAPSHOT_POLICY_UNKNOWN +} + +func (self *SSnapshotPolicy) Refresh() error { + if snapshotPolicies, total, err := self.region.GetSnapshotPolicies(self.AutoSnapshotPolicyId, 0, 1); err != nil { + return err + } else if total != 1 { + return cloudprovider.ErrNotFound + } else if err := jsonutils.Update(self, snapshotPolicies[0]); err != nil { + return err + } + return nil +} + +func (self *SSnapshotPolicy) IsEmulated() bool { + return false +} + +func (self *SSnapshotPolicy) GetProjectId() string { + return "" +} + +func (self *SSnapshotPolicy) GetRetentionDays() int { + if self.IsPermanent { + return -1 + } + return self.RetentionDays +} + +func (self *SSnapshotPolicy) GetRepeatWeekdays() ([]int, error) { + if len(self.Policy) == 0 { + return nil, errors.Error("Policy Set Empty") + } + repeatWeekdays := self.Policy[0].DayOfWeek + if len(repeatWeekdays) > 0 { + if repeatWeekdays[0] == 0 { + repeatWeekdays = append(repeatWeekdays, 7)[1:] + } + } + return repeatWeekdays, nil +} + +func (self *SSnapshotPolicy) GetTimePoints() ([]int, error) { + if len(self.Policy) == 0 { + return nil, errors.Error("Policy Set Empty") + } + return self.Policy[0].Hour, nil +} + +func (self *SSnapshotPolicy) IsActivated() bool { + return self.Activated +} + +func (self *SRegion) GetISnapshotPolicies() ([]cloudprovider.ICloudSnapshotPolicy, error) { + snapshotPolicies, total, err := self.GetSnapshotPolicies("", 0, 50) + if err != nil { + return nil, err + } + for len(snapshotPolicies) < total { + var parts []SSnapshotPolicy + parts, total, err = self.GetSnapshotPolicies("", len(snapshotPolicies), 50) + if err != nil { + return nil, err + } + snapshotPolicies = append(snapshotPolicies, parts...) + } + ret := make([]cloudprovider.ICloudSnapshotPolicy, len(snapshotPolicies)) + for i := 0; i < len(snapshotPolicies); i += 1 { + ret[i] = &snapshotPolicies[i] + } + return ret, nil +} + +func (self *SRegion) GetSnapshotPolicies(policyId string, offset int, limit int) ([]SSnapshotPolicy, int, error) { + params := make(map[string]string) + if len(policyId) > 0 { + params["AutoSnapshotPolicyIds.0"] = policyId + } + if limit != 0 { + params["Limit"] = strconv.Itoa(limit) + params["Offset"] = strconv.Itoa(offset) + } + body, err := self.cbsRequest("DescribeAutoSnapshotPolicies", params) + if err != nil { + return nil, 0, errors.Wrap(err, "Get Snapshot Policies failed") + } + snapshotPolicies := make([]SSnapshotPolicy, 0, 1) + if err := body.Unmarshal(&snapshotPolicies, "AutoSnapshotPolicySet"); err != nil { + return nil, 0, errors.Wrap(err, "Unmarshal snapshot policies detail failed") + } + for i := range snapshotPolicies { + snapshotPolicies[i].region = self + } + return snapshotPolicies, len(snapshotPolicies), nil +} + +func (self *SSnapshotPolicy) Delete() error { + if self.region == nil { + return fmt.Errorf("Not init region for snapshotPolicy %s", self.GetId()) + } + return self.region.DeleteSnapshotPolicy(self.GetId()) +} + +func (self *SRegion) DeleteSnapshotPolicy(snapshotPolicyId string) error { + params := make(map[string]string) + params["AutoSnapshotPolicyIds.0"] = snapshotPolicyId + _, err := self.cbsRequest("DeleteAutoSnapshotPolicies", params) + if err != nil { + return errors.Wrapf(err, "delete auto snapshot policy %s failed", snapshotPolicyId) + } + return nil +} + +func (self *SRegion) GetISnapshotPolicyById(snapshotPolicyId string) (cloudprovider.ICloudSnapshotPolicy, error) { + policies, _, err := self.GetSnapshotPolicies(snapshotPolicyId, 0, 1) + if err != nil { + return nil, err + } + if len(policies) == 0 { + return nil, cloudprovider.ErrNotFound + } + return &policies[0], nil +} + +func (self *SRegion) CreateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput) (string, error) { + if input.RepeatWeekdays == nil { + return "", fmt.Errorf("Can't create snapshot policy with nil repeatWeekdays") + } + if input.TimePoints == nil { + return "", fmt.Errorf("Can't create snapshot policy with nil timePoints") + } + params := make(map[string]string) + + // In Qcloud, that IsPermanent is true means that keep snapshot forever, + // In OneCloud, that RetentionDays is -1 means that keep snapshot forever. + if input.RetentionDays == -1 { + params["IsPermanent"] = strconv.FormatBool(true) + } else { + params["RetentionDays"] = strconv.Itoa(input.RetentionDays) + } + dayOfWeekPrefix, hourPrefix := "Policy.0.DayOfWeek.", "Policy.0.Hour." + for index, day := range input.RepeatWeekdays { + if day == 7 { + day = 0 + } + params[dayOfWeekPrefix+strconv.Itoa(index)] = strconv.Itoa(day) + } + if len(input.PolicyName) > 0 { + params["AutoSnapshotPolicyName"] = input.PolicyName + } + for index, hour := range input.TimePoints { + params[hourPrefix+strconv.Itoa(index)] = strconv.Itoa(hour) + } + body, err := self.cbsRequest("CreateAutoSnapshotPolicy", params) + if err != nil { + return "", errors.Wrap(err, "create auto snapshot policy failed") + } + id, _ := body.GetString("AutoSnapshotPolicyId") + return id, nil +} + +func (self *SRegion) UpdateSnapshotPolicy(input *cloudprovider.SnapshotPolicyInput, snapshotPolicyId string) error { + // not implement + return nil +} + +func (self *SRegion) ApplySnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { + params := make(map[string]string) + params["AutoSnapshotPolicyId"] = snapshotPolicyId + params["DiskIds.0"] = diskId + _, err := self.cbsRequest("BindAutoSnapshotPolicy", params) + if err != nil { + return errors.Wrapf(err, "Bind AutoSnapshotPolicy %s to Disk failed", snapshotPolicyId) + } + return nil +} + +func (self *SRegion) CancelSnapshotPolicyToDisks(snapshotPolicyId string, diskId string) error { + params := make(map[string]string) + params["AutoSnapshotPolicyId"] = snapshotPolicyId + params["DiskIds.0"] = diskId + _, err := self.cbsRequest("UnbindAutoSnapshotPolicy", params) + if err != nil { + return errors.Wrapf(err, "Unbind AutoSnapshotPolicy %s of Disk failed", snapshotPolicyId) + } + return nil +} + +func (self *SRegion) GetSnapshotIdByDiskId(diskID string) ([]string, error) { + params := make(map[string]string) + params["DiskId"] = diskID + + rps, err := self.cbsRequest("DescribeDiskAssociatedAutoSnapshotPolicy", params) + if err != nil { + return nil, errors.Wrapf(err, "Get All SnapshotpolicyIDs of Disk %s failed", diskID) + } + + snapshotpolicies := make([]SSnapshotPolicy, 0) + if err := rps.Unmarshal(&snapshotpolicies, "AutoSnapshotPolicySet"); err != nil { + return nil, errors.Wrapf(err, "Unmarshal snapshot policies details failed") + } + ret := make([]string, len(snapshotpolicies)) + for i := range snapshotpolicies { + ret[i] = snapshotpolicies[i].GetId() + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/storage.go new file mode 100644 index 0000000000..66ee5129fc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/storage.go @@ -0,0 +1,156 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStorage struct { + multicloud.SStorageBase + zone *SZone + storageType string + available bool +} + +func (self *SStorage) GetId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), strings.ToLower(self.storageType)) +} + +func (self *SStorage) GetName() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), strings.ToLower(self.storageType)) +} + +func (self *SStorage) GetGlobalId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), strings.ToLower(self.storageType)) +} + +func (self *SStorage) IsEmulated() bool { + return true +} + +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++ { + disks[i].storage = self + idisks[i] = &disks[i] + } + return idisks, nil +} + +func (self *SStorage) GetStorageType() string { + return strings.ToLower(self.storageType) +} + +func (self *SStorage) GetMediumType() string { + if strings.HasSuffix(self.storageType, "_BASIC") { + return api.DISK_TYPE_ROTATE + } + return api.DISK_TYPE_SSD +} + +func (self *SStorage) GetCapacityMB() int64 { + return 0 // unlimited +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + return conf +} + +func (self *SStorage) GetStatus() string { + if !self.available { + return api.STORAGE_OFFLINE + } + return api.STORAGE_ONLINE +} + +func (self *SStorage) Refresh() error { + // do nothing + return nil +} + +func (self *SStorage) GetEnabled() bool { + return self.available == true +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.zone.region.getStoragecache() +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + diskId, err := self.zone.region.CreateDisk(self.zone.Zone, self.storageType, conf.Name, conf.SizeGb, conf.Desc, conf.ProjectId) + if err != nil { + log.Errorf("createDisk fail %s", err) + return nil, err + } + //腾讯刚创建完成的磁盘,需要稍微等待才能查询 + for i := 0; i < 3; i++ { + disk, err := self.zone.region.GetDisk(diskId) + if err == nil { + disk.storage = self + return disk, nil + } + time.Sleep(time.Second * 3) + } + log.Errorf("getDisk fail %s id %s", err, diskId) + return nil, cloudprovider.ErrNotFound +} + +func (self *SStorage) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) { + disk, err := self.zone.region.GetDisk(idStr) + if err != nil { + return nil, err + } + disk.storage = self + return disk, nil +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + return strings.ToLower(self.storageType) != api.STORAGE_CLOUD_HSSD +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/storagecache.go new file mode 100644 index 0000000000..6e9911446a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/storagecache.go @@ -0,0 +1,213 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "context" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +type SStoragecache struct { + multicloud.SResourceBase + QcloudTags + region *SRegion +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) +} + +func (self *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) +} + +func (self *SStoragecache) GetStatus() string { + return "available" +} + +func (self *SStoragecache) Refresh() error { + return nil +} + +func (self *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetGlobalId()) +} + +func (self *SStoragecache) IsEmulated() bool { + return false +} + +func (self *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + // if imageId, err := self.region.createIImage(snapshoutId, 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 + // if err := cloudprovider.WaitStatus(iimage[0], compute.IMAGE_STATUS_ACTIVE, 15*time.Second, 3600*time.Second); err != nil { + // return nil, err + // } + // return iimage[0], nil + // } + return nil, nil +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + //return self.downloadImage(userCred, imageId, extId, path) + return nil, nil +} + +func (self *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + images := make([]SImage, 0) + for { + parts, total, err := self.region.GetImages("", "PRIVATE_IMAGE", nil, "", len(images), 50) + if err != nil { + return nil, errors.Wrapf(err, "GetImages") + } + images = append(images, parts...) + if len(images) >= total { + break + } + } + ret := []cloudprovider.ICloudImage{} + for i := 0; i < len(images); i += 1 { + images[i].storageCache = self + ret = append(ret, &images[i]) + } + return ret, nil +} + +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + parts, _, err := self.region.GetImages("", "", []string{extId}, "", 0, 1) + if err != nil { + return nil, err + } + if len(parts) == 0 { + return nil, cloudprovider.ErrNotFound + } + parts[0].storageCache = self + return &parts[0], nil +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return self.uploadImage(ctx, userCred, image, callback) +} + +func (self *SRegion) getCosUrl(bucket, object string) string { + //signature := cosauth.NewSignature(self.client.AppID, bucket, self.client.secretId, time.Now().Add(time.Minute*30).String(), time.Now().String(), "yunion", object).SignOnce(self.client.secretKey) + return fmt.Sprintf("http://%s-%s.cos.%s.myqcloud.com/%s", bucket, self.client.appId, self.Region, object) +} + +func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + // first upload image to oss + s := auth.GetAdminSession(ctx, options.Options.Region) + + _, reader, sizeBytes, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) + if err != nil { + return "", err + } + + bucketName := strings.Replace(strings.ToLower(self.region.GetId()+image.ImageId), "-", "", -1) + if len(bucketName) > 40 { + bucketName = bucketName[:40] + } + exists, _ := self.region.IBucketExist(bucketName) + if !exists { + log.Debugf("Bucket %s not exists, to create ...", bucketName) + err := self.region.CreateIBucket(bucketName, "", "public-read") + if err != nil { + log.Errorf("Create bucket error %s", err) + return "", err + } + } else { + log.Debugf("Bucket %s exists", bucketName) + } + defer self.region.DeleteIBucket(bucketName) + log.Debugf("To upload image to bucket %s ...", bucketName) + bucket, err := self.region.GetIBucketById(bucketName) + if err != nil { + return "", errors.Wrap(err, "GetIBucketByName") + } + body := multicloud.NewProgress(sizeBytes, 80, reader, callback) + err = cloudprovider.UploadObject(context.Background(), bucket, image.ImageId, 0, body, sizeBytes, "", "", nil, false) + // err = bucket.PutObject(context.Background(), image.ImageId, reader, sizeBytes, "", "", "") + if err != nil { + log.Errorf("UploadObject error %s %s", image.ImageId, err) + return "", errors.Wrap(err, "bucket.PutObject") + } + + defer bucket.DeleteObject(context.Background(), image.ImageId) + + // 腾讯云镜像名称需要小于20个字符 + imageBaseName := image.ImageId[:10] + if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { + imageBaseName = fmt.Sprintf("img%s", image.ImageId[:10]) + } + imageName := imageBaseName + nameIdx := 1 + + // check image name, avoid name conflict + for { + _, err = self.region.GetImageByName(imageName) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + break + } else { + return "", err + } + } + imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) + nameIdx++ + } + + log.Debugf("Import image %s", imageName) + img, err := self.region.ImportImage(imageName, image.OsArch, image.OsDistribution, image.OsVersion, self.region.getCosUrl(bucketName, image.ImageId)) + if err != nil { + return "", err + } + err = cloudprovider.WaitStatus(img, api.CACHED_IMAGE_STATUS_ACTIVE, 15*time.Second, 3600*time.Second) + if err != nil { + return "", err + } + if callback != nil { + callback(100) + } + return img.ImageId, nil +} diff --git a/pkg/multicloud/qcloud/sts.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/sts.go similarity index 100% rename from pkg/multicloud/qcloud/sts.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/sts.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tag_base.go new file mode 100644 index 0000000000..030fd26646 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tag_base.go @@ -0,0 +1,105 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "strings" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type QcloudTags struct { + TagSet []multicloud.STag + + // Redis + InstanceTags []multicloud.STag + // Elasticsearch + TagList []multicloud.STag + // Kafka + Tags []multicloud.STag + // Cdn + Tag []multicloud.STag + // TDSQL + ResourceTags []multicloud.STag +} + +func (self *QcloudTags) getTags() (map[string]string, error) { + ret := map[string]string{} + for _, tag := range self.TagSet { + if tag.Value == "null" { + tag.Value = "" + } + ret[tag.Key] = tag.Value + } + for _, tag := range self.InstanceTags { + if tag.TagValue == "null" { + tag.TagValue = "" + } + ret[tag.TagKey] = tag.TagValue + } + for _, tag := range self.TagList { + if tag.TagValue == "null" { + tag.TagValue = "" + } + ret[tag.TagKey] = tag.TagValue + } + for _, tag := range self.Tags { + if tag.TagValue == "null" { + tag.TagValue = "" + } + ret[tag.TagKey] = tag.TagValue + } + for _, tag := range self.Tag { + if tag.TagValue == "null" { + tag.TagValue = "" + } + ret[tag.TagKey] = tag.TagValue + } + for _, tag := range self.ResourceTags { + if tag.TagValue == "null" { + tag.TagValue = "" + } + ret[tag.TagKey] = tag.TagValue + } + return ret, nil +} + +func (self *QcloudTags) GetTags() (map[string]string, error) { + tags, _ := self.getTags() + for k := range tags { + if strings.HasPrefix(k, "tencentcloud:") { + delete(tags, k) + } + } + return tags, nil +} + +func (self *QcloudTags) GetSysTags() map[string]string { + tags, _ := self.getTags() + ret := map[string]string{} + for k, v := range tags { + if strings.HasPrefix(k, "tencentcloud:") { + ret[k] = v + } + } + return ret +} + +func (self *QcloudTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/pkg/multicloud/qcloud/tags.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tags.go similarity index 100% rename from pkg/multicloud/qcloud/tags.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tags.go diff --git a/pkg/multicloud/qcloud/tdsql_account.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tdsql_account.go similarity index 96% rename from pkg/multicloud/qcloud/tdsql_account.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tdsql_account.go index 76e086e3e5..d3fc8dc3a0 100644 --- a/pkg/multicloud/qcloud/tdsql_account.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tdsql_account.go @@ -17,13 +17,13 @@ package qcloud import ( "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type STDSQLAccount struct { multicloud.SDBInstanceAccountBase - multicloud.QcloudTags + QcloudTags rds *STDSQL UserName string diff --git a/pkg/multicloud/qcloud/tdsql_database.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tdsql_database.go similarity index 93% rename from pkg/multicloud/qcloud/tdsql_database.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tdsql_database.go index 2555e7478d..2676da8d3d 100644 --- a/pkg/multicloud/qcloud/tdsql_database.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/tdsql_database.go @@ -17,15 +17,15 @@ package qcloud import ( "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type STDSQLDatabase struct { rds *STDSQL multicloud.SResourceBase - multicloud.QcloudTags + QcloudTags DbName string } diff --git a/pkg/multicloud/qcloud/types.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/types.go similarity index 100% rename from pkg/multicloud/qcloud/types.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/types.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/vpc.go new file mode 100644 index 0000000000..0a060f5475 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/vpc.go @@ -0,0 +1,428 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + QcloudTags + + region *SRegion + + iwires []cloudprovider.ICloudWire + + secgroups []cloudprovider.ICloudSecurityGroup + + CidrBlock string + CreatedTime time.Time + DhcpOptionsId string + DnsServerSet []string + DomainName string + EnableMulticast bool + IsDefault bool + VpcId string + VpcName string +} + +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) IsEmulated() bool { + return false +} + +func (self *SVpc) GetIsDefault() bool { + return self.IsDefault +} + +func (self *SVpc) GetCidrBlock() string { + return self.CidrBlock +} + +func (self *SVpc) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} + +func (self *SVpc) Delete() error { + return self.region.DeleteVpc(self.VpcId) +} + +func (self *SVpc) SetTags(tags map[string]string, replace bool) error { + return self.region.SetResourceTags("vpc", "vpc", []string{self.VpcId}, tags, replace) +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + secgroups := make([]SSecurityGroup, 0) + for { + parts, total, err := self.region.GetSecurityGroups([]string{}, self.VpcId, "", len(secgroups), 50) + if err != nil { + return nil, err + } + secgroups = append(secgroups, parts...) + if len(secgroups) >= total { + break + } + } + isecgroups := make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) + for i := 0; i < len(secgroups); i++ { + secgroups[i].region = self.region + isecgroups[i] = &secgroups[i] + } + return isecgroups, nil +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + rts := []cloudprovider.ICloudRouteTable{} + routetables, err := self.region.GetAllRouteTables(self.GetId(), []string{}) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetAllRouteTables(%s, []string{})", self.GetId()) + } + for i := range routetables { + routetables[i].vpc = self + rts = append(rts, &routetables[i]) + } + return rts, nil +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + routetables, err := self.region.GetAllRouteTables(self.GetId(), []string{routeTableId}) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetAllRouteTables(%s, []string{})", self.GetId()) + } + if len(routetables) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(routetables) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + routetables[0].vpc = self + return &routetables[0], nil +} + +func (self *SVpc) getWireByZoneId(zoneId string) *SWire { + for i := 0; i <= len(self.iwires); i++ { + wire := self.iwires[i].(*SWire) + if wire.zone.Zone == zoneId { + return wire + } + } + return nil +} + +func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { + nats := []SNatGateway{} + for { + part, total, err := self.region.GetNatGateways(self.VpcId, len(nats), 50) + if err != nil { + return nil, err + } + nats = append(nats, part...) + if len(nats) >= total { + break + } + } + inats := []cloudprovider.ICloudNatGateway{} + for i := 0; i < len(nats); i++ { + nats[i].vpc = self + inats = append(inats, &nats[i]) + } + return inats, nil +} + +func (self *SVpc) fetchNetworks() error { + networks, total, err := self.region.GetNetworks(nil, self.VpcId, 0, 50) + if err != nil { + return err + } + if total > len(networks) { + networks, _, err = self.region.GetNetworks(nil, self.VpcId, 0, total) + if err != nil { + return err + } + } + for i := 0; i < len(networks); i += 1 { + wire := self.getWireByZoneId(networks[i].Zone) + networks[i].wire = wire + wire.addNetwork(&networks[i]) + } + return nil +} + +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) GetIWires() ([]cloudprovider.ICloudWire, error) { + if self.iwires == nil { + err := self.fetchNetworks() + if err != nil { + return nil, err + } + } + return self.iwires, nil +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +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) addWire(wire *SWire) { + if self.iwires == nil { + self.iwires = make([]cloudprovider.ICloudWire, 0) + } + self.iwires = append(self.iwires, wire) +} + +func (self *SVpc) GetSVpcPeeringConnections() ([]SVpcPC, error) { + svpcPCs, err := self.region.GetAllVpcPeeringConnections(self.GetId()) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetAllVpcPeeringConnections(%s)", self.GetId()) + } + ret := []SVpcPC{} + for i := range svpcPCs { + if svpcPCs[i].UnVpcID == self.VpcId { + svpcPCs[i].vpc = self + ret = append(ret, svpcPCs[i]) + } + } + return ret, nil +} + +func (self *SVpc) GetAccepterSVpcPeeringConnections() ([]SVpcPC, error) { + result := []SVpcPC{} + svpcPCs, err := self.region.GetAllVpcPeeringConnections("") + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetAllVpcPeeringConnections(%s)", self.GetId()) + } + + for i := range svpcPCs { + if svpcPCs[i].PeerVpcID == self.GetId() { + svpcPCs[i].vpc = self + result = append(result, svpcPCs[i]) + } + + } + return result, nil +} + +func (self *SVpc) GetSVpcPeeringConnectionById(id string) (*SVpcPC, error) { + svpcPC, err := self.region.GetVpcPeeringConnectionbyId(id) + if err != nil { + return nil, errors.Wrapf(err, "self.region.GetVpcPeeringConnectionbyId(%s)", id) + } + svpcPC.vpc = self + return svpcPC, nil +} + +func (self *SVpc) CreateSVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPC, error) { + vpcPCId, err := self.region.CreateVpcPeeringConnection(self.GetId(), opts) + if err != nil { + return nil, errors.Wrapf(err, "self.region.CreateVpcPeeringConnection(%s, %s)", self.GetId(), jsonutils.Marshal(opts).String()) + } + SvpcPC, err := self.GetSVpcPeeringConnectionById(vpcPCId) + if err != nil { + return nil, errors.Wrapf(err, "self.GetSVpcPeeringConnectionById(%s)", vpcPCId) + } + return SvpcPC, nil +} + +func (self *SVpc) CreateCrossRegionSVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (*SVpcPC, error) { + taskId, err := self.region.CreateVpcPeeringConnectionEx(self.GetId(), opts) + if err != nil { + return nil, errors.Wrapf(err, "self.region.CreateVpcPeeringConnectionEx(%s, %s)", self.GetId(), jsonutils.Marshal(opts).String()) + } + err = cloudprovider.Wait(time.Second*5, time.Minute*6, func() (bool, error) { + status, err := self.region.DescribeVpcTaskResult(fmt.Sprintf("%d", taskId)) + if err != nil { + return false, errors.Wrap(err, "self.vpc.region.DescribeVpcTaskResult") + } + //任务的当前状态。0:成功,1:失败,2:进行中。 + if status == 1 { + return false, errors.Wrapf(fmt.Errorf("taskfailed,taskId=%d", taskId), "client.DescribeVpcTaskResult(taskId)") + } + if status == 0 { + return true, nil + } + return false, nil + }) + if err != nil { + return nil, errors.Wrapf(err, "cloudprovider.Wait %d", taskId) + } + svpcPCs, err := self.GetSVpcPeeringConnections() + if err != nil { + return nil, errors.Wrap(err, "self.GetSVpcPeeringConnections()") + } + for i := range svpcPCs { + if svpcPCs[i].GetPeerVpcId() == opts.PeerVpcId { + return &svpcPCs[i], nil + } + } + return nil, errors.Wrap(cloudprovider.ErrNotFound, "vpcPeeringConnection not found after createEx") +} + +func (self *SVpc) AcceptSVpcPeeringConnection(id string) error { + err := self.region.AcceptVpcPeeringConnection(id) + if err != nil { + return errors.Wrapf(err, "self.region.AcceptVpcPeeringConnection(%s)", id) + } + return nil +} + +func (self *SVpc) AcceptCrossRegionSVpcPeeringConnection(id string) error { + taskId, err := self.region.AcceptVpcPeeringConnectionEx(id) + if err != nil { + return errors.Wrapf(err, "self.region.AcceptVpcPeeringConnectionEx(%s)", id) + } + err = cloudprovider.Wait(time.Second*5, time.Minute*6, func() (bool, error) { + status, err := self.region.DescribeVpcTaskResult(fmt.Sprintf("%d", taskId)) + if err != nil { + return false, errors.Wrap(err, "self.vpc.region.DescribeVpcTaskResult") + } + //任务的当前状态。0:成功,1:失败,2:进行中。 + if status == 1 { + return false, errors.Wrap(fmt.Errorf("taskfailed,taskId=%d", taskId), "client.DescribeVpcTaskResult(taskId)") + } + if status == 0 { + return true, nil + } + return false, nil + }) + if err != nil { + return errors.Wrapf(err, " cloudprovider.Wait %d", taskId) + } + svpcPC, err := self.GetSVpcPeeringConnectionById(id) + if err != nil { + return errors.Wrapf(err, "self.GetSVpcPeeringConnectionById(%s)", id) + } + if svpcPC.GetStatus() != api.VPC_PEERING_CONNECTION_STATUS_ACTIVE { + return errors.Wrap(cloudprovider.ErrInvalidStatus, "invalid status after AcceptCrossRegionSVpcPeeringConnection") + } + return nil +} + +func (self *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + result := []cloudprovider.ICloudVpcPeeringConnection{} + SVpcPCs, err := self.GetSVpcPeeringConnections() + if err != nil { + return nil, errors.Wrap(err, "self.GetSVpcPeeringConnections()") + } + for i := range SVpcPCs { + result = append(result, &SVpcPCs[i]) + } + return result, nil +} + +func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + result := []cloudprovider.ICloudVpcPeeringConnection{} + SVpcPCs, err := self.GetAccepterSVpcPeeringConnections() + if err != nil { + return nil, errors.Wrap(err, "self.GetSVpcPeeringConnections()") + } + for i := range SVpcPCs { + result = append(result, &SVpcPCs[i]) + } + return result, nil +} + +func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { + svpcPC, err := self.GetSVpcPeeringConnectionById(id) + if err != nil { + return nil, errors.Wrapf(err, "self.GetSVpcPeeringConnectionById(%s)", id) + } + return svpcPC, nil +} + +func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { + if self.GetRegion().GetId() == opts.PeerRegionId { + return self.CreateSVpcPeeringConnection(opts) + } else { + return self.CreateCrossRegionSVpcPeeringConnection(opts) + } +} + +func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { + svpcPC, err := self.GetSVpcPeeringConnectionById(id) + if err != nil { + return errors.Wrapf(err, "self.GetSVpcPeeringConnectionById(%s)", id) + } + if svpcPC.GetStatus() == api.VPC_PEERING_CONNECTION_STATUS_ACTIVE { + return nil + } + + if !svpcPC.IsCrossRegion() { + return self.AcceptSVpcPeeringConnection(id) + } else { + return self.AcceptCrossRegionSVpcPeeringConnection(id) + } +} + +func (self *SVpc) GetAuthorityOwnerId() string { + return self.region.client.ownerName +} + +func (self *SVpc) ProposeJoinICloudInterVpcNetwork(opts *cloudprovider.SVpcJointInterVpcNetworkOption) error { + instance := SCcnAttachInstanceInput{ + InstanceType: "VPC", + InstanceId: self.GetId(), + InstanceRegion: self.region.GetId(), + } + err := self.region.AttachCcnInstances(opts.InterVpcNetworkId, opts.NetworkAuthorityOwnerId, []SCcnAttachInstanceInput{instance}) + if err != nil { + return errors.Wrapf(err, "self.region.AttachCcnInstance(%s,%s,%s)", jsonutils.Marshal(opts).String(), self.GetId(), self.region.GetId()) + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/vpc_peering_connection.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/vpc_peering_connection.go new file mode 100644 index 0000000000..397c6861c9 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/vpc_peering_connection.go @@ -0,0 +1,287 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpcPC struct { + multicloud.SResourceBase + QcloudTags + vpc *SVpc + VpcID string `json:"vpcId"` + UnVpcID string `json:"unVpcId"` + PeerVpcID string `json:"peerVpcId"` + UnPeerVpcID string `json:"unPeerVpcId"` + AppID string `json:"appId"` + PeeringConnectionID string `json:"peeringConnectionId"` + PeeringConnectionName string `json:"peeringConnectionName"` + State int `json:"state"` + CreateTime string `json:"createTime"` + Uin string `json:"uin"` + PeerUin string `json:"peerUin"` + Region string `json:"region"` + PeerRegion string `json:"peerRegion"` +} + +func (region *SRegion) DescribeVpcPeeringConnections(vpcId string, peeringConnectionId string, offset int, limit int) ([]SVpcPC, int, error) { + if limit > 50 || limit <= 0 { + limit = 50 + } + params := make(map[string]string) + params["offset"] = fmt.Sprintf("%d", offset) + params["limit"] = fmt.Sprintf("%d", limit) + if len(vpcId) > 0 { + params["vpcId"] = vpcId + } + if len(peeringConnectionId) > 0 { + params["peeringConnectionId"] = peeringConnectionId + } + body, err := region.vpc2017Request("DescribeVpcPeeringConnections", params) + if err != nil { + return nil, 0, errors.Wrapf(err, `region.vpcRequest("DescribeVpcPeeringConnections", %s)`, jsonutils.Marshal(params).String()) + } + + total, _ := body.Float("totalCount") + if total <= 0 { + return nil, int(total), nil + } + + vpcPCs := make([]SVpcPC, 0) + err = body.Unmarshal(&vpcPCs, "data") + if err != nil { + return nil, 0, errors.Wrapf(err, "body.Unmarshal(&vpcPCs,%s)", body.String()) + } + return vpcPCs, int(total), nil +} + +func (region *SRegion) GetAllVpcPeeringConnections(vpcId string) ([]SVpcPC, error) { + result := []SVpcPC{} + for { + vpcPCS, total, err := region.DescribeVpcPeeringConnections(vpcId, "", len(result), 50) + if err != nil { + return nil, errors.Wrapf(err, `client.DescribeVpcPeeringConnections(%s,"",%d,50)`, vpcId, len(result)) + } + result = append(result, vpcPCS...) + if total <= len(result) { + break + } + } + return result, nil +} + +func (region *SRegion) GetVpcPeeringConnectionbyId(vpcPCId string) (*SVpcPC, error) { + vpcPCs, _, err := region.DescribeVpcPeeringConnections("", vpcPCId, 0, 50) + if err != nil { + return nil, errors.Wrapf(err, `client.DescribeVpcPeeringConnections("", %s, 0, 50)`, vpcPCId) + } + if len(vpcPCs) < 1 { + return nil, errors.Wrapf(cloudprovider.ErrNotFound, "GetVpcPeeringConnectionbyId(%s)", vpcPCId) + } + if len(vpcPCs) > 1 { + return nil, errors.Wrapf(cloudprovider.ErrDuplicateId, "GetVpcPeeringConnectionbyId(%s)", vpcPCId) + } + return &vpcPCs[0], nil +} + +func (region *SRegion) CreateVpcPeeringConnection(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (string, error) { + params := make(map[string]string) + params["vpcId"] = vpcId + params["peerVpcId"] = opts.PeerVpcId + params["peerUin"] = opts.PeerAccountId + params["peeringConnectionName"] = opts.Name + body, err := region.vpc2017Request("CreateVpcPeeringConnection", params) + if err != nil { + return "", errors.Wrapf(err, `client.vpc2017Request("CreateVpcPeeringConnection", %s)`, jsonutils.Marshal(params).String()) + } + peeringId, err := body.GetString("peeringConnectionId") + if err != nil { + return "", errors.Wrapf(err, `%s body.GetString("peeringConnectionId")`, body.String()) + } + return peeringId, nil +} + +func (region *SRegion) AcceptVpcPeeringConnection(peeringId string) error { + params := make(map[string]string) + params["peeringConnectionId"] = peeringId + _, err := region.vpc2017Request("AcceptVpcPeeringConnection", params) + if err != nil { + return errors.Wrapf(err, `client.vpc2017Request("AcceptVpcPeeringConnection",%s)`, jsonutils.Marshal(params).String()) + } + return nil +} + +func (region *SRegion) DeleteVpcPeeringConnection(peeringId string) error { + params := make(map[string]string) + params["peeringConnectionId"] = peeringId + _, err := region.vpc2017Request("DeleteVpcPeeringConnection", params) + if err != nil { + return errors.Wrapf(err, `client.vpc2017Request("DeleteVpcPeeringConnection",%s)`, jsonutils.Marshal(params).String()) + } + return nil +} + +func (region *SRegion) CreateVpcPeeringConnectionEx(vpcId string, opts *cloudprovider.VpcPeeringConnectionCreateOptions) (int64, error) { + params := make(map[string]string) + params["vpcId"] = vpcId + params["peerVpcId"] = opts.PeerVpcId + params["peerUin"] = opts.PeerAccountId + params["peeringConnectionName"] = opts.Name + params["peerRegion"] = opts.PeerRegionId + params["bandwidth"] = fmt.Sprintf("%d", opts.Bandwidth) + body, err := region.vpc2017Request("CreateVpcPeeringConnectionEx", params) + if err != nil { + return 0, errors.Wrapf(err, `client.vpc2017Request("CreateVpcPeeringConnectionEx", %s)`, jsonutils.Marshal(params).String()) + } + taskId, err := body.Int("taskId") + if err != nil { + return 0, errors.Wrapf(err, `%s body.Int("taskId")`, body.String()) + } + return taskId, nil +} + +func (region *SRegion) DescribeVpcTaskResult(taskId string) (int, error) { + params := make(map[string]string) + params["taskId"] = taskId + body, err := region.vpc2017Request("DescribeVpcTaskResult", params) + if err != nil { + return 0, errors.Wrapf(err, `client.vpc2017Request("DescribeVpcTaskResult",%s)`, taskId) + } + status, err := body.Float("data", "status") + if err != nil { + return 0, errors.Wrapf(err, `%s body.Int("data.status")`, body.String()) + } + return int(status), nil +} + +func (region *SRegion) AcceptVpcPeeringConnectionEx(peeringId string) (int64, error) { + params := make(map[string]string) + params["peeringConnectionId"] = peeringId + body, err := region.vpc2017Request("AcceptVpcPeeringConnectionEx", params) + if err != nil { + return 0, errors.Wrapf(err, `client.vpc2017Request("AcceptVpcPeeringConnectionEx", %s)`, jsonutils.Marshal(params).String()) + } + taskId, err := body.Int("taskId") + if err != nil { + return 0, errors.Wrapf(err, `%s body.Int("taskId")`, body.String()) + } + return taskId, nil +} + +func (region *SRegion) DeleteVpcPeeringConnectionEx(peeringId string) (int64, error) { + params := make(map[string]string) + params["peeringConnectionId"] = peeringId + body, err := region.vpc2017Request("DeleteVpcPeeringConnectionEx", params) + if err != nil { + return 0, errors.Wrapf(err, `client.vpc2017Request("DeleteVpcPeeringConnectionEx",%s)`, jsonutils.Marshal(params).String()) + } + taskId, err := body.Int("taskId") + if err != nil { + return 0, errors.Wrapf(err, `%s body.Int("taskId")`, body.String()) + } + return taskId, nil +} + +func (self *SVpcPC) GetId() string { + return self.PeeringConnectionID +} + +func (self *SVpcPC) GetName() string { + return self.PeeringConnectionName +} + +func (self *SVpcPC) GetGlobalId() string { + return self.GetId() +} + +func (self *SVpcPC) GetStatus() string { + switch self.State { + case 1: + return api.VPC_PEERING_CONNECTION_STATUS_ACTIVE + case 0: + return api.VPC_PEERING_CONNECTION_STATUS_PENDING_ACCEPT + default: + return api.VPC_PEERING_CONNECTION_STATUS_UNKNOWN + } +} + +func (self *SVpcPC) Refresh() error { + svpcPC, err := self.vpc.region.GetVpcPeeringConnectionbyId(self.GetId()) + if err != nil { + return errors.Wrapf(err, "self.vpc.region.GetVpcPeeringConnectionbyId(%s)", self.GetId()) + } + return jsonutils.Update(self, svpcPC) +} + +func (self *SVpcPC) GetPeerVpcId() string { + return self.UnPeerVpcID +} + +func (self *SVpcPC) GetPeerAccountId() string { + if strings.Contains(self.PeerUin, ".") { + return strings.Split(self.PeerUin, ".")[0] + } + return self.PeerUin +} + +func (self *SVpcPC) GetEnabled() bool { + return true +} + +func (self *SVpcPC) Delete() error { + if !self.IsCrossRegion() { + return self.vpc.region.DeleteVpcPeeringConnection(self.GetId()) + } + taskId, err := self.vpc.region.DeleteVpcPeeringConnectionEx(self.GetId()) + if err != nil { + return errors.Wrapf(err, "self.vpc.region.DeleteVpcPeeringConnection(%s)", self.GetId()) + } + //err = self.vpc.region.WaitVpcTask(fmt.Sprintf("%d", taskId), time.Second*5, time.Minute*10) + err = cloudprovider.Wait(time.Second*5, time.Minute*6, func() (bool, error) { + status, err := self.vpc.region.DescribeVpcTaskResult(fmt.Sprintf("%d", taskId)) + if err != nil { + return false, errors.Wrap(err, "self.vpc.region.DescribeVpcTaskResult") + } + //任务的当前状态。0:成功,1:失败,2:进行中。 + if status == 1 { + return false, errors.Wrap(fmt.Errorf("taskfailed,taskId=%d", taskId), "client.DescribeVpcTaskResult(taskId)") + } + if status == 0 { + return true, nil + } + return false, nil + }) + if err != nil { + return errors.Wrapf(err, "self.region.WaitTask(%d)", taskId) + } + return nil +} + +func (self *SVpcPC) IsCrossRegion() bool { + if len(self.Region) == 0 { + return false + } + return self.Region != self.PeerRegion +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/wire.go new file mode 100644 index 0000000000..8feee936d8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/wire.go @@ -0,0 +1,156 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + QcloudTags + 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) IsEmulated() bool { + return true +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SWire) Refresh() error { + return nil +} + +func (self *SWire) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.zone.GetGlobalId()) +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SWire) GetBandwidth() int { + return 10000 +} + +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].(*SNetwork) + if network.SubnetId == networkId { + return network + } + } + return nil +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + networkId, err := self.zone.region.CreateNetwork(self.zone.Zone, self.vpc.VpcId, opts.Name, opts.Cidr, opts.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 vswitch after create????") + return nil, cloudprovider.ErrNotFound + } + return network, nil +} + +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) 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].(*SNetwork) + if network.SubnetId == networkId { + return network + } + } + return nil +} + +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) 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.SubnetId { + find = true + break + } + } + if !find { + self.inetworks = append(self.inetworks, network) + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/zone.go new file mode 100644 index 0000000000..27a784d2ef --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/qcloud/zone.go @@ -0,0 +1,312 @@ +// Copyright 2019 Yunion +// +// 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 qcloud + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type InstanceChargeType string + +const ( + PrePaidInstanceChargeType InstanceChargeType = "PREPAID" + PostPaidInstanceChargeType InstanceChargeType = "POSTPAID_BY_HOUR" + CdhPaidInstanceChargeType InstanceChargeType = "CDHPAID" + DefaultInstanceChargeType = PostPaidInstanceChargeType +) + +type SZone struct { + multicloud.SResourceBase + QcloudTags + region *SRegion + + iwires []cloudprovider.ICloudWire + + host *SHost + + istorages []cloudprovider.ICloudStorage + + instanceTypes []string + refreshTime time.Time + localstorages []string + cloudstorages []string + + Zone string + ZoneName string + ZoneState string +} + +func (self *SZone) GetId() string { + return self.Zone +} + +func (self *SZone) GetName() string { + return self.ZoneName +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + en := self.ZoneName + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.Zone) +} + +func (self *SZone) IsEmulated() bool { + return false +} + +func (self *SZone) Refresh() error { + // do nothing + return nil +} + +func (self *SZone) GetStatus() string { + if self.ZoneState == "AVAILABLE" { + return api.ZONE_ENABLE + } + return api.ZONE_SOLDOUT +} + +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) GetIHosts() ([]cloudprovider.ICloudHost, error) { + return []cloudprovider.ICloudHost{self.getHost()}, nil +} + +func (self *SZone) getHost() *SHost { + if self.host == nil { + self.host = &SHost{zone: self} + } + return self.host +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +type SDiskConfigSet struct { + Available bool + DeviceClass string + DiskChargeType string + DiskType string + DiskUsage string + InstanceFamily string + MaxDiskSize int + MinDiskSize int + Zone string +} + +func (self *SRegion) GetDiskConfigSet(zoneName string) ([]SDiskConfigSet, error) { + params := map[string]string{} + params["Region"] = self.Region + params["Zones.0"] = zoneName + params["InquiryType"] = "INQUIRY_CBS_CONFIG" + body, err := self.cbsRequest("DescribeDiskConfigQuota", params) + if err != nil { + return nil, err + } + diskConfigSet := []SDiskConfigSet{} + return diskConfigSet, body.Unmarshal(&diskConfigSet, "DiskConfigSet") +} + +func (self *SZone) fetchStorages() error { + self.istorages = []cloudprovider.ICloudStorage{} + diskConfigSet, err := self.region.GetDiskConfigSet(self.Zone) + if err != nil { + return err + } + self.cloudstorages = []string{} + for _, diskConfig := range diskConfigSet { + if !utils.IsInStringArray(strings.ToUpper(diskConfig.DiskType), self.cloudstorages) { + self.cloudstorages = append(self.cloudstorages, strings.ToUpper(diskConfig.DiskType)) + storage := SStorage{zone: self, storageType: diskConfig.DiskType, available: diskConfig.Available} + self.istorages = append(self.istorages, &storage) + } + } + for _, storageType := range []string{"CLOUD_PREMIUM", "CLOUD_SSD", "CLOUD_BASIC"} { + if !utils.IsInStringArray(storageType, self.cloudstorages) { + self.cloudstorages = append(self.cloudstorages, storageType) + storage := SStorage{zone: self, storageType: storageType, available: false} + self.istorages = append(self.istorages, &storage) + } + } + self.localstorages, err = self.region.GetZoneLocalStorages(self.Zone) + if err != nil { + log.Errorf("falied to fetch local storage for zone %s", self.Zone) + } + for _, localstorageType := range self.localstorages { + storage := SLocalStorage{zone: self, storageType: localstorageType, available: true} + self.istorages = append(self.istorages, &storage) + } + for _, storageType := range QCLOUD_LOCAL_STORAGE_TYPES { + if !utils.IsInStringArray(storageType, self.localstorages) { + storage := SLocalStorage{zone: self, storageType: storageType, available: false} + self.istorages = append(self.istorages, &storage) + } + } + return nil +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "fetchStorages") + } + } + return self.istorages, nil +} + +func (self *SZone) getLocalStorageByCategory(category string) (*SLocalStorage, error) { + if len(self.localstorages) == 0 { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrap(err, "fetchStorages") + } + } + if utils.IsInStringArray(strings.ToUpper(category), self.localstorages) { + return &SLocalStorage{zone: self, storageType: strings.ToUpper(category)}, nil + } + return nil, fmt.Errorf("No such storage %s", category) +} + +func (self *SZone) validateStorageType(category string) error { + if len(self.localstorages) == 0 || len(self.cloudstorages) == 0 { + err := self.fetchStorages() + if err != nil { + return errors.Wrap(err, "fetchStorages") + } + } + if utils.IsInStringArray(strings.ToUpper(category), self.localstorages) || utils.IsInStringArray(strings.ToUpper(category), self.cloudstorages) { + return nil + } + return fmt.Errorf("No such storage %s", category) +} + +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++ { + if utils.IsInStringArray(storages[i].GetStorageType(), self.localstorages) { + continue + //return &SStorage{zone: self, storageType: strings.ToUpper(storages[i].GetStorageType())}, nil + } + storage := storages[i].(*SStorage) + if strings.ToLower(storage.storageType) == strings.ToLower(category) { + return storage, nil + } + } + return nil, fmt.Errorf("No such storage %s", category) +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "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) addWire(wire *SWire) { + if self.iwires == nil { + self.iwires = make([]cloudprovider.ICloudWire, 0) + } + self.iwires = append(self.iwires, wire) +} + +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) fetchInstanceTypes() { + self.instanceTypes = []string{} + params := map[string]string{} + params["Region"] = self.region.Region + params["Filters.0.Name"] = "zone" + params["Filters.0.Values.0"] = self.Zone + if body, err := self.region.cvmRequest("DescribeInstanceTypeConfigs", params, true); err != nil { + log.Errorf("DescribeInstanceTypeConfigs error: %v", err) + } else if configSet, err := body.GetArray("InstanceTypeConfigSet"); err != nil { + log.Errorf("Get InstanceTypeConfigSet error: %v", err) + } else { + for _, config := range configSet { + if instanceType, err := config.GetString("InstanceType"); err == nil && !utils.IsInStringArray(instanceType, self.instanceTypes) { + self.instanceTypes = append(self.instanceTypes, instanceType) + } + } + self.refreshTime = time.Now() + } +} + +func (self *SZone) getAvaliableInstanceTypes() []string { + if self.instanceTypes == nil || len(self.instanceTypes) == 0 || time.Now().Sub(self.refreshTime).Hours() > refreshHours() { + self.fetchInstanceTypes() + } + return self.instanceTypes +} + +func refreshHours() float64 { + return 5 +} + +func (self *SZone) getCosEndpoint() string { + return fmt.Sprintf("cos.%s.myqcloud.com", self.GetId()) +} + +func (self *SZone) getCosWebsiteEndpoint() string { + return fmt.Sprintf("cos-website.%s.myqcloud.com", self.GetId()) +} diff --git a/pkg/multicloud/region_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/region_base.go similarity index 99% rename from pkg/multicloud/region_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/region_base.go index 790049e27e..ae0134c3e3 100644 --- a/pkg/multicloud/region_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/region_base.go @@ -19,7 +19,7 @@ import ( "yunion.io/x/pkg/errors" - "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SRegion struct { diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/bucket.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/bucket.go new file mode 100644 index 0000000000..c960a025ca --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/bucket.go @@ -0,0 +1,185 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "context" + "io" + "net/http" + "time" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SBucket struct { + SResourceBase + + region *SRegion + + RegionId string + MaxPart int + MaxPartBytes int64 + Acl string + Location string + StorageClass string + AccessUrls []cloudprovider.SBucketAccessUrl + + Stats cloudprovider.SBucketStats + Limit cloudprovider.SBucketStats +} + +func (self *SBucket) MaxPartCount() int { + return self.MaxPart +} + +func (self *SBucket) MaxPartSizeBytes() int64 { + return self.MaxPartBytes +} + +func (self *SBucket) GetAcl() cloudprovider.TBucketACLType { + return cloudprovider.TBucketACLType(self.Acl) +} + +func (self *SBucket) GetLocation() string { + return self.Location +} + +func (self *SBucket) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SBucket) GetStorageClass() string { + return self.StorageClass +} + +func (self *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { + return self.AccessUrls +} + +func (self *SBucket) GetStats() cloudprovider.SBucketStats { + return self.Stats +} + +func (self *SBucket) GetLimit() cloudprovider.SBucketStats { + return self.Limit +} + +func (self *SBucket) SetLimit(limit cloudprovider.SBucketStats) error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) LimitSupport() cloudprovider.SBucketStats { + return self.Limit +} + +func (self *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) SetAcl(acl cloudprovider.TBucketACLType) error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { + return cloudprovider.SListObjectResult{}, cloudprovider.ErrNotSupported +} + +func (self *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SBucket) DeleteObject(ctx context.Context, keys string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SBucket) PutObject(ctx context.Context, key string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucketName string, srcKey string, srcOffset int64, srcLength int64) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) SetWebsite(conf cloudprovider.SBucketWebsiteConf) error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) GetWebsiteConf() (cloudprovider.SBucketWebsiteConf, error) { + return cloudprovider.SBucketWebsiteConf{}, cloudprovider.ErrNotSupported +} + +func (self *SBucket) DeleteWebSiteConf() error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) SetCORS(rules []cloudprovider.SBucketCORSRule) error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) GetCORSRules() ([]cloudprovider.SBucketCORSRule, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SBucket) DeleteCORS() error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) SetReferer(conf cloudprovider.SBucketRefererConf) error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) GetReferer() (cloudprovider.SBucketRefererConf, error) { + return cloudprovider.SBucketRefererConf{}, cloudprovider.ErrNotSupported +} + +func (self *SBucket) GetCdnDomains() ([]cloudprovider.SCdnDomain, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SBucket) GetPolicy() ([]cloudprovider.SBucketPolicyStatement, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SBucket) SetPolicy(policy cloudprovider.SBucketPolicyStatementInput) error { + return cloudprovider.ErrNotSupported +} + +func (self *SBucket) DeletePolicy(id []string) ([]cloudprovider.SBucketPolicyStatement, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SBucket) ListMultipartUploads() ([]cloudprovider.SBucketMultipartUploads, error) { + return nil, cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/dbinstance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/dbinstance.go new file mode 100644 index 0000000000..ce3eab4dc3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/dbinstance.go @@ -0,0 +1,216 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "context" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SDBInstance struct { + SResourceBase + + region *SRegion + RegionId string + SecurityGroupIds []string + Port int + Engine string + EngineVersion string + InstanceType string + VcpuCount int + VmemSizeMb int + DiskSizeGb int + DiskSizeUsedGb int + Category string + StorageType string + MaintainTime string + ConnectionStr string + InternalConnectionStr string + Zone1Id string + Zone2Id string + Zone3Id string + VpcId string + Iops int +} + +func (self *SDBInstance) Reboot() error { + return cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) GetMasterInstanceId() string { + return "" +} + +func (self *SDBInstance) GetSecurityGroupIds() ([]string, error) { + return self.SecurityGroupIds, nil +} + +func (self *SDBInstance) SetSecurityGroups(ids []string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) GetPort() int { + return self.Port +} + +func (self *SDBInstance) GetEngine() string { + return self.Engine +} + +func (self *SDBInstance) GetEngineVersion() string { + return self.EngineVersion +} + +func (self *SDBInstance) GetInstanceType() string { + return self.InstanceType +} + +func (self *SDBInstance) GetVcpuCount() int { + return self.VcpuCount +} + +func (self *SDBInstance) GetVmemSizeMB() int { + return self.VmemSizeMb +} + +func (self *SDBInstance) GetDiskSizeGB() int { + return self.DiskSizeGb +} + +func (self *SDBInstance) GetDiskSizeUsedMB() int { + return self.DiskSizeUsedGb +} + +func (self *SDBInstance) GetCategory() string { + return self.Category +} + +func (self *SDBInstance) GetStorageType() string { + return self.StorageType +} + +func (self *SDBInstance) GetMaintainTime() string { + return self.MaintainTime +} + +func (self *SDBInstance) GetConnectionStr() string { + return self.ConnectionStr +} + +func (self *SDBInstance) GetInternalConnectionStr() string { + return self.InternalConnectionStr +} + +func (self *SDBInstance) GetZone1Id() string { + return self.Zone1Id +} + +func (self *SDBInstance) GetZone2Id() string { + return self.Zone2Id +} + +func (self *SDBInstance) GetZone3Id() string { + return self.Zone3Id +} + +func (self *SDBInstance) GetIVpcId() string { + return self.VpcId +} + +func (self *SDBInstance) GetIops() int { + return self.Iops +} + +func (self *SDBInstance) GetDBNetworks() ([]cloudprovider.SDBInstanceNetwork, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDBInstance) GetIDBInstanceParameters() ([]cloudprovider.ICloudDBInstanceParameter, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SDBInstance) GetIDBInstanceDatabases() ([]cloudprovider.ICloudDBInstanceDatabase, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) GetIDBInstanceAccounts() ([]cloudprovider.ICloudDBInstanceAccount, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) GetIDBInstanceBackups() ([]cloudprovider.ICloudDBInstanceBackup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedDBInstanceChangeConfig) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) OpenPublicConnection() error { + return cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) ClosePublicConnection() error { + return cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) CreateDatabase(conf *cloudprovider.SDBInstanceDatabaseCreateConfig) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) CreateAccount(conf *cloudprovider.SDBInstanceAccountCreateConfig) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) CreateIBackup(conf *cloudprovider.SDBInstanceBackupCreateConfig) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) RecoveryFromBackup(conf *cloudprovider.SDBInstanceRecoveryConfig) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDBInstance) Delete() error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetIDBInstances() ([]cloudprovider.ICloudDBInstance, error) { + res, err := self.client.GetDBInstances() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudDBInstance{} + for i := range res { + if res[i].RegionId != self.GetId() { + continue + } + res[i].region = self + ret = append(ret, &res[i]) + } + return ret, nil +} + +func (self *SRegion) GetIDBInstanceById(id string) (cloudprovider.ICloudDBInstance, error) { + res, err := self.GetIDBInstances() + if err != nil { + return nil, err + } + for i := range res { + if res[i].GetGlobalId() == id { + return res[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/disk.go new file mode 100644 index 0000000000..297bbd6a32 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/disk.go @@ -0,0 +1,131 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "context" + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SDisk struct { + SResourceBase + + storage *SStorage + ZoneId string + StorageId string + DiskFormat string + DiskSizeMb int + IsAutoDelete bool + DiskType string + FsFormat string + Iops int + Driver string + CacheMode string + Mountpoint string + AccessPath string +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + if self.storage == nil { + return nil, fmt.Errorf("disk %s(%s) missing storage", self.Name, self.Id) + } + return self.storage, nil +} + +func (self *SDisk) GetIStorageId() string { + return self.StorageId +} + +func (self *SDisk) GetDiskFormat() string { + return self.DiskFormat +} + +func (self *SDisk) GetDiskSizeMB() int { + return self.DiskSizeMb +} + +func (self *SDisk) GetIsAutoDelete() bool { + return self.IsAutoDelete +} + +func (self *SDisk) GetTemplateId() string { + return "" +} + +func (self *SDisk) GetDiskType() string { + if len(self.DiskType) == 0 { + return api.DISK_TYPE_DATA + } + return self.DiskType +} + +func (self *SDisk) GetFsFormat() string { + return self.FsFormat +} + +func (self *SDisk) GetIsNonPersistent() bool { + return false +} + +func (self *SDisk) GetIops() int { + return self.Iops +} + +func (self *SDisk) GetDriver() string { + return self.Driver +} + +func (self *SDisk) GetCacheMode() string { + return self.CacheMode +} + +func (self *SDisk) GetMountpoint() string { + return self.Mountpoint +} + +func (self *SDisk) GetAccessPath() string { + return self.AccessPath +} + +func (self *SDisk) Delete(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SDisk) GetExtSnapshotPolicyIds() ([]string, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { + return cloudprovider.ErrNotSupported +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/doc.go new file mode 100644 index 0000000000..f5b36586be --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/doc.go @@ -0,0 +1 @@ +package remotefile // import "yunion.io/x/cloudmux/pkg/multicloud/remotefile" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/eip.go new file mode 100644 index 0000000000..937e897c49 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/eip.go @@ -0,0 +1,73 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SEip struct { + SResourceBase + + IpAddr string + RegionId string + AssociateId string + Bandwidth int +} + +func (self *SEip) GetIpAddr() string { + return self.IpAddr +} + +func (self *SEip) GetMode() string { + return api.EIP_MODE_STANDALONE_EIP +} + +func (self *SEip) GetINetworkId() string { + return "" +} + +func (self *SEip) GetAssociationType() string { + return api.EIP_ASSOCIATE_TYPE_SERVER +} + +func (self *SEip) GetAssociationExternalId() string { + return self.AssociateId +} + +func (self *SEip) GetBandwidth() int { + return self.Bandwidth +} + +func (self *SEip) GetInternetChargeType() string { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC +} + +func (self *SEip) Delete() error { + return cloudprovider.ErrNotSupported +} + +func (self *SEip) Associate(conf *cloudprovider.AssociateConfig) error { + return cloudprovider.ErrNotSupported +} + +func (self *SEip) Dissociate() error { + return cloudprovider.ErrNotSupported +} + +func (self *SEip) ChangeBandwidth(bw int) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/host.go new file mode 100644 index 0000000000..83d388550e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/host.go @@ -0,0 +1,193 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SHost struct { + SResourceBase + multicloud.SHostBase + zone *SZone + + AccessIp string + AccessMac string + ZoneId string + Enabled bool + HostStatus string + SN string + CpuCount int + NodeCount int8 + CpuDesc string + CpuMbz int + MemSizeMb int + StorageSizeMb int + StorageType string + + AttachStorageTypes []string +} + +func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SHost) GetEnabled() bool { + return self.Enabled +} + +func (self *SHost) GetHostStatus() string { + if len(self.HostStatus) == 0 { + return api.HOST_ONLINE + } + return self.HostStatus +} + +func (self *SHost) GetAccessIp() string { + return self.AccessIp +} + +func (self *SHost) GetAccessMac() string { + return self.AccessMac +} + +func (self *SHost) GetSysInfo() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (self *SHost) GetSN() string { + return self.SN +} + +func (self *SHost) GetCpuCount() int { + return self.CpuCount +} + +func (self *SHost) GetNodeCount() int8 { + return self.NodeCount +} + +func (self *SHost) GetCpuDesc() string { + return self.CpuDesc +} + +func (self *SHost) GetCpuMhz() int { + return self.CpuMbz +} + +func (self *SHost) GetCpuCmtbound() float32 { + return 1 +} + +func (self *SHost) GetMemSizeMB() int { + return self.MemSizeMb +} + +func (self *SHost) GetMemCmtbound() float32 { + return 1 +} + +func (self *SHost) GetReservedMemoryMb() int { + return 0 +} + +func (self *SHost) GetStorageSizeMB() int { + return self.StorageSizeMb +} + +func (self *SHost) GetStorageType() string { + return self.StorageType +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_REMOTEFILE +} + +func (self *SHost) GetIsMaintenance() bool { + return false +} + +func (self *SHost) GetVersion() string { + return "" +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.zone.GetIStorages() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + if utils.IsInStringArray(storages[i].GetStorageType(), self.AttachStorageTypes) { + ret = append(ret, storages[i]) + } + } + return ret, nil +} + +func (self *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storages, err := self.GetIStorages() + if err != nil { + return nil, err + } + for i := range storages { + if storages[i].GetGlobalId() == id { + return storages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms, err := self.zone.region.client.GetInstances() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudVM{} + for i := range vms { + if vms[i].HostId != self.GetId() { + continue + } + vms[i].host = self + ret = append(ret, &vms[i]) + } + return ret, nil +} + +func (self *SHost) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vms, err := self.GetIVMs() + if err != nil { + return nil, err + } + for i := range vms { + if vms[i].GetGlobalId() == id { + return vms[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + return nil, cloudprovider.ErrNotImplemented +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/instance.go new file mode 100644 index 0000000000..432ed5493a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/instance.go @@ -0,0 +1,264 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "context" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type SInstance struct { + SResourceBase + + host *SHost + + osInfo *imagetools.ImageInfo + + HostId string + Hostname string + SecurityGroupIds []string + VcpuCount int + VmemSizeMb int + BootOrder string + Vga string + Vdi string + OsArch string + OsType string + OsName string + Bios string + Machine string + InstanceType string + Bandwidth int + Throughput int + EipId string + Disks []SDisk + + Nics []SInstanceNic +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + return self.SecurityGroupIds, nil +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) StartVM(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetIHostId() string { + return self.HostId +} + +func (self *SInstance) GetInternetMaxBandwidthOut() int { + return self.Bandwidth +} + +func (self *SInstance) GetThroughput() int { + return self.Throughput +} + +func (self *SInstance) GetSerialOutput(port int) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SInstance) ConvertPublicIpToEip() error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) RebuildRoot(ctx context.Context, config *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SInstance) MigrateVM(hostid string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) LiveMigrateVM(hostid string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetError() error { + return nil +} + +func (self *SInstance) CreateInstanceSnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudInstanceSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetInstanceSnapshot(idStr string) (cloudprovider.ICloudInstanceSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetInstanceSnapshots() ([]cloudprovider.ICloudInstanceSnapshot, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SInstance) ResetToInstanceSnapshot(ctx context.Context, idStr string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstance) SaveImage(opts *cloudprovider.SaveImageOptions) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SInstance) AllocatePublicIpAddress() (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (self *SInstance) GetVcpuCount() int { + return self.VcpuCount +} + +func (self *SInstance) GetVmemSizeMB() int { + return self.VmemSizeMb +} + +func (self *SInstance) GetBootOrder() string { + return self.BootOrder +} + +func (self *SInstance) GetVga() string { + return self.Vga +} + +func (self *SInstance) GetVdi() string { + return self.Vdi +} + +func (ins *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { + if ins.osInfo == nil { + osInfo := imagetools.NormalizeImageInfo(ins.OsName, ins.OsArch, ins.OsType, "", "") + ins.osInfo = &osInfo + } + return ins.osInfo +} + +func (ins *SInstance) GetOsArch() string { + return ins.getNormalizedOsInfo().OsArch +} + +func (ins *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(ins.getNormalizedOsInfo().OsType) +} + +func (ins *SInstance) GetFullOsName() string { + return ins.OsName +} + +func (ins *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(ins.Bios) +} + +func (ins *SInstance) GetOsLang() string { + return ins.getNormalizedOsInfo().OsLang +} + +func (ins *SInstance) GetOsDist() string { + return ins.getNormalizedOsInfo().OsDistro +} + +func (ins *SInstance) GetOsVersion() string { + return ins.getNormalizedOsInfo().OsVersion +} + +func (self *SInstance) GetMachine() string { + return self.Machine +} + +func (self *SInstance) GetInstanceType() string { + return self.InstanceType +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_REMOTEFILE +} + +func (self *SInstance) GetHostname() string { + return self.Hostname +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + ret := []cloudprovider.ICloudDisk{} + for i := range self.Disks { + ret = append(ret, &self.Disks[i]) + } + return ret, nil +} + +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + return self.host.zone.region.GetIEipById(self.EipId) +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + ret := []cloudprovider.ICloudNic{} + for i := range self.Nics { + ret = append(ret, &self.Nics[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/instancenic.go new file mode 100644 index 0000000000..706f520ae1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/instancenic.go @@ -0,0 +1,64 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import "yunion.io/x/cloudmux/pkg/cloudprovider" + +type SInstanceNic struct { + SResourceBase + + Ip string + Mac string + Classic bool + Driver string + NetworkId string + SubAddr []string +} + +func (self *SInstanceNic) GetIP() string { + return self.Ip +} + +func (self *SInstanceNic) GetMAC() string { + return self.Mac +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return self.Classic +} + +func (self *SInstanceNic) GetDriver() string { + return self.Driver +} + +func (self *SInstanceNic) GetINetworkId() string { + return self.NetworkId +} + +func (self *SInstanceNic) GetSubAddress() ([]string, error) { + return self.SubAddr, nil +} + +func (self *SInstanceNic) AssignNAddress(count int) ([]string, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SInstanceNic) AssignAddress(ipAddrs []string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SInstanceNic) UnassignAddress(ipAddrs []string) error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/loadbalancer.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/loadbalancer.go new file mode 100644 index 0000000000..3e0bbd0841 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/loadbalancer.go @@ -0,0 +1,118 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "context" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SLoadbalancer struct { + SResourceBase + + region *SRegion + RegionId string + Address string + AddressType string + NetworkType string + VpcId string + ZoneId string + Zone1Id string + InstanceType string + ChargeType string + Bandwidth int + NetworkIds []string +} + +func (self *SLoadbalancer) GetAddress() string { + return self.Address +} + +func (self *SLoadbalancer) GetAddressType() string { + return self.AddressType +} + +func (self *SLoadbalancer) GetNetworkType() string { + return self.NetworkType +} + +func (self *SLoadbalancer) GetNetworkIds() []string { + return self.NetworkIds +} + +func (self *SLoadbalancer) GetVpcId() string { + return self.VpcId +} + +func (self *SLoadbalancer) GetZoneId() string { + return self.ZoneId +} + +func (self *SLoadbalancer) GetZone1Id() string { + return self.Zone1Id +} + +func (self *SLoadbalancer) GetLoadbalancerSpec() string { + return self.InstanceType +} + +func (self *SLoadbalancer) GetChargeType() string { + return self.ChargeType +} + +func (self *SLoadbalancer) GetEgressMbps() int { + return self.Bandwidth +} + +func (self *SLoadbalancer) GetIEIP() (cloudprovider.ICloudEIP, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SLoadbalancer) Delete(ctx context.Context) error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) Start() error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) Stop() error { + return cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoadbalancerListener, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) CreateILoadBalancerBackendGroup(group *cloudprovider.SLoadbalancerBackendGroup) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetILoadBalancerBackendGroupById(groupId string) (cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) CreateILoadBalancerListener(ctx context.Context, listener *cloudprovider.SLoadbalancerListener) (cloudprovider.ICloudLoadbalancerListener, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SLoadbalancer) GetILoadBalancerListenerById(listenerId string) (cloudprovider.ICloudLoadbalancerListener, error) { + return nil, cloudprovider.ErrNotSupported +} diff --git a/pkg/multicloud/remotefile/misc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/misc.go similarity index 100% rename from pkg/multicloud/remotefile/misc.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/misc.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/monitor.go new file mode 100644 index 0000000000..fd279e5a34 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/monitor.go @@ -0,0 +1,34 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +func (self *SRemoteFileClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) + } +} + +func (self *SRemoteFileClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.getMetrics(opts.ResourceType, opts.MetricType) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/network.go new file mode 100644 index 0000000000..2806c49355 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/network.go @@ -0,0 +1,68 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + SResourceBase + + wire *SWire + WireId string + IpStart string + IpEnd string + IpMask int8 + Gatway string +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpStart() string { + return self.IpStart +} + +func (self *SNetwork) GetIpEnd() string { + return self.IpEnd +} + +func (self *SNetwork) GetIpMask() int8 { + return self.IpMask +} + +func (self *SNetwork) GetGateway() string { + return self.Gatway +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) Delete() error { + return cloudprovider.ErrNotSupported +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 6 +} diff --git a/pkg/multicloud/remotefile/projects.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/projects.go similarity index 90% rename from pkg/multicloud/remotefile/projects.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/projects.go index f0c38922c6..0b88d62f18 100644 --- a/pkg/multicloud/remotefile/projects.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/projects.go @@ -15,13 +15,13 @@ package remotefile import ( - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SProject struct { multicloud.SProjectBase - multicloud.RemoteFileTags + RemoteFileTags Id string Name string diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/provider/doc.go new file mode 100644 index 0000000000..7ff3647c89 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/provider/doc.go @@ -0,0 +1 @@ +package provider // import "yunion.io/x/cloudmux/pkg/multicloud/remotefile/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/provider/provider.go new file mode 100644 index 0000000000..0a06f7fe15 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/provider/provider.go @@ -0,0 +1,155 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/remotefile" +) + +type SRemoteFileProviderFactory struct { + cloudprovider.SPrivateCloudBaseProviderFactory +} + +func (self *SRemoteFileProviderFactory) GetId() string { + return remotefile.CLOUD_PROVIDER_REMOTEFILE +} + +func (self *SRemoteFileProviderFactory) GetName() string { + return remotefile.CLOUD_PROVIDER_REMOTEFILE +} + +func (self *SRemoteFileProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AuthUrl) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "auth_url") + } + if len(input.Username) == 0 { + input.Username = "root" + } + if len(input.Password) == 0 { + input.Password = "password" + } + output.Account = input.Username + output.Secret = input.Password + output.AccessUrl = input.AuthUrl + return output, nil +} + +func (self *SRemoteFileProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + return output, cloudprovider.ErrNotSupported +} + +func (self *SRemoteFileProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + client, err := remotefile.NewRemoteFileClient( + remotefile.NewRemoteFileClientConfig( + cfg.URL, + cfg.Account, + cfg.Secret, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SRemoteFileProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SRemoteFileProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + return map[string]string{ + "REMOTEFILE_AUTH_URL": info.Url, + }, nil +} + +func init() { + factory := SRemoteFileProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SRemoteFileProvider struct { + cloudprovider.SBaseProvider + client *remotefile.SRemoteFileClient +} + +func (self *SRemoteFileProvider) GetVersion() string { + return "" +} + +func (self *SRemoteFileProvider) GetSysInfo() (jsonutils.JSONObject, error) { + return jsonutils.NewDict(), nil +} + +func (self *SRemoteFileProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SRemoteFileProvider) GetAccountId() string { + return "" +} + +func (self *SRemoteFileProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SRemoteFileProvider) GetIRegionById(id string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(id) +} + +func (self *SRemoteFileProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, cloudprovider.ErrNotSupported +} + +func (self *SRemoteFileProvider) GetCloudRegionExternalIdPrefix() string { + return self.client.GetCloudRegionExternalIdPrefix() +} + +func (self *SRemoteFileProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SRemoteFileProvider) CreateIProject(name string) (cloudprovider.ICloudProject, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRemoteFileProvider) GetStorageClasses(regionId string) []string { + return nil +} + +func (self *SRemoteFileProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (self *SRemoteFileProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (self *SRemoteFileProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SRemoteFileProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetMetrics(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/region.go new file mode 100644 index 0000000000..2000335a82 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/region.go @@ -0,0 +1,324 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + SResourceBase + multicloud.SRegion + multicloud.SRegionSecurityGroupBase + multicloud.SRegionOssBase + multicloud.SRegionLbBase + + client *SRemoteFileClient +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s%s", self.client.GetCloudRegionExternalIdPrefix(), self.Id) +} + +func (self *SRegion) GetProvider() string { + return self.client.cpcfg.Vendor +} + +func (self *SRegion) GetCloudEnv() string { + return "" +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + zones, err := self.client.GetZones() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudZone{} + for i := range zones { + if zones[i].RegionId != self.GetId() { + continue + } + zones[i].region = self + ret = append(ret, &zones[i]) + } + return ret, nil +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + zones, err := self.client.GetZones() + if err != nil { + return nil, err + } + for i := 0; i < len(zones); i += 1 { + if zones[i].RegionId != self.GetId() { + continue + } + if zones[i].GetGlobalId() == id { + zones[i].region = self + return &zones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + instances, err := region.client.GetInstances() + if err != nil { + return nil, err + } + instance := SInstance{} + for _, v := range instances { + if v.Id == id { + return &instance, nil + } + } + return nil, errors.Wrapf(errors.ErrNotFound, "GetIVMById:%s", id) +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + vpcs, err := self.client.GetVpcs() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudVpc{} + for i := range vpcs { + if vpcs[i].RegionId != self.GetId() { + continue + } + vpcs[i].region = self + ret = append(ret, &vpcs[i]) + } + return ret, nil +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + ivpcs, err := self.GetIVpcs() + if err != nil { + return nil, err + } + for i := 0; i < len(ivpcs); i += 1 { + if ivpcs[i].GetGlobalId() == id { + return ivpcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, err := self.client.GetEips() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudEIP{} + for i := range eips { + if eips[i].RegionId != self.GetId() { + continue + } + ret = append(ret, &eips[i]) + } + return ret, nil +} + +func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { + eips, err := self.GetIEips() + if err != nil { + return nil, err + } + for i := range eips { + if eips[i].GetGlobalId() == id { + return eips[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) CreateEIP(opts *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := self.client.GetSecgroups() + if err != nil { + return nil, err + } + for i := range secgroups { + if secgroups[i].GetGlobalId() == secgroupId { + return &secgroups[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := self.client.GetSecgroups() + if err != nil { + return nil, err + } + for i := range secgroups { + if secgroups[i].GetName() == opts.Name { + return &secgroups[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + lbs, err := self.client.GetLoadbalancers() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudLoadbalancer{} + for i := range lbs { + if lbs[i].RegionId != self.GetId() { + continue + } + lbs[i].region = self + ret = append(ret, &lbs[i]) + } + return ret, nil +} + +func (self *SRegion) GetILoadBalancerById(id string) (cloudprovider.ICloudLoadbalancer, error) { + lbs, err := self.GetILoadBalancers() + if err != nil { + return nil, err + } + for i := range lbs { + if lbs[i].GetGlobalId() == id { + return lbs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + buckets, err := self.client.GetBuckets() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudBucket{} + for i := range buckets { + if buckets[i].RegionId != self.GetId() { + continue + } + buckets[i].region = self + ret = append(ret, &buckets[i]) + } + return ret, nil +} + +func (self *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, error) { + buckets, err := self.GetIBuckets() + if err != nil { + return nil, err + } + for i := range buckets { + if buckets[i].GetName() == name { + return buckets[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { + buckets, err := self.GetIBuckets() + if err != nil { + return nil, err + } + for i := range buckets { + if buckets[i].GetGlobalId() == name { + return buckets[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) CreateIBucket(name string, storageClassStr string, acl string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetIMiscResources() ([]cloudprovider.ICloudMiscResource, error) { + misc, err := self.client.GetMisc() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudMiscResource{} + for i := range misc { + ret = append(ret, &misc[i]) + } + return ret, nil +} + +func (self *SRegion) GetCapabilities() []string { + return self.client.GetCapabilities() +} diff --git a/pkg/multicloud/remotefile/remotefile.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/remotefile.go similarity index 99% rename from pkg/multicloud/remotefile/remotefile.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/remotefile.go index 1afecabeff..cf08f0e24c 100644 --- a/pkg/multicloud/remotefile/remotefile.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/remotefile.go @@ -21,8 +21,8 @@ import ( "yunion.io/x/jsonutils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/pkg/multicloud/remotefile/resource.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/resource.go similarity index 94% rename from pkg/multicloud/remotefile/resource.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/resource.go index 756176c7d1..ff8adc58bb 100644 --- a/pkg/multicloud/remotefile/resource.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/resource.go @@ -17,12 +17,12 @@ package remotefile import ( "time" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SResourceBase struct { - multicloud.RemoteFileTags + RemoteFileTags multicloud.SBillingBase Id string Name string diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/securitygroup.go new file mode 100644 index 0000000000..7d75303428 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/securitygroup.go @@ -0,0 +1,48 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import "yunion.io/x/cloudmux/pkg/cloudprovider" + +type SSecurityGroup struct { + SResourceBase + + VpcId string + Desc string +} + +func (self *SSecurityGroup) GetDescription() string { + return self.Desc +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + return []cloudprovider.SecurityRule{}, nil +} + +func (self *SSecurityGroup) GetVpcId() string { + return self.VpcId +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + return cloudprovider.ErrNotSupported +} + +func (self *SSecurityGroup) GetReferences() ([]cloudprovider.SecurityGroupReference, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SSecurityGroup) Delete() error { + return cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/storage.go new file mode 100644 index 0000000000..22b6aa11ea --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/storage.go @@ -0,0 +1,111 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "yunion.io/x/jsonutils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SStorage struct { + SResourceBase + + zone *SZone + ZoneId string + StorageType string + MediumType string + CapacityMb int64 + CapacityUsedMb int64 + Enabled bool + SkipSync bool +} + +func (self *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return nil +} + +func (self *SStorage) GetIZone() cloudprovider.ICloudZone { + return self.zone +} + +func (self *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := self.zone.region.client.GetDisks() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudDisk{} + for i := range disks { + if disks[i].StorageId != self.GetId() { + continue + } + disks[i].storage = self + ret = append(ret, &disks[i]) + } + return ret, nil +} + +func (self *SStorage) GetStorageType() string { + return self.StorageType +} + +func (self *SStorage) GetMediumType() string { + return self.MediumType +} + +func (self *SStorage) GetCapacityMB() int64 { + return self.CapacityMb +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return self.CapacityUsedMb +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (self *SStorage) GetEnabled() bool { + return self.Enabled +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SStorage) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disks, err := self.GetIDisks() + if err != nil { + return nil, err + } + for i := range disks { + if disks[i].GetGlobalId() == id { + return disks[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} + +func (self *SStorage) DisableSync() bool { + return self.SkipSync +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/tag_base.go new file mode 100644 index 0000000000..c44aecd31d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/tag_base.go @@ -0,0 +1,38 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type RemoteFileTags struct { + Tags map[string]string + SysTags map[string]string +} + +func (self *RemoteFileTags) GetTags() (map[string]string, error) { + return self.Tags, nil +} + +func (self *RemoteFileTags) GetSysTags() map[string]string { + return self.SysTags +} + +func (self *RemoteFileTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/vpc.go new file mode 100644 index 0000000000..03e93603da --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/vpc.go @@ -0,0 +1,153 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + SResourceBase + + region *SRegion + + RegionId string + CidrBlock string + IsDefault bool +} + +func (self *SVpc) Delete() error { + return cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetCidrBlock() string { + return self.CidrBlock +} + +func (self *SVpc) GetIRouteTableById(id string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + wires, err := self.region.client.GetWires() + if err != nil { + return nil, err + } + zones, err := self.region.client.GetZones() + if err != nil { + return nil, err + } + zoneIds := []string{} + for i := range zones { + zoneIds = append(zoneIds, zones[i].Id) + } + ret := []cloudprovider.ICloudWire{} + for i := range wires { + if wires[i].VpcId != self.GetId() || !utils.IsInStringArray(wires[i].ZoneId, zoneIds) { + continue + } + wires[i].region = self.region + ret = append(ret, &wires[i]) + } + return ret, nil +} + +func (self *SVpc) CreateIWire(opts *cloudprovider.SWireCreateOptions) (cloudprovider.ICloudWire, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := self.region.client.GetSecgroups() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudSecurityGroup{} + for i := range secgroups { + if secgroups[i].VpcId != self.GetId() { + continue + } + ret = append(ret, &secgroups[i]) + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SVpc) GetIWireById(id string) (cloudprovider.ICloudWire, error) { + wires, err := self.GetIWires() + if err != nil { + return nil, err + } + for i := range wires { + if wires[i].GetGlobalId() == id { + return wires[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SVpc) GetINatGateways() ([]cloudprovider.ICloudNatGateway, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) CreateINatGateway(opts *cloudprovider.NatGatewayCreateOptions) (cloudprovider.ICloudNatGateway, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetICloudVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetICloudAccepterVpcPeeringConnections() ([]cloudprovider.ICloudVpcPeeringConnection, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetICloudVpcPeeringConnectionById(id string) (cloudprovider.ICloudVpcPeeringConnection, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) CreateICloudVpcPeeringConnection(opts *cloudprovider.VpcPeeringConnectionCreateOptions) (cloudprovider.ICloudVpcPeeringConnection, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) AcceptICloudVpcPeeringConnection(id string) error { + return cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetAuthorityOwnerId() string { + return "" +} + +func (self *SVpc) ProposeJoinICloudInterVpcNetwork(opts *cloudprovider.SVpcJointInterVpcNetworkOption) error { + return cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetICloudIPv6Gateways() ([]cloudprovider.ICloudIPv6Gateway, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetIsDefault() bool { + return self.IsDefault +} + +func (self *SVpc) GetRegion() cloudprovider.ICloudRegion { + return self.region +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/wire.go new file mode 100644 index 0000000000..67bee42ab3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/wire.go @@ -0,0 +1,93 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import "yunion.io/x/cloudmux/pkg/cloudprovider" + +type SWire struct { + SResourceBase + + region *SRegion + + WireId string + VpcId string + ZoneId string + Bandwidth int +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + vpcs, err := self.region.client.GetVpcs() + if err != nil { + return nil + } + for i := range vpcs { + if vpcs[i].GetId() == self.VpcId { + vpcs[i].region = self.region + return &vpcs[i] + } + } + return nil +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + zones, err := self.region.client.GetZones() + if err != nil { + return nil + } + for i := range zones { + if zones[i].GetId() == self.ZoneId { + zones[i].region = self.region + return &zones[i] + } + } + return nil +} + +func (self *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + networks, err := self.region.client.GetNetworks() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudNetwork{} + for i := range networks { + if networks[i].WireId != self.GetId() { + continue + } + networks[i].wire = self + ret = append(ret, &networks[i]) + } + return ret, nil +} + +func (self *SWire) GetBandwidth() int { + return self.Bandwidth +} + +func (self *SWire) GetINetworkById(id string) (cloudprovider.ICloudNetwork, error) { + networks, err := self.GetINetworks() + if err != nil { + return nil, err + } + for i := range networks { + if networks[i].GetGlobalId() == id { + return networks[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + return nil, cloudprovider.ErrNotSupported +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/zone.go new file mode 100644 index 0000000000..432dd9e8b4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/remotefile/zone.go @@ -0,0 +1,90 @@ +// Copyright 2019 Yunion +// +// 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 remotefile + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SZone struct { + SResourceBase + region *SRegion + + RegionId string +} + +func (self *SZone) GetIRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + hosts, err := self.region.client.GetHosts() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudHost{} + for i := range hosts { + if hosts[i].ZoneId != self.GetId() { + continue + } + hosts[i].zone = self + ret = append(ret, &hosts[i]) + } + return ret, nil +} + +func (self *SZone) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + hosts, err := self.GetIHosts() + if err != nil { + return nil, err + } + for i := range hosts { + if hosts[i].GetGlobalId() == id { + return hosts[i], nil + } + } + return nil, errors.Wrapf(cloudprovider.ErrNotFound, id) +} + +func (self *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := self.region.client.GetStorages() + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudStorage{} + for i := range storages { + if storages[i].ZoneId != self.GetId() { + continue + } + storages[i].zone = self + ret = append(ret, &storages[i]) + } + return ret, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storages, err := self.GetIStorages() + if err != nil { + return nil, err + } + for i := range storages { + if storages[i].GetGlobalId() == id { + return storages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} diff --git a/pkg/multicloud/resource_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/resource_base.go similarity index 100% rename from pkg/multicloud/resource_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/resource_base.go diff --git a/pkg/multicloud/secgroup_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/secgroup_base.go similarity index 94% rename from pkg/multicloud/secgroup_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/secgroup_base.go index 428cdc0802..db01838303 100644 --- a/pkg/multicloud/secgroup_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/secgroup_base.go @@ -14,7 +14,7 @@ package multicloud -import "yunion.io/x/onecloud/pkg/cloudprovider" +import "yunion.io/x/cloudmux/pkg/cloudprovider" type SSecurityGroup struct { SVirtualResourceBase diff --git a/pkg/multicloud/serversku_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/serversku_base.go similarity index 94% rename from pkg/multicloud/serversku_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/serversku_base.go index 3e29758dac..6e899c7279 100644 --- a/pkg/multicloud/serversku_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/serversku_base.go @@ -15,7 +15,7 @@ package multicloud import ( - api "yunion.io/x/onecloud/pkg/apis/compute" + api "yunion.io/x/cloudmux/pkg/apis/compute" ) type SServerSku struct { diff --git a/pkg/multicloud/storage_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/storage_base.go similarity index 100% rename from pkg/multicloud/storage_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/storage_base.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/tag_base.go new file mode 100644 index 0000000000..fe67eff98e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/tag_base.go @@ -0,0 +1,44 @@ +// Copyright 2019 Yunion +// +// 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 multicloud + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type STagBase struct { +} + +func (self STagBase) GetSysTags() map[string]string { + return nil +} + +func (self STagBase) GetTags() (map[string]string, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") +} + +func (self STagBase) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} + +type STag struct { + TagKey string + TagValue string + + Key string + Value string +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/client.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/client.go new file mode 100644 index 0000000000..ae5f618f8c --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/client.go @@ -0,0 +1,204 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "context" + "crypto/sha1" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +const UCLOUD_API_HOST = "https://api.ucloud.cn" + +// API返回结果对应的字段名 +var UCLOUD_API_RESULT_KEYS = map[string]string{ + "AllocateEIP": "EIPSet", + "GetProjectList": "ProjectSet", + "GetRegion": "Regions", + "DescribeVPC": "DataSet", + "DescribeImage": "ImageSet", + "DescribeIsolationGroup": "IsolationGroupSet", + "DescribeUHostInstance": "UHostSet", + "DescribeUHostTags": "TagSet", + "DescribeUDSet": "UDSet", + "DescribeUDisk": "DataSet", + "DescribeUDiskSnapshot": "DataSet", + "DescribeEIP": "EIPSet", + "DescribeFirewall": "DataSet", + "DescribeSubnet": "DataSet", + "DescribeBucket": "DataSet", + "CreateUDisk": "UDiskId", + "CreateVPC": "VPCId", + "CreateUDiskSnapshot": "SnapshotId", + "DescribeVIP": "VIPSet", +} + +type SParams struct { + data jsonutils.JSONDict +} + +type SUcloudError struct { + Action string `json:"Action"` + Message string `json:"Message"` + RetCode int64 `json:"RetCode"` +} + +func (self *SUcloudError) Error() string { + return fmt.Sprintf("Do %s failed, code: %d, %s", self.Action, self.RetCode, self.Message) +} + +func NewUcloudParams() SParams { + data := jsonutils.NewDict() + return SParams{data: *data} +} + +func (self *SParams) Set(key string, value interface{}) { + switch v := value.(type) { + case string: + self.data.Set(key, jsonutils.NewString(v)) + case int64: + self.data.Set(key, jsonutils.NewInt(v)) + case int: + self.data.Set(key, jsonutils.NewInt(int64(v))) + case bool: + self.data.Set(key, jsonutils.NewBool(v)) + case float64: + self.data.Set(key, jsonutils.NewFloat64(v)) + case float32: + self.data.Set(key, jsonutils.NewFloat32(v)) + case []string: + self.data.Set(key, jsonutils.NewStringArray(v)) + default: + log.Debugf("unsuported params type %T", value) + } +} + +func (self *SParams) SetAction(action string) { + self.data.Set("Action", jsonutils.NewString(action)) +} + +func (self *SParams) SetPagination(limit, offset int) { + if limit == 0 { + limit = 20 + } + + self.data.Set("Limit", jsonutils.NewInt(int64(limit))) + self.data.Set("Offset", jsonutils.NewInt(int64(offset))) +} + +func (self *SParams) String() string { + return self.data.String() +} + +func (self *SParams) PrettyString() string { + return self.data.PrettyString() +} + +func (self *SParams) GetParams() jsonutils.JSONDict { + return self.data +} + +// https://docs.ucloud.cn/api/summary/signature +func BuildParams(params SParams, privateKey string) jsonutils.JSONObject { + data := params.GetParams() + // remove old Signature + data.Remove("Signature") + + // 排序并计算signture + keys := data.SortedKeys() + lst := []string{} + for _, k := range keys { + lst = append(lst, k) + v, _ := data.GetString(k) + lst = append(lst, v) + } + + raw := strings.Join(lst, "") + privateKey + signture := fmt.Sprintf("%x", sha1.Sum([]byte(raw))) + + data.Set("Signature", jsonutils.NewString(signture)) + return &data +} + +func GetSignature(params SParams, privateKey string) string { + sign, _ := BuildParams(params, privateKey).GetString("Signature") + return sign +} + +func parseUcloudResponse(params SParams, resp jsonutils.JSONObject) (jsonutils.JSONObject, error) { + err := &SUcloudError{} + e := resp.Unmarshal(err) + if e != nil { + return nil, e + } + + err.Action, _ = params.data.GetString("Action") + + if err.RetCode > 0 { + if err.RetCode == 171 { + return nil, errors.Wrapf(httperrors.ErrInvalidAccessKey, err.Error()) + } + return nil, err + } + + return resp, nil +} + +func jsonRequest(client *SUcloudClient, params SParams) (jsonutils.JSONObject, error) { + ctx := context.Background() + MAX_RETRY := 3 + retry := 0 + var err error + var resp jsonutils.JSONObject + for retry < MAX_RETRY { + _, resp, err = httputils.JSONRequest( + client.httpClient, + ctx, + httputils.POST, + UCLOUD_API_HOST, + nil, + BuildParams(params, client.accessKeySecret), + client.debug) + + if err == nil { + return parseUcloudResponse(params, resp) + } + + switch e := err.(type) { + case *httputils.JSONClientError: + if e.Code >= 499 && !strings.Contains(err.Error(), cloudprovider.ErrAccountReadOnly.Error()) { + time.Sleep(3 * time.Second) + retry += 1 + continue + } else { + return nil, err + } + default: + return nil, err + } + } + + return resp, err +} diff --git a/pkg/multicloud/ucloud/consts.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/consts.go similarity index 100% rename from pkg/multicloud/ucloud/consts.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/consts.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/disk.go new file mode 100644 index 0000000000..606df2102e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/disk.go @@ -0,0 +1,456 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://docs.ucloud.cn/api/udisk-api/describe_udisk +type SDisk struct { + storage *SStorage + multicloud.SDisk + UcloudTags + + Status string `json:"Status"` + DeviceName string `json:"DeviceName"` + UHostID string `json:"UHostId"` + Tag string `json:"Tag"` + Version string `json:"Version"` + Name string `json:"Name"` + Zone string `json:"Zone"` + UHostIP string `json:"UHostIP"` + DiskType string `json:"DiskType"` + UDataArkMode string `json:"UDataArkMode"` + SnapshotLimit int `json:"SnapshotLimit"` + ExpiredTime int64 `json:"ExpiredTime"` + SnapshotCount int `json:"SnapshotCount"` + IsExpire string `json:"IsExpire"` + UDiskID string `json:"UDiskId"` + ChargeType string `json:"ChargeType"` + UHostName string `json:"UHostName"` + CreateTime int64 `json:"CreateTime"` + SizeGB int `json:"Size"` +} + +func (self *SDisk) GetProjectId() string { + return self.storage.zone.region.client.projectId +} + +func (self *SDisk) GetId() string { + return self.UDiskID +} + +func (self *SDisk) GetName() string { + if len(self.Name) == 0 { + return self.GetId() + } + + return self.Name +} + +func (self *SDisk) GetGlobalId() string { + return self.GetId() +} + +func (self *SDisk) GetStatus() string { + switch self.Status { + case "Available": + return api.DISK_READY + case "Attaching": + return api.DISK_ATTACHING + case "InUse": + return api.DISK_READY + case "Detaching": + return api.DISK_DETACHING + case "Initializating": + return api.DISK_ALLOCATING + case "Failed": + return api.DISK_ALLOC_FAILED + case "Cloning": + return api.DISK_CLONING + case "Restoring": + return api.DISK_RESET + case "RestoreFailed": + return api.DISK_RESET_FAILED + default: + return api.DISK_UNKNOWN + } +} + +func (self *SDisk) Refresh() error { + new, err := self.storage.zone.region.GetDisk(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SDisk) IsEmulated() bool { + return false +} + +func (self *SDisk) GetSysTags() map[string]string { + data := map[string]string{} + data["hypervisor"] = api.HYPERVISOR_UCLOUD + + return data +} + +// Year,Month,Dynamic,Trial +func (self *SDisk) GetBillingType() string { + switch self.ChargeType { + case "Year", "Month": + return billing_api.BILLING_TYPE_PREPAID + default: + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SDisk) GetCreatedAt() time.Time { + return time.Unix(self.CreateTime, 0) +} + +func (self *SDisk) GetExpiredAt() time.Time { + return time.Unix(self.ExpiredTime, 0) +} + +func (self *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + return self.storage, nil +} + +func (self *SDisk) GetDiskFormat() string { + return "vhd" +} + +func (self *SDisk) GetDiskSizeMB() int { + return self.SizeGB * 1024 +} + +func (self *SDisk) GetIsAutoDelete() bool { + if self.DiskType == "SystemDisk" { + return true + } + + return false +} + +func (self *SDisk) GetTemplateId() string { + if strings.Contains(self.DiskType, "SystemDisk") && len(self.UHostID) > 0 { + ins, err := self.storage.zone.region.GetInstanceByID(self.UHostID) + if err != nil { + log.Errorln(err) + } + + return ins.ImageID + } + + return "" +} + +func (self *SDisk) GetDiskType() string { + if strings.Contains(self.DiskType, "SystemDisk") { + return api.DISK_TYPE_SYS + } + + return api.DISK_TYPE_DATA +} + +func (self *SDisk) GetStorageType() string { + if self.storage == nil { + if strings.Contains(self.DiskType, "SSD") { + return api.STORAGE_UCLOUD_CLOUD_SSD + } else { + return api.STORAGE_UCLOUD_CLOUD_NORMAL + } + } + + return self.storage.storageType +} + +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) GetAccessPath() string { + return "" +} + +func (self *SDisk) Delete(ctx context.Context) error { + return self.storage.zone.region.DeleteDisk(self.Zone, self.GetId()) +} + +func (self *SDisk) CreateISnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := self.storage.zone.region.CreateSnapshot(self.Zone, self.GetId(), name, desc) + if err != nil { + return nil, err + } + + isnapshot, err := self.GetISnapshot(snapshot) + if err != nil { + return nil, err + } + + err = cloudprovider.WaitStatus(isnapshot, api.SNAPSHOT_READY, time.Second*10, time.Second*300) + if err != nil { + return nil, errors.Wrap(err, "CreateISnapshot") + } + + return isnapshot, nil +} + +func (self *SDisk) getSnapshot(snapshotId string) (*SSnapshot, error) { + snapshot, err := self.storage.zone.region.GetSnapshotById(self.Zone, snapshotId) + return &snapshot, err +} + +func (self *SDisk) GetISnapshot(idStr string) (cloudprovider.ICloudSnapshot, error) { + snapshot, err := self.getSnapshot(idStr) + return snapshot, err +} + +func (self *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := self.storage.zone.region.GetSnapshots("", self.GetId(), "") + if err != nil { + return nil, err + } + + isnapshots := make([]cloudprovider.ICloudSnapshot, len(snapshots)) + for i := 0; i < len(snapshots); i++ { + isnapshots[i] = &snapshots[i] + } + return isnapshots, nil +} + +func (self *SDisk) Resize(ctx context.Context, newSizeMB int64) error { + var sizeGB int64 + // 向上取整 + if (newSizeMB % 1024) > 0 { + sizeGB = newSizeMB/1024 + 1 + } else { + sizeGB = newSizeMB / 1024 + } + + if self.Status == "InUse" { + err := self.storage.zone.region.DetachDisk(self.Zone, self.UHostID, self.UDiskID) + if err != nil { + return err + } + + defer self.storage.zone.region.AttachDisk(self.Zone, self.UHostID, self.UDiskID) + err = cloudprovider.WaitStatusWithDelay(self, api.DISK_READY, 10*time.Second, 5*time.Second, 60*time.Second) + if err != nil { + return errors.Wrap(err, "DiskResize") + } + + } + return self.storage.zone.region.resizeDisk(self.Zone, self.GetId(), sizeGB) +} + +func (self *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + err := self.storage.zone.region.resetDisk(self.Zone, self.GetId(), snapshotId) + if err != nil { + return "", err + } + + return self.GetId(), nil +} + +func (self *SDisk) Rebuild(ctx context.Context) error { + return self.storage.zone.region.resetDisk(self.Zone, self.GetId(), "") +} + +func (self *SRegion) GetDisk(diskId string) (*SDisk, error) { + if len(diskId) == 0 { + return nil, fmt.Errorf("GetDisk id should not empty") + } + + disks, err := self.GetDisks("", "", []string{diskId}) + if err != nil { + return nil, err + } + + if len(disks) == 1 { + return &disks[0], nil + } else if len(disks) == 0 { + return nil, cloudprovider.ErrNotFound + } else { + return nil, fmt.Errorf("GetDisk %s %d found", diskId, len(disks)) + } +} + +// https://docs.ucloud.cn/api/udisk-api/describe_udisk +// diskType DataDisk|SystemDisk (DataDisk表示数据盘,SystemDisk表示系统盘) +func (self *SRegion) GetDisks(zoneId string, diskType string, diskIds []string) ([]SDisk, error) { + disks := make([]SDisk, 0) + params := NewUcloudParams() + if len(zoneId) > 0 { + params.Set("Zone", zoneId) + } + + if len(diskType) > 0 { + params.Set("DiskType", diskType) + } + + err := self.DoListAll("DescribeUDisk", params, &disks) + if err != nil { + return nil, err + } + + if len(diskIds) > 0 { + filtedDisks := make([]SDisk, 0) + for i := range disks { + if utils.IsInStringArray(disks[i].UDiskID, diskIds) { + filtedDisks = append(filtedDisks, disks[i]) + } + } + + return filtedDisks, nil + } + + return disks, nil +} + +// https://docs.ucloud.cn/api/udisk-api/delete_udisk +func (self *SRegion) DeleteDisk(zoneId string, diskId string) error { + params := NewUcloudParams() + params.Set("Zone", zoneId) + params.Set("UDiskId", diskId) + + return self.DoAction("DeleteUDisk", params, nil) +} + +// https://docs.ucloud.cn/api/udisk-api/create_udisk +func (self *SRegion) CreateDisk(zoneId string, category string, name string, sizeGb int) (string, error) { + params := NewUcloudParams() + params.Set("Zone", zoneId) + params.Set("Size", sizeGb) + params.Set("Name", name) + params.Set("DiskType", category) + + diskIds := make([]string, 0) + err := self.DoAction("CreateUDisk", params, &diskIds) + if err != nil { + return "", err + } + + if len(diskIds) == 0 { + return "", fmt.Errorf("CreateDisk with empty response") + } + + return diskIds[0], nil +} + +// https://docs.ucloud.cn/api/udisk-api/create_udisk_snapshot +func (self *SRegion) CreateSnapshot(zoneId, diskId, name, desc string) (string, error) { + params := NewUcloudParams() + params.Set("Zone", zoneId) + params.Set("UDiskId", diskId) + params.Set("Name", name) + params.Set("Comment", desc) + + snapshotIds := make([]string, 0) + err := self.DoAction("CreateUDiskSnapshot", params, &snapshotIds) + if err != nil { + return "", err + } + + if len(snapshotIds) == 0 { + return "", fmt.Errorf("CreateSnapshot with empty response") + } + + return snapshotIds[0], nil +} + +// https://docs.ucloud.cn/api/udisk-api/resize_udisk +func (self *SRegion) resizeDisk(zoneId string, diskId string, sizeGB int64) error { + params := NewUcloudParams() + params.Set("Zone", zoneId) + params.Set("Size", sizeGB) + params.Set("UDiskId", diskId) + + return self.DoAction("ResizeUDisk", params, nil) +} + +// https://docs.ucloud.cn/api/udisk-api/restore_u_disk +func (self *SRegion) resetDisk(zoneId, diskId, snapshotId string) error { + params := NewUcloudParams() + params.Set("Zone", zoneId) + params.Set("UDiskId", diskId) + if len(snapshotId) > 0 { + params.Set("SnapshotId", snapshotId) + } + + return self.DoAction("RestoreUDisk", params, nil) +} + +// https://docs.ucloud.cn/api/udisk-api/attach_udisk +func (self *SRegion) AttachDisk(zoneId string, instanceId string, diskId string) error { + params := NewUcloudParams() + params.Set("Zone", zoneId) + params.Set("UHostId", instanceId) + params.Set("UDiskId", diskId) + + return self.DoAction("AttachUDisk", params, nil) +} + +// https://docs.ucloud.cn/api/udisk-api/detach_udisk +func (self *SRegion) DetachDisk(zoneId string, instanceId string, diskId string) error { + idisks, err := self.GetDisk(diskId) + if err != nil { + return err + } + + if idisks.Status == "Available" { + return nil + } + + params := NewUcloudParams() + params.Set("Zone", zoneId) + params.Set("UHostId", instanceId) + params.Set("UDiskId", diskId) + + return self.DoAction("DetachUDisk", params, nil) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/doc.go new file mode 100644 index 0000000000..eed7e93827 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 ucloud // import "yunion.io/x/cloudmux/pkg/multicloud/ucloud" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/eip.go new file mode 100644 index 0000000000..d096433969 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/eip.go @@ -0,0 +1,289 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +const ( + EIP_CHARGE_TYPE_BY_TRAFFIC = "traffic" + EIP_CHARGE_TYPE_BY_BANDWIDTH = "bandwidth" +) + +// https://docs.ucloud.cn/api/unet-api/describe_eip +type SEip struct { + region *SRegion + multicloud.SEipBase + UcloudTags + + BandwidthMb int `json:"Bandwidth"` + BandwidthType int `json:"BandwidthType"` + ChargeType string `json:"ChargeType"` + CreateTime int64 `json:"CreateTime"` + EIPAddr []EIPAddr `json:"EIPAddr"` + EIPID string `json:"EIPId"` + Expire bool `json:"Expire"` + ExpireTime int64 `json:"ExpireTime"` + Name string `json:"Name"` + PayMode string `json:"PayMode"` + Remark string `json:"Remark"` + Resource Resource `json:"Resource"` + ShareBandwidthSet ShareBandwidthSet `json:"ShareBandwidthSet"` + Status string `json:"Status"` + Tag string `json:"Tag"` + Weight int `json:"Weight"` +} + +func (self *SEip) GetProjectId() string { + return self.region.client.projectId +} + +type EIPAddr struct { + IP string `json:"IP"` + OperatorName string `json:"OperatorName"` +} + +type Resource struct { + ResourceID string `json:"ResourceID"` + ResourceName string `json:"ResourceName"` + ResourceType string `json:"ResourceType"` + Zone string `json:"Zone"` +} + +type ShareBandwidthSet struct { + ShareBandwidth int `json:"ShareBandwidth"` + ShareBandwidthID string `json:"ShareBandwidthId"` + ShareBandwidthName string `json:"ShareBandwidthName"` +} + +func (self *SEip) GetId() string { + return self.EIPID +} + +func (self *SEip) GetName() string { + if len(self.Name) == 0 { + return self.GetId() + } + + return self.Name +} + +func (self *SEip) GetGlobalId() string { + return self.GetId() +} + +// 弹性IP的资源绑定状态, 枚举值为: used: 已绑定, free: 未绑定, freeze: 已冻结 +func (self *SEip) GetStatus() string { + switch self.Status { + case "used": + return api.EIP_STATUS_ASSOCIATE // ? + case "free": + return api.EIP_STATUS_READY + case "freeze": + return api.EIP_STATUS_UNKNOWN + default: + return api.EIP_STATUS_UNKNOWN + } +} + +func (self *SEip) Refresh() error { + if self.IsEmulated() { + return nil + } + new, err := self.region.GetEipById(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SEip) IsEmulated() bool { + return false +} + +// 付费方式, 枚举值为: Year, 按年付费; Month, 按月付费; Dynamic, 按小时付费; Trial, 试用. 按小时付费和试用这两种付费模式需要开通权限. +func (self *SEip) GetBillingType() string { + switch self.ChargeType { + case "Year", "Month": + return billing_api.BILLING_TYPE_PREPAID + default: + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SEip) GetCreatedAt() time.Time { + return time.Unix(self.CreateTime, 0) +} + +func (self *SEip) GetExpiredAt() time.Time { + return time.Unix(self.ExpireTime, 0) +} + +func (self *SEip) GetIpAddr() string { + if len(self.EIPAddr) > 1 { + log.Warningf("GetIpAddr %d eip addr found", len(self.EIPAddr)) + } else if len(self.EIPAddr) == 0 { + return "" + } + + return self.EIPAddr[0].IP +} + +func (self *SEip) GetMode() string { + return api.EIP_MODE_STANDALONE_EIP +} + +func (self *SEip) GetAssociationType() string { + switch self.Resource.ResourceType { + case "uhost": + return api.EIP_ASSOCIATE_TYPE_SERVER + case "natgw": + return api.EIP_ASSOCIATE_TYPE_NAT_GATEWAY + case "ulb": + return api.EIP_ASSOCIATE_TYPE_LOADBALANCER + default: + return self.Resource.ResourceType + } +} + +// 已绑定的资源类型, 枚举值为: uhost, 云主机;natgw:NAT网关;ulb:负载均衡器;upm: 物理机; hadoophost: 大数据集群;fortresshost:堡垒机;udockhost:容器;udhost:私有专区主机;vpngw:IPSec VPN;ucdr:云灾备;dbaudit:数据库审计。 +func (self *SEip) GetAssociationExternalId() string { + return self.Resource.ResourceID +} + +func (self *SEip) GetBandwidth() int { + return self.BandwidthMb +} + +func (self *SEip) GetINetworkId() string { + return "" +} + +// 弹性IP的计费模式, 枚举值为: "Bandwidth", 带宽计费; "Traffic", 流量计费; "ShareBandwidth",共享带宽模式. 默认为 "Bandwidth". +func (self *SEip) GetInternetChargeType() string { + switch self.PayMode { + case "Bandwidth": + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH + case "Traffic": + return api.EIP_CHARGE_TYPE_BY_TRAFFIC + default: + return api.EIP_CHARGE_TYPE_BY_BANDWIDTH + } +} + +func (self *SEip) Delete() error { + return self.region.DeallocateEIP(self.GetId()) +} + +func (self *SEip) Associate(conf *cloudprovider.AssociateConfig) error { + return self.region.AssociateEip(self.GetId(), conf.InstanceId) +} + +func (self *SEip) Dissociate() error { + return self.region.DissociateEip(self.GetId(), self.Resource.ResourceID) +} + +func (self *SEip) ChangeBandwidth(bw int) error { + return self.region.UpdateEipBandwidth(self.GetId(), bw) +} + +// https://docs.ucloud.cn/api/unet-api/allocate_eip +// 增加共享带宽模式ShareBandwidth +func (self *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + if len(eip.BGPType) == 0 { + if strings.HasPrefix(self.GetId(), "cn-") { + eip.BGPType = "Bgp" + } else { + eip.BGPType = "International" + } + } + + params := NewUcloudParams() + params.Set("OperatorName", eip.BGPType) + params.Set("Bandwidth", eip.BandwidthMbps) + params.Set("Name", eip.Name) + var payMode string + switch eip.ChargeType { + case api.EIP_CHARGE_TYPE_BY_TRAFFIC: + payMode = "Traffic" + case api.EIP_CHARGE_TYPE_BY_BANDWIDTH: + payMode = "Bandwidth" + } + params.Set("PayMode", payMode) + params.Set("ChargeType", "Dynamic") // 按需付费 + + eips := make([]SEip, 0) + err := self.DoAction("AllocateEIP", params, &eips) + if err != nil { + return nil, err + } + + if len(eips) == 1 { + eip := eips[0] + eip.region = self + eip.Refresh() + return &eip, nil + } else { + return nil, fmt.Errorf("CreateEIP %d eip created", len(eips)) + } +} + +// https://docs.ucloud.cn/api/unet-api/release_eip +func (self *SRegion) DeallocateEIP(eipId string) error { + params := NewUcloudParams() + params.Set("EIPId", eipId) + + return self.DoAction("ReleaseEIP", params, nil) +} + +// https://docs.ucloud.cn/api/unet-api/bind_eip +func (self *SRegion) AssociateEip(eipId string, instanceId string) error { + params := NewUcloudParams() + params.Set("EIPId", eipId) + params.Set("ResourceType", "uhost") + params.Set("ResourceId", instanceId) + + return self.DoAction("BindEIP", params, nil) +} + +// https://docs.ucloud.cn/api/unet-api/unbind_eip +func (self *SRegion) DissociateEip(eipId string, instanceId string) error { + params := NewUcloudParams() + params.Set("EIPId", eipId) + params.Set("ResourceType", "uhost") + params.Set("ResourceId", instanceId) + + return self.DoAction("UnBindEIP", params, nil) +} + +// https://docs.ucloud.cn/api/unet-api/modify_eip_bandwidth +func (self *SRegion) UpdateEipBandwidth(eipId string, bw int) error { + params := NewUcloudParams() + params.Set("EIPId", eipId) + params.Set("Bandwidth", bw) + + return self.DoAction("ModifyEIPBandwidth", params, nil) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/host.go new file mode 100644 index 0000000000..7ffb1c0c94 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/host.go @@ -0,0 +1,359 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "encoding/base64" + "fmt" + "strconv" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone + + projectId string +} + +func (self *SHost) GetId() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId()) +} + +func (self *SHost) GetName() string { + return fmt.Sprintf("%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId()) +} + +func (self *SHost) GetGlobalId() string { + return self.GetId() +} + +func (self *SHost) GetStatus() string { + return api.HOST_STATUS_RUNNING +} + +func (self *SHost) Refresh() error { + return nil +} + +func (self *SHost) IsEmulated() bool { + return true +} + +func (self *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + vms, err := self.zone.GetInstances() + 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(id string) (cloudprovider.ICloudVM, error) { + vm, err := self.zone.region.GetInstanceByID(id) + if err != nil { + return nil, err + } + + vm.host = self + return &vm, 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 api.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_UCLOUD), "manufacture") + return info +} + +func (self *SHost) GetSN() string { + return "" +} + +func (self *SHost) GetCpuCount() int { + 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 api.DISK_TYPE_HYBRID +} + +func (self *SHost) GetHostType() string { + return api.HOST_TYPE_UCLOUD +} + +func (self *SHost) GetIsMaintenance() bool { + return false +} + +func (self *SHost) GetVersion() string { + return UCLOUD_API_VERSION +} + +// 不支持user data +// 不支持指定keypair +func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + vmId, err := self._createVM(desc.Name, desc.ExternalImageId, desc.SysDisk, desc.Cpu, desc.MemoryMB, desc.InstanceType, desc.ExternalNetworkId, desc.IpAddr, desc.Description, desc.Password, desc.DataDisks, desc.ExternalSecgroupId, desc.BillingCycle) + if err != nil { + return nil, err + } + + vm, err := self.zone.region.GetInstanceByID(vmId) + if err != nil { + return nil, err + } + + vm.host = self + return &vm, err +} + +func (self *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +type SInstanceType struct { + UHostType string + CPU int + MemoryMB int + GPU int +} + +func ParseInstanceType(instanceType string) (SInstanceType, error) { + i := SInstanceType{} + segs := strings.Split(instanceType, ".") + if len(segs) < 3 { + return i, fmt.Errorf("invalid instance type %s", instanceType) + } else if len(segs) >= 4 { + gpu, err := strconv.Atoi(strings.TrimLeft(segs[3], "g")) + if err != nil { + return i, err + } + + i.GPU = gpu + } + + cpu, err := strconv.Atoi(strings.TrimLeft(segs[1], "c")) + if err != nil { + return i, err + } + + mem, err := strconv.Atoi(strings.TrimLeft(segs[2], "m")) + if err != nil { + return i, err + } + + i.UHostType = segs[0] + i.CPU = cpu + i.MemoryMB = mem * 1024 + return i, nil +} + +func (self *SHost) _createVM(name, imgId string, sysDisk cloudprovider.SDiskInfo, cpu, memMB int, instanceType string, + networkId, ipAddr, desc, passwd string, + dataDisks []cloudprovider.SDiskInfo, secgroupId string, bc *billing.SBillingCycle) (string, error) { + // 网络配置及安全组绑定 + net, _ := self.zone.region.getNetwork(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 { + return "", fmt.Errorf("CreateVM no secgroupId specified") + } + + if len(passwd) == 0 { + return "", fmt.Errorf("CreateVM password should not be emtpty") + } + + // 镜像及硬盘配置 + img, err := self.zone.region.GetImage(imgId) + if err != nil { + log.Errorf("GetImage %s fail %s", imgId, err) + return "", err + } + if img.GetStatus() != api.CACHED_IMAGE_STATUS_ACTIVE { + log.Errorf("image %s status %s, expect %s", imgId, img.GetStatus(), api.CACHED_IMAGE_STATUS_ACTIVE) + return "", fmt.Errorf("image not ready") + } + + disks := make([]SDisk, len(dataDisks)+1) + disks[0].SizeGB = int(img.ImageSizeGB) + if sysDisk.SizeGB > 0 && sysDisk.SizeGB > int(img.ImageSizeGB) { + disks[0].SizeGB = sysDisk.SizeGB + } + disks[0].DiskType = sysDisk.StorageType + + for i, dataDisk := range dataDisks { + disks[i+1].SizeGB = dataDisk.SizeGB + disks[i+1].DiskType = dataDisk.StorageType + } + + // 创建实例 + // https://docs.ucloud.cn/api/uhost-api/uhost_type + // https://docs.ucloud.cn/compute/uhost/introduction/uhost/type + var vmId string + i, err := ParseInstanceType(instanceType) + if err != nil { + if cpu <= 0 || memMB <= 0 { + return "", err + } else { + i.UHostType = "N2" + i.CPU = cpu + i.MemoryMB = memMB + } + } + + vmId, err = self.zone.region.CreateInstance(name, imgId, i.UHostType, passwd, net.wire.vpc.GetId(), networkId, secgroupId, self.zone.ZoneId, desc, ipAddr, i.CPU, i.MemoryMB, i.GPU, disks, bc) + if err != nil { + return "", fmt.Errorf("Failed to create: %v", err) + } + + return vmId, nil +} + +// https://docs.ucloud.cn/api/uhost-api/create_uhost_instance +// https://docs.ucloud.cn/api/uhost-api/specification +// 支持8-30位字符, 不能包含[A-Z],[a-z],[0-9]和[()`~!@#$%^&*-+=_|{}[]:;'<>,.?/]之外的非法字符 +func (self *SRegion) CreateInstance(name, imageId, hostType, password, vpcId, SubnetId, securityGroupId, + zoneId, desc, ipAddr string, cpu, memMB, gpu int, disks []SDisk, bc *billing.SBillingCycle) (string, error) { + params := NewUcloudParams() + params.Set("Zone", zoneId) + params.Set("ImageId", imageId) + params.Set("Password", base64.StdEncoding.EncodeToString([]byte(password))) + params.Set("LoginMode", "Password") + params.Set("Name", name) + params.Set("UHostType", hostType) + params.Set("CPU", cpu) + params.Set("Memory", memMB) + params.Set("VPCId", vpcId) + params.Set("SubnetId", SubnetId) + params.Set("SecurityGroupId", securityGroupId) + if gpu > 0 { + params.Set("GPU", gpu) + } + + if bc != nil && bc.GetMonths() >= 1 && bc.GetMonths() < 10 { + params.Set("ChargeType", "Month") + params.Set("Quantity", bc.GetMonths()) + } else if bc != nil && bc.GetMonths() >= 10 && bc.GetMonths() < 12 { + params.Set("ChargeType", "Year") + params.Set("Quantity", 1) + } else if bc != nil && bc.GetYears() >= 1 { + params.Set("ChargeType", "Year") + params.Set("Quantity", bc.GetYears()) + } else { + params.Set("ChargeType", "Dynamic") + } + + // boot disk + params.Set("Disks.0.IsBoot", "True") + params.Set("Disks.0.Type", disks[0].DiskType) + params.Set("Disks.0.Size", disks[0].SizeGB) + + // data disk + for i, disk := range disks[1:] { + N := i + 1 + params.Set(fmt.Sprintf("Disks.%d.IsBoot", N), "False") + params.Set(fmt.Sprintf("Disks.%d.Type", N), disk.DiskType) + params.Set(fmt.Sprintf("Disks.%d.Size", N), disk.SizeGB) + } + + type Ret struct { + UHostIds []string + } + + ret := Ret{} + err := self.DoAction("CreateUHostInstance", params, &ret) + if err != nil { + return "", err + } + + if len(ret.UHostIds) == 1 { + return ret.UHostIds[0], nil + } + + return "", fmt.Errorf("CreateInstance %d instance created. %s", len(ret.UHostIds), ret.UHostIds) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/image.go new file mode 100644 index 0000000000..e53010751b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/image.go @@ -0,0 +1,228 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type SImage struct { + multicloud.SImageBase + UcloudTags + storageCache *SStoragecache + + // normalized image info + imgInfo *imagetools.ImageInfo + + Zone string `json:"Zone"` + ImageDescription string `json:"ImageDescription"` + OSName string `json:"OsName"` + ImageID string `json:"ImageId"` + State string `json:"State"` + ImageName string `json:"ImageName"` + OSType string `json:"OsType"` + CreateTime int64 `json:"CreateTime"` + ImageType string `json:"ImageType"` + ImageSizeGB int64 `json:"ImageSize"` +} + +func (self *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (self *SImage) GetId() string { + return self.ImageID +} + +func (self *SImage) GetName() string { + if len(self.ImageName) == 0 { + return self.GetId() + } + + return self.ImageName +} + +func (self *SImage) GetGlobalId() string { + return self.GetId() +} + +// 镜像状态, 可用:Available,制作中:Making, 不可用:Unavailable +func (self *SImage) GetStatus() string { + switch self.State { + case "Available": + return api.CACHED_IMAGE_STATUS_ACTIVE + case "Making": + return api.CACHED_IMAGE_STATUS_CACHING + case "Unavailable": + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + default: + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (self *SImage) Refresh() error { + new, err := self.storageCache.region.GetImage(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SImage) IsEmulated() bool { + return false +} + +func (self *SImage) Delete(ctx context.Context) error { + return self.storageCache.region.DeleteImage(self.GetId()) +} + +func (self *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return self.storageCache +} + +func (self *SImage) GetSizeByte() int64 { + return self.ImageSizeGB * 1024 * 1024 * 1024 +} + +// 镜像类型。标准镜像:Base,镜像市场:Business, 自定义镜像:Custom,默认返回所有类型 +func (self *SImage) GetImageType() cloudprovider.TImageType { + switch self.ImageType { + case "Base": + return cloudprovider.ImageTypeSystem + case "Custom": + return cloudprovider.ImageTypeCustomized + case "Business": + return cloudprovider.ImageTypeShared + default: + return cloudprovider.ImageTypeCustomized + } +} + +func (self *SImage) GetImageStatus() string { + switch self.State { + case "Available": + return cloudprovider.IMAGE_STATUS_ACTIVE + case "Making": + return cloudprovider.IMAGE_STATUS_QUEUED + case "Unavailable": + return cloudprovider.IMAGE_STATUS_KILLED + default: + return cloudprovider.IMAGE_STATUS_KILLED + } +} + +func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if self.imgInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(self.ImageName, "", "", "", "") + self.imgInfo = &imgInfo + } + + return self.imgInfo +} + +func (self *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(self.getNormalizedImageInfo().OsType) +} + +func (self *SImage) GetOsDist() string { + return self.getNormalizedImageInfo().OsDistro +} + +func (self *SImage) GetOsVersion() string { + return self.getNormalizedImageInfo().OsVersion +} + +func (self *SImage) GetOsArch() string { + return self.getNormalizedImageInfo().OsArch +} + +func (img *SImage) GetOsLang() string { + return img.getNormalizedImageInfo().OsLang +} + +func (img *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(img.getNormalizedImageInfo().OsBios) +} + +func (img *SImage) GetFullOsName() string { + return img.ImageName +} + +func (self *SImage) GetMinOsDiskSizeGb() int { + return int(self.ImageSizeGB) +} + +func (self *SImage) GetImageFormat() string { + return "" +} + +func (self *SImage) GetCreatedAt() time.Time { + return time.Unix(self.CreateTime, 0) +} + +// https://docs.ucloud.cn/api/uhost-api/describe_image +func (self *SRegion) GetImage(imageId string) (SImage, error) { + params := NewUcloudParams() + params.Set("ImageId", imageId) + + images := make([]SImage, 0) + err := self.DoListAll("DescribeImage", params, &images) + if err != nil { + return SImage{}, err + } + + if len(images) == 1 { + return images[0], nil + } else if len(images) == 0 { + return SImage{}, cloudprovider.ErrNotFound + } else { + return SImage{}, fmt.Errorf("GetImage %s %d found.", imageId, len(images)) + } +} + +// https://docs.ucloud.cn/api/uhost-api/describe_image +// ImageType 标准镜像:Base,镜像市场:Business, 自定义镜像:Custom,默认返回所有类型 +func (self *SRegion) GetImages(imageType string, imageId string) ([]SImage, error) { + params := NewUcloudParams() + + if len(imageId) > 0 { + params.Set("ImageId", imageId) + } + + if len(imageType) > 0 { + params.Set("ImageType", imageType) + } + + images := make([]SImage, 0) + err := self.DoListAll("DescribeImage", params, &images) + return images, err +} + +// https://docs.ucloud.cn/api/uhost-api/terminate_custom_image +func (self *SRegion) DeleteImage(imageId string) error { + params := NewUcloudParams() + params.Set("ImageId", imageId) + + return self.DoAction("TerminateCustomImage", params, nil) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/instance.go new file mode 100644 index 0000000000..0e11609323 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/instance.go @@ -0,0 +1,705 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "context" + "encoding/base64" + "fmt" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + billing_api "yunion.io/x/cloudmux/pkg/apis/billing" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/imagetools" +) + +type SInstance struct { + multicloud.SInstanceBase + UcloudTags + + host *SHost + + osInfo *imagetools.ImageInfo + + UHostID string `json:"UHostId"` + Zone string `json:"Zone"` + LifeCycle string `json:"LifeCycle"` + OSName string `json:"OsName"` + ImageID string `json:"ImageId"` + BasicImageID string `json:"BasicImageId"` + BasicImageName string `json:"BasicImageName"` + Tag string `json:"Tag"` + Name string `json:"Name"` + Remark string `json:"Remark"` + State string `json:"State"` + NetworkState string `json:"NetworkState"` + HostType string `json:"HostType"` + StorageType string `json:"StorageType"` + TotalDiskSpace int `json:"TotalDiskSpace"` + DiskSet []DiskSet `json:"DiskSet"` + NetCapability string `json:"NetCapability"` + IPSet []IPSet `json:"IPSet"` + SubnetType string `json:"SubnetType"` + ChargeType string `json:"ChargeType"` + ExpireTime int64 `json:"ExpireTime"` + AutoRenew string `json:"AutoRenew"` + IsExpire string `json:"IsExpire"` + UHostType string `json:"UHostType"` + OSType string `json:"OsType"` + CreateTime int64 `json:"CreateTime"` + CPU int `json:"CPU"` + GPU int `json:"GPU"` + MemoryMB int `json:"Memory"` + TimemachineFeature string `json:"TimemachineFeature"` + HotplugFeature bool `json:"HotplugFeature"` + NetCapFeature bool `json:"NetCapFeature"` + BootDiskState string `json:"BootDiskState"` +} + +func (self *SInstance) GetSecurityGroupIds() ([]string, error) { + secgroups, err := self.GetSecurityGroups() + if err != nil { + log.Errorln(err) + } + + secgroupIds := make([]string, 0) + for _, secgroup := range secgroups { + secgroupIds = append(secgroupIds, secgroup.GetId()) + } + + return secgroupIds, nil +} + +func (self *SInstance) GetProjectId() string { + return self.host.zone.region.client.projectId +} + +func (self *SInstance) GetError() error { + return nil +} + +type DiskSet struct { + DiskID string `json:"DiskId"` + DiskType string `json:"DiskType"` + Drive string `json:"Drive"` + IsBoot bool `json:"IsBoot"` + Size int `json:"Size"` + Encrypted string `json:"Encrypted"` + Type string `json:"Type"` +} + +type IPSet struct { + Type string `json:"Type"` + IP string `json:"IP"` + IPId string `json:"IPId"` // IP资源ID (内网IP无对应的资源ID) + MAC string `json:"Mac"` + VPCID string `json:"VPCId"` + SubnetID string `json:"SubnetId"` +} + +type SVncInfo struct { + VNCIP string `json:"VncIP"` + VNCPassword string `json:"VncPassword"` + UHostID string `json:"UHostId"` + Action string `json:"Action"` + VNCPort int64 `json:"VncPort"` +} + +func (self *SInstance) GetId() string { + return self.UHostID +} + +func (self *SInstance) GetName() string { + if len(self.Name) == 0 { + return self.GetId() + } + return self.Name +} + +func (self *SInstance) GetHostname() string { + return self.GetName() +} + +func (self *SInstance) GetGlobalId() string { + return self.GetId() +} + +// 实例状态,枚举值: +// >初始化: Initializing; +// >启动中: Starting; +// > 运行中: Running; +// > 关机中: Stopping; +// >关机: Stopped +// >安装失败: Install Fail; +// >重启中: Rebooting +func (self *SInstance) GetStatus() string { + switch self.State { + case "Running": + return api.VM_RUNNING + case "Stopped": + return api.VM_READY + case "Rebooting": + return api.VM_STOPPING + case "Initializing": + return api.VM_INIT + case "Starting": + return api.VM_STARTING + case "Stopping": + return api.VM_STOPPING + case "Install Fail": + return api.VM_CREATE_FAILED + default: + return api.VM_UNKNOWN + } +} + +func (self *SInstance) Refresh() error { + new, err := self.host.zone.region.GetInstanceByID(self.GetId()) + if err != nil { + return err + } + + new.host = self.host + return jsonutils.Update(self, new) +} + +func (self *SInstance) IsEmulated() bool { + return false +} + +func (self *SInstance) GetSysTags() map[string]string { + data := map[string]string{} + // todo: add price key here + data["zone_ext_id"] = self.host.zone.GetGlobalId() + if len(self.BasicImageID) > 0 { + if image, err := self.host.zone.region.GetImage(self.BasicImageID); err != nil { + log.Errorf("Failed to find image %s for instance %s", self.BasicImageID, self.GetName()) + } else { + meta := image.GetSysTags() + for k, v := range meta { + data[k] = v + } + } + } + + return data +} + +// 计费模式,枚举值为: Year,按年付费; Month,按月付费; Dynamic,按需付费(需开启权限); +func (self *SInstance) GetBillingType() string { + switch self.ChargeType { + case "Year", "Month": + return billing_api.BILLING_TYPE_PREPAID + default: + return billing_api.BILLING_TYPE_POSTPAID + } +} + +func (self *SInstance) GetCreatedAt() time.Time { + return time.Unix(self.CreateTime, 0) +} + +func (self *SInstance) GetExpiredAt() time.Time { + if self.AutoRenew != "Yes" { + return time.Unix(self.ExpireTime, 0) + } + + return time.Time{} +} + +func (self *SInstance) GetIHost() cloudprovider.ICloudHost { + return self.host +} + +func (self *SInstance) GetLocalDisk(diskId, storageType string, sizeGB int, isBoot bool) SDisk { + diskType := "" + if isBoot { + diskType = "SystemDisk" + } + + disk := SDisk{ + SDisk: multicloud.SDisk{}, + Status: "Available", + UHostID: self.GetId(), + Name: diskId, + Zone: self.host.zone.GetId(), + DiskType: diskType, + UDiskID: diskId, + UHostName: self.GetName(), + CreateTime: self.CreateTime, + SizeGB: sizeGB, + } + + disk.storage = &SStorage{zone: self.host.zone, storageType: storageType} + return disk +} + +func (self *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + localDisks := make([]SDisk, 0) + diskIds := make([]string, 0) + for _, disk := range self.DiskSet { + if utils.IsInStringArray(disk.DiskType, []string{api.STORAGE_UCLOUD_LOCAL_NORMAL, api.STORAGE_UCLOUD_LOCAL_SSD}) { + localDisks = append(localDisks, self.GetLocalDisk(disk.DiskID, disk.DiskType, disk.Size, disk.IsBoot)) + } else { + diskIds = append(diskIds, disk.DiskID) + } + } + + disks := []SDisk{} + var err error + if len(diskIds) > 0 { + disks, err = self.host.zone.region.GetDisks("", "", diskIds) + if err != nil { + return nil, err + } + } + + disks = append(disks, localDisks...) + idisks := make([]cloudprovider.ICloudDisk, len(disks)) + for i := 0; i < len(disks); i += 1 { + if disks[i].storage == nil { + var category string + if strings.Contains(disks[i].DiskType, "SSD") { + category = api.STORAGE_UCLOUD_CLOUD_SSD + } else { + category = api.STORAGE_UCLOUD_CLOUD_NORMAL + } + storage, err := self.host.zone.getStorageByCategory(category) + if err != nil { + return nil, err + } + disks[i].storage = storage + } + idisks[i] = &disks[i] + // 将系统盘放到第0个位置 + if disks[i].GetDiskType() == api.DISK_TYPE_SYS { + idisks[0], idisks[i] = idisks[i], idisks[0] + } + } + + return idisks, nil +} + +func (self *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + nics := make([]cloudprovider.ICloudNic, 0) + + for _, ip := range self.IPSet { + if len(ip.SubnetID) == 0 { + continue + } + + nic := SInstanceNic{ + instance: self, + ipAddr: ip.IP, + macAddr: ip.MAC, + } + nics = append(nics, &nic) + } + + return nics, nil +} + +// 国际: Internation,BGP: BGP,内网: Private +func (self *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + for _, ip := range self.IPSet { + if len(ip.IPId) > 0 { + eip, err := self.host.zone.region.GetEipById(ip.IPId) + if err != nil { + return nil, err + } + + return &eip, nil + } + } + + return nil, nil +} + +func (self *SInstance) GetVcpuCount() int { + return self.CPU +} + +func (self *SInstance) GetVmemSizeMB() int { + return self.MemoryMB +} + +func (self *SInstance) GetBootOrder() string { + return "dcn" +} + +func (self *SInstance) GetVga() string { + return "std" +} + +func (self *SInstance) GetVdi() string { + return "vnc" +} + +func (ins *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { + if ins.osInfo == nil { + osInfo := imagetools.NormalizeImageInfo(ins.OSName, "", ins.OSType, "", "") + ins.osInfo = &osInfo + } + return ins.osInfo +} + +func (ins *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(ins.getNormalizedOsInfo().OsType) +} + +func (ins *SInstance) GetFullOsName() string { + return ins.OSName +} + +func (ins *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(ins.getNormalizedOsInfo().OsBios) +} + +func (ins *SInstance) GetOsArch() string { + return ins.getNormalizedOsInfo().OsArch +} + +func (ins *SInstance) GetOsDist() string { + return ins.getNormalizedOsInfo().OsDistro +} + +func (ins *SInstance) GetOsVersion() string { + return ins.getNormalizedOsInfo().OsVersion +} + +func (ins *SInstance) GetOsLang() string { + return ins.getNormalizedOsInfo().OsLang +} + +func (self *SInstance) GetMachine() string { + return "pc" +} + +func (self *SInstance) GetInstanceType() string { + // C1.c8.m24 + if strings.HasPrefix(self.HostType, "G") { + return fmt.Sprintf("%s.c%d.m%d.g%d", self.HostType, self.CPU, self.MemoryMB/1014, self.GPU) + } else { + return fmt.Sprintf("%s.c%d.m%d", self.HostType, self.CPU, self.MemoryMB/1014) + } +} + +func (self *SInstance) AssignSecurityGroup(secgroupId string) error { + return self.host.zone.region.assignSecurityGroups(self.GetId(), secgroupId) +} + +// https://docs.ucloud.cn/api/unet-api/grant_firewall +func (self *SInstance) SetSecurityGroups(secgroupIds []string) error { + if len(secgroupIds) == 0 { + return fmt.Errorf("SetSecurityGroups secgroup id should not be empty") + } else if len(secgroupIds) > 1 { + return fmt.Errorf("SetSecurityGroups only allowed to assign one secgroup id. %d given", len(secgroupIds)) + } + + return self.host.zone.region.assignSecurityGroups(self.GetId(), secgroupIds[0]) +} + +func (self *SInstance) GetHypervisor() string { + return api.HYPERVISOR_UCLOUD +} + +func (self *SInstance) StartVM(ctx context.Context) error { + err := self.host.zone.region.StartVM(self.GetId()) + if err != nil { + return err + } + err = cloudprovider.WaitStatusWithDelay(self, api.VM_RUNNING, 10*time.Second, 10*time.Second, 600*time.Second) + if err != nil { + return errors.Wrap(err, "StartVM") + } + + return nil +} + +func (self *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + err := self.host.zone.region.StopVM(self.GetId()) + if err != nil { + return err + } + err = cloudprovider.WaitStatusWithDelay(self, api.VM_READY, 10*time.Second, 10*time.Second, 600*time.Second) + if err != nil { + return errors.Wrap(err, "StopVM") + } + + return nil +} + +func (self *SInstance) DeleteVM(ctx context.Context) error { + return self.host.zone.region.DeleteVM(self.GetId()) +} + +func (self *SInstance) UpdateVM(ctx context.Context, name string) error { + return self.host.zone.region.UpdateVM(self.GetId(), name) +} + +func (self *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +// https://docs.ucloud.cn/api/uhost-api/reinstall_uhost_instance +// 1.请确认在重新安装之前,该实例已被关闭; +// 2.请确认该实例未挂载UDisk; +// todo:// 3.将原系统重装为不同类型的系统时(Linux->Windows),不可选择保留数据盘; +// 4.重装不同版本的系统时(CentOS6->CentOS7),若选择保留数据盘,请注意数据盘的文件系统格式; +// 5.若主机CPU低于2核,不可重装为Windows系统。 +func (self *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + if len(desc.PublicKey) > 0 { + return "", fmt.Errorf("DeployVM not support assign ssh keypair") + } + + if self.GetStatus() != api.VM_READY { + return "", fmt.Errorf("DeployVM instance status %s , expected %s.", self.GetStatus(), api.VM_READY) + } + + if len(self.DiskSet) > 1 { + for _, disk := range self.DiskSet { + if disk.Type == "Data" { + err := self.host.zone.region.DetachDisk(self.host.zone.GetId(), self.GetId(), disk.DiskID) + if err != nil { + return "", fmt.Errorf("RebuildRoot detach disk %s", err) + } + + defer self.host.zone.region.AttachDisk(self.host.zone.GetId(), self.GetId(), disk.DiskID) + } + + } + } + + err := self.host.zone.region.RebuildRoot(self.GetId(), desc.ImageId, desc.Password) + if err != nil { + return "", err + } + + err = cloudprovider.WaitStatusWithDelay(self, api.VM_RUNNING, 10*time.Second, 15*time.Second, 300*time.Second) + if err != nil { + return "", errors.Wrap(err, "RebuildRoot") + } + + disks, err := self.GetIDisks() + if len(disks) > 0 { + return disks[0].GetId(), nil + } else { + return "", fmt.Errorf("RebuildRoot %s", err) + } +} + +func (self *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + if len(publicKey) > 0 { + return fmt.Errorf("DeployVM not support assign ssh keypair") + } + + if deleteKeypair { + return fmt.Errorf("DeployVM not support delete ssh keypair") + } + + if self.GetStatus() != api.VM_READY { + return fmt.Errorf("DeployVM instance status %s , expected %s.", self.GetStatus(), api.VM_READY) + } + + if len(password) > 0 { + err := self.host.zone.region.ResetVMPasswd(self.GetId(), password) + if err != nil { + return err + } + } + + err := cloudprovider.WaitStatus(self, api.VM_READY, 10*time.Second, 300*time.Second) + if err != nil { + return errors.Wrap(err, "DeployVM") + } + + return nil +} + +func (self *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + if len(config.InstanceType) > 0 { + return self.ChangeConfig2(ctx, config.InstanceType) + } + return self.host.zone.region.ResizeVM(self.GetId(), config.Cpu, config.MemoryMB) +} + +func (self *SInstance) ChangeConfig2(ctx context.Context, instanceType string) error { + i, err := ParseInstanceType(instanceType) + if err != nil { + return err + } + + return self.host.zone.region.ResizeVM(self.GetId(), i.CPU, i.MemoryMB) +} + +func (self *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + return self.host.zone.region.GetInstanceVNCUrl(self.GetId()) +} + +func (self *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return self.host.zone.region.AttachDisk(self.host.zone.GetId(), self.GetId(), diskId) +} + +func (self *SInstance) DetachDisk(ctx context.Context, diskId string) error { + err := self.host.zone.region.DetachDisk(self.host.zone.GetId(), self.GetId(), diskId) + if err != nil { + return err + } + + disk, err := self.host.zone.region.GetDisk(diskId) + if err != nil { + return err + } + + disk.storage = &SStorage{zone: self.host.zone, storageType: disk.GetStorageType()} + err = cloudprovider.WaitStatusWithDelay(disk, api.DISK_READY, 10*time.Second, 10*time.Second, 60*time.Second) + if err != nil { + return errors.Wrap(err, "DetachDisk") + } + + return nil +} + +func (self *SInstance) Renew(bc billing.SBillingCycle) error { + // return self.host.zone.region + return self.host.zone.region.RenewInstance(self.GetId(), bc) +} + +func (self *SInstance) GetSecurityGroups() ([]SSecurityGroup, error) { + return self.host.zone.region.GetSecurityGroups("", self.GetId(), "") +} + +// https://docs.ucloud.cn/api/uhost-api/get_uhost_instance_vnc_info +func (self *SRegion) GetInstanceVNCUrl(instanceId string) (*cloudprovider.ServerVncOutput, error) { + params := NewUcloudParams() + params.Set("UHostId", instanceId) + vnc := SVncInfo{} + err := self.DoAction("GetUHostInstanceVncInfo", params, &vnc) + if err != nil { + return nil, err + } + + ret := &cloudprovider.ServerVncOutput{ + Host: vnc.VNCIP, + Port: vnc.VNCPort, + Password: vnc.VNCPassword, + Hypervisor: api.HYPERVISOR_UCLOUD, + } + return ret, nil +} + +// https://docs.ucloud.cn/api/unet-api/grant_firewall +func (self *SRegion) assignSecurityGroups(instanceId string, secgroupId string) error { + params := NewUcloudParams() + params.Set("FWId", secgroupId) + params.Set("ResourceType", "uhost") + params.Set("ResourceId", instanceId) + + return self.DoAction("GrantFirewall", params, nil) +} + +// https://docs.ucloud.cn/api/uhost-api/start_uhost_instance +func (self *SRegion) StartVM(instanceId string) error { + params := NewUcloudParams() + params.Set("UHostId", instanceId) + + return self.DoAction("StartUHostInstance", params, nil) +} + +// https://docs.ucloud.cn/api/uhost-api/stop_uhost_instance +func (self *SRegion) StopVM(instanceId string) error { + params := NewUcloudParams() + params.Set("UHostId", instanceId) + + return self.DoAction("StopUHostInstance", params, nil) +} + +// https://docs.ucloud.cn/api/uhost-api/terminate_uhost_instance +func (self *SRegion) DeleteVM(instanceId string) error { + params := NewUcloudParams() + params.Set("UHostId", instanceId) + params.Set("Destroy", 1) // 跳过回收站,直接删除 + + return self.DoAction("TerminateUHostInstance", params, nil) +} + +// https://docs.ucloud.cn/api/uhost-api/modify_uhost_instance_name +func (self *SRegion) UpdateVM(instanceId, name string) error { + params := NewUcloudParams() + params.Set("UHostId", instanceId) + params.Set("Name", name) + + return self.DoAction("ModifyUHostInstanceName", params, nil) +} + +// ChargeType : Dynamic(按需)/Month(按月)/Year(按年) +func (self *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle) error { + params := NewUcloudParams() + params.Set("ResourceId", instanceId) + params.Set("ResourceType", "Host") + + if bc.GetMonths() >= 10 && bc.GetMonths() < 12 { + params.Set("ChargeType", "Year") + params.Set("Quantity", 1) + } else if bc.GetYears() >= 1 { + params.Set("ChargeType", "Year") + params.Set("Quantity", bc.GetYears()) + } else { + params.Set("ChargeType", "Month") + params.Set("Quantity", bc.GetMonths()) + } + + return self.DoAction("CreateRenew", params, nil) +} + +// https://docs.ucloud.cn/api/uhost-api/reset_uhost_instance_password +// 该操作需要UHost实例处于关闭状态。 +func (self *SRegion) ResetVMPasswd(instanceId, password string) error { + params := NewUcloudParams() + params.Set("UHostId", instanceId) + params.Set("Password", base64.StdEncoding.EncodeToString([]byte(password))) + + return self.DoAction("ResetUHostInstancePassword", params, nil) +} + +// https://docs.ucloud.cn/api/uhost-api/reinstall_uhost_instance +// (密码格式使用BASE64编码;LoginMode不可变更) +func (self *SRegion) RebuildRoot(instanceId, imageId, password string) error { + params := NewUcloudParams() + params.Set("UHostId", instanceId) + params.Set("Password", base64.StdEncoding.EncodeToString([]byte(password))) + params.Set("ImageId", imageId) + + return self.DoAction("ReinstallUHostInstance", params, nil) +} + +// https://docs.ucloud.cn/api/uhost-api/resize_uhost_instance +func (self *SRegion) ResizeVM(instanceId string, cpu, memoryMB int) error { + params := NewUcloudParams() + params.Set("UHostId", instanceId) + params.Set("CPU", cpu) + params.Set("Memory", memoryMB) + + return self.DoAction("ResizeUHostInstance", params, nil) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/instancenic.go new file mode 100644 index 0000000000..e67b74352e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/instancenic.go @@ -0,0 +1,56 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + instance *SInstance + ipAddr string + macAddr string + + cloudprovider.DummyICloudNic +} + +func (self *SInstanceNic) GetId() string { + return "" +} + +func (self *SInstanceNic) GetIP() string { + return self.ipAddr +} + +func (self *SInstanceNic) GetMAC() string { + return self.macAddr +} + +func (self *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (self *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (self *SInstanceNic) GetINetworkId() string { + for _, ip := range self.instance.IPSet { + if ip.IP == self.ipAddr { + return ip.SubnetID + } + } + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/latitud_and_longitude.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/latitud_and_longitude.go new file mode 100644 index 0000000000..974327013a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/latitud_and_longitude.go @@ -0,0 +1,48 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +// https://docs.ucloud.cn/api/summary/regionlist +var LatitudeAndLongitude = map[string]cloudprovider.SGeographicInfo{ + "cn-bj1": {Latitude: 39.9041999, Longitude: 116.4073963, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-bj2": {Latitude: 39.9041999, Longitude: 116.4073963, City: api.CITY_BEI_JING, CountryCode: api.COUNTRY_CODE_CN}, + "cn-sh": {Latitude: 31.2303904, Longitude: 121.4737021, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-sh2": {Latitude: 31.2303904, Longitude: 121.4737021, City: api.CITY_SHANG_HAI, CountryCode: api.COUNTRY_CODE_CN}, + "cn-gd": {Latitude: 23.12911, Longitude: 113.264385, City: api.CITY_GUANG_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, + "hk": {Latitude: 22.396428, Longitude: 114.109497, City: api.CITY_HONG_KONG, CountryCode: api.COUNTRY_CODE_CN}, + "us-ca": {Latitude: 34.0522342, Longitude: -118.2436849, City: api.CITY_LOS_ANGELES, CountryCode: api.COUNTRY_CODE_US}, + "us-ws": {Latitude: 38.9071923, Longitude: -77.0368707, City: api.CITY_WASHINGTON, CountryCode: api.COUNTRY_CODE_US}, + "ge-fra": {Latitude: 50.1109221, Longitude: 8.6821267, City: api.CITY_FRANKFURT, CountryCode: api.COUNTRY_CODE_DE}, + "th-bkk": {Latitude: 13.7563309, Longitude: 100.5017651, City: api.CITY_BANGKOK, CountryCode: api.COUNTRY_CODE_TH}, + "kr-seoul": {Latitude: 37.566535, Longitude: 126.9779692, City: api.CITY_SEOUL, CountryCode: api.COUNTRY_CODE_KR}, + "sg": {Latitude: 1.352083, Longitude: 103.819836, City: api.CITY_SINGAPORE, CountryCode: api.COUNTRY_CODE_SG}, + "tw-tp": {Latitude: 25.0329694, Longitude: 121.5654177, City: api.CITY_TAIPEI, CountryCode: api.COUNTRY_CODE_CN}, + "tw-kh": {Latitude: 22.6272784, Longitude: 120.3014353, City: api.CITY_KAOHSIUNG, CountryCode: api.COUNTRY_CODE_CN}, + "jpn-tky": {Latitude: 35.7090259, Longitude: 139.7319925, City: api.CITY_TOKYO, CountryCode: api.COUNTRY_CODE_JP}, + "rus-mosc": {Latitude: 55.755826, Longitude: 37.6172999, City: api.CITY_MOSCOW, CountryCode: api.COUNTRY_CODE_RU}, + "uae-dubai": {Latitude: 25.2048493, Longitude: 55.2707828, City: api.CITY_DUBAI, CountryCode: api.COUNTRY_CODE_AE}, + "idn-jakarta": {Latitude: -6.2087634, Longitude: 106.845599, City: api.CITY_JAKARTA, CountryCode: api.COUNTRY_CODE_ID}, + "ind-mumbai": {Latitude: 19.0759837, Longitude: 72.8776559, City: api.CITY_MUMBAI, CountryCode: api.COUNTRY_CODE_IN}, + "bra-saopaulo": {Latitude: -23.5505199, Longitude: -46.6333094, City: api.CITY_SAO_PAULO, CountryCode: api.COUNTRY_CODE_BR}, + "uk-london": {Latitude: 51.5073509, Longitude: -0.1277583, City: api.CITY_LONDON, CountryCode: api.COUNTRY_CODE_GB}, + "afr-nigeria": {Latitude: 6.5243793, Longitude: 3.3792057, City: api.CITY_LAGOS, CountryCode: api.COUNTRY_CODE_NG}, + "vn-sng": {Latitude: 10.8230989, Longitude: 106.6296638, City: api.CITY_HO_CHI_MINH, CountryCode: api.COUNTRY_CODE_VN}, + "cn-qz": {Latitude: 24.9037185, Longitude: 118.5134676, City: api.CITY_QUAN_ZHOU, CountryCode: api.COUNTRY_CODE_CN}, +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/network.go new file mode 100644 index 0000000000..76f0a5b973 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/network.go @@ -0,0 +1,201 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +// https://docs.ucloud.cn/api/vpc2.0-api/describe_subnet +type SNetwork struct { + multicloud.SResourceBase + UcloudTags + wire *SWire + + CreateTime int64 `json:"CreateTime"` + Gateway string `json:"Gateway"` + HasNATGW bool `json:"HasNATGW"` + Name string `json:"Name"` + Netmask string `json:"Netmask"` + Remark string `json:"Remark"` + RouteTableID string `json:"RouteTableId"` + Subnet string `json:"Subnet"` + SubnetID string `json:"SubnetId"` + SubnetName string `json:"SubnetName"` + SubnetType int `json:"SubnetType"` + Tag string `json:"Tag"` + VPCID string `json:"VPCId"` + VPCName string `json:"VPCName"` + VRouterID string `json:"VRouterId"` + Zone string `json:"Zone"` +} + +func (self *SNetwork) GetProjectId() string { + return self.wire.region.client.projectId +} + +func (self *SNetwork) GetId() string { + return self.SubnetID +} + +func (self *SNetwork) GetName() string { + if len(self.SubnetName) > 0 { + return self.SubnetName + } + + return self.GetId() +} + +func (self *SNetwork) GetGlobalId() string { + return self.GetId() +} + +func (self *SNetwork) GetStatus() string { + return api.NETWORK_STATUS_AVAILABLE +} + +func (self *SNetwork) Refresh() error { + log.Debugf("network refresh %s", self.GetId()) + new, err := self.wire.region.getNetwork(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SNetwork) IsEmulated() bool { + return false +} + +func (self *SNetwork) GetIWire() cloudprovider.ICloudWire { + return self.wire +} + +func (self *SNetwork) GetIpStart() string { + pref, _ := netutils.NewIPV4Prefix(self.Subnet + "/" + self.Netmask) + startIp := pref.Address.NetAddr(pref.MaskLen) // 0 + startIp = startIp.StepUp() // 1 gateway + startIp = startIp.StepUp() // 2 + return startIp.String() +} + +func (self *SNetwork) GetIpEnd() string { + pref, _ := netutils.NewIPV4Prefix(self.Subnet + "/" + self.Netmask) + endIp := pref.Address.BroadcastAddr(pref.MaskLen) // 255 + endIp = endIp.StepDown() // 254 + return endIp.String() +} + +func (self *SNetwork) GetIpMask() int8 { + pref, _ := netutils.NewIPV4Prefix(self.Subnet + "/" + self.Netmask) + return pref.MaskLen +} + +func (self *SNetwork) GetGateway() string { + return self.Gateway +} + +func (self *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (self *SNetwork) GetIsPublic() bool { + return true +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeDomain +} + +func (self *SNetwork) Delete() error { + return self.wire.region.DeleteNetwork(self.GetId()) +} + +func (self *SNetwork) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +// https://docs.ucloud.cn/api/vpc2.0-api/describe_subnet +func (self *SRegion) getNetwork(networkId string) (*SNetwork, error) { + if len(networkId) == 0 { + return nil, fmt.Errorf("getNetwork network id should not be empty") + } + networks := make([]SNetwork, 0) + + params := NewUcloudParams() + params.Set("SubnetId", networkId) + err := self.DoListAll("DescribeSubnet", params, &networks) + if err != nil { + return nil, err + } + + if len(networks) == 1 { + network := networks[0] + vpc, err := self.getVpc(network.VPCID) + if err != nil { + return nil, err + } + network.wire = &SWire{region: self, vpc: vpc, inetworks: []cloudprovider.ICloudNetwork{&network}} + return &network, nil + } else if len(networks) == 0 { + return nil, cloudprovider.ErrNotFound + } else { + return nil, fmt.Errorf("getNetwork %s %d found", networkId, len(networks)) + } +} + +// https://docs.ucloud.cn/api/vpc2.0-api/delete_subnet +func (self *SRegion) DeleteNetwork(networkId string) error { + params := NewUcloudParams() + params.Set("SubnetId", networkId) + + return self.DoAction("DeleteSubnet", params, nil) +} + +// https://docs.ucloud.cn/api/vpc2.0-api/create_subnet +func (self *SRegion) CreateNetwork(vpcId string, name string, cidr string, desc string) (*SNetwork, error) { + ip, mask, err := netutils.ParsePrefix(cidr) + if err != nil { + return nil, fmt.Errorf("CreateINetwork invalid cidr %s", cidr) + } + + params := NewUcloudParams() + params.Set("VPCId", vpcId) + params.Set("Subnet", ip.String()) + params.Set("Netmask", int(mask)) + params.Set("SubnetName", name) + params.Set("Remark", desc) + + type SNet struct { + SubnetId string + } + + net := SNet{} + err = self.DoAction("CreateSubnet", params, &net) + if err != nil { + return nil, err + } + + return self.getNetwork(net.SubnetId) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/project.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/project.go new file mode 100644 index 0000000000..8b787e8c7f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/project.go @@ -0,0 +1,64 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://docs.ucloud.cn/api/summary/get_project_list +type SProject struct { + multicloud.SProjectBase + UcloudTags + ProjectID string `json:"ProjectId"` + ProjectName string `json:"ProjectName"` + ParentID string `json:"ParentId"` + ParentName string `json:"ParentName"` + CreateTime int64 `json:"CreateTime"` + IsDefault bool `json:"IsDefault"` + MemberCount int64 `json:"MemberCount"` + ResourceCount int64 `json:"ResourceCount"` +} + +func (self *SProject) GetId() string { + return self.ProjectID +} + +func (self *SProject) GetName() string { + return self.ProjectName +} + +func (self *SProject) GetGlobalId() string { + return self.GetId() +} + +func (self *SProject) GetStatus() string { + return "" +} + +func (self *SProject) Refresh() error { + return nil +} + +func (self *SProject) IsEmulated() bool { + return false +} + +func (self *SUcloudClient) FetchProjects() ([]SProject, error) { + params := NewUcloudParams() + projects := make([]SProject, 0) + err := self.DoListAll("GetProjectList", params, &projects) + return projects, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/provider/doc.go new file mode 100644 index 0000000000..201deebd4f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/ucloud/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/provider/provider.go new file mode 100644 index 0000000000..91f26c13a3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/provider/provider.go @@ -0,0 +1,193 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/ucloud" +) + +// tag:finished +type SUcloudProviderFactory struct { + cloudprovider.SPublicCloudBaseProviderFactory +} + +func (self *SUcloudProviderFactory) GetId() string { + return ucloud.CLOUD_PROVIDER_UCLOUD +} + +func (self *SUcloudProviderFactory) GetName() string { + return ucloud.CLOUD_PROVIDER_UCLOUD_CN +} + +func (self *SUcloudProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + return output, nil +} + +func (self *SUcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id") + } + if len(input.AccessKeySecret) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_secret") + } + output = cloudprovider.SCloudaccount{ + Account: input.AccessKeyId, + Secret: input.AccessKeySecret, + } + return output, nil +} + +func parseAccount(account string) (accessKey string, projectId string) { + segs := strings.Split(account, "::") + if len(segs) == 2 { + accessKey = segs[0] + projectId = segs[1] + } else { + accessKey = account + projectId = "" + } + + return +} + +func (self *SUcloudProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + accessKey, projectId := parseAccount(cfg.Account) + client, err := ucloud.NewUcloudClient( + ucloud.NewUcloudClientConfig( + accessKey, cfg.Secret, + ).ProjectId(projectId).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SUcloudProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SUcloudProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + accessKey, projectId := parseAccount(info.Account) + return map[string]string{ + "UCLOUD_ACCESS_KEY": accessKey, + "UCLOUD_SECRET": info.Secret, + "UCLOUD_REGION": ucloud.UCLOUD_DEFAULT_REGION, + "UCLOUD_PROJECT": projectId, + }, nil +} + +func init() { + factory := SUcloudProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SUcloudProvider struct { + cloudprovider.SBaseProvider + client *ucloud.SUcloudClient +} + +func (self *SUcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + projects, err := self.client.FetchProjects() + if err != nil { + return nil, err + } + + iprojects := make([]cloudprovider.ICloudProject, len(projects)) + for i := range projects { + iprojects[i] = &projects[i] + } + + return iprojects, nil +} + +func (self *SUcloudProvider) GetSysInfo() (jsonutils.JSONObject, error) { + regions := self.client.GetIRegions() + info := jsonutils.NewDict() + info.Add(jsonutils.NewInt(int64(len(regions))), "region_count") + info.Add(jsonutils.NewString(ucloud.UCLOUD_API_VERSION), "api_version") + return info, nil +} + +func (self *SUcloudProvider) GetVersion() string { + return ucloud.UCLOUD_API_VERSION +} + +func (self *SUcloudProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SUcloudProvider) GetAccountId() string { + return self.client.GetAccountId() +} + +func (self *SUcloudProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SUcloudProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(extId) +} + +func (self *SUcloudProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_NORMAL, cloudprovider.ErrNotSupported +} + +func (self *SUcloudProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SUcloudProvider) GetStorageClasses(regionId string) []string { + return []string{ + "STANDARD", "IA", "ARCHIVE", + } +} + +func (self *SUcloudProvider) GetBucketCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLPublicRead), + } +} + +func (self *SUcloudProvider) GetObjectCannedAcls(regionId string) []string { + return []string{ + string(cloudprovider.ACLPrivate), + string(cloudprovider.ACLPublicRead), + } +} + +func (self *SUcloudProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/region.go new file mode 100644 index 0000000000..3f9a51f30d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/region.go @@ -0,0 +1,697 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "fmt" + "strings" + + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + multicloud.SRegion + client *SUcloudClient + + RegionID string + + izones []cloudprovider.ICloudZone + ivpcs []cloudprovider.ICloudVpc + + storageCache *SStoragecache + + latitude float64 + longitude float64 + fetchLocation bool +} + +func (self *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetId() string { + return self.RegionID +} + +func (self *SRegion) GetName() string { + if name, exist := UCLOUD_REGION_NAMES[self.GetId()]; exist { + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_UCLOUD_CN, name) + } + + return fmt.Sprintf("%s %s", CLOUD_PROVIDER_UCLOUD_CN, self.GetId()) +} + +func (self *SRegion) GetI18n() cloudprovider.SModelI18nTable { + var en string + if name, exist := UCLOUD_REGION_NAMES_EN[self.GetId()]; exist { + en = fmt.Sprintf("%s %s", CLOUD_PROVIDER_UCLOUD, name) + } else { + en = fmt.Sprintf("%s %s", CLOUD_PROVIDER_UCLOUD, self.GetId()) + } + + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_UCLOUD, self.GetId()) +} + +func (self *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (self *SRegion) Refresh() error { + return nil +} + +func (self *SRegion) IsEmulated() bool { + return false +} + +func (self *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + if info, ok := LatitudeAndLongitude[self.GetId()]; ok { + return info + } + return cloudprovider.SGeographicInfo{} +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + instance, err := self.GetInstanceByID(id) + if err != nil { + return nil, err + } + return &instance, nil +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + return self.GetDisk(id) +} + +func (self *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if self.izones == nil { + var err error + err = self.fetchInfrastructure() + if 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 +} + +// https://docs.ucloud.cn/api/unet-api/describe_eip +func (self *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + params := NewUcloudParams() + eips := make([]SEip, 0) + err := self.DoListAll("DescribeEIP", params, &eips) + if err != nil { + return nil, err + } + + ieips := []cloudprovider.ICloudEIP{} + for i := range eips { + eip := eips[i] + eip.region = self + ieips = append(ieips, &eip) + } + + return ieips, nil +} + +func (self *SRegion) GetIVpcById(id string) (cloudprovider.ICloudVpc, error) { + ivpcs, err := self.GetIVpcs() + if err != nil { + return nil, err + } + for i := 0; i < len(ivpcs); i += 1 { + if ivpcs[i].GetGlobalId() == id { + return ivpcs[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetEipById(eipId string) (SEip, error) { + params := NewUcloudParams() + params.Set("EIPIds.0", eipId) + eips := make([]SEip, 0) + err := self.DoListAll("DescribeEIP", params, &eips) + if err != nil { + return SEip{}, err + } + + if len(eips) == 1 { + eip := eips[0] + eip.region = self + return eip, nil + } else if len(eips) == 0 { + return SEip{}, cloudprovider.ErrNotFound + } else { + return SEip{}, fmt.Errorf("GetEipById %d eip found", len(eips)) + } +} + +func (self *SRegion) GetIEipById(id string) (cloudprovider.ICloudEIP, error) { + eip, err := self.GetEipById(id) + return &eip, err +} + +// https://docs.ucloud.cn/api/unet-api/delete_firewall +func (self *SRegion) DeleteSecurityGroup(secgroupId string) error { + params := NewUcloudParams() + params.Set("FWId", secgroupId) + return self.DoAction("DeleteFirewall", params, nil) +} + +func (self *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return self.GetSecurityGroupById(secgroupId) +} + +func (self *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := self.GetSecurityGroups("", "", opts.Name) + if err != nil { + return nil, err + } + if len(secgroups) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(secgroups) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return &secgroups[0], nil +} + +func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + externalId, err := self.CreateDefaultSecurityGroup(conf.Name, conf.Desc) + if err != nil { + return nil, err + } + return self.GetISecurityGroupById(externalId) +} + +// https://docs.ucloud.cn/api/unet-api/describe_firewall +// 绑定防火墙组的资源类型,默认为全部资源类型。枚举值为:"unatgw",NAT网关; "uhost",云主机; "upm",物理云主机; "hadoophost",hadoop节点; "fortresshost",堡垒机; "udhost",私有专区主机;"udockhost",容器;"dbaudit",数据库审计. +// todo: 是否需要过滤出仅绑定云主机的安全组? + +func (self *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + params := NewUcloudParams() + params.Set("Name", opts.NAME) + params.Set("Remark", opts.Desc) + for i, cidr := range strings.Split(opts.CIDR, ",") { + params.Set(fmt.Sprintf("Network.%d", i), cidr) + } + + vpcId := "" + err := self.DoAction("CreateVPC", params, &vpcId) + if err != nil { + return nil, err + } + + return self.GetIVpcById(vpcId) +} + +// https://docs.ucloud.cn/api/udisk-api/describe_udisk_snapshot +func (self *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + params := NewUcloudParams() + snapshots := make([]SSnapshot, 0) + err := self.DoListAll("DescribeUDiskSnapshot", params, &snapshots) + if err != nil { + return nil, err + } + + isnapshots := make([]cloudprovider.ICloudSnapshot, 0) + for i := range snapshots { + snapshots[i].region = self + isnapshots = append(isnapshots, &snapshots[i]) + } + + return isnapshots, nil +} + +func (self *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + if len(snapshotId) == 0 { + return nil, cloudprovider.ErrNotFound + } + + params := NewUcloudParams() + snapshots := make([]SSnapshot, 0) + err := self.DoListAll("DescribeUDiskSnapshot", params, &snapshots) + if err != nil { + return nil, err + } + + for i := range snapshots { + if snapshots[i].SnapshotID == snapshotId { + snapshot := snapshots[i] + snapshot.region = self + return &snapshot, nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + iHosts := make([]cloudprovider.ICloudHost, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneHost, err := izones[i].GetIHosts() + if err != nil { + return nil, err + } + iHosts = append(iHosts, iZoneHost...) + } + return iHosts, nil +} + +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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + iStores := make([]cloudprovider.ICloudStorage, 0) + + izones, err := self.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i += 1 { + iZoneStores, err := izones[i].GetIStorages() + if err != nil { + return nil, err + } + iStores = append(iStores, iZoneStores...) + } + return iStores, nil +} + +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 errors.Cause(err) != cloudprovider.ErrNotFound { + return nil, err + } + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) getStoragecache() *SStoragecache { + if self.storageCache == nil { + self.storageCache = &SStoragecache{region: self} + } + return self.storageCache +} + +func (self *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + return []cloudprovider.ICloudStoragecache{storageCache}, nil +} + +func (self *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + storageCache := self.getStoragecache() + if storageCache.GetGlobalId() == id { + return storageCache, nil + } + return nil, cloudprovider.ErrNotFound +} + +func (self *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SRegion) GetSkus(zoneId string) ([]cloudprovider.ICloudSku, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SRegion) GetProvider() string { + return CLOUD_PROVIDER_UCLOUD +} + +func (self *SRegion) GetCloudEnv() string { + return "" +} + +func (self *SRegion) DoListAll(action string, params SParams, result interface{}) error { + params.Set("Region", self.GetId()) + return self.client.DoListAll(action, params, result) +} + +// return total,lenght,error +func (self *SRegion) DoListPart(action string, limit int, offset int, params SParams, result interface{}) (int, int, error) { + params.Set("Region", self.GetId()) + return self.client.DoListPart(action, limit, offset, params, result) +} + +func (self *SRegion) DoAction(action string, params SParams, result interface{}) error { + params.Set("Region", self.GetId()) + return self.client.DoAction(action, params, result) +} + +func (self *SRegion) fetchInfrastructure() error { + 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 { + vpc := self.ivpcs[i].(*SVPC) + wire := SWire{region: self, vpc: vpc} + vpc.addWire(&wire) + + for j := 0; j < len(self.izones); j += 1 { + zone := self.izones[j].(*SZone) + zone.addWire(&wire) + } + } + return nil +} + +func (self *SRegion) fetchZones() error { + type Region struct { + RegionID int64 `json:"RegionId"` + RegionName string `json:"RegionName"` + IsDefault bool `json:"IsDefault"` + BitMaps string `json:"BitMaps"` + Region string `json:"Region"` + Zone string `json:"Zone"` + } + + params := NewUcloudParams() + regions := make([]Region, 0) + err := self.client.DoListAll("GetRegion", params, ®ions) + if err != nil { + return err + } + + for _, r := range regions { + if r.Region != self.GetId() { + continue + } + + szone := SZone{} + szone.ZoneId = r.Zone + szone.RegionId = r.Region + szone.region = self + self.izones = append(self.izones, &szone) + } + + return nil +} + +func (self *SRegion) fetchIVpcs() error { + vpcs := make([]SVPC, 0) + params := NewUcloudParams() + err := self.DoListAll("DescribeVPC", params, &vpcs) + if err != nil { + return err + } + + for i := range vpcs { + vpc := vpcs[i] + vpc.region = self + self.ivpcs = append(self.ivpcs, &vpc) + } + + return nil +} + +// https://docs.ucloud.cn/api/uhost-api/describe_uhost_instance +func (self *SRegion) GetInstanceByID(instanceId string) (SInstance, error) { + params := NewUcloudParams() + params.Set("UHostIds.0", instanceId) + instances := make([]SInstance, 0) + err := self.DoAction("DescribeUHostInstance", params, &instances) + if err != nil { + return SInstance{}, err + } + + if len(instances) == 1 { + return instances[0], nil + } else if len(instances) == 0 { + return SInstance{}, cloudprovider.ErrNotFound + } else { + return SInstance{}, fmt.Errorf("GetInstanceByID %s %d found.", instanceId, len(instances)) + } +} + +// GRE协议被忽略了 +func toUcloudSecRule(rule cloudprovider.SecurityRule) []string { + net := rule.IPNet.String() + action := "DROP" + if rule.Action == secrules.SecurityRuleAllow { + action = "ACCEPT" + } + + rules := make([]string, 0) + if len(rule.Ports) > 0 { + for _, port := range rule.Ports { + _rules := generatorRule(rule.Protocol, net, action, port, port, rule.Priority) + rules = append(rules, _rules...) + } + } else { + _rules := generatorRule(rule.Protocol, net, action, rule.PortStart, rule.PortEnd, rule.Priority) + rules = append(rules, _rules...) + } + + return rules +} + +func generatorRule(protocol, net, action string, startPort, endPort, priority int) []string { + rules := make([]string, 0) + + var ports string + if startPort <= 0 || endPort <= 0 { + ports = "1-65535" + } else if startPort == endPort { + ports = fmt.Sprintf("%d", startPort) + } else { + ports = fmt.Sprintf("%d-%d", startPort, endPort) + } + prio := "LOW" + switch priority { + case 1: + prio = "LOW" + case 2: + prio = "MEDIUM" + case 3: + prio = "HIGH" + } + + template := fmt.Sprintf("%s|%s|%s|%s|%s|", "%s", "%s", net, action, prio) + switch protocol { + case secrules.PROTO_ANY: + rules = append(rules, fmt.Sprintf(template, "TCP", ports)) + rules = append(rules, fmt.Sprintf(template, "UDP", ports)) + rules = append(rules, fmt.Sprintf(template, "ICMP", "")) + case secrules.PROTO_TCP: + rules = append(rules, fmt.Sprintf(template, "TCP", ports)) + case secrules.PROTO_UDP: + rules = append(rules, fmt.Sprintf(template, "UDP", ports)) + case secrules.PROTO_ICMP: + rules = append(rules, fmt.Sprintf(template, "ICMP", "")) + } + + return rules +} + +// https://docs.ucloud.cn/api/unet-api/update_firewall +func (self *SRegion) syncSecgroupRules(secgroupId string, rules []cloudprovider.SecurityRule) error { + _rules := []string{} + for _, r := range rules { + _rules = append(_rules, toUcloudSecRule(r)...) + } + + params := NewUcloudParams() + params.Set("FWId", secgroupId) + for i, r := range _rules { + N := i + 1 + params.Set(fmt.Sprintf("Rule.%d", N), r) + } + + return self.DoAction("UpdateFirewall", params, nil) +} + +func (self *SRegion) GetClient() *SUcloudClient { + return self.client +} + +// https://docs.ucloud.cn/api/ufile-api/describe_bucket +func (client *SUcloudClient) listBuckets(name string, offset int, limit int) ([]SBucket, error) { + params := NewUcloudParams() + if len(name) > 0 { + params.Set("BucketName", name) + } else { + params.Set("Limit", limit) + params.Set("Offset", offset) + } + buckets := make([]SBucket, 0) + // request without RegionId + err := client.DoAction("DescribeBucket", params, &buckets) + if err != nil { + return nil, errors.Wrap(err, "DoAction DescribeBucket") + } + return buckets, nil +} + +// https://docs.ucloud.cn/api/ufile-api/update_bucket +func (region *SRegion) updateBucket(name string, aclType string) error { + params := NewUcloudParams() + params.Set("BucketName", name) + params.Set("ProjectId", region.client.projectId) + params.Set("Type", aclType) + return region.client.DoAction("UpdateBucket", params, nil) +} + +func (region *SRegion) GetIBuckets() ([]cloudprovider.ICloudBucket, error) { + iBuckets, err := region.client.getIBuckets() + if err != nil { + return nil, errors.Wrap(err, "getIBuckets") + } + ret := make([]cloudprovider.ICloudBucket, 0) + for i := range iBuckets { + if iBuckets[i].GetLocation() != region.GetId() { + continue + } + ret = append(ret, iBuckets[i]) + } + return ret, nil +} + +func (region *SRegion) CreateIBucket(name string, storageClassStr string, aclStr string) error { + if aclStr != "private" && aclStr != "public" { + return errors.Error("invalid acl") + } + return region.CreateBucket(name, aclStr) +} + +func (region *SRegion) DeleteIBucket(name string) error { + err := region.DeleteBucket(name) + if err != nil { + if strings.Index(err.Error(), "bucket not found") >= 0 { + return nil + } + return errors.Wrap(err, "region.DeleteBucket") + } + return nil +} + +func (region *SRegion) IBucketExist(name string) (bool, error) { + parts, err := region.client.listBuckets(name, 0, 1) + if err != nil { + return false, errors.Wrap(err, "region.listBuckets") + } + if len(parts) == 0 { + return false, cloudprovider.ErrNotFound + } + return true, nil +} + +func (region *SRegion) GetIBucketById(bucketId string) (cloudprovider.ICloudBucket, error) { + return cloudprovider.GetIBucketById(region, bucketId) +} + +func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { + return region.GetIBucketByName(name) +} + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/securitygroup.go new file mode 100644 index 0000000000..0ddea31e89 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/securitygroup.go @@ -0,0 +1,253 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "fmt" + "math/rand" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://docs.ucloud.cn/api/unet-api/describe_firewall +type SSecurityGroup struct { + multicloud.SSecurityGroup + UcloudTags + region *SRegion + vpc *SVPC // 安全组在UCLOUD实际上与VPC是没有直接关联的。这里的vpc字段只是为了统一,仅仅是标记是哪个VPC在操作该安全组。 + + CreateTime int64 `json:"CreateTime"` + FWID string `json:"FWId"` + GroupID string `json:"GroupId"` + Name string `json:"Name"` + Remark string `json:"Remark"` + ResourceCount int `json:"ResourceCount"` + Rule []Rule `json:"Rule"` + Tag string `json:"Tag"` + Type string `json:"Type"` +} + +func (self *SSecurityGroup) GetProjectId() string { + return self.region.client.projectId +} + +type Rule struct { + DstPort string `json:"DstPort"` + Priority string `json:"Priority"` + ProtocolType string `json:"ProtocolType"` + RuleAction string `json:"RuleAction"` + SrcIP string `json:"SrcIP"` +} + +func (self *SSecurityGroup) GetId() string { + return self.FWID +} + +func (self *SSecurityGroup) GetName() string { + if len(self.Name) == 0 { + return self.GetId() + } + + return self.Name +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.GetId() +} + +func (self *SSecurityGroup) GetStatus() string { + return "" +} + +func (self *SSecurityGroup) Refresh() error { + if new, err := self.region.GetSecurityGroupById(self.GetId()); err != nil { + return err + } else { + return jsonutils.Update(self, new) + } +} + +func (self *SSecurityGroup) IsEmulated() bool { + return false +} + +func (self *SSecurityGroup) GetDescription() string { + return self.Remark +} + +func (self *SSecurityGroup) UcloudSecRuleToOnecloud(rule Rule) (cloudprovider.SecurityRule, error) { + secrule := cloudprovider.SecurityRule{} + switch rule.Priority { + case "HIGH": + secrule.Priority = 3 + case "MEDIUM": + secrule.Priority = 2 + case "LOW": + secrule.Priority = 1 + default: + secrule.Priority = 1 + } + + switch rule.RuleAction { + case "ACCEPT": + secrule.Action = secrules.SecurityRuleAllow + case "DROP": + secrule.Action = secrules.SecurityRuleDeny + default: + secrule.Action = secrules.SecurityRuleDeny + } + + secrule.ParseCIDR(rule.SrcIP) + secrule.Protocol = strings.ToLower(rule.ProtocolType) + secrule.Direction = secrules.SecurityRuleIngress + err := secrule.ParsePorts(rule.DstPort) + if err != nil { + return secrule, errors.Wrapf(err, "ParsePorts(%s)", rule.DstPort) + } + + return secrule, nil +} + +// https://docs.ucloud.cn/network/firewall/firewall +// 只有入方向规则 +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + rules := make([]cloudprovider.SecurityRule, 0) + for _, r := range self.Rule { + rule, err := self.UcloudSecRuleToOnecloud(r) + if err != nil { + log.Errorf("failed to convert rule for group %s(%s) error: %v", self.Name, self.GroupID, err) + continue + } + rules = append(rules, rule) + } + + return rules, nil +} + +func (self *SSecurityGroup) GetVpcId() string { + // 无vpc关联的安全组统一返回normal + return api.NORMAL_VPC_ID +} + +func (self *SRegion) GetSecurityGroupById(secGroupId string) (*SSecurityGroup, error) { + secgroups, err := self.GetSecurityGroups(secGroupId, "", "") + if err != nil { + return nil, err + } + + if len(secgroups) == 1 { + return &secgroups[0], nil + } else if len(secgroups) == 0 { + return nil, cloudprovider.ErrNotFound + } else { + return nil, fmt.Errorf("GetSecurityGroupById %s %d found", secGroupId, len(secgroups)) + } +} + +func randomString(prefix string, length int) string { + bytes := []byte("0123456789abcdefghijklmnopqrstuvwxyz") + result := []byte{} + r := rand.New(rand.NewSource(time.Now().UnixNano())) + for i := 0; i < length; i++ { + result = append(result, bytes[r.Intn(len(bytes))]) + } + return prefix + string(result) +} + +func (self *SRegion) CreateDefaultSecurityGroup(name, description string) (string, error) { + // 减少安全组名称冲突 + name = randomString(name, 4) + return self.CreateSecurityGroup(name, description, []string{"TCP|1-65535|0.0.0.0/0|ACCEPT|LOW", "UDP|1-65535|0.0.0.0/0|ACCEPT|LOW", "ICMP||0.0.0.0/0|ACCEPT|LOW"}) +} + +// https://docs.ucloud.cn/api/unet-api/create_firewall +func (self *SRegion) CreateSecurityGroup(name, description string, rules []string) (string, error) { + params := NewUcloudParams() + params.Set("Name", name) + params.Set("Remark", description) + if len(rules) == 0 { + return "", fmt.Errorf("CreateSecurityGroup required at least one rule") + } + + for i, rule := range rules { + params.Set(fmt.Sprintf("Rule.%d", i), rule) + } + + type Firewall struct { + FWId string + } + + firewall := Firewall{} + err := self.DoAction("CreateFirewall", params, &firewall) + if err != nil { + return "", err + } + + return firewall.FWId, nil +} + +// https://docs.ucloud.cn/api/unet-api/describe_firewall +func (self *SRegion) GetSecurityGroups(secGroupId string, resourceId string, name string) ([]SSecurityGroup, error) { + secgroups := make([]SSecurityGroup, 0) + + params := NewUcloudParams() + if len(secGroupId) > 0 { + params.Set("FWId", secGroupId) + } + + if len(resourceId) > 0 { + params.Set("ResourceId", resourceId) + params.Set("ResourceType", "uhost") // 默认只支持"uhost",云主机 + } + err := self.DoListAll("DescribeFirewall", params, &secgroups) + if err != nil { + if strings.Contains(err.Error(), "not exist") { + return nil, cloudprovider.ErrNotFound + } + return nil, err + } + + result := []SSecurityGroup{} + + for i := range secgroups { + if len(name) == 0 || secgroups[i].Name == name { + secgroups[i].region = self + result = append(result, secgroups[i]) + } + } + + return result, nil +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + if len(inAdds) == 0 && len(inDels) == 0 { + return nil + } + rules := append(common, inAdds...) + return self.region.syncSecgroupRules(self.FWID, rules) +} + +func (self *SSecurityGroup) Delete() error { + return self.region.DeleteSecurityGroup(self.FWID) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/snapshot.go new file mode 100644 index 0000000000..9cb95c4877 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/snapshot.go @@ -0,0 +1,207 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://docs.ucloud.cn/api/udisk-api/describe_udisk_snapshot +type SSnapshot struct { + multicloud.SResourceBase + UcloudTags + region *SRegion + + Comment string `json:"Comment"` + ChargeType string `json:"ChargeType"` + Name string `json:"Name"` + UDiskName string `json:"UDiskName"` + ExpiredTime int64 `json:"ExpiredTime"` + UDiskID string `json:"UDiskId"` + SnapshotID string `json:"SnapshotId"` + CreateTime int64 `json:"CreateTime"` + SizeGB int32 `json:"Size"` + Status string `json:"Status"` + IsUDiskAvailable bool `json:"IsUDiskAvailable"` + Version string `json:"Version"` + DiskType int `json:"DiskType"` + UHostID string `json:"UHostId"` +} + +func (self *SSnapshot) GetProjectId() string { + return self.region.client.projectId +} + +func (self *SSnapshot) GetId() string { + return self.SnapshotID +} + +func (self *SSnapshot) GetName() string { + if len(self.Name) == 0 { + return self.GetId() + } + + return self.Name +} + +func (self *SSnapshot) GetGlobalId() string { + return self.GetId() +} + +// 快照状态,Normal:正常,Failed:失败,Creating:制作中 +func (self *SSnapshot) GetStatus() string { + switch self.Status { + case "Normal": + return api.SNAPSHOT_READY + case "Failed": + return api.SNAPSHOT_FAILED + case "Creating": + return api.SNAPSHOT_CREATING + default: + return api.SNAPSHOT_UNKNOWN + } +} + +func (self *SSnapshot) Refresh() error { + disk, err := self.region.GetDisk(self.UDiskID) + if err != nil { + return err + } + + snapshot, err := self.region.GetSnapshotById(disk.Zone, self.GetId()) + if err != nil { + return err + } + + if err := jsonutils.Update(self, snapshot); err != nil { + return err + } + + return nil +} + +func (self *SSnapshot) IsEmulated() bool { + return false +} + +func (self *SSnapshot) GetSizeMb() int32 { + return self.SizeGB * 1024 +} + +func (self *SSnapshot) GetDiskId() string { + return self.UDiskID +} + +// 磁盘类型,0:数据盘,1:系统盘 +func (self *SSnapshot) GetDiskType() string { + if self.DiskType == 1 { + return api.DISK_TYPE_SYS + } else { + return api.DISK_TYPE_DATA + } +} + +// https://docs.ucloud.cn/api/udisk-api/delete_udisk_snapshot +func (self *SSnapshot) Delete() error { + zoneId := "" + idisk, err := self.region.GetDisk(self.UDiskID) + if err == nil { + zoneId = idisk.Zone + } else if errors.Cause(err) == cloudprovider.ErrNotFound { + zones, err := self.region.GetIZones() + if err != nil { + return errors.Wrap(err, "snapshot.Delete GetIZones") + } + + for _, zone := range zones { + if _, err := self.region.GetSnapshotById(zone.GetId(), self.GetId()); err == nil { + zoneId = zone.GetId() + break + } + } + } else { + return errors.Wrap(err, "snapshot.Delete") + } + + if len(zoneId) == 0 { + return fmt.Errorf("snapshot.Delete can not found snapshot %s zone id", self.GetId()) + } + + return self.region.DeleteSnapshot(self.GetId(), zoneId) +} + +func (self *SRegion) GetSnapshotById(zoneId string, snapshotId string) (SSnapshot, error) { + snapshots, err := self.GetSnapshots(zoneId, "", snapshotId) + if err != nil { + return SSnapshot{}, err + } + + if len(snapshots) == 1 { + return snapshots[0], nil + } else if len(snapshots) == 0 { + return SSnapshot{}, cloudprovider.ErrNotFound + } else { + return SSnapshot{}, fmt.Errorf("GetSnapshotById %s %d found", snapshotId, len(snapshots)) + } +} + +func (self *SRegion) GetSnapshots(zoneId string, diskId string, snapshotId string) ([]SSnapshot, error) { + params := NewUcloudParams() + if len(diskId) > 0 { + disk, err := self.GetDisk(diskId) + if err != nil { + return nil, err + } + + params.Set("UDiskId", diskId) + params.Set("Zone", disk.Zone) + } + + if len(zoneId) > 0 { + params.Set("Zone", zoneId) + } + + if len(snapshotId) > 0 { + params.Set("SnapshotId", snapshotId) + } + + snapshots := make([]SSnapshot, 0) + err := self.DoAction("DescribeUDiskSnapshot", params, &snapshots) + if err != nil { + return nil, err + } + + for i := range snapshots { + snapshots[i].region = self + } + + return snapshots, nil +} + +// https://docs.ucloud.cn/api/udisk-api/delete_udisk_snapshot +func (self *SRegion) DeleteSnapshot(snapshotId string, zoneId string) error { + params := NewUcloudParams() + params.Set("SnapshotId", snapshotId) + params.Set("Zone", zoneId) + + return self.DoAction("DeleteUDiskSnapshot", params, nil) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/storage.go new file mode 100644 index 0000000000..de01147e4d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/storage.go @@ -0,0 +1,157 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SStorage struct { + multicloud.SStorageBase + UcloudTags + zone *SZone + storageType string +} + +func (self *SStorage) GetId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetName() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Name, self.zone.GetId(), self.storageType) +} + +func (self *SStorage) GetGlobalId() string { + return fmt.Sprintf("%s-%s-%s", self.zone.region.client.cpcfg.Id, self.zone.GetGlobalId(), self.storageType) +} + +func (self *SStorage) GetStatus() string { + return api.STORAGE_ONLINE +} + +func (self *SStorage) Refresh() error { + return nil +} + +func (self *SStorage) IsEmulated() bool { + return true +} + +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, err := self.zone.region.GetDisks(self.zone.GetId(), "", nil) + if err != nil { + return nil, err + } + + filtedDisks := make([]SDisk, 0) + for _, disk := range disks { + // ssd 盘 + if self.storageType == api.STORAGE_UCLOUD_CLOUD_SSD && strings.Contains(disk.DiskType, "SSD") { + filtedDisks = append(filtedDisks, disk) + } + + // 普通盘 + if self.storageType == api.STORAGE_UCLOUD_CLOUD_NORMAL && !strings.Contains(disk.DiskType, "SSD") { + filtedDisks = append(filtedDisks, disk) + } + } + + idisks := make([]cloudprovider.ICloudDisk, len(filtedDisks)) + for i := 0; i < len(filtedDisks); i += 1 { + filtedDisks[i].storage = self + idisks[i] = &filtedDisks[i] + } + return idisks, nil +} + +func (self *SStorage) GetStorageType() string { + return self.storageType +} + +func (self *SStorage) GetMediumType() string { + if self.storageType == api.STORAGE_UCLOUD_CLOUD_SSD { + return api.DISK_TYPE_SSD + } else { + return api.DISK_TYPE_ROTATE + } +} + +func (self *SStorage) GetCapacityMB() int64 { + return 0 // unlimited +} + +func (self *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (self *SStorage) GetStorageConf() jsonutils.JSONObject { + return jsonutils.NewDict() +} + +func (self *SStorage) GetEnabled() bool { + return true +} + +func (self *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + diskType := "DataDisk" + switch self.storageType { + case api.STORAGE_UCLOUD_CLOUD_SSD: + diskType = "SSDDataDisk" + } + diskId, err := self.zone.region.CreateDisk(self.zone.GetId(), diskType, conf.Name, conf.SizeGb) + if err != nil { + return nil, err + } + + disk, err := self.zone.region.GetDisk(diskId) + if err != nil { + return nil, err + } + + disk.storage = self + return disk, nil +} + +func (self *SStorage) GetIDiskById(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 + } +} + +func (self *SStorage) GetMountPoint() string { + return "" +} + +func (self *SStorage) IsSysDiskStore() bool { + return true +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/storagecache.go new file mode 100644 index 0000000000..4fc2c8a1c3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/storagecache.go @@ -0,0 +1,393 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "context" + "fmt" + "math" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +type SStoragecache struct { + multicloud.SResourceBase + UcloudTags + region *SRegion +} + +func GetBucketName(regionId string, imageId string) string { + return fmt.Sprintf("imgcache-%s-%s", strings.ToLower(regionId), strings.ToLower(imageId)) +} + +func (self *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, self.region.GetId()) +} + +func (self *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Name, self.region.GetId()) +} + +func (self *SStoragecache) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.region.client.cpcfg.Id, 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) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (self *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + images, err := self.region.GetImages("", "Custom") + if err != nil { + return nil, errors.Wrapf(err, "GetImages") + } + ret := []cloudprovider.ICloudImage{} + for i := range images { + images[i].storageCache = self + ret = append(ret, &images[i]) + } + return ret, nil +} + +func (self *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + image, err := self.region.GetImage(extId) + image.storageCache = self + return &image, err +} + +func (self *SStoragecache) GetPath() string { + return "" +} + +func (self *SStoragecache) CreateIImage(snapshotId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} + +// https://docs.ucloud.cn/api/uhost-api/import_custom_image +func (self *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return self.uploadImage(ctx, userCred, image, callback) +} + +func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + if len(image.OsVersion) == 0 { + return "", fmt.Errorf("uploadImage os version is empty") + } + + bucketName := GetBucketName(self.region.GetId(), image.ImageId) + + // create bucket + exist, err := self.region.IBucketExist(bucketName) + if err != nil { + return "", errors.Wrap(err, "self.region.IBucketExist") + } + if !exist { + err = self.region.CreateBucket(bucketName, "private") + if err != nil { + return "", errors.Wrap(err, "CreateBucket") + } + } + defer func() { + e := self.region.DeleteBucket(bucketName) + if e != nil { + log.Errorf("uploadImage delete bucket %s", e.Error()) + } + }() + + // upload to ucloud + s := auth.GetAdminSession(ctx, options.Options.Region) + meta, reader, size, err := modules.Images.Download(s, image.ImageId, string(qemuimg.VMDK), false) + if err != nil { + return "", err + } + log.Debugf("Images meta data %s", meta) + minDiskMB, _ := meta.Int("min_disk") + minDiskGB := int64(math.Ceil(float64(minDiskMB) / 1024)) + + if minDiskGB < 40 { + minDiskGB = 40 + } else if minDiskGB > 1024 { + minDiskGB = 1024 + } + // size, _ := meta.Int("size") + md5, _ := meta.GetString("checksum") + diskFormat, _ := meta.GetString("disk_format") + // upload to ucloud + bucket, err := self.region.GetIBucketById(bucketName) + if err != nil { + return "", errors.Wrap(err, "GetIBucketByName") + } + file := SFile{ + bucket: bucket.(*SBucket), + file: multicloud.NewProgress(size, 98, reader, callback), + + Size: size, + FileName: image.ImageId, + Hash: md5, + } + + err = file.Upload() + if err != nil { + return "", err + } + defer func() { + e := file.Delete() + if e != nil { + log.Errorf("uploadImage delete object %s", e.Error()) + } + }() // remove object + + // check image name, avoid name conflict + imageBaseName := image.ImageId + if imageBaseName[0] >= '0' && imageBaseName[0] <= '9' { + imageBaseName = fmt.Sprintf("img%s", image.ImageId) + } + imageName := imageBaseName + nameIdx := 1 + + for { + _, err = self.region.GetImageByName(imageName) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + break + } else { + return "", err + } + } + + imageName = fmt.Sprintf("%s-%d", imageBaseName, nameIdx) + nameIdx += 1 + log.Debugf("uploadImage Match remote name %s", imageName) + } + + imgId, err := self.region.ImportImage(imageName, file.FetchFileUrl(), image.OsDistribution, image.OsVersion, diskFormat) + + if err != nil { + log.Errorf("ImportImage error %s %s", file.FetchFileUrl(), err) + return "", err + } + + // timeout: 1hour = 3600 seconds + err = cloudprovider.WaitCreated(60*time.Second, 3600*time.Second, func() bool { + image, err := self.region.GetImage(imgId) + if err == nil && image.State == "Available" { + return true + } + + return false + }) + if err != nil { + return "", errors.Wrap(err, "UploadImage") + } + if callback != nil { + callback(100) + } + return imgId, err +} + +// https://docs.ucloud.cn/api/uhost-api/create_custom_image +func (self *SRegion) createIImage(snapshotId, imageName, imageDesc string) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +/*func (self *SRegion) GetBucketDomain(name string) (string, error) { + params := NewUcloudParams() + params.Set("BucketName", name) + + res := make([]SBucket, 0) + err := self.client.DoListAll("DescribeBucket", params, &res) + if err != nil { + return "", err + } + + if len(res) == 1 && len(res[0].Domain.Src) >= 1 { + return res[0].Domain.Src[0], nil + } else { + return "", fmt.Errorf("GetBucketDomain failed. %v", res) + } +}*/ + +// https://docs.ucloud.cn/api/ufile-api/create_bucket +func (self *SRegion) CreateBucket(name, bucketType string) error { + params := NewUcloudParams() + params.Set("BucketName", name) + params.Set("Type", bucketType) + err := self.DoAction("CreateBucket", params, nil) + if err != nil { + return err + } + self.client.invalidateIBuckets() + return nil +} + +// https://docs.ucloud.cn/api/ufile-api/delete_bucket +func (self *SRegion) DeleteBucket(name string) error { + params := NewUcloudParams() + params.Set("BucketName", name) + err := self.DoAction("DeleteBucket", params, nil) + if err != nil { + return err + } + self.client.invalidateIBuckets() + return nil +} + +// https://docs.ucloud.cn/api/ufile-api/put_file +func (self *SRegion) uploadObj(name string) error { + params := NewUcloudParams() + params.Set("BucketName", name) + return self.DoAction("PutFile", params, nil) +} + +func (self *SRegion) GetImageByName(name string) (*SImage, error) { + images, err := self.GetImages("Custom", "") + if err != nil { + return nil, err + } + + for i := range images { + if images[i].GetName() == name { + return &images[i], nil + } + } + + return nil, cloudprovider.ErrNotFound +} + +func normalizeOsType(osType string) string { + switch strings.ToLower(osType) { + case "centos": + return "CentOS" + case "ubuntu": + return "Ubuntu" + case "windows": + return "Windows" + case "redHat": + return "RedHat" + case "debian": + return "Debian" + default: + return "Other" + } +} + +func normalizeOsName(normalizeOsType string, fullVersion string) string { + if utils.IsInStringArray(normalizeOsType, []string{"CentOS", "RedHat", "Debian"}) { + if len(fullVersion) >= 3 { + return fmt.Sprintf("%s %s 64位", normalizeOsType, fullVersion[0:3]) + } else { + return fmt.Sprintf("%s %s.0 64位", normalizeOsType, fullVersion[0:1]) + } + } + + if normalizeOsType == "Ubuntu" { + if len(fullVersion) >= 5 { + return fmt.Sprintf("Ubuntu %s 64位", fullVersion[0:5]) + } else if len(fullVersion) >= 2 { + return fmt.Sprintf("Ubuntu %s.04 64位", fullVersion[0:2]) + } else { + // 默认猜一个? + return "Ubuntu 14.04 64位" + } + } + + if normalizeOsType == "Windows" { + if len(fullVersion) >= 4 { + return fmt.Sprintf("Windows %s 64位", fullVersion[0:4]) + } else { + // 默认猜一个? + return "Windows 2016 64位" + } + } + + return "Other" +} + +func normalizeDiskFormat(diskFormat string) (string, error) { + switch strings.ToLower(diskFormat) { + case "raw": + return "RAW", nil + case "vhd": + return "VHD", nil + case "vmdk": + return "VMDK", nil + case "qcow2": + return "qcow2", nil + default: + return "", fmt.Errorf("unsupported image format %s", diskFormat) + } +} + +// https://docs.ucloud.cn/api/uhost-api/import_custom_image +func (self *SRegion) ImportImage(name string, ufileUrl string, osType string, osVersion string, diskFormat string) (string, error) { + format, err := normalizeDiskFormat(diskFormat) + if err != nil { + return "", err + } + + nOsType := normalizeOsType(osType) + + params := NewUcloudParams() + params.Set("ImageName", name) + params.Set("UFileUrl", ufileUrl) + // 操作系统平台,比如CentOS、Ubuntu、Windows、RedHat等,请参考控制台的镜像版本;若导入控制台上没有的操作系统,参数为Other + params.Set("OsType", nOsType) + // 操作系统详细版本,请参考控制台的镜像版本;OsType为Other时,输入参数为Other + params.Set("OsName", normalizeOsName(nOsType, osVersion)) + params.Set("Format", format) + params.Set("Auth", "True") + params.Set("ImageDescription", osVersion) + + type SImageId struct { + ImageId string + } + + ret := SImageId{} + log.Debugf("ImportImage with params %s", params.String()) + err = self.DoAction("ImportCustomImage", params, &ret) + if err != nil { + return "", err + } + + return ret.ImageId, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/tag_base.go new file mode 100644 index 0000000000..4dcdde051d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/tag_base.go @@ -0,0 +1,36 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type UcloudTags struct { +} + +func (self *UcloudTags) GetTags() (map[string]string, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") +} + +func (self *UcloudTags) GetSysTags() map[string]string { + return nil +} + +func (self *UcloudTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/pkg/multicloud/ucloud/ucloud.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/ucloud.go similarity index 99% rename from pkg/multicloud/ucloud/ucloud.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/ucloud.go index e76c387b6f..06c3b0d817 100644 --- a/pkg/multicloud/ucloud/ucloud.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/ucloud.go @@ -25,8 +25,8 @@ import ( "yunion.io/x/log" "yunion.io/x/pkg/errors" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) /* diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/ufile.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/ufile.go new file mode 100644 index 0000000000..9dead430d4 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/ufile.go @@ -0,0 +1,394 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "context" + "crypto/hmac" + "crypto/sha1" + "encoding/base64" + "fmt" + "io" + "net/http" + "net/url" + "strconv" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/httputils" +) + +type SBucket struct { + multicloud.SBaseBucket + UcloudTags + + region *SRegion + + // projectId string + + Domain Domain `json:"Domain"` + BucketID string `json:"BucketId"` + Region string `json:"Region"` + CreateTime int64 `json:"CreateTime"` + Biz string `json:"Biz"` + BucketName string `json:"BucketName"` + ModifyTime int64 `json:"ModifyTime"` + Type string `json:"Type"` + Tag string `json:"Tag"` + HasUserDomain int64 `json:"HasUserDomain"` + CDNDomainID []string `json:"CdnDomainId"` +} + +type Domain struct { + Src []string `json:"Src"` + CDN []string `json:"Cdn"` + CustomCDN []interface{} `json:"CustomCdn"` + CustomSrc []interface{} `json:"CustomSrc"` +} + +type SFile struct { + bucket *SBucket + + BucketName string `json:"BucketName"` + FileName string `json:"FileName"` + Size int64 `json:"Size"` + Hash string `json:"Hash"` + MimeType string `json:"MimeType"` + CreateTime int64 `json:"CreateTime"` + ModifyTime int64 `json:"ModifyTime"` + StorageClass string `json:"StorageClass"` + + file io.Reader +} + +func (client *SUcloudClient) signHeader(httpMethod string, path string, md5 string) string { + contentType := "" + if httpMethod == http.MethodPut { + contentType = "application/octet-stream" + } + + data := httpMethod + "\n" + data += md5 + "\n" + data += contentType + "\n" + data += "\n" + data += path + + log.Debugf("sign %s", data) + h := hmac.New(sha1.New, []byte(client.accessKeySecret)) + h.Write([]byte(data)) + return base64.StdEncoding.EncodeToString(h.Sum(nil)) +} + +func (self *SFile) signHeader(httpMethod string) string { + return self.bucket.region.client.signHeader(httpMethod, "/"+self.bucket.BucketName+"/"+self.FileName, self.Hash) +} + +func (self *SFile) auth(httpMethod string) string { + return "UCloud" + " " + self.bucket.region.client.accessKeyId + ":" + self.signHeader(httpMethod) +} + +func (self *SFile) GetHost() string { + return self.bucket.Domain.Src[0] +} + +func (self *SFile) GetUrl() string { + return fmt.Sprintf("http://%s/%s", self.GetHost(), self.FileName) +} + +// https://github.com/ufilesdk-dev/ufile-gosdk/blob/master/auth.go +func (self *SFile) FetchFileUrl() string { + expired := strconv.FormatInt(time.Now().Add(6*time.Hour).Unix(), 10) + // sign + data := "GET\n\n\n" + expired + "\n" + data += "/" + self.bucket.BucketName + "/" + self.FileName + h := hmac.New(sha1.New, []byte(self.bucket.region.client.accessKeySecret)) + h.Write([]byte(data)) + sign := base64.StdEncoding.EncodeToString(h.Sum(nil)) + + urlEncoder := url.Values{} + urlEncoder.Add("UCloudPublicKey", self.bucket.region.client.accessKeyId) + urlEncoder.Add("Signature", sign) + urlEncoder.Add("Expires", expired) + querys := urlEncoder.Encode() + return fmt.Sprintf("%s?%s", self.GetUrl(), querys) +} + +func (self *SFile) Upload() error { + req, _ := http.NewRequest(http.MethodPut, self.GetUrl(), self.file) + req.Header.Add("Authorization", self.auth(http.MethodPut)) + req.Header.Add("Content-MD5", self.Hash) + req.Header.Add("Content-Type", "application/octet-stream") + req.Header.Add("Content-Length", strconv.FormatInt(self.Size, 10)) + _, err := doRequest(req) + return err +} + +func (self *SFile) Delete() error { + req, _ := http.NewRequest(http.MethodDelete, self.GetUrl(), nil) + req.Header.Add("Authorization", self.auth(http.MethodDelete)) + _, err := doRequest(req) + return err +} + +func (self *SFile) GetIBucket() cloudprovider.ICloudBucket { + return self.bucket +} + +func (self *SFile) GetKey() string { + return self.FileName +} + +func (self *SFile) GetSizeBytes() int64 { + return self.Size +} + +func (self *SFile) GetLastModified() time.Time { + return time.Unix(self.ModifyTime, 0) +} + +func (self *SFile) GetStorageClass() string { + return self.StorageClass +} + +func (self *SFile) GetETag() string { + return self.Hash +} + +func (self *SFile) GetContentType() string { + return self.MimeType +} + +func (self *SFile) GetAcl() cloudprovider.TBucketACLType { + return self.bucket.GetAcl() +} + +func (self *SFile) SetAcl(cloudprovider.TBucketACLType) error { + return nil +} + +func (self *SFile) GetMeta() http.Header { + return nil +} + +func (self *SFile) SetMeta(ctx context.Context, meta http.Header) error { + return cloudprovider.ErrNotSupported +} + +func doRequest(req *http.Request) (jsonutils.JSONObject, error) { + // ufile request use no timeout client so as to download/upload large files + res, err := httputils.GetAdaptiveTimeoutClient().Do(req) + if err != nil { + return nil, errors.Wrap(err, "httpclient Do") + } + _, body, err := httputils.ParseJSONResponse("", res, err, false) + if err != nil { + return nil, errors.Wrap(err, "ParseJSONResponse") + } + return body, nil +} + +type sPrefixFileListOutput struct { + BucketName string + BucketId string + NextMarker string + DataSet []SFile +} + +func (b *SBucket) doPrefixFileList(prefix string, marker string, limit int) (*sPrefixFileListOutput, error) { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(""), "list") + if len(prefix) > 0 { + params.Add(jsonutils.NewString(prefix), "prefix") + } + if len(marker) > 0 { + params.Add(jsonutils.NewString(marker), "marker") + } + if limit > 0 { + params.Add(jsonutils.NewInt(int64(limit)), "limit") + } + host := fmt.Sprintf("https://%s.ufile.ucloud.cn", b.BucketName) + path := fmt.Sprintf("/?%s", params.QueryString()) + + log.Debugf("Request %s%s", host, path) + + req, _ := http.NewRequest(http.MethodGet, host+path, nil) + + sign := b.region.client.signHeader(http.MethodGet, path, "") + auth := "UCloud" + " " + b.region.client.accessKeyId + ":" + sign + + req.Header.Add("Authorization", auth) + + output := sPrefixFileListOutput{} + + body, err := doRequest(req) + if err != nil { + return nil, errors.Wrap(err, "doRequest") + } + err = body.Unmarshal(&output) + if err != nil { + return nil, errors.Wrap(err, "body.Unmarshal") + } + + return &output, nil +} + +func (b *SBucket) GetProjectId() string { + return b.region.client.projectId +} + +func (b *SBucket) GetGlobalId() string { + return b.BucketID +} + +func (b *SBucket) GetName() string { + return b.BucketName +} + +func (b *SBucket) GetLocation() string { + return b.region.GetId() +} + +func (b *SBucket) GetIRegion() cloudprovider.ICloudRegion { + return b.region +} + +func (b *SBucket) GetCreatedAt() time.Time { + return time.Unix(b.CreateTime, 0) +} + +func (b *SBucket) GetStorageClass() string { + return "" +} + +func (b *SBucket) GetAcl() cloudprovider.TBucketACLType { + switch b.Type { + case "public": + return cloudprovider.ACLPublicRead + default: + return cloudprovider.ACLPrivate + } +} + +func (b *SBucket) SetAcl(aclStr cloudprovider.TBucketACLType) error { + aclType := "private" + if aclStr == cloudprovider.ACLPublicRead || aclStr == cloudprovider.ACLPublicReadWrite { + aclType = "public" + } + return b.region.updateBucket(b.BucketName, aclType) +} + +func (b *SBucket) getSrcUrl() string { + if len(b.Domain.Src) > 0 { + return b.Domain.Src[0] + } + return "" +} + +func (b *SBucket) GetAccessUrls() []cloudprovider.SBucketAccessUrl { + ret := make([]cloudprovider.SBucketAccessUrl, 0) + for i, u := range b.Domain.Src { + primary := false + if i == 0 { + primary = true + } + ret = append(ret, cloudprovider.SBucketAccessUrl{ + Url: u, + Description: fmt.Sprintf("src%d", i), + Primary: primary, + }) + } + for i, u := range b.Domain.CDN { + ret = append(ret, cloudprovider.SBucketAccessUrl{ + Url: u, + Description: fmt.Sprintf("cdn%d", i), + }) + } + return ret +} + +func (b *SBucket) GetStats() cloudprovider.SBucketStats { + stats, _ := cloudprovider.GetIBucketStats(b) + return stats +} + +func (b *SBucket) ListObjects(prefix string, marker string, delimiter string, maxCount int) (cloudprovider.SListObjectResult, error) { + result := cloudprovider.SListObjectResult{} + + output, err := b.doPrefixFileList(prefix, marker, maxCount) + if err != nil { + return result, errors.Wrap(err, "b.doPrefixFileList") + } + + if len(output.NextMarker) > 0 { + result.NextMarker = output.NextMarker + result.IsTruncated = true + } + + result.Objects = make([]cloudprovider.ICloudObject, len(output.DataSet)) + for i := range output.DataSet { + result.Objects[i] = &output.DataSet[i] + } + + return result, nil +} + +func (b *SBucket) PutObject(ctx context.Context, key string, input io.Reader, sizeBytes int64, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + return cloudprovider.ErrNotSupported +} + +func (b *SBucket) NewMultipartUpload(ctx context.Context, key string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (b *SBucket) UploadPart(ctx context.Context, key string, uploadId string, partIndex int, input io.Reader, partSize int64, offset, totalSize int64) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (b *SBucket) CompleteMultipartUpload(ctx context.Context, key string, uploadId string, partEtags []string) error { + return cloudprovider.ErrNotSupported +} + +func (b *SBucket) AbortMultipartUpload(ctx context.Context, key string, uploadId string) error { + return cloudprovider.ErrNotSupported +} + +func (b *SBucket) DeleteObject(ctx context.Context, key string) error { + file := SFile{ + bucket: b, + FileName: key, + } + return file.Delete() +} + +func (b *SBucket) GetTempUrl(method string, key string, expire time.Duration) (string, error) { + return "", cloudprovider.ErrNotSupported +} + +func (b *SBucket) CopyObject(ctx context.Context, destKey string, srcBucket, srcKey string, cannedAcl cloudprovider.TBucketACLType, storageClassStr string, meta http.Header) error { + return cloudprovider.ErrNotSupported +} + +func (b *SBucket) GetObject(ctx context.Context, key string, rangeOpt *cloudprovider.SGetObjectRange) (io.ReadCloser, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (b *SBucket) CopyPart(ctx context.Context, key string, uploadId string, partIndex int, srcBucketName string, srcKey string, srcOffset int64, srcLength int64) (string, error) { + return "", cloudprovider.ErrNotSupported +} diff --git a/pkg/multicloud/ucloud/utils.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/utils.go similarity index 100% rename from pkg/multicloud/ucloud/utils.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/utils.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/vip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/vip.go new file mode 100644 index 0000000000..d7350831e1 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/vip.go @@ -0,0 +1,119 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVipAddr struct { + VIP string + SubnetId string +} + +func (ip *SVipAddr) GetIP() string { + return ip.VIP +} + +func (ip *SVipAddr) GetINetworkId() string { + return ip.SubnetId +} + +func (ip *SVipAddr) IsPrimary() bool { + return true +} + +func (ip *SVipAddr) GetGlobalId() string { + return ip.VIP +} + +type SVip struct { + multicloud.SNetworkInterfaceBase + UcloudTags + region *SRegion + CreateTime int64 + Name string + RealIp string + Remark string + SubnetId string + Tag string + VIP string + VIPId string + VPCId string + Zone string +} + +func (vip *SVip) GetName() string { + if len(vip.Name) > 0 { + return vip.Name + } + return vip.VIPId +} + +func (vip *SVip) GetId() string { + return vip.VIPId +} + +func (vip *SVip) GetGlobalId() string { + return vip.VIPId +} + +func (vip *SVip) GetMacAddress() string { + ip, _ := netutils.NewIPV4Addr(vip.VIP) + return ip.ToMac("00:16:") +} + +func (vip *SVip) GetAssociateType() string { + return "" +} + +func (vip *SVip) GetAssociateId() string { + return "" +} + +func (vip *SVip) GetStatus() string { + return api.NETWORK_INTERFACE_STATUS_AVAILABLE +} + +func (vip *SVip) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { + ip := &SVipAddr{VIP: vip.VIP, SubnetId: vip.SubnetId} + return []cloudprovider.ICloudInterfaceAddress{ip}, nil +} + +func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { + vips, err := region.GetVips() + if err != nil { + return nil, errors.Wrap(err, "region.GetVips") + } + ret := []cloudprovider.ICloudNetworkInterface{} + for i := 0; i < len(vips); i++ { + vips[i].region = region + ret = append(ret, &vips[i]) + } + return ret, nil +} + +func (self *SRegion) GetVips() ([]SVip, error) { + vips := []SVip{} + params := NewUcloudParams() + + err := self.DoListAll("DescribeVIP", params, &vips) + return vips, err +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/vpc.go new file mode 100644 index 0000000000..fdba13a52b --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/vpc.go @@ -0,0 +1,242 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "fmt" + "strings" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVPC struct { + multicloud.SVpc + UcloudTags + + region *SRegion + + iwires []cloudprovider.ICloudWire + secgroups []cloudprovider.ICloudSecurityGroup + + CreateTime int64 `json:"CreateTime"` + Name string `json:"Name"` + Network []string `json:"Network"` + NetworkInfo []NetworkInfo `json:"NetworkInfo"` + SubnetCount int `json:"SubnetCount"` + Tag string `json:"Tag"` + UpdateTime int64 `json:"UpdateTime"` + VPCID string `json:"VPCId"` +} + +type NetworkInfo struct { + Network string `json:"Network"` + SubnetCount int `json:"SubnetCount"` +} + +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.Name) > 0 { + return self.Name + } + return self.VPCID +} + +func (self *SVPC) GetGlobalId() string { + return self.GetId() +} + +func (self *SVPC) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} + +func (self *SVPC) Refresh() error { + new, err := self.region.getVpc(self.GetId()) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SVPC) IsEmulated() bool { + return false +} + +func (self *SVPC) GetRegion() cloudprovider.ICloudRegion { + return self.region +} + +func (self *SVPC) GetIsDefault() bool { + return false +} + +func (self *SVPC) GetCidrBlock() string { + return strings.Join(self.Network, ",") +} + +func (self *SVPC) GetIWires() ([]cloudprovider.ICloudWire, error) { + if self.iwires == nil { + err := self.fetchNetworks() + if err != nil { + return nil, err + } + } + return self.iwires, nil +} + +// 由于Ucloud 安全组和vpc没有直接关联,这里是返回同一个项目下的防火墙列表,会导致重复同步的问题。 +// https://docs.ucloud.cn/api/unet-api/grant_firewall +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) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + rts := []cloudprovider.ICloudRouteTable{} + return rts, nil +} + +func (self *SVPC) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVPC) Delete() error { + return self.region.DeleteVpc(self.GetId()) +} + +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) fetchNetworks() error { + networks, err := self.region.GetNetworks(self.GetId()) + if err != nil { + return err + } + + for i := 0; i < len(networks); i += 1 { + wire := self.getWireByRegionId(self.region.GetId()) + networks[i].wire = wire + wire.addNetwork(&networks[i]) + } + + return nil +} + +func (self *SVPC) getWireByRegionId(regionId string) *SWire { + if len(regionId) == 0 { + return nil + } + + for i := 0; i < len(self.iwires); i++ { + wire := self.iwires[i].(*SWire) + + if wire.region.GetId() == regionId { + return wire + } + } + + return nil +} + +func (self *SRegion) getVpc(vpcId string) (*SVPC, error) { + vpcs, err := self.GetVpcs(vpcId) + if err != nil { + return nil, err + } + + if len(vpcs) == 1 { + return &vpcs[0], nil + } else if len(vpcs) == 0 { + return nil, cloudprovider.ErrNotFound + } else { + return nil, fmt.Errorf("getVpc %s %d found", vpcId, len(vpcs)) + } +} + +// https://docs.ucloud.cn/api/vpc2.0-api/delete_vpc +func (self *SRegion) DeleteVpc(vpcId string) error { + params := NewUcloudParams() + params.Set("VPCId", vpcId) + return self.DoAction("DeleteVPC", params, nil) +} + +// https://support.huaweicloud.com/api-vpc/zh-cn_topic_0020090625.html +func (self *SRegion) GetVpcs(vpcId string) ([]SVPC, error) { + vpcs := make([]SVPC, 0) + params := NewUcloudParams() + if len(vpcId) > 0 { + params.Set("VPCIds.0", vpcId) + } + + err := self.DoListAll("DescribeVPC", params, &vpcs) + return vpcs, err +} + +func (self *SRegion) GetNetworks(vpcId string) ([]SNetwork, error) { + params := NewUcloudParams() + if len(vpcId) > 0 { + params.Set("VPCId", vpcId) + } + + networks := make([]SNetwork, 0) + err := self.DoAction("DescribeSubnet", params, &networks) + return networks, err +} + +// UCLOUD 同一个项目共用安全组(防火墙) +func (self *SVPC) fetchSecurityGroups() error { + secgroups, err := self.region.GetSecurityGroups("", "", "") + if err != nil { + return err + } + + self.secgroups = make([]cloudprovider.ICloudSecurityGroup, len(secgroups)) + for i := 0; i < len(secgroups); i++ { + secgroups[i].vpc = self + secgroups[i].region = self.region + self.secgroups[i] = &secgroups[i] + } + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/wire.go new file mode 100644 index 0000000000..95a4dbd6a0 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/wire.go @@ -0,0 +1,113 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// 子网在整个region可用 +type SWire struct { + multicloud.SResourceBase + UcloudTags + region *SRegion + vpc *SVPC + + inetworks []cloudprovider.ICloudNetwork +} + +func (self *SWire) GetId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetId(), self.region.GetId()) +} + +func (self *SWire) GetName() string { + return self.GetId() +} + +func (self *SWire) GetGlobalId() string { + return fmt.Sprintf("%s-%s", self.vpc.GetGlobalId(), self.region.GetGlobalId()) +} + +func (self *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (self *SWire) Refresh() error { + return nil +} + +func (self *SWire) IsEmulated() bool { + return true +} + +func (self *SWire) GetIVpc() cloudprovider.ICloudVpc { + return self.vpc +} + +func (self *SWire) GetIZone() cloudprovider.ICloudZone { + return nil +} + +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 +} + +// https://docs.ucloud.cn/api/vpc2.0-api/create_subnet +func (self *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + return self.region.CreateNetwork(self.vpc.GetId(), opts.Name, opts.Cidr, opts.Desc) +} + +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.GetId() { + find = true + break + } + } + if !find { + self.inetworks = append(self.inetworks, network) + } +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/zone.go new file mode 100644 index 0000000000..171afeeae7 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/ucloud/zone.go @@ -0,0 +1,203 @@ +// Copyright 2019 Yunion +// +// 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 ucloud + +import ( + "fmt" + + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +// https://docs.ucloud.cn/api/udisk-api/create_udisk +// UDisk 类型: DataDisk(普通数据盘),SSDDataDisk(SSD数据盘),默认值(DataDisk) +var StorageTypes = []string{ + api.STORAGE_UCLOUD_CLOUD_NORMAL, + api.STORAGE_UCLOUD_CLOUD_SSD, + api.STORAGE_UCLOUD_LOCAL_NORMAL, // 本地盘 + api.STORAGE_UCLOUD_LOCAL_SSD, // 本地SSD盘 +} + +type SZone struct { + multicloud.SResourceBase + UcloudTags + region *SRegion + host *SHost + + iwires []cloudprovider.ICloudWire + istorages []cloudprovider.ICloudStorage + + RegionId string + ZoneId 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, projectId: self.region.client.projectId} + } + 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) GetId() string { + return self.ZoneId +} + +func (self *SZone) GetName() string { + if name, exists := UCLOUD_ZONE_NAMES[self.GetId()]; exists { + return name + } + + return self.GetId() +} + +func (self *SZone) GetI18n() cloudprovider.SModelI18nTable { + var en string + if name, exists := UCLOUD_ZONE_NAMES_EN[self.GetId()]; exists { + en = name + } else { + en = self.GetId() + } + + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(self.GetName()).CN(self.GetName()).EN(en) + return table +} + +func (self *SZone) GetGlobalId() string { + return fmt.Sprintf("%s/%s", self.region.GetGlobalId(), self.GetId()) +} + +func (self *SZone) GetStatus() string { + return api.ZONE_ENABLE +} + +func (self *SZone) Refresh() error { + return nil +} + +func (self *SZone) IsEmulated() bool { + return false +} + +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 { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "fetchStorages") + } + } + return self.istorages, nil +} + +func (self *SZone) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + if self.istorages == nil { + err := self.fetchStorages() + if err != nil { + return nil, errors.Wrapf(err, "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 +} + +// https://docs.ucloud.cn/api/uhost-api/describe_uhost_instance +func (self *SZone) GetInstances() ([]SInstance, error) { + return self.region.GetInstances(self.GetId(), "") +} + +func (self *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { + return self.iwires, nil +} + +// https://docs.ucloud.cn/api/uhost-api/describe_uhost_instance +func (self *SRegion) GetInstances(zoneId string, instanceId string) ([]SInstance, error) { + instances := make([]SInstance, 0) + + params := NewUcloudParams() + if len(zoneId) > 0 { + params.Set("Zone", zoneId) + } + + if len(instanceId) > 0 { + params.Set("UHostIds.0", instanceId) + } + + err := self.DoListAll("DescribeUHostInstance", params, &instances) + return instances, err +} + +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) +} diff --git a/pkg/multicloud/virtualresource_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/virtualresource_base.go similarity index 100% rename from pkg/multicloud/virtualresource_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/virtualresource_base.go diff --git a/pkg/multicloud/vpc_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/vpc_base.go similarity index 97% rename from pkg/multicloud/vpc_base.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/vpc_base.go index d187628ef2..f5abd09825 100644 --- a/pkg/multicloud/vpc_base.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/vpc_base.go @@ -17,8 +17,8 @@ package multicloud import ( "yunion.io/x/pkg/errors" - apis "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + apis "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" ) type SVpc struct { diff --git a/pkg/multicloud/zstack/cluster.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/cluster.go similarity index 100% rename from pkg/multicloud/zstack/cluster.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/cluster.go diff --git a/pkg/multicloud/zstack/configuration.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/configuration.go similarity index 100% rename from pkg/multicloud/zstack/configuration.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/configuration.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/disk.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/disk.go new file mode 100644 index 0000000000..4c46f58df8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/disk.go @@ -0,0 +1,419 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SDisk struct { + multicloud.SDisk + ZStackTags + + localStorage *SLocalStorage + storage *SStorage + region *SRegion + + ZStackBasic + PrimaryStorageUUID string `json:"primaryStorageUuid"` + VMInstanceUUID string `json:"vmInstanceUuid"` + DiskOfferingUUID string `json:"diskOfferingUuid"` + RootImageUUID string `json:"rootImageUuid"` + InstallPath string `json:"installPath"` + Type string `json:"type"` + Format string `json:"format"` + Size int `json:"size"` + ActualSize int `json:"actualSize"` + DeviceID float32 `json:"deviceId"` + State string `json:"state"` + Status string `json:"status"` + + ZStackTime +} + +func (region *SRegion) GetDisk(diskId string) (*SDisk, error) { + disk := &SDisk{region: region} + err := region.client.getResource("volumes", diskId, disk) + if err != nil { + return nil, err + } + if disk.Status == "NotInstantiated" || disk.Status == "Deleted" { + return nil, cloudprovider.ErrNotFound + } + return disk, nil +} + +func (region *SRegion) GetDiskWithStorage(diskId string) (*SDisk, error) { + disk, err := region.GetDisk(diskId) + if err != nil { + log.Errorf("Get Disk %s error: %v", diskId, err) + return nil, err + } + storage, err := region.GetStorage(disk.PrimaryStorageUUID) + if err != nil { + log.Errorf("Get primary storage %s error: %v", disk.PrimaryStorageUUID, err) + return nil, err + } + switch storage.Type { + case StorageTypeLocal: + if len(disk.VMInstanceUUID) > 0 { + instance, err := region.GetInstance(disk.VMInstanceUUID) + if err != nil { + return nil, err + } + hostId := instance.LastHostUUID + if len(hostId) == 0 { + hostId = instance.HostUUID + } + disk.localStorage = &SLocalStorage{region: region, primaryStorageID: storage.UUID, HostUUID: hostId} + return disk, nil + } + tags, err := region.GetResourceSysTags("", "VolumeVO", disk.UUID, "") + if err != nil { + log.Errorf("get disk tag error: %v", err) + return nil, err + } + for i := 0; i < len(tags); i++ { + if strings.HasPrefix(tags[i].Tag, "localStorage::hostUuid::") { + hostInfo := strings.Split(tags[i].Tag, "localStorage::hostUuid::") + if len(hostInfo) == 2 { + localStorage, err := region.GetLocalStorage(storage.UUID, hostInfo[1]) + if err != nil { + return nil, err + } + disk.localStorage = localStorage + return disk, nil + } + return nil, fmt.Errorf("invalid host info %s from disk %s", tags[i].Tag, disk.Name) + } + } + return nil, cloudprovider.ErrNotFound + case StorageTypeCeph: + disk.storage = storage + return disk, nil + default: + return nil, fmt.Errorf("Unsupport StorageType %s", storage.Type) + } +} + +func (region *SRegion) GetDisks(storageId string, diskIds []string, diskType string) ([]SDisk, error) { + disks := []SDisk{} + params := url.Values{} + params.Add("q", "status!=Deleted") + params.Add("q", "status!=NotInstantiated") + if len(storageId) > 0 { + params.Add("q", "primaryStorageUuid="+storageId) + } + if len(diskIds) > 0 { + params.Add("q", "uuid?="+strings.Join(diskIds, ",")) + } + if len(diskType) > 0 { + params.Add("q", "type="+diskType) + } + return disks, region.client.listAll("volumes", params, &disks) +} + +func (disk *SDisk) GetSysTags() map[string]string { + data := map[string]string{} + data["hypervisor"] = api.HYPERVISOR_ZSTACK + return data +} + +func (disk *SDisk) GetId() string { + return disk.UUID +} + +func (disk *SDisk) Delete(ctx context.Context) error { + if disk.Status == "Deleted" { + return disk.region.ExpungeDisk(disk.UUID) + } + return disk.region.DeleteDisk(disk.UUID) +} + +func (disk *SDisk) Resize(ctx context.Context, sizeMb int64) error { + return disk.region.ResizeDisk(disk.UUID, sizeMb) +} + +func (disk *SDisk) GetName() string { + return disk.Name +} + +func (disk *SDisk) GetGlobalId() string { + return disk.UUID +} + +func (disk *SDisk) IsEmulated() bool { + return false +} + +func (disk *SDisk) GetIStorage() (cloudprovider.ICloudStorage, error) { + if disk.localStorage != nil { + return disk.localStorage, nil + } + if disk.storage != nil { + return disk.storage, nil + } + return nil, cloudprovider.ErrNotFound +} + +func (disk *SDisk) GetIStorageId() string { + storage, err := disk.region.GetStorage(disk.PrimaryStorageUUID) + if err != nil { + return disk.PrimaryStorageUUID + } else if storage.Type == StorageTypeLocal && len(disk.VMInstanceUUID) > 0 { + instnace, err := disk.region.GetInstance(disk.VMInstanceUUID) + if err != nil { + log.Warningf("failed to get instance %s for disk %s(%s) error: %v", disk.VMInstanceUUID, disk.Name, disk.UUID, err) + return "" + } + return fmt.Sprintf("%s/%s", disk.PrimaryStorageUUID, instnace.LastHostUUID) + } + return disk.PrimaryStorageUUID +} + +func (disk *SDisk) GetStatus() string { + switch disk.Status { + case "Ready": + return api.DISK_READY + case "NotInstantiated": + //数据云盘特有的状态。在这个连接状态中,数据云盘只存在于数据库的表记录中。NotInstantiated状态的数据云盘可以挂载到任何类型虚拟机管理程序管理的云主机上;当挂载到云主机上后,数据云盘的hypervisorType域会存储云主机对应的虚拟机管理程序类型,在主存储上被实例化为虚拟机管理程序类型的实际二进制文件,同时连接状态会改为就绪(Ready);在这之后,这些数据云盘就只能被重新挂载到相同类型虚拟机管理程序管理的云主机上了。 + return api.DISK_INIT + case "Creating": + return api.DISK_ALLOCATING + case "Deleted": + return api.DISK_DEALLOC + default: + log.Errorf("Unknown disk %s(%s) status %s", disk.Name, disk.UUID, disk.Status) + return api.DISK_UNKNOWN + } +} + +func (disk *SDisk) Refresh() error { + new, err := disk.region.GetDisk(disk.UUID) + if err != nil { + return err + } + return jsonutils.Update(disk, new) +} + +func (disk *SDisk) GetDiskFormat() string { + return disk.Format +} + +func (disk *SDisk) GetDiskSizeMB() int { + return disk.Size / 1024 / 1024 +} + +func (disk *SDisk) GetIsAutoDelete() bool { + return disk.GetDiskType() == api.DISK_TYPE_SYS || disk.localStorage != nil +} + +func (disk *SDisk) GetTemplateId() string { + return disk.RootImageUUID +} + +func (disk *SDisk) GetDiskType() string { + switch disk.Type { + case "Root": + return api.DISK_TYPE_SYS + default: + return api.DISK_TYPE_DATA + } +} + +func (disk *SDisk) GetFsFormat() string { + return "" +} + +func (disk *SDisk) GetIsNonPersistent() bool { + return false +} + +func (disk *SDisk) GetDriver() string { + return "scsi" +} + +func (disk *SDisk) GetCacheMode() string { + return "none" +} + +func (disk *SDisk) GetMountpoint() string { + return "" +} + +func (region *SRegion) CreateDisk(name string, storageId string, hostId string, poolName string, sizeGb int, desc string) (*SDisk, error) { + offerings, err := region.GetDiskOfferings(sizeGb) + if err != nil { + return nil, err + } + diskOfferingUuid := "" + if len(offerings) > 0 { + diskOfferingUuid = offerings[0].UUID + } else { + offering, err := region.CreateDiskOffering(sizeGb) + if err != nil { + return nil, err + } + diskOfferingUuid = offering.UUID + defer region.DeleteDiskOffering(diskOfferingUuid) + } + params := map[string]interface{}{ + "params": map[string]string{ + "name": name, + "description": desc, + "diskOfferingUuid": diskOfferingUuid, + "primaryStorageUuid": storageId, + }, + } + if len(hostId) > 0 { + params["systemTags"] = []string{"localStorage::hostUuid::" + hostId} + } + if len(poolName) > 0 { + params["systemTags"] = []string{"ceph::pool::" + poolName} + } + resp, err := region.client.post("volumes/data", jsonutils.Marshal(params)) + if err != nil { + return nil, err + } + disk := &SDisk{region: region} + return disk, resp.Unmarshal(disk, "inventory") +} + +func (region *SRegion) ExpungeDisk(diskId string) error { + params := map[string]interface{}{ + "expungeDataVolume": jsonutils.NewDict(), + } + _, err := region.client.put("volumes", diskId, jsonutils.Marshal(params)) + return err +} + +func (region *SRegion) DeleteDisk(diskId string) error { + err := region.client.delete("volumes", diskId, "Enforcing") + if err != nil { + return err + } + return region.ExpungeDisk(diskId) +} + +func (region *SRegion) ResizeDisk(diskId string, sizeMb int64) error { + disk, err := region.GetDisk(diskId) + if err != nil { + return err + } + + if disk.GetDiskSizeMB() == int(sizeMb) { + return nil + } + + params := jsonutils.Marshal(map[string]interface{}{ + fmt.Sprintf("resize%sVolume", disk.Type): map[string]int64{ + "size": sizeMb * 1024 * 1024, + }, + }) + resource := "volumes/resize" + if disk.Type == "Data" { + resource = "volumes/data/resize" + } + _, err = region.client.put(resource, diskId, params) + return err +} + +func (disk *SDisk) CreateISnapshot(ctx context.Context, name, desc string) (cloudprovider.ICloudSnapshot, error) { + return disk.region.CreateSnapshot(name, disk.UUID, desc) +} + +func (disk *SDisk) GetISnapshot(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + snapshots, err := disk.region.GetSnapshots(snapshotId, disk.UUID) + if err != nil { + return nil, err + } + if len(snapshots) == 1 { + if snapshots[0].UUID == snapshotId { + return &snapshots[0], nil + } + return nil, cloudprovider.ErrNotFound + } + if len(snapshots) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return nil, cloudprovider.ErrNotFound +} + +func (disk *SDisk) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := disk.region.GetSnapshots("", disk.UUID) + if err != nil { + return nil, err + } + isnapshots := []cloudprovider.ICloudSnapshot{} + for i := 0; i < len(snapshots); i++ { + isnapshots = append(isnapshots, &snapshots[i]) + } + return isnapshots, nil +} + +func (disk *SDisk) Reset(ctx context.Context, snapshotId string) (string, error) { + _, err := disk.region.ResetDisks(snapshotId) + return disk.UUID, err +} + +func (region *SRegion) ResetDisks(snapshotId string) (jsonutils.JSONObject, error) { + params := map[string]interface{}{ + "revertVolumeFromSnapshot": jsonutils.NewDict(), + } + return region.client.put("volume-snapshots", snapshotId, jsonutils.Marshal(params)) +} + +func (disk *SDisk) GetBillingType() string { + return "" +} + +func (disk *SDisk) GetExpiredAt() time.Time { + return time.Time{} +} + +func (disk *SDisk) GetCreatedAt() time.Time { + return disk.CreateDate +} + +func (disk *SDisk) GetAccessPath() string { + return disk.InstallPath +} + +func (disk *SDisk) Rebuild(ctx context.Context) error { + return disk.region.RebuildDisk(disk.UUID) +} + +func (region *SRegion) RebuildDisk(diskId string) error { + params := map[string]interface{}{ + "recoverDataVolume": jsonutils.NewDict(), + } + _, err := region.client.put("volumes", diskId, jsonutils.Marshal(params)) + return err +} + +func (disk *SDisk) GetProjectId() string { + return "" +} diff --git a/pkg/multicloud/zstack/disk_offering.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/disk_offering.go similarity index 100% rename from pkg/multicloud/zstack/disk_offering.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/disk_offering.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/doc.go new file mode 100644 index 0000000000..fc6eaea6bf --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 zstack // import "yunion.io/x/cloudmux/pkg/multicloud/zstack" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/eip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/eip.go new file mode 100644 index 0000000000..884535443f --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/eip.go @@ -0,0 +1,203 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "fmt" + "net/url" + "time" + + "yunion.io/x/jsonutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SEipAddress struct { + region *SRegion + multicloud.SEipBase + ZStackTags + + ZStackBasic + VMNicUUID string `json:"vmNicUuid"` + VipUUID string `json:"vipUuid"` + State string `json:"state"` + VipIP string `json:"vipIp"` + GuestIP string `json:"guestIp"` + ZStackTime +} + +func (region *SRegion) GetEip(eipId string) (*SEipAddress, error) { + eip := &SEipAddress{region: region} + return eip, region.client.getResource("eips", eipId, eip) +} + +func (region *SRegion) GetEips(eipId, instanceId string) ([]SEipAddress, error) { + eips := []SEipAddress{} + params := url.Values{} + if len(eipId) > 0 { + params.Add("q", "uuid="+eipId) + } + if len(instanceId) > 0 { + params.Add("q", "vmNic.vmInstanceUuid="+instanceId) + } + err := region.client.listAll("eips", params, &eips) + if err != nil { + return nil, err + } + for i := 0; i < len(eips); i++ { + eips[i].region = region + } + return eips, nil +} + +func (eip *SEipAddress) GetId() string { + return eip.UUID +} + +func (eip *SEipAddress) GetName() string { + return eip.Name +} + +func (eip *SEipAddress) GetGlobalId() string { + return eip.UUID +} + +func (eip *SEipAddress) GetStatus() string { + return api.EIP_STATUS_READY +} + +func (eip *SEipAddress) Refresh() error { + new, err := eip.region.GetEip(eip.UUID) + if err != nil { + return err + } + return jsonutils.Update(eip, new) +} + +func (eip *SEipAddress) IsEmulated() bool { + return false +} + +func (eip *SEipAddress) GetIpAddr() string { + return eip.VipIP +} + +func (eip *SEipAddress) GetMode() string { + return api.EIP_MODE_STANDALONE_EIP +} + +func (eip *SEipAddress) GetAssociationType() string { + if len(eip.GetAssociationExternalId()) > 0 { + return api.EIP_ASSOCIATE_TYPE_SERVER + } + return "" +} + +func (eip *SEipAddress) GetAssociationExternalId() string { + if len(eip.VMNicUUID) > 0 { + instances, err := eip.region.GetInstances("", "", eip.VMNicUUID) + if err == nil && len(instances) == 1 { + return instances[0].UUID + } + } + return "" +} + +func (eip *SEipAddress) GetBillingType() string { + return "" +} + +func (eip *SEipAddress) GetCreatedAt() time.Time { + return eip.CreateDate +} + +func (eip *SEipAddress) GetExpiredAt() time.Time { + return time.Time{} +} + +func (eip *SEipAddress) Delete() error { + return eip.region.DeleteVirtualIP(eip.VipUUID) +} + +func (eip *SEipAddress) GetBandwidth() int { + return 0 +} + +func (eip *SEipAddress) GetINetworkId() string { + vip, err := eip.region.GetVirtualIP(eip.VipUUID) + if err == nil { + return eip.region.GetNetworkId(vip) + } + return "" +} + +func (eip *SEipAddress) GetInternetChargeType() string { + return api.EIP_CHARGE_TYPE_BY_TRAFFIC +} + +func (eip *SEipAddress) Associate(conf *cloudprovider.AssociateConfig) error { + return eip.region.AssociateEip(conf.InstanceId, eip.UUID) +} + +func (eip *SEipAddress) Dissociate() error { + return eip.region.DisassociateEip(eip.UUID) +} + +func (eip *SEipAddress) ChangeBandwidth(bw int) error { + return cloudprovider.ErrNotSupported +} + +func (eip *SEipAddress) GetProjectId() string { + return "" +} + +func (region *SRegion) CreateEip(name string, vipId string, desc string) (*SEipAddress, error) { + params := map[string]map[string]string{ + "params": { + "name": name, + "description": desc, + "vipUuid": vipId, + }, + } + eip := &SEipAddress{region: region} + resp, err := region.client.post("eips", jsonutils.Marshal(params)) + if err != nil { + return nil, err + } + return eip, resp.Unmarshal(eip, "inventory") +} + +func (region *SRegion) AssociateEip(instanceId, eipId string) error { + instance, err := region.GetInstance(instanceId) + if err != nil { + return err + } + if len(instance.VMNics) == 0 { + return fmt.Errorf("instance %s does not have any nic", instance.Name) + } + resource := fmt.Sprintf("eips/%s/vm-instances/nics/%s", eipId, instance.VMNics[0].UUID) + params := map[string]interface{}{ + "params": jsonutils.NewDict(), + } + _, err = region.client.post(resource, jsonutils.Marshal(params)) + return err +} + +func (region *SRegion) DisassociateEip(eipId string) error { + resource := fmt.Sprintf("eips/%s/vm-instances/nics", eipId) + return region.client.delete(resource, "", "") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/host.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/host.go new file mode 100644 index 0000000000..343b6c8205 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/host.go @@ -0,0 +1,479 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "fmt" + "net/url" + "strings" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SHost struct { + multicloud.SHostBase + zone *SZone + + ZStackBasic + Username string `json:"username"` + SSHPort int `json:"sshPort"` + ZoneUUID string `json:"zoneUuid"` + ClusterUUID string `json:"clusterUuid"` + ManagementIP string `json:"managementIp"` + HypervisorType string `json:"hypervisorType"` + State string `json:"state"` + Status string `json:"status"` + TotalCPUCapacity int `json:"totalCpuCapacity"` + AvailableCPUCapacity int `json:"availableCpuCapacity"` + CPUSockets int `json:"cpuSockets"` + TotalMemoryCapacity int `json:"totalMemoryCapacity"` + AvailableMemoryCapacity int `json:"availableMemoryCapacity"` + CPUNum int `json:"cpuNum"` + ZStackTime +} + +func (region *SRegion) GetHosts(zoneId string, hostId string) ([]SHost, error) { + hosts := []SHost{} + params := url.Values{} + if len(zoneId) > 0 { + params.Add("q", "zone.uuid="+zoneId) + } + if len(hostId) > 0 { + params.Add("q", "uuid="+hostId) + } + if SkipEsxi { + params.Add("q", "hypervisorType!=ESX") + } + return hosts, region.client.listAll("hosts", params, &hosts) +} + +func (region *SRegion) GetHost(hostId string) (*SHost, error) { + host := &SHost{} + err := region.client.getResource("hosts", hostId, host) + if err != nil { + return nil, err + } + zone, err := region.GetZone(host.ZoneUUID) + if err != nil { + return nil, err + } + host.zone = zone + return host, nil +} + +func (host *SHost) GetIWires() ([]cloudprovider.ICloudWire, error) { + wires, err := host.zone.region.GetWires(host.ZoneUUID, "", host.ClusterUUID) + if err != nil { + return nil, err + } + iwires := []cloudprovider.ICloudWire{} + for i := 0; i < len(wires); i++ { + iwires = append(iwires, &wires[i]) + } + return iwires, nil +} + +func (host *SHost) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + storages, err := host.zone.region.GetStorages(host.zone.UUID, host.ClusterUUID, "") + if err != nil { + return nil, err + } + istorages := []cloudprovider.ICloudStorage{} + for i := 0; i < len(storages); i++ { + storages[i].region = host.zone.region + switch storages[i].Type { + case StorageTypeLocal: + localStorages, err := host.zone.region.getILocalStorages(storages[i].UUID, host.UUID) + if err != nil { + return nil, err + } + istorages = append(istorages, localStorages...) + case StorageTypeCeph: + istorages = append(istorages, &storages[i]) + case StorageTypeVCenter: + } + } + return istorages, nil +} + +func (host *SHost) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + return host.zone.GetIStorageById(id) +} + +func (host *SHost) GetIVMs() ([]cloudprovider.ICloudVM, error) { + instances, err := host.zone.region.GetInstances(host.UUID, "", "") + if err != nil { + return nil, err + } + iInstnace := []cloudprovider.ICloudVM{} + for i := 0; i < len(instances); i++ { + instances[i].host = host + iInstnace = append(iInstnace, &instances[i]) + } + return iInstnace, nil +} + +func (host *SHost) GetIVMById(instanceId string) (cloudprovider.ICloudVM, error) { + instance, err := host.zone.region.GetInstance(instanceId) + if err != nil { + return nil, err + } + instance.host = host + return instance, nil +} + +func (host *SHost) GetId() string { + return host.UUID +} + +func (host *SHost) GetName() string { + return host.Name +} + +func (host *SHost) GetGlobalId() string { + return host.GetId() +} + +func (host *SHost) IsEmulated() bool { + return false +} + +func (host *SHost) GetStatus() string { + if host.Status == "Connected" { + return api.HOST_STATUS_RUNNING + } + return api.HOST_STATUS_UNKNOWN +} + +func (host *SHost) Refresh() error { + return nil +} + +func (host *SHost) GetHostStatus() string { + if host.Status == "Connected" { + return api.HOST_ONLINE + } + return api.HOST_OFFLINE +} + +func (host *SHost) GetEnabled() bool { + return host.State == "Enabled" +} + +func (host *SHost) GetAccessIp() string { + return host.ManagementIP +} + +func (host *SHost) GetAccessMac() string { + return "" +} + +func (host *SHost) GetSysInfo() jsonutils.JSONObject { + info := jsonutils.NewDict() + info.Add(jsonutils.NewString(CLOUD_PROVIDER_ZSTACK), "manufacture") + return info +} + +func (host *SHost) GetSN() string { + return "" +} + +func (host *SHost) GetReservedMemoryMb() int { + host.zone.fetchHostCmtbound() + return host.zone.reservedMemeoryMb +} + +func (host *SHost) GetCpuCmtbound() float32 { + host.zone.fetchHostCmtbound() + return host.zone.cpuCmtbound +} + +func (host *SHost) GetMemCmtbound() float32 { + host.zone.fetchHostCmtbound() + return host.zone.memCmtbound +} + +func (host *SHost) GetCpuCount() int { + cpuCmtBound := host.GetCpuCmtbound() + if cpuCmtBound > 0 { + return int(float32(host.TotalCPUCapacity) / cpuCmtBound) + } + return host.TotalCPUCapacity +} + +func (host *SHost) GetNodeCount() int8 { + return int8(host.CPUSockets) +} + +func (host *SHost) GetCpuDesc() string { + return "" +} + +func (host *SHost) GetCpuMhz() int { + return 0 +} + +func (host *SHost) GetMemSizeMB() int { + return host.TotalMemoryCapacity / 1024 / 1024 +} + +func (host *SHost) GetStorageSizeMB() int { + storages, err := host.zone.region.GetStorages(host.zone.UUID, host.ClusterUUID, "") + if err != nil { + return 0 + } + totalStorage := 0 + for _, storage := range storages { + if storage.Type == StorageTypeLocal { + localStorages, err := host.zone.region.GetLocalStorages(storage.UUID, host.UUID) + if err != nil { + return 0 + } + for i := 0; i < len(localStorages); i++ { + totalStorage += int(localStorages[i].TotalCapacity) + } + } + } + return totalStorage / 1024 / 1024 +} + +func (host *SHost) GetStorageType() string { + return api.DISK_TYPE_HYBRID +} + +func (host *SHost) GetHostType() string { + return api.HOST_TYPE_ZSTACK +} + +func (region *SRegion) cleanDisks(diskIds []string) { + for i := 0; i < len(diskIds); i++ { + err := region.DeleteDisk(diskIds[i]) + if err != nil { + log.Errorf("clean disk %s error: %v", diskIds[i], err) + } + } +} + +func (region *SRegion) createDataDisks(disks []cloudprovider.SDiskInfo, hostId string) ([]string, error) { + diskIds := []string{} + + storages, err := region.GetStorages("", "", "") + if err != nil { + return nil, errors.Wrapf(err, "createDataDisks.GetStorages") + } + + localstorages := []SLocalStorage{} + + for _, storage := range storages { + if storage.Type == StorageTypeLocal { + localstorage, _ := region.GetLocalStorage(storage.UUID, hostId) + if localstorage != nil { + localstorages = append(localstorages, *localstorage) + } + } + } + + for i := 0; i < len(disks); i++ { + storageInfo := strings.Split(disks[i].StorageExternalId, "/") + if len(storageInfo) == 0 { + return diskIds, fmt.Errorf("invalidate storage externalId: %s", disks[i].StorageExternalId) + } + storage, err := region.GetStorage(storageInfo[0]) + if err != nil { + return diskIds, errors.Wrapf(err, "createDataDisks") + } + + switch storage.Type { + case StorageTypeCeph: + poolName := "" + for _, pool := range storage.Pools { + if pool.Type == CephPoolTypeData { + poolName = pool.PoolName + } + } + if len(poolName) == 0 { + return diskIds, fmt.Errorf("failed to found ceph data pool for storage %s to createDataDisk", storage.Name) + } + disk, err := region.CreateDisk(disks[i].Name, storage.UUID, "", poolName, disks[i].SizeGB, "") + if err != nil { + return diskIds, err + } + diskIds = append(diskIds, disk.UUID) + case StorageTypeLocal: + if len(localstorages) == 0 { + return nil, fmt.Errorf("No validate localstorage") + } + var disk *SDisk + var err error + for _, localstorage := range localstorages { + disk, err = region.CreateDisk(disks[i].Name, localstorage.primaryStorageID, hostId, "", disks[i].SizeGB, "") + if err != nil { + log.Warningf("createDataDisks error: %v", err) + } else { + diskIds = append(diskIds, disk.UUID) + break + } + } + if err != nil { + return diskIds, err + } + default: + return diskIds, fmt.Errorf("not support storageType %s", disks[i].StorageType) + } + } + return diskIds, nil +} + +func (host *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudprovider.ICloudVM, error) { + instance, err := host.zone.region._createVM(desc, host.ZoneUUID) + if err != nil { + return nil, errors.Wrapf(err, "host.zone.region._createVM") + } + + diskIds, err := host.zone.region.createDataDisks(desc.DataDisks, instance.HostUUID) + if err != nil { + defer host.zone.region.cleanDisks(diskIds) + defer host.zone.region.DeleteVM(instance.UUID) + return nil, errors.Wrapf(err, "host.zone.region.createDataDisks") + } + + err = host.zone.region.ResizeDisk(instance.RootVolumeUUID, int64(desc.SysDisk.SizeGB)*1024) + if err != nil { + log.Warningf("failed to resize system disk %s error: %v", instance.RootVolumeUUID, err) + } + + for i := 0; i < len(diskIds); i++ { + err = host.zone.region.AttachDisk(instance.UUID, diskIds[i]) + if err != nil { + log.Errorf("failed to attach disk %s into instance %s error: %v", diskIds[i], instance.Name, err) + } + } + err = host.zone.region.AssignSecurityGroup(instance.UUID, desc.ExternalSecgroupId) + if err != nil { + return nil, err + } + return host.GetIVMById(instance.UUID) +} + +func (region *SRegion) _createVM(desc *cloudprovider.SManagedVMCreateConfig, zoneId string) (*SInstance, error) { + l3Id := strings.Split(desc.ExternalNetworkId, "/")[0] + if len(l3Id) == 0 { + return nil, fmt.Errorf("invalid networkid: %s", desc.ExternalNetworkId) + } + _, err := region.GetL3Network(l3Id) + if err != nil { + log.Errorf("failed to found l3network %s error: %v", l3Id, err) + return nil, err + } + offerings := map[string]string{} + if len(desc.InstanceType) > 0 { + offering, err := region.GetInstanceOfferingByType(desc.InstanceType) + if err != nil { + if errors.Cause(err) == cloudprovider.ErrNotFound { + offering, err = region.CreateInstanceOffering(desc.InstanceType, desc.Cpu, desc.MemoryMB, "UserVm") + if err != nil { + return nil, err + } + } else { + return nil, err + } + } + offerings[offering.Name] = offering.UUID + } else { + _offerings, err := region.GetInstanceOfferings("", "", desc.Cpu, desc.MemoryMB) + if err != nil { + return nil, err + } + for _, offering := range _offerings { + offerings[offering.Name] = offering.UUID + } + if len(offerings) == 0 { + return nil, fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB) + } + } + return region.CreateInstance(desc, l3Id, zoneId, offerings) +} + +func (region *SRegion) CreateInstance(desc *cloudprovider.SManagedVMCreateConfig, l3Id, zoneId string, offerings map[string]string) (*SInstance, error) { + instance := &SInstance{} + systemTags := []string{ + "createWithoutCdRom::true", + "usbRedirect::false", + "vmConsoleMode::vnc", + "cleanTraffic::false", + } + if len(desc.IpAddr) > 0 { + systemTags = append(systemTags, fmt.Sprintf("staticIp::%s::%s", l3Id, desc.IpAddr)) + } + if len(desc.UserData) > 0 { + systemTags = append(systemTags, "userdata::"+desc.UserData) + } + if len(desc.PublicKey) > 0 { + systemTags = append(systemTags, "sshkey::"+desc.PublicKey) + } + var err error + for offerName, offerId := range offerings { + params := map[string]interface{}{ + "params": map[string]interface{}{ + "name": desc.NameEn, + "description": desc.Description, + "instanceOfferingUuid": offerId, + "imageUuid": desc.ExternalImageId, + "l3NetworkUuids": []string{ + l3Id, + }, + "zoneUuid": zoneId, + "dataVolumeSystemTags": []string{}, + "rootVolumeSystemTags": []string{}, + "vmMachineType": "", + "tagUuids": []string{}, + "defaultL3NetworkUuid": l3Id, + "dataDiskOfferingUuids": []string{}, + "systemTags": systemTags, + "vmNicConfig": []string{}, + }, + } + + log.Debugf("Try instanceOffering : %s", offerName) + err = region.client.create("vm-instances", jsonutils.Marshal(params), instance) + if err == nil { + return instance, nil + } + log.Errorf("create %s instance failed error: %v", offerName, err) + } + if err != nil { + return nil, err + } + return nil, fmt.Errorf("instance type %dC%dMB not avaiable", desc.Cpu, desc.MemoryMB) +} + +func (host *SHost) GetIHostNics() ([]cloudprovider.ICloudHostNetInterface, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (host *SHost) GetIsMaintenance() bool { + return false +} + +func (host *SHost) GetVersion() string { + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/image.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/image.go new file mode 100644 index 0000000000..1f385d3421 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/image.go @@ -0,0 +1,303 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" + "sort" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/httputils" + "yunion.io/x/onecloud/pkg/util/imagetools" + "yunion.io/x/onecloud/pkg/util/multipart" +) + +type SBackupStorageRef struct { + BackupStorageUUID string `json:"backupStorageUuid"` + CreateDate time.Time `json:"createDate"` + ImageUUID string `json:"ImageUuid"` + InstallPath string `json:"installPath"` + LastOpDate time.Time `json:"lastOpDate"` + Status string `json:"status"` +} + +type SImage struct { + multicloud.SImageBase + ZStackTags + storageCache *SStoragecache + + // normalized image info + imgInfo *imagetools.ImageInfo + + BackupStorageRefs []SBackupStorageRef `json:"backupStorageRefs"` + ActualSize int `json:"actualSize"` + CreateDate time.Time `json:"createDate"` + Description string `json:"description"` + Format string `json:"format"` + LastOpDate time.Time `json:"lastOpDate"` + MD5Sum string `json:"md5sum"` + MediaType string `json:"mediaType"` + Name string `json:"name"` + Platform string `json:"platform"` + Size int `json:"size"` + State string `json:"state"` + Status string `json:"Ready"` + System bool `json:"system"` + Type string `json:"type"` + URL string `json:"url"` + UUID string `json:"uuid"` +} + +func (image *SImage) GetMinRamSizeMb() int { + return 0 +} + +func (image *SImage) GetId() string { + return image.UUID +} + +func (image *SImage) GetName() string { + return image.Name +} + +func (image *SImage) IsEmulated() bool { + return false +} + +func (image *SImage) Delete(ctx context.Context) error { + return image.storageCache.region.DeleteImage(image.UUID) +} + +func (image *SImage) GetGlobalId() string { + return image.UUID +} + +func (region *SRegion) DeleteImage(imageId string) error { + err := region.client.delete("images", imageId, "") + if err != nil { + return err + } + params := map[string]interface{}{ + "expungeImage": jsonutils.NewDict(), + } + _, err = region.client.put("images", imageId, jsonutils.Marshal(params)) + return err +} + +func (image *SImage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return image.storageCache +} + +func (image *SImage) GetStatus() string { + if image.State != "Enabled" { + return api.CACHED_IMAGE_STATUS_CACHING + } + switch image.Status { + case "Ready": + return api.CACHED_IMAGE_STATUS_ACTIVE + case "Downloading": + return api.CACHED_IMAGE_STATUS_CACHING + case "Deleted": + return api.CACHED_IMAGE_STATUS_DELETING + default: + log.Errorf("Unknown image status: %s", image.Status) + return api.CACHED_IMAGE_STATUS_CACHE_FAILED + } +} + +func (image *SImage) GetImageStatus() string { + switch image.Status { + case "Ready": + return cloudprovider.IMAGE_STATUS_ACTIVE + case "Deleted": + return cloudprovider.IMAGE_STATUS_DELETED + default: + return cloudprovider.IMAGE_STATUS_KILLED + } +} + +func (image *SImage) Refresh() error { + new, err := image.storageCache.region.GetImage(image.UUID) + if err != nil { + return err + } + return jsonutils.Update(image, new) +} + +func (image *SImage) GetImageType() cloudprovider.TImageType { + return cloudprovider.ImageTypeSystem +} + +func (image *SImage) GetSizeByte() int64 { + return int64(image.Size) +} + +func (self *SImage) getNormalizedImageInfo() *imagetools.ImageInfo { + if self.imgInfo == nil { + imgInfo := imagetools.NormalizeImageInfo(self.URL, "", self.Platform, self.Platform, "") + self.imgInfo = &imgInfo + } + + return self.imgInfo +} + +func (image *SImage) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(image.getNormalizedImageInfo().OsType) +} + +func (image *SImage) GetOsDist() string { + return image.getNormalizedImageInfo().OsDistro +} + +func (image *SImage) GetOsVersion() string { + return image.getNormalizedImageInfo().OsVersion +} + +func (image *SImage) GetOsArch() string { + return image.getNormalizedImageInfo().OsArch +} + +func (image *SImage) GetBios() cloudprovider.TBiosType { + return cloudprovider.TBiosType(image.getNormalizedImageInfo().OsBios) +} + +func (image *SImage) GetOsLang() string { + return image.getNormalizedImageInfo().OsLang +} + +func (image *SImage) GetFullOsName() string { + return image.URL +} + +func (image *SImage) GetMinOsDiskSizeGb() int { + return image.Size / 1024 / 1024 / 1024 +} + +func (image *SImage) GetImageFormat() string { + return image.Format +} + +func (image *SImage) GetCreatedAt() time.Time { + return image.CreateDate +} + +func (region *SRegion) GetImage(imageId string) (*SImage, error) { + image := &SImage{} + err := region.client.getResource("images", imageId, image) + if err != nil { + return nil, errors.Wrapf(err, "region.GetImage") + } + return image, nil +} + +func (region *SRegion) GetImages(zoneId string, imageId string) ([]SImage, error) { + images := []SImage{} + params := url.Values{} + params.Add("q", "system=false") + if len(zoneId) > 0 { + params.Add("q", "backupStorage.zone.uuid="+zoneId) + } + if len(imageId) > 0 { + params.Add("q", "uuid="+imageId) + } + if SkipEsxi { + params.Add("q", "type!=vmware") + } + return images, region.client.listAll("images", params, &images) +} + +func (region *SRegion) GetBackupStorageUUID(zondId string) ([]string, error) { + imageServers, err := region.GetImageServers(zondId, "") + if err != nil { + return nil, err + } + if len(imageServers) == 0 { + return nil, fmt.Errorf("failed to found any image servers") + } + servers := ImageServers(imageServers) + sort.Sort(servers) + return []string{servers[0].UUID}, nil +} + +func (region *SRegion) CreateImage(zoneId string, imageName, format, osType, desc string, reader io.Reader, size int64, callback func(progress float32)) (*SImage, error) { + backupStorageUUIDs, err := region.GetBackupStorageUUID(zoneId) + if err != nil { + return nil, err + } + platform := "" + switch osType { + case "linux": + platform = "Linux" + case "windows": + platform = "Windows" + default: + platform = "Other" + } + parmas := map[string]interface{}{ + "params": map[string]interface{}{ + "name": imageName, + "url": fmt.Sprintf("upload://%s", imageName), + "description": desc, + "mediaType": "RootVolumeTemplate", + "system": false, + "format": format, + "platform": platform, + "backupStorageUuids": backupStorageUUIDs, + "systemTags": []string{"qemuga", "bootMode::Legacy"}, + }, + } + + if reader == nil { + return nil, fmt.Errorf("invalid reader") + } + + if size == 0 { + return nil, fmt.Errorf("invalid image size") + } + + body := multipart.NewReader(reader, "", imageName) + + image := &SImage{} + err = region.client.create("images", jsonutils.Marshal(parmas), image) + if err != nil { + return nil, err + } + + if len(image.BackupStorageRefs) < 0 { + return nil, fmt.Errorf("no InstallPath reture") + } + header := http.Header{} + header.Add("X-IMAGE-UUID", image.UUID) + header.Add("X-IMAGE-SIZE", fmt.Sprintf("%d", size)) + header.Add("Content-Type", body.FormDataContentType()) + r := multicloud.NewProgress(size, 99, body, callback) + resp, err := httputils.Request(httputils.GetTimeoutClient(0), context.Background(), "POST", image.BackupStorageRefs[0].InstallPath, header, r, false) + if err != nil { + return nil, err + } + defer resp.Body.Close() + return image, nil +} diff --git a/pkg/multicloud/zstack/image_server.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/image_server.go similarity index 100% rename from pkg/multicloud/zstack/image_server.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/image_server.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/instance.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/instance.go new file mode 100644 index 0000000000..38e6d1b2cb --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/instance.go @@ -0,0 +1,689 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/utils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/billing" + "yunion.io/x/onecloud/pkg/util/imagetools" + "yunion.io/x/onecloud/pkg/util/version" +) + +type SInstanceCdrome struct { +} + +type SInstance struct { + multicloud.SInstanceBase + ZStackTags + host *SHost + + osInfo *imagetools.ImageInfo + + ZStackBasic + ZoneUUID string `json:"zoneUuid"` + ClusterUUID string `json:"clusterUuid"` + HostUUID string `json:"hostUuid"` + LastHostUUID string `json:"lastHostUuid"` + RootVolumeUUID string `json:"rootVolumeUuid"` + Platform string `json:"platform"` + InstanceOfferingUUID string `json:"instanceOfferingUuid"` + + DefaultL3NetworkUUID string `json:"defaultL3NetworkUuid"` + Type string `json:"type"` + HypervisorType string `json:"hypervisorType"` + MemorySize int `json:"memorySize"` + CPUNum int `json:"cpuNum"` + CPUSpeed int `json:"cpuSpeed"` + State string `json:"state"` + InternalID string `json:"internalId"` + VMNics []SInstanceNic `json:"vmNics"` + AllVolumes []SDisk `json:"allVolumes"` + VMCdRoms []SInstanceCdrome `json:"vmCdRoms"` + ZStackTime +} + +func (region *SRegion) GetInstance(instanceId string) (*SInstance, error) { + instance := &SInstance{} + err := region.client.getResource("vm-instances", instanceId, instance) + if err != nil { + return nil, err + } + if instance.State == "Destroyed" { + return nil, cloudprovider.ErrNotFound + } + return instance, nil +} + +func (region *SRegion) GetInstances(hostId string, instanceId string, nicId string) ([]SInstance, error) { + instance := []SInstance{} + params := url.Values{} + params.Add("q", "type=UserVm") + params.Add("q", "state!=Destroyed") + if len(hostId) > 0 { + params.Add("q", "lastHostUuid="+hostId) + } + if len(instanceId) > 0 { + params.Add("q", "uuid="+instanceId) + } + if len(nicId) > 0 { + params.Add("q", "vmNics.uuid="+nicId) + } + if SkipEsxi { + params.Add("q", "hypervisorType!=ESX") + } + return instance, region.client.listAll("vm-instances", params, &instance) +} + +func (instance *SInstance) GetSecurityGroupIds() ([]string, error) { + ids := []string{} + secgroups, err := instance.host.zone.region.GetSecurityGroups("", instance.UUID, "") + if err != nil { + return nil, err + } + for _, secgroup := range secgroups { + ids = append(ids, secgroup.UUID) + } + return ids, nil +} + +func (instance *SInstance) GetIHost() cloudprovider.ICloudHost { + return instance.host +} + +func (instance *SInstance) GetIHostId() string { + if len(instance.LastHostUUID) > 0 { + return instance.LastHostUUID + } + return instance.HostUUID +} + +func (instance *SInstance) GetId() string { + return instance.UUID +} + +func (instance *SInstance) GetName() string { + return instance.Name +} + +func (instance *SInstance) GetHostname() string { + return instance.Name +} + +func (instance *SInstance) GetGlobalId() string { + return instance.GetId() +} + +func (instance *SInstance) IsEmulated() bool { + return false +} + +func (instance *SInstance) GetInstanceType() string { + if len(instance.InstanceOfferingUUID) > 0 { + offer, err := instance.host.zone.region.GetInstanceOffering(instance.InstanceOfferingUUID) + if err == nil { + return offer.Name + } + } + return instance.Type +} + +func (instance *SInstance) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + idisks := []cloudprovider.ICloudDisk{} + rootDisk, err := instance.host.zone.region.GetDiskWithStorage(instance.RootVolumeUUID) + if err != nil { + return nil, err + } + idisks = append(idisks, rootDisk) + for i := 0; i < len(instance.AllVolumes); i++ { + if instance.AllVolumes[i].UUID != instance.RootVolumeUUID { + dataDisk, err := instance.host.zone.region.GetDiskWithStorage(instance.AllVolumes[i].UUID) + if err != nil { + return nil, err + } + idisks = append(idisks, dataDisk) + } + } + return idisks, nil +} + +func (instance *SInstance) GetINics() ([]cloudprovider.ICloudNic, error) { + iNics := []cloudprovider.ICloudNic{} + for i := 0; i < len(instance.VMNics); i++ { + instance.VMNics[i].instance = instance + iNics = append(iNics, &instance.VMNics[i]) + } + return iNics, nil +} + +func (instance *SInstance) GetVcpuCount() int { + return instance.CPUNum +} + +func (instance *SInstance) GetVmemSizeMB() int { + return instance.MemorySize / 1024 / 1024 +} + +func (instance *SInstance) GetBootOrder() string { + return instance.host.zone.region.GetBootOrder(instance.UUID) +} + +func (region *SRegion) GetBootOrder(instanceId string) string { + resp, err := region.client.get("vm-instances", instanceId, "boot-orders") + if err != nil { + return "dcn" + } + orders := []string{} + err = resp.Unmarshal(&orders, "orders") + if err != nil { + return "dcn" + } + order := "" + for _, _order := range orders { + switch _order { + case "CdRom": + order += "c" + case "HardDisk": + order += "d" + default: + log.Errorf("Unknown BootOrder %s for instance %s", _order, instanceId) + } + } + return order +} + +func (instance *SInstance) GetVga() string { + return "std" +} + +func (instance *SInstance) GetVdi() string { + return "vnc" +} + +func (instance *SInstance) getNormalizedOsInfo() *imagetools.ImageInfo { + if instance.osInfo == nil { + osInfo := imagetools.NormalizeImageInfo(instance.Platform, "", "", "", "") + instance.osInfo = &osInfo + } + return instance.osInfo +} + +func (instance *SInstance) GetOsType() cloudprovider.TOsType { + return cloudprovider.TOsType(instance.getNormalizedOsInfo().OsType) +} + +func (instance *SInstance) GetFullOsName() string { + return instance.Platform +} + +func (instance *SInstance) GetBios() cloudprovider.TBiosType { + return cloudprovider.ToBiosType(instance.getNormalizedOsInfo().OsBios) +} + +func (instance *SInstance) GetOsDist() string { + return instance.getNormalizedOsInfo().OsDistro +} + +func (instance *SInstance) GetOsVersion() string { + return instance.getNormalizedOsInfo().OsVersion +} + +func (instance *SInstance) GetOsLang() string { + return instance.getNormalizedOsInfo().OsLang +} + +func (instance *SInstance) GetOsArch() string { + return instance.getNormalizedOsInfo().OsArch +} + +func (instance *SInstance) GetMachine() string { + return "pc" +} + +func (instance *SInstance) GetStatus() string { + switch instance.State { + case "Stopped": + return api.VM_READY + case "Running": + return api.VM_RUNNING + case "Destroyed": + return api.VM_DEALLOCATED + default: + log.Errorf("Unknown instance %s status %s", instance.Name, instance.State) + return api.VM_UNKNOWN + } +} + +func (instance *SInstance) Refresh() error { + new, err := instance.host.zone.region.GetInstance(instance.UUID) + if err != nil { + return err + } + return jsonutils.Update(instance, new) +} + +func (instance *SInstance) GetHypervisor() string { + return api.HYPERVISOR_ZSTACK +} + +func (instance *SInstance) StartVM(ctx context.Context) error { + err := instance.host.zone.region.StartVM(instance.UUID) + if err != nil { + return err + } + return cloudprovider.WaitStatus(instance, api.VM_RUNNING, 5*time.Second, 5*time.Minute) +} + +func (region *SRegion) StartVM(instanceId string) error { + params := map[string]interface{}{ + "startVmInstance": jsonutils.NewDict(), + } + _, err := region.client.put("vm-instances", instanceId, jsonutils.Marshal(params)) + return err +} + +func (instance *SInstance) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error { + err := instance.host.zone.region.StopVM(instance.UUID, opts.IsForce) + if err != nil { + return err + } + return cloudprovider.WaitStatus(instance, api.VM_READY, 5*time.Second, 5*time.Minute) +} + +func (region *SRegion) StopVM(instanceId string, isForce bool) error { + option := "grace" + if isForce { + option = "cold" + } + params := map[string]interface{}{ + "stopVmInstance": map[string]string{ + "type": option, + "stopHA": "true", + }, + } + _, err := region.client.put("vm-instances", instanceId, jsonutils.Marshal(params)) + return err +} + +func (instance *SInstance) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) { + info, err := instance.host.zone.region.GetInstanceConsoleInfo(instance.UUID) + if err != nil { + return nil, err + } + authURL, _ := url.Parse(instance.host.zone.region.client.authURL) + url := fmt.Sprintf("%s://%s:5000/thirdparty/vnc_auto.html?host=%s&port=%d&token=%s&title=%s", info.Scheme, authURL.Hostname(), info.Hostname, info.Port, info.Token, instance.Name) + if ver, _ := instance.host.zone.region.client.GetVersion(); ver != nil { + if version.GE(ver.Version, "4.0.0") { + url = fmt.Sprintf("%s://%s:5000/novnc/index.html?host=%s&port=%d&token=%s&title=%s&language=zh-CN&lowVersion=false", info.Scheme, authURL.Hostname(), info.Hostname, info.Port, info.Token, instance.Name) + } + } + password, _ := instance.host.zone.region.GetInstanceConsolePassword(instance.UUID) + if len(password) > 0 { + url = url + fmt.Sprintf("&password=%s", password) + } + ret := &cloudprovider.ServerVncOutput{ + Url: url, + Protocol: "zstack", + InstanceId: instance.UUID, + Hypervisor: api.HYPERVISOR_ZSTACK, + } + return ret, nil +} + +func (instance *SInstance) UpdateVM(ctx context.Context, name string) error { + params := map[string]interface{}{ + "updateVmInstance": map[string]string{ + "name": name, + }, + } + return instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params)) +} + +func (region *SRegion) UpdateVM(instanceId string, params jsonutils.JSONObject) error { + _, err := region.client.put("vm-instances", instanceId, params) + return err +} + +func (instance *SInstance) DeployVM(ctx context.Context, name string, username string, password string, publicKey string, deleteKeypair bool, description string) error { + if instance.Name != name || instance.Description != description { + params := map[string]interface{}{ + "updateVmInstance": map[string]string{ + "name": name, + "description": description, + }, + } + err := instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params)) + if err != nil { + return err + } + } + if len(password) > 0 { + params := map[string]interface{}{ + "changeVmPassword": map[string]string{ + "account": username, + "password": password, + }, + } + err := instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params)) + if err != nil { + return err + } + } + if len(publicKey) > 0 { + params := map[string]interface{}{ + "setVmSshKey": map[string]string{ + "SshKey": publicKey, + }, + } + err := instance.host.zone.region.UpdateVM(instance.UUID, jsonutils.Marshal(params)) + if err != nil { + return err + } + } + if deleteKeypair { + err := instance.host.zone.region.client.delete("vm-instances", fmt.Sprintf("%s/ssh-keys", instance.UUID), "") + if err != nil { + return err + } + } + + return nil +} + +func (instance *SInstance) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) { + return instance.host.zone.region.RebuildRoot(instance.UUID, desc.ImageId, desc.SysSizeGB) +} + +func (region *SRegion) RebuildRoot(instanceId, imageId string, sysSizeGB int) (string, error) { + params := map[string]interface{}{ + "changeVmImage": map[string]string{ + "imageUuid": imageId, + }, + } + instance := &SInstance{} + resp, err := region.client.put("vm-instances", instanceId, jsonutils.Marshal(params)) + if err != nil { + return "", err + } + err = resp.Unmarshal(instance, "inventory") + if err != nil { + return "", err + } + disk, err := region.GetDisk(instance.RootVolumeUUID) + if err != nil { + return "", err + } + if sysSizeGB > disk.GetDiskSizeMB()*1024 { + return instance.RootVolumeUUID, region.ResizeDisk(disk.UUID, int64(sysSizeGB)*1024) + } + return instance.RootVolumeUUID, nil +} + +func (instance *SInstance) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error { + offerings, err := instance.host.zone.region.GetInstanceOfferings("", "", config.Cpu, config.MemoryMB) + if err != nil { + return err + } + if len(config.InstanceType) > 0 { + for _, offering := range offerings { + if offering.Name == config.InstanceType { + return instance.host.zone.region.ChangeConfig(instance.UUID, offering.UUID) + } + } + offering, err := instance.host.zone.region.CreateInstanceOffering(config.InstanceType, config.Cpu, config.MemoryMB, "UserVm") + if err != nil { + return err + } + return instance.host.zone.region.ChangeConfig(instance.UUID, offering.UUID) + } + for _, offering := range offerings { + log.Debugf("try instance offering %s(%s) ...", offering.Name, offering.UUID) + err := instance.host.zone.region.ChangeConfig(instance.UUID, offering.UUID) + if err != nil { + log.Errorf("failed to change config for instance %s(%s) error: %v", instance.Name, instance.UUID, err) + } else { + return nil + } + } + return fmt.Errorf("Failed to change vm config, specification not supported") +} + +func (region *SRegion) ChangeConfig(instanceId, offeringId string) error { + params := map[string]interface{}{ + "changeInstanceOffering": map[string]string{ + "instanceOfferingUuid": offeringId, + }, + } + return region.UpdateVM(instanceId, jsonutils.Marshal(params)) +} + +func (instance *SInstance) AttachDisk(ctx context.Context, diskId string) error { + return instance.host.zone.region.AttachDisk(instance.UUID, diskId) +} + +func (region *SRegion) AttachDisk(instanceId string, diskId string) error { + _, err := region.client.post(fmt.Sprintf("volumes/%s/vm-instances/%s", diskId, instanceId), jsonutils.NewDict()) + return err +} + +func (instance *SInstance) DetachDisk(ctx context.Context, diskId string) error { + return instance.host.zone.region.DetachDisk(instance.UUID, diskId) +} + +func (region *SRegion) DetachDisk(instanceId, diskId string) error { + url := fmt.Sprintf("volumes/%s/vm-instances?vmUuid=%s", diskId, instanceId) + err := region.client.delete(url, "", "") + if err != nil && strings.Contains(err.Error(), "is not attached to any vm") { + return nil + } + return err +} + +func (instance *SInstance) DeleteVM(ctx context.Context) error { + disks, err := instance.GetIDisks() + if err != nil { + return errors.Wrapf(err, "GetIDisks") + } + err = instance.host.zone.region.DeleteVM(instance.UUID) + if err != nil { + return errors.Wrapf(err, "DeleteVM") + } + for i := range disks { + if disks[i].GetDiskType() != api.DISK_TYPE_SYS && disks[i].GetIsAutoDelete() { + err = disks[i].Delete(ctx) + if err != nil { + log.Warningf("delete disk %s failed %s", disks[i].GetId(), err) + } + } + } + return nil +} + +func (region *SRegion) DeleteVM(instanceId string) error { + err := region.client.delete("vm-instances", instanceId, "Enforcing") + if err != nil { + return err + } + params := map[string]interface{}{ + "expungeVmInstance": jsonutils.NewDict(), + } + _, err = region.client.put("vm-instances", instanceId, jsonutils.Marshal(params)) + if err != nil { + return errors.Wrapf(err, "expungeVmInstance") + } + return nil +} + +func (instance *SInstance) GetIEIP() (cloudprovider.ICloudEIP, error) { + eips, err := instance.host.zone.region.GetEips("", instance.UUID) + if err != nil { + return nil, err + } + if len(eips) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(eips) == 1 { + return &eips[0], nil + } + return nil, cloudprovider.ErrDuplicateId +} + +func (instance *SInstance) AssignSecurityGroup(secgroupId string) error { + return instance.host.zone.region.AssignSecurityGroup(instance.UUID, secgroupId) +} + +func (instance *SInstance) SetSecurityGroups(secgroupIds []string) error { + currentIds, err := instance.GetSecurityGroupIds() + if err != nil { + return err + } + for _, id := range currentIds { + if !utils.IsInStringArray(id, secgroupIds) { + err := instance.host.zone.region.RevokeSecurityGroup(instance.UUID, id) + if err != nil { + return err + } + } + } + for _, id := range secgroupIds { + if !utils.IsInStringArray(id, currentIds) { + err := instance.host.zone.region.AssignSecurityGroup(instance.UUID, id) + if err != nil { + return err + } + } + } + return nil +} + +func (region *SRegion) AssignSecurityGroup(instanceId, secgroupId string) error { + instance, err := region.GetInstance(instanceId) + if err != nil { + return err + } + secgroup, err := region.GetSecurityGroup(secgroupId) + if err != nil { + return err + } + if len(instance.VMNics) > 0 { + if !utils.IsInStringArray(instance.VMNics[0].L3NetworkUUID, secgroup.AttachedL3NetworkUUIDs) { + resource := fmt.Sprintf("security-groups/%s/l3-networks/%s", secgroupId, instance.VMNics[0].L3NetworkUUID) + _, err := region.client.post(resource, jsonutils.NewDict()) + if err != nil { + return err + } + } + params := map[string]interface{}{ + "params": map[string]interface{}{ + "vmNicUuids": []string{instance.VMNics[0].UUID}, + }, + } + resource := fmt.Sprintf("security-groups/%s/vm-instances/nics", secgroupId) + _, err = region.client.post(resource, jsonutils.Marshal(params)) + return err + } + return nil +} + +func (region *SRegion) RevokeSecurityGroup(instanceId, secgroupId string) error { + instance, err := region.GetInstance(instanceId) + if err != nil { + return err + } + for _, nic := range instance.VMNics { + resource := fmt.Sprintf("security-groups/%s/vm-instances/nics?vmNicUuids=%s", secgroupId, nic.UUID) + err := region.client.delete(resource, "", "") + if err != nil { + return err + } + } + return nil +} + +func (instance *SInstance) GetBillingType() string { + return "" +} + +func (instance *SInstance) GetCreatedAt() time.Time { + return instance.CreateDate +} + +func (instance *SInstance) GetExpiredAt() time.Time { + return time.Time{} +} + +func (instance *SInstance) UpdateUserData(userData string) error { + return cloudprovider.ErrNotSupported +} + +func (instance *SInstance) Renew(bc billing.SBillingCycle) error { + return cloudprovider.ErrNotSupported +} + +func (instance *SInstance) GetProjectId() string { + return "" +} + +func (instance *SInstance) GetError() error { + return nil +} + +type SConsoleInfo struct { + Scheme string `json:"scheme"` + Hostname string `json:"hostname"` + Port int `json:"port"` + Token string `json:"token"` +} + +func (region *SRegion) GetInstanceConsoleInfo(instnaceId string) (*SConsoleInfo, error) { + params := map[string]interface{}{ + "params": map[string]string{ + "vmInstanceUuid": instnaceId, + }, + } + resp, err := region.client.post("consoles", jsonutils.Marshal(params)) + if err != nil { + return nil, err + } + info := &SConsoleInfo{} + err = resp.Unmarshal(info, "inventory") + if err != nil { + return nil, err + } + return info, nil +} + +func (region *SRegion) GetInstanceConsolePassword(instnaceId string) (string, error) { + resp, err := region.client.get("vm-instances", instnaceId, "console-passwords") + if err != nil { + return "", err + } + if resp.Contains("consolePassword") { + return resp.GetString("consolePassword") + } + return "", nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/instancenic.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/instancenic.go new file mode 100644 index 0000000000..7554e7d2e3 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/instancenic.go @@ -0,0 +1,74 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SInstanceNic struct { + instance *SInstance + + UUID string `json:"uuid"` + VMInstanceUUID string `json:"vmInstanceUuid"` + L3NetworkUUID string `json:"l3NetworkUuid"` + IP string `json:"ip"` + Mac string `json:"mac"` + HypervisorType string `json:"hypervisorType"` + IPVersion int `json:"ipVersion"` + UsedIps []string `json:"usedIps"` + InternalName string `json:"internalName"` + DeviceID int `json:"deviceId"` + ZStackTime + + cloudprovider.DummyICloudNic +} + +func (nic *SInstanceNic) GetId() string { + return "" +} + +func (nic *SInstanceNic) GetIP() string { + return nic.IP +} + +func (nic *SInstanceNic) GetMAC() string { + return nic.Mac +} + +func (nic *SInstanceNic) GetDriver() string { + return "virtio" +} + +func (nic *SInstanceNic) InClassicNetwork() bool { + return false +} + +func (nic *SInstanceNic) GetINetworkId() string { + networks, err := nic.instance.host.zone.region.GetNetworks(nic.instance.host.zone.UUID, "", nic.L3NetworkUUID, "") + if err != nil { + log.Errorf("failed to found networks for nic %v error: %v", jsonutils.Marshal(nic).String(), err) + return "" + } + for i := 0; i < len(networks); i++ { + if networks[i].Contains(nic.IP) { + return networks[i].L3NetworkUUID + } + } + return "" +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/monitor.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/monitor.go new file mode 100644 index 0000000000..341b309fe5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/monitor.go @@ -0,0 +1,141 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type SDataPoint struct { + DataPoints []DataPoint `json:"data"` +} + +type DataPoint struct { + Value float64 `json:"value"` + Time int64 `json:"time"` + Labels Label `json:"labels"` +} + +type Label struct { + VMUuid string `json:"VMUuid"` + HostUuid string `json:"HostUuid"` +} + +func (self *SZStackClient) GetMonitorData(name string, namespace string, since time.Time, until time.Time) ([]DataPoint, error) { + datas := SDataPoint{} + param := jsonutils.NewDict() + param.Add(jsonutils.NewString(namespace), "namespace") + param.Add(jsonutils.NewString(name), "metricName") + param.Add(jsonutils.NewString("60"), "period") + param.Add(jsonutils.NewInt(since.Unix()), "startTime") + param.Add(jsonutils.NewInt(until.Unix()), "endTime") + rep, err := self.getMonitor("zwatch/metrics", param) + if err != nil { + return nil, err + } + return datas.DataPoints, rep.Unmarshal(&datas) +} + +func (self *SZStackClient) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + switch opts.ResourceType { + case cloudprovider.METRIC_RESOURCE_TYPE_SERVER: + return self.GetEcsMetrics(opts) + case cloudprovider.METRIC_RESOURCE_TYPE_HOST: + return self.GetHostMetrics(opts) + default: + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "%s", opts.ResourceType) + } +} + +func (self *SZStackClient) GetHostMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ns, metricName := "ZStack/Host", "" + switch opts.MetricType { + case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: + metricName = "CPUAverageUsedUtilization" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: + metricName = "DiskReadBytes" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: + metricName = "DiskWriteBytes" + case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: + metricName = "NetworkInBytes" + case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: + metricName = "NetworkOutBytes" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: + metricName = "DiskReadOps" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: + metricName = "DiskWriteOps" + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) + } + data, err := self.GetMonitorData(metricName, ns, opts.StartTime, opts.EndTime) + if err != nil { + return nil, errors.Wrapf(err, "GetMonitorData") + } + ret := []cloudprovider.MetricValues{} + for i := range data { + metric := cloudprovider.MetricValues{} + metric.MetricType = opts.MetricType + metric.Id = data[i].Labels.HostUuid + metric.Values = append(metric.Values, cloudprovider.MetricValue{ + Timestamp: time.Unix(data[i].Time, 0), + Value: data[i].Value, + }) + ret = append(ret, metric) + } + return ret, nil +} + +func (self *SZStackClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + ns, metricName := "ZStack/VM", "" + switch opts.MetricType { + case cloudprovider.VM_METRIC_TYPE_CPU_USAGE: + metricName = "CPUAverageUsedUtilization" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_BPS: + metricName = "DiskReadBytes" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_BPS: + metricName = "DiskWriteBytes" + case cloudprovider.VM_METRIC_TYPE_NET_BPS_RX: + metricName = "NetworkInBytes" + case cloudprovider.VM_METRIC_TYPE_NET_BPS_TX: + metricName = "NetworkOutBytes" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_READ_IOPS: + metricName = "DiskReadOps" + case cloudprovider.VM_METRIC_TYPE_DISK_IO_WRITE_IOPS: + metricName = "DiskWriteOps" + default: + return nil, errors.Wrapf(cloudprovider.ErrNotSupported, "%s", opts.MetricType) + } + data, err := self.GetMonitorData(metricName, ns, opts.StartTime, opts.EndTime) + if err != nil { + return nil, errors.Wrapf(err, "GetMonitorData") + } + ret := []cloudprovider.MetricValues{} + for i := range data { + metric := cloudprovider.MetricValues{} + metric.MetricType = opts.MetricType + metric.Id = data[i].Labels.VMUuid + metric.Values = append(metric.Values, cloudprovider.MetricValue{ + Timestamp: time.Unix(data[i].Time, 0), + Value: data[i].Value, + }) + ret = append(ret, metric) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/network.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/network.go new file mode 100644 index 0000000000..f6cb71292a --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/network.go @@ -0,0 +1,258 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "fmt" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/rbacutils" +) + +type SNetwork struct { + multicloud.SResourceBase + ZStackTags + wire *SWire + + ZStackBasic + L3NetworkUUID string `json:"l3NetworkUuid"` + StartIP string `json:"startIp"` + EndIP string `json:"endIp"` + Netmask string `json:"netmask"` + Gateway string `json:"gateway"` + NetworkCIDR string `json:"networkCidr"` + IPVersion int `json:"ipVersion"` + PrefixLen int `json:"prefixLen"` + ZStackTime +} + +type SHostRoute struct { + ID int + L3NetworkUuid string `json:"l3NetworkUuid"` + Prefix string + Nexthop string + ZStackTime +} + +type SL3Network struct { + ZStackBasic + Type string `json:"type"` + ZoneUUID string `json:"zoneUuid"` + L2NetworkUUID string `json:"l2NetworkUuid"` + State string `json:"state"` + System bool `json:"system"` + Category bool `json:"category"` + IPVersion int `json:"ipVersion"` + DNS []string `json:"dns"` + Networks []SNetwork `json:"ipRanges"` + HostRoute []SHostRoute `json:"hostRoute"` + ZStackTime +} + +func (region *SRegion) GetNetwork(zoneId, wireId, l3Id, networkId string) (*SNetwork, error) { + networks, err := region.GetNetworks(zoneId, wireId, l3Id, networkId) + if err != nil { + return nil, err + } + if len(networks) == 1 { + if networks[0].UUID == networkId { + return &networks[0], nil + } + return nil, cloudprovider.ErrNotFound + } + if len(networks) == 0 || len(networkId) == 0 { + return nil, cloudprovider.ErrNotFound + } + return nil, cloudprovider.ErrDuplicateId +} + +func (region *SRegion) GetL3Network(l3Id string) (*SL3Network, error) { + l3network := &SL3Network{} + return l3network, region.client.getResource("l3-networks", l3Id, l3network) +} + +func (region *SRegion) GetL3Networks(zoneId string, wireId string, l3Id string) ([]SL3Network, error) { + l3Networks := []SL3Network{} + params := url.Values{} + if len(zoneId) > 0 { + params.Add("q", "zone.uuid="+zoneId) + } + if len(wireId) > 0 { + params.Add("q", "l2NetworkUuid="+wireId) + } + if len(l3Id) > 0 { + params.Add("q", "uuid="+l3Id) + } + return l3Networks, region.client.listAll("l3-networks", params, &l3Networks) +} + +func (region *SRegion) GetNetworks(zoneId string, wireId string, l3Id string, networkId string) ([]SNetwork, error) { + l3Networks, err := region.GetL3Networks(zoneId, wireId, l3Id) + if err != nil { + return nil, err + } + networks := []SNetwork{} + for i := 0; i < len(l3Networks); i++ { + for j := 0; j < len(l3Networks[i].Networks); j++ { + if len(networkId) == 0 || l3Networks[i].Networks[j].UUID == networkId { + networks = append(networks, l3Networks[i].Networks[j]) + } + } + } + return networks, nil +} + +func (network *SNetwork) GetId() string { + return network.UUID +} + +func (network *SNetwork) GetName() string { + return network.Name +} + +func (network *SNetwork) GetGlobalId() string { + return fmt.Sprintf("%s/%s", network.L3NetworkUUID, network.UUID) +} + +func (network *SNetwork) IsEmulated() bool { + return false +} + +func (network *SNetwork) GetStatus() string { + return api.NETWORK_STATUS_AVAILABLE +} + +func (network *SNetwork) Delete() error { + return network.wire.vpc.region.DeleteNetwork(network.UUID) +} + +func (region *SRegion) DeleteNetwork(networkId string) error { + network, err := region.GetNetwork("", "", "", networkId) + if err != nil { + return err + } + l3, err := region.GetL3Network(network.L3NetworkUUID) + if err != nil { + return err + } + if len(l3.Networks) == 1 { + return region.client.delete("l3-networks", l3.UUID, "") + } + return region.client.delete("l3-networks/ip-ranges", networkId, "") +} + +func (network *SNetwork) GetIWire() cloudprovider.ICloudWire { + return network.wire +} + +func (network *SNetwork) GetAllocTimeoutSeconds() int { + return 120 // 2 minutes +} + +func (network *SNetwork) GetGateway() string { + return network.Gateway +} + +func (network *SNetwork) GetIpStart() string { + return network.StartIP +} + +func (network *SNetwork) GetIpEnd() string { + return network.EndIP +} + +func (network *SNetwork) GetIPRange() netutils.IPV4AddrRange { + start, _ := netutils.NewIPV4Addr(network.GetIpStart()) + end, _ := netutils.NewIPV4Addr(network.GetIpEnd()) + return netutils.NewIPV4AddrRange(start, end) +} + +func (network *SNetwork) Contains(ipAddr string) bool { + ip, err := netutils.NewIPV4Addr(ipAddr) + if err != nil { + return false + } + return network.GetIPRange().Contains(ip) +} + +func (network *SNetwork) GetIpMask() int8 { + return int8(network.PrefixLen) +} + +func (network *SNetwork) GetIsPublic() bool { + return true +} + +func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope { + return rbacutils.ScopeSystem +} + +func (network *SNetwork) GetServerType() string { + return api.NETWORK_TYPE_GUEST +} + +func (network *SNetwork) Refresh() error { + new, err := network.wire.vpc.region.GetNetwork("", network.wire.UUID, network.L3NetworkUUID, network.UUID) + if err != nil { + return err + } + return jsonutils.Update(network, new) +} + +func (network *SNetwork) GetProjectId() string { + return "" +} + +func (region *SRegion) CreateNetwork(name string, cidr string, wireId string, desc string) (*SNetwork, error) { + params := map[string]interface{}{ + "params": map[string]interface{}{ + "name": name, + "type": "L3BasicNetwork", + "l2NetworkUuid": wireId, + "category": "Private", + "system": false, + }, + } + l3 := &SL3Network{} + resp, err := region.client.post("l3-networks", jsonutils.Marshal(params)) + if err != nil { + return nil, err + } + err = resp.Unmarshal(l3, "inventory") + if err != nil { + return nil, err + } + region.AttachServiceForl3Network(l3.UUID, []string{"Flat", "SecurityGroup"}) + params = map[string]interface{}{ + "params": map[string]interface{}{ + "name": name, + "networkCidr": cidr, + }, + } + resource := fmt.Sprintf("l3-networks/%s/ip-ranges/by-cidr", l3.UUID) + resp, err = region.client.post(resource, jsonutils.Marshal(params)) + if err != nil { + region.client.delete("l3-networks", l3.UUID, "") + return nil, err + } + network := &SNetwork{} + return network, resp.Unmarshal(network, "inventory") +} diff --git a/pkg/multicloud/zstack/network_service.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/network_service.go similarity index 100% rename from pkg/multicloud/zstack/network_service.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/network_service.go diff --git a/pkg/multicloud/zstack/offering.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/offering.go similarity index 97% rename from pkg/multicloud/zstack/offering.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/offering.go index f6d0839eb1..1a4e034525 100644 --- a/pkg/multicloud/zstack/offering.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/offering.go @@ -22,14 +22,14 @@ import ( "yunion.io/x/jsonutils" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SInstanceOffering struct { multicloud.SServerSku - multicloud.ZStackTags + ZStackTags region *SRegion ZStackBasic diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/provider/doc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/provider/doc.go new file mode 100644 index 0000000000..0a47e3bb35 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/provider/doc.go @@ -0,0 +1,15 @@ +// Copyright 2019 Yunion +// +// 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 provider // import "yunion.io/x/cloudmux/pkg/multicloud/zstack/provider" diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/provider/provider.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/provider/provider.go new file mode 100644 index 0000000000..0b4051e4ef --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/provider/provider.go @@ -0,0 +1,167 @@ +// Copyright 2019 Yunion +// +// 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 provider + +import ( + "context" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/cloudmux/pkg/multicloud/zstack" +) + +type SZStackProviderFactory struct { + cloudprovider.SPrivateCloudBaseProviderFactory +} + +func (self *SZStackProviderFactory) GetId() string { + return zstack.CLOUD_PROVIDER_ZSTACK +} + +func (self *SZStackProviderFactory) GetName() string { + return zstack.CLOUD_PROVIDER_ZSTACK +} + +func (self *SZStackProviderFactory) GetSupportedBrands() []string { + return []string{api.ZSTACK_BRAND_DSTACK} +} + +func (self *SZStackProviderFactory) ValidateCreateCloudaccountData(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AuthUrl) == 0 { + return output, errors.Wrap(httperrors.ErrMissingParameter, "auth_url") + } + output.AccessUrl = input.AuthUrl + //为了兼容以前用username的参数,2.12之后尽可能的使用access_key_id参数 + if len(input.AccessKeyId) > 0 && len(input.AccessKeySecret) > 0 { + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + } else if len(input.Username) > 0 && len(input.Password) > 0 { + output.Account = input.Username + output.Secret = input.Password + } else { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id or access_key_secret") + } + return output, nil +} + +func (self *SZStackProviderFactory) ValidateUpdateCloudaccountCredential(ctx context.Context, userCred mcclient.TokenCredential, input cloudprovider.SCloudaccountCredential, cloudaccount string) (cloudprovider.SCloudaccount, error) { + output := cloudprovider.SCloudaccount{} + if len(input.AccessKeyId) > 0 && len(input.AccessKeySecret) > 0 { + output.Account = input.AccessKeyId + output.Secret = input.AccessKeySecret + } else if len(input.Username) > 0 && len(input.Password) > 0 { + output.Account = input.Username + output.Secret = input.Password + } else { + return output, errors.Wrap(httperrors.ErrMissingParameter, "access_key_id or access_key_secret") + } + return output, nil +} + +func (self *SZStackProviderFactory) GetProvider(cfg cloudprovider.ProviderConfig) (cloudprovider.ICloudProvider, error) { + client, err := zstack.NewZStackClient( + zstack.NewZstackClientConfig( + cfg.URL, cfg.Account, cfg.Secret, + ).CloudproviderConfig(cfg), + ) + if err != nil { + return nil, err + } + return &SZStackProvider{ + SBaseProvider: cloudprovider.NewBaseProvider(self), + client: client, + }, nil +} + +func (self *SZStackProviderFactory) GetClientRC(info cloudprovider.SProviderInfo) (map[string]string, error) { + return map[string]string{ + "ZSTACK_AUTH_URL": info.Url, + "ZSTACK_USERNAME": info.Account, + "ZSTACK_PASSWORD": info.Secret, + "ZSTACK_REGION_ID": zstack.ZSTACK_DEFAULT_REGION, + }, nil +} + +func init() { + factory := SZStackProviderFactory{} + cloudprovider.RegisterFactory(&factory) +} + +type SZStackProvider struct { + cloudprovider.SBaseProvider + client *zstack.SZStackClient +} + +func (self *SZStackProvider) GetVersion() string { + return "" +} + +func (self *SZStackProvider) GetSysInfo() (jsonutils.JSONObject, error) { + return jsonutils.NewDict(), nil +} + +func (self *SZStackProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { + return self.client.GetSubAccounts() +} + +func (self *SZStackProvider) GetAccountId() string { + return "" +} + +func (self *SZStackProvider) GetIRegions() []cloudprovider.ICloudRegion { + return self.client.GetIRegions() +} + +func (self *SZStackProvider) GetIRegionById(extId string) (cloudprovider.ICloudRegion, error) { + return self.client.GetIRegionById(extId) +} + +func (self *SZStackProvider) GetBalance() (float64, string, error) { + return 0.0, api.CLOUD_PROVIDER_HEALTH_UNKNOWN, cloudprovider.ErrNotSupported +} + +func (self *SZStackProvider) GetCloudRegionExternalIdPrefix() string { + return self.client.GetCloudRegionExternalIdPrefix() +} + +func (self *SZStackProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} + +func (self *SZStackProvider) GetStorageClasses(regionId string) []string { + return nil +} + +func (self *SZStackProvider) GetBucketCannedAcls(regionId string) []string { + return nil +} + +func (self *SZStackProvider) GetObjectCannedAcls(regionId string) []string { + return nil +} + +func (self *SZStackProvider) GetCapabilities() []string { + return self.client.GetCapabilities() +} + +func (self *SZStackProvider) GetMetrics(opts *cloudprovider.MetricListOptions) ([]cloudprovider.MetricValues, error) { + return self.client.GetEcsMetrics(opts) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/quota.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/quota.go new file mode 100644 index 0000000000..2942171c81 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/quota.go @@ -0,0 +1,104 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "net/url" + + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +/* + "uuid":"132e0ad32b2242c4a648440be917ec4a", + "name":"pci.num", + "identityUuid":"2dce5dc485554d21a3796500c1db007a", + "identityType":"AccountVO", + "value":0, + "lastOpDate":"Dec 28, 2019 2:26:03 PM", + "createDate":"Dec 28, 2019 2:26:03 PM" +*/ + +type SQuota struct { + Uuid string + Name string + IdentityUuid string + IdentityType string + Value int +} + +func (q *SQuota) GetGlobalId() string { + return q.Uuid +} + +func (q *SQuota) GetName() string { + return q.Name +} + +func (q *SQuota) GetDesc() string { + return "" +} + +func (q *SQuota) GetQuotaType() string { + return q.Name +} + +func (q *SQuota) GetMaxQuotaCount() int { + return q.Value +} + +func (q *SQuota) GetCurrentQuotaUsedCount() int { + return -1 +} + +func (region *SRegion) GetQuotas() ([]SQuota, error) { + quotas := []SQuota{} + params := url.Values{} + err := region.client.listAll("accounts/quotas", params, "as) + if err != nil { + return nil, err + } + return quotas, nil +} + +type SUserAccount struct { + Uuid string +} + +func (region *SRegion) GetUserAccount(name string) ([]SUserAccount, error) { + users := []SUserAccount{} + params := url.Values{} + if len(name) > 0 { + params.Add("q", "name="+name) + } + err := region.client.listAll("accounts/users", params, &users) + if err != nil { + return nil, errors.Wrap(err, "users.list") + } + return users, nil +} + +func (region *SRegion) GetICloudQuotas() ([]cloudprovider.ICloudQuota, error) { + quotas, err := region.GetQuotas() + if err != nil { + return nil, errors.Wrap(err, "GetQuotas") + } + ret := []cloudprovider.ICloudQuota{} + for i := range quotas { + ret = append(ret, "as[i]) + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/region.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/region.go new file mode 100644 index 0000000000..986e283e4e --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/region.go @@ -0,0 +1,386 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SRegion struct { + multicloud.SRegion + multicloud.SNoObjectStorageRegion + + client *SZStackClient + + Name string + + izones []cloudprovider.ICloudZone + ivpcs []cloudprovider.ICloudVpc +} + +func (region *SRegion) GetILoadBalancerBackendGroups() ([]cloudprovider.ICloudLoadbalancerBackendGroup, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetClient() *SZStackClient { + return region.client +} + +func (region *SRegion) GetId() string { + return region.Name +} + +func (region *SRegion) GetName() string { + return region.client.cpcfg.Name +} + +func (region *SRegion) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(region.GetName()).CN(region.GetName()) + return table +} + +func (region *SRegion) GetGlobalId() string { + return fmt.Sprintf("%s/%s", CLOUD_PROVIDER_ZSTACK, region.client.cpcfg.Id) +} + +func (region *SRegion) IsEmulated() bool { + return false +} + +func (region *SRegion) GetProvider() string { + return CLOUD_PROVIDER_ZSTACK +} + +func (region *SRegion) GetCloudEnv() string { + return "" +} + +func (region *SRegion) GetGeographicInfo() cloudprovider.SGeographicInfo { + return cloudprovider.SGeographicInfo{} +} + +func (region *SRegion) GetStatus() string { + return api.CLOUD_REGION_STATUS_INSERVER +} + +func (region *SRegion) Refresh() error { + // do nothing + return nil +} + +func (self *SRegion) GetIVMById(id string) (cloudprovider.ICloudVM, error) { + vm, err := self.GetInstance(id) + if err != nil { + return nil, err + } + return vm, nil +} + +func (self *SRegion) GetIDiskById(id string) (cloudprovider.ICloudDisk, error) { + disk, err := self.GetDisk(id) + if err != nil { + return nil, err + } + return disk, nil +} + +func (region *SRegion) GetIHostById(id string) (cloudprovider.ICloudHost, error) { + return region.GetHost(id) +} + +func (region *SRegion) GetIStorageById(id string) (cloudprovider.ICloudStorage, error) { + storages, err := region.getIStorages("") + if err != nil { + return nil, err + } + for i := 0; i < len(storages); i++ { + if storages[i].GetGlobalId() == id { + return storages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetIHosts() ([]cloudprovider.ICloudHost, error) { + hosts, err := region.GetHosts("", "") + if err != nil { + return nil, err + } + ihosts := []cloudprovider.ICloudHost{} + for i := 0; i < len(hosts); i++ { + ihosts = append(ihosts, &hosts[i]) + } + return ihosts, nil +} + +func (region *SRegion) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + return region.getIStorages("") +} + +func (region *SRegion) GetIStoragecacheById(id string) (cloudprovider.ICloudStoragecache, error) { + caches, err := region.GetIStoragecaches() + if err != nil { + return nil, err + } + for i := 0; i < len(caches); i++ { + if caches[i].GetGlobalId() == id { + return caches[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetIStoragecaches() ([]cloudprovider.ICloudStoragecache, error) { + zones, err := region.GetZones("") + if err != nil { + return nil, err + } + icaches := []cloudprovider.ICloudStoragecache{} + for i := 0; i < len(zones); i++ { + icaches = append(icaches, &SStoragecache{ZoneId: zones[i].UUID, region: region}) + } + return icaches, nil +} + +func (region *SRegion) GetIVpcById(vpcId string) (cloudprovider.ICloudVpc, error) { + return &SVpc{region: region}, nil +} + +func (region *SRegion) GetIZoneById(id string) (cloudprovider.ICloudZone, error) { + izones, err := region.GetIZones() + if err != nil { + return nil, err + } + for i := 0; i < len(izones); i++ { + if izones[i].GetGlobalId() == id { + return izones[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (region *SRegion) GetZone(zoneId string) (*SZone, error) { + zone := &SZone{region: region} + return zone, region.client.getResource("zones", zoneId, zone) +} + +func (region *SRegion) GetZones(zoneId string) ([]SZone, error) { + zones := []SZone{} + params := url.Values{} + if len(zoneId) > 0 { + params.Add("q", "uuid="+zoneId) + } + err := region.client.listAll("zones", params, &zones) + if err != nil { + return nil, err + } + for i := 0; i < len(zones); i++ { + zones[i].region = region + } + return zones, nil +} + +func (region *SRegion) fetchZones() { + if region.izones == nil || len(region.izones) == 0 { + zones, err := region.GetZones("") + if err != nil { + log.Errorf("failed to get zones error: %v", err) + return + } + region.izones = []cloudprovider.ICloudZone{} + for i := 0; i < len(zones); i++ { + region.izones = append(region.izones, &zones[i]) + } + } +} + +func (region *SRegion) fetchInfrastructure() error { + region.fetchZones() + region.GetIVpcs() + return nil +} + +func (region *SRegion) GetIZones() ([]cloudprovider.ICloudZone, error) { + if region.izones == nil { + if err := region.fetchInfrastructure(); err != nil { + return nil, err + } + } + return region.izones, nil +} + +func (region *SRegion) GetVpc() *SVpc { + return &SVpc{region: region} +} + +func (region *SRegion) GetIVpcs() ([]cloudprovider.ICloudVpc, error) { + region.ivpcs = []cloudprovider.ICloudVpc{region.GetVpc()} + return region.ivpcs, nil +} + +func (region *SRegion) CreateIVpc(opts *cloudprovider.VpcCreateOptions) (cloudprovider.ICloudVpc, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (region *SRegion) CreateEIP(eip *cloudprovider.SEip) (cloudprovider.ICloudEIP, error) { + if len(eip.NetworkExternalId) == 0 { + return nil, fmt.Errorf("networkId cannot be empty") + } + networkInfo := strings.Split(eip.NetworkExternalId, "/") + if len(networkInfo) != 2 { + return nil, fmt.Errorf("invalid network externalId, it should be `l3networId/networkId` format") + } + _, err := region.GetL3Network(networkInfo[0]) + if err != nil { + return nil, err + } + vip, err := region.CreateVirtualIP(eip.Name, "", eip.IP, networkInfo[0]) + if err != nil { + return nil, err + } + return region.CreateEip(eip.Name, vip.UUID, "") +} + +func (region *SRegion) GetIEipById(eipId string) (cloudprovider.ICloudEIP, error) { + return region.GetEip(eipId) +} + +func (region *SRegion) GetILoadBalancers() ([]cloudprovider.ICloudLoadbalancer, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetILoadBalancerById(loadbalancerId string) (cloudprovider.ICloudLoadbalancer, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetILoadBalancerAclById(aclId string) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetILoadBalancerCertificateById(certId string) (cloudprovider.ICloudLoadbalancerCertificate, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) CreateILoadBalancerCertificate(cert *cloudprovider.SLoadbalancerCertificate) (cloudprovider.ICloudLoadbalancerCertificate, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetILoadBalancerAcls() ([]cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetILoadBalancerCertificates() ([]cloudprovider.ICloudLoadbalancerCertificate, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) CreateILoadBalancer(loadbalancer *cloudprovider.SLoadbalancer) (cloudprovider.ICloudLoadbalancer, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) CreateILoadBalancerAcl(acl *cloudprovider.SLoadbalancerAccessControlList) (cloudprovider.ICloudLoadbalancerAcl, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (region *SRegion) GetIEips() ([]cloudprovider.ICloudEIP, error) { + eips, err := region.GetEips("", "") + if err != nil { + return nil, err + } + ieips := []cloudprovider.ICloudEIP{} + for i := 0; i < len(eips); i++ { + ieips = append(ieips, &eips[i]) + } + return ieips, nil +} + +func (region *SRegion) GetISnapshots() ([]cloudprovider.ICloudSnapshot, error) { + snapshots, err := region.GetSnapshots("", "") + if err != nil { + return nil, err + } + isnapshots := []cloudprovider.ICloudSnapshot{} + for i := 0; i < len(snapshots); i++ { + snapshots[i].region = region + isnapshots = append(isnapshots, &snapshots[i]) + } + return isnapshots, nil +} + +func (region *SRegion) GetISnapshotById(snapshotId string) (cloudprovider.ICloudSnapshot, error) { + return region.GetSnapshot(snapshotId) +} + +func (region *SRegion) GetISkus() ([]cloudprovider.ICloudSku, error) { + offerings, err := region.GetInstanceOfferings("", "", 0, 0) + if err != nil { + return nil, err + } + iskus := []cloudprovider.ICloudSku{} + for i := 0; i < len(offerings); i++ { + offerings[i].region = region + iskus = append(iskus, &offerings[i]) + } + return iskus, nil +} + +func (region *SRegion) DeleteISkuByName(name string) error { + offerings, err := region.GetInstanceOfferings("", name, 0, 0) + if err != nil { + return errors.Wrap(err, "region.GetInstanceOfferings") + } + for _, offering := range offerings { + err = offering.Delete() + if err != nil { + return err + } + } + return nil +} + +func (region *SRegion) GetISecurityGroupById(secgroupId string) (cloudprovider.ICloudSecurityGroup, error) { + return region.GetSecurityGroup(secgroupId) +} + +func (region *SRegion) GetISecurityGroupByName(opts *cloudprovider.SecurityGroupFilterOptions) (cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := region.GetSecurityGroups("", "", opts.Name) + if err != nil { + return nil, err + } + if len(secgroups) == 0 { + return nil, cloudprovider.ErrNotFound + } + if len(secgroups) > 1 { + return nil, cloudprovider.ErrDuplicateId + } + return &secgroups[0], nil +} + +func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { + return region.CreateSecurityGroup(conf.Name, conf.Desc) +} + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/securitygroup.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/securitygroup.go new file mode 100644 index 0000000000..d7167a6cbc --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/securitygroup.go @@ -0,0 +1,264 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" + "yunion.io/x/pkg/util/secrules" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSecurityGroupRule struct { + ZStackBasic + SecurityGroupUUID string `json:"securityGroupUuid"` + Type string `json:"type"` + IPVersion int `json:"ipVersion"` + StartPort int `json:"startPort"` + EndPort int `json:"endPort"` + Protocol string `json:"protocol"` + State string `json:"state"` + AllowedCIDR string `json:"allowedCidr"` + RemoteSecurityGroupUUID string `json:"remoteSecurityGroupUuid"` + ZStackTime +} + +type SSecurityGroup struct { + multicloud.SSecurityGroup + ZStackTags + region *SRegion + + ZStackBasic + State string `json:"state"` + IPVersion int `json:"ipVersion"` + ZStackTime + InternalID int `json:"internalId"` + Rules []SSecurityGroupRule `json:"rules"` + AttachedL3NetworkUUIDs []string `json:"attachedL3NetworkUuids"` +} + +func (region *SRegion) GetSecurityGroup(secgroupId string) (*SSecurityGroup, error) { + secgroup := &SSecurityGroup{region: region} + return secgroup, region.client.getResource("security-groups", secgroupId, secgroup) +} + +func (region *SRegion) GetSecurityGroups(secgroupId string, instanceId string, name string) ([]SSecurityGroup, error) { + secgroups := []SSecurityGroup{} + params := url.Values{} + if len(secgroupId) > 0 { + params.Add("q", "uuid="+secgroupId) + } + if len(instanceId) > 0 { + params.Add("q", "vmNic.vmInstanceUuid="+instanceId) + } + if len(name) > 0 { + params.Add("q", "name="+name) + } + err := region.client.listAll("security-groups", params, &secgroups) + if err != nil { + return nil, err + } + for i := 0; i < len(secgroups); i++ { + secgroups[i].region = region + } + return secgroups, nil +} + +func (self *SSecurityGroup) GetVpcId() string { + return api.NORMAL_VPC_ID +} + +func (self *SSecurityGroup) GetId() string { + return self.UUID +} + +func (self *SSecurityGroup) GetGlobalId() string { + return self.UUID +} + +func (self *SSecurityGroup) GetDescription() string { + return self.Description +} + +func (rule *SSecurityGroupRule) toRule() (cloudprovider.SecurityRule, error) { + r := cloudprovider.SecurityRule{ + ExternalId: rule.UUID, + SecurityRule: secrules.SecurityRule{ + Direction: secrules.DIR_IN, + Action: secrules.SecurityRuleAllow, + Priority: 1, + Protocol: secrules.PROTO_ANY, + PortStart: rule.StartPort, + PortEnd: rule.EndPort, + }, + } + r.ParseCIDR(rule.AllowedCIDR) + if rule.Type == "Egress" { + r.Direction = secrules.DIR_OUT + } + if rule.Protocol != "ALL" { + r.Protocol = strings.ToLower(rule.Protocol) + } + err := r.ValidateRule() + if err != nil { + return r, errors.Wrap(err, "invalid rule") + } + return r, nil +} + +func (self *SSecurityGroup) GetRules() ([]cloudprovider.SecurityRule, error) { + rules := []cloudprovider.SecurityRule{} + for i := 0; i < len(self.Rules); i++ { + if self.Rules[i].IPVersion == 4 { + rule, err := self.Rules[i].toRule() + if err != nil { + return nil, err + } + rules = append(rules, rule) + } + } + return rules, nil +} + +func (self *SSecurityGroup) GetName() string { + return self.Name +} + +func (self *SSecurityGroup) GetStatus() string { + return "" +} + +func (self *SSecurityGroup) IsEmulated() bool { + return false +} + +func (self *SSecurityGroup) Refresh() error { + new, err := self.region.GetSecurityGroup(self.UUID) + if err != nil { + return err + } + return jsonutils.Update(self, new) +} + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} + +func (region *SRegion) AddSecurityGroupRule(secgroupId string, rules []cloudprovider.SecurityRule) error { + ruleParam := []map[string]interface{}{} + for _, rule := range rules { + Type := "Ingress" + if rule.Direction == secrules.DIR_OUT { + Type = "Egress" + } + protocol := "ALL" + if rule.Protocol != secrules.PROTO_ANY { + protocol = strings.ToUpper(rule.Protocol) + } + if rule.Protocol == secrules.PROTO_ICMP || rule.Protocol == secrules.PROTO_ANY { + rule.PortStart = -1 + rule.PortEnd = -1 + rule.Ports = []int{} + } + if len(rule.Ports) > 0 { + for _, port := range rule.Ports { + ruleParam = append(ruleParam, map[string]interface{}{ + "type": Type, + "startPort": port, + "endPort": port, + "protocol": protocol, + "allowedCidr": rule.IPNet.String(), + }) + } + } else { + if protocol != "ALL" { + // TCP UDP端口不能为-1 + if (rule.Protocol == secrules.PROTO_TCP || rule.Protocol == secrules.PROTO_UDP) && + (rule.PortStart <= 0 && rule.PortEnd <= 0) { + rule.PortStart = 0 + rule.PortEnd = 65535 + } + ruleParam = append(ruleParam, map[string]interface{}{ + "type": Type, + "startPort": rule.PortStart, + "endPort": rule.PortEnd, + "protocol": protocol, + "allowedCidr": rule.IPNet.String(), + }) + } else { + ruleParam = append(ruleParam, map[string]interface{}{ + "type": Type, + "protocol": protocol, + "allowedCidr": rule.IPNet.String(), + }) + } + } + } + if len(ruleParam) > 0 { + params := map[string]interface{}{ + "params": map[string]interface{}{ + "rules": ruleParam, + }, + } + return region.client.create(fmt.Sprintf("security-groups/%s/rules", secgroupId), jsonutils.Marshal(params), nil) + } + return nil +} + +func (region *SRegion) DeleteSecurityGroupRules(ruleIds []string) error { + if len(ruleIds) > 0 { + ids := []string{} + for _, ruleId := range ruleIds { + ids = append(ids, fmt.Sprintf("ruleUuids=%s", ruleId)) + } + resource := fmt.Sprintf("security-groups/rules?%s", strings.Join(ids, "&")) + return region.client.delete(resource, "", "") + } + return nil +} + +func (region *SRegion) CreateSecurityGroup(name, desc string) (*SSecurityGroup, error) { + secgroup := &SSecurityGroup{region: region} + params := map[string]map[string]string{ + "params": { + "name": name, + "description": desc, + }, + } + return secgroup, region.client.create("security-groups", jsonutils.Marshal(params), secgroup) +} + +func (self *SSecurityGroup) SyncRules(common, inAdds, outAdds, inDels, outDels []cloudprovider.SecurityRule) error { + deleteIds := []string{} + for _, r := range append(inDels, outDels...) { + deleteIds = append(deleteIds, r.ExternalId) + } + err := self.region.DeleteSecurityGroupRules(deleteIds) + if err != nil { + return errors.Wrapf(err, "DeleteSecurityGroupRules(%s)", deleteIds) + } + return self.region.AddSecurityGroupRule(self.UUID, append(inAdds, outAdds...)) +} + +func (self *SSecurityGroup) Delete() error { + return self.region.client.delete("security-groups", self.UUID, "Permissive") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/snapshot.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/snapshot.go new file mode 100644 index 0000000000..507e644162 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/snapshot.go @@ -0,0 +1,144 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "fmt" + "net/url" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SSnapshot struct { + multicloud.SResourceBase + ZStackTags + region *SRegion + + ZStackBasic + PrimaryStorageUUID string `json:"primaryStorageUuid"` + VolumeUUID string `json:"volumeUuid"` + VolumeType string `json:"volumeType"` + Format string `json:"format"` + Latest bool `json:"latest"` + Size int `json:"size"` + State string `json:"state"` + Status string `json:"status"` +} + +func (snapshot *SSnapshot) GetId() string { + return snapshot.UUID +} + +func (snapshot *SSnapshot) GetName() string { + return snapshot.Name +} + +func (snapshot *SSnapshot) GetStatus() string { + switch snapshot.Status { + case "Ready": + return api.SNAPSHOT_READY + default: + log.Errorf("unknown snapshot %s(%s) status %s", snapshot.Name, snapshot.UUID, snapshot.Status) + return api.SNAPSHOT_UNKNOWN + } +} + +func (snapshot *SSnapshot) GetSizeMb() int32 { + return int32(snapshot.Size / 1024 / 1024) +} + +func (snapshot *SSnapshot) GetDiskId() string { + return snapshot.VolumeUUID +} + +func (snapshot *SSnapshot) GetDiskType() string { + switch snapshot.VolumeType { + case "Root": + return api.DISK_TYPE_SYS + default: + return api.DISK_TYPE_DATA + } +} + +func (snapshot *SSnapshot) Refresh() error { + new, err := snapshot.region.GetSnapshot(snapshot.UUID) + if err != nil { + return err + } + return jsonutils.Update(snapshot, new) +} + +func (snapshot *SSnapshot) GetGlobalId() string { + return snapshot.UUID +} + +func (snapshot *SSnapshot) IsEmulated() bool { + return false +} + +func (region *SRegion) GetSnapshot(snapshotId string) (*SSnapshot, error) { + snapshot := &SSnapshot{region: region} + return snapshot, region.client.getResource("volume-snapshots", snapshotId, snapshot) +} + +func (region *SRegion) GetSnapshots(snapshotId string, diskId string) ([]SSnapshot, error) { + snapshots := []SSnapshot{} + params := url.Values{} + if len(snapshotId) > 0 { + params.Add("q", "uuid="+snapshotId) + } + if len(diskId) > 0 { + params.Add("q", "volumeUuid="+diskId) + } + if err := region.client.listAll("volume-snapshots", params, &snapshots); err != nil { + return nil, err + } + for i := 0; i < len(snapshots); i++ { + snapshots[i].region = region + } + return snapshots, nil +} + +func (snapshot *SSnapshot) Delete() error { + return snapshot.region.DeleteSnapshot(snapshot.UUID) +} + +func (region *SRegion) DeleteSnapshot(snapshotId string) error { + return region.client.delete("volume-snapshots", snapshotId, "Enforcing") +} + +func (snapshot *SSnapshot) GetProjectId() string { + return "" +} + +func (region *SRegion) CreateSnapshot(name, diskId, desc string) (*SSnapshot, error) { + params := map[string]interface{}{ + "params": map[string]string{ + "name": name, + "description": desc, + }, + } + resource := fmt.Sprintf("volumes/%s/volume-snapshots", diskId) + resp, err := region.client.post(resource, jsonutils.Marshal(params)) + if err != nil { + return nil, err + } + snapshot := &SSnapshot{region: region} + return snapshot, resp.Unmarshal(snapshot, "inventory") +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/storage.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/storage.go new file mode 100644 index 0000000000..9e81372a21 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/storage.go @@ -0,0 +1,266 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "fmt" + "net/url" + "strings" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type TStorageType string + +type TCephPoolType string + +const ( + StorageTypeCeph = TStorageType("Ceph") + StorageTypeLocal = TStorageType("LocalStorage") + StorageTypeVCenter = TStorageType("VCenter") + + CephPoolTypeData = TCephPoolType("Data") + CephPoolTypeRoot = TCephPoolType("Root") + CephPoolTypeImageCache = TCephPoolType("ImageCache") +) + +type SPool struct { + UUID string `json:"uuid"` + PrimaryStorageUUID string `json:"primaryStorageUuid"` + PoolName string `json:"poolName"` + Type TCephPoolType `json:"type"` + AvailableCapacity int64 `json:"availableCapacity"` + UsedCapacity int64 `json:"usedCapacity"` + ReplicatedSize int64 `json:"replicatedSize"` + TotalCapacity int64 `json:"totalCapacity"` + ZStackTime +} + +type SStorage struct { + multicloud.SStorageBase + ZStackTags + region *SRegion + + ZStackBasic + VCenterUUID string `json:"VCenterUuid"` + Datastore string `json:"datastore"` + ZoneUUID string `json:"zoneUuid"` + URL string `json:"url"` + TotalCapacity int64 `json:"totalCapacity"` + AvailableCapacity int `json:"availableCapacity"` + TotalPhysicalCapacity int `json:"totalPhysicalCapacity"` + AvailablePhysicalCapacity int `json:"availablePhysicalCapacity"` + Type TStorageType `json:"type"` + State string `json:"state"` + Status string `json:"status"` + MountPath string `json:"mountPath"` + AttachedClusterUUIDs []string `json:"attachedClusterUuids"` + + Pools []SPool `json:"pools"` + + ZStackTime +} + +func (region *SRegion) getIStorages(zondId string) ([]cloudprovider.ICloudStorage, error) { + primaryStorages, err := region.GetStorages(zondId, "", "") + if err != nil { + return nil, err + } + istorage := []cloudprovider.ICloudStorage{} + for i := 0; i < len(primaryStorages); i++ { + primaryStorage := primaryStorages[i] + switch primaryStorage.Type { + case StorageTypeLocal: + ilocalStorages, err := region.getILocalStorages(primaryStorage.UUID, "") + if err != nil { + return nil, err + } + istorage = append(istorage, ilocalStorages...) + case StorageTypeCeph: + primaryStorage.region = region + istorage = append(istorage, &primaryStorage) + case StorageTypeVCenter: + } + } + return istorage, nil +} + +func (region *SRegion) GetStorage(storageId string) (*SStorage, error) { + if len(storageId) == 0 { + return nil, cloudprovider.ErrNotFound + } + storages, err := region.GetStorages("", "", storageId) + if err != nil { + return nil, err + } + if len(storages) == 1 && storages[0].UUID == storageId { + storages[0].region = region + return &storages[0], nil + } + if len(storages) == 0 { + return nil, cloudprovider.ErrNotFound + } + return nil, cloudprovider.ErrDuplicateId +} + +func (region *SRegion) GetStorages(zoneId, clusterId, storageId string) ([]SStorage, error) { + storages := []SStorage{} + params := url.Values{} + if len(zoneId) > 0 { + params.Add("q", "zone.uuid="+zoneId) + } + if len(clusterId) > 0 { + params.Add("q", "cluster.uuid="+clusterId) + } + if SkipEsxi { + params.Add("q", "type!=VCenter") + } + if len(storageId) > 0 { + params.Add("q", "uuid="+storageId) + } + return storages, region.client.listAll("primary-storage", params, &storages) +} + +func (storage *SStorage) GetStatus() string { + if storage.Status == "Connected" { + return api.STORAGE_ONLINE + } + return api.STORAGE_OFFLINE +} + +func (storage *SStorage) GetId() string { + return storage.UUID +} + +func (storage *SStorage) GetName() string { + return storage.Name +} + +func (storage *SStorage) GetGlobalId() string { + return storage.GetId() +} + +func (storage *SStorage) IsEmulated() bool { + return false +} + +func (storage *SStorage) GetIZone() cloudprovider.ICloudZone { + zone, err := storage.region.GetZone(storage.ZoneUUID) + if err != nil { + log.Errorf("failed to find zone for storage %s(%s)", storage.Name, storage.UUID) + return nil + } + return zone +} + +func (storage *SStorage) GetIDisks() ([]cloudprovider.ICloudDisk, error) { + disks, err := storage.region.GetDisks(storage.UUID, []string{}, "") + if err != nil { + return nil, err + } + idisks := []cloudprovider.ICloudDisk{} + for i := 0; i < len(disks); i++ { + disks[i].storage = storage + disks[i].region = storage.region + idisks = append(idisks, &disks[i]) + } + return idisks, nil +} + +func (storage *SStorage) GetStorageType() string { + return strings.ToLower(string(storage.Type)) +} + +func (storage *SStorage) GetMediumType() string { + return api.DISK_TYPE_ROTATE +} + +func (storage *SStorage) GetCapacityMB() int64 { + return storage.TotalCapacity / 1024 / 1024 +} + +func (storage *SStorage) GetCapacityUsedMB() int64 { + return 0 +} + +func (storage *SStorage) GetStorageConf() jsonutils.JSONObject { + conf := jsonutils.NewDict() + return conf +} + +func (storage *SStorage) Refresh() error { + // do nothing + return nil +} + +func (storage *SStorage) GetEnabled() bool { + return true +} + +func (storage *SStorage) GetIStoragecache() cloudprovider.ICloudStoragecache { + return &SStoragecache{ZoneId: storage.ZoneUUID, region: storage.region} +} + +func (storage *SStorage) CreateIDisk(conf *cloudprovider.DiskCreateConfig) (cloudprovider.ICloudDisk, error) { + poolName, err := storage.GetDataPoolName() + if err != nil { + return nil, err + } + disk, err := storage.region.CreateDisk(conf.Name, storage.UUID, "", poolName, conf.SizeGb, conf.Desc) + if err != nil { + return nil, err + } + disk.storage = storage + return disk, nil +} + +func (storage *SStorage) GetIDiskById(diskId string) (cloudprovider.ICloudDisk, error) { + disk, err := storage.region.GetDisk(diskId) + if err != nil { + return nil, err + } + if disk.PrimaryStorageUUID != storage.UUID { + return nil, cloudprovider.ErrNotFound + } + disk.region = storage.region + disk.storage = storage + return disk, nil +} + +func (storage *SStorage) GetMountPoint() string { + poolName, _ := storage.GetDataPoolName() + if len(poolName) > 0 { + return fmt.Sprintf("ceph://%s", poolName) + } + return "" +} + +func (storage *SStorage) IsSysDiskStore() bool { + return true +} + +func (storage *SStorage) GetDataPoolName() (string, error) { + for _, pool := range storage.Pools { + if pool.Type == CephPoolTypeData { + return pool.PoolName, nil + } + } + return "", fmt.Errorf("failed to found storage %s(%s) data pool name", storage.Name, storage.UUID) +} diff --git a/pkg/multicloud/zstack/storage_local.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/storage_local.go similarity index 97% rename from pkg/multicloud/zstack/storage_local.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/storage_local.go index 532d8b5d2f..59262ca383 100644 --- a/pkg/multicloud/zstack/storage_local.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/storage_local.go @@ -22,14 +22,14 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" - "yunion.io/x/onecloud/pkg/multicloud" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" ) type SLocalStorage struct { multicloud.SStorageBase - multicloud.ZStackTags + ZStackTags region *SRegion primaryStorageID string diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/storagecache.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/storagecache.go new file mode 100644 index 0000000000..421b73859d --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/storagecache.go @@ -0,0 +1,137 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "context" + "fmt" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/compute/options" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/auth" + modules "yunion.io/x/onecloud/pkg/mcclient/modules/image" + "yunion.io/x/cloudmux/pkg/multicloud" + "yunion.io/x/onecloud/pkg/util/qemuimg" +) + +type SStoragecache struct { + multicloud.SResourceBase + ZStackTags + ZoneId string + region *SRegion +} + +func (scache *SStoragecache) GetId() string { + return fmt.Sprintf("%s-%s/%s", scache.region.client.cpcfg.Id, scache.region.GetId(), scache.ZoneId) +} + +func (scache *SStoragecache) GetName() string { + return fmt.Sprintf("%s-%s/%s", scache.region.client.cpcfg.Name, scache.region.GetId(), scache.ZoneId) +} + +func (scache *SStoragecache) GetStatus() string { + return "available" +} + +func (scache *SStoragecache) Refresh() error { + return nil +} + +func (scache *SStoragecache) GetGlobalId() string { + return scache.GetId() +} + +func (scache *SStoragecache) IsEmulated() bool { + return false +} + +func (scache *SStoragecache) GetICustomizedCloudImages() ([]cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (scache *SStoragecache) GetICloudImages() ([]cloudprovider.ICloudImage, error) { + images, err := scache.region.GetImages(scache.ZoneId, "") + if err != nil { + return nil, err + } + ret := []cloudprovider.ICloudImage{} + for i := 0; i < len(images); i++ { + images[i].storageCache = scache + ret = append(ret, &images[i]) + } + return ret, nil +} + +func (scache *SStoragecache) GetIImageById(extId string) (cloudprovider.ICloudImage, error) { + images, err := scache.region.GetImages(scache.ZoneId, extId) + if err != nil { + return nil, err + } + if len(images) == 1 { + images[0].storageCache = scache + return &images[0], nil + } + if len(images) == 0 { + return nil, cloudprovider.ErrNotFound + } + return nil, cloudprovider.ErrDuplicateId +} + +func (scache *SStoragecache) GetPath() string { + return "" +} + +func (scache *SStoragecache) UploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + return scache.uploadImage(ctx, userCred, image, callback) +} + +func (self *SStoragecache) uploadImage(ctx context.Context, userCred mcclient.TokenCredential, image *cloudprovider.SImageCreateOption, callback func(progress float32)) (string, error) { + s := auth.GetAdminSession(ctx, options.Options.Region) + + meta, reader, size, err := modules.Images.Download(s, image.ImageId, string(qemuimg.QCOW2), false) + if err != nil { + return "", err + } + log.Infof("meta data %s", meta) + + // size, _ := meta.Int("size") + img, err := self.region.CreateImage(self.ZoneId, image.ImageName, string(qemuimg.QCOW2), image.OsType, "", reader, size, callback) + if err != nil { + return "", err + } + img.storageCache = self + err = cloudprovider.WaitStatus(img, api.CACHED_IMAGE_STATUS_ACTIVE, time.Second*5, time.Minute*20) //windows镜像转换比较慢,等待时间稍微设长一些 + if err != nil { + log.Errorf("waitting for image %s(%s) status ready timeout", img.Name, img.UUID) + } + if callback != nil { + callback(100) + } + return img.UUID, err +} + +func (scache *SStoragecache) CreateIImage(snapshoutId, imageName, osType, imageDesc string) (cloudprovider.ICloudImage, error) { + return nil, cloudprovider.ErrNotImplemented +} + +func (scache *SStoragecache) DownloadImage(userCred mcclient.TokenCredential, imageId string, extId string, path string) (jsonutils.JSONObject, error) { + return nil, cloudprovider.ErrNotImplemented +} diff --git a/pkg/multicloud/zstack/systag.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/systag.go similarity index 100% rename from pkg/multicloud/zstack/systag.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/systag.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/tag_base.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/tag_base.go new file mode 100644 index 0000000000..974bf81607 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/tag_base.go @@ -0,0 +1,36 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "yunion.io/x/pkg/errors" + + "yunion.io/x/cloudmux/pkg/cloudprovider" +) + +type ZStackTags struct { +} + +func (self *ZStackTags) GetTags() (map[string]string, error) { + return nil, errors.Wrapf(cloudprovider.ErrNotImplemented, "GetTags") +} + +func (self *ZStackTags) GetSysTags() map[string]string { + return nil +} + +func (self *ZStackTags) SetTags(tags map[string]string, replace bool) error { + return errors.Wrap(cloudprovider.ErrNotImplemented, "SetTags") +} diff --git a/pkg/multicloud/zstack/version.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/version.go similarity index 100% rename from pkg/multicloud/zstack/version.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/version.go diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/vip.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/vip.go new file mode 100644 index 0000000000..184ad124a5 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/vip.go @@ -0,0 +1,180 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "fmt" + "net/url" + + "github.com/pkg/errors" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/util/netutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVirtualIP struct { + multicloud.SNetworkInterfaceBase + ZStackTags + region *SRegion + ZStackBasic + IPRangeUUID string `json:"ipRangeUuid"` + L3NetworkUUID string `json:"l3NetworkUuid"` + IP string `json:"ip"` + State string `json:"state"` + Gateway string `json:"gateway"` + Netmask string `json:"netmask"` + PrefixLen int `json:"prefixLen"` + ServiceProvider string `json:"serviceProvider"` + PeerL3NetworkUuids []string `json:"peerL3NetworkUuids"` + UseFor string `json:"useFor"` + UsedIPUUID string `json:"usedIpUuid"` + ZStackTime +} + +type SInterfaceIP struct { + IP string + L3NetworkUUID string + IPRangeUUID string +} + +func (ip *SInterfaceIP) GetIP() string { + return ip.IP +} + +func (ip *SInterfaceIP) GetINetworkId() string { + return fmt.Sprintf("%s/%s", ip.L3NetworkUUID, ip.IPRangeUUID) +} + +func (ip *SInterfaceIP) IsPrimary() bool { + return true +} + +func (ip *SInterfaceIP) GetGlobalId() string { + return ip.IP +} + +func (vip *SVirtualIP) GetName() string { + if len(vip.Name) > 0 { + return vip.Name + } + return vip.UUID +} + +func (vip *SVirtualIP) GetId() string { + return vip.UUID +} + +func (vip *SVirtualIP) GetGlobalId() string { + return vip.UUID +} + +func (vip *SVirtualIP) GetMacAddress() string { + ip, _ := netutils.NewIPV4Addr(vip.IP) + return ip.ToMac("00:16:") +} + +func (vip *SVirtualIP) GetAssociateType() string { + switch vip.UseFor { + case "LoadBalancer": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_LOADBALANCER + case "Eip": + return api.NETWORK_INTERFACE_ASSOCIATE_TYPE_RESERVED + } + return vip.UseFor +} + +func (vip *SVirtualIP) GetAssociateId() string { + return vip.UsedIPUUID +} + +func (vip *SVirtualIP) GetStatus() string { + if vip.State == "Enabled" { + return api.NETWORK_INTERFACE_STATUS_AVAILABLE + } + return api.NETWORK_INTERFACE_STATUS_UNKNOWN +} + +func (vip *SVirtualIP) GetICloudInterfaceAddresses() ([]cloudprovider.ICloudInterfaceAddress, error) { + ip := &SInterfaceIP{IP: vip.IP, IPRangeUUID: vip.IPRangeUUID, L3NetworkUUID: vip.L3NetworkUUID} + return []cloudprovider.ICloudInterfaceAddress{ip}, nil +} + +func (region *SRegion) GetVirtualIP(vipId string) (*SVirtualIP, error) { + vip := &SVirtualIP{} + return vip, region.client.getResource("vips", vipId, vip) +} + +func (region *SRegion) GetNetworkId(vip *SVirtualIP) string { + networks, err := region.GetNetworks("", "", vip.L3NetworkUUID, "") + if err == nil { + for _, network := range networks { + if network.Contains(vip.IP) { + return fmt.Sprintf("%s/%s", vip.L3NetworkUUID, network.UUID) + } + } + } + return "" +} + +func (region *SRegion) GetVirtualIPs(vipId string) ([]SVirtualIP, error) { + vips := []SVirtualIP{} + params := url.Values{} + if len(vipId) > 0 { + params.Add("q", "uuid="+vipId) + } + return vips, region.client.listAll("vips", params, &vips) +} + +func (region *SRegion) CreateVirtualIP(name, desc, ip string, l3Id string) (*SVirtualIP, error) { + vip := SVirtualIP{} + params := map[string]map[string]string{ + "params": { + "name": name, + "description": desc, + "l3NetworkUuid": l3Id, + }, + } + if len(ip) > 0 { + params["params"]["requiredIp"] = ip + } + resp, err := region.client.post("vips", jsonutils.Marshal(params)) + if err != nil { + return nil, err + } + return &vip, resp.Unmarshal(&vip, "inventory") +} + +func (region *SRegion) DeleteVirtualIP(vipId string) error { + return region.client.delete("vips", vipId, "") +} + +func (region *SRegion) GetINetworkInterfaces() ([]cloudprovider.ICloudNetworkInterface, error) { + vips, err := region.GetVirtualIPs("") + if err != nil { + return nil, errors.Wrap(err, "region.GetVirtualIPs") + } + ret := []cloudprovider.ICloudNetworkInterface{} + for i := 0; i < len(vips); i++ { + if vips[i].UseFor != "Eip" { + vips[i].region = region + ret = append(ret, &vips[i]) + } + } + return ret, nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/vpc.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/vpc.go new file mode 100644 index 0000000000..adf2178203 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/vpc.go @@ -0,0 +1,116 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "fmt" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SVpc struct { + multicloud.SVpc + ZStackTags + + region *SRegion + + iwires []cloudprovider.ICloudWire +} + +func (vpc *SVpc) GetId() string { + return fmt.Sprintf("%s/vpc", vpc.region.GetGlobalId()) +} + +func (vpc *SVpc) GetName() string { + return fmt.Sprintf("%s-VPC", vpc.region.client.cpcfg.Name) +} + +func (vpc *SVpc) GetGlobalId() string { + return vpc.GetId() +} + +func (vpc *SVpc) IsEmulated() bool { + return true +} + +func (vpc *SVpc) GetIsDefault() bool { + return true +} + +func (vpc *SVpc) GetCidrBlock() string { + return "" +} + +func (vpc *SVpc) GetStatus() string { + return api.VPC_STATUS_AVAILABLE +} + +func (vpc *SVpc) Refresh() error { + return nil +} + +func (vpc *SVpc) GetRegion() cloudprovider.ICloudRegion { + return vpc.region +} + +func (vpc *SVpc) GetIWires() ([]cloudprovider.ICloudWire, error) { + if vpc.iwires == nil || len(vpc.iwires) == 0 { + vpc.iwires = []cloudprovider.ICloudWire{} + wires, err := vpc.region.GetWires("", "", "") + if err != nil { + return nil, err + } + for i := 0; i < len(wires); i++ { + wires[i].vpc = vpc + vpc.iwires = append(vpc.iwires, &wires[i]) + } + } + return vpc.iwires, nil +} + +func (vpc *SVpc) GetIWireById(wireId string) (cloudprovider.ICloudWire, error) { + wire, err := vpc.region.GetWire(wireId) + if err != nil { + return nil, err + } + wire.vpc = vpc + return wire, nil +} + +func (vpc *SVpc) GetISecurityGroups() ([]cloudprovider.ICloudSecurityGroup, error) { + secgroups, err := vpc.region.GetSecurityGroups("", "", "") + if err != nil { + return nil, err + } + isecgroups := []cloudprovider.ICloudSecurityGroup{} + for i := 0; i < len(secgroups); i++ { + isecgroups = append(isecgroups, &secgroups[i]) + } + return isecgroups, nil +} + +func (vpc *SVpc) GetIRouteTables() ([]cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (self *SVpc) GetIRouteTableById(routeTableId string) (cloudprovider.ICloudRouteTable, error) { + return nil, cloudprovider.ErrNotSupported +} + +func (vpc *SVpc) Delete() error { + return nil +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/wire.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/wire.go new file mode 100644 index 0000000000..f9b699d3d8 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/wire.go @@ -0,0 +1,147 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "fmt" + "net/url" + "strings" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SWire struct { + multicloud.SResourceBase + ZStackTags + vpc *SVpc + + inetworks []cloudprovider.ICloudNetwork + + ZStackBasic + Vlan int `json:"vlan"` + ZoneUUID string `json:"zoneUuid"` + PhysicalInterface string `json:"physicalInterface"` + Type string `json:"type"` + ZStackTime + AttachedClusterUUIDs []string `json:"attachedClusterUuids"` +} + +func (region *SRegion) GetWire(wireId string) (*SWire, error) { + wire := &SWire{vpc: region.GetVpc()} + return wire, region.client.getResource("l2-networks", wireId, wire) +} + +func (region *SRegion) GetWires(zoneId string, wireId string, clusterId string) ([]SWire, error) { + wires := []SWire{} + clusterIds, err := region.GetClusterIds() + if err != nil { + return nil, err + } + params := url.Values{} + params.Add("q", "attachedClusterUuids?="+strings.Join(clusterIds, ",")) + if len(clusterId) > 0 { + params.Set("q", "attachedClusterUuids?="+clusterId) + } + if len(zoneId) > 0 { + params.Add("q", "zone.uuid="+zoneId) + } + if len(wireId) > 0 { + params.Add("q", "uuid="+wireId) + } + err = region.client.listAll("l2-networks", params, &wires) + if err != nil { + return nil, err + } + for i := 0; i < len(wires); i++ { + wires[i].vpc = region.GetVpc() + } + return wires, nil +} + +func (wire *SWire) GetId() string { + return wire.UUID +} + +func (wire *SWire) GetName() string { + return wire.Name +} + +func (wire *SWire) IsEmulated() bool { + return false +} + +func (wire *SWire) GetStatus() string { + return api.WIRE_STATUS_AVAILABLE +} + +func (wire *SWire) Refresh() error { + return nil +} + +func (wire *SWire) GetGlobalId() string { + return wire.UUID +} + +func (wire *SWire) GetIVpc() cloudprovider.ICloudVpc { + return nil +} + +func (wire *SWire) GetIZone() cloudprovider.ICloudZone { + zone, _ := wire.vpc.region.GetZone(wire.ZoneUUID) + return zone +} + +func (wire *SWire) GetINetworks() ([]cloudprovider.ICloudNetwork, error) { + if wire.inetworks == nil || len(wire.inetworks) == 0 { + networks, err := wire.vpc.region.GetNetworks(wire.ZoneUUID, wire.UUID, "", "") + if err != nil { + return nil, err + } + wire.inetworks = []cloudprovider.ICloudNetwork{} + for i := 0; i < len(networks); i++ { + networks[i].wire = wire + wire.inetworks = append(wire.inetworks, &networks[i]) + } + } + return wire.inetworks, nil +} + +func (wire *SWire) GetBandwidth() int { + return 10000 +} + +func (wire *SWire) CreateINetwork(opts *cloudprovider.SNetworkCreateOptions) (cloudprovider.ICloudNetwork, error) { + network, err := wire.vpc.region.CreateNetwork(opts.Name, opts.Cidr, wire.UUID, opts.Desc) + if err != nil { + return nil, err + } + network.wire = wire + return network, nil +} + +func (wire *SWire) GetINetworkById(netid string) (cloudprovider.ICloudNetwork, error) { + idInfo := strings.Split(netid, "/") + if len(idInfo) == 2 { + network, err := wire.vpc.region.GetNetwork(wire.ZoneUUID, wire.UUID, idInfo[0], idInfo[1]) + if err != nil { + return nil, err + } + network.wire = wire + return network, nil + } + return nil, fmt.Errorf("invalid netid %s", netid) +} diff --git a/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/zone.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/zone.go new file mode 100644 index 0000000000..eb5cc86138 --- /dev/null +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/zone.go @@ -0,0 +1,183 @@ +// Copyright 2019 Yunion +// +// 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 zstack + +import ( + "strconv" + + "yunion.io/x/log" + "yunion.io/x/pkg/util/fileutils" + + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" + "yunion.io/x/cloudmux/pkg/multicloud" +) + +type SZone struct { + multicloud.SResourceBase + ZStackTags + region *SRegion + + ZStackBasic + Type string + State string + cpuCmtbound float32 + memCmtbound float32 + reservedMemeoryMb int + + iwires []cloudprovider.ICloudWire + istorages []cloudprovider.ICloudStorage + + ihosts []cloudprovider.ICloudHost +} + +func (zone *SZone) GetId() string { + return zone.Name +} + +func (zone *SZone) GetName() string { + return zone.Name +} + +func (zone *SZone) GetI18n() cloudprovider.SModelI18nTable { + table := cloudprovider.SModelI18nTable{} + table["name"] = cloudprovider.NewSModelI18nEntry(zone.GetName()).CN(zone.GetName()) + return table +} + +func (zone *SZone) GetGlobalId() string { + return zone.GetId() +} + +func (zone *SZone) IsEmulated() bool { + return false +} + +func (zone *SZone) GetStatus() string { + if zone.State == "Enabled" { + return api.ZONE_ENABLE + } + return api.ZONE_DISABLE +} + +func (zone *SZone) Refresh() error { + // do nothing + return nil +} + +func (zone *SZone) GetIRegion() cloudprovider.ICloudRegion { + return zone.region +} + +func (zone *SZone) fetchHostCmtbound() { + if zone.cpuCmtbound > 0 || zone.memCmtbound > 0 || zone.reservedMemeoryMb > 0 { + return + } + configurations, err := zone.region.GetConfigrations() + if err != nil { + log.Errorf("failed to get global configurations error: %v", err) + return + } + for _, config := range configurations { + if config.Name == "cpu.overProvisioning.ratio" && config.Category == "host" { + if cpuCmtbound, err := strconv.ParseFloat(config.Value, 32); err == nil { + zone.cpuCmtbound = float32(cpuCmtbound) + } + } + if config.Name == "reservedMemory" && config.Category == "kvm" { + zone.reservedMemeoryMb, _ = fileutils.GetSizeMb(config.Value, 'M', 1024) + } + if config.Name == "overProvisioning.memory" && config.Category == "mevoco" { + if memCmtbound, err := strconv.ParseFloat(config.Value, 32); err == nil { + zone.memCmtbound = float32(memCmtbound) + } + } + } +} + +func (zone *SZone) fetchStorages(clusterId string) error { + storages, err := zone.region.getIStorages(zone.UUID) + if err != nil { + return err + } + zone.istorages = storages + return nil +} + +func (zone *SZone) GetIStorages() ([]cloudprovider.ICloudStorage, error) { + if zone.istorages == nil || len(zone.istorages) == 0 { + return zone.istorages, zone.fetchStorages("") + } + return zone.istorages, nil +} + +func (zone *SZone) GetIStorageById(storageId string) (cloudprovider.ICloudStorage, error) { + err := zone.fetchStorages("") + if err != nil { + return nil, err + } + for i := 0; i < len(zone.istorages); i++ { + if zone.istorages[i].GetGlobalId() == storageId { + return zone.istorages[i], nil + } + } + return nil, cloudprovider.ErrNotFound +} + +func (zone *SZone) GetIHostById(hostId string) (cloudprovider.ICloudHost, error) { + host, err := zone.region.GetHost(hostId) + if err != nil { + return nil, err + } + if host.ZoneUUID != zone.UUID { + return nil, cloudprovider.ErrNotFound + } + host.zone = zone + return host, nil +} + +func (zone *SZone) fetchHosts() error { + hosts, err := zone.region.GetHosts(zone.UUID, "") + if err != nil { + return err + } + zone.ihosts = []cloudprovider.ICloudHost{} + for i := 0; i < len(hosts); i++ { + hosts[i].zone = zone + zone.ihosts = append(zone.ihosts, &hosts[i]) + } + return nil +} + +func (zone *SZone) GetIHosts() ([]cloudprovider.ICloudHost, error) { + if zone.ihosts == nil || len(zone.ihosts) == 0 { + return zone.ihosts, zone.fetchHosts() + } + return zone.ihosts, nil +} + +func (zone *SZone) GetIWires() ([]cloudprovider.ICloudWire, error) { + if zone.iwires == nil || len(zone.iwires) == 0 { + wires, err := zone.region.GetWires(zone.UUID, "", "") + if err != nil { + return nil, err + } + zone.iwires = []cloudprovider.ICloudWire{} + for i := 0; i < len(wires); i++ { + zone.iwires = append(zone.iwires, &wires[i]) + } + } + return zone.iwires, nil +} diff --git a/pkg/multicloud/zstack/zstack.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/zstack.go similarity index 99% rename from pkg/multicloud/zstack/zstack.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/zstack.go index 9ba1ec5ae2..bc07003850 100644 --- a/pkg/multicloud/zstack/zstack.go +++ b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/zstack.go @@ -32,8 +32,8 @@ import ( "yunion.io/x/jsonutils" "yunion.io/x/log" - api "yunion.io/x/onecloud/pkg/apis/compute" - "yunion.io/x/onecloud/pkg/cloudprovider" + api "yunion.io/x/cloudmux/pkg/apis/compute" + "yunion.io/x/cloudmux/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/util/httputils" ) diff --git a/pkg/multicloud/zstack/zstack_const.go b/vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/zstack_const.go similarity index 100% rename from pkg/multicloud/zstack/zstack_const.go rename to vendor/yunion.io/x/cloudmux/pkg/multicloud/zstack/zstack_const.go